From cc49b6f53ae726d4e9b87ad9709e47d6f3e6fc9b Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 1 Aug 2017 13:28:41 +0200 Subject: [PATCH 0001/2215] add subscribe to conf event api --- coreapi/CMakeLists.txt | 11 +- coreapi/linphonecore.c | 12 + src/conference/conference-event-package.cpp | 101 + src/conference/conference-event-package.h | 51 + src/conference/conference-info.cxx | 9272 +++++++++++++++++++ src/conference/conference-info.hxx | 3862 ++++++++ src/conference/conference-info.xsd | 387 + src/conference/conference-listener.h | 41 + src/conference/xml.hxx | 503 + tester/CMakeLists.txt | 15 +- tester/confeventpackage_tester.cpp | 717 ++ tester/eventapi_tester.c | 6 +- tester/liblinphone_tester.h | 3 +- tester/tester.c | 2 +- 14 files changed, 14974 insertions(+), 9 deletions(-) create mode 100644 src/conference/conference-event-package.cpp create mode 100644 src/conference/conference-event-package.h create mode 100644 src/conference/conference-info.cxx create mode 100644 src/conference/conference-info.hxx create mode 100644 src/conference/conference-info.xsd create mode 100644 src/conference/conference-listener.h create mode 100644 src/conference/xml.hxx create mode 100644 tester/confeventpackage_tester.cpp diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 4dd144b9d..b0747a5fd 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -38,6 +38,9 @@ set(LINPHONE_PRIVATE_HEADER_FILES ../src/object/object.h ../src/object/singleton.h ../src/utils/general.h + ../src/conference/conference-listener.h + ../src/conference/conference-event-package.h + ../src/conference/conference-info.hxx bellesip_sal/sal_impl.h carddav.h conference_private.h @@ -122,7 +125,12 @@ set(LINPHONE_SOURCE_FILES_C xmlrpc.c vtables.c ) -set(LINPHONE_SOURCE_FILES_CXX conference.cc) +set(LINPHONE_SOURCE_FILES_CXX + conference.cc + ../src/conference/conference-event-package.cpp + ../src/conference/conference-info.cxx +) +set(LINPHONE_INCLUDE_DIRS ${LINPHONE_INCLUDE_DIRS} /Users/reisbenjamin/xsd-4.0.0-i686-macosx/libxsd /usr/local/Cellar/xerces-c/3.1.4/include) if(ANDROID) list(APPEND LINPHONE_SOURCE_FILES_CXX linphonecore_jni.cc) set_source_files_properties(linphonecore_jni.cc PROPERTIES COMPILE_DEFINITIONS "USE_JAVAH") @@ -158,6 +166,7 @@ set(LIBS ${MEDIASTREAMER2_LIBRARIES} ${ORTP_LIBRARIES} ${XML2_LIBRARIES} + /usr/local/Cellar/xerces-c/3.1.4/lib/libxerces-c.dylib ) if(WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") list(APPEND LIBS "Ws2_32") diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 327ce21b2..07d215d8c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -45,6 +45,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mediastreamer2/msjpegwriter.h" #include "mediastreamer2/msogl.h" #include "mediastreamer2/msvolume.h" +#include "conference/conference-event-package.h" #ifdef INET6 #ifndef _WIN32 @@ -2115,12 +2116,23 @@ static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEve linphone_friend_list_notify_presence_received(list, lev, body); friendLists = friendLists->next; } + } else if (strcmp(notified_event, "Conference") == 0) { + LinphonePrivate::Conference::ConferenceEventPackage *cep = reinterpret_cast(linphone_event_get_user_data(lev)); + if(cep) { + ms_message("notify event for conference %s", cep->getConfId().c_str()); + cep->notifyReceived((char *) linphone_content_get_buffer(body)); + } } } static void linphone_core_internal_subscription_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state) { if (strcasecmp(linphone_event_get_name(lev), "Presence") == 0) { linphone_friend_list_subscription_state_changed(lc, lev, state); + } else if (strcmp(linphone_event_get_name(lev), "Conference") == 0) { + LinphonePrivate::Conference::ConferenceEventPackage *cep = reinterpret_cast(linphone_event_get_user_data(lev)); + if(cep) { + + } } } diff --git a/src/conference/conference-event-package.cpp b/src/conference/conference-event-package.cpp new file mode 100644 index 000000000..41a2b26bf --- /dev/null +++ b/src/conference/conference-event-package.cpp @@ -0,0 +1,101 @@ +/* + * conference-event-package.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "conference-event-package.h" +#include "conference-info.hxx" +#include "private.h" + +using namespace std; +using namespace conference_info; +using namespace LinphonePrivate; + +class LinphonePrivate::Conference::ConferenceEventPackagePrivate : public ObjectPrivate { +public: + LinphoneCore *lc; + ConferenceListener *listener; + LinphoneAddress *confAddr; + string confId; + LinphoneEvent *lev; +}; + +Conference::ConferenceEventPackage::ConferenceEventPackage(LinphoneCore *lc, ConferenceListener *listener, LinphoneAddress *confAddr) : Object(new Conference::ConferenceEventPackagePrivate) { + L_D(ConferenceEventPackage); + xercesc::XMLPlatformUtils::Initialize(); + d->lc = lc; + d->listener = listener; + d->confAddr = confAddr; + linphone_address_ref(confAddr); + d->lev = NULL; +} + +Conference::ConferenceEventPackage::~ConferenceEventPackage() { + L_D(ConferenceEventPackage); + xercesc::XMLPlatformUtils::Terminate(); + linphone_address_unref(d->confAddr); + if(d->lev) linphone_event_unref(d->lev); +} + +void Conference::ConferenceEventPackage::subscribe(string confId) { + L_D(ConferenceEventPackage); + d->confId = confId; + d->lev = linphone_core_create_subscribe(d->lc, d->confAddr, "Conference", 600); + linphone_event_ref(d->lev); + linphone_event_set_internal(d->lev, TRUE); + linphone_event_set_user_data(d->lev, this); + linphone_event_add_custom_header(d->lev, "Conf-id", d->confId.c_str()); // TODO : ??? + linphone_event_send_subscribe(d->lev, NULL); +} + +void Conference::ConferenceEventPackage::unsubscribe() { + L_D(ConferenceEventPackage); + linphone_event_terminate(d->lev); +} + +void Conference::ConferenceEventPackage::notifyReceived(const char *xmlBody) { + L_D(ConferenceEventPackage); + istringstream data(xmlBody); + unique_ptr confInfo = parseConference_info(data, xml_schema::Flags::dont_validate); + if(strcmp(confInfo->getEntity().c_str(), linphone_address_as_string(d->confAddr)) == 0) { + for (const auto &user : confInfo->getUsers()->getUser()) { + LinphoneAddress *addr = linphone_core_interpret_url(d->lc, user.getEntity()->c_str()); + if(user.getState() == "deleted") { + d->listener->participantRemoved(addr); + } else { + bool isAdmin = false; + if(user.getRoles()) { + for (const auto &entry : user.getRoles()->getEntry()) { + if (entry == "admin") { + isAdmin = true; + break; + } + } + } + if(user.getState() == "full") { + d->listener->participantAdded(addr); + } + d->listener->participantSetAdmin(addr, isAdmin); + } + linphone_address_unref(addr); + } + } +} + +string Conference::ConferenceEventPackage::getConfId() { + L_D(ConferenceEventPackage); + return d->confId; +} diff --git a/src/conference/conference-event-package.h b/src/conference/conference-event-package.h new file mode 100644 index 000000000..3237cf41d --- /dev/null +++ b/src/conference/conference-event-package.h @@ -0,0 +1,51 @@ +/* + * conference-event-package.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CONFERENCE_EVENT_PACKAGE_H_ +#define _CONFERENCE_EVENT_PACKAGE_H_ + +#include + +#include "object/object.h" +#include "conference-listener.h" +#include "linphone/core.h" + +namespace LinphonePrivate { + namespace Conference { + class ConferenceEventPackagePrivate; + + // ------------------------------------------------------------------------- + // ConferenceEventPackage. + // ------------------------------------------------------------------------- + class ConferenceEventPackage : public Object { + public: + ConferenceEventPackage(LinphoneCore *lc, ConferenceListener *listener, LinphoneAddress *confAddr); + ~ConferenceEventPackage(); + void subscribe(std::string confId); + void notifyReceived(const char *xmlBody); + void unsubscribe(); + std::string getConfId(); + + private: + L_DECLARE_PRIVATE(ConferenceEventPackage); + L_DISABLE_COPY(ConferenceEventPackage); + }; + } +} + +#endif // ifndef _CONFERENCE_EVENT_PACKAGE_H_ diff --git a/src/conference/conference-info.cxx b/src/conference/conference-info.cxx new file mode 100644 index 000000000..d43cb20d0 --- /dev/null +++ b/src/conference/conference-info.cxx @@ -0,0 +1,9272 @@ +// Copyright (c) 2005-2014 Code Synthesis Tools CC +// +// This program was generated by CodeSynthesis XSD, an XML Schema to +// C++ data binding compiler. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// 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 St, Fifth Floor, Boston, MA 02110-1301 USA +// +// In addition, as a special exception, Code Synthesis Tools CC gives +// permission to link this program with the Xerces-C++ library (or with +// modified versions of Xerces-C++ that use the same license as Xerces-C++), +// and distribute linked combinations including the two. You must obey +// the GNU General Public License version 2 in all respects for all of +// the code used other than Xerces-C++. If you modify this copy of the +// program, you may extend this exception to your version of the program, +// but you are not obligated to do so. If you do not wish to do so, delete +// this exception statement from your version. +// +// Furthermore, Code Synthesis Tools CC makes a special exception for +// the Free/Libre and Open Source Software (FLOSS) which is described +// in the accompanying FLOSSE file. +// + +// Begin prologue. +// +// +// End prologue. + +#include + +#include "conference-info.hxx" + +namespace conference_info +{ + // Conference_type + // + + const Conference_type::Conference_descriptionOptional& Conference_type:: + getConference_description () const + { + return this->conference_description_; + } + + Conference_type::Conference_descriptionOptional& Conference_type:: + getConference_description () + { + return this->conference_description_; + } + + void Conference_type:: + setConference_description (const Conference_descriptionType& x) + { + this->conference_description_.set (x); + } + + void Conference_type:: + setConference_description (const Conference_descriptionOptional& x) + { + this->conference_description_ = x; + } + + void Conference_type:: + setConference_description (::std::unique_ptr< Conference_descriptionType > x) + { + this->conference_description_.set (std::move (x)); + } + + const Conference_type::Host_infoOptional& Conference_type:: + getHost_info () const + { + return this->host_info_; + } + + Conference_type::Host_infoOptional& Conference_type:: + getHost_info () + { + return this->host_info_; + } + + void Conference_type:: + setHost_info (const Host_infoType& x) + { + this->host_info_.set (x); + } + + void Conference_type:: + setHost_info (const Host_infoOptional& x) + { + this->host_info_ = x; + } + + void Conference_type:: + setHost_info (::std::unique_ptr< Host_infoType > x) + { + this->host_info_.set (std::move (x)); + } + + const Conference_type::Conference_stateOptional& Conference_type:: + getConference_state () const + { + return this->conference_state_; + } + + Conference_type::Conference_stateOptional& Conference_type:: + getConference_state () + { + return this->conference_state_; + } + + void Conference_type:: + setConference_state (const Conference_stateType& x) + { + this->conference_state_.set (x); + } + + void Conference_type:: + setConference_state (const Conference_stateOptional& x) + { + this->conference_state_ = x; + } + + void Conference_type:: + setConference_state (::std::unique_ptr< Conference_stateType > x) + { + this->conference_state_.set (std::move (x)); + } + + const Conference_type::UsersOptional& Conference_type:: + getUsers () const + { + return this->users_; + } + + Conference_type::UsersOptional& Conference_type:: + getUsers () + { + return this->users_; + } + + void Conference_type:: + setUsers (const UsersType& x) + { + this->users_.set (x); + } + + void Conference_type:: + setUsers (const UsersOptional& x) + { + this->users_ = x; + } + + void Conference_type:: + setUsers (::std::unique_ptr< UsersType > x) + { + this->users_.set (std::move (x)); + } + + const Conference_type::Sidebars_by_refOptional& Conference_type:: + getSidebars_by_ref () const + { + return this->sidebars_by_ref_; + } + + Conference_type::Sidebars_by_refOptional& Conference_type:: + getSidebars_by_ref () + { + return this->sidebars_by_ref_; + } + + void Conference_type:: + setSidebars_by_ref (const Sidebars_by_refType& x) + { + this->sidebars_by_ref_.set (x); + } + + void Conference_type:: + setSidebars_by_ref (const Sidebars_by_refOptional& x) + { + this->sidebars_by_ref_ = x; + } + + void Conference_type:: + setSidebars_by_ref (::std::unique_ptr< Sidebars_by_refType > x) + { + this->sidebars_by_ref_.set (std::move (x)); + } + + const Conference_type::Sidebars_by_valOptional& Conference_type:: + getSidebars_by_val () const + { + return this->sidebars_by_val_; + } + + Conference_type::Sidebars_by_valOptional& Conference_type:: + getSidebars_by_val () + { + return this->sidebars_by_val_; + } + + void Conference_type:: + setSidebars_by_val (const Sidebars_by_valType& x) + { + this->sidebars_by_val_.set (x); + } + + void Conference_type:: + setSidebars_by_val (const Sidebars_by_valOptional& x) + { + this->sidebars_by_val_ = x; + } + + void Conference_type:: + setSidebars_by_val (::std::unique_ptr< Sidebars_by_valType > x) + { + this->sidebars_by_val_.set (std::move (x)); + } + + const Conference_type::AnySequence& Conference_type:: + getAny () const + { + return this->any_; + } + + Conference_type::AnySequence& Conference_type:: + getAny () + { + return this->any_; + } + + void Conference_type:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const Conference_type::EntityType& Conference_type:: + getEntity () const + { + return this->entity_.get (); + } + + Conference_type::EntityType& Conference_type:: + getEntity () + { + return this->entity_.get (); + } + + void Conference_type:: + setEntity (const EntityType& x) + { + this->entity_.set (x); + } + + void Conference_type:: + setEntity (::std::unique_ptr< EntityType > x) + { + this->entity_.set (std::move (x)); + } + + ::std::unique_ptr< Conference_type::EntityType > Conference_type:: + detachEntity () + { + return this->entity_.detach (); + } + + const Conference_type::StateType& Conference_type:: + getState () const + { + return this->state_.get (); + } + + Conference_type::StateType& Conference_type:: + getState () + { + return this->state_.get (); + } + + void Conference_type:: + setState (const StateType& x) + { + this->state_.set (x); + } + + void Conference_type:: + setState (::std::unique_ptr< StateType > x) + { + this->state_.set (std::move (x)); + } + + ::std::unique_ptr< Conference_type::StateType > Conference_type:: + detachState () + { + return this->state_.detach (); + } + + const Conference_type::StateType& Conference_type:: + getStateDefaultValue () + { + return state_default_value_; + } + + const Conference_type::VersionOptional& Conference_type:: + getVersion () const + { + return this->version_; + } + + Conference_type::VersionOptional& Conference_type:: + getVersion () + { + return this->version_; + } + + void Conference_type:: + setVersion (const VersionType& x) + { + this->version_.set (x); + } + + void Conference_type:: + setVersion (const VersionOptional& x) + { + this->version_ = x; + } + + const Conference_type::AnyAttributeSet& Conference_type:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + Conference_type::AnyAttributeSet& Conference_type:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void Conference_type:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& Conference_type:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& Conference_type:: + getDomDocument () + { + return *this->dom_document_; + } + + + // State_type + // + + State_type:: + State_type (Value v) + : ::xml_schema::String (_xsd_State_type_literals_[v]) + { + } + + State_type:: + State_type (const char* v) + : ::xml_schema::String (v) + { + } + + State_type:: + State_type (const ::std::string& v) + : ::xml_schema::String (v) + { + } + + State_type:: + State_type (const ::xml_schema::String& v) + : ::xml_schema::String (v) + { + } + + State_type:: + State_type (const State_type& v, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (v, f, c) + { + } + + State_type& State_type:: + operator= (Value v) + { + static_cast< ::xml_schema::String& > (*this) = + ::xml_schema::String (_xsd_State_type_literals_[v]); + + return *this; + } + + + // Conference_description_type + // + + const Conference_description_type::Display_textOptional& Conference_description_type:: + getDisplay_text () const + { + return this->display_text_; + } + + Conference_description_type::Display_textOptional& Conference_description_type:: + getDisplay_text () + { + return this->display_text_; + } + + void Conference_description_type:: + setDisplay_text (const Display_textType& x) + { + this->display_text_.set (x); + } + + void Conference_description_type:: + setDisplay_text (const Display_textOptional& x) + { + this->display_text_ = x; + } + + void Conference_description_type:: + setDisplay_text (::std::unique_ptr< Display_textType > x) + { + this->display_text_.set (std::move (x)); + } + + const Conference_description_type::SubjectOptional& Conference_description_type:: + getSubject () const + { + return this->subject_; + } + + Conference_description_type::SubjectOptional& Conference_description_type:: + getSubject () + { + return this->subject_; + } + + void Conference_description_type:: + setSubject (const SubjectType& x) + { + this->subject_.set (x); + } + + void Conference_description_type:: + setSubject (const SubjectOptional& x) + { + this->subject_ = x; + } + + void Conference_description_type:: + setSubject (::std::unique_ptr< SubjectType > x) + { + this->subject_.set (std::move (x)); + } + + const Conference_description_type::Free_textOptional& Conference_description_type:: + getFree_text () const + { + return this->free_text_; + } + + Conference_description_type::Free_textOptional& Conference_description_type:: + getFree_text () + { + return this->free_text_; + } + + void Conference_description_type:: + setFree_text (const Free_textType& x) + { + this->free_text_.set (x); + } + + void Conference_description_type:: + setFree_text (const Free_textOptional& x) + { + this->free_text_ = x; + } + + void Conference_description_type:: + setFree_text (::std::unique_ptr< Free_textType > x) + { + this->free_text_.set (std::move (x)); + } + + const Conference_description_type::KeywordsOptional& Conference_description_type:: + getKeywords () const + { + return this->keywords_; + } + + Conference_description_type::KeywordsOptional& Conference_description_type:: + getKeywords () + { + return this->keywords_; + } + + void Conference_description_type:: + setKeywords (const KeywordsType& x) + { + this->keywords_.set (x); + } + + void Conference_description_type:: + setKeywords (const KeywordsOptional& x) + { + this->keywords_ = x; + } + + void Conference_description_type:: + setKeywords (::std::unique_ptr< KeywordsType > x) + { + this->keywords_.set (std::move (x)); + } + + const Conference_description_type::Conf_urisOptional& Conference_description_type:: + getConf_uris () const + { + return this->conf_uris_; + } + + Conference_description_type::Conf_urisOptional& Conference_description_type:: + getConf_uris () + { + return this->conf_uris_; + } + + void Conference_description_type:: + setConf_uris (const Conf_urisType& x) + { + this->conf_uris_.set (x); + } + + void Conference_description_type:: + setConf_uris (const Conf_urisOptional& x) + { + this->conf_uris_ = x; + } + + void Conference_description_type:: + setConf_uris (::std::unique_ptr< Conf_urisType > x) + { + this->conf_uris_.set (std::move (x)); + } + + const Conference_description_type::Service_urisOptional& Conference_description_type:: + getService_uris () const + { + return this->service_uris_; + } + + Conference_description_type::Service_urisOptional& Conference_description_type:: + getService_uris () + { + return this->service_uris_; + } + + void Conference_description_type:: + setService_uris (const Service_urisType& x) + { + this->service_uris_.set (x); + } + + void Conference_description_type:: + setService_uris (const Service_urisOptional& x) + { + this->service_uris_ = x; + } + + void Conference_description_type:: + setService_uris (::std::unique_ptr< Service_urisType > x) + { + this->service_uris_.set (std::move (x)); + } + + const Conference_description_type::Maximum_user_countOptional& Conference_description_type:: + getMaximum_user_count () const + { + return this->maximum_user_count_; + } + + Conference_description_type::Maximum_user_countOptional& Conference_description_type:: + getMaximum_user_count () + { + return this->maximum_user_count_; + } + + void Conference_description_type:: + setMaximum_user_count (const Maximum_user_countType& x) + { + this->maximum_user_count_.set (x); + } + + void Conference_description_type:: + setMaximum_user_count (const Maximum_user_countOptional& x) + { + this->maximum_user_count_ = x; + } + + const Conference_description_type::Available_mediaOptional& Conference_description_type:: + getAvailable_media () const + { + return this->available_media_; + } + + Conference_description_type::Available_mediaOptional& Conference_description_type:: + getAvailable_media () + { + return this->available_media_; + } + + void Conference_description_type:: + setAvailable_media (const Available_mediaType& x) + { + this->available_media_.set (x); + } + + void Conference_description_type:: + setAvailable_media (const Available_mediaOptional& x) + { + this->available_media_ = x; + } + + void Conference_description_type:: + setAvailable_media (::std::unique_ptr< Available_mediaType > x) + { + this->available_media_.set (std::move (x)); + } + + const Conference_description_type::AnySequence& Conference_description_type:: + getAny () const + { + return this->any_; + } + + Conference_description_type::AnySequence& Conference_description_type:: + getAny () + { + return this->any_; + } + + void Conference_description_type:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const Conference_description_type::AnyAttributeSet& Conference_description_type:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + Conference_description_type::AnyAttributeSet& Conference_description_type:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void Conference_description_type:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& Conference_description_type:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& Conference_description_type:: + getDomDocument () + { + return *this->dom_document_; + } + + + // Host_type + // + + const Host_type::Display_textOptional& Host_type:: + getDisplay_text () const + { + return this->display_text_; + } + + Host_type::Display_textOptional& Host_type:: + getDisplay_text () + { + return this->display_text_; + } + + void Host_type:: + setDisplay_text (const Display_textType& x) + { + this->display_text_.set (x); + } + + void Host_type:: + setDisplay_text (const Display_textOptional& x) + { + this->display_text_ = x; + } + + void Host_type:: + setDisplay_text (::std::unique_ptr< Display_textType > x) + { + this->display_text_.set (std::move (x)); + } + + const Host_type::Web_pageOptional& Host_type:: + getWeb_page () const + { + return this->web_page_; + } + + Host_type::Web_pageOptional& Host_type:: + getWeb_page () + { + return this->web_page_; + } + + void Host_type:: + setWeb_page (const Web_pageType& x) + { + this->web_page_.set (x); + } + + void Host_type:: + setWeb_page (const Web_pageOptional& x) + { + this->web_page_ = x; + } + + void Host_type:: + setWeb_page (::std::unique_ptr< Web_pageType > x) + { + this->web_page_.set (std::move (x)); + } + + const Host_type::UrisOptional& Host_type:: + getUris () const + { + return this->uris_; + } + + Host_type::UrisOptional& Host_type:: + getUris () + { + return this->uris_; + } + + void Host_type:: + setUris (const UrisType& x) + { + this->uris_.set (x); + } + + void Host_type:: + setUris (const UrisOptional& x) + { + this->uris_ = x; + } + + void Host_type:: + setUris (::std::unique_ptr< UrisType > x) + { + this->uris_.set (std::move (x)); + } + + const Host_type::AnySequence& Host_type:: + getAny () const + { + return this->any_; + } + + Host_type::AnySequence& Host_type:: + getAny () + { + return this->any_; + } + + void Host_type:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const Host_type::AnyAttributeSet& Host_type:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + Host_type::AnyAttributeSet& Host_type:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void Host_type:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& Host_type:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& Host_type:: + getDomDocument () + { + return *this->dom_document_; + } + + + // Conference_state_type + // + + const Conference_state_type::User_countOptional& Conference_state_type:: + getUser_count () const + { + return this->user_count_; + } + + Conference_state_type::User_countOptional& Conference_state_type:: + getUser_count () + { + return this->user_count_; + } + + void Conference_state_type:: + setUser_count (const User_countType& x) + { + this->user_count_.set (x); + } + + void Conference_state_type:: + setUser_count (const User_countOptional& x) + { + this->user_count_ = x; + } + + const Conference_state_type::ActiveOptional& Conference_state_type:: + getActive () const + { + return this->active_; + } + + Conference_state_type::ActiveOptional& Conference_state_type:: + getActive () + { + return this->active_; + } + + void Conference_state_type:: + setActive (const ActiveType& x) + { + this->active_.set (x); + } + + void Conference_state_type:: + setActive (const ActiveOptional& x) + { + this->active_ = x; + } + + const Conference_state_type::LockedOptional& Conference_state_type:: + getLocked () const + { + return this->locked_; + } + + Conference_state_type::LockedOptional& Conference_state_type:: + getLocked () + { + return this->locked_; + } + + void Conference_state_type:: + setLocked (const LockedType& x) + { + this->locked_.set (x); + } + + void Conference_state_type:: + setLocked (const LockedOptional& x) + { + this->locked_ = x; + } + + const Conference_state_type::AnySequence& Conference_state_type:: + getAny () const + { + return this->any_; + } + + Conference_state_type::AnySequence& Conference_state_type:: + getAny () + { + return this->any_; + } + + void Conference_state_type:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const Conference_state_type::AnyAttributeSet& Conference_state_type:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + Conference_state_type::AnyAttributeSet& Conference_state_type:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void Conference_state_type:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& Conference_state_type:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& Conference_state_type:: + getDomDocument () + { + return *this->dom_document_; + } + + + // Conference_media_type + // + + const Conference_media_type::EntrySequence& Conference_media_type:: + getEntry () const + { + return this->entry_; + } + + Conference_media_type::EntrySequence& Conference_media_type:: + getEntry () + { + return this->entry_; + } + + void Conference_media_type:: + setEntry (const EntrySequence& s) + { + this->entry_ = s; + } + + const Conference_media_type::AnyAttributeSet& Conference_media_type:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + Conference_media_type::AnyAttributeSet& Conference_media_type:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void Conference_media_type:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& Conference_media_type:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& Conference_media_type:: + getDomDocument () + { + return *this->dom_document_; + } + + + // Conference_medium_type + // + + const Conference_medium_type::Display_textOptional& Conference_medium_type:: + getDisplay_text () const + { + return this->display_text_; + } + + Conference_medium_type::Display_textOptional& Conference_medium_type:: + getDisplay_text () + { + return this->display_text_; + } + + void Conference_medium_type:: + setDisplay_text (const Display_textType& x) + { + this->display_text_.set (x); + } + + void Conference_medium_type:: + setDisplay_text (const Display_textOptional& x) + { + this->display_text_ = x; + } + + void Conference_medium_type:: + setDisplay_text (::std::unique_ptr< Display_textType > x) + { + this->display_text_.set (std::move (x)); + } + + const Conference_medium_type::TypeType& Conference_medium_type:: + getType () const + { + return this->type_.get (); + } + + Conference_medium_type::TypeType& Conference_medium_type:: + getType () + { + return this->type_.get (); + } + + void Conference_medium_type:: + setType (const TypeType& x) + { + this->type_.set (x); + } + + void Conference_medium_type:: + setType (::std::unique_ptr< TypeType > x) + { + this->type_.set (std::move (x)); + } + + ::std::unique_ptr< Conference_medium_type::TypeType > Conference_medium_type:: + detachType () + { + return this->type_.detach (); + } + + const Conference_medium_type::StatusOptional& Conference_medium_type:: + getStatus () const + { + return this->status_; + } + + Conference_medium_type::StatusOptional& Conference_medium_type:: + getStatus () + { + return this->status_; + } + + void Conference_medium_type:: + setStatus (const StatusType& x) + { + this->status_.set (x); + } + + void Conference_medium_type:: + setStatus (const StatusOptional& x) + { + this->status_ = x; + } + + void Conference_medium_type:: + setStatus (::std::unique_ptr< StatusType > x) + { + this->status_.set (std::move (x)); + } + + const Conference_medium_type::AnySequence& Conference_medium_type:: + getAny () const + { + return this->any_; + } + + Conference_medium_type::AnySequence& Conference_medium_type:: + getAny () + { + return this->any_; + } + + void Conference_medium_type:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const Conference_medium_type::LabelType& Conference_medium_type:: + getLabel () const + { + return this->label_.get (); + } + + Conference_medium_type::LabelType& Conference_medium_type:: + getLabel () + { + return this->label_.get (); + } + + void Conference_medium_type:: + setLabel (const LabelType& x) + { + this->label_.set (x); + } + + void Conference_medium_type:: + setLabel (::std::unique_ptr< LabelType > x) + { + this->label_.set (std::move (x)); + } + + ::std::unique_ptr< Conference_medium_type::LabelType > Conference_medium_type:: + detachLabel () + { + return this->label_.detach (); + } + + const Conference_medium_type::AnyAttributeSet& Conference_medium_type:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + Conference_medium_type::AnyAttributeSet& Conference_medium_type:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void Conference_medium_type:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& Conference_medium_type:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& Conference_medium_type:: + getDomDocument () + { + return *this->dom_document_; + } + + + // Uris_type + // + + const Uris_type::EntrySequence& Uris_type:: + getEntry () const + { + return this->entry_; + } + + Uris_type::EntrySequence& Uris_type:: + getEntry () + { + return this->entry_; + } + + void Uris_type:: + setEntry (const EntrySequence& s) + { + this->entry_ = s; + } + + const Uris_type::StateType& Uris_type:: + getState () const + { + return this->state_.get (); + } + + Uris_type::StateType& Uris_type:: + getState () + { + return this->state_.get (); + } + + void Uris_type:: + setState (const StateType& x) + { + this->state_.set (x); + } + + void Uris_type:: + setState (::std::unique_ptr< StateType > x) + { + this->state_.set (std::move (x)); + } + + ::std::unique_ptr< Uris_type::StateType > Uris_type:: + detachState () + { + return this->state_.detach (); + } + + const Uris_type::StateType& Uris_type:: + getStateDefaultValue () + { + return state_default_value_; + } + + const Uris_type::AnyAttributeSet& Uris_type:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + Uris_type::AnyAttributeSet& Uris_type:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void Uris_type:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& Uris_type:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& Uris_type:: + getDomDocument () + { + return *this->dom_document_; + } + + + // Uri_type + // + + const Uri_type::UriType& Uri_type:: + getUri () const + { + return this->uri_.get (); + } + + Uri_type::UriType& Uri_type:: + getUri () + { + return this->uri_.get (); + } + + void Uri_type:: + setUri (const UriType& x) + { + this->uri_.set (x); + } + + void Uri_type:: + setUri (::std::unique_ptr< UriType > x) + { + this->uri_.set (std::move (x)); + } + + ::std::unique_ptr< Uri_type::UriType > Uri_type:: + detachUri () + { + return this->uri_.detach (); + } + + const Uri_type::Display_textOptional& Uri_type:: + getDisplay_text () const + { + return this->display_text_; + } + + Uri_type::Display_textOptional& Uri_type:: + getDisplay_text () + { + return this->display_text_; + } + + void Uri_type:: + setDisplay_text (const Display_textType& x) + { + this->display_text_.set (x); + } + + void Uri_type:: + setDisplay_text (const Display_textOptional& x) + { + this->display_text_ = x; + } + + void Uri_type:: + setDisplay_text (::std::unique_ptr< Display_textType > x) + { + this->display_text_.set (std::move (x)); + } + + const Uri_type::PurposeOptional& Uri_type:: + getPurpose () const + { + return this->purpose_; + } + + Uri_type::PurposeOptional& Uri_type:: + getPurpose () + { + return this->purpose_; + } + + void Uri_type:: + setPurpose (const PurposeType& x) + { + this->purpose_.set (x); + } + + void Uri_type:: + setPurpose (const PurposeOptional& x) + { + this->purpose_ = x; + } + + void Uri_type:: + setPurpose (::std::unique_ptr< PurposeType > x) + { + this->purpose_.set (std::move (x)); + } + + const Uri_type::ModifiedOptional& Uri_type:: + getModified () const + { + return this->modified_; + } + + Uri_type::ModifiedOptional& Uri_type:: + getModified () + { + return this->modified_; + } + + void Uri_type:: + setModified (const ModifiedType& x) + { + this->modified_.set (x); + } + + void Uri_type:: + setModified (const ModifiedOptional& x) + { + this->modified_ = x; + } + + void Uri_type:: + setModified (::std::unique_ptr< ModifiedType > x) + { + this->modified_.set (std::move (x)); + } + + const Uri_type::AnySequence& Uri_type:: + getAny () const + { + return this->any_; + } + + Uri_type::AnySequence& Uri_type:: + getAny () + { + return this->any_; + } + + void Uri_type:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const Uri_type::AnyAttributeSet& Uri_type:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + Uri_type::AnyAttributeSet& Uri_type:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void Uri_type:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& Uri_type:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& Uri_type:: + getDomDocument () + { + return *this->dom_document_; + } + + + // Keywords_type + // + + Keywords_type:: + Keywords_type () + : ::xsd::cxx::tree::list< ::xml_schema::String, char > (this) + { + } + + Keywords_type:: + Keywords_type (size_type n, const ::xml_schema::String& x) + : ::xsd::cxx::tree::list< ::xml_schema::String, char > (n, x, this) + { + } + + Keywords_type:: + Keywords_type (const Keywords_type& o, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::SimpleType (o, f, c), + ::xsd::cxx::tree::list< ::xml_schema::String, char > (o, f, this) + { + } + + // Users_type + // + + const Users_type::UserSequence& Users_type:: + getUser () const + { + return this->user_; + } + + Users_type::UserSequence& Users_type:: + getUser () + { + return this->user_; + } + + void Users_type:: + setUser (const UserSequence& s) + { + this->user_ = s; + } + + const Users_type::AnySequence& Users_type:: + getAny () const + { + return this->any_; + } + + Users_type::AnySequence& Users_type:: + getAny () + { + return this->any_; + } + + void Users_type:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const Users_type::StateType& Users_type:: + getState () const + { + return this->state_.get (); + } + + Users_type::StateType& Users_type:: + getState () + { + return this->state_.get (); + } + + void Users_type:: + setState (const StateType& x) + { + this->state_.set (x); + } + + void Users_type:: + setState (::std::unique_ptr< StateType > x) + { + this->state_.set (std::move (x)); + } + + ::std::unique_ptr< Users_type::StateType > Users_type:: + detachState () + { + return this->state_.detach (); + } + + const Users_type::StateType& Users_type:: + getStateDefaultValue () + { + return state_default_value_; + } + + const Users_type::AnyAttributeSet& Users_type:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + Users_type::AnyAttributeSet& Users_type:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void Users_type:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& Users_type:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& Users_type:: + getDomDocument () + { + return *this->dom_document_; + } + + + // User_type + // + + const User_type::Display_textOptional& User_type:: + getDisplay_text () const + { + return this->display_text_; + } + + User_type::Display_textOptional& User_type:: + getDisplay_text () + { + return this->display_text_; + } + + void User_type:: + setDisplay_text (const Display_textType& x) + { + this->display_text_.set (x); + } + + void User_type:: + setDisplay_text (const Display_textOptional& x) + { + this->display_text_ = x; + } + + void User_type:: + setDisplay_text (::std::unique_ptr< Display_textType > x) + { + this->display_text_.set (std::move (x)); + } + + const User_type::Associated_aorsOptional& User_type:: + getAssociated_aors () const + { + return this->associated_aors_; + } + + User_type::Associated_aorsOptional& User_type:: + getAssociated_aors () + { + return this->associated_aors_; + } + + void User_type:: + setAssociated_aors (const Associated_aorsType& x) + { + this->associated_aors_.set (x); + } + + void User_type:: + setAssociated_aors (const Associated_aorsOptional& x) + { + this->associated_aors_ = x; + } + + void User_type:: + setAssociated_aors (::std::unique_ptr< Associated_aorsType > x) + { + this->associated_aors_.set (std::move (x)); + } + + const User_type::RolesOptional& User_type:: + getRoles () const + { + return this->roles_; + } + + User_type::RolesOptional& User_type:: + getRoles () + { + return this->roles_; + } + + void User_type:: + setRoles (const RolesType& x) + { + this->roles_.set (x); + } + + void User_type:: + setRoles (const RolesOptional& x) + { + this->roles_ = x; + } + + void User_type:: + setRoles (::std::unique_ptr< RolesType > x) + { + this->roles_.set (std::move (x)); + } + + const User_type::LanguagesOptional& User_type:: + getLanguages () const + { + return this->languages_; + } + + User_type::LanguagesOptional& User_type:: + getLanguages () + { + return this->languages_; + } + + void User_type:: + setLanguages (const LanguagesType& x) + { + this->languages_.set (x); + } + + void User_type:: + setLanguages (const LanguagesOptional& x) + { + this->languages_ = x; + } + + void User_type:: + setLanguages (::std::unique_ptr< LanguagesType > x) + { + this->languages_.set (std::move (x)); + } + + const User_type::Cascaded_focusOptional& User_type:: + getCascaded_focus () const + { + return this->cascaded_focus_; + } + + User_type::Cascaded_focusOptional& User_type:: + getCascaded_focus () + { + return this->cascaded_focus_; + } + + void User_type:: + setCascaded_focus (const Cascaded_focusType& x) + { + this->cascaded_focus_.set (x); + } + + void User_type:: + setCascaded_focus (const Cascaded_focusOptional& x) + { + this->cascaded_focus_ = x; + } + + void User_type:: + setCascaded_focus (::std::unique_ptr< Cascaded_focusType > x) + { + this->cascaded_focus_.set (std::move (x)); + } + + const User_type::EndpointSequence& User_type:: + getEndpoint () const + { + return this->endpoint_; + } + + User_type::EndpointSequence& User_type:: + getEndpoint () + { + return this->endpoint_; + } + + void User_type:: + setEndpoint (const EndpointSequence& s) + { + this->endpoint_ = s; + } + + const User_type::AnySequence& User_type:: + getAny () const + { + return this->any_; + } + + User_type::AnySequence& User_type:: + getAny () + { + return this->any_; + } + + void User_type:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const User_type::EntityOptional& User_type:: + getEntity () const + { + return this->entity_; + } + + User_type::EntityOptional& User_type:: + getEntity () + { + return this->entity_; + } + + void User_type:: + setEntity (const EntityType& x) + { + this->entity_.set (x); + } + + void User_type:: + setEntity (const EntityOptional& x) + { + this->entity_ = x; + } + + void User_type:: + setEntity (::std::unique_ptr< EntityType > x) + { + this->entity_.set (std::move (x)); + } + + const User_type::StateType& User_type:: + getState () const + { + return this->state_.get (); + } + + User_type::StateType& User_type:: + getState () + { + return this->state_.get (); + } + + void User_type:: + setState (const StateType& x) + { + this->state_.set (x); + } + + void User_type:: + setState (::std::unique_ptr< StateType > x) + { + this->state_.set (std::move (x)); + } + + ::std::unique_ptr< User_type::StateType > User_type:: + detachState () + { + return this->state_.detach (); + } + + const User_type::StateType& User_type:: + getStateDefaultValue () + { + return state_default_value_; + } + + const User_type::AnyAttributeSet& User_type:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + User_type::AnyAttributeSet& User_type:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void User_type:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& User_type:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& User_type:: + getDomDocument () + { + return *this->dom_document_; + } + + + // User_roles_type + // + + const User_roles_type::EntrySequence& User_roles_type:: + getEntry () const + { + return this->entry_; + } + + User_roles_type::EntrySequence& User_roles_type:: + getEntry () + { + return this->entry_; + } + + void User_roles_type:: + setEntry (const EntrySequence& s) + { + this->entry_ = s; + } + + const User_roles_type::AnyAttributeSet& User_roles_type:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + User_roles_type::AnyAttributeSet& User_roles_type:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void User_roles_type:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& User_roles_type:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& User_roles_type:: + getDomDocument () + { + return *this->dom_document_; + } + + + // User_languages_type + // + + User_languages_type:: + User_languages_type () + : ::xsd::cxx::tree::list< ::xml_schema::Language, char > (this) + { + } + + User_languages_type:: + User_languages_type (size_type n, const ::xml_schema::Language& x) + : ::xsd::cxx::tree::list< ::xml_schema::Language, char > (n, x, this) + { + } + + User_languages_type:: + User_languages_type (const User_languages_type& o, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::SimpleType (o, f, c), + ::xsd::cxx::tree::list< ::xml_schema::Language, char > (o, f, this) + { + } + + // Endpoint_type + // + + const Endpoint_type::Display_textOptional& Endpoint_type:: + getDisplay_text () const + { + return this->display_text_; + } + + Endpoint_type::Display_textOptional& Endpoint_type:: + getDisplay_text () + { + return this->display_text_; + } + + void Endpoint_type:: + setDisplay_text (const Display_textType& x) + { + this->display_text_.set (x); + } + + void Endpoint_type:: + setDisplay_text (const Display_textOptional& x) + { + this->display_text_ = x; + } + + void Endpoint_type:: + setDisplay_text (::std::unique_ptr< Display_textType > x) + { + this->display_text_.set (std::move (x)); + } + + const Endpoint_type::ReferredOptional& Endpoint_type:: + getReferred () const + { + return this->referred_; + } + + Endpoint_type::ReferredOptional& Endpoint_type:: + getReferred () + { + return this->referred_; + } + + void Endpoint_type:: + setReferred (const ReferredType& x) + { + this->referred_.set (x); + } + + void Endpoint_type:: + setReferred (const ReferredOptional& x) + { + this->referred_ = x; + } + + void Endpoint_type:: + setReferred (::std::unique_ptr< ReferredType > x) + { + this->referred_.set (std::move (x)); + } + + const Endpoint_type::StatusOptional& Endpoint_type:: + getStatus () const + { + return this->status_; + } + + Endpoint_type::StatusOptional& Endpoint_type:: + getStatus () + { + return this->status_; + } + + void Endpoint_type:: + setStatus (const StatusType& x) + { + this->status_.set (x); + } + + void Endpoint_type:: + setStatus (const StatusOptional& x) + { + this->status_ = x; + } + + void Endpoint_type:: + setStatus (::std::unique_ptr< StatusType > x) + { + this->status_.set (std::move (x)); + } + + const Endpoint_type::Joining_methodOptional& Endpoint_type:: + getJoining_method () const + { + return this->joining_method_; + } + + Endpoint_type::Joining_methodOptional& Endpoint_type:: + getJoining_method () + { + return this->joining_method_; + } + + void Endpoint_type:: + setJoining_method (const Joining_methodType& x) + { + this->joining_method_.set (x); + } + + void Endpoint_type:: + setJoining_method (const Joining_methodOptional& x) + { + this->joining_method_ = x; + } + + void Endpoint_type:: + setJoining_method (::std::unique_ptr< Joining_methodType > x) + { + this->joining_method_.set (std::move (x)); + } + + const Endpoint_type::Joining_infoOptional& Endpoint_type:: + getJoining_info () const + { + return this->joining_info_; + } + + Endpoint_type::Joining_infoOptional& Endpoint_type:: + getJoining_info () + { + return this->joining_info_; + } + + void Endpoint_type:: + setJoining_info (const Joining_infoType& x) + { + this->joining_info_.set (x); + } + + void Endpoint_type:: + setJoining_info (const Joining_infoOptional& x) + { + this->joining_info_ = x; + } + + void Endpoint_type:: + setJoining_info (::std::unique_ptr< Joining_infoType > x) + { + this->joining_info_.set (std::move (x)); + } + + const Endpoint_type::Disconnection_methodOptional& Endpoint_type:: + getDisconnection_method () const + { + return this->disconnection_method_; + } + + Endpoint_type::Disconnection_methodOptional& Endpoint_type:: + getDisconnection_method () + { + return this->disconnection_method_; + } + + void Endpoint_type:: + setDisconnection_method (const Disconnection_methodType& x) + { + this->disconnection_method_.set (x); + } + + void Endpoint_type:: + setDisconnection_method (const Disconnection_methodOptional& x) + { + this->disconnection_method_ = x; + } + + void Endpoint_type:: + setDisconnection_method (::std::unique_ptr< Disconnection_methodType > x) + { + this->disconnection_method_.set (std::move (x)); + } + + const Endpoint_type::Disconnection_infoOptional& Endpoint_type:: + getDisconnection_info () const + { + return this->disconnection_info_; + } + + Endpoint_type::Disconnection_infoOptional& Endpoint_type:: + getDisconnection_info () + { + return this->disconnection_info_; + } + + void Endpoint_type:: + setDisconnection_info (const Disconnection_infoType& x) + { + this->disconnection_info_.set (x); + } + + void Endpoint_type:: + setDisconnection_info (const Disconnection_infoOptional& x) + { + this->disconnection_info_ = x; + } + + void Endpoint_type:: + setDisconnection_info (::std::unique_ptr< Disconnection_infoType > x) + { + this->disconnection_info_.set (std::move (x)); + } + + const Endpoint_type::MediaSequence& Endpoint_type:: + getMedia () const + { + return this->media_; + } + + Endpoint_type::MediaSequence& Endpoint_type:: + getMedia () + { + return this->media_; + } + + void Endpoint_type:: + setMedia (const MediaSequence& s) + { + this->media_ = s; + } + + const Endpoint_type::Call_infoOptional& Endpoint_type:: + getCall_info () const + { + return this->call_info_; + } + + Endpoint_type::Call_infoOptional& Endpoint_type:: + getCall_info () + { + return this->call_info_; + } + + void Endpoint_type:: + setCall_info (const Call_infoType& x) + { + this->call_info_.set (x); + } + + void Endpoint_type:: + setCall_info (const Call_infoOptional& x) + { + this->call_info_ = x; + } + + void Endpoint_type:: + setCall_info (::std::unique_ptr< Call_infoType > x) + { + this->call_info_.set (std::move (x)); + } + + const Endpoint_type::AnySequence& Endpoint_type:: + getAny () const + { + return this->any_; + } + + Endpoint_type::AnySequence& Endpoint_type:: + getAny () + { + return this->any_; + } + + void Endpoint_type:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const Endpoint_type::EntityOptional& Endpoint_type:: + getEntity () const + { + return this->entity_; + } + + Endpoint_type::EntityOptional& Endpoint_type:: + getEntity () + { + return this->entity_; + } + + void Endpoint_type:: + setEntity (const EntityType& x) + { + this->entity_.set (x); + } + + void Endpoint_type:: + setEntity (const EntityOptional& x) + { + this->entity_ = x; + } + + void Endpoint_type:: + setEntity (::std::unique_ptr< EntityType > x) + { + this->entity_.set (std::move (x)); + } + + const Endpoint_type::StateType& Endpoint_type:: + getState () const + { + return this->state_.get (); + } + + Endpoint_type::StateType& Endpoint_type:: + getState () + { + return this->state_.get (); + } + + void Endpoint_type:: + setState (const StateType& x) + { + this->state_.set (x); + } + + void Endpoint_type:: + setState (::std::unique_ptr< StateType > x) + { + this->state_.set (std::move (x)); + } + + ::std::unique_ptr< Endpoint_type::StateType > Endpoint_type:: + detachState () + { + return this->state_.detach (); + } + + const Endpoint_type::StateType& Endpoint_type:: + getStateDefaultValue () + { + return state_default_value_; + } + + const Endpoint_type::AnyAttributeSet& Endpoint_type:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + Endpoint_type::AnyAttributeSet& Endpoint_type:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void Endpoint_type:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& Endpoint_type:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& Endpoint_type:: + getDomDocument () + { + return *this->dom_document_; + } + + + // Endpoint_status_type + // + + Endpoint_status_type:: + Endpoint_status_type (Value v) + : ::xml_schema::String (_xsd_Endpoint_status_type_literals_[v]) + { + } + + Endpoint_status_type:: + Endpoint_status_type (const char* v) + : ::xml_schema::String (v) + { + } + + Endpoint_status_type:: + Endpoint_status_type (const ::std::string& v) + : ::xml_schema::String (v) + { + } + + Endpoint_status_type:: + Endpoint_status_type (const ::xml_schema::String& v) + : ::xml_schema::String (v) + { + } + + Endpoint_status_type:: + Endpoint_status_type (const Endpoint_status_type& v, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (v, f, c) + { + } + + Endpoint_status_type& Endpoint_status_type:: + operator= (Value v) + { + static_cast< ::xml_schema::String& > (*this) = + ::xml_schema::String (_xsd_Endpoint_status_type_literals_[v]); + + return *this; + } + + + // Joining_type + // + + Joining_type:: + Joining_type (Value v) + : ::xml_schema::String (_xsd_Joining_type_literals_[v]) + { + } + + Joining_type:: + Joining_type (const char* v) + : ::xml_schema::String (v) + { + } + + Joining_type:: + Joining_type (const ::std::string& v) + : ::xml_schema::String (v) + { + } + + Joining_type:: + Joining_type (const ::xml_schema::String& v) + : ::xml_schema::String (v) + { + } + + Joining_type:: + Joining_type (const Joining_type& v, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (v, f, c) + { + } + + Joining_type& Joining_type:: + operator= (Value v) + { + static_cast< ::xml_schema::String& > (*this) = + ::xml_schema::String (_xsd_Joining_type_literals_[v]); + + return *this; + } + + + // Disconnection_type + // + + Disconnection_type:: + Disconnection_type (Value v) + : ::xml_schema::String (_xsd_Disconnection_type_literals_[v]) + { + } + + Disconnection_type:: + Disconnection_type (const char* v) + : ::xml_schema::String (v) + { + } + + Disconnection_type:: + Disconnection_type (const ::std::string& v) + : ::xml_schema::String (v) + { + } + + Disconnection_type:: + Disconnection_type (const ::xml_schema::String& v) + : ::xml_schema::String (v) + { + } + + Disconnection_type:: + Disconnection_type (const Disconnection_type& v, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (v, f, c) + { + } + + Disconnection_type& Disconnection_type:: + operator= (Value v) + { + static_cast< ::xml_schema::String& > (*this) = + ::xml_schema::String (_xsd_Disconnection_type_literals_[v]); + + return *this; + } + + + // Execution_type + // + + const Execution_type::WhenOptional& Execution_type:: + getWhen () const + { + return this->when_; + } + + Execution_type::WhenOptional& Execution_type:: + getWhen () + { + return this->when_; + } + + void Execution_type:: + setWhen (const WhenType& x) + { + this->when_.set (x); + } + + void Execution_type:: + setWhen (const WhenOptional& x) + { + this->when_ = x; + } + + void Execution_type:: + setWhen (::std::unique_ptr< WhenType > x) + { + this->when_.set (std::move (x)); + } + + const Execution_type::ReasonOptional& Execution_type:: + getReason () const + { + return this->reason_; + } + + Execution_type::ReasonOptional& Execution_type:: + getReason () + { + return this->reason_; + } + + void Execution_type:: + setReason (const ReasonType& x) + { + this->reason_.set (x); + } + + void Execution_type:: + setReason (const ReasonOptional& x) + { + this->reason_ = x; + } + + void Execution_type:: + setReason (::std::unique_ptr< ReasonType > x) + { + this->reason_.set (std::move (x)); + } + + const Execution_type::ByOptional& Execution_type:: + getBy () const + { + return this->by_; + } + + Execution_type::ByOptional& Execution_type:: + getBy () + { + return this->by_; + } + + void Execution_type:: + setBy (const ByType& x) + { + this->by_.set (x); + } + + void Execution_type:: + setBy (const ByOptional& x) + { + this->by_ = x; + } + + void Execution_type:: + setBy (::std::unique_ptr< ByType > x) + { + this->by_.set (std::move (x)); + } + + const Execution_type::AnyAttributeSet& Execution_type:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + Execution_type::AnyAttributeSet& Execution_type:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void Execution_type:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& Execution_type:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& Execution_type:: + getDomDocument () + { + return *this->dom_document_; + } + + + // Call_type + // + + const Call_type::SipOptional& Call_type:: + getSip () const + { + return this->sip_; + } + + Call_type::SipOptional& Call_type:: + getSip () + { + return this->sip_; + } + + void Call_type:: + setSip (const SipType& x) + { + this->sip_.set (x); + } + + void Call_type:: + setSip (const SipOptional& x) + { + this->sip_ = x; + } + + void Call_type:: + setSip (::std::unique_ptr< SipType > x) + { + this->sip_.set (std::move (x)); + } + + const Call_type::AnySequence& Call_type:: + getAny () const + { + return this->any_; + } + + Call_type::AnySequence& Call_type:: + getAny () + { + return this->any_; + } + + void Call_type:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const Call_type::AnyAttributeSet& Call_type:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + Call_type::AnyAttributeSet& Call_type:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void Call_type:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& Call_type:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& Call_type:: + getDomDocument () + { + return *this->dom_document_; + } + + + // Sip_dialog_id_type + // + + const Sip_dialog_id_type::Display_textOptional& Sip_dialog_id_type:: + getDisplay_text () const + { + return this->display_text_; + } + + Sip_dialog_id_type::Display_textOptional& Sip_dialog_id_type:: + getDisplay_text () + { + return this->display_text_; + } + + void Sip_dialog_id_type:: + setDisplay_text (const Display_textType& x) + { + this->display_text_.set (x); + } + + void Sip_dialog_id_type:: + setDisplay_text (const Display_textOptional& x) + { + this->display_text_ = x; + } + + void Sip_dialog_id_type:: + setDisplay_text (::std::unique_ptr< Display_textType > x) + { + this->display_text_.set (std::move (x)); + } + + const Sip_dialog_id_type::Call_idType& Sip_dialog_id_type:: + getCall_id () const + { + return this->call_id_.get (); + } + + Sip_dialog_id_type::Call_idType& Sip_dialog_id_type:: + getCall_id () + { + return this->call_id_.get (); + } + + void Sip_dialog_id_type:: + setCall_id (const Call_idType& x) + { + this->call_id_.set (x); + } + + void Sip_dialog_id_type:: + setCall_id (::std::unique_ptr< Call_idType > x) + { + this->call_id_.set (std::move (x)); + } + + ::std::unique_ptr< Sip_dialog_id_type::Call_idType > Sip_dialog_id_type:: + detachCall_id () + { + return this->call_id_.detach (); + } + + const Sip_dialog_id_type::From_tagType& Sip_dialog_id_type:: + getFrom_tag () const + { + return this->from_tag_.get (); + } + + Sip_dialog_id_type::From_tagType& Sip_dialog_id_type:: + getFrom_tag () + { + return this->from_tag_.get (); + } + + void Sip_dialog_id_type:: + setFrom_tag (const From_tagType& x) + { + this->from_tag_.set (x); + } + + void Sip_dialog_id_type:: + setFrom_tag (::std::unique_ptr< From_tagType > x) + { + this->from_tag_.set (std::move (x)); + } + + ::std::unique_ptr< Sip_dialog_id_type::From_tagType > Sip_dialog_id_type:: + detachFrom_tag () + { + return this->from_tag_.detach (); + } + + const Sip_dialog_id_type::To_tagType& Sip_dialog_id_type:: + getTo_tag () const + { + return this->to_tag_.get (); + } + + Sip_dialog_id_type::To_tagType& Sip_dialog_id_type:: + getTo_tag () + { + return this->to_tag_.get (); + } + + void Sip_dialog_id_type:: + setTo_tag (const To_tagType& x) + { + this->to_tag_.set (x); + } + + void Sip_dialog_id_type:: + setTo_tag (::std::unique_ptr< To_tagType > x) + { + this->to_tag_.set (std::move (x)); + } + + ::std::unique_ptr< Sip_dialog_id_type::To_tagType > Sip_dialog_id_type:: + detachTo_tag () + { + return this->to_tag_.detach (); + } + + const Sip_dialog_id_type::AnySequence& Sip_dialog_id_type:: + getAny () const + { + return this->any_; + } + + Sip_dialog_id_type::AnySequence& Sip_dialog_id_type:: + getAny () + { + return this->any_; + } + + void Sip_dialog_id_type:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const Sip_dialog_id_type::AnyAttributeSet& Sip_dialog_id_type:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + Sip_dialog_id_type::AnyAttributeSet& Sip_dialog_id_type:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void Sip_dialog_id_type:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& Sip_dialog_id_type:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& Sip_dialog_id_type:: + getDomDocument () + { + return *this->dom_document_; + } + + + // Media_type + // + + const Media_type::Display_textOptional& Media_type:: + getDisplay_text () const + { + return this->display_text_; + } + + Media_type::Display_textOptional& Media_type:: + getDisplay_text () + { + return this->display_text_; + } + + void Media_type:: + setDisplay_text (const Display_textType& x) + { + this->display_text_.set (x); + } + + void Media_type:: + setDisplay_text (const Display_textOptional& x) + { + this->display_text_ = x; + } + + void Media_type:: + setDisplay_text (::std::unique_ptr< Display_textType > x) + { + this->display_text_.set (std::move (x)); + } + + const Media_type::TypeOptional& Media_type:: + getType () const + { + return this->type_; + } + + Media_type::TypeOptional& Media_type:: + getType () + { + return this->type_; + } + + void Media_type:: + setType (const TypeType& x) + { + this->type_.set (x); + } + + void Media_type:: + setType (const TypeOptional& x) + { + this->type_ = x; + } + + void Media_type:: + setType (::std::unique_ptr< TypeType > x) + { + this->type_.set (std::move (x)); + } + + const Media_type::LabelOptional& Media_type:: + getLabel () const + { + return this->label_; + } + + Media_type::LabelOptional& Media_type:: + getLabel () + { + return this->label_; + } + + void Media_type:: + setLabel (const LabelType& x) + { + this->label_.set (x); + } + + void Media_type:: + setLabel (const LabelOptional& x) + { + this->label_ = x; + } + + void Media_type:: + setLabel (::std::unique_ptr< LabelType > x) + { + this->label_.set (std::move (x)); + } + + const Media_type::Src_idOptional& Media_type:: + getSrc_id () const + { + return this->src_id_; + } + + Media_type::Src_idOptional& Media_type:: + getSrc_id () + { + return this->src_id_; + } + + void Media_type:: + setSrc_id (const Src_idType& x) + { + this->src_id_.set (x); + } + + void Media_type:: + setSrc_id (const Src_idOptional& x) + { + this->src_id_ = x; + } + + void Media_type:: + setSrc_id (::std::unique_ptr< Src_idType > x) + { + this->src_id_.set (std::move (x)); + } + + const Media_type::StatusOptional& Media_type:: + getStatus () const + { + return this->status_; + } + + Media_type::StatusOptional& Media_type:: + getStatus () + { + return this->status_; + } + + void Media_type:: + setStatus (const StatusType& x) + { + this->status_.set (x); + } + + void Media_type:: + setStatus (const StatusOptional& x) + { + this->status_ = x; + } + + void Media_type:: + setStatus (::std::unique_ptr< StatusType > x) + { + this->status_.set (std::move (x)); + } + + const Media_type::AnySequence& Media_type:: + getAny () const + { + return this->any_; + } + + Media_type::AnySequence& Media_type:: + getAny () + { + return this->any_; + } + + void Media_type:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const Media_type::IdType& Media_type:: + getId () const + { + return this->id_.get (); + } + + Media_type::IdType& Media_type:: + getId () + { + return this->id_.get (); + } + + void Media_type:: + setId (const IdType& x) + { + this->id_.set (x); + } + + void Media_type:: + setId (::std::unique_ptr< IdType > x) + { + this->id_.set (std::move (x)); + } + + ::std::unique_ptr< Media_type::IdType > Media_type:: + detachId () + { + return this->id_.detach (); + } + + const Media_type::AnyAttributeSet& Media_type:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + Media_type::AnyAttributeSet& Media_type:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void Media_type:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& Media_type:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& Media_type:: + getDomDocument () + { + return *this->dom_document_; + } + + + // Media_status_type + // + + Media_status_type:: + Media_status_type (Value v) + : ::xml_schema::String (_xsd_Media_status_type_literals_[v]) + { + } + + Media_status_type:: + Media_status_type (const char* v) + : ::xml_schema::String (v) + { + } + + Media_status_type:: + Media_status_type (const ::std::string& v) + : ::xml_schema::String (v) + { + } + + Media_status_type:: + Media_status_type (const ::xml_schema::String& v) + : ::xml_schema::String (v) + { + } + + Media_status_type:: + Media_status_type (const Media_status_type& v, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (v, f, c) + { + } + + Media_status_type& Media_status_type:: + operator= (Value v) + { + static_cast< ::xml_schema::String& > (*this) = + ::xml_schema::String (_xsd_Media_status_type_literals_[v]); + + return *this; + } + + + // Sidebars_by_val_type + // + + const Sidebars_by_val_type::EntrySequence& Sidebars_by_val_type:: + getEntry () const + { + return this->entry_; + } + + Sidebars_by_val_type::EntrySequence& Sidebars_by_val_type:: + getEntry () + { + return this->entry_; + } + + void Sidebars_by_val_type:: + setEntry (const EntrySequence& s) + { + this->entry_ = s; + } + + const Sidebars_by_val_type::StateType& Sidebars_by_val_type:: + getState () const + { + return this->state_.get (); + } + + Sidebars_by_val_type::StateType& Sidebars_by_val_type:: + getState () + { + return this->state_.get (); + } + + void Sidebars_by_val_type:: + setState (const StateType& x) + { + this->state_.set (x); + } + + void Sidebars_by_val_type:: + setState (::std::unique_ptr< StateType > x) + { + this->state_.set (std::move (x)); + } + + ::std::unique_ptr< Sidebars_by_val_type::StateType > Sidebars_by_val_type:: + detachState () + { + return this->state_.detach (); + } + + const Sidebars_by_val_type::StateType& Sidebars_by_val_type:: + getStateDefaultValue () + { + return state_default_value_; + } + + const Sidebars_by_val_type::AnyAttributeSet& Sidebars_by_val_type:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + Sidebars_by_val_type::AnyAttributeSet& Sidebars_by_val_type:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void Sidebars_by_val_type:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& Sidebars_by_val_type:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& Sidebars_by_val_type:: + getDomDocument () + { + return *this->dom_document_; + } +} + +#include + +#include + +namespace conference_info +{ + // Conference_type + // + + const Conference_type::StateType Conference_type::state_default_value_ ( + "full"); + + Conference_type:: + Conference_type (const EntityType& entity) + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + conference_description_ (this), + host_info_ (this), + conference_state_ (this), + users_ (this), + sidebars_by_ref_ (this), + sidebars_by_val_ (this), + any_ (this->getDomDocument ()), + entity_ (entity, this), + state_ (getStateDefaultValue (), this), + version_ (this), + any_attribute_ (this->getDomDocument ()) + { + } + + Conference_type:: + Conference_type (const Conference_type& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + conference_description_ (x.conference_description_, f, this), + host_info_ (x.host_info_, f, this), + conference_state_ (x.conference_state_, f, this), + users_ (x.users_, f, this), + sidebars_by_ref_ (x.sidebars_by_ref_, f, this), + sidebars_by_val_ (x.sidebars_by_val_, f, this), + any_ (x.any_, this->getDomDocument ()), + entity_ (x.entity_, f, this), + state_ (x.state_, f, this), + version_ (x.version_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + Conference_type:: + Conference_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + conference_description_ (this), + host_info_ (this), + conference_state_ (this), + users_ (this), + sidebars_by_ref_ (this), + sidebars_by_val_ (this), + any_ (this->getDomDocument ()), + entity_ (this), + state_ (this), + version_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void Conference_type:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // conference-description + // + if (n.name () == "conference-description" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Conference_descriptionType > r ( + Conference_descriptionTraits::create (i, f, this)); + + if (!this->conference_description_) + { + this->conference_description_.set (::std::move (r)); + continue; + } + } + + // host-info + // + if (n.name () == "host-info" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Host_infoType > r ( + Host_infoTraits::create (i, f, this)); + + if (!this->host_info_) + { + this->host_info_.set (::std::move (r)); + continue; + } + } + + // conference-state + // + if (n.name () == "conference-state" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Conference_stateType > r ( + Conference_stateTraits::create (i, f, this)); + + if (!this->conference_state_) + { + this->conference_state_.set (::std::move (r)); + continue; + } + } + + // users + // + if (n.name () == "users" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< UsersType > r ( + UsersTraits::create (i, f, this)); + + if (!this->users_) + { + this->users_.set (::std::move (r)); + continue; + } + } + + // sidebars-by-ref + // + if (n.name () == "sidebars-by-ref" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Sidebars_by_refType > r ( + Sidebars_by_refTraits::create (i, f, this)); + + if (!this->sidebars_by_ref_) + { + this->sidebars_by_ref_.set (::std::move (r)); + continue; + } + } + + // sidebars-by-val + // + if (n.name () == "sidebars-by-val" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Sidebars_by_valType > r ( + Sidebars_by_valTraits::create (i, f, this)); + + if (!this->sidebars_by_val_) + { + this->sidebars_by_val_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "entity" && n.namespace_ ().empty ()) + { + this->entity_.set (EntityTraits::create (i, f, this)); + continue; + } + + if (n.name () == "state" && n.namespace_ ().empty ()) + { + this->state_.set (StateTraits::create (i, f, this)); + continue; + } + + if (n.name () == "version" && n.namespace_ ().empty ()) + { + this->version_.set (VersionTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + + if (!entity_.present ()) + { + throw ::xsd::cxx::tree::expected_attribute< char > ( + "entity", + ""); + } + + if (!state_.present ()) + { + this->state_.set (getStateDefaultValue ()); + } + } + + Conference_type* Conference_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Conference_type (*this, f, c); + } + + Conference_type& Conference_type:: + operator= (const Conference_type& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->conference_description_ = x.conference_description_; + this->host_info_ = x.host_info_; + this->conference_state_ = x.conference_state_; + this->users_ = x.users_; + this->sidebars_by_ref_ = x.sidebars_by_ref_; + this->sidebars_by_val_ = x.sidebars_by_val_; + this->any_ = x.any_; + this->entity_ = x.entity_; + this->state_ = x.state_; + this->version_ = x.version_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + Conference_type:: + ~Conference_type () + { + } + + // State_type + // + + State_type:: + State_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (e, f, c) + { + _xsd_State_type_convert (); + } + + State_type:: + State_type (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (a, f, c) + { + _xsd_State_type_convert (); + } + + State_type:: + State_type (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (s, e, f, c) + { + _xsd_State_type_convert (); + } + + State_type* State_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class State_type (*this, f, c); + } + + State_type::Value State_type:: + _xsd_State_type_convert () const + { + ::xsd::cxx::tree::enum_comparator< char > c (_xsd_State_type_literals_); + const Value* i (::std::lower_bound ( + _xsd_State_type_indexes_, + _xsd_State_type_indexes_ + 3, + *this, + c)); + + if (i == _xsd_State_type_indexes_ + 3 || _xsd_State_type_literals_[*i] != *this) + { + throw ::xsd::cxx::tree::unexpected_enumerator < char > (*this); + } + + return *i; + } + + const char* const State_type:: + _xsd_State_type_literals_[3] = + { + "full", + "partial", + "deleted" + }; + + const State_type::Value State_type:: + _xsd_State_type_indexes_[3] = + { + ::conference_info::State_type::deleted, + ::conference_info::State_type::full, + ::conference_info::State_type::partial + }; + + // Conference_description_type + // + + Conference_description_type:: + Conference_description_type () + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + subject_ (this), + free_text_ (this), + keywords_ (this), + conf_uris_ (this), + service_uris_ (this), + maximum_user_count_ (this), + available_media_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + } + + Conference_description_type:: + Conference_description_type (const Conference_description_type& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (x.display_text_, f, this), + subject_ (x.subject_, f, this), + free_text_ (x.free_text_, f, this), + keywords_ (x.keywords_, f, this), + conf_uris_ (x.conf_uris_, f, this), + service_uris_ (x.service_uris_, f, this), + maximum_user_count_ (x.maximum_user_count_, f, this), + available_media_ (x.available_media_, f, this), + any_ (x.any_, this->getDomDocument ()), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + Conference_description_type:: + Conference_description_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + subject_ (this), + free_text_ (this), + keywords_ (this), + conf_uris_ (this), + service_uris_ (this), + maximum_user_count_ (this), + available_media_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void Conference_description_type:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-text + // + if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Display_textType > r ( + Display_textTraits::create (i, f, this)); + + if (!this->display_text_) + { + this->display_text_.set (::std::move (r)); + continue; + } + } + + // subject + // + if (n.name () == "subject" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< SubjectType > r ( + SubjectTraits::create (i, f, this)); + + if (!this->subject_) + { + this->subject_.set (::std::move (r)); + continue; + } + } + + // free-text + // + if (n.name () == "free-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Free_textType > r ( + Free_textTraits::create (i, f, this)); + + if (!this->free_text_) + { + this->free_text_.set (::std::move (r)); + continue; + } + } + + // keywords + // + if (n.name () == "keywords" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< KeywordsType > r ( + KeywordsTraits::create (i, f, this)); + + if (!this->keywords_) + { + this->keywords_.set (::std::move (r)); + continue; + } + } + + // conf-uris + // + if (n.name () == "conf-uris" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Conf_urisType > r ( + Conf_urisTraits::create (i, f, this)); + + if (!this->conf_uris_) + { + this->conf_uris_.set (::std::move (r)); + continue; + } + } + + // service-uris + // + if (n.name () == "service-uris" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Service_urisType > r ( + Service_urisTraits::create (i, f, this)); + + if (!this->service_uris_) + { + this->service_uris_.set (::std::move (r)); + continue; + } + } + + // maximum-user-count + // + if (n.name () == "maximum-user-count" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + if (!this->maximum_user_count_) + { + this->maximum_user_count_.set (Maximum_user_countTraits::create (i, f, this)); + continue; + } + } + + // available-media + // + if (n.name () == "available-media" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Available_mediaType > r ( + Available_mediaTraits::create (i, f, this)); + + if (!this->available_media_) + { + this->available_media_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + } + + Conference_description_type* Conference_description_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Conference_description_type (*this, f, c); + } + + Conference_description_type& Conference_description_type:: + operator= (const Conference_description_type& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->display_text_ = x.display_text_; + this->subject_ = x.subject_; + this->free_text_ = x.free_text_; + this->keywords_ = x.keywords_; + this->conf_uris_ = x.conf_uris_; + this->service_uris_ = x.service_uris_; + this->maximum_user_count_ = x.maximum_user_count_; + this->available_media_ = x.available_media_; + this->any_ = x.any_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + Conference_description_type:: + ~Conference_description_type () + { + } + + // Host_type + // + + Host_type:: + Host_type () + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + web_page_ (this), + uris_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + } + + Host_type:: + Host_type (const Host_type& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (x.display_text_, f, this), + web_page_ (x.web_page_, f, this), + uris_ (x.uris_, f, this), + any_ (x.any_, this->getDomDocument ()), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + Host_type:: + Host_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + web_page_ (this), + uris_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void Host_type:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-text + // + if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Display_textType > r ( + Display_textTraits::create (i, f, this)); + + if (!this->display_text_) + { + this->display_text_.set (::std::move (r)); + continue; + } + } + + // web-page + // + if (n.name () == "web-page" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Web_pageType > r ( + Web_pageTraits::create (i, f, this)); + + if (!this->web_page_) + { + this->web_page_.set (::std::move (r)); + continue; + } + } + + // uris + // + if (n.name () == "uris" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< UrisType > r ( + UrisTraits::create (i, f, this)); + + if (!this->uris_) + { + this->uris_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + } + + Host_type* Host_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Host_type (*this, f, c); + } + + Host_type& Host_type:: + operator= (const Host_type& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->display_text_ = x.display_text_; + this->web_page_ = x.web_page_; + this->uris_ = x.uris_; + this->any_ = x.any_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + Host_type:: + ~Host_type () + { + } + + // Conference_state_type + // + + Conference_state_type:: + Conference_state_type () + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + user_count_ (this), + active_ (this), + locked_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + } + + Conference_state_type:: + Conference_state_type (const Conference_state_type& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + user_count_ (x.user_count_, f, this), + active_ (x.active_, f, this), + locked_ (x.locked_, f, this), + any_ (x.any_, this->getDomDocument ()), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + Conference_state_type:: + Conference_state_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + user_count_ (this), + active_ (this), + locked_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void Conference_state_type:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // user-count + // + if (n.name () == "user-count" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + if (!this->user_count_) + { + this->user_count_.set (User_countTraits::create (i, f, this)); + continue; + } + } + + // active + // + if (n.name () == "active" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + if (!this->active_) + { + this->active_.set (ActiveTraits::create (i, f, this)); + continue; + } + } + + // locked + // + if (n.name () == "locked" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + if (!this->locked_) + { + this->locked_.set (LockedTraits::create (i, f, this)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + } + + Conference_state_type* Conference_state_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Conference_state_type (*this, f, c); + } + + Conference_state_type& Conference_state_type:: + operator= (const Conference_state_type& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->user_count_ = x.user_count_; + this->active_ = x.active_; + this->locked_ = x.locked_; + this->any_ = x.any_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + Conference_state_type:: + ~Conference_state_type () + { + } + + // Conference_media_type + // + + Conference_media_type:: + Conference_media_type () + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (this), + any_attribute_ (this->getDomDocument ()) + { + } + + Conference_media_type:: + Conference_media_type (const Conference_media_type& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (x.entry_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + Conference_media_type:: + Conference_media_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void Conference_media_type:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // entry + // + if (n.name () == "entry" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< EntryType > r ( + EntryTraits::create (i, f, this)); + + this->entry_.push_back (::std::move (r)); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + } + + Conference_media_type* Conference_media_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Conference_media_type (*this, f, c); + } + + Conference_media_type& Conference_media_type:: + operator= (const Conference_media_type& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->entry_ = x.entry_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + Conference_media_type:: + ~Conference_media_type () + { + } + + // Conference_medium_type + // + + Conference_medium_type:: + Conference_medium_type (const TypeType& type, + const LabelType& label) + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + type_ (type, this), + status_ (this), + any_ (this->getDomDocument ()), + label_ (label, this), + any_attribute_ (this->getDomDocument ()) + { + } + + Conference_medium_type:: + Conference_medium_type (const Conference_medium_type& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (x.display_text_, f, this), + type_ (x.type_, f, this), + status_ (x.status_, f, this), + any_ (x.any_, this->getDomDocument ()), + label_ (x.label_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + Conference_medium_type:: + Conference_medium_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + type_ (this), + status_ (this), + any_ (this->getDomDocument ()), + label_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void Conference_medium_type:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-text + // + if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Display_textType > r ( + Display_textTraits::create (i, f, this)); + + if (!this->display_text_) + { + this->display_text_.set (::std::move (r)); + continue; + } + } + + // type + // + if (n.name () == "type" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< TypeType > r ( + TypeTraits::create (i, f, this)); + + if (!type_.present ()) + { + this->type_.set (::std::move (r)); + continue; + } + } + + // status + // + if (n.name () == "status" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< StatusType > r ( + StatusTraits::create (i, f, this)); + + if (!this->status_) + { + this->status_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + if (!type_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "type", + "urn:ietf:params:xml:ns:conference-info"); + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "label" && n.namespace_ ().empty ()) + { + this->label_.set (LabelTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + + if (!label_.present ()) + { + throw ::xsd::cxx::tree::expected_attribute< char > ( + "label", + ""); + } + } + + Conference_medium_type* Conference_medium_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Conference_medium_type (*this, f, c); + } + + Conference_medium_type& Conference_medium_type:: + operator= (const Conference_medium_type& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->display_text_ = x.display_text_; + this->type_ = x.type_; + this->status_ = x.status_; + this->any_ = x.any_; + this->label_ = x.label_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + Conference_medium_type:: + ~Conference_medium_type () + { + } + + // Uris_type + // + + const Uris_type::StateType Uris_type::state_default_value_ ( + "full"); + + Uris_type:: + Uris_type () + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (this), + state_ (getStateDefaultValue (), this), + any_attribute_ (this->getDomDocument ()) + { + } + + Uris_type:: + Uris_type (const Uris_type& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (x.entry_, f, this), + state_ (x.state_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + Uris_type:: + Uris_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (this), + state_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void Uris_type:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // entry + // + if (n.name () == "entry" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< EntryType > r ( + EntryTraits::create (i, f, this)); + + this->entry_.push_back (::std::move (r)); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "state" && n.namespace_ ().empty ()) + { + this->state_.set (StateTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + + if (!state_.present ()) + { + this->state_.set (getStateDefaultValue ()); + } + } + + Uris_type* Uris_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Uris_type (*this, f, c); + } + + Uris_type& Uris_type:: + operator= (const Uris_type& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->entry_ = x.entry_; + this->state_ = x.state_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + Uris_type:: + ~Uris_type () + { + } + + // Uri_type + // + + Uri_type:: + Uri_type (const UriType& uri) + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + uri_ (uri, this), + display_text_ (this), + purpose_ (this), + modified_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + } + + Uri_type:: + Uri_type (const Uri_type& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + uri_ (x.uri_, f, this), + display_text_ (x.display_text_, f, this), + purpose_ (x.purpose_, f, this), + modified_ (x.modified_, f, this), + any_ (x.any_, this->getDomDocument ()), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + Uri_type:: + Uri_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + uri_ (this), + display_text_ (this), + purpose_ (this), + modified_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void Uri_type:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // uri + // + if (n.name () == "uri" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< UriType > r ( + UriTraits::create (i, f, this)); + + if (!uri_.present ()) + { + this->uri_.set (::std::move (r)); + continue; + } + } + + // display-text + // + if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Display_textType > r ( + Display_textTraits::create (i, f, this)); + + if (!this->display_text_) + { + this->display_text_.set (::std::move (r)); + continue; + } + } + + // purpose + // + if (n.name () == "purpose" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< PurposeType > r ( + PurposeTraits::create (i, f, this)); + + if (!this->purpose_) + { + this->purpose_.set (::std::move (r)); + continue; + } + } + + // modified + // + if (n.name () == "modified" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< ModifiedType > r ( + ModifiedTraits::create (i, f, this)); + + if (!this->modified_) + { + this->modified_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + if (!uri_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "uri", + "urn:ietf:params:xml:ns:conference-info"); + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + } + + Uri_type* Uri_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Uri_type (*this, f, c); + } + + Uri_type& Uri_type:: + operator= (const Uri_type& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->uri_ = x.uri_; + this->display_text_ = x.display_text_; + this->purpose_ = x.purpose_; + this->modified_ = x.modified_; + this->any_ = x.any_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + Uri_type:: + ~Uri_type () + { + } + + // Keywords_type + // + + Keywords_type:: + Keywords_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::SimpleType (e, f, c), + ::xsd::cxx::tree::list< ::xml_schema::String, char > (e, f, this) + { + } + + Keywords_type:: + Keywords_type (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::SimpleType (a, f, c), + ::xsd::cxx::tree::list< ::xml_schema::String, char > (a, f, this) + { + } + + Keywords_type:: + Keywords_type (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::SimpleType (s, e, f, c), + ::xsd::cxx::tree::list< ::xml_schema::String, char > (s, e, f, this) + { + } + + Keywords_type* Keywords_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Keywords_type (*this, f, c); + } + + Keywords_type:: + ~Keywords_type () + { + } + + // Users_type + // + + const Users_type::StateType Users_type::state_default_value_ ( + "full"); + + Users_type:: + Users_type () + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + user_ (this), + any_ (this->getDomDocument ()), + state_ (getStateDefaultValue (), this), + any_attribute_ (this->getDomDocument ()) + { + } + + Users_type:: + Users_type (const Users_type& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + user_ (x.user_, f, this), + any_ (x.any_, this->getDomDocument ()), + state_ (x.state_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + Users_type:: + Users_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + user_ (this), + any_ (this->getDomDocument ()), + state_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void Users_type:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // user + // + if (n.name () == "user" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< UserType > r ( + UserTraits::create (i, f, this)); + + this->user_.push_back (::std::move (r)); + continue; + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "state" && n.namespace_ ().empty ()) + { + this->state_.set (StateTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + + if (!state_.present ()) + { + this->state_.set (getStateDefaultValue ()); + } + } + + Users_type* Users_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Users_type (*this, f, c); + } + + Users_type& Users_type:: + operator= (const Users_type& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->user_ = x.user_; + this->any_ = x.any_; + this->state_ = x.state_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + Users_type:: + ~Users_type () + { + } + + // User_type + // + + const User_type::StateType User_type::state_default_value_ ( + "full"); + + User_type:: + User_type () + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + associated_aors_ (this), + roles_ (this), + languages_ (this), + cascaded_focus_ (this), + endpoint_ (this), + any_ (this->getDomDocument ()), + entity_ (this), + state_ (getStateDefaultValue (), this), + any_attribute_ (this->getDomDocument ()) + { + } + + User_type:: + User_type (const User_type& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (x.display_text_, f, this), + associated_aors_ (x.associated_aors_, f, this), + roles_ (x.roles_, f, this), + languages_ (x.languages_, f, this), + cascaded_focus_ (x.cascaded_focus_, f, this), + endpoint_ (x.endpoint_, f, this), + any_ (x.any_, this->getDomDocument ()), + entity_ (x.entity_, f, this), + state_ (x.state_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + User_type:: + User_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + associated_aors_ (this), + roles_ (this), + languages_ (this), + cascaded_focus_ (this), + endpoint_ (this), + any_ (this->getDomDocument ()), + entity_ (this), + state_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void User_type:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-text + // + if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Display_textType > r ( + Display_textTraits::create (i, f, this)); + + if (!this->display_text_) + { + this->display_text_.set (::std::move (r)); + continue; + } + } + + // associated-aors + // + if (n.name () == "associated-aors" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Associated_aorsType > r ( + Associated_aorsTraits::create (i, f, this)); + + if (!this->associated_aors_) + { + this->associated_aors_.set (::std::move (r)); + continue; + } + } + + // roles + // + if (n.name () == "roles" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< RolesType > r ( + RolesTraits::create (i, f, this)); + + if (!this->roles_) + { + this->roles_.set (::std::move (r)); + continue; + } + } + + // languages + // + if (n.name () == "languages" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< LanguagesType > r ( + LanguagesTraits::create (i, f, this)); + + if (!this->languages_) + { + this->languages_.set (::std::move (r)); + continue; + } + } + + // cascaded-focus + // + if (n.name () == "cascaded-focus" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Cascaded_focusType > r ( + Cascaded_focusTraits::create (i, f, this)); + + if (!this->cascaded_focus_) + { + this->cascaded_focus_.set (::std::move (r)); + continue; + } + } + + // endpoint + // + if (n.name () == "endpoint" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< EndpointType > r ( + EndpointTraits::create (i, f, this)); + + this->endpoint_.push_back (::std::move (r)); + continue; + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "entity" && n.namespace_ ().empty ()) + { + this->entity_.set (EntityTraits::create (i, f, this)); + continue; + } + + if (n.name () == "state" && n.namespace_ ().empty ()) + { + this->state_.set (StateTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + + if (!state_.present ()) + { + this->state_.set (getStateDefaultValue ()); + } + } + + User_type* User_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class User_type (*this, f, c); + } + + User_type& User_type:: + operator= (const User_type& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->display_text_ = x.display_text_; + this->associated_aors_ = x.associated_aors_; + this->roles_ = x.roles_; + this->languages_ = x.languages_; + this->cascaded_focus_ = x.cascaded_focus_; + this->endpoint_ = x.endpoint_; + this->any_ = x.any_; + this->entity_ = x.entity_; + this->state_ = x.state_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + User_type:: + ~User_type () + { + } + + // User_roles_type + // + + User_roles_type:: + User_roles_type () + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (this), + any_attribute_ (this->getDomDocument ()) + { + } + + User_roles_type:: + User_roles_type (const User_roles_type& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (x.entry_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + User_roles_type:: + User_roles_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void User_roles_type:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // entry + // + if (n.name () == "entry" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< EntryType > r ( + EntryTraits::create (i, f, this)); + + this->entry_.push_back (::std::move (r)); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + } + + User_roles_type* User_roles_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class User_roles_type (*this, f, c); + } + + User_roles_type& User_roles_type:: + operator= (const User_roles_type& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->entry_ = x.entry_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + User_roles_type:: + ~User_roles_type () + { + } + + // User_languages_type + // + + User_languages_type:: + User_languages_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::SimpleType (e, f, c), + ::xsd::cxx::tree::list< ::xml_schema::Language, char > (e, f, this) + { + } + + User_languages_type:: + User_languages_type (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::SimpleType (a, f, c), + ::xsd::cxx::tree::list< ::xml_schema::Language, char > (a, f, this) + { + } + + User_languages_type:: + User_languages_type (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::SimpleType (s, e, f, c), + ::xsd::cxx::tree::list< ::xml_schema::Language, char > (s, e, f, this) + { + } + + User_languages_type* User_languages_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class User_languages_type (*this, f, c); + } + + User_languages_type:: + ~User_languages_type () + { + } + + // Endpoint_type + // + + const Endpoint_type::StateType Endpoint_type::state_default_value_ ( + "full"); + + Endpoint_type:: + Endpoint_type () + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + referred_ (this), + status_ (this), + joining_method_ (this), + joining_info_ (this), + disconnection_method_ (this), + disconnection_info_ (this), + media_ (this), + call_info_ (this), + any_ (this->getDomDocument ()), + entity_ (this), + state_ (getStateDefaultValue (), this), + any_attribute_ (this->getDomDocument ()) + { + } + + Endpoint_type:: + Endpoint_type (const Endpoint_type& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (x.display_text_, f, this), + referred_ (x.referred_, f, this), + status_ (x.status_, f, this), + joining_method_ (x.joining_method_, f, this), + joining_info_ (x.joining_info_, f, this), + disconnection_method_ (x.disconnection_method_, f, this), + disconnection_info_ (x.disconnection_info_, f, this), + media_ (x.media_, f, this), + call_info_ (x.call_info_, f, this), + any_ (x.any_, this->getDomDocument ()), + entity_ (x.entity_, f, this), + state_ (x.state_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + Endpoint_type:: + Endpoint_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + referred_ (this), + status_ (this), + joining_method_ (this), + joining_info_ (this), + disconnection_method_ (this), + disconnection_info_ (this), + media_ (this), + call_info_ (this), + any_ (this->getDomDocument ()), + entity_ (this), + state_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void Endpoint_type:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-text + // + if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Display_textType > r ( + Display_textTraits::create (i, f, this)); + + if (!this->display_text_) + { + this->display_text_.set (::std::move (r)); + continue; + } + } + + // referred + // + if (n.name () == "referred" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< ReferredType > r ( + ReferredTraits::create (i, f, this)); + + if (!this->referred_) + { + this->referred_.set (::std::move (r)); + continue; + } + } + + // status + // + if (n.name () == "status" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< StatusType > r ( + StatusTraits::create (i, f, this)); + + if (!this->status_) + { + this->status_.set (::std::move (r)); + continue; + } + } + + // joining-method + // + if (n.name () == "joining-method" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Joining_methodType > r ( + Joining_methodTraits::create (i, f, this)); + + if (!this->joining_method_) + { + this->joining_method_.set (::std::move (r)); + continue; + } + } + + // joining-info + // + if (n.name () == "joining-info" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Joining_infoType > r ( + Joining_infoTraits::create (i, f, this)); + + if (!this->joining_info_) + { + this->joining_info_.set (::std::move (r)); + continue; + } + } + + // disconnection-method + // + if (n.name () == "disconnection-method" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Disconnection_methodType > r ( + Disconnection_methodTraits::create (i, f, this)); + + if (!this->disconnection_method_) + { + this->disconnection_method_.set (::std::move (r)); + continue; + } + } + + // disconnection-info + // + if (n.name () == "disconnection-info" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Disconnection_infoType > r ( + Disconnection_infoTraits::create (i, f, this)); + + if (!this->disconnection_info_) + { + this->disconnection_info_.set (::std::move (r)); + continue; + } + } + + // media + // + if (n.name () == "media" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< MediaType > r ( + MediaTraits::create (i, f, this)); + + this->media_.push_back (::std::move (r)); + continue; + } + + // call-info + // + if (n.name () == "call-info" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Call_infoType > r ( + Call_infoTraits::create (i, f, this)); + + if (!this->call_info_) + { + this->call_info_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "entity" && n.namespace_ ().empty ()) + { + this->entity_.set (EntityTraits::create (i, f, this)); + continue; + } + + if (n.name () == "state" && n.namespace_ ().empty ()) + { + this->state_.set (StateTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + + if (!state_.present ()) + { + this->state_.set (getStateDefaultValue ()); + } + } + + Endpoint_type* Endpoint_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Endpoint_type (*this, f, c); + } + + Endpoint_type& Endpoint_type:: + operator= (const Endpoint_type& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->display_text_ = x.display_text_; + this->referred_ = x.referred_; + this->status_ = x.status_; + this->joining_method_ = x.joining_method_; + this->joining_info_ = x.joining_info_; + this->disconnection_method_ = x.disconnection_method_; + this->disconnection_info_ = x.disconnection_info_; + this->media_ = x.media_; + this->call_info_ = x.call_info_; + this->any_ = x.any_; + this->entity_ = x.entity_; + this->state_ = x.state_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + Endpoint_type:: + ~Endpoint_type () + { + } + + // Endpoint_status_type + // + + Endpoint_status_type:: + Endpoint_status_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (e, f, c) + { + _xsd_Endpoint_status_type_convert (); + } + + Endpoint_status_type:: + Endpoint_status_type (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (a, f, c) + { + _xsd_Endpoint_status_type_convert (); + } + + Endpoint_status_type:: + Endpoint_status_type (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (s, e, f, c) + { + _xsd_Endpoint_status_type_convert (); + } + + Endpoint_status_type* Endpoint_status_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Endpoint_status_type (*this, f, c); + } + + Endpoint_status_type::Value Endpoint_status_type:: + _xsd_Endpoint_status_type_convert () const + { + ::xsd::cxx::tree::enum_comparator< char > c (_xsd_Endpoint_status_type_literals_); + const Value* i (::std::lower_bound ( + _xsd_Endpoint_status_type_indexes_, + _xsd_Endpoint_status_type_indexes_ + 9, + *this, + c)); + + if (i == _xsd_Endpoint_status_type_indexes_ + 9 || _xsd_Endpoint_status_type_literals_[*i] != *this) + { + throw ::xsd::cxx::tree::unexpected_enumerator < char > (*this); + } + + return *i; + } + + const char* const Endpoint_status_type:: + _xsd_Endpoint_status_type_literals_[9] = + { + "pending", + "dialing-out", + "dialing-in", + "alerting", + "on-hold", + "connected", + "muted-via-focus", + "disconnecting", + "disconnected" + }; + + const Endpoint_status_type::Value Endpoint_status_type:: + _xsd_Endpoint_status_type_indexes_[9] = + { + ::conference_info::Endpoint_status_type::alerting, + ::conference_info::Endpoint_status_type::connected, + ::conference_info::Endpoint_status_type::dialing_in, + ::conference_info::Endpoint_status_type::dialing_out, + ::conference_info::Endpoint_status_type::disconnected, + ::conference_info::Endpoint_status_type::disconnecting, + ::conference_info::Endpoint_status_type::muted_via_focus, + ::conference_info::Endpoint_status_type::on_hold, + ::conference_info::Endpoint_status_type::pending + }; + + // Joining_type + // + + Joining_type:: + Joining_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (e, f, c) + { + _xsd_Joining_type_convert (); + } + + Joining_type:: + Joining_type (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (a, f, c) + { + _xsd_Joining_type_convert (); + } + + Joining_type:: + Joining_type (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (s, e, f, c) + { + _xsd_Joining_type_convert (); + } + + Joining_type* Joining_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Joining_type (*this, f, c); + } + + Joining_type::Value Joining_type:: + _xsd_Joining_type_convert () const + { + ::xsd::cxx::tree::enum_comparator< char > c (_xsd_Joining_type_literals_); + const Value* i (::std::lower_bound ( + _xsd_Joining_type_indexes_, + _xsd_Joining_type_indexes_ + 3, + *this, + c)); + + if (i == _xsd_Joining_type_indexes_ + 3 || _xsd_Joining_type_literals_[*i] != *this) + { + throw ::xsd::cxx::tree::unexpected_enumerator < char > (*this); + } + + return *i; + } + + const char* const Joining_type:: + _xsd_Joining_type_literals_[3] = + { + "dialed-in", + "dialed-out", + "focus-owner" + }; + + const Joining_type::Value Joining_type:: + _xsd_Joining_type_indexes_[3] = + { + ::conference_info::Joining_type::dialed_in, + ::conference_info::Joining_type::dialed_out, + ::conference_info::Joining_type::focus_owner + }; + + // Disconnection_type + // + + Disconnection_type:: + Disconnection_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (e, f, c) + { + _xsd_Disconnection_type_convert (); + } + + Disconnection_type:: + Disconnection_type (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (a, f, c) + { + _xsd_Disconnection_type_convert (); + } + + Disconnection_type:: + Disconnection_type (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (s, e, f, c) + { + _xsd_Disconnection_type_convert (); + } + + Disconnection_type* Disconnection_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Disconnection_type (*this, f, c); + } + + Disconnection_type::Value Disconnection_type:: + _xsd_Disconnection_type_convert () const + { + ::xsd::cxx::tree::enum_comparator< char > c (_xsd_Disconnection_type_literals_); + const Value* i (::std::lower_bound ( + _xsd_Disconnection_type_indexes_, + _xsd_Disconnection_type_indexes_ + 4, + *this, + c)); + + if (i == _xsd_Disconnection_type_indexes_ + 4 || _xsd_Disconnection_type_literals_[*i] != *this) + { + throw ::xsd::cxx::tree::unexpected_enumerator < char > (*this); + } + + return *i; + } + + const char* const Disconnection_type:: + _xsd_Disconnection_type_literals_[4] = + { + "departed", + "booted", + "failed", + "busy" + }; + + const Disconnection_type::Value Disconnection_type:: + _xsd_Disconnection_type_indexes_[4] = + { + ::conference_info::Disconnection_type::booted, + ::conference_info::Disconnection_type::busy, + ::conference_info::Disconnection_type::departed, + ::conference_info::Disconnection_type::failed + }; + + // Execution_type + // + + Execution_type:: + Execution_type () + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + when_ (this), + reason_ (this), + by_ (this), + any_attribute_ (this->getDomDocument ()) + { + } + + Execution_type:: + Execution_type (const Execution_type& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + when_ (x.when_, f, this), + reason_ (x.reason_, f, this), + by_ (x.by_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + Execution_type:: + Execution_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + when_ (this), + reason_ (this), + by_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void Execution_type:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // when + // + if (n.name () == "when" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< WhenType > r ( + WhenTraits::create (i, f, this)); + + if (!this->when_) + { + this->when_.set (::std::move (r)); + continue; + } + } + + // reason + // + if (n.name () == "reason" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< ReasonType > r ( + ReasonTraits::create (i, f, this)); + + if (!this->reason_) + { + this->reason_.set (::std::move (r)); + continue; + } + } + + // by + // + if (n.name () == "by" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< ByType > r ( + ByTraits::create (i, f, this)); + + if (!this->by_) + { + this->by_.set (::std::move (r)); + continue; + } + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + } + + Execution_type* Execution_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Execution_type (*this, f, c); + } + + Execution_type& Execution_type:: + operator= (const Execution_type& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->when_ = x.when_; + this->reason_ = x.reason_; + this->by_ = x.by_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + Execution_type:: + ~Execution_type () + { + } + + // Call_type + // + + Call_type:: + Call_type () + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + sip_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + } + + Call_type:: + Call_type (const Call_type& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + sip_ (x.sip_, f, this), + any_ (x.any_, this->getDomDocument ()), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + Call_type:: + Call_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + sip_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void Call_type:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // sip + // + if (n.name () == "sip" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< SipType > r ( + SipTraits::create (i, f, this)); + + if (!this->sip_) + { + this->sip_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + } + + Call_type* Call_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Call_type (*this, f, c); + } + + Call_type& Call_type:: + operator= (const Call_type& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->sip_ = x.sip_; + this->any_ = x.any_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + Call_type:: + ~Call_type () + { + } + + // Sip_dialog_id_type + // + + Sip_dialog_id_type:: + Sip_dialog_id_type (const Call_idType& call_id, + const From_tagType& from_tag, + const To_tagType& to_tag) + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + call_id_ (call_id, this), + from_tag_ (from_tag, this), + to_tag_ (to_tag, this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + } + + Sip_dialog_id_type:: + Sip_dialog_id_type (const Sip_dialog_id_type& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (x.display_text_, f, this), + call_id_ (x.call_id_, f, this), + from_tag_ (x.from_tag_, f, this), + to_tag_ (x.to_tag_, f, this), + any_ (x.any_, this->getDomDocument ()), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + Sip_dialog_id_type:: + Sip_dialog_id_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + call_id_ (this), + from_tag_ (this), + to_tag_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void Sip_dialog_id_type:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-text + // + if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Display_textType > r ( + Display_textTraits::create (i, f, this)); + + if (!this->display_text_) + { + this->display_text_.set (::std::move (r)); + continue; + } + } + + // call-id + // + if (n.name () == "call-id" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Call_idType > r ( + Call_idTraits::create (i, f, this)); + + if (!call_id_.present ()) + { + this->call_id_.set (::std::move (r)); + continue; + } + } + + // from-tag + // + if (n.name () == "from-tag" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< From_tagType > r ( + From_tagTraits::create (i, f, this)); + + if (!from_tag_.present ()) + { + this->from_tag_.set (::std::move (r)); + continue; + } + } + + // to-tag + // + if (n.name () == "to-tag" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< To_tagType > r ( + To_tagTraits::create (i, f, this)); + + if (!to_tag_.present ()) + { + this->to_tag_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + if (!call_id_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "call-id", + "urn:ietf:params:xml:ns:conference-info"); + } + + if (!from_tag_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "from-tag", + "urn:ietf:params:xml:ns:conference-info"); + } + + if (!to_tag_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "to-tag", + "urn:ietf:params:xml:ns:conference-info"); + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + } + + Sip_dialog_id_type* Sip_dialog_id_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Sip_dialog_id_type (*this, f, c); + } + + Sip_dialog_id_type& Sip_dialog_id_type:: + operator= (const Sip_dialog_id_type& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->display_text_ = x.display_text_; + this->call_id_ = x.call_id_; + this->from_tag_ = x.from_tag_; + this->to_tag_ = x.to_tag_; + this->any_ = x.any_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + Sip_dialog_id_type:: + ~Sip_dialog_id_type () + { + } + + // Media_type + // + + Media_type:: + Media_type (const IdType& id) + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + type_ (this), + label_ (this), + src_id_ (this), + status_ (this), + any_ (this->getDomDocument ()), + id_ (id, this), + any_attribute_ (this->getDomDocument ()) + { + } + + Media_type:: + Media_type (const Media_type& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (x.display_text_, f, this), + type_ (x.type_, f, this), + label_ (x.label_, f, this), + src_id_ (x.src_id_, f, this), + status_ (x.status_, f, this), + any_ (x.any_, this->getDomDocument ()), + id_ (x.id_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + Media_type:: + Media_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + type_ (this), + label_ (this), + src_id_ (this), + status_ (this), + any_ (this->getDomDocument ()), + id_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void Media_type:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-text + // + if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Display_textType > r ( + Display_textTraits::create (i, f, this)); + + if (!this->display_text_) + { + this->display_text_.set (::std::move (r)); + continue; + } + } + + // type + // + if (n.name () == "type" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< TypeType > r ( + TypeTraits::create (i, f, this)); + + if (!this->type_) + { + this->type_.set (::std::move (r)); + continue; + } + } + + // label + // + if (n.name () == "label" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< LabelType > r ( + LabelTraits::create (i, f, this)); + + if (!this->label_) + { + this->label_.set (::std::move (r)); + continue; + } + } + + // src-id + // + if (n.name () == "src-id" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< Src_idType > r ( + Src_idTraits::create (i, f, this)); + + if (!this->src_id_) + { + this->src_id_.set (::std::move (r)); + continue; + } + } + + // status + // + if (n.name () == "status" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< StatusType > r ( + StatusTraits::create (i, f, this)); + + if (!this->status_) + { + this->status_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "id" && n.namespace_ ().empty ()) + { + this->id_.set (IdTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + + if (!id_.present ()) + { + throw ::xsd::cxx::tree::expected_attribute< char > ( + "id", + ""); + } + } + + Media_type* Media_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Media_type (*this, f, c); + } + + Media_type& Media_type:: + operator= (const Media_type& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->display_text_ = x.display_text_; + this->type_ = x.type_; + this->label_ = x.label_; + this->src_id_ = x.src_id_; + this->status_ = x.status_; + this->any_ = x.any_; + this->id_ = x.id_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + Media_type:: + ~Media_type () + { + } + + // Media_status_type + // + + Media_status_type:: + Media_status_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (e, f, c) + { + _xsd_Media_status_type_convert (); + } + + Media_status_type:: + Media_status_type (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (a, f, c) + { + _xsd_Media_status_type_convert (); + } + + Media_status_type:: + Media_status_type (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (s, e, f, c) + { + _xsd_Media_status_type_convert (); + } + + Media_status_type* Media_status_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Media_status_type (*this, f, c); + } + + Media_status_type::Value Media_status_type:: + _xsd_Media_status_type_convert () const + { + ::xsd::cxx::tree::enum_comparator< char > c (_xsd_Media_status_type_literals_); + const Value* i (::std::lower_bound ( + _xsd_Media_status_type_indexes_, + _xsd_Media_status_type_indexes_ + 4, + *this, + c)); + + if (i == _xsd_Media_status_type_indexes_ + 4 || _xsd_Media_status_type_literals_[*i] != *this) + { + throw ::xsd::cxx::tree::unexpected_enumerator < char > (*this); + } + + return *i; + } + + const char* const Media_status_type:: + _xsd_Media_status_type_literals_[4] = + { + "recvonly", + "sendonly", + "sendrecv", + "inactive" + }; + + const Media_status_type::Value Media_status_type:: + _xsd_Media_status_type_indexes_[4] = + { + ::conference_info::Media_status_type::inactive, + ::conference_info::Media_status_type::recvonly, + ::conference_info::Media_status_type::sendonly, + ::conference_info::Media_status_type::sendrecv + }; + + // Sidebars_by_val_type + // + + const Sidebars_by_val_type::StateType Sidebars_by_val_type::state_default_value_ ( + "full"); + + Sidebars_by_val_type:: + Sidebars_by_val_type () + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (this), + state_ (getStateDefaultValue (), this), + any_attribute_ (this->getDomDocument ()) + { + } + + Sidebars_by_val_type:: + Sidebars_by_val_type (const Sidebars_by_val_type& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (x.entry_, f, this), + state_ (x.state_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + Sidebars_by_val_type:: + Sidebars_by_val_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (this), + state_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void Sidebars_by_val_type:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // entry + // + if (n.name () == "entry" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< EntryType > r ( + EntryTraits::create (i, f, this)); + + this->entry_.push_back (::std::move (r)); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "state" && n.namespace_ ().empty ()) + { + this->state_.set (StateTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + + if (!state_.present ()) + { + this->state_.set (getStateDefaultValue ()); + } + } + + Sidebars_by_val_type* Sidebars_by_val_type:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Sidebars_by_val_type (*this, f, c); + } + + Sidebars_by_val_type& Sidebars_by_val_type:: + operator= (const Sidebars_by_val_type& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->entry_ = x.entry_; + this->state_ = x.state_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + Sidebars_by_val_type:: + ~Sidebars_by_val_type () + { + } +} + +#include + +namespace conference_info +{ + ::std::ostream& + operator<< (::std::ostream& o, const Conference_type& i) + { + if (i.getConference_description ()) + { + o << ::std::endl << "conference-description: " << *i.getConference_description (); + } + + if (i.getHost_info ()) + { + o << ::std::endl << "host-info: " << *i.getHost_info (); + } + + if (i.getConference_state ()) + { + o << ::std::endl << "conference-state: " << *i.getConference_state (); + } + + if (i.getUsers ()) + { + o << ::std::endl << "users: " << *i.getUsers (); + } + + if (i.getSidebars_by_ref ()) + { + o << ::std::endl << "sidebars-by-ref: " << *i.getSidebars_by_ref (); + } + + if (i.getSidebars_by_val ()) + { + o << ::std::endl << "sidebars-by-val: " << *i.getSidebars_by_val (); + } + + o << ::std::endl << "entity: " << i.getEntity (); + o << ::std::endl << "state: " << i.getState (); + if (i.getVersion ()) + { + o << ::std::endl << "version: " << *i.getVersion (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, State_type::Value i) + { + return o << State_type::_xsd_State_type_literals_[i]; + } + + ::std::ostream& + operator<< (::std::ostream& o, const State_type& i) + { + return o << static_cast< const ::xml_schema::String& > (i); + } + + ::std::ostream& + operator<< (::std::ostream& o, const Conference_description_type& i) + { + if (i.getDisplay_text ()) + { + o << ::std::endl << "display-text: " << *i.getDisplay_text (); + } + + if (i.getSubject ()) + { + o << ::std::endl << "subject: " << *i.getSubject (); + } + + if (i.getFree_text ()) + { + o << ::std::endl << "free-text: " << *i.getFree_text (); + } + + if (i.getKeywords ()) + { + o << ::std::endl << "keywords: " << *i.getKeywords (); + } + + if (i.getConf_uris ()) + { + o << ::std::endl << "conf-uris: " << *i.getConf_uris (); + } + + if (i.getService_uris ()) + { + o << ::std::endl << "service-uris: " << *i.getService_uris (); + } + + if (i.getMaximum_user_count ()) + { + o << ::std::endl << "maximum-user-count: " << *i.getMaximum_user_count (); + } + + if (i.getAvailable_media ()) + { + o << ::std::endl << "available-media: " << *i.getAvailable_media (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Host_type& i) + { + if (i.getDisplay_text ()) + { + o << ::std::endl << "display-text: " << *i.getDisplay_text (); + } + + if (i.getWeb_page ()) + { + o << ::std::endl << "web-page: " << *i.getWeb_page (); + } + + if (i.getUris ()) + { + o << ::std::endl << "uris: " << *i.getUris (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Conference_state_type& i) + { + if (i.getUser_count ()) + { + o << ::std::endl << "user-count: " << *i.getUser_count (); + } + + if (i.getActive ()) + { + o << ::std::endl << "active: " << *i.getActive (); + } + + if (i.getLocked ()) + { + o << ::std::endl << "locked: " << *i.getLocked (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Conference_media_type& i) + { + for (Conference_media_type::EntryConstIterator + b (i.getEntry ().begin ()), e (i.getEntry ().end ()); + b != e; ++b) + { + o << ::std::endl << "entry: " << *b; + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Conference_medium_type& i) + { + if (i.getDisplay_text ()) + { + o << ::std::endl << "display-text: " << *i.getDisplay_text (); + } + + o << ::std::endl << "type: " << i.getType (); + if (i.getStatus ()) + { + o << ::std::endl << "status: " << *i.getStatus (); + } + + o << ::std::endl << "label: " << i.getLabel (); + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Uris_type& i) + { + for (Uris_type::EntryConstIterator + b (i.getEntry ().begin ()), e (i.getEntry ().end ()); + b != e; ++b) + { + o << ::std::endl << "entry: " << *b; + } + + o << ::std::endl << "state: " << i.getState (); + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Uri_type& i) + { + o << ::std::endl << "uri: " << i.getUri (); + if (i.getDisplay_text ()) + { + o << ::std::endl << "display-text: " << *i.getDisplay_text (); + } + + if (i.getPurpose ()) + { + o << ::std::endl << "purpose: " << *i.getPurpose (); + } + + if (i.getModified ()) + { + o << ::std::endl << "modified: " << *i.getModified (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Keywords_type& i) + { + return o << static_cast< const ::xsd::cxx::tree::list< ::xml_schema::String, char >& > (i); + } + + ::std::ostream& + operator<< (::std::ostream& o, const Users_type& i) + { + for (Users_type::UserConstIterator + b (i.getUser ().begin ()), e (i.getUser ().end ()); + b != e; ++b) + { + o << ::std::endl << "user: " << *b; + } + + o << ::std::endl << "state: " << i.getState (); + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const User_type& i) + { + if (i.getDisplay_text ()) + { + o << ::std::endl << "display-text: " << *i.getDisplay_text (); + } + + if (i.getAssociated_aors ()) + { + o << ::std::endl << "associated-aors: " << *i.getAssociated_aors (); + } + + if (i.getRoles ()) + { + o << ::std::endl << "roles: " << *i.getRoles (); + } + + if (i.getLanguages ()) + { + o << ::std::endl << "languages: " << *i.getLanguages (); + } + + if (i.getCascaded_focus ()) + { + o << ::std::endl << "cascaded-focus: " << *i.getCascaded_focus (); + } + + for (User_type::EndpointConstIterator + b (i.getEndpoint ().begin ()), e (i.getEndpoint ().end ()); + b != e; ++b) + { + o << ::std::endl << "endpoint: " << *b; + } + + if (i.getEntity ()) + { + o << ::std::endl << "entity: " << *i.getEntity (); + } + + o << ::std::endl << "state: " << i.getState (); + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const User_roles_type& i) + { + for (User_roles_type::EntryConstIterator + b (i.getEntry ().begin ()), e (i.getEntry ().end ()); + b != e; ++b) + { + o << ::std::endl << "entry: " << *b; + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const User_languages_type& i) + { + return o << static_cast< const ::xsd::cxx::tree::list< ::xml_schema::Language, char >& > (i); + } + + ::std::ostream& + operator<< (::std::ostream& o, const Endpoint_type& i) + { + if (i.getDisplay_text ()) + { + o << ::std::endl << "display-text: " << *i.getDisplay_text (); + } + + if (i.getReferred ()) + { + o << ::std::endl << "referred: " << *i.getReferred (); + } + + if (i.getStatus ()) + { + o << ::std::endl << "status: " << *i.getStatus (); + } + + if (i.getJoining_method ()) + { + o << ::std::endl << "joining-method: " << *i.getJoining_method (); + } + + if (i.getJoining_info ()) + { + o << ::std::endl << "joining-info: " << *i.getJoining_info (); + } + + if (i.getDisconnection_method ()) + { + o << ::std::endl << "disconnection-method: " << *i.getDisconnection_method (); + } + + if (i.getDisconnection_info ()) + { + o << ::std::endl << "disconnection-info: " << *i.getDisconnection_info (); + } + + for (Endpoint_type::MediaConstIterator + b (i.getMedia ().begin ()), e (i.getMedia ().end ()); + b != e; ++b) + { + o << ::std::endl << "media: " << *b; + } + + if (i.getCall_info ()) + { + o << ::std::endl << "call-info: " << *i.getCall_info (); + } + + if (i.getEntity ()) + { + o << ::std::endl << "entity: " << *i.getEntity (); + } + + o << ::std::endl << "state: " << i.getState (); + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, Endpoint_status_type::Value i) + { + return o << Endpoint_status_type::_xsd_Endpoint_status_type_literals_[i]; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Endpoint_status_type& i) + { + return o << static_cast< const ::xml_schema::String& > (i); + } + + ::std::ostream& + operator<< (::std::ostream& o, Joining_type::Value i) + { + return o << Joining_type::_xsd_Joining_type_literals_[i]; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Joining_type& i) + { + return o << static_cast< const ::xml_schema::String& > (i); + } + + ::std::ostream& + operator<< (::std::ostream& o, Disconnection_type::Value i) + { + return o << Disconnection_type::_xsd_Disconnection_type_literals_[i]; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Disconnection_type& i) + { + return o << static_cast< const ::xml_schema::String& > (i); + } + + ::std::ostream& + operator<< (::std::ostream& o, const Execution_type& i) + { + if (i.getWhen ()) + { + o << ::std::endl << "when: " << *i.getWhen (); + } + + if (i.getReason ()) + { + o << ::std::endl << "reason: " << *i.getReason (); + } + + if (i.getBy ()) + { + o << ::std::endl << "by: " << *i.getBy (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Call_type& i) + { + if (i.getSip ()) + { + o << ::std::endl << "sip: " << *i.getSip (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Sip_dialog_id_type& i) + { + if (i.getDisplay_text ()) + { + o << ::std::endl << "display-text: " << *i.getDisplay_text (); + } + + o << ::std::endl << "call-id: " << i.getCall_id (); + o << ::std::endl << "from-tag: " << i.getFrom_tag (); + o << ::std::endl << "to-tag: " << i.getTo_tag (); + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Media_type& i) + { + if (i.getDisplay_text ()) + { + o << ::std::endl << "display-text: " << *i.getDisplay_text (); + } + + if (i.getType ()) + { + o << ::std::endl << "type: " << *i.getType (); + } + + if (i.getLabel ()) + { + o << ::std::endl << "label: " << *i.getLabel (); + } + + if (i.getSrc_id ()) + { + o << ::std::endl << "src-id: " << *i.getSrc_id (); + } + + if (i.getStatus ()) + { + o << ::std::endl << "status: " << *i.getStatus (); + } + + o << ::std::endl << "id: " << i.getId (); + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, Media_status_type::Value i) + { + return o << Media_status_type::_xsd_Media_status_type_literals_[i]; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Media_status_type& i) + { + return o << static_cast< const ::xml_schema::String& > (i); + } + + ::std::ostream& + operator<< (::std::ostream& o, const Sidebars_by_val_type& i) + { + for (Sidebars_by_val_type::EntryConstIterator + b (i.getEntry ().begin ()), e (i.getEntry ().end ()); + b != e; ++b) + { + o << ::std::endl << "entry: " << *b; + } + + o << ::std::endl << "state: " << i.getState (); + return o; + } +} + +#include +#include +#include + +namespace conference_info +{ + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (const ::std::string& u, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::Flags::dont_initialize) == 0, + (f & ::xml_schema::Flags::keep_dom) == 0); + + ::xsd::cxx::tree::error_handler< char > h; + + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + u, h, p, f)); + + h.throw_if_failed< ::xsd::cxx::tree::parsing< char > > (); + + return ::std::unique_ptr< ::conference_info::Conference_type > ( + ::conference_info::parseConference_info ( + std::move (d), f | ::xml_schema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (const ::std::string& u, + ::xml_schema::ErrorHandler& h, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::Flags::dont_initialize) == 0, + (f & ::xml_schema::Flags::keep_dom) == 0); + + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + u, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::conference_info::Conference_type > ( + ::conference_info::parseConference_info ( + std::move (d), f | ::xml_schema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (const ::std::string& u, + ::xercesc::DOMErrorHandler& h, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + u, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::conference_info::Conference_type > ( + ::conference_info::parseConference_info ( + std::move (d), f | ::xml_schema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::std::istream& is, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::Flags::dont_initialize) == 0, + (f & ::xml_schema::Flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is); + return ::conference_info::parseConference_info (isrc, f, p); + } + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::std::istream& is, + ::xml_schema::ErrorHandler& h, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::Flags::dont_initialize) == 0, + (f & ::xml_schema::Flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is); + return ::conference_info::parseConference_info (isrc, h, f, p); + } + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::std::istream& is, + ::xercesc::DOMErrorHandler& h, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xsd::cxx::xml::sax::std_input_source isrc (is); + return ::conference_info::parseConference_info (isrc, h, f, p); + } + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::std::istream& is, + const ::std::string& sid, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::Flags::dont_initialize) == 0, + (f & ::xml_schema::Flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); + return ::conference_info::parseConference_info (isrc, f, p); + } + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::std::istream& is, + const ::std::string& sid, + ::xml_schema::ErrorHandler& h, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::Flags::dont_initialize) == 0, + (f & ::xml_schema::Flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); + return ::conference_info::parseConference_info (isrc, h, f, p); + } + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::std::istream& is, + const ::std::string& sid, + ::xercesc::DOMErrorHandler& h, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); + return ::conference_info::parseConference_info (isrc, h, f, p); + } + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::xercesc::InputSource& i, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xsd::cxx::tree::error_handler< char > h; + + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + i, h, p, f)); + + h.throw_if_failed< ::xsd::cxx::tree::parsing< char > > (); + + return ::std::unique_ptr< ::conference_info::Conference_type > ( + ::conference_info::parseConference_info ( + std::move (d), f | ::xml_schema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::xercesc::InputSource& i, + ::xml_schema::ErrorHandler& h, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + i, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::conference_info::Conference_type > ( + ::conference_info::parseConference_info ( + std::move (d), f | ::xml_schema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::xercesc::InputSource& i, + ::xercesc::DOMErrorHandler& h, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + i, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::conference_info::Conference_type > ( + ::conference_info::parseConference_info ( + std::move (d), f | ::xml_schema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (const ::xercesc::DOMDocument& doc, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + if (f & ::xml_schema::Flags::keep_dom) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + static_cast< ::xercesc::DOMDocument* > (doc.cloneNode (true))); + + return ::std::unique_ptr< ::conference_info::Conference_type > ( + ::conference_info::parseConference_info ( + std::move (d), f | ::xml_schema::Flags::own_dom, p)); + } + + const ::xercesc::DOMElement& e (*doc.getDocumentElement ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (e)); + + if (n.name () == "conference-info" && + n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< ::conference_info::Conference_type > r ( + ::xsd::cxx::tree::traits< ::conference_info::Conference_type, char >::create ( + e, f, 0)); + return r; + } + + throw ::xsd::cxx::tree::unexpected_element < char > ( + n.name (), + n.namespace_ (), + "conference-info", + "urn:ietf:params:xml:ns:conference-info"); + } + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d, + ::xml_schema::Flags f, + const ::xml_schema::Properties&) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > c ( + ((f & ::xml_schema::Flags::keep_dom) && + !(f & ::xml_schema::Flags::own_dom)) + ? static_cast< ::xercesc::DOMDocument* > (d->cloneNode (true)) + : 0); + + ::xercesc::DOMDocument& doc (c.get () ? *c : *d); + const ::xercesc::DOMElement& e (*doc.getDocumentElement ()); + + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (e)); + + if (f & ::xml_schema::Flags::keep_dom) + doc.setUserData (::xml_schema::dom::treeNodeKey, + (c.get () ? &c : &d), + 0); + + if (n.name () == "conference-info" && + n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< ::conference_info::Conference_type > r ( + ::xsd::cxx::tree::traits< ::conference_info::Conference_type, char >::create ( + e, f, 0)); + return r; + } + + throw ::xsd::cxx::tree::unexpected_element < char > ( + n.name (), + n.namespace_ (), + "conference-info", + "urn:ietf:params:xml:ns:conference-info"); + } +} + +#include +#include +#include + +namespace conference_info +{ + void + serializeConference_info (::std::ostream& o, + const ::conference_info::Conference_type& s, + const ::xml_schema::NamespaceInfomap& m, + const ::std::string& e, + ::xml_schema::Flags f) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::Flags::dont_initialize) == 0); + + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::conference_info::serializeConference_info (s, m, f)); + + ::xsd::cxx::tree::error_handler< char > h; + + ::xsd::cxx::xml::dom::ostream_format_target t (o); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + h.throw_if_failed< ::xsd::cxx::tree::serialization< char > > (); + } + } + + void + serializeConference_info (::std::ostream& o, + const ::conference_info::Conference_type& s, + ::xml_schema::ErrorHandler& h, + const ::xml_schema::NamespaceInfomap& m, + const ::std::string& e, + ::xml_schema::Flags f) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::Flags::dont_initialize) == 0); + + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::conference_info::serializeConference_info (s, m, f)); + ::xsd::cxx::xml::dom::ostream_format_target t (o); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + throw ::xsd::cxx::tree::serialization< char > (); + } + } + + void + serializeConference_info (::std::ostream& o, + const ::conference_info::Conference_type& s, + ::xercesc::DOMErrorHandler& h, + const ::xml_schema::NamespaceInfomap& m, + const ::std::string& e, + ::xml_schema::Flags f) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::conference_info::serializeConference_info (s, m, f)); + ::xsd::cxx::xml::dom::ostream_format_target t (o); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + throw ::xsd::cxx::tree::serialization< char > (); + } + } + + void + serializeConference_info (::xercesc::XMLFormatTarget& t, + const ::conference_info::Conference_type& s, + const ::xml_schema::NamespaceInfomap& m, + const ::std::string& e, + ::xml_schema::Flags f) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::conference_info::serializeConference_info (s, m, f)); + + ::xsd::cxx::tree::error_handler< char > h; + + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + h.throw_if_failed< ::xsd::cxx::tree::serialization< char > > (); + } + } + + void + serializeConference_info (::xercesc::XMLFormatTarget& t, + const ::conference_info::Conference_type& s, + ::xml_schema::ErrorHandler& h, + const ::xml_schema::NamespaceInfomap& m, + const ::std::string& e, + ::xml_schema::Flags f) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::conference_info::serializeConference_info (s, m, f)); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + throw ::xsd::cxx::tree::serialization< char > (); + } + } + + void + serializeConference_info (::xercesc::XMLFormatTarget& t, + const ::conference_info::Conference_type& s, + ::xercesc::DOMErrorHandler& h, + const ::xml_schema::NamespaceInfomap& m, + const ::std::string& e, + ::xml_schema::Flags f) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::conference_info::serializeConference_info (s, m, f)); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + throw ::xsd::cxx::tree::serialization< char > (); + } + } + + void + serializeConference_info (::xercesc::DOMDocument& d, + const ::conference_info::Conference_type& s, + ::xml_schema::Flags) + { + ::xercesc::DOMElement& e (*d.getDocumentElement ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (e)); + + if (n.name () == "conference-info" && + n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + e << s; + } + else + { + throw ::xsd::cxx::tree::unexpected_element < char > ( + n.name (), + n.namespace_ (), + "conference-info", + "urn:ietf:params:xml:ns:conference-info"); + } + } + + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > + serializeConference_info (const ::conference_info::Conference_type& s, + const ::xml_schema::NamespaceInfomap& m, + ::xml_schema::Flags f) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::serialize< char > ( + "conference-info", + "urn:ietf:params:xml:ns:conference-info", + m, f)); + + ::conference_info::serializeConference_info (*d, s, f); + return d; + } + + void + operator<< (::xercesc::DOMElement& e, const Conference_type& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (Conference_type::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // conference-description + // + if (i.getConference_description ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "conference-description", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getConference_description (); + } + + // host-info + // + if (i.getHost_info ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "host-info", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getHost_info (); + } + + // conference-state + // + if (i.getConference_state ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "conference-state", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getConference_state (); + } + + // users + // + if (i.getUsers ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "users", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getUsers (); + } + + // sidebars-by-ref + // + if (i.getSidebars_by_ref ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "sidebars-by-ref", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getSidebars_by_ref (); + } + + // sidebars-by-val + // + if (i.getSidebars_by_val ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "sidebars-by-val", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getSidebars_by_val (); + } + + // any + // + for (Conference_type::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + + // entity + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "entity", + e)); + + a << i.getEntity (); + } + + // state + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "state", + e)); + + a << i.getState (); + } + + // version + // + if (i.getVersion ()) + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "version", + e)); + + a << *i.getVersion (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const State_type& i) + { + e << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xercesc::DOMAttr& a, const State_type& i) + { + a << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xml_schema::ListStream& l, + const State_type& i) + { + l << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xercesc::DOMElement& e, const Conference_description_type& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (Conference_description_type::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // display-text + // + if (i.getDisplay_text ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-text", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisplay_text (); + } + + // subject + // + if (i.getSubject ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "subject", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getSubject (); + } + + // free-text + // + if (i.getFree_text ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "free-text", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getFree_text (); + } + + // keywords + // + if (i.getKeywords ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "keywords", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getKeywords (); + } + + // conf-uris + // + if (i.getConf_uris ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "conf-uris", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getConf_uris (); + } + + // service-uris + // + if (i.getService_uris ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "service-uris", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getService_uris (); + } + + // maximum-user-count + // + if (i.getMaximum_user_count ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "maximum-user-count", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getMaximum_user_count (); + } + + // available-media + // + if (i.getAvailable_media ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "available-media", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getAvailable_media (); + } + + // any + // + for (Conference_description_type::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + } + + void + operator<< (::xercesc::DOMElement& e, const Host_type& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (Host_type::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // display-text + // + if (i.getDisplay_text ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-text", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisplay_text (); + } + + // web-page + // + if (i.getWeb_page ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "web-page", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getWeb_page (); + } + + // uris + // + if (i.getUris ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "uris", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getUris (); + } + + // any + // + for (Host_type::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + } + + void + operator<< (::xercesc::DOMElement& e, const Conference_state_type& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (Conference_state_type::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // user-count + // + if (i.getUser_count ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "user-count", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getUser_count (); + } + + // active + // + if (i.getActive ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "active", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getActive (); + } + + // locked + // + if (i.getLocked ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "locked", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getLocked (); + } + + // any + // + for (Conference_state_type::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + } + + void + operator<< (::xercesc::DOMElement& e, const Conference_media_type& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (Conference_media_type::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // entry + // + for (Conference_media_type::EntryConstIterator + b (i.getEntry ().begin ()), n (i.getEntry ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "entry", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *b; + } + } + + void + operator<< (::xercesc::DOMElement& e, const Conference_medium_type& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (Conference_medium_type::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // display-text + // + if (i.getDisplay_text ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-text", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisplay_text (); + } + + // type + // + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "type", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << i.getType (); + } + + // status + // + if (i.getStatus ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "status", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getStatus (); + } + + // any + // + for (Conference_medium_type::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + + // label + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "label", + e)); + + a << i.getLabel (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const Uris_type& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (Uris_type::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // entry + // + for (Uris_type::EntryConstIterator + b (i.getEntry ().begin ()), n (i.getEntry ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "entry", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *b; + } + + // state + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "state", + e)); + + a << i.getState (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const Uri_type& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (Uri_type::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // uri + // + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "uri", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << i.getUri (); + } + + // display-text + // + if (i.getDisplay_text ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-text", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisplay_text (); + } + + // purpose + // + if (i.getPurpose ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "purpose", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getPurpose (); + } + + // modified + // + if (i.getModified ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "modified", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getModified (); + } + + // any + // + for (Uri_type::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + } + + void + operator<< (::xercesc::DOMElement& e, const Keywords_type& i) + { + e << static_cast< const ::xsd::cxx::tree::list< ::xml_schema::String, char >& > (i); + } + + void + operator<< (::xercesc::DOMAttr& a, const Keywords_type& i) + { + a << static_cast< const ::xsd::cxx::tree::list< ::xml_schema::String, char >& > (i); + } + + void + operator<< (::xml_schema::ListStream& l, + const Keywords_type& i) + { + l << static_cast< const ::xsd::cxx::tree::list< ::xml_schema::String, char >& > (i); + } + + void + operator<< (::xercesc::DOMElement& e, const Users_type& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (Users_type::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // user + // + for (Users_type::UserConstIterator + b (i.getUser ().begin ()), n (i.getUser ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "user", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *b; + } + + // any + // + for (Users_type::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + + // state + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "state", + e)); + + a << i.getState (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const User_type& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (User_type::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // display-text + // + if (i.getDisplay_text ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-text", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisplay_text (); + } + + // associated-aors + // + if (i.getAssociated_aors ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "associated-aors", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getAssociated_aors (); + } + + // roles + // + if (i.getRoles ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "roles", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getRoles (); + } + + // languages + // + if (i.getLanguages ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "languages", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getLanguages (); + } + + // cascaded-focus + // + if (i.getCascaded_focus ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "cascaded-focus", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getCascaded_focus (); + } + + // endpoint + // + for (User_type::EndpointConstIterator + b (i.getEndpoint ().begin ()), n (i.getEndpoint ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "endpoint", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *b; + } + + // any + // + for (User_type::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + + // entity + // + if (i.getEntity ()) + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "entity", + e)); + + a << *i.getEntity (); + } + + // state + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "state", + e)); + + a << i.getState (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const User_roles_type& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (User_roles_type::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // entry + // + for (User_roles_type::EntryConstIterator + b (i.getEntry ().begin ()), n (i.getEntry ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "entry", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *b; + } + } + + void + operator<< (::xercesc::DOMElement& e, const User_languages_type& i) + { + e << static_cast< const ::xsd::cxx::tree::list< ::xml_schema::Language, char >& > (i); + } + + void + operator<< (::xercesc::DOMAttr& a, const User_languages_type& i) + { + a << static_cast< const ::xsd::cxx::tree::list< ::xml_schema::Language, char >& > (i); + } + + void + operator<< (::xml_schema::ListStream& l, + const User_languages_type& i) + { + l << static_cast< const ::xsd::cxx::tree::list< ::xml_schema::Language, char >& > (i); + } + + void + operator<< (::xercesc::DOMElement& e, const Endpoint_type& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (Endpoint_type::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // display-text + // + if (i.getDisplay_text ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-text", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisplay_text (); + } + + // referred + // + if (i.getReferred ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "referred", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getReferred (); + } + + // status + // + if (i.getStatus ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "status", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getStatus (); + } + + // joining-method + // + if (i.getJoining_method ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "joining-method", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getJoining_method (); + } + + // joining-info + // + if (i.getJoining_info ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "joining-info", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getJoining_info (); + } + + // disconnection-method + // + if (i.getDisconnection_method ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "disconnection-method", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisconnection_method (); + } + + // disconnection-info + // + if (i.getDisconnection_info ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "disconnection-info", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisconnection_info (); + } + + // media + // + for (Endpoint_type::MediaConstIterator + b (i.getMedia ().begin ()), n (i.getMedia ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "media", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *b; + } + + // call-info + // + if (i.getCall_info ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "call-info", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getCall_info (); + } + + // any + // + for (Endpoint_type::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + + // entity + // + if (i.getEntity ()) + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "entity", + e)); + + a << *i.getEntity (); + } + + // state + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "state", + e)); + + a << i.getState (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const Endpoint_status_type& i) + { + e << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xercesc::DOMAttr& a, const Endpoint_status_type& i) + { + a << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xml_schema::ListStream& l, + const Endpoint_status_type& i) + { + l << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xercesc::DOMElement& e, const Joining_type& i) + { + e << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xercesc::DOMAttr& a, const Joining_type& i) + { + a << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xml_schema::ListStream& l, + const Joining_type& i) + { + l << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xercesc::DOMElement& e, const Disconnection_type& i) + { + e << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xercesc::DOMAttr& a, const Disconnection_type& i) + { + a << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xml_schema::ListStream& l, + const Disconnection_type& i) + { + l << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xercesc::DOMElement& e, const Execution_type& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (Execution_type::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // when + // + if (i.getWhen ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "when", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getWhen (); + } + + // reason + // + if (i.getReason ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "reason", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getReason (); + } + + // by + // + if (i.getBy ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "by", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getBy (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const Call_type& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (Call_type::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // sip + // + if (i.getSip ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "sip", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getSip (); + } + + // any + // + for (Call_type::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + } + + void + operator<< (::xercesc::DOMElement& e, const Sip_dialog_id_type& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (Sip_dialog_id_type::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // display-text + // + if (i.getDisplay_text ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-text", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisplay_text (); + } + + // call-id + // + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "call-id", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << i.getCall_id (); + } + + // from-tag + // + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "from-tag", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << i.getFrom_tag (); + } + + // to-tag + // + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "to-tag", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << i.getTo_tag (); + } + + // any + // + for (Sip_dialog_id_type::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + } + + void + operator<< (::xercesc::DOMElement& e, const Media_type& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (Media_type::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // display-text + // + if (i.getDisplay_text ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-text", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisplay_text (); + } + + // type + // + if (i.getType ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "type", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getType (); + } + + // label + // + if (i.getLabel ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "label", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getLabel (); + } + + // src-id + // + if (i.getSrc_id ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "src-id", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getSrc_id (); + } + + // status + // + if (i.getStatus ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "status", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getStatus (); + } + + // any + // + for (Media_type::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + + // id + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "id", + e)); + + a << i.getId (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const Media_status_type& i) + { + e << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xercesc::DOMAttr& a, const Media_status_type& i) + { + a << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xml_schema::ListStream& l, + const Media_status_type& i) + { + l << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xercesc::DOMElement& e, const Sidebars_by_val_type& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (Sidebars_by_val_type::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // entry + // + for (Sidebars_by_val_type::EntryConstIterator + b (i.getEntry ().begin ()), n (i.getEntry ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "entry", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *b; + } + + // state + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "state", + e)); + + a << i.getState (); + } + } +} + +#include + +// Begin epilogue. +// +// +// End epilogue. + diff --git a/src/conference/conference-info.hxx b/src/conference/conference-info.hxx new file mode 100644 index 000000000..45404038b --- /dev/null +++ b/src/conference/conference-info.hxx @@ -0,0 +1,3862 @@ +// Copyright (c) 2005-2014 Code Synthesis Tools CC +// +// This program was generated by CodeSynthesis XSD, an XML Schema to +// C++ data binding compiler. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// 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 St, Fifth Floor, Boston, MA 02110-1301 USA +// +// In addition, as a special exception, Code Synthesis Tools CC gives +// permission to link this program with the Xerces-C++ library (or with +// modified versions of Xerces-C++ that use the same license as Xerces-C++), +// and distribute linked combinations including the two. You must obey +// the GNU General Public License version 2 in all respects for all of +// the code used other than Xerces-C++. If you modify this copy of the +// program, you may extend this exception to your version of the program, +// but you are not obligated to do so. If you do not wish to do so, delete +// this exception statement from your version. +// +// Furthermore, Code Synthesis Tools CC makes a special exception for +// the Free/Libre and Open Source Software (FLOSS) which is described +// in the accompanying FLOSSE file. +// + +#ifndef CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_FLEXISIP_SRC_XML_CONFERENCE_INFO_HXX +#define CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_FLEXISIP_SRC_XML_CONFERENCE_INFO_HXX + +#ifndef XSD_CXX11 +#define XSD_CXX11 +#endif + +#ifndef XSD_USE_CHAR +#define XSD_USE_CHAR +#endif + +#ifndef XSD_CXX_TREE_USE_CHAR +#define XSD_CXX_TREE_USE_CHAR +#endif + +// Begin prologue. +// +// +// End prologue. + +#include + +#if (XSD_INT_VERSION != 4000000L) +#error XSD runtime version mismatch +#endif + +#include + +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace xml_schema +{ + // anyType and anySimpleType. + // + typedef ::xsd::cxx::tree::type Type; + typedef ::xsd::cxx::tree::simple_type< char, Type > SimpleType; + typedef ::xsd::cxx::tree::type Container; + + // 8-bit + // + typedef signed char Byte; + typedef unsigned char UnsignedByte; + + // 16-bit + // + typedef short Short; + typedef unsigned short UnsignedShort; + + // 32-bit + // + typedef int Int; + typedef unsigned int UnsignedInt; + + // 64-bit + // + typedef long long Long; + typedef unsigned long long UnsignedLong; + + // Supposed to be arbitrary-length integral types. + // + typedef long long Integer; + typedef long long NonPositiveInteger; + typedef unsigned long long NonNegativeInteger; + typedef unsigned long long PositiveInteger; + typedef long long NegativeInteger; + + // Boolean. + // + typedef bool Boolean; + + // Floating-point types. + // + typedef float Float; + typedef double Double; + typedef double Decimal; + + // String types. + // + typedef ::xsd::cxx::tree::string< char, SimpleType > String; + typedef ::xsd::cxx::tree::normalized_string< char, String > NormalizedString; + typedef ::xsd::cxx::tree::token< char, NormalizedString > Token; + typedef ::xsd::cxx::tree::name< char, Token > Name; + typedef ::xsd::cxx::tree::nmtoken< char, Token > Nmtoken; + typedef ::xsd::cxx::tree::nmtokens< char, SimpleType, Nmtoken > Nmtokens; + typedef ::xsd::cxx::tree::ncname< char, Name > Ncname; + typedef ::xsd::cxx::tree::language< char, Token > Language; + + // ID/IDREF. + // + typedef ::xsd::cxx::tree::id< char, Ncname > Id; + typedef ::xsd::cxx::tree::idref< char, Ncname, Type > Idref; + typedef ::xsd::cxx::tree::idrefs< char, SimpleType, Idref > Idrefs; + + // URI. + // + typedef ::xsd::cxx::tree::uri< char, SimpleType > Uri; + + // Qualified name. + // + typedef ::xsd::cxx::tree::qname< char, SimpleType, Uri, Ncname > Qname; + + // Binary. + // + typedef ::xsd::cxx::tree::buffer< char > Buffer; + typedef ::xsd::cxx::tree::base64_binary< char, SimpleType > Base64Binary; + typedef ::xsd::cxx::tree::hex_binary< char, SimpleType > HexBinary; + + // Date/time. + // + typedef ::xsd::cxx::tree::time_zone TimeZone; + typedef ::xsd::cxx::tree::date< char, SimpleType > Date; + typedef ::xsd::cxx::tree::date_time< char, SimpleType > DateTime; + typedef ::xsd::cxx::tree::duration< char, SimpleType > Duration; + typedef ::xsd::cxx::tree::gday< char, SimpleType > Gday; + typedef ::xsd::cxx::tree::gmonth< char, SimpleType > Gmonth; + typedef ::xsd::cxx::tree::gmonth_day< char, SimpleType > GmonthDay; + typedef ::xsd::cxx::tree::gyear< char, SimpleType > Gyear; + typedef ::xsd::cxx::tree::gyear_month< char, SimpleType > GyearMonth; + typedef ::xsd::cxx::tree::time< char, SimpleType > Time; + + // Entity. + // + typedef ::xsd::cxx::tree::entity< char, Ncname > Entity; + typedef ::xsd::cxx::tree::entities< char, SimpleType, Entity > Entities; + + typedef ::xsd::cxx::tree::content_order ContentOrder; + // Namespace information and list stream. Used in + // serialization functions. + // + typedef ::xsd::cxx::xml::dom::namespace_info< char > NamespaceInfo; + typedef ::xsd::cxx::xml::dom::namespace_infomap< char > NamespaceInfomap; + typedef ::xsd::cxx::tree::list_stream< char > ListStream; + typedef ::xsd::cxx::tree::as_double< Double > AsDouble; + typedef ::xsd::cxx::tree::as_decimal< Decimal > AsDecimal; + typedef ::xsd::cxx::tree::facet Facet; + + // Flags and properties. + // + typedef ::xsd::cxx::tree::flags Flags; + typedef ::xsd::cxx::tree::properties< char > Properties; + + // Parsing/serialization diagnostics. + // + typedef ::xsd::cxx::tree::severity Severity; + typedef ::xsd::cxx::tree::error< char > Error; + typedef ::xsd::cxx::tree::diagnostics< char > Diagnostics; + + // Exceptions. + // + typedef ::xsd::cxx::tree::exception< char > Exception; + typedef ::xsd::cxx::tree::bounds< char > Bounds; + typedef ::xsd::cxx::tree::duplicate_id< char > DuplicateId; + typedef ::xsd::cxx::tree::parsing< char > Parsing; + typedef ::xsd::cxx::tree::expected_element< char > ExpectedElement; + typedef ::xsd::cxx::tree::unexpected_element< char > UnexpectedElement; + typedef ::xsd::cxx::tree::expected_attribute< char > ExpectedAttribute; + typedef ::xsd::cxx::tree::unexpected_enumerator< char > UnexpectedEnumerator; + typedef ::xsd::cxx::tree::expected_text_content< char > ExpectedTextContent; + typedef ::xsd::cxx::tree::no_prefix_mapping< char > NoPrefixMapping; + typedef ::xsd::cxx::tree::serialization< char > Serialization; + + // Error handler callback interface. + // + typedef ::xsd::cxx::xml::error_handler< char > ErrorHandler; + + // DOM interaction. + // + namespace dom + { + // Automatic pointer for DOMDocument. + // + using ::xsd::cxx::xml::dom::unique_ptr; + +#ifndef XSD_CXX_TREE_TREE_NODE_KEY__XML_SCHEMA +#define XSD_CXX_TREE_TREE_NODE_KEY__XML_SCHEMA + // DOM user data key for back pointers to tree nodes. + // + const XMLCh* const treeNodeKey = ::xsd::cxx::tree::user_data_keys::node; +#endif + } +} + +// Forward declarations. +// +namespace conference_info +{ + class Conference_type; + class State_type; + class Conference_description_type; + class Host_type; + class Conference_state_type; + class Conference_media_type; + class Conference_medium_type; + class Uris_type; + class Uri_type; + class Keywords_type; + class Users_type; + class User_type; + class User_roles_type; + class User_languages_type; + class Endpoint_type; + class Endpoint_status_type; + class Joining_type; + class Disconnection_type; + class Execution_type; + class Call_type; + class Sip_dialog_id_type; + class Media_type; + class Media_status_type; + class Sidebars_by_val_type; +} + + +#include // ::std::unique_ptr +#include // std::numeric_limits +#include // std::binary_search +#include // std::move + +#include + +#include +#include +#include +#include + +#include + +#include + +#include "xml.hxx" + +namespace conference_info +{ + class Conference_type: public ::xml_schema::Type + { + public: + // conference-description + // + typedef ::conference_info::Conference_description_type Conference_descriptionType; + typedef ::xsd::cxx::tree::optional< Conference_descriptionType > Conference_descriptionOptional; + typedef ::xsd::cxx::tree::traits< Conference_descriptionType, char > Conference_descriptionTraits; + + const Conference_descriptionOptional& + getConference_description () const; + + Conference_descriptionOptional& + getConference_description (); + + void + setConference_description (const Conference_descriptionType& x); + + void + setConference_description (const Conference_descriptionOptional& x); + + void + setConference_description (::std::unique_ptr< Conference_descriptionType > p); + + // host-info + // + typedef ::conference_info::Host_type Host_infoType; + typedef ::xsd::cxx::tree::optional< Host_infoType > Host_infoOptional; + typedef ::xsd::cxx::tree::traits< Host_infoType, char > Host_infoTraits; + + const Host_infoOptional& + getHost_info () const; + + Host_infoOptional& + getHost_info (); + + void + setHost_info (const Host_infoType& x); + + void + setHost_info (const Host_infoOptional& x); + + void + setHost_info (::std::unique_ptr< Host_infoType > p); + + // conference-state + // + typedef ::conference_info::Conference_state_type Conference_stateType; + typedef ::xsd::cxx::tree::optional< Conference_stateType > Conference_stateOptional; + typedef ::xsd::cxx::tree::traits< Conference_stateType, char > Conference_stateTraits; + + const Conference_stateOptional& + getConference_state () const; + + Conference_stateOptional& + getConference_state (); + + void + setConference_state (const Conference_stateType& x); + + void + setConference_state (const Conference_stateOptional& x); + + void + setConference_state (::std::unique_ptr< Conference_stateType > p); + + // users + // + typedef ::conference_info::Users_type UsersType; + typedef ::xsd::cxx::tree::optional< UsersType > UsersOptional; + typedef ::xsd::cxx::tree::traits< UsersType, char > UsersTraits; + + const UsersOptional& + getUsers () const; + + UsersOptional& + getUsers (); + + void + setUsers (const UsersType& x); + + void + setUsers (const UsersOptional& x); + + void + setUsers (::std::unique_ptr< UsersType > p); + + // sidebars-by-ref + // + typedef ::conference_info::Uris_type Sidebars_by_refType; + typedef ::xsd::cxx::tree::optional< Sidebars_by_refType > Sidebars_by_refOptional; + typedef ::xsd::cxx::tree::traits< Sidebars_by_refType, char > Sidebars_by_refTraits; + + const Sidebars_by_refOptional& + getSidebars_by_ref () const; + + Sidebars_by_refOptional& + getSidebars_by_ref (); + + void + setSidebars_by_ref (const Sidebars_by_refType& x); + + void + setSidebars_by_ref (const Sidebars_by_refOptional& x); + + void + setSidebars_by_ref (::std::unique_ptr< Sidebars_by_refType > p); + + // sidebars-by-val + // + typedef ::conference_info::Sidebars_by_val_type Sidebars_by_valType; + typedef ::xsd::cxx::tree::optional< Sidebars_by_valType > Sidebars_by_valOptional; + typedef ::xsd::cxx::tree::traits< Sidebars_by_valType, char > Sidebars_by_valTraits; + + const Sidebars_by_valOptional& + getSidebars_by_val () const; + + Sidebars_by_valOptional& + getSidebars_by_val (); + + void + setSidebars_by_val (const Sidebars_by_valType& x); + + void + setSidebars_by_val (const Sidebars_by_valOptional& x); + + void + setSidebars_by_val (::std::unique_ptr< Sidebars_by_valType > p); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // entity + // + typedef ::xml_schema::Uri EntityType; + typedef ::xsd::cxx::tree::traits< EntityType, char > EntityTraits; + + const EntityType& + getEntity () const; + + EntityType& + getEntity (); + + void + setEntity (const EntityType& x); + + void + setEntity (::std::unique_ptr< EntityType > p); + + ::std::unique_ptr< EntityType > + detachEntity (); + + // state + // + typedef ::conference_info::State_type StateType; + typedef ::xsd::cxx::tree::traits< StateType, char > StateTraits; + + const StateType& + getState () const; + + StateType& + getState (); + + void + setState (const StateType& x); + + void + setState (::std::unique_ptr< StateType > p); + + ::std::unique_ptr< StateType > + detachState (); + + static const StateType& + getStateDefaultValue (); + + // version + // + typedef ::xml_schema::UnsignedInt VersionType; + typedef ::xsd::cxx::tree::optional< VersionType > VersionOptional; + typedef ::xsd::cxx::tree::traits< VersionType, char > VersionTraits; + + const VersionOptional& + getVersion () const; + + VersionOptional& + getVersion (); + + void + setVersion (const VersionType& x); + + void + setVersion (const VersionOptional& x); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + Conference_type (const EntityType&); + + Conference_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Conference_type (const Conference_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Conference_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Conference_type& + operator= (const Conference_type& x); + + virtual + ~Conference_type (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + Conference_descriptionOptional conference_description_; + Host_infoOptional host_info_; + Conference_stateOptional conference_state_; + UsersOptional users_; + Sidebars_by_refOptional sidebars_by_ref_; + Sidebars_by_valOptional sidebars_by_val_; + AnySequence any_; + ::xsd::cxx::tree::one< EntityType > entity_; + ::xsd::cxx::tree::one< StateType > state_; + static const StateType state_default_value_; + VersionOptional version_; + AnyAttributeSet any_attribute_; + }; + + class State_type: public ::xml_schema::String + { + public: + enum Value + { + full, + partial, + deleted + }; + + State_type (Value v); + + State_type (const char* v); + + State_type (const ::std::string& v); + + State_type (const ::xml_schema::String& v); + + State_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + State_type (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + State_type (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + State_type (const State_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual State_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + State_type& + operator= (Value v); + + virtual + operator Value () const + { + return _xsd_State_type_convert (); + } + + protected: + Value + _xsd_State_type_convert () const; + + public: + static const char* const _xsd_State_type_literals_[3]; + static const Value _xsd_State_type_indexes_[3]; + }; + + class Conference_description_type: public ::xml_schema::Type + { + public: + // display-text + // + typedef ::xml_schema::String Display_textType; + typedef ::xsd::cxx::tree::optional< Display_textType > Display_textOptional; + typedef ::xsd::cxx::tree::traits< Display_textType, char > Display_textTraits; + + const Display_textOptional& + getDisplay_text () const; + + Display_textOptional& + getDisplay_text (); + + void + setDisplay_text (const Display_textType& x); + + void + setDisplay_text (const Display_textOptional& x); + + void + setDisplay_text (::std::unique_ptr< Display_textType > p); + + // subject + // + typedef ::xml_schema::String SubjectType; + typedef ::xsd::cxx::tree::optional< SubjectType > SubjectOptional; + typedef ::xsd::cxx::tree::traits< SubjectType, char > SubjectTraits; + + const SubjectOptional& + getSubject () const; + + SubjectOptional& + getSubject (); + + void + setSubject (const SubjectType& x); + + void + setSubject (const SubjectOptional& x); + + void + setSubject (::std::unique_ptr< SubjectType > p); + + // free-text + // + typedef ::xml_schema::String Free_textType; + typedef ::xsd::cxx::tree::optional< Free_textType > Free_textOptional; + typedef ::xsd::cxx::tree::traits< Free_textType, char > Free_textTraits; + + const Free_textOptional& + getFree_text () const; + + Free_textOptional& + getFree_text (); + + void + setFree_text (const Free_textType& x); + + void + setFree_text (const Free_textOptional& x); + + void + setFree_text (::std::unique_ptr< Free_textType > p); + + // keywords + // + typedef ::conference_info::Keywords_type KeywordsType; + typedef ::xsd::cxx::tree::optional< KeywordsType > KeywordsOptional; + typedef ::xsd::cxx::tree::traits< KeywordsType, char > KeywordsTraits; + + const KeywordsOptional& + getKeywords () const; + + KeywordsOptional& + getKeywords (); + + void + setKeywords (const KeywordsType& x); + + void + setKeywords (const KeywordsOptional& x); + + void + setKeywords (::std::unique_ptr< KeywordsType > p); + + // conf-uris + // + typedef ::conference_info::Uris_type Conf_urisType; + typedef ::xsd::cxx::tree::optional< Conf_urisType > Conf_urisOptional; + typedef ::xsd::cxx::tree::traits< Conf_urisType, char > Conf_urisTraits; + + const Conf_urisOptional& + getConf_uris () const; + + Conf_urisOptional& + getConf_uris (); + + void + setConf_uris (const Conf_urisType& x); + + void + setConf_uris (const Conf_urisOptional& x); + + void + setConf_uris (::std::unique_ptr< Conf_urisType > p); + + // service-uris + // + typedef ::conference_info::Uris_type Service_urisType; + typedef ::xsd::cxx::tree::optional< Service_urisType > Service_urisOptional; + typedef ::xsd::cxx::tree::traits< Service_urisType, char > Service_urisTraits; + + const Service_urisOptional& + getService_uris () const; + + Service_urisOptional& + getService_uris (); + + void + setService_uris (const Service_urisType& x); + + void + setService_uris (const Service_urisOptional& x); + + void + setService_uris (::std::unique_ptr< Service_urisType > p); + + // maximum-user-count + // + typedef ::xml_schema::UnsignedInt Maximum_user_countType; + typedef ::xsd::cxx::tree::optional< Maximum_user_countType > Maximum_user_countOptional; + typedef ::xsd::cxx::tree::traits< Maximum_user_countType, char > Maximum_user_countTraits; + + const Maximum_user_countOptional& + getMaximum_user_count () const; + + Maximum_user_countOptional& + getMaximum_user_count (); + + void + setMaximum_user_count (const Maximum_user_countType& x); + + void + setMaximum_user_count (const Maximum_user_countOptional& x); + + // available-media + // + typedef ::conference_info::Conference_media_type Available_mediaType; + typedef ::xsd::cxx::tree::optional< Available_mediaType > Available_mediaOptional; + typedef ::xsd::cxx::tree::traits< Available_mediaType, char > Available_mediaTraits; + + const Available_mediaOptional& + getAvailable_media () const; + + Available_mediaOptional& + getAvailable_media (); + + void + setAvailable_media (const Available_mediaType& x); + + void + setAvailable_media (const Available_mediaOptional& x); + + void + setAvailable_media (::std::unique_ptr< Available_mediaType > p); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + Conference_description_type (); + + Conference_description_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Conference_description_type (const Conference_description_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Conference_description_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Conference_description_type& + operator= (const Conference_description_type& x); + + virtual + ~Conference_description_type (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + Display_textOptional display_text_; + SubjectOptional subject_; + Free_textOptional free_text_; + KeywordsOptional keywords_; + Conf_urisOptional conf_uris_; + Service_urisOptional service_uris_; + Maximum_user_countOptional maximum_user_count_; + Available_mediaOptional available_media_; + AnySequence any_; + AnyAttributeSet any_attribute_; + }; + + class Host_type: public ::xml_schema::Type + { + public: + // display-text + // + typedef ::xml_schema::String Display_textType; + typedef ::xsd::cxx::tree::optional< Display_textType > Display_textOptional; + typedef ::xsd::cxx::tree::traits< Display_textType, char > Display_textTraits; + + const Display_textOptional& + getDisplay_text () const; + + Display_textOptional& + getDisplay_text (); + + void + setDisplay_text (const Display_textType& x); + + void + setDisplay_text (const Display_textOptional& x); + + void + setDisplay_text (::std::unique_ptr< Display_textType > p); + + // web-page + // + typedef ::xml_schema::Uri Web_pageType; + typedef ::xsd::cxx::tree::optional< Web_pageType > Web_pageOptional; + typedef ::xsd::cxx::tree::traits< Web_pageType, char > Web_pageTraits; + + const Web_pageOptional& + getWeb_page () const; + + Web_pageOptional& + getWeb_page (); + + void + setWeb_page (const Web_pageType& x); + + void + setWeb_page (const Web_pageOptional& x); + + void + setWeb_page (::std::unique_ptr< Web_pageType > p); + + // uris + // + typedef ::conference_info::Uris_type UrisType; + typedef ::xsd::cxx::tree::optional< UrisType > UrisOptional; + typedef ::xsd::cxx::tree::traits< UrisType, char > UrisTraits; + + const UrisOptional& + getUris () const; + + UrisOptional& + getUris (); + + void + setUris (const UrisType& x); + + void + setUris (const UrisOptional& x); + + void + setUris (::std::unique_ptr< UrisType > p); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + Host_type (); + + Host_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Host_type (const Host_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Host_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Host_type& + operator= (const Host_type& x); + + virtual + ~Host_type (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + Display_textOptional display_text_; + Web_pageOptional web_page_; + UrisOptional uris_; + AnySequence any_; + AnyAttributeSet any_attribute_; + }; + + class Conference_state_type: public ::xml_schema::Type + { + public: + // user-count + // + typedef ::xml_schema::UnsignedInt User_countType; + typedef ::xsd::cxx::tree::optional< User_countType > User_countOptional; + typedef ::xsd::cxx::tree::traits< User_countType, char > User_countTraits; + + const User_countOptional& + getUser_count () const; + + User_countOptional& + getUser_count (); + + void + setUser_count (const User_countType& x); + + void + setUser_count (const User_countOptional& x); + + // active + // + typedef ::xml_schema::Boolean ActiveType; + typedef ::xsd::cxx::tree::optional< ActiveType > ActiveOptional; + typedef ::xsd::cxx::tree::traits< ActiveType, char > ActiveTraits; + + const ActiveOptional& + getActive () const; + + ActiveOptional& + getActive (); + + void + setActive (const ActiveType& x); + + void + setActive (const ActiveOptional& x); + + // locked + // + typedef ::xml_schema::Boolean LockedType; + typedef ::xsd::cxx::tree::optional< LockedType > LockedOptional; + typedef ::xsd::cxx::tree::traits< LockedType, char > LockedTraits; + + const LockedOptional& + getLocked () const; + + LockedOptional& + getLocked (); + + void + setLocked (const LockedType& x); + + void + setLocked (const LockedOptional& x); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + Conference_state_type (); + + Conference_state_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Conference_state_type (const Conference_state_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Conference_state_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Conference_state_type& + operator= (const Conference_state_type& x); + + virtual + ~Conference_state_type (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + User_countOptional user_count_; + ActiveOptional active_; + LockedOptional locked_; + AnySequence any_; + AnyAttributeSet any_attribute_; + }; + + class Conference_media_type: public ::xml_schema::Type + { + public: + // entry + // + typedef ::conference_info::Conference_medium_type EntryType; + typedef ::xsd::cxx::tree::sequence< EntryType > EntrySequence; + typedef EntrySequence::iterator EntryIterator; + typedef EntrySequence::const_iterator EntryConstIterator; + typedef ::xsd::cxx::tree::traits< EntryType, char > EntryTraits; + + const EntrySequence& + getEntry () const; + + EntrySequence& + getEntry (); + + void + setEntry (const EntrySequence& s); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + Conference_media_type (); + + Conference_media_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Conference_media_type (const Conference_media_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Conference_media_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Conference_media_type& + operator= (const Conference_media_type& x); + + virtual + ~Conference_media_type (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + EntrySequence entry_; + AnyAttributeSet any_attribute_; + }; + + class Conference_medium_type: public ::xml_schema::Type + { + public: + // display-text + // + typedef ::xml_schema::String Display_textType; + typedef ::xsd::cxx::tree::optional< Display_textType > Display_textOptional; + typedef ::xsd::cxx::tree::traits< Display_textType, char > Display_textTraits; + + const Display_textOptional& + getDisplay_text () const; + + Display_textOptional& + getDisplay_text (); + + void + setDisplay_text (const Display_textType& x); + + void + setDisplay_text (const Display_textOptional& x); + + void + setDisplay_text (::std::unique_ptr< Display_textType > p); + + // type + // + typedef ::xml_schema::String TypeType; + typedef ::xsd::cxx::tree::traits< TypeType, char > TypeTraits; + + const TypeType& + getType () const; + + TypeType& + getType (); + + void + setType (const TypeType& x); + + void + setType (::std::unique_ptr< TypeType > p); + + ::std::unique_ptr< TypeType > + detachType (); + + // status + // + typedef ::conference_info::Media_status_type StatusType; + typedef ::xsd::cxx::tree::optional< StatusType > StatusOptional; + typedef ::xsd::cxx::tree::traits< StatusType, char > StatusTraits; + + const StatusOptional& + getStatus () const; + + StatusOptional& + getStatus (); + + void + setStatus (const StatusType& x); + + void + setStatus (const StatusOptional& x); + + void + setStatus (::std::unique_ptr< StatusType > p); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // label + // + typedef ::xml_schema::String LabelType; + typedef ::xsd::cxx::tree::traits< LabelType, char > LabelTraits; + + const LabelType& + getLabel () const; + + LabelType& + getLabel (); + + void + setLabel (const LabelType& x); + + void + setLabel (::std::unique_ptr< LabelType > p); + + ::std::unique_ptr< LabelType > + detachLabel (); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + Conference_medium_type (const TypeType&, + const LabelType&); + + Conference_medium_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Conference_medium_type (const Conference_medium_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Conference_medium_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Conference_medium_type& + operator= (const Conference_medium_type& x); + + virtual + ~Conference_medium_type (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + Display_textOptional display_text_; + ::xsd::cxx::tree::one< TypeType > type_; + StatusOptional status_; + AnySequence any_; + ::xsd::cxx::tree::one< LabelType > label_; + AnyAttributeSet any_attribute_; + }; + + class Uris_type: public ::xml_schema::Type + { + public: + // entry + // + typedef ::conference_info::Uri_type EntryType; + typedef ::xsd::cxx::tree::sequence< EntryType > EntrySequence; + typedef EntrySequence::iterator EntryIterator; + typedef EntrySequence::const_iterator EntryConstIterator; + typedef ::xsd::cxx::tree::traits< EntryType, char > EntryTraits; + + const EntrySequence& + getEntry () const; + + EntrySequence& + getEntry (); + + void + setEntry (const EntrySequence& s); + + // state + // + typedef ::conference_info::State_type StateType; + typedef ::xsd::cxx::tree::traits< StateType, char > StateTraits; + + const StateType& + getState () const; + + StateType& + getState (); + + void + setState (const StateType& x); + + void + setState (::std::unique_ptr< StateType > p); + + ::std::unique_ptr< StateType > + detachState (); + + static const StateType& + getStateDefaultValue (); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + Uris_type (); + + Uris_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Uris_type (const Uris_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Uris_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Uris_type& + operator= (const Uris_type& x); + + virtual + ~Uris_type (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + EntrySequence entry_; + ::xsd::cxx::tree::one< StateType > state_; + static const StateType state_default_value_; + AnyAttributeSet any_attribute_; + }; + + class Uri_type: public ::xml_schema::Type + { + public: + // uri + // + typedef ::xml_schema::Uri UriType; + typedef ::xsd::cxx::tree::traits< UriType, char > UriTraits; + + const UriType& + getUri () const; + + UriType& + getUri (); + + void + setUri (const UriType& x); + + void + setUri (::std::unique_ptr< UriType > p); + + ::std::unique_ptr< UriType > + detachUri (); + + // display-text + // + typedef ::xml_schema::String Display_textType; + typedef ::xsd::cxx::tree::optional< Display_textType > Display_textOptional; + typedef ::xsd::cxx::tree::traits< Display_textType, char > Display_textTraits; + + const Display_textOptional& + getDisplay_text () const; + + Display_textOptional& + getDisplay_text (); + + void + setDisplay_text (const Display_textType& x); + + void + setDisplay_text (const Display_textOptional& x); + + void + setDisplay_text (::std::unique_ptr< Display_textType > p); + + // purpose + // + typedef ::xml_schema::String PurposeType; + typedef ::xsd::cxx::tree::optional< PurposeType > PurposeOptional; + typedef ::xsd::cxx::tree::traits< PurposeType, char > PurposeTraits; + + const PurposeOptional& + getPurpose () const; + + PurposeOptional& + getPurpose (); + + void + setPurpose (const PurposeType& x); + + void + setPurpose (const PurposeOptional& x); + + void + setPurpose (::std::unique_ptr< PurposeType > p); + + // modified + // + typedef ::conference_info::Execution_type ModifiedType; + typedef ::xsd::cxx::tree::optional< ModifiedType > ModifiedOptional; + typedef ::xsd::cxx::tree::traits< ModifiedType, char > ModifiedTraits; + + const ModifiedOptional& + getModified () const; + + ModifiedOptional& + getModified (); + + void + setModified (const ModifiedType& x); + + void + setModified (const ModifiedOptional& x); + + void + setModified (::std::unique_ptr< ModifiedType > p); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + Uri_type (const UriType&); + + Uri_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Uri_type (const Uri_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Uri_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Uri_type& + operator= (const Uri_type& x); + + virtual + ~Uri_type (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + ::xsd::cxx::tree::one< UriType > uri_; + Display_textOptional display_text_; + PurposeOptional purpose_; + ModifiedOptional modified_; + AnySequence any_; + AnyAttributeSet any_attribute_; + }; + + class Keywords_type: public ::xml_schema::SimpleType, + public ::xsd::cxx::tree::list< ::xml_schema::String, char > + { + public: + Keywords_type (); + + Keywords_type (size_type n, const ::xml_schema::String& x); + + template < typename I > + Keywords_type (const I& begin, const I& end) + : ::xsd::cxx::tree::list< ::xml_schema::String, char > (begin, end, this) + { + } + + Keywords_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Keywords_type (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Keywords_type (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Keywords_type (const Keywords_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Keywords_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + virtual + ~Keywords_type (); + }; + + class Users_type: public ::xml_schema::Type + { + public: + // user + // + typedef ::conference_info::User_type UserType; + typedef ::xsd::cxx::tree::sequence< UserType > UserSequence; + typedef UserSequence::iterator UserIterator; + typedef UserSequence::const_iterator UserConstIterator; + typedef ::xsd::cxx::tree::traits< UserType, char > UserTraits; + + const UserSequence& + getUser () const; + + UserSequence& + getUser (); + + void + setUser (const UserSequence& s); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // state + // + typedef ::conference_info::State_type StateType; + typedef ::xsd::cxx::tree::traits< StateType, char > StateTraits; + + const StateType& + getState () const; + + StateType& + getState (); + + void + setState (const StateType& x); + + void + setState (::std::unique_ptr< StateType > p); + + ::std::unique_ptr< StateType > + detachState (); + + static const StateType& + getStateDefaultValue (); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + Users_type (); + + Users_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Users_type (const Users_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Users_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Users_type& + operator= (const Users_type& x); + + virtual + ~Users_type (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + UserSequence user_; + AnySequence any_; + ::xsd::cxx::tree::one< StateType > state_; + static const StateType state_default_value_; + AnyAttributeSet any_attribute_; + }; + + class User_type: public ::xml_schema::Type + { + public: + // display-text + // + typedef ::xml_schema::String Display_textType; + typedef ::xsd::cxx::tree::optional< Display_textType > Display_textOptional; + typedef ::xsd::cxx::tree::traits< Display_textType, char > Display_textTraits; + + const Display_textOptional& + getDisplay_text () const; + + Display_textOptional& + getDisplay_text (); + + void + setDisplay_text (const Display_textType& x); + + void + setDisplay_text (const Display_textOptional& x); + + void + setDisplay_text (::std::unique_ptr< Display_textType > p); + + // associated-aors + // + typedef ::conference_info::Uris_type Associated_aorsType; + typedef ::xsd::cxx::tree::optional< Associated_aorsType > Associated_aorsOptional; + typedef ::xsd::cxx::tree::traits< Associated_aorsType, char > Associated_aorsTraits; + + const Associated_aorsOptional& + getAssociated_aors () const; + + Associated_aorsOptional& + getAssociated_aors (); + + void + setAssociated_aors (const Associated_aorsType& x); + + void + setAssociated_aors (const Associated_aorsOptional& x); + + void + setAssociated_aors (::std::unique_ptr< Associated_aorsType > p); + + // roles + // + typedef ::conference_info::User_roles_type RolesType; + typedef ::xsd::cxx::tree::optional< RolesType > RolesOptional; + typedef ::xsd::cxx::tree::traits< RolesType, char > RolesTraits; + + const RolesOptional& + getRoles () const; + + RolesOptional& + getRoles (); + + void + setRoles (const RolesType& x); + + void + setRoles (const RolesOptional& x); + + void + setRoles (::std::unique_ptr< RolesType > p); + + // languages + // + typedef ::conference_info::User_languages_type LanguagesType; + typedef ::xsd::cxx::tree::optional< LanguagesType > LanguagesOptional; + typedef ::xsd::cxx::tree::traits< LanguagesType, char > LanguagesTraits; + + const LanguagesOptional& + getLanguages () const; + + LanguagesOptional& + getLanguages (); + + void + setLanguages (const LanguagesType& x); + + void + setLanguages (const LanguagesOptional& x); + + void + setLanguages (::std::unique_ptr< LanguagesType > p); + + // cascaded-focus + // + typedef ::xml_schema::Uri Cascaded_focusType; + typedef ::xsd::cxx::tree::optional< Cascaded_focusType > Cascaded_focusOptional; + typedef ::xsd::cxx::tree::traits< Cascaded_focusType, char > Cascaded_focusTraits; + + const Cascaded_focusOptional& + getCascaded_focus () const; + + Cascaded_focusOptional& + getCascaded_focus (); + + void + setCascaded_focus (const Cascaded_focusType& x); + + void + setCascaded_focus (const Cascaded_focusOptional& x); + + void + setCascaded_focus (::std::unique_ptr< Cascaded_focusType > p); + + // endpoint + // + typedef ::conference_info::Endpoint_type EndpointType; + typedef ::xsd::cxx::tree::sequence< EndpointType > EndpointSequence; + typedef EndpointSequence::iterator EndpointIterator; + typedef EndpointSequence::const_iterator EndpointConstIterator; + typedef ::xsd::cxx::tree::traits< EndpointType, char > EndpointTraits; + + const EndpointSequence& + getEndpoint () const; + + EndpointSequence& + getEndpoint (); + + void + setEndpoint (const EndpointSequence& s); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // entity + // + typedef ::xml_schema::Uri EntityType; + typedef ::xsd::cxx::tree::optional< EntityType > EntityOptional; + typedef ::xsd::cxx::tree::traits< EntityType, char > EntityTraits; + + const EntityOptional& + getEntity () const; + + EntityOptional& + getEntity (); + + void + setEntity (const EntityType& x); + + void + setEntity (const EntityOptional& x); + + void + setEntity (::std::unique_ptr< EntityType > p); + + // state + // + typedef ::conference_info::State_type StateType; + typedef ::xsd::cxx::tree::traits< StateType, char > StateTraits; + + const StateType& + getState () const; + + StateType& + getState (); + + void + setState (const StateType& x); + + void + setState (::std::unique_ptr< StateType > p); + + ::std::unique_ptr< StateType > + detachState (); + + static const StateType& + getStateDefaultValue (); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + User_type (); + + User_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + User_type (const User_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual User_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + User_type& + operator= (const User_type& x); + + virtual + ~User_type (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + Display_textOptional display_text_; + Associated_aorsOptional associated_aors_; + RolesOptional roles_; + LanguagesOptional languages_; + Cascaded_focusOptional cascaded_focus_; + EndpointSequence endpoint_; + AnySequence any_; + EntityOptional entity_; + ::xsd::cxx::tree::one< StateType > state_; + static const StateType state_default_value_; + AnyAttributeSet any_attribute_; + }; + + class User_roles_type: public ::xml_schema::Type + { + public: + // entry + // + typedef ::xml_schema::String EntryType; + typedef ::xsd::cxx::tree::sequence< EntryType > EntrySequence; + typedef EntrySequence::iterator EntryIterator; + typedef EntrySequence::const_iterator EntryConstIterator; + typedef ::xsd::cxx::tree::traits< EntryType, char > EntryTraits; + + const EntrySequence& + getEntry () const; + + EntrySequence& + getEntry (); + + void + setEntry (const EntrySequence& s); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + User_roles_type (); + + User_roles_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + User_roles_type (const User_roles_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual User_roles_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + User_roles_type& + operator= (const User_roles_type& x); + + virtual + ~User_roles_type (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + EntrySequence entry_; + AnyAttributeSet any_attribute_; + }; + + class User_languages_type: public ::xml_schema::SimpleType, + public ::xsd::cxx::tree::list< ::xml_schema::Language, char > + { + public: + User_languages_type (); + + User_languages_type (size_type n, const ::xml_schema::Language& x); + + template < typename I > + User_languages_type (const I& begin, const I& end) + : ::xsd::cxx::tree::list< ::xml_schema::Language, char > (begin, end, this) + { + } + + User_languages_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + User_languages_type (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + User_languages_type (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + User_languages_type (const User_languages_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual User_languages_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + virtual + ~User_languages_type (); + }; + + class Endpoint_type: public ::xml_schema::Type + { + public: + // display-text + // + typedef ::xml_schema::String Display_textType; + typedef ::xsd::cxx::tree::optional< Display_textType > Display_textOptional; + typedef ::xsd::cxx::tree::traits< Display_textType, char > Display_textTraits; + + const Display_textOptional& + getDisplay_text () const; + + Display_textOptional& + getDisplay_text (); + + void + setDisplay_text (const Display_textType& x); + + void + setDisplay_text (const Display_textOptional& x); + + void + setDisplay_text (::std::unique_ptr< Display_textType > p); + + // referred + // + typedef ::conference_info::Execution_type ReferredType; + typedef ::xsd::cxx::tree::optional< ReferredType > ReferredOptional; + typedef ::xsd::cxx::tree::traits< ReferredType, char > ReferredTraits; + + const ReferredOptional& + getReferred () const; + + ReferredOptional& + getReferred (); + + void + setReferred (const ReferredType& x); + + void + setReferred (const ReferredOptional& x); + + void + setReferred (::std::unique_ptr< ReferredType > p); + + // status + // + typedef ::conference_info::Endpoint_status_type StatusType; + typedef ::xsd::cxx::tree::optional< StatusType > StatusOptional; + typedef ::xsd::cxx::tree::traits< StatusType, char > StatusTraits; + + const StatusOptional& + getStatus () const; + + StatusOptional& + getStatus (); + + void + setStatus (const StatusType& x); + + void + setStatus (const StatusOptional& x); + + void + setStatus (::std::unique_ptr< StatusType > p); + + // joining-method + // + typedef ::conference_info::Joining_type Joining_methodType; + typedef ::xsd::cxx::tree::optional< Joining_methodType > Joining_methodOptional; + typedef ::xsd::cxx::tree::traits< Joining_methodType, char > Joining_methodTraits; + + const Joining_methodOptional& + getJoining_method () const; + + Joining_methodOptional& + getJoining_method (); + + void + setJoining_method (const Joining_methodType& x); + + void + setJoining_method (const Joining_methodOptional& x); + + void + setJoining_method (::std::unique_ptr< Joining_methodType > p); + + // joining-info + // + typedef ::conference_info::Execution_type Joining_infoType; + typedef ::xsd::cxx::tree::optional< Joining_infoType > Joining_infoOptional; + typedef ::xsd::cxx::tree::traits< Joining_infoType, char > Joining_infoTraits; + + const Joining_infoOptional& + getJoining_info () const; + + Joining_infoOptional& + getJoining_info (); + + void + setJoining_info (const Joining_infoType& x); + + void + setJoining_info (const Joining_infoOptional& x); + + void + setJoining_info (::std::unique_ptr< Joining_infoType > p); + + // disconnection-method + // + typedef ::conference_info::Disconnection_type Disconnection_methodType; + typedef ::xsd::cxx::tree::optional< Disconnection_methodType > Disconnection_methodOptional; + typedef ::xsd::cxx::tree::traits< Disconnection_methodType, char > Disconnection_methodTraits; + + const Disconnection_methodOptional& + getDisconnection_method () const; + + Disconnection_methodOptional& + getDisconnection_method (); + + void + setDisconnection_method (const Disconnection_methodType& x); + + void + setDisconnection_method (const Disconnection_methodOptional& x); + + void + setDisconnection_method (::std::unique_ptr< Disconnection_methodType > p); + + // disconnection-info + // + typedef ::conference_info::Execution_type Disconnection_infoType; + typedef ::xsd::cxx::tree::optional< Disconnection_infoType > Disconnection_infoOptional; + typedef ::xsd::cxx::tree::traits< Disconnection_infoType, char > Disconnection_infoTraits; + + const Disconnection_infoOptional& + getDisconnection_info () const; + + Disconnection_infoOptional& + getDisconnection_info (); + + void + setDisconnection_info (const Disconnection_infoType& x); + + void + setDisconnection_info (const Disconnection_infoOptional& x); + + void + setDisconnection_info (::std::unique_ptr< Disconnection_infoType > p); + + // media + // + typedef ::conference_info::Media_type MediaType; + typedef ::xsd::cxx::tree::sequence< MediaType > MediaSequence; + typedef MediaSequence::iterator MediaIterator; + typedef MediaSequence::const_iterator MediaConstIterator; + typedef ::xsd::cxx::tree::traits< MediaType, char > MediaTraits; + + const MediaSequence& + getMedia () const; + + MediaSequence& + getMedia (); + + void + setMedia (const MediaSequence& s); + + // call-info + // + typedef ::conference_info::Call_type Call_infoType; + typedef ::xsd::cxx::tree::optional< Call_infoType > Call_infoOptional; + typedef ::xsd::cxx::tree::traits< Call_infoType, char > Call_infoTraits; + + const Call_infoOptional& + getCall_info () const; + + Call_infoOptional& + getCall_info (); + + void + setCall_info (const Call_infoType& x); + + void + setCall_info (const Call_infoOptional& x); + + void + setCall_info (::std::unique_ptr< Call_infoType > p); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // entity + // + typedef ::xml_schema::String EntityType; + typedef ::xsd::cxx::tree::optional< EntityType > EntityOptional; + typedef ::xsd::cxx::tree::traits< EntityType, char > EntityTraits; + + const EntityOptional& + getEntity () const; + + EntityOptional& + getEntity (); + + void + setEntity (const EntityType& x); + + void + setEntity (const EntityOptional& x); + + void + setEntity (::std::unique_ptr< EntityType > p); + + // state + // + typedef ::conference_info::State_type StateType; + typedef ::xsd::cxx::tree::traits< StateType, char > StateTraits; + + const StateType& + getState () const; + + StateType& + getState (); + + void + setState (const StateType& x); + + void + setState (::std::unique_ptr< StateType > p); + + ::std::unique_ptr< StateType > + detachState (); + + static const StateType& + getStateDefaultValue (); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + Endpoint_type (); + + Endpoint_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Endpoint_type (const Endpoint_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Endpoint_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Endpoint_type& + operator= (const Endpoint_type& x); + + virtual + ~Endpoint_type (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + Display_textOptional display_text_; + ReferredOptional referred_; + StatusOptional status_; + Joining_methodOptional joining_method_; + Joining_infoOptional joining_info_; + Disconnection_methodOptional disconnection_method_; + Disconnection_infoOptional disconnection_info_; + MediaSequence media_; + Call_infoOptional call_info_; + AnySequence any_; + EntityOptional entity_; + ::xsd::cxx::tree::one< StateType > state_; + static const StateType state_default_value_; + AnyAttributeSet any_attribute_; + }; + + class Endpoint_status_type: public ::xml_schema::String + { + public: + enum Value + { + pending, + dialing_out, + dialing_in, + alerting, + on_hold, + connected, + muted_via_focus, + disconnecting, + disconnected + }; + + Endpoint_status_type (Value v); + + Endpoint_status_type (const char* v); + + Endpoint_status_type (const ::std::string& v); + + Endpoint_status_type (const ::xml_schema::String& v); + + Endpoint_status_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Endpoint_status_type (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Endpoint_status_type (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Endpoint_status_type (const Endpoint_status_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Endpoint_status_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Endpoint_status_type& + operator= (Value v); + + virtual + operator Value () const + { + return _xsd_Endpoint_status_type_convert (); + } + + protected: + Value + _xsd_Endpoint_status_type_convert () const; + + public: + static const char* const _xsd_Endpoint_status_type_literals_[9]; + static const Value _xsd_Endpoint_status_type_indexes_[9]; + }; + + class Joining_type: public ::xml_schema::String + { + public: + enum Value + { + dialed_in, + dialed_out, + focus_owner + }; + + Joining_type (Value v); + + Joining_type (const char* v); + + Joining_type (const ::std::string& v); + + Joining_type (const ::xml_schema::String& v); + + Joining_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Joining_type (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Joining_type (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Joining_type (const Joining_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Joining_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Joining_type& + operator= (Value v); + + virtual + operator Value () const + { + return _xsd_Joining_type_convert (); + } + + protected: + Value + _xsd_Joining_type_convert () const; + + public: + static const char* const _xsd_Joining_type_literals_[3]; + static const Value _xsd_Joining_type_indexes_[3]; + }; + + class Disconnection_type: public ::xml_schema::String + { + public: + enum Value + { + departed, + booted, + failed, + busy + }; + + Disconnection_type (Value v); + + Disconnection_type (const char* v); + + Disconnection_type (const ::std::string& v); + + Disconnection_type (const ::xml_schema::String& v); + + Disconnection_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Disconnection_type (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Disconnection_type (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Disconnection_type (const Disconnection_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Disconnection_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Disconnection_type& + operator= (Value v); + + virtual + operator Value () const + { + return _xsd_Disconnection_type_convert (); + } + + protected: + Value + _xsd_Disconnection_type_convert () const; + + public: + static const char* const _xsd_Disconnection_type_literals_[4]; + static const Value _xsd_Disconnection_type_indexes_[4]; + }; + + class Execution_type: public ::xml_schema::Type + { + public: + // when + // + typedef ::xml_schema::DateTime WhenType; + typedef ::xsd::cxx::tree::optional< WhenType > WhenOptional; + typedef ::xsd::cxx::tree::traits< WhenType, char > WhenTraits; + + const WhenOptional& + getWhen () const; + + WhenOptional& + getWhen (); + + void + setWhen (const WhenType& x); + + void + setWhen (const WhenOptional& x); + + void + setWhen (::std::unique_ptr< WhenType > p); + + // reason + // + typedef ::xml_schema::String ReasonType; + typedef ::xsd::cxx::tree::optional< ReasonType > ReasonOptional; + typedef ::xsd::cxx::tree::traits< ReasonType, char > ReasonTraits; + + const ReasonOptional& + getReason () const; + + ReasonOptional& + getReason (); + + void + setReason (const ReasonType& x); + + void + setReason (const ReasonOptional& x); + + void + setReason (::std::unique_ptr< ReasonType > p); + + // by + // + typedef ::xml_schema::Uri ByType; + typedef ::xsd::cxx::tree::optional< ByType > ByOptional; + typedef ::xsd::cxx::tree::traits< ByType, char > ByTraits; + + const ByOptional& + getBy () const; + + ByOptional& + getBy (); + + void + setBy (const ByType& x); + + void + setBy (const ByOptional& x); + + void + setBy (::std::unique_ptr< ByType > p); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + Execution_type (); + + Execution_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Execution_type (const Execution_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Execution_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Execution_type& + operator= (const Execution_type& x); + + virtual + ~Execution_type (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + WhenOptional when_; + ReasonOptional reason_; + ByOptional by_; + AnyAttributeSet any_attribute_; + }; + + class Call_type: public ::xml_schema::Type + { + public: + // sip + // + typedef ::conference_info::Sip_dialog_id_type SipType; + typedef ::xsd::cxx::tree::optional< SipType > SipOptional; + typedef ::xsd::cxx::tree::traits< SipType, char > SipTraits; + + const SipOptional& + getSip () const; + + SipOptional& + getSip (); + + void + setSip (const SipType& x); + + void + setSip (const SipOptional& x); + + void + setSip (::std::unique_ptr< SipType > p); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + Call_type (); + + Call_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Call_type (const Call_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Call_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Call_type& + operator= (const Call_type& x); + + virtual + ~Call_type (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + SipOptional sip_; + AnySequence any_; + AnyAttributeSet any_attribute_; + }; + + class Sip_dialog_id_type: public ::xml_schema::Type + { + public: + // display-text + // + typedef ::xml_schema::String Display_textType; + typedef ::xsd::cxx::tree::optional< Display_textType > Display_textOptional; + typedef ::xsd::cxx::tree::traits< Display_textType, char > Display_textTraits; + + const Display_textOptional& + getDisplay_text () const; + + Display_textOptional& + getDisplay_text (); + + void + setDisplay_text (const Display_textType& x); + + void + setDisplay_text (const Display_textOptional& x); + + void + setDisplay_text (::std::unique_ptr< Display_textType > p); + + // call-id + // + typedef ::xml_schema::String Call_idType; + typedef ::xsd::cxx::tree::traits< Call_idType, char > Call_idTraits; + + const Call_idType& + getCall_id () const; + + Call_idType& + getCall_id (); + + void + setCall_id (const Call_idType& x); + + void + setCall_id (::std::unique_ptr< Call_idType > p); + + ::std::unique_ptr< Call_idType > + detachCall_id (); + + // from-tag + // + typedef ::xml_schema::String From_tagType; + typedef ::xsd::cxx::tree::traits< From_tagType, char > From_tagTraits; + + const From_tagType& + getFrom_tag () const; + + From_tagType& + getFrom_tag (); + + void + setFrom_tag (const From_tagType& x); + + void + setFrom_tag (::std::unique_ptr< From_tagType > p); + + ::std::unique_ptr< From_tagType > + detachFrom_tag (); + + // to-tag + // + typedef ::xml_schema::String To_tagType; + typedef ::xsd::cxx::tree::traits< To_tagType, char > To_tagTraits; + + const To_tagType& + getTo_tag () const; + + To_tagType& + getTo_tag (); + + void + setTo_tag (const To_tagType& x); + + void + setTo_tag (::std::unique_ptr< To_tagType > p); + + ::std::unique_ptr< To_tagType > + detachTo_tag (); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + Sip_dialog_id_type (const Call_idType&, + const From_tagType&, + const To_tagType&); + + Sip_dialog_id_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Sip_dialog_id_type (const Sip_dialog_id_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Sip_dialog_id_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Sip_dialog_id_type& + operator= (const Sip_dialog_id_type& x); + + virtual + ~Sip_dialog_id_type (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + Display_textOptional display_text_; + ::xsd::cxx::tree::one< Call_idType > call_id_; + ::xsd::cxx::tree::one< From_tagType > from_tag_; + ::xsd::cxx::tree::one< To_tagType > to_tag_; + AnySequence any_; + AnyAttributeSet any_attribute_; + }; + + class Media_type: public ::xml_schema::Type + { + public: + // display-text + // + typedef ::xml_schema::String Display_textType; + typedef ::xsd::cxx::tree::optional< Display_textType > Display_textOptional; + typedef ::xsd::cxx::tree::traits< Display_textType, char > Display_textTraits; + + const Display_textOptional& + getDisplay_text () const; + + Display_textOptional& + getDisplay_text (); + + void + setDisplay_text (const Display_textType& x); + + void + setDisplay_text (const Display_textOptional& x); + + void + setDisplay_text (::std::unique_ptr< Display_textType > p); + + // type + // + typedef ::xml_schema::String TypeType; + typedef ::xsd::cxx::tree::optional< TypeType > TypeOptional; + typedef ::xsd::cxx::tree::traits< TypeType, char > TypeTraits; + + const TypeOptional& + getType () const; + + TypeOptional& + getType (); + + void + setType (const TypeType& x); + + void + setType (const TypeOptional& x); + + void + setType (::std::unique_ptr< TypeType > p); + + // label + // + typedef ::xml_schema::String LabelType; + typedef ::xsd::cxx::tree::optional< LabelType > LabelOptional; + typedef ::xsd::cxx::tree::traits< LabelType, char > LabelTraits; + + const LabelOptional& + getLabel () const; + + LabelOptional& + getLabel (); + + void + setLabel (const LabelType& x); + + void + setLabel (const LabelOptional& x); + + void + setLabel (::std::unique_ptr< LabelType > p); + + // src-id + // + typedef ::xml_schema::String Src_idType; + typedef ::xsd::cxx::tree::optional< Src_idType > Src_idOptional; + typedef ::xsd::cxx::tree::traits< Src_idType, char > Src_idTraits; + + const Src_idOptional& + getSrc_id () const; + + Src_idOptional& + getSrc_id (); + + void + setSrc_id (const Src_idType& x); + + void + setSrc_id (const Src_idOptional& x); + + void + setSrc_id (::std::unique_ptr< Src_idType > p); + + // status + // + typedef ::conference_info::Media_status_type StatusType; + typedef ::xsd::cxx::tree::optional< StatusType > StatusOptional; + typedef ::xsd::cxx::tree::traits< StatusType, char > StatusTraits; + + const StatusOptional& + getStatus () const; + + StatusOptional& + getStatus (); + + void + setStatus (const StatusType& x); + + void + setStatus (const StatusOptional& x); + + void + setStatus (::std::unique_ptr< StatusType > p); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // id + // + typedef ::xml_schema::String IdType; + typedef ::xsd::cxx::tree::traits< IdType, char > IdTraits; + + const IdType& + getId () const; + + IdType& + getId (); + + void + setId (const IdType& x); + + void + setId (::std::unique_ptr< IdType > p); + + ::std::unique_ptr< IdType > + detachId (); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + Media_type (const IdType&); + + Media_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Media_type (const Media_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Media_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Media_type& + operator= (const Media_type& x); + + virtual + ~Media_type (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + Display_textOptional display_text_; + TypeOptional type_; + LabelOptional label_; + Src_idOptional src_id_; + StatusOptional status_; + AnySequence any_; + ::xsd::cxx::tree::one< IdType > id_; + AnyAttributeSet any_attribute_; + }; + + class Media_status_type: public ::xml_schema::String + { + public: + enum Value + { + recvonly, + sendonly, + sendrecv, + inactive + }; + + Media_status_type (Value v); + + Media_status_type (const char* v); + + Media_status_type (const ::std::string& v); + + Media_status_type (const ::xml_schema::String& v); + + Media_status_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Media_status_type (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Media_status_type (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Media_status_type (const Media_status_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Media_status_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Media_status_type& + operator= (Value v); + + virtual + operator Value () const + { + return _xsd_Media_status_type_convert (); + } + + protected: + Value + _xsd_Media_status_type_convert () const; + + public: + static const char* const _xsd_Media_status_type_literals_[4]; + static const Value _xsd_Media_status_type_indexes_[4]; + }; + + class Sidebars_by_val_type: public ::xml_schema::Type + { + public: + // entry + // + typedef ::conference_info::Conference_type EntryType; + typedef ::xsd::cxx::tree::sequence< EntryType > EntrySequence; + typedef EntrySequence::iterator EntryIterator; + typedef EntrySequence::const_iterator EntryConstIterator; + typedef ::xsd::cxx::tree::traits< EntryType, char > EntryTraits; + + const EntrySequence& + getEntry () const; + + EntrySequence& + getEntry (); + + void + setEntry (const EntrySequence& s); + + // state + // + typedef ::conference_info::State_type StateType; + typedef ::xsd::cxx::tree::traits< StateType, char > StateTraits; + + const StateType& + getState () const; + + StateType& + getState (); + + void + setState (const StateType& x); + + void + setState (::std::unique_ptr< StateType > p); + + ::std::unique_ptr< StateType > + detachState (); + + static const StateType& + getStateDefaultValue (); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + Sidebars_by_val_type (); + + Sidebars_by_val_type (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Sidebars_by_val_type (const Sidebars_by_val_type& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Sidebars_by_val_type* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Sidebars_by_val_type& + operator= (const Sidebars_by_val_type& x); + + virtual + ~Sidebars_by_val_type (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + EntrySequence entry_; + ::xsd::cxx::tree::one< StateType > state_; + static const StateType state_default_value_; + AnyAttributeSet any_attribute_; + }; +} + +#include + +namespace conference_info +{ + ::std::ostream& + operator<< (::std::ostream&, const Conference_type&); + + ::std::ostream& + operator<< (::std::ostream&, State_type::Value); + + ::std::ostream& + operator<< (::std::ostream&, const State_type&); + + ::std::ostream& + operator<< (::std::ostream&, const Conference_description_type&); + + ::std::ostream& + operator<< (::std::ostream&, const Host_type&); + + ::std::ostream& + operator<< (::std::ostream&, const Conference_state_type&); + + ::std::ostream& + operator<< (::std::ostream&, const Conference_media_type&); + + ::std::ostream& + operator<< (::std::ostream&, const Conference_medium_type&); + + ::std::ostream& + operator<< (::std::ostream&, const Uris_type&); + + ::std::ostream& + operator<< (::std::ostream&, const Uri_type&); + + ::std::ostream& + operator<< (::std::ostream&, const Keywords_type&); + + ::std::ostream& + operator<< (::std::ostream&, const Users_type&); + + ::std::ostream& + operator<< (::std::ostream&, const User_type&); + + ::std::ostream& + operator<< (::std::ostream&, const User_roles_type&); + + ::std::ostream& + operator<< (::std::ostream&, const User_languages_type&); + + ::std::ostream& + operator<< (::std::ostream&, const Endpoint_type&); + + ::std::ostream& + operator<< (::std::ostream&, Endpoint_status_type::Value); + + ::std::ostream& + operator<< (::std::ostream&, const Endpoint_status_type&); + + ::std::ostream& + operator<< (::std::ostream&, Joining_type::Value); + + ::std::ostream& + operator<< (::std::ostream&, const Joining_type&); + + ::std::ostream& + operator<< (::std::ostream&, Disconnection_type::Value); + + ::std::ostream& + operator<< (::std::ostream&, const Disconnection_type&); + + ::std::ostream& + operator<< (::std::ostream&, const Execution_type&); + + ::std::ostream& + operator<< (::std::ostream&, const Call_type&); + + ::std::ostream& + operator<< (::std::ostream&, const Sip_dialog_id_type&); + + ::std::ostream& + operator<< (::std::ostream&, const Media_type&); + + ::std::ostream& + operator<< (::std::ostream&, Media_status_type::Value); + + ::std::ostream& + operator<< (::std::ostream&, const Media_status_type&); + + ::std::ostream& + operator<< (::std::ostream&, const Sidebars_by_val_type&); +} + +#include + +#include +#include +#include + +namespace conference_info +{ + // Parse a URI or a local file. + // + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (const ::std::string& uri, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (const ::std::string& uri, + ::xml_schema::ErrorHandler& eh, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (const ::std::string& uri, + ::xercesc::DOMErrorHandler& eh, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + // Parse std::istream. + // + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::std::istream& is, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::std::istream& is, + ::xml_schema::ErrorHandler& eh, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::std::istream& is, + ::xercesc::DOMErrorHandler& eh, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::std::istream& is, + const ::std::string& id, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::std::istream& is, + const ::std::string& id, + ::xml_schema::ErrorHandler& eh, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::std::istream& is, + const ::std::string& id, + ::xercesc::DOMErrorHandler& eh, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + // Parse xercesc::InputSource. + // + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::xercesc::InputSource& is, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::xercesc::InputSource& is, + ::xml_schema::ErrorHandler& eh, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::xercesc::InputSource& is, + ::xercesc::DOMErrorHandler& eh, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + // Parse xercesc::DOMDocument. + // + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (const ::xercesc::DOMDocument& d, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::conference_info::Conference_type > + parseConference_info (::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); +} + +#include + +#include +#include +#include + +#include + +namespace conference_info +{ + // Serialize to std::ostream. + // + + void + serializeConference_info (::std::ostream& os, + const ::conference_info::Conference_type& x, + const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::xml_schema::Flags f = 0); + + void + serializeConference_info (::std::ostream& os, + const ::conference_info::Conference_type& x, + ::xml_schema::ErrorHandler& eh, + const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::xml_schema::Flags f = 0); + + void + serializeConference_info (::std::ostream& os, + const ::conference_info::Conference_type& x, + ::xercesc::DOMErrorHandler& eh, + const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::xml_schema::Flags f = 0); + + // Serialize to xercesc::XMLFormatTarget. + // + + void + serializeConference_info (::xercesc::XMLFormatTarget& ft, + const ::conference_info::Conference_type& x, + const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::xml_schema::Flags f = 0); + + void + serializeConference_info (::xercesc::XMLFormatTarget& ft, + const ::conference_info::Conference_type& x, + ::xml_schema::ErrorHandler& eh, + const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::xml_schema::Flags f = 0); + + void + serializeConference_info (::xercesc::XMLFormatTarget& ft, + const ::conference_info::Conference_type& x, + ::xercesc::DOMErrorHandler& eh, + const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::xml_schema::Flags f = 0); + + // Serialize to an existing xercesc::DOMDocument. + // + + void + serializeConference_info (::xercesc::DOMDocument& d, + const ::conference_info::Conference_type& x, + ::xml_schema::Flags f = 0); + + // Serialize to a new xercesc::DOMDocument. + // + + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > + serializeConference_info (const ::conference_info::Conference_type& x, + const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), + ::xml_schema::Flags f = 0); + + void + operator<< (::xercesc::DOMElement&, const Conference_type&); + + void + operator<< (::xercesc::DOMElement&, const State_type&); + + void + operator<< (::xercesc::DOMAttr&, const State_type&); + + void + operator<< (::xml_schema::ListStream&, + const State_type&); + + void + operator<< (::xercesc::DOMElement&, const Conference_description_type&); + + void + operator<< (::xercesc::DOMElement&, const Host_type&); + + void + operator<< (::xercesc::DOMElement&, const Conference_state_type&); + + void + operator<< (::xercesc::DOMElement&, const Conference_media_type&); + + void + operator<< (::xercesc::DOMElement&, const Conference_medium_type&); + + void + operator<< (::xercesc::DOMElement&, const Uris_type&); + + void + operator<< (::xercesc::DOMElement&, const Uri_type&); + + void + operator<< (::xercesc::DOMElement&, const Keywords_type&); + + void + operator<< (::xercesc::DOMAttr&, const Keywords_type&); + + void + operator<< (::xml_schema::ListStream&, + const Keywords_type&); + + void + operator<< (::xercesc::DOMElement&, const Users_type&); + + void + operator<< (::xercesc::DOMElement&, const User_type&); + + void + operator<< (::xercesc::DOMElement&, const User_roles_type&); + + void + operator<< (::xercesc::DOMElement&, const User_languages_type&); + + void + operator<< (::xercesc::DOMAttr&, const User_languages_type&); + + void + operator<< (::xml_schema::ListStream&, + const User_languages_type&); + + void + operator<< (::xercesc::DOMElement&, const Endpoint_type&); + + void + operator<< (::xercesc::DOMElement&, const Endpoint_status_type&); + + void + operator<< (::xercesc::DOMAttr&, const Endpoint_status_type&); + + void + operator<< (::xml_schema::ListStream&, + const Endpoint_status_type&); + + void + operator<< (::xercesc::DOMElement&, const Joining_type&); + + void + operator<< (::xercesc::DOMAttr&, const Joining_type&); + + void + operator<< (::xml_schema::ListStream&, + const Joining_type&); + + void + operator<< (::xercesc::DOMElement&, const Disconnection_type&); + + void + operator<< (::xercesc::DOMAttr&, const Disconnection_type&); + + void + operator<< (::xml_schema::ListStream&, + const Disconnection_type&); + + void + operator<< (::xercesc::DOMElement&, const Execution_type&); + + void + operator<< (::xercesc::DOMElement&, const Call_type&); + + void + operator<< (::xercesc::DOMElement&, const Sip_dialog_id_type&); + + void + operator<< (::xercesc::DOMElement&, const Media_type&); + + void + operator<< (::xercesc::DOMElement&, const Media_status_type&); + + void + operator<< (::xercesc::DOMAttr&, const Media_status_type&); + + void + operator<< (::xml_schema::ListStream&, + const Media_status_type&); + + void + operator<< (::xercesc::DOMElement&, const Sidebars_by_val_type&); +} + +#include + +// Begin epilogue. +// +// +// End epilogue. + +#endif // CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_FLEXISIP_SRC_XML_CONFERENCE_INFO_HXX diff --git a/src/conference/conference-info.xsd b/src/conference/conference-info.xsd new file mode 100644 index 000000000..8f7b332ac --- /dev/null +++ b/src/conference/conference-info.xsd @@ -0,0 +1,387 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/conference/conference-listener.h b/src/conference/conference-listener.h new file mode 100644 index 000000000..e5c596fd3 --- /dev/null +++ b/src/conference/conference-listener.h @@ -0,0 +1,41 @@ +/* + * conference-listener.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CONFERENCE_LISTENER_H_ +#define _CONFERENCE_LISTENER_H_ + +#include "linphone/core.h" + +namespace LinphonePrivate { + namespace Conference { + // ------------------------------------------------------------------------- + // ConferenceListener. + // ------------------------------------------------------------------------- + class ConferenceListener { + public: + //virtual ~ConferenceListener() = 0; + virtual void conferenceCreated(LinphoneAddress *confAddress) = 0; + virtual void conferenceTerminated(LinphoneAddress *confAddress) = 0; + virtual void participantAdded(LinphoneAddress *addr) = 0; + virtual void participantRemoved(LinphoneAddress *addr) = 0; + virtual void participantSetAdmin(LinphoneAddress *addr, bool isAdmin) = 0; + }; + } +} + +#endif // ifndef _CONFERENCE_LISTENER_H_ \ No newline at end of file diff --git a/src/conference/xml.hxx b/src/conference/xml.hxx new file mode 100644 index 000000000..52de06acf --- /dev/null +++ b/src/conference/xml.hxx @@ -0,0 +1,503 @@ +// Copyright (c) 2005-2014 Code Synthesis Tools CC +// +// This program was generated by CodeSynthesis XSD, an XML Schema to +// C++ data binding compiler. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// 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 St, Fifth Floor, Boston, MA 02110-1301 USA +// +// In addition, as a special exception, Code Synthesis Tools CC gives +// permission to link this program with the Xerces-C++ library (or with +// modified versions of Xerces-C++ that use the same license as Xerces-C++), +// and distribute linked combinations including the two. You must obey +// the GNU General Public License version 2 in all respects for all of +// the code used other than Xerces-C++. If you modify this copy of the +// program, you may extend this exception to your version of the program, +// but you are not obligated to do so. If you do not wish to do so, delete +// this exception statement from your version. +// +// Furthermore, Code Synthesis Tools CC makes a special exception for +// the Free/Libre and Open Source Software (FLOSS) which is described +// in the accompanying FLOSSE file. +// + +#ifndef CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_FLEXISIP_PRIVATE_SRC_XML_XML_HXX +#define CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_FLEXISIP_PRIVATE_SRC_XML_XML_HXX + +#ifndef XSD_CXX11 +#define XSD_CXX11 +#endif + +#ifndef XSD_USE_CHAR +#define XSD_USE_CHAR +#endif + +#ifndef XSD_CXX_TREE_USE_CHAR +#define XSD_CXX_TREE_USE_CHAR +#endif + +// Begin prologue. +// +// +// End prologue. + +#include + +#if (XSD_INT_VERSION != 4000000L) +#error XSD runtime version mismatch +#endif + +#include + +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace xml_schema +{ + // anyType and anySimpleType. + // + typedef ::xsd::cxx::tree::type Type; + typedef ::xsd::cxx::tree::simple_type< char, Type > SimpleType; + typedef ::xsd::cxx::tree::type Container; + + // 8-bit + // + typedef signed char Byte; + typedef unsigned char UnsignedByte; + + // 16-bit + // + typedef short Short; + typedef unsigned short UnsignedShort; + + // 32-bit + // + typedef int Int; + typedef unsigned int UnsignedInt; + + // 64-bit + // + typedef long long Long; + typedef unsigned long long UnsignedLong; + + // Supposed to be arbitrary-length integral types. + // + typedef long long Integer; + typedef long long NonPositiveInteger; + typedef unsigned long long NonNegativeInteger; + typedef unsigned long long PositiveInteger; + typedef long long NegativeInteger; + + // Boolean. + // + typedef bool Boolean; + + // Floating-point types. + // + typedef float Float; + typedef double Double; + typedef double Decimal; + + // String types. + // + typedef ::xsd::cxx::tree::string< char, SimpleType > String; + typedef ::xsd::cxx::tree::normalized_string< char, String > NormalizedString; + typedef ::xsd::cxx::tree::token< char, NormalizedString > Token; + typedef ::xsd::cxx::tree::name< char, Token > Name; + typedef ::xsd::cxx::tree::nmtoken< char, Token > Nmtoken; + typedef ::xsd::cxx::tree::nmtokens< char, SimpleType, Nmtoken > Nmtokens; + typedef ::xsd::cxx::tree::ncname< char, Name > Ncname; + typedef ::xsd::cxx::tree::language< char, Token > Language; + + // ID/IDREF. + // + typedef ::xsd::cxx::tree::id< char, Ncname > Id; + typedef ::xsd::cxx::tree::idref< char, Ncname, Type > Idref; + typedef ::xsd::cxx::tree::idrefs< char, SimpleType, Idref > Idrefs; + + // URI. + // + typedef ::xsd::cxx::tree::uri< char, SimpleType > Uri; + + // Qualified name. + // + typedef ::xsd::cxx::tree::qname< char, SimpleType, Uri, Ncname > Qname; + + // Binary. + // + typedef ::xsd::cxx::tree::buffer< char > Buffer; + typedef ::xsd::cxx::tree::base64_binary< char, SimpleType > Base64Binary; + typedef ::xsd::cxx::tree::hex_binary< char, SimpleType > HexBinary; + + // Date/time. + // + typedef ::xsd::cxx::tree::time_zone TimeZone; + typedef ::xsd::cxx::tree::date< char, SimpleType > Date; + typedef ::xsd::cxx::tree::date_time< char, SimpleType > DateTime; + typedef ::xsd::cxx::tree::duration< char, SimpleType > Duration; + typedef ::xsd::cxx::tree::gday< char, SimpleType > Gday; + typedef ::xsd::cxx::tree::gmonth< char, SimpleType > Gmonth; + typedef ::xsd::cxx::tree::gmonth_day< char, SimpleType > GmonthDay; + typedef ::xsd::cxx::tree::gyear< char, SimpleType > Gyear; + typedef ::xsd::cxx::tree::gyear_month< char, SimpleType > GyearMonth; + typedef ::xsd::cxx::tree::time< char, SimpleType > Time; + + // Entity. + // + typedef ::xsd::cxx::tree::entity< char, Ncname > Entity; + typedef ::xsd::cxx::tree::entities< char, SimpleType, Entity > Entities; + + typedef ::xsd::cxx::tree::content_order ContentOrder; + // Namespace information and list stream. Used in + // serialization functions. + // + typedef ::xsd::cxx::xml::dom::namespace_info< char > NamespaceInfo; + typedef ::xsd::cxx::xml::dom::namespace_infomap< char > NamespaceInfomap; + typedef ::xsd::cxx::tree::list_stream< char > ListStream; + typedef ::xsd::cxx::tree::as_double< Double > AsDouble; + typedef ::xsd::cxx::tree::as_decimal< Decimal > AsDecimal; + typedef ::xsd::cxx::tree::facet Facet; + + // Flags and properties. + // + typedef ::xsd::cxx::tree::flags Flags; + typedef ::xsd::cxx::tree::properties< char > Properties; + + // Parsing/serialization diagnostics. + // + typedef ::xsd::cxx::tree::severity Severity; + typedef ::xsd::cxx::tree::error< char > Error; + typedef ::xsd::cxx::tree::diagnostics< char > Diagnostics; + + // Exceptions. + // + typedef ::xsd::cxx::tree::exception< char > Exception; + typedef ::xsd::cxx::tree::bounds< char > Bounds; + typedef ::xsd::cxx::tree::duplicate_id< char > DuplicateId; + typedef ::xsd::cxx::tree::parsing< char > Parsing; + typedef ::xsd::cxx::tree::expected_element< char > ExpectedElement; + typedef ::xsd::cxx::tree::unexpected_element< char > UnexpectedElement; + typedef ::xsd::cxx::tree::expected_attribute< char > ExpectedAttribute; + typedef ::xsd::cxx::tree::unexpected_enumerator< char > UnexpectedEnumerator; + typedef ::xsd::cxx::tree::expected_text_content< char > ExpectedTextContent; + typedef ::xsd::cxx::tree::no_prefix_mapping< char > NoPrefixMapping; + typedef ::xsd::cxx::tree::serialization< char > Serialization; + + // Error handler callback interface. + // + typedef ::xsd::cxx::xml::error_handler< char > ErrorHandler; + + // DOM interaction. + // + namespace dom + { + // Automatic pointer for DOMDocument. + // + using ::xsd::cxx::xml::dom::unique_ptr; + +#ifndef XSD_CXX_TREE_TREE_NODE_KEY__XML_SCHEMA +#define XSD_CXX_TREE_TREE_NODE_KEY__XML_SCHEMA + // DOM user data key for back pointers to tree nodes. + // + const XMLCh* const treeNodeKey = ::xsd::cxx::tree::user_data_keys::node; +#endif + } +} + +// Forward declarations. +// +namespace namespace_ +{ + class Lang; + class Space; + class Lang_member; +} + + +#include // ::std::unique_ptr +#include // std::numeric_limits +#include // std::binary_search +#include // std::move + +#include + +#include +#include +#include +#include + +#include + +#include + +namespace namespace_ +{ + class Lang: public ::xml_schema::String + { + public: + + Lang (const char* v); + + Lang (const ::std::string& v); + + Lang (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Lang (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Lang (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Lang (const Lang& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Lang* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + }; + + class Space: public ::xml_schema::Ncname + { + public: + enum Value + { + default_, + preserve + }; + + Space (Value v); + + Space (const char* v); + + Space (const ::std::string& v); + + Space (const ::xml_schema::Ncname& v); + + Space (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Space (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Space (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Space (const Space& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Space* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Space& + operator= (Value v); + + virtual + operator Value () const + { + return _xsd_Space_convert (); + } + + protected: + Value + _xsd_Space_convert () const; + + public: + static const char* const _xsd_Space_literals_[2]; + static const Value _xsd_Space_indexes_[2]; + }; + + class Lang_member: public ::xml_schema::String + { + public: + enum Value + { + empty + }; + + Lang_member (Value v); + + Lang_member (const char* v); + + Lang_member (const ::std::string& v); + + Lang_member (const ::xml_schema::String& v); + + Lang_member (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Lang_member (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Lang_member (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Lang_member (const Lang_member& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Lang_member* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Lang_member& + operator= (Value v); + + virtual + operator Value () const + { + return _xsd_Lang_member_convert (); + } + + protected: + Value + _xsd_Lang_member_convert () const; + + public: + static const char* const _xsd_Lang_member_literals_[1]; + static const Value _xsd_Lang_member_indexes_[1]; + }; +} + +#include + +namespace namespace_ +{ + ::std::ostream& + operator<< (::std::ostream&, const Lang&); + + ::std::ostream& + operator<< (::std::ostream&, Space::Value); + + ::std::ostream& + operator<< (::std::ostream&, const Space&); + + ::std::ostream& + operator<< (::std::ostream&, Lang_member::Value); + + ::std::ostream& + operator<< (::std::ostream&, const Lang_member&); +} + +#include + +#include +#include +#include + +namespace namespace_ +{ +} + +#include + +#include +#include +#include + +#include + +namespace namespace_ +{ + void + operator<< (::xercesc::DOMElement&, const Lang&); + + void + operator<< (::xercesc::DOMAttr&, const Lang&); + + void + operator<< (::xml_schema::ListStream&, + const Lang&); + + void + operator<< (::xercesc::DOMElement&, const Space&); + + void + operator<< (::xercesc::DOMAttr&, const Space&); + + void + operator<< (::xml_schema::ListStream&, + const Space&); + + void + operator<< (::xercesc::DOMElement&, const Lang_member&); + + void + operator<< (::xercesc::DOMAttr&, const Lang_member&); + + void + operator<< (::xml_schema::ListStream&, + const Lang_member&); +} + +#include + +// Begin epilogue. +// +// +// End epilogue. + +#endif // CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_FLEXISIP_PRIVATE_SRC_XML_XML_HXX diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index 45e83bb6c..7ef874e88 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -192,6 +192,10 @@ set(SOURCE_FILES_C video_tester.c ) +set(SOURCE_FILES_CXX + confeventpackage_tester.cpp +) + set(SOURCE_FILES_OBJC ) if(APPLE) if (IOS) @@ -200,6 +204,7 @@ if(APPLE) endif() bc_apply_compile_flags(SOURCE_FILES_C STRICT_OPTIONS_CPP STRICT_OPTIONS_C) +bc_apply_compile_flags(SOURCE_FILES_C_CXX STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX) bc_apply_compile_flags(SOURCE_FILES_OBJC STRICT_OPTIONS_CPP STRICT_OPTIONS_OBJC) if(MSVC) @@ -222,7 +227,7 @@ endif() # on mobile platforms, we compile the tester as a library so that we can link with it directly from native applications if(ANDROID OR IOS) - add_library(linphonetester SHARED ${SOURCE_FILES_C}) + add_library(linphonetester SHARED ${SOURCE_FILES_C} ${SOURCE_FILES_CXX}) target_include_directories(linphonetester PUBLIC ${BCTOOLBOX_TESTER_INCLUDE_DIRS}) target_link_libraries(linphonetester ${LINPHONE_LIBS_FOR_TOOLS} ${OTHER_LIBS_FOR_TESTER}) if(IOS) @@ -243,7 +248,7 @@ if(ANDROID OR IOS) PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ ) elseif(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") - add_library(linphone_tester_static STATIC ${SOURCE_FILES_C}) + add_library(linphone_tester_static STATIC ${SOURCE_FILES_C} ${SOURCE_FILES_CXX}) target_include_directories(linphone_tester_static PUBLIC ${BCTOOLBOX_TESTER_INCLUDE_DIRS}) target_link_libraries(linphone_tester_static ${LINPHONE_LIBS_FOR_TOOLS} ${OTHER_LIBS_FOR_TESTER}) @@ -277,9 +282,9 @@ endif() if (NOT ANDROID AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") if(IOS) set_source_files_properties(${IOS_RESOURCES_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) - add_executable(liblinphone_tester MACOSX_BUNDLE ${IOS_RESOURCES_FILES} ${SOURCE_FILES_C} ${SOURCE_FILES_OBJC}) + add_executable(liblinphone_tester MACOSX_BUNDLE ${IOS_RESOURCES_FILES} ${SOURCE_FILES_C} ${SOURCE_FILES_CXX} ${SOURCE_FILES_OBJC}) else() - add_executable(liblinphone_tester ${SOURCE_FILES_C} ${SOURCE_FILES_OBJC}) + add_executable(liblinphone_tester ${SOURCE_FILES_C} ${SOURCE_FILES_CXX} ${SOURCE_FILES_OBJC}) endif() set_target_properties(liblinphone_tester PROPERTIES LINK_FLAGS "${LINPHONE_LDFLAGS}") set_target_properties(liblinphone_tester PROPERTIES LINKER_LANGUAGE CXX) @@ -312,4 +317,4 @@ if (NOT ANDROID AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") install(FILES ${IMAGE_FILES} DESTINATION "${CMAKE_INSTALL_DATADIR}/liblinphone_tester/images") install(FILES ${VCARD_FILES} DESTINATION "${CMAKE_INSTALL_DATADIR}/liblinphone_tester/vcards") endif() -endif() +endif() \ No newline at end of file diff --git a/tester/confeventpackage_tester.cpp b/tester/confeventpackage_tester.cpp new file mode 100644 index 000000000..e66bbb602 --- /dev/null +++ b/tester/confeventpackage_tester.cpp @@ -0,0 +1,717 @@ +/* + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 Belledonne Communications SARL + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include +#include + +#include "linphone/core.h" +#include "private.h" +#include "liblinphone_tester.h" +#include "conference/conference-listener.h" +#include "conference/conference-event-package.h" + +using namespace LinphonePrivate; +using namespace std; + +static const char *first_notify = \ +" "\ +" "\ +" "\ +" "\ +" Agenda: This month's goals"\ +" "\ +" "\ +" http://sharepoint/salesgroup/"\ +" web-page"\ +" "\ +" "\ +" "\ +" "\ +" "\ +" 33"\ +" "\ +" "\ +" "\ +" "\ +" Bob Hoskins"\ +" "\ +" "\ +" Bob's Laptop"\ +" disconnected"\ +" departed"\ +" "\ +" 2005-03-04T20:00:00Z"\ +" bad voice quality"\ +" sip:mike@example.com"\ +" "\ +" "\ +" "\ +" main audio"\ +" audio"\ +" "\ +" 432424"\ +" sendrecv"\ +" "\ +" "\ +" "\ +" "\ +" "\ +" Alice"\ +" "\ +" admin"\ +" participant"\ +" "\ +" "\ +" "\ +" connected"\ +" dialed-out"\ +" "\ +" 2005-03-04T20:00:00Z"\ +" sip:mike@example.com"\ +" "\ +" "\ +" "\ +" main audio"\ +" audio"\ +" "\ +" 534232"\ +" sendrecv"\ +" "\ +" "\ +" "\ +" "\ +" "; + +static const char *participant_added_notify = \ +" "\ +" "\ +" "\ +" "\ +" Agenda: This month's goals"\ +" "\ +" "\ +" http://sharepoint/salesgroup/"\ +" web-page"\ +" "\ +" "\ +" "\ +" "\ +" "\ +" 33"\ +" "\ +" "\ +" "\ +" "\ +" Bob Hoskins"\ +" "\ +" "\ +" Frank's Laptop"\ +" disconnected"\ +" departed"\ +" "\ +" 2005-03-04T20:00:00Z"\ +" bad voice quality"\ +" sip:mike@example.com"\ +" "\ +" "\ +" "\ +" main audio"\ +" audio"\ +" "\ +" 432424"\ +" sendrecv"\ +" "\ +" "\ +" "\ +" "\ +" "; + +static const char *participant_not_added_notify = \ +" "\ +" "\ +" "\ +" "\ +" Agenda: This month's goals"\ +" "\ +" "\ +" http://sharepoint/salesgroup/"\ +" web-page"\ +" "\ +" "\ +" "\ +" "\ +" "\ +" 33"\ +" "\ +" "\ +" "\ +" "\ +" Bob Hoskins"\ +" "\ +" "\ +" Frank's Laptop"\ +" disconnected"\ +" departed"\ +" "\ +" 2005-03-04T20:00:00Z"\ +" bad voice quality"\ +" sip:mike@example.com"\ +" "\ +" "\ +" "\ +" main audio"\ +" audio"\ +" "\ +" 432424"\ +" sendrecv"\ +" "\ +" "\ +" "\ +" "\ +" "; + +static const char *participant_deleted_notify = \ +" "\ +" "\ +" "\ +" "\ +" Agenda: This month's goals"\ +" "\ +" "\ +" http://sharepoint/salesgroup/"\ +" web-page"\ +" "\ +" "\ +" "\ +" "\ +" "\ +" 33"\ +" "\ +" "\ +" "\ +" "\ +" Bob Hoskins"\ +" "\ +" "\ +" Bob's Laptop"\ +" disconnected"\ +" departed"\ +" "\ +" 2005-03-04T20:00:00Z"\ +" bad voice quality"\ +" sip:mike@example.com"\ +" "\ +" "\ +" "\ +" main audio"\ +" audio"\ +" "\ +" 432424"\ +" sendrecv"\ +" "\ +" "\ +" "\ +" "\ +" "; + +static const char *participant_admined_notify = \ +" "\ +" "\ +" "\ +" "\ +" Agenda: This month's goals"\ +" "\ +" "\ +" http://sharepoint/salesgroup/"\ +" web-page"\ +" "\ +" "\ +" "\ +" "\ +" "\ +" 33"\ +" "\ +" "\ +" "\ +" "\ +" Bob Hoskins"\ +" "\ +" participant"\ +" admin"\ +" "\ +" "\ +" "\ +" Bob's Laptop"\ +" disconnected"\ +" departed"\ +" "\ +" 2005-03-04T20:00:00Z"\ +" bad voice quality"\ +" sip:mike@example.com"\ +" "\ +" "\ +" "\ +" main audio"\ +" audio"\ +" "\ +" 432424"\ +" sendrecv"\ +" "\ +" "\ +" "\ +" "\ +" "; + +static const char *participant_unadmined_notify = \ +" "\ +" "\ +" "\ +" "\ +" Agenda: This month's goals"\ +" "\ +" "\ +" http://sharepoint/salesgroup/"\ +" web-page"\ +" "\ +" "\ +" "\ +" "\ +" "\ +" 33"\ +" "\ +" "\ +" "\ +" "\ +" Alice Hoskins"\ +" "\ +" participant"\ +" "\ +" "\ +" "\ +" Alice's Laptop"\ +" disconnected"\ +" departed"\ +" "\ +" 2005-03-04T20:00:00Z"\ +" bad voice quality"\ +" sip:mike@example.com"\ +" "\ +" "\ +" "\ +" main audio"\ +" audio"\ +" "\ +" 432424"\ +" sendrecv"\ +" "\ +" "\ +" "\ +" "\ +" "; + + +static const char *bobUri = "sip:bob@example.com"; +static const char *aliceUri = "sip:alice@example.com"; +static const char *frankUri = "sip:frank@example.com"; +static const char *confUri = "sips:conf233@example.com"; + +void linphone_conf_event_notify(LinphoneEvent *lev) { + LinphoneContent* content = linphone_core_create_content(lev->lc); + const char* uri = linphone_address_as_string_uri_only((LinphoneAddress*)sal_op_get_to_address(lev->op)); + char notify[strlen(first_notify) + strlen(uri)]; + snprintf(notify, sizeof(notify), first_notify, uri); + linphone_content_set_buffer(content,notify,strlen(notify)); + linphone_event_notify(lev, content); + linphone_content_unref(content); +} + +class ConferenceEventTester : public Conference::ConferenceListener { +public: + Conference::ConferenceEventPackage *cep; + map *participants; + + ConferenceEventTester(LinphoneCore *lc, LinphoneAddress *confAddr); + ~ConferenceEventTester(); + void conferenceCreated(LinphoneAddress *confAddress); + void conferenceTerminated(LinphoneAddress *confAddress); + void participantAdded(LinphoneAddress *addr); + void participantRemoved(LinphoneAddress *addr); + void participantSetAdmin(LinphoneAddress *addr, bool isAdmin); +}; +ConferenceEventTester::~ConferenceEventTester() { + this->cep->~ConferenceEventPackage(); +} +ConferenceEventTester::ConferenceEventTester(LinphoneCore *lc, LinphoneAddress *confAddr) { + this->cep = new Conference::ConferenceEventPackage(lc, this, confAddr); + this->participants = new map; +} +void ConferenceEventTester::conferenceCreated(LinphoneAddress *confAddress) {} +void ConferenceEventTester::conferenceTerminated(LinphoneAddress *confAddress){} +void ConferenceEventTester::participantAdded(LinphoneAddress *addr) { + this->participants->insert(pair(linphone_address_as_string(addr),0)); +} +void ConferenceEventTester::participantRemoved(LinphoneAddress *addr){ + this->participants->erase(linphone_address_as_string(addr)); +} +void ConferenceEventTester::participantSetAdmin(LinphoneAddress *addr, bool isAdmin){ +const char *addrAsString = linphone_address_as_string(addr); + if(this->participants->find(addrAsString) != this->participants->end()) { + this->participants->erase(addrAsString); + this->participants->insert(pair(addrAsString, isAdmin ? 1 : 0)); + } +} + +void first_notify_parsing(void){ + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri); + ConferenceEventTester *tester = new ConferenceEventTester(marie->lc, confAddress); + LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); + LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); + char notify[strlen(first_notify) + strlen(confUri)]; + + snprintf(notify, sizeof(notify), first_notify, confUri); + tester->cep->notifyReceived(notify); + + BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr)) != tester->participants->end()); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr))->second == 1); + + linphone_address_unref(bobAddr); + linphone_address_unref(aliceAddr); + linphone_address_unref(confAddress); + tester->ConferenceEventTester::~ConferenceEventTester(); + linphone_core_manager_destroy(marie); +} + +void first_notify_parsing_wrong_conf(void){ + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, "sips:conf322@example.com"); + ConferenceEventTester *tester = new ConferenceEventTester(marie->lc, confAddress); + LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); + LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); + char notify[strlen(first_notify) + strlen(confUri)]; + + snprintf(notify, sizeof(notify), first_notify, confUri); + tester->cep->notifyReceived(notify); + + BC_ASSERT_EQUAL(tester->participants->size(), 0, int, "%d"); + BC_ASSERT_FALSE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); + BC_ASSERT_FALSE(tester->participants->find(linphone_address_as_string(aliceAddr)) != tester->participants->end()); + + linphone_address_unref(bobAddr); + linphone_address_unref(aliceAddr); + linphone_address_unref(confAddress); + tester->ConferenceEventTester::~ConferenceEventTester(); + linphone_core_manager_destroy(marie); +} + +void participant_added_parsing(void){ + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri); + ConferenceEventTester *tester = new ConferenceEventTester(marie->lc, confAddress); + LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); + LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); + LinphoneAddress *frankAddr = linphone_core_interpret_url(marie->lc, frankUri); + char notify[strlen(first_notify) + strlen(confUri)]; + char notify_added[strlen(participant_added_notify) + strlen(confUri)]; + + snprintf(notify, sizeof(notify), first_notify, confUri); + tester->cep->notifyReceived(notify); + + BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr)) != tester->participants->end()); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr))->second == 1); + + snprintf(notify_added, sizeof(notify_added), participant_added_notify, confUri); + tester->cep->notifyReceived(notify_added); + + BC_ASSERT_EQUAL(tester->participants->size(), 3, int, "%d"); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(frankAddr)) != tester->participants->end()); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(frankAddr))->second == 0); + + linphone_address_unref(bobAddr); + linphone_address_unref(aliceAddr); + linphone_address_unref(frankAddr); + linphone_address_unref(confAddress); + tester->ConferenceEventTester::~ConferenceEventTester(); + linphone_core_manager_destroy(marie); +} + +void participant_not_added_parsing(void){ + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri); + ConferenceEventTester *tester = new ConferenceEventTester(marie->lc, confAddress); + LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); + LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); + LinphoneAddress *frankAddr = linphone_core_interpret_url(marie->lc, frankUri); + char notify[strlen(first_notify) + strlen(confUri)]; + char notify_not_added[strlen(participant_not_added_notify) + strlen(confUri)]; + + snprintf(notify, sizeof(notify), first_notify, confUri); + tester->cep->notifyReceived(notify); + + BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr)) != tester->participants->end()); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr))->second == 1); + + snprintf(notify_not_added, sizeof(notify_not_added), participant_not_added_notify, confUri); + tester->cep->notifyReceived(notify_not_added); + + BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); + BC_ASSERT_FALSE(tester->participants->find(linphone_address_as_string(frankAddr)) != tester->participants->end()); + + linphone_address_unref(bobAddr); + linphone_address_unref(aliceAddr); + linphone_address_unref(frankAddr); + linphone_address_unref(confAddress); + tester->ConferenceEventTester::~ConferenceEventTester(); + linphone_core_manager_destroy(marie); +} + +void participant_deleted_parsing(void){ + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri); + ConferenceEventTester *tester = new ConferenceEventTester(marie->lc, confAddress); + LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); + LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); + char notify[strlen(first_notify) + strlen(confUri)]; + char notify_deleted[strlen(participant_deleted_notify) + strlen(confUri)]; + + snprintf(notify, sizeof(notify), first_notify, confUri); + tester->cep->notifyReceived(notify); + + BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr)) != tester->participants->end()); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr))->second == 1); + + snprintf(notify_deleted, sizeof(notify_deleted), participant_deleted_notify, confUri); + tester->cep->notifyReceived(notify_deleted); + + BC_ASSERT_EQUAL(tester->participants->size(), 1, int, "%d"); + BC_ASSERT_FALSE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); + + linphone_address_unref(bobAddr); + linphone_address_unref(aliceAddr); + linphone_address_unref(confAddress); + tester->ConferenceEventTester::~ConferenceEventTester(); + linphone_core_manager_destroy(marie); +} + +void participant_admined_parsing(void){ + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri); + ConferenceEventTester *tester = new ConferenceEventTester(marie->lc, confAddress); + LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); + LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); + char notify[strlen(first_notify) + strlen(confUri)]; + char notify_admined[strlen(participant_admined_notify) + strlen(confUri)]; + + snprintf(notify, sizeof(notify), first_notify, confUri); + tester->cep->notifyReceived(notify); + + BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr)) != tester->participants->end()); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr))->second == 1); + + snprintf(notify_admined, sizeof(notify_admined), participant_admined_notify, confUri); + tester->cep->notifyReceived(notify_admined); + + BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr))->second == 1); + + linphone_address_unref(bobAddr); + linphone_address_unref(aliceAddr); + linphone_address_unref(confAddress); + tester->ConferenceEventTester::~ConferenceEventTester(); + linphone_core_manager_destroy(marie); +} + +void participant_unadmined_parsing(void){ + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri); + ConferenceEventTester *tester = new ConferenceEventTester(marie->lc, confAddress); + LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); + LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); + char notify[strlen(first_notify) + strlen(confUri)]; + char notify_unadmined[strlen(participant_unadmined_notify) + strlen(confUri)]; + + snprintf(notify, sizeof(notify), first_notify, confUri); + tester->cep->notifyReceived(notify); + + BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr)) != tester->participants->end()); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr))->second == 1); + + snprintf(notify_unadmined, sizeof(notify_unadmined), participant_unadmined_notify, confUri); + tester->cep->notifyReceived(notify_unadmined); + + BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr)) != tester->participants->end()); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr))->second == 0); + + linphone_address_unref(bobAddr); + linphone_address_unref(aliceAddr); + linphone_address_unref(confAddress); + tester->ConferenceEventTester::~ConferenceEventTester(); + linphone_core_manager_destroy(marie); +} + +void send_subscribe_receive_first_notify(void){ + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + ConferenceEventTester *tester = new ConferenceEventTester(marie->lc, pauline->identity); + LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); + LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); + string confId("conf233"); + + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneRegistrationOk,1,1000)); + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneRegistrationOk,1,1000)); + + tester->cep->subscribe(confId); + + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000)); + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneSubscriptionActive,1,3000)); + wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_NotifyReceived,1,3000); + + BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr)) != tester->participants->end()); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr))->second == 1); + + tester->cep->unsubscribe(); + + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); + + linphone_address_unref(bobAddr); + linphone_address_unref(aliceAddr); + tester->ConferenceEventTester::~ConferenceEventTester(); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +test_t conf_event_tests[] = { + TEST_NO_TAG("First notify parsing", first_notify_parsing), + TEST_NO_TAG("First notify parsing wrong conf", first_notify_parsing_wrong_conf), + TEST_NO_TAG("Participant added", participant_added_parsing), + TEST_NO_TAG("Participant not added", participant_not_added_parsing), + TEST_NO_TAG("Participant deleted", participant_deleted_parsing), + TEST_NO_TAG("Participant admined", participant_admined_parsing), + TEST_NO_TAG("Participant unadmined", participant_unadmined_parsing), + TEST_NO_TAG("Send subscribe receive first notify", send_subscribe_receive_first_notify) +}; + +test_suite_t conf_event_test_suite = {"Conf event package", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each, + sizeof(conf_event_tests) / sizeof(conf_event_tests[0]), conf_event_tests}; diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index 7bc39eba8..7369095b5 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -82,7 +82,11 @@ void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, Li counters->number_of_LinphoneSubscriptionActive++; if (linphone_event_get_subscription_dir(lev)==LinphoneSubscriptionIncoming){ mgr->lev=lev; - linphone_event_notify(lev,content); + if(strcmp(linphone_event_get_name(lev), "Conference") == 0) { + linphone_conf_event_notify(lev); + } else { + linphone_event_notify(lev,content); + } } break; case LinphoneSubscriptionTerminated: diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 15f55b0d6..77aa54e37 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -48,6 +48,7 @@ extern test_suite_t presence_test_suite; extern test_suite_t presence_server_test_suite; extern test_suite_t upnp_test_suite; extern test_suite_t event_test_suite; +extern test_suite_t conf_event_test_suite; extern test_suite_t flexisip_test_suite; extern test_suite_t stun_test_suite; extern test_suite_t remote_provisioning_test_suite; @@ -401,7 +402,7 @@ LinphoneAddress * linphone_core_manager_resolve(LinphoneCoreManager *mgr, const FILE *sip_start(const char *senario, const char* dest_username, const char *passwd, LinphoneAddress* dest_addres); void early_media_without_sdp_in_200_base( bool_t use_video, bool_t use_ice ); - +void linphone_conf_event_notify(LinphoneEvent *lev); #ifdef __cplusplus }; diff --git a/tester/tester.c b/tester/tester.c index 40f8b43b9..a211e1dcf 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -566,7 +566,7 @@ void liblinphone_tester_add_suites() { #endif bc_tester_add_suite(&stun_test_suite); bc_tester_add_suite(&event_test_suite); - bc_tester_add_suite(&flexisip_test_suite); + bc_tester_add_suite(&conf_event_test_suite); bc_tester_add_suite(&remote_provisioning_test_suite); bc_tester_add_suite(&quality_reporting_test_suite); bc_tester_add_suite(&log_collection_test_suite); From e62fe07eca64a96ac45d336b7ee3e37d91de025a Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 1 Aug 2017 13:30:45 +0200 Subject: [PATCH 0002/2215] put back flexisip test suite --- tester/tester.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tester/tester.c b/tester/tester.c index a211e1dcf..6c5454960 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -550,11 +550,9 @@ void liblinphone_tester_clear_accounts(void){ void liblinphone_tester_add_suites() { bc_tester_add_suite(&setup_test_suite); - bc_tester_add_suite(®ister_test_suite); bc_tester_add_suite(&tunnel_test_suite); bc_tester_add_suite(&offeranswer_test_suite); bc_tester_add_suite(&call_test_suite); - bc_tester_add_suite(&call_video_test_suite); bc_tester_add_suite(&audio_bypass_suite); bc_tester_add_suite(&multi_call_test_suite); bc_tester_add_suite(&message_test_suite); @@ -567,6 +565,7 @@ void liblinphone_tester_add_suites() { bc_tester_add_suite(&stun_test_suite); bc_tester_add_suite(&event_test_suite); bc_tester_add_suite(&conf_event_test_suite); + bc_tester_add_suite(&flexisip_test_suite); bc_tester_add_suite(&remote_provisioning_test_suite); bc_tester_add_suite(&quality_reporting_test_suite); bc_tester_add_suite(&log_collection_test_suite); From d93ccca824341ee1f192a9259eef703f871af5d7 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 1 Aug 2017 15:39:00 +0200 Subject: [PATCH 0003/2215] put bak tests suites --- tester/confeventpackage_tester.cpp | 15 +++++++-------- tester/tester.c | 2 ++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/tester/confeventpackage_tester.cpp b/tester/confeventpackage_tester.cpp index e66bbb602..14199f963 100644 --- a/tester/confeventpackage_tester.cpp +++ b/tester/confeventpackage_tester.cpp @@ -413,7 +413,7 @@ static const char *aliceUri = "sip:alice@example.com"; static const char *frankUri = "sip:frank@example.com"; static const char *confUri = "sips:conf233@example.com"; -void linphone_conf_event_notify(LinphoneEvent *lev) { +void linphone_conf_event_notify(LinphoneEvent *lev){ LinphoneContent* content = linphone_core_create_content(lev->lc); const char* uri = linphone_address_as_string_uri_only((LinphoneAddress*)sal_op_get_to_address(lev->op)); char notify[strlen(first_notify) + strlen(uri)]; @@ -423,7 +423,7 @@ void linphone_conf_event_notify(LinphoneEvent *lev) { linphone_content_unref(content); } -class ConferenceEventTester : public Conference::ConferenceListener { +class ConferenceEventTester : public Conference::ConferenceListener{ public: Conference::ConferenceEventPackage *cep; map *participants; @@ -436,16 +436,16 @@ public: void participantRemoved(LinphoneAddress *addr); void participantSetAdmin(LinphoneAddress *addr, bool isAdmin); }; -ConferenceEventTester::~ConferenceEventTester() { +ConferenceEventTester::~ConferenceEventTester(){ this->cep->~ConferenceEventPackage(); } -ConferenceEventTester::ConferenceEventTester(LinphoneCore *lc, LinphoneAddress *confAddr) { +ConferenceEventTester::ConferenceEventTester(LinphoneCore *lc, LinphoneAddress *confAddr){ this->cep = new Conference::ConferenceEventPackage(lc, this, confAddr); this->participants = new map; } -void ConferenceEventTester::conferenceCreated(LinphoneAddress *confAddress) {} +void ConferenceEventTester::conferenceCreated(LinphoneAddress *confAddress){} void ConferenceEventTester::conferenceTerminated(LinphoneAddress *confAddress){} -void ConferenceEventTester::participantAdded(LinphoneAddress *addr) { +void ConferenceEventTester::participantAdded(LinphoneAddress *addr){ this->participants->insert(pair(linphone_address_as_string(addr),0)); } void ConferenceEventTester::participantRemoved(LinphoneAddress *addr){ @@ -453,7 +453,7 @@ void ConferenceEventTester::participantRemoved(LinphoneAddress *addr){ } void ConferenceEventTester::participantSetAdmin(LinphoneAddress *addr, bool isAdmin){ const char *addrAsString = linphone_address_as_string(addr); - if(this->participants->find(addrAsString) != this->participants->end()) { + if(this->participants->find(addrAsString) != this->participants->end()){ this->participants->erase(addrAsString); this->participants->insert(pair(addrAsString, isAdmin ? 1 : 0)); } @@ -697,7 +697,6 @@ void send_subscribe_receive_first_notify(void){ linphone_address_unref(bobAddr); linphone_address_unref(aliceAddr); tester->ConferenceEventTester::~ConferenceEventTester(); - linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } diff --git a/tester/tester.c b/tester/tester.c index 6c5454960..2ddbc6e83 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -550,9 +550,11 @@ void liblinphone_tester_clear_accounts(void){ void liblinphone_tester_add_suites() { bc_tester_add_suite(&setup_test_suite); + bc_tester_add_suite(®ister_test_suite); bc_tester_add_suite(&tunnel_test_suite); bc_tester_add_suite(&offeranswer_test_suite); bc_tester_add_suite(&call_test_suite); + bc_tester_add_suite(&call_video_test_suite); bc_tester_add_suite(&audio_bypass_suite); bc_tester_add_suite(&multi_call_test_suite); bc_tester_add_suite(&message_test_suite); From d77af8855828343db8f177523c6b06a0794ac088 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 2 Aug 2017 15:06:00 +0200 Subject: [PATCH 0004/2215] use shared_ptr --- src/conference/conference-listener.h | 2 +- tester/confeventpackage_tester.cpp | 178 +++++++++++++-------------- 2 files changed, 85 insertions(+), 95 deletions(-) diff --git a/src/conference/conference-listener.h b/src/conference/conference-listener.h index e5c596fd3..9ed9fa7f9 100644 --- a/src/conference/conference-listener.h +++ b/src/conference/conference-listener.h @@ -28,7 +28,7 @@ namespace LinphonePrivate { // ------------------------------------------------------------------------- class ConferenceListener { public: - //virtual ~ConferenceListener() = 0; + virtual ~ConferenceListener() = default; virtual void conferenceCreated(LinphoneAddress *confAddress) = 0; virtual void conferenceTerminated(LinphoneAddress *confAddress) = 0; virtual void participantAdded(LinphoneAddress *addr) = 0; diff --git a/tester/confeventpackage_tester.cpp b/tester/confeventpackage_tester.cpp index 14199f963..b909bf122 100644 --- a/tester/confeventpackage_tester.cpp +++ b/tester/confeventpackage_tester.cpp @@ -425,90 +425,86 @@ void linphone_conf_event_notify(LinphoneEvent *lev){ class ConferenceEventTester : public Conference::ConferenceListener{ public: - Conference::ConferenceEventPackage *cep; - map *participants; + shared_ptr cep; + map participants; ConferenceEventTester(LinphoneCore *lc, LinphoneAddress *confAddr); - ~ConferenceEventTester(); + void conferenceCreated(LinphoneAddress *confAddress); void conferenceTerminated(LinphoneAddress *confAddress); void participantAdded(LinphoneAddress *addr); void participantRemoved(LinphoneAddress *addr); void participantSetAdmin(LinphoneAddress *addr, bool isAdmin); }; -ConferenceEventTester::~ConferenceEventTester(){ - this->cep->~ConferenceEventPackage(); -} + ConferenceEventTester::ConferenceEventTester(LinphoneCore *lc, LinphoneAddress *confAddr){ - this->cep = new Conference::ConferenceEventPackage(lc, this, confAddr); - this->participants = new map; + this->cep = make_shared(lc, this, confAddr); } + void ConferenceEventTester::conferenceCreated(LinphoneAddress *confAddress){} void ConferenceEventTester::conferenceTerminated(LinphoneAddress *confAddress){} void ConferenceEventTester::participantAdded(LinphoneAddress *addr){ - this->participants->insert(pair(linphone_address_as_string(addr),0)); + this->participants.insert(pair(linphone_address_as_string(addr),0)); } void ConferenceEventTester::participantRemoved(LinphoneAddress *addr){ - this->participants->erase(linphone_address_as_string(addr)); + this->participants.erase(linphone_address_as_string(addr)); } void ConferenceEventTester::participantSetAdmin(LinphoneAddress *addr, bool isAdmin){ const char *addrAsString = linphone_address_as_string(addr); - if(this->participants->find(addrAsString) != this->participants->end()){ - this->participants->erase(addrAsString); - this->participants->insert(pair(addrAsString, isAdmin ? 1 : 0)); + if(this->participants.find(addrAsString) != this->participants.end()){ + this->participants.erase(addrAsString); + this->participants.insert(pair(addrAsString, isAdmin ? 1 : 0)); } } void first_notify_parsing(void){ LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri); - ConferenceEventTester *tester = new ConferenceEventTester(marie->lc, confAddress); + ConferenceEventTester tester(marie->lc, confAddress); LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); char notify[strlen(first_notify) + strlen(confUri)]; snprintf(notify, sizeof(notify), first_notify, confUri); - tester->cep->notifyReceived(notify); + tester.cep->notifyReceived(notify); - BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr)) != tester->participants->end()); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr))->second == 0); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr))->second == 1); + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second == 1); linphone_address_unref(bobAddr); linphone_address_unref(aliceAddr); linphone_address_unref(confAddress); - tester->ConferenceEventTester::~ConferenceEventTester(); linphone_core_manager_destroy(marie); } void first_notify_parsing_wrong_conf(void){ LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, "sips:conf322@example.com"); - ConferenceEventTester *tester = new ConferenceEventTester(marie->lc, confAddress); + ConferenceEventTester tester(marie->lc, confAddress); LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); char notify[strlen(first_notify) + strlen(confUri)]; snprintf(notify, sizeof(notify), first_notify, confUri); - tester->cep->notifyReceived(notify); + tester.cep->notifyReceived(notify); - BC_ASSERT_EQUAL(tester->participants->size(), 0, int, "%d"); - BC_ASSERT_FALSE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); - BC_ASSERT_FALSE(tester->participants->find(linphone_address_as_string(aliceAddr)) != tester->participants->end()); + BC_ASSERT_EQUAL(tester.participants.size(), 0, int, "%d"); + BC_ASSERT_FALSE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); + BC_ASSERT_FALSE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); linphone_address_unref(bobAddr); linphone_address_unref(aliceAddr); linphone_address_unref(confAddress); - tester->ConferenceEventTester::~ConferenceEventTester(); linphone_core_manager_destroy(marie); } void participant_added_parsing(void){ LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri); - ConferenceEventTester *tester = new ConferenceEventTester(marie->lc, confAddress); + ConferenceEventTester tester(marie->lc, confAddress); LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); LinphoneAddress *frankAddr = linphone_core_interpret_url(marie->lc, frankUri); @@ -516,33 +512,32 @@ void participant_added_parsing(void){ char notify_added[strlen(participant_added_notify) + strlen(confUri)]; snprintf(notify, sizeof(notify), first_notify, confUri); - tester->cep->notifyReceived(notify); + tester.cep->notifyReceived(notify); - BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr)) != tester->participants->end()); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr))->second == 0); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr))->second == 1); + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second == 1); snprintf(notify_added, sizeof(notify_added), participant_added_notify, confUri); - tester->cep->notifyReceived(notify_added); + tester.cep->notifyReceived(notify_added); - BC_ASSERT_EQUAL(tester->participants->size(), 3, int, "%d"); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(frankAddr)) != tester->participants->end()); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(frankAddr))->second == 0); + BC_ASSERT_EQUAL(tester.participants.size(), 3, int, "%d"); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(frankAddr)) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(frankAddr))->second == 0); linphone_address_unref(bobAddr); linphone_address_unref(aliceAddr); linphone_address_unref(frankAddr); linphone_address_unref(confAddress); - tester->ConferenceEventTester::~ConferenceEventTester(); linphone_core_manager_destroy(marie); } void participant_not_added_parsing(void){ LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri); - ConferenceEventTester *tester = new ConferenceEventTester(marie->lc, confAddress); + ConferenceEventTester tester(marie->lc, confAddress); LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); LinphoneAddress *frankAddr = linphone_core_interpret_url(marie->lc, frankUri); @@ -550,127 +545,123 @@ void participant_not_added_parsing(void){ char notify_not_added[strlen(participant_not_added_notify) + strlen(confUri)]; snprintf(notify, sizeof(notify), first_notify, confUri); - tester->cep->notifyReceived(notify); + tester.cep->notifyReceived(notify); - BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr)) != tester->participants->end()); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr))->second == 0); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr))->second == 1); + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second == 1); snprintf(notify_not_added, sizeof(notify_not_added), participant_not_added_notify, confUri); - tester->cep->notifyReceived(notify_not_added); + tester.cep->notifyReceived(notify_not_added); - BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); - BC_ASSERT_FALSE(tester->participants->find(linphone_address_as_string(frankAddr)) != tester->participants->end()); + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_FALSE(tester.participants.find(linphone_address_as_string(frankAddr)) != tester.participants.end()); linphone_address_unref(bobAddr); linphone_address_unref(aliceAddr); linphone_address_unref(frankAddr); linphone_address_unref(confAddress); - tester->ConferenceEventTester::~ConferenceEventTester(); linphone_core_manager_destroy(marie); } void participant_deleted_parsing(void){ LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri); - ConferenceEventTester *tester = new ConferenceEventTester(marie->lc, confAddress); + ConferenceEventTester tester(marie->lc, confAddress); LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); char notify[strlen(first_notify) + strlen(confUri)]; char notify_deleted[strlen(participant_deleted_notify) + strlen(confUri)]; snprintf(notify, sizeof(notify), first_notify, confUri); - tester->cep->notifyReceived(notify); + tester.cep->notifyReceived(notify); - BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr)) != tester->participants->end()); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr))->second == 0); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr))->second == 1); + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second == 1); snprintf(notify_deleted, sizeof(notify_deleted), participant_deleted_notify, confUri); - tester->cep->notifyReceived(notify_deleted); + tester.cep->notifyReceived(notify_deleted); - BC_ASSERT_EQUAL(tester->participants->size(), 1, int, "%d"); - BC_ASSERT_FALSE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); + BC_ASSERT_EQUAL(tester.participants.size(), 1, int, "%d"); + BC_ASSERT_FALSE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); linphone_address_unref(bobAddr); linphone_address_unref(aliceAddr); linphone_address_unref(confAddress); - tester->ConferenceEventTester::~ConferenceEventTester(); linphone_core_manager_destroy(marie); } void participant_admined_parsing(void){ LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri); - ConferenceEventTester *tester = new ConferenceEventTester(marie->lc, confAddress); + ConferenceEventTester tester(marie->lc, confAddress); LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); char notify[strlen(first_notify) + strlen(confUri)]; char notify_admined[strlen(participant_admined_notify) + strlen(confUri)]; snprintf(notify, sizeof(notify), first_notify, confUri); - tester->cep->notifyReceived(notify); + tester.cep->notifyReceived(notify); - BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr)) != tester->participants->end()); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr))->second == 0); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr))->second == 1); + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second == 1); snprintf(notify_admined, sizeof(notify_admined), participant_admined_notify, confUri); - tester->cep->notifyReceived(notify_admined); + tester.cep->notifyReceived(notify_admined); - BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr))->second == 1); + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr))->second == 1); linphone_address_unref(bobAddr); linphone_address_unref(aliceAddr); linphone_address_unref(confAddress); - tester->ConferenceEventTester::~ConferenceEventTester(); linphone_core_manager_destroy(marie); } void participant_unadmined_parsing(void){ LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri); - ConferenceEventTester *tester = new ConferenceEventTester(marie->lc, confAddress); + ConferenceEventTester tester(marie->lc, confAddress); LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); char notify[strlen(first_notify) + strlen(confUri)]; char notify_unadmined[strlen(participant_unadmined_notify) + strlen(confUri)]; snprintf(notify, sizeof(notify), first_notify, confUri); - tester->cep->notifyReceived(notify); + tester.cep->notifyReceived(notify); - BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr)) != tester->participants->end()); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr))->second == 0); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr))->second == 1); + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second == 1); snprintf(notify_unadmined, sizeof(notify_unadmined), participant_unadmined_notify, confUri); - tester->cep->notifyReceived(notify_unadmined); + tester.cep->notifyReceived(notify_unadmined); - BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr)) != tester->participants->end()); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr))->second == 0); + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second == 0); linphone_address_unref(bobAddr); linphone_address_unref(aliceAddr); linphone_address_unref(confAddress); - tester->ConferenceEventTester::~ConferenceEventTester(); linphone_core_manager_destroy(marie); } void send_subscribe_receive_first_notify(void){ LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); - ConferenceEventTester *tester = new ConferenceEventTester(marie->lc, pauline->identity); + ConferenceEventTester tester(marie->lc, pauline->identity); LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); string confId("conf233"); @@ -678,25 +669,24 @@ void send_subscribe_receive_first_notify(void){ BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneRegistrationOk,1,1000)); BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneRegistrationOk,1,1000)); - tester->cep->subscribe(confId); + tester.cep->subscribe(confId); BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000)); BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneSubscriptionActive,1,3000)); wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_NotifyReceived,1,3000); - BC_ASSERT_EQUAL(tester->participants->size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr)) != tester->participants->end()); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr)) != tester->participants->end()); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(bobAddr))->second == 0); - BC_ASSERT_TRUE(tester->participants->find(linphone_address_as_string(aliceAddr))->second == 1); + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second == 1); - tester->cep->unsubscribe(); + tester.cep->unsubscribe(); BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); linphone_address_unref(bobAddr); linphone_address_unref(aliceAddr); - tester->ConferenceEventTester::~ConferenceEventTester(); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } From fc029784356e7aeef46959c70a2219e70c7710b9 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 4 Aug 2017 14:24:08 +0200 Subject: [PATCH 0005/2215] create the conf event notify + tests --- coreapi/CMakeLists.txt | 6 +- coreapi/linphonecore.c | 15 +- .../local-conference-event-handler.cpp | 155 ++++++++ .../local-conference-event-handler.h | 112 ++++++ ...pp => remote-conference-event-handler.cpp} | 31 +- ...ge.h => remote-conference-event-handler.h} | 23 +- tester/confeventpackage_tester.cpp | 374 +++++++++++++----- tester/eventapi_tester.c | 2 +- 8 files changed, 587 insertions(+), 131 deletions(-) create mode 100644 src/conference/local-conference-event-handler.cpp create mode 100644 src/conference/local-conference-event-handler.h rename src/conference/{conference-event-package.cpp => remote-conference-event-handler.cpp} (71%) rename src/conference/{conference-event-package.h => remote-conference-event-handler.h} (67%) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index b0747a5fd..a2dec92ab 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -39,7 +39,8 @@ set(LINPHONE_PRIVATE_HEADER_FILES ../src/object/singleton.h ../src/utils/general.h ../src/conference/conference-listener.h - ../src/conference/conference-event-package.h + ../src/conference/remote-conference-event-handler.h + ../src/conference/local-conference-event-handler.h ../src/conference/conference-info.hxx bellesip_sal/sal_impl.h carddav.h @@ -127,7 +128,8 @@ set(LINPHONE_SOURCE_FILES_C ) set(LINPHONE_SOURCE_FILES_CXX conference.cc - ../src/conference/conference-event-package.cpp + ../src/conference/remote-conference-event-handler.cpp + ../src/conference/local-conference-event-handler.cpp ../src/conference/conference-info.cxx ) set(LINPHONE_INCLUDE_DIRS ${LINPHONE_INCLUDE_DIRS} /Users/reisbenjamin/xsd-4.0.0-i686-macosx/libxsd /usr/local/Cellar/xerces-c/3.1.4/include) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 07d215d8c..6786c376a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -45,7 +45,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mediastreamer2/msjpegwriter.h" #include "mediastreamer2/msogl.h" #include "mediastreamer2/msvolume.h" -#include "conference/conference-event-package.h" +#include "conference/remote-conference-event-handler.h" #ifdef INET6 #ifndef _WIN32 @@ -2117,10 +2117,10 @@ static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEve friendLists = friendLists->next; } } else if (strcmp(notified_event, "Conference") == 0) { - LinphonePrivate::Conference::ConferenceEventPackage *cep = reinterpret_cast(linphone_event_get_user_data(lev)); - if(cep) { - ms_message("notify event for conference %s", cep->getConfId().c_str()); - cep->notifyReceived((char *) linphone_content_get_buffer(body)); + LinphonePrivate::Conference::RemoteConferenceEventHandler *handler = reinterpret_cast(linphone_event_get_user_data(lev)); + if(handler) { + ms_message("notify event for conference %s", handler->getConfId().c_str()); + handler->notifyReceived((char *) linphone_content_get_buffer(body)); } } } @@ -2129,10 +2129,7 @@ static void linphone_core_internal_subscription_state_changed(LinphoneCore *lc, if (strcasecmp(linphone_event_get_name(lev), "Presence") == 0) { linphone_friend_list_subscription_state_changed(lc, lev, state); } else if (strcmp(linphone_event_get_name(lev), "Conference") == 0) { - LinphonePrivate::Conference::ConferenceEventPackage *cep = reinterpret_cast(linphone_event_get_user_data(lev)); - if(cep) { - - } + } } diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp new file mode 100644 index 000000000..ef26d59ef --- /dev/null +++ b/src/conference/local-conference-event-handler.cpp @@ -0,0 +1,155 @@ +/* + * local-conference-event-handler.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "local-conference-event-handler.h" +#include "conference-info.hxx" +#include "private.h" + +using namespace std; +using namespace conference_info; +using namespace LinphonePrivate; + +class Conference::LocalConferenceEventHandlerPrivate : public ObjectPrivate { +public: + void notifyFullState(string notify, LinphoneEvent *lev); + void notifyAllExcept(string notify, LinphoneAddress *addr); + + LocalConference *conf; + LinphoneCore *lc; +}; + +void Conference::LocalConferenceEventHandlerPrivate::notifyFullState(string notify, LinphoneEvent *lev) { + LinphoneContent* content = linphone_core_create_content(lev->lc); + linphone_content_set_buffer(content,notify.c_str(),strlen(notify.c_str())); + linphone_event_notify(lev, content); + linphone_content_unref(content); + // linphone_event_unref(lev); ?? +} + +void Conference::LocalConferenceEventHandlerPrivate::notifyAllExcept(string notify, LinphoneAddress *addr) { + for(auto participant : conf->getParticipants()) { + if(!linphone_address_equal(participant.getAddress(), addr)) { + LinphoneEvent *lev = linphone_core_create_notify(lc, participant.getAddress(), "Conference"); + LinphoneContent* content = linphone_core_create_content(lev->lc); + linphone_content_set_buffer(content,notify.c_str(),strlen(notify.c_str())); + linphone_event_notify(lev, content); + linphone_content_unref(content); + linphone_event_unref(lev); + } + } +} + +// -------- Conference::LocalConferenceEventHandler public methods --------- +Conference::LocalConferenceEventHandler::LocalConferenceEventHandler(LinphoneCore *core, LocalConference *localConf) : Object(new LocalConferenceEventHandlerPrivate) { + L_D(LocalConferenceEventHandler); + xercesc::XMLPlatformUtils::Initialize(); + d->conf = localConf; + d->lc = core; // conf->getCore() ? +} + +Conference::LocalConferenceEventHandler::~LocalConferenceEventHandler() { + xercesc::XMLPlatformUtils::Terminate(); +} + +string Conference::LocalConferenceEventHandler::subscribeReceived(LinphoneEvent *lev) { + L_D(LocalConferenceEventHandler); + char *entity = linphone_address_as_string_uri_only(d->conf->getAddress()); + Conference_type confInfo = Conference_type(entity); + Users_type users; + confInfo.setUsers(users); + stringstream notify; + xml_schema::NamespaceInfomap map; + + map[""].name = "urn:ietf:params:xml:ns:conference-info"; + for(auto participant : d->conf->getParticipants()) { + User_type user = User_type(); + User_roles_type roles; + user.setRoles(roles); + user.setEntity(linphone_address_as_string_uri_only(participant.getAddress())); + user.getRoles()->getEntry().push_back(participant.isAdmin() ? "admin" : "participant"); + user.setState("full"); + confInfo.getUsers()->getUser().push_back(user); + } + + serializeConference_info(notify, confInfo, map); + //d->notifyFullState(notify.str(), lev); + return notify.str(); +} + +string Conference::LocalConferenceEventHandler::notifyParticipantAdded(LinphoneAddress *addr) { + L_D(LocalConferenceEventHandler); + char *entity = linphone_address_as_string_uri_only(d->conf->getAddress()); + Conference_type confInfo = Conference_type(entity); + Users_type users; + confInfo.setUsers(users); + stringstream notify; + xml_schema::NamespaceInfomap map; + + User_type user = User_type(); + User_roles_type roles; + user.setRoles(roles); + user.setEntity(linphone_address_as_string_uri_only(addr)); + user.getRoles()->getEntry().push_back("participant"); + user.setState("full"); + confInfo.getUsers()->getUser().push_back(user); + + serializeConference_info(notify, confInfo, map); + //d->notifyAllExcept(notify.str(), addr); + return notify.str(); +} + +string Conference::LocalConferenceEventHandler::notifyParticipantRemoved(LinphoneAddress *addr) { + L_D(LocalConferenceEventHandler); + char *entity = linphone_address_as_string_uri_only(d->conf->getAddress()); + Conference_type confInfo = Conference_type(entity); + Users_type users; + confInfo.setUsers(users); + stringstream notify; + xml_schema::NamespaceInfomap map; + + User_type user = User_type(); + user.setEntity(linphone_address_as_string_uri_only(addr)); + user.setState("deleted"); + confInfo.getUsers()->getUser().push_back(user); + + serializeConference_info(notify, confInfo, map); + //d->notifyAllExcept(notify.str(), addr); + return notify.str(); +} + +string Conference::LocalConferenceEventHandler::notifyParticipantSetAdmin(LinphoneAddress *addr, bool isAdmin) { + L_D(LocalConferenceEventHandler); + char *entity = linphone_address_as_string_uri_only(d->conf->getAddress()); + Conference_type confInfo = Conference_type(entity); + Users_type users; + confInfo.setUsers(users); + stringstream notify; + xml_schema::NamespaceInfomap map; + + User_type user = User_type(); + User_roles_type roles; + user.setRoles(roles); + user.setEntity(linphone_address_as_string_uri_only(addr)); + user.getRoles()->getEntry().push_back(isAdmin ? "admin" : "participant"); + user.setState("partial"); + confInfo.getUsers()->getUser().push_back(user); + + serializeConference_info(notify, confInfo, map); + //d->notifyAllExcept(notify.str(), addr); + return notify.str(); +} diff --git a/src/conference/local-conference-event-handler.h b/src/conference/local-conference-event-handler.h new file mode 100644 index 000000000..001a2a492 --- /dev/null +++ b/src/conference/local-conference-event-handler.h @@ -0,0 +1,112 @@ +/* + * local-conference-event-handler.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _LOCAL_CONFERENCE_EVENT_HANDLER_H_ +#define _LOCAL_CONFERENCE_EVENT_HANDLER_H_ + +#include +#include +#include + +#include "object/object.h" +#include "linphone/core.h" +#include "linphone/event.h" + +namespace LinphonePrivate { + namespace Conference { + // ------------------------------------------------------------------------- + // LocalConferenceEventHandler. + // ------------------------------------------------------------------------- + class LocalConference; + class LocalConferenceEventHandlerPrivate; + class LocalConferenceEventHandler : public Object { + public: + LocalConferenceEventHandler(LinphoneCore *core, LocalConference* localConf); + ~LocalConferenceEventHandler(); + std::string subscribeReceived(LinphoneEvent *lev); + std::string notifyParticipantAdded(LinphoneAddress *addr); + std::string notifyParticipantRemoved(LinphoneAddress *addr); + std::string notifyParticipantSetAdmin(LinphoneAddress *addr, bool isAdmin); + + private: + L_DECLARE_PRIVATE(LocalConferenceEventHandler); + L_DISABLE_COPY(LocalConferenceEventHandler); + }; + + class Participant { + public: + Participant(LinphoneAddress *addr, bool admin); + ~Participant(); + bool isAdmin(); + LinphoneAddress *getAddress(); + + LinphoneAddress *mAddr; + bool mAdmin; + }; + + class LocalConference { + public: + LocalConference(LinphoneCore *lc, LinphoneAddress *confAddr); + ~LocalConference(); + LinphoneAddress *getAddress(); + std::list getParticipants(); + + std::shared_ptr mHandler; + std::list mParticipants; + LinphoneAddress *mConfAddr; + }; + } +} + + +// -------- Conference::LocalConference public methods --------- +LinphonePrivate::Conference::LocalConference::LocalConference(LinphoneCore *core, LinphoneAddress *confAddr) { + mConfAddr = confAddr; + mHandler = std::make_shared(core, this); +} + +LinphonePrivate::Conference::LocalConference::~LocalConference() { + //linphone_address_unref(mConfAddr); +} + +LinphoneAddress* LinphonePrivate::Conference::LocalConference::getAddress() { + return mConfAddr; +} + +std::list LinphonePrivate::Conference::LocalConference::getParticipants() { + return mParticipants; +} + +LinphonePrivate::Conference::Participant::Participant(LinphoneAddress *addr, bool admin) { + mAddr = addr; + mAdmin = admin; +} + +LinphonePrivate::Conference::Participant::~Participant() { + //linphone_address_unref(mAddr); +} + +bool LinphonePrivate::Conference::Participant::isAdmin() { + return mAdmin; +} + +LinphoneAddress* LinphonePrivate::Conference::Participant::getAddress() { + return mAddr; +} + +#endif // ifndef _LOCAL_CONFERENCE_EVENT_HANDLER_H_ \ No newline at end of file diff --git a/src/conference/conference-event-package.cpp b/src/conference/remote-conference-event-handler.cpp similarity index 71% rename from src/conference/conference-event-package.cpp rename to src/conference/remote-conference-event-handler.cpp index 41a2b26bf..226aa9e4c 100644 --- a/src/conference/conference-event-package.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -1,5 +1,5 @@ /* - * conference-event-package.cpp + * remote-conference-event-handler.cpp * Copyright (C) 2017 Belledonne Communications SARL * * This program is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -#include "conference-event-package.h" +#include "remote-conference-event-handler.h" #include "conference-info.hxx" #include "private.h" @@ -24,7 +24,7 @@ using namespace std; using namespace conference_info; using namespace LinphonePrivate; -class LinphonePrivate::Conference::ConferenceEventPackagePrivate : public ObjectPrivate { +class Conference::RemoteConferenceEventHandlerPrivate : public ObjectPrivate { public: LinphoneCore *lc; ConferenceListener *listener; @@ -33,8 +33,9 @@ public: LinphoneEvent *lev; }; -Conference::ConferenceEventPackage::ConferenceEventPackage(LinphoneCore *lc, ConferenceListener *listener, LinphoneAddress *confAddr) : Object(new Conference::ConferenceEventPackagePrivate) { - L_D(ConferenceEventPackage); +// -------- Conference::RemoteConferenceEventHandler public methods --------- +Conference::RemoteConferenceEventHandler::RemoteConferenceEventHandler(LinphoneCore *lc, ConferenceListener *listener, LinphoneAddress *confAddr) : Object(new RemoteConferenceEventHandlerPrivate) { + L_D(RemoteConferenceEventHandler); xercesc::XMLPlatformUtils::Initialize(); d->lc = lc; d->listener = listener; @@ -43,15 +44,15 @@ Conference::ConferenceEventPackage::ConferenceEventPackage(LinphoneCore *lc, Con d->lev = NULL; } -Conference::ConferenceEventPackage::~ConferenceEventPackage() { - L_D(ConferenceEventPackage); +Conference::RemoteConferenceEventHandler::~RemoteConferenceEventHandler() { + L_D(RemoteConferenceEventHandler); xercesc::XMLPlatformUtils::Terminate(); linphone_address_unref(d->confAddr); if(d->lev) linphone_event_unref(d->lev); } -void Conference::ConferenceEventPackage::subscribe(string confId) { - L_D(ConferenceEventPackage); +void Conference::RemoteConferenceEventHandler::subscribe(string confId) { + L_D(RemoteConferenceEventHandler); d->confId = confId; d->lev = linphone_core_create_subscribe(d->lc, d->confAddr, "Conference", 600); linphone_event_ref(d->lev); @@ -61,13 +62,13 @@ void Conference::ConferenceEventPackage::subscribe(string confId) { linphone_event_send_subscribe(d->lev, NULL); } -void Conference::ConferenceEventPackage::unsubscribe() { - L_D(ConferenceEventPackage); +void Conference::RemoteConferenceEventHandler::unsubscribe() { + L_D(RemoteConferenceEventHandler); linphone_event_terminate(d->lev); } -void Conference::ConferenceEventPackage::notifyReceived(const char *xmlBody) { - L_D(ConferenceEventPackage); +void Conference::RemoteConferenceEventHandler::notifyReceived(const char *xmlBody) { + L_D(RemoteConferenceEventHandler); istringstream data(xmlBody); unique_ptr confInfo = parseConference_info(data, xml_schema::Flags::dont_validate); if(strcmp(confInfo->getEntity().c_str(), linphone_address_as_string(d->confAddr)) == 0) { @@ -95,7 +96,7 @@ void Conference::ConferenceEventPackage::notifyReceived(const char *xmlBody) { } } -string Conference::ConferenceEventPackage::getConfId() { - L_D(ConferenceEventPackage); +string Conference::RemoteConferenceEventHandler::getConfId() { + L_D(RemoteConferenceEventHandler); return d->confId; } diff --git a/src/conference/conference-event-package.h b/src/conference/remote-conference-event-handler.h similarity index 67% rename from src/conference/conference-event-package.h rename to src/conference/remote-conference-event-handler.h index 3237cf41d..ef8212128 100644 --- a/src/conference/conference-event-package.h +++ b/src/conference/remote-conference-event-handler.h @@ -1,5 +1,5 @@ /* - * conference-event-package.h + * remote-conference-event-handler.h * Copyright (C) 2017 Belledonne Communications SARL * * This program is free software: you can redistribute it and/or modify @@ -16,8 +16,8 @@ * along with this program. If not, see . */ -#ifndef _CONFERENCE_EVENT_PACKAGE_H_ -#define _CONFERENCE_EVENT_PACKAGE_H_ +#ifndef _REMOTE_CONFERENCE_EVENT_HANDLER_H_ +#define _REMOTE_CONFERENCE_EVENT_HANDLER_H_ #include @@ -27,25 +27,24 @@ namespace LinphonePrivate { namespace Conference { - class ConferenceEventPackagePrivate; - // ------------------------------------------------------------------------- - // ConferenceEventPackage. + // RemoteConferenceEventHandler. // ------------------------------------------------------------------------- - class ConferenceEventPackage : public Object { + class RemoteConferenceEventHandlerPrivate; + class RemoteConferenceEventHandler : public Object { public: - ConferenceEventPackage(LinphoneCore *lc, ConferenceListener *listener, LinphoneAddress *confAddr); - ~ConferenceEventPackage(); + RemoteConferenceEventHandler(LinphoneCore *lc, ConferenceListener *listener, LinphoneAddress *confAddr); + ~RemoteConferenceEventHandler(); void subscribe(std::string confId); void notifyReceived(const char *xmlBody); void unsubscribe(); std::string getConfId(); private: - L_DECLARE_PRIVATE(ConferenceEventPackage); - L_DISABLE_COPY(ConferenceEventPackage); + L_DECLARE_PRIVATE(RemoteConferenceEventHandler); + L_DISABLE_COPY(RemoteConferenceEventHandler); }; } } -#endif // ifndef _CONFERENCE_EVENT_PACKAGE_H_ +#endif // ifndef _REMOTE_CONFERENCE_EVENT_HANDLER_H_ diff --git a/tester/confeventpackage_tester.cpp b/tester/confeventpackage_tester.cpp index b909bf122..e737ec654 100644 --- a/tester/confeventpackage_tester.cpp +++ b/tester/confeventpackage_tester.cpp @@ -22,7 +22,8 @@ #include "private.h" #include "liblinphone_tester.h" #include "conference/conference-listener.h" -#include "conference/conference-event-package.h" +#include "conference/remote-conference-event-handler.h" +#include "conference/local-conference-event-handler.h" using namespace LinphonePrivate; using namespace std; @@ -413,20 +414,12 @@ static const char *aliceUri = "sip:alice@example.com"; static const char *frankUri = "sip:frank@example.com"; static const char *confUri = "sips:conf233@example.com"; -void linphone_conf_event_notify(LinphoneEvent *lev){ - LinphoneContent* content = linphone_core_create_content(lev->lc); - const char* uri = linphone_address_as_string_uri_only((LinphoneAddress*)sal_op_get_to_address(lev->op)); - char notify[strlen(first_notify) + strlen(uri)]; - snprintf(notify, sizeof(notify), first_notify, uri); - linphone_content_set_buffer(content,notify,strlen(notify)); - linphone_event_notify(lev, content); - linphone_content_unref(content); -} + class ConferenceEventTester : public Conference::ConferenceListener{ public: - shared_ptr cep; - map participants; + shared_ptr mHandler; + map mParticipants; ConferenceEventTester(LinphoneCore *lc, LinphoneAddress *confAddr); @@ -438,22 +431,22 @@ public: }; ConferenceEventTester::ConferenceEventTester(LinphoneCore *lc, LinphoneAddress *confAddr){ - this->cep = make_shared(lc, this, confAddr); + mHandler = make_shared(lc, this, confAddr); } void ConferenceEventTester::conferenceCreated(LinphoneAddress *confAddress){} void ConferenceEventTester::conferenceTerminated(LinphoneAddress *confAddress){} void ConferenceEventTester::participantAdded(LinphoneAddress *addr){ - this->participants.insert(pair(linphone_address_as_string(addr),0)); + mParticipants.insert(pair(linphone_address_as_string(addr),0)); } void ConferenceEventTester::participantRemoved(LinphoneAddress *addr){ - this->participants.erase(linphone_address_as_string(addr)); + mParticipants.erase(linphone_address_as_string(addr)); } void ConferenceEventTester::participantSetAdmin(LinphoneAddress *addr, bool isAdmin){ const char *addrAsString = linphone_address_as_string(addr); - if(this->participants.find(addrAsString) != this->participants.end()){ - this->participants.erase(addrAsString); - this->participants.insert(pair(addrAsString, isAdmin ? 1 : 0)); + if(mParticipants.find(addrAsString) != mParticipants.end()){ + mParticipants.erase(addrAsString); + mParticipants.insert(pair(addrAsString, isAdmin ? 1 : 0)); } } @@ -466,13 +459,13 @@ void first_notify_parsing(void){ char notify[strlen(first_notify) + strlen(confUri)]; snprintf(notify, sizeof(notify), first_notify, confUri); - tester.cep->notifyReceived(notify); + tester.mHandler->notifyReceived(notify); - BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr))->second == 0); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second == 1); + BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); linphone_address_unref(bobAddr); linphone_address_unref(aliceAddr); @@ -489,11 +482,11 @@ void first_notify_parsing_wrong_conf(void){ char notify[strlen(first_notify) + strlen(confUri)]; snprintf(notify, sizeof(notify), first_notify, confUri); - tester.cep->notifyReceived(notify); + tester.mHandler->notifyReceived(notify); - BC_ASSERT_EQUAL(tester.participants.size(), 0, int, "%d"); - BC_ASSERT_FALSE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); - BC_ASSERT_FALSE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); + BC_ASSERT_EQUAL(tester.mParticipants.size(), 0, int, "%d"); + BC_ASSERT_FALSE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); + BC_ASSERT_FALSE(tester.mParticipants.find(linphone_address_as_string(aliceAddr)) != tester.mParticipants.end()); linphone_address_unref(bobAddr); linphone_address_unref(aliceAddr); @@ -512,20 +505,20 @@ void participant_added_parsing(void){ char notify_added[strlen(participant_added_notify) + strlen(confUri)]; snprintf(notify, sizeof(notify), first_notify, confUri); - tester.cep->notifyReceived(notify); + tester.mHandler->notifyReceived(notify); - BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr))->second == 0); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second == 1); + BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); snprintf(notify_added, sizeof(notify_added), participant_added_notify, confUri); - tester.cep->notifyReceived(notify_added); + tester.mHandler->notifyReceived(notify_added); - BC_ASSERT_EQUAL(tester.participants.size(), 3, int, "%d"); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(frankAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(frankAddr))->second == 0); + BC_ASSERT_EQUAL(tester.mParticipants.size(), 3, int, "%d"); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(frankAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(frankAddr))->second == 0); linphone_address_unref(bobAddr); linphone_address_unref(aliceAddr); @@ -545,19 +538,19 @@ void participant_not_added_parsing(void){ char notify_not_added[strlen(participant_not_added_notify) + strlen(confUri)]; snprintf(notify, sizeof(notify), first_notify, confUri); - tester.cep->notifyReceived(notify); + tester.mHandler->notifyReceived(notify); - BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr))->second == 0); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second == 1); + BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); snprintf(notify_not_added, sizeof(notify_not_added), participant_not_added_notify, confUri); - tester.cep->notifyReceived(notify_not_added); + tester.mHandler->notifyReceived(notify_not_added); - BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); - BC_ASSERT_FALSE(tester.participants.find(linphone_address_as_string(frankAddr)) != tester.participants.end()); + BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); + BC_ASSERT_FALSE(tester.mParticipants.find(linphone_address_as_string(frankAddr)) != tester.mParticipants.end()); linphone_address_unref(bobAddr); linphone_address_unref(aliceAddr); @@ -576,19 +569,19 @@ void participant_deleted_parsing(void){ char notify_deleted[strlen(participant_deleted_notify) + strlen(confUri)]; snprintf(notify, sizeof(notify), first_notify, confUri); - tester.cep->notifyReceived(notify); + tester.mHandler->notifyReceived(notify); - BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr))->second == 0); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second == 1); + BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); snprintf(notify_deleted, sizeof(notify_deleted), participant_deleted_notify, confUri); - tester.cep->notifyReceived(notify_deleted); + tester.mHandler->notifyReceived(notify_deleted); - BC_ASSERT_EQUAL(tester.participants.size(), 1, int, "%d"); - BC_ASSERT_FALSE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); + BC_ASSERT_EQUAL(tester.mParticipants.size(), 1, int, "%d"); + BC_ASSERT_FALSE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); linphone_address_unref(bobAddr); linphone_address_unref(aliceAddr); @@ -606,20 +599,20 @@ void participant_admined_parsing(void){ char notify_admined[strlen(participant_admined_notify) + strlen(confUri)]; snprintf(notify, sizeof(notify), first_notify, confUri); - tester.cep->notifyReceived(notify); + tester.mHandler->notifyReceived(notify); - BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr))->second == 0); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second == 1); + BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); snprintf(notify_admined, sizeof(notify_admined), participant_admined_notify, confUri); - tester.cep->notifyReceived(notify_admined); + tester.mHandler->notifyReceived(notify_admined); - BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr))->second == 1); + BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 1); linphone_address_unref(bobAddr); linphone_address_unref(aliceAddr); @@ -637,20 +630,20 @@ void participant_unadmined_parsing(void){ char notify_unadmined[strlen(participant_unadmined_notify) + strlen(confUri)]; snprintf(notify, sizeof(notify), first_notify, confUri); - tester.cep->notifyReceived(notify); + tester.mHandler->notifyReceived(notify); - BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr))->second == 0); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second == 1); + BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); snprintf(notify_unadmined, sizeof(notify_unadmined), participant_unadmined_notify, confUri); - tester.cep->notifyReceived(notify_unadmined); + tester.mHandler->notifyReceived(notify_unadmined); - BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second == 0); + BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 0); linphone_address_unref(bobAddr); linphone_address_unref(aliceAddr); @@ -658,39 +651,231 @@ void participant_unadmined_parsing(void){ linphone_core_manager_destroy(marie); } -void send_subscribe_receive_first_notify(void){ +void send_first_notify(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + ConferenceEventTester tester(marie->lc, pauline->identity); + Conference::LocalConference localConf(pauline->lc, pauline->identity); + LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); + LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); + Conference::Participant p1(bobAddr, false); + Conference::Participant p2(aliceAddr, true); + LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "Conference"); + string notify; + + localConf.mParticipants.push_back(p1); + localConf.mParticipants.push_back(p2); + notify = localConf.mHandler->subscribeReceived(lev); + tester.mHandler->notifyReceived(notify.c_str()); + + BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); + + linphone_event_unref(lev); + linphone_address_unref(bobAddr); + linphone_address_unref(aliceAddr); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +void send_added_notify(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); ConferenceEventTester tester(marie->lc, pauline->identity); + Conference::LocalConference localConf(pauline->lc, pauline->identity); LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); - string confId("conf233"); + LinphoneAddress *frankAddr = linphone_core_interpret_url(marie->lc, frankUri); + Conference::Participant p1(bobAddr, false); + Conference::Participant p2(aliceAddr, true); + Conference::Participant p3(frankAddr, false); + LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "Conference"); + string notify; - BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneRegistrationOk,1,1000)); - BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneRegistrationOk,1,1000)); + localConf.mParticipants.push_back(p1); + localConf.mParticipants.push_back(p2); + notify = localConf.mHandler->subscribeReceived(lev); + tester.mHandler->notifyReceived(notify.c_str()); - tester.cep->subscribe(confId); + BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); - BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000)); - BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneSubscriptionActive,1,3000)); - wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_NotifyReceived,1,3000); + notify = localConf.mHandler->notifyParticipantAdded(frankAddr); + tester.mHandler->notifyReceived(notify.c_str()); - BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr))->second == 0); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second == 1); + BC_ASSERT_EQUAL(tester.mParticipants.size(), 3, int, "%d"); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(frankAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(frankAddr))->second == 0); - tester.cep->unsubscribe(); + linphone_event_unref(lev); + linphone_address_unref(bobAddr); + linphone_address_unref(aliceAddr); + linphone_address_unref(frankAddr); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} - BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); +void send_removed_notify(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + ConferenceEventTester tester(marie->lc, pauline->identity); + Conference::LocalConference localConf(pauline->lc, pauline->identity); + LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); + LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); + Conference::Participant p1(bobAddr, false); + Conference::Participant p2(aliceAddr, true); + LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "Conference"); + string notify; + localConf.mParticipants.push_back(p1); + localConf.mParticipants.push_back(p2); + notify = localConf.mHandler->subscribeReceived(lev); + tester.mHandler->notifyReceived(notify.c_str()); + + BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); + + notify = localConf.mHandler->notifyParticipantRemoved(bobAddr); + tester.mHandler->notifyReceived(notify.c_str()); + + BC_ASSERT_EQUAL(tester.mParticipants.size(), 1, int, "%d"); + BC_ASSERT_FALSE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); + + linphone_event_unref(lev); linphone_address_unref(bobAddr); linphone_address_unref(aliceAddr); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } +void send_admined_notify(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + ConferenceEventTester tester(marie->lc, pauline->identity); + Conference::LocalConference localConf(pauline->lc, pauline->identity); + LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); + LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); + Conference::Participant p1(bobAddr, false); + Conference::Participant p2(aliceAddr, true); + Conference::Participant p3(bobAddr, true); + LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "Conference"); + string notify; + + localConf.mParticipants.push_back(p1); + localConf.mParticipants.push_back(p2); + notify = localConf.mHandler->subscribeReceived(lev); + tester.mHandler->notifyReceived(notify.c_str()); + + BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); + + notify = localConf.mHandler->notifyParticipantSetAdmin(bobAddr, true); + tester.mHandler->notifyReceived(notify.c_str()); + + BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 1); + + linphone_event_unref(lev); + linphone_address_unref(bobAddr); + linphone_address_unref(aliceAddr); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +void send_unadmined_notify(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + ConferenceEventTester tester(marie->lc, pauline->identity); + Conference::LocalConference localConf(pauline->lc, pauline->identity); + LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); + LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); + Conference::Participant p1(bobAddr, false); + Conference::Participant p2(aliceAddr, true); + Conference::Participant p3(aliceAddr, false); + LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "Conference"); + string notify; + + localConf.mParticipants.push_back(p1); + localConf.mParticipants.push_back(p2); + notify = localConf.mHandler->subscribeReceived(lev); + tester.mHandler->notifyReceived(notify.c_str()); + + BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); + + notify = localConf.mHandler->notifyParticipantSetAdmin(aliceAddr, false); + tester.mHandler->notifyReceived(notify.c_str()); + + BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 0); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 0); + + linphone_event_unref(lev); + linphone_address_unref(bobAddr); + linphone_address_unref(aliceAddr); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +void send_subscribe_receive_first_notify(void){ + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + ConferenceEventTester tester(marie->lc, pauline->identity); + LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); + LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); + string confId("conf233"); + + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneRegistrationOk,1,1000)); + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneRegistrationOk,1,1000)); + + tester.mHandler->subscribe(confId); + + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000)); + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneSubscriptionActive,1,3000)); + wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_NotifyReceived,1,3000); + + BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr)) != tester.mParticipants.end()); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 0); + BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); + + tester.mHandler->unsubscribe(); + + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); + + linphone_address_unref(bobAddr); + linphone_address_unref(aliceAddr); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + test_t conf_event_tests[] = { TEST_NO_TAG("First notify parsing", first_notify_parsing), TEST_NO_TAG("First notify parsing wrong conf", first_notify_parsing_wrong_conf), @@ -699,7 +884,12 @@ test_t conf_event_tests[] = { TEST_NO_TAG("Participant deleted", participant_deleted_parsing), TEST_NO_TAG("Participant admined", participant_admined_parsing), TEST_NO_TAG("Participant unadmined", participant_unadmined_parsing), - TEST_NO_TAG("Send subscribe receive first notify", send_subscribe_receive_first_notify) + TEST_NO_TAG("Send first notify", send_first_notify), + TEST_NO_TAG("Send participant added notify", send_added_notify), + TEST_NO_TAG("Send participant removed notify", send_removed_notify), + TEST_NO_TAG("Send participant admined notify", send_admined_notify), + TEST_NO_TAG("Send participant unadmined notify", send_unadmined_notify) + //TEST_NO_TAG("Send subscribe receive first notify", send_subscribe_receive_first_notify) }; test_suite_t conf_event_test_suite = {"Conf event package", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each, diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index 7369095b5..24614827f 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -83,7 +83,7 @@ void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, Li if (linphone_event_get_subscription_dir(lev)==LinphoneSubscriptionIncoming){ mgr->lev=lev; if(strcmp(linphone_event_get_name(lev), "Conference") == 0) { - linphone_conf_event_notify(lev); + // TODO : Get LocalConfEventHandler and call handler->subscribeReceived(lev) } else { linphone_event_notify(lev,content); } From bbd08f3aaf20907f6244e642d93592aedef41086 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 4 Aug 2017 14:44:10 +0200 Subject: [PATCH 0006/2215] fix merge --- coreapi/CMakeLists.txt | 5 +---- src/conference/local-conference-event-handler.cpp | 2 +- src/conference/remote-conference-event-handler.cpp | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 5bccca85d..06d84215d 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -184,11 +184,8 @@ set(LIBS ${MEDIASTREAMER2_LIBRARIES} ${ORTP_LIBRARIES} ${XML2_LIBRARIES} -<<<<<<< HEAD - /usr/local/Cellar/xerces-c/3.1.4/lib/libxerces-c.dylib -======= ${BELR_LIBRARIES} ->>>>>>> origin/master + /usr/local/Cellar/xerces-c/3.1.4/lib/libxerces-c.dylib ) if(WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") list(APPEND LIBS "Ws2_32") diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index ef26d59ef..ff0e6a3b5 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -55,7 +55,7 @@ void Conference::LocalConferenceEventHandlerPrivate::notifyAllExcept(string noti } // -------- Conference::LocalConferenceEventHandler public methods --------- -Conference::LocalConferenceEventHandler::LocalConferenceEventHandler(LinphoneCore *core, LocalConference *localConf) : Object(new LocalConferenceEventHandlerPrivate) { +Conference::LocalConferenceEventHandler::LocalConferenceEventHandler(LinphoneCore *core, LocalConference *localConf) : Object(*new LocalConferenceEventHandlerPrivate) { L_D(LocalConferenceEventHandler); xercesc::XMLPlatformUtils::Initialize(); d->conf = localConf; diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 226aa9e4c..08ed76c36 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -34,7 +34,7 @@ public: }; // -------- Conference::RemoteConferenceEventHandler public methods --------- -Conference::RemoteConferenceEventHandler::RemoteConferenceEventHandler(LinphoneCore *lc, ConferenceListener *listener, LinphoneAddress *confAddr) : Object(new RemoteConferenceEventHandlerPrivate) { +Conference::RemoteConferenceEventHandler::RemoteConferenceEventHandler(LinphoneCore *lc, ConferenceListener *listener, LinphoneAddress *confAddr) : Object(*new RemoteConferenceEventHandlerPrivate) { L_D(RemoteConferenceEventHandler); xercesc::XMLPlatformUtils::Initialize(); d->lc = lc; From 23f4d851f193b1e8998b9f2aacdae3c315ce8c2c Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 7 Aug 2017 11:22:56 +0200 Subject: [PATCH 0007/2215] better use of memory --- .../local-conference-event-handler.cpp | 4 +-- .../local-conference-event-handler.h | 29 ++++++++++++------- tester/confeventpackage_tester.cpp | 18 ++++++------ 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index ff0e6a3b5..3bde61970 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -42,7 +42,7 @@ void Conference::LocalConferenceEventHandlerPrivate::notifyFullState(string noti } void Conference::LocalConferenceEventHandlerPrivate::notifyAllExcept(string notify, LinphoneAddress *addr) { - for(auto participant : conf->getParticipants()) { + for(const auto &participant : conf->getParticipants()) { if(!linphone_address_equal(participant.getAddress(), addr)) { LinphoneEvent *lev = linphone_core_create_notify(lc, participant.getAddress(), "Conference"); LinphoneContent* content = linphone_core_create_content(lev->lc); @@ -76,7 +76,7 @@ string Conference::LocalConferenceEventHandler::subscribeReceived(LinphoneEvent xml_schema::NamespaceInfomap map; map[""].name = "urn:ietf:params:xml:ns:conference-info"; - for(auto participant : d->conf->getParticipants()) { + for(const auto &participant : d->conf->getParticipants()) { User_type user = User_type(); User_roles_type roles; user.setRoles(roles); diff --git a/src/conference/local-conference-event-handler.h b/src/conference/local-conference-event-handler.h index 001a2a492..0b2768685 100644 --- a/src/conference/local-conference-event-handler.h +++ b/src/conference/local-conference-event-handler.h @@ -52,9 +52,10 @@ namespace LinphonePrivate { public: Participant(LinphoneAddress *addr, bool admin); ~Participant(); - bool isAdmin(); - LinphoneAddress *getAddress(); + bool isAdmin() const; + const LinphoneAddress *getAddress() const; + private: LinphoneAddress *mAddr; bool mAdmin; }; @@ -63,12 +64,15 @@ namespace LinphonePrivate { public: LocalConference(LinphoneCore *lc, LinphoneAddress *confAddr); ~LocalConference(); - LinphoneAddress *getAddress(); - std::list getParticipants(); - - std::shared_ptr mHandler; + const LinphoneAddress *getAddress() const; + std::list getParticipants() const; + const std::shared_ptr getHandler() const; + std::list mParticipants; + + private: LinphoneAddress *mConfAddr; + std::shared_ptr mHandler; }; } } @@ -84,11 +88,16 @@ LinphonePrivate::Conference::LocalConference::~LocalConference() { //linphone_address_unref(mConfAddr); } -LinphoneAddress* LinphonePrivate::Conference::LocalConference::getAddress() { +const LinphoneAddress* LinphonePrivate::Conference::LocalConference::getAddress() const { return mConfAddr; } -std::list LinphonePrivate::Conference::LocalConference::getParticipants() { + +const std::shared_ptr LinphonePrivate::Conference::LocalConference::getHandler() const { + return mHandler; +} + +std::list LinphonePrivate::Conference::LocalConference::getParticipants() const { return mParticipants; } @@ -101,11 +110,11 @@ LinphonePrivate::Conference::Participant::~Participant() { //linphone_address_unref(mAddr); } -bool LinphonePrivate::Conference::Participant::isAdmin() { +bool LinphonePrivate::Conference::Participant::isAdmin() const { return mAdmin; } -LinphoneAddress* LinphonePrivate::Conference::Participant::getAddress() { +const LinphoneAddress* LinphonePrivate::Conference::Participant::getAddress() const { return mAddr; } diff --git a/tester/confeventpackage_tester.cpp b/tester/confeventpackage_tester.cpp index e737ec654..64d43468e 100644 --- a/tester/confeventpackage_tester.cpp +++ b/tester/confeventpackage_tester.cpp @@ -665,7 +665,7 @@ void send_first_notify(void) { localConf.mParticipants.push_back(p1); localConf.mParticipants.push_back(p2); - notify = localConf.mHandler->subscribeReceived(lev); + notify = localConf.getHandler()->subscribeReceived(lev); tester.mHandler->notifyReceived(notify.c_str()); BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); @@ -697,7 +697,7 @@ void send_added_notify(void) { localConf.mParticipants.push_back(p1); localConf.mParticipants.push_back(p2); - notify = localConf.mHandler->subscribeReceived(lev); + notify = localConf.getHandler()->subscribeReceived(lev); tester.mHandler->notifyReceived(notify.c_str()); BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); @@ -706,7 +706,7 @@ void send_added_notify(void) { BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 0); BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); - notify = localConf.mHandler->notifyParticipantAdded(frankAddr); + notify = localConf.getHandler()->notifyParticipantAdded(frankAddr); tester.mHandler->notifyReceived(notify.c_str()); BC_ASSERT_EQUAL(tester.mParticipants.size(), 3, int, "%d"); @@ -739,7 +739,7 @@ void send_removed_notify(void) { localConf.mParticipants.push_back(p1); localConf.mParticipants.push_back(p2); - notify = localConf.mHandler->subscribeReceived(lev); + notify = localConf.getHandler()->subscribeReceived(lev); tester.mHandler->notifyReceived(notify.c_str()); BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); @@ -748,7 +748,7 @@ void send_removed_notify(void) { BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 0); BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); - notify = localConf.mHandler->notifyParticipantRemoved(bobAddr); + notify = localConf.getHandler()->notifyParticipantRemoved(bobAddr); tester.mHandler->notifyReceived(notify.c_str()); BC_ASSERT_EQUAL(tester.mParticipants.size(), 1, int, "%d"); @@ -778,7 +778,7 @@ void send_admined_notify(void) { localConf.mParticipants.push_back(p1); localConf.mParticipants.push_back(p2); - notify = localConf.mHandler->subscribeReceived(lev); + notify = localConf.getHandler()->subscribeReceived(lev); tester.mHandler->notifyReceived(notify.c_str()); BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); @@ -787,7 +787,7 @@ void send_admined_notify(void) { BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 0); BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); - notify = localConf.mHandler->notifyParticipantSetAdmin(bobAddr, true); + notify = localConf.getHandler()->notifyParticipantSetAdmin(bobAddr, true); tester.mHandler->notifyReceived(notify.c_str()); BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); @@ -818,7 +818,7 @@ void send_unadmined_notify(void) { localConf.mParticipants.push_back(p1); localConf.mParticipants.push_back(p2); - notify = localConf.mHandler->subscribeReceived(lev); + notify = localConf.getHandler()->subscribeReceived(lev); tester.mHandler->notifyReceived(notify.c_str()); BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); @@ -827,7 +827,7 @@ void send_unadmined_notify(void) { BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(bobAddr))->second == 0); BC_ASSERT_TRUE(tester.mParticipants.find(linphone_address_as_string(aliceAddr))->second == 1); - notify = localConf.mHandler->notifyParticipantSetAdmin(aliceAddr, false); + notify = localConf.getHandler()->notifyParticipantSetAdmin(aliceAddr, false); tester.mHandler->notifyReceived(notify.c_str()); BC_ASSERT_EQUAL(tester.mParticipants.size(), 2, int, "%d"); From 8272134d35371acb3d22c7736b5e5d191877e547 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 7 Aug 2017 11:56:54 +0200 Subject: [PATCH 0008/2215] allow abstract participant arch to localConference --- .../local-conference-event-handler.h | 8 ++++++-- tester/confeventpackage_tester.cpp | 20 +++++++++---------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/conference/local-conference-event-handler.h b/src/conference/local-conference-event-handler.h index 0b2768685..4dd08d1e5 100644 --- a/src/conference/local-conference-event-handler.h +++ b/src/conference/local-conference-event-handler.h @@ -67,12 +67,12 @@ namespace LinphonePrivate { const LinphoneAddress *getAddress() const; std::list getParticipants() const; const std::shared_ptr getHandler() const; - - std::list mParticipants; + void addParticipant(Participant p); private: LinphoneAddress *mConfAddr; std::shared_ptr mHandler; + std::list mParticipants; }; } } @@ -101,6 +101,10 @@ std::list LinphonePrivate::Conference: return mParticipants; } +void LinphonePrivate::Conference::LocalConference::addParticipant(LinphonePrivate::Conference::Participant p) { + mParticipants.push_back(p); +} + LinphonePrivate::Conference::Participant::Participant(LinphoneAddress *addr, bool admin) { mAddr = addr; mAdmin = admin; diff --git a/tester/confeventpackage_tester.cpp b/tester/confeventpackage_tester.cpp index 64d43468e..a0753694d 100644 --- a/tester/confeventpackage_tester.cpp +++ b/tester/confeventpackage_tester.cpp @@ -663,8 +663,8 @@ void send_first_notify(void) { LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "Conference"); string notify; - localConf.mParticipants.push_back(p1); - localConf.mParticipants.push_back(p2); + localConf.addParticipant(p1); + localConf.addParticipant(p2); notify = localConf.getHandler()->subscribeReceived(lev); tester.mHandler->notifyReceived(notify.c_str()); @@ -695,8 +695,8 @@ void send_added_notify(void) { LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "Conference"); string notify; - localConf.mParticipants.push_back(p1); - localConf.mParticipants.push_back(p2); + localConf.addParticipant(p1); + localConf.addParticipant(p2); notify = localConf.getHandler()->subscribeReceived(lev); tester.mHandler->notifyReceived(notify.c_str()); @@ -737,8 +737,8 @@ void send_removed_notify(void) { LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "Conference"); string notify; - localConf.mParticipants.push_back(p1); - localConf.mParticipants.push_back(p2); + localConf.addParticipant(p1); + localConf.addParticipant(p2); notify = localConf.getHandler()->subscribeReceived(lev); tester.mHandler->notifyReceived(notify.c_str()); @@ -776,8 +776,8 @@ void send_admined_notify(void) { LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "Conference"); string notify; - localConf.mParticipants.push_back(p1); - localConf.mParticipants.push_back(p2); + localConf.addParticipant(p1); + localConf.addParticipant(p2); notify = localConf.getHandler()->subscribeReceived(lev); tester.mHandler->notifyReceived(notify.c_str()); @@ -816,8 +816,8 @@ void send_unadmined_notify(void) { LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "Conference"); string notify; - localConf.mParticipants.push_back(p1); - localConf.mParticipants.push_back(p2); + localConf.addParticipant(p1); + localConf.addParticipant(p2); notify = localConf.getHandler()->subscribeReceived(lev); tester.mHandler->notifyReceived(notify.c_str()); From 3e3991acc2dd36b9849e360f1b51f785f0203e40 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 7 Aug 2017 12:02:33 +0200 Subject: [PATCH 0009/2215] remove useless variable --- tester/confeventpackage_tester.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/tester/confeventpackage_tester.cpp b/tester/confeventpackage_tester.cpp index a0753694d..82d8adc3a 100644 --- a/tester/confeventpackage_tester.cpp +++ b/tester/confeventpackage_tester.cpp @@ -691,7 +691,6 @@ void send_added_notify(void) { LinphoneAddress *frankAddr = linphone_core_interpret_url(marie->lc, frankUri); Conference::Participant p1(bobAddr, false); Conference::Participant p2(aliceAddr, true); - Conference::Participant p3(frankAddr, false); LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "Conference"); string notify; @@ -772,7 +771,6 @@ void send_admined_notify(void) { LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); Conference::Participant p1(bobAddr, false); Conference::Participant p2(aliceAddr, true); - Conference::Participant p3(bobAddr, true); LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "Conference"); string notify; @@ -812,7 +810,6 @@ void send_unadmined_notify(void) { LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); Conference::Participant p1(bobAddr, false); Conference::Participant p2(aliceAddr, true); - Conference::Participant p3(aliceAddr, false); LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "Conference"); string notify; From 6a90b6371e576be2e480d2b460a0b62f63bf4606 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 10 Aug 2017 14:21:20 +0200 Subject: [PATCH 0010/2215] merge master --- CMakeLists.txt | 1 + coreapi/CMakeLists.txt | 41 +++------- coreapi/misc.c | 1 + coreapi/private.h | 21 ----- include/linphone/content.h | 22 ++++++ include/sal/sal.h | 6 +- src/CMakeLists.txt | 79 +++++++++++++++++++ .../local-conference-event-handler.cpp | 1 + .../remote-conference-event-handler.cpp | 1 + src/cpim/header/cpim-core-headers.h | 6 +- src/cpim/header/cpim-generic-header.cpp | 4 +- src/cpim/header/cpim-generic-header.h | 2 +- src/cpim/header/cpim-header-p.h | 1 + src/cpim/header/cpim-header.h | 2 +- src/cpim/message/cpim-message.cpp | 1 + src/cpim/message/cpim-message.h | 2 +- src/cpim/parser/cpim-parser.cpp | 1 + src/object/object-p.h | 41 ++++++++++ src/object/object.cpp | 33 ++++++++ src/object/object.h | 23 +----- src/object/singleton.h | 10 ++- src/utils/general.h | 18 +++++ tester/message_tester.c | 4 +- 23 files changed, 236 insertions(+), 85 deletions(-) create mode 100644 src/CMakeLists.txt create mode 100644 src/object/object-p.h create mode 100644 src/object/object.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d0ff54e5..17b86bbaa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -330,6 +330,7 @@ endif() add_subdirectory(include) add_subdirectory(java) +add_subdirectory(src) add_subdirectory(coreapi) add_subdirectory(share) if(ENABLE_CONSOLE_UI) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 06d84215d..905a521d9 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -33,24 +33,7 @@ if(ANDROID) find_package(Support REQUIRED) endif() - -set(LINPHONE_PRIVATE_HEADER_FILES - ../src/conference/conference-info.hxx - ../src/conference/conference-listener.h - ../src/conference/local-conference-event-handler.h - ../src/conference/remote-conference-event-handler.h - ../src/cpim/cpim.h - ../src/cpim/header/cpim-core-headers.h - ../src/cpim/header/cpim-generic-header.h - ../src/cpim/header/cpim-header-p.h - ../src/cpim/header/cpim-header.h - ../src/cpim/message/cpim-message.h - ../src/cpim/parser/cpim-grammar.h - ../src/cpim/parser/cpim-parser.h - ../src/object/object.h - ../src/object/singleton.h - ../src/utils/general.h - ../src/utils/utils.h +list(APPEND LINPHONE_PRIVATE_HEADER_FILES bellesip_sal/sal_impl.h carddav.h conference_private.h @@ -137,18 +120,8 @@ set(LINPHONE_SOURCE_FILES_C ) set(LINPHONE_SOURCE_FILES_CXX conference.cc - ../src/conference/conference-info.cxx - ../src/conference/local-conference-event-handler.cpp - ../src/conference/remote-conference-event-handler.cpp - ../src/cpim/header/cpim-core-headers.cpp - ../src/cpim/header/cpim-generic-header.cpp - ../src/cpim/header/cpim-header.cpp - ../src/cpim/message/cpim-message.cpp - ../src/cpim/parser/cpim-grammar.cpp - ../src/cpim/parser/cpim-parser.cpp - ../src/utils/utils.cpp ) -set(LINPHONE_INCLUDE_DIRS ${LINPHONE_INCLUDE_DIRS} /Users/reisbenjamin/xsd-4.0.0-i686-macosx/libxsd /usr/local/Cellar/xerces-c/3.1.4/include) +set(LINPHONE_INCLUDE_DIRS ${LINPHONE_INCLUDE_DIRS}) if(ANDROID) list(APPEND LINPHONE_SOURCE_FILES_CXX linphonecore_jni.cc) set_source_files_properties(linphonecore_jni.cc PROPERTIES COMPILE_DEFINITIONS "USE_JAVAH") @@ -233,7 +206,10 @@ bc_apply_compile_flags(LINPHONE_SOURCE_FILES_CXX STRICT_OPTIONS_CPP STRICT_OPTIO bc_apply_compile_flags(LINPHONE_SOURCE_FILES_OBJC STRICT_OPTIONS_CPP STRICT_OPTIONS_OBJC) if(ENABLE_STATIC) - add_library(linphone-static STATIC ${LINPHONE_HEADER_FILES} ${LINPHONE_PRIVATE_HEADER_FILES} ${LINPHONE_SOURCE_FILES_C} ${LINPHONE_SOURCE_FILES_CXX} ${LINPHONE_SOURCE_FILES_OBJC}) + add_library(linphone-static STATIC ${LINPHONE_HEADER_FILES} ${LINPHONE_PRIVATE_HEADER_FILES} + ${LINPHONE_SOURCE_FILES_C} ${LINPHONE_SOURCE_FILES_CXX} ${LINPHONE_SOURCE_FILES_OBJC} + $ + ) set_target_properties(linphone-static PROPERTIES OUTPUT_NAME linphone) add_dependencies(linphone-static liblinphone-git-version) target_include_directories(linphone-static PUBLIC ${LINPHONE_INCLUDE_DIRS}) @@ -250,7 +226,10 @@ if(ENABLE_STATIC) ) endif() if(ENABLE_SHARED) - add_library(linphone SHARED ${LINPHONE_HEADER_FILES} ${LINPHONE_PRIVATE_HEADER_FILES} ${LINPHONE_SOURCE_FILES_C} ${LINPHONE_SOURCE_FILES_CXX} ${LINPHONE_SOURCE_FILES_OBJC}) + add_library(linphone SHARED ${LINPHONE_HEADER_FILES} ${LINPHONE_PRIVATE_HEADER_FILES} + ${LINPHONE_SOURCE_FILES_C} ${LINPHONE_SOURCE_FILES_CXX} ${LINPHONE_SOURCE_FILES_OBJC} + $ + ) if(IOS) if(IOS) set(MIN_OS ${LINPHONE_IOS_DEPLOYMENT_TARGET}) diff --git a/coreapi/misc.c b/coreapi/misc.c index 6d0f4819f..fe10698aa 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -579,6 +579,7 @@ static const struct addrinfo * find_nat64_addrinfo(const struct addrinfo *ai) { static const struct addrinfo * find_ipv4_addrinfo(const struct addrinfo *ai) { while (ai != NULL) { if (ai->ai_family == AF_INET) break; + if (ai->ai_family == AF_INET6 && ai->ai_flags & AI_V4MAPPED) break; ai = ai->ai_next; } return ai; diff --git a/coreapi/private.h b/coreapi/private.h index a43cb2713..83d1d14c2 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -1946,27 +1946,6 @@ SalStreamDir sal_dir_from_call_params_dir(LinphoneMediaDirection cpdir); /***************************************************************************** * LINPHONE CONTENT PRIVATE ACCESSORS * ****************************************************************************/ -/** - * Get the key associated with a RCS file transfer message if encrypted - * @param[in] content LinphoneContent object. - * @return The key to encrypt/decrypt the file associated to this content. - */ -LINPHONE_PUBLIC const char *linphone_content_get_key(const LinphoneContent *content); - -/** - * Get the size of key associated with a RCS file transfer message if encrypted - * @param[in] content LinphoneContent object. - * @return The key size in bytes - */ -size_t linphone_content_get_key_size(const LinphoneContent *content); - -/** - * Set the key associated with a RCS file transfer message if encrypted - * @param[in] content LinphoneContent object. - * @param[in] key The key to be used to encrypt/decrypt file associated to this content. - * @param[in] keyLength The lengh of the key. - */ -void linphone_content_set_key(LinphoneContent *content, const char *key, const size_t keyLength); /** * Get the address of the crypto context associated with a RCS file transfer message if encrypted diff --git a/include/linphone/content.h b/include/linphone/content.h index c91a15559..653d4344a 100644 --- a/include/linphone/content.h +++ b/include/linphone/content.h @@ -192,6 +192,28 @@ LINPHONE_PUBLIC LinphoneContent * linphone_content_find_part_by_header(const Lin */ LINPHONE_PUBLIC const char * linphone_content_get_custom_header(const LinphoneContent *content, const char *header_name); +/** + * Get the key associated with a RCS file transfer message if encrypted + * @param[in] content LinphoneContent object. + * @return The key to encrypt/decrypt the file associated to this content. + */ +LINPHONE_PUBLIC const char *linphone_content_get_key(const LinphoneContent *content); + +/** + * Get the size of key associated with a RCS file transfer message if encrypted + * @param[in] content LinphoneContent object. + * @return The key size in bytes + */ +LINPHONE_PUBLIC size_t linphone_content_get_key_size(const LinphoneContent *content); + +/** + * Set the key associated with a RCS file transfer message if encrypted + * @param[in] content LinphoneContent object. + * @param[in] key The key to be used to encrypt/decrypt file associated to this content. + * @param[in] keyLength The lengh of the key. + */ +LINPHONE_PUBLIC void linphone_content_set_key(LinphoneContent *content, const char *key, const size_t keyLength); + /** * @} */ diff --git a/include/sal/sal.h b/include/sal/sal.h index 4a566e157..f41c09336 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -346,7 +346,7 @@ int sal_media_description_get_nb_active_streams(const SalMediaDescription *md); struct SalOpBase; typedef void (*SalOpReleaseCb)(struct SalOpBase *op); - + /*this structure must be at the first byte of the SalOp structure defined by implementors*/ typedef struct SalOpBase{ Sal *root; @@ -658,7 +658,7 @@ void sal_verify_server_certificates(Sal *ctx, bool_t verify); void sal_verify_server_cn(Sal *ctx, bool_t verify); void sal_set_ssl_config(Sal *ctx, void *ssl_config); LINPHONE_PUBLIC void sal_set_uuid(Sal*ctx, const char *uuid); -int sal_create_uuid(Sal*ctx, char *uuid, size_t len); +LINPHONE_PUBLIC int sal_create_uuid(Sal*ctx, char *uuid, size_t len); int sal_generate_uuid(char *uuid, size_t len); LINPHONE_PUBLIC void sal_enable_test_features(Sal*ctx, bool_t enabled); void sal_use_no_initial_route(Sal *ctx, bool_t enabled); @@ -963,5 +963,3 @@ int sal_get_http_proxy_port(const Sal *sal); #endif #endif - - diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 000000000..f86e48ea2 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,79 @@ +############################################################################ +# CMakeLists.txt +# Copyright (C) 2017 Belledonne Communications, Grenoble France +# +############################################################################ +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +############################################################################ + +set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES + conference/conference-info.hxx + conference/conference-listener.h + conference/local-conference-event-handler.h + conference/remote-conference-event-handler.h + cpim/cpim.h + cpim/header/cpim-core-headers.h + cpim/header/cpim-generic-header.h + cpim/header/cpim-header-p.h + cpim/header/cpim-header.h + cpim/message/cpim-message.h + cpim/parser/cpim-grammar.h + cpim/parser/cpim-parser.h + object/object.h + object/object-p.h + object/singleton.h + utils/general.h + utils/utils.h +) + +set(LINPHONE_CXX_OBJECTS_SOURCE_FILES + conference/conference-info.cxx + conference/local-conference-event-handler.cpp + conference/remote-conference-event-handler.cpp + cpim/header/cpim-core-headers.cpp + cpim/header/cpim-generic-header.cpp + cpim/header/cpim-header.cpp + cpim/message/cpim-message.cpp + cpim/parser/cpim-grammar.cpp + cpim/parser/cpim-parser.cpp + object/object.cpp + utils/utils.cpp +) + +set(LINPHONE_CXX_OBJECTS_DEFINITIONS "-DLIBLINPHONE_EXPORTS") +set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS} /Users/reisbenjamin/xsd-4.0.0-i686-macosx/libxsd /usr/local/Cellar/xerces-c/3.1.4/include) + +set(LINPHONE_PRIVATE_HEADER_FILES) +foreach(header ${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES}) + list(APPEND LINPHONE_PRIVATE_HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/${header}") +endforeach() +set(LINPHONE_PRIVATE_HEADER_FILES ${LINPHONE_PRIVATE_HEADER_FILES} PARENT_SCOPE) + +bc_apply_compile_flags(LINPHONE_CXX_OBJECTS_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX) + +if(ENABLE_STATIC) + add_library(linphone-cxx-objects-static OBJECT ${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES} ${LINPHONE_CXX_OBJECTS_SOURCE_FILES}) + target_compile_definitions(linphone-cxx-objects-static PRIVATE ${LINPHONE_CXX_OBJECTS_DEFINITIONS}) + target_include_directories(linphone-cxx-objects-static PRIVATE ${LINPHONE_CXX_OBJECTS_INCLUDE_DIRS} ${LINPHONE_INCLUDE_DIRS}) +endif() + +if(ENABLE_SHARED) + add_library(linphone-cxx-objects OBJECT ${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES} ${LINPHONE_CXX_OBJECTS_SOURCE_FILES}) + target_compile_definitions(linphone-cxx-objects PRIVATE ${LINPHONE_CXX_OBJECTS_DEFINITIONS}) + target_include_directories(linphone-cxx-objects PRIVATE ${LINPHONE_CXX_OBJECTS_INCLUDE_DIRS} ${LINPHONE_INCLUDE_DIRS}) + target_compile_options(linphone-cxx-objects PRIVATE "-fPIC") +endif() diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 3bde61970..09ff726fe 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -19,6 +19,7 @@ #include "local-conference-event-handler.h" #include "conference-info.hxx" #include "private.h" +#include "object/object-p.h" using namespace std; using namespace conference_info; diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 08ed76c36..71eb39026 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -19,6 +19,7 @@ #include "remote-conference-event-handler.h" #include "conference-info.hxx" #include "private.h" +#include "object/object-p.h" using namespace std; using namespace conference_info; diff --git a/src/cpim/header/cpim-core-headers.h b/src/cpim/header/cpim-core-headers.h index 965904908..3ff1deecd 100644 --- a/src/cpim/header/cpim-core-headers.h +++ b/src/cpim/header/cpim-core-headers.h @@ -24,7 +24,7 @@ // ============================================================================= #define MAKE_CORE_HEADER(CLASS_PREFIX, NAME) \ - class CLASS_PREFIX ## Header : public CoreHeader { \ + class LINPHONE_PUBLIC CLASS_PREFIX ## Header : public CoreHeader { \ public: \ CLASS_PREFIX ## Header() = default; \ inline std::string getName() const override { \ @@ -43,7 +43,7 @@ namespace LinphonePrivate { // Generic core header. // ------------------------------------------------------------------------- - class CoreHeader : public Header { + class LINPHONE_PUBLIC CoreHeader : public Header { friend class HeaderNode; public: @@ -79,7 +79,7 @@ namespace LinphonePrivate { class SubjectHeaderPrivate; - class SubjectHeader : public CoreHeader { + class LINPHONE_PUBLIC SubjectHeader : public CoreHeader { friend class HeaderNode; public: diff --git a/src/cpim/header/cpim-generic-header.cpp b/src/cpim/header/cpim-generic-header.cpp index 178cfbb27..6c043c55d 100644 --- a/src/cpim/header/cpim-generic-header.cpp +++ b/src/cpim/header/cpim-generic-header.cpp @@ -32,8 +32,10 @@ using namespace LinphonePrivate; class Cpim::GenericHeaderPrivate : public HeaderPrivate { public: + GenericHeaderPrivate () : parameters(make_shared > >()) {} + string name; - shared_ptr > > parameters = make_shared > >(); + shared_ptr > > parameters; }; Cpim::GenericHeader::GenericHeader () : Header(*new GenericHeaderPrivate) {} diff --git a/src/cpim/header/cpim-generic-header.h b/src/cpim/header/cpim-generic-header.h index fb1a198cf..94ced0e44 100644 --- a/src/cpim/header/cpim-generic-header.h +++ b/src/cpim/header/cpim-generic-header.h @@ -31,7 +31,7 @@ namespace LinphonePrivate { class GenericHeaderPrivate; class HeaderNode; - class GenericHeader : public Header { + class LINPHONE_PUBLIC GenericHeader : public Header { friend class HeaderNode; public: diff --git a/src/cpim/header/cpim-header-p.h b/src/cpim/header/cpim-header-p.h index 2e3208dd4..446e98647 100644 --- a/src/cpim/header/cpim-header-p.h +++ b/src/cpim/header/cpim-header-p.h @@ -20,6 +20,7 @@ #define _CPIM_HEADER_P_H_ #include "cpim-header.h" +#include "object/object-p.h" // ============================================================================= diff --git a/src/cpim/header/cpim-header.h b/src/cpim/header/cpim-header.h index 3dbcb2fbe..1839d3afa 100644 --- a/src/cpim/header/cpim-header.h +++ b/src/cpim/header/cpim-header.h @@ -29,7 +29,7 @@ namespace LinphonePrivate { namespace Cpim { class HeaderPrivate; - class Header : public Object { + class LINPHONE_PUBLIC Header : public Object { public: virtual ~Header () = default; diff --git a/src/cpim/message/cpim-message.cpp b/src/cpim/message/cpim-message.cpp index af1e06209..7eab6fea0 100644 --- a/src/cpim/message/cpim-message.cpp +++ b/src/cpim/message/cpim-message.cpp @@ -19,6 +19,7 @@ #include #include "cpim/parser/cpim-parser.h" +#include "object/object-p.h" #include "utils/utils.h" #include "cpim-message.h" diff --git a/src/cpim/message/cpim-message.h b/src/cpim/message/cpim-message.h index 2620fe336..fe8d0d03f 100644 --- a/src/cpim/message/cpim-message.h +++ b/src/cpim/message/cpim-message.h @@ -28,7 +28,7 @@ namespace LinphonePrivate { namespace Cpim { class MessagePrivate; - class Message : public Object { + class LINPHONE_PUBLIC Message : public Object { public: Message (); diff --git a/src/cpim/parser/cpim-parser.cpp b/src/cpim/parser/cpim-parser.cpp index 8d2a88e97..8c637fcb4 100644 --- a/src/cpim/parser/cpim-parser.cpp +++ b/src/cpim/parser/cpim-parser.cpp @@ -24,6 +24,7 @@ #include "linphone/core.h" #include "cpim-grammar.h" +#include "object/object-p.h" #include "utils/utils.h" #include "cpim-parser.h" diff --git a/src/object/object-p.h b/src/object/object-p.h new file mode 100644 index 000000000..f08a6b968 --- /dev/null +++ b/src/object/object-p.h @@ -0,0 +1,41 @@ +/* + * object-p.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _OBJECT_P_H_ +#define _OBJECT_P_H_ + +#include "utils/general.h" + +// ============================================================================= + +namespace LinphonePrivate { + class Object; + + class ObjectPrivate { + public: + virtual ~ObjectPrivate () = default; + + protected: + Object *mPublic = nullptr; + + private: + L_DECLARE_PUBLIC(Object); + }; +} + +#endif // ifndef _OBJECT_P_H_ diff --git a/src/object/object.cpp b/src/object/object.cpp new file mode 100644 index 000000000..a4c0a5a34 --- /dev/null +++ b/src/object/object.cpp @@ -0,0 +1,33 @@ +/* + * object.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "object-p.h" + +#include "object.h" + +using namespace LinphonePrivate; + +// ============================================================================= + +Object::~Object () { + delete mPrivate; +} + +Object::Object (ObjectPrivate &p) : mPrivate(&p) { + mPrivate->mPublic = this; +} diff --git a/src/object/object.h b/src/object/object.h index 76ae2d67f..5756bcc8e 100644 --- a/src/object/object.h +++ b/src/object/object.h @@ -24,29 +24,14 @@ // ============================================================================= namespace LinphonePrivate { - class Object; + class ObjectPrivate; - class ObjectPrivate { + class LINPHONE_PUBLIC Object { public: - virtual ~ObjectPrivate () = default; + virtual ~Object (); protected: - Object *mPublic = nullptr; - - private: - L_DECLARE_PUBLIC(Object); - }; - - class Object { - public: - virtual ~Object () { - delete mPrivate; - } - - protected: - explicit Object (ObjectPrivate &p) : mPrivate(&p) { - mPrivate->mPublic = this; - } + explicit Object (ObjectPrivate &p); ObjectPrivate *mPrivate = nullptr; diff --git a/src/object/singleton.h b/src/object/singleton.h index 6acad3c6d..16e16d471 100644 --- a/src/object/singleton.h +++ b/src/object/singleton.h @@ -30,8 +30,10 @@ namespace LinphonePrivate { virtual ~Singleton () = default; static T *getInstance () { - if (!mInstance) + if (!mInstance) { mInstance = new T(); + static SingletonDeleter deleter; + } return mInstance; } @@ -39,6 +41,12 @@ namespace LinphonePrivate { explicit Singleton (ObjectPrivate &p) : Object(p) {} private: + struct SingletonDeleter { + ~SingletonDeleter () { + delete mInstance; + } + }; + static T *mInstance; L_DISABLE_COPY(Singleton); diff --git a/src/utils/general.h b/src/utils/general.h index 0fc5afe6f..e0a8ed7f6 100644 --- a/src/utils/general.h +++ b/src/utils/general.h @@ -21,6 +21,24 @@ #ifndef _GENERAL_H_ #define _GENERAL_H_ +#ifndef LINPHONE_PUBLIC + #if defined(_MSC_VER) + #ifdef LINPHONE_STATIC + #define LINPHONE_PUBLIC + #else + #ifdef LINPHONE_EXPORTS + #define LINPHONE_PUBLIC __declspec(dllexport) + #else + #define LINPHONE_PUBLIC __declspec(dllimport) + #endif + #endif + #else + #define LINPHONE_PUBLIC + #endif +#endif + +// ----------------------------------------------------------------------------- + #define L_DECLARE_PRIVATE(CLASS) \ inline CLASS ## Private * getPrivate() { \ return reinterpret_cast(mPrivate); \ diff --git a/tester/message_tester.c b/tester/message_tester.c index c7a7156cb..cff9645fc 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -2492,12 +2492,12 @@ test_t message_tests[] = { }; static int message_tester_before_suite(void) { - liblinphone_tester_keep_uuid = TRUE; + //liblinphone_tester_keep_uuid = TRUE; return 0; } static int message_tester_after_suite(void) { - liblinphone_tester_keep_uuid = FALSE; + //liblinphone_tester_keep_uuid = FALSE; return 0; } From e1fb16defa3fe905ae5d3f5dbfaf90aa6eaaa7c8 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 14 Aug 2017 15:42:03 +0200 Subject: [PATCH 0011/2215] rearrange files --- .../local-conference-event-handler.cpp | 2 +- .../remote-conference-event-handler.cpp | 2 +- src/{conference => xml}/conference-info.cxx | 0 src/{conference => xml}/conference-info.hxx | 6 +- src/{conference => xml}/conference-info.xsd | 0 src/xml/xml.cxx | 451 ++++++++++++++++++ src/{conference => xml}/xml.hxx | 6 +- src/xml/xml.xsd | 287 +++++++++++ 8 files changed, 746 insertions(+), 8 deletions(-) rename src/{conference => xml}/conference-info.cxx (100%) rename src/{conference => xml}/conference-info.hxx (99%) rename src/{conference => xml}/conference-info.xsd (100%) create mode 100644 src/xml/xml.cxx rename src/{conference => xml}/xml.hxx (97%) create mode 100644 src/xml/xml.xsd diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 09ff726fe..7b49d5b7b 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -17,7 +17,7 @@ */ #include "local-conference-event-handler.h" -#include "conference-info.hxx" +#include "xml/conference-info.hxx" #include "private.h" #include "object/object-p.h" diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 71eb39026..4aa8561be 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -17,7 +17,7 @@ */ #include "remote-conference-event-handler.h" -#include "conference-info.hxx" +#include "xml/conference-info.hxx" #include "private.h" #include "object/object-p.h" diff --git a/src/conference/conference-info.cxx b/src/xml/conference-info.cxx similarity index 100% rename from src/conference/conference-info.cxx rename to src/xml/conference-info.cxx diff --git a/src/conference/conference-info.hxx b/src/xml/conference-info.hxx similarity index 99% rename from src/conference/conference-info.hxx rename to src/xml/conference-info.hxx index 45404038b..70cdb386e 100644 --- a/src/conference/conference-info.hxx +++ b/src/xml/conference-info.hxx @@ -31,8 +31,8 @@ // in the accompanying FLOSSE file. // -#ifndef CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_FLEXISIP_SRC_XML_CONFERENCE_INFO_HXX -#define CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_FLEXISIP_SRC_XML_CONFERENCE_INFO_HXX +#ifndef CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_LINPHONE_DESKTOP_SUBMODULES_LINPHONE_SRC_XML_CONFERENCE_INFO_HXX +#define CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_LINPHONE_DESKTOP_SUBMODULES_LINPHONE_SRC_XML_CONFERENCE_INFO_HXX #ifndef XSD_CXX11 #define XSD_CXX11 @@ -3859,4 +3859,4 @@ namespace conference_info // // End epilogue. -#endif // CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_FLEXISIP_SRC_XML_CONFERENCE_INFO_HXX +#endif // CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_LINPHONE_DESKTOP_SUBMODULES_LINPHONE_SRC_XML_CONFERENCE_INFO_HXX diff --git a/src/conference/conference-info.xsd b/src/xml/conference-info.xsd similarity index 100% rename from src/conference/conference-info.xsd rename to src/xml/conference-info.xsd diff --git a/src/xml/xml.cxx b/src/xml/xml.cxx new file mode 100644 index 000000000..be2199c9d --- /dev/null +++ b/src/xml/xml.cxx @@ -0,0 +1,451 @@ +// Copyright (c) 2005-2014 Code Synthesis Tools CC +// +// This program was generated by CodeSynthesis XSD, an XML Schema to +// C++ data binding compiler. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// 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 St, Fifth Floor, Boston, MA 02110-1301 USA +// +// In addition, as a special exception, Code Synthesis Tools CC gives +// permission to link this program with the Xerces-C++ library (or with +// modified versions of Xerces-C++ that use the same license as Xerces-C++), +// and distribute linked combinations including the two. You must obey +// the GNU General Public License version 2 in all respects for all of +// the code used other than Xerces-C++. If you modify this copy of the +// program, you may extend this exception to your version of the program, +// but you are not obligated to do so. If you do not wish to do so, delete +// this exception statement from your version. +// +// Furthermore, Code Synthesis Tools CC makes a special exception for +// the Free/Libre and Open Source Software (FLOSS) which is described +// in the accompanying FLOSSE file. +// + +// Begin prologue. +// +// +// End prologue. + +#include + +#include "xml.hxx" + +namespace namespace_ +{ + // Lang + // + + Lang:: + Lang (const char* s) + : ::xml_schema::String (s) + { + } + + Lang:: + Lang (const ::std::string& s) + : ::xml_schema::String (s) + { + } + + Lang:: + Lang (const Lang& o, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (o, f, c) + { + } + + // Space + // + + Space:: + Space (Value v) + : ::xml_schema::Ncname (_xsd_Space_literals_[v]) + { + } + + Space:: + Space (const char* v) + : ::xml_schema::Ncname (v) + { + } + + Space:: + Space (const ::std::string& v) + : ::xml_schema::Ncname (v) + { + } + + Space:: + Space (const ::xml_schema::Ncname& v) + : ::xml_schema::Ncname (v) + { + } + + Space:: + Space (const Space& v, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Ncname (v, f, c) + { + } + + Space& Space:: + operator= (Value v) + { + static_cast< ::xml_schema::Ncname& > (*this) = + ::xml_schema::Ncname (_xsd_Space_literals_[v]); + + return *this; + } + + + // Lang_member + // + + Lang_member:: + Lang_member (Value v) + : ::xml_schema::String (_xsd_Lang_member_literals_[v]) + { + } + + Lang_member:: + Lang_member (const char* v) + : ::xml_schema::String (v) + { + } + + Lang_member:: + Lang_member (const ::std::string& v) + : ::xml_schema::String (v) + { + } + + Lang_member:: + Lang_member (const ::xml_schema::String& v) + : ::xml_schema::String (v) + { + } + + Lang_member:: + Lang_member (const Lang_member& v, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (v, f, c) + { + } + + Lang_member& Lang_member:: + operator= (Value v) + { + static_cast< ::xml_schema::String& > (*this) = + ::xml_schema::String (_xsd_Lang_member_literals_[v]); + + return *this; + } +} + +#include + +#include + +namespace namespace_ +{ + // Lang + // + + Lang:: + Lang (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (e, f, c) + { + } + + Lang:: + Lang (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (a, f, c) + { + } + + Lang:: + Lang (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (s, e, f, c) + { + } + + Lang* Lang:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Lang (*this, f, c); + } + + // Space + // + + Space:: + Space (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Ncname (e, f, c) + { + _xsd_Space_convert (); + } + + Space:: + Space (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Ncname (a, f, c) + { + _xsd_Space_convert (); + } + + Space:: + Space (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Ncname (s, e, f, c) + { + _xsd_Space_convert (); + } + + Space* Space:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Space (*this, f, c); + } + + Space::Value Space:: + _xsd_Space_convert () const + { + ::xsd::cxx::tree::enum_comparator< char > c (_xsd_Space_literals_); + const Value* i (::std::lower_bound ( + _xsd_Space_indexes_, + _xsd_Space_indexes_ + 2, + *this, + c)); + + if (i == _xsd_Space_indexes_ + 2 || _xsd_Space_literals_[*i] != *this) + { + throw ::xsd::cxx::tree::unexpected_enumerator < char > (*this); + } + + return *i; + } + + const char* const Space:: + _xsd_Space_literals_[2] = + { + "default", + "preserve" + }; + + const Space::Value Space:: + _xsd_Space_indexes_[2] = + { + ::namespace_::Space::default_, + ::namespace_::Space::preserve + }; + + // Lang_member + // + + Lang_member:: + Lang_member (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (e, f, c) + { + _xsd_Lang_member_convert (); + } + + Lang_member:: + Lang_member (const ::xercesc::DOMAttr& a, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (a, f, c) + { + _xsd_Lang_member_convert (); + } + + Lang_member:: + Lang_member (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (s, e, f, c) + { + _xsd_Lang_member_convert (); + } + + Lang_member* Lang_member:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Lang_member (*this, f, c); + } + + Lang_member::Value Lang_member:: + _xsd_Lang_member_convert () const + { + ::xsd::cxx::tree::enum_comparator< char > c (_xsd_Lang_member_literals_); + const Value* i (::std::lower_bound ( + _xsd_Lang_member_indexes_, + _xsd_Lang_member_indexes_ + 1, + *this, + c)); + + if (i == _xsd_Lang_member_indexes_ + 1 || _xsd_Lang_member_literals_[*i] != *this) + { + throw ::xsd::cxx::tree::unexpected_enumerator < char > (*this); + } + + return *i; + } + + const char* const Lang_member:: + _xsd_Lang_member_literals_[1] = + { + "" + }; + + const Lang_member::Value Lang_member:: + _xsd_Lang_member_indexes_[1] = + { + ::namespace_::Lang_member::empty + }; +} + +#include + +namespace namespace_ +{ + ::std::ostream& + operator<< (::std::ostream& o, const Lang& i) + { + return o << static_cast< const ::xml_schema::String& > (i); + } + + ::std::ostream& + operator<< (::std::ostream& o, Space::Value i) + { + return o << Space::_xsd_Space_literals_[i]; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Space& i) + { + return o << static_cast< const ::xml_schema::Ncname& > (i); + } + + ::std::ostream& + operator<< (::std::ostream& o, Lang_member::Value i) + { + return o << Lang_member::_xsd_Lang_member_literals_[i]; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Lang_member& i) + { + return o << static_cast< const ::xml_schema::String& > (i); + } +} + +#include +#include +#include + +namespace namespace_ +{ +} + +#include +#include +#include + +namespace namespace_ +{ + void + operator<< (::xercesc::DOMElement& e, const Lang& i) + { + e << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xercesc::DOMAttr& a, const Lang& i) + { + a << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xml_schema::ListStream& l, + const Lang& i) + { + l << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xercesc::DOMElement& e, const Space& i) + { + e << static_cast< const ::xml_schema::Ncname& > (i); + } + + void + operator<< (::xercesc::DOMAttr& a, const Space& i) + { + a << static_cast< const ::xml_schema::Ncname& > (i); + } + + void + operator<< (::xml_schema::ListStream& l, + const Space& i) + { + l << static_cast< const ::xml_schema::Ncname& > (i); + } + + void + operator<< (::xercesc::DOMElement& e, const Lang_member& i) + { + e << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xercesc::DOMAttr& a, const Lang_member& i) + { + a << static_cast< const ::xml_schema::String& > (i); + } + + void + operator<< (::xml_schema::ListStream& l, + const Lang_member& i) + { + l << static_cast< const ::xml_schema::String& > (i); + } +} + +#include + +// Begin epilogue. +// +// +// End epilogue. + diff --git a/src/conference/xml.hxx b/src/xml/xml.hxx similarity index 97% rename from src/conference/xml.hxx rename to src/xml/xml.hxx index 52de06acf..d63650f40 100644 --- a/src/conference/xml.hxx +++ b/src/xml/xml.hxx @@ -31,8 +31,8 @@ // in the accompanying FLOSSE file. // -#ifndef CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_FLEXISIP_PRIVATE_SRC_XML_XML_HXX -#define CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_FLEXISIP_PRIVATE_SRC_XML_XML_HXX +#ifndef CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_LINPHONE_DESKTOP_SUBMODULES_LINPHONE_SRC_XML_XML_HXX +#define CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_LINPHONE_DESKTOP_SUBMODULES_LINPHONE_SRC_XML_XML_HXX #ifndef XSD_CXX11 #define XSD_CXX11 @@ -500,4 +500,4 @@ namespace namespace_ // // End epilogue. -#endif // CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_FLEXISIP_PRIVATE_SRC_XML_XML_HXX +#endif // CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_LINPHONE_DESKTOP_SUBMODULES_LINPHONE_SRC_XML_XML_HXX diff --git a/src/xml/xml.xsd b/src/xml/xml.xsd new file mode 100644 index 000000000..aea7d0db0 --- /dev/null +++ b/src/xml/xml.xsd @@ -0,0 +1,287 @@ + + + + + + +
+

About the XML namespace

+ +
+

+ This schema document describes the XML namespace, in a form + suitable for import by other schema documents. +

+

+ See + http://www.w3.org/XML/1998/namespace.html and + + http://www.w3.org/TR/REC-xml for information + about this namespace. +

+

+ Note that local names in this namespace are intended to be + defined only by the World Wide Web Consortium or its subgroups. + The names currently defined in this namespace are listed below. + They should not be used with conflicting semantics by any Working + Group, specification, or document instance. +

+

+ See further below in this document for more information about how to refer to this schema document from your own + XSD schema documents and about the + namespace-versioning policy governing this schema document. +

+
+
+
+
+ + + + +
+ +

lang (as an attribute name)

+

+ denotes an attribute whose value + is a language code for the natural language of the content of + any element; its value is inherited. This name is reserved + by virtue of its definition in the XML specification.

+ +
+
+

Notes

+

+ Attempting to install the relevant ISO 2- and 3-letter + codes as the enumerated possible values is probably never + going to be a realistic possibility. +

+

+ See BCP 47 at + http://www.rfc-editor.org/rfc/bcp/bcp47.txt + and the IANA language subtag registry at + + http://www.iana.org/assignments/language-subtag-registry + for further information. +

+

+ The union allows for the 'un-declaration' of xml:lang with + the empty string. +

+
+
+
+ + + + + + + + + +
+ + + + +
+ +

space (as an attribute name)

+

+ denotes an attribute whose + value is a keyword indicating what whitespace processing + discipline is intended for the content of the element; its + value is inherited. This name is reserved by virtue of its + definition in the XML specification.

+ +
+
+
+ + + + + + +
+ + + +
+ +

base (as an attribute name)

+

+ denotes an attribute whose value + provides a URI to be used as the base for interpreting any + relative URIs in the scope of the element on which it + appears; its value is inherited. This name is reserved + by virtue of its definition in the XML Base specification.

+ +

+ See http://www.w3.org/TR/xmlbase/ + for information about this attribute. +

+
+
+
+
+ + + + +
+ +

id (as an attribute name)

+

+ denotes an attribute whose value + should be interpreted as if declared to be of type ID. + This name is reserved by virtue of its definition in the + xml:id specification.

+ +

+ See http://www.w3.org/TR/xml-id/ + for information about this attribute. +

+
+
+
+
+ + + + + + + + + + +
+ +

Father (in any context at all)

+ +
+

+ denotes Jon Bosak, the chair of + the original XML Working Group. This name is reserved by + the following decision of the W3C XML Plenary and + XML Coordination groups: +

+
+

+ In appreciation for his vision, leadership and + dedication the W3C XML Plenary on this 10th day of + February, 2000, reserves for Jon Bosak in perpetuity + the XML name "xml:Father". +

+
+
+
+
+
+ + + +
+

About this schema document

+ +
+

+ This schema defines attributes and an attribute group suitable + for use by schemas wishing to allow xml:base, + xml:lang, xml:space or + xml:id attributes on elements they define. +

+

+ To enable this, such a schema must import this schema for + the XML namespace, e.g. as follows: +

+
+          <schema . . .>
+           . . .
+           <import namespace="http://www.w3.org/XML/1998/namespace"
+                      schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+     
+

+ or +

+
+           <import namespace="http://www.w3.org/XML/1998/namespace"
+                      schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
+     
+

+ Subsequently, qualified reference to any of the attributes or the + group defined below will have the desired effect, e.g. +

+
+          <type . . .>
+           . . .
+           <attributeGroup ref="xml:specialAttrs"/>
+     
+

+ will define a type which will schema-validate an instance element + with any of those attributes. +

+
+
+
+
+ + + +
+

Versioning policy for this schema document

+
+

+ In keeping with the XML Schema WG's standard versioning + policy, this schema document will persist at + + http://www.w3.org/2009/01/xml.xsd. +

+

+ At the date of issue it can also be found at + + http://www.w3.org/2001/xml.xsd. +

+

+ The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML + Schema itself, or with the XML namespace itself. In other words, + if the XML Schema or XML namespaces change, the version of this + document at + http://www.w3.org/2001/xml.xsd + + will change accordingly; the version at + + http://www.w3.org/2009/01/xml.xsd + + will not change. +

+

+ Previous dated (and unchanging) versions of this schema + document are at: +

+ +
+
+
+
+ +
+ From c681332e72b3a10a2ee1baa0fbd66acbedd524be Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 14 Aug 2017 15:41:59 +0200 Subject: [PATCH 0012/2215] Correctly locate libxsd. --- CMakeLists.txt | 1 + coreapi/CMakeLists.txt | 2 +- src/CMakeLists.txt | 2 +- src/conference/local-conference-event-handler.h | 3 ++- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 17b86bbaa..2625c0acd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,6 +124,7 @@ else() find_package(Belr REQUIRED) endif() find_package(XML2 REQUIRED) +find_package(LibXsd REQUIRED) find_package(Zlib) if(ENABLE_TUNNEL) if(LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 905a521d9..8d926a907 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -158,7 +158,7 @@ set(LIBS ${ORTP_LIBRARIES} ${XML2_LIBRARIES} ${BELR_LIBRARIES} - /usr/local/Cellar/xerces-c/3.1.4/lib/libxerces-c.dylib + ${LIBXSD_LIBRARIES} ) if(WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") list(APPEND LIBS "Ws2_32") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f86e48ea2..8ed54e447 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -55,7 +55,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES ) set(LINPHONE_CXX_OBJECTS_DEFINITIONS "-DLIBLINPHONE_EXPORTS") -set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS} /Users/reisbenjamin/xsd-4.0.0-i686-macosx/libxsd /usr/local/Cellar/xerces-c/3.1.4/include) +set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS} ${LIBXSD_INCLUDE_DIRS}) set(LINPHONE_PRIVATE_HEADER_FILES) foreach(header ${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES}) diff --git a/src/conference/local-conference-event-handler.h b/src/conference/local-conference-event-handler.h index 4dd08d1e5..7a803ba84 100644 --- a/src/conference/local-conference-event-handler.h +++ b/src/conference/local-conference-event-handler.h @@ -20,6 +20,7 @@ #define _LOCAL_CONFERENCE_EVENT_HANDLER_H_ #include +#include #include #include @@ -122,4 +123,4 @@ const LinphoneAddress* LinphonePrivate::Conference::Participant::getAddress() co return mAddr; } -#endif // ifndef _LOCAL_CONFERENCE_EVENT_HANDLER_H_ \ No newline at end of file +#endif // ifndef _LOCAL_CONFERENCE_EVENT_HANDLER_H_ From 8c54a0e85d9abdafd82795a0459a54f14e7eb2d6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 14 Aug 2017 16:49:00 +0200 Subject: [PATCH 0013/2215] Fix naming of files generated by xsd. --- src/CMakeLists.txt | 9 +++++++-- src/conference/local-conference-event-handler.cpp | 2 +- src/conference/remote-conference-event-handler.cpp | 2 +- src/xml/{conference-info.cxx => conference-info.cpp} | 2 +- src/xml/{conference-info.hxx => conference-info.h} | 8 ++++---- src/xml/{xml.cxx => xml.cpp} | 2 +- src/xml/{xml.hxx => xml.h} | 6 +++--- 7 files changed, 18 insertions(+), 13 deletions(-) rename src/xml/{conference-info.cxx => conference-info.cpp} (99%) rename src/xml/{conference-info.hxx => conference-info.h} (99%) rename src/xml/{xml.cxx => xml.cpp} (99%) rename src/xml/{xml.hxx => xml.h} (97%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8ed54e447..dc8c3dc3f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,7 +21,6 @@ ############################################################################ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES - conference/conference-info.hxx conference/conference-listener.h conference/local-conference-event-handler.h conference/remote-conference-event-handler.h @@ -38,10 +37,11 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES object/singleton.h utils/general.h utils/utils.h + xml/conference-info.h + xml/xml.h ) set(LINPHONE_CXX_OBJECTS_SOURCE_FILES - conference/conference-info.cxx conference/local-conference-event-handler.cpp conference/remote-conference-event-handler.cpp cpim/header/cpim-core-headers.cpp @@ -52,8 +52,13 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES cpim/parser/cpim-parser.cpp object/object.cpp utils/utils.cpp + xml/conference-info.cpp + xml/xml.cpp ) +ADD_XSD_WRAPPERS(xml/xml "XML XSD - xml.xsd") +ADD_XSD_WRAPPERS(xml/conference-info "Conference info XSD - conference-info.xsd") + set(LINPHONE_CXX_OBJECTS_DEFINITIONS "-DLIBLINPHONE_EXPORTS") set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS} ${LIBXSD_INCLUDE_DIRS}) diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 7b49d5b7b..a0ccca42a 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -17,7 +17,7 @@ */ #include "local-conference-event-handler.h" -#include "xml/conference-info.hxx" +#include "xml/conference-info.h" #include "private.h" #include "object/object-p.h" diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 4aa8561be..879d40c4a 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -17,7 +17,7 @@ */ #include "remote-conference-event-handler.h" -#include "xml/conference-info.hxx" +#include "xml/conference-info.h" #include "private.h" #include "object/object-p.h" diff --git a/src/xml/conference-info.cxx b/src/xml/conference-info.cpp similarity index 99% rename from src/xml/conference-info.cxx rename to src/xml/conference-info.cpp index d43cb20d0..228e2fb9d 100644 --- a/src/xml/conference-info.cxx +++ b/src/xml/conference-info.cpp @@ -38,7 +38,7 @@ #include -#include "conference-info.hxx" +#include "conference-info.h" namespace conference_info { diff --git a/src/xml/conference-info.hxx b/src/xml/conference-info.h similarity index 99% rename from src/xml/conference-info.hxx rename to src/xml/conference-info.h index 70cdb386e..1626d55e3 100644 --- a/src/xml/conference-info.hxx +++ b/src/xml/conference-info.h @@ -31,8 +31,8 @@ // in the accompanying FLOSSE file. // -#ifndef CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_LINPHONE_DESKTOP_SUBMODULES_LINPHONE_SRC_XML_CONFERENCE_INFO_HXX -#define CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_LINPHONE_DESKTOP_SUBMODULES_LINPHONE_SRC_XML_CONFERENCE_INFO_HXX +#ifndef XML_CONFERENCE_INFO_H +#define XML_CONFERENCE_INFO_H #ifndef XSD_CXX11 #define XSD_CXX11 @@ -299,7 +299,7 @@ namespace conference_info #include -#include "xml.hxx" +#include "xml.h" namespace conference_info { @@ -3859,4 +3859,4 @@ namespace conference_info // // End epilogue. -#endif // CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_LINPHONE_DESKTOP_SUBMODULES_LINPHONE_SRC_XML_CONFERENCE_INFO_HXX +#endif // XML_CONFERENCE_INFO_H diff --git a/src/xml/xml.cxx b/src/xml/xml.cpp similarity index 99% rename from src/xml/xml.cxx rename to src/xml/xml.cpp index be2199c9d..5be074eb8 100644 --- a/src/xml/xml.cxx +++ b/src/xml/xml.cpp @@ -38,7 +38,7 @@ #include -#include "xml.hxx" +#include "xml.h" namespace namespace_ { diff --git a/src/xml/xml.hxx b/src/xml/xml.h similarity index 97% rename from src/xml/xml.hxx rename to src/xml/xml.h index d63650f40..916ef8807 100644 --- a/src/xml/xml.hxx +++ b/src/xml/xml.h @@ -31,8 +31,8 @@ // in the accompanying FLOSSE file. // -#ifndef CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_LINPHONE_DESKTOP_SUBMODULES_LINPHONE_SRC_XML_XML_HXX -#define CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_LINPHONE_DESKTOP_SUBMODULES_LINPHONE_SRC_XML_XML_HXX +#ifndef XML_XML_H +#define XML_XML_H #ifndef XSD_CXX11 #define XSD_CXX11 @@ -500,4 +500,4 @@ namespace namespace_ // // End epilogue. -#endif // CXX_USERS_REISBENJAMIN_DEVELOPPEMENT_LINPHONE_DESKTOP_SUBMODULES_LINPHONE_SRC_XML_XML_HXX +#endif // XML_XML_H From 37b9abe75931681e82bd72b12cd730d3b6f6c0bc Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 28 Aug 2017 15:49:09 +0200 Subject: [PATCH 0014/2215] libxsd temporary optionnal --- CMakeLists.txt | 2 +- coreapi/CMakeLists.txt | 4 +++- src/CMakeLists.txt | 13 +++++++++---- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 24d225847..8c52f90f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,7 +133,7 @@ else() find_package(Belr REQUIRED) endif() find_package(XML2 REQUIRED) -find_package(LibXsd REQUIRED) +find_package(LibXsd) find_package(Soci) find_package(Zlib) if(ENABLE_TUNNEL) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 88c78b589..61a84cb91 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -158,7 +158,6 @@ set(LIBS ${ORTP_LIBRARIES} ${XML2_LIBRARIES} ${BELR_LIBRARIES} - ${LIBXSD_LIBRARIES} ) if(WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") list(APPEND LIBS "Ws2_32") @@ -169,6 +168,9 @@ endif() if(ZLIB_FOUND) list(APPEND LIBS ${ZLIB_LIBRARIES}) endif() +if(LIBXSD_FOUND) + list(APPEND LIBS ${LIBXSD_LIBRARIES}) +endif() if(SOCI_FOUND) list(APPEND LIBS ${SOCI_LIBRARIES}) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4b064d20e..3210f9861 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -89,14 +89,19 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES xml/conference-info.cpp xml/xml.cpp ) +if(LIBXSD_FOUND) + ADD_XSD_WRAPPERS(xml/xml "XML XSD - xml.xsd") + ADD_XSD_WRAPPERS(xml/conference-info "Conference info XSD - conference-info.xsd") +endif() -ADD_XSD_WRAPPERS(xml/xml "XML XSD - xml.xsd") -ADD_XSD_WRAPPERS(xml/conference-info "Conference info XSD - conference-info.xsd") - -set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS} ${LIBXSD_INCLUDE_DIRS}) +set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS}) set(LINPHONE_CXX_OBJECTS_DEFINITIONS "-DLIBLINPHONE_EXPORTS") set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS}) +if(LIBXSD_FOUND) + list(APPEND LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${LIBXSD_INCLUDE_DIRS}) +endif() + if(SOCI_FOUND) list(APPEND LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${SOCI_INCLUDE_DIRS} ${SOCI_MYSQL_INCLUDES}) add_definitions(-DSOCI_ENABLED) From 621385d2217bf214138522e5da97927cfbd3c1c9 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 28 Aug 2017 15:50:06 +0200 Subject: [PATCH 0015/2215] Revert "libxsd temporary optionnal" This reverts commit 37b9abe75931681e82bd72b12cd730d3b6f6c0bc. --- CMakeLists.txt | 2 +- coreapi/CMakeLists.txt | 4 +--- src/CMakeLists.txt | 13 ++++--------- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c52f90f5..24d225847 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,7 +133,7 @@ else() find_package(Belr REQUIRED) endif() find_package(XML2 REQUIRED) -find_package(LibXsd) +find_package(LibXsd REQUIRED) find_package(Soci) find_package(Zlib) if(ENABLE_TUNNEL) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 61a84cb91..88c78b589 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -158,6 +158,7 @@ set(LIBS ${ORTP_LIBRARIES} ${XML2_LIBRARIES} ${BELR_LIBRARIES} + ${LIBXSD_LIBRARIES} ) if(WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") list(APPEND LIBS "Ws2_32") @@ -168,9 +169,6 @@ endif() if(ZLIB_FOUND) list(APPEND LIBS ${ZLIB_LIBRARIES}) endif() -if(LIBXSD_FOUND) - list(APPEND LIBS ${LIBXSD_LIBRARIES}) -endif() if(SOCI_FOUND) list(APPEND LIBS ${SOCI_LIBRARIES}) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3210f9861..4b064d20e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -89,19 +89,14 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES xml/conference-info.cpp xml/xml.cpp ) -if(LIBXSD_FOUND) - ADD_XSD_WRAPPERS(xml/xml "XML XSD - xml.xsd") - ADD_XSD_WRAPPERS(xml/conference-info "Conference info XSD - conference-info.xsd") -endif() -set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS}) +ADD_XSD_WRAPPERS(xml/xml "XML XSD - xml.xsd") +ADD_XSD_WRAPPERS(xml/conference-info "Conference info XSD - conference-info.xsd") + +set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS} ${LIBXSD_INCLUDE_DIRS}) set(LINPHONE_CXX_OBJECTS_DEFINITIONS "-DLIBLINPHONE_EXPORTS") set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS}) -if(LIBXSD_FOUND) - list(APPEND LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${LIBXSD_INCLUDE_DIRS}) -endif() - if(SOCI_FOUND) list(APPEND LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${SOCI_INCLUDE_DIRS} ${SOCI_MYSQL_INCLUDES}) add_definitions(-DSOCI_ENABLED) From c43454cbc929beac7c2c76821392f82e04c357f6 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 29 Aug 2017 11:20:26 +0200 Subject: [PATCH 0016/2215] add resource-lists.xsd --- src/CMakeLists.txt | 1 + src/xml/resource-lists.xsd | 81 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 src/xml/resource-lists.xsd diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4b064d20e..679599314 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -92,6 +92,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES ADD_XSD_WRAPPERS(xml/xml "XML XSD - xml.xsd") ADD_XSD_WRAPPERS(xml/conference-info "Conference info XSD - conference-info.xsd") +ADD_XSD_WRAPPERS(xml/resource-lists "Resourece lists XSD - resource-lists.xsd") set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS} ${LIBXSD_INCLUDE_DIRS}) set(LINPHONE_CXX_OBJECTS_DEFINITIONS "-DLIBLINPHONE_EXPORTS") diff --git a/src/xml/resource-lists.xsd b/src/xml/resource-lists.xsd new file mode 100644 index 000000000..c4884db55 --- /dev/null +++ b/src/xml/resource-lists.xsd @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 4ca48b6162698edc88b68a8acf5752798ee48574 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 29 Aug 2017 15:42:01 +0200 Subject: [PATCH 0017/2215] add resource-lists generated API --- src/xml/resource-lists.cpp | 2451 ++++++++++++++++++++++++++++++++++++ src/xml/resource-lists.h | 1254 ++++++++++++++++++ 2 files changed, 3705 insertions(+) create mode 100644 src/xml/resource-lists.cpp create mode 100644 src/xml/resource-lists.h diff --git a/src/xml/resource-lists.cpp b/src/xml/resource-lists.cpp new file mode 100644 index 000000000..0f94f63c0 --- /dev/null +++ b/src/xml/resource-lists.cpp @@ -0,0 +1,2451 @@ +// Copyright (c) 2005-2014 Code Synthesis Tools CC +// +// This program was generated by CodeSynthesis XSD, an XML Schema to +// C++ data binding compiler. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// 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 St, Fifth Floor, Boston, MA 02110-1301 USA +// +// In addition, as a special exception, Code Synthesis Tools CC gives +// permission to link this program with the Xerces-C++ library (or with +// modified versions of Xerces-C++ that use the same license as Xerces-C++), +// and distribute linked combinations including the two. You must obey +// the GNU General Public License version 2 in all respects for all of +// the code used other than Xerces-C++. If you modify this copy of the +// program, you may extend this exception to your version of the program, +// but you are not obligated to do so. If you do not wish to do so, delete +// this exception statement from your version. +// +// Furthermore, Code Synthesis Tools CC makes a special exception for +// the Free/Libre and Open Source Software (FLOSS) which is described +// in the accompanying FLOSSE file. +// + +// Begin prologue. +// +// +// End prologue. + +#include + +#include "resource-lists.h" + +namespace resource_lists +{ + // ListType + // + + const ListType::Display_nameOptional& ListType:: + getDisplay_name () const + { + return this->display_name_; + } + + ListType::Display_nameOptional& ListType:: + getDisplay_name () + { + return this->display_name_; + } + + void ListType:: + setDisplay_name (const Display_nameType& x) + { + this->display_name_.set (x); + } + + void ListType:: + setDisplay_name (const Display_nameOptional& x) + { + this->display_name_ = x; + } + + void ListType:: + setDisplay_name (::std::unique_ptr< Display_nameType > x) + { + this->display_name_.set (std::move (x)); + } + + const ListType::ListSequence& ListType:: + getList () const + { + return this->list_; + } + + ListType::ListSequence& ListType:: + getList () + { + return this->list_; + } + + void ListType:: + setList (const ListSequence& s) + { + this->list_ = s; + } + + const ListType::ExternalSequence& ListType:: + getExternal () const + { + return this->external_; + } + + ListType::ExternalSequence& ListType:: + getExternal () + { + return this->external_; + } + + void ListType:: + setExternal (const ExternalSequence& s) + { + this->external_ = s; + } + + const ListType::EntrySequence& ListType:: + getEntry () const + { + return this->entry_; + } + + ListType::EntrySequence& ListType:: + getEntry () + { + return this->entry_; + } + + void ListType:: + setEntry (const EntrySequence& s) + { + this->entry_ = s; + } + + const ListType::Entry_refSequence& ListType:: + getEntry_ref () const + { + return this->entry_ref_; + } + + ListType::Entry_refSequence& ListType:: + getEntry_ref () + { + return this->entry_ref_; + } + + void ListType:: + setEntry_ref (const Entry_refSequence& s) + { + this->entry_ref_ = s; + } + + const ListType::AnySequence& ListType:: + getAny () const + { + return this->any_; + } + + ListType::AnySequence& ListType:: + getAny () + { + return this->any_; + } + + void ListType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const ListType::NameOptional& ListType:: + getName () const + { + return this->name_; + } + + ListType::NameOptional& ListType:: + getName () + { + return this->name_; + } + + void ListType:: + setName (const NameType& x) + { + this->name_.set (x); + } + + void ListType:: + setName (const NameOptional& x) + { + this->name_ = x; + } + + void ListType:: + setName (::std::unique_ptr< NameType > x) + { + this->name_.set (std::move (x)); + } + + const ListType::AnyAttributeSet& ListType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + ListType::AnyAttributeSet& ListType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void ListType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& ListType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& ListType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // EntryType + // + + const EntryType::Display_nameOptional& EntryType:: + getDisplay_name () const + { + return this->display_name_; + } + + EntryType::Display_nameOptional& EntryType:: + getDisplay_name () + { + return this->display_name_; + } + + void EntryType:: + setDisplay_name (const Display_nameType& x) + { + this->display_name_.set (x); + } + + void EntryType:: + setDisplay_name (const Display_nameOptional& x) + { + this->display_name_ = x; + } + + void EntryType:: + setDisplay_name (::std::unique_ptr< Display_nameType > x) + { + this->display_name_.set (std::move (x)); + } + + const EntryType::AnySequence& EntryType:: + getAny () const + { + return this->any_; + } + + EntryType::AnySequence& EntryType:: + getAny () + { + return this->any_; + } + + void EntryType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const EntryType::UriType& EntryType:: + getUri () const + { + return this->uri_.get (); + } + + EntryType::UriType& EntryType:: + getUri () + { + return this->uri_.get (); + } + + void EntryType:: + setUri (const UriType& x) + { + this->uri_.set (x); + } + + void EntryType:: + setUri (::std::unique_ptr< UriType > x) + { + this->uri_.set (std::move (x)); + } + + ::std::unique_ptr< EntryType::UriType > EntryType:: + detachUri () + { + return this->uri_.detach (); + } + + const EntryType::AnyAttributeSet& EntryType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + EntryType::AnyAttributeSet& EntryType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void EntryType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& EntryType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& EntryType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // Entry_refType + // + + const Entry_refType::Display_nameOptional& Entry_refType:: + getDisplay_name () const + { + return this->display_name_; + } + + Entry_refType::Display_nameOptional& Entry_refType:: + getDisplay_name () + { + return this->display_name_; + } + + void Entry_refType:: + setDisplay_name (const Display_nameType& x) + { + this->display_name_.set (x); + } + + void Entry_refType:: + setDisplay_name (const Display_nameOptional& x) + { + this->display_name_ = x; + } + + void Entry_refType:: + setDisplay_name (::std::unique_ptr< Display_nameType > x) + { + this->display_name_.set (std::move (x)); + } + + const Entry_refType::AnySequence& Entry_refType:: + getAny () const + { + return this->any_; + } + + Entry_refType::AnySequence& Entry_refType:: + getAny () + { + return this->any_; + } + + void Entry_refType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const Entry_refType::RefType& Entry_refType:: + getRef () const + { + return this->ref_.get (); + } + + Entry_refType::RefType& Entry_refType:: + getRef () + { + return this->ref_.get (); + } + + void Entry_refType:: + setRef (const RefType& x) + { + this->ref_.set (x); + } + + void Entry_refType:: + setRef (::std::unique_ptr< RefType > x) + { + this->ref_.set (std::move (x)); + } + + ::std::unique_ptr< Entry_refType::RefType > Entry_refType:: + detachRef () + { + return this->ref_.detach (); + } + + const Entry_refType::AnyAttributeSet& Entry_refType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + Entry_refType::AnyAttributeSet& Entry_refType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void Entry_refType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& Entry_refType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& Entry_refType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // ExternalType + // + + const ExternalType::Display_nameOptional& ExternalType:: + getDisplay_name () const + { + return this->display_name_; + } + + ExternalType::Display_nameOptional& ExternalType:: + getDisplay_name () + { + return this->display_name_; + } + + void ExternalType:: + setDisplay_name (const Display_nameType& x) + { + this->display_name_.set (x); + } + + void ExternalType:: + setDisplay_name (const Display_nameOptional& x) + { + this->display_name_ = x; + } + + void ExternalType:: + setDisplay_name (::std::unique_ptr< Display_nameType > x) + { + this->display_name_.set (std::move (x)); + } + + const ExternalType::AnySequence& ExternalType:: + getAny () const + { + return this->any_; + } + + ExternalType::AnySequence& ExternalType:: + getAny () + { + return this->any_; + } + + void ExternalType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const ExternalType::AnchorOptional& ExternalType:: + getAnchor () const + { + return this->anchor_; + } + + ExternalType::AnchorOptional& ExternalType:: + getAnchor () + { + return this->anchor_; + } + + void ExternalType:: + setAnchor (const AnchorType& x) + { + this->anchor_.set (x); + } + + void ExternalType:: + setAnchor (const AnchorOptional& x) + { + this->anchor_ = x; + } + + void ExternalType:: + setAnchor (::std::unique_ptr< AnchorType > x) + { + this->anchor_.set (std::move (x)); + } + + const ExternalType::AnyAttributeSet& ExternalType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + ExternalType::AnyAttributeSet& ExternalType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void ExternalType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& ExternalType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& ExternalType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // Display_nameType + // + + const Display_nameType::LangOptional& Display_nameType:: + getLang () const + { + return this->lang_; + } + + Display_nameType::LangOptional& Display_nameType:: + getLang () + { + return this->lang_; + } + + void Display_nameType:: + setLang (const LangType& x) + { + this->lang_.set (x); + } + + void Display_nameType:: + setLang (const LangOptional& x) + { + this->lang_ = x; + } + + void Display_nameType:: + setLang (::std::unique_ptr< LangType > x) + { + this->lang_.set (std::move (x)); + } + + + // List + // + + + // Display_name + // + + + // Resource_lists + // + + const Resource_lists::ListSequence& Resource_lists:: + getList () const + { + return this->list_; + } + + Resource_lists::ListSequence& Resource_lists:: + getList () + { + return this->list_; + } + + void Resource_lists:: + setList (const ListSequence& s) + { + this->list_ = s; + } +} + +#include + +#include + +namespace resource_lists +{ + // ListType + // + + ListType:: + ListType () + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (this), + list_ (this), + external_ (this), + entry_ (this), + entry_ref_ (this), + any_ (this->getDomDocument ()), + name_ (this), + any_attribute_ (this->getDomDocument ()) + { + } + + ListType:: + ListType (const ListType& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (x.display_name_, f, this), + list_ (x.list_, f, this), + external_ (x.external_, f, this), + entry_ (x.entry_, f, this), + entry_ref_ (x.entry_ref_, f, this), + any_ (x.any_, this->getDomDocument ()), + name_ (x.name_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + ListType:: + ListType (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (this), + list_ (this), + external_ (this), + entry_ (this), + entry_ref_ (this), + any_ (this->getDomDocument ()), + name_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void ListType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-name + // + if (n.name () == "display-name" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< Display_nameType > r ( + Display_nameTraits::create (i, f, this)); + + if (!this->display_name_) + { + this->display_name_.set (::std::move (r)); + continue; + } + } + + // list + // + if (n.name () == "list" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< ListType1 > r ( + ListTraits::create (i, f, this)); + + this->list_.push_back (::std::move (r)); + continue; + } + + // external + // + if (n.name () == "external" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< ExternalType > r ( + ExternalTraits::create (i, f, this)); + + this->external_.push_back (::std::move (r)); + continue; + } + + // entry + // + if (n.name () == "entry" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< EntryType > r ( + EntryTraits::create (i, f, this)); + + this->entry_.push_back (::std::move (r)); + continue; + } + + // entry-ref + // + if (n.name () == "entry-ref" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< Entry_refType > r ( + Entry_refTraits::create (i, f, this)); + + this->entry_ref_.push_back (::std::move (r)); + continue; + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "name" && n.namespace_ ().empty ()) + { + this->name_.set (NameTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + } + + ListType* ListType:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class ListType (*this, f, c); + } + + ListType& ListType:: + operator= (const ListType& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->display_name_ = x.display_name_; + this->list_ = x.list_; + this->external_ = x.external_; + this->entry_ = x.entry_; + this->entry_ref_ = x.entry_ref_; + this->any_ = x.any_; + this->name_ = x.name_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + ListType:: + ~ListType () + { + } + + // EntryType + // + + EntryType:: + EntryType (const UriType& uri) + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (this), + any_ (this->getDomDocument ()), + uri_ (uri, this), + any_attribute_ (this->getDomDocument ()) + { + } + + EntryType:: + EntryType (const EntryType& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (x.display_name_, f, this), + any_ (x.any_, this->getDomDocument ()), + uri_ (x.uri_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + EntryType:: + EntryType (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (this), + any_ (this->getDomDocument ()), + uri_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void EntryType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-name + // + if (n.name () == "display-name" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< Display_nameType > r ( + Display_nameTraits::create (i, f, this)); + + if (!this->display_name_) + { + this->display_name_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "uri" && n.namespace_ ().empty ()) + { + this->uri_.set (UriTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + + if (!uri_.present ()) + { + throw ::xsd::cxx::tree::expected_attribute< char > ( + "uri", + ""); + } + } + + EntryType* EntryType:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class EntryType (*this, f, c); + } + + EntryType& EntryType:: + operator= (const EntryType& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->display_name_ = x.display_name_; + this->any_ = x.any_; + this->uri_ = x.uri_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + EntryType:: + ~EntryType () + { + } + + // Entry_refType + // + + Entry_refType:: + Entry_refType (const RefType& ref) + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (this), + any_ (this->getDomDocument ()), + ref_ (ref, this), + any_attribute_ (this->getDomDocument ()) + { + } + + Entry_refType:: + Entry_refType (const Entry_refType& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (x.display_name_, f, this), + any_ (x.any_, this->getDomDocument ()), + ref_ (x.ref_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + Entry_refType:: + Entry_refType (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (this), + any_ (this->getDomDocument ()), + ref_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void Entry_refType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-name + // + if (n.name () == "display-name" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< Display_nameType > r ( + Display_nameTraits::create (i, f, this)); + + if (!this->display_name_) + { + this->display_name_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "ref" && n.namespace_ ().empty ()) + { + this->ref_.set (RefTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + + if (!ref_.present ()) + { + throw ::xsd::cxx::tree::expected_attribute< char > ( + "ref", + ""); + } + } + + Entry_refType* Entry_refType:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Entry_refType (*this, f, c); + } + + Entry_refType& Entry_refType:: + operator= (const Entry_refType& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->display_name_ = x.display_name_; + this->any_ = x.any_; + this->ref_ = x.ref_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + Entry_refType:: + ~Entry_refType () + { + } + + // ExternalType + // + + ExternalType:: + ExternalType () + : ::xml_schema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (this), + any_ (this->getDomDocument ()), + anchor_ (this), + any_attribute_ (this->getDomDocument ()) + { + } + + ExternalType:: + ExternalType (const ExternalType& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (x.display_name_, f, this), + any_ (x.any_, this->getDomDocument ()), + anchor_ (x.anchor_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + ExternalType:: + ExternalType (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (this), + any_ (this->getDomDocument ()), + anchor_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void ExternalType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-name + // + if (n.name () == "display-name" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< Display_nameType > r ( + Display_nameTraits::create (i, f, this)); + + if (!this->display_name_) + { + this->display_name_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "anchor" && n.namespace_ ().empty ()) + { + this->anchor_.set (AnchorTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + } + + ExternalType* ExternalType:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class ExternalType (*this, f, c); + } + + ExternalType& ExternalType:: + operator= (const ExternalType& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->display_name_ = x.display_name_; + this->any_ = x.any_; + this->anchor_ = x.anchor_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + ExternalType:: + ~ExternalType () + { + } + + // Display_nameType + // + + Display_nameType:: + Display_nameType () + : ::xml_schema::String (), + lang_ (this) + { + } + + Display_nameType:: + Display_nameType (const char* _xsd_String_base) + : ::xml_schema::String (_xsd_String_base), + lang_ (this) + { + } + + Display_nameType:: + Display_nameType (const ::std::string& _xsd_String_base) + : ::xml_schema::String (_xsd_String_base), + lang_ (this) + { + } + + Display_nameType:: + Display_nameType (const ::xml_schema::String& _xsd_String_base) + : ::xml_schema::String (_xsd_String_base), + lang_ (this) + { + } + + Display_nameType:: + Display_nameType (const Display_nameType& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (x, f, c), + lang_ (x.lang_, f, this) + { + } + + Display_nameType:: + Display_nameType (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::String (e, f | ::xml_schema::Flags::base, c), + lang_ (this) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, false, false, true); + this->parse (p, f); + } + } + + void Display_nameType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "lang" && n.namespace_ () == "http://www.w3.org/XML/1998/namespace") + { + this->lang_.set (LangTraits::create (i, f, this)); + continue; + } + } + } + + Display_nameType* Display_nameType:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Display_nameType (*this, f, c); + } + + Display_nameType& Display_nameType:: + operator= (const Display_nameType& x) + { + if (this != &x) + { + static_cast< ::xml_schema::String& > (*this) = x; + this->lang_ = x.lang_; + } + + return *this; + } + + Display_nameType:: + ~Display_nameType () + { + } + + // List + // + + List:: + List () + : ::resource_lists::ListType () + { + } + + List:: + List (const List& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::resource_lists::ListType (x, f, c) + { + } + + List:: + List (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::resource_lists::ListType (e, f, c) + { + } + + List* List:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class List (*this, f, c); + } + + List:: + ~List () + { + } + + // Display_name + // + + Display_name:: + Display_name () + : ::resource_lists::Display_nameType () + { + } + + Display_name:: + Display_name (const char* _xsd_String_base) + : ::resource_lists::Display_nameType (_xsd_String_base) + { + } + + Display_name:: + Display_name (const ::std::string& _xsd_String_base) + : ::resource_lists::Display_nameType (_xsd_String_base) + { + } + + Display_name:: + Display_name (const ::xml_schema::String& _xsd_String_base) + : ::resource_lists::Display_nameType (_xsd_String_base) + { + } + + Display_name:: + Display_name (const Display_name& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::resource_lists::Display_nameType (x, f, c) + { + } + + Display_name:: + Display_name (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::resource_lists::Display_nameType (e, f, c) + { + } + + Display_name* Display_name:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Display_name (*this, f, c); + } + + Display_name:: + ~Display_name () + { + } + + // Resource_lists + // + + Resource_lists:: + Resource_lists () + : ::xml_schema::Type (), + list_ (this) + { + } + + Resource_lists:: + Resource_lists (const Resource_lists& x, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (x, f, c), + list_ (x.list_, f, this) + { + } + + Resource_lists:: + Resource_lists (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f, + ::xml_schema::Container* c) + : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), + list_ (this) + { + if ((f & ::xml_schema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, false); + this->parse (p, f); + } + } + + void Resource_lists:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // list + // + if (n.name () == "list" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< ListType > r ( + ListTraits::create (i, f, this)); + + this->list_.push_back (::std::move (r)); + continue; + } + + break; + } + } + + Resource_lists* Resource_lists:: + _clone (::xml_schema::Flags f, + ::xml_schema::Container* c) const + { + return new class Resource_lists (*this, f, c); + } + + Resource_lists& Resource_lists:: + operator= (const Resource_lists& x) + { + if (this != &x) + { + static_cast< ::xml_schema::Type& > (*this) = x; + this->list_ = x.list_; + } + + return *this; + } + + Resource_lists:: + ~Resource_lists () + { + } +} + +#include + +namespace resource_lists +{ + ::std::ostream& + operator<< (::std::ostream& o, const ListType& i) + { + if (i.getDisplay_name ()) + { + o << ::std::endl << "display-name: " << *i.getDisplay_name (); + } + + for (ListType::ListConstIterator + b (i.getList ().begin ()), e (i.getList ().end ()); + b != e; ++b) + { + o << ::std::endl << "list: " << *b; + } + + for (ListType::ExternalConstIterator + b (i.getExternal ().begin ()), e (i.getExternal ().end ()); + b != e; ++b) + { + o << ::std::endl << "external: " << *b; + } + + for (ListType::EntryConstIterator + b (i.getEntry ().begin ()), e (i.getEntry ().end ()); + b != e; ++b) + { + o << ::std::endl << "entry: " << *b; + } + + for (ListType::Entry_refConstIterator + b (i.getEntry_ref ().begin ()), e (i.getEntry_ref ().end ()); + b != e; ++b) + { + o << ::std::endl << "entry-ref: " << *b; + } + + if (i.getName ()) + { + o << ::std::endl << "name: " << *i.getName (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const EntryType& i) + { + if (i.getDisplay_name ()) + { + o << ::std::endl << "display-name: " << *i.getDisplay_name (); + } + + o << ::std::endl << "uri: " << i.getUri (); + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Entry_refType& i) + { + if (i.getDisplay_name ()) + { + o << ::std::endl << "display-name: " << *i.getDisplay_name (); + } + + o << ::std::endl << "ref: " << i.getRef (); + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const ExternalType& i) + { + if (i.getDisplay_name ()) + { + o << ::std::endl << "display-name: " << *i.getDisplay_name (); + } + + if (i.getAnchor ()) + { + o << ::std::endl << "anchor: " << *i.getAnchor (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Display_nameType& i) + { + o << static_cast< const ::xml_schema::String& > (i); + + if (i.getLang ()) + { + o << ::std::endl << "lang: " << *i.getLang (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const List& i) + { + o << static_cast< const ::resource_lists::ListType& > (i); + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Display_name& i) + { + o << static_cast< const ::resource_lists::Display_nameType& > (i); + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const Resource_lists& i) + { + for (Resource_lists::ListConstIterator + b (i.getList ().begin ()), e (i.getList ().end ()); + b != e; ++b) + { + o << ::std::endl << "list: " << *b; + } + + return o; + } +} + +#include +#include +#include + +namespace resource_lists +{ + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (const ::std::string& u, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::Flags::dont_initialize) == 0, + (f & ::xml_schema::Flags::keep_dom) == 0); + + ::xsd::cxx::tree::error_handler< char > h; + + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + u, h, p, f)); + + h.throw_if_failed< ::xsd::cxx::tree::parsing< char > > (); + + return ::std::unique_ptr< ::resource_lists::Resource_lists > ( + ::resource_lists::parseResource_lists ( + std::move (d), f | ::xml_schema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (const ::std::string& u, + ::xml_schema::ErrorHandler& h, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::Flags::dont_initialize) == 0, + (f & ::xml_schema::Flags::keep_dom) == 0); + + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + u, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::resource_lists::Resource_lists > ( + ::resource_lists::parseResource_lists ( + std::move (d), f | ::xml_schema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (const ::std::string& u, + ::xercesc::DOMErrorHandler& h, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + u, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::resource_lists::Resource_lists > ( + ::resource_lists::parseResource_lists ( + std::move (d), f | ::xml_schema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::std::istream& is, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::Flags::dont_initialize) == 0, + (f & ::xml_schema::Flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is); + return ::resource_lists::parseResource_lists (isrc, f, p); + } + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::std::istream& is, + ::xml_schema::ErrorHandler& h, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::Flags::dont_initialize) == 0, + (f & ::xml_schema::Flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is); + return ::resource_lists::parseResource_lists (isrc, h, f, p); + } + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::std::istream& is, + ::xercesc::DOMErrorHandler& h, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xsd::cxx::xml::sax::std_input_source isrc (is); + return ::resource_lists::parseResource_lists (isrc, h, f, p); + } + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::std::istream& is, + const ::std::string& sid, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::Flags::dont_initialize) == 0, + (f & ::xml_schema::Flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); + return ::resource_lists::parseResource_lists (isrc, f, p); + } + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::std::istream& is, + const ::std::string& sid, + ::xml_schema::ErrorHandler& h, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::Flags::dont_initialize) == 0, + (f & ::xml_schema::Flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); + return ::resource_lists::parseResource_lists (isrc, h, f, p); + } + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::std::istream& is, + const ::std::string& sid, + ::xercesc::DOMErrorHandler& h, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); + return ::resource_lists::parseResource_lists (isrc, h, f, p); + } + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::xercesc::InputSource& i, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xsd::cxx::tree::error_handler< char > h; + + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + i, h, p, f)); + + h.throw_if_failed< ::xsd::cxx::tree::parsing< char > > (); + + return ::std::unique_ptr< ::resource_lists::Resource_lists > ( + ::resource_lists::parseResource_lists ( + std::move (d), f | ::xml_schema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::xercesc::InputSource& i, + ::xml_schema::ErrorHandler& h, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + i, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::resource_lists::Resource_lists > ( + ::resource_lists::parseResource_lists ( + std::move (d), f | ::xml_schema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::xercesc::InputSource& i, + ::xercesc::DOMErrorHandler& h, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + i, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::resource_lists::Resource_lists > ( + ::resource_lists::parseResource_lists ( + std::move (d), f | ::xml_schema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (const ::xercesc::DOMDocument& doc, + ::xml_schema::Flags f, + const ::xml_schema::Properties& p) + { + if (f & ::xml_schema::Flags::keep_dom) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + static_cast< ::xercesc::DOMDocument* > (doc.cloneNode (true))); + + return ::std::unique_ptr< ::resource_lists::Resource_lists > ( + ::resource_lists::parseResource_lists ( + std::move (d), f | ::xml_schema::Flags::own_dom, p)); + } + + const ::xercesc::DOMElement& e (*doc.getDocumentElement ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (e)); + + if (n.name () == "resource-lists" && + n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< ::resource_lists::Resource_lists > r ( + ::xsd::cxx::tree::traits< ::resource_lists::Resource_lists, char >::create ( + e, f, 0)); + return r; + } + + throw ::xsd::cxx::tree::unexpected_element < char > ( + n.name (), + n.namespace_ (), + "resource-lists", + "urn:ietf:params:xml:ns:resource-lists"); + } + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d, + ::xml_schema::Flags f, + const ::xml_schema::Properties&) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > c ( + ((f & ::xml_schema::Flags::keep_dom) && + !(f & ::xml_schema::Flags::own_dom)) + ? static_cast< ::xercesc::DOMDocument* > (d->cloneNode (true)) + : 0); + + ::xercesc::DOMDocument& doc (c.get () ? *c : *d); + const ::xercesc::DOMElement& e (*doc.getDocumentElement ()); + + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (e)); + + if (f & ::xml_schema::Flags::keep_dom) + doc.setUserData (::xml_schema::dom::treeNodeKey, + (c.get () ? &c : &d), + 0); + + if (n.name () == "resource-lists" && + n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< ::resource_lists::Resource_lists > r ( + ::xsd::cxx::tree::traits< ::resource_lists::Resource_lists, char >::create ( + e, f, 0)); + return r; + } + + throw ::xsd::cxx::tree::unexpected_element < char > ( + n.name (), + n.namespace_ (), + "resource-lists", + "urn:ietf:params:xml:ns:resource-lists"); + } +} + +#include +#include +#include + +namespace resource_lists +{ + void + operator<< (::xercesc::DOMElement& e, const ListType& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (ListType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // display-name + // + if (i.getDisplay_name ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-name", + "urn:ietf:params:xml:ns:resource-lists", + e)); + + s << *i.getDisplay_name (); + } + + // list + // + for (ListType::ListConstIterator + b (i.getList ().begin ()), n (i.getList ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "list", + "urn:ietf:params:xml:ns:resource-lists", + e)); + + s << *b; + } + + // external + // + for (ListType::ExternalConstIterator + b (i.getExternal ().begin ()), n (i.getExternal ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "external", + "urn:ietf:params:xml:ns:resource-lists", + e)); + + s << *b; + } + + // entry + // + for (ListType::EntryConstIterator + b (i.getEntry ().begin ()), n (i.getEntry ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "entry", + "urn:ietf:params:xml:ns:resource-lists", + e)); + + s << *b; + } + + // entry-ref + // + for (ListType::Entry_refConstIterator + b (i.getEntry_ref ().begin ()), n (i.getEntry_ref ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "entry-ref", + "urn:ietf:params:xml:ns:resource-lists", + e)); + + s << *b; + } + + // any + // + for (ListType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + + // name + // + if (i.getName ()) + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "name", + e)); + + a << *i.getName (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const EntryType& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (EntryType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // display-name + // + if (i.getDisplay_name ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-name", + "urn:ietf:params:xml:ns:resource-lists", + e)); + + s << *i.getDisplay_name (); + } + + // any + // + for (EntryType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + + // uri + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "uri", + e)); + + a << i.getUri (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const Entry_refType& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (Entry_refType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // display-name + // + if (i.getDisplay_name ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-name", + "urn:ietf:params:xml:ns:resource-lists", + e)); + + s << *i.getDisplay_name (); + } + + // any + // + for (Entry_refType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + + // ref + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "ref", + e)); + + a << i.getRef (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const ExternalType& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // any_attribute + // + for (ExternalType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // display-name + // + if (i.getDisplay_name ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-name", + "urn:ietf:params:xml:ns:resource-lists", + e)); + + s << *i.getDisplay_name (); + } + + // any + // + for (ExternalType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + + // anchor + // + if (i.getAnchor ()) + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "anchor", + e)); + + a << *i.getAnchor (); + } + } + + void + serializeResource_lists (::std::ostream& o, + const ::resource_lists::Resource_lists& s, + const ::xml_schema::NamespaceInfomap& m, + const ::std::string& e, + ::xml_schema::Flags f) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::Flags::dont_initialize) == 0); + + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::resource_lists::serializeResource_lists (s, m, f)); + + ::xsd::cxx::tree::error_handler< char > h; + + ::xsd::cxx::xml::dom::ostream_format_target t (o); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + h.throw_if_failed< ::xsd::cxx::tree::serialization< char > > (); + } + } + + void + serializeResource_lists (::std::ostream& o, + const ::resource_lists::Resource_lists& s, + ::xml_schema::ErrorHandler& h, + const ::xml_schema::NamespaceInfomap& m, + const ::std::string& e, + ::xml_schema::Flags f) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::Flags::dont_initialize) == 0); + + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::resource_lists::serializeResource_lists (s, m, f)); + ::xsd::cxx::xml::dom::ostream_format_target t (o); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + throw ::xsd::cxx::tree::serialization< char > (); + } + } + + void + serializeResource_lists (::std::ostream& o, + const ::resource_lists::Resource_lists& s, + ::xercesc::DOMErrorHandler& h, + const ::xml_schema::NamespaceInfomap& m, + const ::std::string& e, + ::xml_schema::Flags f) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::resource_lists::serializeResource_lists (s, m, f)); + ::xsd::cxx::xml::dom::ostream_format_target t (o); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + throw ::xsd::cxx::tree::serialization< char > (); + } + } + + void + serializeResource_lists (::xercesc::XMLFormatTarget& t, + const ::resource_lists::Resource_lists& s, + const ::xml_schema::NamespaceInfomap& m, + const ::std::string& e, + ::xml_schema::Flags f) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::resource_lists::serializeResource_lists (s, m, f)); + + ::xsd::cxx::tree::error_handler< char > h; + + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + h.throw_if_failed< ::xsd::cxx::tree::serialization< char > > (); + } + } + + void + serializeResource_lists (::xercesc::XMLFormatTarget& t, + const ::resource_lists::Resource_lists& s, + ::xml_schema::ErrorHandler& h, + const ::xml_schema::NamespaceInfomap& m, + const ::std::string& e, + ::xml_schema::Flags f) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::resource_lists::serializeResource_lists (s, m, f)); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + throw ::xsd::cxx::tree::serialization< char > (); + } + } + + void + serializeResource_lists (::xercesc::XMLFormatTarget& t, + const ::resource_lists::Resource_lists& s, + ::xercesc::DOMErrorHandler& h, + const ::xml_schema::NamespaceInfomap& m, + const ::std::string& e, + ::xml_schema::Flags f) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::resource_lists::serializeResource_lists (s, m, f)); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + throw ::xsd::cxx::tree::serialization< char > (); + } + } + + void + serializeResource_lists (::xercesc::DOMDocument& d, + const ::resource_lists::Resource_lists& s, + ::xml_schema::Flags) + { + ::xercesc::DOMElement& e (*d.getDocumentElement ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (e)); + + if (n.name () == "resource-lists" && + n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + e << s; + } + else + { + throw ::xsd::cxx::tree::unexpected_element < char > ( + n.name (), + n.namespace_ (), + "resource-lists", + "urn:ietf:params:xml:ns:resource-lists"); + } + } + + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > + serializeResource_lists (const ::resource_lists::Resource_lists& s, + const ::xml_schema::NamespaceInfomap& m, + ::xml_schema::Flags f) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::serialize< char > ( + "resource-lists", + "urn:ietf:params:xml:ns:resource-lists", + m, f)); + + ::resource_lists::serializeResource_lists (*d, s, f); + return d; + } + + void + operator<< (::xercesc::DOMElement& e, const Display_nameType& i) + { + e << static_cast< const ::xml_schema::String& > (i); + + // lang + // + if (i.getLang ()) + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "lang", + "http://www.w3.org/XML/1998/namespace", + e)); + + a << *i.getLang (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const List& i) + { + e << static_cast< const ::resource_lists::ListType& > (i); + } + + void + operator<< (::xercesc::DOMElement& e, const Display_name& i) + { + e << static_cast< const ::resource_lists::Display_nameType& > (i); + } + + void + operator<< (::xercesc::DOMElement& e, const Resource_lists& i) + { + e << static_cast< const ::xml_schema::Type& > (i); + + // list + // + for (Resource_lists::ListConstIterator + b (i.getList ().begin ()), n (i.getList ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "list", + "urn:ietf:params:xml:ns:resource-lists", + e)); + + s << *b; + } + } +} + +#include + +// Begin epilogue. +// +// +// End epilogue. + diff --git a/src/xml/resource-lists.h b/src/xml/resource-lists.h new file mode 100644 index 000000000..4c499fa3d --- /dev/null +++ b/src/xml/resource-lists.h @@ -0,0 +1,1254 @@ +// Copyright (c) 2005-2014 Code Synthesis Tools CC +// +// This program was generated by CodeSynthesis XSD, an XML Schema to +// C++ data binding compiler. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// 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 St, Fifth Floor, Boston, MA 02110-1301 USA +// +// In addition, as a special exception, Code Synthesis Tools CC gives +// permission to link this program with the Xerces-C++ library (or with +// modified versions of Xerces-C++ that use the same license as Xerces-C++), +// and distribute linked combinations including the two. You must obey +// the GNU General Public License version 2 in all respects for all of +// the code used other than Xerces-C++. If you modify this copy of the +// program, you may extend this exception to your version of the program, +// but you are not obligated to do so. If you do not wish to do so, delete +// this exception statement from your version. +// +// Furthermore, Code Synthesis Tools CC makes a special exception for +// the Free/Libre and Open Source Software (FLOSS) which is described +// in the accompanying FLOSSE file. +// + +#ifndef XML_RESOURCE_LISTS_H +#define XML_RESOURCE_LISTS_H + +#ifndef XSD_CXX11 +#define XSD_CXX11 +#endif + +#ifndef XSD_USE_CHAR +#define XSD_USE_CHAR +#endif + +#ifndef XSD_CXX_TREE_USE_CHAR +#define XSD_CXX_TREE_USE_CHAR +#endif + +// Begin prologue. +// +// +// End prologue. + +#include + +#if (XSD_INT_VERSION != 4000000L) +#error XSD runtime version mismatch +#endif + +#include + +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace xml_schema +{ + // anyType and anySimpleType. + // + typedef ::xsd::cxx::tree::type Type; + typedef ::xsd::cxx::tree::simple_type< char, Type > SimpleType; + typedef ::xsd::cxx::tree::type Container; + + // 8-bit + // + typedef signed char Byte; + typedef unsigned char UnsignedByte; + + // 16-bit + // + typedef short Short; + typedef unsigned short UnsignedShort; + + // 32-bit + // + typedef int Int; + typedef unsigned int UnsignedInt; + + // 64-bit + // + typedef long long Long; + typedef unsigned long long UnsignedLong; + + // Supposed to be arbitrary-length integral types. + // + typedef long long Integer; + typedef long long NonPositiveInteger; + typedef unsigned long long NonNegativeInteger; + typedef unsigned long long PositiveInteger; + typedef long long NegativeInteger; + + // Boolean. + // + typedef bool Boolean; + + // Floating-point types. + // + typedef float Float; + typedef double Double; + typedef double Decimal; + + // String types. + // + typedef ::xsd::cxx::tree::string< char, SimpleType > String; + typedef ::xsd::cxx::tree::normalized_string< char, String > NormalizedString; + typedef ::xsd::cxx::tree::token< char, NormalizedString > Token; + typedef ::xsd::cxx::tree::name< char, Token > Name; + typedef ::xsd::cxx::tree::nmtoken< char, Token > Nmtoken; + typedef ::xsd::cxx::tree::nmtokens< char, SimpleType, Nmtoken > Nmtokens; + typedef ::xsd::cxx::tree::ncname< char, Name > Ncname; + typedef ::xsd::cxx::tree::language< char, Token > Language; + + // ID/IDREF. + // + typedef ::xsd::cxx::tree::id< char, Ncname > Id; + typedef ::xsd::cxx::tree::idref< char, Ncname, Type > Idref; + typedef ::xsd::cxx::tree::idrefs< char, SimpleType, Idref > Idrefs; + + // URI. + // + typedef ::xsd::cxx::tree::uri< char, SimpleType > Uri; + + // Qualified name. + // + typedef ::xsd::cxx::tree::qname< char, SimpleType, Uri, Ncname > Qname; + + // Binary. + // + typedef ::xsd::cxx::tree::buffer< char > Buffer; + typedef ::xsd::cxx::tree::base64_binary< char, SimpleType > Base64Binary; + typedef ::xsd::cxx::tree::hex_binary< char, SimpleType > HexBinary; + + // Date/time. + // + typedef ::xsd::cxx::tree::time_zone TimeZone; + typedef ::xsd::cxx::tree::date< char, SimpleType > Date; + typedef ::xsd::cxx::tree::date_time< char, SimpleType > DateTime; + typedef ::xsd::cxx::tree::duration< char, SimpleType > Duration; + typedef ::xsd::cxx::tree::gday< char, SimpleType > Gday; + typedef ::xsd::cxx::tree::gmonth< char, SimpleType > Gmonth; + typedef ::xsd::cxx::tree::gmonth_day< char, SimpleType > GmonthDay; + typedef ::xsd::cxx::tree::gyear< char, SimpleType > Gyear; + typedef ::xsd::cxx::tree::gyear_month< char, SimpleType > GyearMonth; + typedef ::xsd::cxx::tree::time< char, SimpleType > Time; + + // Entity. + // + typedef ::xsd::cxx::tree::entity< char, Ncname > Entity; + typedef ::xsd::cxx::tree::entities< char, SimpleType, Entity > Entities; + + typedef ::xsd::cxx::tree::content_order ContentOrder; + // Namespace information and list stream. Used in + // serialization functions. + // + typedef ::xsd::cxx::xml::dom::namespace_info< char > NamespaceInfo; + typedef ::xsd::cxx::xml::dom::namespace_infomap< char > NamespaceInfomap; + typedef ::xsd::cxx::tree::list_stream< char > ListStream; + typedef ::xsd::cxx::tree::as_double< Double > AsDouble; + typedef ::xsd::cxx::tree::as_decimal< Decimal > AsDecimal; + typedef ::xsd::cxx::tree::facet Facet; + + // Flags and properties. + // + typedef ::xsd::cxx::tree::flags Flags; + typedef ::xsd::cxx::tree::properties< char > Properties; + + // Parsing/serialization diagnostics. + // + typedef ::xsd::cxx::tree::severity Severity; + typedef ::xsd::cxx::tree::error< char > Error; + typedef ::xsd::cxx::tree::diagnostics< char > Diagnostics; + + // Exceptions. + // + typedef ::xsd::cxx::tree::exception< char > Exception; + typedef ::xsd::cxx::tree::bounds< char > Bounds; + typedef ::xsd::cxx::tree::duplicate_id< char > DuplicateId; + typedef ::xsd::cxx::tree::parsing< char > Parsing; + typedef ::xsd::cxx::tree::expected_element< char > ExpectedElement; + typedef ::xsd::cxx::tree::unexpected_element< char > UnexpectedElement; + typedef ::xsd::cxx::tree::expected_attribute< char > ExpectedAttribute; + typedef ::xsd::cxx::tree::unexpected_enumerator< char > UnexpectedEnumerator; + typedef ::xsd::cxx::tree::expected_text_content< char > ExpectedTextContent; + typedef ::xsd::cxx::tree::no_prefix_mapping< char > NoPrefixMapping; + typedef ::xsd::cxx::tree::serialization< char > Serialization; + + // Error handler callback interface. + // + typedef ::xsd::cxx::xml::error_handler< char > ErrorHandler; + + // DOM interaction. + // + namespace dom + { + // Automatic pointer for DOMDocument. + // + using ::xsd::cxx::xml::dom::unique_ptr; + +#ifndef XSD_CXX_TREE_TREE_NODE_KEY__XML_SCHEMA +#define XSD_CXX_TREE_TREE_NODE_KEY__XML_SCHEMA + // DOM user data key for back pointers to tree nodes. + // + const XMLCh* const treeNodeKey = ::xsd::cxx::tree::user_data_keys::node; +#endif + } +} + +// Forward declarations. +// +namespace resource_lists +{ + class ListType; + class EntryType; + class Entry_refType; + class ExternalType; + class Display_nameType; + class List; + class Display_name; + class Resource_lists; +} + + +#include // ::std::unique_ptr +#include // std::numeric_limits +#include // std::binary_search +#include // std::move + +#include + +#include +#include +#include +#include + +#include + +#include + +#include "xml.h" + +namespace resource_lists +{ + class ListType: public ::xml_schema::Type + { + public: + // display-name + // + typedef ::resource_lists::Display_nameType Display_nameType; + typedef ::xsd::cxx::tree::optional< Display_nameType > Display_nameOptional; + typedef ::xsd::cxx::tree::traits< Display_nameType, char > Display_nameTraits; + + const Display_nameOptional& + getDisplay_name () const; + + Display_nameOptional& + getDisplay_name (); + + void + setDisplay_name (const Display_nameType& x); + + void + setDisplay_name (const Display_nameOptional& x); + + void + setDisplay_name (::std::unique_ptr< Display_nameType > p); + + // list + // + typedef ::resource_lists::List ListType1; + typedef ::xsd::cxx::tree::sequence< ListType1 > ListSequence; + typedef ListSequence::iterator ListIterator; + typedef ListSequence::const_iterator ListConstIterator; + typedef ::xsd::cxx::tree::traits< ListType1, char > ListTraits; + + const ListSequence& + getList () const; + + ListSequence& + getList (); + + void + setList (const ListSequence& s); + + // external + // + typedef ::resource_lists::ExternalType ExternalType; + typedef ::xsd::cxx::tree::sequence< ExternalType > ExternalSequence; + typedef ExternalSequence::iterator ExternalIterator; + typedef ExternalSequence::const_iterator ExternalConstIterator; + typedef ::xsd::cxx::tree::traits< ExternalType, char > ExternalTraits; + + const ExternalSequence& + getExternal () const; + + ExternalSequence& + getExternal (); + + void + setExternal (const ExternalSequence& s); + + // entry + // + typedef ::resource_lists::EntryType EntryType; + typedef ::xsd::cxx::tree::sequence< EntryType > EntrySequence; + typedef EntrySequence::iterator EntryIterator; + typedef EntrySequence::const_iterator EntryConstIterator; + typedef ::xsd::cxx::tree::traits< EntryType, char > EntryTraits; + + const EntrySequence& + getEntry () const; + + EntrySequence& + getEntry (); + + void + setEntry (const EntrySequence& s); + + // entry-ref + // + typedef ::resource_lists::Entry_refType Entry_refType; + typedef ::xsd::cxx::tree::sequence< Entry_refType > Entry_refSequence; + typedef Entry_refSequence::iterator Entry_refIterator; + typedef Entry_refSequence::const_iterator Entry_refConstIterator; + typedef ::xsd::cxx::tree::traits< Entry_refType, char > Entry_refTraits; + + const Entry_refSequence& + getEntry_ref () const; + + Entry_refSequence& + getEntry_ref (); + + void + setEntry_ref (const Entry_refSequence& s); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // name + // + typedef ::xml_schema::String NameType; + typedef ::xsd::cxx::tree::optional< NameType > NameOptional; + typedef ::xsd::cxx::tree::traits< NameType, char > NameTraits; + + const NameOptional& + getName () const; + + NameOptional& + getName (); + + void + setName (const NameType& x); + + void + setName (const NameOptional& x); + + void + setName (::std::unique_ptr< NameType > p); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + ListType (); + + ListType (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + ListType (const ListType& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual ListType* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + ListType& + operator= (const ListType& x); + + virtual + ~ListType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + Display_nameOptional display_name_; + ListSequence list_; + ExternalSequence external_; + EntrySequence entry_; + Entry_refSequence entry_ref_; + AnySequence any_; + NameOptional name_; + AnyAttributeSet any_attribute_; + }; + + class EntryType: public ::xml_schema::Type + { + public: + // display-name + // + typedef ::resource_lists::Display_name Display_nameType; + typedef ::xsd::cxx::tree::optional< Display_nameType > Display_nameOptional; + typedef ::xsd::cxx::tree::traits< Display_nameType, char > Display_nameTraits; + + const Display_nameOptional& + getDisplay_name () const; + + Display_nameOptional& + getDisplay_name (); + + void + setDisplay_name (const Display_nameType& x); + + void + setDisplay_name (const Display_nameOptional& x); + + void + setDisplay_name (::std::unique_ptr< Display_nameType > p); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // uri + // + typedef ::xml_schema::Uri UriType; + typedef ::xsd::cxx::tree::traits< UriType, char > UriTraits; + + const UriType& + getUri () const; + + UriType& + getUri (); + + void + setUri (const UriType& x); + + void + setUri (::std::unique_ptr< UriType > p); + + ::std::unique_ptr< UriType > + detachUri (); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + EntryType (const UriType&); + + EntryType (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + EntryType (const EntryType& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual EntryType* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + EntryType& + operator= (const EntryType& x); + + virtual + ~EntryType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + Display_nameOptional display_name_; + AnySequence any_; + ::xsd::cxx::tree::one< UriType > uri_; + AnyAttributeSet any_attribute_; + }; + + class Entry_refType: public ::xml_schema::Type + { + public: + // display-name + // + typedef ::resource_lists::Display_nameType Display_nameType; + typedef ::xsd::cxx::tree::optional< Display_nameType > Display_nameOptional; + typedef ::xsd::cxx::tree::traits< Display_nameType, char > Display_nameTraits; + + const Display_nameOptional& + getDisplay_name () const; + + Display_nameOptional& + getDisplay_name (); + + void + setDisplay_name (const Display_nameType& x); + + void + setDisplay_name (const Display_nameOptional& x); + + void + setDisplay_name (::std::unique_ptr< Display_nameType > p); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // ref + // + typedef ::xml_schema::Uri RefType; + typedef ::xsd::cxx::tree::traits< RefType, char > RefTraits; + + const RefType& + getRef () const; + + RefType& + getRef (); + + void + setRef (const RefType& x); + + void + setRef (::std::unique_ptr< RefType > p); + + ::std::unique_ptr< RefType > + detachRef (); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + Entry_refType (const RefType&); + + Entry_refType (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Entry_refType (const Entry_refType& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Entry_refType* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Entry_refType& + operator= (const Entry_refType& x); + + virtual + ~Entry_refType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + Display_nameOptional display_name_; + AnySequence any_; + ::xsd::cxx::tree::one< RefType > ref_; + AnyAttributeSet any_attribute_; + }; + + class ExternalType: public ::xml_schema::Type + { + public: + // display-name + // + typedef ::resource_lists::Display_nameType Display_nameType; + typedef ::xsd::cxx::tree::optional< Display_nameType > Display_nameOptional; + typedef ::xsd::cxx::tree::traits< Display_nameType, char > Display_nameTraits; + + const Display_nameOptional& + getDisplay_name () const; + + Display_nameOptional& + getDisplay_name (); + + void + setDisplay_name (const Display_nameType& x); + + void + setDisplay_name (const Display_nameOptional& x); + + void + setDisplay_name (::std::unique_ptr< Display_nameType > p); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // anchor + // + typedef ::xml_schema::Uri AnchorType; + typedef ::xsd::cxx::tree::optional< AnchorType > AnchorOptional; + typedef ::xsd::cxx::tree::traits< AnchorType, char > AnchorTraits; + + const AnchorOptional& + getAnchor () const; + + AnchorOptional& + getAnchor (); + + void + setAnchor (const AnchorType& x); + + void + setAnchor (const AnchorOptional& x); + + void + setAnchor (::std::unique_ptr< AnchorType > p); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + ExternalType (); + + ExternalType (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + ExternalType (const ExternalType& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual ExternalType* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + ExternalType& + operator= (const ExternalType& x); + + virtual + ~ExternalType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + Display_nameOptional display_name_; + AnySequence any_; + AnchorOptional anchor_; + AnyAttributeSet any_attribute_; + }; + + class Display_nameType: public ::xml_schema::String + { + public: + // lang + // + typedef ::namespace_::Lang LangType; + typedef ::xsd::cxx::tree::optional< LangType > LangOptional; + typedef ::xsd::cxx::tree::traits< LangType, char > LangTraits; + + const LangOptional& + getLang () const; + + LangOptional& + getLang (); + + void + setLang (const LangType& x); + + void + setLang (const LangOptional& x); + + void + setLang (::std::unique_ptr< LangType > p); + + // Constructors. + // + Display_nameType (); + + Display_nameType (const char*); + + Display_nameType (const ::std::string&); + + Display_nameType (const ::xml_schema::String&); + + Display_nameType (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Display_nameType (const Display_nameType& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Display_nameType* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Display_nameType& + operator= (const Display_nameType& x); + + virtual + ~Display_nameType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + LangOptional lang_; + }; + + class List: public ::resource_lists::ListType + { + public: + // Constructors. + // + List (); + + List (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + List (const List& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual List* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + virtual + ~List (); + }; + + class Display_name: public ::resource_lists::Display_nameType + { + public: + // Constructors. + // + Display_name (); + + Display_name (const char*); + + Display_name (const ::std::string&); + + Display_name (const ::xml_schema::String&); + + Display_name (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Display_name (const Display_name& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Display_name* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + virtual + ~Display_name (); + }; + + class Resource_lists: public ::xml_schema::Type + { + public: + // list + // + typedef ::resource_lists::ListType ListType; + typedef ::xsd::cxx::tree::sequence< ListType > ListSequence; + typedef ListSequence::iterator ListIterator; + typedef ListSequence::const_iterator ListConstIterator; + typedef ::xsd::cxx::tree::traits< ListType, char > ListTraits; + + const ListSequence& + getList () const; + + ListSequence& + getList (); + + void + setList (const ListSequence& s); + + // Constructors. + // + Resource_lists (); + + Resource_lists (const ::xercesc::DOMElement& e, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + Resource_lists (const Resource_lists& x, + ::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0); + + virtual Resource_lists* + _clone (::xml_schema::Flags f = 0, + ::xml_schema::Container* c = 0) const; + + Resource_lists& + operator= (const Resource_lists& x); + + virtual + ~Resource_lists (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::Flags); + + protected: + ListSequence list_; + }; +} + +#include + +namespace resource_lists +{ + ::std::ostream& + operator<< (::std::ostream&, const ListType&); + + ::std::ostream& + operator<< (::std::ostream&, const EntryType&); + + ::std::ostream& + operator<< (::std::ostream&, const Entry_refType&); + + ::std::ostream& + operator<< (::std::ostream&, const ExternalType&); + + ::std::ostream& + operator<< (::std::ostream&, const Display_nameType&); + + ::std::ostream& + operator<< (::std::ostream&, const List&); + + ::std::ostream& + operator<< (::std::ostream&, const Display_name&); + + ::std::ostream& + operator<< (::std::ostream&, const Resource_lists&); +} + +#include + +#include +#include +#include + +namespace resource_lists +{ + // Parse a URI or a local file. + // + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (const ::std::string& uri, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (const ::std::string& uri, + ::xml_schema::ErrorHandler& eh, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (const ::std::string& uri, + ::xercesc::DOMErrorHandler& eh, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + // Parse std::istream. + // + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::std::istream& is, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::std::istream& is, + ::xml_schema::ErrorHandler& eh, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::std::istream& is, + ::xercesc::DOMErrorHandler& eh, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::std::istream& is, + const ::std::string& id, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::std::istream& is, + const ::std::string& id, + ::xml_schema::ErrorHandler& eh, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::std::istream& is, + const ::std::string& id, + ::xercesc::DOMErrorHandler& eh, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + // Parse xercesc::InputSource. + // + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::xercesc::InputSource& is, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::xercesc::InputSource& is, + ::xml_schema::ErrorHandler& eh, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::xercesc::InputSource& is, + ::xercesc::DOMErrorHandler& eh, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + // Parse xercesc::DOMDocument. + // + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (const ::xercesc::DOMDocument& d, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + + ::std::unique_ptr< ::resource_lists::Resource_lists > + parseResource_lists (::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d, + ::xml_schema::Flags f = 0, + const ::xml_schema::Properties& p = ::xml_schema::Properties ()); +} + +#include + +#include +#include +#include + +#include + +namespace resource_lists +{ + void + operator<< (::xercesc::DOMElement&, const ListType&); + + void + operator<< (::xercesc::DOMElement&, const EntryType&); + + void + operator<< (::xercesc::DOMElement&, const Entry_refType&); + + void + operator<< (::xercesc::DOMElement&, const ExternalType&); + + // Serialize to std::ostream. + // + + void + serializeResource_lists (::std::ostream& os, + const ::resource_lists::Resource_lists& x, + const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::xml_schema::Flags f = 0); + + void + serializeResource_lists (::std::ostream& os, + const ::resource_lists::Resource_lists& x, + ::xml_schema::ErrorHandler& eh, + const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::xml_schema::Flags f = 0); + + void + serializeResource_lists (::std::ostream& os, + const ::resource_lists::Resource_lists& x, + ::xercesc::DOMErrorHandler& eh, + const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::xml_schema::Flags f = 0); + + // Serialize to xercesc::XMLFormatTarget. + // + + void + serializeResource_lists (::xercesc::XMLFormatTarget& ft, + const ::resource_lists::Resource_lists& x, + const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::xml_schema::Flags f = 0); + + void + serializeResource_lists (::xercesc::XMLFormatTarget& ft, + const ::resource_lists::Resource_lists& x, + ::xml_schema::ErrorHandler& eh, + const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::xml_schema::Flags f = 0); + + void + serializeResource_lists (::xercesc::XMLFormatTarget& ft, + const ::resource_lists::Resource_lists& x, + ::xercesc::DOMErrorHandler& eh, + const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::xml_schema::Flags f = 0); + + // Serialize to an existing xercesc::DOMDocument. + // + + void + serializeResource_lists (::xercesc::DOMDocument& d, + const ::resource_lists::Resource_lists& x, + ::xml_schema::Flags f = 0); + + // Serialize to a new xercesc::DOMDocument. + // + + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > + serializeResource_lists (const ::resource_lists::Resource_lists& x, + const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), + ::xml_schema::Flags f = 0); + + void + operator<< (::xercesc::DOMElement&, const Display_nameType&); + + void + operator<< (::xercesc::DOMElement&, const List&); + + void + operator<< (::xercesc::DOMElement&, const Display_name&); + + void + operator<< (::xercesc::DOMElement&, const Resource_lists&); +} + +#include + +// Begin epilogue. +// +// +// End epilogue. + +#endif // XML_RESOURCE_LISTS_H From 6d54b3c46da37d415009937a044ca9187da78978 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 4 Aug 2017 16:53:29 +0200 Subject: [PATCH 0018/2215] Add class skeletons for refactoring of conference. --- src/CMakeLists.txt | 22 +++++++ src/call/call.cpp | 54 +++++++++++++++ src/call/call.h | 46 +++++++++++++ src/chat/chat-room.cpp | 1 + src/chat/chat-room.h | 1 + src/conference/conference-listener.h | 37 +++++++++++ src/conference/conference-p.h | 43 ++++++++++++ src/conference/conference.cpp | 29 +++++++++ src/conference/conference.h | 44 +++++++++++++ src/conference/local-conference.cpp | 35 ++++++++++ src/conference/local-conference.h | 41 ++++++++++++ src/conference/params/call-session-params-p.h | 43 ++++++++++++ src/conference/params/call-session-params.cpp | 27 ++++++++ src/conference/params/call-session-params.h | 44 +++++++++++++ .../params/media-session-params.cpp | 36 ++++++++++ src/conference/params/media-session-params.h | 41 ++++++++++++ src/conference/participant.cpp | 65 +++++++++++++++++++ src/conference/participant.h | 48 ++++++++++++++ src/conference/remote-conference.cpp | 35 ++++++++++ src/conference/remote-conference.h | 41 ++++++++++++ src/conference/session/call-session-p.h | 43 ++++++++++++ src/conference/session/call-session.cpp | 29 +++++++++ src/conference/session/call-session.h | 44 +++++++++++++ src/conference/session/media-session.cpp | 41 ++++++++++++ src/conference/session/media-session.h | 41 ++++++++++++ 25 files changed, 931 insertions(+) create mode 100644 src/call/call.cpp create mode 100644 src/call/call.h create mode 100644 src/conference/conference-listener.h create mode 100644 src/conference/conference-p.h create mode 100644 src/conference/conference.cpp create mode 100644 src/conference/conference.h create mode 100644 src/conference/local-conference.cpp create mode 100644 src/conference/local-conference.h create mode 100644 src/conference/params/call-session-params-p.h create mode 100644 src/conference/params/call-session-params.cpp create mode 100644 src/conference/params/call-session-params.h create mode 100644 src/conference/params/media-session-params.cpp create mode 100644 src/conference/params/media-session-params.h create mode 100644 src/conference/participant.cpp create mode 100644 src/conference/participant.h create mode 100644 src/conference/remote-conference.cpp create mode 100644 src/conference/remote-conference.h create mode 100644 src/conference/session/call-session-p.h create mode 100644 src/conference/session/call-session.cpp create mode 100644 src/conference/session/call-session.h create mode 100644 src/conference/session/media-session.cpp create mode 100644 src/conference/session/media-session.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 94c5f0f96..c744240b8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,8 +24,21 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES address/address-p.h address/address.h c-wrapper/c-tools.h + call/call.h chat/chat-room-p.h chat/chat-room.h + conference/conference.h + conference/conference-listener.h + conference/conference-p.h + conference/local-conference.h + conference/params/call-session-params.h + conference/params/call-session-params-p.h + conference/params/media-session-params.h + conference/participant.h + conference/remote-conference.h + conference/session/call-session.h + conference/session/call-session-p.h + conference/session/media-session.h content/content.h core/core.h chat/imdn.h @@ -66,11 +79,20 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES address/address.cpp c-wrapper/api/c-address.cpp c-wrapper/api/c-event-log.cpp + call/call.cpp chat/chat-room.cpp content/content.cpp core/core.cpp chat/imdn.cpp chat/is-composing.cpp + conference/conference.cpp + conference/local-conference.cpp + conference/params/call-session-params.cpp + conference/params/media-session-params.cpp + conference/participant.cpp + conference/remote-conference.cpp + conference/session/call-session.cpp + conference/session/media-session.cpp cpim/header/cpim-core-headers.cpp cpim/header/cpim-generic-header.cpp cpim/header/cpim-header.cpp diff --git a/src/call/call.cpp b/src/call/call.cpp new file mode 100644 index 000000000..b5c8d88e9 --- /dev/null +++ b/src/call/call.cpp @@ -0,0 +1,54 @@ +/* + * call.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "object/object-p.h" + +#include "call.h" + +using namespace std; + +using namespace LinphonePrivate; + +// ============================================================================= + +class Call::CallPrivate : public ObjectPrivate { +public: + LinphoneCallDir direction; + LinphoneCallState state = LinphoneCallIdle; +}; + +// ============================================================================= + +Call::Call::Call (LinphoneCallDir direction) : Object(*new CallPrivate) { + L_D(Call); + d->direction = direction; +} + +// ----------------------------------------------------------------------------- + +LinphoneCallDir Call::Call::getDirection () const { + L_D(const Call); + return d->direction; +} + +// ----------------------------------------------------------------------------- + +LinphoneCallState Call::Call::getState () const { + L_D(const Call); + return d->state; +} diff --git a/src/call/call.h b/src/call/call.h new file mode 100644 index 000000000..03c6af06a --- /dev/null +++ b/src/call/call.h @@ -0,0 +1,46 @@ +/* + * call.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CALL_CALL_H_ +#define _CALL_CALL_H_ + +#include "linphone/types.h" + +#include "object/object.h" + +// ============================================================================= + +namespace LinphonePrivate { + namespace Call { + class CallPrivate; + + class Call : public Object { + public: + Call (LinphoneCallDir direction); + + LinphoneCallDir getDirection() const; + LinphoneCallState getState() const; + + private: + L_DECLARE_PRIVATE(Call); + L_DISABLE_COPY(Call); + }; + } +} + +#endif // ifndef _CALL_CALL_H_ diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 3aeac16d8..72d37c6ca 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -995,3 +995,4 @@ const LinphoneAddress *ChatRoom::getPeerAddress () const { } LINPHONE_END_NAMESPACE + diff --git a/src/chat/chat-room.h b/src/chat/chat-room.h index 9584b3304..d3052d711 100644 --- a/src/chat/chat-room.h +++ b/src/chat/chat-room.h @@ -68,3 +68,4 @@ private: LINPHONE_END_NAMESPACE #endif // ifndef _CHAT_ROOM_H_ + diff --git a/src/conference/conference-listener.h b/src/conference/conference-listener.h new file mode 100644 index 000000000..80d312395 --- /dev/null +++ b/src/conference/conference-listener.h @@ -0,0 +1,37 @@ +/* + * conference-listener.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CONFERENCE_LISTENER_H_ +#define _CONFERENCE_LISTENER_H_ + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ConferenceListener : public Object { +public: + virtual void conferenceCreated (LinphoneAddress *addr) = 0; + virtual void conferenceTerminated (LinphoneAddress *addr) = 0; + virtual void participantAdded (LinphoneAddress *addr) = 0; + virtual void participantRemoved (LinphoneAddress *addr) = 0; + virtual void participantSetAdmin (LinphoneAddress *addr, bool isAdmin) = 0; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CONFERENCE_LISTENER_H_ diff --git a/src/conference/conference-p.h b/src/conference/conference-p.h new file mode 100644 index 000000000..7584b8ebf --- /dev/null +++ b/src/conference/conference-p.h @@ -0,0 +1,43 @@ +/* + * conference-p.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CONFERENCE_P_H_ +#define _CONFERENCE_P_H_ + +#include "object/object-p.h" + +#include "conference.h" + +#include + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ConferencePrivate : public ObjectPrivate { +public: + virtual ~ConferencePrivate () = default; + + std::string confId; + + L_DECLARE_PUBLIC(Conference); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CONFERENCE_P_H_ diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp new file mode 100644 index 000000000..b5072d3e9 --- /dev/null +++ b/src/conference/conference.cpp @@ -0,0 +1,29 @@ +/* + * conference.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "conference-p.h" + +#include "conference.h" + +LINPHONE_BEGIN_NAMESPACE + +// ============================================================================= + +Conference::Conference (ConferencePrivate &p) : Object(p) {} + +LINPHONE_END_NAMESPACE diff --git a/src/conference/conference.h b/src/conference/conference.h new file mode 100644 index 000000000..aa76a0cde --- /dev/null +++ b/src/conference/conference.h @@ -0,0 +1,44 @@ +/* + * conference.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CONFERENCE_H_ +#define _CONFERENCE_H_ + +#include "object/object.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ConferencePrivate; + +class Conference : public Object { +public: + Conference (); + +protected: + explicit Conference (ConferencePrivate &p); + +private: + L_DECLARE_PRIVATE(Conference); + L_DISABLE_COPY(Conference); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CONFERENCE_H_ diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp new file mode 100644 index 000000000..c330e5e5b --- /dev/null +++ b/src/conference/local-conference.cpp @@ -0,0 +1,35 @@ +/* + * local-conference.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "conference-p.h" + +#include "local-conference.h" + +LINPHONE_BEGIN_NAMESPACE + +// ============================================================================= + +class LocalConferencePrivate : public ConferencePrivate { +public: +}; + +// ============================================================================= + +LocalConference::LocalConference () : Conference(*new LocalConferencePrivate) {} + +LINPHONE_END_NAMESPACE diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h new file mode 100644 index 000000000..7ff04d176 --- /dev/null +++ b/src/conference/local-conference.h @@ -0,0 +1,41 @@ +/* + * local-conference.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _LOCAL_CONFERENCE_H_ +#define _LOCAL_CONFERENCE_H_ + +#include "conference.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class LocalConferencePrivate; + +class LocalConference : public Conference { +public: + LocalConference (); + +private: + L_DECLARE_PRIVATE(LocalConference); + L_DISABLE_COPY(LocalConference); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _LOCAL_CONFERENCE_H_ diff --git a/src/conference/params/call-session-params-p.h b/src/conference/params/call-session-params-p.h new file mode 100644 index 000000000..0ff9181e1 --- /dev/null +++ b/src/conference/params/call-session-params-p.h @@ -0,0 +1,43 @@ +/* + * call-session-params-p.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CONFERENCE_CALL_SESSION_PARAMS_P_H_ +#define _CONFERENCE_CALL_SESSION_PARAMS_P_H_ + +#include "object/object-p.h" + +#include "call-session-params.h" + +#include "linphone/types.h" + +// ============================================================================= + +namespace LinphonePrivate { + namespace Conference { + class CallSessionParamsPrivate : public ObjectPrivate { + public: + virtual ~CallSessionParamsPrivate () = default; + + LinphonePrivacyMask privacy = LinphonePrivacyNone; + + L_DECLARE_PUBLIC(CallSessionParams); + }; + } +} + +#endif // ifndef _CONFERENCE_CALL_SESSION_PARAMS_P_H_ diff --git a/src/conference/params/call-session-params.cpp b/src/conference/params/call-session-params.cpp new file mode 100644 index 000000000..bfab89a94 --- /dev/null +++ b/src/conference/params/call-session-params.cpp @@ -0,0 +1,27 @@ +/* + * call-session-params.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "call-session-params-p.h" + +#include "call-session-params.h" + +using namespace LinphonePrivate; + +// ============================================================================= + +Conference::CallSessionParams::CallSessionParams (CallSessionParamsPrivate &p) : Object(p) {} diff --git a/src/conference/params/call-session-params.h b/src/conference/params/call-session-params.h new file mode 100644 index 000000000..8414987f6 --- /dev/null +++ b/src/conference/params/call-session-params.h @@ -0,0 +1,44 @@ +/* + * call-session-params.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CONFERENCE_CALL_SESSION_PARAMS_H_ +#define _CONFERENCE_CALL_SESSION_PARAMS_H_ + +#include "object/object.h" + +// ============================================================================= + +namespace LinphonePrivate { + namespace Conference { + class CallSessionParamsPrivate; + + class CallSessionParams : public Object { + public: + CallSessionParams (); + + protected: + explicit CallSessionParams (CallSessionParamsPrivate &p); + + private: + L_DECLARE_PRIVATE(CallSessionParams); + L_DISABLE_COPY(CallSessionParams); + }; + } +} + +#endif // ifndef _CONFERENCE_CALL_SESSION_PARAMS_H_ diff --git a/src/conference/params/media-session-params.cpp b/src/conference/params/media-session-params.cpp new file mode 100644 index 000000000..028b04bfe --- /dev/null +++ b/src/conference/params/media-session-params.cpp @@ -0,0 +1,36 @@ +/* + * media-session-params.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "call-session-params-p.h" + +#include "media-session-params.h" + +#include "linphone/types.h" + +using namespace LinphonePrivate; + +// ============================================================================= + +class Conference::MediaSessionParamsPrivate : public CallSessionParamsPrivate { +public: + LinphoneMediaEncryption encryption = LinphoneMediaEncryptionNone; +}; + +// ============================================================================= + +Conference::MediaSessionParams::MediaSessionParams () : CallSessionParams(*new MediaSessionParamsPrivate) {} diff --git a/src/conference/params/media-session-params.h b/src/conference/params/media-session-params.h new file mode 100644 index 000000000..6b9ef351c --- /dev/null +++ b/src/conference/params/media-session-params.h @@ -0,0 +1,41 @@ +/* + * media-session-params.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CONFERENCE_MEDIA_SESSION_PARAMS_H_ +#define _CONFERENCE_MEDIA_SESSION_PARAMS_H_ + +#include "call-session-params.h" + +// ============================================================================= + +namespace LinphonePrivate { + namespace Conference { + class MediaSessionParamsPrivate; + + class MediaSessionParams : public CallSessionParams { + public: + MediaSessionParams (); + + private: + L_DECLARE_PRIVATE(MediaSessionParams); + L_DISABLE_COPY(MediaSessionParams); + }; + } +} + +#endif // ifndef _CONFERENCE_MEDIA_SESSION_PARAMS_H_ diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp new file mode 100644 index 000000000..c636c1e6d --- /dev/null +++ b/src/conference/participant.cpp @@ -0,0 +1,65 @@ +/* + * participant.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "object/object-p.h" + +#include "participant.h" + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +// ============================================================================= + +class ParticipantPrivate : public ObjectPrivate { +public: + ~ParticipantPrivate (); + + Address addr; + bool isAdmin = false; +}; + +ParticipantPrivate::~ParticipantPrivate() {} + +// ============================================================================= + +Participant::Participant (const Address &addr) : Object(*new ParticipantPrivate) { + L_D(Participant); + d->addr = addr; +} + +// ----------------------------------------------------------------------------- + +const Address& Participant::getAddress () const { + L_D(const Participant); + return d->addr; +} + +// ----------------------------------------------------------------------------- + +bool Participant::isAdmin () const { + L_D(const Participant); + return d->isAdmin; +} + +void Participant::setAdmin (bool isAdmin) { + L_D(Participant); + d->isAdmin = isAdmin; +} + +LINPHONE_END_NAMESPACE diff --git a/src/conference/participant.h b/src/conference/participant.h new file mode 100644 index 000000000..8a6ce2bca --- /dev/null +++ b/src/conference/participant.h @@ -0,0 +1,48 @@ +/* + * participant.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _PARTICIPANT_H_ +#define _PARTICIPANT_H_ + +#include "address/address.h" + +#include "object/object.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ParticipantPrivate; + +class Participant : public Object { +public: + Participant (const Address &addr); + + const Address& getAddress () const; + + bool isAdmin () const; + void setAdmin (bool isAdmin); + +private: + L_DECLARE_PRIVATE(Participant); + L_DISABLE_COPY(Participant); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _PARTICIPANT_H_ diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp new file mode 100644 index 000000000..d73e2a17a --- /dev/null +++ b/src/conference/remote-conference.cpp @@ -0,0 +1,35 @@ +/* + * remote-conference.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "conference-p.h" + +#include "remote-conference.h" + +LINPHONE_BEGIN_NAMESPACE + +// ============================================================================= + +class RemoteConferencePrivate : public ConferencePrivate { +public: +}; + +// ============================================================================= + +RemoteConference::RemoteConference () : Conference(*new RemoteConferencePrivate) {} + +LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h new file mode 100644 index 000000000..f6f456936 --- /dev/null +++ b/src/conference/remote-conference.h @@ -0,0 +1,41 @@ +/* + * remote-conference.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _REMOTE_CONFERENCE_H_ +#define _REMOTE_CONFERENCE_H_ + +#include "conference.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class RemoteConferencePrivate; + +class RemoteConference : public Conference { +public: + RemoteConference (); + +private: + L_DECLARE_PRIVATE(RemoteConference); + L_DISABLE_COPY(RemoteConference); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _REMOTE_CONFERENCE_H_ diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h new file mode 100644 index 000000000..e74d5b4a8 --- /dev/null +++ b/src/conference/session/call-session-p.h @@ -0,0 +1,43 @@ +/* + * call-session-p.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CALL_SESSION_P_H_ +#define _CALL_SESSION_P_H_ + +#include "object/object-p.h" + +#include "call-session.h" + +#include "bellesip_sal/sal_impl.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class CallSessionPrivate : public ObjectPrivate { +public: + virtual ~CallSessionPrivate () = default; + + SalOp *op; + + L_DECLARE_PUBLIC(CallSession); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CALL_SESSION_P_H_ diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp new file mode 100644 index 000000000..1bae79848 --- /dev/null +++ b/src/conference/session/call-session.cpp @@ -0,0 +1,29 @@ +/* + * call-session.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "call-session-p.h" + +#include "call-session.h" + +LINPHONE_BEGIN_NAMESPACE + +// ============================================================================= + +CallSession::CallSession (CallSessionPrivate &p) : Object(p) {} + +LINPHONE_END_NAMESPACE diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h new file mode 100644 index 000000000..fb6e9de78 --- /dev/null +++ b/src/conference/session/call-session.h @@ -0,0 +1,44 @@ +/* + * call-session.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CALL_SESSION_H_ +#define _CALL_SESSION_H_ + +#include "object/object.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class CallSessionPrivate; + +class CallSession : public Object { +public: + CallSession (); + +protected: + explicit CallSession (CallSessionPrivate &p); + +private: + L_DECLARE_PRIVATE(CallSession); + L_DISABLE_COPY(CallSession); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CALL_SESSION_H_ diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp new file mode 100644 index 000000000..0b4faf9ad --- /dev/null +++ b/src/conference/session/media-session.cpp @@ -0,0 +1,41 @@ +/* + * media-session.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "call-session-p.h" + +#include "media-session.h" + +#include + +LINPHONE_BEGIN_NAMESPACE + +// ============================================================================= + +class MediaSessionPrivate : public CallSessionPrivate { +public: + AudioStream *audioStream = nullptr; + VideoStream *videoStream = nullptr; + TextStream *textStream = nullptr; + IceSession *iceSession = nullptr; +}; + +// ============================================================================= + +MediaSession::MediaSession () : CallSession(*new MediaSessionPrivate) {} + +LINPHONE_END_NAMESPACE diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h new file mode 100644 index 000000000..898ad283b --- /dev/null +++ b/src/conference/session/media-session.h @@ -0,0 +1,41 @@ +/* + * media-session.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _MEDIA_SESSION_H_ +#define _MEDIA_SESSION_H_ + +#include "call-session.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class MediaSessionPrivate; + +class MediaSession : public CallSession { +public: + MediaSession (); + +private: + L_DECLARE_PRIVATE(MediaSession); + L_DISABLE_COPY(MediaSession); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _MEDIA_SESSION_H_ From d795a30518c4a5dd66ab52b069989ab5a731197a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 8 Aug 2017 14:04:23 +0200 Subject: [PATCH 0019/2215] Convert LinphoneCallParams to use MediaSessionParams C++ class. --- coreapi/call_params.c | 486 +++++++++++------- coreapi/callbacks.c | 27 +- coreapi/conference.cc | 28 +- coreapi/linphonecall.c | 324 ++++++------ coreapi/linphonecore.c | 50 +- coreapi/misc.c | 28 +- coreapi/private.h | 80 ++- coreapi/quality_reporting.c | 6 +- include/linphone/call_params.h | 10 + src/CMakeLists.txt | 1 + src/conference/params/call-session-params-p.h | 62 ++- src/conference/params/call-session-params.cpp | 167 +++++- src/conference/params/call-session-params.h | 92 +++- .../params/media-session-params-p.h | 100 ++++ .../params/media-session-params.cpp | 304 ++++++++++- src/conference/params/media-session-params.h | 134 ++++- tester/call_single_tester.c | 2 +- tester/call_video_tester.c | 2 +- tester/tester.c | 2 +- 19 files changed, 1388 insertions(+), 517 deletions(-) create mode 100644 src/conference/params/media-session-params-p.h diff --git a/coreapi/call_params.c b/coreapi/call_params.c index b1bbf7d20..a6f95b940 100644 --- a/coreapi/call_params.c +++ b/coreapi/call_params.c @@ -20,18 +20,26 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/call_params.h" #include "private.h" +#include "conference/params/media-session-params.h" +#include "conference/params/call-session-params-p.h" +#include "conference/params/media-session-params-p.h" + + +struct _LinphoneCallParams{ + belle_sip_object_t base; + void *user_data; + LinphonePrivate::MediaSessionParams *msp; +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneCallParams); + /******************************************************************************* * Internal functions * ******************************************************************************/ SalMediaProto get_proto_from_call_params(const LinphoneCallParams *params) { - if ((params->media_encryption == LinphoneMediaEncryptionSRTP) && params->avpf_enabled) return SalProtoRtpSavpf; - if (params->media_encryption == LinphoneMediaEncryptionSRTP) return SalProtoRtpSavp; - if ((params->media_encryption == LinphoneMediaEncryptionDTLS) && params->avpf_enabled) return SalProtoUdpTlsRtpSavpf; - if (params->media_encryption == LinphoneMediaEncryptionDTLS) return SalProtoUdpTlsRtpSavp; - if (params->avpf_enabled) return SalProtoRtpAvpf; - return SalProtoRtpAvp; + return params->msp->getMediaProto(); } SalStreamDir sal_dir_from_call_params_dir(LinphoneMediaDirection cpdir) { @@ -73,34 +81,16 @@ SalStreamDir get_video_dir_from_call_params(const LinphoneCallParams *params) { return sal_dir_from_call_params_dir(linphone_call_params_get_video_direction(params)); } -void linphone_call_params_set_custom_headers(LinphoneCallParams *params, const SalCustomHeader *ch){ - if (params->custom_headers){ - sal_custom_header_free(params->custom_headers); - params->custom_headers = NULL; - } - if (ch){ - params->custom_headers = sal_custom_header_clone(ch); - } +void linphone_call_params_set_custom_headers(LinphoneCallParams *params, const SalCustomHeader *ch) { + static_cast(params->msp)->getPrivate()->setCustomHeaders(ch); } void linphone_call_params_set_custom_sdp_attributes(LinphoneCallParams *params, const SalCustomSdpAttribute *csa) { - if (params->custom_sdp_attributes) { - sal_custom_sdp_attribute_free(params->custom_sdp_attributes); - params->custom_sdp_attributes = NULL; - } - if (csa) { - params->custom_sdp_attributes = sal_custom_sdp_attribute_clone(csa); - } + static_cast(params->msp)->getPrivate()->setCustomSdpAttributes(csa); } void linphone_call_params_set_custom_sdp_media_attributes(LinphoneCallParams *params, LinphoneStreamType type, const SalCustomSdpAttribute *csa) { - if (params->custom_sdp_media_attributes[type]) { - sal_custom_sdp_attribute_free(params->custom_sdp_media_attributes[type]); - params->custom_sdp_media_attributes[type] = NULL; - } - if (csa) { - params->custom_sdp_media_attributes[type] = sal_custom_sdp_attribute_clone(csa); - } + static_cast(params->msp)->getPrivate()->setCustomSdpMediaAttributes(type, csa); } @@ -108,202 +98,392 @@ void linphone_call_params_set_custom_sdp_media_attributes(LinphoneCallParams *pa * Public functions * ******************************************************************************/ -void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value){ - params->custom_headers=sal_custom_header_append(params->custom_headers,header_name,header_value); +void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value) { + params->msp->addCustomHeader(header_name, header_value); } void linphone_call_params_add_custom_sdp_attribute(LinphoneCallParams *params, const char *attribute_name, const char *attribute_value) { - params->custom_sdp_attributes = sal_custom_sdp_attribute_append(params->custom_sdp_attributes, attribute_name, attribute_value); + params->msp->addCustomSdpAttribute(attribute_name, attribute_value); } void linphone_call_params_add_custom_sdp_media_attribute(LinphoneCallParams *params, LinphoneStreamType type, const char *attribute_name, const char *attribute_value) { - params->custom_sdp_media_attributes[type] = sal_custom_sdp_attribute_append(params->custom_sdp_media_attributes[type], attribute_name, attribute_value); + params->msp->addCustomSdpMediaAttribute(type, attribute_name, attribute_value); } void linphone_call_params_clear_custom_sdp_attributes(LinphoneCallParams *params) { - linphone_call_params_set_custom_sdp_attributes(params, NULL); + params->msp->clearCustomSdpAttributes(); } void linphone_call_params_clear_custom_sdp_media_attributes(LinphoneCallParams *params, LinphoneStreamType type) { - linphone_call_params_set_custom_sdp_media_attributes(params, type, NULL); + params->msp->clearCustomSdpMediaAttributes(type); } -LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){ - return (LinphoneCallParams *)belle_sip_object_clone((const belle_sip_object_t *)cp); +LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *params) { + return (LinphoneCallParams *)belle_sip_object_clone((const belle_sip_object_t *)params); } -bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){ - return cp->real_early_media; +bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *params) { + return params->msp->earlyMediaSendingEnabled(); } -void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){ - cp->real_early_media=enabled; +void linphone_call_params_enable_early_media_sending(LinphoneCallParams *params, bool_t enabled) { + params->msp->enableEarlyMediaSending(enabled); } -void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){ - cp->low_bandwidth=enabled; +void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *params, bool_t enabled) { + params->msp->enableLowBandwidth(enabled); } -void linphone_call_params_enable_audio(LinphoneCallParams *cp, bool_t enabled){ - cp->has_audio=enabled; - if (enabled && cp->audio_dir==LinphoneMediaDirectionInactive) - cp->audio_dir=LinphoneMediaDirectionSendRecv; +void linphone_call_params_enable_audio(LinphoneCallParams *params, bool_t enabled) { + params->msp->enableAudio(enabled); } LinphoneStatus linphone_call_params_enable_realtime_text(LinphoneCallParams *params, bool_t yesno) { - params->realtimetext_enabled=yesno; + params->msp->enableRealtimeText(yesno); return 0; } -void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){ - cp->has_video=enabled; - if (enabled && cp->video_dir==LinphoneMediaDirectionInactive) - cp->video_dir=LinphoneMediaDirectionSendRecv; +void linphone_call_params_enable_video(LinphoneCallParams *params, bool_t enabled) { + params->msp->enableVideo(enabled); } -const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name){ - return sal_custom_header_find(params->custom_headers,header_name); +const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name) { + std::string value = params->msp->getCustomHeader(header_name); + return value.empty() ? nullptr : value.c_str(); } const char * linphone_call_params_get_custom_sdp_attribute(const LinphoneCallParams *params, const char *attribute_name) { - return sal_custom_sdp_attribute_find(params->custom_sdp_attributes, attribute_name); + std::string value = params->msp->getCustomSdpAttribute(attribute_name); + return value.empty() ? nullptr : value.c_str(); } const char * linphone_call_params_get_custom_sdp_media_attribute(const LinphoneCallParams *params, LinphoneStreamType type, const char *attribute_name) { - return sal_custom_sdp_attribute_find(params->custom_sdp_media_attributes[type], attribute_name); + std::string value = params->msp->getCustomSdpMediaAttribute(type, attribute_name); + return value.empty() ? nullptr : value.c_str(); } -bool_t linphone_call_params_get_local_conference_mode(const LinphoneCallParams *cp){ - return cp->in_conference; +bool_t linphone_call_params_get_local_conference_mode(const LinphoneCallParams *params) { + return linphone_call_params_get_in_conference(params); } -LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) { - return cp->media_encryption; +LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *params) { + return params->msp->getMediaEncryption(); } LinphonePrivacyMask linphone_call_params_get_privacy(const LinphoneCallParams *params) { - return params->privacy; + return params->msp->getPrivacy(); } -float linphone_call_params_get_received_framerate(const LinphoneCallParams *cp){ - return cp->received_fps; +float linphone_call_params_get_received_framerate(const LinphoneCallParams *params) { + return params->msp->getReceivedFps(); } -MSVideoSize linphone_call_params_get_received_video_size(const LinphoneCallParams *cp) { - return cp->recv_vsize; +MSVideoSize linphone_call_params_get_received_video_size(const LinphoneCallParams *params) { + MSVideoSize vsize; + LinphoneVideoDefinition *vdef = params->msp->getReceivedVideoDefinition(); + if (vdef) { + vsize.width = linphone_video_definition_get_width(vdef); + vsize.height = linphone_video_definition_get_height(vdef); + } else { + vsize.width = MS_VIDEO_SIZE_UNKNOWN_W; + vsize.height = MS_VIDEO_SIZE_UNKNOWN_H; + } + return vsize; } -const LinphoneVideoDefinition * linphone_call_params_get_received_video_definition(const LinphoneCallParams *cp) { - return cp->recv_vdef; +const LinphoneVideoDefinition * linphone_call_params_get_received_video_definition(const LinphoneCallParams *params) { + return params->msp->getReceivedVideoDefinition(); } -const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp){ - return cp->record_file; +const char *linphone_call_params_get_record_file(const LinphoneCallParams *params) { + const std::string &value = params->msp->getRecordFilePath(); + return value.empty() ? nullptr : value.c_str(); } -const char * linphone_call_params_get_rtp_profile(const LinphoneCallParams *cp) { - return sal_media_proto_to_string(get_proto_from_call_params(cp)); +const char * linphone_call_params_get_rtp_profile(const LinphoneCallParams *params) { + return params->msp->getRtpProfile(); } -float linphone_call_params_get_sent_framerate(const LinphoneCallParams *cp){ - return cp->sent_fps; +float linphone_call_params_get_sent_framerate(const LinphoneCallParams *params) { + return params->msp->getSentFps(); } -MSVideoSize linphone_call_params_get_sent_video_size(const LinphoneCallParams *cp) { - return cp->sent_vsize; +MSVideoSize linphone_call_params_get_sent_video_size(const LinphoneCallParams *params) { + MSVideoSize vsize; + LinphoneVideoDefinition *vdef = params->msp->getSentVideoDefinition(); + if (vdef) { + vsize.width = linphone_video_definition_get_width(vdef); + vsize.height = linphone_video_definition_get_height(vdef); + } else { + vsize.width = MS_VIDEO_SIZE_UNKNOWN_W; + vsize.height = MS_VIDEO_SIZE_UNKNOWN_H; + } + return vsize; } -const LinphoneVideoDefinition * linphone_call_params_get_sent_video_definition(const LinphoneCallParams *cp) { - return cp->sent_vdef; +const LinphoneVideoDefinition * linphone_call_params_get_sent_video_definition(const LinphoneCallParams *params) { + return params->msp->getSentVideoDefinition(); } -const char *linphone_call_params_get_session_name(const LinphoneCallParams *cp){ - return cp->session_name; +const char *linphone_call_params_get_session_name(const LinphoneCallParams *params) { + const std::string &value = params->msp->getSessionName(); + return value.empty() ? nullptr : value.c_str(); } -LinphonePayloadType *linphone_call_params_get_used_audio_payload_type(const LinphoneCallParams *cp) { - return cp->audio_codec ? linphone_payload_type_new(NULL, cp->audio_codec) : NULL; +LinphonePayloadType *linphone_call_params_get_used_audio_payload_type(const LinphoneCallParams *params) { + return params->msp->getUsedAudioPayloadType(); } -LinphonePayloadType *linphone_call_params_get_used_video_payload_type(const LinphoneCallParams *cp) { - return cp->video_codec ? linphone_payload_type_new(NULL, cp->video_codec) : NULL; +LinphonePayloadType *linphone_call_params_get_used_video_payload_type(const LinphoneCallParams *params) { + return params->msp->getUsedVideoPayloadType(); } -LinphonePayloadType *linphone_call_params_get_used_text_payload_type(const LinphoneCallParams *cp) { - return cp->text_codec ? linphone_payload_type_new(NULL, cp->text_codec) : NULL; +LinphonePayloadType *linphone_call_params_get_used_text_payload_type(const LinphoneCallParams *params) { + return params->msp->getUsedRealtimeTextPayloadType(); } -const OrtpPayloadType *linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) { - return cp->audio_codec; +const OrtpPayloadType *linphone_call_params_get_used_audio_codec(const LinphoneCallParams *params) { + return params->msp->getUsedAudioCodec(); } -const OrtpPayloadType *linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) { - return cp->video_codec; +void linphone_call_params_set_used_audio_codec(LinphoneCallParams *params, OrtpPayloadType *codec) { + params->msp->getPrivate()->setUsedAudioCodec(codec); } -const OrtpPayloadType *linphone_call_params_get_used_text_codec(const LinphoneCallParams *cp) { - return cp->text_codec; +const OrtpPayloadType *linphone_call_params_get_used_video_codec(const LinphoneCallParams *params) { + return params->msp->getUsedVideoCodec(); } - -bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) { - return cp->low_bandwidth; +void linphone_call_params_set_used_video_codec(LinphoneCallParams *params, OrtpPayloadType *codec) { + params->msp->getPrivate()->setUsedVideoCodec(codec); } -void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){ - cp->audio_bw=bandwidth; +const OrtpPayloadType *linphone_call_params_get_used_text_codec(const LinphoneCallParams *params) { + return params->msp->getUsedRealtimeTextCodec(); } -void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, LinphoneMediaEncryption e) { - cp->media_encryption = e; +void linphone_call_params_set_used_text_codec(LinphoneCallParams *params, OrtpPayloadType *codec) { + params->msp->getPrivate()->setUsedRealtimeTextCodec(codec); +} + +bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *params) { + return params->msp->lowBandwidthEnabled(); +} + +int linphone_call_params_get_audio_bandwidth_limit(const LinphoneCallParams *params) { + return params->msp->getAudioBandwidthLimit(); +} + +void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *params, int bandwidth) { + params->msp->setAudioBandwidthLimit(bandwidth); +} + +void linphone_call_params_set_media_encryption(LinphoneCallParams *params, LinphoneMediaEncryption encryption) { + params->msp->setMediaEncryption(encryption); } void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacyMask privacy) { - params->privacy=privacy; + params->msp->setPrivacy(privacy); } -void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path){ - if (cp->record_file){ - ms_free(cp->record_file); - cp->record_file=NULL; - } - if (path) cp->record_file=ms_strdup(path); +void linphone_call_params_set_record_file(LinphoneCallParams *params, const char *path) { + params->msp->setRecordFilePath(path ? path : ""); } -void linphone_call_params_set_session_name(LinphoneCallParams *cp, const char *name){ - if (cp->session_name){ - ms_free(cp->session_name); - cp->session_name=NULL; - } - if (name) cp->session_name=ms_strdup(name); +void linphone_call_params_set_session_name(LinphoneCallParams *params, const char *name) { + params->msp->setSessionName(name ? name : ""); } -bool_t linphone_call_params_audio_enabled(const LinphoneCallParams *cp){ - return cp->has_audio; +bool_t linphone_call_params_audio_enabled(const LinphoneCallParams *params) { + return params->msp->audioEnabled(); } bool_t linphone_call_params_realtime_text_enabled(const LinphoneCallParams *params) { - return params->realtimetext_enabled; + return params->msp->realtimeTextEnabled(); } -bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){ - return cp->has_video; +bool_t linphone_call_params_video_enabled(const LinphoneCallParams *params) { + return params->msp->videoEnabled(); } -LinphoneMediaDirection linphone_call_params_get_audio_direction(const LinphoneCallParams *cp) { - return cp->audio_dir; +LinphoneMediaDirection linphone_call_params_get_audio_direction(const LinphoneCallParams *params) { + return params->msp->getAudioDirection(); } -LinphoneMediaDirection linphone_call_params_get_video_direction(const LinphoneCallParams *cp) { - return cp->video_dir; +LinphoneMediaDirection linphone_call_params_get_video_direction(const LinphoneCallParams *params) { + return params->msp->getVideoDirection(); } -void linphone_call_params_set_audio_direction(LinphoneCallParams *cp,LinphoneMediaDirection dir) { - cp->audio_dir=dir; +void linphone_call_params_set_audio_direction(LinphoneCallParams *params, LinphoneMediaDirection dir) { + params->msp->setAudioDirection(dir); } -void linphone_call_params_set_video_direction(LinphoneCallParams *cp,LinphoneMediaDirection dir) { - cp->video_dir=dir; +void linphone_call_params_set_video_direction(LinphoneCallParams *params, LinphoneMediaDirection dir) { + params->msp->setVideoDirection(dir); +} + +void linphone_call_params_enable_audio_multicast(LinphoneCallParams *params, bool_t yesno) { + params->msp->enableAudioMulticast(yesno); +} + +bool_t linphone_call_params_audio_multicast_enabled(const LinphoneCallParams *params) { + return params->msp->audioMulticastEnabled(); +} + +void linphone_call_params_enable_video_multicast(LinphoneCallParams *params, bool_t yesno) { + params->msp->enableVideoMulticast(yesno); +} +bool_t linphone_call_params_video_multicast_enabled(const LinphoneCallParams *params) { + return params->msp->videoMulticastEnabled(); +} + +bool_t linphone_call_params_real_early_media_enabled(const LinphoneCallParams *params) { + return params->msp->earlyMediaSendingEnabled(); +} + +bool_t linphone_call_params_avpf_enabled(const LinphoneCallParams *params) { + return params->msp->avpfEnabled(); +} + +void linphone_call_params_enable_avpf(LinphoneCallParams *params, bool_t enable) { + params->msp->enableAvpf(enable); +} + +bool_t linphone_call_params_mandatory_media_encryption_enabled(const LinphoneCallParams *params) { + return params->msp->mandatoryMediaEncryptionEnabled(); +} + +void linphone_call_params_enable_mandatory_media_encryption(LinphoneCallParams *params, bool_t value) { + params->msp->enableMandatoryMediaEncryption(value); +} + +uint16_t linphone_call_params_get_avpf_rr_interval(const LinphoneCallParams *params) { + return params->msp->getAvpfRrInterval(); +} + +void linphone_call_params_set_avpf_rr_interval(LinphoneCallParams *params, uint16_t value) { + params->msp->setAvpfRrInterval(value); +} + +void linphone_call_params_set_sent_fps(LinphoneCallParams *params, float value) { + params->msp->getPrivate()->setSentFps(value); +} + +void linphone_call_params_set_received_fps(LinphoneCallParams *params, float value) { + params->msp->getPrivate()->setReceivedFps(value); +} + + +/******************************************************************************* + * Private functions * + ******************************************************************************/ + +bool_t linphone_call_params_get_in_conference(const LinphoneCallParams *params) { + return static_cast(params->msp)->getPrivate()->getInConference(); +} + +void linphone_call_params_set_in_conference(LinphoneCallParams *params, bool_t value) { + static_cast(params->msp)->getPrivate()->setInConference(value); +} + +bool_t linphone_call_params_get_internal_call_update(const LinphoneCallParams *params) { + return static_cast(params->msp)->getPrivate()->getInternalCallUpdate(); +} + +void linphone_call_params_set_internal_call_update(LinphoneCallParams *params, bool_t value) { + static_cast(params->msp)->getPrivate()->setInternalCallUpdate(value); +} + +bool_t linphone_call_params_implicit_rtcp_fb_enabled(const LinphoneCallParams *params) { + return params->msp->getPrivate()->implicitRtcpFbEnabled(); +} + +void linphone_call_params_enable_implicit_rtcp_fb(LinphoneCallParams *params, bool_t value) { + params->msp->getPrivate()->enableImplicitRtcpFb(value); +} + +int linphone_call_params_get_down_bandwidth(const LinphoneCallParams *params) { + return params->msp->getPrivate()->getDownBandwidth(); +} + +void linphone_call_params_set_down_bandwidth(LinphoneCallParams *params, int value) { + params->msp->getPrivate()->setDownBandwidth(value); +} + +int linphone_call_params_get_up_bandwidth(const LinphoneCallParams *params) { + return params->msp->getPrivate()->getUpBandwidth(); +} + +void linphone_call_params_set_up_bandwidth(LinphoneCallParams *params, int value) { + params->msp->getPrivate()->setUpBandwidth(value); +} + +int linphone_call_params_get_down_ptime(const LinphoneCallParams *params) { + return params->msp->getPrivate()->getDownPtime(); +} + +void linphone_call_params_set_down_ptime(LinphoneCallParams *params, int value) { + params->msp->getPrivate()->setDownPtime(value); +} + +int linphone_call_params_get_up_ptime(const LinphoneCallParams *params) { + return params->msp->getPrivate()->getUpPtime(); +} + +void linphone_call_params_set_up_ptime(LinphoneCallParams *params, int value) { + params->msp->getPrivate()->setUpPtime(value); +} + +SalCustomHeader * linphone_call_params_get_custom_headers(const LinphoneCallParams *params) { + return static_cast(params->msp)->getPrivate()->getCustomHeaders(); +} + +SalCustomSdpAttribute * linphone_call_params_get_custom_sdp_attributes(const LinphoneCallParams *params) { + return static_cast(params->msp)->getPrivate()->getCustomSdpAttributes(); +} + +SalCustomSdpAttribute * linphone_call_params_get_custom_sdp_media_attributes(const LinphoneCallParams *params, LinphoneStreamType type) { + return static_cast(params->msp)->getPrivate()->getCustomSdpMediaAttributes(type); +} + +LinphoneCall * linphone_call_params_get_referer(const LinphoneCallParams *params) { + return static_cast(params->msp)->getPrivate()->getReferer(); +} + +void linphone_call_params_set_referer(LinphoneCallParams *params, LinphoneCall *referer) { + static_cast(params->msp)->getPrivate()->setReferer(referer); +} + +bool_t linphone_call_params_get_update_call_when_ice_completed(const LinphoneCallParams *params) { + return params->msp->getPrivate()->getUpdateCallWhenIceCompleted(); +} + +void linphone_call_params_set_update_call_when_ice_completed(LinphoneCallParams *params, bool_t value) { + params->msp->getPrivate()->setUpdateCallWhenIceCompleted(value); +} + +void linphone_call_params_set_sent_vsize(LinphoneCallParams *params, MSVideoSize vsize) { + params->msp->getPrivate()->setSentVideoDefinition(linphone_video_definition_new(vsize.width, vsize.height, nullptr)); +} + +void linphone_call_params_set_recv_vsize(LinphoneCallParams *params, MSVideoSize vsize) { + params->msp->getPrivate()->setReceivedVideoDefinition(linphone_video_definition_new(vsize.width, vsize.height, nullptr)); +} + +void linphone_call_params_set_sent_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef) { + params->msp->getPrivate()->setSentVideoDefinition(vdef); +} + +void linphone_call_params_set_received_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef) { + params->msp->getPrivate()->setReceivedVideoDefinition(vdef); +} + +bool_t linphone_call_params_get_no_user_consent(const LinphoneCallParams *params) { + return static_cast(params->msp)->getPrivate()->getNoUserConsent(); +} + +void linphone_call_params_set_no_user_consent(LinphoneCallParams *params, bool_t value) { + static_cast(params->msp)->getPrivate()->setNoUserConsent(value); } @@ -328,69 +508,23 @@ void linphone_call_params_unref(LinphoneCallParams *cp) { belle_sip_object_unref(cp); } -void linphone_call_params_enable_audio_multicast(LinphoneCallParams *params, bool_t yesno) { - params->audio_multicast_enabled=yesno; -} - -bool_t linphone_call_params_audio_multicast_enabled(const LinphoneCallParams *params) { - return params->audio_multicast_enabled; -} - -void linphone_call_params_enable_video_multicast(LinphoneCallParams *params, bool_t yesno) { - params->video_multicast_enabled=yesno; -} -bool_t linphone_call_params_video_multicast_enabled(const LinphoneCallParams *params) { - return params->video_multicast_enabled; -} /******************************************************************************* * Constructor and destructor functions * ******************************************************************************/ -static void _linphone_call_params_uninit(LinphoneCallParams *cp){ - unsigned int i; - if (cp->record_file) ms_free(cp->record_file); - if (cp->custom_headers) sal_custom_header_free(cp->custom_headers); - if (cp->custom_sdp_attributes) sal_custom_sdp_attribute_free(cp->custom_sdp_attributes); - for (i = 0; i < (unsigned int)LinphoneStreamTypeUnknown; i++) { - if (cp->custom_sdp_media_attributes[i]) sal_custom_sdp_attribute_free(cp->custom_sdp_media_attributes[i]); - } - if (cp->session_name) ms_free(cp->session_name); - if (cp->sent_vdef != NULL) linphone_video_definition_unref(cp->sent_vdef); - if (cp->recv_vdef != NULL) linphone_video_definition_unref(cp->recv_vdef); +static void _linphone_call_params_destroy(LinphoneCallParams *params) { + delete params->msp; } static void _linphone_call_params_clone(LinphoneCallParams *dst, const LinphoneCallParams *src) { - unsigned int i; - - /* - * Save the belle_sip_object_t part, copy the entire structure and restore the belle_sip_object_t part - */ - belle_sip_object_t tmp = dst->base; - memcpy(dst, src, sizeof(LinphoneCallParams)); - dst->base = tmp; - - if (src->sent_vdef) dst->sent_vdef = linphone_video_definition_ref(src->sent_vdef); - if (src->recv_vdef) dst->recv_vdef = linphone_video_definition_ref(src->recv_vdef); - if (src->record_file) dst->record_file=ms_strdup(src->record_file); - if (src->session_name) dst->session_name=ms_strdup(src->session_name); - /* - * The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient. - */ - if (src->custom_headers) dst->custom_headers=sal_custom_header_clone(src->custom_headers); - if (src->custom_sdp_attributes) dst->custom_sdp_attributes = sal_custom_sdp_attribute_clone(src->custom_sdp_attributes); - for (i = 0; i < (unsigned int)LinphoneStreamTypeUnknown; i++) { - if (src->custom_sdp_media_attributes[i]) dst->custom_sdp_media_attributes[i] = sal_custom_sdp_attribute_clone(src->custom_sdp_media_attributes[i]); - } + dst->msp = new LinphonePrivate::MediaSessionParams(*src->msp); } LinphoneCallParams * linphone_call_params_new(void) { - LinphoneCallParams *cp=belle_sip_object_new(LinphoneCallParams); - cp->audio_dir=LinphoneMediaDirectionSendRecv; - cp->video_dir=LinphoneMediaDirectionSendRecv; - cp->has_audio=TRUE; - cp->realtimetext_enabled = FALSE; - return cp; + LinphoneCallParams *params = belle_sip_object_new(LinphoneCallParams); + params->msp = new LinphonePrivate::MediaSessionParams(); + return params; } /* DEPRECATED */ @@ -401,7 +535,7 @@ void linphone_call_params_destroy(LinphoneCallParams *cp) { BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCallParams); BELLE_SIP_INSTANCIATE_VPTR(LinphoneCallParams, belle_sip_object_t, - (belle_sip_object_destroy_t)_linphone_call_params_uninit, + (belle_sip_object_destroy_t)_linphone_call_params_destroy, (belle_sip_object_clone_t)_linphone_call_params_clone, // clone NULL, // marshal FALSE diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 155d87db4..a96860fec 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -40,7 +40,8 @@ static int media_parameters_changed(LinphoneCall *call, SalMediaDescription *old int otherdesc_changed; char *tmp1=NULL; char *tmp2=NULL; - if (call->params->in_conference != call->current_params->in_conference) return SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION; + if (linphone_call_params_get_in_conference(call->params) != linphone_call_params_get_in_conference(call->current_params)) + return SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION; if (call->up_bw != linphone_core_get_upload_bandwidth(call->core)) return SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION; if (call->localdesc_changed) ms_message("Local description has changed: %s", tmp1 = sal_media_description_print_differences(call->localdesc_changed)); otherdesc_changed = sal_media_description_equals(oldmd, newmd); @@ -199,7 +200,7 @@ void linphone_call_update_streams(LinphoneCall *call, SalMediaDescription *new_m linphone_call_init_media_streams(call); } - if (call->params->real_early_media && (call->state == LinphoneCallOutgoingEarlyMedia)) { + if (linphone_call_params_real_early_media_enabled(call->params) && (call->state == LinphoneCallOutgoingEarlyMedia)) { prepare_early_media_forking(call); } linphone_call_start_media_streams(call, target_state); @@ -464,7 +465,7 @@ static void call_ringing(SalOp *h){ if (call==NULL) return; /*set privacy*/ - call->current_params->privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op); + linphone_call_params_set_privacy(call->current_params, (LinphonePrivacyMask)sal_op_get_privacy(call->op)); linphone_core_notify_display_status(lc,_("Remote ringing.")); @@ -543,10 +544,10 @@ static void process_call_accepted(LinphoneCore *lc, LinphoneCall *call, SalOp *o linphone_task_list_init(&tl); rmd=sal_call_get_remote_media_description(op); /*set privacy*/ - call->current_params->privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op); + linphone_call_params_set_privacy(call->current_params, (LinphonePrivacyMask)sal_op_get_privacy(call->op)); /*reset the internal call update flag, so it doesn't risk to be copied and used in further re-INVITEs*/ - if (call->params->internal_call_update) - call->params->internal_call_update = FALSE; + if (linphone_call_params_get_internal_call_update(call->params)) + linphone_call_params_set_internal_call_update(call->params, FALSE); #ifdef BUILD_UPNP @@ -585,7 +586,7 @@ static void process_call_accepted(LinphoneCore *lc, LinphoneCall *call, SalOp *o next_state = LinphoneCallPausedByRemote; next_state_str = "Call paused by remote"; }else{ - if (!call->params->in_conference) + if (!linphone_call_params_get_in_conference(call->params)) lc->current_call=call; next_state = LinphoneCallStreamsRunning; next_state_str = "Streams running"; @@ -993,22 +994,22 @@ static void call_failure(SalOp *op){ int i; for (i = 0; i < call->localdesc->nb_streams; i++) { if (!sal_stream_description_active(&call->localdesc->streams[i])) continue; - if (call->params->media_encryption == LinphoneMediaEncryptionSRTP) { - if (call->params->avpf_enabled == TRUE) { + if (linphone_call_params_get_media_encryption(call->params) == LinphoneMediaEncryptionSRTP) { + if (linphone_call_params_avpf_enabled(call->params) == TRUE) { if (i == 0) ms_message("Retrying call [%p] with SAVP", call); - call->params->avpf_enabled = FALSE; + linphone_call_params_enable_avpf(call->params, FALSE); linphone_call_restart_invite(call); return; } else if (!linphone_core_is_media_encryption_mandatory(lc)) { if (i == 0) ms_message("Retrying call [%p] with AVP", call); - call->params->media_encryption = LinphoneMediaEncryptionNone; + linphone_call_params_set_media_encryption(call->params, LinphoneMediaEncryptionNone); memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto)); linphone_call_restart_invite(call); return; } - } else if (call->params->avpf_enabled == TRUE) { + } else if (linphone_call_params_avpf_enabled(call->params) == TRUE) { if (i == 0) ms_message("Retrying call [%p] with AVP", call); - call->params->avpf_enabled = FALSE; + linphone_call_params_enable_avpf(call->params, FALSE); linphone_call_restart_invite(call); return; } diff --git a/coreapi/conference.cc b/coreapi/conference.cc index 50d1680c7..39a12916a 100644 --- a/coreapi/conference.cc +++ b/coreapi/conference.cc @@ -415,7 +415,7 @@ int LocalConference::inviteAddresses(const std::list &ad LinphoneCallParams * new_params = params ? linphone_call_params_copy(params) : linphone_core_create_call_params(m_core, NULL); LinphoneCall *call; /*toggle this flag so the call is immediately added to the conference upon acceptance*/ - new_params->in_conference = TRUE; + linphone_call_params_set_in_conference(new_params, TRUE); linphone_call_params_enable_video(new_params, FALSE); /*turn off video as it is not supported for conferencing at this time*/ call = linphone_core_invite_address_with_params(m_core, addr, new_params); if (!call){ @@ -424,7 +424,7 @@ int LocalConference::inviteAddresses(const std::list &ad linphone_call_params_unref(new_params); }else{ /*there is already a call to this address, so simply join it to the local conference if not already done*/ - if (!call->current_params->in_conference) + if (!linphone_call_params_get_in_conference(call->current_params)) addParticipant(call); } /*if the local participant is not yet created, created it and it to the conference */ @@ -434,19 +434,19 @@ int LocalConference::inviteAddresses(const std::list &ad } int LocalConference::addParticipant(LinphoneCall *call) { - if (call->current_params->in_conference){ + if (linphone_call_params_get_in_conference(call->current_params)){ ms_error("Already in conference"); return -1; } if (call->state==LinphoneCallPaused){ - call->params->in_conference=TRUE; - call->params->has_video=FALSE; + linphone_call_params_set_in_conference(call->params, TRUE); + linphone_call_params_enable_video(call->params, FALSE); linphone_call_resume(call); }else if (call->state==LinphoneCallStreamsRunning){ LinphoneCallParams *params = linphone_core_create_call_params(m_core, call); - params->in_conference=TRUE; - params->has_video=FALSE; + linphone_call_params_set_in_conference(params, TRUE); + linphone_call_params_enable_video(params, FALSE); if (call->audiostream || call->videostream){ linphone_call_stop_media_streams(call); /*free the audio & video local resources*/ @@ -471,8 +471,8 @@ int LocalConference::removeFromConference(LinphoneCall *call, bool_t active){ int err=0; char *str; - if (!call->current_params->in_conference){ - if (call->params->in_conference){ + if (!linphone_call_params_get_in_conference(call->current_params)){ + if (linphone_call_params_get_in_conference(call->params)){ ms_warning("Not (yet) in conference, be patient"); return -1; }else{ @@ -480,14 +480,14 @@ int LocalConference::removeFromConference(LinphoneCall *call, bool_t active){ return -1; } } - call->params->in_conference=FALSE; + linphone_call_params_set_in_conference(call->params, FALSE); str=linphone_call_get_remote_address_as_string(call); ms_message("%s will be removed from conference", str); ms_free(str); if (active){ LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call)); - params->in_conference=FALSE; + linphone_call_params_set_in_conference(params, FALSE); // reconnect local audio with this call if (isIn()){ ms_message("Leaving conference for reconnecting with unique call."); @@ -522,7 +522,7 @@ int LocalConference::convertConferenceToCall(){ while (calls) { LinphoneCall *rc=(LinphoneCall*)calls->data; calls=calls->next; - if (rc->params->in_conference) { // not using current_param + if (linphone_call_params_get_in_conference(rc->params)) { // not using current_param bool_t active_after_removed=isIn(); err=removeFromConference(rc, active_after_removed); break; @@ -566,7 +566,7 @@ int LocalConference::terminate() { while (calls) { LinphoneCall *call=(LinphoneCall*)calls->data; calls=calls->next; - if (call->current_params->in_conference) { + if (linphone_call_params_get_in_conference(call->current_params)) { linphone_call_terminate(call); } } @@ -639,7 +639,7 @@ int LocalConference::stopRecording() { } void LocalConference::onCallStreamStarting(LinphoneCall *call, bool isPausedByRemote) { - call->params->has_video = FALSE; + linphone_call_params_enable_video(call->params, FALSE); call->camera_enabled = FALSE; ms_message("LocalConference::onCallStreamStarting(): joining AudioStream [%p] of call [%p] into conference.", call->audiostream, call); MSAudioEndpoint *ep=ms_audio_endpoint_get_from_stream(call->audiostream,TRUE); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 9a67095d5..622a8acb1 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -217,11 +217,11 @@ static bool_t generate_b64_crypto_key(size_t key_length, char* key_out, size_t k } static bool_t linphone_call_encryption_mandatory(LinphoneCall *call){ - if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) { + if (linphone_call_params_get_media_encryption(call->params)==LinphoneMediaEncryptionDTLS) { ms_message("Forced encryption mandatory on call [%p] due to SRTP-DTLS",call); return TRUE; } - return call->params->encryption_mandatory; + return linphone_call_params_mandatory_media_encryption_enabled(call->params); } LinphoneCore *linphone_call_get_core(const LinphoneCall *call){ @@ -303,15 +303,18 @@ static uint16_t linphone_call_get_avpf_rr_interval(const LinphoneCall *call) { static void propagate_encryption_changed(LinphoneCall *call){ if (!linphone_call_all_streams_encrypted(call)) { ms_message("Some streams are not encrypted"); - call->current_params->media_encryption=LinphoneMediaEncryptionNone; + linphone_call_params_set_media_encryption(call->current_params, LinphoneMediaEncryptionNone); linphone_call_notify_encryption_changed(call, FALSE, call->auth_token); } else { if (call->auth_token) {/* ZRTP only is using auth_token */ - call->current_params->media_encryption=LinphoneMediaEncryptionZRTP; + linphone_call_params_set_media_encryption(call->current_params, LinphoneMediaEncryptionZRTP); } else { /* otherwise it must be DTLS as SDES doesn't go through this function */ - call->current_params->media_encryption=LinphoneMediaEncryptionDTLS; + linphone_call_params_set_media_encryption(call->current_params, LinphoneMediaEncryptionDTLS); } - ms_message("All streams are encrypted key exchanged using %s", call->current_params->media_encryption==LinphoneMediaEncryptionZRTP?"ZRTP":call->current_params->media_encryption==LinphoneMediaEncryptionDTLS?"DTLS":"Unknown mechanism"); + ms_message("All streams are encrypted key exchanged using %s", + linphone_call_params_get_media_encryption(call->current_params) == LinphoneMediaEncryptionZRTP + ? "ZRTP" + : linphone_call_params_get_media_encryption(call->current_params) == LinphoneMediaEncryptionDTLS ? "DTLS" : "Unknown mechanism"); linphone_call_notify_encryption_changed(call, TRUE, call->auth_token); #ifdef VIDEO_ENABLED if (linphone_call_encryption_mandatory(call) && call->videostream && media_stream_started((MediaStream *)call->videostream)) { @@ -328,7 +331,7 @@ static void linphone_call_audiostream_encryption_changed(void *data, bool_t encr call = (LinphoneCall *)data; if (encrypted) { - if (call->params->media_encryption==LinphoneMediaEncryptionZRTP) { /* if encryption is DTLS, no status to be displayed */ + if (linphone_call_params_get_media_encryption(call->params) == LinphoneMediaEncryptionZRTP) { /* if encryption is DTLS, no status to be displayed */ snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token); linphone_core_notify_display_status(call->core, status); } @@ -338,9 +341,9 @@ static void linphone_call_audiostream_encryption_changed(void *data, bool_t encr #ifdef VIDEO_ENABLED // Enable video encryption - if (call->params->media_encryption==LinphoneMediaEncryptionZRTP) { + if (linphone_call_params_get_media_encryption(call->params) == LinphoneMediaEncryptionZRTP) { const LinphoneCallParams *params=linphone_call_get_current_params(call); - if (params->has_video) { + if (linphone_call_params_video_enabled(params)) { ms_message("Trying to start ZRTP encryption on video stream"); video_stream_start_zrtp(call->videostream); } @@ -650,7 +653,7 @@ static void setup_zrtp_hash(LinphoneCall *call, SalMediaDescription *md) { if (!sal_stream_description_active(&md->streams[i])) continue; if (call->sessions[i].zrtp_context!=NULL) { ms_zrtp_getHelloHash(call->sessions[i].zrtp_context, md->streams[i].zrtphash, 128); - if (call->params->media_encryption==LinphoneMediaEncryptionZRTP) { /* turn on the flag to use it if ZRTP is set */ + if (linphone_call_params_get_media_encryption(call->params)==LinphoneMediaEncryptionZRTP) { /* turn on the flag to use it if ZRTP is set */ md->streams[i].haveZrtpHash = 1; } else { md->streams[i].haveZrtpHash = 0; @@ -673,18 +676,18 @@ static void setup_rtcp_fb(LinphoneCall *call, SalMediaDescription *md) { if (!sal_stream_description_active(&md->streams[i])) continue; md->streams[i].rtcp_fb.generic_nack_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_fb_generic_nack_enabled", 0); md->streams[i].rtcp_fb.tmmbr_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_fb_tmmbr_enabled", 1); - md->streams[i].implicit_rtcp_fb = call->params->implicit_rtcp_fb; + md->streams[i].implicit_rtcp_fb = linphone_call_params_implicit_rtcp_fb_enabled(call->params); for (pt_it = md->streams[i].payloads; pt_it != NULL; pt_it = pt_it->next) { pt = (PayloadType *)pt_it->data; - if (call->params->avpf_enabled == FALSE && call->params->implicit_rtcp_fb == FALSE) { + if (linphone_call_params_avpf_enabled(call->params) == FALSE && linphone_call_params_implicit_rtcp_fb_enabled(call->params) == FALSE) { payload_type_unset_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); memset(&avpf_params, 0, sizeof(avpf_params)); }else { payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); avpf_params = payload_type_get_avpf_params(pt); - avpf_params.trr_interval = call->params->avpf_rr_interval; + avpf_params.trr_interval = linphone_call_params_get_avpf_rr_interval(call->params); } payload_type_set_avpf_params(pt, avpf_params); } @@ -860,21 +863,21 @@ void linphone_call_make_local_media_description(LinphoneCall *call) { strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username)); if (subject) strncpy(md->name,subject,sizeof(md->name)); - if (params->down_bw) - md->bandwidth=params->down_bw; + if (linphone_call_params_get_down_bandwidth(params)) + md->bandwidth=linphone_call_params_get_down_bandwidth(params); else md->bandwidth=linphone_core_get_download_bandwidth(lc); - if (params->custom_sdp_attributes) - md->custom_sdp_attributes = sal_custom_sdp_attribute_clone(params->custom_sdp_attributes); + if (linphone_call_params_get_custom_sdp_attributes(params)) + md->custom_sdp_attributes = sal_custom_sdp_attribute_clone(linphone_call_params_get_custom_sdp_attributes(params)); /*set audio capabilities */ - codec_hints.bandwidth_limit=params->audio_bw; + codec_hints.bandwidth_limit=linphone_call_params_get_audio_bandwidth_limit(params); codec_hints.max_codecs=-1; codec_hints.previously_used=old_md ? old_md->streams[call->main_audio_stream_index].already_assigned_payloads : NULL; l=make_codec_list(lc, &codec_hints, SalAudio, lc->codecs_conf.audio_codecs); - if (params->has_audio && l != NULL) { + if (linphone_call_params_audio_enabled(params) && l != NULL) { strncpy(md->streams[call->main_audio_stream_index].rtp_addr,linphone_call_get_public_ip_for_stream(call,call->main_audio_stream_index),sizeof(md->streams[call->main_audio_stream_index].rtp_addr)); strncpy(md->streams[call->main_audio_stream_index].rtcp_addr,linphone_call_get_public_ip_for_stream(call,call->main_audio_stream_index),sizeof(md->streams[call->main_audio_stream_index].rtcp_addr)); strncpy(md->streams[call->main_audio_stream_index].name,"Audio",sizeof(md->streams[call->main_audio_stream_index].name)-1); @@ -884,8 +887,8 @@ void linphone_call_make_local_media_description(LinphoneCall *call) { md->streams[call->main_audio_stream_index].dir=get_audio_dir_from_call_params(params); md->streams[call->main_audio_stream_index].type=SalAudio; md->streams[call->main_audio_stream_index].rtcp_mux = rtcp_mux; - if (params->down_ptime) - md->streams[call->main_audio_stream_index].ptime=params->down_ptime; + if (linphone_call_params_get_down_ptime(params)) + md->streams[call->main_audio_stream_index].ptime=linphone_call_params_get_down_ptime(params); else md->streams[call->main_audio_stream_index].ptime=linphone_core_get_download_ptime(lc); md->streams[call->main_audio_stream_index].max_rate=get_max_codec_sample_rate(l); @@ -905,8 +908,8 @@ void linphone_call_make_local_media_description(LinphoneCall *call) { md->streams[call->main_audio_stream_index].dir = SalStreamInactive; if(l) l=bctbx_list_free_with_data(l, (void (*)(void *))payload_type_destroy); } - if (params->custom_sdp_media_attributes[LinphoneStreamTypeAudio]) - md->streams[call->main_audio_stream_index].custom_sdp_attributes = sal_custom_sdp_attribute_clone(params->custom_sdp_media_attributes[LinphoneStreamTypeAudio]); + if (linphone_call_params_get_custom_sdp_media_attributes(params, LinphoneStreamTypeAudio)) + md->streams[call->main_audio_stream_index].custom_sdp_attributes = sal_custom_sdp_attribute_clone(linphone_call_params_get_custom_sdp_media_attributes(params, LinphoneStreamTypeAudio)); md->streams[call->main_video_stream_index].proto=md->streams[call->main_audio_stream_index].proto; md->streams[call->main_video_stream_index].dir=get_video_dir_from_call_params(params); @@ -919,7 +922,7 @@ void linphone_call_make_local_media_description(LinphoneCall *call) { codec_hints.previously_used=old_md ? old_md->streams[call->main_video_stream_index].already_assigned_payloads : NULL; l=make_codec_list(lc, &codec_hints, SalVideo, lc->codecs_conf.video_codecs); - if (params->has_video && l != NULL){ + if (linphone_call_params_video_enabled(params) && l != NULL){ strncpy(md->streams[call->main_video_stream_index].rtp_addr,linphone_call_get_public_ip_for_stream(call,call->main_video_stream_index),sizeof(md->streams[call->main_video_stream_index].rtp_addr)); strncpy(md->streams[call->main_video_stream_index].rtcp_addr,linphone_call_get_public_ip_for_stream(call,call->main_video_stream_index),sizeof(md->streams[call->main_video_stream_index].rtcp_addr)); md->streams[call->main_video_stream_index].rtp_port=call->media_ports[call->main_video_stream_index].rtp_port; @@ -940,15 +943,15 @@ void linphone_call_make_local_media_description(LinphoneCall *call) { md->streams[call->main_video_stream_index].dir = SalStreamInactive; if(l) l=bctbx_list_free_with_data(l, (void (*)(void *))payload_type_destroy); } - if (params->custom_sdp_media_attributes[LinphoneStreamTypeVideo]) - md->streams[call->main_video_stream_index].custom_sdp_attributes = sal_custom_sdp_attribute_clone(params->custom_sdp_media_attributes[LinphoneStreamTypeVideo]); + if (linphone_call_params_get_custom_sdp_media_attributes(params, LinphoneStreamTypeVideo)) + md->streams[call->main_video_stream_index].custom_sdp_attributes = sal_custom_sdp_attribute_clone(linphone_call_params_get_custom_sdp_media_attributes(params, LinphoneStreamTypeVideo)); md->streams[call->main_text_stream_index].proto=md->streams[call->main_audio_stream_index].proto; md->streams[call->main_text_stream_index].dir=SalStreamSendRecv; md->streams[call->main_text_stream_index].type=SalText; md->streams[call->main_text_stream_index].rtcp_mux = rtcp_mux; strncpy(md->streams[call->main_text_stream_index].name,"Text",sizeof(md->streams[call->main_text_stream_index].name)-1); - if (params->realtimetext_enabled) { + if (linphone_call_params_realtime_text_enabled(params)) { strncpy(md->streams[call->main_text_stream_index].rtp_addr,linphone_call_get_public_ip_for_stream(call,call->main_text_stream_index),sizeof(md->streams[call->main_text_stream_index].rtp_addr)); strncpy(md->streams[call->main_text_stream_index].rtcp_addr,linphone_call_get_public_ip_for_stream(call,call->main_text_stream_index),sizeof(md->streams[call->main_text_stream_index].rtcp_addr)); @@ -974,8 +977,8 @@ void linphone_call_make_local_media_description(LinphoneCall *call) { ms_message("Don't put text stream on local offer for call [%p]",call); md->streams[call->main_text_stream_index].dir = SalStreamInactive; } - if (params->custom_sdp_media_attributes[LinphoneStreamTypeText]) - md->streams[call->main_text_stream_index].custom_sdp_attributes = sal_custom_sdp_attribute_clone(params->custom_sdp_media_attributes[LinphoneStreamTypeText]); + if (linphone_call_params_get_custom_sdp_media_attributes(params, LinphoneStreamTypeText)) + md->streams[call->main_text_stream_index].custom_sdp_attributes = sal_custom_sdp_attribute_clone(linphone_call_params_get_custom_sdp_media_attributes(params, LinphoneStreamTypeText)); md->nb_streams = MAX(md->nb_streams,max_index+1); @@ -1004,7 +1007,7 @@ void linphone_call_make_local_media_description(LinphoneCall *call) { transfer_already_assigned_payload_types(old_md,md); call->localdesc_changed=sal_media_description_equals(md,old_md); sal_media_description_unref(old_md); - if (call->params->internal_call_update){ + if (linphone_call_params_get_internal_call_update(call->params)){ /* * An internal call update (ICE reINVITE) is not expected to modify the actual media stream parameters. * However, the localdesc may change between first INVITE and ICE reINVITE, for example if the remote party has declined a video stream. @@ -1107,7 +1110,7 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, call->log=linphone_call_log_new(call->dir, from, to); call->camera_enabled=TRUE; call->current_params = linphone_call_params_new(); - call->current_params->media_encryption=LinphoneMediaEncryptionNone; + linphone_call_params_set_media_encryption(call->current_params, LinphoneMediaEncryptionNone); call->dtls_certificate_fingerprint = NULL; if (call->dir == LinphoneCallIncoming) call->me=to; @@ -1172,11 +1175,11 @@ void linphone_call_create_op_to(LinphoneCall *call, LinphoneAddress *to){ if (call->op) sal_op_release(call->op); call->op=sal_op_new(call->core->sal); sal_op_set_user_pointer(call->op,call); - if (call->params->referer) - sal_call_set_referer(call->op,call->params->referer->op); - linphone_configure_op(call->core,call->op,to,call->params->custom_headers,FALSE); - if (call->params->privacy != LinphonePrivacyDefault) - sal_op_set_privacy(call->op,(SalPrivacyMask)call->params->privacy); + if (linphone_call_params_get_referer(call->params)) + sal_call_set_referer(call->op,linphone_call_params_get_referer(call->params)->op); + linphone_configure_op(call->core,call->op,to,linphone_call_params_get_custom_headers(call->params),FALSE); + if (linphone_call_params_get_privacy(call->params) != LinphonePrivacyDefault) + sal_op_set_privacy(call->op,(SalPrivacyMask)linphone_call_params_get_privacy(call->params)); /*else privacy might be set by proxy */ } @@ -1184,11 +1187,11 @@ void linphone_call_create_op(LinphoneCall *call){ if (call->op) sal_op_release(call->op); call->op=sal_op_new(call->core->sal); sal_op_set_user_pointer(call->op,call); - if (call->params->referer) - sal_call_set_referer(call->op,call->params->referer->op); - linphone_configure_op(call->core,call->op,call->log->to,call->params->custom_headers,FALSE); - if (call->params->privacy != LinphonePrivacyDefault) - sal_op_set_privacy(call->op,(SalPrivacyMask)call->params->privacy); + if (linphone_call_params_get_referer(call->params)) + sal_call_set_referer(call->op,linphone_call_params_get_referer(call->params)->op); + linphone_configure_op(call->core,call->op,call->log->to,linphone_call_params_get_custom_headers(call->params),FALSE); + if (linphone_call_params_get_privacy(call->params) != LinphonePrivacyDefault) + sal_op_set_privacy(call->op,(SalPrivacyMask)linphone_call_params_get_privacy(call->params)); /*else privacy might be set by proxy */ } @@ -1359,7 +1362,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr call->params = linphone_call_params_copy(params); linphone_call_init_common(call, from, to); - call->current_params->update_call_when_ice_completed = call->params->update_call_when_ice_completed; /*copy param*/ + linphone_call_params_set_update_call_when_ice_completed(call->current_params, linphone_call_params_get_update_call_when_ice_completed(call->params)); /*copy param*/ linphone_call_fill_media_multicast_addr(call); @@ -1378,8 +1381,8 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr #endif //BUILD_UPNP discover_mtu(lc,linphone_address_get_domain (to)); - if (params->referer){ - call->referer=linphone_call_ref(params->referer); + if (linphone_call_params_get_referer(params)){ + call->referer=linphone_call_ref(linphone_call_params_get_referer(params)); } linphone_call_create_op_to(call, to); @@ -1407,21 +1410,21 @@ static void linphone_call_incoming_select_ip_version(LinphoneCall *call, Linphon */ void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, SalMediaDescription *md) { /* Handle AVPF, SRTP and DTLS. */ - call->params->avpf_enabled = sal_media_description_has_avpf(md); + linphone_call_params_enable_avpf(call->params, sal_media_description_has_avpf(md)); if (call->dest_proxy != NULL) { - call->params->avpf_rr_interval = linphone_proxy_config_get_avpf_rr_interval(call->dest_proxy) * 1000; + linphone_call_params_set_avpf_rr_interval(call->params, linphone_proxy_config_get_avpf_rr_interval(call->dest_proxy) * 1000); } else { - call->params->avpf_rr_interval = linphone_core_get_avpf_rr_interval(call->core)*1000; + linphone_call_params_set_avpf_rr_interval(call->params, linphone_core_get_avpf_rr_interval(call->core)*1000); } if ((sal_media_description_has_zrtp(md) == TRUE) && (linphone_core_media_encryption_supported(call->core, LinphoneMediaEncryptionZRTP) == TRUE)) { - call->params->media_encryption = LinphoneMediaEncryptionZRTP; + linphone_call_params_set_media_encryption(call->params, LinphoneMediaEncryptionZRTP); }else if ((sal_media_description_has_dtls(md) == TRUE) && (media_stream_dtls_supported() == TRUE)) { - call->params->media_encryption = LinphoneMediaEncryptionDTLS; + linphone_call_params_set_media_encryption(call->params, LinphoneMediaEncryptionDTLS); }else if ((sal_media_description_has_srtp(md) == TRUE) && (ms_srtp_supported() == TRUE)) { - call->params->media_encryption = LinphoneMediaEncryptionSRTP; - }else if (call->params->media_encryption != LinphoneMediaEncryptionZRTP){ - call->params->media_encryption = LinphoneMediaEncryptionNone; + linphone_call_params_set_media_encryption(call->params, LinphoneMediaEncryptionSRTP); + }else if (linphone_call_params_get_media_encryption(call->params) != LinphoneMediaEncryptionZRTP){ + linphone_call_params_set_media_encryption(call->params, LinphoneMediaEncryptionNone); } /*in case of nat64, even ipv4 addresses are reachable from v6. Should be enhanced to manage stream by stream connectivity (I.E v6 or v4)*/ @@ -1586,12 +1589,12 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro * end apparently does not support. This features are: privacy, video */ /*set privacy*/ - call->current_params->privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op); + linphone_call_params_set_privacy(call->current_params, (LinphonePrivacyMask)sal_op_get_privacy(call->op)); /*config params*/ - call->current_params->update_call_when_ice_completed = call->params->update_call_when_ice_completed; /*copy config params*/ + linphone_call_params_set_update_call_when_ice_completed(call->current_params, linphone_call_params_get_update_call_when_ice_completed(call->params)); /*copy config params*/ /*set video support */ - call->params->has_video = linphone_core_video_enabled(lc) && lc->video_policy.automatically_accept; + linphone_call_params_enable_video(call->params, linphone_core_video_enabled(lc) && lc->video_policy.automatically_accept); if (md) { // It is licit to receive an INVITE without SDP // In this case WE chose the media parameters according to policy. @@ -1752,22 +1755,22 @@ void linphone_call_fix_call_parameters(LinphoneCall *call, SalMediaDescription * } rcp = linphone_call_get_remote_params(call); if (rcp){ - if (call->params->has_audio && !rcp->has_audio){ + if (linphone_call_params_audio_enabled(call->params) && !linphone_call_params_audio_enabled(rcp)){ ms_message("Call [%p]: disabling audio in our call params because the remote doesn't want it.", call); - call->params->has_audio = FALSE; + linphone_call_params_enable_audio(call->params, FALSE); } - if (call->params->has_video && !rcp->has_video){ + if (linphone_call_params_video_enabled(call->params) && !linphone_call_params_video_enabled(rcp)){ ms_message("Call [%p]: disabling video in our call params because the remote doesn't want it.", call); - call->params->has_video = FALSE; + linphone_call_params_enable_video(call->params, FALSE); } - if (rcp->has_video && call->core->video_policy.automatically_accept && linphone_core_video_enabled(call->core) && !call->params->has_video){ + if (linphone_call_params_video_enabled(rcp) && call->core->video_policy.automatically_accept && linphone_core_video_enabled(call->core) && !linphone_call_params_video_enabled(call->params)){ ms_message("Call [%p]: re-enabling video in our call params because the remote wants it and the policy allows to automatically accept.", call); linphone_call_params_enable_video(call->params, TRUE); } - if (rcp->realtimetext_enabled && !call->params->realtimetext_enabled) { - call->params->realtimetext_enabled = TRUE; + if (linphone_call_params_realtime_text_enabled(rcp) && !linphone_call_params_realtime_text_enabled(call->params)) { + linphone_call_params_enable_realtime_text(call->params, TRUE); } } } @@ -2059,23 +2062,20 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){ #ifdef VIDEO_ENABLED VideoStream *vstream; #endif - MS_VIDEO_SIZE_ASSIGN(call->current_params->sent_vsize, UNKNOWN); - MS_VIDEO_SIZE_ASSIGN(call->current_params->recv_vsize, UNKNOWN); + LinphoneVideoDefinition *vdef = linphone_video_definition_new(MS_VIDEO_SIZE_UNKNOWN_W, MS_VIDEO_SIZE_UNKNOWN_H, NULL); + linphone_call_params_set_sent_video_definition(call->current_params, vdef); + linphone_call_params_set_received_video_definition(call->current_params, vdef); #ifdef VIDEO_ENABLED - if (call->current_params->sent_vdef != NULL) linphone_video_definition_unref(call->current_params->sent_vdef); - call->current_params->sent_vdef = NULL; - if (call->current_params->recv_vdef != NULL) linphone_video_definition_unref(call->current_params->recv_vdef); - call->current_params->recv_vdef = NULL; vstream = call->videostream; if (vstream != NULL) { - call->current_params->sent_vsize = video_stream_get_sent_video_size(vstream); - call->current_params->recv_vsize = video_stream_get_received_video_size(vstream); - call->current_params->sent_vdef = linphone_factory_create_video_definition( - linphone_factory_get(), call->current_params->sent_vsize.width, call->current_params->sent_vsize.height); - call->current_params->recv_vdef = linphone_factory_create_video_definition( - linphone_factory_get(), call->current_params->recv_vsize.width, call->current_params->recv_vsize.height); - call->current_params->sent_fps = video_stream_get_sent_framerate(vstream); - call->current_params->received_fps = video_stream_get_received_framerate(vstream); + MSVideoSize vsize = video_stream_get_sent_video_size(vstream); + LinphoneVideoDefinition *vdef = linphone_video_definition_new(vsize.width, vsize.height, NULL); + linphone_call_params_set_sent_video_definition(call->current_params, vdef); + vsize = video_stream_get_received_video_size(vstream); + vdef = linphone_video_definition_new(vsize.width, vsize.height, NULL); + linphone_call_params_set_received_video_definition(call->current_params, vdef); + linphone_call_params_set_sent_fps(call->current_params, video_stream_get_sent_framerate(vstream)); + linphone_call_params_set_received_fps(call->current_params, video_stream_get_received_framerate(vstream)); } #endif @@ -2088,16 +2088,16 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){ * Typically there can be inactive streams for which the media layer has no idea of whether they are encrypted or not. */ - switch (call->params->media_encryption) { + switch (linphone_call_params_get_media_encryption(call->params)) { case LinphoneMediaEncryptionZRTP: if (at_least_one_stream_started(call)){ if ((all_streams_encrypted = linphone_call_all_streams_encrypted(call)) && linphone_call_get_authentication_token(call)) { - call->current_params->media_encryption=LinphoneMediaEncryptionZRTP; + linphone_call_params_set_media_encryption(call->current_params, LinphoneMediaEncryptionZRTP); } else { /*to avoid to many traces*/ ms_debug("Encryption was requested to be %s, but isn't effective (all_streams_encrypted=%i, auth_token=%s)", - linphone_media_encryption_to_string(call->params->media_encryption), all_streams_encrypted, call->auth_token == NULL ? "" : call->auth_token); - call->current_params->media_encryption=LinphoneMediaEncryptionNone; + linphone_media_encryption_to_string(linphone_call_params_get_media_encryption(call->params)), all_streams_encrypted, call->auth_token == NULL ? "" : call->auth_token); + linphone_call_params_set_media_encryption(call->current_params, LinphoneMediaEncryptionNone); } }//else don't update the state if all streams are shutdown. break; @@ -2105,50 +2105,50 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){ case LinphoneMediaEncryptionSRTP: if (at_least_one_stream_started(call)){ if (linphone_call_get_n_active_streams(call)==0 || (all_streams_encrypted = linphone_call_all_streams_encrypted(call))) { - call->current_params->media_encryption = call->params->media_encryption; + linphone_call_params_set_media_encryption(call->current_params, linphone_call_params_get_media_encryption(call->params)); } else { /*to avoid to many traces*/ ms_debug("Encryption was requested to be %s, but isn't effective (all_streams_encrypted=%i)", - linphone_media_encryption_to_string(call->params->media_encryption), all_streams_encrypted); - call->current_params->media_encryption=LinphoneMediaEncryptionNone; + linphone_media_encryption_to_string(linphone_call_params_get_media_encryption(call->params)), all_streams_encrypted); + linphone_call_params_set_media_encryption(call->current_params, LinphoneMediaEncryptionNone); } }//else don't update the state if all streams are shutdown. break; case LinphoneMediaEncryptionNone: /* check if we actually switched to ZRTP */ if (at_least_one_stream_started(call) && (all_streams_encrypted = linphone_call_all_streams_encrypted(call)) && linphone_call_get_authentication_token(call)) { - call->current_params->media_encryption=LinphoneMediaEncryptionZRTP; + linphone_call_params_set_media_encryption(call->current_params, LinphoneMediaEncryptionZRTP); } else { - call->current_params->media_encryption=LinphoneMediaEncryptionNone; + linphone_call_params_set_media_encryption(call->current_params, LinphoneMediaEncryptionNone); } break; } - call->current_params->avpf_enabled = linphone_call_all_streams_avpf_enabled(call) && sal_media_description_has_avpf(md); - if (call->current_params->avpf_enabled == TRUE) { - call->current_params->avpf_rr_interval = linphone_call_get_avpf_rr_interval(call); + linphone_call_params_enable_avpf(call->current_params, linphone_call_all_streams_avpf_enabled(call) && sal_media_description_has_avpf(md)); + if (linphone_call_params_avpf_enabled(call->current_params) == TRUE) { + linphone_call_params_set_avpf_rr_interval(call->current_params, linphone_call_get_avpf_rr_interval(call)); } else { - call->current_params->avpf_rr_interval = 0; + linphone_call_params_set_avpf_rr_interval(call->current_params, 0); } if (md){ const char *rtp_addr; SalStreamDescription *sd=sal_media_description_find_best_stream(md,SalAudio); - call->current_params->audio_dir=sd ? media_direction_from_sal_stream_dir(sd->dir) : LinphoneMediaDirectionInactive; - if (call->current_params->audio_dir != LinphoneMediaDirectionInactive) { + linphone_call_params_set_audio_direction(call->current_params, sd ? media_direction_from_sal_stream_dir(sd->dir) : LinphoneMediaDirectionInactive); + if (linphone_call_params_get_audio_direction(call->current_params) != LinphoneMediaDirectionInactive) { rtp_addr = sd->rtp_addr[0]!='\0' ? sd->rtp_addr : call->resultdesc->addr; - call->current_params->audio_multicast_enabled = ms_is_multicast(rtp_addr); + linphone_call_params_enable_audio_multicast(call->current_params, ms_is_multicast(rtp_addr)); } else - call->current_params->audio_multicast_enabled = FALSE; + linphone_call_params_enable_audio_multicast(call->current_params, FALSE); sd=sal_media_description_find_best_stream(md,SalVideo); - call->current_params->implicit_rtcp_fb = sd ? sal_stream_description_has_implicit_avpf(sd): FALSE; - call->current_params->video_dir=sd ? media_direction_from_sal_stream_dir(sd->dir) : LinphoneMediaDirectionInactive; - if (call->current_params->video_dir != LinphoneMediaDirectionInactive) { + linphone_call_params_enable_implicit_rtcp_fb(call->current_params, sd ? sal_stream_description_has_implicit_avpf(sd): FALSE); + linphone_call_params_set_video_direction(call->current_params, sd ? media_direction_from_sal_stream_dir(sd->dir) : LinphoneMediaDirectionInactive); + if (linphone_call_params_get_video_direction(call->current_params) != LinphoneMediaDirectionInactive) { rtp_addr = sd->rtp_addr[0]!='\0' ? sd->rtp_addr : call->resultdesc->addr; - call->current_params->video_multicast_enabled = ms_is_multicast(rtp_addr); + linphone_call_params_enable_video_multicast(call->current_params, ms_is_multicast(rtp_addr)); } else - call->current_params->video_multicast_enabled = FALSE; + linphone_call_params_enable_video_multicast(call->current_params, FALSE); } @@ -2173,21 +2173,21 @@ const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){ for (i = 0; i < nb_video_streams; i++) { sd = sal_media_description_get_active_stream_of_type(md, SalVideo, i); - if (sal_stream_description_active(sd) == TRUE) cp->has_video = TRUE; - if (sal_stream_description_has_srtp(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP; + if (sal_stream_description_active(sd) == TRUE) linphone_call_params_enable_video(cp, TRUE); + if (sal_stream_description_has_srtp(sd) == TRUE) linphone_call_params_set_media_encryption(cp, LinphoneMediaEncryptionSRTP); } for (i = 0; i < nb_audio_streams; i++) { sd = sal_media_description_get_active_stream_of_type(md, SalAudio, i); - if (sal_stream_description_has_srtp(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP; + if (sal_stream_description_has_srtp(sd) == TRUE) linphone_call_params_set_media_encryption(cp, LinphoneMediaEncryptionSRTP); } for (i = 0; i < nb_text_streams; i++) { sd = sal_media_description_get_active_stream_of_type(md, SalText, i); - if (sal_stream_description_has_srtp(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP; - cp->realtimetext_enabled = TRUE; + if (sal_stream_description_has_srtp(sd) == TRUE) linphone_call_params_set_media_encryption(cp, LinphoneMediaEncryptionSRTP); + linphone_call_params_enable_realtime_text(cp, TRUE); } - if (!cp->has_video){ + if (!linphone_call_params_video_enabled(cp)){ if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){ - cp->low_bandwidth=TRUE; + linphone_call_params_enable_low_bandwidth(cp, TRUE); } } if (md->name[0]!='\0') linphone_call_params_set_session_name(cp,md->name); @@ -2343,7 +2343,7 @@ void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){ void linphone_call_send_vfu_request(LinphoneCall *call) { #ifdef VIDEO_ENABLED const LinphoneCallParams *current_params = linphone_call_get_current_params(call); - if ((current_params->avpf_enabled || current_params->implicit_rtcp_fb )&& call->videostream && media_stream_get_state((const MediaStream *)call->videostream) == MSStreamStarted) { // || sal_media_description_has_implicit_avpf((const SalMediaDescription *)call->resultdesc) + if ((linphone_call_params_avpf_enabled(current_params) || linphone_call_params_implicit_rtcp_fb_enabled(current_params)) && call->videostream && media_stream_get_state((const MediaStream *)call->videostream) == MSStreamStarted) { // || sal_media_description_has_implicit_avpf((const SalMediaDescription *)call->resultdesc) ms_message("Request Full Intra Request on call [%p]", call); video_stream_send_fir(call->videostream); } else if (call->core->sip_conf.vfu_with_info) { @@ -2487,11 +2487,11 @@ int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){ if (incoming_offer){ remote=sal_call_get_remote_media_description(call->op); has_video=linphone_core_video_enabled(call->core) && linphone_core_media_description_contains_video_stream(remote); - }else has_video=call->params->has_video; + }else has_video=linphone_call_params_video_enabled(call->params); _linphone_call_prepare_ice_for_stream(call,call->main_audio_stream_index,TRUE); if (has_video) _linphone_call_prepare_ice_for_stream(call,call->main_video_stream_index,TRUE); - if (call->params->realtimetext_enabled) _linphone_call_prepare_ice_for_stream(call,call->main_text_stream_index,TRUE); + if (linphone_call_params_realtime_text_enabled(call->params)) _linphone_call_prepare_ice_for_stream(call,call->main_text_stream_index,TRUE); /*start ICE gathering*/ if (incoming_offer) linphone_call_update_ice_from_remote_media_description(call, remote, TRUE); /*this may delete the ice session*/ @@ -2503,7 +2503,7 @@ int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){ video_stream_prepare_video(call->videostream); } #endif - if (call->params->realtimetext_enabled && call->textstream->ms.state==MSStreamInitialized) { + if (linphone_call_params_realtime_text_enabled(call->params) && call->textstream->ms.state==MSStreamInitialized) { text_stream_prepare_text(call->textstream); } err = linphone_core_gather_ice_candidates(call->core,call); @@ -2556,7 +2556,7 @@ static SalMulticastRole linphone_call_get_multicast_role(const LinphoneCall *cal static void setup_dtls_params(LinphoneCall *call, MediaStream* stream) { LinphoneCore *lc=call->core; - if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) { + if (linphone_call_params_get_media_encryption(call->params)==LinphoneMediaEncryptionDTLS) { MSDtlsSrtpParams params; char *certificate, *key; memset(¶ms,0,sizeof(MSDtlsSrtpParams)); @@ -3082,9 +3082,9 @@ static int get_ideal_audio_bw(LinphoneCall *call, const SalMediaDescription *md, /*case where b=AS is given globally, not per stream*/ remote_bw=md->bandwidth; } - if (params->up_bw>0){ + if (linphone_call_params_get_up_bandwidth(params)>0){ forced=TRUE; - upload_bw=params->up_bw; + upload_bw=linphone_call_params_get_up_bandwidth(params); }else upload_bw=total_upload_bw; upload_bw=get_min_bandwidth(upload_bw,remote_bw); if (!will_use_video || forced) return upload_bw; @@ -3146,8 +3146,8 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m /*this will update call->audio_bw*/ linphone_core_update_allocated_audio_bandwidth_in_call(call,pt,bw); bw=call->audio_bw; - if (params->up_ptime) - up_ptime=params->up_ptime; + if (linphone_call_params_get_up_ptime(params)) + up_ptime=linphone_call_params_get_up_ptime(params); else up_ptime=linphone_core_get_upload_ptime(lc); } first=FALSE; @@ -3448,8 +3448,8 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, LinphoneCallSta if (used_pt!=-1){ bool_t ok = TRUE; - call->current_params->audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt); - call->current_params->has_audio = TRUE; + linphone_call_params_set_used_audio_codec(call->current_params, rtp_profile_get_payload(call->audio_profile, used_pt)); + linphone_call_params_enable_audio(call->current_params, TRUE); if (playcard==NULL) { ms_warning("No card defined for playback !"); } @@ -3483,7 +3483,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, LinphoneCallSta captcard=NULL; playcard=NULL; } - if (call->params->in_conference){ + if (linphone_call_params_get_in_conference(call->params)){ /* first create the graph without soundcard resources*/ captcard=playcard=NULL; } @@ -3497,9 +3497,9 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, LinphoneCallSta if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate); rtp_session_enable_rtcp_mux(call->audiostream->ms.sessions.rtp_session, stream->rtcp_mux); - if (!call->params->in_conference && call->params->record_file){ - audio_stream_mixed_record_open(call->audiostream,call->params->record_file); - call->current_params->record_file=ms_strdup(call->params->record_file); + if (!linphone_call_params_get_in_conference(call->params) && linphone_call_params_get_record_file(call->params)){ + audio_stream_mixed_record_open(call->audiostream,linphone_call_params_get_record_file(call->params)); + linphone_call_params_set_record_file(call->current_params, linphone_call_params_get_record_file(call->params)); } /* valid local tags are > 0 */ if (sal_stream_description_has_srtp(stream) == TRUE) { @@ -3515,7 +3515,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, LinphoneCallSta } configure_rtp_session_for_rtcp_fb(call, stream); configure_rtp_session_for_rtcp_xr(lc, call, SalAudio); - configure_adaptive_rate_control(call, (MediaStream*)call->audiostream, call->current_params->audio_codec, video_will_be_used); + configure_adaptive_rate_control(call, (MediaStream*)call->audiostream, (PayloadType *)linphone_call_params_get_used_audio_codec(call->current_params), video_will_be_used); if (is_multicast) rtp_session_set_multicast_ttl(call->audiostream->ms.sessions.rtp_session,stream->ttl); @@ -3582,17 +3582,17 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, LinphoneCallSta setup_ring_player(lc,call); } - if (call->params->in_conference && lc->conf_ctx){ + if (linphone_call_params_get_in_conference(call->params) && lc->conf_ctx){ /*transform the graph to connect it to the conference filter */ mute = stream->dir==SalStreamRecvOnly; linphone_conference_on_call_stream_starting(lc->conf_ctx, call, mute); } - call->current_params->in_conference=call->params->in_conference; - call->current_params->low_bandwidth=call->params->low_bandwidth; + linphone_call_params_set_in_conference(call->current_params, linphone_call_params_get_in_conference(call->params)); + linphone_call_params_enable_low_bandwidth(call->current_params, linphone_call_params_low_bandwidth_enabled(call->params)); /* start ZRTP engine if needed : set here or remote have a zrtp-hash attribute */ if (linphone_core_media_encryption_supported(lc, LinphoneMediaEncryptionZRTP) && - (call->params->media_encryption == LinphoneMediaEncryptionZRTP || remote_stream->haveZrtpHash==1) ){ + (linphone_call_params_get_media_encryption(call->params) == LinphoneMediaEncryptionZRTP || remote_stream->haveZrtpHash==1) ){ audio_stream_start_zrtp(call->audiostream); if (remote_stream->haveZrtpHash == 1) { int retval; @@ -3666,8 +3666,8 @@ static void linphone_call_start_video_stream(LinphoneCall *call, LinphoneCallSta bool_t is_inactive=FALSE; MSWebCam *cam; - call->current_params->video_codec = rtp_profile_get_payload(call->video_profile, used_pt); - call->current_params->has_video=TRUE; + linphone_call_params_set_used_video_codec(call->current_params, rtp_profile_get_payload(call->video_profile, used_pt)); + linphone_call_params_enable_video(call->current_params, TRUE); rtp_session_enable_rtcp_mux(call->videostream->ms.sessions.rtp_session, vstream->rtcp_mux); if (lc->video_conf.preview_vsize.width!=0) @@ -3721,7 +3721,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, LinphoneCallSta } configure_rtp_session_for_rtcp_fb(call, vstream); configure_rtp_session_for_rtcp_xr(lc, call, SalVideo); - configure_adaptive_rate_control(call, (MediaStream*)call->videostream, call->current_params->video_codec, TRUE); + configure_adaptive_rate_control(call, (MediaStream*)call->videostream, (PayloadType *)linphone_call_params_get_used_video_codec(call->current_params), TRUE); call->log->video_enabled = TRUE; video_stream_set_direction (call->videostream, dir); @@ -3767,7 +3767,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, LinphoneCallSta _linphone_call_set_next_video_frame_decoded_trigger(call); /* start ZRTP engine if needed : set here or remote have a zrtp-hash attribute */ - if (call->params->media_encryption==LinphoneMediaEncryptionZRTP || remote_stream->haveZrtpHash==1) { + if (linphone_call_params_get_media_encryption(call->params)==LinphoneMediaEncryptionZRTP || remote_stream->haveZrtpHash==1) { /*audio stream is already encrypted and video stream is active*/ if (media_stream_secured((MediaStream *)call->audiostream) && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) { video_stream_start_zrtp(call->videostream); @@ -3816,8 +3816,8 @@ static void linphone_call_start_text_stream(LinphoneCall *call) { call->text_profile = make_profile(call, call->resultdesc, tstream, &used_pt); if (used_pt != -1) { - call->current_params->text_codec = rtp_profile_get_payload(call->text_profile, used_pt); - call->current_params->realtimetext_enabled = TRUE; + linphone_call_params_set_used_text_codec(call->current_params, rtp_profile_get_payload(call->text_profile, used_pt)); + linphone_call_params_enable_realtime_text(call->current_params, TRUE); if (sal_stream_description_has_srtp(tstream) == TRUE) { int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, tstream->crypto_local_tag); @@ -3868,7 +3868,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState nex } BCTBX_NO_BREAK; case LinphoneCallOutgoingEarlyMedia: - if (!call->params->real_early_media){ + if (!linphone_call_params_early_media_sending_enabled(call->params)){ call->all_muted = TRUE; } break; @@ -3878,9 +3878,9 @@ void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState nex break; } - call->current_params->audio_codec = NULL; - call->current_params->video_codec = NULL; - call->current_params->text_codec = NULL; + linphone_call_params_set_used_audio_codec(call->current_params, NULL); + linphone_call_params_set_used_video_codec(call->current_params, NULL); + linphone_call_params_set_used_text_codec(call->current_params, NULL); if ((call->audiostream == NULL) && (call->videostream == NULL)) { ms_fatal("start_media_stream() called without prior init !"); @@ -3903,19 +3903,19 @@ void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState nex ms_message("linphone_call_start_media_streams() call=[%p] local upload_bandwidth=[%i] kbit/s; local download_bandwidth=[%i] kbit/s", call, linphone_core_get_upload_bandwidth(lc),linphone_core_get_download_bandwidth(lc)); - call->current_params->has_audio = FALSE; + linphone_call_params_enable_audio(call->current_params, FALSE); if (call->audiostream!=NULL) { linphone_call_start_audio_stream(call, next_state, video_will_be_used); } else { ms_warning("linphone_call_start_media_streams(): no audio stream!"); } - call->current_params->has_video=FALSE; + linphone_call_params_enable_video(call->current_params, FALSE); if (call->videostream!=NULL) { if (call->audiostream) audio_stream_link_video(call->audiostream,call->videostream); linphone_call_start_video_stream(call, next_state); } /*the onhold file is to be played once both audio and video are ready.*/ - if (call->onhold_file && !call->params->in_conference && call->audiostream){ + if (call->onhold_file && !linphone_call_params_get_in_conference(call->params) && call->audiostream){ MSFilter *player = audio_stream_open_remote_play(call->audiostream, call->onhold_file); if (player){ int pause_time=500; @@ -3926,15 +3926,15 @@ void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState nex call->up_bw=linphone_core_get_upload_bandwidth(lc); - if (call->params->realtimetext_enabled) { + if (linphone_call_params_realtime_text_enabled(call->params)) { linphone_call_start_text_stream(call); } set_dtls_fingerprint_on_all_streams(call); if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) { - if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) { - call->current_params->update_call_when_ice_completed = FALSE; + if (linphone_call_params_get_media_encryption(call->params)==LinphoneMediaEncryptionDTLS) { + linphone_call_params_set_update_call_when_ice_completed(call->current_params, FALSE); ms_message("Disabling update call when ice completed on call [%p]",call); } ice_session_start_connectivity_checks(call->ice_session); @@ -4086,7 +4086,7 @@ static void linphone_call_stop_audio_stream(LinphoneCall *call) { ortp_ev_queue_destroy(call->audiostream_app_evq); call->audiostream_app_evq=NULL; - call->current_params->audio_codec = NULL; + linphone_call_params_set_used_audio_codec(call->current_params, NULL); } } @@ -4105,7 +4105,7 @@ static void linphone_call_stop_video_stream(LinphoneCall *call) { ortp_ev_queue_flush(call->videostream_app_evq); ortp_ev_queue_destroy(call->videostream_app_evq); call->videostream_app_evq=NULL; - call->current_params->video_codec = NULL; + linphone_call_params_set_used_video_codec(call->current_params, NULL); } #endif } @@ -4128,7 +4128,7 @@ static void linphone_call_stop_text_stream(LinphoneCall *call) { ortp_ev_queue_flush(call->textstream_app_evq); ortp_ev_queue_destroy(call->textstream_app_evq); call->textstream_app_evq = NULL; - call->current_params->text_codec = NULL; + linphone_call_params_set_used_text_codec(call->current_params, NULL); } } @@ -4538,18 +4538,18 @@ float linphone_call_stats_get_round_trip_delay(const LinphoneCallStats *stats) { } void linphone_call_start_recording(LinphoneCall *call){ - if (!call->params->record_file){ + if (!linphone_call_params_get_record_file(call->params)){ ms_error("linphone_call_start_recording(): no output file specified. Use linphone_call_params_set_record_file()."); return; } - if (call->audiostream && !call->params->in_conference){ + if (call->audiostream && !linphone_call_params_get_in_conference(call->params)){ audio_stream_mixed_record_start(call->audiostream); } call->record_active=TRUE; } void linphone_call_stop_recording(LinphoneCall *call){ - if (call->audiostream && !call->params->in_conference){ + if (call->audiostream && !linphone_call_params_get_in_conference(call->params)){ audio_stream_mixed_record_stop(call->audiostream); } call->record_active=FALSE; @@ -4650,9 +4650,9 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ /* At least one ICE session has succeeded, so perform a call update. */ if (ice_session_has_completed_check_list(call->ice_session) == TRUE) { const LinphoneCallParams *current_param = linphone_call_get_current_params(call); - if (ice_session_role(call->ice_session) == IR_Controlling && current_param->update_call_when_ice_completed ) { + if (ice_session_role(call->ice_session) == IR_Controlling && linphone_call_params_get_update_call_when_ice_completed(current_param)) { LinphoneCallParams *params = linphone_core_create_call_params(call->core, call); - params->internal_call_update = TRUE; + linphone_call_params_set_internal_call_update(params, TRUE); linphone_call_update(call, params); linphone_call_params_unref(params); } @@ -4942,7 +4942,7 @@ void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState stat } bool_t linphone_call_is_in_conference(const LinphoneCall *call) { - return call->params->in_conference; + return linphone_call_params_get_in_conference(call->params); } LinphoneConference *linphone_call_get_conference(const LinphoneCall *call) { @@ -5286,7 +5286,7 @@ LinphoneStatus linphone_call_resume(LinphoneCall *call) { return -1; } lc = linphone_call_get_core(call); - if (call->params->in_conference == FALSE) { + if (linphone_call_params_get_in_conference(call->params) == FALSE) { if (linphone_core_sound_resources_locked(lc)) { ms_warning("Cannot resume call %p because another call is locking the sound resources.", call); return -1; @@ -5314,12 +5314,12 @@ LinphoneStatus linphone_call_resume(LinphoneCall *call) { sal_call_set_local_media_description(call->op, NULL); } sal_media_description_set_dir(call->localdesc, SalStreamSendRecv); - if (call->params->in_conference && !call->current_params->in_conference) subject = "Conference"; + if (linphone_call_params_get_in_conference(call->params) && !linphone_call_params_get_in_conference(call->current_params)) subject = "Conference"; if (sal_call_update(call->op, subject, FALSE) != 0) { return -1; } linphone_call_set_state(call, LinphoneCallResuming,"Resuming"); - if (call->params->in_conference == FALSE) + if (linphone_call_params_get_in_conference(call->params) == FALSE) lc->current_call = call; remote_address = linphone_call_get_remote_address_as_string(call); display_status = ms_strdup_printf("Resuming the call with with %s", remote_address); @@ -5548,7 +5548,7 @@ LinphoneStatus linphone_call_accept_with_params(LinphoneCall *call, const Linpho linphone_call_prepare_ice(call, TRUE); linphone_call_make_local_media_description(call); sal_call_set_local_media_description(call->op, call->localdesc); - sal_op_set_sent_custom_header(call->op, params->custom_headers); + sal_op_set_sent_custom_header(call->op, linphone_call_params_get_custom_headers(params)); } /* Give a chance a set card prefered sampling frequency */ @@ -5603,7 +5603,7 @@ LinphoneStatus linphone_call_accept_early_media_with_params(LinphoneCall *call, _linphone_call_set_new_params(call, params); linphone_call_make_local_media_description(call); sal_call_set_local_media_description(call->op, call->localdesc); - sal_op_set_sent_custom_header(call->op, params->custom_headers); + sal_op_set_sent_custom_header(call->op, linphone_call_params_get_custom_headers(params)); } sal_call_notify_ringing(call->op, TRUE); @@ -5720,7 +5720,7 @@ LinphoneStatus linphone_call_update(LinphoneCall *call, const LinphoneCallParams int linphone_call_start_update(LinphoneCall *call) { const char *subject; int err; - bool_t no_user_consent = call->params->no_user_consent; + bool_t no_user_consent = linphone_call_params_get_no_user_consent(call->params); LinphoneCore *lc = linphone_call_get_core(call); linphone_call_fill_media_multicast_addr(call); @@ -5731,9 +5731,9 @@ int linphone_call_start_update(LinphoneCall *call) { linphone_call_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); } #endif // BUILD_UPNP - if (call->params->in_conference) { + if (linphone_call_params_get_in_conference(call->params)) { subject = "Conference"; - } else if (call->params->internal_call_update) { + } else if (linphone_call_params_get_internal_call_update(call->params)) { subject = "ICE processing concluded"; } else if (no_user_consent) { subject = "Refreshing"; @@ -5824,13 +5824,13 @@ int _linphone_call_accept_update(LinphoneCall *call, const LinphoneCallParams *p _linphone_call_set_new_params(call, params); } - if (call->params->has_video && !linphone_core_video_enabled(lc)) { + if (linphone_call_params_video_enabled(call->params) && !linphone_core_video_enabled(lc)) { ms_warning("Requested video but video support is globally disabled. Refusing video."); - call->params->has_video = FALSE; + linphone_call_params_enable_video(call->params, FALSE); } - if (call->current_params->in_conference) { + if (linphone_call_params_get_in_conference(call->current_params)) { ms_warning("Video isn't supported in conference"); - call->params->has_video = FALSE; + linphone_call_params_enable_video(call->params, FALSE); } /* Update multicast params according to call params */ linphone_call_fill_media_multicast_addr(call); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 5c881db24..b3a6a8d7e 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3340,10 +3340,10 @@ LinphoneCall * linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall * } if (!params){ - cp->has_audio = call->current_params->has_audio; - cp->has_video = call->current_params->has_video; /*start the call to refer-target with video enabled if original call had video*/ + linphone_call_params_enable_audio(cp, linphone_call_params_audio_enabled(call->current_params)); + linphone_call_params_enable_video(cp, linphone_call_params_video_enabled(call->current_params)); /*start the call to refer-target with video enabled if original call had video*/ } - cp->referer=call; + linphone_call_params_set_referer(cp, call); ms_message("Starting new call to refered address %s",call->refer_to); call->refer_pending=FALSE; newcall=linphone_core_invite_with_params(lc,call->refer_to,cp); @@ -3456,7 +3456,7 @@ const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAdd LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url){ LinphoneCall *call; LinphoneCallParams *p=linphone_core_create_call_params(lc, NULL); - p->has_video &= !!lc->video_policy.automatically_initiate; + linphone_call_params_enable_video(p, linphone_call_params_video_enabled(p) & !!lc->video_policy.automatically_initiate); call=linphone_core_invite_with_params(lc,url,p); linphone_call_params_unref(p); return call; @@ -3476,7 +3476,7 @@ LinphoneCall * linphone_core_invite_with_params(LinphoneCore *lc, const char *ur LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr){ LinphoneCall *call; LinphoneCallParams *p=linphone_core_create_call_params(lc, NULL); - p->has_video &= !!lc->video_policy.automatically_initiate; + linphone_call_params_enable_video(p, linphone_call_params_video_enabled(p) & !!lc->video_policy.automatically_initiate); call=linphone_core_invite_address_with_params (lc,addr,p); linphone_call_params_unref(p); return call; @@ -3554,11 +3554,11 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const if (proxy!=NULL) { from=linphone_proxy_config_get_identity(proxy); - cp->avpf_enabled = linphone_proxy_config_avpf_enabled(proxy); - cp->avpf_rr_interval = linphone_proxy_config_get_avpf_rr_interval(proxy) * 1000; + linphone_call_params_enable_avpf(cp, linphone_proxy_config_avpf_enabled(proxy)); + linphone_call_params_set_avpf_rr_interval(cp, linphone_proxy_config_get_avpf_rr_interval(proxy) * 1000); }else{ - cp->avpf_enabled=linphone_core_get_avpf_mode(lc)==LinphoneAVPFEnabled; - if (cp->avpf_enabled) cp->avpf_rr_interval=linphone_core_get_avpf_rr_interval(lc) * 1000; + linphone_call_params_enable_avpf(cp, linphone_core_get_avpf_mode(lc)==LinphoneAVPFEnabled); + if (linphone_call_params_avpf_enabled(cp)) linphone_call_params_set_avpf_rr_interval(cp, linphone_core_get_avpf_rr_interval(lc) * 1000); } /* if no proxy or no identity defined for this proxy, default to primary contact*/ @@ -6808,26 +6808,26 @@ void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m) { } void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params) { - params->has_audio = TRUE; - params->has_video=linphone_core_video_enabled(lc) && lc->video_policy.automatically_initiate; + linphone_call_params_enable_audio(params, TRUE); + linphone_call_params_enable_video(params, linphone_core_video_enabled(lc) && lc->video_policy.automatically_initiate); if (!linphone_core_video_enabled(lc) && lc->video_policy.automatically_initiate){ ms_error("LinphoneCore has video disabled for both capture and display, but video policy is to start the call with video. " "This is a possible mis-use of the API. In this case, video is disabled in default LinphoneCallParams"); } - params->media_encryption=linphone_core_get_media_encryption(lc); - params->in_conference=FALSE; - params->realtimetext_enabled = linphone_core_realtime_text_enabled(lc); - params->privacy=LinphonePrivacyDefault; - params->avpf_enabled=linphone_core_get_avpf_mode(lc); - params->implicit_rtcp_fb = lp_config_get_int(lc->config,"rtp","rtcp_fb_implicit_rtcp_fb",TRUE); - params->avpf_rr_interval = linphone_core_get_avpf_rr_interval(lc); - params->audio_dir=LinphoneMediaDirectionSendRecv; - params->video_dir=LinphoneMediaDirectionSendRecv; - params->real_early_media=lp_config_get_int(lc->config,"misc","real_early_media",FALSE); - params->audio_multicast_enabled=linphone_core_audio_multicast_enabled(lc); - params->video_multicast_enabled=linphone_core_video_multicast_enabled(lc); - params->update_call_when_ice_completed = lp_config_get_int(lc->config, "sip", "update_call_when_ice_completed", TRUE); - params->encryption_mandatory = linphone_core_is_media_encryption_mandatory(lc); + linphone_call_params_set_media_encryption(params, linphone_core_get_media_encryption(lc)); + linphone_call_params_set_in_conference(params, FALSE); + linphone_call_params_enable_realtime_text(params, linphone_core_realtime_text_enabled(lc)); + linphone_call_params_set_privacy(params, LinphonePrivacyDefault); + linphone_call_params_enable_avpf(params, linphone_core_get_avpf_mode(lc)); + linphone_call_params_enable_implicit_rtcp_fb(params, lp_config_get_int(lc->config,"rtp","rtcp_fb_implicit_rtcp_fb",TRUE)); + linphone_call_params_set_avpf_rr_interval(params, linphone_core_get_avpf_rr_interval(lc)); + linphone_call_params_set_audio_direction(params, LinphoneMediaDirectionSendRecv); + linphone_call_params_set_video_direction(params, LinphoneMediaDirectionSendRecv); + linphone_call_params_enable_early_media_sending(params, lp_config_get_int(lc->config,"misc","real_early_media",FALSE)); + linphone_call_params_enable_audio_multicast(params, linphone_core_audio_multicast_enabled(lc)); + linphone_call_params_enable_video_multicast(params, linphone_core_video_multicast_enabled(lc)); + linphone_call_params_set_update_call_when_ice_completed(params, lp_config_get_int(lc->config, "sip", "update_call_when_ice_completed", TRUE)); + linphone_call_params_enable_mandatory_media_encryption(params, linphone_core_is_media_encryption_mandatory(lc)); } void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) { diff --git a/coreapi/misc.c b/coreapi/misc.c index fe10698aa..709e3e83f 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -464,13 +464,15 @@ void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, Linphone if (ping_time_ms>threshold){ /* we might be in a 2G network*/ - params->low_bandwidth=TRUE; + linphone_call_params_enable_low_bandwidth(params, TRUE); }/*else use default settings */ } - if (params->low_bandwidth){ - params->up_bw=params->down_bw=linphone_core_get_edge_bw(lc); - params->up_ptime=params->down_ptime=linphone_core_get_edge_ptime(lc); - params->has_video=FALSE; + if (linphone_call_params_low_bandwidth_enabled(params)){ + linphone_call_params_set_up_bandwidth(params, linphone_core_get_edge_bw(lc)); + linphone_call_params_set_down_bandwidth(params, linphone_core_get_edge_bw(lc)); + linphone_call_params_set_up_ptime(params, linphone_core_get_edge_ptime(lc)); + linphone_call_params_set_down_ptime(params, linphone_core_get_edge_ptime(lc)); + linphone_call_params_enable_video(params, FALSE); } } @@ -555,7 +557,7 @@ static void linphone_core_add_local_ice_candidates(LinphoneCall *call, int famil ice_add_local_candidate(video_cl, "host", family, addr, call->media_ports[call->main_video_stream_index].rtcp_port, 2, NULL); call->video_stats->ice_state = LinphoneIceStateInProgress; } - if (call->params->realtimetext_enabled && (text_cl != NULL) + if (linphone_call_params_realtime_text_enabled(call->params) && (text_cl != NULL) && (ice_check_list_state(text_cl) != ICL_Completed) && (ice_check_list_candidates_gathered(text_cl) == FALSE)) { ice_add_local_candidate(text_cl, "host", family, addr, call->media_ports[call->main_text_stream_index].rtp_port, 1, NULL); ice_add_local_candidate(text_cl, "host", family, addr, call->media_ports[call->main_text_stream_index].rtcp_port, 2, NULL); @@ -706,7 +708,7 @@ void linphone_call_update_ice_state_in_call_stats(LinphoneCall *call) { session_state = ice_session_state(call->ice_session); if ((session_state == IS_Completed) || ((session_state == IS_Failed) && (ice_session_has_completed_check_list(call->ice_session) == TRUE))) { - if (call->params->has_audio && (audio_check_list != NULL)) { + if (linphone_call_params_audio_enabled(call->params) && (audio_check_list != NULL)) { if (ice_check_list_state(audio_check_list) == ICL_Completed) { switch (ice_check_list_selected_valid_candidate_type(audio_check_list)) { case ICT_HostCandidate: @@ -729,7 +731,7 @@ void linphone_call_update_ice_state_in_call_stats(LinphoneCall *call) { } }else call->audio_stats->ice_state = LinphoneIceStateNotActivated; - if (call->params->has_video && (video_check_list != NULL)) { + if (linphone_call_params_video_enabled(call->params) && (video_check_list != NULL)) { if (ice_check_list_state(video_check_list) == ICL_Completed) { switch (ice_check_list_selected_valid_candidate_type(video_check_list)) { case ICT_HostCandidate: @@ -752,7 +754,7 @@ void linphone_call_update_ice_state_in_call_stats(LinphoneCall *call) { } }else call->video_stats->ice_state = LinphoneIceStateNotActivated; - if (call->params->realtimetext_enabled && (text_check_list != NULL)) { + if (linphone_call_params_realtime_text_enabled(call->params) && (text_check_list != NULL)) { if (ice_check_list_state(text_check_list) == ICL_Completed) { switch (ice_check_list_selected_valid_candidate_type(text_check_list)) { case ICT_HostCandidate: @@ -776,18 +778,18 @@ void linphone_call_update_ice_state_in_call_stats(LinphoneCall *call) { }else call->text_stats->ice_state = LinphoneIceStateNotActivated; } else if (session_state == IS_Running) { call->audio_stats->ice_state = LinphoneIceStateInProgress; - if (call->params->has_video && (video_check_list != NULL)) { + if (linphone_call_params_video_enabled(call->params) && (video_check_list != NULL)) { call->video_stats->ice_state = LinphoneIceStateInProgress; } - if (call->params->realtimetext_enabled && (text_check_list != NULL)) { + if (linphone_call_params_realtime_text_enabled(call->params) && (text_check_list != NULL)) { call->text_stats->ice_state = LinphoneIceStateInProgress; } } else { call->audio_stats->ice_state = LinphoneIceStateFailed; - if (call->params->has_video && (video_check_list != NULL)) { + if (linphone_call_params_video_enabled(call->params) && (video_check_list != NULL)) { call->video_stats->ice_state = LinphoneIceStateFailed; } - if (call->params->realtimetext_enabled && (text_check_list != NULL)) { + if (linphone_call_params_realtime_text_enabled(call->params) && (text_check_list != NULL)) { call->text_stats->ice_state = LinphoneIceStateFailed; } } diff --git a/coreapi/private.h b/coreapi/private.h index 24f2b2649..5418287e4 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -131,54 +131,6 @@ extern "C" { #define STRING_SET(field, value) do{ if (field){bctbx_free(field);field=NULL;}; field=bctbx_strdup(value); }while(0) #define STRING_TRANSFER(field, newvalue) do{ if (field){bctbx_free(field);field=NULL;}; field=newvalue; }while(0) -struct _LinphoneCallParams{ - belle_sip_object_t base; - void *user_data; - LinphoneCall *referer; /*in case this call creation is consecutive to an incoming transfer, this points to the original call */ - int audio_bw; /* bandwidth limit for audio stream */ - LinphoneMediaEncryption media_encryption; - PayloadType *audio_codec; /*audio codec currently in use */ - PayloadType *video_codec; /*video codec currently in use */ - PayloadType *text_codec; /*text codec currently in use */ - MSVideoSize sent_vsize; /* DEPRECATED: Size of the video currently being sent */ - MSVideoSize recv_vsize; /* DEPRECATED: Size of the video currently being received */ - LinphoneVideoDefinition *sent_vdef; /* Definition of the video currently being sent */ - LinphoneVideoDefinition *recv_vdef; /* Definition of the video currrently being received */ - float received_fps,sent_fps; - int down_bw; - int up_bw; - int down_ptime; - int up_ptime; - char *record_file; - char *session_name; - SalCustomHeader *custom_headers; - SalCustomSdpAttribute *custom_sdp_attributes; - SalCustomSdpAttribute *custom_sdp_media_attributes[LinphoneStreamTypeUnknown]; - LinphonePrivacyMask privacy; - LinphoneMediaDirection audio_dir; - LinphoneMediaDirection video_dir; - bool_t has_audio; - bool_t has_video; - bool_t avpf_enabled; /* RTCP feedback messages are enabled */ - bool_t implicit_rtcp_fb; - - bool_t real_early_media; /*send real media even during early media (for outgoing calls)*/ - bool_t in_conference; /*in conference mode */ - bool_t low_bandwidth; - bool_t no_user_consent;/*when set to TRUE an UPDATE request will be used instead of reINVITE*/ - - uint16_t avpf_rr_interval; /*in milliseconds*/ - bool_t internal_call_update; /*use mark that call update was requested internally (might be by ice) - unused for the moment*/ - bool_t video_multicast_enabled; - - bool_t audio_multicast_enabled; - bool_t realtimetext_enabled; - bool_t update_call_when_ice_completed; - bool_t encryption_mandatory; -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneCallParams); - typedef enum _ImdnType { ImdnTypeDelivery, @@ -445,6 +397,38 @@ SalStreamDir get_video_dir_from_call_params(const LinphoneCallParams *params); void linphone_call_params_set_custom_headers(LinphoneCallParams *params, const SalCustomHeader *ch); void linphone_call_params_set_custom_sdp_attributes(LinphoneCallParams *params, const SalCustomSdpAttribute *csa); void linphone_call_params_set_custom_sdp_media_attributes(LinphoneCallParams *params, LinphoneStreamType type, const SalCustomSdpAttribute *csa); +bool_t linphone_call_params_get_in_conference(const LinphoneCallParams *params); +void linphone_call_params_set_in_conference(LinphoneCallParams *params, bool_t value); +bool_t linphone_call_params_get_internal_call_update(const LinphoneCallParams *params); +void linphone_call_params_set_internal_call_update(LinphoneCallParams *params, bool_t value); +bool_t linphone_call_params_implicit_rtcp_fb_enabled(const LinphoneCallParams *params); +void linphone_call_params_enable_implicit_rtcp_fb(LinphoneCallParams *params, bool_t value); +int linphone_call_params_get_down_bandwidth(const LinphoneCallParams *params); +void linphone_call_params_set_down_bandwidth(LinphoneCallParams *params, int value); +int linphone_call_params_get_up_bandwidth(const LinphoneCallParams *params); +void linphone_call_params_set_up_bandwidth(LinphoneCallParams *params, int value); +int linphone_call_params_get_down_ptime(const LinphoneCallParams *params); +void linphone_call_params_set_down_ptime(LinphoneCallParams *params, int value); +int linphone_call_params_get_up_ptime(const LinphoneCallParams *params); +void linphone_call_params_set_up_ptime(LinphoneCallParams *params, int value); +SalCustomHeader * linphone_call_params_get_custom_headers(const LinphoneCallParams *params); +SalCustomSdpAttribute * linphone_call_params_get_custom_sdp_attributes(const LinphoneCallParams *params); +SalCustomSdpAttribute * linphone_call_params_get_custom_sdp_media_attributes(const LinphoneCallParams *params, LinphoneStreamType type); +LinphoneCall * linphone_call_params_get_referer(const LinphoneCallParams *params); +void linphone_call_params_set_referer(LinphoneCallParams *params, LinphoneCall *referer); +bool_t linphone_call_params_get_update_call_when_ice_completed(const LinphoneCallParams *params); +void linphone_call_params_set_update_call_when_ice_completed(LinphoneCallParams *params, bool_t value); +void linphone_call_params_set_sent_vsize(LinphoneCallParams *params, MSVideoSize vsize); +void linphone_call_params_set_recv_vsize(LinphoneCallParams *params, MSVideoSize vsize); +void linphone_call_params_set_sent_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef); +void linphone_call_params_set_received_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef); +void linphone_call_params_set_sent_fps(LinphoneCallParams *params, float value); +void linphone_call_params_set_received_fps(LinphoneCallParams *params, float value); +void linphone_call_params_set_used_audio_codec(LinphoneCallParams *params, OrtpPayloadType *codec); +void linphone_call_params_set_used_video_codec(LinphoneCallParams *params, OrtpPayloadType *codec); +void linphone_call_params_set_used_text_codec(LinphoneCallParams *params, OrtpPayloadType *codec); +bool_t linphone_call_params_get_no_user_consent(const LinphoneCallParams *params); +void linphone_call_params_set_no_user_consent(LinphoneCallParams *params, bool_t value); void linphone_auth_info_write_config(LinphoneConfig *config, LinphoneAuthInfo *obj, int pos); LinphoneAuthInfo * linphone_auth_info_new_from_config_file(LpConfig *config, int pos); diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index bee5dc6dc..3c3289f8b 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -545,15 +545,15 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { /*yet we use the same payload config for local and remote, since this is the largest use case*/ if (stats_type == LINPHONE_CALL_STATS_AUDIO && call->audiostream != NULL) { stream = &call->audiostream->ms; - local_payload = current_params->audio_codec; + local_payload = linphone_call_params_get_used_audio_codec(current_params); remote_payload = local_payload; } else if (stats_type == LINPHONE_CALL_STATS_VIDEO && call->videostream != NULL) { stream = &call->videostream->ms; - local_payload = current_params->video_codec; + local_payload = linphone_call_params_get_used_video_codec(current_params); remote_payload = local_payload; } else if (stats_type == LINPHONE_CALL_STATS_TEXT && call->textstream != NULL) { stream = &call->textstream->ms; - local_payload = current_params->text_codec; + local_payload = linphone_call_params_get_used_text_codec(current_params); remote_payload = local_payload; } diff --git a/include/linphone/call_params.h b/include/linphone/call_params.h index 173cca313..a483232cc 100644 --- a/include/linphone/call_params.h +++ b/include/linphone/call_params.h @@ -338,6 +338,16 @@ LINPHONE_PUBLIC void linphone_call_params_set_audio_direction(LinphoneCallParams LINPHONE_PUBLIC void linphone_call_params_set_video_direction(LinphoneCallParams *cp, LinphoneMediaDirection dir); +int linphone_call_params_get_audio_bandwidth_limit(const LinphoneCallParams *params); +bool_t linphone_call_params_real_early_media_enabled(const LinphoneCallParams *params); +bool_t linphone_call_params_avpf_enabled(const LinphoneCallParams *params); +void linphone_call_params_enable_avpf(LinphoneCallParams *params, bool_t enable); +bool_t linphone_call_params_mandatory_media_encryption_enabled(const LinphoneCallParams *params); +void linphone_call_params_enable_mandatory_media_encryption(LinphoneCallParams *params, bool_t value); +uint16_t linphone_call_params_get_avpf_rr_interval(const LinphoneCallParams *params); +void linphone_call_params_set_avpf_rr_interval(LinphoneCallParams *params, uint16_t value); + + /******************************************************************************* * Reference and user data handling functions * ******************************************************************************/ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c744240b8..0a895b87e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -34,6 +34,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES conference/params/call-session-params.h conference/params/call-session-params-p.h conference/params/media-session-params.h + conference/params/media-session-params-p.h conference/participant.h conference/remote-conference.h conference/session/call-session.h diff --git a/src/conference/params/call-session-params-p.h b/src/conference/params/call-session-params-p.h index 0ff9181e1..0aa300aa3 100644 --- a/src/conference/params/call-session-params-p.h +++ b/src/conference/params/call-session-params-p.h @@ -16,28 +16,58 @@ * along with this program. If not, see . */ -#ifndef _CONFERENCE_CALL_SESSION_PARAMS_P_H_ -#define _CONFERENCE_CALL_SESSION_PARAMS_P_H_ +#ifndef _CALL_SESSION_PARAMS_P_H_ +#define _CALL_SESSION_PARAMS_P_H_ -#include "object/object-p.h" +#include "object/clonable-object-p.h" #include "call-session-params.h" -#include "linphone/types.h" - // ============================================================================= -namespace LinphonePrivate { - namespace Conference { - class CallSessionParamsPrivate : public ObjectPrivate { - public: - virtual ~CallSessionParamsPrivate () = default; +LINPHONE_BEGIN_NAMESPACE - LinphonePrivacyMask privacy = LinphonePrivacyNone; +class CallSessionParamsPrivate : public ClonableObjectPrivate { +public: + CallSessionParamsPrivate () = default; + CallSessionParamsPrivate (const CallSessionParamsPrivate &src); + virtual ~CallSessionParamsPrivate (); - L_DECLARE_PUBLIC(CallSessionParams); - }; - } -} + bool getInConference () const { return inConference; } + void setInConference (bool value) { inConference = value; } + bool getInternalCallUpdate () const { return internalCallUpdate; } + void setInternalCallUpdate (bool value) { internalCallUpdate = value; } + bool getNoUserConsent () const { return noUserConsent; } + void setNoUserConsent (bool value) { noUserConsent = value; } -#endif // ifndef _CONFERENCE_CALL_SESSION_PARAMS_P_H_ + SalCustomHeader * getCustomHeaders () const; + void setCustomHeaders (const SalCustomHeader *ch); + SalCustomSdpAttribute * getCustomSdpAttributes () const; + void setCustomSdpAttributes (const SalCustomSdpAttribute *csa); + SalCustomSdpAttribute * getCustomSdpMediaAttributes (LinphoneStreamType lst) const; + void setCustomSdpMediaAttributes (LinphoneStreamType lst, const SalCustomSdpAttribute *csa); + + LinphoneCall *getReferer () const { return referer; } + void setReferer (LinphoneCall *call) { referer = call; } + +public: + std::string sessionName; + + LinphonePrivacyMask privacy = LinphonePrivacyNone; + +private: + bool inConference = false; + bool internalCallUpdate = false; + bool noUserConsent = false; /* When set to true an UPDATE request will be used instead of reINVITE */ + SalCustomHeader *customHeaders = nullptr; + SalCustomSdpAttribute *customSdpAttributes = nullptr; + SalCustomSdpAttribute *customSdpMediaAttributes[LinphoneStreamTypeUnknown]; + LinphoneCall *referer = nullptr; /* In case call creation is consecutive to an incoming transfer, this points to the original call */ + +public: + L_DECLARE_PUBLIC(CallSessionParams); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CALL_SESSION_PARAMS_P_H_ diff --git a/src/conference/params/call-session-params.cpp b/src/conference/params/call-session-params.cpp index bfab89a94..dae870ad2 100644 --- a/src/conference/params/call-session-params.cpp +++ b/src/conference/params/call-session-params.cpp @@ -20,8 +20,171 @@ #include "call-session-params.h" -using namespace LinphonePrivate; +using namespace std; + +LINPHONE_BEGIN_NAMESPACE // ============================================================================= -Conference::CallSessionParams::CallSessionParams (CallSessionParamsPrivate &p) : Object(p) {} +CallSessionParamsPrivate::CallSessionParamsPrivate (const CallSessionParamsPrivate &src) { + sessionName = src.sessionName; + privacy = src.privacy; + inConference = src.inConference; + internalCallUpdate = src.internalCallUpdate; + noUserConsent = src.noUserConsent; + /* The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient. */ + if (src.customHeaders) + customHeaders = sal_custom_header_clone(src.customHeaders); + if (src.customSdpAttributes) + customSdpAttributes = sal_custom_sdp_attribute_clone(src.customSdpAttributes); + for (unsigned int i = 0; i < (unsigned int)LinphoneStreamTypeUnknown; i++) { + if (src.customSdpMediaAttributes[i]) + customSdpMediaAttributes[i] = sal_custom_sdp_attribute_clone(src.customSdpMediaAttributes[i]); + } + referer = src.referer; +} + +CallSessionParamsPrivate::~CallSessionParamsPrivate () { + if (customHeaders) + sal_custom_header_free(customHeaders); + if (customSdpAttributes) + sal_custom_sdp_attribute_free(customSdpAttributes); + for (unsigned int i = 0; i < (unsigned int)LinphoneStreamTypeUnknown; i++) { + if (customSdpMediaAttributes[i]) + sal_custom_sdp_attribute_free(customSdpMediaAttributes[i]); + } +} + +// ----------------------------------------------------------------------------- + +SalCustomHeader * CallSessionParamsPrivate::getCustomHeaders () const { + return customHeaders; +} + +void CallSessionParamsPrivate::setCustomHeaders (const SalCustomHeader *ch) { + if (customHeaders) { + sal_custom_header_free(customHeaders); + customHeaders = nullptr; + } + if (ch) + customHeaders = sal_custom_header_clone(ch); +} + +// ----------------------------------------------------------------------------- + +SalCustomSdpAttribute * CallSessionParamsPrivate::getCustomSdpAttributes () const { + return customSdpAttributes; +} + +void CallSessionParamsPrivate::setCustomSdpAttributes (const SalCustomSdpAttribute *csa) { + if (customSdpAttributes) { + sal_custom_sdp_attribute_free(customSdpAttributes); + customSdpAttributes = nullptr; + } + if (csa) + customSdpAttributes = sal_custom_sdp_attribute_clone(csa); +} + +// ----------------------------------------------------------------------------- + +SalCustomSdpAttribute * CallSessionParamsPrivate::getCustomSdpMediaAttributes (LinphoneStreamType lst) const { + return customSdpMediaAttributes[lst]; +} + +void CallSessionParamsPrivate::setCustomSdpMediaAttributes (LinphoneStreamType lst, const SalCustomSdpAttribute *csa) { + if (customSdpMediaAttributes[lst]) { + sal_custom_sdp_attribute_free(customSdpMediaAttributes[lst]); + customSdpMediaAttributes[lst] = nullptr; + } + if (csa) + customSdpMediaAttributes[lst] = sal_custom_sdp_attribute_clone(csa); +} + +// ============================================================================= + +CallSessionParams::CallSessionParams () : ClonableObject(*new CallSessionParamsPrivate) {} + +CallSessionParams::CallSessionParams (CallSessionParamsPrivate &p) : ClonableObject(p) { + L_D(CallSessionParams); + memset(d->customSdpMediaAttributes, 0, sizeof(d->customSdpMediaAttributes)); +} + +CallSessionParams::CallSessionParams (const CallSessionParams &src) + : ClonableObject(*new CallSessionParamsPrivate(*src.getPrivate())) {} + +// ----------------------------------------------------------------------------- + +const string& CallSessionParams::getSessionName () const { + L_D(const CallSessionParams); + return d->sessionName; +} + +void CallSessionParams::setSessionName (const string &sessionName) { + L_D(CallSessionParams); + d->sessionName = sessionName; +} + +// ----------------------------------------------------------------------------- + +LinphonePrivacyMask CallSessionParams::getPrivacy () const { + L_D(const CallSessionParams); + return d->privacy; +} + +void CallSessionParams::setPrivacy (LinphonePrivacyMask privacy) { + L_D(CallSessionParams); + d->privacy = privacy; +} + +// ----------------------------------------------------------------------------- + +void CallSessionParams::addCustomHeader (const string &headerName, const string &headerValue) { + L_D(CallSessionParams); + d->customHeaders = sal_custom_header_append(d->customHeaders, headerName.c_str(), headerValue.c_str()); +} + +void CallSessionParams::clearCustomHeaders () { + L_D(CallSessionParams); + d->setCustomHeaders(nullptr); +} + +const char * CallSessionParams::getCustomHeader (const string &headerName) const { + L_D(const CallSessionParams); + return sal_custom_header_find(d->customHeaders, headerName.c_str()); +} + +// ----------------------------------------------------------------------------- + +void CallSessionParams::addCustomSdpAttribute (const string &attributeName, const string &attributeValue) { + L_D(CallSessionParams); + d->customSdpAttributes = sal_custom_sdp_attribute_append(d->customSdpAttributes, attributeName.c_str(), attributeValue.c_str()); +} + +void CallSessionParams::clearCustomSdpAttributes () { + L_D(CallSessionParams); + d->setCustomSdpAttributes(nullptr); +} + +const char * CallSessionParams::getCustomSdpAttribute (const string &attributeName) const { + L_D(const CallSessionParams); + return sal_custom_sdp_attribute_find(d->customSdpAttributes, attributeName.c_str()); +} + +// ----------------------------------------------------------------------------- + +void CallSessionParams::addCustomSdpMediaAttribute (LinphoneStreamType lst, const string &attributeName, const string &attributeValue) { + L_D(CallSessionParams); + d->customSdpMediaAttributes[lst] = sal_custom_sdp_attribute_append(d->customSdpMediaAttributes[lst], attributeName.c_str(), attributeValue.c_str()); +} + +void CallSessionParams::clearCustomSdpMediaAttributes (LinphoneStreamType lst) { + L_D(CallSessionParams); + d->setCustomSdpMediaAttributes(lst, nullptr); +} + +const char * CallSessionParams::getCustomSdpMediaAttribute (LinphoneStreamType lst, const string &attributeName) const { + L_D(const CallSessionParams); + return sal_custom_sdp_attribute_find(d->customSdpMediaAttributes[lst], attributeName.c_str()); +} + +LINPHONE_END_NAMESPACE diff --git a/src/conference/params/call-session-params.h b/src/conference/params/call-session-params.h index 8414987f6..68d6ca716 100644 --- a/src/conference/params/call-session-params.h +++ b/src/conference/params/call-session-params.h @@ -16,29 +16,85 @@ * along with this program. If not, see . */ -#ifndef _CONFERENCE_CALL_SESSION_PARAMS_H_ -#define _CONFERENCE_CALL_SESSION_PARAMS_H_ +#ifndef _CALL_SESSION_PARAMS_H_ +#define _CALL_SESSION_PARAMS_H_ -#include "object/object.h" +#include + +#include "object/clonable-object.h" + +#include "linphone/types.h" +#include "sal/sal.h" + +extern "C" { + bool_t linphone_call_params_get_in_conference(const LinphoneCallParams *params); + void linphone_call_params_set_in_conference(LinphoneCallParams *params, bool_t value); + bool_t linphone_call_params_get_internal_call_update(const LinphoneCallParams *params); + void linphone_call_params_set_internal_call_update(LinphoneCallParams *params, bool_t value); + bool_t linphone_call_params_get_no_user_consent(const LinphoneCallParams *params); + void linphone_call_params_set_no_user_consent(LinphoneCallParams *params, bool_t value); + SalCustomHeader * linphone_call_params_get_custom_headers(const LinphoneCallParams *params); + void linphone_call_params_set_custom_headers(LinphoneCallParams *params, const SalCustomHeader *ch); + SalCustomSdpAttribute * linphone_call_params_get_custom_sdp_attributes(const LinphoneCallParams *params); + void linphone_call_params_set_custom_sdp_attributes(LinphoneCallParams *params, const SalCustomSdpAttribute *csa); + SalCustomSdpAttribute * linphone_call_params_get_custom_sdp_media_attributes(const LinphoneCallParams *params, LinphoneStreamType type); + void linphone_call_params_set_custom_sdp_media_attributes(LinphoneCallParams *params, LinphoneStreamType type, const SalCustomSdpAttribute *csa); + LinphoneCall * linphone_call_params_get_referer(const LinphoneCallParams *params); + void linphone_call_params_set_referer(LinphoneCallParams *params, LinphoneCall *referer); +} // ============================================================================= -namespace LinphonePrivate { - namespace Conference { - class CallSessionParamsPrivate; +LINPHONE_BEGIN_NAMESPACE - class CallSessionParams : public Object { - public: - CallSessionParams (); +class CallSessionParamsPrivate; - protected: - explicit CallSessionParams (CallSessionParamsPrivate &p); +class CallSessionParams : public ClonableObject { + friend unsigned char ::linphone_call_params_get_in_conference(const LinphoneCallParams *params); + friend void ::linphone_call_params_set_in_conference(LinphoneCallParams *params, unsigned char value); + friend unsigned char ::linphone_call_params_get_internal_call_update(const LinphoneCallParams *params); + friend void ::linphone_call_params_set_internal_call_update(LinphoneCallParams *params, unsigned char value); + friend unsigned char ::linphone_call_params_get_no_user_consent(const LinphoneCallParams *params); + friend void ::linphone_call_params_set_no_user_consent(LinphoneCallParams *params, unsigned char value); + friend SalCustomHeader * ::linphone_call_params_get_custom_headers(const LinphoneCallParams *params); + friend void ::linphone_call_params_set_custom_headers(LinphoneCallParams *params, const SalCustomHeader *ch); + friend SalCustomSdpAttribute * ::linphone_call_params_get_custom_sdp_attributes(const LinphoneCallParams *params); + friend void ::linphone_call_params_set_custom_sdp_attributes(LinphoneCallParams *params, const SalCustomSdpAttribute *csa); + friend SalCustomSdpAttribute * ::linphone_call_params_get_custom_sdp_media_attributes(const LinphoneCallParams *params, LinphoneStreamType type); + friend void ::linphone_call_params_set_custom_sdp_media_attributes(LinphoneCallParams *params, LinphoneStreamType type, const SalCustomSdpAttribute *csa); + friend LinphoneCall * ::linphone_call_params_get_referer(const LinphoneCallParams *params); + friend void ::linphone_call_params_set_referer(LinphoneCallParams *params, LinphoneCall *referer); - private: - L_DECLARE_PRIVATE(CallSessionParams); - L_DISABLE_COPY(CallSessionParams); - }; - } -} +public: + CallSessionParams (); + CallSessionParams (const CallSessionParams &src); + virtual ~CallSessionParams () = default; -#endif // ifndef _CONFERENCE_CALL_SESSION_PARAMS_H_ + const std::string& getSessionName () const; + void setSessionName (const std::string &sessionName); + + LinphonePrivacyMask getPrivacy () const; + void setPrivacy (LinphonePrivacyMask privacy); + + void addCustomHeader (const std::string &headerName, const std::string &headerValue); + void clearCustomHeaders (); + const char * getCustomHeader (const std::string &headerName) const; + + void addCustomSdpAttribute (const std::string &attributeName, const std::string &attributeValue); + void clearCustomSdpAttributes (); + const char * getCustomSdpAttribute (const std::string &attributeName) const; + + void addCustomSdpMediaAttribute (LinphoneStreamType lst, const std::string &attributeName, const std::string &attributeValue); + void clearCustomSdpMediaAttributes (LinphoneStreamType lst); + const char * getCustomSdpMediaAttribute (LinphoneStreamType lst, const std::string &attributeName) const; + +protected: + explicit CallSessionParams (CallSessionParamsPrivate &p); + +private: + L_DECLARE_PRIVATE(CallSessionParams); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CALL_SESSION_PARAMS_H_ diff --git a/src/conference/params/media-session-params-p.h b/src/conference/params/media-session-params-p.h new file mode 100644 index 000000000..867c990bb --- /dev/null +++ b/src/conference/params/media-session-params-p.h @@ -0,0 +1,100 @@ +/* + * media-session-params-p.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _MEDIA_SESSION_PARAMS_P_H_ +#define _MEDIA_SESSION_PARAMS_P_H_ + +#include "media-session-params.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class MediaSessionParamsPrivate : public CallSessionParamsPrivate { +public: + MediaSessionParamsPrivate () = default; + MediaSessionParamsPrivate (const MediaSessionParamsPrivate &src); + virtual ~MediaSessionParamsPrivate (); + + void enableImplicitRtcpFb (bool value) { _implicitRtcpFbEnabled = value; } + bool implicitRtcpFbEnabled () const { return _implicitRtcpFbEnabled; } + int getDownBandwidth () const { return downBandwidth; } + void setDownBandwidth (int value) { downBandwidth = value; } + int getUpBandwidth () const { return upBandwidth; } + void setUpBandwidth (int value) { upBandwidth = value; } + int getDownPtime () const { return downPtime; } + void setDownPtime (int value) { downPtime = value; } + int getUpPtime () const { return upPtime; } + void setUpPtime (int value) { upPtime = value; } + bool getUpdateCallWhenIceCompleted () const { return updateCallWhenIceCompleted; } + void setUpdateCallWhenIceCompleted (bool value) { updateCallWhenIceCompleted = value; } + + void setReceivedFps (float value) { receivedFps = value; } + void setReceivedVideoDefinition (LinphoneVideoDefinition *value); + void setSentFps (float value) { sentFps = value; } + void setSentVideoDefinition (LinphoneVideoDefinition *value); + void setUsedAudioCodec (OrtpPayloadType *pt) { usedAudioCodec = pt; } + void setUsedVideoCodec (OrtpPayloadType *pt) { usedVideoCodec = pt; } + void setUsedRealtimeTextCodec (OrtpPayloadType *pt) { usedRealtimeTextCodec = pt; } + +public: + bool audioEnabled = true; + int audioBandwidthLimit = 0; + LinphoneMediaDirection audioDirection = LinphoneMediaDirectionSendRecv; + bool audioMulticastEnabled = false; + PayloadType *usedAudioCodec = nullptr; + + bool videoEnabled = false; + LinphoneMediaDirection videoDirection = LinphoneMediaDirectionSendRecv; + bool videoMulticastEnabled = false; + PayloadType *usedVideoCodec = nullptr; + float receivedFps = 0.f; + LinphoneVideoDefinition *receivedVideoDefinition = nullptr; + float sentFps = 0.f; + LinphoneVideoDefinition *sentVideoDefinition = nullptr; + + bool realtimeTextEnabled = false; + PayloadType *usedRealtimeTextCodec = nullptr; + + bool avpfEnabled = false; + uint16_t avpfRrInterval = 0; /* In milliseconds */ + + bool lowBandwidthEnabled = false; + + std::string recordFilePath; + + bool earlyMediaSendingEnabled = false; /* Send real media even during early media (for outgoing calls) */ + + LinphoneMediaEncryption encryption = LinphoneMediaEncryptionNone; + bool mandatoryMediaEncryptionEnabled = false; + +private: + bool _implicitRtcpFbEnabled = false; + int downBandwidth = 0; + int upBandwidth = 0; + int downPtime = 0; + int upPtime = 0; + bool updateCallWhenIceCompleted = true; + +public: + L_DECLARE_PUBLIC(MediaSessionParams); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _MEDIA_SESSION_PARAMS_P_H_ diff --git a/src/conference/params/media-session-params.cpp b/src/conference/params/media-session-params.cpp index 028b04bfe..bb2bd441f 100644 --- a/src/conference/params/media-session-params.cpp +++ b/src/conference/params/media-session-params.cpp @@ -17,20 +17,310 @@ */ #include "call-session-params-p.h" +#include "media-session-params-p.h" #include "media-session-params.h" -#include "linphone/types.h" +#include "private.h" -using namespace LinphonePrivate; +using namespace std; + +LINPHONE_BEGIN_NAMESPACE // ============================================================================= -class Conference::MediaSessionParamsPrivate : public CallSessionParamsPrivate { -public: - LinphoneMediaEncryption encryption = LinphoneMediaEncryptionNone; -}; +MediaSessionParamsPrivate::MediaSessionParamsPrivate (const MediaSessionParamsPrivate &src) : CallSessionParamsPrivate(src) { + audioEnabled = src.audioEnabled; + audioBandwidthLimit = src.audioBandwidthLimit; + audioDirection = src.audioDirection; + audioMulticastEnabled = src.audioMulticastEnabled; + usedAudioCodec = src.usedAudioCodec; + videoEnabled = src.videoEnabled; + videoDirection = src.videoDirection; + videoMulticastEnabled = src.videoMulticastEnabled; + usedVideoCodec = src.usedVideoCodec; + receivedFps = src.receivedFps; + receivedVideoDefinition = src.receivedVideoDefinition ? linphone_video_definition_ref(src.receivedVideoDefinition) : nullptr; + sentFps = src.sentFps; + sentVideoDefinition = src.sentVideoDefinition ? linphone_video_definition_ref(src.sentVideoDefinition) : nullptr; + realtimeTextEnabled = src.realtimeTextEnabled; + usedRealtimeTextCodec = src.usedRealtimeTextCodec; + avpfEnabled = src.avpfEnabled; + avpfRrInterval = src.avpfRrInterval; + lowBandwidthEnabled = src.lowBandwidthEnabled; + recordFilePath = src.recordFilePath; + earlyMediaSendingEnabled = src.earlyMediaSendingEnabled; + encryption = src.encryption; + mandatoryMediaEncryptionEnabled = src.mandatoryMediaEncryptionEnabled; + _implicitRtcpFbEnabled = src._implicitRtcpFbEnabled; + downBandwidth = src.downBandwidth; + upBandwidth = src.upBandwidth; + downPtime = src.downPtime; + upPtime = src.upPtime; + updateCallWhenIceCompleted = src.updateCallWhenIceCompleted; +} + +MediaSessionParamsPrivate::~MediaSessionParamsPrivate () { + if (receivedVideoDefinition) + linphone_video_definition_unref(receivedVideoDefinition); + if (sentVideoDefinition) + linphone_video_definition_unref(sentVideoDefinition); +} + +// ----------------------------------------------------------------------------- + +void MediaSessionParamsPrivate::setReceivedVideoDefinition (LinphoneVideoDefinition *value) { + if (receivedVideoDefinition) + linphone_video_definition_unref(receivedVideoDefinition); + receivedVideoDefinition = linphone_video_definition_ref(value); +} + +void MediaSessionParamsPrivate::setSentVideoDefinition (LinphoneVideoDefinition *value) { + if (sentVideoDefinition) + linphone_video_definition_unref(sentVideoDefinition); + sentVideoDefinition = linphone_video_definition_ref(value); +} // ============================================================================= -Conference::MediaSessionParams::MediaSessionParams () : CallSessionParams(*new MediaSessionParamsPrivate) {} +MediaSessionParams::MediaSessionParams () : CallSessionParams(*new MediaSessionParamsPrivate) {} + +MediaSessionParams::MediaSessionParams (const MediaSessionParams &src) + : CallSessionParams(*new MediaSessionParamsPrivate(*src.getPrivate())) {} + +// ----------------------------------------------------------------------------- + +bool MediaSessionParams::audioEnabled () const { + L_D(const MediaSessionParams); + return d->audioEnabled; +} + +bool MediaSessionParams::audioMulticastEnabled () const { + L_D(const MediaSessionParams); + return d->audioMulticastEnabled; +} + +void MediaSessionParams::enableAudio (bool value) { + L_D(MediaSessionParams); + d->audioEnabled = value; + if (d->audioEnabled && (getAudioDirection() == LinphoneMediaDirectionInactive)) + setAudioDirection(LinphoneMediaDirectionSendRecv); +} + +void MediaSessionParams::enableAudioMulticast (bool value) { + L_D(MediaSessionParams); + d->audioMulticastEnabled = value; +} + +int MediaSessionParams::getAudioBandwidthLimit () const { + L_D(const MediaSessionParams); + return d->audioBandwidthLimit; +} + +LinphoneMediaDirection MediaSessionParams::getAudioDirection () const { + L_D(const MediaSessionParams); + return d->audioDirection; +} + +const OrtpPayloadType * MediaSessionParams::getUsedAudioCodec () const { + L_D(const MediaSessionParams); + return d->usedAudioCodec; +} + +LinphonePayloadType * MediaSessionParams::getUsedAudioPayloadType () const { + L_D(const MediaSessionParams); + return d->usedAudioCodec ? linphone_payload_type_new(nullptr, d->usedAudioCodec) : nullptr; +} + +void MediaSessionParams::setAudioBandwidthLimit (int value) { + L_D(MediaSessionParams); + d->audioBandwidthLimit = value; +} + +void MediaSessionParams::setAudioDirection (LinphoneMediaDirection direction) { + L_D(MediaSessionParams); + d->audioDirection = direction; +} + +// ----------------------------------------------------------------------------- + +void MediaSessionParams::enableVideo (bool value) { + L_D(MediaSessionParams); + d->videoEnabled = value; + if (d->videoEnabled && (getVideoDirection() == LinphoneMediaDirectionInactive)) + setVideoDirection(LinphoneMediaDirectionSendRecv); +} + +void MediaSessionParams::enableVideoMulticast (bool value) { + L_D(MediaSessionParams); + d->videoMulticastEnabled = value; +} + +float MediaSessionParams::getReceivedFps () const { + L_D(const MediaSessionParams); + return d->receivedFps; +} + +LinphoneVideoDefinition * MediaSessionParams::getReceivedVideoDefinition () const { + L_D(const MediaSessionParams); + return d->receivedVideoDefinition; +} + +float MediaSessionParams::getSentFps () const { + L_D(const MediaSessionParams); + return d->sentFps; +} + +LinphoneVideoDefinition * MediaSessionParams::getSentVideoDefinition () const { + L_D(const MediaSessionParams); + return d->sentVideoDefinition; +} + +const OrtpPayloadType * MediaSessionParams::getUsedVideoCodec () const { + L_D(const MediaSessionParams); + return d->usedVideoCodec; +} + +LinphonePayloadType * MediaSessionParams::getUsedVideoPayloadType () const { + L_D(const MediaSessionParams); + return d->usedVideoCodec ? linphone_payload_type_new(nullptr, d->usedVideoCodec) : nullptr; +} + +LinphoneMediaDirection MediaSessionParams::getVideoDirection () const { + L_D(const MediaSessionParams); + return d->videoDirection; +} + +void MediaSessionParams::setVideoDirection (LinphoneMediaDirection direction) { + L_D(MediaSessionParams); + d->videoDirection = direction; +} + +bool MediaSessionParams::videoEnabled () const { + L_D(const MediaSessionParams); + return d->videoEnabled; +} + +bool MediaSessionParams::videoMulticastEnabled () const { + L_D(const MediaSessionParams); + return d->videoMulticastEnabled; +} + +// ----------------------------------------------------------------------------- + +void MediaSessionParams::enableRealtimeText (bool value) { + L_D(MediaSessionParams); + d->realtimeTextEnabled = value; +} + +const OrtpPayloadType * MediaSessionParams::getUsedRealtimeTextCodec () const { + L_D(const MediaSessionParams); + return d->usedRealtimeTextCodec; +} + +LinphonePayloadType * MediaSessionParams::getUsedRealtimeTextPayloadType () const { + L_D(const MediaSessionParams); + return d->usedRealtimeTextCodec ? linphone_payload_type_new(nullptr, d->usedRealtimeTextCodec) : nullptr; +} + +bool MediaSessionParams::realtimeTextEnabled () const { + L_D(const MediaSessionParams); + return d->realtimeTextEnabled; +} + +// ----------------------------------------------------------------------------- + +bool MediaSessionParams::avpfEnabled () const { + L_D(const MediaSessionParams); + return d->avpfEnabled; +} + +void MediaSessionParams::enableAvpf (bool value) { + L_D(MediaSessionParams); + d->avpfEnabled = value; +} + +uint16_t MediaSessionParams::getAvpfRrInterval () const { + L_D(const MediaSessionParams); + return d->avpfRrInterval; +} + +void MediaSessionParams::setAvpfRrInterval (uint16_t value) { + L_D(MediaSessionParams); + d->avpfRrInterval = value; +} + +// ----------------------------------------------------------------------------- + +bool MediaSessionParams::lowBandwidthEnabled () const { + L_D(const MediaSessionParams); + return d->lowBandwidthEnabled; +} + +void MediaSessionParams::enableLowBandwidth (bool value) { + L_D(MediaSessionParams); + d->lowBandwidthEnabled = value; +} + +// ----------------------------------------------------------------------------- + +const string& MediaSessionParams::getRecordFilePath () const { + L_D(const MediaSessionParams); + return d->recordFilePath; +} + +void MediaSessionParams::setRecordFilePath (const string &path) { + L_D(MediaSessionParams); + d->recordFilePath = path; +} + +// ----------------------------------------------------------------------------- + +bool MediaSessionParams::earlyMediaSendingEnabled () const { + L_D(const MediaSessionParams); + return d->earlyMediaSendingEnabled; +} + +void MediaSessionParams::enableEarlyMediaSending (bool value) { + L_D(MediaSessionParams); + d->earlyMediaSendingEnabled = value; +} + +// ----------------------------------------------------------------------------- + +void MediaSessionParams::enableMandatoryMediaEncryption (bool value) { + L_D(MediaSessionParams); + d->mandatoryMediaEncryptionEnabled = value; +} + +LinphoneMediaEncryption MediaSessionParams::getMediaEncryption () const { + L_D(const MediaSessionParams); + return d->encryption; +} + +bool MediaSessionParams::mandatoryMediaEncryptionEnabled () const { + L_D(const MediaSessionParams); + return d->mandatoryMediaEncryptionEnabled; +} + +void MediaSessionParams::setMediaEncryption (LinphoneMediaEncryption encryption) { + L_D(MediaSessionParams); + d->encryption = encryption; +} + +// ----------------------------------------------------------------------------- + +SalMediaProto MediaSessionParams::getMediaProto () const { + if ((getMediaEncryption() == LinphoneMediaEncryptionSRTP) && avpfEnabled()) return SalProtoRtpSavpf; + if (getMediaEncryption() == LinphoneMediaEncryptionSRTP) return SalProtoRtpSavp; + if ((getMediaEncryption() == LinphoneMediaEncryptionDTLS) && avpfEnabled()) return SalProtoUdpTlsRtpSavpf; + if (getMediaEncryption() == LinphoneMediaEncryptionDTLS) return SalProtoUdpTlsRtpSavp; + if (avpfEnabled()) return SalProtoRtpAvpf; + return SalProtoRtpAvp; +} + +const char * MediaSessionParams::getRtpProfile () const { + return sal_media_proto_to_string(getMediaProto()); +} + +LINPHONE_END_NAMESPACE diff --git a/src/conference/params/media-session-params.h b/src/conference/params/media-session-params.h index 6b9ef351c..8916f9c03 100644 --- a/src/conference/params/media-session-params.h +++ b/src/conference/params/media-session-params.h @@ -16,26 +16,126 @@ * along with this program. If not, see . */ -#ifndef _CONFERENCE_MEDIA_SESSION_PARAMS_H_ -#define _CONFERENCE_MEDIA_SESSION_PARAMS_H_ +#ifndef _MEDIA_SESSION_PARAMS_H_ +#define _MEDIA_SESSION_PARAMS_H_ #include "call-session-params.h" -// ============================================================================= +#include -namespace LinphonePrivate { - namespace Conference { - class MediaSessionParamsPrivate; - - class MediaSessionParams : public CallSessionParams { - public: - MediaSessionParams (); - - private: - L_DECLARE_PRIVATE(MediaSessionParams); - L_DISABLE_COPY(MediaSessionParams); - }; - } +extern "C" { + bool_t linphone_call_params_implicit_rtcp_fb_enabled(const LinphoneCallParams *params); + void linphone_call_params_enable_implicit_rtcp_fb(LinphoneCallParams *params, bool_t value); + int linphone_call_params_get_down_bandwidth(const LinphoneCallParams *params); + void linphone_call_params_set_down_bandwidth(LinphoneCallParams *params, int value); + int linphone_call_params_get_up_bandwidth(const LinphoneCallParams *params); + void linphone_call_params_set_up_bandwidth(LinphoneCallParams *params, int value); + int linphone_call_params_get_down_ptime(const LinphoneCallParams *params); + void linphone_call_params_set_down_ptime(LinphoneCallParams *params, int value); + int linphone_call_params_get_up_ptime(const LinphoneCallParams *params); + void linphone_call_params_set_up_ptime(LinphoneCallParams *params, int value); + bool_t linphone_call_params_get_update_call_when_ice_completed(const LinphoneCallParams *params); + void linphone_call_params_set_update_call_when_ice_completed(LinphoneCallParams *params, bool_t value); + void linphone_call_params_set_received_fps(LinphoneCallParams *params, float value); + void linphone_call_params_set_received_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef); + void linphone_call_params_set_recv_vsize(LinphoneCallParams *params, MSVideoSize vsize); + void linphone_call_params_set_sent_fps(LinphoneCallParams *params, float value); + void linphone_call_params_set_sent_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef); + void linphone_call_params_set_sent_vsize(LinphoneCallParams *params, MSVideoSize vsize); + void linphone_call_params_set_used_audio_codec(LinphoneCallParams *params, OrtpPayloadType *codec); + void linphone_call_params_set_used_video_codec(LinphoneCallParams *params, OrtpPayloadType *codec); + void linphone_call_params_set_used_text_codec(LinphoneCallParams *params, OrtpPayloadType *codec); } -#endif // ifndef _CONFERENCE_MEDIA_SESSION_PARAMS_H_ +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class MediaSessionParamsPrivate; + +class MediaSessionParams : public CallSessionParams { + friend unsigned char ::linphone_call_params_implicit_rtcp_fb_enabled(const LinphoneCallParams *params); + friend void ::linphone_call_params_enable_implicit_rtcp_fb(LinphoneCallParams *params, unsigned char value); + friend int ::linphone_call_params_get_down_bandwidth(const LinphoneCallParams *params); + friend void ::linphone_call_params_set_down_bandwidth(LinphoneCallParams *params, int value); + friend int ::linphone_call_params_get_up_bandwidth(const LinphoneCallParams *params); + friend void ::linphone_call_params_set_up_bandwidth(LinphoneCallParams *params, int value); + friend int ::linphone_call_params_get_down_ptime(const LinphoneCallParams *params); + friend void ::linphone_call_params_set_down_ptime(LinphoneCallParams *params, int value); + friend int ::linphone_call_params_get_up_ptime(const LinphoneCallParams *params); + friend void ::linphone_call_params_set_up_ptime(LinphoneCallParams *params, int value); + friend unsigned char ::linphone_call_params_get_update_call_when_ice_completed(const LinphoneCallParams *params); + friend void ::linphone_call_params_set_update_call_when_ice_completed(LinphoneCallParams *params, unsigned char value); + friend void ::linphone_call_params_set_received_fps(LinphoneCallParams *params, float value); + friend void ::linphone_call_params_set_received_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef); + friend void ::linphone_call_params_set_recv_vsize(LinphoneCallParams *params, MSVideoSize vsize); + friend void ::linphone_call_params_set_sent_fps(LinphoneCallParams *params, float value); + friend void ::linphone_call_params_set_sent_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef); + friend void ::linphone_call_params_set_sent_vsize(LinphoneCallParams *params, MSVideoSize vsize); + friend void ::linphone_call_params_set_used_audio_codec(LinphoneCallParams *params, OrtpPayloadType *codec); + friend void ::linphone_call_params_set_used_video_codec(LinphoneCallParams *params, OrtpPayloadType *codec); + friend void ::linphone_call_params_set_used_text_codec(LinphoneCallParams *params, OrtpPayloadType *codec); + +public: + MediaSessionParams (); + MediaSessionParams (const MediaSessionParams &src); + virtual ~MediaSessionParams () = default; + + bool audioEnabled () const; + bool audioMulticastEnabled () const; + void enableAudio (bool value); + void enableAudioMulticast (bool value); + int getAudioBandwidthLimit () const; + LinphoneMediaDirection getAudioDirection () const; + const OrtpPayloadType * getUsedAudioCodec () const; + LinphonePayloadType * getUsedAudioPayloadType () const; + void setAudioBandwidthLimit (int value); + void setAudioDirection (LinphoneMediaDirection direction); + + void enableVideo (bool value); + void enableVideoMulticast (bool value); + float getReceivedFps () const; + LinphoneVideoDefinition * getReceivedVideoDefinition () const; + float getSentFps () const; + LinphoneVideoDefinition * getSentVideoDefinition () const; + const OrtpPayloadType * getUsedVideoCodec () const; + LinphonePayloadType * getUsedVideoPayloadType () const; + LinphoneMediaDirection getVideoDirection () const; + void setVideoDirection (LinphoneMediaDirection direction); + bool videoEnabled () const; + bool videoMulticastEnabled () const; + + void enableRealtimeText (bool value); + const OrtpPayloadType * getUsedRealtimeTextCodec () const; + LinphonePayloadType * getUsedRealtimeTextPayloadType () const; + bool realtimeTextEnabled () const; + + bool avpfEnabled () const; + void enableAvpf (bool value); + uint16_t getAvpfRrInterval () const; + void setAvpfRrInterval (uint16_t value); + + bool lowBandwidthEnabled () const; + void enableLowBandwidth (bool value); + + const std::string& getRecordFilePath () const; + void setRecordFilePath (const std::string &path); + + bool earlyMediaSendingEnabled () const; + void enableEarlyMediaSending (bool value); + + void enableMandatoryMediaEncryption (bool value); + LinphoneMediaEncryption getMediaEncryption () const; + bool mandatoryMediaEncryptionEnabled () const; + void setMediaEncryption (LinphoneMediaEncryption encryption); + + SalMediaProto getMediaProto () const; + const char * getRtpProfile () const; + +private: + L_DECLARE_PRIVATE(MediaSessionParams); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _MEDIA_SESSION_PARAMS_H_ diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index 9d610103a..ea4a6efee 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -3733,7 +3733,7 @@ static void call_with_in_dialog_update(void) { liblinphone_tester_check_rtcp(marie,pauline); params=linphone_core_create_call_params(marie->lc,linphone_core_get_current_call(marie->lc)); - params->no_user_consent=TRUE; + linphone_call_params_set_no_user_consent(params, TRUE); linphone_call_update(linphone_core_get_current_call(marie->lc),params); linphone_call_params_unref(params); BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,1)); diff --git a/tester/call_video_tester.c b/tester/call_video_tester.c index b0de949c6..e0285172f 100644 --- a/tester/call_video_tester.c +++ b/tester/call_video_tester.c @@ -1846,7 +1846,7 @@ static void incoming_reinvite_with_invalid_ack_sdp(void){ BC_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)))); caller_params = linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)); - BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,(int*)&caller_params->has_video,FALSE)); + // TODO [refactoring]: BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,(int*)&caller_params->has_video,FALSE)); sal_call_set_sdp_handling(inc_call->op, SalOpSDPNormal); } diff --git a/tester/tester.c b/tester/tester.c index 0ba670dc7..b5ea13ff8 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -710,7 +710,7 @@ static void check_ice_from_rtp(LinphoneCall *c1, LinphoneCall *c2, LinphoneStrea const LinphoneCallParams *cp1 = linphone_call_get_current_params(c1); const LinphoneCallParams *cp2 = linphone_call_get_current_params(c2); - if (cp1->update_call_when_ice_completed && cp2->update_call_when_ice_completed) { + if (linphone_call_params_get_update_call_when_ice_completed(cp1) && linphone_call_params_get_update_call_when_ice_completed(cp2)) { memset(&remaddr, 0, remaddrlen); result_desc = sal_call_get_final_media_description(c2->op); expected_addr = result_desc->streams[0].rtp_addr; From 7588a54016865d962018a12144789118482dc28d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 16 Aug 2017 10:41:28 +0200 Subject: [PATCH 0020/2215] Convert LinphoneCall to Call C++ class. --- coreapi/call_params.c | 95 +- coreapi/callbacks.c | 1078 +--- coreapi/chat.c | 6 +- coreapi/conference.cc | 31 +- coreapi/info.c | 4 +- coreapi/linphonecall.c | 5214 ++--------------- coreapi/linphonecore.c | 408 +- coreapi/misc.c | 910 +-- coreapi/nat_policy.c | 7 +- coreapi/offeranswer.c | 2 + coreapi/payload_type.c | 22 +- coreapi/player.c | 27 +- coreapi/private.h | 190 +- coreapi/proxy.c | 15 - coreapi/quality_reporting.c | 49 +- coreapi/upnp.c | 1412 ----- coreapi/upnp.h | 48 - daemon/commands/jitterbuffer.cc | 6 +- daemon/commands/msfilter-add-fmtp.cc | 5 +- include/linphone/call.h | 26 +- include/linphone/core.h | 2 + include/linphone/types.h | 3 + src/CMakeLists.txt | 16 +- src/c-wrapper/c-private-types.h | 46 + src/c-wrapper/c-tools.h | 9 + src/call/call-listener.h | 52 + src/call/call-p.h | 90 + src/call/call.cpp | 462 +- src/call/call.h | 94 +- src/chat/chat-room.cpp | 14 +- src/conference/conference-listener.h | 2 +- src/conference/conference-p.h | 34 +- src/conference/conference.cpp | 90 +- src/conference/conference.h | 19 +- src/conference/local-conference.cpp | 3 +- src/conference/local-conference.h | 2 +- src/conference/params/call-session-params-p.h | 6 - src/conference/params/call-session-params.cpp | 89 +- src/conference/params/call-session-params.h | 45 +- .../params/media-session-params-p.h | 26 +- .../params/media-session-params.cpp | 174 + src/conference/params/media-session-params.h | 59 +- src/conference/participant-p.h | 53 + src/conference/participant.cpp | 21 +- src/conference/participant.h | 6 + src/conference/remote-conference.cpp | 3 +- src/conference/remote-conference.h | 2 +- .../session/call-session-listener.h | 48 + src/conference/session/call-session-p.h | 78 +- src/conference/session/call-session.cpp | 1075 +++- src/conference/session/call-session.h | 41 +- src/conference/session/media-session-p.h | 300 + src/conference/session/media-session.cpp | 4645 ++++++++++++++- src/conference/session/media-session.h | 63 +- src/conference/session/port-config.h | 37 + src/nat/ice-agent.cpp | 689 +++ src/nat/ice-agent.h | 76 + src/nat/stun-client.cpp | 253 + src/nat/stun-client.h | 63 + src/utils/payload-type-handler.cpp | 304 + src/utils/payload-type-handler.h | 84 + tester/CMakeLists.txt | 2 - tester/Makefile.am | 2 - tester/call_single_tester.c | 79 +- tester/call_video_tester.c | 32 +- tester/complex_sip_case_tester.c | 10 +- tester/dtmf_tester.c | 4 +- tester/flexisip_tester.c | 3 +- tester/offeranswer_tester.c | 2 + tester/quality_reporting_tester.c | 18 +- tester/rcfiles/upnp_rc | 2 - tester/stun_tester.c | 56 +- tester/tester.c | 21 +- tester/upnp_tester.c | 63 - tester/video_tester.c | 4 + 75 files changed, 9911 insertions(+), 9120 deletions(-) delete mode 100644 coreapi/upnp.c delete mode 100644 coreapi/upnp.h create mode 100644 src/c-wrapper/c-private-types.h create mode 100644 src/call/call-listener.h create mode 100644 src/call/call-p.h create mode 100644 src/conference/participant-p.h create mode 100644 src/conference/session/call-session-listener.h create mode 100644 src/conference/session/media-session-p.h create mode 100644 src/conference/session/port-config.h create mode 100644 src/nat/ice-agent.cpp create mode 100644 src/nat/ice-agent.h create mode 100644 src/nat/stun-client.cpp create mode 100644 src/nat/stun-client.h create mode 100644 src/utils/payload-type-handler.cpp create mode 100644 src/utils/payload-type-handler.h delete mode 100644 tester/rcfiles/upnp_rc delete mode 100644 tester/upnp_tester.c diff --git a/coreapi/call_params.c b/coreapi/call_params.c index a6f95b940..504cca79a 100644 --- a/coreapi/call_params.c +++ b/coreapi/call_params.c @@ -20,17 +20,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/call_params.h" #include "private.h" +#include "c-wrapper/c-private-types.h" +#include "c-wrapper/c-tools.h" #include "conference/params/media-session-params.h" #include "conference/params/call-session-params-p.h" #include "conference/params/media-session-params-p.h" -struct _LinphoneCallParams{ - belle_sip_object_t base; - void *user_data; - LinphonePrivate::MediaSessionParams *msp; -}; - BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneCallParams); @@ -82,15 +78,15 @@ SalStreamDir get_video_dir_from_call_params(const LinphoneCallParams *params) { } void linphone_call_params_set_custom_headers(LinphoneCallParams *params, const SalCustomHeader *ch) { - static_cast(params->msp)->getPrivate()->setCustomHeaders(ch); + L_GET_PRIVATE(static_cast(params->msp.get()))->setCustomHeaders(ch); } void linphone_call_params_set_custom_sdp_attributes(LinphoneCallParams *params, const SalCustomSdpAttribute *csa) { - static_cast(params->msp)->getPrivate()->setCustomSdpAttributes(csa); + L_GET_PRIVATE(params->msp.get())->setCustomSdpAttributes(csa); } void linphone_call_params_set_custom_sdp_media_attributes(LinphoneCallParams *params, LinphoneStreamType type, const SalCustomSdpAttribute *csa) { - static_cast(params->msp)->getPrivate()->setCustomSdpMediaAttributes(type, csa); + L_GET_PRIVATE(params->msp.get())->setCustomSdpMediaAttributes(type, csa); } @@ -247,7 +243,7 @@ const OrtpPayloadType *linphone_call_params_get_used_audio_codec(const LinphoneC } void linphone_call_params_set_used_audio_codec(LinphoneCallParams *params, OrtpPayloadType *codec) { - params->msp->getPrivate()->setUsedAudioCodec(codec); + L_GET_PRIVATE(params->msp.get())->setUsedAudioCodec(codec); } const OrtpPayloadType *linphone_call_params_get_used_video_codec(const LinphoneCallParams *params) { @@ -255,7 +251,7 @@ const OrtpPayloadType *linphone_call_params_get_used_video_codec(const LinphoneC } void linphone_call_params_set_used_video_codec(LinphoneCallParams *params, OrtpPayloadType *codec) { - params->msp->getPrivate()->setUsedVideoCodec(codec); + L_GET_PRIVATE(params->msp.get())->setUsedVideoCodec(codec); } const OrtpPayloadType *linphone_call_params_get_used_text_codec(const LinphoneCallParams *params) { @@ -263,7 +259,7 @@ const OrtpPayloadType *linphone_call_params_get_used_text_codec(const LinphoneCa } void linphone_call_params_set_used_text_codec(LinphoneCallParams *params, OrtpPayloadType *codec) { - params->msp->getPrivate()->setUsedRealtimeTextCodec(codec); + L_GET_PRIVATE(params->msp.get())->setUsedRealtimeTextCodec(codec); } bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *params) { @@ -366,11 +362,11 @@ void linphone_call_params_set_avpf_rr_interval(LinphoneCallParams *params, uint1 } void linphone_call_params_set_sent_fps(LinphoneCallParams *params, float value) { - params->msp->getPrivate()->setSentFps(value); + L_GET_PRIVATE(params->msp.get())->setSentFps(value); } void linphone_call_params_set_received_fps(LinphoneCallParams *params, float value) { - params->msp->getPrivate()->setReceivedFps(value); + L_GET_PRIVATE(params->msp.get())->setReceivedFps(value); } @@ -379,111 +375,115 @@ void linphone_call_params_set_received_fps(LinphoneCallParams *params, float val ******************************************************************************/ bool_t linphone_call_params_get_in_conference(const LinphoneCallParams *params) { - return static_cast(params->msp)->getPrivate()->getInConference(); + return L_GET_PRIVATE(static_cast(params->msp.get()))->getInConference(); } void linphone_call_params_set_in_conference(LinphoneCallParams *params, bool_t value) { - static_cast(params->msp)->getPrivate()->setInConference(value); + L_GET_PRIVATE(static_cast(params->msp.get()))->setInConference(value); } bool_t linphone_call_params_get_internal_call_update(const LinphoneCallParams *params) { - return static_cast(params->msp)->getPrivate()->getInternalCallUpdate(); + return L_GET_PRIVATE(static_cast(params->msp.get()))->getInternalCallUpdate(); } void linphone_call_params_set_internal_call_update(LinphoneCallParams *params, bool_t value) { - static_cast(params->msp)->getPrivate()->setInternalCallUpdate(value); + L_GET_PRIVATE(static_cast(params->msp.get()))->setInternalCallUpdate(value); } bool_t linphone_call_params_implicit_rtcp_fb_enabled(const LinphoneCallParams *params) { - return params->msp->getPrivate()->implicitRtcpFbEnabled(); + return L_GET_PRIVATE(params->msp.get())->implicitRtcpFbEnabled(); } void linphone_call_params_enable_implicit_rtcp_fb(LinphoneCallParams *params, bool_t value) { - params->msp->getPrivate()->enableImplicitRtcpFb(value); + L_GET_PRIVATE(params->msp.get())->enableImplicitRtcpFb(value); } int linphone_call_params_get_down_bandwidth(const LinphoneCallParams *params) { - return params->msp->getPrivate()->getDownBandwidth(); + return L_GET_PRIVATE(params->msp.get())->getDownBandwidth(); } void linphone_call_params_set_down_bandwidth(LinphoneCallParams *params, int value) { - params->msp->getPrivate()->setDownBandwidth(value); + L_GET_PRIVATE(params->msp.get())->setDownBandwidth(value); } int linphone_call_params_get_up_bandwidth(const LinphoneCallParams *params) { - return params->msp->getPrivate()->getUpBandwidth(); + return L_GET_PRIVATE(params->msp.get())->getUpBandwidth(); } void linphone_call_params_set_up_bandwidth(LinphoneCallParams *params, int value) { - params->msp->getPrivate()->setUpBandwidth(value); + L_GET_PRIVATE(params->msp.get())->setUpBandwidth(value); } int linphone_call_params_get_down_ptime(const LinphoneCallParams *params) { - return params->msp->getPrivate()->getDownPtime(); + return L_GET_PRIVATE(params->msp.get())->getDownPtime(); } void linphone_call_params_set_down_ptime(LinphoneCallParams *params, int value) { - params->msp->getPrivate()->setDownPtime(value); + L_GET_PRIVATE(params->msp.get())->setDownPtime(value); } int linphone_call_params_get_up_ptime(const LinphoneCallParams *params) { - return params->msp->getPrivate()->getUpPtime(); + return L_GET_PRIVATE(params->msp.get())->getUpPtime(); } void linphone_call_params_set_up_ptime(LinphoneCallParams *params, int value) { - params->msp->getPrivate()->setUpPtime(value); + L_GET_PRIVATE(params->msp.get())->setUpPtime(value); } SalCustomHeader * linphone_call_params_get_custom_headers(const LinphoneCallParams *params) { - return static_cast(params->msp)->getPrivate()->getCustomHeaders(); + return L_GET_PRIVATE(static_cast(params->msp.get()))->getCustomHeaders(); } SalCustomSdpAttribute * linphone_call_params_get_custom_sdp_attributes(const LinphoneCallParams *params) { - return static_cast(params->msp)->getPrivate()->getCustomSdpAttributes(); + return L_GET_PRIVATE(params->msp.get())->getCustomSdpAttributes(); } SalCustomSdpAttribute * linphone_call_params_get_custom_sdp_media_attributes(const LinphoneCallParams *params, LinphoneStreamType type) { - return static_cast(params->msp)->getPrivate()->getCustomSdpMediaAttributes(type); + return L_GET_PRIVATE(params->msp.get())->getCustomSdpMediaAttributes(type); } LinphoneCall * linphone_call_params_get_referer(const LinphoneCallParams *params) { - return static_cast(params->msp)->getPrivate()->getReferer(); + return L_GET_PRIVATE(static_cast(params->msp.get()))->getReferer(); } void linphone_call_params_set_referer(LinphoneCallParams *params, LinphoneCall *referer) { - static_cast(params->msp)->getPrivate()->setReferer(referer); + L_GET_PRIVATE(static_cast(params->msp.get()))->setReferer(referer); } bool_t linphone_call_params_get_update_call_when_ice_completed(const LinphoneCallParams *params) { - return params->msp->getPrivate()->getUpdateCallWhenIceCompleted(); + return L_GET_PRIVATE(params->msp.get())->getUpdateCallWhenIceCompleted(); } void linphone_call_params_set_update_call_when_ice_completed(LinphoneCallParams *params, bool_t value) { - params->msp->getPrivate()->setUpdateCallWhenIceCompleted(value); + L_GET_PRIVATE(params->msp.get())->setUpdateCallWhenIceCompleted(value); } void linphone_call_params_set_sent_vsize(LinphoneCallParams *params, MSVideoSize vsize) { - params->msp->getPrivate()->setSentVideoDefinition(linphone_video_definition_new(vsize.width, vsize.height, nullptr)); + L_GET_PRIVATE(params->msp.get())->setSentVideoDefinition(linphone_video_definition_new(vsize.width, vsize.height, nullptr)); } void linphone_call_params_set_recv_vsize(LinphoneCallParams *params, MSVideoSize vsize) { - params->msp->getPrivate()->setReceivedVideoDefinition(linphone_video_definition_new(vsize.width, vsize.height, nullptr)); + L_GET_PRIVATE(params->msp.get())->setReceivedVideoDefinition(linphone_video_definition_new(vsize.width, vsize.height, nullptr)); } void linphone_call_params_set_sent_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef) { - params->msp->getPrivate()->setSentVideoDefinition(vdef); + L_GET_PRIVATE(params->msp.get())->setSentVideoDefinition(vdef); } void linphone_call_params_set_received_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef) { - params->msp->getPrivate()->setReceivedVideoDefinition(vdef); + L_GET_PRIVATE(params->msp.get())->setReceivedVideoDefinition(vdef); } bool_t linphone_call_params_get_no_user_consent(const LinphoneCallParams *params) { - return static_cast(params->msp)->getPrivate()->getNoUserConsent(); + return L_GET_PRIVATE(static_cast(params->msp.get()))->getNoUserConsent(); } void linphone_call_params_set_no_user_consent(LinphoneCallParams *params, bool_t value) { - static_cast(params->msp)->getPrivate()->setNoUserConsent(value); + L_GET_PRIVATE(static_cast(params->msp.get()))->setNoUserConsent(value); +} + +std::shared_ptr linphone_call_params_get_cpp_obj(const LinphoneCallParams *params) { + return params->msp; } @@ -514,19 +514,24 @@ void linphone_call_params_unref(LinphoneCallParams *cp) { ******************************************************************************/ static void _linphone_call_params_destroy(LinphoneCallParams *params) { - delete params->msp; + params->msp = nullptr; } static void _linphone_call_params_clone(LinphoneCallParams *dst, const LinphoneCallParams *src) { - dst->msp = new LinphonePrivate::MediaSessionParams(*src->msp); + dst->msp = std::make_shared(*src->msp); } -LinphoneCallParams * linphone_call_params_new(void) { +LinphoneCallParams * linphone_call_params_new(LinphoneCore *core) { LinphoneCallParams *params = belle_sip_object_new(LinphoneCallParams); - params->msp = new LinphonePrivate::MediaSessionParams(); + params->msp = std::make_shared(); + params->msp->initDefault(core); return params; } +LinphoneCallParams * linphone_call_params_new_for_wrapper(void) { + return belle_sip_object_new(LinphoneCallParams); +} + /* DEPRECATED */ void linphone_call_params_destroy(LinphoneCallParams *cp) { linphone_call_params_unref(cp); diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index a96860fec..9bb75ccc8 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -33,201 +33,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #endif +#include "c-wrapper/c-tools.h" +#include "call/call-p.h" +#include "conference/session/call-session.h" +#include "conference/session/call-session-p.h" +#include "conference/session/media-session.h" +#include "conference/session/media-session-p.h" + static void register_failure(SalOp *op); -static int media_parameters_changed(LinphoneCall *call, SalMediaDescription *oldmd, SalMediaDescription *newmd) { - int result=0; - int otherdesc_changed; - char *tmp1=NULL; - char *tmp2=NULL; - if (linphone_call_params_get_in_conference(call->params) != linphone_call_params_get_in_conference(call->current_params)) - return SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION; - if (call->up_bw != linphone_core_get_upload_bandwidth(call->core)) return SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION; - if (call->localdesc_changed) ms_message("Local description has changed: %s", tmp1 = sal_media_description_print_differences(call->localdesc_changed)); - otherdesc_changed = sal_media_description_equals(oldmd, newmd); - if (otherdesc_changed) ms_message("Other description has changed: %s", tmp2 = sal_media_description_print_differences(otherdesc_changed)); - result = call->localdesc_changed | otherdesc_changed; - if (tmp1) ms_free(tmp1); - if (tmp2) ms_free(tmp2); - return result; -} - -void linphone_core_update_streams_destinations(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) { - SalStreamDescription *new_audiodesc = NULL; - SalStreamDescription *new_videodesc = NULL; - char *rtp_addr, *rtcp_addr; - int i; - - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { - if (!sal_stream_description_active(&new_md->streams[i])) continue; - if (new_md->streams[i].type == SalAudio) { - new_audiodesc = &new_md->streams[i]; - } else if (new_md->streams[i].type == SalVideo) { - new_videodesc = &new_md->streams[i]; - } - } - if (call->audiostream && new_audiodesc) { - rtp_addr = (new_audiodesc->rtp_addr[0] != '\0') ? new_audiodesc->rtp_addr : new_md->addr; - rtcp_addr = (new_audiodesc->rtcp_addr[0] != '\0') ? new_audiodesc->rtcp_addr : new_md->addr; - ms_message("Change audio stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port); - rtp_session_set_remote_addr_full(call->audiostream->ms.sessions.rtp_session, rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port); - } -#ifdef VIDEO_ENABLED - if (call->videostream && new_videodesc) { - rtp_addr = (new_videodesc->rtp_addr[0] != '\0') ? new_videodesc->rtp_addr : new_md->addr; - rtcp_addr = (new_videodesc->rtcp_addr[0] != '\0') ? new_videodesc->rtcp_addr : new_md->addr; - ms_message("Change video stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port); - rtp_session_set_remote_addr_full(call->videostream->ms.sessions.rtp_session, rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port); - } -#else - (void)new_videodesc; -#endif -} - -static void _clear_early_media_destinations(LinphoneCall *call, MediaStream *ms){ - RtpSession *session=ms->sessions.rtp_session; - rtp_session_clear_aux_remote_addr(session); - if (!call->ice_session) rtp_session_set_symmetric_rtp(session,linphone_core_symmetric_rtp_enabled(call->core));/*restore symmetric rtp if ICE is not used*/ -} - -static void clear_early_media_destinations(LinphoneCall *call){ - if (call->audiostream){ - _clear_early_media_destinations(call,(MediaStream*)call->audiostream); - } - if (call->videostream){ - _clear_early_media_destinations(call,(MediaStream*)call->videostream); - } -} - -static void prepare_early_media_forking(LinphoneCall *call){ - /*we need to disable symmetric rtp otherwise our outgoing streams will be switching permanently between the multiple destinations*/ - if (call->audiostream){ - rtp_session_set_symmetric_rtp(call->audiostream->ms.sessions.rtp_session,FALSE); - } - if (call->videostream){ - rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,FALSE); - } -} - -void linphone_call_update_frozen_payloads(LinphoneCall *call, SalMediaDescription *result_desc){ - SalMediaDescription *local=call->localdesc; - int i; - for(i=0;inb_streams;++i){ - bctbx_list_t *elem; - for (elem=result_desc->streams[i].payloads;elem!=NULL;elem=elem->next){ - PayloadType *pt=(PayloadType*)elem->data; - if (is_payload_type_number_available(local->streams[i].already_assigned_payloads, payload_type_get_number(pt), NULL)){ - /*new codec, needs to be added to the list*/ - local->streams[i].already_assigned_payloads=bctbx_list_append(local->streams[i].already_assigned_payloads, payload_type_clone(pt)); - ms_message("LinphoneCall[%p] : payload type %i %s/%i fmtp=%s added to frozen list.", - call, payload_type_get_number(pt), pt->mime_type, pt->clock_rate, pt->recv_fmtp ? pt->recv_fmtp : ""); - } - } - } -} - -void linphone_call_update_streams(LinphoneCall *call, SalMediaDescription *new_md, LinphoneCallState target_state) { - LinphoneCore *lc = linphone_call_get_core(call); - SalMediaDescription *oldmd = call->resultdesc; - int md_changed = 0; - - if (!((call->state == LinphoneCallIncomingEarlyMedia) && (linphone_core_get_ring_during_incoming_early_media(lc)))) { - linphone_core_stop_ringing(lc); - } - if (!new_md) { - ms_error("linphone_call_update_streams() called with null media description"); - return; - } - linphone_call_update_biggest_desc(call, call->localdesc); - sal_media_description_ref(new_md); - call->resultdesc = new_md; - if ((call->audiostream && (call->audiostream->ms.state == MSStreamStarted)) || (call->videostream && (call->videostream->ms.state == MSStreamStarted))) { - clear_early_media_destinations(call); - - /* We already started media: check if we really need to restart it */ - if (oldmd) { - md_changed = media_parameters_changed(call, oldmd, new_md); - /*might not be mandatory to restart stream for each ice restart as it leads bad user experience, specially in video. See 0002495 for better background on this*/ - if ((md_changed & ( SAL_MEDIA_DESCRIPTION_CODEC_CHANGED - |SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED - |SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED - |SAL_MEDIA_DESCRIPTION_ICE_RESTART_DETECTED - |SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION ))) { - ms_message("Media descriptions are different, need to restart the streams."); - } else if (call->playing_ringbacktone) { - ms_message("Playing ringback tone, will restart the streams."); - } else { - if (call->all_muted && target_state == LinphoneCallStreamsRunning) { - ms_message("Early media finished, unmuting inputs..."); - /* We were in early media, now we want to enable real media */ - call->all_muted = FALSE; - if (call->audiostream) linphone_core_enable_mic(lc, linphone_core_mic_enabled(lc)); -#ifdef VIDEO_ENABLED - if (call->videostream && call->camera_enabled) { - linphone_call_enable_camera(call, linphone_call_camera_enabled(call)); - } -#endif - } - if (md_changed == SAL_MEDIA_DESCRIPTION_UNCHANGED) { - /*FIXME ZRTP, might be restarted in any cases ? */ - ms_message("No need to restart streams, SDP is unchanged."); - goto end; - } else { - if (md_changed & SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED) { - ms_message("Network parameters have changed, update them."); - linphone_core_update_streams_destinations(call, oldmd, new_md); - } - if (md_changed & SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED) { - ms_message("Crypto parameters have changed, update them."); - linphone_call_update_crypto_parameters(call, oldmd, new_md); - } - goto end; - } - } - } - linphone_call_stop_media_streams(call); - if (md_changed & SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED) { - ms_message("Media ip type has changed, destroying sessions context on call [%p]", call); - ms_media_stream_sessions_uninit(&call->sessions[call->main_audio_stream_index]); - ms_media_stream_sessions_uninit(&call->sessions[call->main_video_stream_index]); - ms_media_stream_sessions_uninit(&call->sessions[call->main_text_stream_index]); - } - linphone_call_init_media_streams(call); - } - - if (call->audiostream == NULL) { - /* This happens after pausing the call locally. The streams are destroyed and then we wait the 200Ok to recreate them */ - linphone_call_init_media_streams(call); - } - - if (linphone_call_params_real_early_media_enabled(call->params) && (call->state == LinphoneCallOutgoingEarlyMedia)) { - prepare_early_media_forking(call); - } - linphone_call_start_media_streams(call, target_state); - if ((call->state == LinphoneCallPausing) && call->paused_by_app && (bctbx_list_size(lc->calls) == 1)) { - linphone_core_play_named_tone(lc, LinphoneToneCallOnHold); - } - linphone_call_update_frozen_payloads(call, new_md); - -end: - if (oldmd) sal_media_description_unref(oldmd); - -} - -#if 0 -static bool_t is_duplicate_call(LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to){ - bctbx_list_t *elem; - for(elem=lc->calls;elem!=NULL;elem=elem->next){ - LinphoneCall *call=(LinphoneCall*)elem->data; - if (linphone_address_weak_equal(call->log->from,from) && - linphone_address_weak_equal(call->log->to, to)){ - return TRUE; - } - } - return FALSE; -} -#endif - static bool_t already_a_call_with_remote_address(const LinphoneCore *lc, const LinphoneAddress *remote) { bctbx_list_t *elem; ms_message("Searching for already_a_call_with_remote_address."); @@ -249,155 +63,115 @@ static LinphoneCall * look_for_broken_call_to_replace(SalOp *h, LinphoneCore *lc const bctbx_list_t *it = calls; while (it != NULL) { LinphoneCall *replaced_call = NULL; +#if 0 LinphoneCall *call = (LinphoneCall *)bctbx_list_get_data(it); +#endif SalOp *replaced_op = sal_call_get_replaces(h); if (replaced_op) replaced_call = (LinphoneCall*)sal_op_get_user_pointer(replaced_op); +#if 0 if ((call->broken && sal_call_compare_op(h, call->op)) || ((replaced_call == call) && (strcmp(sal_op_get_from(h), sal_op_get_from(replaced_op)) == 0) && (strcmp(sal_op_get_to(h), sal_op_get_to(replaced_op)) == 0))) { return call; } +#endif it = bctbx_list_next(it); } return NULL; } -static void call_received(SalOp *h){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); - LinphoneCall *call; - LinphoneCall *replaced_call; - char *alt_contact; - LinphoneAddress *from_addr=NULL; - LinphoneAddress *to_addr=NULL; - LinphoneAddress *from_address_to_search_if_me=NULL; /*address used to know if I'm the caller*/ - SalMediaDescription *md; - const char * p_asserted_id; - LinphoneErrorInfo *ei = NULL; - LinphonePresenceActivity *activity = NULL; - +static void call_received(SalOp *h) { /* Look if this INVITE is for a call that has already been notified but broken because of network failure */ - replaced_call = look_for_broken_call_to_replace(h, lc); - if (replaced_call != NULL) { - linphone_call_replace_op(replaced_call, h); + LinphoneCore *lc = reinterpret_cast(sal_get_user_pointer(sal_op_get_sal(h))); + LinphoneCall *replacedCall = look_for_broken_call_to_replace(h, lc); + if (replacedCall) { + linphone_call_replace_op(replacedCall, h); return; } - p_asserted_id = sal_custom_header_find(sal_op_get_recv_custom_header(h),"P-Asserted-Identity"); - /*in some situation, better to trust the network rather than the UAC*/ - if (lp_config_get_int(lc->config,"sip","call_logs_use_asserted_id_instead_of_from",0)) { - LinphoneAddress *p_asserted_id_addr; - if (!p_asserted_id) { - ms_warning("No P-Asserted-Identity header found so cannot use it for op [%p] instead of from",h); - } else { - p_asserted_id_addr = linphone_address_new(p_asserted_id); - if (!p_asserted_id_addr) { - ms_warning("Unsupported P-Asserted-Identity header for op [%p] ",h); - } else { - ms_message("Using P-Asserted-Identity [%s] instead of from [%s] for op [%p]",p_asserted_id,sal_op_get_from(h),h); - from_addr=p_asserted_id_addr; - } - } + LinphoneAddress *fromAddr = nullptr; + const char *pAssertedId = sal_custom_header_find(sal_op_get_recv_custom_header(h), "P-Asserted-Identity"); + /* In some situation, better to trust the network rather than the UAC */ + if (lp_config_get_int(linphone_core_get_config(lc), "sip", "call_logs_use_asserted_id_instead_of_from", 0)) { + if (pAssertedId) { + LinphoneAddress *pAssertedIdAddr = linphone_address_new(pAssertedId); + if (pAssertedIdAddr) { + ms_message("Using P-Asserted-Identity [%s] instead of from [%s] for op [%p]", pAssertedId, sal_op_get_from(h), h); + fromAddr = pAssertedIdAddr; + } else + ms_warning("Unsupported P-Asserted-Identity header for op [%p] ", h); + } else + ms_warning("No P-Asserted-Identity header found so cannot use it for op [%p] instead of from", h); } - if (!from_addr) - from_addr=linphone_address_new(sal_op_get_from(h)); - to_addr=linphone_address_new(sal_op_get_to(h)); + if (!fromAddr) + fromAddr = linphone_address_new(sal_op_get_from(h)); + LinphoneAddress *toAddr = linphone_address_new(sal_op_get_to(h)); - /* first check if we can answer successfully to this invite */ - if (linphone_presence_model_get_basic_status(lc->presence_model) == LinphonePresenceBasicStatusClosed + /* First check if we can answer successfully to this invite */ + LinphonePresenceActivity *activity = nullptr; + if ((linphone_presence_model_get_basic_status(lc->presence_model) == LinphonePresenceBasicStatusClosed) && (activity = linphone_presence_model_get_activity(lc->presence_model))) { + char *altContact = nullptr; switch (linphone_presence_activity_get_type(activity)) { case LinphonePresenceActivityPermanentAbsence: - alt_contact = linphone_presence_model_get_contact(lc->presence_model); - if (alt_contact != NULL) { + altContact = linphone_presence_model_get_contact(lc->presence_model); + if (altContact) { SalErrorInfo sei; memset(&sei, 0, sizeof(sei)); - sal_error_info_set(&sei,SalReasonRedirect, "SIP", 0, NULL, NULL); - sal_call_decline_with_error_info(h, &sei,alt_contact); - ms_free(alt_contact); - ei = linphone_error_info_new(); - linphone_error_info_set(ei, NULL, LinphoneReasonMovedPermanently, 302, "Moved permanently", NULL); - linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, from_addr, to_addr, ei); + sal_error_info_set(&sei, SalReasonRedirect, "SIP", 0, nullptr, nullptr); + sal_call_decline_with_error_info(h, &sei, altContact); + ms_free(altContact); + LinphoneErrorInfo *ei = linphone_error_info_new(); + linphone_error_info_set(ei, nullptr, LinphoneReasonMovedPermanently, 302, "Moved permanently", nullptr); + linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, fromAddr, toAddr, ei); sal_op_release(h); sal_error_info_reset(&sei); return; } break; default: - /*nothing special to be done*/ + /* Nothing special to be done */ break; } } - if (!linphone_core_can_we_add_call(lc)){/*busy*/ - sal_call_decline(h,SalReasonBusy,NULL); - ei = linphone_error_info_new(); - linphone_error_info_set(ei, NULL, LinphoneReasonBusy, 486, "Busy - too many calls", NULL); - linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, from_addr, to_addr, ei); + if (!linphone_core_can_we_add_call(lc)) { /* Busy */ + sal_call_decline(h, SalReasonBusy, nullptr); + LinphoneErrorInfo *ei = linphone_error_info_new(); + linphone_error_info_set(ei, nullptr, LinphoneReasonBusy, 486, "Busy - too many calls", nullptr); + linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, fromAddr, toAddr, ei); sal_op_release(h); return; } - - if (sal_op_get_privacy(h) == SalPrivacyNone) { - from_address_to_search_if_me=linphone_address_clone(from_addr); - } else if (p_asserted_id) { - from_address_to_search_if_me = linphone_address_new(p_asserted_id); - } else { - ms_warning ("Hidden from identity, don't know if it's me"); - } - - if (from_address_to_search_if_me && already_a_call_with_remote_address(lc,from_address_to_search_if_me)){ - char *addr = linphone_address_as_string(from_addr); - ms_warning("Receiving a call while one with same address [%s] is initiated, refusing this one with busy message.",addr); - sal_call_decline(h,SalReasonBusy,NULL); - ei = linphone_error_info_new(); - linphone_error_info_set(ei, NULL, LinphoneReasonBusy, 486, "Busy - duplicated call", NULL); - linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, from_addr, to_addr, ei); + /* Check if I'm the caller */ + LinphoneAddress *fromAddressToSearchIfMe = nullptr; + if (sal_op_get_privacy(h) == SalPrivacyNone) + fromAddressToSearchIfMe = linphone_address_clone(fromAddr); + else if (pAssertedId) + fromAddressToSearchIfMe = linphone_address_new(pAssertedId); + else + ms_warning("Hidden from identity, don't know if it's me"); + if (fromAddressToSearchIfMe && already_a_call_with_remote_address(lc, fromAddressToSearchIfMe)) { + char *addr = linphone_address_as_string(fromAddr); + ms_warning("Receiving a call while one with same address [%s] is initiated, refusing this one with busy message", addr); + sal_call_decline(h, SalReasonBusy, nullptr); + LinphoneErrorInfo *ei = linphone_error_info_new(); + linphone_error_info_set(ei, nullptr, LinphoneReasonBusy, 486, "Busy - duplicated call", nullptr); + linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, fromAddr, toAddr, ei); sal_op_release(h); - linphone_address_unref(from_address_to_search_if_me); + linphone_address_unref(fromAddressToSearchIfMe); ms_free(addr); return; - } else if (from_address_to_search_if_me) { - linphone_address_unref(from_address_to_search_if_me); } + if (fromAddressToSearchIfMe) + linphone_address_unref(fromAddressToSearchIfMe); - call=linphone_call_new_incoming(lc,from_addr,to_addr,h); - - linphone_call_make_local_media_description(call); - sal_call_set_local_media_description(call->op,call->localdesc); - md=sal_call_get_final_media_description(call->op); - if (md){ - if (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md)){ - ei = linphone_error_info_new(); - linphone_error_info_set(ei, NULL, LinphoneReasonNotAcceptable, 488, "Not acceptable here", NULL); - linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, linphone_address_ref(from_addr), linphone_address_ref(to_addr), ei); - sal_call_decline(call->op,SalReasonNotAcceptable,NULL); - linphone_call_unref(call); - return; - } - } - - /* the call is acceptable so we can now add it to our list */ - linphone_core_add_call(lc,call); - linphone_call_ref(call); /*prevent the call from being destroyed while we are notifying, if the user declines within the state callback */ - - call->bg_task_id=sal_begin_background_task("liblinphone call notification", NULL, NULL); - - if (call->defer_notify_incoming) { - /* Defer ringing until the end of the ICE candidates gathering process. */ - ms_message("Defer ringing to gather ICE candidates"); - return; - } -#ifdef BUILD_UPNP - if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) && (call->upnp_session != NULL)) { - /* Defer ringing until the end of the ICE candidates gathering process. */ - ms_message("Defer ringing to gather uPnP candidates"); - return; - } -#endif //BUILD_UPNP - - linphone_core_notify_incoming_call(lc,call); + LinphoneCall *call = linphone_call_new_incoming(lc, fromAddr, toAddr, h); + linphone_address_unref(fromAddr); + linphone_address_unref(toAddr); + L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->startIncomingNotification(); } static void call_rejected(SalOp *h){ @@ -407,43 +181,7 @@ static void call_rejected(SalOp *h){ linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, linphone_address_new(sal_op_get_from(h)), linphone_address_new(sal_op_get_to(h)), ei); } -static void try_early_media_forking(LinphoneCall *call, SalMediaDescription *md){ - SalMediaDescription *cur_md=call->resultdesc; - int i; - SalStreamDescription *ref_stream,*new_stream; - ms_message("Early media response received from another branch, checking if media can be forked to this new destination."); - - for (i=0;istreams[i])) continue; - ref_stream=&cur_md->streams[i]; - new_stream=&md->streams[i]; - if (ref_stream->type==new_stream->type && ref_stream->payloads && new_stream->payloads){ - PayloadType *refpt, *newpt; - refpt=(PayloadType*)ref_stream->payloads->data; - newpt=(PayloadType*)new_stream->payloads->data; - if (strcmp(refpt->mime_type,newpt->mime_type)==0 && refpt->clock_rate==newpt->clock_rate - && payload_type_get_number(refpt)==payload_type_get_number(newpt)){ - MediaStream *ms=NULL; - if (ref_stream->type==SalAudio){ - ms=(MediaStream*)call->audiostream; - }else if (ref_stream->type==SalVideo){ - ms=(MediaStream*)call->videostream; - } - if (ms){ - RtpSession *session=ms->sessions.rtp_session; - const char *rtp_addr=new_stream->rtp_addr[0]!='\0' ? new_stream->rtp_addr : md->addr; - const char *rtcp_addr=new_stream->rtcp_addr[0]!='\0' ? new_stream->rtcp_addr : md->addr; - if (ms_is_multicast(rtp_addr)) - ms_message("Multicast addr [%s/%i] does not need auxiliary rtp's destination for call [%p]", - rtp_addr,new_stream->rtp_port,call); - else - rtp_session_add_aux_remote_addr_full(session,rtp_addr,new_stream->rtp_port,rtcp_addr,new_stream->rtcp_port); - } - } - } - } -} - +#if 0 static void start_remote_ring(LinphoneCore *lc, LinphoneCall *call) { if (lc->sound_conf.play_sndcard!=NULL){ MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; @@ -456,200 +194,18 @@ static void start_remote_ring(LinphoneCore *lc, LinphoneCall *call) { } } } - -static void call_ringing(SalOp *h){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(h); - SalMediaDescription *md; - - if (call==NULL) return; - - /*set privacy*/ - linphone_call_params_set_privacy(call->current_params, (LinphonePrivacyMask)sal_op_get_privacy(call->op)); - - linphone_core_notify_display_status(lc,_("Remote ringing.")); - - md=sal_call_get_final_media_description(h); - if (md==NULL){ - linphone_core_stop_dtmf_stream(lc); - if (call->state==LinphoneCallOutgoingEarlyMedia){ - /*already doing early media */ - return; - } - if (lc->ringstream == NULL) start_remote_ring(lc, call); - ms_message("Remote ringing..."); - linphone_core_notify_display_status(lc,_("Remote ringing...")); - linphone_call_set_state(call,LinphoneCallOutgoingRinging,"Remote ringing"); - }else{ - /*initialize the remote call params by invoking linphone_call_get_remote_params(). This is useful as the SDP may not be present in the 200Ok*/ - linphone_call_get_remote_params(call); - /*accept early media */ - if ((call->audiostream && audio_stream_started(call->audiostream)) -#ifdef VIDEO_ENABLED - || (call->videostream && video_stream_started(call->videostream)) #endif - ) { - /*streams already started */ - try_early_media_forking(call,md); - #ifdef VIDEO_ENABLED - if (call->videostream){ - /*just request for iframe*/ - video_stream_send_vfu(call->videostream); - } - #endif - return; - } - linphone_core_notify_show_interface(lc); - linphone_core_notify_display_status(lc,_("Early media.")); - linphone_call_set_state(call,LinphoneCallOutgoingEarlyMedia,"Early media"); - linphone_core_stop_ringing(lc); - ms_message("Doing early media..."); - linphone_call_update_streams(call, md, call->state); - if ((linphone_call_params_get_audio_direction(linphone_call_get_current_params(call)) == LinphoneMediaDirectionInactive) && call->audiostream) { - if (lc->ringstream != NULL) return; /* Already ringing! */ - start_remote_ring(lc, call); - } - } +static void call_ringing(SalOp *h) { + LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(h)); + if (!session) return; + L_GET_PRIVATE(session)->remoteRinging(); } static void start_pending_refer(LinphoneCall *call){ +#if 0 linphone_core_start_refered_call(call->core, call,NULL); -} - -static void process_call_accepted(LinphoneCore *lc, LinphoneCall *call, SalOp *op){ - SalMediaDescription *md, *rmd; - LinphoneCallState next_state = LinphoneCallIdle; - const char *next_state_str = NULL; - LinphoneTaskList tl; - - switch (call->state){/*immediately notify the connected state, even if errors occur after*/ - case LinphoneCallOutgoingProgress: - case LinphoneCallOutgoingRinging: - case LinphoneCallOutgoingEarlyMedia: - /*immediately notify the connected state*/ - linphone_call_set_state(call,LinphoneCallConnected,"Connected"); - { - char *tmp=linphone_call_get_remote_address_as_string (call); - char *msg=ms_strdup_printf(_("Call answered by %s"),tmp); - linphone_core_notify_display_status(lc,msg); - ms_free(tmp); - ms_free(msg); - } - break; - default: - break; - } - - linphone_task_list_init(&tl); - rmd=sal_call_get_remote_media_description(op); - /*set privacy*/ - linphone_call_params_set_privacy(call->current_params, (LinphonePrivacyMask)sal_op_get_privacy(call->op)); - /*reset the internal call update flag, so it doesn't risk to be copied and used in further re-INVITEs*/ - if (linphone_call_params_get_internal_call_update(call->params)) - linphone_call_params_set_internal_call_update(call->params, FALSE); - - -#ifdef BUILD_UPNP - if (call->upnp_session != NULL && rmd) { - linphone_call_update_upnp_from_remote_media_description(call, rmd); - } -#endif //BUILD_UPNP - - md=sal_call_get_final_media_description(op); - if (md == NULL && call->prevstate == LinphoneCallOutgoingEarlyMedia && call->resultdesc != NULL){ - ms_message("Using early media SDP since none was received with the 200 OK"); - md = call->resultdesc; - } - if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md))){ - md = NULL; - } - if (md){ /*there is a valid SDP in the response, either offer or answer, and we're able to start/update the streams*/ - - /* Handle remote ICE attributes if any. */ - if (call->ice_session != NULL && rmd) { - linphone_call_update_ice_from_remote_media_description(call, rmd, !sal_call_is_offerer(op)); - } - - switch (call->state){ - case LinphoneCallResuming: - linphone_core_notify_display_status(lc,_("Call resumed.")); - BCTBX_NO_BREAK; /*intentionally no break*/ - case LinphoneCallConnected: - if (call->referer) linphone_core_notify_refer_state(lc,call->referer,call); - BCTBX_NO_BREAK; /*intentionally no break*/ - case LinphoneCallUpdating: - case LinphoneCallUpdatedByRemote: - if (!sal_media_description_has_dir(call->localdesc, SalStreamInactive) && - (sal_media_description_has_dir(md,SalStreamRecvOnly) || - sal_media_description_has_dir(md,SalStreamInactive))){ - next_state = LinphoneCallPausedByRemote; - next_state_str = "Call paused by remote"; - }else{ - if (!linphone_call_params_get_in_conference(call->params)) - lc->current_call=call; - next_state = LinphoneCallStreamsRunning; - next_state_str = "Streams running"; - } - break; - case LinphoneCallEarlyUpdating: - next_state_str = "Early update accepted"; - next_state = call->prevstate; - break; - case LinphoneCallPausing: - /*when we entered the pausing state, we always reach the paused state whatever the content of the remote SDP is. - Our streams are all send-only (with music), soundcard and camera are never used*/ - next_state = LinphoneCallPaused; - next_state_str = "Call paused"; - if (call->refer_pending) - linphone_task_list_add(&tl, (LinphoneCoreIterateHook)start_pending_refer, call); - break; - default: - ms_error("call_accepted(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state)); - break; - } - - if (next_state != LinphoneCallIdle){ - linphone_call_update_remote_session_id_and_ver(call); - linphone_call_update_ice_state_in_call_stats(call); - linphone_call_update_streams(call, md, next_state); - linphone_call_fix_call_parameters(call, rmd); - linphone_call_set_state(call, next_state, next_state_str); - }else{ - ms_error("BUG: next_state is not set in call_accepted(), current state is %s", linphone_call_state_to_string(call->state)); - } - }else{ /*invalid or no SDP*/ - switch (call->prevstate){ - /*send a bye only in case of early states*/ - case LinphoneCallOutgoingInit: - case LinphoneCallOutgoingProgress: - case LinphoneCallOutgoingRinging: - case LinphoneCallOutgoingEarlyMedia: - case LinphoneCallIncomingReceived: - case LinphoneCallIncomingEarlyMedia: - ms_error("Incompatible SDP answer received, need to abort the call"); - linphone_call_abort(call, _("Incompatible, check codecs or security settings...")); - break; - /*otherwise we are able to resume previous state*/ - default: - ms_error("Incompatible SDP answer received"); - switch(call->state) { - case LinphoneCallPausedByRemote: - break; - case LinphoneCallPaused: - break; - case LinphoneCallStreamsRunning: - break; - default: - ms_message("Incompatible SDP answer received, restoring previous state [%s]",linphone_call_state_to_string(call->prevstate)); - linphone_call_set_state(call,call->prevstate,_("Incompatible media parameters.")); - break; - } - break; - } - } - linphone_task_list_run(&tl); - linphone_task_list_free(&tl); +#endif } /* @@ -657,245 +213,54 @@ static void process_call_accepted(LinphoneCore *lc, LinphoneCall *call, SalOp *o * - when the call is accepted * - when a request is accepted (pause, resume) */ -static void call_accepted(SalOp *op){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - - if (call == NULL){ - ms_warning("call_accepted: call does no longer exist."); - return ; - } - process_call_accepted(lc, call, op); -} - -static void call_resumed(LinphoneCore *lc, LinphoneCall *call){ - linphone_core_notify_display_status(lc,_("We have been resumed.")); - _linphone_call_accept_update(call,NULL,LinphoneCallStreamsRunning,"Connected (streams running)"); -} - -static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){ - LinphoneCallParams *params; - - /* we are being paused */ - linphone_core_notify_display_status(lc,_("We are paused by other party.")); - params = linphone_call_params_copy(call->params); - if (lp_config_get_int(lc->config, "sip", "inactive_video_on_pause", 0)) { - linphone_call_params_set_video_direction(params, LinphoneMediaDirectionInactive); - } - _linphone_call_accept_update(call,params,LinphoneCallPausedByRemote,"Call paused by remote"); - linphone_call_params_unref(params); -} - -static void call_updated_by_remote(LinphoneCore *lc, LinphoneCall *call){ - linphone_core_notify_display_status(lc,_("Call is updated by remote.")); - linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote"); - if (call->defer_update == FALSE){ - if (call->state == LinphoneCallUpdatedByRemote){ - linphone_call_accept_update(call, NULL); - }else{ - /*otherwise it means that the app responded by linphone_core_accept_call_update - * within the callback, so job is already done.*/ - } - }else{ - if (call->state == LinphoneCallUpdatedByRemote){ - ms_message("LinphoneCall [%p]: UpdatedByRemoted was signaled but defered. LinphoneCore expects the application to call " - "linphone_core_accept_call_update() later.", call); - } +static void call_accepted(SalOp *op) { + LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); + if (!session) { + ms_warning("call_accepted: CallSession no longer exists"); + return; } + L_GET_PRIVATE(session)->accepted(); } /* this callback is called when an incoming re-INVITE/ SIP UPDATE modifies the session*/ -static void call_updated(LinphoneCore *lc, LinphoneCall *call, SalOp *op, bool_t is_update){ - SalErrorInfo sei; - SalMediaDescription *rmd=sal_call_get_remote_media_description(op); - - memset(&sei, 0, sizeof(sei)); - call->defer_update = lp_config_get_int(lc->config, "sip", "defer_update_default", FALSE); - - switch(call->state){ - case LinphoneCallPausedByRemote: - if (sal_media_description_has_dir(rmd,SalStreamSendRecv) || sal_media_description_has_dir(rmd,SalStreamRecvOnly)){ - call_resumed(lc,call); - }else{ - call_updated_by_remote(lc, call); - } - break; - /*SIP UPDATE CASE*/ - case LinphoneCallOutgoingRinging: - case LinphoneCallOutgoingEarlyMedia: - case LinphoneCallIncomingEarlyMedia: - if (is_update) { - linphone_call_set_state(call, LinphoneCallEarlyUpdatedByRemote, "EarlyUpdatedByRemote"); - _linphone_call_accept_update(call,NULL,call->prevstate,linphone_call_state_to_string(call->prevstate)); - } - break; - case LinphoneCallStreamsRunning: - case LinphoneCallConnected: - case LinphoneCallUpdatedByRemote: // Can happen on UAC connectivity loss - if (sal_media_description_has_dir(rmd,SalStreamSendOnly) || sal_media_description_has_dir(rmd,SalStreamInactive)){ - call_paused_by_remote(lc,call); - }else{ - call_updated_by_remote(lc, call); - } - break; - case LinphoneCallPaused: - /*we'll remain in pause state but accept the offer anyway according to default parameters*/ - _linphone_call_accept_update(call,NULL,call->state,linphone_call_state_to_string(call->state)); - break; - case LinphoneCallUpdating: - case LinphoneCallPausing: - case LinphoneCallResuming: - sal_error_info_set(&sei,SalReasonInternalError, "SIP", 0, NULL, NULL); - sal_call_decline_with_error_info(call->op, &sei,NULL); - BCTBX_NO_BREAK; /*no break*/ - case LinphoneCallIdle: - case LinphoneCallOutgoingInit: - case LinphoneCallEnd: - case LinphoneCallIncomingReceived: - case LinphoneCallOutgoingProgress: - case LinphoneCallRefered: - case LinphoneCallError: - case LinphoneCallReleased: - case LinphoneCallEarlyUpdatedByRemote: - case LinphoneCallEarlyUpdating: - ms_warning("Receiving reINVITE or UPDATE while in state [%s], should not happen.",linphone_call_state_to_string(call->state)); - break; - } - sal_error_info_reset(&sei); -} - -/* this callback is called when an incoming re-INVITE/ SIP UPDATE modifies the session*/ -static void call_updating(SalOp *op, bool_t is_update){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - SalMediaDescription *rmd=sal_call_get_remote_media_description(op); - SalErrorInfo sei; - - if (!call) { - ms_error("call_updating(): call doesn't exist anymore"); - return ; - } - memset(&sei, 0, sizeof(sei)); - linphone_call_fix_call_parameters(call, rmd); - if (call->state!=LinphoneCallPaused){ - /*Refresh the local description, but in paused state, we don't change anything.*/ - if (rmd == NULL && lp_config_get_int(call->core->config,"sip","sdp_200_ack_follow_video_policy",0)) { - LinphoneCallParams *p=linphone_core_create_call_params(lc, NULL); - ms_message("Applying default policy for offering SDP on call [%p]",call); - _linphone_call_set_new_params(call, p); - linphone_call_params_unref(p); - } - linphone_call_make_local_media_description(call); - sal_call_set_local_media_description(call->op,call->localdesc); - } - if (rmd == NULL){ - /* case of a reINVITE or UPDATE without SDP */ - call->expect_media_in_ack = TRUE; - sal_call_accept(op); /*respond with an offer*/ - /*don't do anything else in this case, wait for the ACK to receive to notify the app*/ - }else { - SalMediaDescription *md; - SalMediaDescription *prev_result_desc=call->resultdesc; - - call->expect_media_in_ack = FALSE; - - md=sal_call_get_final_media_description(call->op); - if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md))){ - sal_error_info_set(&sei,SalReasonNotAcceptable, "SIP", 0, NULL, NULL); - sal_call_decline_with_error_info(call->op, &sei,NULL); - sal_error_info_reset(&sei); - return; - } - if (is_update && prev_result_desc && md){ - int diff=sal_media_description_equals(prev_result_desc,md); - if (diff & (SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED|SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED)){ - ms_warning("Cannot accept this update, it is changing parameters that require user approval"); - sal_error_info_set(&sei,SalReasonUnknown, "SIP", 504, "Cannot change the session parameters without prompting the user", NULL); - sal_call_decline_with_error_info(call->op, &sei,NULL); - sal_error_info_reset(&sei); - return; - } - } - call_updated(lc, call, op, is_update); - } -} - - -static void call_ack_received(SalOp *op, SalCustomHeader *ack){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - - if (call == NULL){ - ms_warning("call_ack(): no call for which an ack is expected"); +static void call_updating(SalOp *op, bool_t is_update) { + LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); + if (!session) { + ms_warning("call_updating: CallSession no longer exists"); return; } - linphone_call_notify_ack_processing(call, reinterpret_cast(ack), TRUE); - if (call->expect_media_in_ack){ - switch(call->state){ - case LinphoneCallStreamsRunning: - case LinphoneCallPausedByRemote: - linphone_call_set_state(call, LinphoneCallUpdatedByRemote, "UpdatedByRemote"); - break; - default: - break; - } - process_call_accepted(lc, call, op); - } + L_GET_PRIVATE(session)->updating(is_update); } -static void call_ack_being_sent(SalOp *op, SalCustomHeader *ack){ - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - - if (call == NULL){ - ms_warning("call_ack(): no call for which an ack is supposed to be sent"); +static void call_ack_received(SalOp *op, SalCustomHeader *ack) { + LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); + if (!session) { + ms_warning("call_ack_received(): no CallSession for which an ack is expected"); return; } - linphone_call_notify_ack_processing(call, reinterpret_cast(ack), FALSE); + L_GET_PRIVATE(session)->ackReceived(reinterpret_cast(ack)); } -static void call_terminated(SalOp *op, const char *from){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - if (call==NULL) return; - - switch(linphone_call_get_state(call)){ - case LinphoneCallEnd: - case LinphoneCallError: - ms_warning("call_terminated: already terminated, ignoring."); - return; - break; - case LinphoneCallIncomingReceived: - case LinphoneCallIncomingEarlyMedia: - if(!sal_op_get_reason_error_info(op)->protocol || strcmp(sal_op_get_reason_error_info(op)->protocol, "") == 0) { - linphone_error_info_set(call->ei,NULL, LinphoneReasonNotAnswered, 0, "Incoming call cancelled", NULL); - call->non_op_error = TRUE; - } - break; - default: - break; +static void call_ack_being_sent(SalOp *op, SalCustomHeader *ack) { + LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); + if (!session) { + ms_warning("call_ack_being_sent(): no CallSession for which an ack is supposed to be sent"); + return; } - ms_message("Current call terminated..."); - if (call->refer_pending){ - linphone_core_start_refered_call(lc,call,NULL); - } - //we stop the call only if we have this current call or if we are in call - if ((bctbx_list_size(lc->calls) == 1) || linphone_core_in_call(lc)) { - linphone_core_stop_ringing(lc); - } - linphone_call_stop_media_streams(call); - linphone_core_notify_show_interface(lc); - linphone_core_notify_display_status(lc,_("Call terminated.")); + L_GET_PRIVATE(session)->ackBeingSent(reinterpret_cast(ack)); +} -#ifdef BUILD_UPNP - linphone_call_delete_upnp_session(call); -#endif //BUILD_UPNP - - linphone_call_set_state(call, LinphoneCallEnd,"Call ended"); +static void call_terminated(SalOp *op, const char *from) { + LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); + if (!session) + return; + L_GET_PRIVATE(session)->terminated(); } static int resume_call_after_failed_transfer(LinphoneCall *call){ +#if 0 if (call->was_automatically_paused && call->state==LinphoneCallPausing) return BELLE_SIP_CONTINUE; /*was still in pausing state*/ @@ -909,189 +274,38 @@ static int resume_call_after_failed_transfer(LinphoneCall *call){ } linphone_call_unref(call); return BELLE_SIP_STOP; +#else + return BELLE_SIP_STOP; +#endif } -static void call_failure(SalOp *op){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - const SalErrorInfo *ei=sal_op_get_error_info(op); - const char *msg486=_("User is busy."); - const char *msg480=_("User is temporarily unavailable."); - /*const char *retrymsg=_("%s. Retry after %i minute(s).");*/ - const char *msg600=_("User does not want to be disturbed."); - const char *msg603=_("Call declined."); - const char *msg=ei->full_string; - LinphoneCall *referer; - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - bool_t stop_ringing = TRUE; - bctbx_list_t *calls = lc->calls; - - if (call==NULL){ - ms_warning("Call faillure reported on already terminated call."); - return ; - } - - referer=call->referer; - - linphone_core_notify_show_interface(lc); - switch(ei->reason){ - case SalReasonNone: - break; - case SalReasonRequestTimeout: - msg=_("Request timeout."); - linphone_core_notify_display_status(lc,msg); - break; - case SalReasonDeclined: - msg=msg603; - linphone_core_notify_display_status(lc,msg603); - break; - case SalReasonBusy: - msg=msg486; - linphone_core_notify_display_status(lc,msg486); - break; - case SalReasonRedirect: - { - linphone_call_stop_media_streams(call); - if ( - call->state == LinphoneCallOutgoingInit || - call->state == LinphoneCallOutgoingProgress || - call->state == LinphoneCallOutgoingRinging || - call->state == LinphoneCallOutgoingEarlyMedia - ) { - const SalAddress* redirection_to = sal_op_get_remote_contact_address(call->op); - if (redirection_to) { - char *url = sal_address_as_string(redirection_to); - ms_warning("Redirecting call [%p] to %s",call, url); - if (call->log->to) - linphone_address_unref(call->log->to); - call->log->to = linphone_address_new(url); - ms_free(url); - linphone_call_restart_invite(call); - return; - } - } - msg=_("Redirected"); - linphone_core_notify_display_status(lc,msg); - } - break; - case SalReasonTemporarilyUnavailable: - msg=msg480; - linphone_core_notify_display_status(lc,msg480); - break; - case SalReasonNotFound: - linphone_core_notify_display_status(lc,msg); - break; - case SalReasonDoNotDisturb: - msg=msg600; - linphone_core_notify_display_status(lc,msg600); - break; - case SalReasonUnsupportedContent: /*state == LinphoneCallOutgoingInit) - || (call->state == LinphoneCallOutgoingProgress) - || (call->state == LinphoneCallOutgoingRinging) /* Push notification case */ - || (call->state == LinphoneCallOutgoingEarlyMedia)) { - int i; - for (i = 0; i < call->localdesc->nb_streams; i++) { - if (!sal_stream_description_active(&call->localdesc->streams[i])) continue; - if (linphone_call_params_get_media_encryption(call->params) == LinphoneMediaEncryptionSRTP) { - if (linphone_call_params_avpf_enabled(call->params) == TRUE) { - if (i == 0) ms_message("Retrying call [%p] with SAVP", call); - linphone_call_params_enable_avpf(call->params, FALSE); - linphone_call_restart_invite(call); - return; - } else if (!linphone_core_is_media_encryption_mandatory(lc)) { - if (i == 0) ms_message("Retrying call [%p] with AVP", call); - linphone_call_params_set_media_encryption(call->params, LinphoneMediaEncryptionNone); - memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto)); - linphone_call_restart_invite(call); - return; - } - } else if (linphone_call_params_avpf_enabled(call->params) == TRUE) { - if (i == 0) ms_message("Retrying call [%p] with AVP", call); - linphone_call_params_enable_avpf(call->params, FALSE); - linphone_call_restart_invite(call); - return; - } - } - } - msg=_("Incompatible media parameters."); - linphone_core_notify_display_status(lc,msg); - break; - default: - linphone_core_notify_display_status(lc,_("Call failed.")); - } - - /*some call errors are not fatal*/ - switch (call->state) { - case LinphoneCallUpdating: - case LinphoneCallPausing: - case LinphoneCallResuming: - if (ei->reason != SalReasonNoMatch){ - ms_message("Call error on state [%s], restoring previous state",linphone_call_state_to_string(call->prevstate)); - linphone_call_set_state(call, call->prevstate,ei->full_string); - return; - } - default: - break; /*nothing to do*/ - } - - /* Stop ringing */ - bool_t ring_during_early_media = linphone_core_get_ring_during_incoming_early_media(lc); - while(calls) { - if (((LinphoneCall *)calls->data)->state == LinphoneCallIncomingReceived || (ring_during_early_media && ((LinphoneCall *)calls->data)->state == LinphoneCallIncomingEarlyMedia)) { - stop_ringing = FALSE; - break; - } - calls = calls->next; - } - if(stop_ringing) { - linphone_core_stop_ringing(lc); - } - linphone_call_stop_media_streams(call); - -#ifdef BUILD_UPNP - linphone_call_delete_upnp_session(call); -#endif //BUILD_UPNP - - if (call->state!=LinphoneCallEnd && call->state!=LinphoneCallError){ - if (ei->reason==SalReasonDeclined){ - linphone_call_set_state(call,LinphoneCallEnd,"Call declined."); - }else{ - if (linphone_call_state_is_early(call->state)){ - linphone_call_set_state(call,LinphoneCallError,ei->full_string); - }else{ - linphone_call_set_state(call, LinphoneCallEnd, ei->full_string); - } - } - if (ei->reason!=SalReasonNone) linphone_core_play_call_error_tone(lc,linphone_reason_from_sal(ei->reason)); - } - - if (referer){ - /*notify referer of the failure*/ - linphone_core_notify_refer_state(lc,referer,call); - /*schedule automatic resume of the call. This must be done only after the notifications are completed due to dialog serialization of requests.*/ - linphone_core_queue_task(lc,(belle_sip_source_func_t)resume_call_after_failed_transfer,linphone_call_ref(referer),"Automatic call resuming after failed transfer"); +static void call_failure(SalOp *op) { + LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); + if (!session) { + ms_warning("Failure reported on already terminated CallSession"); + return; } + L_GET_PRIVATE(session)->failure(); } -static void call_released(SalOp *op){ - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - if (call!=NULL){ - linphone_call_set_state(call,LinphoneCallReleased,"Call released"); - }else{ - /*we can arrive here when the core manages call at Sal level without creating a LinphoneCall object. Typicially: - * - when declining an incoming call with busy because maximum number of calls is reached. - */ +static void call_released(SalOp *op) { + LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); + if (!session) { + /* We can get here when the core manages call at Sal level without creating a Call object. Typicially, + * when declining an incoming call with busy because maximum number of calls is reached. */ + return; } + L_GET_PRIVATE(session)->setState(LinphoneCallReleased, "Call released"); } static void call_cancel_done(SalOp *op) { +#if 0 LinphoneCall *call = (LinphoneCall *)sal_op_get_user_pointer(op); if (call->reinvite_on_cancel_response_requested == TRUE) { call->reinvite_on_cancel_response_requested = FALSE; linphone_call_reinvite_to_recover_from_connection_loss(call); } +#endif } static void auth_failure(SalOp *op, SalAuthInfo* info) { @@ -1166,25 +380,28 @@ static void register_failure(SalOp *op){ } } -static void vfu_request(SalOp *op){ -#ifdef VIDEO_ENABLED - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op); - if (call==NULL){ - ms_warning("VFU request but no call !"); - return ; +static void vfu_request(SalOp *op) { + LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); + if (!session) + return; + LinphonePrivate::MediaSession *mediaSession = dynamic_cast(session); + if (!mediaSession) { + ms_warning("VFU request but no MediaSession!"); + return; } - if (call->videostream) - video_stream_send_vfu(call->videostream); -#endif + L_GET_PRIVATE(mediaSession)->sendVfu(); } static void dtmf_received(SalOp *op, char dtmf){ +#if 0 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); if (!call) return; linphone_call_notify_dtmf_received(call, dtmf); +#endif } static void refer_received(Sal *sal, SalOp *op, const char *referto){ +#if 0 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); LinphoneAddress *refer_to_addr = linphone_address_new(referto); @@ -1211,6 +428,7 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){ }else { linphone_core_notify_refer_received(lc,referto); } +#endif } static void message_received(SalOp *op, const SalMessage *msg){ @@ -1254,19 +472,13 @@ static void subscribe_presence_closed(SalOp *op, const char *from){ linphone_subscription_closed(lc,op); } -static void ping_reply(SalOp *op){ - LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op); - ms_message("ping reply !"); - if (call){ - if (call->state==LinphoneCallOutgoingInit){ - call->ping_replied=TRUE; - linphone_call_proceed_with_invite_if_ready(call, NULL); - } - } - else - { - ms_warning("ping reply without call attached..."); +static void ping_reply(SalOp *op) { + LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); + if (!session) { + ms_warning("Ping reply without CallSession attached..."); + return; } + L_GET_PRIVATE(session)->pingReply(); } static bool_t fill_auth_info_with_client_certificate(LinphoneCore *lc, SalAuthInfo* sai) { diff --git a/coreapi/chat.c b/coreapi/chat.c index 3710ad7f6..3674db2ff 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -192,7 +192,7 @@ static LinphoneChatRoom *_linphone_core_create_chat_room(LinphoneCore *lc, Linph } LinphoneChatRoom *_linphone_core_create_chat_room_from_call(LinphoneCall *call){ - LinphoneChatRoom *cr = _linphone_core_create_chat_room_base(call->core, + LinphoneChatRoom *cr = _linphone_core_create_chat_room_base(linphone_call_get_core(call), linphone_address_clone(linphone_call_get_remote_address(call))); linphone_chat_room_set_call(cr, call); return cr; @@ -614,7 +614,7 @@ LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg, uint32_t const uint32_t crlf = 0x0D0A; const uint32_t lf = 0x0A; - if (!call || !call->textstream) { + if (!call || !linphone_call_get_stream(call, LinphoneStreamTypeText)) { return -1; } @@ -637,7 +637,7 @@ LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg, uint32_t delete value; } - text_stream_putchar32(call->textstream, character); + text_stream_putchar32(reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeText)), character); return 0; } diff --git a/coreapi/conference.cc b/coreapi/conference.cc index 39a12916a..0f881ee2e 100644 --- a/coreapi/conference.cc +++ b/coreapi/conference.cc @@ -54,8 +54,9 @@ public: ~Participant() { linphone_address_unref(m_uri); +#if 0 if(m_call) m_call->conf_ref = NULL; - +#endif } const LinphoneAddress *getUri() const { @@ -257,7 +258,9 @@ Conference::Conference(LinphoneCore *core, LinphoneConference *conf, const Confe int Conference::addParticipant(LinphoneCall *call) { Participant *p =new Participant(call); m_participants.push_back(p); +#if 0 call->conf_ref = m_conference; +#endif return 0; } @@ -424,7 +427,7 @@ int LocalConference::inviteAddresses(const std::list &ad linphone_call_params_unref(new_params); }else{ /*there is already a call to this address, so simply join it to the local conference if not already done*/ - if (!linphone_call_params_get_in_conference(call->current_params)) + if (!linphone_call_params_get_in_conference(linphone_call_get_current_params(call))) addParticipant(call); } /*if the local participant is not yet created, created it and it to the conference */ @@ -434,6 +437,7 @@ int LocalConference::inviteAddresses(const std::list &ad } int LocalConference::addParticipant(LinphoneCall *call) { +#if 0 if (linphone_call_params_get_in_conference(call->current_params)){ ms_error("Already in conference"); return -1; @@ -465,9 +469,13 @@ int LocalConference::addParticipant(LinphoneCall *call) { return -1; } return 0; +#else + return 0; +#endif } int LocalConference::removeFromConference(LinphoneCall *call, bool_t active){ +#if 0 int err=0; char *str; @@ -501,6 +509,9 @@ int LocalConference::removeFromConference(LinphoneCall *call, bool_t active){ err=_linphone_call_pause(call); } return err; +#else + return 0; +#endif } int LocalConference::remoteParticipantsCount() { @@ -522,7 +533,7 @@ int LocalConference::convertConferenceToCall(){ while (calls) { LinphoneCall *rc=(LinphoneCall*)calls->data; calls=calls->next; - if (linphone_call_params_get_in_conference(rc->params)) { // not using current_param + if (linphone_call_params_get_in_conference(linphone_call_get_params(rc))) { // not using current_param bool_t active_after_removed=isIn(); err=removeFromConference(rc, active_after_removed); break; @@ -566,7 +577,7 @@ int LocalConference::terminate() { while (calls) { LinphoneCall *call=(LinphoneCall*)calls->data; calls=calls->next; - if (linphone_call_params_get_in_conference(call->current_params)) { + if (linphone_call_params_get_in_conference(linphone_call_get_current_params(call))) { linphone_call_terminate(call); } } @@ -639,6 +650,7 @@ int LocalConference::stopRecording() { } void LocalConference::onCallStreamStarting(LinphoneCall *call, bool isPausedByRemote) { +#if 0 linphone_call_params_enable_video(call->params, FALSE); call->camera_enabled = FALSE; ms_message("LocalConference::onCallStreamStarting(): joining AudioStream [%p] of call [%p] into conference.", call->audiostream, call); @@ -648,16 +660,20 @@ void LocalConference::onCallStreamStarting(LinphoneCall *call, bool isPausedByRe call->endpoint=ep; setState(LinphoneConferenceRunning); Conference::addParticipant(call); +#endif } void LocalConference::onCallStreamStopping(LinphoneCall *call) { +#if 0 ms_audio_conference_remove_member(m_conf,call->endpoint); ms_audio_endpoint_release_from_stream(call->endpoint); call->endpoint=NULL; Conference::removeParticipant(call); +#endif } void LocalConference::onCallTerminating(LinphoneCall *call) { +#if 0 int remote_count=remoteParticipantsCount(); ms_message("conference_check_uninit(): size=%i", getSize()); if (remote_count==1 && !m_terminating){ @@ -672,6 +688,7 @@ void LocalConference::onCallTerminating(LinphoneCall *call) { } setState(LinphoneConferenceStopped); } +#endif } @@ -701,6 +718,7 @@ int RemoteConference::inviteAddresses(const std::list & } int RemoteConference::addParticipant(LinphoneCall *call) { +#if 0 LinphoneAddress *addr; LinphoneCallParams *params; @@ -742,6 +760,9 @@ int RemoteConference::addParticipant(LinphoneCall *call) { ms_error("Could not add call %p to the conference. Bad conference state (%s)", call, stateToString(m_state)); return -1; } +#else + return -1; +#endif } int RemoteConference::removeParticipant(const LinphoneAddress *uri) { @@ -762,7 +783,7 @@ int RemoteConference::removeParticipant(const LinphoneAddress *uri) { linphone_address_set_method_param(refer_to_addr, "BYE"); refer_to = linphone_address_as_string(refer_to_addr); linphone_address_unref(refer_to_addr); - res = sal_call_refer(m_focusCall->op, refer_to); + res = sal_call_refer(linphone_call_get_op(m_focusCall), refer_to); ms_free(refer_to); if(res == 0) { diff --git a/coreapi/info.c b/coreapi/info.c index 27eb883a4..e6b09b8e3 100644 --- a/coreapi/info.c +++ b/coreapi/info.c @@ -78,8 +78,8 @@ LinphoneInfoMessage *linphone_core_create_info_message(LinphoneCore *lc){ LinphoneStatus linphone_call_send_info_message(LinphoneCall *call, const LinphoneInfoMessage *info) { SalBodyHandler *body_handler = sal_body_handler_from_content(info->content); - sal_op_set_sent_custom_header(call->op, info->headers); - return sal_send_info(call->op,NULL, NULL, body_handler); + sal_op_set_sent_custom_header(linphone_call_get_op(call), info->headers); + return sal_send_info(linphone_call_get_op(call), NULL, NULL, body_handler); } void linphone_info_message_add_header(LinphoneInfoMessage *im, const char *name, const char *value){ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 622a8acb1..d5a5eb690 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -45,20 +45,61 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // For migration purpose. #include "address/address-p.h" +#include "c-wrapper/c-private-types.h" #include "c-wrapper/c-tools.h" +#include "call/call.h" +#include "call/call-p.h" +#include "conference/params/media-session-params-p.h" -inline OrtpRtcpXrStatSummaryFlag operator|(OrtpRtcpXrStatSummaryFlag a, OrtpRtcpXrStatSummaryFlag b) { - return static_cast(static_cast(a) | static_cast(b)); -} +struct _LinphoneCall{ + belle_sip_object_t base; + void *user_data; + bctbx_list_t *callbacks; /* A list of LinphoneCallCbs object */ + LinphoneCallCbs *current_cbs; /* The current LinphoneCallCbs object used to call a callback */ + std::shared_ptr call; + LinphoneCallParams *currentParamsCache; + LinphoneCallParams *paramsCache; + LinphoneCallParams *remoteParamsCache; + LinphoneAddress *remoteAddressCache; + char *remoteContactCache; + struct _LinphoneCore *core; + LinphoneErrorInfo *ei; + SalMediaDescription *localdesc; + SalMediaDescription *resultdesc; + struct _LinphoneCallLog *log; + SalOp *op; + SalOp *ping_op; + LinphoneCallState transfer_state; /*idle if no transfer*/ + struct _AudioStream *audiostream; /**/ + struct _VideoStream *videostream; + struct _TextStream *textstream; + MSAudioEndpoint *endpoint; /*used for conferencing*/ + char *refer_to; + LinphoneCallParams *params; + LinphoneCallParams *current_params; + LinphoneCallParams *remote_params; + LinphoneCallStats *audio_stats; + LinphoneCallStats *video_stats; + LinphoneCallStats *text_stats; + LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/ + LinphoneCall *transfer_target;/*if this call received a transfer request, then transfer_target points to the new call created to the refer target */ + LinphonePlayer *player; + char *dtmf_sequence; /*DTMF sequence needed to be sent using #dtmfs_timer*/ + belle_sip_source_t *dtmfs_timer; /*DTMF timer needed to send a DTMF sequence*/ + LinphoneChatRoom *chat_room; + LinphoneConference *conf_ref; /**> Point on the associated conference if this call is part of a conference. NULL instead. */ + bool_t refer_pending; + bool_t defer_update; + bool_t was_automatically_paused; + bool_t paused_by_app; + bool_t broken; /*set to TRUE when the call is in broken state due to network disconnection or transport */ + bool_t need_localip_refresh; + bool_t reinvite_on_cancel_response_requested; + bool_t non_op_error; /*set when the LinphoneErrorInfo was set at higher level than sal*/ +}; -static const char *EC_STATE_STORE = ".linphone.ecstate"; -#define EC_STATE_MAX_LEN 1048576 // 1Mo - -static void linphone_call_stats_uninit(LinphoneCallStats *stats); -static void linphone_call_get_local_ip(LinphoneCall *call, const LinphoneAddress *remote_addr); -static void _linphone_call_set_next_video_frame_decoded_trigger(LinphoneCall *call); -void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index); +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneCall); typedef belle_sip_object_t_vptr_t LinphoneCallCbs_vptr_t; @@ -185,233 +226,21 @@ MSWebCam *get_nowebcam_device(MSFactory* f){ #endif } -static bool_t generate_b64_crypto_key(size_t key_length, char* key_out, size_t key_out_size) { - size_t b64_size; - uint8_t* tmp = (uint8_t*) ms_malloc0(key_length); - if (sal_get_random_bytes(tmp, key_length)==NULL) { - ms_error("Failed to generate random key"); - ms_free(tmp); - return FALSE; - } - - b64_size = b64::b64_encode((const char*)tmp, key_length, NULL, 0); - if (b64_size == 0) { - ms_error("Failed to get b64 result size"); - ms_free(tmp); - return FALSE; - } - if (b64_size>=key_out_size){ - ms_error("Insufficient room for writing base64 SRTP key"); - ms_free(tmp); - return FALSE; - } - b64_size = b64::b64_encode((const char*)tmp, key_length, key_out, key_out_size); - if (b64_size == 0) { - ms_error("Failed to b64 encode key"); - ms_free(tmp); - return FALSE; - } - key_out[b64_size] = '\0'; - ms_free(tmp); - return TRUE; +LinphoneCore *linphone_call_get_core(const LinphoneCall *call) { + return linphone_call_get_cpp_obj(call)->getCore(); } -static bool_t linphone_call_encryption_mandatory(LinphoneCall *call){ - if (linphone_call_params_get_media_encryption(call->params)==LinphoneMediaEncryptionDTLS) { - ms_message("Forced encryption mandatory on call [%p] due to SRTP-DTLS",call); - return TRUE; - } - return linphone_call_params_mandatory_media_encryption_enabled(call->params); +const char * linphone_call_get_authentication_token(LinphoneCall *call) { + std::string token = linphone_call_get_cpp_obj(call)->getAuthenticationToken(); + return token.empty() ? nullptr : token.c_str(); } -LinphoneCore *linphone_call_get_core(const LinphoneCall *call){ - return call->core; +bool_t linphone_call_get_authentication_token_verified(const LinphoneCall *call) { + return linphone_call_get_cpp_obj(call)->getAuthenticationTokenVerified(); } -const char* linphone_call_get_authentication_token(LinphoneCall *call){ - return call->auth_token; -} - -bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){ - return call->auth_token_verified; -} - -static bool_t at_least_one_stream_started(const LinphoneCall *call){ - return (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted ) - || (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) - || (call->textstream && media_stream_get_state((MediaStream *)call->textstream) == MSStreamStarted); -} - -static bool_t linphone_call_all_streams_encrypted(const LinphoneCall *call) { - int number_of_encrypted_stream = 0; - int number_of_active_stream = 0; - - if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) { - number_of_active_stream++; - if(media_stream_secured((MediaStream *)call->audiostream)) - number_of_encrypted_stream++; - } - if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) { - number_of_active_stream++; - if (media_stream_secured((MediaStream *)call->videostream)) - number_of_encrypted_stream++; - } - if (call->textstream && media_stream_get_state((MediaStream *)call->textstream) == MSStreamStarted) { - number_of_active_stream++; - if (media_stream_secured((MediaStream *)call->textstream)) - number_of_encrypted_stream++; - } - return number_of_active_stream>0 && number_of_active_stream==number_of_encrypted_stream; -} - -static bool_t linphone_call_all_streams_avpf_enabled(const LinphoneCall *call) { - int nb_active_streams = 0; - int nb_avpf_enabled_streams = 0; - if (call) { - if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) { - nb_active_streams++; - if (media_stream_avpf_enabled((MediaStream *)call->audiostream)) - nb_avpf_enabled_streams++; - } - if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) { - nb_active_streams++; - if (media_stream_avpf_enabled((MediaStream *)call->videostream)) - nb_avpf_enabled_streams++; - } - } - return ((nb_active_streams > 0) && (nb_active_streams == nb_avpf_enabled_streams)); -} - -static uint16_t linphone_call_get_avpf_rr_interval(const LinphoneCall *call) { - uint16_t rr_interval = 0; - uint16_t stream_rr_interval; - if (call) { - if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) { - stream_rr_interval = media_stream_get_avpf_rr_interval((MediaStream *)call->audiostream); - if (stream_rr_interval > rr_interval) rr_interval = stream_rr_interval; - } - if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) { - stream_rr_interval = media_stream_get_avpf_rr_interval((MediaStream *)call->videostream); - if (stream_rr_interval > rr_interval) rr_interval = stream_rr_interval; - } - } else { - rr_interval = 5000; - } - return rr_interval; -} - -static void propagate_encryption_changed(LinphoneCall *call){ - if (!linphone_call_all_streams_encrypted(call)) { - ms_message("Some streams are not encrypted"); - linphone_call_params_set_media_encryption(call->current_params, LinphoneMediaEncryptionNone); - linphone_call_notify_encryption_changed(call, FALSE, call->auth_token); - } else { - if (call->auth_token) {/* ZRTP only is using auth_token */ - linphone_call_params_set_media_encryption(call->current_params, LinphoneMediaEncryptionZRTP); - } else { /* otherwise it must be DTLS as SDES doesn't go through this function */ - linphone_call_params_set_media_encryption(call->current_params, LinphoneMediaEncryptionDTLS); - } - ms_message("All streams are encrypted key exchanged using %s", - linphone_call_params_get_media_encryption(call->current_params) == LinphoneMediaEncryptionZRTP - ? "ZRTP" - : linphone_call_params_get_media_encryption(call->current_params) == LinphoneMediaEncryptionDTLS ? "DTLS" : "Unknown mechanism"); - linphone_call_notify_encryption_changed(call, TRUE, call->auth_token); -#ifdef VIDEO_ENABLED - if (linphone_call_encryption_mandatory(call) && call->videostream && media_stream_started((MediaStream *)call->videostream)) { - video_stream_send_vfu(call->videostream); /*nothing could have been sent yet so generating key frame*/ - } -#endif - } -} - -static void linphone_call_audiostream_encryption_changed(void *data, bool_t encrypted) { - char status[255]={0}; - LinphoneCall *call; - - call = (LinphoneCall *)data; - - if (encrypted) { - if (linphone_call_params_get_media_encryption(call->params) == LinphoneMediaEncryptionZRTP) { /* if encryption is DTLS, no status to be displayed */ - snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token); - linphone_core_notify_display_status(call->core, status); - } - } - - propagate_encryption_changed(call); - -#ifdef VIDEO_ENABLED - // Enable video encryption - if (linphone_call_params_get_media_encryption(call->params) == LinphoneMediaEncryptionZRTP) { - const LinphoneCallParams *params=linphone_call_get_current_params(call); - if (linphone_call_params_video_enabled(params)) { - ms_message("Trying to start ZRTP encryption on video stream"); - video_stream_start_zrtp(call->videostream); - } - } -#endif -} - -static void linphone_call_audiostream_auth_token_ready(void *data, const char* auth_token, bool_t verified) { - LinphoneCall *call=(LinphoneCall *)data; - if (call->auth_token != NULL) - ms_free(call->auth_token); - - call->auth_token=ms_strdup(auth_token); - call->auth_token_verified=verified; - - ms_message("Authentication token is %s (%s)", auth_token, verified?"verified":"unverified"); -} - -void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified){ - if (call->audiostream==NULL || !media_stream_started(&call->audiostream->ms)){ - ms_error("linphone_call_set_authentication_token_verified(): No audio stream or not started"); - return; - } - if (call->audiostream->ms.sessions.zrtp_context==NULL){ - ms_error("linphone_call_set_authentication_token_verified(): No zrtp context."); - return; - } - if (!call->auth_token_verified && verified){ - ms_zrtp_sas_verified(call->audiostream->ms.sessions.zrtp_context); - }else if (call->auth_token_verified && !verified){ - ms_zrtp_sas_reset_verified(call->audiostream->ms.sessions.zrtp_context); - } - call->auth_token_verified=verified; - propagate_encryption_changed(call); -} - -static int get_max_codec_sample_rate(const bctbx_list_t *codecs){ - int max_sample_rate=0; - const bctbx_list_t *it; - for(it=codecs;it!=NULL;it=it->next){ - PayloadType *pt=(PayloadType*)it->data; - int sample_rate; - - if( strcasecmp("G722",pt->mime_type) == 0 ){ - /* G722 spec says 8000 but the codec actually requires 16000 */ - sample_rate = 16000; - }else sample_rate=pt->clock_rate; - if (sample_rate>max_sample_rate) max_sample_rate=sample_rate; - } - return max_sample_rate; -} - -static int find_payload_type_number(const bctbx_list_t *assigned, const PayloadType *pt){ - const bctbx_list_t *elem; - const PayloadType *candidate=NULL; - for(elem=assigned;elem!=NULL;elem=elem->next){ - const PayloadType *it=(const PayloadType*)elem->data; - if ((strcasecmp(pt->mime_type, payload_type_get_mime(it)) == 0) - && (it->clock_rate==pt->clock_rate) - && (it->channels==pt->channels || pt->channels<=0)) { - candidate=it; - if ((it->recv_fmtp!=NULL && pt->recv_fmtp!=NULL && strcasecmp(it->recv_fmtp, pt->recv_fmtp)==0) - || (it->recv_fmtp==NULL && pt->recv_fmtp==NULL)){ - break;/*exact match*/ - } - } - } - return candidate ? payload_type_get_number(candidate) : -1; +void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified) { + linphone_call_get_cpp_obj(call)->setAuthenticationTokenVerified(verified); } bool_t is_payload_type_number_available(const bctbx_list_t *l, int number, const PayloadType *ignore){ @@ -423,767 +252,14 @@ bool_t is_payload_type_number_available(const bctbx_list_t *l, int number, const return TRUE; } -static void linphone_core_assign_payload_type_numbers(LinphoneCore *lc, bctbx_list_t *codecs){ - bctbx_list_t *elem; - int dyn_number=lc->codecs_conf.dyn_pt; - PayloadType *red = NULL, *t140 = NULL; - - for (elem=codecs; elem!=NULL; elem=elem->next){ - PayloadType *pt=(PayloadType*)elem->data; - int number=payload_type_get_number(pt); - - /*check if number is duplicated: it could be the case if the remote forced us to use a mapping with a previous offer*/ - if (number!=-1 && !(pt->flags & PAYLOAD_TYPE_FROZEN_NUMBER)){ - if (!is_payload_type_number_available(codecs, number, pt)){ - ms_message("Reassigning payload type %i %s/%i because already offered.", number, pt->mime_type, pt->clock_rate); - number=-1; /*need to be re-assigned*/ - } - } - - if (number==-1){ - while(dyn_number<127){ - if (is_payload_type_number_available(codecs, dyn_number, NULL)){ - payload_type_set_number(pt, dyn_number); - dyn_number++; - break; - } - dyn_number++; - } - if (dyn_number==127){ - ms_error("Too many payload types configured ! codec %s/%i is disabled.", pt->mime_type, pt->clock_rate); - payload_type_set_enable(pt, FALSE); - } - } - - if (strcmp(pt->mime_type, payload_type_t140_red.mime_type) == 0) { - red = pt; - } else if (strcmp(pt->mime_type, payload_type_t140.mime_type) == 0) { - t140 = pt; - } - } - - if (t140 && red) { - int t140_payload_type_number = payload_type_get_number(t140); - char *red_fmtp = ms_strdup_printf("%i/%i/%i", t140_payload_type_number, t140_payload_type_number, t140_payload_type_number); - payload_type_set_recv_fmtp(red, red_fmtp); - ms_free(red_fmtp); - } -} - -static bool_t has_telephone_event_at_rate(const bctbx_list_t *tev, int rate){ - const bctbx_list_t *it; - for(it=tev;it!=NULL;it=it->next){ - const PayloadType *pt=(PayloadType*)it->data; - if (pt->clock_rate==rate) return TRUE; - } - return FALSE; -} - -static bctbx_list_t * create_telephone_events(LinphoneCore *lc, const bctbx_list_t *codecs){ - const bctbx_list_t *it; - bctbx_list_t *ret=NULL; - for(it=codecs;it!=NULL;it=it->next){ - const PayloadType *pt=(PayloadType*)it->data; - if (!has_telephone_event_at_rate(ret,pt->clock_rate)){ - PayloadType *tev=payload_type_clone(&payload_type_telephone_event); - tev->clock_rate=pt->clock_rate; - /*let it choose the number dynamically as for normal codecs*/ - payload_type_set_number(tev, -1); - if (ret==NULL){ - /*But for first telephone-event, prefer the number that was configured in the core*/ - if (is_payload_type_number_available(codecs, lc->codecs_conf.telephone_event_pt, NULL)){ - payload_type_set_number(tev, lc->codecs_conf.telephone_event_pt); - } - } - ret=bctbx_list_append(ret,tev); - } - } - return ret; -} - -static bctbx_list_t *create_special_payload_types(LinphoneCore *lc, const bctbx_list_t *codecs){ - bctbx_list_t *ret=create_telephone_events(lc, codecs); - if (linphone_core_generic_comfort_noise_enabled(lc)){ - PayloadType *cn=payload_type_clone(&payload_type_cn); - payload_type_set_number(cn, 13); - ret=bctbx_list_append(ret, cn); - } - return ret; -} - -typedef struct _CodecConstraints{ - int bandwidth_limit; - int max_codecs; - bctbx_list_t *previously_used; -}CodecConstraints; - -static bctbx_list_t *make_codec_list(LinphoneCore *lc, CodecConstraints * hints, SalStreamType stype, const bctbx_list_t *codecs){ - bctbx_list_t *l=NULL; - const bctbx_list_t *it; - int nb = 0; - - for(it=codecs;it!=NULL;it=it->next){ - PayloadType *pt=(PayloadType*)it->data; - int num; - - if (!payload_type_enabled(pt)) { - continue; - } - if (hints->bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,hints->bandwidth_limit)){ - ms_message("Codec %s/%i eliminated because of audio bandwidth constraint of %i kbit/s", - pt->mime_type,pt->clock_rate,hints->bandwidth_limit); - continue; - } - if (!_linphone_core_check_payload_type_usability(lc, pt)) { - continue; - } - pt=payload_type_clone(pt); - - /*look for a previously assigned number for this codec*/ - num=find_payload_type_number(hints->previously_used, pt); - if (num!=-1){ - payload_type_set_number(pt,num); - payload_type_set_flag(pt, PAYLOAD_TYPE_FROZEN_NUMBER); - } - - l=bctbx_list_append(l, pt); - nb++; - if ((hints->max_codecs > 0) && (nb >= hints->max_codecs)) break; - } - if (stype==SalAudio){ - bctbx_list_t *specials=create_special_payload_types(lc,l); - l=bctbx_list_concat(l,specials); - } - linphone_core_assign_payload_type_numbers(lc, l); - return l; -} - -static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc, const StunCandidate *tc){ - int i; - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { - if (!sal_stream_description_active(&md->streams[i])) continue; - if ((md->streams[i].type == SalAudio) && (ac->port != 0)) { - strcpy(md->streams[i].rtp_addr,ac->addr); - md->streams[i].rtp_port=ac->port; - if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || sal_media_description_get_nb_active_streams(md)==1){ - strcpy(md->addr,ac->addr); - } - } else if ((md->streams[i].type == SalVideo) && (vc->port != 0)) { - strcpy(md->streams[i].rtp_addr,vc->addr); - md->streams[i].rtp_port=vc->port; - } else if ((md->streams[i].type == SalText) && (tc->port != 0)) { - strcpy(md->streams[i].rtp_addr,tc->addr); - md->streams[i].rtp_port=tc->port; - } - } -} - -static int setup_encryption_key(SalSrtpCryptoAlgo *crypto, MSCryptoSuite suite, unsigned int tag){ - size_t keylen=0; - crypto->tag=tag; - crypto->algo=suite; - switch(suite){ - case MS_AES_128_SHA1_80: - case MS_AES_128_SHA1_32: - case MS_AES_128_NO_AUTH: - case MS_NO_CIPHER_SHA1_80: /*not sure for this one*/ - keylen=30; - break; - case MS_AES_256_SHA1_80: - case MS_AES_CM_256_SHA1_80: - case MS_AES_256_SHA1_32: - keylen=46; - break; - case MS_CRYPTO_SUITE_INVALID: - break; - } - if (keylen==0 || !generate_b64_crypto_key(keylen, crypto->master_key, SAL_SRTP_KEY_SIZE)){ - ms_error("Could not generate SRTP key."); - crypto->algo = MS_CRYPTO_SUITE_INVALID; - return -1; - } - return 0; -} -static void setup_dtls_keys(LinphoneCall *call, SalMediaDescription *md){ - int i; - for(i=0; istreams[i])) continue; - /* if media encryption is set to DTLS check presence of fingerprint in the call which shall have been set at stream init but it may have failed when retrieving certificate resulting in no fingerprint present and then DTLS not usable */ - if (sal_stream_description_has_dtls(&md->streams[i]) == TRUE) { - strncpy(md->streams[i].dtls_fingerprint, call->dtls_certificate_fingerprint, sizeof(md->streams[i].dtls_fingerprint)); /* get the self fingerprint from call(it's computed at stream init) */ - md->streams[i].dtls_role = SalDtlsRoleUnset; /* if we are offering, SDP will have actpass setup attribute when role is unset, if we are responding the result mediadescription will be set to SalDtlsRoleIsClient */ - } else { - md->streams[i].dtls_fingerprint[0] = '\0'; - md->streams[i].dtls_role = SalDtlsRoleInvalid; - - } - } - -} -static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){ - LinphoneCore *lc=call->core; - int i,j; - SalMediaDescription *old_md=call->localdesc; - bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",1); - - for(i=0; istreams[i])) continue; - if (sal_stream_description_has_srtp(&md->streams[i]) == TRUE) { - if (keep_srtp_keys && old_md && (sal_stream_description_active(&old_md->streams[i]) == TRUE) && (sal_stream_description_has_srtp(&old_md->streams[i]) == TRUE)) { - int j; - ms_message("Keeping same crypto keys."); - for(j=0;jstreams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo)); - } - }else{ - const MSCryptoSuite *suites=linphone_core_get_srtp_crypto_suites(lc); - for(j=0;suites!=NULL && suites[j]!=MS_CRYPTO_SUITE_INVALID && jstreams[i].crypto[j],suites[j],j+1); - } - } - } - } -} - - -static void setup_zrtp_hash(LinphoneCall *call, SalMediaDescription *md) { - int i; - if (linphone_core_media_encryption_supported(call->core, LinphoneMediaEncryptionZRTP)) { /* set the hello hash for all streams */ - for(i=0; istreams[i])) continue; - if (call->sessions[i].zrtp_context!=NULL) { - ms_zrtp_getHelloHash(call->sessions[i].zrtp_context, md->streams[i].zrtphash, 128); - if (linphone_call_params_get_media_encryption(call->params)==LinphoneMediaEncryptionZRTP) { /* turn on the flag to use it if ZRTP is set */ - md->streams[i].haveZrtpHash = 1; - } else { - md->streams[i].haveZrtpHash = 0; - } - } else { - md->streams[i].haveZrtpHash = 0; - } - } - } -} - -static void setup_rtcp_fb(LinphoneCall *call, SalMediaDescription *md) { - bctbx_list_t *pt_it; - PayloadType *pt; - PayloadTypeAvpfParams avpf_params; - LinphoneCore *lc = call->core; - int i; - - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { - if (!sal_stream_description_active(&md->streams[i])) continue; - md->streams[i].rtcp_fb.generic_nack_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_fb_generic_nack_enabled", 0); - md->streams[i].rtcp_fb.tmmbr_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_fb_tmmbr_enabled", 1); - md->streams[i].implicit_rtcp_fb = linphone_call_params_implicit_rtcp_fb_enabled(call->params); - - for (pt_it = md->streams[i].payloads; pt_it != NULL; pt_it = pt_it->next) { - pt = (PayloadType *)pt_it->data; - - if (linphone_call_params_avpf_enabled(call->params) == FALSE && linphone_call_params_implicit_rtcp_fb_enabled(call->params) == FALSE) { - payload_type_unset_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); - memset(&avpf_params, 0, sizeof(avpf_params)); - }else { - payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); - avpf_params = payload_type_get_avpf_params(pt); - avpf_params.trr_interval = linphone_call_params_get_avpf_rr_interval(call->params); - } - payload_type_set_avpf_params(pt, avpf_params); - } - } -} - -static void setup_rtcp_xr(LinphoneCall *call, SalMediaDescription *md) { - LinphoneCore *lc = call->core; - int i; - - md->rtcp_xr.enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_enabled", 1); - if (md->rtcp_xr.enabled == TRUE) { - const char *rcvr_rtt_mode = lp_config_get_string(lc->config, "rtp", "rtcp_xr_rcvr_rtt_mode", "all"); - if (strcasecmp(rcvr_rtt_mode, "all") == 0) md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttAll; - else if (strcasecmp(rcvr_rtt_mode, "sender") == 0) md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttSender; - else md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttNone; - if (md->rtcp_xr.rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) { - md->rtcp_xr.rcvr_rtt_max_size = lp_config_get_int(lc->config, "rtp", "rtcp_xr_rcvr_rtt_max_size", 10000); - } - md->rtcp_xr.stat_summary_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_stat_summary_enabled", 1); - if (md->rtcp_xr.stat_summary_enabled == TRUE) { - md->rtcp_xr.stat_summary_flags = OrtpRtcpXrStatSummaryLoss | OrtpRtcpXrStatSummaryDup | OrtpRtcpXrStatSummaryJitt | OrtpRtcpXrStatSummaryTTL; - } - md->rtcp_xr.voip_metrics_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_voip_metrics_enabled", 1); - } - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { - if (!sal_stream_description_active(&md->streams[i])) continue; - memcpy(&md->streams[i].rtcp_xr, &md->rtcp_xr, sizeof(md->streams[i].rtcp_xr)); - } -} - -void linphone_call_increment_local_media_description(LinphoneCall *call){ - SalMediaDescription *md=call->localdesc; - md->session_ver++; -} - void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall *call){ - LinphoneCore *lc = call->core; - if (call->ice_session != NULL) { - /*set this to FALSE once flexisip are updated everywhere, let's say in December 2016.*/ - bool_t use_nortpproxy = lp_config_get_int(lc->config, "sip", "ice_uses_nortpproxy", TRUE); - _update_local_media_description_from_ice(call->localdesc, call->ice_session, use_nortpproxy); - linphone_call_update_ice_state_in_call_stats(call); - } -#ifdef BUILD_UPNP - if(call->upnp_session != NULL) { - linphone_call_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); - linphone_call_update_upnp_state_in_call_stats(call); - } -#endif //BUILD_UPNP -} - -static void transfer_already_assigned_payload_types(SalMediaDescription *old, SalMediaDescription *md){ - int i; - for(i=0;istreams[i].already_assigned_payloads=old->streams[i].already_assigned_payloads; - old->streams[i].already_assigned_payloads=NULL; - } -} - -static const char *linphone_call_get_bind_ip_for_stream(LinphoneCall *call, int stream_index){ - const char *bind_ip = lp_config_get_string(call->core->config,"rtp","bind_address", - call->af == AF_INET6 ? "::0" : "0.0.0.0"); - PortConfig *pc = &call->media_ports[stream_index]; - if (pc->multicast_ip[0]!='\0'){ - if (call->dir==LinphoneCallOutgoing){ - /*as multicast sender, we must decide a local interface to use to send multicast, and bind to it*/ - linphone_core_get_local_ip_for(strchr(pc->multicast_ip,':') ? AF_INET6 : AF_INET, - NULL, pc->multicast_bind_ip); - bind_ip = pc->multicast_bind_ip; - }else{ - /*otherwise we shall use an address family of the same family of the multicast address, because - * dual stack socket and multicast don't work well on Mac OS (linux is OK, as usual).*/ - bind_ip = strchr(pc->multicast_ip,':') ? "::0" : "0.0.0.0"; - } - } - return bind_ip; -} - -static const char *linphone_call_get_public_ip_for_stream(LinphoneCall *call, int stream_index){ - const char *public_ip=call->media_localip; - - if (call->media_ports[stream_index].multicast_ip[0]!='\0') - public_ip=call->media_ports[stream_index].multicast_ip; - return public_ip; -} - -void linphone_call_update_biggest_desc(LinphoneCall *call, SalMediaDescription *md){ - if (call->biggestdesc==NULL || md->nb_streams>call->biggestdesc->nb_streams){ - /*we have been offered and now are ready to proceed, or we added a new stream*/ - /*store the media description to remember the mapping of calls*/ - if (call->biggestdesc){ - sal_media_description_unref(call->biggestdesc); - call->biggestdesc=NULL; - } - call->biggestdesc=sal_media_description_ref(md); - } -} - -static void force_streams_dir_according_to_state(LinphoneCall *call, SalMediaDescription *md){ - int i; - - for (i=0; istreams[i]; - - switch (call->state){ - case LinphoneCallPausing: - case LinphoneCallPaused: - if (sd->dir != SalStreamInactive) { - sd->dir = SalStreamSendOnly; - if (sd->type == SalVideo){ - if (lp_config_get_int(call->core->config, "sip", "inactive_video_on_pause", 0)) { - sd->dir = SalStreamInactive; - } - } - } - break; - default: - break; - } - - /* Reflect the stream directions in the call params */ - if (i == call->main_audio_stream_index) { - linphone_call_params_set_audio_direction(call->current_params, media_direction_from_sal_stream_dir(sd->dir)); - } else if (i == call->main_video_stream_index) { - linphone_call_params_set_video_direction(call->current_params, media_direction_from_sal_stream_dir(sd->dir)); - } - } } void linphone_call_make_local_media_description(LinphoneCall *call) { - bctbx_list_t *l; - SalMediaDescription *old_md=call->localdesc; - int i; - int max_index = 0; - SalMediaDescription *md=sal_media_description_new(); - LinphoneAddress *addr; - const char *subject; - CodecConstraints codec_hints={0}; - LinphoneCallParams *params = call->params; - LinphoneCore *lc = call->core; - bool_t rtcp_mux = lp_config_get_int(lc->config, "rtp", "rtcp_mux", 0); - - /*multicast is only set in case of outgoing call*/ - if (call->dir == LinphoneCallOutgoing && linphone_call_params_audio_multicast_enabled(params)) { - md->streams[call->main_audio_stream_index].ttl=linphone_core_get_audio_multicast_ttl(lc); - md->streams[call->main_audio_stream_index].multicast_role = SalMulticastSender; - } - - if (call->dir == LinphoneCallOutgoing && linphone_call_params_video_multicast_enabled(params)) { - md->streams[call->main_video_stream_index].ttl=linphone_core_get_video_multicast_ttl(lc); - md->streams[call->main_video_stream_index].multicast_role = SalMulticastSender; - } - - subject=linphone_call_params_get_session_name(params); - - linphone_core_adapt_to_network(lc,call->ping_time,params); - - if (call->dest_proxy) { - addr=linphone_address_clone(linphone_proxy_config_get_identity_address(call->dest_proxy)); - } else { - addr=linphone_address_new(linphone_core_get_identity(lc)); - } - - md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff)); - md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff)); - md->nb_streams=(call->biggestdesc ? call->biggestdesc->nb_streams : 1); - - /*re-check local ip address each time we make a new offer, because it may change in case of network reconnection*/ - linphone_call_get_local_ip(call, call->dir == LinphoneCallOutgoing ? call->log->to : call->log->from); - strncpy(md->addr,call->media_localip,sizeof(md->addr)); - if (linphone_address_get_username(addr)) /*might be null in case of identity without userinfo*/ - strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username)); - if (subject) strncpy(md->name,subject,sizeof(md->name)); - - if (linphone_call_params_get_down_bandwidth(params)) - md->bandwidth=linphone_call_params_get_down_bandwidth(params); - else md->bandwidth=linphone_core_get_download_bandwidth(lc); - - if (linphone_call_params_get_custom_sdp_attributes(params)) - md->custom_sdp_attributes = sal_custom_sdp_attribute_clone(linphone_call_params_get_custom_sdp_attributes(params)); - - /*set audio capabilities */ - - codec_hints.bandwidth_limit=linphone_call_params_get_audio_bandwidth_limit(params); - codec_hints.max_codecs=-1; - codec_hints.previously_used=old_md ? old_md->streams[call->main_audio_stream_index].already_assigned_payloads : NULL; - l=make_codec_list(lc, &codec_hints, SalAudio, lc->codecs_conf.audio_codecs); - - if (linphone_call_params_audio_enabled(params) && l != NULL) { - strncpy(md->streams[call->main_audio_stream_index].rtp_addr,linphone_call_get_public_ip_for_stream(call,call->main_audio_stream_index),sizeof(md->streams[call->main_audio_stream_index].rtp_addr)); - strncpy(md->streams[call->main_audio_stream_index].rtcp_addr,linphone_call_get_public_ip_for_stream(call,call->main_audio_stream_index),sizeof(md->streams[call->main_audio_stream_index].rtcp_addr)); - strncpy(md->streams[call->main_audio_stream_index].name,"Audio",sizeof(md->streams[call->main_audio_stream_index].name)-1); - md->streams[call->main_audio_stream_index].rtp_port=call->media_ports[call->main_audio_stream_index].rtp_port; - md->streams[call->main_audio_stream_index].rtcp_port=call->media_ports[call->main_audio_stream_index].rtcp_port; - md->streams[call->main_audio_stream_index].proto=get_proto_from_call_params(params); - md->streams[call->main_audio_stream_index].dir=get_audio_dir_from_call_params(params); - md->streams[call->main_audio_stream_index].type=SalAudio; - md->streams[call->main_audio_stream_index].rtcp_mux = rtcp_mux; - if (linphone_call_params_get_down_ptime(params)) - md->streams[call->main_audio_stream_index].ptime=linphone_call_params_get_down_ptime(params); - else - md->streams[call->main_audio_stream_index].ptime=linphone_core_get_download_ptime(lc); - md->streams[call->main_audio_stream_index].max_rate=get_max_codec_sample_rate(l); - md->streams[call->main_audio_stream_index].payloads=l; - if (call->audiostream && call->audiostream->ms.sessions.rtp_session) { - char* me = linphone_address_as_string_uri_only(call->me); - md->streams[call->main_audio_stream_index].rtp_ssrc=rtp_session_get_send_ssrc(call->audiostream->ms.sessions.rtp_session); - strncpy(md->streams[call->main_audio_stream_index].rtcp_cname,me,sizeof(md->streams[call->main_audio_stream_index].rtcp_cname)); - ms_free(me); - } - else - ms_warning("Cannot get audio local ssrc for call [%p]",call); - if (call->main_audio_stream_index > max_index) - max_index = call->main_audio_stream_index; - } else { - ms_message("Don't put audio stream on local offer for call [%p]",call); - md->streams[call->main_audio_stream_index].dir = SalStreamInactive; - if(l) l=bctbx_list_free_with_data(l, (void (*)(void *))payload_type_destroy); - } - if (linphone_call_params_get_custom_sdp_media_attributes(params, LinphoneStreamTypeAudio)) - md->streams[call->main_audio_stream_index].custom_sdp_attributes = sal_custom_sdp_attribute_clone(linphone_call_params_get_custom_sdp_media_attributes(params, LinphoneStreamTypeAudio)); - - md->streams[call->main_video_stream_index].proto=md->streams[call->main_audio_stream_index].proto; - md->streams[call->main_video_stream_index].dir=get_video_dir_from_call_params(params); - md->streams[call->main_video_stream_index].type=SalVideo; - md->streams[call->main_video_stream_index].rtcp_mux = rtcp_mux; - strncpy(md->streams[call->main_video_stream_index].name,"Video",sizeof(md->streams[call->main_video_stream_index].name)-1); - - codec_hints.bandwidth_limit=0; - codec_hints.max_codecs=-1; - codec_hints.previously_used=old_md ? old_md->streams[call->main_video_stream_index].already_assigned_payloads : NULL; - l=make_codec_list(lc, &codec_hints, SalVideo, lc->codecs_conf.video_codecs); - - if (linphone_call_params_video_enabled(params) && l != NULL){ - strncpy(md->streams[call->main_video_stream_index].rtp_addr,linphone_call_get_public_ip_for_stream(call,call->main_video_stream_index),sizeof(md->streams[call->main_video_stream_index].rtp_addr)); - strncpy(md->streams[call->main_video_stream_index].rtcp_addr,linphone_call_get_public_ip_for_stream(call,call->main_video_stream_index),sizeof(md->streams[call->main_video_stream_index].rtcp_addr)); - md->streams[call->main_video_stream_index].rtp_port=call->media_ports[call->main_video_stream_index].rtp_port; - md->streams[call->main_video_stream_index].rtcp_port=call->media_ports[call->main_video_stream_index].rtcp_port; - md->streams[call->main_video_stream_index].payloads=l; - if (call->videostream && call->videostream->ms.sessions.rtp_session) { - char* me = linphone_address_as_string_uri_only(call->me); - md->streams[call->main_video_stream_index].rtp_ssrc=rtp_session_get_send_ssrc(call->videostream->ms.sessions.rtp_session); - strncpy(md->streams[call->main_video_stream_index].rtcp_cname,me,sizeof(md->streams[call->main_video_stream_index].rtcp_cname)); - ms_free(me); - } - else - ms_warning("Cannot get video local ssrc for call [%p]",call); - if (call->main_video_stream_index > max_index) - max_index = call->main_video_stream_index; - } else { - ms_message("Don't put video stream on local offer for call [%p]",call); - md->streams[call->main_video_stream_index].dir = SalStreamInactive; - if(l) l=bctbx_list_free_with_data(l, (void (*)(void *))payload_type_destroy); - } - if (linphone_call_params_get_custom_sdp_media_attributes(params, LinphoneStreamTypeVideo)) - md->streams[call->main_video_stream_index].custom_sdp_attributes = sal_custom_sdp_attribute_clone(linphone_call_params_get_custom_sdp_media_attributes(params, LinphoneStreamTypeVideo)); - - md->streams[call->main_text_stream_index].proto=md->streams[call->main_audio_stream_index].proto; - md->streams[call->main_text_stream_index].dir=SalStreamSendRecv; - md->streams[call->main_text_stream_index].type=SalText; - md->streams[call->main_text_stream_index].rtcp_mux = rtcp_mux; - strncpy(md->streams[call->main_text_stream_index].name,"Text",sizeof(md->streams[call->main_text_stream_index].name)-1); - if (linphone_call_params_realtime_text_enabled(params)) { - strncpy(md->streams[call->main_text_stream_index].rtp_addr,linphone_call_get_public_ip_for_stream(call,call->main_text_stream_index),sizeof(md->streams[call->main_text_stream_index].rtp_addr)); - strncpy(md->streams[call->main_text_stream_index].rtcp_addr,linphone_call_get_public_ip_for_stream(call,call->main_text_stream_index),sizeof(md->streams[call->main_text_stream_index].rtcp_addr)); - - md->streams[call->main_text_stream_index].rtp_port=call->media_ports[call->main_text_stream_index].rtp_port; - md->streams[call->main_text_stream_index].rtcp_port=call->media_ports[call->main_text_stream_index].rtcp_port; - - codec_hints.bandwidth_limit=0; - codec_hints.max_codecs=-1; - codec_hints.previously_used=old_md ? old_md->streams[call->main_text_stream_index].already_assigned_payloads : NULL; - l=make_codec_list(lc, &codec_hints, SalText, lc->codecs_conf.text_codecs); - md->streams[call->main_text_stream_index].payloads=l; - if (call->textstream && call->textstream->ms.sessions.rtp_session) { - char* me = linphone_address_as_string_uri_only(call->me); - md->streams[call->main_text_stream_index].rtp_ssrc=rtp_session_get_send_ssrc(call->textstream->ms.sessions.rtp_session); - strncpy(md->streams[call->main_text_stream_index].rtcp_cname,me,sizeof(md->streams[call->main_text_stream_index].rtcp_cname)); - ms_free(me); - } - else - ms_warning("Cannot get text local ssrc for call [%p]",call); - if (call->main_text_stream_index > max_index) - max_index = call->main_text_stream_index; - } else { - ms_message("Don't put text stream on local offer for call [%p]",call); - md->streams[call->main_text_stream_index].dir = SalStreamInactive; - } - if (linphone_call_params_get_custom_sdp_media_attributes(params, LinphoneStreamTypeText)) - md->streams[call->main_text_stream_index].custom_sdp_attributes = sal_custom_sdp_attribute_clone(linphone_call_params_get_custom_sdp_media_attributes(params, LinphoneStreamTypeText)); - - md->nb_streams = MAX(md->nb_streams,max_index+1); - - /* Deactivate unused streams. */ - for (i = md->nb_streams; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { - if (md->streams[i].rtp_port == 0) { - md->streams[i].dir = SalStreamInactive; - if (call->biggestdesc && i < call->biggestdesc->nb_streams) { - md->streams[i].proto = call->biggestdesc->streams[i].proto; - md->streams[i].type = call->biggestdesc->streams[i].type; - } - } - } - setup_encryption_keys(call,md); - setup_dtls_keys(call,md); - setup_zrtp_hash(call, md); - - setup_rtcp_fb(call, md); - setup_rtcp_xr(call, md); - - update_media_description_from_stun(md, &call->ac, &call->vc, &call->tc); - call->localdesc=md; - linphone_call_update_local_media_description_from_ice_or_upnp(call); - linphone_address_unref(addr); - if (old_md){ - transfer_already_assigned_payload_types(old_md,md); - call->localdesc_changed=sal_media_description_equals(md,old_md); - sal_media_description_unref(old_md); - if (linphone_call_params_get_internal_call_update(call->params)){ - /* - * An internal call update (ICE reINVITE) is not expected to modify the actual media stream parameters. - * However, the localdesc may change between first INVITE and ICE reINVITE, for example if the remote party has declined a video stream. - * We use the internal_call_update flag to prevent trigger an unnecessary media restart. - */ - call->localdesc_changed = 0; - } - } - force_streams_dir_according_to_state(call, md); -} - -static int find_port_offset(LinphoneCore *lc, int stream_index, int base_port){ - int offset; - bctbx_list_t *elem; - int tried_port; - int existing_port; - bool_t already_used=FALSE; - - for(offset=0;offset<100;offset+=2){ - tried_port=base_port+offset; - already_used=FALSE; - for(elem=lc->calls;elem!=NULL;elem=elem->next){ - LinphoneCall *call=(LinphoneCall*)elem->data; - existing_port=call->media_ports[stream_index].rtp_port; - if (existing_port==tried_port) { - already_used=TRUE; - break; - } - } - if (!already_used) break; - } - if (offset==100){ - ms_error("Could not find any free port !"); - return -1; - } - return offset; -} - -static int select_random_port(LinphoneCore *lc, int stream_index, int min_port, int max_port) { - bctbx_list_t *elem; - int nb_tries; - int tried_port = 0; - int existing_port = 0; - bool_t already_used = FALSE; - - tried_port = (ortp_random() % (max_port - min_port) + min_port) & ~0x1; - if (tried_port < min_port) tried_port = min_port + 2; - for (nb_tries = 0; nb_tries < 100; nb_tries++) { - for (elem = lc->calls; elem != NULL; elem = elem->next) { - LinphoneCall *call = (LinphoneCall *)elem->data; - existing_port=call->media_ports[stream_index].rtp_port; - if (existing_port == tried_port) { - already_used = TRUE; - break; - } - } - if (!already_used) break; - } - if (nb_tries == 100) { - ms_error("Could not find any free port!"); - return -1; - } - return tried_port; -} - -static void port_config_set_random(LinphoneCall *call, int stream_index){ - call->media_ports[stream_index].rtp_port=-1; - call->media_ports[stream_index].rtcp_port=-1; -} - -static void port_config_set(LinphoneCall *call, int stream_index, int min_port, int max_port){ - int port_offset; - if (min_port>0 && max_port>0){ - if (min_port == max_port) { - /* Used fixed RTP audio port. */ - port_offset=find_port_offset(call->core, stream_index, min_port); - if (port_offset==-1) { - port_config_set_random(call, stream_index); - return; - } - call->media_ports[stream_index].rtp_port=min_port+port_offset; - } else { - /* Select random RTP audio port in the specified range. */ - call->media_ports[stream_index].rtp_port = select_random_port(call->core, stream_index, min_port, max_port); - } - call->media_ports[stream_index].rtcp_port=call->media_ports[stream_index].rtp_port+1; - }else port_config_set_random(call,stream_index); -} - -static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){ - int min_port, max_port; - ms_message("New LinphoneCall [%p] initialized (LinphoneCore version: %s)",call,linphone_core_get_version()); - call->ei = linphone_error_info_new(); - call->core->send_call_stats_periodical_updates = lp_config_get_int(call->core->config, "misc", "send_call_stats_periodical_updates", 0); - call->main_audio_stream_index = LINPHONE_CALL_STATS_AUDIO; - call->main_video_stream_index = LINPHONE_CALL_STATS_VIDEO; - call->main_text_stream_index = LINPHONE_CALL_STATS_TEXT; - call->state=LinphoneCallIdle; - call->transfer_state = LinphoneCallIdle; - call->log=linphone_call_log_new(call->dir, from, to); - call->camera_enabled=TRUE; - call->current_params = linphone_call_params_new(); - linphone_call_params_set_media_encryption(call->current_params, LinphoneMediaEncryptionNone); - call->dtls_certificate_fingerprint = NULL; - if (call->dir == LinphoneCallIncoming) - call->me=to; - else - call->me=from; - linphone_address_ref(call->me); - - linphone_core_get_audio_port_range(call->core, &min_port, &max_port); - port_config_set(call,call->main_audio_stream_index,min_port,max_port); - - linphone_core_get_video_port_range(call->core, &min_port, &max_port); - port_config_set(call,call->main_video_stream_index,min_port,max_port); - - linphone_core_get_text_port_range(call->core, &min_port, &max_port); - port_config_set(call,call->main_text_stream_index,min_port,max_port); - - linphone_call_init_stats(call->audio_stats, LinphoneStreamTypeAudio); - linphone_call_init_stats(call->video_stats, LinphoneStreamTypeVideo); - linphone_call_init_stats(call->text_stats, LinphoneStreamTypeText); - - if (call->dest_proxy == NULL) { - /* Try to define the destination proxy if it has not already been done to have a correct contact field in the SIP messages */ - call->dest_proxy = linphone_core_lookup_known_proxy(call->core, call->log->to); - } - - - if (call->dest_proxy != NULL) - call->nat_policy = linphone_proxy_config_get_nat_policy(call->dest_proxy); - if (call->nat_policy == NULL) - call->nat_policy = linphone_core_get_nat_policy(call->core); - - linphone_nat_policy_ref(call->nat_policy); - -} - -void linphone_call_init_stats(LinphoneCallStats *stats, LinphoneStreamType type) { - stats->type = type; - stats->received_rtcp = NULL; - stats->sent_rtcp = NULL; - stats->ice_state = LinphoneIceStateNotActivated; -#ifdef BUILD_UPNP - stats->upnp_state = LinphoneUpnpStateIdle; -#else - stats->upnp_state = LinphoneUpnpStateNotAvailable; -#endif //BUILD_UPNP -} - -static void discover_mtu(LinphoneCore *lc, const char *remote){ - int mtu; - if (lc->net_conf.mtu==0 ){ - /*attempt to discover mtu*/ - mtu=ms_discover_mtu(remote); - if (mtu>0){ - ms_factory_set_mtu(lc->factory, mtu); - ms_message("Discovered mtu is %i, RTP payload max size is %i", - mtu, ms_factory_get_payload_max_size(lc->factory)); - } - } -} - -void linphone_call_create_op_to(LinphoneCall *call, LinphoneAddress *to){ - if (call->op) sal_op_release(call->op); - call->op=sal_op_new(call->core->sal); - sal_op_set_user_pointer(call->op,call); - if (linphone_call_params_get_referer(call->params)) - sal_call_set_referer(call->op,linphone_call_params_get_referer(call->params)->op); - linphone_configure_op(call->core,call->op,to,linphone_call_params_get_custom_headers(call->params),FALSE); - if (linphone_call_params_get_privacy(call->params) != LinphonePrivacyDefault) - sal_op_set_privacy(call->op,(SalPrivacyMask)linphone_call_params_get_privacy(call->params)); - /*else privacy might be set by proxy */ } void linphone_call_create_op(LinphoneCall *call){ +#if 0 if (call->op) sal_op_release(call->op); call->op=sal_op_new(call->core->sal); sal_op_set_user_pointer(call->op,call); @@ -1193,113 +269,7 @@ void linphone_call_create_op(LinphoneCall *call){ if (linphone_call_params_get_privacy(call->params) != LinphonePrivacyDefault) sal_op_set_privacy(call->op,(SalPrivacyMask)linphone_call_params_get_privacy(call->params)); /*else privacy might be set by proxy */ -} - -/* - * Choose IP version we are going to use for RTP streams IP address advertised in SDP. - * The algorithm is as follows: - * - if ipv6 is disabled at the core level, it is always AF_INET - * - Otherwise, if the destination address for the call is an IPv6 address, use IPv6. - * - Otherwise, if the call is done through a known proxy config, then use the information obtained during REGISTER - * to know if IPv6 is supported by the server. -**/ -static void linphone_call_outgoing_select_ip_version(LinphoneCall *call, LinphoneAddress *to, LinphoneProxyConfig *cfg){ - if (linphone_core_ipv6_enabled(call->core)){ - if (sal_address_is_ipv6(L_GET_PRIVATE_FROM_C_STRUCT(to, Address)->getInternalAddress())) { - call->af=AF_INET6; - }else if (cfg && cfg->op){ - call->af=sal_op_get_address_family(cfg->op); - }else{ - call->af=AF_UNSPEC; - } - if (call->af == AF_UNSPEC) { - char ipv4[LINPHONE_IPADDR_SIZE]; - char ipv6[LINPHONE_IPADDR_SIZE]; - bool_t have_ipv6 = FALSE; - bool_t have_ipv4 = FALSE; - /*check connectivity for IPv4 and IPv6*/ - if (linphone_core_get_local_ip_for(AF_INET6, NULL, ipv6) == 0){ - have_ipv6 = TRUE; - } - if (linphone_core_get_local_ip_for(AF_INET, NULL, ipv4) == 0){ - have_ipv4 = TRUE; - } - if (have_ipv6){ - if (!have_ipv4) { - call->af = AF_INET6; - }else if (lp_config_get_int(call->core->config, "rtp", "prefer_ipv6", 1)){ /*this property tells whether ipv6 is prefered if two versions are available*/ - call->af = AF_INET6; - }else{ - call->af = AF_INET; - } - }else call->af = AF_INET; - /*fill the media_localip default value since we have it here*/ - strncpy(call->media_localip,call->af == AF_INET6 ? ipv6 : ipv4, LINPHONE_IPADDR_SIZE); - } - }else call->af=AF_INET; -} - -/** - * Fill the local ip that routes to the internet according to the destination, or guess it by other special means (upnp). - */ -static void linphone_call_get_local_ip(LinphoneCall *call, const LinphoneAddress *remote_addr){ - const char *ip = NULL; - int af = call->af; - const char *dest = NULL; - - if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseNatAddress - && (ip=linphone_core_get_nat_address_resolved(call->core))!=NULL){ - strncpy(call->media_localip,ip,LINPHONE_IPADDR_SIZE); - return; - } -#ifdef BUILD_UPNP - else if (call->core->upnp != NULL && linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseUpnp && - linphone_upnp_context_get_state(call->core->upnp) == LinphoneUpnpStateOk) { - ip = linphone_upnp_context_get_external_ipaddress(call->core->upnp); - strncpy(call->media_localip,ip,LINPHONE_IPADDR_SIZE); - goto found; - } -#endif //BUILD_UPNP - - /*next, sometime, override from config*/ - if ((ip=lp_config_get_string(call->core->config,"rtp","bind_address",NULL)) != NULL) - goto found; - - /*if a known proxy was identified for this call, then we may have a chance to take the local ip address - * from the socket that connect to this proxy */ - if (call->dest_proxy && call->dest_proxy->op){ - if ((ip = sal_op_get_local_address(call->dest_proxy->op, NULL)) != NULL){ - ms_message("Found media local-ip from signaling."); - goto found; - } - } - - /*in last resort, attempt to find the local ip that routes to destination if given as an IP address, - or the default route (dest=NULL)*/ - if (call->dest_proxy == NULL) { - struct addrinfo hints; - struct addrinfo *res = NULL; - int err; - /*FIXME the following doesn't work for IPv6 address because of brakets*/ - const char *domain = linphone_address_get_domain(remote_addr); - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_NUMERICHOST; - err = getaddrinfo(domain, NULL, &hints, &res); - if (err == 0) { - dest = domain; - } - if (res != NULL) freeaddrinfo(res); - } - - if (dest != NULL || call->media_localip[0] == '\0' || call->need_localip_refresh){ - call->need_localip_refresh = FALSE; - linphone_core_get_local_ip(call->core, af, dest, call->media_localip); - } - return; -found: - strncpy(call->media_localip,ip,LINPHONE_IPADDR_SIZE); +#endif } static void linphone_call_destroy(LinphoneCall *obj); @@ -1313,466 +283,28 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneCall, belle_sip_object_t, FALSE ); -void linphone_call_fill_media_multicast_addr(LinphoneCall *call) { - if (linphone_call_params_audio_multicast_enabled(call->params)){ - strncpy(call->media_ports[call->main_audio_stream_index].multicast_ip, - linphone_core_get_audio_multicast_addr(call->core), sizeof(call->media_ports[call->main_audio_stream_index].multicast_ip)); - } else - call->media_ports[call->main_audio_stream_index].multicast_ip[0]='\0'; - - if (linphone_call_params_video_multicast_enabled(call->params)){ - strncpy(call->media_ports[call->main_video_stream_index].multicast_ip, - linphone_core_get_video_multicast_addr(call->core), sizeof(call->media_ports[call->main_video_stream_index].multicast_ip)); - } else - call->media_ports[call->main_video_stream_index].multicast_ip[0]='\0'; -} - -void linphone_call_check_ice_session(LinphoneCall *call, IceRole role, bool_t is_reinvite){ - if (call->ice_session) return; /*already created*/ - - if (!linphone_nat_policy_ice_enabled(call->nat_policy)){ - return; - } - - if (is_reinvite && lp_config_get_int(call->core->config, "net", "allow_late_ice", 0) == 0) return; - - call->ice_session = ice_session_new(); - /*for backward compatibility purposes, shall be enabled by default in futur*/ - ice_session_enable_message_integrity_check(call->ice_session,lp_config_get_int(call->core->config,"net","ice_session_enable_message_integrity_check",1)); - if (lp_config_get_int(call->core->config, "net", "dont_default_to_stun_candidates", 0)){ - IceCandidateType types[ICT_CandidateTypeMax]; - types[0] = ICT_HostCandidate; - types[1] = ICT_RelayedCandidate; - types[2] = ICT_CandidateInvalid; - ice_session_set_default_candidates_types(call->ice_session, types); - } - ice_session_set_role(call->ice_session, role); -} - -LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){ +LinphoneCall * linphone_call_new_outgoing(LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){ LinphoneCall *call = belle_sip_object_new(LinphoneCall); - call->dir=LinphoneCallOutgoing; - call->core=lc; - call->dest_proxy=cfg; - call->audio_stats = linphone_call_stats_ref(linphone_call_stats_new()); - call->video_stats = linphone_call_stats_ref(linphone_call_stats_new()); - call->text_stats = linphone_call_stats_ref(linphone_call_stats_new()); - linphone_call_outgoing_select_ip_version(call,to,cfg); - linphone_call_get_local_ip(call, to); - call->params = linphone_call_params_copy(params); - linphone_call_init_common(call, from, to); - - linphone_call_params_set_update_call_when_ice_completed(call->current_params, linphone_call_params_get_update_call_when_ice_completed(call->params)); /*copy param*/ - - linphone_call_fill_media_multicast_addr(call); - - linphone_call_check_ice_session(call, IR_Controlling, FALSE); - - if (linphone_nat_policy_stun_enabled(call->nat_policy) && !(linphone_nat_policy_ice_enabled(call->nat_policy) - || linphone_nat_policy_turn_enabled(call->nat_policy))) { - call->ping_time=linphone_core_run_stun_tests(call->core,call); - } -#ifdef BUILD_UPNP - if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) { - if(!lc->rtp_conf.disable_upnp) { - call->upnp_session = linphone_upnp_session_new(call); - } - } -#endif //BUILD_UPNP - - discover_mtu(lc,linphone_address_get_domain (to)); - if (linphone_call_params_get_referer(params)){ - call->referer=linphone_call_ref(linphone_call_params_get_referer(params)); - } - - linphone_call_create_op_to(call, to); + call->currentParamsCache = linphone_call_params_new_for_wrapper(); + call->paramsCache = linphone_call_params_new_for_wrapper(); + call->remoteParamsCache = linphone_call_params_new_for_wrapper(); + call->remoteAddressCache = linphone_address_new(nullptr); + call->call = std::make_shared(call, lc, LinphoneCallOutgoing, *L_GET_CPP_PTR_FROM_C_STRUCT(from, Address), *L_GET_CPP_PTR_FROM_C_STRUCT(to, Address), cfg, nullptr, linphone_call_params_get_cpp_obj(params)); return call; } -/*Select IP version to use for advertising local addresses of RTP streams, for an incoming call. - *If the call is received through a know proxy that is IPv6, use IPv6. - *Otherwise check the remote contact address. - *If later the resulting media description tells that we have to send IPv4, it won't be a problem because the RTP sockets - * are dual stack. - */ -static void linphone_call_incoming_select_ip_version(LinphoneCall *call, LinphoneProxyConfig *cfg){ - if (linphone_core_ipv6_enabled(call->core)){ - if (cfg && cfg->op){ - call->af=sal_op_get_address_family(cfg->op); - }else{ - call->af=sal_op_get_address_family(call->op); - } - }else call->af=AF_INET; -} - -/** - * Fix call parameters on incoming call to eg. enable AVPF if the incoming call propose it and it is not enabled locally. - */ -void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, SalMediaDescription *md) { - /* Handle AVPF, SRTP and DTLS. */ - linphone_call_params_enable_avpf(call->params, sal_media_description_has_avpf(md)); - if (call->dest_proxy != NULL) { - linphone_call_params_set_avpf_rr_interval(call->params, linphone_proxy_config_get_avpf_rr_interval(call->dest_proxy) * 1000); - } else { - linphone_call_params_set_avpf_rr_interval(call->params, linphone_core_get_avpf_rr_interval(call->core)*1000); - } - - if ((sal_media_description_has_zrtp(md) == TRUE) && (linphone_core_media_encryption_supported(call->core, LinphoneMediaEncryptionZRTP) == TRUE)) { - linphone_call_params_set_media_encryption(call->params, LinphoneMediaEncryptionZRTP); - }else if ((sal_media_description_has_dtls(md) == TRUE) && (media_stream_dtls_supported() == TRUE)) { - linphone_call_params_set_media_encryption(call->params, LinphoneMediaEncryptionDTLS); - }else if ((sal_media_description_has_srtp(md) == TRUE) && (ms_srtp_supported() == TRUE)) { - linphone_call_params_set_media_encryption(call->params, LinphoneMediaEncryptionSRTP); - }else if (linphone_call_params_get_media_encryption(call->params) != LinphoneMediaEncryptionZRTP){ - linphone_call_params_set_media_encryption(call->params, LinphoneMediaEncryptionNone); - } - - /*in case of nat64, even ipv4 addresses are reachable from v6. Should be enhanced to manage stream by stream connectivity (I.E v6 or v4)*/ - /*if (!sal_media_description_has_ipv6(md)){ - ms_message("The remote SDP doesn't seem to offer any IPv6 connectivity, so disabling IPv6 for this call."); - call->af = AF_INET; - }*/ - linphone_call_fix_call_parameters(call, md); -} - -static void linphone_call_compute_streams_indexes(LinphoneCall *call, const SalMediaDescription *md) { - int i, j; - bool_t audio_found = FALSE, video_found = FALSE, text_found = FALSE; - - for (i = 0; i < md->nb_streams; i++) { - if (md->streams[i].type == SalAudio) { - if (!audio_found) { - call->main_audio_stream_index = i; - audio_found = TRUE; - ms_message("audio stream index found: %i, updating main audio stream index", i); - } else { - ms_message("audio stream index found: %i, but main audio stream already set to %i", i, call->main_audio_stream_index); - } - - // Check that the default value of a another stream doesn't match the new one - if (i == call->main_video_stream_index) { - for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { - if (sal_stream_description_active(&md->streams[j])) continue; - if (j != call->main_video_stream_index && j != call->main_text_stream_index) { - ms_message("%i was used for video stream ; now using %i", i, j); - call->main_video_stream_index = j; - break; - } - } - } - if (i == call->main_text_stream_index) { - for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { - if (sal_stream_description_active(&md->streams[j])) continue; - if (j != call->main_video_stream_index && j != call->main_text_stream_index) { - ms_message("%i was used for text stream ; now using %i", i, j); - call->main_text_stream_index = j; - break; - } - } - } - } else if (md->streams[i].type == SalVideo) { - if (!video_found) { - call->main_video_stream_index = i; - video_found = TRUE; - ms_message("video stream index found: %i, updating main video stream index", i); - } else { - ms_message("video stream index found: %i, but main video stream already set to %i", i, call->main_video_stream_index); - } - - // Check that the default value of a another stream doesn't match the new one - if (i == call->main_audio_stream_index) { - for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { - if (sal_stream_description_active(&md->streams[j])) continue; - if (j != call->main_audio_stream_index && j != call->main_text_stream_index) { - ms_message("%i was used for audio stream ; now using %i", i, j); - call->main_audio_stream_index = j; - break; - } - } - } - if (i == call->main_text_stream_index) { - for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { - if (sal_stream_description_active(&md->streams[j])) continue; - if (j != call->main_audio_stream_index && j != call->main_text_stream_index) { - ms_message("%i was used for text stream ; now using %i", i, j); - call->main_text_stream_index = j; - break; - } - } - } - } else if (md->streams[i].type == SalText) { - if (!text_found) { - call->main_text_stream_index = i; - text_found = TRUE; - ms_message("text stream index found: %i, updating main text stream index", i); - } else { - ms_message("text stream index found: %i, but main text stream already set to %i", i, call->main_text_stream_index); - } - - // Check that the default value of a another stream doesn't match the new one - if (i == call->main_audio_stream_index) { - for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { - if (sal_stream_description_active(&md->streams[j])) continue; - if (j != call->main_video_stream_index && j != call->main_audio_stream_index) { - ms_message("%i was used for audio stream ; now using %i", i, j); - call->main_audio_stream_index = j; - break; - } - } - } - if (i == call->main_video_stream_index) { - for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { - if (sal_stream_description_active(&md->streams[j])) continue; - if (j != call->main_video_stream_index && j != call->main_audio_stream_index) { - ms_message("%i was used for video stream ; now using %i", i, j); - call->main_video_stream_index = j; - break; - } - } - } - } - } -} - -LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){ +LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, SalOp *op) { LinphoneCall *call = belle_sip_object_new(LinphoneCall); - SalMediaDescription *md; - LinphoneNatPolicy *nat_policy = NULL; - int i; - call->dir=LinphoneCallIncoming; - call->audio_stats = linphone_call_stats_ref(linphone_call_stats_new()); - call->video_stats = linphone_call_stats_ref(linphone_call_stats_new()); - call->text_stats = linphone_call_stats_ref(linphone_call_stats_new()); - sal_op_set_user_pointer(op,call); - call->op=op; - call->core=lc; - - call->dest_proxy = linphone_core_lookup_known_proxy(call->core, to); - linphone_call_incoming_select_ip_version(call, call->dest_proxy); - /*note that the choice of IP version for streams is later refined by - * linphone_call_set_compatible_incoming_call_parameters() when examining the remote offer, if any. - * If the remote offer contains IPv4 addresses, we should propose IPv4 as well*/ - - sal_op_cnx_ip_to_0000_if_sendonly_enable(op,lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0)); - - md = sal_call_get_remote_media_description(op); - - if (lc->sip_conf.ping_with_options){ -#ifdef BUILD_UPNP - if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp && - linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) { -#else //BUILD_UPNP - { -#endif //BUILD_UPNP - /*the following sends an option request back to the caller so that - we get a chance to discover our nat'd address before answering.*/ - call->ping_op=sal_op_new(lc->sal); - - linphone_configure_op(lc, call->ping_op, from, NULL, FALSE); - - sal_op_set_route(call->ping_op,sal_op_get_network_origin(op)); - sal_op_set_user_pointer(call->ping_op,call); - - sal_ping(call->ping_op,sal_op_get_from(call->ping_op), sal_op_get_to(call->ping_op)); - } - } - - linphone_address_clean(from); - linphone_call_get_local_ip(call, from); - call->params = linphone_call_params_new(); - linphone_call_init_common(call, from, to); - call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/ - linphone_core_init_default_params(lc, call->params); - - /* - * Initialize call parameters according to incoming call parameters. This is to avoid to ask later (during reINVITEs) for features that the remote - * end apparently does not support. This features are: privacy, video - */ - /*set privacy*/ - linphone_call_params_set_privacy(call->current_params, (LinphonePrivacyMask)sal_op_get_privacy(call->op)); - /*config params*/ - linphone_call_params_set_update_call_when_ice_completed(call->current_params, linphone_call_params_get_update_call_when_ice_completed(call->params)); /*copy config params*/ - - /*set video support */ - linphone_call_params_enable_video(call->params, linphone_core_video_enabled(lc) && lc->video_policy.automatically_accept); - if (md) { - // It is licit to receive an INVITE without SDP - // In this case WE chose the media parameters according to policy. - linphone_call_set_compatible_incoming_call_parameters(call, md); - /* set multicast role & address if any*/ - if (!sal_call_is_offerer(op)){ - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { - if (md->streams[i].dir == SalStreamInactive) { - continue; - } - - if (md->streams[i].rtp_addr[0]!='\0' && ms_is_multicast(md->streams[i].rtp_addr)){ - md->streams[i].multicast_role = SalMulticastReceiver; - strncpy(call->media_ports[i].multicast_ip,md->streams[i].rtp_addr,sizeof(call->media_ports[i].multicast_ip)); - } - } - } - } - - nat_policy=call->nat_policy; - if ((nat_policy != NULL) && linphone_nat_policy_ice_enabled(nat_policy)) { - /* Create the ice session now if ICE is required */ - if (md){ - linphone_call_check_ice_session(call, IR_Controlled, FALSE); - }else{ - nat_policy = NULL; - ms_warning("ICE not supported for incoming INVITE without SDP."); - } - } - - /*reserve the sockets immediately*/ - linphone_call_init_media_streams(call); - if (nat_policy != NULL) { - if (linphone_nat_policy_ice_enabled(nat_policy)) { - call->defer_notify_incoming = linphone_call_prepare_ice(call,TRUE) == 1; - } else if (linphone_nat_policy_stun_enabled(nat_policy)) { - call->ping_time=linphone_core_run_stun_tests(call->core,call); - } else if (linphone_nat_policy_upnp_enabled(nat_policy)) { -#ifdef BUILD_UPNP - if(!lc->rtp_conf.disable_upnp) { - call->upnp_session = linphone_upnp_session_new(call); - if (call->upnp_session != NULL) { - if (linphone_call_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) { - /* uPnP port mappings failed, proceed with the call anyway. */ - linphone_call_delete_upnp_session(call); - } - } - } -#endif //BUILD_UPNP - } - } - - discover_mtu(lc,linphone_address_get_domain(from)); + call->currentParamsCache = linphone_call_params_new_for_wrapper(); + call->paramsCache = linphone_call_params_new_for_wrapper(); + call->remoteParamsCache = linphone_call_params_new_for_wrapper(); + call->remoteAddressCache = linphone_address_new(nullptr); + call->call = std::make_shared(call, lc, LinphoneCallIncoming, *L_GET_CPP_PTR_FROM_C_STRUCT(from, Address), *L_GET_CPP_PTR_FROM_C_STRUCT(to, Address), nullptr, op, nullptr); + L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->initiateIncoming(); return call; } -/* - * Frees the media resources of the call. - * This has to be done at the earliest, unlike signaling resources that sometimes need to be kept a bit more longer. - * It is called by linphone_call_set_terminated() (for termination of calls signaled to the application), or directly by the destructor of LinphoneCall - * (_linphone_call_destroy) if the call was never notified to the application. - */ static void linphone_call_free_media_resources(LinphoneCall *call){ - int i; - - linphone_call_stop_media_streams(call); - linphone_call_delete_upnp_session(call); - linphone_call_delete_ice_session(call); - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i){ - ms_media_stream_sessions_uninit(&call->sessions[i]); - } - linphone_call_stats_uninit(call->audio_stats); - linphone_call_stats_uninit(call->video_stats); - linphone_call_stats_uninit(call->text_stats); -} - -/* - * Called internally when reaching the Released state, to perform cleanups to break circular references. -**/ -static void linphone_call_set_released(LinphoneCall *call){ - if (call->op!=NULL) { - /*transfer the last error so that it can be obtained even in Released state*/ - if (!call->non_op_error){ - linphone_error_info_from_sal_op(call->ei, call->op); - } - /* so that we cannot have anymore upcalls for SAL - concerning this call*/ - sal_op_release(call->op); - call->op=NULL; - } - /*it is necessary to reset pointers to other call to prevent circular references that would result in memory never freed.*/ - if (call->referer){ - linphone_call_unref(call->referer); - call->referer=NULL; - } - if (call->transfer_target){ - linphone_call_unref(call->transfer_target); - call->transfer_target=NULL; - } - if (call->chat_room){ - linphone_chat_room_unref(call->chat_room); - call->chat_room = NULL; - } - linphone_call_unref(call); -} - -/* this function is called internally to get rid of a call that was notified to the application, because it reached the end or error state. - It performs the following tasks: - - remove the call from the internal list of calls - - update the call logs accordingly -*/ -static void linphone_call_set_terminated(LinphoneCall *call){ - LinphoneCore *lc=call->core; - - linphone_call_free_media_resources(call); - linphone_call_log_completed(call); - - if (call == lc->current_call){ - ms_message("Resetting the current call"); - lc->current_call=NULL; - } - - if (linphone_core_del_call(lc,call) != 0){ - ms_error("Could not remove the call from the list !!!"); - } - if(lc->conf_ctx) linphone_conference_on_call_terminating(lc->conf_ctx, call); - if (call->ringing_beep){ - linphone_core_stop_dtmf(lc); - call->ringing_beep=FALSE; - } - if (call->chat_room){ - linphone_chat_room_set_call(call->chat_room, NULL); - } - if (lc->calls == NULL){ - ms_bandwidth_controller_reset_state(lc->bw_controller); - } -} - -/*function to be called at each incoming reINVITE, in order to adjust various local parameters to what is being offered by remote: - * - the video enablement parameter according to what is offered and our local policy. - * Fixing the call->params to proper values avoid request video by accident during internal call updates, pauses and resumes - * - the stream indexes. - */ -void linphone_call_fix_call_parameters(LinphoneCall *call, SalMediaDescription *rmd){ - const LinphoneCallParams* rcp; - - if (rmd) { - linphone_call_compute_streams_indexes(call, rmd); - linphone_call_update_biggest_desc(call, rmd); - /* Why disabling implicit_rtcp_fb ? It is a local policy choice actually. It doesn't disturb to propose it again and again - * even if the other end apparently doesn't support it. - * The following line of code is causing trouble, while for example making an audio call, then adding video. - * Due to the 200Ok response of the audio-only offer where no rtcp-fb attribute is present, implicit_rtcp_fb is set to - * FALSE, which is then preventing it to be eventually used when video is later added to the call. - * I did the choice of commenting it out. - */ - /*call->params->implicit_rtcp_fb &= sal_media_description_has_implicit_avpf(rmd);*/ - } - rcp = linphone_call_get_remote_params(call); - if (rcp){ - if (linphone_call_params_audio_enabled(call->params) && !linphone_call_params_audio_enabled(rcp)){ - ms_message("Call [%p]: disabling audio in our call params because the remote doesn't want it.", call); - linphone_call_params_enable_audio(call->params, FALSE); - } - if (linphone_call_params_video_enabled(call->params) && !linphone_call_params_video_enabled(rcp)){ - ms_message("Call [%p]: disabling video in our call params because the remote doesn't want it.", call); - linphone_call_params_enable_video(call->params, FALSE); - } - - if (linphone_call_params_video_enabled(rcp) && call->core->video_policy.automatically_accept && linphone_core_video_enabled(call->core) && !linphone_call_params_video_enabled(call->params)){ - ms_message("Call [%p]: re-enabling video in our call params because the remote wants it and the policy allows to automatically accept.", call); - linphone_call_params_enable_video(call->params, TRUE); - } - - if (linphone_call_params_realtime_text_enabled(rcp) && !linphone_call_params_realtime_text_enabled(call->params)) { - linphone_call_params_enable_realtime_text(call->params, TRUE); - } - } } const char *linphone_call_state_to_string(LinphoneCallState cs){ @@ -1824,134 +356,27 @@ const char *linphone_call_state_to_string(LinphoneCallState cs){ } void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){ - LinphoneCore *lc=call->core; - - if (call->state!=cstate){ - call->prevstate=call->state; - - /*Make sanity checks with call state changes. Any bad transition can result in unpredictable results - *or irrecoverable errors in the application*/ - if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){ - if (cstate!=LinphoneCallReleased){ - ms_fatal("Abnormal call resurection from %s to %s, aborting." ,linphone_call_state_to_string(call->state) - ,linphone_call_state_to_string(cstate)); - return; - } - }else if (cstate == LinphoneCallReleased && (call->prevstate != LinphoneCallError && call->prevstate != LinphoneCallEnd)){ - ms_fatal("Attempt to move call [%p] to Released state while it was not previously in Error or End state. Aborting.", call); - return; - } - ms_message("Call %p: moving from state %s to %s",call - ,linphone_call_state_to_string(call->state) - ,linphone_call_state_to_string(cstate)); - - if (cstate!=LinphoneCallRefered){ - /*LinphoneCallRefered is rather an event, not a state. - Indeed it does not change the state of the call (still paused or running)*/ - call->state=cstate; - } - - switch (cstate) { - case LinphoneCallOutgoingInit: - case LinphoneCallIncomingReceived: -#ifdef __ANDROID__ - ms_message("Call [%p] acquires both wifi and multicast lock",call); - linphone_core_wifi_lock_acquire(call->core); - linphone_core_multicast_lock_acquire(call->core); /*does no affect battery more than regular rtp traffic*/ -#endif - break; - case LinphoneCallEnd: - case LinphoneCallError: - switch(linphone_error_info_get_reason(linphone_call_get_error_info(call))) { - case LinphoneReasonDeclined: - call->log->status=LinphoneCallDeclined; - break; - case LinphoneReasonNotAnswered: - if (call->log->dir == LinphoneCallIncoming){ - call->log->status=LinphoneCallMissed; - } - break; - case LinphoneReasonNone: - if (call->log->dir == LinphoneCallIncoming){ - const LinphoneErrorInfo *ei = linphone_call_get_error_info(call); - if (ei) { - int code = linphone_error_info_get_protocol_code(ei); - if((code >= 200 && code < 300)) { - // error between 200-299 means accepted elsewhere - call->log->status=LinphoneCallAcceptedElsewhere; - break; - } - } - } - break; - case LinphoneReasonDoNotDisturb: - if (call->log->dir == LinphoneCallIncoming){ - const LinphoneErrorInfo *ei = linphone_call_get_error_info(call); - if (ei) { - int code = linphone_error_info_get_protocol_code(ei); - if(code >= 600 && code < 700) { - // error between 600-699 means declined elsewhere - call->log->status=LinphoneCallDeclinedElsewhere; - break; - } - } - } - break; - default: - break; - } - linphone_call_set_terminated(call); - break; - case LinphoneCallConnected: - call->log->status=LinphoneCallSuccess; - call->log->connected_date_time = ms_time(NULL); - break; - case LinphoneCallReleased: -#ifdef __ANDROID__ - ms_message("Call [%p] releases wifi/multicast lock",call); - linphone_core_wifi_lock_release(call->core); - linphone_core_multicast_lock_release(call->core); -#endif - break; - case LinphoneCallStreamsRunning: - if (call->prevstate == LinphoneCallUpdating || call->prevstate == LinphoneCallUpdatedByRemote) { - LinphoneReason reason = linphone_call_get_reason(call); - char *msg; - if (reason != LinphoneReasonNone) { - msg = ms_strdup_printf(_("Call parameters could not be modified: %s."), linphone_reason_to_string(reason)); - } else { - msg = ms_strdup(_("Call parameters were successfully modified.")); - } - linphone_core_notify_display_status(lc, msg); - ms_free(msg); - } - break; - default: - break; - } - - if(cstate!=LinphoneCallStreamsRunning) { - if (call->dtmfs_timer!=NULL){ - /*cancelling DTMF sequence, if any*/ - linphone_call_cancel_dtmfs(call); - } - } - if (!message) { - ms_error("%s(): You must fill a reason when changing call state (from %s o %s)." - , __FUNCTION__ - , linphone_call_state_to_string(call->prevstate) - , linphone_call_state_to_string(call->state)); - } - linphone_call_notify_state_changed(call, cstate, message ? message : ""); - linphone_reporting_call_state_updated(call); - if (cstate==LinphoneCallReleased) {/*shall be performed after app notification*/ - linphone_call_set_released(call); - } - } } -static void linphone_call_destroy(LinphoneCall *obj){ - ms_message("Call [%p] freed.",obj); +static void linphone_call_destroy(LinphoneCall *obj) { + ms_message("Call [%p] freed.", obj); + obj->call = nullptr; + if (obj->currentParamsCache) { + linphone_call_params_unref(obj->currentParamsCache); + obj->currentParamsCache = nullptr; + } + if (obj->paramsCache) { + linphone_call_params_unref(obj->paramsCache); + obj->paramsCache = nullptr; + } + if (obj->remoteParamsCache) { + linphone_call_params_unref(obj->remoteParamsCache); + obj->remoteParamsCache = nullptr; + } + if (obj->remoteAddressCache) { + linphone_address_unref(obj->remoteAddressCache); + obj->remoteAddressCache = nullptr; + } bctbx_list_free_with_data(obj->callbacks, (bctbx_list_free_func)linphone_call_cbs_unref); if (obj->audiostream || obj->videostream){ linphone_call_free_media_resources(obj); @@ -1972,10 +397,6 @@ static void linphone_call_destroy(LinphoneCall *obj){ sal_op_release(obj->op); obj->op=NULL; } - if (obj->biggestdesc!=NULL){ - sal_media_description_unref(obj->biggestdesc); - obj->biggestdesc=NULL; - } if (obj->resultdesc!=NULL) { sal_media_description_unref(obj->resultdesc); obj->resultdesc=NULL; @@ -2004,14 +425,6 @@ static void linphone_call_destroy(LinphoneCall *obj){ linphone_call_log_unref(obj->log); obj->log=NULL; } - if (obj->auth_token) { - ms_free(obj->auth_token); - obj->auth_token=NULL; - } - if (obj->dtls_certificate_fingerprint) { - ms_free(obj->dtls_certificate_fingerprint); - obj->dtls_certificate_fingerprint=NULL; - } if (obj->dtmfs_timer) { linphone_call_cancel_dtmfs(obj); } @@ -2027,15 +440,7 @@ static void linphone_call_destroy(LinphoneCall *obj){ linphone_call_params_unref(obj->remote_params); obj->remote_params=NULL; } - if (obj->me) { - linphone_address_unref(obj->me); - obj->me = NULL; - } - if (obj->onhold_file) ms_free(obj->onhold_file); - if (obj->ei) linphone_error_info_unref(obj->ei); - if (obj->nat_policy) - linphone_nat_policy_unref(obj->nat_policy); } LinphoneCall * linphone_call_ref(LinphoneCall *obj){ @@ -2047,338 +452,167 @@ void linphone_call_unref(LinphoneCall *obj){ belle_sip_object_unref(obj); } -static unsigned int linphone_call_get_n_active_streams(const LinphoneCall *call) { - SalMediaDescription *md=NULL; - if (call->op) - md = sal_call_get_remote_media_description(call->op); - if (!md) - return 0; - return sal_media_description_nb_active_streams_of_type(md, SalAudio) + sal_media_description_nb_active_streams_of_type(md, SalVideo) + sal_media_description_nb_active_streams_of_type(md, SalText); -} - const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){ - SalMediaDescription *md=call->resultdesc; - int all_streams_encrypted = 0; -#ifdef VIDEO_ENABLED - VideoStream *vstream; -#endif - LinphoneVideoDefinition *vdef = linphone_video_definition_new(MS_VIDEO_SIZE_UNKNOWN_W, MS_VIDEO_SIZE_UNKNOWN_H, NULL); - linphone_call_params_set_sent_video_definition(call->current_params, vdef); - linphone_call_params_set_received_video_definition(call->current_params, vdef); -#ifdef VIDEO_ENABLED - vstream = call->videostream; - if (vstream != NULL) { - MSVideoSize vsize = video_stream_get_sent_video_size(vstream); - LinphoneVideoDefinition *vdef = linphone_video_definition_new(vsize.width, vsize.height, NULL); - linphone_call_params_set_sent_video_definition(call->current_params, vdef); - vsize = video_stream_get_received_video_size(vstream); - vdef = linphone_video_definition_new(vsize.width, vsize.height, NULL); - linphone_call_params_set_received_video_definition(call->current_params, vdef); - linphone_call_params_set_sent_fps(call->current_params, video_stream_get_sent_framerate(vstream)); - linphone_call_params_set_received_fps(call->current_params, video_stream_get_received_framerate(vstream)); - } -#endif - - /* REVISITED - * Previous code was buggy. - * Relying on the mediastream's state (added by jehan: only) to know the current encryption is unreliable. - * For (added by jehan: both DTLS and) ZRTP it is though necessary. - * But for all others the current_params->media_encryption state should reflect (added by jehan: both) what is agreed by the offer/answer - * mechanism (added by jehan: and encryption status from media which is much stronger than only result of offer/answer ) - * Typically there can be inactive streams for which the media layer has no idea of whether they are encrypted or not. - */ - - switch (linphone_call_params_get_media_encryption(call->params)) { - case LinphoneMediaEncryptionZRTP: - if (at_least_one_stream_started(call)){ - if ((all_streams_encrypted = linphone_call_all_streams_encrypted(call)) && linphone_call_get_authentication_token(call)) { - linphone_call_params_set_media_encryption(call->current_params, LinphoneMediaEncryptionZRTP); - } else { - /*to avoid to many traces*/ - ms_debug("Encryption was requested to be %s, but isn't effective (all_streams_encrypted=%i, auth_token=%s)", - linphone_media_encryption_to_string(linphone_call_params_get_media_encryption(call->params)), all_streams_encrypted, call->auth_token == NULL ? "" : call->auth_token); - linphone_call_params_set_media_encryption(call->current_params, LinphoneMediaEncryptionNone); - } - }//else don't update the state if all streams are shutdown. - break; - case LinphoneMediaEncryptionDTLS: - case LinphoneMediaEncryptionSRTP: - if (at_least_one_stream_started(call)){ - if (linphone_call_get_n_active_streams(call)==0 || (all_streams_encrypted = linphone_call_all_streams_encrypted(call))) { - linphone_call_params_set_media_encryption(call->current_params, linphone_call_params_get_media_encryption(call->params)); - } else { - /*to avoid to many traces*/ - ms_debug("Encryption was requested to be %s, but isn't effective (all_streams_encrypted=%i)", - linphone_media_encryption_to_string(linphone_call_params_get_media_encryption(call->params)), all_streams_encrypted); - linphone_call_params_set_media_encryption(call->current_params, LinphoneMediaEncryptionNone); - } - }//else don't update the state if all streams are shutdown. - break; - case LinphoneMediaEncryptionNone: - /* check if we actually switched to ZRTP */ - if (at_least_one_stream_started(call) && (all_streams_encrypted = linphone_call_all_streams_encrypted(call)) && linphone_call_get_authentication_token(call)) { - linphone_call_params_set_media_encryption(call->current_params, LinphoneMediaEncryptionZRTP); - } else { - linphone_call_params_set_media_encryption(call->current_params, LinphoneMediaEncryptionNone); - } - break; - } - linphone_call_params_enable_avpf(call->current_params, linphone_call_all_streams_avpf_enabled(call) && sal_media_description_has_avpf(md)); - if (linphone_call_params_avpf_enabled(call->current_params) == TRUE) { - linphone_call_params_set_avpf_rr_interval(call->current_params, linphone_call_get_avpf_rr_interval(call)); - } else { - linphone_call_params_set_avpf_rr_interval(call->current_params, 0); - } - if (md){ - const char *rtp_addr; - - SalStreamDescription *sd=sal_media_description_find_best_stream(md,SalAudio); - - linphone_call_params_set_audio_direction(call->current_params, sd ? media_direction_from_sal_stream_dir(sd->dir) : LinphoneMediaDirectionInactive); - if (linphone_call_params_get_audio_direction(call->current_params) != LinphoneMediaDirectionInactive) { - rtp_addr = sd->rtp_addr[0]!='\0' ? sd->rtp_addr : call->resultdesc->addr; - linphone_call_params_enable_audio_multicast(call->current_params, ms_is_multicast(rtp_addr)); - } else - linphone_call_params_enable_audio_multicast(call->current_params, FALSE); - - sd=sal_media_description_find_best_stream(md,SalVideo); - linphone_call_params_enable_implicit_rtcp_fb(call->current_params, sd ? sal_stream_description_has_implicit_avpf(sd): FALSE); - linphone_call_params_set_video_direction(call->current_params, sd ? media_direction_from_sal_stream_dir(sd->dir) : LinphoneMediaDirectionInactive); - if (linphone_call_params_get_video_direction(call->current_params) != LinphoneMediaDirectionInactive) { - rtp_addr = sd->rtp_addr[0]!='\0' ? sd->rtp_addr : call->resultdesc->addr; - linphone_call_params_enable_video_multicast(call->current_params, ms_is_multicast(rtp_addr)); - } else - linphone_call_params_enable_video_multicast(call->current_params, FALSE); - - } - - return call->current_params; + call->currentParamsCache->msp = linphone_call_get_cpp_obj(call)->getCurrentParams(); + return call->currentParamsCache; } -const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){ - if (call->op){ - LinphoneCallParams *cp; - SalMediaDescription *md; - const SalCustomHeader *ch; - - md=sal_call_get_remote_media_description(call->op); - if (md) { - SalStreamDescription *sd; - unsigned int i; - unsigned int nb_audio_streams = sal_media_description_nb_active_streams_of_type(md, SalAudio); - unsigned int nb_video_streams = sal_media_description_nb_active_streams_of_type(md, SalVideo); - unsigned int nb_text_streams = sal_media_description_nb_active_streams_of_type(md, SalText); - if (call->remote_params != NULL) linphone_call_params_unref(call->remote_params); - cp = call->remote_params = linphone_call_params_new(); - - for (i = 0; i < nb_video_streams; i++) { - sd = sal_media_description_get_active_stream_of_type(md, SalVideo, i); - if (sal_stream_description_active(sd) == TRUE) linphone_call_params_enable_video(cp, TRUE); - if (sal_stream_description_has_srtp(sd) == TRUE) linphone_call_params_set_media_encryption(cp, LinphoneMediaEncryptionSRTP); - } - for (i = 0; i < nb_audio_streams; i++) { - sd = sal_media_description_get_active_stream_of_type(md, SalAudio, i); - if (sal_stream_description_has_srtp(sd) == TRUE) linphone_call_params_set_media_encryption(cp, LinphoneMediaEncryptionSRTP); - } - for (i = 0; i < nb_text_streams; i++) { - sd = sal_media_description_get_active_stream_of_type(md, SalText, i); - if (sal_stream_description_has_srtp(sd) == TRUE) linphone_call_params_set_media_encryption(cp, LinphoneMediaEncryptionSRTP); - linphone_call_params_enable_realtime_text(cp, TRUE); - } - if (!linphone_call_params_video_enabled(cp)){ - if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){ - linphone_call_params_enable_low_bandwidth(cp, TRUE); - } - } - if (md->name[0]!='\0') linphone_call_params_set_session_name(cp,md->name); - - linphone_call_params_set_custom_sdp_attributes(call->remote_params, md->custom_sdp_attributes); - linphone_call_params_set_custom_sdp_media_attributes(call->remote_params, LinphoneStreamTypeAudio, md->streams[call->main_audio_stream_index].custom_sdp_attributes); - linphone_call_params_set_custom_sdp_media_attributes(call->remote_params, LinphoneStreamTypeVideo, md->streams[call->main_video_stream_index].custom_sdp_attributes); - linphone_call_params_set_custom_sdp_media_attributes(call->remote_params, LinphoneStreamTypeText, md->streams[call->main_text_stream_index].custom_sdp_attributes); - } - ch = sal_op_get_recv_custom_header(call->op); - if (ch){ - /*instanciate a remote_params only if a SIP message was received before (custom headers indicates this).*/ - if (call->remote_params == NULL) call->remote_params = linphone_call_params_new(); - linphone_call_params_set_custom_headers(call->remote_params, ch); - } - return call->remote_params; - } - return NULL; +const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call) { + call->remoteParamsCache->msp = linphone_call_get_cpp_obj(call)->getRemoteParams(); + if (call->remoteParamsCache->msp) + return call->remoteParamsCache; + return nullptr; } -const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){ - return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to; +const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call) { + std::shared_ptr addr = std::make_shared(linphone_call_get_cpp_obj(call)->getRemoteAddress()); + L_SET_CPP_PTR_FROM_C_STRUCT(call->remoteAddressCache, addr); + return call->remoteAddressCache; } const LinphoneAddress * linphone_call_get_to_address(const LinphoneCall *call){ +#if 0 return (const LinphoneAddress *)sal_op_get_to_address(call->op); +#else + return nullptr; +#endif } const char *linphone_call_get_to_header(const LinphoneCall *call, const char *name){ +#if 0 return sal_custom_header_find(sal_op_get_recv_custom_header(call->op),name); +#else + return nullptr; +#endif } -char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){ - return linphone_address_as_string(linphone_call_get_remote_address(call)); +char * linphone_call_get_remote_address_as_string(const LinphoneCall *call) { + return ms_strdup(linphone_call_get_cpp_obj(call)->getRemoteAddressAsString().c_str()); } const LinphoneAddress * linphone_call_get_diversion_address(const LinphoneCall *call){ +#if 0 return call->op?(const LinphoneAddress *)sal_op_get_diversion_address(call->op):NULL; +#else + return nullptr; +#endif } -LinphoneCallState linphone_call_get_state(const LinphoneCall *call){ - return call->state; +LinphoneCallState linphone_call_get_state(const LinphoneCall *call) { + return linphone_call_get_cpp_obj(call)->getState(); } -LinphoneReason linphone_call_get_reason(const LinphoneCall *call){ - return linphone_error_info_get_reason(linphone_call_get_error_info(call)); +LinphoneReason linphone_call_get_reason(const LinphoneCall *call) { + return linphone_call_get_cpp_obj(call)->getReason(); } -const LinphoneErrorInfo *linphone_call_get_error_info(const LinphoneCall *call){ - if (!call->non_op_error){ - linphone_error_info_from_sal_op(call->ei, call->op); - } - return call->ei; +const LinphoneErrorInfo * linphone_call_get_error_info(const LinphoneCall *call) { + return linphone_call_get_cpp_obj(call)->getErrorInfo(); } -void *linphone_call_get_user_data(const LinphoneCall *call) -{ +void *linphone_call_get_user_data(const LinphoneCall *call) { return call->user_data; } -void linphone_call_set_user_data(LinphoneCall *call, void *user_pointer) -{ +void linphone_call_set_user_data(LinphoneCall *call, void *user_pointer) { call->user_data = user_pointer; } LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){ - return call->log; + return linphone_call_get_cpp_obj(call)->getLog(); } const char *linphone_call_get_refer_to(const LinphoneCall *call){ +#if 0 return call->refer_to; +#else + return nullptr; +#endif } LinphoneCall *linphone_call_get_transferer_call(const LinphoneCall *call){ +#if 0 return call->referer; +#else + return nullptr; +#endif } LinphoneCall *linphone_call_get_transfer_target_call(const LinphoneCall *call){ +#if 0 return call->transfer_target; +#else + return nullptr; +#endif } -LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){ - return call->log->dir; +LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call) { + return linphone_call_log_get_dir(linphone_call_get_log(call)); } const char *linphone_call_get_remote_user_agent(LinphoneCall *call){ +#if 0 if (call->op){ return sal_op_get_remote_ua (call->op); } return NULL; +#else + return nullptr; +#endif } -const char *linphone_call_get_remote_contact(LinphoneCall *call){ - if( call->op ){ - /*sal_op_get_remote_contact preserves header params*/ - return sal_op_get_remote_contact(call->op); - } - return NULL; +const char * linphone_call_get_remote_contact(LinphoneCall *call) { + std::string contact = linphone_call_get_cpp_obj(call)->getRemoteContact(); + if (contact.empty()) + return nullptr; + if (call->remoteContactCache) + bctbx_free(call->remoteContactCache); + call->remoteContactCache = bctbx_strdup(contact.c_str()); + return call->remoteContactCache; } bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){ +#if 0 return call->refer_pending; -} - -static int _linphone_call_compute_duration (const LinphoneCall *call) { - if (call->log->connected_date_time == 0) return 0; - else return (int)(ms_time(NULL) - call->log->connected_date_time); +#else + return FALSE; +#endif } int linphone_call_get_duration(const LinphoneCall *call) { - switch (call->state) { - case LinphoneCallEnd: - case LinphoneCallError: - case LinphoneCallReleased: - return call->log->duration; - default: - return _linphone_call_compute_duration(call); - } + return linphone_call_get_cpp_obj(call)->getDuration(); } LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){ +#if 0 SalOp *op=sal_call_get_replaces(call->op); if (op){ return (LinphoneCall*)sal_op_get_user_pointer(op); } return NULL; +#else + return nullptr; +#endif } -void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){ -#ifdef VIDEO_ENABLED - call->camera_enabled=enable; - switch(call->state) { - case LinphoneCallStreamsRunning: - case LinphoneCallOutgoingEarlyMedia: - case LinphoneCallIncomingEarlyMedia: - case LinphoneCallConnected: - if(call->videostream!=NULL - && video_stream_started(call->videostream) - && video_stream_get_camera(call->videostream) != linphone_call_get_video_device(call)) { - const char *cur_cam, *new_cam; - cur_cam = video_stream_get_camera(call->videostream) ? ms_web_cam_get_name(video_stream_get_camera(call->videostream)) : "NULL"; - new_cam = linphone_call_get_video_device(call) ? ms_web_cam_get_name(linphone_call_get_video_device(call)) : "NULL"; - ms_message("Switching video cam from [%s] to [%s] on call [%p]" , cur_cam, new_cam, call); - video_stream_change_camera(call->videostream, linphone_call_get_video_device(call)); - } - break; - - default: break; - } -#endif +void linphone_call_enable_camera(LinphoneCall *call, bool_t enable) { + linphone_call_get_cpp_obj(call)->enableCamera(enable); } void linphone_call_send_vfu_request(LinphoneCall *call) { -#ifdef VIDEO_ENABLED - const LinphoneCallParams *current_params = linphone_call_get_current_params(call); - if ((linphone_call_params_avpf_enabled(current_params) || linphone_call_params_implicit_rtcp_fb_enabled(current_params)) && call->videostream && media_stream_get_state((const MediaStream *)call->videostream) == MSStreamStarted) { // || sal_media_description_has_implicit_avpf((const SalMediaDescription *)call->resultdesc) - ms_message("Request Full Intra Request on call [%p]", call); - video_stream_send_fir(call->videostream); - } else if (call->core->sip_conf.vfu_with_info) { - ms_message("Request SIP INFO FIR on call [%p]", call); - if (LinphoneCallStreamsRunning == linphone_call_get_state(call)) - sal_call_send_vfu_request(call->op); - } else { - ms_message("vfu request using sip disabled from config [sip,vfu_with_info]"); - } -#endif + linphone_call_get_cpp_obj(call)->sendVfuRequest(); } LinphoneStatus linphone_call_take_video_snapshot(LinphoneCall *call, const char *file) { -#ifdef VIDEO_ENABLED - if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){ - return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file); - } - ms_warning("Cannot take snapshot: no currently running video stream on this call."); -#endif - return -1; + return linphone_call_get_cpp_obj(call)->takeVideoSnapshot(file ? file : ""); } LinphoneStatus linphone_call_take_preview_snapshot(LinphoneCall *call, const char *file) { -#ifdef VIDEO_ENABLED - if (call->videostream!=NULL && call->videostream->local_jpegwriter!=NULL){ - return ms_filter_call_method(call->videostream->local_jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file); - } - ms_warning("Cannot take local snapshot: no currently running video stream on this call."); - return -1; -#endif - return -1; + return linphone_call_get_cpp_obj(call)->takePreviewSnapshot(file ? file : ""); } -bool_t linphone_call_camera_enabled (const LinphoneCall *call){ - return call->camera_enabled; +bool_t linphone_call_camera_enabled (const LinphoneCall *call) { + return linphone_call_get_cpp_obj(call)->cameraEnabled(); } /** @@ -2398,547 +632,13 @@ const char* linphone_privacy_to_string(LinphonePrivacy privacy) { } } - -#ifdef TEST_EXT_RENDERER -static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){ - ms_message("rendercb, local buffer=%p, remote buffer=%p", - local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL); -} -#endif - -#ifdef VIDEO_ENABLED -static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){ - LinphoneCall* call = (LinphoneCall*) user_pointer; - switch (event_id) { - case MS_VIDEO_DECODER_DECODING_ERRORS: - ms_warning("MS_VIDEO_DECODER_DECODING_ERRORS"); - if (call->videostream && (video_stream_is_decoding_error_to_be_reported(call->videostream, 5000) == TRUE)) { - video_stream_decoding_error_reported(call->videostream); - linphone_call_send_vfu_request(call); - } - break; - case MS_VIDEO_DECODER_RECOVERED_FROM_ERRORS: - ms_message("MS_VIDEO_DECODER_RECOVERED_FROM_ERRORS"); - if (call->videostream) { - video_stream_decoding_error_recovered(call->videostream); - } - break; - case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED: - ms_message("First video frame decoded successfully"); - if (call->nextVideoFrameDecoded._func != NULL){ - call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data); - call->nextVideoFrameDecoded._func = NULL; - call->nextVideoFrameDecoded._user_data = NULL; - } - break; - case MS_VIDEO_DECODER_SEND_PLI: - case MS_VIDEO_DECODER_SEND_SLI: - case MS_VIDEO_DECODER_SEND_RPSI: - /* Handled internally by mediastreamer2. */ - break; - default: - ms_warning("Unhandled event %i", event_id); - break; - } -} -#endif - -static void _linphone_call_set_next_video_frame_decoded_trigger(LinphoneCall *call){ -#ifdef VIDEO_ENABLED - if (call->nextVideoFrameDecoded._func && call->videostream && call->videostream->ms.decoder) - ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION); -#endif -} - void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) { - call->nextVideoFrameDecoded._func = cb; - call->nextVideoFrameDecoded._user_data = user_data; - _linphone_call_set_next_video_frame_decoded_trigger(call); -} - -static void port_config_set_random_choosed(LinphoneCall *call, int stream_index, RtpSession *session){ - call->media_ports[stream_index].rtp_port=rtp_session_get_local_port(session); - call->media_ports[stream_index].rtcp_port=rtp_session_get_local_rtcp_port(session); -} - -static void _linphone_call_prepare_ice_for_stream(LinphoneCall *call, int stream_index, bool_t create_checklist){ - MediaStream *ms = stream_index == call->main_audio_stream_index ? (MediaStream*)call->audiostream : stream_index == call->main_video_stream_index ? (MediaStream*)call->videostream : (MediaStream*)call->textstream; - if (linphone_nat_policy_ice_enabled(call->nat_policy) && (call->ice_session != NULL)){ - IceCheckList *cl; - rtp_session_set_pktinfo(ms->sessions.rtp_session, TRUE); - cl=ice_session_check_list(call->ice_session, stream_index); - if (cl == NULL && create_checklist) { - cl=ice_check_list_new(); - ice_session_add_check_list(call->ice_session, cl, stream_index); - ms_message("Created new ICE check list for stream [%i]",stream_index); - } - if (cl) { - media_stream_set_ice_check_list(ms, cl); - } - } -} - -int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){ - SalMediaDescription *remote = NULL; - int err; - bool_t has_video=FALSE; - - if (linphone_nat_policy_ice_enabled(call->nat_policy) && (call->ice_session != NULL)){ - if (incoming_offer){ - remote=sal_call_get_remote_media_description(call->op); - has_video=linphone_core_video_enabled(call->core) && linphone_core_media_description_contains_video_stream(remote); - }else has_video=linphone_call_params_video_enabled(call->params); - - _linphone_call_prepare_ice_for_stream(call,call->main_audio_stream_index,TRUE); - if (has_video) _linphone_call_prepare_ice_for_stream(call,call->main_video_stream_index,TRUE); - if (linphone_call_params_realtime_text_enabled(call->params)) _linphone_call_prepare_ice_for_stream(call,call->main_text_stream_index,TRUE); - /*start ICE gathering*/ - if (incoming_offer) - linphone_call_update_ice_from_remote_media_description(call, remote, TRUE); /*this may delete the ice session*/ - if (call->ice_session && !ice_session_candidates_gathered(call->ice_session)){ - if (call->audiostream->ms.state==MSStreamInitialized) - audio_stream_prepare_sound(call->audiostream, NULL, NULL); -#ifdef VIDEO_ENABLED - if (has_video && call->videostream && call->videostream->ms.state==MSStreamInitialized) { - video_stream_prepare_video(call->videostream); - } -#endif - if (linphone_call_params_realtime_text_enabled(call->params) && call->textstream->ms.state==MSStreamInitialized) { - text_stream_prepare_text(call->textstream); - } - err = linphone_core_gather_ice_candidates(call->core,call); - if (err == 0) { - /* Ice candidates gathering wasn't started, but we can proceed with the call anyway. */ - linphone_call_stop_media_streams_for_ice_gathering(call); - }else if (err == -1) { - linphone_call_stop_media_streams_for_ice_gathering(call); - linphone_call_delete_ice_session(call); - } - return err;/* 1= gathering in progress, wait; 0=proceed*/ - } - } - return 0; -} - -/*eventually join to a multicast group if told to do so*/ -static void linphone_call_join_multicast_group(LinphoneCall *call, int stream_index, MediaStream *ms){ - if (call->media_ports[stream_index].multicast_ip[stream_index]!='\0'){ - media_stream_join_multicast_group(ms, call->media_ports[stream_index].multicast_ip); - } else - ms_error("Cannot join multicast group if multicast ip is not set for call [%p]",call); -} - -static SalMulticastRole linphone_call_get_multicast_role(const LinphoneCall *call,SalStreamType type) { - SalMulticastRole multicast_role=SalMulticastInactive; - SalMediaDescription *remotedesc, *localdesc; - SalStreamDescription *stream_desc = NULL; - if (!call->op) goto end; - remotedesc = sal_call_get_remote_media_description(call->op); - localdesc = call->localdesc; - if (!localdesc && !remotedesc && call->dir == LinphoneCallOutgoing) { - /*well using call dir*/ - if ((type == SalAudio && linphone_call_params_audio_multicast_enabled(call->params)) - || (type == SalVideo && linphone_call_params_video_multicast_enabled(call->params))) - multicast_role=SalMulticastSender; - } else if (localdesc && (!remotedesc || sal_call_is_offerer(call->op))) { - stream_desc = sal_media_description_find_best_stream(localdesc, type); - } else if (!sal_call_is_offerer(call->op) && remotedesc) - stream_desc = sal_media_description_find_best_stream(remotedesc, type); - - if (stream_desc) - multicast_role = stream_desc->multicast_role; - - end: - ms_message("Call [%p], stream type [%s], multicast role is [%s]",call, sal_stream_type_to_string(type), - sal_multicast_role_to_string(multicast_role)); - return multicast_role; -} - -static void setup_dtls_params(LinphoneCall *call, MediaStream* stream) { - LinphoneCore *lc=call->core; - if (linphone_call_params_get_media_encryption(call->params)==LinphoneMediaEncryptionDTLS) { - MSDtlsSrtpParams params; - char *certificate, *key; - memset(¶ms,0,sizeof(MSDtlsSrtpParams)); - /* TODO : search for a certificate with CNAME=sip uri(retrieved from variable me) or default : linphone-dtls-default-identity */ - /* This will parse the directory to find a matching fingerprint or generate it if not found */ - /* returned string must be freed */ - sal_certificates_chain_parse_directory(&certificate, &key, &call->dtls_certificate_fingerprint, lc->user_certificates_path, "linphone-dtls-default-identity", SAL_CERTIFICATE_RAW_FORMAT_PEM, TRUE, TRUE); - - if (key!= NULL && certificate!=NULL) { - params.pem_certificate = (char *)certificate; - params.pem_pkey = (char *)key; - params.role = MSDtlsSrtpRoleUnset; /* default is unset, then check if we have a result SalMediaDescription */ - media_stream_enable_dtls(stream,¶ms); - ms_free(certificate); - ms_free(key); - } else { - ms_error("Unable to retrieve or generate DTLS certificate and key - DTLS disabled"); - /* TODO : check if encryption forced, if yes, stop call */ - } - } -} - -static void setZrtpCryptoTypesParameters(MSZrtpParams *params, LinphoneCore *lc) -{ - int i; - const MSCryptoSuite *srtp_suites; - MsZrtpCryptoTypesCount ciphersCount, authTagsCount; - - if (params == NULL) return; - if (lc == NULL) return; - - srtp_suites = linphone_core_get_srtp_crypto_suites(lc); - if (srtp_suites!=NULL) { - for(i=0; srtp_suites[i]!=MS_CRYPTO_SUITE_INVALID && iciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1; - params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS32; - break; - case MS_AES_128_NO_AUTH: - params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1; - break; - case MS_NO_CIPHER_SHA1_80: - params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80; - break; - case MS_AES_128_SHA1_80: - params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1; - params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80; - break; - case MS_AES_CM_256_SHA1_80: - ms_warning("Deprecated crypto suite MS_AES_CM_256_SHA1_80, use MS_AES_256_SHA1_80 instead"); - BCTBX_NO_BREAK; - case MS_AES_256_SHA1_80: - params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES3; - params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80; - break; - case MS_AES_256_SHA1_32: - params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES3; - params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS32; - break; - case MS_CRYPTO_SUITE_INVALID: - break; - } - } - } - - /* linphone_core_get_srtp_crypto_suites is used to determine sensible defaults; here each can be overridden */ - ciphersCount = linphone_core_get_zrtp_cipher_suites(lc, params->ciphers); /* if not present in config file, params->ciphers is not modified */ - if (ciphersCount!=0) { /* use zrtp_cipher_suites config only when present, keep config from srtp_crypto_suite otherwise */ - params->ciphersCount = ciphersCount; - } - params->hashesCount = linphone_core_get_zrtp_hash_suites(lc, params->hashes); - authTagsCount = linphone_core_get_zrtp_auth_suites(lc, params->authTags); /* if not present in config file, params->authTags is not modified */ - if (authTagsCount!=0) { - params->authTagsCount = authTagsCount; /* use zrtp_auth_suites config only when present, keep config from srtp_crypto_suite otherwise */ - } - params->sasTypesCount = linphone_core_get_zrtp_sas_suites(lc, params->sasTypes); - params->keyAgreementsCount = linphone_core_get_zrtp_key_agreement_suites(lc, params->keyAgreements); -} - -static OrtpJitterBufferAlgorithm name_to_jb_algo(const char *value){ - if (value){ - if (strcasecmp(value, "basic") == 0) return OrtpJitterBufferBasic; - else if (strcasecmp(value, "rls") == 0) return OrtpJitterBufferRecursiveLeastSquare; - } - ms_error("Invalid jitter buffer algorithm: %s", value); - return OrtpJitterBufferRecursiveLeastSquare; -} - -static void apply_jitter_buffer_params(LinphoneCore *lc, RtpSession *session, LinphoneStreamType type){ - JBParameters params; - - rtp_session_get_jitter_buffer_params(session, ¶ms); - params.min_size = lp_config_get_int(lc->config, "rtp", "jitter_buffer_min_size", 40); - params.max_size = lp_config_get_int(lc->config, "rtp", "jitter_buffer_max_size", 250); - params.max_packets = params.max_size * 200 / 1000; /*allow 200 packet per seconds, quite large*/ - params.buffer_algorithm = name_to_jb_algo(lp_config_get_string(lc->config, "rtp", "jitter_buffer_algorithm", "rls")); - params.refresh_ms = lp_config_get_int(lc->config, "rtp", "jitter_buffer_refresh_period", 5000); - params.ramp_refresh_ms = lp_config_get_int(lc->config, "rtp", "jitter_buffer_ramp_refresh_period", 5000); - params.ramp_step_ms = lp_config_get_int(lc->config, "rtp", "jitter_buffer_ramp_step", 20); - params.ramp_threshold = lp_config_get_int(lc->config, "rtp", "jitter_buffer_ramp_threshold", 70); - - switch (type){ - case LinphoneStreamTypeAudio: - case LinphoneStreamTypeText: /*let's use the same params for text as for audio.*/ - params.nom_size = linphone_core_get_audio_jittcomp(lc); - params.adaptive = linphone_core_audio_adaptive_jittcomp_enabled(lc); - break; - case LinphoneStreamTypeVideo: - params.nom_size = linphone_core_get_video_jittcomp(lc); - params.adaptive = linphone_core_video_adaptive_jittcomp_enabled(lc); - break; - case LinphoneStreamTypeUnknown: - ms_fatal("apply_jitter_buffer_params: should not happen"); - break; - } - params.enabled = params.nom_size > 0; - if (params.enabled){ - if (params.min_size > params.nom_size){ - params.min_size = params.nom_size; - } - if (params.max_size < params.nom_size){ - params.max_size = params.nom_size; - } - } - rtp_session_set_jitter_buffer_params(session, ¶ms); -} - -void linphone_call_init_audio_stream(LinphoneCall *call){ - LinphoneCore *lc=call->core; - AudioStream *audiostream; - const char *location; - int dscp; - const char *rtcp_tool=linphone_core_get_user_agent(call->core); - char* cname; - - if (call->audiostream != NULL) return; - if (call->sessions[call->main_audio_stream_index].rtp_session==NULL){ - SalMulticastRole multicast_role = linphone_call_get_multicast_role(call,SalAudio); - SalMediaDescription *remotedesc=NULL; - SalStreamDescription *stream_desc = NULL; - if (call->op) remotedesc = sal_call_get_remote_media_description(call->op); - if (remotedesc) - stream_desc = sal_media_description_find_best_stream(remotedesc, SalAudio); - - call->audiostream=audiostream=audio_stream_new2(lc->factory, linphone_call_get_bind_ip_for_stream(call,call->main_audio_stream_index), - multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[call->main_audio_stream_index].rtp_port, - multicast_role == SalMulticastReceiver ? 0 /*disabled for now*/ : call->media_ports[call->main_audio_stream_index].rtcp_port); - if (multicast_role == SalMulticastReceiver) - linphone_call_join_multicast_group(call, call->main_audio_stream_index, &audiostream->ms); - rtp_session_enable_network_simulation(call->audiostream->ms.sessions.rtp_session, &lc->net_conf.netsim_params); - apply_jitter_buffer_params(lc, call->audiostream->ms.sessions.rtp_session, LinphoneStreamTypeAudio); - cname = linphone_address_as_string_uri_only(call->me); - audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool); - ms_free(cname); - rtp_session_set_symmetric_rtp(audiostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc)); - setup_dtls_params(call, &audiostream->ms); - - /* init zrtp even if we didn't explicitely set it, just in case peer offers it */ - if (linphone_core_media_encryption_supported(lc, LinphoneMediaEncryptionZRTP)) { - char *peerUri = linphone_address_as_string_uri_only((call->dir==LinphoneCallIncoming) ? call->log->from : call->log->to); - char *selfUri = linphone_address_as_string_uri_only((call->dir==LinphoneCallIncoming) ? call->log->to : call->log->from); - MSZrtpParams params; - memset(¶ms,0,sizeof(MSZrtpParams)); - /*call->current_params.media_encryption will be set later when zrtp is activated*/ - params.zidCacheDB = linphone_core_get_zrtp_cache_db(lc); - params.peerUri=peerUri; - params.selfUri=selfUri; - params.limeKeyTimeSpan = bctbx_time_string_to_sec(lp_config_get_string(lc->config, "sip", "lime_key_validity", "0")); /* get key lifespan from config file, default is 0:forever valid */ - setZrtpCryptoTypesParameters(¶ms,call->core); - audio_stream_enable_zrtp(call->audiostream,¶ms); - if (peerUri != NULL) ms_free(peerUri); - if (selfUri != NULL) ms_free(selfUri); - } - - media_stream_reclaim_sessions(&audiostream->ms, &call->sessions[call->main_audio_stream_index]); - }else{ - call->audiostream=audio_stream_new_with_sessions(lc->factory, &call->sessions[call->main_audio_stream_index]); - - } - audiostream=call->audiostream; - if (call->media_ports[call->main_audio_stream_index].rtp_port==-1){ - port_config_set_random_choosed(call,call->main_audio_stream_index,audiostream->ms.sessions.rtp_session); - } - dscp=linphone_core_get_audio_dscp(lc); - if (dscp!=-1) - audio_stream_set_dscp(audiostream,dscp); - if (linphone_core_echo_limiter_enabled(lc)){ - const char *type=lp_config_get_string(lc->config,"sound","el_type","mic"); - if (strcasecmp(type,"mic")==0) - audio_stream_enable_echo_limiter(audiostream,ELControlMic); - else if (strcasecmp(type,"full")==0) - audio_stream_enable_echo_limiter(audiostream,ELControlFull); - } - - /* equalizer location in the graph: 'mic' = in input graph, otherwise in output graph. - Any other value than mic will default to output graph for compatibility */ - location = lp_config_get_string(lc->config,"sound","eq_location","hp"); - audiostream->eq_loc = (strcasecmp(location,"mic") == 0) ? MSEqualizerMic : MSEqualizerHP; - ms_message("Equalizer location: %s", location); - - audio_stream_enable_gain_control(audiostream,TRUE); - if (linphone_core_echo_cancellation_enabled(lc)){ - int len,delay,framesize; - len=lp_config_get_int(lc->config,"sound","ec_tail_len",0); - delay=lp_config_get_int(lc->config,"sound","ec_delay",0); - framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0); - audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize); - if (audiostream->ec) { - char *statestr=reinterpret_cast(ms_malloc0(EC_STATE_MAX_LEN)); - if (lp_config_relative_file_exists(lc->config, EC_STATE_STORE) - && lp_config_read_relative_file(lc->config, EC_STATE_STORE, statestr, EC_STATE_MAX_LEN) == 0) { - ms_filter_call_method(audiostream->ec, MS_ECHO_CANCELLER_SET_STATE_STRING, statestr); - } - ms_free(statestr); - } - } - audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc)); - { - int enabled=lp_config_get_int(lc->config,"sound","noisegate",0); - audio_stream_enable_noise_gate(audiostream,enabled); - } - - audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc)); - - if (lc->rtptf){ - RtpTransport *meta_rtp; - RtpTransport *meta_rtcp; - - rtp_session_get_transports(audiostream->ms.sessions.rtp_session,&meta_rtp,&meta_rtcp); - if (meta_rtp_transport_get_endpoint(meta_rtp) == NULL) { - ms_message("LinphoneCall[%p]: using custom audio RTP transport endpoint.", call); - meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->media_ports[call->main_audio_stream_index].rtp_port)); - } - if (meta_rtp_transport_get_endpoint(meta_rtcp) == NULL) { - meta_rtp_transport_set_endpoint(meta_rtcp,lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->media_ports[call->main_audio_stream_index].rtcp_port)); - } - } - - call->audiostream_app_evq = ortp_ev_queue_new(); - rtp_session_register_event_queue(audiostream->ms.sessions.rtp_session,call->audiostream_app_evq); - - _linphone_call_prepare_ice_for_stream(call,call->main_audio_stream_index,FALSE); -} - -void linphone_call_init_video_stream(LinphoneCall *call){ -#ifdef VIDEO_ENABLED - LinphoneCore *lc=call->core; - char* cname; - const char *rtcp_tool = linphone_core_get_user_agent(call->core); - - if (call->videostream == NULL){ - int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0); - int dscp=linphone_core_get_video_dscp(lc); - const char *display_filter=linphone_core_get_video_display_filter(lc); - - if (call->sessions[call->main_video_stream_index].rtp_session==NULL){ - SalMulticastRole multicast_role = linphone_call_get_multicast_role(call,SalVideo); - SalMediaDescription *remotedesc=NULL; - SalStreamDescription *stream_desc = NULL; - if (call->op) remotedesc = sal_call_get_remote_media_description(call->op); - if (remotedesc) - stream_desc = sal_media_description_find_best_stream(remotedesc, SalVideo); - - call->videostream=video_stream_new2(lc->factory, linphone_call_get_bind_ip_for_stream(call,call->main_video_stream_index), - multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[call->main_video_stream_index].rtp_port, - multicast_role == SalMulticastReceiver ? 0 /*disabled for now*/ : call->media_ports[call->main_video_stream_index].rtcp_port); - if (multicast_role == SalMulticastReceiver) - linphone_call_join_multicast_group(call, call->main_video_stream_index, &call->videostream->ms); - rtp_session_enable_network_simulation(call->videostream->ms.sessions.rtp_session, &lc->net_conf.netsim_params); - apply_jitter_buffer_params(lc, call->videostream->ms.sessions.rtp_session, LinphoneStreamTypeVideo); - cname = linphone_address_as_string_uri_only(call->me); - video_stream_set_rtcp_information(call->videostream, cname, rtcp_tool); - ms_free(cname); - rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc)); - setup_dtls_params(call, &call->videostream->ms); - /* init zrtp even if we didn't explicitely set it, just in case peer offers it */ - if (linphone_core_media_encryption_supported(lc, LinphoneMediaEncryptionZRTP)) { - video_stream_enable_zrtp(call->videostream, call->audiostream); - } - - media_stream_reclaim_sessions(&call->videostream->ms, &call->sessions[call->main_video_stream_index]); - }else{ - call->videostream=video_stream_new_with_sessions(lc->factory, &call->sessions[call->main_video_stream_index]); - } - - if (call->media_ports[call->main_video_stream_index].rtp_port==-1){ - port_config_set_random_choosed(call,call->main_video_stream_index,call->videostream->ms.sessions.rtp_session); - } - if (dscp!=-1) - video_stream_set_dscp(call->videostream,dscp); - video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0)); - if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.sessions.rtp_session,video_recv_buf_size); - - if (display_filter != NULL) - video_stream_set_display_filter_name(call->videostream,display_filter); - video_stream_set_event_callback(call->videostream,video_stream_event_cb, call); - - if (lc->rtptf){ - RtpTransport *meta_rtp; - RtpTransport *meta_rtcp; - - rtp_session_get_transports(call->videostream->ms.sessions.rtp_session,&meta_rtp,&meta_rtcp); - if (meta_rtp_transport_get_endpoint(meta_rtp) == NULL) { - ms_message("LinphoneCall[%p]: using custom video RTP transport endpoint.", call); - meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->media_ports[call->main_video_stream_index].rtp_port)); - } - if (meta_rtp_transport_get_endpoint(meta_rtcp) == NULL) { - meta_rtp_transport_set_endpoint(meta_rtcp,lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->media_ports[call->main_video_stream_index].rtcp_port)); - } - } - call->videostream_app_evq = ortp_ev_queue_new(); - rtp_session_register_event_queue(call->videostream->ms.sessions.rtp_session,call->videostream_app_evq); - _linphone_call_prepare_ice_for_stream(call,call->main_video_stream_index,FALSE); -#ifdef TEST_EXT_RENDERER - video_stream_set_render_callback(call->videostream,rendercb,NULL); -#endif - } -#else - call->videostream=NULL; -#endif -} - -void linphone_call_init_text_stream(LinphoneCall *call){ - TextStream *textstream; - LinphoneCore *lc=call->core; - char* cname; - - if (call->textstream != NULL) return; - if (call->sessions[call->main_text_stream_index].rtp_session == NULL) { - SalMulticastRole multicast_role = linphone_call_get_multicast_role(call, SalText); - SalMediaDescription *remotedesc = NULL; - SalStreamDescription *stream_desc = NULL; - if (call->op) remotedesc = sal_call_get_remote_media_description(call->op); - if (remotedesc) stream_desc = sal_media_description_find_best_stream(remotedesc, SalText); - - call->textstream = textstream = text_stream_new2(lc->factory, linphone_call_get_bind_ip_for_stream(call,call->main_text_stream_index), - multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[call->main_text_stream_index].rtp_port, - multicast_role == SalMulticastReceiver ? 0 /*disabled for now*/ : call->media_ports[call->main_text_stream_index].rtcp_port); - if (multicast_role == SalMulticastReceiver) - linphone_call_join_multicast_group(call, call->main_text_stream_index, &textstream->ms); - rtp_session_enable_network_simulation(call->textstream->ms.sessions.rtp_session, &lc->net_conf.netsim_params); - apply_jitter_buffer_params(lc, call->textstream->ms.sessions.rtp_session, LinphoneStreamTypeText); - cname = linphone_address_as_string_uri_only(call->me); - ms_free(cname); - rtp_session_set_symmetric_rtp(textstream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc)); - setup_dtls_params(call, &textstream->ms); - media_stream_reclaim_sessions(&textstream->ms, &call->sessions[call->main_text_stream_index]); - } else { - call->textstream = text_stream_new_with_sessions(lc->factory, &call->sessions[call->main_text_stream_index]); - } - textstream = call->textstream; - if (call->media_ports[call->main_text_stream_index].rtp_port == -1) { - port_config_set_random_choosed(call, call->main_text_stream_index, textstream->ms.sessions.rtp_session); - } - - if (lc->rtptf){ - RtpTransport *meta_rtp; - RtpTransport *meta_rtcp; - - rtp_session_get_transports(textstream->ms.sessions.rtp_session, &meta_rtp, &meta_rtcp); - if (meta_rtp_transport_get_endpoint(meta_rtp) == NULL) { - meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->media_ports[call->main_text_stream_index].rtp_port)); - } - if (meta_rtp_transport_get_endpoint(meta_rtcp) == NULL) { - meta_rtp_transport_set_endpoint(meta_rtcp,lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->media_ports[call->main_text_stream_index].rtcp_port)); - } - } - - call->textstream_app_evq = ortp_ev_queue_new(); - rtp_session_register_event_queue(textstream->ms.sessions.rtp_session, call->textstream_app_evq); - - _linphone_call_prepare_ice_for_stream(call, call->main_text_stream_index, FALSE); + linphone_call_get_cpp_obj(call)->setNextVideoFrameDecodedCallback(cb, user_data); } void linphone_call_init_media_streams(LinphoneCall *call){ - linphone_call_init_audio_stream(call); - linphone_call_init_video_stream(call); - linphone_call_init_text_stream(call); } - static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'}; static void linphone_core_dtmf_received(LinphoneCall *call, int dtmf){ @@ -2949,50 +649,6 @@ static void linphone_core_dtmf_received(LinphoneCall *call, int dtmf){ linphone_call_notify_dtmf_received(call, dtmf_tab[dtmf]); } -static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){ - const char *eq_active = lp_config_get_string(lc->config, "sound", "eq_active", NULL); - const char *eq_gains = lp_config_get_string(lc->config, "sound", "eq_gains", NULL); - - if(eq_active) ms_warning("'eq_active' linphonerc parameter has not effect anymore. Please use 'mic_eq_active' or 'spk_eq_active' instead"); - if(eq_gains) ms_warning("'eq_gains' linphonerc parameter has not effect anymore. Please use 'mic_eq_gains' or 'spk_eq_gains' instead"); - if (st->mic_equalizer){ - MSFilter *f=st->mic_equalizer; - int enabled=lp_config_get_int(lc->config,"sound","mic_eq_active",0); - const char *gains=lp_config_get_string(lc->config,"sound","mic_eq_gains",NULL); - ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled); - if (enabled && gains){ - bctbx_list_t *gains_list = ms_parse_equalizer_string(gains); - bctbx_list_t *it; - for(it=gains_list; it; it=it->next) { - MSEqualizerGain *g = (MSEqualizerGain *)it->data; - ms_message("Read microphone equalizer gains: %f(~%f) --> %f",g->frequency,g->width,g->gain); - ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN, g); - } - if(gains_list) bctbx_list_free_with_data(gains_list, ms_free); - } - } - if (st->spk_equalizer){ - MSFilter *f=st->spk_equalizer; - int enabled=lp_config_get_int(lc->config,"sound","spk_eq_active",0); - const char *gains=lp_config_get_string(lc->config,"sound","spk_eq_gains",NULL); - ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled); - if (enabled && gains){ - bctbx_list_t *gains_list = ms_parse_equalizer_string(gains); - bctbx_list_t *it; - for(it=gains_list; it; it=it->next) { - MSEqualizerGain *g = (MSEqualizerGain *)it->data; - ms_message("Read speaker equalizer gains: %f(~%f) --> %f",g->frequency,g->width,g->gain); - ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN, g); - } - if(gains_list) bctbx_list_free_with_data(gains_list, ms_free); - } - } -} - -void set_mic_gain_db(AudioStream *st, float gain){ - audio_stream_set_mic_gain_db(st, gain); -} - void set_playback_gain_db(AudioStream *st, float gain){ if (st->volrecv){ ms_filter_call_method(st->volrecv,MS_VOLUME_SET_DB_GAIN,&gain); @@ -3001,183 +657,6 @@ void set_playback_gain_db(AudioStream *st, float gain){ /*This function is not static because used internally in linphone-daemon project*/ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){ - float mic_gain=lc->sound_conf.soft_mic_lev; - float thres = 0; - float recv_gain; - float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05f); - float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0); - int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0); - float speed; - float force; - int sustain; - float transmit_thres; - MSFilter *f=NULL; - float floorgain; - int spk_agc; - - if (!muted) - set_mic_gain_db(st,mic_gain); - else - audio_stream_set_mic_gain(st,0); - - recv_gain = lc->sound_conf.soft_play_lev; - if (recv_gain != 0) { - set_playback_gain_db(st,recv_gain); - } - - if (st->volsend){ - ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal); - speed=lp_config_get_float(lc->config,"sound","el_speed",-1); - thres=lp_config_get_float(lc->config,"sound","el_thres",-1); - force=lp_config_get_float(lc->config,"sound","el_force",-1); - sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1); - transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1); - f=st->volsend; - if (speed==-1) speed=0.03f; - if (force==-1) force=25; - ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed); - ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force); - if (thres!=-1) - ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres); - if (sustain!=-1) - ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain); - if (transmit_thres!=-1) - ms_filter_call_method(f,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&transmit_thres); - - ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres); - ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain); - } - if (st->volrecv){ - /* parameters for a limited noise-gate effect, using echo limiter threshold */ - floorgain = (float)(1/pow(10,mic_gain/10)); - spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0); - ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc); - ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres); - ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain); - } - parametrize_equalizer(lc,st); -} - -static void post_configure_audio_streams(LinphoneCall *call, bool_t muted){ - AudioStream *st=call->audiostream; - LinphoneCore *lc=call->core; - _post_configure_audio_stream(st,lc,muted); - if (linphone_core_dtmf_received_has_listener(lc)){ - audio_stream_play_received_dtmfs(call->audiostream,FALSE); - } - if (call->record_active) - linphone_call_start_recording(call); -} - -static int get_ideal_audio_bw(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc){ - int remote_bw=0; - int upload_bw; - int total_upload_bw=linphone_core_get_upload_bandwidth(call->core); - const LinphoneCallParams *params=call->params; - bool_t will_use_video=linphone_core_media_description_contains_video_stream(md); - bool_t forced=FALSE; - - if (desc->bandwidth>0) remote_bw=desc->bandwidth; - else if (md->bandwidth>0) { - /*case where b=AS is given globally, not per stream*/ - remote_bw=md->bandwidth; - } - if (linphone_call_params_get_up_bandwidth(params)>0){ - forced=TRUE; - upload_bw=linphone_call_params_get_up_bandwidth(params); - }else upload_bw=total_upload_bw; - upload_bw=get_min_bandwidth(upload_bw,remote_bw); - if (!will_use_video || forced) return upload_bw; - - if (bandwidth_is_greater(upload_bw,512)){ - upload_bw=100; - }else if (bandwidth_is_greater(upload_bw,256)){ - upload_bw=64; - }else if (bandwidth_is_greater(upload_bw,128)){ - upload_bw=40; - }else if (bandwidth_is_greater(upload_bw,0)){ - upload_bw=24; - } - return upload_bw; -} - -static int get_video_bw(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc){ - int remote_bw=0; - int bw; - if (desc->bandwidth>0) remote_bw=desc->bandwidth; - else if (md->bandwidth>0) { - /*case where b=AS is given globally, not per stream*/ - remote_bw=get_remaining_bandwidth_for_video(md->bandwidth,call->audio_bw); - } else { - remote_bw = lp_config_get_int(call->core->config, "net", "default_max_bandwidth", 1500); - } - bw=get_min_bandwidth(get_remaining_bandwidth_for_video(linphone_core_get_upload_bandwidth(call->core),call->audio_bw),remote_bw); - return bw; -} - -static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){ - int bw=0; - const bctbx_list_t *elem; - RtpProfile *prof=rtp_profile_new("Call profile"); - bool_t first=TRUE; - LinphoneCore *lc=call->core; - int up_ptime=0; - const LinphoneCallParams *params=call->params; - - *used_pt=-1; - - if (desc->type==SalAudio) - bw=get_ideal_audio_bw(call,md,desc); - else if (desc->type==SalVideo) - bw=get_video_bw(call,md,desc); - //else if (desc->type== SalText) - - - for(elem=desc->payloads;elem!=NULL;elem=elem->next){ - PayloadType *pt=(PayloadType*)elem->data; - int number; - /* make a copy of the payload type, so that we left the ones from the SalStreamDescription unchanged. - If the SalStreamDescription is freed, this will have no impact on the running streams*/ - pt=payload_type_clone(pt); - - if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) { - /*first codec in list is the selected one*/ - if (desc->type==SalAudio){ - /*this will update call->audio_bw*/ - linphone_core_update_allocated_audio_bandwidth_in_call(call,pt,bw); - bw=call->audio_bw; - if (linphone_call_params_get_up_ptime(params)) - up_ptime=linphone_call_params_get_up_ptime(params); - else up_ptime=linphone_core_get_upload_ptime(lc); - } - first=FALSE; - } - if (*used_pt == -1){ - /*don't select telephone-event as a payload type*/ - if (strcasecmp(pt->mime_type, "telephone-event") != 0){ - *used_pt = payload_type_get_number(pt); - } - } - - if (pt->flags & PAYLOAD_TYPE_BITRATE_OVERRIDE){ - ms_message("Payload type [%s/%i] has explicit bitrate [%i] kbit/s", pt->mime_type, pt->clock_rate, pt->normal_bitrate/1000); - pt->normal_bitrate=get_min_bandwidth(pt->normal_bitrate,bw*1000); - } else pt->normal_bitrate=bw*1000; - if (desc->ptime>0){ - up_ptime=desc->ptime; - } - if (up_ptime>0){ - char tmp[40]; - snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime); - payload_type_append_send_fmtp(pt,tmp); - } - number=payload_type_get_number(pt); - if (rtp_profile_get_payload(prof,number)!=NULL){ - ms_warning("A payload type with number %i already exists in profile !",number); - }else - rtp_profile_set_payload(prof,number,pt); - } - return prof; } static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){ @@ -3193,1108 +672,61 @@ static bool_t linphone_call_sound_resources_available(LinphoneCall *call){ (current==NULL || current==call); } -static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) { - int i; - for(i=0; itype == SalAudio) { - session = call->audiostream->ms.sessions.rtp_session; - } else if (stream->type == SalVideo) { - session = call->videostream->ms.sessions.rtp_session; - } else { - // Do nothing for streams that are not audio or video - return; - } - if (stream->rtcp_fb.generic_nack_enabled) - rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_GENERIC_NACK, TRUE); - else - rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_GENERIC_NACK, FALSE); - if (stream->rtcp_fb.tmmbr_enabled) - rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_TMMBR, TRUE); - else - rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_TMMBR, FALSE); -} - -static void configure_rtp_session_for_rtcp_xr(LinphoneCore *lc, LinphoneCall *call, SalStreamType type) { - RtpSession *session = NULL; - const OrtpRtcpXrConfiguration *localconfig; - const OrtpRtcpXrConfiguration *remoteconfig; - OrtpRtcpXrConfiguration currentconfig; - const SalStreamDescription *localstream; - const SalStreamDescription *remotestream; - SalMediaDescription *remotedesc = sal_call_get_remote_media_description(call->op); - - if (!remotedesc) return; - - localstream = sal_media_description_find_best_stream(call->localdesc, type); - if (!localstream) return; - localconfig = &localstream->rtcp_xr; - remotestream = sal_media_description_find_best_stream(remotedesc, type); - if (!remotestream) return; - remoteconfig = &remotestream->rtcp_xr; - - if (localstream->dir == SalStreamInactive) return; - else if (localstream->dir == SalStreamRecvOnly) { - /* Use local config for unilateral parameters and remote config for collaborative parameters. */ - memcpy(¤tconfig, localconfig, sizeof(currentconfig)); - currentconfig.rcvr_rtt_mode = remoteconfig->rcvr_rtt_mode; - currentconfig.rcvr_rtt_max_size = remoteconfig->rcvr_rtt_max_size; - } else { - memcpy(¤tconfig, remoteconfig, sizeof(currentconfig)); - } - if (type == SalAudio) { - session = call->audiostream->ms.sessions.rtp_session; - } else if (type == SalVideo) { - session = call->videostream->ms.sessions.rtp_session; - } else if (type == SalText) { - session = call->textstream->ms.sessions.rtp_session; - } - rtp_session_configure_rtcp_xr(session, ¤tconfig); -} - -static void start_dtls( MSMediaStreamSessions *sessions, const SalStreamDescription *sd,const SalStreamDescription *remote) { - if (sal_stream_description_has_dtls(sd) == TRUE) { - /*DTLS*/ - SalDtlsRole salRole = sd->dtls_role; - if (salRole!=SalDtlsRoleInvalid) { /* if DTLS is available at both end points */ - /* give the peer certificate fingerprint to dtls context */ - ms_dtls_srtp_set_peer_fingerprint(sessions->dtls_context, remote->dtls_fingerprint); - ms_dtls_srtp_set_role(sessions->dtls_context, (salRole == SalDtlsRoleIsClient)?MSDtlsSrtpRoleIsClient:MSDtlsSrtpRoleIsServer); /* set the role to client */ - ms_dtls_srtp_start(sessions->dtls_context); /* then start the engine, it will send the DTLS client Hello */ - } else { - ms_warning("unable to start DTLS engine on stream session [%p], Dtls role in resulting media description is invalid",sessions); - } - } -} - -static void start_dtls_on_all_streams(LinphoneCall *call) { - SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op); - SalMediaDescription *result_desc = sal_call_get_final_media_description(call->op); - if( remote_desc == NULL || result_desc == NULL ){ - /* this can happen in some tricky cases (early-media without SDP in the 200). In that case, simply skip DTLS code */ - return; - } - - if (call->audiostream && (media_stream_get_state((const MediaStream *)call->audiostream) == MSStreamStarted))/*dtls must start at the end of ice*/ - start_dtls(&call->audiostream->ms.sessions - ,sal_media_description_find_best_stream(result_desc,SalAudio) - ,sal_media_description_find_best_stream(remote_desc,SalAudio)); -#if VIDEO_ENABLED - if (call->videostream && (media_stream_get_state((const MediaStream *)call->videostream) == MSStreamStarted))/*dtls must start at the end of ice*/ - start_dtls(&call->videostream->ms.sessions - ,sal_media_description_find_best_stream(result_desc,SalVideo) - ,sal_media_description_find_best_stream(remote_desc,SalVideo)); -#endif - if (call->textstream && (media_stream_get_state((const MediaStream *)call->textstream) == MSStreamStarted))/*dtls must start at the end of ice*/ - start_dtls(&call->textstream->ms.sessions - ,sal_media_description_find_best_stream(result_desc,SalText) - ,sal_media_description_find_best_stream(remote_desc,SalText)); - return; -} - -static void set_dtls_fingerprint( MSMediaStreamSessions *sessions, const SalStreamDescription *sd,const SalStreamDescription *remote) { - if (sal_stream_description_has_dtls(sd) == TRUE) { - /*DTLS*/ - SalDtlsRole salRole = sd->dtls_role; - if (salRole!=SalDtlsRoleInvalid) { /* if DTLS is available at both end points */ - /* give the peer certificate fingerprint to dtls context */ - ms_dtls_srtp_set_peer_fingerprint(sessions->dtls_context, remote->dtls_fingerprint); - } else { - ms_warning("unable to start DTLS engine on stream session [%p], Dtls role in resulting media description is invalid",sessions); - } - } -} - -static void set_dtls_fingerprint_on_all_streams(LinphoneCall *call) { - SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op); - SalMediaDescription *result_desc = sal_call_get_final_media_description(call->op); - - if( remote_desc == NULL || result_desc == NULL ){ - /* this can happen in some tricky cases (early-media without SDP in the 200). In that case, simply skip DTLS code */ - return; - } - - if (call->audiostream && (media_stream_get_state((const MediaStream *)call->audiostream) == MSStreamStarted))/*dtls must start at the end of ice*/ - set_dtls_fingerprint(&call->audiostream->ms.sessions - ,sal_media_description_find_best_stream(result_desc,SalAudio) - ,sal_media_description_find_best_stream(remote_desc,SalAudio)); -#if VIDEO_ENABLED - if (call->videostream && (media_stream_get_state((const MediaStream *)call->videostream) == MSStreamStarted))/*dtls must start at the end of ice*/ - set_dtls_fingerprint(&call->videostream->ms.sessions - ,sal_media_description_find_best_stream(result_desc,SalVideo) - ,sal_media_description_find_best_stream(remote_desc,SalVideo)); -#endif - if (call->textstream && (media_stream_get_state((const MediaStream *)call->textstream) == MSStreamStarted))/*dtls must start at the end of ice*/ - set_dtls_fingerprint(&call->textstream->ms.sessions - ,sal_media_description_find_best_stream(result_desc,SalText) - ,sal_media_description_find_best_stream(remote_desc,SalText)); - return; -} - -static RtpSession * create_audio_rtp_io_session(LinphoneCall *call) { - PayloadType *pt; - LinphoneCore *lc = call->core; - const char *local_ip = lp_config_get_string(lc->config, "sound", "rtp_local_addr", "127.0.0.1"); - const char *remote_ip = lp_config_get_string(lc->config, "sound", "rtp_remote_addr", "127.0.0.1"); - int local_port = lp_config_get_int(lc->config, "sound", "rtp_local_port", 17076); - int remote_port = lp_config_get_int(lc->config, "sound", "rtp_remote_port", 17078); - int ptnum = lp_config_get_int(lc->config, "sound", "rtp_ptnum", 0); - const char *rtpmap = lp_config_get_string(lc->config, "sound", "rtp_map", "pcmu/8000/1"); - int symmetric = lp_config_get_int(lc->config, "sound", "rtp_symmetric", 0); - int jittcomp = lp_config_get_int(lc->config, "sound", "rtp_jittcomp", 0); /* 0 means no jitter buffer*/ - RtpSession *rtp_session = NULL; - pt = rtp_profile_get_payload_from_rtpmap(call->audio_profile, rtpmap); - if (pt != NULL) { - call->rtp_io_audio_profile = rtp_profile_new("RTP IO audio profile"); - rtp_profile_set_payload(call->rtp_io_audio_profile, ptnum, payload_type_clone(pt)); - rtp_session = ms_create_duplex_rtp_session(local_ip, local_port, -1, ms_factory_get_mtu(lc->factory)); - rtp_session_set_profile(rtp_session, call->rtp_io_audio_profile); - rtp_session_set_remote_addr_and_port(rtp_session, remote_ip, remote_port, -1); - rtp_session_enable_rtcp(rtp_session, FALSE); - rtp_session_set_payload_type(rtp_session, ptnum); - rtp_session_set_jitter_compensation(rtp_session, jittcomp); - rtp_session_enable_jitter_buffer(rtp_session, jittcomp>0); - rtp_session_set_symmetric_rtp(rtp_session, (bool_t)symmetric); - } - return rtp_session; -} - -static void linphone_call_set_on_hold_file(LinphoneCall *call, const char *file){ - if (call->onhold_file){ - ms_free(call->onhold_file); - call->onhold_file = NULL; - } - if (file){ - call->onhold_file = ms_strdup(file); - } -} - -static void configure_adaptive_rate_control(LinphoneCall *call, MediaStream *ms, PayloadType *pt, bool_t video_will_be_used){ - LinphoneCore *lc = call->core; - bool_t enabled = linphone_core_adaptive_rate_control_enabled(lc); - - if (enabled){ - const char *algo = linphone_core_get_adaptive_rate_algorithm(lc); - bool_t is_advanced = TRUE; - if (strcasecmp(algo, "basic") == 0) is_advanced = FALSE; - else if (strcasecmp(algo, "advanced") == 0) is_advanced = TRUE; - - if (is_advanced){ - /*we can't use media_stream_avpf_enabled() here because the active PayloadType is not set yet in the MediaStream.*/ - if (!pt || !(pt->flags & PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED)){ - ms_warning("LinphoneCall[%p] - advanced adaptive rate control requested but avpf is not activated in this stream. Reverting to basic rate control instead.", call); - is_advanced = FALSE; - }else{ - ms_message("LinphoneCall[%p] - setting up advanced rate control.", call); - } - } - - if (is_advanced){ - ms_bandwidth_controller_add_stream(lc->bw_controller, ms); - media_stream_enable_adaptive_bitrate_control(ms, FALSE); - }else{ - media_stream_set_adaptive_bitrate_algorithm(ms, MSQosAnalyzerAlgorithmSimple); - if (ms->type == MSAudio && video_will_be_used){ - enabled = FALSE; /*if this is an audio stream but video is going to be used, there is - no need to perform basic rate control on the audio stream, just the video stream.*/ - } - media_stream_enable_adaptive_bitrate_control(ms, enabled); - } - }else{ - media_stream_enable_adaptive_bitrate_control(ms, FALSE); - } -} - -static void linphone_call_start_audio_stream(LinphoneCall *call, LinphoneCallState next_state, bool_t video_will_be_used){ - LinphoneCore *lc=call->core; - int used_pt=-1; - const SalStreamDescription *stream; - MSSndCard *playcard; - MSSndCard *captcard; - bool_t use_ec; - bool_t mute; - const char *playfile; - const char *recfile; - const char *file_to_play = NULL; - const SalStreamDescription *local_st_desc; - int crypto_idx; - MSMediaStreamIO io = MS_MEDIA_STREAM_IO_INITIALIZER; - bool_t use_rtp_io = lp_config_get_int(lc->config, "sound", "rtp_io", FALSE); - bool_t use_rtp_io_enable_local_output = lp_config_get_int(lc->config, "sound", "rtp_io_enable_local_output", FALSE); - - stream = sal_media_description_find_best_stream(call->resultdesc, SalAudio); - if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){ - /* get remote stream description to check for zrtp-hash presence */ - SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op); - const SalStreamDescription *remote_stream = sal_media_description_find_best_stream(remote_desc, SalAudio); - - const char *rtp_addr=stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr; - bool_t is_multicast=ms_is_multicast(rtp_addr); - playcard=lc->sound_conf.lsd_card ? - lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; - captcard=lc->sound_conf.capt_sndcard; - playfile=lc->play_file; - recfile=lc->rec_file; - call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt); - - if (used_pt!=-1){ - bool_t ok = TRUE; - linphone_call_params_set_used_audio_codec(call->current_params, rtp_profile_get_payload(call->audio_profile, used_pt)); - linphone_call_params_enable_audio(call->current_params, TRUE); - if (playcard==NULL) { - ms_warning("No card defined for playback !"); - } - if (captcard==NULL) { - ms_warning("No card defined for capture !"); - } - /*Don't use file or soundcard capture when placed in recv-only mode*/ - if (stream->rtp_port==0 - || stream->dir==SalStreamRecvOnly - || (stream->multicast_role == SalMulticastReceiver && is_multicast)){ - captcard=NULL; - playfile=NULL; - } - if (next_state == LinphoneCallPaused){ - /*in paused state, we never use soundcard*/ - playcard=NULL; - captcard=NULL; - recfile=NULL; - /*And we will eventually play "playfile" if set by the user*/ - } - if (call->playing_ringbacktone){ - captcard=NULL; - playfile=NULL;/* it is setup later*/ - if (lp_config_get_int(lc->config,"sound","send_ringback_without_playback", 0) == 1){ - playcard = NULL; - recfile = NULL; - } - } - /*if playfile are supplied don't use soundcards*/ - if (lc->use_files || (use_rtp_io && !use_rtp_io_enable_local_output)) { - captcard=NULL; - playcard=NULL; - } - if (linphone_call_params_get_in_conference(call->params)){ - /* first create the graph without soundcard resources*/ - captcard=playcard=NULL; - } - if (!linphone_call_sound_resources_available(call)){ - ms_message("Sound resources are used by another call, not using soundcard."); - captcard=playcard=NULL; - } - use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc); - audio_stream_enable_echo_canceller(call->audiostream, use_ec); - if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate); - if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate); - - rtp_session_enable_rtcp_mux(call->audiostream->ms.sessions.rtp_session, stream->rtcp_mux); - if (!linphone_call_params_get_in_conference(call->params) && linphone_call_params_get_record_file(call->params)){ - audio_stream_mixed_record_open(call->audiostream,linphone_call_params_get_record_file(call->params)); - linphone_call_params_set_record_file(call->current_params, linphone_call_params_get_record_file(call->params)); - } - /* valid local tags are > 0 */ - if (sal_stream_description_has_srtp(stream) == TRUE) { - local_st_desc=sal_media_description_find_stream(call->localdesc,stream->proto,SalAudio); - crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag); - - if (crypto_idx >= 0) { - ms_media_stream_sessions_set_srtp_recv_key_b64(&call->audiostream->ms.sessions, stream->crypto[0].algo,stream->crypto[0].master_key); - ms_media_stream_sessions_set_srtp_send_key_b64(&call->audiostream->ms.sessions, stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key); - } else { - ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag); - } - } - configure_rtp_session_for_rtcp_fb(call, stream); - configure_rtp_session_for_rtcp_xr(lc, call, SalAudio); - configure_adaptive_rate_control(call, (MediaStream*)call->audiostream, (PayloadType *)linphone_call_params_get_used_audio_codec(call->current_params), video_will_be_used); - if (is_multicast) - rtp_session_set_multicast_ttl(call->audiostream->ms.sessions.rtp_session,stream->ttl); - - if (use_rtp_io) { - if(use_rtp_io_enable_local_output){ - io.input.type = MSResourceRtp; - io.input.session = create_audio_rtp_io_session(call); - - if (playcard){ - io.output.type = MSResourceSoundcard; - io.output.soundcard = playcard; - }else{ - io.output.type = MSResourceFile; - io.output.file = recfile; - } - } - else { - io.input.type = io.output.type = MSResourceRtp; - io.input.session = io.output.session = create_audio_rtp_io_session(call); - } - - if (io.input.session == NULL) { - ok = FALSE; - } - }else { - if (playcard){ - io.output.type = MSResourceSoundcard; - io.output.soundcard = playcard; - }else{ - io.output.type = MSResourceFile; - io.output.file = recfile; - } - if (captcard){ - io.input.type = MSResourceSoundcard; - io.input.soundcard = captcard; - }else{ - io.input.type = MSResourceFile; - file_to_play = playfile; - io.input.file = NULL; /*we prefer to use the remote_play api, that allows to play multimedia files */ - } - - } - if (ok == TRUE) { - int err = audio_stream_start_from_io(call->audiostream, - call->audio_profile, - rtp_addr, - stream->rtp_port, - stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr, - (linphone_core_rtcp_enabled(lc) && !is_multicast) ? (stream->rtcp_port ? stream->rtcp_port : stream->rtp_port+1) : 0, - used_pt, - &io); - if (err == 0){ - post_configure_audio_streams(call, (call->all_muted || call->audio_muted) && !call->playing_ringbacktone); - } - } - - ms_media_stream_sessions_set_encryption_mandatory(&call->audiostream->ms.sessions, linphone_call_encryption_mandatory(call)); - - if (next_state == LinphoneCallPaused && captcard == NULL && playfile != NULL){ - int pause_time=500; - ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time); - } - if (call->playing_ringbacktone){ - setup_ring_player(lc,call); - } - - if (linphone_call_params_get_in_conference(call->params) && lc->conf_ctx){ - /*transform the graph to connect it to the conference filter */ - mute = stream->dir==SalStreamRecvOnly; - linphone_conference_on_call_stream_starting(lc->conf_ctx, call, mute); - } - linphone_call_params_set_in_conference(call->current_params, linphone_call_params_get_in_conference(call->params)); - linphone_call_params_enable_low_bandwidth(call->current_params, linphone_call_params_low_bandwidth_enabled(call->params)); - - /* start ZRTP engine if needed : set here or remote have a zrtp-hash attribute */ - if (linphone_core_media_encryption_supported(lc, LinphoneMediaEncryptionZRTP) && - (linphone_call_params_get_media_encryption(call->params) == LinphoneMediaEncryptionZRTP || remote_stream->haveZrtpHash==1) ){ - audio_stream_start_zrtp(call->audiostream); - if (remote_stream->haveZrtpHash == 1) { - int retval; - if ((retval = ms_zrtp_setPeerHelloHash(call->audiostream->ms.sessions.zrtp_context, (uint8_t *)remote_stream->zrtphash, strlen((const char *)(remote_stream->zrtphash)))) != 0) { - ms_error("Zrtp hash mismatch 0x%x", retval); - } - } - } - }else ms_warning("No audio stream accepted ?"); - } - linphone_call_set_on_hold_file(call, file_to_play); -} - -#ifdef VIDEO_ENABLED -static RtpSession * create_video_rtp_io_session(LinphoneCall *call) { - PayloadType *pt; - LinphoneCore *lc = call->core; - const char *local_ip = lp_config_get_string(lc->config, "video", "rtp_local_addr", "127.0.0.1"); - const char *remote_ip = lp_config_get_string(lc->config, "video", "rtp_remote_addr", "127.0.0.1"); - int local_port = lp_config_get_int(lc->config, "video", "rtp_local_port", 19076); - int remote_port = lp_config_get_int(lc->config, "video", "rtp_remote_port", 19078); - int ptnum = lp_config_get_int(lc->config, "video", "rtp_ptnum", 0); - const char *rtpmap = lp_config_get_string(lc->config, "video", "rtp_map", "vp8/90000/1"); - int symmetric = lp_config_get_int(lc->config, "video", "rtp_symmetric", 0); - int jittcomp = lp_config_get_int(lc->config, "video", "rtp_jittcomp", 0); /* 0 means no jitter buffer*/ - RtpSession *rtp_session = NULL; - pt = rtp_profile_get_payload_from_rtpmap(call->video_profile, rtpmap); - if (pt != NULL) { - call->rtp_io_video_profile = rtp_profile_new("RTP IO video profile"); - rtp_profile_set_payload(call->rtp_io_video_profile, ptnum, payload_type_clone(pt)); - rtp_session = ms_create_duplex_rtp_session(local_ip, local_port, -1, ms_factory_get_mtu(lc->factory)); - rtp_session_set_profile(rtp_session, call->rtp_io_video_profile); - rtp_session_set_remote_addr_and_port(rtp_session, remote_ip, remote_port, -1); - rtp_session_enable_rtcp(rtp_session, FALSE); - rtp_session_set_payload_type(rtp_session, ptnum); - rtp_session_set_symmetric_rtp(rtp_session, (bool_t)symmetric); - rtp_session_set_jitter_compensation(rtp_session, jittcomp); - rtp_session_enable_jitter_buffer(rtp_session, jittcomp>0); - } - return rtp_session; -} -#endif - -static void linphone_call_start_video_stream(LinphoneCall *call, LinphoneCallState next_state){ -#ifdef VIDEO_ENABLED - LinphoneCore *lc=call->core; - int used_pt=-1; - const SalStreamDescription *vstream; - MSFilter* source = NULL; - bool_t reused_preview = FALSE; - bool_t use_rtp_io = lp_config_get_int(lc->config, "video", "rtp_io", FALSE); - MSMediaStreamIO io = MS_MEDIA_STREAM_IO_INITIALIZER; - - /* shutdown preview */ - if (lc->previewstream!=NULL) { - if( lc->video_conf.reuse_preview_source == FALSE) video_preview_stop(lc->previewstream); - else source = video_preview_stop_reuse_source(lc->previewstream); - lc->previewstream=NULL; - } - - vstream = sal_media_description_find_best_stream(call->resultdesc, SalVideo); - if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) { - const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr; - const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr; - const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,vstream->proto,SalVideo); - bool_t is_multicast=ms_is_multicast(rtp_addr); - call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt); - - if (used_pt!=-1){ - MediaStreamDir dir= MediaStreamSendRecv; - bool_t is_inactive=FALSE; - MSWebCam *cam; - - linphone_call_params_set_used_video_codec(call->current_params, rtp_profile_get_payload(call->video_profile, used_pt)); - linphone_call_params_enable_video(call->current_params, TRUE); - - rtp_session_enable_rtcp_mux(call->videostream->ms.sessions.rtp_session, vstream->rtcp_mux); - if (lc->video_conf.preview_vsize.width!=0) - video_stream_set_preview_size(call->videostream,lc->video_conf.preview_vsize); - video_stream_set_fps(call->videostream,linphone_core_get_preferred_framerate(lc)); - if (lp_config_get_int(lc->config, "video", "nowebcam_uses_normal_fps", 0)) - call->videostream->staticimage_webcam_fps_optimization = FALSE; - video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc)); - video_stream_enable_self_view(call->videostream,lc->video_conf.selfview); - if (call->video_window_id != NULL) - video_stream_set_native_window_id(call->videostream, call->video_window_id); - else if (lc->video_window_id != NULL) - video_stream_set_native_window_id(call->videostream, lc->video_window_id); - if (lc->preview_window_id != NULL) - video_stream_set_native_preview_window_id(call->videostream, lc->preview_window_id); - video_stream_use_preview_video_window (call->videostream,lc->use_preview_window); - - if (is_multicast){ - if (vstream->multicast_role == SalMulticastReceiver) - dir=MediaStreamRecvOnly; - else - dir=MediaStreamSendOnly; - } else if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){ - dir=MediaStreamSendOnly; - }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){ - dir=MediaStreamRecvOnly; - }else if (vstream->dir==SalStreamSendRecv){ - if (lc->video_conf.display && lc->video_conf.capture) - dir=MediaStreamSendRecv; - else if (lc->video_conf.display) - dir=MediaStreamRecvOnly; - else - dir=MediaStreamSendOnly; - }else{ - ms_warning("video stream is inactive."); - /*either inactive or incompatible with local capabilities*/ - is_inactive=TRUE; - } - cam = linphone_call_get_video_device(call); - if (!is_inactive){ - /* get remote stream description to check for zrtp-hash presence */ - SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op); - const SalStreamDescription *remote_stream = sal_media_description_find_best_stream(remote_desc, SalVideo); - - if (sal_stream_description_has_srtp(vstream) == TRUE) { - int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, vstream->crypto_local_tag); - if (crypto_idx >= 0) { - ms_media_stream_sessions_set_srtp_recv_key_b64(&call->videostream->ms.sessions, vstream->crypto[0].algo,vstream->crypto[0].master_key); - ms_media_stream_sessions_set_srtp_send_key_b64(&call->videostream->ms.sessions, vstream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key); - } - } - configure_rtp_session_for_rtcp_fb(call, vstream); - configure_rtp_session_for_rtcp_xr(lc, call, SalVideo); - configure_adaptive_rate_control(call, (MediaStream*)call->videostream, (PayloadType *)linphone_call_params_get_used_video_codec(call->current_params), TRUE); - - call->log->video_enabled = TRUE; - video_stream_set_direction (call->videostream, dir); - ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation); - video_stream_set_device_rotation(call->videostream, lc->device_rotation); - video_stream_set_freeze_on_error(call->videostream, lp_config_get_int(lc->config, "video", "freeze_on_error", 1)); - if (is_multicast) - rtp_session_set_multicast_ttl(call->videostream->ms.sessions.rtp_session,vstream->ttl); - - video_stream_use_video_preset(call->videostream, lp_config_get_string(lc->config, "video", "preset", NULL)); - if (lc->video_conf.reuse_preview_source && source) { - ms_message("video_stream_start_with_source kept: %p", source); - video_stream_start_with_source(call->videostream, - call->video_profile, rtp_addr, vstream->rtp_port, - rtcp_addr, - linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port+1) : 0, - used_pt, -1, cam, source); - reused_preview = TRUE; - } else { - bool_t ok = TRUE; - if (use_rtp_io) { - io.input.type = io.output.type = MSResourceRtp; - io.input.session = io.output.session = create_video_rtp_io_session(call); - if (io.input.session == NULL) { - ok = FALSE; - ms_warning("Cannot create video RTP IO session"); - } - } else { - io.input.type = MSResourceCamera; - io.input.camera = cam; - io.output.type = MSResourceDefault; - } - if (ok) { - video_stream_start_from_io(call->videostream, - call->video_profile, rtp_addr, vstream->rtp_port, - rtcp_addr, - (linphone_core_rtcp_enabled(lc) && !is_multicast) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port+1) : 0, - used_pt, &io); - } - } - ms_media_stream_sessions_set_encryption_mandatory(&call->videostream->ms.sessions, - linphone_call_encryption_mandatory(call)); - _linphone_call_set_next_video_frame_decoded_trigger(call); - - /* start ZRTP engine if needed : set here or remote have a zrtp-hash attribute */ - if (linphone_call_params_get_media_encryption(call->params)==LinphoneMediaEncryptionZRTP || remote_stream->haveZrtpHash==1) { - /*audio stream is already encrypted and video stream is active*/ - if (media_stream_secured((MediaStream *)call->audiostream) && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) { - video_stream_start_zrtp(call->videostream); - if (remote_stream->haveZrtpHash == 1) { - int retval; - if ((retval = ms_zrtp_setPeerHelloHash(call->videostream->ms.sessions.zrtp_context, (uint8_t *)remote_stream->zrtphash, strlen((const char *)(remote_stream->zrtphash)))) != 0) { - ms_error("video stream ZRTP hash mismatch 0x%x", retval); - } - } - } - } - } - }else ms_warning("No video stream accepted."); - }else{ - ms_message("No valid video stream defined."); - } - if( reused_preview == FALSE && source != NULL ){ - /* destroy not-reused source filter */ - ms_warning("Video preview (%p) not reused: destroying it.", source); - ms_filter_destroy(source); - } - -#endif -} - -static void real_time_text_character_received(void *userdata, struct _MSFilter *f, unsigned int id, void *arg) { - if (id == MS_RTT_4103_RECEIVED_CHAR) { - LinphoneCall *call = (LinphoneCall *)userdata; - RealtimeTextReceivedCharacter *data = (RealtimeTextReceivedCharacter *)arg; - LinphoneChatRoom * chat_room = linphone_call_get_chat_room(call); - linphone_core_real_time_text_received(call->core, chat_room, data->character, call); - } -} - -static void linphone_call_start_text_stream(LinphoneCall *call) { - LinphoneCore *lc = call->core; - int used_pt = -1; - const SalStreamDescription *tstream; - - tstream = sal_media_description_find_best_stream(call->resultdesc, SalText); - if (tstream != NULL && tstream->dir != SalStreamInactive && tstream->rtp_port != 0) { - const char *rtp_addr = tstream->rtp_addr[0] != '\0' ? tstream->rtp_addr : call->resultdesc->addr; - const char *rtcp_addr = tstream->rtcp_addr[0] != '\0' ? tstream->rtcp_addr : call->resultdesc->addr; - const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, tstream->proto, SalText); - bool_t is_multicast = ms_is_multicast(rtp_addr); - call->text_profile = make_profile(call, call->resultdesc, tstream, &used_pt); - - if (used_pt != -1) { - linphone_call_params_set_used_text_codec(call->current_params, rtp_profile_get_payload(call->text_profile, used_pt)); - linphone_call_params_enable_realtime_text(call->current_params, TRUE); - - if (sal_stream_description_has_srtp(tstream) == TRUE) { - int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, tstream->crypto_local_tag); - if (crypto_idx >= 0) { - ms_media_stream_sessions_set_srtp_recv_key_b64(&call->textstream->ms.sessions, tstream->crypto[0].algo, tstream->crypto[0].master_key); - ms_media_stream_sessions_set_srtp_send_key_b64(&call->textstream->ms.sessions, tstream->crypto[0].algo, local_st_desc->crypto[crypto_idx].master_key); - } - } - - configure_rtp_session_for_rtcp_fb(call, tstream); - configure_rtp_session_for_rtcp_xr(lc, call, SalText); - rtp_session_enable_rtcp_mux(call->textstream->ms.sessions.rtp_session, tstream->rtcp_mux); - - if (is_multicast) rtp_session_set_multicast_ttl(call->textstream->ms.sessions.rtp_session,tstream->ttl); - - text_stream_start(call->textstream, call->text_profile, rtp_addr, tstream->rtp_port, rtcp_addr, (linphone_core_rtcp_enabled(lc) && !is_multicast) ? (tstream->rtcp_port ? tstream->rtcp_port : tstream->rtp_port + 1) : 0, used_pt); - ms_filter_add_notify_callback(call->textstream->rttsink, real_time_text_character_received, call, FALSE); - - ms_media_stream_sessions_set_encryption_mandatory(&call->textstream->ms.sessions, - linphone_call_encryption_mandatory(call)); - } else ms_warning("No text stream accepted."); - } else { - ms_message("No valid text stream defined."); - } -} - -void linphone_call_set_symmetric_rtp(LinphoneCall *call, bool_t val){ - int i; - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i){ - MSMediaStreamSessions *mss = &call->sessions[i]; - if (mss->rtp_session){ - rtp_session_set_symmetric_rtp(mss->rtp_session, val); - } - } -} - -void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState next_state){ - LinphoneCore *lc=call->core; - bool_t video_will_be_used = FALSE; -#ifdef VIDEO_ENABLED - const SalStreamDescription *vstream=sal_media_description_find_best_stream(call->resultdesc,SalVideo); -#endif - - switch (next_state){ - case LinphoneCallIncomingEarlyMedia: - if (linphone_core_get_remote_ringback_tone(lc)){ - call->playing_ringbacktone = TRUE; - } - BCTBX_NO_BREAK; - case LinphoneCallOutgoingEarlyMedia: - if (!linphone_call_params_early_media_sending_enabled(call->params)){ - call->all_muted = TRUE; - } - break; - default: - call->playing_ringbacktone = FALSE; - call->all_muted = FALSE; - break; - } - - linphone_call_params_set_used_audio_codec(call->current_params, NULL); - linphone_call_params_set_used_video_codec(call->current_params, NULL); - linphone_call_params_set_used_text_codec(call->current_params, NULL); - - if ((call->audiostream == NULL) && (call->videostream == NULL)) { - ms_fatal("start_media_stream() called without prior init !"); - return; - } - - if (call->ice_session != NULL){ - /*if there is an ICE session when we are about to start streams, then ICE will conduct the media path checking and authentication properly. - * Symmetric RTP must be turned off*/ - linphone_call_set_symmetric_rtp(call, FALSE); - } - - call->nb_media_starts++; -#if defined(VIDEO_ENABLED) - if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){ - /*when video is used, do not make adaptive rate control on audio, it is stupid.*/ - video_will_be_used = TRUE; - } -#endif - ms_message("linphone_call_start_media_streams() call=[%p] local upload_bandwidth=[%i] kbit/s; local download_bandwidth=[%i] kbit/s", - call, linphone_core_get_upload_bandwidth(lc),linphone_core_get_download_bandwidth(lc)); - - linphone_call_params_enable_audio(call->current_params, FALSE); - if (call->audiostream!=NULL) { - linphone_call_start_audio_stream(call, next_state, video_will_be_used); - } else { - ms_warning("linphone_call_start_media_streams(): no audio stream!"); - } - linphone_call_params_enable_video(call->current_params, FALSE); - if (call->videostream!=NULL) { - if (call->audiostream) audio_stream_link_video(call->audiostream,call->videostream); - linphone_call_start_video_stream(call, next_state); - } - /*the onhold file is to be played once both audio and video are ready.*/ - if (call->onhold_file && !linphone_call_params_get_in_conference(call->params) && call->audiostream){ - MSFilter *player = audio_stream_open_remote_play(call->audiostream, call->onhold_file); - if (player){ - int pause_time=500; - ms_filter_call_method(player, MS_PLAYER_SET_LOOP, &pause_time); - ms_filter_call_method_noarg(player, MS_PLAYER_START); - } - } - - call->up_bw=linphone_core_get_upload_bandwidth(lc); - - if (linphone_call_params_realtime_text_enabled(call->params)) { - linphone_call_start_text_stream(call); - } - - set_dtls_fingerprint_on_all_streams(call); - - if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) { - if (linphone_call_params_get_media_encryption(call->params)==LinphoneMediaEncryptionDTLS) { - linphone_call_params_set_update_call_when_ice_completed(call->current_params, FALSE); - ms_message("Disabling update call when ice completed on call [%p]",call); - } - ice_session_start_connectivity_checks(call->ice_session); - } else { - /*should not start dtls until ice is completed*/ - start_dtls_on_all_streams(call); - } - -} - -void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){ - if(call->audiostream && call->audiostream->ms.state==MSStreamPreparing) audio_stream_unprepare_sound(call->audiostream); -#ifdef VIDEO_ENABLED - if (call->videostream && call->videostream->ms.state==MSStreamPreparing) { - video_stream_unprepare_video(call->videostream); - } -#endif - if (call->textstream && call->textstream->ms.state == MSStreamPreparing) { - text_stream_unprepare_text(call->textstream); - } -} - -static bool_t update_stream_crypto_params(LinphoneCall *call, const SalStreamDescription *local_st_desc, SalStreamDescription *old_stream, SalStreamDescription *new_stream, MediaStream *ms){ - int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag); - if (crypto_idx >= 0) { - if (call->localdesc_changed & SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED) - ms_media_stream_sessions_set_srtp_send_key_b64(&ms->sessions, new_stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key); - if (strcmp(old_stream->crypto[0].master_key,new_stream->crypto[0].master_key)!=0){ - ms_media_stream_sessions_set_srtp_recv_key_b64(&ms->sessions, new_stream->crypto[0].algo,new_stream->crypto[0].master_key); - } - return TRUE; - } else { - ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag); - } - return FALSE; -} - -void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) { - SalStreamDescription *old_stream; - SalStreamDescription *new_stream; - const SalStreamDescription *local_st_desc; - - local_st_desc = sal_media_description_find_secure_stream_of_type(call->localdesc, SalAudio); - old_stream = sal_media_description_find_secure_stream_of_type(old_md, SalAudio); - new_stream = sal_media_description_find_secure_stream_of_type(new_md, SalAudio); - if (call->audiostream && local_st_desc && old_stream && new_stream && - update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->audiostream->ms)){ - } - - local_st_desc = sal_media_description_find_secure_stream_of_type(call->localdesc, SalText); - old_stream = sal_media_description_find_secure_stream_of_type(old_md, SalText); - new_stream = sal_media_description_find_secure_stream_of_type(new_md, SalText); - if (call->textstream && local_st_desc && old_stream && new_stream && - update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->textstream->ms)){ - } - - start_dtls_on_all_streams(call); - -#ifdef VIDEO_ENABLED - local_st_desc = sal_media_description_find_secure_stream_of_type(call->localdesc, SalVideo); - old_stream = sal_media_description_find_secure_stream_of_type(old_md, SalVideo); - new_stream = sal_media_description_find_secure_stream_of_type(new_md, SalVideo); - if (call->videostream && local_st_desc && old_stream && new_stream && - update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->videostream->ms)){ - } -#endif -} - -void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call) { - SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op); - if (remote_desc) { - call->remote_session_id = remote_desc->session_id; - call->remote_session_ver = remote_desc->session_ver; - } -} - -void linphone_call_delete_ice_session(LinphoneCall *call){ - if (call->ice_session != NULL) { - ice_session_destroy(call->ice_session); - call->ice_session = NULL; - if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = NULL; - if (call->videostream != NULL) call->videostream->ms.ice_check_list = NULL; - if (call->textstream != NULL) call->textstream->ms.ice_check_list = NULL; - call->audio_stats->ice_state = LinphoneIceStateNotActivated; - call->video_stats->ice_state = LinphoneIceStateNotActivated; - call->text_stats->ice_state = LinphoneIceStateNotActivated; - } -} - void linphone_call_delete_upnp_session(LinphoneCall *call){ -#ifdef BUILD_UPNP - if(call->upnp_session!=NULL) { - linphone_upnp_session_destroy(call->upnp_session); - call->upnp_session=NULL; - } -#endif //BUILD_UPNP -} - -static void linphone_call_log_fill_stats(LinphoneCallLog *log, MediaStream *st){ - float quality=media_stream_get_average_quality_rating(st); - if (quality>=0){ - if (log->quality!=-1){ - log->quality*=quality/5.0f; - }else log->quality=quality; - } -} - -static void update_rtp_stats(LinphoneCall *call, int stream_index) { - if (call->sessions[stream_index].rtp_session) { - const rtp_stats_t *stats = rtp_session_get_stats(call->sessions[stream_index].rtp_session); - LinphoneCallStats *call_stats = NULL; - if (stream_index == call->main_audio_stream_index) { - call_stats = call->audio_stats; - } else if (stream_index == call->main_video_stream_index) { - call_stats = call->video_stats; - } else { - call_stats = call->text_stats; - } - if (call_stats) memcpy(&(call_stats->rtp_stats), stats, sizeof(*stats)); - } -} - -static void linphone_call_stop_audio_stream(LinphoneCall *call) { - LinphoneCore *lc = call->core; - if (call->audiostream!=NULL) { - linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_AUDIO); - media_stream_reclaim_sessions(&call->audiostream->ms,&call->sessions[call->main_audio_stream_index]); - - if (call->audiostream->ec){ - char *state_str=NULL; - ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str); - if (state_str){ - ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str)); - lp_config_write_relative_file(call->core->config, EC_STATE_STORE, state_str); - } - } - audio_stream_get_local_rtp_stats(call->audiostream,&call->log->local_stats); - linphone_call_log_fill_stats (call->log,(MediaStream*)call->audiostream); - if (call->endpoint){ - linphone_conference_on_call_stream_stopping(lc->conf_ctx, call); - } - ms_bandwidth_controller_remove_stream(lc->bw_controller, (MediaStream*)call->audiostream); - audio_stream_stop(call->audiostream); - update_rtp_stats(call, call->main_audio_stream_index); - call->audiostream=NULL; - linphone_call_handle_stream_events(call, call->main_audio_stream_index); - rtp_session_unregister_event_queue(call->sessions[call->main_audio_stream_index].rtp_session, call->audiostream_app_evq); - ortp_ev_queue_flush(call->audiostream_app_evq); - ortp_ev_queue_destroy(call->audiostream_app_evq); - call->audiostream_app_evq=NULL; - - linphone_call_params_set_used_audio_codec(call->current_params, NULL); - } -} - -static void linphone_call_stop_video_stream(LinphoneCall *call) { -#ifdef VIDEO_ENABLED - if (call->videostream!=NULL){ - linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_VIDEO); - media_stream_reclaim_sessions(&call->videostream->ms,&call->sessions[call->main_video_stream_index]); - linphone_call_log_fill_stats(call->log,(MediaStream*)call->videostream); - ms_bandwidth_controller_remove_stream(call->core->bw_controller, (MediaStream*)call->videostream); - video_stream_stop(call->videostream); - update_rtp_stats(call, call->main_video_stream_index); - call->videostream=NULL; - linphone_call_handle_stream_events(call, call->main_video_stream_index); - rtp_session_unregister_event_queue(call->sessions[call->main_video_stream_index].rtp_session, call->videostream_app_evq); - ortp_ev_queue_flush(call->videostream_app_evq); - ortp_ev_queue_destroy(call->videostream_app_evq); - call->videostream_app_evq=NULL; - linphone_call_params_set_used_video_codec(call->current_params, NULL); - } -#endif -} - -static void unset_rtp_profile(LinphoneCall *call, int i){ - if (call->sessions[i].rtp_session) - rtp_session_set_profile(call->sessions[i].rtp_session,&av_profile); -} - -static void linphone_call_stop_text_stream(LinphoneCall *call) { - if (call->textstream != NULL) { - linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_TEXT); - media_stream_reclaim_sessions(&call->textstream->ms, &call->sessions[call->main_text_stream_index]); - linphone_call_log_fill_stats(call->log, (MediaStream*)call->textstream); - text_stream_stop(call->textstream); - update_rtp_stats(call, call->main_text_stream_index); - call->textstream = NULL; - linphone_call_handle_stream_events(call, call->main_text_stream_index); - rtp_session_unregister_event_queue(call->sessions[call->main_text_stream_index].rtp_session, call->textstream_app_evq); - ortp_ev_queue_flush(call->textstream_app_evq); - ortp_ev_queue_destroy(call->textstream_app_evq); - call->textstream_app_evq = NULL; - linphone_call_params_set_used_text_codec(call->current_params, NULL); - } } void linphone_call_stop_media_streams(LinphoneCall *call){ - if (call->audiostream || call->videostream || call->textstream) { - if (call->audiostream && call->videostream) - audio_stream_unlink_video(call->audiostream, call->videostream); - linphone_call_stop_audio_stream(call); - linphone_call_stop_video_stream(call); - linphone_call_stop_text_stream(call); - - if (call->core->msevq != NULL) { - ms_event_queue_skip(call->core->msevq); - } - } - - if (call->audio_profile){ - rtp_profile_destroy(call->audio_profile); - call->audio_profile=NULL; - unset_rtp_profile(call,call->main_audio_stream_index); - } - if (call->video_profile){ - rtp_profile_destroy(call->video_profile); - call->video_profile=NULL; - unset_rtp_profile(call,call->main_video_stream_index); - } - if (call->text_profile){ - rtp_profile_destroy(call->text_profile); - call->text_profile=NULL; - unset_rtp_profile(call,call->main_text_stream_index); - } - if (call->rtp_io_audio_profile) { - rtp_profile_destroy(call->rtp_io_audio_profile); - call->rtp_io_audio_profile = NULL; - } - if (call->rtp_io_video_profile) { - rtp_profile_destroy(call->rtp_io_video_profile); - call->rtp_io_video_profile = NULL; - } - - linphone_core_soundcard_hint_check(call->core); } void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) { - if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){ - bool_t bypass_mode = !enable; - ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode); - } + linphone_call_get_cpp_obj(call)->enableEchoCancellation(enable); } -bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) { - if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){ - bool_t val; - ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val); - return !val; - } else { - return linphone_core_echo_cancellation_enabled(call->core); - } +bool_t linphone_call_echo_cancellation_enabled(const LinphoneCall *call) { + return linphone_call_get_cpp_obj(call)->echoCancellationEnabled(); } -void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){ - if (call!=NULL && call->audiostream!=NULL ) { - if (val) { - const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic"); - if (strcasecmp(type,"mic")==0) - audio_stream_enable_echo_limiter(call->audiostream,ELControlMic); - else if (strcasecmp(type,"full")==0) - audio_stream_enable_echo_limiter(call->audiostream,ELControlFull); - } else { - audio_stream_enable_echo_limiter(call->audiostream,ELInactive); - } - } +void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val) { + linphone_call_get_cpp_obj(call)->enableEchoLimiter(val); } -bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){ - if (call!=NULL && call->audiostream!=NULL ){ - return call->audiostream->el_type !=ELInactive ; - } else { - return linphone_core_echo_limiter_enabled(call->core); - } +bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call) { + return linphone_call_get_cpp_obj(call)->echoLimiterEnabled(); } -float linphone_call_get_play_volume(LinphoneCall *call){ - AudioStream *st=call->audiostream; - if (st && st->volrecv){ - float vol=0; - ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol); - return vol; - - } - return LINPHONE_VOLUME_DB_LOWEST; +float linphone_call_get_play_volume(const LinphoneCall *call) { + return linphone_call_get_cpp_obj(call)->getPlayVolume(); } -float linphone_call_get_record_volume(LinphoneCall *call){ - AudioStream *st=call->audiostream; - if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){ - float vol=0; - ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol); - return vol; - - } - return LINPHONE_VOLUME_DB_LOWEST; +float linphone_call_get_record_volume(const LinphoneCall *call) { + return linphone_call_get_cpp_obj(call)->getRecordVolume(); } float linphone_call_get_speaker_volume_gain(const LinphoneCall *call) { - if(call->audiostream) return audio_stream_get_sound_card_output_gain(call->audiostream); - else { - ms_error("Could not get playback volume: no audio stream"); - return -1.0f; - } + return linphone_call_get_cpp_obj(call)->getSpeakerVolumeGain(); } void linphone_call_set_speaker_volume_gain(LinphoneCall *call, float volume) { - if(call->audiostream) audio_stream_set_sound_card_output_gain(call->audiostream, volume); - else ms_error("Could not set playback volume: no audio stream"); + linphone_call_get_cpp_obj(call)->setSpeakerVolumeGain(volume); } float linphone_call_get_microphone_volume_gain(const LinphoneCall *call) { - if(call->audiostream) return audio_stream_get_sound_card_input_gain(call->audiostream); - else { - ms_error("Could not get record volume: no audio stream"); - return -1.0f; - } + return linphone_call_get_cpp_obj(call)->getMicrophoneVolumeGain(); } void linphone_call_set_microphone_volume_gain(LinphoneCall *call, float volume) { - if(call->audiostream) audio_stream_set_sound_card_input_gain(call->audiostream, volume); - else ms_error("Could not set record volume: no audio stream"); + linphone_call_get_cpp_obj(call)->setMicrophoneVolumeGain(volume); } -static float agregate_ratings(float audio_rating, float video_rating){ - float result; - if (audio_rating<0 && video_rating<0) result=-1; - else if (audio_rating<0) result=video_rating*5.0f; - else if (video_rating<0) result=audio_rating*5.0f; - else result=audio_rating*video_rating*5.0f; - return result; +float linphone_call_get_current_quality(const LinphoneCall *call) { + return linphone_call_get_cpp_obj(call)->getCurrentQuality(); } -float linphone_call_get_current_quality(LinphoneCall *call){ - float audio_rating=-1.f; - float video_rating=-1.f; - - if (call->audiostream){ - audio_rating=media_stream_get_quality_rating((MediaStream*)call->audiostream)/5.0f; - } - if (call->videostream){ - video_rating=media_stream_get_quality_rating((MediaStream*)call->videostream)/5.0f; - } - return agregate_ratings(audio_rating, video_rating); +float linphone_call_get_average_quality(const LinphoneCall *call) { + return linphone_call_get_cpp_obj(call)->getAverageQuality(); } -float linphone_call_get_average_quality(LinphoneCall *call){ - float audio_rating=-1.f; - float video_rating=-1.f; - - if (call->audiostream){ - audio_rating = media_stream_get_average_quality_rating((MediaStream*)call->audiostream)/5.0f; - } - if (call->videostream){ - video_rating = media_stream_get_average_quality_rating((MediaStream*)call->videostream)/5.0f; - } - return agregate_ratings(audio_rating, video_rating); -} - -static void update_local_stats(LinphoneCallStats *stats, MediaStream *stream) { +void linphone_call_stats_update(LinphoneCallStats *stats, MediaStream *stream) { PayloadType *pt; RtpSession *session = stream->sessions.rtp_session; const MSQualityIndicator *qi = media_stream_get_quality_indicator(stream); @@ -4307,21 +739,11 @@ static void update_local_stats(LinphoneCallStats *stats, MediaStream *stream) { stats->clockrate = pt ? pt->clock_rate : 8000; } -static MediaStream *linphone_call_get_stream(LinphoneCall *call, LinphoneStreamType type){ - switch(type){ - case LinphoneStreamTypeAudio: - return &call->audiostream->ms; - case LinphoneStreamTypeVideo: - return &call->videostream->ms; - case LinphoneStreamTypeText: - return &call->textstream->ms; - case LinphoneStreamTypeUnknown: - break; - } - return NULL; +MediaStream * linphone_call_get_stream(LinphoneCall *call, LinphoneStreamType type) { + return L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->getMediaStream(type); } -static void _linphone_call_stats_clone(LinphoneCallStats *dst, const LinphoneCallStats *src) { +void _linphone_call_stats_clone(LinphoneCallStats *dst, const LinphoneCallStats *src) { /* * Save the belle_sip_object_t part, copy the entire structure and restore the belle_sip_object_t part */ @@ -4333,48 +755,24 @@ static void _linphone_call_stats_clone(LinphoneCallStats *dst, const LinphoneCal dst->sent_rtcp = NULL; } -LinphoneCallStats *linphone_call_get_stats(LinphoneCall *call, LinphoneStreamType type){ - if ((int)type >=0 && type<=LinphoneStreamTypeText){ - LinphoneCallStats *stats = NULL; - LinphoneCallStats *stats_copy = linphone_call_stats_new(); - if (type == LinphoneStreamTypeAudio) { - stats = call->audio_stats; - } else if (type == LinphoneStreamTypeVideo) { - stats = call->video_stats; - } else if (type == LinphoneStreamTypeText) { - stats = call->text_stats; - } - MediaStream *ms = linphone_call_get_stream(call, type); - if (ms && stats) update_local_stats(stats, ms); - _linphone_call_stats_clone(stats_copy, stats); - return stats_copy; - } - ms_error("Invalid stream type %i", (int)type); - return NULL; +LinphoneCallStats *linphone_call_get_stats(LinphoneCall *call, LinphoneStreamType type) { + return linphone_call_get_cpp_obj(call)->getStats(type); } LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call) { - return linphone_call_get_stats(call, LinphoneStreamTypeAudio); + return linphone_call_get_cpp_obj(call)->getAudioStats(); } LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call) { - return linphone_call_get_stats(call, LinphoneStreamTypeVideo); + return linphone_call_get_cpp_obj(call)->getVideoStats(); } LinphoneCallStats *linphone_call_get_text_stats(LinphoneCall *call) { - return linphone_call_get_stats(call, LinphoneStreamTypeText); + return linphone_call_get_cpp_obj(call)->getTextStats(); } -static bool_t ice_in_progress(LinphoneCallStats *stats){ - return stats->ice_state==LinphoneIceStateInProgress; -} - -bool_t linphone_call_media_in_progress(LinphoneCall *call){ - bool_t ret=FALSE; - if (ice_in_progress(call->audio_stats) || ice_in_progress(call->video_stats) || ice_in_progress(call->text_stats)) - ret=TRUE; - /*TODO: could check zrtp state, upnp state*/ - return ret; +bool_t linphone_call_media_in_progress(const LinphoneCall *call) { + return linphone_call_get_cpp_obj(call)->mediaInProgress(); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCallStats); @@ -4537,74 +935,12 @@ float linphone_call_stats_get_round_trip_delay(const LinphoneCallStats *stats) { return stats->round_trip_delay; } -void linphone_call_start_recording(LinphoneCall *call){ - if (!linphone_call_params_get_record_file(call->params)){ - ms_error("linphone_call_start_recording(): no output file specified. Use linphone_call_params_set_record_file()."); - return; - } - if (call->audiostream && !linphone_call_params_get_in_conference(call->params)){ - audio_stream_mixed_record_start(call->audiostream); - } - call->record_active=TRUE; +void linphone_call_start_recording(LinphoneCall *call) { + linphone_call_get_cpp_obj(call)->startRecording(); } -void linphone_call_stop_recording(LinphoneCall *call){ - if (call->audiostream && !linphone_call_params_get_in_conference(call->params)){ - audio_stream_mixed_record_stop(call->audiostream); - } - call->record_active=FALSE; -} - -static void report_bandwidth_for_stream(LinphoneCall *call, MediaStream *ms, LinphoneStreamType type){ - bool_t active = ms ? (media_stream_get_state(ms) == MSStreamStarted) : FALSE; - LinphoneCallStats *stats = NULL; - if (type == LinphoneStreamTypeAudio) { - stats = call->audio_stats; - } else if (type == LinphoneStreamTypeVideo) { - stats = call->video_stats; - } else if (type == LinphoneStreamTypeText) { - stats = call->text_stats; - } else { - return; - } - - stats->download_bandwidth=(active) ? (float)(media_stream_get_down_bw(ms)*1e-3) : 0.f; - stats->upload_bandwidth=(active) ? (float)(media_stream_get_up_bw(ms)*1e-3) : 0.f; - stats->rtcp_download_bandwidth=(active) ? (float)(media_stream_get_rtcp_down_bw(ms)*1e-3) : 0.f; - stats->rtcp_upload_bandwidth=(active) ? (float)(media_stream_get_rtcp_up_bw(ms)*1e-3) : 0.f; - stats->rtp_remote_family=(active) - ? (ortp_stream_is_ipv6(&ms->sessions.rtp_session->rtp.gs) ? LinphoneAddressFamilyInet6 : LinphoneAddressFamilyInet) : LinphoneAddressFamilyUnspec; - - if (call->core->send_call_stats_periodical_updates){ - if (active) update_local_stats(stats, ms); - stats->updated |= LINPHONE_CALL_STATS_PERIODICAL_UPDATE; - linphone_call_notify_stats_updated(call, stats); - stats->updated=0; - } -} - -static void report_bandwidth(LinphoneCall *call, MediaStream *as, MediaStream *vs, MediaStream *ts){ - report_bandwidth_for_stream(call, as, LinphoneStreamTypeAudio); - report_bandwidth_for_stream(call, vs, LinphoneStreamTypeVideo); - report_bandwidth_for_stream(call, ts, LinphoneStreamTypeText); - - ms_message( "Bandwidth usage for call [%p]:\n" - "\tRTP audio=[d=%5.1f,u=%5.1f], video=[d=%5.1f,u=%5.1f], text=[d=%5.1f,u=%5.1f] kbits/sec\n" - "\tRTCP audio=[d=%5.1f,u=%5.1f], video=[d=%5.1f,u=%5.1f], text=[d=%5.1f,u=%5.1f] kbits/sec", - call, - call->audio_stats->download_bandwidth, - call->audio_stats->upload_bandwidth, - call->video_stats->download_bandwidth, - call->video_stats->upload_bandwidth, - call->text_stats->download_bandwidth, - call->text_stats->upload_bandwidth, - call->audio_stats->rtcp_download_bandwidth, - call->audio_stats->rtcp_upload_bandwidth, - call->video_stats->rtcp_download_bandwidth, - call->video_stats->rtcp_upload_bandwidth, - call->text_stats->rtcp_download_bandwidth, - call->text_stats->rtcp_upload_bandwidth - ); +void linphone_call_stop_recording(LinphoneCall *call) { + linphone_call_get_cpp_obj(call)->stopRecording(); } static void linphone_call_lost(LinphoneCall *call){ @@ -4624,81 +960,6 @@ static void linphone_call_lost(LinphoneCall *call){ ms_free(temp); } -static void linphone_call_on_ice_gathering_finished(LinphoneCall *call){ - int ping_time; - const SalMediaDescription *rmd = sal_call_get_remote_media_description(call->op); - if (rmd){ - linphone_call_clear_unused_ice_candidates(call, rmd); - } - ice_session_compute_candidates_foundations(call->ice_session); - ice_session_eliminate_redundant_candidates(call->ice_session); - ice_session_choose_default_candidates(call->ice_session); - ping_time = ice_session_average_gathering_round_trip_time(call->ice_session); - if (ping_time >=0) { - call->ping_time=ping_time; - } -} - -static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ - OrtpEventType evt=ortp_event_get_type(ev); - OrtpEventData *evd=ortp_event_get_data(ev); - - if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { - switch (ice_session_state(call->ice_session)) { - case IS_Completed: - case IS_Failed: - /* At least one ICE session has succeeded, so perform a call update. */ - if (ice_session_has_completed_check_list(call->ice_session) == TRUE) { - const LinphoneCallParams *current_param = linphone_call_get_current_params(call); - if (ice_session_role(call->ice_session) == IR_Controlling && linphone_call_params_get_update_call_when_ice_completed(current_param)) { - LinphoneCallParams *params = linphone_core_create_call_params(call->core, call); - linphone_call_params_set_internal_call_update(params, TRUE); - linphone_call_update(call, params); - linphone_call_params_unref(params); - } - start_dtls_on_all_streams(call); - } - break; - default: - break; - } - linphone_call_update_ice_state_in_call_stats(call); - } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) { - if (evd->info.ice_processing_successful==FALSE) { - ms_warning("No STUN answer from [%s], continuing without STUN",linphone_core_get_stun_server(call->core)); - } - linphone_call_on_ice_gathering_finished(call); - switch (call->state) { - case LinphoneCallUpdating: - linphone_call_start_update(call); - break; - case LinphoneCallUpdatedByRemote: - linphone_call_start_accept_update(call, call->prevstate,linphone_call_state_to_string(call->prevstate)); - break; - case LinphoneCallOutgoingInit: - linphone_call_stop_media_streams_for_ice_gathering(call); - linphone_call_proceed_with_invite_if_ready(call, NULL); - break; - case LinphoneCallIdle: - linphone_call_stop_media_streams_for_ice_gathering(call); - linphone_call_update_local_media_description_from_ice_or_upnp(call); - sal_call_set_local_media_description(call->op,call->localdesc); - linphone_core_notify_incoming_call(call->core, call); - break; - default: - break; - } - } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) { - if (call->state==LinphoneCallUpdatedByRemote){ - linphone_call_start_accept_update(call, call->prevstate, linphone_call_state_to_string(call->prevstate)); - linphone_call_update_ice_state_in_call_stats(call); - } - } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) { - ice_session_restart(call->ice_session, IR_Controlling); - linphone_call_update(call, call->current_params); - } -} - /*do not change the prototype of this function, it is also used internally in linphone-daemon.*/ void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEvent *ev){ OrtpEventType evt=ortp_event_get_type(ev); @@ -4712,7 +973,7 @@ void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEve stats->rtcp_received_via_mux = evd->info.socket_type == OrtpRTPSocket; evd->packet = NULL; stats->updated = LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE; - update_local_stats(stats,ms); + linphone_call_stats_update(stats,ms); } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { memcpy(&stats->jitter_stats, rtp_session_get_jitter_stats(ms->sessions.rtp_session), sizeof(jitter_stats_t)); if (stats->sent_rtcp != NULL) @@ -4720,7 +981,7 @@ void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEve stats->sent_rtcp = evd->packet; evd->packet = NULL; stats->updated = LINPHONE_CALL_STATS_SENT_RTCP_UPDATE; - update_local_stats(stats,ms); + linphone_call_stats_update(stats,ms); } } @@ -4735,203 +996,16 @@ void linphone_call_stats_uninit(LinphoneCallStats *stats){ } } -void linphone_call_notify_stats_updated_with_stream_index(LinphoneCall *call, int stream_index){ - LinphoneCallStats *stats = NULL; - if (stream_index == call->main_audio_stream_index) { - stats = call->audio_stats; - } else if (stream_index == call->main_video_stream_index) { - stats = call->video_stats; - } else { - stats = call->text_stats; - } - if (stats->updated){ - switch(stats->updated) { - case LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE: - case LINPHONE_CALL_STATS_SENT_RTCP_UPDATE: - linphone_reporting_on_rtcp_update(call, stream_index == call->main_audio_stream_index ? SalAudio : stream_index == call->main_video_stream_index ? SalVideo : SalText); - break; - default: - break; - } - linphone_call_notify_stats_updated(call, stats); - stats->updated = 0; - } -} - -static MediaStream * linphone_call_get_media_stream(LinphoneCall *call, int stream_index){ - if (stream_index == call->main_audio_stream_index) - return (MediaStream*)call->audiostream; - if (stream_index == call->main_video_stream_index) - return (MediaStream*)call->videostream; - if (stream_index == call->main_text_stream_index) - return (MediaStream*)call->textstream; - ms_error("linphone_call_get_media_stream(): no stream index %i", stream_index); - return NULL; -} - -static OrtpEvQueue *linphone_call_get_event_queue(LinphoneCall *call, int stream_index){ - if (stream_index == call->main_audio_stream_index) - return call->audiostream_app_evq; - if (stream_index == call->main_video_stream_index) - return call->videostream_app_evq; - if (stream_index == call->main_text_stream_index) - return call->textstream_app_evq; - ms_error("linphone_call_get_event_queue(): no stream index %i", stream_index); - return NULL; -} - -void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index){ - MediaStream *ms = stream_index == call->main_audio_stream_index ? (MediaStream *)call->audiostream : (stream_index == call->main_video_stream_index ? (MediaStream *)call->videostream : (MediaStream *)call->textstream); - OrtpEvQueue *evq; - OrtpEvent *ev; - - if (ms){ - /* Ensure there is no dangling ICE check list. */ - if (call->ice_session == NULL) { - media_stream_set_ice_check_list(ms, NULL); - } - - switch(ms->type){ - case MSAudio: - audio_stream_iterate((AudioStream*)ms); - break; - case MSVideo: - #ifdef VIDEO_ENABLED - video_stream_iterate((VideoStream*)ms); - #endif - break; - case MSText: - text_stream_iterate((TextStream*)ms); - break; - default: - ms_error("linphone_call_handle_stream_events(): unsupported stream type."); - return; - break; - } - } - /*yes the event queue has to be taken at each iteration, because ice events may perform operations re-creating the streams*/ - while((evq = linphone_call_get_event_queue(call, stream_index)) != NULL && NULL != (ev=ortp_ev_queue_get(evq))){ - OrtpEventType evt=ortp_event_get_type(ev); - OrtpEventData *evd=ortp_event_get_data(ev); - int stats_index; - LinphoneCallStats *stats = NULL; - - if (stream_index == call->main_audio_stream_index) { - stats_index = LINPHONE_CALL_STATS_AUDIO; - stats = call->audio_stats; - } else if (stream_index == call->main_video_stream_index) { - stats_index = LINPHONE_CALL_STATS_VIDEO; - stats = call->video_stats; - } else { - stats_index = LINPHONE_CALL_STATS_TEXT; - stats = call->text_stats; - } - - /*and yes the MediaStream must be taken at each iteration, because it may have changed due to the handling of events - * in this loop*/ - ms = linphone_call_get_media_stream(call, stream_index); - - if (ms) linphone_call_stats_fill(stats,ms,ev); - linphone_call_notify_stats_updated_with_stream_index(call,stats_index); - - if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){ - if (stream_index == call->main_audio_stream_index) - linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted); - else if (stream_index == call->main_video_stream_index) { - propagate_encryption_changed(call); - } - } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) { - if (stream_index == call->main_audio_stream_index) - linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_info.sas, evd->info.zrtp_info.verified); - } else if (evt == ORTP_EVENT_DTLS_ENCRYPTION_CHANGED) { - if (stream_index == call->main_audio_stream_index) - linphone_call_audiostream_encryption_changed(call, evd->info.dtls_stream_encrypted); - else if (stream_index == call->main_video_stream_index) - propagate_encryption_changed(call); - }else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) - || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) { - if (ms) handle_ice_events(call, ev); - } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){ - linphone_core_dtmf_received(call,evd->info.telephone_event); - } else if (evt == ORTP_EVENT_NEW_VIDEO_BANDWIDTH_ESTIMATION_AVAILABLE) { - ms_message("Video bandwidth estimation is %i kbit/s", (int)evd->info.video_bandwidth_available / 1000); - //TODO - } - ortp_event_destroy(ev); - } -} - -void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){ - int disconnect_timeout = linphone_core_get_nortp_timeout(call->core); - bool_t disconnected=FALSE; - - switch (call->state) { - case LinphoneCallStreamsRunning: - case LinphoneCallOutgoingEarlyMedia: - case LinphoneCallIncomingEarlyMedia: - case LinphoneCallPausedByRemote: - case LinphoneCallPaused: - if (one_second_elapsed){ - float audio_load=0, video_load=0, text_load=0; - if (call->audiostream != NULL) { - if (call->audiostream->ms.sessions.ticker) - audio_load = ms_ticker_get_average_load(call->audiostream->ms.sessions.ticker); - } - if (call->videostream != NULL) { - if (call->videostream->ms.sessions.ticker) - video_load = ms_ticker_get_average_load(call->videostream->ms.sessions.ticker); - } - if (call->textstream != NULL) { - if (call->textstream->ms.sessions.ticker) - text_load = ms_ticker_get_average_load(call->textstream->ms.sessions.ticker); - } - report_bandwidth(call, (MediaStream*)call->audiostream, (MediaStream*)call->videostream, (MediaStream*)call->textstream); - ms_message("Thread processing load: audio=%f\tvideo=%f\ttext=%f", audio_load, video_load, text_load); - } - break; - default: - /*no stats for other states*/ - break; - } - -#ifdef BUILD_UPNP - linphone_upnp_call_process(call); -#endif //BUILD_UPNP - - linphone_call_handle_stream_events(call, call->main_audio_stream_index); - linphone_call_handle_stream_events(call, call->main_video_stream_index); - linphone_call_handle_stream_events(call, call->main_text_stream_index); - if ((call->state == LinphoneCallStreamsRunning || - call->state == LinphoneCallPausedByRemote) && one_second_elapsed && call->audiostream!=NULL - && call->audiostream->ms.state==MSStreamStarted && disconnect_timeout>0 ) { - disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout); - } - if (disconnected) linphone_call_lost(call); -} - -void linphone_call_log_completed(LinphoneCall *call){ - LinphoneCore *lc=call->core; - - call->log->duration= _linphone_call_compute_duration(call); /*store duration since connected*/ - call->log->error_info = linphone_error_info_ref((LinphoneErrorInfo*)linphone_call_get_error_info(call)); - - if (call->log->status==LinphoneCallMissed){ - char *info; - lc->missed_calls++; - info=ortp_strdup_printf(ngettext("You have missed %i call.", - "You have missed %i calls.", lc->missed_calls), - lc->missed_calls); - linphone_core_notify_display_status(lc,info); - ms_free(info); - } - linphone_core_report_call_log(lc, call->log); -} - LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) { +#if 0 return call->transfer_state; +#else + return LinphoneCallIdle; +#endif } void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) { +#if 0 if (state != call->transfer_state) { ms_message("Transfer state for call [%p] changed from [%s] to [%s]",call ,linphone_call_state_to_string(call->transfer_state) @@ -4939,122 +1013,58 @@ void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState stat call->transfer_state = state; linphone_call_notify_transfer_state_changed(call, state); } +#endif } bool_t linphone_call_is_in_conference(const LinphoneCall *call) { +#if 0 return linphone_call_params_get_in_conference(call->params); +#else + return FALSE; +#endif } LinphoneConference *linphone_call_get_conference(const LinphoneCall *call) { +#if 0 return call->conf_ref; +#else + return nullptr; +#endif } void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) { - VideoStream* vstream = call->videostream; - if (vstream && vstream->output) { - float zoom[3]; - float halfsize; - - if (zoom_factor < 1) - zoom_factor = 1; - halfsize = 0.5f * 1.0f / zoom_factor; - - if ((*cx - halfsize) < 0) - *cx = 0 + halfsize; - if ((*cx + halfsize) > 1) - *cx = 1 - halfsize; - if ((*cy - halfsize) < 0) - *cy = 0 + halfsize; - if ((*cy + halfsize) > 1) - *cy = 1 - halfsize; - - zoom[0] = zoom_factor; - zoom[1] = *cx; - zoom[2] = *cy; - ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom); - }else ms_warning("Could not apply zoom: video output wasn't activated."); -} - -static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ - LinphoneAddress *ctt=NULL; - LinphoneAddress *ret=NULL; - //const char *localip=call->localip; - - /* first use user's supplied ip address if asked*/ - if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress){ - ctt=linphone_core_get_primary_contact_parsed(lc); - linphone_address_set_domain(ctt,linphone_core_get_nat_address_resolved(lc)); - ret=ctt; - } else if (call->op && sal_op_get_contact_address(call->op)!=NULL){ - /* if already choosed, don't change it */ - return NULL; - } else if (call->ping_op && sal_op_get_contact_address(call->ping_op)) { - char *addr = sal_address_as_string(sal_op_get_contact_address(call->ping_op)); - /* if the ping OPTIONS request succeeded use the contact guessed from the - received, rport*/ - ms_message("Contact has been fixed using OPTIONS"/* to %s",guessed*/); - ret=linphone_address_new(addr); - ms_free(addr); - } else if (dest_proxy && dest_proxy->op && sal_op_get_contact_address(dest_proxy->op)){ - char *addr = sal_address_as_string(sal_op_get_contact_address(dest_proxy->op)); - - /*if using a proxy, use the contact address as guessed with the REGISTERs*/ - ms_message("Contact has been fixed using proxy" /*to %s",fixed_contact*/); - ret=linphone_address_new(addr); - ms_free(addr); - } else { - ctt=linphone_core_get_primary_contact_parsed(lc); - if (ctt!=NULL){ - /*otherwise use supplied localip*/ - linphone_address_set_domain(ctt,NULL/*localip*/); - linphone_address_set_port(ctt,-1/*linphone_core_get_sip_port(lc)*/); - ms_message("Contact has not been fixed stack will do"/* to %s",ret*/); - ret=ctt; - } - } - return ret; -} - -void linphone_call_set_contact_op(LinphoneCall* call) { - SalAddress *sal_address = nullptr; - { - LinphoneAddress *contact = get_fixed_contact(call->core,call,call->dest_proxy); - if (contact) { - sal_address = const_cast(L_GET_PRIVATE_FROM_C_STRUCT(contact, Address)->getInternalAddress()); - sal_address_ref(sal_address); - linphone_address_unref(contact); - } - } - - sal_op_set_and_clean_contact_address(call->op, sal_address); + linphone_call_get_cpp_obj(call)->zoomVideo(zoom_factor, cx, cy); } LinphonePlayer *linphone_call_get_player(LinphoneCall *call){ +#if 0 if (call->player==NULL) call->player=linphone_call_build_player(call); return call->player; +#else + return nullptr; +#endif } void linphone_call_set_params(LinphoneCall *call, const LinphoneCallParams *params){ +#if 0 if ( call->state == LinphoneCallOutgoingInit || call->state == LinphoneCallIncomingReceived){ _linphone_call_set_new_params(call, params); } else { ms_error("linphone_call_set_params() invalid state %s to call this function", linphone_call_state_to_string(call->state)); } +#endif } void _linphone_call_set_new_params(LinphoneCall *call, const LinphoneCallParams *params){ - LinphoneCallParams *cp=NULL; - if (params) cp=linphone_call_params_copy(params); - if (call->params) linphone_call_params_unref(call->params); - call->params=cp; } -const LinphoneCallParams * linphone_call_get_params(LinphoneCall *call){ - return call->params; +const LinphoneCallParams * linphone_call_get_params(LinphoneCall *call) { + call->paramsCache->msp = linphone_call_get_cpp_obj(call)->getParams(); + return call->paramsCache; } @@ -5092,6 +1102,7 @@ static int send_dtmf_handler(void *data, unsigned int revents){ } LinphoneStatus linphone_call_send_dtmf(LinphoneCall *call, char dtmf) { +#if 0 if (call==NULL){ ms_warning("linphone_call_send_dtmf(): invalid call, canceling DTMF."); return -1; @@ -5100,9 +1111,13 @@ LinphoneStatus linphone_call_send_dtmf(LinphoneCall *call, char dtmf) { send_dtmf_handler(call,0); call->dtmf_sequence = NULL; return 0; +#else + return 0; +#endif } LinphoneStatus linphone_call_send_dtmfs(LinphoneCall *call,const char *dtmfs) { +#if 0 if (call==NULL){ ms_warning("linphone_call_send_dtmfs(): invalid call, canceling DTMF sequence."); return -1; @@ -5117,9 +1132,13 @@ LinphoneStatus linphone_call_send_dtmfs(LinphoneCall *call,const char *dtmfs) { call->dtmfs_timer = sal_create_timer(call->core->sal, send_dtmf_handler, call, delay_ms, "DTMF sequence timer"); } return 0; +#else + return 0; +#endif } void linphone_call_cancel_dtmfs(LinphoneCall *call) { +#if 0 /*nothing to do*/ if (!call || !call->dtmfs_timer) return; @@ -5130,114 +1149,67 @@ void linphone_call_cancel_dtmfs(LinphoneCall *call) { ms_free(call->dtmf_sequence); call->dtmf_sequence = NULL; } +#endif } void * linphone_call_get_native_video_window_id(const LinphoneCall *call) { - if (call->video_window_id) { - /* The video id was previously set by the app. */ - return call->video_window_id; - } -#ifdef VIDEO_ENABLED - else if (call->videostream) { - /* It was not set but we want to get the one automatically created by mediastreamer2 (desktop versions only). */ - return video_stream_get_native_window_id(call->videostream); - } -#endif - return 0; + return linphone_call_get_cpp_obj(call)->getNativeVideoWindowId(); } void linphone_call_set_native_video_window_id(LinphoneCall *call, void *id) { - call->video_window_id = id; -#ifdef VIDEO_ENABLED - if (call->videostream) { - video_stream_set_native_window_id(call->videostream, id); + linphone_call_get_cpp_obj(call)->setNativeVideoWindowId(id); +} + +void linphone_call_set_audio_route(LinphoneCall *call, LinphoneAudioRoute route) { +#if 0 + if (call != NULL && call->audiostream != NULL){ + audio_stream_set_audio_route(call->audiostream, (MSAudioRoute) route); } #endif } -MSWebCam *linphone_call_get_video_device(const LinphoneCall *call) { - LinphoneCallState state = linphone_call_get_state(call); - bool_t paused = (state == LinphoneCallPausing) || (state == LinphoneCallPaused); - if (paused || call->all_muted || (call->camera_enabled == FALSE)) - return get_nowebcam_device(call->core->factory); - else - return call->core->video_conf.device; -} - -void linphone_call_set_audio_route(LinphoneCall *call, LinphoneAudioRoute route) { - if (call != NULL && call->audiostream != NULL){ - audio_stream_set_audio_route(call->audiostream, (MSAudioRoute) route); - } -} - LinphoneChatRoom * linphone_call_get_chat_room(LinphoneCall *call) { +#if 0 if (!call->chat_room){ if (call->state != LinphoneCallReleased && call->state != LinphoneCallEnd){ call->chat_room = _linphone_core_create_chat_room_from_call(call); } } return call->chat_room; -} - -int linphone_call_get_stream_count(LinphoneCall *call) { - // Revisit when multiple media streams will be implemented -#ifdef VIDEO_ENABLED - if (linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) { - return 3; - } - return 2; #else - if (linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) { - return 2; - } - return 1; + return nullptr; #endif } -MSFormatType linphone_call_get_stream_type(LinphoneCall *call, int stream_index) { - // Revisit when multiple media streams will be implemented - if (stream_index == call->main_video_stream_index) { - return MSVideo; - } else if (stream_index == call->main_text_stream_index) { - return MSText; - } else if (stream_index == call->main_audio_stream_index){ - return MSAudio; - } - return MSUnknownMedia; +int linphone_call_get_stream_count(const LinphoneCall *call) { + return linphone_call_get_cpp_obj(call)->getStreamCount(); } -RtpTransport* linphone_call_get_meta_rtp_transport(LinphoneCall *call, int stream_index) { - RtpTransport *meta_rtp; - RtpTransport *meta_rtcp; - - if (!call || stream_index < 0 || stream_index >= linphone_call_get_stream_count(call)) { - return NULL; - } - - rtp_session_get_transports(call->sessions[stream_index].rtp_session, &meta_rtp, &meta_rtcp); - return meta_rtp; +MSFormatType linphone_call_get_stream_type(const LinphoneCall *call, int stream_index) { + return linphone_call_get_cpp_obj(call)->getStreamType(stream_index); } -RtpTransport* linphone_call_get_meta_rtcp_transport(LinphoneCall *call, int stream_index) { - RtpTransport *meta_rtp; - RtpTransport *meta_rtcp; +RtpTransport * linphone_call_get_meta_rtp_transport(const LinphoneCall *call, int stream_index) { + return linphone_call_get_cpp_obj(call)->getMetaRtpTransport(stream_index); +} - if (!call || stream_index < 0 || stream_index >= linphone_call_get_stream_count(call)) { - return NULL; - } - - rtp_session_get_transports(call->sessions[stream_index].rtp_session, &meta_rtp, &meta_rtcp); - return meta_rtcp; +RtpTransport * linphone_call_get_meta_rtcp_transport(const LinphoneCall *call, int stream_index) { + return linphone_call_get_cpp_obj(call)->getMetaRtcpTransport(stream_index); } LinphoneStatus linphone_call_pause(LinphoneCall *call) { +#if 0 int err = _linphone_call_pause(call); if (err == 0) call->paused_by_app = TRUE; return err; +#else + return 0; +#endif } /* Internal version that does not play tone indication*/ int _linphone_call_pause(LinphoneCall *call) { +#if 0 LinphoneCore *lc; const char *subject = NULL; @@ -5258,11 +1230,6 @@ int _linphone_call_pause(LinphoneCall *call) { call->broken = FALSE; linphone_call_set_state(call, LinphoneCallPausing, "Pausing call"); linphone_call_make_local_media_description(call); -#ifdef BUILD_UPNP - if (call->upnp_session != NULL) { - linphone_call_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); - } -#endif // BUILD_UPNP sal_call_set_local_media_description(call->op, call->localdesc); if (sal_call_update(call->op, subject, FALSE) != 0) { linphone_core_notify_display_warning(lc, _("Could not pause the call")); @@ -5273,9 +1240,13 @@ int _linphone_call_pause(LinphoneCall *call) { linphone_call_stop_media_streams(call); call->paused_by_app = FALSE; return 0; +#else + return 0; +#endif } LinphoneStatus linphone_call_resume(LinphoneCall *call) { +#if 0 LinphoneCore *lc; const char *subject = "Call resuming"; char *remote_address; @@ -5303,11 +1274,6 @@ LinphoneStatus linphone_call_resume(LinphoneCall *call) { if (call->audiostream) audio_stream_play(call->audiostream, NULL); linphone_call_make_local_media_description(call); -#ifdef BUILD_UPNP - if (call->upnp_session != NULL) { - linphone_call_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); - } -#endif // BUILD_UPNP if (!lc->sip_conf.sdp_200_ack) { sal_call_set_local_media_description(call->op, call->localdesc); } else { @@ -5333,84 +1299,24 @@ LinphoneStatus linphone_call_resume(LinphoneCall *call) { sal_call_set_local_media_description(call->op, call->localdesc); } return 0; +#else + return 0; +#endif } static void terminate_call(LinphoneCall *call) { - LinphoneCore *lc = linphone_call_get_core(call); - const bctbx_list_t *calls = linphone_core_get_calls(lc); - bool_t stop_ringing = TRUE; - - if ((call->state == LinphoneCallIncomingReceived) && (linphone_error_info_get_reason(call->ei) != LinphoneReasonNotAnswered)){ - linphone_error_info_set_reason(call->ei, LinphoneReasonDeclined); - call->non_op_error = TRUE; - } - - /* Stop ringing */ - bool_t ring_during_early_media = linphone_core_get_ring_during_incoming_early_media(lc); - while(calls) { - if (((LinphoneCall *)calls->data)->state == LinphoneCallIncomingReceived || (ring_during_early_media && ((LinphoneCall *)calls->data)->state == LinphoneCallIncomingEarlyMedia)) { - stop_ringing = FALSE; - break; - } - calls = calls->next; - } - if(stop_ringing) { - linphone_core_stop_ringing(lc); - } - linphone_call_stop_media_streams(call); - -#ifdef BUILD_UPNP - linphone_call_delete_upnp_session(call); -#endif // BUILD_UPNP - - linphone_core_notify_display_status(lc, _("Call ended") ); - linphone_call_set_state(call, LinphoneCallEnd, "Call terminated"); } LinphoneStatus linphone_call_terminate(LinphoneCall *call) { - return linphone_call_terminate_with_error_info(call, NULL); + return linphone_call_get_cpp_obj(call)->terminate(); } - -LinphoneStatus linphone_call_terminate_with_error_info(LinphoneCall *call , const LinphoneErrorInfo *ei){ - SalErrorInfo sei; - LinphoneErrorInfo* p_ei = (LinphoneErrorInfo*) ei; - - memset(&sei, 0, sizeof(sei)); - ms_message("Terminate call [%p] which is currently in state %s", call, linphone_call_state_to_string(call->state)); - switch (call->state) { - case LinphoneCallReleased: - case LinphoneCallEnd: - case LinphoneCallError: - ms_warning("No need to terminate a call [%p] in state [%s]", call, linphone_call_state_to_string(call->state)); - return -1; - case LinphoneCallIncomingReceived: - case LinphoneCallIncomingEarlyMedia: - return linphone_call_decline_with_error_info(call, p_ei); - case LinphoneCallOutgoingInit: - /* In state OutgoingInit, op has to be destroyed */ - sal_op_release(call->op); - call->op = NULL; - break; - default: - - if (ei == NULL){ - sal_call_terminate(call->op); - } - else{ - linphone_error_info_to_sal(ei, &sei); - sal_call_terminate_with_error(call->op, &sei); - sal_error_info_reset(&sei); - } - break; - } - - terminate_call(call); - return 0; - +LinphoneStatus linphone_call_terminate_with_error_info(LinphoneCall *call , const LinphoneErrorInfo *ei) { + return linphone_call_get_cpp_obj(call)->terminate(ei); } LinphoneStatus linphone_call_redirect(LinphoneCall *call, const char *redirect_uri) { +#if 0 char *real_url = NULL; LinphoneCore *lc; LinphoneAddress *real_parsed_url; @@ -5440,328 +1346,45 @@ LinphoneStatus linphone_call_redirect(LinphoneCall *call, const char *redirect_u linphone_address_unref(real_parsed_url); sal_error_info_reset(&sei); return 0; -} - -LinphoneStatus linphone_call_decline(LinphoneCall * call, LinphoneReason reason) { - LinphoneStatus status; - LinphoneErrorInfo *ei = linphone_error_info_new(); - linphone_error_info_set(ei, "SIP", reason,linphone_reason_to_error_code(reason), NULL, NULL); - status = linphone_call_decline_with_error_info(call, ei); - linphone_error_info_unref(ei); - return status; -} - - -LinphoneStatus linphone_call_decline_with_error_info(LinphoneCall * call, const LinphoneErrorInfo *ei) { - SalErrorInfo sei; - SalErrorInfo sub_sei; - - memset(&sei, 0, sizeof(sei)); - memset(&sub_sei, 0, sizeof(sub_sei)); - sei.sub_sei = &sub_sei; - - if ((call->state != LinphoneCallIncomingReceived) && (call->state != LinphoneCallIncomingEarlyMedia)) { - ms_error("Cannot decline a call that is in state %s", linphone_call_state_to_string(call->state)); - return -1; - } - if (ei) { - linphone_error_info_to_sal(ei, &sei); - sal_call_decline_with_error_info(call->op, &sei , NULL); - }else{ - sal_call_decline(call->op, SalReasonDeclined, NULL); - } - sal_error_info_reset(&sei); - sal_error_info_reset(&sub_sei); - terminate_call(call); +#else return 0; +#endif +} + +LinphoneStatus linphone_call_decline(LinphoneCall *call, LinphoneReason reason) { + return linphone_call_get_cpp_obj(call)->decline(reason); +} + +LinphoneStatus linphone_call_decline_with_error_info(LinphoneCall *call, const LinphoneErrorInfo *ei) { + return linphone_call_get_cpp_obj(call)->decline(ei); } LinphoneStatus linphone_call_accept(LinphoneCall *call) { - return linphone_call_accept_with_params(call, NULL); + return linphone_call_get_cpp_obj(call)->accept(nullptr); } LinphoneStatus linphone_call_accept_with_params(LinphoneCall *call, const LinphoneCallParams *params) { - LinphoneCore *lc; - SalOp *replaced; - SalMediaDescription *new_md; - bool_t was_ringing = FALSE; - bctbx_list_t *iterator, *copy; - - switch (call->state) { - case LinphoneCallIncomingReceived: - case LinphoneCallIncomingEarlyMedia: - break; - default: - ms_error("linphone_core_accept_call_with_params() call [%p] is in state [%s], operation not permitted.", - call, linphone_call_state_to_string(call->state)); - return -1; - } - - lc = linphone_call_get_core(call); - for (iterator = copy = bctbx_list_copy(linphone_core_get_calls(lc)); iterator != NULL; iterator = bctbx_list_next(iterator)) { - LinphoneCall *a_call = (LinphoneCall *)bctbx_list_get_data(iterator); - if (a_call == call) continue; - switch (a_call->state) { - case LinphoneCallOutgoingInit: - case LinphoneCallOutgoingProgress: - case LinphoneCallOutgoingRinging: - case LinphoneCallOutgoingEarlyMedia: - ms_message("Already existing call [%p] in state [%s], canceling it before accepting new call [%p]", - a_call, linphone_call_state_to_string(a_call->state), call); - linphone_call_terminate(a_call); - break; - default: - break; /* Nothing to do */ - } - } - bctbx_list_free(copy); - - /* Check if this call is supposed to replace an already running one */ - replaced = sal_call_get_replaces(call->op); - if (replaced) { - LinphoneCall *rc = (LinphoneCall *)sal_op_get_user_pointer(replaced); - if (rc) { - ms_message("Call %p replaces call %p. This last one is going to be terminated automatically.", call, rc); - linphone_call_terminate(rc); - } - } - - if (lc->current_call != call) { - linphone_core_preempt_sound_resources(lc); - } - - /* Stop ringing */ - if (linphone_ringtoneplayer_is_started(lc->ringtoneplayer)) { - ms_message("Stop ringing"); - linphone_core_stop_ringing(lc); - was_ringing = TRUE; - } - if (call->ringing_beep) { - linphone_core_stop_dtmf(lc); - call->ringing_beep = FALSE; - } - - /* Try to be best-effort in giving real local or routable contact address */ - linphone_call_set_contact_op(call); - if (params) { - _linphone_call_set_new_params(call, params); - linphone_call_prepare_ice(call, TRUE); - linphone_call_make_local_media_description(call); - sal_call_set_local_media_description(call->op, call->localdesc); - sal_op_set_sent_custom_header(call->op, linphone_call_params_get_custom_headers(params)); - } - - /* Give a chance a set card prefered sampling frequency */ - if (call->localdesc->streams[0].max_rate > 0) { - ms_message("Configuring prefered card sampling rate to [%i]", call->localdesc->streams[0].max_rate); - if (lc->sound_conf.play_sndcard) - ms_snd_card_set_preferred_sample_rate(lc->sound_conf.play_sndcard, call->localdesc->streams[0].max_rate); - if (lc->sound_conf.capt_sndcard) - ms_snd_card_set_preferred_sample_rate(lc->sound_conf.capt_sndcard, call->localdesc->streams[0].max_rate); - } - - if (!was_ringing && (call->audiostream->ms.state == MSStreamInitialized) && !lc->use_files) { - audio_stream_prepare_sound(call->audiostream, lc->sound_conf.play_sndcard, lc->sound_conf.capt_sndcard); - } - - linphone_call_update_remote_session_id_and_ver(call); - - sal_call_accept(call->op); - linphone_core_notify_display_status(lc, _("Connected.")); - lc->current_call = call; - linphone_call_set_state(call, LinphoneCallConnected, "Connected"); - new_md = sal_call_get_final_media_description(call->op); - linphone_call_stop_ice_for_inactive_streams(call, new_md); - if (new_md) { - linphone_call_update_streams(call, new_md, LinphoneCallStreamsRunning); - linphone_call_set_state(call, LinphoneCallStreamsRunning, "Connected (streams running)"); - } else { - call->expect_media_in_ack = TRUE; - } - - ms_message("Call answered"); - return 0; + return linphone_call_get_cpp_obj(call)->accept(params ? linphone_call_params_get_cpp_obj(params) : nullptr); } LinphoneStatus linphone_call_accept_early_media(LinphoneCall* call) { - return linphone_call_accept_early_media_with_params(call, NULL); + return linphone_call_get_cpp_obj(call)->acceptEarlyMedia(); } LinphoneStatus linphone_call_accept_early_media_with_params(LinphoneCall *call, const LinphoneCallParams *params) { - SalMediaDescription* md; - - if (call->state != LinphoneCallIncomingReceived) { - ms_error("Bad state %s for linphone_core_accept_early_media_with_params()", linphone_call_state_to_string(call->state)); - return -1; - } - - /* Try to be best-effort in giving real local or routable contact address for 100Rel case */ - linphone_call_set_contact_op(call); - - /* If parameters are passed, update the media description */ - if (params) { - _linphone_call_set_new_params(call, params); - linphone_call_make_local_media_description(call); - sal_call_set_local_media_description(call->op, call->localdesc); - sal_op_set_sent_custom_header(call->op, linphone_call_params_get_custom_headers(params)); - } - - sal_call_notify_ringing(call->op, TRUE); - - linphone_call_set_state(call, LinphoneCallIncomingEarlyMedia, "Incoming call early media"); - md = sal_call_get_final_media_description(call->op); - if (md) linphone_call_update_streams(call, md, call->state); - return 0; + return linphone_call_get_cpp_obj(call)->acceptEarlyMedia(params ? linphone_call_params_get_cpp_obj(params) : nullptr); } LinphoneStatus linphone_call_update(LinphoneCall *call, const LinphoneCallParams *params) { - int err = 0; - LinphoneCallState nextstate; - LinphoneCallState initial_state = call->state; - const LinphoneCallParams *current_params; - -#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP) - bool_t has_video = FALSE; -#endif - - switch (initial_state) { - case LinphoneCallIncomingReceived: - case LinphoneCallIncomingEarlyMedia: - case LinphoneCallOutgoingRinging: - case LinphoneCallOutgoingEarlyMedia: - nextstate = LinphoneCallEarlyUpdating; - break; - case LinphoneCallStreamsRunning: - case LinphoneCallPausedByRemote: - case LinphoneCallUpdatedByRemote: - nextstate = LinphoneCallUpdating; - break; - case LinphoneCallPaused: - nextstate = LinphoneCallPausing; - break; - case LinphoneCallOutgoingProgress: - case LinphoneCallPausing: - case LinphoneCallResuming: - case LinphoneCallUpdating: - nextstate = initial_state; - break; - default: - ms_error("linphone_call_update() is not allowed in [%s] state", linphone_call_state_to_string(call->state)); - return -1; - } - - current_params = linphone_call_get_current_params(call); - if ((current_params != NULL) && (current_params == params)) { - ms_warning("linphone_call_update() is given the current params of the call, this probably not what you intend to do!"); - } - - linphone_call_check_ice_session(call, IR_Controlling, TRUE); - - if (params != NULL) { - call->broken = FALSE; - linphone_call_set_state(call, nextstate, "Updating call"); -#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP) - has_video = call->params->has_video; - - /* Video removal */ - if ((call->videostream != NULL) && !params->has_video) { - if (call->upnp_session != NULL) { - if (linphone_call_update_upnp(call) < 0) { - /* uPnP port mappings failed, proceed with the call anyway. */ - linphone_call_delete_upnp_session(call); - } - } - } -#endif /* defined(VIDEO_ENABLED) && defined(BUILD_UPNP) */ - _linphone_call_set_new_params(call, params); - err = linphone_call_prepare_ice(call, FALSE); - if (err == 1) { - ms_message("Defer call update to gather ICE candidates"); - return 0; - } - -#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP) - /* Video adding */ - if (!has_video && call->params->has_video) { - if(call->upnp_session != NULL) { - ms_message("Defer call update to add uPnP port mappings"); - video_stream_prepare_video(call->videostream); - if (linphone_call_update_upnp(call) < 0) { - /* uPnP port mappings failed, proceed with the call anyway. */ - linphone_call_delete_upnp_session(call); - } else { - return err; - } - } - } -#endif /* defined(VIDEO_ENABLED) && defined(BUILD_UPNP) */ - if ((err = linphone_call_start_update(call)) && (call->state != initial_state)) { - /* Restore initial state */ - linphone_call_set_state(call, initial_state, "Restore initial state"); - } - } else { -#ifdef VIDEO_ENABLED - LinphoneCore *lc = linphone_call_get_core(call); - if ((call->videostream != NULL) && (call->state == LinphoneCallStreamsRunning)) { - video_stream_set_sent_video_size(call->videostream, linphone_core_get_preferred_video_size(lc)); - video_stream_set_fps(call->videostream, linphone_core_get_preferred_framerate(lc)); - if (call->camera_enabled && (call->videostream->cam != lc->video_conf.device)) { - video_stream_change_camera(call->videostream, lc->video_conf.device); - } else { - video_stream_update_video_params(call->videostream); - } - } -#endif - } - - return err; + return linphone_call_get_cpp_obj(call)->update(params ? linphone_call_params_get_cpp_obj(params) : nullptr); } int linphone_call_start_update(LinphoneCall *call) { - const char *subject; - int err; - bool_t no_user_consent = linphone_call_params_get_no_user_consent(call->params); - LinphoneCore *lc = linphone_call_get_core(call); - - linphone_call_fill_media_multicast_addr(call); - - if (!no_user_consent) linphone_call_make_local_media_description(call); -#ifdef BUILD_UPNP - if (call->upnp_session != NULL) { - linphone_call_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); - } -#endif // BUILD_UPNP - if (linphone_call_params_get_in_conference(call->params)) { - subject = "Conference"; - } else if (linphone_call_params_get_internal_call_update(call->params)) { - subject = "ICE processing concluded"; - } else if (no_user_consent) { - subject = "Refreshing"; - } else { - subject = "Media change"; - } - linphone_core_notify_display_status(lc, _("Modifying call parameters...")); - if (!lc->sip_conf.sdp_200_ack) { - sal_call_set_local_media_description(call->op, call->localdesc); - } else { - sal_call_set_local_media_description(call->op, NULL); - } - if (call->dest_proxy && call->dest_proxy->op) { - /* Give a chance to update the contact address if connectivity has changed */ - sal_op_set_contact_address(call->op, sal_op_get_contact_address(call->dest_proxy->op)); - } else { - sal_op_set_contact_address(call->op, NULL); - } - err = sal_call_update(call->op, subject, no_user_consent); - if (lc->sip_conf.sdp_200_ack) { - /* We are NOT offering, set local media description after sending the call so that we are ready to - process the remote offer when it will arrive. */ - sal_call_set_local_media_description(call->op, call->localdesc); - } - return err; + return 0; } LinphoneStatus linphone_call_defer_update(LinphoneCall *call) { +#if 0 if (call->state != LinphoneCallUpdatedByRemote) { ms_error("linphone_call_defer_update() not done in state LinphoneCallUpdatedByRemote"); return -1; @@ -5774,105 +1397,21 @@ LinphoneStatus linphone_call_defer_update(LinphoneCall *call) { call->defer_update=TRUE; return 0; +#else + return 0; +#endif } int linphone_call_start_accept_update(LinphoneCall *call, LinphoneCallState next_state, const char *state_info) { - SalMediaDescription *md; - - if ((call->ice_session != NULL) && (ice_session_nb_losing_pairs(call->ice_session) > 0)) { - /* Defer the sending of the answer until there are no losing pairs left */ - return 0; - } - - linphone_call_make_local_media_description(call); - linphone_call_update_remote_session_id_and_ver(call); - sal_call_set_local_media_description(call->op, call->localdesc); - sal_call_accept(call->op); - md = sal_call_get_final_media_description(call->op); - linphone_call_stop_ice_for_inactive_streams(call, md); - if (md && !sal_media_description_empty(md)) { - linphone_call_update_streams(call, md, next_state); - } - linphone_call_set_state(call, next_state, state_info); - return 0; -} - -int _linphone_call_accept_update(LinphoneCall *call, const LinphoneCallParams *params, LinphoneCallState next_state, const char *state_info) { - SalMediaDescription *remote_desc; - bool_t keep_sdp_version; - LinphoneCore *lc = linphone_call_get_core(call); -#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP) - bool_t old_has_video = call->params->has_video; -#endif - - remote_desc = sal_call_get_remote_media_description(call->op); - keep_sdp_version = lp_config_get_int(lc->config, "sip", "keep_sdp_version", 0); - if (keep_sdp_version && (remote_desc->session_id == call->remote_session_id) && (remote_desc->session_ver == call->remote_session_ver)) { - /* Remote has sent an INVITE with the same SDP as before, so send a 200 OK with the same SDP as before. */ - ms_warning("SDP version has not changed, send same SDP as before."); - sal_call_accept(call->op); - linphone_call_set_state(call, next_state, state_info); - return 0; - } - if (params == NULL) { - if (!sal_call_is_offerer(call->op)) { - /* Reset call param for multicast because this param is only relevant when offering */ - linphone_call_params_enable_audio_multicast(call->params, FALSE); - linphone_call_params_enable_video_multicast(call->params, FALSE); - } - } else { - _linphone_call_set_new_params(call, params); - } - - if (linphone_call_params_video_enabled(call->params) && !linphone_core_video_enabled(lc)) { - ms_warning("Requested video but video support is globally disabled. Refusing video."); - linphone_call_params_enable_video(call->params, FALSE); - } - if (linphone_call_params_get_in_conference(call->current_params)) { - ms_warning("Video isn't supported in conference"); - linphone_call_params_enable_video(call->params, FALSE); - } - /* Update multicast params according to call params */ - linphone_call_fill_media_multicast_addr(call); - - linphone_call_check_ice_session(call, IR_Controlled, TRUE); - linphone_call_init_media_streams(call); /* So that video stream is initialized if necessary */ - if (linphone_call_prepare_ice(call, TRUE) == 1) { - return 0; /* Deferred until completion of ICE gathering */ - } - -#ifdef BUILD_UPNP - if (call->upnp_session != NULL) { - linphone_call_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(call->op)); -#ifdef VIDEO_ENABLED - if ((call->params->has_video) && (call->params->has_video != old_has_video)) { - video_stream_prepare_video(call->videostream); - if (linphone_call_update_upnp(call) < 0) { - /* uPnP update failed, proceed with the call anyway. */ - linphone_call_delete_upnp_session(call); - } else return 0; - } -#endif // VIDEO_ENABLED - } -#endif // BUILD_UPNP - - linphone_call_start_accept_update(call, next_state, state_info); return 0; } LinphoneStatus linphone_call_accept_update(LinphoneCall *call, const LinphoneCallParams *params) { - if (call->state != LinphoneCallUpdatedByRemote) { - ms_error("linphone_call_accept_update(): invalid state %s to call this function.", linphone_call_state_to_string(call->state)); - return -1; - } - if (call->expect_media_in_ack) { - ms_error("linphone_call_accept_update() is not possible during a late offer incoming reINVITE (INVITE without SDP)"); - return -1; - } - return _linphone_call_accept_update(call, params, call->prevstate, linphone_call_state_to_string(call->prevstate)); + return linphone_call_get_cpp_obj(call)->acceptUpdate(params ? linphone_call_params_get_cpp_obj(params) : nullptr); } LinphoneStatus linphone_call_transfer(LinphoneCall *call, const char *refer_to) { +#if 0 char *real_url = NULL; LinphoneCore *lc = linphone_call_get_core(call); LinphoneAddress *real_parsed_url = linphone_core_interpret_url(lc, refer_to); @@ -5888,15 +1427,23 @@ LinphoneStatus linphone_call_transfer(LinphoneCall *call, const char *refer_to) linphone_address_unref(real_parsed_url); linphone_call_set_transfer_state(call, LinphoneCallOutgoingInit); return 0; +#else + return 0; +#endif } LinphoneStatus linphone_call_transfer_to_another(LinphoneCall *call, LinphoneCall *dest) { +#if 0 int result = sal_call_refer_with_replaces (call->op, dest->op); linphone_call_set_transfer_state(call, LinphoneCallOutgoingInit); return result; +#else + return 0; +#endif } int linphone_call_abort(LinphoneCall *call, const char *error) { +#if 0 LinphoneCore *lc = linphone_call_get_core(call); sal_call_terminate(call->op); @@ -5905,120 +1452,24 @@ int linphone_call_abort(LinphoneCall *call, const char *error) { linphone_core_stop_ringing(lc); linphone_call_stop_media_streams(call); -#ifdef BUILD_UPNP - linphone_call_delete_upnp_session(call); -#endif // BUILD_UPNP - linphone_core_notify_display_status(lc, _("Call aborted")); linphone_call_set_state(call, LinphoneCallError, error); return 0; +#else + return 0; +#endif } int linphone_call_proceed_with_invite_if_ready(LinphoneCall *call, LinphoneProxyConfig *dest_proxy) { - bool_t ice_ready = FALSE; - bool_t upnp_ready = FALSE; - bool_t ping_ready = FALSE; - - if (call->ice_session != NULL) { - if (ice_session_candidates_gathered(call->ice_session)) ice_ready = TRUE; - } else { - ice_ready = TRUE; - } -#ifdef BUILD_UPNP - if (call->upnp_session != NULL) { - if (linphone_upnp_session_get_state(call->upnp_session) == LinphoneUpnpStateOk) upnp_ready = TRUE; - } else { - upnp_ready = TRUE; - } -#else - upnp_ready=TRUE; -#endif // BUILD_UPNP - if (call->ping_op != NULL) { - if (call->ping_replied == TRUE) ping_ready = TRUE; - } else { - ping_ready = TRUE; - } - - if ((ice_ready == TRUE) && (upnp_ready == TRUE) && (ping_ready == TRUE)) { - return linphone_call_start_invite(call, NULL); - } return 0; } int linphone_call_start_invite(LinphoneCall *call, const LinphoneAddress *destination /* = NULL if to be taken from the call log */) { - int err; - char *real_url, *barmsg; - char *from; - LinphoneCore *lc = linphone_call_get_core(call); - - /* Try to be best-effort in giving real local or routable contact address */ - linphone_call_set_contact_op(call); - - linphone_core_stop_dtmf_stream(lc); - linphone_call_make_local_media_description(call); - - if (lc->ringstream == NULL) { - if (lc->sound_conf.play_sndcard && lc->sound_conf.capt_sndcard) { - /* Give a chance a set card prefered sampling frequency */ - if (call->localdesc->streams[0].max_rate > 0) { - ms_snd_card_set_preferred_sample_rate(lc->sound_conf.play_sndcard, call->localdesc->streams[0].max_rate); - } - if (!lc->use_files) { - audio_stream_prepare_sound(call->audiostream, lc->sound_conf.play_sndcard, lc->sound_conf.capt_sndcard); - } - } - } - real_url = linphone_address_as_string(destination ? destination : call->log->to); - from = linphone_address_as_string(call->log->from); - - if (!lc->sip_conf.sdp_200_ack) { - /* We are offering, set local media description before sending the call */ - sal_call_set_local_media_description(call->op, call->localdesc); - } - - barmsg = ms_strdup_printf("%s %s", _("Contacting"), real_url); - linphone_core_notify_display_status(lc, barmsg); - ms_free(barmsg); - - linphone_call_ref(call); /* Take a ref because sal_call() may destroy the call if no SIP transport is available */ - err = sal_call(call->op, from, real_url); - - if (err < 0) { - if ((call->state != LinphoneCallError) && (call->state != LinphoneCallReleased)) { - /* sal_call() may invoke call_failure() and call_released() SAL callbacks synchronously, - in which case there is no need to perform a state change here. */ - linphone_core_notify_display_status(lc, _("Could not call")); - linphone_call_stop_media_streams(call); - linphone_call_set_state(call, LinphoneCallError, "Call failed"); - } - goto end; - } - if (lc->sip_conf.sdp_200_ack) { - /* We are NOT offering, set local media description after sending the call so that we are ready to - process the remote offer when it will arrive. */ - sal_call_set_local_media_description(call->op, call->localdesc); - } - call->log->call_id = ms_strdup(sal_op_get_call_id(call->op)); /* Must be known at that time */ - linphone_call_set_state(call, LinphoneCallOutgoingProgress, "Outgoing call in progress"); - -end: - linphone_call_unref(call); /* Revert the ref taken before calling sal_call() */ - ms_free(real_url); - ms_free(from); - return err; -} - -int linphone_call_restart_invite(LinphoneCall *call) { - linphone_call_create_op(call); - linphone_call_stop_media_streams(call); - ms_media_stream_sessions_uninit(&call->sessions[call->main_audio_stream_index]); - ms_media_stream_sessions_uninit(&call->sessions[call->main_video_stream_index]); - ms_media_stream_sessions_uninit(&call->sessions[call->main_text_stream_index]); - linphone_call_init_media_streams(call); - return linphone_call_start_invite(call, NULL); + return 0; } void linphone_call_set_broken(LinphoneCall *call){ +#if 0 switch(call->state){ /*for all the early states, we prefer to drop the call*/ case LinphoneCallOutgoingInit: @@ -6046,6 +1497,7 @@ void linphone_call_set_broken(LinphoneCall *call){ ms_error("linphone_call_set_broken() unimplemented case."); break; } +#endif } static void linphone_call_repair_by_invite_with_replaces(LinphoneCall *call) { @@ -6059,6 +1511,7 @@ static void linphone_call_repair_by_invite_with_replaces(LinphoneCall *call) { } void linphone_call_reinvite_to_recover_from_connection_loss(LinphoneCall *call) { +#if 0 LinphoneCallParams *params; ms_message("LinphoneCall[%p] is going to be updated (reINVITE) in order to recover from lost connectivity", call); if (call->ice_session){ @@ -6067,9 +1520,11 @@ void linphone_call_reinvite_to_recover_from_connection_loss(LinphoneCall *call) params = linphone_core_create_call_params(call->core, call); linphone_call_update(call, params); linphone_call_params_unref(params); +#endif } void linphone_call_repair_if_broken(LinphoneCall *call){ +#if 0 SalErrorInfo sei; if (!call->broken) return; if (!call->core->media_network_reachable) return; @@ -6126,9 +1581,11 @@ void linphone_call_repair_if_broken(LinphoneCall *call){ break; } sal_error_info_reset(&sei); +#endif } void linphone_call_refresh_sockets(LinphoneCall *call){ +#if 0 int i; for (i=0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i){ MSMediaStreamSessions *mss = &call->sessions[i]; @@ -6136,9 +1593,11 @@ void linphone_call_refresh_sockets(LinphoneCall *call){ rtp_session_refresh_sockets(mss->rtp_session); } } +#endif } void linphone_call_replace_op(LinphoneCall *call, SalOp *op) { +#if 0 SalOp *oldop = call->op; LinphoneCallState oldstate = linphone_call_get_state(call); call->op = op; @@ -6177,9 +1636,11 @@ void linphone_call_replace_op(LinphoneCall *call, SalOp *op) { break; } sal_op_release(oldop); +#endif } void linphone_call_ogl_render(const LinphoneCall *call) { +#if 0 #ifdef VIDEO_ENABLED VideoStream *stream = call->videostream; @@ -6187,6 +1648,7 @@ void linphone_call_ogl_render(const LinphoneCall *call) { ms_filter_call_method(stream->output, MS_OGL_RENDER, NULL); #endif +#endif } void linphone_call_add_callbacks(LinphoneCall *call, LinphoneCallCbs *cbs) { @@ -6244,3 +1706,35 @@ void linphone_call_notify_info_message_received(LinphoneCall *call, const Linpho void linphone_call_notify_ack_processing(LinphoneCall *call, LinphoneHeaders *msg, bool_t is_received) { NOTIFY_IF_EXIST(ack_processing, call, msg, is_received) } + +SalOp * linphone_call_get_op(const LinphoneCall *call) { + return L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->getOp(); +} + +LinphoneProxyConfig * linphone_call_get_dest_proxy(const LinphoneCall *call) { + return L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->getDestProxy(); +} + +LinphoneCallLog * linphone_call_get_log(const LinphoneCall *call) { + return linphone_call_get_call_log(call); +} + +IceSession * linphone_call_get_ice_session(const LinphoneCall *call) { + return L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->getIceSession(); +} + +bool_t linphone_call_get_audio_muted(const LinphoneCall *call) { + return L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->getAudioMuted(); +} + +void linphone_call_set_audio_muted(LinphoneCall *call, bool_t value) { + L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->setAudioMuted(value); +} + +bool_t linphone_call_get_all_muted(const LinphoneCall *call) { + return linphone_call_get_cpp_obj(call)->getAllMuted(); +} + +std::shared_ptr linphone_call_get_cpp_obj(const LinphoneCall *call) { + return call->call; +} diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index b3a6a8d7e..5025a3880 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -65,6 +65,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "TargetConditionals.h" #endif +#include "c-wrapper/c-tools.h" +#include "call/call-p.h" +#include "conference/params/media-session-params-p.h" + #ifdef HAVE_ZLIB #define COMPRESSED_LOG_COLLECTION_EXTENSION "gz" #ifdef _WIN32 @@ -443,7 +447,7 @@ int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){ bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call){ //return TRUE if the unique(for the moment) incoming call asked to be autoanswered if(call) - return sal_call_autoanswer_asked(call->op); + return sal_call_autoanswer_asked(linphone_call_get_op(call)); else return FALSE; } @@ -1565,8 +1569,10 @@ static bool_t get_codec(LinphoneCore *lc, SalStreamType type, int index, Payload payload_type_set_recv_fmtp(pt,fmtp); *default_list=bctbx_list_append(*default_list, pt); } - if (enabled ) pt->flags|=PAYLOAD_TYPE_ENABLED; - else pt->flags&=~PAYLOAD_TYPE_ENABLED; + if (enabled) + payload_type_set_enable(pt, TRUE); + else + payload_type_set_enable(pt, FALSE); *ret=pt; return TRUE; } @@ -1973,6 +1979,7 @@ static void misc_config_read(LinphoneCore *lc) { sal_set_uuid(lc->sal, uuid); lc->user_certificates_path=ms_strdup(lp_config_get_string(config,"misc","user_certificates_path",".")); + lc->send_call_stats_periodical_updates = lp_config_get_int(config, "misc", "send_call_stats_periodical_updates", 0); } void linphone_core_reload_ms_plugins(LinphoneCore *lc, const char *path){ @@ -2637,7 +2644,7 @@ static void apply_jitter_value(LinphoneCore *lc, int value, MSFormatType stype){ for (it=lc->calls;it!=NULL;it=it->next){ MediaStream *ms; call=(LinphoneCall*)it->data; - ms = stype==MSAudio ? (MediaStream*)call->audiostream : (MediaStream*)call->videostream; + ms = stype==MSAudio ? linphone_call_get_stream(call, LinphoneStreamTypeAudio) : linphone_call_get_stream(call, LinphoneStreamTypeVideo); if (ms){ RtpSession *s=ms->sessions.rtp_session; if (s){ @@ -3124,7 +3131,6 @@ void linphone_core_iterate(LinphoneCore *lc){ bctbx_list_t *calls; LinphoneCall *call; uint64_t curtime_ms = ms_get_cur_time_ms(); /*monotonic time*/ - int elapsed; time_t current_real_time = ms_time(NULL); int64_t diff_time; bool_t one_second_elapsed=FALSE; @@ -3213,51 +3219,14 @@ void linphone_core_iterate(LinphoneCore *lc){ proxy_update(lc); - //we have to iterate for each call + /* We have to iterate for each call */ calls = lc->calls; - while(calls!= NULL){ - call = (LinphoneCall *)calls->data; - elapsed = (int)(current_real_time - call->log->start_date_time); - /* get immediately a reference to next one in case the one - we are going to examine is destroy and removed during - linphone_call_start_invite() */ - calls=calls->next; - linphone_call_background_tasks(call,one_second_elapsed); - if (call->state==LinphoneCallOutgoingInit && (elapsed>=lc->sip_conf.delayed_timeout)){ - /*start the call even if the OPTIONS reply did not arrive*/ - if (call->ice_session != NULL) { - ms_warning("ICE candidates gathering from [%s] has not finished yet, proceed with the call without ICE anyway." - ,linphone_nat_policy_get_stun_server(call->nat_policy)); - linphone_call_delete_ice_session(call); - linphone_call_stop_media_streams_for_ice_gathering(call); - } -#ifdef BUILD_UPNP - if (call->upnp_session != NULL) { - ms_warning("uPnP mapping has not finished yet, proceeded with the call without uPnP anyway."); - linphone_call_delete_upnp_session(call); - } -#endif //BUILD_UPNP - linphone_call_start_invite(call, NULL); - } - if (call->state==LinphoneCallIncomingReceived || call->state==LinphoneCallIncomingEarlyMedia){ - if (one_second_elapsed) ms_message("incoming call ringing for %i seconds",elapsed); - if (elapsed>lc->sip_conf.inc_timeout){ - LinphoneReason decline_reason; - ms_message("incoming call timeout (%i)",lc->sip_conf.inc_timeout); - decline_reason = (lc->current_call != call) ? LinphoneReasonBusy : LinphoneReasonDeclined; - call->log->status=LinphoneCallMissed; - call->non_op_error = TRUE; - linphone_error_info_set(call->ei, NULL, decline_reason, linphone_reason_to_error_code(decline_reason), "Not answered", NULL); - linphone_call_decline(call, decline_reason); - } - } - if ( (lc->sip_conf.in_call_timeout > 0) - && (call->log->connected_date_time != 0) - && ((current_real_time - call->log->connected_date_time) > lc->sip_conf.in_call_timeout)) - { - ms_message("in call timeout (%i)",lc->sip_conf.in_call_timeout); - linphone_call_terminate(call); - } + while (calls) { + call = reinterpret_cast(bctbx_list_get_data(calls)); + /* Get immediately a reference to next one in case the one we are going to examine is destroyed + * and removed during linphone_call_start_invite() */ + calls = bctbx_list_next(calls); + L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->iterate(current_real_time, one_second_elapsed); } if (linphone_core_video_preview_enabled(lc)){ @@ -3330,6 +3299,7 @@ const char * linphone_core_get_route(LinphoneCore *lc){ } LinphoneCall * linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){ +#if 0 LinphoneCallParams *cp=params ? linphone_call_params_copy(params) : linphone_core_create_call_params(lc, NULL); LinphoneCall *newcall; @@ -3353,12 +3323,17 @@ LinphoneCall * linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall * linphone_core_notify_refer_state(lc,call,newcall); } return newcall; +#else + return nullptr; +#endif } void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, LinphoneCall *newcall){ +#if 0 if (referer->op!=NULL){ sal_call_notify_refer_state(referer->op,newcall ? newcall->op : NULL); } +#endif } /* @@ -3528,9 +3503,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const const char *from=NULL; LinphoneProxyConfig *proxy=NULL; LinphoneAddress *parsed_url2=NULL; - char *real_url=NULL; LinphoneCall *call; - bool_t defer = FALSE; LinphoneCallParams *cp; if (!(!linphone_call_params_audio_enabled(params) || @@ -3548,10 +3521,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const } cp = linphone_call_params_copy(params); - - real_url=linphone_address_as_string(addr); proxy=linphone_core_lookup_known_proxy(lc,addr); - if (proxy!=NULL) { from=linphone_proxy_config_get_identity(proxy); linphone_call_params_enable_avpf(cp, linphone_proxy_config_avpf_enabled(proxy)); @@ -3565,8 +3535,8 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const if (from==NULL) from=linphone_core_get_primary_contact(lc); parsed_url2=linphone_address_new(from); - - call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(addr),cp,proxy); + call=linphone_call_new_outgoing(lc,parsed_url2,addr,cp,proxy); + linphone_address_unref(parsed_url2); if(linphone_core_add_call(lc,call)!= 0) { @@ -3576,56 +3546,19 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const return NULL; } +#if 0 /* Unless this call is for a conference, it becomes now the current one*/ - if (linphone_call_params_get_local_conference_mode(params) == FALSE) lc->current_call=call; - linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call"); - call->log->start_date_time=ms_time(NULL); - linphone_call_init_media_streams(call); - - if (linphone_nat_policy_ice_enabled(call->nat_policy)) { - if (lc->sip_conf.sdp_200_ack){ - ms_warning("ICE is not supported when sending INVITE without SDP"); - }else{ - /* Defer the start of the call after the ICE gathering process. */ - if (linphone_call_prepare_ice(call,FALSE)==1) - defer=TRUE; - } - } - else if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) { -#ifdef BUILD_UPNP - if (linphone_call_update_upnp(call) < 0) { - /* uPnP port mappings failed, proceed with the call anyway. */ - linphone_call_delete_upnp_session(call); - } else { - defer = TRUE; - } -#endif // BUILD_UPNP - } - - if (call->dest_proxy==NULL && lc->sip_conf.ping_with_options==TRUE){ -#ifdef BUILD_UPNP - if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp && - linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) { -#else //BUILD_UPNP - { -#endif //BUILD_UPNP - /*defer the start of the call after the OPTIONS ping*/ - call->ping_replied=FALSE; - call->ping_op=sal_op_new(lc->sal); - sal_ping(call->ping_op,from,real_url); - sal_op_set_user_pointer(call->ping_op,call); - defer = TRUE; + if (linphone_call_params_get_local_conference_mode(params) == FALSE) +#endif + lc->current_call=call; + bool defer = L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->initiateOutgoing(); + if (!defer) { + if (L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->startInvite(nullptr) != 0) { + /* The call has already gone to error and released state, so do not return it */ + call = nullptr; } } - if (defer==FALSE) { - if (linphone_call_start_invite(call,NULL) != 0){ - /*the call has already gone to error and released state, so do not return it*/ - call = NULL; - } - } - - if (real_url!=NULL) ms_free(real_url); linphone_call_params_unref(cp); return call; } @@ -3642,12 +3575,11 @@ LinphoneStatus linphone_core_transfer_call_to_another(LinphoneCore *lc, Linphone return linphone_call_transfer_to_another(call, dest); } -bool_t linphone_core_is_incoming_invite_pending(LinphoneCore*lc){ +bool_t linphone_core_is_incoming_invite_pending(LinphoneCore*lc) { LinphoneCall *call = linphone_core_get_current_call(lc); - if(call != NULL) - { - if(call->dir==LinphoneCallIncoming - && (call->state == LinphoneCallIncomingReceived || call->state == LinphoneCallIncomingEarlyMedia)) + if (call) { + if ((linphone_call_get_dir(call) == LinphoneCallIncoming) + && ((linphone_call_get_state(call) == LinphoneCallIncomingReceived) || (linphone_call_get_state(call) == LinphoneCallIncomingEarlyMedia))) return TRUE; } return FALSE; @@ -3658,21 +3590,7 @@ bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription } void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ - char *barmesg; - char *tmp; - LinphoneAddress *from_parsed; - bool_t propose_early_media=lp_config_get_int(lc->config,"sip","incoming_calls_early_media",FALSE); - - from_parsed=linphone_address_new(sal_op_get_from(call->op)); - linphone_address_clean(from_parsed); - tmp=linphone_address_as_string(from_parsed); - linphone_address_unref(from_parsed); - barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"), - (sal_call_autoanswer_asked(call->op)) ?_(" and asked autoanswer."):"."); - linphone_core_notify_show_interface(lc); - linphone_core_notify_display_status(lc,barmesg); - - /* play the ring if this is the only call*/ + /* Play the ring if this is the only call*/ if (bctbx_list_size(lc->calls)==1){ MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard; lc->current_call=call; @@ -3682,34 +3600,11 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ linphone_ringtoneplayer_start(lc->factory, lc->ringtoneplayer, ringcard, lc->sound_conf.local_ring, 2000); }else{ /* else play a tone within the context of the current call */ +#if 0 call->ringing_beep=TRUE; +#endif linphone_core_play_named_tone(lc,LinphoneToneCallWaiting); } - - linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call"); - /*from now on, the application is aware of the call and supposed to take background task or already submitted notification to the user. - We can then drop our background task.*/ - if (call->bg_task_id!=0) { - sal_end_background_task(call->bg_task_id); - call->bg_task_id=0; - } - - if (call->state==LinphoneCallIncomingReceived){ - /*try to be best-effort in giving real local or routable contact address for 100Rel case*/ - linphone_call_set_contact_op(call); - - if (propose_early_media){ - linphone_call_accept_early_media(call); - }else sal_call_notify_ringing(call->op,FALSE); - - if (sal_call_get_replaces(call->op)!=NULL && lp_config_get_int(lc->config,"sip","auto_answer_replacing_calls",1)){ - linphone_call_accept(call); - } - } - linphone_call_unref(call); - - ms_free(barmesg); - ms_free(tmp); } LinphoneStatus linphone_core_accept_early_media_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) { @@ -4122,11 +4017,11 @@ void linphone_core_set_mic_gain_db (LinphoneCore *lc, float gaindb){ lp_config_set_float(lc->config,"sound","mic_gain_db",lc->sound_conf.soft_mic_lev); } - if (call==NULL || (st=call->audiostream)==NULL){ + if (!call || !(st = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeAudio)))) { ms_message("linphone_core_set_mic_gain_db(): no active call."); return; } - set_mic_gain_db(st,gain); + audio_stream_set_mic_gain_db(st,gain); } float linphone_core_get_mic_gain_db(LinphoneCore *lc) { @@ -4143,7 +4038,7 @@ void linphone_core_set_playback_gain_db (LinphoneCore *lc, float gaindb){ lp_config_set_float(lc->config,"sound","playback_gain_db",lc->sound_conf.soft_play_lev); } - if (call==NULL || (st=call->audiostream)==NULL){ + if (!call || !(st = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeAudio)))) { ms_message("linphone_core_set_playback_gain_db(): no active call."); return; } @@ -4471,9 +4366,10 @@ void linphone_core_enable_mic(LinphoneCore *lc, bool_t enable) { list = linphone_core_get_calls(lc); for (elem = list; elem != NULL; elem = elem->next) { call = (LinphoneCall *)elem->data; - call->audio_muted = !enable; - if (call->audiostream) - linphone_core_mute_audio_stream(lc, call->audiostream, call->audio_muted); + linphone_call_set_audio_muted(call, !enable); + AudioStream *astream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeAudio)); + if (astream) + linphone_core_mute_audio_stream(lc, astream, linphone_call_get_audio_muted(call)); } } @@ -4485,7 +4381,7 @@ bool_t linphone_core_mic_enabled(LinphoneCore *lc) { ms_warning("%s(): No current call!", __FUNCTION__); return TRUE; } - return !call->audio_muted; + return !linphone_call_get_audio_muted(call); } bool_t linphone_core_is_rtp_muted(LinphoneCore *lc){ @@ -4495,7 +4391,7 @@ bool_t linphone_core_is_rtp_muted(LinphoneCore *lc){ return FALSE; } if( linphone_core_get_rtp_no_xmit_on_audio_mute(lc)){ - return call->audio_muted; + return linphone_call_get_audio_muted(call); } return FALSE; } @@ -4531,27 +4427,15 @@ const char * linphone_core_get_stun_server(const LinphoneCore *lc){ bool_t linphone_core_upnp_available(){ -#ifdef BUILD_UPNP - return TRUE; -#else return FALSE; -#endif //BUILD_UPNP } LinphoneUpnpState linphone_core_get_upnp_state(const LinphoneCore *lc){ -#ifdef BUILD_UPNP - return linphone_upnp_context_get_state(lc->upnp); -#else return LinphoneUpnpStateNotAvailable; -#endif //BUILD_UPNP } const char * linphone_core_get_upnp_external_ipaddress(const LinphoneCore *lc){ -#ifdef BUILD_UPNP - return linphone_upnp_context_get_external_ipaddress(lc->upnp); -#else return NULL; -#endif //BUILD_UPNP } void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr) { @@ -4620,11 +4504,7 @@ void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy linphone_nat_policy_enable_stun(nat_policy, TRUE); break; case LinphonePolicyUseUpnp: -#ifdef BUILD_UPNP - linphone_nat_policy_enable_upnp(nat_policy, TRUE); -#else - ms_warning("UPNP is not available, reset firewall policy to no firewall"); -#endif //BUILD_UPNP + ms_warning("UPNP is no longer supported, reset firewall policy to no firewall"); break; } @@ -4691,28 +4571,10 @@ void linphone_core_set_nat_policy(LinphoneCore *lc, LinphoneNatPolicy *policy) { linphone_nat_policy_save_to_config(lc->nat_policy); } -#ifdef BUILD_UPNP - linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0)); - if (linphone_nat_policy_upnp_enabled(policy)) { - if (lc->upnp == NULL) { - lc->upnp = linphone_upnp_context_new(lc); - } - sal_nat_helper_enable(lc->sal, FALSE); - sal_enable_auto_contacts(lc->sal, FALSE); - sal_use_rport(lc->sal, FALSE); - } else { - if (lc->upnp != NULL) { - linphone_upnp_context_destroy(lc->upnp); - lc->upnp = NULL; - } -#endif - sal_nat_helper_enable(lc->sal, lp_config_get_int(lc->config, "net", "enable_nat_helper", 1)); - sal_enable_auto_contacts(lc->sal, TRUE); - sal_use_rport(lc->sal, lp_config_get_int(lc->config, "sip", "use_rport", 1)); - if (lc->sip_conf.contact) update_primary_contact(lc); -#ifdef BUILD_UPNP - } -#endif + sal_nat_helper_enable(lc->sal, lp_config_get_int(lc->config, "net", "enable_nat_helper", 1)); + sal_enable_auto_contacts(lc->sal, TRUE); + sal_use_rport(lc->sal, lp_config_get_int(lc->config, "sip", "use_rport", 1)); + if (lc->sip_conf.contact) update_primary_contact(lc); } LinphoneNatPolicy * linphone_core_get_nat_policy(const LinphoneCore *lc) { @@ -5092,8 +4954,10 @@ void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val){ if (linphone_core_ready(lc)) { lp_config_set_int(lc->config,"video","self_view",linphone_core_self_view_enabled(lc)); } - if (call && call->videostream){ - video_stream_enable_self_view(call->videostream,val); + if (call) { + VideoStream *vstream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeVideo)); + if (vstream) + video_stream_enable_self_view(vstream,val); } if (linphone_core_ready(lc)){ lp_config_set_int(lc->config,"video","self_view",val); @@ -5139,8 +5003,10 @@ static VideoStream * get_active_video_stream(LinphoneCore *lc){ VideoStream *vs = NULL; LinphoneCall *call=linphone_core_get_current_call (lc); /* Select the video stream from the call in the first place */ - if (call && call->videostream) { - vs = call->videostream; + if (call) { + VideoStream *vstream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeVideo)); + if (vstream) + vs = vstream; } /* If not in call, select the video stream from the preview */ if (vs == NULL && lc->previewstream) { @@ -5231,8 +5097,11 @@ void * linphone_core_get_native_video_window_id(const LinphoneCore *lc){ #ifdef VIDEO_ENABLED /*case where it was not set but we want to get the one automatically created by mediastreamer2 (desktop versions only)*/ LinphoneCall *call=linphone_core_get_current_call (lc); - if (call && call->videostream) - return video_stream_get_native_window_id(call->videostream); + if (call) { + VideoStream *vstream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeVideo)); + if (vstream) + return video_stream_get_native_window_id(vstream); + } #endif } return 0; @@ -5256,11 +5125,12 @@ static void unset_video_window_id(LinphoneCore *lc, bool_t preview, void *id){ #ifdef VIDEO_ENABLED for(elem=lc->calls;elem!=NULL;elem=elem->next){ call=(LinphoneCall *) elem->data; - if (call->videostream){ + VideoStream *vstream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeVideo)); + if (vstream){ if (preview) - video_stream_set_native_preview_window_id(call->videostream,id); + video_stream_set_native_preview_window_id(vstream,id); else - video_stream_set_native_window_id(call->videostream,id); + video_stream_set_native_window_id(vstream,id); } } #endif @@ -5278,8 +5148,10 @@ void linphone_core_set_native_video_window_id(LinphoneCore *lc, void *id){ #ifdef VIDEO_ENABLED { LinphoneCall *call=linphone_core_get_current_call(lc); - if (call!=NULL && call->videostream){ - video_stream_set_native_window_id(call->videostream,id); + if (call) { + VideoStream *vstream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeVideo)); + if (vstream) + video_stream_set_native_window_id(vstream,id); } } #endif @@ -5293,8 +5165,11 @@ void * linphone_core_get_native_preview_window_id(const LinphoneCore *lc){ /*case where we want the id automatically created by mediastreamer2 (desktop versions only)*/ #ifdef VIDEO_ENABLED LinphoneCall *call=linphone_core_get_current_call(lc); - if (call && call->videostream) - return video_stream_get_native_preview_window_id(call->videostream); + if (call) { + VideoStream *vstream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeVideo)); + if (vstream) + return video_stream_get_native_preview_window_id(vstream); + } if (lc->previewstream) return video_preview_get_native_window_id(lc->previewstream); #endif @@ -5314,8 +5189,10 @@ void linphone_core_set_native_preview_window_id(LinphoneCore *lc, void *id){ #ifdef VIDEO_ENABLED { LinphoneCall *call=linphone_core_get_current_call(lc); - if (call!=NULL && call->videostream){ - video_stream_set_native_preview_window_id(call->videostream,id); + if (call) { + VideoStream *vstream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeVideo)); + if (vstream) + video_stream_set_native_preview_window_id(vstream,id); }else if (lc->previewstream){ video_preview_set_native_window_id(lc->previewstream,id); } @@ -5327,8 +5204,10 @@ void linphone_core_show_video(LinphoneCore *lc, bool_t show){ #ifdef VIDEO_ENABLED LinphoneCall *call=linphone_core_get_current_call(lc); ms_error("linphone_core_show_video %d", show); - if (call!=NULL && call->videostream){ - video_stream_show_video(call->videostream,show); + if (call) { + VideoStream *vstream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeVideo)); + if (vstream) + video_stream_show_video(vstream,show); } #endif } @@ -5347,8 +5226,10 @@ void linphone_core_set_device_rotation(LinphoneCore *lc, int rotation) { #ifdef VIDEO_ENABLED { LinphoneCall *call=linphone_core_get_current_call(lc); - if (call!=NULL && call->videostream){ - video_stream_set_device_rotation(call->videostream,rotation); + if (call) { + VideoStream *vstream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeVideo)); + if (vstream) + video_stream_set_device_rotation(vstream,rotation); } } #endif @@ -5357,8 +5238,10 @@ void linphone_core_set_device_rotation(LinphoneCore *lc, int rotation) { int linphone_core_get_camera_sensor_rotation(LinphoneCore *lc) { #ifdef VIDEO_ENABLED LinphoneCall *call = linphone_core_get_current_call(lc); - if ((call != NULL) && (call->videostream != NULL)) { - return video_stream_get_camera_sensor_rotation(call->videostream); + if (call) { + VideoStream *vstream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeVideo)); + if (vstream) + return video_stream_get_camera_sensor_rotation(vstream); } #endif return -1; @@ -5570,7 +5453,7 @@ void linphone_core_preview_ogl_render(const LinphoneCore *lc) { #ifdef VIDEO_ENABLED LinphoneCall *call = linphone_core_get_current_call(lc); - VideoStream *stream = call ? call->videostream : lc->previewstream; + VideoStream *stream = call ? reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeVideo)) : lc->previewstream; if (stream && stream->output2 && ms_filter_get_id(stream->output2) == MS_OGL_ID) { int mirroring = TRUE; @@ -5601,8 +5484,11 @@ void linphone_core_set_play_file(LinphoneCore *lc, const char *file){ } if (file!=NULL) { lc->play_file=ms_strdup(file); - if (call && call->audiostream && call->audiostream->ms.state==MSStreamStarted) - audio_stream_play(call->audiostream,file); + if (call) { + AudioStream *astream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeAudio)); + if (astream && astream->ms.state==MSStreamStarted) + audio_stream_play(astream,file); + } } } @@ -5618,8 +5504,11 @@ void linphone_core_set_record_file(LinphoneCore *lc, const char *file){ } if (file!=NULL) { lc->rec_file=ms_strdup(file); - if (call && call->audiostream) - audio_stream_record(call->audiostream,file); + if (call) { + AudioStream *astream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeAudio)); + if (astream) + audio_stream_record(astream,file); + } } } @@ -5633,7 +5522,7 @@ static MSFilter *get_audio_resource(LinphoneCore *lc, LinphoneAudioResourceType AudioStream *stream=NULL; RingStream *ringstream; if (call){ - stream=call->audiostream; + stream=reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeAudio)); }else if (linphone_core_is_in_conference(lc)){ stream=linphone_conference_get_audio_stream(lc->conf_ctx); } @@ -5808,10 +5697,11 @@ void linphone_core_set_rtp_transport_factories(LinphoneCore* lc, LinphoneRtpTran int linphone_core_get_current_call_stats(LinphoneCore *lc, rtp_stats_t *local, rtp_stats_t *remote){ LinphoneCall *call=linphone_core_get_current_call (lc); - if (call!=NULL){ - if (call->audiostream!=NULL){ + if (call){ + AudioStream *astream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeAudio)); + if (astream){ memset(remote,0,sizeof(*remote)); - audio_stream_get_local_rtp_stats (call->audiostream,local); + audio_stream_get_local_rtp_stats (astream,local); return 0; } } @@ -6098,13 +5988,6 @@ static void linphone_core_uninit(LinphoneCore *lc) sip_setup_unregister_all(); -#ifdef BUILD_UPNP - if(lc->upnp != NULL) { - linphone_upnp_context_destroy(lc->upnp); - lc->upnp = NULL; - } -#endif //BUILD_UPNP - if (lp_config_needs_commit(lc->config)) lp_config_sync(lc->config); lp_config_destroy(lc->config); lc->config = NULL; /* Mark the config as NULL to block further calls */ @@ -6196,18 +6079,6 @@ static void set_sip_network_reachable(LinphoneCore* lc,bool_t is_sip_reachable, /*mark all calls as broken, so that they can be either dropped immediately or restaured when network will be back*/ bctbx_list_for_each(lc->calls, (MSIterateFunc) linphone_call_set_broken); } -#ifdef BUILD_UPNP - if(lc->upnp == NULL) { - if(is_sip_reachable && linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) { - lc->upnp = linphone_upnp_context_new(lc); - } - } else { - if(!is_sip_reachable && linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) { - linphone_upnp_context_destroy(lc->upnp); - lc->upnp = NULL; - } - } -#endif } void linphone_core_repair_calls(LinphoneCore *lc){ @@ -6323,7 +6194,8 @@ void linphone_core_soundcard_hint_check( LinphoneCore* lc){ /* check if the remaining calls are paused */ while( the_calls ){ call = reinterpret_cast(the_calls->data); - if( call->state != LinphoneCallPausing && call->state != LinphoneCallPaused && call->state != LinphoneCallEnd && call->state != LinphoneCallError){ + if (linphone_call_get_state(call) != LinphoneCallPausing && linphone_call_get_state(call) != LinphoneCallPaused + && linphone_call_get_state(call) != LinphoneCallEnd && linphone_call_get_state(call) != LinphoneCallError){ dont_need_sound = FALSE; break; } @@ -6454,16 +6326,10 @@ LinphoneGlobalState linphone_core_get_global_state(const LinphoneCore *lc){ } -static LinphoneCallParams *_create_call_params(LinphoneCore *lc){ - LinphoneCallParams *p=linphone_call_params_new(); - linphone_core_init_default_params(lc, p); - return p; -} - LinphoneCallParams *linphone_core_create_call_params(LinphoneCore *lc, LinphoneCall *call){ - if (!call) return _create_call_params(lc); - if (call->params){ - return linphone_call_params_copy(call->params); + if (!call) return linphone_call_params_new(lc); + if (linphone_call_get_params(call)){ + return linphone_call_params_copy(linphone_call_get_params(call)); } ms_error("linphone_core_create_call_params(): call [%p] is not in a state where call params can be created or used.", call); return NULL; @@ -6474,11 +6340,6 @@ const char *linphone_error_to_string(LinphoneReason err){ } void linphone_core_enable_keep_alive(LinphoneCore* lc,bool_t enable) { -#ifdef BUILD_UPNP - if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp) { - enable = FALSE; - } -#endif //BUILD_UPNP if (enable > 0) { sal_use_tcp_tls_keepalive(lc->sal,lc->sip_conf.tcp_tls_keepalive); sal_set_keepalive_period(lc->sal,lc->sip_conf.keepalive_period); @@ -6497,7 +6358,7 @@ void linphone_core_start_dtmf_stream(LinphoneCore* lc) { } void linphone_core_stop_ringing(LinphoneCore* lc) { - LinphoneCall *call=linphone_core_get_current_call(lc); + //LinphoneCall *call=linphone_core_get_current_call(lc); if (linphone_ringtoneplayer_is_started(lc->ringtoneplayer)) { linphone_ringtoneplayer_stop(lc->ringtoneplayer); } @@ -6507,10 +6368,12 @@ void linphone_core_stop_ringing(LinphoneCore* lc) { lc->dmfs_playing_start_time=0; lc->ringstream_autorelease=TRUE; } +#if 0 if (call && call->ringing_beep){ linphone_core_stop_dtmf(lc); call->ringing_beep=FALSE; } +#endif } void linphone_core_stop_dtmf_stream(LinphoneCore* lc) { @@ -6688,7 +6551,7 @@ bool_t linphone_core_sound_resources_locked(LinphoneCore *lc){ return TRUE; } - switch (c->state) { + switch (linphone_call_get_state(c)) { case LinphoneCallOutgoingInit: case LinphoneCallOutgoingProgress: case LinphoneCallOutgoingRinging: @@ -6808,26 +6671,7 @@ void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m) { } void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params) { - linphone_call_params_enable_audio(params, TRUE); - linphone_call_params_enable_video(params, linphone_core_video_enabled(lc) && lc->video_policy.automatically_initiate); - if (!linphone_core_video_enabled(lc) && lc->video_policy.automatically_initiate){ - ms_error("LinphoneCore has video disabled for both capture and display, but video policy is to start the call with video. " - "This is a possible mis-use of the API. In this case, video is disabled in default LinphoneCallParams"); - } - linphone_call_params_set_media_encryption(params, linphone_core_get_media_encryption(lc)); - linphone_call_params_set_in_conference(params, FALSE); - linphone_call_params_enable_realtime_text(params, linphone_core_realtime_text_enabled(lc)); - linphone_call_params_set_privacy(params, LinphonePrivacyDefault); - linphone_call_params_enable_avpf(params, linphone_core_get_avpf_mode(lc)); - linphone_call_params_enable_implicit_rtcp_fb(params, lp_config_get_int(lc->config,"rtp","rtcp_fb_implicit_rtcp_fb",TRUE)); - linphone_call_params_set_avpf_rr_interval(params, linphone_core_get_avpf_rr_interval(lc)); - linphone_call_params_set_audio_direction(params, LinphoneMediaDirectionSendRecv); - linphone_call_params_set_video_direction(params, LinphoneMediaDirectionSendRecv); - linphone_call_params_enable_early_media_sending(params, lp_config_get_int(lc->config,"misc","real_early_media",FALSE)); - linphone_call_params_enable_audio_multicast(params, linphone_core_audio_multicast_enabled(lc)); - linphone_call_params_enable_video_multicast(params, linphone_core_video_multicast_enabled(lc)); - linphone_call_params_set_update_call_when_ice_completed(params, lp_config_get_int(lc->config, "sip", "update_call_when_ice_completed", TRUE)); - linphone_call_params_enable_mandatory_media_encryption(params, linphone_core_is_media_encryption_mandatory(lc)); + linphone_call_params_get_cpp_obj(params)->initDefault(lc); } void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) { @@ -7063,6 +6907,10 @@ bool_t linphone_core_realtime_text_enabled(LinphoneCore *lc) { return lc->text_conf.enabled; } +void linphone_core_enable_realtime_text(LinphoneCore *lc, bool_t value) { + lc->text_conf.enabled = value; +} + void linphone_core_set_http_proxy_host(LinphoneCore *lc, const char *host) { lp_config_set_string(lc->config,"sip","http_proxy_host",host); if (lc->sal) { diff --git a/coreapi/misc.c b/coreapi/misc.c index 709e3e83f..2c6836e86 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -56,88 +56,19 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define pclose _pclose #endif - -#define UDP_HDR_SZ 8 -#define RTP_HDR_SZ 12 -#define IP4_HDR_SZ 20 /*20 is the minimum, but there may be some options*/ - -static void clear_ice_check_list(LinphoneCall *call, IceCheckList *removed); - - -/* - *((codec-birate*ptime/8) + RTP header + UDP header + IP header)*8/ptime; - *ptime=1/npacket - */ - -static double get_audio_payload_bandwidth_from_codec_bitrate(const PayloadType *pt){ - double npacket=50; - double packet_size; - int bitrate; - - if (strcmp(payload_type_get_mime(&payload_type_aaceld_44k), payload_type_get_mime(pt))==0) { - /*special case of aac 44K because ptime= 10ms*/ - npacket=100; - }else if (strcmp(payload_type_get_mime(&payload_type_ilbc), payload_type_get_mime(pt))==0) { - npacket=1000/30.0; - } - - bitrate=pt->normal_bitrate; - packet_size= (((double)bitrate)/(npacket*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ; - return packet_size*8.0*npacket; -} - -typedef struct vbr_codec_bitrate{ - int max_avail_bitrate; - int min_rate; - int recomended_bitrate; -}vbr_codec_bitrate_t; - -static vbr_codec_bitrate_t defauls_vbr[]={ - //{ 100, 44100, 100 }, - { 64, 44100, 50 }, - { 64, 16000, 40 }, - { 32, 16000, 32 }, - { 32, 8000, 32 }, - { 0 , 8000, 24 }, - { 0 , 0, 0 } -}; - -static int lookup_vbr_typical_bitrate(int maxbw, int clock_rate){ - vbr_codec_bitrate_t *it; - if (maxbw<=0) maxbw=defauls_vbr[0].max_avail_bitrate; - for(it=defauls_vbr;it->min_rate!=0;it++){ - if (maxbw>=it->max_avail_bitrate && clock_rate>=it->min_rate) - return it->recomended_bitrate; - } - ms_error("lookup_vbr_typical_bitrate(): should not happen."); - return 32; -} - -int get_audio_payload_bandwidth(const LinphoneCore *lc, const PayloadType *pt, int maxbw) { - if (payload_type_is_vbr(pt)) { - if (pt->flags & PAYLOAD_TYPE_BITRATE_OVERRIDE){ - ms_debug("PayloadType %s/%i has bitrate override",pt->mime_type,pt->clock_rate); - return pt->normal_bitrate/1000; - } - return lookup_vbr_typical_bitrate(maxbw,pt->clock_rate); - }else return (int)ceil(get_audio_payload_bandwidth_from_codec_bitrate(pt)/1000.0);/*rounding codec bandwidth should be avoid, specially for AMR*/ -} - -void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt, int maxbw){ - call->audio_bw=get_audio_payload_bandwidth(call->core,pt,maxbw); - ms_message("Audio bandwidth for this call is %i",call->audio_bw); -} +#include "nat/stun-client.h" +#include "utils/payload-type-handler.h" void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc){ const bctbx_list_t *elem; - int maxbw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc), + int maxbw=LinphonePrivate::PayloadTypeHandler::getMinBandwidth(linphone_core_get_download_bandwidth(lc), linphone_core_get_upload_bandwidth(lc)); int max_codec_bitrate=0; for(elem=linphone_core_get_audio_codecs(lc);elem!=NULL;elem=elem->next){ PayloadType *pt=(PayloadType*)elem->data; if (payload_type_enabled(pt)){ - int pt_bitrate=get_audio_payload_bandwidth(lc,pt,maxbw); + int pt_bitrate=LinphonePrivate::PayloadTypeHandler::getAudioPayloadTypeBandwidth(pt,maxbw); if (max_codec_bitrate==0) { max_codec_bitrate=pt_bitrate; }else if (max_codec_bitratetype){ case PAYLOAD_AUDIO_CONTINUOUS: case PAYLOAD_AUDIO_PACKETIZED: - codec_band=get_audio_payload_bandwidth(lc,pt,bandwidth_limit); - ret=bandwidth_is_greater(bandwidth_limit,(int)codec_band); + codec_band=LinphonePrivate::PayloadTypeHandler::getAudioPayloadTypeBandwidth(pt,bandwidth_limit); + ret=LinphonePrivate::PayloadTypeHandler::bandwidthIsGreater(bandwidth_limit,(int)codec_band); /*ms_message("Payload %s: codec_bandwidth=%g, bandwidth_limit=%i",pt->mime_type,codec_band,bandwidth_limit);*/ break; case PAYLOAD_VIDEO: @@ -196,59 +127,6 @@ bool_t lp_spawn_command_line_sync(const char *command, char **result,int *comman return FALSE; } -static ortp_socket_t create_socket(int local_port){ - struct sockaddr_in laddr; - ortp_socket_t sock; - int optval; - sock=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP); - if (sock<0) { - ms_error("Fail to create socket"); - return -1; - } - memset (&laddr,0,sizeof(laddr)); - laddr.sin_family=AF_INET; - laddr.sin_addr.s_addr=INADDR_ANY; - laddr.sin_port=htons(local_port); - if (bind(sock,(struct sockaddr*)&laddr,sizeof(laddr))<0){ - ms_error("Bind socket to 0.0.0.0:%i failed: %s",local_port,getSocketError()); - close_socket(sock); - return -1; - } - optval=1; - if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, - (SOCKET_OPTION_VALUE)&optval, sizeof (optval))<0){ - ms_warning("Fail to set SO_REUSEADDR"); - } - set_non_blocking_socket(sock); - return sock; -} - -static int send_stun_request(int sock, const struct sockaddr *server, socklen_t addrlen, int id, bool_t change_addr){ - char *buf = NULL; - size_t len; - int err = 0; - MSStunMessage *req = ms_stun_binding_request_create(); - UInt96 tr_id = ms_stun_message_get_tr_id(req); - tr_id.octet[0] = id; - ms_stun_message_set_tr_id(req, tr_id); - ms_stun_message_enable_change_ip(req, change_addr); - ms_stun_message_enable_change_port(req, change_addr); - len = ms_stun_message_encode(req, &buf); - if (len <= 0) { - ms_error("Fail to encode stun message."); - err = -1; - } else { - err = bctbx_sendto(sock, buf, len, 0, server, addrlen); - if (err < 0) { - ms_error("sendto failed: %s",strerror(errno)); - err = -1; - } - } - if (buf != NULL) ms_free(buf); - ms_free(req); - return err; -} - int linphone_parse_host_port(const char *input, char *host, size_t hostlen, int *port){ char tmphost[NI_MAXHOST]={0}; @@ -294,156 +172,19 @@ int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, sock return 0; } -static int recv_stun_response(ortp_socket_t sock, char *ipaddr, int *port, int *id) { - char buf[MS_STUN_MAX_MESSAGE_SIZE]; - int len = MS_STUN_MAX_MESSAGE_SIZE; - MSStunMessage *resp; - - len = recv(sock, buf, len, 0); - if (len > 0) { - struct in_addr ia; - resp = ms_stun_message_create_from_buffer_parsing((uint8_t *)buf, (ssize_t)len); - if (resp != NULL) { - const MSStunAddress *stun_addr; - UInt96 tr_id = ms_stun_message_get_tr_id(resp); - *id = tr_id.octet[0]; - stun_addr = ms_stun_message_get_xor_mapped_address(resp); - if (stun_addr != NULL) { - *port = stun_addr->ip.v4.port; - ia.s_addr = htonl(stun_addr->ip.v4.addr); - } else { - stun_addr = ms_stun_message_get_mapped_address(resp); - if (stun_addr != NULL) { - *port = stun_addr->ip.v4.port; - ia.s_addr = htonl(stun_addr->ip.v4.addr); - } else len = -1; - } - if (len > 0) strncpy(ipaddr, inet_ntoa(ia), LINPHONE_IPADDR_SIZE); - } - } - return len; -} - /* this functions runs a simple stun test and return the number of milliseconds to complete the tests, or -1 if the test were failed.*/ -int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ - const char *server=linphone_core_get_stun_server(lc); - StunCandidate *ac=&call->ac; - StunCandidate *vc=&call->vc; - StunCandidate *tc=&call->tc; - - if (lc->sip_conf.ipv6_enabled){ - ms_warning("stun support is not implemented for ipv6"); - return -1; - } - if (call->media_ports[call->main_audio_stream_index].rtp_port==-1){ - ms_warning("Stun-only support not available for system random port"); - return -1; - } - if (server!=NULL){ - const struct addrinfo *ai=linphone_core_get_stun_server_addrinfo(lc); - ortp_socket_t sock1=-1, sock2=-1, sock3=-1; - int loops=0; - bool_t video_enabled=linphone_core_video_enabled(lc); - bool_t got_audio,got_video,got_text; - bool_t cone_audio=FALSE,cone_video=FALSE,cone_text=FALSE; - struct timeval init,cur; - double elapsed; - int ret=0; - - if (ai==NULL){ - ms_error("Could not obtain stun server addrinfo."); - return -1; - } - linphone_core_notify_display_status(lc,_("Stun lookup in progress...")); - - /*create the two audio and video RTP sockets, and send STUN message to our stun server */ - sock1=create_socket(call->media_ports[call->main_audio_stream_index].rtp_port); - if (sock1==-1) return -1; - if (video_enabled){ - sock2=create_socket(call->media_ports[call->main_video_stream_index].rtp_port); - if (sock2==-1) return -1; - } - sock3=create_socket(call->media_ports[call->main_text_stream_index].rtp_port); - if (sock3==-1) return -1; - - got_audio=FALSE; - got_video=FALSE; - got_text=FALSE; - ortp_gettimeofday(&init,NULL); - do{ - - int id; - if (loops%20==0){ - ms_message("Sending stun requests..."); - send_stun_request((int)sock1,ai->ai_addr,(socklen_t)ai->ai_addrlen,11,TRUE); - send_stun_request((int)sock1,ai->ai_addr,(socklen_t)ai->ai_addrlen,1,FALSE); - if (sock2!=-1){ - send_stun_request((int)sock2,ai->ai_addr,(socklen_t)ai->ai_addrlen,22,TRUE); - send_stun_request((int)sock2,ai->ai_addr,(socklen_t)ai->ai_addrlen,2,FALSE); - } - if (sock3!=-1){ - send_stun_request((int)sock3,ai->ai_addr,(socklen_t)ai->ai_addrlen,33,TRUE); - send_stun_request((int)sock3,ai->ai_addr,(socklen_t)ai->ai_addrlen,3,FALSE); - } - } - ms_usleep(10000); - - if (recv_stun_response(sock1, ac->addr, &ac->port, &id) > 0) { - ms_message("STUN test result: local audio port maps to %s:%i", ac->addr, ac->port); - if (id==11) cone_audio=TRUE; - got_audio=TRUE; - } - if (recv_stun_response(sock2, vc->addr, &vc->port, &id) > 0) { - ms_message("STUN test result: local video port maps to %s:%i", vc->addr, vc->port); - if (id==22) cone_video=TRUE; - got_video=TRUE; - } - if (recv_stun_response(sock3, tc->addr, &tc->port, &id)>0) { - ms_message("STUN test result: local text port maps to %s:%i", tc->addr, tc->port); - if (id==33) cone_text=TRUE; - got_text=TRUE; - } - ortp_gettimeofday(&cur,NULL); - elapsed=((cur.tv_sec-init.tv_sec)*1000.0) + ((cur.tv_usec-init.tv_usec)/1000.0); - if (elapsed>2000) { - ms_message("Stun responses timeout, going ahead."); - ret=-1; - break; - } - loops++; - }while(!(got_audio && (got_video||sock2==-1) && (got_text||sock3==-1) ) ); - if (ret==0) ret=(int)elapsed; - if (!got_audio){ - ms_error("No stun server response for audio port."); - }else{ - if (!cone_audio) { - ms_message("NAT is symmetric for audio port"); - } - } - if (sock2!=-1){ - if (!got_video){ - ms_error("No stun server response for video port."); - }else{ - if (!cone_video) { - ms_message("NAT is symmetric for video port."); - } - } - } - if (sock3!=-1){ - if (!got_text){ - ms_error("No stun server response for text port."); - }else{ - if (!cone_text) { - ms_message("NAT is symmetric for text port."); - } - } - } - close_socket(sock1); - if (sock2!=-1) close_socket(sock2); - if (sock3!=-1) close_socket(sock3); - return ret; - } - return -1; +int linphone_run_stun_tests(LinphoneCore *lc, int audioPort, int videoPort, int textPort, + char *audioCandidateAddr, int *audioCandidatePort, char *videoCandidateAddr, int *videoCandidatePort, char *textCandidateAddr, int *textCandidatePort) { + LinphonePrivate::StunClient *client = new LinphonePrivate::StunClient(lc); + int ret = client->run(audioPort, videoPort, textPort); + strncpy(audioCandidateAddr, client->getAudioCandidate().address.c_str(), LINPHONE_IPADDR_SIZE); + *audioCandidatePort = client->getAudioCandidate().port; + strncpy(videoCandidateAddr, client->getVideoCandidate().address.c_str(), LINPHONE_IPADDR_SIZE); + *videoCandidatePort = client->getVideoCandidate().port; + strncpy(textCandidateAddr, client->getTextCandidate().address.c_str(), LINPHONE_IPADDR_SIZE); + *textCandidatePort = client->getTextCandidate().port; + delete client; + return ret; } int linphone_core_get_edge_bw(LinphoneCore *lc){ @@ -456,27 +197,6 @@ int linphone_core_get_edge_ptime(LinphoneCore *lc){ return edge_ptime; } -void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params){ - int threshold; - if (ping_time_ms>0 && lp_config_get_int(lc->config,"net","activate_edge_workarounds",0)==1){ - ms_message("Stun server ping time is %i ms",ping_time_ms); - threshold=lp_config_get_int(lc->config,"net","edge_ping_time",500); - - if (ping_time_ms>threshold){ - /* we might be in a 2G network*/ - linphone_call_params_enable_low_bandwidth(params, TRUE); - }/*else use default settings */ - } - if (linphone_call_params_low_bandwidth_enabled(params)){ - linphone_call_params_set_up_bandwidth(params, linphone_core_get_edge_bw(lc)); - linphone_call_params_set_down_bandwidth(params, linphone_core_get_edge_bw(lc)); - linphone_call_params_set_up_ptime(params, linphone_core_get_edge_ptime(lc)); - linphone_call_params_set_down_ptime(params, linphone_core_get_edge_ptime(lc)); - linphone_call_params_enable_video(params, FALSE); - } -} - - void linphone_core_resolve_stun_server(LinphoneCore *lc){ if (lc->nat_policy != NULL) { linphone_nat_policy_resolve_stun_server(lc->nat_policy); @@ -502,180 +222,6 @@ void linphone_core_enable_short_turn_refresh(LinphoneCore *lc, bool_t enable) { lc->short_turn_refresh = enable; } -static void stun_auth_requested_cb(LinphoneCall *call, const char *realm, const char *nonce, const char **username, const char **password, const char **ha1) { - LinphoneProxyConfig *proxy = NULL; - const LinphoneNatPolicy *nat_policy = NULL; - const LinphoneAddress *addr = NULL; - const LinphoneAuthInfo *auth_info = NULL; - LinphoneCore *lc = call->core; - const char *user = NULL; - - // Get the username from the nat policy or the proxy config - if (call->dest_proxy != NULL) proxy = call->dest_proxy; - else proxy = linphone_core_get_default_proxy_config(call->core); - if (proxy == NULL) return; - nat_policy = linphone_proxy_config_get_nat_policy(proxy); - if (nat_policy != NULL) { - user = linphone_nat_policy_get_stun_server_username(nat_policy); - } else { - nat_policy = call->nat_policy; - if (nat_policy != NULL) { - user = linphone_nat_policy_get_stun_server_username(nat_policy); - } - } - if (user == NULL) { - /* If the username has not been found in the nat_policy, take the username from the currently used proxy config. */ - addr = linphone_proxy_config_get_identity_address(proxy); - if (addr == NULL) return; - user = linphone_address_get_username(addr); - } - if (user == NULL) return; - - auth_info = linphone_core_find_auth_info(lc, realm, user, NULL); - if (auth_info != NULL) { - const char *hash = linphone_auth_info_get_ha1(auth_info); - if (hash != NULL) { - *ha1 = hash; - } else { - *password = linphone_auth_info_get_passwd(auth_info); - } - *username = user; - } else { - ms_warning("No auth info found for STUN auth request"); - } -} - -static void linphone_core_add_local_ice_candidates(LinphoneCall *call, int family, const char *addr, IceCheckList *audio_cl, IceCheckList *video_cl, IceCheckList *text_cl) { - if ((ice_check_list_state(audio_cl) != ICL_Completed) && (ice_check_list_candidates_gathered(audio_cl) == FALSE)) { - ice_add_local_candidate(audio_cl, "host", family, addr, call->media_ports[call->main_audio_stream_index].rtp_port, 1, NULL); - ice_add_local_candidate(audio_cl, "host", family, addr, call->media_ports[call->main_audio_stream_index].rtcp_port, 2, NULL); - call->audio_stats->ice_state = LinphoneIceStateInProgress; - } - if (linphone_core_video_enabled(call->core) && (video_cl != NULL) - && (ice_check_list_state(video_cl) != ICL_Completed) && (ice_check_list_candidates_gathered(video_cl) == FALSE)) { - ice_add_local_candidate(video_cl, "host", family, addr, call->media_ports[call->main_video_stream_index].rtp_port, 1, NULL); - ice_add_local_candidate(video_cl, "host", family, addr, call->media_ports[call->main_video_stream_index].rtcp_port, 2, NULL); - call->video_stats->ice_state = LinphoneIceStateInProgress; - } - if (linphone_call_params_realtime_text_enabled(call->params) && (text_cl != NULL) - && (ice_check_list_state(text_cl) != ICL_Completed) && (ice_check_list_candidates_gathered(text_cl) == FALSE)) { - ice_add_local_candidate(text_cl, "host", family, addr, call->media_ports[call->main_text_stream_index].rtp_port, 1, NULL); - ice_add_local_candidate(text_cl, "host", family, addr, call->media_ports[call->main_text_stream_index].rtcp_port, 2, NULL); - call->text_stats->ice_state = LinphoneIceStateInProgress; - } -} - -static const struct addrinfo * find_nat64_addrinfo(const struct addrinfo *ai) { - while (ai != NULL) { - if (ai->ai_family == AF_INET6) { - struct sockaddr_storage ss; - socklen_t sslen = sizeof(ss); - bctbx_sockaddr_remove_nat64_mapping(ai->ai_addr, (struct sockaddr *)&ss, &sslen); - if (ss.ss_family == AF_INET) break; - } - ai = ai->ai_next; - } - return ai; -} - -static const struct addrinfo * find_ipv4_addrinfo(const struct addrinfo *ai) { - while (ai != NULL) { - if (ai->ai_family == AF_INET) break; - if (ai->ai_family == AF_INET6 && ai->ai_flags & AI_V4MAPPED) break; - ai = ai->ai_next; - } - return ai; -} - -static const struct addrinfo * find_ipv6_addrinfo(const struct addrinfo *ai) { - while (ai != NULL) { - if (ai->ai_family == AF_INET6) break; - ai = ai->ai_next; - } - return ai; -} - -/** - * Choose the preferred IP address to use to contact the STUN server from the list of IP addresses - * the DNS resolution returned. If a NAT64 address is present, use it, otherwise if an IPv4 address - * is present, use it, otherwise use an IPv6 address if it is present. - */ -static const struct addrinfo * get_preferred_stun_server_addrinfo(const struct addrinfo *ai) { - const struct addrinfo *preferred_ai = find_nat64_addrinfo(ai); - if (!preferred_ai) preferred_ai = find_ipv4_addrinfo(ai); - if (!preferred_ai) preferred_ai = find_ipv6_addrinfo(ai); - return preferred_ai; -} - -/* Return values: - * 1 : STUN gathering is started - * 0 : no STUN gathering is started, but it's ok to proceed with ICE anyway (with local candidates only or because STUN gathering was already done before) - * -1: no gathering started and something went wrong with local candidates. There is no way to start the ICE session. - */ -int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call){ - char local_addr[64]; - const struct addrinfo *ai = NULL; - IceCheckList *audio_cl; - IceCheckList *video_cl; - IceCheckList *text_cl; - LinphoneNatPolicy *nat_policy = call->nat_policy; - - if (call->ice_session == NULL) return -1; - audio_cl = ice_session_check_list(call->ice_session, call->main_audio_stream_index); - video_cl = ice_session_check_list(call->ice_session, call->main_video_stream_index); - text_cl = ice_session_check_list(call->ice_session, call->main_text_stream_index); - if ((audio_cl == NULL) && (video_cl == NULL) && (text_cl == NULL)) return -1; - - if ((nat_policy != NULL) && linphone_nat_policy_stun_server_activated(nat_policy)) { - ai=linphone_nat_policy_get_stun_server_addrinfo(nat_policy); - if (ai==NULL){ - ms_warning("Fail to resolve STUN server for ICE gathering, continuing without stun."); - } else { - ai = get_preferred_stun_server_addrinfo(ai); - } - }else{ - ms_warning("Ice is used without stun server."); - } - linphone_core_notify_display_status(lc, _("ICE local candidates gathering in progress...")); - - ice_session_enable_forced_relay(call->ice_session, lc->forced_ice_relay); - ice_session_enable_short_turn_refresh(call->ice_session, lc->short_turn_refresh); - - /* Gather local host candidates. */ - if (call->af == AF_INET6) { - if (linphone_core_get_local_ip_for(AF_INET6, NULL, local_addr) < 0) { - ms_error("Fail to get local IPv6"); - return -1; - } else { - linphone_core_add_local_ice_candidates(call, AF_INET6, local_addr, audio_cl, video_cl, text_cl); - } - } - if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) { - if (call->af != AF_INET6) { - ms_error("Fail to get local IPv4"); - return -1; - } - } else { - linphone_core_add_local_ice_candidates(call, AF_INET, local_addr, audio_cl, video_cl, text_cl); - } - if ((ai != NULL) && (nat_policy != NULL) && linphone_nat_policy_stun_server_activated(nat_policy)) { - bool_t gathering_in_progress; - const char *server = linphone_nat_policy_get_stun_server(nat_policy); - ms_message("ICE: gathering candidate from [%s] using %s", server, linphone_nat_policy_turn_enabled(nat_policy) ? "TURN" : "STUN"); - /* Gather local srflx candidates. */ - ice_session_enable_turn(call->ice_session, linphone_nat_policy_turn_enabled(nat_policy)); - ice_session_set_stun_auth_requested_cb(call->ice_session, (MSStunAuthRequestedCb)stun_auth_requested_cb, call); - gathering_in_progress = ice_session_gather_candidates(call->ice_session, ai->ai_addr, (socklen_t)ai->ai_addrlen); - return (gathering_in_progress == FALSE) ? 0 : 1; - } else { - ms_message("ICE: bypass candidates gathering"); - ice_session_compute_candidates_foundations(call->ice_session); - ice_session_eliminate_redundant_candidates(call->ice_session); - ice_session_choose_default_candidates(call->ice_session); - } - return 0; -} - const char *linphone_ice_state_to_string(LinphoneIceState state){ switch(state){ case LinphoneIceStateFailed: @@ -695,236 +241,6 @@ const char *linphone_ice_state_to_string(LinphoneIceState state){ } void linphone_call_update_ice_state_in_call_stats(LinphoneCall *call) { - IceCheckList *audio_check_list; - IceCheckList *video_check_list; - IceCheckList *text_check_list; - IceSessionState session_state; - - if (call->ice_session == NULL) return; - audio_check_list = ice_session_check_list(call->ice_session, call->main_audio_stream_index); - video_check_list = ice_session_check_list(call->ice_session, call->main_video_stream_index); - text_check_list = ice_session_check_list(call->ice_session, call->main_text_stream_index); - if ((audio_check_list == NULL) && (video_check_list == NULL) && (text_check_list == NULL)) return; - - session_state = ice_session_state(call->ice_session); - if ((session_state == IS_Completed) || ((session_state == IS_Failed) && (ice_session_has_completed_check_list(call->ice_session) == TRUE))) { - if (linphone_call_params_audio_enabled(call->params) && (audio_check_list != NULL)) { - if (ice_check_list_state(audio_check_list) == ICL_Completed) { - switch (ice_check_list_selected_valid_candidate_type(audio_check_list)) { - case ICT_HostCandidate: - call->audio_stats->ice_state = LinphoneIceStateHostConnection; - break; - case ICT_ServerReflexiveCandidate: - case ICT_PeerReflexiveCandidate: - call->audio_stats->ice_state = LinphoneIceStateReflexiveConnection; - break; - case ICT_RelayedCandidate: - call->audio_stats->ice_state = LinphoneIceStateRelayConnection; - break; - case ICT_CandidateInvalid: - case ICT_CandidateTypeMax: - /*shall not happen*/ - break; - } - } else { - call->audio_stats->ice_state = LinphoneIceStateFailed; - } - }else call->audio_stats->ice_state = LinphoneIceStateNotActivated; - - if (linphone_call_params_video_enabled(call->params) && (video_check_list != NULL)) { - if (ice_check_list_state(video_check_list) == ICL_Completed) { - switch (ice_check_list_selected_valid_candidate_type(video_check_list)) { - case ICT_HostCandidate: - call->video_stats->ice_state = LinphoneIceStateHostConnection; - break; - case ICT_ServerReflexiveCandidate: - case ICT_PeerReflexiveCandidate: - call->video_stats->ice_state = LinphoneIceStateReflexiveConnection; - break; - case ICT_RelayedCandidate: - call->video_stats->ice_state = LinphoneIceStateRelayConnection; - break; - case ICT_CandidateInvalid: - case ICT_CandidateTypeMax: - /*shall not happen*/ - break; - } - } else { - call->video_stats->ice_state = LinphoneIceStateFailed; - } - }else call->video_stats->ice_state = LinphoneIceStateNotActivated; - - if (linphone_call_params_realtime_text_enabled(call->params) && (text_check_list != NULL)) { - if (ice_check_list_state(text_check_list) == ICL_Completed) { - switch (ice_check_list_selected_valid_candidate_type(text_check_list)) { - case ICT_HostCandidate: - call->text_stats->ice_state = LinphoneIceStateHostConnection; - break; - case ICT_ServerReflexiveCandidate: - case ICT_PeerReflexiveCandidate: - call->text_stats->ice_state = LinphoneIceStateReflexiveConnection; - break; - case ICT_RelayedCandidate: - call->text_stats->ice_state = LinphoneIceStateRelayConnection; - break; - case ICT_CandidateInvalid: - case ICT_CandidateTypeMax: - /*shall not happen*/ - break; - } - } else { - call->text_stats->ice_state = LinphoneIceStateFailed; - } - }else call->text_stats->ice_state = LinphoneIceStateNotActivated; - } else if (session_state == IS_Running) { - call->audio_stats->ice_state = LinphoneIceStateInProgress; - if (linphone_call_params_video_enabled(call->params) && (video_check_list != NULL)) { - call->video_stats->ice_state = LinphoneIceStateInProgress; - } - if (linphone_call_params_realtime_text_enabled(call->params) && (text_check_list != NULL)) { - call->text_stats->ice_state = LinphoneIceStateInProgress; - } - } else { - call->audio_stats->ice_state = LinphoneIceStateFailed; - if (linphone_call_params_video_enabled(call->params) && (video_check_list != NULL)) { - call->video_stats->ice_state = LinphoneIceStateFailed; - } - if (linphone_call_params_realtime_text_enabled(call->params) && (text_check_list != NULL)) { - call->text_stats->ice_state = LinphoneIceStateFailed; - } - } - ms_message("Call [%p] New ICE state: audio: [%s] video: [%s] text: [%s]", call, - linphone_ice_state_to_string(call->audio_stats->ice_state), linphone_ice_state_to_string(call->video_stats->ice_state), linphone_ice_state_to_string(call->text_stats->ice_state)); -} - -void linphone_call_stop_ice_for_inactive_streams(LinphoneCall *call, SalMediaDescription *desc) { - int i; - IceSession *session = call->ice_session; - - if (session == NULL) return; - if (ice_session_state(session) == IS_Completed) return; - - for (i = 0; i < desc->nb_streams; i++) { - IceCheckList *cl = ice_session_check_list(session, i); - if (!sal_stream_description_active(&desc->streams[i]) && cl) { - ice_session_remove_check_list(session, cl); - clear_ice_check_list(call, cl); - } - } - - linphone_call_update_ice_state_in_call_stats(call); -} - -void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session, bool_t use_nortpproxy) { - IceCandidate *rtp_candidate = NULL; - IceCandidate *rtcp_candidate = NULL; - IceSessionState session_state = ice_session_state(session); - int nb_candidates; - int i; - int j; - bool_t result = FALSE; - - if (session_state == IS_Completed) { - IceCheckList *first_cl = NULL; - for (i = 0; i < desc->nb_streams; i++) { - IceCheckList *cl = ice_session_check_list(session, i); - if (cl != NULL) { - first_cl = cl; - break; - } - } - if (first_cl != NULL) { - result = ice_check_list_selected_valid_local_candidate(first_cl, &rtp_candidate, NULL); - } - if (result == TRUE) { - strncpy(desc->addr, rtp_candidate->taddr.ip, sizeof(desc->addr)); - } else { - ms_warning("If ICE has completed successfully, rtp_candidate should be set!"); - } - } - - strncpy(desc->ice_pwd, ice_session_local_pwd(session), sizeof(desc->ice_pwd)); - strncpy(desc->ice_ufrag, ice_session_local_ufrag(session), sizeof(desc->ice_ufrag)); - for (i = 0; i < desc->nb_streams; i++) { - SalStreamDescription *stream = &desc->streams[i]; - IceCheckList *cl = ice_session_check_list(session, i); - nb_candidates = 0; - rtp_candidate = rtcp_candidate = NULL; - if (!sal_stream_description_active(stream) || (cl == NULL)) continue; - if (ice_check_list_state(cl) == ICL_Completed) { - if (use_nortpproxy) stream->set_nortpproxy = TRUE; - result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_candidate, &rtcp_candidate); - } else { - stream->set_nortpproxy = FALSE; - result = ice_check_list_default_local_candidate(ice_session_check_list(session, i), &rtp_candidate, &rtcp_candidate); - } - if (result == TRUE) { - strncpy(stream->rtp_addr, rtp_candidate->taddr.ip, sizeof(stream->rtp_addr)); - strncpy(stream->rtcp_addr, rtcp_candidate->taddr.ip, sizeof(stream->rtcp_addr)); - stream->rtp_port = rtp_candidate->taddr.port; - stream->rtcp_port = rtcp_candidate->taddr.port; - } else { - memset(stream->rtp_addr, 0, sizeof(stream->rtp_addr)); - memset(stream->rtcp_addr, 0, sizeof(stream->rtcp_addr)); - } - if ((strlen(ice_check_list_local_pwd(cl)) != strlen(desc->ice_pwd)) || (strcmp(ice_check_list_local_pwd(cl), desc->ice_pwd))) - strncpy(stream->ice_pwd, ice_check_list_local_pwd(cl), sizeof(stream->ice_pwd)); - else - memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd)); - if ((strlen(ice_check_list_local_ufrag(cl)) != strlen(desc->ice_ufrag)) || (strcmp(ice_check_list_local_ufrag(cl), desc->ice_ufrag))) - strncpy(stream->ice_ufrag, ice_check_list_local_ufrag(cl), sizeof(stream->ice_ufrag)); - else - memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd)); - stream->ice_mismatch = ice_check_list_is_mismatch(cl); - if ((ice_check_list_state(cl) == ICL_Running) || (ice_check_list_state(cl) == ICL_Completed)) { - memset(stream->ice_candidates, 0, sizeof(stream->ice_candidates)); - for (j = 0; j < MIN((int)bctbx_list_size(cl->local_candidates), SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES); j++) { - SalIceCandidate *sal_candidate = &stream->ice_candidates[nb_candidates]; - IceCandidate *ice_candidate = reinterpret_cast(bctbx_list_nth_data(cl->local_candidates, j)); - const char *default_addr = NULL; - int default_port = 0; - if (ice_candidate->componentID == 1) { - default_addr = stream->rtp_addr; - default_port = stream->rtp_port; - } else if (ice_candidate->componentID == 2) { - default_addr = stream->rtcp_addr; - default_port = stream->rtcp_port; - } else continue; - if (default_addr[0] == '\0') default_addr = desc->addr; - /* Only include the candidates matching the default destination for each component of the stream if the state is Completed as specified in RFC5245 section 9.1.2.2. */ - if ((ice_check_list_state(cl) == ICL_Completed) - && !((ice_candidate->taddr.port == default_port) && (strlen(ice_candidate->taddr.ip) == strlen(default_addr)) && (strcmp(ice_candidate->taddr.ip, default_addr) == 0))) - continue; - strncpy(sal_candidate->foundation, ice_candidate->foundation, sizeof(sal_candidate->foundation)); - sal_candidate->componentID = ice_candidate->componentID; - sal_candidate->priority = ice_candidate->priority; - strncpy(sal_candidate->type, ice_candidate_type(ice_candidate), sizeof(sal_candidate->type)); - strncpy(sal_candidate->addr, ice_candidate->taddr.ip, sizeof(sal_candidate->addr)); - sal_candidate->port = ice_candidate->taddr.port; - if ((ice_candidate->base != NULL) && (ice_candidate->base != ice_candidate)) { - strncpy(sal_candidate->raddr, ice_candidate->base->taddr.ip, sizeof(sal_candidate->raddr)); - sal_candidate->rport = ice_candidate->base->taddr.port; - } - nb_candidates++; - } - } - if ((ice_check_list_state(cl) == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) { - memset(stream->ice_remote_candidates, 0, sizeof(stream->ice_remote_candidates)); - if (ice_check_list_selected_valid_remote_candidate(cl, &rtp_candidate, &rtcp_candidate) == TRUE) { - strncpy(stream->ice_remote_candidates[0].addr, rtp_candidate->taddr.ip, sizeof(stream->ice_remote_candidates[0].addr)); - stream->ice_remote_candidates[0].port = rtp_candidate->taddr.port; - strncpy(stream->ice_remote_candidates[1].addr, rtcp_candidate->taddr.ip, sizeof(stream->ice_remote_candidates[1].addr)); - stream->ice_remote_candidates[1].port = rtcp_candidate->taddr.port; - } else { - ms_error("ice: Selected valid remote candidates should be present if the check list is in the Completed state"); - } - } else { - for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) { - stream->ice_remote_candidates[j].addr[0] = '\0'; - stream->ice_remote_candidates[j].port = 0; - } - } - } } static void get_default_addr_and_port(uint16_t componentID, const SalMediaDescription *md, const SalStreamDescription *stream, const char **addr, int *port) @@ -939,16 +255,8 @@ static void get_default_addr_and_port(uint16_t componentID, const SalMediaDescri if ((*addr)[0] == '\0') *addr = md->addr; } -static void clear_ice_check_list(LinphoneCall *call, IceCheckList *removed){ - if (call->audiostream && call->audiostream->ms.ice_check_list==removed) - call->audiostream->ms.ice_check_list=NULL; - if (call->videostream && call->videostream->ms.ice_check_list==removed) - call->videostream->ms.ice_check_list=NULL; - if (call->textstream && call->textstream->ms.ice_check_list==removed) - call->textstream->ms.ice_check_list=NULL; -} - void linphone_call_clear_unused_ice_candidates(LinphoneCall *call, const SalMediaDescription *md){ +#if 0 int i; if (!call->localdesc) return; @@ -962,6 +270,7 @@ void linphone_call_clear_unused_ice_candidates(LinphoneCall *call, const SalMedi ice_check_list_remove_rtcp_candidates(cl); } } +#endif } bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md){ @@ -1613,186 +922,7 @@ void linphone_task_list_free(LinphoneTaskList *t){ t->hooks = bctbx_list_free_with_data(t->hooks, (void (*)(void*))ms_free); } -static bool_t _ice_params_found_in_remote_media_description(IceSession *ice_session, const SalMediaDescription *md) { - const SalStreamDescription *stream; - IceCheckList *cl = NULL; - int i; - bool_t ice_params_found = FALSE; - if ((md->ice_pwd[0] != '\0') && (md->ice_ufrag[0] != '\0')) { - ice_params_found=TRUE; - } else { - for (i = 0; i < md->nb_streams; i++) { - stream = &md->streams[i]; - cl = ice_session_check_list(ice_session, i); - if (cl) { - if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) { - ice_params_found=TRUE; - } else { - ice_params_found=FALSE; - break; - } - } - } - } - return ice_params_found; -} - -static bool_t _check_for_ice_restart_and_set_remote_credentials(IceSession *ice_session, const SalMediaDescription *md, bool_t is_offer) { - const SalStreamDescription *stream; - IceCheckList *cl = NULL; - bool_t ice_restarted = FALSE; - int i; - - if ((strcmp(md->addr, "0.0.0.0") == 0) || (strcmp(md->addr, "::0") == 0)) { - ice_session_restart(ice_session, is_offer ? IR_Controlled : IR_Controlling); - ice_restarted = TRUE; - } else { - for (i = 0; i < md->nb_streams; i++) { - stream = &md->streams[i]; - cl = ice_session_check_list(ice_session, i); - if (cl && (strcmp(stream->rtp_addr, "0.0.0.0") == 0)) { - ice_session_restart(ice_session, is_offer ? IR_Controlled : IR_Controlling); - ice_restarted = TRUE; - break; - } - } - } - if ((ice_session_remote_ufrag(ice_session) == NULL) && (ice_session_remote_pwd(ice_session) == NULL)) { - ice_session_set_remote_credentials(ice_session, md->ice_ufrag, md->ice_pwd); - } else if (ice_session_remote_credentials_changed(ice_session, md->ice_ufrag, md->ice_pwd)) { - if (ice_restarted == FALSE) { - ice_session_restart(ice_session, is_offer ? IR_Controlled : IR_Controlling); - ice_restarted = TRUE; - } - ice_session_set_remote_credentials(ice_session, md->ice_ufrag, md->ice_pwd); - } - for (i = 0; i < md->nb_streams; i++) { - stream = &md->streams[i]; - cl = ice_session_check_list(ice_session, i); - if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) { - if (ice_check_list_remote_credentials_changed(cl, stream->ice_ufrag, stream->ice_pwd)) { - if (ice_restarted == FALSE - && ice_check_list_get_remote_ufrag(cl) - && ice_check_list_get_remote_pwd(cl)) { - /* restart only if remote ufrag/paswd was already set*/ - ice_session_restart(ice_session, is_offer ? IR_Controlled : IR_Controlling); - ice_restarted = TRUE; - } - ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd); - break; - } - } - } - return ice_restarted; -} - -static void _create_ice_check_lists_and_parse_ice_attributes(LinphoneCall *call, const SalMediaDescription *md, bool_t ice_restarted) { - const SalStreamDescription *stream; - IceCheckList *cl = NULL; - bool_t default_candidate = FALSE; - const char *addr = NULL; - int port = 0; - int componentID = 0; - int remote_family; - int family; - int i, j; - - for (i = 0; i < md->nb_streams; i++) { - stream = &md->streams[i]; - cl = ice_session_check_list(call->ice_session, i); - - if (cl==NULL) continue; - if (stream->ice_mismatch == TRUE) { - ice_check_list_set_state(cl, ICL_Failed); - continue; - } - if (stream->rtp_port == 0) { - ice_session_remove_check_list(call->ice_session, cl); - clear_ice_check_list(call,cl); - continue; - } - - if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) - ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd); - for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) { - const SalIceCandidate *candidate = &stream->ice_candidates[j]; - default_candidate = FALSE; - addr = NULL; - port = 0; - if (candidate->addr[0] == '\0') break; - if ((candidate->componentID == 0) || (candidate->componentID > 2)) continue; - get_default_addr_and_port(candidate->componentID, md, stream, &addr, &port); - if (addr && (candidate->port == port) && (strlen(candidate->addr) == strlen(addr)) && (strcmp(candidate->addr, addr) == 0)) - default_candidate = TRUE; - if (strchr(candidate->addr, ':') != NULL) family = AF_INET6; - else family = AF_INET; - ice_add_remote_candidate(cl, candidate->type, family, candidate->addr, candidate->port, candidate->componentID, - candidate->priority, candidate->foundation, default_candidate); - } - if (ice_restarted == FALSE) { - bool_t losing_pairs_added = FALSE; - for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) { - const SalIceRemoteCandidate *remote_candidate = &stream->ice_remote_candidates[j]; - addr = NULL; - port = 0; - componentID = j + 1; - if (remote_candidate->addr[0] == '\0') break; - get_default_addr_and_port(componentID, md, stream, &addr, &port); - if (j == 0) { - /* If we receive a re-invite and we finished ICE processing on our side, use the candidates given by the remote. */ - ice_check_list_unselect_valid_pairs(cl); - } - if (strchr(remote_candidate->addr, ':') != NULL) remote_family = AF_INET6; - else remote_family = AF_INET; - if (strchr(addr, ':') != NULL) family = AF_INET6; - else family = AF_INET; - - ice_add_losing_pair(cl, j + 1, remote_family, remote_candidate->addr, remote_candidate->port, family, addr, port); - losing_pairs_added = TRUE; - } - if (losing_pairs_added == TRUE) ice_check_list_check_completed(cl); - } - } -} - -static void _update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md, bool_t is_offer) { - const SalStreamDescription *stream; - IceCheckList *cl = NULL; - bool_t ice_restarted = FALSE; - int i; - - /* Check for ICE restart and set remote credentials. */ - ice_restarted = _check_for_ice_restart_and_set_remote_credentials(call->ice_session, md, is_offer); - - /* Create ICE check lists if needed and parse ICE attributes. */ - _create_ice_check_lists_and_parse_ice_attributes(call, md, ice_restarted); - for (i = 0; i < md->nb_streams; i++) { - stream = &md->streams[i]; - cl = ice_session_check_list(call->ice_session, i); - if (!cl) continue; - - if (!sal_stream_description_active(stream)) { - ice_session_remove_check_list_from_idx(call->ice_session, i); - clear_ice_check_list(call, cl); - } - } - linphone_call_clear_unused_ice_candidates(call, md); - ice_session_check_mismatch(call->ice_session); -} - void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md, bool_t is_offer){ - if (_ice_params_found_in_remote_media_description(call->ice_session, md) == TRUE) { - _update_ice_from_remote_media_description(call, md, is_offer); - } else { - /* Response from remote does not contain mandatory ICE attributes, delete the session. */ - linphone_call_delete_ice_session(call); - linphone_call_set_symmetric_rtp(call, linphone_core_symmetric_rtp_enabled(linphone_call_get_core(call))); - return; - } - if (ice_session_nb_check_lists(call->ice_session) == 0) { - linphone_call_delete_ice_session(call); - linphone_call_set_symmetric_rtp(call, linphone_core_symmetric_rtp_enabled(linphone_call_get_core(call))); - } } void linphone_core_report_call_log(LinphoneCore *lc, LinphoneCallLog *call_log){ diff --git a/coreapi/nat_policy.c b/coreapi/nat_policy.c index dcd0b2d75..3290011d8 100644 --- a/coreapi/nat_policy.c +++ b/coreapi/nat_policy.c @@ -163,12 +163,7 @@ bool_t linphone_nat_policy_upnp_enabled(const LinphoneNatPolicy *policy) { void linphone_nat_policy_enable_upnp(LinphoneNatPolicy *policy, bool_t enable) { policy->upnp_enabled = enable; if (enable) { -#ifdef BUILD_UPNP - policy->stun_enabled = policy->turn_enabled = policy->ice_enabled = FALSE; - ms_warning("Enabling uPnP NAT policy has disabled any other previously enabled policies"); -#else - ms_warning("Cannot enable the uPnP NAT policy because the uPnP support is not compiled in"); -#endif + ms_warning("uPnP NAT policy is no longer supported"); } } diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 793f6539d..2e657b9a5 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -21,6 +21,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "offeranswer.h" #include "private.h" +#include "utils/payload-type-handler.h" + static bool_t only_telephone_event(const bctbx_list_t *l){ for(;l!=NULL;l=l->next){ PayloadType *p=(PayloadType*)l->data; diff --git a/coreapi/payload_type.c b/coreapi/payload_type.c index 20e2bc949..fba57120e 100644 --- a/coreapi/payload_type.c +++ b/coreapi/payload_type.c @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/payload_type.h" #include "private.h" +#include "utils/payload-type-handler.h" + struct _LinphonePayloadType { belle_sip_object_t base; OrtpPayloadType *pt; @@ -134,16 +136,16 @@ const char *linphone_payload_type_get_encoder_description(const LinphonePayloadT } static int _linphone_core_get_payload_type_normal_bitrate(const LinphoneCore *lc, const OrtpPayloadType *pt) { - int maxbw = get_min_bandwidth(linphone_core_get_download_bandwidth(lc), + int maxbw = LinphonePrivate::PayloadTypeHandler::getMinBandwidth(linphone_core_get_download_bandwidth(lc), linphone_core_get_upload_bandwidth(lc)); if (pt->type==PAYLOAD_AUDIO_CONTINUOUS || pt->type==PAYLOAD_AUDIO_PACKETIZED){ - return get_audio_payload_bandwidth(lc, pt, maxbw); + return LinphonePrivate::PayloadTypeHandler::getAudioPayloadTypeBandwidth(pt, maxbw); }else if (pt->type==PAYLOAD_VIDEO){ int video_bw; if (maxbw<=0) { video_bw=1500; /*default bitrate for video stream when no bandwidth limit is set, around 1.5 Mbit/s*/ }else{ - video_bw=get_remaining_bandwidth_for_video(maxbw,lc->audio_bw); + video_bw=LinphonePrivate::PayloadTypeHandler::getRemainingBandwidthForVideo(maxbw,lc->audio_bw); } return video_bw; } @@ -258,7 +260,7 @@ bool_t linphone_payload_type_is_vbr(const LinphonePayloadType *pt) { } bool_t _linphone_core_check_payload_type_usability(const LinphoneCore *lc, const OrtpPayloadType *pt) { - int maxbw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc), + int maxbw=LinphonePrivate::PayloadTypeHandler::getMinBandwidth(linphone_core_get_download_bandwidth(lc), linphone_core_get_upload_bandwidth(lc)); return linphone_core_is_payload_type_usable_for_bandwidth(lc, pt, maxbw); } @@ -293,3 +295,15 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphonePayloadType, belle_sip_object_t, NULL, // marshale TRUE // unown ); + + +void payload_type_set_enable(OrtpPayloadType *pt, bool_t value) { + if (value) + payload_type_set_flag(pt, PAYLOAD_TYPE_ENABLED); + else + payload_type_unset_flag(pt, PAYLOAD_TYPE_ENABLED); +} + +bool_t payload_type_enabled(const OrtpPayloadType *pt) { + return (pt->flags & PAYLOAD_TYPE_ENABLED); +} diff --git a/coreapi/player.c b/coreapi/player.c index 48ab48e04..1f3b21e67 100644 --- a/coreapi/player.c +++ b/coreapi/player.c @@ -112,15 +112,16 @@ void _linphone_player_destroy(LinphonePlayer *player) { static bool_t call_player_check_state(LinphonePlayer *player, bool_t check_player){ LinphoneCall *call=(LinphoneCall*)player->impl; - if (call->state!=LinphoneCallStreamsRunning){ - ms_warning("Call [%p]: in-call player not usable in state [%s]",call,linphone_call_state_to_string(call->state)); + if (linphone_call_get_state(call)!=LinphoneCallStreamsRunning){ + ms_warning("Call [%p]: in-call player not usable in state [%s]",call,linphone_call_state_to_string(linphone_call_get_state(call))); return FALSE; } - if (call->audiostream==NULL) { + AudioStream *astream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeAudio)); + if (astream==NULL) { ms_error("call_player_check_state(): no audiostream."); return FALSE; } - if (check_player && call->audiostream->av_player.player==NULL){ + if (check_player && astream->av_player.player==NULL){ ms_error("call_player_check_state(): no player."); return FALSE; } @@ -138,7 +139,8 @@ static int call_player_open(LinphonePlayer* player, const char *filename){ LinphoneCall *call=(LinphoneCall*)player->impl; MSFilter *filter; if (!call_player_check_state(player,FALSE)) return -1; - filter=audio_stream_open_remote_play(call->audiostream,filename); + AudioStream *astream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeAudio)); + filter=audio_stream_open_remote_play(astream,filename); if (!filter) return -1; ms_filter_add_notify_callback(filter,&on_eof,player,FALSE); return 0; @@ -147,33 +149,38 @@ static int call_player_open(LinphonePlayer* player, const char *filename){ static int call_player_start(LinphonePlayer *player){ LinphoneCall *call=(LinphoneCall*)player->impl; if (!call_player_check_state(player,TRUE)) return -1; - return ms_filter_call_method_noarg(call->audiostream->av_player.player,MS_PLAYER_START); + AudioStream *astream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeAudio)); + return ms_filter_call_method_noarg(astream->av_player.player,MS_PLAYER_START); } static int call_player_pause(LinphonePlayer *player){ LinphoneCall *call=(LinphoneCall*)player->impl; if (!call_player_check_state(player,TRUE)) return -1; - return ms_filter_call_method_noarg(call->audiostream->av_player.player,MS_PLAYER_PAUSE); + AudioStream *astream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeAudio)); + return ms_filter_call_method_noarg(astream->av_player.player,MS_PLAYER_PAUSE); } static MSPlayerState call_player_get_state(LinphonePlayer *player){ LinphoneCall *call=(LinphoneCall*)player->impl; MSPlayerState state=MSPlayerClosed; if (!call_player_check_state(player,TRUE)) return MSPlayerClosed; - ms_filter_call_method(call->audiostream->av_player.player,MS_PLAYER_GET_STATE,&state); + AudioStream *astream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeAudio)); + ms_filter_call_method(astream->av_player.player,MS_PLAYER_GET_STATE,&state); return state; } static int call_player_seek(LinphonePlayer *player, int time_ms){ LinphoneCall *call=(LinphoneCall*)player->impl; if (!call_player_check_state(player,TRUE)) return -1; - return ms_filter_call_method(call->audiostream->av_player.player,MS_PLAYER_SEEK_MS,&time_ms); + AudioStream *astream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeAudio)); + return ms_filter_call_method(astream->av_player.player,MS_PLAYER_SEEK_MS,&time_ms); } static void call_player_close(LinphonePlayer *player){ LinphoneCall *call=(LinphoneCall*)player->impl; if (!call_player_check_state(player,TRUE)) return; - audio_stream_close_remote_play(call->audiostream); + AudioStream *astream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeAudio)); + audio_stream_close_remote_play(astream); } diff --git a/coreapi/private.h b/coreapi/private.h index 5418287e4..a8ee78145 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -54,9 +54,6 @@ #include "mediastreamer2/ice.h" #include "mediastreamer2/mediastream.h" #include "mediastreamer2/msconference.h" -#ifdef BUILD_UPNP -#include "upnp.h" -#endif //BUILD_UPNP #ifndef LIBLINPHONE_VERSION @@ -266,105 +263,6 @@ struct _LinphoneCallCbs { LinphoneCallCbs * _linphone_call_cbs_new(void); -struct _LinphoneCall{ - belle_sip_object_t base; - void *user_data; - struct _LinphoneCore *core; - LinphoneErrorInfo *ei; - int af; /*the address family to prefer for RTP path, guessed from signaling path*/ - LinphoneCallDir dir; - SalMediaDescription *biggestdesc; /*media description with all already proposed streams, used to remember the mapping of streams*/ - SalMediaDescription *localdesc; - SalMediaDescription *resultdesc; - struct _RtpProfile *audio_profile; - struct _RtpProfile *video_profile; - struct _RtpProfile *text_profile; - struct _RtpProfile *rtp_io_audio_profile; - struct _RtpProfile *rtp_io_video_profile; - struct _LinphoneCallLog *log; - LinphoneAddress *me; /*Either from or to based on call dir*/ - LinphoneAddress *diversion_address; - SalOp *op; - SalOp *ping_op; - char media_localip[LINPHONE_IPADDR_SIZE]; /* our best guess for local media ipaddress for this call */ - LinphoneCallState state; - LinphoneCallState prevstate; - LinphoneCallState transfer_state; /*idle if no transfer*/ - LinphoneProxyConfig *dest_proxy; - int main_audio_stream_index, main_video_stream_index, main_text_stream_index; - PortConfig media_ports[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; - MSMediaStreamSessions sessions[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; /*the rtp, srtp, zrtp contexts for each stream*/ - StunCandidate ac, vc, tc; /*audio video text ip/port discovered by STUN*/ - struct _AudioStream *audiostream; /**/ - struct _VideoStream *videostream; - struct _TextStream *textstream; - void *video_window_id; - MSAudioEndpoint *endpoint; /*used for conferencing*/ - char *refer_to; - LinphoneCallParams *params; - LinphoneCallParams *current_params; - LinphoneCallParams *remote_params; - int up_bw; /*upload bandwidth setting at the time the call is started. Used to detect if it changes during a call */ - int audio_bw; /*upload bandwidth used by audio */ - OrtpEvQueue *audiostream_app_evq; - char *auth_token; - OrtpEvQueue *videostream_app_evq; - OrtpEvQueue *textstream_app_evq; - CallCallbackObj nextVideoFrameDecoded; - LinphoneCallStats *audio_stats; - LinphoneCallStats *video_stats; - LinphoneCallStats *text_stats; -#ifdef BUILD_UPNP - UpnpSession *upnp_session; -#endif //BUILD_UPNP - IceSession *ice_session; - int ping_time; - unsigned int remote_session_id; - unsigned int remote_session_ver; - LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/ - LinphoneCall *transfer_target;/*if this call received a transfer request, then transfer_target points to the new call created to the refer target */ - int localdesc_changed;/*not a boolean, contains a mask representing changes*/ - LinphonePlayer *player; - unsigned long bg_task_id; /*used to prevent device to suspend app while a call is received in background*/ - unsigned int nb_media_starts; - - char *dtmf_sequence; /*DTMF sequence needed to be sent using #dtmfs_timer*/ - belle_sip_source_t *dtmfs_timer; /*DTMF timer needed to send a DTMF sequence*/ - - char *dtls_certificate_fingerprint; /**> This fingerprint is computed during stream init and is stored in call to be used when making local media description */ - char *onhold_file; /*set if a on-hold file is to be played*/ - LinphoneChatRoom *chat_room; - LinphoneConference *conf_ref; /**> Point on the associated conference if this call is part of a conference. NULL instead. */ - bool_t refer_pending; - bool_t expect_media_in_ack; - bool_t audio_muted; - bool_t camera_enabled; - - bool_t all_muted; /*this flag is set during early medias*/ - bool_t playing_ringbacktone; - bool_t ringing_beep; /* whether this call is ringing through an already existent current call*/ - bool_t auth_token_verified; - - bool_t defer_update; - bool_t was_automatically_paused; - bool_t ping_replied; - bool_t record_active; - - bool_t paused_by_app; - bool_t broken; /*set to TRUE when the call is in broken state due to network disconnection or transport */ - bool_t defer_notify_incoming; - bool_t need_localip_refresh; - - bool_t reinvite_on_cancel_response_requested; - bool_t non_op_error; /*set when the LinphoneErrorInfo was set at higher level than sal*/ - - bctbx_list_t *callbacks; /* A list of LinphoneCallCbs object */ - LinphoneCallCbs *current_cbs; /* The current LinphoneCallCbs object used to call a callback */ - LinphoneNatPolicy *nat_policy; /*nat policy for this call, either from proxy nor from core*/ -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneCall); - void linphone_call_notify_state_changed(LinphoneCall *call, LinphoneCallState cstate, const char *message); void linphone_call_notify_dtmf_received(LinphoneCall *call, int dtmf); @@ -374,23 +272,28 @@ void linphone_call_notify_stats_updated(LinphoneCall *call, const LinphoneCallSt void linphone_call_notify_info_message_received(LinphoneCall *call, const LinphoneInfoMessage *msg); void linphone_call_notify_ack_processing(LinphoneCall *call, LinphoneHeaders *msg, bool_t is_received); -LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg); -LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op); +LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg); +LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, SalOp *op); void _linphone_call_set_new_params(LinphoneCall *call, const LinphoneCallParams *params); void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message); -void linphone_call_set_contact_op(LinphoneCall* call); -void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, SalMediaDescription *md); -void linphone_call_set_symmetric_rtp(LinphoneCall *call, bool_t val); /* private: */ LinphoneCallLog * linphone_call_log_new(LinphoneCallDir dir, LinphoneAddress *from, LinphoneAddress * to); -void linphone_call_log_completed(LinphoneCall *call); void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state); LinphonePlayer *linphone_call_build_player(LinphoneCall*call); void linphone_call_refresh_sockets(LinphoneCall *call); void linphone_call_replace_op(LinphoneCall *call, SalOp *op); void linphone_call_reinvite_to_recover_from_connection_loss(LinphoneCall *call); -LinphoneCallParams * linphone_call_params_new(void); +SalOp * linphone_call_get_op(const LinphoneCall *call); +LinphoneProxyConfig * linphone_call_get_dest_proxy(const LinphoneCall *call); +MediaStream * linphone_call_get_stream(LinphoneCall *call, LinphoneStreamType type); +LinphoneCallLog * linphone_call_get_log(const LinphoneCall *call); +IceSession * linphone_call_get_ice_session(const LinphoneCall *call); +bool_t linphone_call_get_audio_muted(const LinphoneCall *call); +void linphone_call_set_audio_muted(LinphoneCall *call, bool_t value); +bool_t linphone_call_get_all_muted(const LinphoneCall *call); + +LinphoneCallParams * linphone_call_params_new(LinphoneCore *core); SalMediaProto get_proto_from_call_params(const LinphoneCallParams *params); SalStreamDir get_audio_dir_from_call_params(const LinphoneCallParams *params); SalStreamDir get_video_dir_from_call_params(const LinphoneCallParams *params); @@ -496,24 +399,6 @@ int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, sock bool_t host_has_ipv6_network(void); bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret); -static MS2_INLINE int get_min_bandwidth(int dbw, int ubw){ - if (dbw<=0) return ubw; - if (ubw<=0) return dbw; - return MIN(dbw,ubw); -} - -static MS2_INLINE bool_t bandwidth_is_greater(int bw1, int bw2){ - if (bw1<=0) return TRUE; - else if (bw2<=0) return FALSE; - else return bw1>=bw2; -} - -static MS2_INLINE int get_remaining_bandwidth_for_video(int total, int audio){ - int ret = total-audio-10; - if (ret < 0) ret = 0; - return ret; -} - static MS2_INLINE void set_string(char **dest, const char *src, bool_t lowercase){ if (*dest){ ms_free(*dest); @@ -528,10 +413,6 @@ static MS2_INLINE void set_string(char **dest, const char *src, bool_t lowercase } } -#define PAYLOAD_TYPE_ENABLED PAYLOAD_TYPE_USER_FLAG_0 -#define PAYLOAD_TYPE_BITRATE_OVERRIDE PAYLOAD_TYPE_USER_FLAG_3 -#define PAYLOAD_TYPE_FROZEN_NUMBER PAYLOAD_TYPE_USER_FLAG_4 - void linphone_process_authentication(LinphoneCore* lc, SalOp *op); void linphone_authentication_ok(LinphoneCore *lc, SalOp *op); void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from); @@ -547,19 +428,18 @@ void linphone_subscription_answered(LinphoneCore *lc, SalOp *op); void linphone_subscription_closed(LinphoneCore *lc, SalOp *op); void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc); -void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt, int maxbw); -LINPHONE_PUBLIC int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call); +LINPHONE_PUBLIC int linphone_run_stun_tests(LinphoneCore *lc, int audioPort, int videoPort, int textPort, + char *audioCandidateAddr, int *audioCandidatePort, char *videoCandidateAddr, int *videoCandidatePort, char *textCandidateAddr, int *textCandidatePort); void linphone_core_resolve_stun_server(LinphoneCore *lc); LINPHONE_PUBLIC const struct addrinfo *linphone_core_get_stun_server_addrinfo(LinphoneCore *lc); -void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params); -int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call); LINPHONE_PUBLIC void linphone_core_enable_forced_ice_relay(LinphoneCore *lc, bool_t enable); LINPHONE_PUBLIC void linphone_core_enable_short_turn_refresh(LinphoneCore *lc, bool_t enable); void linphone_call_update_ice_state_in_call_stats(LinphoneCall *call); LINPHONE_PUBLIC void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEvent *ev); -void linphone_call_stop_ice_for_inactive_streams(LinphoneCall *call, SalMediaDescription *result); -void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session, bool_t use_nortpproxy); +void linphone_call_stats_update(LinphoneCallStats *stats, MediaStream *stream); +void linphone_call_stats_uninit(LinphoneCallStats *stats); +void _linphone_call_stats_clone(LinphoneCallStats *dst, const LinphoneCallStats *src); void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall *call); void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md, bool_t is_offer); void linphone_call_clear_unused_ice_candidates(LinphoneCall *call, const SalMediaDescription *md); @@ -582,20 +462,10 @@ void linphone_proxy_config_write_to_config_file(LinphoneConfig* config,LinphoneP int linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *msg); void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, uint32_t character, LinphoneCall *call); -void linphone_call_init_stats(LinphoneCallStats *stats, LinphoneStreamType type); -void linphone_call_fix_call_parameters(LinphoneCall *call, SalMediaDescription *rmd); -void linphone_call_init_audio_stream(LinphoneCall *call); -void linphone_call_init_video_stream(LinphoneCall *call); -void linphone_call_init_text_stream(LinphoneCall *call); void linphone_call_init_media_streams(LinphoneCall *call); -void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState target_state); void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call); void linphone_call_stop_media_streams(LinphoneCall *call); -void linphone_call_delete_ice_session(LinphoneCall *call); void linphone_call_delete_upnp_session(LinphoneCall *call); -void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call); -void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md); -void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call); int _linphone_core_apply_transports(LinphoneCore *lc); const char * linphone_core_get_identity(LinphoneCore *lc); @@ -960,7 +830,6 @@ LinphoneToneDescription *linphone_core_get_call_error_tone(const LinphoneCore *l void linphone_core_play_call_error_tone(LinphoneCore *lc, LinphoneReason reason); void _linphone_core_set_tone(LinphoneCore *lc, LinphoneReason reason, LinphoneToneID id, const char *audiofile); LINPHONE_PUBLIC const char *linphone_core_get_tone_file(const LinphoneCore *lc, LinphoneToneID id); -int _linphone_call_accept_update(LinphoneCall *call, const LinphoneCallParams *params, LinphoneCallState next_state, const char *state_info); typedef struct _LinphoneTaskList{ MSList *hooks; @@ -1084,9 +953,6 @@ struct _LinphoneCore sqlite3 *friends_db; bool_t debug_storage; #endif -#ifdef BUILD_UPNP - UpnpContext *upnp; -#endif //BUILD_UPNP belle_http_provider_t *http_provider; belle_tls_crypto_config_t *http_crypto_config; belle_http_request_listener_t *provisioning_http_listener; @@ -1171,9 +1037,6 @@ void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const void linphone_call_update_biggest_desc(LinphoneCall *call, SalMediaDescription *md); void linphone_call_make_local_media_description(LinphoneCall *call); void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, LinphoneCall *call, LinphoneCallParams *params); -void linphone_call_increment_local_media_description(LinphoneCall *call); -void linphone_call_fill_media_multicast_addr(LinphoneCall *call); -void linphone_call_update_streams(LinphoneCall *call, SalMediaDescription *new_md, LinphoneCallState target_state); bool_t linphone_core_is_payload_type_usable_for_bandwidth(const LinphoneCore *lc, const PayloadType *pt, int bandwidth_limit); @@ -1219,7 +1082,6 @@ struct _EchoTester { typedef struct _EchoTester EchoTester; -void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed); void linphone_call_set_broken(LinphoneCall *call); void linphone_call_repair_if_broken(LinphoneCall *call); void linphone_core_repair_calls(LinphoneCore *lc); @@ -1283,9 +1145,7 @@ bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc); const char *linphone_core_create_uuid(LinphoneCore *lc); void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact); void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact, LinphoneProxyConfig *proxy); -void linphone_call_create_op_to(LinphoneCall *call, LinphoneAddress *to); void linphone_call_create_op(LinphoneCall *call); -int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer); void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, SalBodyHandler *body); LinphoneContent * linphone_content_new(void); LinphoneContent * linphone_content_copy(const LinphoneContent *ref); @@ -1692,18 +1552,10 @@ char * linphone_timestamp_to_rfc3339_string(time_t timestamp); void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const SalOp *op); -static MS2_INLINE void payload_type_set_enable(OrtpPayloadType *pt,int value) -{ - if ((value)!=0) payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED); \ - else payload_type_unset_flag(pt,PAYLOAD_TYPE_ENABLED); -} - -static MS2_INLINE bool_t payload_type_enabled(const OrtpPayloadType *pt) { - return (((pt)->flags & PAYLOAD_TYPE_ENABLED)!=0); -} +void payload_type_set_enable(OrtpPayloadType *pt, bool_t value); +bool_t payload_type_enabled(const OrtpPayloadType *pt); bool_t is_payload_type_number_available(const MSList *l, int number, const OrtpPayloadType *ignore); -int get_audio_payload_bandwidth(const LinphoneCore *lc, const PayloadType *pt, int maxbw); LinphonePayloadType *linphone_payload_type_new(LinphoneCore *lc, OrtpPayloadType *ortp_pt); bool_t _linphone_core_check_payload_type_usability(const LinphoneCore *lc, const OrtpPayloadType *pt); OrtpPayloadType *linphone_payload_type_get_ortp_pt(const LinphonePayloadType *pt); @@ -1917,7 +1769,6 @@ void linphone_core_notify_friend_list_removed(LinphoneCore *lc, LinphoneFriendLi void linphone_core_notify_call_created(LinphoneCore *lc, LinphoneCall *call); void linphone_core_notify_version_update_check_result_received(LinphoneCore *lc, LinphoneVersionUpdateCheckResult result, const char *version, const char *url); -void set_mic_gain_db(AudioStream *st, float gain); void set_playback_gain_db(AudioStream *st, float gain); LinphoneMediaDirection media_direction_from_sal_stream_dir(SalStreamDir dir); @@ -1956,7 +1807,6 @@ void v_table_reference_destroy(VTableReference *ref); LINPHONE_PUBLIC void _linphone_core_add_callbacks(LinphoneCore *lc, LinphoneCoreCbs *vtable, bool_t internal); #ifdef VIDEO_ENABLED -LINPHONE_PUBLIC MSWebCam *linphone_call_get_video_device(const LinphoneCall *call); MSWebCam *get_nowebcam_device(MSFactory *f); #endif LinphoneLimeState linphone_core_lime_for_file_sharing_enabled(const LinphoneCore *lc); @@ -1969,8 +1819,6 @@ char *linphone_presence_model_to_xml(LinphonePresenceModel *model) ; #define LINPHONE_SQLITE3_VFS "sqlite3bctbx_vfs" -void linphone_call_check_ice_session(LinphoneCall *call, IceRole role, bool_t is_reinvite); - bool_t linphone_call_state_is_early(LinphoneCallState state); struct _LinphoneErrorInfo{ diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 43ddd184a..e5a4e03b1 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -467,13 +467,6 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *cfg){ if (cfg->contact_uri_params){ linphone_address_set_uri_params(contact,cfg->contact_uri_params); } -#ifdef BUILD_UPNP - if (cfg->lc->upnp != NULL && linphone_core_get_firewall_policy(cfg->lc)==LinphonePolicyUseUpnp && - linphone_upnp_context_get_state(cfg->lc->upnp) == LinphoneUpnpStateOk) { - localip = linphone_upnp_context_get_external_ipaddress(cfg->lc->upnp); - localport = linphone_upnp_context_get_external_port(cfg->lc->upnp); - } -#endif //BUILD_UPNP linphone_address_set_port(contact,localport); linphone_address_set_domain(contact,localip); linphone_address_set_display_name(contact,NULL); @@ -1274,14 +1267,6 @@ SipSetup *linphone_proxy_config_get_sip_setup(LinphoneProxyConfig *cfg){ static bool_t can_register(LinphoneProxyConfig *cfg){ LinphoneCore *lc=cfg->lc; -#ifdef BUILD_UPNP - if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp){ - if(lc->sip_conf.register_only_when_upnp_is_ok && - (lc->upnp == NULL || !linphone_upnp_context_is_ready_for_register(lc->upnp))) { - return FALSE; - } - } -#endif //BUILD_UPNP if (lc->sip_conf.register_only_when_network_is_up){ return lc->sip_network_reachable; } diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 3c3289f8b..2727fa861 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -154,10 +154,15 @@ static uint8_t are_metrics_filled(const reporting_content_metrics_t *rm) { } static bool_t quality_reporting_enabled(const LinphoneCall * call) { +#if 0 return (call->dest_proxy != NULL && linphone_proxy_config_quality_reporting_enabled(call->dest_proxy)); +#else + return FALSE; +#endif } static bool_t media_report_enabled(LinphoneCall * call, int stats_type){ +#if 0 if (! quality_reporting_enabled(call)) return FALSE; @@ -168,6 +173,9 @@ static bool_t media_report_enabled(LinphoneCall * call, int stats_type){ return FALSE; return (call->log->reporting.reports[stats_type] != NULL); +#else + return FALSE; +#endif } static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * offset, const reporting_content_metrics_t *rm) { @@ -351,18 +359,18 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report, linphone_content_set_buffer(content, buffer, strlen(buffer)); ms_free(buffer); - if (call->log->reporting.on_report_sent != NULL) { - SalStreamType type = report == call->log->reporting.reports[0] ? SalAudio : report == call->log->reporting.reports[1] ? SalVideo : SalText; - call->log->reporting.on_report_sent(call, type, content); + if (linphone_call_get_log(call)->reporting.on_report_sent != NULL) { + SalStreamType type = report == linphone_call_get_log(call)->reporting.reports[0] ? SalAudio : report == linphone_call_get_log(call)->reporting.reports[1] ? SalVideo : SalText; + linphone_call_get_log(call)->reporting.on_report_sent(call, type, content); } - collector_uri = linphone_proxy_config_get_quality_reporting_collector(call->dest_proxy); + collector_uri = linphone_proxy_config_get_quality_reporting_collector(linphone_call_get_dest_proxy(call)); if (!collector_uri){ - collector_uri = collector_uri_allocated = ms_strdup_printf("sip:%s", linphone_proxy_config_get_domain(call->dest_proxy)); + collector_uri = collector_uri_allocated = ms_strdup_printf("sip:%s", linphone_proxy_config_get_domain(linphone_call_get_dest_proxy(call))); } request_uri = linphone_address_new(collector_uri); - lev = linphone_core_create_one_shot_publish(call->core, request_uri, "vq-rtcpxr"); + lev = linphone_core_create_one_shot_publish(linphone_call_get_core(call), request_uri, "vq-rtcpxr"); /* Special exception for quality report PUBLISH: if the collector_uri has any transport related parameters * (port, transport, maddr), then it is sent directly. * Otherwise it is routed as any LinphoneEvent publish, following proxy config policy. @@ -414,6 +422,7 @@ static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDesc } static void update_ip(LinphoneCall * call, int stats_type) { +#if 0 SalStreamType sal_stream_type = stats_type == LINPHONE_CALL_STATS_AUDIO ? SalAudio : stats_type == LINPHONE_CALL_STATS_VIDEO ? SalVideo : SalText; const SalStreamDescription * local_desc = get_media_stream_for_desc(call->localdesc, sal_stream_type); const SalStreamDescription * remote_desc = get_media_stream_for_desc(sal_call_get_remote_media_description(call->op), sal_stream_type); @@ -438,6 +447,7 @@ static void update_ip(LinphoneCall * call, int stats_type) { STR_REASSIGN(call->log->reporting.reports[stats_type]->info.remote_addr.ip, ms_strdup(sal_call_get_remote_media_description(call->op)->addr)); } } +#endif } static void qos_analyzer_on_action_suggested(void *user_data, int datac, const char** datav){ @@ -449,7 +459,7 @@ static void qos_analyzer_on_action_suggested(void *user_data, int datac, const c int bitrate[3] = {-1, -1, -1}; int up_bw[3] = {-1, -1, -1}; int down_bw[3] = {-1, -1, -1}; - MediaStream *streams[3] = { (MediaStream*) call->audiostream, (MediaStream *) call->videostream, (MediaStream *) call->textstream }; + MediaStream *streams[3] = { linphone_call_get_stream(call, LinphoneStreamTypeAudio), linphone_call_get_stream(call, LinphoneStreamTypeVideo), linphone_call_get_stream(call, LinphoneStreamTypeText) }; for (i = 0; i < 3; i++){ if (streams[i] != NULL){ if (streams[i]->encoder != NULL){ @@ -462,10 +472,11 @@ static void qos_analyzer_on_action_suggested(void *user_data, int datac, const c down_bw[i] = (int)(media_stream_get_down_bw(streams[i])/1000.f); } } - if (call->audiostream!=NULL){ - if (call->audiostream->ms.encoder!=NULL){ - if(ms_filter_has_method(call->audiostream->ms.encoder,MS_AUDIO_ENCODER_GET_PTIME)){ - ms_filter_call_method(call->audiostream->ms.encoder,MS_AUDIO_ENCODER_GET_PTIME,&ptime); + AudioStream *astream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeAudio)); + if (astream!=NULL){ + if (astream->ms.encoder!=NULL){ + if(ms_filter_has_method(astream->ms.encoder,MS_AUDIO_ENCODER_GET_PTIME)){ + ms_filter_call_method(astream->ms.encoder,MS_AUDIO_ENCODER_GET_PTIME,&ptime); } } } @@ -489,6 +500,7 @@ void linphone_reporting_update_ip(LinphoneCall * call) { } void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { +#if 0 MediaStream * stream = NULL; const PayloadType * local_payload = NULL; const PayloadType * remote_payload = NULL; @@ -588,6 +600,7 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { } ms_free(dialog_id); +#endif } /* generate random float in interval ] 0.9 t ; 1.1 t [*/ @@ -596,6 +609,7 @@ static float reporting_rand(float t){ } void linphone_reporting_on_rtcp_update(LinphoneCall *call, SalStreamType stats_type) { +#if 0 reporting_session_report_t * report = call->log->reporting.reports[stats_type]; reporting_content_metrics_t * metrics = NULL; LinphoneCallStats *stats = NULL; @@ -665,9 +679,11 @@ void linphone_reporting_on_rtcp_update(LinphoneCall *call, SalStreamType stats_t linphone_reporting_update_media_info(call, stats_type); send_report(call, report, "VQIntervalReport"); } +#endif } static int publish_report(LinphoneCall *call, const char *event_type){ +#if 0 int ret = 0; int i; for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++){ @@ -684,11 +700,18 @@ static int publish_report(LinphoneCall *call, const char *event_type){ } } return ret; +#else + return 0; +#endif } int linphone_reporting_publish_session_report(LinphoneCall* call, bool_t call_term) { +#if 0 const char * session_type = call_term?"VQSessionReport: CallTerm":"VQSessionReport"; return publish_report(call, session_type); +#else + return 0; +#endif } int linphone_reporting_publish_interval_report(LinphoneCall* call) { @@ -709,6 +732,7 @@ static bool_t set_on_action_suggested_cb(MediaStream *stream,void (*on_action_su } void linphone_reporting_call_state_updated(LinphoneCall *call){ +#if 0 LinphoneCallState state=linphone_call_get_state(call); if (state == LinphoneCallReleased||!quality_reporting_enabled(call)){ return; @@ -744,6 +768,7 @@ void linphone_reporting_call_state_updated(LinphoneCall *call){ break; } } +#endif } reporting_session_report_t * linphone_reporting_new() { @@ -808,5 +833,5 @@ void linphone_reporting_destroy(reporting_session_report_t * report) { void linphone_reporting_set_on_report_send(LinphoneCall *call, LinphoneQualityReportingReportSendCb cb){ - call->log->reporting.on_report_sent = cb; + linphone_call_get_log(call)->reporting.on_report_sent = cb; } diff --git a/coreapi/upnp.c b/coreapi/upnp.c deleted file mode 100644 index 642eb24bc..000000000 --- a/coreapi/upnp.c +++ /dev/null @@ -1,1412 +0,0 @@ -/* -linphone -Copyright (C) 2012 Belledonne Communications SARL - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "upnp.h" -#include "private.h" -#include "linphone/lpconfig.h" -#include - -#define UPNP_STRINGIFY(x) #x -#define UPNP_TOSTRING(x) UPNP_STRINGIFY(x) - -#define UPNP_ADD_MAX_RETRY 4 -#define UPNP_REMOVE_MAX_RETRY 4 -#define UPNP_SECTION_NAME "uPnP" -#define UPNP_CORE_READY_CHECK 1 -#define UPNP_CORE_RETRY_DELAY 10 -#define UPNP_CALL_RETRY_DELAY 3 -#define UPNP_UUID_LEN 128 -#define UPNP_UUID_LEN_STR UPNP_TOSTRING(UPNP_UUID_LEN) -/* - * uPnP Definitions - */ - -typedef struct _UpnpPortBinding { - ms_mutex_t mutex; - LinphoneUpnpState state; - upnp_igd_ip_protocol protocol; - char *device_id; - char local_addr[LINPHONE_IPADDR_SIZE]; - int local_port; - char external_addr[LINPHONE_IPADDR_SIZE]; - int external_port; - int retry; - int ref; - bool_t to_remove; - bool_t to_add; - time_t last_update; -} UpnpPortBinding; - -typedef struct _UpnpStream { - UpnpPortBinding *rtp; - UpnpPortBinding *rtcp; - LinphoneUpnpState state; -} UpnpStream; - -struct _UpnpSession { - LinphoneCall *call; - UpnpStream *audio; - UpnpStream *video; - LinphoneUpnpState state; -}; - -struct _UpnpContext { - LinphoneCore *lc; - upnp_igd_context *upnp_igd_ctxt; - UpnpPortBinding *sip_tcp; - UpnpPortBinding *sip_tls; - UpnpPortBinding *sip_udp; - LinphoneUpnpState state; - bctbx_list_t *removing_configs; - bctbx_list_t *adding_configs; - bctbx_list_t *pending_bindings; - - ms_mutex_t mutex; - ms_cond_t empty_cond; - - time_t last_ready_check; - LinphoneUpnpState last_ready_state; -}; - - -bool_t linphone_core_upnp_hook(void *data); -void linphone_upnp_update(UpnpContext *ctx); -bool_t linphone_upnp_is_blacklisted(UpnpContext *ctx); - -UpnpPortBinding *linphone_upnp_port_binding_new(void); -UpnpPortBinding *linphone_upnp_port_binding_new_with_parameters(upnp_igd_ip_protocol protocol, int local_port, int external_port); -UpnpPortBinding *linphone_upnp_port_binding_new_or_collect(bctbx_list_t *list, upnp_igd_ip_protocol protocol, int local_port, int external_port); -UpnpPortBinding *linphone_upnp_port_binding_copy(const UpnpPortBinding *port); -void linphone_upnp_port_binding_set_device_id(UpnpPortBinding *port, const char * device_id); -bool_t linphone_upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2); -UpnpPortBinding *linphone_upnp_port_binding_equivalent_in_list(bctbx_list_t *list, const UpnpPortBinding *port); -UpnpPortBinding *linphone_upnp_port_binding_retain(UpnpPortBinding *port); -void linphone_upnp_update_port_binding(UpnpContext *lupnp, UpnpPortBinding **port_mapping, upnp_igd_ip_protocol protocol, int port, int retry_delay); -void linphone_upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *port); -void linphone_upnp_port_binding_release(UpnpPortBinding *port); -void linphone_upnp_update_config(UpnpContext *lupnp); -void linphone_upnp_update_proxy(UpnpContext *lupnp, bool_t force); - -// Configuration -bctbx_list_t *linphone_upnp_config_list_port_bindings(struct _LpConfig *lpc, const char *device_id); -void linphone_upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port); -void linphone_upnp_config_remove_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port); - -// uPnP -int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry); -int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry); - -static int linphone_upnp_strncmpi(const char *str1, const char *str2, int len) { - int i = 0; - char char1, char2; - while(i < len) { - char1 = toupper(*str1); - char2 = toupper(*str2); - if(char1 == '\0' || char1 != char2) { - return char1 - char2; - } - str1++; - str2++; - i++; - } - return 0; -} - -static int linphone_upnp_str_min(const char *str1, const char *str2) { - int len1 = strlen(str1); - int len2 = strlen(str2); - if(len1 > len2) { - return len2; - } - return len1; -} - -char * linphone_upnp_format_device_id(const char *device_id) { - char *ret = NULL; - char *tmp; - char tchar; - bool_t copy; - if(device_id == NULL) { - return ret; - } - ret = ms_new0(char, UPNP_UUID_LEN + 1); - tmp = ret; - if(linphone_upnp_strncmpi(device_id, "uuid:", linphone_upnp_str_min(device_id, "uuid:")) == 0) { - device_id += strlen("uuid:"); - } - while(*device_id != '\0' && tmp - ret < UPNP_UUID_LEN) { - copy = FALSE; - tchar = *device_id; - if(tchar >= '0' && tchar <= '9') - copy = TRUE; - if(!copy && tchar >= 'A' && tchar <= 'Z') - copy = TRUE; - if(!copy && tchar >= 'a' && tchar <= 'z') - copy = TRUE; - if(copy) { - *tmp = *device_id; - tmp++; - } - device_id++; - } - *tmp = '\0'; - return ret; -} - -/** - * uPnP Callbacks - */ - -/* Convert uPnP IGD logs to ortp logs */ -void linphone_upnp_igd_print(void *cookie, upnp_igd_print_level level, const char *fmt, va_list list) { - int ortp_level = ORTP_DEBUG; - switch(level) { - case UPNP_IGD_MESSAGE: - ortp_level = ORTP_MESSAGE; - break; - case UPNP_IGD_WARNING: - ortp_level = ORTP_DEBUG; // Too verbose otherwise - break; - case UPNP_IGD_ERROR: - ortp_level = ORTP_DEBUG; // Too verbose otherwise - break; - default: - break; - } - ortp_logv(ORTP_LOG_DOMAIN, ortp_level, fmt, list); -} - -void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { - UpnpContext *lupnp = (UpnpContext *)cookie; - upnp_igd_port_mapping *mapping = NULL; - UpnpPortBinding *port_mapping = NULL; - const char *ip_address = NULL; - const char *connection_status = NULL; - bool_t nat_enabled = FALSE; - bool_t blacklisted = FALSE; - LinphoneUpnpState old_state; - - if(lupnp == NULL || lupnp->upnp_igd_ctxt == NULL) { - ms_error("uPnP IGD: Invalid context in callback"); - return; - } - - ms_mutex_lock(&lupnp->mutex); - old_state = lupnp->state; - - switch(event) { - case UPNP_IGD_DEVICE_ADDED: - case UPNP_IGD_DEVICE_REMOVED: - case UPNP_IGD_EXTERNAL_IPADDRESS_CHANGED: - case UPNP_IGD_NAT_ENABLED_CHANGED: - case UPNP_IGD_CONNECTION_STATUS_CHANGED: - ip_address = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt); - connection_status = upnp_igd_get_connection_status(lupnp->upnp_igd_ctxt); - nat_enabled = upnp_igd_get_nat_enabled(lupnp->upnp_igd_ctxt); - blacklisted = linphone_upnp_is_blacklisted(lupnp); - - if(ip_address == NULL || connection_status == NULL) { - ms_message("uPnP IGD: Pending"); - lupnp->state = LinphoneUpnpStatePending; - } else if(strcasecmp(connection_status, "Connected") || !nat_enabled) { - ms_message("uPnP IGD: Not Available"); - lupnp->state = LinphoneUpnpStateNotAvailable; - } else if(blacklisted) { - ms_message("uPnP IGD: Router is blacklisted"); - lupnp->state = LinphoneUpnpStateBlacklisted; - } else { - ms_message("uPnP IGD: Connected"); - lupnp->state = LinphoneUpnpStateOk; - if(old_state != LinphoneUpnpStateOk) { - linphone_upnp_update(lupnp); - } - } - - break; - - case UPNP_IGD_PORT_MAPPING_ADD_SUCCESS: - mapping = (upnp_igd_port_mapping *) arg; - port_mapping = (UpnpPortBinding*) mapping->cookie; - port_mapping->external_port = mapping->remote_port; - port_mapping->state = LinphoneUpnpStateOk; - linphone_upnp_port_binding_log(ORTP_MESSAGE, "Added port binding", port_mapping); - linphone_upnp_config_add_port_binding(lupnp, port_mapping); - - break; - - case UPNP_IGD_PORT_MAPPING_ADD_FAILURE: - mapping = (upnp_igd_port_mapping *) arg; - port_mapping = (UpnpPortBinding*) mapping->cookie; - port_mapping->external_port = -1; //Force random external port - if(linphone_upnp_context_send_add_port_binding(lupnp, port_mapping, TRUE) != 0) { - linphone_upnp_port_binding_log(ORTP_ERROR, "Can't add port binding", port_mapping); - } - - break; - - case UPNP_IGD_PORT_MAPPING_REMOVE_SUCCESS: - mapping = (upnp_igd_port_mapping *) arg; - port_mapping = (UpnpPortBinding*) mapping->cookie; - port_mapping->state = LinphoneUpnpStateIdle; - linphone_upnp_port_binding_log(ORTP_MESSAGE, "Removed port binding", port_mapping); - linphone_upnp_config_remove_port_binding(lupnp, port_mapping); - - break; - - case UPNP_IGD_PORT_MAPPING_REMOVE_FAILURE: - mapping = (upnp_igd_port_mapping *) arg; - port_mapping = (UpnpPortBinding*) mapping->cookie; - if(linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping, TRUE) != 0) { - linphone_upnp_port_binding_log(ORTP_ERROR, "Can't remove port binding", port_mapping); - linphone_upnp_config_remove_port_binding(lupnp, port_mapping); - } - - break; - - default: - break; - } - - if(port_mapping != NULL) { - /* - * Execute delayed actions - */ - if(port_mapping->to_remove) { - if(port_mapping->state == LinphoneUpnpStateOk) { - port_mapping->to_remove = FALSE; - linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping, FALSE); - } else if(port_mapping->state == LinphoneUpnpStateKo) { - port_mapping->to_remove = FALSE; - } - } - if(port_mapping->to_add) { - if(port_mapping->state == LinphoneUpnpStateIdle || port_mapping->state == LinphoneUpnpStateKo) { - port_mapping->to_add = FALSE; - linphone_upnp_context_send_add_port_binding(lupnp, port_mapping, FALSE); - } - } - - lupnp->pending_bindings = bctbx_list_remove(lupnp->pending_bindings, port_mapping); - linphone_upnp_port_binding_release(port_mapping); - } - - /* - * If there is no pending binding emit a signal - */ - if(lupnp->pending_bindings == NULL) { - ms_cond_signal(&lupnp->empty_cond); - } - ms_mutex_unlock(&lupnp->mutex); -} - - -/** - * uPnP Context - */ - -UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) { - UpnpContext *lupnp = (UpnpContext *)ms_new0(UpnpContext,1); - char address[LINPHONE_IPADDR_SIZE]; - const char*upnp_binding_address=address; - if (linphone_core_get_local_ip_for(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,NULL,address)) { - ms_warning("Linphone core [%p] cannot guess local address for upnp, let's choice the lib",lc); - upnp_binding_address=NULL; - } - ms_mutex_init(&lupnp->mutex, NULL); - ms_cond_init(&lupnp->empty_cond, NULL); - - lupnp->last_ready_check = 0; - lupnp->last_ready_state = LinphoneUpnpStateIdle; - - lupnp->lc = lc; - lupnp->pending_bindings = NULL; - lupnp->adding_configs = NULL; - lupnp->removing_configs = NULL; - lupnp->state = LinphoneUpnpStateIdle; - ms_message("uPnP IGD: New %p for core %p bound to %s", lupnp, lc,upnp_binding_address); - - // Init ports - lupnp->sip_udp = NULL; - lupnp->sip_tcp = NULL; - lupnp->sip_tls = NULL; - - linphone_core_add_iterate_hook(lc, linphone_core_upnp_hook, lupnp); - - lupnp->upnp_igd_ctxt = NULL; - lupnp->upnp_igd_ctxt = upnp_igd_create(linphone_upnp_igd_callback, linphone_upnp_igd_print, address, lupnp); - if(lupnp->upnp_igd_ctxt == NULL) { - lupnp->state = LinphoneUpnpStateKo; - ms_error("Can't create uPnP IGD context"); - return NULL; - } - - lupnp->state = LinphoneUpnpStatePending; - upnp_igd_start(lupnp->upnp_igd_ctxt); - - return lupnp; -} - -void linphone_upnp_context_destroy(UpnpContext *lupnp) { - linphone_core_remove_iterate_hook(lupnp->lc, linphone_core_upnp_hook, lupnp); - - ms_mutex_lock(&lupnp->mutex); - - if(lupnp->lc->sip_network_reachable) { - /* Send port binding removes */ - if(lupnp->sip_udp != NULL) { - linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_udp, TRUE); - } - if(lupnp->sip_tcp != NULL) { - linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tcp, TRUE); - } - if(lupnp->sip_tls != NULL) { - linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tls, TRUE); - } - } - - /* Wait all pending bindings are done */ - if(lupnp->pending_bindings != NULL) { - ms_message("uPnP IGD: Wait all pending port bindings ..."); - ms_cond_wait(&lupnp->empty_cond, &lupnp->mutex); - } - ms_mutex_unlock(&lupnp->mutex); - - if(lupnp->upnp_igd_ctxt != NULL) { - upnp_igd_destroy(lupnp->upnp_igd_ctxt); - lupnp->upnp_igd_ctxt = NULL; - } - - /* No more multi threading here */ - - /* Run one more time configuration update and proxy */ - linphone_upnp_update_config(lupnp); - linphone_upnp_update_proxy(lupnp, TRUE); - - /* Release port bindings */ - if(lupnp->sip_udp != NULL) { - linphone_upnp_port_binding_release(lupnp->sip_udp); - lupnp->sip_udp = NULL; - } - if(lupnp->sip_tcp != NULL) { - linphone_upnp_port_binding_release(lupnp->sip_tcp); - lupnp->sip_tcp = NULL; - } - if(lupnp->sip_tls != NULL) { - linphone_upnp_port_binding_release(lupnp->sip_tls); - lupnp->sip_tcp = NULL; - } - - /* Release lists */ - bctbx_list_for_each(lupnp->adding_configs,(void (*)(void*))linphone_upnp_port_binding_release); - lupnp->adding_configs = bctbx_list_free(lupnp->adding_configs); - bctbx_list_for_each(lupnp->removing_configs,(void (*)(void*))linphone_upnp_port_binding_release); - lupnp->removing_configs = bctbx_list_free(lupnp->removing_configs); - bctbx_list_for_each(lupnp->pending_bindings,(void (*)(void*))linphone_upnp_port_binding_release); - lupnp->pending_bindings = bctbx_list_free(lupnp->pending_bindings); - - ms_mutex_destroy(&lupnp->mutex); - ms_cond_destroy(&lupnp->empty_cond); - - ms_message("uPnP IGD: destroy %p", lupnp); - ms_free(lupnp); -} - -LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *lupnp) { - LinphoneUpnpState state = LinphoneUpnpStateKo; - if(lupnp != NULL) { - ms_mutex_lock(&lupnp->mutex); - state = lupnp->state; - ms_mutex_unlock(&lupnp->mutex); - } - return state; -} - -bool_t _linphone_upnp_context_is_ready_for_register(UpnpContext *lupnp) { - bool_t ready = TRUE; - - // 1 Check global uPnP state - ready = (lupnp->state == LinphoneUpnpStateOk); - - // 2 Check external ip address - if(ready) { - if (upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt) == NULL) { - ready = FALSE; - } - } - - // 3 Check sip ports bindings - if(ready) { - if(lupnp->sip_udp != NULL) { - if(lupnp->sip_udp->state != LinphoneUpnpStateOk) { - ready = FALSE; - } - } else if(lupnp->sip_tcp != NULL) { - if(lupnp->sip_tcp->state != LinphoneUpnpStateOk) { - ready = FALSE; - } - } else if(lupnp->sip_tls != NULL) { - if(lupnp->sip_tls->state != LinphoneUpnpStateOk) { - ready = FALSE; - } - } else { - ready = FALSE; - } - } - - return ready; -} - -bool_t linphone_upnp_context_is_ready_for_register(UpnpContext *lupnp) { - bool_t ready = FALSE; - if(lupnp != NULL) { - ms_mutex_lock(&lupnp->mutex); - ready = _linphone_upnp_context_is_ready_for_register(lupnp); - ms_mutex_unlock(&lupnp->mutex); - } - return ready; -} - -int linphone_upnp_context_get_external_port(UpnpContext *lupnp) { - int port = -1; - if(lupnp != NULL) { - ms_mutex_lock(&lupnp->mutex); - - if(lupnp->sip_udp != NULL) { - if(lupnp->sip_udp->state == LinphoneUpnpStateOk) { - port = lupnp->sip_udp->external_port; - } - } else if(lupnp->sip_tcp != NULL) { - if(lupnp->sip_tcp->state == LinphoneUpnpStateOk) { - port = lupnp->sip_tcp->external_port; - } - } else if(lupnp->sip_tls != NULL) { - if(lupnp->sip_tls->state == LinphoneUpnpStateOk) { - port = lupnp->sip_tls->external_port; - } - } - - ms_mutex_unlock(&lupnp->mutex); - } - return port; -} - -bool_t linphone_upnp_is_blacklisted(UpnpContext *lupnp) { - const char * device_model_name = upnp_igd_get_device_model_name(lupnp->upnp_igd_ctxt); - const char * device_model_number = upnp_igd_get_device_model_number(lupnp->upnp_igd_ctxt); - const char * blacklist = lp_config_get_string(lupnp->lc->config, "net", "upnp_blacklist", NULL); - bool_t blacklisted = FALSE; - char *str; - char *pch; - char *model_name; - char *model_number; - - // Sanity checks - if(device_model_name == NULL || device_model_number == NULL || blacklist == NULL) { - return FALSE; - } - - // Find in the list - str = strdup(blacklist); - pch = strtok(str, ";"); - while (pch != NULL && !blacklisted) { - // Extract model name & number - model_name = pch; - model_number = strstr(pch, ","); - if(model_number != NULL) { - *(model_number++) = '\0'; - } - - // Compare with current device - if(strcmp(model_name, device_model_name) == 0) { - if(model_number == NULL || strcmp(model_number, device_model_number) == 0) { - blacklisted = TRUE; - } - } - pch = strtok(NULL, ";"); - } - free(str); - - return blacklisted; -} - -void linphone_upnp_refresh(UpnpContext * lupnp) { - upnp_igd_refresh(lupnp->upnp_igd_ctxt); -} - -const char* linphone_upnp_context_get_external_ipaddress(UpnpContext *lupnp) { - const char* addr = NULL; - if(lupnp != NULL) { - ms_mutex_lock(&lupnp->mutex); - addr = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt); - ms_mutex_unlock(&lupnp->mutex); - } - return addr; -} - -int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry) { - upnp_igd_port_mapping mapping; - char description[128]; - int ret; - - if(lupnp->state != LinphoneUpnpStateOk) { - return -2; - } - - // Compute port binding state - if(port->state != LinphoneUpnpStateAdding) { - port->to_remove = FALSE; - switch(port->state) { - case LinphoneUpnpStateKo: - case LinphoneUpnpStateIdle: { - port->retry = 0; - port->state = LinphoneUpnpStateAdding; - } - break; - case LinphoneUpnpStateRemoving: { - port->to_add = TRUE; - return 0; - } - break; - default: - return 0; - } - } - - // No retry if specified - if(port->retry != 0 && !retry) { - return -1; - } - - if(port->retry >= UPNP_ADD_MAX_RETRY) { - ret = -1; - } else { - linphone_upnp_port_binding_set_device_id(port, upnp_igd_get_device_id(lupnp->upnp_igd_ctxt)); - mapping.cookie = linphone_upnp_port_binding_retain(port); - lupnp->pending_bindings = bctbx_list_append(lupnp->pending_bindings, mapping.cookie); - - mapping.local_port = port->local_port; - mapping.local_host = port->local_addr; - if(port->external_port == -1) - port->external_port = rand()%(0xffff - 1024) + 1024; - mapping.remote_port = port->external_port; - mapping.remote_host = ""; - snprintf(description, 128, "%s %s at %s:%d", - "Linphone", - (port->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP": "UDP", - port->local_addr, port->local_port); - mapping.description = description; - mapping.protocol = port->protocol; - - port->retry++; - linphone_upnp_port_binding_log(ORTP_MESSAGE, "Try to add port binding", port); - ret = upnp_igd_add_port_mapping(lupnp->upnp_igd_ctxt, &mapping); - } - if(ret != 0) { - port->state = LinphoneUpnpStateKo; - } - return ret; -} - -int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry) { - upnp_igd_port_mapping mapping; - int ret; - - if(lupnp->state != LinphoneUpnpStateOk) { - return -2; - } - - // Compute port binding state - if(port->state != LinphoneUpnpStateRemoving) { - port->to_add = FALSE; - switch(port->state) { - case LinphoneUpnpStateOk: { - port->retry = 0; - port->state = LinphoneUpnpStateRemoving; - } - break; - case LinphoneUpnpStateAdding: { - port->to_remove = TRUE; - return 0; - } - break; - default: - return 0; - } - } - - // No retry if specified - if(port->retry != 0 && !retry) { - return 1; - } - - if(port->retry >= UPNP_REMOVE_MAX_RETRY) { - ret = -1; - } else { - linphone_upnp_port_binding_set_device_id(port, upnp_igd_get_device_id(lupnp->upnp_igd_ctxt)); - mapping.cookie = linphone_upnp_port_binding_retain(port); - lupnp->pending_bindings = bctbx_list_append(lupnp->pending_bindings, mapping.cookie); - - mapping.remote_port = port->external_port; - mapping.remote_host = ""; - mapping.protocol = port->protocol; - port->retry++; - linphone_upnp_port_binding_log(ORTP_MESSAGE, "Try to remove port binding", port); - ret = upnp_igd_delete_port_mapping(lupnp->upnp_igd_ctxt, &mapping); - } - if(ret != 0) { - port->state = LinphoneUpnpStateKo; - } - return ret; -} - -/* - * uPnP Core interfaces - */ - -int linphone_call_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool_t video) { - LinphoneCore *lc = call->core; - UpnpContext *lupnp = lc->upnp; - int ret = -1; - - if(lupnp == NULL) { - return ret; - } - - ms_mutex_lock(&lupnp->mutex); - - // Don't handle when the call - if(lupnp->state == LinphoneUpnpStateOk && call->upnp_session != NULL) { - ret = 0; - - /* - * Audio part - */ - linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtp, - UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->media_ports[call->main_audio_stream_index].rtp_port:0, UPNP_CALL_RETRY_DELAY); - - linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtcp, - UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->media_ports[call->main_audio_stream_index].rtcp_port:0, UPNP_CALL_RETRY_DELAY); - - /* - * Video part - */ - linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtp, - UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->media_ports[call->main_video_stream_index].rtp_port:0, UPNP_CALL_RETRY_DELAY); - - linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtcp, - UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->media_ports[call->main_video_stream_index].rtcp_port:0, UPNP_CALL_RETRY_DELAY); - } - - ms_mutex_unlock(&lupnp->mutex); - - /* - * Update uPnP call state - */ - linphone_upnp_call_process(call); - - return ret; -} - - - -int linphone_call_update_upnp_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md) { - bool_t audio = FALSE; - bool_t video = FALSE; - int i; - const SalStreamDescription *stream; - - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { - stream = &md->streams[i]; - if (!sal_stream_description_active(stream)) continue; - if(stream->type == SalAudio) { - audio = TRUE; - } else if(stream->type == SalVideo) { - video = TRUE; - } - } - - return linphone_call_update_upnp_audio_video(call, audio, video); -} - -int linphone_call_update_upnp(LinphoneCall *call) { - return linphone_call_update_upnp_audio_video(call, call->audiostream!=NULL, call->videostream!=NULL); -} - -void linphone_call_update_upnp_state_in_call_stats(LinphoneCall *call) { - call->audio_stats->upnp_state = call->upnp_session->audio->state; - call->video_stats->upnp_state = call->upnp_session->video->state; -} - -void linphone_upnp_update_stream_state(UpnpStream *stream) { - if((stream->rtp == NULL || stream->rtp->state == LinphoneUpnpStateOk || stream->rtp->state == LinphoneUpnpStateIdle) && - (stream->rtcp == NULL || stream->rtcp->state == LinphoneUpnpStateOk || stream->rtcp->state == LinphoneUpnpStateIdle)) { - stream->state = LinphoneUpnpStateOk; - } else if((stream->rtp != NULL && - (stream->rtp->state == LinphoneUpnpStateAdding || stream->rtp->state == LinphoneUpnpStateRemoving)) || - (stream->rtcp != NULL && - (stream->rtcp->state == LinphoneUpnpStateAdding || stream->rtcp->state == LinphoneUpnpStateRemoving))) { - stream->state = LinphoneUpnpStatePending; - } else if((stream->rtp != NULL && stream->rtp->state == LinphoneUpnpStateKo) || - (stream->rtcp != NULL && stream->rtcp->state == LinphoneUpnpStateKo)) { - stream->state = LinphoneUpnpStateKo; - } else { - ms_error("Invalid stream %p state", stream); - } -} - -int linphone_upnp_call_process(LinphoneCall *call) { - LinphoneCore *lc = call->core; - UpnpContext *lupnp = lc->upnp; - int ret = -1; - LinphoneUpnpState oldState = 0, newState = 0; - - if(lupnp == NULL) { - return ret; - } - - ms_mutex_lock(&lupnp->mutex); - - // Don't handle when the call - if(lupnp->state == LinphoneUpnpStateOk && call->upnp_session != NULL) { - ret = 0; - - /* - * Update Audio state - */ - linphone_upnp_update_stream_state(call->upnp_session->audio); - - /* - * Update Video state - */ - linphone_upnp_update_stream_state(call->upnp_session->video); - - /* - * Update stat - */ - linphone_call_update_upnp_state_in_call_stats(call); - - /* - * Update session state - */ - oldState = call->upnp_session->state; - if(call->upnp_session->audio->state == LinphoneUpnpStateOk && - call->upnp_session->video->state == LinphoneUpnpStateOk) { - call->upnp_session->state = LinphoneUpnpStateOk; - } else if(call->upnp_session->audio->state == LinphoneUpnpStatePending || - call->upnp_session->video->state == LinphoneUpnpStatePending) { - call->upnp_session->state = LinphoneUpnpStatePending; - } else if(call->upnp_session->audio->state == LinphoneUpnpStateKo || - call->upnp_session->video->state == LinphoneUpnpStateKo) { - call->upnp_session->state = LinphoneUpnpStateKo; - } else { - call->upnp_session->state = LinphoneUpnpStateIdle; - } - newState = call->upnp_session->state; - } - - ms_mutex_unlock(&lupnp->mutex); - - /* When change is done proceed update */ - if(oldState != LinphoneUpnpStateOk && oldState != LinphoneUpnpStateKo && - (newState == LinphoneUpnpStateOk || newState == LinphoneUpnpStateKo)) { - if(call->upnp_session->state == LinphoneUpnpStateOk) - ms_message("uPnP IGD: uPnP for Call %p is ok", call); - else - ms_message("uPnP IGD: uPnP for Call %p is ko", call); - - switch (call->state) { - case LinphoneCallUpdating: - linphone_call_start_update(call); - break; - case LinphoneCallUpdatedByRemote: - linphone_call_start_accept_update(call, call->prevstate, linphone_call_state_to_string(call->prevstate)); - break; - case LinphoneCallOutgoingInit: - linphone_call_proceed_with_invite_if_ready(call, NULL); - break; - case LinphoneCallIdle: - linphone_call_update_local_media_description_from_ice_or_upnp(call); - sal_call_set_local_media_description(call->op,call->localdesc); - linphone_core_notify_incoming_call(lc, call); - break; - default: - break; - } - } - - return ret; -} - -static const char *linphone_core_upnp_get_charptr_null(const char *str) { - if(str != NULL) { - return str; - } - return "(Null)"; -} - -void linphone_upnp_update(UpnpContext *lupnp) { - bctbx_list_t *global_list = NULL; - bctbx_list_t *list = NULL; - bctbx_list_t *item; - LinphoneCall *call; - UpnpPortBinding *port_mapping, *port_mapping2; - - ms_message("uPnP IGD: Name:%s", linphone_core_upnp_get_charptr_null(upnp_igd_get_device_name(lupnp->upnp_igd_ctxt))); - ms_message("uPnP IGD: Device:%s %s", - linphone_core_upnp_get_charptr_null(upnp_igd_get_device_model_name(lupnp->upnp_igd_ctxt)), - linphone_core_upnp_get_charptr_null(upnp_igd_get_device_model_number(lupnp->upnp_igd_ctxt))); - ms_message("uPnP IGD: Refresh mappings"); - - if(lupnp->sip_udp != NULL) { - global_list = bctbx_list_append(global_list, lupnp->sip_udp); - } - if(lupnp->sip_tcp != NULL) { - global_list = bctbx_list_append(global_list, lupnp->sip_tcp); - } - if(lupnp->sip_tls != NULL) { - global_list = bctbx_list_append(global_list, lupnp->sip_tls); - } - - list = lupnp->lc->calls; - while(list != NULL) { - call = (LinphoneCall *)list->data; - if(call->upnp_session != NULL) { - if(call->upnp_session->audio->rtp != NULL) { - global_list = bctbx_list_append(global_list, call->upnp_session->audio->rtp); - } - if(call->upnp_session->audio->rtcp != NULL) { - global_list = bctbx_list_append(global_list, call->upnp_session->audio->rtcp); - } - if(call->upnp_session->video->rtp != NULL) { - global_list = bctbx_list_append(global_list, call->upnp_session->video->rtp); - } - if(call->upnp_session->video->rtcp != NULL) { - global_list = bctbx_list_append(global_list, call->upnp_session->video->rtcp); - } - } - list = list->next; - } - - list = linphone_upnp_config_list_port_bindings(lupnp->lc->config, upnp_igd_get_device_id(lupnp->upnp_igd_ctxt)); - for(item = list;item != NULL; item = item->next) { - port_mapping = (UpnpPortBinding *)item->data; - port_mapping2 = linphone_upnp_port_binding_equivalent_in_list(global_list, port_mapping); - if(port_mapping2 == NULL) { - linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping, TRUE); - } else if(port_mapping2->state == LinphoneUpnpStateIdle){ - /* Force to remove */ - port_mapping2->state = LinphoneUpnpStateOk; - } - } - bctbx_list_for_each(list, (void (*)(void*))linphone_upnp_port_binding_release); - list = bctbx_list_free(list); - - - // (Re)Add removed port bindings - list = global_list; - while(list != NULL) { - port_mapping = (UpnpPortBinding *)list->data; - linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping, TRUE); - linphone_upnp_context_send_add_port_binding(lupnp, port_mapping, TRUE); - list = list->next; - } - global_list = bctbx_list_free(global_list); -} - -void linphone_upnp_update_port_binding(UpnpContext *lupnp, UpnpPortBinding **port_mapping, upnp_igd_ip_protocol protocol, int port, int retry_delay) { - const char *local_addr, *external_addr; - time_t now = time(NULL); - if(port != 0) { - if(*port_mapping != NULL) { - if(port != (*port_mapping)->local_port) { - linphone_upnp_context_send_remove_port_binding(lupnp, *port_mapping, FALSE); - *port_mapping = NULL; - } - } - if(*port_mapping == NULL) { - *port_mapping = linphone_upnp_port_binding_new_or_collect(lupnp->pending_bindings, protocol, port, port); - } - - // Get addresses - local_addr = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt); - external_addr = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt); - - // Force binding update on local address change - if(local_addr != NULL) { - if(strncmp((*port_mapping)->local_addr, local_addr, sizeof((*port_mapping)->local_addr))) { - linphone_upnp_context_send_remove_port_binding(lupnp, *port_mapping, FALSE); - strncpy((*port_mapping)->local_addr, local_addr, sizeof((*port_mapping)->local_addr)); - } - } - if(external_addr != NULL) { - strncpy((*port_mapping)->external_addr, external_addr, sizeof((*port_mapping)->external_addr)); - } - - // Add (if not already done) the binding - if(now - (*port_mapping)->last_update >= retry_delay) { - (*port_mapping)->last_update = now; - linphone_upnp_context_send_add_port_binding(lupnp, *port_mapping, FALSE); - } - } else { - if(*port_mapping != NULL) { - linphone_upnp_context_send_remove_port_binding(lupnp, *port_mapping, FALSE); - *port_mapping = NULL; - } - } -} - -void linphone_upnp_update_config(UpnpContext* lupnp) { - char key[64]; - const bctbx_list_t *item; - UpnpPortBinding *port_mapping; - - /* Add configs */ - for(item = lupnp->adding_configs;item!=NULL;item=item->next) { - port_mapping = (UpnpPortBinding *)item->data; - snprintf(key, sizeof(key), "%s-%s-%d-%d", - port_mapping->device_id, - (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", - port_mapping->external_port, - port_mapping->local_port); - lp_config_set_string(lupnp->lc->config, UPNP_SECTION_NAME, key, "uPnP"); - linphone_upnp_port_binding_log(ORTP_DEBUG, "Configuration: Added port binding", port_mapping); - } - bctbx_list_for_each(lupnp->adding_configs,(void (*)(void*))linphone_upnp_port_binding_release); - lupnp->adding_configs = bctbx_list_free(lupnp->adding_configs); - - /* Remove configs */ - for(item = lupnp->removing_configs;item!=NULL;item=item->next) { - port_mapping = (UpnpPortBinding *)item->data; - snprintf(key, sizeof(key), "%s-%s-%d-%d", - port_mapping->device_id, - (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", - port_mapping->external_port, - port_mapping->local_port); - lp_config_set_string(lupnp->lc->config, UPNP_SECTION_NAME, key, NULL); - linphone_upnp_port_binding_log(ORTP_DEBUG, "Configuration: Removed port binding", port_mapping); - } - bctbx_list_for_each(lupnp->removing_configs,(void (*)(void*))linphone_upnp_port_binding_release); - lupnp->removing_configs = bctbx_list_free(lupnp->removing_configs); -} - -void linphone_upnp_update_proxy(UpnpContext* lupnp, bool_t force) { - LinphoneUpnpState ready_state; - const bctbx_list_t *item; - time_t now = (force)? (lupnp->last_ready_check + UPNP_CORE_READY_CHECK) : time(NULL); - - /* Refresh registers if we are ready */ - if(now - lupnp->last_ready_check >= UPNP_CORE_READY_CHECK) { - lupnp->last_ready_check = now; - ready_state = (_linphone_upnp_context_is_ready_for_register(lupnp))? LinphoneUpnpStateOk: LinphoneUpnpStateKo; - if(ready_state != lupnp->last_ready_state) { - for(item=linphone_core_get_proxy_config_list(lupnp->lc);item!=NULL;item=item->next) { - LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)item->data; - if (linphone_proxy_config_register_enabled(cfg)) { - if (ready_state != LinphoneUpnpStateOk) { - // Only reset ithe registration if we require that upnp should be ok - if(lupnp->lc->sip_conf.register_only_when_upnp_is_ok) { - linphone_proxy_config_set_state(cfg, LinphoneRegistrationNone, "Registration impossible (uPnP not ready)"); - } else { - cfg->commit=TRUE; - } - } else { - cfg->commit=TRUE; - } - } - } - lupnp->last_ready_state = ready_state; - } - } -} - -bool_t linphone_core_upnp_hook(void *data) { - LCSipTransports transport; - UpnpContext *lupnp = (UpnpContext *)data; - - ms_mutex_lock(&lupnp->mutex); - - /* Update ports */ - if(lupnp->state == LinphoneUpnpStateOk) { - linphone_core_get_sip_transports(lupnp->lc, &transport); - linphone_upnp_update_port_binding(lupnp, &lupnp->sip_udp, UPNP_IGD_IP_PROTOCOL_UDP, transport.udp_port, UPNP_CORE_RETRY_DELAY); - linphone_upnp_update_port_binding(lupnp, &lupnp->sip_tcp, UPNP_IGD_IP_PROTOCOL_TCP, transport.tcp_port, UPNP_CORE_RETRY_DELAY); - linphone_upnp_update_port_binding(lupnp, &lupnp->sip_tls, UPNP_IGD_IP_PROTOCOL_TCP, transport.tls_port, UPNP_CORE_RETRY_DELAY); - } - - linphone_upnp_update_proxy(lupnp, FALSE); - linphone_upnp_update_config(lupnp); - - ms_mutex_unlock(&lupnp->mutex); - return TRUE; -} - -int linphone_call_update_local_media_description_from_upnp(SalMediaDescription *desc, UpnpSession *session) { - int i; - SalStreamDescription *stream; - UpnpStream *upnpStream; - - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { - stream = &desc->streams[i]; - if (!sal_stream_description_active(stream)) continue; - upnpStream = NULL; - if(stream->type == SalAudio) { - upnpStream = session->audio; - } else if(stream->type == SalVideo) { - upnpStream = session->video; - } - if(upnpStream != NULL) { - if(upnpStream->rtp != NULL && upnpStream->rtp->state == LinphoneUpnpStateOk) { - strncpy(stream->rtp_addr, upnpStream->rtp->external_addr, LINPHONE_IPADDR_SIZE); - stream->rtp_port = upnpStream->rtp->external_port; - } - if(upnpStream->rtcp != NULL && upnpStream->rtcp->state == LinphoneUpnpStateOk) { - strncpy(stream->rtcp_addr, upnpStream->rtcp->external_addr, LINPHONE_IPADDR_SIZE); - stream->rtcp_port = upnpStream->rtcp->external_port; - } - } - } - return 0; -} - - -/* - * uPnP Port Binding - */ - -UpnpPortBinding *linphone_upnp_port_binding_new(void) { - UpnpPortBinding *port = NULL; - port = ms_new0(UpnpPortBinding,1); - ms_mutex_init(&port->mutex, NULL); - port->state = LinphoneUpnpStateIdle; - port->protocol = UPNP_IGD_IP_PROTOCOL_UDP; - port->device_id = NULL; - port->local_addr[0] = '\0'; - port->local_port = -1; - port->external_addr[0] = '\0'; - port->external_port = -1; - port->to_remove = FALSE; - port->to_add = FALSE; - port->ref = 1; - port->last_update = 0; - return port; -} - -UpnpPortBinding *linphone_upnp_port_binding_new_with_parameters(upnp_igd_ip_protocol protocol, int local_port, int external_port) { - UpnpPortBinding *port_binding = linphone_upnp_port_binding_new(); - port_binding->protocol = protocol; - port_binding->local_port = local_port; - port_binding->external_port = external_port; - return port_binding; -} - -UpnpPortBinding *linphone_upnp_port_binding_new_or_collect(bctbx_list_t *list, upnp_igd_ip_protocol protocol, int local_port, int external_port) { - UpnpPortBinding *tmp_binding; - UpnpPortBinding *end_binding; - - // Seek an binding with same protocol and local port - end_binding = linphone_upnp_port_binding_new_with_parameters(protocol, local_port, -1); - tmp_binding = linphone_upnp_port_binding_equivalent_in_list(list, end_binding); - - // Must be not attached to any struct - if(tmp_binding != NULL && tmp_binding->ref == 1) { - linphone_upnp_port_binding_release(end_binding); - end_binding = linphone_upnp_port_binding_retain(tmp_binding); - } else { - end_binding->external_port = external_port; - } - return end_binding; -} - -UpnpPortBinding *linphone_upnp_port_binding_copy(const UpnpPortBinding *port) { - UpnpPortBinding *new_port = NULL; - new_port = ms_new0(UpnpPortBinding,1); - memcpy(new_port, port, sizeof(UpnpPortBinding)); - new_port->device_id = NULL; - linphone_upnp_port_binding_set_device_id(new_port, port->device_id); - ms_mutex_init(&new_port->mutex, NULL); - new_port->ref = 1; - return new_port; -} - -void linphone_upnp_port_binding_set_device_id(UpnpPortBinding *port, const char *device_id) { - char *formated_device_id = linphone_upnp_format_device_id(device_id); - if(formated_device_id != NULL && port->device_id != NULL) { - if(strcmp(formated_device_id, port->device_id) == 0) { - ms_free(formated_device_id); - return; - } - } - if(port->device_id != NULL) { - ms_free(port->device_id); - } - port->device_id = formated_device_id; -} - -void linphone_upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *port) { - if(strlen(port->local_addr)) { - ortp_log(level, "uPnP IGD: %s %s|%d->%s:%d (retry %d)", msg, - (port->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", - port->external_port, - port->local_addr, - port->local_port, - port->retry - 1); - } else { - ortp_log(level, "uPnP IGD: %s %s|%d->%d (retry %d)", msg, - (port->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", - port->external_port, - port->local_port, - port->retry - 1); - } -} - -// Return true if the binding are equivalent. (Note external_port == -1 means "don't care") -bool_t linphone_upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2) { - return port1->protocol == port2->protocol && - port1->local_port == port2->local_port && - (port1->external_port == -1 || port2->external_port == -1 || port1->external_port == port2->external_port); -} - -UpnpPortBinding *linphone_upnp_port_binding_equivalent_in_list(bctbx_list_t *list, const UpnpPortBinding *port) { - UpnpPortBinding *port_mapping; - while(list != NULL) { - port_mapping = (UpnpPortBinding *)list->data; - if(linphone_upnp_port_binding_equal(port, port_mapping)) { - return port_mapping; - } - list = list->next; - } - - return NULL; -} - -UpnpPortBinding *linphone_upnp_port_binding_retain(UpnpPortBinding *port) { - ms_mutex_lock(&port->mutex); - port->ref++; - ms_mutex_unlock(&port->mutex); - return port; -} - -void linphone_upnp_port_binding_release(UpnpPortBinding *port) { - ms_mutex_lock(&port->mutex); - if(--port->ref == 0) { - if(port->device_id != NULL) { - ms_free(port->device_id); - } - ms_mutex_unlock(&port->mutex); - ms_mutex_destroy(&port->mutex); - ms_free(port); - return; - } - ms_mutex_unlock(&port->mutex); -} - - -/* - * uPnP Stream - */ - -UpnpStream* linphone_upnp_stream_new(void) { - UpnpStream *stream = ms_new0(UpnpStream,1); - stream->state = LinphoneUpnpStateIdle; - stream->rtp = NULL; - stream->rtcp = NULL; - return stream; -} - -void linphone_upnp_stream_destroy(UpnpStream* stream) { - if(stream->rtp != NULL) { - linphone_upnp_port_binding_release(stream->rtp); - stream->rtp = NULL; - } - if(stream->rtcp != NULL) { - linphone_upnp_port_binding_release(stream->rtcp); - stream->rtcp = NULL; - } - ms_free(stream); -} - - -/* - * uPnP Session - */ - -UpnpSession* linphone_upnp_session_new(LinphoneCall* call) { - UpnpSession *session = ms_new0(UpnpSession,1); - session->call = call; - session->state = LinphoneUpnpStateIdle; - session->audio = linphone_upnp_stream_new(); - session->video = linphone_upnp_stream_new(); - return session; -} - -void linphone_upnp_session_destroy(UpnpSession *session) { - LinphoneCore *lc = session->call->core; - - if(lc->upnp != NULL) { - /* Remove bindings */ - if(session->audio->rtp != NULL) { - linphone_upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtp, TRUE); - } - if(session->audio->rtcp != NULL) { - linphone_upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtcp, TRUE); - } - if(session->video->rtp != NULL) { - linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtp, TRUE); - } - if(session->video->rtcp != NULL) { - linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtcp, TRUE); - } - } - - session->call->audio_stats->upnp_state = LinphoneUpnpStateKo; - session->call->video_stats->upnp_state = LinphoneUpnpStateKo; - - linphone_upnp_stream_destroy(session->audio); - linphone_upnp_stream_destroy(session->video); - ms_free(session); -} - -LinphoneUpnpState linphone_upnp_session_get_state(UpnpSession *session) { - return session->state; -} - - -/* - * uPnP Config - */ - -struct linphone_upnp_config_list_port_bindings_struct { - struct _LpConfig *lpc; - bctbx_list_t *retList; - const char *device_id; -}; - -static void linphone_upnp_config_list_port_bindings_cb(const char *entry, struct linphone_upnp_config_list_port_bindings_struct *cookie) { - char device_id[UPNP_UUID_LEN + 1]; - char protocol_str[4]; // TCP or UDP - upnp_igd_ip_protocol protocol; - int external_port; - int local_port; - int ret; - bool_t valid = TRUE; - UpnpPortBinding *port; - - ret = sscanf(entry, "%"UPNP_UUID_LEN_STR"[^-]-%3s-%i-%i", device_id, protocol_str, &external_port, &local_port); - if(ret == 4) { - // Handle only wanted device bindings - if(device_id != NULL && strcmp(cookie->device_id, device_id) != 0) { - return; - } - if(linphone_upnp_strncmpi(protocol_str, "TCP", 3) == 0) { - protocol = UPNP_IGD_IP_PROTOCOL_TCP; - } else if(linphone_upnp_strncmpi(protocol_str, "UDP", 3) == 0) { - protocol = UPNP_IGD_IP_PROTOCOL_UDP; - } else { - valid = FALSE; - } - if(valid) { - port = linphone_upnp_port_binding_new(); - linphone_upnp_port_binding_set_device_id(port, device_id); - port->state = LinphoneUpnpStateOk; - port->protocol = protocol; - port->external_port = external_port; - port->local_port = local_port; - cookie->retList = bctbx_list_append(cookie->retList, port); - } - } else { - valid = FALSE; - } - if(!valid) { - ms_warning("uPnP configuration invalid line: %s", entry); - } -} - -bctbx_list_t *linphone_upnp_config_list_port_bindings(struct _LpConfig *lpc, const char *device_id) { - char *formated_device_id = linphone_upnp_format_device_id(device_id); - struct linphone_upnp_config_list_port_bindings_struct cookie = {lpc, NULL, formated_device_id}; - lp_config_for_each_entry(lpc, UPNP_SECTION_NAME, (void(*)(const char *, void*))linphone_upnp_config_list_port_bindings_cb, &cookie); - ms_free(formated_device_id); - return cookie.retList; -} - -void linphone_upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port) { - bctbx_list_t *list; - UpnpPortBinding *list_port; - - if(port->device_id == NULL) { - ms_error("Can't remove port binding without device_id"); - return; - } - - list = lupnp->removing_configs; - while(list != NULL) { - list_port = (UpnpPortBinding *)list->data; - if(linphone_upnp_port_binding_equal(list_port, port) == TRUE) { - lupnp->removing_configs = bctbx_list_remove(lupnp->removing_configs, list_port); - linphone_upnp_port_binding_release(list_port); - return; - } - list = bctbx_list_next(list); - } - - list = lupnp->adding_configs; - while(list != NULL) { - list_port = (UpnpPortBinding *)list->data; - if(linphone_upnp_port_binding_equal(list_port, port) == TRUE) { - return; - } - list = bctbx_list_next(list); - } - - list_port = linphone_upnp_port_binding_copy(port); - lupnp->adding_configs = bctbx_list_append(lupnp->adding_configs, list_port); -} - -void linphone_upnp_config_remove_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port) { - bctbx_list_t *list; - UpnpPortBinding *list_port; - - if(port->device_id == NULL) { - ms_error("Can't remove port binding without device_id"); - return; - } - - list = lupnp->adding_configs; - while(list != NULL) { - list_port = (UpnpPortBinding *)list->data; - if(linphone_upnp_port_binding_equal(list_port, port) == TRUE) { - lupnp->adding_configs = bctbx_list_remove(lupnp->adding_configs, list_port); - linphone_upnp_port_binding_release(list_port); - return; - } - list = bctbx_list_next(list); - } - - list = lupnp->removing_configs; - while(list != NULL) { - list_port = (UpnpPortBinding *)list->data; - if(linphone_upnp_port_binding_equal(list_port, port) == TRUE) { - return; - } - list = bctbx_list_next(list); - } - - list_port = linphone_upnp_port_binding_copy(port); - lupnp->removing_configs = bctbx_list_append(lupnp->removing_configs, list_port); -} diff --git a/coreapi/upnp.h b/coreapi/upnp.h deleted file mode 100644 index a8abeb16b..000000000 --- a/coreapi/upnp.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -linphone -Copyright (C) 2012 Belledonne Communications SARL - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef LINPHONE_UPNP_H -#define LINPHONE_UPNP_H - -#include "mediastreamer2/upnp_igd.h" -#include "linphone/core.h" -#include "sal/sal.h" - -typedef struct _UpnpSession UpnpSession; -typedef struct _UpnpContext UpnpContext; - -int linphone_call_update_local_media_description_from_upnp(SalMediaDescription *desc, UpnpSession *session); -int linphone_call_update_upnp_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md); -int linphone_call_update_upnp(LinphoneCall *call); - -int linphone_upnp_call_process(LinphoneCall *call); -UpnpSession* linphone_upnp_session_new(LinphoneCall *call); -void linphone_upnp_session_destroy(UpnpSession* session); -LinphoneUpnpState linphone_upnp_session_get_state(UpnpSession *session); - -UpnpContext *linphone_upnp_context_new(LinphoneCore *lc); -void linphone_upnp_context_destroy(UpnpContext *ctx); -void linphone_upnp_refresh(UpnpContext *ctx); -LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *ctx); -const char *linphone_upnp_context_get_external_ipaddress(UpnpContext *ctx); -int linphone_upnp_context_get_external_port(UpnpContext *ctx); -bool_t linphone_upnp_context_is_ready_for_register(UpnpContext *ctx); -void linphone_call_update_upnp_state_in_call_stats(LinphoneCall *call); - -#endif //LINPHONE_UPNP_H diff --git a/daemon/commands/jitterbuffer.cc b/daemon/commands/jitterbuffer.cc index 335f7bdb2..99dee451b 100644 --- a/daemon/commands/jitterbuffer.cc +++ b/daemon/commands/jitterbuffer.cc @@ -124,9 +124,11 @@ void JitterBufferResetCommand::exec(Daemon *app, const string& args) { } istr >> streamtype; if (streamtype == "video") { - rtprecv = call->videostream ? call->videostream->ms.rtprecv : NULL; + VideoStream *vstream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeVideo)); + rtprecv = vstream ? vstream->ms.rtprecv : NULL; } else { - rtprecv = call->audiostream ? call->audiostream->ms.rtprecv : NULL; + AudioStream *astream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeAudio)); + rtprecv = astream ? astream->ms.rtprecv : NULL; } } else { AudioStream *stream = app->findAudioStream(arg2); diff --git a/daemon/commands/msfilter-add-fmtp.cc b/daemon/commands/msfilter-add-fmtp.cc index afce5a513..d9aba9e55 100644 --- a/daemon/commands/msfilter-add-fmtp.cc +++ b/daemon/commands/msfilter-add-fmtp.cc @@ -54,11 +54,12 @@ void MSFilterAddFmtpCommand::exec(Daemon *app, const string& args) { app->sendResponse(Response("No Call with such id.")); return; } - if (call->audiostream == NULL || call->audiostream->ms.encoder == NULL) { + AudioStream *astream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeAudio)); + if (astream == NULL || astream->ms.encoder == NULL) { app->sendResponse(Response("This call doesn't have an active audio stream.")); return; } - ms_filter_call_method(call->audiostream->ms.encoder, MS_FILTER_ADD_FMTP, (void *)fmtp.c_str()); + ms_filter_call_method(astream->ms.encoder, MS_FILTER_ADD_FMTP, (void *)fmtp.c_str()); } else if (type.compare("stream") == 0) { AudioStream *stream = app->findAudioStream(id); if (stream == NULL) { diff --git a/include/linphone/call.h b/include/linphone/call.h index ffa4b8261..94ffd09c1 100644 --- a/include/linphone/call.h +++ b/include/linphone/call.h @@ -28,10 +28,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * @{ */ -/** Callback prototype */ -typedef void (*LinphoneCallCbFunc)(LinphoneCall *call, void *user_data); - - #ifdef __cplusplus extern "C" { #endif @@ -245,7 +241,7 @@ LINPHONE_PUBLIC const char * linphone_call_get_authentication_token(LinphoneCall * @param call the LinphoneCall * @return TRUE if authentication token is verifed, false otherwise. **/ -LINPHONE_PUBLIC bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call); +LINPHONE_PUBLIC bool_t linphone_call_get_authentication_token_verified(const LinphoneCall *call); /** * Set the result of ZRTP short code verification by user. @@ -345,7 +341,7 @@ LINPHONE_PUBLIC void linphone_call_set_audio_route(LinphoneCall *call, LinphoneA * @param call * @return 2 **/ -LINPHONE_PUBLIC int linphone_call_get_stream_count(LinphoneCall *call); +LINPHONE_PUBLIC int linphone_call_get_stream_count(const LinphoneCall *call); /** * Returns the type of stream for the given stream index. @@ -353,7 +349,7 @@ LINPHONE_PUBLIC int linphone_call_get_stream_count(LinphoneCall *call); * @param stream_index * @return the type (MSAudio, MSVideo, MSText) of the stream of given index. **/ -LINPHONE_PUBLIC MSFormatType linphone_call_get_stream_type(LinphoneCall *call, int stream_index); +LINPHONE_PUBLIC MSFormatType linphone_call_get_stream_type(const LinphoneCall *call, int stream_index); /** * Returns the meta rtp transport for the given stream index. @@ -361,7 +357,7 @@ LINPHONE_PUBLIC MSFormatType linphone_call_get_stream_type(LinphoneCall *call, i * @param stream_index * @return a pointer to the meta rtp transport if it exists, NULL otherwise **/ -LINPHONE_PUBLIC RtpTransport * linphone_call_get_meta_rtp_transport(LinphoneCall *call, int stream_index); +LINPHONE_PUBLIC RtpTransport * linphone_call_get_meta_rtp_transport(const LinphoneCall *call, int stream_index); /** * Returns the meta rtcp transport for the given stream index. @@ -369,7 +365,7 @@ LINPHONE_PUBLIC RtpTransport * linphone_call_get_meta_rtp_transport(LinphoneCall * @param stream_index * @return a pointer to the meta rtcp transport if it exists, NULL otherwise **/ -LINPHONE_PUBLIC RtpTransport * linphone_call_get_meta_rtcp_transport(LinphoneCall *call, int stream_index); +LINPHONE_PUBLIC RtpTransport * linphone_call_get_meta_rtcp_transport(const LinphoneCall *call, int stream_index); /** * Pauses the call. If a music file has been setup using linphone_core_set_play_file(), @@ -715,7 +711,7 @@ LINPHONE_PUBLIC void linphone_call_enable_echo_cancellation(LinphoneCall *call, /** * Returns TRUE if echo cancellation is enabled. **/ -LINPHONE_PUBLIC bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *lc); +LINPHONE_PUBLIC bool_t linphone_call_echo_cancellation_enabled(const LinphoneCall *call); /** * Enables or disable echo limiter for this call @@ -751,14 +747,14 @@ LINPHONE_PUBLIC LinphoneChatRoom * linphone_call_get_chat_room(LinphoneCall *cal * @param call The call. * @return float Volume level in percentage. */ -LINPHONE_PUBLIC float linphone_call_get_play_volume(LinphoneCall *call); +LINPHONE_PUBLIC float linphone_call_get_play_volume(const LinphoneCall *call); /** * Get the mesured record volume level (sent to remote) in dbm0. * @param call The call. * @return float Volume level in percentage. */ -LINPHONE_PUBLIC float linphone_call_get_record_volume(LinphoneCall *call); +LINPHONE_PUBLIC float linphone_call_get_record_volume(const LinphoneCall *call); /** * Get speaker volume gain. @@ -813,14 +809,14 @@ LINPHONE_PUBLIC void linphone_call_set_microphone_volume_gain(LinphoneCall *call * @return The function returns -1 if no quality measurement is available, for example if no * active audio stream exist. Otherwise it returns the quality rating. **/ -LINPHONE_PUBLIC float linphone_call_get_current_quality(LinphoneCall *call); +LINPHONE_PUBLIC float linphone_call_get_current_quality(const LinphoneCall *call); /** * Returns call quality averaged over all the duration of the call. * * See linphone_call_get_current_quality() for more details about quality measurement. **/ -LINPHONE_PUBLIC float linphone_call_get_average_quality(LinphoneCall *call); +LINPHONE_PUBLIC float linphone_call_get_average_quality(const LinphoneCall *call); /** * Start call recording. @@ -849,7 +845,7 @@ LINPHONE_PUBLIC LinphonePlayer * linphone_call_get_player(LinphoneCall *call); * @param call the call * @return TRUE if media is busy in establishing the connection, FALSE otherwise. **/ -LINPHONE_PUBLIC bool_t linphone_call_media_in_progress(LinphoneCall *call); +LINPHONE_PUBLIC bool_t linphone_call_media_in_progress(const LinphoneCall *call); /** * Call generic OpenGL render for a given call. diff --git a/include/linphone/core.h b/include/linphone/core.h index 17c9e9103..9033527a7 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -4680,6 +4680,8 @@ LINPHONE_PUBLIC const char * linphone_core_get_video_preset(const LinphoneCore * */ LINPHONE_PUBLIC bool_t linphone_core_realtime_text_enabled(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_enable_realtime_text(LinphoneCore *lc, bool_t value); + /** * Set http proxy address to be used for signaling during next channel connection. Use #linphone_core_set_network_reachable FASLE/TRUE to force channel restart. * @param[in] lc LinphoneCore object diff --git a/include/linphone/types.h b/include/linphone/types.h index f8a0a7271..b35a02ccc 100644 --- a/include/linphone/types.h +++ b/include/linphone/types.h @@ -257,6 +257,9 @@ typedef struct _LinphoneCall LinphoneCall; */ typedef struct _LinphoneCallCbs LinphoneCallCbs; +/** Callback prototype */ +typedef void (*LinphoneCallCbFunc)(LinphoneCall *call, void *user_data); + /** * Enum representing the direction of a call. * @ingroup call_logs diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0a895b87e..84529f6ce 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,10 +23,15 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES address/address-p.h address/address.h + c-wrapper/c-private-types.h c-wrapper/c-tools.h call/call.h + call/call-listener.h + call/call-p.h chat/chat-room-p.h chat/chat-room.h + chat/imdn.h + chat/is-composing.h conference/conference.h conference/conference-listener.h conference/conference-p.h @@ -36,14 +41,15 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES conference/params/media-session-params.h conference/params/media-session-params-p.h conference/participant.h + conference/participant-p.h conference/remote-conference.h conference/session/call-session.h + conference/session/call-session-listener.h conference/session/call-session-p.h conference/session/media-session.h + conference/session/port-config.h content/content.h core/core.h - chat/imdn.h - chat/is-composing.h cpim/cpim.h cpim/header/cpim-core-headers.h cpim/header/cpim-generic-header.h @@ -68,12 +74,15 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES event-log/message-event.h logger/logger.h message/message.h + nat/ice-agent.h + nat/stun-client.h object/clonable-object-p.h object/clonable-object.h object/object-p.h object/object.h object/singleton.h utils/content-type.h + utils/payload-type-handler.h ) set(LINPHONE_CXX_OBJECTS_SOURCE_FILES @@ -111,10 +120,13 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES event-log/message-event.cpp logger/logger.cpp message/message.cpp + nat/ice-agent.cpp + nat/stun-client.cpp object/clonable-object.cpp object/object.cpp utils/content-type.cpp utils/general.cpp + utils/payload-type-handler.cpp utils/utils.cpp ) diff --git a/src/c-wrapper/c-private-types.h b/src/c-wrapper/c-private-types.h new file mode 100644 index 000000000..bf84e1db1 --- /dev/null +++ b/src/c-wrapper/c-private-types.h @@ -0,0 +1,46 @@ +/* + * c-private-types.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _C_PRIVATE_TYPES_H_ +#define _C_PRIVATE_TYPES_H_ + +#include + +#include "conference/params/media-session-params.h" + +// ============================================================================= + +#ifdef __cplusplus + extern "C" { +#endif + +// ============================================================================= +// C Structures. +// ============================================================================= + +struct _LinphoneCallParams{ + belle_sip_object_t base; + void *user_data; + std::shared_ptr msp; +}; + +#ifdef __cplusplus + } +#endif + +#endif // ifndef _C_PRIVATE_TYPES_H_ diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index 9d8975fb8..ec4969c14 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -59,6 +59,12 @@ public: return static_cast *>(object)->cppPtr; } + template + static inline void setCppPtrFromC (void *object, std::shared_ptr &cppPtr) { + L_ASSERT(object); + static_cast *>(object)->cppPtr = cppPtr; + } + private: Wrapper (); @@ -108,6 +114,9 @@ LINPHONE_END_NAMESPACE #define L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, TYPE) \ LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC(OBJECT) +#define L_SET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_PTR) \ + LINPHONE_NAMESPACE::Wrapper::setCppPtrFromC(OBJECT, CPP_PTR) + #define L_GET_PRIVATE(OBJECT) \ LINPHONE_NAMESPACE::Wrapper::getPrivate(OBJECT) diff --git a/src/call/call-listener.h b/src/call/call-listener.h new file mode 100644 index 000000000..8e7d36bdd --- /dev/null +++ b/src/call/call-listener.h @@ -0,0 +1,52 @@ +/* + * call-listener.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CALL_LISTENER_H_ +#define _CALL_LISTENER_H_ + +#include + +#include "linphone/types.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class CallListener { +public: + virtual void ackBeingSent (LinphoneHeaders *headers) = 0; + virtual void ackReceived (LinphoneHeaders *headers) = 0; + virtual void callSetReleased () = 0; + virtual void callSetTerminated () = 0; + virtual void callStateChanged (LinphoneCallState state, const std::string &message) = 0; + virtual void incomingCallStarted () = 0; + virtual void incomingCallToBeAdded () = 0; + + virtual void encryptionChanged (bool activated, const std::string &authToken) = 0; + + virtual void statsUpdated (const LinphoneCallStats *stats) = 0; + + virtual void setCurrentCall () = 0; + + virtual void firstVideoFrameDecoded () = 0; + virtual void resetFirstVideoFrameDecoded () = 0; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CALL_LISTENER_H_ diff --git a/src/call/call-p.h b/src/call/call-p.h new file mode 100644 index 000000000..682b545c2 --- /dev/null +++ b/src/call/call-p.h @@ -0,0 +1,90 @@ +/* + * call-p.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CALL_P_H_ +#define _CALL_P_H_ + +#include + +#include "object/object-p.h" + +#include "call.h" +#include "conference/conference.h" + +#include "private.h" + +// ============================================================================= + +extern std::shared_ptr linphone_call_get_cpp_obj(const LinphoneCall *call); + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class CallPrivate : public ObjectPrivate, CallListener { +public: + CallPrivate (LinphoneCall *call, LinphoneCore *core, LinphoneCallDir direction, const Address &from, const Address &to, + LinphoneProxyConfig *cfg, SalOp *op, const std::shared_ptr msp); + virtual ~CallPrivate (); + + void initiateIncoming (); + bool initiateOutgoing (); + void iterate (time_t currentRealTime, bool oneSecondElapsed); + void startIncomingNotification (); + int startInvite (const Address *destination); /* If destination is nullptr, it is taken from the call log */ + + std::shared_ptr getActiveSession () const; + bool getAudioMuted () const; + Conference * getConference () const { return conference; } + LinphoneProxyConfig * getDestProxy () const; + IceSession * getIceSession () const; + MediaStream * getMediaStream (LinphoneStreamType type) const; + SalOp * getOp () const; + void setAudioMuted (bool value); + + void ackBeingSent (LinphoneHeaders *headers); + void ackReceived (LinphoneHeaders *headers); + void callSetReleased (); + void callSetTerminated (); + void callStateChanged (LinphoneCallState state, const std::string &message); + void incomingCallStarted (); + void incomingCallToBeAdded (); + + void encryptionChanged (bool activated, const std::string &authToken); + + void statsUpdated (const LinphoneCallStats *stats); + + void setCurrentCall (); + + void firstVideoFrameDecoded (); + void resetFirstVideoFrameDecoded (); + +private: + LinphoneCall *lcall = nullptr; + + LinphoneCore *core = nullptr; + Conference *conference = nullptr; + + CallCallbackObj nextVideoFrameDecoded; + + L_DECLARE_PUBLIC(Call); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CALL_P_H_ diff --git a/src/call/call.cpp b/src/call/call.cpp index b5c8d88e9..c55cc0999 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -16,39 +16,473 @@ * along with this program. If not, see . */ -#include "object/object-p.h" +#include "call-p.h" +#include "conference/participant-p.h" +#include "conference/session/media-session-p.h" #include "call.h" +#include "conference/local-conference.h" +#include "conference/remote-conference.h" +#include "conference/session/media-session.h" +#include "logger/logger.h" + +#include "private.h" using namespace std; -using namespace LinphonePrivate; +LINPHONE_BEGIN_NAMESPACE // ============================================================================= -class Call::CallPrivate : public ObjectPrivate { -public: - LinphoneCallDir direction; - LinphoneCallState state = LinphoneCallIdle; -}; +CallPrivate::CallPrivate (LinphoneCall *call, LinphoneCore *core, LinphoneCallDir direction, const Address &from, const Address &to, + LinphoneProxyConfig *cfg, SalOp *op, const shared_ptr msp) : lcall(call), core(core) { + nextVideoFrameDecoded._func = nullptr; + nextVideoFrameDecoded._user_data = nullptr; +} + +CallPrivate::~CallPrivate () { + if (conference) + delete conference; +} + +// ----------------------------------------------------------------------------- + +shared_ptr CallPrivate::getActiveSession () const { + return conference->getActiveParticipant()->getPrivate()->getSession(); +} + +bool CallPrivate::getAudioMuted () const { + return static_cast(getActiveSession().get())->getPrivate()->getAudioMuted(); +} + +LinphoneProxyConfig * CallPrivate::getDestProxy () const { + return getActiveSession()->getPrivate()->getDestProxy(); +} + +IceSession * CallPrivate::getIceSession () const { + return static_cast(getActiveSession().get())->getPrivate()->getIceSession(); +} + +MediaStream * CallPrivate::getMediaStream (LinphoneStreamType type) const { + return static_cast(getActiveSession().get())->getPrivate()->getMediaStream(type); +} + +SalOp * CallPrivate::getOp () const { + return getActiveSession()->getPrivate()->getOp(); +} + +void CallPrivate::setAudioMuted (bool value) { + static_cast(getActiveSession().get())->getPrivate()->setAudioMuted(value); +} + +// ----------------------------------------------------------------------------- + +void CallPrivate::initiateIncoming () { + getActiveSession()->initiateIncoming(); +} + +bool CallPrivate::initiateOutgoing () { + return getActiveSession()->initiateOutgoing(); +} + +void CallPrivate::iterate (time_t currentRealTime, bool oneSecondElapsed) { + getActiveSession()->iterate(currentRealTime, oneSecondElapsed); +} + +void CallPrivate::startIncomingNotification () { + getActiveSession()->startIncomingNotification(); +} + +int CallPrivate::startInvite (const Address *destination) { + return getActiveSession()->startInvite(destination); +} + +// ----------------------------------------------------------------------------- + +void CallPrivate::ackBeingSent (LinphoneHeaders *headers) { + if (lcall) + linphone_call_notify_ack_processing(lcall, headers, false); +} + +void CallPrivate::ackReceived (LinphoneHeaders *headers) { + if (lcall) + linphone_call_notify_ack_processing(lcall, headers, true); +} + +void CallPrivate::callSetReleased () { + if (lcall) + linphone_call_unref(lcall); +} + +void CallPrivate::callSetTerminated () { + if (lcall) { + if (lcall == core->current_call) { + lInfo() << "Resetting the current call"; + core->current_call = nullptr; + } + if (linphone_core_del_call(core, lcall) != 0) + lError() << "Could not remove the call from the list!!!"; +#if 0 + if (core->conf_ctx) + linphone_conference_on_call_terminating(core->conf_ctx, lcall); + if (lcall->ringing_beep){ + linphone_core_stop_dtmf(core); + lcall->ringing_beep = false; + } + if (lcall->chat_room) + linphone_chat_room_set_call(lcall->chat_room, nullptr); +#endif + if (!core->calls) + ms_bandwidth_controller_reset_state(core->bw_controller); + } +} + +void CallPrivate::callStateChanged (LinphoneCallState state, const std::string &message) { + if (lcall) + linphone_call_notify_state_changed(lcall, state, message.c_str()); +} + +void CallPrivate::incomingCallStarted () { + if (lcall) + linphone_core_notify_incoming_call(core, lcall); +} + +void CallPrivate::incomingCallToBeAdded () { + if (lcall) /* The call is acceptable so we can now add it to our list */ + linphone_core_add_call(core, lcall); +} + +void CallPrivate::encryptionChanged (bool activated, const std::string &authToken) { + if (lcall) + linphone_call_notify_encryption_changed(lcall, activated, authToken.empty() ? nullptr : authToken.c_str()); +} + +void CallPrivate::statsUpdated (const LinphoneCallStats *stats) { + if (lcall) + linphone_call_notify_stats_updated(lcall, stats); +} + +void CallPrivate::setCurrentCall () { + if (lcall) + core->current_call = lcall; +} + +void CallPrivate::firstVideoFrameDecoded () { + if (lcall && nextVideoFrameDecoded._func) { + nextVideoFrameDecoded._func(lcall, nextVideoFrameDecoded._user_data); + nextVideoFrameDecoded._func = nullptr; + nextVideoFrameDecoded._user_data = nullptr; + } +} + +void CallPrivate::resetFirstVideoFrameDecoded () { +#ifdef VIDEO_ENABLED + if (lcall && nextVideoFrameDecoded._func) + static_cast(getActiveSession().get())->resetFirstVideoFrameDecoded(); +#endif +} // ============================================================================= -Call::Call::Call (LinphoneCallDir direction) : Object(*new CallPrivate) { +Call::Call (LinphoneCall *call, LinphoneCore *core, LinphoneCallDir direction, const Address &from, const Address &to, + LinphoneProxyConfig *cfg, SalOp *op, const shared_ptr msp) : Object(*new CallPrivate(call, core, direction, from, to, cfg, op, msp)) { L_D(Call); - d->direction = direction; + const Address *myAddress = (direction == LinphoneCallIncoming) ? &to : &from; + string confType = lp_config_get_string(linphone_core_get_config(core), "misc", "conference_type", "local"); + if (confType == "remote") { + d->conference = new RemoteConference(core, *myAddress, d); + } else { + d->conference = new LocalConference(core, *myAddress, d); + } + const Address *remoteAddress = (direction == LinphoneCallIncoming) ? &from : &to; + shared_ptr participant = d->conference->addParticipant(*remoteAddress, msp, true); + participant->getPrivate()->getSession()->configure(direction, cfg, op, from, to); } // ----------------------------------------------------------------------------- -LinphoneCallDir Call::Call::getDirection () const { - L_D(const Call); - return d->direction; +LinphoneStatus Call::accept (const shared_ptr msp) { + L_D(Call); + return static_cast(d->getActiveSession().get())->accept(msp); +} + +LinphoneStatus Call::acceptEarlyMedia (const std::shared_ptr msp) { + L_D(Call); + return static_cast(d->getActiveSession().get())->acceptEarlyMedia(msp); +} + +LinphoneStatus Call::acceptUpdate (const shared_ptr msp) { + L_D(Call); + return static_cast(d->getActiveSession().get())->acceptUpdate(msp); +} + +LinphoneStatus Call::decline (LinphoneReason reason) { + L_D(Call); + return d->getActiveSession()->decline(reason); +} + +LinphoneStatus Call::decline (const LinphoneErrorInfo *ei) { + L_D(Call); + return d->getActiveSession()->decline(ei); +} + +void Call::sendVfuRequest () { + L_D(Call); + static_cast(d->getActiveSession().get())->sendVfuRequest(); +} + +void Call::startRecording () { + L_D(Call); + static_cast(d->getActiveSession().get())->startRecording(); +} + +void Call::stopRecording () { + L_D(Call); + static_cast(d->getActiveSession().get())->stopRecording(); +} + +LinphoneStatus Call::takePreviewSnapshot (const std::string& file) { + L_D(Call); + return static_cast(d->getActiveSession().get())->takePreviewSnapshot(file); +} + +LinphoneStatus Call::takeVideoSnapshot (const std::string& file) { + L_D(Call); + return static_cast(d->getActiveSession().get())->takeVideoSnapshot(file); +} + +LinphoneStatus Call::terminate (const LinphoneErrorInfo *ei) { + L_D(Call); + return d->getActiveSession()->terminate(ei); +} + +LinphoneStatus Call::update (const std::shared_ptr msp) { + L_D(Call); + return static_cast(d->getActiveSession().get())->update(msp); +} + +void Call::zoomVideo (float zoomFactor, float *cx, float *cy) { + L_D(Call); + static_cast(d->getActiveSession().get())->zoomVideo(zoomFactor, cx, cy); } // ----------------------------------------------------------------------------- -LinphoneCallState Call::Call::getState () const { +bool Call::cameraEnabled () const { L_D(const Call); - return d->state; + return static_cast(d->getActiveSession().get())->cameraEnabled(); } + +bool Call::echoCancellationEnabled () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->echoCancellationEnabled(); +} + +bool Call::echoLimiterEnabled () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->echoLimiterEnabled(); +} + +void Call::enableCamera (bool value) { + L_D(Call); + static_cast(d->getActiveSession().get())->enableCamera(value); +} + +void Call::enableEchoCancellation (bool value) { + L_D(Call); + static_cast(d->getActiveSession().get())->enableEchoCancellation(value); +} + +void Call::enableEchoLimiter (bool value) { + L_D(Call); + static_cast(d->getActiveSession().get())->enableEchoLimiter(value); +} + +bool Call::getAllMuted () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->getAllMuted(); +} + +LinphoneCallStats * Call::getAudioStats () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->getAudioStats(); +} + +string Call::getAuthenticationToken () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->getAuthenticationToken(); +} + +bool Call::getAuthenticationTokenVerified () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->getAuthenticationTokenVerified(); +} + +float Call::getAverageQuality () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->getAverageQuality(); +} + +LinphoneCore * Call::getCore () const { + L_D(const Call); + return d->core; +} + +const shared_ptr Call::getCurrentParams () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->getCurrentParams(); +} + +float Call::getCurrentQuality () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->getCurrentQuality(); +} + +LinphoneCallDir Call::getDirection () const { + L_D(const Call); + return d->getActiveSession()->getDirection(); +} + +int Call::getDuration () const { + L_D(const Call); + return d->getActiveSession()->getDuration(); +} + +const LinphoneErrorInfo * Call::getErrorInfo () const { + L_D(const Call); + return d->getActiveSession()->getErrorInfo(); +} + +LinphoneCallLog * Call::getLog () const { + L_D(const Call); + return d->getActiveSession()->getLog(); +} + +RtpTransport * Call::getMetaRtcpTransport (int streamIndex) { + L_D(Call); + return static_cast(d->getActiveSession().get())->getMetaRtcpTransport(streamIndex); +} + +RtpTransport * Call::getMetaRtpTransport (int streamIndex) { + L_D(Call); + return static_cast(d->getActiveSession().get())->getMetaRtpTransport(streamIndex); +} + +float Call::getMicrophoneVolumeGain () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->getMicrophoneVolumeGain(); +} + +void * Call::getNativeVideoWindowId () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->getNativeVideoWindowId(); +} + +const std::shared_ptr Call::getParams () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->getMediaParams(); +} + +float Call::getPlayVolume () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->getPlayVolume(); +} + +LinphoneReason Call::getReason () const { + L_D(const Call); + return d->getActiveSession()->getReason(); +} + +float Call::getRecordVolume () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->getRecordVolume(); +} + +const Address& Call::getRemoteAddress () const { + L_D(const Call); + return d->getActiveSession()->getRemoteAddress(); +} + +string Call::getRemoteAddressAsString () const { + L_D(const Call); + return d->getActiveSession()->getRemoteAddressAsString(); +} + +string Call::getRemoteContact () const { + L_D(const Call); + return d->getActiveSession()->getRemoteContact(); +} + +const shared_ptr Call::getRemoteParams () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->getRemoteParams(); +} + +float Call::getSpeakerVolumeGain () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->getSpeakerVolumeGain(); +} + +LinphoneCallState Call::getState () const { + L_D(const Call); + return d->getActiveSession()->getState(); +} + +LinphoneCallStats * Call::getStats (LinphoneStreamType type) const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->getStats(type); +} + +int Call::getStreamCount () { + L_D(Call); + return static_cast(d->getActiveSession().get())->getStreamCount(); +} + +MSFormatType Call::getStreamType (int streamIndex) const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->getStreamType(streamIndex); +} + +LinphoneCallStats * Call::getTextStats () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->getTextStats(); +} + +LinphoneCallStats * Call::getVideoStats () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->getVideoStats(); +} + +bool Call::mediaInProgress () const { + L_D(const Call); + return static_cast(d->getActiveSession().get())->mediaInProgress(); +} + +void Call::setAuthenticationTokenVerified (bool value) { + L_D(Call); + static_cast(d->getActiveSession().get())->setAuthenticationTokenVerified(value); +} + +void Call::setMicrophoneVolumeGain (float value) { + L_D(Call); + static_cast(d->getActiveSession().get())->setMicrophoneVolumeGain(value); +} + +void Call::setNativeVideoWindowId (void *id) { + L_D(Call); + static_cast(d->getActiveSession().get())->setNativeVideoWindowId(id); +} + +void Call::setNextVideoFrameDecodedCallback (LinphoneCallCbFunc cb, void *user_data) { + L_D(Call); + d->nextVideoFrameDecoded._func = cb; + d->nextVideoFrameDecoded._user_data = user_data; + d->resetFirstVideoFrameDecoded(); +} + +void Call::setSpeakerVolumeGain (float value) { + L_D(Call); + static_cast(d->getActiveSession().get())->setSpeakerVolumeGain(value); +} + +LINPHONE_END_NAMESPACE diff --git a/src/call/call.h b/src/call/call.h index 03c6af06a..ee6c2f658 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -19,28 +19,94 @@ #ifndef _CALL_CALL_H_ #define _CALL_CALL_H_ +#include + #include "linphone/types.h" #include "object/object.h" +#include "address/address.h" +#include "call/call-listener.h" +#include "conference/params/media-session-params.h" // ============================================================================= -namespace LinphonePrivate { - namespace Call { - class CallPrivate; +LINPHONE_BEGIN_NAMESPACE - class Call : public Object { - public: - Call (LinphoneCallDir direction); +class CallPrivate; +class CallSessionPrivate; +class MediaSessionPrivate; - LinphoneCallDir getDirection() const; - LinphoneCallState getState() const; +class Call : public Object { + friend class CallSessionPrivate; + friend class MediaSessionPrivate; - private: - L_DECLARE_PRIVATE(Call); - L_DISABLE_COPY(Call); - }; - } -} +public: + Call (LinphoneCall *call, LinphoneCore *core, LinphoneCallDir direction, const Address &from, const Address &to, + LinphoneProxyConfig *cfg, SalOp *op, const std::shared_ptr msp); + + LinphoneStatus accept (const std::shared_ptr msp = nullptr); + LinphoneStatus acceptEarlyMedia (const std::shared_ptr msp = nullptr); + LinphoneStatus acceptUpdate (const std::shared_ptr msp); + LinphoneStatus decline (LinphoneReason reason); + LinphoneStatus decline (const LinphoneErrorInfo *ei); + void sendVfuRequest (); + void startRecording (); + void stopRecording (); + LinphoneStatus takePreviewSnapshot (const std::string& file); + LinphoneStatus takeVideoSnapshot (const std::string& file); + LinphoneStatus terminate (const LinphoneErrorInfo *ei = nullptr); + LinphoneStatus update (const std::shared_ptr msp = nullptr); + void zoomVideo (float zoomFactor, float *cx, float *cy); + + bool cameraEnabled () const; + bool echoCancellationEnabled () const; + bool echoLimiterEnabled () const; + void enableCamera (bool value); + void enableEchoCancellation (bool value); + void enableEchoLimiter (bool value); + bool getAllMuted () const; + LinphoneCallStats * getAudioStats () const; + std::string getAuthenticationToken () const; + bool getAuthenticationTokenVerified () const; + float getAverageQuality () const; + LinphoneCore * getCore () const; + const std::shared_ptr getCurrentParams () const; + float getCurrentQuality () const; + LinphoneCallDir getDirection () const; + int getDuration () const; + const LinphoneErrorInfo * getErrorInfo () const; + LinphoneCallLog * getLog () const; + RtpTransport * getMetaRtcpTransport (int streamIndex); + RtpTransport * getMetaRtpTransport (int streamIndex); + float getMicrophoneVolumeGain () const; + void * getNativeVideoWindowId () const; + const std::shared_ptr getParams () const; + float getPlayVolume () const; + LinphoneReason getReason () const; + float getRecordVolume () const; + const Address& getRemoteAddress () const; + std::string getRemoteAddressAsString () const; + std::string getRemoteContact () const; + const std::shared_ptr getRemoteParams () const; + float getSpeakerVolumeGain () const; + LinphoneCallState getState () const; + LinphoneCallStats * getStats (LinphoneStreamType type) const; + int getStreamCount (); + MSFormatType getStreamType (int streamIndex) const; + LinphoneCallStats * getTextStats () const; + LinphoneCallStats * getVideoStats () const; + bool mediaInProgress () const; + void setAuthenticationTokenVerified (bool value); + void setMicrophoneVolumeGain (float value); + void setNativeVideoWindowId (void *id); + void setNextVideoFrameDecodedCallback (LinphoneCallCbFunc cb, void *user_data); + void setSpeakerVolumeGain (float value); + +private: + L_DECLARE_PRIVATE(Call); + L_DISABLE_COPY(Call); +}; + +LINPHONE_END_NAMESPACE #endif // ifndef _CALL_CALL_H_ diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 72d37c6ca..b8fd05c1e 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -523,8 +523,8 @@ void ChatRoomPrivate::realtimeTextReceived (uint32_t character, LinphoneCall *ca linphone_chat_message_set_from(pendingMessage, peerAddress); if (pendingMessage->to) linphone_address_unref(pendingMessage->to); - pendingMessage->to = call->dest_proxy - ? linphone_address_clone(call->dest_proxy->identity_address) + pendingMessage->to = linphone_call_get_dest_proxy(call) + ? linphone_address_clone(linphone_call_get_dest_proxy(call)->identity_address) : linphone_address_new(linphone_core_get_identity(core)); pendingMessage->time = ms_time(0); pendingMessage->state = LinphoneChatMessageStateDelivered; @@ -868,11 +868,11 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { if (lp_config_get_int(d->core->config, "sip", "chat_use_call_dialogs", 0) != 0) { call = linphone_core_get_call_by_remote_address(d->core, d->peer.c_str()); if (call) { - if (call->state == LinphoneCallConnected || call->state == LinphoneCallStreamsRunning || - call->state == LinphoneCallPaused || call->state == LinphoneCallPausing || - call->state == LinphoneCallPausedByRemote) { + if (linphone_call_get_state(call) == LinphoneCallConnected || linphone_call_get_state(call) == LinphoneCallStreamsRunning || + linphone_call_get_state(call) == LinphoneCallPaused || linphone_call_get_state(call) == LinphoneCallPausing || + linphone_call_get_state(call) == LinphoneCallPausedByRemote) { ms_message("send SIP msg through the existing call."); - op = call->op; + op = linphone_call_get_op(call); identity = linphone_core_find_best_identity(d->core, linphone_call_get_remote_address(call)); } } @@ -960,7 +960,7 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { ms_free(clearTextContentType); } - if (call && call->op == op) { + if (call && linphone_call_get_op(call) == op) { /* In this case, chat delivery status is not notified, so unrefing chat message right now */ /* Might be better fixed by delivering status, but too costly for now */ linphone_chat_room_remove_transient_message(msg->chat_room, msg); diff --git a/src/conference/conference-listener.h b/src/conference/conference-listener.h index 80d312395..4bed6f68a 100644 --- a/src/conference/conference-listener.h +++ b/src/conference/conference-listener.h @@ -23,7 +23,7 @@ LINPHONE_BEGIN_NAMESPACE -class ConferenceListener : public Object { +class ConferenceListener { public: virtual void conferenceCreated (LinphoneAddress *addr) = 0; virtual void conferenceTerminated (LinphoneAddress *addr) = 0; diff --git a/src/conference/conference-p.h b/src/conference/conference-p.h index 7584b8ebf..f97cf84be 100644 --- a/src/conference/conference-p.h +++ b/src/conference/conference-p.h @@ -19,9 +19,13 @@ #ifndef _CONFERENCE_P_H_ #define _CONFERENCE_P_H_ +#include + #include "object/object-p.h" -#include "conference.h" +#include "conference/conference.h" +#include "conference/participant.h" +#include "conference/session/call-session-listener.h" #include @@ -29,11 +33,35 @@ LINPHONE_BEGIN_NAMESPACE -class ConferencePrivate : public ObjectPrivate { +class ConferencePrivate : public ObjectPrivate, CallSessionListener { public: virtual ~ConferencePrivate () = default; - std::string confId; + LinphoneCore * getCore () const { return core; } + + virtual void ackBeingSent (const CallSession &session, LinphoneHeaders *headers); + virtual void ackReceived (const CallSession &session, LinphoneHeaders *headers); + virtual void callSessionAccepted (const CallSession &session); + virtual void callSessionSetReleased (const CallSession &session); + virtual void callSessionSetTerminated (const CallSession &session); + virtual void callSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message); + virtual void incomingCallSessionStarted (const CallSession &session); + + virtual void encryptionChanged (const CallSession &session, bool activated, const std::string &authToken); + + virtual void statsUpdated (const LinphoneCallStats *stats); + + virtual void setCurrentSession (const CallSession &session); + + virtual void firstVideoFrameDecoded (const CallSession &session); + virtual void resetFirstVideoFrameDecoded (const CallSession &session); + +private: + LinphoneCore *core = nullptr; + CallListener *callListener = nullptr; + + std::shared_ptr me = nullptr; + std::shared_ptr activeParticipant = nullptr; L_DECLARE_PUBLIC(Conference); }; diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index b5072d3e9..6ca8cbaba 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -17,13 +17,101 @@ */ #include "conference-p.h" +#include "participant-p.h" #include "conference.h" +using namespace std; + LINPHONE_BEGIN_NAMESPACE // ============================================================================= -Conference::Conference (ConferencePrivate &p) : Object(p) {} +void ConferencePrivate::ackBeingSent (const CallSession &session, LinphoneHeaders *headers) { + if (callListener) + callListener->ackBeingSent(headers); +} + +void ConferencePrivate::ackReceived (const CallSession &session, LinphoneHeaders *headers) { + if (callListener) + callListener->ackReceived(headers); +} + +void ConferencePrivate::callSessionAccepted (const CallSession &session) { + if (callListener) + callListener->incomingCallToBeAdded(); +} + +void ConferencePrivate::callSessionSetReleased (const CallSession &session) { + if (callListener) + callListener->callSetReleased(); +} + +void ConferencePrivate::callSessionSetTerminated (const CallSession &session) { + if (callListener) + callListener->callSetTerminated(); +} + +void ConferencePrivate::callSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message) { + if (callListener) + callListener->callStateChanged(state, message); +} + +void ConferencePrivate::incomingCallSessionStarted (const CallSession &session) { + if (callListener) + callListener->incomingCallStarted(); +} + +void ConferencePrivate::encryptionChanged (const CallSession &session, bool activated, const std::string &authToken) { + if (callListener) + callListener->encryptionChanged(activated, authToken); +} + +void ConferencePrivate::statsUpdated (const LinphoneCallStats *stats) { + if (callListener) + callListener->statsUpdated(stats); +} + +void ConferencePrivate::setCurrentSession (const CallSession &session) { + if (callListener) + callListener->setCurrentCall(); +} + +void ConferencePrivate::firstVideoFrameDecoded (const CallSession &session) { + if (callListener) + callListener->firstVideoFrameDecoded(); +} + +void ConferencePrivate::resetFirstVideoFrameDecoded (const CallSession &session) { + if (callListener) + callListener->resetFirstVideoFrameDecoded(); +} + +// ============================================================================= + +Conference::Conference (ConferencePrivate &p, LinphoneCore *core, const Address &myAddress, CallListener *listener) + : Object(p) { + L_D(Conference); + d->core = core; + d->callListener = listener; + d->me = make_shared(myAddress); +} + +shared_ptr Conference::addParticipant (const Address &addr, const shared_ptr params, bool hasMedia) { + L_D(Conference); + d->activeParticipant = make_shared(addr); + d->activeParticipant->getPrivate()->createSession(*this, params, hasMedia, d); + return d->activeParticipant; +} + +shared_ptr Conference::getActiveParticipant () const { + L_D(const Conference); + return d->activeParticipant; +} + +shared_ptr Conference::getMe () const { + L_D(const Conference); + return d->me; +} LINPHONE_END_NAMESPACE diff --git a/src/conference/conference.h b/src/conference/conference.h index aa76a0cde..a65535954 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -19,20 +19,35 @@ #ifndef _CONFERENCE_H_ #define _CONFERENCE_H_ +#include + #include "object/object.h" +#include "address/address.h" +#include "call/call-listener.h" +#include "conference/params/call-session-params.h" +#include "conference/participant.h" + +#include "linphone/types.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE class ConferencePrivate; +class CallSessionPrivate; class Conference : public Object { + friend class CallSessionPrivate; + public: - Conference (); + //Conference (CallListener *listener = nullptr); + + std::shared_ptr addParticipant (const Address &addr, const std::shared_ptr params, bool hasMedia); + std::shared_ptr getActiveParticipant () const; + std::shared_ptr getMe () const; protected: - explicit Conference (ConferencePrivate &p); + explicit Conference (ConferencePrivate &p, LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); private: L_DECLARE_PRIVATE(Conference); diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index c330e5e5b..acb5a432c 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -30,6 +30,7 @@ public: // ============================================================================= -LocalConference::LocalConference () : Conference(*new LocalConferencePrivate) {} +LocalConference::LocalConference (LinphoneCore *core, const Address &myAddress, CallListener *listener) + : Conference(*new LocalConferencePrivate, core, myAddress, listener) {} LINPHONE_END_NAMESPACE diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h index 7ff04d176..5a2b3bbe9 100644 --- a/src/conference/local-conference.h +++ b/src/conference/local-conference.h @@ -29,7 +29,7 @@ class LocalConferencePrivate; class LocalConference : public Conference { public: - LocalConference (); + LocalConference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); private: L_DECLARE_PRIVATE(LocalConference); diff --git a/src/conference/params/call-session-params-p.h b/src/conference/params/call-session-params-p.h index 0aa300aa3..c410f5e37 100644 --- a/src/conference/params/call-session-params-p.h +++ b/src/conference/params/call-session-params-p.h @@ -42,10 +42,6 @@ public: SalCustomHeader * getCustomHeaders () const; void setCustomHeaders (const SalCustomHeader *ch); - SalCustomSdpAttribute * getCustomSdpAttributes () const; - void setCustomSdpAttributes (const SalCustomSdpAttribute *csa); - SalCustomSdpAttribute * getCustomSdpMediaAttributes (LinphoneStreamType lst) const; - void setCustomSdpMediaAttributes (LinphoneStreamType lst, const SalCustomSdpAttribute *csa); LinphoneCall *getReferer () const { return referer; } void setReferer (LinphoneCall *call) { referer = call; } @@ -60,8 +56,6 @@ private: bool internalCallUpdate = false; bool noUserConsent = false; /* When set to true an UPDATE request will be used instead of reINVITE */ SalCustomHeader *customHeaders = nullptr; - SalCustomSdpAttribute *customSdpAttributes = nullptr; - SalCustomSdpAttribute *customSdpMediaAttributes[LinphoneStreamTypeUnknown]; LinphoneCall *referer = nullptr; /* In case call creation is consecutive to an incoming transfer, this points to the original call */ public: diff --git a/src/conference/params/call-session-params.cpp b/src/conference/params/call-session-params.cpp index dae870ad2..7a4b7fb3b 100644 --- a/src/conference/params/call-session-params.cpp +++ b/src/conference/params/call-session-params.cpp @@ -35,24 +35,12 @@ CallSessionParamsPrivate::CallSessionParamsPrivate (const CallSessionParamsPriva /* The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient. */ if (src.customHeaders) customHeaders = sal_custom_header_clone(src.customHeaders); - if (src.customSdpAttributes) - customSdpAttributes = sal_custom_sdp_attribute_clone(src.customSdpAttributes); - for (unsigned int i = 0; i < (unsigned int)LinphoneStreamTypeUnknown; i++) { - if (src.customSdpMediaAttributes[i]) - customSdpMediaAttributes[i] = sal_custom_sdp_attribute_clone(src.customSdpMediaAttributes[i]); - } referer = src.referer; } CallSessionParamsPrivate::~CallSessionParamsPrivate () { if (customHeaders) sal_custom_header_free(customHeaders); - if (customSdpAttributes) - sal_custom_sdp_attribute_free(customSdpAttributes); - for (unsigned int i = 0; i < (unsigned int)LinphoneStreamTypeUnknown; i++) { - if (customSdpMediaAttributes[i]) - sal_custom_sdp_attribute_free(customSdpMediaAttributes[i]); - } } // ----------------------------------------------------------------------------- @@ -70,50 +58,25 @@ void CallSessionParamsPrivate::setCustomHeaders (const SalCustomHeader *ch) { customHeaders = sal_custom_header_clone(ch); } -// ----------------------------------------------------------------------------- - -SalCustomSdpAttribute * CallSessionParamsPrivate::getCustomSdpAttributes () const { - return customSdpAttributes; -} - -void CallSessionParamsPrivate::setCustomSdpAttributes (const SalCustomSdpAttribute *csa) { - if (customSdpAttributes) { - sal_custom_sdp_attribute_free(customSdpAttributes); - customSdpAttributes = nullptr; - } - if (csa) - customSdpAttributes = sal_custom_sdp_attribute_clone(csa); -} - -// ----------------------------------------------------------------------------- - -SalCustomSdpAttribute * CallSessionParamsPrivate::getCustomSdpMediaAttributes (LinphoneStreamType lst) const { - return customSdpMediaAttributes[lst]; -} - -void CallSessionParamsPrivate::setCustomSdpMediaAttributes (LinphoneStreamType lst, const SalCustomSdpAttribute *csa) { - if (customSdpMediaAttributes[lst]) { - sal_custom_sdp_attribute_free(customSdpMediaAttributes[lst]); - customSdpMediaAttributes[lst] = nullptr; - } - if (csa) - customSdpMediaAttributes[lst] = sal_custom_sdp_attribute_clone(csa); -} - // ============================================================================= CallSessionParams::CallSessionParams () : ClonableObject(*new CallSessionParamsPrivate) {} -CallSessionParams::CallSessionParams (CallSessionParamsPrivate &p) : ClonableObject(p) { - L_D(CallSessionParams); - memset(d->customSdpMediaAttributes, 0, sizeof(d->customSdpMediaAttributes)); -} +CallSessionParams::CallSessionParams (CallSessionParamsPrivate &p) : ClonableObject(p) {} CallSessionParams::CallSessionParams (const CallSessionParams &src) : ClonableObject(*new CallSessionParamsPrivate(*src.getPrivate())) {} // ----------------------------------------------------------------------------- +void CallSessionParams::initDefault (LinphoneCore *core) { + L_D(CallSessionParams); + d->inConference = false; + d->privacy = LinphonePrivacyDefault; +} + +// ----------------------------------------------------------------------------- + const string& CallSessionParams::getSessionName () const { L_D(const CallSessionParams); return d->sessionName; @@ -153,38 +116,4 @@ const char * CallSessionParams::getCustomHeader (const string &headerName) const return sal_custom_header_find(d->customHeaders, headerName.c_str()); } -// ----------------------------------------------------------------------------- - -void CallSessionParams::addCustomSdpAttribute (const string &attributeName, const string &attributeValue) { - L_D(CallSessionParams); - d->customSdpAttributes = sal_custom_sdp_attribute_append(d->customSdpAttributes, attributeName.c_str(), attributeValue.c_str()); -} - -void CallSessionParams::clearCustomSdpAttributes () { - L_D(CallSessionParams); - d->setCustomSdpAttributes(nullptr); -} - -const char * CallSessionParams::getCustomSdpAttribute (const string &attributeName) const { - L_D(const CallSessionParams); - return sal_custom_sdp_attribute_find(d->customSdpAttributes, attributeName.c_str()); -} - -// ----------------------------------------------------------------------------- - -void CallSessionParams::addCustomSdpMediaAttribute (LinphoneStreamType lst, const string &attributeName, const string &attributeValue) { - L_D(CallSessionParams); - d->customSdpMediaAttributes[lst] = sal_custom_sdp_attribute_append(d->customSdpMediaAttributes[lst], attributeName.c_str(), attributeValue.c_str()); -} - -void CallSessionParams::clearCustomSdpMediaAttributes (LinphoneStreamType lst) { - L_D(CallSessionParams); - d->setCustomSdpMediaAttributes(lst, nullptr); -} - -const char * CallSessionParams::getCustomSdpMediaAttribute (LinphoneStreamType lst, const string &attributeName) const { - L_D(const CallSessionParams); - return sal_custom_sdp_attribute_find(d->customSdpMediaAttributes[lst], attributeName.c_str()); -} - LINPHONE_END_NAMESPACE diff --git a/src/conference/params/call-session-params.h b/src/conference/params/call-session-params.h index 68d6ca716..a3afc3e31 100644 --- a/src/conference/params/call-session-params.h +++ b/src/conference/params/call-session-params.h @@ -26,50 +26,25 @@ #include "linphone/types.h" #include "sal/sal.h" -extern "C" { - bool_t linphone_call_params_get_in_conference(const LinphoneCallParams *params); - void linphone_call_params_set_in_conference(LinphoneCallParams *params, bool_t value); - bool_t linphone_call_params_get_internal_call_update(const LinphoneCallParams *params); - void linphone_call_params_set_internal_call_update(LinphoneCallParams *params, bool_t value); - bool_t linphone_call_params_get_no_user_consent(const LinphoneCallParams *params); - void linphone_call_params_set_no_user_consent(LinphoneCallParams *params, bool_t value); - SalCustomHeader * linphone_call_params_get_custom_headers(const LinphoneCallParams *params); - void linphone_call_params_set_custom_headers(LinphoneCallParams *params, const SalCustomHeader *ch); - SalCustomSdpAttribute * linphone_call_params_get_custom_sdp_attributes(const LinphoneCallParams *params); - void linphone_call_params_set_custom_sdp_attributes(LinphoneCallParams *params, const SalCustomSdpAttribute *csa); - SalCustomSdpAttribute * linphone_call_params_get_custom_sdp_media_attributes(const LinphoneCallParams *params, LinphoneStreamType type); - void linphone_call_params_set_custom_sdp_media_attributes(LinphoneCallParams *params, LinphoneStreamType type, const SalCustomSdpAttribute *csa); - LinphoneCall * linphone_call_params_get_referer(const LinphoneCallParams *params); - void linphone_call_params_set_referer(LinphoneCallParams *params, LinphoneCall *referer); -} - // ============================================================================= LINPHONE_BEGIN_NAMESPACE +class CallSession; class CallSessionParamsPrivate; +class CallSessionPrivate; class CallSessionParams : public ClonableObject { - friend unsigned char ::linphone_call_params_get_in_conference(const LinphoneCallParams *params); - friend void ::linphone_call_params_set_in_conference(LinphoneCallParams *params, unsigned char value); - friend unsigned char ::linphone_call_params_get_internal_call_update(const LinphoneCallParams *params); - friend void ::linphone_call_params_set_internal_call_update(LinphoneCallParams *params, unsigned char value); - friend unsigned char ::linphone_call_params_get_no_user_consent(const LinphoneCallParams *params); - friend void ::linphone_call_params_set_no_user_consent(LinphoneCallParams *params, unsigned char value); - friend SalCustomHeader * ::linphone_call_params_get_custom_headers(const LinphoneCallParams *params); - friend void ::linphone_call_params_set_custom_headers(LinphoneCallParams *params, const SalCustomHeader *ch); - friend SalCustomSdpAttribute * ::linphone_call_params_get_custom_sdp_attributes(const LinphoneCallParams *params); - friend void ::linphone_call_params_set_custom_sdp_attributes(LinphoneCallParams *params, const SalCustomSdpAttribute *csa); - friend SalCustomSdpAttribute * ::linphone_call_params_get_custom_sdp_media_attributes(const LinphoneCallParams *params, LinphoneStreamType type); - friend void ::linphone_call_params_set_custom_sdp_media_attributes(LinphoneCallParams *params, LinphoneStreamType type, const SalCustomSdpAttribute *csa); - friend LinphoneCall * ::linphone_call_params_get_referer(const LinphoneCallParams *params); - friend void ::linphone_call_params_set_referer(LinphoneCallParams *params, LinphoneCall *referer); + friend class CallSession; + friend class CallSessionPrivate; public: CallSessionParams (); CallSessionParams (const CallSessionParams &src); virtual ~CallSessionParams () = default; + virtual void initDefault (LinphoneCore *core); + const std::string& getSessionName () const; void setSessionName (const std::string &sessionName); @@ -80,14 +55,6 @@ public: void clearCustomHeaders (); const char * getCustomHeader (const std::string &headerName) const; - void addCustomSdpAttribute (const std::string &attributeName, const std::string &attributeValue); - void clearCustomSdpAttributes (); - const char * getCustomSdpAttribute (const std::string &attributeName) const; - - void addCustomSdpMediaAttribute (LinphoneStreamType lst, const std::string &attributeName, const std::string &attributeValue); - void clearCustomSdpMediaAttributes (LinphoneStreamType lst); - const char * getCustomSdpMediaAttribute (LinphoneStreamType lst, const std::string &attributeName) const; - protected: explicit CallSessionParams (CallSessionParamsPrivate &p); diff --git a/src/conference/params/media-session-params-p.h b/src/conference/params/media-session-params-p.h index 867c990bb..f2ca7ca8c 100644 --- a/src/conference/params/media-session-params-p.h +++ b/src/conference/params/media-session-params-p.h @@ -19,18 +19,35 @@ #ifndef _MEDIA_SESSION_PARAMS_P_H_ #define _MEDIA_SESSION_PARAMS_P_H_ +#include + +#include "call-session-params-p.h" + #include "media-session-params.h" // ============================================================================= +extern std::shared_ptr linphone_call_params_get_cpp_obj(const LinphoneCallParams *params); +extern LinphoneCallParams * linphone_call_params_new_for_wrapper(void); + +// ============================================================================= + LINPHONE_BEGIN_NAMESPACE class MediaSessionParamsPrivate : public CallSessionParamsPrivate { public: - MediaSessionParamsPrivate () = default; + MediaSessionParamsPrivate (); MediaSessionParamsPrivate (const MediaSessionParamsPrivate &src); virtual ~MediaSessionParamsPrivate (); + static SalStreamDir mediaDirectionToSalStreamDir (LinphoneMediaDirection direction); + static LinphoneMediaDirection salStreamDirToMediaDirection (SalStreamDir dir); + + void adaptToNetwork (LinphoneCore *core, int pingTimeMs); + + SalStreamDir getSalAudioDirection () const; + SalStreamDir getSalVideoDirection () const; + void enableImplicitRtcpFb (bool value) { _implicitRtcpFbEnabled = value; } bool implicitRtcpFbEnabled () const { return _implicitRtcpFbEnabled; } int getDownBandwidth () const { return downBandwidth; } @@ -52,6 +69,11 @@ public: void setUsedVideoCodec (OrtpPayloadType *pt) { usedVideoCodec = pt; } void setUsedRealtimeTextCodec (OrtpPayloadType *pt) { usedRealtimeTextCodec = pt; } + SalCustomSdpAttribute * getCustomSdpAttributes () const; + void setCustomSdpAttributes (const SalCustomSdpAttribute *csa); + SalCustomSdpAttribute * getCustomSdpMediaAttributes (LinphoneStreamType lst) const; + void setCustomSdpMediaAttributes (LinphoneStreamType lst, const SalCustomSdpAttribute *csa); + public: bool audioEnabled = true; int audioBandwidthLimit = 0; @@ -90,6 +112,8 @@ private: int downPtime = 0; int upPtime = 0; bool updateCallWhenIceCompleted = true; + SalCustomSdpAttribute *customSdpAttributes = nullptr; + SalCustomSdpAttribute *customSdpMediaAttributes[LinphoneStreamTypeUnknown]; public: L_DECLARE_PUBLIC(MediaSessionParams); diff --git a/src/conference/params/media-session-params.cpp b/src/conference/params/media-session-params.cpp index bb2bd441f..79216feb6 100644 --- a/src/conference/params/media-session-params.cpp +++ b/src/conference/params/media-session-params.cpp @@ -21,6 +21,8 @@ #include "media-session-params.h" +#include "logger/logger.h" + #include "private.h" using namespace std; @@ -29,6 +31,10 @@ LINPHONE_BEGIN_NAMESPACE // ============================================================================= +MediaSessionParamsPrivate::MediaSessionParamsPrivate () { + memset(customSdpMediaAttributes, 0, sizeof(customSdpMediaAttributes)); +} + MediaSessionParamsPrivate::MediaSessionParamsPrivate (const MediaSessionParamsPrivate &src) : CallSessionParamsPrivate(src) { audioEnabled = src.audioEnabled; audioBandwidthLimit = src.audioBandwidthLimit; @@ -58,6 +64,13 @@ MediaSessionParamsPrivate::MediaSessionParamsPrivate (const MediaSessionParamsPr downPtime = src.downPtime; upPtime = src.upPtime; updateCallWhenIceCompleted = src.updateCallWhenIceCompleted; + if (src.customSdpAttributes) + customSdpAttributes = sal_custom_sdp_attribute_clone(src.customSdpAttributes); + memset(customSdpMediaAttributes, 0, sizeof(customSdpMediaAttributes)); + for (unsigned int i = 0; i < (unsigned int)LinphoneStreamTypeUnknown; i++) { + if (src.customSdpMediaAttributes[i]) + customSdpMediaAttributes[i] = sal_custom_sdp_attribute_clone(src.customSdpMediaAttributes[i]); + } } MediaSessionParamsPrivate::~MediaSessionParamsPrivate () { @@ -65,6 +78,78 @@ MediaSessionParamsPrivate::~MediaSessionParamsPrivate () { linphone_video_definition_unref(receivedVideoDefinition); if (sentVideoDefinition) linphone_video_definition_unref(sentVideoDefinition); + if (customSdpAttributes) + sal_custom_sdp_attribute_free(customSdpAttributes); + for (unsigned int i = 0; i < (unsigned int)LinphoneStreamTypeUnknown; i++) { + if (customSdpMediaAttributes[i]) + sal_custom_sdp_attribute_free(customSdpMediaAttributes[i]); + } +} + +// ----------------------------------------------------------------------------- + +SalStreamDir MediaSessionParamsPrivate::mediaDirectionToSalStreamDir (LinphoneMediaDirection direction) { + switch (direction) { + case LinphoneMediaDirectionInactive: + return SalStreamInactive; + case LinphoneMediaDirectionSendOnly: + return SalStreamSendOnly; + case LinphoneMediaDirectionRecvOnly: + return SalStreamRecvOnly; + case LinphoneMediaDirectionSendRecv: + return SalStreamSendRecv; + case LinphoneMediaDirectionInvalid: + lError() << "LinphoneMediaDirectionInvalid shall not be used"; + return SalStreamInactive; + } + return SalStreamSendRecv; +} + +LinphoneMediaDirection MediaSessionParamsPrivate::salStreamDirToMediaDirection (SalStreamDir dir) { + switch (dir) { + case SalStreamInactive: + return LinphoneMediaDirectionInactive; + case SalStreamSendOnly: + return LinphoneMediaDirectionSendOnly; + case SalStreamRecvOnly: + return LinphoneMediaDirectionRecvOnly; + case SalStreamSendRecv: + return LinphoneMediaDirectionSendRecv; + } + return LinphoneMediaDirectionSendRecv; +} + +// ----------------------------------------------------------------------------- + +void MediaSessionParamsPrivate::adaptToNetwork (LinphoneCore *core, int pingTimeMs) { + L_Q(MediaSessionParams); + if ((pingTimeMs > 0) && lp_config_get_int(linphone_core_get_config(core), "net", "activate_edge_workarounds", 0)) { + lInfo() << "STUN server ping time is " << pingTimeMs << " ms"; + int threshold = lp_config_get_int(linphone_core_get_config(core), "net", "edge_ping_time", 500); + if (pingTimeMs > threshold) { + /* We might be in a 2G network */ + q->enableLowBandwidth(true); + } /* else use default settings */ + } + if (q->lowBandwidthEnabled()) { + setUpBandwidth(linphone_core_get_edge_bw(core)); + setDownBandwidth(linphone_core_get_edge_bw(core)); + setUpPtime(linphone_core_get_edge_ptime(core)); + setDownPtime(linphone_core_get_edge_ptime(core)); + q->enableVideo(false); + } +} + +// ----------------------------------------------------------------------------- + +SalStreamDir MediaSessionParamsPrivate::getSalAudioDirection () const { + L_Q(const MediaSessionParams); + return mediaDirectionToSalStreamDir(q->getAudioDirection()); +} + +SalStreamDir MediaSessionParamsPrivate::getSalVideoDirection () const { + L_Q(const MediaSessionParams); + return mediaDirectionToSalStreamDir(q->getVideoDirection()); } // ----------------------------------------------------------------------------- @@ -81,6 +166,36 @@ void MediaSessionParamsPrivate::setSentVideoDefinition (LinphoneVideoDefinition sentVideoDefinition = linphone_video_definition_ref(value); } +// ----------------------------------------------------------------------------- + +SalCustomSdpAttribute * MediaSessionParamsPrivate::getCustomSdpAttributes () const { + return customSdpAttributes; +} + +void MediaSessionParamsPrivate::setCustomSdpAttributes (const SalCustomSdpAttribute *csa) { + if (customSdpAttributes) { + sal_custom_sdp_attribute_free(customSdpAttributes); + customSdpAttributes = nullptr; + } + if (csa) + customSdpAttributes = sal_custom_sdp_attribute_clone(csa); +} + +// ----------------------------------------------------------------------------- + +SalCustomSdpAttribute * MediaSessionParamsPrivate::getCustomSdpMediaAttributes (LinphoneStreamType lst) const { + return customSdpMediaAttributes[lst]; +} + +void MediaSessionParamsPrivate::setCustomSdpMediaAttributes (LinphoneStreamType lst, const SalCustomSdpAttribute *csa) { + if (customSdpMediaAttributes[lst]) { + sal_custom_sdp_attribute_free(customSdpMediaAttributes[lst]); + customSdpMediaAttributes[lst] = nullptr; + } + if (csa) + customSdpMediaAttributes[lst] = sal_custom_sdp_attribute_clone(csa); +} + // ============================================================================= MediaSessionParams::MediaSessionParams () : CallSessionParams(*new MediaSessionParamsPrivate) {} @@ -90,6 +205,31 @@ MediaSessionParams::MediaSessionParams (const MediaSessionParams &src) // ----------------------------------------------------------------------------- +void MediaSessionParams::initDefault (LinphoneCore *core) { + L_D(MediaSessionParams); + CallSessionParams::initDefault(core); + d->audioEnabled = true; + d->videoEnabled = linphone_core_video_enabled(core) && core->video_policy.automatically_initiate; + if (!linphone_core_video_enabled(core) && core->video_policy.automatically_initiate) { + lError() << "LinphoneCore has video disabled for both capture and display, but video policy is to start the call with video. " + "This is a possible mis-use of the API. In this case, video is disabled in default LinphoneCallParams"; + } + d->realtimeTextEnabled = linphone_core_realtime_text_enabled(core); + d->encryption = linphone_core_get_media_encryption(core); + d->avpfEnabled = (linphone_core_get_avpf_mode(core) == LinphoneAVPFEnabled); + d->_implicitRtcpFbEnabled = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_fb_implicit_rtcp_fb", true); + d->avpfRrInterval = linphone_core_get_avpf_rr_interval(core); + d->audioDirection = LinphoneMediaDirectionSendRecv; + d->videoDirection = LinphoneMediaDirectionSendRecv; + d->earlyMediaSendingEnabled = lp_config_get_int(linphone_core_get_config(core), "misc", "real_early_media", false); + d->audioMulticastEnabled = linphone_core_audio_multicast_enabled(core); + d->videoMulticastEnabled = linphone_core_video_multicast_enabled(core); + d->updateCallWhenIceCompleted = lp_config_get_int(linphone_core_get_config(core), "sip", "update_call_when_ice_completed", true); + d->mandatoryMediaEncryptionEnabled = linphone_core_is_media_encryption_mandatory(core); +} + +// ----------------------------------------------------------------------------- + bool MediaSessionParams::audioEnabled () const { L_D(const MediaSessionParams); return d->audioEnabled; @@ -323,4 +463,38 @@ const char * MediaSessionParams::getRtpProfile () const { return sal_media_proto_to_string(getMediaProto()); } +// ----------------------------------------------------------------------------- + +void MediaSessionParams::addCustomSdpAttribute (const string &attributeName, const string &attributeValue) { + L_D(MediaSessionParams); + d->customSdpAttributes = sal_custom_sdp_attribute_append(d->customSdpAttributes, attributeName.c_str(), attributeValue.c_str()); +} + +void MediaSessionParams::clearCustomSdpAttributes () { + L_D(MediaSessionParams); + d->setCustomSdpAttributes(nullptr); +} + +const char * MediaSessionParams::getCustomSdpAttribute (const string &attributeName) const { + L_D(const MediaSessionParams); + return sal_custom_sdp_attribute_find(d->customSdpAttributes, attributeName.c_str()); +} + +// ----------------------------------------------------------------------------- + +void MediaSessionParams::addCustomSdpMediaAttribute (LinphoneStreamType lst, const string &attributeName, const string &attributeValue) { + L_D(MediaSessionParams); + d->customSdpMediaAttributes[lst] = sal_custom_sdp_attribute_append(d->customSdpMediaAttributes[lst], attributeName.c_str(), attributeValue.c_str()); +} + +void MediaSessionParams::clearCustomSdpMediaAttributes (LinphoneStreamType lst) { + L_D(MediaSessionParams); + d->setCustomSdpMediaAttributes(lst, nullptr); +} + +const char * MediaSessionParams::getCustomSdpMediaAttribute (LinphoneStreamType lst, const string &attributeName) const { + L_D(const MediaSessionParams); + return sal_custom_sdp_attribute_find(d->customSdpMediaAttributes[lst], attributeName.c_str()); +} + LINPHONE_END_NAMESPACE diff --git a/src/conference/params/media-session-params.h b/src/conference/params/media-session-params.h index 8916f9c03..a5f09fdcc 100644 --- a/src/conference/params/media-session-params.h +++ b/src/conference/params/media-session-params.h @@ -23,64 +23,25 @@ #include -extern "C" { - bool_t linphone_call_params_implicit_rtcp_fb_enabled(const LinphoneCallParams *params); - void linphone_call_params_enable_implicit_rtcp_fb(LinphoneCallParams *params, bool_t value); - int linphone_call_params_get_down_bandwidth(const LinphoneCallParams *params); - void linphone_call_params_set_down_bandwidth(LinphoneCallParams *params, int value); - int linphone_call_params_get_up_bandwidth(const LinphoneCallParams *params); - void linphone_call_params_set_up_bandwidth(LinphoneCallParams *params, int value); - int linphone_call_params_get_down_ptime(const LinphoneCallParams *params); - void linphone_call_params_set_down_ptime(LinphoneCallParams *params, int value); - int linphone_call_params_get_up_ptime(const LinphoneCallParams *params); - void linphone_call_params_set_up_ptime(LinphoneCallParams *params, int value); - bool_t linphone_call_params_get_update_call_when_ice_completed(const LinphoneCallParams *params); - void linphone_call_params_set_update_call_when_ice_completed(LinphoneCallParams *params, bool_t value); - void linphone_call_params_set_received_fps(LinphoneCallParams *params, float value); - void linphone_call_params_set_received_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef); - void linphone_call_params_set_recv_vsize(LinphoneCallParams *params, MSVideoSize vsize); - void linphone_call_params_set_sent_fps(LinphoneCallParams *params, float value); - void linphone_call_params_set_sent_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef); - void linphone_call_params_set_sent_vsize(LinphoneCallParams *params, MSVideoSize vsize); - void linphone_call_params_set_used_audio_codec(LinphoneCallParams *params, OrtpPayloadType *codec); - void linphone_call_params_set_used_video_codec(LinphoneCallParams *params, OrtpPayloadType *codec); - void linphone_call_params_set_used_text_codec(LinphoneCallParams *params, OrtpPayloadType *codec); -} - // ============================================================================= LINPHONE_BEGIN_NAMESPACE +class MediaSession; +class MediaSessionPrivate; class MediaSessionParamsPrivate; class MediaSessionParams : public CallSessionParams { - friend unsigned char ::linphone_call_params_implicit_rtcp_fb_enabled(const LinphoneCallParams *params); - friend void ::linphone_call_params_enable_implicit_rtcp_fb(LinphoneCallParams *params, unsigned char value); - friend int ::linphone_call_params_get_down_bandwidth(const LinphoneCallParams *params); - friend void ::linphone_call_params_set_down_bandwidth(LinphoneCallParams *params, int value); - friend int ::linphone_call_params_get_up_bandwidth(const LinphoneCallParams *params); - friend void ::linphone_call_params_set_up_bandwidth(LinphoneCallParams *params, int value); - friend int ::linphone_call_params_get_down_ptime(const LinphoneCallParams *params); - friend void ::linphone_call_params_set_down_ptime(LinphoneCallParams *params, int value); - friend int ::linphone_call_params_get_up_ptime(const LinphoneCallParams *params); - friend void ::linphone_call_params_set_up_ptime(LinphoneCallParams *params, int value); - friend unsigned char ::linphone_call_params_get_update_call_when_ice_completed(const LinphoneCallParams *params); - friend void ::linphone_call_params_set_update_call_when_ice_completed(LinphoneCallParams *params, unsigned char value); - friend void ::linphone_call_params_set_received_fps(LinphoneCallParams *params, float value); - friend void ::linphone_call_params_set_received_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef); - friend void ::linphone_call_params_set_recv_vsize(LinphoneCallParams *params, MSVideoSize vsize); - friend void ::linphone_call_params_set_sent_fps(LinphoneCallParams *params, float value); - friend void ::linphone_call_params_set_sent_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef); - friend void ::linphone_call_params_set_sent_vsize(LinphoneCallParams *params, MSVideoSize vsize); - friend void ::linphone_call_params_set_used_audio_codec(LinphoneCallParams *params, OrtpPayloadType *codec); - friend void ::linphone_call_params_set_used_video_codec(LinphoneCallParams *params, OrtpPayloadType *codec); - friend void ::linphone_call_params_set_used_text_codec(LinphoneCallParams *params, OrtpPayloadType *codec); + friend class MediaSession; + friend class MediaSessionPrivate; public: MediaSessionParams (); MediaSessionParams (const MediaSessionParams &src); virtual ~MediaSessionParams () = default; + void initDefault (LinphoneCore *core); + bool audioEnabled () const; bool audioMulticastEnabled () const; void enableAudio (bool value); @@ -132,6 +93,14 @@ public: SalMediaProto getMediaProto () const; const char * getRtpProfile () const; + void addCustomSdpAttribute (const std::string &attributeName, const std::string &attributeValue); + void clearCustomSdpAttributes (); + const char * getCustomSdpAttribute (const std::string &attributeName) const; + + void addCustomSdpMediaAttribute (LinphoneStreamType lst, const std::string &attributeName, const std::string &attributeValue); + void clearCustomSdpMediaAttributes (LinphoneStreamType lst); + const char * getCustomSdpMediaAttribute (LinphoneStreamType lst, const std::string &attributeName) const; + private: L_DECLARE_PRIVATE(MediaSessionParams); }; diff --git a/src/conference/participant-p.h b/src/conference/participant-p.h new file mode 100644 index 000000000..8bef6f69e --- /dev/null +++ b/src/conference/participant-p.h @@ -0,0 +1,53 @@ +/* + * participant-p.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _PARTICIPANT_P_H_ +#define _PARTICIPANT_P_H_ + +#include + +#include "object/object-p.h" + +#include "conference/participant.h" +#include "conference/session/call-session.h" +#include "conference/session/call-session-listener.h" +#include "conference/params/call-session-params.h" + +#include "linphone/types.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ParticipantPrivate : public ObjectPrivate { +public: + virtual ~ParticipantPrivate () = default; + + void createSession (const Conference &conference, const std::shared_ptr params, bool hasMedia, CallSessionListener *listener); + std::shared_ptr getSession () const; + + Address addr; + bool isAdmin = false; + std::shared_ptr session = nullptr; + + L_DECLARE_PUBLIC(Participant); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _PARTICIPANT_P_H_ diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index c636c1e6d..0739feb25 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -17,8 +17,11 @@ */ #include "object/object-p.h" +#include "participant-p.h" #include "participant.h" +#include "params/media-session-params.h" +#include "session/media-session.h" using namespace std; @@ -26,15 +29,17 @@ LINPHONE_BEGIN_NAMESPACE // ============================================================================= -class ParticipantPrivate : public ObjectPrivate { -public: - ~ParticipantPrivate (); +void ParticipantPrivate::createSession (const Conference &conference, const shared_ptr params, bool hasMedia, CallSessionListener *listener) { + if (hasMedia && (!params || dynamic_cast(params.get()))) { + session = make_shared(conference, params, listener); + } else { + session = make_shared(conference, params, listener); + } +} - Address addr; - bool isAdmin = false; -}; - -ParticipantPrivate::~ParticipantPrivate() {} +shared_ptr ParticipantPrivate::getSession () const { + return session; +} // ============================================================================= diff --git a/src/conference/participant.h b/src/conference/participant.h index 8a6ce2bca..bccb4f37b 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -22,6 +22,7 @@ #include "address/address.h" #include "object/object.h" +#include "conference/params/call-session-params.h" // ============================================================================= @@ -30,6 +31,11 @@ LINPHONE_BEGIN_NAMESPACE class ParticipantPrivate; class Participant : public Object { + friend class Call; + friend class CallPrivate; + friend class Conference; + friend class MediaSessionPrivate; + public: Participant (const Address &addr); diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index d73e2a17a..21fcbb3cb 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -30,6 +30,7 @@ public: // ============================================================================= -RemoteConference::RemoteConference () : Conference(*new RemoteConferencePrivate) {} +RemoteConference::RemoteConference (LinphoneCore *core, const Address &myAddress, CallListener *listener) + : Conference(*new RemoteConferencePrivate, core, myAddress, listener) {} LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index f6f456936..699c1b9c6 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -29,7 +29,7 @@ class RemoteConferencePrivate; class RemoteConference : public Conference { public: - RemoteConference (); + RemoteConference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); private: L_DECLARE_PRIVATE(RemoteConference); diff --git a/src/conference/session/call-session-listener.h b/src/conference/session/call-session-listener.h new file mode 100644 index 000000000..676330069 --- /dev/null +++ b/src/conference/session/call-session-listener.h @@ -0,0 +1,48 @@ +/* + * call-session-listener.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CALL_SESSION_LISTENER_H_ +#define _CALL_SESSION_LISTENER_H_ + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class CallSessionListener { +public: + virtual void ackBeingSent (const CallSession &session, LinphoneHeaders *headers) = 0; + virtual void ackReceived (const CallSession &session, LinphoneHeaders *headers) = 0; + virtual void callSessionAccepted (const CallSession &session) = 0; + virtual void callSessionSetReleased (const CallSession &session) = 0; + virtual void callSessionSetTerminated (const CallSession &session) = 0; + virtual void callSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message) = 0; + virtual void incomingCallSessionStarted (const CallSession &session) = 0; + + virtual void encryptionChanged (const CallSession &session, bool activated, const std::string &authToken) = 0; + + virtual void statsUpdated (const LinphoneCallStats *stats) = 0; + + virtual void setCurrentSession (const CallSession &session) = 0; + + virtual void firstVideoFrameDecoded (const CallSession &session) = 0; + virtual void resetFirstVideoFrameDecoded (const CallSession &session) = 0; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CALL_SESSION_LISTENER_H_ diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index e74d5b4a8..915120e17 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -19,21 +19,91 @@ #ifndef _CALL_SESSION_P_H_ #define _CALL_SESSION_P_H_ +#include +#include + #include "object/object-p.h" #include "call-session.h" -#include "bellesip_sal/sal_impl.h" - // ============================================================================= LINPHONE_BEGIN_NAMESPACE class CallSessionPrivate : public ObjectPrivate { public: - virtual ~CallSessionPrivate () = default; + CallSessionPrivate (const Conference &conference, const std::shared_ptr params, CallSessionListener *listener); + virtual ~CallSessionPrivate (); - SalOp *op; + int computeDuration () const; + virtual void initializeParamsAccordingToIncomingCallParams (); + virtual void setState (LinphoneCallState newState, const std::string &message); + bool startPing (); + void setPingTime (int value) { pingTime = value; } + + LinphoneProxyConfig * getDestProxy () const { return destProxy; } + SalOp * getOp () const { return op; } + + virtual void accepted (); + void ackBeingSent (LinphoneHeaders *headers); + virtual void ackReceived (LinphoneHeaders *headers); + virtual bool failure (); + void pingReply (); + virtual void remoteRinging (); + virtual void terminated (); + void updated (bool isUpdate); + void updatedByRemote (); + void updating (bool isUpdate); + +protected: + void accept (const std::shared_ptr params); + virtual LinphoneStatus acceptUpdate (const std::shared_ptr csp, LinphoneCallState nextState, const std::string &stateInfo); + LinphoneStatus checkForAcceptation () const; + virtual void handleIncomingReceivedStateInIncomingNotification (); + virtual bool isReadyForInvite () const; + bool isUpdateAllowed (LinphoneCallState &nextState) const; + virtual void setReleased (); + virtual void setTerminated (); + virtual LinphoneStatus startAcceptUpdate (LinphoneCallState nextState, const std::string &stateInfo); + virtual LinphoneStatus startUpdate (); + virtual void terminate (); + virtual void updateCurrentParams (); + + void setContactOp (); + +private: + void completeLog (); + void createOpTo (const LinphoneAddress *to); + + LinphoneAddress * getFixedContact () const; + +protected: + const Conference &conference; + LinphoneCore *core = nullptr; + CallSessionListener *listener = nullptr; + + std::shared_ptr params = nullptr; + std::shared_ptr currentParams = nullptr; + std::shared_ptr remoteParams = nullptr; + + LinphoneCallDir direction = LinphoneCallOutgoing; + LinphoneCallState state = LinphoneCallIdle; + LinphoneCallState prevState = LinphoneCallIdle; + //LinphoneCallState transferState = LinphoneCallIdle; + LinphoneProxyConfig *destProxy = nullptr; + LinphoneErrorInfo *ei = nullptr; + LinphoneCallLog *log = nullptr; + LinphoneNatPolicy *natPolicy = nullptr; + + SalOp *op = nullptr; + + SalOp *pingOp = nullptr; + bool pingReplied = false; + int pingTime = 0; + + bool deferIncomingNotification = false; + bool deferUpdate = false; + bool nonOpError = false; /* Set when the LinphoneErrorInfo was set at higher level than sal */ L_DECLARE_PUBLIC(CallSession); }; diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 1bae79848..de05172b7 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -16,14 +16,1085 @@ * along with this program. If not, see . */ -#include "call-session-p.h" +#include -#include "call-session.h" +#include "c-wrapper/c-tools.h" + +#include "address/address-p.h" +#include "conference/session/call-session-p.h" +#include "call/call-p.h" +#include "conference/conference-p.h" +#include "conference/params/call-session-params-p.h" + +#include "conference/session/call-session.h" + +#include "logger/logger.h" + +#include "linphone/core.h" + +#include "private.h" + +using namespace std; LINPHONE_BEGIN_NAMESPACE // ============================================================================= +CallSessionPrivate::CallSessionPrivate (const Conference &conference, const shared_ptr params, CallSessionListener *listener) + : conference(conference), listener(listener) { + if (params) + this->params = make_shared(*params.get()); + currentParams = make_shared(); + core = conference.getPrivate()->getCore(); + ei = linphone_error_info_new(); +} + +CallSessionPrivate::~CallSessionPrivate () { + if (ei) + linphone_error_info_unref(ei); + if (log) + linphone_call_log_unref(log); + if (natPolicy) + linphone_nat_policy_unref(natPolicy); + if (op) + sal_op_release(op); +} + +// ----------------------------------------------------------------------------- + +int CallSessionPrivate::computeDuration () const { + if (log->connected_date_time == 0) + return 0; + return (int)(ms_time(nullptr) - log->connected_date_time); +} + +/* + * Initialize call parameters according to incoming call parameters. This is to avoid to ask later (during reINVITEs) for features that the remote + * end apparently does not support. This features are: privacy, video... + */ +void CallSessionPrivate::initializeParamsAccordingToIncomingCallParams () { + currentParams->setPrivacy((LinphonePrivacyMask)sal_op_get_privacy(op)); +} + +void CallSessionPrivate::setState(LinphoneCallState newState, const string &message) { + L_Q(CallSession); + if (state != newState){ + prevState = state; + + /* Make sanity checks with call state changes. Any bad transition can result in unpredictable results + or irrecoverable errors in the application. */ + if ((state == LinphoneCallEnd) || (state == LinphoneCallError)) { + if (newState != LinphoneCallReleased) { + lFatal() << "Abnormal call resurection from " << linphone_call_state_to_string(state) << + " to " << linphone_call_state_to_string(newState) << " , aborting"; + return; + } + } else if ((newState == LinphoneCallReleased) && (prevState != LinphoneCallError) && (prevState != LinphoneCallEnd)) { + lFatal() << "Attempt to move CallSession [" << q << "] to Released state while it was not previously in Error or End state, aborting"; + return; + } + lInfo() << "CallSession [" << q << "] moving from state " << linphone_call_state_to_string(state) << " to " << linphone_call_state_to_string(newState); + + if (newState != LinphoneCallRefered) { + /* LinphoneCallRefered is rather an event, not a state. + Indeed it does not change the state of the call (still paused or running). */ + state = newState; + } + + switch (newState) { + case LinphoneCallOutgoingInit: + case LinphoneCallIncomingReceived: +#ifdef __ANDROID__ + lInfo() << "CallSession [" << q << "] acquires both wifi and multicast lock"; + linphone_core_wifi_lock_acquire(core); + linphone_core_multicast_lock_acquire(core); /* Does no affect battery more than regular rtp traffic */ +#endif + break; + case LinphoneCallEnd: + case LinphoneCallError: + switch (linphone_error_info_get_reason(q->getErrorInfo())) { + case LinphoneReasonDeclined: + log->status = LinphoneCallDeclined; + break; + case LinphoneReasonNotAnswered: + if (log->dir == LinphoneCallIncoming) + log->status = LinphoneCallMissed; + break; + case LinphoneReasonNone: + if (log->dir == LinphoneCallIncoming) { + if (ei) { + int code = linphone_error_info_get_protocol_code(ei); + if ((code >= 200) && (code < 300)) + log->status = LinphoneCallAcceptedElsewhere; + } + } + break; + case LinphoneReasonDoNotDisturb: + if (log->dir == LinphoneCallIncoming) { + if (ei) { + int code = linphone_error_info_get_protocol_code(ei); + if ((code >= 600) && (code < 700)) + log->status = LinphoneCallDeclinedElsewhere; + } + } + break; + default: + break; + } + setTerminated(); + break; + case LinphoneCallConnected: + log->status = LinphoneCallSuccess; + log->connected_date_time = ms_time(nullptr); + break; + case LinphoneCallReleased: +#ifdef __ANDROID__ + lInfo() << "CallSession [" << q << "] releases wifi/multicast lock"; + linphone_core_wifi_lock_release(core); + linphone_core_multicast_lock_release(core); +#endif + break; + case LinphoneCallStreamsRunning: + if ((prevState == LinphoneCallUpdating) || (prevState == LinphoneCallUpdatedByRemote)) { + LinphoneReason reason = linphone_error_info_get_reason(ei); + char *msg; + if (reason != LinphoneReasonNone) { + msg = ms_strdup_printf(_("Call parameters could not be modified: %s."), linphone_reason_to_string(reason)); + } else { + msg = ms_strdup(_("Call parameters were successfully modified.")); + } + linphone_core_notify_display_status(core, msg); + ms_free(msg); + } + break; + default: + break; + } + + if (newState != LinphoneCallStreamsRunning) { +#if 0 // TODO + if (call->dtmfs_timer!=NULL){ + /*cancelling DTMF sequence, if any*/ + linphone_call_cancel_dtmfs(call); + } +#endif + } + if (message.empty()) { + lError() << "You must fill a reason when changing call state (from " << + linphone_call_state_to_string(prevState) << " to " << linphone_call_state_to_string(state) << ")"; + } + if (listener) + listener->callSessionStateChanged(*q, state, message); + if (newState == LinphoneCallReleased) + setReleased(); /* Shall be performed after app notification */ + } +} + +bool CallSessionPrivate::startPing () { + if (core->sip_conf.ping_with_options) { + /* Defer the start of the call after the OPTIONS ping for outgoing call or + * send an option request back to the caller so that we get a chance to discover our nat'd address + * before answering for incoming call */ + pingReplied = false; + pingOp = sal_op_new(core->sal); + if (direction == LinphoneCallIncoming) { + const char *from = sal_op_get_from(pingOp); + const char *to = sal_op_get_to(pingOp); + linphone_configure_op(core, pingOp, log->from, nullptr, false); + sal_op_set_route(pingOp, sal_op_get_network_origin(op)); + sal_ping(pingOp, from, to); + } else if (direction == LinphoneCallOutgoing) { + char *from = linphone_address_as_string(log->from); + char *to = linphone_address_as_string(log->to); + sal_ping(pingOp, from, to); + ms_free(from); + ms_free(to); + } + sal_op_set_user_pointer(pingOp, this); + return true; + } + return false; +} + +// ----------------------------------------------------------------------------- + +void CallSessionPrivate::accepted () { + L_Q(CallSession); + char *msg = nullptr; + /* Immediately notify the connected state, even if errors occur after */ + switch (state) { + case LinphoneCallOutgoingProgress: + case LinphoneCallOutgoingRinging: + case LinphoneCallOutgoingEarlyMedia: + /* Immediately notify the connected state */ + setState(LinphoneCallConnected, "Connected"); + msg = ms_strdup_printf(_("Call answered by %s"), q->getRemoteAddressAsString().c_str()); + linphone_core_notify_display_status(core, msg); + ms_free(msg); + break; + default: + break; + } + currentParams->setPrivacy((LinphonePrivacyMask)sal_op_get_privacy(op)); +} + +void CallSessionPrivate::ackBeingSent (LinphoneHeaders *headers) { + L_Q(CallSession); + if (listener) + listener->ackBeingSent(*q, headers); +} + +void CallSessionPrivate::ackReceived (LinphoneHeaders *headers) { + L_Q(CallSession); + if (listener) + listener->ackReceived(*q, headers); +} + +bool CallSessionPrivate::failure () { + L_Q(CallSession); + linphone_core_notify_show_interface(core); + const char *msg = ei->full_string; + const char *msg486 = "User is busy."; + const char *msg480 = "User is temporarily unavailable."; + const char *msg600 = "User does not want to be disturbed."; + const char *msg603 = "Call declined."; + const SalErrorInfo *ei = sal_op_get_error_info(op); + switch (ei->reason) { + case SalReasonNone: + break; + case SalReasonRequestTimeout: + msg = "Request timeout."; + linphone_core_notify_display_status(core, msg); + break; + case SalReasonDeclined: + linphone_core_notify_display_status(core, msg603); + break; + case SalReasonBusy: + linphone_core_notify_display_status(core, msg486); + break; + case SalReasonRedirect: + if ((state == LinphoneCallOutgoingInit) || (state == LinphoneCallOutgoingProgress) + || (state == LinphoneCallOutgoingRinging) /* Push notification case */ || (state == LinphoneCallOutgoingEarlyMedia)) { + const SalAddress *redirectionTo = sal_op_get_remote_contact_address(op); + if (redirectionTo) { + char *url = sal_address_as_string(redirectionTo); + lWarning() << "Redirecting CallSession [" << q << "] to " << url; + if (log->to) + linphone_address_unref(log->to); + log->to = linphone_address_new(url); + ms_free(url); +#if 0 + linphone_call_restart_invite(call); +#endif + return true; + } + msg = "Redirected"; + linphone_core_notify_display_status(core, msg); + } + break; + case SalReasonTemporarilyUnavailable: + linphone_core_notify_display_status(core, msg480); + break; + case SalReasonNotFound: + linphone_core_notify_display_status(core, msg); + break; + case SalReasonDoNotDisturb: + linphone_core_notify_display_status(core, msg600); + break; + case SalReasonUnsupportedContent: /* This is for compatibility: linphone sent 415 because of SDP offer answer failure */ + case SalReasonNotAcceptable: + break; + default: + linphone_core_notify_display_status(core, "Call failed."); + break; + } + + /* Some call errors are not fatal */ + switch (state) { + case LinphoneCallUpdating: + case LinphoneCallPausing: + case LinphoneCallResuming: + if (ei->reason != SalReasonNoMatch) { + lInfo() << "Call error on state [" << linphone_call_state_to_string(state) << "], restoring previous state [" << linphone_call_state_to_string(prevState) << "]"; + setState(prevState, ei->full_string); + return true; + } + default: + break; + } + + if ((state != LinphoneCallEnd) && (state != LinphoneCallError)) { + if (ei->reason == SalReasonDeclined) + setState(LinphoneCallEnd, "Call declined"); + else { + if (linphone_call_state_is_early(state)) + setState(LinphoneCallError, ei->full_string); + else + setState(LinphoneCallEnd, ei->full_string); + } +#if 0 // TODO: handle in Call class + if (ei->reason != SalReasonNone) + linphone_core_play_call_error_tone(core, linphone_reason_from_sal(ei->reason)); +#endif + } +#if 0 + LinphoneCall *referer=call->referer; + if (referer){ + /*notify referer of the failure*/ + linphone_core_notify_refer_state(lc,referer,call); + /*schedule automatic resume of the call. This must be done only after the notifications are completed due to dialog serialization of requests.*/ + linphone_core_queue_task(lc,(belle_sip_source_func_t)resume_call_after_failed_transfer,linphone_call_ref(referer),"Automatic call resuming after failed transfer"); + } +#endif + return false; +} + +void CallSessionPrivate::pingReply () { + L_Q(CallSession); + if (state == LinphoneCallOutgoingInit) { + pingReplied = true; + if (isReadyForInvite()) + q->startInvite(nullptr); + } +} + +void CallSessionPrivate::remoteRinging () { + L_Q(CallSession); + /* Set privacy */ + q->getCurrentParams()->setPrivacy((LinphonePrivacyMask)sal_op_get_privacy(op)); + linphone_core_notify_display_status(core, _("Remote ringing.")); +#if 0 + if (lc->ringstream == NULL) start_remote_ring(lc, call); +#endif + lInfo() << "Remote ringing..."; + linphone_core_notify_display_status(core, _("Remote ringing...")); + setState(LinphoneCallOutgoingRinging, "Remote ringing"); +} + +void CallSessionPrivate::terminated () { + switch (state) { + case LinphoneCallEnd: + case LinphoneCallError: + lWarning() << "terminated: already terminated, ignoring"; + return; + case LinphoneCallIncomingReceived: + case LinphoneCallIncomingEarlyMedia: + if (!sal_op_get_reason_error_info(op)->protocol || strcmp(sal_op_get_reason_error_info(op)->protocol, "") == 0) { + linphone_error_info_set(ei, nullptr, LinphoneReasonNotAnswered, 0, "Incoming call cancelled", nullptr); + nonOpError = true; + } + break; + default: + break; + } +#if 0 + if (call->refer_pending) + linphone_core_start_refered_call(lc,call,NULL); + //we stop the call only if we have this current call or if we are in call + if ((bctbx_list_size(lc->calls) == 1) || linphone_core_in_call(lc)) { + linphone_core_stop_ringing(lc); + } +#endif + linphone_core_notify_show_interface(core); + linphone_core_notify_display_status(core, _("Call terminated.")); + setState(LinphoneCallEnd, "Call ended"); +} + +void CallSessionPrivate::updated (bool isUpdate) { + deferUpdate = lp_config_get_int(linphone_core_get_config(core), "sip", "defer_update_default", FALSE); + SalErrorInfo sei; + memset(&sei, 0, sizeof(sei)); + switch (state) { + case LinphoneCallPausedByRemote: + updatedByRemote(); + break; + /* SIP UPDATE CASE */ + case LinphoneCallOutgoingRinging: + case LinphoneCallOutgoingEarlyMedia: + case LinphoneCallIncomingEarlyMedia: + if (isUpdate) { + setState(LinphoneCallEarlyUpdatedByRemote, "EarlyUpdatedByRemote"); + acceptUpdate(nullptr, prevState, linphone_call_state_to_string(prevState)); + } + break; + case LinphoneCallStreamsRunning: + case LinphoneCallConnected: + case LinphoneCallUpdatedByRemote: /* Can happen on UAC connectivity loss */ + updatedByRemote(); + break; + case LinphoneCallPaused: + /* We'll remain in pause state but accept the offer anyway according to default parameters */ + acceptUpdate(nullptr, state, linphone_call_state_to_string(state)); + break; + case LinphoneCallUpdating: + case LinphoneCallPausing: + case LinphoneCallResuming: + sal_error_info_set(&sei, SalReasonInternalError, "SIP", 0, nullptr, nullptr); + sal_call_decline_with_error_info(op, &sei, nullptr); + BCTBX_NO_BREAK; /* no break */ + case LinphoneCallIdle: + case LinphoneCallOutgoingInit: + case LinphoneCallEnd: + case LinphoneCallIncomingReceived: + case LinphoneCallOutgoingProgress: + case LinphoneCallRefered: + case LinphoneCallError: + case LinphoneCallReleased: + case LinphoneCallEarlyUpdatedByRemote: + case LinphoneCallEarlyUpdating: + lWarning() << "Receiving reINVITE or UPDATE while in state [" << linphone_call_state_to_string(state) << "], should not happen"; + break; + } +} + +void CallSessionPrivate::updatedByRemote () { + L_Q(CallSession); + linphone_core_notify_display_status(core, "Call is updated by remote"); + setState(LinphoneCallUpdatedByRemote,"Call updated by remote"); + if (deferUpdate) { + if (state == LinphoneCallUpdatedByRemote) + lInfo() << "CallSession [" << q << "]: UpdatedByRemoted was signaled but defered. LinphoneCore expects the application to call linphone_core_accept_call_update() later."; + } else { + if (state == LinphoneCallUpdatedByRemote) + q->acceptUpdate(nullptr); + else { + /* Otherwise it means that the app responded by linphone_core_accept_call_update + * within the callback, so job is already done. */ + } + } +} + +void CallSessionPrivate::updating (bool isUpdate) { + updated(isUpdate); +} + +// ----------------------------------------------------------------------------- + +void CallSessionPrivate::accept (const shared_ptr params) { + L_Q(CallSession); + /* Try to be best-effort in giving real local or routable contact address */ + setContactOp(); + if (params) { + this->params = params; + sal_op_set_sent_custom_header(op, params->getPrivate()->getCustomHeaders()); + } + + sal_call_accept(op); + linphone_core_notify_display_status(core, _("Connected.")); + if (listener) + listener->setCurrentSession(*q); + setState(LinphoneCallConnected, "Connected"); +} + +LinphoneStatus CallSessionPrivate::acceptUpdate (const shared_ptr csp, LinphoneCallState nextState, const string &stateInfo) { + return startAcceptUpdate(nextState, stateInfo); +} + +LinphoneStatus CallSessionPrivate::checkForAcceptation () const { + L_Q(const CallSession); + switch (state) { + case LinphoneCallIncomingReceived: + case LinphoneCallIncomingEarlyMedia: + break; + default: + lError() << "checkForAcceptation() CallSession [" << q << "] is in state [" << linphone_call_state_to_string(state) << "], operation not permitted"; + return -1; + } + bctbx_list_t *copy = bctbx_list_copy(linphone_core_get_calls(core)); + for (bctbx_list_t *it = copy; it != nullptr; it = bctbx_list_next(it)) { + LinphoneCall *call = reinterpret_cast(bctbx_list_get_data(it)); + shared_ptr session = linphone_call_get_cpp_obj(call)->getPrivate()->getActiveSession(); + if (session.get() == q) continue; + switch (session->getState()) { + case LinphoneCallOutgoingInit: + case LinphoneCallOutgoingProgress: + case LinphoneCallOutgoingRinging: + case LinphoneCallOutgoingEarlyMedia: + lInfo() << "Already existing CallSession [" << session << "] in state [" << linphone_call_state_to_string(session->getState()) + << "], canceling it before accepting new CallSession [" << q << "]"; + session->terminate(); + break; + default: + break; /* Nothing to do */ + } + } + bctbx_list_free(copy); + + /* Check if this call is supposed to replace an already running one */ + SalOp *replaced = sal_call_get_replaces(op); + if (replaced) { + CallSession *session = reinterpret_cast(sal_op_get_user_pointer(replaced)); + if (session) { + lInfo() << "CallSession " << q << " replaces CallSession " << session << ". This last one is going to be terminated automatically"; + session->terminate(); + } + } + return 0; +} + +void CallSessionPrivate::handleIncomingReceivedStateInIncomingNotification () { + L_Q(CallSession); + /* Try to be best-effort in giving real local or routable contact address for 100Rel case */ + setContactOp(); + sal_call_notify_ringing(op, false); + if (sal_call_get_replaces(op) && lp_config_get_int(linphone_core_get_config(core), "sip", "auto_answer_replacing_calls", 1)) + q->accept(); +} + +bool CallSessionPrivate::isReadyForInvite () const { + bool pingReady = false; + if (pingOp) { + if (pingReplied) + pingReady = true; + } else + pingReady = true; + return pingReady; +} + +bool CallSessionPrivate::isUpdateAllowed (LinphoneCallState &nextState) const { + switch (state) { + case LinphoneCallIncomingReceived: + case LinphoneCallIncomingEarlyMedia: + case LinphoneCallOutgoingRinging: + case LinphoneCallOutgoingEarlyMedia: + nextState = LinphoneCallEarlyUpdating; + break; + case LinphoneCallStreamsRunning: + case LinphoneCallPausedByRemote: + case LinphoneCallUpdatedByRemote: + nextState = LinphoneCallUpdating; + break; + case LinphoneCallPaused: + nextState = LinphoneCallPausing; + break; + case LinphoneCallOutgoingProgress: + case LinphoneCallPausing: + case LinphoneCallResuming: + case LinphoneCallUpdating: + nextState = state; + break; + default: + lError() << "Update is not allowed in [" << linphone_call_state_to_string(state) << "] state"; + return false; + } + return true; +} + +/* + * Called internally when reaching the Released state, to perform cleanups to break circular references. +**/ +void CallSessionPrivate::setReleased () { + L_Q(CallSession); + if (op) { + /* Transfer the last error so that it can be obtained even in Released state */ + if (!nonOpError) + linphone_error_info_from_sal_op(ei, op); + /* So that we cannot have anymore upcalls for SAL concerning this call */ + sal_op_release(op); + op = nullptr; + } +#if 0 + /* It is necessary to reset pointers to other call to prevent circular references that would result in memory never freed */ + if (call->referer){ + linphone_call_unref(call->referer); + call->referer=NULL; + } + if (call->transfer_target){ + linphone_call_unref(call->transfer_target); + call->transfer_target=NULL; + } + if (call->chat_room){ + linphone_chat_room_unref(call->chat_room); + call->chat_room = NULL; + } +#endif + if (listener) + listener->callSessionSetReleased(*q); +} + +/* This method is called internally to get rid of a call that was notified to the application, + * because it reached the end or error state. It performs the following tasks: + * - remove the call from the internal list of calls + * - update the call logs accordingly + */ +void CallSessionPrivate::setTerminated() { + L_Q(CallSession); + completeLog(); + if (listener) + listener->callSessionSetTerminated(*q); +} + +LinphoneStatus CallSessionPrivate::startAcceptUpdate (LinphoneCallState nextState, const std::string &stateInfo) { + sal_call_accept(op); + setState(nextState, stateInfo); + return 0; +} + +LinphoneStatus CallSessionPrivate::startUpdate () { + L_Q(CallSession); + string subject; + if (q->getParams()->getPrivate()->getInConference()) + subject = "Conference"; + else if (q->getParams()->getPrivate()->getInternalCallUpdate()) + subject = "ICE processing concluded"; + else if (q->getParams()->getPrivate()->getNoUserConsent()) + subject = "Refreshing"; + else + subject = "Media change"; + linphone_core_notify_display_status(core, "Modifying call parameters..."); + if (destProxy && destProxy->op) { + /* Give a chance to update the contact address if connectivity has changed */ + sal_op_set_contact_address(op, sal_op_get_contact_address(destProxy->op)); + } else + sal_op_set_contact_address(op, nullptr); + return sal_call_update(op, subject.c_str(), q->getParams()->getPrivate()->getNoUserConsent()); +} + +void CallSessionPrivate::terminate () { + if ((state == LinphoneCallIncomingReceived) && (linphone_error_info_get_reason(ei) != LinphoneReasonNotAnswered)) { + linphone_error_info_set_reason(ei, LinphoneReasonDeclined); + nonOpError = true; + } + linphone_core_notify_display_status(core, _("Call ended")); + setState(LinphoneCallEnd, "Call terminated"); +} + +void CallSessionPrivate::updateCurrentParams () {} + +// ----------------------------------------------------------------------------- + +void CallSessionPrivate::setContactOp () { + SalAddress *salAddress = nullptr; + LinphoneAddress *contact = getFixedContact(); + if (contact) { + salAddress = const_cast(L_GET_PRIVATE_FROM_C_STRUCT(contact, Address)->getInternalAddress()); + sal_address_ref(salAddress); + linphone_address_unref(contact); + } + sal_op_set_and_clean_contact_address(op, salAddress); +} + +// ----------------------------------------------------------------------------- + +void CallSessionPrivate::completeLog () { + log->duration = computeDuration(); /* Store duration since connected */ + log->error_info = linphone_error_info_ref(ei); + if (log->status == LinphoneCallMissed) { + core->missed_calls++; + char *info = bctbx_strdup_printf(ngettext("You have missed %i call.", "You have missed %i calls.", core->missed_calls), core->missed_calls); + linphone_core_notify_display_status(core, info); + bctbx_free(info); + } + linphone_core_report_call_log(core, log); +} + +void CallSessionPrivate::createOpTo (const LinphoneAddress *to) { + L_Q(CallSession); + if (op) + sal_op_release(op); + op = sal_op_new(core->sal); + sal_op_set_user_pointer(op, q); +#if 0 + if (linphone_call_params_get_referer(call->params)) + sal_call_set_referer(call->op,linphone_call_params_get_referer(call->params)->op); +#endif + linphone_configure_op(core, op, to, q->getParams()->getPrivate()->getCustomHeaders(), false); + if (q->getParams()->getPrivacy() != LinphonePrivacyDefault) + sal_op_set_privacy(op, (SalPrivacyMask)q->getParams()->getPrivacy()); + /* else privacy might be set by proxy */ +} + +// ----------------------------------------------------------------------------- + +LinphoneAddress * CallSessionPrivate::getFixedContact () const { + LinphoneAddress *result = nullptr; + if (op && sal_op_get_contact_address(op)) { + /* If already choosed, don't change it */ + return nullptr; + } else if (pingOp && sal_op_get_contact_address(pingOp)) { + /* If the ping OPTIONS request succeeded use the contact guessed from the received, rport */ + lInfo() << "Contact has been fixed using OPTIONS"; + char *addr = sal_address_as_string(sal_op_get_contact_address(pingOp)); + result = linphone_address_new(addr); + ms_free(addr); + } else if (destProxy && destProxy->op && sal_op_get_contact_address(destProxy->op)) { + /* If using a proxy, use the contact address as guessed with the REGISTERs */ + lInfo() << "Contact has been fixed using proxy"; + char *addr = sal_address_as_string(sal_op_get_contact_address(destProxy->op)); + result = linphone_address_new(addr); + ms_free(addr); + } else { + result = linphone_core_get_primary_contact_parsed(core); + if (result) { + /* Otherwise use supplied localip */ + linphone_address_set_domain(result, nullptr /* localip */); + linphone_address_set_port(result, -1 /* linphone_core_get_sip_port(core) */); + lInfo() << "Contact has not been fixed, stack will do"; + } + } + return result; +} + +// ============================================================================= + +CallSession::CallSession (const Conference &conference, const shared_ptr params, CallSessionListener *listener) + : Object(*new CallSessionPrivate(conference, params, listener)) { + lInfo() << "New CallSession [" << this << "] initialized (LinphoneCore version: " << linphone_core_get_version() << ")"; +} + CallSession::CallSession (CallSessionPrivate &p) : Object(p) {} +// ----------------------------------------------------------------------------- + +LinphoneStatus CallSession::accept (const shared_ptr csp) { + L_D(CallSession); + LinphoneStatus result = d->checkForAcceptation(); + if (result < 0) return result; + d->accept(csp); + return 0; +} + +LinphoneStatus CallSession::acceptUpdate (const shared_ptr csp) { + L_D(CallSession); + if (d->state != LinphoneCallUpdatedByRemote) { + lError() << "CallSession::acceptUpdate(): invalid state " << linphone_call_state_to_string(d->state) << " to call this method"; + return -1; + } + return d->acceptUpdate(csp, d->prevState, linphone_call_state_to_string(d->prevState)); +} + +void CallSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalOp *op, const Address &from, const Address &to) { + L_D(CallSession); + d->direction = direction; + d->destProxy = cfg; + LinphoneAddress *fromAddr = linphone_address_new(from.asString().c_str()); + LinphoneAddress *toAddr = linphone_address_new(to.asString().c_str()); + if (!d->destProxy) { + /* Try to define the destination proxy if it has not already been done to have a correct contact field in the SIP messages */ + d->destProxy = linphone_core_lookup_known_proxy(d->core, toAddr); + } + d->log = linphone_call_log_new(direction, fromAddr, toAddr); + + if (d->destProxy) + d->natPolicy = linphone_proxy_config_get_nat_policy(d->destProxy); + if (!d->natPolicy) + d->natPolicy = linphone_core_get_nat_policy(d->core); + linphone_nat_policy_ref(d->natPolicy); + + if (op) { + /* We already have an op for incoming calls */ + d->op = op; + sal_op_set_user_pointer(d->op, this); + sal_op_cnx_ip_to_0000_if_sendonly_enable(op, lp_config_get_default_int(linphone_core_get_config(d->core), + "sip", "cnx_ip_to_0000_if_sendonly_enabled", 0)); + d->log->call_id = ms_strdup(sal_op_get_call_id(op)); /* Must be known at that time */ + } + + if (direction == LinphoneCallOutgoing) { + d->startPing(); + } else if (direction == LinphoneCallIncoming) { + d->params = make_shared(); + d->params->initDefault(d->core); + } +} + +LinphoneStatus CallSession::decline (LinphoneReason reason) { + LinphoneErrorInfo *ei = linphone_error_info_new(); + linphone_error_info_set(ei, "SIP", reason, linphone_reason_to_error_code(reason), nullptr, nullptr); + LinphoneStatus status = decline(ei); + linphone_error_info_unref(ei); + return status; +} + +LinphoneStatus CallSession::decline (const LinphoneErrorInfo *ei) { + L_D(CallSession); + SalErrorInfo sei; + SalErrorInfo sub_sei; + memset(&sei, 0, sizeof(sei)); + memset(&sub_sei, 0, sizeof(sub_sei)); + sei.sub_sei = &sub_sei; + if ((d->state != LinphoneCallIncomingReceived) && (d->state != LinphoneCallIncomingEarlyMedia)) { + lError() << "Cannot decline a CallSession that is in state " << linphone_call_state_to_string(d->state); + return -1; + } + if (ei) { + linphone_error_info_to_sal(ei, &sei); + sal_call_decline_with_error_info(d->op, &sei , nullptr); + } else + sal_call_decline(d->op, SalReasonDeclined, nullptr); + sal_error_info_reset(&sei); + sal_error_info_reset(&sub_sei); + d->terminate(); + return 0; +} + +void CallSession::initiateIncoming () {} + +bool CallSession::initiateOutgoing () { + L_D(CallSession); + bool defer = false; + d->setState(LinphoneCallOutgoingInit, "Starting outgoing call"); + d->log->start_date_time = ms_time(nullptr); + if (!d->destProxy) + defer = d->startPing(); + if (d->direction == LinphoneCallOutgoing) { + d->createOpTo(d->log->to); + } + return defer; +} + +void CallSession::iterate (time_t currentRealTime, bool oneSecondElapsed) { + L_D(CallSession); + int elapsed = (int)(currentRealTime - d->log->start_date_time); + if ((d->state == LinphoneCallOutgoingInit) && (elapsed >= d->core->sip_conf.delayed_timeout)) { + /* Start the call even if the OPTIONS reply did not arrive */ + startInvite(nullptr); + } + if ((d->state == LinphoneCallIncomingReceived) || (d->state == LinphoneCallIncomingEarlyMedia)) { + if (oneSecondElapsed) + lInfo() << "Incoming call ringing for " << elapsed << " seconds"; + if (elapsed > d->core->sip_conf.inc_timeout) { + lInfo() << "Incoming call timeout (" << d->core->sip_conf.inc_timeout << ")"; +#if 0 + LinphoneReason declineReason = (core->current_call != call) ? LinphoneReasonBusy : LinphoneReasonDeclined; +#endif + d->log->status = LinphoneCallMissed; +#if 0 + call->non_op_error = TRUE; + linphone_error_info_set(call->ei, NULL, decline_reason, linphone_reason_to_error_code(decline_reason), "Not answered", NULL); + linphone_call_decline(call, decline_reason); +#endif + } + } + if ((d->core->sip_conf.in_call_timeout > 0) && (d->log->connected_date_time != 0) + && ((currentRealTime - d->log->connected_date_time) > d->core->sip_conf.in_call_timeout)) { + lInfo() << "In call timeout (" << d->core->sip_conf.in_call_timeout << ")"; + terminate(); + } +} + +void CallSession::startIncomingNotification () { + L_D(CallSession); + if (d->listener) + d->listener->callSessionAccepted(*this); + /* Prevent the CallSession from being destroyed while we are notifying, if the user declines within the state callback */ + shared_ptr ref = shared_from_this(); +#if 0 + call->bg_task_id=sal_begin_background_task("liblinphone call notification", NULL, NULL); +#endif + if (d->deferIncomingNotification) { + lInfo() << "Defer ringing"; + return; + } + + LinphoneAddress *fromParsed = linphone_address_new(sal_op_get_from(d->op)); + linphone_address_clean(fromParsed); + char *tmp = linphone_address_as_string(fromParsed); + linphone_address_unref(fromParsed); + char *msg = ms_strdup_printf("%s %s%s", tmp, _("is contacting you"), (sal_call_autoanswer_asked(d->op)) ? _(" and asked autoanswer") : ""); + ms_free(tmp); + linphone_core_notify_show_interface(d->core); + linphone_core_notify_display_status(d->core, msg); + ms_free(msg); + + if (d->listener) + d->listener->incomingCallSessionStarted(*this); + + d->setState(LinphoneCallIncomingReceived, "Incoming call"); + + /* From now on, the application is aware of the call and supposed to take background task or already submitted notification to the user. + * We can then drop our background task. */ +#if 0 + if (call->bg_task_id!=0) { + sal_end_background_task(call->bg_task_id); + call->bg_task_id=0; + } +#endif + + if (d->state == LinphoneCallIncomingReceived) { + d->handleIncomingReceivedStateInIncomingNotification(); + } +} + +int CallSession::startInvite (const Address *destination) { + L_D(CallSession); + /* Try to be best-effort in giving real local or routable contact address */ + d->setContactOp(); + string destinationStr; + char *realUrl = nullptr; + if (destination) + destinationStr = destination->asString(); + else { + realUrl = linphone_address_as_string(d->log->to); + destinationStr = realUrl; + ms_free(realUrl); + } + ostringstream os; + os << "Contacting " << destinationStr; + linphone_core_notify_display_status(d->core, os.str().c_str()); + char *from = linphone_address_as_string(d->log->from); + /* Take a ref because sal_call() may destroy the CallSession if no SIP transport is available */ + shared_ptr ref = shared_from_this(); + int result = sal_call(d->op, from, destinationStr.c_str()); + ms_free(from); + if (result < 0) { + if ((d->state != LinphoneCallError) && (d->state != LinphoneCallReleased)) { + /* sal_call() may invoke call_failure() and call_released() SAL callbacks synchronously, + in which case there is no need to perform a state change here. */ + linphone_core_notify_display_status(d->core, _("Could not call")); + d->setState(LinphoneCallError, "Call failed"); + } + } else { + d->log->call_id = ms_strdup(sal_op_get_call_id(d->op)); /* Must be known at that time */ + d->setState(LinphoneCallOutgoingProgress, "Outgoing call in progress"); + } + return result; +} + +LinphoneStatus CallSession::terminate (const LinphoneErrorInfo *ei) { + L_D(CallSession); + lInfo() << "Terminate CallSession [" << this << "] which is currently in state [" << linphone_call_state_to_string(d->state) << "]"; + SalErrorInfo sei; + memset(&sei, 0, sizeof(sei)); + switch (d->state) { + case LinphoneCallReleased: + case LinphoneCallEnd: + case LinphoneCallError: + lWarning() << "No need to terminate CallSession [" << this << "] in state [" << linphone_call_state_to_string(d->state) << "]"; + return -1; + case LinphoneCallIncomingReceived: + case LinphoneCallIncomingEarlyMedia: + return decline(ei); + case LinphoneCallOutgoingInit: + /* In state OutgoingInit, op has to be destroyed */ + sal_op_release(d->op); + d->op = nullptr; + break; + default: + if (ei) { + linphone_error_info_to_sal(ei, &sei); + sal_call_terminate_with_error(d->op, &sei); + sal_error_info_reset(&sei); + } else + sal_call_terminate(d->op); + break; + } + + d->terminate(); + return 0; +} + +LinphoneStatus CallSession::update (const shared_ptr csp) { + L_D(CallSession); + LinphoneCallState nextState; + LinphoneCallState initialState = d->state; + if (!d->isUpdateAllowed(nextState)) + return -1; + if (d->currentParams.get() == csp.get()) + lWarning() << "CallSession::update() is given the current params, this is probably not what you intend to do!"; + LinphoneStatus result = d->startUpdate(); + if (result && (d->state != initialState)) { + /* Restore initial state */ + d->setState(initialState, "Restore initial state"); + } + return result; +} + +// ----------------------------------------------------------------------------- + +LinphoneCallDir CallSession::getDirection () const { + L_D(const CallSession); + return d->direction; +} + +int CallSession::getDuration () const { + L_D(const CallSession); + switch (d->state) { + case LinphoneCallEnd: + case LinphoneCallError: + case LinphoneCallReleased: + return d->log->duration; + default: + return d->computeDuration(); + } +} + +const LinphoneErrorInfo * CallSession::getErrorInfo () const { + L_D(const CallSession); + if (!d->nonOpError) + linphone_error_info_from_sal_op(d->ei, d->op); + return d->ei; +} + +LinphoneCallLog * CallSession::getLog () const { + L_D(const CallSession); + return d->log; +} + +LinphoneReason CallSession::getReason () const { + return linphone_error_info_get_reason(getErrorInfo()); +} + +const Address& CallSession::getRemoteAddress () const { + L_D(const CallSession); + return *L_GET_CPP_PTR_FROM_C_STRUCT((d->direction == LinphoneCallIncoming) + ? linphone_call_log_get_from(d->log) : linphone_call_log_get_to(d->log), + Address); +} + +string CallSession::getRemoteAddressAsString () const { + return getRemoteAddress().asString(); +} + +string CallSession::getRemoteContact () const { + L_D(const CallSession); + if (d->op) { + /* sal_op_get_remote_contact preserves header params */ + return sal_op_get_remote_contact(d->op); + } + return string(); +} + +const shared_ptr CallSession::getRemoteParams () { + L_D(CallSession); + if (d->op){ + const SalCustomHeader *ch = sal_op_get_recv_custom_header(d->op); + if (ch) { + /* Instanciate a remote_params only if a SIP message was received before (custom headers indicates this) */ + if (!d->remoteParams) + d->remoteParams = make_shared(); + d->remoteParams->getPrivate()->setCustomHeaders(ch); + } + return d->remoteParams; + } + return nullptr; +} + +LinphoneCallState CallSession::getState () const { + L_D(const CallSession); + return d->state; +} + +// ----------------------------------------------------------------------------- + +string CallSession::getRemoteUserAgent () const { + L_D(const CallSession); + if (d->op) + return sal_op_get_remote_ua(d->op); + return string(); +} + +shared_ptr CallSession::getCurrentParams () { + L_D(CallSession); + d->updateCurrentParams(); + return d->currentParams; +} + +// ----------------------------------------------------------------------------- + +const shared_ptr CallSession::getParams () const { + L_D(const CallSession); + return d->params; +} + LINPHONE_END_NAMESPACE diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index fb6e9de78..89576c970 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -19,17 +19,54 @@ #ifndef _CALL_SESSION_H_ #define _CALL_SESSION_H_ +#include + #include "object/object.h" +#include "address/address.h" +#include "conference/conference.h" +#include "conference/params/call-session-params.h" +#include "conference/session/call-session-listener.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE +class CallPrivate; class CallSessionPrivate; -class CallSession : public Object { +class CallSession : public Object, public std::enable_shared_from_this { + friend class CallPrivate; + public: - CallSession (); + CallSession (const Conference &conference, const std::shared_ptr params, CallSessionListener *listener); + + LinphoneStatus accept (const std::shared_ptr csp = nullptr); + LinphoneStatus acceptUpdate (const std::shared_ptr csp); + virtual void configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalOp *op, const Address &from, const Address &to); + LinphoneStatus decline (LinphoneReason reason); + LinphoneStatus decline (const LinphoneErrorInfo *ei); + virtual void initiateIncoming (); + virtual bool initiateOutgoing (); + virtual void iterate (time_t currentRealTime, bool oneSecondElapsed); + virtual void startIncomingNotification (); + virtual int startInvite (const Address *destination); + LinphoneStatus terminate (const LinphoneErrorInfo *ei = nullptr); + LinphoneStatus update (const std::shared_ptr csp); + + std::shared_ptr getCurrentParams (); + LinphoneCallDir getDirection () const; + int getDuration () const; + const LinphoneErrorInfo * getErrorInfo () const; + LinphoneCallLog * getLog () const; + virtual const std::shared_ptr getParams () const; + LinphoneReason getReason () const; + const Address& getRemoteAddress () const; + std::string getRemoteAddressAsString () const; + std::string getRemoteContact () const; + const std::shared_ptr getRemoteParams (); + LinphoneCallState getState () const; + + std::string getRemoteUserAgent () const; protected: explicit CallSession (CallSessionPrivate &p); diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h new file mode 100644 index 000000000..3d4258bac --- /dev/null +++ b/src/conference/session/media-session-p.h @@ -0,0 +1,300 @@ +/* + * media-session-p.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _MEDIA_SESSION_P_H_ +#define _MEDIA_SESSION_P_H_ + +#include +#include + +#include "call-session-p.h" + +#include "media-session.h" +#include "port-config.h" +#include "nat/ice-agent.h" +#include "nat/stun-client.h" + +#include "linphone/call_stats.h" +#include "sal/sal.h" + +#include "private.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class MediaSessionPrivate : public CallSessionPrivate { +public: + MediaSessionPrivate (const Conference &conference, const std::shared_ptr params, CallSessionListener *listener); + virtual ~MediaSessionPrivate (); + +public: + static void stunAuthRequestedCb (void *userData, const char *realm, const char *nonce, const char **username, const char **password, const char **ha1); + + void accepted (); + void ackReceived (LinphoneHeaders *headers); + bool failure (); + void pausedByRemote (); + void remoteRinging (); + void resumed (); + void terminated (); + void updated (bool isUpdate); + void updating (bool isUpdate); + + void enableSymmetricRtp (bool value); + void sendVfu (); + + void clearIceCheckList (IceCheckList *cl); + void deactivateIce (); + void prepareStreamsForIceGathering (bool hasVideo); + void stopStreamsForIceGathering (); + + int getAf () const { return af; } + bool getAudioMuted () const { return audioMuted; } + LinphoneCore * getCore () const { return core; } + IceSession * getIceSession () const { return iceAgent->getIceSession(); } + SalMediaDescription * getLocalDesc () const { return localDesc; } + MediaStream * getMediaStream (LinphoneStreamType type) const; + LinphoneNatPolicy * getNatPolicy () const { return natPolicy; } + int getRtcpPort (LinphoneStreamType type) const; + int getRtpPort (LinphoneStreamType type) const; + LinphoneCallStats * getStats (LinphoneStreamType type) const; + int getStreamIndex (LinphoneStreamType type) const; + int getStreamIndex (MediaStream *ms) const; + SalOp * getOp () const { return op; } + void setAudioMuted (bool value) { audioMuted = value; } + +private: + static OrtpJitterBufferAlgorithm jitterBufferNameToAlgo (const std::string &name); + +#ifdef VIDEO_ENABLED + static void videoStreamEventCb (void *userData, const MSFilter *f, const unsigned int eventId, const void *args); +#endif +#ifdef TEST_EXT_RENDERER + static void extRendererCb (void *userData, const MSPicture *local, const MSPicture *remote); +#endif + static void realTimeTextCharacterReceived (void *userData, MSFilter *f, unsigned int id, void *arg); + + static float aggregateQualityRatings (float audioRating, float videoRating); + + void setState (LinphoneCallState newState, const std::string &message); + + void computeStreamsIndexes (const SalMediaDescription *md); + void fixCallParams (SalMediaDescription *rmd); + void initializeParamsAccordingToIncomingCallParams (); + void setCompatibleIncomingCallParams (SalMediaDescription *md); + void updateBiggestDesc (SalMediaDescription *md); + void updateRemoteSessionIdAndVer (); + + void initStats (LinphoneCallStats *stats, LinphoneStreamType type); + void notifyStatsUpdated (int streamIndex) const; + + OrtpEvQueue * getEventQueue (int streamIndex) const; + MediaStream * getMediaStream (int streamIndex) const; + MSWebCam * getVideoDevice () const; + + void fillMulticastMediaAddresses (); + int selectFixedPort (int streamIndex, std::pair portRange); + int selectRandomPort (int streamIndex, std::pair portRange); + void setPortConfig (int streamIndex, std::pair portRange); + void setPortConfigFromRtpSession (int streamIndex, RtpSession *session); + void setRandomPortConfig (int streamIndex); + + void discoverMtu (const Address &remoteAddr); + std::string getBindIpForStream (int streamIndex); + void getLocalIp (const Address &remoteAddr); + std::string getPublicIpForStream (int streamIndex); + void runStunTestsIfNeeded (); + void selectIncomingIpVersion (); + void selectOutgoingIpVersion (); + + void forceStreamsDirAccordingToState (SalMediaDescription *md); + bool generateB64CryptoKey (size_t keyLength, char *keyOut, size_t keyOutSize); + void makeLocalMediaDescription (); + int setupEncryptionKey (SalSrtpCryptoAlgo *crypto, MSCryptoSuite suite, unsigned int tag); + void setupDtlsKeys (SalMediaDescription *md); + void setupEncryptionKeys (SalMediaDescription *md); + void setupRtcpFb (SalMediaDescription *md); + void setupRtcpXr (SalMediaDescription *md); + void setupZrtpHash (SalMediaDescription *md); + void transferAlreadyAssignedPayloadTypes (SalMediaDescription *oldMd, SalMediaDescription *md); + void updateLocalMediaDescriptionFromIce (); + + SalMulticastRole getMulticastRole (SalStreamType type); + void joinMulticastGroup (int streamIndex, MediaStream *ms); + + int findCryptoIndexFromTag (const SalSrtpCryptoAlgo crypto[], unsigned char tag); + void setDtlsFingerprint (MSMediaStreamSessions *sessions, const SalStreamDescription *sd, const SalStreamDescription *remote); + void setDtlsFingerprintOnAllStreams (); + void setupDtlsParams (MediaStream *ms); + void setZrtpCryptoTypesParameters (MSZrtpParams *params); + void startDtls (MSMediaStreamSessions *sessions, const SalStreamDescription *sd, const SalStreamDescription *remote); + void startDtlsOnAllStreams (); + void updateCryptoParameters (SalMediaDescription *oldMd, SalMediaDescription *newMd); + bool updateStreamCryptoParameters (const SalStreamDescription *localStreamDesc, SalStreamDescription *oldStream, SalStreamDescription *newStream, MediaStream *ms); + + int getIdealAudioBandwidth (const SalMediaDescription *md, const SalStreamDescription *desc); + int getVideoBandwidth (const SalMediaDescription *md, const SalStreamDescription *desc); + RtpProfile * makeProfile (const SalMediaDescription *md, const SalStreamDescription *desc, int *usedPt); + void unsetRtpProfile (int streamIndex); + void updateAllocatedAudioBandwidth (const PayloadType *pt, int maxbw); + + void applyJitterBufferParams (RtpSession *session, LinphoneStreamType type); + void clearEarlyMediaDestination (MediaStream *ms); + void clearEarlyMediaDestinations (); + void configureAdaptiveRateControl (MediaStream *ms, const OrtpPayloadType *pt, bool videoWillBeUsed); + void configureRtpSessionForRtcpFb (const SalStreamDescription *stream); + void configureRtpSessionForRtcpXr (SalStreamType type); + RtpSession * createAudioRtpIoSession (); + RtpSession * createVideoRtpIoSession (); + void freeResources (); + void handleIceEvents (OrtpEvent *ev); + void handleStreamEvents (int streamIndex); + void initializeAudioStream (); + void initializeStreams (); + void initializeTextStream (); + void initializeVideoStream (); + void parameterizeEqualizer (AudioStream *stream); + void prepareEarlyMediaForking (); + void postConfigureAudioStream (AudioStream *stream, bool muted); + void postConfigureAudioStreams (bool muted); + void setPlaybackGainDb (AudioStream *stream, float gain); + void setSymmetricRtp (bool value); + void startAudioStream (LinphoneCallState targetState, bool videoWillBeUsed); + void startStreams (LinphoneCallState targetState); + void startTextStream (); + void startVideoStream (LinphoneCallState targetState); + void stopAudioStream (); + void stopStreams (); + void stopTextStream (); + void stopVideoStream (); + void tryEarlyMediaForking (SalMediaDescription *md); + void updateFrozenPayloads (SalMediaDescription *result); + void updateStreams (SalMediaDescription *newMd, LinphoneCallState targetState); + void updateStreamsDestinations (SalMediaDescription *oldMd, SalMediaDescription *newMd); + + bool allStreamsAvpfEnabled () const; + bool allStreamsEncrypted () const; + bool atLeastOneStreamStarted () const; + void audioStreamAuthTokenReady (const std::string &authToken, bool verified); + void audioStreamEncryptionChanged (bool encrypted); + uint16_t getAvpfRrInterval () const; + int getNbActiveStreams () const; + bool isEncryptionMandatory () const; + int mediaParametersChanged (SalMediaDescription *oldMd, SalMediaDescription *newMd); + void propagateEncryptionChanged (); + + void fillLogStats (MediaStream *st); + void updateLocalStats (LinphoneCallStats *stats, MediaStream *stream) const; + void updateRtpStats (LinphoneCallStats *stats, int streamIndex); + + bool mediaReportEnabled (int statsType); + bool qualityReportingEnabled () const; + void updateReportingCallState (); + void updateReportingMediaInfo (int statsType); + + void executeBackgroundTasks (bool oneSecondElapsed); + void reportBandwidth (); + void reportBandwidthForStream (MediaStream *ms, LinphoneStreamType type); + + void handleIncomingReceivedStateInIncomingNotification (); + bool isReadyForInvite () const; + void setTerminated (); + LinphoneStatus startAcceptUpdate (LinphoneCallState nextState, const std::string &stateInfo); + LinphoneStatus startUpdate (); + void terminate (); + void updateCurrentParams (); + + void accept (const std::shared_ptr params); + LinphoneStatus acceptUpdate (const std::shared_ptr csp, LinphoneCallState nextState, const std::string &stateInfo); + +#ifdef VIDEO_ENABLED + void videoStreamEventCb (const MSFilter *f, const unsigned int eventId, const void *args); +#endif + void realTimeTextCharacterReceived (MSFilter *f, unsigned int id, void *arg); + + void stunAuthRequestedCb (const char *realm, const char *nonce, const char **username, const char **password, const char **ha1); + +private: + static const std::string ecStateStore; + static const int ecStateMaxLen; + + std::shared_ptr params = nullptr; + std::shared_ptr currentParams = nullptr; + std::shared_ptr remoteParams = nullptr; + + AudioStream *audioStream = nullptr; + OrtpEvQueue *audioStreamEvQueue = nullptr; + LinphoneCallStats *audioStats = nullptr; + RtpProfile *audioProfile = nullptr; + RtpProfile *rtpIoAudioProfile = nullptr; + int mainAudioStreamIndex = LINPHONE_CALL_STATS_AUDIO; + + VideoStream *videoStream = nullptr; + OrtpEvQueue *videoStreamEvQueue = nullptr; + LinphoneCallStats *videoStats = nullptr; + RtpProfile *rtpIoVideoProfile = nullptr; + RtpProfile *videoProfile = nullptr; + int mainVideoStreamIndex = LINPHONE_CALL_STATS_VIDEO; + void *videoWindowId = nullptr; + bool cameraEnabled = true; + + TextStream *textStream = nullptr; + OrtpEvQueue *textStreamEvQueue = nullptr; + LinphoneCallStats *textStats = nullptr; + RtpProfile *textProfile = nullptr; + int mainTextStreamIndex = LINPHONE_CALL_STATS_TEXT; + + StunClient *stunClient = nullptr; + IceAgent *iceAgent = nullptr; + + int af; /* The address family to prefer for RTP path, guessed from signaling path */ + std::string mediaLocalIp; + PortConfig mediaPorts[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; + bool needMediaLocalIpRefresh = false; + MSMediaStreamSessions sessions[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; /* The rtp, srtp, zrtp contexts for each stream */ + SalMediaDescription *localDesc = nullptr; + int localDescChanged = 0; + SalMediaDescription *biggestDesc = nullptr; + SalMediaDescription *resultDesc = nullptr; + bool expectMediaInAck = false; + unsigned int remoteSessionId = 0; + unsigned int remoteSessionVer = 0; + + std::string authToken; + bool authTokenVerified = false; + std::string dtlsCertificateFingerprint; + + unsigned int nbMediaStarts = 0; + int upBandwidth = 0; /* Upload bandwidth setting at the time the call is started. Used to detect if it changes during a call */ + int audioBandwidth = 0; /* Upload bandwidth used by audio */ + + bool allMuted = false; + bool audioMuted = false; + bool pausedByApp = false; + bool playingRingbackTone = false; + bool recordActive = false; + + std::string onHoldFile; + + L_DECLARE_PUBLIC(MediaSession); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _MEDIA_SESSION_P_H_ diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 0b4faf9ad..8add69a49 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -16,26 +16,4649 @@ * along with this program. If not, see . */ -#include "call-session-p.h" +#include +#include -#include "media-session.h" +#include "address/address-p.h" +#include "c-wrapper/c-tools.h" +#include "conference/session/media-session-p.h" +#include "call/call-p.h" +#include "conference/participant-p.h" +#include "conference/params/media-session-params-p.h" +#include "conference/session/media-session.h" +#include "utils/payload-type-handler.h" + +#include "logger/logger.h" + +#include "linphone/core.h" + +#include #include +#include +#include +#include +#include +#include +#include +#include + +#include "private.h" + +using namespace std; LINPHONE_BEGIN_NAMESPACE -// ============================================================================= +#define STR_REASSIGN(dest, src) { \ + if (dest) \ + ms_free(dest); \ + dest = src; \ +} -class MediaSessionPrivate : public CallSessionPrivate { -public: - AudioStream *audioStream = nullptr; - VideoStream *videoStream = nullptr; - TextStream *textStream = nullptr; - IceSession *iceSession = nullptr; -}; +inline OrtpRtcpXrStatSummaryFlag operator|(OrtpRtcpXrStatSummaryFlag a, OrtpRtcpXrStatSummaryFlag b) { + return static_cast(static_cast(a) | static_cast(b)); +} // ============================================================================= -MediaSession::MediaSession () : CallSession(*new MediaSessionPrivate) {} +const string MediaSessionPrivate::ecStateStore = ".linphone.ecstate"; +const int MediaSessionPrivate::ecStateMaxLen = 1048576; /* 1Mo */ + +// ============================================================================= + +MediaSessionPrivate::MediaSessionPrivate (const Conference &conference, const shared_ptr params, CallSessionListener *listener) + : CallSessionPrivate(conference, params, listener) { + if (params) + this->params = make_shared(*(reinterpret_cast(params.get()))); + currentParams = make_shared(); + + audioStats = linphone_call_stats_ref(linphone_call_stats_new()); + initStats(audioStats, LinphoneStreamTypeAudio); + videoStats = linphone_call_stats_ref(linphone_call_stats_new()); + initStats(videoStats, LinphoneStreamTypeVideo); + textStats = linphone_call_stats_ref(linphone_call_stats_new()); + initStats(textStats, LinphoneStreamTypeText); + + int minPort, maxPort; + linphone_core_get_audio_port_range(core, &minPort, &maxPort); + setPortConfig(mainAudioStreamIndex, make_pair(minPort, maxPort)); + linphone_core_get_video_port_range(core, &minPort, &maxPort); + setPortConfig(mainVideoStreamIndex, make_pair(minPort, maxPort)); + linphone_core_get_text_port_range(core, &minPort, &maxPort); + setPortConfig(mainTextStreamIndex, make_pair(minPort, maxPort)); + + memset(sessions, 0, sizeof(sessions)); +} + +MediaSessionPrivate::~MediaSessionPrivate () { + if (audioStats) + linphone_call_stats_unref(audioStats); + if (videoStats) + linphone_call_stats_unref(videoStats); + if (textStats) + linphone_call_stats_unref(textStats); + if (stunClient) + delete stunClient; + delete iceAgent; + if (localDesc) + sal_media_description_unref(localDesc); + if (biggestDesc) + sal_media_description_unref(biggestDesc); + if (resultDesc) + sal_media_description_unref(resultDesc); +} + +// ----------------------------------------------------------------------------- + +void MediaSessionPrivate::stunAuthRequestedCb (void *userData, const char *realm, const char *nonce, const char **username, const char **password, const char **ha1) { + MediaSessionPrivate *msp = reinterpret_cast(userData); + msp->stunAuthRequestedCb(realm, nonce, username, password, ha1); +} + +// ----------------------------------------------------------------------------- + +void MediaSessionPrivate::accepted () { + L_Q(MediaSession); + CallSessionPrivate::accepted(); + LinphoneTaskList tl; + linphone_task_list_init(&tl); + /* Reset the internal call update flag, so it doesn't risk to be copied and used in further re-INVITEs */ + params->getPrivate()->setInternalCallUpdate(false); + SalMediaDescription *rmd = sal_call_get_remote_media_description(op); + SalMediaDescription *md = sal_call_get_final_media_description(op); + if (!md && (prevState == LinphoneCallOutgoingEarlyMedia) && resultDesc) { + lInfo() << "Using early media SDP since none was received with the 200 OK"; + md = resultDesc; + } + if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(core, md))) + md = nullptr; + if (md) { + /* There is a valid SDP in the response, either offer or answer, and we're able to start/update the streams */ + if (rmd) { + /* Handle remote ICE attributes if any. */ + iceAgent->updateFromRemoteMediaDescription(localDesc, rmd, !sal_call_is_offerer(op)); + } + LinphoneCallState nextState = LinphoneCallIdle; + string nextStateMsg; + switch (state) { + case LinphoneCallResuming: + linphone_core_notify_display_status(core, _("Call resumed.")); + BCTBX_NO_BREAK; /* Intentional no break */ + case LinphoneCallConnected: +#if 0 + if (call->referer) + linphone_core_notify_refer_state(lc,call->referer,call); +#endif + BCTBX_NO_BREAK; /* Intentional no break */ + case LinphoneCallUpdating: + case LinphoneCallUpdatedByRemote: + if (!sal_media_description_has_dir(localDesc, SalStreamInactive) + && (sal_media_description_has_dir(md, SalStreamRecvOnly) || sal_media_description_has_dir(md, SalStreamInactive))) { + nextState = LinphoneCallPausedByRemote; + nextStateMsg = "Call paused by remote"; + } else { + if (!params->getPrivate()->getInConference() && listener) + listener->setCurrentSession(*q); + nextState = LinphoneCallStreamsRunning; + nextStateMsg = "Streams running"; + } + break; + case LinphoneCallEarlyUpdating: + nextState = prevState; + nextStateMsg = "Early update accepted"; + break; + case LinphoneCallPausing: + /* When we entered the pausing state, we always reach the paused state whatever the content of the remote SDP is. + * Our streams are all send-only (with music), soundcard and camera are never used. */ + nextState = LinphoneCallPaused; + nextStateMsg = "Call paused"; +#if 0 + if (call->refer_pending) + linphone_task_list_add(&tl, (LinphoneCoreIterateHook)start_pending_refer, call); +#endif + break; + default: + lError() << "accepted(): don't know what to do in state [" << linphone_call_state_to_string(state) << "]"; + break; + } + + if (nextState == LinphoneCallIdle) + lError() << "BUG: nextState is not set in accepted(), current state is " << linphone_call_state_to_string(state); + else { + updateRemoteSessionIdAndVer(); + iceAgent->updateIceStateInCallStats(); + updateStreams(md, nextState); + fixCallParams(rmd); + setState(nextState, nextStateMsg); + } + } else { /* Invalid or no SDP */ + switch (prevState) { + /* Send a bye only in case of early states */ + case LinphoneCallOutgoingInit: + case LinphoneCallOutgoingProgress: + case LinphoneCallOutgoingRinging: + case LinphoneCallOutgoingEarlyMedia: + case LinphoneCallIncomingReceived: + case LinphoneCallIncomingEarlyMedia: + lError() << "Incompatible SDP answer received, need to abort the call"; +#if 0 + linphone_call_abort(call, _("Incompatible, check codecs or security settings...")); +#endif + break; + /* Otherwise we are able to resume previous state */ + default: + lError() << "Incompatible SDP answer received"; + switch(state) { + case LinphoneCallPausedByRemote: + case LinphoneCallPaused: + case LinphoneCallStreamsRunning: + break; + default: + lInfo() << "Incompatible SDP answer received, restoring previous state [" << linphone_call_state_to_string(prevState) << "]"; + setState(prevState, _("Incompatible media parameters.")); + break; + } + break; + } + } + linphone_task_list_run(&tl); + linphone_task_list_free(&tl); +} + +void MediaSessionPrivate::ackReceived (LinphoneHeaders *headers) { + CallSessionPrivate::ackReceived(headers); + if (expectMediaInAck) { + switch (state) { + case LinphoneCallStreamsRunning: + case LinphoneCallPausedByRemote: + setState(LinphoneCallUpdatedByRemote, "UpdatedByRemote"); + break; + default: + break; + } + accepted(); + } +} + +bool MediaSessionPrivate::failure () { + L_Q(MediaSession); + const SalErrorInfo *ei = sal_op_get_error_info(op); + const char *msg = ei->full_string; + switch (ei->reason) { + case SalReasonRedirect: + stopStreams(); + break; + case SalReasonUnsupportedContent: /* This is for compatibility: linphone sent 415 because of SDP offer answer failure */ + case SalReasonNotAcceptable: + lInfo() << "Outgoing CallSession [" << q << "] failed with SRTP and/or AVPF enabled"; + if ((state == LinphoneCallOutgoingInit) || (state == LinphoneCallOutgoingProgress) + || (state == LinphoneCallOutgoingRinging) /* Push notification case */ || (state == LinphoneCallOutgoingEarlyMedia)) { + for (int i = 0; i < localDesc->nb_streams; i++) { + if (!sal_stream_description_active(&localDesc->streams[i])) + continue; + if (params->getMediaEncryption() == LinphoneMediaEncryptionSRTP) { + if (params->avpfEnabled()) { + if (i == 0) + lInfo() << "Retrying CallSession [" << q << "] with SAVP"; + params->enableAvpf(false); +#if 0 + linphone_call_restart_invite(call); +#endif + return true; + } else if (!linphone_core_is_media_encryption_mandatory(core)) { + if (i == 0) + lInfo() << "Retrying CallSession [" << q << "] with AVP"; + params->setMediaEncryption(LinphoneMediaEncryptionNone); + memset(localDesc->streams[i].crypto, 0, sizeof(localDesc->streams[i].crypto)); +#if 0 + linphone_call_restart_invite(call); +#endif + return true; + } + } else if (params->avpfEnabled()) { + if (i == 0) + lInfo() << "Retrying CallSession [" << q << "] with AVP"; + params->enableAvpf(false); +#if 0 + linphone_call_restart_invite(call); +#endif + return true; + } + } + } + msg = "Incompatible media parameters."; + linphone_core_notify_display_status(core, msg); + break; + default: + break; + } + + bool stop = CallSessionPrivate::failure(); + if (stop) + return true; + +#if 0 + /* Stop ringing */ + bool_t ring_during_early_media = linphone_core_get_ring_during_incoming_early_media(lc); + bool_t stop_ringing = TRUE; + bctbx_list_t *calls = lc->calls; + while(calls) { + if (((LinphoneCall *)calls->data)->state == LinphoneCallIncomingReceived || (ring_during_early_media && ((LinphoneCall *)calls->data)->state == LinphoneCallIncomingEarlyMedia)) { + stop_ringing = FALSE; + break; + } + calls = calls->next; + } + if(stop_ringing) { + linphone_core_stop_ringing(lc); + } +#endif + stopStreams(); + return false; +} + +void MediaSessionPrivate::pausedByRemote () { + linphone_core_notify_display_status(core, "We are paused by other party"); + shared_ptr newParams = make_shared(*params.get()); + if (lp_config_get_int(linphone_core_get_config(core), "sip", "inactive_video_on_pause", 0)) + newParams->setVideoDirection(LinphoneMediaDirectionInactive); + acceptUpdate(newParams, LinphoneCallPausedByRemote, "Call paused by remote"); +} + +void MediaSessionPrivate::remoteRinging () { + L_Q(MediaSession); + /* Set privacy */ + q->getCurrentParams()->setPrivacy((LinphonePrivacyMask)sal_op_get_privacy(op)); + linphone_core_notify_display_status(core, _("Remote ringing.")); + SalMediaDescription *md = sal_call_get_final_media_description(op); + if (md) { + /* Initialize the remote call params by invoking linphone_call_get_remote_params(). This is useful as the SDP may not be present in the 200Ok */ + q->getRemoteParams(); + /* Accept early media */ + if ((audioStream && audio_stream_started(audioStream)) +#ifdef VIDEO_ENABLED + || (videoStream && video_stream_started(videoStream)) +#endif + ) { + /* Streams already started */ + tryEarlyMediaForking(md); +#ifdef VIDEO_ENABLED + if (videoStream) + video_stream_send_vfu(videoStream); /* Request for iframe */ +#endif + return; + } + + linphone_core_notify_show_interface(core); + linphone_core_notify_display_status(core, _("Early media.")); + setState(LinphoneCallOutgoingEarlyMedia, "Early media"); +#if 0 + linphone_core_stop_ringing(lc); +#endif + lInfo() << "Doing early media..."; + updateStreams(md, state); + if ((q->getCurrentParams()->getAudioDirection() == LinphoneMediaDirectionInactive) && audioStream) { +#if 0 + if (lc->ringstream != NULL) return; /* Already ringing! */ + start_remote_ring(lc, call); +#endif + } + } else { + linphone_core_stop_dtmf_stream(core); + if (state == LinphoneCallOutgoingEarlyMedia) { + /* Already doing early media */ + return; + } +#if 0 + if (lc->ringstream == NULL) start_remote_ring(lc, call); +#endif + lInfo() << "Remote ringing..."; + linphone_core_notify_display_status(core, _("Remote ringing...")); + setState(LinphoneCallOutgoingRinging, "Remote ringing"); + } +} + +void MediaSessionPrivate::resumed () { + linphone_core_notify_display_status(core, "We have been resumed"); + acceptUpdate(nullptr, LinphoneCallStreamsRunning, "Connected (streams running)"); +} + +void MediaSessionPrivate::terminated () { + stopStreams(); + CallSessionPrivate::terminated(); +} + +/* This callback is called when an incoming re-INVITE/ SIP UPDATE modifies the session */ +void MediaSessionPrivate::updated (bool isUpdate) { + SalMediaDescription *rmd = sal_call_get_remote_media_description(op); + switch (state) { + case LinphoneCallPausedByRemote: + if (sal_media_description_has_dir(rmd, SalStreamSendRecv) || sal_media_description_has_dir(rmd, SalStreamRecvOnly)) { + resumed(); + return; + } + break; + case LinphoneCallStreamsRunning: + case LinphoneCallConnected: + case LinphoneCallUpdatedByRemote: /* Can happen on UAC connectivity loss */ + if (sal_media_description_has_dir(rmd, SalStreamSendOnly) || sal_media_description_has_dir(rmd, SalStreamInactive)) { + pausedByRemote(); + return; + } + break; + default: + /* The other cases are handled in CallSessionPrivate::updated */ + break; + } + CallSessionPrivate::updated(isUpdate); +} + +void MediaSessionPrivate::updating (bool isUpdate) { + L_Q(MediaSession); + SalMediaDescription *rmd = sal_call_get_remote_media_description(op); + fixCallParams(rmd); + if (state != LinphoneCallPaused) { + /* Refresh the local description, but in paused state, we don't change anything. */ + if (!rmd && lp_config_get_int(linphone_core_get_config(core), "sip", "sdp_200_ack_follow_video_policy", 0)) { + lInfo() << "Applying default policy for offering SDP on CallSession [" << q << "]"; + params = make_shared(); + params->initDefault(core); + } + makeLocalMediaDescription(); + sal_call_set_local_media_description(op, localDesc); + } + if (rmd) { + SalErrorInfo sei; + memset(&sei, 0, sizeof(sei)); + expectMediaInAck = false; + SalMediaDescription *md = sal_call_get_final_media_description(op); + if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(core, md))) { + sal_error_info_set(&sei, SalReasonNotAcceptable, "SIP", 0, nullptr, nullptr); + sal_call_decline_with_error_info(op, &sei, nullptr); + sal_error_info_reset(&sei); + return; + } + SalMediaDescription *prevResultDesc = resultDesc; + if (isUpdate && prevResultDesc && md){ + int diff = sal_media_description_equals(prevResultDesc, md); + if (diff & (SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED | SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED)) { + lWarning() << "Cannot accept this update, it is changing parameters that require user approval"; + sal_error_info_set(&sei, SalReasonUnknown, "SIP", 504, "Cannot change the session parameters without prompting the user", nullptr); + sal_call_decline_with_error_info(op, &sei, nullptr); + sal_error_info_reset(&sei); + return; + } + } + updated(isUpdate); + } else { + /* Case of a reINVITE or UPDATE without SDP */ + expectMediaInAck = true; + sal_call_accept(op); /* Respond with an offer */ + /* Don't do anything else in this case, wait for the ACK to receive to notify the app */ + } +} + +// ----------------------------------------------------------------------------- + +void MediaSessionPrivate::enableSymmetricRtp (bool value) { + for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + if (sessions[i].rtp_session) + rtp_session_set_symmetric_rtp(sessions[i].rtp_session, value); + } +} + +void MediaSessionPrivate::sendVfu () { +#ifdef VIDEO_ENABLED + if (videoStream) + video_stream_send_vfu(videoStream); +#endif +} + +// ----------------------------------------------------------------------------- + +void MediaSessionPrivate::clearIceCheckList (IceCheckList *cl) { + if (audioStream && audioStream->ms.ice_check_list == cl) + audioStream->ms.ice_check_list = nullptr; + if (videoStream && videoStream->ms.ice_check_list == cl) + videoStream->ms.ice_check_list = nullptr; + if (textStream && textStream->ms.ice_check_list == cl) + textStream->ms.ice_check_list = nullptr; +} + +void MediaSessionPrivate::deactivateIce () { + if (audioStream) + audioStream->ms.ice_check_list = nullptr; + if (videoStream) + videoStream->ms.ice_check_list = nullptr; + if (textStream) + textStream->ms.ice_check_list = nullptr; + audioStats->ice_state = LinphoneIceStateNotActivated; + videoStats->ice_state = LinphoneIceStateNotActivated; + textStats->ice_state = LinphoneIceStateNotActivated; + stopStreamsForIceGathering(); +} + +void MediaSessionPrivate::prepareStreamsForIceGathering (bool hasVideo) { + if (audioStream->ms.state == MSStreamInitialized) + audio_stream_prepare_sound(audioStream, nullptr, nullptr); +#ifdef VIDEO_ENABLED + if (hasVideo && videoStream && (videoStream->ms.state == MSStreamInitialized)) + video_stream_prepare_video(videoStream); +#endif + if (params->realtimeTextEnabled() && (textStream->ms.state == MSStreamInitialized)) + text_stream_prepare_text(textStream); +} + +void MediaSessionPrivate::stopStreamsForIceGathering () { + if (audioStream && (audioStream->ms.state == MSStreamPreparing)) + audio_stream_unprepare_sound(audioStream); +#ifdef VIDEO_ENABLED + if (videoStream && (videoStream->ms.state == MSStreamPreparing)) + video_stream_unprepare_video(videoStream); +#endif + if (textStream && (textStream->ms.state == MSStreamPreparing)) + text_stream_unprepare_text(textStream); +} + +// ----------------------------------------------------------------------------- + +MediaStream * MediaSessionPrivate::getMediaStream (LinphoneStreamType type) const { + switch (type) { + case LinphoneStreamTypeAudio: + return &audioStream->ms; + case LinphoneStreamTypeVideo: + return &videoStream->ms; + case LinphoneStreamTypeText: + return &textStream->ms; + case LinphoneStreamTypeUnknown: + default: + return nullptr; + } +} + +int MediaSessionPrivate::getRtcpPort (LinphoneStreamType type) const { + return mediaPorts[getStreamIndex(getMediaStream(type))].rtcpPort; +} + +int MediaSessionPrivate::getRtpPort (LinphoneStreamType type) const { + return mediaPorts[getStreamIndex(getMediaStream(type))].rtpPort; +} + +LinphoneCallStats * MediaSessionPrivate::getStats (LinphoneStreamType type) const { + switch (type) { + case LinphoneStreamTypeAudio: + return audioStats; + case LinphoneStreamTypeVideo: + return videoStats; + case LinphoneStreamTypeText: + return textStats; + case LinphoneStreamTypeUnknown: + default: + return nullptr; + } +} + +int MediaSessionPrivate::getStreamIndex (LinphoneStreamType type) const { + return getStreamIndex(getMediaStream(type)); +} + +int MediaSessionPrivate::getStreamIndex (MediaStream *ms) const { + if (ms == &audioStream->ms) + return mainAudioStreamIndex; + else if (ms == &videoStream->ms) + return mainVideoStreamIndex; + else if (ms == &textStream->ms) + return mainTextStreamIndex; + return -1; +} + +// ----------------------------------------------------------------------------- + +OrtpJitterBufferAlgorithm MediaSessionPrivate::jitterBufferNameToAlgo (const string &name) { + if (name == "basic") return OrtpJitterBufferBasic; + if (name == "rls") return OrtpJitterBufferRecursiveLeastSquare; + lError() << "Invalid jitter buffer algorithm: " << name; + return OrtpJitterBufferRecursiveLeastSquare; +} + +#ifdef VIDEO_ENABLED +void MediaSessionPrivate::videoStreamEventCb (void *userData, const MSFilter *f, const unsigned int eventId, const void *args) { + MediaSessionPrivate *msp = reinterpret_cast(userData); + msp->videoStreamEventCb(f, eventId, args); +} +#endif + +#ifdef TEST_EXT_RENDERER +void MediaSessionPrivate::extRendererCb (void *userData, const MSPicture *local, const MSPicture *remote) { + lInfo() << "extRendererCb, local buffer=" << local ? local->planes[0] : nullptr + << ", remote buffer=" << remote ? remote->planes[0] : nullptr); +} +#endif + +void MediaSessionPrivate::realTimeTextCharacterReceived (void *userData, MSFilter *f, unsigned int id, void *arg) { + MediaSessionPrivate *msp = reinterpret_cast(userData); + msp->realTimeTextCharacterReceived(f, id, arg); +} + +// ----------------------------------------------------------------------------- + +float MediaSessionPrivate::aggregateQualityRatings (float audioRating, float videoRating) { + float result; + if ((audioRating < 0) && (videoRating < 0)) + result = -1; + else if (audioRating < 0) + result = videoRating * 5.0f; + else if (videoRating < 0) + result = audioRating * 5.0f; + else + result = audioRating * videoRating * 5.0f; + return result; +} + +// ----------------------------------------------------------------------------- + +void MediaSessionPrivate::setState (LinphoneCallState newState, const string &message) { + L_Q(MediaSession); + /* Take a ref on the session otherwise it might get destroyed during the call to setState */ + shared_ptr session = q->shared_from_this(); + CallSessionPrivate::setState(newState, message); + updateReportingCallState(); +} + +// ----------------------------------------------------------------------------- + +void MediaSessionPrivate::computeStreamsIndexes (const SalMediaDescription *md) { + bool audioFound = false; + bool videoFound = false; + bool textFound = false; + for (int i = 0; i < md->nb_streams; i++) { + if (md->streams[i].type == SalAudio) { + if (audioFound) + lInfo() << "audio stream index found: " << i << ", but main audio stream already set to " << mainAudioStreamIndex; + else { + mainAudioStreamIndex = i; + audioFound = true; + lInfo() << "audio stream index found: " << i << ", updating main audio stream index"; + } + /* Check that the default value of a another stream doesn't match the new one */ + if (i == mainVideoStreamIndex) { + for (int j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { + if (sal_stream_description_active(&md->streams[j])) + continue; + if ((j != mainVideoStreamIndex) && (j != mainTextStreamIndex)) { + lInfo() << i << " was used for video stream ; now using " << j; + mainVideoStreamIndex = j; + break; + } + } + } + if (i == mainTextStreamIndex) { + for (int j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { + if (sal_stream_description_active(&md->streams[j])) + continue; + if ((j != mainVideoStreamIndex) && (j != mainTextStreamIndex)) { + lInfo() << i << " was used for text stream ; now using " << j; + mainTextStreamIndex = j; + break; + } + } + } + } else if (md->streams[i].type == SalVideo) { + if (videoFound) + lInfo() << "video stream index found: " << i << ", but main video stream already set to " << mainVideoStreamIndex; + else { + mainVideoStreamIndex = i; + videoFound = true; + lInfo() << "video stream index found: " << i << ", updating main video stream index"; + } + /* Check that the default value of a another stream doesn't match the new one */ + if (i == mainAudioStreamIndex) { + for (int j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { + if (sal_stream_description_active(&md->streams[j])) + continue; + if ((j != mainAudioStreamIndex) && (j != mainTextStreamIndex)) { + lInfo() << i << " was used for audio stream ; now using " << j; + mainAudioStreamIndex = j; + break; + } + } + } + if (i == mainTextStreamIndex) { + for (int j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { + if (sal_stream_description_active(&md->streams[j])) + continue; + if ((j != mainAudioStreamIndex) && (j != mainTextStreamIndex)) { + lInfo() << i << " was used for text stream ; now using " << j; + mainTextStreamIndex = j; + break; + } + } + } + } else if (md->streams[i].type == SalText) { + if (textFound) + lInfo() << "text stream index found: " << i << ", but main text stream already set to " << mainTextStreamIndex; + else { + mainTextStreamIndex = i; + textFound = true; + lInfo() << "text stream index found: " << i << ", updating main text stream index"; + } + /* Check that the default value of a another stream doesn't match the new one */ + if (i == mainAudioStreamIndex) { + for (int j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { + if (sal_stream_description_active(&md->streams[j])) + continue; + if ((j != mainVideoStreamIndex) && (j != mainAudioStreamIndex)) { + lInfo() << i << " was used for audio stream ; now using " << j; + mainAudioStreamIndex = j; + break; + } + } + } + if (i == mainVideoStreamIndex) { + for (int j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { + if (sal_stream_description_active(&md->streams[j])) + continue; + if ((j != mainVideoStreamIndex) && (j != mainAudioStreamIndex)) { + lInfo() << i << " was used for video stream ; now using " << j; + mainVideoStreamIndex = j; + break; + } + } + } + } + } +} + +/* + * This method needs to be called at each incoming reINVITE, in order to adjust various local parameters to what is being offered by remote: + * - the stream indexes. + * - the video enablement parameter according to what is offered and our local policy. + * Fixing the params to proper values avoid request video by accident during internal call updates, pauses and resumes + */ +void MediaSessionPrivate::fixCallParams (SalMediaDescription *rmd) { + L_Q(MediaSession); + if (rmd) { + computeStreamsIndexes(rmd); + updateBiggestDesc(rmd); + /* Why disabling implicit_rtcp_fb ? It is a local policy choice actually. It doesn't disturb to propose it again and again + * even if the other end apparently doesn't support it. + * The following line of code is causing trouble, while for example making an audio call, then adding video. + * Due to the 200Ok response of the audio-only offer where no rtcp-fb attribute is present, implicit_rtcp_fb is set to + * false, which is then preventing it to be eventually used when video is later added to the call. + * I did the choice of commenting it out. + */ + /*params.getPrivate()->enableImplicitRtcpFb(params.getPrivate()->implicitRtcpFbEnabled() & sal_media_description_has_implicit_avpf(rmd));*/ + } + const shared_ptr rcp = q->getRemoteParams(); + if (rcp) { + if (params->audioEnabled() && !rcp->audioEnabled()) { + lInfo() << "CallSession [" << q << "]: disabling audio in our call params because the remote doesn't want it"; + params->enableAudio(false); + } + if (params->videoEnabled() && !rcp->videoEnabled()) { + lInfo() << "CallSession [" << q << "]: disabling video in our call params because the remote doesn't want it"; + params->enableVideo(false); + } + if (rcp->videoEnabled() && core->video_policy.automatically_accept && linphone_core_video_enabled(core) && !params->videoEnabled()) { + lInfo() << "CallSession [" << q << "]: re-enabling video in our call params because the remote wants it and the policy allows to automatically accept"; + params->enableVideo(true); + } + if (rcp->realtimeTextEnabled() && !params->realtimeTextEnabled()) + params->enableRealtimeText(true); + } +} + +void MediaSessionPrivate::initializeParamsAccordingToIncomingCallParams () { + CallSessionPrivate::initializeParamsAccordingToIncomingCallParams(); + currentParams->getPrivate()->setUpdateCallWhenIceCompleted(params->getPrivate()->getUpdateCallWhenIceCompleted()); + params->enableVideo(linphone_core_video_enabled(core) && core->video_policy.automatically_accept); + SalMediaDescription *md = sal_call_get_remote_media_description(op); + if (md) { + /* It is licit to receive an INVITE without SDP, in this case WE choose the media parameters according to policy */ + setCompatibleIncomingCallParams(md); + /* Set multicast role & address if any */ + if (!sal_call_is_offerer(op)) { + for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + if (md->streams[i].dir == SalStreamInactive) + continue; + if ((md->streams[i].rtp_addr[0] != '\0') && ms_is_multicast(md->streams[i].rtp_addr)) { + md->streams[i].multicast_role = SalMulticastReceiver; + mediaPorts[i].multicastIp = md->streams[i].rtp_addr; + } + } + } + } +} + +/** + * Fix call parameters on incoming call to eg. enable AVPF if the incoming call propose it and it is not enabled locally. + */ +void MediaSessionPrivate::setCompatibleIncomingCallParams (SalMediaDescription *md) { + /* Handle AVPF, SRTP and DTLS */ + params->enableAvpf(sal_media_description_has_avpf(md)); + if (destProxy) + params->setAvpfRrInterval(linphone_proxy_config_get_avpf_rr_interval(destProxy) * 1000); + else + params->setAvpfRrInterval(linphone_core_get_avpf_rr_interval(core) * 1000); + if (sal_media_description_has_zrtp(md) && linphone_core_media_encryption_supported(core, LinphoneMediaEncryptionZRTP)) + params->setMediaEncryption(LinphoneMediaEncryptionZRTP); + else if (sal_media_description_has_dtls(md) && media_stream_dtls_supported()) + params->setMediaEncryption(LinphoneMediaEncryptionDTLS); + else if (sal_media_description_has_srtp(md) && ms_srtp_supported()) + params->setMediaEncryption(LinphoneMediaEncryptionSRTP); + else if (params->getMediaEncryption() != LinphoneMediaEncryptionZRTP) + params->setMediaEncryption(LinphoneMediaEncryptionNone); + /* In case of nat64, even ipv4 addresses are reachable from v6. Should be enhanced to manage stream by stream connectivity (I.E v6 or v4) */ + /*if (!sal_media_description_has_ipv6(md)){ + lInfo() << "The remote SDP doesn't seem to offer any IPv6 connectivity, so disabling IPv6 for this call"; + af = AF_INET; + }*/ + fixCallParams(md); +} + +void MediaSessionPrivate::updateBiggestDesc (SalMediaDescription *md) { + if (!biggestDesc || (md->nb_streams > biggestDesc->nb_streams)) { + /* We have been offered and now are ready to proceed, or we added a new stream, + * store the media description to remember the mapping of calls */ + if (biggestDesc) { + sal_media_description_unref(biggestDesc); + biggestDesc = nullptr; + } + biggestDesc = sal_media_description_ref(md); + } +} + +void MediaSessionPrivate::updateRemoteSessionIdAndVer () { + SalMediaDescription *desc = sal_call_get_remote_media_description(op); + if (desc) { + remoteSessionId = desc->session_id; + remoteSessionVer = desc->session_ver; + } +} + +// ----------------------------------------------------------------------------- + +void MediaSessionPrivate::initStats (LinphoneCallStats *stats, LinphoneStreamType type) { + stats->type = type; + stats->received_rtcp = nullptr; + stats->sent_rtcp = nullptr; + stats->ice_state = LinphoneIceStateNotActivated; +} + +void MediaSessionPrivate::notifyStatsUpdated (int streamIndex) const { + LinphoneCallStats *stats = nullptr; + if (streamIndex == mainAudioStreamIndex) + stats = audioStats; + else if (streamIndex == mainVideoStreamIndex) + stats = videoStats; + else if (streamIndex == mainTextStreamIndex) + stats = textStats; + else + return; + if (stats->updated) { + switch (stats->updated) { + case LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE: + case LINPHONE_CALL_STATS_SENT_RTCP_UPDATE: +#if 0 + linphone_reporting_on_rtcp_update(call, stream_index == call->main_audio_stream_index ? SalAudio : stream_index == call->main_video_stream_index ? SalVideo : SalText); +#endif + break; + default: + break; + } + if (listener) + listener->statsUpdated(stats); + stats->updated = 0; + } +} + +// ----------------------------------------------------------------------------- + +OrtpEvQueue * MediaSessionPrivate::getEventQueue (int streamIndex) const { + if (streamIndex == mainAudioStreamIndex) + return audioStreamEvQueue; + if (streamIndex == mainVideoStreamIndex) + return videoStreamEvQueue; + if (streamIndex == mainTextStreamIndex) + return textStreamEvQueue; + lError() << "getEventQueue(): no stream index " << streamIndex; + return nullptr; +} + +MediaStream * MediaSessionPrivate::getMediaStream (int streamIndex) const { + if (streamIndex == mainAudioStreamIndex) + return &audioStream->ms; + if (streamIndex == mainVideoStreamIndex) + return &videoStream->ms; + if (streamIndex == mainTextStreamIndex) + return &textStream->ms; + lError() << "getMediaStream(): no stream index " << streamIndex; + return nullptr; +} + +MSWebCam * MediaSessionPrivate::getVideoDevice () const { + bool paused = (state == LinphoneCallPausing) || (state == LinphoneCallPaused); + if (paused || allMuted || !cameraEnabled) + return get_nowebcam_device(core->factory); + else + return core->video_conf.device; +} + +// ----------------------------------------------------------------------------- + +void MediaSessionPrivate::fillMulticastMediaAddresses () { + if (params->audioMulticastEnabled()) + mediaPorts[mainAudioStreamIndex].multicastIp = linphone_core_get_audio_multicast_addr(core); + if (params->videoMulticastEnabled()) + mediaPorts[mainVideoStreamIndex].multicastIp = linphone_core_get_video_multicast_addr(core); +} + +int MediaSessionPrivate::selectFixedPort (int streamIndex, pair portRange) { + for (int triedPort = portRange.first; triedPort < (portRange.first + 100); triedPort += 2) { + bool alreadyUsed = false; + for (const bctbx_list_t *elem = linphone_core_get_calls(core); elem != nullptr; elem = bctbx_list_next(elem)) { + LinphoneCall *lcall = reinterpret_cast(bctbx_list_get_data(elem)); + CallPrivate *callp = linphone_call_get_cpp_obj(lcall)->getPrivate(); + MediaSession *session = dynamic_cast(callp->getConference()->getActiveParticipant()->getPrivate()->getSession().get()); + int existingPort = session->getPrivate()->mediaPorts[streamIndex].rtpPort; + if (existingPort == triedPort) { + alreadyUsed = true; + break; + } + } + if (!alreadyUsed) + return triedPort; + } + + lError() << "Could not find any free port !"; + return -1; +} + +int MediaSessionPrivate::selectRandomPort (int streamIndex, pair portRange) { + for (int nbTries = 0; nbTries < 100; nbTries++) { + bool alreadyUsed = false; + int triedPort = (ortp_random() % (portRange.second - portRange.first) + portRange.first) & ~0x1; + if (triedPort < portRange.first) triedPort = portRange.first + 2; + for (const bctbx_list_t *elem = linphone_core_get_calls(core); elem != nullptr; elem = bctbx_list_next(elem)) { + LinphoneCall *lcall = reinterpret_cast(bctbx_list_get_data(elem)); + CallPrivate *callp = linphone_call_get_cpp_obj(lcall)->getPrivate(); + MediaSession *session = dynamic_cast(callp->getConference()->getActiveParticipant()->getPrivate()->getSession().get()); + int existingPort = session->getPrivate()->mediaPorts[streamIndex].rtpPort; + if (existingPort == triedPort) { + alreadyUsed = true; + break; + } + } + if (!alreadyUsed) + return triedPort; + } + + lError() << "Could not find any free port!"; + return -1; +} + +void MediaSessionPrivate::setPortConfig(int streamIndex, pair portRange) { + if ((portRange.first <= 0) && (portRange.second <= 0)) { + setRandomPortConfig(streamIndex); + } else { + if (portRange.first == portRange.second) { + /* Fixed port */ + int port = selectFixedPort(streamIndex, portRange); + if (port == -1) { + setRandomPortConfig(streamIndex); + return; + } + mediaPorts[streamIndex].rtpPort = port; + } else { + /* Select random port in the specified range */ + mediaPorts[streamIndex].rtpPort = selectRandomPort(streamIndex, portRange); + } + mediaPorts[streamIndex].rtcpPort = mediaPorts[streamIndex].rtpPort + 1; + } +} + +void MediaSessionPrivate::setPortConfigFromRtpSession (int streamIndex, RtpSession *session) { + mediaPorts[streamIndex].rtpPort = rtp_session_get_local_port(session); + mediaPorts[streamIndex].rtcpPort = rtp_session_get_local_rtcp_port(session); +} + +void MediaSessionPrivate::setRandomPortConfig (int streamIndex) { + mediaPorts[streamIndex].rtpPort = -1; + mediaPorts[streamIndex].rtcpPort = -1; +} + +// ----------------------------------------------------------------------------- + +void MediaSessionPrivate::discoverMtu (const Address &remoteAddr) { + if (core->net_conf.mtu == 0) { + /* Attempt to discover mtu */ + int mtu = ms_discover_mtu(remoteAddr.getDomain().c_str()); + if (mtu > 0) { + ms_factory_set_mtu(core->factory, mtu); + lInfo() << "Discovered mtu is " << mtu << ", RTP payload max size is " << ms_factory_get_payload_max_size(core->factory); + } + } +} + +string MediaSessionPrivate::getBindIpForStream (int streamIndex) { + string bindIp = lp_config_get_string(linphone_core_get_config(core), "rtp", "bind_address", (af == AF_INET6) ? "::0" : "0.0.0.0"); + PortConfig *pc = &mediaPorts[streamIndex]; + if (!pc->multicastIp.empty()){ + if (direction == LinphoneCallOutgoing) { + /* As multicast sender, we must decide a local interface to use to send multicast, and bind to it */ + char multicastBindIp[LINPHONE_IPADDR_SIZE]; + memset(multicastBindIp, 0, sizeof(multicastBindIp)); + linphone_core_get_local_ip_for(pc->multicastIp.find_first_of(':') ? AF_INET6 : AF_INET, nullptr, multicastBindIp); + bindIp = pc->multicastBindIp = multicastBindIp; + } else { + /* Otherwise we shall use an address family of the same family of the multicast address, because + * dual stack socket and multicast don't work well on Mac OS (linux is OK, as usual). */ + bindIp = pc->multicastIp.find_first_of(':') ? "::0" : "0.0.0.0"; + } + } + return bindIp; +} + +/** + * Fill the local ip that routes to the internet according to the destination, or guess it by other special means. + */ +void MediaSessionPrivate::getLocalIp (const Address &remoteAddr) { + /* Next, sometime, override from config */ + const char *ip = lp_config_get_string(linphone_core_get_config(core), "rtp", "bind_address", nullptr); + if (ip) { + mediaLocalIp = ip; + return; + } + + /* If a known proxy was identified for this call, then we may have a chance to take the local ip address + * from the socket that connects to this proxy */ + if (destProxy && destProxy->op) { + ip = sal_op_get_local_address(destProxy->op, nullptr); + if (ip) { + lInfo() << "Found media local-ip from signaling."; + mediaLocalIp = ip; + return; + } + } + + /* In last resort, attempt to find the local ip that routes to destination if given as an IP address, + or the default route (dest == nullptr) */ + const char *dest = nullptr; + if (!destProxy) { + struct addrinfo hints; + struct addrinfo *res = nullptr; + int err; + /* FIXME the following doesn't work for IPv6 address because of brakets */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICHOST; + err = getaddrinfo(remoteAddr.getDomain().c_str(), NULL, &hints, &res); + if (err == 0) + dest = remoteAddr.getDomain().c_str(); + if (res) freeaddrinfo(res); + } + + if (dest || mediaLocalIp.empty() || needMediaLocalIpRefresh) { + needMediaLocalIpRefresh = false; + char ip[LINPHONE_IPADDR_SIZE]; + linphone_core_get_local_ip(core, af, dest, ip); + mediaLocalIp = ip; + } +} + +string MediaSessionPrivate::getPublicIpForStream (int streamIndex) { + if (!mediaPorts[streamIndex].multicastIp.empty()) + return mediaPorts[streamIndex].multicastIp; + return mediaLocalIp; +} + +void MediaSessionPrivate::runStunTestsIfNeeded () { + if (linphone_nat_policy_stun_enabled(natPolicy) && !(linphone_nat_policy_ice_enabled(natPolicy) || linphone_nat_policy_turn_enabled(natPolicy))) { + stunClient = new StunClient(core); + int ret = stunClient->run(mediaPorts[mainAudioStreamIndex].rtpPort, mediaPorts[mainVideoStreamIndex].rtpPort, mediaPorts[mainTextStreamIndex].rtpPort); + if (ret >= 0) + pingTime = ret; + } +} + +/* + * Select IP version to use for advertising local addresses of RTP streams, for an incoming call. + * If the call is received through a know proxy that is IPv6, use IPv6. + * Otherwise check the remote contact address. + * If later the resulting media description tells that we have to send IPv4, it won't be a problem because the RTP sockets + * are dual stack. + */ +void MediaSessionPrivate::selectIncomingIpVersion () { + if (linphone_core_ipv6_enabled(core)) { + if (destProxy && destProxy->op) + af = sal_op_get_address_family(destProxy->op); + else + af = sal_op_get_address_family(op); + } else + af = AF_INET; +} + +/* + * Choose IP version we are going to use for RTP streams IP address advertised in SDP. + * The algorithm is as follows: + * - if ipv6 is disabled at the core level, it is always AF_INET + * - Otherwise, if the destination address for the call is an IPv6 address, use IPv6. + * - Otherwise, if the call is done through a known proxy config, then use the information obtained during REGISTER + * to know if IPv6 is supported by the server. +**/ +void MediaSessionPrivate::selectOutgoingIpVersion () { + if (!linphone_core_ipv6_enabled(core)) { + af = AF_INET; + return; + } + + LinphoneAddress *to = linphone_call_log_get_to_address(log); + if (sal_address_is_ipv6(L_GET_PRIVATE_FROM_C_STRUCT(to, Address)->getInternalAddress())) + af = AF_INET6; + else if (destProxy && destProxy->op) + af = sal_op_get_address_family(destProxy->op); + else { + char ipv4[LINPHONE_IPADDR_SIZE]; + char ipv6[LINPHONE_IPADDR_SIZE]; + bool haveIpv6 = false; + bool haveIpv4 = false; + /* Check connectivity for IPv4 and IPv6 */ + if (linphone_core_get_local_ip_for(AF_INET6, NULL, ipv6) == 0) + haveIpv6 = true; + if (linphone_core_get_local_ip_for(AF_INET, NULL, ipv4) == 0) + haveIpv4 = true; + if (haveIpv6) { + if (!haveIpv4) + af = AF_INET6; + else if (lp_config_get_int(linphone_core_get_config(core), "rtp", "prefer_ipv6", 1)) /* This property tells whether ipv6 is prefered if two versions are available */ + af = AF_INET6; + else + af = AF_INET; + } else + af = AF_INET; + /* Fill the media_localip default value since we have it here */ + mediaLocalIp = (af == AF_INET6) ? ipv6 : ipv4; + } +} + +// ----------------------------------------------------------------------------- + +void MediaSessionPrivate::forceStreamsDirAccordingToState (SalMediaDescription *md) { + L_Q(MediaSession); + for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + SalStreamDescription *sd = &md->streams[i]; + switch (state) { + case LinphoneCallPausing: + case LinphoneCallPaused: + if (sd->dir != SalStreamInactive) { + sd->dir = SalStreamSendOnly; + if ((sd->type == SalVideo) && lp_config_get_int(linphone_core_get_config(core), "sip", "inactive_video_on_pause", 0)) + sd->dir = SalStreamInactive; + } + break; + default: + break; + } + /* Reflect the stream directions in the call params */ + if (i == mainAudioStreamIndex) + q->getCurrentParams()->setAudioDirection(MediaSessionParamsPrivate::salStreamDirToMediaDirection(sd->dir)); + else if (i == mainVideoStreamIndex) + q->getCurrentParams()->setVideoDirection(MediaSessionParamsPrivate::salStreamDirToMediaDirection(sd->dir)); + } +} + +bool MediaSessionPrivate::generateB64CryptoKey (size_t keyLength, char *keyOut, size_t keyOutSize) { + uint8_t *tmp = (uint8_t *)ms_malloc0(keyLength); + if (sal_get_random_bytes(tmp, keyLength)) { + lError() << "Failed to generate random key"; + ms_free(tmp); + return false; + } + size_t b64Size = b64::b64_encode((const char *)tmp, keyLength, nullptr, 0); + if (b64Size == 0) { + lError() << "Failed to get b64 result size"; + ms_free(tmp); + return false; + } + if (b64Size >= keyOutSize) { + lError() << "Insufficient room for writing base64 SRTP key"; + ms_free(tmp); + return false; + } + b64Size = b64::b64_encode((const char *)tmp, keyLength, keyOut, keyOutSize); + if (b64Size == 0) { + lError() << "Failed to b64 encode key"; + ms_free(tmp); + return false; + } + keyOut[b64Size] = '\0'; + ms_free(tmp); + return true; +} + +void MediaSessionPrivate::makeLocalMediaDescription () { + L_Q(MediaSession); + int maxIndex = 0; + bool rtcpMux = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_mux", 0); + SalMediaDescription *md = sal_media_description_new(); + SalMediaDescription *oldMd = localDesc; + + /* Multicast is only set in case of outgoing call */ + if (direction == LinphoneCallOutgoing) { + if (params->audioMulticastEnabled()) { + md->streams[mainAudioStreamIndex].ttl = linphone_core_get_audio_multicast_ttl(core); + md->streams[mainAudioStreamIndex].multicast_role = SalMulticastSender; + } + if (params->videoMulticastEnabled()) { + md->streams[mainVideoStreamIndex].ttl = linphone_core_get_video_multicast_ttl(core); + md->streams[mainVideoStreamIndex].multicast_role = SalMulticastSender; + } + } + + params->getPrivate()->adaptToNetwork(core, pingTime); + + string subject = q->getParams()->getSessionName(); + if (!subject.empty()) + strncpy(md->name, subject.c_str(), sizeof(md->name)); + md->session_id = (oldMd ? oldMd->session_id : (rand() & 0xfff)); + md->session_ver = (oldMd ? (oldMd->session_ver + 1) : (rand() & 0xfff)); + md->nb_streams = (biggestDesc ? biggestDesc->nb_streams : 1); + + /* Re-check local ip address each time we make a new offer, because it may change in case of network reconnection */ + getLocalIp(*L_GET_CPP_PTR_FROM_C_STRUCT((direction == LinphoneCallOutgoing) ? log->to : log->from, Address).get()); + strncpy(md->addr, mediaLocalIp.c_str(), sizeof(md->addr)); + LinphoneAddress *addr = nullptr; + if (destProxy) { + addr = linphone_address_clone(linphone_proxy_config_get_identity_address(destProxy)); + } else { + addr = linphone_address_new(linphone_core_get_identity(core)); + } + if (linphone_address_get_username(addr)) /* Might be null in case of identity without userinfo */ + strncpy(md->username, linphone_address_get_username(addr), sizeof(md->username)); + linphone_address_unref(addr); + + int bandwidth = params->getPrivate()->getDownBandwidth(); + if (bandwidth) + md->bandwidth = bandwidth; + else + md->bandwidth = linphone_core_get_download_bandwidth(core); + + SalCustomSdpAttribute *customSdpAttributes = params->getPrivate()->getCustomSdpAttributes(); + if (customSdpAttributes) + md->custom_sdp_attributes = sal_custom_sdp_attribute_clone(customSdpAttributes); + + PayloadTypeHandler pth(core); + + bctbx_list_t *l = pth.makeCodecsList(SalAudio, params->getAudioBandwidthLimit(), -1, + oldMd ? oldMd->streams[mainAudioStreamIndex].already_assigned_payloads : nullptr); + if (l && params->audioEnabled()) { + strncpy(md->streams[mainAudioStreamIndex].rtp_addr, getPublicIpForStream(mainAudioStreamIndex).c_str(), sizeof(md->streams[mainAudioStreamIndex].rtp_addr)); + strncpy(md->streams[mainAudioStreamIndex].rtcp_addr, getPublicIpForStream(mainAudioStreamIndex).c_str(), sizeof(md->streams[mainAudioStreamIndex].rtcp_addr)); + strncpy(md->streams[mainAudioStreamIndex].name, "Audio", sizeof(md->streams[mainAudioStreamIndex].name) - 1); + md->streams[mainAudioStreamIndex].rtp_port = mediaPorts[mainAudioStreamIndex].rtpPort; + md->streams[mainAudioStreamIndex].rtcp_port = mediaPorts[mainAudioStreamIndex].rtcpPort; + md->streams[mainAudioStreamIndex].proto = params->getMediaProto(); + md->streams[mainAudioStreamIndex].dir = params->getPrivate()->getSalAudioDirection(); + md->streams[mainAudioStreamIndex].type = SalAudio; + md->streams[mainAudioStreamIndex].rtcp_mux = rtcpMux; + int downPtime = params->getPrivate()->getDownPtime(); + if (downPtime) + md->streams[mainAudioStreamIndex].ptime = downPtime; + else + md->streams[mainAudioStreamIndex].ptime = linphone_core_get_download_ptime(core); + md->streams[mainAudioStreamIndex].max_rate = pth.getMaxCodecSampleRate(l); + md->streams[mainAudioStreamIndex].payloads = l; + if (audioStream && audioStream->ms.sessions.rtp_session) { + md->streams[mainAudioStreamIndex].rtp_ssrc = rtp_session_get_send_ssrc(audioStream->ms.sessions.rtp_session); + strncpy(md->streams[mainAudioStreamIndex].rtcp_cname, conference.getMe()->getAddress().asStringUriOnly().c_str(), sizeof(md->streams[mainAudioStreamIndex].rtcp_cname)); + } + else + lWarning() << "Cannot get audio local ssrc for CallSession [" << q << "]"; + if (mainAudioStreamIndex > maxIndex) + maxIndex = mainAudioStreamIndex; + } else { + lInfo() << "Don't put audio stream on local offer for CallSession [" << q << "]"; + md->streams[mainAudioStreamIndex].dir = SalStreamInactive; + if(l) + l = bctbx_list_free_with_data(l, (bctbx_list_free_func)payload_type_destroy); + } + SalCustomSdpAttribute *sdpMediaAttributes = params->getPrivate()->getCustomSdpMediaAttributes(LinphoneStreamTypeAudio); + if (sdpMediaAttributes) + md->streams[mainAudioStreamIndex].custom_sdp_attributes = sal_custom_sdp_attribute_clone(sdpMediaAttributes); + + md->streams[mainVideoStreamIndex].proto = md->streams[mainAudioStreamIndex].proto; + md->streams[mainVideoStreamIndex].dir = params->getPrivate()->getSalVideoDirection(); + md->streams[mainVideoStreamIndex].type = SalVideo; + md->streams[mainVideoStreamIndex].rtcp_mux = rtcpMux; + strncpy(md->streams[mainVideoStreamIndex].name, "Video", sizeof(md->streams[mainVideoStreamIndex].name) - 1); + + l = pth.makeCodecsList(SalVideo, 0, -1, + oldMd ? oldMd->streams[mainVideoStreamIndex].already_assigned_payloads : nullptr); + if (l && params->videoEnabled()){ + strncpy(md->streams[mainVideoStreamIndex].rtp_addr, getPublicIpForStream(mainVideoStreamIndex).c_str(), sizeof(md->streams[mainVideoStreamIndex].rtp_addr)); + strncpy(md->streams[mainVideoStreamIndex].rtcp_addr, getPublicIpForStream(mainVideoStreamIndex).c_str(), sizeof(md->streams[mainVideoStreamIndex].rtcp_addr)); + md->streams[mainVideoStreamIndex].rtp_port = mediaPorts[mainVideoStreamIndex].rtpPort; + md->streams[mainVideoStreamIndex].rtcp_port = mediaPorts[mainVideoStreamIndex].rtcpPort; + md->streams[mainVideoStreamIndex].payloads = l; + if (videoStream && videoStream->ms.sessions.rtp_session) { + md->streams[mainVideoStreamIndex].rtp_ssrc = rtp_session_get_send_ssrc(videoStream->ms.sessions.rtp_session); + strncpy(md->streams[mainVideoStreamIndex].rtcp_cname, conference.getMe()->getAddress().asStringUriOnly().c_str(), sizeof(md->streams[mainVideoStreamIndex].rtcp_cname)); + } else + lWarning() << "Cannot get video local ssrc for CallSession [" << q << "]"; + if (mainVideoStreamIndex > maxIndex) + maxIndex = mainVideoStreamIndex; + } else { + lInfo() << "Don't put video stream on local offer for CallSession [" << q << "]"; + md->streams[mainVideoStreamIndex].dir = SalStreamInactive; + if(l) + l = bctbx_list_free_with_data(l, (bctbx_list_free_func)payload_type_destroy); + } + sdpMediaAttributes = params->getPrivate()->getCustomSdpMediaAttributes(LinphoneStreamTypeVideo); + if (sdpMediaAttributes) + md->streams[mainVideoStreamIndex].custom_sdp_attributes = sal_custom_sdp_attribute_clone(sdpMediaAttributes); + + md->streams[mainTextStreamIndex].proto = md->streams[mainAudioStreamIndex].proto; + md->streams[mainTextStreamIndex].dir = SalStreamSendRecv; + md->streams[mainTextStreamIndex].type = SalText; + md->streams[mainTextStreamIndex].rtcp_mux = rtcpMux; + strncpy(md->streams[mainTextStreamIndex].name, "Text", sizeof(md->streams[mainTextStreamIndex].name) - 1); + if (params->realtimeTextEnabled()) { + strncpy(md->streams[mainTextStreamIndex].rtp_addr, getPublicIpForStream(mainTextStreamIndex).c_str(), sizeof(md->streams[mainTextStreamIndex].rtp_addr)); + strncpy(md->streams[mainTextStreamIndex].rtcp_addr, getPublicIpForStream(mainTextStreamIndex).c_str(), sizeof(md->streams[mainTextStreamIndex].rtcp_addr)); + + md->streams[mainTextStreamIndex].rtp_port = mediaPorts[mainTextStreamIndex].rtpPort; + md->streams[mainTextStreamIndex].rtcp_port = mediaPorts[mainTextStreamIndex].rtcpPort; + + l = pth.makeCodecsList(SalText, 0, -1, + oldMd ? oldMd->streams[mainTextStreamIndex].already_assigned_payloads : nullptr); + md->streams[mainTextStreamIndex].payloads = l; + if (textStream && textStream->ms.sessions.rtp_session) { + md->streams[mainTextStreamIndex].rtp_ssrc = rtp_session_get_send_ssrc(textStream->ms.sessions.rtp_session); + strncpy(md->streams[mainTextStreamIndex].rtcp_cname, conference.getMe()->getAddress().asStringUriOnly().c_str(), sizeof(md->streams[mainTextStreamIndex].rtcp_cname)); + } else + lWarning() << "Cannot get text local ssrc for CallSession [" << q << "]"; + if (mainTextStreamIndex > maxIndex) + maxIndex = mainTextStreamIndex; + } else { + lInfo() << "Don't put text stream on local offer for CallSession [" << q << "]"; + md->streams[mainTextStreamIndex].dir = SalStreamInactive; + } + sdpMediaAttributes = params->getPrivate()->getCustomSdpMediaAttributes(LinphoneStreamTypeText); + if (sdpMediaAttributes) + md->streams[mainTextStreamIndex].custom_sdp_attributes = sal_custom_sdp_attribute_clone(sdpMediaAttributes); + + md->nb_streams = MAX(md->nb_streams, maxIndex + 1); + + /* Deactivate unused streams */ + for (int i = md->nb_streams; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + if (md->streams[i].rtp_port == 0) { + md->streams[i].dir = SalStreamInactive; + if (biggestDesc && (i < biggestDesc->nb_streams)) { + md->streams[i].proto = biggestDesc->streams[i].proto; + md->streams[i].type = biggestDesc->streams[i].type; + } + } + } + setupEncryptionKeys(md); + setupDtlsKeys(md); + setupZrtpHash(md); + setupRtcpFb(md); + setupRtcpXr(md); + if (stunClient) + stunClient->updateMediaDescription(md); + localDesc = md; + updateLocalMediaDescriptionFromIce(); + if (oldMd) { + transferAlreadyAssignedPayloadTypes(oldMd, md); + localDescChanged = sal_media_description_equals(md, oldMd); + sal_media_description_unref(oldMd); + if (params->getPrivate()->getInternalCallUpdate()) { + /* + * An internal call update (ICE reINVITE) is not expected to modify the actual media stream parameters. + * However, the localDesc may change between first INVITE and ICE reINVITE, for example if the remote party has declined a video stream. + * We use the internalCallUpdate flag to prevent trigger an unnecessary media restart. + */ + localDescChanged = 0; + } + } + forceStreamsDirAccordingToState(md); +} + +void MediaSessionPrivate::setupDtlsKeys (SalMediaDescription *md) { + for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + if (!sal_stream_description_active(&md->streams[i])) + continue; + /* If media encryption is set to DTLS check presence of fingerprint in the call which shall have been set at stream init + * but it may have failed when retrieving certificate resulting in no fingerprint present and then DTLS not usable */ + if (sal_stream_description_has_dtls(&md->streams[i])) { + /* Get the self fingerprint from call (it's computed at stream init) */ + strncpy(md->streams[i].dtls_fingerprint, dtlsCertificateFingerprint.c_str(), sizeof(md->streams[i].dtls_fingerprint)); + /* If we are offering, SDP will have actpass setup attribute when role is unset, if we are responding the result mediadescription will be set to SalDtlsRoleIsClient */ + md->streams[i].dtls_role = SalDtlsRoleUnset; + } else { + md->streams[i].dtls_fingerprint[0] = '\0'; + md->streams[i].dtls_role = SalDtlsRoleInvalid; + } + } +} + +int MediaSessionPrivate::setupEncryptionKey (SalSrtpCryptoAlgo *crypto, MSCryptoSuite suite, unsigned int tag) { + crypto->tag = tag; + crypto->algo = suite; + size_t keylen = 0; + switch (suite) { + case MS_AES_128_SHA1_80: + case MS_AES_128_SHA1_32: + case MS_AES_128_NO_AUTH: + case MS_NO_CIPHER_SHA1_80: /* Not sure for this one */ + keylen = 30; + break; + case MS_AES_256_SHA1_80: + case MS_AES_CM_256_SHA1_80: + case MS_AES_256_SHA1_32: + keylen = 46; + break; + case MS_CRYPTO_SUITE_INVALID: + break; + } + if ((keylen == 0) || !generateB64CryptoKey(keylen, crypto->master_key, SAL_SRTP_KEY_SIZE)) { + lError() << "Could not generate SRTP key"; + crypto->algo = MS_CRYPTO_SUITE_INVALID; + return -1; + } + return 0; +} + +void MediaSessionPrivate::setupRtcpFb (SalMediaDescription *md) { + for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + if (!sal_stream_description_active(&md->streams[i])) + continue; + md->streams[i].rtcp_fb.generic_nack_enabled = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_fb_generic_nack_enabled", 0); + md->streams[i].rtcp_fb.tmmbr_enabled = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_fb_tmmbr_enabled", 1); + md->streams[i].implicit_rtcp_fb = params->getPrivate()->implicitRtcpFbEnabled(); + for (const bctbx_list_t *it = md->streams[i].payloads; it != nullptr; it = bctbx_list_next(it)) { + OrtpPayloadType *pt = reinterpret_cast(bctbx_list_get_data(it)); + PayloadTypeAvpfParams avpf_params; + if (!params->avpfEnabled() && !params->getPrivate()->implicitRtcpFbEnabled()) { + payload_type_unset_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); + memset(&avpf_params, 0, sizeof(avpf_params)); + } else { + payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); + avpf_params = payload_type_get_avpf_params(pt); + avpf_params.trr_interval = params->getAvpfRrInterval(); + } + payload_type_set_avpf_params(pt, avpf_params); + } + } +} + +void MediaSessionPrivate::setupRtcpXr (SalMediaDescription *md) { + md->rtcp_xr.enabled = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_xr_enabled", 1); + if (md->rtcp_xr.enabled) { + const char *rcvr_rtt_mode = lp_config_get_string(linphone_core_get_config(core), "rtp", "rtcp_xr_rcvr_rtt_mode", "all"); + if (strcasecmp(rcvr_rtt_mode, "all") == 0) + md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttAll; + else if (strcasecmp(rcvr_rtt_mode, "sender") == 0) + md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttSender; + else + md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttNone; + if (md->rtcp_xr.rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) + md->rtcp_xr.rcvr_rtt_max_size = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_xr_rcvr_rtt_max_size", 10000); + md->rtcp_xr.stat_summary_enabled = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_xr_stat_summary_enabled", 1); + if (md->rtcp_xr.stat_summary_enabled) + md->rtcp_xr.stat_summary_flags = OrtpRtcpXrStatSummaryLoss | OrtpRtcpXrStatSummaryDup | OrtpRtcpXrStatSummaryJitt | OrtpRtcpXrStatSummaryTTL; + md->rtcp_xr.voip_metrics_enabled = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_xr_voip_metrics_enabled", 1); + } + for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + if (!sal_stream_description_active(&md->streams[i])) + continue; + memcpy(&md->streams[i].rtcp_xr, &md->rtcp_xr, sizeof(md->streams[i].rtcp_xr)); + } +} + +void MediaSessionPrivate::setupZrtpHash (SalMediaDescription *md) { + if (linphone_core_media_encryption_supported(core, LinphoneMediaEncryptionZRTP)) { + /* Set the hello hash for all streams */ + for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + if (!sal_stream_description_active(&md->streams[i])) + continue; + if (sessions[i].zrtp_context) { + ms_zrtp_getHelloHash(sessions[i].zrtp_context, md->streams[i].zrtphash, 128); + /* Turn on the flag to use it if ZRTP is set */ + md->streams[i].haveZrtpHash = (params->getMediaEncryption() == LinphoneMediaEncryptionZRTP); + } else + md->streams[i].haveZrtpHash = 0; + } + } +} + +void MediaSessionPrivate::setupEncryptionKeys (SalMediaDescription *md) { + SalMediaDescription *oldMd = localDesc; + bool keepSrtpKeys = lp_config_get_int(linphone_core_get_config(core), "sip", "keep_srtp_keys", 1); + for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + if (!sal_stream_description_active(&md->streams[i])) + continue; + if (sal_stream_description_has_srtp(&md->streams[i])) { + if (keepSrtpKeys && oldMd && sal_stream_description_active(&oldMd->streams[i]) && sal_stream_description_has_srtp(&oldMd->streams[i])) { + lInfo() << "Keeping same crypto keys"; + for (int j = 0; j < SAL_CRYPTO_ALGO_MAX; j++) { + memcpy(&md->streams[i].crypto[j], &oldMd->streams[i].crypto[j], sizeof(SalSrtpCryptoAlgo)); + } + } else { + const MSCryptoSuite *suites = linphone_core_get_srtp_crypto_suites(core); + for (int j = 0; (suites != nullptr) && (suites[j] != MS_CRYPTO_SUITE_INVALID) && (j < SAL_CRYPTO_ALGO_MAX); j++) { + setupEncryptionKey(&md->streams[i].crypto[j], suites[j], j + 1); + } + } + } + } +} + +void MediaSessionPrivate::transferAlreadyAssignedPayloadTypes (SalMediaDescription *oldMd, SalMediaDescription *md) { + for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + md->streams[i].already_assigned_payloads = oldMd->streams[i].already_assigned_payloads; + oldMd->streams[i].already_assigned_payloads = nullptr; + } +} + +void MediaSessionPrivate::updateLocalMediaDescriptionFromIce () { + iceAgent->updateLocalMediaDescriptionFromIce(localDesc); + iceAgent->updateIceStateInCallStats(); +} + +// ----------------------------------------------------------------------------- + +SalMulticastRole MediaSessionPrivate::getMulticastRole (SalStreamType type) { + L_Q(MediaSession); + SalMulticastRole multicastRole = SalMulticastInactive; + if (op) { + SalStreamDescription *streamDesc = nullptr; + SalMediaDescription *remoteDesc = sal_call_get_remote_media_description(op); + if (!localDesc && !remoteDesc && (direction == LinphoneCallOutgoing)) { + /* Well using call dir */ + if (((type == SalAudio) && params->audioMulticastEnabled()) + || ((type == SalVideo) && params->videoMulticastEnabled())) + multicastRole = SalMulticastSender; + } else if (localDesc && (!remoteDesc || sal_call_is_offerer(op))) { + streamDesc = sal_media_description_find_best_stream(localDesc, type); + } else if (!sal_call_is_offerer(op) && remoteDesc) { + streamDesc = sal_media_description_find_best_stream(remoteDesc, type); + } + + if (streamDesc) + multicastRole = streamDesc->multicast_role; + } + lInfo() << "CallSession [" << q << "], stream type [" << sal_stream_type_to_string(type) << "], multicast role is [" + << sal_multicast_role_to_string(multicastRole) << "]"; + return multicastRole; +} + +void MediaSessionPrivate::joinMulticastGroup (int streamIndex, MediaStream *ms) { + L_Q(MediaSession); + if (!mediaPorts[streamIndex].multicastIp.empty()) + media_stream_join_multicast_group(ms, mediaPorts[streamIndex].multicastIp.c_str()); + else + lError() << "Cannot join multicast group if multicast ip is not set for call [" << q << "]"; +} + +// ----------------------------------------------------------------------------- + +int MediaSessionPrivate::findCryptoIndexFromTag (const SalSrtpCryptoAlgo crypto[], unsigned char tag) { + for (int i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) { + if (crypto[i].tag == tag) + return i; + } + return -1; +} + +void MediaSessionPrivate::setDtlsFingerprint (MSMediaStreamSessions *sessions, const SalStreamDescription *sd, const SalStreamDescription *remote) { + if (sal_stream_description_has_dtls(sd)) { + if (sd->dtls_role == SalDtlsRoleInvalid) + lWarning() << "Unable to start DTLS engine on stream session [" << sessions << "], Dtls role in resulting media description is invalid"; + else { /* If DTLS is available at both end points */ + /* Give the peer certificate fingerprint to dtls context */ + ms_dtls_srtp_set_peer_fingerprint(sessions->dtls_context, remote->dtls_fingerprint); + } + } +} + +void MediaSessionPrivate::setDtlsFingerprintOnAllStreams () { + SalMediaDescription *remote = sal_call_get_remote_media_description(op); + SalMediaDescription *result = sal_call_get_final_media_description(op); + if (!remote || !result) { + /* This can happen in some tricky cases (early-media without SDP in the 200). In that case, simply skip DTLS code */ + return; + } + if (audioStream && (media_stream_get_state(&audioStream->ms) == MSStreamStarted)) + setDtlsFingerprint(&audioStream->ms.sessions, sal_media_description_find_best_stream(result, SalAudio), sal_media_description_find_best_stream(remote, SalAudio)); +#if VIDEO_ENABLED + if (videoStream && (media_stream_get_state(&videoStream->ms) == MSStreamStarted)) + setDtlsFingerprint(&videoStream->ms.sessions, sal_media_description_find_best_stream(result, SalVideo), sal_media_description_find_best_stream(remote, SalVideo)); +#endif + if (textStream && (media_stream_get_state(&textStream->ms) == MSStreamStarted)) + setDtlsFingerprint(&textStream->ms.sessions, sal_media_description_find_best_stream(result, SalText), sal_media_description_find_best_stream(remote, SalText)); +} + +void MediaSessionPrivate::setupDtlsParams (MediaStream *ms) { + if (params->getMediaEncryption() == LinphoneMediaEncryptionDTLS) { + MSDtlsSrtpParams params; + memset(¶ms, 0, sizeof(MSDtlsSrtpParams)); + /* TODO : search for a certificate with CNAME=sip uri(retrieved from variable me) or default : linphone-dtls-default-identity */ + /* This will parse the directory to find a matching fingerprint or generate it if not found */ + /* returned string must be freed */ + char *certificate = nullptr; + char *key = nullptr; + char *fingerprint = nullptr; + sal_certificates_chain_parse_directory(&certificate, &key, &fingerprint, + linphone_core_get_user_certificates_path(core), "linphone-dtls-default-identity", SAL_CERTIFICATE_RAW_FORMAT_PEM, true, true); + if (fingerprint) { + dtlsCertificateFingerprint = fingerprint; + ms_free(fingerprint); + } + if (key && certificate) { + params.pem_certificate = certificate; + params.pem_pkey = key; + params.role = MSDtlsSrtpRoleUnset; /* Default is unset, then check if we have a result SalMediaDescription */ + media_stream_enable_dtls(ms, ¶ms); + ms_free(certificate); + ms_free(key); + } else { + lError() << "Unable to retrieve or generate DTLS certificate and key - DTLS disabled"; + /* TODO : check if encryption forced, if yes, stop call */ + } + } +} + +void MediaSessionPrivate::setZrtpCryptoTypesParameters (MSZrtpParams *params) { + if (!params) + return; + + const MSCryptoSuite *srtpSuites = linphone_core_get_srtp_crypto_suites(core); + if (srtpSuites) { + for(int i = 0; (srtpSuites[i] != MS_CRYPTO_SUITE_INVALID) && (i < SAL_CRYPTO_ALGO_MAX) && (i < MS_MAX_ZRTP_CRYPTO_TYPES); i++) { + switch (srtpSuites[i]) { + case MS_AES_128_SHA1_32: + params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1; + params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS32; + break; + case MS_AES_128_NO_AUTH: + params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1; + break; + case MS_NO_CIPHER_SHA1_80: + params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80; + break; + case MS_AES_128_SHA1_80: + params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1; + params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80; + break; + case MS_AES_CM_256_SHA1_80: + lWarning() << "Deprecated crypto suite MS_AES_CM_256_SHA1_80, use MS_AES_256_SHA1_80 instead"; + BCTBX_NO_BREAK; + case MS_AES_256_SHA1_80: + params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES3; + params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80; + break; + case MS_AES_256_SHA1_32: + params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES3; + params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS32; + break; + case MS_CRYPTO_SUITE_INVALID: + break; + } + } + } + + /* linphone_core_get_srtp_crypto_suites is used to determine sensible defaults; here each can be overridden */ + MsZrtpCryptoTypesCount ciphersCount = linphone_core_get_zrtp_cipher_suites(core, params->ciphers); /* if not present in config file, params->ciphers is not modified */ + if (ciphersCount != 0) /* Use zrtp_cipher_suites config only when present, keep config from srtp_crypto_suite otherwise */ + params->ciphersCount = ciphersCount; + params->hashesCount = linphone_core_get_zrtp_hash_suites(core, params->hashes); + MsZrtpCryptoTypesCount authTagsCount = linphone_core_get_zrtp_auth_suites(core, params->authTags); /* If not present in config file, params->authTags is not modified */ + if (authTagsCount != 0) + params->authTagsCount = authTagsCount; /* Use zrtp_auth_suites config only when present, keep config from srtp_crypto_suite otherwise */ + params->sasTypesCount = linphone_core_get_zrtp_sas_suites(core, params->sasTypes); + params->keyAgreementsCount = linphone_core_get_zrtp_key_agreement_suites(core, params->keyAgreements); +} + +void MediaSessionPrivate::startDtls (MSMediaStreamSessions *sessions, const SalStreamDescription *sd, const SalStreamDescription *remote) { + if (sal_stream_description_has_dtls(sd)) { + if (sd->dtls_role == SalDtlsRoleInvalid) + lWarning() << "Unable to start DTLS engine on stream session [" << sessions << "], Dtls role in resulting media description is invalid"; + else { /* If DTLS is available at both end points */ + /* Give the peer certificate fingerprint to dtls context */ + ms_dtls_srtp_set_peer_fingerprint(sessions->dtls_context, remote->dtls_fingerprint); + ms_dtls_srtp_set_role(sessions->dtls_context, (sd->dtls_role == SalDtlsRoleIsClient) ? MSDtlsSrtpRoleIsClient : MSDtlsSrtpRoleIsServer); /* Set the role to client */ + ms_dtls_srtp_start(sessions->dtls_context); /* Then start the engine, it will send the DTLS client Hello */ + } + } +} + +void MediaSessionPrivate::startDtlsOnAllStreams () { + SalMediaDescription *remote = sal_call_get_remote_media_description(op); + SalMediaDescription *result = sal_call_get_final_media_description(op); + if (!remote || !result) { + /* This can happen in some tricky cases (early-media without SDP in the 200). In that case, simply skip DTLS code */ + return; + } + if (audioStream && (media_stream_get_state(&audioStream->ms) == MSStreamStarted)) + startDtls(&audioStream->ms.sessions, sal_media_description_find_best_stream(result, SalAudio), sal_media_description_find_best_stream(remote, SalAudio)); +#if VIDEO_ENABLED + if (videoStream && (media_stream_get_state(&videoStream->ms) == MSStreamStarted)) + startDtls(&videoStream->ms.sessions, sal_media_description_find_best_stream(result, SalVideo), sal_media_description_find_best_stream(remote, SalVideo)); +#endif + if (textStream && (media_stream_get_state(&textStream->ms) == MSStreamStarted)) + startDtls(&textStream->ms.sessions, sal_media_description_find_best_stream(result, SalText), sal_media_description_find_best_stream(remote, SalText)); +} + +void MediaSessionPrivate::updateCryptoParameters (SalMediaDescription *oldMd, SalMediaDescription *newMd) { + const SalStreamDescription *localStreamDesc = sal_media_description_find_secure_stream_of_type(localDesc, SalAudio); + SalStreamDescription *oldStream = sal_media_description_find_secure_stream_of_type(oldMd, SalAudio); + SalStreamDescription *newStream = sal_media_description_find_secure_stream_of_type(newMd, SalAudio); + if (audioStream && localStreamDesc && oldStream && newStream) + updateStreamCryptoParameters(localStreamDesc, oldStream, newStream, &audioStream->ms); +#ifdef VIDEO_ENABLED + localStreamDesc = sal_media_description_find_secure_stream_of_type(localDesc, SalVideo); + oldStream = sal_media_description_find_secure_stream_of_type(oldMd, SalVideo); + newStream = sal_media_description_find_secure_stream_of_type(newMd, SalVideo); + if (videoStream && localStreamDesc && oldStream && newStream) + updateStreamCryptoParameters(localStreamDesc, oldStream, newStream, &videoStream->ms); +#endif + localStreamDesc = sal_media_description_find_secure_stream_of_type(localDesc, SalText); + oldStream = sal_media_description_find_secure_stream_of_type(oldMd, SalText); + newStream = sal_media_description_find_secure_stream_of_type(newMd, SalText); + if (textStream && localStreamDesc && oldStream && newStream) + updateStreamCryptoParameters(localStreamDesc, oldStream, newStream, &textStream->ms); + startDtlsOnAllStreams(); +} + +bool MediaSessionPrivate::updateStreamCryptoParameters (const SalStreamDescription *localStreamDesc, SalStreamDescription *oldStream, SalStreamDescription *newStream, MediaStream *ms) { + int cryptoIdx = findCryptoIndexFromTag(localStreamDesc->crypto, newStream->crypto_local_tag); + if (cryptoIdx >= 0) { + if (localDescChanged & SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED) + ms_media_stream_sessions_set_srtp_send_key_b64(&ms->sessions, newStream->crypto[0].algo, localStreamDesc->crypto[cryptoIdx].master_key); + if (strcmp(oldStream->crypto[0].master_key, newStream->crypto[0].master_key) != 0) + ms_media_stream_sessions_set_srtp_recv_key_b64(&ms->sessions, newStream->crypto[0].algo, newStream->crypto[0].master_key); + return true; + } else + lWarning() << "Failed to find local crypto algo with tag: " << newStream->crypto_local_tag; + return false; +} + +// ----------------------------------------------------------------------------- + +int MediaSessionPrivate::getIdealAudioBandwidth (const SalMediaDescription *md, const SalStreamDescription *desc) { + int remoteBandwidth = 0; + if (desc->bandwidth > 0) + remoteBandwidth = desc->bandwidth; + else if (md->bandwidth > 0) { + /* Case where b=AS is given globally, not per stream */ + remoteBandwidth = md->bandwidth; + } + int uploadBandwidth = 0; + bool forced = false; + if (params->getPrivate()->getUpBandwidth() > 0) { + forced = true; + uploadBandwidth = params->getPrivate()->getUpBandwidth(); + } else + uploadBandwidth = linphone_core_get_upload_bandwidth(core); + uploadBandwidth = PayloadTypeHandler::getMinBandwidth(uploadBandwidth, remoteBandwidth); + if (!linphone_core_media_description_contains_video_stream(md) || forced) + return uploadBandwidth; + if (PayloadTypeHandler::bandwidthIsGreater(uploadBandwidth, 512)) + uploadBandwidth = 100; + else if (PayloadTypeHandler::bandwidthIsGreater(uploadBandwidth, 256)) + uploadBandwidth = 64; + else if (PayloadTypeHandler::bandwidthIsGreater(uploadBandwidth, 128)) + uploadBandwidth = 40; + else if (PayloadTypeHandler::bandwidthIsGreater(uploadBandwidth, 0)) + uploadBandwidth = 24; + return uploadBandwidth; +} + +int MediaSessionPrivate::getVideoBandwidth (const SalMediaDescription *md, const SalStreamDescription *desc) { + int remoteBandwidth = 0; + if (desc->bandwidth > 0) + remoteBandwidth = desc->bandwidth; + else if (md->bandwidth > 0) { + /* Case where b=AS is given globally, not per stream */ + remoteBandwidth = PayloadTypeHandler::getRemainingBandwidthForVideo(md->bandwidth, audioBandwidth); + } else + remoteBandwidth = lp_config_get_int(linphone_core_get_config(core), "net", "default_max_bandwidth", 1500); + return PayloadTypeHandler::getMinBandwidth(PayloadTypeHandler::getRemainingBandwidthForVideo(linphone_core_get_upload_bandwidth(core), audioBandwidth), remoteBandwidth); +} + +RtpProfile * MediaSessionPrivate::makeProfile (const SalMediaDescription *md, const SalStreamDescription *desc, int *usedPt) { + *usedPt = -1; + int bandwidth = 0; + if (desc->type == SalAudio) + bandwidth = getIdealAudioBandwidth(md, desc); + else if (desc->type == SalVideo) + bandwidth = getVideoBandwidth(md, desc); + + bool first = true; + RtpProfile *profile = rtp_profile_new("Call profile"); + for (const bctbx_list_t *elem = desc->payloads; elem != nullptr; elem = bctbx_list_next(elem)) { + OrtpPayloadType *pt = reinterpret_cast(bctbx_list_get_data(elem)); + /* Make a copy of the payload type, so that we left the ones from the SalStreamDescription unchanged. + * If the SalStreamDescription is freed, this will have no impact on the running streams. */ + pt = payload_type_clone(pt); + int upPtime = 0; + if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) { + /* First codec in list is the selected one */ + if (desc->type == SalAudio) { + updateAllocatedAudioBandwidth(pt, bandwidth); + bandwidth = audioBandwidth; + upPtime = params->getPrivate()->getUpPtime(); + if (!upPtime) + upPtime = linphone_core_get_upload_ptime(core); + } + first = false; + } + if (*usedPt == -1) { + /* Don't select telephone-event as a payload type */ + if (strcasecmp(pt->mime_type, "telephone-event") != 0) + *usedPt = payload_type_get_number(pt); + } + if (pt->flags & PAYLOAD_TYPE_BITRATE_OVERRIDE) { + lInfo() << "Payload type [" << pt->mime_type << "/" << pt->clock_rate << "] has explicit bitrate [" << (pt->normal_bitrate / 1000) << "] kbit/s"; + pt->normal_bitrate = PayloadTypeHandler::getMinBandwidth(pt->normal_bitrate, bandwidth * 1000); + } else + pt->normal_bitrate = bandwidth * 1000; + if (desc->ptime > 0) + upPtime = desc->ptime; + if (upPtime > 0) { + ostringstream os; + os << "ptime=" << upPtime; + payload_type_append_send_fmtp(pt, os.str().c_str()); + } + int number = payload_type_get_number(pt); + if (rtp_profile_get_payload(profile, number)) + lWarning() << "A payload type with number " << number << " already exists in profile!"; + else + rtp_profile_set_payload(profile, number, pt); + } + return profile; +} + +void MediaSessionPrivate::unsetRtpProfile (int streamIndex) { + if (sessions[streamIndex].rtp_session) + rtp_session_set_profile(sessions[streamIndex].rtp_session, &av_profile); +} + +void MediaSessionPrivate::updateAllocatedAudioBandwidth (const PayloadType *pt, int maxbw) { + L_Q(MediaSession); + audioBandwidth = PayloadTypeHandler::getAudioPayloadTypeBandwidth(pt, maxbw); + lInfo() << "Audio bandwidth for CallSession [" << q << "] is " << audioBandwidth; +} + +// ----------------------------------------------------------------------------- + +void MediaSessionPrivate::applyJitterBufferParams (RtpSession *session, LinphoneStreamType type) { + LinphoneConfig *config = linphone_core_get_config(core); + JBParameters params; + rtp_session_get_jitter_buffer_params(session, ¶ms); + params.min_size = lp_config_get_int(config, "rtp", "jitter_buffer_min_size", 40); + params.max_size = lp_config_get_int(config, "rtp", "jitter_buffer_max_size", 250); + params.max_packets = params.max_size * 200 / 1000; /* Allow 200 packet per seconds, quite large */ + const char *algo = lp_config_get_string(config, "rtp", "jitter_buffer_algorithm", "rls"); + params.buffer_algorithm = jitterBufferNameToAlgo(algo ? algo : ""); + params.refresh_ms = lp_config_get_int(config, "rtp", "jitter_buffer_refresh_period", 5000); + params.ramp_refresh_ms = lp_config_get_int(config, "rtp", "jitter_buffer_ramp_refresh_period", 5000); + params.ramp_step_ms = lp_config_get_int(config, "rtp", "jitter_buffer_ramp_step", 20); + params.ramp_threshold = lp_config_get_int(config, "rtp", "jitter_buffer_ramp_threshold", 70); + + switch (type) { + case LinphoneStreamTypeAudio: + case LinphoneStreamTypeText: /* Let's use the same params for text as for audio */ + params.nom_size = linphone_core_get_audio_jittcomp(core); + params.adaptive = linphone_core_audio_adaptive_jittcomp_enabled(core); + break; + case LinphoneStreamTypeVideo: + params.nom_size = linphone_core_get_video_jittcomp(core); + params.adaptive = linphone_core_video_adaptive_jittcomp_enabled(core); + break; + case LinphoneStreamTypeUnknown: + lFatal() << "applyJitterBufferParams: should not happen"; + break; + } + params.enabled = params.nom_size > 0; + if (params.enabled) { + if (params.min_size > params.nom_size) + params.min_size = params.nom_size; + if (params.max_size < params.nom_size) + params.max_size = params.nom_size; + } + rtp_session_set_jitter_buffer_params(session, ¶ms); +} + +void MediaSessionPrivate::clearEarlyMediaDestination (MediaStream *ms) { + RtpSession *session = ms->sessions.rtp_session; + rtp_session_clear_aux_remote_addr(session); + /* Restore symmetric rtp if ICE is not used */ + if (!iceAgent->hasSession()) + rtp_session_set_symmetric_rtp(session, linphone_core_symmetric_rtp_enabled(core)); +} + +void MediaSessionPrivate::clearEarlyMediaDestinations () { + if (audioStream) + clearEarlyMediaDestination(&audioStream->ms); + if (videoStream) + clearEarlyMediaDestination(&videoStream->ms); +} + +void MediaSessionPrivate::configureAdaptiveRateControl (MediaStream *ms, const OrtpPayloadType *pt, bool videoWillBeUsed) { + L_Q(MediaSession); + bool enabled = linphone_core_adaptive_rate_control_enabled(core); + if (!enabled) { + media_stream_enable_adaptive_bitrate_control(ms, false); + return; + } + bool isAdvanced = true; + string algo = linphone_core_get_adaptive_rate_algorithm(core); + if (algo == "basic") + isAdvanced = false; + else if (algo == "advanced") + isAdvanced = true; + if (isAdvanced) { + /* We can't use media_stream_avpf_enabled() here because the active PayloadType is not set yet in the MediaStream */ + if (!pt || !(pt->flags & PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED)) { + lWarning() << "CallSession [" << q << "] - advanced adaptive rate control requested but avpf is not activated in this stream. Reverting to basic rate control instead"; + isAdvanced = false; + } else + lInfo() << "CallSession [" << q << "] - setting up advanced rate control"; + } + if (isAdvanced) { + ms_bandwidth_controller_add_stream(core->bw_controller, ms); + media_stream_enable_adaptive_bitrate_control(ms, false); + } else { + media_stream_set_adaptive_bitrate_algorithm(ms, MSQosAnalyzerAlgorithmSimple); + if ((ms->type == MSAudio) && videoWillBeUsed) { + /* If this is an audio stream but video is going to be used, there is no need to perform + * basic rate control on the audio stream, just the video stream. */ + enabled = false; + } + media_stream_enable_adaptive_bitrate_control(ms, enabled); + } +} + +void MediaSessionPrivate::configureRtpSessionForRtcpFb (const SalStreamDescription *stream) { + RtpSession *session = nullptr; + if (stream->type == SalAudio) + session = audioStream->ms.sessions.rtp_session; + else if (stream->type == SalVideo) + session = videoStream->ms.sessions.rtp_session; + else + return; /* Do nothing for streams that are not audio or video */ + if (stream->rtcp_fb.generic_nack_enabled) + rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_GENERIC_NACK, true); + else + rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_GENERIC_NACK, false); + if (stream->rtcp_fb.tmmbr_enabled) + rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_TMMBR, true); + else + rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_TMMBR, false); +} + +void MediaSessionPrivate::configureRtpSessionForRtcpXr (SalStreamType type) { + SalMediaDescription *remote = sal_call_get_remote_media_description(op); + if (!remote) + return; + const SalStreamDescription *localStream = sal_media_description_find_best_stream(localDesc, type); + if (!localStream) + return; + const SalStreamDescription *remoteStream = sal_media_description_find_best_stream(remote, type); + if (!remoteStream) + return; + OrtpRtcpXrConfiguration currentConfig; + const OrtpRtcpXrConfiguration *remoteConfig = &remoteStream->rtcp_xr; + if (localStream->dir == SalStreamInactive) + return; + else if (localStream->dir == SalStreamRecvOnly) { + /* Use local config for unilateral parameters and remote config for collaborative parameters */ + memcpy(¤tConfig, &localStream->rtcp_xr, sizeof(currentConfig)); + currentConfig.rcvr_rtt_mode = remoteConfig->rcvr_rtt_mode; + currentConfig.rcvr_rtt_max_size = remoteConfig->rcvr_rtt_max_size; + } else + memcpy(¤tConfig, remoteConfig, sizeof(currentConfig)); + RtpSession *session = nullptr; + if (type == SalAudio) { + session = audioStream->ms.sessions.rtp_session; + } else if (type == SalVideo) { + session = videoStream->ms.sessions.rtp_session; + } else if (type == SalText) { + session = textStream->ms.sessions.rtp_session; + } + rtp_session_configure_rtcp_xr(session, ¤tConfig); +} + +RtpSession * MediaSessionPrivate::createAudioRtpIoSession () { + LinphoneConfig *config = linphone_core_get_config(core); + const char *rtpmap = lp_config_get_string(config, "sound", "rtp_map", "pcmu/8000/1"); + OrtpPayloadType *pt = rtp_profile_get_payload_from_rtpmap(audioProfile, rtpmap); + if (!pt) + return nullptr; + rtpIoAudioProfile = rtp_profile_new("RTP IO audio profile"); + int ptnum = lp_config_get_int(config, "sound", "rtp_ptnum", 0); + rtp_profile_set_payload(rtpIoAudioProfile, ptnum, payload_type_clone(pt)); + const char *localIp = lp_config_get_string(config, "sound", "rtp_local_addr", "127.0.0.1"); + int localPort = lp_config_get_int(config, "sound", "rtp_local_port", 17076); + RtpSession *rtpSession = ms_create_duplex_rtp_session(localIp, localPort, -1, ms_factory_get_mtu(core->factory)); + rtp_session_set_profile(rtpSession, rtpIoAudioProfile); + const char *remoteIp = lp_config_get_string(config, "sound", "rtp_remote_addr", "127.0.0.1"); + int remotePort = lp_config_get_int(config, "sound", "rtp_remote_port", 17078); + rtp_session_set_remote_addr_and_port(rtpSession, remoteIp, remotePort, -1); + rtp_session_enable_rtcp(rtpSession, false); + rtp_session_set_payload_type(rtpSession, ptnum); + int jittcomp = lp_config_get_int(config, "sound", "rtp_jittcomp", 0); /* 0 means no jitter buffer */ + rtp_session_set_jitter_compensation(rtpSession, jittcomp); + rtp_session_enable_jitter_buffer(rtpSession, (jittcomp > 0)); + bool symmetric = lp_config_get_int(config, "sound", "rtp_symmetric", 0); + rtp_session_set_symmetric_rtp(rtpSession, symmetric); + return rtpSession; +} + +RtpSession * MediaSessionPrivate::createVideoRtpIoSession () { +#ifdef VIDEO_ENABLED + LinphoneConfig *config = linphone_core_get_config(core); + const char *rtpmap = lp_config_get_string(config, "video", "rtp_map", "vp8/90000/1"); + OrtpPayloadType *pt = rtp_profile_get_payload_from_rtpmap(videoProfile, rtpmap); + if (!pt) + return nullptr; + rtpIoVideoProfile = rtp_profile_new("RTP IO video profile"); + int ptnum = lp_config_get_int(config, "video", "rtp_ptnum", 0); + rtp_profile_set_payload(rtpIoVideoProfile, ptnum, payload_type_clone(pt)); + const char *localIp = lp_config_get_string(config, "video", "rtp_local_addr", "127.0.0.1"); + int localPort = lp_config_get_int(config, "video", "rtp_local_port", 19076); + RtpSession *rtpSession = ms_create_duplex_rtp_session(localIp, localPort, -1, ms_factory_get_mtu(core->factory)); + rtp_session_set_profile(rtpSession, rtpIoVideoProfile); + const char *remoteIp = lp_config_get_string(config, "video", "rtp_remote_addr", "127.0.0.1"); + int remotePort = lp_config_get_int(config, "video", "rtp_remote_port", 19078); + rtp_session_set_remote_addr_and_port(rtpSession, remoteIp, remotePort, -1); + rtp_session_enable_rtcp(rtpSession, false); + rtp_session_set_payload_type(rtpSession, ptnum); + bool symmetric = lp_config_get_int(config, "video", "rtp_symmetric", 0); + rtp_session_set_symmetric_rtp(rtpSession, symmetric); + int jittcomp = lp_config_get_int(config, "video", "rtp_jittcomp", 0); /* 0 means no jitter buffer */ + rtp_session_set_jitter_compensation(rtpSession, jittcomp); + rtp_session_enable_jitter_buffer(rtpSession, (jittcomp > 0)); + return rtpSession; +#else + return nullptr; +#endif +} + +/* + * Frees the media resources of the call. + * This has to be done at the earliest, unlike signaling resources that sometimes need to be kept a bit more longer. + * It is called by setTerminated() (for termination of calls signaled to the application), or directly by the destructor of the session + * if it was never notified to the application. + */ +void MediaSessionPrivate::freeResources () { + stopStreams(); + iceAgent->deleteSession(); + for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) + ms_media_stream_sessions_uninit(&sessions[i]); + linphone_call_stats_uninit(audioStats); + linphone_call_stats_uninit(videoStats); + linphone_call_stats_uninit(textStats); +} + +void MediaSessionPrivate::handleIceEvents (OrtpEvent *ev) { + L_Q(MediaSession); + OrtpEventType evt = ortp_event_get_type(ev); + OrtpEventData *evd = ortp_event_get_data(ev); + if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { + if (iceAgent->hasCompletedCheckList()) { + /* At least one ICE session has succeeded, so perform a call update */ + if (iceAgent->isControlling() && q->getCurrentParams()->getPrivate()->getUpdateCallWhenIceCompleted()) { + shared_ptr newParams = make_shared(*params.get()); + newParams->getPrivate()->setInternalCallUpdate(true); + q->update(newParams); + } + startDtlsOnAllStreams(); + } + iceAgent->updateIceStateInCallStats(); + } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) { + if (!evd->info.ice_processing_successful) + lWarning() << "No STUN answer from [" << linphone_core_get_stun_server(core) << "], continuing without STUN"; + iceAgent->gatheringFinished(); + switch (state) { + case LinphoneCallUpdating: + startUpdate(); + break; + case LinphoneCallUpdatedByRemote: + startAcceptUpdate(prevState, linphone_call_state_to_string(prevState)); + break; + case LinphoneCallOutgoingInit: + stopStreamsForIceGathering(); + if (isReadyForInvite()) + q->startInvite(nullptr); + break; + case LinphoneCallIdle: + stopStreamsForIceGathering(); + updateLocalMediaDescriptionFromIce(); + sal_call_set_local_media_description(op, localDesc); + deferIncomingNotification = false; + static_cast(q)->startIncomingNotification(); + break; + default: + break; + } + } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) { + if (state == LinphoneCallUpdatedByRemote) { + startAcceptUpdate(prevState, linphone_call_state_to_string(prevState)); + iceAgent->updateIceStateInCallStats(); + } + } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) { + iceAgent->restartSession(IR_Controlling); + q->update(currentParams); + } +} + +void MediaSessionPrivate::handleStreamEvents (int streamIndex) { + MediaStream *ms = (streamIndex == mainAudioStreamIndex) ? &audioStream->ms : + (streamIndex == mainVideoStreamIndex ? &videoStream->ms : &textStream->ms); + if (ms) { + /* Ensure there is no dangling ICE check list */ + if (!iceAgent->hasSession()) + media_stream_set_ice_check_list(ms, nullptr); + switch(ms->type){ + case MSAudio: + audio_stream_iterate((AudioStream *)ms); + break; + case MSVideo: +#ifdef VIDEO_ENABLED + video_stream_iterate((VideoStream *)ms); +#endif + break; + case MSText: + text_stream_iterate((TextStream *)ms); + break; + default: + lError() << "handleStreamEvents(): unsupported stream type"; + return; + } + } + OrtpEvQueue *evq; + OrtpEvent *ev; + /* Yes the event queue has to be taken at each iteration, because ice events may perform operations re-creating the streams */ + while ((evq = getEventQueue(streamIndex)) && (ev = ortp_ev_queue_get(evq))) { + LinphoneCallStats *stats = nullptr; + if (streamIndex == mainAudioStreamIndex) + stats = audioStats; + else if (streamIndex == mainVideoStreamIndex) + stats = videoStats; + else + stats = textStats; + /* And yes the MediaStream must be taken at each iteration, because it may have changed due to the handling of events + * in this loop*/ + ms = getMediaStream(streamIndex); + if (ms) + linphone_call_stats_fill(stats, ms, ev); + notifyStatsUpdated(streamIndex); + OrtpEventType evt = ortp_event_get_type(ev); + OrtpEventData *evd = ortp_event_get_data(ev); + if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED) { + if (streamIndex == mainAudioStreamIndex) + audioStreamEncryptionChanged(evd->info.zrtp_stream_encrypted); + else if (streamIndex == mainVideoStreamIndex) + propagateEncryptionChanged(); + } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) { + if (streamIndex == mainAudioStreamIndex) + audioStreamAuthTokenReady(evd->info.zrtp_info.sas, evd->info.zrtp_info.verified); + } else if (evt == ORTP_EVENT_DTLS_ENCRYPTION_CHANGED) { + if (streamIndex == mainAudioStreamIndex) + audioStreamEncryptionChanged(evd->info.dtls_stream_encrypted); + else if (streamIndex == mainVideoStreamIndex) + propagateEncryptionChanged(); + } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) + || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) { + if (ms) + handleIceEvents(ev); + } else if (evt == ORTP_EVENT_TELEPHONE_EVENT) { +#if 0 + linphone_core_dtmf_received(call, evd->info.telephone_event); +#endif + } else if (evt == ORTP_EVENT_NEW_VIDEO_BANDWIDTH_ESTIMATION_AVAILABLE) { + lInfo() << "Video bandwidth estimation is " << (int)(evd->info.video_bandwidth_available / 1000.) << " kbit/s"; + // TODO + } + ortp_event_destroy(ev); + } +} + +void MediaSessionPrivate::initializeAudioStream () { + L_Q(MediaSession); + if (audioStream) + return; + if (!sessions[mainAudioStreamIndex].rtp_session) { + SalMulticastRole multicastRole = getMulticastRole(SalAudio); + SalMediaDescription *remoteDesc = nullptr; + SalStreamDescription *streamDesc = nullptr; + if (op) + remoteDesc = sal_call_get_remote_media_description(op); + if (remoteDesc) + streamDesc = sal_media_description_find_best_stream(remoteDesc, SalAudio); + + audioStream = audio_stream_new2(core->factory, getBindIpForStream(mainAudioStreamIndex).c_str(), + (multicastRole == SalMulticastReceiver) ? streamDesc->rtp_port : mediaPorts[mainAudioStreamIndex].rtpPort, + (multicastRole == SalMulticastReceiver) ? 0 /* Disabled for now */ : mediaPorts[mainAudioStreamIndex].rtcpPort); + if (multicastRole == SalMulticastReceiver) + joinMulticastGroup(mainAudioStreamIndex, &audioStream->ms); + rtp_session_enable_network_simulation(audioStream->ms.sessions.rtp_session, &core->net_conf.netsim_params); + applyJitterBufferParams(audioStream->ms.sessions.rtp_session, LinphoneStreamTypeAudio); + string userAgent = linphone_core_get_user_agent(core); + audio_stream_set_rtcp_information(audioStream, conference.getMe()->getAddress().asStringUriOnly().c_str(), userAgent.c_str()); + rtp_session_set_symmetric_rtp(audioStream->ms.sessions.rtp_session, linphone_core_symmetric_rtp_enabled(core)); + setupDtlsParams(&audioStream->ms); + + /* Initialize zrtp even if we didn't explicitely set it, just in case peer offers it */ + if (linphone_core_media_encryption_supported(core, LinphoneMediaEncryptionZRTP)) { + char *peerUri = linphone_address_as_string_uri_only((direction == LinphoneCallIncoming) ? log->from : log->to); + char *selfUri = linphone_address_as_string_uri_only((direction == LinphoneCallIncoming) ? log->to : log->from); + MSZrtpParams params; + memset(¶ms, 0, sizeof(MSZrtpParams)); + /* media encryption of current params will be set later when zrtp is activated */ + params.zidCacheDB = linphone_core_get_zrtp_cache_db(core); + params.peerUri = peerUri; + params.selfUri = selfUri; + /* Get key lifespan from config file, default is 0:forever valid */ + params.limeKeyTimeSpan = bctbx_time_string_to_sec(lp_config_get_string(linphone_core_get_config(core), "sip", "lime_key_validity", "0")); + setZrtpCryptoTypesParameters(¶ms); + audio_stream_enable_zrtp(audioStream, ¶ms); + if (peerUri != NULL) ms_free(peerUri); + if (selfUri != NULL) ms_free(selfUri); + } + + media_stream_reclaim_sessions(&audioStream->ms, &sessions[mainAudioStreamIndex]); + } else { + audioStream = audio_stream_new_with_sessions(core->factory, &sessions[mainAudioStreamIndex]); + } + + if (mediaPorts[mainAudioStreamIndex].rtpPort == -1) + setPortConfigFromRtpSession(mainAudioStreamIndex, audioStream->ms.sessions.rtp_session); + int dscp = linphone_core_get_audio_dscp(core); + if (dscp != -1) + audio_stream_set_dscp(audioStream, dscp); + if (linphone_core_echo_limiter_enabled(core)) { + string type = lp_config_get_string(linphone_core_get_config(core), "sound", "el_type", "mic"); + if (type == "mic") + audio_stream_enable_echo_limiter(audioStream, ELControlMic); + else if (type == "full") + audio_stream_enable_echo_limiter(audioStream, ELControlFull); + } + + /* Equalizer location in the graph: 'mic' = in input graph, otherwise in output graph. + Any other value than mic will default to output graph for compatibility */ + string location = lp_config_get_string(linphone_core_get_config(core), "sound", "eq_location", "hp"); + audioStream->eq_loc = (location == "mic") ? MSEqualizerMic : MSEqualizerHP; + lInfo() << "Equalizer location: " << location; + + audio_stream_enable_gain_control(audioStream, true); + if (linphone_core_echo_cancellation_enabled(core)) { + int len = lp_config_get_int(linphone_core_get_config(core), "sound", "ec_tail_len", 0); + int delay = lp_config_get_int(linphone_core_get_config(core), "sound", "ec_delay", 0); + int framesize = lp_config_get_int(linphone_core_get_config(core), "sound", "ec_framesize", 0); + audio_stream_set_echo_canceller_params(audioStream, len, delay, framesize); + if (audioStream->ec) { + char *statestr=reinterpret_cast(ms_malloc0(ecStateMaxLen)); + if (lp_config_relative_file_exists(linphone_core_get_config(core), ecStateStore.c_str()) + && (lp_config_read_relative_file(linphone_core_get_config(core), ecStateStore.c_str(), statestr, ecStateMaxLen) == 0)) { + ms_filter_call_method(audioStream->ec, MS_ECHO_CANCELLER_SET_STATE_STRING, statestr); + } + ms_free(statestr); + } + } + audio_stream_enable_automatic_gain_control(audioStream, linphone_core_agc_enabled(core)); + int enabled = lp_config_get_int(linphone_core_get_config(core), "sound", "noisegate", 0); + audio_stream_enable_noise_gate(audioStream, enabled); + audio_stream_set_features(audioStream, linphone_core_get_audio_features(core)); + + if (core->rtptf) { + RtpTransport *meta_rtp; + RtpTransport *meta_rtcp; + rtp_session_get_transports(audioStream->ms.sessions.rtp_session, &meta_rtp, &meta_rtcp); + if (!meta_rtp_transport_get_endpoint(meta_rtp)) { + lInfo() << "CallSession [" << q << "] using custom audio RTP transport endpoint"; + meta_rtp_transport_set_endpoint(meta_rtp, core->rtptf->audio_rtp_func(core->rtptf->audio_rtp_func_data, mediaPorts[mainAudioStreamIndex].rtpPort)); + } + if (!meta_rtp_transport_get_endpoint(meta_rtcp)) + meta_rtp_transport_set_endpoint(meta_rtcp, core->rtptf->audio_rtcp_func(core->rtptf->audio_rtcp_func_data, mediaPorts[mainAudioStreamIndex].rtcpPort)); + } + + audioStreamEvQueue = ortp_ev_queue_new(); + rtp_session_register_event_queue(audioStream->ms.sessions.rtp_session, audioStreamEvQueue); + iceAgent->prepareIceForStream(&audioStream->ms, false); +} + +void MediaSessionPrivate::initializeStreams () { + initializeAudioStream(); + initializeVideoStream(); + initializeTextStream(); +} + +void MediaSessionPrivate::initializeTextStream () { + if (textStream) + return; + if (!sessions[mainTextStreamIndex].rtp_session) { + SalMulticastRole multicastRole = getMulticastRole(SalText); + SalMediaDescription *remoteDesc = nullptr; + SalStreamDescription *streamDesc = nullptr; + if (op) + remoteDesc = sal_call_get_remote_media_description(op); + if (remoteDesc) + streamDesc = sal_media_description_find_best_stream(remoteDesc, SalText); + + textStream = text_stream_new2(core->factory, getBindIpForStream(mainTextStreamIndex).c_str(), + (multicastRole == SalMulticastReceiver) ? streamDesc->rtp_port : mediaPorts[mainTextStreamIndex].rtpPort, + (multicastRole == SalMulticastReceiver) ? 0 /* Disabled for now */ : mediaPorts[mainTextStreamIndex].rtcpPort); + if (multicastRole == SalMulticastReceiver) + joinMulticastGroup(mainTextStreamIndex, &textStream->ms); + rtp_session_enable_network_simulation(textStream->ms.sessions.rtp_session, &core->net_conf.netsim_params); + applyJitterBufferParams(textStream->ms.sessions.rtp_session, LinphoneStreamTypeText); + rtp_session_set_symmetric_rtp(textStream->ms.sessions.rtp_session, linphone_core_symmetric_rtp_enabled(core)); + setupDtlsParams(&textStream->ms); + media_stream_reclaim_sessions(&textStream->ms, &sessions[mainTextStreamIndex]); + } else + textStream = text_stream_new_with_sessions(core->factory, &sessions[mainTextStreamIndex]); + if (mediaPorts[mainTextStreamIndex].rtpPort == -1) + setPortConfigFromRtpSession(mainTextStreamIndex, textStream->ms.sessions.rtp_session); + + if (core->rtptf) { + RtpTransport *meta_rtp; + RtpTransport *meta_rtcp; + rtp_session_get_transports(textStream->ms.sessions.rtp_session, &meta_rtp, &meta_rtcp); + if (!meta_rtp_transport_get_endpoint(meta_rtp)) + meta_rtp_transport_set_endpoint(meta_rtp, core->rtptf->audio_rtp_func(core->rtptf->audio_rtp_func_data, mediaPorts[mainTextStreamIndex].rtpPort)); + if (!meta_rtp_transport_get_endpoint(meta_rtcp)) + meta_rtp_transport_set_endpoint(meta_rtcp, core->rtptf->audio_rtcp_func(core->rtptf->audio_rtcp_func_data, mediaPorts[mainTextStreamIndex].rtcpPort)); + } + + textStreamEvQueue = ortp_ev_queue_new(); + rtp_session_register_event_queue(textStream->ms.sessions.rtp_session, textStreamEvQueue); + iceAgent->prepareIceForStream(&textStream->ms, false); +} + +void MediaSessionPrivate::initializeVideoStream () { +#ifdef VIDEO_ENABLED + L_Q(MediaSession); + if (videoStream) + return; + if (!sessions[mainVideoStreamIndex].rtp_session) { + SalMulticastRole multicastRole = getMulticastRole(SalVideo); + SalMediaDescription *remoteDesc = nullptr; + SalStreamDescription *streamDesc = nullptr; + if (op) + remoteDesc = sal_call_get_remote_media_description(op); + if (remoteDesc) + streamDesc = sal_media_description_find_best_stream(remoteDesc, SalVideo); + + videoStream = video_stream_new2(core->factory, getBindIpForStream(mainVideoStreamIndex).c_str(), + (multicastRole == SalMulticastReceiver) ? streamDesc->rtp_port : mediaPorts[mainVideoStreamIndex].rtpPort, + (multicastRole == SalMulticastReceiver) ? 0 /* Disabled for now */ : mediaPorts[mainVideoStreamIndex].rtcpPort); + if (multicastRole == SalMulticastReceiver) + joinMulticastGroup(mainVideoStreamIndex, &videoStream->ms); + rtp_session_enable_network_simulation(videoStream->ms.sessions.rtp_session, &core->net_conf.netsim_params); + applyJitterBufferParams(videoStream->ms.sessions.rtp_session, LinphoneStreamTypeVideo); + string userAgent = linphone_core_get_user_agent(core); + video_stream_set_rtcp_information(videoStream, conference.getMe()->getAddress().asStringUriOnly().c_str(), userAgent.c_str()); + rtp_session_set_symmetric_rtp(videoStream->ms.sessions.rtp_session, linphone_core_symmetric_rtp_enabled(core)); + setupDtlsParams(&videoStream->ms); + /* Initialize zrtp even if we didn't explicitely set it, just in case peer offers it */ + if (linphone_core_media_encryption_supported(core, LinphoneMediaEncryptionZRTP)) + video_stream_enable_zrtp(videoStream, audioStream); + + media_stream_reclaim_sessions(&videoStream->ms, &sessions[mainVideoStreamIndex]); + } else + videoStream = video_stream_new_with_sessions(core->factory, &sessions[mainVideoStreamIndex]); + + if (mediaPorts[mainVideoStreamIndex].rtpPort == -1) + setPortConfigFromRtpSession(mainVideoStreamIndex, videoStream->ms.sessions.rtp_session); + int dscp = linphone_core_get_video_dscp(core); + if (dscp!=-1) + video_stream_set_dscp(videoStream, dscp); + video_stream_enable_display_filter_auto_rotate(videoStream, + lp_config_get_int(linphone_core_get_config(core), "video", "display_filter_auto_rotate", 0)); + int videoRecvBufSize = lp_config_get_int(linphone_core_get_config(core), "video", "recv_buf_size", 0); + if (videoRecvBufSize > 0) + rtp_session_set_recv_buf_size(videoStream->ms.sessions.rtp_session, videoRecvBufSize); + + const char *displayFilter = linphone_core_get_video_display_filter(core); + if (displayFilter) + video_stream_set_display_filter_name(videoStream, displayFilter); + video_stream_set_event_callback(videoStream, videoStreamEventCb, this); + + if (core->rtptf) { + RtpTransport *meta_rtp; + RtpTransport *meta_rtcp; + rtp_session_get_transports(videoStream->ms.sessions.rtp_session, &meta_rtp, &meta_rtcp); + if (!meta_rtp_transport_get_endpoint(meta_rtp)) { + lInfo() << "CallSession [" << q << "] using custom video RTP transport endpoint"; + meta_rtp_transport_set_endpoint(meta_rtp, core->rtptf->video_rtp_func(core->rtptf->video_rtp_func_data, mediaPorts[mainVideoStreamIndex].rtpPort)); + } + if (!meta_rtp_transport_get_endpoint(meta_rtcp)) + meta_rtp_transport_set_endpoint(meta_rtcp, core->rtptf->video_rtcp_func(core->rtptf->video_rtcp_func_data, mediaPorts[mainVideoStreamIndex].rtcpPort)); + } + videoStreamEvQueue = ortp_ev_queue_new(); + rtp_session_register_event_queue(videoStream->ms.sessions.rtp_session, videoStreamEvQueue); + iceAgent->prepareIceForStream(&videoStream->ms, false); +#ifdef TEST_EXT_RENDERER + video_stream_set_render_callback(videoStream, extRendererCb, nullptr); +#endif +#else + videoStream = nullptr; +#endif +} + +void MediaSessionPrivate::parameterizeEqualizer (AudioStream *stream) { + LinphoneConfig *config = linphone_core_get_config(core); + const char *eqActive = lp_config_get_string(config, "sound", "eq_active", nullptr); + if (eqActive) + lWarning() << "'eq_active' linphonerc parameter has no effect anymore. Please use 'mic_eq_active' or 'spk_eq_active' instead"; + const char *eqGains = lp_config_get_string(config, "sound", "eq_gains", nullptr); + if(eqGains) + lWarning() << "'eq_gains' linphonerc parameter has no effect anymore. Please use 'mic_eq_gains' or 'spk_eq_gains' instead"; + if (stream->mic_equalizer) { + MSFilter *f = stream->mic_equalizer; + bool enabled = lp_config_get_int(config, "sound", "mic_eq_active", 0); + ms_filter_call_method(f, MS_EQUALIZER_SET_ACTIVE, &enabled); + const char *gains = lp_config_get_string(config, "sound", "mic_eq_gains", nullptr); + if (enabled && gains) { + bctbx_list_t *gainsList = ms_parse_equalizer_string(gains); + for (bctbx_list_t *it = gainsList; it; it = bctbx_list_next(it)) { + MSEqualizerGain *g = reinterpret_cast(bctbx_list_get_data(it)); + lInfo() << "Read microphone equalizer gains: " << g->frequency << "(~" << g->width << ") --> " << g->gain; + ms_filter_call_method(f, MS_EQUALIZER_SET_GAIN, g); + } + if (gainsList) + bctbx_list_free_with_data(gainsList, ms_free); + } + } + if (stream->spk_equalizer) { + MSFilter *f = stream->spk_equalizer; + bool enabled = lp_config_get_int(config, "sound", "spk_eq_active", 0); + ms_filter_call_method(f, MS_EQUALIZER_SET_ACTIVE, &enabled); + const char *gains = lp_config_get_string(config, "sound", "spk_eq_gains", nullptr); + if (enabled && gains) { + bctbx_list_t *gainsList = ms_parse_equalizer_string(gains); + for (bctbx_list_t *it = gainsList; it; it = bctbx_list_next(it)) { + MSEqualizerGain *g = reinterpret_cast(bctbx_list_get_data(it)); + lInfo() << "Read speaker equalizer gains: " << g->frequency << "(~" << g->width << ") --> " << g->gain; + ms_filter_call_method(f, MS_EQUALIZER_SET_GAIN, g); + } + if (gainsList) + bctbx_list_free_with_data(gainsList, ms_free); + } + } +} + +void MediaSessionPrivate::prepareEarlyMediaForking () { + /* We need to disable symmetric rtp otherwise our outgoing streams will be switching permanently between the multiple destinations */ + if (audioStream) + rtp_session_set_symmetric_rtp(audioStream->ms.sessions.rtp_session, false); + if (videoStream) + rtp_session_set_symmetric_rtp(videoStream->ms.sessions.rtp_session, false); +} + +void MediaSessionPrivate::postConfigureAudioStream (AudioStream *stream, bool muted) { + float micGain = core->sound_conf.soft_mic_lev; + if (muted) + audio_stream_set_mic_gain(stream, 0); + else + audio_stream_set_mic_gain_db(stream, micGain); + float recvGain = core->sound_conf.soft_play_lev; + if (recvGain) + setPlaybackGainDb(stream, recvGain); + LinphoneConfig *config = linphone_core_get_config(core); + float ngThres = lp_config_get_float(config, "sound", "ng_thres", 0.05f); + float ngFloorGain = lp_config_get_float(config, "sound", "ng_floorgain", 0); + if (stream->volsend) { + int dcRemoval = lp_config_get_int(config, "sound", "dc_removal", 0); + ms_filter_call_method(stream->volsend, MS_VOLUME_REMOVE_DC, &dcRemoval); + float speed = lp_config_get_float(config, "sound", "el_speed", -1); + float thres = lp_config_get_float(config, "sound", "el_thres", -1); + float force = lp_config_get_float(config, "sound", "el_force", -1); + int sustain = lp_config_get_int(config, "sound", "el_sustain", -1); + float transmitThres = lp_config_get_float(config, "sound", "el_transmit_thres", -1); + if (speed == -1) + speed = 0.03f; + if (force == -1) + force = 25; + MSFilter *f = stream->volsend; + ms_filter_call_method(f, MS_VOLUME_SET_EA_SPEED, &speed); + ms_filter_call_method(f, MS_VOLUME_SET_EA_FORCE, &force); + if (thres != -1) + ms_filter_call_method(f, MS_VOLUME_SET_EA_THRESHOLD, &thres); + if (sustain != -1) + ms_filter_call_method(f, MS_VOLUME_SET_EA_SUSTAIN, &sustain); + if (transmitThres != -1) + ms_filter_call_method(f, MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD, &transmitThres); + ms_filter_call_method(f, MS_VOLUME_SET_NOISE_GATE_THRESHOLD, &ngThres); + ms_filter_call_method(f, MS_VOLUME_SET_NOISE_GATE_FLOORGAIN, &ngFloorGain); + } + if (stream->volrecv) { + /* Parameters for a limited noise-gate effect, using echo limiter threshold */ + float floorGain = (float)(1 / pow(10, micGain / 10)); + int spkAgc = lp_config_get_int(config, "sound", "speaker_agc_enabled", 0); + MSFilter *f = stream->volrecv; + ms_filter_call_method(f, MS_VOLUME_ENABLE_AGC, &spkAgc); + ms_filter_call_method(f, MS_VOLUME_SET_NOISE_GATE_THRESHOLD, &ngThres); + ms_filter_call_method(f, MS_VOLUME_SET_NOISE_GATE_FLOORGAIN, &floorGain); + } + parameterizeEqualizer(stream); +} + +void MediaSessionPrivate::postConfigureAudioStreams (bool muted) { + L_Q(MediaSession); + postConfigureAudioStream(audioStream, muted); + if (linphone_core_dtmf_received_has_listener(core)) + audio_stream_play_received_dtmfs(audioStream, false); + if (recordActive) + q->startRecording(); +} + +void MediaSessionPrivate::setPlaybackGainDb (AudioStream *stream, float gain) { + if (stream->volrecv) + ms_filter_call_method(stream->volrecv, MS_VOLUME_SET_DB_GAIN, &gain); + else + lWarning() << "Could not apply playback gain: gain control wasn't activated"; +} + +void MediaSessionPrivate::setSymmetricRtp (bool value) { + for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + MSMediaStreamSessions *mss = &sessions[i]; + if (mss->rtp_session) + rtp_session_set_symmetric_rtp(mss->rtp_session, value); + } +} + +void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool videoWillBeUsed) { + const SalStreamDescription *stream = sal_media_description_find_best_stream(resultDesc, SalAudio); + if (stream && (stream->dir != SalStreamInactive) && (stream->rtp_port != 0)) { + int usedPt = -1; + onHoldFile = ""; + audioProfile = makeProfile(resultDesc, stream, &usedPt); + if (usedPt == -1) + lWarning() << "No audio stream accepted?"; + else { + const char *rtpAddr = (stream->rtp_addr[0] != '\0') ? stream->rtp_addr : resultDesc->addr; + bool isMulticast = ms_is_multicast(rtpAddr); + bool ok = true; + currentParams->getPrivate()->setUsedAudioCodec(rtp_profile_get_payload(audioProfile, usedPt)); + currentParams->enableAudio(true); + MSSndCard *playcard = core->sound_conf.lsd_card ? core->sound_conf.lsd_card : core->sound_conf.play_sndcard; + if (!playcard) + lWarning() << "No card defined for playback!"; + MSSndCard *captcard = core->sound_conf.capt_sndcard; + if (!captcard) + lWarning() << "No card defined for capture!"; + string playfile = core->play_file ? core->play_file : ""; + string recfile = core->rec_file ? core->rec_file : ""; + /* Don't use file or soundcard capture when placed in recv-only mode */ + if ((stream->rtp_port == 0) || (stream->dir == SalStreamRecvOnly) || ((stream->multicast_role == SalMulticastReceiver) && isMulticast)) { + captcard = nullptr; + playfile = ""; + } + if (targetState == LinphoneCallPaused) { + /* In paused state, we never use soundcard */ + playcard = captcard = nullptr; + recfile = ""; + /* And we will eventually play "playfile" if set by the user */ + } + if (playingRingbackTone) { + captcard = nullptr; + playfile = ""; /* It is setup later */ + if (lp_config_get_int(linphone_core_get_config(core), "sound", "send_ringback_without_playback", 0) == 1) { + playcard = nullptr; + recfile = ""; + } + } + /* If playfile are supplied don't use soundcards */ + bool useRtpIo = lp_config_get_int(linphone_core_get_config(core), "sound", "rtp_io", false); + bool useRtpIoEnableLocalOutput = lp_config_get_int(linphone_core_get_config(core), "sound", "rtp_io_enable_local_output", false); + if (core->use_files || (useRtpIo && !useRtpIoEnableLocalOutput)) { + captcard = playcard = nullptr; + } + if (params->getPrivate()->getInConference()) { + /* First create the graph without soundcard resources */ + captcard = playcard = nullptr; + } +#if 0 + if (!linphone_call_sound_resources_available(call)){ + ms_message("Sound resources are used by another call, not using soundcard."); + captcard = playcard = nullptr; + } +#endif + bool useEc = (captcard == nullptr) ? false : linphone_core_echo_cancellation_enabled(core); + audio_stream_enable_echo_canceller(audioStream, useEc); + if (playcard && (stream->max_rate > 0)) + ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate); + if (captcard && (stream->max_rate > 0)) + ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate); + rtp_session_enable_rtcp_mux(audioStream->ms.sessions.rtp_session, stream->rtcp_mux); + if (!params->getPrivate()->getInConference() && !params->getRecordFilePath().empty()) { + audio_stream_mixed_record_open(audioStream, params->getRecordFilePath().c_str()); + currentParams->setRecordFilePath(params->getRecordFilePath()); + } + /* Valid local tags are > 0 */ + if (sal_stream_description_has_srtp(stream)) { + const SalStreamDescription *localStreamDesc = sal_media_description_find_stream(localDesc, stream->proto, SalAudio); + int cryptoIdx = findCryptoIndexFromTag(localStreamDesc->crypto, stream->crypto_local_tag); + if (cryptoIdx >= 0) { + ms_media_stream_sessions_set_srtp_recv_key_b64(&audioStream->ms.sessions, stream->crypto[0].algo, stream->crypto[0].master_key); + ms_media_stream_sessions_set_srtp_send_key_b64(&audioStream->ms.sessions, stream->crypto[0].algo, localStreamDesc->crypto[cryptoIdx].master_key); + } else + lWarning() << "Failed to find local crypto algo with tag: " << stream->crypto_local_tag; + } + configureRtpSessionForRtcpFb(stream); + configureRtpSessionForRtcpXr(SalAudio); + configureAdaptiveRateControl(&audioStream->ms, currentParams->getUsedAudioCodec(), videoWillBeUsed); + if (isMulticast) + rtp_session_set_multicast_ttl(audioStream->ms.sessions.rtp_session, stream->ttl); + MSMediaStreamIO io = MS_MEDIA_STREAM_IO_INITIALIZER; + if (useRtpIo) { + if (useRtpIoEnableLocalOutput) { + io.input.type = MSResourceRtp; + io.input.session = createAudioRtpIoSession(); + if (playcard) { + io.output.type = MSResourceSoundcard; + io.output.soundcard = playcard; + } else { + io.output.type = MSResourceFile; + io.output.file = recfile.c_str(); + } + } else { + io.input.type = io.output.type = MSResourceRtp; + io.input.session = io.output.session = createAudioRtpIoSession(); + } + if (!io.input.session) + ok = false; + } else { + if (playcard) { + io.output.type = MSResourceSoundcard; + io.output.soundcard = playcard; + } else { + io.output.type = MSResourceFile; + io.output.file = recfile.c_str(); + } + if (captcard) { + io.input.type = MSResourceSoundcard; + io.input.soundcard = captcard; + } else { + io.input.type = MSResourceFile; + onHoldFile = playfile; + io.input.file = nullptr; /* We prefer to use the remote_play api, that allows to play multimedia files */ + } + } + if (ok) { + int err = audio_stream_start_from_io(audioStream, audioProfile, rtpAddr, stream->rtp_port, + (stream->rtcp_addr[0] != '\0') ? stream->rtcp_addr : resultDesc->addr, + (linphone_core_rtcp_enabled(core) && !isMulticast) ? (stream->rtcp_port ? stream->rtcp_port : stream->rtp_port + 1) : 0, + usedPt, &io); + if (err == 0) + postConfigureAudioStreams((allMuted || audioMuted) && !playingRingbackTone); + } + ms_media_stream_sessions_set_encryption_mandatory(&audioStream->ms.sessions, isEncryptionMandatory()); + if ((targetState == LinphoneCallPaused) && !captcard && !playfile.empty()) { + int pauseTime = 500; + ms_filter_call_method(audioStream->soundread, MS_FILE_PLAYER_LOOP, &pauseTime); + } +#if 0 + if (playingRingbacktone) { + setup_ring_player(lc,call); + } +#endif + if (params->getPrivate()->getInConference() && core->conf_ctx) { + /* Transform the graph to connect it to the conference filter */ +#if 0 + bool mute = (stream->dir == SalStreamRecvOnly); + linphone_conference_on_call_stream_starting(core->conf_ctx, call, mute); +#endif + } + currentParams->getPrivate()->setInConference(params->getPrivate()->getInConference()); + currentParams->enableLowBandwidth(params->lowBandwidthEnabled()); + /* Start ZRTP engine if needed : set here or remote have a zrtp-hash attribute */ + SalMediaDescription *remote = sal_call_get_remote_media_description(op); + const SalStreamDescription *remoteStream = sal_media_description_find_best_stream(remote, SalAudio); + if (linphone_core_media_encryption_supported(core, LinphoneMediaEncryptionZRTP) + && ((params->getMediaEncryption() == LinphoneMediaEncryptionZRTP) || (remoteStream->haveZrtpHash == 1))) { + audio_stream_start_zrtp(audioStream); + if (remoteStream->haveZrtpHash == 1) { + int retval = ms_zrtp_setPeerHelloHash(audioStream->ms.sessions.zrtp_context, (uint8_t *)remoteStream->zrtphash, strlen((const char *)(remoteStream->zrtphash))); + if (retval != 0) + lError() << "Zrtp hash mismatch 0x" << hex << retval; + } + } + } + } +} + +void MediaSessionPrivate::startStreams (LinphoneCallState targetState) { + L_Q(MediaSession); + switch (targetState) { + case LinphoneCallIncomingEarlyMedia: + if (linphone_core_get_remote_ringback_tone(core)) { + playingRingbackTone = true; + } + BCTBX_NO_BREAK; + case LinphoneCallOutgoingEarlyMedia: + if (!params->earlyMediaSendingEnabled()) + allMuted = true; + break; + default: + playingRingbackTone = false; + allMuted = false; + break; + } + + currentParams->getPrivate()->setUsedAudioCodec(nullptr); + currentParams->getPrivate()->setUsedVideoCodec(nullptr); + currentParams->getPrivate()->setUsedRealtimeTextCodec(nullptr); + + if (!audioStream && !videoStream) { + lFatal() << "startStreams() called without prior init!"; + return; + } + if (iceAgent->hasSession()) { + /* If there is an ICE session when we are about to start streams, then ICE will conduct the media path checking and authentication properly. + * Symmetric RTP must be turned off */ + setSymmetricRtp(false); + } + + nbMediaStarts++; + bool videoWillBeUsed = false; +#if defined(VIDEO_ENABLED) + const SalStreamDescription *vstream = sal_media_description_find_best_stream(resultDesc, SalVideo); + if (vstream && (vstream->dir != SalStreamInactive) && vstream->payloads) { + /* When video is used, do not make adaptive rate control on audio, it is stupid */ + videoWillBeUsed = true; + } +#endif + lInfo() << "startStreams() CallSession=[" << q << "] local upload_bandwidth=[" << linphone_core_get_upload_bandwidth(core) + << "] kbit/s; local download_bandwidth=[" << linphone_core_get_download_bandwidth(core) << "] kbit/s"; + currentParams->enableAudio(false); + if (audioStream) + startAudioStream(targetState, videoWillBeUsed); + else + lWarning() << "startStreams(): no audio stream!"; + currentParams->enableVideo(false); + if (videoStream) { + if (audioStream) + audio_stream_link_video(audioStream, videoStream); + startVideoStream(targetState); + } + /* The on-hold file is to be played once both audio and video are ready */ + if (!onHoldFile.empty() && !params->getPrivate()->getInConference() && audioStream) { + MSFilter *player = audio_stream_open_remote_play(audioStream, onHoldFile.c_str()); + if (player) { + int pauseTime = 500; + ms_filter_call_method(player, MS_PLAYER_SET_LOOP, &pauseTime); + ms_filter_call_method_noarg(player, MS_PLAYER_START); + } + } + upBandwidth = linphone_core_get_upload_bandwidth(core); + if (params->realtimeTextEnabled()) + startTextStream(); + + setDtlsFingerprintOnAllStreams(); + if (!iceAgent->hasCompleted()) { + if (params->getMediaEncryption() == LinphoneMediaEncryptionDTLS) { + currentParams->getPrivate()->setUpdateCallWhenIceCompleted(false); + lInfo() << "Disabling update call when ice completed on call [" << q << "]"; + } + iceAgent->startConnectivityChecks(); + } else { + /* Should not start dtls until ice is completed */ + startDtlsOnAllStreams(); + } +} + +void MediaSessionPrivate::startTextStream () { + L_Q(MediaSession); + const SalStreamDescription *tstream = sal_media_description_find_best_stream(resultDesc, SalText); + if (tstream && (tstream->dir != SalStreamInactive) && (tstream->rtp_port != 0)) { + const char *rtpAddr = tstream->rtp_addr[0] != '\0' ? tstream->rtp_addr : resultDesc->addr; + const char *rtcpAddr = tstream->rtcp_addr[0] != '\0' ? tstream->rtcp_addr : resultDesc->addr; + const SalStreamDescription *localStreamDesc = sal_media_description_find_stream(localDesc, tstream->proto, SalText); + int usedPt = -1; + textProfile = makeProfile(resultDesc, tstream, &usedPt); + if (usedPt == -1) + lWarning() << "No text stream accepted"; + else { + currentParams->getPrivate()->setUsedRealtimeTextCodec(rtp_profile_get_payload(textProfile, usedPt)); + currentParams->enableRealtimeText(true); + if (sal_stream_description_has_srtp(tstream)) { + int cryptoIdx = findCryptoIndexFromTag(localStreamDesc->crypto, tstream->crypto_local_tag); + if (cryptoIdx >= 0) { + ms_media_stream_sessions_set_srtp_recv_key_b64(&textStream->ms.sessions, tstream->crypto[0].algo, tstream->crypto[0].master_key); + ms_media_stream_sessions_set_srtp_send_key_b64(&textStream->ms.sessions, tstream->crypto[0].algo, localStreamDesc->crypto[cryptoIdx].master_key); + } + } + configureRtpSessionForRtcpFb(tstream); + configureRtpSessionForRtcpXr(SalText); + rtp_session_enable_rtcp_mux(textStream->ms.sessions.rtp_session, tstream->rtcp_mux); + bool_t isMulticast = ms_is_multicast(rtpAddr); + if (isMulticast) + rtp_session_set_multicast_ttl(textStream->ms.sessions.rtp_session, tstream->ttl); + text_stream_start(textStream, textProfile, rtpAddr, tstream->rtp_port, rtcpAddr, + (linphone_core_rtcp_enabled(core) && !isMulticast) ? (tstream->rtcp_port ? tstream->rtcp_port : tstream->rtp_port + 1) : 0, usedPt); + ms_filter_add_notify_callback(textStream->rttsink, realTimeTextCharacterReceived, q, false); + ms_media_stream_sessions_set_encryption_mandatory(&textStream->ms.sessions, isEncryptionMandatory()); + } + } else + lInfo() << "No valid text stream defined"; +} + +void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { +#ifdef VIDEO_ENABLED + L_Q(MediaSession); + bool reusedPreview = false; + /* Shutdown preview */ + MSFilter *source = nullptr; + if (core->previewstream) { + if (core->video_conf.reuse_preview_source) + source = video_preview_stop_reuse_source(core->previewstream); + else + video_preview_stop(core->previewstream); + core->previewstream = nullptr; + } + const SalStreamDescription *vstream = sal_media_description_find_best_stream(resultDesc, SalVideo); + if (vstream && (vstream->dir != SalStreamInactive) && (vstream->rtp_port != 0)) { + int usedPt = -1; + videoProfile = makeProfile(resultDesc, vstream, &usedPt); + if (usedPt == -1) + lWarning() << "No video stream accepted"; + else { + currentParams->getPrivate()->setUsedVideoCodec(rtp_profile_get_payload(videoProfile, usedPt)); + currentParams->enableVideo(true); + rtp_session_enable_rtcp_mux(videoStream->ms.sessions.rtp_session, vstream->rtcp_mux); + if (core->video_conf.preview_vsize.width != 0) + video_stream_set_preview_size(videoStream, core->video_conf.preview_vsize); + video_stream_set_fps(videoStream, linphone_core_get_preferred_framerate(core)); + if (lp_config_get_int(linphone_core_get_config(core), "video", "nowebcam_uses_normal_fps", 0)) + videoStream->staticimage_webcam_fps_optimization = false; + const LinphoneVideoDefinition *vdef = linphone_core_get_preferred_video_definition(core); + MSVideoSize vsize; + vsize.width = linphone_video_definition_get_width(vdef); + vsize.height = linphone_video_definition_get_height(vdef); + video_stream_set_sent_video_size(videoStream, vsize); + video_stream_enable_self_view(videoStream, core->video_conf.selfview); + if (videoWindowId) + video_stream_set_native_window_id(videoStream, videoWindowId); + else if (core->video_window_id) + video_stream_set_native_window_id(videoStream, core->video_window_id); + if (core->preview_window_id) + video_stream_set_native_preview_window_id(videoStream, core->preview_window_id); + video_stream_use_preview_video_window(videoStream, core->use_preview_window); + const char *rtpAddr = (vstream->rtp_addr[0] != '\0') ? vstream->rtp_addr : resultDesc->addr; + const char *rtcpAddr = (vstream->rtcp_addr[0] != '\0') ? vstream->rtcp_addr : resultDesc->addr; + bool isMulticast = ms_is_multicast(rtpAddr); + MediaStreamDir dir = MediaStreamSendRecv; + bool isActive = true; + if (isMulticast) { + if (vstream->multicast_role == SalMulticastReceiver) + dir = MediaStreamRecvOnly; + else + dir = MediaStreamSendOnly; + } else if ((vstream->dir == SalStreamSendOnly) && core->video_conf.capture) + dir = MediaStreamSendOnly; + else if ((vstream->dir == SalStreamRecvOnly) && core->video_conf.display) + dir = MediaStreamRecvOnly; + else if (vstream->dir == SalStreamSendRecv) { + if (core->video_conf.display && core->video_conf.capture) + dir = MediaStreamSendRecv; + else if (core->video_conf.display) + dir = MediaStreamRecvOnly; + else + dir = MediaStreamSendOnly; + } else { + lWarning() << "Video stream is inactive"; + /* Either inactive or incompatible with local capabilities */ + isActive = false; + } + MSWebCam *cam = getVideoDevice(); + if (isActive) { + if (sal_stream_description_has_srtp(vstream)) { + const SalStreamDescription *localStreamDesc = sal_media_description_find_stream(localDesc, vstream->proto, SalVideo); + int cryptoIdx = findCryptoIndexFromTag(localStreamDesc->crypto, vstream->crypto_local_tag); + if (cryptoIdx >= 0) { + ms_media_stream_sessions_set_srtp_recv_key_b64(&videoStream->ms.sessions, vstream->crypto[0].algo, vstream->crypto[0].master_key); + ms_media_stream_sessions_set_srtp_send_key_b64(&videoStream->ms.sessions, vstream->crypto[0].algo, localStreamDesc->crypto[cryptoIdx].master_key); + } + } + configureRtpSessionForRtcpFb(vstream); + configureRtpSessionForRtcpXr(SalVideo); + configureAdaptiveRateControl(&videoStream->ms, currentParams->getUsedVideoCodec(), true); + log->video_enabled = true; + video_stream_set_direction(videoStream, dir); + lInfo() << "startVideoStream: device_rotation=" << core->device_rotation; + video_stream_set_device_rotation(videoStream, core->device_rotation); + video_stream_set_freeze_on_error(videoStream, lp_config_get_int(linphone_core_get_config(core), "video", "freeze_on_error", 1)); + if (isMulticast) + rtp_session_set_multicast_ttl(videoStream->ms.sessions.rtp_session, vstream->ttl); + video_stream_use_video_preset(videoStream, lp_config_get_string(linphone_core_get_config(core), "video", "preset", nullptr)); + if (core->video_conf.reuse_preview_source && source) { + lInfo() << "video_stream_start_with_source kept: " << source; + video_stream_start_with_source(videoStream, videoProfile, rtpAddr, vstream->rtp_port, rtcpAddr, + linphone_core_rtcp_enabled(core) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port + 1) : 0, + usedPt, -1, cam, source); + reusedPreview = true; + } else { + bool ok = true; + MSMediaStreamIO io = MS_MEDIA_STREAM_IO_INITIALIZER; + bool useRtpIo = lp_config_get_int(linphone_core_get_config(core), "video", "rtp_io", false); + if (useRtpIo) { + io.input.type = io.output.type = MSResourceRtp; + io.input.session = io.output.session = createVideoRtpIoSession(); + if (!io.input.session) { + ok = false; + lWarning() << "Cannot create video RTP IO session"; + } + } else { + io.input.type = MSResourceCamera; + io.input.camera = cam; + io.output.type = MSResourceDefault; + } + if (ok) { + video_stream_start_from_io(videoStream, videoProfile, rtpAddr, vstream->rtp_port, rtcpAddr, + (linphone_core_rtcp_enabled(core) && !isMulticast) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port + 1) : 0, + usedPt, &io); + } + } + ms_media_stream_sessions_set_encryption_mandatory(&videoStream->ms.sessions, isEncryptionMandatory()); + if (listener) + listener->resetFirstVideoFrameDecoded(*q); + /* Start ZRTP engine if needed : set here or remote have a zrtp-hash attribute */ + SalMediaDescription *remote = sal_call_get_remote_media_description(op); + const SalStreamDescription *remoteStream = sal_media_description_find_best_stream(remote, SalVideo); + if ((params->getMediaEncryption() == LinphoneMediaEncryptionZRTP) || (remoteStream->haveZrtpHash == 1)) { + /* Audio stream is already encrypted and video stream is active */ + if (media_stream_secured(&audioStream->ms) && (media_stream_get_state(&videoStream->ms) == MSStreamStarted)) { + video_stream_start_zrtp(videoStream); + if (remoteStream->haveZrtpHash == 1) { + int retval = ms_zrtp_setPeerHelloHash(videoStream->ms.sessions.zrtp_context, (uint8_t *)remoteStream->zrtphash, strlen((const char *)(remoteStream->zrtphash))); + if (retval != 0) + lError() << "Video stream ZRTP hash mismatch 0x" << hex << retval; + } + } + } + } + } + } else + lInfo() << "No valid video stream defined"; + if (!reusedPreview && source) { + /* Destroy not-reused source filter */ + lWarning() << "Video preview (" << source << ") not reused: destroying it"; + ms_filter_destroy(source); + } +#endif +} + +void MediaSessionPrivate::stopAudioStream () { + L_Q(MediaSession); + if (audioStream) { + updateReportingMediaInfo(LINPHONE_CALL_STATS_AUDIO); + media_stream_reclaim_sessions(&audioStream->ms, &sessions[mainAudioStreamIndex]); + if (audioStream->ec) { + char *stateStr = nullptr; + ms_filter_call_method(audioStream->ec, MS_ECHO_CANCELLER_GET_STATE_STRING, &stateStr); + if (stateStr) { + lInfo() << "Writing echo canceler state, " << (int)strlen(stateStr) << " bytes"; + lp_config_write_relative_file(linphone_core_get_config(core), ecStateStore.c_str(), stateStr); + } + } + audio_stream_get_local_rtp_stats(audioStream, &log->local_stats); + fillLogStats(&audioStream->ms); +#if 0 + if (call->endpoint) { + linphone_conference_on_call_stream_stopping(lc->conf_ctx, call); + } +#endif + ms_bandwidth_controller_remove_stream(core->bw_controller, &audioStream->ms); + audio_stream_stop(audioStream); + updateRtpStats(audioStats, mainAudioStreamIndex); + audioStream = nullptr; + handleStreamEvents(mainAudioStreamIndex); + rtp_session_unregister_event_queue(sessions[mainAudioStreamIndex].rtp_session, audioStreamEvQueue); + ortp_ev_queue_flush(audioStreamEvQueue); + ortp_ev_queue_destroy(audioStreamEvQueue); + audioStreamEvQueue = nullptr; + + q->getCurrentParams()->getPrivate()->setUsedAudioCodec(nullptr); + } +} + +void MediaSessionPrivate::stopStreams () { + if (audioStream || videoStream || textStream) { + if (audioStream && videoStream) + audio_stream_unlink_video(audioStream, videoStream); + stopAudioStream(); + stopVideoStream(); + stopTextStream(); + if (core->msevq) + ms_event_queue_skip(core->msevq); + } + + if (audioProfile) { + rtp_profile_destroy(audioProfile); + audioProfile = nullptr; + unsetRtpProfile(mainAudioStreamIndex); + } + if (videoProfile) { + rtp_profile_destroy(videoProfile); + videoProfile = nullptr; + unsetRtpProfile(mainVideoStreamIndex); + } + if (textProfile) { + rtp_profile_destroy(textProfile); + textProfile = nullptr; + unsetRtpProfile(mainTextStreamIndex); + } + if (rtpIoAudioProfile) { + rtp_profile_destroy(rtpIoAudioProfile); + rtpIoAudioProfile = nullptr; + } + if (rtpIoVideoProfile) { + rtp_profile_destroy(rtpIoVideoProfile); + rtpIoVideoProfile = nullptr; + } + + linphone_core_soundcard_hint_check(core); +} + +void MediaSessionPrivate::stopTextStream () { + L_Q(MediaSession); + if (textStream) { + updateReportingMediaInfo(LINPHONE_CALL_STATS_TEXT); + media_stream_reclaim_sessions(&textStream->ms, &sessions[mainTextStreamIndex]); + fillLogStats(&textStream->ms); + text_stream_stop(textStream); + updateRtpStats(textStats, mainTextStreamIndex); + textStream = nullptr; + handleStreamEvents(mainTextStreamIndex); + rtp_session_unregister_event_queue(sessions[mainTextStreamIndex].rtp_session, textStreamEvQueue); + ortp_ev_queue_flush(textStreamEvQueue); + ortp_ev_queue_destroy(textStreamEvQueue); + textStreamEvQueue = nullptr; + q->getCurrentParams()->getPrivate()->setUsedRealtimeTextCodec(nullptr); + } +} + +void MediaSessionPrivate::stopVideoStream () { +#ifdef VIDEO_ENABLED + L_Q(MediaSession); + if (videoStream) { + updateReportingMediaInfo(LINPHONE_CALL_STATS_VIDEO); + media_stream_reclaim_sessions(&videoStream->ms, &sessions[mainVideoStreamIndex]); + fillLogStats(&videoStream->ms); + ms_bandwidth_controller_remove_stream(core->bw_controller, &videoStream->ms); + video_stream_stop(videoStream); + updateRtpStats(videoStats, mainVideoStreamIndex); + videoStream = nullptr; + handleStreamEvents(mainVideoStreamIndex); + rtp_session_unregister_event_queue(sessions[mainVideoStreamIndex].rtp_session, videoStreamEvQueue); + ortp_ev_queue_flush(videoStreamEvQueue); + ortp_ev_queue_destroy(videoStreamEvQueue); + videoStreamEvQueue = nullptr; + q->getCurrentParams()->getPrivate()->setUsedVideoCodec(nullptr); + } +#endif +} + +void MediaSessionPrivate::tryEarlyMediaForking (SalMediaDescription *md) { + L_Q(MediaSession); + lInfo() << "Early media response received from another branch, checking if media can be forked to this new destination"; + for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + if (!sal_stream_description_active(&resultDesc->streams[i])) + continue; + SalStreamDescription *refStream = &resultDesc->streams[i]; + SalStreamDescription *newStream = &md->streams[i]; + if ((refStream->type == newStream->type) && refStream->payloads && newStream->payloads) { + OrtpPayloadType *refpt = reinterpret_cast(refStream->payloads->data); + OrtpPayloadType *newpt = reinterpret_cast(newStream->payloads->data); + if ((strcmp(refpt->mime_type, newpt->mime_type) == 0) && (refpt->clock_rate == newpt->clock_rate) + && (payload_type_get_number(refpt) == payload_type_get_number(newpt))) { + MediaStream *ms = nullptr; + if (refStream->type == SalAudio) + ms = &audioStream->ms; + else if (refStream->type == SalVideo) + ms = &videoStream->ms; + if (ms) { + RtpSession *session = ms->sessions.rtp_session; + const char *rtpAddr = (newStream->rtp_addr[0] != '\0') ? newStream->rtp_addr : md->addr; + const char *rtcpAddr = (newStream->rtcp_addr[0] != '\0') ? newStream->rtcp_addr : md->addr; + if (ms_is_multicast(rtpAddr)) + lInfo() << "Multicast addr [" << rtpAddr << "/" << newStream->rtp_port << "] does not need auxiliary rtp's destination for CallSession [" << q << "]"; + else + rtp_session_add_aux_remote_addr_full(session, rtpAddr, newStream->rtp_port, rtcpAddr, newStream->rtcp_port); + } + } + } + } +} + +void MediaSessionPrivate::updateFrozenPayloads (SalMediaDescription *result) { + L_Q(MediaSession); + for (int i = 0; i < result->nb_streams; i++) { + for (bctbx_list_t *elem = result->streams[i].payloads; elem != nullptr; elem = bctbx_list_next(elem)) { + OrtpPayloadType *pt = reinterpret_cast(bctbx_list_get_data(elem)); + if (PayloadTypeHandler::isPayloadTypeNumberAvailable(localDesc->streams[i].already_assigned_payloads, payload_type_get_number(pt), nullptr)) { + /* New codec, needs to be added to the list */ + localDesc->streams[i].already_assigned_payloads = bctbx_list_append(localDesc->streams[i].already_assigned_payloads, payload_type_clone(pt)); + lInfo() << "CallSession[" << q << "] : payload type " << payload_type_get_number(pt) << " " << pt->mime_type << "/" << pt->clock_rate + << " fmtp=" << (pt->recv_fmtp ? pt->recv_fmtp : "") << " added to frozen list"; + } + } + } +} + +void MediaSessionPrivate::updateStreams (SalMediaDescription *newMd, LinphoneCallState targetState) { + L_Q(MediaSession); + if (!((state == LinphoneCallIncomingEarlyMedia) && linphone_core_get_ring_during_incoming_early_media(core))) + linphone_core_stop_ringing(core); + if (!newMd) { + lError() << "updateStreams() called with null media description"; + return; + } + updateBiggestDesc(localDesc); + sal_media_description_ref(newMd); + SalMediaDescription *oldMd = resultDesc; + resultDesc = newMd; + if ((audioStream && (audioStream->ms.state == MSStreamStarted)) || (videoStream && (videoStream->ms.state == MSStreamStarted))) { + clearEarlyMediaDestinations(); + + /* We already started media: check if we really need to restart it */ + int mdChanged = 0; + if (oldMd) { + mdChanged = mediaParametersChanged(oldMd, newMd); + /* Might not be mandatory to restart stream for each ice restart as it leads bad user experience, specially in video. See 0002495 for better background on this */ + if (mdChanged & (SAL_MEDIA_DESCRIPTION_CODEC_CHANGED + | SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED + | SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED + | SAL_MEDIA_DESCRIPTION_ICE_RESTART_DETECTED + | SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION)) + lInfo() << "Media descriptions are different, need to restart the streams"; +#if 0 + else if (call->playing_ringbacktone) + ms_message("Playing ringback tone, will restart the streams."); +#endif + else { +#if 0 + if (call->all_muted && (targetState == LinphoneCallStreamsRunning)) { + lInfo() << "Early media finished, unmuting inputs..."; + /* We were in early media, now we want to enable real media */ + call->all_muted = FALSE; + if (audioStream) + linphone_core_enable_mic(core, linphone_core_mic_enabled(core)); +#ifdef VIDEO_ENABLED + if (videoStream && cameraEnabled) + linphone_call_enable_camera(call, linphone_call_camera_enabled(call)); +#endif + } +#endif + if (mdChanged == SAL_MEDIA_DESCRIPTION_UNCHANGED) { + /* FIXME ZRTP, might be restarted in any cases? */ + lInfo() << "No need to restart streams, SDP is unchanged"; + if (oldMd) + sal_media_description_unref(oldMd); + return; + } else { + if (mdChanged & SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED) { + lInfo() << "Network parameters have changed, update them"; + updateStreamsDestinations(oldMd, newMd); + } + if (mdChanged & SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED) { + lInfo() << "Crypto parameters have changed, update them"; + updateCryptoParameters(oldMd, newMd); + } + if (oldMd) + sal_media_description_unref(oldMd); + return; + } + } + } + stopStreams(); + if (mdChanged & SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED) { + lInfo() << "Media ip type has changed, destroying sessions context on CallSession [" << q << "]"; + ms_media_stream_sessions_uninit(&sessions[mainAudioStreamIndex]); + ms_media_stream_sessions_uninit(&sessions[mainVideoStreamIndex]); + ms_media_stream_sessions_uninit(&sessions[mainTextStreamIndex]); + } + initializeStreams(); + } + + if (!audioStream) { + /* This happens after pausing the call locally. The streams are destroyed and then we wait the 200Ok to recreate them */ + initializeStreams(); + } + + if (params->earlyMediaSendingEnabled() && (state == LinphoneCallOutgoingEarlyMedia)) + prepareEarlyMediaForking(); + startStreams(targetState); + if ((state == LinphoneCallPausing) && pausedByApp && (bctbx_list_size(core->calls) == 1)) + linphone_core_play_named_tone(core, LinphoneToneCallOnHold); + updateFrozenPayloads(newMd); + + if (oldMd) + sal_media_description_unref(oldMd); +} + +void MediaSessionPrivate::updateStreamsDestinations (SalMediaDescription *oldMd, SalMediaDescription *newMd) { + SalStreamDescription *newAudioDesc = nullptr; + SalStreamDescription *newVideoDesc = nullptr; + for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + if (!sal_stream_description_active(&newMd->streams[i])) + continue; + if (newMd->streams[i].type == SalAudio) + newAudioDesc = &newMd->streams[i]; + else if (newMd->streams[i].type == SalVideo) + newVideoDesc = &newMd->streams[i]; + } + if (audioStream && newAudioDesc) { + const char *rtpAddr = (newAudioDesc->rtp_addr[0] != '\0') ? newAudioDesc->rtp_addr : newMd->addr; + const char *rtcpAddr = (newAudioDesc->rtcp_addr[0] != '\0') ? newAudioDesc->rtcp_addr : newMd->addr; + lInfo() << "Change audio stream destination: RTP=" << rtpAddr << ":" << newAudioDesc->rtp_port << " RTCP=" << rtcpAddr << ":" << newAudioDesc->rtcp_port; + rtp_session_set_remote_addr_full(audioStream->ms.sessions.rtp_session, rtpAddr, newAudioDesc->rtp_port, rtcpAddr, newAudioDesc->rtcp_port); + } +#ifdef VIDEO_ENABLED + if (videoStream && newVideoDesc) { + const char *rtpAddr = (newVideoDesc->rtp_addr[0] != '\0') ? newVideoDesc->rtp_addr : newMd->addr; + const char *rtcpAddr = (newVideoDesc->rtcp_addr[0] != '\0') ? newVideoDesc->rtcp_addr : newMd->addr; + lInfo() << "Change video stream destination: RTP=" << rtpAddr << ":" << newVideoDesc->rtp_port << " RTCP=" << rtcpAddr << ":" << newVideoDesc->rtcp_port; + rtp_session_set_remote_addr_full(videoStream->ms.sessions.rtp_session, rtpAddr, newVideoDesc->rtp_port, rtcpAddr, newVideoDesc->rtcp_port); + } +#endif +} + +// ----------------------------------------------------------------------------- + +bool MediaSessionPrivate::allStreamsAvpfEnabled () const { + int nbActiveStreams = 0; + int nbAvpfEnabledStreams = 0; + if (audioStream && media_stream_get_state(&audioStream->ms) == MSStreamStarted) { + nbActiveStreams++; + if (media_stream_avpf_enabled(&audioStream->ms)) + nbAvpfEnabledStreams++; + } + if (videoStream && media_stream_get_state(&videoStream->ms) == MSStreamStarted) { + nbActiveStreams++; + if (media_stream_avpf_enabled(&videoStream->ms)) + nbAvpfEnabledStreams++; + } + return (nbActiveStreams > 0) && (nbActiveStreams == nbAvpfEnabledStreams); +} + +bool MediaSessionPrivate::allStreamsEncrypted () const { + int numberOfEncryptedStreams = 0; + int numberOfActiveStreams = 0; + if (audioStream && (media_stream_get_state(&audioStream->ms) == MSStreamStarted)) { + numberOfActiveStreams++; + if (media_stream_secured(&audioStream->ms)) + numberOfEncryptedStreams++; + } + if (videoStream && (media_stream_get_state(&videoStream->ms) == MSStreamStarted)) { + numberOfActiveStreams++; + if (media_stream_secured(&videoStream->ms)) + numberOfEncryptedStreams++; + } + if (textStream && (media_stream_get_state(&textStream->ms) == MSStreamStarted)) { + numberOfActiveStreams++; + if (media_stream_secured(&textStream->ms)) + numberOfEncryptedStreams++; + } + return (numberOfActiveStreams > 0) && (numberOfActiveStreams == numberOfEncryptedStreams); +} + +bool MediaSessionPrivate::atLeastOneStreamStarted () const { + return (audioStream && (media_stream_get_state(&audioStream->ms) == MSStreamStarted)) + || (videoStream && (media_stream_get_state(&videoStream->ms) == MSStreamStarted)) + || (textStream && (media_stream_get_state(&textStream->ms) == MSStreamStarted)); +} + +void MediaSessionPrivate::audioStreamAuthTokenReady (const string &authToken, bool verified) { + this->authToken = authToken; + authTokenVerified = verified; + lInfo() << "Authentication token is " << authToken << "(" << (verified ? "verified" : "unverified") << ")"; +} + +void MediaSessionPrivate::audioStreamEncryptionChanged (bool encrypted) { + L_Q(MediaSession); + if (encrypted && (params->getMediaEncryption() == LinphoneMediaEncryptionZRTP)) { + /* If encryption is DTLS, no status to be displayed */ + char status[255]; + memset(status, 0, sizeof(status)); + snprintf(status, sizeof(status) - 1, _("Authentication token is %s"), authToken.c_str()); + linphone_core_notify_display_status(core, status); + } + + propagateEncryptionChanged(); + +#ifdef VIDEO_ENABLED + /* Enable video encryption */ + if ((params->getMediaEncryption() == LinphoneMediaEncryptionZRTP) && q->getCurrentParams()->videoEnabled()) { + lInfo() << "Trying to start ZRTP encryption on video stream"; + video_stream_start_zrtp(videoStream); + } +#endif +} + +uint16_t MediaSessionPrivate::getAvpfRrInterval () const { + uint16_t rrInterval = 0; + if (audioStream && (media_stream_get_state(&audioStream->ms) == MSStreamStarted)) { + uint16_t streamRrInterval = media_stream_get_avpf_rr_interval(&audioStream->ms); + if (streamRrInterval > rrInterval) rrInterval = streamRrInterval; + } + if (videoStream && (media_stream_get_state(&videoStream->ms) == MSStreamStarted)) { + uint16_t streamRrInterval = media_stream_get_avpf_rr_interval(&videoStream->ms); + if (streamRrInterval > rrInterval) rrInterval = streamRrInterval; + } + return rrInterval; +} + +int MediaSessionPrivate::getNbActiveStreams () const { + SalMediaDescription *md = nullptr; + if (op) + md = sal_call_get_remote_media_description(op); + if (!md) + return 0; + return sal_media_description_nb_active_streams_of_type(md, SalAudio) + sal_media_description_nb_active_streams_of_type(md, SalVideo) + sal_media_description_nb_active_streams_of_type(md, SalText); +} + +bool MediaSessionPrivate::isEncryptionMandatory () const { + L_Q(const MediaSession); + if (params->getMediaEncryption() == LinphoneMediaEncryptionDTLS) { + lInfo() << "Forced encryption mandatory on CallSession [" << q << "] due to SRTP-DTLS"; + return true; + } + return params->mandatoryMediaEncryptionEnabled(); +} + +int MediaSessionPrivate::mediaParametersChanged (SalMediaDescription *oldMd, SalMediaDescription *newMd) { + if (params->getPrivate()->getInConference() != currentParams->getPrivate()->getInConference()) + return SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION; + if (upBandwidth != linphone_core_get_upload_bandwidth(core)) + return SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION; + if (localDescChanged) { + char *differences = sal_media_description_print_differences(localDescChanged); + lInfo() << "Local description has changed: " << differences; + ms_free(differences); + } + int otherDescChanged = sal_media_description_equals(oldMd, newMd); + if (otherDescChanged) { + char *differences = sal_media_description_print_differences(otherDescChanged); + lInfo() << "Other description has changed: " << differences; + ms_free(differences); + } + return localDescChanged | otherDescChanged; +} + +void MediaSessionPrivate::propagateEncryptionChanged () { + L_Q(MediaSession); + if (!allStreamsEncrypted()) { + lInfo() << "Some streams are not encrypted"; + q->getCurrentParams()->setMediaEncryption(LinphoneMediaEncryptionNone); + if (listener) + listener->encryptionChanged(*q, false, authToken); + } else { + if (!authToken.empty()) { + /* ZRTP only is using auth_token */ + q->getCurrentParams()->setMediaEncryption(LinphoneMediaEncryptionZRTP); + } else { + /* Otherwise it must be DTLS as SDES doesn't go through this function */ + q->getCurrentParams()->setMediaEncryption(LinphoneMediaEncryptionDTLS); + } + lInfo() << "All streams are encrypted, key exchanged using " + << ((q->getCurrentParams()->getMediaEncryption() == LinphoneMediaEncryptionZRTP) ? "ZRTP" + : (q->getCurrentParams()->getMediaEncryption() == LinphoneMediaEncryptionDTLS) ? "DTLS" : "Unknown mechanism"); + if (listener) + listener->encryptionChanged(*q, true, authToken); +#ifdef VIDEO_ENABLED + if (isEncryptionMandatory() && videoStream && media_stream_started(&videoStream->ms)) { + /* Nothing could have been sent yet so generating key frame */ + video_stream_send_vfu(videoStream); + } +#endif + } +} + +// ----------------------------------------------------------------------------- + +void MediaSessionPrivate::fillLogStats (MediaStream *st) { + float quality = media_stream_get_average_quality_rating(st); + if (quality >= 0) { + if (log->quality == -1) + log->quality = quality; + else + log->quality *= quality / 5.0f; + } +} + +void MediaSessionPrivate::updateRtpStats (LinphoneCallStats *stats, int streamIndex) { + if (sessions[streamIndex].rtp_session) { + const rtp_stats_t *rtpStats = rtp_session_get_stats(sessions[streamIndex].rtp_session); + if (stats) + memcpy(&(stats->rtp_stats), rtpStats, sizeof(*rtpStats)); + } +} + +// ----------------------------------------------------------------------------- + +bool MediaSessionPrivate::mediaReportEnabled (int statsType) { + L_Q(MediaSession); + if (!qualityReportingEnabled()) + return false; + if ((statsType == LINPHONE_CALL_STATS_VIDEO) && !q->getCurrentParams()->videoEnabled()) + return false; + if ((statsType == LINPHONE_CALL_STATS_TEXT) && !q->getCurrentParams()->realtimeTextEnabled()) + return false; + return (log->reporting.reports[statsType] != nullptr); +} + +bool MediaSessionPrivate::qualityReportingEnabled () const { + return (destProxy && linphone_proxy_config_quality_reporting_enabled(destProxy)); +} + +void MediaSessionPrivate::updateReportingCallState () { + if ((state == LinphoneCallReleased) || !qualityReportingEnabled()) + return; + switch (state) { + case LinphoneCallStreamsRunning: +#if 0 + for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + int streamIndex = (i == mainAudioStreamIndex) ? LINPHONE_CALL_STATS_AUDIO : mainVideoStreamIndex ? LINPHONE_CALL_STATS_VIDEO : LINPHONE_CALL_STATS_TEXT; + bool enabled = mediaReportEnabled(streamIndex); + MediaStream *ms = getMediaStream(i); + if (enabled && set_on_action_suggested_cb(ms, qos_analyzer_on_action_suggested, log->reporting.reports[streamIndex])) { + log->reporting.reports[streamIndex]->call = call; + STR_REASSIGN(log->reporting.reports[streamIndex]->qos_analyzer.name, ms_strdup(ms_qos_analyzer_get_name(ms_bitrate_controller_get_qos_analyzer(ms->rc)))); + } + } + linphone_reporting_update_ip(call); + if (!mediaReportEnabled(LINPHONE_CALL_STATS_VIDEO) && log->reporting.was_video_running) + send_report(log->reporting.reports[LINPHONE_CALL_STATS_VIDEO], "VQSessionReport"); +#endif + log->reporting.was_video_running = mediaReportEnabled(LINPHONE_CALL_STATS_VIDEO); + break; + case LinphoneCallEnd: +#if 0 + set_on_action_suggested_cb(&audioStream->ms, nullptr, nullptr); + set_on_action_suggested_cb(&videoStream->ms, nullptr, nullptr); + if ((log->status == LinphoneCallSuccess) || (log->status == LinphoneCallAborted)) + linphone_reporting_publish_session_report(call, true); +#endif + break; + default: + break; + } +} + +void MediaSessionPrivate::updateReportingMediaInfo (int statsType) { + L_Q(MediaSession); + /* op might be already released if hanging up in state LinphoneCallOutgoingInit */ + if (!op || !mediaReportEnabled(statsType)) + return; + + char *dialogId = sal_op_get_dialog_id(op); + reporting_session_report_t * report = log->reporting.reports[statsType]; + STR_REASSIGN(report->info.call_id, ms_strdup(log->call_id)); + + STR_REASSIGN(report->local_metrics.user_agent, ms_strdup(linphone_core_get_user_agent(core))); + STR_REASSIGN(report->remote_metrics.user_agent, ms_strdup(q->getRemoteUserAgent().c_str())); + + /* RFC states: "LocalGroupID provides the identification for the purposes of aggregation for the local endpoint" */ + STR_REASSIGN(report->info.local_addr.group, ms_strdup_printf("%s-%s-%s", + dialogId ? dialogId : "", "local", + report->local_metrics.user_agent ? report->local_metrics.user_agent : "")); + STR_REASSIGN(report->info.remote_addr.group, ms_strdup_printf("%s-%s-%s", + dialogId ? dialogId : "", "remote", + report->remote_metrics.user_agent ? report->remote_metrics.user_agent : "")); + + if (direction == LinphoneCallIncoming) { + STR_REASSIGN(report->info.remote_addr.id, linphone_address_as_string(log->from)); + STR_REASSIGN(report->info.local_addr.id, linphone_address_as_string(log->to)); + STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.remote_addr.id)); + } else { + STR_REASSIGN(report->info.remote_addr.id, linphone_address_as_string(log->to)); + STR_REASSIGN(report->info.local_addr.id, linphone_address_as_string(log->from)); + STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.local_addr.id)); + } + + report->local_metrics.timestamps.start = log->start_date_time; + report->local_metrics.timestamps.stop = log->start_date_time + q->getDuration(); + + /* We use same timestamps for remote too */ + report->remote_metrics.timestamps.start = log->start_date_time; + report->remote_metrics.timestamps.stop = log->start_date_time + q->getDuration(); + + /* Yet we use the same payload config for local and remote, since this is the largest use case */ + MediaStream *stream = nullptr; + const OrtpPayloadType *localPayload = nullptr; + const OrtpPayloadType *remotePayload = nullptr; + if (audioStream && (statsType == LINPHONE_CALL_STATS_AUDIO)) { + stream = &audioStream->ms; + localPayload = q->getCurrentParams()->getUsedAudioCodec(); + remotePayload = localPayload; + } else if (videoStream && (statsType == LINPHONE_CALL_STATS_VIDEO)) { + stream = &videoStream->ms; + localPayload = q->getCurrentParams()->getUsedVideoCodec(); + remotePayload = localPayload; + } else if (textStream && (statsType == LINPHONE_CALL_STATS_TEXT)) { + stream = &textStream->ms; + localPayload = q->getCurrentParams()->getUsedRealtimeTextCodec(); + remotePayload = localPayload; + } + + if (stream) { + RtpSession * session = stream->sessions.rtp_session; + report->info.local_addr.ssrc = rtp_session_get_send_ssrc(session); + report->info.remote_addr.ssrc = rtp_session_get_recv_ssrc(session); + if (stream->qi){ + report->local_metrics.quality_estimates.moslq = ms_quality_indicator_get_average_lq_rating(stream->qi) >= 0 ? + MAX(1, ms_quality_indicator_get_average_lq_rating(stream->qi)) : -1; + report->local_metrics.quality_estimates.moscq = ms_quality_indicator_get_average_rating(stream->qi) >= 0 ? + MAX(1, ms_quality_indicator_get_average_rating(stream->qi)) : -1; + } + } + + STR_REASSIGN(report->dialog_id, ms_strdup_printf("%s;%u", dialogId ? dialogId : "", report->info.local_addr.ssrc)); + ms_free(dialogId); + + if (localPayload) { + report->local_metrics.session_description.payload_type = localPayload->type; + if (localPayload->mime_type) + STR_REASSIGN(report->local_metrics.session_description.payload_desc, ms_strdup(localPayload->mime_type)); + report->local_metrics.session_description.sample_rate = localPayload->clock_rate; + if (localPayload->recv_fmtp) + STR_REASSIGN(report->local_metrics.session_description.fmtp, ms_strdup(localPayload->recv_fmtp)); + } + + if (remotePayload) { + report->remote_metrics.session_description.payload_type = remotePayload->type; + STR_REASSIGN(report->remote_metrics.session_description.payload_desc, ms_strdup(remotePayload->mime_type)); + report->remote_metrics.session_description.sample_rate = remotePayload->clock_rate; + STR_REASSIGN(report->remote_metrics.session_description.fmtp, ms_strdup(remotePayload->recv_fmtp)); + } +} + +// ----------------------------------------------------------------------------- + +void MediaSessionPrivate::executeBackgroundTasks (bool oneSecondElapsed) { + switch (state) { + case LinphoneCallStreamsRunning: + case LinphoneCallOutgoingEarlyMedia: + case LinphoneCallIncomingEarlyMedia: + case LinphoneCallPausedByRemote: + case LinphoneCallPaused: + if (oneSecondElapsed) { + float audioLoad = 0.f; + float videoLoad = 0.f; + float textLoad = 0.f; + if (audioStream && audioStream->ms.sessions.ticker) + audioLoad = ms_ticker_get_average_load(audioStream->ms.sessions.ticker); + if (videoStream && videoStream->ms.sessions.ticker) + videoLoad = ms_ticker_get_average_load(videoStream->ms.sessions.ticker); + if (textStream && textStream->ms.sessions.ticker) + textLoad = ms_ticker_get_average_load(textStream->ms.sessions.ticker); + reportBandwidth(); + lInfo() << "Thread processing load: audio=" << audioLoad << "\tvideo=" << videoLoad << "\ttext=" << textLoad; + } + break; + default: + /* No stats for other states */ + break; + } + + handleStreamEvents(mainAudioStreamIndex); + handleStreamEvents(mainVideoStreamIndex); + handleStreamEvents(mainTextStreamIndex); + + int disconnectTimeout = linphone_core_get_nortp_timeout(core); + bool disconnected = false; + if (((state == LinphoneCallStreamsRunning) || (state == LinphoneCallPausedByRemote)) && oneSecondElapsed && audioStream + && (audioStream->ms.state == MSStreamStarted) && (disconnectTimeout > 0)) { + disconnected = !audio_stream_alive(audioStream, disconnectTimeout); + } +#if 0 + if (disconnected) + linphone_call_lost(call); +#endif +} + +void MediaSessionPrivate::reportBandwidth () { + L_Q(MediaSession); + reportBandwidthForStream(&audioStream->ms, LinphoneStreamTypeAudio); + reportBandwidthForStream(&videoStream->ms, LinphoneStreamTypeVideo); + reportBandwidthForStream(&textStream->ms, LinphoneStreamTypeText); + + lInfo() << "Bandwidth usage for CallSession [" << q << "]:\n" << fixed << setprecision(2) << + "\tRTP audio=[d=" << audioStats->download_bandwidth << ",u=" << audioStats->upload_bandwidth << + "], video=[d=" << videoStats->download_bandwidth << ",u=" << videoStats->upload_bandwidth << + "], text=[d=" << textStats->download_bandwidth << ",u=" << textStats->upload_bandwidth << "] kbits/sec\n" << + "\tRTCP audio=[d=" << audioStats->rtcp_download_bandwidth << ",u=" << audioStats->rtcp_upload_bandwidth << + "], video=[d=" << videoStats->rtcp_download_bandwidth << ",u=" << videoStats->rtcp_upload_bandwidth << + "], text=[d=" << textStats->rtcp_download_bandwidth << ",u=" << textStats->rtcp_upload_bandwidth << "] kbits/sec"; +} + +void MediaSessionPrivate::reportBandwidthForStream (MediaStream *ms, LinphoneStreamType type) { + LinphoneCallStats *stats = nullptr; + if (type == LinphoneStreamTypeAudio) { + stats = audioStats; + } else if (type == LinphoneStreamTypeVideo) { + stats = videoStats; + } else if (type == LinphoneStreamTypeText) { + stats = textStats; + } else + return; + + bool active = ms ? (media_stream_get_state(ms) == MSStreamStarted) : false; + stats->download_bandwidth = active ? (float)(media_stream_get_down_bw(ms) * 1e-3) : 0.f; + stats->upload_bandwidth = active ? (float)(media_stream_get_up_bw(ms) * 1e-3) : 0.f; + stats->rtcp_download_bandwidth = active ? (float)(media_stream_get_rtcp_down_bw(ms) * 1e-3) : 0.f; + stats->rtcp_upload_bandwidth = active ? (float)(media_stream_get_rtcp_up_bw(ms) * 1e-3) : 0.f; + stats->rtp_remote_family = active ? (ortp_stream_is_ipv6(&ms->sessions.rtp_session->rtp.gs) ? LinphoneAddressFamilyInet6 : LinphoneAddressFamilyInet) : LinphoneAddressFamilyUnspec; + + if (core->send_call_stats_periodical_updates) { + if (active) + linphone_call_stats_update(stats, ms); + stats->updated |= LINPHONE_CALL_STATS_PERIODICAL_UPDATE; + if (listener) + listener->statsUpdated(stats); + stats->updated = 0; + } +} + +// ----------------------------------------------------------------------------- + +void MediaSessionPrivate::handleIncomingReceivedStateInIncomingNotification () { + L_Q(MediaSession); + /* Try to be best-effort in giving real local or routable contact address for 100Rel case */ + setContactOp(); + bool proposeEarlyMedia = lp_config_get_int(linphone_core_get_config(core), "sip", "incoming_calls_early_media", false); + if (proposeEarlyMedia) + q->acceptEarlyMedia(); + else + sal_call_notify_ringing(op, false); + if (sal_call_get_replaces(op) && lp_config_get_int(linphone_core_get_config(core), "sip", "auto_answer_replacing_calls", 1)) + q->accept(); +} + +bool MediaSessionPrivate::isReadyForInvite () const { + bool callSessionReady = CallSessionPrivate::isReadyForInvite(); + bool iceReady = false; + if (iceAgent->hasSession()) { + if (iceAgent->candidatesGathered()) + iceReady = true; + } else + iceReady = true; + return callSessionReady && iceReady; +} + +void MediaSessionPrivate::setTerminated () { + freeResources(); + CallSessionPrivate::setTerminated(); +} + +LinphoneStatus MediaSessionPrivate::startAcceptUpdate (LinphoneCallState nextState, const string &stateInfo) { + if (iceAgent->hasSession() && (iceAgent->getNbLosingPairs() > 0)) { + /* Defer the sending of the answer until there are no losing pairs left */ + return 0; + } + makeLocalMediaDescription(); + updateRemoteSessionIdAndVer(); + sal_call_set_local_media_description(op, localDesc); + sal_call_accept(op); + SalMediaDescription *md = sal_call_get_final_media_description(op); + iceAgent->stopIceForInactiveStreams(md); + if (md && !sal_media_description_empty(md)) + updateStreams(md, nextState); + setState(nextState, stateInfo); + return 0; +} + +LinphoneStatus MediaSessionPrivate::startUpdate () { + fillMulticastMediaAddresses(); + if (!params->getPrivate()->getNoUserConsent()) + makeLocalMediaDescription(); + if (!core->sip_conf.sdp_200_ack) + sal_call_set_local_media_description(op, localDesc); + else + sal_call_set_local_media_description(op, nullptr); + LinphoneStatus result = CallSessionPrivate::startUpdate(); + if (core->sip_conf.sdp_200_ack) { + /* We are NOT offering, set local media description after sending the call so that we are ready to + * process the remote offer when it will arrive. */ + sal_call_set_local_media_description(op, localDesc); + } + return result; +} + +void MediaSessionPrivate::terminate () { +#if 0 // TODO: handle in Call class + /* Stop ringing */ + bool_t stop_ringing = TRUE; + bool_t ring_during_early_media = linphone_core_get_ring_during_incoming_early_media(lc); + const bctbx_list_t *calls = linphone_core_get_calls(lc); + while(calls) { + if (((LinphoneCall *)calls->data)->state == LinphoneCallIncomingReceived || (ring_during_early_media && ((LinphoneCall *)calls->data)->state == LinphoneCallIncomingEarlyMedia)) { + stop_ringing = FALSE; + break; + } + calls = calls->next; + } + if(stop_ringing) { + linphone_core_stop_ringing(lc); + } +#endif + + stopStreams(); + CallSessionPrivate::terminate(); +} + +void MediaSessionPrivate::updateCurrentParams () { + CallSessionPrivate::updateCurrentParams(); + + LinphoneVideoDefinition *vdef = linphone_video_definition_new(MS_VIDEO_SIZE_UNKNOWN_W, MS_VIDEO_SIZE_UNKNOWN_H, nullptr); + currentParams->getPrivate()->setSentVideoDefinition(vdef); + currentParams->getPrivate()->setReceivedVideoDefinition(vdef); + linphone_video_definition_unref(vdef); +#ifdef VIDEO_ENABLED + if (videoStream) { + MSVideoSize vsize = video_stream_get_sent_video_size(videoStream); + vdef = linphone_video_definition_new(vsize.width, vsize.height, nullptr); + currentParams->getPrivate()->setSentVideoDefinition(vdef); + linphone_video_definition_unref(vdef); + vsize = video_stream_get_received_video_size(videoStream); + vdef = linphone_video_definition_new(vsize.width, vsize.height, nullptr); + currentParams->getPrivate()->setReceivedVideoDefinition(vdef); + linphone_video_definition_unref(vdef); + currentParams->getPrivate()->setSentFps(video_stream_get_sent_framerate(videoStream)); + currentParams->getPrivate()->setReceivedFps(video_stream_get_received_framerate(videoStream)); + } +#endif + + /* REVISITED + * Previous code was buggy. + * Relying on the mediastream's state (added by jehan: only) to know the current encryption is unreliable. + * For (added by jehan: both DTLS and) ZRTP it is though necessary. + * But for all others the current_params->media_encryption state should reflect (added by jehan: both) what is agreed by the offer/answer + * mechanism (added by jehan: and encryption status from media which is much stronger than only result of offer/answer ) + * Typically there can be inactive streams for which the media layer has no idea of whether they are encrypted or not. + */ + + switch (params->getMediaEncryption()) { + case LinphoneMediaEncryptionZRTP: + if (atLeastOneStreamStarted()) { + if (allStreamsEncrypted() && !authToken.empty()) + currentParams->setMediaEncryption(LinphoneMediaEncryptionZRTP); + else { + /* To avoid too many traces */ + lDebug() << "Encryption was requested to be " << linphone_media_encryption_to_string(params->getMediaEncryption()) + << ", but isn't effective (allStreamsEncrypted=" << allStreamsEncrypted() << ", auth_token=" << authToken << ")"; + currentParams->setMediaEncryption(LinphoneMediaEncryptionNone); + } + } /* else don't update the state if all streams are shutdown */ + break; + case LinphoneMediaEncryptionDTLS: + case LinphoneMediaEncryptionSRTP: + if (atLeastOneStreamStarted()) { + if ((getNbActiveStreams() == 0) || allStreamsEncrypted()) + currentParams->setMediaEncryption(params->getMediaEncryption()); + else { + /* To avoid to many traces */ + lDebug() << "Encryption was requested to be " << linphone_media_encryption_to_string(params->getMediaEncryption()) + << ", but isn't effective (allStreamsEncrypted=" << allStreamsEncrypted() << ")"; + currentParams->setMediaEncryption(LinphoneMediaEncryptionNone); + } + } /* else don't update the state if all streams are shutdown */ + break; + case LinphoneMediaEncryptionNone: + /* Check if we actually switched to ZRTP */ + if (atLeastOneStreamStarted() && allStreamsEncrypted() && !authToken.empty()) + currentParams->setMediaEncryption(LinphoneMediaEncryptionZRTP); + else + currentParams->setMediaEncryption(LinphoneMediaEncryptionNone); + break; + } + SalMediaDescription *md = resultDesc; + currentParams->enableAvpf(allStreamsAvpfEnabled() && sal_media_description_has_avpf(md)); + if (currentParams->avpfEnabled()) + currentParams->setAvpfRrInterval(getAvpfRrInterval()); + else + currentParams->setAvpfRrInterval(0); + if (md) { + SalStreamDescription *sd = sal_media_description_find_best_stream(md, SalAudio); + currentParams->setAudioDirection(sd ? MediaSessionParamsPrivate::salStreamDirToMediaDirection(sd->dir) : LinphoneMediaDirectionInactive); + if (currentParams->getAudioDirection() != LinphoneMediaDirectionInactive) { + const char *rtpAddr = (sd->rtp_addr[0] != '\0') ? sd->rtp_addr : md->addr; + currentParams->enableAudioMulticast(ms_is_multicast(rtpAddr)); + } else + currentParams->enableAudioMulticast(false); + sd = sal_media_description_find_best_stream(md, SalVideo); + currentParams->getPrivate()->enableImplicitRtcpFb(sd ? sal_stream_description_has_implicit_avpf(sd): false); + currentParams->setVideoDirection(sd ? MediaSessionParamsPrivate::salStreamDirToMediaDirection(sd->dir) : LinphoneMediaDirectionInactive); + if (currentParams->getVideoDirection() != LinphoneMediaDirectionInactive) { + const char *rtpAddr = (sd->rtp_addr[0] != '\0') ? sd->rtp_addr : md->addr; + currentParams->enableVideoMulticast(ms_is_multicast(rtpAddr)); + } else + currentParams->enableVideoMulticast(false); + } +} + +// ----------------------------------------------------------------------------- + +void MediaSessionPrivate::accept (const shared_ptr params) { + if (params) { + this->params = params; + iceAgent->prepare(localDesc, true); + makeLocalMediaDescription(); + sal_call_set_local_media_description(op, localDesc); + } + + updateRemoteSessionIdAndVer(); + + /* Give a chance a set card prefered sampling frequency */ + if (localDesc->streams[0].max_rate > 0) { + lInfo() << "Configuring prefered card sampling rate to [" << localDesc->streams[0].max_rate << "]"; + if (core->sound_conf.play_sndcard) + ms_snd_card_set_preferred_sample_rate(core->sound_conf.play_sndcard, localDesc->streams[0].max_rate); + if (core->sound_conf.capt_sndcard) + ms_snd_card_set_preferred_sample_rate(core->sound_conf.capt_sndcard, localDesc->streams[0].max_rate); + } + +#if 0 + if (!was_ringing && (audioStream->ms.state == MSStreamInitialized) && !core->use_files) { + audio_stream_prepare_sound(audioStream, core->sound_conf.play_sndcard, core->sound_conf.capt_sndcard); + } +#endif + + CallSessionPrivate::accept(params); + + SalMediaDescription *newMd = sal_call_get_final_media_description(op); + iceAgent->stopIceForInactiveStreams(newMd); + if (newMd) { + updateStreams(newMd, LinphoneCallStreamsRunning); + setState(LinphoneCallStreamsRunning, "Connected (streams running)"); + } else + expectMediaInAck = true; +} + +LinphoneStatus MediaSessionPrivate::acceptUpdate (const shared_ptr csp, LinphoneCallState nextState, const string &stateInfo) { + L_Q(MediaSession); + SalMediaDescription *desc = sal_call_get_remote_media_description(op); + bool keepSdpVersion = lp_config_get_int(linphone_core_get_config(core), "sip", "keep_sdp_version", 0); + if (keepSdpVersion && (desc->session_id == remoteSessionId) && (desc->session_ver == remoteSessionVer)) { + /* Remote has sent an INVITE with the same SDP as before, so send a 200 OK with the same SDP as before. */ + lWarning() << "SDP version has not changed, send same SDP as before"; + sal_call_accept(op); + setState(nextState, stateInfo); + return 0; + } + if (csp) + params = make_shared(*static_cast(csp.get())); + else { + if (!sal_call_is_offerer(op)) { + /* Reset call params for multicast because this param is only relevant when offering */ + params->enableAudioMulticast(false); + params->enableVideoMulticast(false); + } + } + if (params->videoEnabled() && !linphone_core_video_enabled(core)) { + lWarning() << "Requested video but video support is globally disabled. Refusing video"; + params->enableVideo(false); + } + if (q->getCurrentParams()->getPrivate()->getInConference()) { + lWarning() << "Video isn't supported in conference"; + params->enableVideo(false); + } + /* Update multicast params according to call params */ + fillMulticastMediaAddresses(); + iceAgent->checkSession(IR_Controlled, true); + initializeStreams(); /* So that video stream is initialized if necessary */ + if (iceAgent->prepare(localDesc, true)) + return 0; /* Deferred until completion of ICE gathering */ + startAcceptUpdate(nextState, stateInfo); + return 0; +} + +// ----------------------------------------------------------------------------- + +#ifdef VIDEO_ENABLED +void MediaSessionPrivate::videoStreamEventCb (const MSFilter *f, const unsigned int eventId, const void *args) { + L_Q(MediaSession); + switch (eventId) { + case MS_VIDEO_DECODER_DECODING_ERRORS: + lWarning() << "MS_VIDEO_DECODER_DECODING_ERRORS"; + if (videoStream && video_stream_is_decoding_error_to_be_reported(videoStream, 5000)) { + video_stream_decoding_error_reported(videoStream); + q->sendVfuRequest(); + } + break; + case MS_VIDEO_DECODER_RECOVERED_FROM_ERRORS: + lInfo() << "MS_VIDEO_DECODER_RECOVERED_FROM_ERRORS"; + if (videoStream) + video_stream_decoding_error_recovered(videoStream); + break; + case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED: + lInfo() << "First video frame decoded successfully"; + if (listener) + listener->firstVideoFrameDecoded(*q); + break; + case MS_VIDEO_DECODER_SEND_PLI: + case MS_VIDEO_DECODER_SEND_SLI: + case MS_VIDEO_DECODER_SEND_RPSI: + /* Handled internally by mediastreamer2 */ + break; + default: + lWarning() << "Unhandled event " << eventId; + break; + } +} +#endif + +void MediaSessionPrivate::realTimeTextCharacterReceived (MSFilter *f, unsigned int id, void *arg) { + if (id == MS_RTT_4103_RECEIVED_CHAR) { +#if 0 + RealtimeTextReceivedCharacter *data = reinterpret_cast(arg); + LinphoneChatRoom * chat_room = linphone_call_get_chat_room(call); + linphone_core_real_time_text_received(call->core, chat_room, data->character, call); +#endif + } +} + +// ----------------------------------------------------------------------------- + +void MediaSessionPrivate::stunAuthRequestedCb (const char *realm, const char *nonce, const char **username, const char **password, const char **ha1) { + /* Get the username from the nat policy or the proxy config */ + LinphoneProxyConfig *proxy = nullptr; + if (destProxy) + proxy = destProxy; + else + proxy = linphone_core_get_default_proxy_config(core); + if (!proxy) + return; + const char * user = nullptr; + LinphoneNatPolicy *proxyNatPolicy = linphone_proxy_config_get_nat_policy(proxy); + if (proxyNatPolicy) + user = linphone_nat_policy_get_stun_server_username(proxyNatPolicy); + else if (natPolicy) + user = linphone_nat_policy_get_stun_server_username(natPolicy); + if (!user) { + /* If the username has not been found in the nat_policy, take the username from the currently used proxy config */ + const LinphoneAddress *addr = linphone_proxy_config_get_identity_address(proxy); + if (!addr) + return; + user = linphone_address_get_username(addr); + } + if (!user) + return; + + const LinphoneAuthInfo *authInfo = linphone_core_find_auth_info(core, realm, user, nullptr); + if (!authInfo) { + lWarning() << "No auth info found for STUN auth request"; + return; + } + const char *hash = linphone_auth_info_get_ha1(authInfo); + if (hash) + *ha1 = hash; + else + *password = linphone_auth_info_get_passwd(authInfo); + *username = user; +} + +// ============================================================================= + +MediaSession::MediaSession (const Conference &conference, const shared_ptr params, CallSessionListener *listener) + : CallSession(*new MediaSessionPrivate(conference, params, listener)) { + L_D(MediaSession); + d->iceAgent = new IceAgent(*this); +} + +// ----------------------------------------------------------------------------- + +LinphoneStatus MediaSession::accept (const shared_ptr msp) { + L_D(MediaSession); + LinphoneStatus result = d->checkForAcceptation(); + if (result < 0) return result; + +#if 0 + bool_t was_ringing = FALSE; + + if (lc->current_call != call) { + linphone_core_preempt_sound_resources(lc); + } + + /* Stop ringing */ + if (linphone_ringtoneplayer_is_started(lc->ringtoneplayer)) { + ms_message("Stop ringing"); + linphone_core_stop_ringing(lc); + was_ringing = TRUE; + } + if (call->ringing_beep) { + linphone_core_stop_dtmf(lc); + call->ringing_beep = FALSE; + } +#endif + + d->accept(msp); + lInfo() << "CallSession accepted"; + return 0; +} + +LinphoneStatus MediaSession::acceptEarlyMedia (const std::shared_ptr msp) { + L_D(MediaSession); + if (d->state != LinphoneCallIncomingReceived) { + lError() << "Bad state " << linphone_call_state_to_string(d->state) << " for MediaSession::acceptEarlyMedia()"; + return -1; + } + /* Try to be best-effort in giving real local or routable contact address for 100Rel case */ + d->setContactOp(); + /* If parameters are passed, update the media description */ + if (msp) { + d->params = msp; + d->makeLocalMediaDescription(); + sal_call_set_local_media_description(d->op, d->localDesc); + sal_op_set_sent_custom_header(d->op, d->params->getPrivate()->getCustomHeaders()); + } + sal_call_notify_ringing(d->op, true); + d->setState(LinphoneCallIncomingEarlyMedia, "Incoming call early media"); + SalMediaDescription *md = sal_call_get_final_media_description(d->op); + if (md) + d->updateStreams(md, d->state); + return 0; +} + +LinphoneStatus MediaSession::acceptUpdate (const shared_ptr msp) { + L_D(MediaSession); + if (d->expectMediaInAck) { + lError() << "MediaSession::acceptUpdate() is not possible during a late offer incoming reINVITE (INVITE without SDP)"; + return -1; + } + return CallSession::acceptUpdate(msp); +} + +// ----------------------------------------------------------------------------- + +void MediaSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalOp *op, const Address &from, const Address &to) { + L_D(MediaSession); + CallSession::configure (direction, cfg, op, from, to); + + if (direction == LinphoneCallOutgoing) { + d->selectOutgoingIpVersion(); + d->getLocalIp(to); + getCurrentParams()->getPrivate()->setUpdateCallWhenIceCompleted(d->params->getPrivate()->getUpdateCallWhenIceCompleted()); + d->fillMulticastMediaAddresses(); + if (d->natPolicy && linphone_nat_policy_ice_enabled(d->natPolicy)) + d->iceAgent->checkSession(IR_Controlling, false); + d->runStunTestsIfNeeded(); + d->discoverMtu(to); +#if 0 + if (linphone_call_params_get_referer(params)){ + call->referer=linphone_call_ref(linphone_call_params_get_referer(params)); + } +#endif + } else if (direction == LinphoneCallIncoming) { + d->selectIncomingIpVersion(); + /* Note that the choice of IP version for streams is later refined by setCompatibleIncomingCallParams() when examining the + * remote offer, if any. If the remote offer contains IPv4 addresses, we should propose IPv4 as well. */ + Address cleanedFrom = from; + cleanedFrom.clean(); + d->getLocalIp(cleanedFrom); + d->params = make_shared(); + d->params->initDefault(d->core); + d->initializeParamsAccordingToIncomingCallParams(); + SalMediaDescription *md = sal_call_get_remote_media_description(d->op); + if (d->natPolicy && linphone_nat_policy_ice_enabled(d->natPolicy)) { + if (md) { + /* Create the ice session now if ICE is required */ + d->iceAgent->checkSession(IR_Controlled, false); + } else { + d->natPolicy = nullptr; + lWarning() << "ICE not supported for incoming INVITE without SDP"; + } + } + if (d->natPolicy) + d->runStunTestsIfNeeded(); + d->discoverMtu(cleanedFrom); + } +} + +void MediaSession::initiateIncoming () { + L_D(MediaSession); + CallSession::initiateIncoming(); + d->initializeStreams(); + if (d->natPolicy) { + if (linphone_nat_policy_ice_enabled(d->natPolicy)) + d->deferIncomingNotification = d->iceAgent->prepare(d->localDesc, true); + } +} + +bool MediaSession::initiateOutgoing () { + L_D(MediaSession); + bool defer = CallSession::initiateOutgoing(); + d->initializeStreams(); + if (linphone_nat_policy_ice_enabled(d->natPolicy)) { + if (d->core->sip_conf.sdp_200_ack) + lWarning() << "ICE is not supported when sending INVITE without SDP"; + else { + /* Defer the start of the call after the ICE gathering process */ + defer |= d->iceAgent->prepare(d->localDesc, false); + } + } + return defer; +} + +void MediaSession::iterate (time_t currentRealTime, bool oneSecondElapsed) { + L_D(MediaSession); + int elapsed = (int)(currentRealTime - d->log->start_date_time); + d->executeBackgroundTasks(oneSecondElapsed); + if ((d->state == LinphoneCallOutgoingInit) && (elapsed >= d->core->sip_conf.delayed_timeout)) { + if (d->iceAgent->hasSession()) { + lWarning() << "ICE candidates gathering from [" << linphone_nat_policy_get_stun_server(d->natPolicy) << "] has not finished yet, proceed with the call without ICE anyway"; + d->iceAgent->deleteSession(); + } + } + CallSession::iterate(currentRealTime, oneSecondElapsed); +} + +void MediaSession::sendVfuRequest () { +#ifdef VIDEO_ENABLED + L_D(MediaSession); + shared_ptr currentParams = getCurrentParams(); + if ((currentParams->avpfEnabled() || currentParams->getPrivate()->implicitRtcpFbEnabled()) + && d->videoStream && media_stream_get_state(&d->videoStream->ms) == MSStreamStarted) { // || sal_media_description_has_implicit_avpf((const SalMediaDescription *)call->resultdesc) + lInfo() << "Request Full Intra Request on CallSession [" << this << "]"; + video_stream_send_fir(d->videoStream); + } else if (d->core->sip_conf.vfu_with_info) { + lInfo() << "Request SIP INFO FIR on CallSession [" << this << "]"; + if (d->state == LinphoneCallStreamsRunning) + sal_call_send_vfu_request(d->op); + } else + lInfo() << "vfu request using sip disabled from config [sip,vfu_with_info]"; +#endif +} + +void MediaSession::startIncomingNotification () { + L_D(MediaSession); + d->makeLocalMediaDescription(); + sal_call_set_local_media_description(d->op, d->localDesc); + SalMediaDescription *md = sal_call_get_final_media_description(d->op); + if (md) { + if (sal_media_description_empty(md) || linphone_core_incompatible_security(d->core, md)) { + LinphoneErrorInfo *ei = linphone_error_info_new(); + linphone_error_info_set(ei, nullptr, LinphoneReasonNotAcceptable, 488, "Not acceptable here", nullptr); +#if 0 + linphone_core_report_early_failed_call(d->core, LinphoneCallIncoming, linphone_address_ref(from_addr), linphone_address_ref(to_addr), ei); +#endif + sal_call_decline(d->op, SalReasonNotAcceptable, nullptr); +#if 0 + linphone_call_unref(call); +#endif + return; + } + } + + CallSession::startIncomingNotification(); +} + +int MediaSession::startInvite (const Address *destination) { + L_D(MediaSession); + linphone_core_stop_dtmf_stream(d->core); + d->makeLocalMediaDescription(); + if (d->core->ringstream && d->core->sound_conf.play_sndcard && d->core->sound_conf.capt_sndcard) { + /* Give a chance to set card prefered sampling frequency */ + if (d->localDesc->streams[0].max_rate > 0) + ms_snd_card_set_preferred_sample_rate(d->core->sound_conf.play_sndcard, d->localDesc->streams[0].max_rate); + if (!d->core->use_files) + audio_stream_prepare_sound(d->audioStream, d->core->sound_conf.play_sndcard, d->core->sound_conf.capt_sndcard); + } + if (!d->core->sip_conf.sdp_200_ack) { + /* We are offering, set local media description before sending the call */ + sal_call_set_local_media_description(d->op, d->localDesc); + } + + int result = CallSession::startInvite(destination); + if (result < 0) { + if (d->state == LinphoneCallError) + d->stopStreams(); + return result; + } + if (d->core->sip_conf.sdp_200_ack) { + /* We are NOT offering, set local media description after sending the call so that we are ready to + process the remote offer when it will arrive. */ + sal_call_set_local_media_description(d->op, d->localDesc); + } + return result; +} + +void MediaSession::startRecording () { + L_D(MediaSession); + if (d->params->getRecordFilePath().empty()) { + lError() << "MediaSession::startRecording(): no output file specified. Use linphone_call_params_set_record_file()"; + return; + } + if (d->audioStream && !d->params->getPrivate()->getInConference()) + audio_stream_mixed_record_start(d->audioStream); + d->recordActive = true; +} + +void MediaSession::stopRecording () { + L_D(MediaSession); + if (d->audioStream && !d->params->getPrivate()->getInConference()) + audio_stream_mixed_record_stop(d->audioStream); + d->recordActive = false; +} + +LinphoneStatus MediaSession::update (const shared_ptr msp) { + L_D(MediaSession); + LinphoneCallState nextState; + LinphoneCallState initialState = d->state; + if (!d->isUpdateAllowed(nextState)) + return -1; + if (d->currentParams.get() == msp.get()) + lWarning() << "CallSession::update() is given the current params, this is probably not what you intend to do!"; + d->iceAgent->checkSession(IR_Controlling, true); + if (d->params) { +#if 0 + call->broken = FALSE; +#endif + d->setState(nextState, "Updating call"); + d->params = msp; + if (d->iceAgent->prepare(d->localDesc, false)) { + lInfo() << "Defer CallSession update to gather ICE candidates"; + return 0; + } + LinphoneStatus result = d->startUpdate(); + if (result && (d->state != initialState)) { + /* Restore initial state */ + d->setState(initialState, "Restore initial state"); + } + } else { +#ifdef VIDEO_ENABLED + if (d->videoStream && (d->state == LinphoneCallStreamsRunning)) { + const LinphoneVideoDefinition *vdef = linphone_core_get_preferred_video_definition(d->core); + MSVideoSize vsize; + vsize.width = linphone_video_definition_get_width(vdef); + vsize.height = linphone_video_definition_get_height(vdef); + video_stream_set_sent_video_size(d->videoStream, vsize); + video_stream_set_fps(d->videoStream, linphone_core_get_preferred_framerate(d->core)); + if (d->cameraEnabled && (d->videoStream->cam != d->core->video_conf.device)) + video_stream_change_camera(d->videoStream, d->core->video_conf.device); + else + video_stream_update_video_params(d->videoStream); + } +#endif + } + return 0; +} + +// ----------------------------------------------------------------------------- + +void MediaSession::resetFirstVideoFrameDecoded () { + L_D(MediaSession); + if (d->videoStream && d->videoStream->ms.decoder) + ms_filter_call_method_noarg(d->videoStream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION); +} + +LinphoneStatus MediaSession::takePreviewSnapshot (const std::string& file) { +#ifdef VIDEO_ENABLED + L_D(MediaSession); + if (d->videoStream && d->videoStream->local_jpegwriter) { + const char *filepath = file.empty() ? nullptr : file.c_str(); + return ms_filter_call_method(d->videoStream->local_jpegwriter, MS_JPEG_WRITER_TAKE_SNAPSHOT, (void *)filepath); + } + lWarning() << "Cannot take local snapshot: no currently running video stream on this call"; +#endif + return -1; +} + +LinphoneStatus MediaSession::takeVideoSnapshot (const std::string& file) { +#ifdef VIDEO_ENABLED + L_D(MediaSession); + if (d->videoStream && d->videoStream->jpegwriter) { + const char *filepath = file.empty() ? nullptr : file.c_str(); + return ms_filter_call_method(d->videoStream->jpegwriter, MS_JPEG_WRITER_TAKE_SNAPSHOT, (void *)filepath); + } + lWarning() << "Cannot take snapshot: no currently running video stream on this call"; +#endif + return -1; +} + +void MediaSession::zoomVideo (float zoomFactor, float *cx, float *cy) { + L_D(MediaSession); + if (d->videoStream && d->videoStream->output) { + if (zoomFactor < 1) + zoomFactor = 1; + float halfsize = 0.5f * 1.0f / zoomFactor; + if ((*cx - halfsize) < 0) + *cx = 0 + halfsize; + if ((*cx + halfsize) > 1) + *cx = 1 - halfsize; + if ((*cy - halfsize) < 0) + *cy = 0 + halfsize; + if ((*cy + halfsize) > 1) + *cy = 1 - halfsize; + float zoom[3] = { zoomFactor, *cx, *cy }; + ms_filter_call_method(d->videoStream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom); + } else + lWarning() << "Could not apply zoom: video output wasn't activated"; +} + +// ----------------------------------------------------------------------------- + +bool MediaSession::cameraEnabled () const { + L_D(const MediaSession); + return d->cameraEnabled; +} + +bool MediaSession::echoCancellationEnabled () const { + L_D(const MediaSession); + if (d->audioStream && d->audioStream->ec) { + bool val; + ms_filter_call_method(d->audioStream->ec, MS_ECHO_CANCELLER_GET_BYPASS_MODE, &val); + return !val; + } else + return linphone_core_echo_cancellation_enabled(d->core); +} + +bool MediaSession::echoLimiterEnabled () const { + L_D(const MediaSession); + if (d->audioStream) + return d->audioStream->el_type !=ELInactive; + else + return linphone_core_echo_limiter_enabled(d->core); +} + +void MediaSession::enableCamera (bool value) { + L_D(MediaSession); +#ifdef VIDEO_ENABLED + d->cameraEnabled = value; + switch (d->state) { + case LinphoneCallStreamsRunning: + case LinphoneCallOutgoingEarlyMedia: + case LinphoneCallIncomingEarlyMedia: + case LinphoneCallConnected: + if (d->videoStream && video_stream_started(d->videoStream) && (video_stream_get_camera(d->videoStream) != d->getVideoDevice())) { + string currentCam = video_stream_get_camera(d->videoStream) ? ms_web_cam_get_name(video_stream_get_camera(d->videoStream)) : "NULL"; + string newCam = d->getVideoDevice() ? ms_web_cam_get_name(d->getVideoDevice()) : "NULL"; + lInfo() << "Switching video cam from [" << currentCam << "] to [" << newCam << "] on CallSession [" << this << "]"; + video_stream_change_camera(d->videoStream, d->getVideoDevice()); + } + break; + default: + break; + } +#endif +} + +void MediaSession::enableEchoCancellation (bool value) { + L_D(MediaSession); + if (d->audioStream && d->audioStream->ec) { + bool bypassMode = !value; + ms_filter_call_method(d->audioStream->ec, MS_ECHO_CANCELLER_SET_BYPASS_MODE, &bypassMode); + } +} + +void MediaSession::enableEchoLimiter (bool value) { + L_D(MediaSession); + if (d->audioStream) { + if (value) { + string type = lp_config_get_string(linphone_core_get_config(d->core), "sound", "el_type", "mic"); + if (type == "mic") + audio_stream_enable_echo_limiter(d->audioStream, ELControlMic); + else if (type == "full") + audio_stream_enable_echo_limiter(d->audioStream, ELControlFull); + } else + audio_stream_enable_echo_limiter(d->audioStream, ELInactive); + } +} + +bool MediaSession::getAllMuted () const { + L_D(const MediaSession); + return d->allMuted; +} + +LinphoneCallStats * MediaSession::getAudioStats () const { + return getStats(LinphoneStreamTypeAudio); +} + +string MediaSession::getAuthenticationToken () const { + L_D(const MediaSession); + return d->authToken; +} + +bool MediaSession::getAuthenticationTokenVerified () const { + L_D(const MediaSession); + return d->authTokenVerified; +} + +float MediaSession::getAverageQuality () const { + L_D(const MediaSession); + float audioRating = -1.f; + float videoRating = -1.f; + if (d->audioStream) + audioRating = media_stream_get_average_quality_rating(&d->audioStream->ms) / 5.0f; + if (d->videoStream) + videoRating = media_stream_get_average_quality_rating(&d->videoStream->ms) / 5.0f; + return MediaSessionPrivate::aggregateQualityRatings(audioRating, videoRating); +} + +shared_ptr MediaSession::getCurrentParams () { + L_D(MediaSession); + d->updateCurrentParams(); + return d->currentParams; +} + +float MediaSession::getCurrentQuality () const { + L_D(const MediaSession); + float audioRating = -1.f; + float videoRating = -1.f; + if (d->audioStream) + audioRating = media_stream_get_quality_rating(&d->audioStream->ms) / 5.0f; + if (d->videoStream) + videoRating = media_stream_get_quality_rating(&d->videoStream->ms) / 5.0f; + return MediaSessionPrivate::aggregateQualityRatings(audioRating, videoRating); +} + +const shared_ptr MediaSession::getMediaParams () const { + L_D(const MediaSession); + return d->params; +} + +RtpTransport * MediaSession::getMetaRtcpTransport (int streamIndex) { + L_D(MediaSession); + if ((streamIndex < 0) || (streamIndex >= getStreamCount())) + return nullptr; + RtpTransport *metaRtp; + RtpTransport *metaRtcp; + rtp_session_get_transports(d->sessions[streamIndex].rtp_session, &metaRtp, &metaRtcp); + return metaRtcp; +} + +RtpTransport * MediaSession::getMetaRtpTransport (int streamIndex) { + L_D(MediaSession); + if ((streamIndex < 0) || (streamIndex >= getStreamCount())) + return nullptr; + RtpTransport *metaRtp; + RtpTransport *metaRtcp; + rtp_session_get_transports(d->sessions[streamIndex].rtp_session, &metaRtp, &metaRtcp); + return metaRtp; +} + +float MediaSession::getMicrophoneVolumeGain () const { + L_D(const MediaSession); + if (d->audioStream) + return audio_stream_get_sound_card_input_gain(d->audioStream); + else { + lError() << "Could not get record volume: no audio stream"; + return -1.0f; + } +} + +void * MediaSession::getNativeVideoWindowId () const { + L_D(const MediaSession); + if (d->videoWindowId) { + /* The video id was previously set by the app */ + return d->videoWindowId; + } +#ifdef VIDEO_ENABLED + else if (d->videoStream) { + /* It was not set but we want to get the one automatically created by mediastreamer2 (desktop versions only) */ + return video_stream_get_native_window_id(d->videoStream); + } +#endif + return nullptr; +} + +const shared_ptr MediaSession::getParams () const { + L_D(const MediaSession); + return d->params; +} + +float MediaSession::getPlayVolume () const { + L_D(const MediaSession); + if (d->audioStream && d->audioStream->volrecv) { + float vol = 0; + ms_filter_call_method(d->audioStream->volrecv, MS_VOLUME_GET, &vol); + return vol; + } + return LINPHONE_VOLUME_DB_LOWEST; +} + +float MediaSession::getRecordVolume () const { + L_D(const MediaSession); + if (d->audioStream && d->audioStream->volsend && !d->audioMuted && (d->state == LinphoneCallStreamsRunning)) { + float vol = 0; + ms_filter_call_method(d->audioStream->volsend, MS_VOLUME_GET, &vol); + return vol; + } + return LINPHONE_VOLUME_DB_LOWEST; +} + +const shared_ptr MediaSession::getRemoteParams () { + L_D(MediaSession); + if (d->op){ + SalMediaDescription *md = sal_call_get_remote_media_description(d->op); + if (md) { + d->remoteParams = make_shared(); + unsigned int nbAudioStreams = sal_media_description_nb_active_streams_of_type(md, SalAudio); + for (unsigned int i = 0; i < nbAudioStreams; i++) { + SalStreamDescription *sd = sal_media_description_get_active_stream_of_type(md, SalAudio, i); + if (sal_stream_description_has_srtp(sd)) + d->remoteParams->setMediaEncryption(LinphoneMediaEncryptionSRTP); + } + unsigned int nbVideoStreams = sal_media_description_nb_active_streams_of_type(md, SalVideo); + for (unsigned int i = 0; i < nbVideoStreams; i++) { + SalStreamDescription *sd = sal_media_description_get_active_stream_of_type(md, SalVideo, i); + if (sal_stream_description_active(sd)) + d->remoteParams->enableVideo(true); + if (sal_stream_description_has_srtp(sd)) + d->remoteParams->setMediaEncryption(LinphoneMediaEncryptionSRTP); + } + unsigned int nbTextStreams = sal_media_description_nb_active_streams_of_type(md, SalText); + for (unsigned int i = 0; i < nbTextStreams; i++) { + SalStreamDescription *sd = sal_media_description_get_active_stream_of_type(md, SalText, i); + if (sal_stream_description_has_srtp(sd)) + d->remoteParams->setMediaEncryption(LinphoneMediaEncryptionSRTP); + d->remoteParams->enableRealtimeText(true); + } + if (!d->remoteParams->videoEnabled()) { + if ((md->bandwidth > 0) && (md->bandwidth <= linphone_core_get_edge_bw(d->core))) + d->remoteParams->enableLowBandwidth(true); + } + if (md->name[0] != '\0') + d->remoteParams->setSessionName(md->name); + + d->remoteParams->getPrivate()->setCustomSdpAttributes(md->custom_sdp_attributes); + d->remoteParams->getPrivate()->setCustomSdpMediaAttributes(LinphoneStreamTypeAudio, md->streams[d->mainAudioStreamIndex].custom_sdp_attributes); + d->remoteParams->getPrivate()->setCustomSdpMediaAttributes(LinphoneStreamTypeVideo, md->streams[d->mainVideoStreamIndex].custom_sdp_attributes); + d->remoteParams->getPrivate()->setCustomSdpMediaAttributes(LinphoneStreamTypeText, md->streams[d->mainTextStreamIndex].custom_sdp_attributes); + } + const SalCustomHeader *ch = sal_op_get_recv_custom_header(d->op); + if (ch) { + /* Instanciate a remote_params only if a SIP message was received before (custom headers indicates this) */ + if (!d->remoteParams) + d->remoteParams = make_shared(); + d->remoteParams->getPrivate()->setCustomHeaders(ch); + } + return d->remoteParams; + } + return nullptr; +} + +float MediaSession::getSpeakerVolumeGain () const { + L_D(const MediaSession); + if (d->audioStream) + return audio_stream_get_sound_card_output_gain(d->audioStream); + else { + lError() << "Could not get playback volume: no audio stream"; + return -1.0f; + } +} + +LinphoneCallStats * MediaSession::getStats (LinphoneStreamType type) const { + L_D(const MediaSession); + if (type == LinphoneStreamTypeUnknown) + return nullptr; + LinphoneCallStats *stats = nullptr; + LinphoneCallStats *statsCopy = linphone_call_stats_new(); + if (type == LinphoneStreamTypeAudio) + stats = d->audioStats; + else if (type == LinphoneStreamTypeVideo) + stats = d->videoStats; + else if (type == LinphoneStreamTypeText) + stats = d->textStats; + MediaStream *ms = d->getMediaStream(type); + if (ms && stats) + linphone_call_stats_update(stats, ms); + _linphone_call_stats_clone(statsCopy, stats); + return statsCopy; +} + +int MediaSession::getStreamCount () { + /* TODO: Revisit when multiple media streams will be implemented */ +#ifdef VIDEO_ENABLED + if (getCurrentParams()->realtimeTextEnabled()) + return 3; + return 2; +#else + if (getCurrentParams()->realtimeTextEnabled()) + return 2; + return 1; +#endif +} + +MSFormatType MediaSession::getStreamType (int streamIndex) const { + L_D(const MediaSession); + /* TODO: Revisit when multiple media streams will be implemented */ + if (streamIndex == d->mainVideoStreamIndex) + return MSVideo; + else if (streamIndex == d->mainTextStreamIndex) + return MSText; + else if (streamIndex == d->mainAudioStreamIndex) + return MSAudio; + return MSUnknownMedia; +} + +LinphoneCallStats * MediaSession::getTextStats () const { + return getStats(LinphoneStreamTypeText); +} + +LinphoneCallStats * MediaSession::getVideoStats () const { + return getStats(LinphoneStreamTypeVideo); +} + +bool MediaSession::mediaInProgress () const { + L_D(const MediaSession); + if ((d->audioStats->ice_state == LinphoneIceStateInProgress) + || (d->videoStats->ice_state == LinphoneIceStateInProgress) + || (d->textStats->ice_state == LinphoneIceStateInProgress)) + return true; + /* TODO: could check zrtp state */ + return false; +} + +void MediaSession::setAuthenticationTokenVerified (bool value) { + L_D(MediaSession); + if (!d->audioStream || !media_stream_started(&d->audioStream->ms)) { + lError() << "MediaSession::setAuthenticationTokenVerified(): No audio stream or not started"; + return; + } + if (!d->audioStream->ms.sessions.zrtp_context) { + lError() << "MediaSession::setAuthenticationTokenVerified(): No zrtp context"; + return; + } + if (!d->authTokenVerified && value) + ms_zrtp_sas_verified(d->audioStream->ms.sessions.zrtp_context); + else if (d->authTokenVerified && !value) + ms_zrtp_sas_reset_verified(d->audioStream->ms.sessions.zrtp_context); + d->authTokenVerified = value; + d->propagateEncryptionChanged(); +} + +void MediaSession::setMicrophoneVolumeGain (float value) { + L_D(MediaSession); + if(d->audioStream) + audio_stream_set_sound_card_input_gain(d->audioStream, value); + else + lError() << "Could not set record volume: no audio stream"; +} + +void MediaSession::setNativeVideoWindowId (void *id) { + L_D(MediaSession); + d->videoWindowId = id; +#ifdef VIDEO_ENABLED + if (d->videoStream) + video_stream_set_native_window_id(d->videoStream, id); +#endif +} + +void MediaSession::setSpeakerVolumeGain (float value) { + L_D(MediaSession); + if (d->audioStream) + audio_stream_set_sound_card_output_gain(d->audioStream, value); + else + lError() << "Could not set playback volume: no audio stream"; +} LINPHONE_END_NAMESPACE diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index 898ad283b..10ee36e5e 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -19,17 +19,78 @@ #ifndef _MEDIA_SESSION_H_ #define _MEDIA_SESSION_H_ +#include + #include "call-session.h" +#include "conference/params/media-session-params.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE +class CallPrivate; +class IceAgent; class MediaSessionPrivate; class MediaSession : public CallSession { + friend class CallPrivate; + friend class IceAgent; + public: - MediaSession (); + MediaSession (const Conference &conference, const std::shared_ptr params, CallSessionListener *listener); + + LinphoneStatus accept (const std::shared_ptr msp = nullptr); + LinphoneStatus acceptEarlyMedia (const std::shared_ptr msp = nullptr); + LinphoneStatus acceptUpdate (const std::shared_ptr msp); + void configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalOp *op, const Address &from, const Address &to); + void initiateIncoming (); + bool initiateOutgoing (); + void iterate (time_t currentRealTime, bool oneSecondElapsed); + void sendVfuRequest (); + void startIncomingNotification (); + int startInvite (const Address *destination); + void startRecording (); + void stopRecording (); + LinphoneStatus update (const std::shared_ptr msp); + + void resetFirstVideoFrameDecoded (); + LinphoneStatus takePreviewSnapshot (const std::string& file); + LinphoneStatus takeVideoSnapshot (const std::string& file); + void zoomVideo (float zoomFactor, float *cx, float *cy); + + bool cameraEnabled () const; + bool echoCancellationEnabled () const; + bool echoLimiterEnabled () const; + void enableCamera (bool value); + void enableEchoCancellation (bool value); + void enableEchoLimiter (bool value); + bool getAllMuted () const; + LinphoneCallStats * getAudioStats () const; + std::string getAuthenticationToken () const; + bool getAuthenticationTokenVerified () const; + float getAverageQuality () const; + std::shared_ptr getCurrentParams (); + float getCurrentQuality () const; + const std::shared_ptr getMediaParams () const; + RtpTransport * getMetaRtcpTransport (int streamIndex); + RtpTransport * getMetaRtpTransport (int streamIndex); + float getMicrophoneVolumeGain () const; + void * getNativeVideoWindowId () const; + const std::shared_ptr getParams () const; + float getPlayVolume () const; + float getRecordVolume () const; + const std::shared_ptr getRemoteParams (); + float getSpeakerVolumeGain () const; + LinphoneCallStats * getStats (LinphoneStreamType type) const; + int getStreamCount (); + MSFormatType getStreamType (int streamIndex) const; + LinphoneCallStats * getTextStats () const; + LinphoneCallStats * getVideoStats () const; + bool mediaInProgress () const; + void setAuthenticationTokenVerified (bool value); + void setMicrophoneVolumeGain (float value); + void setNativeVideoWindowId (void *id); + void setSpeakerVolumeGain (float value); private: L_DECLARE_PRIVATE(MediaSession); diff --git a/src/conference/session/port-config.h b/src/conference/session/port-config.h new file mode 100644 index 000000000..c4fdf6649 --- /dev/null +++ b/src/conference/session/port-config.h @@ -0,0 +1,37 @@ +/* + * port-config.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _PORT_CONFIG_H_ +#define _PORT_CONFIG_H_ + +#include + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +struct PortConfig { + std::string multicastIp; + std::string multicastBindIp; + int rtpPort = -1; + int rtcpPort = -1; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _PORT_CONFIG_H_ diff --git a/src/nat/ice-agent.cpp b/src/nat/ice-agent.cpp new file mode 100644 index 000000000..a3568719b --- /dev/null +++ b/src/nat/ice-agent.cpp @@ -0,0 +1,689 @@ +/* + * ice-agent.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "ice-agent.h" +#include "conference/session/media-session-p.h" + +#include "logger/logger.h" + +#include "linphone/core.h" + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +// ============================================================================= + +bool IceAgent::candidatesGathered () const { + if (!iceSession) + return false; + return ice_session_candidates_gathered(iceSession); +} + +void IceAgent::checkSession (IceRole role, bool isReinvite) { + if (iceSession) + return; /* Already created */ + LinphoneConfig *config = linphone_core_get_config(mediaSession.getPrivate()->getCore()); + if (isReinvite && (lp_config_get_int(config, "net", "allow_late_ice", 0) == 0)) + return; + iceSession = ice_session_new(); + /* For backward compatibility purposes, shall be enabled by default in the future */ + ice_session_enable_message_integrity_check(iceSession, lp_config_get_int(config, "net", "ice_session_enable_message_integrity_check", 1)); + if (lp_config_get_int(config, "net", "dont_default_to_stun_candidates", 0)) { + IceCandidateType types[ICT_CandidateTypeMax]; + types[0] = ICT_HostCandidate; + types[1] = ICT_RelayedCandidate; + types[2] = ICT_CandidateInvalid; + ice_session_set_default_candidates_types(iceSession, types); + } + ice_session_set_role(iceSession, role); +} + +void IceAgent::deleteSession () { + if (!iceSession) + return; + ice_session_destroy(iceSession); + iceSession = nullptr; + mediaSession.getPrivate()->deactivateIce(); +} + +void IceAgent::gatheringFinished () { + const SalMediaDescription *rmd = sal_call_get_remote_media_description(mediaSession.getPrivate()->getOp()); + if (rmd) + clearUnusedIceCandidates(mediaSession.getPrivate()->getLocalDesc(), rmd); + if (!iceSession) + return; + ice_session_compute_candidates_foundations(iceSession); + ice_session_eliminate_redundant_candidates(iceSession); + ice_session_choose_default_candidates(iceSession); + int pingTime = ice_session_average_gathering_round_trip_time(iceSession); + if (pingTime >=0) { + mediaSession.getPrivate()->setPingTime(pingTime); + } +} + +int IceAgent::getNbLosingPairs () const { + if (!iceSession) + return 0; + return ice_session_nb_losing_pairs(iceSession); +} + +bool IceAgent::hasCompleted () const { + if (!iceSession) + return false; + return (ice_session_state(iceSession) == IS_Completed); +} + +bool IceAgent::hasCompletedCheckList () const { + if (!iceSession) + return false; + switch (ice_session_state(iceSession)) { + case IS_Completed: + case IS_Failed: + return ice_session_has_completed_check_list(iceSession); + default: + return false; + } +} + +bool IceAgent::isControlling () const { + if (!iceSession) + return false; + return (ice_session_role(iceSession) == IR_Controlling); +} + +bool IceAgent::prepare (const SalMediaDescription *localDesc, bool incomingOffer) { + if (!iceSession) + return false; + + SalMediaDescription *remoteDesc = nullptr; + bool hasVideo = false; + if (incomingOffer) { + remoteDesc = sal_call_get_remote_media_description(mediaSession.getPrivate()->getOp()); + hasVideo = linphone_core_video_enabled(mediaSession.getPrivate()->getCore()) && linphone_core_media_description_contains_video_stream(remoteDesc); + } else + hasVideo = mediaSession.getMediaParams()->videoEnabled(); + + prepareIceForStream(mediaSession.getPrivate()->getMediaStream(LinphoneStreamTypeAudio), true); + if (hasVideo) + prepareIceForStream(mediaSession.getPrivate()->getMediaStream(LinphoneStreamTypeVideo), true); + if (mediaSession.getMediaParams()->realtimeTextEnabled()) + prepareIceForStream(mediaSession.getPrivate()->getMediaStream(LinphoneStreamTypeText), true); + /* Start ICE gathering */ + if (incomingOffer) + updateFromRemoteMediaDescription(localDesc, remoteDesc, true); /* This may delete the ice session */ + if (iceSession && !ice_session_candidates_gathered(iceSession)) { + mediaSession.getPrivate()->prepareStreamsForIceGathering(hasVideo); + int err = gatherIceCandidates(); + if (err == 0) { + /* Ice candidates gathering wasn't started, but we can proceed with the call anyway. */ + mediaSession.getPrivate()->stopStreamsForIceGathering(); + return false; + } else if (err == -1) { + mediaSession.getPrivate()->stopStreamsForIceGathering(); + deleteSession(); + return false; + } + return true; + } + return false; +} + +void IceAgent::prepareIceForStream (MediaStream *ms, bool createChecklist) { + if (!iceSession) + return; + int streamIndex = mediaSession.getPrivate()->getStreamIndex(ms); + rtp_session_set_pktinfo(ms->sessions.rtp_session, true); + IceCheckList *cl = ice_session_check_list(iceSession, streamIndex); + if (!cl && createChecklist) { + cl = ice_check_list_new(); + ice_session_add_check_list(iceSession, cl, streamIndex); + lInfo() << "Created new ICE check list for stream [" << streamIndex << "]"; + } + if (cl) + media_stream_set_ice_check_list(ms, cl); +} + +void IceAgent::restartSession (IceRole role) { + if (!iceSession) + return; + ice_session_restart(iceSession, role); +} + +void IceAgent::startConnectivityChecks () { + if (!iceSession) + return; + ice_session_start_connectivity_checks(iceSession); +} + +void IceAgent::stopIceForInactiveStreams (SalMediaDescription *desc) { + if (!iceSession) + return; + if (ice_session_state(iceSession) == IS_Completed) + return; + for (int i = 0; i < desc->nb_streams; i++) { + IceCheckList *cl = ice_session_check_list(iceSession, i); + if (!sal_stream_description_active(&desc->streams[i]) && cl) { + ice_session_remove_check_list(iceSession, cl); + mediaSession.getPrivate()->clearIceCheckList(cl); + } + } + updateIceStateInCallStats(); +} + +void IceAgent::updateFromRemoteMediaDescription (const SalMediaDescription *localDesc, const SalMediaDescription *remoteDesc, bool isOffer) { + if (!iceSession) + return; + if (!iceParamsFoundInRemoteMediaDescription(remoteDesc)) { + /* Response from remote does not contain mandatory ICE attributes, delete the session */ + deleteSession(); + mediaSession.getPrivate()->enableSymmetricRtp(linphone_core_symmetric_rtp_enabled(mediaSession.getPrivate()->getCore())); + return; + } + + /* Check for ICE restart and set remote credentials */ + bool iceRestarted = checkForIceRestartAndSetRemoteCredentials(remoteDesc, isOffer); + + /* Create ICE check lists if needed and parse ICE attributes */ + createIceCheckListsAndParseIceAttributes(remoteDesc, iceRestarted); + for (int i = 0; i < remoteDesc->nb_streams; i++) { + const SalStreamDescription *stream = &remoteDesc->streams[i]; + IceCheckList *cl = ice_session_check_list(iceSession, i); + if (!cl) continue; + if (!sal_stream_description_active(stream)) { + ice_session_remove_check_list_from_idx(iceSession, i); + mediaSession.getPrivate()->clearIceCheckList(cl); + } + } + clearUnusedIceCandidates(localDesc, remoteDesc); + ice_session_check_mismatch(iceSession); + + if (ice_session_nb_check_lists(iceSession) == 0) { + deleteSession(); + mediaSession.getPrivate()->enableSymmetricRtp(linphone_core_symmetric_rtp_enabled(mediaSession.getPrivate()->getCore())); + } +} + +void IceAgent::updateIceStateInCallStats () { + if (!iceSession) + return; + IceCheckList *audioCheckList = ice_session_check_list(iceSession, mediaSession.getPrivate()->getStreamIndex(LinphoneStreamTypeAudio)); + IceCheckList *videoCheckList = ice_session_check_list(iceSession, mediaSession.getPrivate()->getStreamIndex(LinphoneStreamTypeVideo)); + IceCheckList *textCheckList = ice_session_check_list(iceSession, mediaSession.getPrivate()->getStreamIndex(LinphoneStreamTypeText)); + if (!audioCheckList && !videoCheckList && !textCheckList) + return; + + LinphoneCallStats *audioStats = mediaSession.getPrivate()->getStats(LinphoneStreamTypeAudio); + LinphoneCallStats *videoStats = mediaSession.getPrivate()->getStats(LinphoneStreamTypeVideo); + LinphoneCallStats *textStats = mediaSession.getPrivate()->getStats(LinphoneStreamTypeText); + IceSessionState sessionState = ice_session_state(iceSession); + if ((sessionState == IS_Completed) || ((sessionState == IS_Failed) && ice_session_has_completed_check_list(iceSession))) { + audioStats->ice_state = LinphoneIceStateNotActivated; + if (audioCheckList && mediaSession.getMediaParams()->audioEnabled()) + updateIceStateInCallStatsForStream(audioStats, audioCheckList); + + videoStats->ice_state = LinphoneIceStateNotActivated; + if (videoCheckList && mediaSession.getMediaParams()->videoEnabled()) + updateIceStateInCallStatsForStream(videoStats, videoCheckList); + + textStats->ice_state = LinphoneIceStateNotActivated; + if (textCheckList && mediaSession.getMediaParams()->realtimeTextEnabled()) + updateIceStateInCallStatsForStream(textStats, textCheckList); + } else if (sessionState == IS_Running) { + if (audioCheckList && mediaSession.getMediaParams()->audioEnabled()) + audioStats->ice_state = LinphoneIceStateInProgress; + if (videoCheckList && mediaSession.getMediaParams()->videoEnabled()) + videoStats->ice_state = LinphoneIceStateInProgress; + if (textCheckList && mediaSession.getMediaParams()->realtimeTextEnabled()) + textStats->ice_state = LinphoneIceStateInProgress; + } else { + if (audioCheckList && mediaSession.getMediaParams()->audioEnabled()) + audioStats->ice_state = LinphoneIceStateFailed; + if (videoCheckList && mediaSession.getMediaParams()->videoEnabled()) + videoStats->ice_state = LinphoneIceStateFailed; + if (textCheckList && mediaSession.getMediaParams()->realtimeTextEnabled()) + textStats->ice_state = LinphoneIceStateFailed; + } + lInfo() << "CallSession [" << &mediaSession << "] New ICE state: audio: [" << linphone_ice_state_to_string(audioStats->ice_state) + << "] video: [" << linphone_ice_state_to_string(videoStats->ice_state) + << "] text: [" << linphone_ice_state_to_string(textStats->ice_state) << "]"; +} + +void IceAgent::updateLocalMediaDescriptionFromIce (SalMediaDescription *desc) { + if (!iceSession) + return; + IceCandidate *rtpCandidate = nullptr; + IceCandidate *rtcpCandidate = nullptr; + bool result = false; + IceSessionState sessionState = ice_session_state(iceSession); + if (sessionState == IS_Completed) { + IceCheckList *firstCl = nullptr; + for (int i = 0; i < desc->nb_streams; i++) { + IceCheckList *cl = ice_session_check_list(iceSession, i); + if (cl) { + firstCl = cl; + break; + } + } + if (firstCl) + result = ice_check_list_selected_valid_local_candidate(firstCl, &rtpCandidate, nullptr); + if (result) + strncpy(desc->addr, rtpCandidate->taddr.ip, sizeof(desc->addr)); + else + lWarning() << "If ICE has completed successfully, rtp_candidate should be set!"; + } + + strncpy(desc->ice_pwd, ice_session_local_pwd(iceSession), sizeof(desc->ice_pwd)); + strncpy(desc->ice_ufrag, ice_session_local_ufrag(iceSession), sizeof(desc->ice_ufrag)); + for (int i = 0; i < desc->nb_streams; i++) { + SalStreamDescription *stream = &desc->streams[i]; + IceCheckList *cl = ice_session_check_list(iceSession, i); + rtpCandidate = rtcpCandidate = nullptr; + if (!sal_stream_description_active(stream) || !cl) + continue; + if (ice_check_list_state(cl) == ICL_Completed) { + /* Set this to false once flexisip are updated everywhere, let's say in December 2016 */ + LinphoneConfig *config = linphone_core_get_config(mediaSession.getPrivate()->getCore()); + bool useNoRtpProxy = lp_config_get_int(config, "sip", "ice_uses_nortpproxy", true); + if (useNoRtpProxy) + stream->set_nortpproxy = true; + result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(iceSession, i), &rtpCandidate, &rtcpCandidate); + } else { + stream->set_nortpproxy = false; + result = ice_check_list_default_local_candidate(ice_session_check_list(iceSession, i), &rtpCandidate, &rtcpCandidate); + } + if (result) { + strncpy(stream->rtp_addr, rtpCandidate->taddr.ip, sizeof(stream->rtp_addr)); + strncpy(stream->rtcp_addr, rtcpCandidate->taddr.ip, sizeof(stream->rtcp_addr)); + stream->rtp_port = rtpCandidate->taddr.port; + stream->rtcp_port = rtcpCandidate->taddr.port; + } else { + memset(stream->rtp_addr, 0, sizeof(stream->rtp_addr)); + memset(stream->rtcp_addr, 0, sizeof(stream->rtcp_addr)); + } + if ((strlen(ice_check_list_local_pwd(cl)) != strlen(desc->ice_pwd)) || (strcmp(ice_check_list_local_pwd(cl), desc->ice_pwd))) + strncpy(stream->ice_pwd, ice_check_list_local_pwd(cl), sizeof(stream->ice_pwd)); + else + memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd)); + if ((strlen(ice_check_list_local_ufrag(cl)) != strlen(desc->ice_ufrag)) || (strcmp(ice_check_list_local_ufrag(cl), desc->ice_ufrag))) + strncpy(stream->ice_ufrag, ice_check_list_local_ufrag(cl), sizeof(stream->ice_ufrag)); + else + memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd)); + stream->ice_mismatch = ice_check_list_is_mismatch(cl); + if ((ice_check_list_state(cl) == ICL_Running) || (ice_check_list_state(cl) == ICL_Completed)) { + memset(stream->ice_candidates, 0, sizeof(stream->ice_candidates)); + int nbCandidates = 0; + for (int j = 0; j < MIN((int)bctbx_list_size(cl->local_candidates), SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES); j++) { + SalIceCandidate *salCandidate = &stream->ice_candidates[nbCandidates]; + IceCandidate *iceCandidate = reinterpret_cast(bctbx_list_nth_data(cl->local_candidates, j)); + const char *defaultAddr = nullptr; + int defaultPort = 0; + if (iceCandidate->componentID == 1) { + defaultAddr = stream->rtp_addr; + defaultPort = stream->rtp_port; + } else if (iceCandidate->componentID == 2) { + defaultAddr = stream->rtcp_addr; + defaultPort = stream->rtcp_port; + } else + continue; + if (defaultAddr[0] == '\0') + defaultAddr = desc->addr; + /* Only include the candidates matching the default destination for each component of the stream if the state is Completed as specified in RFC5245 section 9.1.2.2. */ + if ((ice_check_list_state(cl) == ICL_Completed) + && !((iceCandidate->taddr.port == defaultPort) && (strlen(iceCandidate->taddr.ip) == strlen(defaultAddr)) && (strcmp(iceCandidate->taddr.ip, defaultAddr) == 0))) + continue; + strncpy(salCandidate->foundation, iceCandidate->foundation, sizeof(salCandidate->foundation)); + salCandidate->componentID = iceCandidate->componentID; + salCandidate->priority = iceCandidate->priority; + strncpy(salCandidate->type, ice_candidate_type(iceCandidate), sizeof(salCandidate->type)); + strncpy(salCandidate->addr, iceCandidate->taddr.ip, sizeof(salCandidate->addr)); + salCandidate->port = iceCandidate->taddr.port; + if (iceCandidate->base && (iceCandidate->base != iceCandidate)) { + strncpy(salCandidate->raddr, iceCandidate->base->taddr.ip, sizeof(salCandidate->raddr)); + salCandidate->rport = iceCandidate->base->taddr.port; + } + nbCandidates++; + } + } + if ((ice_check_list_state(cl) == ICL_Completed) && (ice_session_role(iceSession) == IR_Controlling)) { + memset(stream->ice_remote_candidates, 0, sizeof(stream->ice_remote_candidates)); + if (ice_check_list_selected_valid_remote_candidate(cl, &rtpCandidate, &rtcpCandidate)) { + strncpy(stream->ice_remote_candidates[0].addr, rtpCandidate->taddr.ip, sizeof(stream->ice_remote_candidates[0].addr)); + stream->ice_remote_candidates[0].port = rtpCandidate->taddr.port; + strncpy(stream->ice_remote_candidates[1].addr, rtcpCandidate->taddr.ip, sizeof(stream->ice_remote_candidates[1].addr)); + stream->ice_remote_candidates[1].port = rtcpCandidate->taddr.port; + } else + lError() << "ice: Selected valid remote candidates should be present if the check list is in the Completed state"; + } else { + for (int j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) { + stream->ice_remote_candidates[j].addr[0] = '\0'; + stream->ice_remote_candidates[j].port = 0; + } + } + } +} + +// ----------------------------------------------------------------------------- + +void IceAgent::addLocalIceCandidates (int family, const char *addr, IceCheckList *audioCl, IceCheckList *videoCl, IceCheckList *textCl) { + if ((ice_check_list_state(audioCl) != ICL_Completed) && !ice_check_list_candidates_gathered(audioCl)) { + int rtpPort = mediaSession.getPrivate()->getRtpPort(LinphoneStreamTypeAudio); + int rtcpPort = mediaSession.getPrivate()->getRtcpPort(LinphoneStreamTypeAudio); + ice_add_local_candidate(audioCl, "host", family, addr, rtpPort, 1, nullptr); + ice_add_local_candidate(audioCl, "host", family, addr, rtcpPort, 2, nullptr); + LinphoneCallStats *audioStats = mediaSession.getPrivate()->getStats(LinphoneStreamTypeAudio); + audioStats->ice_state = LinphoneIceStateInProgress; + } + LinphoneCore *core = mediaSession.getPrivate()->getCore(); + if (linphone_core_video_enabled(core) && videoCl && (ice_check_list_state(videoCl) != ICL_Completed) && !ice_check_list_candidates_gathered(videoCl)) { + int rtpPort = mediaSession.getPrivate()->getRtpPort(LinphoneStreamTypeVideo); + int rtcpPort = mediaSession.getPrivate()->getRtcpPort(LinphoneStreamTypeVideo); + ice_add_local_candidate(videoCl, "host", family, addr, rtpPort, 1, nullptr); + ice_add_local_candidate(videoCl, "host", family, addr, rtcpPort, 2, nullptr); + LinphoneCallStats *videoStats = mediaSession.getPrivate()->getStats(LinphoneStreamTypeVideo); + videoStats->ice_state = LinphoneIceStateInProgress; + } + if (mediaSession.getMediaParams()->realtimeTextEnabled() && textCl && (ice_check_list_state(textCl) != ICL_Completed) && !ice_check_list_candidates_gathered(textCl)) { + int rtpPort = mediaSession.getPrivate()->getRtpPort(LinphoneStreamTypeText); + int rtcpPort = mediaSession.getPrivate()->getRtcpPort(LinphoneStreamTypeText); + ice_add_local_candidate(textCl, "host", family, addr, rtpPort, 1, nullptr); + ice_add_local_candidate(textCl, "host", family, addr, rtcpPort, 2, nullptr); + LinphoneCallStats *textStats = mediaSession.getPrivate()->getStats(LinphoneStreamTypeText); + textStats->ice_state = LinphoneIceStateInProgress; + } +} + +bool IceAgent::checkForIceRestartAndSetRemoteCredentials (const SalMediaDescription *md, bool isOffer) { + bool iceRestarted = false; + string addr = md->addr; + if ((addr == "0.0.0.0") || (addr == "::0")) { + ice_session_restart(iceSession, isOffer ? IR_Controlled : IR_Controlling); + iceRestarted = true; + } else { + for (int i = 0; i < md->nb_streams; i++) { + const SalStreamDescription *stream = &md->streams[i]; + IceCheckList *cl = ice_session_check_list(iceSession, i); + string rtpAddr = stream->rtp_addr; + if (cl && (rtpAddr == "0.0.0.0")) { + ice_session_restart(iceSession, isOffer ? IR_Controlled : IR_Controlling); + iceRestarted = true; + break; + } + } + } + if (!ice_session_remote_ufrag(iceSession) && !ice_session_remote_pwd(iceSession)) { + ice_session_set_remote_credentials(iceSession, md->ice_ufrag, md->ice_pwd); + } else if (ice_session_remote_credentials_changed(iceSession, md->ice_ufrag, md->ice_pwd)) { + if (!iceRestarted) { + ice_session_restart(iceSession, isOffer ? IR_Controlled : IR_Controlling); + iceRestarted = true; + } + ice_session_set_remote_credentials(iceSession, md->ice_ufrag, md->ice_pwd); + } + for (int i = 0; i < md->nb_streams; i++) { + const SalStreamDescription *stream = &md->streams[i]; + IceCheckList *cl = ice_session_check_list(iceSession, i); + if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) { + if (ice_check_list_remote_credentials_changed(cl, stream->ice_ufrag, stream->ice_pwd)) { + if (!iceRestarted && ice_check_list_get_remote_ufrag(cl) && ice_check_list_get_remote_pwd(cl)) { + /* Restart only if remote ufrag/paswd was already set */ + ice_session_restart(iceSession, isOffer ? IR_Controlled : IR_Controlling); + iceRestarted = true; + } + ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd); + break; + } + } + } + return iceRestarted; +} + +void IceAgent::clearUnusedIceCandidates (const SalMediaDescription *localDesc, const SalMediaDescription *remoteDesc) { + if (!localDesc) + return; + for (int i = 0; i < remoteDesc->nb_streams; i++) { + const SalStreamDescription *localStream = &localDesc->streams[i]; + const SalStreamDescription *stream = &remoteDesc->streams[i]; + IceCheckList *cl = ice_session_check_list(iceSession, i); + if (!cl || !localStream) + continue; + if (stream->rtcp_mux && localStream->rtcp_mux) { + ice_check_list_remove_rtcp_candidates(cl); + } + } +} + +void IceAgent::createIceCheckListsAndParseIceAttributes (const SalMediaDescription *md, bool iceRestarted) { + for (int i = 0; i < md->nb_streams; i++) { + const SalStreamDescription *stream = &md->streams[i]; + IceCheckList *cl = ice_session_check_list(iceSession, i); + if (!cl) + continue; + if (stream->ice_mismatch) { + ice_check_list_set_state(cl, ICL_Failed); + continue; + } + if (stream->rtp_port == 0) { + ice_session_remove_check_list(iceSession, cl); + mediaSession.getPrivate()->clearIceCheckList(cl); + continue; + } + if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) + ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd); + for (int j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) { + bool defaultCandidate = false; + const SalIceCandidate *candidate = &stream->ice_candidates[j]; + if (candidate->addr[0] == '\0') + break; + if ((candidate->componentID == 0) || (candidate->componentID > 2)) + continue; + const char *addr = nullptr; + int port = 0; + getIceDefaultAddrAndPort(candidate->componentID, md, stream, &addr, &port); + if (addr && (candidate->port == port) && (strlen(candidate->addr) == strlen(addr)) && (strcmp(candidate->addr, addr) == 0)) + defaultCandidate = true; + int family = AF_INET; + if (strchr(candidate->addr, ':')) + family = AF_INET6; + ice_add_remote_candidate(cl, candidate->type, family, candidate->addr, candidate->port, candidate->componentID, + candidate->priority, candidate->foundation, defaultCandidate); + } + if (!iceRestarted) { + bool_t losingPairsAdded = false; + for (int j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) { + const SalIceRemoteCandidate *remoteCandidate = &stream->ice_remote_candidates[j]; + const char *addr = nullptr; + int port = 0; + int componentID = j + 1; + if (remoteCandidate->addr[0] == '\0') break; + getIceDefaultAddrAndPort(componentID, md, stream, &addr, &port); + if (j == 0) /* If we receive a re-invite and we finished ICE processing on our side, use the candidates given by the remote. */ + ice_check_list_unselect_valid_pairs(cl); + int remoteFamily = AF_INET; + if (strchr(remoteCandidate->addr, ':')) + remoteFamily = AF_INET6; + int family = AF_INET; + if (strchr(addr, ':')) + family = AF_INET6; + ice_add_losing_pair(cl, j + 1, remoteFamily, remoteCandidate->addr, remoteCandidate->port, family, addr, port); + losingPairsAdded = true; + } + if (losingPairsAdded) + ice_check_list_check_completed(cl); + } + } +} + +/** Return values: + * 1: STUN gathering is started + * 0: no STUN gathering is started, but it's ok to proceed with ICE anyway (with local candidates only or because STUN gathering was already done before) + * -1: no gathering started and something went wrong with local candidates. There is no way to start the ICE session. + */ +int IceAgent::gatherIceCandidates () { + if (!iceSession) + return -1; + IceCheckList *audioCl = ice_session_check_list(iceSession, mediaSession.getPrivate()->getStreamIndex(LinphoneStreamTypeAudio)); + IceCheckList *videoCl = ice_session_check_list(iceSession, mediaSession.getPrivate()->getStreamIndex(LinphoneStreamTypeVideo)); + IceCheckList *textCl = ice_session_check_list(iceSession, mediaSession.getPrivate()->getStreamIndex(LinphoneStreamTypeText)); + if (!audioCl && !videoCl && !textCl) + return -1; + + const struct addrinfo *ai = nullptr; + LinphoneNatPolicy *natPolicy = mediaSession.getPrivate()->getNatPolicy(); + if (natPolicy && linphone_nat_policy_stun_server_activated(natPolicy)) { + ai = linphone_nat_policy_get_stun_server_addrinfo(natPolicy); + if (ai) + ai = getIcePreferredStunServerAddrinfo(ai); + else + lWarning() << "Failed to resolve STUN server for ICE gathering, continuing without STUN"; + } else + lWarning() << "ICE is used without STUN server"; + LinphoneCore *core = mediaSession.getPrivate()->getCore(); + linphone_core_notify_display_status(core, _("ICE local candidates gathering in progress...")); + ice_session_enable_forced_relay(iceSession, core->forced_ice_relay); + ice_session_enable_short_turn_refresh(iceSession, core->short_turn_refresh); + + /* Gather local host candidates. */ + char localAddr[64]; + if (mediaSession.getPrivate()->getAf() == AF_INET6) { + if (linphone_core_get_local_ip_for(AF_INET6, nullptr, localAddr) < 0) { + lError() << "Fail to get local IPv6"; + return -1; + } else + addLocalIceCandidates(AF_INET6, localAddr, audioCl, videoCl, textCl); + } + if (linphone_core_get_local_ip_for(AF_INET, nullptr, localAddr) < 0) { + if (mediaSession.getPrivate()->getAf() != AF_INET6) { + lError() << "Fail to get local IPv4"; + return -1; + } + } else + addLocalIceCandidates(AF_INET, localAddr, audioCl, videoCl, textCl); + if (ai && natPolicy && linphone_nat_policy_stun_server_activated(natPolicy)) { + string server = linphone_nat_policy_get_stun_server(natPolicy); + lInfo() << "ICE: gathering candidates from [" << server << "] using " << (linphone_nat_policy_turn_enabled(natPolicy) ? "TURN" : "STUN"); + /* Gather local srflx candidates */ + ice_session_enable_turn(iceSession, linphone_nat_policy_turn_enabled(natPolicy)); + ice_session_set_stun_auth_requested_cb(iceSession, MediaSessionPrivate::stunAuthRequestedCb, &mediaSession); + return ice_session_gather_candidates(iceSession, ai->ai_addr, (socklen_t)ai->ai_addrlen) ? 1 : 0; + } else { + lInfo() << "ICE: bypass candidates gathering"; + ice_session_compute_candidates_foundations(iceSession); + ice_session_eliminate_redundant_candidates(iceSession); + ice_session_choose_default_candidates(iceSession); + } + return 0; +} + +void IceAgent::getIceDefaultAddrAndPort (uint16_t componentID, const SalMediaDescription *md, const SalStreamDescription *stream, const char **addr, int *port) { + if (componentID == 1) { + *addr = stream->rtp_addr; + *port = stream->rtp_port; + } else if (componentID == 2) { + *addr = stream->rtcp_addr; + *port = stream->rtcp_port; + } else + return; + if ((*addr)[0] == '\0') *addr = md->addr; +} + +/** + * Choose the preferred IP address to use to contact the STUN server from the list of IP addresses + * the DNS resolution returned. If a NAT64 address is present, use it, otherwise if an IPv4 address + * is present, use it, otherwise use an IPv6 address if it is present. + */ +const struct addrinfo * IceAgent::getIcePreferredStunServerAddrinfo (const struct addrinfo *ai) { + /* Search for NAT64 addrinfo */ + const struct addrinfo *it = ai; + while (it) { + if (it->ai_family == AF_INET6) { + struct sockaddr_storage ss; + socklen_t sslen = sizeof(ss); + bctbx_sockaddr_remove_nat64_mapping(it->ai_addr, (struct sockaddr *)&ss, &sslen); + if (ss.ss_family == AF_INET) break; + } + it = it->ai_next; + } + const struct addrinfo *preferredAi = it; + if (!preferredAi) { + /* Search for IPv4 addrinfo */ + it = ai; + while (it) { + if (it->ai_family == AF_INET) + break; + if ((it->ai_family == AF_INET6) && (it->ai_flags & AI_V4MAPPED)) + break; + it = it->ai_next; + } + preferredAi = it; + } + if (!preferredAi) { + /* Search for IPv6 addrinfo */ + it = ai; + while (it) { + if (it->ai_family == AF_INET6) + break; + it = it->ai_next; + } + preferredAi = it; + } + return preferredAi; +} + +bool IceAgent::iceParamsFoundInRemoteMediaDescription (const SalMediaDescription *md) { + if ((md->ice_pwd[0] != '\0') && (md->ice_ufrag[0] != '\0')) + return true; + bool found = false; + for (int i = 0; i < md->nb_streams; i++) { + const SalStreamDescription *stream = &md->streams[i]; + IceCheckList *cl = ice_session_check_list(iceSession, i); + if (cl) { + if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) + found = true; + else { + found = false; + break; + } + } + } + return found; +} + +void IceAgent::updateIceStateInCallStatsForStream (LinphoneCallStats *stats, IceCheckList *cl) { + if (ice_check_list_state(cl) == ICL_Completed) { + switch (ice_check_list_selected_valid_candidate_type(cl)) { + case ICT_HostCandidate: + stats->ice_state = LinphoneIceStateHostConnection; + break; + case ICT_ServerReflexiveCandidate: + case ICT_PeerReflexiveCandidate: + stats->ice_state = LinphoneIceStateReflexiveConnection; + break; + case ICT_RelayedCandidate: + stats->ice_state = LinphoneIceStateRelayConnection; + break; + case ICT_CandidateInvalid: + case ICT_CandidateTypeMax: + /* Shall not happen */ + break; + } + } else + stats->ice_state = LinphoneIceStateFailed; +} + +LINPHONE_END_NAMESPACE diff --git a/src/nat/ice-agent.h b/src/nat/ice-agent.h new file mode 100644 index 000000000..0019ecd29 --- /dev/null +++ b/src/nat/ice-agent.h @@ -0,0 +1,76 @@ +/* + * ice-agent.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _ICE_AGENT_H_ +#define _ICE_AGENT_H_ + +#include +#include + +#include "linphone/types.h" +#include "linphone/utils/general.h" +#include "sal/sal.h" + +#include "conference/session/media-session.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class IceAgent { +public: + IceAgent (MediaSession &mediaSession) : mediaSession(mediaSession) {} + + bool candidatesGathered () const; + void checkSession (IceRole role, bool isReinvite); + void deleteSession (); + void gatheringFinished (); + int getNbLosingPairs () const; + IceSession * getIceSession () const { return iceSession; } + bool hasCompleted () const; + bool hasCompletedCheckList () const; + bool hasSession () const { return iceSession; } + bool isControlling () const; + bool prepare (const SalMediaDescription *localDesc, bool incomingOffer); + void prepareIceForStream (MediaStream *ms, bool createChecklist); + void restartSession (IceRole role); + void startConnectivityChecks (); + void stopIceForInactiveStreams (SalMediaDescription *desc); + void updateFromRemoteMediaDescription (const SalMediaDescription *localDesc, const SalMediaDescription *remoteDesc, bool isOffer); + void updateIceStateInCallStats (); + void updateLocalMediaDescriptionFromIce (SalMediaDescription *desc); + +private: + void addLocalIceCandidates (int family, const char *addr, IceCheckList *audioCl, IceCheckList *videoCl, IceCheckList *textCl); + bool checkForIceRestartAndSetRemoteCredentials (const SalMediaDescription *md, bool isOffer); + void clearUnusedIceCandidates (const SalMediaDescription *localDesc, const SalMediaDescription *remoteDesc); + void createIceCheckListsAndParseIceAttributes (const SalMediaDescription *md, bool iceRestarted); + int gatherIceCandidates (); + void getIceDefaultAddrAndPort (uint16_t componentID, const SalMediaDescription *md, const SalStreamDescription *stream, const char **addr, int *port); + const struct addrinfo * getIcePreferredStunServerAddrinfo (const struct addrinfo *ai); + bool iceParamsFoundInRemoteMediaDescription (const SalMediaDescription *md); + void updateIceStateInCallStatsForStream (LinphoneCallStats *stats, IceCheckList *cl); + +private: + MediaSession &mediaSession; + IceSession *iceSession = nullptr; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _ICE_AGENT_H_ diff --git a/src/nat/stun-client.cpp b/src/nat/stun-client.cpp new file mode 100644 index 000000000..3399488f9 --- /dev/null +++ b/src/nat/stun-client.cpp @@ -0,0 +1,253 @@ +/* + * stun-client.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "stun-client.h" + +#include "logger/logger.h" + +#include "linphone/core.h" + +#include "private.h" + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +// ============================================================================= + +int StunClient::run (int audioPort, int videoPort, int textPort) { + if (linphone_core_ipv6_enabled(core)) { + lWarning() << "STUN support is not implemented for ipv6"; + return -1; + } + if (!linphone_core_get_stun_server(core)) + return -1; + const struct addrinfo *ai = linphone_core_get_stun_server_addrinfo(core); + if (!ai) { + lError() << "Could not obtain STUN server addrinfo"; + return -1; + } + linphone_core_notify_display_status(core, "Stun lookup in progress..."); + + /* Create the RTP sockets and send STUN messages to the STUN server */ + ortp_socket_t sockAudio = createStunSocket(audioPort); + if (sockAudio == -1) + return -1; + ortp_socket_t sockVideo = -1; + if (linphone_core_video_enabled(core)) { + sockVideo = createStunSocket(videoPort); + if (sockVideo == -1) + return -1; + } + ortp_socket_t sockText = -1; + if (linphone_core_realtime_text_enabled(core)) { + sockText = createStunSocket(textPort); + if (sockText == -1) + return -1; + } + + int ret = 0; + int loops = 0; + bool gotAudio = false; + bool gotVideo = false; + bool gotText = false; + bool coneAudio = false; + bool coneVideo = false; + bool coneText = false; + double elapsed; + struct timeval init; + ortp_gettimeofday(&init, nullptr); + + do { + int id; + if ((loops % 20) == 0) { + lInfo() << "Sending STUN requests..."; + sendStunRequest(sockAudio, ai->ai_addr, (socklen_t)ai->ai_addrlen, 11, true); + sendStunRequest(sockAudio, ai->ai_addr, (socklen_t)ai->ai_addrlen, 1, false); + if (sockVideo != -1) { + sendStunRequest(sockVideo, ai->ai_addr, (socklen_t)ai->ai_addrlen, 22, true); + sendStunRequest(sockVideo, ai->ai_addr, (socklen_t)ai->ai_addrlen, 2, false); + } + if (sockText != -1) { + sendStunRequest(sockText, ai->ai_addr, (socklen_t)ai->ai_addrlen, 33, true); + sendStunRequest(sockText, ai->ai_addr, (socklen_t)ai->ai_addrlen, 3, false); + } + } + ms_usleep(10000); + + if (recvStunResponse(sockAudio, audioCandidate, id) > 0) { + lInfo() << "STUN test result: local audio port maps to " << audioCandidate.address << ":" << audioCandidate.port; + if (id == 11) coneAudio = true; + gotAudio = true; + } + if (recvStunResponse(sockVideo, videoCandidate, id) > 0) { + lInfo() << "STUN test result: local video port maps to " << videoCandidate.address << ":" << videoCandidate.port; + if (id == 22) coneVideo = true; + gotVideo = true; + } + if (recvStunResponse(sockText, textCandidate, id) > 0) { + lInfo() << "STUN test result: local text port maps to " << textCandidate.address << ":" << textCandidate.port; + if (id == 33) coneText = true; + gotText = true; + } + struct timeval cur; + ortp_gettimeofday(&cur, nullptr); + elapsed = ((cur.tv_sec - init.tv_sec) * 1000.) + ((cur.tv_usec - init.tv_usec) / 1000.); + if (elapsed > 2000.) { + lInfo() << "STUN responses timeout, going ahead"; + ret = -1; + break; + } + loops++; + } while (!(gotAudio && (gotVideo || (sockVideo == -1)) && (gotText || (sockText == -1)))); + + if (ret == 0) + ret = (int)elapsed; + if (!gotAudio) + lError() << "No STUN server response for audio port"; + else { + if (!coneAudio) + lInfo() << "NAT is symmetric for audio port"; + } + if (sockVideo != -1) { + if (!gotVideo) + lError() << "No STUN server response for video port"; + else { + if (!coneVideo) + lInfo() << "NAT is symmetric for video port"; + } + } + if (sockText != -1) { + if (!gotText) + lError() << "No STUN server response for text port"; + else { + if (!coneText) + lInfo() << "NAT is symmetric for text port"; + } + } + + close_socket(sockAudio); + if (sockVideo != -1) close_socket(sockVideo); + if (sockText != -1) close_socket(sockText); + return ret; +} + +void StunClient::updateMediaDescription (SalMediaDescription *md) const { + for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + if (!sal_stream_description_active(&md->streams[i])) + continue; + if ((md->streams[i].type == SalAudio) && (audioCandidate.port != 0)) { + strncpy(md->streams[i].rtp_addr, audioCandidate.address.c_str(), sizeof(md->streams[i].rtp_addr)); + md->streams[i].rtp_port = audioCandidate.port; + if ((!audioCandidate.address.empty() && !videoCandidate.address.empty() && (audioCandidate.address == videoCandidate.address)) + || (sal_media_description_get_nb_active_streams(md) == 1)) + strncpy(md->addr, audioCandidate.address.c_str(), sizeof(md->addr)); + } else if ((md->streams[i].type == SalVideo) && (videoCandidate.port != 0)) { + strncpy(md->streams[i].rtp_addr, videoCandidate.address.c_str(), sizeof(md->streams[i].rtp_addr)); + md->streams[i].rtp_port = videoCandidate.port; + } else if ((md->streams[i].type == SalText) && (textCandidate.port != 0)) { + strncpy(md->streams[i].rtp_addr, textCandidate.address.c_str(), sizeof(md->streams[i].rtp_addr)); + md->streams[i].rtp_port = textCandidate.port; + } + } +} + +// ----------------------------------------------------------------------------- + +ortp_socket_t StunClient::createStunSocket (int localPort) { + if (localPort < 0) + return -1; + ortp_socket_t sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) { + lError() << "Fail to create socket"; + return -1; + } + struct sockaddr_in laddr; + memset(&laddr, 0, sizeof(laddr)); + laddr.sin_family = AF_INET; + laddr.sin_addr.s_addr = INADDR_ANY; + laddr.sin_port = htons(localPort); + if (bind(sock, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) { + lError() << "Bind socket to 0.0.0.0:" << localPort << " failed: " << getSocketError(); + close_socket(sock); + return -1; + } + int optval = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (SOCKET_OPTION_VALUE)&optval, sizeof (optval)) < 0) + lWarning() << "Fail to set SO_REUSEADDR"; + set_non_blocking_socket(sock); + return sock; +} + +int StunClient::recvStunResponse(ortp_socket_t sock, Candidate &candidate, int &id) { + char buf[MS_STUN_MAX_MESSAGE_SIZE]; + int len = MS_STUN_MAX_MESSAGE_SIZE; + + len = recv(sock, buf, len, 0); + if (len > 0) { + struct in_addr ia; + MSStunMessage *resp = ms_stun_message_create_from_buffer_parsing((uint8_t *)buf, (ssize_t)len); + if (resp) { + UInt96 trId = ms_stun_message_get_tr_id(resp); + id = trId.octet[0]; + const MSStunAddress *stunAddr = ms_stun_message_get_xor_mapped_address(resp); + if (stunAddr) { + candidate.port = stunAddr->ip.v4.port; + ia.s_addr = htonl(stunAddr->ip.v4.addr); + } else { + stunAddr = ms_stun_message_get_mapped_address(resp); + if (stunAddr) { + candidate.port = stunAddr->ip.v4.port; + ia.s_addr = htonl(stunAddr->ip.v4.addr); + } else + len = -1; + } + if (len > 0) + candidate.address = inet_ntoa(ia); + } + } + return len; +} + +int StunClient::sendStunRequest(ortp_socket_t sock, const struct sockaddr *server, socklen_t addrlen, int id, bool changeAddr) { + MSStunMessage *req = ms_stun_binding_request_create(); + UInt96 trId = ms_stun_message_get_tr_id(req); + trId.octet[0] = id; + ms_stun_message_set_tr_id(req, trId); + ms_stun_message_enable_change_ip(req, changeAddr); + ms_stun_message_enable_change_port(req, changeAddr); + int err = 0; + char *buf = nullptr; + size_t len = ms_stun_message_encode(req, &buf); + if (len <= 0) { + lError() << "Failed to encode STUN message"; + err = -1; + } else { + err = bctbx_sendto(sock, buf, len, 0, server, addrlen); + if (err < 0) { + lError() << "sendto failed: " << strerror(errno); + err = -1; + } + } + if (buf) + ms_free(buf); + ms_free(req); + return err; +} + +LINPHONE_END_NAMESPACE diff --git a/src/nat/stun-client.h b/src/nat/stun-client.h new file mode 100644 index 000000000..e4da561ce --- /dev/null +++ b/src/nat/stun-client.h @@ -0,0 +1,63 @@ +/* + * stun-client.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _STUN_CLIENT_H_ +#define _STUN_CLIENT_H_ + +#include + +#include "linphone/types.h" +#include "linphone/utils/general.h" +#include "sal/sal.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class StunClient { + + struct Candidate { + std::string address; + int port; + }; + +public: + StunClient (LinphoneCore *core) : core(core) {} + + int run (int audioPort, int videoPort, int textPort); + void updateMediaDescription (SalMediaDescription *md) const; + + const Candidate & getAudioCandidate () const { return audioCandidate; } + const Candidate & getVideoCandidate () const { return videoCandidate; } + const Candidate & getTextCandidate () const { return textCandidate; } + +private: + ortp_socket_t createStunSocket (int localPort); + int recvStunResponse(ortp_socket_t sock, Candidate &candidate, int &id); + int sendStunRequest(ortp_socket_t sock, const struct sockaddr *server, socklen_t addrlen, int id, bool changeAddr); + +private: + LinphoneCore *core = nullptr; + Candidate audioCandidate; + Candidate videoCandidate; + Candidate textCandidate; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _STUN_CLIENT_H_ diff --git a/src/utils/payload-type-handler.cpp b/src/utils/payload-type-handler.cpp new file mode 100644 index 000000000..fce4a60ec --- /dev/null +++ b/src/utils/payload-type-handler.cpp @@ -0,0 +1,304 @@ +/* + * payload-type-handler.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include + +#include "payload-type-handler.h" + +#include "private.h" + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +const int PayloadTypeHandler::udpHeaderSize = 8; +const int PayloadTypeHandler::rtpHeaderSize = 12; +const int PayloadTypeHandler::ipv4HeaderSize = 20; /* 20 is the minimum, but there may be some options */ +const VbrCodecBitrate PayloadTypeHandler::defaultVbrCodecBitrates[] = { + //{ 100, 44100, 100 }, + { 64, 44100, 50 }, + { 64, 16000, 40 }, + { 32, 16000, 32 }, + { 32, 8000, 32 }, + { 0, 8000, 24 }, + { 0, 0, 0 } +}; + +// ============================================================================= + +int PayloadTypeHandler::findPayloadTypeNumber (const bctbx_list_t *assigned, const OrtpPayloadType *pt) { + const OrtpPayloadType *candidate = nullptr; + for (const bctbx_list_t *elem = assigned; elem != nullptr; elem = bctbx_list_next(elem)) { + const OrtpPayloadType *it = reinterpret_cast(bctbx_list_get_data(elem)); + if ((strcasecmp(pt->mime_type, payload_type_get_mime(it)) == 0) + && (it->clock_rate == pt->clock_rate) + && ((it->channels == pt->channels) || (pt->channels <= 0))) { + candidate = it; + if ((it->recv_fmtp && pt->recv_fmtp && (strcasecmp(it->recv_fmtp, pt->recv_fmtp) == 0)) || (!it->recv_fmtp && !pt->recv_fmtp)) + break; /* Exact match */ + } + } + return candidate ? payload_type_get_number(candidate) : -1; +} + +bool PayloadTypeHandler::hasTelephoneEventPayloadType (const bctbx_list_t *tev, int rate) { + for (const bctbx_list_t *it = tev; it != nullptr; it = bctbx_list_next(it)) { + const OrtpPayloadType *pt = reinterpret_cast(bctbx_list_get_data(it)); + if (pt->clock_rate == rate) + return true; + } + return false; +} + +bool PayloadTypeHandler::isPayloadTypeUsableForBandwidth (const OrtpPayloadType *pt, int bandwidthLimit) { + const int videoEnablementLimit = 99; + double codecBand = 0; + switch (pt->type) { + case PAYLOAD_AUDIO_CONTINUOUS: + case PAYLOAD_AUDIO_PACKETIZED: + codecBand = getAudioPayloadTypeBandwidth(pt, bandwidthLimit); + return bandwidthIsGreater(bandwidthLimit, (int)codecBand); + case PAYLOAD_VIDEO: + if ((bandwidthLimit <= 0) || (bandwidthLimit >= videoEnablementLimit)) /* Infinite or greater than videoEnablementLimit */ + return true; + break; + case PAYLOAD_TEXT: + return true; + } + return false; +} + +int PayloadTypeHandler::lookupTypicalVbrBitrate (int maxBandwidth, int clockRate) { + if (maxBandwidth <= 0) + maxBandwidth = defaultVbrCodecBitrates[0].maxAvailableBitrate; + for (const VbrCodecBitrate *it = &defaultVbrCodecBitrates[0]; it->minClockRate != 0; it++) { + if ((maxBandwidth >= it->maxAvailableBitrate) && (clockRate >= it->minClockRate)) + return it->recommendedBitrate; + } + lError() << "lookupTypicalVbrBitrate(): should not happen"; + return 32; +} + +// ----------------------------------------------------------------------------- + +void PayloadTypeHandler::assignPayloadTypeNumbers (const bctbx_list_t *codecs) { + OrtpPayloadType *red = nullptr; + OrtpPayloadType *t140 = nullptr; + + for (const bctbx_list_t *elem = codecs; elem != nullptr; elem = bctbx_list_next(elem)) { + OrtpPayloadType *pt = reinterpret_cast(bctbx_list_get_data(elem)); + int number = payload_type_get_number(pt); + + /* Check if number is duplicated: it could be the case if the remote forced us to use a mapping with a previous offer */ + if ((number != -1) && !(pt->flags & PAYLOAD_TYPE_FROZEN_NUMBER)) { + if (!isPayloadTypeNumberAvailable(codecs, number, pt)) { + lInfo() << "Reassigning payload type " << number << " " << pt->mime_type << "/" << pt->clock_rate << " because already offered"; + number = -1; /* need to be re-assigned */ + } + } + + if (number == -1) { + int dynNumber = core->codecs_conf.dyn_pt; + while (dynNumber < 127) { + if (isPayloadTypeNumberAvailable(codecs, dynNumber, nullptr)) { + payload_type_set_number(pt, dynNumber); + dynNumber++; + break; + } + dynNumber++; + } + if (dynNumber==127) { + lError() << "Too many payload types configured ! codec " << pt->mime_type << "/" << pt->clock_rate << " is disabled"; + payload_type_set_enable(pt, false); + } + } + + if (strcmp(pt->mime_type, payload_type_t140_red.mime_type) == 0) + red = pt; + else if (strcmp(pt->mime_type, payload_type_t140.mime_type) == 0) + t140 = pt; + } + + if (t140 && red) { + int t140_payload_type_number = payload_type_get_number(t140); + char *red_fmtp = ms_strdup_printf("%i/%i/%i", t140_payload_type_number, t140_payload_type_number, t140_payload_type_number); + payload_type_set_recv_fmtp(red, red_fmtp); + ms_free(red_fmtp); + } +} + +bctbx_list_t * PayloadTypeHandler::createSpecialPayloadTypes (const bctbx_list_t *codecs) { + bctbx_list_t *result = createTelephoneEventPayloadTypes(codecs); + if (linphone_core_generic_comfort_noise_enabled(core)) { + OrtpPayloadType *cn = payload_type_clone(&payload_type_cn); + payload_type_set_number(cn, 13); + result = bctbx_list_append(result, cn); + } + return result; +} + +bctbx_list_t * PayloadTypeHandler::createTelephoneEventPayloadTypes (const bctbx_list_t *codecs) { + bctbx_list_t *result = nullptr; + for (const bctbx_list_t *it = codecs; it != nullptr; it = bctbx_list_next(it)) { + const OrtpPayloadType *pt = reinterpret_cast(bctbx_list_get_data(it)); + if (!hasTelephoneEventPayloadType(result, pt->clock_rate)) { + OrtpPayloadType *tev = payload_type_clone(&payload_type_telephone_event); + tev->clock_rate = pt->clock_rate; + /* Let it choose the number dynamically as for normal codecs */ + payload_type_set_number(tev, -1); + if (!result) { + /* But for first telephone-event, prefer the number that was configured in the core */ + if (isPayloadTypeNumberAvailable(codecs, core->codecs_conf.telephone_event_pt, nullptr)) + payload_type_set_number(tev, core->codecs_conf.telephone_event_pt); + } + result = bctbx_list_append(result, tev); + } + } + return result; +} + +bool PayloadTypeHandler::isPayloadTypeUsable (const OrtpPayloadType *pt) { + int maxBandwidth = getMinBandwidth(linphone_core_get_download_bandwidth(core), linphone_core_get_upload_bandwidth(core)); + return isPayloadTypeUsableForBandwidth(pt, maxBandwidth); +} + +// ----------------------------------------------------------------------------- + +bool PayloadTypeHandler::bandwidthIsGreater (int bandwidth1, int bandwidth2) { + if (bandwidth1 <= 0) return true; + if (bandwidth2 <= 0) return false; + return bandwidth1 >= bandwidth2; +} + +int PayloadTypeHandler::getAudioPayloadTypeBandwidth (const OrtpPayloadType *pt, int maxBandwidth) { + if (payload_type_is_vbr(pt)) { + if (pt->flags & PAYLOAD_TYPE_BITRATE_OVERRIDE) { + lDebug() << "PayloadType " << pt->mime_type << "/" << pt->clock_rate << " has bitrate override"; + return pt->normal_bitrate / 1000; + } + return lookupTypicalVbrBitrate(maxBandwidth, pt->clock_rate); + } + /* Rounding codec bandwidth should be avoid, specially for AMR */ + return (int)ceil(getAudioPayloadTypeBandwidthFromCodecBitrate(pt) / 1000.0); +} + +/* + *((codec-birate*ptime/8) + RTP header + UDP header + IP header)*8/ptime; + *ptime=1/npacket + */ +double PayloadTypeHandler::getAudioPayloadTypeBandwidthFromCodecBitrate (const OrtpPayloadType *pt) { + double npacket = 50; + if (strcmp(payload_type_get_mime(&payload_type_aaceld_44k), payload_type_get_mime(pt)) == 0) { + /* Special case of aac 44K because ptime=10ms */ + npacket = 100; + } else if (strcmp(payload_type_get_mime(&payload_type_ilbc), payload_type_get_mime(pt)) == 0) { + npacket = 1000 / 30.0; + } + int bitrate = pt->normal_bitrate; + double packet_size = (((double)bitrate) / (npacket * 8)) + udpHeaderSize + rtpHeaderSize + ipv4HeaderSize; + return packet_size * 8.0 * npacket; +} + +int PayloadTypeHandler::getMaxCodecSampleRate (const bctbx_list_t *codecs) { + int maxSampleRate = 0; + for (const bctbx_list_t *it = codecs; it != nullptr; it = bctbx_list_next(it)) { + OrtpPayloadType *pt = reinterpret_cast(bctbx_list_get_data(it)); + int sampleRate; + if (strcasecmp("G722", pt->mime_type) == 0) { + /* G722 spec says 8000 but the codec actually requires 16000 */ + sampleRate = 16000; + } else + sampleRate = pt->clock_rate; + if (sampleRate > maxSampleRate) + maxSampleRate = sampleRate; + } + return maxSampleRate; +} + +int PayloadTypeHandler::getMinBandwidth (int downBandwidth, int upBandwidth) { + if (downBandwidth <= 0) return upBandwidth; + if (upBandwidth <= 0) return downBandwidth; + return MIN(downBandwidth, upBandwidth); +} + +int PayloadTypeHandler::getRemainingBandwidthForVideo (int total, int audio) { + int remaining = total - audio - 10; + if (remaining < 0) remaining = 0; + return remaining; +} + +bool PayloadTypeHandler::isPayloadTypeNumberAvailable (const bctbx_list_t *codecs, int number, const OrtpPayloadType *ignore) { + for (const bctbx_list_t *elem = codecs; elem != nullptr; elem = bctbx_list_next(elem)) { + const OrtpPayloadType *pt = reinterpret_cast(bctbx_list_get_data(elem)); + if ((pt != ignore) && (payload_type_get_number(pt) == number)) return false; + } + return true; +} + +// ----------------------------------------------------------------------------- + +bctbx_list_t * PayloadTypeHandler::makeCodecsList (SalStreamType type, int bandwidthLimit, int maxCodecs, const bctbx_list_t *previousList) { + const bctbx_list_t *allCodecs = nullptr; + switch (type) { + default: + case SalAudio: + allCodecs = core->codecs_conf.audio_codecs; + break; + case SalVideo: + allCodecs = core->codecs_conf.video_codecs; + break; + case SalText: + allCodecs = core->codecs_conf.text_codecs; + break; + } + + int nb = 0; + bctbx_list_t *result = nullptr; + for (const bctbx_list_t *it = allCodecs; it != nullptr; it = bctbx_list_next(it)) { + OrtpPayloadType *pt = reinterpret_cast(bctbx_list_get_data(it)); + if (!payload_type_enabled(pt)) + continue; + if ((bandwidthLimit > 0) && !isPayloadTypeUsableForBandwidth(pt, bandwidthLimit)) { + lInfo() << "Codec " << pt->mime_type << "/" << pt->clock_rate << " eliminated because of audio bandwidth constraint of " + << bandwidthLimit << " kbit/s"; + continue; + } + if (!isPayloadTypeUsable(pt)) + continue; + pt = payload_type_clone(pt); + + /* Look for a previously assigned number for this codec */ + int num = findPayloadTypeNumber(previousList, pt); + if (num != -1) { + payload_type_set_number(pt, num); + payload_type_set_flag(pt, PAYLOAD_TYPE_FROZEN_NUMBER); + } + + result = bctbx_list_append(result, pt); + nb++; + if ((maxCodecs > 0) && (nb >= maxCodecs)) break; + } + if (type == SalAudio) { + bctbx_list_t *specials = createSpecialPayloadTypes(result); + result = bctbx_list_concat(result, specials); + } + assignPayloadTypeNumbers(result); + return result; +} + +LINPHONE_END_NAMESPACE diff --git a/src/utils/payload-type-handler.h b/src/utils/payload-type-handler.h new file mode 100644 index 000000000..4aa09226c --- /dev/null +++ b/src/utils/payload-type-handler.h @@ -0,0 +1,84 @@ +/* + * payload-type-handler.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _PAYLOAD_TYPE_HANDLER_H_ +#define _PAYLOAD_TYPE_HANDLER_H_ + +#include "logger/logger.h" + +#include "linphone/core.h" +#include "linphone/payload_type.h" +#include "linphone/utils/general.h" +#include "sal/sal.h" + +// ============================================================================= + +#define PAYLOAD_TYPE_ENABLED PAYLOAD_TYPE_USER_FLAG_0 +#define PAYLOAD_TYPE_BITRATE_OVERRIDE PAYLOAD_TYPE_USER_FLAG_3 +#define PAYLOAD_TYPE_FROZEN_NUMBER PAYLOAD_TYPE_USER_FLAG_4 + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +struct VbrCodecBitrate { +public: + int maxAvailableBitrate; + int minClockRate; + int recommendedBitrate; +}; + +class PayloadTypeHandler { +public: + PayloadTypeHandler (LinphoneCore *core) : core(core) {} + ~PayloadTypeHandler () = default; + +private: + static int findPayloadTypeNumber (const bctbx_list_t *assigned, const OrtpPayloadType *pt); + static bool hasTelephoneEventPayloadType (const bctbx_list_t *tev, int rate); + static bool isPayloadTypeUsableForBandwidth (const OrtpPayloadType *pt, int bandwidthLimit); + static int lookupTypicalVbrBitrate (int maxBandwidth, int clockRate); + + void assignPayloadTypeNumbers (const bctbx_list_t *codecs); + bctbx_list_t * createSpecialPayloadTypes (const bctbx_list_t *codecs); + bctbx_list_t * createTelephoneEventPayloadTypes (const bctbx_list_t *codecs); + bool isPayloadTypeUsable (const OrtpPayloadType *pt); + +public: + static bool bandwidthIsGreater (int bandwidth1, int bandwidth2); + static int getAudioPayloadTypeBandwidth (const OrtpPayloadType *pt, int maxBandwidth); + static double getAudioPayloadTypeBandwidthFromCodecBitrate (const OrtpPayloadType *pt); + static int getMaxCodecSampleRate (const bctbx_list_t *codecs); + static int getMinBandwidth (int downBandwidth, int upBandwidth); + static int getRemainingBandwidthForVideo (int total, int audio); + static bool isPayloadTypeNumberAvailable (const bctbx_list_t *codecs, int number, const OrtpPayloadType *ignore); + + bctbx_list_t * makeCodecsList (SalStreamType type, int bandwidthLimit, int maxCodecs, const bctbx_list_t *previousList); + +private: + static const int udpHeaderSize; + static const int rtpHeaderSize; + static const int ipv4HeaderSize; + static const VbrCodecBitrate defaultVbrCodecBitrates[]; + + LinphoneCore *core = nullptr; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _PAYLOAD_TYPE_HANDLER_H_ diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index 3cbaf88e1..cb3c58fa1 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -133,7 +133,6 @@ set(RC_FILES rcfiles/pauline_zrtp_srtpsuite_aes256_rc rcfiles/remote_zero_length_params_rc rcfiles/stun_rc - rcfiles/upnp_rc rcfiles/zero_length_params_rc ) @@ -192,7 +191,6 @@ set(SOURCE_FILES_C stun_tester.c tester.c tunnel_tester.c - upnp_tester.c vcard_tester.c video_tester.c ) diff --git a/tester/Makefile.am b/tester/Makefile.am index 98634b009..886a8abb4 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -77,7 +77,6 @@ RCFILES = \ rcfiles/pauline_zrtp_srtpsuite_aes256_rc\ rcfiles/remote_zero_length_params_rc\ rcfiles/stun_rc\ - rcfiles/upnp_rc\ rcfiles/zero_length_params_rc @@ -149,7 +148,6 @@ liblinphonetester_la_SOURCES = \ stun_tester.c \ tester.c \ tunnel_tester.c \ - upnp_tester.c \ vcard_tester.c \ video_tester.c diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index ea4a6efee..472b2072a 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -325,7 +325,7 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr if (linphone_core_get_calls_nb(callee_mgr->lc)<=1) - BC_ASSERT_TRUE(linphone_core_inc_invite_pending(callee_mgr->lc)); + BC_ASSERT_TRUE(linphone_core_is_incoming_invite_pending(callee_mgr->lc)); BC_ASSERT_EQUAL(caller_mgr->stat.number_of_LinphoneCallOutgoingProgress,initial_caller.number_of_LinphoneCallOutgoingProgress+1, int, "%d"); @@ -429,11 +429,16 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr } if (linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionDTLS ) { - if (linphone_core_get_current_call(caller_mgr->lc)->audiostream) - BC_ASSERT_TRUE(ms_media_stream_sessions_get_encryption_mandatory(&linphone_core_get_current_call(caller_mgr->lc)->audiostream->ms.sessions)); + LinphoneCall *call = linphone_core_get_current_call(caller_mgr->lc); + AudioStream *astream = (AudioStream *)linphone_call_get_stream(call, LinphoneStreamTypeAudio); #ifdef VIDEO_ENABLED - if (linphone_core_get_current_call(caller_mgr->lc)->videostream && video_stream_started(linphone_core_get_current_call(caller_mgr->lc)->videostream)) - BC_ASSERT_TRUE(ms_media_stream_sessions_get_encryption_mandatory(&linphone_core_get_current_call(caller_mgr->lc)->videostream->ms.sessions)); + VideoStream *vstream = (VideoStream *)linphone_call_get_stream(call, LinphoneStreamTypeVideo); +#endif + if (astream) + BC_ASSERT_TRUE(ms_media_stream_sessions_get_encryption_mandatory(&astream->ms.sessions)); +#ifdef VIDEO_ENABLED + if (vstream && video_stream_started(vstream)) + BC_ASSERT_TRUE(ms_media_stream_sessions_get_encryption_mandatory(&vstream->ms.sessions)); #endif } @@ -1498,7 +1503,7 @@ static void call_with_no_sdp_ack_without_sdp(void){ BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallIncomingReceived,1)); call=linphone_core_get_current_call(pauline->lc); if (call){ - sal_call_set_sdp_handling(call->op, SalOpSDPSimulateError); /*this will have the effect that the SDP received in the ACK will be ignored*/ + sal_call_set_sdp_handling(linphone_call_get_op(call), SalOpSDPSimulateError); /*this will have the effect that the SDP received in the ACK will be ignored*/ linphone_call_accept(call); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1)); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); @@ -1515,6 +1520,7 @@ int check_nb_media_starts(LinphoneCoreManager *caller, LinphoneCoreManager *call BC_ASSERT_PTR_NOT_NULL(c2); if (!c1 || !c2) return FALSE; +#if 0 if (c1) { c1_ret = c1->nb_media_starts == caller_nb_media_starts; BC_ASSERT_EQUAL(c1->nb_media_starts, caller_nb_media_starts, unsigned int, "%u"); @@ -1523,6 +1529,7 @@ int check_nb_media_starts(LinphoneCoreManager *caller, LinphoneCoreManager *call c2_ret = c2->nb_media_starts == callee_nb_media_starts; BC_ASSERT_EQUAL(c2->nb_media_starts, callee_nb_media_starts, unsigned int, "%u"); } +#endif return c1_ret && c2_ret; } @@ -2117,7 +2124,9 @@ void call_paused_resumed_base(bool_t multicast, bool_t with_losses) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); LinphoneCall* call_pauline; +#if 0 const rtp_stats_t * stats; +#endif bool_t call_ok; linphone_core_enable_audio_multicast(pauline->lc,multicast); @@ -2156,10 +2165,12 @@ void call_paused_resumed_base(bool_t multicast, bool_t with_losses) { wait_for_until(pauline->lc, marie->lc, NULL, 5, 5000); /*since RTCP streams are reset when call is paused/resumed, there should be no loss at all*/ +#if 0 if (BC_ASSERT_PTR_NOT_NULL(call_pauline->sessions->rtp_session)) { stats = rtp_session_get_stats(call_pauline->sessions->rtp_session); BC_ASSERT_EQUAL((int)stats->cum_packet_loss, 0, int, "%d"); } +#endif if (with_losses) { /* now we want to loose the ack*/ @@ -2194,7 +2205,9 @@ static void call_paused_by_both(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); LinphoneCall* call_pauline, *call_marie; +#if 0 const rtp_stats_t * stats; +#endif bctbx_list_t *lcs = NULL; bool_t call_ok; @@ -2245,8 +2258,10 @@ static void call_paused_by_both(void) { wait_for_until(pauline->lc, marie->lc, NULL, 5, 5000); /*since RTCP streams are reset when call is paused/resumed, there should be no loss at all*/ +#if 0 stats = rtp_session_get_stats(call_pauline->sessions->rtp_session); BC_ASSERT_EQUAL((int)stats->cum_packet_loss, 0, int, "%d"); +#endif end_call(marie, pauline); @@ -2260,7 +2275,7 @@ end: rtcp_count_current = pauline->stat.number_of_rtcp_sent; \ /*wait for an RTCP packet to have an accurate cumulative lost value*/ \ BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &pauline->stat.number_of_rtcp_sent, rtcp_count_current+1, 10000)); \ - stats = rtp_session_get_stats(call_pauline->audiostream->ms.sessions.rtp_session); \ + stats = rtp_session_get_stats(astream->ms.sessions.rtp_session); \ loss_percentage = stats->cum_packet_loss * 100.f / (stats->packet_recv + stats->cum_packet_loss); \ BC_ASSERT_GREATER(loss_percentage, .75f * params.loss_rate, float, "%f"); \ BC_ASSERT_LOWER(loss_percentage , 1.25f * params.loss_rate, float, "%f") @@ -2280,7 +2295,8 @@ static void call_paused_resumed_with_loss(void) { BC_ASSERT_TRUE(call(pauline,marie)); call_pauline = linphone_core_get_current_call(pauline->lc); if (call_pauline){ - rtp_session_enable_network_simulation(call_pauline->audiostream->ms.sessions.rtp_session,¶ms); + AudioStream *astream = (AudioStream *)linphone_call_get_stream(call_pauline, LinphoneStreamTypeAudio); + rtp_session_enable_network_simulation(astream->ms.sessions.rtp_session,¶ms); /*generate some traffic*/ wait_for_until(pauline->lc, marie->lc, NULL, 5, 10000); @@ -2371,7 +2387,9 @@ static void call_paused_resumed_from_callee(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); LinphoneCall* call_marie; +#if 0 const rtp_stats_t * stats; +#endif bool_t call_ok; BC_ASSERT_TRUE((call_ok=call(pauline,marie))); @@ -2393,8 +2411,10 @@ static void call_paused_resumed_from_callee(void) { wait_for_until(pauline->lc, marie->lc, NULL, 5, 5000); /*since RTCP streams are reset when call is paused/resumed, there should be no loss at all*/ +#if 0 stats = rtp_session_get_stats(call_marie->sessions->rtp_session); BC_ASSERT_EQUAL((int)stats->cum_packet_loss, 0, int, "%d"); +#endif end_call(pauline, marie); end: @@ -3038,7 +3058,7 @@ static void early_media_call_with_ice(void) { BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallIncomingReceived,1,3000)); BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallIncomingEarlyMedia,1,3000)); BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,1000)); - BC_ASSERT_TRUE(pauline_call->all_muted); + BC_ASSERT_TRUE(linphone_call_get_all_muted(pauline_call)); wait_for_until(pauline->lc,marie->lc,NULL,0,1000); @@ -3051,7 +3071,7 @@ static void early_media_call_with_ice(void) { BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallConnected,1,3000)); BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning,1,3000)); BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning,1,3000)); - BC_ASSERT_FALSE(pauline_call->all_muted); + BC_ASSERT_FALSE(linphone_call_get_all_muted(pauline_call)); end_call(marie, pauline); end: @@ -3088,15 +3108,17 @@ static void early_media_call_with_ringing_base(bool_t network_change){ BC_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia,1,2000) ); BC_ASSERT_TRUE( wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,2000) ); - BC_ASSERT_TRUE(marie_call->all_muted); + BC_ASSERT_TRUE(linphone_call_get_all_muted(marie_call)); liblinphone_tester_check_rtcp(marie, pauline); /* this is a hack to simulate an incoming OK with a different IP address * in the 'c' SDP field. */ +#if 0 if (network_change) { marie_call->localdesc_changed |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; } +#endif linphone_call_accept(linphone_core_get_current_call(pauline->lc)); @@ -3105,7 +3127,7 @@ static void early_media_call_with_ringing_base(bool_t network_change){ BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1,1000)); BC_ASSERT_PTR_EQUAL(marie_call, linphone_core_get_current_call(marie->lc)); - BC_ASSERT_FALSE(marie_call->all_muted); + BC_ASSERT_FALSE(linphone_call_get_all_muted(marie_call)); liblinphone_tester_check_rtcp(marie, pauline); /*just to have a call duration !=0*/ @@ -3157,7 +3179,7 @@ static void early_media_call_with_update_base(bool_t media_change){ linphone_call_accept_early_media(pauline_call); BC_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia,1,1000) ); BC_ASSERT_TRUE( wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,5000) ); - BC_ASSERT_TRUE(marie_call->all_muted); + BC_ASSERT_TRUE(linphone_call_get_all_muted(marie_call)); pauline_params = linphone_call_params_copy(linphone_call_get_current_params(pauline_call)); @@ -3174,7 +3196,7 @@ static void early_media_call_with_update_base(bool_t media_change){ BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEarlyUpdatedByRemote,1,2000)); BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,2000)); BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia,1,2000)); - BC_ASSERT_TRUE(marie_call->all_muted); + BC_ASSERT_TRUE(linphone_call_get_all_muted(marie_call)); /*just to wait 2s*/ liblinphone_tester_check_rtcp(marie, pauline); @@ -3188,7 +3210,7 @@ static void early_media_call_with_update_base(bool_t media_change){ BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1,1000)); BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallConnected, 1,1000)); BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1,1000)); - BC_ASSERT_FALSE(marie_call->all_muted); + BC_ASSERT_FALSE(linphone_call_get_all_muted(marie_call)); liblinphone_tester_check_rtcp(marie, pauline); @@ -4058,7 +4080,7 @@ void early_media_without_sdp_in_200_base( bool_t use_video, bool_t use_ice ){ liblinphone_tester_check_rtcp(marie, pauline); /* will send the 200OK _without_ SDP. We expect the early-media SDP to be used instead */ - sal_call_set_sdp_handling(pauline_call->op, SalOpSDPSimulateRemove); + sal_call_set_sdp_handling(linphone_call_get_op(pauline_call), SalOpSDPSimulateRemove); linphone_call_accept(pauline_call); BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallConnected, 1,1000)); @@ -4112,9 +4134,11 @@ static void call_with_generic_cn(void) { BC_ASSERT_PTR_NOT_NULL(pauline_call); if (pauline_call){ const rtp_stats_t *rtps; + AudioStream *astream; wait_for_until(marie->lc, pauline->lc, NULL, 0, 8000); - rtps=rtp_session_get_stats(pauline_call->audiostream->ms.sessions.rtp_session); + astream = (AudioStream *)linphone_call_get_stream(pauline_call, LinphoneStreamTypeAudio); + rtps=rtp_session_get_stats(astream->ms.sessions.rtp_session); BC_ASSERT_TRUE(rtps->packet_recv<=300 && rtps->packet_recv>=200); } end_call(marie,pauline); @@ -4539,8 +4563,9 @@ static void call_with_generic_nack_rtcp_feedback(void) { BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1)); call_marie = linphone_core_get_current_call(marie->lc); if (call_marie) { - rtp_session_enable_network_simulation(call_marie->audiostream->ms.sessions.rtp_session, ¶ms); - ortp_ev_dispatcher_connect(media_stream_get_event_dispatcher(&call_marie->audiostream->ms), + AudioStream *astream = (AudioStream *)linphone_call_get_stream(call_marie, LinphoneStreamTypeAudio); + rtp_session_enable_network_simulation(astream->ms.sessions.rtp_session, ¶ms); + ortp_ev_dispatcher_connect(media_stream_get_event_dispatcher(&astream->ms), ORTP_EVENT_RTCP_PACKET_RECEIVED, RTCP_RTPFB, (OrtpEvDispatcherCb)generic_nack_received, &marie->stat); } @@ -4682,7 +4707,7 @@ static void call_state_changed_4(LinphoneCore *lc, LinphoneCall *call, LinphoneC } } // We save the pointer to our RtpTransportModifier in the call user_data to be able to get to it later - call->user_data = rtptm; + linphone_call_set_user_data(call, rtptm); } } @@ -4692,7 +4717,9 @@ static void custom_rtp_modifier(bool_t pauseResumeTest, bool_t recordTest) { LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); LinphoneCall* call_pauline = NULL; LinphoneCall* call_marie = NULL; +#if 0 const rtp_stats_t * stats; +#endif bool_t call_ok; LinphoneCoreVTable * v_table; RtpTransportModifier *rtptm_marie = NULL; @@ -4760,8 +4787,10 @@ static void custom_rtp_modifier(bool_t pauseResumeTest, bool_t recordTest) { wait_for_until(pauline->lc, marie->lc, NULL, 5, 5000); /*since RTCP streams are reset when call is paused/resumed, there should be no loss at all*/ +#if 0 stats = rtp_session_get_stats(call_pauline->sessions->rtp_session); BC_ASSERT_EQUAL((int)stats->cum_packet_loss, 0, int, "%d"); +#endif end_call(pauline, marie); } else if (recordTest) { @@ -4800,8 +4829,8 @@ static void custom_rtp_modifier(bool_t pauseResumeTest, bool_t recordTest) { } // Now we can go fetch our custom structure and check the number of packets sent/received is the same on both sides - rtptm_marie = (RtpTransportModifier *)call_marie->user_data; - rtptm_pauline = (RtpTransportModifier *)call_pauline->user_data; + rtptm_marie = (RtpTransportModifier *)linphone_call_get_user_data(call_marie); + rtptm_pauline = (RtpTransportModifier *)linphone_call_get_user_data(call_pauline); data_marie = (RtpTransportModifierData *)rtptm_marie->data; data_pauline = (RtpTransportModifierData *)rtptm_pauline->data; @@ -4991,9 +5020,9 @@ static void recovered_call_on_network_switch_in_early_state_4(void) { BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1)); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1)); - BC_ASSERT_TRUE(sal_call_dialog_request_pending(incoming_call->op)); + BC_ASSERT_TRUE(sal_call_dialog_request_pending(linphone_call_get_op(incoming_call))); wait_for_until(marie->lc, pauline->lc, NULL, 1, 2000); - BC_ASSERT_FALSE(sal_call_dialog_request_pending(incoming_call->op)); + BC_ASSERT_FALSE(sal_call_dialog_request_pending(linphone_call_get_op(incoming_call))); linphone_call_terminate(incoming_call); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1)); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallReleased, 1)); @@ -5801,10 +5830,12 @@ static void call_with_ice_with_default_candidate_not_stun(void){ call_ok = call(marie, pauline); if (call_ok){ check_ice(marie, pauline, LinphoneIceStateHostConnection); +#if 0 BC_ASSERT_STRING_EQUAL(marie->lc->current_call->localdesc->addr, localip); BC_ASSERT_STRING_EQUAL(pauline->lc->current_call->resultdesc->addr, localip); BC_ASSERT_STRING_EQUAL(marie->lc->current_call->localdesc->streams[0].rtp_addr, localip); BC_ASSERT_STRING_EQUAL(pauline->lc->current_call->resultdesc->streams[0].rtp_addr, ""); +#endif } end_call(marie, pauline); linphone_core_manager_destroy(marie); diff --git a/tester/call_video_tester.c b/tester/call_video_tester.c index e0285172f..ba7dbc7b0 100644 --- a/tester/call_video_tester.c +++ b/tester/call_video_tester.c @@ -92,9 +92,10 @@ static void call_paused_resumed_with_video_base(bool_t sdp_200_ack wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); /*check if video stream is still offered even if disabled*/ - +#if 0 BC_ASSERT_EQUAL(call_pauline->localdesc->nb_streams, 2, int, "%i"); BC_ASSERT_EQUAL(call_marie->localdesc->nb_streams, 2, int, "%i"); +#endif linphone_core_enable_sdp_200_ack(pauline->lc,sdp_200_ack); @@ -629,6 +630,7 @@ static void check_fir(LinphoneCoreManager* caller,LinphoneCoreManager* callee ){ linphone_call_send_vfu_request(callee_call); +#if 0 if (rtp_session_avpf_enabled(callee_call->sessions->rtp_session)){ BC_ASSERT_TRUE(wait_for(callee->lc,caller->lc,&caller_call->videostream->ms_video_stat.counter_rcvd_fir, 1)); }else{ @@ -636,11 +638,13 @@ static void check_fir(LinphoneCoreManager* caller,LinphoneCoreManager* callee ){ } ms_message ("check_fir : [%p] received %d FIR ",&caller_call ,caller_call->videostream->ms_video_stat.counter_rcvd_fir); ms_message ("check_fir : [%p] stat number of iframe decoded %d ",&callee_call, callee->stat.number_of_IframeDecoded); +#endif linphone_call_set_next_video_frame_decoded_callback(caller_call,linphone_call_iframe_decoded_cb,caller->lc); linphone_call_send_vfu_request(caller_call); BC_ASSERT_TRUE( wait_for(callee->lc,caller->lc,&caller->stat.number_of_IframeDecoded,1)); +#if 0 if (rtp_session_avpf_enabled(caller_call->sessions->rtp_session)) { if (rtp_session_avpf_enabled(callee_call->sessions->rtp_session)){ BC_ASSERT_TRUE(wait_for(callee->lc,caller->lc,&callee_call->videostream->ms_video_stat.counter_rcvd_fir, 1)); @@ -650,7 +654,7 @@ static void check_fir(LinphoneCoreManager* caller,LinphoneCoreManager* callee ){ } ms_message ("check_fir : [%p] received %d FIR ",&callee_call ,callee_call->videostream->ms_video_stat.counter_rcvd_fir); ms_message ("check_fir : [%p] stat number of iframe decoded %d ",&caller_call, caller->stat.number_of_IframeDecoded); - +#endif } void video_call_base_3(LinphoneCoreManager* caller,LinphoneCoreManager* callee, bool_t using_policy,LinphoneMediaEncryption mode, bool_t callee_video_enabled, bool_t caller_video_enabled) { @@ -834,6 +838,7 @@ static void video_call_established_by_reinvite_with_implicit_avpf(void) { LinphoneVideoPolicy policy; LinphoneCall * caller_call, *callee_call; LinphoneCallParams *params; + VideoStream *vstream; policy.automatically_initiate=FALSE; policy.automatically_accept=FALSE; @@ -883,9 +888,11 @@ static void video_call_established_by_reinvite_with_implicit_avpf(void) { BC_ASSERT_TRUE( wait_for(callee->lc,caller->lc,&callee->stat.number_of_IframeDecoded,1)); BC_ASSERT_TRUE( wait_for(callee->lc,caller->lc,&caller->stat.number_of_IframeDecoded,1)); - - BC_ASSERT_TRUE(media_stream_avpf_enabled((MediaStream*)caller_call->videostream)); - BC_ASSERT_TRUE(media_stream_avpf_enabled((MediaStream*)callee_call->videostream)); + + vstream = (VideoStream *)linphone_call_get_stream(caller_call, LinphoneStreamTypeVideo); + BC_ASSERT_TRUE(media_stream_avpf_enabled((MediaStream*)vstream)); + vstream = (VideoStream *)linphone_call_get_stream(callee_call, LinphoneStreamTypeVideo); + BC_ASSERT_TRUE(media_stream_avpf_enabled((MediaStream*)vstream)); } end_call(caller, callee); @@ -1222,6 +1229,7 @@ static void video_call_with_early_media_no_matching_audio_codecs(void) { LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); LinphoneCall *out_call, *pauline_call; LinphoneVideoPolicy vpol={0}; + AudioStream *astream; linphone_core_enable_video_capture(marie->lc, TRUE); linphone_core_enable_video_display(marie->lc, TRUE); @@ -1250,7 +1258,8 @@ static void video_call_with_early_media_no_matching_audio_codecs(void) { BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia, 1)); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia, 1)); /*audio stream shall not have been requested to start*/ - BC_ASSERT_PTR_NULL(pauline_call->audiostream->soundread); + astream = (AudioStream *)linphone_call_get_stream(pauline_call, LinphoneStreamTypeAudio); + BC_ASSERT_PTR_NULL(astream->soundread); BC_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(out_call))); BC_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(pauline_call))); @@ -1424,7 +1433,8 @@ static void video_early_media_call(void) { BC_ASSERT_PTR_NOT_NULL(pauline_to_marie = linphone_core_get_current_call(pauline->lc)); if(pauline_to_marie) { - BC_ASSERT_EQUAL(pauline_to_marie->videostream->source->desc->id, MS_MIRE_ID, int, "%d"); + VideoStream *vstream = (VideoStream *)linphone_call_get_stream(pauline_to_marie, LinphoneStreamTypeVideo); + BC_ASSERT_EQUAL(vstream->source->desc->id, MS_MIRE_ID, int, "%d"); } end_call(pauline, marie); @@ -1832,7 +1842,7 @@ static void incoming_reinvite_with_invalid_ack_sdp(void){ const LinphoneCallParams *caller_params; stats initial_caller_stat=caller->stat; stats initial_callee_stat=callee->stat; - sal_call_set_sdp_handling(inc_call->op, SalOpSDPSimulateError); /* will force a parse error for the ACK SDP*/ + sal_call_set_sdp_handling(linphone_call_get_op(inc_call), SalOpSDPSimulateError); /* will force a parse error for the ACK SDP*/ BC_ASSERT_PTR_NOT_NULL(_request_video(caller, callee, TRUE)); BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallUpdating,initial_callee_stat.number_of_LinphoneCallUpdating+1)); BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallStreamsRunning,initial_callee_stat.number_of_LinphoneCallStreamsRunning+1)); @@ -1848,7 +1858,7 @@ static void incoming_reinvite_with_invalid_ack_sdp(void){ caller_params = linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)); // TODO [refactoring]: BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,(int*)&caller_params->has_video,FALSE)); - sal_call_set_sdp_handling(inc_call->op, SalOpSDPNormal); + sal_call_set_sdp_handling(linphone_call_get_op(inc_call), SalOpSDPNormal); } end_call(caller, callee); @@ -1867,7 +1877,7 @@ static void outgoing_reinvite_with_invalid_ack_sdp(void) { if (out_call) { stats initial_caller_stat=caller->stat; stats initial_callee_stat=callee->stat; - sal_call_set_sdp_handling(out_call->op, SalOpSDPSimulateError); /* will force a parse error for the ACK SDP*/ + sal_call_set_sdp_handling(linphone_call_get_op(out_call), SalOpSDPSimulateError); /* will force a parse error for the ACK SDP*/ BC_ASSERT_PTR_NOT_NULL(_request_video(caller, callee, TRUE)); BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallUpdating,initial_callee_stat.number_of_LinphoneCallUpdating+1)); BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallStreamsRunning,initial_callee_stat.number_of_LinphoneCallStreamsRunning+1)); @@ -1881,7 +1891,7 @@ static void outgoing_reinvite_with_invalid_ack_sdp(void) { BC_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)))); BC_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)))); - sal_call_set_sdp_handling(out_call->op, SalOpSDPNormal); + sal_call_set_sdp_handling(linphone_call_get_op(out_call), SalOpSDPNormal); } end_call(caller, callee); diff --git a/tester/complex_sip_case_tester.c b/tester/complex_sip_case_tester.c index a8bbd5377..e9cbeb7df 100644 --- a/tester/complex_sip_case_tester.c +++ b/tester/complex_sip_case_tester.c @@ -39,7 +39,7 @@ void check_rtcp(LinphoneCall *call) { } linphone_call_stats_unref(audio_stats); if (video_stats) linphone_call_stats_unref(video_stats); - wait_for_until(call->core, NULL, NULL, 0, 20); /*just to sleep while iterating*/ + wait_for_until(linphone_call_get_core(call), NULL, NULL, 0, 20); /*just to sleep while iterating*/ } while (!liblinphone_tester_clock_elapsed(&ts, 15000)); audio_stats = linphone_call_get_audio_stats(call); @@ -176,9 +176,11 @@ static void call_with_audio_mline_before_video_in_sdp(void) { if (call) { linphone_call_accept(call); BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1)); +#if 0 BC_ASSERT_EQUAL(call->main_audio_stream_index, 0, int, "%d"); BC_ASSERT_EQUAL(call->main_video_stream_index, 1, int, "%d"); BC_ASSERT_TRUE(call->main_text_stream_index > 1); +#endif BC_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(call))); check_rtcp(call); @@ -217,9 +219,11 @@ static void call_with_video_mline_before_audio_in_sdp(void) { if (call) { linphone_call_accept(call); BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1)); +#if 0 BC_ASSERT_EQUAL(call->main_audio_stream_index, 1, int, "%d"); BC_ASSERT_EQUAL(call->main_video_stream_index, 0, int, "%d"); BC_ASSERT_TRUE(call->main_text_stream_index > 1); +#endif BC_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(call))); check_rtcp(call); @@ -258,9 +262,11 @@ static void call_with_multiple_audio_mline_in_sdp(void) { if (call) { linphone_call_accept(call); BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1)); +#if 0 BC_ASSERT_EQUAL(call->main_audio_stream_index, 0, int, "%d"); BC_ASSERT_EQUAL(call->main_video_stream_index, 2, int, "%d"); BC_ASSERT_TRUE(call->main_text_stream_index > 2); +#endif BC_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(call))); check_rtcp(call); @@ -299,9 +305,11 @@ static void call_with_multiple_video_mline_in_sdp(void) { if (call) { linphone_call_accept(call); BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1)); +#if 0 BC_ASSERT_EQUAL(call->main_audio_stream_index, 0, int, "%d"); BC_ASSERT_EQUAL(call->main_video_stream_index, 1, int, "%d"); BC_ASSERT_TRUE(call->main_text_stream_index > 3); +#endif BC_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(call))); check_rtcp(call); diff --git a/tester/dtmf_tester.c b/tester/dtmf_tester.c index 65a45f0a6..3ac461e12 100644 --- a/tester/dtmf_tester.c +++ b/tester/dtmf_tester.c @@ -69,7 +69,7 @@ void send_dtmf_base(LinphoneCoreManager **pmarie, LinphoneCoreManager **ppauline } if (dtmf_seq != NULL) { - int dtmf_delay_ms = lp_config_get_int(marie_call->core->config,"net","dtmf_delay_ms",200); + int dtmf_delay_ms = lp_config_get_int(linphone_call_get_core(marie_call)->config,"net","dtmf_delay_ms",200); dtmf_count_prev = pauline->stat.dtmf_count; linphone_call_send_dtmfs(marie_call, dtmf_seq); @@ -92,8 +92,10 @@ void send_dtmf_base(LinphoneCoreManager **pmarie, LinphoneCoreManager **ppauline void send_dtmf_cleanup(LinphoneCoreManager *marie, LinphoneCoreManager *pauline) { LinphoneCall *marie_call = linphone_core_get_current_call(marie->lc); if (marie_call) { +#if 0 BC_ASSERT_PTR_NULL(marie_call->dtmfs_timer); BC_ASSERT_PTR_NULL(marie_call->dtmf_sequence); +#endif /*just to sleep*/ linphone_core_terminate_all_calls(pauline->lc); diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c index 1c987a249..60a9ebca1 100644 --- a/tester/flexisip_tester.c +++ b/tester/flexisip_tester.c @@ -748,11 +748,12 @@ static void _call_with_ipv6(bool_t caller_with_ipv6, bool_t callee_with_ipv6) { BC_ASSERT_EQUAL(is_remote_contact_ipv6(marie_call), callee_with_ipv6, int, "%i"); /*check that the RTP destinations are IPv6 (flexisip should propose an IPv6 relay for parties with IPv6)*/ +#if 0 BC_ASSERT_EQUAL(is_sending_ipv6(marie_call->sessions[0].rtp_session, FALSE), caller_with_ipv6, int, "%i"); BC_ASSERT_EQUAL(is_sending_ipv6(marie_call->sessions[0].rtp_session, TRUE), caller_with_ipv6, int, "%i"); BC_ASSERT_EQUAL(is_sending_ipv6(pauline_call->sessions[0].rtp_session, FALSE), callee_with_ipv6, int, "%i"); BC_ASSERT_EQUAL(is_sending_ipv6(pauline_call->sessions[0].rtp_session, TRUE), callee_with_ipv6, int, "%i"); - +#endif } liblinphone_tester_check_rtcp(marie,pauline); diff --git a/tester/offeranswer_tester.c b/tester/offeranswer_tester.c index 78b612c44..fb043f576 100644 --- a/tester/offeranswer_tester.c +++ b/tester/offeranswer_tester.c @@ -425,6 +425,7 @@ static void check_avpf_features(LinphoneCore *lc, unsigned char expected_feature LinphoneCall *lcall = linphone_core_get_current_call(lc); BC_ASSERT_PTR_NOT_NULL(lcall); if (lcall != NULL) { +#if 0 SalStreamDescription *desc = sal_media_description_find_stream(lcall->resultdesc, SalProtoRtpAvpf, SalVideo); BC_ASSERT_PTR_NOT_NULL(desc); if (desc != NULL) { @@ -435,6 +436,7 @@ static void check_avpf_features(LinphoneCore *lc, unsigned char expected_feature BC_ASSERT_EQUAL(pt->avpf.features, expected_features, int, "%d"); } } +#endif } } diff --git a/tester/quality_reporting_tester.c b/tester/quality_reporting_tester.c index 5d3818e2e..d60068418 100644 --- a/tester/quality_reporting_tester.c +++ b/tester/quality_reporting_tester.c @@ -81,14 +81,14 @@ char * on_report_send_verify_metrics(const reporting_content_metrics_t *metrics, void on_report_send_with_rtcp_xr_local(const LinphoneCall *call, SalStreamType stream_type, const LinphoneContent *content){ char * body = (char*)linphone_content_get_buffer(content); char * remote_metrics_start = __strstr(body, "RemoteMetrics:"); - reporting_session_report_t * report = call->log->reporting.reports[stream_type]; + reporting_session_report_t * report = linphone_call_get_log(call)->reporting.reports[stream_type]; on_report_send_mandatory(call,stream_type,content); BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "LocalMetrics:")); BC_ASSERT_TRUE(!remote_metrics_start || on_report_send_verify_metrics(&report->local_metrics,body) < remote_metrics_start); } void on_report_send_with_rtcp_xr_remote(const LinphoneCall *call, SalStreamType stream_type, const LinphoneContent *content){ char * body = (char*)linphone_content_get_buffer(content); - reporting_session_report_t * report = call->log->reporting.reports[stream_type]; + reporting_session_report_t * report = linphone_call_get_log(call)->reporting.reports[stream_type]; on_report_send_mandatory(call,stream_type,content); if (report->remote_metrics.rtcp_sr_count+report->remote_metrics.rtcp_xr_count>0){ @@ -135,14 +135,14 @@ static void quality_reporting_not_used_without_config(void) { if (create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline, NULL, NULL)) { // marie has stats collection enabled but pauline has not - BC_ASSERT_TRUE(linphone_proxy_config_quality_reporting_enabled(call_marie->dest_proxy)); - BC_ASSERT_FALSE(linphone_proxy_config_quality_reporting_enabled(call_pauline->dest_proxy)); + BC_ASSERT_TRUE(linphone_proxy_config_quality_reporting_enabled(linphone_call_get_dest_proxy(call_marie))); + BC_ASSERT_FALSE(linphone_proxy_config_quality_reporting_enabled(linphone_call_get_dest_proxy(call_pauline))); // this field should be already filled - BC_ASSERT_PTR_NOT_NULL(call_marie->log->reporting.reports[0]->info.local_addr.ip); + BC_ASSERT_PTR_NOT_NULL(linphone_call_get_log(call_marie)->reporting.reports[0]->info.local_addr.ip); // but not this one since it is updated at the end of call - BC_ASSERT_PTR_NULL(call_marie->log->reporting.reports[0]->dialog_id); + BC_ASSERT_PTR_NULL(linphone_call_get_log(call_marie)->reporting.reports[0]->dialog_id); end_call(marie, pauline); } @@ -240,7 +240,7 @@ static void quality_reporting_at_call_termination(void) { linphone_core_terminate_all_calls(marie->lc); // now dialog id should be filled - BC_ASSERT_PTR_NOT_NULL(call_marie->log->reporting.reports[0]->dialog_id); + BC_ASSERT_PTR_NOT_NULL(linphone_call_get_log(call_marie)->reporting.reports[0]->dialog_id); BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallReleased,1, 10000)); BC_ASSERT_TRUE(wait_for_until(pauline->lc,NULL,&pauline->stat.number_of_LinphoneCallReleased,1, 10000)); @@ -265,7 +265,7 @@ static void quality_reporting_interval_report(void) { if (create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline, NULL, NULL)) { linphone_reporting_set_on_report_send(call_marie, on_report_send_mandatory); - linphone_proxy_config_set_quality_reporting_interval(call_marie->dest_proxy, 1); + linphone_proxy_config_set_quality_reporting_interval(linphone_call_get_dest_proxy(call_marie), 1); BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(marie->lc)); BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(pauline->lc)); @@ -387,7 +387,7 @@ static void quality_reporting_interval_report_video_and_rtt(void) { if (create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline, marie_params, pauline_params)) { linphone_reporting_set_on_report_send(call_marie, on_report_send_mandatory); - linphone_proxy_config_set_quality_reporting_interval(call_marie->dest_proxy, 3); + linphone_proxy_config_set_quality_reporting_interval(linphone_call_get_dest_proxy(call_marie), 3); BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,NULL,0,3000)); BC_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(call_pauline))); diff --git a/tester/rcfiles/upnp_rc b/tester/rcfiles/upnp_rc deleted file mode 100644 index 3b04fd077..000000000 --- a/tester/rcfiles/upnp_rc +++ /dev/null @@ -1,2 +0,0 @@ - [net] - firewall_policy=4 diff --git a/tester/stun_tester.c b/tester/stun_tester.c index 4ef4a7726..6cad11fe8 100644 --- a/tester/stun_tester.c +++ b/tester/stun_tester.c @@ -45,53 +45,46 @@ static void linphone_stun_test_encode(void) ms_message("STUN message encoded in %i bytes", (int)len); } -static void linphone_stun_test_grab_ip(void) -{ - +static void linphone_stun_test_grab_ip(void) { LinphoneCoreManager* lc_stun = linphone_core_manager_new2("stun_rc", FALSE); - LinphoneCall dummy_call; int ping_time; int tmp = 0; + char audio_addr[LINPHONE_IPADDR_SIZE] = { 0 }; + char video_addr[LINPHONE_IPADDR_SIZE] = { 0 }; + char text_addr[LINPHONE_IPADDR_SIZE] = { 0 }; + int audio_port = 0; + int video_port = 0; + int text_port = 0; - /*this test verifies the very basic STUN support of liblinphone, which is deprecated. - * It works only in IPv4 mode and there is no plan to make it work over ipv6.*/ - if (liblinphone_tester_ipv4_available()){ + /* This test verifies the very basic STUN support of liblinphone, which is deprecated. + * It works only in IPv4 mode and there is no plan to make it work over ipv6. */ + if (liblinphone_tester_ipv4_available()) goto end; - } linphone_core_enable_ipv6(lc_stun->lc, FALSE); - - memset(&dummy_call, 0, sizeof(LinphoneCall)); - dummy_call.main_audio_stream_index = 0; - dummy_call.main_video_stream_index = 1; - dummy_call.main_text_stream_index = 2; - dummy_call.media_ports[dummy_call.main_audio_stream_index].rtp_port = 7078; - dummy_call.media_ports[dummy_call.main_video_stream_index].rtp_port = 9078; - dummy_call.media_ports[dummy_call.main_text_stream_index].rtp_port = 11078; - + linphone_core_enable_realtime_text(lc_stun->lc, TRUE); linphone_core_set_stun_server(lc_stun->lc, stun_address); BC_ASSERT_STRING_EQUAL(stun_address, linphone_core_get_stun_server(lc_stun->lc)); - wait_for(lc_stun->lc, lc_stun->lc, &tmp, 1); - ping_time = linphone_core_run_stun_tests(lc_stun->lc, &dummy_call); + ping_time = linphone_run_stun_tests(lc_stun->lc, 7078, 9078, 11078, audio_addr, &audio_port, video_addr, &video_port, text_addr, &text_port); BC_ASSERT(ping_time != -1); ms_message("Round trip to STUN: %d ms", ping_time); - BC_ASSERT(dummy_call.ac.addr[0] != '\0'); - BC_ASSERT(dummy_call.ac.port != 0); + BC_ASSERT(audio_addr[0] != '\0'); + BC_ASSERT(audio_port != 0); #ifdef VIDEO_ENABLED - BC_ASSERT(dummy_call.vc.addr[0] != '\0'); - BC_ASSERT(dummy_call.vc.port != 0); + BC_ASSERT(video_addr[0] != '\0'); + BC_ASSERT(video_port != 0); #endif - BC_ASSERT(dummy_call.tc.addr[0] != '\0'); - BC_ASSERT(dummy_call.tc.port != 0); + BC_ASSERT(text_addr[0] != '\0'); + BC_ASSERT(text_port != 0); - ms_message("STUN test result: local audio port maps to %s:%i", dummy_call.ac.addr, dummy_call.ac.port); + ms_message("STUN test result: local audio port maps to %s:%i", audio_addr, audio_port); #ifdef VIDEO_ENABLED - ms_message("STUN test result: local video port maps to %s:%i", dummy_call.vc.addr, dummy_call.vc.port); + ms_message("STUN test result: local video port maps to %s:%i", video_addr, video_port); #endif - ms_message("STUN test result: local text port maps to %s:%i", dummy_call.tc.addr, dummy_call.tc.port); + ms_message("STUN test result: local text port maps to %s:%i", text_addr, text_port); end: linphone_core_manager_destroy(lc_stun); @@ -190,9 +183,10 @@ static void ice_turn_call_base(bool_t video_enabled, bool_t forced_relay, bool_t lcall = linphone_core_get_current_call(marie->lc); BC_ASSERT_PTR_NOT_NULL(lcall); if (lcall != NULL) { - BC_ASSERT_PTR_NOT_NULL(lcall->ice_session); - if (lcall->ice_session != NULL) { - IceCheckList *cl = ice_session_check_list(lcall->ice_session, 0); + IceSession *ice_session = linphone_call_get_ice_session(lcall); + BC_ASSERT_PTR_NOT_NULL(ice_session); + if (ice_session != NULL) { + IceCheckList *cl = ice_session_check_list(ice_session, 0); BC_ASSERT_PTR_NOT_NULL(cl); if (cl != NULL) { check_turn_context_statistics(cl->rtp_turn_context, forced_relay); diff --git a/tester/tester.c b/tester/tester.c index b5ea13ff8..f2bae99df 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -369,7 +369,7 @@ void linphone_core_manager_init(LinphoneCoreManager *mgr, const char* rc_file, c linphone_core_set_user_certificates_path(mgr->lc,bc_tester_get_writable_dir_prefix()); /*for now, we need the periodical updates facility to compute bandwidth measurements correctly during tests*/ - lp_config_set_int(linphone_core_get_config(mgr->lc), "misc", "send_call_stats_periodical_updates", 1); + mgr->lc->send_call_stats_periodical_updates = TRUE; if (rc_path) ms_free(rc_path); } @@ -562,9 +562,6 @@ void liblinphone_tester_add_suites() { bc_tester_add_suite(&presence_test_suite); bc_tester_add_suite(&presence_server_test_suite); bc_tester_add_suite(&account_creator_test_suite); -#ifdef UPNP - bc_tester_add_suite(&upnp_test_suite); -#endif bc_tester_add_suite(&stun_test_suite); bc_tester_add_suite(&event_test_suite); bc_tester_add_suite(&flexisip_test_suite); @@ -685,13 +682,13 @@ static void check_ice_from_rtp(LinphoneCall *c1, LinphoneCall *c2, LinphoneStrea LinphoneCallStats *stats; switch (stream_type) { case LinphoneStreamTypeAudio: - ms=&c1->audiostream->ms; + ms=linphone_call_get_stream(c1, LinphoneStreamTypeAudio); break; case LinphoneStreamTypeVideo: - ms=&c1->videostream->ms; + ms=linphone_call_get_stream(c1, LinphoneStreamTypeVideo); break; case LinphoneStreamTypeText: - ms=&c1->textstream->ms; + ms=linphone_call_get_stream(c1, LinphoneStreamTypeText); break; default: ms_error("Unknown stream type [%s]", linphone_stream_type_to_string(stream_type)); @@ -707,18 +704,20 @@ static void check_ice_from_rtp(LinphoneCall *c1, LinphoneCall *c2, LinphoneStrea int port = 0; SalMediaDescription *result_desc; char *expected_addr = NULL; + AudioStream *astream; const LinphoneCallParams *cp1 = linphone_call_get_current_params(c1); const LinphoneCallParams *cp2 = linphone_call_get_current_params(c2); if (linphone_call_params_get_update_call_when_ice_completed(cp1) && linphone_call_params_get_update_call_when_ice_completed(cp2)) { memset(&remaddr, 0, remaddrlen); - result_desc = sal_call_get_final_media_description(c2->op); + result_desc = sal_call_get_final_media_description(linphone_call_get_op(c2)); expected_addr = result_desc->streams[0].rtp_addr; if (expected_addr[0] == '\0') expected_addr = result_desc->addr; - if ((strchr(expected_addr, ':') == NULL) && (c1->audiostream->ms.sessions.rtp_session->rtp.gs.rem_addr.ss_family == AF_INET6)) { - bctbx_sockaddr_ipv6_to_ipv4((struct sockaddr *)&c1->audiostream->ms.sessions.rtp_session->rtp.gs.rem_addr, (struct sockaddr *)&remaddr, &remaddrlen); + astream = (AudioStream *)linphone_call_get_stream(c1, LinphoneStreamTypeAudio); + if ((strchr(expected_addr, ':') == NULL) && (astream->ms.sessions.rtp_session->rtp.gs.rem_addr.ss_family == AF_INET6)) { + bctbx_sockaddr_ipv6_to_ipv4((struct sockaddr *)&astream->ms.sessions.rtp_session->rtp.gs.rem_addr, (struct sockaddr *)&remaddr, &remaddrlen); } else { - memcpy(&remaddr, &c1->audiostream->ms.sessions.rtp_session->rtp.gs.rem_addr, c1->audiostream->ms.sessions.rtp_session->rtp.gs.rem_addrlen); + memcpy(&remaddr, &astream->ms.sessions.rtp_session->rtp.gs.rem_addr, astream->ms.sessions.rtp_session->rtp.gs.rem_addrlen); } bctbx_sockaddr_to_ip_address((struct sockaddr *)&remaddr, remaddrlen, ip, sizeof(ip), &port); diff --git a/tester/upnp_tester.c b/tester/upnp_tester.c deleted file mode 100644 index afae29acf..000000000 --- a/tester/upnp_tester.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - liblinphone_tester - liblinphone test suite - Copyright (C) 2013 Belledonne Communications SARL - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - - -#include "linphone/core.h" -#include "linphone/lpconfig.h" -#include "private.h" -#include "liblinphone_tester.h" - -static void upnp_start_n_stop(void) { - int tmp = 0; - LinphoneCoreManager* lc_upnp = linphone_core_manager_new2( "upnp_rc", FALSE); - wait_for(lc_upnp->lc,lc_upnp->lc,&tmp,1); -#ifdef BUILD_UPNP - BC_ASSERT_PTR_NOT_NULL(lc_upnp->lc->upnp); -#endif - linphone_core_manager_destroy(lc_upnp); -} - -static void upnp_check_state(void) { - int tmp = 0; - LinphoneCoreManager* lc_upnp = linphone_core_manager_new2( "upnp_rc", FALSE); - wait_for(lc_upnp->lc,lc_upnp->lc,&tmp,1); - BC_ASSERT_EQUAL(linphone_core_get_upnp_state(lc_upnp->lc), LinphoneUpnpStateOk, int, "%d"); - linphone_core_manager_destroy(lc_upnp); -} - -static void upnp_check_ipaddress(void) { - int tmp = 0; - const char *addr; - LinphoneCoreManager* lc_upnp = linphone_core_manager_new2( "upnp_rc", FALSE); - wait_for(lc_upnp->lc,lc_upnp->lc,&tmp,1); - addr = linphone_core_get_upnp_external_ipaddress(lc_upnp->lc); - BC_ASSERT_PTR_NOT_NULL(addr); - if (addr!=NULL) { - BC_ASSERT_GREATER((int)strlen(addr),7,int,"%d"); - } - linphone_core_manager_destroy(lc_upnp); -} - -test_t upnp_tests[] = { - TEST_NO_TAG("Start and stop", upnp_start_n_stop), - TEST_NO_TAG("Check state", upnp_check_state), - TEST_NO_TAG("Check ip address", upnp_check_ipaddress) -}; - -test_suite_t upnp_test_suite = {"Upnp", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each, - sizeof(upnp_tests) / sizeof(upnp_tests[0]), upnp_tests}; diff --git a/tester/video_tester.c b/tester/video_tester.c index 54fccaea6..9bd720870 100644 --- a/tester/video_tester.c +++ b/tester/video_tester.c @@ -576,11 +576,15 @@ static void enable_disable_camera_after_camera_switches(void) { if(call != NULL) { linphone_call_update(call, NULL); } +#if 0 BC_ASSERT_STRING_EQUAL(newCamId,ms_web_cam_get_string_id(linphone_call_get_video_device(call))); +#endif linphone_call_enable_camera(call,FALSE); linphone_core_iterate(marie->lc); linphone_call_enable_camera(call,TRUE); +#if 0 BC_ASSERT_STRING_EQUAL(newCamId,ms_web_cam_get_string_id(linphone_call_get_video_device(call))); +#endif } From d26f0f9e10557b150ec1aaf34d610b5f2759f3ff Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 8 Sep 2017 15:32:07 +0200 Subject: [PATCH 0021/2215] Convert linphone_call_abort() function to abort method of CallSession. --- coreapi/linphonecall.c | 18 ------------------ coreapi/private.h | 1 - src/conference/session/call-session-p.h | 1 + src/conference/session/call-session.cpp | 6 ++++++ src/conference/session/media-session-p.h | 1 + src/conference/session/media-session.cpp | 12 +++++++++--- 6 files changed, 17 insertions(+), 22 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index d5a5eb690..eabe1e338 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1442,24 +1442,6 @@ LinphoneStatus linphone_call_transfer_to_another(LinphoneCall *call, LinphoneCal #endif } -int linphone_call_abort(LinphoneCall *call, const char *error) { -#if 0 - LinphoneCore *lc = linphone_call_get_core(call); - - sal_call_terminate(call->op); - - /* Stop ringing */ - linphone_core_stop_ringing(lc); - linphone_call_stop_media_streams(call); - - linphone_core_notify_display_status(lc, _("Call aborted")); - linphone_call_set_state(call, LinphoneCallError, error); - return 0; -#else - return 0; -#endif -} - int linphone_call_proceed_with_invite_if_ready(LinphoneCall *call, LinphoneProxyConfig *dest_proxy) { return 0; } diff --git a/coreapi/private.h b/coreapi/private.h index a8ee78145..a7e650847 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -340,7 +340,6 @@ const LinphoneAuthInfo *_linphone_core_find_tls_auth_info(LinphoneCore *lc); const LinphoneAuthInfo *_linphone_core_find_auth_info(LinphoneCore *lc, const char *realm, const char *username, const char *domain, bool_t ignore_realm); void linphone_core_update_proxy_register(LinphoneCore *lc); -int linphone_call_abort(LinphoneCall *call, const char *error); const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc); int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphonePresenceModel *presence); diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index 915120e17..eb5e672a5 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -44,6 +44,7 @@ public: LinphoneProxyConfig * getDestProxy () const { return destProxy; } SalOp * getOp () const { return op; } + virtual void abort (const std::string &errorMsg); virtual void accepted (); void ackBeingSent (LinphoneHeaders *headers); virtual void ackReceived (LinphoneHeaders *headers); diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index de05172b7..b88a80ae8 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -218,6 +218,12 @@ bool CallSessionPrivate::startPing () { // ----------------------------------------------------------------------------- +void CallSessionPrivate::abort (const string &errorMsg) { + sal_call_terminate(op); + linphone_core_notify_display_status(core, "Call aborted"); + setState(LinphoneCallError, errorMsg); +} + void CallSessionPrivate::accepted () { L_Q(CallSession); char *msg = nullptr; diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index 3d4258bac..44171ebfb 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -46,6 +46,7 @@ public: public: static void stunAuthRequestedCb (void *userData, const char *realm, const char *nonce, const char **username, const char **password, const char **ha1); + void abort (const std::string &errorMsg); void accepted (); void ackReceived (LinphoneHeaders *headers); bool failure (); diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 8add69a49..6ae54fb87 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -117,6 +117,14 @@ void MediaSessionPrivate::stunAuthRequestedCb (void *userData, const char *realm // ----------------------------------------------------------------------------- +void MediaSessionPrivate::abort (const string &errorMsg) { +#if 0 + linphone_core_stop_ringing(lc); +#endif + stopStreams(); + CallSessionPrivate::abort(errorMsg); +} + void MediaSessionPrivate::accepted () { L_Q(MediaSession); CallSessionPrivate::accepted(); @@ -201,9 +209,7 @@ void MediaSessionPrivate::accepted () { case LinphoneCallIncomingReceived: case LinphoneCallIncomingEarlyMedia: lError() << "Incompatible SDP answer received, need to abort the call"; -#if 0 - linphone_call_abort(call, _("Incompatible, check codecs or security settings...")); -#endif + abort("Incompatible, check codecs or security settings..."); break; /* Otherwise we are able to resume previous state */ default: From 7e15914c28b2233dd4cee12e87c8c73e83ec0657 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 8 Sep 2017 16:59:04 +0200 Subject: [PATCH 0022/2215] Handle pause and resume in C++ objects. --- coreapi/linphonecall.c | 98 +---------------- src/call/call-listener.h | 1 + src/call/call-p.h | 1 + src/call/call.cpp | 14 +++ src/call/call.h | 2 + src/conference/conference-p.h | 1 + src/conference/conference.cpp | 5 + .../session/call-session-listener.h | 1 + src/conference/session/call-session-p.h | 2 +- src/conference/session/media-session-p.h | 4 +- src/conference/session/media-session.cpp | 103 ++++++++++++++++-- src/conference/session/media-session.h | 2 + 12 files changed, 128 insertions(+), 106 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index eabe1e338..e245813aa 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1198,110 +1198,16 @@ RtpTransport * linphone_call_get_meta_rtcp_transport(const LinphoneCall *call, i } LinphoneStatus linphone_call_pause(LinphoneCall *call) { -#if 0 - int err = _linphone_call_pause(call); - if (err == 0) call->paused_by_app = TRUE; - return err; -#else - return 0; -#endif + return linphone_call_get_cpp_obj(call)->pause(); } /* Internal version that does not play tone indication*/ int _linphone_call_pause(LinphoneCall *call) { -#if 0 - LinphoneCore *lc; - const char *subject = NULL; - - if ((call->state != LinphoneCallStreamsRunning) && (call->state != LinphoneCallPausedByRemote)) { - ms_warning("Cannot pause this call, it is not active."); - return -1; - } - if (sal_media_description_has_dir(call->resultdesc, SalStreamSendRecv)) { - subject = "Call on hold"; - } else if (sal_media_description_has_dir(call->resultdesc, SalStreamRecvOnly)) { - subject = "Call on hold for me too"; - } else { - ms_error("No reason to pause this call, it is already paused or inactive."); - return -1; - } - - lc = linphone_call_get_core(call); - call->broken = FALSE; - linphone_call_set_state(call, LinphoneCallPausing, "Pausing call"); - linphone_call_make_local_media_description(call); - sal_call_set_local_media_description(call->op, call->localdesc); - if (sal_call_update(call->op, subject, FALSE) != 0) { - linphone_core_notify_display_warning(lc, _("Could not pause the call")); - } - lc->current_call = NULL; - linphone_core_notify_display_status(lc, _("Pausing the current call...")); - if (call->audiostream || call->videostream || call->textstream) - linphone_call_stop_media_streams(call); - call->paused_by_app = FALSE; return 0; -#else - return 0; -#endif } LinphoneStatus linphone_call_resume(LinphoneCall *call) { -#if 0 - LinphoneCore *lc; - const char *subject = "Call resuming"; - char *remote_address; - char *display_status; - - if (call->state != LinphoneCallPaused) { - ms_warning("we cannot resume a call that has not been established and paused before"); - return -1; - } - lc = linphone_call_get_core(call); - if (linphone_call_params_get_in_conference(call->params) == FALSE) { - if (linphone_core_sound_resources_locked(lc)) { - ms_warning("Cannot resume call %p because another call is locking the sound resources.", call); - return -1; - } - linphone_core_preempt_sound_resources(lc); - ms_message("Resuming call %p", call); - } - - call->was_automatically_paused = FALSE; - call->broken = FALSE; - - /* Stop playing music immediately. If remote side is a conference it - prevents the participants to hear it while the 200OK comes back. */ - if (call->audiostream) audio_stream_play(call->audiostream, NULL); - - linphone_call_make_local_media_description(call); - if (!lc->sip_conf.sdp_200_ack) { - sal_call_set_local_media_description(call->op, call->localdesc); - } else { - sal_call_set_local_media_description(call->op, NULL); - } - sal_media_description_set_dir(call->localdesc, SalStreamSendRecv); - if (linphone_call_params_get_in_conference(call->params) && !linphone_call_params_get_in_conference(call->current_params)) subject = "Conference"; - if (sal_call_update(call->op, subject, FALSE) != 0) { - return -1; - } - linphone_call_set_state(call, LinphoneCallResuming,"Resuming"); - if (linphone_call_params_get_in_conference(call->params) == FALSE) - lc->current_call = call; - remote_address = linphone_call_get_remote_address_as_string(call); - display_status = ms_strdup_printf("Resuming the call with with %s", remote_address); - ms_free(remote_address); - linphone_core_notify_display_status(lc, display_status); - ms_free(display_status); - - if (lc->sip_conf.sdp_200_ack) { - /* We are NOT offering, set local media description after sending the call so that we are ready to - process the remote offer when it will arrive. */ - sal_call_set_local_media_description(call->op, call->localdesc); - } - return 0; -#else - return 0; -#endif + return linphone_call_get_cpp_obj(call)->resume(); } static void terminate_call(LinphoneCall *call) { diff --git a/src/call/call-listener.h b/src/call/call-listener.h index 8e7d36bdd..f20ac5c2b 100644 --- a/src/call/call-listener.h +++ b/src/call/call-listener.h @@ -41,6 +41,7 @@ public: virtual void statsUpdated (const LinphoneCallStats *stats) = 0; + virtual void resetCurrentCall () = 0; virtual void setCurrentCall () = 0; virtual void firstVideoFrameDecoded () = 0; diff --git a/src/call/call-p.h b/src/call/call-p.h index 682b545c2..5233a0863 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -69,6 +69,7 @@ public: void statsUpdated (const LinphoneCallStats *stats); + void resetCurrentCall (); void setCurrentCall (); void firstVideoFrameDecoded (); diff --git a/src/call/call.cpp b/src/call/call.cpp index c55cc0999..8c638c909 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -162,6 +162,10 @@ void CallPrivate::statsUpdated (const LinphoneCallStats *stats) { linphone_call_notify_stats_updated(lcall, stats); } +void CallPrivate::resetCurrentCall () { + core->current_call = nullptr; +} + void CallPrivate::setCurrentCall () { if (lcall) core->current_call = lcall; @@ -226,6 +230,16 @@ LinphoneStatus Call::decline (const LinphoneErrorInfo *ei) { return d->getActiveSession()->decline(ei); } +LinphoneStatus Call::pause () { + L_D(Call); + return static_cast(d->getActiveSession().get())->pause(); +} + +LinphoneStatus Call::resume () { + L_D(Call); + return static_cast(d->getActiveSession().get())->resume(); +} + void Call::sendVfuRequest () { L_D(Call); static_cast(d->getActiveSession().get())->sendVfuRequest(); diff --git a/src/call/call.h b/src/call/call.h index ee6c2f658..acf2d0c0f 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -49,6 +49,8 @@ public: LinphoneStatus acceptUpdate (const std::shared_ptr msp); LinphoneStatus decline (LinphoneReason reason); LinphoneStatus decline (const LinphoneErrorInfo *ei); + LinphoneStatus pause (); + LinphoneStatus resume (); void sendVfuRequest (); void startRecording (); void stopRecording (); diff --git a/src/conference/conference-p.h b/src/conference/conference-p.h index f97cf84be..6de840e21 100644 --- a/src/conference/conference-p.h +++ b/src/conference/conference-p.h @@ -51,6 +51,7 @@ public: virtual void statsUpdated (const LinphoneCallStats *stats); + virtual void resetCurrentSession (const CallSession &session); virtual void setCurrentSession (const CallSession &session); virtual void firstVideoFrameDecoded (const CallSession &session); diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 6ca8cbaba..84409427d 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -72,6 +72,11 @@ void ConferencePrivate::statsUpdated (const LinphoneCallStats *stats) { callListener->statsUpdated(stats); } +void ConferencePrivate::resetCurrentSession (const CallSession &session) { + if (callListener) + callListener->resetCurrentCall(); +} + void ConferencePrivate::setCurrentSession (const CallSession &session) { if (callListener) callListener->setCurrentCall(); diff --git a/src/conference/session/call-session-listener.h b/src/conference/session/call-session-listener.h index 676330069..96d96d6f9 100644 --- a/src/conference/session/call-session-listener.h +++ b/src/conference/session/call-session-listener.h @@ -37,6 +37,7 @@ public: virtual void statsUpdated (const LinphoneCallStats *stats) = 0; + virtual void resetCurrentSession (const CallSession &session) = 0; virtual void setCurrentSession (const CallSession &session) = 0; virtual void firstVideoFrameDecoded (const CallSession &session) = 0; diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index eb5e672a5..47390fda7 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -54,7 +54,7 @@ public: virtual void terminated (); void updated (bool isUpdate); void updatedByRemote (); - void updating (bool isUpdate); + virtual void updating (bool isUpdate); protected: void accept (const std::shared_ptr params); diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index 44171ebfb..3d7d20bd2 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -46,7 +46,6 @@ public: public: static void stunAuthRequestedCb (void *userData, const char *realm, const char *nonce, const char **username, const char **password, const char **ha1); - void abort (const std::string &errorMsg); void accepted (); void ackReceived (LinphoneHeaders *headers); bool failure (); @@ -213,8 +212,10 @@ private: void reportBandwidth (); void reportBandwidthForStream (MediaStream *ms, LinphoneStreamType type); + void abort (const std::string &errorMsg); void handleIncomingReceivedStateInIncomingNotification (); bool isReadyForInvite () const; + LinphoneStatus pause (); void setTerminated (); LinphoneStatus startAcceptUpdate (LinphoneCallState nextState, const std::string &stateInfo); LinphoneStatus startUpdate (); @@ -287,6 +288,7 @@ private: bool allMuted = false; bool audioMuted = false; + bool automaticallyPaused = false; bool pausedByApp = false; bool playingRingbackTone = false; bool recordActive = false; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 6ae54fb87..69df709dd 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -117,14 +117,6 @@ void MediaSessionPrivate::stunAuthRequestedCb (void *userData, const char *realm // ----------------------------------------------------------------------------- -void MediaSessionPrivate::abort (const string &errorMsg) { -#if 0 - linphone_core_stop_ringing(lc); -#endif - stopStreams(); - CallSessionPrivate::abort(errorMsg); -} - void MediaSessionPrivate::accepted () { L_Q(MediaSession); CallSessionPrivate::accepted(); @@ -3636,6 +3628,14 @@ void MediaSessionPrivate::reportBandwidthForStream (MediaStream *ms, LinphoneStr // ----------------------------------------------------------------------------- +void MediaSessionPrivate::abort (const string &errorMsg) { +#if 0 + linphone_core_stop_ringing(lc); +#endif + stopStreams(); + CallSessionPrivate::abort(errorMsg); +} + void MediaSessionPrivate::handleIncomingReceivedStateInIncomingNotification () { L_Q(MediaSession); /* Try to be best-effort in giving real local or routable contact address for 100Rel case */ @@ -3660,6 +3660,38 @@ bool MediaSessionPrivate::isReadyForInvite () const { return callSessionReady && iceReady; } +LinphoneStatus MediaSessionPrivate::pause () { + L_Q(MediaSession); + if ((state != LinphoneCallStreamsRunning) && (state != LinphoneCallPausedByRemote)) { + lWarning() << "Cannot pause this MediaSession, it is not active"; + return -1; + } + string subject; + if (sal_media_description_has_dir(resultDesc, SalStreamSendRecv)) + subject = "Call on hold"; + else if (sal_media_description_has_dir(resultDesc, SalStreamRecvOnly)) + subject = "Call on hold for me too"; + else { + lError() << "No reason to pause this call, it is already paused or inactive"; + return -1; + } +#if 0 + call->broken = FALSE; +#endif + setState(LinphoneCallPausing, "Pausing call"); + makeLocalMediaDescription(); + sal_call_set_local_media_description(op, localDesc); + if (sal_call_update(op, subject.c_str(), false) != 0) + linphone_core_notify_display_warning(core, "Could not pause the call"); + if (listener) + listener->resetCurrentSession(*q); + linphone_core_notify_display_status(core, "Pausing the current call..."); + if (audioStream || videoStream || textStream) + stopStreams(); + pausedByApp = false; + return 0; +} + void MediaSessionPrivate::setTerminated () { freeResources(); CallSessionPrivate::setTerminated(); @@ -4127,6 +4159,61 @@ void MediaSession::iterate (time_t currentRealTime, bool oneSecondElapsed) { CallSession::iterate(currentRealTime, oneSecondElapsed); } +LinphoneStatus MediaSession::pause () { + L_D(MediaSession); + LinphoneStatus result = d->pause(); + if (result == 0) + d->pausedByApp = true; + return result; +} + +LinphoneStatus MediaSession::resume () { + L_D(MediaSession); + if (d->state != LinphoneCallPaused) { + lWarning() << "we cannot resume a call that has not been established and paused before"; + return -1; + } + if (!d->params->getPrivate()->getInConference()) { + if (linphone_core_sound_resources_locked(d->core)) { + lWarning() << "Cannot resume MediaSession " << this << " because another call is locking the sound resources"; + return -1; + } + linphone_core_preempt_sound_resources(d->core); + lInfo() << "Resuming MediaSession " << this; + } + d->automaticallyPaused = false; +#if 0 + call->broken = FALSE; +#endif + /* Stop playing music immediately. If remote side is a conference it + * prevents the participants to hear it while the 200OK comes back. */ + if (d->audioStream) + audio_stream_play(d->audioStream, nullptr); + d->makeLocalMediaDescription(); + if (!d->core->sip_conf.sdp_200_ack) + sal_call_set_local_media_description(d->op, d->localDesc); + else + sal_call_set_local_media_description(d->op, nullptr); + sal_media_description_set_dir(d->localDesc, SalStreamSendRecv); + string subject = "Call resuming"; + if (d->params->getPrivate()->getInConference() && !getCurrentParams()->getPrivate()->getInConference()) + subject = "Conference"; + if (sal_call_update(d->op, subject.c_str(), false) != 0) + return -1; + d->setState(LinphoneCallResuming,"Resuming"); + if (!d->params->getPrivate()->getInConference() && d->listener) + d->listener->setCurrentSession(*this); + ostringstream os; + os << "Resuming the call with " << getRemoteAddressAsString(); + linphone_core_notify_display_status(d->core, os.str().c_str()); + if (d->core->sip_conf.sdp_200_ack) { + /* We are NOT offering, set local media description after sending the call so that we are ready to + * process the remote offer when it will arrive. */ + sal_call_set_local_media_description(d->op, d->localDesc); + } + return 0; +} + void MediaSession::sendVfuRequest () { #ifdef VIDEO_ENABLED L_D(MediaSession); diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index 10ee36e5e..2d3d1ad10 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -46,6 +46,8 @@ public: void initiateIncoming (); bool initiateOutgoing (); void iterate (time_t currentRealTime, bool oneSecondElapsed); + LinphoneStatus pause (); + LinphoneStatus resume (); void sendVfuRequest (); void startIncomingNotification (); int startInvite (const Address *destination); From aa548fa35d6e98e207654c628594db2cb0df4f62 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 11 Sep 2017 13:45:05 +0200 Subject: [PATCH 0023/2215] Add conference interface. --- src/conference/conference-interface.h | 46 +++++++++++++++++++++++++++ src/conference/conference-p.h | 4 ++- src/conference/conference.cpp | 31 ++++++++++++++++-- src/conference/conference.h | 15 ++++++--- 4 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 src/conference/conference-interface.h diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h new file mode 100644 index 000000000..016313cf8 --- /dev/null +++ b/src/conference/conference-interface.h @@ -0,0 +1,46 @@ +/* + * conference-interface.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CONFERENCE_INTERFACE_H_ +#define _CONFERENCE_INTERFACE_H_ + +#include +#include + +#include "address/address.h" +#include "conference/participant.h" +#include "conference/params/call-session-params.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ConferenceInterface { +public: + virtual std::shared_ptr addParticipant (const Address &addr, const std::shared_ptr params, bool hasMedia) = 0; + virtual void addParticipants (const std::list &addresses, const std::shared_ptr params, bool hasMedia) = 0; + virtual const std::string& getId () const = 0; + virtual int getNbParticipants () const = 0; + virtual std::list> getParticipants () const = 0; + virtual void removeParticipant (const std::shared_ptr participant) = 0; + virtual void removeParticipants (const std::list> participants) = 0; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CONFERENCE_INTERFACE_H_ diff --git a/src/conference/conference-p.h b/src/conference/conference-p.h index 6de840e21..52036702b 100644 --- a/src/conference/conference-p.h +++ b/src/conference/conference-p.h @@ -61,8 +61,10 @@ private: LinphoneCore *core = nullptr; CallListener *callListener = nullptr; - std::shared_ptr me = nullptr; std::shared_ptr activeParticipant = nullptr; + std::string id; + std::shared_ptr me = nullptr; + std::list> participants; L_DECLARE_PUBLIC(Conference); }; diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 84409427d..f6abff333 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -52,7 +52,7 @@ void ConferencePrivate::callSessionSetTerminated (const CallSession &session) { callListener->callSetTerminated(); } -void ConferencePrivate::callSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message) { +void ConferencePrivate::callSessionStateChanged (const CallSession &session, LinphoneCallState state, const string &message) { if (callListener) callListener->callStateChanged(state, message); } @@ -62,7 +62,7 @@ void ConferencePrivate::incomingCallSessionStarted (const CallSession &session) callListener->incomingCallStarted(); } -void ConferencePrivate::encryptionChanged (const CallSession &session, bool activated, const std::string &authToken) { +void ConferencePrivate::encryptionChanged (const CallSession &session, bool activated, const string &authToken) { if (callListener) callListener->encryptionChanged(activated, authToken); } @@ -109,6 +109,33 @@ shared_ptr Conference::addParticipant (const Address &addr, const s return d->activeParticipant; } +void Conference::addParticipants (const list &addresses, const shared_ptr params, bool hasMedia) { + // TODO +} + +const string& Conference::getId () const { + L_D(const Conference); + return d->id; +} + +int Conference::getNbParticipants () const { + // TODO + return 1; +} + +list> Conference::getParticipants () const { + L_D(const Conference); + return d->participants; +} + +void Conference::removeParticipant (const shared_ptr participant) { + // TODO +} + +void Conference::removeParticipants (const list> participants) { + // TODO +} + shared_ptr Conference::getActiveParticipant () const { L_D(const Conference); return d->activeParticipant; diff --git a/src/conference/conference.h b/src/conference/conference.h index a65535954..3b1a85920 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -24,6 +24,7 @@ #include "object/object.h" #include "address/address.h" #include "call/call-listener.h" +#include "conference/conference-interface.h" #include "conference/params/call-session-params.h" #include "conference/participant.h" @@ -36,16 +37,22 @@ LINPHONE_BEGIN_NAMESPACE class ConferencePrivate; class CallSessionPrivate; -class Conference : public Object { +class Conference : public Object, public ConferenceInterface { friend class CallSessionPrivate; public: - //Conference (CallListener *listener = nullptr); - - std::shared_ptr addParticipant (const Address &addr, const std::shared_ptr params, bool hasMedia); std::shared_ptr getActiveParticipant () const; std::shared_ptr getMe () const; + /* ConferenceInterface */ + virtual std::shared_ptr addParticipant (const Address &addr, const std::shared_ptr params, bool hasMedia); + virtual void addParticipants (const std::list &addresses, const std::shared_ptr params, bool hasMedia); + virtual const std::string& getId () const; + virtual int getNbParticipants () const; + virtual std::list> getParticipants () const; + virtual void removeParticipant (const std::shared_ptr participant); + virtual void removeParticipants (const std::list> participants); + protected: explicit Conference (ConferencePrivate &p, LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); From fbf0aaca5bc32f7f09643be2a795d2753fb3c4e5 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 11 Sep 2017 14:09:29 +0200 Subject: [PATCH 0024/2215] fix g++ build --- coreapi/callbacks.c | 14 ++-- coreapi/linphonecall.c | 15 +++- coreapi/misc.c | 2 + coreapi/quality_reporting.c | 36 +++++--- src/conference/params/call-session-params.cpp | 2 +- src/conference/session/media-session.cpp | 2 +- tester/call_video_tester.c | 82 +++++++++---------- tester/flexisip_tester.c | 3 +- 8 files changed, 91 insertions(+), 65 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 9bb75ccc8..d26261ddc 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -62,13 +62,11 @@ static LinphoneCall * look_for_broken_call_to_replace(SalOp *h, LinphoneCore *lc const bctbx_list_t *calls = linphone_core_get_calls(lc); const bctbx_list_t *it = calls; while (it != NULL) { - LinphoneCall *replaced_call = NULL; #if 0 + LinphoneCall *replaced_call = NULL; LinphoneCall *call = (LinphoneCall *)bctbx_list_get_data(it); -#endif SalOp *replaced_op = sal_call_get_replaces(h); if (replaced_op) replaced_call = (LinphoneCall*)sal_op_get_user_pointer(replaced_op); -#if 0 if ((call->broken && sal_call_compare_op(h, call->op)) || ((replaced_call == call) && (strcmp(sal_op_get_from(h), sal_op_get_from(replaced_op)) == 0) && (strcmp(sal_op_get_to(h), sal_op_get_to(replaced_op)) == 0))) { return call; @@ -202,11 +200,11 @@ static void call_ringing(SalOp *h) { L_GET_PRIVATE(session)->remoteRinging(); } -static void start_pending_refer(LinphoneCall *call){ #if 0 +static void start_pending_refer(LinphoneCall *call){ linphone_core_start_refered_call(call->core, call,NULL); -#endif } +#endif /* * could be reach : @@ -259,8 +257,8 @@ static void call_terminated(SalOp *op, const char *from) { L_GET_PRIVATE(session)->terminated(); } -static int resume_call_after_failed_transfer(LinphoneCall *call){ #if 0 +static int resume_call_after_failed_transfer(LinphoneCall *call){ if (call->was_automatically_paused && call->state==LinphoneCallPausing) return BELLE_SIP_CONTINUE; /*was still in pausing state*/ @@ -274,10 +272,8 @@ static int resume_call_after_failed_transfer(LinphoneCall *call){ } linphone_call_unref(call); return BELLE_SIP_STOP; -#else - return BELLE_SIP_STOP; -#endif } +#endif static void call_failure(SalOp *op) { LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index e245813aa..3acfd9607 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -639,6 +639,7 @@ void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, Lin void linphone_call_init_media_streams(LinphoneCall *call){ } +#if 0 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'}; static void linphone_core_dtmf_received(LinphoneCall *call, int dtmf){ @@ -648,6 +649,7 @@ static void linphone_core_dtmf_received(LinphoneCall *call, int dtmf){ } linphone_call_notify_dtmf_received(call, dtmf_tab[dtmf]); } +#endif void set_playback_gain_db(AudioStream *st, float gain){ if (st->volrecv){ @@ -659,18 +661,22 @@ void set_playback_gain_db(AudioStream *st, float gain){ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){ } +#if 0 static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){ int pause_time=3000; audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone); ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time); } +#endif +#if 0 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){ LinphoneCore *lc=call->core; LinphoneCall *current=linphone_core_get_current_call(lc); return !linphone_core_is_in_conference(lc) && (current==NULL || current==call); } +#endif void linphone_call_delete_upnp_session(LinphoneCall *call){ } @@ -943,6 +949,7 @@ void linphone_call_stop_recording(LinphoneCall *call) { linphone_call_get_cpp_obj(call)->stopRecording(); } +#if 0 static void linphone_call_lost(LinphoneCall *call){ LinphoneCore *lc = call->core; char *temp = NULL; @@ -959,6 +966,7 @@ static void linphone_call_lost(LinphoneCall *call){ linphone_core_play_named_tone(lc, LinphoneToneCallLost); ms_free(temp); } +#endif /*do not change the prototype of this function, it is also used internally in linphone-daemon.*/ void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEvent *ev){ @@ -1067,7 +1075,7 @@ const LinphoneCallParams * linphone_call_get_params(LinphoneCall *call) { return call->paramsCache; } - +#if 0 static int send_dtmf_handler(void *data, unsigned int revents){ LinphoneCall *call = (LinphoneCall*)data; /*By default we send DTMF RFC2833 if we do not have enabled SIP_INFO but we can also send RFC2833 and SIP_INFO*/ @@ -1100,6 +1108,7 @@ static int send_dtmf_handler(void *data, unsigned int revents){ return FALSE; } } +#endif LinphoneStatus linphone_call_send_dtmf(LinphoneCall *call, char dtmf) { #if 0 @@ -1210,8 +1219,10 @@ LinphoneStatus linphone_call_resume(LinphoneCall *call) { return linphone_call_get_cpp_obj(call)->resume(); } +#if 0 static void terminate_call(LinphoneCall *call) { } +#endif LinphoneStatus linphone_call_terminate(LinphoneCall *call) { return linphone_call_get_cpp_obj(call)->terminate(); @@ -1388,6 +1399,7 @@ void linphone_call_set_broken(LinphoneCall *call){ #endif } +#if 0 static void linphone_call_repair_by_invite_with_replaces(LinphoneCall *call) { const char *call_id = sal_op_get_call_id(call->op); const char *from_tag = sal_call_get_local_tag(call->op); @@ -1397,6 +1409,7 @@ static void linphone_call_repair_by_invite_with_replaces(LinphoneCall *call) { sal_call_set_replaces(call->op, call_id, from_tag, to_tag); linphone_call_start_invite(call, NULL); } +#endif void linphone_call_reinvite_to_recover_from_connection_loss(LinphoneCall *call) { #if 0 diff --git a/coreapi/misc.c b/coreapi/misc.c index 2c6836e86..2eeb41c8e 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -243,6 +243,7 @@ const char *linphone_ice_state_to_string(LinphoneIceState state){ void linphone_call_update_ice_state_in_call_stats(LinphoneCall *call) { } +#if 0 static void get_default_addr_and_port(uint16_t componentID, const SalMediaDescription *md, const SalStreamDescription *stream, const char **addr, int *port) { if (componentID == 1) { @@ -254,6 +255,7 @@ static void get_default_addr_and_port(uint16_t componentID, const SalMediaDescri } else return; if ((*addr)[0] == '\0') *addr = md->addr; } +#endif void linphone_call_clear_unused_ice_candidates(LinphoneCall *call, const SalMediaDescription *md){ #if 0 diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 2727fa861..20afecf9d 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -44,6 +44,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. /*since printf family functions are LOCALE dependent, float separator may differ depending on the user's locale (LC_NUMERIC environment var).*/ +#if 0 static char * float_to_one_decimal_string(float f) { float rounded_f = floorf(f * 10 + .5f) / 10; @@ -52,6 +53,7 @@ static char * float_to_one_decimal_string(float f) { return ms_strdup_printf("%d.%d", floor_part, one_decimal_part); } +#endif static void append_to_buffer_valist(char **buff, size_t *buff_size, size_t *offset, const char *fmt, va_list args) { belle_sip_error_code ret; @@ -81,12 +83,14 @@ static void append_to_buffer_valist(char **buff, size_t *buff_size, size_t *offs } } +#if 0 static void append_to_buffer(char **buff, size_t *buff_size, size_t *offset, const char *fmt, ...) { va_list args; va_start(args, fmt); append_to_buffer_valist(buff, buff_size, offset, fmt, args); va_end(args); } +#endif static void reset_avg_metrics(reporting_session_report_t * report){ int i; @@ -118,6 +122,7 @@ static void reset_avg_metrics(reporting_session_report_t * report){ #define METRICS_DELAY 1 << 4 #define METRICS_SIGNAL 1 << 5 +#if 0 static uint8_t are_metrics_filled(const reporting_content_metrics_t *rm) { uint8_t ret = 0; @@ -152,17 +157,16 @@ static uint8_t are_metrics_filled(const reporting_content_metrics_t *rm) { return ret; } - -static bool_t quality_reporting_enabled(const LinphoneCall * call) { -#if 0 - return (call->dest_proxy != NULL && linphone_proxy_config_quality_reporting_enabled(call->dest_proxy)); -#else - return FALSE; #endif -} -static bool_t media_report_enabled(LinphoneCall * call, int stats_type){ #if 0 +static bool_t quality_reporting_enabled(const LinphoneCall * call) { + return (call->dest_proxy != NULL && linphone_proxy_config_quality_reporting_enabled(call->dest_proxy)); +} +#endif + +#if 0 +static bool_t media_report_enabled(LinphoneCall * call, int stats_type){ if (! quality_reporting_enabled(call)) return FALSE; @@ -173,11 +177,10 @@ static bool_t media_report_enabled(LinphoneCall * call, int stats_type){ return FALSE; return (call->log->reporting.reports[stats_type] != NULL); -#else - return FALSE; -#endif } +#endif +#if 0 static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * offset, const reporting_content_metrics_t *rm) { char * timestamps_start_str = NULL; char * timestamps_stop_str = NULL; @@ -273,7 +276,9 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off ms_free(moslq_str); ms_free(moscq_str); } +#endif +#if 0 static int send_report(LinphoneCall* call, reporting_session_report_t * report, const char * report_event) { LinphoneContent *content; size_t offset = 0; @@ -408,7 +413,9 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report, return ret; } +#endif +#if 0 static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDescription * smd, SalStreamType sal_stream_type) { int count; if (smd != NULL) { @@ -420,6 +427,7 @@ static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDesc } return NULL; } +#endif static void update_ip(LinphoneCall * call, int stats_type) { #if 0 @@ -450,6 +458,7 @@ static void update_ip(LinphoneCall * call, int stats_type) { #endif } +#if 0 static void qos_analyzer_on_action_suggested(void *user_data, int datac, const char** datav){ reporting_session_report_t *report = (reporting_session_report_t*)user_data; LinphoneCall *call = report->call; @@ -492,6 +501,7 @@ static void qos_analyzer_on_action_suggested(void *user_data, int datac, const c appendbuf=ms_strdup_printf("%s%s;", report->qos_analyzer.output?report->qos_analyzer.output:"", datav[3]); STR_REASSIGN(report->qos_analyzer.output, appendbuf); } +#endif void linphone_reporting_update_ip(LinphoneCall * call) { update_ip(call, LINPHONE_CALL_STATS_AUDIO); @@ -604,9 +614,11 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { } /* generate random float in interval ] 0.9 t ; 1.1 t [*/ +#if 0 static float reporting_rand(float t){ return t * (.2f * (rand() / (RAND_MAX * 1.0f)) + 0.9f); } +#endif void linphone_reporting_on_rtcp_update(LinphoneCall *call, SalStreamType stats_type) { #if 0 @@ -718,6 +730,7 @@ int linphone_reporting_publish_interval_report(LinphoneCall* call) { return publish_report(call, "VQIntervalReport"); } +#if 0 static bool_t set_on_action_suggested_cb(MediaStream *stream,void (*on_action_suggested)(void*,int,const char**),void* u) { if (stream&&stream->rc){ MSQosAnalyzer *analyzer=ms_bitrate_controller_get_qos_analyzer(stream->rc); @@ -730,6 +743,7 @@ static bool_t set_on_action_suggested_cb(MediaStream *stream,void (*on_action_su } return FALSE; } +#endif void linphone_reporting_call_state_updated(LinphoneCall *call){ #if 0 diff --git a/src/conference/params/call-session-params.cpp b/src/conference/params/call-session-params.cpp index 7a4b7fb3b..4cc8d7963 100644 --- a/src/conference/params/call-session-params.cpp +++ b/src/conference/params/call-session-params.cpp @@ -26,7 +26,7 @@ LINPHONE_BEGIN_NAMESPACE // ============================================================================= -CallSessionParamsPrivate::CallSessionParamsPrivate (const CallSessionParamsPrivate &src) { +CallSessionParamsPrivate::CallSessionParamsPrivate (const CallSessionParamsPrivate &src) : ClonableObjectPrivate () { sessionName = src.sessionName; privacy = src.privacy; inConference = src.inConference; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 69df709dd..e74ee7cca 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -3571,13 +3571,13 @@ void MediaSessionPrivate::executeBackgroundTasks (bool oneSecondElapsed) { handleStreamEvents(mainVideoStreamIndex); handleStreamEvents(mainTextStreamIndex); +#if 0 int disconnectTimeout = linphone_core_get_nortp_timeout(core); bool disconnected = false; if (((state == LinphoneCallStreamsRunning) || (state == LinphoneCallPausedByRemote)) && oneSecondElapsed && audioStream && (audioStream->ms.state == MSStreamStarted) && (disconnectTimeout > 0)) { disconnected = !audio_stream_alive(audioStream, disconnectTimeout); } -#if 0 if (disconnected) linphone_call_lost(call); #endif diff --git a/tester/call_video_tester.c b/tester/call_video_tester.c index ba7dbc7b0..1588d5b76 100644 --- a/tester/call_video_tester.c +++ b/tester/call_video_tester.c @@ -166,7 +166,7 @@ static void zrtp_video_call(void) { static void call_state_changed_callback_to_accept_video(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState state, const char *message){ LinphoneCoreVTable *vtable; - if (state == LinphoneCallUpdatedByRemote){ + if (state == LinphoneCallUpdatedByRemote){ LinphoneCallParams *params = linphone_core_create_call_params(lc, call); linphone_call_params_enable_video(params, TRUE); linphone_call_accept_update(call, params); @@ -192,7 +192,7 @@ static LinphoneCall* _request_video(LinphoneCoreManager* caller,LinphoneCoreMana if (!BC_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(callee->lc))))){ BC_FAIL("Video was requested while it was already active. This test doesn't look very sane."); } - + if (accept_with_params) { LinphoneCoreVTable *vtable = linphone_core_v_table_new(); vtable->call_state_changed = call_state_changed_callback_to_accept_video; @@ -227,7 +227,7 @@ bool_t request_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee, bo LinphoneVideoActivationPolicy *video_policy; LinphoneCall *call_obj; bool_t video_added = FALSE; - + if ((call_obj=_request_video(caller, callee, accept_with_params))){ BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallUpdatedByRemote,initial_caller_stat.number_of_LinphoneCallUpdatedByRemote+1)); BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallUpdating,initial_callee_stat.number_of_LinphoneCallUpdating+1)); @@ -237,7 +237,7 @@ bool_t request_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee, bo video_policy = linphone_core_get_video_activation_policy(caller->lc); if (video_policy->automatically_accept || accept_with_params) { video_added = BC_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)))); - video_added = + video_added = BC_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)))) && video_added; } else { @@ -302,12 +302,12 @@ static bool_t remove_video(LinphoneCoreManager *caller, LinphoneCoreManager *cal } if ((call_obj = linphone_core_get_current_call(callee->lc))) { - + if (!BC_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(call_obj)))){ BC_FAIL("Video was asked to be dropped while it was not active. This test doesn't look very sane."); return FALSE; } - + callee_params = linphone_core_create_call_params(callee->lc, call_obj); /* Remove video. */ linphone_call_params_enable_video(callee_params, FALSE); @@ -844,7 +844,7 @@ static void video_call_established_by_reinvite_with_implicit_avpf(void) { policy.automatically_accept=FALSE; linphone_core_set_video_policy(callee->lc,&policy); - + policy.automatically_initiate=TRUE; policy.automatically_accept=TRUE; linphone_core_set_video_policy(caller->lc,&policy); @@ -855,21 +855,21 @@ static void video_call_established_by_reinvite_with_implicit_avpf(void) { linphone_core_enable_video_display(caller->lc, TRUE); linphone_core_enable_video_capture(caller->lc, TRUE); - + linphone_core_set_video_device(caller->lc,liblinphone_tester_mire_id); linphone_core_set_video_device(callee->lc,liblinphone_tester_mire_id); - + caller_call = linphone_core_invite_address(caller->lc, callee->identity); if (BC_ASSERT_TRUE( wait_for(callee->lc,caller->lc,&callee->stat.number_of_LinphoneCallIncomingReceived,1))){ callee_call = linphone_core_get_current_call(callee->lc); - + linphone_core_accept_call(callee->lc, linphone_core_get_current_call(callee->lc)); BC_ASSERT_TRUE( wait_for(callee->lc,caller->lc,&callee->stat.number_of_LinphoneCallStreamsRunning,1)); BC_ASSERT_TRUE( wait_for(callee->lc,caller->lc,&caller->stat.number_of_LinphoneCallStreamsRunning,1)); - + BC_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(callee_call))); BC_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(caller_call))); - + /*then callee adds video*/ params = linphone_core_create_call_params(callee->lc, callee_call); linphone_call_params_enable_video(params, TRUE); @@ -879,13 +879,13 @@ static void video_call_established_by_reinvite_with_implicit_avpf(void) { BC_ASSERT_TRUE( wait_for(callee->lc,caller->lc,&caller->stat.number_of_LinphoneCallUpdatedByRemote,1)); BC_ASSERT_TRUE( wait_for(callee->lc,caller->lc,&callee->stat.number_of_LinphoneCallStreamsRunning,2)); BC_ASSERT_TRUE( wait_for(callee->lc,caller->lc,&caller->stat.number_of_LinphoneCallStreamsRunning,2)); - + BC_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(callee_call))); BC_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(caller_call))); - + linphone_call_set_next_video_frame_decoded_callback(caller_call,linphone_call_iframe_decoded_cb,caller->lc); linphone_call_set_next_video_frame_decoded_callback(callee_call,linphone_call_iframe_decoded_cb,callee->lc); - + BC_ASSERT_TRUE( wait_for(callee->lc,caller->lc,&callee->stat.number_of_IframeDecoded,1)); BC_ASSERT_TRUE( wait_for(callee->lc,caller->lc,&caller->stat.number_of_IframeDecoded,1)); @@ -894,7 +894,7 @@ static void video_call_established_by_reinvite_with_implicit_avpf(void) { vstream = (VideoStream *)linphone_call_get_stream(callee_call, LinphoneStreamTypeVideo); BC_ASSERT_TRUE(media_stream_avpf_enabled((MediaStream*)vstream)); } - + end_call(caller, callee); linphone_core_manager_destroy(callee); linphone_core_manager_destroy(caller); @@ -1000,7 +1000,7 @@ static void _call_with_ice_video(LinphoneVideoPolicy caller_policy, LinphoneVide unsigned int nb_media_starts = 1; const LinphoneCallParams *marie_remote_params; const LinphoneCallParams *pauline_current_params; - + /* * Pauline is the caller * Marie is the callee @@ -1027,13 +1027,13 @@ static void _call_with_ice_video(LinphoneVideoPolicy caller_policy, LinphoneVide * they will not be used at the end.*/ linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); - + linphone_core_set_audio_port(marie->lc, -1); linphone_core_set_video_port(marie->lc, -1); linphone_core_set_audio_port(pauline->lc, -1); linphone_core_set_video_port(pauline->lc, -1); - + linphone_core_invite_address(pauline->lc, marie->identity); if (!BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneCallIncomingReceived, 1))) goto end; marie_remote_params = linphone_call_get_remote_params(linphone_core_get_current_call(marie->lc)); @@ -1041,18 +1041,18 @@ static void _call_with_ice_video(LinphoneVideoPolicy caller_policy, LinphoneVide if (marie_remote_params){ BC_ASSERT_TRUE(linphone_call_params_video_enabled(marie_remote_params) == caller_policy.automatically_initiate); } - + linphone_call_accept(linphone_core_get_current_call(marie->lc)); BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1) && wait_for(pauline->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1)); - + pauline_current_params = linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)); BC_ASSERT_PTR_NOT_NULL(pauline_current_params); if (pauline_current_params){ - BC_ASSERT_TRUE(linphone_call_params_video_enabled(pauline_current_params) == + BC_ASSERT_TRUE(linphone_call_params_video_enabled(pauline_current_params) == (caller_policy.automatically_initiate && callee_policy.automatically_accept)); } - + /* Wait for ICE reINVITEs to complete. */ BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2) && wait_for(pauline->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 2)); @@ -1063,8 +1063,8 @@ static void _call_with_ice_video(LinphoneVideoPolicy caller_policy, LinphoneVide } BC_ASSERT_TRUE(check_ice(pauline, marie, LinphoneIceStateHostConnection)); BC_ASSERT_TRUE(check_nb_media_starts(pauline, marie, nb_media_starts, nb_media_starts)); - - + + if (caller_policy.automatically_initiate && callee_policy.automatically_accept && (video_added_by_caller || video_added_by_callee)){ BC_FAIL("Tired developer detected. You have requested the test to add video while it is already established from the beginning of the call."); }else{ @@ -1095,7 +1095,7 @@ static void _call_with_ice_video(LinphoneVideoPolicy caller_policy, LinphoneVide BC_ASSERT_TRUE(check_ice(pauline, marie, LinphoneIceStateHostConnection)); nb_media_starts++; BC_ASSERT_TRUE(check_nb_media_starts(pauline, marie, nb_media_starts, nb_media_starts)); - + } end_call(pauline, marie); @@ -1332,7 +1332,7 @@ static void accept_call_in_send_only_base(LinphoneCoreManager* pauline, Linphone /*The send-only client shall set rtp symmetric in absence of media relay for this test.*/ lp_config_set_int(marie->lc->config,"rtp","symmetric",1); - + linphone_call_set_next_video_frame_decoded_callback(linphone_core_invite_address(pauline->lc,marie->identity) ,linphone_call_iframe_decoded_cb ,pauline->lc); @@ -1605,15 +1605,15 @@ static void classic_video_entry_phone_setup(void) { linphone_core_set_avpf_mode(callee_mgr->lc, LinphoneAVPFEnabled); linphone_core_set_video_policy(caller_mgr->lc, &vpol); linphone_core_set_video_policy(callee_mgr->lc, &vpol); - - + + // important: VP8 has really poor performances with the mire camera, at least // on iOS - so when ever h264 is available, let's use it instead if (linphone_core_find_payload_type(caller_mgr->lc,"h264", -1, -1)!=NULL) { disable_all_video_codecs_except_one(caller_mgr->lc,"h264"); disable_all_video_codecs_except_one(callee_mgr->lc,"h264"); - + /*On Mac OS, set VGA as the prefered size, otherwise we don't benefit from the hardware * accelerated H264 videotoolbox codec*/ if (ms_factory_get_encoder(linphone_core_get_ms_factory(callee_mgr->lc), "H264")->id == MS_VT_H264_ENC_ID){ @@ -1857,7 +1857,7 @@ static void incoming_reinvite_with_invalid_ack_sdp(void){ BC_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)))); caller_params = linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)); // TODO [refactoring]: BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,(int*)&caller_params->has_video,FALSE)); - + (void)caller_params; sal_call_set_sdp_handling(linphone_call_get_op(inc_call), SalOpSDPNormal); } end_call(caller, callee); @@ -1958,40 +1958,40 @@ static void call_with_early_media_and_no_sdp_in_200_with_video(void){ /* - * This test simulates a network congestion in the video flow from marie to pauline. + * This test simulates a network congestion in the video flow from marie to pauline. * The stream from pauline to marie is not under test. - * It checks that a first TMMBR consecutive to congestion detection is received, and a second one after congestion resolution is received + * It checks that a first TMMBR consecutive to congestion detection is received, and a second one after congestion resolution is received * a few seconds later. * The parameters used for the network simulator correspond to a "light congestion", which are the ones that translate into relatively * small packet losses, hence the more difficult to detect at first sight. - * + * **/ static void video_call_with_thin_congestion(void){ LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_rc"); LinphoneVideoPolicy pol = {0}; OrtpNetworkSimulatorParams simparams = { 0 }; - + linphone_core_set_video_device(marie->lc, "Mire: Mire (synthetic moving picture)"); linphone_core_enable_video_capture(marie->lc, TRUE); linphone_core_enable_video_display(marie->lc, TRUE); linphone_core_enable_video_capture(pauline->lc, TRUE); linphone_core_enable_video_display(pauline->lc, TRUE); - + pol.automatically_accept = TRUE; pol.automatically_initiate = TRUE; linphone_core_set_video_policy(marie->lc, &pol); linphone_core_set_video_policy(pauline->lc, &pol); - + linphone_core_set_preferred_video_size_by_name(marie->lc, "vga"); simparams.mode = OrtpNetworkSimulatorOutbound; simparams.enabled = TRUE; simparams.max_bandwidth = 400000; simparams.max_buffer_size = (int)simparams.max_bandwidth; simparams.latency = 60; - + linphone_core_set_network_simulator_params(marie->lc, &simparams); - + if (BC_ASSERT_TRUE(call(marie, pauline))){ LinphoneCall *call = linphone_core_get_current_call(pauline->lc); int first_tmmbr; @@ -2001,12 +2001,12 @@ static void video_call_with_thin_congestion(void){ BC_ASSERT_GREATER((float)marie->stat.last_tmmbr_value_received, 220000.f, float, "%f"); BC_ASSERT_LOWER((float)marie->stat.last_tmmbr_value_received, 300000.f, float, "%f"); first_tmmbr = marie->stat.last_tmmbr_value_received; - + /*another tmmbr with a greater value is expected once the congestion is resolved*/ BC_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &marie->stat.last_tmmbr_value_received, first_tmmbr + 1, 15000)); BC_ASSERT_GREATER((float)marie->stat.last_tmmbr_value_received, 290000.f, float, "%f"); BC_ASSERT_GREATER(linphone_call_get_current_quality(call), 4.f, float, "%f"); - + end_call(marie, pauline); } linphone_core_manager_destroy(marie); diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c index df792bb8a..bc03161fa 100644 --- a/tester/flexisip_tester.c +++ b/tester/flexisip_tester.c @@ -691,12 +691,13 @@ static void call_with_sips_not_achievable(void){ } - +#if 0 static bool_t is_sending_ipv6(RtpSession *session, bool_t rtcp){ const struct sockaddr *dest = rtcp ? (struct sockaddr*)&session->rtcp.gs.rem_addr : (struct sockaddr*)&session->rtp.gs.rem_addr; struct sockaddr_in6 *in6=(struct sockaddr_in6*)dest; return dest->sa_family == AF_INET6 && !IN6_IS_ADDR_V4MAPPED(&in6->sin6_addr); } +#endif static bool_t is_remote_contact_ipv6(LinphoneCall *call){ const char *contact=linphone_call_get_remote_contact(call); LinphoneAddress *ct_addr; From 54994602ae9c227e307ec24951bb982d5f248d0d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 11 Sep 2017 14:51:43 +0200 Subject: [PATCH 0025/2215] Remove useless endl in the logger. --- src/logger/logger.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/logger/logger.cpp b/src/logger/logger.cpp index 7ca01589d..ede21b596 100644 --- a/src/logger/logger.cpp +++ b/src/logger/logger.cpp @@ -44,7 +44,6 @@ Logger::Logger (Level level) : Object(*new LoggerPrivate) { Logger::~Logger () { L_D(Logger); - d->os << endl; const string str = d->os.str(); switch (d->level) { From 10a84cf9af42bd4367d358a35ae5b482185bd67b Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 11 Sep 2017 14:55:47 +0200 Subject: [PATCH 0026/2215] feat(chat): move cpim in chat folder --- src/{ => chat}/cpim/cpim.h | 0 src/{ => chat}/cpim/header/cpim-core-headers.cpp | 2 +- src/{ => chat}/cpim/header/cpim-core-headers.h | 0 src/{ => chat}/cpim/header/cpim-generic-header.cpp | 2 +- src/{ => chat}/cpim/header/cpim-generic-header.h | 0 src/{ => chat}/cpim/header/cpim-header-p.h | 0 src/{ => chat}/cpim/header/cpim-header.cpp | 0 src/{ => chat}/cpim/header/cpim-header.h | 0 src/{ => chat}/cpim/message/cpim-message.cpp | 2 +- src/{ => chat}/cpim/message/cpim-message.h | 4 ++-- src/{ => chat}/cpim/parser/cpim-grammar.cpp | 0 src/{ => chat}/cpim/parser/cpim-grammar.h | 0 src/{ => chat}/cpim/parser/cpim-parser.cpp | 0 src/{ => chat}/cpim/parser/cpim-parser.h | 2 +- 14 files changed, 6 insertions(+), 6 deletions(-) rename src/{ => chat}/cpim/cpim.h (100%) rename src/{ => chat}/cpim/header/cpim-core-headers.cpp (98%) rename src/{ => chat}/cpim/header/cpim-core-headers.h (100%) rename src/{ => chat}/cpim/header/cpim-generic-header.cpp (98%) rename src/{ => chat}/cpim/header/cpim-generic-header.h (100%) rename src/{ => chat}/cpim/header/cpim-header-p.h (100%) rename src/{ => chat}/cpim/header/cpim-header.cpp (100%) rename src/{ => chat}/cpim/header/cpim-header.h (100%) rename src/{ => chat}/cpim/message/cpim-message.cpp (98%) rename src/{ => chat}/cpim/message/cpim-message.h (94%) rename src/{ => chat}/cpim/parser/cpim-grammar.cpp (100%) rename src/{ => chat}/cpim/parser/cpim-grammar.h (100%) rename src/{ => chat}/cpim/parser/cpim-parser.cpp (100%) rename src/{ => chat}/cpim/parser/cpim-parser.h (98%) diff --git a/src/cpim/cpim.h b/src/chat/cpim/cpim.h similarity index 100% rename from src/cpim/cpim.h rename to src/chat/cpim/cpim.h diff --git a/src/cpim/header/cpim-core-headers.cpp b/src/chat/cpim/header/cpim-core-headers.cpp similarity index 98% rename from src/cpim/header/cpim-core-headers.cpp rename to src/chat/cpim/header/cpim-core-headers.cpp index 6270b810a..4643d6e5c 100644 --- a/src/cpim/header/cpim-core-headers.cpp +++ b/src/chat/cpim/header/cpim-core-headers.cpp @@ -16,8 +16,8 @@ * along with this program. If not, see . */ +#include "chat/cpim/parser/cpim-parser.h" #include "cpim-header-p.h" -#include "cpim/parser/cpim-parser.h" #include "cpim-core-headers.h" diff --git a/src/cpim/header/cpim-core-headers.h b/src/chat/cpim/header/cpim-core-headers.h similarity index 100% rename from src/cpim/header/cpim-core-headers.h rename to src/chat/cpim/header/cpim-core-headers.h diff --git a/src/cpim/header/cpim-generic-header.cpp b/src/chat/cpim/header/cpim-generic-header.cpp similarity index 98% rename from src/cpim/header/cpim-generic-header.cpp rename to src/chat/cpim/header/cpim-generic-header.cpp index 7fb7a088f..d2a55cbea 100644 --- a/src/cpim/header/cpim-generic-header.cpp +++ b/src/chat/cpim/header/cpim-generic-header.cpp @@ -20,8 +20,8 @@ #include "linphone/utils/utils.h" +#include "chat/cpim/parser/cpim-parser.h" #include "cpim-header-p.h" -#include "cpim/parser/cpim-parser.h" #include "cpim-generic-header.h" diff --git a/src/cpim/header/cpim-generic-header.h b/src/chat/cpim/header/cpim-generic-header.h similarity index 100% rename from src/cpim/header/cpim-generic-header.h rename to src/chat/cpim/header/cpim-generic-header.h diff --git a/src/cpim/header/cpim-header-p.h b/src/chat/cpim/header/cpim-header-p.h similarity index 100% rename from src/cpim/header/cpim-header-p.h rename to src/chat/cpim/header/cpim-header-p.h diff --git a/src/cpim/header/cpim-header.cpp b/src/chat/cpim/header/cpim-header.cpp similarity index 100% rename from src/cpim/header/cpim-header.cpp rename to src/chat/cpim/header/cpim-header.cpp diff --git a/src/cpim/header/cpim-header.h b/src/chat/cpim/header/cpim-header.h similarity index 100% rename from src/cpim/header/cpim-header.h rename to src/chat/cpim/header/cpim-header.h diff --git a/src/cpim/message/cpim-message.cpp b/src/chat/cpim/message/cpim-message.cpp similarity index 98% rename from src/cpim/message/cpim-message.cpp rename to src/chat/cpim/message/cpim-message.cpp index b3bc56ee9..29252e934 100644 --- a/src/cpim/message/cpim-message.cpp +++ b/src/chat/cpim/message/cpim-message.cpp @@ -20,7 +20,7 @@ #include "linphone/utils/utils.h" -#include "cpim/parser/cpim-parser.h" +#include "chat/cpim/parser/cpim-parser.h" #include "object/object-p.h" #include "cpim-message.h" diff --git a/src/cpim/message/cpim-message.h b/src/chat/cpim/message/cpim-message.h similarity index 94% rename from src/cpim/message/cpim-message.h rename to src/chat/cpim/message/cpim-message.h index 6905cb364..38c1cd5a0 100644 --- a/src/cpim/message/cpim-message.h +++ b/src/chat/cpim/message/cpim-message.h @@ -19,8 +19,8 @@ #ifndef _CPIM_MESSAGE_H_ #define _CPIM_MESSAGE_H_ -#include "cpim/header/cpim-core-headers.h" -#include "cpim/header/cpim-generic-header.h" +#include "chat/cpim/header/cpim-core-headers.h" +#include "chat/cpim/header/cpim-generic-header.h" // ============================================================================= diff --git a/src/cpim/parser/cpim-grammar.cpp b/src/chat/cpim/parser/cpim-grammar.cpp similarity index 100% rename from src/cpim/parser/cpim-grammar.cpp rename to src/chat/cpim/parser/cpim-grammar.cpp diff --git a/src/cpim/parser/cpim-grammar.h b/src/chat/cpim/parser/cpim-grammar.h similarity index 100% rename from src/cpim/parser/cpim-grammar.h rename to src/chat/cpim/parser/cpim-grammar.h diff --git a/src/cpim/parser/cpim-parser.cpp b/src/chat/cpim/parser/cpim-parser.cpp similarity index 100% rename from src/cpim/parser/cpim-parser.cpp rename to src/chat/cpim/parser/cpim-parser.cpp diff --git a/src/cpim/parser/cpim-parser.h b/src/chat/cpim/parser/cpim-parser.h similarity index 98% rename from src/cpim/parser/cpim-parser.h rename to src/chat/cpim/parser/cpim-parser.h index fc7c42d8d..e6686eb2d 100644 --- a/src/cpim/parser/cpim-parser.h +++ b/src/chat/cpim/parser/cpim-parser.h @@ -19,7 +19,7 @@ #ifndef _CPIM_PARSER_H_ #define _CPIM_PARSER_H_ -#include "cpim/message/cpim-message.h" +#include "chat/cpim/message/cpim-message.h" #include "object/singleton.h" // ============================================================================= From d88a87d6fc601860f77a34648e1541b42f23c6e0 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 11 Sep 2017 16:24:19 +0200 Subject: [PATCH 0027/2215] fix build with cpim --- src/CMakeLists.txt | 28 ++++++++++++++-------------- tester/cpim-tester.cpp | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1c79a1cae..bff469b22 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,6 +31,14 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES chat/chat-message.h chat/chat-room-p.h chat/chat-room.h + chat/cpim/cpim.h + chat/cpim/header/cpim-core-headers.h + chat/cpim/header/cpim-generic-header.h + chat/cpim/header/cpim-header-p.h + chat/cpim/header/cpim-header.h + chat/cpim/message/cpim-message.h + chat/cpim/parser/cpim-grammar.h + chat/cpim/parser/cpim-parser.h chat/imdn.h chat/is-composing.h conference/conference-listener.h @@ -51,14 +59,6 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES conference/session/port-config.h content/content.h core/core.h - cpim/cpim.h - cpim/header/cpim-core-headers.h - cpim/header/cpim-generic-header.h - cpim/header/cpim-header-p.h - cpim/header/cpim-header.h - cpim/message/cpim-message.h - cpim/parser/cpim-grammar.h - cpim/parser/cpim-parser.h db/abstract/abstract-db-p.h db/abstract/abstract-db.h db/events-db.h @@ -92,6 +92,12 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES call/call.cpp chat/chat-message.cpp chat/chat-room.cpp + chat/cpim/header/cpim-core-headers.cpp + chat/cpim/header/cpim-generic-header.cpp + chat/cpim/header/cpim-header.cpp + chat/cpim/message/cpim-message.cpp + chat/cpim/parser/cpim-grammar.cpp + chat/cpim/parser/cpim-parser.cpp chat/imdn.cpp chat/is-composing.cpp conference/conference.cpp @@ -104,12 +110,6 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES conference/session/media-session.cpp content/content.cpp core/core.cpp - cpim/header/cpim-core-headers.cpp - cpim/header/cpim-generic-header.cpp - cpim/header/cpim-header.cpp - cpim/message/cpim-message.cpp - cpim/parser/cpim-grammar.cpp - cpim/parser/cpim-parser.cpp db/abstract/abstract-db.cpp db/events-db.cpp db/provider/db-session-provider.cpp diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index 214453389..8c7522905 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -#include "cpim/cpim.h" +#include "chat/cpim/cpim.h" #include "liblinphone_tester.h" From 20d5ded82727c139805c87ffafe20f067e6be647 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 11 Sep 2017 17:06:00 +0200 Subject: [PATCH 0028/2215] Fixed build --- src/conference/conference.cpp | 2 +- src/conference/conference.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index f6abff333..5175c43fe 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -132,7 +132,7 @@ void Conference::removeParticipant (const shared_ptr participant) { // TODO } -void Conference::removeParticipants (const list> participants) { +void Conference::removeParticipants (const list> participants) { // TODO } diff --git a/src/conference/conference.h b/src/conference/conference.h index 3b1a85920..04d69279e 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -51,7 +51,7 @@ public: virtual int getNbParticipants () const; virtual std::list> getParticipants () const; virtual void removeParticipant (const std::shared_ptr participant); - virtual void removeParticipants (const std::list> participants); + virtual void removeParticipants (const std::list> participants); protected: explicit Conference (ConferencePrivate &p, LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); From 5600ce3a6f78b1dc2d3fc6087f1194e9b882febe Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 11 Sep 2017 17:17:57 +0200 Subject: [PATCH 0029/2215] Another const in list issue fixed --- src/conference/conference-interface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index 016313cf8..181052912 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -38,7 +38,7 @@ public: virtual int getNbParticipants () const = 0; virtual std::list> getParticipants () const = 0; virtual void removeParticipant (const std::shared_ptr participant) = 0; - virtual void removeParticipants (const std::list> participants) = 0; + virtual void removeParticipants (const std::list> participants) = 0; }; LINPHONE_END_NAMESPACE From 8063ae024e1e7b6c0ddecdcbe32e9f9402f23600 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 11 Sep 2017 18:03:45 +0200 Subject: [PATCH 0030/2215] Create classes for the different types of chat rooms. --- coreapi/chat.c | 111 +++++++++------ include/linphone/chat.h | 4 +- src/CMakeLists.txt | 9 ++ src/chat/basic-chat-room-p.h | 45 ++++++ src/chat/basic-chat-room.cpp | 70 ++++++++++ src/chat/basic-chat-room.h | 58 ++++++++ src/chat/chat-room-p.h | 9 +- src/chat/chat-room.cpp | 188 ++++++++------------------ src/chat/chat-room.h | 15 +- src/chat/client-group-chat-room-p.h | 43 ++++++ src/chat/client-group-chat-room.cpp | 30 ++++ src/chat/client-group-chat-room.h | 57 ++++++++ src/chat/real-time-text-chat-room-p.h | 56 ++++++++ src/chat/real-time-text-chat-room.cpp | 175 ++++++++++++++++++++++++ src/chat/real-time-text-chat-room.h | 62 +++++++++ src/conference/conference-interface.h | 2 +- src/conference/conference.cpp | 2 +- src/conference/conference.h | 2 +- 18 files changed, 745 insertions(+), 193 deletions(-) create mode 100644 src/chat/basic-chat-room-p.h create mode 100644 src/chat/basic-chat-room.cpp create mode 100644 src/chat/basic-chat-room.h create mode 100644 src/chat/client-group-chat-room-p.h create mode 100644 src/chat/client-group-chat-room.cpp create mode 100644 src/chat/client-group-chat-room.h create mode 100644 src/chat/real-time-text-chat-room-p.h create mode 100644 src/chat/real-time-text-chat-room.cpp create mode 100644 src/chat/real-time-text-chat-room.h diff --git a/coreapi/chat.c b/coreapi/chat.c index 3674db2ff..807c1701b 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -36,14 +36,16 @@ #include "linphone/wrapper_utils.h" #include "c-wrapper/c-tools.h" -#include "chat/chat-room-p.h" -#include "chat/chat-room.h" +#include "chat/basic-chat-room.h" +#include "chat/real-time-text-chat-room.h" +#include "chat/real-time-text-chat-room-p.h" #include "utils/content-type.h" struct _LinphoneChatRoom{ belle_sip_object_t base; void *user_data; LinphonePrivate::ChatRoom *cr; + LinphoneAddress *peerAddressCache; }; BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneChatRoom); @@ -163,13 +165,20 @@ const bctbx_list_t *linphone_core_get_chat_rooms(LinphoneCore *lc) { } static bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from) { - return linphone_address_weak_equal(cr->cr->getPeerAddress(), from); + LinphoneAddress *addr = linphone_address_new(cr->cr->getPeerAddress().asString().c_str()); + bool_t result = linphone_address_weak_equal(addr, from); + linphone_address_unref(addr); + return result; } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneChatRoom); static void _linphone_chat_room_destroy(LinphoneChatRoom *cr) { delete cr->cr; + if (cr->peerAddressCache) { + linphone_address_unref(cr->peerAddressCache); + cr->peerAddressCache = nullptr; + } } BELLE_SIP_INSTANCIATE_VPTR(LinphoneChatRoom, belle_sip_object_t, @@ -178,14 +187,17 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneChatRoom, belle_sip_object_t, NULL, // marshal FALSE); -LinphoneChatRoom *_linphone_core_create_chat_room_base(LinphoneCore *lc, LinphoneAddress *addr){ +LinphoneChatRoom *_linphone_core_create_chat_room_base(LinphoneCore *lc, const LinphoneAddress *addr) { LinphoneChatRoom *cr = belle_sip_object_new(LinphoneChatRoom); - cr->cr = new LinphonePrivate::ChatRoom(lc, addr); + if (linphone_core_realtime_text_enabled(lc)) + cr->cr = new LinphonePrivate::RealTimeTextChatRoom(lc, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address).get()); + else + cr->cr = new LinphonePrivate::BasicChatRoom(lc, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address).get()); L_GET_PRIVATE(cr->cr)->setCBackPointer(cr); return cr; } -static LinphoneChatRoom *_linphone_core_create_chat_room(LinphoneCore *lc, LinphoneAddress *addr) { +static LinphoneChatRoom *_linphone_core_create_chat_room(LinphoneCore *lc, const LinphoneAddress *addr) { LinphoneChatRoom *cr = _linphone_core_create_chat_room_base(lc, addr); lc->chatrooms = bctbx_list_append(lc->chatrooms, (void *)cr); return cr; @@ -238,7 +250,7 @@ static LinphoneChatRoom *_linphone_core_get_or_create_chat_room(LinphoneCore *lc LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr) { LinphoneChatRoom *ret = _linphone_core_get_chat_room(lc, addr); if (!ret) { - ret = _linphone_core_create_chat_room(lc, linphone_address_clone(addr)); + ret = _linphone_core_create_chat_room(lc, addr); } return ret; } @@ -391,16 +403,20 @@ bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr) { return cr->cr->isRemoteComposing(); } -LinphoneCore *linphone_chat_room_get_lc(LinphoneChatRoom *cr) { +LinphoneCore *linphone_chat_room_get_lc(const LinphoneChatRoom *cr) { return linphone_chat_room_get_core(cr); } -LinphoneCore *linphone_chat_room_get_core(LinphoneChatRoom *cr) { +LinphoneCore *linphone_chat_room_get_core(const LinphoneChatRoom *cr) { return cr->cr->getCore(); } const LinphoneAddress *linphone_chat_room_get_peer_address(LinphoneChatRoom *cr) { - return cr->cr->getPeerAddress(); + if (cr->peerAddressCache) { + linphone_address_unref(cr->peerAddressCache); + } + cr->peerAddressCache = linphone_address_new(cr->cr->getPeerAddress().asString().c_str()); + return cr->peerAddressCache; } LinphoneChatMessage *linphone_chat_room_create_message(LinphoneChatRoom *cr, const char *message) { @@ -599,46 +615,52 @@ void linphone_chat_message_send_display_notification(LinphoneChatMessage *cm) { } void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, uint32_t character, LinphoneCall *call) { - L_GET_PRIVATE(cr->cr)->realtimeTextReceived(character, call); + if (linphone_core_realtime_text_enabled(lc)) + L_GET_PRIVATE(static_cast(cr->cr))->realtimeTextReceived(character, call); } uint32_t linphone_chat_room_get_char(const LinphoneChatRoom *cr) { - return cr->cr->getChar(); + if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) + return static_cast(cr->cr)->getChar(); + return 0; } LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg, uint32_t character) { LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); - LinphoneCall *call = cr->cr->getCall(); - LinphoneCore *lc = cr->cr->getCore(); - const uint32_t new_line = 0x2028; - const uint32_t crlf = 0x0D0A; - const uint32_t lf = 0x0A; + if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) { + LinphoneCall *call = static_cast(cr->cr)->getCall(); + LinphoneCore *lc = static_cast(cr->cr)->getCore(); + const uint32_t new_line = 0x2028; + const uint32_t crlf = 0x0D0A; + const uint32_t lf = 0x0A; - if (!call || !linphone_call_get_stream(call, LinphoneStreamTypeText)) { - return -1; - } - - if (character == new_line || character == crlf || character == lf) { - if (lc && lp_config_get_int(lc->config, "misc", "store_rtt_messages", 1) == 1) { - ms_debug("New line sent, forge a message with content %s", msg->message); - msg->time = ms_time(0); - msg->state = LinphoneChatMessageStateDisplayed; - msg->dir = LinphoneChatMessageOutgoing; - if (msg->from) linphone_address_unref(msg->from); - msg->from = linphone_address_new(linphone_core_get_identity(lc)); - msg->storage_id = linphone_chat_message_store(msg); - ms_free(msg->message); - msg->message = NULL; + if (!call || !linphone_call_get_stream(call, LinphoneStreamTypeText)) { + return -1; } - } else { - char *value = LinphonePrivate::Utils::utf8ToChar(character); - msg->message = ms_strcat_printf(msg->message, value); - ms_debug("Sent RTT character: %s (%lu), pending text is %s", value, (unsigned long)character, msg->message); - delete value; - } - text_stream_putchar32(reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeText)), character); - return 0; + if (character == new_line || character == crlf || character == lf) { + if (lc && lp_config_get_int(lc->config, "misc", "store_rtt_messages", 1) == 1) { + ms_debug("New line sent, forge a message with content %s", msg->message); + msg->time = ms_time(0); + msg->state = LinphoneChatMessageStateDisplayed; + msg->dir = LinphoneChatMessageOutgoing; + if (msg->from) linphone_address_unref(msg->from); + msg->from = linphone_address_new(linphone_core_get_identity(lc)); + msg->storage_id = linphone_chat_message_store(msg); + ms_free(msg->message); + msg->message = NULL; + } + } else { + char *value = LinphonePrivate::Utils::utf8ToChar(character); + msg->message = ms_strcat_printf(msg->message, value); + ms_debug("Sent RTT character: %s (%lu), pending text is %s", value, (unsigned long)character, msg->message); + delete value; + } + + text_stream_putchar32(reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeText)), character); + return 0; + } + return -1; } const char* linphone_chat_message_get_message_id(const LinphoneChatMessage *cm) { @@ -650,7 +672,9 @@ void linphone_chat_room_compose(LinphoneChatRoom *cr) { } LinphoneCall *linphone_chat_room_get_call(const LinphoneChatRoom *room) { - return room->cr->getCall(); + if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(room))) + return static_cast(room->cr)->getCall(); + return nullptr; } void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call) { @@ -773,7 +797,10 @@ const LinphoneAddress *linphone_chat_message_get_to_address(const LinphoneChatMe if (msg->to) return msg->to; if (msg->dir == LinphoneChatMessageOutgoing) { - return msg->chat_room->cr->getPeerAddress(); + if (msg->chat_room->peerAddressCache) + linphone_address_unref(msg->chat_room->peerAddressCache); + msg->chat_room->peerAddressCache = linphone_address_new(msg->chat_room->cr->getPeerAddress().asString().c_str()); + return msg->chat_room->peerAddressCache; } return NULL; } diff --git a/include/linphone/chat.h b/include/linphone/chat.h index c3d6ab006..e20a25ea7 100644 --- a/include/linphone/chat.h +++ b/include/linphone/chat.h @@ -207,12 +207,12 @@ LINPHONE_PUBLIC int linphone_chat_room_get_unread_messages_count(LinphoneChatRoo * @deprecated use linphone_chat_room_get_core() * @donotwrap **/ -LINPHONE_PUBLIC LINPHONE_DEPRECATED LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr); +LINPHONE_PUBLIC LINPHONE_DEPRECATED LinphoneCore* linphone_chat_room_get_lc(const LinphoneChatRoom *cr); /** * Returns back pointer to #LinphoneCore object. **/ -LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_core(LinphoneChatRoom *cr); +LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_core(const LinphoneChatRoom *cr); /** * When realtime text is enabled #linphone_call_params_realtime_text_enabled, #LinphoneCoreIsComposingReceivedCb is call everytime a char is received from peer. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bff469b22..56243ca4f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -28,9 +28,13 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES call/call-listener.h call/call-p.h call/call.h + chat/basic-chat-room.h + chat/basic-chat-room-p.h chat/chat-message.h chat/chat-room-p.h chat/chat-room.h + chat/client-group-chat-room.h + chat/client-group-chat-room-p.h chat/cpim/cpim.h chat/cpim/header/cpim-core-headers.h chat/cpim/header/cpim-generic-header.h @@ -41,6 +45,8 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES chat/cpim/parser/cpim-parser.h chat/imdn.h chat/is-composing.h + chat/real-time-text-chat-room.h + chat/real-time-text-chat-room-p.h conference/conference-listener.h conference/conference-p.h conference/conference.h @@ -90,8 +96,10 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES c-wrapper/api/c-address.cpp c-wrapper/api/c-event-log.cpp call/call.cpp + chat/basic-chat-room.cpp chat/chat-message.cpp chat/chat-room.cpp + chat/client-group-chat-room.cpp chat/cpim/header/cpim-core-headers.cpp chat/cpim/header/cpim-generic-header.cpp chat/cpim/header/cpim-header.cpp @@ -100,6 +108,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES chat/cpim/parser/cpim-parser.cpp chat/imdn.cpp chat/is-composing.cpp + chat/real-time-text-chat-room.cpp conference/conference.cpp conference/local-conference.cpp conference/params/call-session-params.cpp diff --git a/src/chat/basic-chat-room-p.h b/src/chat/basic-chat-room-p.h new file mode 100644 index 000000000..54cd99f16 --- /dev/null +++ b/src/chat/basic-chat-room-p.h @@ -0,0 +1,45 @@ +/* + * basic-chat-room-p.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _BASIC_CHAT_ROOM_P_H_ +#define _BASIC_CHAT_ROOM_P_H_ + +// From coreapi. +#include "private.h" + +#include "basic-chat-room.h" +#include "chat/chat-room-p.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class BasicChatRoomPrivate : public ChatRoomPrivate { +public: + BasicChatRoomPrivate (LinphoneCore *core, const Address &peerAddress); + virtual ~BasicChatRoomPrivate () = default; + +private: + std::string dummyConferenceId; + + L_DECLARE_PUBLIC(BasicChatRoom); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _BASIC_CHAT_ROOM_P_H_ diff --git a/src/chat/basic-chat-room.cpp b/src/chat/basic-chat-room.cpp new file mode 100644 index 000000000..e4768c988 --- /dev/null +++ b/src/chat/basic-chat-room.cpp @@ -0,0 +1,70 @@ +/* + * basic-chat-room.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "basic-chat-room-p.h" +#include "logger/logger.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +BasicChatRoomPrivate::BasicChatRoomPrivate (LinphoneCore *core, const Address &peerAddress) : ChatRoomPrivate(core, peerAddress) {} + +// ============================================================================= + +BasicChatRoom::BasicChatRoom (LinphoneCore *core, const Address &peerAddress) : ChatRoom(*new BasicChatRoomPrivate(core, peerAddress)) {} + +// ----------------------------------------------------------------------------- + +shared_ptr BasicChatRoom::addParticipant (const Address &addr, const shared_ptr params, bool hasMedia) { + lError() << "addParticipant() is not allowed on a BasicChatRoom"; + return nullptr; +} + +void BasicChatRoom::addParticipants (const list
&addresses, const shared_ptr params, bool hasMedia) { + lError() << "addParticipants() is not allowed on a BasicChatRoom"; +} + +const string& BasicChatRoom::getId () const { + L_D(const BasicChatRoom); + lError() << "a BasicChatRoom does not have a conference id"; + return d->dummyConferenceId; +} + +int BasicChatRoom::getNbParticipants () const { + return 1; +} + +list> BasicChatRoom::getParticipants () const { + L_D(const BasicChatRoom); + list> l; + l.push_back(make_shared(d->peerAddress)); + return l; +} + +void BasicChatRoom::removeParticipant (const shared_ptr participant) { + lError() << "removeParticipant() is not allowed on a BasicChatRoom"; +} + +void BasicChatRoom::removeParticipants (const list> participants) { + lError() << "removeParticipants() is not allowed on a BasicChatRoom"; +} + +LINPHONE_END_NAMESPACE diff --git a/src/chat/basic-chat-room.h b/src/chat/basic-chat-room.h new file mode 100644 index 000000000..f47341fc7 --- /dev/null +++ b/src/chat/basic-chat-room.h @@ -0,0 +1,58 @@ +/* + * basic-chat-room.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _BASIC_CHAT_ROOM_H_ +#define _BASIC_CHAT_ROOM_H_ + +// From coreapi +#include "private.h" + +#include "chat/chat-room.h" +#include "conference/conference-interface.h" + +#include "linphone/types.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class BasicChatRoomPrivate; + +class BasicChatRoom : public ChatRoom { +public: + BasicChatRoom (LinphoneCore *core, const Address &peerAddress); + virtual ~BasicChatRoom () = default; + + /* ConferenceInterface */ + std::shared_ptr addParticipant (const Address &addr, const std::shared_ptr params, bool hasMedia); + void addParticipants (const std::list
&addresses, const std::shared_ptr params, bool hasMedia); + const std::string& getId () const; + int getNbParticipants () const; + std::list> getParticipants () const; + void removeParticipant (const std::shared_ptr participant); + void removeParticipants (const std::list> participants); + +private: + L_DECLARE_PRIVATE(BasicChatRoom); + L_DISABLE_COPY(BasicChatRoom); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _BASIC_CHAT_ROOM_H_ + diff --git a/src/chat/chat-room-p.h b/src/chat/chat-room-p.h index 4f7e492d9..6d480f77f 100644 --- a/src/chat/chat-room-p.h +++ b/src/chat/chat-room-p.h @@ -33,7 +33,7 @@ LINPHONE_BEGIN_NAMESPACE class ChatRoomPrivate : public ObjectPrivate, public IsComposingListener { public: - ChatRoomPrivate (LinphoneCore *core); + ChatRoomPrivate (LinphoneCore *core, const Address &peerAddress); virtual ~ChatRoomPrivate (); private: @@ -62,7 +62,7 @@ public: this->call = call; } -private: +protected: void sendIsComposingNotification (); int createChatMessageFromDb (int argc, char **argv, char **colName); @@ -78,7 +78,7 @@ public: LinphoneReason messageReceived (SalOp *op, const SalMessage *msg); void realtimeTextReceived (uint32_t character, LinphoneCall *call); -private: +protected: void chatMessageReceived (LinphoneChatMessage *msg); void imdnReceived (const std::string &text); void isComposingReceived (const std::string &text); @@ -92,8 +92,7 @@ public: LinphoneChatRoom *cBackPointer = nullptr; LinphoneCore *core = nullptr; LinphoneCall *call = nullptr; - LinphoneAddress *peerAddress = nullptr; - std::string peer; + Address peerAddress; int unreadCount = -1; bool isComposing = false; bool remoteIsComposing = false; diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index d120efba8..a3e7f4030 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -22,6 +22,7 @@ #include "chat-room-p.h" #include "imdn.h" +#include "c-wrapper/c-tools.h" #include "logger/logger.h" #include "utils/content-type.h" @@ -33,17 +34,13 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ChatRoomPrivate::ChatRoomPrivate (LinphoneCore *core) - : core(core), isComposingHandler(core, this) {} +ChatRoomPrivate::ChatRoomPrivate (LinphoneCore *core, const Address &peerAddress) + : core(core), peerAddress(peerAddress), isComposingHandler(core, this) {} ChatRoomPrivate::~ChatRoomPrivate () { for (auto it = transientMessages.begin(); it != transientMessages.end(); it++) { linphone_chat_message_release(*it); } - if (!receivedRttCharacters.empty()) { - for (auto it = receivedRttCharacters.begin(); it != receivedRttCharacters.end(); it++) - bctbx_free(*it); - } if (core) { if (bctbx_list_find(core->chatrooms, cBackPointer)) { lError() << "LinphoneChatRoom[" << cBackPointer << "] is destroyed while still being used by the LinphoneCore. " << @@ -52,7 +49,6 @@ ChatRoomPrivate::~ChatRoomPrivate () { core->chatrooms = bctbx_list_remove(core->chatrooms, cBackPointer); } } - linphone_address_unref(peerAddress); if (pendingMessage) linphone_chat_message_destroy(pendingMessage); } @@ -120,7 +116,8 @@ void ChatRoomPrivate::sendImdn (const string &content, LinphoneReason reason) { L_Q(ChatRoom); const char *identity = nullptr; - LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core, peerAddress); + LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str()); + LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core, peer); if (proxy) identity = linphone_address_as_string(linphone_proxy_config_get_identity_address(proxy)); else @@ -128,11 +125,11 @@ void ChatRoomPrivate::sendImdn (const string &content, LinphoneReason reason) { /* Sending out of call */ SalOp *op = sal_op_new(core->sal); - linphone_configure_op(core, op, peerAddress, nullptr, lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0)); + linphone_configure_op(core, op, peer, nullptr, lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0)); LinphoneChatMessage *msg = q->createMessage(content); LinphoneAddress *fromAddr = linphone_address_new(identity); linphone_chat_message_set_from_address(msg, fromAddr); - LinphoneAddress *toAddr = linphone_address_new(peer.c_str()); + LinphoneAddress *toAddr = linphone_address_new(peerAddress.asString().c_str()); linphone_chat_message_set_to_address(msg, toAddr); linphone_chat_message_set_content_type(msg, "message/imdn+xml"); @@ -148,12 +145,13 @@ void ChatRoomPrivate::sendImdn (const string &content, LinphoneReason reason) { } if (retval <= 0) { - sal_message_send(op, identity, peer.c_str(), msg->content_type, msg->message, nullptr); + sal_message_send(op, identity, peerAddress.asString().c_str(), msg->content_type, msg->message, nullptr); } linphone_chat_message_unref(msg); linphone_address_unref(fromAddr); linphone_address_unref(toAddr); + linphone_address_unref(peer); sal_op_unref(op); } @@ -165,11 +163,11 @@ int ChatRoomPrivate::getMessagesCount (bool unreadOnly) { /* Optimization: do not read database if the count is already available in memory */ if (unreadOnly && unreadCount >= 0) return unreadCount; - char *peer = linphone_address_as_string_uri_only(peerAddress); + string peer = peerAddress.asStringUriOnly(); char *option = nullptr; if (unreadOnly) option = bctbx_strdup_printf("AND status!=%i AND direction=%i", LinphoneChatMessageStateDisplayed, LinphoneChatMessageIncoming); - char *buf = sqlite3_mprintf("SELECT count(*) FROM history WHERE remoteContact = %Q %s;", peer, unreadOnly ? option : ""); + char *buf = sqlite3_mprintf("SELECT count(*) FROM history WHERE remoteContact = %Q %s;", peer.c_str(), unreadOnly ? option : ""); sqlite3_stmt *selectStatement; int numrows = 0; int returnValue = sqlite3_prepare_v2(core->db, buf, -1, &selectStatement, nullptr); @@ -180,7 +178,6 @@ int ChatRoomPrivate::getMessagesCount (bool unreadOnly) { } sqlite3_finalize(selectStatement); sqlite3_free(buf); - ms_free(peer); /* No need to test the sign of unreadCount here because it has been tested above */ if (unreadOnly) { @@ -196,7 +193,8 @@ void ChatRoomPrivate::sendIsComposingNotification () { L_Q(ChatRoom); LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(core); if (linphone_im_notif_policy_get_send_is_composing(policy)) { - LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core, peerAddress); + LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str()); + LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core, peer); const char *identity = nullptr; if (proxy) @@ -206,14 +204,14 @@ void ChatRoomPrivate::sendIsComposingNotification () { /* Sending out of call */ SalOp *op = sal_op_new(core->sal); - linphone_configure_op(core, op, peerAddress, nullptr, lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0)); + linphone_configure_op(core, op, peer, nullptr, lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0)); string content = isComposingHandler.marshal(isComposing); if (!content.empty()) { int retval = -1; LinphoneAddress *fromAddr = linphone_address_new(identity); LinphoneChatMessage *msg = q->createMessage(content); linphone_chat_message_set_from_address(msg, fromAddr); - linphone_chat_message_set_to_address(msg, peerAddress); + linphone_chat_message_set_to_address(msg, peer); linphone_chat_message_set_content_type(msg, "application/im-iscomposing+xml"); LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(core); @@ -226,13 +224,14 @@ void ChatRoomPrivate::sendIsComposingNotification () { } if (retval <= 0) { - sal_message_send(op, identity, peer.c_str(), msg->content_type, msg->message, nullptr); + sal_message_send(op, identity, peerAddress.asString().c_str(), msg->content_type, msg->message, nullptr); } linphone_chat_message_unref(msg); linphone_address_unref(fromAddr); sal_op_unref(op); } + linphone_address_unref(peer); } } @@ -270,15 +269,17 @@ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colN if (!newMessage) { newMessage = q->createMessage(argv[4] ? argv[4] : ""); + LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str()); if (atoi(argv[3]) == LinphoneChatMessageIncoming) { newMessage->dir = LinphoneChatMessageIncoming; - linphone_chat_message_set_from(newMessage, peerAddress); + linphone_chat_message_set_from(newMessage, peer); newMessage->to = nullptr; /* Will be filled at the end */ } else { newMessage->dir = LinphoneChatMessageOutgoing; newMessage->from = nullptr; /* Will be filled at the end */ - linphone_chat_message_set_to(newMessage, peerAddress); + linphone_chat_message_set_to(newMessage, peer); } + linphone_address_unref(peer); newMessage->time = (time_t)atol(argv[9]); newMessage->is_read = atoi(argv[6]); @@ -358,12 +359,11 @@ void ChatRoomPrivate::sqlRequestMessage (sqlite3 *db, const string &stmt) { list ChatRoomPrivate::findMessages (const string &messageId) { if (!core->db) return list(); - char *peer = linphone_address_as_string_uri_only(peerAddress); - char *buf = sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q AND messageId = %Q", peer, messageId.c_str()); + string peer = peerAddress.asStringUriOnly(); + char *buf = sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q AND messageId = %Q", peer.c_str(), messageId.c_str()); messages.clear(); sqlRequestMessage(core->db, buf); sqlite3_free(buf); - ms_free(peer); list result = messages; messages.clear(); return result; @@ -401,7 +401,9 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa msg = q->createMessage(salMsg->text ? salMsg->text : ""); linphone_chat_message_set_content_type(msg, salMsg->content_type); - linphone_chat_message_set_from(msg, peerAddress); + LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str()); + linphone_chat_message_set_from(msg, peer); + linphone_address_unref(peer); LinphoneAddress *to = sal_op_get_to(op) ? linphone_address_new(sal_op_get_to(op)) : linphone_address_new(linphone_core_get_identity(core)); msg->to = to; @@ -494,59 +496,6 @@ end: return reason; } -void ChatRoomPrivate::realtimeTextReceived (uint32_t character, LinphoneCall *call) { - L_Q(ChatRoom); - const uint32_t new_line = 0x2028; - const uint32_t crlf = 0x0D0A; - const uint32_t lf = 0x0A; - - if (call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) { - LinphoneChatMessageCharacter *cmc = bctbx_new0(LinphoneChatMessageCharacter, 1); - - if (!pendingMessage) - pendingMessage = q->createMessage(""); - - cmc->value = character; - cmc->has_been_read = FALSE; - receivedRttCharacters.push_back(cmc); - - remoteIsComposing = true; - linphone_core_notify_is_composing_received(core, cBackPointer); - - if ((character == new_line) || (character == crlf) || (character == lf)) { - /* End of message */ - lDebug() << "New line received, forge a message with content " << pendingMessage->message; - linphone_chat_message_set_from(pendingMessage, peerAddress); - if (pendingMessage->to) - linphone_address_unref(pendingMessage->to); - pendingMessage->to = linphone_call_get_dest_proxy(call) - ? linphone_address_clone(linphone_call_get_dest_proxy(call)->identity_address) - : linphone_address_new(linphone_core_get_identity(core)); - pendingMessage->time = ms_time(0); - pendingMessage->state = LinphoneChatMessageStateDelivered; - pendingMessage->dir = LinphoneChatMessageIncoming; - - if (lp_config_get_int(core->config, "misc", "store_rtt_messages", 1) == 1) - storeOrUpdateMessage(pendingMessage); - - if (unreadCount < 0) unreadCount = 1; - else unreadCount++; - - chatMessageReceived(pendingMessage); - linphone_chat_message_unref(pendingMessage); - pendingMessage = nullptr; - for (auto it = receivedRttCharacters.begin(); it != receivedRttCharacters.end(); it++) - ms_free(*it); - receivedRttCharacters.clear(); - } else { - char *value = Utils::utf8ToChar(character); - pendingMessage->message = ms_strcat_printf(pendingMessage->message, value); - lDebug() << "Received RTT character: " << value << " (" << character << "), pending text is " << pendingMessage->message; - delete value; - } - } -} - // ----------------------------------------------------------------------------- void ChatRoomPrivate::chatMessageReceived (LinphoneChatMessage *msg) { @@ -589,13 +538,9 @@ void ChatRoomPrivate::isComposingRefreshNeeded () { // ============================================================================= -ChatRoom::ChatRoom (LinphoneCore *core, LinphoneAddress *peerAddress) : Object(*new ChatRoomPrivate(core)) { - L_D(ChatRoom); - d->peerAddress = peerAddress; - char *peerStr = linphone_address_as_string(d->peerAddress); - d->peer = peerStr; - ms_free(peerStr); -} +ChatRoom::ChatRoom (LinphoneCore *core, const Address &peerAddress) : Object(*new ChatRoomPrivate(core, peerAddress)) {} + +ChatRoom::ChatRoom (ChatRoomPrivate &p) : Object(p) {} // ----------------------------------------------------------------------------- @@ -617,7 +562,9 @@ LinphoneChatMessage *ChatRoom::createFileTransferMessage (const LinphoneContent cm->message = nullptr; cm->file_transfer_information = linphone_content_copy(initialContent); cm->dir = LinphoneChatMessageOutgoing; - linphone_chat_message_set_to(cm, d->peerAddress); + LinphoneAddress *peer = linphone_address_new(d->peerAddress.asString().c_str()); + linphone_chat_message_set_to(cm, peer); + linphone_address_unref(peer); cm->from = linphone_address_new(linphone_core_get_identity(d->core)); /* This will be set to application/vnd.gsma.rcs-ft-http+xml when we will transfer the xml reply from server to the peers */ cm->content_type = nullptr; @@ -645,11 +592,10 @@ LinphoneChatMessage *ChatRoom::createMessage (const string &msg) { void ChatRoom::deleteHistory () { L_D(ChatRoom); if (!d->core->db) return; - char *peer = linphone_address_as_string_uri_only(d->peerAddress); - char *buf = sqlite3_mprintf("DELETE FROM history WHERE remoteContact = %Q;", peer); + string peer = d->peerAddress.asStringUriOnly(); + char *buf = sqlite3_mprintf("DELETE FROM history WHERE remoteContact = %Q;", peer.c_str()); d->sqlRequest(d->core->db, buf); sqlite3_free(buf); - ms_free(peer); if (d->unreadCount > 0) d->unreadCount = 0; } @@ -697,20 +643,6 @@ LinphoneChatMessage * ChatRoom::findMessageWithDirection (const string &messageI return ret; } -uint32_t ChatRoom::getChar () const { - L_D(const ChatRoom); - if (!d->receivedRttCharacters.empty()) { - for (auto it = d->receivedRttCharacters.begin(); it != d->receivedRttCharacters.end(); it++) { - LinphoneChatMessageCharacter *cmc = *it; - if (!cmc->has_been_read) { - cmc->has_been_read = TRUE; - return cmc->value; - } - } - } - return 0; -} - list ChatRoom::getHistory (int nbMessages) { return getHistoryRange(0, nbMessages - 1); } @@ -723,13 +655,13 @@ int ChatRoom::getHistorySize () { list ChatRoom::getHistoryRange (int startm, int endm) { L_D(ChatRoom); if (!d->core->db) return list(); - char *peer = linphone_address_as_string_uri_only(d->peerAddress); + string peer = d->peerAddress.asStringUriOnly(); d->messages.clear(); /* Since we want to append query parameters depending on arguments given, we use malloc instead of sqlite3_mprintf */ const int bufMaxSize = 512; char *buf = reinterpret_cast(ms_malloc(bufMaxSize)); - buf = sqlite3_snprintf(bufMaxSize - 1, buf, "SELECT * FROM history WHERE remoteContact = %Q ORDER BY id DESC", peer); + buf = sqlite3_snprintf(bufMaxSize - 1, buf, "SELECT * FROM history WHERE remoteContact = %Q ORDER BY id DESC", peer.c_str()); if (startm < 0) startm = 0; if (((endm > 0) && (endm >= startm)) || ((startm == 0) && (endm == 0))) { @@ -775,7 +707,6 @@ list ChatRoom::getHistoryRange (int startm, int endm) { list result = d->messages; d->messages.clear(); - ms_free(peer); return result; } @@ -797,8 +728,8 @@ void ChatRoom::markAsRead () { /* Optimization: do not modify the database if no message is marked as unread */ if (getUnreadMessagesCount() == 0) return; - char *peer = linphone_address_as_string_uri_only(d->peerAddress); - char *buf = sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q AND direction = %i AND status != %i", peer, LinphoneChatMessageIncoming, LinphoneChatMessageStateDisplayed); + string peer = d->peerAddress.asStringUriOnly(); + char *buf = sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q AND direction = %i AND status != %i", peer.c_str(), LinphoneChatMessageIncoming, LinphoneChatMessageStateDisplayed); d->sqlRequestMessage(d->core->db, buf); sqlite3_free(buf); for (auto it = d->messages.begin(); it != d->messages.end(); it++) { @@ -806,10 +737,9 @@ void ChatRoom::markAsRead () { linphone_chat_message_unref(*it); } d->messages.clear(); - buf = sqlite3_mprintf("UPDATE history SET status=%i WHERE remoteContact=%Q AND direction=%i;", LinphoneChatMessageStateDisplayed, peer, LinphoneChatMessageIncoming); + buf = sqlite3_mprintf("UPDATE history SET status=%i WHERE remoteContact=%Q AND direction=%i;", LinphoneChatMessageStateDisplayed, peer.c_str(), LinphoneChatMessageIncoming); d->sqlRequest(d->core->db, buf); sqlite3_free(buf); - ms_free(peer); if (d->pendingMessage) { linphone_chat_message_set_state(d->pendingMessage, LinphoneChatMessageStateDisplayed); @@ -822,14 +752,6 @@ void ChatRoom::markAsRead () { void ChatRoom::sendMessage (LinphoneChatMessage *msg) { L_D(ChatRoom); - /* Stubed rtt */ - if (d->call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(d->call))) { - uint32_t new_line = 0x2028; - linphone_chat_message_put_char(msg, new_line); - linphone_chat_message_unref(msg); - return; - } - msg->dir = LinphoneChatMessageOutgoing; /* Check if we shall upload a file to a server */ @@ -847,9 +769,10 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { } else { SalOp *op = msg->op; LinphoneCall *call = nullptr; - const char *identity = nullptr; + string identity; char *clearTextMessage = nullptr; char *clearTextContentType = nullptr; + LinphoneAddress *peer = linphone_address_new(d->peerAddress.asString().c_str()); if (msg->message) { clearTextMessage = ms_strdup(msg->message); @@ -862,7 +785,7 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { d->addTransientMessage(msg); msg->time = ms_time(0); if (lp_config_get_int(d->core->config, "sip", "chat_use_call_dialogs", 0) != 0) { - call = linphone_core_get_call_by_remote_address(d->core, d->peer.c_str()); + call = linphone_core_get_call_by_remote_address(d->core, d->peerAddress.asString().c_str()); if (call) { if (linphone_call_get_state(call) == LinphoneCallConnected || linphone_call_get_state(call) == LinphoneCallStreamsRunning || linphone_call_get_state(call) == LinphoneCallPaused || linphone_call_get_state(call) == LinphoneCallPausing || @@ -874,10 +797,10 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { } } - if (!identity) { - LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(d->core, d->peerAddress); + if (identity.empty()) { + LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(d->core, peer); if (proxy) { - identity = linphone_address_as_string(linphone_proxy_config_get_identity_address(proxy)); + identity = L_GET_CPP_PTR_FROM_C_STRUCT(linphone_proxy_config_get_identity_address(proxy), Address)->asString(); } else { identity = linphone_core_get_primary_contact(d->core); } @@ -886,7 +809,7 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { /* BUG: the file transfer message constructor sets the from, but doesn't do it as well as here */ linphone_address_unref(msg->from); } - msg->from = linphone_address_new(identity); + msg->from = linphone_address_new(identity.c_str()); int retval = -1; LinphoneImEncryptionEngine *imee = d->core->im_encryption_engine; @@ -904,7 +827,7 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { if (!op) { /* Sending out of call */ msg->op = op = sal_op_new(d->core->sal); - linphone_configure_op(d->core, op, d->peerAddress, msg->custom_headers, + linphone_configure_op(d->core, op, peer, msg->custom_headers, lp_config_get_int(d->core->config, "sip", "chat_msg_with_contact", 0)); sal_op_set_user_pointer(op, msg); /* If out of call, directly store msg */ } @@ -914,21 +837,20 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { d->storeOrUpdateMessage(msg); linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); linphone_chat_message_unref(msg); + linphone_address_unref(peer); return; } if (msg->external_body_url) { char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", msg->external_body_url); - sal_message_send(op, identity, d->peer.c_str(), content_type, nullptr, nullptr); + sal_message_send(op, identity.c_str(), d->peerAddress.asString().c_str(), content_type, nullptr, nullptr); ms_free(content_type); } else { - char *peerUri = linphone_address_as_string_uri_only(d->peerAddress); if (msg->content_type) { - sal_message_send(op, identity, d->peer.c_str(), msg->content_type, msg->message, peerUri); + sal_message_send(op, identity.c_str(), d->peerAddress.asString().c_str(), msg->content_type, msg->message, d->peerAddress.asStringUriOnly().c_str()); } else { - sal_text_send(op, identity, d->peer.c_str(), msg->message); + sal_text_send(op, identity.c_str(), d->peerAddress.asString().c_str(), msg->message); } - ms_free(peerUri); } if (msg->message && clearTextMessage && strcmp(msg->message, clearTextMessage) != 0) { @@ -955,6 +877,7 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { if (clearTextContentType) { ms_free(clearTextContentType); } + linphone_address_unref(peer); if (call && linphone_call_get_op(call) == op) { /* In this case, chat delivery status is not notified, so unrefing chat message right now */ @@ -973,11 +896,6 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { // ----------------------------------------------------------------------------- -LinphoneCall *ChatRoom::getCall () const { - L_D(const ChatRoom); - return d->call; -} - LinphoneCore *ChatRoom::getCore () const { L_D(const ChatRoom); return d->core; @@ -985,7 +903,7 @@ LinphoneCore *ChatRoom::getCore () const { // ----------------------------------------------------------------------------- -const LinphoneAddress *ChatRoom::getPeerAddress () const { +const Address& ChatRoom::getPeerAddress () const { L_D(const ChatRoom); return d->peerAddress; } diff --git a/src/chat/chat-room.h b/src/chat/chat-room.h index d3052d711..d5663d416 100644 --- a/src/chat/chat-room.h +++ b/src/chat/chat-room.h @@ -24,7 +24,9 @@ #include +#include "address/address.h" #include "object/object.h" +#include "conference/conference-interface.h" #include "linphone/types.h" @@ -34,9 +36,9 @@ LINPHONE_BEGIN_NAMESPACE class ChatRoomPrivate; -class ChatRoom : public Object { +class ChatRoom : public Object, public ConferenceInterface { public: - ChatRoom (LinphoneCore *core, LinphoneAddress *peerAddress); + ChatRoom (LinphoneCore *core, const Address &peerAddress); virtual ~ChatRoom () = default; void compose (); @@ -46,19 +48,20 @@ public: void deleteMessage (LinphoneChatMessage *msg); LinphoneChatMessage * findMessage (const std::string& messageId); LinphoneChatMessage * findMessageWithDirection (const std::string &messageId, LinphoneChatMessageDir direction); - uint32_t getChar () const; std::list getHistory (int nbMessages); int getHistorySize (); std::list getHistoryRange (int startm, int endm); int getUnreadMessagesCount (); bool isRemoteComposing () const; void markAsRead (); - void sendMessage (LinphoneChatMessage *msg); + virtual void sendMessage (LinphoneChatMessage *msg); - LinphoneCall *getCall () const; LinphoneCore *getCore () const; - const LinphoneAddress *getPeerAddress () const; + const Address& getPeerAddress () const; + +protected: + explicit ChatRoom (ChatRoomPrivate &p); private: L_DECLARE_PRIVATE(ChatRoom); diff --git a/src/chat/client-group-chat-room-p.h b/src/chat/client-group-chat-room-p.h new file mode 100644 index 000000000..3e6fe2d1f --- /dev/null +++ b/src/chat/client-group-chat-room-p.h @@ -0,0 +1,43 @@ +/* + * client-group-chat-room-p.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CLIENT_GROUP_CHAT_ROOM_P_H_ +#define _CLIENT_GROUP_CHAT_ROOM_P_H_ + +// From coreapi. +#include "private.h" + +#include "client-group-chat-room.h" +#include "chat/chat-room-p.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ClientGroupChatRoomPrivate : public ChatRoomPrivate { +public: + ClientGroupChatRoomPrivate (LinphoneCore *core, const Address &peerAddress); + virtual ~ClientGroupChatRoomPrivate () = default; + +private: + L_DECLARE_PUBLIC(ClientGroupChatRoom); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CLIENT_GROUP_CHAT_ROOM_P_H_ diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp new file mode 100644 index 000000000..9f607a71a --- /dev/null +++ b/src/chat/client-group-chat-room.cpp @@ -0,0 +1,30 @@ +/* + * client-group-chat-room.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "client-group-chat-room-p.h" +#include "logger/logger.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core, const Address &peerAddress) : ChatRoomPrivate(core, peerAddress) {} + +LINPHONE_END_NAMESPACE diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h new file mode 100644 index 000000000..6c70ab363 --- /dev/null +++ b/src/chat/client-group-chat-room.h @@ -0,0 +1,57 @@ +/* + * client-group-chat-room.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CLIENT_GROUP_CHAT_ROOM_H_ +#define _CLIENT_GROUP_CHAT_ROOM_H_ + +// From coreapi +#include "private.h" + +#include "chat/chat-room.h" + +#include "linphone/types.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ClientGroupChatRoomPrivate; + +class ClientGroupChatRoom : public ChatRoom { +public: + ClientGroupChatRoom (LinphoneCore *core, const Address &peerAddress); + virtual ~ClientGroupChatRoom () = default; + + /* ConferenceInterface */ + std::shared_ptr addParticipant (const Address &addr, const std::shared_ptr params, bool hasMedia); + void addParticipants (const std::list
&addresses, const std::shared_ptr params, bool hasMedia); + const std::string& getId () const; + int getNbParticipants () const; + std::list> getParticipants () const; + void removeParticipant (const std::shared_ptr participant); + void removeParticipants (const std::list> participants); + +private: + L_DECLARE_PRIVATE(ClientGroupChatRoom); + L_DISABLE_COPY(ClientGroupChatRoom); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CLIENT_GROUP_CHAT_ROOM_H_ + diff --git a/src/chat/real-time-text-chat-room-p.h b/src/chat/real-time-text-chat-room-p.h new file mode 100644 index 000000000..50ca2db1c --- /dev/null +++ b/src/chat/real-time-text-chat-room-p.h @@ -0,0 +1,56 @@ +/* + * real-time-text-chat-room-p.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _REAL_TIME_TEXT_CHAT_ROOM_P_H_ +#define _REAL_TIME_TEXT_CHAT_ROOM_P_H_ + +// From coreapi. +#include "private.h" + +#include "real-time-text-chat-room.h" +#include "chat/chat-room-p.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class RealTimeTextChatRoomPrivate : public ChatRoomPrivate { +public: + RealTimeTextChatRoomPrivate (LinphoneCore *core, const Address &peerAddress); + virtual ~RealTimeTextChatRoomPrivate (); + +public: + void setCall (LinphoneCall *call) { this->call = call; } + +public: + void realtimeTextReceived (uint32_t character, LinphoneCall *call); + +public: + LinphoneCall *call = nullptr; + std::list receivedRttCharacters; + LinphoneChatMessage *pendingMessage = nullptr; + +private: + std::string dummyConferenceId; + + L_DECLARE_PUBLIC(RealTimeTextChatRoom); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _REAL_TIME_TEXT_CHAT_ROOM_P_H_ diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp new file mode 100644 index 000000000..680e5d05c --- /dev/null +++ b/src/chat/real-time-text-chat-room.cpp @@ -0,0 +1,175 @@ +/* + * chat-room.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include + +#include "linphone/utils/utils.h" + +#include "real-time-text-chat-room-p.h" +#include "logger/logger.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +RealTimeTextChatRoomPrivate::RealTimeTextChatRoomPrivate (LinphoneCore *core, const Address &peerAddress) + : ChatRoomPrivate(core, peerAddress) {} + +RealTimeTextChatRoomPrivate::~RealTimeTextChatRoomPrivate () { + if (!receivedRttCharacters.empty()) { + for (auto it = receivedRttCharacters.begin(); it != receivedRttCharacters.end(); it++) + bctbx_free(*it); + } + if (pendingMessage) + linphone_chat_message_destroy(pendingMessage); +} + +// ----------------------------------------------------------------------------- + +void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, LinphoneCall *call) { + L_Q(ChatRoom); + const uint32_t new_line = 0x2028; + const uint32_t crlf = 0x0D0A; + const uint32_t lf = 0x0A; + + if (call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) { + LinphoneChatMessageCharacter *cmc = bctbx_new0(LinphoneChatMessageCharacter, 1); + + if (!pendingMessage) + pendingMessage = q->createMessage(""); + + cmc->value = character; + cmc->has_been_read = FALSE; + receivedRttCharacters.push_back(cmc); + + remoteIsComposing = true; + linphone_core_notify_is_composing_received(core, cBackPointer); + + if ((character == new_line) || (character == crlf) || (character == lf)) { + /* End of message */ + lDebug() << "New line received, forge a message with content " << pendingMessage->message; + LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str()); + linphone_chat_message_set_from(pendingMessage, peer); + linphone_address_unref(peer); + if (pendingMessage->to) + linphone_address_unref(pendingMessage->to); + pendingMessage->to = linphone_call_get_dest_proxy(call) + ? linphone_address_clone(linphone_call_get_dest_proxy(call)->identity_address) + : linphone_address_new(linphone_core_get_identity(core)); + pendingMessage->time = ms_time(0); + pendingMessage->state = LinphoneChatMessageStateDelivered; + pendingMessage->dir = LinphoneChatMessageIncoming; + + if (lp_config_get_int(core->config, "misc", "store_rtt_messages", 1) == 1) + storeOrUpdateMessage(pendingMessage); + + if (unreadCount < 0) unreadCount = 1; + else unreadCount++; + + chatMessageReceived(pendingMessage); + linphone_chat_message_unref(pendingMessage); + pendingMessage = nullptr; + for (auto it = receivedRttCharacters.begin(); it != receivedRttCharacters.end(); it++) + ms_free(*it); + receivedRttCharacters.clear(); + } else { + char *value = Utils::utf8ToChar(character); + pendingMessage->message = ms_strcat_printf(pendingMessage->message, value); + lDebug() << "Received RTT character: " << value << " (" << character << "), pending text is " << pendingMessage->message; + delete value; + } + } +} + +// ============================================================================= + +RealTimeTextChatRoom::RealTimeTextChatRoom (LinphoneCore *core, const Address &peerAddress) : ChatRoom(*new RealTimeTextChatRoomPrivate(core, peerAddress)) {} + +// ----------------------------------------------------------------------------- + +void RealTimeTextChatRoom::sendMessage (LinphoneChatMessage *msg) { + L_D(ChatRoom); + if (d->call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(d->call))) { + uint32_t new_line = 0x2028; + linphone_chat_message_put_char(msg, new_line); + linphone_chat_message_unref(msg); + } +} + +// ----------------------------------------------------------------------------- + +uint32_t RealTimeTextChatRoom::getChar () const { + L_D(const ChatRoom); + if (!d->receivedRttCharacters.empty()) { + for (auto it = d->receivedRttCharacters.begin(); it != d->receivedRttCharacters.end(); it++) { + LinphoneChatMessageCharacter *cmc = *it; + if (!cmc->has_been_read) { + cmc->has_been_read = TRUE; + return cmc->value; + } + } + } + return 0; +} + +// ----------------------------------------------------------------------------- + +LinphoneCall *RealTimeTextChatRoom::getCall () const { + L_D(const ChatRoom); + return d->call; +} + +// ----------------------------------------------------------------------------- + +shared_ptr RealTimeTextChatRoom::addParticipant (const Address &addr, const shared_ptr params, bool hasMedia) { + lError() << "addParticipant() is not allowed on a RealTimeTextChatRoom"; + return nullptr; +} + +void RealTimeTextChatRoom::addParticipants (const list
&addresses, const shared_ptr params, bool hasMedia) { + lError() << "addParticipants() is not allowed on a RealTimeTextChatRoom"; +} + +const string& RealTimeTextChatRoom::getId () const { + L_D(const RealTimeTextChatRoom); + lError() << "a RealTimeTextChatRoom does not have a conference id"; + return d->dummyConferenceId; +} + +int RealTimeTextChatRoom::getNbParticipants () const { + return 1; +} + +list> RealTimeTextChatRoom::getParticipants () const { + L_D(const RealTimeTextChatRoom); + list> l; + l.push_back(make_shared(d->peerAddress)); + return l; +} + +void RealTimeTextChatRoom::removeParticipant (const shared_ptr participant) { + lError() << "removeParticipant() is not allowed on a RealTimeTextChatRoom"; +} + +void RealTimeTextChatRoom::removeParticipants (const list> participants) { + lError() << "removeParticipants() is not allowed on a RealTimeTextChatRoom"; +} + +LINPHONE_END_NAMESPACE diff --git a/src/chat/real-time-text-chat-room.h b/src/chat/real-time-text-chat-room.h new file mode 100644 index 000000000..3987a8a9b --- /dev/null +++ b/src/chat/real-time-text-chat-room.h @@ -0,0 +1,62 @@ +/* + * real-time-text-chat-room.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _REAL_TIME_TEXT_CHAT_ROOM_H_ +#define _REAL_TIME_TEXT_CHAT_ROOM_H_ + +// From coreapi +#include "private.h" + +#include "chat/chat-room.h" + +#include "linphone/types.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class RealTimeTextChatRoomPrivate; + +class RealTimeTextChatRoom : public ChatRoom { +public: + RealTimeTextChatRoom (LinphoneCore *core, const Address &peerAddress); + virtual ~RealTimeTextChatRoom () = default; + + void sendMessage (LinphoneChatMessage *msg); + + uint32_t getChar () const; + LinphoneCall *getCall () const; + + /* ConferenceInterface */ + std::shared_ptr addParticipant (const Address &addr, const std::shared_ptr params, bool hasMedia); + void addParticipants (const std::list
&addresses, const std::shared_ptr params, bool hasMedia); + const std::string& getId () const; + int getNbParticipants () const; + std::list> getParticipants () const; + void removeParticipant (const std::shared_ptr participant); + void removeParticipants (const std::list> participants); + +private: + L_DECLARE_PRIVATE(RealTimeTextChatRoom); + L_DISABLE_COPY(RealTimeTextChatRoom); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _REAL_TIME_TEXT_CHAT_ROOM_H_ + diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index 181052912..6c0090e05 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -33,7 +33,7 @@ LINPHONE_BEGIN_NAMESPACE class ConferenceInterface { public: virtual std::shared_ptr addParticipant (const Address &addr, const std::shared_ptr params, bool hasMedia) = 0; - virtual void addParticipants (const std::list &addresses, const std::shared_ptr params, bool hasMedia) = 0; + virtual void addParticipants (const std::list
&addresses, const std::shared_ptr params, bool hasMedia) = 0; virtual const std::string& getId () const = 0; virtual int getNbParticipants () const = 0; virtual std::list> getParticipants () const = 0; diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 5175c43fe..affe724ec 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -109,7 +109,7 @@ shared_ptr Conference::addParticipant (const Address &addr, const s return d->activeParticipant; } -void Conference::addParticipants (const list &addresses, const shared_ptr params, bool hasMedia) { +void Conference::addParticipants (const list
&addresses, const shared_ptr params, bool hasMedia) { // TODO } diff --git a/src/conference/conference.h b/src/conference/conference.h index 04d69279e..c5c9619b7 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -46,7 +46,7 @@ public: /* ConferenceInterface */ virtual std::shared_ptr addParticipant (const Address &addr, const std::shared_ptr params, bool hasMedia); - virtual void addParticipants (const std::list &addresses, const std::shared_ptr params, bool hasMedia); + virtual void addParticipants (const std::list
&addresses, const std::shared_ptr params, bool hasMedia); virtual const std::string& getId () const; virtual int getNbParticipants () const; virtual std::list> getParticipants () const; From 6c6135826748cd9045c7d0ff5754dafbdf900937 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 12 Sep 2017 11:28:01 +0200 Subject: [PATCH 0031/2215] Set 'on' prefix for listener methods. --- src/call/call-listener.h | 26 +++++----- src/call/call-p.h | 32 ++++++------ src/call/call.cpp | 28 +++++----- src/chat/chat-room-p.h | 7 +-- src/chat/chat-room.cpp | 6 +-- src/chat/is-composing-listener.h | 6 +-- src/chat/is-composing.cpp | 8 +-- src/conference/conference-listener.h | 10 ++-- src/conference/conference-p.h | 32 ++++++------ src/conference/conference.cpp | 52 +++++++++---------- .../session/call-session-listener.h | 26 +++++----- src/conference/session/call-session.cpp | 16 +++--- src/conference/session/media-session.cpp | 18 +++---- 13 files changed, 132 insertions(+), 135 deletions(-) diff --git a/src/call/call-listener.h b/src/call/call-listener.h index f20ac5c2b..90027833d 100644 --- a/src/call/call-listener.h +++ b/src/call/call-listener.h @@ -29,23 +29,23 @@ LINPHONE_BEGIN_NAMESPACE class CallListener { public: - virtual void ackBeingSent (LinphoneHeaders *headers) = 0; - virtual void ackReceived (LinphoneHeaders *headers) = 0; - virtual void callSetReleased () = 0; - virtual void callSetTerminated () = 0; - virtual void callStateChanged (LinphoneCallState state, const std::string &message) = 0; - virtual void incomingCallStarted () = 0; - virtual void incomingCallToBeAdded () = 0; + virtual void onAckBeingSent (LinphoneHeaders *headers) = 0; + virtual void onAckReceived (LinphoneHeaders *headers) = 0; + virtual void onCallSetReleased () = 0; + virtual void onCallSetTerminated () = 0; + virtual void onCallStateChanged (LinphoneCallState state, const std::string &message) = 0; + virtual void onIncomingCallStarted () = 0; + virtual void onIncomingCallToBeAdded () = 0; - virtual void encryptionChanged (bool activated, const std::string &authToken) = 0; + virtual void onEncryptionChanged (bool activated, const std::string &authToken) = 0; - virtual void statsUpdated (const LinphoneCallStats *stats) = 0; + virtual void onStatsUpdated (const LinphoneCallStats *stats) = 0; - virtual void resetCurrentCall () = 0; - virtual void setCurrentCall () = 0; + virtual void onResetCurrentCall () = 0; + virtual void onSetCurrentCall () = 0; - virtual void firstVideoFrameDecoded () = 0; - virtual void resetFirstVideoFrameDecoded () = 0; + virtual void onFirstVideoFrameDecoded () = 0; + virtual void onResetFirstVideoFrameDecoded () = 0; }; LINPHONE_END_NAMESPACE diff --git a/src/call/call-p.h b/src/call/call-p.h index 5233a0863..78e7a69de 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -57,23 +57,21 @@ public: SalOp * getOp () const; void setAudioMuted (bool value); - void ackBeingSent (LinphoneHeaders *headers); - void ackReceived (LinphoneHeaders *headers); - void callSetReleased (); - void callSetTerminated (); - void callStateChanged (LinphoneCallState state, const std::string &message); - void incomingCallStarted (); - void incomingCallToBeAdded (); - - void encryptionChanged (bool activated, const std::string &authToken); - - void statsUpdated (const LinphoneCallStats *stats); - - void resetCurrentCall (); - void setCurrentCall (); - - void firstVideoFrameDecoded (); - void resetFirstVideoFrameDecoded (); +private: + /* CallListener */ + void onAckBeingSent (LinphoneHeaders *headers); + void onAckReceived (LinphoneHeaders *headers); + void onCallSetReleased (); + void onCallSetTerminated (); + void onCallStateChanged (LinphoneCallState state, const std::string &message); + void onIncomingCallStarted (); + void onIncomingCallToBeAdded (); + void onEncryptionChanged (bool activated, const std::string &authToken); + void onStatsUpdated (const LinphoneCallStats *stats); + void onResetCurrentCall (); + void onSetCurrentCall (); + void onFirstVideoFrameDecoded (); + void onResetFirstVideoFrameDecoded (); private: LinphoneCall *lcall = nullptr; diff --git a/src/call/call.cpp b/src/call/call.cpp index 8c638c909..e3da64617 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -99,22 +99,22 @@ int CallPrivate::startInvite (const Address *destination) { // ----------------------------------------------------------------------------- -void CallPrivate::ackBeingSent (LinphoneHeaders *headers) { +void CallPrivate::onAckBeingSent (LinphoneHeaders *headers) { if (lcall) linphone_call_notify_ack_processing(lcall, headers, false); } -void CallPrivate::ackReceived (LinphoneHeaders *headers) { +void CallPrivate::onAckReceived (LinphoneHeaders *headers) { if (lcall) linphone_call_notify_ack_processing(lcall, headers, true); } -void CallPrivate::callSetReleased () { +void CallPrivate::onCallSetReleased () { if (lcall) linphone_call_unref(lcall); } -void CallPrivate::callSetTerminated () { +void CallPrivate::onCallSetTerminated () { if (lcall) { if (lcall == core->current_call) { lInfo() << "Resetting the current call"; @@ -137,41 +137,41 @@ void CallPrivate::callSetTerminated () { } } -void CallPrivate::callStateChanged (LinphoneCallState state, const std::string &message) { +void CallPrivate::onCallStateChanged (LinphoneCallState state, const std::string &message) { if (lcall) linphone_call_notify_state_changed(lcall, state, message.c_str()); } -void CallPrivate::incomingCallStarted () { +void CallPrivate::onIncomingCallStarted () { if (lcall) linphone_core_notify_incoming_call(core, lcall); } -void CallPrivate::incomingCallToBeAdded () { +void CallPrivate::onIncomingCallToBeAdded () { if (lcall) /* The call is acceptable so we can now add it to our list */ linphone_core_add_call(core, lcall); } -void CallPrivate::encryptionChanged (bool activated, const std::string &authToken) { +void CallPrivate::onEncryptionChanged (bool activated, const std::string &authToken) { if (lcall) linphone_call_notify_encryption_changed(lcall, activated, authToken.empty() ? nullptr : authToken.c_str()); } -void CallPrivate::statsUpdated (const LinphoneCallStats *stats) { +void CallPrivate::onStatsUpdated (const LinphoneCallStats *stats) { if (lcall) linphone_call_notify_stats_updated(lcall, stats); } -void CallPrivate::resetCurrentCall () { +void CallPrivate::onResetCurrentCall () { core->current_call = nullptr; } -void CallPrivate::setCurrentCall () { +void CallPrivate::onSetCurrentCall () { if (lcall) core->current_call = lcall; } -void CallPrivate::firstVideoFrameDecoded () { +void CallPrivate::onFirstVideoFrameDecoded () { if (lcall && nextVideoFrameDecoded._func) { nextVideoFrameDecoded._func(lcall, nextVideoFrameDecoded._user_data); nextVideoFrameDecoded._func = nullptr; @@ -179,7 +179,7 @@ void CallPrivate::firstVideoFrameDecoded () { } } -void CallPrivate::resetFirstVideoFrameDecoded () { +void CallPrivate::onResetFirstVideoFrameDecoded () { #ifdef VIDEO_ENABLED if (lcall && nextVideoFrameDecoded._func) static_cast(getActiveSession().get())->resetFirstVideoFrameDecoded(); @@ -491,7 +491,7 @@ void Call::setNextVideoFrameDecodedCallback (LinphoneCallCbFunc cb, void *user_d L_D(Call); d->nextVideoFrameDecoded._func = cb; d->nextVideoFrameDecoded._user_data = user_data; - d->resetFirstVideoFrameDecoded(); + d->onResetFirstVideoFrameDecoded(); } void Call::setSpeakerVolumeGain (float value) { diff --git a/src/chat/chat-room-p.h b/src/chat/chat-room-p.h index 6d480f77f..2e6f88bb0 100644 --- a/src/chat/chat-room-p.h +++ b/src/chat/chat-room-p.h @@ -84,9 +84,10 @@ protected: void isComposingReceived (const std::string &text); private: - void isComposingStateChanged (bool isComposing); - void isRemoteComposingStateChanged (bool isComposing); - void isComposingRefreshNeeded (); + /* IsComposingListener */ + void onIsComposingStateChanged (bool isComposing); + void onIsRemoteComposingStateChanged (bool isComposing); + void onIsComposingRefreshNeeded (); public: LinphoneChatRoom *cBackPointer = nullptr; diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index a3e7f4030..8e1158644 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -522,17 +522,17 @@ void ChatRoomPrivate::isComposingReceived (const string &text) { // ----------------------------------------------------------------------------- -void ChatRoomPrivate::isComposingStateChanged (bool isComposing) { +void ChatRoomPrivate::onIsComposingStateChanged (bool isComposing) { this->isComposing = isComposing; sendIsComposingNotification(); } -void ChatRoomPrivate::isRemoteComposingStateChanged (bool isComposing) { +void ChatRoomPrivate::onIsRemoteComposingStateChanged (bool isComposing) { remoteIsComposing = isComposing; linphone_core_notify_is_composing_received(core, cBackPointer); } -void ChatRoomPrivate::isComposingRefreshNeeded () { +void ChatRoomPrivate::onIsComposingRefreshNeeded () { sendIsComposingNotification(); } diff --git a/src/chat/is-composing-listener.h b/src/chat/is-composing-listener.h index 730fc9761..9d8c2a40b 100644 --- a/src/chat/is-composing-listener.h +++ b/src/chat/is-composing-listener.h @@ -27,9 +27,9 @@ LINPHONE_BEGIN_NAMESPACE class IsComposingListener { public: - virtual void isComposingStateChanged (bool isComposing) = 0; - virtual void isRemoteComposingStateChanged (bool isComposing) = 0; - virtual void isComposingRefreshNeeded () = 0; + virtual void onIsComposingStateChanged (bool isComposing) = 0; + virtual void onIsRemoteComposingStateChanged (bool isComposing) = 0; + virtual void onIsComposingRefreshNeeded () = 0; }; LINPHONE_END_NAMESPACE diff --git a/src/chat/is-composing.cpp b/src/chat/is-composing.cpp index efc1c685d..09bd1ba2a 100644 --- a/src/chat/is-composing.cpp +++ b/src/chat/is-composing.cpp @@ -226,7 +226,7 @@ void IsComposing::parse (xmlparsing_context_t *xmlCtx) { stopRemoteRefreshTimer(); } - listener->isRemoteComposingStateChanged(state); + listener->onIsRemoteComposingStateChanged(state); linphone_free_xml_text_content(stateStr); } if (refreshStr) @@ -234,18 +234,18 @@ void IsComposing::parse (xmlparsing_context_t *xmlCtx) { } int IsComposing::idleTimerExpired (unsigned int revents) { - listener->isComposingStateChanged(false); + listener->onIsComposingStateChanged(false); return BELLE_SIP_STOP; } int IsComposing::refreshTimerExpired (unsigned int revents) { - listener->isComposingRefreshNeeded(); + listener->onIsComposingRefreshNeeded(); return BELLE_SIP_CONTINUE; } int IsComposing::remoteRefreshTimerExpired (unsigned int revents) { stopRemoteRefreshTimer(); - listener->isRemoteComposingStateChanged(false); + listener->onIsRemoteComposingStateChanged(false); return BELLE_SIP_STOP; } diff --git a/src/conference/conference-listener.h b/src/conference/conference-listener.h index 4bed6f68a..c68f634a4 100644 --- a/src/conference/conference-listener.h +++ b/src/conference/conference-listener.h @@ -25,11 +25,11 @@ LINPHONE_BEGIN_NAMESPACE class ConferenceListener { public: - virtual void conferenceCreated (LinphoneAddress *addr) = 0; - virtual void conferenceTerminated (LinphoneAddress *addr) = 0; - virtual void participantAdded (LinphoneAddress *addr) = 0; - virtual void participantRemoved (LinphoneAddress *addr) = 0; - virtual void participantSetAdmin (LinphoneAddress *addr, bool isAdmin) = 0; + virtual void onConferenceCreated (LinphoneAddress *addr) = 0; + virtual void onConferenceTerminated (LinphoneAddress *addr) = 0; + virtual void onParticipantAdded (LinphoneAddress *addr) = 0; + virtual void onParticipantRemoved (LinphoneAddress *addr) = 0; + virtual void onParticipantSetAdmin (LinphoneAddress *addr, bool isAdmin) = 0; }; LINPHONE_END_NAMESPACE diff --git a/src/conference/conference-p.h b/src/conference/conference-p.h index 52036702b..e2341de01 100644 --- a/src/conference/conference-p.h +++ b/src/conference/conference-p.h @@ -39,23 +39,21 @@ public: LinphoneCore * getCore () const { return core; } - virtual void ackBeingSent (const CallSession &session, LinphoneHeaders *headers); - virtual void ackReceived (const CallSession &session, LinphoneHeaders *headers); - virtual void callSessionAccepted (const CallSession &session); - virtual void callSessionSetReleased (const CallSession &session); - virtual void callSessionSetTerminated (const CallSession &session); - virtual void callSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message); - virtual void incomingCallSessionStarted (const CallSession &session); - - virtual void encryptionChanged (const CallSession &session, bool activated, const std::string &authToken); - - virtual void statsUpdated (const LinphoneCallStats *stats); - - virtual void resetCurrentSession (const CallSession &session); - virtual void setCurrentSession (const CallSession &session); - - virtual void firstVideoFrameDecoded (const CallSession &session); - virtual void resetFirstVideoFrameDecoded (const CallSession &session); +private: + /* CallSessionListener */ + virtual void onAckBeingSent (const CallSession &session, LinphoneHeaders *headers); + virtual void onAckReceived (const CallSession &session, LinphoneHeaders *headers); + virtual void onCallSessionAccepted (const CallSession &session); + virtual void onCallSessionSetReleased (const CallSession &session); + virtual void onCallSessionSetTerminated (const CallSession &session); + virtual void onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message); + virtual void onIncomingCallSessionStarted (const CallSession &session); + virtual void onEncryptionChanged (const CallSession &session, bool activated, const std::string &authToken); + virtual void onStatsUpdated (const LinphoneCallStats *stats); + virtual void onResetCurrentSession (const CallSession &session); + virtual void onSetCurrentSession (const CallSession &session); + virtual void onFirstVideoFrameDecoded (const CallSession &session); + virtual void onResetFirstVideoFrameDecoded (const CallSession &session); private: LinphoneCore *core = nullptr; diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index affe724ec..856a6e587 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -27,69 +27,69 @@ LINPHONE_BEGIN_NAMESPACE // ============================================================================= -void ConferencePrivate::ackBeingSent (const CallSession &session, LinphoneHeaders *headers) { +void ConferencePrivate::onAckBeingSent (const CallSession &session, LinphoneHeaders *headers) { if (callListener) - callListener->ackBeingSent(headers); + callListener->onAckBeingSent(headers); } -void ConferencePrivate::ackReceived (const CallSession &session, LinphoneHeaders *headers) { +void ConferencePrivate::onAckReceived (const CallSession &session, LinphoneHeaders *headers) { if (callListener) - callListener->ackReceived(headers); + callListener->onAckReceived(headers); } -void ConferencePrivate::callSessionAccepted (const CallSession &session) { +void ConferencePrivate::onCallSessionAccepted (const CallSession &session) { if (callListener) - callListener->incomingCallToBeAdded(); + callListener->onIncomingCallToBeAdded(); } -void ConferencePrivate::callSessionSetReleased (const CallSession &session) { +void ConferencePrivate::onCallSessionSetReleased (const CallSession &session) { if (callListener) - callListener->callSetReleased(); + callListener->onCallSetReleased(); } -void ConferencePrivate::callSessionSetTerminated (const CallSession &session) { +void ConferencePrivate::onCallSessionSetTerminated (const CallSession &session) { if (callListener) - callListener->callSetTerminated(); + callListener->onCallSetTerminated(); } -void ConferencePrivate::callSessionStateChanged (const CallSession &session, LinphoneCallState state, const string &message) { +void ConferencePrivate::onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const string &message) { if (callListener) - callListener->callStateChanged(state, message); + callListener->onCallStateChanged(state, message); } -void ConferencePrivate::incomingCallSessionStarted (const CallSession &session) { +void ConferencePrivate::onIncomingCallSessionStarted (const CallSession &session) { if (callListener) - callListener->incomingCallStarted(); + callListener->onIncomingCallStarted(); } -void ConferencePrivate::encryptionChanged (const CallSession &session, bool activated, const string &authToken) { +void ConferencePrivate::onEncryptionChanged (const CallSession &session, bool activated, const string &authToken) { if (callListener) - callListener->encryptionChanged(activated, authToken); + callListener->onEncryptionChanged(activated, authToken); } -void ConferencePrivate::statsUpdated (const LinphoneCallStats *stats) { +void ConferencePrivate::onStatsUpdated (const LinphoneCallStats *stats) { if (callListener) - callListener->statsUpdated(stats); + callListener->onStatsUpdated(stats); } -void ConferencePrivate::resetCurrentSession (const CallSession &session) { +void ConferencePrivate::onResetCurrentSession (const CallSession &session) { if (callListener) - callListener->resetCurrentCall(); + callListener->onResetCurrentCall(); } -void ConferencePrivate::setCurrentSession (const CallSession &session) { +void ConferencePrivate::onSetCurrentSession (const CallSession &session) { if (callListener) - callListener->setCurrentCall(); + callListener->onSetCurrentCall(); } -void ConferencePrivate::firstVideoFrameDecoded (const CallSession &session) { +void ConferencePrivate::onFirstVideoFrameDecoded (const CallSession &session) { if (callListener) - callListener->firstVideoFrameDecoded(); + callListener->onFirstVideoFrameDecoded(); } -void ConferencePrivate::resetFirstVideoFrameDecoded (const CallSession &session) { +void ConferencePrivate::onResetFirstVideoFrameDecoded (const CallSession &session) { if (callListener) - callListener->resetFirstVideoFrameDecoded(); + callListener->onResetFirstVideoFrameDecoded(); } // ============================================================================= diff --git a/src/conference/session/call-session-listener.h b/src/conference/session/call-session-listener.h index 96d96d6f9..29f574559 100644 --- a/src/conference/session/call-session-listener.h +++ b/src/conference/session/call-session-listener.h @@ -25,23 +25,23 @@ LINPHONE_BEGIN_NAMESPACE class CallSessionListener { public: - virtual void ackBeingSent (const CallSession &session, LinphoneHeaders *headers) = 0; - virtual void ackReceived (const CallSession &session, LinphoneHeaders *headers) = 0; - virtual void callSessionAccepted (const CallSession &session) = 0; - virtual void callSessionSetReleased (const CallSession &session) = 0; - virtual void callSessionSetTerminated (const CallSession &session) = 0; - virtual void callSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message) = 0; - virtual void incomingCallSessionStarted (const CallSession &session) = 0; + virtual void onAckBeingSent (const CallSession &session, LinphoneHeaders *headers) = 0; + virtual void onAckReceived (const CallSession &session, LinphoneHeaders *headers) = 0; + virtual void onCallSessionAccepted (const CallSession &session) = 0; + virtual void onCallSessionSetReleased (const CallSession &session) = 0; + virtual void onCallSessionSetTerminated (const CallSession &session) = 0; + virtual void onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message) = 0; + virtual void onIncomingCallSessionStarted (const CallSession &session) = 0; - virtual void encryptionChanged (const CallSession &session, bool activated, const std::string &authToken) = 0; + virtual void onEncryptionChanged (const CallSession &session, bool activated, const std::string &authToken) = 0; - virtual void statsUpdated (const LinphoneCallStats *stats) = 0; + virtual void onStatsUpdated (const LinphoneCallStats *stats) = 0; - virtual void resetCurrentSession (const CallSession &session) = 0; - virtual void setCurrentSession (const CallSession &session) = 0; + virtual void onResetCurrentSession (const CallSession &session) = 0; + virtual void onSetCurrentSession (const CallSession &session) = 0; - virtual void firstVideoFrameDecoded (const CallSession &session) = 0; - virtual void resetFirstVideoFrameDecoded (const CallSession &session) = 0; + virtual void onFirstVideoFrameDecoded (const CallSession &session) = 0; + virtual void onResetFirstVideoFrameDecoded (const CallSession &session) = 0; }; LINPHONE_END_NAMESPACE diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index b88a80ae8..ef902e8eb 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -184,7 +184,7 @@ void CallSessionPrivate::setState(LinphoneCallState newState, const string &mess linphone_call_state_to_string(prevState) << " to " << linphone_call_state_to_string(state) << ")"; } if (listener) - listener->callSessionStateChanged(*q, state, message); + listener->onCallSessionStateChanged(*q, state, message); if (newState == LinphoneCallReleased) setReleased(); /* Shall be performed after app notification */ } @@ -247,13 +247,13 @@ void CallSessionPrivate::accepted () { void CallSessionPrivate::ackBeingSent (LinphoneHeaders *headers) { L_Q(CallSession); if (listener) - listener->ackBeingSent(*q, headers); + listener->onAckBeingSent(*q, headers); } void CallSessionPrivate::ackReceived (LinphoneHeaders *headers) { L_Q(CallSession); if (listener) - listener->ackReceived(*q, headers); + listener->onAckReceived(*q, headers); } bool CallSessionPrivate::failure () { @@ -488,7 +488,7 @@ void CallSessionPrivate::accept (const shared_ptr params) { sal_call_accept(op); linphone_core_notify_display_status(core, _("Connected.")); if (listener) - listener->setCurrentSession(*q); + listener->onSetCurrentSession(*q); setState(LinphoneCallConnected, "Connected"); } @@ -615,7 +615,7 @@ void CallSessionPrivate::setReleased () { } #endif if (listener) - listener->callSessionSetReleased(*q); + listener->onCallSessionSetReleased(*q); } /* This method is called internally to get rid of a call that was notified to the application, @@ -627,7 +627,7 @@ void CallSessionPrivate::setTerminated() { L_Q(CallSession); completeLog(); if (listener) - listener->callSessionSetTerminated(*q); + listener->onCallSessionSetTerminated(*q); } LinphoneStatus CallSessionPrivate::startAcceptUpdate (LinphoneCallState nextState, const std::string &stateInfo) { @@ -882,7 +882,7 @@ void CallSession::iterate (time_t currentRealTime, bool oneSecondElapsed) { void CallSession::startIncomingNotification () { L_D(CallSession); if (d->listener) - d->listener->callSessionAccepted(*this); + d->listener->onCallSessionAccepted(*this); /* Prevent the CallSession from being destroyed while we are notifying, if the user declines within the state callback */ shared_ptr ref = shared_from_this(); #if 0 @@ -904,7 +904,7 @@ void CallSession::startIncomingNotification () { ms_free(msg); if (d->listener) - d->listener->incomingCallSessionStarted(*this); + d->listener->onIncomingCallSessionStarted(*this); d->setState(LinphoneCallIncomingReceived, "Incoming call"); diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index e74ee7cca..615f1bdf4 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -158,7 +158,7 @@ void MediaSessionPrivate::accepted () { nextStateMsg = "Call paused by remote"; } else { if (!params->getPrivate()->getInConference() && listener) - listener->setCurrentSession(*q); + listener->onSetCurrentSession(*q); nextState = LinphoneCallStreamsRunning; nextStateMsg = "Streams running"; } @@ -865,7 +865,7 @@ void MediaSessionPrivate::notifyStatsUpdated (int streamIndex) const { break; } if (listener) - listener->statsUpdated(stats); + listener->onStatsUpdated(stats); stats->updated = 0; } } @@ -2926,7 +2926,7 @@ void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { } ms_media_stream_sessions_set_encryption_mandatory(&videoStream->ms.sessions, isEncryptionMandatory()); if (listener) - listener->resetFirstVideoFrameDecoded(*q); + listener->onResetFirstVideoFrameDecoded(*q); /* Start ZRTP engine if needed : set here or remote have a zrtp-hash attribute */ SalMediaDescription *remote = sal_call_get_remote_media_description(op); const SalStreamDescription *remoteStream = sal_media_description_find_best_stream(remote, SalVideo); @@ -3357,7 +3357,7 @@ void MediaSessionPrivate::propagateEncryptionChanged () { lInfo() << "Some streams are not encrypted"; q->getCurrentParams()->setMediaEncryption(LinphoneMediaEncryptionNone); if (listener) - listener->encryptionChanged(*q, false, authToken); + listener->onEncryptionChanged(*q, false, authToken); } else { if (!authToken.empty()) { /* ZRTP only is using auth_token */ @@ -3370,7 +3370,7 @@ void MediaSessionPrivate::propagateEncryptionChanged () { << ((q->getCurrentParams()->getMediaEncryption() == LinphoneMediaEncryptionZRTP) ? "ZRTP" : (q->getCurrentParams()->getMediaEncryption() == LinphoneMediaEncryptionDTLS) ? "DTLS" : "Unknown mechanism"); if (listener) - listener->encryptionChanged(*q, true, authToken); + listener->onEncryptionChanged(*q, true, authToken); #ifdef VIDEO_ENABLED if (isEncryptionMandatory() && videoStream && media_stream_started(&videoStream->ms)) { /* Nothing could have been sent yet so generating key frame */ @@ -3621,7 +3621,7 @@ void MediaSessionPrivate::reportBandwidthForStream (MediaStream *ms, LinphoneStr linphone_call_stats_update(stats, ms); stats->updated |= LINPHONE_CALL_STATS_PERIODICAL_UPDATE; if (listener) - listener->statsUpdated(stats); + listener->onStatsUpdated(stats); stats->updated = 0; } } @@ -3684,7 +3684,7 @@ LinphoneStatus MediaSessionPrivate::pause () { if (sal_call_update(op, subject.c_str(), false) != 0) linphone_core_notify_display_warning(core, "Could not pause the call"); if (listener) - listener->resetCurrentSession(*q); + listener->onResetCurrentSession(*q); linphone_core_notify_display_status(core, "Pausing the current call..."); if (audioStream || videoStream || textStream) stopStreams(); @@ -3940,7 +3940,7 @@ void MediaSessionPrivate::videoStreamEventCb (const MSFilter *f, const unsigned case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED: lInfo() << "First video frame decoded successfully"; if (listener) - listener->firstVideoFrameDecoded(*q); + listener->onFirstVideoFrameDecoded(*q); break; case MS_VIDEO_DECODER_SEND_PLI: case MS_VIDEO_DECODER_SEND_SLI: @@ -4202,7 +4202,7 @@ LinphoneStatus MediaSession::resume () { return -1; d->setState(LinphoneCallResuming,"Resuming"); if (!d->params->getPrivate()->getInConference() && d->listener) - d->listener->setCurrentSession(*this); + d->listener->onSetCurrentSession(*this); ostringstream os; os << "Resuming the call with " << getRemoteAddressAsString(); linphone_core_notify_display_status(d->core, os.str().c_str()); From 665ff35efc7b5ed11abfcb3a9f7c1254b3146880 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 12 Sep 2017 11:30:52 +0200 Subject: [PATCH 0032/2215] feat(core): add wrapped content --- src/content/content.cpp | 146 +++++++++++++++++++++++++++++++++++++++- src/content/content.h | 35 +++++++++- 2 files changed, 175 insertions(+), 6 deletions(-) diff --git a/src/content/content.cpp b/src/content/content.cpp index 2003b1613..b3fd66d4e 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -16,22 +16,162 @@ * along with this program. If not, see . */ +// From coreapi. +#include "private.h" + +#include "c-wrapper/c-tools.h" #include "object/object-p.h" #include "content.h" // ============================================================================= +using namespace std; + LINPHONE_BEGIN_NAMESPACE class ContentPrivate : public ObjectPrivate { -private: +public: + struct Cache { + string type; + string subType; + string customHeaderValue; + string encoding; + }; - L_DECLARE_PUBLIC(Content); + SalBodyHandler *bodyHandler = nullptr; + void *cryptoContext = nullptr; + string name; + string key; + + mutable Cache cache; }; // ----------------------------------------------------------------------------- -Content::Content (ContentPrivate &p) : Object(p) {} +Content::Content () : Object(*new ContentPrivate) {} + +const string &Content::getType () const { + L_D(const Content); + d->cache.type = sal_body_handler_get_subtype(d->bodyHandler); + return d->cache.type; +} + +void Content::setType (const string &type) { + L_D(Content); + sal_body_handler_set_type(d->bodyHandler, L_STRING_TO_C(type)); +} + +const string &Content::getSubType () const { + L_D(const Content); + d->cache.subType = sal_body_handler_get_subtype(d->bodyHandler); + return d->cache.subType; +} + +void Content::setSubType (const string &subType) { + L_D(Content); + sal_body_handler_set_subtype(d->bodyHandler, L_STRING_TO_C(subType)); +} + +const void *Content::getBuffer () const { + L_D(const Content); + return sal_body_handler_get_data(d->bodyHandler); +} + +void Content::setBuffer (const void *buffer, size_t size) { + L_D(Content); + sal_body_handler_set_size(d->bodyHandler, size); + void *data = belle_sip_malloc(size); + sal_body_handler_set_data(d->bodyHandler, memcpy(data, buffer, size)); +} + +size_t Content::getSize () const { + L_D(const Content); + return sal_body_handler_get_size(d->bodyHandler); +} + +void Content::setSize (size_t size) { + L_D(Content); + sal_body_handler_set_data(d->bodyHandler, nullptr); + sal_body_handler_set_size(d->bodyHandler, size); +} + +const string &Content::getEncoding () const { + L_D(const Content); + d->cache.encoding = sal_body_handler_get_encoding(d->bodyHandler); + return d->cache.encoding; +} + +void Content::setEncoding (const string &encoding) { + L_D(Content); + sal_body_handler_set_encoding(d->bodyHandler, L_STRING_TO_C(encoding)); +} + +const string &Content::getName () const { + L_D(const Content); + return d->name; +} + +void Content::setName (const string &name) { + L_D(Content); + d->name = name; +} + +bool Content::isMultipart () const { + L_D(const Content); + return sal_body_handler_is_multipart(d->bodyHandler); +} + +shared_ptr Content::getPart (int index) const { + L_D(const Content); + + if (!isMultipart()) + return nullptr; + + SalBodyHandler *bodyHandler = sal_body_handler_get_part(d->bodyHandler, index); + if (!bodyHandler) + return nullptr; + + Content *content = new Content(); + sal_body_handler_ref(bodyHandler); + content->getPrivate()->bodyHandler = bodyHandler; + return shared_ptr(content); +} + +shared_ptr Content::findPartByHeader (const string &headerName, const string &headerValue) const { + L_D(const Content); + + if (!isMultipart()) + return nullptr; + + SalBodyHandler *bodyHandler = sal_body_handler_find_part_by_header( + d->bodyHandler, + L_STRING_TO_C(headerName), + L_STRING_TO_C(headerValue) + ); + if (!bodyHandler) + return nullptr; + + Content *content = new Content(); + sal_body_handler_ref(bodyHandler); + content->getPrivate()->bodyHandler = bodyHandler; + return shared_ptr(content); +} + +const string &Content::getCustomHeaderValue (const string &headerName) const { + L_D(const Content); + d->cache.customHeaderValue = sal_body_handler_get_header(d->bodyHandler, L_STRING_TO_C(headerName)); + return d->cache.customHeaderValue; +} + +const string &Content::getKey () const { + L_D(const Content); + return d->key; +} + +void Content::setKey (const string &key) { + L_D(Content); + d->key = key; +} LINPHONE_END_NAMESPACE diff --git a/src/content/content.h b/src/content/content.h index fa59de1e7..89f4b16e8 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -19,6 +19,9 @@ #ifndef _CONTENT_H_ #define _CONTENT_H_ +#include +#include + #include "object/object.h" // ============================================================================= @@ -27,14 +30,40 @@ LINPHONE_BEGIN_NAMESPACE class ContentPrivate; -class LINPHONE_PUBLIC Content : public Object { +class Content : public Object { friend class Core; public: - // Nothing for the moment. + const std::string &getType () const; + void setType (const std::string &type); + + const std::string &getSubType () const; + void setSubType (const std::string &subType); + + const void *getBuffer () const; + void setBuffer (const void *buffer, size_t size); + + size_t getSize () const; + void setSize (size_t size); + + const std::string &getEncoding () const; + void setEncoding (const std::string &encoding); + + const std::string &getName () const; + void setName (const std::string &name); + + bool isMultipart () const; + + std::shared_ptr getPart (int index) const; + std::shared_ptr findPartByHeader (const std::string &headerName, const std::string &headerValue) const; + + const std::string &getCustomHeaderValue (const std::string &headerName) const; + + const std::string &getKey () const; + void setKey (const std::string &key); private: - Content (ContentPrivate &p); + Content (); L_DECLARE_PRIVATE(Content); L_DISABLE_COPY(Content); From 1e1d0d2f7fb6f7e62138fd56a1a4546e50da3d6c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 12 Sep 2017 11:55:35 +0200 Subject: [PATCH 0033/2215] Add c-tools macros and methods to convert bctbx_list_t to std::list and the opposite. --- coreapi/chat.c | 6 +----- src/c-wrapper/c-tools.h | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 807c1701b..b51c7284a 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -682,11 +682,7 @@ void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call) { } bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr) { - std::list l = L_GET_PRIVATE(cr->cr)->getTransientMessages(); - bctbx_list_t *result = nullptr; - for (auto it = l.begin(); it != l.end(); it++) - result = bctbx_list_append(result, *it); - return result; + return L_GET_C_LIST_FROM_CPP_LIST(L_GET_PRIVATE(cr->cr)->getTransientMessages(), LinphoneChatMessage); } const char *linphone_chat_message_state_to_string(const LinphoneChatMessageState state) { diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index 8f4b6d738..e97368bcf 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -19,6 +19,7 @@ #ifndef _C_TOOLS_H_ #define _C_TOOLS_H_ +#include #include #include @@ -63,6 +64,22 @@ public: static_cast *>(object)->cppPtr = cppPtr; } + template + static inline bctbx_list_t * getCListFromCppList (std::list cppList) { + bctbx_list_t *result = nullptr; + for (auto it = cppList.begin(); it != cppList.end(); it++) + result = bctbx_list_append(result, *it); + return result; + } + + template + static inline std::list getCppListFromCList (bctbx_list_t *cList) { + std::list result; + for (auto it = cList; it; it = bctbx_list_next(it)) + result.push_back(static_cast(bctbx_list_get_data(it))); + return result; + } + private: Wrapper (); @@ -121,4 +138,9 @@ LINPHONE_END_NAMESPACE #define L_GET_PRIVATE_FROM_C_STRUCT(OBJECT, TYPE) \ L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, TYPE).get()) +#define L_GET_C_LIST_FROM_CPP_LIST(LIST, TYPE) \ + LINPHONE_NAMESPACE::Wrapper::getCListFromCppList(LIST) +#define L_GET_CPP_LIST_FROM_C_LIST(LIST, TYPE) \ + LINPHONE_NAMESPACE::Wrapper::getCppListFromCList(LIST) + #endif // ifndef _C_TOOLS_H_ From 68bb508cb5af4173be1bb2d8411a2bd9b73af272 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 12 Sep 2017 12:11:49 +0200 Subject: [PATCH 0034/2215] feat(core): add ContentType class --- src/CMakeLists.txt | 10 +++- src/content/content-type.cpp | 111 +++++++++++++++++++++++++++++++++++ src/content/content-type.h | 58 ++++++++++++++++++ 3 files changed, 176 insertions(+), 3 deletions(-) create mode 100644 src/content/content-type.cpp create mode 100644 src/content/content-type.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 56243ca4f..e656f4111 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -28,13 +28,13 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES call/call-listener.h call/call-p.h call/call.h - chat/basic-chat-room.h chat/basic-chat-room-p.h + chat/basic-chat-room.h chat/chat-message.h chat/chat-room-p.h chat/chat-room.h - chat/client-group-chat-room.h chat/client-group-chat-room-p.h + chat/client-group-chat-room.h chat/cpim/cpim.h chat/cpim/header/cpim-core-headers.h chat/cpim/header/cpim-generic-header.h @@ -45,8 +45,8 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES chat/cpim/parser/cpim-parser.h chat/imdn.h chat/is-composing.h - chat/real-time-text-chat-room.h chat/real-time-text-chat-room-p.h + chat/real-time-text-chat-room.h conference/conference-listener.h conference/conference-p.h conference/conference.h @@ -63,6 +63,8 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES conference/session/call-session.h conference/session/media-session.h conference/session/port-config.h + content/content-type.h + content/content.h content/content.h core/core.h db/abstract/abstract-db-p.h @@ -117,6 +119,8 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES conference/remote-conference.cpp conference/session/call-session.cpp conference/session/media-session.cpp + content/content-type.cpp + content/content.cpp content/content.cpp core/core.cpp db/abstract/abstract-db.cpp diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp new file mode 100644 index 000000000..11fae0713 --- /dev/null +++ b/src/content/content-type.cpp @@ -0,0 +1,111 @@ +/* + * content-type.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "content-type.h" +#include "object/clonable-object-p.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +class ContentTypePrivate : public ClonableObjectPrivate { +public: + string type; + string subType; +}; + +// ----------------------------------------------------------------------------- + +ContentType::ContentType (const string &contentType) : ClonableObject(*new ContentTypePrivate) { + L_D(ContentType); + + size_t pos = contentType.find('/'); + if (pos == string::npos) + return; + + if (setType(contentType.substr(0, pos))) { + if (!setSubType(contentType.substr(pos + 1))) + d->type.clear(); + } +} + +ContentType::ContentType (const string &type, const string &subType) : ClonableObject(*new ContentTypePrivate) { + L_D(ContentType); + + if (setType(type)) { + if (!setSubType(subType)) + d->type.clear(); + } +} + +ContentType::ContentType (const ContentType &src) : ContentType(src.getType(), src.getSubType()) {} + +ContentType &ContentType::operator= (const ContentType &src) { + if (this != &src) { + setType(src.getType()); + setSubType(src.getSubType()); + } + + return *this; +} + +bool ContentType::operator== (const ContentType &contentType) { + return getType() == contentType.getType() && getSubType() == contentType.getSubType(); +} + +const string &ContentType::getType () const { + L_D(const ContentType); + return d->type; +} + +bool ContentType::setType (const std::string &type) { + L_D(ContentType); + if (type.find('/') == string::npos) { + d->type = type; + return true; + } + return false; +} + +const string &ContentType::getSubType () const { + L_D(const ContentType); + return d->subType; +} + +bool ContentType::setSubType (const std::string &subType) { + L_D(ContentType); + if (subType.find('/') == string::npos) { + d->subType = subType; + return true; + } + return false; +} + +bool ContentType::isValid () const { + L_D(const ContentType); + return !d->type.empty() && !d->subType.empty(); +} + +string ContentType::asString () const { + L_D(const ContentType); + return isValid() ? d->type + "/" + d->subType : ""; +} + +LINPHONE_END_NAMESPACE diff --git a/src/content/content-type.h b/src/content/content-type.h new file mode 100644 index 000000000..79daa8a17 --- /dev/null +++ b/src/content/content-type.h @@ -0,0 +1,58 @@ +/* + * content-type.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CONTENT_TYPE_H_ +#define _CONTENT_TYPE_H_ + +#include + +#include "object/clonable-object.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ContentTypePrivate; + +class LINPHONE_PUBLIC ContentType : public ClonableObject { +public: + ContentType (const std::string &contentType = ""); + ContentType (const std::string &type, const std::string &subType); + ContentType (const ContentType &src); + + ContentType &operator= (const ContentType &src); + + bool operator== (const ContentType &contentType); + + bool isValid () const; + + const std::string &getType () const; + bool setType (const std::string &type); + + const std::string &getSubType () const; + bool setSubType (const std::string &subType); + + std::string asString () const; + +private: + L_DECLARE_PRIVATE(ContentType); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CONTENT_TYPE_H_ From 8fce516b8f8026f5f0e8fb1391aadf1d51e9df72 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 12 Sep 2017 13:27:45 +0200 Subject: [PATCH 0035/2215] Added chat message modifiers skeletons --- src/CMakeLists.txt | 5 +++ src/chat/chat-message.cpp | 7 ++++ src/chat/chat-message.h | 1 + src/chat/modifier/chat-message-modifier.h | 38 +++++++++++++++++++ .../modifier/cpim-chat-message-modifier.cpp | 33 ++++++++++++++++ .../modifier/cpim-chat-message-modifier.h | 38 +++++++++++++++++++ .../multipart-chat-message-modifier.cpp | 33 ++++++++++++++++ .../multipart-chat-message-modifier.h | 38 +++++++++++++++++++ 8 files changed, 193 insertions(+) create mode 100644 src/chat/modifier/chat-message-modifier.h create mode 100644 src/chat/modifier/cpim-chat-message-modifier.cpp create mode 100644 src/chat/modifier/cpim-chat-message-modifier.h create mode 100644 src/chat/modifier/multipart-chat-message-modifier.cpp create mode 100644 src/chat/modifier/multipart-chat-message-modifier.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e656f4111..024d0cb6f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,6 +47,9 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES chat/is-composing.h chat/real-time-text-chat-room-p.h chat/real-time-text-chat-room.h + chat/modifier/chat-message-modifier.h + chat/modifier/multipart-chat-message-modifier.h + chat/modifier/cpim-chat-message-modifier.h conference/conference-listener.h conference/conference-p.h conference/conference.h @@ -111,6 +114,8 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES chat/imdn.cpp chat/is-composing.cpp chat/real-time-text-chat-room.cpp + chat/modifier/multipart-chat-message-modifier.cpp + chat/modifier/cpim-chat-message-modifier.cpp conference/conference.cpp conference/local-conference.cpp conference/params/call-session-params.cpp diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 1e6a987ad..f4cae49b0 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -39,10 +39,12 @@ private: string contentType; string text; bool isSecured = false; + bool isReadOnly = false; time_t time = 0; string id; string appData; list > contents; + shared_ptr private_content; unordered_map customHeaders; ChatMessage::State state = ChatMessage::Idle; shared_ptr eventsDb; @@ -127,6 +129,11 @@ bool ChatMessage::isSecured () const { return d->isSecured; } +bool ChatMessage::isReadOnly () const { + L_D(const ChatMessage); + return d->isReadOnly; +} + time_t ChatMessage::getTime () const { L_D(const ChatMessage); return d->time; diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index 830cf9991..e69883d40 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -77,6 +77,7 @@ public: bool containsReadableText () const; bool isSecured () const; + bool isReadOnly () const; time_t getTime () const; diff --git a/src/chat/modifier/chat-message-modifier.h b/src/chat/modifier/chat-message-modifier.h new file mode 100644 index 000000000..7fa2de4cb --- /dev/null +++ b/src/chat/modifier/chat-message-modifier.h @@ -0,0 +1,38 @@ +/* + * chat-message-modifier.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + + #ifndef _CHAT_MESSAGE_MODIFIER_H_ + #define _CHAT_MESSAGE_MODIFIER_H_ + + #include "chat/chat-message.h" + + // ============================================================================= + + LINPHONE_BEGIN_NAMESPACE + + class ChatMessageModifier { + public: + virtual void encode(std::shared_ptr msg) = 0; + virtual void decode(std::shared_ptr msg) = 0; + virtual ~ChatMessageModifier () = default; + }; + + LINPHONE_END_NAMESPACE + + #endif // ifndef _CHAT_MESSAGE_MODIFIER_H_ + \ No newline at end of file diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp new file mode 100644 index 000000000..c6843a242 --- /dev/null +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -0,0 +1,33 @@ +/* + * cpim-chat-message-modifier.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + + #include "cpim-chat-message-modifier.h" + + LINPHONE_BEGIN_NAMESPACE + + using namespace std; + + void CpimChatMessageModifier::encode(shared_ptr msg) { + //TODO + } + + void CpimChatMessageModifier::decode(shared_ptr msg) { + //TODO + } + +LINPHONE_END_NAMESPACE \ No newline at end of file diff --git a/src/chat/modifier/cpim-chat-message-modifier.h b/src/chat/modifier/cpim-chat-message-modifier.h new file mode 100644 index 000000000..ccdaddbdc --- /dev/null +++ b/src/chat/modifier/cpim-chat-message-modifier.h @@ -0,0 +1,38 @@ +/* + * cpim-chat-message-modifier.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + + #ifndef _CPIM_CHAT_MESSAGE_MODIFIER_H_ + #define _CPIM_CHAT_MESSAGE_MODIFIER_H_ + + #include "chat-message-modifier.h" + + // ============================================================================= + + LINPHONE_BEGIN_NAMESPACE + + class CpimChatMessageModifier : ChatMessageModifier { + public: + virtual void encode(std::shared_ptr msg) = 0; + virtual void decode(std::shared_ptr msg) = 0; + virtual ~CpimChatMessageModifier () = default; + }; + + LINPHONE_END_NAMESPACE + + #endif // ifndef _CPIM_CHAT_MESSAGE_MODIFIER_H_ + \ No newline at end of file diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp new file mode 100644 index 000000000..c805cfeb9 --- /dev/null +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -0,0 +1,33 @@ +/* + * multipart-chat-message-modifier.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + + #include "multipart-chat-message-modifier.h" + + LINPHONE_BEGIN_NAMESPACE + + using namespace std; + + void MultipartChatMessageModifier::encode(shared_ptr msg) { + //TODO + } + + void MultipartChatMessageModifier::decode(shared_ptr msg) { + //TODO + } + +LINPHONE_END_NAMESPACE \ No newline at end of file diff --git a/src/chat/modifier/multipart-chat-message-modifier.h b/src/chat/modifier/multipart-chat-message-modifier.h new file mode 100644 index 000000000..4577825b4 --- /dev/null +++ b/src/chat/modifier/multipart-chat-message-modifier.h @@ -0,0 +1,38 @@ +/* + * multipart-chat-message-modifier.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + + #ifndef _MULTIPART_CHAT_MESSAGE_MODIFIER_H_ + #define _MULTIPART_CHAT_MESSAGE_MODIFIER_H_ + + #include "chat-message-modifier.h" + + // ============================================================================= + + LINPHONE_BEGIN_NAMESPACE + + class MultipartChatMessageModifier : ChatMessageModifier { + public: + virtual void encode(std::shared_ptr msg) = 0; + virtual void decode(std::shared_ptr msg) = 0; + virtual ~MultipartChatMessageModifier () = default; + }; + + LINPHONE_END_NAMESPACE + + #endif // ifndef _MULTIPART_CHAT_MESSAGE_MODIFIER_H_ + \ No newline at end of file From 207a871090b901bd6e90aaaaa86ebf7b73d27035 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 12 Sep 2017 14:28:59 +0200 Subject: [PATCH 0036/2215] Changes for ChatMessage & ChatMessageModifiers --- src/CMakeLists.txt | 1 + src/chat/chat-message-p.h | 59 +++++++++++++++++ src/chat/chat-message.cpp | 64 +++++++++---------- src/chat/chat-message.h | 3 - src/chat/modifier/chat-message-modifier.h | 4 +- .../modifier/cpim-chat-message-modifier.cpp | 10 ++- .../modifier/cpim-chat-message-modifier.h | 5 +- .../multipart-chat-message-modifier.cpp | 9 ++- .../multipart-chat-message-modifier.h | 5 +- 9 files changed, 113 insertions(+), 47 deletions(-) create mode 100644 src/chat/chat-message-p.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 024d0cb6f..27c42b3e2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -30,6 +30,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES call/call.h chat/basic-chat-room-p.h chat/basic-chat-room.h + chat/chat-message-p.h chat/chat-message.h chat/chat-room-p.h chat/chat-room.h diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h new file mode 100644 index 000000000..ffd699d17 --- /dev/null +++ b/src/chat/chat-message-p.h @@ -0,0 +1,59 @@ +/* + * chat-message-p.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CHAT_MESSAGE_P_H_ +#define _CHAT_MESSAGE_P_H_ + +#include + +#include "chat-message.h" +#include "db/events-db.h" +#include "object/object-p.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ChatMessagePrivate : public ObjectPrivate { +private: + std::weak_ptr chatRoom; + ChatMessage::Direction direction = ChatMessage::Incoming; + // LinphoneAddress *from; + // LinphoneAddress *to; + std::shared_ptr errorInfo; + std::string contentType; + std::string text; + bool isSecured = false; + bool isReadOnly = false; + time_t time = 0; + std::string id; + std::string appData; + std::list > contents; + std::shared_ptr internalContent; + std::unordered_map customHeaders; + ChatMessage::State state = ChatMessage::Idle; + std::shared_ptr eventsDb; + + L_DECLARE_PUBLIC(ChatMessage); + friend class CpimChatMessageModifier; + friend class MultipartChatMessageModifier; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CHAT_MESSAGE_P_H_ diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index f4cae49b0..a5e816342 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -21,37 +21,23 @@ #include "db/events-db.h" #include "object/object-p.h" +#include "linphone/types.h" +#include "linphone/core.h" +#include "linphone/lpconfig.h" + +#include "chat-message-p.h" #include "chat-message.h" +#include "modifier/multipart-chat-message-modifier.h" +#include "modifier/cpim-chat-message-modifier.h" +#include "chat-room.h" + // ============================================================================= LINPHONE_BEGIN_NAMESPACE using namespace std; -class ChatMessagePrivate : public ObjectPrivate { -private: - weak_ptr chatRoom; - ChatMessage::Direction direction = ChatMessage::Incoming; - // LinphoneAddress *from; - // LinphoneAddress *to; - shared_ptr errorInfo; - string contentType; - string text; - bool isSecured = false; - bool isReadOnly = false; - time_t time = 0; - string id; - string appData; - list > contents; - shared_ptr private_content; - unordered_map customHeaders; - ChatMessage::State state = ChatMessage::Idle; - shared_ptr eventsDb; - - L_DECLARE_PUBLIC(ChatMessage); -}; - // ----------------------------------------------------------------------------- ChatMessage::ChatMessage (ChatMessagePrivate &p) : Object(p) {} @@ -105,17 +91,21 @@ string ChatMessage::getContentType () const { return d->contentType; } -string ChatMessage::getText () const { - L_D(const ChatMessage); - return d->text; -} - -void ChatMessage::setText (const string &text) { - L_D(ChatMessage); - d->text = text; -} - void ChatMessage::send () const { + L_D(const ChatMessage); + + if (d->contents.size() > 1) { + MultipartChatMessageModifier mcmm; + mcmm.encode(d); + } + + LinphoneCore *lc = getChatRoom()->getCore(); + LpConfig *lpc = linphone_core_get_config(lc); + if (lp_config_get_int(lpc, "sip", "use_cpim", 0) == 1) { + CpimChatMessageModifier ccmm; + ccmm.encode(d); + } + // TODO. } @@ -164,11 +154,15 @@ list > ChatMessage::getContents () const { void ChatMessage::addContent (const shared_ptr &content) { L_D(ChatMessage); + if (d->isReadOnly) return; + d->contents.push_back(content); } void ChatMessage::removeContent (const shared_ptr &content) { L_D(ChatMessage); + if (d->isReadOnly) return; + d->contents.remove(const_pointer_cast(content)); } @@ -184,11 +178,15 @@ string ChatMessage::getCustomHeaderValue (const string &headerName) const { void ChatMessage::addCustomHeader (const string &headerName, const string &headerValue) { L_D(ChatMessage); + if (d->isReadOnly) return; + d->customHeaders[headerName] = headerValue; } void ChatMessage::removeCustomHeader (const string &headerName) { L_D(ChatMessage); + if (d->isReadOnly) return; + d->customHeaders.erase(headerName); } diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index e69883d40..727a6fb93 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -69,9 +69,6 @@ public: std::string getContentType () const; - std::string getText () const; - void setText (const std::string &text); - void send () const; bool containsReadableText () const; diff --git a/src/chat/modifier/chat-message-modifier.h b/src/chat/modifier/chat-message-modifier.h index 7fa2de4cb..64434abe5 100644 --- a/src/chat/modifier/chat-message-modifier.h +++ b/src/chat/modifier/chat-message-modifier.h @@ -27,8 +27,8 @@ class ChatMessageModifier { public: - virtual void encode(std::shared_ptr msg) = 0; - virtual void decode(std::shared_ptr msg) = 0; + virtual void encode(const LinphonePrivate::ChatMessagePrivate* msg) = 0; + virtual void decode(const LinphonePrivate::ChatMessagePrivate* msg) = 0; virtual ~ChatMessageModifier () = default; }; diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index c6843a242..b29d4cd27 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -16,17 +16,23 @@ * along with this program. If not, see . */ + #include "chat/chat-message-p.h" #include "cpim-chat-message-modifier.h" LINPHONE_BEGIN_NAMESPACE using namespace std; - void CpimChatMessageModifier::encode(shared_ptr msg) { + void CpimChatMessageModifier::encode(const LinphonePrivate::ChatMessagePrivate* msg) { //TODO + if (msg->internalContent) { + // Another ChatMessageModifier was called before this one, we apply our changes on the private content + } else { + // We're the first ChatMessageModifier to be called, we'll create the private content from the public one + } } - void CpimChatMessageModifier::decode(shared_ptr msg) { + void CpimChatMessageModifier::decode(const LinphonePrivate::ChatMessagePrivate* msg) { //TODO } diff --git a/src/chat/modifier/cpim-chat-message-modifier.h b/src/chat/modifier/cpim-chat-message-modifier.h index ccdaddbdc..d5ee530c6 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.h +++ b/src/chat/modifier/cpim-chat-message-modifier.h @@ -27,8 +27,9 @@ class CpimChatMessageModifier : ChatMessageModifier { public: - virtual void encode(std::shared_ptr msg) = 0; - virtual void decode(std::shared_ptr msg) = 0; + CpimChatMessageModifier() {}; + virtual void encode(const LinphonePrivate::ChatMessagePrivate* msg); + virtual void decode(const LinphonePrivate::ChatMessagePrivate* msg); virtual ~CpimChatMessageModifier () = default; }; diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index c805cfeb9..f980a9bfd 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -16,17 +16,20 @@ * along with this program. If not, see . */ + #include "chat/chat-message-p.h" #include "multipart-chat-message-modifier.h" LINPHONE_BEGIN_NAMESPACE using namespace std; - void MultipartChatMessageModifier::encode(shared_ptr msg) { - //TODO + void MultipartChatMessageModifier::encode(const LinphonePrivate::ChatMessagePrivate* msg) { + if (msg->contents.size() > 1) { + //TODO + } } - void MultipartChatMessageModifier::decode(shared_ptr msg) { + void MultipartChatMessageModifier::decode(const LinphonePrivate::ChatMessagePrivate* msg) { //TODO } diff --git a/src/chat/modifier/multipart-chat-message-modifier.h b/src/chat/modifier/multipart-chat-message-modifier.h index 4577825b4..9f9b23069 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.h +++ b/src/chat/modifier/multipart-chat-message-modifier.h @@ -27,8 +27,9 @@ class MultipartChatMessageModifier : ChatMessageModifier { public: - virtual void encode(std::shared_ptr msg) = 0; - virtual void decode(std::shared_ptr msg) = 0; + MultipartChatMessageModifier() {}; + virtual void encode(const LinphonePrivate::ChatMessagePrivate* msg); + virtual void decode(const LinphonePrivate::ChatMessagePrivate* msg); virtual ~MultipartChatMessageModifier () = default; }; From 44152b9f4830ec8a6817456065fd4c80c17e3d4e Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 12 Sep 2017 15:07:50 +0200 Subject: [PATCH 0037/2215] use real pointer in c wrapped clonable object --- coreapi/chat.c | 4 +- src/address/address.cpp | 10 +-- src/address/address.h | 4 +- src/c-wrapper/api/c-address.cpp | 12 +-- src/c-wrapper/c-tools.h | 94 +++++++++++++++++++++--- src/chat/chat-room.cpp | 1 - src/conference/session/media-session.cpp | 2 +- tester/setup_tester.c | 1 - 8 files changed, 102 insertions(+), 26 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index b51c7284a..40d80657a 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -190,9 +190,9 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneChatRoom, belle_sip_object_t, LinphoneChatRoom *_linphone_core_create_chat_room_base(LinphoneCore *lc, const LinphoneAddress *addr) { LinphoneChatRoom *cr = belle_sip_object_new(LinphoneChatRoom); if (linphone_core_realtime_text_enabled(lc)) - cr->cr = new LinphonePrivate::RealTimeTextChatRoom(lc, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address).get()); + cr->cr = new LinphonePrivate::RealTimeTextChatRoom(lc, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address)); else - cr->cr = new LinphonePrivate::BasicChatRoom(lc, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address).get()); + cr->cr = new LinphonePrivate::BasicChatRoom(lc, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address)); L_GET_PRIVATE(cr->cr)->setCBackPointer(cr); return cr; } diff --git a/src/address/address.cpp b/src/address/address.cpp index 7bac71911..5bd7226d8 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -66,15 +66,15 @@ Address &Address::operator= (const Address &src) { return *this; } -Address::operator bool () const { - L_D(const Address); - return static_cast(d->internalAddress); -} - bool Address::operator== (const Address &address) const { return equal(address); } +bool Address::isValid () const { + L_D(const Address); + return static_cast(d->internalAddress); +} + const string &Address::getScheme () const { L_D(const Address); d->cache.scheme = L_C_TO_STRING(sal_address_get_scheme(d->internalAddress)); diff --git a/src/address/address.h b/src/address/address.h index 84048a681..e35688f0c 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -38,10 +38,10 @@ public: Address &operator= (const Address &src); - operator bool () const; - bool operator== (const Address &address) const; + bool isValid () const; + const std::string &getScheme () const; const std::string &getDisplayName () const; diff --git a/src/c-wrapper/api/c-address.cpp b/src/c-wrapper/api/c-address.cpp index 126c416d8..bd9ec8b29 100644 --- a/src/c-wrapper/api/c-address.cpp +++ b/src/c-wrapper/api/c-address.cpp @@ -26,12 +26,14 @@ using namespace std; -L_DECLARE_C_STRUCT_IMPL(Address, address); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(Address, address); LinphoneAddress *linphone_address_new (const char *address) { - shared_ptr cppPtr = make_shared(L_C_TO_STRING(address)); - if (!*cppPtr.get()) + LINPHONE_NAMESPACE::Address *cppPtr = new LINPHONE_NAMESPACE::Address(L_C_TO_STRING(address)); + if (!cppPtr->isValid()) { + delete cppPtr; return nullptr; + } LinphoneAddress *object = _linphone_address_init(); object->cppPtr = cppPtr; @@ -136,11 +138,11 @@ char *linphone_address_as_string_uri_only (const LinphoneAddress *address) { } bool_t linphone_address_weak_equal (const LinphoneAddress *address1, const LinphoneAddress *address2) { - return address1->cppPtr->weakEqual(*address2->cppPtr.get()); + return address1->cppPtr->weakEqual(*address2->cppPtr); } bool_t linphone_address_equal (const LinphoneAddress *address1, const LinphoneAddress *address2) { - return *address1->cppPtr.get() == *address2->cppPtr.get(); + return *address1->cppPtr == *address2->cppPtr; } const char *linphone_address_get_header (const LinphoneAddress *address, const char *header_name) { diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index e97368bcf..4878f60fb 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -38,24 +38,62 @@ private: std::shared_ptr cppPtr; }; + template + struct WrappedClonableObject { + belle_sip_object_t base; + T *cppPtr; + }; + public: template static inline decltype (std::declval().getPrivate()) getPrivate (T *object) { if (!object) - return nullptr; + return nullptr; return object->getPrivate(); } - template - static inline std::shared_ptr getCppPtrFromC (void *object) { + // --------------------------------------------------------------------------- + // Get c/cpp ptr helpers. + // --------------------------------------------------------------------------- + + template< + typename CppType, + typename CType, + typename std::enable_if::value>::type = 0 + > + static inline std::shared_ptr getCppPtrFromC (CType *object) { L_ASSERT(object); - return static_cast *>(object)->cppPtr; + return reinterpret_cast *>(object)->cppPtr; } - template - static inline std::shared_ptr getCppPtrFromC (const void *object) { + template< + typename CppType, + typename CType, + typename std::enable_if::value, CppType>::type = 0 + > + static inline std::shared_ptr getCppPtrFromC (const CType *object) { L_ASSERT(object); - return static_cast *>(object)->cppPtr; + return reinterpret_cast *>(object)->cppPtr; + } + + template< + typename CppType, + typename CType, + typename = typename std::enable_if::value, CppType>::type + > + static inline CppType *getCppPtrFromC (CType *object) { + L_ASSERT(object); + return reinterpret_cast *>(object)->cppPtr; + } + + template< + typename CppType, + typename CType, + typename = typename std::enable_if::value, CppType>::type + > + static inline const CppType *getCppPtrFromC (const CType *object) { + L_ASSERT(object); + return reinterpret_cast *>(object)->cppPtr; } template @@ -64,6 +102,18 @@ public: static_cast *>(object)->cppPtr = cppPtr; } + template + static T *getCppPtr (const std::shared_ptr &cppPtr) { + return cppPtr.get(); + } + + template + static T *getCppPtr (T *cppPtr) { + return cppPtr; + } + + // --------------------------------------------------------------------------- + template static inline bctbx_list_t * getCListFromCppList (std::list cppList) { bctbx_list_t *result = nullptr; @@ -116,6 +166,30 @@ LINPHONE_END_NAMESPACE FALSE \ ); +#define L_DECLARE_C_CLONABLE_STRUCT_IMPL(STRUCT, C_NAME) \ + struct _Linphone ## STRUCT { \ + belle_sip_object_t base; \ + LINPHONE_NAMESPACE::STRUCT *cppPtr; \ + }; \ + BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## STRUCT); \ + static Linphone ## STRUCT *_linphone_ ## C_NAME ## _init() { \ + return belle_sip_object_new(Linphone ## STRUCT); \ + } \ + static void _linphone_ ## C_NAME ## _uninit(Linphone ## STRUCT * object) { \ + delete object->cppPtr; \ + } \ + static void _linphone_ ## C_NAME ## _clone(Linphone ## STRUCT * dest, const Linphone ## STRUCT * src) { \ + L_ASSERT(src->cppPtr); \ + dest->cppPtr = new LINPHONE_NAMESPACE::STRUCT(*src->cppPtr); \ + } \ + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## STRUCT); \ + BELLE_SIP_INSTANCIATE_VPTR(Linphone ## STRUCT, belle_sip_object_t, \ + _linphone_ ## C_NAME ## _uninit, \ + _linphone_ ## C_NAME ## _clone, \ + NULL, \ + FALSE \ + ); + #define L_DECLARE_C_STRUCT_NEW_DEFAULT(STRUCT, C_NAME) \ Linphone ## STRUCT * linphone_ ## C_NAME ## _new() { \ Linphone ## STRUCT * object = _linphone_ ## C_NAME ## _init(); \ @@ -127,7 +201,7 @@ LINPHONE_END_NAMESPACE #define L_C_TO_STRING(STR) ((STR) == NULL ? std::string() : (STR)) #define L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, TYPE) \ - LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC(OBJECT) + LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC(OBJECT) #define L_SET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_PTR) \ LINPHONE_NAMESPACE::Wrapper::setCppPtrFromC(OBJECT, CPP_PTR) @@ -136,7 +210,9 @@ LINPHONE_END_NAMESPACE LINPHONE_NAMESPACE::Wrapper::getPrivate(OBJECT) #define L_GET_PRIVATE_FROM_C_STRUCT(OBJECT, TYPE) \ - L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, TYPE).get()) + L_GET_PRIVATE(LINPHONE_NAMESPACE::Wrapper::getCppPtr( \ + L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, TYPE) \ + )) #define L_GET_C_LIST_FROM_CPP_LIST(LIST, TYPE) \ LINPHONE_NAMESPACE::Wrapper::getCListFromCppList(LIST) diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 8e1158644..b9000397d 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -909,4 +909,3 @@ const Address& ChatRoom::getPeerAddress () const { } LINPHONE_END_NAMESPACE - diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 615f1bdf4..72f39635b 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -1224,7 +1224,7 @@ void MediaSessionPrivate::makeLocalMediaDescription () { md->nb_streams = (biggestDesc ? biggestDesc->nb_streams : 1); /* Re-check local ip address each time we make a new offer, because it may change in case of network reconnection */ - getLocalIp(*L_GET_CPP_PTR_FROM_C_STRUCT((direction == LinphoneCallOutgoing) ? log->to : log->from, Address).get()); + getLocalIp(*L_GET_CPP_PTR_FROM_C_STRUCT((direction == LinphoneCallOutgoing) ? log->to : log->from, Address)); strncpy(md->addr, mediaLocalIp.c_str(), sizeof(md->addr)); LinphoneAddress *addr = nullptr; if (destProxy) { diff --git a/tester/setup_tester.c b/tester/setup_tester.c index ba4956e5f..5f4e24890 100644 --- a/tester/setup_tester.c +++ b/tester/setup_tester.c @@ -42,7 +42,6 @@ static void core_init_test(void) { static void linphone_address_test(void) { linphone_address_unref(create_linphone_address(NULL)); BC_ASSERT_PTR_NULL(linphone_address_new("sip:@sip.linphone.org")); - } static void core_sip_transport_test(void) { From 4d85643a9c3803099f7000171cbfc1edeea174b6 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 12 Sep 2017 17:46:04 +0200 Subject: [PATCH 0038/2215] feat(core): add better content class --- src/CMakeLists.txt | 2 - src/content/content.cpp | 191 +++++++++++++--------------------------- src/content/content.h | 46 ++++------ 3 files changed, 76 insertions(+), 163 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 27c42b3e2..fe9c45996 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -69,7 +69,6 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES conference/session/port-config.h content/content-type.h content/content.h - content/content.h core/core.h db/abstract/abstract-db-p.h db/abstract/abstract-db.h @@ -127,7 +126,6 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES conference/session/media-session.cpp content/content-type.cpp content/content.cpp - content/content.cpp core/core.cpp db/abstract/abstract-db.cpp db/events-db.cpp diff --git a/src/content/content.cpp b/src/content/content.cpp index b3fd66d4e..021032f09 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -16,11 +16,8 @@ * along with this program. If not, see . */ -// From coreapi. -#include "private.h" - -#include "c-wrapper/c-tools.h" -#include "object/object-p.h" +#include "content-type.h" +#include "object/clonable-object-p.h" #include "content.h" @@ -30,148 +27,82 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -class ContentPrivate : public ObjectPrivate { +class ContentPrivate : public ClonableObjectPrivate { public: - struct Cache { - string type; - string subType; - string customHeaderValue; - string encoding; - }; - - SalBodyHandler *bodyHandler = nullptr; - void *cryptoContext = nullptr; - string name; - string key; - - mutable Cache cache; + vector body; + ContentType contentType; }; // ----------------------------------------------------------------------------- -Content::Content () : Object(*new ContentPrivate) {} +Content::Content () : ClonableObject(*new ContentPrivate) {} -const string &Content::getType () const { - L_D(const Content); - d->cache.type = sal_body_handler_get_subtype(d->bodyHandler); - return d->cache.type; -} - -void Content::setType (const string &type) { +Content::Content (const Content &src) : ClonableObject(*new ContentPrivate) { L_D(Content); - sal_body_handler_set_type(d->bodyHandler, L_STRING_TO_C(type)); + d->body = src.getBody(); + d->contentType = src.getContentType(); } -const string &Content::getSubType () const { - L_D(const Content); - d->cache.subType = sal_body_handler_get_subtype(d->bodyHandler); - return d->cache.subType; -} - -void Content::setSubType (const string &subType) { +Content::Content (Content &&src) { L_D(Content); - sal_body_handler_set_subtype(d->bodyHandler, L_STRING_TO_C(subType)); + d->body = move(src.getPrivate()->body); + d->contentType = move(src.getPrivate()->contentType); } -const void *Content::getBuffer () const { - L_D(const Content); - return sal_body_handler_get_data(d->bodyHandler); -} - -void Content::setBuffer (const void *buffer, size_t size) { +Content &Content::operator= (const Content &src) { L_D(Content); - sal_body_handler_set_size(d->bodyHandler, size); - void *data = belle_sip_malloc(size); - sal_body_handler_set_data(d->bodyHandler, memcpy(data, buffer, size)); + if (this != &src) { + d->body = src.getBody(); + d->contentType = src.getContentType(); + } + + return *this; +} + +Content &Content::operator= (Content &&src) { + L_D(Content); + if (this != &src) { + d->body = move(src.getPrivate()->body); + d->contentType = move(src.getPrivate()->contentType); + } + + return *this; +} + +const ContentType &Content::getContentType () const { + L_D(const Content); + return d->contentType; +} + +void Content::setContentType (const ContentType &contentType) { + L_D(Content); + d->contentType = contentType; +} + +const std::vector &Content::getBody () const { + L_D(const Content); + return d->body; +} + +void Content::setBody (const std::vector &body) { + L_D(Content); + d->body = body; +} + +void Content::setBody (const std::string &body) { + L_D(Content); + d->body = vector(body.cbegin(), body.cend()); +} + +void Content::setBody (const void *buffer, size_t size) { + L_D(Content); + const char *start = static_cast(buffer); + d->body = vector(start, start + size); } size_t Content::getSize () const { L_D(const Content); - return sal_body_handler_get_size(d->bodyHandler); -} - -void Content::setSize (size_t size) { - L_D(Content); - sal_body_handler_set_data(d->bodyHandler, nullptr); - sal_body_handler_set_size(d->bodyHandler, size); -} - -const string &Content::getEncoding () const { - L_D(const Content); - d->cache.encoding = sal_body_handler_get_encoding(d->bodyHandler); - return d->cache.encoding; -} - -void Content::setEncoding (const string &encoding) { - L_D(Content); - sal_body_handler_set_encoding(d->bodyHandler, L_STRING_TO_C(encoding)); -} - -const string &Content::getName () const { - L_D(const Content); - return d->name; -} - -void Content::setName (const string &name) { - L_D(Content); - d->name = name; -} - -bool Content::isMultipart () const { - L_D(const Content); - return sal_body_handler_is_multipart(d->bodyHandler); -} - -shared_ptr Content::getPart (int index) const { - L_D(const Content); - - if (!isMultipart()) - return nullptr; - - SalBodyHandler *bodyHandler = sal_body_handler_get_part(d->bodyHandler, index); - if (!bodyHandler) - return nullptr; - - Content *content = new Content(); - sal_body_handler_ref(bodyHandler); - content->getPrivate()->bodyHandler = bodyHandler; - return shared_ptr(content); -} - -shared_ptr Content::findPartByHeader (const string &headerName, const string &headerValue) const { - L_D(const Content); - - if (!isMultipart()) - return nullptr; - - SalBodyHandler *bodyHandler = sal_body_handler_find_part_by_header( - d->bodyHandler, - L_STRING_TO_C(headerName), - L_STRING_TO_C(headerValue) - ); - if (!bodyHandler) - return nullptr; - - Content *content = new Content(); - sal_body_handler_ref(bodyHandler); - content->getPrivate()->bodyHandler = bodyHandler; - return shared_ptr(content); -} - -const string &Content::getCustomHeaderValue (const string &headerName) const { - L_D(const Content); - d->cache.customHeaderValue = sal_body_handler_get_header(d->bodyHandler, L_STRING_TO_C(headerName)); - return d->cache.customHeaderValue; -} - -const string &Content::getKey () const { - L_D(const Content); - return d->key; -} - -void Content::setKey (const string &key) { - L_D(Content); - d->key = key; + return d->body.size(); } LINPHONE_END_NAMESPACE diff --git a/src/content/content.h b/src/content/content.h index 89f4b16e8..1a60e7fec 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -19,54 +19,38 @@ #ifndef _CONTENT_H_ #define _CONTENT_H_ -#include #include +#include -#include "object/object.h" +#include "object/clonable-object.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE class ContentPrivate; +class ContentType; -class Content : public Object { - friend class Core; - +class LINPHONE_PUBLIC Content : public ClonableObject { public: - const std::string &getType () const; - void setType (const std::string &type); + Content (); + Content (const Content &src); + Content (Content &&src); - const std::string &getSubType () const; - void setSubType (const std::string &subType); + Content &operator= (const Content &src); + Content &operator= (Content &&src); - const void *getBuffer () const; - void setBuffer (const void *buffer, size_t size); + const ContentType &getContentType () const; + void setContentType (const ContentType &contentType); + const std::vector &getBody () const; + void setBody (const std::vector &body); + void setBody (const std::string &body); + void setBody (const void *buffer, size_t size); size_t getSize () const; - void setSize (size_t size); - - const std::string &getEncoding () const; - void setEncoding (const std::string &encoding); - - const std::string &getName () const; - void setName (const std::string &name); - - bool isMultipart () const; - - std::shared_ptr getPart (int index) const; - std::shared_ptr findPartByHeader (const std::string &headerName, const std::string &headerValue) const; - - const std::string &getCustomHeaderValue (const std::string &headerName) const; - - const std::string &getKey () const; - void setKey (const std::string &key); private: - Content (); - L_DECLARE_PRIVATE(Content); - L_DISABLE_COPY(Content); }; LINPHONE_END_NAMESPACE From 093ae07e7929c5f8e2c44225d3348e1a5044bf62 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 12 Sep 2017 17:48:30 +0200 Subject: [PATCH 0039/2215] fix build --- src/content/content.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/content.cpp b/src/content/content.cpp index 021032f09..9e89f7afa 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -43,7 +43,7 @@ Content::Content (const Content &src) : ClonableObject(*new ContentPrivate) { d->contentType = src.getContentType(); } -Content::Content (Content &&src) { +Content::Content (Content &&src) : ClonableObject(*new ContentPrivate) { L_D(Content); d->body = move(src.getPrivate()->body); d->contentType = move(src.getPrivate()->contentType); From b1a37f6bd0e7bffd5b5304537ffb42dd57bd4d85 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 13 Sep 2017 09:12:42 +0200 Subject: [PATCH 0040/2215] feat(utils): remove content-type files --- coreapi/chat.c | 4 ++-- src/CMakeLists.txt | 2 -- src/chat/chat-room.cpp | 6 ++--- src/content/content-type.cpp | 32 +++++++++++++++++++++++++++ src/content/content-type.h | 10 +++++++++ src/utils/content-type.cpp | 43 ------------------------------------ src/utils/content-type.h | 39 -------------------------------- 7 files changed, 47 insertions(+), 89 deletions(-) delete mode 100644 src/utils/content-type.cpp delete mode 100644 src/utils/content-type.h diff --git a/coreapi/chat.c b/coreapi/chat.c index 40d80657a..b7e26f8e8 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -37,9 +37,9 @@ #include "c-wrapper/c-tools.h" #include "chat/basic-chat-room.h" -#include "chat/real-time-text-chat-room.h" #include "chat/real-time-text-chat-room-p.h" -#include "utils/content-type.h" +#include "chat/real-time-text-chat-room.h" +#include "content/content-type.h" struct _LinphoneChatRoom{ belle_sip_object_t base; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fe9c45996..0db3bbd4f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -92,7 +92,6 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES object/object-p.h object/object.h object/singleton.h - utils/content-type.h utils/payload-type-handler.h ) @@ -141,7 +140,6 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES nat/stun-client.cpp object/clonable-object.cpp object/object.cpp - utils/content-type.cpp utils/general.cpp utils/payload-type-handler.cpp utils/utils.cpp diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index b9000397d..cb6b3ff24 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -20,11 +20,11 @@ #include "linphone/utils/utils.h" -#include "chat-room-p.h" -#include "imdn.h" #include "c-wrapper/c-tools.h" +#include "chat-room-p.h" +#include "content/content-type.h" +#include "imdn.h" #include "logger/logger.h" -#include "utils/content-type.h" #include "chat-room.h" diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index 11fae0713..7b55d4322 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -108,4 +108,36 @@ string ContentType::asString () const { return isValid() ? d->type + "/" + d->subType : ""; } +bool ContentType::isFileTransfer () const { + return isFileTransfer(asString()); +} + +bool ContentType::isImIsComposing () const { + return isFileTransfer(asString()); +} + +bool ContentType::isImdn () const { + return isImdn(asString()); +} + +bool ContentType::isText () const { + return isText(asString()); +} + +bool ContentType::isFileTransfer (const string &contentType) { + return contentType == "application/vnd.gsma.rcs-ft-http+xml"; +} + +bool ContentType::isImIsComposing (const string &contentType) { + return contentType == "application/im-iscomposing+xml"; +} + +bool ContentType::isImdn (const string &contentType) { + return contentType == "message/imdn+xml"; +} + +bool ContentType::isText (const string &contentType) { + return contentType == "text/plain"; +} + LINPHONE_END_NAMESPACE diff --git a/src/content/content-type.h b/src/content/content-type.h index 79daa8a17..15095207c 100644 --- a/src/content/content-type.h +++ b/src/content/content-type.h @@ -49,6 +49,16 @@ public: std::string asString () const; + bool isFileTransfer () const; + bool isImIsComposing () const; + bool isImdn () const; + bool isText () const; + + static bool isFileTransfer (const std::string &contentType); + static bool isImIsComposing (const std::string &contentType); + static bool isImdn (const std::string &contentType); + static bool isText (const std::string &contentType); + private: L_DECLARE_PRIVATE(ContentType); }; diff --git a/src/utils/content-type.cpp b/src/utils/content-type.cpp deleted file mode 100644 index ee1aac657..000000000 --- a/src/utils/content-type.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * content-type.cpp - * Copyright (C) 2017 Belledonne Communications SARL - * - * 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, see . - */ - -#include "content-type.h" - -// ============================================================================= - -using namespace std; - -LINPHONE_BEGIN_NAMESPACE - -bool ContentType::isFileTransfer (const string &contentType) { - return "application/vnd.gsma.rcs-ft-http+xml" == contentType; -} - -bool ContentType::isImIsComposing (const string &contentType) { - return "application/im-iscomposing+xml" == contentType; -} - -bool ContentType::isImdn (const string &contentType) { - return "message/imdn+xml" == contentType; -} - -bool ContentType::isText (const string &contentType) { - return "text/plain" == contentType; -} - -LINPHONE_END_NAMESPACE diff --git a/src/utils/content-type.h b/src/utils/content-type.h deleted file mode 100644 index e8e736bc5..000000000 --- a/src/utils/content-type.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * content-type.h - * Copyright (C) 2017 Belledonne Communications SARL - * - * 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, see . - */ - -#ifndef _CONTENT_TYPE_H_ -#define _CONTENT_TYPE_H_ - -#include - -#include "linphone/utils/general.h" - -// ============================================================================= - -LINPHONE_BEGIN_NAMESPACE - -namespace ContentType { - bool isFileTransfer (const std::string &contentType); - bool isImIsComposing (const std::string &contentType); - bool isImdn (const std::string &contentType); - bool isText (const std::string &contentType); -} - -LINPHONE_END_NAMESPACE - -#endif // ifndef _CONTENT_TYPE_H_ From 615174f4458d572614143387747d2e771ce33322 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 13 Sep 2017 10:40:41 +0200 Subject: [PATCH 0041/2215] Compil fix --- include/linphone/utils/general.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index fca6c903f..17978a996 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -65,10 +65,10 @@ LINPHONE_BEGIN_NAMESPACE void l_assert (const char *condition, const char *file, int line); -#ifdef DEBUG +#ifndef DEBUG #define L_ASSERT(CONDITION) static_cast(false && (CONDITION)) #else - #define L_ASSERT(CONDITION) ((CONDITION) ? static_cast(0) : l_assert(#CONDITION, __FILE__, __LINE__)) + #define L_ASSERT(CONDITION) ((CONDITION) ? static_cast(0) : LINPHONE_NAMESPACE::l_assert(#CONDITION, __FILE__, __LINE__)) #endif // Allows access to private internal data. From cd10ea5d6697e1e9f60d6b0a4b0413e551434db1 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 13 Sep 2017 12:05:47 +0200 Subject: [PATCH 0042/2215] feat(Object): provide a way to deal with user data (properties/variant) --- src/CMakeLists.txt | 12 +- src/c-wrapper/c-tools.h | 1 - src/call/call-listener.h | 2 - src/chat/cpim/header/cpim-header.h | 2 - src/chat/imdn.h | 2 - src/chat/is-composing.h | 2 - src/conference/conference-p.h | 2 - src/conference/params/call-session-params.h | 2 - src/conference/session/call-session-p.h | 1 - src/conference/session/media-session-p.h | 1 - src/content/content.cpp | 7 +- src/db/abstract/abstract-db.h | 2 - src/db/provider/db-session-provider.h | 2 - src/db/provider/db-session.h | 2 - src/object/object-p.h | 6 + src/object/object.cpp | 18 ++ src/object/object.h | 8 + src/variant/variant.cpp | 174 ++++++++++++++++++++ src/variant/variant.h | 133 +++++++++++++++ 19 files changed, 348 insertions(+), 31 deletions(-) create mode 100644 src/variant/variant.cpp create mode 100644 src/variant/variant.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0db3bbd4f..c3958f0e9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -46,11 +46,11 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES chat/cpim/parser/cpim-parser.h chat/imdn.h chat/is-composing.h + chat/modifier/chat-message-modifier.h + chat/modifier/cpim-chat-message-modifier.h + chat/modifier/multipart-chat-message-modifier.h chat/real-time-text-chat-room-p.h chat/real-time-text-chat-room.h - chat/modifier/chat-message-modifier.h - chat/modifier/multipart-chat-message-modifier.h - chat/modifier/cpim-chat-message-modifier.h conference/conference-listener.h conference/conference-p.h conference/conference.h @@ -93,6 +93,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES object/object.h object/singleton.h utils/payload-type-handler.h + variant/variant.h ) set(LINPHONE_CXX_OBJECTS_SOURCE_FILES @@ -112,9 +113,9 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES chat/cpim/parser/cpim-parser.cpp chat/imdn.cpp chat/is-composing.cpp - chat/real-time-text-chat-room.cpp - chat/modifier/multipart-chat-message-modifier.cpp chat/modifier/cpim-chat-message-modifier.cpp + chat/modifier/multipart-chat-message-modifier.cpp + chat/real-time-text-chat-room.cpp conference/conference.cpp conference/local-conference.cpp conference/params/call-session-params.cpp @@ -143,6 +144,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES utils/general.cpp utils/payload-type-handler.cpp utils/utils.cpp + variant/variant.cpp ) set(LINPHONE_CXX_OBJECTS_DEFINITIONS "-DLIBLINPHONE_EXPORTS") diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index 4878f60fb..5ea666d75 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -21,7 +21,6 @@ #include #include -#include // From coreapi. #include "private.h" diff --git a/src/call/call-listener.h b/src/call/call-listener.h index 90027833d..20e436b45 100644 --- a/src/call/call-listener.h +++ b/src/call/call-listener.h @@ -19,8 +19,6 @@ #ifndef _CALL_LISTENER_H_ #define _CALL_LISTENER_H_ -#include - #include "linphone/types.h" // ============================================================================= diff --git a/src/chat/cpim/header/cpim-header.h b/src/chat/cpim/header/cpim-header.h index 8fadea125..3a0d9d91c 100644 --- a/src/chat/cpim/header/cpim-header.h +++ b/src/chat/cpim/header/cpim-header.h @@ -19,8 +19,6 @@ #ifndef _CPIM_HEADER_H_ #define _CPIM_HEADER_H_ -#include - #include "object/object.h" // ============================================================================= diff --git a/src/chat/imdn.h b/src/chat/imdn.h index 07584fa3f..c4bb6d1a5 100644 --- a/src/chat/imdn.h +++ b/src/chat/imdn.h @@ -19,8 +19,6 @@ #ifndef _IMDN_H_ #define _IMDN_H_ -#include - #include "linphone/utils/general.h" #include "chat-room.h" diff --git a/src/chat/is-composing.h b/src/chat/is-composing.h index e219ec4f9..f9cc44d7c 100644 --- a/src/chat/is-composing.h +++ b/src/chat/is-composing.h @@ -19,8 +19,6 @@ #ifndef _IS_COMPOSING_H_ #define _IS_COMPOSING_H_ -#include - #include "linphone/utils/general.h" #include "is-composing-listener.h" diff --git a/src/conference/conference-p.h b/src/conference/conference-p.h index e2341de01..70dc0658c 100644 --- a/src/conference/conference-p.h +++ b/src/conference/conference-p.h @@ -27,8 +27,6 @@ #include "conference/participant.h" #include "conference/session/call-session-listener.h" -#include - // ============================================================================= LINPHONE_BEGIN_NAMESPACE diff --git a/src/conference/params/call-session-params.h b/src/conference/params/call-session-params.h index a3afc3e31..adb6ed1eb 100644 --- a/src/conference/params/call-session-params.h +++ b/src/conference/params/call-session-params.h @@ -19,8 +19,6 @@ #ifndef _CALL_SESSION_PARAMS_H_ #define _CALL_SESSION_PARAMS_H_ -#include - #include "object/clonable-object.h" #include "linphone/types.h" diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index 47390fda7..bca4ed0a3 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -20,7 +20,6 @@ #define _CALL_SESSION_P_H_ #include -#include #include "object/object-p.h" diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index 3d7d20bd2..a70865307 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -19,7 +19,6 @@ #ifndef _MEDIA_SESSION_P_H_ #define _MEDIA_SESSION_P_H_ -#include #include #include "call-session-p.h" diff --git a/src/content/content.cpp b/src/content/content.cpp index 9e89f7afa..a77f01eab 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -61,11 +61,8 @@ Content &Content::operator= (const Content &src) { Content &Content::operator= (Content &&src) { L_D(Content); - if (this != &src) { - d->body = move(src.getPrivate()->body); - d->contentType = move(src.getPrivate()->contentType); - } - + d->body = move(src.getPrivate()->body); + d->contentType = move(src.getPrivate()->contentType); return *this; } diff --git a/src/db/abstract/abstract-db.h b/src/db/abstract/abstract-db.h index 3eac6971f..ac8922077 100644 --- a/src/db/abstract/abstract-db.h +++ b/src/db/abstract/abstract-db.h @@ -19,8 +19,6 @@ #ifndef _ABSTRACT_DB_H_ #define _ABSTRACT_DB_H_ -#include - #include "object/object.h" // ============================================================================= diff --git a/src/db/provider/db-session-provider.h b/src/db/provider/db-session-provider.h index 50542d5eb..370aec943 100644 --- a/src/db/provider/db-session-provider.h +++ b/src/db/provider/db-session-provider.h @@ -19,8 +19,6 @@ #ifndef _DB_SESSION_PROVIDER_H_ #define _DB_SESSION_PROVIDER_H_ -#include - #include "db-session.h" #include "object/singleton.h" diff --git a/src/db/provider/db-session.h b/src/db/provider/db-session.h index ac8a0582e..410c6b742 100644 --- a/src/db/provider/db-session.h +++ b/src/db/provider/db-session.h @@ -19,8 +19,6 @@ #ifndef _DB_SESSION_H_ #define _DB_SESSION_H_ -#include - #include "object/clonable-object.h" // ============================================================================= diff --git a/src/object/object-p.h b/src/object/object-p.h index f8c378a7d..74ac5b953 100644 --- a/src/object/object-p.h +++ b/src/object/object-p.h @@ -19,8 +19,12 @@ #ifndef _OBJECT_P_H_ #define _OBJECT_P_H_ +#include + #include "linphone/utils/general.h" +#include "variant/variant.h" + // ============================================================================= LINPHONE_BEGIN_NAMESPACE @@ -33,6 +37,8 @@ protected: Object *mPublic = nullptr; private: + std::unordered_map properties; + L_DECLARE_PUBLIC(Object); }; diff --git a/src/object/object.cpp b/src/object/object.cpp index 191337235..b201df143 100644 --- a/src/object/object.cpp +++ b/src/object/object.cpp @@ -22,6 +22,8 @@ // ============================================================================= +using namespace std; + LINPHONE_BEGIN_NAMESPACE Object::~Object () { @@ -32,4 +34,20 @@ Object::Object (ObjectPrivate &p) : mPrivate(&p) { mPrivate->mPublic = this; } +Variant Object::getProperty (const string &name) const { + L_D(const Object); + auto it = d->properties.find(name); + return it == d->properties.cend() ? Variant() : it->second; +} + +void Object::setProperty (const string &name, const Variant &value) { + L_D(Object); + d->properties[name] = value; +} + +void Object::setProperty (const string &name, Variant &&value) { + L_D(Object); + d->properties[name] = move(value); +} + LINPHONE_END_NAMESPACE diff --git a/src/object/object.h b/src/object/object.h index f49b0b4f8..0941664d9 100644 --- a/src/object/object.h +++ b/src/object/object.h @@ -19,16 +19,24 @@ #ifndef _OBJECT_H_ #define _OBJECT_H_ +#include + #include "linphone/utils/general.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE +class Variant; + class LINPHONE_PUBLIC Object { public: virtual ~Object (); + Variant getProperty (const std::string &name) const; + void setProperty (const std::string &name, const Variant &value); + void setProperty (const std::string &name, Variant &&value); + protected: explicit Object (ObjectPrivate &p); diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp new file mode 100644 index 000000000..e36d6cd1d --- /dev/null +++ b/src/variant/variant.cpp @@ -0,0 +1,174 @@ +/* + * variant.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "variant.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class VariantPrivate { +public: + union Value { + int i; + unsigned int ui; + long l; + unsigned long ul; + long long ll; + unsigned long long ull; + bool b; + double d; + float f; + }; + + Variant::Type type = Variant::Invalid; + Value value = {}; +}; + +Variant::Variant () { + // Nothing. Construct an invalid invariant. +} + +Variant::Variant (Type type) { + // TODO. +} + +Variant::Variant (const Variant &src) { + // TODO. +} + +Variant::Variant (Variant &&src) { + // TODO. +} + +Variant::Variant (int value) : Variant(Int) { + L_D(Variant); + d->value.i = value; +} + +Variant::Variant (unsigned int value) : Variant(Int) { + L_D(Variant); + d->value.ui = value; +} + +Variant::Variant (long value) : Variant(Int) { + L_D(Variant); + d->value.l = value; +} + +Variant::Variant (unsigned long value) : Variant(Int) { + L_D(Variant); + d->value.ul = value; +} + +Variant::Variant (long long value) : Variant(Int) { + L_D(Variant); + d->value.ll = value; +} + +Variant::Variant (unsigned long long value) : Variant(Int) { + L_D(Variant); + d->value.ull = value; +} + +Variant::Variant (bool value) : Variant(Int) { + L_D(Variant); + d->value.b = value; +} + +Variant::Variant (double value) : Variant(Int) { + L_D(Variant); + d->value.d = value; +} + +Variant::Variant (float value) : Variant(Int) { + L_D(Variant); + d->value.f = value; +} + +Variant::Variant (const std::string &value) { + // TODO. +} + +Variant::~Variant () { + // TODO. +} + +bool Variant::operator!= (const Variant &variant) const { + // TODO. + return false; +} + +bool Variant::operator< (const Variant &variant) const { + // TODO. + return false; +} + +bool Variant::operator<= (const Variant &variant) const { + // TODO. + return false; +} + +Variant &Variant::operator= (const Variant &variant) { + // TODO. + return *this; +} + +Variant &Variant::operator= (Variant &&variant) { + // TODO. + return *this; +} + +bool Variant::operator== (const Variant &variant) const { + // TODO. + return false; +} + +bool Variant::operator> (const Variant &variant) const { + // TODO. + return false; +} + +bool Variant::operator>= (const Variant &variant) const { + // TODO. + return false; +} + +bool Variant::isValid () const { + // TODO. + return false; +} + +void Variant::clear () { + // TODO. +} + +void Variant::swap (const Variant &variant) { + // TODO. +} + +// ----------------------------------------------------------------------------- + +void Variant::getValue (int type, void *value, bool *soFarSoGood) { + if (type <= 0 || type >= MaxDefaultTypes) + return; // Unable to get value. + + // TODO. +} + +LINPHONE_END_NAMESPACE diff --git a/src/variant/variant.h b/src/variant/variant.h new file mode 100644 index 000000000..fccf35d95 --- /dev/null +++ b/src/variant/variant.h @@ -0,0 +1,133 @@ +/* + * variant.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _VARIANT_H_ +#define _VARIANT_H_ + +#include + +#include "linphone/utils/general.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +#define L_DECLARE_VARIANT_TYPES(FUNC) \ + FUNC(int, Int, 1) \ + FUNC(unsigned int, UnsignedInt, 2) \ + FUNC(long, Long, 3) \ + FUNC(unsigned long, UnsignedLong, 4) \ + FUNC(long long, LongLong, 5) \ + FUNC(unsigned long long, UnsignedLongLong, 6) \ + FUNC(bool, Bool, 7) \ + FUNC(double, Double, 8) \ + FUNC(float, Float, 9) \ + FUNC(std::string, String, 10) \ + FUNC(void *, Generic, 11) + +#define L_DECLARE_VARIANT_ENUM_TYPE(TYPE, NAME, ID) NAME = ID, +#define L_DECLARE_VARIANT_TRAIT_TYPE(TYPE, NAME, ID) \ + template<> \ + struct Variant::IdOfType { \ + static const int id = ID; \ + }; + +class VariantPrivate; + +class Variant { +public: + enum Type { + Invalid = 0, + L_DECLARE_VARIANT_TYPES(L_DECLARE_VARIANT_ENUM_TYPE) + MaxDefaultTypes + }; + + Variant (); + Variant (Type type); + + Variant (const Variant &src); + Variant (Variant &&src); + + Variant (int value); + Variant (unsigned int value); + Variant (long value); + Variant (unsigned long value); + Variant (long long value); + Variant (unsigned long long value); + Variant (bool value); + Variant (double value); + Variant (float value); + Variant (const std::string &value); + + template::value> > + // void* constructor. Must be explicitly called. + Variant (T value); + + ~Variant (); + + bool operator!= (const Variant &variant) const; + bool operator< (const Variant &variant) const; + bool operator<= (const Variant &variant) const; + Variant &operator= (const Variant &variant); + Variant &operator= (Variant &&variant); + bool operator== (const Variant &variant) const; + bool operator> (const Variant &variant) const; + bool operator>= (const Variant &variant) const; + + template + void setValue (const T &value) { + // TODO. + } + + template + T getValue (bool *soFarSoGood = nullptr) const { + constexpr int id = IdOfType::id; + static_assert(id != Invalid, "Unable to get value of unsupported type."); + + T value; + getValue(id, &value, &soFarSoGood); + return value; + } + + bool isValid () const; + + void clear (); + void swap (const Variant &variant); + +private: + template + struct IdOfType { + static const int id = Invalid; + }; + + void getValue (int type, void *value, bool *soFarSoGood); + + VariantPrivate *mPrivate = nullptr; + + L_DECLARE_PRIVATE(Variant); +}; + +L_DECLARE_VARIANT_TYPES(L_DECLARE_VARIANT_TRAIT_TYPE); + +#undef L_DECLARE_VARIANT_TYPES +#undef L_DECLARE_VARIANT_ENUM_TYPE +#undef L_DECLARE_VARIANT_TRAIT_TYPE + +LINPHONE_END_NAMESPACE + +#endif // ifndef _VARIANT_H_ From 05b91d4b64796944b17d849717b3f1dc69e5d3e7 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 13 Sep 2017 12:35:44 +0200 Subject: [PATCH 0043/2215] Started CPIM chat message modifier --- src/chat/chat-message.cpp | 6 ++- src/chat/chat-message.h | 2 +- src/chat/modifier/chat-message-modifier.h | 4 +- .../modifier/cpim-chat-message-modifier.cpp | 37 +++++++++++++++++-- .../modifier/cpim-chat-message-modifier.h | 4 +- .../multipart-chat-message-modifier.cpp | 4 +- .../multipart-chat-message-modifier.h | 4 +- 7 files changed, 47 insertions(+), 14 deletions(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index a5e816342..3adc8bea0 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -91,8 +91,8 @@ string ChatMessage::getContentType () const { return d->contentType; } -void ChatMessage::send () const { - L_D(const ChatMessage); +void ChatMessage::send () { + L_D(ChatMessage); if (d->contents.size() > 1) { MultipartChatMessageModifier mcmm; @@ -107,6 +107,8 @@ void ChatMessage::send () const { } // TODO. + + d->isReadOnly = true; } bool ChatMessage::containsReadableText () const { diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index 727a6fb93..9769c2ef7 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -69,7 +69,7 @@ public: std::string getContentType () const; - void send () const; + void send (); bool containsReadableText () const; diff --git a/src/chat/modifier/chat-message-modifier.h b/src/chat/modifier/chat-message-modifier.h index 64434abe5..97e8724f7 100644 --- a/src/chat/modifier/chat-message-modifier.h +++ b/src/chat/modifier/chat-message-modifier.h @@ -27,8 +27,8 @@ class ChatMessageModifier { public: - virtual void encode(const LinphonePrivate::ChatMessagePrivate* msg) = 0; - virtual void decode(const LinphonePrivate::ChatMessagePrivate* msg) = 0; + virtual void encode(LinphonePrivate::ChatMessagePrivate* msg) = 0; + virtual void decode(LinphonePrivate::ChatMessagePrivate* msg) = 0; virtual ~ChatMessageModifier () = default; }; diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index b29d4cd27..b2deb558b 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -16,23 +16,54 @@ * along with this program. If not, see . */ + #include + + #include "content/content-type.h" + #include "content/content.h" #include "chat/chat-message-p.h" + #include "chat/cpim/cpim.h" + #include "cpim-chat-message-modifier.h" LINPHONE_BEGIN_NAMESPACE using namespace std; - void CpimChatMessageModifier::encode(const LinphonePrivate::ChatMessagePrivate* msg) { - //TODO + void CpimChatMessageModifier::encode(LinphonePrivate::ChatMessagePrivate* msg) { + Cpim::Message message; + Cpim::GenericHeader contentTypeHeader; + contentTypeHeader.setName("Content-Type"); + contentTypeHeader.setValue("Message/CPIM"); + message.addCpimHeader(contentTypeHeader); + + shared_ptr content; if (msg->internalContent) { // Another ChatMessageModifier was called before this one, we apply our changes on the private content + content = msg->internalContent; } else { // We're the first ChatMessageModifier to be called, we'll create the private content from the public one + // We take the first one because if there is more of them, the multipart modifier should have been called first + // So we should not be in this block + content = msg->contents.front(); + } + + string contentType = content->getContentType().asString(); + const vector body = content->getBody(); + string contentBody(body.begin(), body.end()); + message.setContent("ContentType: " + contentType + "\r\n" + contentBody); + + if (!message.isValid()) { + //TODO + } else { + shared_ptr newContent = make_shared(); + ContentType newContentType("Message/CPIM"); + newContent->setContentType(newContentType); + newContent->setBody(message.asString()); + msg->internalContent = newContent; } } - void CpimChatMessageModifier::decode(const LinphonePrivate::ChatMessagePrivate* msg) { + void CpimChatMessageModifier::decode(LinphonePrivate::ChatMessagePrivate* msg) { //TODO } diff --git a/src/chat/modifier/cpim-chat-message-modifier.h b/src/chat/modifier/cpim-chat-message-modifier.h index d5ee530c6..f31f1cb12 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.h +++ b/src/chat/modifier/cpim-chat-message-modifier.h @@ -28,8 +28,8 @@ class CpimChatMessageModifier : ChatMessageModifier { public: CpimChatMessageModifier() {}; - virtual void encode(const LinphonePrivate::ChatMessagePrivate* msg); - virtual void decode(const LinphonePrivate::ChatMessagePrivate* msg); + virtual void encode(LinphonePrivate::ChatMessagePrivate* msg); + virtual void decode(LinphonePrivate::ChatMessagePrivate* msg); virtual ~CpimChatMessageModifier () = default; }; diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index f980a9bfd..352de4e2a 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -23,13 +23,13 @@ using namespace std; - void MultipartChatMessageModifier::encode(const LinphonePrivate::ChatMessagePrivate* msg) { + void MultipartChatMessageModifier::encode(LinphonePrivate::ChatMessagePrivate* msg) { if (msg->contents.size() > 1) { //TODO } } - void MultipartChatMessageModifier::decode(const LinphonePrivate::ChatMessagePrivate* msg) { + void MultipartChatMessageModifier::decode(LinphonePrivate::ChatMessagePrivate* msg) { //TODO } diff --git a/src/chat/modifier/multipart-chat-message-modifier.h b/src/chat/modifier/multipart-chat-message-modifier.h index 9f9b23069..b66f618f0 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.h +++ b/src/chat/modifier/multipart-chat-message-modifier.h @@ -28,8 +28,8 @@ class MultipartChatMessageModifier : ChatMessageModifier { public: MultipartChatMessageModifier() {}; - virtual void encode(const LinphonePrivate::ChatMessagePrivate* msg); - virtual void decode(const LinphonePrivate::ChatMessagePrivate* msg); + virtual void encode(LinphonePrivate::ChatMessagePrivate* msg); + virtual void decode(LinphonePrivate::ChatMessagePrivate* msg); virtual ~MultipartChatMessageModifier () = default; }; From 3d30114ea73d9c811c04dc4709a8b7d87093116e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 13 Sep 2017 13:10:09 +0200 Subject: [PATCH 0044/2215] Removed string content type from chatMessage --- src/chat/chat-message-p.h | 1 - src/chat/chat-message.cpp | 5 ----- 2 files changed, 6 deletions(-) diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index ffd699d17..991a23aff 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -36,7 +36,6 @@ private: // LinphoneAddress *from; // LinphoneAddress *to; std::shared_ptr errorInfo; - std::string contentType; std::string text; bool isSecured = false; bool isReadOnly = false; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 3adc8bea0..10e30db06 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -86,11 +86,6 @@ shared_ptr ChatMessage::getErrorInfo () const { return d->errorInfo; } -string ChatMessage::getContentType () const { - L_D(const ChatMessage); - return d->contentType; -} - void ChatMessage::send () { L_D(ChatMessage); From 0c9fbfc16cac104bd107d0a8db02a4815f5df7be Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 13 Sep 2017 15:27:36 +0200 Subject: [PATCH 0045/2215] Improved CPIM parser to parse all MIME-encapsulated message content headers --- src/chat/cpim/message/cpim-message.cpp | 39 ++++++++++- src/chat/cpim/message/cpim-message.h | 4 ++ src/chat/cpim/parser/cpim-grammar.cpp | 2 +- src/chat/cpim/parser/cpim-parser.cpp | 19 +++++- .../modifier/cpim-chat-message-modifier.cpp | 40 +++++++++-- src/content/content-type.cpp | 4 ++ src/content/content-type.h | 1 + tester/cpim-tester.cpp | 68 +++++++++++++------ 8 files changed, 144 insertions(+), 33 deletions(-) diff --git a/src/chat/cpim/message/cpim-message.cpp b/src/chat/cpim/message/cpim-message.cpp index 29252e934..2dc33f4c3 100644 --- a/src/chat/cpim/message/cpim-message.cpp +++ b/src/chat/cpim/message/cpim-message.cpp @@ -20,6 +20,7 @@ #include "linphone/utils/utils.h" +#include "logger/logger.h" #include "chat/cpim/parser/cpim-parser.h" #include "object/object-p.h" @@ -37,6 +38,7 @@ public: shared_ptr cpimHeaders = make_shared(); shared_ptr messageHeaders = make_shared(); + shared_ptr contentHeaders = make_shared(); string content; }; @@ -92,6 +94,30 @@ void Cpim::Message::removeMessageHeader (const Header &messageHeader) { // ----------------------------------------------------------------------------- +Cpim::Message::HeaderList Cpim::Message::getContentHeaders () const { + L_D(const Message); + return d->contentHeaders; +} + +bool Cpim::Message::addContentHeader (const Header &contentHeader) { + L_D(Message); + + if (!contentHeader.isValid()) + return false; + + d->contentHeaders->push_back(Parser::getInstance()->cloneHeader(contentHeader)); + return true; +} + +void Cpim::Message::removeContentHeader (const Header &contentHeader) { + L_D(Message); + d->contentHeaders->remove_if([&contentHeader](const shared_ptr &header) { + return contentHeader.getName() == header->getName() && contentHeader.getValue() == header->getValue(); + }); +} + +// ----------------------------------------------------------------------------- + string Cpim::Message::getContent () const { L_D(const Message); return d->content; @@ -125,11 +151,18 @@ string Cpim::Message::asString () const { output += "\r\n"; - for (const auto &messageHeader : *d->messageHeaders) - output += messageHeader->asString(); + if (d->messageHeaders->size() > 0) { + for (const auto &messageHeader : *d->messageHeaders) + output += messageHeader->asString(); + output += "\r\n"; + } + + for (const auto &contentHeaders : *d->contentHeaders) + output += contentHeaders->asString(); + output += "\r\n"; - output += ""; // TODO: Headers MIME. + output += getContent(); return output; diff --git a/src/chat/cpim/message/cpim-message.h b/src/chat/cpim/message/cpim-message.h index 38c1cd5a0..0ddf36d69 100644 --- a/src/chat/cpim/message/cpim-message.h +++ b/src/chat/cpim/message/cpim-message.h @@ -42,6 +42,10 @@ namespace Cpim { HeaderList getMessageHeaders () const; bool addMessageHeader (const Header &messageHeader); void removeMessageHeader (const Header &messageHeader); + + HeaderList getContentHeaders () const; + bool addContentHeader (const Header &contentHeader); + void removeContentHeader (const Header &contentHeader); std::string getContent () const; bool setContent (const std::string &content); diff --git a/src/chat/cpim/parser/cpim-grammar.cpp b/src/chat/cpim/parser/cpim-grammar.cpp index 94bd86d16..b9b863f12 100644 --- a/src/chat/cpim/parser/cpim-grammar.cpp +++ b/src/chat/cpim/parser/cpim-grammar.cpp @@ -25,7 +25,7 @@ LINPHONE_BEGIN_NAMESPACE static const char *grammar = // See: https://tools.ietf.org/html/rfc3862 R"==GRAMMAR==( -Message = Headers CRLF Headers CRLF +Message = Headers CRLF Headers CRLF [Headers CRLF] Headers = *Header Header = Header-name ":" Header-parameters SP Header-value CRLF diff --git a/src/chat/cpim/parser/cpim-parser.cpp b/src/chat/cpim/parser/cpim-parser.cpp index 1cf503a66..0a6ee995e 100644 --- a/src/chat/cpim/parser/cpim-parser.cpp +++ b/src/chat/cpim/parser/cpim-parser.cpp @@ -166,7 +166,7 @@ namespace Cpim { // Warning: Call this function one time! shared_ptr createMessage () const { size_t size = mHeaders->size(); - if (size != 2) { + if (size < 2 || size > 3) { lWarning() << "Bad headers lists size."; return nullptr; } @@ -190,9 +190,21 @@ namespace Cpim { } // Add message headers. + if (mHeaders->size() > 2) { + list>::iterator it = mHeaders->begin(); + std::advance(it, 1); + shared_ptr messageHeaders = *it; + for (const auto &headerNode : *messageHeaders) { + const shared_ptr header = headerNode->createHeader(); + if (!header || !message->addMessageHeader(*header)) + return nullptr; + } + } + + // Add content headers. for (const auto &headerNode : *mHeaders->back()) { const shared_ptr header = headerNode->createHeader(); - if (!header || !message->addMessageHeader(*header)) + if (!header || !message->addContentHeader(*header)) return nullptr; } @@ -265,8 +277,9 @@ shared_ptr Cpim::Parser::parseMessage (const string &input) { } shared_ptr message = messageNode->createMessage(); - if (message) + if (message) { message->setContent(input.substr(parsedSize)); + } return message; } diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index b2deb558b..d03344abe 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -31,10 +31,10 @@ void CpimChatMessageModifier::encode(LinphonePrivate::ChatMessagePrivate* msg) { Cpim::Message message; - Cpim::GenericHeader contentTypeHeader; - contentTypeHeader.setName("Content-Type"); - contentTypeHeader.setValue("Message/CPIM"); - message.addCpimHeader(contentTypeHeader); + Cpim::GenericHeader cpimContentTypeHeader; + cpimContentTypeHeader.setName("Content-Type"); + cpimContentTypeHeader.setValue("Message/CPIM"); + message.addCpimHeader(cpimContentTypeHeader); shared_ptr content; if (msg->internalContent) { @@ -50,7 +50,13 @@ string contentType = content->getContentType().asString(); const vector body = content->getBody(); string contentBody(body.begin(), body.end()); - message.setContent("ContentType: " + contentType + "\r\n" + contentBody); + + Cpim::GenericHeader contentTypeHeader; + contentTypeHeader.setName("Content-Type"); + contentTypeHeader.setValue(contentType); + message.addContentHeader(contentTypeHeader); + + message.setContent(contentBody); if (!message.isValid()) { //TODO @@ -64,7 +70,29 @@ } void CpimChatMessageModifier::decode(LinphonePrivate::ChatMessagePrivate* msg) { - //TODO + shared_ptr content; + if (msg->internalContent) { + content = msg->internalContent; + } else { + content = msg->contents.front(); + } + + ContentType contentType = content->getContentType(); + if (contentType.asString() == "Message/CPIM") { + const vector body = content->getBody(); + string contentBody(body.begin(), body.end()); + shared_ptr message = Cpim::Message::createFromString(contentBody); + if (message && message->isValid()) { + shared_ptr newContent = make_shared(); + ContentType newContentType(message->getContentHeaders()->front()->getValue()); + newContent->setContentType(newContentType); + newContent->setBody(message->getContent()); + } else { + //TODO + } + } else { + //TODO + } } LINPHONE_END_NAMESPACE \ No newline at end of file diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index 7b55d4322..4fc11faf0 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -70,6 +70,10 @@ bool ContentType::operator== (const ContentType &contentType) { return getType() == contentType.getType() && getSubType() == contentType.getSubType(); } +bool ContentType::operator== (const string &contentType) { + return *this == ContentType(contentType); +} + const string &ContentType::getType () const { L_D(const ContentType); return d->type; diff --git a/src/content/content-type.h b/src/content/content-type.h index 15095207c..9df428f9f 100644 --- a/src/content/content-type.h +++ b/src/content/content-type.h @@ -38,6 +38,7 @@ public: ContentType &operator= (const ContentType &src); bool operator== (const ContentType &contentType); + bool operator== (const std::string &contentType); bool isValid () const; diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index 8c7522905..ea83c2f65 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -37,6 +37,8 @@ static void parse_minimal_message () { const string str2 = message->asString(); BC_ASSERT_STRING_EQUAL(str2.c_str(), str.c_str()); + + BC_ASSERT_STRING_EQUAL(message->getContent().c_str(), ""); } static void set_generic_header_name () { @@ -227,6 +229,10 @@ static void check_subject_header_language () { } static void parse_rfc_example () { + const string body = "" + "Here is the text of my message." + ""; + const string str = "Content-type: Message/CPIM\r\n" "\r\n" "From: MR SANDERS \r\n" @@ -239,21 +245,25 @@ static void parse_rfc_example () { "MyFeatures.VitalMessageOption: Confirmation-requested\r\n" "MyFeatures.WackyMessageOption: Use-silly-font\r\n" "\r\n" - "Content-type text/xml; charset=utf-8\r\n" + "Content-Type: text/xml; charset=utf-8\r\n" "Content-ID: <1234567890@foo.com>\r\n" - "\r\n" - "" - "Here is the text of my message." - ""; + "\r\n" + body; shared_ptr message = Cpim::Message::createFromString(str); if (!BC_ASSERT_PTR_NOT_NULL(message)) return; const string str2 = message->asString(); BC_ASSERT_STRING_EQUAL(str2.c_str(), str.c_str()); + + string content = message->getContent(); + BC_ASSERT_STRING_EQUAL(content.c_str(), body.c_str()); } static void parse_message_with_generic_header_parameters () { + const string body = "" + "Here is the text of my message." + ""; + const string str = "Content-type: Message/CPIM\r\n" "\r\n" "From: MR SANDERS \r\n" @@ -261,18 +271,18 @@ static void parse_message_with_generic_header_parameters () { "yaya: coucou\r\n" "yepee:;good=bad ugly\r\n" "\r\n" - "Content-type text/xml; charset=utf-8\r\n" + "Content-Type: text/xml; charset=utf-8\r\n" "Content-ID: <1234567890@foo.com>\r\n" - "\r\n" - "" - "Here is the text of my message." - ""; + "\r\n" + body; shared_ptr message = Cpim::Message::createFromString(str); if (!BC_ASSERT_PTR_NOT_NULL(message)) return; const string str2 = message->asString(); BC_ASSERT_STRING_EQUAL(str2.c_str(), str.c_str()); + + string content = message->getContent(); + BC_ASSERT_STRING_EQUAL(content.c_str(), body.c_str()); } static void build_message () { @@ -281,11 +291,11 @@ static void build_message () { return; // Set CPIM headers. - Cpim::GenericHeader contentTypeHeader; - if (!BC_ASSERT_TRUE(contentTypeHeader.setName("Content-Type"))) return; - if (!BC_ASSERT_TRUE(contentTypeHeader.setValue("Message/CPIM"))) return; + Cpim::GenericHeader cpimContentTypeHeader; + if (!BC_ASSERT_TRUE(cpimContentTypeHeader.setName("Content-Type"))) return; + if (!BC_ASSERT_TRUE(cpimContentTypeHeader.setValue("Message/CPIM"))) return; - if (!BC_ASSERT_TRUE(message.addCpimHeader(contentTypeHeader))) return; + if (!BC_ASSERT_TRUE(message.addCpimHeader(cpimContentTypeHeader))) return; // Set message headers. Cpim::FromHeader fromHeader; @@ -328,10 +338,18 @@ static void build_message () { if (!BC_ASSERT_TRUE(message.addMessageHeader(vitalMessageHeader))) return; if (!BC_ASSERT_TRUE(message.addMessageHeader(wackyMessageHeader))) return; - const string content = "Content-type text/xml; charset=utf-8\r\n" - "Content-ID: <1234567890@foo.com>\r\n" - "\r\n" - "" + // Set Content headers. + Cpim::GenericHeader contentTypeHeader; + if (!BC_ASSERT_TRUE(contentTypeHeader.setName("Content-Type"))) return; + if (!BC_ASSERT_TRUE( contentTypeHeader.setValue("text/xml; charset=utf-8"))) return; + if (!BC_ASSERT_TRUE(message.addContentHeader(contentTypeHeader))) return; + + Cpim::GenericHeader contentIdHeader; + if (!BC_ASSERT_TRUE(contentIdHeader.setName("Content-ID"))) return; + if (!BC_ASSERT_TRUE( contentIdHeader.setValue("<1234567890@foo.com>"))) return; + if (!BC_ASSERT_TRUE(message.addContentHeader(contentIdHeader))) return; + + const string content = "" "Here is the text of my message." ""; @@ -351,7 +369,7 @@ static void build_message () { "MyFeatures.VitalMessageOption: Confirmation-requested\r\n" "MyFeatures.WackyMessageOption: Use-silly-font\r\n" "\r\n" - "Content-type text/xml; charset=utf-8\r\n" + "Content-Type: text/xml; charset=utf-8\r\n" "Content-ID: <1234567890@foo.com>\r\n" "\r\n" "" @@ -361,6 +379,14 @@ static void build_message () { BC_ASSERT_STRING_EQUAL(strMessage.c_str(), expectedMessage.c_str()); } +static void cpim_chat_message_modifier_encoder(void) { + +} + +static void cpim_chat_message_modifier_decoder(void) { + +} + test_t cpim_tests[] = { TEST_NO_TAG("Parse minimal CPIM message", parse_minimal_message), TEST_NO_TAG("Set generic header name", set_generic_header_name), @@ -370,7 +396,9 @@ test_t cpim_tests[] = { TEST_NO_TAG("Check Subject header language", check_subject_header_language), TEST_NO_TAG("Parse RFC example", parse_rfc_example), TEST_NO_TAG("Parse Message with generic header parameters", parse_message_with_generic_header_parameters), - TEST_NO_TAG("Build Message", build_message) + TEST_NO_TAG("Build Message", build_message), + TEST_NO_TAG("CPIM chat message modifier encoder", cpim_chat_message_modifier_encoder), + TEST_NO_TAG("CPIM chat message modifier decoder", cpim_chat_message_modifier_decoder) }; test_suite_t cpim_test_suite = { From a7b9d99f6276150270b3538ba1602cee287f5ac2 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 13 Sep 2017 16:57:31 +0200 Subject: [PATCH 0046/2215] feat(variant): add impl (in progress) on getValue --- src/chat/chat-message-p.h | 2 - src/chat/chat-message.cpp | 6 +- src/chat/chat-message.h | 2 - src/chat/cpim/parser/cpim-parser.cpp | 2 - src/db/provider/db-session-provider.cpp | 2 - src/variant/variant.cpp | 145 ++++++++++++++++++++++-- src/variant/variant.h | 33 ++++-- 7 files changed, 157 insertions(+), 35 deletions(-) diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 991a23aff..87198de32 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -19,8 +19,6 @@ #ifndef _CHAT_MESSAGE_P_H_ #define _CHAT_MESSAGE_P_H_ -#include - #include "chat-message.h" #include "db/events-db.h" #include "object/object-p.h" diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 10e30db06..ee56033da 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -16,8 +16,6 @@ * along with this program. If not, see . */ -#include - #include "db/events-db.h" #include "object/object-p.h" @@ -88,7 +86,7 @@ shared_ptr ChatMessage::getErrorInfo () const { void ChatMessage::send () { L_D(ChatMessage); - + if (d->contents.size() > 1) { MultipartChatMessageModifier mcmm; mcmm.encode(d); @@ -159,7 +157,7 @@ void ChatMessage::addContent (const shared_ptr &content) { void ChatMessage::removeContent (const shared_ptr &content) { L_D(ChatMessage); if (d->isReadOnly) return; - + d->contents.remove(const_pointer_cast(content)); } diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index 9769c2ef7..b8b026c8e 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -67,8 +67,6 @@ public: std::shared_ptr getErrorInfo () const; - std::string getContentType () const; - void send (); bool containsReadableText () const; diff --git a/src/chat/cpim/parser/cpim-parser.cpp b/src/chat/cpim/parser/cpim-parser.cpp index 0a6ee995e..15f6a1c6e 100644 --- a/src/chat/cpim/parser/cpim-parser.cpp +++ b/src/chat/cpim/parser/cpim-parser.cpp @@ -16,8 +16,6 @@ * along with this program. If not, see . */ -#include - #include #include diff --git a/src/db/provider/db-session-provider.cpp b/src/db/provider/db-session-provider.cpp index 35dc9c82c..34edc9a5f 100644 --- a/src/db/provider/db-session-provider.cpp +++ b/src/db/provider/db-session-provider.cpp @@ -16,8 +16,6 @@ * along with this program. If not, see . */ -#include - #ifdef SOCI_ENABLED #include #endif // ifdef SOCI_ENABLED diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index e36d6cd1d..fa18701ed 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -20,6 +20,8 @@ // ============================================================================= +using namespace std; + LINPHONE_BEGIN_NAMESPACE class VariantPrivate { @@ -27,10 +29,13 @@ public: union Value { int i; unsigned int ui; + short s; + unsigned short us; long l; unsigned long ul; long long ll; unsigned long long ull; + char c; bool b; double d; float f; @@ -61,42 +66,57 @@ Variant::Variant (int value) : Variant(Int) { d->value.i = value; } -Variant::Variant (unsigned int value) : Variant(Int) { +Variant::Variant (unsigned int value) : Variant(UnsignedInt) { L_D(Variant); d->value.ui = value; } -Variant::Variant (long value) : Variant(Int) { +Variant::Variant (short value) : Variant(Short) { + L_D(Variant); + d->value.s = value; +} + +Variant::Variant (unsigned short value) : Variant(UnsignedShort) { + L_D(Variant); + d->value.us = value; +} + +Variant::Variant (long value) : Variant(Long) { L_D(Variant); d->value.l = value; } -Variant::Variant (unsigned long value) : Variant(Int) { +Variant::Variant (unsigned long value) : Variant(UnsignedLong) { L_D(Variant); d->value.ul = value; } -Variant::Variant (long long value) : Variant(Int) { +Variant::Variant (long long value) : Variant(LongLong) { L_D(Variant); d->value.ll = value; } -Variant::Variant (unsigned long long value) : Variant(Int) { +Variant::Variant (unsigned long long value) : Variant(UnsignedLongLong) { L_D(Variant); d->value.ull = value; } -Variant::Variant (bool value) : Variant(Int) { +Variant::Variant (char value) : Variant(Char) { + L_D(Variant); + d->value.c = value; +} + +Variant::Variant (bool value) : Variant(Bool) { L_D(Variant); d->value.b = value; } -Variant::Variant (double value) : Variant(Int) { +Variant::Variant (double value) : Variant(Double) { L_D(Variant); d->value.d = value; } -Variant::Variant (float value) : Variant(Int) { +Variant::Variant (float value) : Variant(Float) { L_D(Variant); d->value.f = value; } @@ -162,13 +182,114 @@ void Variant::swap (const Variant &variant) { // TODO. } +// ----------------------------------------------------------------------------- +// Number conversions. // ----------------------------------------------------------------------------- -void Variant::getValue (int type, void *value, bool *soFarSoGood) { - if (type <= 0 || type >= MaxDefaultTypes) - return; // Unable to get value. - +static inline long long getValueAsNumber (const VariantPrivate &p, bool *soFarSoGood) { // TODO. + return 0; +} + +static inline unsigned long long getValueAsUnsignedNumber (const VariantPrivate &p, bool *soFarSoGood) { + // TODO. + return 0; +} + +// ----------------------------------------------------------------------------- +// Specific conversions. +// ----------------------------------------------------------------------------- + +static inline bool getValueAsBool (const VariantPrivate &p, bool *soFarSoGood) { + // TODO. + return false; +} + +static inline double getValueAsDouble (const VariantPrivate &p, bool *soFarSoGood) { + // TODO. + return 0.0; +} + +static inline float getValueAsFloat (const VariantPrivate &p, bool *soFarSoGood) { + // TODO. + return 0.f; +} + +static inline float getValueAsString (const VariantPrivate &p, bool *soFarSoGood) { + // TODO. + return 0.f; +} + +static inline void *getValueAsGeneric (const VariantPrivate &p, bool *soFarSoGood) { + // TODO. + return nullptr; +} + +// ----------------------------------------------------------------------------- + +void Variant::getValue (int type, void *value, bool *soFarSoGood) const { + L_D(const Variant); + + if (type <= 0 || type >= MaxDefaultTypes) { + *soFarSoGood = false; + // Unable to get value. It will be great to support custom types. + return; + } + + switch (static_cast(type)) { + // Cast as Number. + case Int: + *static_cast(value) = static_cast(getValueAsNumber(*d, soFarSoGood)); + break; + case Short: + *static_cast(value) = static_cast(getValueAsNumber(*d, soFarSoGood)); + break; + case Long: + *static_cast(value) = static_cast(getValueAsNumber(*d, soFarSoGood)); + break; + case LongLong: + *static_cast(value) = getValueAsNumber(*d, soFarSoGood); + break; + case Char: + *static_cast(value) = static_cast(getValueAsNumber(*d, soFarSoGood)); + break; + + // Cast as Unsigned number. + case UnsignedInt: + *static_cast(value) = static_cast(getValueAsNumber(*d, soFarSoGood)); + break; + case UnsignedShort: + *static_cast(value) = static_cast(getValueAsNumber(*d, soFarSoGood)); + break; + case UnsignedLong: + *static_cast(value) = static_cast(getValueAsNumber(*d, soFarSoGood)); + break; + case UnsignedLongLong: + *static_cast(value) = getValueAsNumber(*d, soFarSoGood); + break; + + // Cast as specific value. + case Bool: + *static_cast(value) = getValueAsBool(*d, soFarSoGood); + break; + case Double: + *static_cast(value) = getValueAsDouble(*d, soFarSoGood); + break; + case Float: + *static_cast(value) = getValueAsFloat(*d, soFarSoGood); + break; + case String: + *static_cast(value) = getValueAsString(*d, soFarSoGood); + break; + case Generic: + *static_cast(value) = getValueAsGeneric(*d, soFarSoGood); + break; + + case Invalid: + case MaxDefaultTypes: + *soFarSoGood = false; + break; + } } LINPHONE_END_NAMESPACE diff --git a/src/variant/variant.h b/src/variant/variant.h index fccf35d95..2966f79d1 100644 --- a/src/variant/variant.h +++ b/src/variant/variant.h @@ -30,15 +30,18 @@ LINPHONE_BEGIN_NAMESPACE #define L_DECLARE_VARIANT_TYPES(FUNC) \ FUNC(int, Int, 1) \ FUNC(unsigned int, UnsignedInt, 2) \ - FUNC(long, Long, 3) \ - FUNC(unsigned long, UnsignedLong, 4) \ - FUNC(long long, LongLong, 5) \ - FUNC(unsigned long long, UnsignedLongLong, 6) \ - FUNC(bool, Bool, 7) \ - FUNC(double, Double, 8) \ - FUNC(float, Float, 9) \ - FUNC(std::string, String, 10) \ - FUNC(void *, Generic, 11) + FUNC(short, Short, 3) \ + FUNC(unsigned short, UnsignedShort, 4) \ + FUNC(long, Long, 5) \ + FUNC(unsigned long, UnsignedLong, 6) \ + FUNC(long long, LongLong, 7) \ + FUNC(unsigned long long, UnsignedLongLong, 8) \ + FUNC(char, Char, 9) \ + FUNC(bool, Bool, 10) \ + FUNC(double, Double, 11) \ + FUNC(float, Float, 12) \ + FUNC(std::string, String, 13) \ + FUNC(void *, Generic, 14) #define L_DECLARE_VARIANT_ENUM_TYPE(TYPE, NAME, ID) NAME = ID, #define L_DECLARE_VARIANT_TRAIT_TYPE(TYPE, NAME, ID) \ @@ -65,10 +68,13 @@ public: Variant (int value); Variant (unsigned int value); + Variant (short value); + Variant (unsigned short value); Variant (long value); Variant (unsigned long value); Variant (long long value); Variant (unsigned long long value); + Variant (char value); Variant (bool value); Variant (double value); Variant (float value); @@ -100,7 +106,12 @@ public: static_assert(id != Invalid, "Unable to get value of unsupported type."); T value; - getValue(id, &value, &soFarSoGood); + + bool ok; + getValue(id, static_cast(&value), &ok); + if (soFarSoGood) + *soFarSoGood = ok; + return value; } @@ -115,7 +126,7 @@ private: static const int id = Invalid; }; - void getValue (int type, void *value, bool *soFarSoGood); + void getValue (int type, void *value, bool *soFarSoGood) const; VariantPrivate *mPrivate = nullptr; From a5ce479aa3585dd07938312e92f10ad0e046d60e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 13 Sep 2017 10:37:30 +0200 Subject: [PATCH 0047/2215] Add function to create a client group chat room. --- coreapi/chat.c | 12 +- include/linphone/chat.h | 2 + src/CMakeLists.txt | 1 - src/c-wrapper/c-tools.h | 14 +- src/call/call-listener.h | 2 + src/chat/basic-chat-room.cpp | 4 +- src/chat/chat-room-p.h | 2 +- src/chat/chat-room.cpp | 6 +- src/chat/chat-room.h | 2 +- src/chat/client-group-chat-room-p.h | 2 +- src/chat/client-group-chat-room.cpp | 47 ++++- src/chat/client-group-chat-room.h | 8 +- src/chat/is-composing-listener.h | 2 + src/chat/real-time-text-chat-room.cpp | 4 +- src/conference/conference-interface.h | 2 + src/conference/conference-p.h | 70 -------- src/conference/conference.cpp | 161 +++++++++--------- src/conference/conference.h | 41 ++++- src/conference/local-conference.cpp | 10 +- src/conference/local-conference.h | 3 - src/conference/participant.h | 2 + src/conference/remote-conference.cpp | 10 +- src/conference/remote-conference.h | 4 +- .../session/call-session-listener.h | 2 + src/conference/session/call-session.cpp | 3 +- 25 files changed, 211 insertions(+), 205 deletions(-) delete mode 100644 src/conference/conference-p.h diff --git a/coreapi/chat.c b/coreapi/chat.c index b7e26f8e8..aa35495ef 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -37,8 +37,9 @@ #include "c-wrapper/c-tools.h" #include "chat/basic-chat-room.h" -#include "chat/real-time-text-chat-room-p.h" +#include "chat/client-group-chat-room.h" #include "chat/real-time-text-chat-room.h" +#include "chat/real-time-text-chat-room-p.h" #include "content/content-type.h" struct _LinphoneChatRoom{ @@ -255,6 +256,15 @@ LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAd return ret; } +LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, bctbx_list_t *addresses) { + LinphoneChatRoom *cr = belle_sip_object_new(LinphoneChatRoom); + std::list l = L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(addresses, Address); + LinphonePrivate::Address me; // TODO + cr->cr = new LinphonePrivate::ClientGroupChatRoom(lc, me, l); + L_GET_PRIVATE(cr->cr)->setCBackPointer(cr); + return cr; +} + void linphone_core_delete_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr) { if (bctbx_list_find(lc->chatrooms, cr)) { lc->chatrooms = bctbx_list_remove(lc->chatrooms, cr); diff --git a/include/linphone/chat.h b/include/linphone/chat.h index e20a25ea7..3bc02d839 100644 --- a/include/linphone/chat.h +++ b/include/linphone/chat.h @@ -457,6 +457,8 @@ LINPHONE_PUBLIC void linphone_chat_message_set_user_data(LinphoneChatMessage* me **/ LINPHONE_PUBLIC LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg); +LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, bctbx_list_t *addresses); + LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg); /** diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c3958f0e9..248535880 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -52,7 +52,6 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES chat/real-time-text-chat-room-p.h chat/real-time-text-chat-room.h conference/conference-listener.h - conference/conference-p.h conference/conference.h conference/local-conference.h conference/params/call-session-params-p.h diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index 5ea666d75..8a30c1e77 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -116,8 +116,8 @@ public: template static inline bctbx_list_t * getCListFromCppList (std::list cppList) { bctbx_list_t *result = nullptr; - for (auto it = cppList.begin(); it != cppList.end(); it++) - result = bctbx_list_append(result, *it); + for (const auto &value : cppList) + result = bctbx_list_append(result, value); return result; } @@ -129,6 +129,14 @@ public: return result; } + template + static inline std::list getCppListOfCppObjFromCListOfStructPtr (bctbx_list_t *cList) { + std::list result; + for (auto it = cList; it; it = bctbx_list_next(it)) + result.push_back(*getCppPtrFromC(reinterpret_cast(bctbx_list_get_data(it)))); + return result; + } + private: Wrapper (); @@ -217,5 +225,7 @@ LINPHONE_END_NAMESPACE LINPHONE_NAMESPACE::Wrapper::getCListFromCppList(LIST) #define L_GET_CPP_LIST_FROM_C_LIST(LIST, TYPE) \ LINPHONE_NAMESPACE::Wrapper::getCppListFromCList(LIST) +#define L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(LIST, TYPE) \ + LINPHONE_NAMESPACE::Wrapper::getCppListOfCppObjFromCListOfStructPtr(LIST) #endif // ifndef _C_TOOLS_H_ diff --git a/src/call/call-listener.h b/src/call/call-listener.h index 20e436b45..02c9f05dd 100644 --- a/src/call/call-listener.h +++ b/src/call/call-listener.h @@ -27,6 +27,8 @@ LINPHONE_BEGIN_NAMESPACE class CallListener { public: + virtual ~CallListener() = default; + virtual void onAckBeingSent (LinphoneHeaders *headers) = 0; virtual void onAckReceived (LinphoneHeaders *headers) = 0; virtual void onCallSetReleased () = 0; diff --git a/src/chat/basic-chat-room.cpp b/src/chat/basic-chat-room.cpp index e4768c988..d59554da5 100644 --- a/src/chat/basic-chat-room.cpp +++ b/src/chat/basic-chat-room.cpp @@ -25,7 +25,9 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -BasicChatRoomPrivate::BasicChatRoomPrivate (LinphoneCore *core, const Address &peerAddress) : ChatRoomPrivate(core, peerAddress) {} +BasicChatRoomPrivate::BasicChatRoomPrivate (LinphoneCore *core, const Address &peerAddress) : ChatRoomPrivate(core) { + this->peerAddress = peerAddress; +} // ============================================================================= diff --git a/src/chat/chat-room-p.h b/src/chat/chat-room-p.h index 2e6f88bb0..84b4b10d6 100644 --- a/src/chat/chat-room-p.h +++ b/src/chat/chat-room-p.h @@ -33,7 +33,7 @@ LINPHONE_BEGIN_NAMESPACE class ChatRoomPrivate : public ObjectPrivate, public IsComposingListener { public: - ChatRoomPrivate (LinphoneCore *core, const Address &peerAddress); + ChatRoomPrivate (LinphoneCore *core); virtual ~ChatRoomPrivate (); private: diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index cb6b3ff24..f984adf59 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -34,8 +34,8 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ChatRoomPrivate::ChatRoomPrivate (LinphoneCore *core, const Address &peerAddress) - : core(core), peerAddress(peerAddress), isComposingHandler(core, this) {} +ChatRoomPrivate::ChatRoomPrivate (LinphoneCore *core) + : core(core), isComposingHandler(core, this) {} ChatRoomPrivate::~ChatRoomPrivate () { for (auto it = transientMessages.begin(); it != transientMessages.end(); it++) { @@ -538,7 +538,7 @@ void ChatRoomPrivate::onIsComposingRefreshNeeded () { // ============================================================================= -ChatRoom::ChatRoom (LinphoneCore *core, const Address &peerAddress) : Object(*new ChatRoomPrivate(core, peerAddress)) {} +ChatRoom::ChatRoom (LinphoneCore *core) : Object(*new ChatRoomPrivate(core)) {} ChatRoom::ChatRoom (ChatRoomPrivate &p) : Object(p) {} diff --git a/src/chat/chat-room.h b/src/chat/chat-room.h index d5663d416..e2c34047f 100644 --- a/src/chat/chat-room.h +++ b/src/chat/chat-room.h @@ -38,7 +38,7 @@ class ChatRoomPrivate; class ChatRoom : public Object, public ConferenceInterface { public: - ChatRoom (LinphoneCore *core, const Address &peerAddress); + ChatRoom (LinphoneCore *core); virtual ~ChatRoom () = default; void compose (); diff --git a/src/chat/client-group-chat-room-p.h b/src/chat/client-group-chat-room-p.h index 3e6fe2d1f..346faf869 100644 --- a/src/chat/client-group-chat-room-p.h +++ b/src/chat/client-group-chat-room-p.h @@ -31,7 +31,7 @@ LINPHONE_BEGIN_NAMESPACE class ClientGroupChatRoomPrivate : public ChatRoomPrivate { public: - ClientGroupChatRoomPrivate (LinphoneCore *core, const Address &peerAddress); + ClientGroupChatRoomPrivate (LinphoneCore *core); virtual ~ClientGroupChatRoomPrivate () = default; private: diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 9f607a71a..82550087a 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -17,14 +17,55 @@ */ #include "client-group-chat-room-p.h" +#include "conference/participant-p.h" #include "logger/logger.h" -// ============================================================================= - using namespace std; LINPHONE_BEGIN_NAMESPACE -ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core, const Address &peerAddress) : ChatRoomPrivate(core, peerAddress) {} +// ============================================================================= + +ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core) : ChatRoomPrivate(core) {} + +// ============================================================================= + +ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, std::list
&addresses) + : ChatRoom(*new ChatRoomPrivate(core)), RemoteConference(core, me, nullptr) { + // TODO +} + +// ----------------------------------------------------------------------------- + +shared_ptr ClientGroupChatRoom::addParticipant (const Address &addr, const shared_ptr params, bool hasMedia) { + activeParticipant = make_shared(addr); + activeParticipant->getPrivate()->createSession(*this, params, hasMedia, this); + return activeParticipant; +} + +void ClientGroupChatRoom::addParticipants (const list
&addresses, const shared_ptr params, bool hasMedia) { + // TODO +} + +const string& ClientGroupChatRoom::getId () const { + return id; +} + +int ClientGroupChatRoom::getNbParticipants () const { + // TODO + return 1; +} + +list> ClientGroupChatRoom::getParticipants () const { + return participants; +} + +void ClientGroupChatRoom::removeParticipant (const shared_ptr participant) { + // TODO +} + +void ClientGroupChatRoom::removeParticipants (const list> participants) { + // TODO +} LINPHONE_END_NAMESPACE diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index 6c70ab363..f19a07326 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -23,6 +23,7 @@ #include "private.h" #include "chat/chat-room.h" +#include "conference/remote-conference.h" #include "linphone/types.h" @@ -32,11 +33,12 @@ LINPHONE_BEGIN_NAMESPACE class ClientGroupChatRoomPrivate; -class ClientGroupChatRoom : public ChatRoom { +class ClientGroupChatRoom : public ChatRoom, public RemoteConference { public: - ClientGroupChatRoom (LinphoneCore *core, const Address &peerAddress); + ClientGroupChatRoom (LinphoneCore *core, const Address &me, std::list
&addresses); virtual ~ClientGroupChatRoom () = default; +public: /* ConferenceInterface */ std::shared_ptr addParticipant (const Address &addr, const std::shared_ptr params, bool hasMedia); void addParticipants (const std::list
&addresses, const std::shared_ptr params, bool hasMedia); @@ -44,7 +46,7 @@ public: int getNbParticipants () const; std::list> getParticipants () const; void removeParticipant (const std::shared_ptr participant); - void removeParticipants (const std::list> participants); + void removeParticipants (const std::list> participants); private: L_DECLARE_PRIVATE(ClientGroupChatRoom); diff --git a/src/chat/is-composing-listener.h b/src/chat/is-composing-listener.h index 9d8c2a40b..66bd50c4d 100644 --- a/src/chat/is-composing-listener.h +++ b/src/chat/is-composing-listener.h @@ -27,6 +27,8 @@ LINPHONE_BEGIN_NAMESPACE class IsComposingListener { public: + virtual ~IsComposingListener() = default; + virtual void onIsComposingStateChanged (bool isComposing) = 0; virtual void onIsRemoteComposingStateChanged (bool isComposing) = 0; virtual void onIsComposingRefreshNeeded () = 0; diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 680e5d05c..4933b1874 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -30,7 +30,9 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE RealTimeTextChatRoomPrivate::RealTimeTextChatRoomPrivate (LinphoneCore *core, const Address &peerAddress) - : ChatRoomPrivate(core, peerAddress) {} + : ChatRoomPrivate(core) { + this->peerAddress = peerAddress; +} RealTimeTextChatRoomPrivate::~RealTimeTextChatRoomPrivate () { if (!receivedRttCharacters.empty()) { diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index 6c0090e05..85e22ff67 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -32,6 +32,8 @@ LINPHONE_BEGIN_NAMESPACE class ConferenceInterface { public: + virtual ~ConferenceInterface() = default; + virtual std::shared_ptr addParticipant (const Address &addr, const std::shared_ptr params, bool hasMedia) = 0; virtual void addParticipants (const std::list
&addresses, const std::shared_ptr params, bool hasMedia) = 0; virtual const std::string& getId () const = 0; diff --git a/src/conference/conference-p.h b/src/conference/conference-p.h deleted file mode 100644 index 70dc0658c..000000000 --- a/src/conference/conference-p.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * conference-p.h - * Copyright (C) 2017 Belledonne Communications SARL - * - * 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, see . - */ - -#ifndef _CONFERENCE_P_H_ -#define _CONFERENCE_P_H_ - -#include - -#include "object/object-p.h" - -#include "conference/conference.h" -#include "conference/participant.h" -#include "conference/session/call-session-listener.h" - -// ============================================================================= - -LINPHONE_BEGIN_NAMESPACE - -class ConferencePrivate : public ObjectPrivate, CallSessionListener { -public: - virtual ~ConferencePrivate () = default; - - LinphoneCore * getCore () const { return core; } - -private: - /* CallSessionListener */ - virtual void onAckBeingSent (const CallSession &session, LinphoneHeaders *headers); - virtual void onAckReceived (const CallSession &session, LinphoneHeaders *headers); - virtual void onCallSessionAccepted (const CallSession &session); - virtual void onCallSessionSetReleased (const CallSession &session); - virtual void onCallSessionSetTerminated (const CallSession &session); - virtual void onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message); - virtual void onIncomingCallSessionStarted (const CallSession &session); - virtual void onEncryptionChanged (const CallSession &session, bool activated, const std::string &authToken); - virtual void onStatsUpdated (const LinphoneCallStats *stats); - virtual void onResetCurrentSession (const CallSession &session); - virtual void onSetCurrentSession (const CallSession &session); - virtual void onFirstVideoFrameDecoded (const CallSession &session); - virtual void onResetFirstVideoFrameDecoded (const CallSession &session); - -private: - LinphoneCore *core = nullptr; - CallListener *callListener = nullptr; - - std::shared_ptr activeParticipant = nullptr; - std::string id; - std::shared_ptr me = nullptr; - std::list> participants; - - L_DECLARE_PUBLIC(Conference); -}; - -LINPHONE_END_NAMESPACE - -#endif // ifndef _CONFERENCE_P_H_ diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 856a6e587..989713577 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -16,7 +16,6 @@ * along with this program. If not, see . */ -#include "conference-p.h" #include "participant-p.h" #include "conference.h" @@ -27,86 +26,23 @@ LINPHONE_BEGIN_NAMESPACE // ============================================================================= -void ConferencePrivate::onAckBeingSent (const CallSession &session, LinphoneHeaders *headers) { - if (callListener) - callListener->onAckBeingSent(headers); +Conference::Conference (LinphoneCore *core, const Address &myAddress, CallListener *listener) + : core(core), callListener(listener) { + me = make_shared(myAddress); } -void ConferencePrivate::onAckReceived (const CallSession &session, LinphoneHeaders *headers) { - if (callListener) - callListener->onAckReceived(headers); +// ----------------------------------------------------------------------------- + +shared_ptr Conference::getActiveParticipant () const { + return activeParticipant; } -void ConferencePrivate::onCallSessionAccepted (const CallSession &session) { - if (callListener) - callListener->onIncomingCallToBeAdded(); -} - -void ConferencePrivate::onCallSessionSetReleased (const CallSession &session) { - if (callListener) - callListener->onCallSetReleased(); -} - -void ConferencePrivate::onCallSessionSetTerminated (const CallSession &session) { - if (callListener) - callListener->onCallSetTerminated(); -} - -void ConferencePrivate::onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const string &message) { - if (callListener) - callListener->onCallStateChanged(state, message); -} - -void ConferencePrivate::onIncomingCallSessionStarted (const CallSession &session) { - if (callListener) - callListener->onIncomingCallStarted(); -} - -void ConferencePrivate::onEncryptionChanged (const CallSession &session, bool activated, const string &authToken) { - if (callListener) - callListener->onEncryptionChanged(activated, authToken); -} - -void ConferencePrivate::onStatsUpdated (const LinphoneCallStats *stats) { - if (callListener) - callListener->onStatsUpdated(stats); -} - -void ConferencePrivate::onResetCurrentSession (const CallSession &session) { - if (callListener) - callListener->onResetCurrentCall(); -} - -void ConferencePrivate::onSetCurrentSession (const CallSession &session) { - if (callListener) - callListener->onSetCurrentCall(); -} - -void ConferencePrivate::onFirstVideoFrameDecoded (const CallSession &session) { - if (callListener) - callListener->onFirstVideoFrameDecoded(); -} - -void ConferencePrivate::onResetFirstVideoFrameDecoded (const CallSession &session) { - if (callListener) - callListener->onResetFirstVideoFrameDecoded(); -} - -// ============================================================================= - -Conference::Conference (ConferencePrivate &p, LinphoneCore *core, const Address &myAddress, CallListener *listener) - : Object(p) { - L_D(Conference); - d->core = core; - d->callListener = listener; - d->me = make_shared(myAddress); -} +// ----------------------------------------------------------------------------- shared_ptr Conference::addParticipant (const Address &addr, const shared_ptr params, bool hasMedia) { - L_D(Conference); - d->activeParticipant = make_shared(addr); - d->activeParticipant->getPrivate()->createSession(*this, params, hasMedia, d); - return d->activeParticipant; + activeParticipant = make_shared(addr); + activeParticipant->getPrivate()->createSession(*this, params, hasMedia, this); + return activeParticipant; } void Conference::addParticipants (const list
&addresses, const shared_ptr params, bool hasMedia) { @@ -114,8 +50,7 @@ void Conference::addParticipants (const list
&addresses, const shared_p } const string& Conference::getId () const { - L_D(const Conference); - return d->id; + return id; } int Conference::getNbParticipants () const { @@ -124,8 +59,7 @@ int Conference::getNbParticipants () const { } list> Conference::getParticipants () const { - L_D(const Conference); - return d->participants; + return participants; } void Conference::removeParticipant (const shared_ptr participant) { @@ -136,14 +70,71 @@ void Conference::removeParticipants (const list> partici // TODO } -shared_ptr Conference::getActiveParticipant () const { - L_D(const Conference); - return d->activeParticipant; +// ----------------------------------------------------------------------------- + +void Conference::onAckBeingSent (const CallSession &session, LinphoneHeaders *headers) { + if (callListener) + callListener->onAckBeingSent(headers); } -shared_ptr Conference::getMe () const { - L_D(const Conference); - return d->me; +void Conference::onAckReceived (const CallSession &session, LinphoneHeaders *headers) { + if (callListener) + callListener->onAckReceived(headers); +} + +void Conference::onCallSessionAccepted (const CallSession &session) { + if (callListener) + callListener->onIncomingCallToBeAdded(); +} + +void Conference::onCallSessionSetReleased (const CallSession &session) { + if (callListener) + callListener->onCallSetReleased(); +} + +void Conference::onCallSessionSetTerminated (const CallSession &session) { + if (callListener) + callListener->onCallSetTerminated(); +} + +void Conference::onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const string &message) { + if (callListener) + callListener->onCallStateChanged(state, message); +} + +void Conference::onIncomingCallSessionStarted (const CallSession &session) { + if (callListener) + callListener->onIncomingCallStarted(); +} + +void Conference::onEncryptionChanged (const CallSession &session, bool activated, const string &authToken) { + if (callListener) + callListener->onEncryptionChanged(activated, authToken); +} + +void Conference::onStatsUpdated (const LinphoneCallStats *stats) { + if (callListener) + callListener->onStatsUpdated(stats); +} + +void Conference::onResetCurrentSession (const CallSession &session) { + if (callListener) + callListener->onResetCurrentCall(); +} + +void Conference::onSetCurrentSession (const CallSession &session) { + if (callListener) + callListener->onSetCurrentCall(); +} + +void Conference::onFirstVideoFrameDecoded (const CallSession &session) { + if (callListener) + callListener->onFirstVideoFrameDecoded(); +} + +void Conference::onResetFirstVideoFrameDecoded (const CallSession &session) { + if (callListener) + callListener->onResetFirstVideoFrameDecoded(); } LINPHONE_END_NAMESPACE diff --git a/src/conference/conference.h b/src/conference/conference.h index c5c9619b7..fc027da6d 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -27,6 +27,7 @@ #include "conference/conference-interface.h" #include "conference/params/call-session-params.h" #include "conference/participant.h" +#include "conference/session/call-session-listener.h" #include "linphone/types.h" @@ -34,16 +35,20 @@ LINPHONE_BEGIN_NAMESPACE -class ConferencePrivate; class CallSessionPrivate; -class Conference : public Object, public ConferenceInterface { +class Conference : public ConferenceInterface, public CallSessionListener { friend class CallSessionPrivate; public: - std::shared_ptr getActiveParticipant () const; - std::shared_ptr getMe () const; + virtual ~Conference() = default; + std::shared_ptr getActiveParticipant () const; + std::shared_ptr getMe () const { return me; } + + LinphoneCore * getCore () const { return core; } + +public: /* ConferenceInterface */ virtual std::shared_ptr addParticipant (const Address &addr, const std::shared_ptr params, bool hasMedia); virtual void addParticipants (const std::list
&addresses, const std::shared_ptr params, bool hasMedia); @@ -53,11 +58,35 @@ public: virtual void removeParticipant (const std::shared_ptr participant); virtual void removeParticipants (const std::list> participants); +private: + /* CallSessionListener */ + virtual void onAckBeingSent (const CallSession &session, LinphoneHeaders *headers); + virtual void onAckReceived (const CallSession &session, LinphoneHeaders *headers); + virtual void onCallSessionAccepted (const CallSession &session); + virtual void onCallSessionSetReleased (const CallSession &session); + virtual void onCallSessionSetTerminated (const CallSession &session); + virtual void onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message); + virtual void onIncomingCallSessionStarted (const CallSession &session); + virtual void onEncryptionChanged (const CallSession &session, bool activated, const std::string &authToken); + virtual void onStatsUpdated (const LinphoneCallStats *stats); + virtual void onResetCurrentSession (const CallSession &session); + virtual void onSetCurrentSession (const CallSession &session); + virtual void onFirstVideoFrameDecoded (const CallSession &session); + virtual void onResetFirstVideoFrameDecoded (const CallSession &session); + protected: - explicit Conference (ConferencePrivate &p, LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); + explicit Conference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); + +protected: + LinphoneCore *core = nullptr; + CallListener *callListener = nullptr; + + std::shared_ptr activeParticipant = nullptr; + std::string id; + std::shared_ptr me = nullptr; + std::list> participants; private: - L_DECLARE_PRIVATE(Conference); L_DISABLE_COPY(Conference); }; diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index acb5a432c..a8be2c11c 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -16,21 +16,13 @@ * along with this program. If not, see . */ -#include "conference-p.h" - #include "local-conference.h" LINPHONE_BEGIN_NAMESPACE // ============================================================================= -class LocalConferencePrivate : public ConferencePrivate { -public: -}; - -// ============================================================================= - LocalConference::LocalConference (LinphoneCore *core, const Address &myAddress, CallListener *listener) - : Conference(*new LocalConferencePrivate, core, myAddress, listener) {} + : Conference(core, myAddress, listener) {} LINPHONE_END_NAMESPACE diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h index 5a2b3bbe9..8b29b3752 100644 --- a/src/conference/local-conference.h +++ b/src/conference/local-conference.h @@ -25,14 +25,11 @@ LINPHONE_BEGIN_NAMESPACE -class LocalConferencePrivate; - class LocalConference : public Conference { public: LocalConference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); private: - L_DECLARE_PRIVATE(LocalConference); L_DISABLE_COPY(LocalConference); }; diff --git a/src/conference/participant.h b/src/conference/participant.h index bccb4f37b..de205ee77 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -28,11 +28,13 @@ LINPHONE_BEGIN_NAMESPACE +class ClientGroupChatRoom; class ParticipantPrivate; class Participant : public Object { friend class Call; friend class CallPrivate; + friend class ClientGroupChatRoom; friend class Conference; friend class MediaSessionPrivate; diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index 21fcbb3cb..537b79acc 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -16,21 +16,13 @@ * along with this program. If not, see . */ -#include "conference-p.h" - #include "remote-conference.h" LINPHONE_BEGIN_NAMESPACE // ============================================================================= -class RemoteConferencePrivate : public ConferencePrivate { -public: -}; - -// ============================================================================= - RemoteConference::RemoteConference (LinphoneCore *core, const Address &myAddress, CallListener *listener) - : Conference(*new RemoteConferencePrivate, core, myAddress, listener) {} + : Conference(core, myAddress, listener) {} LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index 699c1b9c6..40d9cc387 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -25,14 +25,12 @@ LINPHONE_BEGIN_NAMESPACE -class RemoteConferencePrivate; - class RemoteConference : public Conference { public: RemoteConference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); + virtual ~RemoteConference() = default; private: - L_DECLARE_PRIVATE(RemoteConference); L_DISABLE_COPY(RemoteConference); }; diff --git a/src/conference/session/call-session-listener.h b/src/conference/session/call-session-listener.h index 29f574559..228820a29 100644 --- a/src/conference/session/call-session-listener.h +++ b/src/conference/session/call-session-listener.h @@ -25,6 +25,8 @@ LINPHONE_BEGIN_NAMESPACE class CallSessionListener { public: + virtual ~CallSessionListener() = default; + virtual void onAckBeingSent (const CallSession &session, LinphoneHeaders *headers) = 0; virtual void onAckReceived (const CallSession &session, LinphoneHeaders *headers) = 0; virtual void onCallSessionAccepted (const CallSession &session) = 0; diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index ef902e8eb..595fc2c70 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -23,7 +23,6 @@ #include "address/address-p.h" #include "conference/session/call-session-p.h" #include "call/call-p.h" -#include "conference/conference-p.h" #include "conference/params/call-session-params-p.h" #include "conference/session/call-session.h" @@ -45,7 +44,7 @@ CallSessionPrivate::CallSessionPrivate (const Conference &conference, const shar if (params) this->params = make_shared(*params.get()); currentParams = make_shared(); - core = conference.getPrivate()->getCore(); + core = conference.getCore(); ei = linphone_error_info_new(); } From 4a13ac6a7a37b45c4c2feea437ed9d8fd01689e9 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 13 Sep 2017 17:38:28 +0200 Subject: [PATCH 0048/2215] Use real pointer for C++ object inside LinphoneCallParams as it is a ClonableObject. --- coreapi/CMakeLists.txt | 1 - coreapi/call_log.c | 4 +- coreapi/chat.c | 17 +- coreapi/linphonecall.c | 33 +-- coreapi/linphonecore.c | 14 +- coreapi/proxy.c | 6 +- include/linphone/call_log.h | 4 +- include/linphone/core.h | 6 +- src/CMakeLists.txt | 2 +- src/c-wrapper/api/c-address.cpp | 2 +- .../c-wrapper/api/c-call-params.cpp | 226 ++++++++---------- src/c-wrapper/c-private-types.h | 46 ---- src/c-wrapper/c-tools.h | 42 ++-- src/call/call-p.h | 2 +- src/call/call.cpp | 18 +- src/call/call.h | 18 +- src/chat/basic-chat-room.cpp | 4 +- src/chat/basic-chat-room.h | 4 +- src/chat/chat-room.cpp | 2 +- src/chat/client-group-chat-room.cpp | 11 +- src/chat/client-group-chat-room.h | 4 +- src/chat/real-time-text-chat-room.cpp | 4 +- src/chat/real-time-text-chat-room.h | 4 +- src/conference/conference-interface.h | 4 +- src/conference/conference.cpp | 4 +- src/conference/conference.h | 4 +- src/conference/local-conference.h | 1 + .../params/media-session-params-p.h | 1 - src/conference/participant-p.h | 2 +- src/conference/participant.cpp | 5 +- src/conference/remote-conference.h | 3 + src/conference/session/call-session-p.h | 12 +- src/conference/session/call-session.cpp | 44 ++-- src/conference/session/call-session.h | 14 +- src/conference/session/media-session-p.h | 12 +- src/conference/session/media-session.cpp | 74 +++--- src/conference/session/media-session.h | 20 +- 37 files changed, 335 insertions(+), 339 deletions(-) rename coreapi/call_params.c => src/c-wrapper/api/c-call-params.cpp (68%) delete mode 100644 src/c-wrapper/c-private-types.h diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index a22bfc5ed..532f74bef 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -70,7 +70,6 @@ set(LINPHONE_SOURCE_FILES_C buffer.c callbacks.c call_log.c - call_params.c carddav.c chat.c chat_file_transfer.c diff --git a/coreapi/call_log.c b/coreapi/call_log.c index 47e689b1a..54088adc4 100644 --- a/coreapi/call_log.c +++ b/coreapi/call_log.c @@ -179,7 +179,7 @@ int linphone_call_log_get_duration(LinphoneCallLog *cl){ return cl->duration; } -LinphoneAddress *linphone_call_log_get_from_address(LinphoneCallLog *cl){ +const LinphoneAddress *linphone_call_log_get_from_address(LinphoneCallLog *cl){ return cl->from; } @@ -211,7 +211,7 @@ LinphoneCallStatus linphone_call_log_get_status(LinphoneCallLog *cl){ return cl->status; } -LinphoneAddress *linphone_call_log_get_to_address(LinphoneCallLog *cl){ +const LinphoneAddress *linphone_call_log_get_to_address(LinphoneCallLog *cl){ return cl->to; } diff --git a/coreapi/chat.c b/coreapi/chat.c index aa35495ef..9aa35ed7e 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -191,9 +191,9 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneChatRoom, belle_sip_object_t, LinphoneChatRoom *_linphone_core_create_chat_room_base(LinphoneCore *lc, const LinphoneAddress *addr) { LinphoneChatRoom *cr = belle_sip_object_new(LinphoneChatRoom); if (linphone_core_realtime_text_enabled(lc)) - cr->cr = new LinphonePrivate::RealTimeTextChatRoom(lc, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address)); + cr->cr = new LinphonePrivate::RealTimeTextChatRoom(lc, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address, Address)); else - cr->cr = new LinphonePrivate::BasicChatRoom(lc, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address)); + cr->cr = new LinphonePrivate::BasicChatRoom(lc, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address, Address)); L_GET_PRIVATE(cr->cr)->setCBackPointer(cr); return cr; } @@ -257,9 +257,20 @@ LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAd } LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, bctbx_list_t *addresses) { + const char *factoryUri = linphone_core_get_chat_conference_factory_uri(lc); + if (!factoryUri) + return nullptr; LinphoneChatRoom *cr = belle_sip_object_new(LinphoneChatRoom); + LinphoneAddress *factoryAddr = linphone_address_new(factoryUri); + LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(lc, factoryAddr); + linphone_address_unref(factoryAddr); + std::string from; + if (proxy) + from = L_GET_CPP_PTR_FROM_C_STRUCT(linphone_proxy_config_get_identity_address(proxy), Address, Address)->asString(); + if (from.empty()) + from = linphone_core_get_primary_contact(lc); + LinphonePrivate::Address me(from); std::list l = L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(addresses, Address); - LinphonePrivate::Address me; // TODO cr->cr = new LinphonePrivate::ClientGroupChatRoom(lc, me, l); L_GET_PRIVATE(cr->cr)->setCBackPointer(cr); return cr; diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 3acfd9607..516dd216c 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -45,7 +45,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // For migration purpose. #include "address/address-p.h" -#include "c-wrapper/c-private-types.h" #include "c-wrapper/c-tools.h" #include "call/call.h" #include "call/call-p.h" @@ -289,7 +288,9 @@ LinphoneCall * linphone_call_new_outgoing(LinphoneCore *lc, const LinphoneAddres call->paramsCache = linphone_call_params_new_for_wrapper(); call->remoteParamsCache = linphone_call_params_new_for_wrapper(); call->remoteAddressCache = linphone_address_new(nullptr); - call->call = std::make_shared(call, lc, LinphoneCallOutgoing, *L_GET_CPP_PTR_FROM_C_STRUCT(from, Address), *L_GET_CPP_PTR_FROM_C_STRUCT(to, Address), cfg, nullptr, linphone_call_params_get_cpp_obj(params)); + call->call = std::make_shared(call, lc, LinphoneCallOutgoing, + *L_GET_CPP_PTR_FROM_C_STRUCT(from, Address, Address), *L_GET_CPP_PTR_FROM_C_STRUCT(to, Address, Address), + cfg, nullptr, L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams, CallParams)); return call; } @@ -299,7 +300,9 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, const LinphoneAddres call->paramsCache = linphone_call_params_new_for_wrapper(); call->remoteParamsCache = linphone_call_params_new_for_wrapper(); call->remoteAddressCache = linphone_address_new(nullptr); - call->call = std::make_shared(call, lc, LinphoneCallIncoming, *L_GET_CPP_PTR_FROM_C_STRUCT(from, Address), *L_GET_CPP_PTR_FROM_C_STRUCT(to, Address), nullptr, op, nullptr); + call->call = std::make_shared(call, lc, LinphoneCallIncoming, + *L_GET_CPP_PTR_FROM_C_STRUCT(from, Address, Address), *L_GET_CPP_PTR_FROM_C_STRUCT(to, Address, Address), + nullptr, op, nullptr); L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->initiateIncoming(); return call; } @@ -453,20 +456,20 @@ void linphone_call_unref(LinphoneCall *obj){ } const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){ - call->currentParamsCache->msp = linphone_call_get_cpp_obj(call)->getCurrentParams(); + L_SET_CPP_PTR_FROM_C_STRUCT(call->currentParamsCache, linphone_call_get_cpp_obj(call)->getCurrentParams()); return call->currentParamsCache; } const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call) { - call->remoteParamsCache->msp = linphone_call_get_cpp_obj(call)->getRemoteParams(); - if (call->remoteParamsCache->msp) - return call->remoteParamsCache; - return nullptr; + const LinphonePrivate::MediaSessionParams *remoteParams = linphone_call_get_cpp_obj(call)->getRemoteParams(); + if (!remoteParams) + return nullptr; + L_SET_CPP_PTR_FROM_C_STRUCT(call->remoteParamsCache, remoteParams); + return call->remoteParamsCache; } const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call) { - std::shared_ptr addr = std::make_shared(linphone_call_get_cpp_obj(call)->getRemoteAddress()); - L_SET_CPP_PTR_FROM_C_STRUCT(call->remoteAddressCache, addr); + L_SET_CPP_PTR_FROM_C_STRUCT(call->remoteAddressCache, &linphone_call_get_cpp_obj(call)->getRemoteAddress()); return call->remoteAddressCache; } @@ -1071,7 +1074,7 @@ void _linphone_call_set_new_params(LinphoneCall *call, const LinphoneCallParams } const LinphoneCallParams * linphone_call_get_params(LinphoneCall *call) { - call->paramsCache->msp = linphone_call_get_cpp_obj(call)->getParams(); + L_SET_CPP_PTR_FROM_C_STRUCT(call->paramsCache, linphone_call_get_cpp_obj(call)->getParams()); return call->paramsCache; } @@ -1281,7 +1284,7 @@ LinphoneStatus linphone_call_accept(LinphoneCall *call) { } LinphoneStatus linphone_call_accept_with_params(LinphoneCall *call, const LinphoneCallParams *params) { - return linphone_call_get_cpp_obj(call)->accept(params ? linphone_call_params_get_cpp_obj(params) : nullptr); + return linphone_call_get_cpp_obj(call)->accept(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams, CallParams) : nullptr); } LinphoneStatus linphone_call_accept_early_media(LinphoneCall* call) { @@ -1289,11 +1292,11 @@ LinphoneStatus linphone_call_accept_early_media(LinphoneCall* call) { } LinphoneStatus linphone_call_accept_early_media_with_params(LinphoneCall *call, const LinphoneCallParams *params) { - return linphone_call_get_cpp_obj(call)->acceptEarlyMedia(params ? linphone_call_params_get_cpp_obj(params) : nullptr); + return linphone_call_get_cpp_obj(call)->acceptEarlyMedia(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams, CallParams) : nullptr); } LinphoneStatus linphone_call_update(LinphoneCall *call, const LinphoneCallParams *params) { - return linphone_call_get_cpp_obj(call)->update(params ? linphone_call_params_get_cpp_obj(params) : nullptr); + return linphone_call_get_cpp_obj(call)->update(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams, CallParams) : nullptr); } int linphone_call_start_update(LinphoneCall *call) { @@ -1324,7 +1327,7 @@ int linphone_call_start_accept_update(LinphoneCall *call, LinphoneCallState next } LinphoneStatus linphone_call_accept_update(LinphoneCall *call, const LinphoneCallParams *params) { - return linphone_call_get_cpp_obj(call)->acceptUpdate(params ? linphone_call_params_get_cpp_obj(params) : nullptr); + return linphone_call_get_cpp_obj(call)->acceptUpdate(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams, CallParams) : nullptr); } LinphoneStatus linphone_call_transfer(LinphoneCall *call, const char *refer_to) { diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ebc57dd9b..8e4416df4 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3359,7 +3359,7 @@ static bctbx_list_t *make_routes_for_proxy(LinphoneProxyConfig *proxy, const Lin ret=bctbx_list_append(ret,sal_address_new(local_route)); } if (srv_route){ - ret=bctbx_list_append(ret,sal_address_clone(L_GET_PRIVATE_FROM_C_STRUCT(srv_route, Address)->getInternalAddress())); + ret=bctbx_list_append(ret,sal_address_clone(L_GET_PRIVATE_FROM_C_STRUCT(srv_route, Address, Address)->getInternalAddress())); } if (ret==NULL){ /*if the proxy address matches the domain part of the destination, then use the same transport @@ -5918,7 +5918,7 @@ void friends_config_uninit(LinphoneCore* lc) ms_message("Destroying friends done."); } -LpConfig * linphone_core_get_config(LinphoneCore *lc){ +LpConfig * linphone_core_get_config(const LinphoneCore *lc){ return lc->config; } @@ -6671,7 +6671,7 @@ void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m) { } void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params) { - linphone_call_params_get_cpp_obj(params)->initDefault(lc); + L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams, CallParams)->initDefault(lc); } void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) { @@ -7085,6 +7085,14 @@ LinphoneConference *linphone_core_get_conference(LinphoneCore *lc) { return lc->conf_ctx; } +void linphone_core_set_chat_conference_factory_uri(LinphoneCore *lc, const char *uri) { + lp_config_set_string(linphone_core_get_config(lc), "misc", "chat_conference_factory_uri", uri); +} + +const char * linphone_core_get_chat_conference_factory_uri(const LinphoneCore *lc) { + return lp_config_get_string(linphone_core_get_config(lc), "misc", "chat_conference_factory_uri", nullptr); +} + void linphone_core_set_tls_cert(LinphoneCore *lc, const char *tls_cert) { if (lc->tls_cert) { ms_free(lc->tls_cert); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index e5a4e03b1..e3f3ce9cd 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -500,7 +500,7 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *cfg){ linphone_configure_op(cfg->lc, cfg->op, cfg->identity_address, cfg->sent_headers, FALSE); if ((contact=guess_contact_for_register(cfg))) { - sal_op_set_contact_address(cfg->op, L_GET_PRIVATE_FROM_C_STRUCT(contact, Address)->getInternalAddress()); + sal_op_set_contact_address(cfg->op, L_GET_PRIVATE_FROM_C_STRUCT(contact, Address, Address)->getInternalAddress()); linphone_address_unref(contact); } @@ -511,7 +511,7 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *cfg){ proxy_string, cfg->reg_identity, cfg->expires, - cfg->pending_contact ? L_GET_PRIVATE_FROM_C_STRUCT(cfg->pending_contact, Address)->getInternalAddress() : NULL + cfg->pending_contact ? L_GET_PRIVATE_FROM_C_STRUCT(cfg->pending_contact, Address, Address)->getInternalAddress() : NULL )==0) { if (cfg->pending_contact) { linphone_address_unref(cfg->pending_contact); @@ -1393,7 +1393,7 @@ const char* linphone_proxy_config_get_transport(const LinphoneProxyConfig *cfg) bool_t destroy_route_addr = FALSE; if (linphone_proxy_config_get_service_route(cfg)) { - route_addr = L_GET_PRIVATE_FROM_C_STRUCT(linphone_proxy_config_get_service_route(cfg), Address)->getInternalAddress(); + route_addr = L_GET_PRIVATE_FROM_C_STRUCT(linphone_proxy_config_get_service_route(cfg), Address, Address)->getInternalAddress(); } else if (linphone_proxy_config_get_route(cfg)) { addr=linphone_proxy_config_get_route(cfg); } else if(linphone_proxy_config_get_addr(cfg)) { diff --git a/include/linphone/call_log.h b/include/linphone/call_log.h index 4320cb72b..fb5e743e1 100644 --- a/include/linphone/call_log.h +++ b/include/linphone/call_log.h @@ -62,7 +62,7 @@ LINPHONE_PUBLIC int linphone_call_log_get_duration(LinphoneCallLog *cl); * @param[in] cl LinphoneCallLog object * @return The origin address (ie from) of the call. **/ -LINPHONE_PUBLIC LinphoneAddress * linphone_call_log_get_from_address(LinphoneCallLog *cl); +LINPHONE_PUBLIC const LinphoneAddress * linphone_call_log_get_from_address(LinphoneCallLog *cl); /** * Get the RTP statistics computed locally regarding the call. @@ -123,7 +123,7 @@ LINPHONE_PUBLIC LinphoneCallStatus linphone_call_log_get_status(LinphoneCallLog * @param[in] cl LinphoneCallLog object * @return The destination address (ie to) of the call. **/ -LINPHONE_PUBLIC LinphoneAddress * linphone_call_log_get_to_address(LinphoneCallLog *cl); +LINPHONE_PUBLIC const LinphoneAddress * linphone_call_log_get_to_address(LinphoneCallLog *cl); /** * Associate a persistent reference key to the call log. diff --git a/include/linphone/core.h b/include/linphone/core.h index 9033527a7..e34b45f9c 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -3908,7 +3908,7 @@ LINPHONE_PUBLIC void linphone_core_set_user_data(LinphoneCore *lc, void *userdat * sections and pairs of key=value in the configuration file. * @ingroup misc **/ -LINPHONE_PUBLIC LinphoneConfig * linphone_core_get_config(LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneConfig * linphone_core_get_config(const LinphoneCore *lc); /** * Create a LpConfig object from a user config file. @@ -4187,6 +4187,10 @@ LINPHONE_PUBLIC LinphoneStatus linphone_core_stop_conference_recording(LinphoneC */ LINPHONE_PUBLIC LinphoneConference *linphone_core_get_conference(LinphoneCore *lc); +void linphone_core_set_chat_conference_factory_uri(LinphoneCore *lc, const char *uri); + +const char * linphone_core_get_chat_conference_factory_uri(const LinphoneCore *lc); + /** * @} */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 248535880..773f308f8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,7 +23,6 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES address/address-p.h address/address.h - c-wrapper/c-private-types.h c-wrapper/c-tools.h call/call-listener.h call/call-p.h @@ -98,6 +97,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES set(LINPHONE_CXX_OBJECTS_SOURCE_FILES address/address.cpp c-wrapper/api/c-address.cpp + c-wrapper/api/c-call-params.cpp c-wrapper/api/c-event-log.cpp call/call.cpp chat/basic-chat-room.cpp diff --git a/src/c-wrapper/api/c-address.cpp b/src/c-wrapper/api/c-address.cpp index bd9ec8b29..80d4002db 100644 --- a/src/c-wrapper/api/c-address.cpp +++ b/src/c-wrapper/api/c-address.cpp @@ -26,7 +26,7 @@ using namespace std; -L_DECLARE_C_CLONABLE_STRUCT_IMPL(Address, address); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(Address, Address, address); LinphoneAddress *linphone_address_new (const char *address) { LINPHONE_NAMESPACE::Address *cppPtr = new LINPHONE_NAMESPACE::Address(L_C_TO_STRING(address)); diff --git a/coreapi/call_params.c b/src/c-wrapper/api/c-call-params.cpp similarity index 68% rename from coreapi/call_params.c rename to src/c-wrapper/api/c-call-params.cpp index 504cca79a..2b130b39b 100644 --- a/coreapi/call_params.c +++ b/src/c-wrapper/api/c-call-params.cpp @@ -20,14 +20,19 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/call_params.h" #include "private.h" -#include "c-wrapper/c-private-types.h" #include "c-wrapper/c-tools.h" #include "conference/params/media-session-params.h" #include "conference/params/call-session-params-p.h" #include "conference/params/media-session-params-p.h" -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneCallParams); +#define GET_CALL_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, CallSessionParams, CallParams) +#define GET_CALL_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, CallSessionParams, CallParams) +#define GET_MEDIA_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, MediaSessionParams, CallParams) +#define GET_MEDIA_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, MediaSessionParams, CallParams) + + +L_DECLARE_C_CLONABLE_STRUCT_IMPL(MediaSessionParams, CallParams, call_params) /******************************************************************************* @@ -35,7 +40,7 @@ BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneCallParams); ******************************************************************************/ SalMediaProto get_proto_from_call_params(const LinphoneCallParams *params) { - return params->msp->getMediaProto(); + return GET_MEDIA_CPP_PTR(params)->getMediaProto(); } SalStreamDir sal_dir_from_call_params_dir(LinphoneMediaDirection cpdir) { @@ -78,15 +83,15 @@ SalStreamDir get_video_dir_from_call_params(const LinphoneCallParams *params) { } void linphone_call_params_set_custom_headers(LinphoneCallParams *params, const SalCustomHeader *ch) { - L_GET_PRIVATE(static_cast(params->msp.get()))->setCustomHeaders(ch); + GET_CALL_CPP_PRIVATE_PTR(params)->setCustomHeaders(ch); } void linphone_call_params_set_custom_sdp_attributes(LinphoneCallParams *params, const SalCustomSdpAttribute *csa) { - L_GET_PRIVATE(params->msp.get())->setCustomSdpAttributes(csa); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setCustomSdpAttributes(csa); } void linphone_call_params_set_custom_sdp_media_attributes(LinphoneCallParams *params, LinphoneStreamType type, const SalCustomSdpAttribute *csa) { - L_GET_PRIVATE(params->msp.get())->setCustomSdpMediaAttributes(type, csa); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setCustomSdpMediaAttributes(type, csa); } @@ -95,23 +100,23 @@ void linphone_call_params_set_custom_sdp_media_attributes(LinphoneCallParams *pa ******************************************************************************/ void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value) { - params->msp->addCustomHeader(header_name, header_value); + GET_MEDIA_CPP_PTR(params)->addCustomHeader(header_name, header_value); } void linphone_call_params_add_custom_sdp_attribute(LinphoneCallParams *params, const char *attribute_name, const char *attribute_value) { - params->msp->addCustomSdpAttribute(attribute_name, attribute_value); + GET_MEDIA_CPP_PTR(params)->addCustomSdpAttribute(attribute_name, attribute_value); } void linphone_call_params_add_custom_sdp_media_attribute(LinphoneCallParams *params, LinphoneStreamType type, const char *attribute_name, const char *attribute_value) { - params->msp->addCustomSdpMediaAttribute(type, attribute_name, attribute_value); + GET_MEDIA_CPP_PTR(params)->addCustomSdpMediaAttribute(type, attribute_name, attribute_value); } void linphone_call_params_clear_custom_sdp_attributes(LinphoneCallParams *params) { - params->msp->clearCustomSdpAttributes(); + GET_MEDIA_CPP_PTR(params)->clearCustomSdpAttributes(); } void linphone_call_params_clear_custom_sdp_media_attributes(LinphoneCallParams *params, LinphoneStreamType type) { - params->msp->clearCustomSdpMediaAttributes(type); + GET_MEDIA_CPP_PTR(params)->clearCustomSdpMediaAttributes(type); } LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *params) { @@ -119,42 +124,42 @@ LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *params) } bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *params) { - return params->msp->earlyMediaSendingEnabled(); + return GET_MEDIA_CPP_PTR(params)->earlyMediaSendingEnabled(); } void linphone_call_params_enable_early_media_sending(LinphoneCallParams *params, bool_t enabled) { - params->msp->enableEarlyMediaSending(enabled); + GET_MEDIA_CPP_PTR(params)->enableEarlyMediaSending(enabled); } void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *params, bool_t enabled) { - params->msp->enableLowBandwidth(enabled); + GET_MEDIA_CPP_PTR(params)->enableLowBandwidth(enabled); } void linphone_call_params_enable_audio(LinphoneCallParams *params, bool_t enabled) { - params->msp->enableAudio(enabled); + GET_MEDIA_CPP_PTR(params)->enableAudio(enabled); } LinphoneStatus linphone_call_params_enable_realtime_text(LinphoneCallParams *params, bool_t yesno) { - params->msp->enableRealtimeText(yesno); + GET_MEDIA_CPP_PTR(params)->enableRealtimeText(yesno); return 0; } void linphone_call_params_enable_video(LinphoneCallParams *params, bool_t enabled) { - params->msp->enableVideo(enabled); + GET_MEDIA_CPP_PTR(params)->enableVideo(enabled); } const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name) { - std::string value = params->msp->getCustomHeader(header_name); + std::string value = GET_MEDIA_CPP_PTR(params)->getCustomHeader(header_name); return value.empty() ? nullptr : value.c_str(); } const char * linphone_call_params_get_custom_sdp_attribute(const LinphoneCallParams *params, const char *attribute_name) { - std::string value = params->msp->getCustomSdpAttribute(attribute_name); + std::string value = GET_MEDIA_CPP_PTR(params)->getCustomSdpAttribute(attribute_name); return value.empty() ? nullptr : value.c_str(); } const char * linphone_call_params_get_custom_sdp_media_attribute(const LinphoneCallParams *params, LinphoneStreamType type, const char *attribute_name) { - std::string value = params->msp->getCustomSdpMediaAttribute(type, attribute_name); + std::string value = GET_MEDIA_CPP_PTR(params)->getCustomSdpMediaAttribute(type, attribute_name); return value.empty() ? nullptr : value.c_str(); } @@ -163,20 +168,20 @@ bool_t linphone_call_params_get_local_conference_mode(const LinphoneCallParams * } LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *params) { - return params->msp->getMediaEncryption(); + return GET_MEDIA_CPP_PTR(params)->getMediaEncryption(); } LinphonePrivacyMask linphone_call_params_get_privacy(const LinphoneCallParams *params) { - return params->msp->getPrivacy(); + return GET_MEDIA_CPP_PTR(params)->getPrivacy(); } float linphone_call_params_get_received_framerate(const LinphoneCallParams *params) { - return params->msp->getReceivedFps(); + return GET_MEDIA_CPP_PTR(params)->getReceivedFps(); } MSVideoSize linphone_call_params_get_received_video_size(const LinphoneCallParams *params) { MSVideoSize vsize; - LinphoneVideoDefinition *vdef = params->msp->getReceivedVideoDefinition(); + LinphoneVideoDefinition *vdef = GET_MEDIA_CPP_PTR(params)->getReceivedVideoDefinition(); if (vdef) { vsize.width = linphone_video_definition_get_width(vdef); vsize.height = linphone_video_definition_get_height(vdef); @@ -188,25 +193,25 @@ MSVideoSize linphone_call_params_get_received_video_size(const LinphoneCallParam } const LinphoneVideoDefinition * linphone_call_params_get_received_video_definition(const LinphoneCallParams *params) { - return params->msp->getReceivedVideoDefinition(); + return GET_MEDIA_CPP_PTR(params)->getReceivedVideoDefinition(); } const char *linphone_call_params_get_record_file(const LinphoneCallParams *params) { - const std::string &value = params->msp->getRecordFilePath(); + const std::string &value = GET_MEDIA_CPP_PTR(params)->getRecordFilePath(); return value.empty() ? nullptr : value.c_str(); } const char * linphone_call_params_get_rtp_profile(const LinphoneCallParams *params) { - return params->msp->getRtpProfile(); + return GET_MEDIA_CPP_PTR(params)->getRtpProfile(); } float linphone_call_params_get_sent_framerate(const LinphoneCallParams *params) { - return params->msp->getSentFps(); + return GET_MEDIA_CPP_PTR(params)->getSentFps(); } MSVideoSize linphone_call_params_get_sent_video_size(const LinphoneCallParams *params) { MSVideoSize vsize; - LinphoneVideoDefinition *vdef = params->msp->getSentVideoDefinition(); + LinphoneVideoDefinition *vdef = GET_MEDIA_CPP_PTR(params)->getSentVideoDefinition(); if (vdef) { vsize.width = linphone_video_definition_get_width(vdef); vsize.height = linphone_video_definition_get_height(vdef); @@ -218,155 +223,155 @@ MSVideoSize linphone_call_params_get_sent_video_size(const LinphoneCallParams *p } const LinphoneVideoDefinition * linphone_call_params_get_sent_video_definition(const LinphoneCallParams *params) { - return params->msp->getSentVideoDefinition(); + return GET_MEDIA_CPP_PTR(params)->getSentVideoDefinition(); } const char *linphone_call_params_get_session_name(const LinphoneCallParams *params) { - const std::string &value = params->msp->getSessionName(); + const std::string &value = GET_MEDIA_CPP_PTR(params)->getSessionName(); return value.empty() ? nullptr : value.c_str(); } LinphonePayloadType *linphone_call_params_get_used_audio_payload_type(const LinphoneCallParams *params) { - return params->msp->getUsedAudioPayloadType(); + return GET_MEDIA_CPP_PTR(params)->getUsedAudioPayloadType(); } LinphonePayloadType *linphone_call_params_get_used_video_payload_type(const LinphoneCallParams *params) { - return params->msp->getUsedVideoPayloadType(); + return GET_MEDIA_CPP_PTR(params)->getUsedVideoPayloadType(); } LinphonePayloadType *linphone_call_params_get_used_text_payload_type(const LinphoneCallParams *params) { - return params->msp->getUsedRealtimeTextPayloadType(); + return GET_MEDIA_CPP_PTR(params)->getUsedRealtimeTextPayloadType(); } const OrtpPayloadType *linphone_call_params_get_used_audio_codec(const LinphoneCallParams *params) { - return params->msp->getUsedAudioCodec(); + return GET_MEDIA_CPP_PTR(params)->getUsedAudioCodec(); } void linphone_call_params_set_used_audio_codec(LinphoneCallParams *params, OrtpPayloadType *codec) { - L_GET_PRIVATE(params->msp.get())->setUsedAudioCodec(codec); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setUsedAudioCodec(codec); } const OrtpPayloadType *linphone_call_params_get_used_video_codec(const LinphoneCallParams *params) { - return params->msp->getUsedVideoCodec(); + return GET_MEDIA_CPP_PTR(params)->getUsedVideoCodec(); } void linphone_call_params_set_used_video_codec(LinphoneCallParams *params, OrtpPayloadType *codec) { - L_GET_PRIVATE(params->msp.get())->setUsedVideoCodec(codec); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setUsedVideoCodec(codec); } const OrtpPayloadType *linphone_call_params_get_used_text_codec(const LinphoneCallParams *params) { - return params->msp->getUsedRealtimeTextCodec(); + return GET_MEDIA_CPP_PTR(params)->getUsedRealtimeTextCodec(); } void linphone_call_params_set_used_text_codec(LinphoneCallParams *params, OrtpPayloadType *codec) { - L_GET_PRIVATE(params->msp.get())->setUsedRealtimeTextCodec(codec); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setUsedRealtimeTextCodec(codec); } bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *params) { - return params->msp->lowBandwidthEnabled(); + return GET_MEDIA_CPP_PTR(params)->lowBandwidthEnabled(); } int linphone_call_params_get_audio_bandwidth_limit(const LinphoneCallParams *params) { - return params->msp->getAudioBandwidthLimit(); + return GET_MEDIA_CPP_PTR(params)->getAudioBandwidthLimit(); } void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *params, int bandwidth) { - params->msp->setAudioBandwidthLimit(bandwidth); + GET_MEDIA_CPP_PTR(params)->setAudioBandwidthLimit(bandwidth); } void linphone_call_params_set_media_encryption(LinphoneCallParams *params, LinphoneMediaEncryption encryption) { - params->msp->setMediaEncryption(encryption); + GET_MEDIA_CPP_PTR(params)->setMediaEncryption(encryption); } void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacyMask privacy) { - params->msp->setPrivacy(privacy); + GET_MEDIA_CPP_PTR(params)->setPrivacy(privacy); } void linphone_call_params_set_record_file(LinphoneCallParams *params, const char *path) { - params->msp->setRecordFilePath(path ? path : ""); + GET_MEDIA_CPP_PTR(params)->setRecordFilePath(path ? path : ""); } void linphone_call_params_set_session_name(LinphoneCallParams *params, const char *name) { - params->msp->setSessionName(name ? name : ""); + GET_MEDIA_CPP_PTR(params)->setSessionName(name ? name : ""); } bool_t linphone_call_params_audio_enabled(const LinphoneCallParams *params) { - return params->msp->audioEnabled(); + return GET_MEDIA_CPP_PTR(params)->audioEnabled(); } bool_t linphone_call_params_realtime_text_enabled(const LinphoneCallParams *params) { - return params->msp->realtimeTextEnabled(); + return GET_MEDIA_CPP_PTR(params)->realtimeTextEnabled(); } bool_t linphone_call_params_video_enabled(const LinphoneCallParams *params) { - return params->msp->videoEnabled(); + return GET_MEDIA_CPP_PTR(params)->videoEnabled(); } LinphoneMediaDirection linphone_call_params_get_audio_direction(const LinphoneCallParams *params) { - return params->msp->getAudioDirection(); + return GET_MEDIA_CPP_PTR(params)->getAudioDirection(); } LinphoneMediaDirection linphone_call_params_get_video_direction(const LinphoneCallParams *params) { - return params->msp->getVideoDirection(); + return GET_MEDIA_CPP_PTR(params)->getVideoDirection(); } void linphone_call_params_set_audio_direction(LinphoneCallParams *params, LinphoneMediaDirection dir) { - params->msp->setAudioDirection(dir); + GET_MEDIA_CPP_PTR(params)->setAudioDirection(dir); } void linphone_call_params_set_video_direction(LinphoneCallParams *params, LinphoneMediaDirection dir) { - params->msp->setVideoDirection(dir); + GET_MEDIA_CPP_PTR(params)->setVideoDirection(dir); } void linphone_call_params_enable_audio_multicast(LinphoneCallParams *params, bool_t yesno) { - params->msp->enableAudioMulticast(yesno); + GET_MEDIA_CPP_PTR(params)->enableAudioMulticast(yesno); } bool_t linphone_call_params_audio_multicast_enabled(const LinphoneCallParams *params) { - return params->msp->audioMulticastEnabled(); + return GET_MEDIA_CPP_PTR(params)->audioMulticastEnabled(); } void linphone_call_params_enable_video_multicast(LinphoneCallParams *params, bool_t yesno) { - params->msp->enableVideoMulticast(yesno); + GET_MEDIA_CPP_PTR(params)->enableVideoMulticast(yesno); } bool_t linphone_call_params_video_multicast_enabled(const LinphoneCallParams *params) { - return params->msp->videoMulticastEnabled(); + return GET_MEDIA_CPP_PTR(params)->videoMulticastEnabled(); } bool_t linphone_call_params_real_early_media_enabled(const LinphoneCallParams *params) { - return params->msp->earlyMediaSendingEnabled(); + return GET_MEDIA_CPP_PTR(params)->earlyMediaSendingEnabled(); } bool_t linphone_call_params_avpf_enabled(const LinphoneCallParams *params) { - return params->msp->avpfEnabled(); + return GET_MEDIA_CPP_PTR(params)->avpfEnabled(); } void linphone_call_params_enable_avpf(LinphoneCallParams *params, bool_t enable) { - params->msp->enableAvpf(enable); + GET_MEDIA_CPP_PTR(params)->enableAvpf(enable); } bool_t linphone_call_params_mandatory_media_encryption_enabled(const LinphoneCallParams *params) { - return params->msp->mandatoryMediaEncryptionEnabled(); + return GET_MEDIA_CPP_PTR(params)->mandatoryMediaEncryptionEnabled(); } void linphone_call_params_enable_mandatory_media_encryption(LinphoneCallParams *params, bool_t value) { - params->msp->enableMandatoryMediaEncryption(value); + GET_MEDIA_CPP_PTR(params)->enableMandatoryMediaEncryption(value); } uint16_t linphone_call_params_get_avpf_rr_interval(const LinphoneCallParams *params) { - return params->msp->getAvpfRrInterval(); + return GET_MEDIA_CPP_PTR(params)->getAvpfRrInterval(); } void linphone_call_params_set_avpf_rr_interval(LinphoneCallParams *params, uint16_t value) { - params->msp->setAvpfRrInterval(value); + GET_MEDIA_CPP_PTR(params)->setAvpfRrInterval(value); } void linphone_call_params_set_sent_fps(LinphoneCallParams *params, float value) { - L_GET_PRIVATE(params->msp.get())->setSentFps(value); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setSentFps(value); } void linphone_call_params_set_received_fps(LinphoneCallParams *params, float value) { - L_GET_PRIVATE(params->msp.get())->setReceivedFps(value); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setReceivedFps(value); } @@ -375,115 +380,111 @@ void linphone_call_params_set_received_fps(LinphoneCallParams *params, float val ******************************************************************************/ bool_t linphone_call_params_get_in_conference(const LinphoneCallParams *params) { - return L_GET_PRIVATE(static_cast(params->msp.get()))->getInConference(); + return GET_CALL_CPP_PRIVATE_PTR(params)->getInConference(); } void linphone_call_params_set_in_conference(LinphoneCallParams *params, bool_t value) { - L_GET_PRIVATE(static_cast(params->msp.get()))->setInConference(value); + GET_CALL_CPP_PRIVATE_PTR(params)->setInConference(value); } bool_t linphone_call_params_get_internal_call_update(const LinphoneCallParams *params) { - return L_GET_PRIVATE(static_cast(params->msp.get()))->getInternalCallUpdate(); + return GET_CALL_CPP_PRIVATE_PTR(params)->getInternalCallUpdate(); } void linphone_call_params_set_internal_call_update(LinphoneCallParams *params, bool_t value) { - L_GET_PRIVATE(static_cast(params->msp.get()))->setInternalCallUpdate(value); + GET_CALL_CPP_PRIVATE_PTR(params)->setInternalCallUpdate(value); } bool_t linphone_call_params_implicit_rtcp_fb_enabled(const LinphoneCallParams *params) { - return L_GET_PRIVATE(params->msp.get())->implicitRtcpFbEnabled(); + return GET_MEDIA_CPP_PRIVATE_PTR(params)->implicitRtcpFbEnabled(); } void linphone_call_params_enable_implicit_rtcp_fb(LinphoneCallParams *params, bool_t value) { - L_GET_PRIVATE(params->msp.get())->enableImplicitRtcpFb(value); + GET_MEDIA_CPP_PRIVATE_PTR(params)->enableImplicitRtcpFb(value); } int linphone_call_params_get_down_bandwidth(const LinphoneCallParams *params) { - return L_GET_PRIVATE(params->msp.get())->getDownBandwidth(); + return GET_MEDIA_CPP_PRIVATE_PTR(params)->getDownBandwidth(); } void linphone_call_params_set_down_bandwidth(LinphoneCallParams *params, int value) { - L_GET_PRIVATE(params->msp.get())->setDownBandwidth(value); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setDownBandwidth(value); } int linphone_call_params_get_up_bandwidth(const LinphoneCallParams *params) { - return L_GET_PRIVATE(params->msp.get())->getUpBandwidth(); + return GET_MEDIA_CPP_PRIVATE_PTR(params)->getUpBandwidth(); } void linphone_call_params_set_up_bandwidth(LinphoneCallParams *params, int value) { - L_GET_PRIVATE(params->msp.get())->setUpBandwidth(value); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setUpBandwidth(value); } int linphone_call_params_get_down_ptime(const LinphoneCallParams *params) { - return L_GET_PRIVATE(params->msp.get())->getDownPtime(); + return GET_MEDIA_CPP_PRIVATE_PTR(params)->getDownPtime(); } void linphone_call_params_set_down_ptime(LinphoneCallParams *params, int value) { - L_GET_PRIVATE(params->msp.get())->setDownPtime(value); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setDownPtime(value); } int linphone_call_params_get_up_ptime(const LinphoneCallParams *params) { - return L_GET_PRIVATE(params->msp.get())->getUpPtime(); + return GET_MEDIA_CPP_PRIVATE_PTR(params)->getUpPtime(); } void linphone_call_params_set_up_ptime(LinphoneCallParams *params, int value) { - L_GET_PRIVATE(params->msp.get())->setUpPtime(value); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setUpPtime(value); } SalCustomHeader * linphone_call_params_get_custom_headers(const LinphoneCallParams *params) { - return L_GET_PRIVATE(static_cast(params->msp.get()))->getCustomHeaders(); + return GET_CALL_CPP_PRIVATE_PTR(params)->getCustomHeaders(); } SalCustomSdpAttribute * linphone_call_params_get_custom_sdp_attributes(const LinphoneCallParams *params) { - return L_GET_PRIVATE(params->msp.get())->getCustomSdpAttributes(); + return GET_MEDIA_CPP_PRIVATE_PTR(params)->getCustomSdpAttributes(); } SalCustomSdpAttribute * linphone_call_params_get_custom_sdp_media_attributes(const LinphoneCallParams *params, LinphoneStreamType type) { - return L_GET_PRIVATE(params->msp.get())->getCustomSdpMediaAttributes(type); + return GET_MEDIA_CPP_PRIVATE_PTR(params)->getCustomSdpMediaAttributes(type); } LinphoneCall * linphone_call_params_get_referer(const LinphoneCallParams *params) { - return L_GET_PRIVATE(static_cast(params->msp.get()))->getReferer(); + return GET_CALL_CPP_PRIVATE_PTR(params)->getReferer(); } void linphone_call_params_set_referer(LinphoneCallParams *params, LinphoneCall *referer) { - L_GET_PRIVATE(static_cast(params->msp.get()))->setReferer(referer); + GET_CALL_CPP_PRIVATE_PTR(params)->setReferer(referer); } bool_t linphone_call_params_get_update_call_when_ice_completed(const LinphoneCallParams *params) { - return L_GET_PRIVATE(params->msp.get())->getUpdateCallWhenIceCompleted(); + return GET_MEDIA_CPP_PRIVATE_PTR(params)->getUpdateCallWhenIceCompleted(); } void linphone_call_params_set_update_call_when_ice_completed(LinphoneCallParams *params, bool_t value) { - L_GET_PRIVATE(params->msp.get())->setUpdateCallWhenIceCompleted(value); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setUpdateCallWhenIceCompleted(value); } void linphone_call_params_set_sent_vsize(LinphoneCallParams *params, MSVideoSize vsize) { - L_GET_PRIVATE(params->msp.get())->setSentVideoDefinition(linphone_video_definition_new(vsize.width, vsize.height, nullptr)); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setSentVideoDefinition(linphone_video_definition_new(vsize.width, vsize.height, nullptr)); } void linphone_call_params_set_recv_vsize(LinphoneCallParams *params, MSVideoSize vsize) { - L_GET_PRIVATE(params->msp.get())->setReceivedVideoDefinition(linphone_video_definition_new(vsize.width, vsize.height, nullptr)); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setReceivedVideoDefinition(linphone_video_definition_new(vsize.width, vsize.height, nullptr)); } void linphone_call_params_set_sent_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef) { - L_GET_PRIVATE(params->msp.get())->setSentVideoDefinition(vdef); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setSentVideoDefinition(vdef); } void linphone_call_params_set_received_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef) { - L_GET_PRIVATE(params->msp.get())->setReceivedVideoDefinition(vdef); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setReceivedVideoDefinition(vdef); } bool_t linphone_call_params_get_no_user_consent(const LinphoneCallParams *params) { - return L_GET_PRIVATE(static_cast(params->msp.get()))->getNoUserConsent(); + return GET_CALL_CPP_PRIVATE_PTR(params)->getNoUserConsent(); } void linphone_call_params_set_no_user_consent(LinphoneCallParams *params, bool_t value) { - L_GET_PRIVATE(static_cast(params->msp.get()))->setNoUserConsent(value); -} - -std::shared_ptr linphone_call_params_get_cpp_obj(const LinphoneCallParams *params) { - return params->msp; + GET_CALL_CPP_PRIVATE_PTR(params)->setNoUserConsent(value); } @@ -492,11 +493,11 @@ std::shared_ptr linphone_call_params_get_cp ******************************************************************************/ void *linphone_call_params_get_user_data(const LinphoneCallParams *cp) { - return cp->user_data; + return cp->userData; } void linphone_call_params_set_user_data(LinphoneCallParams *cp, void *ud) { - cp->user_data = ud; + cp->userData = ud; } LinphoneCallParams * linphone_call_params_ref(LinphoneCallParams *cp) { @@ -513,35 +514,18 @@ void linphone_call_params_unref(LinphoneCallParams *cp) { * Constructor and destructor functions * ******************************************************************************/ -static void _linphone_call_params_destroy(LinphoneCallParams *params) { - params->msp = nullptr; -} - -static void _linphone_call_params_clone(LinphoneCallParams *dst, const LinphoneCallParams *src) { - dst->msp = std::make_shared(*src->msp); -} - LinphoneCallParams * linphone_call_params_new(LinphoneCore *core) { - LinphoneCallParams *params = belle_sip_object_new(LinphoneCallParams); - params->msp = std::make_shared(); - params->msp->initDefault(core); + LinphoneCallParams *params = _linphone_call_params_init(); + params->cppPtr = new LinphonePrivate::MediaSessionParams(); + params->cppPtr->initDefault(core); return params; } LinphoneCallParams * linphone_call_params_new_for_wrapper(void) { - return belle_sip_object_new(LinphoneCallParams); + return _linphone_call_params_init(); } /* DEPRECATED */ void linphone_call_params_destroy(LinphoneCallParams *cp) { linphone_call_params_unref(cp); } - -BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCallParams); - -BELLE_SIP_INSTANCIATE_VPTR(LinphoneCallParams, belle_sip_object_t, - (belle_sip_object_destroy_t)_linphone_call_params_destroy, - (belle_sip_object_clone_t)_linphone_call_params_clone, // clone - NULL, // marshal - FALSE -); diff --git a/src/c-wrapper/c-private-types.h b/src/c-wrapper/c-private-types.h deleted file mode 100644 index bf84e1db1..000000000 --- a/src/c-wrapper/c-private-types.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * c-private-types.h - * Copyright (C) 2017 Belledonne Communications SARL - * - * 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, see . - */ - -#ifndef _C_PRIVATE_TYPES_H_ -#define _C_PRIVATE_TYPES_H_ - -#include - -#include "conference/params/media-session-params.h" - -// ============================================================================= - -#ifdef __cplusplus - extern "C" { -#endif - -// ============================================================================= -// C Structures. -// ============================================================================= - -struct _LinphoneCallParams{ - belle_sip_object_t base; - void *user_data; - std::shared_ptr msp; -}; - -#ifdef __cplusplus - } -#endif - -#endif // ifndef _C_PRIVATE_TYPES_H_ diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index 8a30c1e77..ce811af34 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -40,6 +40,7 @@ private: template struct WrappedClonableObject { belle_sip_object_t base; + void *userData; T *cppPtr; }; @@ -101,6 +102,16 @@ public: static_cast *>(object)->cppPtr = cppPtr; } + template + static inline void setCppPtrFromC (void *object, T *cppPtr) { + L_ASSERT(object); + T *tPtr = reinterpret_cast(static_cast *>(object)->cppPtr); + if (tPtr != cppPtr) { + delete tPtr; + static_cast *>(object)->cppPtr = new T(*cppPtr); + } + } + template static T *getCppPtr (const std::shared_ptr &cppPtr) { return cppPtr.get(); @@ -173,24 +184,25 @@ LINPHONE_END_NAMESPACE FALSE \ ); -#define L_DECLARE_C_CLONABLE_STRUCT_IMPL(STRUCT, C_NAME) \ - struct _Linphone ## STRUCT { \ +#define L_DECLARE_C_CLONABLE_STRUCT_IMPL(CPP_CLASS, C_STRUCT, C_NAME) \ + struct _Linphone ## C_STRUCT { \ belle_sip_object_t base; \ - LINPHONE_NAMESPACE::STRUCT *cppPtr; \ + void *userData; \ + LINPHONE_NAMESPACE::CPP_CLASS *cppPtr; \ }; \ - BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## STRUCT); \ - static Linphone ## STRUCT *_linphone_ ## C_NAME ## _init() { \ - return belle_sip_object_new(Linphone ## STRUCT); \ + BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_STRUCT); \ + static Linphone ## C_STRUCT *_linphone_ ## C_NAME ## _init() { \ + return belle_sip_object_new(Linphone ## C_STRUCT); \ } \ - static void _linphone_ ## C_NAME ## _uninit(Linphone ## STRUCT * object) { \ + static void _linphone_ ## C_NAME ## _uninit(Linphone ## C_STRUCT * object) { \ delete object->cppPtr; \ } \ - static void _linphone_ ## C_NAME ## _clone(Linphone ## STRUCT * dest, const Linphone ## STRUCT * src) { \ + static void _linphone_ ## C_NAME ## _clone(Linphone ## C_STRUCT * dest, const Linphone ## C_STRUCT * src) { \ L_ASSERT(src->cppPtr); \ - dest->cppPtr = new LINPHONE_NAMESPACE::STRUCT(*src->cppPtr); \ + dest->cppPtr = new LINPHONE_NAMESPACE::CPP_CLASS(*src->cppPtr); \ } \ - BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## STRUCT); \ - BELLE_SIP_INSTANCIATE_VPTR(Linphone ## STRUCT, belle_sip_object_t, \ + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## C_STRUCT); \ + BELLE_SIP_INSTANCIATE_VPTR(Linphone ## C_STRUCT, belle_sip_object_t, \ _linphone_ ## C_NAME ## _uninit, \ _linphone_ ## C_NAME ## _clone, \ NULL, \ @@ -207,8 +219,8 @@ LINPHONE_END_NAMESPACE #define L_STRING_TO_C(STR) ((STR).empty() ? NULL : (STR).c_str()) #define L_C_TO_STRING(STR) ((STR) == NULL ? std::string() : (STR)) -#define L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, TYPE) \ - LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC(OBJECT) +#define L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE, C_TYPE) \ + LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC(OBJECT) #define L_SET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_PTR) \ LINPHONE_NAMESPACE::Wrapper::setCppPtrFromC(OBJECT, CPP_PTR) @@ -216,9 +228,9 @@ LINPHONE_END_NAMESPACE #define L_GET_PRIVATE(OBJECT) \ LINPHONE_NAMESPACE::Wrapper::getPrivate(OBJECT) -#define L_GET_PRIVATE_FROM_C_STRUCT(OBJECT, TYPE) \ +#define L_GET_PRIVATE_FROM_C_STRUCT(OBJECT, CPP_TYPE, C_TYPE) \ L_GET_PRIVATE(LINPHONE_NAMESPACE::Wrapper::getCppPtr( \ - L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, TYPE) \ + L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE, C_TYPE) \ )) #define L_GET_C_LIST_FROM_CPP_LIST(LIST, TYPE) \ diff --git a/src/call/call-p.h b/src/call/call-p.h index 78e7a69de..98b062f74 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -39,7 +39,7 @@ LINPHONE_BEGIN_NAMESPACE class CallPrivate : public ObjectPrivate, CallListener { public: CallPrivate (LinphoneCall *call, LinphoneCore *core, LinphoneCallDir direction, const Address &from, const Address &to, - LinphoneProxyConfig *cfg, SalOp *op, const std::shared_ptr msp); + LinphoneProxyConfig *cfg, SalOp *op, const MediaSessionParams *msp); virtual ~CallPrivate (); void initiateIncoming (); diff --git a/src/call/call.cpp b/src/call/call.cpp index e3da64617..d8ee56d40 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -35,7 +35,7 @@ LINPHONE_BEGIN_NAMESPACE // ============================================================================= CallPrivate::CallPrivate (LinphoneCall *call, LinphoneCore *core, LinphoneCallDir direction, const Address &from, const Address &to, - LinphoneProxyConfig *cfg, SalOp *op, const shared_ptr msp) : lcall(call), core(core) { + LinphoneProxyConfig *cfg, SalOp *op, const MediaSessionParams *msp) : lcall(call), core(core) { nextVideoFrameDecoded._func = nullptr; nextVideoFrameDecoded._user_data = nullptr; } @@ -189,7 +189,7 @@ void CallPrivate::onResetFirstVideoFrameDecoded () { // ============================================================================= Call::Call (LinphoneCall *call, LinphoneCore *core, LinphoneCallDir direction, const Address &from, const Address &to, - LinphoneProxyConfig *cfg, SalOp *op, const shared_ptr msp) : Object(*new CallPrivate(call, core, direction, from, to, cfg, op, msp)) { + LinphoneProxyConfig *cfg, SalOp *op, const MediaSessionParams *msp) : Object(*new CallPrivate(call, core, direction, from, to, cfg, op, msp)) { L_D(Call); const Address *myAddress = (direction == LinphoneCallIncoming) ? &to : &from; string confType = lp_config_get_string(linphone_core_get_config(core), "misc", "conference_type", "local"); @@ -205,17 +205,17 @@ Call::Call (LinphoneCall *call, LinphoneCore *core, LinphoneCallDir direction, c // ----------------------------------------------------------------------------- -LinphoneStatus Call::accept (const shared_ptr msp) { +LinphoneStatus Call::accept (const MediaSessionParams *msp) { L_D(Call); return static_cast(d->getActiveSession().get())->accept(msp); } -LinphoneStatus Call::acceptEarlyMedia (const std::shared_ptr msp) { +LinphoneStatus Call::acceptEarlyMedia (const MediaSessionParams *msp) { L_D(Call); return static_cast(d->getActiveSession().get())->acceptEarlyMedia(msp); } -LinphoneStatus Call::acceptUpdate (const shared_ptr msp) { +LinphoneStatus Call::acceptUpdate (const MediaSessionParams *msp) { L_D(Call); return static_cast(d->getActiveSession().get())->acceptUpdate(msp); } @@ -270,7 +270,7 @@ LinphoneStatus Call::terminate (const LinphoneErrorInfo *ei) { return d->getActiveSession()->terminate(ei); } -LinphoneStatus Call::update (const std::shared_ptr msp) { +LinphoneStatus Call::update (const MediaSessionParams *msp) { L_D(Call); return static_cast(d->getActiveSession().get())->update(msp); } @@ -342,7 +342,7 @@ LinphoneCore * Call::getCore () const { return d->core; } -const shared_ptr Call::getCurrentParams () const { +const MediaSessionParams * Call::getCurrentParams () const { L_D(const Call); return static_cast(d->getActiveSession().get())->getCurrentParams(); } @@ -392,7 +392,7 @@ void * Call::getNativeVideoWindowId () const { return static_cast(d->getActiveSession().get())->getNativeVideoWindowId(); } -const std::shared_ptr Call::getParams () const { +const MediaSessionParams * Call::getParams () const { L_D(const Call); return static_cast(d->getActiveSession().get())->getMediaParams(); } @@ -427,7 +427,7 @@ string Call::getRemoteContact () const { return d->getActiveSession()->getRemoteContact(); } -const shared_ptr Call::getRemoteParams () const { +const MediaSessionParams * Call::getRemoteParams () const { L_D(const Call); return static_cast(d->getActiveSession().get())->getRemoteParams(); } diff --git a/src/call/call.h b/src/call/call.h index acf2d0c0f..2cb14bf3d 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -19,8 +19,6 @@ #ifndef _CALL_CALL_H_ #define _CALL_CALL_H_ -#include - #include "linphone/types.h" #include "object/object.h" @@ -42,11 +40,11 @@ class Call : public Object { public: Call (LinphoneCall *call, LinphoneCore *core, LinphoneCallDir direction, const Address &from, const Address &to, - LinphoneProxyConfig *cfg, SalOp *op, const std::shared_ptr msp); + LinphoneProxyConfig *cfg, SalOp *op, const MediaSessionParams *msp); - LinphoneStatus accept (const std::shared_ptr msp = nullptr); - LinphoneStatus acceptEarlyMedia (const std::shared_ptr msp = nullptr); - LinphoneStatus acceptUpdate (const std::shared_ptr msp); + LinphoneStatus accept (const MediaSessionParams *msp = nullptr); + LinphoneStatus acceptEarlyMedia (const MediaSessionParams *msp = nullptr); + LinphoneStatus acceptUpdate (const MediaSessionParams *msp); LinphoneStatus decline (LinphoneReason reason); LinphoneStatus decline (const LinphoneErrorInfo *ei); LinphoneStatus pause (); @@ -57,7 +55,7 @@ public: LinphoneStatus takePreviewSnapshot (const std::string& file); LinphoneStatus takeVideoSnapshot (const std::string& file); LinphoneStatus terminate (const LinphoneErrorInfo *ei = nullptr); - LinphoneStatus update (const std::shared_ptr msp = nullptr); + LinphoneStatus update (const MediaSessionParams *msp = nullptr); void zoomVideo (float zoomFactor, float *cx, float *cy); bool cameraEnabled () const; @@ -72,7 +70,7 @@ public: bool getAuthenticationTokenVerified () const; float getAverageQuality () const; LinphoneCore * getCore () const; - const std::shared_ptr getCurrentParams () const; + const MediaSessionParams * getCurrentParams () const; float getCurrentQuality () const; LinphoneCallDir getDirection () const; int getDuration () const; @@ -82,14 +80,14 @@ public: RtpTransport * getMetaRtpTransport (int streamIndex); float getMicrophoneVolumeGain () const; void * getNativeVideoWindowId () const; - const std::shared_ptr getParams () const; + const MediaSessionParams * getParams () const; float getPlayVolume () const; LinphoneReason getReason () const; float getRecordVolume () const; const Address& getRemoteAddress () const; std::string getRemoteAddressAsString () const; std::string getRemoteContact () const; - const std::shared_ptr getRemoteParams () const; + const MediaSessionParams * getRemoteParams () const; float getSpeakerVolumeGain () const; LinphoneCallState getState () const; LinphoneCallStats * getStats (LinphoneStreamType type) const; diff --git a/src/chat/basic-chat-room.cpp b/src/chat/basic-chat-room.cpp index d59554da5..a83535d03 100644 --- a/src/chat/basic-chat-room.cpp +++ b/src/chat/basic-chat-room.cpp @@ -35,12 +35,12 @@ BasicChatRoom::BasicChatRoom (LinphoneCore *core, const Address &peerAddress) : // ----------------------------------------------------------------------------- -shared_ptr BasicChatRoom::addParticipant (const Address &addr, const shared_ptr params, bool hasMedia) { +shared_ptr BasicChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { lError() << "addParticipant() is not allowed on a BasicChatRoom"; return nullptr; } -void BasicChatRoom::addParticipants (const list
&addresses, const shared_ptr params, bool hasMedia) { +void BasicChatRoom::addParticipants (const list
&addresses, const CallSessionParams *params, bool hasMedia) { lError() << "addParticipants() is not allowed on a BasicChatRoom"; } diff --git a/src/chat/basic-chat-room.h b/src/chat/basic-chat-room.h index f47341fc7..3c696c67d 100644 --- a/src/chat/basic-chat-room.h +++ b/src/chat/basic-chat-room.h @@ -39,8 +39,8 @@ public: virtual ~BasicChatRoom () = default; /* ConferenceInterface */ - std::shared_ptr addParticipant (const Address &addr, const std::shared_ptr params, bool hasMedia); - void addParticipants (const std::list
&addresses, const std::shared_ptr params, bool hasMedia); + std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia); + void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia); const std::string& getId () const; int getNbParticipants () const; std::list> getParticipants () const; diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index f984adf59..2758244b7 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -800,7 +800,7 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { if (identity.empty()) { LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(d->core, peer); if (proxy) { - identity = L_GET_CPP_PTR_FROM_C_STRUCT(linphone_proxy_config_get_identity_address(proxy), Address)->asString(); + identity = L_GET_CPP_PTR_FROM_C_STRUCT(linphone_proxy_config_get_identity_address(proxy), Address, Address)->asString(); } else { identity = linphone_core_get_primary_contact(d->core); } diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 82550087a..47ad6a2e5 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -32,18 +32,25 @@ ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core) : Ch ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, std::list
&addresses) : ChatRoom(*new ChatRoomPrivate(core)), RemoteConference(core, me, nullptr) { + string factoryUri = linphone_core_get_chat_conference_factory_uri(core); + focus = make_shared(factoryUri); + CallSessionParams csp; + shared_ptr session = focus->getPrivate()->createSession(*this, &csp, false, this); + session->configure(LinphoneCallOutgoing, nullptr, nullptr, me, focus->getAddress()); + session->initiateOutgoing(); + session->startInvite(nullptr); // TODO } // ----------------------------------------------------------------------------- -shared_ptr ClientGroupChatRoom::addParticipant (const Address &addr, const shared_ptr params, bool hasMedia) { +shared_ptr ClientGroupChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { activeParticipant = make_shared(addr); activeParticipant->getPrivate()->createSession(*this, params, hasMedia, this); return activeParticipant; } -void ClientGroupChatRoom::addParticipants (const list
&addresses, const shared_ptr params, bool hasMedia) { +void ClientGroupChatRoom::addParticipants (const list
&addresses, const CallSessionParams *params, bool hasMedia) { // TODO } diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index f19a07326..b32d5951f 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -40,8 +40,8 @@ public: public: /* ConferenceInterface */ - std::shared_ptr addParticipant (const Address &addr, const std::shared_ptr params, bool hasMedia); - void addParticipants (const std::list
&addresses, const std::shared_ptr params, bool hasMedia); + std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia); + void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia); const std::string& getId () const; int getNbParticipants () const; std::list> getParticipants () const; diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 4933b1874..2f352f3d8 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -140,12 +140,12 @@ LinphoneCall *RealTimeTextChatRoom::getCall () const { // ----------------------------------------------------------------------------- -shared_ptr RealTimeTextChatRoom::addParticipant (const Address &addr, const shared_ptr params, bool hasMedia) { +shared_ptr RealTimeTextChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { lError() << "addParticipant() is not allowed on a RealTimeTextChatRoom"; return nullptr; } -void RealTimeTextChatRoom::addParticipants (const list
&addresses, const shared_ptr params, bool hasMedia) { +void RealTimeTextChatRoom::addParticipants (const list
&addresses, const CallSessionParams *params, bool hasMedia) { lError() << "addParticipants() is not allowed on a RealTimeTextChatRoom"; } diff --git a/src/chat/real-time-text-chat-room.h b/src/chat/real-time-text-chat-room.h index 3987a8a9b..949691722 100644 --- a/src/chat/real-time-text-chat-room.h +++ b/src/chat/real-time-text-chat-room.h @@ -43,8 +43,8 @@ public: LinphoneCall *getCall () const; /* ConferenceInterface */ - std::shared_ptr addParticipant (const Address &addr, const std::shared_ptr params, bool hasMedia); - void addParticipants (const std::list
&addresses, const std::shared_ptr params, bool hasMedia); + std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia); + void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia); const std::string& getId () const; int getNbParticipants () const; std::list> getParticipants () const; diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index 85e22ff67..840675c8c 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -34,8 +34,8 @@ class ConferenceInterface { public: virtual ~ConferenceInterface() = default; - virtual std::shared_ptr addParticipant (const Address &addr, const std::shared_ptr params, bool hasMedia) = 0; - virtual void addParticipants (const std::list
&addresses, const std::shared_ptr params, bool hasMedia) = 0; + virtual std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) = 0; + virtual void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia) = 0; virtual const std::string& getId () const = 0; virtual int getNbParticipants () const = 0; virtual std::list> getParticipants () const = 0; diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 989713577..1d9e6666c 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -39,13 +39,13 @@ shared_ptr Conference::getActiveParticipant () const { // ----------------------------------------------------------------------------- -shared_ptr Conference::addParticipant (const Address &addr, const shared_ptr params, bool hasMedia) { +shared_ptr Conference::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { activeParticipant = make_shared(addr); activeParticipant->getPrivate()->createSession(*this, params, hasMedia, this); return activeParticipant; } -void Conference::addParticipants (const list
&addresses, const shared_ptr params, bool hasMedia) { +void Conference::addParticipants (const list
&addresses, const CallSessionParams *params, bool hasMedia) { // TODO } diff --git a/src/conference/conference.h b/src/conference/conference.h index fc027da6d..6f4886ff0 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -50,8 +50,8 @@ public: public: /* ConferenceInterface */ - virtual std::shared_ptr addParticipant (const Address &addr, const std::shared_ptr params, bool hasMedia); - virtual void addParticipants (const std::list
&addresses, const std::shared_ptr params, bool hasMedia); + virtual std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia); + virtual void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia); virtual const std::string& getId () const; virtual int getNbParticipants () const; virtual std::list> getParticipants () const; diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h index 8b29b3752..7c60f772a 100644 --- a/src/conference/local-conference.h +++ b/src/conference/local-conference.h @@ -28,6 +28,7 @@ LINPHONE_BEGIN_NAMESPACE class LocalConference : public Conference { public: LocalConference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); + virtual ~LocalConference() = default; private: L_DISABLE_COPY(LocalConference); diff --git a/src/conference/params/media-session-params-p.h b/src/conference/params/media-session-params-p.h index f2ca7ca8c..ece0fb241 100644 --- a/src/conference/params/media-session-params-p.h +++ b/src/conference/params/media-session-params-p.h @@ -27,7 +27,6 @@ // ============================================================================= -extern std::shared_ptr linphone_call_params_get_cpp_obj(const LinphoneCallParams *params); extern LinphoneCallParams * linphone_call_params_new_for_wrapper(void); // ============================================================================= diff --git a/src/conference/participant-p.h b/src/conference/participant-p.h index 8bef6f69e..21f906a07 100644 --- a/src/conference/participant-p.h +++ b/src/conference/participant-p.h @@ -38,7 +38,7 @@ class ParticipantPrivate : public ObjectPrivate { public: virtual ~ParticipantPrivate () = default; - void createSession (const Conference &conference, const std::shared_ptr params, bool hasMedia, CallSessionListener *listener); + std::shared_ptr createSession (const Conference &conference, const CallSessionParams *params, bool hasMedia, CallSessionListener *listener); std::shared_ptr getSession () const; Address addr; diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index 0739feb25..6bbfd4790 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -29,12 +29,13 @@ LINPHONE_BEGIN_NAMESPACE // ============================================================================= -void ParticipantPrivate::createSession (const Conference &conference, const shared_ptr params, bool hasMedia, CallSessionListener *listener) { - if (hasMedia && (!params || dynamic_cast(params.get()))) { +shared_ptr ParticipantPrivate::createSession (const Conference &conference, const CallSessionParams *params, bool hasMedia, CallSessionListener *listener) { + if (hasMedia && (!params || dynamic_cast(params))) { session = make_shared(conference, params, listener); } else { session = make_shared(conference, params, listener); } + return session; } shared_ptr ParticipantPrivate::getSession () const { diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index 40d9cc387..be1aa8c51 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -30,6 +30,9 @@ public: RemoteConference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); virtual ~RemoteConference() = default; +protected: + std::shared_ptr focus = nullptr; + private: L_DISABLE_COPY(RemoteConference); }; diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index bca4ed0a3..2c9ed1c79 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -31,7 +31,7 @@ LINPHONE_BEGIN_NAMESPACE class CallSessionPrivate : public ObjectPrivate { public: - CallSessionPrivate (const Conference &conference, const std::shared_ptr params, CallSessionListener *listener); + CallSessionPrivate (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener); virtual ~CallSessionPrivate (); int computeDuration () const; @@ -56,8 +56,8 @@ public: virtual void updating (bool isUpdate); protected: - void accept (const std::shared_ptr params); - virtual LinphoneStatus acceptUpdate (const std::shared_ptr csp, LinphoneCallState nextState, const std::string &stateInfo); + void accept (const CallSessionParams *params); + virtual LinphoneStatus acceptUpdate (const CallSessionParams *csp, LinphoneCallState nextState, const std::string &stateInfo); LinphoneStatus checkForAcceptation () const; virtual void handleIncomingReceivedStateInIncomingNotification (); virtual bool isReadyForInvite () const; @@ -82,9 +82,9 @@ protected: LinphoneCore *core = nullptr; CallSessionListener *listener = nullptr; - std::shared_ptr params = nullptr; - std::shared_ptr currentParams = nullptr; - std::shared_ptr remoteParams = nullptr; + CallSessionParams *params = nullptr; + CallSessionParams *currentParams = nullptr; + CallSessionParams *remoteParams = nullptr; LinphoneCallDir direction = LinphoneCallOutgoing; LinphoneCallState state = LinphoneCallIdle; diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 595fc2c70..b87892db8 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -39,16 +39,22 @@ LINPHONE_BEGIN_NAMESPACE // ============================================================================= -CallSessionPrivate::CallSessionPrivate (const Conference &conference, const shared_ptr params, CallSessionListener *listener) +CallSessionPrivate::CallSessionPrivate (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener) : conference(conference), listener(listener) { if (params) - this->params = make_shared(*params.get()); - currentParams = make_shared(); + this->params = new CallSessionParams(*params); + currentParams = new CallSessionParams(); core = conference.getCore(); ei = linphone_error_info_new(); } CallSessionPrivate::~CallSessionPrivate () { + if (currentParams) + delete currentParams; + if (params) + delete params; + if (remoteParams) + delete remoteParams; if (ei) linphone_error_info_unref(ei); if (log) @@ -475,13 +481,13 @@ void CallSessionPrivate::updating (bool isUpdate) { // ----------------------------------------------------------------------------- -void CallSessionPrivate::accept (const shared_ptr params) { +void CallSessionPrivate::accept (const CallSessionParams *params) { L_Q(CallSession); /* Try to be best-effort in giving real local or routable contact address */ setContactOp(); if (params) { - this->params = params; - sal_op_set_sent_custom_header(op, params->getPrivate()->getCustomHeaders()); + this->params = new CallSessionParams(*params); + sal_op_set_sent_custom_header(op, this->params->getPrivate()->getCustomHeaders()); } sal_call_accept(op); @@ -491,7 +497,7 @@ void CallSessionPrivate::accept (const shared_ptr params) { setState(LinphoneCallConnected, "Connected"); } -LinphoneStatus CallSessionPrivate::acceptUpdate (const shared_ptr csp, LinphoneCallState nextState, const string &stateInfo) { +LinphoneStatus CallSessionPrivate::acceptUpdate (const CallSessionParams *csp, LinphoneCallState nextState, const string &stateInfo) { return startAcceptUpdate(nextState, stateInfo); } @@ -672,7 +678,7 @@ void CallSessionPrivate::setContactOp () { SalAddress *salAddress = nullptr; LinphoneAddress *contact = getFixedContact(); if (contact) { - salAddress = const_cast(L_GET_PRIVATE_FROM_C_STRUCT(contact, Address)->getInternalAddress()); + salAddress = const_cast(L_GET_PRIVATE_FROM_C_STRUCT(contact, Address, Address)->getInternalAddress()); sal_address_ref(salAddress); linphone_address_unref(contact); } @@ -742,7 +748,7 @@ LinphoneAddress * CallSessionPrivate::getFixedContact () const { // ============================================================================= -CallSession::CallSession (const Conference &conference, const shared_ptr params, CallSessionListener *listener) +CallSession::CallSession (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener) : Object(*new CallSessionPrivate(conference, params, listener)) { lInfo() << "New CallSession [" << this << "] initialized (LinphoneCore version: " << linphone_core_get_version() << ")"; } @@ -751,7 +757,7 @@ CallSession::CallSession (CallSessionPrivate &p) : Object(p) {} // ----------------------------------------------------------------------------- -LinphoneStatus CallSession::accept (const shared_ptr csp) { +LinphoneStatus CallSession::accept (const CallSessionParams *csp) { L_D(CallSession); LinphoneStatus result = d->checkForAcceptation(); if (result < 0) return result; @@ -759,7 +765,7 @@ LinphoneStatus CallSession::accept (const shared_ptr csp) { return 0; } -LinphoneStatus CallSession::acceptUpdate (const shared_ptr csp) { +LinphoneStatus CallSession::acceptUpdate (const CallSessionParams *csp) { L_D(CallSession); if (d->state != LinphoneCallUpdatedByRemote) { lError() << "CallSession::acceptUpdate(): invalid state " << linphone_call_state_to_string(d->state) << " to call this method"; @@ -798,7 +804,7 @@ void CallSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg if (direction == LinphoneCallOutgoing) { d->startPing(); } else if (direction == LinphoneCallIncoming) { - d->params = make_shared(); + d->params = new CallSessionParams(); d->params->initDefault(d->core); } } @@ -989,13 +995,13 @@ LinphoneStatus CallSession::terminate (const LinphoneErrorInfo *ei) { return 0; } -LinphoneStatus CallSession::update (const shared_ptr csp) { +LinphoneStatus CallSession::update (const CallSessionParams *csp) { L_D(CallSession); LinphoneCallState nextState; LinphoneCallState initialState = d->state; if (!d->isUpdateAllowed(nextState)) return -1; - if (d->currentParams.get() == csp.get()) + if (d->currentParams == csp) lWarning() << "CallSession::update() is given the current params, this is probably not what you intend to do!"; LinphoneStatus result = d->startUpdate(); if (result && (d->state != initialState)) { @@ -1044,7 +1050,7 @@ const Address& CallSession::getRemoteAddress () const { L_D(const CallSession); return *L_GET_CPP_PTR_FROM_C_STRUCT((d->direction == LinphoneCallIncoming) ? linphone_call_log_get_from(d->log) : linphone_call_log_get_to(d->log), - Address); + Address, Address); } string CallSession::getRemoteAddressAsString () const { @@ -1060,14 +1066,14 @@ string CallSession::getRemoteContact () const { return string(); } -const shared_ptr CallSession::getRemoteParams () { +const CallSessionParams * CallSession::getRemoteParams () { L_D(CallSession); if (d->op){ const SalCustomHeader *ch = sal_op_get_recv_custom_header(d->op); if (ch) { /* Instanciate a remote_params only if a SIP message was received before (custom headers indicates this) */ if (!d->remoteParams) - d->remoteParams = make_shared(); + d->remoteParams = new CallSessionParams(); d->remoteParams->getPrivate()->setCustomHeaders(ch); } return d->remoteParams; @@ -1089,7 +1095,7 @@ string CallSession::getRemoteUserAgent () const { return string(); } -shared_ptr CallSession::getCurrentParams () { +CallSessionParams * CallSession::getCurrentParams () { L_D(CallSession); d->updateCurrentParams(); return d->currentParams; @@ -1097,7 +1103,7 @@ shared_ptr CallSession::getCurrentParams () { // ----------------------------------------------------------------------------- -const shared_ptr CallSession::getParams () const { +const CallSessionParams * CallSession::getParams () const { L_D(const CallSession); return d->params; } diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index 89576c970..7e6d5634c 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -38,10 +38,10 @@ class CallSession : public Object, public std::enable_shared_from_this params, CallSessionListener *listener); + CallSession (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener); - LinphoneStatus accept (const std::shared_ptr csp = nullptr); - LinphoneStatus acceptUpdate (const std::shared_ptr csp); + LinphoneStatus accept (const CallSessionParams *csp = nullptr); + LinphoneStatus acceptUpdate (const CallSessionParams *csp); virtual void configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalOp *op, const Address &from, const Address &to); LinphoneStatus decline (LinphoneReason reason); LinphoneStatus decline (const LinphoneErrorInfo *ei); @@ -51,19 +51,19 @@ public: virtual void startIncomingNotification (); virtual int startInvite (const Address *destination); LinphoneStatus terminate (const LinphoneErrorInfo *ei = nullptr); - LinphoneStatus update (const std::shared_ptr csp); + LinphoneStatus update (const CallSessionParams *csp); - std::shared_ptr getCurrentParams (); + CallSessionParams *getCurrentParams (); LinphoneCallDir getDirection () const; int getDuration () const; const LinphoneErrorInfo * getErrorInfo () const; LinphoneCallLog * getLog () const; - virtual const std::shared_ptr getParams () const; + virtual const CallSessionParams *getParams () const; LinphoneReason getReason () const; const Address& getRemoteAddress () const; std::string getRemoteAddressAsString () const; std::string getRemoteContact () const; - const std::shared_ptr getRemoteParams (); + const CallSessionParams *getRemoteParams (); LinphoneCallState getState () const; std::string getRemoteUserAgent () const; diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index a70865307..2207fbdef 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -39,7 +39,7 @@ LINPHONE_BEGIN_NAMESPACE class MediaSessionPrivate : public CallSessionPrivate { public: - MediaSessionPrivate (const Conference &conference, const std::shared_ptr params, CallSessionListener *listener); + MediaSessionPrivate (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener); virtual ~MediaSessionPrivate (); public: @@ -221,8 +221,8 @@ private: void terminate (); void updateCurrentParams (); - void accept (const std::shared_ptr params); - LinphoneStatus acceptUpdate (const std::shared_ptr csp, LinphoneCallState nextState, const std::string &stateInfo); + void accept (const MediaSessionParams *params); + LinphoneStatus acceptUpdate (const CallSessionParams *csp, LinphoneCallState nextState, const std::string &stateInfo); #ifdef VIDEO_ENABLED void videoStreamEventCb (const MSFilter *f, const unsigned int eventId, const void *args); @@ -235,9 +235,9 @@ private: static const std::string ecStateStore; static const int ecStateMaxLen; - std::shared_ptr params = nullptr; - std::shared_ptr currentParams = nullptr; - std::shared_ptr remoteParams = nullptr; + MediaSessionParams *params = nullptr; + MediaSessionParams *currentParams = nullptr; + MediaSessionParams *remoteParams = nullptr; AudioStream *audioStream = nullptr; OrtpEvQueue *audioStreamEvQueue = nullptr; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 72f39635b..6158379de 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -66,11 +66,11 @@ const int MediaSessionPrivate::ecStateMaxLen = 1048576; /* 1Mo */ // ============================================================================= -MediaSessionPrivate::MediaSessionPrivate (const Conference &conference, const shared_ptr params, CallSessionListener *listener) - : CallSessionPrivate(conference, params, listener) { - if (params) - this->params = make_shared(*(reinterpret_cast(params.get()))); - currentParams = make_shared(); +MediaSessionPrivate::MediaSessionPrivate (const Conference &conference, const CallSessionParams *csp, CallSessionListener *listener) + : CallSessionPrivate(conference, csp, listener) { + if (csp) + params = new MediaSessionParams(*(reinterpret_cast(csp))); + currentParams = new MediaSessionParams(); audioStats = linphone_call_stats_ref(linphone_call_stats_new()); initStats(audioStats, LinphoneStreamTypeAudio); @@ -91,6 +91,12 @@ MediaSessionPrivate::MediaSessionPrivate (const Conference &conference, const sh } MediaSessionPrivate::~MediaSessionPrivate () { + if (currentParams) + delete currentParams; + if (params) + delete params; + if (remoteParams) + delete remoteParams; if (audioStats) linphone_call_stats_unref(audioStats); if (videoStats) @@ -317,7 +323,7 @@ bool MediaSessionPrivate::failure () { void MediaSessionPrivate::pausedByRemote () { linphone_core_notify_display_status(core, "We are paused by other party"); - shared_ptr newParams = make_shared(*params.get()); + MediaSessionParams *newParams = new MediaSessionParams(*params); if (lp_config_get_int(linphone_core_get_config(core), "sip", "inactive_video_on_pause", 0)) newParams->setVideoDirection(LinphoneMediaDirectionInactive); acceptUpdate(newParams, LinphoneCallPausedByRemote, "Call paused by remote"); @@ -419,7 +425,7 @@ void MediaSessionPrivate::updating (bool isUpdate) { /* Refresh the local description, but in paused state, we don't change anything. */ if (!rmd && lp_config_get_int(linphone_core_get_config(core), "sip", "sdp_200_ack_follow_video_policy", 0)) { lInfo() << "Applying default policy for offering SDP on CallSession [" << q << "]"; - params = make_shared(); + params = new MediaSessionParams(); params->initDefault(core); } makeLocalMediaDescription(); @@ -747,7 +753,7 @@ void MediaSessionPrivate::fixCallParams (SalMediaDescription *rmd) { */ /*params.getPrivate()->enableImplicitRtcpFb(params.getPrivate()->implicitRtcpFbEnabled() & sal_media_description_has_implicit_avpf(rmd));*/ } - const shared_ptr rcp = q->getRemoteParams(); + const MediaSessionParams *rcp = q->getRemoteParams(); if (rcp) { if (params->audioEnabled() && !rcp->audioEnabled()) { lInfo() << "CallSession [" << q << "]: disabling audio in our call params because the remote doesn't want it"; @@ -1111,8 +1117,8 @@ void MediaSessionPrivate::selectOutgoingIpVersion () { return; } - LinphoneAddress *to = linphone_call_log_get_to_address(log); - if (sal_address_is_ipv6(L_GET_PRIVATE_FROM_C_STRUCT(to, Address)->getInternalAddress())) + const LinphoneAddress *to = linphone_call_log_get_to_address(log); + if (sal_address_is_ipv6(L_GET_PRIVATE_FROM_C_STRUCT(to, Address, Address)->getInternalAddress())) af = AF_INET6; else if (destProxy && destProxy->op) af = sal_op_get_address_family(destProxy->op); @@ -1224,7 +1230,7 @@ void MediaSessionPrivate::makeLocalMediaDescription () { md->nb_streams = (biggestDesc ? biggestDesc->nb_streams : 1); /* Re-check local ip address each time we make a new offer, because it may change in case of network reconnection */ - getLocalIp(*L_GET_CPP_PTR_FROM_C_STRUCT((direction == LinphoneCallOutgoing) ? log->to : log->from, Address)); + getLocalIp(*L_GET_CPP_PTR_FROM_C_STRUCT((direction == LinphoneCallOutgoing) ? log->to : log->from, Address, Address)); strncpy(md->addr, mediaLocalIp.c_str(), sizeof(md->addr)); LinphoneAddress *addr = nullptr; if (destProxy) { @@ -2070,7 +2076,7 @@ void MediaSessionPrivate::handleIceEvents (OrtpEvent *ev) { if (iceAgent->hasCompletedCheckList()) { /* At least one ICE session has succeeded, so perform a call update */ if (iceAgent->isControlling() && q->getCurrentParams()->getPrivate()->getUpdateCallWhenIceCompleted()) { - shared_ptr newParams = make_shared(*params.get()); + MediaSessionParams *newParams = new MediaSessionParams(*params); newParams->getPrivate()->setInternalCallUpdate(true); q->update(newParams); } @@ -3845,9 +3851,9 @@ void MediaSessionPrivate::updateCurrentParams () { // ----------------------------------------------------------------------------- -void MediaSessionPrivate::accept (const shared_ptr params) { - if (params) { - this->params = params; +void MediaSessionPrivate::accept (const MediaSessionParams *csp) { + if (csp) { + params = new MediaSessionParams(*csp); iceAgent->prepare(localDesc, true); makeLocalMediaDescription(); sal_call_set_local_media_description(op, localDesc); @@ -3881,7 +3887,7 @@ void MediaSessionPrivate::accept (const shared_ptr params) { expectMediaInAck = true; } -LinphoneStatus MediaSessionPrivate::acceptUpdate (const shared_ptr csp, LinphoneCallState nextState, const string &stateInfo) { +LinphoneStatus MediaSessionPrivate::acceptUpdate (const CallSessionParams *csp, LinphoneCallState nextState, const string &stateInfo) { L_Q(MediaSession); SalMediaDescription *desc = sal_call_get_remote_media_description(op); bool keepSdpVersion = lp_config_get_int(linphone_core_get_config(core), "sip", "keep_sdp_version", 0); @@ -3893,7 +3899,7 @@ LinphoneStatus MediaSessionPrivate::acceptUpdate (const shared_ptr(*static_cast(csp.get())); + params = new MediaSessionParams(*static_cast(csp)); else { if (!sal_call_is_offerer(op)) { /* Reset call params for multicast because this param is only relevant when offering */ @@ -4006,7 +4012,7 @@ void MediaSessionPrivate::stunAuthRequestedCb (const char *realm, const char *no // ============================================================================= -MediaSession::MediaSession (const Conference &conference, const shared_ptr params, CallSessionListener *listener) +MediaSession::MediaSession (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener) : CallSession(*new MediaSessionPrivate(conference, params, listener)) { L_D(MediaSession); d->iceAgent = new IceAgent(*this); @@ -4014,7 +4020,7 @@ MediaSession::MediaSession (const Conference &conference, const shared_ptr msp) { +LinphoneStatus MediaSession::accept (const MediaSessionParams *msp) { L_D(MediaSession); LinphoneStatus result = d->checkForAcceptation(); if (result < 0) return result; @@ -4043,7 +4049,7 @@ LinphoneStatus MediaSession::accept (const shared_ptr msp) { return 0; } -LinphoneStatus MediaSession::acceptEarlyMedia (const std::shared_ptr msp) { +LinphoneStatus MediaSession::acceptEarlyMedia (const MediaSessionParams *msp) { L_D(MediaSession); if (d->state != LinphoneCallIncomingReceived) { lError() << "Bad state " << linphone_call_state_to_string(d->state) << " for MediaSession::acceptEarlyMedia()"; @@ -4053,7 +4059,7 @@ LinphoneStatus MediaSession::acceptEarlyMedia (const std::shared_ptrsetContactOp(); /* If parameters are passed, update the media description */ if (msp) { - d->params = msp; + d->params = new MediaSessionParams(*msp); d->makeLocalMediaDescription(); sal_call_set_local_media_description(d->op, d->localDesc); sal_op_set_sent_custom_header(d->op, d->params->getPrivate()->getCustomHeaders()); @@ -4066,7 +4072,7 @@ LinphoneStatus MediaSession::acceptEarlyMedia (const std::shared_ptr msp) { +LinphoneStatus MediaSession::acceptUpdate (const MediaSessionParams *msp) { L_D(MediaSession); if (d->expectMediaInAck) { lError() << "MediaSession::acceptUpdate() is not possible during a late offer incoming reINVITE (INVITE without SDP)"; @@ -4102,7 +4108,7 @@ void MediaSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cf Address cleanedFrom = from; cleanedFrom.clean(); d->getLocalIp(cleanedFrom); - d->params = make_shared(); + d->params = new MediaSessionParams(); d->params->initDefault(d->core); d->initializeParamsAccordingToIncomingCallParams(); SalMediaDescription *md = sal_call_get_remote_media_description(d->op); @@ -4217,7 +4223,7 @@ LinphoneStatus MediaSession::resume () { void MediaSession::sendVfuRequest () { #ifdef VIDEO_ENABLED L_D(MediaSession); - shared_ptr currentParams = getCurrentParams(); + MediaSessionParams *currentParams = getCurrentParams(); if ((currentParams->avpfEnabled() || currentParams->getPrivate()->implicitRtcpFbEnabled()) && d->videoStream && media_stream_get_state(&d->videoStream->ms) == MSStreamStarted) { // || sal_media_description_has_implicit_avpf((const SalMediaDescription *)call->resultdesc) lInfo() << "Request Full Intra Request on CallSession [" << this << "]"; @@ -4302,13 +4308,13 @@ void MediaSession::stopRecording () { d->recordActive = false; } -LinphoneStatus MediaSession::update (const shared_ptr msp) { +LinphoneStatus MediaSession::update (const MediaSessionParams *msp) { L_D(MediaSession); LinphoneCallState nextState; LinphoneCallState initialState = d->state; if (!d->isUpdateAllowed(nextState)) return -1; - if (d->currentParams.get() == msp.get()) + if (d->currentParams == msp) lWarning() << "CallSession::update() is given the current params, this is probably not what you intend to do!"; d->iceAgent->checkSession(IR_Controlling, true); if (d->params) { @@ -4316,7 +4322,7 @@ LinphoneStatus MediaSession::update (const shared_ptr msp) { call->broken = FALSE; #endif d->setState(nextState, "Updating call"); - d->params = msp; + d->params = new MediaSessionParams(*msp); if (d->iceAgent->prepare(d->localDesc, false)) { lInfo() << "Defer CallSession update to gather ICE candidates"; return 0; @@ -4496,7 +4502,7 @@ float MediaSession::getAverageQuality () const { return MediaSessionPrivate::aggregateQualityRatings(audioRating, videoRating); } -shared_ptr MediaSession::getCurrentParams () { +MediaSessionParams * MediaSession::getCurrentParams () { L_D(MediaSession); d->updateCurrentParams(); return d->currentParams; @@ -4513,7 +4519,7 @@ float MediaSession::getCurrentQuality () const { return MediaSessionPrivate::aggregateQualityRatings(audioRating, videoRating); } -const shared_ptr MediaSession::getMediaParams () const { +const MediaSessionParams * MediaSession::getMediaParams () const { L_D(const MediaSession); return d->params; } @@ -4563,7 +4569,7 @@ void * MediaSession::getNativeVideoWindowId () const { return nullptr; } -const shared_ptr MediaSession::getParams () const { +const CallSessionParams * MediaSession::getParams () const { L_D(const MediaSession); return d->params; } @@ -4588,12 +4594,14 @@ float MediaSession::getRecordVolume () const { return LINPHONE_VOLUME_DB_LOWEST; } -const shared_ptr MediaSession::getRemoteParams () { +const MediaSessionParams * MediaSession::getRemoteParams () { L_D(MediaSession); if (d->op){ SalMediaDescription *md = sal_call_get_remote_media_description(d->op); if (md) { - d->remoteParams = make_shared(); + if (d->remoteParams) + delete d->remoteParams; + d->remoteParams = new MediaSessionParams(); unsigned int nbAudioStreams = sal_media_description_nb_active_streams_of_type(md, SalAudio); for (unsigned int i = 0; i < nbAudioStreams; i++) { SalStreamDescription *sd = sal_media_description_get_active_stream_of_type(md, SalAudio, i); @@ -4631,7 +4639,7 @@ const shared_ptr MediaSession::getRemoteParams () { if (ch) { /* Instanciate a remote_params only if a SIP message was received before (custom headers indicates this) */ if (!d->remoteParams) - d->remoteParams = make_shared(); + d->remoteParams = new MediaSessionParams(); d->remoteParams->getPrivate()->setCustomHeaders(ch); } return d->remoteParams; diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index 2d3d1ad10..589bf1e30 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -19,8 +19,6 @@ #ifndef _MEDIA_SESSION_H_ #define _MEDIA_SESSION_H_ -#include - #include "call-session.h" #include "conference/params/media-session-params.h" @@ -37,11 +35,11 @@ class MediaSession : public CallSession { friend class IceAgent; public: - MediaSession (const Conference &conference, const std::shared_ptr params, CallSessionListener *listener); + MediaSession (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener); - LinphoneStatus accept (const std::shared_ptr msp = nullptr); - LinphoneStatus acceptEarlyMedia (const std::shared_ptr msp = nullptr); - LinphoneStatus acceptUpdate (const std::shared_ptr msp); + LinphoneStatus accept (const MediaSessionParams *msp = nullptr); + LinphoneStatus acceptEarlyMedia (const MediaSessionParams *msp = nullptr); + LinphoneStatus acceptUpdate (const MediaSessionParams *msp); void configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalOp *op, const Address &from, const Address &to); void initiateIncoming (); bool initiateOutgoing (); @@ -53,7 +51,7 @@ public: int startInvite (const Address *destination); void startRecording (); void stopRecording (); - LinphoneStatus update (const std::shared_ptr msp); + LinphoneStatus update (const MediaSessionParams *msp); void resetFirstVideoFrameDecoded (); LinphoneStatus takePreviewSnapshot (const std::string& file); @@ -71,17 +69,17 @@ public: std::string getAuthenticationToken () const; bool getAuthenticationTokenVerified () const; float getAverageQuality () const; - std::shared_ptr getCurrentParams (); + MediaSessionParams *getCurrentParams (); float getCurrentQuality () const; - const std::shared_ptr getMediaParams () const; + const MediaSessionParams *getMediaParams () const; RtpTransport * getMetaRtcpTransport (int streamIndex); RtpTransport * getMetaRtpTransport (int streamIndex); float getMicrophoneVolumeGain () const; void * getNativeVideoWindowId () const; - const std::shared_ptr getParams () const; + const CallSessionParams *getParams () const; float getPlayVolume () const; float getRecordVolume () const; - const std::shared_ptr getRemoteParams (); + const MediaSessionParams *getRemoteParams (); float getSpeakerVolumeGain () const; LinphoneCallStats * getStats (LinphoneStreamType type) const; int getStreamCount (); From 22e5d08aa2ed0c9911d9ed3724ee1d1d47668526 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 13 Sep 2017 17:50:00 +0200 Subject: [PATCH 0049/2215] feat(variant): add getValueAsBool impl --- include/linphone/utils/utils.h | 4 ++ src/utils/utils.cpp | 12 +++++ src/variant/variant.cpp | 93 ++++++++++++++++++++++++++++++++-- 3 files changed, 106 insertions(+), 3 deletions(-) diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h index 91897090c..ccf43a9de 100644 --- a/include/linphone/utils/utils.h +++ b/include/linphone/utils/utils.h @@ -49,6 +49,10 @@ namespace Utils { LINPHONE_PUBLIC int stoi (const std::string &str, size_t *idx = 0, int base = 10); + LINPHONE_PUBLIC std::string stringToLower (const std::string &str); + + LINPHONE_PUBLIC bool stringToBool (const std::string &str); + // Return a buffer allocated with new. LINPHONE_PUBLIC char *utf8ToChar (uint32_t ic); diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 1fea89566..d3ad01afc 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +#include #include #include @@ -87,6 +88,17 @@ int Utils::stoi (const string &str, size_t *idx, int base) { return v; } +string Utils::stringToLower (const string &str) { + string result(str.size(), ' '); + transform(str.cbegin(), str.cend(), result.begin(), ::tolower); + return result; +} + +bool Utils::stringToBool (const string &str) { + const string lowerStr = stringToLower(str); + return !lowerStr.empty() && (lowerStr == "true" || lowerStr == "1"); +} + char *Utils::utf8ToChar (uint32_t ic) { char *result = new char[5]; int size = 0; diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index fa18701ed..8edfdcfb9 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +#include "linphone/utils/utils.h" + #include "variant.h" // ============================================================================= @@ -39,9 +41,12 @@ public: bool b; double d; float f; + string *str; + void *g; }; - Variant::Type type = Variant::Invalid; + // Integer, because type can be a custom type. + int type = Variant::Invalid; Value value = {}; }; @@ -182,6 +187,56 @@ void Variant::swap (const Variant &variant) { // TODO. } +// ----------------------------------------------------------------------------- +// Number helpers. +// ----------------------------------------------------------------------------- + +static inline long long getAssumedNumber (const VariantPrivate &p) { + L_ASSERT(p.type > Variant::Invalid && p.type < Variant::MaxDefaultTypes); + + switch (static_cast(p.type)) { + case Variant::Int: + return p.value.i; + case Variant::Short: + return p.value.s; + case Variant::Long: + return p.value.l; + case Variant::LongLong: + return p.value.ll; + case Variant::Char: + return p.value.c; + case Variant::Double: + return p.value.d; + case Variant::Float: + return p.value.f; + + default: + L_ASSERT(false); + } + + return 0; +} + +static inline unsigned long long getAssumedUnsignedNumber (const VariantPrivate &p) { + L_ASSERT(p.type > Variant::Invalid && p.type < Variant::MaxDefaultTypes); + + switch (static_cast(p.type)) { + case Variant::UnsignedInt: + return p.value.ui; + case Variant::UnsignedShort: + return p.value.us; + case Variant::UnsignedLong: + return p.value.ul; + case Variant::UnsignedLongLong: + return p.value.ull; + + default: + L_ASSERT(false); + } + + return 0; +} + // ----------------------------------------------------------------------------- // Number conversions. // ----------------------------------------------------------------------------- @@ -201,7 +256,39 @@ static inline unsigned long long getValueAsUnsignedNumber (const VariantPrivate // ----------------------------------------------------------------------------- static inline bool getValueAsBool (const VariantPrivate &p, bool *soFarSoGood) { - // TODO. + L_ASSERT(p.type > Variant::Invalid && p.type < Variant::MaxDefaultTypes); + + *soFarSoGood = true; + switch (static_cast(p.type)) { + case Variant::Int: + case Variant::Short: + case Variant::Long: + case Variant::LongLong: + case Variant::Char: + case Variant::Double: + case Variant::Float: + return static_cast(getAssumedNumber(p)); + + case Variant::UnsignedInt: + case Variant::UnsignedShort: + case Variant::UnsignedLong: + case Variant::UnsignedLongLong: + return static_cast(getAssumedUnsignedNumber(p)); + + case Variant::Bool: + return p.value.b; + + case Variant::String: + return Utils::stringToBool(*p.value.str); + + case Variant::Generic: + return static_cast(p.value.g); + + default: + *soFarSoGood = false; + break; + } + return false; } @@ -230,7 +317,7 @@ static inline void *getValueAsGeneric (const VariantPrivate &p, bool *soFarSoGoo void Variant::getValue (int type, void *value, bool *soFarSoGood) const { L_D(const Variant); - if (type <= 0 || type >= MaxDefaultTypes) { + if (type <= Invalid || type >= MaxDefaultTypes) { *soFarSoGood = false; // Unable to get value. It will be great to support custom types. return; From df45d5f1f03d6ae2813512cbe07cf2b889577d87 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 13 Sep 2017 17:54:34 +0200 Subject: [PATCH 0050/2215] Allow adding additional fields when declaring a C struct. --- src/c-wrapper/c-tools.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index ce811af34..0f4855089 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -158,10 +158,11 @@ LINPHONE_END_NAMESPACE // ----------------------------------------------------------------------------- -#define L_DECLARE_C_STRUCT_IMPL(STRUCT, C_NAME) \ +#define L_DECLARE_C_STRUCT_IMPL(STRUCT, C_NAME, ...) \ struct _Linphone ## STRUCT { \ belle_sip_object_t base; \ std::shared_ptr cppPtr; \ + __VA_ARGS__ \ }; \ BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## STRUCT); \ static Linphone ## STRUCT *_linphone_ ## C_NAME ## _init() { \ @@ -184,11 +185,12 @@ LINPHONE_END_NAMESPACE FALSE \ ); -#define L_DECLARE_C_CLONABLE_STRUCT_IMPL(CPP_CLASS, C_STRUCT, C_NAME) \ +#define L_DECLARE_C_CLONABLE_STRUCT_IMPL(CPP_CLASS, C_STRUCT, C_NAME, ...) \ struct _Linphone ## C_STRUCT { \ belle_sip_object_t base; \ void *userData; \ LINPHONE_NAMESPACE::CPP_CLASS *cppPtr; \ + __VA_ARGS__ \ }; \ BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_STRUCT); \ static Linphone ## C_STRUCT *_linphone_ ## C_NAME ## _init() { \ From 79604de277751fab7c5de2e104da6e9b88f71b92 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 14 Sep 2017 09:23:09 +0200 Subject: [PATCH 0051/2215] Store the NAT policy in the media session, not in the call session. --- src/conference/session/call-session-p.h | 1 - src/conference/session/call-session.cpp | 8 -------- src/conference/session/media-session-p.h | 1 + src/conference/session/media-session.cpp | 8 ++++++++ 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index 2c9ed1c79..857c33105 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -93,7 +93,6 @@ protected: LinphoneProxyConfig *destProxy = nullptr; LinphoneErrorInfo *ei = nullptr; LinphoneCallLog *log = nullptr; - LinphoneNatPolicy *natPolicy = nullptr; SalOp *op = nullptr; diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index b87892db8..aff406142 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -59,8 +59,6 @@ CallSessionPrivate::~CallSessionPrivate () { linphone_error_info_unref(ei); if (log) linphone_call_log_unref(log); - if (natPolicy) - linphone_nat_policy_unref(natPolicy); if (op) sal_op_release(op); } @@ -786,12 +784,6 @@ void CallSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg } d->log = linphone_call_log_new(direction, fromAddr, toAddr); - if (d->destProxy) - d->natPolicy = linphone_proxy_config_get_nat_policy(d->destProxy); - if (!d->natPolicy) - d->natPolicy = linphone_core_get_nat_policy(d->core); - linphone_nat_policy_ref(d->natPolicy); - if (op) { /* We already have an op for incoming calls */ d->op = op; diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index 2207fbdef..79286f99e 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -261,6 +261,7 @@ private: RtpProfile *textProfile = nullptr; int mainTextStreamIndex = LINPHONE_CALL_STATS_TEXT; + LinphoneNatPolicy *natPolicy = nullptr; StunClient *stunClient = nullptr; IceAgent *iceAgent = nullptr; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 6158379de..9c2f9c933 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -103,6 +103,8 @@ MediaSessionPrivate::~MediaSessionPrivate () { linphone_call_stats_unref(videoStats); if (textStats) linphone_call_stats_unref(textStats); + if (natPolicy) + linphone_nat_policy_unref(natPolicy); if (stunClient) delete stunClient; delete iceAgent; @@ -4087,6 +4089,12 @@ void MediaSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cf L_D(MediaSession); CallSession::configure (direction, cfg, op, from, to); + if (d->destProxy) + d->natPolicy = linphone_proxy_config_get_nat_policy(d->destProxy); + if (!d->natPolicy) + d->natPolicy = linphone_core_get_nat_policy(d->core); + linphone_nat_policy_ref(d->natPolicy); + if (direction == LinphoneCallOutgoing) { d->selectOutgoingIpVersion(); d->getLocalIp(to); From f4f31dc4227582232985eb6922a90c42598136e0 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 14 Sep 2017 09:28:41 +0200 Subject: [PATCH 0052/2215] feat(variant): add getValueAsDouble impl --- include/linphone/utils/utils.h | 4 ++-- src/utils/utils.cpp | 20 +++++++++++++----- src/variant/variant.cpp | 38 ++++++++++++++++++++++++++++++++-- 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h index ccf43a9de..ddb9eb40a 100644 --- a/include/linphone/utils/utils.h +++ b/include/linphone/utils/utils.h @@ -48,11 +48,11 @@ namespace Utils { LINPHONE_PUBLIC std::string toString (long double val); LINPHONE_PUBLIC int stoi (const std::string &str, size_t *idx = 0, int base = 10); + LINPHONE_PUBLIC double stod (const std::string &str, size_t *idx = 0); + LINPHONE_PUBLIC bool stob (const std::string &str); LINPHONE_PUBLIC std::string stringToLower (const std::string &str); - LINPHONE_PUBLIC bool stringToBool (const std::string &str); - // Return a buffer allocated with new. LINPHONE_PUBLIC char *utf8ToChar (uint32_t ic); diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index d3ad01afc..9e4033f4d 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -88,17 +88,27 @@ int Utils::stoi (const string &str, size_t *idx, int base) { return v; } +double Utils::stod (const std::string &str, size_t *idx) { + char *p; + double v = strtod(str.c_str(), &p); + + if (idx) + *idx = p - str.c_str(); + + return v; +} + +bool Utils::stob (const string &str) { + const string lowerStr = stringToLower(str); + return !lowerStr.empty() && (lowerStr == "true" || lowerStr == "1"); +} + string Utils::stringToLower (const string &str) { string result(str.size(), ' '); transform(str.cbegin(), str.cend(), result.begin(), ::tolower); return result; } -bool Utils::stringToBool (const string &str) { - const string lowerStr = stringToLower(str); - return !lowerStr.empty() && (lowerStr == "true" || lowerStr == "1"); -} - char *Utils::utf8ToChar (uint32_t ic) { char *result = new char[5]; int size = 0; diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index 8edfdcfb9..33c89a4e3 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -279,7 +279,7 @@ static inline bool getValueAsBool (const VariantPrivate &p, bool *soFarSoGood) { return p.value.b; case Variant::String: - return Utils::stringToBool(*p.value.str); + return Utils::stob(*p.value.str); case Variant::Generic: return static_cast(p.value.g); @@ -293,7 +293,41 @@ static inline bool getValueAsBool (const VariantPrivate &p, bool *soFarSoGood) { } static inline double getValueAsDouble (const VariantPrivate &p, bool *soFarSoGood) { - // TODO. + L_ASSERT(p.type > Variant::Invalid && p.type < Variant::MaxDefaultTypes); + + *soFarSoGood = true; + switch (static_cast(p.type)) { + case Variant::Int: + case Variant::Short: + case Variant::Long: + case Variant::LongLong: + case Variant::Char: + case Variant::Float: + return static_cast(getAssumedNumber(p)); + + case Variant::UnsignedInt: + case Variant::UnsignedShort: + case Variant::UnsignedLong: + case Variant::UnsignedLongLong: + return static_cast(getAssumedUnsignedNumber(p)); + + case Variant::Double: + return p.value.d; + + case Variant::Bool: + return static_cast(p.value.b); + + case Variant::String: + return Utils::stod(*p.value.str); + + case Variant::Generic: + return static_cast(!!p.value.g); + + default: + *soFarSoGood = false; + break; + } + return 0.0; } From 8127798358f230be338cc54a7c3029db0af46813 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 14 Sep 2017 09:41:19 +0200 Subject: [PATCH 0053/2215] fix(CallLog): better api... --- coreapi/call_log.c | 24 ++++++++++++------------ include/linphone/call_log.h | 24 ++++++++++++------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/coreapi/call_log.c b/coreapi/call_log.c index 54088adc4..e69346ec6 100644 --- a/coreapi/call_log.c +++ b/coreapi/call_log.c @@ -171,15 +171,15 @@ const char *linphone_call_log_get_call_id(const LinphoneCallLog *cl){ return cl->call_id; } -LinphoneCallDir linphone_call_log_get_dir(LinphoneCallLog *cl){ +LinphoneCallDir linphone_call_log_get_dir(const LinphoneCallLog *cl){ return cl->dir; } -int linphone_call_log_get_duration(LinphoneCallLog *cl){ +int linphone_call_log_get_duration(const LinphoneCallLog *cl){ return cl->duration; } -const LinphoneAddress *linphone_call_log_get_from_address(LinphoneCallLog *cl){ +const LinphoneAddress *linphone_call_log_get_from_address(const LinphoneCallLog *cl){ return cl->from; } @@ -187,7 +187,7 @@ const rtp_stats_t *linphone_call_log_get_local_stats(const LinphoneCallLog *cl){ return &cl->local_stats; } -float linphone_call_log_get_quality(LinphoneCallLog *cl){ +float linphone_call_log_get_quality(const LinphoneCallLog *cl){ return cl->quality; } @@ -195,7 +195,7 @@ const char *linphone_call_log_get_ref_key(const LinphoneCallLog *cl){ return cl->refkey; } -LinphoneAddress *linphone_call_log_get_remote_address(LinphoneCallLog *cl){ +LinphoneAddress *linphone_call_log_get_remote_address(const LinphoneCallLog *cl){ return (cl->dir == LinphoneCallIncoming) ? cl->from : cl->to; } @@ -203,15 +203,15 @@ const rtp_stats_t *linphone_call_log_get_remote_stats(const LinphoneCallLog *cl) return &cl->remote_stats; } -time_t linphone_call_log_get_start_date(LinphoneCallLog *cl){ +time_t linphone_call_log_get_start_date(const LinphoneCallLog *cl){ return cl->start_date_time; } -LinphoneCallStatus linphone_call_log_get_status(LinphoneCallLog *cl){ +LinphoneCallStatus linphone_call_log_get_status(const LinphoneCallLog *cl){ return cl->status; } -const LinphoneAddress *linphone_call_log_get_to_address(LinphoneCallLog *cl){ +const LinphoneAddress *linphone_call_log_get_to_address(const LinphoneCallLog *cl){ return cl->to; } @@ -223,7 +223,7 @@ void linphone_call_log_set_ref_key(LinphoneCallLog *cl, const char *refkey){ if (refkey) cl->refkey=ms_strdup(refkey); } -char * linphone_call_log_to_str(LinphoneCallLog *cl){ +char * linphone_call_log_to_str(const LinphoneCallLog *cl){ const char *status; char *tmp; char *from=linphone_address_as_string (cl->from); @@ -260,15 +260,15 @@ char * linphone_call_log_to_str(LinphoneCallLog *cl){ return tmp; } -bool_t linphone_call_log_video_enabled(LinphoneCallLog *cl) { +bool_t linphone_call_log_video_enabled(const LinphoneCallLog *cl) { return cl->video_enabled; } -bool_t linphone_call_log_was_conference(LinphoneCallLog *cl) { +bool_t linphone_call_log_was_conference(const LinphoneCallLog *cl) { return cl->was_conference; } -const LinphoneErrorInfo *linphone_call_log_get_error_info(LinphoneCallLog *cl){ +const LinphoneErrorInfo *linphone_call_log_get_error_info(const LinphoneCallLog *cl){ return cl->error_info; } diff --git a/include/linphone/call_log.h b/include/linphone/call_log.h index fb5e743e1..cd833391c 100644 --- a/include/linphone/call_log.h +++ b/include/linphone/call_log.h @@ -48,21 +48,21 @@ LINPHONE_PUBLIC const char * linphone_call_log_get_call_id(const LinphoneCallLog * @param[in] cl LinphoneCallLog object * @return The direction of the call. **/ -LINPHONE_PUBLIC LinphoneCallDir linphone_call_log_get_dir(LinphoneCallLog *cl); +LINPHONE_PUBLIC LinphoneCallDir linphone_call_log_get_dir(const LinphoneCallLog *cl); /** * Get the duration of the call since connected. * @param[in] cl LinphoneCallLog object * @return The duration of the call in seconds. **/ -LINPHONE_PUBLIC int linphone_call_log_get_duration(LinphoneCallLog *cl); +LINPHONE_PUBLIC int linphone_call_log_get_duration(const LinphoneCallLog *cl); /** * Get the origin address (ie from) of the call. * @param[in] cl LinphoneCallLog object * @return The origin address (ie from) of the call. **/ -LINPHONE_PUBLIC const LinphoneAddress * linphone_call_log_get_from_address(LinphoneCallLog *cl); +LINPHONE_PUBLIC const LinphoneAddress * linphone_call_log_get_from_address(const LinphoneCallLog *cl); /** * Get the RTP statistics computed locally regarding the call. @@ -76,7 +76,7 @@ LINPHONE_PUBLIC const rtp_stats_t * linphone_call_log_get_local_stats(const Linp * @param[in] cl LinphoneCallLog object * @return The overall quality indication of the call. **/ -LINPHONE_PUBLIC float linphone_call_log_get_quality(LinphoneCallLog *cl); +LINPHONE_PUBLIC float linphone_call_log_get_quality(const LinphoneCallLog *cl); /** * Get the persistent reference key associated to the call log. @@ -94,7 +94,7 @@ LINPHONE_PUBLIC const char * linphone_call_log_get_ref_key(const LinphoneCallLog * @param[in] cl LinphoneCallLog object * @return The remote address of the call. **/ -LINPHONE_PUBLIC LinphoneAddress * linphone_call_log_get_remote_address(LinphoneCallLog *cl); +LINPHONE_PUBLIC LinphoneAddress * linphone_call_log_get_remote_address(const LinphoneCallLog *cl); /** * Get the RTP statistics computed by the remote end and sent back via RTCP. @@ -109,21 +109,21 @@ LINPHONE_PUBLIC const rtp_stats_t * linphone_call_log_get_remote_stats(const Lin * @param[in] cl LinphoneCallLog object * @return The date of the beginning of the call. **/ -LINPHONE_PUBLIC time_t linphone_call_log_get_start_date(LinphoneCallLog *cl); +LINPHONE_PUBLIC time_t linphone_call_log_get_start_date(const LinphoneCallLog *cl); /** * Get the status of the call. * @param[in] cl LinphoneCallLog object * @return The status of the call. **/ -LINPHONE_PUBLIC LinphoneCallStatus linphone_call_log_get_status(LinphoneCallLog *cl); +LINPHONE_PUBLIC LinphoneCallStatus linphone_call_log_get_status(const LinphoneCallLog *cl); /** * Get the destination address (ie to) of the call. * @param[in] cl LinphoneCallLog object * @return The destination address (ie to) of the call. **/ -LINPHONE_PUBLIC const LinphoneAddress * linphone_call_log_get_to_address(LinphoneCallLog *cl); +LINPHONE_PUBLIC const LinphoneAddress * linphone_call_log_get_to_address(const LinphoneCallLog *cl); /** * Associate a persistent reference key to the call log. @@ -141,7 +141,7 @@ LINPHONE_PUBLIC void linphone_call_log_set_ref_key(LinphoneCallLog *cl, const ch * @param[in] cl LinphoneCallLog object * @return A boolean value telling whether video was enabled at the end of the call. **/ -LINPHONE_PUBLIC bool_t linphone_call_log_video_enabled(LinphoneCallLog *cl); +LINPHONE_PUBLIC bool_t linphone_call_log_video_enabled(const LinphoneCallLog *cl); /** * Get a human readable string describing the call. @@ -149,21 +149,21 @@ LINPHONE_PUBLIC bool_t linphone_call_log_video_enabled(LinphoneCallLog *cl); * @param[in] cl LinphoneCallLog object * @return A human readable string describing the call. **/ -LINPHONE_PUBLIC char * linphone_call_log_to_str(LinphoneCallLog *cl); +LINPHONE_PUBLIC char * linphone_call_log_to_str(const LinphoneCallLog *cl); /** * Tells whether that call was a call to a conference server * @param[in] cl #LinphoneCallLog object * @return TRUE if the call was a call to a conference server */ -LINPHONE_PUBLIC bool_t linphone_call_log_was_conference(LinphoneCallLog *cl); +LINPHONE_PUBLIC bool_t linphone_call_log_was_conference(const LinphoneCallLog *cl); /** * When the call was failed, return an object describing the failure. * @param[in] cl #LinphoneCallLog object * @return information about the error encountered by the call associated with this call log. **/ -LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_call_log_get_error_info(LinphoneCallLog *cl); +LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_call_log_get_error_info(const LinphoneCallLog *cl); /******************************************************************************* From f8f072fb3d784419f357891ae6849241e4ed597f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 14 Sep 2017 11:15:36 +0200 Subject: [PATCH 0054/2215] Handle C back pointer in C++ objects. --- src/c-wrapper/c-tools.h | 42 +++++++++++++++++++++++++++++----- src/object/clonable-object-p.h | 4 ++++ src/object/clonable-object.cpp | 16 +++++++++++++ src/object/clonable-object.h | 8 +++++++ src/variant/variant.h | 2 +- 5 files changed, 65 insertions(+), 7 deletions(-) diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index 0f4855089..4fbb27a49 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -22,6 +22,8 @@ #include #include +#include "variant/variant.h" + // From coreapi. #include "private.h" @@ -97,18 +99,21 @@ public: } template - static inline void setCppPtrFromC (void *object, std::shared_ptr &cppPtr) { + static inline void setCppPtrFromC (void *object, const std::shared_ptr &cppPtr) { L_ASSERT(object); static_cast *>(object)->cppPtr = cppPtr; + cppPtr->setProperty("LinphonePrivate::Wrapper::cBackPtr", object); } template - static inline void setCppPtrFromC (void *object, T *cppPtr) { + static inline void setCppPtrFromC (void *object, const T *cppPtr) { L_ASSERT(object); - T *tPtr = reinterpret_cast(static_cast *>(object)->cppPtr); - if (tPtr != cppPtr) { - delete tPtr; - static_cast *>(object)->cppPtr = new T(*cppPtr); + T *oldPtr = reinterpret_cast(static_cast *>(object)->cppPtr); + if (oldPtr != cppPtr) { + delete oldPtr; + T *cppObject = static_cast *>(object)->cppPtr; + cppObject = new T(*cppPtr); + cppObject->setProperty("LinphonePrivate::Wrapper::cBackPtr", object); } } @@ -122,6 +127,28 @@ public: return cppPtr; } + template + static inline CType * getCBackPtr (const std::shared_ptr &object, CType *(*cTypeAllocator)()) { + Variant v = object->getProperty("LinphonePrivate::Wrapper::cBackPtr"); + void *value = v.getValue(); + if (!value) { + CType *cObject = cTypeAllocator(); + setCppPtrFromC(cObject, object); + } + return reinterpret_cast(value); + } + + template + static inline CType * getCBackPtr (const CppType *object, CType *(*cTypeAllocator)()) { + Variant v = object->getProperty("LinphonePrivate::Wrapper::cBackPtr"); + void *value = v.getValue(); + if (!value) { + CType *cObject = cTypeAllocator(); + setCppPtrFromC(cObject, object); + } + return reinterpret_cast(value); + } + // --------------------------------------------------------------------------- template @@ -235,6 +262,9 @@ LINPHONE_END_NAMESPACE L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE, C_TYPE) \ )) +#define L_GET_C_BACK_PTR(OBJECT, C_TYPE, C_NAME) \ + LINPHONE_NAMESPACE::Wrapper::getCBackPtr(OBJECT, _linphone_ ## C_NAME ## _init) + #define L_GET_C_LIST_FROM_CPP_LIST(LIST, TYPE) \ LINPHONE_NAMESPACE::Wrapper::getCListFromCppList(LIST) #define L_GET_CPP_LIST_FROM_C_LIST(LIST, TYPE) \ diff --git a/src/object/clonable-object-p.h b/src/object/clonable-object-p.h index 7d507599f..87266a2c5 100644 --- a/src/object/clonable-object-p.h +++ b/src/object/clonable-object-p.h @@ -23,6 +23,8 @@ #include "linphone/utils/general.h" +#include "variant/variant.h" + // ============================================================================= LINPHONE_BEGIN_NAMESPACE @@ -41,6 +43,8 @@ private: int nRefs = 0; + std::unordered_map properties; + L_DECLARE_PUBLIC(ClonableObject); // It's forbidden to copy directly one Clonable object private. diff --git a/src/object/clonable-object.cpp b/src/object/clonable-object.cpp index 45412dc88..72a9f290d 100644 --- a/src/object/clonable-object.cpp +++ b/src/object/clonable-object.cpp @@ -82,4 +82,20 @@ void ClonableObject::setRef (const ClonableObjectPrivate &p) { mPrivate->ref(); } +Variant ClonableObject::getProperty (const string &name) const { + L_D(const ClonableObject); + auto it = d->properties.find(name); + return it == d->properties.cend() ? Variant() : it->second; +} + +void ClonableObject::setProperty (const string &name, const Variant &value) { + L_D(ClonableObject); + d->properties[name] = value; +} + +void ClonableObject::setProperty (const string &name, Variant &&value) { + L_D(ClonableObject); + d->properties[name] = move(value); +} + LINPHONE_END_NAMESPACE diff --git a/src/object/clonable-object.h b/src/object/clonable-object.h index 34d4771c6..e36c5add2 100644 --- a/src/object/clonable-object.h +++ b/src/object/clonable-object.h @@ -19,16 +19,24 @@ #ifndef _CLONABLE_OBJECT_H_ #define _CLONABLE_OBJECT_H_ +#include + #include "linphone/utils/general.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE +class Variant; + class LINPHONE_PUBLIC ClonableObject { public: virtual ~ClonableObject (); + Variant getProperty (const std::string &name) const; + void setProperty (const std::string &name, const Variant &value); + void setProperty (const std::string &name, Variant &&value); + protected: // Use a new ClonableObjectPrivate without owner. explicit ClonableObject (ClonableObjectPrivate &p); diff --git a/src/variant/variant.h b/src/variant/variant.h index 2966f79d1..4b1ffe529 100644 --- a/src/variant/variant.h +++ b/src/variant/variant.h @@ -82,7 +82,7 @@ public: template::value> > // void* constructor. Must be explicitly called. - Variant (T value); + Variant (T value) {} ~Variant (); From 7c4de39e804768ffc8cfb26a1ddbd037096c7aa9 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 14 Sep 2017 11:16:08 +0200 Subject: [PATCH 0055/2215] Do not access the internal C++ pointer directly, use the c-tools macro for that. --- src/c-wrapper/api/c-call-params.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index 2b130b39b..f20de1e19 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -516,8 +516,8 @@ void linphone_call_params_unref(LinphoneCallParams *cp) { LinphoneCallParams * linphone_call_params_new(LinphoneCore *core) { LinphoneCallParams *params = _linphone_call_params_init(); - params->cppPtr = new LinphonePrivate::MediaSessionParams(); - params->cppPtr->initDefault(core); + L_SET_CPP_PTR_FROM_C_STRUCT(params, new LinphonePrivate::MediaSessionParams()); + GET_MEDIA_CPP_PTR(params)->initDefault(core); return params; } From bef0f90bf5fd1c7a8a54027cf91b312e26777d04 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 14 Sep 2017 11:17:04 +0200 Subject: [PATCH 0056/2215] Add the canHandleParticipants() method to the conference interface. --- src/chat/basic-chat-room.cpp | 4 ++++ src/chat/basic-chat-room.h | 1 + src/chat/client-group-chat-room.cpp | 4 ++++ src/chat/client-group-chat-room.h | 1 + src/chat/real-time-text-chat-room.cpp | 4 ++++ src/chat/real-time-text-chat-room.h | 1 + src/conference/conference-interface.h | 1 + src/conference/conference.cpp | 4 ++++ src/conference/conference.h | 1 + 9 files changed, 21 insertions(+) diff --git a/src/chat/basic-chat-room.cpp b/src/chat/basic-chat-room.cpp index a83535d03..0fe854161 100644 --- a/src/chat/basic-chat-room.cpp +++ b/src/chat/basic-chat-room.cpp @@ -44,6 +44,10 @@ void BasicChatRoom::addParticipants (const list
&addresses, const CallS lError() << "addParticipants() is not allowed on a BasicChatRoom"; } +bool BasicChatRoom::canHandleParticipants () const { + return false; +} + const string& BasicChatRoom::getId () const { L_D(const BasicChatRoom); lError() << "a BasicChatRoom does not have a conference id"; diff --git a/src/chat/basic-chat-room.h b/src/chat/basic-chat-room.h index 3c696c67d..4f6ec7d50 100644 --- a/src/chat/basic-chat-room.h +++ b/src/chat/basic-chat-room.h @@ -41,6 +41,7 @@ public: /* ConferenceInterface */ std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia); void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia); + bool canHandleParticipants () const; const std::string& getId () const; int getNbParticipants () const; std::list> getParticipants () const; diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 47ad6a2e5..2181a5b0e 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -54,6 +54,10 @@ void ClientGroupChatRoom::addParticipants (const list
&addresses, const // TODO } +bool ClientGroupChatRoom::canHandleParticipants () const { + return true; +} + const string& ClientGroupChatRoom::getId () const { return id; } diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index b32d5951f..849af656e 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -42,6 +42,7 @@ public: /* ConferenceInterface */ std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia); void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia); + bool canHandleParticipants () const; const std::string& getId () const; int getNbParticipants () const; std::list> getParticipants () const; diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 2f352f3d8..91b9fcf13 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -149,6 +149,10 @@ void RealTimeTextChatRoom::addParticipants (const list
&addresses, cons lError() << "addParticipants() is not allowed on a RealTimeTextChatRoom"; } +bool RealTimeTextChatRoom::canHandleParticipants () const { + return false; +} + const string& RealTimeTextChatRoom::getId () const { L_D(const RealTimeTextChatRoom); lError() << "a RealTimeTextChatRoom does not have a conference id"; diff --git a/src/chat/real-time-text-chat-room.h b/src/chat/real-time-text-chat-room.h index 949691722..a75f08d67 100644 --- a/src/chat/real-time-text-chat-room.h +++ b/src/chat/real-time-text-chat-room.h @@ -45,6 +45,7 @@ public: /* ConferenceInterface */ std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia); void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia); + bool canHandleParticipants () const; const std::string& getId () const; int getNbParticipants () const; std::list> getParticipants () const; diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index 840675c8c..4cdcb7f32 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -36,6 +36,7 @@ public: virtual std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) = 0; virtual void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia) = 0; + virtual bool canHandleParticipants () const = 0; virtual const std::string& getId () const = 0; virtual int getNbParticipants () const = 0; virtual std::list> getParticipants () const = 0; diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 1d9e6666c..cca7d4cbf 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -49,6 +49,10 @@ void Conference::addParticipants (const list
&addresses, const CallSess // TODO } +bool Conference::canHandleParticipants () const { + return true; +} + const string& Conference::getId () const { return id; } diff --git a/src/conference/conference.h b/src/conference/conference.h index 6f4886ff0..5c22f918f 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -52,6 +52,7 @@ public: /* ConferenceInterface */ virtual std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia); virtual void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia); + virtual bool canHandleParticipants () const; virtual const std::string& getId () const; virtual int getNbParticipants () const; virtual std::list> getParticipants () const; From d6bf89b6e4359360a571abfd75dd3363ffab8ea7 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 14 Sep 2017 14:32:21 +0200 Subject: [PATCH 0057/2215] feat(Variant): impl setValue --- src/variant/variant.cpp | 34 ++++++++++++++++++++++++---------- src/variant/variant.h | 13 ++++++++++--- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index 33c89a4e3..a37c6f3bf 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -51,11 +51,18 @@ public: }; Variant::Variant () { - // Nothing. Construct an invalid invariant. + if (!mPrivate) + mPrivate = new VariantPrivate(); } -Variant::Variant (Type type) { - // TODO. +Variant::Variant (Type type) : Variant() { + if (type != String) + return; + + L_D(Variant); + + if (!d->value.str) + d->value.str = new string(); } Variant::Variant (const Variant &src) { @@ -126,12 +133,17 @@ Variant::Variant (float value) : Variant(Float) { d->value.f = value; } -Variant::Variant (const std::string &value) { - // TODO. +Variant::Variant (const std::string &value) : Variant(String) { + L_D(Variant); + *d->value.str = value; } Variant::~Variant () { - // TODO. + L_D(Variant); + if (d->type == String) + delete d->value.str; + + delete mPrivate; } bool Variant::operator!= (const Variant &variant) const { @@ -175,8 +187,8 @@ bool Variant::operator>= (const Variant &variant) const { } bool Variant::isValid () const { - // TODO. - return false; + L_D(const Variant); + return d->type != Invalid; } void Variant::clear () { @@ -349,11 +361,13 @@ static inline void *getValueAsGeneric (const VariantPrivate &p, bool *soFarSoGoo // ----------------------------------------------------------------------------- void Variant::getValue (int type, void *value, bool *soFarSoGood) const { + L_ASSERT(type > Invalid && type != MaxDefaultTypes); + L_D(const Variant); - if (type <= Invalid || type >= MaxDefaultTypes) { + if (type > MaxDefaultTypes) { *soFarSoGood = false; - // Unable to get value. It will be great to support custom types. + // TODO: Unable to get value. It will be great to support custom types. return; } diff --git a/src/variant/variant.h b/src/variant/variant.h index 4b1ffe529..3eeb9090b 100644 --- a/src/variant/variant.h +++ b/src/variant/variant.h @@ -80,9 +80,9 @@ public: Variant (float value); Variant (const std::string &value); - template::value> > // void* constructor. Must be explicitly called. - Variant (T value) {} + template::value> > + Variant (T value) : Variant (Variant::createGeneric(value)) {} ~Variant (); @@ -97,7 +97,8 @@ public: template void setValue (const T &value) { - // TODO. + // Yeah, I'm crazy. + new (this) Variant(value); } template @@ -128,6 +129,12 @@ private: void getValue (int type, void *value, bool *soFarSoGood) const; + static inline Variant createGeneric (void *value) { + Variant variant(Generic); + variant.setValue(value); + return variant; + } + VariantPrivate *mPrivate = nullptr; L_DECLARE_PRIVATE(Variant); From bd2c2c4ce794bd9eb34d2878842472914fe0ac3d Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 14 Sep 2017 14:40:01 +0200 Subject: [PATCH 0058/2215] fix(Variant): avoid loop in generic variant creation --- src/variant/variant.cpp | 6 ++++++ src/variant/variant.h | 6 +----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index a37c6f3bf..c43499a95 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -427,4 +427,10 @@ void Variant::getValue (int type, void *value, bool *soFarSoGood) const { } } +Variant Variant::createGeneric (void *value) { + Variant variant(Generic); + variant.getPrivate()->value.g = value; + return variant; +} + LINPHONE_END_NAMESPACE diff --git a/src/variant/variant.h b/src/variant/variant.h index 3eeb9090b..c05df2930 100644 --- a/src/variant/variant.h +++ b/src/variant/variant.h @@ -129,11 +129,7 @@ private: void getValue (int type, void *value, bool *soFarSoGood) const; - static inline Variant createGeneric (void *value) { - Variant variant(Generic); - variant.setValue(value); - return variant; - } + static Variant createGeneric (void *value); VariantPrivate *mPrivate = nullptr; From 0102ef79fc9506cdd37e2c074bfa2c1ad047dab6 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 14 Sep 2017 14:52:22 +0200 Subject: [PATCH 0059/2215] feaf(core): remove useless std... --- src/c-wrapper/api/c-call-params.cpp | 15 ++++++++------- src/call/call.cpp | 8 ++++---- src/chat/client-group-chat-room.cpp | 6 +++--- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index f20de1e19..3b4d06c7f 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -25,15 +25,16 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "conference/params/call-session-params-p.h" #include "conference/params/media-session-params-p.h" - #define GET_CALL_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, CallSessionParams, CallParams) #define GET_CALL_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, CallSessionParams, CallParams) #define GET_MEDIA_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, MediaSessionParams, CallParams) #define GET_MEDIA_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, MediaSessionParams, CallParams) - L_DECLARE_C_CLONABLE_STRUCT_IMPL(MediaSessionParams, CallParams, call_params) +// ============================================================================= + +using namespace std; /******************************************************************************* * Internal functions * @@ -149,17 +150,17 @@ void linphone_call_params_enable_video(LinphoneCallParams *params, bool_t enable } const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name) { - std::string value = GET_MEDIA_CPP_PTR(params)->getCustomHeader(header_name); + string value = GET_MEDIA_CPP_PTR(params)->getCustomHeader(header_name); return value.empty() ? nullptr : value.c_str(); } const char * linphone_call_params_get_custom_sdp_attribute(const LinphoneCallParams *params, const char *attribute_name) { - std::string value = GET_MEDIA_CPP_PTR(params)->getCustomSdpAttribute(attribute_name); + string value = GET_MEDIA_CPP_PTR(params)->getCustomSdpAttribute(attribute_name); return value.empty() ? nullptr : value.c_str(); } const char * linphone_call_params_get_custom_sdp_media_attribute(const LinphoneCallParams *params, LinphoneStreamType type, const char *attribute_name) { - std::string value = GET_MEDIA_CPP_PTR(params)->getCustomSdpMediaAttribute(type, attribute_name); + string value = GET_MEDIA_CPP_PTR(params)->getCustomSdpMediaAttribute(type, attribute_name); return value.empty() ? nullptr : value.c_str(); } @@ -197,7 +198,7 @@ const LinphoneVideoDefinition * linphone_call_params_get_received_video_definiti } const char *linphone_call_params_get_record_file(const LinphoneCallParams *params) { - const std::string &value = GET_MEDIA_CPP_PTR(params)->getRecordFilePath(); + const string &value = GET_MEDIA_CPP_PTR(params)->getRecordFilePath(); return value.empty() ? nullptr : value.c_str(); } @@ -227,7 +228,7 @@ const LinphoneVideoDefinition * linphone_call_params_get_sent_video_definition(c } const char *linphone_call_params_get_session_name(const LinphoneCallParams *params) { - const std::string &value = GET_MEDIA_CPP_PTR(params)->getSessionName(); + const string &value = GET_MEDIA_CPP_PTR(params)->getSessionName(); return value.empty() ? nullptr : value.c_str(); } diff --git a/src/call/call.cpp b/src/call/call.cpp index d8ee56d40..678468ea4 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -137,7 +137,7 @@ void CallPrivate::onCallSetTerminated () { } } -void CallPrivate::onCallStateChanged (LinphoneCallState state, const std::string &message) { +void CallPrivate::onCallStateChanged (LinphoneCallState state, const string &message) { if (lcall) linphone_call_notify_state_changed(lcall, state, message.c_str()); } @@ -152,7 +152,7 @@ void CallPrivate::onIncomingCallToBeAdded () { linphone_core_add_call(core, lcall); } -void CallPrivate::onEncryptionChanged (bool activated, const std::string &authToken) { +void CallPrivate::onEncryptionChanged (bool activated, const string &authToken) { if (lcall) linphone_call_notify_encryption_changed(lcall, activated, authToken.empty() ? nullptr : authToken.c_str()); } @@ -255,12 +255,12 @@ void Call::stopRecording () { static_cast(d->getActiveSession().get())->stopRecording(); } -LinphoneStatus Call::takePreviewSnapshot (const std::string& file) { +LinphoneStatus Call::takePreviewSnapshot (const string& file) { L_D(Call); return static_cast(d->getActiveSession().get())->takePreviewSnapshot(file); } -LinphoneStatus Call::takeVideoSnapshot (const std::string& file) { +LinphoneStatus Call::takeVideoSnapshot (const string& file) { L_D(Call); return static_cast(d->getActiveSession().get())->takeVideoSnapshot(file); } diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 2181a5b0e..282303219 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -20,17 +20,17 @@ #include "conference/participant-p.h" #include "logger/logger.h" +// ============================================================================= + using namespace std; LINPHONE_BEGIN_NAMESPACE -// ============================================================================= - ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core) : ChatRoomPrivate(core) {} // ============================================================================= -ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, std::list
&addresses) +ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, list
&addresses) : ChatRoom(*new ChatRoomPrivate(core)), RemoteConference(core, me, nullptr) { string factoryUri = linphone_core_get_chat_conference_factory_uri(core); focus = make_shared(factoryUri); From af09244d95635bf9a96dcf4594a7d71821503025 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 14 Sep 2017 14:56:18 +0200 Subject: [PATCH 0060/2215] fix(CpimParser): simplify code on message headers creation --- src/chat/cpim/parser/cpim-parser.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/chat/cpim/parser/cpim-parser.cpp b/src/chat/cpim/parser/cpim-parser.cpp index 15f6a1c6e..e6207d82c 100644 --- a/src/chat/cpim/parser/cpim-parser.cpp +++ b/src/chat/cpim/parser/cpim-parser.cpp @@ -189,16 +189,13 @@ namespace Cpim { // Add message headers. if (mHeaders->size() > 2) { - list>::iterator it = mHeaders->begin(); - std::advance(it, 1); - shared_ptr messageHeaders = *it; - for (const auto &headerNode : *messageHeaders) { + for (const auto &headerNode : **(++mHeaders->cbegin())) { const shared_ptr header = headerNode->createHeader(); if (!header || !message->addMessageHeader(*header)) return nullptr; } } - + // Add content headers. for (const auto &headerNode : *mHeaders->back()) { const shared_ptr header = headerNode->createHeader(); From d4d2794cd3c6571e74bd9bdcff5a07535a91eb9d Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 14 Sep 2017 15:21:29 +0200 Subject: [PATCH 0061/2215] feat(Object): add a PropertyContainer class --- src/CMakeLists.txt | 2 + src/object/clonable-object-p.h | 4 -- src/object/clonable-object.cpp | 16 -------- src/object/clonable-object.h | 10 ++--- src/object/object.cpp | 16 -------- src/object/object.h | 12 ++---- src/object/property-container.cpp | 61 +++++++++++++++++++++++++++++++ src/object/property-container.h | 54 +++++++++++++++++++++++++++ 8 files changed, 123 insertions(+), 52 deletions(-) create mode 100644 src/object/property-container.cpp create mode 100644 src/object/property-container.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 773f308f8..4c2fe44a2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -89,6 +89,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES object/clonable-object.h object/object-p.h object/object.h + object/property-container.h object/singleton.h utils/payload-type-handler.h variant/variant.h @@ -140,6 +141,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES nat/stun-client.cpp object/clonable-object.cpp object/object.cpp + object/property-container.cpp utils/general.cpp utils/payload-type-handler.cpp utils/utils.cpp diff --git a/src/object/clonable-object-p.h b/src/object/clonable-object-p.h index 87266a2c5..7d507599f 100644 --- a/src/object/clonable-object-p.h +++ b/src/object/clonable-object-p.h @@ -23,8 +23,6 @@ #include "linphone/utils/general.h" -#include "variant/variant.h" - // ============================================================================= LINPHONE_BEGIN_NAMESPACE @@ -43,8 +41,6 @@ private: int nRefs = 0; - std::unordered_map properties; - L_DECLARE_PUBLIC(ClonableObject); // It's forbidden to copy directly one Clonable object private. diff --git a/src/object/clonable-object.cpp b/src/object/clonable-object.cpp index 72a9f290d..45412dc88 100644 --- a/src/object/clonable-object.cpp +++ b/src/object/clonable-object.cpp @@ -82,20 +82,4 @@ void ClonableObject::setRef (const ClonableObjectPrivate &p) { mPrivate->ref(); } -Variant ClonableObject::getProperty (const string &name) const { - L_D(const ClonableObject); - auto it = d->properties.find(name); - return it == d->properties.cend() ? Variant() : it->second; -} - -void ClonableObject::setProperty (const string &name, const Variant &value) { - L_D(ClonableObject); - d->properties[name] = value; -} - -void ClonableObject::setProperty (const string &name, Variant &&value) { - L_D(ClonableObject); - d->properties[name] = move(value); -} - LINPHONE_END_NAMESPACE diff --git a/src/object/clonable-object.h b/src/object/clonable-object.h index e36c5add2..89fe66b3f 100644 --- a/src/object/clonable-object.h +++ b/src/object/clonable-object.h @@ -23,20 +23,16 @@ #include "linphone/utils/general.h" +#include "property-container.h" + // ============================================================================= LINPHONE_BEGIN_NAMESPACE -class Variant; - -class LINPHONE_PUBLIC ClonableObject { +class LINPHONE_PUBLIC ClonableObject : public PropertyContainer { public: virtual ~ClonableObject (); - Variant getProperty (const std::string &name) const; - void setProperty (const std::string &name, const Variant &value); - void setProperty (const std::string &name, Variant &&value); - protected: // Use a new ClonableObjectPrivate without owner. explicit ClonableObject (ClonableObjectPrivate &p); diff --git a/src/object/object.cpp b/src/object/object.cpp index b201df143..01457e82d 100644 --- a/src/object/object.cpp +++ b/src/object/object.cpp @@ -34,20 +34,4 @@ Object::Object (ObjectPrivate &p) : mPrivate(&p) { mPrivate->mPublic = this; } -Variant Object::getProperty (const string &name) const { - L_D(const Object); - auto it = d->properties.find(name); - return it == d->properties.cend() ? Variant() : it->second; -} - -void Object::setProperty (const string &name, const Variant &value) { - L_D(Object); - d->properties[name] = value; -} - -void Object::setProperty (const string &name, Variant &&value) { - L_D(Object); - d->properties[name] = move(value); -} - LINPHONE_END_NAMESPACE diff --git a/src/object/object.h b/src/object/object.h index 0941664d9..7dae752a6 100644 --- a/src/object/object.h +++ b/src/object/object.h @@ -19,24 +19,18 @@ #ifndef _OBJECT_H_ #define _OBJECT_H_ -#include - #include "linphone/utils/general.h" +#include "property-container.h" + // ============================================================================= LINPHONE_BEGIN_NAMESPACE -class Variant; - -class LINPHONE_PUBLIC Object { +class LINPHONE_PUBLIC Object : public PropertyContainer { public: virtual ~Object (); - Variant getProperty (const std::string &name) const; - void setProperty (const std::string &name, const Variant &value); - void setProperty (const std::string &name, Variant &&value); - protected: explicit Object (ObjectPrivate &p); diff --git a/src/object/property-container.cpp b/src/object/property-container.cpp new file mode 100644 index 000000000..0cbc8f712 --- /dev/null +++ b/src/object/property-container.cpp @@ -0,0 +1,61 @@ +/* + * property-container.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include + +#include "property-container.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +class PropertyContainerPrivate { +public: + unordered_map properties; +}; + +// ----------------------------------------------------------------------------- + +// Empty copy constructor. Don't change this pattern. +// PropertyContainer is an Entity component, not a simple structure. +// An Entity is UNIQUE. +PropertyContainer::PropertyContainer (const PropertyContainer &) {} + +PropertyContainer &PropertyContainer::operator= (const PropertyContainer &) { + return *this; +} + +Variant PropertyContainer::getProperty (const string &name) const { + L_D(const PropertyContainer); + auto it = d->properties.find(name); + return it == d->properties.cend() ? Variant() : it->second; +} + +void PropertyContainer::setProperty (const string &name, const Variant &value) { + L_D(PropertyContainer); + d->properties[name] = value; +} + +void PropertyContainer::setProperty (const string &name, Variant &&value) { + L_D(PropertyContainer); + d->properties[name] = move(value); +} + +LINPHONE_END_NAMESPACE diff --git a/src/object/property-container.h b/src/object/property-container.h new file mode 100644 index 000000000..c8cf7724d --- /dev/null +++ b/src/object/property-container.h @@ -0,0 +1,54 @@ +/* + * property-container.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _PROPERTY_CONTAINER_H_ +#define _PROPERTY_CONTAINER_H_ + +#include + +#include "linphone/utils/general.h" + +#include "variant/variant.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class PropertyContainerPrivate; + +class LINPHONE_PUBLIC PropertyContainer { +public: + PropertyContainer () = default; + PropertyContainer (const PropertyContainer &src); + virtual ~PropertyContainer () = default; + + PropertyContainer &operator= (const PropertyContainer &src); + + Variant getProperty (const std::string &name) const; + void setProperty (const std::string &name, const Variant &value); + void setProperty (const std::string &name, Variant &&value); + +private: + PropertyContainerPrivate *mPrivate = nullptr; + + L_DECLARE_PRIVATE(PropertyContainer); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _PROPERTY_CONTAINER_H_ From d09232f31394e485d0d9d65b8ee3bc97a683e3ec Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 14 Sep 2017 15:30:54 +0200 Subject: [PATCH 0062/2215] fix(PropertyContainer): create correctly private data --- src/object/property-container.cpp | 8 +++++++- src/object/property-container.h | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/object/property-container.cpp b/src/object/property-container.cpp index 0cbc8f712..fadc32082 100644 --- a/src/object/property-container.cpp +++ b/src/object/property-container.cpp @@ -33,10 +33,16 @@ public: // ----------------------------------------------------------------------------- +PropertyContainer::PropertyContainer () : mPrivate(new PropertyContainerPrivate) {} + // Empty copy constructor. Don't change this pattern. // PropertyContainer is an Entity component, not a simple structure. // An Entity is UNIQUE. -PropertyContainer::PropertyContainer (const PropertyContainer &) {} +PropertyContainer::PropertyContainer (const PropertyContainer &) : mPrivate(new PropertyContainerPrivate) {} + +PropertyContainer::~PropertyContainer () { + delete mPrivate; +} PropertyContainer &PropertyContainer::operator= (const PropertyContainer &) { return *this; diff --git a/src/object/property-container.h b/src/object/property-container.h index c8cf7724d..67dab6034 100644 --- a/src/object/property-container.h +++ b/src/object/property-container.h @@ -33,9 +33,9 @@ class PropertyContainerPrivate; class LINPHONE_PUBLIC PropertyContainer { public: - PropertyContainer () = default; + PropertyContainer (); PropertyContainer (const PropertyContainer &src); - virtual ~PropertyContainer () = default; + virtual ~PropertyContainer (); PropertyContainer &operator= (const PropertyContainer &src); From 261b8cc88008b466b4337dcd5ce597c5786e9627 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 14 Sep 2017 15:46:01 +0200 Subject: [PATCH 0063/2215] feat(Variant): add copy constructor impl --- src/variant/variant.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index c43499a95..2c1ab35e1 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -66,7 +66,18 @@ Variant::Variant (Type type) : Variant() { } Variant::Variant (const Variant &src) { - // TODO. + // Don't call placement new. + L_ASSERT(!mPrivate); + mPrivate = new VariantPrivate(); + + L_D(Variant); + d->type = src.getPrivate()->type; + + const VariantPrivate::Value &value = src.getPrivate()->value; + if (d->type == String) + d->value.str = new string(*value.str); + else + d->value = value; } Variant::Variant (Variant &&src) { From 1d02af0650c4d572b115a393a49e409cd9da2ba5 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 14 Sep 2017 15:47:59 +0200 Subject: [PATCH 0064/2215] feat(Variant): add copy constructor (with r-value) impl --- src/variant/variant.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index 2c1ab35e1..14bc77141 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -81,7 +81,10 @@ Variant::Variant (const Variant &src) { } Variant::Variant (Variant &&src) { - // TODO. + // Don't call placement new. + L_ASSERT(!mPrivate); + mPrivate = src.mPrivate; + src.mPrivate = nullptr; } Variant::Variant (int value) : Variant(Int) { From 4732e417d721d6fc1c4660faab0535696e51fb67 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 14 Sep 2017 16:11:50 +0200 Subject: [PATCH 0065/2215] feat(Variant): add getValueAsGeneric impl --- src/variant/variant.cpp | 7 ++++- tester/CMakeLists.txt | 1 + tester/liblinphone_tester.h | 1 + tester/property-container-tester.cpp | 44 ++++++++++++++++++++++++++++ tester/tester.c | 1 + 5 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 tester/property-container-tester.cpp diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index 14bc77141..484e3fb9b 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -368,7 +368,12 @@ static inline float getValueAsString (const VariantPrivate &p, bool *soFarSoGood } static inline void *getValueAsGeneric (const VariantPrivate &p, bool *soFarSoGood) { - // TODO. + if (p.type == Variant::Generic) { + *soFarSoGood = true; + return p.value.g; + } + + *soFarSoGood = false; return nullptr; } diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index cb3c58fa1..2169fe567 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -199,6 +199,7 @@ set(SOURCE_FILES_CXX clonable-object-tester.cpp cpim-tester.cpp events-db-tester.cpp + property-container-tester.cpp ) set(SOURCE_FILES_OBJC ) diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 8bd915e62..ed764e09f 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -56,6 +56,7 @@ extern test_suite_t offeranswer_test_suite; extern test_suite_t player_test_suite; extern test_suite_t presence_server_test_suite; extern test_suite_t presence_test_suite; +extern test_suite_t property_container_test_suite; extern test_suite_t proxy_config_test_suite; extern test_suite_t quality_reporting_test_suite; extern test_suite_t register_test_suite; diff --git a/tester/property-container-tester.cpp b/tester/property-container-tester.cpp new file mode 100644 index 000000000..eb01e4fd1 --- /dev/null +++ b/tester/property-container-tester.cpp @@ -0,0 +1,44 @@ +/* + * property-container-tester.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "object/property-container.h" + +#include "liblinphone_tester.h" + +// ============================================================================= + +using namespace std; + +using namespace LinphonePrivate; + +// ----------------------------------------------------------------------------- + +static void set_integer_property () { + PropertyContainer properties; + properties.setProperty("integer", 42); + BC_ASSERT_EQUAL(properties.getProperty("integer").getValue(), 42, int, "%d"); +} + +test_t property_container_tests[] = { + TEST_NO_TAG("Set int property", set_integer_property) +}; + +test_suite_t property_container_test_suite = { + "PropertyContainer", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each, + sizeof(property_container_tests) / sizeof(property_container_tests[0]), property_container_tests +}; diff --git a/tester/tester.c b/tester/tester.c index f2bae99df..1fb24d0f1 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -573,6 +573,7 @@ void liblinphone_tester_add_suites() { bc_tester_add_suite(&cpim_test_suite); bc_tester_add_suite(&clonable_object_test_suite); bc_tester_add_suite(&events_db_test_suite); + bc_tester_add_suite(&property_container_test_suite); #if defined(VIDEO_ENABLED) && defined(HAVE_GTK) bc_tester_add_suite(&video_test_suite); #endif From 8e9bbb689912ec65539f3b8688bcdcd86e5ead5f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 14 Sep 2017 15:21:49 +0200 Subject: [PATCH 0066/2215] Use c-tools for LinphoneChatRoom. --- coreapi/chat.c | 221 +++----------------- coreapi/chat_file_transfer.c | 7 +- coreapi/message_storage.c | 43 ---- coreapi/private.h | 2 + include/linphone/chat.h | 3 +- src/CMakeLists.txt | 1 + src/c-wrapper/api/c-call-params.cpp | 33 ++- src/c-wrapper/api/c-chat-room.cpp | 251 +++++++++++++++++++++++ src/c-wrapper/api/c-event-log.cpp | 4 +- src/c-wrapper/c-tools.h | 76 ++++--- src/chat/chat-room-p.h | 8 - src/chat/chat-room.cpp | 38 ++-- src/chat/real-time-text-chat-room.cpp | 6 +- src/conference/session/call-session.cpp | 4 +- src/conference/session/call-session.h | 4 +- src/conference/session/media-session.cpp | 2 +- src/object/object.h | 5 +- 17 files changed, 391 insertions(+), 317 deletions(-) create mode 100644 src/c-wrapper/api/c-chat-room.cpp diff --git a/coreapi/chat.c b/coreapi/chat.c index 9aa35ed7e..8e9f2b59b 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -42,14 +42,6 @@ #include "chat/real-time-text-chat-room-p.h" #include "content/content-type.h" -struct _LinphoneChatRoom{ - belle_sip_object_t base; - void *user_data; - LinphonePrivate::ChatRoom *cr; - LinphoneAddress *peerAddressCache; -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneChatRoom); static void _linphone_chat_message_destroy(LinphoneChatMessage *msg); @@ -165,47 +157,14 @@ const bctbx_list_t *linphone_core_get_chat_rooms(LinphoneCore *lc) { return lc->chatrooms; } -static bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from) { - LinphoneAddress *addr = linphone_address_new(cr->cr->getPeerAddress().asString().c_str()); - bool_t result = linphone_address_weak_equal(addr, from); - linphone_address_unref(addr); - return result; -} - -BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneChatRoom); - -static void _linphone_chat_room_destroy(LinphoneChatRoom *cr) { - delete cr->cr; - if (cr->peerAddressCache) { - linphone_address_unref(cr->peerAddressCache); - cr->peerAddressCache = nullptr; - } -} - -BELLE_SIP_INSTANCIATE_VPTR(LinphoneChatRoom, belle_sip_object_t, - (belle_sip_object_destroy_t)_linphone_chat_room_destroy, - NULL, // clone - NULL, // marshal - FALSE); - -LinphoneChatRoom *_linphone_core_create_chat_room_base(LinphoneCore *lc, const LinphoneAddress *addr) { - LinphoneChatRoom *cr = belle_sip_object_new(LinphoneChatRoom); - if (linphone_core_realtime_text_enabled(lc)) - cr->cr = new LinphonePrivate::RealTimeTextChatRoom(lc, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address, Address)); - else - cr->cr = new LinphonePrivate::BasicChatRoom(lc, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address, Address)); - L_GET_PRIVATE(cr->cr)->setCBackPointer(cr); - return cr; -} - static LinphoneChatRoom *_linphone_core_create_chat_room(LinphoneCore *lc, const LinphoneAddress *addr) { - LinphoneChatRoom *cr = _linphone_core_create_chat_room_base(lc, addr); + LinphoneChatRoom *cr = linphone_chat_room_new(lc, addr); lc->chatrooms = bctbx_list_append(lc->chatrooms, (void *)cr); return cr; } LinphoneChatRoom *_linphone_core_create_chat_room_from_call(LinphoneCall *call){ - LinphoneChatRoom *cr = _linphone_core_create_chat_room_base(linphone_call_get_core(call), + LinphoneChatRoom *cr = linphone_chat_room_new(linphone_call_get_core(call), linphone_address_clone(linphone_call_get_remote_address(call))); linphone_chat_room_set_call(cr, call); return cr; @@ -219,6 +178,13 @@ static LinphoneChatRoom *_linphone_core_create_chat_room_from_url(LinphoneCore * return NULL; } +static bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from) { + LinphoneAddress *addr = linphone_address_new(L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)->getPeerAddress().asString().c_str()); + bool_t result = linphone_address_weak_equal(addr, from); + linphone_address_unref(addr); + return result; +} + LinphoneChatRoom *_linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr) { LinphoneChatRoom *cr = NULL; bctbx_list_t *elem; @@ -256,24 +222,8 @@ LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAd return ret; } -LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, bctbx_list_t *addresses) { - const char *factoryUri = linphone_core_get_chat_conference_factory_uri(lc); - if (!factoryUri) - return nullptr; - LinphoneChatRoom *cr = belle_sip_object_new(LinphoneChatRoom); - LinphoneAddress *factoryAddr = linphone_address_new(factoryUri); - LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(lc, factoryAddr); - linphone_address_unref(factoryAddr); - std::string from; - if (proxy) - from = L_GET_CPP_PTR_FROM_C_STRUCT(linphone_proxy_config_get_identity_address(proxy), Address, Address)->asString(); - if (from.empty()) - from = linphone_core_get_primary_contact(lc); - LinphonePrivate::Address me(from); - std::list l = L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(addresses, Address); - cr->cr = new LinphonePrivate::ClientGroupChatRoom(lc, me, l); - L_GET_PRIVATE(cr->cr)->setCBackPointer(cr); - return cr; +LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, const bctbx_list_t *addresses) { + return linphone_client_group_chat_room_new(lc, addresses); } void linphone_core_delete_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr) { @@ -290,48 +240,15 @@ LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const c return _linphone_core_get_or_create_chat_room(lc, to); } -void linphone_chat_room_destroy(LinphoneChatRoom *cr) { - linphone_chat_room_unref(cr); -} - -void linphone_chat_room_release(LinphoneChatRoom *cr) { - L_GET_PRIVATE(cr->cr)->release(); -} - -LinphoneChatRoom *linphone_chat_room_ref(LinphoneChatRoom *cr) { - belle_sip_object_ref(cr); - return cr; -} - -void linphone_chat_room_unref(LinphoneChatRoom *cr) { - belle_sip_object_unref(cr); -} - -void *linphone_chat_room_get_user_data(const LinphoneChatRoom *cr) { - return cr->user_data; -} - -void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void *ud) { - cr->user_data = ud; -} - -void linphone_chat_room_remove_transient_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { - L_GET_PRIVATE(cr->cr)->removeTransientMessage(msg); -} - void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state) { linphone_chat_message_set_state(msg, new_state); linphone_chat_message_store_state(msg); if (msg->state == LinphoneChatMessageStateDelivered || msg->state == LinphoneChatMessageStateNotDelivered) { - L_GET_PRIVATE(msg->chat_room->cr)->moveTransientMessageToWeakMessages(msg); + L_GET_PRIVATE_FROM_C_STRUCT(msg->chat_room, ChatRoom, ChatRoom)->moveTransientMessageToWeakMessages(msg); } } -void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg) { - cr->cr->sendMessage(cr->cr->createMessage(msg)); -} - void create_file_transfer_information_from_vnd_gsma_rcs_ft_http_xml(LinphoneChatMessage *msg) { xmlChar *file_url = NULL; xmlDocPtr xmlMessageBody; @@ -415,76 +332,11 @@ int linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage LinphoneAddress *addr = linphone_address_new(sal_msg->from); linphone_address_clean(addr); LinphoneChatRoom *cr = linphone_core_get_chat_room(lc, addr); - LinphoneReason reason = L_GET_PRIVATE(cr->cr)->messageReceived(op, sal_msg); + LinphoneReason reason = L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)->messageReceived(op, sal_msg); linphone_address_unref(addr); return reason; } -bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr) { - return cr->cr->isRemoteComposing(); -} - -LinphoneCore *linphone_chat_room_get_lc(const LinphoneChatRoom *cr) { - return linphone_chat_room_get_core(cr); -} - -LinphoneCore *linphone_chat_room_get_core(const LinphoneChatRoom *cr) { - return cr->cr->getCore(); -} - -const LinphoneAddress *linphone_chat_room_get_peer_address(LinphoneChatRoom *cr) { - if (cr->peerAddressCache) { - linphone_address_unref(cr->peerAddressCache); - } - cr->peerAddressCache = linphone_address_new(cr->cr->getPeerAddress().asString().c_str()); - return cr->peerAddressCache; -} - -LinphoneChatMessage *linphone_chat_room_create_message(LinphoneChatRoom *cr, const char *message) { - return cr->cr->createMessage(message ? message : ""); -} - -LinphoneChatMessage *linphone_chat_room_create_message_2(LinphoneChatRoom *cr, const char *message, - const char *external_body_url, LinphoneChatMessageState state, - time_t time, bool_t is_read, bool_t is_incoming) { - LinphoneChatMessage *msg = linphone_chat_room_create_message(cr, message); - LinphoneCore *lc = linphone_chat_room_get_core(cr); - msg->external_body_url = external_body_url ? ms_strdup(external_body_url) : NULL; - msg->time = time; - msg->is_secured = FALSE; - linphone_chat_message_set_state(msg, state); - if (is_incoming) { - msg->dir = LinphoneChatMessageIncoming; - linphone_chat_message_set_from(msg, linphone_chat_room_get_peer_address(cr)); - msg->to = linphone_address_new(linphone_core_get_identity(lc)); /*direct assignment*/ - } else { - msg->dir = LinphoneChatMessageOutgoing; - linphone_chat_message_set_to(msg, linphone_chat_room_get_peer_address(cr)); - msg->from = linphone_address_new(linphone_core_get_identity(lc));/*direct assignment*/ - } - return msg; -} - -void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage *msg, - LinphoneChatMessageStateChangedCb status_cb, void *ud) { - msg->message_state_changed_cb = status_cb; - msg->message_state_changed_user_data = ud; - cr->cr->sendMessage(msg); -} - -void linphone_chat_room_send_chat_message_2(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { - linphone_chat_message_ref(msg); - cr->cr->sendMessage(msg); -} - -void linphone_chat_room_send_chat_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { - cr->cr->sendMessage(msg); -} - -LinphonePrivate::ChatRoom& linphone_chat_room_get_cpp_obj(LinphoneChatRoom *cr) { - return *cr->cr; -} - void _linphone_chat_message_resend(LinphoneChatMessage *msg, bool_t ref_msg) { LinphoneChatMessageState state = linphone_chat_message_get_state(msg); LinphoneChatRoom *cr; @@ -496,7 +348,7 @@ void _linphone_chat_message_resend(LinphoneChatMessage *msg, bool_t ref_msg) { cr = linphone_chat_message_get_chat_room(msg); if (ref_msg) linphone_chat_message_ref(msg); - cr->cr->sendMessage(msg); + L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)->sendMessage(msg); } void linphone_chat_message_resend(LinphoneChatMessage *msg) { @@ -612,7 +464,7 @@ static char *linphone_chat_message_create_imdn_xml(LinphoneChatMessage *cm, Imdn void linphone_chat_message_send_imdn(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason) { char *content = linphone_chat_message_create_imdn_xml(cm, imdn_type, reason); if (content) { - L_GET_PRIVATE(linphone_chat_message_get_chat_room(cm)->cr)->sendImdn(content, reason); + L_GET_PRIVATE_FROM_C_STRUCT(linphone_chat_message_get_chat_room(cm), ChatRoom, ChatRoom)->sendImdn(content, reason); ms_free(content); } } @@ -636,21 +488,21 @@ void linphone_chat_message_send_display_notification(LinphoneChatMessage *cm) { } void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, uint32_t character, LinphoneCall *call) { - if (linphone_core_realtime_text_enabled(lc)) - L_GET_PRIVATE(static_cast(cr->cr))->realtimeTextReceived(character, call); -} - -uint32_t linphone_chat_room_get_char(const LinphoneChatRoom *cr) { - if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) - return static_cast(cr->cr)->getChar(); - return 0; + if (linphone_core_realtime_text_enabled(lc)) { + std::shared_ptr rttcr = + std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)); + L_GET_PRIVATE(rttcr)->realtimeTextReceived(character, call); + //L_GET_PRIVATE(std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)))->realtimeTextReceived(character, call); + } } LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg, uint32_t character) { LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) { - LinphoneCall *call = static_cast(cr->cr)->getCall(); - LinphoneCore *lc = static_cast(cr->cr)->getCore(); + std::shared_ptr rttcr = + std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)); + LinphoneCall *call = rttcr->getCall(); + LinphoneCore *lc = rttcr->getCore(); const uint32_t new_line = 0x2028; const uint32_t crlf = 0x0D0A; const uint32_t lf = 0x0A; @@ -688,24 +540,6 @@ const char* linphone_chat_message_get_message_id(const LinphoneChatMessage *cm) return cm->message_id; } -void linphone_chat_room_compose(LinphoneChatRoom *cr) { - cr->cr->compose(); -} - -LinphoneCall *linphone_chat_room_get_call(const LinphoneChatRoom *room) { - if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(room))) - return static_cast(room->cr)->getCall(); - return nullptr; -} - -void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call) { - L_GET_PRIVATE(cr->cr)->setCall(call); -} - -bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr) { - return L_GET_C_LIST_FROM_CPP_LIST(L_GET_PRIVATE(cr->cr)->getTransientMessages(), LinphoneChatMessage); -} - const char *linphone_chat_message_state_to_string(const LinphoneChatMessageState state) { switch (state) { case LinphoneChatMessageStateIdle: @@ -814,10 +648,7 @@ const LinphoneAddress *linphone_chat_message_get_to_address(const LinphoneChatMe if (msg->to) return msg->to; if (msg->dir == LinphoneChatMessageOutgoing) { - if (msg->chat_room->peerAddressCache) - linphone_address_unref(msg->chat_room->peerAddressCache); - msg->chat_room->peerAddressCache = linphone_address_new(msg->chat_room->cr->getPeerAddress().asString().c_str()); - return msg->chat_room->peerAddressCache; + return linphone_chat_room_get_peer_address(msg->chat_room); } return NULL; } diff --git a/coreapi/chat_file_transfer.c b/coreapi/chat_file_transfer.c index 02fb3daa3..0fb84a566 100644 --- a/coreapi/chat_file_transfer.c +++ b/coreapi/chat_file_transfer.c @@ -26,10 +26,9 @@ #include "private.h" #include "ortp/b64.h" +#include "c-wrapper/c-tools.h" #include "chat/chat-room.h" -extern LinphonePrivate::ChatRoom& linphone_chat_room_get_cpp_obj(LinphoneChatRoom *cr); - static bool_t file_transfer_in_progress_and_valid(LinphoneChatMessage* msg) { return (msg->chat_room && linphone_chat_room_get_core(msg->chat_room) && msg->http_request && !belle_http_request_is_cancelled(msg->http_request)); } @@ -342,7 +341,7 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co linphone_chat_message_ref(msg); linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone); _release_http_request(msg); - linphone_chat_room_get_cpp_obj(msg->chat_room).sendMessage(msg); + L_GET_CPP_PTR_FROM_C_STRUCT(msg->chat_room, ChatRoom, ChatRoom)->sendMessage(msg); file_upload_end_background_task(msg); linphone_chat_message_unref(msg); } else { @@ -658,5 +657,5 @@ const char *linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage } LinphoneChatMessage *linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent *initial_content) { - return linphone_chat_room_get_cpp_obj(cr).createFileTransferMessage(initial_content); + return L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)->createFileTransferMessage(initial_content); } diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 0b9b39bd0..75b76246c 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -43,9 +43,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include -extern LinphonePrivate::ChatRoom& linphone_chat_room_get_cpp_obj(LinphoneChatRoom *cr); - - static char *utf8_convert(const char *filename){ char db_file_utf8[MAX_PATH_SIZE] = ""; #if defined(_WIN32) @@ -316,46 +313,6 @@ void linphone_chat_message_store_appdata(LinphoneChatMessage* msg){ } } -void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr) { - linphone_chat_room_get_cpp_obj(cr).markAsRead(); -} - -int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr) { - return linphone_chat_room_get_cpp_obj(cr).getUnreadMessagesCount(); -} - -int linphone_chat_room_get_history_size(LinphoneChatRoom *cr) { - return linphone_chat_room_get_cpp_obj(cr).getHistorySize(); -} - -void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { - linphone_chat_room_get_cpp_obj(cr).deleteMessage(msg); -} - -void linphone_chat_room_delete_history(LinphoneChatRoom *cr) { - linphone_chat_room_get_cpp_obj(cr).deleteHistory(); -} - -bctbx_list_t *linphone_chat_room_get_history_range(LinphoneChatRoom *cr, int startm, int endm) { - std::list l = linphone_chat_room_get_cpp_obj(cr).getHistoryRange(startm, endm); - bctbx_list_t *result = nullptr; - for (auto it = l.begin(); it != l.end(); it++) - result = bctbx_list_append(result, *it); - return result; -} - -bctbx_list_t *linphone_chat_room_get_history(LinphoneChatRoom *cr, int nb_message) { - std::list l = linphone_chat_room_get_cpp_obj(cr).getHistory(nb_message); - bctbx_list_t *result = nullptr; - for (auto it = l.begin(); it != l.end(); it++) - result = bctbx_list_append(result, *it); - return result; -} - -LinphoneChatMessage * linphone_chat_room_find_message(LinphoneChatRoom *cr, const char *message_id) { - return linphone_chat_room_get_cpp_obj(cr).findMessage(message_id); -} - static void linphone_create_history_table(sqlite3* db){ char* errmsg=NULL; int ret; diff --git a/coreapi/private.h b/coreapi/private.h index a7e650847..95f98514e 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -503,6 +503,8 @@ void _linphone_proxy_config_unregister(LinphoneProxyConfig *obj); void _linphone_proxy_config_release_ops(LinphoneProxyConfig *obj); /*chat*/ +LinphoneChatRoom * linphone_chat_room_new(LinphoneCore *core, const LinphoneAddress *addr); +LinphoneChatRoom * linphone_client_group_chat_room_new(LinphoneCore *lc, const bctbx_list_t *addresses); void linphone_chat_room_release(LinphoneChatRoom *cr); void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call); bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr); diff --git a/include/linphone/chat.h b/include/linphone/chat.h index 3bc02d839..a3e581064 100644 --- a/include/linphone/chat.h +++ b/include/linphone/chat.h @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define LINPHONE_CHAT_H_ +#include "linphone/callbacks.h" #include "linphone/types.h" @@ -457,7 +458,7 @@ LINPHONE_PUBLIC void linphone_chat_message_set_user_data(LinphoneChatMessage* me **/ LINPHONE_PUBLIC LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg); -LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, bctbx_list_t *addresses); +LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, const bctbx_list_t *addresses); LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4c2fe44a2..7ed8e1602 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -99,6 +99,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES address/address.cpp c-wrapper/api/c-address.cpp c-wrapper/api/c-call-params.cpp + c-wrapper/api/c-chat-room.cpp c-wrapper/api/c-event-log.cpp call/call.cpp chat/basic-chat-room.cpp diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index 3b4d06c7f..ead25cae9 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -1,21 +1,20 @@ /* -linphone -Copyright (C) 2010-2014 Belledonne Communications SARL - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ + * c-call-params.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ #include "linphone/call_params.h" #include "private.h" diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp new file mode 100644 index 000000000..f48c6b473 --- /dev/null +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -0,0 +1,251 @@ +/* + * c-chat-room.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + + +#include "linphone/chat.h" +#include "linphone/wrapper_utils.h" +#include "private.h" + +#include "c-wrapper/c-tools.h" +#include "chat/basic-chat-room.h" +#include "chat/chat-room.h" +#include "chat/chat-room-p.h" +#include "chat/client-group-chat-room.h" +#include "chat/real-time-text-chat-room.h" +#include "chat/real-time-text-chat-room-p.h" + +using namespace std; + +#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, ChatRoom, ChatRoom) +#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, ChatRoom, ChatRoom) + + +static void _linphone_chat_room_constructor(LinphoneChatRoom *cr); +static void _linphone_chat_room_destructor(LinphoneChatRoom *cr); + +L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(ChatRoom, ChatRoom, chat_room, + _linphone_chat_room_constructor, _linphone_chat_room_destructor, + LinphoneAddress *peerAddressCache; +) + +static void _linphone_chat_room_constructor(LinphoneChatRoom *cr) {} + +static void _linphone_chat_room_destructor(LinphoneChatRoom *cr) { + if (cr->peerAddressCache) { + linphone_address_unref(cr->peerAddressCache); + cr->peerAddressCache = nullptr; + } +} + + +/******************************************************************************* + * Public functions * + ******************************************************************************/ + +void linphone_chat_room_release(LinphoneChatRoom *cr) { + GET_CPP_PRIVATE_PTR(cr)->release(); +} + +void linphone_chat_room_remove_transient_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { + GET_CPP_PRIVATE_PTR(cr)->removeTransientMessage(msg); +} + +void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg) { + GET_CPP_PTR(cr)->sendMessage(GET_CPP_PTR(cr)->createMessage(msg)); +} + +bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr) { + return GET_CPP_PTR(cr)->isRemoteComposing(); +} + +LinphoneCore *linphone_chat_room_get_lc(const LinphoneChatRoom *cr) { + return linphone_chat_room_get_core(cr); +} + +LinphoneCore *linphone_chat_room_get_core(const LinphoneChatRoom *cr) { + return GET_CPP_PTR(cr)->getCore(); +} + +const LinphoneAddress *linphone_chat_room_get_peer_address(LinphoneChatRoom *cr) { + if (cr->peerAddressCache) { + linphone_address_unref(cr->peerAddressCache); + } + cr->peerAddressCache = linphone_address_new(GET_CPP_PTR(cr)->getPeerAddress().asString().c_str()); + return cr->peerAddressCache; +} + +LinphoneChatMessage *linphone_chat_room_create_message(LinphoneChatRoom *cr, const char *message) { + return GET_CPP_PTR(cr)->createMessage(message ? message : ""); +} + +LinphoneChatMessage *linphone_chat_room_create_message_2(LinphoneChatRoom *cr, const char *message, + const char *external_body_url, LinphoneChatMessageState state, + time_t time, bool_t is_read, bool_t is_incoming) { + LinphoneChatMessage *msg = linphone_chat_room_create_message(cr, message); + LinphoneCore *lc = linphone_chat_room_get_core(cr); + msg->external_body_url = external_body_url ? ms_strdup(external_body_url) : NULL; + msg->time = time; + msg->is_secured = FALSE; + linphone_chat_message_set_state(msg, state); + if (is_incoming) { + msg->dir = LinphoneChatMessageIncoming; + linphone_chat_message_set_from(msg, linphone_chat_room_get_peer_address(cr)); + msg->to = linphone_address_new(linphone_core_get_identity(lc)); /*direct assignment*/ + } else { + msg->dir = LinphoneChatMessageOutgoing; + linphone_chat_message_set_to(msg, linphone_chat_room_get_peer_address(cr)); + msg->from = linphone_address_new(linphone_core_get_identity(lc));/*direct assignment*/ + } + return msg; +} + +void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage *msg, + LinphoneChatMessageStateChangedCb status_cb, void *ud) { + msg->message_state_changed_cb = status_cb; + msg->message_state_changed_user_data = ud; + GET_CPP_PTR(cr)->sendMessage(msg); +} + +void linphone_chat_room_send_chat_message_2(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { + linphone_chat_message_ref(msg); + GET_CPP_PTR(cr)->sendMessage(msg); +} + +void linphone_chat_room_send_chat_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { + GET_CPP_PTR(cr)->sendMessage(msg); +} + +uint32_t linphone_chat_room_get_char(const LinphoneChatRoom *cr) { + if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) + return static_cast(GET_CPP_PTR(cr).get())->getChar(); + return 0; +} + +void linphone_chat_room_compose(LinphoneChatRoom *cr) { + GET_CPP_PTR(cr)->compose(); +} + +LinphoneCall *linphone_chat_room_get_call(const LinphoneChatRoom *cr) { + if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) + return static_cast(GET_CPP_PTR(cr).get())->getCall(); + return nullptr; +} + +void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call) { + if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) + static_cast(GET_CPP_PRIVATE_PTR(cr))->setCall(call); +} + +bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr) { + return L_GET_C_LIST_FROM_CPP_LIST(GET_CPP_PRIVATE_PTR(cr)->getTransientMessages(), LinphoneChatMessage); +} + +void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr) { + GET_CPP_PTR(cr)->markAsRead(); +} + +int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr) { + return GET_CPP_PTR(cr)->getUnreadMessagesCount(); +} + +int linphone_chat_room_get_history_size(LinphoneChatRoom *cr) { + return GET_CPP_PTR(cr)->getHistorySize(); +} + +void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { + GET_CPP_PTR(cr)->deleteMessage(msg); +} + +void linphone_chat_room_delete_history(LinphoneChatRoom *cr) { + GET_CPP_PTR(cr)->deleteHistory(); +} + +bctbx_list_t *linphone_chat_room_get_history_range(LinphoneChatRoom *cr, int startm, int endm) { + return L_GET_C_LIST_FROM_CPP_LIST(GET_CPP_PTR(cr)->getHistoryRange(startm, endm), LinphoneChatMessage); +} + +bctbx_list_t *linphone_chat_room_get_history(LinphoneChatRoom *cr, int nb_message) { + return L_GET_C_LIST_FROM_CPP_LIST(GET_CPP_PTR(cr)->getHistory(nb_message), LinphoneChatMessage); +} + +LinphoneChatMessage * linphone_chat_room_find_message(LinphoneChatRoom *cr, const char *message_id) { + return GET_CPP_PTR(cr)->findMessage(message_id); +} + + +/******************************************************************************* + * Reference and user data handling functions * + ******************************************************************************/ + +LinphoneChatRoom *linphone_chat_room_ref(LinphoneChatRoom *cr) { + belle_sip_object_ref(cr); + return cr; +} + +void linphone_chat_room_unref(LinphoneChatRoom *cr) { + belle_sip_object_unref(cr); +} + +void *linphone_chat_room_get_user_data(const LinphoneChatRoom *cr) { + // TODO + return nullptr; + //return cr->userData; +} + +void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void *ud) { + // TODO + //cr->userData = ud; +} + + +/******************************************************************************* + * Constructor and destructor functions * + ******************************************************************************/ + +LinphoneChatRoom * linphone_chat_room_new(LinphoneCore *core, const LinphoneAddress *addr) { + LinphoneChatRoom *cr = _linphone_chat_room_init(); + if (linphone_core_realtime_text_enabled(core)) + L_SET_CPP_PTR_FROM_C_STRUCT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address, Address))); + else + L_SET_CPP_PTR_FROM_C_STRUCT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address, Address))); + return cr; +} + +LinphoneChatRoom * linphone_client_group_chat_room_new(LinphoneCore *lc, const bctbx_list_t *addresses) { + const char *factoryUri = linphone_core_get_chat_conference_factory_uri(lc); + if (!factoryUri) + return nullptr; + LinphoneAddress *factoryAddr = linphone_address_new(factoryUri); + LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(lc, factoryAddr); + linphone_address_unref(factoryAddr); + std::string from; + if (proxy) + from = L_GET_CPP_PTR_FROM_C_STRUCT(linphone_proxy_config_get_identity_address(proxy), Address, Address)->asString(); + if (from.empty()) + from = linphone_core_get_primary_contact(lc); + LinphonePrivate::Address me(from); + std::list l = L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(addresses, Address); + LinphoneChatRoom *cr = _linphone_chat_room_init(); + L_SET_CPP_PTR_FROM_C_STRUCT(cr, make_shared(lc, me, l)); + return cr; +} + +/* DEPRECATED */ +void linphone_chat_room_destroy(LinphoneChatRoom *cr) { + linphone_chat_room_unref(cr); +} diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 43631882f..6cb14499c 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -32,7 +32,7 @@ using namespace std; // Event log. // ----------------------------------------------------------------------------- -L_DECLARE_C_STRUCT_IMPL(EventLog, event_log); +L_DECLARE_C_STRUCT_IMPL(EventLog, EventLog, event_log); L_DECLARE_C_STRUCT_NEW_DEFAULT(EventLog, event_log); LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *eventLog) { @@ -43,7 +43,7 @@ LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *eventL // Message event. // ----------------------------------------------------------------------------- -L_DECLARE_C_STRUCT_IMPL(MessageEvent, message_event); +L_DECLARE_C_STRUCT_IMPL(MessageEvent, MessageEvent, message_event); LinphoneMessageEvent *linphone_message_event_new (LinphoneMessage *message) { LinphoneMessageEvent *object = _linphone_message_event_init(); diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index 4fbb27a49..dc70e57d3 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -50,7 +50,14 @@ public: template static inline decltype (std::declval().getPrivate()) getPrivate (T *object) { if (!object) - return nullptr; + return nullptr; + return object->getPrivate(); + } + + template + static inline decltype (std::declval().getPrivate()) getPrivate (const std::shared_ptr &object) { + if (!object) + return nullptr; return object->getPrivate(); } @@ -61,7 +68,8 @@ public: template< typename CppType, typename CType, - typename std::enable_if::value>::type = 0 + typename = typename std::enable_if::value, CppType>::type + //typename std::enable_if::value, CppType>::type = 0 > static inline std::shared_ptr getCppPtrFromC (CType *object) { L_ASSERT(object); @@ -71,7 +79,8 @@ public: template< typename CppType, typename CType, - typename std::enable_if::value, CppType>::type = 0 + typename = typename std::enable_if::value, CppType>::type + //typename std::enable_if::value, CppType>::type = 0 > static inline std::shared_ptr getCppPtrFromC (const CType *object) { L_ASSERT(object); @@ -160,7 +169,7 @@ public: } template - static inline std::list getCppListFromCList (bctbx_list_t *cList) { + static inline std::list getCppListFromCList (const bctbx_list_t *cList) { std::list result; for (auto it = cList; it; it = bctbx_list_next(it)) result.push_back(static_cast(bctbx_list_get_data(it))); @@ -168,7 +177,7 @@ public: } template - static inline std::list getCppListOfCppObjFromCListOfStructPtr (bctbx_list_t *cList) { + static inline std::list getCppListOfCppObjFromCListOfStructPtr (const bctbx_list_t *cList) { std::list result; for (auto it = cList; it; it = bctbx_list_next(it)) result.push_back(*getCppPtrFromC(reinterpret_cast(bctbx_list_get_data(it)))); @@ -185,29 +194,50 @@ LINPHONE_END_NAMESPACE // ----------------------------------------------------------------------------- -#define L_DECLARE_C_STRUCT_IMPL(STRUCT, C_NAME, ...) \ - struct _Linphone ## STRUCT { \ +#define L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(CPP_CLASS, C_STRUCT, C_NAME, CONSTRUCTOR, DESTRUCTOR, ...) \ + struct _Linphone ## C_STRUCT { \ belle_sip_object_t base; \ - std::shared_ptr cppPtr; \ + std::shared_ptr cppPtr; \ __VA_ARGS__ \ }; \ - BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## STRUCT); \ - static Linphone ## STRUCT *_linphone_ ## C_NAME ## _init() { \ - Linphone ## STRUCT * object = belle_sip_object_new(Linphone ## STRUCT); \ - new(&object->cppPtr) std::shared_ptr(); \ + BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_STRUCT); \ + Linphone ## C_STRUCT *_linphone_ ## C_NAME ## _init() { \ + Linphone ## C_STRUCT * object = belle_sip_object_new(Linphone ## C_STRUCT); \ + new(&object->cppPtr) std::shared_ptr(); \ + CONSTRUCTOR(object); \ return object; \ } \ - static void _linphone_ ## C_NAME ## _uninit(Linphone ## STRUCT * object) { \ + void _linphone_ ## C_NAME ## _uninit(Linphone ## C_STRUCT * object) { \ + DESTRUCTOR(object); \ object->cppPtr.~shared_ptr (); \ } \ - static void _linphone_ ## C_NAME ## _clone(Linphone ## STRUCT * dest, const Linphone ## STRUCT * src) { \ - new(&dest->cppPtr) std::shared_ptr(); \ - dest->cppPtr = std::make_shared(*src->cppPtr.get()); \ - } \ - BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## STRUCT); \ - BELLE_SIP_INSTANCIATE_VPTR(Linphone ## STRUCT, belle_sip_object_t, \ + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## C_STRUCT); \ + BELLE_SIP_INSTANCIATE_VPTR(Linphone ## C_STRUCT, belle_sip_object_t, \ _linphone_ ## C_NAME ## _uninit, \ - _linphone_ ## C_NAME ## _clone, \ + NULL, \ + NULL, \ + FALSE \ + ); + +#define L_DECLARE_C_STRUCT_IMPL(CPP_CLASS, C_STRUCT, C_NAME, ...) \ + struct _Linphone ## C_STRUCT { \ + belle_sip_object_t base; \ + std::shared_ptr cppPtr; \ + __VA_ARGS__ \ + }; \ + BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_STRUCT); \ + Linphone ## C_STRUCT *_linphone_ ## C_NAME ## _init() { \ + Linphone ## C_STRUCT * object = belle_sip_object_new(Linphone ## C_STRUCT); \ + new(&object->cppPtr) std::shared_ptr(); \ + return object; \ + } \ + void _linphone_ ## C_NAME ## _uninit(Linphone ## C_STRUCT * object) { \ + object->cppPtr.~shared_ptr (); \ + } \ + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## C_STRUCT); \ + BELLE_SIP_INSTANCIATE_VPTR(Linphone ## C_STRUCT, belle_sip_object_t, \ + _linphone_ ## C_NAME ## _uninit, \ + NULL, \ NULL, \ FALSE \ ); @@ -220,13 +250,13 @@ LINPHONE_END_NAMESPACE __VA_ARGS__ \ }; \ BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_STRUCT); \ - static Linphone ## C_STRUCT *_linphone_ ## C_NAME ## _init() { \ + Linphone ## C_STRUCT *_linphone_ ## C_NAME ## _init() { \ return belle_sip_object_new(Linphone ## C_STRUCT); \ } \ - static void _linphone_ ## C_NAME ## _uninit(Linphone ## C_STRUCT * object) { \ + void _linphone_ ## C_NAME ## _uninit(Linphone ## C_STRUCT * object) { \ delete object->cppPtr; \ } \ - static void _linphone_ ## C_NAME ## _clone(Linphone ## C_STRUCT * dest, const Linphone ## C_STRUCT * src) { \ + void _linphone_ ## C_NAME ## _clone(Linphone ## C_STRUCT * dest, const Linphone ## C_STRUCT * src) { \ L_ASSERT(src->cppPtr); \ dest->cppPtr = new LINPHONE_NAMESPACE::CPP_CLASS(*src->cppPtr); \ } \ diff --git a/src/chat/chat-room-p.h b/src/chat/chat-room-p.h index 84b4b10d6..c1230eadf 100644 --- a/src/chat/chat-room-p.h +++ b/src/chat/chat-room-p.h @@ -54,13 +54,6 @@ public: void sendImdn (const std::string &content, LinphoneReason reason); int getMessagesCount (bool unreadOnly); - void setCBackPointer (LinphoneChatRoom *cr) { - this->cBackPointer = cr; - } - - void setCall (LinphoneCall *call) { - this->call = call; - } protected: void sendIsComposingNotification (); @@ -90,7 +83,6 @@ private: void onIsComposingRefreshNeeded (); public: - LinphoneChatRoom *cBackPointer = nullptr; LinphoneCore *core = nullptr; LinphoneCall *call = nullptr; Address peerAddress; diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 2758244b7..2499e1b43 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -28,6 +28,9 @@ #include "chat-room.h" +extern LinphoneChatRoom * _linphone_chat_room_init(); +#define GET_BACK_PTR(object) L_GET_C_BACK_PTR(object->shared_from_this(), ChatRoom, chat_room) + // ============================================================================= using namespace std; @@ -38,15 +41,16 @@ ChatRoomPrivate::ChatRoomPrivate (LinphoneCore *core) : core(core), isComposingHandler(core, this) {} ChatRoomPrivate::~ChatRoomPrivate () { + L_Q(ChatRoom); for (auto it = transientMessages.begin(); it != transientMessages.end(); it++) { linphone_chat_message_release(*it); } if (core) { - if (bctbx_list_find(core->chatrooms, cBackPointer)) { - lError() << "LinphoneChatRoom[" << cBackPointer << "] is destroyed while still being used by the LinphoneCore. " << + if (bctbx_list_find(core->chatrooms, GET_BACK_PTR(q))) { + lError() << "LinphoneChatRoom[" << GET_BACK_PTR(q) << "] is destroyed while still being used by the LinphoneCore. " << "This is abnormal. linphone_core_get_chat_room() doesn't give a reference, there is no need to call linphone_chat_room_unref(). " << "In order to remove a chat room from the core, use linphone_core_delete_chat_room()."; - core->chatrooms = bctbx_list_remove(core->chatrooms, cBackPointer); + core->chatrooms = bctbx_list_remove(core->chatrooms, GET_BACK_PTR(q)); } } if (pendingMessage) @@ -101,6 +105,7 @@ void ChatRoomPrivate::removeTransientMessage (LinphoneChatMessage *msg) { // ----------------------------------------------------------------------------- void ChatRoomPrivate::release () { + L_Q(ChatRoom); isComposingHandler.stopTimers(); for (auto it = weakMessages.begin(); it != weakMessages.end(); it++) { linphone_chat_message_deactivate(*it); @@ -109,7 +114,7 @@ void ChatRoomPrivate::release () { linphone_chat_message_deactivate(*it); } core = nullptr; - linphone_chat_room_unref(cBackPointer); + linphone_chat_room_unref(GET_BACK_PTR(q)); } void ChatRoomPrivate::sendImdn (const string &content, LinphoneReason reason) { @@ -140,7 +145,7 @@ void ChatRoomPrivate::sendImdn (const string &content, LinphoneReason reason) { LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); if (cbProcessOutgoingMessage) { - retval = cbProcessOutgoingMessage(imee, cBackPointer, msg); + retval = cbProcessOutgoingMessage(imee, GET_BACK_PTR(q), msg); } } @@ -219,7 +224,7 @@ void ChatRoomPrivate::sendIsComposingNotification () { LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); if (cbProcessOutgoingMessage) { - retval = cbProcessOutgoingMessage(imee, cBackPointer, msg); + retval = cbProcessOutgoingMessage(imee, GET_BACK_PTR(q), msg); } } @@ -424,12 +429,12 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsIncomingMessageCb cbProcessIncomingMessage = linphone_im_encryption_engine_cbs_get_process_incoming_message(imeeCbs); if (cbProcessIncomingMessage) { - retval = cbProcessIncomingMessage(imee, cBackPointer, msg); + retval = cbProcessIncomingMessage(imee, GET_BACK_PTR(q), msg); if (retval == 0) { msg->is_secured = TRUE; } else if (retval > 0) { /* Unable to decrypt message */ - linphone_core_notify_message_received_unable_decrypt(core, cBackPointer, msg); + linphone_core_notify_message_received_unable_decrypt(core, GET_BACK_PTR(q), msg); reason = linphone_error_code_to_reason(retval); linphone_chat_message_send_delivery_notification(msg, reason); /* Return LinphoneReasonNone to avoid flexisip resending us a message we can't decrypt */ @@ -499,14 +504,15 @@ end: // ----------------------------------------------------------------------------- void ChatRoomPrivate::chatMessageReceived (LinphoneChatMessage *msg) { + L_Q(ChatRoom); if (msg->message) { /* Legacy API */ - linphone_core_notify_text_message_received(core, cBackPointer, msg->from, msg->message); + linphone_core_notify_text_message_received(core, GET_BACK_PTR(q), msg->from, msg->message); } - linphone_core_notify_message_received(core, cBackPointer, msg); + linphone_core_notify_message_received(core, GET_BACK_PTR(q), msg); if (!ContentType::isImdn(msg->content_type) && !ContentType::isImIsComposing(msg->content_type)) { remoteIsComposing = false; - linphone_core_notify_is_composing_received(core, cBackPointer); + linphone_core_notify_is_composing_received(core, GET_BACK_PTR(q)); linphone_chat_message_send_delivery_notification(msg, LinphoneReasonNone); } } @@ -528,8 +534,9 @@ void ChatRoomPrivate::onIsComposingStateChanged (bool isComposing) { } void ChatRoomPrivate::onIsRemoteComposingStateChanged (bool isComposing) { + L_Q(ChatRoom); remoteIsComposing = isComposing; - linphone_core_notify_is_composing_received(core, cBackPointer); + linphone_core_notify_is_composing_received(core, GET_BACK_PTR(q)); } void ChatRoomPrivate::onIsComposingRefreshNeeded () { @@ -558,7 +565,7 @@ LinphoneChatMessage *ChatRoom::createFileTransferMessage (const LinphoneContent L_D(ChatRoom); LinphoneChatMessage *cm = belle_sip_object_new(LinphoneChatMessage); cm->callbacks = linphone_chat_message_cbs_new(); - cm->chat_room = d->cBackPointer; + cm->chat_room = GET_BACK_PTR(this); cm->message = nullptr; cm->file_transfer_information = linphone_content_copy(initialContent); cm->dir = LinphoneChatMessageOutgoing; @@ -575,11 +582,10 @@ LinphoneChatMessage *ChatRoom::createFileTransferMessage (const LinphoneContent } LinphoneChatMessage *ChatRoom::createMessage (const string &msg) { - L_D(ChatRoom); LinphoneChatMessage *cm = belle_sip_object_new(LinphoneChatMessage); cm->state = LinphoneChatMessageStateIdle; cm->callbacks = linphone_chat_message_cbs_new(); - cm->chat_room = d->cBackPointer; + cm->chat_room = GET_BACK_PTR(this); cm->message = msg.empty() ? nullptr : ms_strdup(msg.c_str()); cm->content_type = ms_strdup("text/plain"); cm->file_transfer_information = nullptr; /* this property is used only when transfering file */ @@ -817,7 +823,7 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); if (cbProcessOutgoingMessage) { - retval = cbProcessOutgoingMessage(imee, d->cBackPointer, msg); + retval = cbProcessOutgoingMessage(imee, GET_BACK_PTR(this), msg); if (retval == 0) { msg->is_secured = TRUE; } diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 91b9fcf13..0d19ca637 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -21,8 +21,12 @@ #include "linphone/utils/utils.h" #include "real-time-text-chat-room-p.h" +#include "c-wrapper/c-tools.h" #include "logger/logger.h" +extern LinphoneChatRoom * _linphone_chat_room_init(); +#define GET_BACK_PTR(object) L_GET_C_BACK_PTR(object->shared_from_this(), ChatRoom, chat_room) + // ============================================================================= using namespace std; @@ -62,7 +66,7 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp receivedRttCharacters.push_back(cmc); remoteIsComposing = true; - linphone_core_notify_is_composing_received(core, cBackPointer); + linphone_core_notify_is_composing_received(core, GET_BACK_PTR(q)); if ((character == new_line) || (character == crlf) || (character == lf)) { /* End of message */ diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index aff406142..41a2a2bfa 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -881,7 +881,7 @@ void CallSession::startIncomingNotification () { if (d->listener) d->listener->onCallSessionAccepted(*this); /* Prevent the CallSession from being destroyed while we are notifying, if the user declines within the state callback */ - shared_ptr ref = shared_from_this(); + shared_ptr ref = static_pointer_cast(shared_from_this()); #if 0 call->bg_task_id=sal_begin_background_task("liblinphone call notification", NULL, NULL); #endif @@ -937,7 +937,7 @@ int CallSession::startInvite (const Address *destination) { linphone_core_notify_display_status(d->core, os.str().c_str()); char *from = linphone_address_as_string(d->log->from); /* Take a ref because sal_call() may destroy the CallSession if no SIP transport is available */ - shared_ptr ref = shared_from_this(); + shared_ptr ref = static_pointer_cast(shared_from_this()); int result = sal_call(d->op, from, destinationStr.c_str()); ms_free(from); if (result < 0) { diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index 7e6d5634c..db46a9871 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -19,8 +19,6 @@ #ifndef _CALL_SESSION_H_ #define _CALL_SESSION_H_ -#include - #include "object/object.h" #include "address/address.h" #include "conference/conference.h" @@ -34,7 +32,7 @@ LINPHONE_BEGIN_NAMESPACE class CallPrivate; class CallSessionPrivate; -class CallSession : public Object, public std::enable_shared_from_this { +class CallSession : public Object { friend class CallPrivate; public: diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 9c2f9c933..fa7be38c3 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -626,7 +626,7 @@ float MediaSessionPrivate::aggregateQualityRatings (float audioRating, float vid void MediaSessionPrivate::setState (LinphoneCallState newState, const string &message) { L_Q(MediaSession); /* Take a ref on the session otherwise it might get destroyed during the call to setState */ - shared_ptr session = q->shared_from_this(); + shared_ptr session = static_pointer_cast(q->shared_from_this()); CallSessionPrivate::setState(newState, message); updateReportingCallState(); } diff --git a/src/object/object.h b/src/object/object.h index 7dae752a6..a09cbc6e0 100644 --- a/src/object/object.h +++ b/src/object/object.h @@ -19,6 +19,8 @@ #ifndef _OBJECT_H_ #define _OBJECT_H_ +#include + #include "linphone/utils/general.h" #include "property-container.h" @@ -27,7 +29,8 @@ LINPHONE_BEGIN_NAMESPACE -class LINPHONE_PUBLIC Object : public PropertyContainer { +class LINPHONE_PUBLIC Object : public std::enable_shared_from_this, public PropertyContainer { + public: virtual ~Object (); From 8cd99594c7837e5aec2b3d21a15654dd555269da Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 14 Sep 2017 16:43:29 +0200 Subject: [PATCH 0067/2215] Add macros to handle user data in c-tools. --- src/c-wrapper/api/c-chat-room.cpp | 9 +++----- src/c-wrapper/c-tools.h | 36 +++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index f48c6b473..5540611ce 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -201,15 +201,12 @@ void linphone_chat_room_unref(LinphoneChatRoom *cr) { belle_sip_object_unref(cr); } -void *linphone_chat_room_get_user_data(const LinphoneChatRoom *cr) { - // TODO - return nullptr; - //return cr->userData; +void * linphone_chat_room_get_user_data(const LinphoneChatRoom *cr) { + return L_GET_USER_DATA_FROM_C_STRUCT(cr, ChatRoom, ChatRoom); } void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void *ud) { - // TODO - //cr->userData = ud; + L_SET_USER_DATA_FROM_C_STRUCT(cr, ud, ChatRoom, ChatRoom); } diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index dc70e57d3..df312fc34 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -160,6 +160,32 @@ public: // --------------------------------------------------------------------------- + template + static void * getUserData (const std::shared_ptr &cppPtr) { + Variant v = cppPtr->getProperty("LinphonePrivate::Wrapper::userData"); + return v.getValue(); + } + + template + static void * getUserData (T *cppPtr) { + Variant v = cppPtr->getProperty("LinphonePrivate::Wrapper::userData"); + return v.getValue(); + } + + template + static inline void setUserData (std::shared_ptr object, void *value) { + L_ASSERT(object); + object->setProperty("LinphonePrivate::Wrapper::userData", value); + } + + template + static inline void setUserData (T *object, void *value) { + L_ASSERT(object); + object->setProperty("LinphonePrivate::Wrapper::userData", value); + } + + // --------------------------------------------------------------------------- + template static inline bctbx_list_t * getCListFromCppList (std::list cppList) { bctbx_list_t *result = nullptr; @@ -295,6 +321,16 @@ LINPHONE_END_NAMESPACE #define L_GET_C_BACK_PTR(OBJECT, C_TYPE, C_NAME) \ LINPHONE_NAMESPACE::Wrapper::getCBackPtr(OBJECT, _linphone_ ## C_NAME ## _init) +#define L_GET_USER_DATA_FROM_C_STRUCT(OBJECT, CPP_TYPE, C_TYPE) \ + LINPHONE_NAMESPACE::Wrapper::getUserData( \ + L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE, C_TYPE) \ + ) +#define L_SET_USER_DATA_FROM_C_STRUCT(OBJECT, VALUE, CPP_TYPE, C_TYPE) \ + LINPHONE_NAMESPACE::Wrapper::setUserData( \ + L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE, C_TYPE), \ + VALUE \ + ) + #define L_GET_C_LIST_FROM_CPP_LIST(LIST, TYPE) \ LINPHONE_NAMESPACE::Wrapper::getCListFromCppList(LIST) #define L_GET_CPP_LIST_FROM_C_LIST(LIST, TYPE) \ From d458d1099f614c75054f4bee05f627ac0985c0fd Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 15 Sep 2017 11:00:33 +0200 Subject: [PATCH 0068/2215] fix(Variant): better code, supports correctly generic values --- src/variant/variant.cpp | 104 +++++++++++++++++++-------- tester/property-container-tester.cpp | 11 ++- 2 files changed, 84 insertions(+), 31 deletions(-) diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index 484e3fb9b..952564293 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -45,24 +45,46 @@ public: void *g; }; + ~VariantPrivate () { + deleteString(); + } + + inline int getType () const { + return type; + } + + inline void setType (int newType) { + L_ASSERT(newType >= Variant::Invalid && newType != Variant::MaxDefaultTypes); + + if (newType != Variant::String) + deleteString(); + else if (type != Variant::String) + value.str = new string(); + + type = newType; + } + + Value value = {}; + +private: + inline void deleteString () { + if (type == Variant::String) + delete value.str; + } + // Integer, because type can be a custom type. int type = Variant::Invalid; - Value value = {}; }; Variant::Variant () { + // Private can exist. (placement new) if (!mPrivate) mPrivate = new VariantPrivate(); } Variant::Variant (Type type) : Variant() { - if (type != String) - return; - L_D(Variant); - - if (!d->value.str) - d->value.str = new string(); + d->setType(type); } Variant::Variant (const Variant &src) { @@ -71,11 +93,13 @@ Variant::Variant (const Variant &src) { mPrivate = new VariantPrivate(); L_D(Variant); - d->type = src.getPrivate()->type; + + int type = src.getPrivate()->getType(); + d->setType(type); const VariantPrivate::Value &value = src.getPrivate()->value; - if (d->type == String) - d->value.str = new string(*value.str); + if (type == String) + *d->value.str = *value.str; else d->value = value; } @@ -154,10 +178,10 @@ Variant::Variant (const std::string &value) : Variant(String) { Variant::~Variant () { L_D(Variant); - if (d->type == String) - delete d->value.str; - delete mPrivate; + // Note: Private data can be stolen by copy operator (r-value). + // It can be null, but it useless to test it. + delete d; } bool Variant::operator!= (const Variant &variant) const { @@ -176,12 +200,32 @@ bool Variant::operator<= (const Variant &variant) const { } Variant &Variant::operator= (const Variant &variant) { - // TODO. + L_D(Variant); + + if (this != &variant) { + // Update type. + int type = variant.getPrivate()->getType(); + d->setType(type); + + // Update value. + const VariantPrivate::Value &value = variant.getPrivate()->value; + if (type == String) + *d->value.str = *value.str; + else + d->value = value; + } + return *this; } Variant &Variant::operator= (Variant &&variant) { - // TODO. + // Unset old d. + delete mPrivate; + + // Set new d. + mPrivate = variant.mPrivate; + variant.mPrivate = nullptr; + return *this; } @@ -202,7 +246,7 @@ bool Variant::operator>= (const Variant &variant) const { bool Variant::isValid () const { L_D(const Variant); - return d->type != Invalid; + return d->getType() != Invalid; } void Variant::clear () { @@ -218,9 +262,10 @@ void Variant::swap (const Variant &variant) { // ----------------------------------------------------------------------------- static inline long long getAssumedNumber (const VariantPrivate &p) { - L_ASSERT(p.type > Variant::Invalid && p.type < Variant::MaxDefaultTypes); + const int type = p.getType(); + L_ASSERT(type > Variant::Invalid && type < Variant::MaxDefaultTypes); - switch (static_cast(p.type)) { + switch (static_cast(type)) { case Variant::Int: return p.value.i; case Variant::Short: @@ -244,9 +289,10 @@ static inline long long getAssumedNumber (const VariantPrivate &p) { } static inline unsigned long long getAssumedUnsignedNumber (const VariantPrivate &p) { - L_ASSERT(p.type > Variant::Invalid && p.type < Variant::MaxDefaultTypes); + const int type = p.getType(); + L_ASSERT(type > Variant::Invalid && type < Variant::MaxDefaultTypes); - switch (static_cast(p.type)) { + switch (static_cast(type)) { case Variant::UnsignedInt: return p.value.ui; case Variant::UnsignedShort: @@ -282,10 +328,10 @@ static inline unsigned long long getValueAsUnsignedNumber (const VariantPrivate // ----------------------------------------------------------------------------- static inline bool getValueAsBool (const VariantPrivate &p, bool *soFarSoGood) { - L_ASSERT(p.type > Variant::Invalid && p.type < Variant::MaxDefaultTypes); + const int type = p.getType(); + L_ASSERT(type > Variant::Invalid && type < Variant::MaxDefaultTypes); - *soFarSoGood = true; - switch (static_cast(p.type)) { + switch (static_cast(type)) { case Variant::Int: case Variant::Short: case Variant::Long: @@ -319,10 +365,10 @@ static inline bool getValueAsBool (const VariantPrivate &p, bool *soFarSoGood) { } static inline double getValueAsDouble (const VariantPrivate &p, bool *soFarSoGood) { - L_ASSERT(p.type > Variant::Invalid && p.type < Variant::MaxDefaultTypes); + const int type = p.getType(); + L_ASSERT(type > Variant::Invalid && type < Variant::MaxDefaultTypes); - *soFarSoGood = true; - switch (static_cast(p.type)) { + switch (static_cast(type)) { case Variant::Int: case Variant::Short: case Variant::Long: @@ -368,10 +414,8 @@ static inline float getValueAsString (const VariantPrivate &p, bool *soFarSoGood } static inline void *getValueAsGeneric (const VariantPrivate &p, bool *soFarSoGood) { - if (p.type == Variant::Generic) { - *soFarSoGood = true; + if (p.getType() == Variant::Generic) return p.value.g; - } *soFarSoGood = false; return nullptr; @@ -384,6 +428,8 @@ void Variant::getValue (int type, void *value, bool *soFarSoGood) const { L_D(const Variant); + *soFarSoGood = true; + if (type > MaxDefaultTypes) { *soFarSoGood = false; // TODO: Unable to get value. It will be great to support custom types. diff --git a/tester/property-container-tester.cpp b/tester/property-container-tester.cpp index eb01e4fd1..6cc7fffb7 100644 --- a/tester/property-container-tester.cpp +++ b/tester/property-container-tester.cpp @@ -28,14 +28,21 @@ using namespace LinphonePrivate; // ----------------------------------------------------------------------------- -static void set_integer_property () { +static void set_int_property () { PropertyContainer properties; properties.setProperty("integer", 42); BC_ASSERT_EQUAL(properties.getProperty("integer").getValue(), 42, int, "%d"); } +static void set_generic_property () { + PropertyContainer properties; + properties.setProperty("generic", reinterpret_cast(0x42)); + BC_ASSERT_EQUAL(properties.getProperty("generic").getValue(), reinterpret_cast(0x42), void *, "%p"); +} + test_t property_container_tests[] = { - TEST_NO_TAG("Set int property", set_integer_property) + TEST_NO_TAG("Set int property", set_int_property), + TEST_NO_TAG("Set generic property", set_generic_property) }; test_suite_t property_container_test_suite = { From f4f3b90c9ed86cbc367ce0aac7757d0bb599f7e9 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 15 Sep 2017 10:59:47 +0200 Subject: [PATCH 0069/2215] Add C wrapper for Participant class. --- coreapi/private.h | 3 +- include/CMakeLists.txt | 1 + include/linphone/api/c-api.h | 1 + include/linphone/api/c-participant.h | 88 ++++++++++++++++++++++++++++ include/linphone/api/c-types.h | 1 + src/CMakeLists.txt | 1 + src/c-wrapper/api/c-participant.cpp | 64 ++++++++++++++++++++ 7 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 include/linphone/api/c-participant.h create mode 100644 src/c-wrapper/api/c-participant.cpp diff --git a/coreapi/private.h b/coreapi/private.h index 95f98514e..d8f94da45 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -1723,7 +1723,8 @@ BELLE_SIP_TYPE_ID(LinphonePlayer), BELLE_SIP_TYPE_ID(LinphonePlayerCbs), BELLE_SIP_TYPE_ID(LinphoneEventLog), BELLE_SIP_TYPE_ID(LinphoneMessage), -BELLE_SIP_TYPE_ID(LinphoneMessageEvent) +BELLE_SIP_TYPE_ID(LinphoneMessageEvent), +BELLE_SIP_TYPE_ID(LinphoneParticipant) BELLE_SIP_DECLARE_TYPES_END diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index d54cb0ddf..cd1e77d89 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -77,6 +77,7 @@ set(C_API_HEADER_FILES c-address.h c-api.h c-event-log.h + c-participant.h c-types.h ) diff --git a/include/linphone/api/c-api.h b/include/linphone/api/c-api.h index 746ac7c3a..fab3520bd 100644 --- a/include/linphone/api/c-api.h +++ b/include/linphone/api/c-api.h @@ -21,5 +21,6 @@ #include "linphone/api/c-address.h" #include "linphone/api/c-event-log.h" +#include "linphone/api/c-participant.h" #endif // ifndef _C_API_H_ diff --git a/include/linphone/api/c-participant.h b/include/linphone/api/c-participant.h new file mode 100644 index 000000000..f09789ce5 --- /dev/null +++ b/include/linphone/api/c-participant.h @@ -0,0 +1,88 @@ +/* + * c-participant.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _C_PARTICIPANT_H_ +#define _C_PARTICIPANT_H_ + +#include "linphone/api/c-types.h" + +// ============================================================================= + +#ifdef __cplusplus + extern "C" { +#endif // ifdef __cplusplus + +/** + * @addtogroup misc + * @{ + */ + +/** + * Increment reference count of LinphoneParticipant object. + **/ +LINPHONE_PUBLIC LinphoneParticipant *linphone_participant_ref (LinphoneParticipant *participant); + +/** + * Decrement reference count of LinphoneParticipant object. + **/ +LINPHONE_PUBLIC void linphone_participant_unref (LinphoneParticipant *participant); + +/** + * Retrieve the user pointer associated with the conference participant. + * @param[in] participant A LinphoneParticipant object + * @return The user pointer associated with the participant. +**/ +LINPHONE_PUBLIC void * linphone_participant_get_user_data(const LinphoneParticipant *participant); + +/** + * Assign a user pointer to the conference participant. + * @param[in] participant A LinphoneParticipant object + * @param[in] ud The user pointer to associate with the participant +**/ +LINPHONE_PUBLIC void linphone_participant_set_user_data(LinphoneParticipant *participant, void *ud); + +/** + * Get the address of a conference participant. + * @param[in] participant A LinphoneParticipant object + * @return The address of the participant + */ +LINPHONE_PUBLIC const LinphoneAddress * linphone_participant_get_address (const LinphoneParticipant *participant); + +/** + * Tells whether a conference participant is an administrator of the conference. + * @param[in] participant A LinphoneParticipant object + * @return A boolean value telling whether the participant is an administrator + */ +LINPHONE_PUBLIC bool_t linphone_participant_is_admin (const LinphoneParticipant *participant); + +/** + * Give the administrator rights or remove them to a conference participant. + * @param[in] participant A LinphoneParticipant object + * @param value A boolean value telling whether the participant should be an administrator or not + */ +LINPHONE_PUBLIC void linphone_participant_set_admin (LinphoneParticipant *participant, bool_t value); + +/** + * @} + */ + +#ifdef __cplusplus + } +#endif // ifdef __cplusplus + +#endif // ifndef _C_PARTICIPANT_H_ diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index d71ba795d..288564328 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -80,6 +80,7 @@ typedef struct _LinphoneConferenceParticipantEvent LinphoneConferenceParticipant typedef struct _LinphoneEventLog LinphoneEventLog; typedef struct _LinphoneMessage LinphoneMessage; typedef struct _LinphoneMessageEvent LinphoneMessageEvent; +typedef struct _LinphoneParticipant LinphoneParticipant; // ============================================================================= // C Enums. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7ed8e1602..55e15fe9b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -101,6 +101,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES c-wrapper/api/c-call-params.cpp c-wrapper/api/c-chat-room.cpp c-wrapper/api/c-event-log.cpp + c-wrapper/api/c-participant.cpp call/call.cpp chat/basic-chat-room.cpp chat/chat-message.cpp diff --git a/src/c-wrapper/api/c-participant.cpp b/src/c-wrapper/api/c-participant.cpp new file mode 100644 index 000000000..d4d787183 --- /dev/null +++ b/src/c-wrapper/api/c-participant.cpp @@ -0,0 +1,64 @@ +/* + * c-participant.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "linphone/api/c-participant.h" + +#include "c-wrapper/c-tools.h" + +#include "conference/participant.h" + +// ============================================================================= + +using namespace std; + +L_DECLARE_C_STRUCT_IMPL(Participant, Participant, participant, + mutable LinphoneAddress *addressCache; +); + +LinphoneParticipant *linphone_participant_ref (LinphoneParticipant *participant) { + belle_sip_object_ref(participant); + return participant; +} + +void linphone_participant_unref (LinphoneParticipant *participant) { + belle_sip_object_unref(participant); +} + +void * linphone_participant_get_user_data(const LinphoneParticipant *participant) { + return L_GET_USER_DATA_FROM_C_STRUCT(participant, Participant, Participant); +} + +void linphone_participant_set_user_data(LinphoneParticipant *participant, void *ud) { + L_SET_USER_DATA_FROM_C_STRUCT(participant, ud, Participant, Participant); +} + +const LinphoneAddress * linphone_participant_get_address (const LinphoneParticipant *participant) { + LinphonePrivate::Address addr = L_GET_CPP_PTR_FROM_C_STRUCT(participant, Participant, Participant)->getAddress(); + if (participant->addressCache) + linphone_address_unref(participant->addressCache); + participant->addressCache = linphone_address_new(addr.asString().c_str()); + return participant->addressCache; +} + +bool_t linphone_participant_is_admin (const LinphoneParticipant *participant) { + return L_GET_CPP_PTR_FROM_C_STRUCT(participant, Participant, Participant)->isAdmin(); +} + +void linphone_participant_set_admin (LinphoneParticipant *participant, bool_t value) { + L_GET_CPP_PTR_FROM_C_STRUCT(participant, Participant, Participant)->setAdmin(value); +} From cfbb66457fab1727c10208581fe283f6a4adf2b5 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 15 Sep 2017 11:34:39 +0200 Subject: [PATCH 0070/2215] Add a specific header for the chat room API. --- include/CMakeLists.txt | 1 + include/linphone/api/c-api.h | 1 + include/linphone/api/c-chat-room.h | 249 +++++++++++++++++++++++++++++ include/linphone/api/c-types.h | 1 + include/linphone/chat.h | 206 +----------------------- 5 files changed, 254 insertions(+), 204 deletions(-) create mode 100644 include/linphone/api/c-chat-room.h diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index cd1e77d89..ecedd8a55 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -76,6 +76,7 @@ set(ROOT_HEADER_FILES set(C_API_HEADER_FILES c-address.h c-api.h + c-chat-room.h c-event-log.h c-participant.h c-types.h diff --git a/include/linphone/api/c-api.h b/include/linphone/api/c-api.h index fab3520bd..009498b29 100644 --- a/include/linphone/api/c-api.h +++ b/include/linphone/api/c-api.h @@ -20,6 +20,7 @@ #define _C_API_H_ #include "linphone/api/c-address.h" +#include "linphone/api/c-chat-room.h" #include "linphone/api/c-event-log.h" #include "linphone/api/c-participant.h" diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h new file mode 100644 index 000000000..5cf75e77d --- /dev/null +++ b/include/linphone/api/c-chat-room.h @@ -0,0 +1,249 @@ +/* + * c-chat-room.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _C_CHAT_ROOM_H_ +#define _C_CHAT_ROOM_H_ + +#include "linphone/api/c-types.h" + +// ============================================================================= + +#ifdef __cplusplus + extern "C" { +#endif // ifdef __cplusplus + +/** + * @addtogroup chatroom + * @{ + */ + +/** + * Acquire a reference to the chat room. + * @param[in] cr The chat room. + * @return The same chat room. +**/ +LINPHONE_PUBLIC LinphoneChatRoom *linphone_chat_room_ref(LinphoneChatRoom *cr); + +/** + * Release reference to the chat room. + * @param[in] cr The chat room. +**/ +LINPHONE_PUBLIC void linphone_chat_room_unref(LinphoneChatRoom *cr); + +/** + * Retrieve the user pointer associated with the chat room. + * @param[in] cr The chat room. + * @return The user pointer associated with the chat room. +**/ +LINPHONE_PUBLIC void *linphone_chat_room_get_user_data(const LinphoneChatRoom *cr); + +/** + * Assign a user pointer to the chat room. + * @param[in] cr The chat room. + * @param[in] ud The user pointer to associate with the chat room. +**/ +LINPHONE_PUBLIC void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void *ud); + +/** + * Create a message attached to a dedicated chat room; + * @param cr the chat room. + * @param message text message, NULL if absent. + * @return a new #LinphoneChatMessage + */ +LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr,const char* message); + +/** + * Create a message attached to a dedicated chat room; + * @param cr the chat room. + * @param message text message, NULL if absent. + * @param external_body_url the URL given in external body or NULL. + * @param state the LinphoneChatMessage.State of the message. + * @param time the time_t at which the message has been received/sent. + * @param is_read TRUE if the message should be flagged as read, FALSE otherwise. + * @param is_incoming TRUE if the message has been received, FALSE otherwise. + * @return a new #LinphoneChatMessage + */ +LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message_2(LinphoneChatRoom *cr, const char* message, const char* external_body_url, LinphoneChatMessageState state, time_t time, bool_t is_read, bool_t is_incoming); + + /** + * Create a message attached to a dedicated chat room with a particular content. + * Use #linphone_chat_room_send_message to initiate the transfer + * @param cr the chat room. + * @param initial_content #LinphoneContent initial content. #LinphoneCoreVTable.file_transfer_send is invoked later to notify file transfer progress and collect next chunk of the message if LinphoneContent.data is NULL. + * @return a new #LinphoneChatMessage + */ +LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent* initial_content); + +/** + * get peer address \link linphone_core_get_chat_room() associated to \endlink this #LinphoneChatRoom + * @param cr #LinphoneChatRoom object + * @return #LinphoneAddress peer address + */ +LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr); + +/** + * Send a message to peer member of this chat room. + * @deprecated Use linphone_chat_room_send_chat_message() instead. + * @param cr #LinphoneChatRoom object + * @param msg message to be sent + * @donotwrap + */ +LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg); + +/** + * Send a message to peer member of this chat room. + * @param cr #LinphoneChatRoom object + * @param msg #LinphoneChatMessage message to be sent + * @param status_cb LinphoneChatMessageStateChangeCb status callback invoked when message is delivered or could not be delivered. May be NULL + * @param ud user data for the status cb. + * @deprecated Use linphone_chat_room_send_chat_message() instead. + * @note The LinphoneChatMessage must not be destroyed until the the callback is called. + * The LinphoneChatMessage reference is transfered to the function and thus doesn't need to be unref'd by the application. + * @donotwrap + */ +LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangedCb status_cb,void* ud); + +/** + * Send a message to peer member of this chat room. + * @param[in] cr LinphoneChatRoom object + * @param[in] msg LinphoneChatMessage object + * The state of the message sending will be notified via the callbacks defined in the LinphoneChatMessageCbs object that can be obtained + * by calling linphone_chat_message_get_callbacks(). + * The LinphoneChatMessage reference is transfered to the function and thus doesn't need to be unref'd by the application. + * @donotwrap + */ +LINPHONE_PUBLIC void linphone_chat_room_send_chat_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg); + +/** + * Mark all messages of the conversation as read + * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation. + */ +LINPHONE_PUBLIC void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr); + +/** + * Delete a message from the chat room history. + * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation. + * @param[in] msg The #LinphoneChatMessage object to remove. + */ + +LINPHONE_PUBLIC void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg); + +/** + * Delete all messages from the history + * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation. + */ +LINPHONE_PUBLIC void linphone_chat_room_delete_history(LinphoneChatRoom *cr); + +/** + * Gets the number of messages in a chat room. + * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which size has to be computed + * @return the number of messages. + */ +LINPHONE_PUBLIC int linphone_chat_room_get_history_size(LinphoneChatRoom *cr); + +/** + * Gets nb_message most recent messages from cr chat room, sorted from oldest to most recent. + * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which messages should be retrieved + * @param[in] nb_message Number of message to retrieve. 0 means everything. + * @return \bctbx_list{LinphoneChatMessage} + */ +LINPHONE_PUBLIC bctbx_list_t *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message); + +/** + * Gets the partial list of messages in the given range, sorted from oldest to most recent. + * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which messages should be retrieved + * @param[in] begin The first message of the range to be retrieved. History most recent message has index 0. + * @param[in] end The last message of the range to be retrieved. History oldest message has index of history size - 1 (use #linphone_chat_room_get_history_size to retrieve history size) + * @return \bctbx_list{LinphoneChatMessage} + */ +LINPHONE_PUBLIC bctbx_list_t *linphone_chat_room_get_history_range(LinphoneChatRoom *cr, int begin, int end); + +LINPHONE_PUBLIC LinphoneChatMessage * linphone_chat_room_find_message(LinphoneChatRoom *cr, const char *message_id); + +/** + * Notifies the destination of the chat message being composed that the user is typing a new message. + * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which a new message is being typed. + */ +LINPHONE_PUBLIC void linphone_chat_room_compose(LinphoneChatRoom *cr); + +/** + * Tells whether the remote is currently composing a message. + * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation. + * @return TRUE if the remote is currently composing a message, FALSE otherwise. + */ +LINPHONE_PUBLIC bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr); + +/** + * Gets the number of unread messages in the chatroom. + * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation. + * @return the number of unread messages. + */ +LINPHONE_PUBLIC int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr); + +/** + * Returns back pointer to #LinphoneCore object. +**/ +LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_core(const LinphoneChatRoom *cr); + +/** + * When realtime text is enabled #linphone_call_params_realtime_text_enabled, #LinphoneCoreIsComposingReceivedCb is call everytime a char is received from peer. + * At the end of remote typing a regular #LinphoneChatMessage is received with committed data from #LinphoneCoreMessageReceivedCb. + * @param[in] cr #LinphoneChatRoom object + * @returns RFC 4103/T.140 char + */ +LINPHONE_PUBLIC uint32_t linphone_chat_room_get_char(const LinphoneChatRoom *cr); + +/** + * Returns true if lime is available for given peer + * + * @return true if zrtp secrets have already been shared and ready to use + */ +LINPHONE_PUBLIC bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr); + +/** + * get Curent Call associated to this chatroom if any + * To commit a message, use #linphone_chat_room_send_message + * @param[in] room LinphoneChatRomm + * @returns LinphoneCall or NULL. + */ +LINPHONE_PUBLIC LinphoneCall *linphone_chat_room_get_call(const LinphoneChatRoom *room); + +/** + * Returns back pointer to #LinphoneCore object. + * @deprecated use linphone_chat_room_get_core() + * @donotwrap +**/ +LINPHONE_PUBLIC LINPHONE_DEPRECATED LinphoneCore* linphone_chat_room_get_lc(const LinphoneChatRoom *cr); + +/** + * Destroy a LinphoneChatRoom. + * @param cr #LinphoneChatRoom object + * @deprecated Use linphone_chat_room_unref() instead. + * @donotwrap + */ +LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_chat_room_destroy(LinphoneChatRoom *cr); + +/** + * @} + */ + +#ifdef __cplusplus + } +#endif // ifdef __cplusplus + +#endif // ifndef _C_CHAT_ROOM_H_ diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index 288564328..3fea38e86 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -75,6 +75,7 @@ typedef struct _LinphoneAddress LinphoneAddress; typedef struct _LinphoneCall LinphoneCall; typedef struct _LinphoneCallEvent LinphoneCallEvent; +typedef struct _LinphoneChatRoom LinphoneChatRoom; typedef struct _LinphoneConferenceEvent LinphoneConferenceEvent; typedef struct _LinphoneConferenceParticipantEvent LinphoneConferenceParticipantEvent; typedef struct _LinphoneEventLog LinphoneEventLog; diff --git a/include/linphone/chat.h b/include/linphone/chat.h index a3e581064..0660003b5 100644 --- a/include/linphone/chat.h +++ b/include/linphone/chat.h @@ -23,6 +23,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/callbacks.h" #include "linphone/types.h" +#include "linphone/api/c-types.h" +#include "linphone/api/c-chat-room.h" #ifdef __cplusplus @@ -34,202 +36,6 @@ extern "C" { * @{ */ -/** - * Destroy a LinphoneChatRoom. - * @param cr #LinphoneChatRoom object - * @deprecated Use linphone_chat_room_unref() instead. - * @donotwrap - */ -LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_chat_room_destroy(LinphoneChatRoom *cr); -/** - * Create a message attached to a dedicated chat room; - * @param cr the chat room. - * @param message text message, NULL if absent. - * @return a new #LinphoneChatMessage - */ -LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr,const char* message); -/** - * Create a message attached to a dedicated chat room; - * @param cr the chat room. - * @param message text message, NULL if absent. - * @param external_body_url the URL given in external body or NULL. - * @param state the LinphoneChatMessage.State of the message. - * @param time the time_t at which the message has been received/sent. - * @param is_read TRUE if the message should be flagged as read, FALSE otherwise. - * @param is_incoming TRUE if the message has been received, FALSE otherwise. - * @return a new #LinphoneChatMessage - */ -LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message_2(LinphoneChatRoom *cr, const char* message, const char* external_body_url, LinphoneChatMessageState state, time_t time, bool_t is_read, bool_t is_incoming); - -/** - * Acquire a reference to the chat room. - * @param[in] cr The chat room. - * @return The same chat room. -**/ -LINPHONE_PUBLIC LinphoneChatRoom *linphone_chat_room_ref(LinphoneChatRoom *cr); - -/** - * Release reference to the chat room. - * @param[in] cr The chat room. -**/ -LINPHONE_PUBLIC void linphone_chat_room_unref(LinphoneChatRoom *cr); - -/** - * Retrieve the user pointer associated with the chat room. - * @param[in] cr The chat room. - * @return The user pointer associated with the chat room. -**/ -LINPHONE_PUBLIC void *linphone_chat_room_get_user_data(const LinphoneChatRoom *cr); - -/** - * Assign a user pointer to the chat room. - * @param[in] cr The chat room. - * @param[in] ud The user pointer to associate with the chat room. -**/ -LINPHONE_PUBLIC void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void *ud); - - /** - * Create a message attached to a dedicated chat room with a particular content. - * Use #linphone_chat_room_send_message to initiate the transfer - * @param cr the chat room. - * @param initial_content #LinphoneContent initial content. #LinphoneCoreVTable.file_transfer_send is invoked later to notify file transfer progress and collect next chunk of the message if LinphoneContent.data is NULL. - * @return a new #LinphoneChatMessage - */ -LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent* initial_content); - -/** - * get peer address \link linphone_core_get_chat_room() associated to \endlink this #LinphoneChatRoom - * @param cr #LinphoneChatRoom object - * @return #LinphoneAddress peer address - */ -LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr); - -/** - * Send a message to peer member of this chat room. - * @deprecated Use linphone_chat_room_send_chat_message() instead. - * @param cr #LinphoneChatRoom object - * @param msg message to be sent - * @donotwrap - */ -LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg); - -/** - * Send a message to peer member of this chat room. - * @param cr #LinphoneChatRoom object - * @param msg #LinphoneChatMessage message to be sent - * @param status_cb LinphoneChatMessageStateChangeCb status callback invoked when message is delivered or could not be delivered. May be NULL - * @param ud user data for the status cb. - * @deprecated Use linphone_chat_room_send_chat_message() instead. - * @note The LinphoneChatMessage must not be destroyed until the the callback is called. - * The LinphoneChatMessage reference is transfered to the function and thus doesn't need to be unref'd by the application. - * @donotwrap - */ -LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangedCb status_cb,void* ud); - -/** - * Send a message to peer member of this chat room. - * @param[in] cr LinphoneChatRoom object - * @param[in] msg LinphoneChatMessage object - * The state of the message sending will be notified via the callbacks defined in the LinphoneChatMessageCbs object that can be obtained - * by calling linphone_chat_message_get_callbacks(). - * The LinphoneChatMessage reference is transfered to the function and thus doesn't need to be unref'd by the application. - * @donotwrap - */ -LINPHONE_PUBLIC void linphone_chat_room_send_chat_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg); - -/** - * Mark all messages of the conversation as read - * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation. - */ -LINPHONE_PUBLIC void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr); - -/** - * Delete a message from the chat room history. - * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation. - * @param[in] msg The #LinphoneChatMessage object to remove. - */ - -LINPHONE_PUBLIC void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg); - -/** - * Delete all messages from the history - * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation. - */ -LINPHONE_PUBLIC void linphone_chat_room_delete_history(LinphoneChatRoom *cr); - -/** - * Gets the number of messages in a chat room. - * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which size has to be computed - * @return the number of messages. - */ -LINPHONE_PUBLIC int linphone_chat_room_get_history_size(LinphoneChatRoom *cr); - -/** - * Gets nb_message most recent messages from cr chat room, sorted from oldest to most recent. - * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which messages should be retrieved - * @param[in] nb_message Number of message to retrieve. 0 means everything. - * @return \bctbx_list{LinphoneChatMessage} - */ -LINPHONE_PUBLIC bctbx_list_t *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message); - -/** - * Gets the partial list of messages in the given range, sorted from oldest to most recent. - * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which messages should be retrieved - * @param[in] begin The first message of the range to be retrieved. History most recent message has index 0. - * @param[in] end The last message of the range to be retrieved. History oldest message has index of history size - 1 (use #linphone_chat_room_get_history_size to retrieve history size) - * @return \bctbx_list{LinphoneChatMessage} - */ -LINPHONE_PUBLIC bctbx_list_t *linphone_chat_room_get_history_range(LinphoneChatRoom *cr, int begin, int end); - -LINPHONE_PUBLIC LinphoneChatMessage * linphone_chat_room_find_message(LinphoneChatRoom *cr, const char *message_id); - -/** - * Notifies the destination of the chat message being composed that the user is typing a new message. - * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which a new message is being typed. - */ -LINPHONE_PUBLIC void linphone_chat_room_compose(LinphoneChatRoom *cr); - -/** - * Tells whether the remote is currently composing a message. - * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation. - * @return TRUE if the remote is currently composing a message, FALSE otherwise. - */ -LINPHONE_PUBLIC bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr); - -/** - * Gets the number of unread messages in the chatroom. - * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation. - * @return the number of unread messages. - */ -LINPHONE_PUBLIC int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr); - -/** - * Returns back pointer to #LinphoneCore object. - * @deprecated use linphone_chat_room_get_core() - * @donotwrap -**/ -LINPHONE_PUBLIC LINPHONE_DEPRECATED LinphoneCore* linphone_chat_room_get_lc(const LinphoneChatRoom *cr); - -/** - * Returns back pointer to #LinphoneCore object. -**/ -LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_core(const LinphoneChatRoom *cr); - -/** - * When realtime text is enabled #linphone_call_params_realtime_text_enabled, #LinphoneCoreIsComposingReceivedCb is call everytime a char is received from peer. - * At the end of remote typing a regular #LinphoneChatMessage is received with committed data from #LinphoneCoreMessageReceivedCb. - * @param[in] cr #LinphoneChatRoom object - * @returns RFC 4103/T.140 char - */ -LINPHONE_PUBLIC uint32_t linphone_chat_room_get_char(const LinphoneChatRoom *cr); - -/** - * Returns true if lime is available for given peer - * - * @return true if zrtp secrets have already been shared and ready to use - */ -LINPHONE_PUBLIC bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr); - /** * Returns an list of chat rooms * @param[in] lc #LinphoneCore object @@ -550,14 +356,6 @@ LINPHONE_PUBLIC LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessag */ LINPHONE_PUBLIC const char* linphone_chat_message_get_message_id(const LinphoneChatMessage *cm); -/** - * get Curent Call associated to this chatroom if any - * To commit a message, use #linphone_chat_room_send_message - * @param[in] room LinphoneChatRomm - * @returns LinphoneCall or NULL. - */ -LINPHONE_PUBLIC LinphoneCall *linphone_chat_room_get_call(const LinphoneChatRoom *room); - /** * Get the LinphoneChatMessageCbs object associated with the LinphoneChatMessage. * @param[in] msg LinphoneChatMessage object From 77397eab832e1b06044f2fbe0505f1195ed9ff98 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 15 Sep 2017 11:55:55 +0200 Subject: [PATCH 0071/2215] Fix bug in Wrapper::setCppPtrFromC where the cppObject was not really assigned. --- src/c-wrapper/c-tools.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index df312fc34..7b50db728 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -120,9 +120,9 @@ public: T *oldPtr = reinterpret_cast(static_cast *>(object)->cppPtr); if (oldPtr != cppPtr) { delete oldPtr; - T *cppObject = static_cast *>(object)->cppPtr; - cppObject = new T(*cppPtr); - cppObject->setProperty("LinphonePrivate::Wrapper::cBackPtr", object); + T **cppObject = &static_cast *>(object)->cppPtr; + *cppObject = new T(*cppPtr); + (*cppObject)->setProperty("LinphonePrivate::Wrapper::cBackPtr", object); } } From b3d868015050b81d2a0044964dc4048bcd756a4f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 15 Sep 2017 12:03:18 +0200 Subject: [PATCH 0072/2215] No longer include a userData field in the C clonable structs. --- src/c-wrapper/api/c-call-params.cpp | 6 +++--- src/c-wrapper/c-tools.h | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index ead25cae9..13d515655 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -492,12 +492,12 @@ void linphone_call_params_set_no_user_consent(LinphoneCallParams *params, bool_t * Reference and user data handling functions * ******************************************************************************/ -void *linphone_call_params_get_user_data(const LinphoneCallParams *cp) { - return cp->userData; +void * linphone_call_params_get_user_data(const LinphoneCallParams *cp) { + return L_GET_USER_DATA_FROM_C_STRUCT(cp, MediaSessionParams, CallParams); } void linphone_call_params_set_user_data(LinphoneCallParams *cp, void *ud) { - cp->userData = ud; + L_SET_USER_DATA_FROM_C_STRUCT(cp, ud, MediaSessionParams, CallParams); } LinphoneCallParams * linphone_call_params_ref(LinphoneCallParams *cp) { diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index 7b50db728..a5300446d 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -42,7 +42,6 @@ private: template struct WrappedClonableObject { belle_sip_object_t base; - void *userData; T *cppPtr; }; @@ -271,7 +270,6 @@ LINPHONE_END_NAMESPACE #define L_DECLARE_C_CLONABLE_STRUCT_IMPL(CPP_CLASS, C_STRUCT, C_NAME, ...) \ struct _Linphone ## C_STRUCT { \ belle_sip_object_t base; \ - void *userData; \ LINPHONE_NAMESPACE::CPP_CLASS *cppPtr; \ __VA_ARGS__ \ }; \ From d619eba238e43bf2c5672dd2d2e6e259ef061600 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 15 Sep 2017 12:04:09 +0200 Subject: [PATCH 0073/2215] feat(Variant): add getValueAsString impl --- include/linphone/utils/utils.h | 1 + src/utils/utils.cpp | 6 +++ src/variant/variant.cpp | 60 +++++++++++++++++++++++----- tester/property-container-tester.cpp | 14 ++++++- 4 files changed, 69 insertions(+), 12 deletions(-) diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h index ddb9eb40a..4321e37eb 100644 --- a/include/linphone/utils/utils.h +++ b/include/linphone/utils/utils.h @@ -46,6 +46,7 @@ namespace Utils { LINPHONE_PUBLIC std::string toString (float val); LINPHONE_PUBLIC std::string toString (double val); LINPHONE_PUBLIC std::string toString (long double val); + LINPHONE_PUBLIC std::string toString (const void *val); LINPHONE_PUBLIC int stoi (const std::string &str, size_t *idx = 0, int base = 10); LINPHONE_PUBLIC double stod (const std::string &str, size_t *idx = 0); diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 9e4033f4d..e67796e34 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -78,6 +78,12 @@ TO_STRING_IMPL(float) TO_STRING_IMPL(double) TO_STRING_IMPL(long double) +string Utils::toString (const void *val) { + ostringstream ss; + ss << val; + return ss.str(); +} + int Utils::stoi (const string &str, size_t *idx, int base) { char *p; int v = strtol(str.c_str(), &p, base); diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index 952564293..edaa139f7 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -69,7 +69,7 @@ public: private: inline void deleteString () { if (type == Variant::String) - delete value.str; + delete value.str; } // Integer, because type can be a custom type. @@ -250,7 +250,8 @@ bool Variant::isValid () const { } void Variant::clear () { - // TODO. + L_D(Variant); + d->setType(Invalid); } void Variant::swap (const Variant &variant) { @@ -374,7 +375,6 @@ static inline double getValueAsDouble (const VariantPrivate &p, bool *soFarSoGoo case Variant::Long: case Variant::LongLong: case Variant::Char: - case Variant::Float: return static_cast(getAssumedNumber(p)); case Variant::UnsignedInt: @@ -383,6 +383,9 @@ static inline double getValueAsDouble (const VariantPrivate &p, bool *soFarSoGoo case Variant::UnsignedLongLong: return static_cast(getAssumedUnsignedNumber(p)); + case Variant::Float: + return static_cast(p.value.f); + case Variant::Double: return p.value.d; @@ -408,9 +411,46 @@ static inline float getValueAsFloat (const VariantPrivate &p, bool *soFarSoGood) return 0.f; } -static inline float getValueAsString (const VariantPrivate &p, bool *soFarSoGood) { - // TODO. - return 0.f; +static inline string getValueAsString (const VariantPrivate &p, bool *soFarSoGood) { + const int type = p.getType(); + L_ASSERT(type > Variant::Invalid && type < Variant::MaxDefaultTypes); + + switch (static_cast(type)) { + case Variant::Int: + case Variant::Short: + case Variant::Long: + case Variant::LongLong: + return Utils::toString(getAssumedNumber(p)); + + case Variant::UnsignedInt: + case Variant::UnsignedShort: + case Variant::UnsignedLong: + case Variant::UnsignedLongLong: + return Utils::toString(getAssumedUnsignedNumber(p)); + + case Variant::Char: + return string(1, p.value.c); + + case Variant::Bool: + return string(p.value.b ? "true" : "false"); + + case Variant::Double: + return Utils::toString(p.value.d); + + case Variant::Float: + return Utils::toString(p.value.f); + + case Variant::String: + return *p.value.str; + + case Variant::Generic: + return Utils::toString(p.value.g); + + default: + *soFarSoGood = false; + } + + return string(); } static inline void *getValueAsGeneric (const VariantPrivate &p, bool *soFarSoGood) { @@ -456,16 +496,16 @@ void Variant::getValue (int type, void *value, bool *soFarSoGood) const { // Cast as Unsigned number. case UnsignedInt: - *static_cast(value) = static_cast(getValueAsNumber(*d, soFarSoGood)); + *static_cast(value) = static_cast(getValueAsUnsignedNumber(*d, soFarSoGood)); break; case UnsignedShort: - *static_cast(value) = static_cast(getValueAsNumber(*d, soFarSoGood)); + *static_cast(value) = static_cast(getValueAsUnsignedNumber(*d, soFarSoGood)); break; case UnsignedLong: - *static_cast(value) = static_cast(getValueAsNumber(*d, soFarSoGood)); + *static_cast(value) = static_cast(getValueAsUnsignedNumber(*d, soFarSoGood)); break; case UnsignedLongLong: - *static_cast(value) = getValueAsNumber(*d, soFarSoGood); + *static_cast(value) = getValueAsUnsignedNumber(*d, soFarSoGood); break; // Cast as specific value. diff --git a/tester/property-container-tester.cpp b/tester/property-container-tester.cpp index 6cc7fffb7..2decc9164 100644 --- a/tester/property-container-tester.cpp +++ b/tester/property-container-tester.cpp @@ -26,14 +26,23 @@ using namespace std; using namespace LinphonePrivate; -// ----------------------------------------------------------------------------- - static void set_int_property () { PropertyContainer properties; properties.setProperty("integer", 42); BC_ASSERT_EQUAL(properties.getProperty("integer").getValue(), 42, int, "%d"); } +static void set_string_property () { + PropertyContainer properties; + const string text = "Hey listen!"; + properties.setProperty("string", text); + + { + string textToCheck = properties.getProperty("string").getValue(); + BC_ASSERT_STRING_EQUAL(textToCheck.c_str(), text.c_str()); + } +} + static void set_generic_property () { PropertyContainer properties; properties.setProperty("generic", reinterpret_cast(0x42)); @@ -42,6 +51,7 @@ static void set_generic_property () { test_t property_container_tests[] = { TEST_NO_TAG("Set int property", set_int_property), + TEST_NO_TAG("Set string property", set_string_property), TEST_NO_TAG("Set generic property", set_generic_property) }; From acce40efc3bf423a6bfb0aab611499bd4866bb4f Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 15 Sep 2017 14:36:08 +0200 Subject: [PATCH 0074/2215] feat(Variant): add getValueAsFloat impl --- include/linphone/utils/utils.h | 1 + src/utils/utils.cpp | 14 +++++++++++-- src/variant/variant.cpp | 38 +++++++++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h index 4321e37eb..bbdeccc68 100644 --- a/include/linphone/utils/utils.h +++ b/include/linphone/utils/utils.h @@ -50,6 +50,7 @@ namespace Utils { LINPHONE_PUBLIC int stoi (const std::string &str, size_t *idx = 0, int base = 10); LINPHONE_PUBLIC double stod (const std::string &str, size_t *idx = 0); + LINPHONE_PUBLIC float stof (const std::string &str, size_t *idx = 0); LINPHONE_PUBLIC bool stob (const std::string &str); LINPHONE_PUBLIC std::string stringToLower (const std::string &str); diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index e67796e34..f2369576e 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -94,12 +94,22 @@ int Utils::stoi (const string &str, size_t *idx, int base) { return v; } -double Utils::stod (const std::string &str, size_t *idx) { +double Utils::stod (const string &str, size_t *idx) { char *p; double v = strtod(str.c_str(), &p); if (idx) - *idx = p - str.c_str(); + *idx = p - str.c_str(); + + return v; +} + +float Utils::stof (const string &str, size_t *idx) { + char *p; + float v = strtof(str.c_str(), &p); + + if (idx) + *idx = p - str.c_str(); return v; } diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index edaa139f7..eb538cedf 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -407,7 +407,43 @@ static inline double getValueAsDouble (const VariantPrivate &p, bool *soFarSoGoo } static inline float getValueAsFloat (const VariantPrivate &p, bool *soFarSoGood) { - // TODO. + const int type = p.getType(); + L_ASSERT(type > Variant::Invalid && type < Variant::MaxDefaultTypes); + + switch (static_cast(type)) { + case Variant::Int: + case Variant::Short: + case Variant::Long: + case Variant::LongLong: + case Variant::Char: + return static_cast(getAssumedNumber(p)); + + case Variant::UnsignedInt: + case Variant::UnsignedShort: + case Variant::UnsignedLong: + case Variant::UnsignedLongLong: + return static_cast(getAssumedUnsignedNumber(p)); + + case Variant::Float: + return p.value.f; + + case Variant::Double: + return static_cast(p.value.d); + + case Variant::Bool: + return static_cast(p.value.b); + + case Variant::String: + return Utils::stof(*p.value.str); + + case Variant::Generic: + return static_cast(!!p.value.g); + + default: + *soFarSoGood = false; + break; + } + return 0.f; } From de2fed5204975b8d654f5171fa074a17fd000e72 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 15 Sep 2017 14:38:02 +0200 Subject: [PATCH 0075/2215] fix(Variant): export as public --- src/variant/variant.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/variant/variant.h b/src/variant/variant.h index c05df2930..ac15d2969 100644 --- a/src/variant/variant.h +++ b/src/variant/variant.h @@ -52,7 +52,7 @@ LINPHONE_BEGIN_NAMESPACE class VariantPrivate; -class Variant { +class LINPHONE_PUBLIC Variant { public: enum Type { Invalid = 0, @@ -97,7 +97,7 @@ public: template void setValue (const T &value) { - // Yeah, I'm crazy. + // Yeah, I'm crazy but it's useful to avoid code duplication. new (this) Variant(value); } From 2f74df954f6e761719a5e6e31c6226af779420a0 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 15 Sep 2017 15:42:02 +0200 Subject: [PATCH 0076/2215] Improve conversion of lists in c-tools. --- src/c-wrapper/api/c-chat-room.cpp | 2 +- src/c-wrapper/c-tools.h | 50 +++++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 5540611ce..4d22db9ab 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -236,7 +236,7 @@ LinphoneChatRoom * linphone_client_group_chat_room_new(LinphoneCore *lc, const b if (from.empty()) from = linphone_core_get_primary_contact(lc); LinphonePrivate::Address me(from); - std::list l = L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(addresses, Address); + std::list l = L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(addresses, Address, Address); LinphoneChatRoom *cr = _linphone_chat_room_init(); L_SET_CPP_PTR_FROM_C_STRUCT(cr, make_shared(lc, me, l)); return cr; diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index a5300446d..d97057a3a 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -68,7 +68,6 @@ public: typename CppType, typename CType, typename = typename std::enable_if::value, CppType>::type - //typename std::enable_if::value, CppType>::type = 0 > static inline std::shared_ptr getCppPtrFromC (CType *object) { L_ASSERT(object); @@ -79,7 +78,6 @@ public: typename CppType, typename CType, typename = typename std::enable_if::value, CppType>::type - //typename std::enable_if::value, CppType>::type = 0 > static inline std::shared_ptr getCppPtrFromC (const CType *object) { L_ASSERT(object); @@ -186,13 +184,29 @@ public: // --------------------------------------------------------------------------- template - static inline bctbx_list_t * getCListFromCppList (std::list cppList) { + static inline bctbx_list_t * getCListFromCppList (const std::list cppList) { bctbx_list_t *result = nullptr; for (const auto &value : cppList) result = bctbx_list_append(result, value); return result; } + template + static inline bctbx_list_t * getCListOfStructPtrFromCppListOfCppObj (const std::list> cppList, CType *(*cTypeAllocator)()) { + bctbx_list_t *result = nullptr; + for (const auto &value : cppList) + result = bctbx_list_append(result, getCBackPtr(value, cTypeAllocator)); + return result; + } + + template + static inline bctbx_list_t * getCListOfStructPtrFromCppListOfCppObj (const std::list cppList, CType *(*cTypeAllocator)()) { + bctbx_list_t *result = nullptr; + for (const auto &value : cppList) + result = bctbx_list_append(result, getCBackPtr(value, cTypeAllocator)); + return result; + } + template static inline std::list getCppListFromCList (const bctbx_list_t *cList) { std::list result; @@ -201,11 +215,27 @@ public: return result; } - template - static inline std::list getCppListOfCppObjFromCListOfStructPtr (const bctbx_list_t *cList) { - std::list result; + template< + typename CppType, + typename CType, + typename = typename std::enable_if::value, CppType>::type + > + static inline std::list> getCppListOfCppObjFromCListOfStructPtr (const bctbx_list_t *cList) { + std::list> result; for (auto it = cList; it; it = bctbx_list_next(it)) - result.push_back(*getCppPtrFromC(reinterpret_cast(bctbx_list_get_data(it)))); + result.push_back(getCppPtrFromC(reinterpret_cast(bctbx_list_get_data(it)))); + return result; + } + + template< + typename CppType, + typename CType, + typename = typename std::enable_if::value, CppType>::type + > + static inline std::list getCppListOfCppObjFromCListOfStructPtr (const bctbx_list_t *cList) { + std::list result; + for (auto it = cList; it; it = bctbx_list_next(it)) + result.push_back(*getCppPtrFromC(reinterpret_cast(bctbx_list_get_data(it)))); return result; } @@ -333,7 +363,9 @@ LINPHONE_END_NAMESPACE LINPHONE_NAMESPACE::Wrapper::getCListFromCppList(LIST) #define L_GET_CPP_LIST_FROM_C_LIST(LIST, TYPE) \ LINPHONE_NAMESPACE::Wrapper::getCppListFromCList(LIST) -#define L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(LIST, TYPE) \ - LINPHONE_NAMESPACE::Wrapper::getCppListOfCppObjFromCListOfStructPtr(LIST) +#define L_GET_C_LIST_OF_STRUCT_PTR_FROM_CPP_LIST_OF_CPP_OBJ(LIST, CPP_TYPE, C_TYPE, C_NAME) \ + LINPHONE_NAMESPACE::Wrapper::getCListOfStructPtrFromCppListOfCppObj(LIST, _linphone_ ## C_NAME ## _init) +#define L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(LIST, CPP_TYPE, C_TYPE) \ + LINPHONE_NAMESPACE::Wrapper::getCppListOfCppObjFromCListOfStructPtr(LIST) #endif // ifndef _C_TOOLS_H_ From d7dbb9b98442718d9c4d0170cfc448eb34f53c92 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 15 Sep 2017 15:42:49 +0200 Subject: [PATCH 0077/2215] Wrap the conference interface in the C chat room object. --- include/linphone/api/c-chat-room.h | 59 ++++++++++++++++++++++++++++++ include/linphone/api/c-types.h | 5 +++ src/c-wrapper/api/c-chat-room.cpp | 37 +++++++++++++++++++ 3 files changed, 101 insertions(+) diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index 5cf75e77d..241609a9c 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -223,6 +223,65 @@ LINPHONE_PUBLIC bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr); */ LINPHONE_PUBLIC LinphoneCall *linphone_chat_room_get_call(const LinphoneChatRoom *room); +/** + * Add a participant to a chat room. This may fail if this type of chat room does not handle participants. + * Use linphone_chat_room_can_handle_participants() to know if this chat room handles participants. + * @param[in] cr A LinphoneChatRoom object + * @param[in] addr The address of the participant to add to the chat room + * @return The newly added participant or NULL in case of failure + */ +LINPHONE_PUBLIC LinphoneParticipant * linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr); + +/** + * Add several participants to a chat room at once. This may fail if this type of chat room does not handle participants. + * Use linphone_chat_room_can_handle_participants() to know if this chat room handles participants. + * @param[in] cr A LinphoneChatRoom object + * @param[in] addresses \bctbx_list{LinphoneAddress} + */ +LINPHONE_PUBLIC void linphone_chat_room_add_participants (LinphoneChatRoom *cr, const bctbx_list_t *addresses); + +/** + * Tells whether a chat room is able to handle participants. + * @param[in] cr A LinphoneChatRoom object + * @return A boolean value telling whether the chat room can handle participants or not + */ +LINPHONE_PUBLIC bool_t linphone_chat_room_can_handle_participants (const LinphoneChatRoom *cr); + +/** + * Get the conference ID of the chat room. + * @param[in] cr A LinphoneChatRoom object + * @return The conference ID of the chat room or NULL if this type of chat room is not conference based + */ +LINPHONE_PUBLIC const char * linphone_chat_room_get_id (const LinphoneChatRoom *cr); + +/** + * Get the number of participants in the chat room (that is without ourselves). + * @param[in] cr A LinphoneChatRoom object + * @return The number of participants in the chat room + */ +LINPHONE_PUBLIC int linphone_chat_room_get_nb_participants (const LinphoneChatRoom *cr); + +/** + * Get the list of participants of a chat room. + * @param[in] cr A LinphoneChatRoom object + * @return \bctbx_list{LinphoneParticipant} + */ +LINPHONE_PUBLIC bctbx_list_t * linphone_chat_room_get_participants (const LinphoneChatRoom *cr); + +/** + * Remove a participant of a chat room. + * @param[in] cr A LinphoneChatRoom object + * @param[in] participant The participant to remove from the chat room + */ +LINPHONE_PUBLIC void linphone_chat_room_remove_participant (LinphoneChatRoom *cr, LinphoneParticipant *participant); + +/** + * Remove several participants of a chat room at once. + * @param[in] cr A LinphoneChatRoom object + * @param[in] participants \bctbx_list{LinphoneParticipant} + */ +LINPHONE_PUBLIC void linphone_chat_room_remove_participants (LinphoneChatRoom *cr, const bctbx_list_t *participants); + /** * Returns back pointer to #LinphoneCore object. * @deprecated use linphone_chat_room_get_core() diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index 3fea38e86..a550c9cc8 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -81,6 +81,11 @@ typedef struct _LinphoneConferenceParticipantEvent LinphoneConferenceParticipant typedef struct _LinphoneEventLog LinphoneEventLog; typedef struct _LinphoneMessage LinphoneMessage; typedef struct _LinphoneMessageEvent LinphoneMessageEvent; + +/** + * The LinphoneParticipant object represents a participant of a conference. + * @ingroup misc +**/ typedef struct _LinphoneParticipant LinphoneParticipant; // ============================================================================= diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 4d22db9ab..bc3e93450 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -35,6 +35,8 @@ using namespace std; #define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, ChatRoom, ChatRoom) +extern LinphoneParticipant * _linphone_participant_init(); + static void _linphone_chat_room_constructor(LinphoneChatRoom *cr); static void _linphone_chat_room_destructor(LinphoneChatRoom *cr); @@ -187,6 +189,41 @@ LinphoneChatMessage * linphone_chat_room_find_message(LinphoneChatRoom *cr, cons return GET_CPP_PTR(cr)->findMessage(message_id); } +LinphoneParticipant * linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr) { + return L_GET_C_BACK_PTR(GET_CPP_PTR(cr)->addParticipant( + *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address, Address), nullptr, false), + Participant, participant); +} + +void linphone_chat_room_add_participants (LinphoneChatRoom *cr, const bctbx_list_t *addresses) { + GET_CPP_PTR(cr)->addParticipants(L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(addresses, Address, Address), nullptr, false); +} + +bool_t linphone_chat_room_can_handle_participants (const LinphoneChatRoom *cr) { + return GET_CPP_PTR(cr)->canHandleParticipants(); +} + +const char * linphone_chat_room_get_id (const LinphoneChatRoom *cr) { + string id = GET_CPP_PTR(cr)->getId(); + return id.empty() ? nullptr : id.c_str(); +} + +int linphone_chat_room_get_nb_participants (const LinphoneChatRoom *cr) { + return GET_CPP_PTR(cr)->getNbParticipants(); +} + +bctbx_list_t * linphone_chat_room_get_participants (const LinphoneChatRoom *cr) { + return L_GET_C_LIST_OF_STRUCT_PTR_FROM_CPP_LIST_OF_CPP_OBJ(GET_CPP_PTR(cr)->getParticipants(), Participant, Participant, participant); +} + +void linphone_chat_room_remove_participant (LinphoneChatRoom *cr, LinphoneParticipant *participant) { + GET_CPP_PTR(cr)->removeParticipant(L_GET_CPP_PTR_FROM_C_STRUCT(participant, Participant, Participant)); +} + +void linphone_chat_room_remove_participants (LinphoneChatRoom *cr, const bctbx_list_t *participants) { + GET_CPP_PTR(cr)->removeParticipants(L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(participants, Participant, Participant)); +} + /******************************************************************************* * Reference and user data handling functions * From 902d6c1d69a93acc0abf7460c3801ac60c15118a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 15 Sep 2017 16:14:46 +0200 Subject: [PATCH 0078/2215] Fix crash in chat room destruction. --- src/chat/chat-room.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 2499e1b43..6d1f6484a 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -41,18 +41,9 @@ ChatRoomPrivate::ChatRoomPrivate (LinphoneCore *core) : core(core), isComposingHandler(core, this) {} ChatRoomPrivate::~ChatRoomPrivate () { - L_Q(ChatRoom); for (auto it = transientMessages.begin(); it != transientMessages.end(); it++) { linphone_chat_message_release(*it); } - if (core) { - if (bctbx_list_find(core->chatrooms, GET_BACK_PTR(q))) { - lError() << "LinphoneChatRoom[" << GET_BACK_PTR(q) << "] is destroyed while still being used by the LinphoneCore. " << - "This is abnormal. linphone_core_get_chat_room() doesn't give a reference, there is no need to call linphone_chat_room_unref(). " << - "In order to remove a chat room from the core, use linphone_core_delete_chat_room()."; - core->chatrooms = bctbx_list_remove(core->chatrooms, GET_BACK_PTR(q)); - } - } if (pendingMessage) linphone_chat_message_destroy(pendingMessage); } From 0a15a02ff07d3c158e0747a908b02780e3818b31 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 18 Sep 2017 11:52:35 +0200 Subject: [PATCH 0079/2215] Add callbacks to the LinphoneChatRoom object. --- coreapi/linphonecore.c | 8 ++ coreapi/private.h | 3 + coreapi/vtables.c | 5 ++ include/CMakeLists.txt | 2 + include/linphone/api/c-callbacks.h | 65 ++++++++++++++ include/linphone/api/c-chat-room-cbs.h | 113 +++++++++++++++++++++++++ include/linphone/api/c-chat-room.h | 7 ++ include/linphone/api/c-types.h | 13 +++ include/linphone/callbacks.h | 8 ++ include/linphone/chat.h | 1 + include/linphone/core.h | 15 ++++ include/linphone/types.h | 7 -- src/CMakeLists.txt | 1 + src/c-wrapper/api/c-chat-room-cbs.cpp | 86 +++++++++++++++++++ src/c-wrapper/api/c-chat-room.cpp | 23 +++-- src/chat/chat-room-p.h | 4 + src/chat/chat-room.cpp | 40 +++++++-- 17 files changed, 379 insertions(+), 22 deletions(-) create mode 100644 include/linphone/api/c-callbacks.h create mode 100644 include/linphone/api/c-chat-room-cbs.h create mode 100644 src/c-wrapper/api/c-chat-room-cbs.cpp diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 8e4416df4..de865fead 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -425,6 +425,14 @@ void linphone_core_cbs_set_version_update_check_result_received(LinphoneCoreCbs cbs->vtable->version_update_check_result_received = cb; } +LinphoneCoreCbsChatRoomInstantiatedCb linphone_core_cbs_get_chat_room_instantiated (LinphoneCoreCbs *cbs) { + return cbs->vtable->chat_room_instantiated; +} + +void linphone_core_cbs_set_chat_room_instantiated (LinphoneCoreCbs *cbs, LinphoneCoreCbsChatRoomInstantiatedCb cb) { + cbs->vtable->chat_room_instantiated = cb; +} + typedef belle_sip_object_t_vptr_t LinphoneCore_vptr_t; BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCore); diff --git a/coreapi/private.h b/coreapi/private.h index d8f94da45..7f25bb906 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -508,6 +508,7 @@ LinphoneChatRoom * linphone_client_group_chat_room_new(LinphoneCore *lc, const b void linphone_chat_room_release(LinphoneChatRoom *cr); void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call); bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr); +LinphoneChatRoomCbs * linphone_chat_room_cbs_new (void); void linphone_chat_message_destroy(LinphoneChatMessage* msg); void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state); void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessageState state); @@ -1681,6 +1682,7 @@ BELLE_SIP_TYPE_ID(LinphoneCallParams), BELLE_SIP_TYPE_ID(LinphoneChatMessage), BELLE_SIP_TYPE_ID(LinphoneChatMessageCbs), BELLE_SIP_TYPE_ID(LinphoneChatRoom), +BELLE_SIP_TYPE_ID(LinphoneChatRoomCbs), BELLE_SIP_TYPE_ID(LinphoneContent), BELLE_SIP_TYPE_ID(LinphoneImEncryptionEngine), BELLE_SIP_TYPE_ID(LinphoneImEncryptionEngineCbs), @@ -1770,6 +1772,7 @@ void linphone_core_notify_friend_list_created(LinphoneCore *lc, LinphoneFriendLi void linphone_core_notify_friend_list_removed(LinphoneCore *lc, LinphoneFriendList *list); void linphone_core_notify_call_created(LinphoneCore *lc, LinphoneCall *call); void linphone_core_notify_version_update_check_result_received(LinphoneCore *lc, LinphoneVersionUpdateCheckResult result, const char *version, const char *url); +void linphone_core_notify_chat_room_instantiated (LinphoneCore *lc, LinphoneChatRoom *cr); void set_playback_gain_db(AudioStream *st, float gain); diff --git a/coreapi/vtables.c b/coreapi/vtables.c index ca9960ef9..ada08a8e7 100644 --- a/coreapi/vtables.c +++ b/coreapi/vtables.c @@ -321,6 +321,11 @@ void linphone_core_notify_version_update_check_result_received(LinphoneCore *lc, cleanup_dead_vtable_refs(lc); } +void linphone_core_notify_chat_room_instantiated (LinphoneCore *lc, LinphoneChatRoom *cr) { + NOTIFY_IF_EXIST(chat_room_instantiated, lc, cr); + cleanup_dead_vtable_refs(lc); +} + static VTableReference * v_table_reference_new(LinphoneCoreCbs *cbs, bool_t internal){ VTableReference *ref=ms_new0(VTableReference,1); ref->valid=TRUE; diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index ecedd8a55..54af30490 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -76,7 +76,9 @@ set(ROOT_HEADER_FILES set(C_API_HEADER_FILES c-address.h c-api.h + c-callbacks.h c-chat-room.h + c-chat-room-cbs.h c-event-log.h c-participant.h c-types.h diff --git a/include/linphone/api/c-callbacks.h b/include/linphone/api/c-callbacks.h new file mode 100644 index 000000000..7402dda84 --- /dev/null +++ b/include/linphone/api/c-callbacks.h @@ -0,0 +1,65 @@ +/* + * c-callbacks.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _C_CALLBACKS_H_ +#define _C_CALLBACKS_H_ + +// TODO: Remove me in the future. +#include "linphone/callbacks.h" + +// ============================================================================= + +#ifdef __cplusplus + extern "C" { +#endif // ifdef __cplusplus + +/** + * @addtogroup chatroom + * @{ + */ + +/** + * Is composing notification callback prototype. + * @param[in] cr #LinphoneChatRoom involved in the conversation + * @param[in] participant The #LinphoneParticipant that has sent the is-composing notification + */ +typedef void (*LinphoneChatRoomCbsIsComposingReceivedCb) (LinphoneChatRoom *cr, const LinphoneParticipant *participant); + +/** + * Callback used to notify a chat room that a message has been received. + * @param[in] cr #LinphoneChatRoom object + * @param[in] msg The #LinphoneChatMessage that has been received + */ +typedef void (*LinphoneChatRoomCbsMessageReceivedCb) (LinphoneChatRoom *cr, LinphoneChatMessage *msg); + +/** + * Callback used to notify a chat room that a message has been received but we were unable to decrypt it + * @param cr #LinphoneChatRoom involved in this conversation + * @param msg The #LinphoneChatMessage that has been received + */ +typedef void (*LinphoneChatRoomCbsUndecryptableMessageReceivedCb) (LinphoneChatRoom *cr, LinphoneChatMessage *msg); + +/** + * @} +**/ + +#ifdef __cplusplus + } +#endif // ifdef __cplusplus + +#endif // ifndef _C_CALLBACKS_H_ diff --git a/include/linphone/api/c-chat-room-cbs.h b/include/linphone/api/c-chat-room-cbs.h new file mode 100644 index 000000000..2b26c2a3f --- /dev/null +++ b/include/linphone/api/c-chat-room-cbs.h @@ -0,0 +1,113 @@ +/* + * c-chat-room-cbs.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _C_CHAT_ROOM_CBS_H_ +#define _C_CHAT_ROOM_CBS_H_ + +#include "linphone/api/c-callbacks.h" +#include "linphone/api/c-types.h" + +// ============================================================================= + +#ifdef __cplusplus + extern "C" { +#endif // ifdef __cplusplus + +/** + * @addtogroup chatroom + * @{ + */ + +/** + * Acquire a reference to the chat room callbacks object. + * @param[in] cbs The chat room callbacks object + * @return The same chat room callbacks object +**/ +LINPHONE_PUBLIC LinphoneChatRoomCbs * linphone_chat_room_cbs_ref (LinphoneChatRoomCbs *cbs); + +/** + * Release reference to the chat room callbacks object. + * @param[in] cr The chat room callbacks object +**/ +LINPHONE_PUBLIC void linphone_chat_room_cbs_unref (LinphoneChatRoomCbs *cbs); + +/** + * Retrieve the user pointer associated with the chat room callbacks object. + * @param[in] cr The chat room callbacks object + * @return The user pointer associated with the chat room callbacks object +**/ +LINPHONE_PUBLIC void * linphone_chat_room_cbs_get_user_data (const LinphoneChatRoomCbs *cbs); + +/** + * Assign a user pointer to the chat room callbacks object. + * @param[in] cr The chat room callbacks object + * @param[in] ud The user pointer to associate with the chat room callbacks object +**/ +LINPHONE_PUBLIC void linphone_chat_room_cbs_set_user_data (LinphoneChatRoomCbs *cbs, void *ud); + +/** + * Get the is-composing received callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @return The current is-composing received callback. + */ +LINPHONE_PUBLIC LinphoneChatRoomCbsIsComposingReceivedCb linphone_chat_room_cbs_get_is_composing_received (const LinphoneChatRoomCbs *cbs); + +/** + * Set the is-composing received callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @param[in] cb The is-composing received callback to be used. + */ +LINPHONE_PUBLIC void linphone_chat_room_cbs_set_is_composing_received (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsIsComposingReceivedCb cb); + +/** + * Get the message received callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @return The current message received callback. + */ +LINPHONE_PUBLIC LinphoneChatRoomCbsMessageReceivedCb linphone_chat_room_cbs_get_message_received (const LinphoneChatRoomCbs *cbs); + +/** + * Set the message received callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @param[in] cb The message received callback to be used. + */ +LINPHONE_PUBLIC void linphone_chat_room_cbs_set_message_received (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsMessageReceivedCb cb); + +/** + * Get the undecryptable message received callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @return The current undecryptable message received callback. + */ +LINPHONE_PUBLIC LinphoneChatRoomCbsUndecryptableMessageReceivedCb linphone_chat_room_cbs_get_undecryptable_message_received (const LinphoneChatRoomCbs *cbs); + +/** + * Set the undecryptable message received callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @param[in] cb The undecryptable message received callback to be used. + */ +LINPHONE_PUBLIC void linphone_chat_room_cbs_set_undecryptable_message_received (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsUndecryptableMessageReceivedCb cb); + +/** + * @} + */ + +#ifdef __cplusplus + } +#endif // ifdef __cplusplus + +#endif // ifndef _C_CHAT_ROOM_H_ diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index 241609a9c..075abca35 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -223,6 +223,13 @@ LINPHONE_PUBLIC bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr); */ LINPHONE_PUBLIC LinphoneCall *linphone_chat_room_get_call(const LinphoneChatRoom *room); +/** + * Get the LinphoneChatRoomCbs object associated with the LinphoneChatRoom. + * @param[in] cr LinphoneChatRoom object + * @return The LinphoneChatRoomCbs object associated with the LinphoneChatRoom + */ +LINPHONE_PUBLIC LinphoneChatRoomCbs * linphone_chat_room_get_callbacks (const LinphoneChatRoom *cr); + /** * Add a participant to a chat room. This may fail if this type of chat room does not handle participants. * Use linphone_chat_room_can_handle_participants() to know if this chat room handles participants. diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index a550c9cc8..79202b952 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -75,7 +75,20 @@ typedef struct _LinphoneAddress LinphoneAddress; typedef struct _LinphoneCall LinphoneCall; typedef struct _LinphoneCallEvent LinphoneCallEvent; + +/** + * A chat room is the place where text messages are exchanged. + * Can be created by linphone_core_create_chat_room(). + * @ingroup chatroom + */ typedef struct _LinphoneChatRoom LinphoneChatRoom; + +/** + * An object to handle the callbacks for the handling a LinphoneChatRoom objects. + * @ingroup chatroom + */ +typedef struct _LinphoneChatRoomCbs LinphoneChatRoomCbs; + typedef struct _LinphoneConferenceEvent LinphoneConferenceEvent; typedef struct _LinphoneConferenceParticipantEvent LinphoneConferenceParticipantEvent; typedef struct _LinphoneEventLog LinphoneEventLog; diff --git a/include/linphone/callbacks.h b/include/linphone/callbacks.h index e25180714..f9f892570 100644 --- a/include/linphone/callbacks.h +++ b/include/linphone/callbacks.h @@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/types.h" +#include "linphone/api/c-callbacks.h" /** @@ -502,6 +503,13 @@ typedef LinphoneCoreCbsFriendListRemovedCb LinphoneCoreFriendListRemovedCb; */ typedef void (*LinphoneCoreCbsVersionUpdateCheckResultReceivedCb) (LinphoneCore *lc, LinphoneVersionUpdateCheckResult result, const char *version, const char *url); +/** + * Callback prototype telling that a LinphoneChatRoom object has been instantiated. This is useful to set the callbacks on the LinphoneChatRoom object. + * @param[in] lc LinphoneCore object + * @param[in] cr The LinphoneChatRoom object that has been instantiated + */ +typedef void (*LinphoneCoreCbsChatRoomInstantiatedCb) (LinphoneCore *lc, LinphoneChatRoom *cr); + /** * @} **/ diff --git a/include/linphone/chat.h b/include/linphone/chat.h index 0660003b5..e84c70bae 100644 --- a/include/linphone/chat.h +++ b/include/linphone/chat.h @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/types.h" #include "linphone/api/c-types.h" #include "linphone/api/c-chat-room.h" +#include "linphone/api/c-chat-room-cbs.h" #ifdef __cplusplus diff --git a/include/linphone/core.h b/include/linphone/core.h index e34b45f9c..f3fa25583 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -218,6 +218,7 @@ typedef struct _LinphoneCoreVTable{ LinphoneCoreFriendListRemovedCb friend_list_removed; LinphoneCoreCbsCallCreatedCb call_created; LinphoneCoreCbsVersionUpdateCheckResultReceivedCb version_update_check_result_received; + LinphoneCoreCbsChatRoomInstantiatedCb chat_room_instantiated; void *user_data; /**. + */ + + +#include "linphone/api/c-chat-room-cbs.h" +#include "private.h" + + +struct _LinphoneChatRoomCbs { + belle_sip_object_t base; + void *userData; + LinphoneChatRoomCbsIsComposingReceivedCb isComposingReceivedCb; + LinphoneChatRoomCbsMessageReceivedCb messageReceivedCb; + LinphoneChatRoomCbsUndecryptableMessageReceivedCb undecryptableMessageReceivedCb; +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneChatRoomCbs); + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneChatRoomCbs); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneChatRoomCbs, belle_sip_object_t, + NULL, // destroy + NULL, // clone + NULL, // marshal + FALSE +); + +LinphoneChatRoomCbs * linphone_chat_room_cbs_new (void) { + return belle_sip_object_new(LinphoneChatRoomCbs); +} + +LinphoneChatRoomCbs * linphone_chat_room_cbs_ref (LinphoneChatRoomCbs *cbs) { + belle_sip_object_ref(cbs); + return cbs; +} + +void linphone_chat_room_cbs_unref (LinphoneChatRoomCbs *cbs) { + belle_sip_object_unref(cbs); +} + +void * linphone_chat_room_cbs_get_user_data (const LinphoneChatRoomCbs *cbs) { + return cbs->userData; +} + +void linphone_chat_room_cbs_set_user_data (LinphoneChatRoomCbs *cbs, void *ud) { + cbs->userData = ud; +} + +LinphoneChatRoomCbsIsComposingReceivedCb linphone_chat_room_cbs_get_is_composing_received (const LinphoneChatRoomCbs *cbs) { + return cbs->isComposingReceivedCb; +} + +void linphone_chat_room_cbs_set_is_composing_received (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsIsComposingReceivedCb cb) { + cbs->isComposingReceivedCb = cb; +} + +LinphoneChatRoomCbsMessageReceivedCb linphone_chat_room_cbs_get_message_received (const LinphoneChatRoomCbs *cbs) { + return cbs->messageReceivedCb; +} + +void linphone_chat_room_cbs_set_message_received (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsMessageReceivedCb cb) { + cbs->messageReceivedCb = cb; +} + +LinphoneChatRoomCbsUndecryptableMessageReceivedCb linphone_chat_room_cbs_get_undecryptable_message_received (const LinphoneChatRoomCbs *cbs) { + return cbs->undecryptableMessageReceivedCb; +} + +void linphone_chat_room_cbs_set_undecryptable_message_received (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsUndecryptableMessageReceivedCb cb) { + cbs->undecryptableMessageReceivedCb = cb; +} diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index bc3e93450..c53b3c41f 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -42,12 +42,17 @@ static void _linphone_chat_room_destructor(LinphoneChatRoom *cr); L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(ChatRoom, ChatRoom, chat_room, _linphone_chat_room_constructor, _linphone_chat_room_destructor, + LinphoneChatRoomCbs *cbs; LinphoneAddress *peerAddressCache; ) -static void _linphone_chat_room_constructor(LinphoneChatRoom *cr) {} +static void _linphone_chat_room_constructor(LinphoneChatRoom *cr) { + cr->cbs = linphone_chat_room_cbs_new(); +} static void _linphone_chat_room_destructor(LinphoneChatRoom *cr) { + linphone_chat_room_cbs_unref(cr->cbs); + cr->cbs = nullptr; if (cr->peerAddressCache) { linphone_address_unref(cr->peerAddressCache); cr->peerAddressCache = nullptr; @@ -189,6 +194,10 @@ LinphoneChatMessage * linphone_chat_room_find_message(LinphoneChatRoom *cr, cons return GET_CPP_PTR(cr)->findMessage(message_id); } +LinphoneChatRoomCbs * linphone_chat_room_get_callbacks (const LinphoneChatRoom *cr) { + return cr->cbs; +} + LinphoneParticipant * linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr) { return L_GET_C_BACK_PTR(GET_CPP_PTR(cr)->addParticipant( *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address, Address), nullptr, false), @@ -257,25 +266,27 @@ LinphoneChatRoom * linphone_chat_room_new(LinphoneCore *core, const LinphoneAddr L_SET_CPP_PTR_FROM_C_STRUCT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address, Address))); else L_SET_CPP_PTR_FROM_C_STRUCT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address, Address))); + linphone_core_notify_chat_room_instantiated(core, cr); return cr; } -LinphoneChatRoom * linphone_client_group_chat_room_new(LinphoneCore *lc, const bctbx_list_t *addresses) { - const char *factoryUri = linphone_core_get_chat_conference_factory_uri(lc); +LinphoneChatRoom * linphone_client_group_chat_room_new(LinphoneCore *core, const bctbx_list_t *addresses) { + const char *factoryUri = linphone_core_get_chat_conference_factory_uri(core); if (!factoryUri) return nullptr; LinphoneAddress *factoryAddr = linphone_address_new(factoryUri); - LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(lc, factoryAddr); + LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core, factoryAddr); linphone_address_unref(factoryAddr); std::string from; if (proxy) from = L_GET_CPP_PTR_FROM_C_STRUCT(linphone_proxy_config_get_identity_address(proxy), Address, Address)->asString(); if (from.empty()) - from = linphone_core_get_primary_contact(lc); + from = linphone_core_get_primary_contact(core); LinphonePrivate::Address me(from); std::list l = L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(addresses, Address, Address); LinphoneChatRoom *cr = _linphone_chat_room_init(); - L_SET_CPP_PTR_FROM_C_STRUCT(cr, make_shared(lc, me, l)); + L_SET_CPP_PTR_FROM_C_STRUCT(cr, make_shared(core, me, l)); + linphone_core_notify_chat_room_instantiated(core, cr); return cr; } diff --git a/src/chat/chat-room-p.h b/src/chat/chat-room-p.h index c1230eadf..d7dd25fe0 100644 --- a/src/chat/chat-room-p.h +++ b/src/chat/chat-room-p.h @@ -76,6 +76,10 @@ protected: void imdnReceived (const std::string &text); void isComposingReceived (const std::string &text); +private: + void notifyChatMessageReceived (LinphoneChatMessage *msg); + void notifyUndecryptableMessageReceived (LinphoneChatMessage *msg); + private: /* IsComposingListener */ void onIsComposingStateChanged (bool isComposing); diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 6d1f6484a..0d7d2eaa3 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -425,7 +425,7 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa msg->is_secured = TRUE; } else if (retval > 0) { /* Unable to decrypt message */ - linphone_core_notify_message_received_unable_decrypt(core, GET_BACK_PTR(q), msg); + notifyUndecryptableMessageReceived(msg); reason = linphone_error_code_to_reason(retval); linphone_chat_message_send_delivery_notification(msg, reason); /* Return LinphoneReasonNone to avoid flexisip resending us a message we can't decrypt */ @@ -472,9 +472,9 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa unreadCount = 1; else unreadCount++; - /* Mark the message as pending so that if linphone_core_chat_room_mark_as_read() is called - in the linphone_chat_room_message_received() callback, it will effectively be marked as - being read before being stored. */ + /* Mark the message as pending so that if ChatRoom::markAsRead() is called in the + * ChatRoomPrivate::chatMessageReceived() callback, it will effectively be marked as + * being read before being stored. */ pendingMessage = msg; } @@ -496,12 +496,8 @@ end: void ChatRoomPrivate::chatMessageReceived (LinphoneChatMessage *msg) { L_Q(ChatRoom); - if (msg->message) { - /* Legacy API */ - linphone_core_notify_text_message_received(core, GET_BACK_PTR(q), msg->from, msg->message); - } - linphone_core_notify_message_received(core, GET_BACK_PTR(q), msg); if (!ContentType::isImdn(msg->content_type) && !ContentType::isImIsComposing(msg->content_type)) { + notifyChatMessageReceived(msg); remoteIsComposing = false; linphone_core_notify_is_composing_received(core, GET_BACK_PTR(q)); linphone_chat_message_send_delivery_notification(msg, LinphoneReasonNone); @@ -519,6 +515,32 @@ void ChatRoomPrivate::isComposingReceived (const string &text) { // ----------------------------------------------------------------------------- +void ChatRoomPrivate::notifyChatMessageReceived (LinphoneChatMessage *msg) { + L_Q(ChatRoom); + LinphoneChatRoom *cr = GET_BACK_PTR(q); + if (msg->message) { + /* Legacy API */ + linphone_core_notify_text_message_received(core, cr, msg->from, msg->message); + } + LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); + LinphoneChatRoomCbsMessageReceivedCb cb = linphone_chat_room_cbs_get_message_received(cbs); + if (cb) + cb(cr, msg); + linphone_core_notify_message_received(core, cr, msg); +} + +void ChatRoomPrivate::notifyUndecryptableMessageReceived (LinphoneChatMessage *msg) { + L_Q(ChatRoom); + LinphoneChatRoom *cr = GET_BACK_PTR(q); + LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); + LinphoneChatRoomCbsUndecryptableMessageReceivedCb cb = linphone_chat_room_cbs_get_undecryptable_message_received(cbs); + if (cb) + cb(cr, msg); + linphone_core_notify_message_received_unable_decrypt(core, cr, msg); +} + +// ----------------------------------------------------------------------------- + void ChatRoomPrivate::onIsComposingStateChanged (bool isComposing) { this->isComposing = isComposing; sendIsComposingNotification(); From 93c17c21947fb40a352c1d21f5f59558536e3a1d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 18 Sep 2017 11:57:32 +0200 Subject: [PATCH 0080/2215] Started c-chat-message --- coreapi/chat.c | 17 ------- include/CMakeLists.txt | 1 + include/linphone/api/c-api.h | 1 + include/linphone/api/c-chat-message.h | 70 +++++++++++++++++++++++++++ include/linphone/chat.h | 24 +-------- src/CMakeLists.txt | 1 + src/c-wrapper/api/c-chat-message.cpp | 52 ++++++++++++++++++++ 7 files changed, 126 insertions(+), 40 deletions(-) create mode 100644 include/linphone/api/c-chat-message.h create mode 100644 src/c-wrapper/api/c-chat-message.cpp diff --git a/coreapi/chat.c b/coreapi/chat.c index 8e9f2b59b..1fd40d017 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -570,14 +570,6 @@ const LinphoneAddress *linphone_chat_message_get_peer_address(LinphoneChatMessag return linphone_chat_room_get_peer_address(msg->chat_room); } -void linphone_chat_message_set_user_data(LinphoneChatMessage *msg, void *ud) { - msg->message_userdata = ud; -} - -void *linphone_chat_message_get_user_data(const LinphoneChatMessage *msg) { - return msg->message_userdata; -} - const char *linphone_chat_message_get_external_body_url(const LinphoneChatMessage *msg) { return msg->external_body_url; } @@ -775,15 +767,6 @@ static void _linphone_chat_message_destroy(LinphoneChatMessage *msg) { } } -LinphoneChatMessage *linphone_chat_message_ref(LinphoneChatMessage *msg) { - belle_sip_object_ref(msg); - return msg; -} - -void linphone_chat_message_unref(LinphoneChatMessage *msg) { - belle_sip_object_unref(msg); -} - void linphone_chat_message_deactivate(LinphoneChatMessage *msg){ if (msg->file_transfer_information != NULL) { _linphone_chat_message_cancel_file_transfer(msg, FALSE); diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 54af30490..a2b7662f5 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -77,6 +77,7 @@ set(C_API_HEADER_FILES c-address.h c-api.h c-callbacks.h + c-chat-message.h c-chat-room.h c-chat-room-cbs.h c-event-log.h diff --git a/include/linphone/api/c-api.h b/include/linphone/api/c-api.h index 009498b29..6f6433104 100644 --- a/include/linphone/api/c-api.h +++ b/include/linphone/api/c-api.h @@ -20,6 +20,7 @@ #define _C_API_H_ #include "linphone/api/c-address.h" +#include "linphone/api/c-chat-message.h" #include "linphone/api/c-chat-room.h" #include "linphone/api/c-event-log.h" #include "linphone/api/c-participant.h" diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h new file mode 100644 index 000000000..bced0fb36 --- /dev/null +++ b/include/linphone/api/c-chat-message.h @@ -0,0 +1,70 @@ +/* + * c-chat-message.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + + #ifndef _C_CHAT_MESSAGE_H_ + #define _C_CHAT_MESSAGE_H_ + + #include "linphone/api/c-types.h" + + // ============================================================================= + + #ifdef __cplusplus + extern "C" { + #endif // ifdef __cplusplus + + /** + * @addtogroup chatmessage + * @{ + */ + +/** + * Acquire a reference to the chat message. + * @param[in] cr The chat message. + * @return The same chat message. +**/ +LINPHONE_PUBLIC LinphoneChatMessage *linphone_chat_message_ref(LinphoneChatMessage *msg); + +/** + * Release reference to the chat message. + * @param[in] cr The chat message. +**/ +LINPHONE_PUBLIC void linphone_chat_message_unref(LinphoneChatMessage *msg); + +/** + * Retrieve the user pointer associated with the chat message. + * @param[in] cr The chat message. + * @return The user pointer associated with the chat message. +**/ +LINPHONE_PUBLIC void *linphone_chat_message_get_user_data(const LinphoneChatMessage *msg); + +/** + * Assign a user pointer to the chat message. + * @param[in] cr The chat message. + * @param[in] ud The user pointer to associate with the chat message. +**/ +LINPHONE_PUBLIC void linphone_chat_message_set_user_data(LinphoneChatMessage *msg, void *ud); + + /** + * @} + */ + +#ifdef __cplusplus +} +#endif // ifdef __cplusplus + +#endif // ifndef _C_CHAT_MESSAGE_H_ \ No newline at end of file diff --git a/include/linphone/chat.h b/include/linphone/chat.h index e84c70bae..9444da7f6 100644 --- a/include/linphone/chat.h +++ b/include/linphone/chat.h @@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/callbacks.h" #include "linphone/types.h" #include "linphone/api/c-types.h" +#include "linphone/api/c-chat-message.h" #include "linphone/api/c-chat-room.h" #include "linphone/api/c-chat-room-cbs.h" @@ -58,19 +59,6 @@ LINPHONE_PUBLIC LinphoneChatMessageState linphone_chat_message_get_state(const L **/ LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* message); -/** - * Acquire a reference to the chat message. - * @param msg the chat message - * @return the same chat message -**/ -LINPHONE_PUBLIC LinphoneChatMessage * linphone_chat_message_ref(LinphoneChatMessage *msg); - -/** - * Release reference to the chat message. - * @param msg the chat message. -**/ -LINPHONE_PUBLIC void linphone_chat_message_unref(LinphoneChatMessage *msg); - /** * Destroys a LinphoneChatMessage. **/ @@ -250,16 +238,6 @@ LINPHONE_PUBLIC const char* linphone_chat_message_get_text(const LinphoneChatMes */ LINPHONE_PUBLIC time_t linphone_chat_message_get_time(const LinphoneChatMessage* message); -/** - * User pointer get function - */ -LINPHONE_PUBLIC void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message); - -/** - *User pointer set function - */ -LINPHONE_PUBLIC void linphone_chat_message_set_user_data(LinphoneChatMessage* message,void*); - /** * Returns the chatroom this message belongs to. **/ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c089e0040..bb16db6da 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -99,6 +99,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES address/address.cpp c-wrapper/api/c-address.cpp c-wrapper/api/c-call-params.cpp + c-wrapper/api/c-chat-message.cpp c-wrapper/api/c-chat-room.cpp c-wrapper/api/c-chat-room-cbs.cpp c-wrapper/api/c-event-log.cpp diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp new file mode 100644 index 000000000..265222519 --- /dev/null +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -0,0 +1,52 @@ +/* + * c-chat-message.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + + + #include "linphone/chat.h" + #include "linphone/wrapper_utils.h" + #include "private.h" + + #include "c-wrapper/c-tools.h" + #include "chat/chat-message.h" + #include "chat/chat-message-p.h" + + using namespace std; + + #define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, ChatMessage, ChatMessage) + #define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, ChatMessage, ChatMessage) + + /******************************************************************************* + * Reference and user data handling functions * + ******************************************************************************/ + +LinphoneChatMessage *linphone_chat_message_ref(LinphoneChatMessage *msg) { + belle_sip_object_ref(msg); + return msg; +} + +void linphone_chat_message_unref(LinphoneChatMessage *msg) { + belle_sip_object_unref(msg); +} + +void * linphone_chat_message_get_user_data(const LinphoneChatMessage *msg) { + return L_GET_USER_DATA_FROM_C_STRUCT(msg, ChatMessage, ChatMessage); +} + +void linphone_chat_message_set_user_data(LinphoneChatMessage *msg, void *ud) { + L_SET_USER_DATA_FROM_C_STRUCT(msg, ud, ChatMessage, ChatMessage); +} \ No newline at end of file From 752d89a8d70a5ce579947cab104a37984af04ca2 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 18 Sep 2017 17:12:23 +0200 Subject: [PATCH 0081/2215] feat(Enums): provide useful macros to share enums between C/C++ --- include/linphone/api/c-types.h | 9 +- include/linphone/enums/event-log-enums.h | 26 +- include/linphone/utils/enum-generator.h | 38 ++- include/linphone/utils/magic-macros.h | 291 +++++++----------- src/db/events-db.cpp | 20 +- src/event-log/call-event.cpp | 2 +- src/event-log/conference-event.cpp | 2 +- .../conference-participant-event.cpp | 8 +- src/event-log/event-log-p.h | 2 +- src/event-log/event-log.h | 5 +- src/event-log/message-event.cpp | 2 +- 11 files changed, 171 insertions(+), 234 deletions(-) diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index 79202b952..d2f707053 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -19,17 +19,12 @@ #ifndef _C_TYPES_H_ #define _C_TYPES_H_ -// Do not move this define. -// Enable C enums. -#define L_USE_C_ENUM - // TODO: Remove me in the future. #include "linphone/types.h" +#include "linphone/utils/enum-generator.h" #include "linphone/enums/event-log-enums.h" -#define L_DECLARE_C_ENUM(CLASS, ENUM, VALUES) enum Linphone ## CLASS ## ENUM { VALUES } - // ============================================================================= #ifdef __cplusplus @@ -105,7 +100,7 @@ typedef struct _LinphoneParticipant LinphoneParticipant; // C Enums. // ============================================================================= -L_DECLARE_C_ENUM(EventLog, Type, L_ENUM_VALUES_EVENT_LOG_TYPE); +L_DECLARE_C_ENUM(EventLogType, L_ENUM_VALUES_EVENT_LOG_TYPE); #ifdef __cplusplus } diff --git a/include/linphone/enums/event-log-enums.h b/include/linphone/enums/event-log-enums.h index 9a6f41e66..2eb4d4416 100644 --- a/include/linphone/enums/event-log-enums.h +++ b/include/linphone/enums/event-log-enums.h @@ -19,22 +19,18 @@ #ifndef _EVENT_LOG_ENUMS_H_ #define _EVENT_LOG_ENUMS_H_ -#include "linphone/utils/enum-generator.h" - // ============================================================================= -#define L_ENUM_VALUES_EVENT_LOG_TYPE \ - L_DECLARE_ENUM_VALUES(EventLog, Type, \ - None, \ - Message, \ - CallStart, \ - CallEnd, \ - ConferenceCreated, \ - ConferenceDestroyed, \ - ConferenceParticipantAdded, \ - ConferenceParticipantRemoved, \ - ConferenceParticipantSetAdmin, \ - ConferenceParticipantUnsetAdmin \ - ) +#define L_ENUM_VALUES_EVENT_LOG_TYPE(F) \ + F(None) \ + F(Message) \ + F(CallStart) \ + F(CallEnd) \ + F(ConferenceCreated) \ + F(ConferenceDestroyed) \ + F(ConferenceParticipantAdded) \ + F(ConferenceParticipantRemoved) \ + F(ConferenceParticipantSetAdmin) \ + F(ConferenceParticipantUnsetAdmin) #endif // ifndef _EVENT_LOG_ENUMS_H_ diff --git a/include/linphone/utils/enum-generator.h b/include/linphone/utils/enum-generator.h index 84ea6453b..030fd94b5 100644 --- a/include/linphone/utils/enum-generator.h +++ b/include/linphone/utils/enum-generator.h @@ -25,15 +25,37 @@ LINPHONE_BEGIN_NAMESPACE -#define L_ENUM_VALUE(C, VALUE) C ## VALUE +// ----------------------------------------------------------------------------- +// Low-level, do not call. +// ----------------------------------------------------------------------------- -#ifndef L_USE_C_ENUM - #define L_DECLARE_ENUM_VALUES(CLASS_NAME, ENUM_NAME, ...) \ - MM_APPLY_COMMA(L_ENUM_VALUE, ENUM_NAME, __VA_ARGS__) -#else - #define L_DECLARE_ENUM_VALUES(CLASS_NAME, ENUM_NAME, ...) \ - MM_APPLY_COMMA(L_ENUM_VALUE, Linphone ## CLASS_NAME ## ENUM_NAME, __VA_ARGS__) -#endif // ifndef L_USE_C_ENUM +// Declare one enum value. `value` is optional, it can be generated. +// It's useful to force value in the case of mask. +#define L_DECLARE_ENUM_VALUE_1_ARGS(NAME) NAME, +#define L_DECLARE_ENUM_VALUE_2_ARGS(NAME, VALUE) NAME = VALUE, + +// Call the right macro. (With or without value.) +#define L_DECLARE_ENUM_MACRO_CHOOSER(...) \ + L_GET_ARG_3(__VA_ARGS__, L_DECLARE_ENUM_VALUE_2_ARGS, L_DECLARE_ENUM_VALUE_1_ARGS) + +// Enum value declaration. +#define L_DECLARE_ENUM_VALUE(...) L_DECLARE_ENUM_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__) + +// ----------------------------------------------------------------------------- +// Public API. +// ----------------------------------------------------------------------------- + +#define L_DECLARE_ENUM(NAME, VALUES) \ + enum class NAME { \ + VALUES(L_DECLARE_ENUM_VALUE) \ + }; + +#define L_C_ENUM_PREFIX Linphone + +#define L_DECLARE_C_ENUM(NAME, VALUES) \ + enum L_CONCAT(L_C_ENUM_PREFIX, NAME) { \ + L_APPLY(L_CONCAT, L_CONCAT(L_C_ENUM_PREFIX, NAME), L_GET_HEAP(VALUES(L_DECLARE_ENUM_VALUE))) \ + }; LINPHONE_END_NAMESPACE diff --git a/include/linphone/utils/magic-macros.h b/include/linphone/utils/magic-macros.h index 5c4eb2f50..439dcdf32 100644 --- a/include/linphone/utils/magic-macros.h +++ b/include/linphone/utils/magic-macros.h @@ -21,220 +21,145 @@ #include "linphone/utils/general.h" -// ============================================================================= -// Original header. -// Source: https://github.com/facebookresearch/ELF/blob/master/elf/pybind_helper.h -// ============================================================================= - -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -// File: macros.h -// Author: Yuxin Wu - // ============================================================================= LINPHONE_BEGIN_NAMESPACE -#define MM_CONCAT__(A, B) A ## B -#define MM_CONCAT_(A, B) MM_CONCAT__(A, B) -#define MM_CONCAT(A, B) MM_CONCAT_(A, B) +// Concat in depth context. +#define L_CONCAT__(A, B) A ## B +#define L_CONCAT_(A, B) L_CONCAT__(A, B) +#define L_CONCAT(A, B) L_CONCAT_(A, B) -#define MM_INVOKE(MACRO, ARGS) MACRO ARGS -#define MM_INVOKE_B(MACRO, ARGS) MACRO ARGS +// Get argument numbers from variadic. +#define L_ARG_N( \ + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, \ + A11, A12, A13, A14, A15, A16, N, ... \ +) N -#define MM_APPLY_1(MACRONAME, C, A1) \ - MM_INVOKE_B(MACRONAME, (C, A1)) +#define L_GET_N_ARGS_HELPER(...) L_ARG_N(__VA_ARGS__) -#define MM_APPLY_2(MACRONAME, C, A1, A2) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_1(MACRONAME, C, A2) +#define L_GET_N_ARGS(...) L_GET_N_ARGS_HELPER( \ + __VA_ARGS__, \ + 16, 15, 14, 13, 12, 11, 10, \ + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 \ +) -#define MM_APPLY_3(MACRONAME, C, A1, A2, A3) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_2(MACRONAME, C, A2, A3) +// Get argument numbers - 1 from variadic. +#define L_GET_N_ARGS_SUB(X, ...) L_GET_N_ARGS(__VA_ARGS__) -#define MM_APPLY_4(MACRONAME, C, A1, A2, A3, A4) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_3(MACRONAME, C, A2, A3, A4) +// Get argument from variadic macro. +#define L_GET_ARG_1(A1, ...) A1 +#define L_GET_ARG_2(A1, A2, ...) A2 +#define L_GET_ARG_3(A1, A2, A3, ...) A3 +#define L_GET_ARG_4(A1, A2, A3, A4, ...) A4 +#define L_GET_ARG_5(A1, A2, A3, A4, A5, ...) A5 +#define L_GET_ARG_6(A1, A2, A3, A4, A5, A6, ...) A6 +#define L_GET_ARG_7(A1, A2, A3, A4, A5, A6, A7, ...) A7 +#define L_GET_ARG_8(A1, A2, A3, A4, A5, A6, A7, A8, ...) A8 +#define L_GET_ARG_9(A1, A2, A3, A4, A5, A6, A7, A8, A9, ...) A9 +#define L_GET_ARG_10(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, ...) A10 +#define L_GET_ARG_11(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, ...) A11 +#define L_GET_ARG_12(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, ...) A12 +#define L_GET_ARG_13(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, ...) A13 +#define L_GET_ARG_14(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, ...) A14 +#define L_GET_ARG_15(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, ...) A15 +#define L_GET_ARG_16(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, ...) A16 -#define MM_APPLY_5(MACRONAME, C, A1, A2, A3, A4, A5) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_4(MACRONAME, C, A2, A3, A4, A5) +// Get left part of variadic. +#define L_GET_HEAP_1(A1, ...) A1 +#define L_GET_HEAP_2(A1, A2, ...) A1, A2 +#define L_GET_HEAP_3(A1, A2, A3, ...) A1, A2, A3 +#define L_GET_HEAP_4(A1, A2, A3, A4, ...) A1, A2, A3, A4 +#define L_GET_HEAP_5(A1, A2, A3, A4, A5, ...) A1, A2, A3, A4, A5 +#define L_GET_HEAP_6(A1, A2, A3, A4, A5, A6, ...) A1, A2, A3, A4, A5, A6 +#define L_GET_HEAP_7(A1, A2, A3, A4, A5, A6, A7, ...) A1, A2, A3, A4, A5, A6, A7 +#define L_GET_HEAP_8(A1, A2, A3, A4, A5, A6, A7, A8, ...) A1, A2, A3, A4, A5, A6, A7, A8 +#define L_GET_HEAP_9(A1, A2, A3, A4, A5, A6, A7, A8, A9, ...) A1, A2, A3, A4, A5, A6, A7, A8, A9 +#define L_GET_HEAP_10(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, ...) A1, A2, A3, A4, A5, A6, A7, A8, A9, A10 +#define L_GET_HEAP_11(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, ...) A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11 +#define L_GET_HEAP_12(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, ...) A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12 +#define L_GET_HEAP_13(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, ...) A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13 +#define L_GET_HEAP_14(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, ...) A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14 +#define L_GET_HEAP_15(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, ...) A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15 +#define L_GET_HEAP_16(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, ...) A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16 -#define MM_APPLY_6(MACRONAME, C, A1, A2, A3, A4, A5, A6) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_5(MACRONAME, C, A2, A3, A4, A5, A6) +#define L_GET_HEAP(...) \ + L_CONCAT(L_GET_HEAP_, L_GET_N_ARGS_SUB(__VA_ARGS__)) (__VA_ARGS__) -#define MM_APPLY_7(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_6(MACRONAME, C, A2, A3, A4, A5, A6, A7) +// Call a macro on args. +#define L_CALL(MACRO, ARGS) MACRO ARGS +#define L_CALL_HELPER(MACRO, ARGS) MACRO ARGS -#define MM_APPLY_8(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_7(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8) +// Map each variadic args. +#define L_APPLY_1(MACRONAME, DATA, A1) \ + L_CALL_HELPER(MACRONAME, (DATA, A1)) -#define MM_APPLY_9(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_8(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9) +#define L_APPLY_2(MACRONAME, DATA, A1, A2) \ + L_CALL_HELPER(MACRONAME, (DATA, A1)), \ + L_APPLY_1(MACRONAME, DATA, A2) -#define MM_APPLY_10(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_9(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10) +#define L_APPLY_3(MACRONAME, DATA, A1, A2, A3) \ + L_CALL_HELPER(MACRONAME, (DATA, A1)), \ + L_APPLY_2(MACRONAME, DATA, A2, A3) -#define MM_APPLY_11(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_10(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) +#define L_APPLY_4(MACRONAME, DATA, A1, A2, A3, A4) \ + L_CALL_HELPER(MACRONAME, (DATA, A1)), \ + L_APPLY_3(MACRONAME, DATA, A2, A3, A4) -#define MM_APPLY_12(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_11(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) +#define L_APPLY_5(MACRONAME, DATA, A1, A2, A3, A4, A5) \ + L_CALL_HELPER(MACRONAME, (DATA, A1)), \ + L_APPLY_4(MACRONAME, DATA, A2, A3, A4, A5) -#define MM_APPLY_13(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_12(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) +#define L_APPLY_6(MACRONAME, DATA, A1, A2, A3, A4, A5, A6) \ + L_CALL_HELPER(MACRONAME, (DATA, A1)), \ + L_APPLY_5(MACRONAME, DATA, A2, A3, A4, A5, A6) -#define MM_APPLY_14(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_13(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) +#define L_APPLY_7(MACRONAME, DATA, A1, A2, A3, A4, A5, A6, A7) \ + L_CALL_HELPER(MACRONAME, (DATA, A1)), \ + L_APPLY_6(MACRONAME, DATA, A2, A3, A4, A5, A6, A7) -#define MM_APPLY_15(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_14(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) +#define L_APPLY_8(MACRONAME, DATA, A1, A2, A3, A4, A5, A6, A7, A8) \ + L_CALL_HELPER(MACRONAME, (DATA, A1)), \ + L_APPLY_7(MACRONAME, DATA, A2, A3, A4, A5, A6, A7, A8) -#define MM_APPLY_16(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_15(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) +#define L_APPLY_9(MACRONAME, DATA, A1, A2, A3, A4, A5, A6, A7, A8, A9) \ + L_CALL_HELPER(MACRONAME, (DATA, A1)), \ + L_APPLY_8(MACRONAME, DATA, A2, A3, A4, A5, A6, A7, A8, A9) -#define MM_APPLY_17(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_16(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17) +#define L_APPLY_10(MACRONAME, DATA, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) \ + L_CALL_HELPER(MACRONAME, (DATA, A1)), \ + L_APPLY_9(MACRONAME, DATA, A2, A3, A4, A5, A6, A7, A8, A9, A10) -#define MM_APPLY_18(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_17(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18) +#define L_APPLY_11(MACRONAME, DATA, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) \ + L_CALL_HELPER(MACRONAME, (DATA, A1)), \ + L_APPLY_10(MACRONAME, DATA, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) -#define MM_APPLY_19(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_18(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19) +#define L_APPLY_12(MACRONAME, DATA, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) \ + L_CALL_HELPER(MACRONAME, (DATA, A1)), \ + L_APPLY_11(MACRONAME, DATA, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) -#define MM_APPLY_20(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_19(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20) +#define L_APPLY_13(MACRONAME, DATA, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) \ + L_CALL_HELPER(MACRONAME, (DATA, A1)), \ + L_APPLY_12(MACRONAME, DATA, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) -#define MM_APPLY_21(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_20(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21) +#define L_APPLY_14(MACRONAME, DATA, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) \ + L_CALL_HELPER(MACRONAME, (DATA, A1)), \ + L_APPLY_13(MACRONAME, DATA, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) -#define MM_APPLY_22(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22) \ - MM_INVOKE_B(MACRONAME, (C, A1)) \ - MM_APPLY_21(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22) +#define L_APPLY_15(MACRONAME, DATA, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) \ + L_CALL_HELPER(MACRONAME, (DATA, A1)), \ + L_APPLY_14(MACRONAME, DATA, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) -#define MM_NARG(...) \ - MM_NARG_(__VA_ARGS__, MM_RSEQ_N()) +#define L_APPLY_16(MACRONAME, DATA, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) \ + L_CALL_HELPER(MACRONAME, (DATA, A1)), \ + L_APPLY_15(MACRONAME, DATA, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) -#define MM_NARG_(...) \ - MM_ARG_N(__VA_ARGS__) - -#define MM_ARG_N( \ - _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ - _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ - _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ - _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ - _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \ - _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \ - _61, _62, _63, N, ...) N - -#define MM_RSEQ_N() \ - 63, 62, 61, 60, \ - 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \ - 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \ - 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \ - 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \ - 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \ - 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 - -#define MM_APPLY(MACRONAME, C, ...) \ - MM_INVOKE( \ - MM_CONCAT(MM_APPLY_, MM_NARG(__VA_ARGS__)), \ - (MACRONAME, C, __VA_ARGS__) \ +#define L_APPLY(MACRONAME, DATA, ...) \ + L_CALL( \ + L_CONCAT(L_APPLY_, L_GET_N_ARGS(__VA_ARGS__)), \ + (MACRONAME, DATA, __VA_ARGS__) \ ) -#define MM_APPLY_COMMA(MACRONAME, C, ...) \ - MM_INVOKE( \ - MM_CONCAT(MM_APPLY_COMMA_, MM_NARG(__VA_ARGS__)), \ - (MACRONAME, C, __VA_ARGS__) \ - ) - -#define MM_APPLY_COMMA_1(MACRONAME, C, A1) \ - MM_INVOKE_B(MACRONAME, (C, A1)) - -#define MM_APPLY_COMMA_2(MACRONAME, C, A1, A2) \ - MM_INVOKE_B(MACRONAME, (C, A1)), \ - MM_APPLY_COMMA_1(MACRONAME, C, A2) - -#define MM_APPLY_COMMA_3(MACRONAME, C, A1, A2, A3) \ - MM_INVOKE_B(MACRONAME, (C, A1)), \ - MM_APPLY_COMMA_2(MACRONAME, C, A2, A3) - -#define MM_APPLY_COMMA_4(MACRONAME, C, A1, A2, A3, A4) \ - MM_INVOKE_B(MACRONAME, (C, A1)), \ - MM_APPLY_COMMA_3(MACRONAME, C, A2, A3, A4) - -#define MM_APPLY_COMMA_5(MACRONAME, C, A1, A2, A3, A4, A5) \ - MM_INVOKE_B(MACRONAME, (C, A1)), \ - MM_APPLY_COMMA_4(MACRONAME, C, A2, A3, A4, A5) - -#define MM_APPLY_COMMA_6(MACRONAME, C, A1, A2, A3, A4, A5, A6) \ - MM_INVOKE_B(MACRONAME, (C, A1)), \ - MM_APPLY_COMMA_5(MACRONAME, C, A2, A3, A4, A5, A6) - -#define MM_APPLY_COMMA_7(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7) \ - MM_INVOKE_B(MACRONAME, (C, A1)), \ - MM_APPLY_COMMA_6(MACRONAME, C, A2, A3, A4, A5, A6, A7) - -#define MM_APPLY_COMMA_8(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8) \ - MM_INVOKE_B(MACRONAME, (C, A1)), \ - MM_APPLY_COMMA_7(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8) - -#define MM_APPLY_COMMA_9(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9) \ - MM_INVOKE_B(MACRONAME, (C, A1)), \ - MM_APPLY_COMMA_8(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9) - -#define MM_APPLY_COMMA_10(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) \ - MM_INVOKE_B(MACRONAME, (C, A1)), \ - MM_APPLY_COMMA_9(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10) - -#define MM_APPLY_COMMA_11(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) \ - MM_INVOKE_B(MACRONAME, (C, A1)), \ - MM_APPLY_COMMA_10(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) - -#define MM_APPLY_COMMA_12(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) \ - MM_INVOKE_B(MACRONAME, (C, A1)), \ - MM_APPLY_COMMA_11(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) - -#define MM_APPLY_COMMA_13(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) \ - MM_INVOKE_B(MACRONAME, (C, A1)), \ - MM_APPLY_COMMA_12(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) - -#define MM_APPLY_COMMA_14(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) \ - MM_INVOKE_B(MACRONAME, (C, A1)), \ - MM_APPLY_COMMA_13(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) - -#define MM_APPLY_COMMA_15(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) \ - MM_INVOKE_B(MACRONAME, (C, A1)), \ - MM_APPLY_COMMA_14(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) - -#define MM_APPLY_COMMA_16(MACRONAME, C, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) \ - MM_INVOKE_B(MACRONAME, (C, A1)), \ - MM_APPLY_COMMA_15(MACRONAME, C, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) - LINPHONE_END_NAMESPACE #endif // ifndef _MAGIC_MACROS_H_ diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 7fdc13037..6cd193f5b 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -281,17 +281,17 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} // TODO. switch (eventLog.getType()) { - case EventLog::TypeNone: + case EventLog::Type::None: return false; - case EventLog::TypeMessage: - case EventLog::TypeCallStart: - case EventLog::TypeCallEnd: - case EventLog::TypeConferenceCreated: - case EventLog::TypeConferenceDestroyed: - case EventLog::TypeConferenceParticipantAdded: - case EventLog::TypeConferenceParticipantRemoved: - case EventLog::TypeConferenceParticipantSetAdmin: - case EventLog::TypeConferenceParticipantUnsetAdmin: + case EventLog::Type::Message: + case EventLog::Type::CallStart: + case EventLog::Type::CallEnd: + case EventLog::Type::ConferenceCreated: + case EventLog::Type::ConferenceDestroyed: + case EventLog::Type::ConferenceParticipantAdded: + case EventLog::Type::ConferenceParticipantRemoved: + case EventLog::Type::ConferenceParticipantSetAdmin: + case EventLog::Type::ConferenceParticipantUnsetAdmin: break; } diff --git a/src/event-log/call-event.cpp b/src/event-log/call-event.cpp index 1078606ec..65556f9c5 100644 --- a/src/event-log/call-event.cpp +++ b/src/event-log/call-event.cpp @@ -36,7 +36,7 @@ public: CallEvent::CallEvent (Type type, const shared_ptr &call) : EventLog(*new CallEventPrivate, type) { L_D(CallEvent); L_ASSERT(call); - L_ASSERT(type == TypeCallStart || type == TypeCallEnd); + L_ASSERT(type == Type::CallStart || type == Type::CallEnd); d->call = call; } diff --git a/src/event-log/conference-event.cpp b/src/event-log/conference-event.cpp index 16486a929..43c040b25 100644 --- a/src/event-log/conference-event.cpp +++ b/src/event-log/conference-event.cpp @@ -30,7 +30,7 @@ LINPHONE_BEGIN_NAMESPACE ConferenceEvent::ConferenceEvent (Type type, const shared_ptr &address) : EventLog(*new ConferenceEventPrivate, type) { L_D(ConferenceEvent); - L_ASSERT(type == TypeConferenceCreated || type == TypeConferenceDestroyed); + L_ASSERT(type == Type::ConferenceCreated || type == Type::ConferenceDestroyed); L_ASSERT(address); d->address = make_shared
(*address); } diff --git a/src/event-log/conference-participant-event.cpp b/src/event-log/conference-participant-event.cpp index d1d647f75..7db503cad 100644 --- a/src/event-log/conference-participant-event.cpp +++ b/src/event-log/conference-participant-event.cpp @@ -41,10 +41,10 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( ) : ConferenceEvent(*new ConferenceParticipantEventPrivate, type, conferenceAddress) { L_D(ConferenceParticipantEvent); L_ASSERT( - type == TypeConferenceParticipantAdded || - type == TypeConferenceParticipantRemoved || - type == TypeConferenceParticipantSetAdmin || - type == TypeConferenceParticipantUnsetAdmin + type == Type::ConferenceParticipantAdded || + type == Type::ConferenceParticipantRemoved || + type == Type::ConferenceParticipantSetAdmin || + type == Type::ConferenceParticipantUnsetAdmin ); L_ASSERT(participantAddress); d->participantAddress = make_shared
(*participantAddress); diff --git a/src/event-log/event-log-p.h b/src/event-log/event-log-p.h index 6a71e025f..1c50b09a5 100644 --- a/src/event-log/event-log-p.h +++ b/src/event-log/event-log-p.h @@ -28,7 +28,7 @@ LINPHONE_BEGIN_NAMESPACE class EventLogPrivate : public ClonableObjectPrivate { private: - EventLog::Type type = EventLog::TypeNone; + EventLog::Type type = EventLog::Type::None; L_DECLARE_PUBLIC(EventLog); }; diff --git a/src/event-log/event-log.h b/src/event-log/event-log.h index 1ccd6c9a0..0527a140a 100644 --- a/src/event-log/event-log.h +++ b/src/event-log/event-log.h @@ -20,6 +20,7 @@ #define _EVENT_LOG_H_ #include "linphone/enums/event-log-enums.h" +#include "linphone/utils/enum-generator.h" #include "object/clonable-object.h" @@ -31,9 +32,7 @@ class EventLogPrivate; class LINPHONE_PUBLIC EventLog : public ClonableObject { public: - enum Type { - L_ENUM_VALUES_EVENT_LOG_TYPE - }; + L_DECLARE_ENUM(Type, L_ENUM_VALUES_EVENT_LOG_TYPE); EventLog (); EventLog (const EventLog &src); diff --git a/src/event-log/message-event.cpp b/src/event-log/message-event.cpp index cda82eb68..319ab3b7a 100644 --- a/src/event-log/message-event.cpp +++ b/src/event-log/message-event.cpp @@ -34,7 +34,7 @@ public: // ----------------------------------------------------------------------------- MessageEvent::MessageEvent (const shared_ptr &message) : - EventLog(*new MessageEventPrivate, EventLog::TypeMessage) { + EventLog(*new MessageEventPrivate, EventLog::Type::Message) { L_D(MessageEvent); L_ASSERT(message); d->message = message; From 013d334226c110ee3c3d493c27730a2b83d48cc1 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 19 Sep 2017 10:25:32 +0200 Subject: [PATCH 0082/2215] fix(c-types): sort --- include/linphone/api/c-types.h | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index d2f707053..72d74fb9d 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -69,7 +69,10 @@ typedef unsigned char bool_t; typedef struct _LinphoneAddress LinphoneAddress; typedef struct _LinphoneCall LinphoneCall; -typedef struct _LinphoneCallEvent LinphoneCallEvent; + +// ----------------------------------------------------------------------------- +// Chatroom. +// ----------------------------------------------------------------------------- /** * A chat room is the place where text messages are exchanged. @@ -84,18 +87,24 @@ typedef struct _LinphoneChatRoom LinphoneChatRoom; */ typedef struct _LinphoneChatRoomCbs LinphoneChatRoomCbs; +typedef struct _LinphoneMessage LinphoneMessage; + +/** +* The LinphoneParticipant object represents a participant of a conference. +* @ingroup misc +**/ +typedef struct _LinphoneParticipant LinphoneParticipant; + +// ----------------------------------------------------------------------------- +// EventLog. +// ----------------------------------------------------------------------------- + +typedef struct _LinphoneCallEvent LinphoneCallEvent; typedef struct _LinphoneConferenceEvent LinphoneConferenceEvent; typedef struct _LinphoneConferenceParticipantEvent LinphoneConferenceParticipantEvent; typedef struct _LinphoneEventLog LinphoneEventLog; -typedef struct _LinphoneMessage LinphoneMessage; typedef struct _LinphoneMessageEvent LinphoneMessageEvent; -/** - * The LinphoneParticipant object represents a participant of a conference. - * @ingroup misc -**/ -typedef struct _LinphoneParticipant LinphoneParticipant; - // ============================================================================= // C Enums. // ============================================================================= From d460e32a0f0e977744e66ecbf2f4b8722ef51352 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 19 Sep 2017 10:40:08 +0200 Subject: [PATCH 0083/2215] feat(Core): use `for (var : list)` syntax when possible --- src/chat/chat-room.cpp | 63 +++++++++++++-------------- src/chat/real-time-text-chat-room.cpp | 11 +++-- 2 files changed, 35 insertions(+), 39 deletions(-) diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 0d7d2eaa3..50550a0e7 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -41,9 +41,8 @@ ChatRoomPrivate::ChatRoomPrivate (LinphoneCore *core) : core(core), isComposingHandler(core, this) {} ChatRoomPrivate::~ChatRoomPrivate () { - for (auto it = transientMessages.begin(); it != transientMessages.end(); it++) { - linphone_chat_message_release(*it); - } + for (auto &message : transientMessages) + linphone_chat_message_release(message); if (pendingMessage) linphone_chat_message_destroy(pendingMessage); } @@ -98,12 +97,12 @@ void ChatRoomPrivate::removeTransientMessage (LinphoneChatMessage *msg) { void ChatRoomPrivate::release () { L_Q(ChatRoom); isComposingHandler.stopTimers(); - for (auto it = weakMessages.begin(); it != weakMessages.end(); it++) { - linphone_chat_message_deactivate(*it); - } - for (auto it = transientMessages.begin(); it != transientMessages.end(); it++) { - linphone_chat_message_deactivate(*it); - } + + for (auto &message : weakMessages) + linphone_chat_message_deactivate(message); + for (auto &message : transientMessages) + linphone_chat_message_deactivate(message); + core = nullptr; linphone_chat_room_unref(GET_BACK_PTR(q)); } @@ -318,17 +317,17 @@ void ChatRoomPrivate::onWeakMessageDestroyed (LinphoneChatMessage *messageBeingD } LinphoneChatMessage *ChatRoomPrivate::getTransientMessage (unsigned int storageId) const { - for (auto it = transientMessages.begin(); it != transientMessages.end(); it++) { - if (linphone_chat_message_get_storage_id(*it) == storageId) - return linphone_chat_message_ref(*it); + for (auto &message : transientMessages) { + if (linphone_chat_message_get_storage_id(message) == storageId) + return linphone_chat_message_ref(message); } return nullptr; } LinphoneChatMessage *ChatRoomPrivate::getWeakMessage (unsigned int storageId) const { - for (auto it = weakMessages.begin(); it != weakMessages.end(); it++) { - if (linphone_chat_message_get_storage_id(*it) == storageId) - return linphone_chat_message_ref(*it); + for (auto &message : weakMessages) { + if (linphone_chat_message_get_storage_id(message) == storageId) + return linphone_chat_message_ref(message); } return nullptr; } @@ -637,8 +636,8 @@ LinphoneChatMessage *ChatRoom::findMessage (const string &messageId) { if (!l.empty()) { cm = l.front(); linphone_chat_message_ref(cm); - for (auto it = l.begin(); it != l.end(); it++) - linphone_chat_message_unref(*it); + for (auto &message : l) + linphone_chat_message_unref(message); } return cm; } @@ -647,17 +646,16 @@ LinphoneChatMessage * ChatRoom::findMessageWithDirection (const string &messageI L_D(ChatRoom); LinphoneChatMessage *ret = nullptr; list l = d->findMessages(messageId); - for (auto it = l.begin(); it != l.end(); it++) { - LinphoneChatMessage *cm = *it; - if (cm->dir == direction) { - linphone_chat_message_ref(cm); - ret = cm; + for (auto &message : l) { + if (message->dir == direction) { + linphone_chat_message_ref(message); + ret = message; break; } } if (!l.empty()) { - for (auto it = l.begin(); it != l.end(); it++) - linphone_chat_message_unref(*it); + for (auto &message : l) + linphone_chat_message_unref(message); } return ret; } @@ -712,13 +710,12 @@ list ChatRoom::getHistoryRange (int startm, int endm) { if (!d->messages.empty()) { /* Fill local addr with core identity instead of per message */ LinphoneAddress *localAddr = linphone_address_new(linphone_core_get_identity(d->core)); - for (auto it = d->messages.begin(); it != d->messages.end(); it++) { - LinphoneChatMessage *msg = *it; - if (msg->dir == LinphoneChatMessageOutgoing) { - if (msg->from != NULL) linphone_address_unref(msg->from); - msg->from = linphone_address_ref(localAddr); + for (auto &message : d->messages) { + if (message->dir == LinphoneChatMessageOutgoing) { + if (message->from != NULL) linphone_address_unref(message->from); + message->from = linphone_address_ref(localAddr); } else { - msg->to = linphone_address_ref(localAddr); + message->to = linphone_address_ref(localAddr); } } linphone_address_unref(localAddr); @@ -751,9 +748,9 @@ void ChatRoom::markAsRead () { char *buf = sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q AND direction = %i AND status != %i", peer.c_str(), LinphoneChatMessageIncoming, LinphoneChatMessageStateDisplayed); d->sqlRequestMessage(d->core->db, buf); sqlite3_free(buf); - for (auto it = d->messages.begin(); it != d->messages.end(); it++) { - linphone_chat_message_send_display_notification(*it); - linphone_chat_message_unref(*it); + for (auto &message : d->messages) { + linphone_chat_message_send_display_notification(message); + linphone_chat_message_unref(message); } d->messages.clear(); buf = sqlite3_mprintf("UPDATE history SET status=%i WHERE remoteContact=%Q AND direction=%i;", LinphoneChatMessageStateDisplayed, peer.c_str(), LinphoneChatMessageIncoming); diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 0d19ca637..359912dae 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -40,8 +40,8 @@ RealTimeTextChatRoomPrivate::RealTimeTextChatRoomPrivate (LinphoneCore *core, co RealTimeTextChatRoomPrivate::~RealTimeTextChatRoomPrivate () { if (!receivedRttCharacters.empty()) { - for (auto it = receivedRttCharacters.begin(); it != receivedRttCharacters.end(); it++) - bctbx_free(*it); + for (auto &rttChars : receivedRttCharacters) + bctbx_free(rttChars); } if (pendingMessage) linphone_chat_message_destroy(pendingMessage); @@ -92,8 +92,8 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp chatMessageReceived(pendingMessage); linphone_chat_message_unref(pendingMessage); pendingMessage = nullptr; - for (auto it = receivedRttCharacters.begin(); it != receivedRttCharacters.end(); it++) - ms_free(*it); + for (auto &rttChars : receivedRttCharacters) + ms_free(rttChars); receivedRttCharacters.clear(); } else { char *value = Utils::utf8ToChar(character); @@ -124,8 +124,7 @@ void RealTimeTextChatRoom::sendMessage (LinphoneChatMessage *msg) { uint32_t RealTimeTextChatRoom::getChar () const { L_D(const ChatRoom); if (!d->receivedRttCharacters.empty()) { - for (auto it = d->receivedRttCharacters.begin(); it != d->receivedRttCharacters.end(); it++) { - LinphoneChatMessageCharacter *cmc = *it; + for (auto &cmc : d->receivedRttCharacters) { if (!cmc->has_been_read) { cmc->has_been_read = TRUE; return cmc->value; From e78064859a306fcd024cf7bb875cbab223e37a81 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 19 Sep 2017 10:53:12 +0200 Subject: [PATCH 0084/2215] feat(Core): use `for (var : list)` syntax when possible (coreapi) --- coreapi/TunnelManager.cc | 27 ++++++++++++-------------- coreapi/conference.cc | 38 ++++++++++++++++++------------------- coreapi/vcard.cc | 41 ++++++++++++++-------------------------- 3 files changed, 45 insertions(+), 61 deletions(-) diff --git a/coreapi/TunnelManager.cc b/coreapi/TunnelManager.cc index dd55a45d4..8a51c392c 100644 --- a/coreapi/TunnelManager.cc +++ b/coreapi/TunnelManager.cc @@ -45,7 +45,7 @@ void TunnelManager::addServer(const char *ip, int port) { ms_warning("TunnelManager is configured in dual mode, use addServerPair instead"); return; } - + mServerAddrs.push_back(ServerAddr(ip,port)); if (mTunnelClient && !mUseDualClient) { static_cast(mTunnelClient)->addServer(ip,port); @@ -70,7 +70,7 @@ void TunnelManager::addServerPair(const char *ip1, int port1, const char *ip2, i ms_warning("TunnelManager is configured in single mode, use addServer instead"); return; } - + mDualServerAddrs.push_back(DualServerAddr(ip1, port1, ip2, port2)); if (mTunnelClient && mUseDualClient) { static_cast(mTunnelClient)->addServerPair(ip1, port1, ip2, port2); @@ -84,11 +84,8 @@ void TunnelManager::cleanServers() { sal_end_background_task(mLongRunningTaskId); mLongRunningTaskId = 0; } - UdpMirrorClientList::iterator it; - for (it = mUdpMirrorClients.begin(); it != mUdpMirrorClients.end();) { - UdpMirrorClient& s=*it++; - s.stop(); - } + for (auto &udpMirrorClient : mUdpMirrorClients) + udpMirrorClient.stop(); mUdpMirrorClients.clear(); mCurrentUdpMirrorClient = mUdpMirrorClients.end(); if (mTunnelClient) mTunnelClient->cleanServers(); @@ -141,7 +138,7 @@ RtpTransport *TunnelManager::createRtpTransport(int port){ dualSocket->recvSocket = ((DualTunnelClient *)mTunnelClient)->createSocket(TunnelRecvOnly, port); dualSocket->recvSocket->setUserPointer(this); } - + RtpTransport *t = ms_new0(RtpTransport,1); t->t_getsocket=NULL; t->t_recvfrom=customRecvfrom; @@ -161,7 +158,7 @@ void TunnelManager::startClient() { } else { mTunnelClient = TunnelClient::create(TRUE); } - + sal_set_tunnel(mCore->sal, mTunnelClient); if (!mUseDualClient) { static_cast(mTunnelClient)->setCallback(tunnelCallback,this); @@ -169,7 +166,7 @@ void TunnelManager::startClient() { static_cast(mTunnelClient)->setCallback(tunnelCallback2,this); } } - + if (mVerifyServerCertificate) { const char *rootCertificatePath = linphone_core_get_root_ca(mCore); if (rootCertificatePath != NULL) { @@ -193,7 +190,7 @@ void TunnelManager::startClient() { static_cast(mTunnelClient)->addServer(addr.mAddr.c_str(), addr.mPort); } } - + mTunnelClient->setHttpProxy(mHttpProxyHost.c_str(), mHttpProxyPort, mHttpUserName.c_str(), mHttpPasswd.c_str()); if (!mTunnelClient->isStarted()) { ms_message("Starting tunnel client"); @@ -380,7 +377,7 @@ void TunnelManager::setMode(LinphoneTunnelMode mode) { linphone_tunnel_mode_to_string(mode)); mMode = mode; applyMode(); - + } void TunnelManager::stopLongRunningTask() { @@ -393,7 +390,7 @@ void TunnelManager::stopLongRunningTask() { void TunnelManager::tunnelCallback(bool connected, void *user_pointer){ TunnelManager *zis = static_cast(user_pointer); Event ev; - + ev.mType=TunnelEvent; ev.mData.mConnected=connected; zis->postEvent(ev); @@ -402,7 +399,7 @@ void TunnelManager::tunnelCallback(bool connected, void *user_pointer){ void TunnelManager::tunnelCallback2(TunnelDirection direction, bool connected, void *user_pointer){ TunnelManager *zis = static_cast(user_pointer); Event ev; - + ev.mType=TunnelEvent; ev.mData.mConnected=connected; zis->postEvent(ev); @@ -515,7 +512,7 @@ void TunnelManager::sUdpMirrorClientCallback(bool isUdpAvailable, void* data) { void TunnelManager::networkReachableCb(LinphoneCore *lc, bool_t reachable) { TunnelManager *tunnel = bcTunnel(linphone_core_get_tunnel(lc)); - + if (reachable) { linphone_core_get_local_ip_for(AF_INET, NULL,tunnel->mLocalAddr); if (tunnel->getMode() == LinphoneTunnelModeAuto){ diff --git a/coreapi/conference.cc b/coreapi/conference.cc index 0f881ee2e..ad291c4c7 100644 --- a/coreapi/conference.cc +++ b/coreapi/conference.cc @@ -32,11 +32,13 @@ #include #include +using namespace std; + namespace Linphone { template -inline std::list<_type> toStd(const bctbx_list_t *l){ - std::list<_type> ret; +inline list<_type> toStd(const bctbx_list_t *l){ + list<_type> ret; for(; l != NULL; l = l->next){ ret.push_back(static_cast<_type>(l->data)); } @@ -108,7 +110,7 @@ public: const Params &getCurrentParams() const {return m_currentParams;} - virtual int inviteAddresses(const std::list &addresses, const LinphoneCallParams *params) = 0; + virtual int inviteAddresses(const list &addresses, const LinphoneCallParams *params) = 0; virtual int addParticipant(LinphoneCall *call) = 0; virtual int removeParticipant(LinphoneCall *call) = 0; virtual int removeParticipant(const LinphoneAddress *uri) = 0; @@ -124,7 +126,7 @@ public: float getInputVolume() const; virtual int getSize() const {return (int)m_participants.size() + (isIn()?1:0);} - const std::list &getParticipants() const {return m_participants;} + const list &getParticipants() const {return m_participants;} virtual int startRecording(const char *path) = 0; virtual int stopRecording() = 0; @@ -152,11 +154,11 @@ protected: Participant *findParticipant(const LinphoneAddress *uri) const; protected: - std::string m_conferenceID; + string m_conferenceID; LinphoneCore *m_core; AudioStream *m_localParticipantStream; bool m_isMuted; - std::list m_participants; + list m_participants; Params m_currentParams; LinphoneConferenceState m_state; LinphoneConference *m_conference; @@ -167,7 +169,7 @@ public: LocalConference(LinphoneCore *core, LinphoneConference *conf, const Params *params = NULL); virtual ~LocalConference(); - virtual int inviteAddresses(const std::list &addresses, const LinphoneCallParams *params); + virtual int inviteAddresses(const list &addresses, const LinphoneCallParams *params); virtual int addParticipant(LinphoneCall *call); virtual int removeParticipant(LinphoneCall *call); virtual int removeParticipant(const LinphoneAddress *uri); @@ -205,7 +207,7 @@ public: RemoteConference(LinphoneCore *core, LinphoneConference *conf, const Params *params = NULL); virtual ~RemoteConference(); - virtual int inviteAddresses(const std::list &addresses, const LinphoneCallParams *params); + virtual int inviteAddresses(const list &addresses, const LinphoneCallParams *params); virtual int addParticipant(LinphoneCall *call); virtual int removeParticipant(LinphoneCall *call) {return -1;} virtual int removeParticipant(const LinphoneAddress *uri); @@ -234,8 +236,8 @@ private: char *m_focusContact; LinphoneCall *m_focusCall; LinphoneCoreCbs *m_coreCbs; - std::list m_pendingCalls; - std::list m_transferingCalls; + list m_pendingCalls; + list m_transferingCalls; }; }; @@ -408,20 +410,18 @@ void LocalConference::addLocalEndpoint() { ms_audio_conference_add_member(m_conf,m_localEndpoint); } -int LocalConference::inviteAddresses(const std::list &addresses, const LinphoneCallParams *params){ - - for (std::list::const_iterator it = addresses.begin(); it != addresses.end(); ++it){ - const LinphoneAddress *addr = *it; - LinphoneCall * call = linphone_core_get_call_by_remote_address2(m_core, addr); - if (!call){ +int LocalConference::inviteAddresses (const list &addresses, const LinphoneCallParams *params) { + for (const auto &address : addresses) { + LinphoneCall * call = linphone_core_get_call_by_remote_address2(m_core, address); + if (!call) { /*start a new call by indicating that it has to be put into the conference directlly*/ LinphoneCallParams * new_params = params ? linphone_call_params_copy(params) : linphone_core_create_call_params(m_core, NULL); LinphoneCall *call; /*toggle this flag so the call is immediately added to the conference upon acceptance*/ linphone_call_params_set_in_conference(new_params, TRUE); linphone_call_params_enable_video(new_params, FALSE); /*turn off video as it is not supported for conferencing at this time*/ - call = linphone_core_invite_address_with_params(m_core, addr, new_params); - if (!call){ + call = linphone_core_invite_address_with_params(m_core, address, new_params); + if (!call) { ms_error("LocalConference::inviteAddresses(): could not invite participant"); } linphone_call_params_unref(new_params); @@ -712,7 +712,7 @@ RemoteConference::~RemoteConference() { linphone_core_cbs_unref(m_coreCbs); } -int RemoteConference::inviteAddresses(const std::list &addresses, const LinphoneCallParams *params){ +int RemoteConference::inviteAddresses(const list &addresses, const LinphoneCallParams *params){ ms_error("RemoteConference::inviteAddresses() not implemented"); return -1; } diff --git a/coreapi/vcard.cc b/coreapi/vcard.cc index c1925e60e..bd0d1fd1b 100644 --- a/coreapi/vcard.cc +++ b/coreapi/vcard.cc @@ -139,11 +139,8 @@ bctbx_list_t* linphone_vcard_context_get_vcard_list_from_file(LinphoneVcardConte } shared_ptr belCards = context->parser->parseFile(filename); if (belCards) { - for (auto it = belCards->getCards().begin(); it != belCards->getCards().end(); ++it) { - shared_ptr belCard = (*it); - LinphoneVcard *vCard = linphone_vcard_new_from_belcard(belCard); - result = bctbx_list_append(result, vCard); - } + for (auto &belCard : belCards->getCards()) + result = bctbx_list_append(result, linphone_vcard_new_from_belcard(belCard)); } } return result; @@ -157,11 +154,8 @@ bctbx_list_t* linphone_vcard_context_get_vcard_list_from_buffer(LinphoneVcardCon } shared_ptr belCards = context->parser->parse(buffer); if (belCards) { - for (auto it = belCards->getCards().begin(); it != belCards->getCards().end(); ++it) { - shared_ptr belCard = (*it); - LinphoneVcard *vCard = linphone_vcard_new_from_belcard(belCard); - result = bctbx_list_append(result, vCard); - } + for (auto &belCard : belCards->getCards()) + result = bctbx_list_append(result, linphone_vcard_new_from_belcard(belCard)); } } return result; @@ -274,17 +268,13 @@ void linphone_vcard_add_sip_address(LinphoneVcard *vCard, const char *sip_addres void linphone_vcard_remove_sip_address(LinphoneVcard *vCard, const char *sip_address) { if (!vCard) return; - shared_ptr impp; - for (auto it = vCard->belCard->getImpp().begin(); it != vCard->belCard->getImpp().end(); ++it) { - const char *value = (*it)->getValue().c_str(); + for (auto &impp : vCard->belCard->getImpp()) { + const char *value = impp->getValue().c_str(); if (strcmp(value, sip_address) == 0) { - impp = *it; + vCard->belCard->removeImpp(impp); break; } } - if (impp) { - vCard->belCard->removeImpp(impp); - } } void linphone_vcard_edit_main_sip_address(LinphoneVcard *vCard, const char *sip_address) { @@ -303,8 +293,8 @@ void linphone_vcard_edit_main_sip_address(LinphoneVcard *vCard, const char *sip_ const bctbx_list_t* linphone_vcard_get_sip_addresses(LinphoneVcard *vCard) { if (!vCard) return NULL; if (!vCard->sip_addresses_cache) { - for (auto it = vCard->belCard->getImpp().begin(); it != vCard->belCard->getImpp().end(); ++it) { - LinphoneAddress* addr = linphone_address_new((*it)->getValue().c_str()); + for (auto &impp : vCard->belCard->getImpp()) { + LinphoneAddress* addr = linphone_address_new(impp->getValue().c_str()); if (addr) { vCard->sip_addresses_cache = bctbx_list_append(vCard->sip_addresses_cache, addr); } @@ -325,24 +315,21 @@ void linphone_vcard_remove_phone_number(LinphoneVcard *vCard, const char *phone) if (!vCard) return; shared_ptr tel; - for (auto it = vCard->belCard->getPhoneNumbers().begin(); it != vCard->belCard->getPhoneNumbers().end(); ++it) { - const char *value = (*it)->getValue().c_str(); + for (auto &phoneNumber : vCard->belCard->getPhoneNumbers()) { + const char *value = phoneNumber->getValue().c_str(); if (strcmp(value, phone) == 0) { - tel = *it; + vCard->belCard->removePhoneNumber(phoneNumber); break; } } - if (tel) { - vCard->belCard->removePhoneNumber(tel); - } } bctbx_list_t* linphone_vcard_get_phone_numbers(const LinphoneVcard *vCard) { bctbx_list_t *result = NULL; if (!vCard) return NULL; - for (auto it = vCard->belCard->getPhoneNumbers().begin(); it != vCard->belCard->getPhoneNumbers().end(); ++it) { - const char *value = (*it)->getValue().c_str(); + for (auto &phoneNumber : vCard->belCard->getPhoneNumbers()) { + const char *value = phoneNumber->getValue().c_str(); result = bctbx_list_append(result, (char *)value); } return result; From 5a5e12dfae3f2d894e438797b6905b1a28595c8c Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 19 Sep 2017 10:58:59 +0200 Subject: [PATCH 0085/2215] feat(c-tools): add const versions of `getCppPtr` --- src/c-wrapper/c-tools.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index d97057a3a..750c57919 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -133,6 +133,16 @@ public: return cppPtr; } + template + static const T *getCppPtr (const std::shared_ptr &cppPtr) { + return cppPtr.get(); + } + + template + static const T *getCppPtr (const T *cppPtr) { + return cppPtr; + } + template static inline CType * getCBackPtr (const std::shared_ptr &object, CType *(*cTypeAllocator)()) { Variant v = object->getProperty("LinphonePrivate::Wrapper::cBackPtr"); From ad7cb274c844ca88ebae4284edf49442e7731585 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 19 Sep 2017 11:11:11 +0200 Subject: [PATCH 0086/2215] fix(chat/conference): use const shared_ptr reference in removeParticipant(s) --- src/c-wrapper/c-tools.h | 16 ++++++++-------- src/chat/basic-chat-room.cpp | 4 ++-- src/chat/basic-chat-room.h | 5 ++--- src/chat/client-group-chat-room.cpp | 4 ++-- src/chat/client-group-chat-room.h | 5 ++--- src/chat/real-time-text-chat-room.cpp | 4 ++-- src/chat/real-time-text-chat-room.h | 5 ++--- src/conference/conference-interface.h | 4 ++-- src/conference/conference.cpp | 4 ++-- src/conference/conference.h | 4 ++-- src/conference/local-conference.cpp | 4 ++-- src/conference/local-conference.h | 4 ++-- 12 files changed, 30 insertions(+), 33 deletions(-) diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index 750c57919..1197e201a 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -144,7 +144,7 @@ public: } template - static inline CType * getCBackPtr (const std::shared_ptr &object, CType *(*cTypeAllocator)()) { + static inline CType *getCBackPtr (const std::shared_ptr &object, CType *(*cTypeAllocator)()) { Variant v = object->getProperty("LinphonePrivate::Wrapper::cBackPtr"); void *value = v.getValue(); if (!value) { @@ -155,7 +155,7 @@ public: } template - static inline CType * getCBackPtr (const CppType *object, CType *(*cTypeAllocator)()) { + static inline CType *getCBackPtr (const CppType *object, CType *(*cTypeAllocator)()) { Variant v = object->getProperty("LinphonePrivate::Wrapper::cBackPtr"); void *value = v.getValue(); if (!value) { @@ -168,19 +168,19 @@ public: // --------------------------------------------------------------------------- template - static void * getUserData (const std::shared_ptr &cppPtr) { + static void *getUserData (const std::shared_ptr &cppPtr) { Variant v = cppPtr->getProperty("LinphonePrivate::Wrapper::userData"); return v.getValue(); } template - static void * getUserData (T *cppPtr) { + static void *getUserData (T *cppPtr) { Variant v = cppPtr->getProperty("LinphonePrivate::Wrapper::userData"); return v.getValue(); } template - static inline void setUserData (std::shared_ptr object, void *value) { + static inline void setUserData (const std::shared_ptr &object, void *value) { L_ASSERT(object); object->setProperty("LinphonePrivate::Wrapper::userData", value); } @@ -194,7 +194,7 @@ public: // --------------------------------------------------------------------------- template - static inline bctbx_list_t * getCListFromCppList (const std::list cppList) { + static inline bctbx_list_t *getCListFromCppList (const std::list cppList) { bctbx_list_t *result = nullptr; for (const auto &value : cppList) result = bctbx_list_append(result, value); @@ -202,7 +202,7 @@ public: } template - static inline bctbx_list_t * getCListOfStructPtrFromCppListOfCppObj (const std::list> cppList, CType *(*cTypeAllocator)()) { + static inline bctbx_list_t *getCListOfStructPtrFromCppListOfCppObj (const std::list> cppList, CType *(*cTypeAllocator)()) { bctbx_list_t *result = nullptr; for (const auto &value : cppList) result = bctbx_list_append(result, getCBackPtr(value, cTypeAllocator)); @@ -210,7 +210,7 @@ public: } template - static inline bctbx_list_t * getCListOfStructPtrFromCppListOfCppObj (const std::list cppList, CType *(*cTypeAllocator)()) { + static inline bctbx_list_t *getCListOfStructPtrFromCppListOfCppObj (const std::list cppList, CType *(*cTypeAllocator)()) { bctbx_list_t *result = nullptr; for (const auto &value : cppList) result = bctbx_list_append(result, getCBackPtr(value, cTypeAllocator)); diff --git a/src/chat/basic-chat-room.cpp b/src/chat/basic-chat-room.cpp index 0fe854161..c7eec4b58 100644 --- a/src/chat/basic-chat-room.cpp +++ b/src/chat/basic-chat-room.cpp @@ -65,11 +65,11 @@ list> BasicChatRoom::getParticipants () const { return l; } -void BasicChatRoom::removeParticipant (const shared_ptr participant) { +void BasicChatRoom::removeParticipant (const shared_ptr &participant) { lError() << "removeParticipant() is not allowed on a BasicChatRoom"; } -void BasicChatRoom::removeParticipants (const list> participants) { +void BasicChatRoom::removeParticipants (const list> &participants) { lError() << "removeParticipants() is not allowed on a BasicChatRoom"; } diff --git a/src/chat/basic-chat-room.h b/src/chat/basic-chat-room.h index 4f6ec7d50..1aced22f7 100644 --- a/src/chat/basic-chat-room.h +++ b/src/chat/basic-chat-room.h @@ -45,8 +45,8 @@ public: const std::string& getId () const; int getNbParticipants () const; std::list> getParticipants () const; - void removeParticipant (const std::shared_ptr participant); - void removeParticipants (const std::list> participants); + void removeParticipant (const std::shared_ptr &participant); + void removeParticipants (const std::list> &participants); private: L_DECLARE_PRIVATE(BasicChatRoom); @@ -56,4 +56,3 @@ private: LINPHONE_END_NAMESPACE #endif // ifndef _BASIC_CHAT_ROOM_H_ - diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 282303219..8878bc7f2 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -71,11 +71,11 @@ list> ClientGroupChatRoom::getParticipants () const { return participants; } -void ClientGroupChatRoom::removeParticipant (const shared_ptr participant) { +void ClientGroupChatRoom::removeParticipant (const shared_ptr &participant) { // TODO } -void ClientGroupChatRoom::removeParticipants (const list> participants) { +void ClientGroupChatRoom::removeParticipants (const list> &participants) { // TODO } diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index 849af656e..04c4181e0 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -46,8 +46,8 @@ public: const std::string& getId () const; int getNbParticipants () const; std::list> getParticipants () const; - void removeParticipant (const std::shared_ptr participant); - void removeParticipants (const std::list> participants); + void removeParticipant (const std::shared_ptr &participant); + void removeParticipants (const std::list> &participants); private: L_DECLARE_PRIVATE(ClientGroupChatRoom); @@ -57,4 +57,3 @@ private: LINPHONE_END_NAMESPACE #endif // ifndef _CLIENT_GROUP_CHAT_ROOM_H_ - diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 359912dae..8acb10ae6 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -173,11 +173,11 @@ list> RealTimeTextChatRoom::getParticipants () const { return l; } -void RealTimeTextChatRoom::removeParticipant (const shared_ptr participant) { +void RealTimeTextChatRoom::removeParticipant (const shared_ptr &participant) { lError() << "removeParticipant() is not allowed on a RealTimeTextChatRoom"; } -void RealTimeTextChatRoom::removeParticipants (const list> participants) { +void RealTimeTextChatRoom::removeParticipants (const list> &participants) { lError() << "removeParticipants() is not allowed on a RealTimeTextChatRoom"; } diff --git a/src/chat/real-time-text-chat-room.h b/src/chat/real-time-text-chat-room.h index a75f08d67..4c26673d8 100644 --- a/src/chat/real-time-text-chat-room.h +++ b/src/chat/real-time-text-chat-room.h @@ -49,8 +49,8 @@ public: const std::string& getId () const; int getNbParticipants () const; std::list> getParticipants () const; - void removeParticipant (const std::shared_ptr participant); - void removeParticipants (const std::list> participants); + void removeParticipant (const std::shared_ptr &participant); + void removeParticipants (const std::list> &participants); private: L_DECLARE_PRIVATE(RealTimeTextChatRoom); @@ -60,4 +60,3 @@ private: LINPHONE_END_NAMESPACE #endif // ifndef _REAL_TIME_TEXT_CHAT_ROOM_H_ - diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index 4cdcb7f32..a32040846 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -40,8 +40,8 @@ public: virtual const std::string& getId () const = 0; virtual int getNbParticipants () const = 0; virtual std::list> getParticipants () const = 0; - virtual void removeParticipant (const std::shared_ptr participant) = 0; - virtual void removeParticipants (const std::list> participants) = 0; + virtual void removeParticipant (const std::shared_ptr &participant) = 0; + virtual void removeParticipants (const std::list> &participants) = 0; }; LINPHONE_END_NAMESPACE diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 47080b829..a6d679421 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -66,11 +66,11 @@ list> Conference::getParticipants () const { return participants; } -void Conference::removeParticipant (const shared_ptr participant) { +void Conference::removeParticipant (const shared_ptr &participant) { // TODO } -void Conference::removeParticipants (const list> participants) { +void Conference::removeParticipants (const list> &participants) { // TODO } diff --git a/src/conference/conference.h b/src/conference/conference.h index 8ad1350e5..f5746b556 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -56,8 +56,8 @@ public: virtual const std::string& getId () const; virtual int getNbParticipants () const; virtual std::list> getParticipants () const; - virtual void removeParticipant (const std::shared_ptr participant); - virtual void removeParticipants (const std::list> participants); + virtual void removeParticipant (const std::shared_ptr &participant); + virtual void removeParticipants (const std::list> &participants); private: /* CallSessionListener */ diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index 906d05afa..96ab857f6 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -68,7 +68,7 @@ list> LocalConference::getParticipants () const { return participants; } -void LocalConference::removeParticipant (const shared_ptr participant) { +void LocalConference::removeParticipant (const shared_ptr &participant) { for (const auto &p : participants) { if (participant->getAddress().equal(p->getAddress())) { participants.remove(p); @@ -77,7 +77,7 @@ void LocalConference::removeParticipant (const shared_ptr participa } } -void LocalConference::removeParticipants (const list> participants) { +void LocalConference::removeParticipants (const list> &participants) { for (const auto &p : participants) removeParticipant(p); } diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h index 0b3c93ae6..18394c5b8 100644 --- a/src/conference/local-conference.h +++ b/src/conference/local-conference.h @@ -41,8 +41,8 @@ public: virtual const std::string& getId () const; virtual int getNbParticipants () const; virtual std::list> getParticipants () const; - virtual void removeParticipant (const std::shared_ptr participant); - virtual void removeParticipants (const std::list> participants); + virtual void removeParticipant (const std::shared_ptr &participant); + virtual void removeParticipants (const std::list> &participants); private: L_DISABLE_COPY(LocalConference); From ffc4abad2d3268d34a9d94c80fc69344f6da7e63 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 19 Sep 2017 11:20:41 +0200 Subject: [PATCH 0087/2215] fix(chat): coding style --- src/chat/chat-message-p.h | 5 +- .../modifier/cpim-chat-message-modifier.cpp | 138 +++++++++--------- 2 files changed, 73 insertions(+), 70 deletions(-) diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 87198de32..7b77764cd 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -28,6 +28,9 @@ LINPHONE_BEGIN_NAMESPACE class ChatMessagePrivate : public ObjectPrivate { + friend class CpimChatMessageModifier; + friend class MultipartChatMessageModifier; + private: std::weak_ptr chatRoom; ChatMessage::Direction direction = ChatMessage::Incoming; @@ -47,8 +50,6 @@ private: std::shared_ptr eventsDb; L_DECLARE_PUBLIC(ChatMessage); - friend class CpimChatMessageModifier; - friend class MultipartChatMessageModifier; }; LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index d03344abe..e36095c71 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -16,83 +16,85 @@ * along with this program. If not, see . */ - #include +#include - #include "content/content-type.h" - #include "content/content.h" - #include "chat/chat-message-p.h" - #include "chat/cpim/cpim.h" +#include "chat/chat-message-p.h" +#include "chat/cpim/cpim.h" +#include "content/content-type.h" +#include "content/content.h" - #include "cpim-chat-message-modifier.h" +#include "cpim-chat-message-modifier.h" - LINPHONE_BEGIN_NAMESPACE - - using namespace std; +// ============================================================================= - void CpimChatMessageModifier::encode(LinphonePrivate::ChatMessagePrivate* msg) { - Cpim::Message message; - Cpim::GenericHeader cpimContentTypeHeader; +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +void CpimChatMessageModifier::encode(LinphonePrivate::ChatMessagePrivate* msg) { + Cpim::Message message; + Cpim::GenericHeader cpimContentTypeHeader; cpimContentTypeHeader.setName("Content-Type"); - cpimContentTypeHeader.setValue("Message/CPIM"); - message.addCpimHeader(cpimContentTypeHeader); - - shared_ptr content; - if (msg->internalContent) { - // Another ChatMessageModifier was called before this one, we apply our changes on the private content - content = msg->internalContent; - } else { - // We're the first ChatMessageModifier to be called, we'll create the private content from the public one - // We take the first one because if there is more of them, the multipart modifier should have been called first - // So we should not be in this block - content = msg->contents.front(); - } + cpimContentTypeHeader.setValue("Message/CPIM"); + message.addCpimHeader(cpimContentTypeHeader); - string contentType = content->getContentType().asString(); - const vector body = content->getBody(); - string contentBody(body.begin(), body.end()); + shared_ptr content; + if (msg->internalContent) { + // Another ChatMessageModifier was called before this one, we apply our changes on the private content + content = msg->internalContent; + } else { + // We're the first ChatMessageModifier to be called, we'll create the private content from the public one + // We take the first one because if there is more of them, the multipart modifier should have been called first + // So we should not be in this block + content = msg->contents.front(); + } - Cpim::GenericHeader contentTypeHeader; + string contentType = content->getContentType().asString(); + const vector body = content->getBody(); + string contentBody(body.begin(), body.end()); + + Cpim::GenericHeader contentTypeHeader; contentTypeHeader.setName("Content-Type"); - contentTypeHeader.setValue(contentType); - message.addContentHeader(contentTypeHeader); + contentTypeHeader.setValue(contentType); + message.addContentHeader(contentTypeHeader); - message.setContent(contentBody); + message.setContent(contentBody); - if (!message.isValid()) { - //TODO - } else { - shared_ptr newContent = make_shared(); - ContentType newContentType("Message/CPIM"); - newContent->setContentType(newContentType); - newContent->setBody(message.asString()); - msg->internalContent = newContent; - } - } + if (!message.isValid()) { + //TODO + } else { + shared_ptr newContent = make_shared(); + ContentType newContentType("Message/CPIM"); + newContent->setContentType(newContentType); + newContent->setBody(message.asString()); + msg->internalContent = newContent; + } +} - void CpimChatMessageModifier::decode(LinphonePrivate::ChatMessagePrivate* msg) { - shared_ptr content; - if (msg->internalContent) { - content = msg->internalContent; - } else { - content = msg->contents.front(); - } +void CpimChatMessageModifier::decode(LinphonePrivate::ChatMessagePrivate* msg) { + shared_ptr content; + if (msg->internalContent) { + content = msg->internalContent; + } else { + content = msg->contents.front(); + } - ContentType contentType = content->getContentType(); - if (contentType.asString() == "Message/CPIM") { - const vector body = content->getBody(); - string contentBody(body.begin(), body.end()); - shared_ptr message = Cpim::Message::createFromString(contentBody); - if (message && message->isValid()) { - shared_ptr newContent = make_shared(); - ContentType newContentType(message->getContentHeaders()->front()->getValue()); - newContent->setContentType(newContentType); - newContent->setBody(message->getContent()); - } else { - //TODO - } - } else { - //TODO - } - } - -LINPHONE_END_NAMESPACE \ No newline at end of file + ContentType contentType = content->getContentType(); + if (contentType.asString() == "Message/CPIM") { + const vector body = content->getBody(); + string contentBody(body.begin(), body.end()); + shared_ptr message = Cpim::Message::createFromString(contentBody); + if (message && message->isValid()) { + shared_ptr newContent = make_shared(); + ContentType newContentType(message->getContentHeaders()->front()->getValue()); + newContent->setContentType(newContentType); + newContent->setBody(message->getContent()); + } else { + //TODO + } + } else { + //TODO + } +} + +LINPHONE_END_NAMESPACE From 1b60a6fc4a5668767550b09c0ddb4d57714cc64f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 19 Sep 2017 11:40:13 +0200 Subject: [PATCH 0088/2215] Handle the chat room state. --- include/CMakeLists.txt | 1 + include/linphone/api/c-callbacks.h | 8 ++++++ include/linphone/api/c-chat-room-cbs.h | 14 +++++++++++ include/linphone/api/c-types.h | 2 ++ include/linphone/enums/chat-room-enums.h | 32 ++++++++++++++++++++++++ include/linphone/utils/enum-generator.h | 3 ++- src/c-wrapper/api/c-chat-room-cbs.cpp | 9 +++++++ src/c-wrapper/api/c-chat-room.cpp | 4 +++ src/chat/chat-room-p.h | 7 +++++- src/chat/chat-room.cpp | 21 ++++++++++++++++ src/chat/chat-room.h | 3 +++ 11 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 include/linphone/enums/chat-room-enums.h diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index a2b7662f5..40d842bf5 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -86,6 +86,7 @@ set(C_API_HEADER_FILES ) set(ENUMS_HEADER_FILES + chat-room-enums.h event-log-enums.h ) diff --git a/include/linphone/api/c-callbacks.h b/include/linphone/api/c-callbacks.h index 7402dda84..a1edf51ee 100644 --- a/include/linphone/api/c-callbacks.h +++ b/include/linphone/api/c-callbacks.h @@ -21,6 +21,7 @@ // TODO: Remove me in the future. #include "linphone/callbacks.h" +#include "linphone/api/c-types.h" // ============================================================================= @@ -47,6 +48,13 @@ typedef void (*LinphoneChatRoomCbsIsComposingReceivedCb) (LinphoneChatRoom *cr, */ typedef void (*LinphoneChatRoomCbsMessageReceivedCb) (LinphoneChatRoom *cr, LinphoneChatMessage *msg); +/** + * Callback used to notify a chat room state has changed. + * @param[in] cr #LinphoneChatRoom object + * @param[in] newState The new state of the chat room + */ +typedef void (*LinphoneChatRoomCbsStateChangedCb) (LinphoneChatRoom *cr, LinphoneChatRoomState newState); + /** * Callback used to notify a chat room that a message has been received but we were unable to decrypt it * @param cr #LinphoneChatRoom involved in this conversation diff --git a/include/linphone/api/c-chat-room-cbs.h b/include/linphone/api/c-chat-room-cbs.h index 2b26c2a3f..0c895cecc 100644 --- a/include/linphone/api/c-chat-room-cbs.h +++ b/include/linphone/api/c-chat-room-cbs.h @@ -88,6 +88,20 @@ LINPHONE_PUBLIC LinphoneChatRoomCbsMessageReceivedCb linphone_chat_room_cbs_get_ */ LINPHONE_PUBLIC void linphone_chat_room_cbs_set_message_received (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsMessageReceivedCb cb); +/** + * Get the state changed callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @return The current state changed callback. + */ +LINPHONE_PUBLIC LinphoneChatRoomCbsStateChangedCb linphone_chat_room_cbs_get_state_changed (const LinphoneChatRoomCbs *cbs); + +/** + * Set the state changed callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @param[in] cb The state changed callback to be used. + */ +LINPHONE_PUBLIC void linphone_chat_room_cbs_set_state_changed (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsStateChangedCb cb); + /** * Get the undecryptable message received callback. * @param[in] cbs LinphoneChatRoomCbs object. diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index 72d74fb9d..de41cda49 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -23,6 +23,7 @@ #include "linphone/types.h" #include "linphone/utils/enum-generator.h" +#include "linphone/enums/chat-room-enums.h" #include "linphone/enums/event-log-enums.h" // ============================================================================= @@ -109,6 +110,7 @@ typedef struct _LinphoneMessageEvent LinphoneMessageEvent; // C Enums. // ============================================================================= +L_DECLARE_C_ENUM(ChatRoomState, L_ENUM_VALUES_CHAT_ROOM_STATE); L_DECLARE_C_ENUM(EventLogType, L_ENUM_VALUES_EVENT_LOG_TYPE); #ifdef __cplusplus diff --git a/include/linphone/enums/chat-room-enums.h b/include/linphone/enums/chat-room-enums.h new file mode 100644 index 000000000..7d67728cb --- /dev/null +++ b/include/linphone/enums/chat-room-enums.h @@ -0,0 +1,32 @@ +/* + * chat-room-enums.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CHAT_ROOM_ENUMS_H_ +#define _CHAT_ROOM_ENUMS_H_ + +// ============================================================================= + +#define L_ENUM_VALUES_CHAT_ROOM_STATE(F) \ + F(None) \ + F(Instantiated) \ + F(CreationPending) \ + F(Created) \ + F(Terminated) \ + F(CreationFailed) + +#endif // ifndef _CHAT_ROOM_ENUMS_H_ diff --git a/include/linphone/utils/enum-generator.h b/include/linphone/utils/enum-generator.h index 030fd94b5..333ff6d98 100644 --- a/include/linphone/utils/enum-generator.h +++ b/include/linphone/utils/enum-generator.h @@ -55,7 +55,8 @@ LINPHONE_BEGIN_NAMESPACE #define L_DECLARE_C_ENUM(NAME, VALUES) \ enum L_CONCAT(L_C_ENUM_PREFIX, NAME) { \ L_APPLY(L_CONCAT, L_CONCAT(L_C_ENUM_PREFIX, NAME), L_GET_HEAP(VALUES(L_DECLARE_ENUM_VALUE))) \ - }; + }; \ + typedef enum L_CONCAT(L_C_ENUM_PREFIX, NAME) L_CONCAT(L_C_ENUM_PREFIX, NAME); LINPHONE_END_NAMESPACE diff --git a/src/c-wrapper/api/c-chat-room-cbs.cpp b/src/c-wrapper/api/c-chat-room-cbs.cpp index 094bd9a15..2e1dd09e2 100644 --- a/src/c-wrapper/api/c-chat-room-cbs.cpp +++ b/src/c-wrapper/api/c-chat-room-cbs.cpp @@ -26,6 +26,7 @@ struct _LinphoneChatRoomCbs { void *userData; LinphoneChatRoomCbsIsComposingReceivedCb isComposingReceivedCb; LinphoneChatRoomCbsMessageReceivedCb messageReceivedCb; + LinphoneChatRoomCbsStateChangedCb stateChangedCb; LinphoneChatRoomCbsUndecryptableMessageReceivedCb undecryptableMessageReceivedCb; }; @@ -77,6 +78,14 @@ void linphone_chat_room_cbs_set_message_received (LinphoneChatRoomCbs *cbs, Linp cbs->messageReceivedCb = cb; } +LinphoneChatRoomCbsStateChangedCb linphone_chat_room_cbs_get_state_changed (const LinphoneChatRoomCbs *cbs) { + return cbs->stateChangedCb; +} + +void linphone_chat_room_cbs_set_state_changed (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsStateChangedCb cb) { + cbs->stateChangedCb = cb; +} + LinphoneChatRoomCbsUndecryptableMessageReceivedCb linphone_chat_room_cbs_get_undecryptable_message_received (const LinphoneChatRoomCbs *cbs) { return cbs->undecryptableMessageReceivedCb; } diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index c53b3c41f..ffe36c6cc 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -267,6 +267,8 @@ LinphoneChatRoom * linphone_chat_room_new(LinphoneCore *core, const LinphoneAddr else L_SET_CPP_PTR_FROM_C_STRUCT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address, Address))); linphone_core_notify_chat_room_instantiated(core, cr); + L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Instantiated); + L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Created); return cr; } @@ -287,6 +289,8 @@ LinphoneChatRoom * linphone_client_group_chat_room_new(LinphoneCore *core, const LinphoneChatRoom *cr = _linphone_chat_room_init(); L_SET_CPP_PTR_FROM_C_STRUCT(cr, make_shared(core, me, l)); linphone_core_notify_chat_room_instantiated(core, cr); + L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Instantiated); + L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::CreationPending); return cr; } diff --git a/src/chat/chat-room-p.h b/src/chat/chat-room-p.h index d7dd25fe0..1f082da49 100644 --- a/src/chat/chat-room-p.h +++ b/src/chat/chat-room-p.h @@ -22,6 +22,9 @@ // From coreapi. #include "private.h" +#include "linphone/enums/chat-room-enums.h" +#include "linphone/utils/enum-generator.h" + #include "chat-room.h" #include "is-composing.h" #include "is-composing-listener.h" @@ -46,7 +49,6 @@ public: std::list getTransientMessages () const { return transientMessages; } - void moveTransientMessageToWeakMessages (LinphoneChatMessage *msg); void removeTransientMessage (LinphoneChatMessage *msg); @@ -54,6 +56,7 @@ public: void sendImdn (const std::string &content, LinphoneReason reason); int getMessagesCount (bool unreadOnly); + void setState (ChatRoom::State newState); protected: void sendIsComposingNotification (); @@ -78,6 +81,7 @@ protected: private: void notifyChatMessageReceived (LinphoneChatMessage *msg); + void notifyStateChanged (); void notifyUndecryptableMessageReceived (LinphoneChatMessage *msg); private: @@ -89,6 +93,7 @@ private: public: LinphoneCore *core = nullptr; LinphoneCall *call = nullptr; + ChatRoom::State state = ChatRoom::State::None; Address peerAddress; int unreadCount = -1; bool isComposing = false; diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 50550a0e7..776c9bd86 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -182,6 +182,13 @@ int ChatRoomPrivate::getMessagesCount (bool unreadOnly) { return numrows; } +void ChatRoomPrivate::setState (ChatRoom::State newState) { + if (newState != state) { + state = newState; + notifyStateChanged(); + } +} + // ----------------------------------------------------------------------------- void ChatRoomPrivate::sendIsComposingNotification () { @@ -528,6 +535,15 @@ void ChatRoomPrivate::notifyChatMessageReceived (LinphoneChatMessage *msg) { linphone_core_notify_message_received(core, cr, msg); } +void ChatRoomPrivate::notifyStateChanged () { + L_Q(ChatRoom); + LinphoneChatRoom *cr = GET_BACK_PTR(q); + LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); + LinphoneChatRoomCbsStateChangedCb cb = linphone_chat_room_cbs_get_state_changed(cbs); + if (cb) + cb(cr, (LinphoneChatRoomState)state); +} + void ChatRoomPrivate::notifyUndecryptableMessageReceived (LinphoneChatMessage *msg) { L_Q(ChatRoom); LinphoneChatRoom *cr = GET_BACK_PTR(q); @@ -924,4 +940,9 @@ const Address& ChatRoom::getPeerAddress () const { return d->peerAddress; } +ChatRoom::State ChatRoom::getState () const { + L_D(const ChatRoom); + return d->state; +} + LINPHONE_END_NAMESPACE diff --git a/src/chat/chat-room.h b/src/chat/chat-room.h index e2c34047f..c71fc7880 100644 --- a/src/chat/chat-room.h +++ b/src/chat/chat-room.h @@ -38,6 +38,8 @@ class ChatRoomPrivate; class ChatRoom : public Object, public ConferenceInterface { public: + L_DECLARE_ENUM(State, L_ENUM_VALUES_CHAT_ROOM_STATE); + ChatRoom (LinphoneCore *core); virtual ~ChatRoom () = default; @@ -59,6 +61,7 @@ public: LinphoneCore *getCore () const; const Address& getPeerAddress () const; + State getState () const; protected: explicit ChatRoom (ChatRoomPrivate &p); From 2096d7998ba54799cbf9245b6a05a525089fabdb Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 19 Sep 2017 11:44:49 +0200 Subject: [PATCH 0089/2215] feat(c-wrapper): coding style --- src/c-wrapper/api/c-address.cpp | 7 +- src/c-wrapper/api/c-call-params.cpp | 253 +++++++++++++------------- src/c-wrapper/api/c-chat-message.cpp | 43 +++-- src/c-wrapper/api/c-chat-room-cbs.cpp | 6 +- src/c-wrapper/api/c-chat-room.cpp | 135 +++++++------- src/c-wrapper/api/c-event-log.cpp | 1 - src/c-wrapper/api/c-participant.cpp | 5 +- src/c-wrapper/c-tools.h | 6 +- 8 files changed, 235 insertions(+), 221 deletions(-) diff --git a/src/c-wrapper/api/c-address.cpp b/src/c-wrapper/api/c-address.cpp index 80d4002db..9e966dfc7 100644 --- a/src/c-wrapper/api/c-address.cpp +++ b/src/c-wrapper/api/c-address.cpp @@ -18,15 +18,16 @@ #include "linphone/api/c-address.h" -#include "c-wrapper/c-tools.h" - #include "address/address.h" +#include "c-wrapper/c-tools.h" // ============================================================================= +L_DECLARE_C_CLONABLE_STRUCT_IMPL(Address, Address, address); + using namespace std; -L_DECLARE_C_CLONABLE_STRUCT_IMPL(Address, Address, address); +// ============================================================================= LinphoneAddress *linphone_address_new (const char *address) { LINPHONE_NAMESPACE::Address *cppPtr = new LINPHONE_NAMESPACE::Address(L_C_TO_STRING(address)); diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index 13d515655..a51c3fead 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -17,12 +17,16 @@ */ #include "linphone/call_params.h" + +// TODO: Remove me later. #include "private.h" #include "c-wrapper/c-tools.h" -#include "conference/params/media-session-params.h" #include "conference/params/call-session-params-p.h" #include "conference/params/media-session-params-p.h" +#include "conference/params/media-session-params.h" + +// ============================================================================= #define GET_CALL_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, CallSessionParams, CallParams) #define GET_CALL_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, CallSessionParams, CallParams) @@ -31,19 +35,17 @@ L_DECLARE_C_CLONABLE_STRUCT_IMPL(MediaSessionParams, CallParams, call_params) -// ============================================================================= - using namespace std; -/******************************************************************************* - * Internal functions * - ******************************************************************************/ +// ============================================================================= +// Internal functions. +// ============================================================================= -SalMediaProto get_proto_from_call_params(const LinphoneCallParams *params) { +SalMediaProto get_proto_from_call_params (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->getMediaProto(); } -SalStreamDir sal_dir_from_call_params_dir(LinphoneMediaDirection cpdir) { +SalStreamDir sal_dir_from_call_params_dir (LinphoneMediaDirection cpdir) { switch (cpdir) { case LinphoneMediaDirectionInactive: return SalStreamInactive; @@ -60,7 +62,7 @@ SalStreamDir sal_dir_from_call_params_dir(LinphoneMediaDirection cpdir) { return SalStreamSendRecv; } -LinphoneMediaDirection media_direction_from_sal_stream_dir(SalStreamDir dir){ +LinphoneMediaDirection media_direction_from_sal_stream_dir (SalStreamDir dir) { switch (dir) { case SalStreamInactive: return LinphoneMediaDirectionInactive; @@ -74,112 +76,111 @@ LinphoneMediaDirection media_direction_from_sal_stream_dir(SalStreamDir dir){ return LinphoneMediaDirectionSendRecv; } -SalStreamDir get_audio_dir_from_call_params(const LinphoneCallParams *params) { +SalStreamDir get_audio_dir_from_call_params (const LinphoneCallParams *params) { return sal_dir_from_call_params_dir(linphone_call_params_get_audio_direction(params)); } -SalStreamDir get_video_dir_from_call_params(const LinphoneCallParams *params) { +SalStreamDir get_video_dir_from_call_params (const LinphoneCallParams *params) { return sal_dir_from_call_params_dir(linphone_call_params_get_video_direction(params)); } -void linphone_call_params_set_custom_headers(LinphoneCallParams *params, const SalCustomHeader *ch) { +void linphone_call_params_set_custom_headers (LinphoneCallParams *params, const SalCustomHeader *ch) { GET_CALL_CPP_PRIVATE_PTR(params)->setCustomHeaders(ch); } -void linphone_call_params_set_custom_sdp_attributes(LinphoneCallParams *params, const SalCustomSdpAttribute *csa) { +void linphone_call_params_set_custom_sdp_attributes (LinphoneCallParams *params, const SalCustomSdpAttribute *csa) { GET_MEDIA_CPP_PRIVATE_PTR(params)->setCustomSdpAttributes(csa); } -void linphone_call_params_set_custom_sdp_media_attributes(LinphoneCallParams *params, LinphoneStreamType type, const SalCustomSdpAttribute *csa) { +void linphone_call_params_set_custom_sdp_media_attributes (LinphoneCallParams *params, LinphoneStreamType type, const SalCustomSdpAttribute *csa) { GET_MEDIA_CPP_PRIVATE_PTR(params)->setCustomSdpMediaAttributes(type, csa); } +// ============================================================================= +// Public functions. +// ============================================================================= -/******************************************************************************* - * Public functions * - ******************************************************************************/ - -void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value) { +void linphone_call_params_add_custom_header (LinphoneCallParams *params, const char *header_name, const char *header_value) { GET_MEDIA_CPP_PTR(params)->addCustomHeader(header_name, header_value); } -void linphone_call_params_add_custom_sdp_attribute(LinphoneCallParams *params, const char *attribute_name, const char *attribute_value) { +void linphone_call_params_add_custom_sdp_attribute (LinphoneCallParams *params, const char *attribute_name, const char *attribute_value) { GET_MEDIA_CPP_PTR(params)->addCustomSdpAttribute(attribute_name, attribute_value); } -void linphone_call_params_add_custom_sdp_media_attribute(LinphoneCallParams *params, LinphoneStreamType type, const char *attribute_name, const char *attribute_value) { +void linphone_call_params_add_custom_sdp_media_attribute (LinphoneCallParams *params, LinphoneStreamType type, const char *attribute_name, const char *attribute_value) { GET_MEDIA_CPP_PTR(params)->addCustomSdpMediaAttribute(type, attribute_name, attribute_value); } -void linphone_call_params_clear_custom_sdp_attributes(LinphoneCallParams *params) { +void linphone_call_params_clear_custom_sdp_attributes (LinphoneCallParams *params) { GET_MEDIA_CPP_PTR(params)->clearCustomSdpAttributes(); } -void linphone_call_params_clear_custom_sdp_media_attributes(LinphoneCallParams *params, LinphoneStreamType type) { +void linphone_call_params_clear_custom_sdp_media_attributes (LinphoneCallParams *params, LinphoneStreamType type) { GET_MEDIA_CPP_PTR(params)->clearCustomSdpMediaAttributes(type); } -LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *params) { +LinphoneCallParams *linphone_call_params_copy (const LinphoneCallParams *params) { return (LinphoneCallParams *)belle_sip_object_clone((const belle_sip_object_t *)params); } -bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *params) { +bool_t linphone_call_params_early_media_sending_enabled (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->earlyMediaSendingEnabled(); } -void linphone_call_params_enable_early_media_sending(LinphoneCallParams *params, bool_t enabled) { +void linphone_call_params_enable_early_media_sending (LinphoneCallParams *params, bool_t enabled) { GET_MEDIA_CPP_PTR(params)->enableEarlyMediaSending(enabled); } -void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *params, bool_t enabled) { +void linphone_call_params_enable_low_bandwidth (LinphoneCallParams *params, bool_t enabled) { GET_MEDIA_CPP_PTR(params)->enableLowBandwidth(enabled); } -void linphone_call_params_enable_audio(LinphoneCallParams *params, bool_t enabled) { +void linphone_call_params_enable_audio (LinphoneCallParams *params, bool_t enabled) { GET_MEDIA_CPP_PTR(params)->enableAudio(enabled); } -LinphoneStatus linphone_call_params_enable_realtime_text(LinphoneCallParams *params, bool_t yesno) { +LinphoneStatus linphone_call_params_enable_realtime_text (LinphoneCallParams *params, bool_t yesno) { GET_MEDIA_CPP_PTR(params)->enableRealtimeText(yesno); return 0; } -void linphone_call_params_enable_video(LinphoneCallParams *params, bool_t enabled) { +void linphone_call_params_enable_video (LinphoneCallParams *params, bool_t enabled) { GET_MEDIA_CPP_PTR(params)->enableVideo(enabled); } -const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name) { +const char *linphone_call_params_get_custom_header (const LinphoneCallParams *params, const char *header_name) { string value = GET_MEDIA_CPP_PTR(params)->getCustomHeader(header_name); return value.empty() ? nullptr : value.c_str(); } -const char * linphone_call_params_get_custom_sdp_attribute(const LinphoneCallParams *params, const char *attribute_name) { +const char *linphone_call_params_get_custom_sdp_attribute (const LinphoneCallParams *params, const char *attribute_name) { string value = GET_MEDIA_CPP_PTR(params)->getCustomSdpAttribute(attribute_name); return value.empty() ? nullptr : value.c_str(); } -const char * linphone_call_params_get_custom_sdp_media_attribute(const LinphoneCallParams *params, LinphoneStreamType type, const char *attribute_name) { +const char *linphone_call_params_get_custom_sdp_media_attribute (const LinphoneCallParams *params, LinphoneStreamType type, const char *attribute_name) { string value = GET_MEDIA_CPP_PTR(params)->getCustomSdpMediaAttribute(type, attribute_name); return value.empty() ? nullptr : value.c_str(); } -bool_t linphone_call_params_get_local_conference_mode(const LinphoneCallParams *params) { +bool_t linphone_call_params_get_local_conference_mode (const LinphoneCallParams *params) { return linphone_call_params_get_in_conference(params); } -LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *params) { +LinphoneMediaEncryption linphone_call_params_get_media_encryption (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->getMediaEncryption(); } -LinphonePrivacyMask linphone_call_params_get_privacy(const LinphoneCallParams *params) { +LinphonePrivacyMask linphone_call_params_get_privacy (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->getPrivacy(); } -float linphone_call_params_get_received_framerate(const LinphoneCallParams *params) { +float linphone_call_params_get_received_framerate (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->getReceivedFps(); } -MSVideoSize linphone_call_params_get_received_video_size(const LinphoneCallParams *params) { +MSVideoSize linphone_call_params_get_received_video_size (const LinphoneCallParams *params) { MSVideoSize vsize; LinphoneVideoDefinition *vdef = GET_MEDIA_CPP_PTR(params)->getReceivedVideoDefinition(); if (vdef) { @@ -192,24 +193,24 @@ MSVideoSize linphone_call_params_get_received_video_size(const LinphoneCallParam return vsize; } -const LinphoneVideoDefinition * linphone_call_params_get_received_video_definition(const LinphoneCallParams *params) { +const LinphoneVideoDefinition *linphone_call_params_get_received_video_definition (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->getReceivedVideoDefinition(); } -const char *linphone_call_params_get_record_file(const LinphoneCallParams *params) { +const char *linphone_call_params_get_record_file (const LinphoneCallParams *params) { const string &value = GET_MEDIA_CPP_PTR(params)->getRecordFilePath(); return value.empty() ? nullptr : value.c_str(); } -const char * linphone_call_params_get_rtp_profile(const LinphoneCallParams *params) { +const char *linphone_call_params_get_rtp_profile (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->getRtpProfile(); } -float linphone_call_params_get_sent_framerate(const LinphoneCallParams *params) { +float linphone_call_params_get_sent_framerate (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->getSentFps(); } -MSVideoSize linphone_call_params_get_sent_video_size(const LinphoneCallParams *params) { +MSVideoSize linphone_call_params_get_sent_video_size (const LinphoneCallParams *params) { MSVideoSize vsize; LinphoneVideoDefinition *vdef = GET_MEDIA_CPP_PTR(params)->getSentVideoDefinition(); if (vdef) { @@ -222,310 +223,308 @@ MSVideoSize linphone_call_params_get_sent_video_size(const LinphoneCallParams *p return vsize; } -const LinphoneVideoDefinition * linphone_call_params_get_sent_video_definition(const LinphoneCallParams *params) { +const LinphoneVideoDefinition *linphone_call_params_get_sent_video_definition (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->getSentVideoDefinition(); } -const char *linphone_call_params_get_session_name(const LinphoneCallParams *params) { +const char *linphone_call_params_get_session_name (const LinphoneCallParams *params) { const string &value = GET_MEDIA_CPP_PTR(params)->getSessionName(); return value.empty() ? nullptr : value.c_str(); } -LinphonePayloadType *linphone_call_params_get_used_audio_payload_type(const LinphoneCallParams *params) { +LinphonePayloadType *linphone_call_params_get_used_audio_payload_type (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->getUsedAudioPayloadType(); } -LinphonePayloadType *linphone_call_params_get_used_video_payload_type(const LinphoneCallParams *params) { +LinphonePayloadType *linphone_call_params_get_used_video_payload_type (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->getUsedVideoPayloadType(); } -LinphonePayloadType *linphone_call_params_get_used_text_payload_type(const LinphoneCallParams *params) { +LinphonePayloadType *linphone_call_params_get_used_text_payload_type (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->getUsedRealtimeTextPayloadType(); } -const OrtpPayloadType *linphone_call_params_get_used_audio_codec(const LinphoneCallParams *params) { +const OrtpPayloadType *linphone_call_params_get_used_audio_codec (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->getUsedAudioCodec(); } -void linphone_call_params_set_used_audio_codec(LinphoneCallParams *params, OrtpPayloadType *codec) { +void linphone_call_params_set_used_audio_codec (LinphoneCallParams *params, OrtpPayloadType *codec) { GET_MEDIA_CPP_PRIVATE_PTR(params)->setUsedAudioCodec(codec); } -const OrtpPayloadType *linphone_call_params_get_used_video_codec(const LinphoneCallParams *params) { +const OrtpPayloadType *linphone_call_params_get_used_video_codec (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->getUsedVideoCodec(); } -void linphone_call_params_set_used_video_codec(LinphoneCallParams *params, OrtpPayloadType *codec) { +void linphone_call_params_set_used_video_codec (LinphoneCallParams *params, OrtpPayloadType *codec) { GET_MEDIA_CPP_PRIVATE_PTR(params)->setUsedVideoCodec(codec); } -const OrtpPayloadType *linphone_call_params_get_used_text_codec(const LinphoneCallParams *params) { +const OrtpPayloadType *linphone_call_params_get_used_text_codec (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->getUsedRealtimeTextCodec(); } -void linphone_call_params_set_used_text_codec(LinphoneCallParams *params, OrtpPayloadType *codec) { +void linphone_call_params_set_used_text_codec (LinphoneCallParams *params, OrtpPayloadType *codec) { GET_MEDIA_CPP_PRIVATE_PTR(params)->setUsedRealtimeTextCodec(codec); } -bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *params) { +bool_t linphone_call_params_low_bandwidth_enabled (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->lowBandwidthEnabled(); } -int linphone_call_params_get_audio_bandwidth_limit(const LinphoneCallParams *params) { +int linphone_call_params_get_audio_bandwidth_limit (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->getAudioBandwidthLimit(); } -void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *params, int bandwidth) { +void linphone_call_params_set_audio_bandwidth_limit (LinphoneCallParams *params, int bandwidth) { GET_MEDIA_CPP_PTR(params)->setAudioBandwidthLimit(bandwidth); } -void linphone_call_params_set_media_encryption(LinphoneCallParams *params, LinphoneMediaEncryption encryption) { +void linphone_call_params_set_media_encryption (LinphoneCallParams *params, LinphoneMediaEncryption encryption) { GET_MEDIA_CPP_PTR(params)->setMediaEncryption(encryption); } -void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacyMask privacy) { +void linphone_call_params_set_privacy (LinphoneCallParams *params, LinphonePrivacyMask privacy) { GET_MEDIA_CPP_PTR(params)->setPrivacy(privacy); } -void linphone_call_params_set_record_file(LinphoneCallParams *params, const char *path) { +void linphone_call_params_set_record_file (LinphoneCallParams *params, const char *path) { GET_MEDIA_CPP_PTR(params)->setRecordFilePath(path ? path : ""); } -void linphone_call_params_set_session_name(LinphoneCallParams *params, const char *name) { +void linphone_call_params_set_session_name (LinphoneCallParams *params, const char *name) { GET_MEDIA_CPP_PTR(params)->setSessionName(name ? name : ""); } -bool_t linphone_call_params_audio_enabled(const LinphoneCallParams *params) { +bool_t linphone_call_params_audio_enabled (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->audioEnabled(); } -bool_t linphone_call_params_realtime_text_enabled(const LinphoneCallParams *params) { +bool_t linphone_call_params_realtime_text_enabled (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->realtimeTextEnabled(); } -bool_t linphone_call_params_video_enabled(const LinphoneCallParams *params) { +bool_t linphone_call_params_video_enabled (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->videoEnabled(); } -LinphoneMediaDirection linphone_call_params_get_audio_direction(const LinphoneCallParams *params) { +LinphoneMediaDirection linphone_call_params_get_audio_direction (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->getAudioDirection(); } -LinphoneMediaDirection linphone_call_params_get_video_direction(const LinphoneCallParams *params) { +LinphoneMediaDirection linphone_call_params_get_video_direction (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->getVideoDirection(); } -void linphone_call_params_set_audio_direction(LinphoneCallParams *params, LinphoneMediaDirection dir) { +void linphone_call_params_set_audio_direction (LinphoneCallParams *params, LinphoneMediaDirection dir) { GET_MEDIA_CPP_PTR(params)->setAudioDirection(dir); } -void linphone_call_params_set_video_direction(LinphoneCallParams *params, LinphoneMediaDirection dir) { +void linphone_call_params_set_video_direction (LinphoneCallParams *params, LinphoneMediaDirection dir) { GET_MEDIA_CPP_PTR(params)->setVideoDirection(dir); } -void linphone_call_params_enable_audio_multicast(LinphoneCallParams *params, bool_t yesno) { +void linphone_call_params_enable_audio_multicast (LinphoneCallParams *params, bool_t yesno) { GET_MEDIA_CPP_PTR(params)->enableAudioMulticast(yesno); } -bool_t linphone_call_params_audio_multicast_enabled(const LinphoneCallParams *params) { +bool_t linphone_call_params_audio_multicast_enabled (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->audioMulticastEnabled(); } -void linphone_call_params_enable_video_multicast(LinphoneCallParams *params, bool_t yesno) { +void linphone_call_params_enable_video_multicast (LinphoneCallParams *params, bool_t yesno) { GET_MEDIA_CPP_PTR(params)->enableVideoMulticast(yesno); } -bool_t linphone_call_params_video_multicast_enabled(const LinphoneCallParams *params) { + +bool_t linphone_call_params_video_multicast_enabled (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->videoMulticastEnabled(); } -bool_t linphone_call_params_real_early_media_enabled(const LinphoneCallParams *params) { +bool_t linphone_call_params_real_early_media_enabled (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->earlyMediaSendingEnabled(); } -bool_t linphone_call_params_avpf_enabled(const LinphoneCallParams *params) { +bool_t linphone_call_params_avpf_enabled (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->avpfEnabled(); } -void linphone_call_params_enable_avpf(LinphoneCallParams *params, bool_t enable) { +void linphone_call_params_enable_avpf (LinphoneCallParams *params, bool_t enable) { GET_MEDIA_CPP_PTR(params)->enableAvpf(enable); } -bool_t linphone_call_params_mandatory_media_encryption_enabled(const LinphoneCallParams *params) { +bool_t linphone_call_params_mandatory_media_encryption_enabled (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->mandatoryMediaEncryptionEnabled(); } -void linphone_call_params_enable_mandatory_media_encryption(LinphoneCallParams *params, bool_t value) { +void linphone_call_params_enable_mandatory_media_encryption (LinphoneCallParams *params, bool_t value) { GET_MEDIA_CPP_PTR(params)->enableMandatoryMediaEncryption(value); } -uint16_t linphone_call_params_get_avpf_rr_interval(const LinphoneCallParams *params) { +uint16_t linphone_call_params_get_avpf_rr_interval (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PTR(params)->getAvpfRrInterval(); } -void linphone_call_params_set_avpf_rr_interval(LinphoneCallParams *params, uint16_t value) { +void linphone_call_params_set_avpf_rr_interval (LinphoneCallParams *params, uint16_t value) { GET_MEDIA_CPP_PTR(params)->setAvpfRrInterval(value); } -void linphone_call_params_set_sent_fps(LinphoneCallParams *params, float value) { +void linphone_call_params_set_sent_fps (LinphoneCallParams *params, float value) { GET_MEDIA_CPP_PRIVATE_PTR(params)->setSentFps(value); } -void linphone_call_params_set_received_fps(LinphoneCallParams *params, float value) { +void linphone_call_params_set_received_fps (LinphoneCallParams *params, float value) { GET_MEDIA_CPP_PRIVATE_PTR(params)->setReceivedFps(value); } +// ============================================================================= +// Private functions. +// ============================================================================= -/******************************************************************************* - * Private functions * - ******************************************************************************/ - -bool_t linphone_call_params_get_in_conference(const LinphoneCallParams *params) { +bool_t linphone_call_params_get_in_conference (const LinphoneCallParams *params) { return GET_CALL_CPP_PRIVATE_PTR(params)->getInConference(); } -void linphone_call_params_set_in_conference(LinphoneCallParams *params, bool_t value) { +void linphone_call_params_set_in_conference (LinphoneCallParams *params, bool_t value) { GET_CALL_CPP_PRIVATE_PTR(params)->setInConference(value); } -bool_t linphone_call_params_get_internal_call_update(const LinphoneCallParams *params) { +bool_t linphone_call_params_get_internal_call_update (const LinphoneCallParams *params) { return GET_CALL_CPP_PRIVATE_PTR(params)->getInternalCallUpdate(); } -void linphone_call_params_set_internal_call_update(LinphoneCallParams *params, bool_t value) { +void linphone_call_params_set_internal_call_update (LinphoneCallParams *params, bool_t value) { GET_CALL_CPP_PRIVATE_PTR(params)->setInternalCallUpdate(value); } -bool_t linphone_call_params_implicit_rtcp_fb_enabled(const LinphoneCallParams *params) { +bool_t linphone_call_params_implicit_rtcp_fb_enabled (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PRIVATE_PTR(params)->implicitRtcpFbEnabled(); } -void linphone_call_params_enable_implicit_rtcp_fb(LinphoneCallParams *params, bool_t value) { +void linphone_call_params_enable_implicit_rtcp_fb (LinphoneCallParams *params, bool_t value) { GET_MEDIA_CPP_PRIVATE_PTR(params)->enableImplicitRtcpFb(value); } -int linphone_call_params_get_down_bandwidth(const LinphoneCallParams *params) { +int linphone_call_params_get_down_bandwidth (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PRIVATE_PTR(params)->getDownBandwidth(); } -void linphone_call_params_set_down_bandwidth(LinphoneCallParams *params, int value) { +void linphone_call_params_set_down_bandwidth (LinphoneCallParams *params, int value) { GET_MEDIA_CPP_PRIVATE_PTR(params)->setDownBandwidth(value); } -int linphone_call_params_get_up_bandwidth(const LinphoneCallParams *params) { +int linphone_call_params_get_up_bandwidth (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PRIVATE_PTR(params)->getUpBandwidth(); } -void linphone_call_params_set_up_bandwidth(LinphoneCallParams *params, int value) { +void linphone_call_params_set_up_bandwidth (LinphoneCallParams *params, int value) { GET_MEDIA_CPP_PRIVATE_PTR(params)->setUpBandwidth(value); } -int linphone_call_params_get_down_ptime(const LinphoneCallParams *params) { +int linphone_call_params_get_down_ptime (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PRIVATE_PTR(params)->getDownPtime(); } -void linphone_call_params_set_down_ptime(LinphoneCallParams *params, int value) { +void linphone_call_params_set_down_ptime (LinphoneCallParams *params, int value) { GET_MEDIA_CPP_PRIVATE_PTR(params)->setDownPtime(value); } -int linphone_call_params_get_up_ptime(const LinphoneCallParams *params) { +int linphone_call_params_get_up_ptime (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PRIVATE_PTR(params)->getUpPtime(); } -void linphone_call_params_set_up_ptime(LinphoneCallParams *params, int value) { +void linphone_call_params_set_up_ptime (LinphoneCallParams *params, int value) { GET_MEDIA_CPP_PRIVATE_PTR(params)->setUpPtime(value); } -SalCustomHeader * linphone_call_params_get_custom_headers(const LinphoneCallParams *params) { +SalCustomHeader *linphone_call_params_get_custom_headers (const LinphoneCallParams *params) { return GET_CALL_CPP_PRIVATE_PTR(params)->getCustomHeaders(); } -SalCustomSdpAttribute * linphone_call_params_get_custom_sdp_attributes(const LinphoneCallParams *params) { +SalCustomSdpAttribute *linphone_call_params_get_custom_sdp_attributes (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PRIVATE_PTR(params)->getCustomSdpAttributes(); } -SalCustomSdpAttribute * linphone_call_params_get_custom_sdp_media_attributes(const LinphoneCallParams *params, LinphoneStreamType type) { +SalCustomSdpAttribute *linphone_call_params_get_custom_sdp_media_attributes (const LinphoneCallParams *params, LinphoneStreamType type) { return GET_MEDIA_CPP_PRIVATE_PTR(params)->getCustomSdpMediaAttributes(type); } -LinphoneCall * linphone_call_params_get_referer(const LinphoneCallParams *params) { +LinphoneCall *linphone_call_params_get_referer (const LinphoneCallParams *params) { return GET_CALL_CPP_PRIVATE_PTR(params)->getReferer(); } -void linphone_call_params_set_referer(LinphoneCallParams *params, LinphoneCall *referer) { +void linphone_call_params_set_referer (LinphoneCallParams *params, LinphoneCall *referer) { GET_CALL_CPP_PRIVATE_PTR(params)->setReferer(referer); } -bool_t linphone_call_params_get_update_call_when_ice_completed(const LinphoneCallParams *params) { +bool_t linphone_call_params_get_update_call_when_ice_completed (const LinphoneCallParams *params) { return GET_MEDIA_CPP_PRIVATE_PTR(params)->getUpdateCallWhenIceCompleted(); } -void linphone_call_params_set_update_call_when_ice_completed(LinphoneCallParams *params, bool_t value) { +void linphone_call_params_set_update_call_when_ice_completed (LinphoneCallParams *params, bool_t value) { GET_MEDIA_CPP_PRIVATE_PTR(params)->setUpdateCallWhenIceCompleted(value); } -void linphone_call_params_set_sent_vsize(LinphoneCallParams *params, MSVideoSize vsize) { +void linphone_call_params_set_sent_vsize (LinphoneCallParams *params, MSVideoSize vsize) { GET_MEDIA_CPP_PRIVATE_PTR(params)->setSentVideoDefinition(linphone_video_definition_new(vsize.width, vsize.height, nullptr)); } -void linphone_call_params_set_recv_vsize(LinphoneCallParams *params, MSVideoSize vsize) { +void linphone_call_params_set_recv_vsize (LinphoneCallParams *params, MSVideoSize vsize) { GET_MEDIA_CPP_PRIVATE_PTR(params)->setReceivedVideoDefinition(linphone_video_definition_new(vsize.width, vsize.height, nullptr)); } -void linphone_call_params_set_sent_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef) { +void linphone_call_params_set_sent_video_definition (LinphoneCallParams *params, LinphoneVideoDefinition *vdef) { GET_MEDIA_CPP_PRIVATE_PTR(params)->setSentVideoDefinition(vdef); } -void linphone_call_params_set_received_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef) { +void linphone_call_params_set_received_video_definition (LinphoneCallParams *params, LinphoneVideoDefinition *vdef) { GET_MEDIA_CPP_PRIVATE_PTR(params)->setReceivedVideoDefinition(vdef); } -bool_t linphone_call_params_get_no_user_consent(const LinphoneCallParams *params) { +bool_t linphone_call_params_get_no_user_consent (const LinphoneCallParams *params) { return GET_CALL_CPP_PRIVATE_PTR(params)->getNoUserConsent(); } -void linphone_call_params_set_no_user_consent(LinphoneCallParams *params, bool_t value) { +void linphone_call_params_set_no_user_consent (LinphoneCallParams *params, bool_t value) { GET_CALL_CPP_PRIVATE_PTR(params)->setNoUserConsent(value); } +// ============================================================================= +// Reference and user data handling functions. +// ============================================================================= -/******************************************************************************* - * Reference and user data handling functions * - ******************************************************************************/ - -void * linphone_call_params_get_user_data(const LinphoneCallParams *cp) { +void *linphone_call_params_get_user_data (const LinphoneCallParams *cp) { return L_GET_USER_DATA_FROM_C_STRUCT(cp, MediaSessionParams, CallParams); } -void linphone_call_params_set_user_data(LinphoneCallParams *cp, void *ud) { +void linphone_call_params_set_user_data (LinphoneCallParams *cp, void *ud) { L_SET_USER_DATA_FROM_C_STRUCT(cp, ud, MediaSessionParams, CallParams); } -LinphoneCallParams * linphone_call_params_ref(LinphoneCallParams *cp) { +LinphoneCallParams *linphone_call_params_ref (LinphoneCallParams *cp) { belle_sip_object_ref(cp); return cp; } -void linphone_call_params_unref(LinphoneCallParams *cp) { +void linphone_call_params_unref (LinphoneCallParams *cp) { belle_sip_object_unref(cp); } +// ============================================================================= +// Constructor and destructor functions. +// ============================================================================= -/******************************************************************************* - * Constructor and destructor functions * - ******************************************************************************/ - -LinphoneCallParams * linphone_call_params_new(LinphoneCore *core) { +LinphoneCallParams *linphone_call_params_new (LinphoneCore *core) { LinphoneCallParams *params = _linphone_call_params_init(); L_SET_CPP_PTR_FROM_C_STRUCT(params, new LinphonePrivate::MediaSessionParams()); GET_MEDIA_CPP_PTR(params)->initDefault(core); return params; } -LinphoneCallParams * linphone_call_params_new_for_wrapper(void) { +LinphoneCallParams *linphone_call_params_new_for_wrapper (void) { return _linphone_call_params_init(); } /* DEPRECATED */ -void linphone_call_params_destroy(LinphoneCallParams *cp) { +void linphone_call_params_destroy (LinphoneCallParams *cp) { linphone_call_params_unref(cp); } diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 265222519..67d14f173 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -16,37 +16,40 @@ * along with this program. If not, see . */ +#include "linphone/chat.h" +#include "linphone/wrapper_utils.h" - #include "linphone/chat.h" - #include "linphone/wrapper_utils.h" - #include "private.h" - - #include "c-wrapper/c-tools.h" - #include "chat/chat-message.h" - #include "chat/chat-message-p.h" - - using namespace std; - - #define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, ChatMessage, ChatMessage) - #define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, ChatMessage, ChatMessage) +// TODO: Remove me later. +#include "private.h" - /******************************************************************************* - * Reference and user data handling functions * - ******************************************************************************/ +#include "c-wrapper/c-tools.h" +#include "chat/chat-message.h" +#include "chat/chat-message-p.h" -LinphoneChatMessage *linphone_chat_message_ref(LinphoneChatMessage *msg) { +// ============================================================================= + +#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, ChatMessage, ChatMessage) +#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, ChatMessage, ChatMessage) + +using namespace std; + +// ============================================================================= +// Reference and user data handling functions. +// ============================================================================= + +LinphoneChatMessage *linphone_chat_message_ref (LinphoneChatMessage *msg) { belle_sip_object_ref(msg); return msg; } -void linphone_chat_message_unref(LinphoneChatMessage *msg) { +void linphone_chat_message_unref (LinphoneChatMessage *msg) { belle_sip_object_unref(msg); } -void * linphone_chat_message_get_user_data(const LinphoneChatMessage *msg) { +void * linphone_chat_message_get_user_data (const LinphoneChatMessage *msg) { return L_GET_USER_DATA_FROM_C_STRUCT(msg, ChatMessage, ChatMessage); } -void linphone_chat_message_set_user_data(LinphoneChatMessage *msg, void *ud) { +void linphone_chat_message_set_user_data (LinphoneChatMessage *msg, void *ud) { L_SET_USER_DATA_FROM_C_STRUCT(msg, ud, ChatMessage, ChatMessage); -} \ No newline at end of file +} diff --git a/src/c-wrapper/api/c-chat-room-cbs.cpp b/src/c-wrapper/api/c-chat-room-cbs.cpp index 2e1dd09e2..04adfabee 100644 --- a/src/c-wrapper/api/c-chat-room-cbs.cpp +++ b/src/c-wrapper/api/c-chat-room-cbs.cpp @@ -16,10 +16,12 @@ * along with this program. If not, see . */ - #include "linphone/api/c-chat-room-cbs.h" + +// TODO: Remove me later. #include "private.h" +// ============================================================================= struct _LinphoneChatRoomCbs { belle_sip_object_t base; @@ -41,6 +43,8 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneChatRoomCbs, belle_sip_object_t, FALSE ); +// ============================================================================= + LinphoneChatRoomCbs * linphone_chat_room_cbs_new (void) { return belle_sip_object_new(LinphoneChatRoomCbs); } diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index ffe36c6cc..41822299f 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -16,41 +16,43 @@ * along with this program. If not, see . */ - #include "linphone/chat.h" #include "linphone/wrapper_utils.h" + +// TODO: Remove me later. #include "private.h" #include "c-wrapper/c-tools.h" #include "chat/basic-chat-room.h" -#include "chat/chat-room.h" #include "chat/chat-room-p.h" +#include "chat/chat-room.h" #include "chat/client-group-chat-room.h" -#include "chat/real-time-text-chat-room.h" #include "chat/real-time-text-chat-room-p.h" +#include "chat/real-time-text-chat-room.h" -using namespace std; +// ============================================================================= #define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, ChatRoom, ChatRoom) #define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, ChatRoom, ChatRoom) +using namespace std; -extern LinphoneParticipant * _linphone_participant_init(); +extern LinphoneParticipant *_linphone_participant_init (); -static void _linphone_chat_room_constructor(LinphoneChatRoom *cr); -static void _linphone_chat_room_destructor(LinphoneChatRoom *cr); +static void _linphone_chat_room_constructor (LinphoneChatRoom *cr); +static void _linphone_chat_room_destructor (LinphoneChatRoom *cr); L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(ChatRoom, ChatRoom, chat_room, _linphone_chat_room_constructor, _linphone_chat_room_destructor, - LinphoneChatRoomCbs *cbs; + LinphoneChatRoomCbs * cbs; LinphoneAddress *peerAddressCache; ) -static void _linphone_chat_room_constructor(LinphoneChatRoom *cr) { +static void _linphone_chat_room_constructor (LinphoneChatRoom *cr) { cr->cbs = linphone_chat_room_cbs_new(); } -static void _linphone_chat_room_destructor(LinphoneChatRoom *cr) { +static void _linphone_chat_room_destructor (LinphoneChatRoom *cr) { linphone_chat_room_cbs_unref(cr->cbs); cr->cbs = nullptr; if (cr->peerAddressCache) { @@ -59,36 +61,35 @@ static void _linphone_chat_room_destructor(LinphoneChatRoom *cr) { } } +// ============================================================================= +// Public functions. +// ============================================================================= -/******************************************************************************* - * Public functions * - ******************************************************************************/ - -void linphone_chat_room_release(LinphoneChatRoom *cr) { +void linphone_chat_room_release (LinphoneChatRoom *cr) { GET_CPP_PRIVATE_PTR(cr)->release(); } -void linphone_chat_room_remove_transient_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { +void linphone_chat_room_remove_transient_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) { GET_CPP_PRIVATE_PTR(cr)->removeTransientMessage(msg); } -void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg) { +void linphone_chat_room_send_message (LinphoneChatRoom *cr, const char *msg) { GET_CPP_PTR(cr)->sendMessage(GET_CPP_PTR(cr)->createMessage(msg)); } -bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr) { +bool_t linphone_chat_room_is_remote_composing (const LinphoneChatRoom *cr) { return GET_CPP_PTR(cr)->isRemoteComposing(); } -LinphoneCore *linphone_chat_room_get_lc(const LinphoneChatRoom *cr) { +LinphoneCore *linphone_chat_room_get_lc (const LinphoneChatRoom *cr) { return linphone_chat_room_get_core(cr); } -LinphoneCore *linphone_chat_room_get_core(const LinphoneChatRoom *cr) { +LinphoneCore *linphone_chat_room_get_core (const LinphoneChatRoom *cr) { return GET_CPP_PTR(cr)->getCore(); } -const LinphoneAddress *linphone_chat_room_get_peer_address(LinphoneChatRoom *cr) { +const LinphoneAddress *linphone_chat_room_get_peer_address (LinphoneChatRoom *cr) { if (cr->peerAddressCache) { linphone_address_unref(cr->peerAddressCache); } @@ -96,13 +97,19 @@ const LinphoneAddress *linphone_chat_room_get_peer_address(LinphoneChatRoom *cr) return cr->peerAddressCache; } -LinphoneChatMessage *linphone_chat_room_create_message(LinphoneChatRoom *cr, const char *message) { +LinphoneChatMessage *linphone_chat_room_create_message (LinphoneChatRoom *cr, const char *message) { return GET_CPP_PTR(cr)->createMessage(message ? message : ""); } -LinphoneChatMessage *linphone_chat_room_create_message_2(LinphoneChatRoom *cr, const char *message, - const char *external_body_url, LinphoneChatMessageState state, - time_t time, bool_t is_read, bool_t is_incoming) { +LinphoneChatMessage *linphone_chat_room_create_message_2 ( + LinphoneChatRoom *cr, + const char *message, + const char *external_body_url, + LinphoneChatMessageState state, + time_t time, + bool_t is_read, + bool_t is_incoming +) { LinphoneChatMessage *msg = linphone_chat_room_create_message(cr, message); LinphoneCore *lc = linphone_chat_room_get_core(cr); msg->external_body_url = external_body_url ? ms_strdup(external_body_url) : NULL; @@ -116,91 +123,95 @@ LinphoneChatMessage *linphone_chat_room_create_message_2(LinphoneChatRoom *cr, c } else { msg->dir = LinphoneChatMessageOutgoing; linphone_chat_message_set_to(msg, linphone_chat_room_get_peer_address(cr)); - msg->from = linphone_address_new(linphone_core_get_identity(lc));/*direct assignment*/ + msg->from = linphone_address_new(linphone_core_get_identity(lc)); /*direct assignment*/ } return msg; } -void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage *msg, - LinphoneChatMessageStateChangedCb status_cb, void *ud) { +void linphone_chat_room_send_message2 ( + LinphoneChatRoom *cr, + LinphoneChatMessage *msg, + LinphoneChatMessageStateChangedCb status_cb, + void *ud +) { msg->message_state_changed_cb = status_cb; msg->message_state_changed_user_data = ud; GET_CPP_PTR(cr)->sendMessage(msg); } -void linphone_chat_room_send_chat_message_2(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { +void linphone_chat_room_send_chat_message_2 (LinphoneChatRoom *cr, LinphoneChatMessage *msg) { linphone_chat_message_ref(msg); GET_CPP_PTR(cr)->sendMessage(msg); } -void linphone_chat_room_send_chat_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { +void linphone_chat_room_send_chat_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) { GET_CPP_PTR(cr)->sendMessage(msg); } -uint32_t linphone_chat_room_get_char(const LinphoneChatRoom *cr) { +uint32_t linphone_chat_room_get_char (const LinphoneChatRoom *cr) { if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) return static_cast(GET_CPP_PTR(cr).get())->getChar(); return 0; } -void linphone_chat_room_compose(LinphoneChatRoom *cr) { +void linphone_chat_room_compose (LinphoneChatRoom *cr) { GET_CPP_PTR(cr)->compose(); } -LinphoneCall *linphone_chat_room_get_call(const LinphoneChatRoom *cr) { +LinphoneCall *linphone_chat_room_get_call (const LinphoneChatRoom *cr) { if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) return static_cast(GET_CPP_PTR(cr).get())->getCall(); return nullptr; } -void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call) { +void linphone_chat_room_set_call (LinphoneChatRoom *cr, LinphoneCall *call) { if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) static_cast(GET_CPP_PRIVATE_PTR(cr))->setCall(call); } -bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr) { +bctbx_list_t *linphone_chat_room_get_transient_messages (const LinphoneChatRoom *cr) { return L_GET_C_LIST_FROM_CPP_LIST(GET_CPP_PRIVATE_PTR(cr)->getTransientMessages(), LinphoneChatMessage); } -void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr) { +void linphone_chat_room_mark_as_read (LinphoneChatRoom *cr) { GET_CPP_PTR(cr)->markAsRead(); } -int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr) { +int linphone_chat_room_get_unread_messages_count (LinphoneChatRoom *cr) { return GET_CPP_PTR(cr)->getUnreadMessagesCount(); } -int linphone_chat_room_get_history_size(LinphoneChatRoom *cr) { +int linphone_chat_room_get_history_size (LinphoneChatRoom *cr) { return GET_CPP_PTR(cr)->getHistorySize(); } -void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { +void linphone_chat_room_delete_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) { GET_CPP_PTR(cr)->deleteMessage(msg); } -void linphone_chat_room_delete_history(LinphoneChatRoom *cr) { +void linphone_chat_room_delete_history (LinphoneChatRoom *cr) { GET_CPP_PTR(cr)->deleteHistory(); } -bctbx_list_t *linphone_chat_room_get_history_range(LinphoneChatRoom *cr, int startm, int endm) { +bctbx_list_t *linphone_chat_room_get_history_range (LinphoneChatRoom *cr, int startm, int endm) { return L_GET_C_LIST_FROM_CPP_LIST(GET_CPP_PTR(cr)->getHistoryRange(startm, endm), LinphoneChatMessage); } -bctbx_list_t *linphone_chat_room_get_history(LinphoneChatRoom *cr, int nb_message) { +bctbx_list_t *linphone_chat_room_get_history (LinphoneChatRoom *cr, int nb_message) { return L_GET_C_LIST_FROM_CPP_LIST(GET_CPP_PTR(cr)->getHistory(nb_message), LinphoneChatMessage); } -LinphoneChatMessage * linphone_chat_room_find_message(LinphoneChatRoom *cr, const char *message_id) { +LinphoneChatMessage *linphone_chat_room_find_message (LinphoneChatRoom *cr, const char *message_id) { return GET_CPP_PTR(cr)->findMessage(message_id); } -LinphoneChatRoomCbs * linphone_chat_room_get_callbacks (const LinphoneChatRoom *cr) { +LinphoneChatRoomCbs *linphone_chat_room_get_callbacks (const LinphoneChatRoom *cr) { return cr->cbs; } -LinphoneParticipant * linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr) { +LinphoneParticipant *linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr) { return L_GET_C_BACK_PTR(GET_CPP_PTR(cr)->addParticipant( - *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address, Address), nullptr, false), + *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address, Address), nullptr, false), Participant, participant); } @@ -212,7 +223,7 @@ bool_t linphone_chat_room_can_handle_participants (const LinphoneChatRoom *cr) { return GET_CPP_PTR(cr)->canHandleParticipants(); } -const char * linphone_chat_room_get_id (const LinphoneChatRoom *cr) { +const char *linphone_chat_room_get_id (const LinphoneChatRoom *cr) { string id = GET_CPP_PTR(cr)->getId(); return id.empty() ? nullptr : id.c_str(); } @@ -221,7 +232,7 @@ int linphone_chat_room_get_nb_participants (const LinphoneChatRoom *cr) { return GET_CPP_PTR(cr)->getNbParticipants(); } -bctbx_list_t * linphone_chat_room_get_participants (const LinphoneChatRoom *cr) { +bctbx_list_t *linphone_chat_room_get_participants (const LinphoneChatRoom *cr) { return L_GET_C_LIST_OF_STRUCT_PTR_FROM_CPP_LIST_OF_CPP_OBJ(GET_CPP_PTR(cr)->getParticipants(), Participant, Participant, participant); } @@ -233,34 +244,32 @@ void linphone_chat_room_remove_participants (LinphoneChatRoom *cr, const bctbx_l GET_CPP_PTR(cr)->removeParticipants(L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(participants, Participant, Participant)); } +// ============================================================================= +// Reference and user data handling functions. +// ============================================================================= -/******************************************************************************* - * Reference and user data handling functions * - ******************************************************************************/ - -LinphoneChatRoom *linphone_chat_room_ref(LinphoneChatRoom *cr) { +LinphoneChatRoom *linphone_chat_room_ref (LinphoneChatRoom *cr) { belle_sip_object_ref(cr); return cr; } -void linphone_chat_room_unref(LinphoneChatRoom *cr) { +void linphone_chat_room_unref (LinphoneChatRoom *cr) { belle_sip_object_unref(cr); } -void * linphone_chat_room_get_user_data(const LinphoneChatRoom *cr) { +void *linphone_chat_room_get_user_data (const LinphoneChatRoom *cr) { return L_GET_USER_DATA_FROM_C_STRUCT(cr, ChatRoom, ChatRoom); } -void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void *ud) { +void linphone_chat_room_set_user_data (LinphoneChatRoom *cr, void *ud) { L_SET_USER_DATA_FROM_C_STRUCT(cr, ud, ChatRoom, ChatRoom); } +// ============================================================================= +// Constructor and destructor functions. +// ============================================================================= -/******************************************************************************* - * Constructor and destructor functions * - ******************************************************************************/ - -LinphoneChatRoom * linphone_chat_room_new(LinphoneCore *core, const LinphoneAddress *addr) { +LinphoneChatRoom *linphone_chat_room_new (LinphoneCore *core, const LinphoneAddress *addr) { LinphoneChatRoom *cr = _linphone_chat_room_init(); if (linphone_core_realtime_text_enabled(core)) L_SET_CPP_PTR_FROM_C_STRUCT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address, Address))); @@ -272,7 +281,7 @@ LinphoneChatRoom * linphone_chat_room_new(LinphoneCore *core, const LinphoneAddr return cr; } -LinphoneChatRoom * linphone_client_group_chat_room_new(LinphoneCore *core, const bctbx_list_t *addresses) { +LinphoneChatRoom *linphone_client_group_chat_room_new (LinphoneCore *core, const bctbx_list_t *addresses) { const char *factoryUri = linphone_core_get_chat_conference_factory_uri(core); if (!factoryUri) return nullptr; @@ -295,6 +304,6 @@ LinphoneChatRoom * linphone_client_group_chat_room_new(LinphoneCore *core, const } /* DEPRECATED */ -void linphone_chat_room_destroy(LinphoneChatRoom *cr) { +void linphone_chat_room_destroy (LinphoneChatRoom *cr) { linphone_chat_room_unref(cr); } diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 6cb14499c..8c021be21 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -19,7 +19,6 @@ #include "linphone/api/c-event-log.h" #include "c-wrapper/c-tools.h" - #include "event-log/call-event.h" #include "event-log/conference-participant-event.h" #include "event-log/message-event.h" diff --git a/src/c-wrapper/api/c-participant.cpp b/src/c-wrapper/api/c-participant.cpp index d4d787183..e91677e18 100644 --- a/src/c-wrapper/api/c-participant.cpp +++ b/src/c-wrapper/api/c-participant.cpp @@ -19,7 +19,6 @@ #include "linphone/api/c-participant.h" #include "c-wrapper/c-tools.h" - #include "conference/participant.h" // ============================================================================= @@ -39,7 +38,7 @@ void linphone_participant_unref (LinphoneParticipant *participant) { belle_sip_object_unref(participant); } -void * linphone_participant_get_user_data(const LinphoneParticipant *participant) { +void *linphone_participant_get_user_data(const LinphoneParticipant *participant) { return L_GET_USER_DATA_FROM_C_STRUCT(participant, Participant, Participant); } @@ -47,7 +46,7 @@ void linphone_participant_set_user_data(LinphoneParticipant *participant, void * L_SET_USER_DATA_FROM_C_STRUCT(participant, ud, Participant, Participant); } -const LinphoneAddress * linphone_participant_get_address (const LinphoneParticipant *participant) { +const LinphoneAddress *linphone_participant_get_address (const LinphoneParticipant *participant) { LinphonePrivate::Address addr = L_GET_CPP_PTR_FROM_C_STRUCT(participant, Participant, Participant)->getAddress(); if (participant->addressCache) linphone_address_unref(participant->addressCache); diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index 1197e201a..1ec204c15 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -22,11 +22,11 @@ #include #include -#include "variant/variant.h" - -// From coreapi. +// TODO: From coreapi. Remove me later. #include "private.h" +#include "variant/variant.h" + // ============================================================================= LINPHONE_BEGIN_NAMESPACE From ceec68bc7af40360b8f60fa4f677fdf462f3bab5 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 19 Sep 2017 12:31:17 +0200 Subject: [PATCH 0090/2215] Fixed XSD compil & link issues --- cmake/FindLibXsd.cmake | 57 ++++++++++++++++++++++++++ console/CMakeLists.txt | 4 +- coreapi/help/examples/C/CMakeLists.txt | 2 +- daemon/CMakeLists.txt | 2 +- include/linphone/api/c-chat-message.h | 28 ++++++------- src/CMakeLists.txt | 27 ++++++++++-- tester/CMakeLists.txt | 2 +- tools/CMakeLists.txt | 10 ++--- 8 files changed, 105 insertions(+), 27 deletions(-) create mode 100644 cmake/FindLibXsd.cmake diff --git a/cmake/FindLibXsd.cmake b/cmake/FindLibXsd.cmake new file mode 100644 index 000000000..7775dbc4a --- /dev/null +++ b/cmake/FindLibXsd.cmake @@ -0,0 +1,57 @@ +############################################################################ +# FindLibXsd.cmake +# Copyright (C) 2017 Belledonne Communications, Grenoble France +# +############################################################################ +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +############################################################################ +# +# - Find the libxsd library +# +# XSD_FOUND - system has libxsd +# XSD_LIBRARIES - The libraries needed to use libxsd + +if(APPLE) +set(XSDCXX_DEFAULT_ROOT_PATH "/usr/local") +else () +set(XSDCXX_DEFAULT_ROOT_PATH "/usr") +endif() + +set(XSDCXX_ROOT_PATH ${XSDCXX_DEFAULT_ROOT_PATH} CACHE STRING "Path of where the bin/xsdcxx executable will be found. Comes from http://www.codesynthesis.com/products/xsd/download.xhtml. On mac use 'brew install xsd'") + +find_program(XSDCXX_PROG NAMES "xsdcxx" "xsd" + HINTS ${XSDCXX_ROOT_PATH}/bin +) +if(XSDCXX_PROG) + set(XSD_FOUND 1) + message(STATUS "XSD found at ${XSDCXX_PROG}, enabling XSD") + # TODO: check XSD is the correct executable + find_library(XERCES_LIBS NAMES xerces-c) + if(NOT XERCES_LIBS) + message(FATAL_ERROR "Failed to find the Xerces library.") + endif() + find_path(XERCES_INCLUDE_DIRS NAMES xercesc/util/XercesDefs.hpp) + if(NOT XERCES_INCLUDE_DIRS) + message(FATAL_ERROR "Failed to find the Xerces includes.") + endif() + set(XSD_LIBRARIES ${XERCES_LIBS}) +else() + set(XSD_FOUND 0) + message(STATUS "Program 'xsdcxx' could not be found in ${XSDCXX_ROOT_PATH}/bin, disabling XSD features") +endif() + +mark_as_advanced(XSD_FOUND) diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index a23ad6cba..1e4de5e1d 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -37,7 +37,7 @@ if(MSVC) endif() add_executable(linphonec ${LINPHONEC_SOURCE_FILES}) -target_link_libraries(linphonec ${LINPHONE_LIBS_FOR_TOOLS} ${BCTOOLBOX_CORE_LIBRARIES} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES}) +target_link_libraries(linphonec ${LINPHONE_LIBS_FOR_TOOLS} ${BCTOOLBOX_CORE_LIBRARIES} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES} ${XSD_LIBRARIES}) set_target_properties(linphonec PROPERTIES LINK_FLAGS "${LINPHONE_LDFLAGS}") if(INTL_FOUND) @@ -46,7 +46,7 @@ endif() if(WIN32) add_executable(linphoned WIN32 ${LINPHONEC_SOURCE_FILES}) - target_link_libraries(linphoned ${LINPHONE_LIBS_FOR_TOOLS} ${BCTOOLBOX_CORE_LIBRARIES} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES}) + target_link_libraries(linphoned ${LINPHONE_LIBS_FOR_TOOLS} ${BCTOOLBOX_CORE_LIBRARIES} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES} ${XSD_LIBRARIES}) if(INTL_FOUND) target_link_libraries(linphoned ${INTL_LIBRARIES}) endif() diff --git a/coreapi/help/examples/C/CMakeLists.txt b/coreapi/help/examples/C/CMakeLists.txt index 84a5b38d5..e89cde8db 100644 --- a/coreapi/help/examples/C/CMakeLists.txt +++ b/coreapi/help/examples/C/CMakeLists.txt @@ -29,7 +29,7 @@ if (ENABLE_TOOLS) string(REPLACE ".c" "" EXECUTABLE_NAME ${EXECUTABLE}) bc_apply_compile_flags(${EXECUTABLE} STRICT_OPTIONS_CPP STRICT_OPTIONS_C) add_executable(${EXECUTABLE_NAME} ${USE_BUNDLE} ${EXECUTABLE}) - target_link_libraries(${EXECUTABLE_NAME} ${LINPHONE_LIBS_FOR_TOOLS} ${MEDIASTREAMER2_LIBRARIES} ${ORTP_LIBRARIES} ${BCTOOLBOX_CORE_LIBRARIES}) + target_link_libraries(${EXECUTABLE_NAME} ${LINPHONE_LIBS_FOR_TOOLS} ${MEDIASTREAMER2_LIBRARIES} ${ORTP_LIBRARIES} ${BCTOOLBOX_CORE_LIBRARIES} ${XSD_LIBRARIES}) set_target_properties(${EXECUTABLE_NAME} PROPERTIES LINK_FLAGS "${LINPHONE_LDFLAGS}") if (NOT IOS) install(TARGETS ${EXECUTABLE_NAME} diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 61178d119..c50915234 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -115,7 +115,7 @@ bc_apply_compile_flags(DAEMON_PIPETEST_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OP add_executable(linphone-daemon ${DAEMON_SOURCE_FILES}) target_include_directories(linphone-daemon PRIVATE ${CMAKE_CURRENT_LIST_DIR}) -target_link_libraries(linphone-daemon ${LINPHONE_LIBS_FOR_TOOLS} ${MEDIASTREAMER2_LIBRARIES} ${ORTP_LIBRARIES} ${BCTOOLBOX_CORE_LIBRARIES}) +target_link_libraries(linphone-daemon ${LINPHONE_LIBS_FOR_TOOLS} ${MEDIASTREAMER2_LIBRARIES} ${ORTP_LIBRARIES} ${BCTOOLBOX_CORE_LIBRARIES} ${XSD_LIBRARIES}) set_target_properties(linphone-daemon PROPERTIES LINK_FLAGS "${LINPHONE_LDFLAGS}") add_executable(linphone-daemon-pipetest ${DAEMON_PIPETEST_SOURCE_FILES}) diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index bced0fb36..f6979295e 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -16,21 +16,21 @@ * along with this program. If not, see . */ - #ifndef _C_CHAT_MESSAGE_H_ - #define _C_CHAT_MESSAGE_H_ +#ifndef _C_CHAT_MESSAGE_H_ +#define _C_CHAT_MESSAGE_H_ - #include "linphone/api/c-types.h" +#include "linphone/api/c-types.h" - // ============================================================================= +// ============================================================================= - #ifdef __cplusplus - extern "C" { - #endif // ifdef __cplusplus +#ifdef __cplusplus + extern "C" { +#endif // ifdef __cplusplus - /** - * @addtogroup chatmessage - * @{ - */ +/** + * @addtogroup chatmessage + * @{ + */ /** * Acquire a reference to the chat message. @@ -59,9 +59,9 @@ LINPHONE_PUBLIC void *linphone_chat_message_get_user_data(const LinphoneChatMess **/ LINPHONE_PUBLIC void linphone_chat_message_set_user_data(LinphoneChatMessage *msg, void *ud); - /** - * @} - */ +/** + * @} + */ #ifdef __cplusplus } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4cbec9c3b..0703ce488 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -160,9 +160,30 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES xml/xml.cpp ) -ADD_XSD_WRAPPERS(xml/xml "XML XSD - xml.xsd") -ADD_XSD_WRAPPERS(xml/conference-info "Conference info XSD - conference-info.xsd") -ADD_XSD_WRAPPERS(xml/resource-lists "Resourece lists XSD - resource-lists.xsd") +function(ADD_XSD_WRAPPERS file _comment) + set(destinations ${CMAKE_CURRENT_BINARY_DIR}/xml/${file}.hxx ${CMAKE_CURRENT_BINARY_DIR}/xml/${file}.cxx) + set(source ${CMAKE_CURRENT_LIST_DIR}/xml/${file}.xsd) + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/xml") + + set(regex "%http://.+/(.+)%\\\$$1%") + + add_custom_command(OUTPUT ${destinations} + COMMAND "${XSDCXX_PROG}" "cxx-tree" "--generate-wildcard" + "--generate-serialization" "--generate-ostream" + "--generate-detach" "--std" "c++11" "--type-naming" "java" + "--function-naming" "java" "--location-regex-trace" "--show-sloc" + "--location-regex" "\"${regex}\"" + "--output-dir" "${CMAKE_CURRENT_BINARY_DIR}/xml" "${source}" + COMMENT "${_comment}") + + add_custom_target(${file} DEPENDS ${destinations} SOURCES ${source}) + + set_source_files_properties(${destinations} PROPERTIES GENERATED ON) + set(FLEXISIP_SOURCES ${FLEXISIP_SOURCES} ${destinations} PARENT_SCOPE) +endfunction() +ADD_XSD_WRAPPERS(xml "XML XSD - xml.xsd") +ADD_XSD_WRAPPERS(conference-info "Conference info XSD - conference-info.xsd") +ADD_XSD_WRAPPERS(resource-lists "Resourece lists XSD - resource-lists.xsd") set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS} ${LIBXSD_INCLUDE_DIRS}) set(LINPHONE_CXX_OBJECTS_DEFINITIONS "-DLIBLINPHONE_EXPORTS") diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index d9730363d..1b71c03db 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -20,7 +20,7 @@ # ############################################################################ -set(OTHER_LIBS_FOR_TESTER ${BCTOOLBOX_LIBRARIES} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES} ${BELLESIP_LIBRARIES} ${XML2_LIBRARIES}) +set(OTHER_LIBS_FOR_TESTER ${BCTOOLBOX_LIBRARIES} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES} ${BELLESIP_LIBRARIES} ${XML2_LIBRARIES} ${XSD_LIBRARIES}) if(INTL_FOUND) list(APPEND OTHER_LIBS_FOR_TESTER ${INTL_LIBRARIES}) endif() diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index fdc797c02..3c66c9cf2 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -33,31 +33,31 @@ endif() set(LP_AUTO_ANSWER_SOURCE_FILES auto_answer.c) bc_apply_compile_flags(LP_AUTO_ANSWER_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_C) add_executable(lp-auto-answer ${USE_BUNDLE} ${LP_AUTO_ANSWER_SOURCE_FILES}) -target_link_libraries(lp-auto-answer ${LINPHONE_LIBS_FOR_TOOLS} ${MEDIASTREAMER2_LIBRARIES} ${ORTP_LIBRARIES} ${BCTOOLBOX_CORE_LIBRARIES}) +target_link_libraries(lp-auto-answer ${LINPHONE_LIBS_FOR_TOOLS} ${MEDIASTREAMER2_LIBRARIES} ${ORTP_LIBRARIES} ${BCTOOLBOX_CORE_LIBRARIES} ${XSD_LIBRARIES}) set_target_properties(lp-auto-answer PROPERTIES LINK_FLAGS "${LINPHONE_LDFLAGS}") set(LP_SENDMSG_SOURCE_FILES lpsendmsg.c) bc_apply_compile_flags(LP_SENDMSG_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_C) add_executable(lp-sendmsg ${USE_BUNDLE} ${LP_SENDMSG_SOURCE_FILES}) -target_link_libraries(lp-sendmsg ${LINPHONE_LIBS_FOR_TOOLS} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES}) +target_link_libraries(lp-sendmsg ${LINPHONE_LIBS_FOR_TOOLS} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES} ${XSD_LIBRARIES}) set_target_properties(lp-sendmsg PROPERTIES LINK_FLAGS "${LINPHONE_LDFLAGS}") set(LP_LPC2XML_TEST_SOURCE_FILES lpc2xml_test.c) bc_apply_compile_flags(LP_LPC2XML_TEST_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_C) add_executable(lpc2xml_test ${USE_BUNDLE} ${LP_LPC2XML_TEST_SOURCE_FILES}) -target_link_libraries(lpc2xml_test ${LINPHONE_LIBS_FOR_TOOLS} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES}) +target_link_libraries(lpc2xml_test ${LINPHONE_LIBS_FOR_TOOLS} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES} ${XSD_LIBRARIES}) set_target_properties(lpc2xml_test PROPERTIES LINK_FLAGS "${LINPHONE_LDFLAGS}") set(LP_XML2LPC_TEST_SOURCE_FILES xml2lpc_test.c) bc_apply_compile_flags(LP_XML2LPC_TEST_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_C) add_executable(xml2lpc_test ${USE_BUNDLE} ${LP_XML2LPC_TEST_SOURCE_FILES}) -target_link_libraries(xml2lpc_test ${LINPHONE_LIBS_FOR_TOOLS} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES}) +target_link_libraries(xml2lpc_test ${LINPHONE_LIBS_FOR_TOOLS} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES} ${XSD_LIBRARIES}) set_target_properties(xml2lpc_test PROPERTIES LINK_FLAGS "${LINPHONE_LDFLAGS}") set(LP_TEST_ECC_SOURCE_FILES test_ecc.c) bc_apply_compile_flags(LP_TEST_ECC_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_C) add_executable(lp-test-ecc ${USE_BUNDLE} ${LP_TEST_ECC_SOURCE_FILES}) -target_link_libraries(lp-test-ecc ${LINPHONE_LIBS_FOR_TOOLS} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES} ${BCTOOLBOX_CORE_LIBRARIES}) +target_link_libraries(lp-test-ecc ${LINPHONE_LIBS_FOR_TOOLS} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES} ${BCTOOLBOX_CORE_LIBRARIES} ${XSD_LIBRARIES}) set_target_properties(lp-test-ecc PROPERTIES LINK_FLAGS "${LINPHONE_LDFLAGS}") if (NOT IOS) From 53b9758d7a8b99fd2b98d392064053b4b639e3fe Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 19 Sep 2017 14:50:09 +0200 Subject: [PATCH 0091/2215] Handle conference listener in client group chat room and wrap participant manipulation callbacks in LinphoneChatRoomCbs. --- include/linphone/api/c-callbacks.h | 22 +++++++ include/linphone/api/c-chat-room-cbs.h | 42 ++++++++++++++ src/c-wrapper/api/c-chat-room-cbs.cpp | 27 +++++++++ src/c-wrapper/api/c-chat-room.cpp | 2 +- src/chat/client-group-chat-room.cpp | 57 +++++++++++++++++++ src/chat/client-group-chat-room.h | 8 +++ src/conference/conference.cpp | 17 +++--- .../local-conference-event-handler.cpp | 12 +++- src/conference/local-conference.cpp | 33 ++--------- src/conference/local-conference.h | 6 -- src/conference/participant.cpp | 6 ++ src/conference/participant.h | 4 +- .../remote-conference-event-handler.cpp | 21 +++++-- .../remote-conference-event-handler.h | 3 +- src/conference/remote-conference.cpp | 42 +++++++++++++- src/conference/remote-conference.h | 18 +++++- tester/conference-event-tester.cpp | 3 +- 17 files changed, 267 insertions(+), 56 deletions(-) diff --git a/include/linphone/api/c-callbacks.h b/include/linphone/api/c-callbacks.h index a1edf51ee..e1d9fd7c9 100644 --- a/include/linphone/api/c-callbacks.h +++ b/include/linphone/api/c-callbacks.h @@ -48,6 +48,28 @@ typedef void (*LinphoneChatRoomCbsIsComposingReceivedCb) (LinphoneChatRoom *cr, */ typedef void (*LinphoneChatRoomCbsMessageReceivedCb) (LinphoneChatRoom *cr, LinphoneChatMessage *msg); +/** + * Callback used to notify a chat room that a participant has been added. + * @param[in] cr #LinphoneChatRoom object + * @param[in] participant The #LinphoneParticipant that has been added to the chat room + */ +typedef void (*LinphoneChatRoomCbsParticipantAddedCb) (LinphoneChatRoom *cr, LinphoneParticipant *participant); + +/** + * Callback used to notify a chat room that a participant has been removed. + * @param[in] cr #LinphoneChatRoom object + * @param[in] participant The #LinphoneParticipant that has been removed from the chat room + */ +typedef void (*LinphoneChatRoomCbsParticipantRemovedCb) (LinphoneChatRoom *cr, LinphoneParticipant *participant); + +/** + * Callback used to notify a chat room that the admin status of a participant has been changed. + * @param[in] cr #LinphoneChatRoom object + * @param[in] participant The #LinphoneParticipant for which the admin status has been changed + * @param[in] isAdmin The new admin status of the participant + */ +typedef void (*LinphoneChatRoomCbsParticipantAdminStatusChangedCb) (LinphoneChatRoom *cr, LinphoneParticipant *participant, bool_t isAdmin); + /** * Callback used to notify a chat room state has changed. * @param[in] cr #LinphoneChatRoom object diff --git a/include/linphone/api/c-chat-room-cbs.h b/include/linphone/api/c-chat-room-cbs.h index 0c895cecc..aca42d1b2 100644 --- a/include/linphone/api/c-chat-room-cbs.h +++ b/include/linphone/api/c-chat-room-cbs.h @@ -88,6 +88,48 @@ LINPHONE_PUBLIC LinphoneChatRoomCbsMessageReceivedCb linphone_chat_room_cbs_get_ */ LINPHONE_PUBLIC void linphone_chat_room_cbs_set_message_received (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsMessageReceivedCb cb); +/** + * Get the participant added callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @return The current participant added callback. + */ +LINPHONE_PUBLIC LinphoneChatRoomCbsParticipantAddedCb linphone_chat_room_cbs_get_participant_added (const LinphoneChatRoomCbs *cbs); + +/** + * Set the participant added callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @param[in] cb The participant added callback to be used. + */ +LINPHONE_PUBLIC void linphone_chat_room_cbs_set_participant_added (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantAddedCb cb); + +/** + * Get the participant removed callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @return The current participant removed callback. + */ +LINPHONE_PUBLIC LinphoneChatRoomCbsParticipantRemovedCb linphone_chat_room_cbs_get_participant_removed (const LinphoneChatRoomCbs *cbs); + +/** + * Set the participant removed callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @param[in] cb The participant removed callback to be used. + */ +LINPHONE_PUBLIC void linphone_chat_room_cbs_set_participant_removed (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantRemovedCb cb); + +/** + * Get the participant admin status changed callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @return The current participant admin status changed callback. + */ +LINPHONE_PUBLIC LinphoneChatRoomCbsParticipantAdminStatusChangedCb linphone_chat_room_cbs_get_participant_admin_status_changed (const LinphoneChatRoomCbs *cbs); + +/** + * Set the participant admin status changed callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @param[in] cb The participant admin status changed callback to be used. + */ +LINPHONE_PUBLIC void linphone_chat_room_cbs_set_participant_admin_status_changed (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantAdminStatusChangedCb cb); + /** * Get the state changed callback. * @param[in] cbs LinphoneChatRoomCbs object. diff --git a/src/c-wrapper/api/c-chat-room-cbs.cpp b/src/c-wrapper/api/c-chat-room-cbs.cpp index 04adfabee..f83f5c5ea 100644 --- a/src/c-wrapper/api/c-chat-room-cbs.cpp +++ b/src/c-wrapper/api/c-chat-room-cbs.cpp @@ -28,6 +28,9 @@ struct _LinphoneChatRoomCbs { void *userData; LinphoneChatRoomCbsIsComposingReceivedCb isComposingReceivedCb; LinphoneChatRoomCbsMessageReceivedCb messageReceivedCb; + LinphoneChatRoomCbsParticipantAddedCb participantAddedCb; + LinphoneChatRoomCbsParticipantRemovedCb participantRemovedCb; + LinphoneChatRoomCbsParticipantAdminStatusChangedCb participantAdminStatusChangedCb; LinphoneChatRoomCbsStateChangedCb stateChangedCb; LinphoneChatRoomCbsUndecryptableMessageReceivedCb undecryptableMessageReceivedCb; }; @@ -82,6 +85,30 @@ void linphone_chat_room_cbs_set_message_received (LinphoneChatRoomCbs *cbs, Linp cbs->messageReceivedCb = cb; } +LinphoneChatRoomCbsParticipantAddedCb linphone_chat_room_cbs_get_participant_added (const LinphoneChatRoomCbs *cbs) { + return cbs->participantAddedCb; +} + +void linphone_chat_room_cbs_set_participant_added (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantAddedCb cb) { + cbs->participantAddedCb = cb; +} + +LinphoneChatRoomCbsParticipantRemovedCb linphone_chat_room_cbs_get_participant_removed (const LinphoneChatRoomCbs *cbs) { + return cbs->participantRemovedCb; +} + +void linphone_chat_room_cbs_set_participant_removed (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantRemovedCb cb) { + cbs->participantRemovedCb = cb; +} + +LinphoneChatRoomCbsParticipantAdminStatusChangedCb linphone_chat_room_cbs_get_participant_admin_status_changed (const LinphoneChatRoomCbs *cbs) { + return cbs->participantAdminStatusChangedCb; +} + +void linphone_chat_room_cbs_set_participant_admin_status_changed (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantAdminStatusChangedCb cb) { + cbs->participantAdminStatusChangedCb = cb; +} + LinphoneChatRoomCbsStateChangedCb linphone_chat_room_cbs_get_state_changed (const LinphoneChatRoomCbs *cbs) { return cbs->stateChangedCb; } diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 41822299f..f7798f167 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -44,7 +44,7 @@ static void _linphone_chat_room_destructor (LinphoneChatRoom *cr); L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(ChatRoom, ChatRoom, chat_room, _linphone_chat_room_constructor, _linphone_chat_room_destructor, - LinphoneChatRoomCbs * cbs; + LinphoneChatRoomCbs *cbs; LinphoneAddress *peerAddressCache; ) diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 8878bc7f2..a267eaa57 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -17,11 +17,15 @@ */ #include "client-group-chat-room-p.h" +#include "c-wrapper/c-tools.h" #include "conference/participant-p.h" #include "logger/logger.h" // ============================================================================= +extern LinphoneChatRoom * _linphone_chat_room_init(); +extern LinphoneParticipant * _linphone_participant_init(); + using namespace std; LINPHONE_BEGIN_NAMESPACE @@ -79,4 +83,57 @@ void ClientGroupChatRoom::removeParticipants (const list // TODO } +// ----------------------------------------------------------------------------- + +void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { + // TODO +} + +void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { + // TODO +} + +void ClientGroupChatRoom::onParticipantAdded (const Address &addr) { + shared_ptr participant = findParticipant(addr); + if (participant) { + lWarning() << "Participant " << participant << " added but already in the list of participants!"; + return; + } + participant = make_shared(addr); + participants.push_back(participant); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this->shared_from_this(), ChatRoom, chat_room); + LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); + LinphoneChatRoomCbsParticipantAddedCb cb = linphone_chat_room_cbs_get_participant_added(cbs); + if (cb) + cb(cr, L_GET_C_BACK_PTR(participant, Participant, participant)); +} + +void ClientGroupChatRoom::onParticipantRemoved (const Address &addr) { + shared_ptr participant = findParticipant(addr); + if (!participant) { + lWarning() << "Participant " << participant << " removed but not in the list of participants!"; + return; + } + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this->shared_from_this(), ChatRoom, chat_room); + LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); + LinphoneChatRoomCbsParticipantRemovedCb cb = linphone_chat_room_cbs_get_participant_removed(cbs); + if (cb) + cb(cr, L_GET_C_BACK_PTR(participant, Participant, participant)); + participants.remove(participant); +} + +void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdmin) { + shared_ptr participant = findParticipant(addr); + if (!participant) { + lWarning() << "Participant " << participant << " admin status has been changed but is not in the list of participants!"; + return; + } + participant->setAdmin(isAdmin); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this->shared_from_this(), ChatRoom, chat_room); + LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); + LinphoneChatRoomCbsParticipantAdminStatusChangedCb cb = linphone_chat_room_cbs_get_participant_admin_status_changed(cbs); + if (cb) + cb(cr, L_GET_C_BACK_PTR(participant, Participant, participant), isAdmin); +} + LINPHONE_END_NAMESPACE diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index 04c4181e0..0101437cf 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -49,6 +49,14 @@ public: void removeParticipant (const std::shared_ptr &participant); void removeParticipants (const std::list> &participants); +private: + /* ConferenceListener */ + void onConferenceCreated (const Address &addr); + void onConferenceTerminated (const Address &addr); + void onParticipantAdded (const Address &addr); + void onParticipantRemoved (const Address &addr); + void onParticipantSetAdmin (const Address &addr, bool isAdmin); + private: L_DECLARE_PRIVATE(ClientGroupChatRoom); L_DISABLE_COPY(ClientGroupChatRoom); diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index a6d679421..ba165dbbc 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -19,6 +19,7 @@ #include "participant-p.h" #include "conference.h" +#include "logger/logger.h" using namespace std; @@ -40,13 +41,13 @@ shared_ptr Conference::getActiveParticipant () const { // ----------------------------------------------------------------------------- shared_ptr Conference::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { - activeParticipant = make_shared(addr); - activeParticipant->getPrivate()->createSession(*this, params, hasMedia, this); - return activeParticipant; + lError() << "Conference class does not handle addParticipant() generically"; + return nullptr; } void Conference::addParticipants (const list
&addresses, const CallSessionParams *params, bool hasMedia) { - // TODO + for (const auto &addr : addresses) + addParticipant(addr, params, hasMedia); } bool Conference::canHandleParticipants () const { @@ -58,8 +59,7 @@ const string& Conference::getId () const { } int Conference::getNbParticipants () const { - // TODO - return 1; + return participants.size(); } list> Conference::getParticipants () const { @@ -67,11 +67,12 @@ list> Conference::getParticipants () const { } void Conference::removeParticipant (const shared_ptr &participant) { - // TODO + lError() << "Conference class does not handle removeParticipant() generically"; } void Conference::removeParticipants (const list> &participants) { - // TODO + for (const auto &p : participants) + removeParticipant(p); } // ----------------------------------------------------------------------------- diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 73e579740..e5cae32ee 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -24,9 +24,10 @@ #include "private.h" +// ============================================================================= + using namespace std; using namespace conference_info; -using namespace LinphonePrivate; LINPHONE_BEGIN_NAMESPACE @@ -39,7 +40,7 @@ public: LocalConference *conf = nullptr; }; -LINPHONE_END_NAMESPACE +// ----------------------------------------------------------------------------- void LocalConferenceEventHandlerPrivate::notifyFullState(string notify, LinphoneEvent *lev) { LinphoneContent *content = linphone_core_create_content(lev->lc); @@ -64,7 +65,8 @@ void LocalConferenceEventHandlerPrivate::notifyAllExcept(string notify, const Ad } } -// -------- Conference::LocalConferenceEventHandler public methods --------- +// ============================================================================= + LocalConferenceEventHandler::LocalConferenceEventHandler(LinphoneCore *core, LocalConference *localConf) : Object(*new LocalConferenceEventHandlerPrivate) { L_D(LocalConferenceEventHandler); xercesc::XMLPlatformUtils::Initialize(); @@ -76,6 +78,8 @@ LocalConferenceEventHandler::~LocalConferenceEventHandler() { xercesc::XMLPlatformUtils::Terminate(); } +// ----------------------------------------------------------------------------- + string LocalConferenceEventHandler::subscribeReceived(LinphoneEvent *lev) { L_D(LocalConferenceEventHandler); string entity = d->conf->getMe()->getAddress().asStringUriOnly(); @@ -163,3 +167,5 @@ string LocalConferenceEventHandler::notifyParticipantSetAdmin(const Address &add //d->notifyAllExcept(notify.str(), addr); return notify.str(); } + +LINPHONE_END_NAMESPACE diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index 96ab857f6..401022812 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -20,7 +20,8 @@ #include "participant-p.h" using namespace std; -using namespace LinphonePrivate; + +LINPHONE_BEGIN_NAMESPACE // ============================================================================= @@ -42,32 +43,11 @@ shared_ptr LocalConference::addParticipant (const Address &addr, co participant = make_shared(addr); participant->getPrivate()->createSession(*this, params, hasMedia, this); participants.push_back(participant); - activeParticipant = participant; + if (!activeParticipant) + activeParticipant = participant; return participant; } -void LocalConference::addParticipants (const list
&addresses, const CallSessionParams *params, bool hasMedia) { - for (const auto &addr : addresses) - addParticipant(addr, params, hasMedia); -} - -bool LocalConference::canHandleParticipants () const { - return true; -} - -const string& LocalConference::getId () const { - return id; -} - -int LocalConference::getNbParticipants () const { - participants.size(); - return 1; -} - -list> LocalConference::getParticipants () const { - return participants; -} - void LocalConference::removeParticipant (const shared_ptr &participant) { for (const auto &p : participants) { if (participant->getAddress().equal(p->getAddress())) { @@ -77,7 +57,4 @@ void LocalConference::removeParticipant (const shared_ptr &pa } } -void LocalConference::removeParticipants (const list> &participants) { - for (const auto &p : participants) - removeParticipant(p); -} +LINPHONE_END_NAMESPACE diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h index 18394c5b8..55e3f761c 100644 --- a/src/conference/local-conference.h +++ b/src/conference/local-conference.h @@ -36,13 +36,7 @@ public: public: /* ConferenceInterface */ virtual std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia); - virtual void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia); - virtual bool canHandleParticipants () const; - virtual const std::string& getId () const; - virtual int getNbParticipants () const; - virtual std::list> getParticipants () const; virtual void removeParticipant (const std::shared_ptr &participant); - virtual void removeParticipants (const std::list> &participants); private: L_DISABLE_COPY(LocalConference); diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index 6bbfd4790..a7642b855 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -68,4 +68,10 @@ void Participant::setAdmin (bool isAdmin) { d->isAdmin = isAdmin; } +// ============================================================================= + +ostream & operator<< (ostream &strm, const shared_ptr &participant) { + return strm << "'" << participant->getAddress().asString() << "'"; +} + LINPHONE_END_NAMESPACE diff --git a/src/conference/participant.h b/src/conference/participant.h index 43891267d..0fbef9f00 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -35,9 +35,9 @@ class Participant : public Object { friend class Call; friend class CallPrivate; friend class ClientGroupChatRoom; - friend class Conference; friend class LocalConference; friend class MediaSessionPrivate; + friend class RemoteConference; public: Participant (const Address &addr); @@ -52,6 +52,8 @@ private: L_DISABLE_COPY(Participant); }; +std::ostream & operator<< (std::ostream &strm, const std::shared_ptr &participant); + LINPHONE_END_NAMESPACE #endif // ifndef _PARTICIPANT_H_ diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 23873ea9a..388a43a55 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -21,9 +21,10 @@ #include "private.h" #include "object/object-p.h" +// ============================================================================= + using namespace std; using namespace conference_info; -using namespace LinphonePrivate; LINPHONE_BEGIN_NAMESPACE @@ -36,15 +37,14 @@ public: LinphoneEvent *lev = nullptr; }; -LINPHONE_END_NAMESPACE +// ============================================================================= -// -------- RemoteConferenceEventHandler public methods --------- -RemoteConferenceEventHandler::RemoteConferenceEventHandler(LinphoneCore *core, ConferenceListener *listener, const Address &confAddr) : Object(*new RemoteConferenceEventHandlerPrivate) { +RemoteConferenceEventHandler::RemoteConferenceEventHandler(LinphoneCore *core, ConferenceListener *listener) + : Object(*new RemoteConferenceEventHandlerPrivate) { L_D(RemoteConferenceEventHandler); xercesc::XMLPlatformUtils::Initialize(); d->core = core; d->listener = listener; - d->confAddr = confAddr; } RemoteConferenceEventHandler::~RemoteConferenceEventHandler() { @@ -54,6 +54,8 @@ RemoteConferenceEventHandler::~RemoteConferenceEventHandler() { linphone_event_unref(d->lev); } +// ----------------------------------------------------------------------------- + void RemoteConferenceEventHandler::subscribe(string confId) { L_D(RemoteConferenceEventHandler); d->confId = confId; @@ -101,7 +103,16 @@ void RemoteConferenceEventHandler::notifyReceived(string xmlBody) { } } +// ----------------------------------------------------------------------------- + string RemoteConferenceEventHandler::getConfId() { L_D(RemoteConferenceEventHandler); return d->confId; } + +void RemoteConferenceEventHandler::setConferenceAddress (const Address &addr) { + L_D(RemoteConferenceEventHandler); + d->confAddr = addr; +} + +LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference-event-handler.h b/src/conference/remote-conference-event-handler.h index ea6bf862a..6ea95adfd 100644 --- a/src/conference/remote-conference-event-handler.h +++ b/src/conference/remote-conference-event-handler.h @@ -32,7 +32,7 @@ class RemoteConferenceEventHandlerPrivate; class RemoteConferenceEventHandler : public Object { public: - RemoteConferenceEventHandler(LinphoneCore *core, ConferenceListener *listener, const Address &confAddr); + RemoteConferenceEventHandler(LinphoneCore *core, ConferenceListener *listener); ~RemoteConferenceEventHandler(); void subscribe(std::string confId); @@ -40,6 +40,7 @@ class RemoteConferenceEventHandler : public Object { void unsubscribe(); std::string getConfId(); + void setConferenceAddress (const Address &addr); private: L_DECLARE_PRIVATE(RemoteConferenceEventHandler); diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index 537b79acc..0136a29cd 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -17,12 +17,52 @@ */ #include "remote-conference.h" +#include "participant-p.h" + +using namespace std; LINPHONE_BEGIN_NAMESPACE // ============================================================================= RemoteConference::RemoteConference (LinphoneCore *core, const Address &myAddress, CallListener *listener) - : Conference(core, myAddress, listener) {} + : Conference(core, myAddress, listener) { + eventHandler = new RemoteConferenceEventHandler(core, this); +} + +// ----------------------------------------------------------------------------- + +shared_ptr RemoteConference::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { + shared_ptr participant = findParticipant(addr); + if (participant) + return participant; + participant = make_shared(addr); + participant->getPrivate()->createSession(*this, params, hasMedia, this); + participants.push_back(participant); + if (!activeParticipant) + activeParticipant = participant; + return participant; +} + +void RemoteConference::removeParticipant (const shared_ptr &participant) { + for (const auto &p : participants) { + if (participant->getAddress().equal(p->getAddress())) { + participants.remove(p); + return; + } + } +} + +// ----------------------------------------------------------------------------- + +void RemoteConference::onConferenceCreated (const Address &addr) {} + +void RemoteConference::onConferenceTerminated (const Address &addr) {} + +void RemoteConference::onParticipantAdded (const Address &addr) {} + +void RemoteConference::onParticipantRemoved (const Address &addr) {} + +void RemoteConference::onParticipantSetAdmin (const Address &addr, bool isAdmin) {} LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index be1aa8c51..c8cb28d6c 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -20,12 +20,13 @@ #define _REMOTE_CONFERENCE_H_ #include "conference.h" +#include "remote-conference-event-handler.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE -class RemoteConference : public Conference { +class RemoteConference : public Conference, public ConferenceListener { public: RemoteConference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); virtual ~RemoteConference() = default; @@ -33,8 +34,23 @@ public: protected: std::shared_ptr focus = nullptr; +public: + /* ConferenceInterface */ + virtual std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia); + virtual void removeParticipant (const std::shared_ptr &participant); + +protected: + /* ConferenceListener */ + virtual void onConferenceCreated (const Address &addr); + virtual void onConferenceTerminated (const Address &addr); + virtual void onParticipantAdded (const Address &addr); + virtual void onParticipantRemoved (const Address &addr); + virtual void onParticipantSetAdmin (const Address &addr, bool isAdmin); + private: L_DISABLE_COPY(RemoteConference); + + RemoteConferenceEventHandler *eventHandler = nullptr; }; LINPHONE_END_NAMESPACE diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index 0deb97164..9de93e4bb 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -437,7 +437,8 @@ public: }; ConferenceEventTester::ConferenceEventTester (LinphoneCore *core, const Address &confAddr) { - handler = new RemoteConferenceEventHandler(core, this, confAddr); + handler = new RemoteConferenceEventHandler(core, this); + handler->setConferenceAddress(confAddr); } ConferenceEventTester::~ConferenceEventTester () { From e5444986c92a4631d450fa5121cff7d3e2e5e5e5 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 19 Sep 2017 17:54:06 +0200 Subject: [PATCH 0092/2215] Correctly search for libxsd and use python script instead of CMake custom target to generate XSD code. --- cmake/FindLibXsd.cmake | 47 +++++++++++---------------- src/CMakeLists.txt | 25 -------------- src/xml/generate.py | 74 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 53 deletions(-) create mode 100755 src/xml/generate.py diff --git a/cmake/FindLibXsd.cmake b/cmake/FindLibXsd.cmake index 7775dbc4a..2e37c38fe 100644 --- a/cmake/FindLibXsd.cmake +++ b/cmake/FindLibXsd.cmake @@ -22,36 +22,27 @@ # # - Find the libxsd library # -# XSD_FOUND - system has libxsd -# XSD_LIBRARIES - The libraries needed to use libxsd +# LIBXSD_FOUND - system has libxsd +# LIBXSD_INCLUDE_DIRS - the libxsd include directory +# LIBXSD_LIBRARIES - The libraries needed to use libxsd -if(APPLE) -set(XSDCXX_DEFAULT_ROOT_PATH "/usr/local") -else () -set(XSDCXX_DEFAULT_ROOT_PATH "/usr") -endif() -set(XSDCXX_ROOT_PATH ${XSDCXX_DEFAULT_ROOT_PATH} CACHE STRING "Path of where the bin/xsdcxx executable will be found. Comes from http://www.codesynthesis.com/products/xsd/download.xhtml. On mac use 'brew install xsd'") +find_package(XercesC) -find_program(XSDCXX_PROG NAMES "xsdcxx" "xsd" - HINTS ${XSDCXX_ROOT_PATH}/bin +find_path(LIBXSD_INCLUDE_DIRS + NAMES xsd/cxx/config.hxx + PATH_SUFFIXES include ) -if(XSDCXX_PROG) - set(XSD_FOUND 1) - message(STATUS "XSD found at ${XSDCXX_PROG}, enabling XSD") - # TODO: check XSD is the correct executable - find_library(XERCES_LIBS NAMES xerces-c) - if(NOT XERCES_LIBS) - message(FATAL_ERROR "Failed to find the Xerces library.") - endif() - find_path(XERCES_INCLUDE_DIRS NAMES xercesc/util/XercesDefs.hpp) - if(NOT XERCES_INCLUDE_DIRS) - message(FATAL_ERROR "Failed to find the Xerces includes.") - endif() - set(XSD_LIBRARIES ${XERCES_LIBS}) -else() - set(XSD_FOUND 0) - message(STATUS "Program 'xsdcxx' could not be found in ${XSDCXX_ROOT_PATH}/bin, disabling XSD features") -endif() -mark_as_advanced(XSD_FOUND) +if(LIBXSD_INCLUDE_DIRS) + list(APPEND LIBXSD_INCLUDE_DIRS ${XercesC_INCLUDE_DIRS}) +endif() +set(LIBXSD_LIBRARIES ${XercesC_LIBRARIES}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LibXsd + DEFAULT_MSG + LIBXSD_INCLUDE_DIRS LIBXSD_LIBRARIES +) + +mark_as_advanced(LIBXSD_INCLUDE_DIRS LIBXSD_LIBRARIES) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0703ce488..8c8b2a14c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -160,31 +160,6 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES xml/xml.cpp ) -function(ADD_XSD_WRAPPERS file _comment) - set(destinations ${CMAKE_CURRENT_BINARY_DIR}/xml/${file}.hxx ${CMAKE_CURRENT_BINARY_DIR}/xml/${file}.cxx) - set(source ${CMAKE_CURRENT_LIST_DIR}/xml/${file}.xsd) - file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/xml") - - set(regex "%http://.+/(.+)%\\\$$1%") - - add_custom_command(OUTPUT ${destinations} - COMMAND "${XSDCXX_PROG}" "cxx-tree" "--generate-wildcard" - "--generate-serialization" "--generate-ostream" - "--generate-detach" "--std" "c++11" "--type-naming" "java" - "--function-naming" "java" "--location-regex-trace" "--show-sloc" - "--location-regex" "\"${regex}\"" - "--output-dir" "${CMAKE_CURRENT_BINARY_DIR}/xml" "${source}" - COMMENT "${_comment}") - - add_custom_target(${file} DEPENDS ${destinations} SOURCES ${source}) - - set_source_files_properties(${destinations} PROPERTIES GENERATED ON) - set(FLEXISIP_SOURCES ${FLEXISIP_SOURCES} ${destinations} PARENT_SCOPE) -endfunction() -ADD_XSD_WRAPPERS(xml "XML XSD - xml.xsd") -ADD_XSD_WRAPPERS(conference-info "Conference info XSD - conference-info.xsd") -ADD_XSD_WRAPPERS(resource-lists "Resourece lists XSD - resource-lists.xsd") - set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS} ${LIBXSD_INCLUDE_DIRS}) set(LINPHONE_CXX_OBJECTS_DEFINITIONS "-DLIBLINPHONE_EXPORTS") set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS}) diff --git a/src/xml/generate.py b/src/xml/generate.py new file mode 100755 index 000000000..42b400479 --- /dev/null +++ b/src/xml/generate.py @@ -0,0 +1,74 @@ +#!/usr/bin/python + +# Copyright (C) 2014 Belledonne Communications SARL +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +from distutils.spawn import find_executable +import os +import sys +from subprocess import Popen, PIPE + + +def find_xsdcxx(): + xsdcxx = find_executable("xsdcxx") + if xsdcxx is not None: + return xsdcxx + xsdcxx = find_executable("xsd") + return xsdcxx + +def generate(name): + xsdcxx = find_xsdcxx() + if xsdcxx is None: + print("Cannot find xsdcxx (or xsd) program in the PATH") + return -1 + print("Using " + xsdcxx) + cwd = os.getcwd() + script_dir = os.path.dirname(os.path.realpath(__file__)) + source_file = name + ".xsd" + print("Generating code from " + source_file) + source_file = os.path.join("xml", source_file) + work_dir = os.path.join(script_dir, "..") + os.chdir(work_dir) + p = Popen([xsdcxx, + "cxx-tree", + "--generate-wildcard", + "--generate-serialization", + "--generate-ostream", + "--generate-detach", + "--std", "c++11", + "--type-naming", "java", + "--function-naming", "java", + "--location-regex-trace", + "--show-sloc", + "--hxx-suffix", ".h", + "--ixx-suffix", ".h", + "--cxx-suffix", ".cpp", + "--location-regex", "%http://.+/(.+)%$1%", + "--output-dir", "xml", + source_file + ], shell=False) + p.communicate() + os.chdir(cwd) + return 0 + +def main(argv = None): + generate("xml") + generate("conference-info") + generate("resource-lists") + +if __name__ == "__main__": + sys.exit(main()) From 8ae87e2f3f155e82b4d5a11a6f1c3e1aedb5bb79 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 19 Sep 2017 14:20:14 +0200 Subject: [PATCH 0093/2215] feat(Core): deal with more warning options! --- CMakeLists.txt | 21 +++++++-- coreapi/private.h | 2 +- src/CMakeLists.txt | 10 +++- src/c-wrapper/api/c-address.cpp | 2 +- src/call/call-p.h | 26 +++++----- src/chat/basic-chat-room.h | 16 +++---- src/chat/chat-room-p.h | 14 +++--- src/chat/chat-room.cpp | 12 +++-- src/chat/client-group-chat-room.h | 16 +++---- src/chat/modifier/chat-message-modifier.h | 42 +++++++++-------- .../modifier/cpim-chat-message-modifier.cpp | 20 ++++---- .../modifier/cpim-chat-message-modifier.h | 41 ++++++++-------- .../multipart-chat-message-modifier.cpp | 32 +++++++------ .../multipart-chat-message-modifier.h | 41 ++++++++-------- src/chat/real-time-text-chat-room.h | 18 +++---- src/conference/conference.h | 47 +++++++++---------- .../local-conference-event-handler.cpp | 12 ++++- src/conference/local-conference.h | 10 +++- .../params/media-session-params.cpp | 2 +- src/conference/params/media-session-params.h | 6 +-- .../remote-conference-event-handler.cpp | 14 +++++- src/conference/session/media-session-p.h | 34 +++++++------- src/conference/session/media-session.h | 14 +++--- 23 files changed, 249 insertions(+), 203 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 24d225847..9cddd930e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,6 +90,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") include(CheckSymbolExists) include(CMakePushCheckState) include(GNUInstallDirs) +include(CheckCXXCompilerFlag) if(NOT CMAKE_INSTALL_RPATH AND CMAKE_INSTALL_PREFIX) set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}) @@ -205,7 +206,7 @@ endif() set(LINPHONE_LDFLAGS "${BELLESIP_LDFLAGS} ${MEDIASTREAMER2_LDFLAGS}") if(BELCARD_FOUND AND APPLE) - set(LINPHONE_LDFLAGS "${LINPHONE_LDFLAGS} -stdlib=libc++") + set(LINPHONE_LDFLAGS "${LINPHONE_LDFLAGS} -stdlib=libc++") endif() # include_directories must be called only UNDER THIS LINE in order to use our @@ -281,7 +282,22 @@ if(MSVC) list(APPEND STRICT_OPTIONS_CPP "/WX") endif() else() - list(APPEND STRICT_OPTIONS_CPP "-Wall" "-Wuninitialized" "-Wno-error=deprecated-declarations") + list(APPEND STRICT_OPTIONS_CPP "\ +-Wall \ +-Wcast-align \ +-Wconversion \ +-Werror=return-type \ +-Wfloat-equal \ +-Winit-self \ +-Wno-error=deprecated-declarations \ +-Woverloaded-virtual \ +-Wpointer-arith \ +-Wuninitialized \ +-Wunused") + CHECK_CXX_COMPILER_FLAG("-Wsuggest-override" SUGGEST_OVERRIDE) + if (SUGGEST_OVERRIDE) + list(APPEND STRICT_OPTIONS_CPP "-Wsuggest-override -Werror=suggest-override") + endif () list(APPEND STRICT_OPTIONS_C "-Wstrict-prototypes" "-Werror=strict-prototypes") if(CMAKE_C_COMPILER_ID STREQUAL "GNU") list(APPEND STRICT_OPTIONS_C "-fno-inline-small-functions") @@ -307,7 +323,6 @@ if(STRICT_OPTIONS_C) list(REMOVE_DUPLICATES STRICT_OPTIONS_C) endif() - set(GETTEXT_PACKAGE "linphone") if(ENABLE_RELATIVE_PREFIX) set(LINPHONE_DATA_DIR ".") diff --git a/coreapi/private.h b/coreapi/private.h index 7f25bb906..cd4673aef 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -407,7 +407,7 @@ static MS2_INLINE void set_string(char **dest, const char *src, bool_t lowercase *dest=ms_strdup(src); if (lowercase) { char *cur = *dest; - for (; *cur; cur++) *cur = tolower(*cur); + for (; *cur; cur++) *cur = (char)tolower(*cur); } } } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8c8b2a14c..ae40aa80b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -178,13 +178,19 @@ set(LINPHONE_PRIVATE_HEADER_FILES ${LINPHONE_PRIVATE_HEADER_FILES} PARENT_SCOPE) bc_apply_compile_flags(LINPHONE_CXX_OBJECTS_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX) if(ENABLE_STATIC) - add_library(linphone-cxx-objects-static OBJECT ${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES} ${LINPHONE_CXX_OBJECTS_SOURCE_FILES}) + add_library( + linphone-cxx-objects-static OBJECT + ${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES} ${LINPHONE_CXX_OBJECTS_SOURCE_FILES} + ) target_compile_definitions(linphone-cxx-objects-static PRIVATE ${LINPHONE_CXX_OBJECTS_DEFINITIONS}) target_include_directories(linphone-cxx-objects-static SYSTEM PRIVATE ${LINPHONE_CXX_OBJECTS_INCLUDE_DIRS} ${LINPHONE_INCLUDE_DIRS}) endif() if(ENABLE_SHARED) - add_library(linphone-cxx-objects OBJECT ${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES} ${LINPHONE_CXX_OBJECTS_SOURCE_FILES}) + add_library( + linphone-cxx-objects OBJECT + ${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES} ${LINPHONE_CXX_OBJECTS_SOURCE_FILES} + ) target_compile_definitions(linphone-cxx-objects PRIVATE ${LINPHONE_CXX_OBJECTS_DEFINITIONS}) target_include_directories(linphone-cxx-objects SYSTEM PRIVATE ${LINPHONE_CXX_OBJECTS_INCLUDE_DIRS} ${LINPHONE_INCLUDE_DIRS}) target_compile_options(linphone-cxx-objects PRIVATE "-fPIC") diff --git a/src/c-wrapper/api/c-address.cpp b/src/c-wrapper/api/c-address.cpp index 9e966dfc7..32add40aa 100644 --- a/src/c-wrapper/api/c-address.cpp +++ b/src/c-wrapper/api/c-address.cpp @@ -42,7 +42,7 @@ LinphoneAddress *linphone_address_new (const char *address) { } LinphoneAddress *linphone_address_clone (const LinphoneAddress *address) { - return (LinphoneAddress *)belle_sip_object_clone(BELLE_SIP_OBJECT(address)); + return reinterpret_cast(belle_sip_object_clone(BELLE_SIP_OBJECT(address))); } LinphoneAddress *linphone_address_ref (LinphoneAddress *address) { diff --git a/src/call/call-p.h b/src/call/call-p.h index 98b062f74..d0035ac9c 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -59,19 +59,19 @@ public: private: /* CallListener */ - void onAckBeingSent (LinphoneHeaders *headers); - void onAckReceived (LinphoneHeaders *headers); - void onCallSetReleased (); - void onCallSetTerminated (); - void onCallStateChanged (LinphoneCallState state, const std::string &message); - void onIncomingCallStarted (); - void onIncomingCallToBeAdded (); - void onEncryptionChanged (bool activated, const std::string &authToken); - void onStatsUpdated (const LinphoneCallStats *stats); - void onResetCurrentCall (); - void onSetCurrentCall (); - void onFirstVideoFrameDecoded (); - void onResetFirstVideoFrameDecoded (); + void onAckBeingSent (LinphoneHeaders *headers) override; + void onAckReceived (LinphoneHeaders *headers) override; + void onCallSetReleased () override; + void onCallSetTerminated () override; + void onCallStateChanged (LinphoneCallState state, const std::string &message) override; + void onIncomingCallStarted () override; + void onIncomingCallToBeAdded () override; + void onEncryptionChanged (bool activated, const std::string &authToken) override; + void onStatsUpdated (const LinphoneCallStats *stats) override; + void onResetCurrentCall () override; + void onSetCurrentCall () override; + void onFirstVideoFrameDecoded () override; + void onResetFirstVideoFrameDecoded () override; private: LinphoneCall *lcall = nullptr; diff --git a/src/chat/basic-chat-room.h b/src/chat/basic-chat-room.h index 1aced22f7..01864f3a9 100644 --- a/src/chat/basic-chat-room.h +++ b/src/chat/basic-chat-room.h @@ -39,14 +39,14 @@ public: virtual ~BasicChatRoom () = default; /* ConferenceInterface */ - std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia); - void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia); - bool canHandleParticipants () const; - const std::string& getId () const; - int getNbParticipants () const; - std::list> getParticipants () const; - void removeParticipant (const std::shared_ptr &participant); - void removeParticipants (const std::list> &participants); + std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; + void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia) override; + bool canHandleParticipants () const override; + const std::string& getId () const override; + int getNbParticipants () const override; + std::list> getParticipants () const override; + void removeParticipant (const std::shared_ptr &participant) override; + void removeParticipants (const std::list> &participants) override; private: L_DECLARE_PRIVATE(BasicChatRoom); diff --git a/src/chat/chat-room-p.h b/src/chat/chat-room-p.h index 1f082da49..d40d69f5d 100644 --- a/src/chat/chat-room-p.h +++ b/src/chat/chat-room-p.h @@ -19,15 +19,15 @@ #ifndef _CHAT_ROOM_P_H_ #define _CHAT_ROOM_P_H_ -// From coreapi. -#include "private.h" - #include "linphone/enums/chat-room-enums.h" #include "linphone/utils/enum-generator.h" +// From coreapi. +#include "private.h" + #include "chat-room.h" -#include "is-composing.h" #include "is-composing-listener.h" +#include "is-composing.h" #include "object/object-p.h" // ============================================================================= @@ -86,9 +86,9 @@ private: private: /* IsComposingListener */ - void onIsComposingStateChanged (bool isComposing); - void onIsRemoteComposingStateChanged (bool isComposing); - void onIsComposingRefreshNeeded (); + void onIsComposingStateChanged (bool isComposing) override; + void onIsRemoteComposingStateChanged (bool isComposing) override; + void onIsComposingRefreshNeeded () override; public: LinphoneCore *core = nullptr; diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 776c9bd86..b3aecbf5d 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -120,7 +120,7 @@ void ChatRoomPrivate::sendImdn (const string &content, LinphoneReason reason) { /* Sending out of call */ SalOp *op = sal_op_new(core->sal); - linphone_configure_op(core, op, peer, nullptr, lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0)); + linphone_configure_op(core, op, peer, nullptr, !!lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0)); LinphoneChatMessage *msg = q->createMessage(content); LinphoneAddress *fromAddr = linphone_address_new(identity); linphone_chat_message_set_from_address(msg, fromAddr); @@ -206,7 +206,7 @@ void ChatRoomPrivate::sendIsComposingNotification () { /* Sending out of call */ SalOp *op = sal_op_new(core->sal); - linphone_configure_op(core, op, peer, nullptr, lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0)); + linphone_configure_op(core, op, peer, nullptr, !!lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0)); string content = isComposingHandler.marshal(isComposing); if (!content.empty()) { int retval = -1; @@ -284,7 +284,7 @@ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colN linphone_address_unref(peer); newMessage->time = (time_t)atol(argv[9]); - newMessage->is_read = atoi(argv[6]); + newMessage->is_read = !!atoi(argv[6]); newMessage->state = static_cast(atoi(argv[7])); newMessage->storage_id = storageId; newMessage->external_body_url = ms_strdup(argv[8]); @@ -859,8 +859,10 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { if (!op) { /* Sending out of call */ msg->op = op = sal_op_new(d->core->sal); - linphone_configure_op(d->core, op, peer, msg->custom_headers, - lp_config_get_int(d->core->config, "sip", "chat_msg_with_contact", 0)); + linphone_configure_op( + d->core, op, peer, msg->custom_headers, + !!lp_config_get_int(d->core->config, "sip", "chat_msg_with_contact", 0) + ); sal_op_set_user_pointer(op, msg); /* If out of call, directly store msg */ } diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index 0101437cf..1dcc1cc47 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -40,14 +40,14 @@ public: public: /* ConferenceInterface */ - std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia); - void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia); - bool canHandleParticipants () const; - const std::string& getId () const; - int getNbParticipants () const; - std::list> getParticipants () const; - void removeParticipant (const std::shared_ptr &participant); - void removeParticipants (const std::list> &participants); + std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; + void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia) override; + bool canHandleParticipants () const override; + const std::string& getId () const override; + int getNbParticipants () const override; + std::list> getParticipants () const override; + void removeParticipant (const std::shared_ptr &participant) override; + void removeParticipants (const std::list> &participants) override; private: /* ConferenceListener */ diff --git a/src/chat/modifier/chat-message-modifier.h b/src/chat/modifier/chat-message-modifier.h index 97e8724f7..1bd6d5a88 100644 --- a/src/chat/modifier/chat-message-modifier.h +++ b/src/chat/modifier/chat-message-modifier.h @@ -16,23 +16,25 @@ * along with this program. If not, see . */ - #ifndef _CHAT_MESSAGE_MODIFIER_H_ - #define _CHAT_MESSAGE_MODIFIER_H_ - - #include "chat/chat-message.h" - - // ============================================================================= - - LINPHONE_BEGIN_NAMESPACE - - class ChatMessageModifier { - public: - virtual void encode(LinphonePrivate::ChatMessagePrivate* msg) = 0; - virtual void decode(LinphonePrivate::ChatMessagePrivate* msg) = 0; - virtual ~ChatMessageModifier () = default; - }; - - LINPHONE_END_NAMESPACE - - #endif // ifndef _CHAT_MESSAGE_MODIFIER_H_ - \ No newline at end of file +#ifndef _CHAT_MESSAGE_MODIFIER_H_ +#define _CHAT_MESSAGE_MODIFIER_H_ + +#include "linphone/utils/general.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ChatMessagePrivate; + +class ChatMessageModifier { +public: + virtual ~ChatMessageModifier () = default; + + virtual void encode (ChatMessagePrivate *messagePrivate) = 0; + virtual void decode (ChatMessagePrivate *messagePrivate) = 0; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CPIM_CHAT_MESSAGE_MODIFIER_H_ diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index e36095c71..dec8d2046 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -16,8 +16,6 @@ * along with this program. If not, see . */ -#include - #include "chat/chat-message-p.h" #include "chat/cpim/cpim.h" #include "content/content-type.h" @@ -31,7 +29,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -void CpimChatMessageModifier::encode(LinphonePrivate::ChatMessagePrivate* msg) { +void CpimChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { Cpim::Message message; Cpim::GenericHeader cpimContentTypeHeader; cpimContentTypeHeader.setName("Content-Type"); @@ -39,14 +37,14 @@ void CpimChatMessageModifier::encode(LinphonePrivate::ChatMessagePrivate* msg) { message.addCpimHeader(cpimContentTypeHeader); shared_ptr content; - if (msg->internalContent) { + if (messagePrivate->internalContent) { // Another ChatMessageModifier was called before this one, we apply our changes on the private content - content = msg->internalContent; + content = messagePrivate->internalContent; } else { // We're the first ChatMessageModifier to be called, we'll create the private content from the public one // We take the first one because if there is more of them, the multipart modifier should have been called first // So we should not be in this block - content = msg->contents.front(); + content = messagePrivate->contents.front(); } string contentType = content->getContentType().asString(); @@ -67,16 +65,16 @@ void CpimChatMessageModifier::encode(LinphonePrivate::ChatMessagePrivate* msg) { ContentType newContentType("Message/CPIM"); newContent->setContentType(newContentType); newContent->setBody(message.asString()); - msg->internalContent = newContent; + messagePrivate->internalContent = newContent; } } -void CpimChatMessageModifier::decode(LinphonePrivate::ChatMessagePrivate* msg) { +void CpimChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { shared_ptr content; - if (msg->internalContent) { - content = msg->internalContent; + if (messagePrivate->internalContent) { + content = messagePrivate->internalContent; } else { - content = msg->contents.front(); + content = messagePrivate->contents.front(); } ContentType contentType = content->getContentType(); diff --git a/src/chat/modifier/cpim-chat-message-modifier.h b/src/chat/modifier/cpim-chat-message-modifier.h index f31f1cb12..9d5696bb0 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.h +++ b/src/chat/modifier/cpim-chat-message-modifier.h @@ -16,24 +16,23 @@ * along with this program. If not, see . */ - #ifndef _CPIM_CHAT_MESSAGE_MODIFIER_H_ - #define _CPIM_CHAT_MESSAGE_MODIFIER_H_ - - #include "chat-message-modifier.h" - - // ============================================================================= - - LINPHONE_BEGIN_NAMESPACE - - class CpimChatMessageModifier : ChatMessageModifier { - public: - CpimChatMessageModifier() {}; - virtual void encode(LinphonePrivate::ChatMessagePrivate* msg); - virtual void decode(LinphonePrivate::ChatMessagePrivate* msg); - virtual ~CpimChatMessageModifier () = default; - }; - - LINPHONE_END_NAMESPACE - - #endif // ifndef _CPIM_CHAT_MESSAGE_MODIFIER_H_ - \ No newline at end of file +#ifndef _CPIM_CHAT_MESSAGE_MODIFIER_H_ +#define _CPIM_CHAT_MESSAGE_MODIFIER_H_ + +#include "chat-message-modifier.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class CpimChatMessageModifier : public ChatMessageModifier { +public: + CpimChatMessageModifier () = default; + + void encode (ChatMessagePrivate *messagePrivate) override; + void decode (ChatMessagePrivate *messagePrivate) override; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CPIM_CHAT_MESSAGE_MODIFIER_H_ diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index 352de4e2a..f0e073cbb 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -16,21 +16,23 @@ * along with this program. If not, see . */ - #include "chat/chat-message-p.h" - #include "multipart-chat-message-modifier.h" +#include "chat/chat-message-p.h" +#include "multipart-chat-message-modifier.h" - LINPHONE_BEGIN_NAMESPACE - - using namespace std; +// ============================================================================= - void MultipartChatMessageModifier::encode(LinphonePrivate::ChatMessagePrivate* msg) { - if (msg->contents.size() > 1) { - //TODO - } - } +using namespace std; - void MultipartChatMessageModifier::decode(LinphonePrivate::ChatMessagePrivate* msg) { - //TODO - } - -LINPHONE_END_NAMESPACE \ No newline at end of file +LINPHONE_BEGIN_NAMESPACE + +void MultipartChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { + if (messagePrivate->contents.size() > 1) { + //TODO + } +} + +void MultipartChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { + //TODO +} + +LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/multipart-chat-message-modifier.h b/src/chat/modifier/multipart-chat-message-modifier.h index b66f618f0..17361d3d6 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.h +++ b/src/chat/modifier/multipart-chat-message-modifier.h @@ -16,24 +16,23 @@ * along with this program. If not, see . */ - #ifndef _MULTIPART_CHAT_MESSAGE_MODIFIER_H_ - #define _MULTIPART_CHAT_MESSAGE_MODIFIER_H_ - - #include "chat-message-modifier.h" - - // ============================================================================= - - LINPHONE_BEGIN_NAMESPACE - - class MultipartChatMessageModifier : ChatMessageModifier { - public: - MultipartChatMessageModifier() {}; - virtual void encode(LinphonePrivate::ChatMessagePrivate* msg); - virtual void decode(LinphonePrivate::ChatMessagePrivate* msg); - virtual ~MultipartChatMessageModifier () = default; - }; - - LINPHONE_END_NAMESPACE - - #endif // ifndef _MULTIPART_CHAT_MESSAGE_MODIFIER_H_ - \ No newline at end of file +#ifndef _MULTIPART_CHAT_MESSAGE_MODIFIER_H_ +#define _MULTIPART_CHAT_MESSAGE_MODIFIER_H_ + +#include "chat-message-modifier.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class MultipartChatMessageModifier : public ChatMessageModifier { +public: + MultipartChatMessageModifier () = default; + + void encode (ChatMessagePrivate *message) override; + void decode (ChatMessagePrivate *message) override; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _MULTIPART_CHAT_MESSAGE_MODIFIER_H_ diff --git a/src/chat/real-time-text-chat-room.h b/src/chat/real-time-text-chat-room.h index 4c26673d8..1be0f549b 100644 --- a/src/chat/real-time-text-chat-room.h +++ b/src/chat/real-time-text-chat-room.h @@ -37,20 +37,20 @@ public: RealTimeTextChatRoom (LinphoneCore *core, const Address &peerAddress); virtual ~RealTimeTextChatRoom () = default; - void sendMessage (LinphoneChatMessage *msg); + void sendMessage (LinphoneChatMessage *msg) override; uint32_t getChar () const; LinphoneCall *getCall () const; /* ConferenceInterface */ - std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia); - void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia); - bool canHandleParticipants () const; - const std::string& getId () const; - int getNbParticipants () const; - std::list> getParticipants () const; - void removeParticipant (const std::shared_ptr &participant); - void removeParticipants (const std::list> &participants); + std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; + void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia) override; + bool canHandleParticipants () const override; + const std::string& getId () const override; + int getNbParticipants () const override; + std::list> getParticipants () const override; + void removeParticipant (const std::shared_ptr &participant) override; + void removeParticipants (const std::list> &participants) override; private: L_DECLARE_PRIVATE(RealTimeTextChatRoom); diff --git a/src/conference/conference.h b/src/conference/conference.h index f5746b556..7d5a0af36 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -19,9 +19,8 @@ #ifndef _CONFERENCE_H_ #define _CONFERENCE_H_ -#include +#include "linphone/types.h" -#include "object/object.h" #include "address/address.h" #include "call/call-listener.h" #include "conference/conference-interface.h" @@ -29,8 +28,6 @@ #include "conference/participant.h" #include "conference/session/call-session-listener.h" -#include "linphone/types.h" - // ============================================================================= LINPHONE_BEGIN_NAMESPACE @@ -50,30 +47,30 @@ public: public: /* ConferenceInterface */ - virtual std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia); - virtual void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia); - virtual bool canHandleParticipants () const; - virtual const std::string& getId () const; - virtual int getNbParticipants () const; - virtual std::list> getParticipants () const; - virtual void removeParticipant (const std::shared_ptr &participant); - virtual void removeParticipants (const std::list> &participants); + virtual std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; + virtual void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia) override; + virtual bool canHandleParticipants () const override; + virtual const std::string& getId () const override; + virtual int getNbParticipants () const override; + virtual std::list> getParticipants () const override; + virtual void removeParticipant (const std::shared_ptr &participant) override; + virtual void removeParticipants (const std::list> &participants) override; private: /* CallSessionListener */ - virtual void onAckBeingSent (const CallSession &session, LinphoneHeaders *headers); - virtual void onAckReceived (const CallSession &session, LinphoneHeaders *headers); - virtual void onCallSessionAccepted (const CallSession &session); - virtual void onCallSessionSetReleased (const CallSession &session); - virtual void onCallSessionSetTerminated (const CallSession &session); - virtual void onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message); - virtual void onIncomingCallSessionStarted (const CallSession &session); - virtual void onEncryptionChanged (const CallSession &session, bool activated, const std::string &authToken); - virtual void onStatsUpdated (const LinphoneCallStats *stats); - virtual void onResetCurrentSession (const CallSession &session); - virtual void onSetCurrentSession (const CallSession &session); - virtual void onFirstVideoFrameDecoded (const CallSession &session); - virtual void onResetFirstVideoFrameDecoded (const CallSession &session); + virtual void onAckBeingSent (const CallSession &session, LinphoneHeaders *headers) override; + virtual void onAckReceived (const CallSession &session, LinphoneHeaders *headers) override; + virtual void onCallSessionAccepted (const CallSession &session) override; + virtual void onCallSessionSetReleased (const CallSession &session) override; + virtual void onCallSessionSetTerminated (const CallSession &session) override; + virtual void onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message) override; + virtual void onIncomingCallSessionStarted (const CallSession &session) override; + virtual void onEncryptionChanged (const CallSession &session, bool activated, const std::string &authToken) override; + virtual void onStatsUpdated (const LinphoneCallStats *stats) override; + virtual void onResetCurrentSession (const CallSession &session) override; + virtual void onSetCurrentSession (const CallSession &session) override; + virtual void onFirstVideoFrameDecoded (const CallSession &session) override; + virtual void onResetFirstVideoFrameDecoded (const CallSession &session) override; protected: explicit Conference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index e5cae32ee..bc84868a2 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -20,10 +20,20 @@ #include "conference/participant.h" #include "local-conference-event-handler.h" #include "object/object-p.h" -#include "xml/conference-info.h" #include "private.h" +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wsuggest-override" +#endif + +#include "xml/conference-info.h" + +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic pop +#endif + // ============================================================================= using namespace std; diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h index 55e3f761c..660081516 100644 --- a/src/conference/local-conference.h +++ b/src/conference/local-conference.h @@ -35,8 +35,14 @@ public: public: /* ConferenceInterface */ - virtual std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia); - virtual void removeParticipant (const std::shared_ptr &participant); + virtual std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; + virtual void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia) override; + virtual bool canHandleParticipants () const override; + virtual const std::string& getId () const override; + virtual int getNbParticipants () const override; + virtual std::list> getParticipants () const override; + virtual void removeParticipant (const std::shared_ptr &participant) override; + virtual void removeParticipants (const std::list> &participants) override; private: L_DISABLE_COPY(LocalConference); diff --git a/src/conference/params/media-session-params.cpp b/src/conference/params/media-session-params.cpp index 79216feb6..fe65b7be3 100644 --- a/src/conference/params/media-session-params.cpp +++ b/src/conference/params/media-session-params.cpp @@ -218,7 +218,7 @@ void MediaSessionParams::initDefault (LinphoneCore *core) { d->encryption = linphone_core_get_media_encryption(core); d->avpfEnabled = (linphone_core_get_avpf_mode(core) == LinphoneAVPFEnabled); d->_implicitRtcpFbEnabled = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_fb_implicit_rtcp_fb", true); - d->avpfRrInterval = linphone_core_get_avpf_rr_interval(core); + d->avpfRrInterval = static_cast(linphone_core_get_avpf_rr_interval(core)); d->audioDirection = LinphoneMediaDirectionSendRecv; d->videoDirection = LinphoneMediaDirectionSendRecv; d->earlyMediaSendingEnabled = lp_config_get_int(linphone_core_get_config(core), "misc", "real_early_media", false); diff --git a/src/conference/params/media-session-params.h b/src/conference/params/media-session-params.h index a5f09fdcc..a8fdb1d7a 100644 --- a/src/conference/params/media-session-params.h +++ b/src/conference/params/media-session-params.h @@ -19,10 +19,10 @@ #ifndef _MEDIA_SESSION_PARAMS_H_ #define _MEDIA_SESSION_PARAMS_H_ -#include "call-session-params.h" - #include +#include "call-session-params.h" + // ============================================================================= LINPHONE_BEGIN_NAMESPACE @@ -40,7 +40,7 @@ public: MediaSessionParams (const MediaSessionParams &src); virtual ~MediaSessionParams () = default; - void initDefault (LinphoneCore *core); + void initDefault (LinphoneCore *core) override; bool audioEnabled () const; bool audioMulticastEnabled () const; diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 388a43a55..433465bda 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -17,10 +17,20 @@ */ #include "remote-conference-event-handler.h" -#include "xml/conference-info.h" #include "private.h" #include "object/object-p.h" +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wsuggest-override" +#endif + +#include "xml/conference-info.h" + +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic pop +#endif + // ============================================================================= using namespace std; @@ -37,7 +47,7 @@ public: LinphoneEvent *lev = nullptr; }; -// ============================================================================= +// ----------------------------------------------------------------------------- RemoteConferenceEventHandler::RemoteConferenceEventHandler(LinphoneCore *core, ConferenceListener *listener) : Object(*new RemoteConferenceEventHandlerPrivate) { diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index 79286f99e..210f2df2a 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -45,15 +45,15 @@ public: public: static void stunAuthRequestedCb (void *userData, const char *realm, const char *nonce, const char **username, const char **password, const char **ha1); - void accepted (); - void ackReceived (LinphoneHeaders *headers); - bool failure (); + void accepted () override; + void ackReceived (LinphoneHeaders *headers) override; + bool failure () override; void pausedByRemote (); - void remoteRinging (); + void remoteRinging () override; void resumed (); - void terminated (); + void terminated () override; void updated (bool isUpdate); - void updating (bool isUpdate); + void updating (bool isUpdate) override; void enableSymmetricRtp (bool value); void sendVfu (); @@ -91,11 +91,11 @@ private: static float aggregateQualityRatings (float audioRating, float videoRating); - void setState (LinphoneCallState newState, const std::string &message); + void setState (LinphoneCallState newState, const std::string &message) override; void computeStreamsIndexes (const SalMediaDescription *md); void fixCallParams (SalMediaDescription *rmd); - void initializeParamsAccordingToIncomingCallParams (); + void initializeParamsAccordingToIncomingCallParams () override; void setCompatibleIncomingCallParams (SalMediaDescription *md); void updateBiggestDesc (SalMediaDescription *md); void updateRemoteSessionIdAndVer (); @@ -211,18 +211,18 @@ private: void reportBandwidth (); void reportBandwidthForStream (MediaStream *ms, LinphoneStreamType type); - void abort (const std::string &errorMsg); - void handleIncomingReceivedStateInIncomingNotification (); - bool isReadyForInvite () const; + void abort (const std::string &errorMsg) override; + void handleIncomingReceivedStateInIncomingNotification () override; + bool isReadyForInvite () const override; LinphoneStatus pause (); - void setTerminated (); - LinphoneStatus startAcceptUpdate (LinphoneCallState nextState, const std::string &stateInfo); - LinphoneStatus startUpdate (); - void terminate (); - void updateCurrentParams (); + void setTerminated () override; + LinphoneStatus startAcceptUpdate (LinphoneCallState nextState, const std::string &stateInfo) override; + LinphoneStatus startUpdate () override; + void terminate () override; + void updateCurrentParams () override; void accept (const MediaSessionParams *params); - LinphoneStatus acceptUpdate (const CallSessionParams *csp, LinphoneCallState nextState, const std::string &stateInfo); + LinphoneStatus acceptUpdate (const CallSessionParams *csp, LinphoneCallState nextState, const std::string &stateInfo) override; #ifdef VIDEO_ENABLED void videoStreamEventCb (const MSFilter *f, const unsigned int eventId, const void *args); diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index 589bf1e30..3403746ea 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -40,15 +40,15 @@ public: LinphoneStatus accept (const MediaSessionParams *msp = nullptr); LinphoneStatus acceptEarlyMedia (const MediaSessionParams *msp = nullptr); LinphoneStatus acceptUpdate (const MediaSessionParams *msp); - void configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalOp *op, const Address &from, const Address &to); - void initiateIncoming (); - bool initiateOutgoing (); - void iterate (time_t currentRealTime, bool oneSecondElapsed); + void configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalOp *op, const Address &from, const Address &to) override; + void initiateIncoming () override; + bool initiateOutgoing () override; + void iterate (time_t currentRealTime, bool oneSecondElapsed) override; LinphoneStatus pause (); LinphoneStatus resume (); void sendVfuRequest (); - void startIncomingNotification (); - int startInvite (const Address *destination); + void startIncomingNotification () override; + int startInvite (const Address *destination) override; void startRecording (); void stopRecording (); LinphoneStatus update (const MediaSessionParams *msp); @@ -76,7 +76,7 @@ public: RtpTransport * getMetaRtpTransport (int streamIndex); float getMicrophoneVolumeGain () const; void * getNativeVideoWindowId () const; - const CallSessionParams *getParams () const; + const CallSessionParams *getParams () const override; float getPlayVolume () const; float getRecordVolume () const; const MediaSessionParams *getRemoteParams (); From b2a0cd770ea1011271c4119116ca19d66325f88e Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 20 Sep 2017 12:40:15 +0200 Subject: [PATCH 0094/2215] fix(core): deal with new cpp flags --- coreapi/account_creator.c | 2 +- coreapi/authentication.c | 2 +- coreapi/bellesip_sal/sal_address_impl.c | 6 +- coreapi/bellesip_sal/sal_impl.c | 12 +- coreapi/bellesip_sal/sal_op_call.c | 2 +- coreapi/bellesip_sal/sal_sdp.c | 42 +++--- coreapi/call_log.c | 2 +- coreapi/conference.cc | 56 ++++---- coreapi/ec-calibrator.c | 45 +++--- coreapi/event.c | 2 +- coreapi/friend.c | 10 +- coreapi/lime.c | 66 ++++----- coreapi/linphonecall.c | 4 +- coreapi/linphonecore.c | 168 +++++++++++------------ coreapi/lpc2xml.c | 24 ++-- coreapi/lpconfig.c | 4 +- coreapi/message_storage.c | 2 +- coreapi/misc.c | 4 +- coreapi/proxy.c | 18 +-- coreapi/siplogin.c | 2 +- coreapi/sqlite3_bctbx_vfs.c | 25 ++-- coreapi/vcard.cc | 2 +- src/conference/session/call-session.cpp | 2 +- src/conference/session/media-session.cpp | 46 ++++--- src/nat/ice-agent.cpp | 27 ++-- src/nat/stun-client.cpp | 22 +-- src/utils/utils.cpp | 22 +-- src/variant/variant.cpp | 12 +- src/xml/conference-info.cpp | 64 +++++---- src/xml/xml.cpp | 18 ++- 30 files changed, 369 insertions(+), 344 deletions(-) diff --git a/coreapi/account_creator.c b/coreapi/account_creator.c index 37f4a8830..e6902ef2b 100644 --- a/coreapi/account_creator.c +++ b/coreapi/account_creator.c @@ -348,7 +348,7 @@ void linphone_account_creator_set_user_data(LinphoneAccountCreator *creator, voi LinphoneAccountCreatorUsernameStatus linphone_account_creator_set_username(LinphoneAccountCreator *creator, const char *username) { int min_length = lp_config_get_int(creator->core->config, "assistant", "username_min_length", -1); int max_length = lp_config_get_int(creator->core->config, "assistant", "username_max_length", -1); - bool_t use_phone_number = lp_config_get_int(creator->core->config, "assistant", "use_phone_number", 0); + bool_t use_phone_number = !!lp_config_get_int(creator->core->config, "assistant", "use_phone_number", 0); const char* regex = lp_config_get_string(creator->core->config, "assistant", "username_regex", 0); if (!username) { creator->username = NULL; diff --git a/coreapi/authentication.c b/coreapi/authentication.c index fe07f9240..a280de6bf 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -219,7 +219,7 @@ void linphone_auth_info_destroy(LinphoneAuthInfo *obj){ void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, int pos) { char key[50]; - bool_t store_ha1_passwd = lp_config_get_int(config, "sip", "store_ha1_passwd", 1); + bool_t store_ha1_passwd = !!lp_config_get_int(config, "sip", "store_ha1_passwd", 1); sprintf(key, "auth_info_%i", pos); lp_config_clean_section(config, key); diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c index 6d89ef8aa..a78bf28e6 100644 --- a/coreapi/bellesip_sal/sal_address_impl.c +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -58,7 +58,7 @@ void sal_address_set_secure(SalAddress *addr, bool_t enabled){ bool_t sal_address_is_secure(const SalAddress *addr){ belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr); - if (uri) return belle_sip_uri_is_secure(uri); + if (uri) return !!belle_sip_uri_is_secure(uri); return FALSE; } @@ -199,7 +199,7 @@ void sal_address_set_param(SalAddress *addr,const char* name,const char* value){ bool_t sal_address_has_param(const SalAddress *addr, const char *name){ belle_sip_parameters_t* parameters = BELLE_SIP_PARAMETERS(addr); - return belle_sip_parameters_has_parameter(parameters, name); + return !!belle_sip_parameters_has_parameter(parameters, name); } const char * sal_address_get_param(const SalAddress *addr, const char *name) { @@ -224,7 +224,7 @@ void sal_address_set_uri_params(SalAddress *addr, const char *params){ bool_t sal_address_has_uri_param(const SalAddress *addr, const char *name){ belle_sip_parameters_t* parameters = BELLE_SIP_PARAMETERS(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(addr))); - return belle_sip_parameters_has_parameter(parameters, name); + return !!belle_sip_parameters_has_parameter(parameters, name); } const char * sal_address_get_uri_param(const SalAddress *addr, const char *name) { diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index b2fe0d69a..ccdb2d197 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -84,7 +84,7 @@ void sal_set_log_level(OrtpLogLevel level) { if (((level&ORTP_DEBUG) != 0) || ((level&ORTP_TRACE) != 0)) { belle_sip_level = BELLE_SIP_LOG_DEBUG; } - + belle_sip_set_log_level(belle_sip_level); } static BctbxLogFunc _belle_sip_log_handler = bctbx_logv_out; @@ -215,7 +215,7 @@ static void process_request_event(void *ud, const belle_sip_request_event_t *eve if (dialog) { op=(SalOp*)belle_sip_dialog_get_application_data(dialog); - + if (op == NULL && strcmp("NOTIFY",method) == 0) { /*special case for Dialog created by notify mathing subscribe*/ belle_sip_transaction_t * sub_trans = belle_sip_dialog_get_last_transaction(dialog); @@ -658,7 +658,7 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i sal_address_set_domain(sal_addr,addr); sal_address_set_port(sal_addr,port); sal_address_set_transport(sal_addr,tr); - result = sal_add_listen_port(ctx, sal_addr, is_tunneled); + result = sal_add_listen_port(ctx, sal_addr, !!is_tunneled); sal_address_destroy(sal_addr); return result; } @@ -986,7 +986,7 @@ const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name){ SalCustomHeader *sal_custom_header_remove(SalCustomHeader *ch, const char *name) { belle_sip_message_t *msg=(belle_sip_message_t*)ch; if (msg==NULL) return NULL; - + belle_sip_message_remove_header(msg, name); return (SalCustomHeader*)msg; } @@ -1066,9 +1066,9 @@ int sal_generate_uuid(char *uuid, size_t len) { if (len==0) return -1; /*create an UUID as described in RFC4122, 4.4 */ belle_sip_random_bytes((unsigned char*)&uuid_struct, sizeof(sal_uuid_t)); - uuid_struct.clock_seq_hi_and_reserved&=~(1<<6); + uuid_struct.clock_seq_hi_and_reserved&=(unsigned char)~(1<<6); uuid_struct.clock_seq_hi_and_reserved|=1<<7; - uuid_struct.time_hi_and_version&=~(0xf<<12); + uuid_struct.time_hi_and_version&=(short unsigned int)~(0xf<<12); uuid_struct.time_hi_and_version|=4<<12; written=snprintf(uuid,len,"%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", uuid_struct.time_low, uuid_struct.time_mid, diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index c6e35e1db..4f416f565 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -327,7 +327,7 @@ static void call_process_response(void *op_base, const belle_sip_response_event_ && (header_content_type = belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t)) && strcmp("application",belle_sip_header_content_type_get_type(header_content_type))==0 && strcmp("media_control+xml",belle_sip_header_content_type_get_subtype(header_content_type))==0) { - unsigned int retry_in = (unsigned int)(1000*((float)rand()/RAND_MAX)); + unsigned int retry_in = (unsigned int)(1000*((float)rand()/(float)RAND_MAX)); belle_sip_source_t *s=sal_create_timer(op->base.root,vfu_retry,sal_op_ref(op), retry_in, "vfu request retry"); ms_message("Rejected vfu request on op [%p], just retry in [%ui] ms",op,retry_in); belle_sip_object_unref(s); diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 22b8c5be1..c2a059d22 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -150,25 +150,25 @@ static void add_rtcp_fb_attributes(belle_sdp_media_description_t *media_desc, co /* Add trr-int if not set generally. */ if (general_trr_int != TRUE && trr_int != 0) { - add_rtcp_fb_trr_int_attribute(media_desc, payload_type_get_number(pt), avpf_params.trr_interval); + add_rtcp_fb_trr_int_attribute(media_desc, (int8_t)payload_type_get_number(pt), avpf_params.trr_interval); } /* Add rtcp-fb attributes according to the AVPF features of the payload types. */ if (avpf_params.features & PAYLOAD_TYPE_AVPF_PLI) { - add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_PLI); + add_rtcp_fb_nack_attribute(media_desc, (int8_t)payload_type_get_number(pt), BELLE_SDP_RTCP_FB_PLI); } if (avpf_params.features & PAYLOAD_TYPE_AVPF_SLI) { - add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_SLI); + add_rtcp_fb_nack_attribute(media_desc, (int8_t)payload_type_get_number(pt), BELLE_SDP_RTCP_FB_SLI); } if (avpf_params.features & PAYLOAD_TYPE_AVPF_RPSI) { if (avpf_params.rpsi_compatibility == TRUE) { - add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_RPSI); + add_rtcp_fb_nack_attribute(media_desc, (int8_t)payload_type_get_number(pt), BELLE_SDP_RTCP_FB_RPSI); } else { - add_rtcp_fb_ack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_RPSI); + add_rtcp_fb_ack_attribute(media_desc, (int8_t)payload_type_get_number(pt), BELLE_SDP_RTCP_FB_RPSI); } } if (avpf_params.features & PAYLOAD_TYPE_AVPF_FIR) { - add_rtcp_fb_ccm_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_FIR); + add_rtcp_fb_ccm_attribute(media_desc, (int8_t)payload_type_get_number(pt), BELLE_SDP_RTCP_FB_FIR); } } } @@ -263,9 +263,9 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session if (ms_crypto_suite_to_name_params(stream->crypto[j].algo,&desc)==0){ if (desc.params) snprintf ( buffer, sizeof ( buffer )-1, "%d %s inline:%s %s", stream->crypto[j].tag, desc.name, stream->crypto[j].master_key,desc.params); - else + else snprintf ( buffer, sizeof ( buffer )-1, "%d %s inline:%s", stream->crypto[j].tag, desc.name, stream->crypto[j].master_key ); - + belle_sdp_media_description_add_attribute( media_desc,belle_sdp_attribute_create ("crypto", buffer)); }else break; } @@ -314,11 +314,11 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session break; } if ( dir ) belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( dir,NULL ) ); - + if (stream->rtcp_mux){ belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create ("rtcp-mux",NULL ) ); } - + if (rtp_port != 0) { different_rtp_and_rtcp_addr = (rtcp_addr[0] != '\0') && (strcmp(rtp_addr, rtcp_addr) != 0); if ((rtcp_port != (rtp_port + 1)) || (different_rtp_and_rtcp_addr == TRUE)) { @@ -337,7 +337,7 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-mismatch",NULL)); } else { if (rtp_port != 0) { - if (stream->ice_pwd[0] != '\0') + if (stream->ice_pwd[0] != '\0') belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-pwd",stream->ice_pwd)); if (stream->ice_ufrag[0] != '\0') belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-ufrag",stream->ice_ufrag)); @@ -432,7 +432,7 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr if ( desc->bandwidth>0 ) { belle_sdp_session_description_set_bandwidth ( session_desc,"AS",desc->bandwidth ); } - + if (desc->set_nortpproxy == TRUE) belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("nortpproxy","yes")); if (desc->ice_pwd[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-pwd",desc->ice_pwd)); if (desc->ice_ufrag[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-ufrag",desc->ice_ufrag)); @@ -501,7 +501,7 @@ static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *med &stream->crypto[valid_count].tag, tmp, tmp2, parameters ); - + if ( nb >= 3 ) { MSCryptoSuite cs; MSCryptoSuiteNameParams np; @@ -651,7 +651,7 @@ static bool_t sdp_parse_rtcp_fb_parameters(belle_sdp_media_description_t *media_ PayloadType *pt; int8_t pt_num; bool_t retval = FALSE; - + /* Handle rtcp-fb attributes that concern all payload types. */ for (it = belle_sdp_media_description_get_attributes(media_desc); it != NULL; it = it->next) { attribute = BELLE_SDP_ATTRIBUTE(it->data); @@ -805,7 +805,7 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, } stream->rtcp_mux = belle_sdp_media_description_get_attribute(media_desc, "rtcp-mux") != NULL; - + /* Get media payload types */ sdp_parse_payload_types(media_desc, stream); @@ -857,7 +857,7 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, /* Get ICE candidate attributes if any */ sdp_parse_media_ice_parameters(media_desc, stream); - + has_avpf_attributes = sdp_parse_rtcp_fb_parameters(media_desc, stream); /* Get RTCP-FB attributes if any */ @@ -892,7 +892,7 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S const char* value; SalDtlsRole session_role=SalDtlsRoleInvalid; int i; - + desc->nb_streams = 0; desc->dir = SalStreamSendRecv; @@ -902,11 +902,11 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S if ( (sname=belle_sdp_session_description_get_session_name(session_desc)) && belle_sdp_session_name_get_value(sname) ){ strncpy(desc->name,belle_sdp_session_name_get_value(sname),sizeof(desc->name) - 1); } - + if ( belle_sdp_session_description_get_bandwidth ( session_desc,"AS" ) >0 ) { desc->bandwidth=belle_sdp_session_description_get_bandwidth ( session_desc,"AS" ); } - + /*in some very rare case, session attribute may set stream dir*/ if ( belle_sdp_session_description_get_attribute ( session_desc,"sendrecv" ) ) { desc->dir=SalStreamSendRecv; @@ -940,10 +940,10 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S /* Get ICE remote ufrag and remote pwd, and ice_lite flag */ value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-ufrag"); if (value) strncpy(desc->ice_ufrag, value, sizeof(desc->ice_ufrag) - 1); - + value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-pwd"); if (value) strncpy(desc->ice_pwd, value, sizeof(desc->ice_pwd)-1); - + value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-lite"); if (value) desc->ice_lite = TRUE; diff --git a/coreapi/call_log.c b/coreapi/call_log.c index e69346ec6..b1c98aeab 100644 --- a/coreapi/call_log.c +++ b/coreapi/call_log.c @@ -153,7 +153,7 @@ bctbx_list_t * call_logs_read_from_config_file(LinphoneCore *lc){ tmp=lp_config_get_string(cfg,logsection,"refkey",NULL); if (tmp) cl->refkey=ms_strdup(tmp); cl->quality=lp_config_get_float(cfg,logsection,"quality",-1); - cl->video_enabled=lp_config_get_int(cfg,logsection,"video_enabled",0); + cl->video_enabled=!!lp_config_get_int(cfg,logsection,"video_enabled",0); tmp=lp_config_get_string(cfg,logsection,"call_id",NULL); if (tmp) cl->call_id=ms_strdup(tmp); call_logs=bctbx_list_append(call_logs,cl); diff --git a/coreapi/conference.cc b/coreapi/conference.cc index ad291c4c7..7934b3585 100644 --- a/coreapi/conference.cc +++ b/coreapi/conference.cc @@ -169,23 +169,25 @@ public: LocalConference(LinphoneCore *core, LinphoneConference *conf, const Params *params = NULL); virtual ~LocalConference(); - virtual int inviteAddresses(const list &addresses, const LinphoneCallParams *params); - virtual int addParticipant(LinphoneCall *call); - virtual int removeParticipant(LinphoneCall *call); - virtual int removeParticipant(const LinphoneAddress *uri); - virtual int terminate(); + virtual int inviteAddresses(const list &addresses, const LinphoneCallParams *params) override; + virtual int addParticipant(LinphoneCall *call) override; + virtual int removeParticipant(LinphoneCall *call) override; + virtual int removeParticipant(const LinphoneAddress *uri) override; + virtual int terminate() override; - virtual int enter(); - virtual int leave(); - virtual bool isIn() const {return m_localParticipantStream!=NULL;} - virtual int getSize() const; + virtual int enter() override; + virtual int leave() override; + virtual bool isIn() const override { + return m_localParticipantStream!=NULL; + } + virtual int getSize() const override; - virtual int startRecording(const char *path); - virtual int stopRecording(); + virtual int startRecording(const char *path) override; + virtual int stopRecording() override; - virtual void onCallStreamStarting(LinphoneCall *call, bool isPausedByRemote); - virtual void onCallStreamStopping(LinphoneCall *call); - virtual void onCallTerminating(LinphoneCall *call); + virtual void onCallStreamStarting(LinphoneCall *call, bool isPausedByRemote) override; + virtual void onCallStreamStopping(LinphoneCall *call) override; + virtual void onCallTerminating(LinphoneCall *call) override; private: void addLocalEndpoint(); @@ -207,18 +209,24 @@ public: RemoteConference(LinphoneCore *core, LinphoneConference *conf, const Params *params = NULL); virtual ~RemoteConference(); - virtual int inviteAddresses(const list &addresses, const LinphoneCallParams *params); - virtual int addParticipant(LinphoneCall *call); - virtual int removeParticipant(LinphoneCall *call) {return -1;} - virtual int removeParticipant(const LinphoneAddress *uri); - virtual int terminate(); + virtual int inviteAddresses(const list &addresses, const LinphoneCallParams *params) override; + virtual int addParticipant(LinphoneCall *call) override; + virtual int removeParticipant(LinphoneCall *call) override { + return -1; + } + virtual int removeParticipant(const LinphoneAddress *uri) override; + virtual int terminate() override; - virtual int enter(); - virtual int leave(); - virtual bool isIn() const; + virtual int enter() override; + virtual int leave() override; + virtual bool isIn() const override; - virtual int startRecording(const char *path) {return 0;} - virtual int stopRecording() {return 0;} + virtual int startRecording (const char *path) override { + return 0; + } + virtual int stopRecording() override { + return 0; + } private: bool focusIsReady() const; diff --git a/coreapi/ec-calibrator.c b/coreapi/ec-calibrator.c index 7c7ddcf54..10578af9a 100644 --- a/coreapi/ec-calibrator.c +++ b/coreapi/ec-calibrator.c @@ -47,8 +47,8 @@ static void ecc_init_filters(EcCalibrator *ecc){ ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&ecc->rate); ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_NCHANNELS,&channels); ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_OUTPUT_NCHANNELS,&ecc_channels); - - + + ecc->det=ms_factory_create_filter(ecc->factory, MS_TONE_DETECTOR_ID); ms_filter_call_method(ecc->det,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate); ecc->rec=ms_factory_create_filter(ecc->factory, MS_VOID_SINK_ID); @@ -62,7 +62,7 @@ static void ecc_init_filters(EcCalibrator *ecc){ ms_filter_call_method(ecc->gen,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate); ecc->write_resampler=ms_factory_create_filter(ecc->factory, MS_RESAMPLE_ID); ecc->sndwrite=ms_snd_card_create_writer(ecc->play_card); - + ms_filter_call_method(ecc->sndwrite,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate); ms_filter_call_method(ecc->sndwrite,MS_FILTER_GET_SAMPLE_RATE,&rate); ms_filter_call_method(ecc->sndwrite,MS_FILTER_SET_NCHANNELS,&ecc_channels); @@ -153,37 +153,37 @@ static void on_tone_received(void *data, MSFilter *f, unsigned int event_id, voi static void ecc_play_tones(EcCalibrator *ecc){ MSDtmfGenCustomTone tone; MSToneDetectorDef expected_tone; - + memset(&tone,0,sizeof(tone)); memset(&expected_tone,0,sizeof(expected_tone)); ms_filter_add_notify_callback(ecc->det,on_tone_received,ecc,TRUE); /* configure the tones to be scanned */ - + strncpy(expected_tone.tone_name,"freq1",sizeof(expected_tone.tone_name)); expected_tone.frequency=(int)2349.32; expected_tone.min_duration=40; expected_tone.min_amplitude=0.1f; ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone); - + strncpy(expected_tone.tone_name,"freq2",sizeof(expected_tone.tone_name)); expected_tone.frequency=(int)2637.02; expected_tone.min_duration=40; expected_tone.min_amplitude=0.1f; ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone); - + strncpy(expected_tone.tone_name,"freq3",sizeof(expected_tone.tone_name)); expected_tone.frequency=(int)2093; expected_tone.min_duration=40; expected_tone.min_amplitude=0.1f; ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone); - + /*play an initial tone to startup the audio playback/capture*/ - + tone.frequencies[0]=140; tone.duration=1000; tone.amplitude=0.5; @@ -192,23 +192,23 @@ static void ecc_play_tones(EcCalibrator *ecc){ ms_sleep(2); ms_filter_add_notify_callback(ecc->gen,on_tone_sent,ecc,TRUE); - + /* play the three tones*/ - - + + if (ecc->play_cool_tones){ strncpy(tone.tone_name, "D", sizeof(tone.tone_name)); tone.frequencies[0]=(int)2349.32; tone.duration=100; ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone); ms_usleep(300000); - + strncpy(tone.tone_name, "E", sizeof(tone.tone_name)); tone.frequencies[0]=(int)2637.02; tone.duration=100; ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone); ms_usleep(300000); - + strncpy(tone.tone_name, "C", sizeof(tone.tone_name)); tone.frequencies[0]=(int)2093; tone.duration=100; @@ -220,20 +220,20 @@ static void ecc_play_tones(EcCalibrator *ecc){ tone.duration=100; ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone); ms_usleep(300000); - + strncpy(tone.tone_name, "D", sizeof(tone.tone_name)); tone.frequencies[0]=(int)2349.32; tone.duration=100; ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone); ms_usleep(300000); - + strncpy(tone.tone_name, "E", sizeof(tone.tone_name)); tone.frequencies[0]=(int)2637.02; tone.duration=100; ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone); ms_usleep(300000); } - + /*these two next ones are for lyrism*/ if (ecc->play_cool_tones){ tone.tone_name[0]='\0'; @@ -241,15 +241,15 @@ static void ecc_play_tones(EcCalibrator *ecc){ tone.duration=400; ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone); ms_usleep(300000); - + tone.tone_name[0]='\0'; tone.frequencies[0]=(int)1567.98; tone.duration=400; ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone); } - + ms_sleep(1); - + if (ecc->freq1 && ecc->freq2 && ecc->freq3) { int delay=(int)(ecc->acc/3); if (delay<0){ @@ -274,7 +274,7 @@ static void ecc_play_tones(EcCalibrator *ecc){ static void * ecc_thread(void *p){ EcCalibrator *ecc=(EcCalibrator*)p; - + ecc_init_filters(ecc); ecc_play_tones(ecc); ecc_deinit_filters(ecc); @@ -320,8 +320,7 @@ int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibration } rate = lp_config_get_int(lc->config,"sound","echo_cancellation_rate",8000); lc->ecc=ec_calibrator_new(lc->factory, lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard,rate,cb,audio_init_cb,audio_uninit_cb,cb_data); - lc->ecc->play_cool_tones = lp_config_get_int(lc->config, "sound", "ec_calibrator_cool_tones", 0); + lc->ecc->play_cool_tones = !!lp_config_get_int(lc->config, "sound", "ec_calibrator_cool_tones", 0); ec_calibrator_start(lc->ecc); return 0; } - diff --git a/coreapi/event.c b/coreapi/event.c index cb7a7f898..fb43c4a3d 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -291,7 +291,7 @@ static LinphoneEvent *_linphone_core_create_publish(LinphoneCore *core, Linphone resource = linphone_proxy_config_get_identity_address(cfg); lev = linphone_event_new(lc,LinphoneSubscriptionInvalidDir, event,expires); - linphone_configure_op_with_proxy(lc,lev->op,resource,NULL,lp_config_get_int(lc->config,"sip","publish_msg_with_contact",0),cfg); + linphone_configure_op_with_proxy(lc,lev->op,resource,NULL, !!lp_config_get_int(lc->config,"sip","publish_msg_with_contact",0),cfg); sal_op_set_manual_refresher_mode(lev->op,!lp_config_get_int(lc->config,"sip","refresh_generic_publish",1)); return lev; } diff --git a/coreapi/friend.c b/coreapi/friend.c index 16c43b596..914f44d66 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -889,7 +889,7 @@ void linphone_core_update_friends_subscriptions(LinphoneCore *lc) { } bool_t linphone_core_should_subscribe_friends_only_when_registered(const LinphoneCore *lc){ - return lp_config_get_int(lc->config,"sip","subscribe_presence_only_when_registered",1); + return !!lp_config_get_int(lc->config,"sip","subscribe_presence_only_when_registered",1); } void linphone_core_send_initial_subscribes(LinphoneCore *lc) { @@ -1030,7 +1030,7 @@ LinphoneFriend * linphone_friend_new_from_config_file(LinphoneCore *lc, int inde linphone_friend_set_inc_subscribe_policy(lf,__policy_str_to_enum(tmp)); } a=lp_config_get_int(config,item,"subscribe",0); - linphone_friend_send_subscribe(lf,a); + linphone_friend_send_subscribe(lf,!!a); a = lp_config_get_int(config, item, "presence_received", 0); lf->presence_received = (bool_t)a; @@ -1156,7 +1156,7 @@ bool_t linphone_friend_create_vcard(LinphoneFriend *fr, const char *name) { lc = fr->friend_list->lc; } if (lc) { - skip = 1 - lp_config_get_int(fr->lc->config, "misc", "store_friends", 1); + skip = !lp_config_get_int(fr->lc->config, "misc", "store_friends", 1); linphone_vcard_set_skip_validation(vcard, skip); } linphone_vcard_set_full_name(vcard, name); @@ -1410,9 +1410,9 @@ static int create_friend(void *data, int argc, char **argv, char **colName) { } } linphone_friend_set_inc_subscribe_policy(lf, static_cast(atoi(argv[3]))); - linphone_friend_send_subscribe(lf, atoi(argv[4])); + linphone_friend_send_subscribe(lf, !!atoi(argv[4])); linphone_friend_set_ref_key(lf, ms_strdup(argv[5])); - lf->presence_received = atoi(argv[9]); + lf->presence_received = !!atoi(argv[9]); lf->storage_id = storage_id; *list = bctbx_list_append(*list, linphone_friend_ref(lf)); diff --git a/coreapi/lime.c b/coreapi/lime.c index 80ebfefc1..5e4e4e209 100644 --- a/coreapi/lime.c +++ b/coreapi/lime.c @@ -144,7 +144,7 @@ int lime_getCachedSndKeysByURI(void *cachedb, limeURIKeys_t *associatedKeys) { /* check validity */ bctbx_get_utc_cur_time(¤tTimeSpec); if (validityTimeSpec.tv_sec == 0 || bctbx_timespec_compare(¤tTimeSpec, &validityTimeSpec)<0) { - associatedKeys->associatedZIDNumber +=1; + associatedKeys->associatedZIDNumber++; /* extend array of pointer to limeKey_t structures to add the one we found */ associatedKeys->peerKeys = (limeKey_t **)bctbx_realloc(associatedKeys->peerKeys, (associatedKeys->associatedZIDNumber)*sizeof(limeKey_t *)); @@ -257,14 +257,14 @@ int lime_setCachedKey(void *cachedb, limeKey_t *associatedKey, uint8_t role, uin uint8_t *colValues[4]; uint8_t sessionIndex[4]; /* buffer to hold the uint32_t buffer index in big endian */ size_t colLength[] = {32, 32, 4, 8}; /* data length: keys and session ID : 32 bytes, Index: 4 bytes(uint32_t), validity : 8 bytes(UTC time as int64_t) */ - int colNums; + uint8_t colNums; if (cachedb == NULL || associatedKey == NULL) { /* there is no cache return error */ return LIME_INVALID_CACHE; } /* wrap values to be written */ - sessionIndex[0] = (associatedKey->sessionIndex>>24)&0xFF; + sessionIndex[0] = (uint8_t)((associatedKey->sessionIndex>>24)&0xFF); sessionIndex[1] = (associatedKey->sessionIndex>>16)&0xFF; sessionIndex[2] = (associatedKey->sessionIndex>>8)&0xFF; sessionIndex[3] = (associatedKey->sessionIndex)&0xFF; @@ -277,14 +277,14 @@ int lime_setCachedKey(void *cachedb, limeKey_t *associatedKey, uint8_t role, uin bctbx_get_utc_cur_time(¤tTime); bctbx_timespec_add(¤tTime, validityTimeSpan); /* store the int64_t in big endian in the cache(cache is not typed, all data seen as blob) */ - colValues[3][0] = (currentTime.tv_sec>>56)&0xFF; - colValues[3][1] = (currentTime.tv_sec>>48)&0xFF; - colValues[3][2] = (currentTime.tv_sec>>40)&0xFF; - colValues[3][3] = (currentTime.tv_sec>>32)&0xFF; - colValues[3][4] = (currentTime.tv_sec>>24)&0xFF; - colValues[3][5] = (currentTime.tv_sec>>16)&0xFF; - colValues[3][6] = (currentTime.tv_sec>>8)&0xFF; - colValues[3][7] = (currentTime.tv_sec)&0xFF; + colValues[3][0] = (uint8_t)((currentTime.tv_sec>>56)&0xFF); + colValues[3][1] = (uint8_t)((currentTime.tv_sec>>48)&0xFF); + colValues[3][2] = (uint8_t)((currentTime.tv_sec>>40)&0xFF); + colValues[3][3] = (uint8_t)((currentTime.tv_sec>>32)&0xFF); + colValues[3][4] = (uint8_t)((currentTime.tv_sec>>24)&0xFF); + colValues[3][5] = (uint8_t)((currentTime.tv_sec>>16)&0xFF); + colValues[3][6] = (uint8_t)((currentTime.tv_sec>>8)&0xFF); + colValues[3][7] = (uint8_t)((currentTime.tv_sec)&0xFF); colNums = 4; } else { @@ -292,7 +292,11 @@ int lime_setCachedKey(void *cachedb, limeKey_t *associatedKey, uint8_t role, uin } /* update cache */ - return bzrtp_cache_write(cachedb, associatedKey->zuid, "lime", role==LIME_SENDER?colNamesSender:colNamesReceiver, colValues, colLength, colNums); + return bzrtp_cache_write( + cachedb, associatedKey->zuid, "lime", + role == LIME_SENDER ? colNamesSender : colNamesReceiver, + colValues, colLength, colNums + ); } /** @@ -596,7 +600,7 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se /* retrieve selfZID from cache, and convert it to an Hexa buffer to easily match it against hex string containg in xml message as pzid */ if (bzrtp_getSelfZID(cachedb, selfURI, selfZid, NULL) != 0) { - ms_error("[LIME] Couldn't get self ZID"); + ms_error("[LIME] Couldn't get self ZID"); return LIME_UNABLE_TO_DECRYPT_MESSAGE; } bctbx_int8_to_str(selfZidHex, selfZid, 12); @@ -606,13 +610,13 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error); xml_ctx->doc = xmlReadDoc((const unsigned char*)message, 0, NULL, 0); if (xml_ctx->doc == NULL) { - ms_error("[LIME] XML doc is null"); + ms_error("[LIME] XML doc is null"); retval = LIME_INVALID_ENCRYPTED_MESSAGE; goto error; } if (linphone_create_xml_xpath_context(xml_ctx) < 0) { - ms_error("[LIME] Couldn't create xml xpath context"); + ms_error("[LIME] Couldn't create xml xpath context"); retval = LIME_INVALID_ENCRYPTED_MESSAGE; goto error; } @@ -627,7 +631,7 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se /* Get the matching key from cache */ retval = lime_getCachedRcvKeyByZid(cachedb, &associatedKey, selfURI, peerURI); if (retval != 0) { - ms_error("[LIME] Couldn't get cache rcv key by ZID"); + ms_error("[LIME] Couldn't get cache rcv key by ZID"); goto error; } @@ -636,7 +640,7 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se if ((msg_object != NULL) && (msg_object->nodesetval != NULL)) { for (i = 1; i <= msg_object->nodesetval->nodeNr; i++) { char *currentZidHex; - + char *encryptedMessageb64; char *encryptedContentTypeb64; snprintf(xpath_str, sizeof(xpath_str), "/doc/msg[%i]/pzid", i); @@ -674,7 +678,7 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se /* do we have retrieved correctly all the needed data */ if (encryptedMessage == NULL) { - ms_error("[LIME] Encrypted message is null, something went wrong..."); + ms_error("[LIME] Encrypted message is null, something went wrong..."); retval = LIME_UNABLE_TO_DECRYPT_MESSAGE; goto error; } @@ -684,7 +688,7 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se /* something wen't wrong with the cache, this shall never happen */ uint8_t associatedKeyIndexHex[9]; bctbx_uint32_to_str(associatedKeyIndexHex, associatedKey.sessionIndex); - ms_error("[LIME] Session index [%s] < associated key's session index [%s], should not happen !", sessionIndexHex, associatedKeyIndexHex); + ms_error("[LIME] Session index [%s] < associated key's session index [%s], should not happen !", sessionIndexHex, associatedKeyIndexHex); ms_free(encryptedMessage); retval = LIME_UNABLE_TO_DECRYPT_MESSAGE; goto error; @@ -692,7 +696,7 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se if ((usedSessionIndex - associatedKey.sessionIndex > MAX_DERIVATION_NUMBER) ) { /* we missed to many messages, ask for a cache reset via a ZRTP call */ - ms_error("[LIME] Too many messages missed (%i), cache should be reset by ZRTP call", usedSessionIndex - associatedKey.sessionIndex); + ms_error("[LIME] Too many messages missed (%i), cache should be reset by ZRTP call", usedSessionIndex - associatedKey.sessionIndex); ms_free(encryptedMessage); retval = LIME_UNABLE_TO_DECRYPT_MESSAGE; goto error; @@ -701,7 +705,7 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se if (associatedKey.sessionIndex != usedSessionIndex) { uint8_t associatedKeyIndexHex[9]; bctbx_uint32_to_str(associatedKeyIndexHex, associatedKey.sessionIndex); - ms_warning("LIME] unexpected session index [%s] received from [%s] (expected [%s]), [%i] messages will be discarded", + ms_warning("LIME] unexpected session index [%s] received from [%s] (expected [%s]), [%i] messages will be discarded", sessionIndexHex, peerURI, associatedKeyIndexHex, usedSessionIndex-associatedKey.sessionIndex); } @@ -716,7 +720,7 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se if (retval != 0) { ms_free(*output); *output = NULL; - ms_error("[LIME] Couldn't decrypt message"); + ms_error("[LIME] Couldn't decrypt message"); retval = LIME_UNABLE_TO_DECRYPT_MESSAGE; goto error; } @@ -729,7 +733,7 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se if (retval != 0) { ms_free(*content_type); *content_type = NULL; - ms_error("[LIME] Couldn't decrypt content type"); + ms_error("[LIME] Couldn't decrypt content type"); retval = LIME_UNABLE_TO_DECRYPT_MESSAGE; goto error; } @@ -758,7 +762,7 @@ bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr) { bool_t res; limeURIKeys_t associatedKeys; char *peer = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); - + /* retrieve keys associated to the peer URI */ associatedKeys.peerURI = bctbx_strdup(peer); associatedKeys.selfURI = NULL; /* TODO : there is no sender associated to chatroom so check for any local URI available, shall we add sender to chatroom? */ @@ -798,7 +802,7 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEn } peerUri = linphone_address_as_string_uri_only(msg->from); selfUri = linphone_address_as_string_uri_only(msg->to); - retval = lime_decryptMultipartMessage(zrtp_cache_db, (uint8_t *)msg->message, selfUri, peerUri, &decrypted_body, &decrypted_content_type, + retval = lime_decryptMultipartMessage(zrtp_cache_db, (uint8_t *)msg->message, selfUri, peerUri, &decrypted_body, &decrypted_content_type, bctbx_time_string_to_sec(lp_config_get_string(lc->config, "sip", "lime_key_validity", "0"))); ms_free(peerUri); ms_free(selfUri); @@ -887,11 +891,11 @@ int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneImEncryptionEn int lime_im_encryption_engine_process_downloading_file_cb(LinphoneImEncryptionEngine *engine, LinphoneChatMessage *msg, size_t offset, const uint8_t *buffer, size_t size, uint8_t *decrypted_buffer) { if (linphone_content_get_key(msg->file_transfer_information) == NULL) return -1; - + if (buffer == NULL || size == 0) { return lime_decryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information), NULL, 0, NULL, NULL); } - + return lime_decryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information), (unsigned char *)linphone_content_get_key(msg->file_transfer_information), size, (char *)decrypted_buffer, (char *)buffer); @@ -900,17 +904,17 @@ int lime_im_encryption_engine_process_downloading_file_cb(LinphoneImEncryptionEn int lime_im_encryption_engine_process_uploading_file_cb(LinphoneImEncryptionEngine *engine, LinphoneChatMessage *msg, size_t offset, const uint8_t *buffer, size_t *size, uint8_t *encrypted_buffer) { size_t file_size = linphone_content_get_size(msg->file_transfer_information); if (linphone_content_get_key(msg->file_transfer_information) == NULL) return -1; - + if (buffer == NULL || *size == 0) { return lime_encryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information), NULL, 0, NULL, NULL); } - + if (file_size == 0) { ms_warning("File size has not been set, encryption will fail if not done in one step (if file is larger than 16K)"); } else if (offset + *size < file_size) { *size -= (*size % 16); } - + return lime_encryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information), (unsigned char *)linphone_content_get_key(msg->file_transfer_information), *size, (char *)buffer, (char *)encrypted_buffer); @@ -972,7 +976,7 @@ bool_t lime_im_encryption_engine_is_file_encryption_enabled_cb(LinphoneImEncrypt return FALSE; } void lime_im_encryption_engine_generate_file_transfer_key_cb(LinphoneImEncryptionEngine *engine, LinphoneChatRoom *room, LinphoneChatMessage *msg) { - + } #endif /* HAVE_LIME */ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 516dd216c..27121210c 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -837,7 +837,7 @@ float linphone_call_stats_get_sender_loss_rate(const LinphoneCallStats *stats) { rtcp_rewind(stats->sent_rtcp); if (!srb) return 0.0; - return 100.0f * report_block_get_fraction_lost(srb) / 256.0f; + return 100.0f * (float)report_block_get_fraction_lost(srb) / 256.0f; } float linphone_call_stats_get_receiver_loss_rate(const LinphoneCallStats *stats) { @@ -859,7 +859,7 @@ float linphone_call_stats_get_receiver_loss_rate(const LinphoneCallStats *stats) rtcp_rewind(stats->received_rtcp); if (!rrb) return 0.0; - return 100.0f * report_block_get_fraction_lost(rrb) / 256.0f; + return 100.0f * (float)report_block_get_fraction_lost(rrb) / 256.0f; } float linphone_call_stats_get_local_loss_rate(const LinphoneCallStats *stats) { diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 00a899938..5a6a7e229 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -445,8 +445,8 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneCore, belle_sip_object_t, ); void lc_callback_obj_init(LCCallbackObj *obj,LinphoneCoreCbFunc func,void* ud) { - obj->_func=func; - obj->_user_data=ud; + obj->_func=func; + obj->_user_data=ud; } int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){ @@ -1094,7 +1094,7 @@ static void net_config_read(LinphoneCore *lc) { if (tmpstr!=NULL && (strlen(tmpstr)<1)) tmpstr=NULL; linphone_core_set_nat_address(lc,tmpstr); tmp=lp_config_get_int(lc->config,"net","nat_sdp_only",0); - lc->net_conf.nat_sdp_only=tmp; + lc->net_conf.nat_sdp_only=!!tmp; tmp=lp_config_get_int(lc->config,"net","mtu",1300); linphone_core_set_mtu(lc,tmp); tmp=lp_config_get_int(lc->config,"net","download_ptime",-1); @@ -1103,9 +1103,9 @@ static void net_config_read(LinphoneCore *lc) { linphone_core_set_download_ptime(lc,tmp); } tmp = lp_config_get_int(lc->config, "net", "dns_srv_enabled", 1); - linphone_core_enable_dns_srv(lc, tmp); + linphone_core_enable_dns_srv(lc, !!tmp); tmp = lp_config_get_int(lc->config, "net", "dns_search_enabled", 1); - linphone_core_enable_dns_search(lc, tmp); + linphone_core_enable_dns_search(lc, !!tmp); } static void build_sound_devices_table(LinphoneCore *lc){ @@ -1245,12 +1245,10 @@ static void sound_config_read(LinphoneCore *lc) tmp=FALSE; /* on iOS we have builtin echo cancellation.*/ #endif tmp=lp_config_get_int(lc->config,"sound","echocancellation",tmp); - linphone_core_enable_echo_cancellation(lc,tmp); + linphone_core_enable_echo_cancellation(lc, !!tmp); linphone_core_set_echo_canceller_filter_name(lc, linphone_core_get_echo_canceller_filter_name(lc)); - linphone_core_enable_echo_limiter(lc, - lp_config_get_int(lc->config,"sound","echolimiter",0)); - linphone_core_enable_agc(lc, - lp_config_get_int(lc->config,"sound","agc",0)); + linphone_core_enable_echo_limiter(lc, !!lp_config_get_int(lc->config,"sound","echolimiter",0)); + linphone_core_enable_agc(lc, !!lp_config_get_int(lc->config,"sound","agc",0)); linphone_core_set_playback_gain_db (lc,lp_config_get_float(lc->config,"sound","playback_gain_db",0)); linphone_core_set_mic_gain_db (lc,lp_config_get_float(lc->config,"sound","mic_gain_db",0)); @@ -1283,8 +1281,8 @@ static void certificates_config_read(LinphoneCore *lc) { } } linphone_core_set_root_ca(lc,rootca); - linphone_core_verify_server_certificates(lc,lp_config_get_int(lc->config,"sip","verify_server_certs",TRUE)); - linphone_core_verify_server_cn(lc,lp_config_get_int(lc->config,"sip","verify_server_cn",TRUE)); + linphone_core_verify_server_certificates(lc, !!lp_config_get_int(lc->config,"sip","verify_server_certs",TRUE)); + linphone_core_verify_server_cn(lc, !!lp_config_get_int(lc->config,"sip","verify_server_cn",TRUE)); bctbx_free(root_ca_path); } @@ -1299,8 +1297,8 @@ static void sip_config_read(LinphoneCore *lc) { sal_use_session_timers(lc->sal,200); } - sal_use_no_initial_route(lc->sal,lp_config_get_int(lc->config,"sip","use_no_initial_route",0)); - sal_use_rport(lc->sal,lp_config_get_int(lc->config,"sip","use_rport",1)); + sal_use_no_initial_route(lc->sal, !!lp_config_get_int(lc->config,"sip","use_no_initial_route",0)); + sal_use_rport(lc->sal, !!lp_config_get_int(lc->config,"sip","use_rport",1)); if (!lp_config_get_int(lc->config,"sip","ipv6_migration_done",FALSE) && lp_config_has_entry(lc->config,"sip","use_ipv6")) { lp_config_clean_entry(lc->config,"sip","use_ipv6"); @@ -1308,7 +1306,7 @@ static void sip_config_read(LinphoneCore *lc) { ms_message("IPV6 settings migration done."); } - lc->sip_conf.ipv6_enabled=lp_config_get_int(lc->config,"sip","use_ipv6",ipv6_default); + lc->sip_conf.ipv6_enabled = !!lp_config_get_int(lc->config,"sip","use_ipv6",ipv6_default); memset(&tr,0,sizeof(tr)); @@ -1343,7 +1341,7 @@ static void sip_config_read(LinphoneCore *lc) { } tmp=lp_config_get_int(lc->config,"sip","guess_hostname",1); - linphone_core_set_guess_hostname(lc,tmp); + linphone_core_set_guess_hostname(lc, !!tmp); tmp=lp_config_get_int(lc->config,"sip","lime",LinphoneLimeDisabled); linphone_core_enable_lime(lc,static_cast(tmp)); @@ -1385,23 +1383,23 @@ static void sip_config_read(LinphoneCore *lc) { linphone_core_set_media_encryption(lc,linphone_core_get_media_encryption(lc)); /*for tuning or test*/ - lc->sip_conf.sdp_200_ack=lp_config_get_int(lc->config,"sip","sdp_200_ack",0); + lc->sip_conf.sdp_200_ack = !!lp_config_get_int(lc->config,"sip","sdp_200_ack",0); lc->sip_conf.register_only_when_network_is_up= - lp_config_get_int(lc->config,"sip","register_only_when_network_is_up",1); + !!lp_config_get_int(lc->config,"sip","register_only_when_network_is_up",1); lc->sip_conf.register_only_when_upnp_is_ok= - lp_config_get_int(lc->config,"sip","register_only_when_upnp_is_ok",1); - lc->sip_conf.ping_with_options=lp_config_get_int(lc->config,"sip","ping_with_options",0); - lc->sip_conf.auto_net_state_mon=lp_config_get_int(lc->config,"sip","auto_net_state_mon",1); - lc->sip_conf.keepalive_period=lp_config_get_int(lc->config,"sip","keepalive_period",10000); - lc->sip_conf.tcp_tls_keepalive=lp_config_get_int(lc->config,"sip","tcp_tls_keepalive",0); + !!lp_config_get_int(lc->config,"sip","register_only_when_upnp_is_ok",1); + lc->sip_conf.ping_with_options= !!lp_config_get_int(lc->config,"sip","ping_with_options",0); + lc->sip_conf.auto_net_state_mon = !!lp_config_get_int(lc->config,"sip","auto_net_state_mon",1); + lc->sip_conf.keepalive_period = lp_config_get_int(lc->config,"sip","keepalive_period",10000); + lc->sip_conf.tcp_tls_keepalive = !!lp_config_get_int(lc->config,"sip","tcp_tls_keepalive",0); linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0)); - sal_use_one_matching_codec_policy(lc->sal,lp_config_get_int(lc->config,"sip","only_one_codec",0)); - sal_use_dates(lc->sal,lp_config_get_int(lc->config,"sip","put_date",0)); - sal_enable_sip_update_method(lc->sal,lp_config_get_int(lc->config,"sip","sip_update",1)); - lc->sip_conf.vfu_with_info=lp_config_get_int(lc->config,"sip","vfu_with_info",1); + sal_use_one_matching_codec_policy(lc->sal, !!lp_config_get_int(lc->config,"sip","only_one_codec",0)); + sal_use_dates(lc->sal, !!lp_config_get_int(lc->config,"sip","put_date",0)); + sal_enable_sip_update_method(lc->sal, !!lp_config_get_int(lc->config,"sip","sip_update",1)); + lc->sip_conf.vfu_with_info = !!lp_config_get_int(lc->config,"sip","vfu_with_info",1); linphone_core_set_sip_transport_timeout(lc, lp_config_get_int(lc->config, "sip", "transport_timeout", 63000)); sal_set_supported_tags(lc->sal,lp_config_get_string(lc->config,"sip","supported","replaces, outbound, gruu")); - lc->sip_conf.save_auth_info = lp_config_get_int(lc->config, "sip", "save_auth_info", 1); + lc->sip_conf.save_auth_info = !!lp_config_get_int(lc->config, "sip", "save_auth_info", 1); linphone_core_create_im_notif_policy(lc); } @@ -1448,11 +1446,11 @@ static void rtp_config_read(LinphoneCore *lc) { linphone_core_set_video_jittcomp(lc,jitt_comp); nortp_timeout=lp_config_get_int(lc->config,"rtp","nortp_timeout",30); linphone_core_set_nortp_timeout(lc,nortp_timeout); - rtp_no_xmit_on_audio_mute=lp_config_get_int(lc->config,"rtp","rtp_no_xmit_on_audio_mute",FALSE); + rtp_no_xmit_on_audio_mute = !!lp_config_get_int(lc->config,"rtp","rtp_no_xmit_on_audio_mute",FALSE); linphone_core_set_rtp_no_xmit_on_audio_mute(lc,rtp_no_xmit_on_audio_mute); - adaptive_jitt_comp_enabled = lp_config_get_int(lc->config, "rtp", "audio_adaptive_jitt_comp_enabled", TRUE); + adaptive_jitt_comp_enabled = !!lp_config_get_int(lc->config, "rtp", "audio_adaptive_jitt_comp_enabled", TRUE); linphone_core_enable_audio_adaptive_jittcomp(lc, adaptive_jitt_comp_enabled); - adaptive_jitt_comp_enabled = lp_config_get_int(lc->config, "rtp", "video_adaptive_jitt_comp_enabled", TRUE); + adaptive_jitt_comp_enabled = !!lp_config_get_int(lc->config, "rtp", "video_adaptive_jitt_comp_enabled", TRUE); linphone_core_enable_video_adaptive_jittcomp(lc, adaptive_jitt_comp_enabled); lc->rtp_conf.disable_upnp = lp_config_get_int(lc->config, "rtp", "disable_upnp", FALSE); linphone_core_set_avpf_mode(lc,static_cast(lp_config_get_int(lc->config,"rtp","avpf",LinphoneAVPFDisabled))); @@ -1461,7 +1459,7 @@ static void rtp_config_read(LinphoneCore *lc) { else lc->rtp_conf.audio_multicast_addr=ms_strdup("224.1.2.3"); if ((tmp_int=lp_config_get_int(lc->config,"rtp","audio_multicast_enabled",-1)) >-1) - linphone_core_enable_audio_multicast(lc,tmp_int); + linphone_core_enable_audio_multicast(lc, !!tmp_int); if ((tmp_int=lp_config_get_int(lc->config,"rtp","audio_multicast_ttl",-1))>0) linphone_core_set_audio_multicast_ttl(lc,tmp_int); else @@ -1475,7 +1473,7 @@ static void rtp_config_read(LinphoneCore *lc) { else lc->rtp_conf.video_multicast_ttl=1;/*local network*/ if ((tmp_int=lp_config_get_int(lc->config,"rtp","video_multicast_enabled",-1)) >0) - linphone_core_enable_video_multicast(lc,tmp_int); + linphone_core_enable_video_multicast(lc, !!tmp_int); } static PayloadType * find_payload(const bctbx_list_t *default_list, const char *mime_type, int clock_rate, int channels, const char *recv_fmtp){ @@ -1616,7 +1614,7 @@ static bctbx_list_t *add_missing_supported_codecs(LinphoneCore *lc, const bctbx_ } last_seen = pt; ms_message("Supported codec %s/%i fmtp=%s automatically added to codec list.", pt->mime_type, - pt->clock_rate, pt->recv_fmtp ? pt->recv_fmtp : ""); + pt->clock_rate, pt->recv_fmtp ? pt->recv_fmtp : ""); }else{ last_seen = (PayloadType*)elem2->data; } @@ -1727,7 +1725,6 @@ static void build_video_devices_table(LinphoneCore *lc){ static void video_config_read(LinphoneCore *lc){ #ifdef VIDEO_ENABLED - int capture, display, self_view, reuse_source; int automatic_video=1; const char *str; LinphoneVideoPolicy vpol; @@ -1749,17 +1746,13 @@ static void video_config_read(LinphoneCore *lc){ #if defined(__ANDROID__) || TARGET_OS_IPHONE automatic_video=0; #endif - capture=lp_config_get_int(lc->config,"video","capture",1); - display=lp_config_get_int(lc->config,"video","display",1); - self_view=lp_config_get_int(lc->config,"video","self_view",1); - reuse_source=lp_config_get_int(lc->config,"video","reuse_source",0); - vpol.automatically_initiate=lp_config_get_int(lc->config,"video","automatically_initiate",automatic_video); - vpol.automatically_accept=lp_config_get_int(lc->config,"video","automatically_accept",automatic_video); - linphone_core_enable_video_capture(lc, capture); - linphone_core_enable_video_display(lc, display); - linphone_core_enable_video_preview(lc,lp_config_get_int(lc->config,"video","show_local",0)); - linphone_core_enable_self_view(lc,self_view); - linphone_core_enable_video_source_reuse(lc, reuse_source); + vpol.automatically_initiate = !!lp_config_get_int(lc->config,"video","automatically_initiate",automatic_video); + vpol.automatically_accept = !!lp_config_get_int(lc->config,"video","automatically_accept",automatic_video); + linphone_core_enable_video_capture(lc, !!lp_config_get_int(lc->config,"video","capture",1)); + linphone_core_enable_video_display(lc, !!lp_config_get_int(lc->config,"video","display",1)); + linphone_core_enable_video_preview(lc, !!lp_config_get_int(lc->config,"video","show_local",0)); + linphone_core_enable_self_view(lc, !!lp_config_get_int(lc->config,"video","self_view",1)); + linphone_core_enable_video_source_reuse(lc, !!lp_config_get_int(lc->config,"video","reuse_source",0)); linphone_core_set_video_policy(lc,&vpol); #endif } @@ -1815,7 +1808,7 @@ void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled } bool_t linphone_core_adaptive_rate_control_enabled(const LinphoneCore *lc){ - return lp_config_get_int(lc->config,"net","adaptive_rate_control",TRUE); + return !!lp_config_get_int(lc->config,"net","adaptive_rate_control",TRUE); } void linphone_core_set_adaptive_rate_algorithm(LinphoneCore *lc, const char* algorithm){ @@ -1836,7 +1829,7 @@ const char * linphone_core_get_adaptive_rate_algorithm(const LinphoneCore *lc){ } bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc){ - return lp_config_get_int(lc->config,"rtp","rtcp_enabled",TRUE); + return !!lp_config_get_int(lc->config,"rtp","rtcp_enabled",TRUE); } void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw){ @@ -1979,7 +1972,7 @@ static void misc_config_read(LinphoneCore *lc) { sal_set_uuid(lc->sal, uuid); lc->user_certificates_path=ms_strdup(lp_config_get_string(config,"misc","user_certificates_path",".")); - lc->send_call_stats_periodical_updates = lp_config_get_int(config, "misc", "send_call_stats_periodical_updates", 0); + lc->send_call_stats_periodical_updates = !!lp_config_get_int(config, "misc", "send_call_stats_periodical_updates", 0); } void linphone_core_reload_ms_plugins(LinphoneCore *lc, const char *path){ @@ -2143,7 +2136,7 @@ static void linphone_core_internal_subscription_state_changed(LinphoneCore *lc, if (strcasecmp(linphone_event_get_name(lev), "Presence") == 0) { linphone_friend_list_subscription_state_changed(lc, lev, state); } else if (strcmp(linphone_event_get_name(lev), "Conference") == 0) { - + } } @@ -2184,11 +2177,11 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig LinphoneCoreCbs *internal_cbs = _linphone_core_cbs_new(); const char *msplugins_dir; const char *image_resources_dir; - + bctbx_init_logger(FALSE); if (liblinphone_user_log_func && liblinphone_current_log_func == NULL) bctbx_set_log_handler(liblinphone_current_log_func=liblinphone_user_log_func); /*default value*/ - + ms_message("Initializing LinphoneCore %s", linphone_core_get_version()); lc->config=lp_config_ref(config); @@ -2218,7 +2211,7 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig linphone_core_set_state(lc,LinphoneGlobalStartup,"Starting up"); ortp_set_log_handler(NULL); /*remove ortp default log handler*/ ortp_init(); - + linphone_core_activate_log_serialization_if_needed(); msplugins_dir = linphone_factory_get_msplugins_dir(lfactory); @@ -2523,7 +2516,7 @@ void linphone_core_enable_generic_comfort_noise(LinphoneCore *lc, bool_t enabled } bool_t linphone_core_generic_comfort_noise_enabled(const LinphoneCore *lc){ - return lp_config_get_int(lc->config, "misc", "use_cn", FALSE); + return !!lp_config_get_int(lc->config, "misc", "use_cn", FALSE); } const bctbx_list_t* linphone_core_get_friend_list(const LinphoneCore *lc) { @@ -2720,7 +2713,7 @@ void linphone_core_set_nortp_timeout(LinphoneCore *lc, int nortp_timeout){ } bool_t linphone_core_get_use_info_for_dtmf(LinphoneCore *lc) { - return lp_config_get_int(lc->config, "sip", "use_info", 0); + return !!lp_config_get_int(lc->config, "sip", "use_info", 0); } void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc,bool_t use_info) { @@ -2730,7 +2723,7 @@ void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc,bool_t use_info) { } bool_t linphone_core_get_use_rfc2833_for_dtmf(LinphoneCore *lc) { - return lp_config_get_int(lc->config, "sip", "use_rfc2833", 1); + return !!lp_config_get_int(lc->config, "sip", "use_rfc2833", 1); } void linphone_core_set_use_rfc2833_for_dtmf(LinphoneCore *lc,bool_t use_rfc2833) { @@ -2841,7 +2834,7 @@ int _linphone_core_apply_transports(LinphoneCore *lc){ } bool_t linphone_core_sip_transport_supported(const LinphoneCore *lc, LinphoneTransportType tp){ - return sal_transport_available(lc->sal,(SalTransport)tp); + return !!sal_transport_available(lc->sal,(SalTransport)tp); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneTransports); @@ -3350,22 +3343,22 @@ void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, L } /* - returns the ideal route set for making an operation through this proxy. - The list must be freed as well as the SalAddress content + returns the ideal route set for making an operation through this proxy. + The list must be freed as well as the SalAddress content - rfc3608 - 6.1. Procedures at the UA + rfc3608 + 6.1. Procedures at the UA - /.../ - For example, some devices will use locally-configured - explicit loose routing to reach a next-hop proxy, and others will use - a default outbound-proxy routing rule. However, for the result to - function, the combination MUST provide valid routing in the local - environment. In general, the service route set is appended to any - locally configured route needed to egress the access proxy chain. - Systems designers must match the service routing policy of their - nodes with the basic SIP routing policy in order to get a workable - system. + /.../ + For example, some devices will use locally-configured + explicit loose routing to reach a next-hop proxy, and others will use + a default outbound-proxy routing rule. However, for the result to + function, the combination MUST provide valid routing in the local + environment. In general, the service route set is appended to any + locally configured route needed to egress the access proxy chain. + Systems designers must match the service routing policy of their + nodes with the basic SIP routing policy in order to get a workable + system. */ static bctbx_list_t *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneAddress *dest){ bctbx_list_t *ret=NULL; @@ -3444,7 +3437,7 @@ const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAdd LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url){ LinphoneCall *call; LinphoneCallParams *p=linphone_core_create_call_params(lc, NULL); - linphone_call_params_enable_video(p, linphone_call_params_video_enabled(p) & !!lc->video_policy.automatically_initiate); + linphone_call_params_enable_video(p, linphone_call_params_video_enabled(p) && !!lc->video_policy.automatically_initiate); call=linphone_core_invite_with_params(lc,url,p); linphone_call_params_unref(p); return call; @@ -3464,7 +3457,7 @@ LinphoneCall * linphone_core_invite_with_params(LinphoneCore *lc, const char *ur LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr){ LinphoneCall *call; LinphoneCallParams *p=linphone_core_create_call_params(lc, NULL); - linphone_call_params_enable_video(p, linphone_call_params_video_enabled(p) & !!lc->video_policy.automatically_initiate); + linphone_call_params_enable_video(p, linphone_call_params_video_enabled(p) && !!lc->video_policy.automatically_initiate); call=linphone_core_invite_address_with_params (lc,addr,p); linphone_call_params_unref(p); return call; @@ -3506,7 +3499,7 @@ void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const Linphon SalAddress *new_contact = contact ? sal_address_clone(contact) : NULL; sal_op_set_and_clean_contact_address(proxy->op, new_contact); } - sal_op_cnx_ip_to_0000_if_sendonly_enable(op,lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0)); /*also set in linphone_call_new_incoming*/ + sal_op_cnx_ip_to_0000_if_sendonly_enable(op, !!lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0)); /*also set in linphone_call_new_incoming*/ } void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact) { linphone_configure_op_with_proxy(lc, op, dest, headers,with_contact,linphone_core_lookup_known_proxy(lc,dest)); @@ -3538,10 +3531,11 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const if (proxy!=NULL) { from=linphone_proxy_config_get_identity(proxy); linphone_call_params_enable_avpf(cp, linphone_proxy_config_avpf_enabled(proxy)); - linphone_call_params_set_avpf_rr_interval(cp, linphone_proxy_config_get_avpf_rr_interval(proxy) * 1000); + linphone_call_params_set_avpf_rr_interval(cp, (uint16_t)(linphone_proxy_config_get_avpf_rr_interval(proxy) * 1000)); }else{ linphone_call_params_enable_avpf(cp, linphone_core_get_avpf_mode(lc)==LinphoneAVPFEnabled); - if (linphone_call_params_avpf_enabled(cp)) linphone_call_params_set_avpf_rr_interval(cp, linphone_core_get_avpf_rr_interval(lc) * 1000); + if (linphone_call_params_avpf_enabled(cp)) + linphone_call_params_set_avpf_rr_interval(cp, (uint16_t)(linphone_core_get_avpf_rr_interval(lc) * 1000)); } /* if no proxy or no identity defined for this proxy, default to primary contact*/ @@ -4014,7 +4008,7 @@ int linphone_core_get_rec_level(LinphoneCore *lc) { void linphone_core_set_ring_level(LinphoneCore *lc, int level){ MSSndCard *sndcard; - lc->sound_conf.ring_lev=level; + lc->sound_conf.ring_lev = (char)level; sndcard=lc->sound_conf.ring_sndcard; if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_PLAYBACK,level); } @@ -4064,14 +4058,14 @@ float linphone_core_get_playback_gain_db(LinphoneCore *lc) { void linphone_core_set_play_level(LinphoneCore *lc, int level){ MSSndCard *sndcard; - lc->sound_conf.play_lev=level; + lc->sound_conf.play_lev = (char)level; sndcard=lc->sound_conf.play_sndcard; if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_PLAYBACK,level); } void linphone_core_set_rec_level(LinphoneCore *lc, int level) { MSSndCard *sndcard; - lc->sound_conf.rec_lev=level; + lc->sound_conf.rec_lev = (char)level; sndcard=lc->sound_conf.capt_sndcard; if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_CAPTURE,level); } @@ -4160,9 +4154,9 @@ const char** linphone_core_get_video_devices(const LinphoneCore *lc){ } void linphone_core_set_default_sound_devices(LinphoneCore *lc){ - linphone_core_set_ringer_device(lc, NULL); - linphone_core_set_playback_device(lc, NULL); - linphone_core_set_capture_device(lc, NULL); + linphone_core_set_ringer_device(lc, NULL); + linphone_core_set_playback_device(lc, NULL); + linphone_core_set_capture_device(lc, NULL); } void linphone_core_reload_sound_devices(LinphoneCore *lc){ @@ -4584,9 +4578,9 @@ void linphone_core_set_nat_policy(LinphoneCore *lc, LinphoneNatPolicy *policy) { linphone_nat_policy_save_to_config(lc->nat_policy); } - sal_nat_helper_enable(lc->sal, lp_config_get_int(lc->config, "net", "enable_nat_helper", 1)); + sal_nat_helper_enable(lc->sal, !!lp_config_get_int(lc->config, "net", "enable_nat_helper", 1)); sal_enable_auto_contacts(lc->sal, TRUE); - sal_use_rport(lc->sal, lp_config_get_int(lc->config, "sip", "use_rport", 1)); + sal_use_rport(lc->sal, !!lp_config_get_int(lc->config, "sip", "use_rport", 1)); if (lc->sip_conf.contact) update_primary_contact(lc); } @@ -5769,7 +5763,7 @@ void sip_config_uninit(LinphoneCore *lc) for(elem=config->proxies;elem!=NULL;elem=bctbx_list_next(elem)){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data); LinphoneRegistrationState state = linphone_proxy_config_get_state(cfg); - still_registered|=(state==LinphoneRegistrationOk||state==LinphoneRegistrationProgress); + still_registered = (state==LinphoneRegistrationOk||state==LinphoneRegistrationProgress); } ms_usleep(100000); } @@ -6202,8 +6196,8 @@ void linphone_core_soundcard_hint_check( LinphoneCore* lc){ bctbx_list_t* the_calls = lc->calls; LinphoneCall* call = NULL; bool_t dont_need_sound = TRUE; - bool_t use_rtp_io = lp_config_get_int(lc->config, "sound", "rtp_io", FALSE); - bool_t use_rtp_io_enable_local_output = lp_config_get_int(lc->config, "sound", "rtp_io_enable_local_output", FALSE); + bool_t use_rtp_io = !!lp_config_get_int(lc->config, "sound", "rtp_io", FALSE); + bool_t use_rtp_io_enable_local_output = !!lp_config_get_int(lc->config, "sound", "rtp_io_enable_local_output", FALSE); /* check if the remaining calls are paused */ while( the_calls ){ diff --git a/coreapi/lpc2xml.c b/coreapi/lpc2xml.c index b15186027..0fe709116 100644 --- a/coreapi/lpc2xml.c +++ b/coreapi/lpc2xml.c @@ -31,8 +31,8 @@ static xmlChar* convert_iso_to_utf8(const char *in) { int ret, size, out_size, temp; xmlCharEncodingHandlerPtr handler; - size = (int)strlen(in) + 1; - out_size = size * 2 - 1; + size = (int)strlen(in) + 1; + out_size = size * 2 - 1; out = reinterpret_cast(ms_malloc((size_t)out_size)); if (out) { @@ -41,7 +41,7 @@ static xmlChar* convert_iso_to_utf8(const char *in) { ms_free(out); return NULL; } - + temp = size-1; ret = handler->input(out, &out_size, (const xmlChar *)in, &temp); if (ret < 0 || temp - size + 1) { @@ -53,7 +53,7 @@ static xmlChar* convert_iso_to_utf8(const char *in) { } } return out; -} +} struct _lpc2xml_context { const LpConfig *lpc; @@ -131,7 +131,7 @@ static int processEntry(const char *section, const char *entry, xmlNode *node, l } lpc2xml_log(ctx, LPC2XML_MESSAGE, "Set %s|%s = %s", section, entry, content); converted_content = convert_iso_to_utf8(content); - + if (converted_content) { // xmlNodeSetContent expects special characters to be escaped, xmlNodeAddContent doesn't (and escapes what needs to be) xmlNodeSetContent(node, (const xmlChar *) ""); @@ -142,7 +142,7 @@ static int processEntry(const char *section, const char *entry, xmlNode *node, l xmlNodeSetContent(node, (const xmlChar *) ""); xmlNodeAddContent(node, (const xmlChar *) content); } - + if (lp_config_get_overwrite_flag_for_entry(ctx->lpc, section, entry) || lp_config_get_overwrite_flag_for_section(ctx->lpc, section)) { xmlSetProp(node, (const xmlChar *)"overwrite", (const xmlChar *) "true"); } @@ -166,7 +166,7 @@ static void processSection_cb(const char *entry, struct __processSectionCtx *ctx ctx->ret = 0; return; } - + if (lp_config_get_skip_flag_for_entry(ctx->ctx->lpc, ctx->section, entry)) { lpc2xml_log(ctx->ctx, LPC2XML_WARNING, "Skipped entry %s", entry); ctx->ret = 0; @@ -208,13 +208,13 @@ static void processConfig_cb(const char *section, struct __processConfigCtx *ctx if(ctx->ret == 0) { xmlNode *node; xmlAttr *name_attr; - + if (lp_config_get_skip_flag_for_section(ctx->ctx->lpc, section)) { lpc2xml_log(ctx->ctx, LPC2XML_WARNING, "Skipped section %s", section); ctx->ret = 0; return; } - + node = xmlNewChild(ctx->node, NULL, (const xmlChar *)"section", NULL); if(node == NULL) { lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Can't create \"section\" element"); @@ -299,7 +299,7 @@ int lpc2xml_convert_file(lpc2xml_context* context, const char *filename) { if(save_ctx != NULL) { ret = internal_convert_lpc2xml(context); if(ret == 0) { - ret = xmlSaveDoc(save_ctx, context->doc); + ret = (int)xmlSaveDoc(save_ctx, context->doc); if(ret != 0) { lpc2xml_log(context, LPC2XML_ERROR, "Can't save document"); lpc2xml_log(context, LPC2XML_ERROR, "%s", context->errorBuffer); @@ -322,7 +322,7 @@ int lpc2xml_convert_fd(lpc2xml_context* context, int fd) { if(save_ctx != NULL) { ret = internal_convert_lpc2xml(context); if(ret == 0) { - ret = xmlSaveDoc(save_ctx, context->doc); + ret = (int)xmlSaveDoc(save_ctx, context->doc); if(ret != 0) { lpc2xml_log(context, LPC2XML_ERROR, "Can't save document"); lpc2xml_log(context, LPC2XML_ERROR, "%s", context->errorBuffer); @@ -346,7 +346,7 @@ int lpc2xml_convert_string(lpc2xml_context* context, char **content) { if(save_ctx != NULL) { ret = internal_convert_lpc2xml(context); if(ret == 0) { - ret = xmlSaveDoc(save_ctx, context->doc); + ret = (int)xmlSaveDoc(save_ctx, context->doc); if(ret != 0) { lpc2xml_log(context, LPC2XML_ERROR, "Can't save document"); lpc2xml_log(context, LPC2XML_ERROR, "%s", context->errorBuffer); diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index 4c496a423..be86c9038 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -832,11 +832,11 @@ void linphone_config_set_skip_flag_for_section(LpConfig *lpconfig, const char *s void lp_item_write(LpItem *item, LpConfig *lpconfig){ int ret =-1 ; if (item->is_comment){ - ret =bctbx_file_fprintf(lpconfig->pFile, 0, "%s\n",item->value); + ret = (int)bctbx_file_fprintf(lpconfig->pFile, 0, "%s\n",item->value); } else if (item->value && item->value[0] != '\0' ){ - ret =bctbx_file_fprintf(lpconfig->pFile, 0, "%s=%s\n",item->key,item->value); + ret = (int)bctbx_file_fprintf(lpconfig->pFile, 0, "%s=%s\n",item->key,item->value); } else { diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 75b76246c..8bf1f1e45 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -64,7 +64,7 @@ static char *utf8_convert(const char *filename){ cb = iconv_open("UTF-8", nl_langinfo(CODESET)); if (cb != (iconv_t)-1) { int ret; - ret = iconv(cb, &inbuf, &inbyteleft, &outbuf, &outbyteleft); + ret = (int)iconv(cb, &inbuf, &inbyteleft, &outbuf, &outbyteleft); if(ret == -1) db_file_utf8[0] = '\0'; iconv_close(cb); } diff --git a/coreapi/misc.c b/coreapi/misc.c index 2eeb41c8e..f8c639a34 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -326,7 +326,7 @@ unsigned int linphone_core_get_audio_features(LinphoneCore *lc){ } bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc){ - return lp_config_get_int(lc->config,"sound","tone_indications",1); + return !!lp_config_get_int(lc->config,"sound","tone_indications",1); } int linphone_core_get_local_ip_for(int type, const char *dest, char *result){ @@ -835,7 +835,7 @@ bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc){ /* Clients don't really need rtp symmetric, unless they have a public IP address and want * to interoperate with natted client. This case is not frequent with client apps. */ - return lp_config_get_int(lc->config,"rtp","symmetric",0); + return !!lp_config_get_int(lc->config,"rtp","symmetric",0); } LinphoneStatus linphone_core_set_network_simulator_params(LinphoneCore *lc, const OrtpNetworkSimulatorParams *params){ diff --git a/coreapi/proxy.c b/coreapi/proxy.c index e3f3ce9cd..41fbf6144 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -116,24 +116,24 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *cf const char *nat_policy_ref = lc ? lp_config_get_default_string(lc->config, "proxy", "nat_policy_ref", NULL):NULL; cfg->lc = lc; cfg->expires = lc ? lp_config_get_default_int(lc->config, "proxy", "reg_expires", 3600) : 3600; - cfg->reg_sendregister = lc ? lp_config_get_default_int(lc->config, "proxy", "reg_sendregister", 1) : 1; + cfg->reg_sendregister = lc ? !!lp_config_get_default_int(lc->config, "proxy", "reg_sendregister", 1) : 1; cfg->dial_prefix = dial_prefix ? ms_strdup(dial_prefix) : NULL; - cfg->dial_escape_plus = lc ? lp_config_get_default_int(lc->config, "proxy", "dial_escape_plus", 0) : 0; + cfg->dial_escape_plus = lc ? !!lp_config_get_default_int(lc->config, "proxy", "dial_escape_plus", 0) : 0; cfg->privacy = lc ? lp_config_get_default_int(lc->config, "proxy", "privacy", LinphonePrivacyDefault) : LinphonePrivacyDefault; cfg->identity_address = identity ? linphone_address_new(identity) : NULL; cfg->reg_identity = cfg->identity_address ? linphone_address_as_string(cfg->identity_address) : NULL; cfg->reg_proxy = proxy ? ms_strdup(proxy) : NULL; cfg->reg_route = route ? ms_strdup(route) : NULL; cfg->realm = realm ? ms_strdup(realm) : NULL; - cfg->quality_reporting_enabled = lc ? lp_config_get_default_int(lc->config, "proxy", "quality_reporting_enabled", 0) : 0; + cfg->quality_reporting_enabled = lc ? !!lp_config_get_default_int(lc->config, "proxy", "quality_reporting_enabled", 0) : 0; cfg->quality_reporting_collector = quality_reporting_collector ? ms_strdup(quality_reporting_collector) : NULL; - cfg->quality_reporting_interval = lc ? lp_config_get_default_int(lc->config, "proxy", "quality_reporting_interval", 0) : 0; + cfg->quality_reporting_interval = lc ? !!lp_config_get_default_int(lc->config, "proxy", "quality_reporting_interval", 0) : 0; cfg->contact_params = contact_params ? ms_strdup(contact_params) : NULL; cfg->contact_uri_params = contact_uri_params ? ms_strdup(contact_uri_params) : NULL; cfg->avpf_mode = lc ? static_cast(lp_config_get_default_int(lc->config, "proxy", "avpf", LinphoneAVPFDefault)) : LinphoneAVPFDefault; - cfg->avpf_rr_interval = lc ? lp_config_get_default_int(lc->config, "proxy", "avpf_rr_interval", 5) : 5; + cfg->avpf_rr_interval = lc ? !!lp_config_get_default_int(lc->config, "proxy", "avpf_rr_interval", 5) : 5; cfg->publish_expires= lc ? lp_config_get_default_int(lc->config, "proxy", "publish_expires", -1) : -1; - cfg->publish = lc ? lp_config_get_default_int(lc->config, "proxy", "publish", FALSE) : FALSE; + cfg->publish = lc ? !!lp_config_get_default_int(lc->config, "proxy", "publish", FALSE) : FALSE; cfg->refkey = refkey ? ms_strdup(refkey) : NULL; if (nat_policy_ref) { LinphoneNatPolicy *policy = linphone_config_create_nat_policy_from_section(lc->config,nat_policy_ref); @@ -570,7 +570,7 @@ bool_t linphone_proxy_config_quality_reporting_enabled(LinphoneProxyConfig *cfg) } void linphone_proxy_config_set_quality_reporting_interval(LinphoneProxyConfig *cfg, int interval) { - cfg->quality_reporting_interval = interval; + cfg->quality_reporting_interval = !!interval; } int linphone_proxy_config_get_quality_reporting_interval(LinphoneProxyConfig *cfg) { @@ -1165,10 +1165,10 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC } #define CONFIGURE_BOOL_VALUE(cfg,config,key,param,param_name) \ - linphone_proxy_config_enable_##param(cfg,lp_config_get_int(config,key,param_name,linphone_proxy_config_##param##_enabled(cfg))); + linphone_proxy_config_enable_##param(cfg, !!lp_config_get_int(config,key,param_name,linphone_proxy_config_##param##_enabled(cfg))); #define CONFIGURE_INT_VALUE(cfg,config,key,param,param_name) \ - linphone_proxy_config_set_##param(cfg,lp_config_get_int(config,key,param_name,linphone_proxy_config_get_##param(cfg))); + linphone_proxy_config_set_##param(cfg, !!lp_config_get_int(config,key,param_name,linphone_proxy_config_get_##param(cfg))); LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore* lc, int index) { diff --git a/coreapi/siplogin.c b/coreapi/siplogin.c index 8cc115615..d657d7f70 100644 --- a/coreapi/siplogin.c +++ b/coreapi/siplogin.c @@ -35,7 +35,7 @@ static void guess_display_name(LinphoneAddress *from){ bool_t surname=0; for(it=linphone_address_get_username(from);*it!='\0';++it){ if (begin){ - *wptr=toupper(*it); + *wptr = (char)toupper(*it); begin=FALSE; }else if (*it=='.'){ if (surname) break; diff --git a/coreapi/sqlite3_bctbx_vfs.c b/coreapi/sqlite3_bctbx_vfs.c index 882ab7368..e43f961e8 100755 --- a/coreapi/sqlite3_bctbx_vfs.c +++ b/coreapi/sqlite3_bctbx_vfs.c @@ -77,7 +77,7 @@ static int sqlite3bctbx_Read(sqlite3_file *p, void *buf, int count, sqlite_int64 int ret; sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t*) p; if (pFile){ - ret = bctbx_file_read(pFile->pbctbx_file, buf, count, (off_t)offset); + ret = (int)bctbx_file_read(pFile->pbctbx_file, buf, count, (off_t)offset); if( ret==count ){ return SQLITE_OK; } @@ -106,7 +106,7 @@ static int sqlite3bctbx_Write(sqlite3_file *p, const void *buf, int count, sqlit sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t*) p; int ret; if (pFile ){ - ret = bctbx_file_write(pFile->pbctbx_file, buf, count, (off_t)offset); + ret = (int)bctbx_file_write(pFile->pbctbx_file, buf, count, (off_t)offset); if(ret > 0 ) return SQLITE_OK; else { return SQLITE_IOERR_WRITE; @@ -119,11 +119,11 @@ static int sqlite3bctbx_Write(sqlite3_file *p, const void *buf, int count, sqlit * TRuncates or extends a file depending on the size provided. * @param p sqlite3_file file handle pointer. * @param size New file size. - * @return SQLITE_OK on success, SQLITE_IOERR_TRUNCATE if an error occurred during truncate, - * SQLITE_ERROR if ther was a problem on the file descriptor. + * @return SQLITE_OK on success, SQLITE_IOERR_TRUNCATE if an error occurred during truncate, + * SQLITE_ERROR if ther was a problem on the file descriptor. */ static int sqlite3bctbx_Truncate(sqlite3_file *p, sqlite_int64 size){ - int rc; + int rc; sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t*) p; if (pFile->pbctbx_file){ rc = bctbx_file_truncate(pFile->pbctbx_file, size); @@ -259,7 +259,7 @@ static char* ConvertFromUtf8Filename(const char* fName){ char* convertedFilename; int nChar, nb_byte; LPWSTR wideFilename; - + nChar = MultiByteToWideChar(CP_UTF8, 0, fName, -1, NULL, 0); if (nChar == 0) return NULL; wideFilename = reinterpret_cast(bctbx_malloc(nChar*sizeof(wideFilename[0]))); @@ -269,7 +269,7 @@ static char* ConvertFromUtf8Filename(const char* fName){ bctbx_free(wideFilename); wideFilename = 0; } - + nb_byte = WideCharToMultiByte(CP_ACP, 0, wideFilename, -1, 0, 0, 0, 0); if (nb_byte == 0) return NULL; convertedFilename = reinterpret_cast(bctbx_malloc(nb_byte)); @@ -290,15 +290,14 @@ static char* ConvertFromUtf8Filename(const char* fName){ char *outbuf=db_file_locale, *inbuf=db_file_utf8; size_t inbyteleft = MAX_PATH_SIZE, outbyteleft = MAX_PATH_SIZE; iconv_t cb; - + if (strcasecmp("UTF-8", nl_langinfo(CODESET)) == 0) { strncpy(db_file_locale, fName, MAX_PATH_SIZE - 1); } else { strncpy(db_file_utf8, fName, MAX_PATH_SIZE-1); cb = iconv_open(nl_langinfo(CODESET), "UTF-8"); if (cb != (iconv_t)-1) { - int ret; - ret = iconv(cb, &inbuf, &inbyteleft, &outbuf, &outbyteleft); + int ret = (int)iconv(cb, &inbuf, &inbyteleft, &outbuf, &outbyteleft); if(ret == -1) db_file_locale[0] = '\0'; iconv_close(cb); } @@ -346,7 +345,7 @@ static int sqlite3bctbx_Open(sqlite3_vfs *pVfs, const char *fName, sqlite3_file if (pFile == NULL || fName == NULL){ return SQLITE_IOERR; } - + /* Set flags to open the file with */ if( flags&SQLITE_OPEN_EXCLUSIVE ) openFlags |= O_EXCL; if( flags&SQLITE_OPEN_CREATE ) openFlags |= O_CREAT; @@ -363,7 +362,7 @@ static int sqlite3bctbx_Open(sqlite3_vfs *pVfs, const char *fName, sqlite3_file } else { pFile->pbctbx_file = NULL; } - + if( pFile->pbctbx_file == NULL){ return SQLITE_CANTOPEN; } @@ -445,7 +444,7 @@ void sqlite3_bctbx_vfs_register( int makeDefault){ sqlite3_vfs* pDefault = sqlite3_vfs_find("unix-none"); #endif pVfsToUse->xCurrentTime = pDefault->xCurrentTime; - + pVfsToUse->xAccess = pDefault->xAccess; pVfsToUse->xFullPathname = pDefault->xFullPathname; diff --git a/coreapi/vcard.cc b/coreapi/vcard.cc index bd0d1fd1b..d020c78dc 100644 --- a/coreapi/vcard.cc +++ b/coreapi/vcard.cc @@ -432,7 +432,7 @@ bool_t linphone_vcard_compare_md5_hash(LinphoneVcard *vCard) { unsigned char previous_md5[VCARD_MD5_HASH_SIZE]; memcpy(previous_md5, vCard->md5, VCARD_MD5_HASH_SIZE); linphone_vcard_compute_md5_hash(vCard); - return memcmp(vCard->md5, previous_md5, VCARD_MD5_HASH_SIZE); + return !!memcmp(vCard->md5, previous_md5, VCARD_MD5_HASH_SIZE); } bool_t linphone_core_vcard_supported(void) { diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 41a2a2bfa..b9643220c 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -788,7 +788,7 @@ void CallSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg /* We already have an op for incoming calls */ d->op = op; sal_op_set_user_pointer(d->op, this); - sal_op_cnx_ip_to_0000_if_sendonly_enable(op, lp_config_get_default_int(linphone_core_get_config(d->core), + sal_op_cnx_ip_to_0000_if_sendonly_enable(op, !!lp_config_get_default_int(linphone_core_get_config(d->core), "sip", "cnx_ip_to_0000_if_sendonly_enabled", 0)); d->log->call_id = ms_strdup(sal_op_get_call_id(op)); /* Must be known at that time */ } diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index fa7be38c3..0f6ee3556 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -803,9 +803,9 @@ void MediaSessionPrivate::setCompatibleIncomingCallParams (SalMediaDescription * /* Handle AVPF, SRTP and DTLS */ params->enableAvpf(sal_media_description_has_avpf(md)); if (destProxy) - params->setAvpfRrInterval(linphone_proxy_config_get_avpf_rr_interval(destProxy) * 1000); + params->setAvpfRrInterval(static_cast(linphone_proxy_config_get_avpf_rr_interval(destProxy) * 1000)); else - params->setAvpfRrInterval(linphone_core_get_avpf_rr_interval(core) * 1000); + params->setAvpfRrInterval(static_cast(linphone_core_get_avpf_rr_interval(core) * 1000)); if (sal_media_description_has_zrtp(md) && linphone_core_media_encryption_supported(core, LinphoneMediaEncryptionZRTP)) params->setMediaEncryption(LinphoneMediaEncryptionZRTP); else if (sal_media_description_has_dtls(md) && media_stream_dtls_supported()) @@ -1440,8 +1440,8 @@ void MediaSessionPrivate::setupRtcpFb (SalMediaDescription *md) { for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (!sal_stream_description_active(&md->streams[i])) continue; - md->streams[i].rtcp_fb.generic_nack_enabled = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_fb_generic_nack_enabled", 0); - md->streams[i].rtcp_fb.tmmbr_enabled = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_fb_tmmbr_enabled", 1); + md->streams[i].rtcp_fb.generic_nack_enabled = !!lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_fb_generic_nack_enabled", 0); + md->streams[i].rtcp_fb.tmmbr_enabled = !!lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_fb_tmmbr_enabled", 1); md->streams[i].implicit_rtcp_fb = params->getPrivate()->implicitRtcpFbEnabled(); for (const bctbx_list_t *it = md->streams[i].payloads; it != nullptr; it = bctbx_list_next(it)) { OrtpPayloadType *pt = reinterpret_cast(bctbx_list_get_data(it)); @@ -1460,7 +1460,7 @@ void MediaSessionPrivate::setupRtcpFb (SalMediaDescription *md) { } void MediaSessionPrivate::setupRtcpXr (SalMediaDescription *md) { - md->rtcp_xr.enabled = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_xr_enabled", 1); + md->rtcp_xr.enabled = !!lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_xr_enabled", 1); if (md->rtcp_xr.enabled) { const char *rcvr_rtt_mode = lp_config_get_string(linphone_core_get_config(core), "rtp", "rtcp_xr_rcvr_rtt_mode", "all"); if (strcasecmp(rcvr_rtt_mode, "all") == 0) @@ -1471,10 +1471,10 @@ void MediaSessionPrivate::setupRtcpXr (SalMediaDescription *md) { md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttNone; if (md->rtcp_xr.rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) md->rtcp_xr.rcvr_rtt_max_size = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_xr_rcvr_rtt_max_size", 10000); - md->rtcp_xr.stat_summary_enabled = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_xr_stat_summary_enabled", 1); + md->rtcp_xr.stat_summary_enabled = !!lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_xr_stat_summary_enabled", 1); if (md->rtcp_xr.stat_summary_enabled) md->rtcp_xr.stat_summary_flags = OrtpRtcpXrStatSummaryLoss | OrtpRtcpXrStatSummaryDup | OrtpRtcpXrStatSummaryJitt | OrtpRtcpXrStatSummaryTTL; - md->rtcp_xr.voip_metrics_enabled = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_xr_voip_metrics_enabled", 1); + md->rtcp_xr.voip_metrics_enabled = !!lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_xr_voip_metrics_enabled", 1); } for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (!sal_stream_description_active(&md->streams[i])) @@ -1739,7 +1739,7 @@ void MediaSessionPrivate::updateCryptoParameters (SalMediaDescription *oldMd, Sa } bool MediaSessionPrivate::updateStreamCryptoParameters (const SalStreamDescription *localStreamDesc, SalStreamDescription *oldStream, SalStreamDescription *newStream, MediaStream *ms) { - int cryptoIdx = findCryptoIndexFromTag(localStreamDesc->crypto, newStream->crypto_local_tag); + int cryptoIdx = findCryptoIndexFromTag(localStreamDesc->crypto, static_cast(newStream->crypto_local_tag)); if (cryptoIdx >= 0) { if (localDescChanged & SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED) ms_media_stream_sessions_set_srtp_send_key_b64(&ms->sessions, newStream->crypto[0].algo, localStreamDesc->crypto[cryptoIdx].master_key); @@ -2277,7 +2277,7 @@ void MediaSessionPrivate::initializeAudioStream () { } } audio_stream_enable_automatic_gain_control(audioStream, linphone_core_agc_enabled(core)); - int enabled = lp_config_get_int(linphone_core_get_config(core), "sound", "noisegate", 0); + bool_t enabled = !!lp_config_get_int(linphone_core_get_config(core), "sound", "noisegate", 0); audio_stream_enable_noise_gate(audioStream, enabled); audio_stream_set_features(audioStream, linphone_core_get_audio_features(core)); @@ -2384,8 +2384,10 @@ void MediaSessionPrivate::initializeVideoStream () { int dscp = linphone_core_get_video_dscp(core); if (dscp!=-1) video_stream_set_dscp(videoStream, dscp); - video_stream_enable_display_filter_auto_rotate(videoStream, - lp_config_get_int(linphone_core_get_config(core), "video", "display_filter_auto_rotate", 0)); + video_stream_enable_display_filter_auto_rotate( + videoStream, + !!lp_config_get_int(linphone_core_get_config(core), "video", "display_filter_auto_rotate", 0) + ); int videoRecvBufSize = lp_config_get_int(linphone_core_get_config(core), "video", "recv_buf_size", 0); if (videoRecvBufSize > 0) rtp_session_set_recv_buf_size(videoStream->ms.sessions.rtp_session, videoRecvBufSize); @@ -2474,7 +2476,7 @@ void MediaSessionPrivate::postConfigureAudioStream (AudioStream *stream, bool mu else audio_stream_set_mic_gain_db(stream, micGain); float recvGain = core->sound_conf.soft_play_lev; - if (recvGain) + if (static_cast(recvGain)) setPlaybackGainDb(stream, recvGain); LinphoneConfig *config = linphone_core_get_config(core); float ngThres = lp_config_get_float(config, "sound", "ng_thres", 0.05f); @@ -2487,18 +2489,18 @@ void MediaSessionPrivate::postConfigureAudioStream (AudioStream *stream, bool mu float force = lp_config_get_float(config, "sound", "el_force", -1); int sustain = lp_config_get_int(config, "sound", "el_sustain", -1); float transmitThres = lp_config_get_float(config, "sound", "el_transmit_thres", -1); - if (speed == -1) + if (static_cast(speed) == -1) speed = 0.03f; - if (force == -1) + if (static_cast(force) == -1) force = 25; MSFilter *f = stream->volsend; ms_filter_call_method(f, MS_VOLUME_SET_EA_SPEED, &speed); ms_filter_call_method(f, MS_VOLUME_SET_EA_FORCE, &force); - if (thres != -1) + if (static_cast(thres) != -1) ms_filter_call_method(f, MS_VOLUME_SET_EA_THRESHOLD, &thres); - if (sustain != -1) + if (static_cast(sustain) != -1) ms_filter_call_method(f, MS_VOLUME_SET_EA_SUSTAIN, &sustain); - if (transmitThres != -1) + if (static_cast(transmitThres) != -1) ms_filter_call_method(f, MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD, &transmitThres); ms_filter_call_method(f, MS_VOLUME_SET_NOISE_GATE_THRESHOLD, &ngThres); ms_filter_call_method(f, MS_VOLUME_SET_NOISE_GATE_FLOORGAIN, &ngFloorGain); @@ -2610,7 +2612,7 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool /* Valid local tags are > 0 */ if (sal_stream_description_has_srtp(stream)) { const SalStreamDescription *localStreamDesc = sal_media_description_find_stream(localDesc, stream->proto, SalAudio); - int cryptoIdx = findCryptoIndexFromTag(localStreamDesc->crypto, stream->crypto_local_tag); + int cryptoIdx = findCryptoIndexFromTag(localStreamDesc->crypto, static_cast(stream->crypto_local_tag)); if (cryptoIdx >= 0) { ms_media_stream_sessions_set_srtp_recv_key_b64(&audioStream->ms.sessions, stream->crypto[0].algo, stream->crypto[0].master_key); ms_media_stream_sessions_set_srtp_send_key_b64(&audioStream->ms.sessions, stream->crypto[0].algo, localStreamDesc->crypto[cryptoIdx].master_key); @@ -2795,7 +2797,7 @@ void MediaSessionPrivate::startTextStream () { currentParams->getPrivate()->setUsedRealtimeTextCodec(rtp_profile_get_payload(textProfile, usedPt)); currentParams->enableRealtimeText(true); if (sal_stream_description_has_srtp(tstream)) { - int cryptoIdx = findCryptoIndexFromTag(localStreamDesc->crypto, tstream->crypto_local_tag); + int cryptoIdx = findCryptoIndexFromTag(localStreamDesc->crypto, static_cast(tstream->crypto_local_tag)); if (cryptoIdx >= 0) { ms_media_stream_sessions_set_srtp_recv_key_b64(&textStream->ms.sessions, tstream->crypto[0].algo, tstream->crypto[0].master_key); ms_media_stream_sessions_set_srtp_send_key_b64(&textStream->ms.sessions, tstream->crypto[0].algo, localStreamDesc->crypto[cryptoIdx].master_key); @@ -2887,7 +2889,7 @@ void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { if (isActive) { if (sal_stream_description_has_srtp(vstream)) { const SalStreamDescription *localStreamDesc = sal_media_description_find_stream(localDesc, vstream->proto, SalVideo); - int cryptoIdx = findCryptoIndexFromTag(localStreamDesc->crypto, vstream->crypto_local_tag); + int cryptoIdx = findCryptoIndexFromTag(localStreamDesc->crypto, static_cast(vstream->crypto_local_tag)); if (cryptoIdx >= 0) { ms_media_stream_sessions_set_srtp_recv_key_b64(&videoStream->ms.sessions, vstream->crypto[0].algo, vstream->crypto[0].master_key); ms_media_stream_sessions_set_srtp_send_key_b64(&videoStream->ms.sessions, vstream->crypto[0].algo, localStreamDesc->crypto[cryptoIdx].master_key); @@ -2900,7 +2902,7 @@ void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { video_stream_set_direction(videoStream, dir); lInfo() << "startVideoStream: device_rotation=" << core->device_rotation; video_stream_set_device_rotation(videoStream, core->device_rotation); - video_stream_set_freeze_on_error(videoStream, lp_config_get_int(linphone_core_get_config(core), "video", "freeze_on_error", 1)); + video_stream_set_freeze_on_error(videoStream, !!lp_config_get_int(linphone_core_get_config(core), "video", "freeze_on_error", 1)); if (isMulticast) rtp_session_set_multicast_ttl(videoStream->ms.sessions.rtp_session, vstream->ttl); video_stream_use_video_preset(videoStream, lp_config_get_string(linphone_core_get_config(core), "video", "preset", nullptr)); @@ -3393,7 +3395,7 @@ void MediaSessionPrivate::propagateEncryptionChanged () { void MediaSessionPrivate::fillLogStats (MediaStream *st) { float quality = media_stream_get_average_quality_rating(st); if (quality >= 0) { - if (log->quality == -1) + if (static_cast(log->quality) == -1) log->quality = quality; else log->quality *= quality / 5.0f; diff --git a/src/nat/ice-agent.cpp b/src/nat/ice-agent.cpp index a3568719b..00cc5219a 100644 --- a/src/nat/ice-agent.cpp +++ b/src/nat/ice-agent.cpp @@ -16,18 +16,18 @@ * along with this program. If not, see . */ -#include "ice-agent.h" -#include "conference/session/media-session-p.h" - -#include "logger/logger.h" - #include "linphone/core.h" +#include "conference/session/media-session-p.h" +#include "logger/logger.h" + +#include "ice-agent.h" + +// ============================================================================= using namespace std; LINPHONE_BEGIN_NAMESPACE -// ============================================================================= bool IceAgent::candidatesGathered () const { if (!iceSession) @@ -43,7 +43,7 @@ void IceAgent::checkSession (IceRole role, bool isReinvite) { return; iceSession = ice_session_new(); /* For backward compatibility purposes, shall be enabled by default in the future */ - ice_session_enable_message_integrity_check(iceSession, lp_config_get_int(config, "net", "ice_session_enable_message_integrity_check", 1)); + ice_session_enable_message_integrity_check(iceSession, !!lp_config_get_int(config, "net", "ice_session_enable_message_integrity_check", 1)); if (lp_config_get_int(config, "net", "dont_default_to_stun_candidates", 0)) { IceCandidateType types[ICT_CandidateTypeMax]; types[0] = ICT_HostCandidate; @@ -494,14 +494,17 @@ void IceAgent::createIceCheckListsAndParseIceAttributes (const SalMediaDescripti continue; const char *addr = nullptr; int port = 0; - getIceDefaultAddrAndPort(candidate->componentID, md, stream, &addr, &port); + getIceDefaultAddrAndPort(static_cast(candidate->componentID), md, stream, &addr, &port); if (addr && (candidate->port == port) && (strlen(candidate->addr) == strlen(addr)) && (strcmp(candidate->addr, addr) == 0)) defaultCandidate = true; int family = AF_INET; if (strchr(candidate->addr, ':')) family = AF_INET6; - ice_add_remote_candidate(cl, candidate->type, family, candidate->addr, candidate->port, candidate->componentID, - candidate->priority, candidate->foundation, defaultCandidate); + ice_add_remote_candidate( + cl, candidate->type, family, candidate->addr, candidate->port, + static_cast(candidate->componentID), + candidate->priority, candidate->foundation, defaultCandidate + ); } if (!iceRestarted) { bool_t losingPairsAdded = false; @@ -511,7 +514,7 @@ void IceAgent::createIceCheckListsAndParseIceAttributes (const SalMediaDescripti int port = 0; int componentID = j + 1; if (remoteCandidate->addr[0] == '\0') break; - getIceDefaultAddrAndPort(componentID, md, stream, &addr, &port); + getIceDefaultAddrAndPort(static_cast(componentID), md, stream, &addr, &port); if (j == 0) /* If we receive a re-invite and we finished ICE processing on our side, use the candidates given by the remote. */ ice_check_list_unselect_valid_pairs(cl); int remoteFamily = AF_INET; @@ -520,7 +523,7 @@ void IceAgent::createIceCheckListsAndParseIceAttributes (const SalMediaDescripti int family = AF_INET; if (strchr(addr, ':')) family = AF_INET6; - ice_add_losing_pair(cl, j + 1, remoteFamily, remoteCandidate->addr, remoteCandidate->port, family, addr, port); + ice_add_losing_pair(cl, static_cast(j + 1), remoteFamily, remoteCandidate->addr, remoteCandidate->port, family, addr, port); losingPairsAdded = true; } if (losingPairsAdded) diff --git a/src/nat/stun-client.cpp b/src/nat/stun-client.cpp index 3399488f9..9f7003fb4 100644 --- a/src/nat/stun-client.cpp +++ b/src/nat/stun-client.cpp @@ -16,20 +16,20 @@ * along with this program. If not, see . */ -#include "stun-client.h" - -#include "logger/logger.h" - #include "linphone/core.h" #include "private.h" +#include "logger/logger.h" + +#include "stun-client.h" + +// ============================================================================= + using namespace std; LINPHONE_BEGIN_NAMESPACE -// ============================================================================= - int StunClient::run (int audioPort, int videoPort, int textPort) { if (linphone_core_ipv6_enabled(core)) { lWarning() << "STUN support is not implemented for ipv6"; @@ -107,7 +107,7 @@ int StunClient::run (int audioPort, int videoPort, int textPort) { } struct timeval cur; ortp_gettimeofday(&cur, nullptr); - elapsed = ((cur.tv_sec - init.tv_sec) * 1000.) + ((cur.tv_usec - init.tv_usec) / 1000.); + elapsed = static_cast(cur.tv_sec - init.tv_sec) * 1000 + static_cast(cur.tv_usec - init.tv_usec) / 1000; if (elapsed > 2000.) { lInfo() << "STUN responses timeout, going ahead"; ret = -1; @@ -181,7 +181,7 @@ ortp_socket_t StunClient::createStunSocket (int localPort) { memset(&laddr, 0, sizeof(laddr)); laddr.sin_family = AF_INET; laddr.sin_addr.s_addr = INADDR_ANY; - laddr.sin_port = htons(localPort); + laddr.sin_port = htons(static_cast(localPort)); if (bind(sock, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) { lError() << "Bind socket to 0.0.0.0:" << localPort << " failed: " << getSocketError(); close_socket(sock); @@ -198,7 +198,7 @@ int StunClient::recvStunResponse(ortp_socket_t sock, Candidate &candidate, int & char buf[MS_STUN_MAX_MESSAGE_SIZE]; int len = MS_STUN_MAX_MESSAGE_SIZE; - len = recv(sock, buf, len, 0); + len = static_cast(recv(sock, buf, len, 0)); if (len > 0) { struct in_addr ia; MSStunMessage *resp = ms_stun_message_create_from_buffer_parsing((uint8_t *)buf, (ssize_t)len); @@ -227,7 +227,7 @@ int StunClient::recvStunResponse(ortp_socket_t sock, Candidate &candidate, int & int StunClient::sendStunRequest(ortp_socket_t sock, const struct sockaddr *server, socklen_t addrlen, int id, bool changeAddr) { MSStunMessage *req = ms_stun_binding_request_create(); UInt96 trId = ms_stun_message_get_tr_id(req); - trId.octet[0] = id; + trId.octet[0] = static_cast(id); ms_stun_message_set_tr_id(req, trId); ms_stun_message_enable_change_ip(req, changeAddr); ms_stun_message_enable_change_port(req, changeAddr); @@ -238,7 +238,7 @@ int StunClient::sendStunRequest(ortp_socket_t sock, const struct sockaddr *serve lError() << "Failed to encode STUN message"; err = -1; } else { - err = bctbx_sendto(sock, buf, len, 0, server, addrlen); + err = static_cast(bctbx_sendto(sock, buf, len, 0, server, addrlen)); if (err < 0) { lError() << "sendto failed: " << strerror(errno); err = -1; diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index f2369576e..dda5139b0 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -86,7 +86,7 @@ string Utils::toString (const void *val) { int Utils::stoi (const string &str, size_t *idx, int base) { char *p; - int v = strtol(str.c_str(), &p, base); + int v = static_cast(strtol(str.c_str(), &p, base)); if (idx) *idx = p - str.c_str(); @@ -129,22 +129,22 @@ char *Utils::utf8ToChar (uint32_t ic) { char *result = new char[5]; int size = 0; if (ic < 0x80) { - result[0] = ic; + result[0] = static_cast(ic); size = 1; } else if (ic < 0x800) { - result[1] = 0x80 + ((ic & 0x3F)); - result[0] = 0xC0 + ((ic >> 6) & 0x1F); + result[1] = static_cast(0x80 + ((ic & 0x3F))); + result[0] = static_cast(0xC0 + ((ic >> 6) & 0x1F)); size = 2; } else if (ic < 0x100000) { - result[2] = 0x80 + (ic & 0x3F); - result[1] = 0x80 + ((ic >> 6) & 0x3F); - result[0] = 0xE0 + ((ic >> 12) & 0xF); + result[2] = static_cast(0x80 + (ic & 0x3F)); + result[1] = static_cast(0x80 + ((ic >> 6) & 0x3F)); + result[0] = static_cast(0xE0 + ((ic >> 12) & 0xF)); size = 3; } else if (ic < 0x110000) { - result[3] = 0x80 + (ic & 0x3F); - result[2] = 0x80 + ((ic >> 6) & 0x3F); - result[1] = 0x80 + ((ic >> 12) & 0x3F); - result[0] = 0xF0 + ((ic >> 18) & 0x7); + result[3] = static_cast(0x80 + (ic & 0x3F)); + result[2] = static_cast(0x80 + ((ic >> 6) & 0x3F)); + result[1] = static_cast(0x80 + ((ic >> 12) & 0x3F)); + result[0] = static_cast(0xF0 + ((ic >> 18) & 0x7)); size = 4; } result[size] = '\0'; diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index eb538cedf..96e5484d2 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -278,9 +278,9 @@ static inline long long getAssumedNumber (const VariantPrivate &p) { case Variant::Char: return p.value.c; case Variant::Double: - return p.value.d; + return static_cast(p.value.d); case Variant::Float: - return p.value.f; + return static_cast(p.value.f); default: L_ASSERT(false); @@ -416,13 +416,13 @@ static inline float getValueAsFloat (const VariantPrivate &p, bool *soFarSoGood) case Variant::Long: case Variant::LongLong: case Variant::Char: - return static_cast(getAssumedNumber(p)); + return static_cast(getAssumedNumber(p)); case Variant::UnsignedInt: case Variant::UnsignedShort: case Variant::UnsignedLong: case Variant::UnsignedLongLong: - return static_cast(getAssumedUnsignedNumber(p)); + return static_cast(getAssumedUnsignedNumber(p)); case Variant::Float: return p.value.f; @@ -431,13 +431,13 @@ static inline float getValueAsFloat (const VariantPrivate &p, bool *soFarSoGood) return static_cast(p.value.d); case Variant::Bool: - return static_cast(p.value.b); + return static_cast(p.value.b); case Variant::String: return Utils::stof(*p.value.str); case Variant::Generic: - return static_cast(!!p.value.g); + return static_cast(!!p.value.g); default: *soFarSoGood = false; diff --git a/src/xml/conference-info.cpp b/src/xml/conference-info.cpp index 228e2fb9d..e09fb01ae 100644 --- a/src/xml/conference-info.cpp +++ b/src/xml/conference-info.cpp @@ -38,12 +38,21 @@ #include +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wsuggest-override" +#endif + #include "conference-info.h" +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic pop +#endif + namespace conference_info { // Conference_type - // + // const Conference_type::Conference_descriptionOptional& Conference_type:: getConference_description () const @@ -365,7 +374,7 @@ namespace conference_info // State_type - // + // State_type:: State_type (Value v) @@ -402,7 +411,7 @@ namespace conference_info State_type& State_type:: operator= (Value v) { - static_cast< ::xml_schema::String& > (*this) = + static_cast< ::xml_schema::String& > (*this) = ::xml_schema::String (_xsd_State_type_literals_[v]); return *this; @@ -410,7 +419,7 @@ namespace conference_info // Conference_description_type - // + // const Conference_description_type::Display_textOptional& Conference_description_type:: getDisplay_text () const @@ -696,7 +705,7 @@ namespace conference_info // Host_type - // + // const Host_type::Display_textOptional& Host_type:: getDisplay_text () const @@ -838,7 +847,7 @@ namespace conference_info // Conference_state_type - // + // const Conference_state_type::User_countOptional& Conference_state_type:: getUser_count () const @@ -962,7 +971,7 @@ namespace conference_info // Conference_media_type - // + // const Conference_media_type::EntrySequence& Conference_media_type:: getEntry () const @@ -1014,7 +1023,7 @@ namespace conference_info // Conference_medium_type - // + // const Conference_medium_type::Display_textOptional& Conference_medium_type:: getDisplay_text () const @@ -1186,7 +1195,7 @@ namespace conference_info // Uris_type - // + // const Uris_type::EntrySequence& Uris_type:: getEntry () const @@ -1274,7 +1283,7 @@ namespace conference_info // Uri_type - // + // const Uri_type::UriType& Uri_type:: getUri () const @@ -1470,7 +1479,7 @@ namespace conference_info } // Users_type - // + // const Users_type::UserSequence& Users_type:: getUser () const @@ -1576,7 +1585,7 @@ namespace conference_info // User_type - // + // const User_type::Display_textOptional& User_type:: getDisplay_text () const @@ -1862,7 +1871,7 @@ namespace conference_info // User_roles_type - // + // const User_roles_type::EntrySequence& User_roles_type:: getEntry () const @@ -1938,7 +1947,7 @@ namespace conference_info } // Endpoint_type - // + // const Endpoint_type::Display_textOptional& Endpoint_type:: getDisplay_text () const @@ -2314,7 +2323,7 @@ namespace conference_info // Endpoint_status_type - // + // Endpoint_status_type:: Endpoint_status_type (Value v) @@ -2351,7 +2360,7 @@ namespace conference_info Endpoint_status_type& Endpoint_status_type:: operator= (Value v) { - static_cast< ::xml_schema::String& > (*this) = + static_cast< ::xml_schema::String& > (*this) = ::xml_schema::String (_xsd_Endpoint_status_type_literals_[v]); return *this; @@ -2359,7 +2368,7 @@ namespace conference_info // Joining_type - // + // Joining_type:: Joining_type (Value v) @@ -2396,7 +2405,7 @@ namespace conference_info Joining_type& Joining_type:: operator= (Value v) { - static_cast< ::xml_schema::String& > (*this) = + static_cast< ::xml_schema::String& > (*this) = ::xml_schema::String (_xsd_Joining_type_literals_[v]); return *this; @@ -2404,7 +2413,7 @@ namespace conference_info // Disconnection_type - // + // Disconnection_type:: Disconnection_type (Value v) @@ -2441,7 +2450,7 @@ namespace conference_info Disconnection_type& Disconnection_type:: operator= (Value v) { - static_cast< ::xml_schema::String& > (*this) = + static_cast< ::xml_schema::String& > (*this) = ::xml_schema::String (_xsd_Disconnection_type_literals_[v]); return *this; @@ -2449,7 +2458,7 @@ namespace conference_info // Execution_type - // + // const Execution_type::WhenOptional& Execution_type:: getWhen () const @@ -2573,7 +2582,7 @@ namespace conference_info // Call_type - // + // const Call_type::SipOptional& Call_type:: getSip () const @@ -2655,7 +2664,7 @@ namespace conference_info // Sip_dialog_id_type - // + // const Sip_dialog_id_type::Display_textOptional& Sip_dialog_id_type:: getDisplay_text () const @@ -2827,7 +2836,7 @@ namespace conference_info // Media_type - // + // const Media_type::Display_textOptional& Media_type:: getDisplay_text () const @@ -3059,7 +3068,7 @@ namespace conference_info // Media_status_type - // + // Media_status_type:: Media_status_type (Value v) @@ -3096,7 +3105,7 @@ namespace conference_info Media_status_type& Media_status_type:: operator= (Value v) { - static_cast< ::xml_schema::String& > (*this) = + static_cast< ::xml_schema::String& > (*this) = ::xml_schema::String (_xsd_Media_status_type_literals_[v]); return *this; @@ -3104,7 +3113,7 @@ namespace conference_info // Sidebars_by_val_type - // + // const Sidebars_by_val_type::EntrySequence& Sidebars_by_val_type:: getEntry () const @@ -9269,4 +9278,3 @@ namespace conference_info // // // End epilogue. - diff --git a/src/xml/xml.cpp b/src/xml/xml.cpp index 5be074eb8..d8fb4a977 100644 --- a/src/xml/xml.cpp +++ b/src/xml/xml.cpp @@ -38,8 +38,17 @@ #include +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wsuggest-override" +#endif + #include "xml.h" +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic pop +#endif + namespace namespace_ { // Lang @@ -66,7 +75,7 @@ namespace namespace_ } // Space - // + // Space:: Space (Value v) @@ -103,7 +112,7 @@ namespace namespace_ Space& Space:: operator= (Value v) { - static_cast< ::xml_schema::Ncname& > (*this) = + static_cast< ::xml_schema::Ncname& > (*this) = ::xml_schema::Ncname (_xsd_Space_literals_[v]); return *this; @@ -111,7 +120,7 @@ namespace namespace_ // Lang_member - // + // Lang_member:: Lang_member (Value v) @@ -148,7 +157,7 @@ namespace namespace_ Lang_member& Lang_member:: operator= (Value v) { - static_cast< ::xml_schema::String& > (*this) = + static_cast< ::xml_schema::String& > (*this) = ::xml_schema::String (_xsd_Lang_member_literals_[v]); return *this; @@ -448,4 +457,3 @@ namespace namespace_ // // // End epilogue. - From f64376cbc134f701caefb92cd837dd020badf803 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 20 Sep 2017 12:49:17 +0200 Subject: [PATCH 0095/2215] fix(Conference): add override when necessary and cast correctly nb participants --- src/chat/client-group-chat-room.h | 10 +++++----- src/conference/conference.cpp | 2 +- src/conference/remote-conference.h | 14 +++++++------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index 1dcc1cc47..5dacb98f2 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -51,11 +51,11 @@ public: private: /* ConferenceListener */ - void onConferenceCreated (const Address &addr); - void onConferenceTerminated (const Address &addr); - void onParticipantAdded (const Address &addr); - void onParticipantRemoved (const Address &addr); - void onParticipantSetAdmin (const Address &addr, bool isAdmin); + void onConferenceCreated (const Address &addr) override; + void onConferenceTerminated (const Address &addr) override; + void onParticipantAdded (const Address &addr) override; + void onParticipantRemoved (const Address &addr) override; + void onParticipantSetAdmin (const Address &addr, bool isAdmin) override; private: L_DECLARE_PRIVATE(ClientGroupChatRoom); diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index ba165dbbc..4a40d509c 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -59,7 +59,7 @@ const string& Conference::getId () const { } int Conference::getNbParticipants () const { - return participants.size(); + return static_cast(participants.size()); } list> Conference::getParticipants () const { diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index c8cb28d6c..c49f44c0b 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -36,16 +36,16 @@ protected: public: /* ConferenceInterface */ - virtual std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia); - virtual void removeParticipant (const std::shared_ptr &participant); + virtual std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; + virtual void removeParticipant (const std::shared_ptr &participant) override; protected: /* ConferenceListener */ - virtual void onConferenceCreated (const Address &addr); - virtual void onConferenceTerminated (const Address &addr); - virtual void onParticipantAdded (const Address &addr); - virtual void onParticipantRemoved (const Address &addr); - virtual void onParticipantSetAdmin (const Address &addr, bool isAdmin); + virtual void onConferenceCreated (const Address &addr) override; + virtual void onConferenceTerminated (const Address &addr) override; + virtual void onParticipantAdded (const Address &addr) override; + virtual void onParticipantRemoved (const Address &addr) override; + virtual void onParticipantSetAdmin (const Address &addr, bool isAdmin) override; private: L_DISABLE_COPY(RemoteConference); From 0cb5cc634555be5cb60b88f35d496b55e401480a Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 20 Sep 2017 13:40:47 +0200 Subject: [PATCH 0096/2215] fix(Core): remove useless virtual --- src/conference/conference.h | 42 +++++++++++++++--------------- src/conference/local-conference.h | 16 ++++++------ src/conference/remote-conference.h | 14 +++++----- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/conference/conference.h b/src/conference/conference.h index 7d5a0af36..583a770c2 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -47,30 +47,30 @@ public: public: /* ConferenceInterface */ - virtual std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; - virtual void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia) override; - virtual bool canHandleParticipants () const override; - virtual const std::string& getId () const override; - virtual int getNbParticipants () const override; - virtual std::list> getParticipants () const override; - virtual void removeParticipant (const std::shared_ptr &participant) override; - virtual void removeParticipants (const std::list> &participants) override; + std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; + void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia) override; + bool canHandleParticipants () const override; + const std::string& getId () const override; + int getNbParticipants () const override; + std::list> getParticipants () const override; + void removeParticipant (const std::shared_ptr &participant) override; + void removeParticipants (const std::list> &participants) override; private: /* CallSessionListener */ - virtual void onAckBeingSent (const CallSession &session, LinphoneHeaders *headers) override; - virtual void onAckReceived (const CallSession &session, LinphoneHeaders *headers) override; - virtual void onCallSessionAccepted (const CallSession &session) override; - virtual void onCallSessionSetReleased (const CallSession &session) override; - virtual void onCallSessionSetTerminated (const CallSession &session) override; - virtual void onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message) override; - virtual void onIncomingCallSessionStarted (const CallSession &session) override; - virtual void onEncryptionChanged (const CallSession &session, bool activated, const std::string &authToken) override; - virtual void onStatsUpdated (const LinphoneCallStats *stats) override; - virtual void onResetCurrentSession (const CallSession &session) override; - virtual void onSetCurrentSession (const CallSession &session) override; - virtual void onFirstVideoFrameDecoded (const CallSession &session) override; - virtual void onResetFirstVideoFrameDecoded (const CallSession &session) override; + void onAckBeingSent (const CallSession &session, LinphoneHeaders *headers) override; + void onAckReceived (const CallSession &session, LinphoneHeaders *headers) override; + void onCallSessionAccepted (const CallSession &session) override; + void onCallSessionSetReleased (const CallSession &session) override; + void onCallSessionSetTerminated (const CallSession &session) override; + void onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message) override; + void onIncomingCallSessionStarted (const CallSession &session) override; + void onEncryptionChanged (const CallSession &session, bool activated, const std::string &authToken) override; + void onStatsUpdated (const LinphoneCallStats *stats) override; + void onResetCurrentSession (const CallSession &session) override; + void onSetCurrentSession (const CallSession &session) override; + void onFirstVideoFrameDecoded (const CallSession &session) override; + void onResetFirstVideoFrameDecoded (const CallSession &session) override; protected: explicit Conference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h index 660081516..30e64229b 100644 --- a/src/conference/local-conference.h +++ b/src/conference/local-conference.h @@ -35,14 +35,14 @@ public: public: /* ConferenceInterface */ - virtual std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; - virtual void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia) override; - virtual bool canHandleParticipants () const override; - virtual const std::string& getId () const override; - virtual int getNbParticipants () const override; - virtual std::list> getParticipants () const override; - virtual void removeParticipant (const std::shared_ptr &participant) override; - virtual void removeParticipants (const std::list> &participants) override; + std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; + void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia) override; + bool canHandleParticipants () const override; + const std::string& getId () const override; + int getNbParticipants () const override; + std::list> getParticipants () const override; + void removeParticipant (const std::shared_ptr &participant) override; + void removeParticipants (const std::list> &participants) override; private: L_DISABLE_COPY(LocalConference); diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index c49f44c0b..ddafca6f1 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -36,16 +36,16 @@ protected: public: /* ConferenceInterface */ - virtual std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; - virtual void removeParticipant (const std::shared_ptr &participant) override; + std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; + void removeParticipant (const std::shared_ptr &participant) override; protected: /* ConferenceListener */ - virtual void onConferenceCreated (const Address &addr) override; - virtual void onConferenceTerminated (const Address &addr) override; - virtual void onParticipantAdded (const Address &addr) override; - virtual void onParticipantRemoved (const Address &addr) override; - virtual void onParticipantSetAdmin (const Address &addr, bool isAdmin) override; + void onConferenceCreated (const Address &addr) override; + void onConferenceTerminated (const Address &addr) override; + void onParticipantAdded (const Address &addr) override; + void onParticipantRemoved (const Address &addr) override; + void onParticipantSetAdmin (const Address &addr, bool isAdmin) override; private: L_DISABLE_COPY(RemoteConference); From c0d1e3ec7226759428801d4aa37656de7dc6fb83 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 20 Sep 2017 14:00:22 +0200 Subject: [PATCH 0097/2215] Started c wrapper for chat message callbacks --- coreapi/private.h | 9 --- include/CMakeLists.txt | 1 + include/linphone/api/c-chat-message-cbs.h | 71 +++++++++++++++++++++++ include/linphone/api/c-types.h | 10 ++++ src/CMakeLists.txt | 1 + src/c-wrapper/api/c-chat-message-cbs.cpp | 67 +++++++++++++++++++++ 6 files changed, 150 insertions(+), 9 deletions(-) create mode 100644 include/linphone/api/c-chat-message-cbs.h create mode 100644 src/c-wrapper/api/c-chat-message-cbs.cpp diff --git a/coreapi/private.h b/coreapi/private.h index cd4673aef..3bcd62a49 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -174,15 +174,6 @@ typedef struct _CallCallbackObj void * _user_data; }CallCallbackObj; -struct _LinphoneChatMessageCbs { - belle_sip_object_t base; - void *user_data; - LinphoneChatMessageCbsMsgStateChangedCb msg_state_changed; - LinphoneChatMessageCbsFileTransferRecvCb file_transfer_recv; /**< Callback to store file received attached to a #LinphoneChatMessage */ - LinphoneChatMessageCbsFileTransferSendCb file_transfer_send; /**< Callback to collect file chunk to be sent for a #LinphoneChatMessage */ - LinphoneChatMessageCbsFileTransferProgressIndicationCb file_transfer_progress_indication; /**< Callback to indicate file transfer progress */ -}; - BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneChatMessageCbs); typedef enum _LinphoneChatMessageDir{ diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 40d842bf5..87c5aa063 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -78,6 +78,7 @@ set(C_API_HEADER_FILES c-api.h c-callbacks.h c-chat-message.h + c-chat-message-cbs.h c-chat-room.h c-chat-room-cbs.h c-event-log.h diff --git a/include/linphone/api/c-chat-message-cbs.h b/include/linphone/api/c-chat-message-cbs.h new file mode 100644 index 000000000..2bcd9b729 --- /dev/null +++ b/include/linphone/api/c-chat-message-cbs.h @@ -0,0 +1,71 @@ +/* + * c-chat-message-cbs.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _C_CHAT_MESSAGE_CBS_H_ +#define _C_CHAT_MESSAGE_CBS_H_ + +#include "linphone/api/c-callbacks.h" +#include "linphone/api/c-types.h" + +// ============================================================================= + +#ifdef __cplusplus + extern "C" { +#endif // ifdef __cplusplus + +/** + * @addtogroup chatroom + * @{ + */ + +/** + * Acquire a reference to the chat room callbacks object. + * @param[in] cbs The chat room callbacks object + * @return The same chat room callbacks object +**/ +LINPHONE_PUBLIC LinphoneChatMessageCbs * linphone_chat_message_cbs_ref (LinphoneChatMessageCbs *cbs); + +/** + * Release reference to the chat room callbacks object. + * @param[in] cr The chat room callbacks object +**/ +LINPHONE_PUBLIC void linphone_chat_message_cbs_unref (LinphoneChatMessageCbs *cbs); + +/** + * Retrieve the user pointer associated with the chat room callbacks object. + * @param[in] cr The chat room callbacks object + * @return The user pointer associated with the chat room callbacks object +**/ +LINPHONE_PUBLIC void * linphone_chat_message_cbs_get_user_data (const LinphoneChatMessageCbs *cbs); + +/** + * Assign a user pointer to the chat room callbacks object. + * @param[in] cr The chat room callbacks object + * @param[in] ud The user pointer to associate with the chat room callbacks object +**/ +LINPHONE_PUBLIC void linphone_chat_message_cbs_set_user_data (LinphoneChatMessageCbs *cbs, void *ud); + +/** + * @} + */ + +#ifdef __cplusplus + } +#endif // ifdef __cplusplus + +#endif // ifndef _C_CHAT_MESSAGE_H_ diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index de41cda49..7e53de356 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -88,8 +88,18 @@ typedef struct _LinphoneChatRoom LinphoneChatRoom; */ typedef struct _LinphoneChatRoomCbs LinphoneChatRoomCbs; +/** + * An chat message is the object that is sent and received through LinphoneChatRooms. + * @ingroup chatroom + */ typedef struct _LinphoneMessage LinphoneMessage; +/** + * An object to handle the callbacks for the handling a LinphoneChatMessage objects. + * @ingroup chatroom + */ +typedef struct _LinphoneChatMessageCbs LinphoneChatMessageCbs; + /** * The LinphoneParticipant object represents a participant of a conference. * @ingroup misc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ae40aa80b..20eaccdc7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -104,6 +104,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES c-wrapper/api/c-address.cpp c-wrapper/api/c-call-params.cpp c-wrapper/api/c-chat-message.cpp + c-wrapper/api/c-chat-message-cbs.cpp c-wrapper/api/c-chat-room.cpp c-wrapper/api/c-chat-room-cbs.cpp c-wrapper/api/c-event-log.cpp diff --git a/src/c-wrapper/api/c-chat-message-cbs.cpp b/src/c-wrapper/api/c-chat-message-cbs.cpp new file mode 100644 index 000000000..d26604dae --- /dev/null +++ b/src/c-wrapper/api/c-chat-message-cbs.cpp @@ -0,0 +1,67 @@ +/* + * c-chat-message-cbs.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "linphone/api/c-chat-message-cbs.h" + +// TODO: Remove me later. +#include "private.h" + +// ============================================================================= + +struct _LinphoneChatMessageCbs { + belle_sip_object_t base; + void *userData; + LinphoneChatMessageCbsMsgStateChangedCb msg_state_changed; + LinphoneChatMessageCbsFileTransferRecvCb file_transfer_recv; + LinphoneChatMessageCbsFileTransferSendCb file_transfer_send; + LinphoneChatMessageCbsFileTransferProgressIndicationCb file_transfer_progress_indication; +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneChatMessageCbs); + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneChatMessageCbs); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneChatMessageCbs, belle_sip_object_t, + NULL, // destroy + NULL, // clone + NULL, // marshal + FALSE +); + +// ============================================================================= + +LinphoneChatMessageCbs * linphone_chat_message_cbs_new (void) { + return belle_sip_object_new(LinphoneChatMessageCbs); +} + +LinphoneChatMessageCbs * linphone_chat_message_cbs_ref (LinphoneChatMessageCbs *cbs) { + belle_sip_object_ref(cbs); + return cbs; +} + +void linphone_chat_message_cbs_unref (LinphoneChatMessageCbs *cbs) { + belle_sip_object_unref(cbs); +} + +void * linphone_chat_message_cbs_get_user_data (const LinphoneChatMessageCbs *cbs) { + return cbs->userData; +} + +void linphone_chat_message_cbs_set_user_data (LinphoneChatMessageCbs *cbs, void *ud) { + cbs->userData = ud; +} From a5a3b2ad261c8cf70ce360635d7ba8c8d482042b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 20 Sep 2017 14:47:08 +0200 Subject: [PATCH 0098/2215] Added chat message callbacks to c wrapper --- coreapi/chat.c | 70 ------------------- include/linphone/api/c-chat-message-cbs.h | 56 +++++++++++++++ include/linphone/chat.h | 83 ----------------------- src/c-wrapper/api/c-chat-message-cbs.cpp | 38 +++++++++++ 4 files changed, 94 insertions(+), 153 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 1fd40d017..d60865b7b 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -43,76 +43,6 @@ #include "content/content-type.h" -static void _linphone_chat_message_destroy(LinphoneChatMessage *msg); - -BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneChatMessageCbs); - -BELLE_SIP_INSTANCIATE_VPTR(LinphoneChatMessageCbs, belle_sip_object_t, - NULL, // destroy - NULL, // clone - NULL, // marshal - FALSE); - -LinphoneChatMessageCbs *linphone_chat_message_cbs_new(void) { - return belle_sip_object_new(LinphoneChatMessageCbs); -} - -LinphoneChatMessageCbs *linphone_chat_message_cbs_ref(LinphoneChatMessageCbs *cbs) { - belle_sip_object_ref(cbs); - return cbs; -} - -void linphone_chat_message_cbs_unref(LinphoneChatMessageCbs *cbs) { - belle_sip_object_unref(cbs); -} - -void *linphone_chat_message_cbs_get_user_data(const LinphoneChatMessageCbs *cbs) { - return cbs->user_data; -} - -void linphone_chat_message_cbs_set_user_data(LinphoneChatMessageCbs *cbs, void *ud) { - cbs->user_data = ud; -} - -LinphoneChatMessageCbsMsgStateChangedCb -linphone_chat_message_cbs_get_msg_state_changed(const LinphoneChatMessageCbs *cbs) { - return cbs->msg_state_changed; -} - -void linphone_chat_message_cbs_set_msg_state_changed(LinphoneChatMessageCbs *cbs, - LinphoneChatMessageCbsMsgStateChangedCb cb) { - cbs->msg_state_changed = cb; -} - -LinphoneChatMessageCbsFileTransferRecvCb linphone_chat_message_cbs_get_file_transfer_recv(const LinphoneChatMessageCbs *cbs) { - return cbs->file_transfer_recv; -} - -void linphone_chat_message_cbs_set_file_transfer_recv(LinphoneChatMessageCbs *cbs, - LinphoneChatMessageCbsFileTransferRecvCb cb) { - cbs->file_transfer_recv = cb; -} - -LinphoneChatMessageCbsFileTransferSendCb linphone_chat_message_cbs_get_file_transfer_send(const LinphoneChatMessageCbs *cbs) { - return cbs->file_transfer_send; -} - -void linphone_chat_message_cbs_set_file_transfer_send(LinphoneChatMessageCbs *cbs, - LinphoneChatMessageCbsFileTransferSendCb cb) { - cbs->file_transfer_send = cb; -} - -LinphoneChatMessageCbsFileTransferProgressIndicationCb -linphone_chat_message_cbs_get_file_transfer_progress_indication(const LinphoneChatMessageCbs *cbs) { - return cbs->file_transfer_progress_indication; -} - -void linphone_chat_message_cbs_set_file_transfer_progress_indication( - LinphoneChatMessageCbs *cbs, LinphoneChatMessageCbsFileTransferProgressIndicationCb cb) { - cbs->file_transfer_progress_indication = cb; -} - - BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneChatMessage); void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessageState state) { diff --git a/include/linphone/api/c-chat-message-cbs.h b/include/linphone/api/c-chat-message-cbs.h index 2bcd9b729..290e13089 100644 --- a/include/linphone/api/c-chat-message-cbs.h +++ b/include/linphone/api/c-chat-message-cbs.h @@ -60,6 +60,62 @@ LINPHONE_PUBLIC void * linphone_chat_message_cbs_get_user_data (const LinphoneCh **/ LINPHONE_PUBLIC void linphone_chat_message_cbs_set_user_data (LinphoneChatMessageCbs *cbs, void *ud); +/** + * Get the message state changed callback. + * @param[in] cbs LinphoneChatMessageCbs object. + * @return The current message state changed callback. + */ + LINPHONE_PUBLIC LinphoneChatMessageCbsMsgStateChangedCb linphone_chat_message_cbs_get_msg_state_changed(const LinphoneChatMessageCbs *cbs); + + /** + * Set the message state changed callback. + * @param[in] cbs LinphoneChatMessageCbs object. + * @param[in] cb The message state changed callback to be used. + */ + LINPHONE_PUBLIC void linphone_chat_message_cbs_set_msg_state_changed(LinphoneChatMessageCbs *cbs, LinphoneChatMessageCbsMsgStateChangedCb cb); + + /** + * Get the file transfer receive callback. + * @param[in] cbs LinphoneChatMessageCbs object. + * @return The current file transfer receive callback. + */ + LINPHONE_PUBLIC LinphoneChatMessageCbsFileTransferRecvCb linphone_chat_message_cbs_get_file_transfer_recv(const LinphoneChatMessageCbs *cbs); + + /** + * Set the file transfer receive callback. + * @param[in] cbs LinphoneChatMessageCbs object. + * @param[in] cb The file transfer receive callback to be used. + */ + LINPHONE_PUBLIC void linphone_chat_message_cbs_set_file_transfer_recv(LinphoneChatMessageCbs *cbs, LinphoneChatMessageCbsFileTransferRecvCb cb); + + /** + * Get the file transfer send callback. + * @param[in] cbs LinphoneChatMessageCbs object. + * @return The current file transfer send callback. + */ + LINPHONE_PUBLIC LinphoneChatMessageCbsFileTransferSendCb linphone_chat_message_cbs_get_file_transfer_send(const LinphoneChatMessageCbs *cbs); + + /** + * Set the file transfer send callback. + * @param[in] cbs LinphoneChatMessageCbs object. + * @param[in] cb The file transfer send callback to be used. + */ + LINPHONE_PUBLIC void linphone_chat_message_cbs_set_file_transfer_send(LinphoneChatMessageCbs *cbs, LinphoneChatMessageCbsFileTransferSendCb cb); + + /** + * Get the file transfer progress indication callback. + * @param[in] cbs LinphoneChatMessageCbs object. + * @return The current file transfer progress indication callback. + */ + LINPHONE_PUBLIC LinphoneChatMessageCbsFileTransferProgressIndicationCb linphone_chat_message_cbs_get_file_transfer_progress_indication(const LinphoneChatMessageCbs *cbs); + + /** + * Set the file transfer progress indication callback. + * @param[in] cbs LinphoneChatMessageCbs object. + * @param[in] cb The file transfer progress indication callback to be used. + */ + LINPHONE_PUBLIC void linphone_chat_message_cbs_set_file_transfer_progress_indication(LinphoneChatMessageCbs *cbs, LinphoneChatMessageCbsFileTransferProgressIndicationCb cb); + /** * @} */ diff --git a/include/linphone/chat.h b/include/linphone/chat.h index 9444da7f6..bef03747c 100644 --- a/include/linphone/chat.h +++ b/include/linphone/chat.h @@ -342,89 +342,6 @@ LINPHONE_PUBLIC const char* linphone_chat_message_get_message_id(const LinphoneC */ LINPHONE_PUBLIC LinphoneChatMessageCbs * linphone_chat_message_get_callbacks(const LinphoneChatMessage *msg); -/** - * Acquire a reference to the LinphoneChatMessageCbs object. - * @param[in] cbs LinphoneChatMessageCbs object. - * @return The same LinphoneChatMessageCbs object. - */ -LINPHONE_PUBLIC LinphoneChatMessageCbs * linphone_chat_message_cbs_ref(LinphoneChatMessageCbs *cbs); - -/** - * Release reference to the LinphoneChatMessageCbs object. - * @param[in] cbs LinphoneChatMessageCbs object. - */ -LINPHONE_PUBLIC void linphone_chat_message_cbs_unref(LinphoneChatMessageCbs *cbs); - -/** - * Retrieve the user pointer associated with the LinphoneChatMessageCbs object. - * @param[in] cbs LinphoneChatMessageCbs object. - * @return The user pointer associated with the LinphoneChatMessageCbs object. - */ -LINPHONE_PUBLIC void *linphone_chat_message_cbs_get_user_data(const LinphoneChatMessageCbs *cbs); - -/** - * Assign a user pointer to the LinphoneChatMessageCbs object. - * @param[in] cbs LinphoneChatMessageCbs object. - * @param[in] ud The user pointer to associate with the LinphoneChatMessageCbs object. - */ -LINPHONE_PUBLIC void linphone_chat_message_cbs_set_user_data(LinphoneChatMessageCbs *cbs, void *ud); - -/** - * Get the message state changed callback. - * @param[in] cbs LinphoneChatMessageCbs object. - * @return The current message state changed callback. - */ -LINPHONE_PUBLIC LinphoneChatMessageCbsMsgStateChangedCb linphone_chat_message_cbs_get_msg_state_changed(const LinphoneChatMessageCbs *cbs); - -/** - * Set the message state changed callback. - * @param[in] cbs LinphoneChatMessageCbs object. - * @param[in] cb The message state changed callback to be used. - */ -LINPHONE_PUBLIC void linphone_chat_message_cbs_set_msg_state_changed(LinphoneChatMessageCbs *cbs, LinphoneChatMessageCbsMsgStateChangedCb cb); - -/** - * Get the file transfer receive callback. - * @param[in] cbs LinphoneChatMessageCbs object. - * @return The current file transfer receive callback. - */ -LINPHONE_PUBLIC LinphoneChatMessageCbsFileTransferRecvCb linphone_chat_message_cbs_get_file_transfer_recv(const LinphoneChatMessageCbs *cbs); - -/** - * Set the file transfer receive callback. - * @param[in] cbs LinphoneChatMessageCbs object. - * @param[in] cb The file transfer receive callback to be used. - */ -LINPHONE_PUBLIC void linphone_chat_message_cbs_set_file_transfer_recv(LinphoneChatMessageCbs *cbs, LinphoneChatMessageCbsFileTransferRecvCb cb); - -/** - * Get the file transfer send callback. - * @param[in] cbs LinphoneChatMessageCbs object. - * @return The current file transfer send callback. - */ -LINPHONE_PUBLIC LinphoneChatMessageCbsFileTransferSendCb linphone_chat_message_cbs_get_file_transfer_send(const LinphoneChatMessageCbs *cbs); - -/** - * Set the file transfer send callback. - * @param[in] cbs LinphoneChatMessageCbs object. - * @param[in] cb The file transfer send callback to be used. - */ -LINPHONE_PUBLIC void linphone_chat_message_cbs_set_file_transfer_send(LinphoneChatMessageCbs *cbs, LinphoneChatMessageCbsFileTransferSendCb cb); - -/** - * Get the file transfer progress indication callback. - * @param[in] cbs LinphoneChatMessageCbs object. - * @return The current file transfer progress indication callback. - */ -LINPHONE_PUBLIC LinphoneChatMessageCbsFileTransferProgressIndicationCb linphone_chat_message_cbs_get_file_transfer_progress_indication(const LinphoneChatMessageCbs *cbs); - -/** - * Set the file transfer progress indication callback. - * @param[in] cbs LinphoneChatMessageCbs object. - * @param[in] cb The file transfer progress indication callback to be used. - */ -LINPHONE_PUBLIC void linphone_chat_message_cbs_set_file_transfer_progress_indication(LinphoneChatMessageCbs *cbs, LinphoneChatMessageCbsFileTransferProgressIndicationCb cb); - /** * @} */ diff --git a/src/c-wrapper/api/c-chat-message-cbs.cpp b/src/c-wrapper/api/c-chat-message-cbs.cpp index d26604dae..3fbae1a2d 100644 --- a/src/c-wrapper/api/c-chat-message-cbs.cpp +++ b/src/c-wrapper/api/c-chat-message-cbs.cpp @@ -65,3 +65,41 @@ void * linphone_chat_message_cbs_get_user_data (const LinphoneChatMessageCbs *cb void linphone_chat_message_cbs_set_user_data (LinphoneChatMessageCbs *cbs, void *ud) { cbs->userData = ud; } + +LinphoneChatMessageCbsMsgStateChangedCb +linphone_chat_message_cbs_get_msg_state_changed(const LinphoneChatMessageCbs *cbs) { + return cbs->msg_state_changed; +} + +void linphone_chat_message_cbs_set_msg_state_changed(LinphoneChatMessageCbs *cbs, + LinphoneChatMessageCbsMsgStateChangedCb cb) { + cbs->msg_state_changed = cb; +} + +LinphoneChatMessageCbsFileTransferRecvCb linphone_chat_message_cbs_get_file_transfer_recv(const LinphoneChatMessageCbs *cbs) { + return cbs->file_transfer_recv; +} + +void linphone_chat_message_cbs_set_file_transfer_recv(LinphoneChatMessageCbs *cbs, + LinphoneChatMessageCbsFileTransferRecvCb cb) { + cbs->file_transfer_recv = cb; +} + +LinphoneChatMessageCbsFileTransferSendCb linphone_chat_message_cbs_get_file_transfer_send(const LinphoneChatMessageCbs *cbs) { + return cbs->file_transfer_send; +} + +void linphone_chat_message_cbs_set_file_transfer_send(LinphoneChatMessageCbs *cbs, + LinphoneChatMessageCbsFileTransferSendCb cb) { + cbs->file_transfer_send = cb; +} + +LinphoneChatMessageCbsFileTransferProgressIndicationCb +linphone_chat_message_cbs_get_file_transfer_progress_indication(const LinphoneChatMessageCbs *cbs) { + return cbs->file_transfer_progress_indication; +} + +void linphone_chat_message_cbs_set_file_transfer_progress_indication( + LinphoneChatMessageCbs *cbs, LinphoneChatMessageCbsFileTransferProgressIndicationCb cb) { + cbs->file_transfer_progress_indication = cb; +} From bcd6a682f26c885618bf498ecea3d68aa6570312 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 20 Sep 2017 15:03:02 +0200 Subject: [PATCH 0099/2215] Fix order of includes to prevent issues with gettext. --- src/conference/local-conference-event-handler.cpp | 5 +++-- src/conference/remote-conference-event-handler.cpp | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index bc84868a2..d06cf4d9a 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -21,8 +21,6 @@ #include "local-conference-event-handler.h" #include "object/object-p.h" -#include "private.h" - #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsuggest-override" @@ -34,6 +32,9 @@ #pragma GCC diagnostic pop #endif +/* Needs to be included after xml/conference-info.h because of _() macro definition that breaks everything */ +#include "private.h" + // ============================================================================= using namespace std; diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 433465bda..8e6099552 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -17,7 +17,6 @@ */ #include "remote-conference-event-handler.h" -#include "private.h" #include "object/object-p.h" #if __clang__ || __GNUC__ >= 4 @@ -31,6 +30,9 @@ #pragma GCC diagnostic pop #endif +/* Needs to be included after xml/conference-info.h because of _() macro definition that breaks everything */ +#include "private.h" + // ============================================================================= using namespace std; From 902ea0a469f96b2a7a5a505cb71506829eaf1e0c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 20 Sep 2017 15:03:29 +0200 Subject: [PATCH 0100/2215] Add missing include. --- include/linphone/chat.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linphone/chat.h b/include/linphone/chat.h index bef03747c..55cd9b2ea 100644 --- a/include/linphone/chat.h +++ b/include/linphone/chat.h @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/types.h" #include "linphone/api/c-types.h" #include "linphone/api/c-chat-message.h" +#include "linphone/api/c-chat-message-cbs.h" #include "linphone/api/c-chat-room.h" #include "linphone/api/c-chat-room-cbs.h" From 4dff332dc772fb7bb89a4ca93650404f50fb48a5 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 20 Sep 2017 15:14:33 +0200 Subject: [PATCH 0101/2215] Fixes for compilation issue with chat latest changes --- coreapi/chat.c | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index d60865b7b..62b708293 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -42,9 +42,6 @@ #include "chat/real-time-text-chat-room-p.h" #include "content/content-type.h" - -BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneChatMessage); - void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessageState state) { /* do not invoke callbacks on orphan messages */ if (state != msg->state && msg->chat_room != NULL) { @@ -65,12 +62,6 @@ void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessa } } -BELLE_SIP_INSTANCIATE_VPTR(LinphoneChatMessage, belle_sip_object_t, - (belle_sip_object_destroy_t)_linphone_chat_message_destroy, - NULL, // clone - NULL, // marshal - FALSE); - void linphone_core_disable_chat(LinphoneCore *lc, LinphoneReason deny_reason) { lc->chat_deny_code = deny_reason; } @@ -665,38 +656,6 @@ void linphone_chat_message_destroy(LinphoneChatMessage *msg) { belle_sip_object_unref(msg); } -static void _linphone_chat_message_destroy(LinphoneChatMessage *msg) { - if (msg->op) - sal_op_release(msg->op); - if (msg->ei) - linphone_error_info_unref(msg->ei); - if (msg->message) - ms_free(msg->message); - if (msg->external_body_url) - ms_free(msg->external_body_url); - if (msg->appdata) - ms_free(msg->appdata); - if (msg->from) - linphone_address_unref(msg->from); - if (msg->to) - linphone_address_unref(msg->to); - if (msg->message_id) - ms_free(msg->message_id); - if (msg->custom_headers) - sal_custom_header_free(msg->custom_headers); - if (msg->content_type) - ms_free(msg->content_type); - if (msg->file_transfer_information) { - linphone_content_unref(msg->file_transfer_information); - } - if (msg->file_transfer_filepath != NULL) { - ms_free(msg->file_transfer_filepath); - } - if (msg->callbacks) { - linphone_chat_message_cbs_unref(msg->callbacks); - } -} - void linphone_chat_message_deactivate(LinphoneChatMessage *msg){ if (msg->file_transfer_information != NULL) { _linphone_chat_message_cancel_file_transfer(msg, FALSE); From 2d242ad9c47ec489fa726dc5ab0be957c70c5605 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 20 Sep 2017 15:54:04 +0200 Subject: [PATCH 0102/2215] add prologue and epilogue to XSD generated files --- src/xml/conference-info.cpp | 73 +++++++++++++++++++------------------ src/xml/conference-info.h | 11 ++++++ src/xml/generate.py | 17 +++++++++ src/xml/resource-lists.cpp | 11 ++++++ src/xml/resource-lists.h | 11 ++++++ src/xml/xml.cpp | 27 ++++++++------ src/xml/xml.h | 11 ++++++ 7 files changed, 114 insertions(+), 47 deletions(-) diff --git a/src/xml/conference-info.cpp b/src/xml/conference-info.cpp index e09fb01ae..7cd27bf03 100644 --- a/src/xml/conference-info.cpp +++ b/src/xml/conference-info.cpp @@ -33,26 +33,23 @@ // Begin prologue. // -// -// End prologue. - -#include #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsuggest-override" #endif -#include "conference-info.h" +// +// End prologue. -#if __clang__ || __GNUC__ >= 4 - #pragma GCC diagnostic pop -#endif +#include + +#include "conference-info.h" namespace conference_info { // Conference_type - // + // const Conference_type::Conference_descriptionOptional& Conference_type:: getConference_description () const @@ -374,7 +371,7 @@ namespace conference_info // State_type - // + // State_type:: State_type (Value v) @@ -411,7 +408,7 @@ namespace conference_info State_type& State_type:: operator= (Value v) { - static_cast< ::xml_schema::String& > (*this) = + static_cast< ::xml_schema::String& > (*this) = ::xml_schema::String (_xsd_State_type_literals_[v]); return *this; @@ -419,7 +416,7 @@ namespace conference_info // Conference_description_type - // + // const Conference_description_type::Display_textOptional& Conference_description_type:: getDisplay_text () const @@ -705,7 +702,7 @@ namespace conference_info // Host_type - // + // const Host_type::Display_textOptional& Host_type:: getDisplay_text () const @@ -847,7 +844,7 @@ namespace conference_info // Conference_state_type - // + // const Conference_state_type::User_countOptional& Conference_state_type:: getUser_count () const @@ -971,7 +968,7 @@ namespace conference_info // Conference_media_type - // + // const Conference_media_type::EntrySequence& Conference_media_type:: getEntry () const @@ -1023,7 +1020,7 @@ namespace conference_info // Conference_medium_type - // + // const Conference_medium_type::Display_textOptional& Conference_medium_type:: getDisplay_text () const @@ -1195,7 +1192,7 @@ namespace conference_info // Uris_type - // + // const Uris_type::EntrySequence& Uris_type:: getEntry () const @@ -1283,7 +1280,7 @@ namespace conference_info // Uri_type - // + // const Uri_type::UriType& Uri_type:: getUri () const @@ -1479,7 +1476,7 @@ namespace conference_info } // Users_type - // + // const Users_type::UserSequence& Users_type:: getUser () const @@ -1585,7 +1582,7 @@ namespace conference_info // User_type - // + // const User_type::Display_textOptional& User_type:: getDisplay_text () const @@ -1871,7 +1868,7 @@ namespace conference_info // User_roles_type - // + // const User_roles_type::EntrySequence& User_roles_type:: getEntry () const @@ -1947,7 +1944,7 @@ namespace conference_info } // Endpoint_type - // + // const Endpoint_type::Display_textOptional& Endpoint_type:: getDisplay_text () const @@ -2323,7 +2320,7 @@ namespace conference_info // Endpoint_status_type - // + // Endpoint_status_type:: Endpoint_status_type (Value v) @@ -2360,7 +2357,7 @@ namespace conference_info Endpoint_status_type& Endpoint_status_type:: operator= (Value v) { - static_cast< ::xml_schema::String& > (*this) = + static_cast< ::xml_schema::String& > (*this) = ::xml_schema::String (_xsd_Endpoint_status_type_literals_[v]); return *this; @@ -2368,7 +2365,7 @@ namespace conference_info // Joining_type - // + // Joining_type:: Joining_type (Value v) @@ -2405,7 +2402,7 @@ namespace conference_info Joining_type& Joining_type:: operator= (Value v) { - static_cast< ::xml_schema::String& > (*this) = + static_cast< ::xml_schema::String& > (*this) = ::xml_schema::String (_xsd_Joining_type_literals_[v]); return *this; @@ -2413,7 +2410,7 @@ namespace conference_info // Disconnection_type - // + // Disconnection_type:: Disconnection_type (Value v) @@ -2450,7 +2447,7 @@ namespace conference_info Disconnection_type& Disconnection_type:: operator= (Value v) { - static_cast< ::xml_schema::String& > (*this) = + static_cast< ::xml_schema::String& > (*this) = ::xml_schema::String (_xsd_Disconnection_type_literals_[v]); return *this; @@ -2458,7 +2455,7 @@ namespace conference_info // Execution_type - // + // const Execution_type::WhenOptional& Execution_type:: getWhen () const @@ -2582,7 +2579,7 @@ namespace conference_info // Call_type - // + // const Call_type::SipOptional& Call_type:: getSip () const @@ -2664,7 +2661,7 @@ namespace conference_info // Sip_dialog_id_type - // + // const Sip_dialog_id_type::Display_textOptional& Sip_dialog_id_type:: getDisplay_text () const @@ -2836,7 +2833,7 @@ namespace conference_info // Media_type - // + // const Media_type::Display_textOptional& Media_type:: getDisplay_text () const @@ -3068,7 +3065,7 @@ namespace conference_info // Media_status_type - // + // Media_status_type:: Media_status_type (Value v) @@ -3105,7 +3102,7 @@ namespace conference_info Media_status_type& Media_status_type:: operator= (Value v) { - static_cast< ::xml_schema::String& > (*this) = + static_cast< ::xml_schema::String& > (*this) = ::xml_schema::String (_xsd_Media_status_type_literals_[v]); return *this; @@ -3113,7 +3110,7 @@ namespace conference_info // Sidebars_by_val_type - // + // const Sidebars_by_val_type::EntrySequence& Sidebars_by_val_type:: getEntry () const @@ -9276,5 +9273,11 @@ namespace conference_info // Begin epilogue. // + +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic pop +#endif + // // End epilogue. + diff --git a/src/xml/conference-info.h b/src/xml/conference-info.h index 1626d55e3..f950882c9 100644 --- a/src/xml/conference-info.h +++ b/src/xml/conference-info.h @@ -48,6 +48,12 @@ // Begin prologue. // + +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wsuggest-override" +#endif + // // End prologue. @@ -3856,6 +3862,11 @@ namespace conference_info // Begin epilogue. // + +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic pop +#endif + // // End epilogue. diff --git a/src/xml/generate.py b/src/xml/generate.py index 42b400479..256230869 100755 --- a/src/xml/generate.py +++ b/src/xml/generate.py @@ -30,6 +30,21 @@ def find_xsdcxx(): xsdcxx = find_executable("xsd") return xsdcxx +def get_prologue(): + return """ +#if __clang__ || __GNUC__ >= 4 +\t#pragma GCC diagnostic push +\t#pragma GCC diagnostic ignored "-Wsuggest-override" +#endif +""" + +def get_epilogue(): + return """ +#if __clang__ || __GNUC__ >= 4 +\t#pragma GCC diagnostic pop +#endif +""" + def generate(name): xsdcxx = find_xsdcxx() if xsdcxx is None: @@ -57,6 +72,8 @@ def generate(name): "--hxx-suffix", ".h", "--ixx-suffix", ".h", "--cxx-suffix", ".cpp", + "--prologue", get_prologue(), + "--epilogue", get_epilogue(), "--location-regex", "%http://.+/(.+)%$1%", "--output-dir", "xml", source_file diff --git a/src/xml/resource-lists.cpp b/src/xml/resource-lists.cpp index 0f94f63c0..bbafc58ea 100644 --- a/src/xml/resource-lists.cpp +++ b/src/xml/resource-lists.cpp @@ -33,6 +33,12 @@ // Begin prologue. // + +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wsuggest-override" +#endif + // // End prologue. @@ -2446,6 +2452,11 @@ namespace resource_lists // Begin epilogue. // + +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic pop +#endif + // // End epilogue. diff --git a/src/xml/resource-lists.h b/src/xml/resource-lists.h index 4c499fa3d..b3dab2800 100644 --- a/src/xml/resource-lists.h +++ b/src/xml/resource-lists.h @@ -48,6 +48,12 @@ // Begin prologue. // + +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wsuggest-override" +#endif + // // End prologue. @@ -1248,6 +1254,11 @@ namespace resource_lists // Begin epilogue. // + +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic pop +#endif + // // End epilogue. diff --git a/src/xml/xml.cpp b/src/xml/xml.cpp index d8fb4a977..68e991eb8 100644 --- a/src/xml/xml.cpp +++ b/src/xml/xml.cpp @@ -33,21 +33,18 @@ // Begin prologue. // -// -// End prologue. - -#include #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsuggest-override" #endif -#include "xml.h" +// +// End prologue. -#if __clang__ || __GNUC__ >= 4 - #pragma GCC diagnostic pop -#endif +#include + +#include "xml.h" namespace namespace_ { @@ -75,7 +72,7 @@ namespace namespace_ } // Space - // + // Space:: Space (Value v) @@ -112,7 +109,7 @@ namespace namespace_ Space& Space:: operator= (Value v) { - static_cast< ::xml_schema::Ncname& > (*this) = + static_cast< ::xml_schema::Ncname& > (*this) = ::xml_schema::Ncname (_xsd_Space_literals_[v]); return *this; @@ -120,7 +117,7 @@ namespace namespace_ // Lang_member - // + // Lang_member:: Lang_member (Value v) @@ -157,7 +154,7 @@ namespace namespace_ Lang_member& Lang_member:: operator= (Value v) { - static_cast< ::xml_schema::String& > (*this) = + static_cast< ::xml_schema::String& > (*this) = ::xml_schema::String (_xsd_Lang_member_literals_[v]); return *this; @@ -455,5 +452,11 @@ namespace namespace_ // Begin epilogue. // + +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic pop +#endif + // // End epilogue. + diff --git a/src/xml/xml.h b/src/xml/xml.h index 916ef8807..54ad50e8c 100644 --- a/src/xml/xml.h +++ b/src/xml/xml.h @@ -48,6 +48,12 @@ // Begin prologue. // + +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wsuggest-override" +#endif + // // End prologue. @@ -497,6 +503,11 @@ namespace namespace_ // Begin epilogue. // + +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic pop +#endif + // // End epilogue. From 6b143b0cad5994d6875e3c682bae197a8518cde5 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 20 Sep 2017 17:30:07 +0200 Subject: [PATCH 0103/2215] feat(EventLog): wrap (partially) --- coreapi/private.h | 76 +++++++------ include/linphone/api/c-event-log.h | 22 +++- include/linphone/api/c-types.h | 2 +- include/linphone/enums/event-log-enums.h | 2 +- src/CMakeLists.txt | 4 +- src/c-wrapper/api/c-event-log.cpp | 106 ++++++++++++------ src/db/events-db.cpp | 4 +- ...ssage-event.cpp => chat-message-event.cpp} | 34 +++--- .../{message-event.h => chat-message-event.h} | 24 ++-- src/event-log/conference-event-p.h | 3 +- src/event-log/conference-event.cpp | 14 +-- src/event-log/conference-event.h | 8 +- .../conference-participant-event.cpp | 13 +-- src/event-log/conference-participant-event.h | 6 +- 14 files changed, 184 insertions(+), 134 deletions(-) rename src/event-log/{message-event.cpp => chat-message-event.cpp} (56%) rename src/event-log/{message-event.h => chat-message-event.h} (64%) diff --git a/coreapi/private.h b/coreapi/private.h index 3bcd62a49..06652f862 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -1658,66 +1658,68 @@ LinphoneCallStats *linphone_call_stats_new(void); /** Belle Sip-based objects need unique ids */ -BELLE_SIP_DECLARE_TYPES_BEGIN(linphone,10000) +BELLE_SIP_DECLARE_TYPES_BEGIN(linphone, 10000) BELLE_SIP_TYPE_ID(LinphoneAccountCreator), BELLE_SIP_TYPE_ID(LinphoneAccountCreatorCbs), BELLE_SIP_TYPE_ID(LinphoneAccountCreatorService), BELLE_SIP_TYPE_ID(LinphoneAddress), +BELLE_SIP_TYPE_ID(LinphoneAuthInfo), BELLE_SIP_TYPE_ID(LinphoneBuffer), -BELLE_SIP_TYPE_ID(LinphoneContactProvider), -BELLE_SIP_TYPE_ID(LinphoneContactSearch), BELLE_SIP_TYPE_ID(LinphoneCall), BELLE_SIP_TYPE_ID(LinphoneCallCbs), +BELLE_SIP_TYPE_ID(LinphoneCallEvent), BELLE_SIP_TYPE_ID(LinphoneCallLog), BELLE_SIP_TYPE_ID(LinphoneCallParams), +BELLE_SIP_TYPE_ID(LinphoneCallStats), BELLE_SIP_TYPE_ID(LinphoneChatMessage), BELLE_SIP_TYPE_ID(LinphoneChatMessageCbs), +BELLE_SIP_TYPE_ID(LinphoneChatMessageEvent), BELLE_SIP_TYPE_ID(LinphoneChatRoom), BELLE_SIP_TYPE_ID(LinphoneChatRoomCbs), +BELLE_SIP_TYPE_ID(LinphoneConference), +BELLE_SIP_TYPE_ID(LinphoneConferenceEvent), +BELLE_SIP_TYPE_ID(LinphoneConferenceParams), +BELLE_SIP_TYPE_ID(LinphoneConferenceParticipantEvent), +BELLE_SIP_TYPE_ID(LinphoneConfig), +BELLE_SIP_TYPE_ID(LinphoneContactProvider), +BELLE_SIP_TYPE_ID(LinphoneContactSearch), BELLE_SIP_TYPE_ID(LinphoneContent), +BELLE_SIP_TYPE_ID(LinphoneCore), +BELLE_SIP_TYPE_ID(LinphoneCoreCbs), +BELLE_SIP_TYPE_ID(LinphoneErrorInfo), +BELLE_SIP_TYPE_ID(LinphoneEvent), +BELLE_SIP_TYPE_ID(LinphoneEventLog), +BELLE_SIP_TYPE_ID(LinphoneFactory), +BELLE_SIP_TYPE_ID(LinphoneFriend), +BELLE_SIP_TYPE_ID(LinphoneFriendList), +BELLE_SIP_TYPE_ID(LinphoneFriendListCbs), BELLE_SIP_TYPE_ID(LinphoneImEncryptionEngine), BELLE_SIP_TYPE_ID(LinphoneImEncryptionEngineCbs), BELLE_SIP_TYPE_ID(LinphoneImNotifPolicy), +BELLE_SIP_TYPE_ID(LinphoneInfoMessage), BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider), BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch), -BELLE_SIP_TYPE_ID(LinphoneProxyConfig), -BELLE_SIP_TYPE_ID(LinphoneFriend), -BELLE_SIP_TYPE_ID(LinphoneFriendList), -BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequest), -BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequestCbs), -BELLE_SIP_TYPE_ID(LinphoneXmlRpcSession), -BELLE_SIP_TYPE_ID(LinphoneTunnel), -BELLE_SIP_TYPE_ID(LinphoneTunnelConfig), -BELLE_SIP_TYPE_ID(LinphoneFriendListCbs), -BELLE_SIP_TYPE_ID(LinphoneEvent), BELLE_SIP_TYPE_ID(LinphoneNatPolicy), -BELLE_SIP_TYPE_ID(LinphoneCore), -BELLE_SIP_TYPE_ID(LinphoneCoreCbs), -BELLE_SIP_TYPE_ID(LinphoneFactory), -BELLE_SIP_TYPE_ID(LinphoneAuthInfo), -BELLE_SIP_TYPE_ID(LinphoneVcard), -BELLE_SIP_TYPE_ID(LinphoneConfig), -BELLE_SIP_TYPE_ID(LinphonePresenceModel), -BELLE_SIP_TYPE_ID(LinphonePresenceService), -BELLE_SIP_TYPE_ID(LinphonePresencePerson), -BELLE_SIP_TYPE_ID(LinphonePresenceActivity), -BELLE_SIP_TYPE_ID(LinphonePresenceNote), -BELLE_SIP_TYPE_ID(LinphoneErrorInfo), -BELLE_SIP_TYPE_ID(LinphoneConferenceParams), -BELLE_SIP_TYPE_ID(LinphoneConference), -BELLE_SIP_TYPE_ID(LinphoneInfoMessage), +BELLE_SIP_TYPE_ID(LinphoneParticipant), BELLE_SIP_TYPE_ID(LinphonePayloadType), -BELLE_SIP_TYPE_ID(LinphoneRange), -BELLE_SIP_TYPE_ID(LinphoneVideoDefinition), -BELLE_SIP_TYPE_ID(LinphoneTransports), -BELLE_SIP_TYPE_ID(LinphoneVideoActivationPolicy), -BELLE_SIP_TYPE_ID(LinphoneCallStats), BELLE_SIP_TYPE_ID(LinphonePlayer), BELLE_SIP_TYPE_ID(LinphonePlayerCbs), -BELLE_SIP_TYPE_ID(LinphoneEventLog), -BELLE_SIP_TYPE_ID(LinphoneMessage), -BELLE_SIP_TYPE_ID(LinphoneMessageEvent), -BELLE_SIP_TYPE_ID(LinphoneParticipant) +BELLE_SIP_TYPE_ID(LinphonePresenceActivity), +BELLE_SIP_TYPE_ID(LinphonePresenceModel), +BELLE_SIP_TYPE_ID(LinphonePresenceNote), +BELLE_SIP_TYPE_ID(LinphonePresencePerson), +BELLE_SIP_TYPE_ID(LinphonePresenceService), +BELLE_SIP_TYPE_ID(LinphoneProxyConfig), +BELLE_SIP_TYPE_ID(LinphoneRange), +BELLE_SIP_TYPE_ID(LinphoneTransports), +BELLE_SIP_TYPE_ID(LinphoneTunnel), +BELLE_SIP_TYPE_ID(LinphoneTunnelConfig), +BELLE_SIP_TYPE_ID(LinphoneVcard), +BELLE_SIP_TYPE_ID(LinphoneVideoActivationPolicy), +BELLE_SIP_TYPE_ID(LinphoneVideoDefinition), +BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequest), +BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequestCbs), +BELLE_SIP_TYPE_ID(LinphoneXmlRpcSession) BELLE_SIP_DECLARE_TYPES_END diff --git a/include/linphone/api/c-event-log.h b/include/linphone/api/c-event-log.h index dcc56f76b..2f4cd097f 100644 --- a/include/linphone/api/c-event-log.h +++ b/include/linphone/api/c-event-log.h @@ -28,16 +28,19 @@ #endif // ifdef __cplusplus LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_new (); +LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_clone (const LinphoneEventLog *event_log); +LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_ref (LinphoneEventLog *event_log); LINPHONE_PUBLIC LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *event_log); LINPHONE_PUBLIC LinphoneCallEvent *linphone_call_event_new (LinphoneEventLogType type, LinphoneCall *call); +LINPHONE_PUBLIC LinphoneCallEvent *linphone_call_event_clone (const LinphoneCallEvent *call_event); LINPHONE_PUBLIC LinphoneCall *linphone_call_event_get_call (const LinphoneCallEvent *call_event); LINPHONE_PUBLIC LinphoneConferenceEvent *linphone_conference_event_new ( LinphoneEventLogType type, const LinphoneAddress *address ); - +LINPHONE_PUBLIC LinphoneConferenceEvent *linphone_conference_event_clone (const LinphoneConferenceEvent *conference_event); LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_event_get_address (const LinphoneConferenceEvent *conference_event); LINPHONE_PUBLIC LinphoneConferenceParticipantEvent *linphone_conference_participant_event_new ( @@ -45,11 +48,20 @@ LINPHONE_PUBLIC LinphoneConferenceParticipantEvent *linphone_conference_particip const LinphoneAddress *conferenceAddress, const LinphoneAddress *participantAddress ); +LINPHONE_PUBLIC LinphoneConferenceParticipantEvent *linphone_conference_participant_event_clone ( + const LinphoneConferenceParticipantEvent *conference_participant_event +); +LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_participant_event_get_participant_address ( + const LinphoneConferenceParticipantEvent *conference_participant_event +); -LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_participant_event_get_participant_address (const LinphoneConferenceParticipantEvent *conference_participant_event); - -LINPHONE_PUBLIC LinphoneMessageEvent *linphone_message_event_new (LinphoneMessage *message); -LINPHONE_PUBLIC LinphoneMessage *linphone_message_event_get_message (const LinphoneMessageEvent *message_event); +LINPHONE_PUBLIC LinphoneChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage *chat_message); +LINPHONE_PUBLIC LinphoneChatMessageEvent *linphone_chat_message_event_clone ( + const LinphoneChatMessageEvent *chat_message_event +); +LINPHONE_PUBLIC LinphoneChatMessage *linphone_chat_message_event_get_chat_message ( + const LinphoneChatMessageEvent *chat_message_event +); #ifdef __cplusplus } diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index 7e53de356..be2d44f2b 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -114,7 +114,7 @@ typedef struct _LinphoneCallEvent LinphoneCallEvent; typedef struct _LinphoneConferenceEvent LinphoneConferenceEvent; typedef struct _LinphoneConferenceParticipantEvent LinphoneConferenceParticipantEvent; typedef struct _LinphoneEventLog LinphoneEventLog; -typedef struct _LinphoneMessageEvent LinphoneMessageEvent; +typedef struct _LinphoneChatMessageEvent LinphoneChatMessageEvent; // ============================================================================= // C Enums. diff --git a/include/linphone/enums/event-log-enums.h b/include/linphone/enums/event-log-enums.h index 2eb4d4416..b71606f6b 100644 --- a/include/linphone/enums/event-log-enums.h +++ b/include/linphone/enums/event-log-enums.h @@ -23,7 +23,7 @@ #define L_ENUM_VALUES_EVENT_LOG_TYPE(F) \ F(None) \ - F(Message) \ + F(ChatMessage) \ F(CallStart) \ F(CallEnd) \ F(ConferenceCreated) \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 20eaccdc7..a7febd197 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -78,12 +78,12 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES db/provider/db-session.h enums.h event-log/call-event.h + event-log/chat-message-event.h event-log/conference-event-p.h event-log/conference-event.h event-log/conference-participant-event.h event-log/event-log-p.h event-log/event-log.h - event-log/message-event.h logger/logger.h nat/ice-agent.h nat/stun-client.h @@ -143,10 +143,10 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES db/provider/db-session-provider.cpp db/provider/db-session.cpp event-log/call-event.cpp + event-log/chat-message-event.cpp event-log/conference-event.cpp event-log/conference-participant-event.cpp event-log/event-log.cpp - event-log/message-event.cpp logger/logger.cpp nat/ice-agent.cpp nat/stun-client.cpp diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 8c021be21..a1bd1a12f 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -16,68 +16,80 @@ * along with this program. If not, see . */ +#include "linphone/api/c-chat-message.h" #include "linphone/api/c-event-log.h" #include "c-wrapper/c-tools.h" +#include "call/call.h" +#include "chat/chat-message.h" #include "event-log/call-event.h" +#include "event-log/chat-message-event.h" #include "event-log/conference-participant-event.h" -#include "event-log/message-event.h" // ============================================================================= +L_DECLARE_C_CLONABLE_STRUCT_IMPL(EventLog, EventLog, event_log); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(CallEvent, CallEvent, call_event); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(ConferenceEvent, ConferenceEvent, conference_event); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(ConferenceParticipantEvent, ConferenceParticipantEvent, conference_participant_event); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(ChatMessageEvent, ChatMessageEvent, chat_message_event); + using namespace std; // ----------------------------------------------------------------------------- // Event log. // ----------------------------------------------------------------------------- -L_DECLARE_C_STRUCT_IMPL(EventLog, EventLog, event_log); -L_DECLARE_C_STRUCT_NEW_DEFAULT(EventLog, event_log); - -LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *eventLog) { - return static_cast(eventLog->cppPtr->getType()); +LinphoneEventLog *linphone_event_log_new () { + LinphoneEventLog *event_log = _linphone_event_log_init(); + L_SET_CPP_PTR_FROM_C_STRUCT(event_log, new LINPHONE_NAMESPACE::EventLog()); + return event_log; } -// ----------------------------------------------------------------------------- -// Message event. -// ----------------------------------------------------------------------------- - -L_DECLARE_C_STRUCT_IMPL(MessageEvent, MessageEvent, message_event); - -LinphoneMessageEvent *linphone_message_event_new (LinphoneMessage *message) { - LinphoneMessageEvent *object = _linphone_message_event_init(); - // TODO: call make_shared with cppPtr. - object->cppPtr = make_shared(nullptr); - return object; +LinphoneEventLog *linphone_event_log_ref (LinphoneEventLog *event_log) { + belle_sip_object_ref(event_log); + return event_log; } -LinphoneMessage *linphone_message_event_get_message (const LinphoneMessageEvent *messageEvent) { - // TODO. - return nullptr; +LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *event_log) { + return static_cast( + L_GET_CPP_PTR_FROM_C_STRUCT(event_log, EventLog, EventLog)->getType() + ); } // ----------------------------------------------------------------------------- // Call event. // ----------------------------------------------------------------------------- -// L_DECLARE_C_STRUCT_IMPL(CallEvent, call_event); - LinphoneCallEvent *linphone_call_event_new (LinphoneEventLogType type, LinphoneCall *call) { - // TODO. - return nullptr; + LinphoneCallEvent *call_event = _linphone_call_event_init(); + L_SET_CPP_PTR_FROM_C_STRUCT( + call_event, + new LINPHONE_NAMESPACE::CallEvent( + static_cast(type), + L_GET_CPP_PTR_FROM_C_STRUCT(call, Call, Call) + ) + ); + return call_event; } +// TODO: REMOVE ME. +extern LinphoneCall *_linphone_call_init (); + LinphoneCall *linphone_call_event_get_call (const LinphoneCallEvent *call_event) { - // TODO. - return nullptr; + return L_GET_C_BACK_PTR( + L_GET_CPP_PTR_FROM_C_STRUCT( + call_event, CallEvent, CallEvent + )->getCall(), + Call, + call + ); } // ----------------------------------------------------------------------------- // Conference event. // ----------------------------------------------------------------------------- -// L_DECLARE_C_STRUCT_IMPL(ConferenceEvent, conference_event); - LinphoneConferenceEvent *linphone_conference_event_new ( LinphoneEventLogType type, const LinphoneAddress *address @@ -95,18 +107,46 @@ const LinphoneAddress *linphone_conference_event_get_address (const LinphoneConf // Conference participant event. // ----------------------------------------------------------------------------- -// L_DECLARE_C_STRUCT_IMPL(ConferenceParticipantEvent, conference_participant_event); - LinphoneConferenceParticipantEvent *linphone_conference_participant_event_new ( LinphoneEventLogType type, - const LinphoneAddress *conference_address, - const LinphoneAddress *participant_address + const LinphoneAddress *conferenceAddress, + const LinphoneAddress *participantAddress ) { // TODO. return nullptr; } -const LinphoneAddress *linphone_conference_participant_event_get_participant_address (const LinphoneConferenceParticipantEvent *conference_participant_event) { +const LinphoneAddress *linphone_conference_participant_event_get_participant_address ( + const LinphoneConferenceParticipantEvent *conference_participant_event +) { // TODO. return nullptr; } + +// ----------------------------------------------------------------------------- +// Message event. +// ----------------------------------------------------------------------------- + +LinphoneChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage *chat_message) { + LinphoneChatMessageEvent *chat_message_event = _linphone_chat_message_event_init(); + L_SET_CPP_PTR_FROM_C_STRUCT( + chat_message_event, + new LINPHONE_NAMESPACE::ChatMessageEvent( + L_GET_CPP_PTR_FROM_C_STRUCT(chat_message, ChatMessage, ChatMessage) + ) + ); + return chat_message_event; +} + +// TODO: REMOVE ME. +extern LinphoneChatMessage *_linphone_chat_message_init (); + +LinphoneChatMessage *linphone_chat_message_event_get_chat_message (const LinphoneChatMessageEvent *chat_message_event) { + return L_GET_C_BACK_PTR( + L_GET_CPP_PTR_FROM_C_STRUCT( + chat_message_event, ChatMessageEvent, ChatMessageEvent + )->getChatMessage(), + ChatMessage, + chat_message + ); +} diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 6cd193f5b..2c30994fd 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -25,7 +25,7 @@ #include "abstract/abstract-db-p.h" #include "chat/chat-message.h" #include "event-log/call-event.h" -#include "event-log/message-event.h" +#include "event-log/chat-message-event.h" #include "logger/logger.h" #include "events-db.h" @@ -283,7 +283,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} switch (eventLog.getType()) { case EventLog::Type::None: return false; - case EventLog::Type::Message: + case EventLog::Type::ChatMessage: case EventLog::Type::CallStart: case EventLog::Type::CallEnd: case EventLog::Type::ConferenceCreated: diff --git a/src/event-log/message-event.cpp b/src/event-log/chat-message-event.cpp similarity index 56% rename from src/event-log/message-event.cpp rename to src/event-log/chat-message-event.cpp index 319ab3b7a..bae401244 100644 --- a/src/event-log/message-event.cpp +++ b/src/event-log/chat-message-event.cpp @@ -1,5 +1,5 @@ /* - * message-event.cpp + * chat-message-event.cpp * Copyright (C) 2017 Belledonne Communications SARL * * This program is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ #include "event-log-p.h" -#include "message-event.h" +#include "chat-message-event.h" // ============================================================================= @@ -26,35 +26,35 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -class MessageEventPrivate : public EventLogPrivate { +class ChatMessageEventPrivate : public EventLogPrivate { public: - shared_ptr message; + shared_ptr chatMessage; }; // ----------------------------------------------------------------------------- -MessageEvent::MessageEvent (const shared_ptr &message) : - EventLog(*new MessageEventPrivate, EventLog::Type::Message) { - L_D(MessageEvent); - L_ASSERT(message); - d->message = message; +ChatMessageEvent::ChatMessageEvent (const shared_ptr &chatMessage) : + EventLog(*new ChatMessageEventPrivate, EventLog::Type::ChatMessage) { + L_D(ChatMessageEvent); + L_ASSERT(chatMessage); + d->chatMessage = chatMessage; } -MessageEvent::MessageEvent (const MessageEvent &src) : MessageEvent(src.getMessage()) {} +ChatMessageEvent::ChatMessageEvent (const ChatMessageEvent &src) : ChatMessageEvent(src.getChatMessage()) {} -MessageEvent &MessageEvent::operator= (const MessageEvent &src) { - L_D(MessageEvent); +ChatMessageEvent &ChatMessageEvent::operator= (const ChatMessageEvent &src) { + L_D(ChatMessageEvent); if (this != &src) { - EventLog::operator=(src); - d->message = src.getPrivate()->message; + EventLog::operator= (src); + d->chatMessage = src.getPrivate()->chatMessage; } return *this; } -shared_ptr MessageEvent::getMessage () const { - L_D(const MessageEvent); - return d->message; +shared_ptr ChatMessageEvent::getChatMessage () const { + L_D(const ChatMessageEvent); + return d->chatMessage; } LINPHONE_END_NAMESPACE diff --git a/src/event-log/message-event.h b/src/event-log/chat-message-event.h similarity index 64% rename from src/event-log/message-event.h rename to src/event-log/chat-message-event.h index b1c12a5fb..9acf3c745 100644 --- a/src/event-log/message-event.h +++ b/src/event-log/chat-message-event.h @@ -1,5 +1,5 @@ /* - * message-event.h + * chat-message-event.h * Copyright (C) 2017 Belledonne Communications SARL * * This program is free software: you can redistribute it and/or modify @@ -16,8 +16,8 @@ * along with this program. If not, see . */ -#ifndef _MESSAGE_EVENT_H_ -#define _MESSAGE_EVENT_H_ +#ifndef _CHAT_MESSAGE_EVENT_H_ +#define _CHAT_MESSAGE_EVENT_H_ #include @@ -27,22 +27,22 @@ LINPHONE_BEGIN_NAMESPACE -class Message; -class MessageEventPrivate; +class ChatMessage; +class ChatMessageEventPrivate; -class LINPHONE_PUBLIC MessageEvent : public EventLog { +class LINPHONE_PUBLIC ChatMessageEvent : public EventLog { public: - MessageEvent (const std::shared_ptr &message); - MessageEvent (const MessageEvent &src); + ChatMessageEvent (const std::shared_ptr &chatMessage); + ChatMessageEvent (const ChatMessageEvent &src); - MessageEvent &operator= (const MessageEvent &src); + ChatMessageEvent &operator= (const ChatMessageEvent &src); - std::shared_ptr getMessage () const; + std::shared_ptr getChatMessage () const; private: - L_DECLARE_PRIVATE(MessageEvent); + L_DECLARE_PRIVATE(ChatMessageEvent); }; LINPHONE_END_NAMESPACE -#endif // ifndef _MESSAGE_EVENT_H_ +#endif // ifndef _CHAT_MESSAGE_EVENT_H_ diff --git a/src/event-log/conference-event-p.h b/src/event-log/conference-event-p.h index 1a44b76b8..bad6d92cd 100644 --- a/src/event-log/conference-event-p.h +++ b/src/event-log/conference-event-p.h @@ -19,6 +19,7 @@ #ifndef _CONFERENCE_EVENT_P_H_ #define _CONFERENCE_EVENT_P_H_ +#include "address/address.h" #include "conference-event.h" #include "event-log-p.h" @@ -29,7 +30,7 @@ LINPHONE_BEGIN_NAMESPACE class ConferenceEventPrivate : public EventLogPrivate { private: - std::shared_ptr address; + Address address; L_DECLARE_PUBLIC(ConferenceEvent); }; diff --git a/src/event-log/conference-event.cpp b/src/event-log/conference-event.cpp index 43c040b25..57657d527 100644 --- a/src/event-log/conference-event.cpp +++ b/src/event-log/conference-event.cpp @@ -27,34 +27,32 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ConferenceEvent::ConferenceEvent (Type type, const shared_ptr &address) : +ConferenceEvent::ConferenceEvent (Type type, const Address &address) : EventLog(*new ConferenceEventPrivate, type) { L_D(ConferenceEvent); L_ASSERT(type == Type::ConferenceCreated || type == Type::ConferenceDestroyed); - L_ASSERT(address); - d->address = make_shared
(*address); + d->address = address; } ConferenceEvent::ConferenceEvent (const ConferenceEvent &src) : ConferenceEvent(src.getType(), src.getAddress()) {} -ConferenceEvent::ConferenceEvent (ConferenceEventPrivate &p, Type type, const shared_ptr &address) : +ConferenceEvent::ConferenceEvent (ConferenceEventPrivate &p, Type type, const Address &address) : EventLog(p, type) { L_D(ConferenceEvent); - L_ASSERT(address); - d->address = make_shared
(*address); + d->address = address; } ConferenceEvent &ConferenceEvent::operator= (const ConferenceEvent &src) { L_D(ConferenceEvent); if (this != &src) { EventLog::operator=(src); - d->address = make_shared
(*src.getPrivate()->address); + d->address = src.getPrivate()->address; } return *this; } -shared_ptr ConferenceEvent::getAddress () const { +const Address &ConferenceEvent::getAddress () const { L_D(const ConferenceEvent); return d->address; } diff --git a/src/event-log/conference-event.h b/src/event-log/conference-event.h index 966af2b2d..cd1584cb7 100644 --- a/src/event-log/conference-event.h +++ b/src/event-log/conference-event.h @@ -19,8 +19,6 @@ #ifndef _CONFERENCE_EVENT_H_ #define _CONFERENCE_EVENT_H_ -#include - #include "event-log.h" // ============================================================================= @@ -32,16 +30,16 @@ class ConferenceEventPrivate; class LINPHONE_PUBLIC ConferenceEvent : public EventLog { public: - ConferenceEvent (Type type, const std::shared_ptr &address); + ConferenceEvent (Type type, const Address &address); ConferenceEvent (const ConferenceEvent &src); virtual ~ConferenceEvent () = default; ConferenceEvent &operator= (const ConferenceEvent &src); - std::shared_ptr getAddress () const; + const Address &getAddress () const; protected: - ConferenceEvent (ConferenceEventPrivate &p, Type type, const std::shared_ptr &address); + ConferenceEvent (ConferenceEventPrivate &p, Type type, const Address &address); private: L_DECLARE_PRIVATE(ConferenceEvent); diff --git a/src/event-log/conference-participant-event.cpp b/src/event-log/conference-participant-event.cpp index 7db503cad..145d03956 100644 --- a/src/event-log/conference-participant-event.cpp +++ b/src/event-log/conference-participant-event.cpp @@ -29,15 +29,15 @@ LINPHONE_BEGIN_NAMESPACE class ConferenceParticipantEventPrivate : public ConferenceEventPrivate { public: - shared_ptr participantAddress; + Address participantAddress; }; // ----------------------------------------------------------------------------- ConferenceParticipantEvent::ConferenceParticipantEvent ( Type type, - const shared_ptr &conferenceAddress, - const shared_ptr &participantAddress + const Address &conferenceAddress, + const Address &participantAddress ) : ConferenceEvent(*new ConferenceParticipantEventPrivate, type, conferenceAddress) { L_D(ConferenceParticipantEvent); L_ASSERT( @@ -46,8 +46,7 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( type == Type::ConferenceParticipantSetAdmin || type == Type::ConferenceParticipantUnsetAdmin ); - L_ASSERT(participantAddress); - d->participantAddress = make_shared
(*participantAddress); + d->participantAddress = participantAddress; } ConferenceParticipantEvent::ConferenceParticipantEvent (const ConferenceParticipantEvent &src) : @@ -57,13 +56,13 @@ ConferenceParticipantEvent &ConferenceParticipantEvent::operator= (const Confere L_D(ConferenceParticipantEvent); if (this != &src) { ConferenceEvent::operator=(src); - d->participantAddress = make_shared
(*src.getPrivate()->participantAddress); + d->participantAddress = src.getPrivate()->participantAddress; } return *this; } -shared_ptr ConferenceParticipantEvent::getParticipantAddress () const { +const Address &ConferenceParticipantEvent::getParticipantAddress () const { L_D(const ConferenceParticipantEvent); return d->participantAddress; } diff --git a/src/event-log/conference-participant-event.h b/src/event-log/conference-participant-event.h index fbb6514d7..03d0d4b48 100644 --- a/src/event-log/conference-participant-event.h +++ b/src/event-log/conference-participant-event.h @@ -31,14 +31,14 @@ class LINPHONE_PUBLIC ConferenceParticipantEvent : public ConferenceEvent { public: ConferenceParticipantEvent ( Type type, - const std::shared_ptr &conferenceAddress, - const std::shared_ptr &participantAddress + const Address &conferenceAddress, + const Address &participantAddress ); ConferenceParticipantEvent (const ConferenceParticipantEvent &src); ConferenceParticipantEvent &operator= (const ConferenceParticipantEvent &src); - std::shared_ptr getParticipantAddress () const; + const Address &getParticipantAddress () const; private: L_DECLARE_PRIVATE(ConferenceParticipantEvent); From 8bd249e81a6350444fff745febabd6013baea149 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 20 Sep 2017 17:33:56 +0200 Subject: [PATCH 0104/2215] Xsd generated now uses our own coding style. --- .../local-conference-event-handler.cpp | 59 +- .../remote-conference-event-handler.cpp | 15 +- src/xml/conference-info.cpp | 17850 ++++++++-------- src/xml/conference-info.h | 6864 +++--- src/xml/epilogue.txt | 3 + src/xml/generate.py | 53 +- src/xml/prologue.txt | 4 + src/xml/resource-lists.cpp | 4510 ++-- src/xml/resource-lists.h | 1854 +- src/xml/xml.cpp | 150 +- src/xml/xml.h | 376 +- 11 files changed, 15928 insertions(+), 15810 deletions(-) create mode 100644 src/xml/epilogue.txt create mode 100644 src/xml/prologue.txt diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index d06cf4d9a..2dbd1e306 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -20,28 +20,19 @@ #include "conference/participant.h" #include "local-conference-event-handler.h" #include "object/object-p.h" - -#if __clang__ || __GNUC__ >= 4 - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wsuggest-override" -#endif - #include "xml/conference-info.h" -#if __clang__ || __GNUC__ >= 4 - #pragma GCC diagnostic pop -#endif - /* Needs to be included after xml/conference-info.h because of _() macro definition that breaks everything */ #include "private.h" // ============================================================================= using namespace std; -using namespace conference_info; LINPHONE_BEGIN_NAMESPACE +using namespace Xsd::ConferenceInfo; + class LocalConferenceEventHandlerPrivate : public ObjectPrivate { public: void notifyFullState(string notify, LinphoneEvent *lev); @@ -94,15 +85,15 @@ LocalConferenceEventHandler::~LocalConferenceEventHandler() { string LocalConferenceEventHandler::subscribeReceived(LinphoneEvent *lev) { L_D(LocalConferenceEventHandler); string entity = d->conf->getMe()->getAddress().asStringUriOnly(); - Conference_type confInfo = Conference_type(entity); - Users_type users; + ConferenceType confInfo = ConferenceType(entity); + UsersType users; confInfo.setUsers(users); - xml_schema::NamespaceInfomap map; + Xsd::XmlSchema::NamespaceInfomap map; map[""].name = "urn:ietf:params:xml:ns:conference-info"; for (const auto &participant : d->conf->getParticipants()) { - User_type user = User_type(); - User_roles_type roles; + UserType user = UserType(); + UserRolesType roles; user.setRoles(roles); user.setEntity(participant->getAddress().asStringUriOnly()); user.getRoles()->getEntry().push_back(participant->isAdmin() ? "admin" : "participant"); @@ -111,7 +102,7 @@ string LocalConferenceEventHandler::subscribeReceived(LinphoneEvent *lev) { } stringstream notify; - serializeConference_info(notify, confInfo, map); + serializeConferenceInfo(notify, confInfo, map); //d->notifyFullState(notify.str(), lev); return notify.str(); } @@ -119,21 +110,21 @@ string LocalConferenceEventHandler::subscribeReceived(LinphoneEvent *lev) { string LocalConferenceEventHandler::notifyParticipantAdded(const Address &addr) { L_D(LocalConferenceEventHandler); string entity = d->conf->getMe()->getAddress().asStringUriOnly(); - Conference_type confInfo = Conference_type(entity); - Users_type users; + ConferenceType confInfo = ConferenceType(entity); + UsersType users; confInfo.setUsers(users); - User_type user = User_type(); - User_roles_type roles; + UserType user = UserType(); + UserRolesType roles; user.setRoles(roles); user.setEntity(addr.asStringUriOnly()); user.getRoles()->getEntry().push_back("participant"); user.setState("full"); confInfo.getUsers()->getUser().push_back(user); - xml_schema::NamespaceInfomap map; + Xsd::XmlSchema::NamespaceInfomap map; stringstream notify; - serializeConference_info(notify, confInfo, map); + serializeConferenceInfo(notify, confInfo, map); //d->notifyAllExcept(notify.str(), addr); return notify.str(); } @@ -141,18 +132,18 @@ string LocalConferenceEventHandler::notifyParticipantAdded(const Address &addr) string LocalConferenceEventHandler::notifyParticipantRemoved(const Address &addr) { L_D(LocalConferenceEventHandler); string entity = d->conf->getMe()->getAddress().asStringUriOnly(); - Conference_type confInfo = Conference_type(entity); - Users_type users; + ConferenceType confInfo = ConferenceType(entity); + UsersType users; confInfo.setUsers(users); - User_type user = User_type(); + UserType user = UserType(); user.setEntity(addr.asStringUriOnly()); user.setState("deleted"); confInfo.getUsers()->getUser().push_back(user); - xml_schema::NamespaceInfomap map; + Xsd::XmlSchema::NamespaceInfomap map; stringstream notify; - serializeConference_info(notify, confInfo, map); + serializeConferenceInfo(notify, confInfo, map); //d->notifyAllExcept(notify.str(), addr); return notify.str(); } @@ -160,21 +151,21 @@ string LocalConferenceEventHandler::notifyParticipantRemoved(const Address &addr string LocalConferenceEventHandler::notifyParticipantSetAdmin(const Address &addr, bool isAdmin) { L_D(LocalConferenceEventHandler); string entity = d->conf->getMe()->getAddress().asStringUriOnly(); - Conference_type confInfo = Conference_type(entity); - Users_type users; + ConferenceType confInfo = ConferenceType(entity); + UsersType users; confInfo.setUsers(users); - User_type user = User_type(); - User_roles_type roles; + UserType user = UserType(); + UserRolesType roles; user.setRoles(roles); user.setEntity(addr.asStringUriOnly()); user.getRoles()->getEntry().push_back(isAdmin ? "admin" : "participant"); user.setState("partial"); confInfo.getUsers()->getUser().push_back(user); - xml_schema::NamespaceInfomap map; + Xsd::XmlSchema::NamespaceInfomap map; stringstream notify; - serializeConference_info(notify, confInfo, map); + serializeConferenceInfo(notify, confInfo, map); //d->notifyAllExcept(notify.str(), addr); return notify.str(); } diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 8e6099552..03668dba0 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -18,28 +18,19 @@ #include "remote-conference-event-handler.h" #include "object/object-p.h" - -#if __clang__ || __GNUC__ >= 4 - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wsuggest-override" -#endif - #include "xml/conference-info.h" -#if __clang__ || __GNUC__ >= 4 - #pragma GCC diagnostic pop -#endif - /* Needs to be included after xml/conference-info.h because of _() macro definition that breaks everything */ #include "private.h" // ============================================================================= using namespace std; -using namespace conference_info; LINPHONE_BEGIN_NAMESPACE +using namespace Xsd::ConferenceInfo; + class RemoteConferenceEventHandlerPrivate : public ObjectPrivate { public: LinphoneCore *core = nullptr; @@ -89,7 +80,7 @@ void RemoteConferenceEventHandler::unsubscribe() { void RemoteConferenceEventHandler::notifyReceived(string xmlBody) { L_D(RemoteConferenceEventHandler); istringstream data(xmlBody); - unique_ptr confInfo = parseConference_info(data, xml_schema::Flags::dont_validate); + unique_ptr confInfo = parseConferenceInfo(data, Xsd::XmlSchema::Flags::dont_validate); if (confInfo->getEntity() == d->confAddr.asString()) { for (const auto &user : confInfo->getUsers()->getUser()) { LinphoneAddress *cAddr = linphone_core_interpret_url(d->core, user.getEntity()->c_str()); diff --git a/src/xml/conference-info.cpp b/src/xml/conference-info.cpp index 7cd27bf03..110ec162a 100644 --- a/src/xml/conference-info.cpp +++ b/src/xml/conference-info.cpp @@ -33,12 +33,10 @@ // Begin prologue. // - #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsuggest-override" #endif - // // End prologue. @@ -46,3154 +44,3160 @@ #include "conference-info.h" -namespace conference_info +namespace LinphonePrivate { - // Conference_type - // - - const Conference_type::Conference_descriptionOptional& Conference_type:: - getConference_description () const - { - return this->conference_description_; - } - - Conference_type::Conference_descriptionOptional& Conference_type:: - getConference_description () - { - return this->conference_description_; - } - - void Conference_type:: - setConference_description (const Conference_descriptionType& x) - { - this->conference_description_.set (x); - } - - void Conference_type:: - setConference_description (const Conference_descriptionOptional& x) - { - this->conference_description_ = x; - } - - void Conference_type:: - setConference_description (::std::unique_ptr< Conference_descriptionType > x) - { - this->conference_description_.set (std::move (x)); - } - - const Conference_type::Host_infoOptional& Conference_type:: - getHost_info () const - { - return this->host_info_; - } - - Conference_type::Host_infoOptional& Conference_type:: - getHost_info () - { - return this->host_info_; - } - - void Conference_type:: - setHost_info (const Host_infoType& x) - { - this->host_info_.set (x); - } - - void Conference_type:: - setHost_info (const Host_infoOptional& x) - { - this->host_info_ = x; - } - - void Conference_type:: - setHost_info (::std::unique_ptr< Host_infoType > x) - { - this->host_info_.set (std::move (x)); - } - - const Conference_type::Conference_stateOptional& Conference_type:: - getConference_state () const - { - return this->conference_state_; - } - - Conference_type::Conference_stateOptional& Conference_type:: - getConference_state () - { - return this->conference_state_; - } - - void Conference_type:: - setConference_state (const Conference_stateType& x) - { - this->conference_state_.set (x); - } - - void Conference_type:: - setConference_state (const Conference_stateOptional& x) - { - this->conference_state_ = x; - } - - void Conference_type:: - setConference_state (::std::unique_ptr< Conference_stateType > x) - { - this->conference_state_.set (std::move (x)); - } - - const Conference_type::UsersOptional& Conference_type:: - getUsers () const - { - return this->users_; - } - - Conference_type::UsersOptional& Conference_type:: - getUsers () - { - return this->users_; - } - - void Conference_type:: - setUsers (const UsersType& x) - { - this->users_.set (x); - } - - void Conference_type:: - setUsers (const UsersOptional& x) - { - this->users_ = x; - } - - void Conference_type:: - setUsers (::std::unique_ptr< UsersType > x) - { - this->users_.set (std::move (x)); - } - - const Conference_type::Sidebars_by_refOptional& Conference_type:: - getSidebars_by_ref () const - { - return this->sidebars_by_ref_; - } - - Conference_type::Sidebars_by_refOptional& Conference_type:: - getSidebars_by_ref () - { - return this->sidebars_by_ref_; - } - - void Conference_type:: - setSidebars_by_ref (const Sidebars_by_refType& x) - { - this->sidebars_by_ref_.set (x); - } - - void Conference_type:: - setSidebars_by_ref (const Sidebars_by_refOptional& x) - { - this->sidebars_by_ref_ = x; - } - - void Conference_type:: - setSidebars_by_ref (::std::unique_ptr< Sidebars_by_refType > x) - { - this->sidebars_by_ref_.set (std::move (x)); - } - - const Conference_type::Sidebars_by_valOptional& Conference_type:: - getSidebars_by_val () const - { - return this->sidebars_by_val_; - } - - Conference_type::Sidebars_by_valOptional& Conference_type:: - getSidebars_by_val () - { - return this->sidebars_by_val_; - } - - void Conference_type:: - setSidebars_by_val (const Sidebars_by_valType& x) - { - this->sidebars_by_val_.set (x); - } - - void Conference_type:: - setSidebars_by_val (const Sidebars_by_valOptional& x) - { - this->sidebars_by_val_ = x; - } - - void Conference_type:: - setSidebars_by_val (::std::unique_ptr< Sidebars_by_valType > x) - { - this->sidebars_by_val_.set (std::move (x)); - } - - const Conference_type::AnySequence& Conference_type:: - getAny () const - { - return this->any_; - } - - Conference_type::AnySequence& Conference_type:: - getAny () - { - return this->any_; - } - - void Conference_type:: - setAny (const AnySequence& s) - { - this->any_ = s; - } - - const Conference_type::EntityType& Conference_type:: - getEntity () const - { - return this->entity_.get (); - } - - Conference_type::EntityType& Conference_type:: - getEntity () - { - return this->entity_.get (); - } - - void Conference_type:: - setEntity (const EntityType& x) - { - this->entity_.set (x); - } - - void Conference_type:: - setEntity (::std::unique_ptr< EntityType > x) - { - this->entity_.set (std::move (x)); - } - - ::std::unique_ptr< Conference_type::EntityType > Conference_type:: - detachEntity () - { - return this->entity_.detach (); - } - - const Conference_type::StateType& Conference_type:: - getState () const - { - return this->state_.get (); - } - - Conference_type::StateType& Conference_type:: - getState () - { - return this->state_.get (); - } - - void Conference_type:: - setState (const StateType& x) - { - this->state_.set (x); - } - - void Conference_type:: - setState (::std::unique_ptr< StateType > x) - { - this->state_.set (std::move (x)); - } - - ::std::unique_ptr< Conference_type::StateType > Conference_type:: - detachState () - { - return this->state_.detach (); - } - - const Conference_type::StateType& Conference_type:: - getStateDefaultValue () - { - return state_default_value_; - } - - const Conference_type::VersionOptional& Conference_type:: - getVersion () const - { - return this->version_; - } - - Conference_type::VersionOptional& Conference_type:: - getVersion () - { - return this->version_; - } - - void Conference_type:: - setVersion (const VersionType& x) - { - this->version_.set (x); - } - - void Conference_type:: - setVersion (const VersionOptional& x) - { - this->version_ = x; - } - - const Conference_type::AnyAttributeSet& Conference_type:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - Conference_type::AnyAttributeSet& Conference_type:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void Conference_type:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& Conference_type:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& Conference_type:: - getDomDocument () - { - return *this->dom_document_; - } - - - // State_type - // - - State_type:: - State_type (Value v) - : ::xml_schema::String (_xsd_State_type_literals_[v]) - { - } - - State_type:: - State_type (const char* v) - : ::xml_schema::String (v) - { - } - - State_type:: - State_type (const ::std::string& v) - : ::xml_schema::String (v) - { - } - - State_type:: - State_type (const ::xml_schema::String& v) - : ::xml_schema::String (v) - { - } - - State_type:: - State_type (const State_type& v, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (v, f, c) - { - } - - State_type& State_type:: - operator= (Value v) - { - static_cast< ::xml_schema::String& > (*this) = - ::xml_schema::String (_xsd_State_type_literals_[v]); - - return *this; - } - - - // Conference_description_type - // - - const Conference_description_type::Display_textOptional& Conference_description_type:: - getDisplay_text () const - { - return this->display_text_; - } - - Conference_description_type::Display_textOptional& Conference_description_type:: - getDisplay_text () - { - return this->display_text_; - } - - void Conference_description_type:: - setDisplay_text (const Display_textType& x) - { - this->display_text_.set (x); - } - - void Conference_description_type:: - setDisplay_text (const Display_textOptional& x) - { - this->display_text_ = x; - } - - void Conference_description_type:: - setDisplay_text (::std::unique_ptr< Display_textType > x) - { - this->display_text_.set (std::move (x)); - } - - const Conference_description_type::SubjectOptional& Conference_description_type:: - getSubject () const - { - return this->subject_; - } - - Conference_description_type::SubjectOptional& Conference_description_type:: - getSubject () - { - return this->subject_; - } - - void Conference_description_type:: - setSubject (const SubjectType& x) - { - this->subject_.set (x); - } - - void Conference_description_type:: - setSubject (const SubjectOptional& x) - { - this->subject_ = x; - } - - void Conference_description_type:: - setSubject (::std::unique_ptr< SubjectType > x) - { - this->subject_.set (std::move (x)); - } - - const Conference_description_type::Free_textOptional& Conference_description_type:: - getFree_text () const - { - return this->free_text_; - } - - Conference_description_type::Free_textOptional& Conference_description_type:: - getFree_text () - { - return this->free_text_; - } - - void Conference_description_type:: - setFree_text (const Free_textType& x) - { - this->free_text_.set (x); - } - - void Conference_description_type:: - setFree_text (const Free_textOptional& x) - { - this->free_text_ = x; - } - - void Conference_description_type:: - setFree_text (::std::unique_ptr< Free_textType > x) - { - this->free_text_.set (std::move (x)); - } - - const Conference_description_type::KeywordsOptional& Conference_description_type:: - getKeywords () const - { - return this->keywords_; - } - - Conference_description_type::KeywordsOptional& Conference_description_type:: - getKeywords () - { - return this->keywords_; - } - - void Conference_description_type:: - setKeywords (const KeywordsType& x) - { - this->keywords_.set (x); - } - - void Conference_description_type:: - setKeywords (const KeywordsOptional& x) - { - this->keywords_ = x; - } - - void Conference_description_type:: - setKeywords (::std::unique_ptr< KeywordsType > x) - { - this->keywords_.set (std::move (x)); - } - - const Conference_description_type::Conf_urisOptional& Conference_description_type:: - getConf_uris () const - { - return this->conf_uris_; - } - - Conference_description_type::Conf_urisOptional& Conference_description_type:: - getConf_uris () - { - return this->conf_uris_; - } - - void Conference_description_type:: - setConf_uris (const Conf_urisType& x) - { - this->conf_uris_.set (x); - } - - void Conference_description_type:: - setConf_uris (const Conf_urisOptional& x) - { - this->conf_uris_ = x; - } - - void Conference_description_type:: - setConf_uris (::std::unique_ptr< Conf_urisType > x) - { - this->conf_uris_.set (std::move (x)); - } - - const Conference_description_type::Service_urisOptional& Conference_description_type:: - getService_uris () const - { - return this->service_uris_; - } - - Conference_description_type::Service_urisOptional& Conference_description_type:: - getService_uris () - { - return this->service_uris_; - } - - void Conference_description_type:: - setService_uris (const Service_urisType& x) - { - this->service_uris_.set (x); - } - - void Conference_description_type:: - setService_uris (const Service_urisOptional& x) - { - this->service_uris_ = x; - } - - void Conference_description_type:: - setService_uris (::std::unique_ptr< Service_urisType > x) - { - this->service_uris_.set (std::move (x)); - } - - const Conference_description_type::Maximum_user_countOptional& Conference_description_type:: - getMaximum_user_count () const - { - return this->maximum_user_count_; - } - - Conference_description_type::Maximum_user_countOptional& Conference_description_type:: - getMaximum_user_count () - { - return this->maximum_user_count_; - } - - void Conference_description_type:: - setMaximum_user_count (const Maximum_user_countType& x) - { - this->maximum_user_count_.set (x); - } - - void Conference_description_type:: - setMaximum_user_count (const Maximum_user_countOptional& x) - { - this->maximum_user_count_ = x; - } - - const Conference_description_type::Available_mediaOptional& Conference_description_type:: - getAvailable_media () const - { - return this->available_media_; - } - - Conference_description_type::Available_mediaOptional& Conference_description_type:: - getAvailable_media () - { - return this->available_media_; - } - - void Conference_description_type:: - setAvailable_media (const Available_mediaType& x) - { - this->available_media_.set (x); - } - - void Conference_description_type:: - setAvailable_media (const Available_mediaOptional& x) - { - this->available_media_ = x; - } - - void Conference_description_type:: - setAvailable_media (::std::unique_ptr< Available_mediaType > x) - { - this->available_media_.set (std::move (x)); - } - - const Conference_description_type::AnySequence& Conference_description_type:: - getAny () const - { - return this->any_; - } - - Conference_description_type::AnySequence& Conference_description_type:: - getAny () - { - return this->any_; - } - - void Conference_description_type:: - setAny (const AnySequence& s) - { - this->any_ = s; - } - - const Conference_description_type::AnyAttributeSet& Conference_description_type:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - Conference_description_type::AnyAttributeSet& Conference_description_type:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void Conference_description_type:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& Conference_description_type:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& Conference_description_type:: - getDomDocument () - { - return *this->dom_document_; - } - - - // Host_type - // - - const Host_type::Display_textOptional& Host_type:: - getDisplay_text () const - { - return this->display_text_; - } - - Host_type::Display_textOptional& Host_type:: - getDisplay_text () - { - return this->display_text_; - } - - void Host_type:: - setDisplay_text (const Display_textType& x) - { - this->display_text_.set (x); - } - - void Host_type:: - setDisplay_text (const Display_textOptional& x) - { - this->display_text_ = x; - } - - void Host_type:: - setDisplay_text (::std::unique_ptr< Display_textType > x) - { - this->display_text_.set (std::move (x)); - } - - const Host_type::Web_pageOptional& Host_type:: - getWeb_page () const - { - return this->web_page_; - } - - Host_type::Web_pageOptional& Host_type:: - getWeb_page () - { - return this->web_page_; - } - - void Host_type:: - setWeb_page (const Web_pageType& x) - { - this->web_page_.set (x); - } - - void Host_type:: - setWeb_page (const Web_pageOptional& x) - { - this->web_page_ = x; - } - - void Host_type:: - setWeb_page (::std::unique_ptr< Web_pageType > x) - { - this->web_page_.set (std::move (x)); - } - - const Host_type::UrisOptional& Host_type:: - getUris () const - { - return this->uris_; - } - - Host_type::UrisOptional& Host_type:: - getUris () - { - return this->uris_; - } - - void Host_type:: - setUris (const UrisType& x) - { - this->uris_.set (x); - } - - void Host_type:: - setUris (const UrisOptional& x) - { - this->uris_ = x; - } - - void Host_type:: - setUris (::std::unique_ptr< UrisType > x) - { - this->uris_.set (std::move (x)); - } - - const Host_type::AnySequence& Host_type:: - getAny () const - { - return this->any_; - } - - Host_type::AnySequence& Host_type:: - getAny () - { - return this->any_; - } - - void Host_type:: - setAny (const AnySequence& s) - { - this->any_ = s; - } - - const Host_type::AnyAttributeSet& Host_type:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - Host_type::AnyAttributeSet& Host_type:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void Host_type:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& Host_type:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& Host_type:: - getDomDocument () - { - return *this->dom_document_; - } - - - // Conference_state_type - // - - const Conference_state_type::User_countOptional& Conference_state_type:: - getUser_count () const - { - return this->user_count_; - } - - Conference_state_type::User_countOptional& Conference_state_type:: - getUser_count () - { - return this->user_count_; - } - - void Conference_state_type:: - setUser_count (const User_countType& x) - { - this->user_count_.set (x); - } - - void Conference_state_type:: - setUser_count (const User_countOptional& x) - { - this->user_count_ = x; - } - - const Conference_state_type::ActiveOptional& Conference_state_type:: - getActive () const - { - return this->active_; - } - - Conference_state_type::ActiveOptional& Conference_state_type:: - getActive () - { - return this->active_; - } - - void Conference_state_type:: - setActive (const ActiveType& x) - { - this->active_.set (x); - } - - void Conference_state_type:: - setActive (const ActiveOptional& x) - { - this->active_ = x; - } - - const Conference_state_type::LockedOptional& Conference_state_type:: - getLocked () const - { - return this->locked_; - } - - Conference_state_type::LockedOptional& Conference_state_type:: - getLocked () - { - return this->locked_; - } - - void Conference_state_type:: - setLocked (const LockedType& x) - { - this->locked_.set (x); - } - - void Conference_state_type:: - setLocked (const LockedOptional& x) - { - this->locked_ = x; - } - - const Conference_state_type::AnySequence& Conference_state_type:: - getAny () const - { - return this->any_; - } - - Conference_state_type::AnySequence& Conference_state_type:: - getAny () - { - return this->any_; - } - - void Conference_state_type:: - setAny (const AnySequence& s) - { - this->any_ = s; - } - - const Conference_state_type::AnyAttributeSet& Conference_state_type:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - Conference_state_type::AnyAttributeSet& Conference_state_type:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void Conference_state_type:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& Conference_state_type:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& Conference_state_type:: - getDomDocument () - { - return *this->dom_document_; - } - - - // Conference_media_type - // - - const Conference_media_type::EntrySequence& Conference_media_type:: - getEntry () const - { - return this->entry_; - } - - Conference_media_type::EntrySequence& Conference_media_type:: - getEntry () - { - return this->entry_; - } - - void Conference_media_type:: - setEntry (const EntrySequence& s) - { - this->entry_ = s; - } - - const Conference_media_type::AnyAttributeSet& Conference_media_type:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - Conference_media_type::AnyAttributeSet& Conference_media_type:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void Conference_media_type:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& Conference_media_type:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& Conference_media_type:: - getDomDocument () - { - return *this->dom_document_; - } - - - // Conference_medium_type - // - - const Conference_medium_type::Display_textOptional& Conference_medium_type:: - getDisplay_text () const - { - return this->display_text_; - } - - Conference_medium_type::Display_textOptional& Conference_medium_type:: - getDisplay_text () - { - return this->display_text_; - } - - void Conference_medium_type:: - setDisplay_text (const Display_textType& x) - { - this->display_text_.set (x); - } - - void Conference_medium_type:: - setDisplay_text (const Display_textOptional& x) - { - this->display_text_ = x; - } - - void Conference_medium_type:: - setDisplay_text (::std::unique_ptr< Display_textType > x) - { - this->display_text_.set (std::move (x)); - } - - const Conference_medium_type::TypeType& Conference_medium_type:: - getType () const - { - return this->type_.get (); - } - - Conference_medium_type::TypeType& Conference_medium_type:: - getType () - { - return this->type_.get (); - } - - void Conference_medium_type:: - setType (const TypeType& x) - { - this->type_.set (x); - } - - void Conference_medium_type:: - setType (::std::unique_ptr< TypeType > x) - { - this->type_.set (std::move (x)); - } - - ::std::unique_ptr< Conference_medium_type::TypeType > Conference_medium_type:: - detachType () - { - return this->type_.detach (); - } - - const Conference_medium_type::StatusOptional& Conference_medium_type:: - getStatus () const - { - return this->status_; - } - - Conference_medium_type::StatusOptional& Conference_medium_type:: - getStatus () - { - return this->status_; - } - - void Conference_medium_type:: - setStatus (const StatusType& x) - { - this->status_.set (x); - } - - void Conference_medium_type:: - setStatus (const StatusOptional& x) - { - this->status_ = x; - } - - void Conference_medium_type:: - setStatus (::std::unique_ptr< StatusType > x) - { - this->status_.set (std::move (x)); - } - - const Conference_medium_type::AnySequence& Conference_medium_type:: - getAny () const - { - return this->any_; - } - - Conference_medium_type::AnySequence& Conference_medium_type:: - getAny () - { - return this->any_; - } - - void Conference_medium_type:: - setAny (const AnySequence& s) - { - this->any_ = s; - } - - const Conference_medium_type::LabelType& Conference_medium_type:: - getLabel () const - { - return this->label_.get (); - } - - Conference_medium_type::LabelType& Conference_medium_type:: - getLabel () - { - return this->label_.get (); - } - - void Conference_medium_type:: - setLabel (const LabelType& x) - { - this->label_.set (x); - } - - void Conference_medium_type:: - setLabel (::std::unique_ptr< LabelType > x) - { - this->label_.set (std::move (x)); - } - - ::std::unique_ptr< Conference_medium_type::LabelType > Conference_medium_type:: - detachLabel () - { - return this->label_.detach (); - } - - const Conference_medium_type::AnyAttributeSet& Conference_medium_type:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - Conference_medium_type::AnyAttributeSet& Conference_medium_type:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void Conference_medium_type:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& Conference_medium_type:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& Conference_medium_type:: - getDomDocument () - { - return *this->dom_document_; - } - - - // Uris_type - // - - const Uris_type::EntrySequence& Uris_type:: - getEntry () const - { - return this->entry_; - } - - Uris_type::EntrySequence& Uris_type:: - getEntry () - { - return this->entry_; - } - - void Uris_type:: - setEntry (const EntrySequence& s) - { - this->entry_ = s; - } - - const Uris_type::StateType& Uris_type:: - getState () const - { - return this->state_.get (); - } - - Uris_type::StateType& Uris_type:: - getState () - { - return this->state_.get (); - } - - void Uris_type:: - setState (const StateType& x) - { - this->state_.set (x); - } - - void Uris_type:: - setState (::std::unique_ptr< StateType > x) - { - this->state_.set (std::move (x)); - } - - ::std::unique_ptr< Uris_type::StateType > Uris_type:: - detachState () - { - return this->state_.detach (); - } - - const Uris_type::StateType& Uris_type:: - getStateDefaultValue () - { - return state_default_value_; - } - - const Uris_type::AnyAttributeSet& Uris_type:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - Uris_type::AnyAttributeSet& Uris_type:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void Uris_type:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& Uris_type:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& Uris_type:: - getDomDocument () - { - return *this->dom_document_; - } - - - // Uri_type - // - - const Uri_type::UriType& Uri_type:: - getUri () const - { - return this->uri_.get (); - } - - Uri_type::UriType& Uri_type:: - getUri () - { - return this->uri_.get (); - } - - void Uri_type:: - setUri (const UriType& x) - { - this->uri_.set (x); - } - - void Uri_type:: - setUri (::std::unique_ptr< UriType > x) - { - this->uri_.set (std::move (x)); - } - - ::std::unique_ptr< Uri_type::UriType > Uri_type:: - detachUri () - { - return this->uri_.detach (); - } - - const Uri_type::Display_textOptional& Uri_type:: - getDisplay_text () const - { - return this->display_text_; - } - - Uri_type::Display_textOptional& Uri_type:: - getDisplay_text () - { - return this->display_text_; - } - - void Uri_type:: - setDisplay_text (const Display_textType& x) - { - this->display_text_.set (x); - } - - void Uri_type:: - setDisplay_text (const Display_textOptional& x) - { - this->display_text_ = x; - } - - void Uri_type:: - setDisplay_text (::std::unique_ptr< Display_textType > x) - { - this->display_text_.set (std::move (x)); - } - - const Uri_type::PurposeOptional& Uri_type:: - getPurpose () const - { - return this->purpose_; - } - - Uri_type::PurposeOptional& Uri_type:: - getPurpose () - { - return this->purpose_; - } - - void Uri_type:: - setPurpose (const PurposeType& x) - { - this->purpose_.set (x); - } - - void Uri_type:: - setPurpose (const PurposeOptional& x) - { - this->purpose_ = x; - } - - void Uri_type:: - setPurpose (::std::unique_ptr< PurposeType > x) - { - this->purpose_.set (std::move (x)); - } - - const Uri_type::ModifiedOptional& Uri_type:: - getModified () const - { - return this->modified_; - } - - Uri_type::ModifiedOptional& Uri_type:: - getModified () - { - return this->modified_; - } - - void Uri_type:: - setModified (const ModifiedType& x) - { - this->modified_.set (x); - } - - void Uri_type:: - setModified (const ModifiedOptional& x) - { - this->modified_ = x; - } - - void Uri_type:: - setModified (::std::unique_ptr< ModifiedType > x) - { - this->modified_.set (std::move (x)); - } - - const Uri_type::AnySequence& Uri_type:: - getAny () const - { - return this->any_; - } - - Uri_type::AnySequence& Uri_type:: - getAny () - { - return this->any_; - } - - void Uri_type:: - setAny (const AnySequence& s) - { - this->any_ = s; - } - - const Uri_type::AnyAttributeSet& Uri_type:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - Uri_type::AnyAttributeSet& Uri_type:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void Uri_type:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& Uri_type:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& Uri_type:: - getDomDocument () - { - return *this->dom_document_; - } - - - // Keywords_type - // - - Keywords_type:: - Keywords_type () - : ::xsd::cxx::tree::list< ::xml_schema::String, char > (this) - { - } - - Keywords_type:: - Keywords_type (size_type n, const ::xml_schema::String& x) - : ::xsd::cxx::tree::list< ::xml_schema::String, char > (n, x, this) - { - } - - Keywords_type:: - Keywords_type (const Keywords_type& o, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::SimpleType (o, f, c), - ::xsd::cxx::tree::list< ::xml_schema::String, char > (o, f, this) - { - } - - // Users_type - // - - const Users_type::UserSequence& Users_type:: - getUser () const - { - return this->user_; - } - - Users_type::UserSequence& Users_type:: - getUser () - { - return this->user_; - } - - void Users_type:: - setUser (const UserSequence& s) - { - this->user_ = s; - } - - const Users_type::AnySequence& Users_type:: - getAny () const - { - return this->any_; - } - - Users_type::AnySequence& Users_type:: - getAny () - { - return this->any_; - } - - void Users_type:: - setAny (const AnySequence& s) - { - this->any_ = s; - } - - const Users_type::StateType& Users_type:: - getState () const - { - return this->state_.get (); - } - - Users_type::StateType& Users_type:: - getState () - { - return this->state_.get (); - } - - void Users_type:: - setState (const StateType& x) - { - this->state_.set (x); - } - - void Users_type:: - setState (::std::unique_ptr< StateType > x) - { - this->state_.set (std::move (x)); - } - - ::std::unique_ptr< Users_type::StateType > Users_type:: - detachState () - { - return this->state_.detach (); - } - - const Users_type::StateType& Users_type:: - getStateDefaultValue () - { - return state_default_value_; - } - - const Users_type::AnyAttributeSet& Users_type:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - Users_type::AnyAttributeSet& Users_type:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void Users_type:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& Users_type:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& Users_type:: - getDomDocument () - { - return *this->dom_document_; - } - - - // User_type - // - - const User_type::Display_textOptional& User_type:: - getDisplay_text () const - { - return this->display_text_; - } - - User_type::Display_textOptional& User_type:: - getDisplay_text () - { - return this->display_text_; - } - - void User_type:: - setDisplay_text (const Display_textType& x) - { - this->display_text_.set (x); - } - - void User_type:: - setDisplay_text (const Display_textOptional& x) - { - this->display_text_ = x; - } - - void User_type:: - setDisplay_text (::std::unique_ptr< Display_textType > x) - { - this->display_text_.set (std::move (x)); - } - - const User_type::Associated_aorsOptional& User_type:: - getAssociated_aors () const - { - return this->associated_aors_; - } - - User_type::Associated_aorsOptional& User_type:: - getAssociated_aors () - { - return this->associated_aors_; - } - - void User_type:: - setAssociated_aors (const Associated_aorsType& x) - { - this->associated_aors_.set (x); - } - - void User_type:: - setAssociated_aors (const Associated_aorsOptional& x) - { - this->associated_aors_ = x; - } - - void User_type:: - setAssociated_aors (::std::unique_ptr< Associated_aorsType > x) - { - this->associated_aors_.set (std::move (x)); - } - - const User_type::RolesOptional& User_type:: - getRoles () const - { - return this->roles_; - } - - User_type::RolesOptional& User_type:: - getRoles () - { - return this->roles_; - } - - void User_type:: - setRoles (const RolesType& x) - { - this->roles_.set (x); - } - - void User_type:: - setRoles (const RolesOptional& x) - { - this->roles_ = x; - } - - void User_type:: - setRoles (::std::unique_ptr< RolesType > x) - { - this->roles_.set (std::move (x)); - } - - const User_type::LanguagesOptional& User_type:: - getLanguages () const - { - return this->languages_; - } - - User_type::LanguagesOptional& User_type:: - getLanguages () - { - return this->languages_; - } - - void User_type:: - setLanguages (const LanguagesType& x) - { - this->languages_.set (x); - } - - void User_type:: - setLanguages (const LanguagesOptional& x) - { - this->languages_ = x; - } - - void User_type:: - setLanguages (::std::unique_ptr< LanguagesType > x) - { - this->languages_.set (std::move (x)); - } - - const User_type::Cascaded_focusOptional& User_type:: - getCascaded_focus () const - { - return this->cascaded_focus_; - } - - User_type::Cascaded_focusOptional& User_type:: - getCascaded_focus () - { - return this->cascaded_focus_; - } - - void User_type:: - setCascaded_focus (const Cascaded_focusType& x) - { - this->cascaded_focus_.set (x); - } - - void User_type:: - setCascaded_focus (const Cascaded_focusOptional& x) - { - this->cascaded_focus_ = x; - } - - void User_type:: - setCascaded_focus (::std::unique_ptr< Cascaded_focusType > x) - { - this->cascaded_focus_.set (std::move (x)); - } - - const User_type::EndpointSequence& User_type:: - getEndpoint () const - { - return this->endpoint_; - } - - User_type::EndpointSequence& User_type:: - getEndpoint () - { - return this->endpoint_; - } - - void User_type:: - setEndpoint (const EndpointSequence& s) - { - this->endpoint_ = s; - } - - const User_type::AnySequence& User_type:: - getAny () const - { - return this->any_; - } - - User_type::AnySequence& User_type:: - getAny () - { - return this->any_; - } - - void User_type:: - setAny (const AnySequence& s) - { - this->any_ = s; - } - - const User_type::EntityOptional& User_type:: - getEntity () const - { - return this->entity_; - } - - User_type::EntityOptional& User_type:: - getEntity () - { - return this->entity_; - } - - void User_type:: - setEntity (const EntityType& x) - { - this->entity_.set (x); - } - - void User_type:: - setEntity (const EntityOptional& x) - { - this->entity_ = x; - } - - void User_type:: - setEntity (::std::unique_ptr< EntityType > x) - { - this->entity_.set (std::move (x)); - } - - const User_type::StateType& User_type:: - getState () const - { - return this->state_.get (); - } - - User_type::StateType& User_type:: - getState () - { - return this->state_.get (); - } - - void User_type:: - setState (const StateType& x) - { - this->state_.set (x); - } - - void User_type:: - setState (::std::unique_ptr< StateType > x) - { - this->state_.set (std::move (x)); - } - - ::std::unique_ptr< User_type::StateType > User_type:: - detachState () - { - return this->state_.detach (); - } - - const User_type::StateType& User_type:: - getStateDefaultValue () - { - return state_default_value_; - } - - const User_type::AnyAttributeSet& User_type:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - User_type::AnyAttributeSet& User_type:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void User_type:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& User_type:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& User_type:: - getDomDocument () - { - return *this->dom_document_; - } - - - // User_roles_type - // - - const User_roles_type::EntrySequence& User_roles_type:: - getEntry () const - { - return this->entry_; - } - - User_roles_type::EntrySequence& User_roles_type:: - getEntry () - { - return this->entry_; - } - - void User_roles_type:: - setEntry (const EntrySequence& s) - { - this->entry_ = s; - } - - const User_roles_type::AnyAttributeSet& User_roles_type:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - User_roles_type::AnyAttributeSet& User_roles_type:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void User_roles_type:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& User_roles_type:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& User_roles_type:: - getDomDocument () - { - return *this->dom_document_; - } - - - // User_languages_type - // - - User_languages_type:: - User_languages_type () - : ::xsd::cxx::tree::list< ::xml_schema::Language, char > (this) - { - } - - User_languages_type:: - User_languages_type (size_type n, const ::xml_schema::Language& x) - : ::xsd::cxx::tree::list< ::xml_schema::Language, char > (n, x, this) - { - } - - User_languages_type:: - User_languages_type (const User_languages_type& o, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::SimpleType (o, f, c), - ::xsd::cxx::tree::list< ::xml_schema::Language, char > (o, f, this) - { - } - - // Endpoint_type - // - - const Endpoint_type::Display_textOptional& Endpoint_type:: - getDisplay_text () const - { - return this->display_text_; - } - - Endpoint_type::Display_textOptional& Endpoint_type:: - getDisplay_text () - { - return this->display_text_; - } - - void Endpoint_type:: - setDisplay_text (const Display_textType& x) - { - this->display_text_.set (x); - } - - void Endpoint_type:: - setDisplay_text (const Display_textOptional& x) - { - this->display_text_ = x; - } - - void Endpoint_type:: - setDisplay_text (::std::unique_ptr< Display_textType > x) - { - this->display_text_.set (std::move (x)); - } - - const Endpoint_type::ReferredOptional& Endpoint_type:: - getReferred () const - { - return this->referred_; - } - - Endpoint_type::ReferredOptional& Endpoint_type:: - getReferred () - { - return this->referred_; - } - - void Endpoint_type:: - setReferred (const ReferredType& x) - { - this->referred_.set (x); - } - - void Endpoint_type:: - setReferred (const ReferredOptional& x) - { - this->referred_ = x; - } - - void Endpoint_type:: - setReferred (::std::unique_ptr< ReferredType > x) - { - this->referred_.set (std::move (x)); - } - - const Endpoint_type::StatusOptional& Endpoint_type:: - getStatus () const - { - return this->status_; - } - - Endpoint_type::StatusOptional& Endpoint_type:: - getStatus () - { - return this->status_; - } - - void Endpoint_type:: - setStatus (const StatusType& x) - { - this->status_.set (x); - } - - void Endpoint_type:: - setStatus (const StatusOptional& x) - { - this->status_ = x; - } - - void Endpoint_type:: - setStatus (::std::unique_ptr< StatusType > x) - { - this->status_.set (std::move (x)); - } - - const Endpoint_type::Joining_methodOptional& Endpoint_type:: - getJoining_method () const - { - return this->joining_method_; - } - - Endpoint_type::Joining_methodOptional& Endpoint_type:: - getJoining_method () - { - return this->joining_method_; - } - - void Endpoint_type:: - setJoining_method (const Joining_methodType& x) - { - this->joining_method_.set (x); - } - - void Endpoint_type:: - setJoining_method (const Joining_methodOptional& x) - { - this->joining_method_ = x; - } - - void Endpoint_type:: - setJoining_method (::std::unique_ptr< Joining_methodType > x) - { - this->joining_method_.set (std::move (x)); - } - - const Endpoint_type::Joining_infoOptional& Endpoint_type:: - getJoining_info () const - { - return this->joining_info_; - } - - Endpoint_type::Joining_infoOptional& Endpoint_type:: - getJoining_info () - { - return this->joining_info_; - } - - void Endpoint_type:: - setJoining_info (const Joining_infoType& x) - { - this->joining_info_.set (x); - } - - void Endpoint_type:: - setJoining_info (const Joining_infoOptional& x) - { - this->joining_info_ = x; - } - - void Endpoint_type:: - setJoining_info (::std::unique_ptr< Joining_infoType > x) - { - this->joining_info_.set (std::move (x)); - } - - const Endpoint_type::Disconnection_methodOptional& Endpoint_type:: - getDisconnection_method () const - { - return this->disconnection_method_; - } - - Endpoint_type::Disconnection_methodOptional& Endpoint_type:: - getDisconnection_method () - { - return this->disconnection_method_; - } - - void Endpoint_type:: - setDisconnection_method (const Disconnection_methodType& x) - { - this->disconnection_method_.set (x); - } - - void Endpoint_type:: - setDisconnection_method (const Disconnection_methodOptional& x) - { - this->disconnection_method_ = x; - } - - void Endpoint_type:: - setDisconnection_method (::std::unique_ptr< Disconnection_methodType > x) - { - this->disconnection_method_.set (std::move (x)); - } - - const Endpoint_type::Disconnection_infoOptional& Endpoint_type:: - getDisconnection_info () const - { - return this->disconnection_info_; - } - - Endpoint_type::Disconnection_infoOptional& Endpoint_type:: - getDisconnection_info () - { - return this->disconnection_info_; - } - - void Endpoint_type:: - setDisconnection_info (const Disconnection_infoType& x) - { - this->disconnection_info_.set (x); - } - - void Endpoint_type:: - setDisconnection_info (const Disconnection_infoOptional& x) - { - this->disconnection_info_ = x; - } - - void Endpoint_type:: - setDisconnection_info (::std::unique_ptr< Disconnection_infoType > x) - { - this->disconnection_info_.set (std::move (x)); - } - - const Endpoint_type::MediaSequence& Endpoint_type:: - getMedia () const - { - return this->media_; - } - - Endpoint_type::MediaSequence& Endpoint_type:: - getMedia () - { - return this->media_; - } - - void Endpoint_type:: - setMedia (const MediaSequence& s) - { - this->media_ = s; - } - - const Endpoint_type::Call_infoOptional& Endpoint_type:: - getCall_info () const - { - return this->call_info_; - } - - Endpoint_type::Call_infoOptional& Endpoint_type:: - getCall_info () - { - return this->call_info_; - } - - void Endpoint_type:: - setCall_info (const Call_infoType& x) - { - this->call_info_.set (x); - } - - void Endpoint_type:: - setCall_info (const Call_infoOptional& x) - { - this->call_info_ = x; - } - - void Endpoint_type:: - setCall_info (::std::unique_ptr< Call_infoType > x) - { - this->call_info_.set (std::move (x)); - } - - const Endpoint_type::AnySequence& Endpoint_type:: - getAny () const - { - return this->any_; - } - - Endpoint_type::AnySequence& Endpoint_type:: - getAny () - { - return this->any_; - } - - void Endpoint_type:: - setAny (const AnySequence& s) - { - this->any_ = s; - } - - const Endpoint_type::EntityOptional& Endpoint_type:: - getEntity () const - { - return this->entity_; - } - - Endpoint_type::EntityOptional& Endpoint_type:: - getEntity () - { - return this->entity_; - } - - void Endpoint_type:: - setEntity (const EntityType& x) - { - this->entity_.set (x); - } - - void Endpoint_type:: - setEntity (const EntityOptional& x) - { - this->entity_ = x; - } - - void Endpoint_type:: - setEntity (::std::unique_ptr< EntityType > x) - { - this->entity_.set (std::move (x)); - } - - const Endpoint_type::StateType& Endpoint_type:: - getState () const - { - return this->state_.get (); - } - - Endpoint_type::StateType& Endpoint_type:: - getState () - { - return this->state_.get (); - } - - void Endpoint_type:: - setState (const StateType& x) - { - this->state_.set (x); - } - - void Endpoint_type:: - setState (::std::unique_ptr< StateType > x) - { - this->state_.set (std::move (x)); - } - - ::std::unique_ptr< Endpoint_type::StateType > Endpoint_type:: - detachState () - { - return this->state_.detach (); - } - - const Endpoint_type::StateType& Endpoint_type:: - getStateDefaultValue () - { - return state_default_value_; - } - - const Endpoint_type::AnyAttributeSet& Endpoint_type:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - Endpoint_type::AnyAttributeSet& Endpoint_type:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void Endpoint_type:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& Endpoint_type:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& Endpoint_type:: - getDomDocument () - { - return *this->dom_document_; - } - - - // Endpoint_status_type - // - - Endpoint_status_type:: - Endpoint_status_type (Value v) - : ::xml_schema::String (_xsd_Endpoint_status_type_literals_[v]) - { - } - - Endpoint_status_type:: - Endpoint_status_type (const char* v) - : ::xml_schema::String (v) - { - } - - Endpoint_status_type:: - Endpoint_status_type (const ::std::string& v) - : ::xml_schema::String (v) - { - } - - Endpoint_status_type:: - Endpoint_status_type (const ::xml_schema::String& v) - : ::xml_schema::String (v) - { - } - - Endpoint_status_type:: - Endpoint_status_type (const Endpoint_status_type& v, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (v, f, c) - { - } - - Endpoint_status_type& Endpoint_status_type:: - operator= (Value v) - { - static_cast< ::xml_schema::String& > (*this) = - ::xml_schema::String (_xsd_Endpoint_status_type_literals_[v]); - - return *this; - } - - - // Joining_type - // - - Joining_type:: - Joining_type (Value v) - : ::xml_schema::String (_xsd_Joining_type_literals_[v]) - { - } - - Joining_type:: - Joining_type (const char* v) - : ::xml_schema::String (v) - { - } - - Joining_type:: - Joining_type (const ::std::string& v) - : ::xml_schema::String (v) - { - } - - Joining_type:: - Joining_type (const ::xml_schema::String& v) - : ::xml_schema::String (v) - { - } - - Joining_type:: - Joining_type (const Joining_type& v, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (v, f, c) - { - } - - Joining_type& Joining_type:: - operator= (Value v) - { - static_cast< ::xml_schema::String& > (*this) = - ::xml_schema::String (_xsd_Joining_type_literals_[v]); - - return *this; - } - - - // Disconnection_type - // - - Disconnection_type:: - Disconnection_type (Value v) - : ::xml_schema::String (_xsd_Disconnection_type_literals_[v]) - { - } - - Disconnection_type:: - Disconnection_type (const char* v) - : ::xml_schema::String (v) - { - } - - Disconnection_type:: - Disconnection_type (const ::std::string& v) - : ::xml_schema::String (v) - { - } - - Disconnection_type:: - Disconnection_type (const ::xml_schema::String& v) - : ::xml_schema::String (v) - { - } - - Disconnection_type:: - Disconnection_type (const Disconnection_type& v, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (v, f, c) - { - } - - Disconnection_type& Disconnection_type:: - operator= (Value v) - { - static_cast< ::xml_schema::String& > (*this) = - ::xml_schema::String (_xsd_Disconnection_type_literals_[v]); - - return *this; - } - - - // Execution_type - // - - const Execution_type::WhenOptional& Execution_type:: - getWhen () const - { - return this->when_; - } - - Execution_type::WhenOptional& Execution_type:: - getWhen () - { - return this->when_; - } - - void Execution_type:: - setWhen (const WhenType& x) - { - this->when_.set (x); - } - - void Execution_type:: - setWhen (const WhenOptional& x) - { - this->when_ = x; - } - - void Execution_type:: - setWhen (::std::unique_ptr< WhenType > x) - { - this->when_.set (std::move (x)); - } - - const Execution_type::ReasonOptional& Execution_type:: - getReason () const - { - return this->reason_; - } - - Execution_type::ReasonOptional& Execution_type:: - getReason () - { - return this->reason_; - } - - void Execution_type:: - setReason (const ReasonType& x) - { - this->reason_.set (x); - } - - void Execution_type:: - setReason (const ReasonOptional& x) - { - this->reason_ = x; - } - - void Execution_type:: - setReason (::std::unique_ptr< ReasonType > x) - { - this->reason_.set (std::move (x)); - } - - const Execution_type::ByOptional& Execution_type:: - getBy () const - { - return this->by_; - } - - Execution_type::ByOptional& Execution_type:: - getBy () - { - return this->by_; - } - - void Execution_type:: - setBy (const ByType& x) - { - this->by_.set (x); - } - - void Execution_type:: - setBy (const ByOptional& x) - { - this->by_ = x; - } - - void Execution_type:: - setBy (::std::unique_ptr< ByType > x) - { - this->by_.set (std::move (x)); - } - - const Execution_type::AnyAttributeSet& Execution_type:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - Execution_type::AnyAttributeSet& Execution_type:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void Execution_type:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& Execution_type:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& Execution_type:: - getDomDocument () - { - return *this->dom_document_; - } - - - // Call_type - // - - const Call_type::SipOptional& Call_type:: - getSip () const - { - return this->sip_; - } - - Call_type::SipOptional& Call_type:: - getSip () - { - return this->sip_; - } - - void Call_type:: - setSip (const SipType& x) - { - this->sip_.set (x); - } - - void Call_type:: - setSip (const SipOptional& x) - { - this->sip_ = x; - } - - void Call_type:: - setSip (::std::unique_ptr< SipType > x) - { - this->sip_.set (std::move (x)); - } - - const Call_type::AnySequence& Call_type:: - getAny () const - { - return this->any_; - } - - Call_type::AnySequence& Call_type:: - getAny () - { - return this->any_; - } - - void Call_type:: - setAny (const AnySequence& s) - { - this->any_ = s; - } - - const Call_type::AnyAttributeSet& Call_type:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - Call_type::AnyAttributeSet& Call_type:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void Call_type:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& Call_type:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& Call_type:: - getDomDocument () - { - return *this->dom_document_; - } - - - // Sip_dialog_id_type - // - - const Sip_dialog_id_type::Display_textOptional& Sip_dialog_id_type:: - getDisplay_text () const - { - return this->display_text_; - } - - Sip_dialog_id_type::Display_textOptional& Sip_dialog_id_type:: - getDisplay_text () - { - return this->display_text_; - } - - void Sip_dialog_id_type:: - setDisplay_text (const Display_textType& x) - { - this->display_text_.set (x); - } - - void Sip_dialog_id_type:: - setDisplay_text (const Display_textOptional& x) - { - this->display_text_ = x; - } - - void Sip_dialog_id_type:: - setDisplay_text (::std::unique_ptr< Display_textType > x) - { - this->display_text_.set (std::move (x)); - } - - const Sip_dialog_id_type::Call_idType& Sip_dialog_id_type:: - getCall_id () const - { - return this->call_id_.get (); - } - - Sip_dialog_id_type::Call_idType& Sip_dialog_id_type:: - getCall_id () - { - return this->call_id_.get (); - } - - void Sip_dialog_id_type:: - setCall_id (const Call_idType& x) - { - this->call_id_.set (x); - } - - void Sip_dialog_id_type:: - setCall_id (::std::unique_ptr< Call_idType > x) - { - this->call_id_.set (std::move (x)); - } - - ::std::unique_ptr< Sip_dialog_id_type::Call_idType > Sip_dialog_id_type:: - detachCall_id () - { - return this->call_id_.detach (); - } - - const Sip_dialog_id_type::From_tagType& Sip_dialog_id_type:: - getFrom_tag () const - { - return this->from_tag_.get (); - } - - Sip_dialog_id_type::From_tagType& Sip_dialog_id_type:: - getFrom_tag () - { - return this->from_tag_.get (); - } - - void Sip_dialog_id_type:: - setFrom_tag (const From_tagType& x) - { - this->from_tag_.set (x); - } - - void Sip_dialog_id_type:: - setFrom_tag (::std::unique_ptr< From_tagType > x) - { - this->from_tag_.set (std::move (x)); - } - - ::std::unique_ptr< Sip_dialog_id_type::From_tagType > Sip_dialog_id_type:: - detachFrom_tag () - { - return this->from_tag_.detach (); - } - - const Sip_dialog_id_type::To_tagType& Sip_dialog_id_type:: - getTo_tag () const - { - return this->to_tag_.get (); - } - - Sip_dialog_id_type::To_tagType& Sip_dialog_id_type:: - getTo_tag () - { - return this->to_tag_.get (); - } - - void Sip_dialog_id_type:: - setTo_tag (const To_tagType& x) - { - this->to_tag_.set (x); - } - - void Sip_dialog_id_type:: - setTo_tag (::std::unique_ptr< To_tagType > x) - { - this->to_tag_.set (std::move (x)); - } - - ::std::unique_ptr< Sip_dialog_id_type::To_tagType > Sip_dialog_id_type:: - detachTo_tag () - { - return this->to_tag_.detach (); - } - - const Sip_dialog_id_type::AnySequence& Sip_dialog_id_type:: - getAny () const - { - return this->any_; - } - - Sip_dialog_id_type::AnySequence& Sip_dialog_id_type:: - getAny () - { - return this->any_; - } - - void Sip_dialog_id_type:: - setAny (const AnySequence& s) - { - this->any_ = s; - } - - const Sip_dialog_id_type::AnyAttributeSet& Sip_dialog_id_type:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - Sip_dialog_id_type::AnyAttributeSet& Sip_dialog_id_type:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void Sip_dialog_id_type:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& Sip_dialog_id_type:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& Sip_dialog_id_type:: - getDomDocument () - { - return *this->dom_document_; - } - - - // Media_type - // - - const Media_type::Display_textOptional& Media_type:: - getDisplay_text () const - { - return this->display_text_; - } - - Media_type::Display_textOptional& Media_type:: - getDisplay_text () - { - return this->display_text_; - } - - void Media_type:: - setDisplay_text (const Display_textType& x) - { - this->display_text_.set (x); - } - - void Media_type:: - setDisplay_text (const Display_textOptional& x) - { - this->display_text_ = x; - } - - void Media_type:: - setDisplay_text (::std::unique_ptr< Display_textType > x) - { - this->display_text_.set (std::move (x)); - } - - const Media_type::TypeOptional& Media_type:: - getType () const - { - return this->type_; - } - - Media_type::TypeOptional& Media_type:: - getType () - { - return this->type_; - } - - void Media_type:: - setType (const TypeType& x) - { - this->type_.set (x); - } - - void Media_type:: - setType (const TypeOptional& x) - { - this->type_ = x; - } - - void Media_type:: - setType (::std::unique_ptr< TypeType > x) - { - this->type_.set (std::move (x)); - } - - const Media_type::LabelOptional& Media_type:: - getLabel () const - { - return this->label_; - } - - Media_type::LabelOptional& Media_type:: - getLabel () - { - return this->label_; - } - - void Media_type:: - setLabel (const LabelType& x) - { - this->label_.set (x); - } - - void Media_type:: - setLabel (const LabelOptional& x) - { - this->label_ = x; - } - - void Media_type:: - setLabel (::std::unique_ptr< LabelType > x) - { - this->label_.set (std::move (x)); - } - - const Media_type::Src_idOptional& Media_type:: - getSrc_id () const - { - return this->src_id_; - } - - Media_type::Src_idOptional& Media_type:: - getSrc_id () - { - return this->src_id_; - } - - void Media_type:: - setSrc_id (const Src_idType& x) - { - this->src_id_.set (x); - } - - void Media_type:: - setSrc_id (const Src_idOptional& x) - { - this->src_id_ = x; - } - - void Media_type:: - setSrc_id (::std::unique_ptr< Src_idType > x) - { - this->src_id_.set (std::move (x)); - } - - const Media_type::StatusOptional& Media_type:: - getStatus () const - { - return this->status_; - } - - Media_type::StatusOptional& Media_type:: - getStatus () - { - return this->status_; - } - - void Media_type:: - setStatus (const StatusType& x) - { - this->status_.set (x); - } - - void Media_type:: - setStatus (const StatusOptional& x) - { - this->status_ = x; - } - - void Media_type:: - setStatus (::std::unique_ptr< StatusType > x) - { - this->status_.set (std::move (x)); - } - - const Media_type::AnySequence& Media_type:: - getAny () const - { - return this->any_; - } - - Media_type::AnySequence& Media_type:: - getAny () - { - return this->any_; - } - - void Media_type:: - setAny (const AnySequence& s) - { - this->any_ = s; - } - - const Media_type::IdType& Media_type:: - getId () const - { - return this->id_.get (); - } - - Media_type::IdType& Media_type:: - getId () - { - return this->id_.get (); - } - - void Media_type:: - setId (const IdType& x) - { - this->id_.set (x); - } - - void Media_type:: - setId (::std::unique_ptr< IdType > x) - { - this->id_.set (std::move (x)); - } - - ::std::unique_ptr< Media_type::IdType > Media_type:: - detachId () - { - return this->id_.detach (); - } - - const Media_type::AnyAttributeSet& Media_type:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - Media_type::AnyAttributeSet& Media_type:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void Media_type:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& Media_type:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& Media_type:: - getDomDocument () - { - return *this->dom_document_; - } - - - // Media_status_type - // - - Media_status_type:: - Media_status_type (Value v) - : ::xml_schema::String (_xsd_Media_status_type_literals_[v]) - { - } - - Media_status_type:: - Media_status_type (const char* v) - : ::xml_schema::String (v) - { - } - - Media_status_type:: - Media_status_type (const ::std::string& v) - : ::xml_schema::String (v) - { - } - - Media_status_type:: - Media_status_type (const ::xml_schema::String& v) - : ::xml_schema::String (v) - { - } - - Media_status_type:: - Media_status_type (const Media_status_type& v, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (v, f, c) - { - } - - Media_status_type& Media_status_type:: - operator= (Value v) - { - static_cast< ::xml_schema::String& > (*this) = - ::xml_schema::String (_xsd_Media_status_type_literals_[v]); - - return *this; - } - - - // Sidebars_by_val_type - // - - const Sidebars_by_val_type::EntrySequence& Sidebars_by_val_type:: - getEntry () const - { - return this->entry_; - } - - Sidebars_by_val_type::EntrySequence& Sidebars_by_val_type:: - getEntry () - { - return this->entry_; - } - - void Sidebars_by_val_type:: - setEntry (const EntrySequence& s) - { - this->entry_ = s; - } - - const Sidebars_by_val_type::StateType& Sidebars_by_val_type:: - getState () const - { - return this->state_.get (); - } - - Sidebars_by_val_type::StateType& Sidebars_by_val_type:: - getState () - { - return this->state_.get (); - } - - void Sidebars_by_val_type:: - setState (const StateType& x) - { - this->state_.set (x); - } - - void Sidebars_by_val_type:: - setState (::std::unique_ptr< StateType > x) - { - this->state_.set (std::move (x)); - } - - ::std::unique_ptr< Sidebars_by_val_type::StateType > Sidebars_by_val_type:: - detachState () - { - return this->state_.detach (); - } - - const Sidebars_by_val_type::StateType& Sidebars_by_val_type:: - getStateDefaultValue () - { - return state_default_value_; - } - - const Sidebars_by_val_type::AnyAttributeSet& Sidebars_by_val_type:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - Sidebars_by_val_type::AnyAttributeSet& Sidebars_by_val_type:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void Sidebars_by_val_type:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& Sidebars_by_val_type:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& Sidebars_by_val_type:: - getDomDocument () - { - return *this->dom_document_; + namespace Xsd + { + namespace ConferenceInfo + { + // ConferenceType + // + + const ConferenceType::ConferenceDescriptionOptional& ConferenceType:: + getConferenceDescription () const + { + return this->conference_description_; + } + + ConferenceType::ConferenceDescriptionOptional& ConferenceType:: + getConferenceDescription () + { + return this->conference_description_; + } + + void ConferenceType:: + setConferenceDescription (const ConferenceDescriptionType& x) + { + this->conference_description_.set (x); + } + + void ConferenceType:: + setConferenceDescription (const ConferenceDescriptionOptional& x) + { + this->conference_description_ = x; + } + + void ConferenceType:: + setConferenceDescription (::std::unique_ptr< ConferenceDescriptionType > x) + { + this->conference_description_.set (std::move (x)); + } + + const ConferenceType::HostInfoOptional& ConferenceType:: + getHostInfo () const + { + return this->host_info_; + } + + ConferenceType::HostInfoOptional& ConferenceType:: + getHostInfo () + { + return this->host_info_; + } + + void ConferenceType:: + setHostInfo (const HostInfoType& x) + { + this->host_info_.set (x); + } + + void ConferenceType:: + setHostInfo (const HostInfoOptional& x) + { + this->host_info_ = x; + } + + void ConferenceType:: + setHostInfo (::std::unique_ptr< HostInfoType > x) + { + this->host_info_.set (std::move (x)); + } + + const ConferenceType::ConferenceStateOptional& ConferenceType:: + getConferenceState () const + { + return this->conference_state_; + } + + ConferenceType::ConferenceStateOptional& ConferenceType:: + getConferenceState () + { + return this->conference_state_; + } + + void ConferenceType:: + setConferenceState (const ConferenceStateType& x) + { + this->conference_state_.set (x); + } + + void ConferenceType:: + setConferenceState (const ConferenceStateOptional& x) + { + this->conference_state_ = x; + } + + void ConferenceType:: + setConferenceState (::std::unique_ptr< ConferenceStateType > x) + { + this->conference_state_.set (std::move (x)); + } + + const ConferenceType::UsersOptional& ConferenceType:: + getUsers () const + { + return this->users_; + } + + ConferenceType::UsersOptional& ConferenceType:: + getUsers () + { + return this->users_; + } + + void ConferenceType:: + setUsers (const UsersType& x) + { + this->users_.set (x); + } + + void ConferenceType:: + setUsers (const UsersOptional& x) + { + this->users_ = x; + } + + void ConferenceType:: + setUsers (::std::unique_ptr< UsersType > x) + { + this->users_.set (std::move (x)); + } + + const ConferenceType::SidebarsByRefOptional& ConferenceType:: + getSidebarsByRef () const + { + return this->sidebars_by_ref_; + } + + ConferenceType::SidebarsByRefOptional& ConferenceType:: + getSidebarsByRef () + { + return this->sidebars_by_ref_; + } + + void ConferenceType:: + setSidebarsByRef (const SidebarsByRefType& x) + { + this->sidebars_by_ref_.set (x); + } + + void ConferenceType:: + setSidebarsByRef (const SidebarsByRefOptional& x) + { + this->sidebars_by_ref_ = x; + } + + void ConferenceType:: + setSidebarsByRef (::std::unique_ptr< SidebarsByRefType > x) + { + this->sidebars_by_ref_.set (std::move (x)); + } + + const ConferenceType::SidebarsByValOptional& ConferenceType:: + getSidebarsByVal () const + { + return this->sidebars_by_val_; + } + + ConferenceType::SidebarsByValOptional& ConferenceType:: + getSidebarsByVal () + { + return this->sidebars_by_val_; + } + + void ConferenceType:: + setSidebarsByVal (const SidebarsByValType& x) + { + this->sidebars_by_val_.set (x); + } + + void ConferenceType:: + setSidebarsByVal (const SidebarsByValOptional& x) + { + this->sidebars_by_val_ = x; + } + + void ConferenceType:: + setSidebarsByVal (::std::unique_ptr< SidebarsByValType > x) + { + this->sidebars_by_val_.set (std::move (x)); + } + + const ConferenceType::AnySequence& ConferenceType:: + getAny () const + { + return this->any_; + } + + ConferenceType::AnySequence& ConferenceType:: + getAny () + { + return this->any_; + } + + void ConferenceType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const ConferenceType::EntityType& ConferenceType:: + getEntity () const + { + return this->entity_.get (); + } + + ConferenceType::EntityType& ConferenceType:: + getEntity () + { + return this->entity_.get (); + } + + void ConferenceType:: + setEntity (const EntityType& x) + { + this->entity_.set (x); + } + + void ConferenceType:: + setEntity (::std::unique_ptr< EntityType > x) + { + this->entity_.set (std::move (x)); + } + + ::std::unique_ptr< ConferenceType::EntityType > ConferenceType:: + setDetachEntity () + { + return this->entity_.detach (); + } + + const ConferenceType::StateType& ConferenceType:: + getState () const + { + return this->state_.get (); + } + + ConferenceType::StateType& ConferenceType:: + getState () + { + return this->state_.get (); + } + + void ConferenceType:: + setState (const StateType& x) + { + this->state_.set (x); + } + + void ConferenceType:: + setState (::std::unique_ptr< StateType > x) + { + this->state_.set (std::move (x)); + } + + ::std::unique_ptr< ConferenceType::StateType > ConferenceType:: + setDetachState () + { + return this->state_.detach (); + } + + const ConferenceType::StateType& ConferenceType:: + getStateDefaultValue () + { + return state_default_value_; + } + + const ConferenceType::VersionOptional& ConferenceType:: + getVersion () const + { + return this->version_; + } + + ConferenceType::VersionOptional& ConferenceType:: + getVersion () + { + return this->version_; + } + + void ConferenceType:: + setVersion (const VersionType& x) + { + this->version_.set (x); + } + + void ConferenceType:: + setVersion (const VersionOptional& x) + { + this->version_ = x; + } + + const ConferenceType::AnyAttributeSet& ConferenceType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + ConferenceType::AnyAttributeSet& ConferenceType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void ConferenceType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& ConferenceType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& ConferenceType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // StateType + // + + StateType:: + StateType (Value v) + : ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_StateType_literals_[v]) + { + } + + StateType:: + StateType (const char* v) + : ::LinphonePrivate::Xsd::XmlSchema::String (v) + { + } + + StateType:: + StateType (const ::std::string& v) + : ::LinphonePrivate::Xsd::XmlSchema::String (v) + { + } + + StateType:: + StateType (const ::LinphonePrivate::Xsd::XmlSchema::String& v) + : ::LinphonePrivate::Xsd::XmlSchema::String (v) + { + } + + StateType:: + StateType (const StateType& v, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (v, f, c) + { + } + + StateType& StateType:: + operator= (Value v) + { + static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = + ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_StateType_literals_[v]); + + return *this; + } + + + // ConferenceDescriptionType + // + + const ConferenceDescriptionType::DisplayTextOptional& ConferenceDescriptionType:: + getDisplayText () const + { + return this->display_text_; + } + + ConferenceDescriptionType::DisplayTextOptional& ConferenceDescriptionType:: + getDisplayText () + { + return this->display_text_; + } + + void ConferenceDescriptionType:: + setDisplayText (const DisplayTextType& x) + { + this->display_text_.set (x); + } + + void ConferenceDescriptionType:: + setDisplayText (const DisplayTextOptional& x) + { + this->display_text_ = x; + } + + void ConferenceDescriptionType:: + setDisplayText (::std::unique_ptr< DisplayTextType > x) + { + this->display_text_.set (std::move (x)); + } + + const ConferenceDescriptionType::SubjectOptional& ConferenceDescriptionType:: + getSubject () const + { + return this->subject_; + } + + ConferenceDescriptionType::SubjectOptional& ConferenceDescriptionType:: + getSubject () + { + return this->subject_; + } + + void ConferenceDescriptionType:: + setSubject (const SubjectType& x) + { + this->subject_.set (x); + } + + void ConferenceDescriptionType:: + setSubject (const SubjectOptional& x) + { + this->subject_ = x; + } + + void ConferenceDescriptionType:: + setSubject (::std::unique_ptr< SubjectType > x) + { + this->subject_.set (std::move (x)); + } + + const ConferenceDescriptionType::FreeTextOptional& ConferenceDescriptionType:: + getFreeText () const + { + return this->free_text_; + } + + ConferenceDescriptionType::FreeTextOptional& ConferenceDescriptionType:: + getFreeText () + { + return this->free_text_; + } + + void ConferenceDescriptionType:: + setFreeText (const FreeTextType& x) + { + this->free_text_.set (x); + } + + void ConferenceDescriptionType:: + setFreeText (const FreeTextOptional& x) + { + this->free_text_ = x; + } + + void ConferenceDescriptionType:: + setFreeText (::std::unique_ptr< FreeTextType > x) + { + this->free_text_.set (std::move (x)); + } + + const ConferenceDescriptionType::KeywordsOptional& ConferenceDescriptionType:: + getKeywords () const + { + return this->keywords_; + } + + ConferenceDescriptionType::KeywordsOptional& ConferenceDescriptionType:: + getKeywords () + { + return this->keywords_; + } + + void ConferenceDescriptionType:: + setKeywords (const KeywordsType& x) + { + this->keywords_.set (x); + } + + void ConferenceDescriptionType:: + setKeywords (const KeywordsOptional& x) + { + this->keywords_ = x; + } + + void ConferenceDescriptionType:: + setKeywords (::std::unique_ptr< KeywordsType > x) + { + this->keywords_.set (std::move (x)); + } + + const ConferenceDescriptionType::ConfUrisOptional& ConferenceDescriptionType:: + getConfUris () const + { + return this->conf_uris_; + } + + ConferenceDescriptionType::ConfUrisOptional& ConferenceDescriptionType:: + getConfUris () + { + return this->conf_uris_; + } + + void ConferenceDescriptionType:: + setConfUris (const ConfUrisType& x) + { + this->conf_uris_.set (x); + } + + void ConferenceDescriptionType:: + setConfUris (const ConfUrisOptional& x) + { + this->conf_uris_ = x; + } + + void ConferenceDescriptionType:: + setConfUris (::std::unique_ptr< ConfUrisType > x) + { + this->conf_uris_.set (std::move (x)); + } + + const ConferenceDescriptionType::ServiceUrisOptional& ConferenceDescriptionType:: + getServiceUris () const + { + return this->service_uris_; + } + + ConferenceDescriptionType::ServiceUrisOptional& ConferenceDescriptionType:: + getServiceUris () + { + return this->service_uris_; + } + + void ConferenceDescriptionType:: + setServiceUris (const ServiceUrisType& x) + { + this->service_uris_.set (x); + } + + void ConferenceDescriptionType:: + setServiceUris (const ServiceUrisOptional& x) + { + this->service_uris_ = x; + } + + void ConferenceDescriptionType:: + setServiceUris (::std::unique_ptr< ServiceUrisType > x) + { + this->service_uris_.set (std::move (x)); + } + + const ConferenceDescriptionType::MaximumUserCountOptional& ConferenceDescriptionType:: + getMaximumUserCount () const + { + return this->maximum_user_count_; + } + + ConferenceDescriptionType::MaximumUserCountOptional& ConferenceDescriptionType:: + getMaximumUserCount () + { + return this->maximum_user_count_; + } + + void ConferenceDescriptionType:: + setMaximumUserCount (const MaximumUserCountType& x) + { + this->maximum_user_count_.set (x); + } + + void ConferenceDescriptionType:: + setMaximumUserCount (const MaximumUserCountOptional& x) + { + this->maximum_user_count_ = x; + } + + const ConferenceDescriptionType::AvailableMediaOptional& ConferenceDescriptionType:: + getAvailableMedia () const + { + return this->available_media_; + } + + ConferenceDescriptionType::AvailableMediaOptional& ConferenceDescriptionType:: + getAvailableMedia () + { + return this->available_media_; + } + + void ConferenceDescriptionType:: + setAvailableMedia (const AvailableMediaType& x) + { + this->available_media_.set (x); + } + + void ConferenceDescriptionType:: + setAvailableMedia (const AvailableMediaOptional& x) + { + this->available_media_ = x; + } + + void ConferenceDescriptionType:: + setAvailableMedia (::std::unique_ptr< AvailableMediaType > x) + { + this->available_media_.set (std::move (x)); + } + + const ConferenceDescriptionType::AnySequence& ConferenceDescriptionType:: + getAny () const + { + return this->any_; + } + + ConferenceDescriptionType::AnySequence& ConferenceDescriptionType:: + getAny () + { + return this->any_; + } + + void ConferenceDescriptionType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const ConferenceDescriptionType::AnyAttributeSet& ConferenceDescriptionType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + ConferenceDescriptionType::AnyAttributeSet& ConferenceDescriptionType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void ConferenceDescriptionType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& ConferenceDescriptionType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& ConferenceDescriptionType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // HostType + // + + const HostType::DisplayTextOptional& HostType:: + getDisplayText () const + { + return this->display_text_; + } + + HostType::DisplayTextOptional& HostType:: + getDisplayText () + { + return this->display_text_; + } + + void HostType:: + setDisplayText (const DisplayTextType& x) + { + this->display_text_.set (x); + } + + void HostType:: + setDisplayText (const DisplayTextOptional& x) + { + this->display_text_ = x; + } + + void HostType:: + setDisplayText (::std::unique_ptr< DisplayTextType > x) + { + this->display_text_.set (std::move (x)); + } + + const HostType::WebPageOptional& HostType:: + getWebPage () const + { + return this->web_page_; + } + + HostType::WebPageOptional& HostType:: + getWebPage () + { + return this->web_page_; + } + + void HostType:: + setWebPage (const WebPageType& x) + { + this->web_page_.set (x); + } + + void HostType:: + setWebPage (const WebPageOptional& x) + { + this->web_page_ = x; + } + + void HostType:: + setWebPage (::std::unique_ptr< WebPageType > x) + { + this->web_page_.set (std::move (x)); + } + + const HostType::UrisOptional& HostType:: + getUris () const + { + return this->uris_; + } + + HostType::UrisOptional& HostType:: + getUris () + { + return this->uris_; + } + + void HostType:: + setUris (const UrisType& x) + { + this->uris_.set (x); + } + + void HostType:: + setUris (const UrisOptional& x) + { + this->uris_ = x; + } + + void HostType:: + setUris (::std::unique_ptr< UrisType > x) + { + this->uris_.set (std::move (x)); + } + + const HostType::AnySequence& HostType:: + getAny () const + { + return this->any_; + } + + HostType::AnySequence& HostType:: + getAny () + { + return this->any_; + } + + void HostType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const HostType::AnyAttributeSet& HostType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + HostType::AnyAttributeSet& HostType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void HostType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& HostType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& HostType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // ConferenceStateType + // + + const ConferenceStateType::UserCountOptional& ConferenceStateType:: + getUserCount () const + { + return this->user_count_; + } + + ConferenceStateType::UserCountOptional& ConferenceStateType:: + getUserCount () + { + return this->user_count_; + } + + void ConferenceStateType:: + setUserCount (const UserCountType& x) + { + this->user_count_.set (x); + } + + void ConferenceStateType:: + setUserCount (const UserCountOptional& x) + { + this->user_count_ = x; + } + + const ConferenceStateType::ActiveOptional& ConferenceStateType:: + getActive () const + { + return this->active_; + } + + ConferenceStateType::ActiveOptional& ConferenceStateType:: + getActive () + { + return this->active_; + } + + void ConferenceStateType:: + setActive (const ActiveType& x) + { + this->active_.set (x); + } + + void ConferenceStateType:: + setActive (const ActiveOptional& x) + { + this->active_ = x; + } + + const ConferenceStateType::LockedOptional& ConferenceStateType:: + getLocked () const + { + return this->locked_; + } + + ConferenceStateType::LockedOptional& ConferenceStateType:: + getLocked () + { + return this->locked_; + } + + void ConferenceStateType:: + setLocked (const LockedType& x) + { + this->locked_.set (x); + } + + void ConferenceStateType:: + setLocked (const LockedOptional& x) + { + this->locked_ = x; + } + + const ConferenceStateType::AnySequence& ConferenceStateType:: + getAny () const + { + return this->any_; + } + + ConferenceStateType::AnySequence& ConferenceStateType:: + getAny () + { + return this->any_; + } + + void ConferenceStateType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const ConferenceStateType::AnyAttributeSet& ConferenceStateType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + ConferenceStateType::AnyAttributeSet& ConferenceStateType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void ConferenceStateType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& ConferenceStateType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& ConferenceStateType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // ConferenceMediaType + // + + const ConferenceMediaType::EntrySequence& ConferenceMediaType:: + getEntry () const + { + return this->entry_; + } + + ConferenceMediaType::EntrySequence& ConferenceMediaType:: + getEntry () + { + return this->entry_; + } + + void ConferenceMediaType:: + setEntry (const EntrySequence& s) + { + this->entry_ = s; + } + + const ConferenceMediaType::AnyAttributeSet& ConferenceMediaType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + ConferenceMediaType::AnyAttributeSet& ConferenceMediaType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void ConferenceMediaType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& ConferenceMediaType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& ConferenceMediaType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // ConferenceMediumType + // + + const ConferenceMediumType::DisplayTextOptional& ConferenceMediumType:: + getDisplayText () const + { + return this->display_text_; + } + + ConferenceMediumType::DisplayTextOptional& ConferenceMediumType:: + getDisplayText () + { + return this->display_text_; + } + + void ConferenceMediumType:: + setDisplayText (const DisplayTextType& x) + { + this->display_text_.set (x); + } + + void ConferenceMediumType:: + setDisplayText (const DisplayTextOptional& x) + { + this->display_text_ = x; + } + + void ConferenceMediumType:: + setDisplayText (::std::unique_ptr< DisplayTextType > x) + { + this->display_text_.set (std::move (x)); + } + + const ConferenceMediumType::TypeType& ConferenceMediumType:: + getType () const + { + return this->type_.get (); + } + + ConferenceMediumType::TypeType& ConferenceMediumType:: + getType () + { + return this->type_.get (); + } + + void ConferenceMediumType:: + setType (const TypeType& x) + { + this->type_.set (x); + } + + void ConferenceMediumType:: + setType (::std::unique_ptr< TypeType > x) + { + this->type_.set (std::move (x)); + } + + ::std::unique_ptr< ConferenceMediumType::TypeType > ConferenceMediumType:: + setDetachType () + { + return this->type_.detach (); + } + + const ConferenceMediumType::StatusOptional& ConferenceMediumType:: + getStatus () const + { + return this->status_; + } + + ConferenceMediumType::StatusOptional& ConferenceMediumType:: + getStatus () + { + return this->status_; + } + + void ConferenceMediumType:: + setStatus (const StatusType& x) + { + this->status_.set (x); + } + + void ConferenceMediumType:: + setStatus (const StatusOptional& x) + { + this->status_ = x; + } + + void ConferenceMediumType:: + setStatus (::std::unique_ptr< StatusType > x) + { + this->status_.set (std::move (x)); + } + + const ConferenceMediumType::AnySequence& ConferenceMediumType:: + getAny () const + { + return this->any_; + } + + ConferenceMediumType::AnySequence& ConferenceMediumType:: + getAny () + { + return this->any_; + } + + void ConferenceMediumType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const ConferenceMediumType::LabelType& ConferenceMediumType:: + getLabel () const + { + return this->label_.get (); + } + + ConferenceMediumType::LabelType& ConferenceMediumType:: + getLabel () + { + return this->label_.get (); + } + + void ConferenceMediumType:: + setLabel (const LabelType& x) + { + this->label_.set (x); + } + + void ConferenceMediumType:: + setLabel (::std::unique_ptr< LabelType > x) + { + this->label_.set (std::move (x)); + } + + ::std::unique_ptr< ConferenceMediumType::LabelType > ConferenceMediumType:: + setDetachLabel () + { + return this->label_.detach (); + } + + const ConferenceMediumType::AnyAttributeSet& ConferenceMediumType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + ConferenceMediumType::AnyAttributeSet& ConferenceMediumType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void ConferenceMediumType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& ConferenceMediumType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& ConferenceMediumType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // UrisType + // + + const UrisType::EntrySequence& UrisType:: + getEntry () const + { + return this->entry_; + } + + UrisType::EntrySequence& UrisType:: + getEntry () + { + return this->entry_; + } + + void UrisType:: + setEntry (const EntrySequence& s) + { + this->entry_ = s; + } + + const UrisType::StateType& UrisType:: + getState () const + { + return this->state_.get (); + } + + UrisType::StateType& UrisType:: + getState () + { + return this->state_.get (); + } + + void UrisType:: + setState (const StateType& x) + { + this->state_.set (x); + } + + void UrisType:: + setState (::std::unique_ptr< StateType > x) + { + this->state_.set (std::move (x)); + } + + ::std::unique_ptr< UrisType::StateType > UrisType:: + setDetachState () + { + return this->state_.detach (); + } + + const UrisType::StateType& UrisType:: + getStateDefaultValue () + { + return state_default_value_; + } + + const UrisType::AnyAttributeSet& UrisType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + UrisType::AnyAttributeSet& UrisType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void UrisType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& UrisType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& UrisType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // UriType + // + + const UriType::UriType1& UriType:: + getUri () const + { + return this->uri_.get (); + } + + UriType::UriType1& UriType:: + getUri () + { + return this->uri_.get (); + } + + void UriType:: + setUri (const UriType1& x) + { + this->uri_.set (x); + } + + void UriType:: + setUri (::std::unique_ptr< UriType1 > x) + { + this->uri_.set (std::move (x)); + } + + ::std::unique_ptr< UriType::UriType1 > UriType:: + setDetachUri () + { + return this->uri_.detach (); + } + + const UriType::DisplayTextOptional& UriType:: + getDisplayText () const + { + return this->display_text_; + } + + UriType::DisplayTextOptional& UriType:: + getDisplayText () + { + return this->display_text_; + } + + void UriType:: + setDisplayText (const DisplayTextType& x) + { + this->display_text_.set (x); + } + + void UriType:: + setDisplayText (const DisplayTextOptional& x) + { + this->display_text_ = x; + } + + void UriType:: + setDisplayText (::std::unique_ptr< DisplayTextType > x) + { + this->display_text_.set (std::move (x)); + } + + const UriType::PurposeOptional& UriType:: + getPurpose () const + { + return this->purpose_; + } + + UriType::PurposeOptional& UriType:: + getPurpose () + { + return this->purpose_; + } + + void UriType:: + setPurpose (const PurposeType& x) + { + this->purpose_.set (x); + } + + void UriType:: + setPurpose (const PurposeOptional& x) + { + this->purpose_ = x; + } + + void UriType:: + setPurpose (::std::unique_ptr< PurposeType > x) + { + this->purpose_.set (std::move (x)); + } + + const UriType::ModifiedOptional& UriType:: + getModified () const + { + return this->modified_; + } + + UriType::ModifiedOptional& UriType:: + getModified () + { + return this->modified_; + } + + void UriType:: + setModified (const ModifiedType& x) + { + this->modified_.set (x); + } + + void UriType:: + setModified (const ModifiedOptional& x) + { + this->modified_ = x; + } + + void UriType:: + setModified (::std::unique_ptr< ModifiedType > x) + { + this->modified_.set (std::move (x)); + } + + const UriType::AnySequence& UriType:: + getAny () const + { + return this->any_; + } + + UriType::AnySequence& UriType:: + getAny () + { + return this->any_; + } + + void UriType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const UriType::AnyAttributeSet& UriType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + UriType::AnyAttributeSet& UriType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void UriType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& UriType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& UriType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // KeywordsType + // + + KeywordsType:: + KeywordsType () + : ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::String, char > (this) + { + } + + KeywordsType:: + KeywordsType (size_type n, const ::LinphonePrivate::Xsd::XmlSchema::String& x) + : ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::String, char > (n, x, this) + { + } + + KeywordsType:: + KeywordsType (const KeywordsType& o, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::SimpleType (o, f, c), + ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::String, char > (o, f, this) + { + } + + // UsersType + // + + const UsersType::UserSequence& UsersType:: + getUser () const + { + return this->user_; + } + + UsersType::UserSequence& UsersType:: + getUser () + { + return this->user_; + } + + void UsersType:: + setUser (const UserSequence& s) + { + this->user_ = s; + } + + const UsersType::AnySequence& UsersType:: + getAny () const + { + return this->any_; + } + + UsersType::AnySequence& UsersType:: + getAny () + { + return this->any_; + } + + void UsersType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const UsersType::StateType& UsersType:: + getState () const + { + return this->state_.get (); + } + + UsersType::StateType& UsersType:: + getState () + { + return this->state_.get (); + } + + void UsersType:: + setState (const StateType& x) + { + this->state_.set (x); + } + + void UsersType:: + setState (::std::unique_ptr< StateType > x) + { + this->state_.set (std::move (x)); + } + + ::std::unique_ptr< UsersType::StateType > UsersType:: + setDetachState () + { + return this->state_.detach (); + } + + const UsersType::StateType& UsersType:: + getStateDefaultValue () + { + return state_default_value_; + } + + const UsersType::AnyAttributeSet& UsersType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + UsersType::AnyAttributeSet& UsersType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void UsersType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& UsersType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& UsersType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // UserType + // + + const UserType::DisplayTextOptional& UserType:: + getDisplayText () const + { + return this->display_text_; + } + + UserType::DisplayTextOptional& UserType:: + getDisplayText () + { + return this->display_text_; + } + + void UserType:: + setDisplayText (const DisplayTextType& x) + { + this->display_text_.set (x); + } + + void UserType:: + setDisplayText (const DisplayTextOptional& x) + { + this->display_text_ = x; + } + + void UserType:: + setDisplayText (::std::unique_ptr< DisplayTextType > x) + { + this->display_text_.set (std::move (x)); + } + + const UserType::AssociatedAorsOptional& UserType:: + getAssociatedAors () const + { + return this->associated_aors_; + } + + UserType::AssociatedAorsOptional& UserType:: + getAssociatedAors () + { + return this->associated_aors_; + } + + void UserType:: + setAssociatedAors (const AssociatedAorsType& x) + { + this->associated_aors_.set (x); + } + + void UserType:: + setAssociatedAors (const AssociatedAorsOptional& x) + { + this->associated_aors_ = x; + } + + void UserType:: + setAssociatedAors (::std::unique_ptr< AssociatedAorsType > x) + { + this->associated_aors_.set (std::move (x)); + } + + const UserType::RolesOptional& UserType:: + getRoles () const + { + return this->roles_; + } + + UserType::RolesOptional& UserType:: + getRoles () + { + return this->roles_; + } + + void UserType:: + setRoles (const RolesType& x) + { + this->roles_.set (x); + } + + void UserType:: + setRoles (const RolesOptional& x) + { + this->roles_ = x; + } + + void UserType:: + setRoles (::std::unique_ptr< RolesType > x) + { + this->roles_.set (std::move (x)); + } + + const UserType::LanguagesOptional& UserType:: + getLanguages () const + { + return this->languages_; + } + + UserType::LanguagesOptional& UserType:: + getLanguages () + { + return this->languages_; + } + + void UserType:: + setLanguages (const LanguagesType& x) + { + this->languages_.set (x); + } + + void UserType:: + setLanguages (const LanguagesOptional& x) + { + this->languages_ = x; + } + + void UserType:: + setLanguages (::std::unique_ptr< LanguagesType > x) + { + this->languages_.set (std::move (x)); + } + + const UserType::CascadedFocusOptional& UserType:: + getCascadedFocus () const + { + return this->cascaded_focus_; + } + + UserType::CascadedFocusOptional& UserType:: + getCascadedFocus () + { + return this->cascaded_focus_; + } + + void UserType:: + setCascadedFocus (const CascadedFocusType& x) + { + this->cascaded_focus_.set (x); + } + + void UserType:: + setCascadedFocus (const CascadedFocusOptional& x) + { + this->cascaded_focus_ = x; + } + + void UserType:: + setCascadedFocus (::std::unique_ptr< CascadedFocusType > x) + { + this->cascaded_focus_.set (std::move (x)); + } + + const UserType::EndpointSequence& UserType:: + getEndpoint () const + { + return this->endpoint_; + } + + UserType::EndpointSequence& UserType:: + getEndpoint () + { + return this->endpoint_; + } + + void UserType:: + setEndpoint (const EndpointSequence& s) + { + this->endpoint_ = s; + } + + const UserType::AnySequence& UserType:: + getAny () const + { + return this->any_; + } + + UserType::AnySequence& UserType:: + getAny () + { + return this->any_; + } + + void UserType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const UserType::EntityOptional& UserType:: + getEntity () const + { + return this->entity_; + } + + UserType::EntityOptional& UserType:: + getEntity () + { + return this->entity_; + } + + void UserType:: + setEntity (const EntityType& x) + { + this->entity_.set (x); + } + + void UserType:: + setEntity (const EntityOptional& x) + { + this->entity_ = x; + } + + void UserType:: + setEntity (::std::unique_ptr< EntityType > x) + { + this->entity_.set (std::move (x)); + } + + const UserType::StateType& UserType:: + getState () const + { + return this->state_.get (); + } + + UserType::StateType& UserType:: + getState () + { + return this->state_.get (); + } + + void UserType:: + setState (const StateType& x) + { + this->state_.set (x); + } + + void UserType:: + setState (::std::unique_ptr< StateType > x) + { + this->state_.set (std::move (x)); + } + + ::std::unique_ptr< UserType::StateType > UserType:: + setDetachState () + { + return this->state_.detach (); + } + + const UserType::StateType& UserType:: + getStateDefaultValue () + { + return state_default_value_; + } + + const UserType::AnyAttributeSet& UserType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + UserType::AnyAttributeSet& UserType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void UserType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& UserType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& UserType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // UserRolesType + // + + const UserRolesType::EntrySequence& UserRolesType:: + getEntry () const + { + return this->entry_; + } + + UserRolesType::EntrySequence& UserRolesType:: + getEntry () + { + return this->entry_; + } + + void UserRolesType:: + setEntry (const EntrySequence& s) + { + this->entry_ = s; + } + + const UserRolesType::AnyAttributeSet& UserRolesType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + UserRolesType::AnyAttributeSet& UserRolesType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void UserRolesType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& UserRolesType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& UserRolesType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // UserLanguagesType + // + + UserLanguagesType:: + UserLanguagesType () + : ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::Language, char > (this) + { + } + + UserLanguagesType:: + UserLanguagesType (size_type n, const ::LinphonePrivate::Xsd::XmlSchema::Language& x) + : ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::Language, char > (n, x, this) + { + } + + UserLanguagesType:: + UserLanguagesType (const UserLanguagesType& o, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::SimpleType (o, f, c), + ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::Language, char > (o, f, this) + { + } + + // EndpointType + // + + const EndpointType::DisplayTextOptional& EndpointType:: + getDisplayText () const + { + return this->display_text_; + } + + EndpointType::DisplayTextOptional& EndpointType:: + getDisplayText () + { + return this->display_text_; + } + + void EndpointType:: + setDisplayText (const DisplayTextType& x) + { + this->display_text_.set (x); + } + + void EndpointType:: + setDisplayText (const DisplayTextOptional& x) + { + this->display_text_ = x; + } + + void EndpointType:: + setDisplayText (::std::unique_ptr< DisplayTextType > x) + { + this->display_text_.set (std::move (x)); + } + + const EndpointType::ReferredOptional& EndpointType:: + getReferred () const + { + return this->referred_; + } + + EndpointType::ReferredOptional& EndpointType:: + getReferred () + { + return this->referred_; + } + + void EndpointType:: + setReferred (const ReferredType& x) + { + this->referred_.set (x); + } + + void EndpointType:: + setReferred (const ReferredOptional& x) + { + this->referred_ = x; + } + + void EndpointType:: + setReferred (::std::unique_ptr< ReferredType > x) + { + this->referred_.set (std::move (x)); + } + + const EndpointType::StatusOptional& EndpointType:: + getStatus () const + { + return this->status_; + } + + EndpointType::StatusOptional& EndpointType:: + getStatus () + { + return this->status_; + } + + void EndpointType:: + setStatus (const StatusType& x) + { + this->status_.set (x); + } + + void EndpointType:: + setStatus (const StatusOptional& x) + { + this->status_ = x; + } + + void EndpointType:: + setStatus (::std::unique_ptr< StatusType > x) + { + this->status_.set (std::move (x)); + } + + const EndpointType::JoiningMethodOptional& EndpointType:: + getJoiningMethod () const + { + return this->joining_method_; + } + + EndpointType::JoiningMethodOptional& EndpointType:: + getJoiningMethod () + { + return this->joining_method_; + } + + void EndpointType:: + setJoiningMethod (const JoiningMethodType& x) + { + this->joining_method_.set (x); + } + + void EndpointType:: + setJoiningMethod (const JoiningMethodOptional& x) + { + this->joining_method_ = x; + } + + void EndpointType:: + setJoiningMethod (::std::unique_ptr< JoiningMethodType > x) + { + this->joining_method_.set (std::move (x)); + } + + const EndpointType::JoiningInfoOptional& EndpointType:: + getJoiningInfo () const + { + return this->joining_info_; + } + + EndpointType::JoiningInfoOptional& EndpointType:: + getJoiningInfo () + { + return this->joining_info_; + } + + void EndpointType:: + setJoiningInfo (const JoiningInfoType& x) + { + this->joining_info_.set (x); + } + + void EndpointType:: + setJoiningInfo (const JoiningInfoOptional& x) + { + this->joining_info_ = x; + } + + void EndpointType:: + setJoiningInfo (::std::unique_ptr< JoiningInfoType > x) + { + this->joining_info_.set (std::move (x)); + } + + const EndpointType::DisconnectionMethodOptional& EndpointType:: + getDisconnectionMethod () const + { + return this->disconnection_method_; + } + + EndpointType::DisconnectionMethodOptional& EndpointType:: + getDisconnectionMethod () + { + return this->disconnection_method_; + } + + void EndpointType:: + setDisconnectionMethod (const DisconnectionMethodType& x) + { + this->disconnection_method_.set (x); + } + + void EndpointType:: + setDisconnectionMethod (const DisconnectionMethodOptional& x) + { + this->disconnection_method_ = x; + } + + void EndpointType:: + setDisconnectionMethod (::std::unique_ptr< DisconnectionMethodType > x) + { + this->disconnection_method_.set (std::move (x)); + } + + const EndpointType::DisconnectionInfoOptional& EndpointType:: + getDisconnectionInfo () const + { + return this->disconnection_info_; + } + + EndpointType::DisconnectionInfoOptional& EndpointType:: + getDisconnectionInfo () + { + return this->disconnection_info_; + } + + void EndpointType:: + setDisconnectionInfo (const DisconnectionInfoType& x) + { + this->disconnection_info_.set (x); + } + + void EndpointType:: + setDisconnectionInfo (const DisconnectionInfoOptional& x) + { + this->disconnection_info_ = x; + } + + void EndpointType:: + setDisconnectionInfo (::std::unique_ptr< DisconnectionInfoType > x) + { + this->disconnection_info_.set (std::move (x)); + } + + const EndpointType::MediaSequence& EndpointType:: + getMedia () const + { + return this->media_; + } + + EndpointType::MediaSequence& EndpointType:: + getMedia () + { + return this->media_; + } + + void EndpointType:: + setMedia (const MediaSequence& s) + { + this->media_ = s; + } + + const EndpointType::CallInfoOptional& EndpointType:: + getCallInfo () const + { + return this->call_info_; + } + + EndpointType::CallInfoOptional& EndpointType:: + getCallInfo () + { + return this->call_info_; + } + + void EndpointType:: + setCallInfo (const CallInfoType& x) + { + this->call_info_.set (x); + } + + void EndpointType:: + setCallInfo (const CallInfoOptional& x) + { + this->call_info_ = x; + } + + void EndpointType:: + setCallInfo (::std::unique_ptr< CallInfoType > x) + { + this->call_info_.set (std::move (x)); + } + + const EndpointType::AnySequence& EndpointType:: + getAny () const + { + return this->any_; + } + + EndpointType::AnySequence& EndpointType:: + getAny () + { + return this->any_; + } + + void EndpointType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const EndpointType::EntityOptional& EndpointType:: + getEntity () const + { + return this->entity_; + } + + EndpointType::EntityOptional& EndpointType:: + getEntity () + { + return this->entity_; + } + + void EndpointType:: + setEntity (const EntityType& x) + { + this->entity_.set (x); + } + + void EndpointType:: + setEntity (const EntityOptional& x) + { + this->entity_ = x; + } + + void EndpointType:: + setEntity (::std::unique_ptr< EntityType > x) + { + this->entity_.set (std::move (x)); + } + + const EndpointType::StateType& EndpointType:: + getState () const + { + return this->state_.get (); + } + + EndpointType::StateType& EndpointType:: + getState () + { + return this->state_.get (); + } + + void EndpointType:: + setState (const StateType& x) + { + this->state_.set (x); + } + + void EndpointType:: + setState (::std::unique_ptr< StateType > x) + { + this->state_.set (std::move (x)); + } + + ::std::unique_ptr< EndpointType::StateType > EndpointType:: + setDetachState () + { + return this->state_.detach (); + } + + const EndpointType::StateType& EndpointType:: + getStateDefaultValue () + { + return state_default_value_; + } + + const EndpointType::AnyAttributeSet& EndpointType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + EndpointType::AnyAttributeSet& EndpointType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void EndpointType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& EndpointType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& EndpointType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // EndpointStatusType + // + + EndpointStatusType:: + EndpointStatusType (Value v) + : ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_EndpointStatusType_literals_[v]) + { + } + + EndpointStatusType:: + EndpointStatusType (const char* v) + : ::LinphonePrivate::Xsd::XmlSchema::String (v) + { + } + + EndpointStatusType:: + EndpointStatusType (const ::std::string& v) + : ::LinphonePrivate::Xsd::XmlSchema::String (v) + { + } + + EndpointStatusType:: + EndpointStatusType (const ::LinphonePrivate::Xsd::XmlSchema::String& v) + : ::LinphonePrivate::Xsd::XmlSchema::String (v) + { + } + + EndpointStatusType:: + EndpointStatusType (const EndpointStatusType& v, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (v, f, c) + { + } + + EndpointStatusType& EndpointStatusType:: + operator= (Value v) + { + static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = + ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_EndpointStatusType_literals_[v]); + + return *this; + } + + + // JoiningType + // + + JoiningType:: + JoiningType (Value v) + : ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_JoiningType_literals_[v]) + { + } + + JoiningType:: + JoiningType (const char* v) + : ::LinphonePrivate::Xsd::XmlSchema::String (v) + { + } + + JoiningType:: + JoiningType (const ::std::string& v) + : ::LinphonePrivate::Xsd::XmlSchema::String (v) + { + } + + JoiningType:: + JoiningType (const ::LinphonePrivate::Xsd::XmlSchema::String& v) + : ::LinphonePrivate::Xsd::XmlSchema::String (v) + { + } + + JoiningType:: + JoiningType (const JoiningType& v, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (v, f, c) + { + } + + JoiningType& JoiningType:: + operator= (Value v) + { + static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = + ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_JoiningType_literals_[v]); + + return *this; + } + + + // DisconnectionType + // + + DisconnectionType:: + DisconnectionType (Value v) + : ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_DisconnectionType_literals_[v]) + { + } + + DisconnectionType:: + DisconnectionType (const char* v) + : ::LinphonePrivate::Xsd::XmlSchema::String (v) + { + } + + DisconnectionType:: + DisconnectionType (const ::std::string& v) + : ::LinphonePrivate::Xsd::XmlSchema::String (v) + { + } + + DisconnectionType:: + DisconnectionType (const ::LinphonePrivate::Xsd::XmlSchema::String& v) + : ::LinphonePrivate::Xsd::XmlSchema::String (v) + { + } + + DisconnectionType:: + DisconnectionType (const DisconnectionType& v, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (v, f, c) + { + } + + DisconnectionType& DisconnectionType:: + operator= (Value v) + { + static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = + ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_DisconnectionType_literals_[v]); + + return *this; + } + + + // ExecutionType + // + + const ExecutionType::WhenOptional& ExecutionType:: + getWhen () const + { + return this->when_; + } + + ExecutionType::WhenOptional& ExecutionType:: + getWhen () + { + return this->when_; + } + + void ExecutionType:: + setWhen (const WhenType& x) + { + this->when_.set (x); + } + + void ExecutionType:: + setWhen (const WhenOptional& x) + { + this->when_ = x; + } + + void ExecutionType:: + setWhen (::std::unique_ptr< WhenType > x) + { + this->when_.set (std::move (x)); + } + + const ExecutionType::ReasonOptional& ExecutionType:: + getReason () const + { + return this->reason_; + } + + ExecutionType::ReasonOptional& ExecutionType:: + getReason () + { + return this->reason_; + } + + void ExecutionType:: + setReason (const ReasonType& x) + { + this->reason_.set (x); + } + + void ExecutionType:: + setReason (const ReasonOptional& x) + { + this->reason_ = x; + } + + void ExecutionType:: + setReason (::std::unique_ptr< ReasonType > x) + { + this->reason_.set (std::move (x)); + } + + const ExecutionType::ByOptional& ExecutionType:: + getBy () const + { + return this->by_; + } + + ExecutionType::ByOptional& ExecutionType:: + getBy () + { + return this->by_; + } + + void ExecutionType:: + setBy (const ByType& x) + { + this->by_.set (x); + } + + void ExecutionType:: + setBy (const ByOptional& x) + { + this->by_ = x; + } + + void ExecutionType:: + setBy (::std::unique_ptr< ByType > x) + { + this->by_.set (std::move (x)); + } + + const ExecutionType::AnyAttributeSet& ExecutionType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + ExecutionType::AnyAttributeSet& ExecutionType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void ExecutionType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& ExecutionType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& ExecutionType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // CallType + // + + const CallType::SipOptional& CallType:: + getSip () const + { + return this->sip_; + } + + CallType::SipOptional& CallType:: + getSip () + { + return this->sip_; + } + + void CallType:: + setSip (const SipType& x) + { + this->sip_.set (x); + } + + void CallType:: + setSip (const SipOptional& x) + { + this->sip_ = x; + } + + void CallType:: + setSip (::std::unique_ptr< SipType > x) + { + this->sip_.set (std::move (x)); + } + + const CallType::AnySequence& CallType:: + getAny () const + { + return this->any_; + } + + CallType::AnySequence& CallType:: + getAny () + { + return this->any_; + } + + void CallType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const CallType::AnyAttributeSet& CallType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + CallType::AnyAttributeSet& CallType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void CallType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& CallType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& CallType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // SipDialogIdType + // + + const SipDialogIdType::DisplayTextOptional& SipDialogIdType:: + getDisplayText () const + { + return this->display_text_; + } + + SipDialogIdType::DisplayTextOptional& SipDialogIdType:: + getDisplayText () + { + return this->display_text_; + } + + void SipDialogIdType:: + setDisplayText (const DisplayTextType& x) + { + this->display_text_.set (x); + } + + void SipDialogIdType:: + setDisplayText (const DisplayTextOptional& x) + { + this->display_text_ = x; + } + + void SipDialogIdType:: + setDisplayText (::std::unique_ptr< DisplayTextType > x) + { + this->display_text_.set (std::move (x)); + } + + const SipDialogIdType::CallIdType& SipDialogIdType:: + getCallId () const + { + return this->call_id_.get (); + } + + SipDialogIdType::CallIdType& SipDialogIdType:: + getCallId () + { + return this->call_id_.get (); + } + + void SipDialogIdType:: + setCallId (const CallIdType& x) + { + this->call_id_.set (x); + } + + void SipDialogIdType:: + setCallId (::std::unique_ptr< CallIdType > x) + { + this->call_id_.set (std::move (x)); + } + + ::std::unique_ptr< SipDialogIdType::CallIdType > SipDialogIdType:: + setDetachCall_id () + { + return this->call_id_.detach (); + } + + const SipDialogIdType::FromTagType& SipDialogIdType:: + getFromTag () const + { + return this->from_tag_.get (); + } + + SipDialogIdType::FromTagType& SipDialogIdType:: + getFromTag () + { + return this->from_tag_.get (); + } + + void SipDialogIdType:: + setFromTag (const FromTagType& x) + { + this->from_tag_.set (x); + } + + void SipDialogIdType:: + setFromTag (::std::unique_ptr< FromTagType > x) + { + this->from_tag_.set (std::move (x)); + } + + ::std::unique_ptr< SipDialogIdType::FromTagType > SipDialogIdType:: + setDetachFrom_tag () + { + return this->from_tag_.detach (); + } + + const SipDialogIdType::ToTagType& SipDialogIdType:: + getToTag () const + { + return this->to_tag_.get (); + } + + SipDialogIdType::ToTagType& SipDialogIdType:: + getToTag () + { + return this->to_tag_.get (); + } + + void SipDialogIdType:: + setToTag (const ToTagType& x) + { + this->to_tag_.set (x); + } + + void SipDialogIdType:: + setToTag (::std::unique_ptr< ToTagType > x) + { + this->to_tag_.set (std::move (x)); + } + + ::std::unique_ptr< SipDialogIdType::ToTagType > SipDialogIdType:: + setDetachTo_tag () + { + return this->to_tag_.detach (); + } + + const SipDialogIdType::AnySequence& SipDialogIdType:: + getAny () const + { + return this->any_; + } + + SipDialogIdType::AnySequence& SipDialogIdType:: + getAny () + { + return this->any_; + } + + void SipDialogIdType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const SipDialogIdType::AnyAttributeSet& SipDialogIdType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + SipDialogIdType::AnyAttributeSet& SipDialogIdType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void SipDialogIdType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& SipDialogIdType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& SipDialogIdType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // MediaType + // + + const MediaType::DisplayTextOptional& MediaType:: + getDisplayText () const + { + return this->display_text_; + } + + MediaType::DisplayTextOptional& MediaType:: + getDisplayText () + { + return this->display_text_; + } + + void MediaType:: + setDisplayText (const DisplayTextType& x) + { + this->display_text_.set (x); + } + + void MediaType:: + setDisplayText (const DisplayTextOptional& x) + { + this->display_text_ = x; + } + + void MediaType:: + setDisplayText (::std::unique_ptr< DisplayTextType > x) + { + this->display_text_.set (std::move (x)); + } + + const MediaType::TypeOptional& MediaType:: + getType () const + { + return this->type_; + } + + MediaType::TypeOptional& MediaType:: + getType () + { + return this->type_; + } + + void MediaType:: + setType (const TypeType& x) + { + this->type_.set (x); + } + + void MediaType:: + setType (const TypeOptional& x) + { + this->type_ = x; + } + + void MediaType:: + setType (::std::unique_ptr< TypeType > x) + { + this->type_.set (std::move (x)); + } + + const MediaType::LabelOptional& MediaType:: + getLabel () const + { + return this->label_; + } + + MediaType::LabelOptional& MediaType:: + getLabel () + { + return this->label_; + } + + void MediaType:: + setLabel (const LabelType& x) + { + this->label_.set (x); + } + + void MediaType:: + setLabel (const LabelOptional& x) + { + this->label_ = x; + } + + void MediaType:: + setLabel (::std::unique_ptr< LabelType > x) + { + this->label_.set (std::move (x)); + } + + const MediaType::SrcIdOptional& MediaType:: + getSrcId () const + { + return this->src_id_; + } + + MediaType::SrcIdOptional& MediaType:: + getSrcId () + { + return this->src_id_; + } + + void MediaType:: + setSrcId (const SrcIdType& x) + { + this->src_id_.set (x); + } + + void MediaType:: + setSrcId (const SrcIdOptional& x) + { + this->src_id_ = x; + } + + void MediaType:: + setSrcId (::std::unique_ptr< SrcIdType > x) + { + this->src_id_.set (std::move (x)); + } + + const MediaType::StatusOptional& MediaType:: + getStatus () const + { + return this->status_; + } + + MediaType::StatusOptional& MediaType:: + getStatus () + { + return this->status_; + } + + void MediaType:: + setStatus (const StatusType& x) + { + this->status_.set (x); + } + + void MediaType:: + setStatus (const StatusOptional& x) + { + this->status_ = x; + } + + void MediaType:: + setStatus (::std::unique_ptr< StatusType > x) + { + this->status_.set (std::move (x)); + } + + const MediaType::AnySequence& MediaType:: + getAny () const + { + return this->any_; + } + + MediaType::AnySequence& MediaType:: + getAny () + { + return this->any_; + } + + void MediaType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const MediaType::IdType& MediaType:: + getId () const + { + return this->id_.get (); + } + + MediaType::IdType& MediaType:: + getId () + { + return this->id_.get (); + } + + void MediaType:: + setId (const IdType& x) + { + this->id_.set (x); + } + + void MediaType:: + setId (::std::unique_ptr< IdType > x) + { + this->id_.set (std::move (x)); + } + + ::std::unique_ptr< MediaType::IdType > MediaType:: + setDetachId () + { + return this->id_.detach (); + } + + const MediaType::AnyAttributeSet& MediaType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + MediaType::AnyAttributeSet& MediaType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void MediaType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& MediaType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& MediaType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // MediaStatusType + // + + MediaStatusType:: + MediaStatusType (Value v) + : ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_MediaStatusType_literals_[v]) + { + } + + MediaStatusType:: + MediaStatusType (const char* v) + : ::LinphonePrivate::Xsd::XmlSchema::String (v) + { + } + + MediaStatusType:: + MediaStatusType (const ::std::string& v) + : ::LinphonePrivate::Xsd::XmlSchema::String (v) + { + } + + MediaStatusType:: + MediaStatusType (const ::LinphonePrivate::Xsd::XmlSchema::String& v) + : ::LinphonePrivate::Xsd::XmlSchema::String (v) + { + } + + MediaStatusType:: + MediaStatusType (const MediaStatusType& v, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (v, f, c) + { + } + + MediaStatusType& MediaStatusType:: + operator= (Value v) + { + static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = + ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_MediaStatusType_literals_[v]); + + return *this; + } + + + // SidebarsByValType + // + + const SidebarsByValType::EntrySequence& SidebarsByValType:: + getEntry () const + { + return this->entry_; + } + + SidebarsByValType::EntrySequence& SidebarsByValType:: + getEntry () + { + return this->entry_; + } + + void SidebarsByValType:: + setEntry (const EntrySequence& s) + { + this->entry_ = s; + } + + const SidebarsByValType::StateType& SidebarsByValType:: + getState () const + { + return this->state_.get (); + } + + SidebarsByValType::StateType& SidebarsByValType:: + getState () + { + return this->state_.get (); + } + + void SidebarsByValType:: + setState (const StateType& x) + { + this->state_.set (x); + } + + void SidebarsByValType:: + setState (::std::unique_ptr< StateType > x) + { + this->state_.set (std::move (x)); + } + + ::std::unique_ptr< SidebarsByValType::StateType > SidebarsByValType:: + setDetachState () + { + return this->state_.detach (); + } + + const SidebarsByValType::StateType& SidebarsByValType:: + getStateDefaultValue () + { + return state_default_value_; + } + + const SidebarsByValType::AnyAttributeSet& SidebarsByValType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + SidebarsByValType::AnyAttributeSet& SidebarsByValType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void SidebarsByValType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& SidebarsByValType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& SidebarsByValType:: + getDomDocument () + { + return *this->dom_document_; + } + } } } @@ -3201,4063 +3205,4075 @@ namespace conference_info #include -namespace conference_info +namespace LinphonePrivate { - // Conference_type - // - - const Conference_type::StateType Conference_type::state_default_value_ ( - "full"); - - Conference_type:: - Conference_type (const EntityType& entity) - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - conference_description_ (this), - host_info_ (this), - conference_state_ (this), - users_ (this), - sidebars_by_ref_ (this), - sidebars_by_val_ (this), - any_ (this->getDomDocument ()), - entity_ (entity, this), - state_ (getStateDefaultValue (), this), - version_ (this), - any_attribute_ (this->getDomDocument ()) + namespace Xsd { - } - - Conference_type:: - Conference_type (const Conference_type& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - conference_description_ (x.conference_description_, f, this), - host_info_ (x.host_info_, f, this), - conference_state_ (x.conference_state_, f, this), - users_ (x.users_, f, this), - sidebars_by_ref_ (x.sidebars_by_ref_, f, this), - sidebars_by_val_ (x.sidebars_by_val_, f, this), - any_ (x.any_, this->getDomDocument ()), - entity_ (x.entity_, f, this), - state_ (x.state_, f, this), - version_ (x.version_, f, this), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - Conference_type:: - Conference_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - conference_description_ (this), - host_info_ (this), - conference_state_ (this), - users_ (this), - sidebars_by_ref_ (this), - sidebars_by_val_ (this), - any_ (this->getDomDocument ()), - entity_ (this), - state_ (this), - version_ (this), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) + namespace ConferenceInfo { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void Conference_type:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // conference-description + // ConferenceType // - if (n.name () == "conference-description" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< Conference_descriptionType > r ( - Conference_descriptionTraits::create (i, f, this)); - if (!this->conference_description_) + const ConferenceType::StateType ConferenceType::state_default_value_ ( + "full"); + + ConferenceType:: + ConferenceType (const EntityType& entity) + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + conference_description_ (this), + host_info_ (this), + conference_state_ (this), + users_ (this), + sidebars_by_ref_ (this), + sidebars_by_val_ (this), + any_ (this->getDomDocument ()), + entity_ (entity, this), + state_ (getStateDefaultValue (), this), + version_ (this), + any_attribute_ (this->getDomDocument ()) + { + } + + ConferenceType:: + ConferenceType (const ConferenceType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + conference_description_ (x.conference_description_, f, this), + host_info_ (x.host_info_, f, this), + conference_state_ (x.conference_state_, f, this), + users_ (x.users_, f, this), + sidebars_by_ref_ (x.sidebars_by_ref_, f, this), + sidebars_by_val_ (x.sidebars_by_val_, f, this), + any_ (x.any_, this->getDomDocument ()), + entity_ (x.entity_, f, this), + state_ (x.state_, f, this), + version_ (x.version_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + ConferenceType:: + ConferenceType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + conference_description_ (this), + host_info_ (this), + conference_state_ (this), + users_ (this), + sidebars_by_ref_ (this), + sidebars_by_val_ (this), + any_ (this->getDomDocument ()), + entity_ (this), + state_ (this), + version_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) { - this->conference_description_.set (::std::move (r)); - continue; + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); } } - // host-info - // - if (n.name () == "host-info" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + void ConferenceType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) { - ::std::unique_ptr< Host_infoType > r ( - Host_infoTraits::create (i, f, this)); - - if (!this->host_info_) + for (; p.more_content (); p.next_content (false)) { - this->host_info_.set (::std::move (r)); - continue; + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // conference-description + // + if (n.name () == "conference-description" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< ConferenceDescriptionType > r ( + ConferenceDescriptionTraits::create (i, f, this)); + + if (!this->conference_description_) + { + this->conference_description_.set (::std::move (r)); + continue; + } + } + + // host-info + // + if (n.name () == "host-info" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< HostInfoType > r ( + HostInfoTraits::create (i, f, this)); + + if (!this->host_info_) + { + this->host_info_.set (::std::move (r)); + continue; + } + } + + // conference-state + // + if (n.name () == "conference-state" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< ConferenceStateType > r ( + ConferenceStateTraits::create (i, f, this)); + + if (!this->conference_state_) + { + this->conference_state_.set (::std::move (r)); + continue; + } + } + + // users + // + if (n.name () == "users" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< UsersType > r ( + UsersTraits::create (i, f, this)); + + if (!this->users_) + { + this->users_.set (::std::move (r)); + continue; + } + } + + // sidebars-by-ref + // + if (n.name () == "sidebars-by-ref" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< SidebarsByRefType > r ( + SidebarsByRefTraits::create (i, f, this)); + + if (!this->sidebars_by_ref_) + { + this->sidebars_by_ref_.set (::std::move (r)); + continue; + } + } + + // sidebars-by-val + // + if (n.name () == "sidebars-by-val" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< SidebarsByValType > r ( + SidebarsByValTraits::create (i, f, this)); + + if (!this->sidebars_by_val_) + { + this->sidebars_by_val_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "entity" && n.namespace_ ().empty ()) + { + this->entity_.set (EntityTraits::create (i, f, this)); + continue; + } + + if (n.name () == "state" && n.namespace_ ().empty ()) + { + this->state_.set (StateTraits::create (i, f, this)); + continue; + } + + if (n.name () == "version" && n.namespace_ ().empty ()) + { + this->version_.set (VersionTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + + if (!entity_.present ()) + { + throw ::xsd::cxx::tree::expected_attribute< char > ( + "entity", + ""); + } + + if (!state_.present ()) + { + this->state_.set (getStateDefaultValue ()); } } - // conference-state - // - if (n.name () == "conference-state" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + ConferenceType* ConferenceType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const { - ::std::unique_ptr< Conference_stateType > r ( - Conference_stateTraits::create (i, f, this)); + return new class ConferenceType (*this, f, c); + } - if (!this->conference_state_) + ConferenceType& ConferenceType:: + operator= (const ConferenceType& x) + { + if (this != &x) { - this->conference_state_.set (::std::move (r)); - continue; + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->conference_description_ = x.conference_description_; + this->host_info_ = x.host_info_; + this->conference_state_ = x.conference_state_; + this->users_ = x.users_; + this->sidebars_by_ref_ = x.sidebars_by_ref_; + this->sidebars_by_val_ = x.sidebars_by_val_; + this->any_ = x.any_; + this->entity_ = x.entity_; + this->state_ = x.state_; + this->version_ = x.version_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + ConferenceType:: + ~ConferenceType () + { + } + + // StateType + // + + StateType:: + StateType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (e, f, c) + { + _xsd_StateType_convert (); + } + + StateType:: + StateType (const ::xercesc::DOMAttr& a, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (a, f, c) + { + _xsd_StateType_convert (); + } + + StateType:: + StateType (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (s, e, f, c) + { + _xsd_StateType_convert (); + } + + StateType* StateType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class StateType (*this, f, c); + } + + StateType::Value StateType:: + _xsd_StateType_convert () const + { + ::xsd::cxx::tree::enum_comparator< char > c (_xsd_StateType_literals_); + const Value* i (::std::lower_bound ( + _xsd_StateType_indexes_, + _xsd_StateType_indexes_ + 3, + *this, + c)); + + if (i == _xsd_StateType_indexes_ + 3 || _xsd_StateType_literals_[*i] != *this) + { + throw ::xsd::cxx::tree::unexpected_enumerator < char > (*this); + } + + return *i; + } + + const char* const StateType:: + _xsd_StateType_literals_[3] = + { + "full", + "partial", + "deleted" + }; + + const StateType::Value StateType:: + _xsd_StateType_indexes_[3] = + { + ::LinphonePrivate::Xsd::ConferenceInfo::StateType::deleted, + ::LinphonePrivate::Xsd::ConferenceInfo::StateType::full, + ::LinphonePrivate::Xsd::ConferenceInfo::StateType::partial + }; + + // ConferenceDescriptionType + // + + ConferenceDescriptionType:: + ConferenceDescriptionType () + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + subject_ (this), + free_text_ (this), + keywords_ (this), + conf_uris_ (this), + service_uris_ (this), + maximum_user_count_ (this), + available_media_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + } + + ConferenceDescriptionType:: + ConferenceDescriptionType (const ConferenceDescriptionType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (x.display_text_, f, this), + subject_ (x.subject_, f, this), + free_text_ (x.free_text_, f, this), + keywords_ (x.keywords_, f, this), + conf_uris_ (x.conf_uris_, f, this), + service_uris_ (x.service_uris_, f, this), + maximum_user_count_ (x.maximum_user_count_, f, this), + available_media_ (x.available_media_, f, this), + any_ (x.any_, this->getDomDocument ()), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + ConferenceDescriptionType:: + ConferenceDescriptionType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + subject_ (this), + free_text_ (this), + keywords_ (this), + conf_uris_ (this), + service_uris_ (this), + maximum_user_count_ (this), + available_media_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); } } - // users - // - if (n.name () == "users" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + void ConferenceDescriptionType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) { - ::std::unique_ptr< UsersType > r ( - UsersTraits::create (i, f, this)); - - if (!this->users_) + for (; p.more_content (); p.next_content (false)) { - this->users_.set (::std::move (r)); - continue; + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-text + // + if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< DisplayTextType > r ( + DisplayTextTraits::create (i, f, this)); + + if (!this->display_text_) + { + this->display_text_.set (::std::move (r)); + continue; + } + } + + // subject + // + if (n.name () == "subject" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< SubjectType > r ( + SubjectTraits::create (i, f, this)); + + if (!this->subject_) + { + this->subject_.set (::std::move (r)); + continue; + } + } + + // free-text + // + if (n.name () == "free-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< FreeTextType > r ( + FreeTextTraits::create (i, f, this)); + + if (!this->free_text_) + { + this->free_text_.set (::std::move (r)); + continue; + } + } + + // keywords + // + if (n.name () == "keywords" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< KeywordsType > r ( + KeywordsTraits::create (i, f, this)); + + if (!this->keywords_) + { + this->keywords_.set (::std::move (r)); + continue; + } + } + + // conf-uris + // + if (n.name () == "conf-uris" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< ConfUrisType > r ( + ConfUrisTraits::create (i, f, this)); + + if (!this->conf_uris_) + { + this->conf_uris_.set (::std::move (r)); + continue; + } + } + + // service-uris + // + if (n.name () == "service-uris" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< ServiceUrisType > r ( + ServiceUrisTraits::create (i, f, this)); + + if (!this->service_uris_) + { + this->service_uris_.set (::std::move (r)); + continue; + } + } + + // maximum-user-count + // + if (n.name () == "maximum-user-count" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + if (!this->maximum_user_count_) + { + this->maximum_user_count_.set (MaximumUserCountTraits::create (i, f, this)); + continue; + } + } + + // available-media + // + if (n.name () == "available-media" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< AvailableMediaType > r ( + AvailableMediaTraits::create (i, f, this)); + + if (!this->available_media_) + { + this->available_media_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } } } - // sidebars-by-ref - // - if (n.name () == "sidebars-by-ref" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + ConferenceDescriptionType* ConferenceDescriptionType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const { - ::std::unique_ptr< Sidebars_by_refType > r ( - Sidebars_by_refTraits::create (i, f, this)); + return new class ConferenceDescriptionType (*this, f, c); + } - if (!this->sidebars_by_ref_) + ConferenceDescriptionType& ConferenceDescriptionType:: + operator= (const ConferenceDescriptionType& x) + { + if (this != &x) { - this->sidebars_by_ref_.set (::std::move (r)); - continue; + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->display_text_ = x.display_text_; + this->subject_ = x.subject_; + this->free_text_ = x.free_text_; + this->keywords_ = x.keywords_; + this->conf_uris_ = x.conf_uris_; + this->service_uris_ = x.service_uris_; + this->maximum_user_count_ = x.maximum_user_count_; + this->available_media_ = x.available_media_; + this->any_ = x.any_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + ConferenceDescriptionType:: + ~ConferenceDescriptionType () + { + } + + // HostType + // + + HostType:: + HostType () + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + web_page_ (this), + uris_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + } + + HostType:: + HostType (const HostType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (x.display_text_, f, this), + web_page_ (x.web_page_, f, this), + uris_ (x.uris_, f, this), + any_ (x.any_, this->getDomDocument ()), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + HostType:: + HostType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + web_page_ (this), + uris_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); } } - // sidebars-by-val - // - if (n.name () == "sidebars-by-val" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + void HostType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) { - ::std::unique_ptr< Sidebars_by_valType > r ( - Sidebars_by_valTraits::create (i, f, this)); - - if (!this->sidebars_by_val_) + for (; p.more_content (); p.next_content (false)) { - this->sidebars_by_val_.set (::std::move (r)); - continue; + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-text + // + if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< DisplayTextType > r ( + DisplayTextTraits::create (i, f, this)); + + if (!this->display_text_) + { + this->display_text_.set (::std::move (r)); + continue; + } + } + + // web-page + // + if (n.name () == "web-page" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< WebPageType > r ( + WebPageTraits::create (i, f, this)); + + if (!this->web_page_) + { + this->web_page_.set (::std::move (r)); + continue; + } + } + + // uris + // + if (n.name () == "uris" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< UrisType > r ( + UrisTraits::create (i, f, this)); + + if (!this->uris_) + { + this->uris_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } } } - // any - // - if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + HostType* HostType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const { - ::xercesc::DOMElement* r ( - static_cast< ::xercesc::DOMElement* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMElement* > (&i), true))); - this->any_.push_back (r); - continue; + return new class HostType (*this, f, c); } - break; - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - if (n.name () == "entity" && n.namespace_ ().empty ()) + HostType& HostType:: + operator= (const HostType& x) { - this->entity_.set (EntityTraits::create (i, f, this)); - continue; - } - - if (n.name () == "state" && n.namespace_ ().empty ()) - { - this->state_.set (StateTraits::create (i, f, this)); - continue; - } - - if (n.name () == "version" && n.namespace_ ().empty ()) - { - this->version_.set (VersionTraits::create (i, f, this)); - continue; - } - - // any_attribute - // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) - { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; - } - } - - if (!entity_.present ()) - { - throw ::xsd::cxx::tree::expected_attribute< char > ( - "entity", - ""); - } - - if (!state_.present ()) - { - this->state_.set (getStateDefaultValue ()); - } - } - - Conference_type* Conference_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Conference_type (*this, f, c); - } - - Conference_type& Conference_type:: - operator= (const Conference_type& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->conference_description_ = x.conference_description_; - this->host_info_ = x.host_info_; - this->conference_state_ = x.conference_state_; - this->users_ = x.users_; - this->sidebars_by_ref_ = x.sidebars_by_ref_; - this->sidebars_by_val_ = x.sidebars_by_val_; - this->any_ = x.any_; - this->entity_ = x.entity_; - this->state_ = x.state_; - this->version_ = x.version_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - Conference_type:: - ~Conference_type () - { - } - - // State_type - // - - State_type:: - State_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (e, f, c) - { - _xsd_State_type_convert (); - } - - State_type:: - State_type (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (a, f, c) - { - _xsd_State_type_convert (); - } - - State_type:: - State_type (const ::std::string& s, - const ::xercesc::DOMElement* e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (s, e, f, c) - { - _xsd_State_type_convert (); - } - - State_type* State_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class State_type (*this, f, c); - } - - State_type::Value State_type:: - _xsd_State_type_convert () const - { - ::xsd::cxx::tree::enum_comparator< char > c (_xsd_State_type_literals_); - const Value* i (::std::lower_bound ( - _xsd_State_type_indexes_, - _xsd_State_type_indexes_ + 3, - *this, - c)); - - if (i == _xsd_State_type_indexes_ + 3 || _xsd_State_type_literals_[*i] != *this) - { - throw ::xsd::cxx::tree::unexpected_enumerator < char > (*this); - } - - return *i; - } - - const char* const State_type:: - _xsd_State_type_literals_[3] = - { - "full", - "partial", - "deleted" - }; - - const State_type::Value State_type:: - _xsd_State_type_indexes_[3] = - { - ::conference_info::State_type::deleted, - ::conference_info::State_type::full, - ::conference_info::State_type::partial - }; - - // Conference_description_type - // - - Conference_description_type:: - Conference_description_type () - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (this), - subject_ (this), - free_text_ (this), - keywords_ (this), - conf_uris_ (this), - service_uris_ (this), - maximum_user_count_ (this), - available_media_ (this), - any_ (this->getDomDocument ()), - any_attribute_ (this->getDomDocument ()) - { - } - - Conference_description_type:: - Conference_description_type (const Conference_description_type& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (x.display_text_, f, this), - subject_ (x.subject_, f, this), - free_text_ (x.free_text_, f, this), - keywords_ (x.keywords_, f, this), - conf_uris_ (x.conf_uris_, f, this), - service_uris_ (x.service_uris_, f, this), - maximum_user_count_ (x.maximum_user_count_, f, this), - available_media_ (x.available_media_, f, this), - any_ (x.any_, this->getDomDocument ()), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - Conference_description_type:: - Conference_description_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (this), - subject_ (this), - free_text_ (this), - keywords_ (this), - conf_uris_ (this), - service_uris_ (this), - maximum_user_count_ (this), - available_media_ (this), - any_ (this->getDomDocument ()), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void Conference_description_type:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // display-text - // - if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< Display_textType > r ( - Display_textTraits::create (i, f, this)); - - if (!this->display_text_) + if (this != &x) { - this->display_text_.set (::std::move (r)); - continue; + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->display_text_ = x.display_text_; + this->web_page_ = x.web_page_; + this->uris_ = x.uris_; + this->any_ = x.any_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + HostType:: + ~HostType () + { + } + + // ConferenceStateType + // + + ConferenceStateType:: + ConferenceStateType () + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + user_count_ (this), + active_ (this), + locked_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + } + + ConferenceStateType:: + ConferenceStateType (const ConferenceStateType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + user_count_ (x.user_count_, f, this), + active_ (x.active_, f, this), + locked_ (x.locked_, f, this), + any_ (x.any_, this->getDomDocument ()), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + ConferenceStateType:: + ConferenceStateType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + user_count_ (this), + active_ (this), + locked_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); } } - // subject - // - if (n.name () == "subject" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + void ConferenceStateType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) { - ::std::unique_ptr< SubjectType > r ( - SubjectTraits::create (i, f, this)); - - if (!this->subject_) + for (; p.more_content (); p.next_content (false)) { - this->subject_.set (::std::move (r)); - continue; + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // user-count + // + if (n.name () == "user-count" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + if (!this->user_count_) + { + this->user_count_.set (UserCountTraits::create (i, f, this)); + continue; + } + } + + // active + // + if (n.name () == "active" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + if (!this->active_) + { + this->active_.set (ActiveTraits::create (i, f, this)); + continue; + } + } + + // locked + // + if (n.name () == "locked" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + if (!this->locked_) + { + this->locked_.set (LockedTraits::create (i, f, this)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } } } - // free-text - // - if (n.name () == "free-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + ConferenceStateType* ConferenceStateType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const { - ::std::unique_ptr< Free_textType > r ( - Free_textTraits::create (i, f, this)); + return new class ConferenceStateType (*this, f, c); + } - if (!this->free_text_) + ConferenceStateType& ConferenceStateType:: + operator= (const ConferenceStateType& x) + { + if (this != &x) { - this->free_text_.set (::std::move (r)); - continue; + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->user_count_ = x.user_count_; + this->active_ = x.active_; + this->locked_ = x.locked_; + this->any_ = x.any_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + ConferenceStateType:: + ~ConferenceStateType () + { + } + + // ConferenceMediaType + // + + ConferenceMediaType:: + ConferenceMediaType () + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (this), + any_attribute_ (this->getDomDocument ()) + { + } + + ConferenceMediaType:: + ConferenceMediaType (const ConferenceMediaType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (x.entry_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + ConferenceMediaType:: + ConferenceMediaType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); } } - // keywords - // - if (n.name () == "keywords" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + void ConferenceMediaType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) { - ::std::unique_ptr< KeywordsType > r ( - KeywordsTraits::create (i, f, this)); - - if (!this->keywords_) + for (; p.more_content (); p.next_content (false)) { - this->keywords_.set (::std::move (r)); - continue; + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // entry + // + if (n.name () == "entry" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< EntryType > r ( + EntryTraits::create (i, f, this)); + + this->entry_.push_back (::std::move (r)); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } } } - // conf-uris - // - if (n.name () == "conf-uris" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + ConferenceMediaType* ConferenceMediaType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const { - ::std::unique_ptr< Conf_urisType > r ( - Conf_urisTraits::create (i, f, this)); + return new class ConferenceMediaType (*this, f, c); + } - if (!this->conf_uris_) + ConferenceMediaType& ConferenceMediaType:: + operator= (const ConferenceMediaType& x) + { + if (this != &x) { - this->conf_uris_.set (::std::move (r)); - continue; + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->entry_ = x.entry_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + ConferenceMediaType:: + ~ConferenceMediaType () + { + } + + // ConferenceMediumType + // + + ConferenceMediumType:: + ConferenceMediumType (const TypeType& type, + const LabelType& label) + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + type_ (type, this), + status_ (this), + any_ (this->getDomDocument ()), + label_ (label, this), + any_attribute_ (this->getDomDocument ()) + { + } + + ConferenceMediumType:: + ConferenceMediumType (const ConferenceMediumType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (x.display_text_, f, this), + type_ (x.type_, f, this), + status_ (x.status_, f, this), + any_ (x.any_, this->getDomDocument ()), + label_ (x.label_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + ConferenceMediumType:: + ConferenceMediumType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + type_ (this), + status_ (this), + any_ (this->getDomDocument ()), + label_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); } } - // service-uris - // - if (n.name () == "service-uris" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + void ConferenceMediumType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) { - ::std::unique_ptr< Service_urisType > r ( - Service_urisTraits::create (i, f, this)); - - if (!this->service_uris_) + for (; p.more_content (); p.next_content (false)) { - this->service_uris_.set (::std::move (r)); - continue; + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-text + // + if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< DisplayTextType > r ( + DisplayTextTraits::create (i, f, this)); + + if (!this->display_text_) + { + this->display_text_.set (::std::move (r)); + continue; + } + } + + // type + // + if (n.name () == "type" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< TypeType > r ( + TypeTraits::create (i, f, this)); + + if (!type_.present ()) + { + this->type_.set (::std::move (r)); + continue; + } + } + + // status + // + if (n.name () == "status" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< StatusType > r ( + StatusTraits::create (i, f, this)); + + if (!this->status_) + { + this->status_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; } - } - - // maximum-user-count - // - if (n.name () == "maximum-user-count" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - if (!this->maximum_user_count_) - { - this->maximum_user_count_.set (Maximum_user_countTraits::create (i, f, this)); - continue; - } - } - - // available-media - // - if (n.name () == "available-media" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< Available_mediaType > r ( - Available_mediaTraits::create (i, f, this)); - - if (!this->available_media_) - { - this->available_media_.set (::std::move (r)); - continue; - } - } - - // any - // - if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) - { - ::xercesc::DOMElement* r ( - static_cast< ::xercesc::DOMElement* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMElement* > (&i), true))); - this->any_.push_back (r); - continue; - } - - break; - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // any_attribute - // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) - { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; - } - } - } - - Conference_description_type* Conference_description_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Conference_description_type (*this, f, c); - } - - Conference_description_type& Conference_description_type:: - operator= (const Conference_description_type& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->display_text_ = x.display_text_; - this->subject_ = x.subject_; - this->free_text_ = x.free_text_; - this->keywords_ = x.keywords_; - this->conf_uris_ = x.conf_uris_; - this->service_uris_ = x.service_uris_; - this->maximum_user_count_ = x.maximum_user_count_; - this->available_media_ = x.available_media_; - this->any_ = x.any_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - Conference_description_type:: - ~Conference_description_type () - { - } - - // Host_type - // - - Host_type:: - Host_type () - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (this), - web_page_ (this), - uris_ (this), - any_ (this->getDomDocument ()), - any_attribute_ (this->getDomDocument ()) - { - } - - Host_type:: - Host_type (const Host_type& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (x.display_text_, f, this), - web_page_ (x.web_page_, f, this), - uris_ (x.uris_, f, this), - any_ (x.any_, this->getDomDocument ()), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - Host_type:: - Host_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (this), - web_page_ (this), - uris_ (this), - any_ (this->getDomDocument ()), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void Host_type:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // display-text - // - if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< Display_textType > r ( - Display_textTraits::create (i, f, this)); - - if (!this->display_text_) - { - this->display_text_.set (::std::move (r)); - continue; - } - } - - // web-page - // - if (n.name () == "web-page" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< Web_pageType > r ( - Web_pageTraits::create (i, f, this)); - - if (!this->web_page_) - { - this->web_page_.set (::std::move (r)); - continue; - } - } - - // uris - // - if (n.name () == "uris" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< UrisType > r ( - UrisTraits::create (i, f, this)); - - if (!this->uris_) - { - this->uris_.set (::std::move (r)); - continue; - } - } - - // any - // - if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) - { - ::xercesc::DOMElement* r ( - static_cast< ::xercesc::DOMElement* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMElement* > (&i), true))); - this->any_.push_back (r); - continue; - } - - break; - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // any_attribute - // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) - { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; - } - } - } - - Host_type* Host_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Host_type (*this, f, c); - } - - Host_type& Host_type:: - operator= (const Host_type& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->display_text_ = x.display_text_; - this->web_page_ = x.web_page_; - this->uris_ = x.uris_; - this->any_ = x.any_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - Host_type:: - ~Host_type () - { - } - - // Conference_state_type - // - - Conference_state_type:: - Conference_state_type () - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - user_count_ (this), - active_ (this), - locked_ (this), - any_ (this->getDomDocument ()), - any_attribute_ (this->getDomDocument ()) - { - } - - Conference_state_type:: - Conference_state_type (const Conference_state_type& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - user_count_ (x.user_count_, f, this), - active_ (x.active_, f, this), - locked_ (x.locked_, f, this), - any_ (x.any_, this->getDomDocument ()), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - Conference_state_type:: - Conference_state_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - user_count_ (this), - active_ (this), - locked_ (this), - any_ (this->getDomDocument ()), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void Conference_state_type:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // user-count - // - if (n.name () == "user-count" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - if (!this->user_count_) - { - this->user_count_.set (User_countTraits::create (i, f, this)); - continue; - } - } - - // active - // - if (n.name () == "active" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - if (!this->active_) - { - this->active_.set (ActiveTraits::create (i, f, this)); - continue; - } - } - - // locked - // - if (n.name () == "locked" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - if (!this->locked_) - { - this->locked_.set (LockedTraits::create (i, f, this)); - continue; - } - } - - // any - // - if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) - { - ::xercesc::DOMElement* r ( - static_cast< ::xercesc::DOMElement* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMElement* > (&i), true))); - this->any_.push_back (r); - continue; - } - - break; - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // any_attribute - // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) - { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; - } - } - } - - Conference_state_type* Conference_state_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Conference_state_type (*this, f, c); - } - - Conference_state_type& Conference_state_type:: - operator= (const Conference_state_type& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->user_count_ = x.user_count_; - this->active_ = x.active_; - this->locked_ = x.locked_; - this->any_ = x.any_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - Conference_state_type:: - ~Conference_state_type () - { - } - - // Conference_media_type - // - - Conference_media_type:: - Conference_media_type () - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - entry_ (this), - any_attribute_ (this->getDomDocument ()) - { - } - - Conference_media_type:: - Conference_media_type (const Conference_media_type& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - entry_ (x.entry_, f, this), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - Conference_media_type:: - Conference_media_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - entry_ (this), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void Conference_media_type:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // entry - // - if (n.name () == "entry" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< EntryType > r ( - EntryTraits::create (i, f, this)); - - this->entry_.push_back (::std::move (r)); - continue; - } - - break; - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // any_attribute - // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) - { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; - } - } - } - - Conference_media_type* Conference_media_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Conference_media_type (*this, f, c); - } - - Conference_media_type& Conference_media_type:: - operator= (const Conference_media_type& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->entry_ = x.entry_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - Conference_media_type:: - ~Conference_media_type () - { - } - - // Conference_medium_type - // - - Conference_medium_type:: - Conference_medium_type (const TypeType& type, - const LabelType& label) - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (this), - type_ (type, this), - status_ (this), - any_ (this->getDomDocument ()), - label_ (label, this), - any_attribute_ (this->getDomDocument ()) - { - } - - Conference_medium_type:: - Conference_medium_type (const Conference_medium_type& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (x.display_text_, f, this), - type_ (x.type_, f, this), - status_ (x.status_, f, this), - any_ (x.any_, this->getDomDocument ()), - label_ (x.label_, f, this), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - Conference_medium_type:: - Conference_medium_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (this), - type_ (this), - status_ (this), - any_ (this->getDomDocument ()), - label_ (this), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void Conference_medium_type:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // display-text - // - if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< Display_textType > r ( - Display_textTraits::create (i, f, this)); - - if (!this->display_text_) - { - this->display_text_.set (::std::move (r)); - continue; - } - } - - // type - // - if (n.name () == "type" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< TypeType > r ( - TypeTraits::create (i, f, this)); if (!type_.present ()) { - this->type_.set (::std::move (r)); - continue; + throw ::xsd::cxx::tree::expected_element< char > ( + "type", + "urn:ietf:params:xml:ns:conference-info"); } - } - // status - // - if (n.name () == "status" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< StatusType > r ( - StatusTraits::create (i, f, this)); - - if (!this->status_) + while (p.more_attributes ()) { - this->status_.set (::std::move (r)); - continue; + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "label" && n.namespace_ ().empty ()) + { + this->label_.set (LabelTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + + if (!label_.present ()) + { + throw ::xsd::cxx::tree::expected_attribute< char > ( + "label", + ""); } } - // any + ConferenceMediumType* ConferenceMediumType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class ConferenceMediumType (*this, f, c); + } + + ConferenceMediumType& ConferenceMediumType:: + operator= (const ConferenceMediumType& x) + { + if (this != &x) + { + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->display_text_ = x.display_text_; + this->type_ = x.type_; + this->status_ = x.status_; + this->any_ = x.any_; + this->label_ = x.label_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + ConferenceMediumType:: + ~ConferenceMediumType () + { + } + + // UrisType // - if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + + const UrisType::StateType UrisType::state_default_value_ ( + "full"); + + UrisType:: + UrisType () + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (this), + state_ (getStateDefaultValue (), this), + any_attribute_ (this->getDomDocument ()) { - ::xercesc::DOMElement* r ( - static_cast< ::xercesc::DOMElement* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMElement* > (&i), true))); - this->any_.push_back (r); - continue; } - break; - } - - if (!type_.present ()) - { - throw ::xsd::cxx::tree::expected_element< char > ( - "type", - "urn:ietf:params:xml:ns:conference-info"); - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - if (n.name () == "label" && n.namespace_ ().empty ()) + UrisType:: + UrisType (const UrisType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (x.entry_, f, this), + state_ (x.state_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) { - this->label_.set (LabelTraits::create (i, f, this)); - continue; } - // any_attribute + UrisType:: + UrisType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (this), + state_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void UrisType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // entry + // + if (n.name () == "entry" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< EntryType > r ( + EntryTraits::create (i, f, this)); + + this->entry_.push_back (::std::move (r)); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "state" && n.namespace_ ().empty ()) + { + this->state_.set (StateTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + + if (!state_.present ()) + { + this->state_.set (getStateDefaultValue ()); + } + } + + UrisType* UrisType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class UrisType (*this, f, c); + } + + UrisType& UrisType:: + operator= (const UrisType& x) + { + if (this != &x) + { + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->entry_ = x.entry_; + this->state_ = x.state_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + UrisType:: + ~UrisType () + { + } + + // UriType // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + + UriType:: + UriType (const UriType1& uri) + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + uri_ (uri, this), + display_text_ (this), + purpose_ (this), + modified_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; - } - } - - if (!label_.present ()) - { - throw ::xsd::cxx::tree::expected_attribute< char > ( - "label", - ""); - } - } - - Conference_medium_type* Conference_medium_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Conference_medium_type (*this, f, c); - } - - Conference_medium_type& Conference_medium_type:: - operator= (const Conference_medium_type& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->display_text_ = x.display_text_; - this->type_ = x.type_; - this->status_ = x.status_; - this->any_ = x.any_; - this->label_ = x.label_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - Conference_medium_type:: - ~Conference_medium_type () - { - } - - // Uris_type - // - - const Uris_type::StateType Uris_type::state_default_value_ ( - "full"); - - Uris_type:: - Uris_type () - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - entry_ (this), - state_ (getStateDefaultValue (), this), - any_attribute_ (this->getDomDocument ()) - { - } - - Uris_type:: - Uris_type (const Uris_type& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - entry_ (x.entry_, f, this), - state_ (x.state_, f, this), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - Uris_type:: - Uris_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - entry_ (this), - state_ (this), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void Uris_type:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // entry - // - if (n.name () == "entry" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< EntryType > r ( - EntryTraits::create (i, f, this)); - - this->entry_.push_back (::std::move (r)); - continue; } - break; - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - if (n.name () == "state" && n.namespace_ ().empty ()) + UriType:: + UriType (const UriType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + uri_ (x.uri_, f, this), + display_text_ (x.display_text_, f, this), + purpose_ (x.purpose_, f, this), + modified_ (x.modified_, f, this), + any_ (x.any_, this->getDomDocument ()), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) { - this->state_.set (StateTraits::create (i, f, this)); - continue; } - // any_attribute - // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + UriType:: + UriType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + uri_ (this), + display_text_ (this), + purpose_ (this), + modified_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } } - } - if (!state_.present ()) - { - this->state_.set (getStateDefaultValue ()); - } - } - - Uris_type* Uris_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Uris_type (*this, f, c); - } - - Uris_type& Uris_type:: - operator= (const Uris_type& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->entry_ = x.entry_; - this->state_ = x.state_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - Uris_type:: - ~Uris_type () - { - } - - // Uri_type - // - - Uri_type:: - Uri_type (const UriType& uri) - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - uri_ (uri, this), - display_text_ (this), - purpose_ (this), - modified_ (this), - any_ (this->getDomDocument ()), - any_attribute_ (this->getDomDocument ()) - { - } - - Uri_type:: - Uri_type (const Uri_type& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - uri_ (x.uri_, f, this), - display_text_ (x.display_text_, f, this), - purpose_ (x.purpose_, f, this), - modified_ (x.modified_, f, this), - any_ (x.any_, this->getDomDocument ()), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - Uri_type:: - Uri_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - uri_ (this), - display_text_ (this), - purpose_ (this), - modified_ (this), - any_ (this->getDomDocument ()), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void Uri_type:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // uri - // - if (n.name () == "uri" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + void UriType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) { - ::std::unique_ptr< UriType > r ( - UriTraits::create (i, f, this)); + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // uri + // + if (n.name () == "uri" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< UriType1 > r ( + UriTraits::create (i, f, this)); + + if (!uri_.present ()) + { + this->uri_.set (::std::move (r)); + continue; + } + } + + // display-text + // + if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< DisplayTextType > r ( + DisplayTextTraits::create (i, f, this)); + + if (!this->display_text_) + { + this->display_text_.set (::std::move (r)); + continue; + } + } + + // purpose + // + if (n.name () == "purpose" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< PurposeType > r ( + PurposeTraits::create (i, f, this)); + + if (!this->purpose_) + { + this->purpose_.set (::std::move (r)); + continue; + } + } + + // modified + // + if (n.name () == "modified" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< ModifiedType > r ( + ModifiedTraits::create (i, f, this)); + + if (!this->modified_) + { + this->modified_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } if (!uri_.present ()) { - this->uri_.set (::std::move (r)); - continue; + throw ::xsd::cxx::tree::expected_element< char > ( + "uri", + "urn:ietf:params:xml:ns:conference-info"); } - } - // display-text - // - if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< Display_textType > r ( - Display_textTraits::create (i, f, this)); - - if (!this->display_text_) + while (p.more_attributes ()) { - this->display_text_.set (::std::move (r)); - continue; + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } } } - // purpose - // - if (n.name () == "purpose" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + UriType* UriType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const { - ::std::unique_ptr< PurposeType > r ( - PurposeTraits::create (i, f, this)); + return new class UriType (*this, f, c); + } - if (!this->purpose_) + UriType& UriType:: + operator= (const UriType& x) + { + if (this != &x) { - this->purpose_.set (::std::move (r)); - continue; + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->uri_ = x.uri_; + this->display_text_ = x.display_text_; + this->purpose_ = x.purpose_; + this->modified_ = x.modified_; + this->any_ = x.any_; + this->any_attribute_ = x.any_attribute_; } + + return *this; } - // modified - // - if (n.name () == "modified" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + UriType:: + ~UriType () { - ::std::unique_ptr< ModifiedType > r ( - ModifiedTraits::create (i, f, this)); + } - if (!this->modified_) + // KeywordsType + // + + KeywordsType:: + KeywordsType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::SimpleType (e, f, c), + ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::String, char > (e, f, this) + { + } + + KeywordsType:: + KeywordsType (const ::xercesc::DOMAttr& a, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::SimpleType (a, f, c), + ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::String, char > (a, f, this) + { + } + + KeywordsType:: + KeywordsType (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::SimpleType (s, e, f, c), + ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::String, char > (s, e, f, this) + { + } + + KeywordsType* KeywordsType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class KeywordsType (*this, f, c); + } + + KeywordsType:: + ~KeywordsType () + { + } + + // UsersType + // + + const UsersType::StateType UsersType::state_default_value_ ( + "full"); + + UsersType:: + UsersType () + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + user_ (this), + any_ (this->getDomDocument ()), + state_ (getStateDefaultValue (), this), + any_attribute_ (this->getDomDocument ()) + { + } + + UsersType:: + UsersType (const UsersType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + user_ (x.user_, f, this), + any_ (x.any_, this->getDomDocument ()), + state_ (x.state_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + UsersType:: + UsersType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + user_ (this), + any_ (this->getDomDocument ()), + state_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) { - this->modified_.set (::std::move (r)); - continue; + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); } } - // any - // - if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + void UsersType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) { - ::xercesc::DOMElement* r ( - static_cast< ::xercesc::DOMElement* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMElement* > (&i), true))); - this->any_.push_back (r); - continue; - } - - break; - } - - if (!uri_.present ()) - { - throw ::xsd::cxx::tree::expected_element< char > ( - "uri", - "urn:ietf:params:xml:ns:conference-info"); - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // any_attribute - // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) - { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; - } - } - } - - Uri_type* Uri_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Uri_type (*this, f, c); - } - - Uri_type& Uri_type:: - operator= (const Uri_type& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->uri_ = x.uri_; - this->display_text_ = x.display_text_; - this->purpose_ = x.purpose_; - this->modified_ = x.modified_; - this->any_ = x.any_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - Uri_type:: - ~Uri_type () - { - } - - // Keywords_type - // - - Keywords_type:: - Keywords_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::SimpleType (e, f, c), - ::xsd::cxx::tree::list< ::xml_schema::String, char > (e, f, this) - { - } - - Keywords_type:: - Keywords_type (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::SimpleType (a, f, c), - ::xsd::cxx::tree::list< ::xml_schema::String, char > (a, f, this) - { - } - - Keywords_type:: - Keywords_type (const ::std::string& s, - const ::xercesc::DOMElement* e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::SimpleType (s, e, f, c), - ::xsd::cxx::tree::list< ::xml_schema::String, char > (s, e, f, this) - { - } - - Keywords_type* Keywords_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Keywords_type (*this, f, c); - } - - Keywords_type:: - ~Keywords_type () - { - } - - // Users_type - // - - const Users_type::StateType Users_type::state_default_value_ ( - "full"); - - Users_type:: - Users_type () - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - user_ (this), - any_ (this->getDomDocument ()), - state_ (getStateDefaultValue (), this), - any_attribute_ (this->getDomDocument ()) - { - } - - Users_type:: - Users_type (const Users_type& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - user_ (x.user_, f, this), - any_ (x.any_, this->getDomDocument ()), - state_ (x.state_, f, this), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - Users_type:: - Users_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - user_ (this), - any_ (this->getDomDocument ()), - state_ (this), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void Users_type:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // user - // - if (n.name () == "user" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< UserType > r ( - UserTraits::create (i, f, this)); - - this->user_.push_back (::std::move (r)); - continue; - } - - // any - // - if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) - { - ::xercesc::DOMElement* r ( - static_cast< ::xercesc::DOMElement* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMElement* > (&i), true))); - this->any_.push_back (r); - continue; - } - - break; - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - if (n.name () == "state" && n.namespace_ ().empty ()) - { - this->state_.set (StateTraits::create (i, f, this)); - continue; - } - - // any_attribute - // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) - { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; - } - } - - if (!state_.present ()) - { - this->state_.set (getStateDefaultValue ()); - } - } - - Users_type* Users_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Users_type (*this, f, c); - } - - Users_type& Users_type:: - operator= (const Users_type& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->user_ = x.user_; - this->any_ = x.any_; - this->state_ = x.state_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - Users_type:: - ~Users_type () - { - } - - // User_type - // - - const User_type::StateType User_type::state_default_value_ ( - "full"); - - User_type:: - User_type () - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (this), - associated_aors_ (this), - roles_ (this), - languages_ (this), - cascaded_focus_ (this), - endpoint_ (this), - any_ (this->getDomDocument ()), - entity_ (this), - state_ (getStateDefaultValue (), this), - any_attribute_ (this->getDomDocument ()) - { - } - - User_type:: - User_type (const User_type& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (x.display_text_, f, this), - associated_aors_ (x.associated_aors_, f, this), - roles_ (x.roles_, f, this), - languages_ (x.languages_, f, this), - cascaded_focus_ (x.cascaded_focus_, f, this), - endpoint_ (x.endpoint_, f, this), - any_ (x.any_, this->getDomDocument ()), - entity_ (x.entity_, f, this), - state_ (x.state_, f, this), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - User_type:: - User_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (this), - associated_aors_ (this), - roles_ (this), - languages_ (this), - cascaded_focus_ (this), - endpoint_ (this), - any_ (this->getDomDocument ()), - entity_ (this), - state_ (this), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void User_type:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // display-text - // - if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< Display_textType > r ( - Display_textTraits::create (i, f, this)); - - if (!this->display_text_) + for (; p.more_content (); p.next_content (false)) { - this->display_text_.set (::std::move (r)); - continue; + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // user + // + if (n.name () == "user" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< UserType > r ( + UserTraits::create (i, f, this)); + + this->user_.push_back (::std::move (r)); + continue; + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; } - } - // associated-aors - // - if (n.name () == "associated-aors" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< Associated_aorsType > r ( - Associated_aorsTraits::create (i, f, this)); - - if (!this->associated_aors_) + while (p.more_attributes ()) { - this->associated_aors_.set (::std::move (r)); - continue; + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "state" && n.namespace_ ().empty ()) + { + this->state_.set (StateTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } } - } - // roles - // - if (n.name () == "roles" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< RolesType > r ( - RolesTraits::create (i, f, this)); - - if (!this->roles_) + if (!state_.present ()) { - this->roles_.set (::std::move (r)); - continue; + this->state_.set (getStateDefaultValue ()); } } - // languages - // - if (n.name () == "languages" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + UsersType* UsersType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const { - ::std::unique_ptr< LanguagesType > r ( - LanguagesTraits::create (i, f, this)); + return new class UsersType (*this, f, c); + } - if (!this->languages_) + UsersType& UsersType:: + operator= (const UsersType& x) + { + if (this != &x) { - this->languages_.set (::std::move (r)); - continue; + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->user_ = x.user_; + this->any_ = x.any_; + this->state_ = x.state_; + this->any_attribute_ = x.any_attribute_; } + + return *this; } - // cascaded-focus - // - if (n.name () == "cascaded-focus" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + UsersType:: + ~UsersType () { - ::std::unique_ptr< Cascaded_focusType > r ( - Cascaded_focusTraits::create (i, f, this)); + } - if (!this->cascaded_focus_) + // UserType + // + + const UserType::StateType UserType::state_default_value_ ( + "full"); + + UserType:: + UserType () + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + associated_aors_ (this), + roles_ (this), + languages_ (this), + cascaded_focus_ (this), + endpoint_ (this), + any_ (this->getDomDocument ()), + entity_ (this), + state_ (getStateDefaultValue (), this), + any_attribute_ (this->getDomDocument ()) + { + } + + UserType:: + UserType (const UserType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (x.display_text_, f, this), + associated_aors_ (x.associated_aors_, f, this), + roles_ (x.roles_, f, this), + languages_ (x.languages_, f, this), + cascaded_focus_ (x.cascaded_focus_, f, this), + endpoint_ (x.endpoint_, f, this), + any_ (x.any_, this->getDomDocument ()), + entity_ (x.entity_, f, this), + state_ (x.state_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + UserType:: + UserType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + associated_aors_ (this), + roles_ (this), + languages_ (this), + cascaded_focus_ (this), + endpoint_ (this), + any_ (this->getDomDocument ()), + entity_ (this), + state_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) { - this->cascaded_focus_.set (::std::move (r)); - continue; + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); } } - // endpoint - // - if (n.name () == "endpoint" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + void UserType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) { - ::std::unique_ptr< EndpointType > r ( - EndpointTraits::create (i, f, this)); - - this->endpoint_.push_back (::std::move (r)); - continue; - } - - // any - // - if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) - { - ::xercesc::DOMElement* r ( - static_cast< ::xercesc::DOMElement* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMElement* > (&i), true))); - this->any_.push_back (r); - continue; - } - - break; - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - if (n.name () == "entity" && n.namespace_ ().empty ()) - { - this->entity_.set (EntityTraits::create (i, f, this)); - continue; - } - - if (n.name () == "state" && n.namespace_ ().empty ()) - { - this->state_.set (StateTraits::create (i, f, this)); - continue; - } - - // any_attribute - // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) - { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; - } - } - - if (!state_.present ()) - { - this->state_.set (getStateDefaultValue ()); - } - } - - User_type* User_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class User_type (*this, f, c); - } - - User_type& User_type:: - operator= (const User_type& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->display_text_ = x.display_text_; - this->associated_aors_ = x.associated_aors_; - this->roles_ = x.roles_; - this->languages_ = x.languages_; - this->cascaded_focus_ = x.cascaded_focus_; - this->endpoint_ = x.endpoint_; - this->any_ = x.any_; - this->entity_ = x.entity_; - this->state_ = x.state_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - User_type:: - ~User_type () - { - } - - // User_roles_type - // - - User_roles_type:: - User_roles_type () - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - entry_ (this), - any_attribute_ (this->getDomDocument ()) - { - } - - User_roles_type:: - User_roles_type (const User_roles_type& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - entry_ (x.entry_, f, this), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - User_roles_type:: - User_roles_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - entry_ (this), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void User_roles_type:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // entry - // - if (n.name () == "entry" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< EntryType > r ( - EntryTraits::create (i, f, this)); - - this->entry_.push_back (::std::move (r)); - continue; - } - - break; - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // any_attribute - // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) - { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; - } - } - } - - User_roles_type* User_roles_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class User_roles_type (*this, f, c); - } - - User_roles_type& User_roles_type:: - operator= (const User_roles_type& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->entry_ = x.entry_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - User_roles_type:: - ~User_roles_type () - { - } - - // User_languages_type - // - - User_languages_type:: - User_languages_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::SimpleType (e, f, c), - ::xsd::cxx::tree::list< ::xml_schema::Language, char > (e, f, this) - { - } - - User_languages_type:: - User_languages_type (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::SimpleType (a, f, c), - ::xsd::cxx::tree::list< ::xml_schema::Language, char > (a, f, this) - { - } - - User_languages_type:: - User_languages_type (const ::std::string& s, - const ::xercesc::DOMElement* e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::SimpleType (s, e, f, c), - ::xsd::cxx::tree::list< ::xml_schema::Language, char > (s, e, f, this) - { - } - - User_languages_type* User_languages_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class User_languages_type (*this, f, c); - } - - User_languages_type:: - ~User_languages_type () - { - } - - // Endpoint_type - // - - const Endpoint_type::StateType Endpoint_type::state_default_value_ ( - "full"); - - Endpoint_type:: - Endpoint_type () - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (this), - referred_ (this), - status_ (this), - joining_method_ (this), - joining_info_ (this), - disconnection_method_ (this), - disconnection_info_ (this), - media_ (this), - call_info_ (this), - any_ (this->getDomDocument ()), - entity_ (this), - state_ (getStateDefaultValue (), this), - any_attribute_ (this->getDomDocument ()) - { - } - - Endpoint_type:: - Endpoint_type (const Endpoint_type& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (x.display_text_, f, this), - referred_ (x.referred_, f, this), - status_ (x.status_, f, this), - joining_method_ (x.joining_method_, f, this), - joining_info_ (x.joining_info_, f, this), - disconnection_method_ (x.disconnection_method_, f, this), - disconnection_info_ (x.disconnection_info_, f, this), - media_ (x.media_, f, this), - call_info_ (x.call_info_, f, this), - any_ (x.any_, this->getDomDocument ()), - entity_ (x.entity_, f, this), - state_ (x.state_, f, this), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - Endpoint_type:: - Endpoint_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (this), - referred_ (this), - status_ (this), - joining_method_ (this), - joining_info_ (this), - disconnection_method_ (this), - disconnection_info_ (this), - media_ (this), - call_info_ (this), - any_ (this->getDomDocument ()), - entity_ (this), - state_ (this), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void Endpoint_type:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // display-text - // - if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< Display_textType > r ( - Display_textTraits::create (i, f, this)); - - if (!this->display_text_) + for (; p.more_content (); p.next_content (false)) { - this->display_text_.set (::std::move (r)); - continue; + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-text + // + if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< DisplayTextType > r ( + DisplayTextTraits::create (i, f, this)); + + if (!this->display_text_) + { + this->display_text_.set (::std::move (r)); + continue; + } + } + + // associated-aors + // + if (n.name () == "associated-aors" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< AssociatedAorsType > r ( + AssociatedAorsTraits::create (i, f, this)); + + if (!this->associated_aors_) + { + this->associated_aors_.set (::std::move (r)); + continue; + } + } + + // roles + // + if (n.name () == "roles" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< RolesType > r ( + RolesTraits::create (i, f, this)); + + if (!this->roles_) + { + this->roles_.set (::std::move (r)); + continue; + } + } + + // languages + // + if (n.name () == "languages" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< LanguagesType > r ( + LanguagesTraits::create (i, f, this)); + + if (!this->languages_) + { + this->languages_.set (::std::move (r)); + continue; + } + } + + // cascaded-focus + // + if (n.name () == "cascaded-focus" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< CascadedFocusType > r ( + CascadedFocusTraits::create (i, f, this)); + + if (!this->cascaded_focus_) + { + this->cascaded_focus_.set (::std::move (r)); + continue; + } + } + + // endpoint + // + if (n.name () == "endpoint" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< EndpointType > r ( + EndpointTraits::create (i, f, this)); + + this->endpoint_.push_back (::std::move (r)); + continue; + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; } - } - // referred - // - if (n.name () == "referred" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< ReferredType > r ( - ReferredTraits::create (i, f, this)); - - if (!this->referred_) + while (p.more_attributes ()) { - this->referred_.set (::std::move (r)); - continue; + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "entity" && n.namespace_ ().empty ()) + { + this->entity_.set (EntityTraits::create (i, f, this)); + continue; + } + + if (n.name () == "state" && n.namespace_ ().empty ()) + { + this->state_.set (StateTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } } - } - // status - // - if (n.name () == "status" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< StatusType > r ( - StatusTraits::create (i, f, this)); - - if (!this->status_) + if (!state_.present ()) { - this->status_.set (::std::move (r)); - continue; + this->state_.set (getStateDefaultValue ()); } } - // joining-method - // - if (n.name () == "joining-method" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + UserType* UserType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const { - ::std::unique_ptr< Joining_methodType > r ( - Joining_methodTraits::create (i, f, this)); + return new class UserType (*this, f, c); + } - if (!this->joining_method_) + UserType& UserType:: + operator= (const UserType& x) + { + if (this != &x) { - this->joining_method_.set (::std::move (r)); - continue; + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->display_text_ = x.display_text_; + this->associated_aors_ = x.associated_aors_; + this->roles_ = x.roles_; + this->languages_ = x.languages_; + this->cascaded_focus_ = x.cascaded_focus_; + this->endpoint_ = x.endpoint_; + this->any_ = x.any_; + this->entity_ = x.entity_; + this->state_ = x.state_; + this->any_attribute_ = x.any_attribute_; } + + return *this; } - // joining-info - // - if (n.name () == "joining-info" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + UserType:: + ~UserType () { - ::std::unique_ptr< Joining_infoType > r ( - Joining_infoTraits::create (i, f, this)); + } - if (!this->joining_info_) + // UserRolesType + // + + UserRolesType:: + UserRolesType () + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (this), + any_attribute_ (this->getDomDocument ()) + { + } + + UserRolesType:: + UserRolesType (const UserRolesType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (x.entry_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + UserRolesType:: + UserRolesType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) { - this->joining_info_.set (::std::move (r)); - continue; + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); } } - // disconnection-method - // - if (n.name () == "disconnection-method" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + void UserRolesType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) { - ::std::unique_ptr< Disconnection_methodType > r ( - Disconnection_methodTraits::create (i, f, this)); - - if (!this->disconnection_method_) + for (; p.more_content (); p.next_content (false)) { - this->disconnection_method_.set (::std::move (r)); - continue; + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // entry + // + if (n.name () == "entry" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< EntryType > r ( + EntryTraits::create (i, f, this)); + + this->entry_.push_back (::std::move (r)); + continue; + } + + break; } - } - // disconnection-info - // - if (n.name () == "disconnection-info" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< Disconnection_infoType > r ( - Disconnection_infoTraits::create (i, f, this)); - - if (!this->disconnection_info_) + while (p.more_attributes ()) { - this->disconnection_info_.set (::std::move (r)); - continue; + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } } } - // media - // - if (n.name () == "media" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + UserRolesType* UserRolesType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const { - ::std::unique_ptr< MediaType > r ( - MediaTraits::create (i, f, this)); - - this->media_.push_back (::std::move (r)); - continue; + return new class UserRolesType (*this, f, c); } - // call-info - // - if (n.name () == "call-info" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + UserRolesType& UserRolesType:: + operator= (const UserRolesType& x) { - ::std::unique_ptr< Call_infoType > r ( - Call_infoTraits::create (i, f, this)); - - if (!this->call_info_) + if (this != &x) { - this->call_info_.set (::std::move (r)); - continue; + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->entry_ = x.entry_; + this->any_attribute_ = x.any_attribute_; } + + return *this; } - // any + UserRolesType:: + ~UserRolesType () + { + } + + // UserLanguagesType // - if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + + UserLanguagesType:: + UserLanguagesType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::SimpleType (e, f, c), + ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::Language, char > (e, f, this) { - ::xercesc::DOMElement* r ( - static_cast< ::xercesc::DOMElement* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMElement* > (&i), true))); - this->any_.push_back (r); - continue; } - break; - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - if (n.name () == "entity" && n.namespace_ ().empty ()) + UserLanguagesType:: + UserLanguagesType (const ::xercesc::DOMAttr& a, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::SimpleType (a, f, c), + ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::Language, char > (a, f, this) { - this->entity_.set (EntityTraits::create (i, f, this)); - continue; } - if (n.name () == "state" && n.namespace_ ().empty ()) + UserLanguagesType:: + UserLanguagesType (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::SimpleType (s, e, f, c), + ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::Language, char > (s, e, f, this) { - this->state_.set (StateTraits::create (i, f, this)); - continue; } - // any_attribute + UserLanguagesType* UserLanguagesType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class UserLanguagesType (*this, f, c); + } + + UserLanguagesType:: + ~UserLanguagesType () + { + } + + // EndpointType // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + + const EndpointType::StateType EndpointType::state_default_value_ ( + "full"); + + EndpointType:: + EndpointType () + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + referred_ (this), + status_ (this), + joining_method_ (this), + joining_info_ (this), + disconnection_method_ (this), + disconnection_info_ (this), + media_ (this), + call_info_ (this), + any_ (this->getDomDocument ()), + entity_ (this), + state_ (getStateDefaultValue (), this), + any_attribute_ (this->getDomDocument ()) { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; } - } - if (!state_.present ()) - { - this->state_.set (getStateDefaultValue ()); - } - } - - Endpoint_type* Endpoint_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Endpoint_type (*this, f, c); - } - - Endpoint_type& Endpoint_type:: - operator= (const Endpoint_type& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->display_text_ = x.display_text_; - this->referred_ = x.referred_; - this->status_ = x.status_; - this->joining_method_ = x.joining_method_; - this->joining_info_ = x.joining_info_; - this->disconnection_method_ = x.disconnection_method_; - this->disconnection_info_ = x.disconnection_info_; - this->media_ = x.media_; - this->call_info_ = x.call_info_; - this->any_ = x.any_; - this->entity_ = x.entity_; - this->state_ = x.state_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - Endpoint_type:: - ~Endpoint_type () - { - } - - // Endpoint_status_type - // - - Endpoint_status_type:: - Endpoint_status_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (e, f, c) - { - _xsd_Endpoint_status_type_convert (); - } - - Endpoint_status_type:: - Endpoint_status_type (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (a, f, c) - { - _xsd_Endpoint_status_type_convert (); - } - - Endpoint_status_type:: - Endpoint_status_type (const ::std::string& s, - const ::xercesc::DOMElement* e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (s, e, f, c) - { - _xsd_Endpoint_status_type_convert (); - } - - Endpoint_status_type* Endpoint_status_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Endpoint_status_type (*this, f, c); - } - - Endpoint_status_type::Value Endpoint_status_type:: - _xsd_Endpoint_status_type_convert () const - { - ::xsd::cxx::tree::enum_comparator< char > c (_xsd_Endpoint_status_type_literals_); - const Value* i (::std::lower_bound ( - _xsd_Endpoint_status_type_indexes_, - _xsd_Endpoint_status_type_indexes_ + 9, - *this, - c)); - - if (i == _xsd_Endpoint_status_type_indexes_ + 9 || _xsd_Endpoint_status_type_literals_[*i] != *this) - { - throw ::xsd::cxx::tree::unexpected_enumerator < char > (*this); - } - - return *i; - } - - const char* const Endpoint_status_type:: - _xsd_Endpoint_status_type_literals_[9] = - { - "pending", - "dialing-out", - "dialing-in", - "alerting", - "on-hold", - "connected", - "muted-via-focus", - "disconnecting", - "disconnected" - }; - - const Endpoint_status_type::Value Endpoint_status_type:: - _xsd_Endpoint_status_type_indexes_[9] = - { - ::conference_info::Endpoint_status_type::alerting, - ::conference_info::Endpoint_status_type::connected, - ::conference_info::Endpoint_status_type::dialing_in, - ::conference_info::Endpoint_status_type::dialing_out, - ::conference_info::Endpoint_status_type::disconnected, - ::conference_info::Endpoint_status_type::disconnecting, - ::conference_info::Endpoint_status_type::muted_via_focus, - ::conference_info::Endpoint_status_type::on_hold, - ::conference_info::Endpoint_status_type::pending - }; - - // Joining_type - // - - Joining_type:: - Joining_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (e, f, c) - { - _xsd_Joining_type_convert (); - } - - Joining_type:: - Joining_type (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (a, f, c) - { - _xsd_Joining_type_convert (); - } - - Joining_type:: - Joining_type (const ::std::string& s, - const ::xercesc::DOMElement* e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (s, e, f, c) - { - _xsd_Joining_type_convert (); - } - - Joining_type* Joining_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Joining_type (*this, f, c); - } - - Joining_type::Value Joining_type:: - _xsd_Joining_type_convert () const - { - ::xsd::cxx::tree::enum_comparator< char > c (_xsd_Joining_type_literals_); - const Value* i (::std::lower_bound ( - _xsd_Joining_type_indexes_, - _xsd_Joining_type_indexes_ + 3, - *this, - c)); - - if (i == _xsd_Joining_type_indexes_ + 3 || _xsd_Joining_type_literals_[*i] != *this) - { - throw ::xsd::cxx::tree::unexpected_enumerator < char > (*this); - } - - return *i; - } - - const char* const Joining_type:: - _xsd_Joining_type_literals_[3] = - { - "dialed-in", - "dialed-out", - "focus-owner" - }; - - const Joining_type::Value Joining_type:: - _xsd_Joining_type_indexes_[3] = - { - ::conference_info::Joining_type::dialed_in, - ::conference_info::Joining_type::dialed_out, - ::conference_info::Joining_type::focus_owner - }; - - // Disconnection_type - // - - Disconnection_type:: - Disconnection_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (e, f, c) - { - _xsd_Disconnection_type_convert (); - } - - Disconnection_type:: - Disconnection_type (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (a, f, c) - { - _xsd_Disconnection_type_convert (); - } - - Disconnection_type:: - Disconnection_type (const ::std::string& s, - const ::xercesc::DOMElement* e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (s, e, f, c) - { - _xsd_Disconnection_type_convert (); - } - - Disconnection_type* Disconnection_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Disconnection_type (*this, f, c); - } - - Disconnection_type::Value Disconnection_type:: - _xsd_Disconnection_type_convert () const - { - ::xsd::cxx::tree::enum_comparator< char > c (_xsd_Disconnection_type_literals_); - const Value* i (::std::lower_bound ( - _xsd_Disconnection_type_indexes_, - _xsd_Disconnection_type_indexes_ + 4, - *this, - c)); - - if (i == _xsd_Disconnection_type_indexes_ + 4 || _xsd_Disconnection_type_literals_[*i] != *this) - { - throw ::xsd::cxx::tree::unexpected_enumerator < char > (*this); - } - - return *i; - } - - const char* const Disconnection_type:: - _xsd_Disconnection_type_literals_[4] = - { - "departed", - "booted", - "failed", - "busy" - }; - - const Disconnection_type::Value Disconnection_type:: - _xsd_Disconnection_type_indexes_[4] = - { - ::conference_info::Disconnection_type::booted, - ::conference_info::Disconnection_type::busy, - ::conference_info::Disconnection_type::departed, - ::conference_info::Disconnection_type::failed - }; - - // Execution_type - // - - Execution_type:: - Execution_type () - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - when_ (this), - reason_ (this), - by_ (this), - any_attribute_ (this->getDomDocument ()) - { - } - - Execution_type:: - Execution_type (const Execution_type& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - when_ (x.when_, f, this), - reason_ (x.reason_, f, this), - by_ (x.by_, f, this), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - Execution_type:: - Execution_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - when_ (this), - reason_ (this), - by_ (this), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void Execution_type:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // when - // - if (n.name () == "when" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + EndpointType:: + EndpointType (const EndpointType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (x.display_text_, f, this), + referred_ (x.referred_, f, this), + status_ (x.status_, f, this), + joining_method_ (x.joining_method_, f, this), + joining_info_ (x.joining_info_, f, this), + disconnection_method_ (x.disconnection_method_, f, this), + disconnection_info_ (x.disconnection_info_, f, this), + media_ (x.media_, f, this), + call_info_ (x.call_info_, f, this), + any_ (x.any_, this->getDomDocument ()), + entity_ (x.entity_, f, this), + state_ (x.state_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) { - ::std::unique_ptr< WhenType > r ( - WhenTraits::create (i, f, this)); + } - if (!this->when_) + EndpointType:: + EndpointType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + referred_ (this), + status_ (this), + joining_method_ (this), + joining_info_ (this), + disconnection_method_ (this), + disconnection_info_ (this), + media_ (this), + call_info_ (this), + any_ (this->getDomDocument ()), + entity_ (this), + state_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) { - this->when_.set (::std::move (r)); - continue; + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); } } - // reason - // - if (n.name () == "reason" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + void EndpointType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) { - ::std::unique_ptr< ReasonType > r ( - ReasonTraits::create (i, f, this)); - - if (!this->reason_) + for (; p.more_content (); p.next_content (false)) { - this->reason_.set (::std::move (r)); - continue; + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-text + // + if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< DisplayTextType > r ( + DisplayTextTraits::create (i, f, this)); + + if (!this->display_text_) + { + this->display_text_.set (::std::move (r)); + continue; + } + } + + // referred + // + if (n.name () == "referred" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< ReferredType > r ( + ReferredTraits::create (i, f, this)); + + if (!this->referred_) + { + this->referred_.set (::std::move (r)); + continue; + } + } + + // status + // + if (n.name () == "status" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< StatusType > r ( + StatusTraits::create (i, f, this)); + + if (!this->status_) + { + this->status_.set (::std::move (r)); + continue; + } + } + + // joining-method + // + if (n.name () == "joining-method" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< JoiningMethodType > r ( + JoiningMethodTraits::create (i, f, this)); + + if (!this->joining_method_) + { + this->joining_method_.set (::std::move (r)); + continue; + } + } + + // joining-info + // + if (n.name () == "joining-info" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< JoiningInfoType > r ( + JoiningInfoTraits::create (i, f, this)); + + if (!this->joining_info_) + { + this->joining_info_.set (::std::move (r)); + continue; + } + } + + // disconnection-method + // + if (n.name () == "disconnection-method" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< DisconnectionMethodType > r ( + DisconnectionMethodTraits::create (i, f, this)); + + if (!this->disconnection_method_) + { + this->disconnection_method_.set (::std::move (r)); + continue; + } + } + + // disconnection-info + // + if (n.name () == "disconnection-info" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< DisconnectionInfoType > r ( + DisconnectionInfoTraits::create (i, f, this)); + + if (!this->disconnection_info_) + { + this->disconnection_info_.set (::std::move (r)); + continue; + } + } + + // media + // + if (n.name () == "media" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< MediaType > r ( + MediaTraits::create (i, f, this)); + + this->media_.push_back (::std::move (r)); + continue; + } + + // call-info + // + if (n.name () == "call-info" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< CallInfoType > r ( + CallInfoTraits::create (i, f, this)); + + if (!this->call_info_) + { + this->call_info_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; } - } - // by - // - if (n.name () == "by" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< ByType > r ( - ByTraits::create (i, f, this)); - - if (!this->by_) + while (p.more_attributes ()) { - this->by_.set (::std::move (r)); - continue; + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "entity" && n.namespace_ ().empty ()) + { + this->entity_.set (EntityTraits::create (i, f, this)); + continue; + } + + if (n.name () == "state" && n.namespace_ ().empty ()) + { + this->state_.set (StateTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } } - } - break; - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // any_attribute - // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) - { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; - } - } - } - - Execution_type* Execution_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Execution_type (*this, f, c); - } - - Execution_type& Execution_type:: - operator= (const Execution_type& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->when_ = x.when_; - this->reason_ = x.reason_; - this->by_ = x.by_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - Execution_type:: - ~Execution_type () - { - } - - // Call_type - // - - Call_type:: - Call_type () - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - sip_ (this), - any_ (this->getDomDocument ()), - any_attribute_ (this->getDomDocument ()) - { - } - - Call_type:: - Call_type (const Call_type& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - sip_ (x.sip_, f, this), - any_ (x.any_, this->getDomDocument ()), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - Call_type:: - Call_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - sip_ (this), - any_ (this->getDomDocument ()), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void Call_type:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // sip - // - if (n.name () == "sip" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< SipType > r ( - SipTraits::create (i, f, this)); - - if (!this->sip_) + if (!state_.present ()) { - this->sip_.set (::std::move (r)); - continue; + this->state_.set (getStateDefaultValue ()); } } - // any - // - if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + EndpointType* EndpointType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const { - ::xercesc::DOMElement* r ( - static_cast< ::xercesc::DOMElement* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMElement* > (&i), true))); - this->any_.push_back (r); - continue; + return new class EndpointType (*this, f, c); } - break; - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // any_attribute - // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + EndpointType& EndpointType:: + operator= (const EndpointType& x) { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; - } - } - } - - Call_type* Call_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Call_type (*this, f, c); - } - - Call_type& Call_type:: - operator= (const Call_type& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->sip_ = x.sip_; - this->any_ = x.any_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - Call_type:: - ~Call_type () - { - } - - // Sip_dialog_id_type - // - - Sip_dialog_id_type:: - Sip_dialog_id_type (const Call_idType& call_id, - const From_tagType& from_tag, - const To_tagType& to_tag) - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (this), - call_id_ (call_id, this), - from_tag_ (from_tag, this), - to_tag_ (to_tag, this), - any_ (this->getDomDocument ()), - any_attribute_ (this->getDomDocument ()) - { - } - - Sip_dialog_id_type:: - Sip_dialog_id_type (const Sip_dialog_id_type& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (x.display_text_, f, this), - call_id_ (x.call_id_, f, this), - from_tag_ (x.from_tag_, f, this), - to_tag_ (x.to_tag_, f, this), - any_ (x.any_, this->getDomDocument ()), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - Sip_dialog_id_type:: - Sip_dialog_id_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (this), - call_id_ (this), - from_tag_ (this), - to_tag_ (this), - any_ (this->getDomDocument ()), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void Sip_dialog_id_type:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // display-text - // - if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< Display_textType > r ( - Display_textTraits::create (i, f, this)); - - if (!this->display_text_) + if (this != &x) { - this->display_text_.set (::std::move (r)); - continue; + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->display_text_ = x.display_text_; + this->referred_ = x.referred_; + this->status_ = x.status_; + this->joining_method_ = x.joining_method_; + this->joining_info_ = x.joining_info_; + this->disconnection_method_ = x.disconnection_method_; + this->disconnection_info_ = x.disconnection_info_; + this->media_ = x.media_; + this->call_info_ = x.call_info_; + this->any_ = x.any_; + this->entity_ = x.entity_; + this->state_ = x.state_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + EndpointType:: + ~EndpointType () + { + } + + // EndpointStatusType + // + + EndpointStatusType:: + EndpointStatusType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (e, f, c) + { + _xsd_EndpointStatusType_convert (); + } + + EndpointStatusType:: + EndpointStatusType (const ::xercesc::DOMAttr& a, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (a, f, c) + { + _xsd_EndpointStatusType_convert (); + } + + EndpointStatusType:: + EndpointStatusType (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (s, e, f, c) + { + _xsd_EndpointStatusType_convert (); + } + + EndpointStatusType* EndpointStatusType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class EndpointStatusType (*this, f, c); + } + + EndpointStatusType::Value EndpointStatusType:: + _xsd_EndpointStatusType_convert () const + { + ::xsd::cxx::tree::enum_comparator< char > c (_xsd_EndpointStatusType_literals_); + const Value* i (::std::lower_bound ( + _xsd_EndpointStatusType_indexes_, + _xsd_EndpointStatusType_indexes_ + 9, + *this, + c)); + + if (i == _xsd_EndpointStatusType_indexes_ + 9 || _xsd_EndpointStatusType_literals_[*i] != *this) + { + throw ::xsd::cxx::tree::unexpected_enumerator < char > (*this); + } + + return *i; + } + + const char* const EndpointStatusType:: + _xsd_EndpointStatusType_literals_[9] = + { + "pending", + "dialing-out", + "dialing-in", + "alerting", + "on-hold", + "connected", + "muted-via-focus", + "disconnecting", + "disconnected" + }; + + const EndpointStatusType::Value EndpointStatusType:: + _xsd_EndpointStatusType_indexes_[9] = + { + ::LinphonePrivate::Xsd::ConferenceInfo::EndpointStatusType::alerting, + ::LinphonePrivate::Xsd::ConferenceInfo::EndpointStatusType::connected, + ::LinphonePrivate::Xsd::ConferenceInfo::EndpointStatusType::dialing_in, + ::LinphonePrivate::Xsd::ConferenceInfo::EndpointStatusType::dialing_out, + ::LinphonePrivate::Xsd::ConferenceInfo::EndpointStatusType::disconnected, + ::LinphonePrivate::Xsd::ConferenceInfo::EndpointStatusType::disconnecting, + ::LinphonePrivate::Xsd::ConferenceInfo::EndpointStatusType::muted_via_focus, + ::LinphonePrivate::Xsd::ConferenceInfo::EndpointStatusType::on_hold, + ::LinphonePrivate::Xsd::ConferenceInfo::EndpointStatusType::pending + }; + + // JoiningType + // + + JoiningType:: + JoiningType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (e, f, c) + { + _xsd_JoiningType_convert (); + } + + JoiningType:: + JoiningType (const ::xercesc::DOMAttr& a, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (a, f, c) + { + _xsd_JoiningType_convert (); + } + + JoiningType:: + JoiningType (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (s, e, f, c) + { + _xsd_JoiningType_convert (); + } + + JoiningType* JoiningType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class JoiningType (*this, f, c); + } + + JoiningType::Value JoiningType:: + _xsd_JoiningType_convert () const + { + ::xsd::cxx::tree::enum_comparator< char > c (_xsd_JoiningType_literals_); + const Value* i (::std::lower_bound ( + _xsd_JoiningType_indexes_, + _xsd_JoiningType_indexes_ + 3, + *this, + c)); + + if (i == _xsd_JoiningType_indexes_ + 3 || _xsd_JoiningType_literals_[*i] != *this) + { + throw ::xsd::cxx::tree::unexpected_enumerator < char > (*this); + } + + return *i; + } + + const char* const JoiningType:: + _xsd_JoiningType_literals_[3] = + { + "dialed-in", + "dialed-out", + "focus-owner" + }; + + const JoiningType::Value JoiningType:: + _xsd_JoiningType_indexes_[3] = + { + ::LinphonePrivate::Xsd::ConferenceInfo::JoiningType::dialed_in, + ::LinphonePrivate::Xsd::ConferenceInfo::JoiningType::dialed_out, + ::LinphonePrivate::Xsd::ConferenceInfo::JoiningType::focus_owner + }; + + // DisconnectionType + // + + DisconnectionType:: + DisconnectionType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (e, f, c) + { + _xsd_DisconnectionType_convert (); + } + + DisconnectionType:: + DisconnectionType (const ::xercesc::DOMAttr& a, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (a, f, c) + { + _xsd_DisconnectionType_convert (); + } + + DisconnectionType:: + DisconnectionType (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (s, e, f, c) + { + _xsd_DisconnectionType_convert (); + } + + DisconnectionType* DisconnectionType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class DisconnectionType (*this, f, c); + } + + DisconnectionType::Value DisconnectionType:: + _xsd_DisconnectionType_convert () const + { + ::xsd::cxx::tree::enum_comparator< char > c (_xsd_DisconnectionType_literals_); + const Value* i (::std::lower_bound ( + _xsd_DisconnectionType_indexes_, + _xsd_DisconnectionType_indexes_ + 4, + *this, + c)); + + if (i == _xsd_DisconnectionType_indexes_ + 4 || _xsd_DisconnectionType_literals_[*i] != *this) + { + throw ::xsd::cxx::tree::unexpected_enumerator < char > (*this); + } + + return *i; + } + + const char* const DisconnectionType:: + _xsd_DisconnectionType_literals_[4] = + { + "departed", + "booted", + "failed", + "busy" + }; + + const DisconnectionType::Value DisconnectionType:: + _xsd_DisconnectionType_indexes_[4] = + { + ::LinphonePrivate::Xsd::ConferenceInfo::DisconnectionType::booted, + ::LinphonePrivate::Xsd::ConferenceInfo::DisconnectionType::busy, + ::LinphonePrivate::Xsd::ConferenceInfo::DisconnectionType::departed, + ::LinphonePrivate::Xsd::ConferenceInfo::DisconnectionType::failed + }; + + // ExecutionType + // + + ExecutionType:: + ExecutionType () + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + when_ (this), + reason_ (this), + by_ (this), + any_attribute_ (this->getDomDocument ()) + { + } + + ExecutionType:: + ExecutionType (const ExecutionType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + when_ (x.when_, f, this), + reason_ (x.reason_, f, this), + by_ (x.by_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + ExecutionType:: + ExecutionType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + when_ (this), + reason_ (this), + by_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); } } - // call-id - // - if (n.name () == "call-id" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + void ExecutionType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) { - ::std::unique_ptr< Call_idType > r ( - Call_idTraits::create (i, f, this)); + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // when + // + if (n.name () == "when" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< WhenType > r ( + WhenTraits::create (i, f, this)); + + if (!this->when_) + { + this->when_.set (::std::move (r)); + continue; + } + } + + // reason + // + if (n.name () == "reason" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< ReasonType > r ( + ReasonTraits::create (i, f, this)); + + if (!this->reason_) + { + this->reason_.set (::std::move (r)); + continue; + } + } + + // by + // + if (n.name () == "by" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< ByType > r ( + ByTraits::create (i, f, this)); + + if (!this->by_) + { + this->by_.set (::std::move (r)); + continue; + } + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + } + + ExecutionType* ExecutionType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class ExecutionType (*this, f, c); + } + + ExecutionType& ExecutionType:: + operator= (const ExecutionType& x) + { + if (this != &x) + { + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->when_ = x.when_; + this->reason_ = x.reason_; + this->by_ = x.by_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + ExecutionType:: + ~ExecutionType () + { + } + + // CallType + // + + CallType:: + CallType () + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + sip_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + } + + CallType:: + CallType (const CallType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + sip_ (x.sip_, f, this), + any_ (x.any_, this->getDomDocument ()), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + CallType:: + CallType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + sip_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void CallType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // sip + // + if (n.name () == "sip" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< SipType > r ( + SipTraits::create (i, f, this)); + + if (!this->sip_) + { + this->sip_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + } + + CallType* CallType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class CallType (*this, f, c); + } + + CallType& CallType:: + operator= (const CallType& x) + { + if (this != &x) + { + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->sip_ = x.sip_; + this->any_ = x.any_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + CallType:: + ~CallType () + { + } + + // SipDialogIdType + // + + SipDialogIdType:: + SipDialogIdType (const CallIdType& call_id, + const FromTagType& from_tag, + const ToTagType& to_tag) + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + call_id_ (call_id, this), + from_tag_ (from_tag, this), + to_tag_ (to_tag, this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + } + + SipDialogIdType:: + SipDialogIdType (const SipDialogIdType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (x.display_text_, f, this), + call_id_ (x.call_id_, f, this), + from_tag_ (x.from_tag_, f, this), + to_tag_ (x.to_tag_, f, this), + any_ (x.any_, this->getDomDocument ()), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + SipDialogIdType:: + SipDialogIdType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + call_id_ (this), + from_tag_ (this), + to_tag_ (this), + any_ (this->getDomDocument ()), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void SipDialogIdType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-text + // + if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< DisplayTextType > r ( + DisplayTextTraits::create (i, f, this)); + + if (!this->display_text_) + { + this->display_text_.set (::std::move (r)); + continue; + } + } + + // call-id + // + if (n.name () == "call-id" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< CallIdType > r ( + CallIdTraits::create (i, f, this)); + + if (!call_id_.present ()) + { + this->call_id_.set (::std::move (r)); + continue; + } + } + + // from-tag + // + if (n.name () == "from-tag" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< FromTagType > r ( + FromTagTraits::create (i, f, this)); + + if (!from_tag_.present ()) + { + this->from_tag_.set (::std::move (r)); + continue; + } + } + + // to-tag + // + if (n.name () == "to-tag" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< ToTagType > r ( + ToTagTraits::create (i, f, this)); + + if (!to_tag_.present ()) + { + this->to_tag_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } if (!call_id_.present ()) { - this->call_id_.set (::std::move (r)); - continue; + throw ::xsd::cxx::tree::expected_element< char > ( + "call-id", + "urn:ietf:params:xml:ns:conference-info"); } - } - - // from-tag - // - if (n.name () == "from-tag" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< From_tagType > r ( - From_tagTraits::create (i, f, this)); if (!from_tag_.present ()) { - this->from_tag_.set (::std::move (r)); - continue; + throw ::xsd::cxx::tree::expected_element< char > ( + "from-tag", + "urn:ietf:params:xml:ns:conference-info"); } - } - - // to-tag - // - if (n.name () == "to-tag" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< To_tagType > r ( - To_tagTraits::create (i, f, this)); if (!to_tag_.present ()) { - this->to_tag_.set (::std::move (r)); - continue; + throw ::xsd::cxx::tree::expected_element< char > ( + "to-tag", + "urn:ietf:params:xml:ns:conference-info"); } - } - // any - // - if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) - { - ::xercesc::DOMElement* r ( - static_cast< ::xercesc::DOMElement* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMElement* > (&i), true))); - this->any_.push_back (r); - continue; - } - - break; - } - - if (!call_id_.present ()) - { - throw ::xsd::cxx::tree::expected_element< char > ( - "call-id", - "urn:ietf:params:xml:ns:conference-info"); - } - - if (!from_tag_.present ()) - { - throw ::xsd::cxx::tree::expected_element< char > ( - "from-tag", - "urn:ietf:params:xml:ns:conference-info"); - } - - if (!to_tag_.present ()) - { - throw ::xsd::cxx::tree::expected_element< char > ( - "to-tag", - "urn:ietf:params:xml:ns:conference-info"); - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // any_attribute - // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) - { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; - } - } - } - - Sip_dialog_id_type* Sip_dialog_id_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Sip_dialog_id_type (*this, f, c); - } - - Sip_dialog_id_type& Sip_dialog_id_type:: - operator= (const Sip_dialog_id_type& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->display_text_ = x.display_text_; - this->call_id_ = x.call_id_; - this->from_tag_ = x.from_tag_; - this->to_tag_ = x.to_tag_; - this->any_ = x.any_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - Sip_dialog_id_type:: - ~Sip_dialog_id_type () - { - } - - // Media_type - // - - Media_type:: - Media_type (const IdType& id) - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (this), - type_ (this), - label_ (this), - src_id_ (this), - status_ (this), - any_ (this->getDomDocument ()), - id_ (id, this), - any_attribute_ (this->getDomDocument ()) - { - } - - Media_type:: - Media_type (const Media_type& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (x.display_text_, f, this), - type_ (x.type_, f, this), - label_ (x.label_, f, this), - src_id_ (x.src_id_, f, this), - status_ (x.status_, f, this), - any_ (x.any_, this->getDomDocument ()), - id_ (x.id_, f, this), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - Media_type:: - Media_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_text_ (this), - type_ (this), - label_ (this), - src_id_ (this), - status_ (this), - any_ (this->getDomDocument ()), - id_ (this), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void Media_type:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // display-text - // - if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< Display_textType > r ( - Display_textTraits::create (i, f, this)); - - if (!this->display_text_) + while (p.more_attributes ()) { - this->display_text_.set (::std::move (r)); - continue; + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } } } - // type - // - if (n.name () == "type" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + SipDialogIdType* SipDialogIdType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const { - ::std::unique_ptr< TypeType > r ( - TypeTraits::create (i, f, this)); + return new class SipDialogIdType (*this, f, c); + } - if (!this->type_) + SipDialogIdType& SipDialogIdType:: + operator= (const SipDialogIdType& x) + { + if (this != &x) { - this->type_.set (::std::move (r)); - continue; + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->display_text_ = x.display_text_; + this->call_id_ = x.call_id_; + this->from_tag_ = x.from_tag_; + this->to_tag_ = x.to_tag_; + this->any_ = x.any_; + this->any_attribute_ = x.any_attribute_; } + + return *this; } - // label - // - if (n.name () == "label" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + SipDialogIdType:: + ~SipDialogIdType () { - ::std::unique_ptr< LabelType > r ( - LabelTraits::create (i, f, this)); + } - if (!this->label_) + // MediaType + // + + MediaType:: + MediaType (const IdType& id) + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + type_ (this), + label_ (this), + src_id_ (this), + status_ (this), + any_ (this->getDomDocument ()), + id_ (id, this), + any_attribute_ (this->getDomDocument ()) + { + } + + MediaType:: + MediaType (const MediaType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (x.display_text_, f, this), + type_ (x.type_, f, this), + label_ (x.label_, f, this), + src_id_ (x.src_id_, f, this), + status_ (x.status_, f, this), + any_ (x.any_, this->getDomDocument ()), + id_ (x.id_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + MediaType:: + MediaType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_text_ (this), + type_ (this), + label_ (this), + src_id_ (this), + status_ (this), + any_ (this->getDomDocument ()), + id_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) { - this->label_.set (::std::move (r)); - continue; + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); } } - // src-id - // - if (n.name () == "src-id" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + void MediaType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) { - ::std::unique_ptr< Src_idType > r ( - Src_idTraits::create (i, f, this)); - - if (!this->src_id_) + for (; p.more_content (); p.next_content (false)) { - this->src_id_.set (::std::move (r)); - continue; + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-text + // + if (n.name () == "display-text" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< DisplayTextType > r ( + DisplayTextTraits::create (i, f, this)); + + if (!this->display_text_) + { + this->display_text_.set (::std::move (r)); + continue; + } + } + + // type + // + if (n.name () == "type" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< TypeType > r ( + TypeTraits::create (i, f, this)); + + if (!this->type_) + { + this->type_.set (::std::move (r)); + continue; + } + } + + // label + // + if (n.name () == "label" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< LabelType > r ( + LabelTraits::create (i, f, this)); + + if (!this->label_) + { + this->label_.set (::std::move (r)); + continue; + } + } + + // src-id + // + if (n.name () == "src-id" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< SrcIdType > r ( + SrcIdTraits::create (i, f, this)); + + if (!this->src_id_) + { + this->src_id_.set (::std::move (r)); + continue; + } + } + + // status + // + if (n.name () == "status" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< StatusType > r ( + StatusTraits::create (i, f, this)); + + if (!this->status_) + { + this->status_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; } - } - // status - // - if (n.name () == "status" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< StatusType > r ( - StatusTraits::create (i, f, this)); - - if (!this->status_) + while (p.more_attributes ()) { - this->status_.set (::std::move (r)); - continue; + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "id" && n.namespace_ ().empty ()) + { + this->id_.set (IdTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + + if (!id_.present ()) + { + throw ::xsd::cxx::tree::expected_attribute< char > ( + "id", + ""); } } - // any + MediaType* MediaType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class MediaType (*this, f, c); + } + + MediaType& MediaType:: + operator= (const MediaType& x) + { + if (this != &x) + { + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->display_text_ = x.display_text_; + this->type_ = x.type_; + this->label_ = x.label_; + this->src_id_ = x.src_id_; + this->status_ = x.status_; + this->any_ = x.any_; + this->id_ = x.id_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + MediaType:: + ~MediaType () + { + } + + // MediaStatusType // - if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:conference-info")) + + MediaStatusType:: + MediaStatusType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (e, f, c) { - ::xercesc::DOMElement* r ( - static_cast< ::xercesc::DOMElement* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMElement* > (&i), true))); - this->any_.push_back (r); - continue; + _xsd_MediaStatusType_convert (); } - break; - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - if (n.name () == "id" && n.namespace_ ().empty ()) + MediaStatusType:: + MediaStatusType (const ::xercesc::DOMAttr& a, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (a, f, c) { - this->id_.set (IdTraits::create (i, f, this)); - continue; + _xsd_MediaStatusType_convert (); } - // any_attribute + MediaStatusType:: + MediaStatusType (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (s, e, f, c) + { + _xsd_MediaStatusType_convert (); + } + + MediaStatusType* MediaStatusType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class MediaStatusType (*this, f, c); + } + + MediaStatusType::Value MediaStatusType:: + _xsd_MediaStatusType_convert () const + { + ::xsd::cxx::tree::enum_comparator< char > c (_xsd_MediaStatusType_literals_); + const Value* i (::std::lower_bound ( + _xsd_MediaStatusType_indexes_, + _xsd_MediaStatusType_indexes_ + 4, + *this, + c)); + + if (i == _xsd_MediaStatusType_indexes_ + 4 || _xsd_MediaStatusType_literals_[*i] != *this) + { + throw ::xsd::cxx::tree::unexpected_enumerator < char > (*this); + } + + return *i; + } + + const char* const MediaStatusType:: + _xsd_MediaStatusType_literals_[4] = + { + "recvonly", + "sendonly", + "sendrecv", + "inactive" + }; + + const MediaStatusType::Value MediaStatusType:: + _xsd_MediaStatusType_indexes_[4] = + { + ::LinphonePrivate::Xsd::ConferenceInfo::MediaStatusType::inactive, + ::LinphonePrivate::Xsd::ConferenceInfo::MediaStatusType::recvonly, + ::LinphonePrivate::Xsd::ConferenceInfo::MediaStatusType::sendonly, + ::LinphonePrivate::Xsd::ConferenceInfo::MediaStatusType::sendrecv + }; + + // SidebarsByValType // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + + const SidebarsByValType::StateType SidebarsByValType::state_default_value_ ( + "full"); + + SidebarsByValType:: + SidebarsByValType () + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (this), + state_ (getStateDefaultValue (), this), + any_attribute_ (this->getDomDocument ()) { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; - } - } - - if (!id_.present ()) - { - throw ::xsd::cxx::tree::expected_attribute< char > ( - "id", - ""); - } - } - - Media_type* Media_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Media_type (*this, f, c); - } - - Media_type& Media_type:: - operator= (const Media_type& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->display_text_ = x.display_text_; - this->type_ = x.type_; - this->label_ = x.label_; - this->src_id_ = x.src_id_; - this->status_ = x.status_; - this->any_ = x.any_; - this->id_ = x.id_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - Media_type:: - ~Media_type () - { - } - - // Media_status_type - // - - Media_status_type:: - Media_status_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (e, f, c) - { - _xsd_Media_status_type_convert (); - } - - Media_status_type:: - Media_status_type (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (a, f, c) - { - _xsd_Media_status_type_convert (); - } - - Media_status_type:: - Media_status_type (const ::std::string& s, - const ::xercesc::DOMElement* e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (s, e, f, c) - { - _xsd_Media_status_type_convert (); - } - - Media_status_type* Media_status_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Media_status_type (*this, f, c); - } - - Media_status_type::Value Media_status_type:: - _xsd_Media_status_type_convert () const - { - ::xsd::cxx::tree::enum_comparator< char > c (_xsd_Media_status_type_literals_); - const Value* i (::std::lower_bound ( - _xsd_Media_status_type_indexes_, - _xsd_Media_status_type_indexes_ + 4, - *this, - c)); - - if (i == _xsd_Media_status_type_indexes_ + 4 || _xsd_Media_status_type_literals_[*i] != *this) - { - throw ::xsd::cxx::tree::unexpected_enumerator < char > (*this); - } - - return *i; - } - - const char* const Media_status_type:: - _xsd_Media_status_type_literals_[4] = - { - "recvonly", - "sendonly", - "sendrecv", - "inactive" - }; - - const Media_status_type::Value Media_status_type:: - _xsd_Media_status_type_indexes_[4] = - { - ::conference_info::Media_status_type::inactive, - ::conference_info::Media_status_type::recvonly, - ::conference_info::Media_status_type::sendonly, - ::conference_info::Media_status_type::sendrecv - }; - - // Sidebars_by_val_type - // - - const Sidebars_by_val_type::StateType Sidebars_by_val_type::state_default_value_ ( - "full"); - - Sidebars_by_val_type:: - Sidebars_by_val_type () - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - entry_ (this), - state_ (getStateDefaultValue (), this), - any_attribute_ (this->getDomDocument ()) - { - } - - Sidebars_by_val_type:: - Sidebars_by_val_type (const Sidebars_by_val_type& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - entry_ (x.entry_, f, this), - state_ (x.state_, f, this), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - Sidebars_by_val_type:: - Sidebars_by_val_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - entry_ (this), - state_ (this), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void Sidebars_by_val_type:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // entry - // - if (n.name () == "entry" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< EntryType > r ( - EntryTraits::create (i, f, this)); - - this->entry_.push_back (::std::move (r)); - continue; } - break; - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - if (n.name () == "state" && n.namespace_ ().empty ()) + SidebarsByValType:: + SidebarsByValType (const SidebarsByValType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (x.entry_, f, this), + state_ (x.state_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) { - this->state_.set (StateTraits::create (i, f, this)); - continue; } - // any_attribute - // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + SidebarsByValType:: + SidebarsByValType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + entry_ (this), + state_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void SidebarsByValType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // entry + // + if (n.name () == "entry" && n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< EntryType > r ( + EntryTraits::create (i, f, this)); + + this->entry_.push_back (::std::move (r)); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "state" && n.namespace_ ().empty ()) + { + this->state_.set (StateTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:conference-info" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + + if (!state_.present ()) + { + this->state_.set (getStateDefaultValue ()); + } + } + + SidebarsByValType* SidebarsByValType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class SidebarsByValType (*this, f, c); + } + + SidebarsByValType& SidebarsByValType:: + operator= (const SidebarsByValType& x) + { + if (this != &x) + { + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->entry_ = x.entry_; + this->state_ = x.state_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + SidebarsByValType:: + ~SidebarsByValType () { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; } } - - if (!state_.present ()) - { - this->state_.set (getStateDefaultValue ()); - } - } - - Sidebars_by_val_type* Sidebars_by_val_type:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Sidebars_by_val_type (*this, f, c); - } - - Sidebars_by_val_type& Sidebars_by_val_type:: - operator= (const Sidebars_by_val_type& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->entry_ = x.entry_; - this->state_ = x.state_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - Sidebars_by_val_type:: - ~Sidebars_by_val_type () - { } } #include -namespace conference_info +namespace LinphonePrivate { - ::std::ostream& - operator<< (::std::ostream& o, const Conference_type& i) + namespace Xsd { - if (i.getConference_description ()) + namespace ConferenceInfo { - o << ::std::endl << "conference-description: " << *i.getConference_description (); + ::std::ostream& + operator<< (::std::ostream& o, const ConferenceType& i) + { + if (i.getConferenceDescription ()) + { + o << ::std::endl << "conference-description: " << *i.getConferenceDescription (); + } + + if (i.getHostInfo ()) + { + o << ::std::endl << "host-info: " << *i.getHostInfo (); + } + + if (i.getConferenceState ()) + { + o << ::std::endl << "conference-state: " << *i.getConferenceState (); + } + + if (i.getUsers ()) + { + o << ::std::endl << "users: " << *i.getUsers (); + } + + if (i.getSidebarsByRef ()) + { + o << ::std::endl << "sidebars-by-ref: " << *i.getSidebarsByRef (); + } + + if (i.getSidebarsByVal ()) + { + o << ::std::endl << "sidebars-by-val: " << *i.getSidebarsByVal (); + } + + o << ::std::endl << "entity: " << i.getEntity (); + o << ::std::endl << "state: " << i.getState (); + if (i.getVersion ()) + { + o << ::std::endl << "version: " << *i.getVersion (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, StateType::Value i) + { + return o << StateType::_xsd_StateType_literals_[i]; + } + + ::std::ostream& + operator<< (::std::ostream& o, const StateType& i) + { + return o << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + ::std::ostream& + operator<< (::std::ostream& o, const ConferenceDescriptionType& i) + { + if (i.getDisplayText ()) + { + o << ::std::endl << "display-text: " << *i.getDisplayText (); + } + + if (i.getSubject ()) + { + o << ::std::endl << "subject: " << *i.getSubject (); + } + + if (i.getFreeText ()) + { + o << ::std::endl << "free-text: " << *i.getFreeText (); + } + + if (i.getKeywords ()) + { + o << ::std::endl << "keywords: " << *i.getKeywords (); + } + + if (i.getConfUris ()) + { + o << ::std::endl << "conf-uris: " << *i.getConfUris (); + } + + if (i.getServiceUris ()) + { + o << ::std::endl << "service-uris: " << *i.getServiceUris (); + } + + if (i.getMaximumUserCount ()) + { + o << ::std::endl << "maximum-user-count: " << *i.getMaximumUserCount (); + } + + if (i.getAvailableMedia ()) + { + o << ::std::endl << "available-media: " << *i.getAvailableMedia (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const HostType& i) + { + if (i.getDisplayText ()) + { + o << ::std::endl << "display-text: " << *i.getDisplayText (); + } + + if (i.getWebPage ()) + { + o << ::std::endl << "web-page: " << *i.getWebPage (); + } + + if (i.getUris ()) + { + o << ::std::endl << "uris: " << *i.getUris (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const ConferenceStateType& i) + { + if (i.getUserCount ()) + { + o << ::std::endl << "user-count: " << *i.getUserCount (); + } + + if (i.getActive ()) + { + o << ::std::endl << "active: " << *i.getActive (); + } + + if (i.getLocked ()) + { + o << ::std::endl << "locked: " << *i.getLocked (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const ConferenceMediaType& i) + { + for (ConferenceMediaType::EntryConstIterator + b (i.getEntry ().begin ()), e (i.getEntry ().end ()); + b != e; ++b) + { + o << ::std::endl << "entry: " << *b; + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const ConferenceMediumType& i) + { + if (i.getDisplayText ()) + { + o << ::std::endl << "display-text: " << *i.getDisplayText (); + } + + o << ::std::endl << "type: " << i.getType (); + if (i.getStatus ()) + { + o << ::std::endl << "status: " << *i.getStatus (); + } + + o << ::std::endl << "label: " << i.getLabel (); + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const UrisType& i) + { + for (UrisType::EntryConstIterator + b (i.getEntry ().begin ()), e (i.getEntry ().end ()); + b != e; ++b) + { + o << ::std::endl << "entry: " << *b; + } + + o << ::std::endl << "state: " << i.getState (); + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const UriType& i) + { + o << ::std::endl << "uri: " << i.getUri (); + if (i.getDisplayText ()) + { + o << ::std::endl << "display-text: " << *i.getDisplayText (); + } + + if (i.getPurpose ()) + { + o << ::std::endl << "purpose: " << *i.getPurpose (); + } + + if (i.getModified ()) + { + o << ::std::endl << "modified: " << *i.getModified (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const KeywordsType& i) + { + return o << static_cast< const ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::String, char >& > (i); + } + + ::std::ostream& + operator<< (::std::ostream& o, const UsersType& i) + { + for (UsersType::UserConstIterator + b (i.getUser ().begin ()), e (i.getUser ().end ()); + b != e; ++b) + { + o << ::std::endl << "user: " << *b; + } + + o << ::std::endl << "state: " << i.getState (); + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const UserType& i) + { + if (i.getDisplayText ()) + { + o << ::std::endl << "display-text: " << *i.getDisplayText (); + } + + if (i.getAssociatedAors ()) + { + o << ::std::endl << "associated-aors: " << *i.getAssociatedAors (); + } + + if (i.getRoles ()) + { + o << ::std::endl << "roles: " << *i.getRoles (); + } + + if (i.getLanguages ()) + { + o << ::std::endl << "languages: " << *i.getLanguages (); + } + + if (i.getCascadedFocus ()) + { + o << ::std::endl << "cascaded-focus: " << *i.getCascadedFocus (); + } + + for (UserType::EndpointConstIterator + b (i.getEndpoint ().begin ()), e (i.getEndpoint ().end ()); + b != e; ++b) + { + o << ::std::endl << "endpoint: " << *b; + } + + if (i.getEntity ()) + { + o << ::std::endl << "entity: " << *i.getEntity (); + } + + o << ::std::endl << "state: " << i.getState (); + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const UserRolesType& i) + { + for (UserRolesType::EntryConstIterator + b (i.getEntry ().begin ()), e (i.getEntry ().end ()); + b != e; ++b) + { + o << ::std::endl << "entry: " << *b; + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const UserLanguagesType& i) + { + return o << static_cast< const ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::Language, char >& > (i); + } + + ::std::ostream& + operator<< (::std::ostream& o, const EndpointType& i) + { + if (i.getDisplayText ()) + { + o << ::std::endl << "display-text: " << *i.getDisplayText (); + } + + if (i.getReferred ()) + { + o << ::std::endl << "referred: " << *i.getReferred (); + } + + if (i.getStatus ()) + { + o << ::std::endl << "status: " << *i.getStatus (); + } + + if (i.getJoiningMethod ()) + { + o << ::std::endl << "joining-method: " << *i.getJoiningMethod (); + } + + if (i.getJoiningInfo ()) + { + o << ::std::endl << "joining-info: " << *i.getJoiningInfo (); + } + + if (i.getDisconnectionMethod ()) + { + o << ::std::endl << "disconnection-method: " << *i.getDisconnectionMethod (); + } + + if (i.getDisconnectionInfo ()) + { + o << ::std::endl << "disconnection-info: " << *i.getDisconnectionInfo (); + } + + for (EndpointType::MediaConstIterator + b (i.getMedia ().begin ()), e (i.getMedia ().end ()); + b != e; ++b) + { + o << ::std::endl << "media: " << *b; + } + + if (i.getCallInfo ()) + { + o << ::std::endl << "call-info: " << *i.getCallInfo (); + } + + if (i.getEntity ()) + { + o << ::std::endl << "entity: " << *i.getEntity (); + } + + o << ::std::endl << "state: " << i.getState (); + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, EndpointStatusType::Value i) + { + return o << EndpointStatusType::_xsd_EndpointStatusType_literals_[i]; + } + + ::std::ostream& + operator<< (::std::ostream& o, const EndpointStatusType& i) + { + return o << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + ::std::ostream& + operator<< (::std::ostream& o, JoiningType::Value i) + { + return o << JoiningType::_xsd_JoiningType_literals_[i]; + } + + ::std::ostream& + operator<< (::std::ostream& o, const JoiningType& i) + { + return o << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + ::std::ostream& + operator<< (::std::ostream& o, DisconnectionType::Value i) + { + return o << DisconnectionType::_xsd_DisconnectionType_literals_[i]; + } + + ::std::ostream& + operator<< (::std::ostream& o, const DisconnectionType& i) + { + return o << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + ::std::ostream& + operator<< (::std::ostream& o, const ExecutionType& i) + { + if (i.getWhen ()) + { + o << ::std::endl << "when: " << *i.getWhen (); + } + + if (i.getReason ()) + { + o << ::std::endl << "reason: " << *i.getReason (); + } + + if (i.getBy ()) + { + o << ::std::endl << "by: " << *i.getBy (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const CallType& i) + { + if (i.getSip ()) + { + o << ::std::endl << "sip: " << *i.getSip (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const SipDialogIdType& i) + { + if (i.getDisplayText ()) + { + o << ::std::endl << "display-text: " << *i.getDisplayText (); + } + + o << ::std::endl << "call-id: " << i.getCallId (); + o << ::std::endl << "from-tag: " << i.getFromTag (); + o << ::std::endl << "to-tag: " << i.getToTag (); + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const MediaType& i) + { + if (i.getDisplayText ()) + { + o << ::std::endl << "display-text: " << *i.getDisplayText (); + } + + if (i.getType ()) + { + o << ::std::endl << "type: " << *i.getType (); + } + + if (i.getLabel ()) + { + o << ::std::endl << "label: " << *i.getLabel (); + } + + if (i.getSrcId ()) + { + o << ::std::endl << "src-id: " << *i.getSrcId (); + } + + if (i.getStatus ()) + { + o << ::std::endl << "status: " << *i.getStatus (); + } + + o << ::std::endl << "id: " << i.getId (); + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, MediaStatusType::Value i) + { + return o << MediaStatusType::_xsd_MediaStatusType_literals_[i]; + } + + ::std::ostream& + operator<< (::std::ostream& o, const MediaStatusType& i) + { + return o << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + ::std::ostream& + operator<< (::std::ostream& o, const SidebarsByValType& i) + { + for (SidebarsByValType::EntryConstIterator + b (i.getEntry ().begin ()), e (i.getEntry ().end ()); + b != e; ++b) + { + o << ::std::endl << "entry: " << *b; + } + + o << ::std::endl << "state: " << i.getState (); + return o; + } } - - if (i.getHost_info ()) - { - o << ::std::endl << "host-info: " << *i.getHost_info (); - } - - if (i.getConference_state ()) - { - o << ::std::endl << "conference-state: " << *i.getConference_state (); - } - - if (i.getUsers ()) - { - o << ::std::endl << "users: " << *i.getUsers (); - } - - if (i.getSidebars_by_ref ()) - { - o << ::std::endl << "sidebars-by-ref: " << *i.getSidebars_by_ref (); - } - - if (i.getSidebars_by_val ()) - { - o << ::std::endl << "sidebars-by-val: " << *i.getSidebars_by_val (); - } - - o << ::std::endl << "entity: " << i.getEntity (); - o << ::std::endl << "state: " << i.getState (); - if (i.getVersion ()) - { - o << ::std::endl << "version: " << *i.getVersion (); - } - - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, State_type::Value i) - { - return o << State_type::_xsd_State_type_literals_[i]; - } - - ::std::ostream& - operator<< (::std::ostream& o, const State_type& i) - { - return o << static_cast< const ::xml_schema::String& > (i); - } - - ::std::ostream& - operator<< (::std::ostream& o, const Conference_description_type& i) - { - if (i.getDisplay_text ()) - { - o << ::std::endl << "display-text: " << *i.getDisplay_text (); - } - - if (i.getSubject ()) - { - o << ::std::endl << "subject: " << *i.getSubject (); - } - - if (i.getFree_text ()) - { - o << ::std::endl << "free-text: " << *i.getFree_text (); - } - - if (i.getKeywords ()) - { - o << ::std::endl << "keywords: " << *i.getKeywords (); - } - - if (i.getConf_uris ()) - { - o << ::std::endl << "conf-uris: " << *i.getConf_uris (); - } - - if (i.getService_uris ()) - { - o << ::std::endl << "service-uris: " << *i.getService_uris (); - } - - if (i.getMaximum_user_count ()) - { - o << ::std::endl << "maximum-user-count: " << *i.getMaximum_user_count (); - } - - if (i.getAvailable_media ()) - { - o << ::std::endl << "available-media: " << *i.getAvailable_media (); - } - - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const Host_type& i) - { - if (i.getDisplay_text ()) - { - o << ::std::endl << "display-text: " << *i.getDisplay_text (); - } - - if (i.getWeb_page ()) - { - o << ::std::endl << "web-page: " << *i.getWeb_page (); - } - - if (i.getUris ()) - { - o << ::std::endl << "uris: " << *i.getUris (); - } - - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const Conference_state_type& i) - { - if (i.getUser_count ()) - { - o << ::std::endl << "user-count: " << *i.getUser_count (); - } - - if (i.getActive ()) - { - o << ::std::endl << "active: " << *i.getActive (); - } - - if (i.getLocked ()) - { - o << ::std::endl << "locked: " << *i.getLocked (); - } - - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const Conference_media_type& i) - { - for (Conference_media_type::EntryConstIterator - b (i.getEntry ().begin ()), e (i.getEntry ().end ()); - b != e; ++b) - { - o << ::std::endl << "entry: " << *b; - } - - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const Conference_medium_type& i) - { - if (i.getDisplay_text ()) - { - o << ::std::endl << "display-text: " << *i.getDisplay_text (); - } - - o << ::std::endl << "type: " << i.getType (); - if (i.getStatus ()) - { - o << ::std::endl << "status: " << *i.getStatus (); - } - - o << ::std::endl << "label: " << i.getLabel (); - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const Uris_type& i) - { - for (Uris_type::EntryConstIterator - b (i.getEntry ().begin ()), e (i.getEntry ().end ()); - b != e; ++b) - { - o << ::std::endl << "entry: " << *b; - } - - o << ::std::endl << "state: " << i.getState (); - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const Uri_type& i) - { - o << ::std::endl << "uri: " << i.getUri (); - if (i.getDisplay_text ()) - { - o << ::std::endl << "display-text: " << *i.getDisplay_text (); - } - - if (i.getPurpose ()) - { - o << ::std::endl << "purpose: " << *i.getPurpose (); - } - - if (i.getModified ()) - { - o << ::std::endl << "modified: " << *i.getModified (); - } - - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const Keywords_type& i) - { - return o << static_cast< const ::xsd::cxx::tree::list< ::xml_schema::String, char >& > (i); - } - - ::std::ostream& - operator<< (::std::ostream& o, const Users_type& i) - { - for (Users_type::UserConstIterator - b (i.getUser ().begin ()), e (i.getUser ().end ()); - b != e; ++b) - { - o << ::std::endl << "user: " << *b; - } - - o << ::std::endl << "state: " << i.getState (); - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const User_type& i) - { - if (i.getDisplay_text ()) - { - o << ::std::endl << "display-text: " << *i.getDisplay_text (); - } - - if (i.getAssociated_aors ()) - { - o << ::std::endl << "associated-aors: " << *i.getAssociated_aors (); - } - - if (i.getRoles ()) - { - o << ::std::endl << "roles: " << *i.getRoles (); - } - - if (i.getLanguages ()) - { - o << ::std::endl << "languages: " << *i.getLanguages (); - } - - if (i.getCascaded_focus ()) - { - o << ::std::endl << "cascaded-focus: " << *i.getCascaded_focus (); - } - - for (User_type::EndpointConstIterator - b (i.getEndpoint ().begin ()), e (i.getEndpoint ().end ()); - b != e; ++b) - { - o << ::std::endl << "endpoint: " << *b; - } - - if (i.getEntity ()) - { - o << ::std::endl << "entity: " << *i.getEntity (); - } - - o << ::std::endl << "state: " << i.getState (); - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const User_roles_type& i) - { - for (User_roles_type::EntryConstIterator - b (i.getEntry ().begin ()), e (i.getEntry ().end ()); - b != e; ++b) - { - o << ::std::endl << "entry: " << *b; - } - - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const User_languages_type& i) - { - return o << static_cast< const ::xsd::cxx::tree::list< ::xml_schema::Language, char >& > (i); - } - - ::std::ostream& - operator<< (::std::ostream& o, const Endpoint_type& i) - { - if (i.getDisplay_text ()) - { - o << ::std::endl << "display-text: " << *i.getDisplay_text (); - } - - if (i.getReferred ()) - { - o << ::std::endl << "referred: " << *i.getReferred (); - } - - if (i.getStatus ()) - { - o << ::std::endl << "status: " << *i.getStatus (); - } - - if (i.getJoining_method ()) - { - o << ::std::endl << "joining-method: " << *i.getJoining_method (); - } - - if (i.getJoining_info ()) - { - o << ::std::endl << "joining-info: " << *i.getJoining_info (); - } - - if (i.getDisconnection_method ()) - { - o << ::std::endl << "disconnection-method: " << *i.getDisconnection_method (); - } - - if (i.getDisconnection_info ()) - { - o << ::std::endl << "disconnection-info: " << *i.getDisconnection_info (); - } - - for (Endpoint_type::MediaConstIterator - b (i.getMedia ().begin ()), e (i.getMedia ().end ()); - b != e; ++b) - { - o << ::std::endl << "media: " << *b; - } - - if (i.getCall_info ()) - { - o << ::std::endl << "call-info: " << *i.getCall_info (); - } - - if (i.getEntity ()) - { - o << ::std::endl << "entity: " << *i.getEntity (); - } - - o << ::std::endl << "state: " << i.getState (); - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, Endpoint_status_type::Value i) - { - return o << Endpoint_status_type::_xsd_Endpoint_status_type_literals_[i]; - } - - ::std::ostream& - operator<< (::std::ostream& o, const Endpoint_status_type& i) - { - return o << static_cast< const ::xml_schema::String& > (i); - } - - ::std::ostream& - operator<< (::std::ostream& o, Joining_type::Value i) - { - return o << Joining_type::_xsd_Joining_type_literals_[i]; - } - - ::std::ostream& - operator<< (::std::ostream& o, const Joining_type& i) - { - return o << static_cast< const ::xml_schema::String& > (i); - } - - ::std::ostream& - operator<< (::std::ostream& o, Disconnection_type::Value i) - { - return o << Disconnection_type::_xsd_Disconnection_type_literals_[i]; - } - - ::std::ostream& - operator<< (::std::ostream& o, const Disconnection_type& i) - { - return o << static_cast< const ::xml_schema::String& > (i); - } - - ::std::ostream& - operator<< (::std::ostream& o, const Execution_type& i) - { - if (i.getWhen ()) - { - o << ::std::endl << "when: " << *i.getWhen (); - } - - if (i.getReason ()) - { - o << ::std::endl << "reason: " << *i.getReason (); - } - - if (i.getBy ()) - { - o << ::std::endl << "by: " << *i.getBy (); - } - - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const Call_type& i) - { - if (i.getSip ()) - { - o << ::std::endl << "sip: " << *i.getSip (); - } - - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const Sip_dialog_id_type& i) - { - if (i.getDisplay_text ()) - { - o << ::std::endl << "display-text: " << *i.getDisplay_text (); - } - - o << ::std::endl << "call-id: " << i.getCall_id (); - o << ::std::endl << "from-tag: " << i.getFrom_tag (); - o << ::std::endl << "to-tag: " << i.getTo_tag (); - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const Media_type& i) - { - if (i.getDisplay_text ()) - { - o << ::std::endl << "display-text: " << *i.getDisplay_text (); - } - - if (i.getType ()) - { - o << ::std::endl << "type: " << *i.getType (); - } - - if (i.getLabel ()) - { - o << ::std::endl << "label: " << *i.getLabel (); - } - - if (i.getSrc_id ()) - { - o << ::std::endl << "src-id: " << *i.getSrc_id (); - } - - if (i.getStatus ()) - { - o << ::std::endl << "status: " << *i.getStatus (); - } - - o << ::std::endl << "id: " << i.getId (); - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, Media_status_type::Value i) - { - return o << Media_status_type::_xsd_Media_status_type_literals_[i]; - } - - ::std::ostream& - operator<< (::std::ostream& o, const Media_status_type& i) - { - return o << static_cast< const ::xml_schema::String& > (i); - } - - ::std::ostream& - operator<< (::std::ostream& o, const Sidebars_by_val_type& i) - { - for (Sidebars_by_val_type::EntryConstIterator - b (i.getEntry ().begin ()), e (i.getEntry ().end ()); - b != e; ++b) - { - o << ::std::endl << "entry: " << *b; - } - - o << ::std::endl << "state: " << i.getState (); - return o; } } @@ -7265,272 +7281,278 @@ namespace conference_info #include #include -namespace conference_info +namespace LinphonePrivate { - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (const ::std::string& u, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) + namespace Xsd { - ::xsd::cxx::xml::auto_initializer i ( - (f & ::xml_schema::Flags::dont_initialize) == 0, - (f & ::xml_schema::Flags::keep_dom) == 0); - - ::xsd::cxx::tree::error_handler< char > h; - - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::xsd::cxx::xml::dom::parse< char > ( - u, h, p, f)); - - h.throw_if_failed< ::xsd::cxx::tree::parsing< char > > (); - - return ::std::unique_ptr< ::conference_info::Conference_type > ( - ::conference_info::parseConference_info ( - std::move (d), f | ::xml_schema::Flags::own_dom, p)); - } - - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (const ::std::string& u, - ::xml_schema::ErrorHandler& h, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xsd::cxx::xml::auto_initializer i ( - (f & ::xml_schema::Flags::dont_initialize) == 0, - (f & ::xml_schema::Flags::keep_dom) == 0); - - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::xsd::cxx::xml::dom::parse< char > ( - u, h, p, f)); - - if (!d.get ()) - throw ::xsd::cxx::tree::parsing< char > (); - - return ::std::unique_ptr< ::conference_info::Conference_type > ( - ::conference_info::parseConference_info ( - std::move (d), f | ::xml_schema::Flags::own_dom, p)); - } - - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (const ::std::string& u, - ::xercesc::DOMErrorHandler& h, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::xsd::cxx::xml::dom::parse< char > ( - u, h, p, f)); - - if (!d.get ()) - throw ::xsd::cxx::tree::parsing< char > (); - - return ::std::unique_ptr< ::conference_info::Conference_type > ( - ::conference_info::parseConference_info ( - std::move (d), f | ::xml_schema::Flags::own_dom, p)); - } - - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::std::istream& is, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xsd::cxx::xml::auto_initializer i ( - (f & ::xml_schema::Flags::dont_initialize) == 0, - (f & ::xml_schema::Flags::keep_dom) == 0); - - ::xsd::cxx::xml::sax::std_input_source isrc (is); - return ::conference_info::parseConference_info (isrc, f, p); - } - - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::std::istream& is, - ::xml_schema::ErrorHandler& h, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xsd::cxx::xml::auto_initializer i ( - (f & ::xml_schema::Flags::dont_initialize) == 0, - (f & ::xml_schema::Flags::keep_dom) == 0); - - ::xsd::cxx::xml::sax::std_input_source isrc (is); - return ::conference_info::parseConference_info (isrc, h, f, p); - } - - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::std::istream& is, - ::xercesc::DOMErrorHandler& h, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xsd::cxx::xml::sax::std_input_source isrc (is); - return ::conference_info::parseConference_info (isrc, h, f, p); - } - - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::std::istream& is, - const ::std::string& sid, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xsd::cxx::xml::auto_initializer i ( - (f & ::xml_schema::Flags::dont_initialize) == 0, - (f & ::xml_schema::Flags::keep_dom) == 0); - - ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); - return ::conference_info::parseConference_info (isrc, f, p); - } - - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::std::istream& is, - const ::std::string& sid, - ::xml_schema::ErrorHandler& h, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xsd::cxx::xml::auto_initializer i ( - (f & ::xml_schema::Flags::dont_initialize) == 0, - (f & ::xml_schema::Flags::keep_dom) == 0); - - ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); - return ::conference_info::parseConference_info (isrc, h, f, p); - } - - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::std::istream& is, - const ::std::string& sid, - ::xercesc::DOMErrorHandler& h, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); - return ::conference_info::parseConference_info (isrc, h, f, p); - } - - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::xercesc::InputSource& i, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xsd::cxx::tree::error_handler< char > h; - - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::xsd::cxx::xml::dom::parse< char > ( - i, h, p, f)); - - h.throw_if_failed< ::xsd::cxx::tree::parsing< char > > (); - - return ::std::unique_ptr< ::conference_info::Conference_type > ( - ::conference_info::parseConference_info ( - std::move (d), f | ::xml_schema::Flags::own_dom, p)); - } - - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::xercesc::InputSource& i, - ::xml_schema::ErrorHandler& h, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::xsd::cxx::xml::dom::parse< char > ( - i, h, p, f)); - - if (!d.get ()) - throw ::xsd::cxx::tree::parsing< char > (); - - return ::std::unique_ptr< ::conference_info::Conference_type > ( - ::conference_info::parseConference_info ( - std::move (d), f | ::xml_schema::Flags::own_dom, p)); - } - - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::xercesc::InputSource& i, - ::xercesc::DOMErrorHandler& h, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::xsd::cxx::xml::dom::parse< char > ( - i, h, p, f)); - - if (!d.get ()) - throw ::xsd::cxx::tree::parsing< char > (); - - return ::std::unique_ptr< ::conference_info::Conference_type > ( - ::conference_info::parseConference_info ( - std::move (d), f | ::xml_schema::Flags::own_dom, p)); - } - - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (const ::xercesc::DOMDocument& doc, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - if (f & ::xml_schema::Flags::keep_dom) + namespace ConferenceInfo { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - static_cast< ::xercesc::DOMDocument* > (doc.cloneNode (true))); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (const ::std::string& u, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::dont_initialize) == 0, + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::keep_dom) == 0); - return ::std::unique_ptr< ::conference_info::Conference_type > ( - ::conference_info::parseConference_info ( - std::move (d), f | ::xml_schema::Flags::own_dom, p)); + ::xsd::cxx::tree::error_handler< char > h; + + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + u, h, p, f)); + + h.throw_if_failed< ::xsd::cxx::tree::parsing< char > > (); + + return ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > ( + ::LinphonePrivate::Xsd::ConferenceInfo::parseConferenceInfo ( + std::move (d), f | ::LinphonePrivate::Xsd::XmlSchema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (const ::std::string& u, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& h, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::dont_initialize) == 0, + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::keep_dom) == 0); + + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + u, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > ( + ::LinphonePrivate::Xsd::ConferenceInfo::parseConferenceInfo ( + std::move (d), f | ::LinphonePrivate::Xsd::XmlSchema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (const ::std::string& u, + ::xercesc::DOMErrorHandler& h, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + u, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > ( + ::LinphonePrivate::Xsd::ConferenceInfo::parseConferenceInfo ( + std::move (d), f | ::LinphonePrivate::Xsd::XmlSchema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::std::istream& is, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::dont_initialize) == 0, + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is); + return ::LinphonePrivate::Xsd::ConferenceInfo::parseConferenceInfo (isrc, f, p); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::std::istream& is, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& h, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::dont_initialize) == 0, + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is); + return ::LinphonePrivate::Xsd::ConferenceInfo::parseConferenceInfo (isrc, h, f, p); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::std::istream& is, + ::xercesc::DOMErrorHandler& h, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::xsd::cxx::xml::sax::std_input_source isrc (is); + return ::LinphonePrivate::Xsd::ConferenceInfo::parseConferenceInfo (isrc, h, f, p); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::std::istream& is, + const ::std::string& sid, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::dont_initialize) == 0, + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); + return ::LinphonePrivate::Xsd::ConferenceInfo::parseConferenceInfo (isrc, f, p); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::std::istream& is, + const ::std::string& sid, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& h, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::dont_initialize) == 0, + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); + return ::LinphonePrivate::Xsd::ConferenceInfo::parseConferenceInfo (isrc, h, f, p); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::std::istream& is, + const ::std::string& sid, + ::xercesc::DOMErrorHandler& h, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); + return ::LinphonePrivate::Xsd::ConferenceInfo::parseConferenceInfo (isrc, h, f, p); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::xercesc::InputSource& i, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::xsd::cxx::tree::error_handler< char > h; + + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + i, h, p, f)); + + h.throw_if_failed< ::xsd::cxx::tree::parsing< char > > (); + + return ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > ( + ::LinphonePrivate::Xsd::ConferenceInfo::parseConferenceInfo ( + std::move (d), f | ::LinphonePrivate::Xsd::XmlSchema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::xercesc::InputSource& i, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& h, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + i, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > ( + ::LinphonePrivate::Xsd::ConferenceInfo::parseConferenceInfo ( + std::move (d), f | ::LinphonePrivate::Xsd::XmlSchema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::xercesc::InputSource& i, + ::xercesc::DOMErrorHandler& h, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + i, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > ( + ::LinphonePrivate::Xsd::ConferenceInfo::parseConferenceInfo ( + std::move (d), f | ::LinphonePrivate::Xsd::XmlSchema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (const ::xercesc::DOMDocument& doc, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + if (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::keep_dom) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + static_cast< ::xercesc::DOMDocument* > (doc.cloneNode (true))); + + return ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > ( + ::LinphonePrivate::Xsd::ConferenceInfo::parseConferenceInfo ( + std::move (d), f | ::LinphonePrivate::Xsd::XmlSchema::Flags::own_dom, p)); + } + + const ::xercesc::DOMElement& e (*doc.getDocumentElement ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (e)); + + if (n.name () == "conference-info" && + n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > r ( + ::xsd::cxx::tree::traits< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType, char >::create ( + e, f, 0)); + return r; + } + + throw ::xsd::cxx::tree::unexpected_element < char > ( + n.name (), + n.namespace_ (), + "conference-info", + "urn:ietf:params:xml:ns:conference-info"); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties&) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > c ( + ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::keep_dom) && + !(f & ::LinphonePrivate::Xsd::XmlSchema::Flags::own_dom)) + ? static_cast< ::xercesc::DOMDocument* > (d->cloneNode (true)) + : 0); + + ::xercesc::DOMDocument& doc (c.get () ? *c : *d); + const ::xercesc::DOMElement& e (*doc.getDocumentElement ()); + + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (e)); + + if (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::keep_dom) + doc.setUserData (::LinphonePrivate::Xsd::XmlSchema::dom::treeNodeKey, + (c.get () ? &c : &d), + 0); + + if (n.name () == "conference-info" && + n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > r ( + ::xsd::cxx::tree::traits< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType, char >::create ( + e, f, 0)); + return r; + } + + throw ::xsd::cxx::tree::unexpected_element < char > ( + n.name (), + n.namespace_ (), + "conference-info", + "urn:ietf:params:xml:ns:conference-info"); + } } - - const ::xercesc::DOMElement& e (*doc.getDocumentElement ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (e)); - - if (n.name () == "conference-info" && - n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< ::conference_info::Conference_type > r ( - ::xsd::cxx::tree::traits< ::conference_info::Conference_type, char >::create ( - e, f, 0)); - return r; - } - - throw ::xsd::cxx::tree::unexpected_element < char > ( - n.name (), - n.namespace_ (), - "conference-info", - "urn:ietf:params:xml:ns:conference-info"); - } - - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d, - ::xml_schema::Flags f, - const ::xml_schema::Properties&) - { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > c ( - ((f & ::xml_schema::Flags::keep_dom) && - !(f & ::xml_schema::Flags::own_dom)) - ? static_cast< ::xercesc::DOMDocument* > (d->cloneNode (true)) - : 0); - - ::xercesc::DOMDocument& doc (c.get () ? *c : *d); - const ::xercesc::DOMElement& e (*doc.getDocumentElement ()); - - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (e)); - - if (f & ::xml_schema::Flags::keep_dom) - doc.setUserData (::xml_schema::dom::treeNodeKey, - (c.get () ? &c : &d), - 0); - - if (n.name () == "conference-info" && - n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - ::std::unique_ptr< ::conference_info::Conference_type > r ( - ::xsd::cxx::tree::traits< ::conference_info::Conference_type, char >::create ( - e, f, 0)); - return r; - } - - throw ::xsd::cxx::tree::unexpected_element < char > ( - n.name (), - n.namespace_ (), - "conference-info", - "urn:ietf:params:xml:ns:conference-info"); } } @@ -7538,1733 +7560,1739 @@ namespace conference_info #include #include -namespace conference_info +namespace LinphonePrivate { - void - serializeConference_info (::std::ostream& o, - const ::conference_info::Conference_type& s, - const ::xml_schema::NamespaceInfomap& m, - const ::std::string& e, - ::xml_schema::Flags f) + namespace Xsd { - ::xsd::cxx::xml::auto_initializer i ( - (f & ::xml_schema::Flags::dont_initialize) == 0); - - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::conference_info::serializeConference_info (s, m, f)); - - ::xsd::cxx::tree::error_handler< char > h; - - ::xsd::cxx::xml::dom::ostream_format_target t (o); - if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) - { - h.throw_if_failed< ::xsd::cxx::tree::serialization< char > > (); - } - } - - void - serializeConference_info (::std::ostream& o, - const ::conference_info::Conference_type& s, - ::xml_schema::ErrorHandler& h, - const ::xml_schema::NamespaceInfomap& m, - const ::std::string& e, - ::xml_schema::Flags f) - { - ::xsd::cxx::xml::auto_initializer i ( - (f & ::xml_schema::Flags::dont_initialize) == 0); - - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::conference_info::serializeConference_info (s, m, f)); - ::xsd::cxx::xml::dom::ostream_format_target t (o); - if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) - { - throw ::xsd::cxx::tree::serialization< char > (); - } - } - - void - serializeConference_info (::std::ostream& o, - const ::conference_info::Conference_type& s, - ::xercesc::DOMErrorHandler& h, - const ::xml_schema::NamespaceInfomap& m, - const ::std::string& e, - ::xml_schema::Flags f) - { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::conference_info::serializeConference_info (s, m, f)); - ::xsd::cxx::xml::dom::ostream_format_target t (o); - if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) - { - throw ::xsd::cxx::tree::serialization< char > (); - } - } - - void - serializeConference_info (::xercesc::XMLFormatTarget& t, - const ::conference_info::Conference_type& s, - const ::xml_schema::NamespaceInfomap& m, - const ::std::string& e, - ::xml_schema::Flags f) - { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::conference_info::serializeConference_info (s, m, f)); - - ::xsd::cxx::tree::error_handler< char > h; - - if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) - { - h.throw_if_failed< ::xsd::cxx::tree::serialization< char > > (); - } - } - - void - serializeConference_info (::xercesc::XMLFormatTarget& t, - const ::conference_info::Conference_type& s, - ::xml_schema::ErrorHandler& h, - const ::xml_schema::NamespaceInfomap& m, - const ::std::string& e, - ::xml_schema::Flags f) - { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::conference_info::serializeConference_info (s, m, f)); - if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) - { - throw ::xsd::cxx::tree::serialization< char > (); - } - } - - void - serializeConference_info (::xercesc::XMLFormatTarget& t, - const ::conference_info::Conference_type& s, - ::xercesc::DOMErrorHandler& h, - const ::xml_schema::NamespaceInfomap& m, - const ::std::string& e, - ::xml_schema::Flags f) - { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::conference_info::serializeConference_info (s, m, f)); - if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) - { - throw ::xsd::cxx::tree::serialization< char > (); - } - } - - void - serializeConference_info (::xercesc::DOMDocument& d, - const ::conference_info::Conference_type& s, - ::xml_schema::Flags) - { - ::xercesc::DOMElement& e (*d.getDocumentElement ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (e)); - - if (n.name () == "conference-info" && - n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") - { - e << s; - } - else - { - throw ::xsd::cxx::tree::unexpected_element < char > ( - n.name (), - n.namespace_ (), - "conference-info", - "urn:ietf:params:xml:ns:conference-info"); - } - } - - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > - serializeConference_info (const ::conference_info::Conference_type& s, - const ::xml_schema::NamespaceInfomap& m, - ::xml_schema::Flags f) - { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::xsd::cxx::xml::dom::serialize< char > ( - "conference-info", - "urn:ietf:params:xml:ns:conference-info", - m, f)); - - ::conference_info::serializeConference_info (*d, s, f); - return d; - } - - void - operator<< (::xercesc::DOMElement& e, const Conference_type& i) - { - e << static_cast< const ::xml_schema::Type& > (i); - - // any_attribute - // - for (Conference_type::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } - - // conference-description - // - if (i.getConference_description ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "conference-description", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getConference_description (); - } - - // host-info - // - if (i.getHost_info ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "host-info", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getHost_info (); - } - - // conference-state - // - if (i.getConference_state ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "conference-state", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getConference_state (); - } - - // users - // - if (i.getUsers ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "users", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getUsers (); - } - - // sidebars-by-ref - // - if (i.getSidebars_by_ref ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "sidebars-by-ref", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getSidebars_by_ref (); - } - - // sidebars-by-val - // - if (i.getSidebars_by_val ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "sidebars-by-val", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getSidebars_by_val (); - } - - // any - // - for (Conference_type::AnyConstIterator - b (i.getAny ().begin ()), n (i.getAny ().end ()); - b != n; ++b) - { - e.appendChild ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMElement* > (&(*b)), true)); - } - - // entity - // - { - ::xercesc::DOMAttr& a ( - ::xsd::cxx::xml::dom::create_attribute ( - "entity", - e)); - - a << i.getEntity (); - } - - // state - // - { - ::xercesc::DOMAttr& a ( - ::xsd::cxx::xml::dom::create_attribute ( - "state", - e)); - - a << i.getState (); - } - - // version - // - if (i.getVersion ()) - { - ::xercesc::DOMAttr& a ( - ::xsd::cxx::xml::dom::create_attribute ( - "version", - e)); - - a << *i.getVersion (); - } - } - - void - operator<< (::xercesc::DOMElement& e, const State_type& i) - { - e << static_cast< const ::xml_schema::String& > (i); - } - - void - operator<< (::xercesc::DOMAttr& a, const State_type& i) - { - a << static_cast< const ::xml_schema::String& > (i); - } - - void - operator<< (::xml_schema::ListStream& l, - const State_type& i) - { - l << static_cast< const ::xml_schema::String& > (i); - } - - void - operator<< (::xercesc::DOMElement& e, const Conference_description_type& i) - { - e << static_cast< const ::xml_schema::Type& > (i); - - // any_attribute - // - for (Conference_description_type::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } - - // display-text - // - if (i.getDisplay_text ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "display-text", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getDisplay_text (); - } - - // subject - // - if (i.getSubject ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "subject", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getSubject (); - } - - // free-text - // - if (i.getFree_text ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "free-text", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getFree_text (); - } - - // keywords - // - if (i.getKeywords ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "keywords", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getKeywords (); - } - - // conf-uris - // - if (i.getConf_uris ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "conf-uris", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getConf_uris (); - } - - // service-uris - // - if (i.getService_uris ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "service-uris", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getService_uris (); - } - - // maximum-user-count - // - if (i.getMaximum_user_count ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "maximum-user-count", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getMaximum_user_count (); - } - - // available-media - // - if (i.getAvailable_media ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "available-media", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getAvailable_media (); - } - - // any - // - for (Conference_description_type::AnyConstIterator - b (i.getAny ().begin ()), n (i.getAny ().end ()); - b != n; ++b) - { - e.appendChild ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMElement* > (&(*b)), true)); - } - } - - void - operator<< (::xercesc::DOMElement& e, const Host_type& i) - { - e << static_cast< const ::xml_schema::Type& > (i); - - // any_attribute - // - for (Host_type::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } - - // display-text - // - if (i.getDisplay_text ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "display-text", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getDisplay_text (); - } - - // web-page - // - if (i.getWeb_page ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "web-page", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getWeb_page (); - } - - // uris - // - if (i.getUris ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "uris", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getUris (); - } - - // any - // - for (Host_type::AnyConstIterator - b (i.getAny ().begin ()), n (i.getAny ().end ()); - b != n; ++b) - { - e.appendChild ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMElement* > (&(*b)), true)); - } - } - - void - operator<< (::xercesc::DOMElement& e, const Conference_state_type& i) - { - e << static_cast< const ::xml_schema::Type& > (i); - - // any_attribute - // - for (Conference_state_type::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } - - // user-count - // - if (i.getUser_count ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "user-count", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getUser_count (); - } - - // active - // - if (i.getActive ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "active", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getActive (); - } - - // locked - // - if (i.getLocked ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "locked", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getLocked (); - } - - // any - // - for (Conference_state_type::AnyConstIterator - b (i.getAny ().begin ()), n (i.getAny ().end ()); - b != n; ++b) - { - e.appendChild ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMElement* > (&(*b)), true)); - } - } - - void - operator<< (::xercesc::DOMElement& e, const Conference_media_type& i) - { - e << static_cast< const ::xml_schema::Type& > (i); - - // any_attribute - // - for (Conference_media_type::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } - - // entry - // - for (Conference_media_type::EntryConstIterator - b (i.getEntry ().begin ()), n (i.getEntry ().end ()); - b != n; ++b) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "entry", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *b; - } - } - - void - operator<< (::xercesc::DOMElement& e, const Conference_medium_type& i) - { - e << static_cast< const ::xml_schema::Type& > (i); - - // any_attribute - // - for (Conference_medium_type::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } - - // display-text - // - if (i.getDisplay_text ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "display-text", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getDisplay_text (); - } - - // type - // - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "type", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << i.getType (); - } - - // status - // - if (i.getStatus ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "status", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getStatus (); - } - - // any - // - for (Conference_medium_type::AnyConstIterator - b (i.getAny ().begin ()), n (i.getAny ().end ()); - b != n; ++b) - { - e.appendChild ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMElement* > (&(*b)), true)); - } - - // label - // - { - ::xercesc::DOMAttr& a ( - ::xsd::cxx::xml::dom::create_attribute ( - "label", - e)); - - a << i.getLabel (); - } - } - - void - operator<< (::xercesc::DOMElement& e, const Uris_type& i) - { - e << static_cast< const ::xml_schema::Type& > (i); - - // any_attribute - // - for (Uris_type::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } - - // entry - // - for (Uris_type::EntryConstIterator - b (i.getEntry ().begin ()), n (i.getEntry ().end ()); - b != n; ++b) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "entry", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *b; - } - - // state - // - { - ::xercesc::DOMAttr& a ( - ::xsd::cxx::xml::dom::create_attribute ( - "state", - e)); - - a << i.getState (); - } - } - - void - operator<< (::xercesc::DOMElement& e, const Uri_type& i) - { - e << static_cast< const ::xml_schema::Type& > (i); - - // any_attribute - // - for (Uri_type::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } - - // uri - // - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "uri", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << i.getUri (); - } - - // display-text - // - if (i.getDisplay_text ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "display-text", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getDisplay_text (); - } - - // purpose - // - if (i.getPurpose ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "purpose", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getPurpose (); - } - - // modified - // - if (i.getModified ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "modified", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getModified (); - } - - // any - // - for (Uri_type::AnyConstIterator - b (i.getAny ().begin ()), n (i.getAny ().end ()); - b != n; ++b) - { - e.appendChild ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMElement* > (&(*b)), true)); - } - } - - void - operator<< (::xercesc::DOMElement& e, const Keywords_type& i) - { - e << static_cast< const ::xsd::cxx::tree::list< ::xml_schema::String, char >& > (i); - } - - void - operator<< (::xercesc::DOMAttr& a, const Keywords_type& i) - { - a << static_cast< const ::xsd::cxx::tree::list< ::xml_schema::String, char >& > (i); - } - - void - operator<< (::xml_schema::ListStream& l, - const Keywords_type& i) - { - l << static_cast< const ::xsd::cxx::tree::list< ::xml_schema::String, char >& > (i); - } - - void - operator<< (::xercesc::DOMElement& e, const Users_type& i) - { - e << static_cast< const ::xml_schema::Type& > (i); - - // any_attribute - // - for (Users_type::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } - - // user - // - for (Users_type::UserConstIterator - b (i.getUser ().begin ()), n (i.getUser ().end ()); - b != n; ++b) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "user", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *b; - } - - // any - // - for (Users_type::AnyConstIterator - b (i.getAny ().begin ()), n (i.getAny ().end ()); - b != n; ++b) - { - e.appendChild ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMElement* > (&(*b)), true)); - } - - // state - // - { - ::xercesc::DOMAttr& a ( - ::xsd::cxx::xml::dom::create_attribute ( - "state", - e)); - - a << i.getState (); - } - } - - void - operator<< (::xercesc::DOMElement& e, const User_type& i) - { - e << static_cast< const ::xml_schema::Type& > (i); - - // any_attribute - // - for (User_type::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } - - // display-text - // - if (i.getDisplay_text ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "display-text", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getDisplay_text (); - } - - // associated-aors - // - if (i.getAssociated_aors ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "associated-aors", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getAssociated_aors (); - } - - // roles - // - if (i.getRoles ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "roles", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getRoles (); - } - - // languages - // - if (i.getLanguages ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "languages", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getLanguages (); - } - - // cascaded-focus - // - if (i.getCascaded_focus ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "cascaded-focus", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getCascaded_focus (); - } - - // endpoint - // - for (User_type::EndpointConstIterator - b (i.getEndpoint ().begin ()), n (i.getEndpoint ().end ()); - b != n; ++b) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "endpoint", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *b; - } - - // any - // - for (User_type::AnyConstIterator - b (i.getAny ().begin ()), n (i.getAny ().end ()); - b != n; ++b) - { - e.appendChild ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMElement* > (&(*b)), true)); - } - - // entity - // - if (i.getEntity ()) - { - ::xercesc::DOMAttr& a ( - ::xsd::cxx::xml::dom::create_attribute ( - "entity", - e)); - - a << *i.getEntity (); - } - - // state - // - { - ::xercesc::DOMAttr& a ( - ::xsd::cxx::xml::dom::create_attribute ( - "state", - e)); - - a << i.getState (); - } - } - - void - operator<< (::xercesc::DOMElement& e, const User_roles_type& i) - { - e << static_cast< const ::xml_schema::Type& > (i); - - // any_attribute - // - for (User_roles_type::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } - - // entry - // - for (User_roles_type::EntryConstIterator - b (i.getEntry ().begin ()), n (i.getEntry ().end ()); - b != n; ++b) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "entry", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *b; - } - } - - void - operator<< (::xercesc::DOMElement& e, const User_languages_type& i) - { - e << static_cast< const ::xsd::cxx::tree::list< ::xml_schema::Language, char >& > (i); - } - - void - operator<< (::xercesc::DOMAttr& a, const User_languages_type& i) - { - a << static_cast< const ::xsd::cxx::tree::list< ::xml_schema::Language, char >& > (i); - } - - void - operator<< (::xml_schema::ListStream& l, - const User_languages_type& i) - { - l << static_cast< const ::xsd::cxx::tree::list< ::xml_schema::Language, char >& > (i); - } - - void - operator<< (::xercesc::DOMElement& e, const Endpoint_type& i) - { - e << static_cast< const ::xml_schema::Type& > (i); - - // any_attribute - // - for (Endpoint_type::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } - - // display-text - // - if (i.getDisplay_text ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "display-text", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getDisplay_text (); - } - - // referred - // - if (i.getReferred ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "referred", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getReferred (); - } - - // status - // - if (i.getStatus ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "status", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getStatus (); - } - - // joining-method - // - if (i.getJoining_method ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "joining-method", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getJoining_method (); - } - - // joining-info - // - if (i.getJoining_info ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "joining-info", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getJoining_info (); - } - - // disconnection-method - // - if (i.getDisconnection_method ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "disconnection-method", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getDisconnection_method (); - } - - // disconnection-info - // - if (i.getDisconnection_info ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "disconnection-info", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getDisconnection_info (); - } - - // media - // - for (Endpoint_type::MediaConstIterator - b (i.getMedia ().begin ()), n (i.getMedia ().end ()); - b != n; ++b) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "media", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *b; - } - - // call-info - // - if (i.getCall_info ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "call-info", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getCall_info (); - } - - // any - // - for (Endpoint_type::AnyConstIterator - b (i.getAny ().begin ()), n (i.getAny ().end ()); - b != n; ++b) - { - e.appendChild ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMElement* > (&(*b)), true)); - } - - // entity - // - if (i.getEntity ()) - { - ::xercesc::DOMAttr& a ( - ::xsd::cxx::xml::dom::create_attribute ( - "entity", - e)); - - a << *i.getEntity (); - } - - // state - // - { - ::xercesc::DOMAttr& a ( - ::xsd::cxx::xml::dom::create_attribute ( - "state", - e)); - - a << i.getState (); - } - } - - void - operator<< (::xercesc::DOMElement& e, const Endpoint_status_type& i) - { - e << static_cast< const ::xml_schema::String& > (i); - } - - void - operator<< (::xercesc::DOMAttr& a, const Endpoint_status_type& i) - { - a << static_cast< const ::xml_schema::String& > (i); - } - - void - operator<< (::xml_schema::ListStream& l, - const Endpoint_status_type& i) - { - l << static_cast< const ::xml_schema::String& > (i); - } - - void - operator<< (::xercesc::DOMElement& e, const Joining_type& i) - { - e << static_cast< const ::xml_schema::String& > (i); - } - - void - operator<< (::xercesc::DOMAttr& a, const Joining_type& i) - { - a << static_cast< const ::xml_schema::String& > (i); - } - - void - operator<< (::xml_schema::ListStream& l, - const Joining_type& i) - { - l << static_cast< const ::xml_schema::String& > (i); - } - - void - operator<< (::xercesc::DOMElement& e, const Disconnection_type& i) - { - e << static_cast< const ::xml_schema::String& > (i); - } - - void - operator<< (::xercesc::DOMAttr& a, const Disconnection_type& i) - { - a << static_cast< const ::xml_schema::String& > (i); - } - - void - operator<< (::xml_schema::ListStream& l, - const Disconnection_type& i) - { - l << static_cast< const ::xml_schema::String& > (i); - } - - void - operator<< (::xercesc::DOMElement& e, const Execution_type& i) - { - e << static_cast< const ::xml_schema::Type& > (i); - - // any_attribute - // - for (Execution_type::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } - - // when - // - if (i.getWhen ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "when", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getWhen (); - } - - // reason - // - if (i.getReason ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "reason", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getReason (); - } - - // by - // - if (i.getBy ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "by", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getBy (); - } - } - - void - operator<< (::xercesc::DOMElement& e, const Call_type& i) - { - e << static_cast< const ::xml_schema::Type& > (i); - - // any_attribute - // - for (Call_type::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } - - // sip - // - if (i.getSip ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "sip", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getSip (); - } - - // any - // - for (Call_type::AnyConstIterator - b (i.getAny ().begin ()), n (i.getAny ().end ()); - b != n; ++b) - { - e.appendChild ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMElement* > (&(*b)), true)); - } - } - - void - operator<< (::xercesc::DOMElement& e, const Sip_dialog_id_type& i) - { - e << static_cast< const ::xml_schema::Type& > (i); - - // any_attribute - // - for (Sip_dialog_id_type::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } - - // display-text - // - if (i.getDisplay_text ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "display-text", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getDisplay_text (); - } - - // call-id - // - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "call-id", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << i.getCall_id (); - } - - // from-tag - // - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "from-tag", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << i.getFrom_tag (); - } - - // to-tag - // - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "to-tag", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << i.getTo_tag (); - } - - // any - // - for (Sip_dialog_id_type::AnyConstIterator - b (i.getAny ().begin ()), n (i.getAny ().end ()); - b != n; ++b) - { - e.appendChild ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMElement* > (&(*b)), true)); - } - } - - void - operator<< (::xercesc::DOMElement& e, const Media_type& i) - { - e << static_cast< const ::xml_schema::Type& > (i); - - // any_attribute - // - for (Media_type::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } - - // display-text - // - if (i.getDisplay_text ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "display-text", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getDisplay_text (); - } - - // type - // - if (i.getType ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "type", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getType (); - } - - // label - // - if (i.getLabel ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "label", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getLabel (); - } - - // src-id - // - if (i.getSrc_id ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "src-id", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getSrc_id (); - } - - // status - // - if (i.getStatus ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "status", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *i.getStatus (); - } - - // any - // - for (Media_type::AnyConstIterator - b (i.getAny ().begin ()), n (i.getAny ().end ()); - b != n; ++b) - { - e.appendChild ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMElement* > (&(*b)), true)); - } - - // id - // - { - ::xercesc::DOMAttr& a ( - ::xsd::cxx::xml::dom::create_attribute ( - "id", - e)); - - a << i.getId (); - } - } - - void - operator<< (::xercesc::DOMElement& e, const Media_status_type& i) - { - e << static_cast< const ::xml_schema::String& > (i); - } - - void - operator<< (::xercesc::DOMAttr& a, const Media_status_type& i) - { - a << static_cast< const ::xml_schema::String& > (i); - } - - void - operator<< (::xml_schema::ListStream& l, - const Media_status_type& i) - { - l << static_cast< const ::xml_schema::String& > (i); - } - - void - operator<< (::xercesc::DOMElement& e, const Sidebars_by_val_type& i) - { - e << static_cast< const ::xml_schema::Type& > (i); - - // any_attribute - // - for (Sidebars_by_val_type::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } - - // entry - // - for (Sidebars_by_val_type::EntryConstIterator - b (i.getEntry ().begin ()), n (i.getEntry ().end ()); - b != n; ++b) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "entry", - "urn:ietf:params:xml:ns:conference-info", - e)); - - s << *b; - } - - // state - // - { - ::xercesc::DOMAttr& a ( - ::xsd::cxx::xml::dom::create_attribute ( - "state", - e)); - - a << i.getState (); + namespace ConferenceInfo + { + void + serializeConferenceInfo (::std::ostream& o, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& s, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m, + const ::std::string& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::dont_initialize) == 0); + + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::LinphonePrivate::Xsd::ConferenceInfo::serializeConferenceInfo (s, m, f)); + + ::xsd::cxx::tree::error_handler< char > h; + + ::xsd::cxx::xml::dom::ostream_format_target t (o); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + h.throw_if_failed< ::xsd::cxx::tree::serialization< char > > (); + } + } + + void + serializeConferenceInfo (::std::ostream& o, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& s, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& h, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m, + const ::std::string& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::dont_initialize) == 0); + + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::LinphonePrivate::Xsd::ConferenceInfo::serializeConferenceInfo (s, m, f)); + ::xsd::cxx::xml::dom::ostream_format_target t (o); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + throw ::xsd::cxx::tree::serialization< char > (); + } + } + + void + serializeConferenceInfo (::std::ostream& o, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& s, + ::xercesc::DOMErrorHandler& h, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m, + const ::std::string& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::LinphonePrivate::Xsd::ConferenceInfo::serializeConferenceInfo (s, m, f)); + ::xsd::cxx::xml::dom::ostream_format_target t (o); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + throw ::xsd::cxx::tree::serialization< char > (); + } + } + + void + serializeConferenceInfo (::xercesc::XMLFormatTarget& t, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& s, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m, + const ::std::string& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::LinphonePrivate::Xsd::ConferenceInfo::serializeConferenceInfo (s, m, f)); + + ::xsd::cxx::tree::error_handler< char > h; + + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + h.throw_if_failed< ::xsd::cxx::tree::serialization< char > > (); + } + } + + void + serializeConferenceInfo (::xercesc::XMLFormatTarget& t, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& s, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& h, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m, + const ::std::string& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::LinphonePrivate::Xsd::ConferenceInfo::serializeConferenceInfo (s, m, f)); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + throw ::xsd::cxx::tree::serialization< char > (); + } + } + + void + serializeConferenceInfo (::xercesc::XMLFormatTarget& t, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& s, + ::xercesc::DOMErrorHandler& h, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m, + const ::std::string& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::LinphonePrivate::Xsd::ConferenceInfo::serializeConferenceInfo (s, m, f)); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + throw ::xsd::cxx::tree::serialization< char > (); + } + } + + void + serializeConferenceInfo (::xercesc::DOMDocument& d, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& s, + ::LinphonePrivate::Xsd::XmlSchema::Flags) + { + ::xercesc::DOMElement& e (*d.getDocumentElement ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (e)); + + if (n.name () == "conference-info" && + n.namespace_ () == "urn:ietf:params:xml:ns:conference-info") + { + e << s; + } + else + { + throw ::xsd::cxx::tree::unexpected_element < char > ( + n.name (), + n.namespace_ (), + "conference-info", + "urn:ietf:params:xml:ns:conference-info"); + } + } + + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > + serializeConferenceInfo (const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& s, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::serialize< char > ( + "conference-info", + "urn:ietf:params:xml:ns:conference-info", + m, f)); + + ::LinphonePrivate::Xsd::ConferenceInfo::serializeConferenceInfo (*d, s, f); + return d; + } + + void + operator<< (::xercesc::DOMElement& e, const ConferenceType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); + + // any_attribute + // + for (ConferenceType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // conference-description + // + if (i.getConferenceDescription ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "conference-description", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getConferenceDescription (); + } + + // host-info + // + if (i.getHostInfo ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "host-info", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getHostInfo (); + } + + // conference-state + // + if (i.getConferenceState ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "conference-state", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getConferenceState (); + } + + // users + // + if (i.getUsers ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "users", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getUsers (); + } + + // sidebars-by-ref + // + if (i.getSidebarsByRef ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "sidebars-by-ref", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getSidebarsByRef (); + } + + // sidebars-by-val + // + if (i.getSidebarsByVal ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "sidebars-by-val", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getSidebarsByVal (); + } + + // any + // + for (ConferenceType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + + // entity + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "entity", + e)); + + a << i.getEntity (); + } + + // state + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "state", + e)); + + a << i.getState (); + } + + // version + // + if (i.getVersion ()) + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "version", + e)); + + a << *i.getVersion (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const StateType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + void + operator<< (::xercesc::DOMAttr& a, const StateType& i) + { + a << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + void + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream& l, + const StateType& i) + { + l << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + void + operator<< (::xercesc::DOMElement& e, const ConferenceDescriptionType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); + + // any_attribute + // + for (ConferenceDescriptionType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // display-text + // + if (i.getDisplayText ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-text", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisplayText (); + } + + // subject + // + if (i.getSubject ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "subject", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getSubject (); + } + + // free-text + // + if (i.getFreeText ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "free-text", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getFreeText (); + } + + // keywords + // + if (i.getKeywords ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "keywords", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getKeywords (); + } + + // conf-uris + // + if (i.getConfUris ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "conf-uris", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getConfUris (); + } + + // service-uris + // + if (i.getServiceUris ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "service-uris", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getServiceUris (); + } + + // maximum-user-count + // + if (i.getMaximumUserCount ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "maximum-user-count", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getMaximumUserCount (); + } + + // available-media + // + if (i.getAvailableMedia ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "available-media", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getAvailableMedia (); + } + + // any + // + for (ConferenceDescriptionType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + } + + void + operator<< (::xercesc::DOMElement& e, const HostType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); + + // any_attribute + // + for (HostType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // display-text + // + if (i.getDisplayText ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-text", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisplayText (); + } + + // web-page + // + if (i.getWebPage ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "web-page", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getWebPage (); + } + + // uris + // + if (i.getUris ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "uris", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getUris (); + } + + // any + // + for (HostType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + } + + void + operator<< (::xercesc::DOMElement& e, const ConferenceStateType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); + + // any_attribute + // + for (ConferenceStateType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // user-count + // + if (i.getUserCount ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "user-count", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getUserCount (); + } + + // active + // + if (i.getActive ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "active", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getActive (); + } + + // locked + // + if (i.getLocked ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "locked", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getLocked (); + } + + // any + // + for (ConferenceStateType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + } + + void + operator<< (::xercesc::DOMElement& e, const ConferenceMediaType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); + + // any_attribute + // + for (ConferenceMediaType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // entry + // + for (ConferenceMediaType::EntryConstIterator + b (i.getEntry ().begin ()), n (i.getEntry ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "entry", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *b; + } + } + + void + operator<< (::xercesc::DOMElement& e, const ConferenceMediumType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); + + // any_attribute + // + for (ConferenceMediumType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // display-text + // + if (i.getDisplayText ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-text", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisplayText (); + } + + // type + // + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "type", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << i.getType (); + } + + // status + // + if (i.getStatus ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "status", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getStatus (); + } + + // any + // + for (ConferenceMediumType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + + // label + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "label", + e)); + + a << i.getLabel (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const UrisType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); + + // any_attribute + // + for (UrisType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // entry + // + for (UrisType::EntryConstIterator + b (i.getEntry ().begin ()), n (i.getEntry ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "entry", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *b; + } + + // state + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "state", + e)); + + a << i.getState (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const UriType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); + + // any_attribute + // + for (UriType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // uri + // + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "uri", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << i.getUri (); + } + + // display-text + // + if (i.getDisplayText ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-text", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisplayText (); + } + + // purpose + // + if (i.getPurpose ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "purpose", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getPurpose (); + } + + // modified + // + if (i.getModified ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "modified", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getModified (); + } + + // any + // + for (UriType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + } + + void + operator<< (::xercesc::DOMElement& e, const KeywordsType& i) + { + e << static_cast< const ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::String, char >& > (i); + } + + void + operator<< (::xercesc::DOMAttr& a, const KeywordsType& i) + { + a << static_cast< const ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::String, char >& > (i); + } + + void + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream& l, + const KeywordsType& i) + { + l << static_cast< const ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::String, char >& > (i); + } + + void + operator<< (::xercesc::DOMElement& e, const UsersType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); + + // any_attribute + // + for (UsersType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // user + // + for (UsersType::UserConstIterator + b (i.getUser ().begin ()), n (i.getUser ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "user", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *b; + } + + // any + // + for (UsersType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + + // state + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "state", + e)); + + a << i.getState (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const UserType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); + + // any_attribute + // + for (UserType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // display-text + // + if (i.getDisplayText ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-text", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisplayText (); + } + + // associated-aors + // + if (i.getAssociatedAors ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "associated-aors", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getAssociatedAors (); + } + + // roles + // + if (i.getRoles ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "roles", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getRoles (); + } + + // languages + // + if (i.getLanguages ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "languages", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getLanguages (); + } + + // cascaded-focus + // + if (i.getCascadedFocus ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "cascaded-focus", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getCascadedFocus (); + } + + // endpoint + // + for (UserType::EndpointConstIterator + b (i.getEndpoint ().begin ()), n (i.getEndpoint ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "endpoint", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *b; + } + + // any + // + for (UserType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + + // entity + // + if (i.getEntity ()) + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "entity", + e)); + + a << *i.getEntity (); + } + + // state + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "state", + e)); + + a << i.getState (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const UserRolesType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); + + // any_attribute + // + for (UserRolesType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // entry + // + for (UserRolesType::EntryConstIterator + b (i.getEntry ().begin ()), n (i.getEntry ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "entry", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *b; + } + } + + void + operator<< (::xercesc::DOMElement& e, const UserLanguagesType& i) + { + e << static_cast< const ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::Language, char >& > (i); + } + + void + operator<< (::xercesc::DOMAttr& a, const UserLanguagesType& i) + { + a << static_cast< const ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::Language, char >& > (i); + } + + void + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream& l, + const UserLanguagesType& i) + { + l << static_cast< const ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::Language, char >& > (i); + } + + void + operator<< (::xercesc::DOMElement& e, const EndpointType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); + + // any_attribute + // + for (EndpointType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // display-text + // + if (i.getDisplayText ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-text", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisplayText (); + } + + // referred + // + if (i.getReferred ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "referred", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getReferred (); + } + + // status + // + if (i.getStatus ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "status", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getStatus (); + } + + // joining-method + // + if (i.getJoiningMethod ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "joining-method", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getJoiningMethod (); + } + + // joining-info + // + if (i.getJoiningInfo ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "joining-info", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getJoiningInfo (); + } + + // disconnection-method + // + if (i.getDisconnectionMethod ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "disconnection-method", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisconnectionMethod (); + } + + // disconnection-info + // + if (i.getDisconnectionInfo ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "disconnection-info", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisconnectionInfo (); + } + + // media + // + for (EndpointType::MediaConstIterator + b (i.getMedia ().begin ()), n (i.getMedia ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "media", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *b; + } + + // call-info + // + if (i.getCallInfo ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "call-info", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getCallInfo (); + } + + // any + // + for (EndpointType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + + // entity + // + if (i.getEntity ()) + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "entity", + e)); + + a << *i.getEntity (); + } + + // state + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "state", + e)); + + a << i.getState (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const EndpointStatusType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + void + operator<< (::xercesc::DOMAttr& a, const EndpointStatusType& i) + { + a << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + void + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream& l, + const EndpointStatusType& i) + { + l << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + void + operator<< (::xercesc::DOMElement& e, const JoiningType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + void + operator<< (::xercesc::DOMAttr& a, const JoiningType& i) + { + a << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + void + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream& l, + const JoiningType& i) + { + l << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + void + operator<< (::xercesc::DOMElement& e, const DisconnectionType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + void + operator<< (::xercesc::DOMAttr& a, const DisconnectionType& i) + { + a << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + void + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream& l, + const DisconnectionType& i) + { + l << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + void + operator<< (::xercesc::DOMElement& e, const ExecutionType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); + + // any_attribute + // + for (ExecutionType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // when + // + if (i.getWhen ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "when", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getWhen (); + } + + // reason + // + if (i.getReason ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "reason", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getReason (); + } + + // by + // + if (i.getBy ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "by", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getBy (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const CallType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); + + // any_attribute + // + for (CallType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // sip + // + if (i.getSip ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "sip", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getSip (); + } + + // any + // + for (CallType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + } + + void + operator<< (::xercesc::DOMElement& e, const SipDialogIdType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); + + // any_attribute + // + for (SipDialogIdType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // display-text + // + if (i.getDisplayText ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-text", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisplayText (); + } + + // call-id + // + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "call-id", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << i.getCallId (); + } + + // from-tag + // + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "from-tag", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << i.getFromTag (); + } + + // to-tag + // + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "to-tag", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << i.getToTag (); + } + + // any + // + for (SipDialogIdType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + } + + void + operator<< (::xercesc::DOMElement& e, const MediaType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); + + // any_attribute + // + for (MediaType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // display-text + // + if (i.getDisplayText ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-text", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getDisplayText (); + } + + // type + // + if (i.getType ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "type", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getType (); + } + + // label + // + if (i.getLabel ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "label", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getLabel (); + } + + // src-id + // + if (i.getSrcId ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "src-id", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getSrcId (); + } + + // status + // + if (i.getStatus ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "status", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *i.getStatus (); + } + + // any + // + for (MediaType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } + + // id + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "id", + e)); + + a << i.getId (); + } + } + + void + operator<< (::xercesc::DOMElement& e, const MediaStatusType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + void + operator<< (::xercesc::DOMAttr& a, const MediaStatusType& i) + { + a << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + void + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream& l, + const MediaStatusType& i) + { + l << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + } + + void + operator<< (::xercesc::DOMElement& e, const SidebarsByValType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); + + // any_attribute + // + for (SidebarsByValType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } + + // entry + // + for (SidebarsByValType::EntryConstIterator + b (i.getEntry ().begin ()), n (i.getEntry ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "entry", + "urn:ietf:params:xml:ns:conference-info", + e)); + + s << *b; + } + + // state + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "state", + e)); + + a << i.getState (); + } + } } } } @@ -9273,11 +9301,9 @@ namespace conference_info // Begin epilogue. // - #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic pop #endif - // // End epilogue. diff --git a/src/xml/conference-info.h b/src/xml/conference-info.h index f950882c9..a8bef962a 100644 --- a/src/xml/conference-info.h +++ b/src/xml/conference-info.h @@ -48,12 +48,10 @@ // Begin prologue. // - #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsuggest-override" #endif - // // End prologue. @@ -106,186 +104,198 @@ #include -namespace xml_schema +namespace LinphonePrivate { - // anyType and anySimpleType. - // - typedef ::xsd::cxx::tree::type Type; - typedef ::xsd::cxx::tree::simple_type< char, Type > SimpleType; - typedef ::xsd::cxx::tree::type Container; - - // 8-bit - // - typedef signed char Byte; - typedef unsigned char UnsignedByte; - - // 16-bit - // - typedef short Short; - typedef unsigned short UnsignedShort; - - // 32-bit - // - typedef int Int; - typedef unsigned int UnsignedInt; - - // 64-bit - // - typedef long long Long; - typedef unsigned long long UnsignedLong; - - // Supposed to be arbitrary-length integral types. - // - typedef long long Integer; - typedef long long NonPositiveInteger; - typedef unsigned long long NonNegativeInteger; - typedef unsigned long long PositiveInteger; - typedef long long NegativeInteger; - - // Boolean. - // - typedef bool Boolean; - - // Floating-point types. - // - typedef float Float; - typedef double Double; - typedef double Decimal; - - // String types. - // - typedef ::xsd::cxx::tree::string< char, SimpleType > String; - typedef ::xsd::cxx::tree::normalized_string< char, String > NormalizedString; - typedef ::xsd::cxx::tree::token< char, NormalizedString > Token; - typedef ::xsd::cxx::tree::name< char, Token > Name; - typedef ::xsd::cxx::tree::nmtoken< char, Token > Nmtoken; - typedef ::xsd::cxx::tree::nmtokens< char, SimpleType, Nmtoken > Nmtokens; - typedef ::xsd::cxx::tree::ncname< char, Name > Ncname; - typedef ::xsd::cxx::tree::language< char, Token > Language; - - // ID/IDREF. - // - typedef ::xsd::cxx::tree::id< char, Ncname > Id; - typedef ::xsd::cxx::tree::idref< char, Ncname, Type > Idref; - typedef ::xsd::cxx::tree::idrefs< char, SimpleType, Idref > Idrefs; - - // URI. - // - typedef ::xsd::cxx::tree::uri< char, SimpleType > Uri; - - // Qualified name. - // - typedef ::xsd::cxx::tree::qname< char, SimpleType, Uri, Ncname > Qname; - - // Binary. - // - typedef ::xsd::cxx::tree::buffer< char > Buffer; - typedef ::xsd::cxx::tree::base64_binary< char, SimpleType > Base64Binary; - typedef ::xsd::cxx::tree::hex_binary< char, SimpleType > HexBinary; - - // Date/time. - // - typedef ::xsd::cxx::tree::time_zone TimeZone; - typedef ::xsd::cxx::tree::date< char, SimpleType > Date; - typedef ::xsd::cxx::tree::date_time< char, SimpleType > DateTime; - typedef ::xsd::cxx::tree::duration< char, SimpleType > Duration; - typedef ::xsd::cxx::tree::gday< char, SimpleType > Gday; - typedef ::xsd::cxx::tree::gmonth< char, SimpleType > Gmonth; - typedef ::xsd::cxx::tree::gmonth_day< char, SimpleType > GmonthDay; - typedef ::xsd::cxx::tree::gyear< char, SimpleType > Gyear; - typedef ::xsd::cxx::tree::gyear_month< char, SimpleType > GyearMonth; - typedef ::xsd::cxx::tree::time< char, SimpleType > Time; - - // Entity. - // - typedef ::xsd::cxx::tree::entity< char, Ncname > Entity; - typedef ::xsd::cxx::tree::entities< char, SimpleType, Entity > Entities; - - typedef ::xsd::cxx::tree::content_order ContentOrder; - // Namespace information and list stream. Used in - // serialization functions. - // - typedef ::xsd::cxx::xml::dom::namespace_info< char > NamespaceInfo; - typedef ::xsd::cxx::xml::dom::namespace_infomap< char > NamespaceInfomap; - typedef ::xsd::cxx::tree::list_stream< char > ListStream; - typedef ::xsd::cxx::tree::as_double< Double > AsDouble; - typedef ::xsd::cxx::tree::as_decimal< Decimal > AsDecimal; - typedef ::xsd::cxx::tree::facet Facet; - - // Flags and properties. - // - typedef ::xsd::cxx::tree::flags Flags; - typedef ::xsd::cxx::tree::properties< char > Properties; - - // Parsing/serialization diagnostics. - // - typedef ::xsd::cxx::tree::severity Severity; - typedef ::xsd::cxx::tree::error< char > Error; - typedef ::xsd::cxx::tree::diagnostics< char > Diagnostics; - - // Exceptions. - // - typedef ::xsd::cxx::tree::exception< char > Exception; - typedef ::xsd::cxx::tree::bounds< char > Bounds; - typedef ::xsd::cxx::tree::duplicate_id< char > DuplicateId; - typedef ::xsd::cxx::tree::parsing< char > Parsing; - typedef ::xsd::cxx::tree::expected_element< char > ExpectedElement; - typedef ::xsd::cxx::tree::unexpected_element< char > UnexpectedElement; - typedef ::xsd::cxx::tree::expected_attribute< char > ExpectedAttribute; - typedef ::xsd::cxx::tree::unexpected_enumerator< char > UnexpectedEnumerator; - typedef ::xsd::cxx::tree::expected_text_content< char > ExpectedTextContent; - typedef ::xsd::cxx::tree::no_prefix_mapping< char > NoPrefixMapping; - typedef ::xsd::cxx::tree::serialization< char > Serialization; - - // Error handler callback interface. - // - typedef ::xsd::cxx::xml::error_handler< char > ErrorHandler; - - // DOM interaction. - // - namespace dom + namespace Xsd { - // Automatic pointer for DOMDocument. - // - using ::xsd::cxx::xml::dom::unique_ptr; + namespace XmlSchema + { + // anyType and anySimpleType. + // + typedef ::xsd::cxx::tree::type Type; + typedef ::xsd::cxx::tree::simple_type< char, Type > SimpleType; + typedef ::xsd::cxx::tree::type Container; -#ifndef XSD_CXX_TREE_TREE_NODE_KEY__XML_SCHEMA -#define XSD_CXX_TREE_TREE_NODE_KEY__XML_SCHEMA - // DOM user data key for back pointers to tree nodes. - // - const XMLCh* const treeNodeKey = ::xsd::cxx::tree::user_data_keys::node; + // 8-bit + // + typedef signed char Byte; + typedef unsigned char UnsignedByte; + + // 16-bit + // + typedef short Short; + typedef unsigned short UnsignedShort; + + // 32-bit + // + typedef int Int; + typedef unsigned int UnsignedInt; + + // 64-bit + // + typedef long long Long; + typedef unsigned long long UnsignedLong; + + // Supposed to be arbitrary-length integral types. + // + typedef long long Integer; + typedef long long NonPositiveInteger; + typedef unsigned long long NonNegativeInteger; + typedef unsigned long long PositiveInteger; + typedef long long NegativeInteger; + + // Boolean. + // + typedef bool Boolean; + + // Floating-point types. + // + typedef float Float; + typedef double Double; + typedef double Decimal; + + // String types. + // + typedef ::xsd::cxx::tree::string< char, SimpleType > String; + typedef ::xsd::cxx::tree::normalized_string< char, String > NormalizedString; + typedef ::xsd::cxx::tree::token< char, NormalizedString > Token; + typedef ::xsd::cxx::tree::name< char, Token > Name; + typedef ::xsd::cxx::tree::nmtoken< char, Token > Nmtoken; + typedef ::xsd::cxx::tree::nmtokens< char, SimpleType, Nmtoken > Nmtokens; + typedef ::xsd::cxx::tree::ncname< char, Name > Ncname; + typedef ::xsd::cxx::tree::language< char, Token > Language; + + // ID/IDREF. + // + typedef ::xsd::cxx::tree::id< char, Ncname > Id; + typedef ::xsd::cxx::tree::idref< char, Ncname, Type > Idref; + typedef ::xsd::cxx::tree::idrefs< char, SimpleType, Idref > Idrefs; + + // URI. + // + typedef ::xsd::cxx::tree::uri< char, SimpleType > Uri; + + // Qualified name. + // + typedef ::xsd::cxx::tree::qname< char, SimpleType, Uri, Ncname > Qname; + + // Binary. + // + typedef ::xsd::cxx::tree::buffer< char > Buffer; + typedef ::xsd::cxx::tree::base64_binary< char, SimpleType > Base64Binary; + typedef ::xsd::cxx::tree::hex_binary< char, SimpleType > HexBinary; + + // Date/time. + // + typedef ::xsd::cxx::tree::time_zone TimeZone; + typedef ::xsd::cxx::tree::date< char, SimpleType > Date; + typedef ::xsd::cxx::tree::date_time< char, SimpleType > DateTime; + typedef ::xsd::cxx::tree::duration< char, SimpleType > Duration; + typedef ::xsd::cxx::tree::gday< char, SimpleType > Gday; + typedef ::xsd::cxx::tree::gmonth< char, SimpleType > Gmonth; + typedef ::xsd::cxx::tree::gmonth_day< char, SimpleType > GmonthDay; + typedef ::xsd::cxx::tree::gyear< char, SimpleType > Gyear; + typedef ::xsd::cxx::tree::gyear_month< char, SimpleType > GyearMonth; + typedef ::xsd::cxx::tree::time< char, SimpleType > Time; + + // Entity. + // + typedef ::xsd::cxx::tree::entity< char, Ncname > Entity; + typedef ::xsd::cxx::tree::entities< char, SimpleType, Entity > Entities; + + typedef ::xsd::cxx::tree::content_order ContentOrder; + // Namespace information and list stream. Used in + // serialization functions. + // + typedef ::xsd::cxx::xml::dom::namespace_info< char > NamespaceInfo; + typedef ::xsd::cxx::xml::dom::namespace_infomap< char > NamespaceInfomap; + typedef ::xsd::cxx::tree::list_stream< char > ListStream; + typedef ::xsd::cxx::tree::as_double< Double > AsDouble; + typedef ::xsd::cxx::tree::as_decimal< Decimal > AsDecimal; + typedef ::xsd::cxx::tree::facet Facet; + + // Flags and properties. + // + typedef ::xsd::cxx::tree::flags Flags; + typedef ::xsd::cxx::tree::properties< char > Properties; + + // Parsing/serialization diagnostics. + // + typedef ::xsd::cxx::tree::severity Severity; + typedef ::xsd::cxx::tree::error< char > Error; + typedef ::xsd::cxx::tree::diagnostics< char > Diagnostics; + + // Exceptions. + // + typedef ::xsd::cxx::tree::exception< char > Exception; + typedef ::xsd::cxx::tree::bounds< char > Bounds; + typedef ::xsd::cxx::tree::duplicate_id< char > DuplicateId; + typedef ::xsd::cxx::tree::parsing< char > Parsing; + typedef ::xsd::cxx::tree::expected_element< char > ExpectedElement; + typedef ::xsd::cxx::tree::unexpected_element< char > UnexpectedElement; + typedef ::xsd::cxx::tree::expected_attribute< char > ExpectedAttribute; + typedef ::xsd::cxx::tree::unexpected_enumerator< char > UnexpectedEnumerator; + typedef ::xsd::cxx::tree::expected_text_content< char > ExpectedTextContent; + typedef ::xsd::cxx::tree::no_prefix_mapping< char > NoPrefixMapping; + typedef ::xsd::cxx::tree::serialization< char > Serialization; + + // Error handler callback interface. + // + typedef ::xsd::cxx::xml::error_handler< char > ErrorHandler; + + // DOM interaction. + // + namespace dom + { + // Automatic pointer for DOMDocument. + // + using ::xsd::cxx::xml::dom::unique_ptr; + +#ifndef XSD_CXX_TREE_TREE_NODE_KEY__LINPHONEPRIVATE__XSD__XMLSCHEMA +#define XSD_CXX_TREE_TREE_NODE_KEY__LINPHONEPRIVATE__XSD__XMLSCHEMA + // DOM user data key for back pointers to tree nodes. + // + const XMLCh* const treeNodeKey = ::xsd::cxx::tree::user_data_keys::node; #endif + } + } } } // Forward declarations. // -namespace conference_info +namespace LinphonePrivate { - class Conference_type; - class State_type; - class Conference_description_type; - class Host_type; - class Conference_state_type; - class Conference_media_type; - class Conference_medium_type; - class Uris_type; - class Uri_type; - class Keywords_type; - class Users_type; - class User_type; - class User_roles_type; - class User_languages_type; - class Endpoint_type; - class Endpoint_status_type; - class Joining_type; - class Disconnection_type; - class Execution_type; - class Call_type; - class Sip_dialog_id_type; - class Media_type; - class Media_status_type; - class Sidebars_by_val_type; + namespace Xsd + { + namespace ConferenceInfo + { + class ConferenceType; + class StateType; + class ConferenceDescriptionType; + class HostType; + class ConferenceStateType; + class ConferenceMediaType; + class ConferenceMediumType; + class UrisType; + class UriType; + class KeywordsType; + class UsersType; + class UserType; + class UserRolesType; + class UserLanguagesType; + class EndpointType; + class EndpointStatusType; + class JoiningType; + class DisconnectionType; + class ExecutionType; + class CallType; + class SipDialogIdType; + class MediaType; + class MediaStatusType; + class SidebarsByValType; + } + } } @@ -307,3253 +317,3265 @@ namespace conference_info #include "xml.h" -namespace conference_info +namespace LinphonePrivate { - class Conference_type: public ::xml_schema::Type + namespace Xsd { - public: - // conference-description - // - typedef ::conference_info::Conference_description_type Conference_descriptionType; - typedef ::xsd::cxx::tree::optional< Conference_descriptionType > Conference_descriptionOptional; - typedef ::xsd::cxx::tree::traits< Conference_descriptionType, char > Conference_descriptionTraits; - - const Conference_descriptionOptional& - getConference_description () const; - - Conference_descriptionOptional& - getConference_description (); - - void - setConference_description (const Conference_descriptionType& x); - - void - setConference_description (const Conference_descriptionOptional& x); - - void - setConference_description (::std::unique_ptr< Conference_descriptionType > p); - - // host-info - // - typedef ::conference_info::Host_type Host_infoType; - typedef ::xsd::cxx::tree::optional< Host_infoType > Host_infoOptional; - typedef ::xsd::cxx::tree::traits< Host_infoType, char > Host_infoTraits; - - const Host_infoOptional& - getHost_info () const; - - Host_infoOptional& - getHost_info (); - - void - setHost_info (const Host_infoType& x); - - void - setHost_info (const Host_infoOptional& x); - - void - setHost_info (::std::unique_ptr< Host_infoType > p); - - // conference-state - // - typedef ::conference_info::Conference_state_type Conference_stateType; - typedef ::xsd::cxx::tree::optional< Conference_stateType > Conference_stateOptional; - typedef ::xsd::cxx::tree::traits< Conference_stateType, char > Conference_stateTraits; - - const Conference_stateOptional& - getConference_state () const; - - Conference_stateOptional& - getConference_state (); - - void - setConference_state (const Conference_stateType& x); - - void - setConference_state (const Conference_stateOptional& x); - - void - setConference_state (::std::unique_ptr< Conference_stateType > p); - - // users - // - typedef ::conference_info::Users_type UsersType; - typedef ::xsd::cxx::tree::optional< UsersType > UsersOptional; - typedef ::xsd::cxx::tree::traits< UsersType, char > UsersTraits; - - const UsersOptional& - getUsers () const; - - UsersOptional& - getUsers (); - - void - setUsers (const UsersType& x); - - void - setUsers (const UsersOptional& x); - - void - setUsers (::std::unique_ptr< UsersType > p); - - // sidebars-by-ref - // - typedef ::conference_info::Uris_type Sidebars_by_refType; - typedef ::xsd::cxx::tree::optional< Sidebars_by_refType > Sidebars_by_refOptional; - typedef ::xsd::cxx::tree::traits< Sidebars_by_refType, char > Sidebars_by_refTraits; - - const Sidebars_by_refOptional& - getSidebars_by_ref () const; - - Sidebars_by_refOptional& - getSidebars_by_ref (); - - void - setSidebars_by_ref (const Sidebars_by_refType& x); - - void - setSidebars_by_ref (const Sidebars_by_refOptional& x); - - void - setSidebars_by_ref (::std::unique_ptr< Sidebars_by_refType > p); - - // sidebars-by-val - // - typedef ::conference_info::Sidebars_by_val_type Sidebars_by_valType; - typedef ::xsd::cxx::tree::optional< Sidebars_by_valType > Sidebars_by_valOptional; - typedef ::xsd::cxx::tree::traits< Sidebars_by_valType, char > Sidebars_by_valTraits; - - const Sidebars_by_valOptional& - getSidebars_by_val () const; - - Sidebars_by_valOptional& - getSidebars_by_val (); - - void - setSidebars_by_val (const Sidebars_by_valType& x); - - void - setSidebars_by_val (const Sidebars_by_valOptional& x); - - void - setSidebars_by_val (::std::unique_ptr< Sidebars_by_valType > p); - - // any - // - typedef ::xsd::cxx::tree::element_sequence AnySequence; - typedef AnySequence::iterator AnyIterator; - typedef AnySequence::const_iterator AnyConstIterator; - - const AnySequence& - getAny () const; - - AnySequence& - getAny (); - - void - setAny (const AnySequence& s); - - // entity - // - typedef ::xml_schema::Uri EntityType; - typedef ::xsd::cxx::tree::traits< EntityType, char > EntityTraits; - - const EntityType& - getEntity () const; - - EntityType& - getEntity (); - - void - setEntity (const EntityType& x); - - void - setEntity (::std::unique_ptr< EntityType > p); - - ::std::unique_ptr< EntityType > - detachEntity (); - - // state - // - typedef ::conference_info::State_type StateType; - typedef ::xsd::cxx::tree::traits< StateType, char > StateTraits; - - const StateType& - getState () const; - - StateType& - getState (); - - void - setState (const StateType& x); - - void - setState (::std::unique_ptr< StateType > p); - - ::std::unique_ptr< StateType > - detachState (); - - static const StateType& - getStateDefaultValue (); - - // version - // - typedef ::xml_schema::UnsignedInt VersionType; - typedef ::xsd::cxx::tree::optional< VersionType > VersionOptional; - typedef ::xsd::cxx::tree::traits< VersionType, char > VersionTraits; - - const VersionOptional& - getVersion () const; - - VersionOptional& - getVersion (); - - void - setVersion (const VersionType& x); - - void - setVersion (const VersionOptional& x); - - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - - const AnyAttributeSet& - getAnyAttribute () const; - - AnyAttributeSet& - getAnyAttribute (); - - void - setAnyAttribute (const AnyAttributeSet& s); - - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; - - ::xercesc::DOMDocument& - getDomDocument (); - - // Constructors. - // - Conference_type (const EntityType&); - - Conference_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Conference_type (const Conference_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Conference_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Conference_type& - operator= (const Conference_type& x); - - virtual - ~Conference_type (); - - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); - - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - - Conference_descriptionOptional conference_description_; - Host_infoOptional host_info_; - Conference_stateOptional conference_state_; - UsersOptional users_; - Sidebars_by_refOptional sidebars_by_ref_; - Sidebars_by_valOptional sidebars_by_val_; - AnySequence any_; - ::xsd::cxx::tree::one< EntityType > entity_; - ::xsd::cxx::tree::one< StateType > state_; - static const StateType state_default_value_; - VersionOptional version_; - AnyAttributeSet any_attribute_; - }; - - class State_type: public ::xml_schema::String - { - public: - enum Value + namespace ConferenceInfo { - full, - partial, - deleted - }; + class ConferenceType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // conference-description + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceDescriptionType ConferenceDescriptionType; + typedef ::xsd::cxx::tree::optional< ConferenceDescriptionType > ConferenceDescriptionOptional; + typedef ::xsd::cxx::tree::traits< ConferenceDescriptionType, char > ConferenceDescriptionTraits; - State_type (Value v); + const ConferenceDescriptionOptional& + getConferenceDescription () const; - State_type (const char* v); + ConferenceDescriptionOptional& + getConferenceDescription (); - State_type (const ::std::string& v); + void + setConferenceDescription (const ConferenceDescriptionType& x); - State_type (const ::xml_schema::String& v); + void + setConferenceDescription (const ConferenceDescriptionOptional& x); - State_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + void + setConferenceDescription (::std::unique_ptr< ConferenceDescriptionType > p); - State_type (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + // host-info + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::HostType HostInfoType; + typedef ::xsd::cxx::tree::optional< HostInfoType > HostInfoOptional; + typedef ::xsd::cxx::tree::traits< HostInfoType, char > HostInfoTraits; - State_type (const ::std::string& s, - const ::xercesc::DOMElement* e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + const HostInfoOptional& + getHostInfo () const; - State_type (const State_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + HostInfoOptional& + getHostInfo (); - virtual State_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; + void + setHostInfo (const HostInfoType& x); - State_type& - operator= (Value v); + void + setHostInfo (const HostInfoOptional& x); - virtual - operator Value () const - { - return _xsd_State_type_convert (); - } + void + setHostInfo (::std::unique_ptr< HostInfoType > p); - protected: - Value - _xsd_State_type_convert () const; + // conference-state + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceStateType ConferenceStateType; + typedef ::xsd::cxx::tree::optional< ConferenceStateType > ConferenceStateOptional; + typedef ::xsd::cxx::tree::traits< ConferenceStateType, char > ConferenceStateTraits; - public: - static const char* const _xsd_State_type_literals_[3]; - static const Value _xsd_State_type_indexes_[3]; - }; + const ConferenceStateOptional& + getConferenceState () const; - class Conference_description_type: public ::xml_schema::Type - { - public: - // display-text - // - typedef ::xml_schema::String Display_textType; - typedef ::xsd::cxx::tree::optional< Display_textType > Display_textOptional; - typedef ::xsd::cxx::tree::traits< Display_textType, char > Display_textTraits; + ConferenceStateOptional& + getConferenceState (); - const Display_textOptional& - getDisplay_text () const; + void + setConferenceState (const ConferenceStateType& x); - Display_textOptional& - getDisplay_text (); + void + setConferenceState (const ConferenceStateOptional& x); - void - setDisplay_text (const Display_textType& x); + void + setConferenceState (::std::unique_ptr< ConferenceStateType > p); - void - setDisplay_text (const Display_textOptional& x); + // users + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::UsersType UsersType; + typedef ::xsd::cxx::tree::optional< UsersType > UsersOptional; + typedef ::xsd::cxx::tree::traits< UsersType, char > UsersTraits; - void - setDisplay_text (::std::unique_ptr< Display_textType > p); + const UsersOptional& + getUsers () const; - // subject - // - typedef ::xml_schema::String SubjectType; - typedef ::xsd::cxx::tree::optional< SubjectType > SubjectOptional; - typedef ::xsd::cxx::tree::traits< SubjectType, char > SubjectTraits; + UsersOptional& + getUsers (); - const SubjectOptional& - getSubject () const; + void + setUsers (const UsersType& x); - SubjectOptional& - getSubject (); + void + setUsers (const UsersOptional& x); - void - setSubject (const SubjectType& x); + void + setUsers (::std::unique_ptr< UsersType > p); - void - setSubject (const SubjectOptional& x); + // sidebars-by-ref + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::UrisType SidebarsByRefType; + typedef ::xsd::cxx::tree::optional< SidebarsByRefType > SidebarsByRefOptional; + typedef ::xsd::cxx::tree::traits< SidebarsByRefType, char > SidebarsByRefTraits; - void - setSubject (::std::unique_ptr< SubjectType > p); + const SidebarsByRefOptional& + getSidebarsByRef () const; - // free-text - // - typedef ::xml_schema::String Free_textType; - typedef ::xsd::cxx::tree::optional< Free_textType > Free_textOptional; - typedef ::xsd::cxx::tree::traits< Free_textType, char > Free_textTraits; + SidebarsByRefOptional& + getSidebarsByRef (); - const Free_textOptional& - getFree_text () const; + void + setSidebarsByRef (const SidebarsByRefType& x); - Free_textOptional& - getFree_text (); + void + setSidebarsByRef (const SidebarsByRefOptional& x); - void - setFree_text (const Free_textType& x); + void + setSidebarsByRef (::std::unique_ptr< SidebarsByRefType > p); - void - setFree_text (const Free_textOptional& x); + // sidebars-by-val + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::SidebarsByValType SidebarsByValType; + typedef ::xsd::cxx::tree::optional< SidebarsByValType > SidebarsByValOptional; + typedef ::xsd::cxx::tree::traits< SidebarsByValType, char > SidebarsByValTraits; - void - setFree_text (::std::unique_ptr< Free_textType > p); + const SidebarsByValOptional& + getSidebarsByVal () const; - // keywords - // - typedef ::conference_info::Keywords_type KeywordsType; - typedef ::xsd::cxx::tree::optional< KeywordsType > KeywordsOptional; - typedef ::xsd::cxx::tree::traits< KeywordsType, char > KeywordsTraits; + SidebarsByValOptional& + getSidebarsByVal (); - const KeywordsOptional& - getKeywords () const; + void + setSidebarsByVal (const SidebarsByValType& x); - KeywordsOptional& - getKeywords (); + void + setSidebarsByVal (const SidebarsByValOptional& x); - void - setKeywords (const KeywordsType& x); + void + setSidebarsByVal (::std::unique_ptr< SidebarsByValType > p); - void - setKeywords (const KeywordsOptional& x); + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; - void - setKeywords (::std::unique_ptr< KeywordsType > p); + const AnySequence& + getAny () const; - // conf-uris - // - typedef ::conference_info::Uris_type Conf_urisType; - typedef ::xsd::cxx::tree::optional< Conf_urisType > Conf_urisOptional; - typedef ::xsd::cxx::tree::traits< Conf_urisType, char > Conf_urisTraits; + AnySequence& + getAny (); - const Conf_urisOptional& - getConf_uris () const; + void + setAny (const AnySequence& s); - Conf_urisOptional& - getConf_uris (); + // entity + // + typedef ::LinphonePrivate::Xsd::XmlSchema::Uri EntityType; + typedef ::xsd::cxx::tree::traits< EntityType, char > EntityTraits; - void - setConf_uris (const Conf_urisType& x); + const EntityType& + getEntity () const; - void - setConf_uris (const Conf_urisOptional& x); + EntityType& + getEntity (); - void - setConf_uris (::std::unique_ptr< Conf_urisType > p); + void + setEntity (const EntityType& x); - // service-uris - // - typedef ::conference_info::Uris_type Service_urisType; - typedef ::xsd::cxx::tree::optional< Service_urisType > Service_urisOptional; - typedef ::xsd::cxx::tree::traits< Service_urisType, char > Service_urisTraits; + void + setEntity (::std::unique_ptr< EntityType > p); - const Service_urisOptional& - getService_uris () const; + ::std::unique_ptr< EntityType > + setDetachEntity (); - Service_urisOptional& - getService_uris (); + // state + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::StateType StateType; + typedef ::xsd::cxx::tree::traits< StateType, char > StateTraits; - void - setService_uris (const Service_urisType& x); + const StateType& + getState () const; - void - setService_uris (const Service_urisOptional& x); + StateType& + getState (); - void - setService_uris (::std::unique_ptr< Service_urisType > p); + void + setState (const StateType& x); - // maximum-user-count - // - typedef ::xml_schema::UnsignedInt Maximum_user_countType; - typedef ::xsd::cxx::tree::optional< Maximum_user_countType > Maximum_user_countOptional; - typedef ::xsd::cxx::tree::traits< Maximum_user_countType, char > Maximum_user_countTraits; + void + setState (::std::unique_ptr< StateType > p); - const Maximum_user_countOptional& - getMaximum_user_count () const; + ::std::unique_ptr< StateType > + setDetachState (); - Maximum_user_countOptional& - getMaximum_user_count (); + static const StateType& + getStateDefaultValue (); - void - setMaximum_user_count (const Maximum_user_countType& x); + // version + // + typedef ::LinphonePrivate::Xsd::XmlSchema::UnsignedInt VersionType; + typedef ::xsd::cxx::tree::optional< VersionType > VersionOptional; + typedef ::xsd::cxx::tree::traits< VersionType, char > VersionTraits; - void - setMaximum_user_count (const Maximum_user_countOptional& x); + const VersionOptional& + getVersion () const; - // available-media - // - typedef ::conference_info::Conference_media_type Available_mediaType; - typedef ::xsd::cxx::tree::optional< Available_mediaType > Available_mediaOptional; - typedef ::xsd::cxx::tree::traits< Available_mediaType, char > Available_mediaTraits; + VersionOptional& + getVersion (); - const Available_mediaOptional& - getAvailable_media () const; + void + setVersion (const VersionType& x); - Available_mediaOptional& - getAvailable_media (); + void + setVersion (const VersionOptional& x); - void - setAvailable_media (const Available_mediaType& x); + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - void - setAvailable_media (const Available_mediaOptional& x); + const AnyAttributeSet& + getAnyAttribute () const; - void - setAvailable_media (::std::unique_ptr< Available_mediaType > p); + AnyAttributeSet& + getAnyAttribute (); - // any - // - typedef ::xsd::cxx::tree::element_sequence AnySequence; - typedef AnySequence::iterator AnyIterator; - typedef AnySequence::const_iterator AnyConstIterator; + void + setAnyAttribute (const AnyAttributeSet& s); - const AnySequence& - getAny () const; + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; - AnySequence& - getAny (); + ::xercesc::DOMDocument& + getDomDocument (); - void - setAny (const AnySequence& s); + // Constructors. + // + ConferenceType (const EntityType&); - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + ConferenceType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - const AnyAttributeSet& - getAnyAttribute () const; + ConferenceType (const ConferenceType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - AnyAttributeSet& - getAnyAttribute (); + virtual ConferenceType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; - void - setAnyAttribute (const AnyAttributeSet& s); + ConferenceType& + operator= (const ConferenceType& x); - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; + virtual + ~ConferenceType (); - ::xercesc::DOMDocument& - getDomDocument (); + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); - // Constructors. - // - Conference_description_type (); + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - Conference_description_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + ConferenceDescriptionOptional conference_description_; + HostInfoOptional host_info_; + ConferenceStateOptional conference_state_; + UsersOptional users_; + SidebarsByRefOptional sidebars_by_ref_; + SidebarsByValOptional sidebars_by_val_; + AnySequence any_; + ::xsd::cxx::tree::one< EntityType > entity_; + ::xsd::cxx::tree::one< StateType > state_; + static const StateType state_default_value_; + VersionOptional version_; + AnyAttributeSet any_attribute_; + }; - Conference_description_type (const Conference_description_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + class StateType: public ::LinphonePrivate::Xsd::XmlSchema::String + { + public: + enum Value + { + full, + partial, + deleted + }; - virtual Conference_description_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; + StateType (Value v); + + StateType (const char* v); + + StateType (const ::std::string& v); + + StateType (const ::LinphonePrivate::Xsd::XmlSchema::String& v); - Conference_description_type& - operator= (const Conference_description_type& x); + StateType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - virtual - ~Conference_description_type (); - - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); - - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - - Display_textOptional display_text_; - SubjectOptional subject_; - Free_textOptional free_text_; - KeywordsOptional keywords_; - Conf_urisOptional conf_uris_; - Service_urisOptional service_uris_; - Maximum_user_countOptional maximum_user_count_; - Available_mediaOptional available_media_; - AnySequence any_; - AnyAttributeSet any_attribute_; - }; - - class Host_type: public ::xml_schema::Type - { - public: - // display-text - // - typedef ::xml_schema::String Display_textType; - typedef ::xsd::cxx::tree::optional< Display_textType > Display_textOptional; - typedef ::xsd::cxx::tree::traits< Display_textType, char > Display_textTraits; - - const Display_textOptional& - getDisplay_text () const; - - Display_textOptional& - getDisplay_text (); - - void - setDisplay_text (const Display_textType& x); - - void - setDisplay_text (const Display_textOptional& x); - - void - setDisplay_text (::std::unique_ptr< Display_textType > p); - - // web-page - // - typedef ::xml_schema::Uri Web_pageType; - typedef ::xsd::cxx::tree::optional< Web_pageType > Web_pageOptional; - typedef ::xsd::cxx::tree::traits< Web_pageType, char > Web_pageTraits; - - const Web_pageOptional& - getWeb_page () const; - - Web_pageOptional& - getWeb_page (); - - void - setWeb_page (const Web_pageType& x); - - void - setWeb_page (const Web_pageOptional& x); - - void - setWeb_page (::std::unique_ptr< Web_pageType > p); - - // uris - // - typedef ::conference_info::Uris_type UrisType; - typedef ::xsd::cxx::tree::optional< UrisType > UrisOptional; - typedef ::xsd::cxx::tree::traits< UrisType, char > UrisTraits; - - const UrisOptional& - getUris () const; - - UrisOptional& - getUris (); - - void - setUris (const UrisType& x); - - void - setUris (const UrisOptional& x); - - void - setUris (::std::unique_ptr< UrisType > p); - - // any - // - typedef ::xsd::cxx::tree::element_sequence AnySequence; - typedef AnySequence::iterator AnyIterator; - typedef AnySequence::const_iterator AnyConstIterator; - - const AnySequence& - getAny () const; - - AnySequence& - getAny (); - - void - setAny (const AnySequence& s); - - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - - const AnyAttributeSet& - getAnyAttribute () const; - - AnyAttributeSet& - getAnyAttribute (); - - void - setAnyAttribute (const AnyAttributeSet& s); - - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; - - ::xercesc::DOMDocument& - getDomDocument (); - - // Constructors. - // - Host_type (); - - Host_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Host_type (const Host_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Host_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Host_type& - operator= (const Host_type& x); - - virtual - ~Host_type (); - - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); - - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - - Display_textOptional display_text_; - Web_pageOptional web_page_; - UrisOptional uris_; - AnySequence any_; - AnyAttributeSet any_attribute_; - }; - - class Conference_state_type: public ::xml_schema::Type - { - public: - // user-count - // - typedef ::xml_schema::UnsignedInt User_countType; - typedef ::xsd::cxx::tree::optional< User_countType > User_countOptional; - typedef ::xsd::cxx::tree::traits< User_countType, char > User_countTraits; - - const User_countOptional& - getUser_count () const; - - User_countOptional& - getUser_count (); - - void - setUser_count (const User_countType& x); - - void - setUser_count (const User_countOptional& x); - - // active - // - typedef ::xml_schema::Boolean ActiveType; - typedef ::xsd::cxx::tree::optional< ActiveType > ActiveOptional; - typedef ::xsd::cxx::tree::traits< ActiveType, char > ActiveTraits; - - const ActiveOptional& - getActive () const; - - ActiveOptional& - getActive (); - - void - setActive (const ActiveType& x); - - void - setActive (const ActiveOptional& x); - - // locked - // - typedef ::xml_schema::Boolean LockedType; - typedef ::xsd::cxx::tree::optional< LockedType > LockedOptional; - typedef ::xsd::cxx::tree::traits< LockedType, char > LockedTraits; - - const LockedOptional& - getLocked () const; - - LockedOptional& - getLocked (); - - void - setLocked (const LockedType& x); - - void - setLocked (const LockedOptional& x); - - // any - // - typedef ::xsd::cxx::tree::element_sequence AnySequence; - typedef AnySequence::iterator AnyIterator; - typedef AnySequence::const_iterator AnyConstIterator; - - const AnySequence& - getAny () const; - - AnySequence& - getAny (); - - void - setAny (const AnySequence& s); - - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - - const AnyAttributeSet& - getAnyAttribute () const; - - AnyAttributeSet& - getAnyAttribute (); - - void - setAnyAttribute (const AnyAttributeSet& s); - - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; - - ::xercesc::DOMDocument& - getDomDocument (); - - // Constructors. - // - Conference_state_type (); - - Conference_state_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Conference_state_type (const Conference_state_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Conference_state_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Conference_state_type& - operator= (const Conference_state_type& x); - - virtual - ~Conference_state_type (); - - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); - - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - - User_countOptional user_count_; - ActiveOptional active_; - LockedOptional locked_; - AnySequence any_; - AnyAttributeSet any_attribute_; - }; - - class Conference_media_type: public ::xml_schema::Type - { - public: - // entry - // - typedef ::conference_info::Conference_medium_type EntryType; - typedef ::xsd::cxx::tree::sequence< EntryType > EntrySequence; - typedef EntrySequence::iterator EntryIterator; - typedef EntrySequence::const_iterator EntryConstIterator; - typedef ::xsd::cxx::tree::traits< EntryType, char > EntryTraits; - - const EntrySequence& - getEntry () const; - - EntrySequence& - getEntry (); - - void - setEntry (const EntrySequence& s); - - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - - const AnyAttributeSet& - getAnyAttribute () const; - - AnyAttributeSet& - getAnyAttribute (); - - void - setAnyAttribute (const AnyAttributeSet& s); - - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; - - ::xercesc::DOMDocument& - getDomDocument (); - - // Constructors. - // - Conference_media_type (); - - Conference_media_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Conference_media_type (const Conference_media_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Conference_media_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Conference_media_type& - operator= (const Conference_media_type& x); - - virtual - ~Conference_media_type (); - - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); - - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - - EntrySequence entry_; - AnyAttributeSet any_attribute_; - }; - - class Conference_medium_type: public ::xml_schema::Type - { - public: - // display-text - // - typedef ::xml_schema::String Display_textType; - typedef ::xsd::cxx::tree::optional< Display_textType > Display_textOptional; - typedef ::xsd::cxx::tree::traits< Display_textType, char > Display_textTraits; - - const Display_textOptional& - getDisplay_text () const; - - Display_textOptional& - getDisplay_text (); - - void - setDisplay_text (const Display_textType& x); - - void - setDisplay_text (const Display_textOptional& x); - - void - setDisplay_text (::std::unique_ptr< Display_textType > p); - - // type - // - typedef ::xml_schema::String TypeType; - typedef ::xsd::cxx::tree::traits< TypeType, char > TypeTraits; - - const TypeType& - getType () const; - - TypeType& - getType (); - - void - setType (const TypeType& x); - - void - setType (::std::unique_ptr< TypeType > p); - - ::std::unique_ptr< TypeType > - detachType (); - - // status - // - typedef ::conference_info::Media_status_type StatusType; - typedef ::xsd::cxx::tree::optional< StatusType > StatusOptional; - typedef ::xsd::cxx::tree::traits< StatusType, char > StatusTraits; - - const StatusOptional& - getStatus () const; - - StatusOptional& - getStatus (); - - void - setStatus (const StatusType& x); - - void - setStatus (const StatusOptional& x); - - void - setStatus (::std::unique_ptr< StatusType > p); - - // any - // - typedef ::xsd::cxx::tree::element_sequence AnySequence; - typedef AnySequence::iterator AnyIterator; - typedef AnySequence::const_iterator AnyConstIterator; - - const AnySequence& - getAny () const; - - AnySequence& - getAny (); - - void - setAny (const AnySequence& s); - - // label - // - typedef ::xml_schema::String LabelType; - typedef ::xsd::cxx::tree::traits< LabelType, char > LabelTraits; - - const LabelType& - getLabel () const; - - LabelType& - getLabel (); - - void - setLabel (const LabelType& x); - - void - setLabel (::std::unique_ptr< LabelType > p); - - ::std::unique_ptr< LabelType > - detachLabel (); - - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - - const AnyAttributeSet& - getAnyAttribute () const; - - AnyAttributeSet& - getAnyAttribute (); - - void - setAnyAttribute (const AnyAttributeSet& s); - - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; - - ::xercesc::DOMDocument& - getDomDocument (); - - // Constructors. - // - Conference_medium_type (const TypeType&, - const LabelType&); - - Conference_medium_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Conference_medium_type (const Conference_medium_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Conference_medium_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Conference_medium_type& - operator= (const Conference_medium_type& x); - - virtual - ~Conference_medium_type (); - - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); - - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - - Display_textOptional display_text_; - ::xsd::cxx::tree::one< TypeType > type_; - StatusOptional status_; - AnySequence any_; - ::xsd::cxx::tree::one< LabelType > label_; - AnyAttributeSet any_attribute_; - }; - - class Uris_type: public ::xml_schema::Type - { - public: - // entry - // - typedef ::conference_info::Uri_type EntryType; - typedef ::xsd::cxx::tree::sequence< EntryType > EntrySequence; - typedef EntrySequence::iterator EntryIterator; - typedef EntrySequence::const_iterator EntryConstIterator; - typedef ::xsd::cxx::tree::traits< EntryType, char > EntryTraits; - - const EntrySequence& - getEntry () const; - - EntrySequence& - getEntry (); - - void - setEntry (const EntrySequence& s); - - // state - // - typedef ::conference_info::State_type StateType; - typedef ::xsd::cxx::tree::traits< StateType, char > StateTraits; - - const StateType& - getState () const; - - StateType& - getState (); - - void - setState (const StateType& x); - - void - setState (::std::unique_ptr< StateType > p); - - ::std::unique_ptr< StateType > - detachState (); - - static const StateType& - getStateDefaultValue (); - - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - - const AnyAttributeSet& - getAnyAttribute () const; - - AnyAttributeSet& - getAnyAttribute (); - - void - setAnyAttribute (const AnyAttributeSet& s); - - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; - - ::xercesc::DOMDocument& - getDomDocument (); - - // Constructors. - // - Uris_type (); - - Uris_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Uris_type (const Uris_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Uris_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Uris_type& - operator= (const Uris_type& x); - - virtual - ~Uris_type (); - - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); - - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - - EntrySequence entry_; - ::xsd::cxx::tree::one< StateType > state_; - static const StateType state_default_value_; - AnyAttributeSet any_attribute_; - }; - - class Uri_type: public ::xml_schema::Type - { - public: - // uri - // - typedef ::xml_schema::Uri UriType; - typedef ::xsd::cxx::tree::traits< UriType, char > UriTraits; - - const UriType& - getUri () const; - - UriType& - getUri (); - - void - setUri (const UriType& x); - - void - setUri (::std::unique_ptr< UriType > p); - - ::std::unique_ptr< UriType > - detachUri (); - - // display-text - // - typedef ::xml_schema::String Display_textType; - typedef ::xsd::cxx::tree::optional< Display_textType > Display_textOptional; - typedef ::xsd::cxx::tree::traits< Display_textType, char > Display_textTraits; - - const Display_textOptional& - getDisplay_text () const; - - Display_textOptional& - getDisplay_text (); - - void - setDisplay_text (const Display_textType& x); - - void - setDisplay_text (const Display_textOptional& x); - - void - setDisplay_text (::std::unique_ptr< Display_textType > p); - - // purpose - // - typedef ::xml_schema::String PurposeType; - typedef ::xsd::cxx::tree::optional< PurposeType > PurposeOptional; - typedef ::xsd::cxx::tree::traits< PurposeType, char > PurposeTraits; - - const PurposeOptional& - getPurpose () const; - - PurposeOptional& - getPurpose (); - - void - setPurpose (const PurposeType& x); - - void - setPurpose (const PurposeOptional& x); - - void - setPurpose (::std::unique_ptr< PurposeType > p); - - // modified - // - typedef ::conference_info::Execution_type ModifiedType; - typedef ::xsd::cxx::tree::optional< ModifiedType > ModifiedOptional; - typedef ::xsd::cxx::tree::traits< ModifiedType, char > ModifiedTraits; - - const ModifiedOptional& - getModified () const; - - ModifiedOptional& - getModified (); - - void - setModified (const ModifiedType& x); - - void - setModified (const ModifiedOptional& x); - - void - setModified (::std::unique_ptr< ModifiedType > p); - - // any - // - typedef ::xsd::cxx::tree::element_sequence AnySequence; - typedef AnySequence::iterator AnyIterator; - typedef AnySequence::const_iterator AnyConstIterator; - - const AnySequence& - getAny () const; - - AnySequence& - getAny (); - - void - setAny (const AnySequence& s); - - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - - const AnyAttributeSet& - getAnyAttribute () const; - - AnyAttributeSet& - getAnyAttribute (); - - void - setAnyAttribute (const AnyAttributeSet& s); - - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; - - ::xercesc::DOMDocument& - getDomDocument (); - - // Constructors. - // - Uri_type (const UriType&); - - Uri_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Uri_type (const Uri_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Uri_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Uri_type& - operator= (const Uri_type& x); - - virtual - ~Uri_type (); - - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); - - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - - ::xsd::cxx::tree::one< UriType > uri_; - Display_textOptional display_text_; - PurposeOptional purpose_; - ModifiedOptional modified_; - AnySequence any_; - AnyAttributeSet any_attribute_; - }; - - class Keywords_type: public ::xml_schema::SimpleType, - public ::xsd::cxx::tree::list< ::xml_schema::String, char > - { - public: - Keywords_type (); - - Keywords_type (size_type n, const ::xml_schema::String& x); - - template < typename I > - Keywords_type (const I& begin, const I& end) - : ::xsd::cxx::tree::list< ::xml_schema::String, char > (begin, end, this) - { - } - - Keywords_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Keywords_type (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Keywords_type (const ::std::string& s, + StateType (const ::xercesc::DOMAttr& a, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + StateType (const ::std::string& s, const ::xercesc::DOMElement* e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - Keywords_type (const Keywords_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + StateType (const StateType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - virtual Keywords_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; + virtual StateType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; - virtual - ~Keywords_type (); - }; + StateType& + operator= (Value v); - class Users_type: public ::xml_schema::Type - { - public: - // user - // - typedef ::conference_info::User_type UserType; - typedef ::xsd::cxx::tree::sequence< UserType > UserSequence; - typedef UserSequence::iterator UserIterator; - typedef UserSequence::const_iterator UserConstIterator; - typedef ::xsd::cxx::tree::traits< UserType, char > UserTraits; + virtual + operator Value () const + { + return _xsd_StateType_convert (); + } - const UserSequence& - getUser () const; + protected: + Value + _xsd_StateType_convert () const; - UserSequence& - getUser (); + public: + static const char* const _xsd_StateType_literals_[3]; + static const Value _xsd_StateType_indexes_[3]; + }; - void - setUser (const UserSequence& s); + class ConferenceDescriptionType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // display-text + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String DisplayTextType; + typedef ::xsd::cxx::tree::optional< DisplayTextType > DisplayTextOptional; + typedef ::xsd::cxx::tree::traits< DisplayTextType, char > DisplayTextTraits; - // any - // - typedef ::xsd::cxx::tree::element_sequence AnySequence; - typedef AnySequence::iterator AnyIterator; - typedef AnySequence::const_iterator AnyConstIterator; - - const AnySequence& - getAny () const; - - AnySequence& - getAny (); + const DisplayTextOptional& + getDisplayText () const; - void - setAny (const AnySequence& s); + DisplayTextOptional& + getDisplayText (); - // state - // - typedef ::conference_info::State_type StateType; - typedef ::xsd::cxx::tree::traits< StateType, char > StateTraits; + void + setDisplayText (const DisplayTextType& x); - const StateType& - getState () const; + void + setDisplayText (const DisplayTextOptional& x); - StateType& - getState (); + void + setDisplayText (::std::unique_ptr< DisplayTextType > p); - void - setState (const StateType& x); - - void - setState (::std::unique_ptr< StateType > p); + // subject + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String SubjectType; + typedef ::xsd::cxx::tree::optional< SubjectType > SubjectOptional; + typedef ::xsd::cxx::tree::traits< SubjectType, char > SubjectTraits; - ::std::unique_ptr< StateType > - detachState (); + const SubjectOptional& + getSubject () const; - static const StateType& - getStateDefaultValue (); + SubjectOptional& + getSubject (); - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + void + setSubject (const SubjectType& x); - const AnyAttributeSet& - getAnyAttribute () const; + void + setSubject (const SubjectOptional& x); - AnyAttributeSet& - getAnyAttribute (); + void + setSubject (::std::unique_ptr< SubjectType > p); - void - setAnyAttribute (const AnyAttributeSet& s); + // free-text + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String FreeTextType; + typedef ::xsd::cxx::tree::optional< FreeTextType > FreeTextOptional; + typedef ::xsd::cxx::tree::traits< FreeTextType, char > FreeTextTraits; - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; + const FreeTextOptional& + getFreeText () const; - ::xercesc::DOMDocument& - getDomDocument (); + FreeTextOptional& + getFreeText (); - // Constructors. - // - Users_type (); + void + setFreeText (const FreeTextType& x); - Users_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + void + setFreeText (const FreeTextOptional& x); - Users_type (const Users_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + void + setFreeText (::std::unique_ptr< FreeTextType > p); - virtual Users_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; + // keywords + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::KeywordsType KeywordsType; + typedef ::xsd::cxx::tree::optional< KeywordsType > KeywordsOptional; + typedef ::xsd::cxx::tree::traits< KeywordsType, char > KeywordsTraits; - Users_type& - operator= (const Users_type& x); + const KeywordsOptional& + getKeywords () const; - virtual - ~Users_type (); + KeywordsOptional& + getKeywords (); - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); + void + setKeywords (const KeywordsType& x); - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + void + setKeywords (const KeywordsOptional& x); - UserSequence user_; - AnySequence any_; - ::xsd::cxx::tree::one< StateType > state_; - static const StateType state_default_value_; - AnyAttributeSet any_attribute_; - }; + void + setKeywords (::std::unique_ptr< KeywordsType > p); - class User_type: public ::xml_schema::Type - { - public: - // display-text - // - typedef ::xml_schema::String Display_textType; - typedef ::xsd::cxx::tree::optional< Display_textType > Display_textOptional; - typedef ::xsd::cxx::tree::traits< Display_textType, char > Display_textTraits; + // conf-uris + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::UrisType ConfUrisType; + typedef ::xsd::cxx::tree::optional< ConfUrisType > ConfUrisOptional; + typedef ::xsd::cxx::tree::traits< ConfUrisType, char > ConfUrisTraits; - const Display_textOptional& - getDisplay_text () const; + const ConfUrisOptional& + getConfUris () const; - Display_textOptional& - getDisplay_text (); + ConfUrisOptional& + getConfUris (); - void - setDisplay_text (const Display_textType& x); + void + setConfUris (const ConfUrisType& x); - void - setDisplay_text (const Display_textOptional& x); + void + setConfUris (const ConfUrisOptional& x); - void - setDisplay_text (::std::unique_ptr< Display_textType > p); + void + setConfUris (::std::unique_ptr< ConfUrisType > p); - // associated-aors - // - typedef ::conference_info::Uris_type Associated_aorsType; - typedef ::xsd::cxx::tree::optional< Associated_aorsType > Associated_aorsOptional; - typedef ::xsd::cxx::tree::traits< Associated_aorsType, char > Associated_aorsTraits; + // service-uris + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::UrisType ServiceUrisType; + typedef ::xsd::cxx::tree::optional< ServiceUrisType > ServiceUrisOptional; + typedef ::xsd::cxx::tree::traits< ServiceUrisType, char > ServiceUrisTraits; - const Associated_aorsOptional& - getAssociated_aors () const; + const ServiceUrisOptional& + getServiceUris () const; - Associated_aorsOptional& - getAssociated_aors (); + ServiceUrisOptional& + getServiceUris (); - void - setAssociated_aors (const Associated_aorsType& x); + void + setServiceUris (const ServiceUrisType& x); - void - setAssociated_aors (const Associated_aorsOptional& x); + void + setServiceUris (const ServiceUrisOptional& x); - void - setAssociated_aors (::std::unique_ptr< Associated_aorsType > p); + void + setServiceUris (::std::unique_ptr< ServiceUrisType > p); - // roles - // - typedef ::conference_info::User_roles_type RolesType; - typedef ::xsd::cxx::tree::optional< RolesType > RolesOptional; - typedef ::xsd::cxx::tree::traits< RolesType, char > RolesTraits; + // maximum-user-count + // + typedef ::LinphonePrivate::Xsd::XmlSchema::UnsignedInt MaximumUserCountType; + typedef ::xsd::cxx::tree::optional< MaximumUserCountType > MaximumUserCountOptional; + typedef ::xsd::cxx::tree::traits< MaximumUserCountType, char > MaximumUserCountTraits; - const RolesOptional& - getRoles () const; + const MaximumUserCountOptional& + getMaximumUserCount () const; - RolesOptional& - getRoles (); + MaximumUserCountOptional& + getMaximumUserCount (); - void - setRoles (const RolesType& x); + void + setMaximumUserCount (const MaximumUserCountType& x); - void - setRoles (const RolesOptional& x); + void + setMaximumUserCount (const MaximumUserCountOptional& x); - void - setRoles (::std::unique_ptr< RolesType > p); + // available-media + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceMediaType AvailableMediaType; + typedef ::xsd::cxx::tree::optional< AvailableMediaType > AvailableMediaOptional; + typedef ::xsd::cxx::tree::traits< AvailableMediaType, char > AvailableMediaTraits; - // languages - // - typedef ::conference_info::User_languages_type LanguagesType; - typedef ::xsd::cxx::tree::optional< LanguagesType > LanguagesOptional; - typedef ::xsd::cxx::tree::traits< LanguagesType, char > LanguagesTraits; + const AvailableMediaOptional& + getAvailableMedia () const; - const LanguagesOptional& - getLanguages () const; + AvailableMediaOptional& + getAvailableMedia (); - LanguagesOptional& - getLanguages (); + void + setAvailableMedia (const AvailableMediaType& x); - void - setLanguages (const LanguagesType& x); + void + setAvailableMedia (const AvailableMediaOptional& x); - void - setLanguages (const LanguagesOptional& x); + void + setAvailableMedia (::std::unique_ptr< AvailableMediaType > p); - void - setLanguages (::std::unique_ptr< LanguagesType > p); + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; - // cascaded-focus - // - typedef ::xml_schema::Uri Cascaded_focusType; - typedef ::xsd::cxx::tree::optional< Cascaded_focusType > Cascaded_focusOptional; - typedef ::xsd::cxx::tree::traits< Cascaded_focusType, char > Cascaded_focusTraits; + const AnySequence& + getAny () const; - const Cascaded_focusOptional& - getCascaded_focus () const; + AnySequence& + getAny (); - Cascaded_focusOptional& - getCascaded_focus (); + void + setAny (const AnySequence& s); - void - setCascaded_focus (const Cascaded_focusType& x); + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - void - setCascaded_focus (const Cascaded_focusOptional& x); + const AnyAttributeSet& + getAnyAttribute () const; - void - setCascaded_focus (::std::unique_ptr< Cascaded_focusType > p); + AnyAttributeSet& + getAnyAttribute (); - // endpoint - // - typedef ::conference_info::Endpoint_type EndpointType; - typedef ::xsd::cxx::tree::sequence< EndpointType > EndpointSequence; - typedef EndpointSequence::iterator EndpointIterator; - typedef EndpointSequence::const_iterator EndpointConstIterator; - typedef ::xsd::cxx::tree::traits< EndpointType, char > EndpointTraits; + void + setAnyAttribute (const AnyAttributeSet& s); - const EndpointSequence& - getEndpoint () const; + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; - EndpointSequence& - getEndpoint (); + ::xercesc::DOMDocument& + getDomDocument (); - void - setEndpoint (const EndpointSequence& s); + // Constructors. + // + ConferenceDescriptionType (); - // any - // - typedef ::xsd::cxx::tree::element_sequence AnySequence; - typedef AnySequence::iterator AnyIterator; - typedef AnySequence::const_iterator AnyConstIterator; + ConferenceDescriptionType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - const AnySequence& - getAny () const; + ConferenceDescriptionType (const ConferenceDescriptionType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - AnySequence& - getAny (); + virtual ConferenceDescriptionType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; - void - setAny (const AnySequence& s); + ConferenceDescriptionType& + operator= (const ConferenceDescriptionType& x); - // entity - // - typedef ::xml_schema::Uri EntityType; - typedef ::xsd::cxx::tree::optional< EntityType > EntityOptional; - typedef ::xsd::cxx::tree::traits< EntityType, char > EntityTraits; + virtual + ~ConferenceDescriptionType (); - const EntityOptional& - getEntity () const; + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); - EntityOptional& - getEntity (); + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - void - setEntity (const EntityType& x); + DisplayTextOptional display_text_; + SubjectOptional subject_; + FreeTextOptional free_text_; + KeywordsOptional keywords_; + ConfUrisOptional conf_uris_; + ServiceUrisOptional service_uris_; + MaximumUserCountOptional maximum_user_count_; + AvailableMediaOptional available_media_; + AnySequence any_; + AnyAttributeSet any_attribute_; + }; - void - setEntity (const EntityOptional& x); + class HostType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // display-text + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String DisplayTextType; + typedef ::xsd::cxx::tree::optional< DisplayTextType > DisplayTextOptional; + typedef ::xsd::cxx::tree::traits< DisplayTextType, char > DisplayTextTraits; - void - setEntity (::std::unique_ptr< EntityType > p); + const DisplayTextOptional& + getDisplayText () const; - // state - // - typedef ::conference_info::State_type StateType; - typedef ::xsd::cxx::tree::traits< StateType, char > StateTraits; + DisplayTextOptional& + getDisplayText (); - const StateType& - getState () const; + void + setDisplayText (const DisplayTextType& x); - StateType& - getState (); + void + setDisplayText (const DisplayTextOptional& x); - void - setState (const StateType& x); + void + setDisplayText (::std::unique_ptr< DisplayTextType > p); - void - setState (::std::unique_ptr< StateType > p); + // web-page + // + typedef ::LinphonePrivate::Xsd::XmlSchema::Uri WebPageType; + typedef ::xsd::cxx::tree::optional< WebPageType > WebPageOptional; + typedef ::xsd::cxx::tree::traits< WebPageType, char > WebPageTraits; - ::std::unique_ptr< StateType > - detachState (); + const WebPageOptional& + getWebPage () const; - static const StateType& - getStateDefaultValue (); + WebPageOptional& + getWebPage (); - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + void + setWebPage (const WebPageType& x); - const AnyAttributeSet& - getAnyAttribute () const; + void + setWebPage (const WebPageOptional& x); - AnyAttributeSet& - getAnyAttribute (); + void + setWebPage (::std::unique_ptr< WebPageType > p); - void - setAnyAttribute (const AnyAttributeSet& s); + // uris + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::UrisType UrisType; + typedef ::xsd::cxx::tree::optional< UrisType > UrisOptional; + typedef ::xsd::cxx::tree::traits< UrisType, char > UrisTraits; + + const UrisOptional& + getUris () const; + + UrisOptional& + getUris (); + + void + setUris (const UrisType& x); + + void + setUris (const UrisOptional& x); + + void + setUris (::std::unique_ptr< UrisType > p); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; + void + setAnyAttribute (const AnyAttributeSet& s); - ::xercesc::DOMDocument& - getDomDocument (); + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; - // Constructors. - // - User_type (); + ::xercesc::DOMDocument& + getDomDocument (); - User_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + // Constructors. + // + HostType (); - User_type (const User_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + HostType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - virtual User_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - User_type& - operator= (const User_type& x); - - virtual - ~User_type (); + HostType (const HostType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); - - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + virtual HostType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; - Display_textOptional display_text_; - Associated_aorsOptional associated_aors_; - RolesOptional roles_; - LanguagesOptional languages_; - Cascaded_focusOptional cascaded_focus_; - EndpointSequence endpoint_; - AnySequence any_; - EntityOptional entity_; - ::xsd::cxx::tree::one< StateType > state_; - static const StateType state_default_value_; - AnyAttributeSet any_attribute_; - }; - - class User_roles_type: public ::xml_schema::Type - { - public: - // entry - // - typedef ::xml_schema::String EntryType; - typedef ::xsd::cxx::tree::sequence< EntryType > EntrySequence; - typedef EntrySequence::iterator EntryIterator; - typedef EntrySequence::const_iterator EntryConstIterator; - typedef ::xsd::cxx::tree::traits< EntryType, char > EntryTraits; - - const EntrySequence& - getEntry () const; - - EntrySequence& - getEntry (); - - void - setEntry (const EntrySequence& s); - - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - - const AnyAttributeSet& - getAnyAttribute () const; - - AnyAttributeSet& - getAnyAttribute (); - - void - setAnyAttribute (const AnyAttributeSet& s); - - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; - - ::xercesc::DOMDocument& - getDomDocument (); - - // Constructors. - // - User_roles_type (); - - User_roles_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - User_roles_type (const User_roles_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual User_roles_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - User_roles_type& - operator= (const User_roles_type& x); - - virtual - ~User_roles_type (); - - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); - - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - - EntrySequence entry_; - AnyAttributeSet any_attribute_; - }; - - class User_languages_type: public ::xml_schema::SimpleType, - public ::xsd::cxx::tree::list< ::xml_schema::Language, char > - { - public: - User_languages_type (); - - User_languages_type (size_type n, const ::xml_schema::Language& x); - - template < typename I > - User_languages_type (const I& begin, const I& end) - : ::xsd::cxx::tree::list< ::xml_schema::Language, char > (begin, end, this) - { - } - - User_languages_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - User_languages_type (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - User_languages_type (const ::std::string& s, + HostType& + operator= (const HostType& x); + + virtual + ~HostType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); + + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + DisplayTextOptional display_text_; + WebPageOptional web_page_; + UrisOptional uris_; + AnySequence any_; + AnyAttributeSet any_attribute_; + }; + + class ConferenceStateType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // user-count + // + typedef ::LinphonePrivate::Xsd::XmlSchema::UnsignedInt UserCountType; + typedef ::xsd::cxx::tree::optional< UserCountType > UserCountOptional; + typedef ::xsd::cxx::tree::traits< UserCountType, char > UserCountTraits; + + const UserCountOptional& + getUserCount () const; + + UserCountOptional& + getUserCount (); + + void + setUserCount (const UserCountType& x); + + void + setUserCount (const UserCountOptional& x); + + // active + // + typedef ::LinphonePrivate::Xsd::XmlSchema::Boolean ActiveType; + typedef ::xsd::cxx::tree::optional< ActiveType > ActiveOptional; + typedef ::xsd::cxx::tree::traits< ActiveType, char > ActiveTraits; + + const ActiveOptional& + getActive () const; + + ActiveOptional& + getActive (); + + void + setActive (const ActiveType& x); + + void + setActive (const ActiveOptional& x); + + // locked + // + typedef ::LinphonePrivate::Xsd::XmlSchema::Boolean LockedType; + typedef ::xsd::cxx::tree::optional< LockedType > LockedOptional; + typedef ::xsd::cxx::tree::traits< LockedType, char > LockedTraits; + + const LockedOptional& + getLocked () const; + + LockedOptional& + getLocked (); + + void + setLocked (const LockedType& x); + + void + setLocked (const LockedOptional& x); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + ConferenceStateType (); + + ConferenceStateType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + ConferenceStateType (const ConferenceStateType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual ConferenceStateType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + ConferenceStateType& + operator= (const ConferenceStateType& x); + + virtual + ~ConferenceStateType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); + + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + UserCountOptional user_count_; + ActiveOptional active_; + LockedOptional locked_; + AnySequence any_; + AnyAttributeSet any_attribute_; + }; + + class ConferenceMediaType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // entry + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceMediumType EntryType; + typedef ::xsd::cxx::tree::sequence< EntryType > EntrySequence; + typedef EntrySequence::iterator EntryIterator; + typedef EntrySequence::const_iterator EntryConstIterator; + typedef ::xsd::cxx::tree::traits< EntryType, char > EntryTraits; + + const EntrySequence& + getEntry () const; + + EntrySequence& + getEntry (); + + void + setEntry (const EntrySequence& s); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + ConferenceMediaType (); + + ConferenceMediaType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + ConferenceMediaType (const ConferenceMediaType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual ConferenceMediaType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + ConferenceMediaType& + operator= (const ConferenceMediaType& x); + + virtual + ~ConferenceMediaType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); + + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + EntrySequence entry_; + AnyAttributeSet any_attribute_; + }; + + class ConferenceMediumType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // display-text + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String DisplayTextType; + typedef ::xsd::cxx::tree::optional< DisplayTextType > DisplayTextOptional; + typedef ::xsd::cxx::tree::traits< DisplayTextType, char > DisplayTextTraits; + + const DisplayTextOptional& + getDisplayText () const; + + DisplayTextOptional& + getDisplayText (); + + void + setDisplayText (const DisplayTextType& x); + + void + setDisplayText (const DisplayTextOptional& x); + + void + setDisplayText (::std::unique_ptr< DisplayTextType > p); + + // type + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String TypeType; + typedef ::xsd::cxx::tree::traits< TypeType, char > TypeTraits; + + const TypeType& + getType () const; + + TypeType& + getType (); + + void + setType (const TypeType& x); + + void + setType (::std::unique_ptr< TypeType > p); + + ::std::unique_ptr< TypeType > + setDetachType (); + + // status + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::MediaStatusType StatusType; + typedef ::xsd::cxx::tree::optional< StatusType > StatusOptional; + typedef ::xsd::cxx::tree::traits< StatusType, char > StatusTraits; + + const StatusOptional& + getStatus () const; + + StatusOptional& + getStatus (); + + void + setStatus (const StatusType& x); + + void + setStatus (const StatusOptional& x); + + void + setStatus (::std::unique_ptr< StatusType > p); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // label + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String LabelType; + typedef ::xsd::cxx::tree::traits< LabelType, char > LabelTraits; + + const LabelType& + getLabel () const; + + LabelType& + getLabel (); + + void + setLabel (const LabelType& x); + + void + setLabel (::std::unique_ptr< LabelType > p); + + ::std::unique_ptr< LabelType > + setDetachLabel (); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + ConferenceMediumType (const TypeType&, + const LabelType&); + + ConferenceMediumType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + ConferenceMediumType (const ConferenceMediumType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual ConferenceMediumType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + ConferenceMediumType& + operator= (const ConferenceMediumType& x); + + virtual + ~ConferenceMediumType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); + + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + DisplayTextOptional display_text_; + ::xsd::cxx::tree::one< TypeType > type_; + StatusOptional status_; + AnySequence any_; + ::xsd::cxx::tree::one< LabelType > label_; + AnyAttributeSet any_attribute_; + }; + + class UrisType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // entry + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::UriType EntryType; + typedef ::xsd::cxx::tree::sequence< EntryType > EntrySequence; + typedef EntrySequence::iterator EntryIterator; + typedef EntrySequence::const_iterator EntryConstIterator; + typedef ::xsd::cxx::tree::traits< EntryType, char > EntryTraits; + + const EntrySequence& + getEntry () const; + + EntrySequence& + getEntry (); + + void + setEntry (const EntrySequence& s); + + // state + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::StateType StateType; + typedef ::xsd::cxx::tree::traits< StateType, char > StateTraits; + + const StateType& + getState () const; + + StateType& + getState (); + + void + setState (const StateType& x); + + void + setState (::std::unique_ptr< StateType > p); + + ::std::unique_ptr< StateType > + setDetachState (); + + static const StateType& + getStateDefaultValue (); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + UrisType (); + + UrisType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + UrisType (const UrisType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual UrisType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + UrisType& + operator= (const UrisType& x); + + virtual + ~UrisType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); + + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + EntrySequence entry_; + ::xsd::cxx::tree::one< StateType > state_; + static const StateType state_default_value_; + AnyAttributeSet any_attribute_; + }; + + class UriType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // uri + // + typedef ::LinphonePrivate::Xsd::XmlSchema::Uri UriType1; + typedef ::xsd::cxx::tree::traits< UriType1, char > UriTraits; + + const UriType1& + getUri () const; + + UriType1& + getUri (); + + void + setUri (const UriType1& x); + + void + setUri (::std::unique_ptr< UriType1 > p); + + ::std::unique_ptr< UriType1 > + setDetachUri (); + + // display-text + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String DisplayTextType; + typedef ::xsd::cxx::tree::optional< DisplayTextType > DisplayTextOptional; + typedef ::xsd::cxx::tree::traits< DisplayTextType, char > DisplayTextTraits; + + const DisplayTextOptional& + getDisplayText () const; + + DisplayTextOptional& + getDisplayText (); + + void + setDisplayText (const DisplayTextType& x); + + void + setDisplayText (const DisplayTextOptional& x); + + void + setDisplayText (::std::unique_ptr< DisplayTextType > p); + + // purpose + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String PurposeType; + typedef ::xsd::cxx::tree::optional< PurposeType > PurposeOptional; + typedef ::xsd::cxx::tree::traits< PurposeType, char > PurposeTraits; + + const PurposeOptional& + getPurpose () const; + + PurposeOptional& + getPurpose (); + + void + setPurpose (const PurposeType& x); + + void + setPurpose (const PurposeOptional& x); + + void + setPurpose (::std::unique_ptr< PurposeType > p); + + // modified + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::ExecutionType ModifiedType; + typedef ::xsd::cxx::tree::optional< ModifiedType > ModifiedOptional; + typedef ::xsd::cxx::tree::traits< ModifiedType, char > ModifiedTraits; + + const ModifiedOptional& + getModified () const; + + ModifiedOptional& + getModified (); + + void + setModified (const ModifiedType& x); + + void + setModified (const ModifiedOptional& x); + + void + setModified (::std::unique_ptr< ModifiedType > p); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + UriType (const UriType1&); + + UriType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + UriType (const UriType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual UriType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + UriType& + operator= (const UriType& x); + + virtual + ~UriType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); + + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + ::xsd::cxx::tree::one< UriType1 > uri_; + DisplayTextOptional display_text_; + PurposeOptional purpose_; + ModifiedOptional modified_; + AnySequence any_; + AnyAttributeSet any_attribute_; + }; + + class KeywordsType: public ::LinphonePrivate::Xsd::XmlSchema::SimpleType, + public ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::String, char > + { + public: + KeywordsType (); + + KeywordsType (size_type n, const ::LinphonePrivate::Xsd::XmlSchema::String& x); + + template < typename I > + KeywordsType (const I& begin, const I& end) + : ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::String, char > (begin, end, this) + { + } + + KeywordsType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + KeywordsType (const ::xercesc::DOMAttr& a, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + KeywordsType (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + KeywordsType (const KeywordsType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual KeywordsType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + virtual + ~KeywordsType (); + }; + + class UsersType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // user + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::UserType UserType; + typedef ::xsd::cxx::tree::sequence< UserType > UserSequence; + typedef UserSequence::iterator UserIterator; + typedef UserSequence::const_iterator UserConstIterator; + typedef ::xsd::cxx::tree::traits< UserType, char > UserTraits; + + const UserSequence& + getUser () const; + + UserSequence& + getUser (); + + void + setUser (const UserSequence& s); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // state + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::StateType StateType; + typedef ::xsd::cxx::tree::traits< StateType, char > StateTraits; + + const StateType& + getState () const; + + StateType& + getState (); + + void + setState (const StateType& x); + + void + setState (::std::unique_ptr< StateType > p); + + ::std::unique_ptr< StateType > + setDetachState (); + + static const StateType& + getStateDefaultValue (); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + UsersType (); + + UsersType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + UsersType (const UsersType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual UsersType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + UsersType& + operator= (const UsersType& x); + + virtual + ~UsersType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); + + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + UserSequence user_; + AnySequence any_; + ::xsd::cxx::tree::one< StateType > state_; + static const StateType state_default_value_; + AnyAttributeSet any_attribute_; + }; + + class UserType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // display-text + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String DisplayTextType; + typedef ::xsd::cxx::tree::optional< DisplayTextType > DisplayTextOptional; + typedef ::xsd::cxx::tree::traits< DisplayTextType, char > DisplayTextTraits; + + const DisplayTextOptional& + getDisplayText () const; + + DisplayTextOptional& + getDisplayText (); + + void + setDisplayText (const DisplayTextType& x); + + void + setDisplayText (const DisplayTextOptional& x); + + void + setDisplayText (::std::unique_ptr< DisplayTextType > p); + + // associated-aors + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::UrisType AssociatedAorsType; + typedef ::xsd::cxx::tree::optional< AssociatedAorsType > AssociatedAorsOptional; + typedef ::xsd::cxx::tree::traits< AssociatedAorsType, char > AssociatedAorsTraits; + + const AssociatedAorsOptional& + getAssociatedAors () const; + + AssociatedAorsOptional& + getAssociatedAors (); + + void + setAssociatedAors (const AssociatedAorsType& x); + + void + setAssociatedAors (const AssociatedAorsOptional& x); + + void + setAssociatedAors (::std::unique_ptr< AssociatedAorsType > p); + + // roles + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::UserRolesType RolesType; + typedef ::xsd::cxx::tree::optional< RolesType > RolesOptional; + typedef ::xsd::cxx::tree::traits< RolesType, char > RolesTraits; + + const RolesOptional& + getRoles () const; + + RolesOptional& + getRoles (); + + void + setRoles (const RolesType& x); + + void + setRoles (const RolesOptional& x); + + void + setRoles (::std::unique_ptr< RolesType > p); + + // languages + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::UserLanguagesType LanguagesType; + typedef ::xsd::cxx::tree::optional< LanguagesType > LanguagesOptional; + typedef ::xsd::cxx::tree::traits< LanguagesType, char > LanguagesTraits; + + const LanguagesOptional& + getLanguages () const; + + LanguagesOptional& + getLanguages (); + + void + setLanguages (const LanguagesType& x); + + void + setLanguages (const LanguagesOptional& x); + + void + setLanguages (::std::unique_ptr< LanguagesType > p); + + // cascaded-focus + // + typedef ::LinphonePrivate::Xsd::XmlSchema::Uri CascadedFocusType; + typedef ::xsd::cxx::tree::optional< CascadedFocusType > CascadedFocusOptional; + typedef ::xsd::cxx::tree::traits< CascadedFocusType, char > CascadedFocusTraits; + + const CascadedFocusOptional& + getCascadedFocus () const; + + CascadedFocusOptional& + getCascadedFocus (); + + void + setCascadedFocus (const CascadedFocusType& x); + + void + setCascadedFocus (const CascadedFocusOptional& x); + + void + setCascadedFocus (::std::unique_ptr< CascadedFocusType > p); + + // endpoint + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::EndpointType EndpointType; + typedef ::xsd::cxx::tree::sequence< EndpointType > EndpointSequence; + typedef EndpointSequence::iterator EndpointIterator; + typedef EndpointSequence::const_iterator EndpointConstIterator; + typedef ::xsd::cxx::tree::traits< EndpointType, char > EndpointTraits; + + const EndpointSequence& + getEndpoint () const; + + EndpointSequence& + getEndpoint (); + + void + setEndpoint (const EndpointSequence& s); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // entity + // + typedef ::LinphonePrivate::Xsd::XmlSchema::Uri EntityType; + typedef ::xsd::cxx::tree::optional< EntityType > EntityOptional; + typedef ::xsd::cxx::tree::traits< EntityType, char > EntityTraits; + + const EntityOptional& + getEntity () const; + + EntityOptional& + getEntity (); + + void + setEntity (const EntityType& x); + + void + setEntity (const EntityOptional& x); + + void + setEntity (::std::unique_ptr< EntityType > p); + + // state + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::StateType StateType; + typedef ::xsd::cxx::tree::traits< StateType, char > StateTraits; + + const StateType& + getState () const; + + StateType& + getState (); + + void + setState (const StateType& x); + + void + setState (::std::unique_ptr< StateType > p); + + ::std::unique_ptr< StateType > + setDetachState (); + + static const StateType& + getStateDefaultValue (); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + UserType (); + + UserType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + UserType (const UserType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual UserType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + UserType& + operator= (const UserType& x); + + virtual + ~UserType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); + + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + DisplayTextOptional display_text_; + AssociatedAorsOptional associated_aors_; + RolesOptional roles_; + LanguagesOptional languages_; + CascadedFocusOptional cascaded_focus_; + EndpointSequence endpoint_; + AnySequence any_; + EntityOptional entity_; + ::xsd::cxx::tree::one< StateType > state_; + static const StateType state_default_value_; + AnyAttributeSet any_attribute_; + }; + + class UserRolesType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // entry + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String EntryType; + typedef ::xsd::cxx::tree::sequence< EntryType > EntrySequence; + typedef EntrySequence::iterator EntryIterator; + typedef EntrySequence::const_iterator EntryConstIterator; + typedef ::xsd::cxx::tree::traits< EntryType, char > EntryTraits; + + const EntrySequence& + getEntry () const; + + EntrySequence& + getEntry (); + + void + setEntry (const EntrySequence& s); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + UserRolesType (); + + UserRolesType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + UserRolesType (const UserRolesType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual UserRolesType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + UserRolesType& + operator= (const UserRolesType& x); + + virtual + ~UserRolesType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); + + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + EntrySequence entry_; + AnyAttributeSet any_attribute_; + }; + + class UserLanguagesType: public ::LinphonePrivate::Xsd::XmlSchema::SimpleType, + public ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::Language, char > + { + public: + UserLanguagesType (); + + UserLanguagesType (size_type n, const ::LinphonePrivate::Xsd::XmlSchema::Language& x); + + template < typename I > + UserLanguagesType (const I& begin, const I& end) + : ::xsd::cxx::tree::list< ::LinphonePrivate::Xsd::XmlSchema::Language, char > (begin, end, this) + { + } + + UserLanguagesType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + UserLanguagesType (const ::xercesc::DOMAttr& a, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + UserLanguagesType (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + UserLanguagesType (const UserLanguagesType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual UserLanguagesType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + virtual + ~UserLanguagesType (); + }; + + class EndpointType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // display-text + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String DisplayTextType; + typedef ::xsd::cxx::tree::optional< DisplayTextType > DisplayTextOptional; + typedef ::xsd::cxx::tree::traits< DisplayTextType, char > DisplayTextTraits; + + const DisplayTextOptional& + getDisplayText () const; + + DisplayTextOptional& + getDisplayText (); + + void + setDisplayText (const DisplayTextType& x); + + void + setDisplayText (const DisplayTextOptional& x); + + void + setDisplayText (::std::unique_ptr< DisplayTextType > p); + + // referred + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::ExecutionType ReferredType; + typedef ::xsd::cxx::tree::optional< ReferredType > ReferredOptional; + typedef ::xsd::cxx::tree::traits< ReferredType, char > ReferredTraits; + + const ReferredOptional& + getReferred () const; + + ReferredOptional& + getReferred (); + + void + setReferred (const ReferredType& x); + + void + setReferred (const ReferredOptional& x); + + void + setReferred (::std::unique_ptr< ReferredType > p); + + // status + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::EndpointStatusType StatusType; + typedef ::xsd::cxx::tree::optional< StatusType > StatusOptional; + typedef ::xsd::cxx::tree::traits< StatusType, char > StatusTraits; + + const StatusOptional& + getStatus () const; + + StatusOptional& + getStatus (); + + void + setStatus (const StatusType& x); + + void + setStatus (const StatusOptional& x); + + void + setStatus (::std::unique_ptr< StatusType > p); + + // joining-method + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::JoiningType JoiningMethodType; + typedef ::xsd::cxx::tree::optional< JoiningMethodType > JoiningMethodOptional; + typedef ::xsd::cxx::tree::traits< JoiningMethodType, char > JoiningMethodTraits; + + const JoiningMethodOptional& + getJoiningMethod () const; + + JoiningMethodOptional& + getJoiningMethod (); + + void + setJoiningMethod (const JoiningMethodType& x); + + void + setJoiningMethod (const JoiningMethodOptional& x); + + void + setJoiningMethod (::std::unique_ptr< JoiningMethodType > p); + + // joining-info + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::ExecutionType JoiningInfoType; + typedef ::xsd::cxx::tree::optional< JoiningInfoType > JoiningInfoOptional; + typedef ::xsd::cxx::tree::traits< JoiningInfoType, char > JoiningInfoTraits; + + const JoiningInfoOptional& + getJoiningInfo () const; + + JoiningInfoOptional& + getJoiningInfo (); + + void + setJoiningInfo (const JoiningInfoType& x); + + void + setJoiningInfo (const JoiningInfoOptional& x); + + void + setJoiningInfo (::std::unique_ptr< JoiningInfoType > p); + + // disconnection-method + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::DisconnectionType DisconnectionMethodType; + typedef ::xsd::cxx::tree::optional< DisconnectionMethodType > DisconnectionMethodOptional; + typedef ::xsd::cxx::tree::traits< DisconnectionMethodType, char > DisconnectionMethodTraits; + + const DisconnectionMethodOptional& + getDisconnectionMethod () const; + + DisconnectionMethodOptional& + getDisconnectionMethod (); + + void + setDisconnectionMethod (const DisconnectionMethodType& x); + + void + setDisconnectionMethod (const DisconnectionMethodOptional& x); + + void + setDisconnectionMethod (::std::unique_ptr< DisconnectionMethodType > p); + + // disconnection-info + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::ExecutionType DisconnectionInfoType; + typedef ::xsd::cxx::tree::optional< DisconnectionInfoType > DisconnectionInfoOptional; + typedef ::xsd::cxx::tree::traits< DisconnectionInfoType, char > DisconnectionInfoTraits; + + const DisconnectionInfoOptional& + getDisconnectionInfo () const; + + DisconnectionInfoOptional& + getDisconnectionInfo (); + + void + setDisconnectionInfo (const DisconnectionInfoType& x); + + void + setDisconnectionInfo (const DisconnectionInfoOptional& x); + + void + setDisconnectionInfo (::std::unique_ptr< DisconnectionInfoType > p); + + // media + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::MediaType MediaType; + typedef ::xsd::cxx::tree::sequence< MediaType > MediaSequence; + typedef MediaSequence::iterator MediaIterator; + typedef MediaSequence::const_iterator MediaConstIterator; + typedef ::xsd::cxx::tree::traits< MediaType, char > MediaTraits; + + const MediaSequence& + getMedia () const; + + MediaSequence& + getMedia (); + + void + setMedia (const MediaSequence& s); + + // call-info + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::CallType CallInfoType; + typedef ::xsd::cxx::tree::optional< CallInfoType > CallInfoOptional; + typedef ::xsd::cxx::tree::traits< CallInfoType, char > CallInfoTraits; + + const CallInfoOptional& + getCallInfo () const; + + CallInfoOptional& + getCallInfo (); + + void + setCallInfo (const CallInfoType& x); + + void + setCallInfo (const CallInfoOptional& x); + + void + setCallInfo (::std::unique_ptr< CallInfoType > p); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // entity + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String EntityType; + typedef ::xsd::cxx::tree::optional< EntityType > EntityOptional; + typedef ::xsd::cxx::tree::traits< EntityType, char > EntityTraits; + + const EntityOptional& + getEntity () const; + + EntityOptional& + getEntity (); + + void + setEntity (const EntityType& x); + + void + setEntity (const EntityOptional& x); + + void + setEntity (::std::unique_ptr< EntityType > p); + + // state + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::StateType StateType; + typedef ::xsd::cxx::tree::traits< StateType, char > StateTraits; + + const StateType& + getState () const; + + StateType& + getState (); + + void + setState (const StateType& x); + + void + setState (::std::unique_ptr< StateType > p); + + ::std::unique_ptr< StateType > + setDetachState (); + + static const StateType& + getStateDefaultValue (); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + EndpointType (); + + EndpointType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + EndpointType (const EndpointType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual EndpointType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + EndpointType& + operator= (const EndpointType& x); + + virtual + ~EndpointType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); + + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + DisplayTextOptional display_text_; + ReferredOptional referred_; + StatusOptional status_; + JoiningMethodOptional joining_method_; + JoiningInfoOptional joining_info_; + DisconnectionMethodOptional disconnection_method_; + DisconnectionInfoOptional disconnection_info_; + MediaSequence media_; + CallInfoOptional call_info_; + AnySequence any_; + EntityOptional entity_; + ::xsd::cxx::tree::one< StateType > state_; + static const StateType state_default_value_; + AnyAttributeSet any_attribute_; + }; + + class EndpointStatusType: public ::LinphonePrivate::Xsd::XmlSchema::String + { + public: + enum Value + { + pending, + dialing_out, + dialing_in, + alerting, + on_hold, + connected, + muted_via_focus, + disconnecting, + disconnected + }; + + EndpointStatusType (Value v); + + EndpointStatusType (const char* v); + + EndpointStatusType (const ::std::string& v); + + EndpointStatusType (const ::LinphonePrivate::Xsd::XmlSchema::String& v); + + EndpointStatusType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + EndpointStatusType (const ::xercesc::DOMAttr& a, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + EndpointStatusType (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + EndpointStatusType (const EndpointStatusType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual EndpointStatusType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + EndpointStatusType& + operator= (Value v); + + virtual + operator Value () const + { + return _xsd_EndpointStatusType_convert (); + } + + protected: + Value + _xsd_EndpointStatusType_convert () const; + + public: + static const char* const _xsd_EndpointStatusType_literals_[9]; + static const Value _xsd_EndpointStatusType_indexes_[9]; + }; + + class JoiningType: public ::LinphonePrivate::Xsd::XmlSchema::String + { + public: + enum Value + { + dialed_in, + dialed_out, + focus_owner + }; + + JoiningType (Value v); + + JoiningType (const char* v); + + JoiningType (const ::std::string& v); + + JoiningType (const ::LinphonePrivate::Xsd::XmlSchema::String& v); + + JoiningType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + JoiningType (const ::xercesc::DOMAttr& a, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + JoiningType (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + JoiningType (const JoiningType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual JoiningType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + JoiningType& + operator= (Value v); + + virtual + operator Value () const + { + return _xsd_JoiningType_convert (); + } + + protected: + Value + _xsd_JoiningType_convert () const; + + public: + static const char* const _xsd_JoiningType_literals_[3]; + static const Value _xsd_JoiningType_indexes_[3]; + }; + + class DisconnectionType: public ::LinphonePrivate::Xsd::XmlSchema::String + { + public: + enum Value + { + departed, + booted, + failed, + busy + }; + + DisconnectionType (Value v); + + DisconnectionType (const char* v); + + DisconnectionType (const ::std::string& v); + + DisconnectionType (const ::LinphonePrivate::Xsd::XmlSchema::String& v); + + DisconnectionType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + DisconnectionType (const ::xercesc::DOMAttr& a, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + DisconnectionType (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + DisconnectionType (const DisconnectionType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual DisconnectionType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + DisconnectionType& + operator= (Value v); + + virtual + operator Value () const + { + return _xsd_DisconnectionType_convert (); + } + + protected: + Value + _xsd_DisconnectionType_convert () const; + + public: + static const char* const _xsd_DisconnectionType_literals_[4]; + static const Value _xsd_DisconnectionType_indexes_[4]; + }; + + class ExecutionType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // when + // + typedef ::LinphonePrivate::Xsd::XmlSchema::DateTime WhenType; + typedef ::xsd::cxx::tree::optional< WhenType > WhenOptional; + typedef ::xsd::cxx::tree::traits< WhenType, char > WhenTraits; + + const WhenOptional& + getWhen () const; + + WhenOptional& + getWhen (); + + void + setWhen (const WhenType& x); + + void + setWhen (const WhenOptional& x); + + void + setWhen (::std::unique_ptr< WhenType > p); + + // reason + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String ReasonType; + typedef ::xsd::cxx::tree::optional< ReasonType > ReasonOptional; + typedef ::xsd::cxx::tree::traits< ReasonType, char > ReasonTraits; + + const ReasonOptional& + getReason () const; + + ReasonOptional& + getReason (); + + void + setReason (const ReasonType& x); + + void + setReason (const ReasonOptional& x); + + void + setReason (::std::unique_ptr< ReasonType > p); + + // by + // + typedef ::LinphonePrivate::Xsd::XmlSchema::Uri ByType; + typedef ::xsd::cxx::tree::optional< ByType > ByOptional; + typedef ::xsd::cxx::tree::traits< ByType, char > ByTraits; + + const ByOptional& + getBy () const; + + ByOptional& + getBy (); + + void + setBy (const ByType& x); + + void + setBy (const ByOptional& x); + + void + setBy (::std::unique_ptr< ByType > p); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + ExecutionType (); + + ExecutionType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + ExecutionType (const ExecutionType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual ExecutionType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + ExecutionType& + operator= (const ExecutionType& x); + + virtual + ~ExecutionType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); + + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + WhenOptional when_; + ReasonOptional reason_; + ByOptional by_; + AnyAttributeSet any_attribute_; + }; + + class CallType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // sip + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::SipDialogIdType SipType; + typedef ::xsd::cxx::tree::optional< SipType > SipOptional; + typedef ::xsd::cxx::tree::traits< SipType, char > SipTraits; + + const SipOptional& + getSip () const; + + SipOptional& + getSip (); + + void + setSip (const SipType& x); + + void + setSip (const SipOptional& x); + + void + setSip (::std::unique_ptr< SipType > p); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + CallType (); + + CallType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + CallType (const CallType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual CallType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + CallType& + operator= (const CallType& x); + + virtual + ~CallType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); + + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + SipOptional sip_; + AnySequence any_; + AnyAttributeSet any_attribute_; + }; + + class SipDialogIdType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // display-text + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String DisplayTextType; + typedef ::xsd::cxx::tree::optional< DisplayTextType > DisplayTextOptional; + typedef ::xsd::cxx::tree::traits< DisplayTextType, char > DisplayTextTraits; + + const DisplayTextOptional& + getDisplayText () const; + + DisplayTextOptional& + getDisplayText (); + + void + setDisplayText (const DisplayTextType& x); + + void + setDisplayText (const DisplayTextOptional& x); + + void + setDisplayText (::std::unique_ptr< DisplayTextType > p); + + // call-id + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String CallIdType; + typedef ::xsd::cxx::tree::traits< CallIdType, char > CallIdTraits; + + const CallIdType& + getCallId () const; + + CallIdType& + getCallId (); + + void + setCallId (const CallIdType& x); + + void + setCallId (::std::unique_ptr< CallIdType > p); + + ::std::unique_ptr< CallIdType > + setDetachCall_id (); + + // from-tag + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String FromTagType; + typedef ::xsd::cxx::tree::traits< FromTagType, char > FromTagTraits; + + const FromTagType& + getFromTag () const; + + FromTagType& + getFromTag (); + + void + setFromTag (const FromTagType& x); + + void + setFromTag (::std::unique_ptr< FromTagType > p); + + ::std::unique_ptr< FromTagType > + setDetachFrom_tag (); + + // to-tag + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String ToTagType; + typedef ::xsd::cxx::tree::traits< ToTagType, char > ToTagTraits; + + const ToTagType& + getToTag () const; + + ToTagType& + getToTag (); + + void + setToTag (const ToTagType& x); + + void + setToTag (::std::unique_ptr< ToTagType > p); + + ::std::unique_ptr< ToTagType > + setDetachTo_tag (); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + SipDialogIdType (const CallIdType&, + const FromTagType&, + const ToTagType&); + + SipDialogIdType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + SipDialogIdType (const SipDialogIdType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual SipDialogIdType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + SipDialogIdType& + operator= (const SipDialogIdType& x); + + virtual + ~SipDialogIdType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); + + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + DisplayTextOptional display_text_; + ::xsd::cxx::tree::one< CallIdType > call_id_; + ::xsd::cxx::tree::one< FromTagType > from_tag_; + ::xsd::cxx::tree::one< ToTagType > to_tag_; + AnySequence any_; + AnyAttributeSet any_attribute_; + }; + + class MediaType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // display-text + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String DisplayTextType; + typedef ::xsd::cxx::tree::optional< DisplayTextType > DisplayTextOptional; + typedef ::xsd::cxx::tree::traits< DisplayTextType, char > DisplayTextTraits; + + const DisplayTextOptional& + getDisplayText () const; + + DisplayTextOptional& + getDisplayText (); + + void + setDisplayText (const DisplayTextType& x); + + void + setDisplayText (const DisplayTextOptional& x); + + void + setDisplayText (::std::unique_ptr< DisplayTextType > p); + + // type + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String TypeType; + typedef ::xsd::cxx::tree::optional< TypeType > TypeOptional; + typedef ::xsd::cxx::tree::traits< TypeType, char > TypeTraits; + + const TypeOptional& + getType () const; + + TypeOptional& + getType (); + + void + setType (const TypeType& x); + + void + setType (const TypeOptional& x); + + void + setType (::std::unique_ptr< TypeType > p); + + // label + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String LabelType; + typedef ::xsd::cxx::tree::optional< LabelType > LabelOptional; + typedef ::xsd::cxx::tree::traits< LabelType, char > LabelTraits; + + const LabelOptional& + getLabel () const; + + LabelOptional& + getLabel (); + + void + setLabel (const LabelType& x); + + void + setLabel (const LabelOptional& x); + + void + setLabel (::std::unique_ptr< LabelType > p); + + // src-id + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String SrcIdType; + typedef ::xsd::cxx::tree::optional< SrcIdType > SrcIdOptional; + typedef ::xsd::cxx::tree::traits< SrcIdType, char > SrcIdTraits; + + const SrcIdOptional& + getSrcId () const; + + SrcIdOptional& + getSrcId (); + + void + setSrcId (const SrcIdType& x); + + void + setSrcId (const SrcIdOptional& x); + + void + setSrcId (::std::unique_ptr< SrcIdType > p); + + // status + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::MediaStatusType StatusType; + typedef ::xsd::cxx::tree::optional< StatusType > StatusOptional; + typedef ::xsd::cxx::tree::traits< StatusType, char > StatusTraits; + + const StatusOptional& + getStatus () const; + + StatusOptional& + getStatus (); + + void + setStatus (const StatusType& x); + + void + setStatus (const StatusOptional& x); + + void + setStatus (::std::unique_ptr< StatusType > p); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // id + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String IdType; + typedef ::xsd::cxx::tree::traits< IdType, char > IdTraits; + + const IdType& + getId () const; + + IdType& + getId (); + + void + setId (const IdType& x); + + void + setId (::std::unique_ptr< IdType > p); + + ::std::unique_ptr< IdType > + setDetachId (); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + MediaType (const IdType&); + + MediaType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + MediaType (const MediaType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual MediaType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + MediaType& + operator= (const MediaType& x); + + virtual + ~MediaType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); + + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + + DisplayTextOptional display_text_; + TypeOptional type_; + LabelOptional label_; + SrcIdOptional src_id_; + StatusOptional status_; + AnySequence any_; + ::xsd::cxx::tree::one< IdType > id_; + AnyAttributeSet any_attribute_; + }; + + class MediaStatusType: public ::LinphonePrivate::Xsd::XmlSchema::String + { + public: + enum Value + { + recvonly, + sendonly, + sendrecv, + inactive + }; + + MediaStatusType (Value v); + + MediaStatusType (const char* v); + + MediaStatusType (const ::std::string& v); + + MediaStatusType (const ::LinphonePrivate::Xsd::XmlSchema::String& v); + + MediaStatusType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + MediaStatusType (const ::xercesc::DOMAttr& a, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + MediaStatusType (const ::std::string& s, const ::xercesc::DOMElement* e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - User_languages_type (const User_languages_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + MediaStatusType (const MediaStatusType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - virtual User_languages_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; + virtual MediaStatusType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; - virtual - ~User_languages_type (); - }; + MediaStatusType& + operator= (Value v); - class Endpoint_type: public ::xml_schema::Type - { - public: - // display-text - // - typedef ::xml_schema::String Display_textType; - typedef ::xsd::cxx::tree::optional< Display_textType > Display_textOptional; - typedef ::xsd::cxx::tree::traits< Display_textType, char > Display_textTraits; + virtual + operator Value () const + { + return _xsd_MediaStatusType_convert (); + } - const Display_textOptional& - getDisplay_text () const; + protected: + Value + _xsd_MediaStatusType_convert () const; - Display_textOptional& - getDisplay_text (); + public: + static const char* const _xsd_MediaStatusType_literals_[4]; + static const Value _xsd_MediaStatusType_indexes_[4]; + }; - void - setDisplay_text (const Display_textType& x); + class SidebarsByValType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // entry + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType EntryType; + typedef ::xsd::cxx::tree::sequence< EntryType > EntrySequence; + typedef EntrySequence::iterator EntryIterator; + typedef EntrySequence::const_iterator EntryConstIterator; + typedef ::xsd::cxx::tree::traits< EntryType, char > EntryTraits; + + const EntrySequence& + getEntry () const; + + EntrySequence& + getEntry (); + + void + setEntry (const EntrySequence& s); + + // state + // + typedef ::LinphonePrivate::Xsd::ConferenceInfo::StateType StateType; + typedef ::xsd::cxx::tree::traits< StateType, char > StateTraits; + + const StateType& + getState () const; + + StateType& + getState (); + + void + setState (const StateType& x); + + void + setState (::std::unique_ptr< StateType > p); + + ::std::unique_ptr< StateType > + setDetachState (); + + static const StateType& + getStateDefaultValue (); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + + const AnyAttributeSet& + getAnyAttribute () const; + + AnyAttributeSet& + getAnyAttribute (); + + void + setAnyAttribute (const AnyAttributeSet& s); + + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; + + ::xercesc::DOMDocument& + getDomDocument (); + + // Constructors. + // + SidebarsByValType (); + + SidebarsByValType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - void - setDisplay_text (const Display_textOptional& x); + SidebarsByValType (const SidebarsByValType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - void - setDisplay_text (::std::unique_ptr< Display_textType > p); + virtual SidebarsByValType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; - // referred - // - typedef ::conference_info::Execution_type ReferredType; - typedef ::xsd::cxx::tree::optional< ReferredType > ReferredOptional; - typedef ::xsd::cxx::tree::traits< ReferredType, char > ReferredTraits; + SidebarsByValType& + operator= (const SidebarsByValType& x); - const ReferredOptional& - getReferred () const; + virtual + ~SidebarsByValType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); - ReferredOptional& - getReferred (); + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - void - setReferred (const ReferredType& x); - - void - setReferred (const ReferredOptional& x); - - void - setReferred (::std::unique_ptr< ReferredType > p); - - // status - // - typedef ::conference_info::Endpoint_status_type StatusType; - typedef ::xsd::cxx::tree::optional< StatusType > StatusOptional; - typedef ::xsd::cxx::tree::traits< StatusType, char > StatusTraits; - - const StatusOptional& - getStatus () const; - - StatusOptional& - getStatus (); - - void - setStatus (const StatusType& x); - - void - setStatus (const StatusOptional& x); - - void - setStatus (::std::unique_ptr< StatusType > p); - - // joining-method - // - typedef ::conference_info::Joining_type Joining_methodType; - typedef ::xsd::cxx::tree::optional< Joining_methodType > Joining_methodOptional; - typedef ::xsd::cxx::tree::traits< Joining_methodType, char > Joining_methodTraits; - - const Joining_methodOptional& - getJoining_method () const; - - Joining_methodOptional& - getJoining_method (); - - void - setJoining_method (const Joining_methodType& x); - - void - setJoining_method (const Joining_methodOptional& x); - - void - setJoining_method (::std::unique_ptr< Joining_methodType > p); - - // joining-info - // - typedef ::conference_info::Execution_type Joining_infoType; - typedef ::xsd::cxx::tree::optional< Joining_infoType > Joining_infoOptional; - typedef ::xsd::cxx::tree::traits< Joining_infoType, char > Joining_infoTraits; - - const Joining_infoOptional& - getJoining_info () const; - - Joining_infoOptional& - getJoining_info (); - - void - setJoining_info (const Joining_infoType& x); - - void - setJoining_info (const Joining_infoOptional& x); - - void - setJoining_info (::std::unique_ptr< Joining_infoType > p); - - // disconnection-method - // - typedef ::conference_info::Disconnection_type Disconnection_methodType; - typedef ::xsd::cxx::tree::optional< Disconnection_methodType > Disconnection_methodOptional; - typedef ::xsd::cxx::tree::traits< Disconnection_methodType, char > Disconnection_methodTraits; - - const Disconnection_methodOptional& - getDisconnection_method () const; - - Disconnection_methodOptional& - getDisconnection_method (); - - void - setDisconnection_method (const Disconnection_methodType& x); - - void - setDisconnection_method (const Disconnection_methodOptional& x); - - void - setDisconnection_method (::std::unique_ptr< Disconnection_methodType > p); - - // disconnection-info - // - typedef ::conference_info::Execution_type Disconnection_infoType; - typedef ::xsd::cxx::tree::optional< Disconnection_infoType > Disconnection_infoOptional; - typedef ::xsd::cxx::tree::traits< Disconnection_infoType, char > Disconnection_infoTraits; - - const Disconnection_infoOptional& - getDisconnection_info () const; - - Disconnection_infoOptional& - getDisconnection_info (); - - void - setDisconnection_info (const Disconnection_infoType& x); - - void - setDisconnection_info (const Disconnection_infoOptional& x); - - void - setDisconnection_info (::std::unique_ptr< Disconnection_infoType > p); - - // media - // - typedef ::conference_info::Media_type MediaType; - typedef ::xsd::cxx::tree::sequence< MediaType > MediaSequence; - typedef MediaSequence::iterator MediaIterator; - typedef MediaSequence::const_iterator MediaConstIterator; - typedef ::xsd::cxx::tree::traits< MediaType, char > MediaTraits; - - const MediaSequence& - getMedia () const; - - MediaSequence& - getMedia (); - - void - setMedia (const MediaSequence& s); - - // call-info - // - typedef ::conference_info::Call_type Call_infoType; - typedef ::xsd::cxx::tree::optional< Call_infoType > Call_infoOptional; - typedef ::xsd::cxx::tree::traits< Call_infoType, char > Call_infoTraits; - - const Call_infoOptional& - getCall_info () const; - - Call_infoOptional& - getCall_info (); - - void - setCall_info (const Call_infoType& x); - - void - setCall_info (const Call_infoOptional& x); - - void - setCall_info (::std::unique_ptr< Call_infoType > p); - - // any - // - typedef ::xsd::cxx::tree::element_sequence AnySequence; - typedef AnySequence::iterator AnyIterator; - typedef AnySequence::const_iterator AnyConstIterator; - - const AnySequence& - getAny () const; - - AnySequence& - getAny (); - - void - setAny (const AnySequence& s); - - // entity - // - typedef ::xml_schema::String EntityType; - typedef ::xsd::cxx::tree::optional< EntityType > EntityOptional; - typedef ::xsd::cxx::tree::traits< EntityType, char > EntityTraits; - - const EntityOptional& - getEntity () const; - - EntityOptional& - getEntity (); - - void - setEntity (const EntityType& x); - - void - setEntity (const EntityOptional& x); - - void - setEntity (::std::unique_ptr< EntityType > p); - - // state - // - typedef ::conference_info::State_type StateType; - typedef ::xsd::cxx::tree::traits< StateType, char > StateTraits; - - const StateType& - getState () const; - - StateType& - getState (); - - void - setState (const StateType& x); - - void - setState (::std::unique_ptr< StateType > p); - - ::std::unique_ptr< StateType > - detachState (); - - static const StateType& - getStateDefaultValue (); - - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - - const AnyAttributeSet& - getAnyAttribute () const; - - AnyAttributeSet& - getAnyAttribute (); - - void - setAnyAttribute (const AnyAttributeSet& s); - - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; - - ::xercesc::DOMDocument& - getDomDocument (); - - // Constructors. - // - Endpoint_type (); - - Endpoint_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Endpoint_type (const Endpoint_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Endpoint_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Endpoint_type& - operator= (const Endpoint_type& x); - - virtual - ~Endpoint_type (); - - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); - - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - - Display_textOptional display_text_; - ReferredOptional referred_; - StatusOptional status_; - Joining_methodOptional joining_method_; - Joining_infoOptional joining_info_; - Disconnection_methodOptional disconnection_method_; - Disconnection_infoOptional disconnection_info_; - MediaSequence media_; - Call_infoOptional call_info_; - AnySequence any_; - EntityOptional entity_; - ::xsd::cxx::tree::one< StateType > state_; - static const StateType state_default_value_; - AnyAttributeSet any_attribute_; - }; - - class Endpoint_status_type: public ::xml_schema::String - { - public: - enum Value - { - pending, - dialing_out, - dialing_in, - alerting, - on_hold, - connected, - muted_via_focus, - disconnecting, - disconnected - }; - - Endpoint_status_type (Value v); - - Endpoint_status_type (const char* v); - - Endpoint_status_type (const ::std::string& v); - - Endpoint_status_type (const ::xml_schema::String& v); - - Endpoint_status_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Endpoint_status_type (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Endpoint_status_type (const ::std::string& s, - const ::xercesc::DOMElement* e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Endpoint_status_type (const Endpoint_status_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Endpoint_status_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Endpoint_status_type& - operator= (Value v); - - virtual - operator Value () const - { - return _xsd_Endpoint_status_type_convert (); + EntrySequence entry_; + ::xsd::cxx::tree::one< StateType > state_; + static const StateType state_default_value_; + AnyAttributeSet any_attribute_; + }; } - - protected: - Value - _xsd_Endpoint_status_type_convert () const; - - public: - static const char* const _xsd_Endpoint_status_type_literals_[9]; - static const Value _xsd_Endpoint_status_type_indexes_[9]; - }; - - class Joining_type: public ::xml_schema::String - { - public: - enum Value - { - dialed_in, - dialed_out, - focus_owner - }; - - Joining_type (Value v); - - Joining_type (const char* v); - - Joining_type (const ::std::string& v); - - Joining_type (const ::xml_schema::String& v); - - Joining_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Joining_type (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Joining_type (const ::std::string& s, - const ::xercesc::DOMElement* e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Joining_type (const Joining_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Joining_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Joining_type& - operator= (Value v); - - virtual - operator Value () const - { - return _xsd_Joining_type_convert (); - } - - protected: - Value - _xsd_Joining_type_convert () const; - - public: - static const char* const _xsd_Joining_type_literals_[3]; - static const Value _xsd_Joining_type_indexes_[3]; - }; - - class Disconnection_type: public ::xml_schema::String - { - public: - enum Value - { - departed, - booted, - failed, - busy - }; - - Disconnection_type (Value v); - - Disconnection_type (const char* v); - - Disconnection_type (const ::std::string& v); - - Disconnection_type (const ::xml_schema::String& v); - - Disconnection_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Disconnection_type (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Disconnection_type (const ::std::string& s, - const ::xercesc::DOMElement* e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Disconnection_type (const Disconnection_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Disconnection_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Disconnection_type& - operator= (Value v); - - virtual - operator Value () const - { - return _xsd_Disconnection_type_convert (); - } - - protected: - Value - _xsd_Disconnection_type_convert () const; - - public: - static const char* const _xsd_Disconnection_type_literals_[4]; - static const Value _xsd_Disconnection_type_indexes_[4]; - }; - - class Execution_type: public ::xml_schema::Type - { - public: - // when - // - typedef ::xml_schema::DateTime WhenType; - typedef ::xsd::cxx::tree::optional< WhenType > WhenOptional; - typedef ::xsd::cxx::tree::traits< WhenType, char > WhenTraits; - - const WhenOptional& - getWhen () const; - - WhenOptional& - getWhen (); - - void - setWhen (const WhenType& x); - - void - setWhen (const WhenOptional& x); - - void - setWhen (::std::unique_ptr< WhenType > p); - - // reason - // - typedef ::xml_schema::String ReasonType; - typedef ::xsd::cxx::tree::optional< ReasonType > ReasonOptional; - typedef ::xsd::cxx::tree::traits< ReasonType, char > ReasonTraits; - - const ReasonOptional& - getReason () const; - - ReasonOptional& - getReason (); - - void - setReason (const ReasonType& x); - - void - setReason (const ReasonOptional& x); - - void - setReason (::std::unique_ptr< ReasonType > p); - - // by - // - typedef ::xml_schema::Uri ByType; - typedef ::xsd::cxx::tree::optional< ByType > ByOptional; - typedef ::xsd::cxx::tree::traits< ByType, char > ByTraits; - - const ByOptional& - getBy () const; - - ByOptional& - getBy (); - - void - setBy (const ByType& x); - - void - setBy (const ByOptional& x); - - void - setBy (::std::unique_ptr< ByType > p); - - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - - const AnyAttributeSet& - getAnyAttribute () const; - - AnyAttributeSet& - getAnyAttribute (); - - void - setAnyAttribute (const AnyAttributeSet& s); - - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; - - ::xercesc::DOMDocument& - getDomDocument (); - - // Constructors. - // - Execution_type (); - - Execution_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Execution_type (const Execution_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Execution_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Execution_type& - operator= (const Execution_type& x); - - virtual - ~Execution_type (); - - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); - - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - - WhenOptional when_; - ReasonOptional reason_; - ByOptional by_; - AnyAttributeSet any_attribute_; - }; - - class Call_type: public ::xml_schema::Type - { - public: - // sip - // - typedef ::conference_info::Sip_dialog_id_type SipType; - typedef ::xsd::cxx::tree::optional< SipType > SipOptional; - typedef ::xsd::cxx::tree::traits< SipType, char > SipTraits; - - const SipOptional& - getSip () const; - - SipOptional& - getSip (); - - void - setSip (const SipType& x); - - void - setSip (const SipOptional& x); - - void - setSip (::std::unique_ptr< SipType > p); - - // any - // - typedef ::xsd::cxx::tree::element_sequence AnySequence; - typedef AnySequence::iterator AnyIterator; - typedef AnySequence::const_iterator AnyConstIterator; - - const AnySequence& - getAny () const; - - AnySequence& - getAny (); - - void - setAny (const AnySequence& s); - - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - - const AnyAttributeSet& - getAnyAttribute () const; - - AnyAttributeSet& - getAnyAttribute (); - - void - setAnyAttribute (const AnyAttributeSet& s); - - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; - - ::xercesc::DOMDocument& - getDomDocument (); - - // Constructors. - // - Call_type (); - - Call_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Call_type (const Call_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Call_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Call_type& - operator= (const Call_type& x); - - virtual - ~Call_type (); - - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); - - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - - SipOptional sip_; - AnySequence any_; - AnyAttributeSet any_attribute_; - }; - - class Sip_dialog_id_type: public ::xml_schema::Type - { - public: - // display-text - // - typedef ::xml_schema::String Display_textType; - typedef ::xsd::cxx::tree::optional< Display_textType > Display_textOptional; - typedef ::xsd::cxx::tree::traits< Display_textType, char > Display_textTraits; - - const Display_textOptional& - getDisplay_text () const; - - Display_textOptional& - getDisplay_text (); - - void - setDisplay_text (const Display_textType& x); - - void - setDisplay_text (const Display_textOptional& x); - - void - setDisplay_text (::std::unique_ptr< Display_textType > p); - - // call-id - // - typedef ::xml_schema::String Call_idType; - typedef ::xsd::cxx::tree::traits< Call_idType, char > Call_idTraits; - - const Call_idType& - getCall_id () const; - - Call_idType& - getCall_id (); - - void - setCall_id (const Call_idType& x); - - void - setCall_id (::std::unique_ptr< Call_idType > p); - - ::std::unique_ptr< Call_idType > - detachCall_id (); - - // from-tag - // - typedef ::xml_schema::String From_tagType; - typedef ::xsd::cxx::tree::traits< From_tagType, char > From_tagTraits; - - const From_tagType& - getFrom_tag () const; - - From_tagType& - getFrom_tag (); - - void - setFrom_tag (const From_tagType& x); - - void - setFrom_tag (::std::unique_ptr< From_tagType > p); - - ::std::unique_ptr< From_tagType > - detachFrom_tag (); - - // to-tag - // - typedef ::xml_schema::String To_tagType; - typedef ::xsd::cxx::tree::traits< To_tagType, char > To_tagTraits; - - const To_tagType& - getTo_tag () const; - - To_tagType& - getTo_tag (); - - void - setTo_tag (const To_tagType& x); - - void - setTo_tag (::std::unique_ptr< To_tagType > p); - - ::std::unique_ptr< To_tagType > - detachTo_tag (); - - // any - // - typedef ::xsd::cxx::tree::element_sequence AnySequence; - typedef AnySequence::iterator AnyIterator; - typedef AnySequence::const_iterator AnyConstIterator; - - const AnySequence& - getAny () const; - - AnySequence& - getAny (); - - void - setAny (const AnySequence& s); - - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - - const AnyAttributeSet& - getAnyAttribute () const; - - AnyAttributeSet& - getAnyAttribute (); - - void - setAnyAttribute (const AnyAttributeSet& s); - - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; - - ::xercesc::DOMDocument& - getDomDocument (); - - // Constructors. - // - Sip_dialog_id_type (const Call_idType&, - const From_tagType&, - const To_tagType&); - - Sip_dialog_id_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Sip_dialog_id_type (const Sip_dialog_id_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Sip_dialog_id_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Sip_dialog_id_type& - operator= (const Sip_dialog_id_type& x); - - virtual - ~Sip_dialog_id_type (); - - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); - - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - - Display_textOptional display_text_; - ::xsd::cxx::tree::one< Call_idType > call_id_; - ::xsd::cxx::tree::one< From_tagType > from_tag_; - ::xsd::cxx::tree::one< To_tagType > to_tag_; - AnySequence any_; - AnyAttributeSet any_attribute_; - }; - - class Media_type: public ::xml_schema::Type - { - public: - // display-text - // - typedef ::xml_schema::String Display_textType; - typedef ::xsd::cxx::tree::optional< Display_textType > Display_textOptional; - typedef ::xsd::cxx::tree::traits< Display_textType, char > Display_textTraits; - - const Display_textOptional& - getDisplay_text () const; - - Display_textOptional& - getDisplay_text (); - - void - setDisplay_text (const Display_textType& x); - - void - setDisplay_text (const Display_textOptional& x); - - void - setDisplay_text (::std::unique_ptr< Display_textType > p); - - // type - // - typedef ::xml_schema::String TypeType; - typedef ::xsd::cxx::tree::optional< TypeType > TypeOptional; - typedef ::xsd::cxx::tree::traits< TypeType, char > TypeTraits; - - const TypeOptional& - getType () const; - - TypeOptional& - getType (); - - void - setType (const TypeType& x); - - void - setType (const TypeOptional& x); - - void - setType (::std::unique_ptr< TypeType > p); - - // label - // - typedef ::xml_schema::String LabelType; - typedef ::xsd::cxx::tree::optional< LabelType > LabelOptional; - typedef ::xsd::cxx::tree::traits< LabelType, char > LabelTraits; - - const LabelOptional& - getLabel () const; - - LabelOptional& - getLabel (); - - void - setLabel (const LabelType& x); - - void - setLabel (const LabelOptional& x); - - void - setLabel (::std::unique_ptr< LabelType > p); - - // src-id - // - typedef ::xml_schema::String Src_idType; - typedef ::xsd::cxx::tree::optional< Src_idType > Src_idOptional; - typedef ::xsd::cxx::tree::traits< Src_idType, char > Src_idTraits; - - const Src_idOptional& - getSrc_id () const; - - Src_idOptional& - getSrc_id (); - - void - setSrc_id (const Src_idType& x); - - void - setSrc_id (const Src_idOptional& x); - - void - setSrc_id (::std::unique_ptr< Src_idType > p); - - // status - // - typedef ::conference_info::Media_status_type StatusType; - typedef ::xsd::cxx::tree::optional< StatusType > StatusOptional; - typedef ::xsd::cxx::tree::traits< StatusType, char > StatusTraits; - - const StatusOptional& - getStatus () const; - - StatusOptional& - getStatus (); - - void - setStatus (const StatusType& x); - - void - setStatus (const StatusOptional& x); - - void - setStatus (::std::unique_ptr< StatusType > p); - - // any - // - typedef ::xsd::cxx::tree::element_sequence AnySequence; - typedef AnySequence::iterator AnyIterator; - typedef AnySequence::const_iterator AnyConstIterator; - - const AnySequence& - getAny () const; - - AnySequence& - getAny (); - - void - setAny (const AnySequence& s); - - // id - // - typedef ::xml_schema::String IdType; - typedef ::xsd::cxx::tree::traits< IdType, char > IdTraits; - - const IdType& - getId () const; - - IdType& - getId (); - - void - setId (const IdType& x); - - void - setId (::std::unique_ptr< IdType > p); - - ::std::unique_ptr< IdType > - detachId (); - - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - - const AnyAttributeSet& - getAnyAttribute () const; - - AnyAttributeSet& - getAnyAttribute (); - - void - setAnyAttribute (const AnyAttributeSet& s); - - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; - - ::xercesc::DOMDocument& - getDomDocument (); - - // Constructors. - // - Media_type (const IdType&); - - Media_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Media_type (const Media_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Media_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Media_type& - operator= (const Media_type& x); - - virtual - ~Media_type (); - - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); - - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - - Display_textOptional display_text_; - TypeOptional type_; - LabelOptional label_; - Src_idOptional src_id_; - StatusOptional status_; - AnySequence any_; - ::xsd::cxx::tree::one< IdType > id_; - AnyAttributeSet any_attribute_; - }; - - class Media_status_type: public ::xml_schema::String - { - public: - enum Value - { - recvonly, - sendonly, - sendrecv, - inactive - }; - - Media_status_type (Value v); - - Media_status_type (const char* v); - - Media_status_type (const ::std::string& v); - - Media_status_type (const ::xml_schema::String& v); - - Media_status_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Media_status_type (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Media_status_type (const ::std::string& s, - const ::xercesc::DOMElement* e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Media_status_type (const Media_status_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Media_status_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Media_status_type& - operator= (Value v); - - virtual - operator Value () const - { - return _xsd_Media_status_type_convert (); - } - - protected: - Value - _xsd_Media_status_type_convert () const; - - public: - static const char* const _xsd_Media_status_type_literals_[4]; - static const Value _xsd_Media_status_type_indexes_[4]; - }; - - class Sidebars_by_val_type: public ::xml_schema::Type - { - public: - // entry - // - typedef ::conference_info::Conference_type EntryType; - typedef ::xsd::cxx::tree::sequence< EntryType > EntrySequence; - typedef EntrySequence::iterator EntryIterator; - typedef EntrySequence::const_iterator EntryConstIterator; - typedef ::xsd::cxx::tree::traits< EntryType, char > EntryTraits; - - const EntrySequence& - getEntry () const; - - EntrySequence& - getEntry (); - - void - setEntry (const EntrySequence& s); - - // state - // - typedef ::conference_info::State_type StateType; - typedef ::xsd::cxx::tree::traits< StateType, char > StateTraits; - - const StateType& - getState () const; - - StateType& - getState (); - - void - setState (const StateType& x); - - void - setState (::std::unique_ptr< StateType > p); - - ::std::unique_ptr< StateType > - detachState (); - - static const StateType& - getStateDefaultValue (); - - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - - const AnyAttributeSet& - getAnyAttribute () const; - - AnyAttributeSet& - getAnyAttribute (); - - void - setAnyAttribute (const AnyAttributeSet& s); - - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; - - ::xercesc::DOMDocument& - getDomDocument (); - - // Constructors. - // - Sidebars_by_val_type (); - - Sidebars_by_val_type (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Sidebars_by_val_type (const Sidebars_by_val_type& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Sidebars_by_val_type* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Sidebars_by_val_type& - operator= (const Sidebars_by_val_type& x); - - virtual - ~Sidebars_by_val_type (); - - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); - - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - - EntrySequence entry_; - ::xsd::cxx::tree::one< StateType > state_; - static const StateType state_default_value_; - AnyAttributeSet any_attribute_; - }; + } } #include -namespace conference_info +namespace LinphonePrivate { - ::std::ostream& - operator<< (::std::ostream&, const Conference_type&); + namespace Xsd + { + namespace ConferenceInfo + { + ::std::ostream& + operator<< (::std::ostream&, const ConferenceType&); - ::std::ostream& - operator<< (::std::ostream&, State_type::Value); + ::std::ostream& + operator<< (::std::ostream&, StateType::Value); - ::std::ostream& - operator<< (::std::ostream&, const State_type&); + ::std::ostream& + operator<< (::std::ostream&, const StateType&); - ::std::ostream& - operator<< (::std::ostream&, const Conference_description_type&); + ::std::ostream& + operator<< (::std::ostream&, const ConferenceDescriptionType&); - ::std::ostream& - operator<< (::std::ostream&, const Host_type&); + ::std::ostream& + operator<< (::std::ostream&, const HostType&); - ::std::ostream& - operator<< (::std::ostream&, const Conference_state_type&); + ::std::ostream& + operator<< (::std::ostream&, const ConferenceStateType&); - ::std::ostream& - operator<< (::std::ostream&, const Conference_media_type&); + ::std::ostream& + operator<< (::std::ostream&, const ConferenceMediaType&); - ::std::ostream& - operator<< (::std::ostream&, const Conference_medium_type&); + ::std::ostream& + operator<< (::std::ostream&, const ConferenceMediumType&); - ::std::ostream& - operator<< (::std::ostream&, const Uris_type&); + ::std::ostream& + operator<< (::std::ostream&, const UrisType&); - ::std::ostream& - operator<< (::std::ostream&, const Uri_type&); + ::std::ostream& + operator<< (::std::ostream&, const UriType&); - ::std::ostream& - operator<< (::std::ostream&, const Keywords_type&); + ::std::ostream& + operator<< (::std::ostream&, const KeywordsType&); - ::std::ostream& - operator<< (::std::ostream&, const Users_type&); + ::std::ostream& + operator<< (::std::ostream&, const UsersType&); - ::std::ostream& - operator<< (::std::ostream&, const User_type&); + ::std::ostream& + operator<< (::std::ostream&, const UserType&); - ::std::ostream& - operator<< (::std::ostream&, const User_roles_type&); + ::std::ostream& + operator<< (::std::ostream&, const UserRolesType&); - ::std::ostream& - operator<< (::std::ostream&, const User_languages_type&); + ::std::ostream& + operator<< (::std::ostream&, const UserLanguagesType&); - ::std::ostream& - operator<< (::std::ostream&, const Endpoint_type&); + ::std::ostream& + operator<< (::std::ostream&, const EndpointType&); - ::std::ostream& - operator<< (::std::ostream&, Endpoint_status_type::Value); + ::std::ostream& + operator<< (::std::ostream&, EndpointStatusType::Value); - ::std::ostream& - operator<< (::std::ostream&, const Endpoint_status_type&); + ::std::ostream& + operator<< (::std::ostream&, const EndpointStatusType&); - ::std::ostream& - operator<< (::std::ostream&, Joining_type::Value); + ::std::ostream& + operator<< (::std::ostream&, JoiningType::Value); - ::std::ostream& - operator<< (::std::ostream&, const Joining_type&); + ::std::ostream& + operator<< (::std::ostream&, const JoiningType&); - ::std::ostream& - operator<< (::std::ostream&, Disconnection_type::Value); + ::std::ostream& + operator<< (::std::ostream&, DisconnectionType::Value); - ::std::ostream& - operator<< (::std::ostream&, const Disconnection_type&); + ::std::ostream& + operator<< (::std::ostream&, const DisconnectionType&); - ::std::ostream& - operator<< (::std::ostream&, const Execution_type&); + ::std::ostream& + operator<< (::std::ostream&, const ExecutionType&); - ::std::ostream& - operator<< (::std::ostream&, const Call_type&); + ::std::ostream& + operator<< (::std::ostream&, const CallType&); - ::std::ostream& - operator<< (::std::ostream&, const Sip_dialog_id_type&); + ::std::ostream& + operator<< (::std::ostream&, const SipDialogIdType&); - ::std::ostream& - operator<< (::std::ostream&, const Media_type&); + ::std::ostream& + operator<< (::std::ostream&, const MediaType&); - ::std::ostream& - operator<< (::std::ostream&, Media_status_type::Value); + ::std::ostream& + operator<< (::std::ostream&, MediaStatusType::Value); - ::std::ostream& - operator<< (::std::ostream&, const Media_status_type&); + ::std::ostream& + operator<< (::std::ostream&, const MediaStatusType&); - ::std::ostream& - operator<< (::std::ostream&, const Sidebars_by_val_type&); + ::std::ostream& + operator<< (::std::ostream&, const SidebarsByValType&); + } + } } #include @@ -3562,100 +3584,106 @@ namespace conference_info #include #include -namespace conference_info +namespace LinphonePrivate { - // Parse a URI or a local file. - // + namespace Xsd + { + namespace ConferenceInfo + { + // Parse a URI or a local file. + // - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (const ::std::string& uri, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (const ::std::string& uri, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (const ::std::string& uri, - ::xml_schema::ErrorHandler& eh, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (const ::std::string& uri, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& eh, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (const ::std::string& uri, - ::xercesc::DOMErrorHandler& eh, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (const ::std::string& uri, + ::xercesc::DOMErrorHandler& eh, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - // Parse std::istream. - // + // Parse std::istream. + // - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::std::istream& is, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::std::istream& is, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::std::istream& is, - ::xml_schema::ErrorHandler& eh, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::std::istream& is, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& eh, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::std::istream& is, - ::xercesc::DOMErrorHandler& eh, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::std::istream& is, + ::xercesc::DOMErrorHandler& eh, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::std::istream& is, - const ::std::string& id, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::std::istream& is, + const ::std::string& id, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::std::istream& is, - const ::std::string& id, - ::xml_schema::ErrorHandler& eh, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::std::istream& is, + const ::std::string& id, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& eh, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::std::istream& is, - const ::std::string& id, - ::xercesc::DOMErrorHandler& eh, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::std::istream& is, + const ::std::string& id, + ::xercesc::DOMErrorHandler& eh, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - // Parse xercesc::InputSource. - // + // Parse xercesc::InputSource. + // - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::xercesc::InputSource& is, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::xercesc::InputSource& is, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::xercesc::InputSource& is, - ::xml_schema::ErrorHandler& eh, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::xercesc::InputSource& is, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& eh, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::xercesc::InputSource& is, - ::xercesc::DOMErrorHandler& eh, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::xercesc::InputSource& is, + ::xercesc::DOMErrorHandler& eh, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - // Parse xercesc::DOMDocument. - // + // Parse xercesc::DOMDocument. + // - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (const ::xercesc::DOMDocument& d, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (const ::xercesc::DOMDocument& d, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::conference_info::Conference_type > - parseConference_info (::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType > + parseConferenceInfo (::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); + } + } } #include @@ -3666,207 +3694,211 @@ namespace conference_info #include -namespace conference_info +namespace LinphonePrivate { - // Serialize to std::ostream. - // + namespace Xsd + { + namespace ConferenceInfo + { + // Serialize to std::ostream. + // - void - serializeConference_info (::std::ostream& os, - const ::conference_info::Conference_type& x, - const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), - const ::std::string& e = "UTF-8", - ::xml_schema::Flags f = 0); + void + serializeConferenceInfo (::std::ostream& os, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); - void - serializeConference_info (::std::ostream& os, - const ::conference_info::Conference_type& x, - ::xml_schema::ErrorHandler& eh, - const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), - const ::std::string& e = "UTF-8", - ::xml_schema::Flags f = 0); + void + serializeConferenceInfo (::std::ostream& os, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& eh, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); - void - serializeConference_info (::std::ostream& os, - const ::conference_info::Conference_type& x, - ::xercesc::DOMErrorHandler& eh, - const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), - const ::std::string& e = "UTF-8", - ::xml_schema::Flags f = 0); + void + serializeConferenceInfo (::std::ostream& os, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, + ::xercesc::DOMErrorHandler& eh, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); - // Serialize to xercesc::XMLFormatTarget. - // + // Serialize to xercesc::XMLFormatTarget. + // - void - serializeConference_info (::xercesc::XMLFormatTarget& ft, - const ::conference_info::Conference_type& x, - const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), - const ::std::string& e = "UTF-8", - ::xml_schema::Flags f = 0); + void + serializeConferenceInfo (::xercesc::XMLFormatTarget& ft, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); - void - serializeConference_info (::xercesc::XMLFormatTarget& ft, - const ::conference_info::Conference_type& x, - ::xml_schema::ErrorHandler& eh, - const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), - const ::std::string& e = "UTF-8", - ::xml_schema::Flags f = 0); + void + serializeConferenceInfo (::xercesc::XMLFormatTarget& ft, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& eh, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); - void - serializeConference_info (::xercesc::XMLFormatTarget& ft, - const ::conference_info::Conference_type& x, - ::xercesc::DOMErrorHandler& eh, - const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), - const ::std::string& e = "UTF-8", - ::xml_schema::Flags f = 0); + void + serializeConferenceInfo (::xercesc::XMLFormatTarget& ft, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, + ::xercesc::DOMErrorHandler& eh, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); - // Serialize to an existing xercesc::DOMDocument. - // + // Serialize to an existing xercesc::DOMDocument. + // - void - serializeConference_info (::xercesc::DOMDocument& d, - const ::conference_info::Conference_type& x, - ::xml_schema::Flags f = 0); + void + serializeConferenceInfo (::xercesc::DOMDocument& d, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); - // Serialize to a new xercesc::DOMDocument. - // + // Serialize to a new xercesc::DOMDocument. + // - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > - serializeConference_info (const ::conference_info::Conference_type& x, - const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), - ::xml_schema::Flags f = 0); + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > + serializeConferenceInfo (const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); - void - operator<< (::xercesc::DOMElement&, const Conference_type&); + void + operator<< (::xercesc::DOMElement&, const ConferenceType&); - void - operator<< (::xercesc::DOMElement&, const State_type&); + void + operator<< (::xercesc::DOMElement&, const StateType&); - void - operator<< (::xercesc::DOMAttr&, const State_type&); + void + operator<< (::xercesc::DOMAttr&, const StateType&); - void - operator<< (::xml_schema::ListStream&, - const State_type&); + void + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream&, + const StateType&); - void - operator<< (::xercesc::DOMElement&, const Conference_description_type&); + void + operator<< (::xercesc::DOMElement&, const ConferenceDescriptionType&); - void - operator<< (::xercesc::DOMElement&, const Host_type&); + void + operator<< (::xercesc::DOMElement&, const HostType&); - void - operator<< (::xercesc::DOMElement&, const Conference_state_type&); + void + operator<< (::xercesc::DOMElement&, const ConferenceStateType&); - void - operator<< (::xercesc::DOMElement&, const Conference_media_type&); + void + operator<< (::xercesc::DOMElement&, const ConferenceMediaType&); - void - operator<< (::xercesc::DOMElement&, const Conference_medium_type&); + void + operator<< (::xercesc::DOMElement&, const ConferenceMediumType&); - void - operator<< (::xercesc::DOMElement&, const Uris_type&); + void + operator<< (::xercesc::DOMElement&, const UrisType&); - void - operator<< (::xercesc::DOMElement&, const Uri_type&); + void + operator<< (::xercesc::DOMElement&, const UriType&); - void - operator<< (::xercesc::DOMElement&, const Keywords_type&); + void + operator<< (::xercesc::DOMElement&, const KeywordsType&); - void - operator<< (::xercesc::DOMAttr&, const Keywords_type&); + void + operator<< (::xercesc::DOMAttr&, const KeywordsType&); - void - operator<< (::xml_schema::ListStream&, - const Keywords_type&); + void + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream&, + const KeywordsType&); - void - operator<< (::xercesc::DOMElement&, const Users_type&); + void + operator<< (::xercesc::DOMElement&, const UsersType&); - void - operator<< (::xercesc::DOMElement&, const User_type&); + void + operator<< (::xercesc::DOMElement&, const UserType&); - void - operator<< (::xercesc::DOMElement&, const User_roles_type&); + void + operator<< (::xercesc::DOMElement&, const UserRolesType&); - void - operator<< (::xercesc::DOMElement&, const User_languages_type&); + void + operator<< (::xercesc::DOMElement&, const UserLanguagesType&); - void - operator<< (::xercesc::DOMAttr&, const User_languages_type&); + void + operator<< (::xercesc::DOMAttr&, const UserLanguagesType&); - void - operator<< (::xml_schema::ListStream&, - const User_languages_type&); + void + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream&, + const UserLanguagesType&); - void - operator<< (::xercesc::DOMElement&, const Endpoint_type&); + void + operator<< (::xercesc::DOMElement&, const EndpointType&); - void - operator<< (::xercesc::DOMElement&, const Endpoint_status_type&); + void + operator<< (::xercesc::DOMElement&, const EndpointStatusType&); - void - operator<< (::xercesc::DOMAttr&, const Endpoint_status_type&); + void + operator<< (::xercesc::DOMAttr&, const EndpointStatusType&); - void - operator<< (::xml_schema::ListStream&, - const Endpoint_status_type&); + void + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream&, + const EndpointStatusType&); - void - operator<< (::xercesc::DOMElement&, const Joining_type&); + void + operator<< (::xercesc::DOMElement&, const JoiningType&); - void - operator<< (::xercesc::DOMAttr&, const Joining_type&); + void + operator<< (::xercesc::DOMAttr&, const JoiningType&); - void - operator<< (::xml_schema::ListStream&, - const Joining_type&); + void + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream&, + const JoiningType&); - void - operator<< (::xercesc::DOMElement&, const Disconnection_type&); + void + operator<< (::xercesc::DOMElement&, const DisconnectionType&); - void - operator<< (::xercesc::DOMAttr&, const Disconnection_type&); + void + operator<< (::xercesc::DOMAttr&, const DisconnectionType&); - void - operator<< (::xml_schema::ListStream&, - const Disconnection_type&); + void + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream&, + const DisconnectionType&); - void - operator<< (::xercesc::DOMElement&, const Execution_type&); + void + operator<< (::xercesc::DOMElement&, const ExecutionType&); - void - operator<< (::xercesc::DOMElement&, const Call_type&); + void + operator<< (::xercesc::DOMElement&, const CallType&); - void - operator<< (::xercesc::DOMElement&, const Sip_dialog_id_type&); + void + operator<< (::xercesc::DOMElement&, const SipDialogIdType&); - void - operator<< (::xercesc::DOMElement&, const Media_type&); + void + operator<< (::xercesc::DOMElement&, const MediaType&); - void - operator<< (::xercesc::DOMElement&, const Media_status_type&); + void + operator<< (::xercesc::DOMElement&, const MediaStatusType&); - void - operator<< (::xercesc::DOMAttr&, const Media_status_type&); + void + operator<< (::xercesc::DOMAttr&, const MediaStatusType&); - void - operator<< (::xml_schema::ListStream&, - const Media_status_type&); + void + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream&, + const MediaStatusType&); - void - operator<< (::xercesc::DOMElement&, const Sidebars_by_val_type&); + void + operator<< (::xercesc::DOMElement&, const SidebarsByValType&); + } + } } #include // Begin epilogue. // - #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic pop #endif - // // End epilogue. diff --git a/src/xml/epilogue.txt b/src/xml/epilogue.txt new file mode 100644 index 000000000..ebe68c888 --- /dev/null +++ b/src/xml/epilogue.txt @@ -0,0 +1,3 @@ +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic pop +#endif diff --git a/src/xml/generate.py b/src/xml/generate.py index 256230869..c5484eaf9 100755 --- a/src/xml/generate.py +++ b/src/xml/generate.py @@ -30,21 +30,6 @@ def find_xsdcxx(): xsdcxx = find_executable("xsd") return xsdcxx -def get_prologue(): - return """ -#if __clang__ || __GNUC__ >= 4 -\t#pragma GCC diagnostic push -\t#pragma GCC diagnostic ignored "-Wsuggest-override" -#endif -""" - -def get_epilogue(): - return """ -#if __clang__ || __GNUC__ >= 4 -\t#pragma GCC diagnostic pop -#endif -""" - def generate(name): xsdcxx = find_xsdcxx() if xsdcxx is None: @@ -56,6 +41,8 @@ def generate(name): source_file = name + ".xsd" print("Generating code from " + source_file) source_file = os.path.join("xml", source_file) + prologue_file = os.path.join("xml", "prologue.txt") + epilogue_file = os.path.join("xml", "epilogue.txt") work_dir = os.path.join(script_dir, "..") os.chdir(work_dir) p = Popen([xsdcxx, @@ -67,15 +54,43 @@ def generate(name): "--std", "c++11", "--type-naming", "java", "--function-naming", "java", - "--location-regex-trace", - "--show-sloc", "--hxx-suffix", ".h", "--ixx-suffix", ".h", "--cxx-suffix", ".cpp", - "--prologue", get_prologue(), - "--epilogue", get_epilogue(), "--location-regex", "%http://.+/(.+)%$1%", "--output-dir", "xml", + "--show-sloc", + "--prologue-file", prologue_file, + "--epilogue-file", epilogue_file, + "--type-regex", "%(?:[^ ]* )?([^,-]+)-([^,-]+)-([^,-]+)-?([^,-]*)%\\u$1\\u$2\\u$3\\u$4%", + "--type-regex", "%(?:[^ ]* )?([^,-]+)-([^,-]+)-?([^,-]*)%\\u$1\\u$2\\u$3%", + "--type-regex", "%(?:[^ ]* )?([^,-]+)-?([^,-]*)%\\u$1\\u$2%", + "--type-regex", "%(?:[^ ]* )?([^,-]+)-([^,-]+)-([^,-]+)-?([^,-]*),([^,]+)%\\u$1\\u$2\\u$3\\u$4\\l\\u$5%", + "--type-regex", "%(?:[^ ]* )?([^,-]+)-([^,-]+)-?([^,-]*),([^,]+)%\\u$1\\u$2\\u$3\\l\\u$4%", + "--type-regex", "%(?:[^ ]* )?([^,-]+)-?([^,-]*),([^,]+)%\\u$1\\u$2\\l\\u$3%", + "--type-regex", "%(?:[^ ]* )?([^,-]+)-([^,-]+)-([^,-]+)-?([^,-]*),([^,]+),([^,]+)%\\u$1\\u$2\\u$3\\u$4\\l\\u$5\\u$6%", + "--type-regex", "%(?:[^ ]* )?([^,-]+)-([^,-]+)-?([^,-]*),([^,]+),([^,]+)%\\u$1\\u$2\\u$3\\l\\u$4\\u$5%", + "--type-regex", "%(?:[^ ]* )?([^,-]+)-?([^,-]*),([^,]+),([^,]+)%\\u$1\\u$2\\l\\u$3\\u$4%", + "--type-regex", "%(?:[^ ]* )?([^,-]+)-([^,-]+)-([^,-]+)-?([^,-]*),([^,]+),([^,]+),([^,]+)%\\u$1\\u$2\\u$3\\u$4\\l\\u$5\\u$6\\u$7%", + "--type-regex", "%(?:[^ ]* )?([^,-]+)-([^,-]+)-?([^,-]*),([^,]+),([^,]+),([^,]+)%\\u$1\\u$2\\u$3\\l\\u$4\\u$5\\u$6%", + "--type-regex", "%(?:[^ ]* )?([^,-]+)-?([^,-]*),([^,]+),([^,]+),([^,]+)%\\u$1\\u$2\\l\\u$3\\u$4\\u$5%", + "--accessor-regex", "%([^,-]+)-([^,-]+)-?([^,-]*)%get\\u$1\\u$2\\u$3%", + "--accessor-regex", "%([^,-]+)-?([^,-]*)%get\\u$1\\u$2%", + "--accessor-regex", "%([^,-]+)-([^,-]+)-?([^,-]*),([^,]+)%get\\u$1\\u$2\\u$3\\l\\u$4%", + "--accessor-regex", "%([^,-]+)-?([^,-]*),([^,]+)%get\\u$1\\u$2\\l\\u$3%", + "--accessor-regex", "%([^,-]+)-([^,-]+)-?([^,-]*),([^,]+),([^,]+)%get\\u$1\\u$2\\u$3\\l\\u$4\\u$5%", + "--accessor-regex", "%([^,-]+)-?([^,-]*),([^,]+),([^,]+)%get\\u$1\\u$2\\l\\u$3\\u$4%", + "--modifier-regex", "%([^,-]+)-([^,-]+)-?([^,-]*)%set\\u$1\\u$2\\u$3%", + "--modifier-regex", "%([^,-]+)-?([^,-]*)%set\\u$1\\u$2%", + "--modifier-regex", "%([^,-]+)-([^,-]+)-?([^,-]*),([^,]+)%set\\u$1\\u$2\\u$3\\l\\u$4%", + "--modifier-regex", "%([^,-]+)-?([^,-]*),([^,]+)%set\\u$1\\u$2\\l\\u$3%", + "--modifier-regex", "%([^,-]+)-([^,-]+)-?([^,-]*),([^,]+),([^,]+)%set\\u$1\\u$2\\u$3\\l\\u$4\\u$5%", + "--modifier-regex", "%([^,-]+)-?([^,-]*),([^,]+),([^,]+)%set\\u$1\\u$2\\l\\u$3\\u$4%", + "--parser-regex", "%([^-]+)-?([^-]*)%parse\\u$1\\u$2%", + "--serializer-regex", "%([^-]+)-?([^-]*)%serialize\\u$1\\u$2%", + "--namespace-map", "http://www.w3.org/2001/XMLSchema=LinphonePrivate::Xsd::XmlSchema", + "--namespace-map", "urn:ietf:params:xml:ns:conference-info=LinphonePrivate::Xsd::ConferenceInfo", + "--namespace-map", "urn:ietf:params:xml:ns:resource-lists=LinphonePrivate::Xsd::ResourceLists", source_file ], shell=False) p.communicate() diff --git a/src/xml/prologue.txt b/src/xml/prologue.txt new file mode 100644 index 000000000..1b3a4dc48 --- /dev/null +++ b/src/xml/prologue.txt @@ -0,0 +1,4 @@ +#if __clang__ || __GNUC__ >= 4 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wsuggest-override" +#endif diff --git a/src/xml/resource-lists.cpp b/src/xml/resource-lists.cpp index bbafc58ea..848bcc6f1 100644 --- a/src/xml/resource-lists.cpp +++ b/src/xml/resource-lists.cpp @@ -33,12 +33,10 @@ // Begin prologue. // - #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsuggest-override" #endif - // // End prologue. @@ -46,589 +44,595 @@ #include "resource-lists.h" -namespace resource_lists +namespace LinphonePrivate { - // ListType - // - - const ListType::Display_nameOptional& ListType:: - getDisplay_name () const - { - return this->display_name_; - } - - ListType::Display_nameOptional& ListType:: - getDisplay_name () - { - return this->display_name_; - } - - void ListType:: - setDisplay_name (const Display_nameType& x) - { - this->display_name_.set (x); - } - - void ListType:: - setDisplay_name (const Display_nameOptional& x) - { - this->display_name_ = x; - } - - void ListType:: - setDisplay_name (::std::unique_ptr< Display_nameType > x) - { - this->display_name_.set (std::move (x)); - } - - const ListType::ListSequence& ListType:: - getList () const - { - return this->list_; - } - - ListType::ListSequence& ListType:: - getList () - { - return this->list_; - } - - void ListType:: - setList (const ListSequence& s) - { - this->list_ = s; - } - - const ListType::ExternalSequence& ListType:: - getExternal () const - { - return this->external_; - } - - ListType::ExternalSequence& ListType:: - getExternal () - { - return this->external_; - } - - void ListType:: - setExternal (const ExternalSequence& s) - { - this->external_ = s; - } - - const ListType::EntrySequence& ListType:: - getEntry () const - { - return this->entry_; - } - - ListType::EntrySequence& ListType:: - getEntry () - { - return this->entry_; - } - - void ListType:: - setEntry (const EntrySequence& s) - { - this->entry_ = s; - } - - const ListType::Entry_refSequence& ListType:: - getEntry_ref () const - { - return this->entry_ref_; - } - - ListType::Entry_refSequence& ListType:: - getEntry_ref () - { - return this->entry_ref_; - } - - void ListType:: - setEntry_ref (const Entry_refSequence& s) - { - this->entry_ref_ = s; - } - - const ListType::AnySequence& ListType:: - getAny () const - { - return this->any_; - } - - ListType::AnySequence& ListType:: - getAny () - { - return this->any_; - } - - void ListType:: - setAny (const AnySequence& s) - { - this->any_ = s; - } - - const ListType::NameOptional& ListType:: - getName () const - { - return this->name_; - } - - ListType::NameOptional& ListType:: - getName () - { - return this->name_; - } - - void ListType:: - setName (const NameType& x) - { - this->name_.set (x); - } - - void ListType:: - setName (const NameOptional& x) - { - this->name_ = x; - } - - void ListType:: - setName (::std::unique_ptr< NameType > x) - { - this->name_.set (std::move (x)); - } - - const ListType::AnyAttributeSet& ListType:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - ListType::AnyAttributeSet& ListType:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void ListType:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& ListType:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& ListType:: - getDomDocument () - { - return *this->dom_document_; - } - - - // EntryType - // - - const EntryType::Display_nameOptional& EntryType:: - getDisplay_name () const - { - return this->display_name_; - } - - EntryType::Display_nameOptional& EntryType:: - getDisplay_name () - { - return this->display_name_; - } - - void EntryType:: - setDisplay_name (const Display_nameType& x) - { - this->display_name_.set (x); - } - - void EntryType:: - setDisplay_name (const Display_nameOptional& x) - { - this->display_name_ = x; - } - - void EntryType:: - setDisplay_name (::std::unique_ptr< Display_nameType > x) - { - this->display_name_.set (std::move (x)); - } - - const EntryType::AnySequence& EntryType:: - getAny () const - { - return this->any_; - } - - EntryType::AnySequence& EntryType:: - getAny () - { - return this->any_; - } - - void EntryType:: - setAny (const AnySequence& s) - { - this->any_ = s; - } - - const EntryType::UriType& EntryType:: - getUri () const - { - return this->uri_.get (); - } - - EntryType::UriType& EntryType:: - getUri () - { - return this->uri_.get (); - } - - void EntryType:: - setUri (const UriType& x) - { - this->uri_.set (x); - } - - void EntryType:: - setUri (::std::unique_ptr< UriType > x) - { - this->uri_.set (std::move (x)); - } - - ::std::unique_ptr< EntryType::UriType > EntryType:: - detachUri () - { - return this->uri_.detach (); - } - - const EntryType::AnyAttributeSet& EntryType:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - EntryType::AnyAttributeSet& EntryType:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void EntryType:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& EntryType:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& EntryType:: - getDomDocument () - { - return *this->dom_document_; - } - - - // Entry_refType - // - - const Entry_refType::Display_nameOptional& Entry_refType:: - getDisplay_name () const - { - return this->display_name_; - } - - Entry_refType::Display_nameOptional& Entry_refType:: - getDisplay_name () - { - return this->display_name_; - } - - void Entry_refType:: - setDisplay_name (const Display_nameType& x) - { - this->display_name_.set (x); - } - - void Entry_refType:: - setDisplay_name (const Display_nameOptional& x) - { - this->display_name_ = x; - } - - void Entry_refType:: - setDisplay_name (::std::unique_ptr< Display_nameType > x) - { - this->display_name_.set (std::move (x)); - } - - const Entry_refType::AnySequence& Entry_refType:: - getAny () const - { - return this->any_; - } - - Entry_refType::AnySequence& Entry_refType:: - getAny () - { - return this->any_; - } - - void Entry_refType:: - setAny (const AnySequence& s) - { - this->any_ = s; - } - - const Entry_refType::RefType& Entry_refType:: - getRef () const - { - return this->ref_.get (); - } - - Entry_refType::RefType& Entry_refType:: - getRef () - { - return this->ref_.get (); - } - - void Entry_refType:: - setRef (const RefType& x) - { - this->ref_.set (x); - } - - void Entry_refType:: - setRef (::std::unique_ptr< RefType > x) - { - this->ref_.set (std::move (x)); - } - - ::std::unique_ptr< Entry_refType::RefType > Entry_refType:: - detachRef () - { - return this->ref_.detach (); - } - - const Entry_refType::AnyAttributeSet& Entry_refType:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - Entry_refType::AnyAttributeSet& Entry_refType:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void Entry_refType:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& Entry_refType:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& Entry_refType:: - getDomDocument () - { - return *this->dom_document_; - } - - - // ExternalType - // - - const ExternalType::Display_nameOptional& ExternalType:: - getDisplay_name () const - { - return this->display_name_; - } - - ExternalType::Display_nameOptional& ExternalType:: - getDisplay_name () - { - return this->display_name_; - } - - void ExternalType:: - setDisplay_name (const Display_nameType& x) - { - this->display_name_.set (x); - } - - void ExternalType:: - setDisplay_name (const Display_nameOptional& x) - { - this->display_name_ = x; - } - - void ExternalType:: - setDisplay_name (::std::unique_ptr< Display_nameType > x) - { - this->display_name_.set (std::move (x)); - } - - const ExternalType::AnySequence& ExternalType:: - getAny () const - { - return this->any_; - } - - ExternalType::AnySequence& ExternalType:: - getAny () - { - return this->any_; - } - - void ExternalType:: - setAny (const AnySequence& s) - { - this->any_ = s; - } - - const ExternalType::AnchorOptional& ExternalType:: - getAnchor () const - { - return this->anchor_; - } - - ExternalType::AnchorOptional& ExternalType:: - getAnchor () - { - return this->anchor_; - } - - void ExternalType:: - setAnchor (const AnchorType& x) - { - this->anchor_.set (x); - } - - void ExternalType:: - setAnchor (const AnchorOptional& x) - { - this->anchor_ = x; - } - - void ExternalType:: - setAnchor (::std::unique_ptr< AnchorType > x) - { - this->anchor_.set (std::move (x)); - } - - const ExternalType::AnyAttributeSet& ExternalType:: - getAnyAttribute () const - { - return this->any_attribute_; - } - - ExternalType::AnyAttributeSet& ExternalType:: - getAnyAttribute () - { - return this->any_attribute_; - } - - void ExternalType:: - setAnyAttribute (const AnyAttributeSet& s) - { - this->any_attribute_ = s; - } - - const ::xercesc::DOMDocument& ExternalType:: - getDomDocument () const - { - return *this->dom_document_; - } - - ::xercesc::DOMDocument& ExternalType:: - getDomDocument () - { - return *this->dom_document_; - } - - - // Display_nameType - // - - const Display_nameType::LangOptional& Display_nameType:: - getLang () const - { - return this->lang_; - } - - Display_nameType::LangOptional& Display_nameType:: - getLang () - { - return this->lang_; - } - - void Display_nameType:: - setLang (const LangType& x) - { - this->lang_.set (x); - } - - void Display_nameType:: - setLang (const LangOptional& x) - { - this->lang_ = x; - } - - void Display_nameType:: - setLang (::std::unique_ptr< LangType > x) - { - this->lang_.set (std::move (x)); - } - - - // List - // - - - // Display_name - // - - - // Resource_lists - // - - const Resource_lists::ListSequence& Resource_lists:: - getList () const - { - return this->list_; - } - - Resource_lists::ListSequence& Resource_lists:: - getList () - { - return this->list_; - } - - void Resource_lists:: - setList (const ListSequence& s) - { - this->list_ = s; + namespace Xsd + { + namespace ResourceLists + { + // ListType + // + + const ListType::DisplayNameOptional& ListType:: + getDisplayName () const + { + return this->display_name_; + } + + ListType::DisplayNameOptional& ListType:: + getDisplayName () + { + return this->display_name_; + } + + void ListType:: + setDisplayName (const DisplayNameType& x) + { + this->display_name_.set (x); + } + + void ListType:: + setDisplayName (const DisplayNameOptional& x) + { + this->display_name_ = x; + } + + void ListType:: + setDisplayName (::std::unique_ptr< DisplayNameType > x) + { + this->display_name_.set (std::move (x)); + } + + const ListType::ListSequence& ListType:: + getList () const + { + return this->list_; + } + + ListType::ListSequence& ListType:: + getList () + { + return this->list_; + } + + void ListType:: + setList (const ListSequence& s) + { + this->list_ = s; + } + + const ListType::ExternalSequence& ListType:: + getExternal () const + { + return this->external_; + } + + ListType::ExternalSequence& ListType:: + getExternal () + { + return this->external_; + } + + void ListType:: + setExternal (const ExternalSequence& s) + { + this->external_ = s; + } + + const ListType::EntrySequence& ListType:: + getEntry () const + { + return this->entry_; + } + + ListType::EntrySequence& ListType:: + getEntry () + { + return this->entry_; + } + + void ListType:: + setEntry (const EntrySequence& s) + { + this->entry_ = s; + } + + const ListType::EntryRefSequence& ListType:: + getEntryRef () const + { + return this->entry_ref_; + } + + ListType::EntryRefSequence& ListType:: + getEntryRef () + { + return this->entry_ref_; + } + + void ListType:: + setEntryRef (const EntryRefSequence& s) + { + this->entry_ref_ = s; + } + + const ListType::AnySequence& ListType:: + getAny () const + { + return this->any_; + } + + ListType::AnySequence& ListType:: + getAny () + { + return this->any_; + } + + void ListType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const ListType::NameOptional& ListType:: + getName () const + { + return this->name_; + } + + ListType::NameOptional& ListType:: + getName () + { + return this->name_; + } + + void ListType:: + setName (const NameType& x) + { + this->name_.set (x); + } + + void ListType:: + setName (const NameOptional& x) + { + this->name_ = x; + } + + void ListType:: + setName (::std::unique_ptr< NameType > x) + { + this->name_.set (std::move (x)); + } + + const ListType::AnyAttributeSet& ListType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + ListType::AnyAttributeSet& ListType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void ListType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& ListType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& ListType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // EntryType + // + + const EntryType::DisplayNameOptional& EntryType:: + getDisplayName () const + { + return this->display_name_; + } + + EntryType::DisplayNameOptional& EntryType:: + getDisplayName () + { + return this->display_name_; + } + + void EntryType:: + setDisplayName (const DisplayNameType& x) + { + this->display_name_.set (x); + } + + void EntryType:: + setDisplayName (const DisplayNameOptional& x) + { + this->display_name_ = x; + } + + void EntryType:: + setDisplayName (::std::unique_ptr< DisplayNameType > x) + { + this->display_name_.set (std::move (x)); + } + + const EntryType::AnySequence& EntryType:: + getAny () const + { + return this->any_; + } + + EntryType::AnySequence& EntryType:: + getAny () + { + return this->any_; + } + + void EntryType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const EntryType::UriType& EntryType:: + getUri () const + { + return this->uri_.get (); + } + + EntryType::UriType& EntryType:: + getUri () + { + return this->uri_.get (); + } + + void EntryType:: + setUri (const UriType& x) + { + this->uri_.set (x); + } + + void EntryType:: + setUri (::std::unique_ptr< UriType > x) + { + this->uri_.set (std::move (x)); + } + + ::std::unique_ptr< EntryType::UriType > EntryType:: + setDetachUri () + { + return this->uri_.detach (); + } + + const EntryType::AnyAttributeSet& EntryType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + EntryType::AnyAttributeSet& EntryType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void EntryType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& EntryType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& EntryType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // EntryRefType + // + + const EntryRefType::DisplayNameOptional& EntryRefType:: + getDisplayName () const + { + return this->display_name_; + } + + EntryRefType::DisplayNameOptional& EntryRefType:: + getDisplayName () + { + return this->display_name_; + } + + void EntryRefType:: + setDisplayName (const DisplayNameType& x) + { + this->display_name_.set (x); + } + + void EntryRefType:: + setDisplayName (const DisplayNameOptional& x) + { + this->display_name_ = x; + } + + void EntryRefType:: + setDisplayName (::std::unique_ptr< DisplayNameType > x) + { + this->display_name_.set (std::move (x)); + } + + const EntryRefType::AnySequence& EntryRefType:: + getAny () const + { + return this->any_; + } + + EntryRefType::AnySequence& EntryRefType:: + getAny () + { + return this->any_; + } + + void EntryRefType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const EntryRefType::RefType& EntryRefType:: + getRef () const + { + return this->ref_.get (); + } + + EntryRefType::RefType& EntryRefType:: + getRef () + { + return this->ref_.get (); + } + + void EntryRefType:: + setRef (const RefType& x) + { + this->ref_.set (x); + } + + void EntryRefType:: + setRef (::std::unique_ptr< RefType > x) + { + this->ref_.set (std::move (x)); + } + + ::std::unique_ptr< EntryRefType::RefType > EntryRefType:: + setDetachRef () + { + return this->ref_.detach (); + } + + const EntryRefType::AnyAttributeSet& EntryRefType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + EntryRefType::AnyAttributeSet& EntryRefType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void EntryRefType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& EntryRefType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& EntryRefType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // ExternalType + // + + const ExternalType::DisplayNameOptional& ExternalType:: + getDisplayName () const + { + return this->display_name_; + } + + ExternalType::DisplayNameOptional& ExternalType:: + getDisplayName () + { + return this->display_name_; + } + + void ExternalType:: + setDisplayName (const DisplayNameType& x) + { + this->display_name_.set (x); + } + + void ExternalType:: + setDisplayName (const DisplayNameOptional& x) + { + this->display_name_ = x; + } + + void ExternalType:: + setDisplayName (::std::unique_ptr< DisplayNameType > x) + { + this->display_name_.set (std::move (x)); + } + + const ExternalType::AnySequence& ExternalType:: + getAny () const + { + return this->any_; + } + + ExternalType::AnySequence& ExternalType:: + getAny () + { + return this->any_; + } + + void ExternalType:: + setAny (const AnySequence& s) + { + this->any_ = s; + } + + const ExternalType::AnchorOptional& ExternalType:: + getAnchor () const + { + return this->anchor_; + } + + ExternalType::AnchorOptional& ExternalType:: + getAnchor () + { + return this->anchor_; + } + + void ExternalType:: + setAnchor (const AnchorType& x) + { + this->anchor_.set (x); + } + + void ExternalType:: + setAnchor (const AnchorOptional& x) + { + this->anchor_ = x; + } + + void ExternalType:: + setAnchor (::std::unique_ptr< AnchorType > x) + { + this->anchor_.set (std::move (x)); + } + + const ExternalType::AnyAttributeSet& ExternalType:: + getAnyAttribute () const + { + return this->any_attribute_; + } + + ExternalType::AnyAttributeSet& ExternalType:: + getAnyAttribute () + { + return this->any_attribute_; + } + + void ExternalType:: + setAnyAttribute (const AnyAttributeSet& s) + { + this->any_attribute_ = s; + } + + const ::xercesc::DOMDocument& ExternalType:: + getDomDocument () const + { + return *this->dom_document_; + } + + ::xercesc::DOMDocument& ExternalType:: + getDomDocument () + { + return *this->dom_document_; + } + + + // DisplayNameType + // + + const DisplayNameType::LangOptional& DisplayNameType:: + getLang () const + { + return this->lang_; + } + + DisplayNameType::LangOptional& DisplayNameType:: + getLang () + { + return this->lang_; + } + + void DisplayNameType:: + setLang (const LangType& x) + { + this->lang_.set (x); + } + + void DisplayNameType:: + setLang (const LangOptional& x) + { + this->lang_ = x; + } + + void DisplayNameType:: + setLang (::std::unique_ptr< LangType > x) + { + this->lang_.set (std::move (x)); + } + + + // List + // + + + // DisplayName + // + + + // ResourceLists + // + + const ResourceLists::ListSequence& ResourceLists:: + getList () const + { + return this->list_; + } + + ResourceLists::ListSequence& ResourceLists:: + getList () + { + return this->list_; + } + + void ResourceLists:: + setList (const ListSequence& s) + { + this->list_ = s; + } + } } } @@ -636,1041 +640,1053 @@ namespace resource_lists #include -namespace resource_lists +namespace LinphonePrivate { - // ListType - // - - ListType:: - ListType () - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_name_ (this), - list_ (this), - external_ (this), - entry_ (this), - entry_ref_ (this), - any_ (this->getDomDocument ()), - name_ (this), - any_attribute_ (this->getDomDocument ()) + namespace Xsd { - } - - ListType:: - ListType (const ListType& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_name_ (x.display_name_, f, this), - list_ (x.list_, f, this), - external_ (x.external_, f, this), - entry_ (x.entry_, f, this), - entry_ref_ (x.entry_ref_, f, this), - any_ (x.any_, this->getDomDocument ()), - name_ (x.name_, f, this), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - ListType:: - ListType (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_name_ (this), - list_ (this), - external_ (this), - entry_ (this), - entry_ref_ (this), - any_ (this->getDomDocument ()), - name_ (this), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) + namespace ResourceLists { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void ListType:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // display-name + // ListType // - if (n.name () == "display-name" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") - { - ::std::unique_ptr< Display_nameType > r ( - Display_nameTraits::create (i, f, this)); - if (!this->display_name_) + ListType:: + ListType () + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (this), + list_ (this), + external_ (this), + entry_ (this), + entry_ref_ (this), + any_ (this->getDomDocument ()), + name_ (this), + any_attribute_ (this->getDomDocument ()) + { + } + + ListType:: + ListType (const ListType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (x.display_name_, f, this), + list_ (x.list_, f, this), + external_ (x.external_, f, this), + entry_ (x.entry_, f, this), + entry_ref_ (x.entry_ref_, f, this), + any_ (x.any_, this->getDomDocument ()), + name_ (x.name_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + ListType:: + ListType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (this), + list_ (this), + external_ (this), + entry_ (this), + entry_ref_ (this), + any_ (this->getDomDocument ()), + name_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) { - this->display_name_.set (::std::move (r)); - continue; + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); } } - // list - // - if (n.name () == "list" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + void ListType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) { - ::std::unique_ptr< ListType1 > r ( - ListTraits::create (i, f, this)); - - this->list_.push_back (::std::move (r)); - continue; - } - - // external - // - if (n.name () == "external" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") - { - ::std::unique_ptr< ExternalType > r ( - ExternalTraits::create (i, f, this)); - - this->external_.push_back (::std::move (r)); - continue; - } - - // entry - // - if (n.name () == "entry" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") - { - ::std::unique_ptr< EntryType > r ( - EntryTraits::create (i, f, this)); - - this->entry_.push_back (::std::move (r)); - continue; - } - - // entry-ref - // - if (n.name () == "entry-ref" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") - { - ::std::unique_ptr< Entry_refType > r ( - Entry_refTraits::create (i, f, this)); - - this->entry_ref_.push_back (::std::move (r)); - continue; - } - - // any - // - if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists")) - { - ::xercesc::DOMElement* r ( - static_cast< ::xercesc::DOMElement* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMElement* > (&i), true))); - this->any_.push_back (r); - continue; - } - - break; - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - if (n.name () == "name" && n.namespace_ ().empty ()) - { - this->name_.set (NameTraits::create (i, f, this)); - continue; - } - - // any_attribute - // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) - { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; - } - } - } - - ListType* ListType:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class ListType (*this, f, c); - } - - ListType& ListType:: - operator= (const ListType& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->display_name_ = x.display_name_; - this->list_ = x.list_; - this->external_ = x.external_; - this->entry_ = x.entry_; - this->entry_ref_ = x.entry_ref_; - this->any_ = x.any_; - this->name_ = x.name_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - ListType:: - ~ListType () - { - } - - // EntryType - // - - EntryType:: - EntryType (const UriType& uri) - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_name_ (this), - any_ (this->getDomDocument ()), - uri_ (uri, this), - any_attribute_ (this->getDomDocument ()) - { - } - - EntryType:: - EntryType (const EntryType& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_name_ (x.display_name_, f, this), - any_ (x.any_, this->getDomDocument ()), - uri_ (x.uri_, f, this), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - EntryType:: - EntryType (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_name_ (this), - any_ (this->getDomDocument ()), - uri_ (this), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void EntryType:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // display-name - // - if (n.name () == "display-name" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") - { - ::std::unique_ptr< Display_nameType > r ( - Display_nameTraits::create (i, f, this)); - - if (!this->display_name_) + for (; p.more_content (); p.next_content (false)) { - this->display_name_.set (::std::move (r)); - continue; + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-name + // + if (n.name () == "display-name" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< DisplayNameType > r ( + DisplayNameTraits::create (i, f, this)); + + if (!this->display_name_) + { + this->display_name_.set (::std::move (r)); + continue; + } + } + + // list + // + if (n.name () == "list" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< ListType1 > r ( + ListTraits::create (i, f, this)); + + this->list_.push_back (::std::move (r)); + continue; + } + + // external + // + if (n.name () == "external" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< ExternalType > r ( + ExternalTraits::create (i, f, this)); + + this->external_.push_back (::std::move (r)); + continue; + } + + // entry + // + if (n.name () == "entry" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< EntryType > r ( + EntryTraits::create (i, f, this)); + + this->entry_.push_back (::std::move (r)); + continue; + } + + // entry-ref + // + if (n.name () == "entry-ref" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< EntryRefType > r ( + EntryRefTraits::create (i, f, this)); + + this->entry_ref_.push_back (::std::move (r)); + continue; + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "name" && n.namespace_ ().empty ()) + { + this->name_.set (NameTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } } } - // any - // - if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists")) + ListType* ListType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const { - ::xercesc::DOMElement* r ( - static_cast< ::xercesc::DOMElement* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMElement* > (&i), true))); - this->any_.push_back (r); - continue; + return new class ListType (*this, f, c); } - break; - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - if (n.name () == "uri" && n.namespace_ ().empty ()) + ListType& ListType:: + operator= (const ListType& x) { - this->uri_.set (UriTraits::create (i, f, this)); - continue; - } - - // any_attribute - // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) - { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; - } - } - - if (!uri_.present ()) - { - throw ::xsd::cxx::tree::expected_attribute< char > ( - "uri", - ""); - } - } - - EntryType* EntryType:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class EntryType (*this, f, c); - } - - EntryType& EntryType:: - operator= (const EntryType& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->display_name_ = x.display_name_; - this->any_ = x.any_; - this->uri_ = x.uri_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - EntryType:: - ~EntryType () - { - } - - // Entry_refType - // - - Entry_refType:: - Entry_refType (const RefType& ref) - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_name_ (this), - any_ (this->getDomDocument ()), - ref_ (ref, this), - any_attribute_ (this->getDomDocument ()) - { - } - - Entry_refType:: - Entry_refType (const Entry_refType& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_name_ (x.display_name_, f, this), - any_ (x.any_, this->getDomDocument ()), - ref_ (x.ref_, f, this), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - Entry_refType:: - Entry_refType (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_name_ (this), - any_ (this->getDomDocument ()), - ref_ (this), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void Entry_refType:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // display-name - // - if (n.name () == "display-name" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") - { - ::std::unique_ptr< Display_nameType > r ( - Display_nameTraits::create (i, f, this)); - - if (!this->display_name_) + if (this != &x) { - this->display_name_.set (::std::move (r)); - continue; + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->display_name_ = x.display_name_; + this->list_ = x.list_; + this->external_ = x.external_; + this->entry_ = x.entry_; + this->entry_ref_ = x.entry_ref_; + this->any_ = x.any_; + this->name_ = x.name_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + ListType:: + ~ListType () + { + } + + // EntryType + // + + EntryType:: + EntryType (const UriType& uri) + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (this), + any_ (this->getDomDocument ()), + uri_ (uri, this), + any_attribute_ (this->getDomDocument ()) + { + } + + EntryType:: + EntryType (const EntryType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (x.display_name_, f, this), + any_ (x.any_, this->getDomDocument ()), + uri_ (x.uri_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) + { + } + + EntryType:: + EntryType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (this), + any_ (this->getDomDocument ()), + uri_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); } } - // any - // - if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists")) + void EntryType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) { - ::xercesc::DOMElement* r ( - static_cast< ::xercesc::DOMElement* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMElement* > (&i), true))); - this->any_.push_back (r); - continue; - } - - break; - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - if (n.name () == "ref" && n.namespace_ ().empty ()) - { - this->ref_.set (RefTraits::create (i, f, this)); - continue; - } - - // any_attribute - // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) - { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; - } - } - - if (!ref_.present ()) - { - throw ::xsd::cxx::tree::expected_attribute< char > ( - "ref", - ""); - } - } - - Entry_refType* Entry_refType:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Entry_refType (*this, f, c); - } - - Entry_refType& Entry_refType:: - operator= (const Entry_refType& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->display_name_ = x.display_name_; - this->any_ = x.any_; - this->ref_ = x.ref_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - Entry_refType:: - ~Entry_refType () - { - } - - // ExternalType - // - - ExternalType:: - ExternalType () - : ::xml_schema::Type (), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_name_ (this), - any_ (this->getDomDocument ()), - anchor_ (this), - any_attribute_ (this->getDomDocument ()) - { - } - - ExternalType:: - ExternalType (const ExternalType& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_name_ (x.display_name_, f, this), - any_ (x.any_, this->getDomDocument ()), - anchor_ (x.anchor_, f, this), - any_attribute_ (x.any_attribute_, this->getDomDocument ()) - { - } - - ExternalType:: - ExternalType (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), - display_name_ (this), - any_ (this->getDomDocument ()), - anchor_ (this), - any_attribute_ (this->getDomDocument ()) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); - this->parse (p, f); - } - } - - void ExternalType:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // display-name - // - if (n.name () == "display-name" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") - { - ::std::unique_ptr< Display_nameType > r ( - Display_nameTraits::create (i, f, this)); - - if (!this->display_name_) + for (; p.more_content (); p.next_content (false)) { - this->display_name_.set (::std::move (r)); - continue; + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-name + // + if (n.name () == "display-name" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< DisplayNameType > r ( + DisplayNameTraits::create (i, f, this)); + + if (!this->display_name_) + { + this->display_name_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "uri" && n.namespace_ ().empty ()) + { + this->uri_.set (UriTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + + if (!uri_.present ()) + { + throw ::xsd::cxx::tree::expected_attribute< char > ( + "uri", + ""); } } - // any + EntryType* EntryType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class EntryType (*this, f, c); + } + + EntryType& EntryType:: + operator= (const EntryType& x) + { + if (this != &x) + { + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->display_name_ = x.display_name_; + this->any_ = x.any_; + this->uri_ = x.uri_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + EntryType:: + ~EntryType () + { + } + + // EntryRefType // - if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists")) + + EntryRefType:: + EntryRefType (const RefType& ref) + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (this), + any_ (this->getDomDocument ()), + ref_ (ref, this), + any_attribute_ (this->getDomDocument ()) { - ::xercesc::DOMElement* r ( - static_cast< ::xercesc::DOMElement* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMElement* > (&i), true))); - this->any_.push_back (r); - continue; } - break; - } - - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - if (n.name () == "anchor" && n.namespace_ ().empty ()) + EntryRefType:: + EntryRefType (const EntryRefType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (x.display_name_, f, this), + any_ (x.any_, this->getDomDocument ()), + ref_ (x.ref_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) { - this->anchor_.set (AnchorTraits::create (i, f, this)); - continue; } - // any_attribute + EntryRefType:: + EntryRefType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (this), + any_ (this->getDomDocument ()), + ref_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } + + void EntryRefType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // display-name + // + if (n.name () == "display-name" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< DisplayNameType > r ( + DisplayNameTraits::create (i, f, this)); + + if (!this->display_name_) + { + this->display_name_.set (::std::move (r)); + continue; + } + } + + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } + + break; + } + + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "ref" && n.namespace_ ().empty ()) + { + this->ref_.set (RefTraits::create (i, f, this)); + continue; + } + + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + + if (!ref_.present ()) + { + throw ::xsd::cxx::tree::expected_attribute< char > ( + "ref", + ""); + } + } + + EntryRefType* EntryRefType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class EntryRefType (*this, f, c); + } + + EntryRefType& EntryRefType:: + operator= (const EntryRefType& x) + { + if (this != &x) + { + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->display_name_ = x.display_name_; + this->any_ = x.any_; + this->ref_ = x.ref_; + this->any_attribute_ = x.any_attribute_; + } + + return *this; + } + + EntryRefType:: + ~EntryRefType () + { + } + + // ExternalType // - if ((!n.namespace_ ().empty () && - n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists" && - n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && - n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + + ExternalType:: + ExternalType () + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (this), + any_ (this->getDomDocument ()), + anchor_ (this), + any_attribute_ (this->getDomDocument ()) { - ::xercesc::DOMAttr* r ( - static_cast< ::xercesc::DOMAttr* > ( - this->getDomDocument ().importNode ( - const_cast< ::xercesc::DOMAttr* > (&i), true))); - this->any_attribute_ .insert (r); - continue; } - } - } - ExternalType* ExternalType:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class ExternalType (*this, f, c); - } - - ExternalType& ExternalType:: - operator= (const ExternalType& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->display_name_ = x.display_name_; - this->any_ = x.any_; - this->anchor_ = x.anchor_; - this->any_attribute_ = x.any_attribute_; - } - - return *this; - } - - ExternalType:: - ~ExternalType () - { - } - - // Display_nameType - // - - Display_nameType:: - Display_nameType () - : ::xml_schema::String (), - lang_ (this) - { - } - - Display_nameType:: - Display_nameType (const char* _xsd_String_base) - : ::xml_schema::String (_xsd_String_base), - lang_ (this) - { - } - - Display_nameType:: - Display_nameType (const ::std::string& _xsd_String_base) - : ::xml_schema::String (_xsd_String_base), - lang_ (this) - { - } - - Display_nameType:: - Display_nameType (const ::xml_schema::String& _xsd_String_base) - : ::xml_schema::String (_xsd_String_base), - lang_ (this) - { - } - - Display_nameType:: - Display_nameType (const Display_nameType& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (x, f, c), - lang_ (x.lang_, f, this) - { - } - - Display_nameType:: - Display_nameType (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (e, f | ::xml_schema::Flags::base, c), - lang_ (this) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, false, false, true); - this->parse (p, f); - } - } - - void Display_nameType:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - while (p.more_attributes ()) - { - const ::xercesc::DOMAttr& i (p.next_attribute ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - if (n.name () == "lang" && n.namespace_ () == "http://www.w3.org/XML/1998/namespace") + ExternalType:: + ExternalType (const ExternalType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (x.display_name_, f, this), + any_ (x.any_, this->getDomDocument ()), + anchor_ (x.anchor_, f, this), + any_attribute_ (x.any_attribute_, this->getDomDocument ()) { - this->lang_.set (LangTraits::create (i, f, this)); - continue; } - } - } - Display_nameType* Display_nameType:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Display_nameType (*this, f, c); - } + ExternalType:: + ExternalType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + dom_document_ (::xsd::cxx::xml::dom::create_document< char > ()), + display_name_ (this), + any_ (this->getDomDocument ()), + anchor_ (this), + any_attribute_ (this->getDomDocument ()) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, true); + this->parse (p, f); + } + } - Display_nameType& Display_nameType:: - operator= (const Display_nameType& x) - { - if (this != &x) - { - static_cast< ::xml_schema::String& > (*this) = x; - this->lang_ = x.lang_; - } + void ExternalType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); - return *this; - } + // display-name + // + if (n.name () == "display-name" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< DisplayNameType > r ( + DisplayNameTraits::create (i, f, this)); - Display_nameType:: - ~Display_nameType () - { - } + if (!this->display_name_) + { + this->display_name_.set (::std::move (r)); + continue; + } + } - // List - // + // any + // + if ((!n.namespace_ ().empty () && n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists")) + { + ::xercesc::DOMElement* r ( + static_cast< ::xercesc::DOMElement* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMElement* > (&i), true))); + this->any_.push_back (r); + continue; + } - List:: - List () - : ::resource_lists::ListType () - { - } + break; + } - List:: - List (const List& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::resource_lists::ListType (x, f, c) - { - } + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); - List:: - List (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::resource_lists::ListType (e, f, c) - { - } + if (n.name () == "anchor" && n.namespace_ ().empty ()) + { + this->anchor_.set (AnchorTraits::create (i, f, this)); + continue; + } - List* List:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class List (*this, f, c); - } + // any_attribute + // + if ((!n.namespace_ ().empty () && + n.namespace_ () != "urn:ietf:params:xml:ns:resource-lists" && + n.namespace_ () != ::xsd::cxx::xml::bits::xmlns_namespace< char > () && + n.namespace_ () != ::xsd::cxx::xml::bits::xsi_namespace< char > ())) + { + ::xercesc::DOMAttr* r ( + static_cast< ::xercesc::DOMAttr* > ( + this->getDomDocument ().importNode ( + const_cast< ::xercesc::DOMAttr* > (&i), true))); + this->any_attribute_ .insert (r); + continue; + } + } + } - List:: - ~List () - { - } + ExternalType* ExternalType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class ExternalType (*this, f, c); + } - // Display_name - // + ExternalType& ExternalType:: + operator= (const ExternalType& x) + { + if (this != &x) + { + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->display_name_ = x.display_name_; + this->any_ = x.any_; + this->anchor_ = x.anchor_; + this->any_attribute_ = x.any_attribute_; + } - Display_name:: - Display_name () - : ::resource_lists::Display_nameType () - { - } + return *this; + } - Display_name:: - Display_name (const char* _xsd_String_base) - : ::resource_lists::Display_nameType (_xsd_String_base) - { - } + ExternalType:: + ~ExternalType () + { + } - Display_name:: - Display_name (const ::std::string& _xsd_String_base) - : ::resource_lists::Display_nameType (_xsd_String_base) - { - } - - Display_name:: - Display_name (const ::xml_schema::String& _xsd_String_base) - : ::resource_lists::Display_nameType (_xsd_String_base) - { - } - - Display_name:: - Display_name (const Display_name& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::resource_lists::Display_nameType (x, f, c) - { - } - - Display_name:: - Display_name (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::resource_lists::Display_nameType (e, f, c) - { - } - - Display_name* Display_name:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Display_name (*this, f, c); - } - - Display_name:: - ~Display_name () - { - } - - // Resource_lists - // - - Resource_lists:: - Resource_lists () - : ::xml_schema::Type (), - list_ (this) - { - } - - Resource_lists:: - Resource_lists (const Resource_lists& x, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (x, f, c), - list_ (x.list_, f, this) - { - } - - Resource_lists:: - Resource_lists (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Type (e, f | ::xml_schema::Flags::base, c), - list_ (this) - { - if ((f & ::xml_schema::Flags::base) == 0) - { - ::xsd::cxx::xml::dom::parser< char > p (e, true, false, false); - this->parse (p, f); - } - } - - void Resource_lists:: - parse (::xsd::cxx::xml::dom::parser< char >& p, - ::xml_schema::Flags f) - { - for (; p.more_content (); p.next_content (false)) - { - const ::xercesc::DOMElement& i (p.cur_element ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (i)); - - // list + // DisplayNameType // - if (n.name () == "list" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") - { - ::std::unique_ptr< ListType > r ( - ListTraits::create (i, f, this)); - this->list_.push_back (::std::move (r)); - continue; + DisplayNameType:: + DisplayNameType () + : ::LinphonePrivate::Xsd::XmlSchema::String (), + lang_ (this) + { } - break; + DisplayNameType:: + DisplayNameType (const char* _xsd_String_base) + : ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_String_base), + lang_ (this) + { + } + + DisplayNameType:: + DisplayNameType (const ::std::string& _xsd_String_base) + : ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_String_base), + lang_ (this) + { + } + + DisplayNameType:: + DisplayNameType (const ::LinphonePrivate::Xsd::XmlSchema::String& _xsd_String_base) + : ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_String_base), + lang_ (this) + { + } + + DisplayNameType:: + DisplayNameType (const DisplayNameType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (x, f, c), + lang_ (x.lang_, f, this) + { + } + + DisplayNameType:: + DisplayNameType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + lang_ (this) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, false, false, true); + this->parse (p, f); + } + } + + void DisplayNameType:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + while (p.more_attributes ()) + { + const ::xercesc::DOMAttr& i (p.next_attribute ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + if (n.name () == "lang" && n.namespace_ () == "http://www.w3.org/XML/1998/namespace") + { + this->lang_.set (LangTraits::create (i, f, this)); + continue; + } + } + } + + DisplayNameType* DisplayNameType:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class DisplayNameType (*this, f, c); + } + + DisplayNameType& DisplayNameType:: + operator= (const DisplayNameType& x) + { + if (this != &x) + { + static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = x; + this->lang_ = x.lang_; + } + + return *this; + } + + DisplayNameType:: + ~DisplayNameType () + { + } + + // List + // + + List:: + List () + : ::LinphonePrivate::Xsd::ResourceLists::ListType () + { + } + + List:: + List (const List& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::ResourceLists::ListType (x, f, c) + { + } + + List:: + List (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::ResourceLists::ListType (e, f, c) + { + } + + List* List:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class List (*this, f, c); + } + + List:: + ~List () + { + } + + // DisplayName + // + + DisplayName:: + DisplayName () + : ::LinphonePrivate::Xsd::ResourceLists::DisplayNameType () + { + } + + DisplayName:: + DisplayName (const char* _xsd_String_base) + : ::LinphonePrivate::Xsd::ResourceLists::DisplayNameType (_xsd_String_base) + { + } + + DisplayName:: + DisplayName (const ::std::string& _xsd_String_base) + : ::LinphonePrivate::Xsd::ResourceLists::DisplayNameType (_xsd_String_base) + { + } + + DisplayName:: + DisplayName (const ::LinphonePrivate::Xsd::XmlSchema::String& _xsd_String_base) + : ::LinphonePrivate::Xsd::ResourceLists::DisplayNameType (_xsd_String_base) + { + } + + DisplayName:: + DisplayName (const DisplayName& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::ResourceLists::DisplayNameType (x, f, c) + { + } + + DisplayName:: + DisplayName (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::ResourceLists::DisplayNameType (e, f, c) + { + } + + DisplayName* DisplayName:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class DisplayName (*this, f, c); + } + + DisplayName:: + ~DisplayName () + { + } + + // ResourceLists + // + + ResourceLists:: + ResourceLists () + : ::LinphonePrivate::Xsd::XmlSchema::Type (), + list_ (this) + { + } + + ResourceLists:: + ResourceLists (const ResourceLists& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (x, f, c), + list_ (x.list_, f, this) + { + } + + ResourceLists:: + ResourceLists (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Type (e, f | ::LinphonePrivate::Xsd::XmlSchema::Flags::base, c), + list_ (this) + { + if ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, false); + this->parse (p, f); + } + } + + void ResourceLists:: + parse (::xsd::cxx::xml::dom::parser< char >& p, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // list + // + if (n.name () == "list" && n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< ListType > r ( + ListTraits::create (i, f, this)); + + this->list_.push_back (::std::move (r)); + continue; + } + + break; + } + } + + ResourceLists* ResourceLists:: + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const + { + return new class ResourceLists (*this, f, c); + } + + ResourceLists& ResourceLists:: + operator= (const ResourceLists& x) + { + if (this != &x) + { + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Type& > (*this) = x; + this->list_ = x.list_; + } + + return *this; + } + + ResourceLists:: + ~ResourceLists () + { + } } } - - Resource_lists* Resource_lists:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const - { - return new class Resource_lists (*this, f, c); - } - - Resource_lists& Resource_lists:: - operator= (const Resource_lists& x) - { - if (this != &x) - { - static_cast< ::xml_schema::Type& > (*this) = x; - this->list_ = x.list_; - } - - return *this; - } - - Resource_lists:: - ~Resource_lists () - { - } } #include -namespace resource_lists +namespace LinphonePrivate { - ::std::ostream& - operator<< (::std::ostream& o, const ListType& i) + namespace Xsd { - if (i.getDisplay_name ()) + namespace ResourceLists { - o << ::std::endl << "display-name: " << *i.getDisplay_name (); + ::std::ostream& + operator<< (::std::ostream& o, const ListType& i) + { + if (i.getDisplayName ()) + { + o << ::std::endl << "display-name: " << *i.getDisplayName (); + } + + for (ListType::ListConstIterator + b (i.getList ().begin ()), e (i.getList ().end ()); + b != e; ++b) + { + o << ::std::endl << "list: " << *b; + } + + for (ListType::ExternalConstIterator + b (i.getExternal ().begin ()), e (i.getExternal ().end ()); + b != e; ++b) + { + o << ::std::endl << "external: " << *b; + } + + for (ListType::EntryConstIterator + b (i.getEntry ().begin ()), e (i.getEntry ().end ()); + b != e; ++b) + { + o << ::std::endl << "entry: " << *b; + } + + for (ListType::EntryRefConstIterator + b (i.getEntryRef ().begin ()), e (i.getEntryRef ().end ()); + b != e; ++b) + { + o << ::std::endl << "entry-ref: " << *b; + } + + if (i.getName ()) + { + o << ::std::endl << "name: " << *i.getName (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const EntryType& i) + { + if (i.getDisplayName ()) + { + o << ::std::endl << "display-name: " << *i.getDisplayName (); + } + + o << ::std::endl << "uri: " << i.getUri (); + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const EntryRefType& i) + { + if (i.getDisplayName ()) + { + o << ::std::endl << "display-name: " << *i.getDisplayName (); + } + + o << ::std::endl << "ref: " << i.getRef (); + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const ExternalType& i) + { + if (i.getDisplayName ()) + { + o << ::std::endl << "display-name: " << *i.getDisplayName (); + } + + if (i.getAnchor ()) + { + o << ::std::endl << "anchor: " << *i.getAnchor (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const DisplayNameType& i) + { + o << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); + + if (i.getLang ()) + { + o << ::std::endl << "lang: " << *i.getLang (); + } + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const List& i) + { + o << static_cast< const ::LinphonePrivate::Xsd::ResourceLists::ListType& > (i); + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const DisplayName& i) + { + o << static_cast< const ::LinphonePrivate::Xsd::ResourceLists::DisplayNameType& > (i); + + return o; + } + + ::std::ostream& + operator<< (::std::ostream& o, const ResourceLists& i) + { + for (ResourceLists::ListConstIterator + b (i.getList ().begin ()), e (i.getList ().end ()); + b != e; ++b) + { + o << ::std::endl << "list: " << *b; + } + + return o; + } } - - for (ListType::ListConstIterator - b (i.getList ().begin ()), e (i.getList ().end ()); - b != e; ++b) - { - o << ::std::endl << "list: " << *b; - } - - for (ListType::ExternalConstIterator - b (i.getExternal ().begin ()), e (i.getExternal ().end ()); - b != e; ++b) - { - o << ::std::endl << "external: " << *b; - } - - for (ListType::EntryConstIterator - b (i.getEntry ().begin ()), e (i.getEntry ().end ()); - b != e; ++b) - { - o << ::std::endl << "entry: " << *b; - } - - for (ListType::Entry_refConstIterator - b (i.getEntry_ref ().begin ()), e (i.getEntry_ref ().end ()); - b != e; ++b) - { - o << ::std::endl << "entry-ref: " << *b; - } - - if (i.getName ()) - { - o << ::std::endl << "name: " << *i.getName (); - } - - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const EntryType& i) - { - if (i.getDisplay_name ()) - { - o << ::std::endl << "display-name: " << *i.getDisplay_name (); - } - - o << ::std::endl << "uri: " << i.getUri (); - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const Entry_refType& i) - { - if (i.getDisplay_name ()) - { - o << ::std::endl << "display-name: " << *i.getDisplay_name (); - } - - o << ::std::endl << "ref: " << i.getRef (); - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const ExternalType& i) - { - if (i.getDisplay_name ()) - { - o << ::std::endl << "display-name: " << *i.getDisplay_name (); - } - - if (i.getAnchor ()) - { - o << ::std::endl << "anchor: " << *i.getAnchor (); - } - - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const Display_nameType& i) - { - o << static_cast< const ::xml_schema::String& > (i); - - if (i.getLang ()) - { - o << ::std::endl << "lang: " << *i.getLang (); - } - - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const List& i) - { - o << static_cast< const ::resource_lists::ListType& > (i); - - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const Display_name& i) - { - o << static_cast< const ::resource_lists::Display_nameType& > (i); - - return o; - } - - ::std::ostream& - operator<< (::std::ostream& o, const Resource_lists& i) - { - for (Resource_lists::ListConstIterator - b (i.getList ().begin ()), e (i.getList ().end ()); - b != e; ++b) - { - o << ::std::endl << "list: " << *b; - } - - return o; } } @@ -1678,272 +1694,278 @@ namespace resource_lists #include #include -namespace resource_lists +namespace LinphonePrivate { - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (const ::std::string& u, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) + namespace Xsd { - ::xsd::cxx::xml::auto_initializer i ( - (f & ::xml_schema::Flags::dont_initialize) == 0, - (f & ::xml_schema::Flags::keep_dom) == 0); - - ::xsd::cxx::tree::error_handler< char > h; - - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::xsd::cxx::xml::dom::parse< char > ( - u, h, p, f)); - - h.throw_if_failed< ::xsd::cxx::tree::parsing< char > > (); - - return ::std::unique_ptr< ::resource_lists::Resource_lists > ( - ::resource_lists::parseResource_lists ( - std::move (d), f | ::xml_schema::Flags::own_dom, p)); - } - - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (const ::std::string& u, - ::xml_schema::ErrorHandler& h, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xsd::cxx::xml::auto_initializer i ( - (f & ::xml_schema::Flags::dont_initialize) == 0, - (f & ::xml_schema::Flags::keep_dom) == 0); - - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::xsd::cxx::xml::dom::parse< char > ( - u, h, p, f)); - - if (!d.get ()) - throw ::xsd::cxx::tree::parsing< char > (); - - return ::std::unique_ptr< ::resource_lists::Resource_lists > ( - ::resource_lists::parseResource_lists ( - std::move (d), f | ::xml_schema::Flags::own_dom, p)); - } - - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (const ::std::string& u, - ::xercesc::DOMErrorHandler& h, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::xsd::cxx::xml::dom::parse< char > ( - u, h, p, f)); - - if (!d.get ()) - throw ::xsd::cxx::tree::parsing< char > (); - - return ::std::unique_ptr< ::resource_lists::Resource_lists > ( - ::resource_lists::parseResource_lists ( - std::move (d), f | ::xml_schema::Flags::own_dom, p)); - } - - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::std::istream& is, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xsd::cxx::xml::auto_initializer i ( - (f & ::xml_schema::Flags::dont_initialize) == 0, - (f & ::xml_schema::Flags::keep_dom) == 0); - - ::xsd::cxx::xml::sax::std_input_source isrc (is); - return ::resource_lists::parseResource_lists (isrc, f, p); - } - - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::std::istream& is, - ::xml_schema::ErrorHandler& h, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xsd::cxx::xml::auto_initializer i ( - (f & ::xml_schema::Flags::dont_initialize) == 0, - (f & ::xml_schema::Flags::keep_dom) == 0); - - ::xsd::cxx::xml::sax::std_input_source isrc (is); - return ::resource_lists::parseResource_lists (isrc, h, f, p); - } - - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::std::istream& is, - ::xercesc::DOMErrorHandler& h, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xsd::cxx::xml::sax::std_input_source isrc (is); - return ::resource_lists::parseResource_lists (isrc, h, f, p); - } - - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::std::istream& is, - const ::std::string& sid, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xsd::cxx::xml::auto_initializer i ( - (f & ::xml_schema::Flags::dont_initialize) == 0, - (f & ::xml_schema::Flags::keep_dom) == 0); - - ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); - return ::resource_lists::parseResource_lists (isrc, f, p); - } - - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::std::istream& is, - const ::std::string& sid, - ::xml_schema::ErrorHandler& h, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xsd::cxx::xml::auto_initializer i ( - (f & ::xml_schema::Flags::dont_initialize) == 0, - (f & ::xml_schema::Flags::keep_dom) == 0); - - ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); - return ::resource_lists::parseResource_lists (isrc, h, f, p); - } - - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::std::istream& is, - const ::std::string& sid, - ::xercesc::DOMErrorHandler& h, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); - return ::resource_lists::parseResource_lists (isrc, h, f, p); - } - - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::xercesc::InputSource& i, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xsd::cxx::tree::error_handler< char > h; - - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::xsd::cxx::xml::dom::parse< char > ( - i, h, p, f)); - - h.throw_if_failed< ::xsd::cxx::tree::parsing< char > > (); - - return ::std::unique_ptr< ::resource_lists::Resource_lists > ( - ::resource_lists::parseResource_lists ( - std::move (d), f | ::xml_schema::Flags::own_dom, p)); - } - - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::xercesc::InputSource& i, - ::xml_schema::ErrorHandler& h, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::xsd::cxx::xml::dom::parse< char > ( - i, h, p, f)); - - if (!d.get ()) - throw ::xsd::cxx::tree::parsing< char > (); - - return ::std::unique_ptr< ::resource_lists::Resource_lists > ( - ::resource_lists::parseResource_lists ( - std::move (d), f | ::xml_schema::Flags::own_dom, p)); - } - - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::xercesc::InputSource& i, - ::xercesc::DOMErrorHandler& h, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::xsd::cxx::xml::dom::parse< char > ( - i, h, p, f)); - - if (!d.get ()) - throw ::xsd::cxx::tree::parsing< char > (); - - return ::std::unique_ptr< ::resource_lists::Resource_lists > ( - ::resource_lists::parseResource_lists ( - std::move (d), f | ::xml_schema::Flags::own_dom, p)); - } - - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (const ::xercesc::DOMDocument& doc, - ::xml_schema::Flags f, - const ::xml_schema::Properties& p) - { - if (f & ::xml_schema::Flags::keep_dom) + namespace ResourceLists { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - static_cast< ::xercesc::DOMDocument* > (doc.cloneNode (true))); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (const ::std::string& u, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::dont_initialize) == 0, + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::keep_dom) == 0); - return ::std::unique_ptr< ::resource_lists::Resource_lists > ( - ::resource_lists::parseResource_lists ( - std::move (d), f | ::xml_schema::Flags::own_dom, p)); + ::xsd::cxx::tree::error_handler< char > h; + + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + u, h, p, f)); + + h.throw_if_failed< ::xsd::cxx::tree::parsing< char > > (); + + return ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > ( + ::LinphonePrivate::Xsd::ResourceLists::parseResourceLists ( + std::move (d), f | ::LinphonePrivate::Xsd::XmlSchema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (const ::std::string& u, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& h, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::dont_initialize) == 0, + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::keep_dom) == 0); + + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + u, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > ( + ::LinphonePrivate::Xsd::ResourceLists::parseResourceLists ( + std::move (d), f | ::LinphonePrivate::Xsd::XmlSchema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (const ::std::string& u, + ::xercesc::DOMErrorHandler& h, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + u, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > ( + ::LinphonePrivate::Xsd::ResourceLists::parseResourceLists ( + std::move (d), f | ::LinphonePrivate::Xsd::XmlSchema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::std::istream& is, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::dont_initialize) == 0, + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is); + return ::LinphonePrivate::Xsd::ResourceLists::parseResourceLists (isrc, f, p); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::std::istream& is, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& h, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::dont_initialize) == 0, + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is); + return ::LinphonePrivate::Xsd::ResourceLists::parseResourceLists (isrc, h, f, p); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::std::istream& is, + ::xercesc::DOMErrorHandler& h, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::xsd::cxx::xml::sax::std_input_source isrc (is); + return ::LinphonePrivate::Xsd::ResourceLists::parseResourceLists (isrc, h, f, p); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::std::istream& is, + const ::std::string& sid, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::dont_initialize) == 0, + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); + return ::LinphonePrivate::Xsd::ResourceLists::parseResourceLists (isrc, f, p); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::std::istream& is, + const ::std::string& sid, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& h, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::dont_initialize) == 0, + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); + return ::LinphonePrivate::Xsd::ResourceLists::parseResourceLists (isrc, h, f, p); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::std::istream& is, + const ::std::string& sid, + ::xercesc::DOMErrorHandler& h, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); + return ::LinphonePrivate::Xsd::ResourceLists::parseResourceLists (isrc, h, f, p); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::xercesc::InputSource& i, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::xsd::cxx::tree::error_handler< char > h; + + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + i, h, p, f)); + + h.throw_if_failed< ::xsd::cxx::tree::parsing< char > > (); + + return ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > ( + ::LinphonePrivate::Xsd::ResourceLists::parseResourceLists ( + std::move (d), f | ::LinphonePrivate::Xsd::XmlSchema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::xercesc::InputSource& i, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& h, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + i, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > ( + ::LinphonePrivate::Xsd::ResourceLists::parseResourceLists ( + std::move (d), f | ::LinphonePrivate::Xsd::XmlSchema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::xercesc::InputSource& i, + ::xercesc::DOMErrorHandler& h, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + i, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > ( + ::LinphonePrivate::Xsd::ResourceLists::parseResourceLists ( + std::move (d), f | ::LinphonePrivate::Xsd::XmlSchema::Flags::own_dom, p)); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (const ::xercesc::DOMDocument& doc, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p) + { + if (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::keep_dom) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + static_cast< ::xercesc::DOMDocument* > (doc.cloneNode (true))); + + return ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > ( + ::LinphonePrivate::Xsd::ResourceLists::parseResourceLists ( + std::move (d), f | ::LinphonePrivate::Xsd::XmlSchema::Flags::own_dom, p)); + } + + const ::xercesc::DOMElement& e (*doc.getDocumentElement ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (e)); + + if (n.name () == "resource-lists" && + n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > r ( + ::xsd::cxx::tree::traits< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists, char >::create ( + e, f, 0)); + return r; + } + + throw ::xsd::cxx::tree::unexpected_element < char > ( + n.name (), + n.namespace_ (), + "resource-lists", + "urn:ietf:params:xml:ns:resource-lists"); + } + + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d, + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + const ::LinphonePrivate::Xsd::XmlSchema::Properties&) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > c ( + ((f & ::LinphonePrivate::Xsd::XmlSchema::Flags::keep_dom) && + !(f & ::LinphonePrivate::Xsd::XmlSchema::Flags::own_dom)) + ? static_cast< ::xercesc::DOMDocument* > (d->cloneNode (true)) + : 0); + + ::xercesc::DOMDocument& doc (c.get () ? *c : *d); + const ::xercesc::DOMElement& e (*doc.getDocumentElement ()); + + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (e)); + + if (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::keep_dom) + doc.setUserData (::LinphonePrivate::Xsd::XmlSchema::dom::treeNodeKey, + (c.get () ? &c : &d), + 0); + + if (n.name () == "resource-lists" && + n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > r ( + ::xsd::cxx::tree::traits< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists, char >::create ( + e, f, 0)); + return r; + } + + throw ::xsd::cxx::tree::unexpected_element < char > ( + n.name (), + n.namespace_ (), + "resource-lists", + "urn:ietf:params:xml:ns:resource-lists"); + } } - - const ::xercesc::DOMElement& e (*doc.getDocumentElement ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (e)); - - if (n.name () == "resource-lists" && - n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") - { - ::std::unique_ptr< ::resource_lists::Resource_lists > r ( - ::xsd::cxx::tree::traits< ::resource_lists::Resource_lists, char >::create ( - e, f, 0)); - return r; - } - - throw ::xsd::cxx::tree::unexpected_element < char > ( - n.name (), - n.namespace_ (), - "resource-lists", - "urn:ietf:params:xml:ns:resource-lists"); - } - - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d, - ::xml_schema::Flags f, - const ::xml_schema::Properties&) - { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > c ( - ((f & ::xml_schema::Flags::keep_dom) && - !(f & ::xml_schema::Flags::own_dom)) - ? static_cast< ::xercesc::DOMDocument* > (d->cloneNode (true)) - : 0); - - ::xercesc::DOMDocument& doc (c.get () ? *c : *d); - const ::xercesc::DOMElement& e (*doc.getDocumentElement ()); - - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (e)); - - if (f & ::xml_schema::Flags::keep_dom) - doc.setUserData (::xml_schema::dom::treeNodeKey, - (c.get () ? &c : &d), - 0); - - if (n.name () == "resource-lists" && - n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") - { - ::std::unique_ptr< ::resource_lists::Resource_lists > r ( - ::xsd::cxx::tree::traits< ::resource_lists::Resource_lists, char >::create ( - e, f, 0)); - return r; - } - - throw ::xsd::cxx::tree::unexpected_element < char > ( - n.name (), - n.namespace_ (), - "resource-lists", - "urn:ietf:params:xml:ns:resource-lists"); } } @@ -1951,499 +1973,505 @@ namespace resource_lists #include #include -namespace resource_lists +namespace LinphonePrivate { - void - operator<< (::xercesc::DOMElement& e, const ListType& i) + namespace Xsd { - e << static_cast< const ::xml_schema::Type& > (i); - - // any_attribute - // - for (ListType::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) + namespace ResourceLists { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + void + operator<< (::xercesc::DOMElement& e, const ListType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } + // any_attribute + // + for (ListType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - // display-name - // - if (i.getDisplay_name ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "display-name", - "urn:ietf:params:xml:ns:resource-lists", - e)); + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } - s << *i.getDisplay_name (); - } + // display-name + // + if (i.getDisplayName ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-name", + "urn:ietf:params:xml:ns:resource-lists", + e)); - // list - // - for (ListType::ListConstIterator - b (i.getList ().begin ()), n (i.getList ().end ()); - b != n; ++b) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "list", - "urn:ietf:params:xml:ns:resource-lists", - e)); + s << *i.getDisplayName (); + } - s << *b; - } + // list + // + for (ListType::ListConstIterator + b (i.getList ().begin ()), n (i.getList ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "list", + "urn:ietf:params:xml:ns:resource-lists", + e)); - // external - // - for (ListType::ExternalConstIterator - b (i.getExternal ().begin ()), n (i.getExternal ().end ()); - b != n; ++b) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "external", - "urn:ietf:params:xml:ns:resource-lists", - e)); + s << *b; + } - s << *b; - } + // external + // + for (ListType::ExternalConstIterator + b (i.getExternal ().begin ()), n (i.getExternal ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "external", + "urn:ietf:params:xml:ns:resource-lists", + e)); - // entry - // - for (ListType::EntryConstIterator - b (i.getEntry ().begin ()), n (i.getEntry ().end ()); - b != n; ++b) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "entry", - "urn:ietf:params:xml:ns:resource-lists", - e)); + s << *b; + } - s << *b; - } + // entry + // + for (ListType::EntryConstIterator + b (i.getEntry ().begin ()), n (i.getEntry ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "entry", + "urn:ietf:params:xml:ns:resource-lists", + e)); - // entry-ref - // - for (ListType::Entry_refConstIterator - b (i.getEntry_ref ().begin ()), n (i.getEntry_ref ().end ()); - b != n; ++b) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "entry-ref", - "urn:ietf:params:xml:ns:resource-lists", - e)); + s << *b; + } - s << *b; - } + // entry-ref + // + for (ListType::EntryRefConstIterator + b (i.getEntryRef ().begin ()), n (i.getEntryRef ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "entry-ref", + "urn:ietf:params:xml:ns:resource-lists", + e)); - // any - // - for (ListType::AnyConstIterator - b (i.getAny ().begin ()), n (i.getAny ().end ()); - b != n; ++b) - { - e.appendChild ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMElement* > (&(*b)), true)); - } + s << *b; + } - // name - // - if (i.getName ()) - { - ::xercesc::DOMAttr& a ( - ::xsd::cxx::xml::dom::create_attribute ( - "name", - e)); + // any + // + for (ListType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } - a << *i.getName (); - } - } + // name + // + if (i.getName ()) + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "name", + e)); - void - operator<< (::xercesc::DOMElement& e, const EntryType& i) - { - e << static_cast< const ::xml_schema::Type& > (i); + a << *i.getName (); + } + } - // any_attribute - // - for (EntryType::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + void + operator<< (::xercesc::DOMElement& e, const EntryType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } + // any_attribute + // + for (EntryType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - // display-name - // - if (i.getDisplay_name ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "display-name", - "urn:ietf:params:xml:ns:resource-lists", - e)); + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } - s << *i.getDisplay_name (); - } + // display-name + // + if (i.getDisplayName ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-name", + "urn:ietf:params:xml:ns:resource-lists", + e)); - // any - // - for (EntryType::AnyConstIterator - b (i.getAny ().begin ()), n (i.getAny ().end ()); - b != n; ++b) - { - e.appendChild ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMElement* > (&(*b)), true)); - } + s << *i.getDisplayName (); + } - // uri - // - { - ::xercesc::DOMAttr& a ( - ::xsd::cxx::xml::dom::create_attribute ( - "uri", - e)); + // any + // + for (EntryType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } - a << i.getUri (); - } - } + // uri + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "uri", + e)); - void - operator<< (::xercesc::DOMElement& e, const Entry_refType& i) - { - e << static_cast< const ::xml_schema::Type& > (i); + a << i.getUri (); + } + } - // any_attribute - // - for (Entry_refType::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + void + operator<< (::xercesc::DOMElement& e, const EntryRefType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } + // any_attribute + // + for (EntryRefType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - // display-name - // - if (i.getDisplay_name ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "display-name", - "urn:ietf:params:xml:ns:resource-lists", - e)); + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } - s << *i.getDisplay_name (); - } + // display-name + // + if (i.getDisplayName ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-name", + "urn:ietf:params:xml:ns:resource-lists", + e)); - // any - // - for (Entry_refType::AnyConstIterator - b (i.getAny ().begin ()), n (i.getAny ().end ()); - b != n; ++b) - { - e.appendChild ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMElement* > (&(*b)), true)); - } + s << *i.getDisplayName (); + } - // ref - // - { - ::xercesc::DOMAttr& a ( - ::xsd::cxx::xml::dom::create_attribute ( - "ref", - e)); + // any + // + for (EntryRefType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } - a << i.getRef (); - } - } + // ref + // + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "ref", + e)); - void - operator<< (::xercesc::DOMElement& e, const ExternalType& i) - { - e << static_cast< const ::xml_schema::Type& > (i); + a << i.getRef (); + } + } - // any_attribute - // - for (ExternalType::AnyAttributeConstIterator - b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); - b != n; ++b) - { - ::xercesc::DOMAttr* a ( - static_cast< ::xercesc::DOMAttr* > ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); + void + operator<< (::xercesc::DOMElement& e, const ExternalType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); - if (a->getLocalName () == 0) - e.setAttributeNode (a); - else - e.setAttributeNodeNS (a); - } + // any_attribute + // + for (ExternalType::AnyAttributeConstIterator + b (i.getAnyAttribute ().begin ()), n (i.getAnyAttribute ().end ()); + b != n; ++b) + { + ::xercesc::DOMAttr* a ( + static_cast< ::xercesc::DOMAttr* > ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMAttr* > (&(*b)), true))); - // display-name - // - if (i.getDisplay_name ()) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "display-name", - "urn:ietf:params:xml:ns:resource-lists", - e)); + if (a->getLocalName () == 0) + e.setAttributeNode (a); + else + e.setAttributeNodeNS (a); + } - s << *i.getDisplay_name (); - } + // display-name + // + if (i.getDisplayName ()) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "display-name", + "urn:ietf:params:xml:ns:resource-lists", + e)); - // any - // - for (ExternalType::AnyConstIterator - b (i.getAny ().begin ()), n (i.getAny ().end ()); - b != n; ++b) - { - e.appendChild ( - e.getOwnerDocument ()->importNode ( - const_cast< ::xercesc::DOMElement* > (&(*b)), true)); - } + s << *i.getDisplayName (); + } - // anchor - // - if (i.getAnchor ()) - { - ::xercesc::DOMAttr& a ( - ::xsd::cxx::xml::dom::create_attribute ( - "anchor", - e)); + // any + // + for (ExternalType::AnyConstIterator + b (i.getAny ().begin ()), n (i.getAny ().end ()); + b != n; ++b) + { + e.appendChild ( + e.getOwnerDocument ()->importNode ( + const_cast< ::xercesc::DOMElement* > (&(*b)), true)); + } - a << *i.getAnchor (); - } - } + // anchor + // + if (i.getAnchor ()) + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "anchor", + e)); - void - serializeResource_lists (::std::ostream& o, - const ::resource_lists::Resource_lists& s, - const ::xml_schema::NamespaceInfomap& m, - const ::std::string& e, - ::xml_schema::Flags f) - { - ::xsd::cxx::xml::auto_initializer i ( - (f & ::xml_schema::Flags::dont_initialize) == 0); + a << *i.getAnchor (); + } + } - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::resource_lists::serializeResource_lists (s, m, f)); + void + serializeResourceLists (::std::ostream& o, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& s, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m, + const ::std::string& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::dont_initialize) == 0); - ::xsd::cxx::tree::error_handler< char > h; + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::LinphonePrivate::Xsd::ResourceLists::serializeResourceLists (s, m, f)); - ::xsd::cxx::xml::dom::ostream_format_target t (o); - if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) - { - h.throw_if_failed< ::xsd::cxx::tree::serialization< char > > (); - } - } + ::xsd::cxx::tree::error_handler< char > h; - void - serializeResource_lists (::std::ostream& o, - const ::resource_lists::Resource_lists& s, - ::xml_schema::ErrorHandler& h, - const ::xml_schema::NamespaceInfomap& m, - const ::std::string& e, - ::xml_schema::Flags f) - { - ::xsd::cxx::xml::auto_initializer i ( - (f & ::xml_schema::Flags::dont_initialize) == 0); + ::xsd::cxx::xml::dom::ostream_format_target t (o); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + h.throw_if_failed< ::xsd::cxx::tree::serialization< char > > (); + } + } - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::resource_lists::serializeResource_lists (s, m, f)); - ::xsd::cxx::xml::dom::ostream_format_target t (o); - if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) - { - throw ::xsd::cxx::tree::serialization< char > (); - } - } + void + serializeResourceLists (::std::ostream& o, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& s, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& h, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m, + const ::std::string& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + ::xsd::cxx::xml::auto_initializer i ( + (f & ::LinphonePrivate::Xsd::XmlSchema::Flags::dont_initialize) == 0); - void - serializeResource_lists (::std::ostream& o, - const ::resource_lists::Resource_lists& s, - ::xercesc::DOMErrorHandler& h, - const ::xml_schema::NamespaceInfomap& m, - const ::std::string& e, - ::xml_schema::Flags f) - { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::resource_lists::serializeResource_lists (s, m, f)); - ::xsd::cxx::xml::dom::ostream_format_target t (o); - if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) - { - throw ::xsd::cxx::tree::serialization< char > (); - } - } + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::LinphonePrivate::Xsd::ResourceLists::serializeResourceLists (s, m, f)); + ::xsd::cxx::xml::dom::ostream_format_target t (o); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + throw ::xsd::cxx::tree::serialization< char > (); + } + } - void - serializeResource_lists (::xercesc::XMLFormatTarget& t, - const ::resource_lists::Resource_lists& s, - const ::xml_schema::NamespaceInfomap& m, - const ::std::string& e, - ::xml_schema::Flags f) - { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::resource_lists::serializeResource_lists (s, m, f)); + void + serializeResourceLists (::std::ostream& o, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& s, + ::xercesc::DOMErrorHandler& h, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m, + const ::std::string& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::LinphonePrivate::Xsd::ResourceLists::serializeResourceLists (s, m, f)); + ::xsd::cxx::xml::dom::ostream_format_target t (o); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + throw ::xsd::cxx::tree::serialization< char > (); + } + } - ::xsd::cxx::tree::error_handler< char > h; + void + serializeResourceLists (::xercesc::XMLFormatTarget& t, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& s, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m, + const ::std::string& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::LinphonePrivate::Xsd::ResourceLists::serializeResourceLists (s, m, f)); - if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) - { - h.throw_if_failed< ::xsd::cxx::tree::serialization< char > > (); - } - } + ::xsd::cxx::tree::error_handler< char > h; - void - serializeResource_lists (::xercesc::XMLFormatTarget& t, - const ::resource_lists::Resource_lists& s, - ::xml_schema::ErrorHandler& h, - const ::xml_schema::NamespaceInfomap& m, - const ::std::string& e, - ::xml_schema::Flags f) - { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::resource_lists::serializeResource_lists (s, m, f)); - if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) - { - throw ::xsd::cxx::tree::serialization< char > (); - } - } + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + h.throw_if_failed< ::xsd::cxx::tree::serialization< char > > (); + } + } - void - serializeResource_lists (::xercesc::XMLFormatTarget& t, - const ::resource_lists::Resource_lists& s, - ::xercesc::DOMErrorHandler& h, - const ::xml_schema::NamespaceInfomap& m, - const ::std::string& e, - ::xml_schema::Flags f) - { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::resource_lists::serializeResource_lists (s, m, f)); - if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) - { - throw ::xsd::cxx::tree::serialization< char > (); - } - } + void + serializeResourceLists (::xercesc::XMLFormatTarget& t, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& s, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& h, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m, + const ::std::string& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::LinphonePrivate::Xsd::ResourceLists::serializeResourceLists (s, m, f)); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + throw ::xsd::cxx::tree::serialization< char > (); + } + } - void - serializeResource_lists (::xercesc::DOMDocument& d, - const ::resource_lists::Resource_lists& s, - ::xml_schema::Flags) - { - ::xercesc::DOMElement& e (*d.getDocumentElement ()); - const ::xsd::cxx::xml::qualified_name< char > n ( - ::xsd::cxx::xml::dom::name< char > (e)); + void + serializeResourceLists (::xercesc::XMLFormatTarget& t, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& s, + ::xercesc::DOMErrorHandler& h, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m, + const ::std::string& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::LinphonePrivate::Xsd::ResourceLists::serializeResourceLists (s, m, f)); + if (!::xsd::cxx::xml::dom::serialize (t, *d, e, h, f)) + { + throw ::xsd::cxx::tree::serialization< char > (); + } + } - if (n.name () == "resource-lists" && - n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") - { - e << s; - } - else - { - throw ::xsd::cxx::tree::unexpected_element < char > ( - n.name (), - n.namespace_ (), - "resource-lists", - "urn:ietf:params:xml:ns:resource-lists"); - } - } + void + serializeResourceLists (::xercesc::DOMDocument& d, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& s, + ::LinphonePrivate::Xsd::XmlSchema::Flags) + { + ::xercesc::DOMElement& e (*d.getDocumentElement ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (e)); - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > - serializeResource_lists (const ::resource_lists::Resource_lists& s, - const ::xml_schema::NamespaceInfomap& m, - ::xml_schema::Flags f) - { - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( - ::xsd::cxx::xml::dom::serialize< char > ( - "resource-lists", - "urn:ietf:params:xml:ns:resource-lists", - m, f)); + if (n.name () == "resource-lists" && + n.namespace_ () == "urn:ietf:params:xml:ns:resource-lists") + { + e << s; + } + else + { + throw ::xsd::cxx::tree::unexpected_element < char > ( + n.name (), + n.namespace_ (), + "resource-lists", + "urn:ietf:params:xml:ns:resource-lists"); + } + } - ::resource_lists::serializeResource_lists (*d, s, f); - return d; - } + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > + serializeResourceLists (const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& s, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m, + ::LinphonePrivate::Xsd::XmlSchema::Flags f) + { + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::serialize< char > ( + "resource-lists", + "urn:ietf:params:xml:ns:resource-lists", + m, f)); - void - operator<< (::xercesc::DOMElement& e, const Display_nameType& i) - { - e << static_cast< const ::xml_schema::String& > (i); + ::LinphonePrivate::Xsd::ResourceLists::serializeResourceLists (*d, s, f); + return d; + } - // lang - // - if (i.getLang ()) - { - ::xercesc::DOMAttr& a ( - ::xsd::cxx::xml::dom::create_attribute ( - "lang", - "http://www.w3.org/XML/1998/namespace", - e)); + void + operator<< (::xercesc::DOMElement& e, const DisplayNameType& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); - a << *i.getLang (); - } - } + // lang + // + if (i.getLang ()) + { + ::xercesc::DOMAttr& a ( + ::xsd::cxx::xml::dom::create_attribute ( + "lang", + "http://www.w3.org/XML/1998/namespace", + e)); - void - operator<< (::xercesc::DOMElement& e, const List& i) - { - e << static_cast< const ::resource_lists::ListType& > (i); - } + a << *i.getLang (); + } + } - void - operator<< (::xercesc::DOMElement& e, const Display_name& i) - { - e << static_cast< const ::resource_lists::Display_nameType& > (i); - } + void + operator<< (::xercesc::DOMElement& e, const List& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::ResourceLists::ListType& > (i); + } - void - operator<< (::xercesc::DOMElement& e, const Resource_lists& i) - { - e << static_cast< const ::xml_schema::Type& > (i); + void + operator<< (::xercesc::DOMElement& e, const DisplayName& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::ResourceLists::DisplayNameType& > (i); + } - // list - // - for (Resource_lists::ListConstIterator - b (i.getList ().begin ()), n (i.getList ().end ()); - b != n; ++b) - { - ::xercesc::DOMElement& s ( - ::xsd::cxx::xml::dom::create_element ( - "list", - "urn:ietf:params:xml:ns:resource-lists", - e)); + void + operator<< (::xercesc::DOMElement& e, const ResourceLists& i) + { + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Type& > (i); - s << *b; + // list + // + for (ResourceLists::ListConstIterator + b (i.getList ().begin ()), n (i.getList ().end ()); + b != n; ++b) + { + ::xercesc::DOMElement& s ( + ::xsd::cxx::xml::dom::create_element ( + "list", + "urn:ietf:params:xml:ns:resource-lists", + e)); + + s << *b; + } + } } } } @@ -2452,11 +2480,9 @@ namespace resource_lists // Begin epilogue. // - #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic pop #endif - // // End epilogue. diff --git a/src/xml/resource-lists.h b/src/xml/resource-lists.h index b3dab2800..ce7f1a8ce 100644 --- a/src/xml/resource-lists.h +++ b/src/xml/resource-lists.h @@ -48,12 +48,10 @@ // Begin prologue. // - #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsuggest-override" #endif - // // End prologue. @@ -106,170 +104,182 @@ #include -namespace xml_schema +namespace LinphonePrivate { - // anyType and anySimpleType. - // - typedef ::xsd::cxx::tree::type Type; - typedef ::xsd::cxx::tree::simple_type< char, Type > SimpleType; - typedef ::xsd::cxx::tree::type Container; - - // 8-bit - // - typedef signed char Byte; - typedef unsigned char UnsignedByte; - - // 16-bit - // - typedef short Short; - typedef unsigned short UnsignedShort; - - // 32-bit - // - typedef int Int; - typedef unsigned int UnsignedInt; - - // 64-bit - // - typedef long long Long; - typedef unsigned long long UnsignedLong; - - // Supposed to be arbitrary-length integral types. - // - typedef long long Integer; - typedef long long NonPositiveInteger; - typedef unsigned long long NonNegativeInteger; - typedef unsigned long long PositiveInteger; - typedef long long NegativeInteger; - - // Boolean. - // - typedef bool Boolean; - - // Floating-point types. - // - typedef float Float; - typedef double Double; - typedef double Decimal; - - // String types. - // - typedef ::xsd::cxx::tree::string< char, SimpleType > String; - typedef ::xsd::cxx::tree::normalized_string< char, String > NormalizedString; - typedef ::xsd::cxx::tree::token< char, NormalizedString > Token; - typedef ::xsd::cxx::tree::name< char, Token > Name; - typedef ::xsd::cxx::tree::nmtoken< char, Token > Nmtoken; - typedef ::xsd::cxx::tree::nmtokens< char, SimpleType, Nmtoken > Nmtokens; - typedef ::xsd::cxx::tree::ncname< char, Name > Ncname; - typedef ::xsd::cxx::tree::language< char, Token > Language; - - // ID/IDREF. - // - typedef ::xsd::cxx::tree::id< char, Ncname > Id; - typedef ::xsd::cxx::tree::idref< char, Ncname, Type > Idref; - typedef ::xsd::cxx::tree::idrefs< char, SimpleType, Idref > Idrefs; - - // URI. - // - typedef ::xsd::cxx::tree::uri< char, SimpleType > Uri; - - // Qualified name. - // - typedef ::xsd::cxx::tree::qname< char, SimpleType, Uri, Ncname > Qname; - - // Binary. - // - typedef ::xsd::cxx::tree::buffer< char > Buffer; - typedef ::xsd::cxx::tree::base64_binary< char, SimpleType > Base64Binary; - typedef ::xsd::cxx::tree::hex_binary< char, SimpleType > HexBinary; - - // Date/time. - // - typedef ::xsd::cxx::tree::time_zone TimeZone; - typedef ::xsd::cxx::tree::date< char, SimpleType > Date; - typedef ::xsd::cxx::tree::date_time< char, SimpleType > DateTime; - typedef ::xsd::cxx::tree::duration< char, SimpleType > Duration; - typedef ::xsd::cxx::tree::gday< char, SimpleType > Gday; - typedef ::xsd::cxx::tree::gmonth< char, SimpleType > Gmonth; - typedef ::xsd::cxx::tree::gmonth_day< char, SimpleType > GmonthDay; - typedef ::xsd::cxx::tree::gyear< char, SimpleType > Gyear; - typedef ::xsd::cxx::tree::gyear_month< char, SimpleType > GyearMonth; - typedef ::xsd::cxx::tree::time< char, SimpleType > Time; - - // Entity. - // - typedef ::xsd::cxx::tree::entity< char, Ncname > Entity; - typedef ::xsd::cxx::tree::entities< char, SimpleType, Entity > Entities; - - typedef ::xsd::cxx::tree::content_order ContentOrder; - // Namespace information and list stream. Used in - // serialization functions. - // - typedef ::xsd::cxx::xml::dom::namespace_info< char > NamespaceInfo; - typedef ::xsd::cxx::xml::dom::namespace_infomap< char > NamespaceInfomap; - typedef ::xsd::cxx::tree::list_stream< char > ListStream; - typedef ::xsd::cxx::tree::as_double< Double > AsDouble; - typedef ::xsd::cxx::tree::as_decimal< Decimal > AsDecimal; - typedef ::xsd::cxx::tree::facet Facet; - - // Flags and properties. - // - typedef ::xsd::cxx::tree::flags Flags; - typedef ::xsd::cxx::tree::properties< char > Properties; - - // Parsing/serialization diagnostics. - // - typedef ::xsd::cxx::tree::severity Severity; - typedef ::xsd::cxx::tree::error< char > Error; - typedef ::xsd::cxx::tree::diagnostics< char > Diagnostics; - - // Exceptions. - // - typedef ::xsd::cxx::tree::exception< char > Exception; - typedef ::xsd::cxx::tree::bounds< char > Bounds; - typedef ::xsd::cxx::tree::duplicate_id< char > DuplicateId; - typedef ::xsd::cxx::tree::parsing< char > Parsing; - typedef ::xsd::cxx::tree::expected_element< char > ExpectedElement; - typedef ::xsd::cxx::tree::unexpected_element< char > UnexpectedElement; - typedef ::xsd::cxx::tree::expected_attribute< char > ExpectedAttribute; - typedef ::xsd::cxx::tree::unexpected_enumerator< char > UnexpectedEnumerator; - typedef ::xsd::cxx::tree::expected_text_content< char > ExpectedTextContent; - typedef ::xsd::cxx::tree::no_prefix_mapping< char > NoPrefixMapping; - typedef ::xsd::cxx::tree::serialization< char > Serialization; - - // Error handler callback interface. - // - typedef ::xsd::cxx::xml::error_handler< char > ErrorHandler; - - // DOM interaction. - // - namespace dom + namespace Xsd { - // Automatic pointer for DOMDocument. - // - using ::xsd::cxx::xml::dom::unique_ptr; + namespace XmlSchema + { + // anyType and anySimpleType. + // + typedef ::xsd::cxx::tree::type Type; + typedef ::xsd::cxx::tree::simple_type< char, Type > SimpleType; + typedef ::xsd::cxx::tree::type Container; -#ifndef XSD_CXX_TREE_TREE_NODE_KEY__XML_SCHEMA -#define XSD_CXX_TREE_TREE_NODE_KEY__XML_SCHEMA - // DOM user data key for back pointers to tree nodes. - // - const XMLCh* const treeNodeKey = ::xsd::cxx::tree::user_data_keys::node; + // 8-bit + // + typedef signed char Byte; + typedef unsigned char UnsignedByte; + + // 16-bit + // + typedef short Short; + typedef unsigned short UnsignedShort; + + // 32-bit + // + typedef int Int; + typedef unsigned int UnsignedInt; + + // 64-bit + // + typedef long long Long; + typedef unsigned long long UnsignedLong; + + // Supposed to be arbitrary-length integral types. + // + typedef long long Integer; + typedef long long NonPositiveInteger; + typedef unsigned long long NonNegativeInteger; + typedef unsigned long long PositiveInteger; + typedef long long NegativeInteger; + + // Boolean. + // + typedef bool Boolean; + + // Floating-point types. + // + typedef float Float; + typedef double Double; + typedef double Decimal; + + // String types. + // + typedef ::xsd::cxx::tree::string< char, SimpleType > String; + typedef ::xsd::cxx::tree::normalized_string< char, String > NormalizedString; + typedef ::xsd::cxx::tree::token< char, NormalizedString > Token; + typedef ::xsd::cxx::tree::name< char, Token > Name; + typedef ::xsd::cxx::tree::nmtoken< char, Token > Nmtoken; + typedef ::xsd::cxx::tree::nmtokens< char, SimpleType, Nmtoken > Nmtokens; + typedef ::xsd::cxx::tree::ncname< char, Name > Ncname; + typedef ::xsd::cxx::tree::language< char, Token > Language; + + // ID/IDREF. + // + typedef ::xsd::cxx::tree::id< char, Ncname > Id; + typedef ::xsd::cxx::tree::idref< char, Ncname, Type > Idref; + typedef ::xsd::cxx::tree::idrefs< char, SimpleType, Idref > Idrefs; + + // URI. + // + typedef ::xsd::cxx::tree::uri< char, SimpleType > Uri; + + // Qualified name. + // + typedef ::xsd::cxx::tree::qname< char, SimpleType, Uri, Ncname > Qname; + + // Binary. + // + typedef ::xsd::cxx::tree::buffer< char > Buffer; + typedef ::xsd::cxx::tree::base64_binary< char, SimpleType > Base64Binary; + typedef ::xsd::cxx::tree::hex_binary< char, SimpleType > HexBinary; + + // Date/time. + // + typedef ::xsd::cxx::tree::time_zone TimeZone; + typedef ::xsd::cxx::tree::date< char, SimpleType > Date; + typedef ::xsd::cxx::tree::date_time< char, SimpleType > DateTime; + typedef ::xsd::cxx::tree::duration< char, SimpleType > Duration; + typedef ::xsd::cxx::tree::gday< char, SimpleType > Gday; + typedef ::xsd::cxx::tree::gmonth< char, SimpleType > Gmonth; + typedef ::xsd::cxx::tree::gmonth_day< char, SimpleType > GmonthDay; + typedef ::xsd::cxx::tree::gyear< char, SimpleType > Gyear; + typedef ::xsd::cxx::tree::gyear_month< char, SimpleType > GyearMonth; + typedef ::xsd::cxx::tree::time< char, SimpleType > Time; + + // Entity. + // + typedef ::xsd::cxx::tree::entity< char, Ncname > Entity; + typedef ::xsd::cxx::tree::entities< char, SimpleType, Entity > Entities; + + typedef ::xsd::cxx::tree::content_order ContentOrder; + // Namespace information and list stream. Used in + // serialization functions. + // + typedef ::xsd::cxx::xml::dom::namespace_info< char > NamespaceInfo; + typedef ::xsd::cxx::xml::dom::namespace_infomap< char > NamespaceInfomap; + typedef ::xsd::cxx::tree::list_stream< char > ListStream; + typedef ::xsd::cxx::tree::as_double< Double > AsDouble; + typedef ::xsd::cxx::tree::as_decimal< Decimal > AsDecimal; + typedef ::xsd::cxx::tree::facet Facet; + + // Flags and properties. + // + typedef ::xsd::cxx::tree::flags Flags; + typedef ::xsd::cxx::tree::properties< char > Properties; + + // Parsing/serialization diagnostics. + // + typedef ::xsd::cxx::tree::severity Severity; + typedef ::xsd::cxx::tree::error< char > Error; + typedef ::xsd::cxx::tree::diagnostics< char > Diagnostics; + + // Exceptions. + // + typedef ::xsd::cxx::tree::exception< char > Exception; + typedef ::xsd::cxx::tree::bounds< char > Bounds; + typedef ::xsd::cxx::tree::duplicate_id< char > DuplicateId; + typedef ::xsd::cxx::tree::parsing< char > Parsing; + typedef ::xsd::cxx::tree::expected_element< char > ExpectedElement; + typedef ::xsd::cxx::tree::unexpected_element< char > UnexpectedElement; + typedef ::xsd::cxx::tree::expected_attribute< char > ExpectedAttribute; + typedef ::xsd::cxx::tree::unexpected_enumerator< char > UnexpectedEnumerator; + typedef ::xsd::cxx::tree::expected_text_content< char > ExpectedTextContent; + typedef ::xsd::cxx::tree::no_prefix_mapping< char > NoPrefixMapping; + typedef ::xsd::cxx::tree::serialization< char > Serialization; + + // Error handler callback interface. + // + typedef ::xsd::cxx::xml::error_handler< char > ErrorHandler; + + // DOM interaction. + // + namespace dom + { + // Automatic pointer for DOMDocument. + // + using ::xsd::cxx::xml::dom::unique_ptr; + +#ifndef XSD_CXX_TREE_TREE_NODE_KEY__LINPHONEPRIVATE__XSD__XMLSCHEMA +#define XSD_CXX_TREE_TREE_NODE_KEY__LINPHONEPRIVATE__XSD__XMLSCHEMA + // DOM user data key for back pointers to tree nodes. + // + const XMLCh* const treeNodeKey = ::xsd::cxx::tree::user_data_keys::node; #endif + } + } } } // Forward declarations. // -namespace resource_lists +namespace LinphonePrivate { - class ListType; - class EntryType; - class Entry_refType; - class ExternalType; - class Display_nameType; - class List; - class Display_name; - class Resource_lists; + namespace Xsd + { + namespace ResourceLists + { + class ListType; + class EntryType; + class EntryRefType; + class ExternalType; + class DisplayNameType; + class List; + class DisplayName; + class ResourceLists; + } + } } @@ -291,758 +301,770 @@ namespace resource_lists #include "xml.h" -namespace resource_lists +namespace LinphonePrivate { - class ListType: public ::xml_schema::Type + namespace Xsd { - public: - // display-name - // - typedef ::resource_lists::Display_nameType Display_nameType; - typedef ::xsd::cxx::tree::optional< Display_nameType > Display_nameOptional; - typedef ::xsd::cxx::tree::traits< Display_nameType, char > Display_nameTraits; + namespace ResourceLists + { + class ListType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // display-name + // + typedef ::LinphonePrivate::Xsd::ResourceLists::DisplayNameType DisplayNameType; + typedef ::xsd::cxx::tree::optional< DisplayNameType > DisplayNameOptional; + typedef ::xsd::cxx::tree::traits< DisplayNameType, char > DisplayNameTraits; + + const DisplayNameOptional& + getDisplayName () const; + + DisplayNameOptional& + getDisplayName (); + + void + setDisplayName (const DisplayNameType& x); + + void + setDisplayName (const DisplayNameOptional& x); + + void + setDisplayName (::std::unique_ptr< DisplayNameType > p); + + // list + // + typedef ::LinphonePrivate::Xsd::ResourceLists::List ListType1; + typedef ::xsd::cxx::tree::sequence< ListType1 > ListSequence; + typedef ListSequence::iterator ListIterator; + typedef ListSequence::const_iterator ListConstIterator; + typedef ::xsd::cxx::tree::traits< ListType1, char > ListTraits; + + const ListSequence& + getList () const; + + ListSequence& + getList (); + + void + setList (const ListSequence& s); - const Display_nameOptional& - getDisplay_name () const; - - Display_nameOptional& - getDisplay_name (); - - void - setDisplay_name (const Display_nameType& x); - - void - setDisplay_name (const Display_nameOptional& x); + // external + // + typedef ::LinphonePrivate::Xsd::ResourceLists::ExternalType ExternalType; + typedef ::xsd::cxx::tree::sequence< ExternalType > ExternalSequence; + typedef ExternalSequence::iterator ExternalIterator; + typedef ExternalSequence::const_iterator ExternalConstIterator; + typedef ::xsd::cxx::tree::traits< ExternalType, char > ExternalTraits; - void - setDisplay_name (::std::unique_ptr< Display_nameType > p); + const ExternalSequence& + getExternal () const; - // list - // - typedef ::resource_lists::List ListType1; - typedef ::xsd::cxx::tree::sequence< ListType1 > ListSequence; - typedef ListSequence::iterator ListIterator; - typedef ListSequence::const_iterator ListConstIterator; - typedef ::xsd::cxx::tree::traits< ListType1, char > ListTraits; + ExternalSequence& + getExternal (); - const ListSequence& - getList () const; + void + setExternal (const ExternalSequence& s); + + // entry + // + typedef ::LinphonePrivate::Xsd::ResourceLists::EntryType EntryType; + typedef ::xsd::cxx::tree::sequence< EntryType > EntrySequence; + typedef EntrySequence::iterator EntryIterator; + typedef EntrySequence::const_iterator EntryConstIterator; + typedef ::xsd::cxx::tree::traits< EntryType, char > EntryTraits; + + const EntrySequence& + getEntry () const; - ListSequence& - getList (); + EntrySequence& + getEntry (); - void - setList (const ListSequence& s); + void + setEntry (const EntrySequence& s); - // external - // - typedef ::resource_lists::ExternalType ExternalType; - typedef ::xsd::cxx::tree::sequence< ExternalType > ExternalSequence; - typedef ExternalSequence::iterator ExternalIterator; - typedef ExternalSequence::const_iterator ExternalConstIterator; - typedef ::xsd::cxx::tree::traits< ExternalType, char > ExternalTraits; + // entry-ref + // + typedef ::LinphonePrivate::Xsd::ResourceLists::EntryRefType EntryRefType; + typedef ::xsd::cxx::tree::sequence< EntryRefType > EntryRefSequence; + typedef EntryRefSequence::iterator EntryRefIterator; + typedef EntryRefSequence::const_iterator EntryRefConstIterator; + typedef ::xsd::cxx::tree::traits< EntryRefType, char > EntryRefTraits; - const ExternalSequence& - getExternal () const; + const EntryRefSequence& + getEntryRef () const; + + EntryRefSequence& + getEntryRef (); + + void + setEntryRef (const EntryRefSequence& s); + + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); + + // name + // + typedef ::LinphonePrivate::Xsd::XmlSchema::String NameType; + typedef ::xsd::cxx::tree::optional< NameType > NameOptional; + typedef ::xsd::cxx::tree::traits< NameType, char > NameTraits; + + const NameOptional& + getName () const; + + NameOptional& + getName (); + + void + setName (const NameType& x); + + void + setName (const NameOptional& x); + + void + setName (::std::unique_ptr< NameType > p); + + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - ExternalSequence& - getExternal (); + const AnyAttributeSet& + getAnyAttribute () const; - void - setExternal (const ExternalSequence& s); + AnyAttributeSet& + getAnyAttribute (); - // entry - // - typedef ::resource_lists::EntryType EntryType; - typedef ::xsd::cxx::tree::sequence< EntryType > EntrySequence; - typedef EntrySequence::iterator EntryIterator; - typedef EntrySequence::const_iterator EntryConstIterator; - typedef ::xsd::cxx::tree::traits< EntryType, char > EntryTraits; + void + setAnyAttribute (const AnyAttributeSet& s); - const EntrySequence& - getEntry () const; + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; - EntrySequence& - getEntry (); + ::xercesc::DOMDocument& + getDomDocument (); - void - setEntry (const EntrySequence& s); + // Constructors. + // + ListType (); - // entry-ref - // - typedef ::resource_lists::Entry_refType Entry_refType; - typedef ::xsd::cxx::tree::sequence< Entry_refType > Entry_refSequence; - typedef Entry_refSequence::iterator Entry_refIterator; - typedef Entry_refSequence::const_iterator Entry_refConstIterator; - typedef ::xsd::cxx::tree::traits< Entry_refType, char > Entry_refTraits; + ListType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - const Entry_refSequence& - getEntry_ref () const; + ListType (const ListType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - Entry_refSequence& - getEntry_ref (); + virtual ListType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; - void - setEntry_ref (const Entry_refSequence& s); - - // any - // - typedef ::xsd::cxx::tree::element_sequence AnySequence; - typedef AnySequence::iterator AnyIterator; - typedef AnySequence::const_iterator AnyConstIterator; - - const AnySequence& - getAny () const; - - AnySequence& - getAny (); - - void - setAny (const AnySequence& s); - - // name - // - typedef ::xml_schema::String NameType; - typedef ::xsd::cxx::tree::optional< NameType > NameOptional; - typedef ::xsd::cxx::tree::traits< NameType, char > NameTraits; - - const NameOptional& - getName () const; - - NameOptional& - getName (); - - void - setName (const NameType& x); - - void - setName (const NameOptional& x); - - void - setName (::std::unique_ptr< NameType > p); - - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + ListType& + operator= (const ListType& x); - const AnyAttributeSet& - getAnyAttribute () const; + virtual + ~ListType (); - AnyAttributeSet& - getAnyAttribute (); + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); - void - setAnyAttribute (const AnyAttributeSet& s); + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; + DisplayNameOptional display_name_; + ListSequence list_; + ExternalSequence external_; + EntrySequence entry_; + EntryRefSequence entry_ref_; + AnySequence any_; + NameOptional name_; + AnyAttributeSet any_attribute_; + }; - ::xercesc::DOMDocument& - getDomDocument (); + class EntryType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // display-name + // + typedef ::LinphonePrivate::Xsd::ResourceLists::DisplayName DisplayNameType; + typedef ::xsd::cxx::tree::optional< DisplayNameType > DisplayNameOptional; + typedef ::xsd::cxx::tree::traits< DisplayNameType, char > DisplayNameTraits; - // Constructors. - // - ListType (); + const DisplayNameOptional& + getDisplayName () const; - ListType (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + DisplayNameOptional& + getDisplayName (); - ListType (const ListType& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + void + setDisplayName (const DisplayNameType& x); - virtual ListType* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; + void + setDisplayName (const DisplayNameOptional& x); - ListType& - operator= (const ListType& x); + void + setDisplayName (::std::unique_ptr< DisplayNameType > p); - virtual - ~ListType (); + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; + + const AnySequence& + getAny () const; + + AnySequence& + getAny (); + + void + setAny (const AnySequence& s); - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); + // uri + // + typedef ::LinphonePrivate::Xsd::XmlSchema::Uri UriType; + typedef ::xsd::cxx::tree::traits< UriType, char > UriTraits; - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + const UriType& + getUri () const; - Display_nameOptional display_name_; - ListSequence list_; - ExternalSequence external_; - EntrySequence entry_; - Entry_refSequence entry_ref_; - AnySequence any_; - NameOptional name_; - AnyAttributeSet any_attribute_; - }; + UriType& + getUri (); - class EntryType: public ::xml_schema::Type - { - public: - // display-name - // - typedef ::resource_lists::Display_name Display_nameType; - typedef ::xsd::cxx::tree::optional< Display_nameType > Display_nameOptional; - typedef ::xsd::cxx::tree::traits< Display_nameType, char > Display_nameTraits; + void + setUri (const UriType& x); - const Display_nameOptional& - getDisplay_name () const; + void + setUri (::std::unique_ptr< UriType > p); - Display_nameOptional& - getDisplay_name (); + ::std::unique_ptr< UriType > + setDetachUri (); - void - setDisplay_name (const Display_nameType& x); + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - void - setDisplay_name (const Display_nameOptional& x); + const AnyAttributeSet& + getAnyAttribute () const; - void - setDisplay_name (::std::unique_ptr< Display_nameType > p); + AnyAttributeSet& + getAnyAttribute (); - // any - // - typedef ::xsd::cxx::tree::element_sequence AnySequence; - typedef AnySequence::iterator AnyIterator; - typedef AnySequence::const_iterator AnyConstIterator; - - const AnySequence& - getAny () const; - - AnySequence& - getAny (); - - void - setAny (const AnySequence& s); + void + setAnyAttribute (const AnyAttributeSet& s); - // uri - // - typedef ::xml_schema::Uri UriType; - typedef ::xsd::cxx::tree::traits< UriType, char > UriTraits; + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; - const UriType& - getUri () const; + ::xercesc::DOMDocument& + getDomDocument (); - UriType& - getUri (); + // Constructors. + // + EntryType (const UriType&); - void - setUri (const UriType& x); + EntryType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - void - setUri (::std::unique_ptr< UriType > p); + EntryType (const EntryType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - ::std::unique_ptr< UriType > - detachUri (); + virtual EntryType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + EntryType& + operator= (const EntryType& x); - const AnyAttributeSet& - getAnyAttribute () const; + virtual + ~EntryType (); - AnyAttributeSet& - getAnyAttribute (); + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); - void - setAnyAttribute (const AnyAttributeSet& s); + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; + DisplayNameOptional display_name_; + AnySequence any_; + ::xsd::cxx::tree::one< UriType > uri_; + AnyAttributeSet any_attribute_; + }; - ::xercesc::DOMDocument& - getDomDocument (); + class EntryRefType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // display-name + // + typedef ::LinphonePrivate::Xsd::ResourceLists::DisplayNameType DisplayNameType; + typedef ::xsd::cxx::tree::optional< DisplayNameType > DisplayNameOptional; + typedef ::xsd::cxx::tree::traits< DisplayNameType, char > DisplayNameTraits; - // Constructors. - // - EntryType (const UriType&); + const DisplayNameOptional& + getDisplayName () const; - EntryType (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + DisplayNameOptional& + getDisplayName (); - EntryType (const EntryType& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + void + setDisplayName (const DisplayNameType& x); - virtual EntryType* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; + void + setDisplayName (const DisplayNameOptional& x); - EntryType& - operator= (const EntryType& x); + void + setDisplayName (::std::unique_ptr< DisplayNameType > p); - virtual - ~EntryType (); + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); + const AnySequence& + getAny () const; - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + AnySequence& + getAny (); - Display_nameOptional display_name_; - AnySequence any_; - ::xsd::cxx::tree::one< UriType > uri_; - AnyAttributeSet any_attribute_; - }; + void + setAny (const AnySequence& s); - class Entry_refType: public ::xml_schema::Type - { - public: - // display-name - // - typedef ::resource_lists::Display_nameType Display_nameType; - typedef ::xsd::cxx::tree::optional< Display_nameType > Display_nameOptional; - typedef ::xsd::cxx::tree::traits< Display_nameType, char > Display_nameTraits; + // ref + // + typedef ::LinphonePrivate::Xsd::XmlSchema::Uri RefType; + typedef ::xsd::cxx::tree::traits< RefType, char > RefTraits; - const Display_nameOptional& - getDisplay_name () const; + const RefType& + getRef () const; - Display_nameOptional& - getDisplay_name (); + RefType& + getRef (); - void - setDisplay_name (const Display_nameType& x); + void + setRef (const RefType& x); - void - setDisplay_name (const Display_nameOptional& x); + void + setRef (::std::unique_ptr< RefType > p); - void - setDisplay_name (::std::unique_ptr< Display_nameType > p); + ::std::unique_ptr< RefType > + setDetachRef (); - // any - // - typedef ::xsd::cxx::tree::element_sequence AnySequence; - typedef AnySequence::iterator AnyIterator; - typedef AnySequence::const_iterator AnyConstIterator; + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - const AnySequence& - getAny () const; + const AnyAttributeSet& + getAnyAttribute () const; - AnySequence& - getAny (); + AnyAttributeSet& + getAnyAttribute (); - void - setAny (const AnySequence& s); + void + setAnyAttribute (const AnyAttributeSet& s); - // ref - // - typedef ::xml_schema::Uri RefType; - typedef ::xsd::cxx::tree::traits< RefType, char > RefTraits; + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; - const RefType& - getRef () const; + ::xercesc::DOMDocument& + getDomDocument (); - RefType& - getRef (); + // Constructors. + // + EntryRefType (const RefType&); - void - setRef (const RefType& x); + EntryRefType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - void - setRef (::std::unique_ptr< RefType > p); + EntryRefType (const EntryRefType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - ::std::unique_ptr< RefType > - detachRef (); + virtual EntryRefType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + EntryRefType& + operator= (const EntryRefType& x); - const AnyAttributeSet& - getAnyAttribute () const; + virtual + ~EntryRefType (); - AnyAttributeSet& - getAnyAttribute (); + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); - void - setAnyAttribute (const AnyAttributeSet& s); + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; + DisplayNameOptional display_name_; + AnySequence any_; + ::xsd::cxx::tree::one< RefType > ref_; + AnyAttributeSet any_attribute_; + }; - ::xercesc::DOMDocument& - getDomDocument (); + class ExternalType: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // display-name + // + typedef ::LinphonePrivate::Xsd::ResourceLists::DisplayNameType DisplayNameType; + typedef ::xsd::cxx::tree::optional< DisplayNameType > DisplayNameOptional; + typedef ::xsd::cxx::tree::traits< DisplayNameType, char > DisplayNameTraits; - // Constructors. - // - Entry_refType (const RefType&); + const DisplayNameOptional& + getDisplayName () const; - Entry_refType (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + DisplayNameOptional& + getDisplayName (); - Entry_refType (const Entry_refType& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + void + setDisplayName (const DisplayNameType& x); - virtual Entry_refType* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; + void + setDisplayName (const DisplayNameOptional& x); - Entry_refType& - operator= (const Entry_refType& x); + void + setDisplayName (::std::unique_ptr< DisplayNameType > p); - virtual - ~Entry_refType (); + // any + // + typedef ::xsd::cxx::tree::element_sequence AnySequence; + typedef AnySequence::iterator AnyIterator; + typedef AnySequence::const_iterator AnyConstIterator; - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); + const AnySequence& + getAny () const; - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + AnySequence& + getAny (); - Display_nameOptional display_name_; - AnySequence any_; - ::xsd::cxx::tree::one< RefType > ref_; - AnyAttributeSet any_attribute_; - }; + void + setAny (const AnySequence& s); - class ExternalType: public ::xml_schema::Type - { - public: - // display-name - // - typedef ::resource_lists::Display_nameType Display_nameType; - typedef ::xsd::cxx::tree::optional< Display_nameType > Display_nameOptional; - typedef ::xsd::cxx::tree::traits< Display_nameType, char > Display_nameTraits; + // anchor + // + typedef ::LinphonePrivate::Xsd::XmlSchema::Uri AnchorType; + typedef ::xsd::cxx::tree::optional< AnchorType > AnchorOptional; + typedef ::xsd::cxx::tree::traits< AnchorType, char > AnchorTraits; - const Display_nameOptional& - getDisplay_name () const; + const AnchorOptional& + getAnchor () const; - Display_nameOptional& - getDisplay_name (); + AnchorOptional& + getAnchor (); - void - setDisplay_name (const Display_nameType& x); + void + setAnchor (const AnchorType& x); - void - setDisplay_name (const Display_nameOptional& x); + void + setAnchor (const AnchorOptional& x); - void - setDisplay_name (::std::unique_ptr< Display_nameType > p); + void + setAnchor (::std::unique_ptr< AnchorType > p); - // any - // - typedef ::xsd::cxx::tree::element_sequence AnySequence; - typedef AnySequence::iterator AnyIterator; - typedef AnySequence::const_iterator AnyConstIterator; + // any_attribute + // + typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; + typedef AnyAttributeSet::iterator AnyAttributeIterator; + typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; - const AnySequence& - getAny () const; + const AnyAttributeSet& + getAnyAttribute () const; - AnySequence& - getAny (); + AnyAttributeSet& + getAnyAttribute (); - void - setAny (const AnySequence& s); + void + setAnyAttribute (const AnyAttributeSet& s); - // anchor - // - typedef ::xml_schema::Uri AnchorType; - typedef ::xsd::cxx::tree::optional< AnchorType > AnchorOptional; - typedef ::xsd::cxx::tree::traits< AnchorType, char > AnchorTraits; + // DOMDocument for wildcard content. + // + const ::xercesc::DOMDocument& + getDomDocument () const; - const AnchorOptional& - getAnchor () const; + ::xercesc::DOMDocument& + getDomDocument (); - AnchorOptional& - getAnchor (); + // Constructors. + // + ExternalType (); - void - setAnchor (const AnchorType& x); + ExternalType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - void - setAnchor (const AnchorOptional& x); + ExternalType (const ExternalType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - void - setAnchor (::std::unique_ptr< AnchorType > p); + virtual ExternalType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; - // any_attribute - // - typedef ::xsd::cxx::tree::attribute_set< char > AnyAttributeSet; - typedef AnyAttributeSet::iterator AnyAttributeIterator; - typedef AnyAttributeSet::const_iterator AnyAttributeConstIterator; + ExternalType& + operator= (const ExternalType& x); - const AnyAttributeSet& - getAnyAttribute () const; + virtual + ~ExternalType (); - AnyAttributeSet& - getAnyAttribute (); + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); - void - setAnyAttribute (const AnyAttributeSet& s); + protected: + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; - // DOMDocument for wildcard content. - // - const ::xercesc::DOMDocument& - getDomDocument () const; + DisplayNameOptional display_name_; + AnySequence any_; + AnchorOptional anchor_; + AnyAttributeSet any_attribute_; + }; - ::xercesc::DOMDocument& - getDomDocument (); + class DisplayNameType: public ::LinphonePrivate::Xsd::XmlSchema::String + { + public: + // lang + // + typedef ::namespace_::Lang LangType; + typedef ::xsd::cxx::tree::optional< LangType > LangOptional; + typedef ::xsd::cxx::tree::traits< LangType, char > LangTraits; - // Constructors. - // - ExternalType (); + const LangOptional& + getLang () const; - ExternalType (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + LangOptional& + getLang (); - ExternalType (const ExternalType& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + void + setLang (const LangType& x); - virtual ExternalType* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; + void + setLang (const LangOptional& x); - ExternalType& - operator= (const ExternalType& x); + void + setLang (::std::unique_ptr< LangType > p); - virtual - ~ExternalType (); + // Constructors. + // + DisplayNameType (); - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); + DisplayNameType (const char*); - protected: - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > dom_document_; + DisplayNameType (const ::std::string&); - Display_nameOptional display_name_; - AnySequence any_; - AnchorOptional anchor_; - AnyAttributeSet any_attribute_; - }; + DisplayNameType (const ::LinphonePrivate::Xsd::XmlSchema::String&); - class Display_nameType: public ::xml_schema::String - { - public: - // lang - // - typedef ::namespace_::Lang LangType; - typedef ::xsd::cxx::tree::optional< LangType > LangOptional; - typedef ::xsd::cxx::tree::traits< LangType, char > LangTraits; + DisplayNameType (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - const LangOptional& - getLang () const; + DisplayNameType (const DisplayNameType& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - LangOptional& - getLang (); + virtual DisplayNameType* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; - void - setLang (const LangType& x); + DisplayNameType& + operator= (const DisplayNameType& x); - void - setLang (const LangOptional& x); + virtual + ~DisplayNameType (); - void - setLang (::std::unique_ptr< LangType > p); + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); - // Constructors. - // - Display_nameType (); + protected: + LangOptional lang_; + }; + + class List: public ::LinphonePrivate::Xsd::ResourceLists::ListType + { + public: + // Constructors. + // + List (); + + List (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + List (const List& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual List* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + virtual + ~List (); + }; + + class DisplayName: public ::LinphonePrivate::Xsd::ResourceLists::DisplayNameType + { + public: + // Constructors. + // + DisplayName (); + + DisplayName (const char*); + + DisplayName (const ::std::string&); + + DisplayName (const ::LinphonePrivate::Xsd::XmlSchema::String&); - Display_nameType (const char*); + DisplayName (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - Display_nameType (const ::std::string&); + DisplayName (const DisplayName& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); - Display_nameType (const ::xml_schema::String&); + virtual DisplayName* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; - Display_nameType (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + virtual + ~DisplayName (); + }; - Display_nameType (const Display_nameType& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Display_nameType* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Display_nameType& - operator= (const Display_nameType& x); - - virtual - ~Display_nameType (); - - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); - - protected: - LangOptional lang_; - }; - - class List: public ::resource_lists::ListType - { - public: - // Constructors. - // - List (); - - List (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - List (const List& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual List* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - virtual - ~List (); - }; - - class Display_name: public ::resource_lists::Display_nameType - { - public: - // Constructors. - // - Display_name (); - - Display_name (const char*); - - Display_name (const ::std::string&); - - Display_name (const ::xml_schema::String&); - - Display_name (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Display_name (const Display_name& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Display_name* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - virtual - ~Display_name (); - }; - - class Resource_lists: public ::xml_schema::Type - { - public: - // list - // - typedef ::resource_lists::ListType ListType; - typedef ::xsd::cxx::tree::sequence< ListType > ListSequence; - typedef ListSequence::iterator ListIterator; - typedef ListSequence::const_iterator ListConstIterator; - typedef ::xsd::cxx::tree::traits< ListType, char > ListTraits; - - const ListSequence& - getList () const; - - ListSequence& - getList (); - - void - setList (const ListSequence& s); - - // Constructors. - // - Resource_lists (); - - Resource_lists (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - Resource_lists (const Resource_lists& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); - - virtual Resource_lists* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; - - Resource_lists& - operator= (const Resource_lists& x); - - virtual - ~Resource_lists (); - - // Implementation. - // - protected: - void - parse (::xsd::cxx::xml::dom::parser< char >&, - ::xml_schema::Flags); - - protected: - ListSequence list_; - }; + class ResourceLists: public ::LinphonePrivate::Xsd::XmlSchema::Type + { + public: + // list + // + typedef ::LinphonePrivate::Xsd::ResourceLists::ListType ListType; + typedef ::xsd::cxx::tree::sequence< ListType > ListSequence; + typedef ListSequence::iterator ListIterator; + typedef ListSequence::const_iterator ListConstIterator; + typedef ::xsd::cxx::tree::traits< ListType, char > ListTraits; + + const ListSequence& + getList () const; + + ListSequence& + getList (); + + void + setList (const ListSequence& s); + + // Constructors. + // + ResourceLists (); + + ResourceLists (const ::xercesc::DOMElement& e, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + ResourceLists (const ResourceLists& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); + + virtual ResourceLists* + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; + + ResourceLists& + operator= (const ResourceLists& x); + + virtual + ~ResourceLists (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::LinphonePrivate::Xsd::XmlSchema::Flags); + + protected: + ListSequence list_; + }; + } + } } #include -namespace resource_lists +namespace LinphonePrivate { - ::std::ostream& - operator<< (::std::ostream&, const ListType&); + namespace Xsd + { + namespace ResourceLists + { + ::std::ostream& + operator<< (::std::ostream&, const ListType&); - ::std::ostream& - operator<< (::std::ostream&, const EntryType&); + ::std::ostream& + operator<< (::std::ostream&, const EntryType&); - ::std::ostream& - operator<< (::std::ostream&, const Entry_refType&); + ::std::ostream& + operator<< (::std::ostream&, const EntryRefType&); - ::std::ostream& - operator<< (::std::ostream&, const ExternalType&); + ::std::ostream& + operator<< (::std::ostream&, const ExternalType&); - ::std::ostream& - operator<< (::std::ostream&, const Display_nameType&); + ::std::ostream& + operator<< (::std::ostream&, const DisplayNameType&); - ::std::ostream& - operator<< (::std::ostream&, const List&); + ::std::ostream& + operator<< (::std::ostream&, const List&); - ::std::ostream& - operator<< (::std::ostream&, const Display_name&); + ::std::ostream& + operator<< (::std::ostream&, const DisplayName&); - ::std::ostream& - operator<< (::std::ostream&, const Resource_lists&); + ::std::ostream& + operator<< (::std::ostream&, const ResourceLists&); + } + } } #include @@ -1051,100 +1073,106 @@ namespace resource_lists #include #include -namespace resource_lists +namespace LinphonePrivate { - // Parse a URI or a local file. - // + namespace Xsd + { + namespace ResourceLists + { + // Parse a URI or a local file. + // - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (const ::std::string& uri, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (const ::std::string& uri, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (const ::std::string& uri, - ::xml_schema::ErrorHandler& eh, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (const ::std::string& uri, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& eh, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (const ::std::string& uri, - ::xercesc::DOMErrorHandler& eh, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (const ::std::string& uri, + ::xercesc::DOMErrorHandler& eh, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - // Parse std::istream. - // + // Parse std::istream. + // - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::std::istream& is, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::std::istream& is, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::std::istream& is, - ::xml_schema::ErrorHandler& eh, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::std::istream& is, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& eh, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::std::istream& is, - ::xercesc::DOMErrorHandler& eh, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::std::istream& is, + ::xercesc::DOMErrorHandler& eh, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::std::istream& is, - const ::std::string& id, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::std::istream& is, + const ::std::string& id, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::std::istream& is, - const ::std::string& id, - ::xml_schema::ErrorHandler& eh, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::std::istream& is, + const ::std::string& id, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& eh, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::std::istream& is, - const ::std::string& id, - ::xercesc::DOMErrorHandler& eh, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::std::istream& is, + const ::std::string& id, + ::xercesc::DOMErrorHandler& eh, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - // Parse xercesc::InputSource. - // + // Parse xercesc::InputSource. + // - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::xercesc::InputSource& is, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::xercesc::InputSource& is, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::xercesc::InputSource& is, - ::xml_schema::ErrorHandler& eh, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::xercesc::InputSource& is, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& eh, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::xercesc::InputSource& is, - ::xercesc::DOMErrorHandler& eh, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::xercesc::InputSource& is, + ::xercesc::DOMErrorHandler& eh, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - // Parse xercesc::DOMDocument. - // + // Parse xercesc::DOMDocument. + // - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (const ::xercesc::DOMDocument& d, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (const ::xercesc::DOMDocument& d, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); - ::std::unique_ptr< ::resource_lists::Resource_lists > - parseResource_lists (::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d, - ::xml_schema::Flags f = 0, - const ::xml_schema::Properties& p = ::xml_schema::Properties ()); + ::std::unique_ptr< ::LinphonePrivate::Xsd::ResourceLists::ResourceLists > + parseResourceLists (::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > d, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + const ::LinphonePrivate::Xsd::XmlSchema::Properties& p = ::LinphonePrivate::Xsd::XmlSchema::Properties ()); + } + } } #include @@ -1155,110 +1183,114 @@ namespace resource_lists #include -namespace resource_lists +namespace LinphonePrivate { - void - operator<< (::xercesc::DOMElement&, const ListType&); + namespace Xsd + { + namespace ResourceLists + { + void + operator<< (::xercesc::DOMElement&, const ListType&); - void - operator<< (::xercesc::DOMElement&, const EntryType&); + void + operator<< (::xercesc::DOMElement&, const EntryType&); - void - operator<< (::xercesc::DOMElement&, const Entry_refType&); + void + operator<< (::xercesc::DOMElement&, const EntryRefType&); - void - operator<< (::xercesc::DOMElement&, const ExternalType&); + void + operator<< (::xercesc::DOMElement&, const ExternalType&); - // Serialize to std::ostream. - // + // Serialize to std::ostream. + // - void - serializeResource_lists (::std::ostream& os, - const ::resource_lists::Resource_lists& x, - const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), - const ::std::string& e = "UTF-8", - ::xml_schema::Flags f = 0); + void + serializeResourceLists (::std::ostream& os, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); - void - serializeResource_lists (::std::ostream& os, - const ::resource_lists::Resource_lists& x, - ::xml_schema::ErrorHandler& eh, - const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), - const ::std::string& e = "UTF-8", - ::xml_schema::Flags f = 0); + void + serializeResourceLists (::std::ostream& os, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& eh, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); - void - serializeResource_lists (::std::ostream& os, - const ::resource_lists::Resource_lists& x, - ::xercesc::DOMErrorHandler& eh, - const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), - const ::std::string& e = "UTF-8", - ::xml_schema::Flags f = 0); + void + serializeResourceLists (::std::ostream& os, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, + ::xercesc::DOMErrorHandler& eh, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); - // Serialize to xercesc::XMLFormatTarget. - // + // Serialize to xercesc::XMLFormatTarget. + // - void - serializeResource_lists (::xercesc::XMLFormatTarget& ft, - const ::resource_lists::Resource_lists& x, - const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), - const ::std::string& e = "UTF-8", - ::xml_schema::Flags f = 0); + void + serializeResourceLists (::xercesc::XMLFormatTarget& ft, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); - void - serializeResource_lists (::xercesc::XMLFormatTarget& ft, - const ::resource_lists::Resource_lists& x, - ::xml_schema::ErrorHandler& eh, - const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), - const ::std::string& e = "UTF-8", - ::xml_schema::Flags f = 0); + void + serializeResourceLists (::xercesc::XMLFormatTarget& ft, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, + ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& eh, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); - void - serializeResource_lists (::xercesc::XMLFormatTarget& ft, - const ::resource_lists::Resource_lists& x, - ::xercesc::DOMErrorHandler& eh, - const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), - const ::std::string& e = "UTF-8", - ::xml_schema::Flags f = 0); + void + serializeResourceLists (::xercesc::XMLFormatTarget& ft, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, + ::xercesc::DOMErrorHandler& eh, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), + const ::std::string& e = "UTF-8", + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); - // Serialize to an existing xercesc::DOMDocument. - // + // Serialize to an existing xercesc::DOMDocument. + // - void - serializeResource_lists (::xercesc::DOMDocument& d, - const ::resource_lists::Resource_lists& x, - ::xml_schema::Flags f = 0); + void + serializeResourceLists (::xercesc::DOMDocument& d, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); - // Serialize to a new xercesc::DOMDocument. - // + // Serialize to a new xercesc::DOMDocument. + // - ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > - serializeResource_lists (const ::resource_lists::Resource_lists& x, - const ::xml_schema::NamespaceInfomap& m = ::xml_schema::NamespaceInfomap (), - ::xml_schema::Flags f = 0); + ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > + serializeResourceLists (const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, + const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); - void - operator<< (::xercesc::DOMElement&, const Display_nameType&); + void + operator<< (::xercesc::DOMElement&, const DisplayNameType&); - void - operator<< (::xercesc::DOMElement&, const List&); + void + operator<< (::xercesc::DOMElement&, const List&); - void - operator<< (::xercesc::DOMElement&, const Display_name&); + void + operator<< (::xercesc::DOMElement&, const DisplayName&); - void - operator<< (::xercesc::DOMElement&, const Resource_lists&); + void + operator<< (::xercesc::DOMElement&, const ResourceLists&); + } + } } #include // Begin epilogue. // - #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic pop #endif - // // End epilogue. diff --git a/src/xml/xml.cpp b/src/xml/xml.cpp index 68e991eb8..b691c35cf 100644 --- a/src/xml/xml.cpp +++ b/src/xml/xml.cpp @@ -33,12 +33,10 @@ // Begin prologue. // - #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsuggest-override" #endif - // // End prologue. @@ -53,21 +51,21 @@ namespace namespace_ Lang:: Lang (const char* s) - : ::xml_schema::String (s) + : ::LinphonePrivate::Xsd::XmlSchema::String (s) { } Lang:: Lang (const ::std::string& s) - : ::xml_schema::String (s) + : ::LinphonePrivate::Xsd::XmlSchema::String (s) { } Lang:: Lang (const Lang& o, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (o, f, c) + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (o, f, c) { } @@ -76,41 +74,41 @@ namespace namespace_ Space:: Space (Value v) - : ::xml_schema::Ncname (_xsd_Space_literals_[v]) + : ::LinphonePrivate::Xsd::XmlSchema::Ncname (_xsd_Space_literals_[v]) { } Space:: Space (const char* v) - : ::xml_schema::Ncname (v) + : ::LinphonePrivate::Xsd::XmlSchema::Ncname (v) { } Space:: Space (const ::std::string& v) - : ::xml_schema::Ncname (v) + : ::LinphonePrivate::Xsd::XmlSchema::Ncname (v) { } Space:: - Space (const ::xml_schema::Ncname& v) - : ::xml_schema::Ncname (v) + Space (const ::LinphonePrivate::Xsd::XmlSchema::Ncname& v) + : ::LinphonePrivate::Xsd::XmlSchema::Ncname (v) { } Space:: Space (const Space& v, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Ncname (v, f, c) + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Ncname (v, f, c) { } Space& Space:: operator= (Value v) { - static_cast< ::xml_schema::Ncname& > (*this) = - ::xml_schema::Ncname (_xsd_Space_literals_[v]); + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Ncname& > (*this) = + ::LinphonePrivate::Xsd::XmlSchema::Ncname (_xsd_Space_literals_[v]); return *this; } @@ -121,41 +119,41 @@ namespace namespace_ Lang_member:: Lang_member (Value v) - : ::xml_schema::String (_xsd_Lang_member_literals_[v]) + : ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_Lang_member_literals_[v]) { } Lang_member:: Lang_member (const char* v) - : ::xml_schema::String (v) + : ::LinphonePrivate::Xsd::XmlSchema::String (v) { } Lang_member:: Lang_member (const ::std::string& v) - : ::xml_schema::String (v) + : ::LinphonePrivate::Xsd::XmlSchema::String (v) { } Lang_member:: - Lang_member (const ::xml_schema::String& v) - : ::xml_schema::String (v) + Lang_member (const ::LinphonePrivate::Xsd::XmlSchema::String& v) + : ::LinphonePrivate::Xsd::XmlSchema::String (v) { } Lang_member:: Lang_member (const Lang_member& v, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (v, f, c) + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (v, f, c) { } Lang_member& Lang_member:: operator= (Value v) { - static_cast< ::xml_schema::String& > (*this) = - ::xml_schema::String (_xsd_Lang_member_literals_[v]); + static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = + ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_Lang_member_literals_[v]); return *this; } @@ -172,32 +170,32 @@ namespace namespace_ Lang:: Lang (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (e, f, c) + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (e, f, c) { } Lang:: Lang (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (a, f, c) + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (a, f, c) { } Lang:: Lang (const ::std::string& s, const ::xercesc::DOMElement* e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (s, e, f, c) + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (s, e, f, c) { } Lang* Lang:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const { return new class Lang (*this, f, c); } @@ -207,18 +205,18 @@ namespace namespace_ Space:: Space (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Ncname (e, f, c) + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Ncname (e, f, c) { _xsd_Space_convert (); } Space:: Space (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Ncname (a, f, c) + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Ncname (a, f, c) { _xsd_Space_convert (); } @@ -226,16 +224,16 @@ namespace namespace_ Space:: Space (const ::std::string& s, const ::xercesc::DOMElement* e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::Ncname (s, e, f, c) + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::Ncname (s, e, f, c) { _xsd_Space_convert (); } Space* Space:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const { return new class Space (*this, f, c); } @@ -277,18 +275,18 @@ namespace namespace_ Lang_member:: Lang_member (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (e, f, c) + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (e, f, c) { _xsd_Lang_member_convert (); } Lang_member:: Lang_member (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (a, f, c) + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (a, f, c) { _xsd_Lang_member_convert (); } @@ -296,16 +294,16 @@ namespace namespace_ Lang_member:: Lang_member (const ::std::string& s, const ::xercesc::DOMElement* e, - ::xml_schema::Flags f, - ::xml_schema::Container* c) - : ::xml_schema::String (s, e, f, c) + ::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) + : ::LinphonePrivate::Xsd::XmlSchema::String (s, e, f, c) { _xsd_Lang_member_convert (); } Lang_member* Lang_member:: - _clone (::xml_schema::Flags f, - ::xml_schema::Container* c) const + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f, + ::LinphonePrivate::Xsd::XmlSchema::Container* c) const { return new class Lang_member (*this, f, c); } @@ -348,7 +346,7 @@ namespace namespace_ ::std::ostream& operator<< (::std::ostream& o, const Lang& i) { - return o << static_cast< const ::xml_schema::String& > (i); + return o << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); } ::std::ostream& @@ -360,7 +358,7 @@ namespace namespace_ ::std::ostream& operator<< (::std::ostream& o, const Space& i) { - return o << static_cast< const ::xml_schema::Ncname& > (i); + return o << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Ncname& > (i); } ::std::ostream& @@ -372,7 +370,7 @@ namespace namespace_ ::std::ostream& operator<< (::std::ostream& o, const Lang_member& i) { - return o << static_cast< const ::xml_schema::String& > (i); + return o << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); } } @@ -393,58 +391,58 @@ namespace namespace_ void operator<< (::xercesc::DOMElement& e, const Lang& i) { - e << static_cast< const ::xml_schema::String& > (i); + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); } void operator<< (::xercesc::DOMAttr& a, const Lang& i) { - a << static_cast< const ::xml_schema::String& > (i); + a << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); } void - operator<< (::xml_schema::ListStream& l, + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream& l, const Lang& i) { - l << static_cast< const ::xml_schema::String& > (i); + l << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); } void operator<< (::xercesc::DOMElement& e, const Space& i) { - e << static_cast< const ::xml_schema::Ncname& > (i); + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Ncname& > (i); } void operator<< (::xercesc::DOMAttr& a, const Space& i) { - a << static_cast< const ::xml_schema::Ncname& > (i); + a << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Ncname& > (i); } void - operator<< (::xml_schema::ListStream& l, + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream& l, const Space& i) { - l << static_cast< const ::xml_schema::Ncname& > (i); + l << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::Ncname& > (i); } void operator<< (::xercesc::DOMElement& e, const Lang_member& i) { - e << static_cast< const ::xml_schema::String& > (i); + e << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); } void operator<< (::xercesc::DOMAttr& a, const Lang_member& i) { - a << static_cast< const ::xml_schema::String& > (i); + a << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); } void - operator<< (::xml_schema::ListStream& l, + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream& l, const Lang_member& i) { - l << static_cast< const ::xml_schema::String& > (i); + l << static_cast< const ::LinphonePrivate::Xsd::XmlSchema::String& > (i); } } @@ -452,11 +450,9 @@ namespace namespace_ // Begin epilogue. // - #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic pop #endif - // // End epilogue. diff --git a/src/xml/xml.h b/src/xml/xml.h index 54ad50e8c..0f1554543 100644 --- a/src/xml/xml.h +++ b/src/xml/xml.h @@ -48,12 +48,10 @@ // Begin prologue. // - #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsuggest-override" #endif - // // End prologue. @@ -106,155 +104,161 @@ #include -namespace xml_schema +namespace LinphonePrivate { - // anyType and anySimpleType. - // - typedef ::xsd::cxx::tree::type Type; - typedef ::xsd::cxx::tree::simple_type< char, Type > SimpleType; - typedef ::xsd::cxx::tree::type Container; - - // 8-bit - // - typedef signed char Byte; - typedef unsigned char UnsignedByte; - - // 16-bit - // - typedef short Short; - typedef unsigned short UnsignedShort; - - // 32-bit - // - typedef int Int; - typedef unsigned int UnsignedInt; - - // 64-bit - // - typedef long long Long; - typedef unsigned long long UnsignedLong; - - // Supposed to be arbitrary-length integral types. - // - typedef long long Integer; - typedef long long NonPositiveInteger; - typedef unsigned long long NonNegativeInteger; - typedef unsigned long long PositiveInteger; - typedef long long NegativeInteger; - - // Boolean. - // - typedef bool Boolean; - - // Floating-point types. - // - typedef float Float; - typedef double Double; - typedef double Decimal; - - // String types. - // - typedef ::xsd::cxx::tree::string< char, SimpleType > String; - typedef ::xsd::cxx::tree::normalized_string< char, String > NormalizedString; - typedef ::xsd::cxx::tree::token< char, NormalizedString > Token; - typedef ::xsd::cxx::tree::name< char, Token > Name; - typedef ::xsd::cxx::tree::nmtoken< char, Token > Nmtoken; - typedef ::xsd::cxx::tree::nmtokens< char, SimpleType, Nmtoken > Nmtokens; - typedef ::xsd::cxx::tree::ncname< char, Name > Ncname; - typedef ::xsd::cxx::tree::language< char, Token > Language; - - // ID/IDREF. - // - typedef ::xsd::cxx::tree::id< char, Ncname > Id; - typedef ::xsd::cxx::tree::idref< char, Ncname, Type > Idref; - typedef ::xsd::cxx::tree::idrefs< char, SimpleType, Idref > Idrefs; - - // URI. - // - typedef ::xsd::cxx::tree::uri< char, SimpleType > Uri; - - // Qualified name. - // - typedef ::xsd::cxx::tree::qname< char, SimpleType, Uri, Ncname > Qname; - - // Binary. - // - typedef ::xsd::cxx::tree::buffer< char > Buffer; - typedef ::xsd::cxx::tree::base64_binary< char, SimpleType > Base64Binary; - typedef ::xsd::cxx::tree::hex_binary< char, SimpleType > HexBinary; - - // Date/time. - // - typedef ::xsd::cxx::tree::time_zone TimeZone; - typedef ::xsd::cxx::tree::date< char, SimpleType > Date; - typedef ::xsd::cxx::tree::date_time< char, SimpleType > DateTime; - typedef ::xsd::cxx::tree::duration< char, SimpleType > Duration; - typedef ::xsd::cxx::tree::gday< char, SimpleType > Gday; - typedef ::xsd::cxx::tree::gmonth< char, SimpleType > Gmonth; - typedef ::xsd::cxx::tree::gmonth_day< char, SimpleType > GmonthDay; - typedef ::xsd::cxx::tree::gyear< char, SimpleType > Gyear; - typedef ::xsd::cxx::tree::gyear_month< char, SimpleType > GyearMonth; - typedef ::xsd::cxx::tree::time< char, SimpleType > Time; - - // Entity. - // - typedef ::xsd::cxx::tree::entity< char, Ncname > Entity; - typedef ::xsd::cxx::tree::entities< char, SimpleType, Entity > Entities; - - typedef ::xsd::cxx::tree::content_order ContentOrder; - // Namespace information and list stream. Used in - // serialization functions. - // - typedef ::xsd::cxx::xml::dom::namespace_info< char > NamespaceInfo; - typedef ::xsd::cxx::xml::dom::namespace_infomap< char > NamespaceInfomap; - typedef ::xsd::cxx::tree::list_stream< char > ListStream; - typedef ::xsd::cxx::tree::as_double< Double > AsDouble; - typedef ::xsd::cxx::tree::as_decimal< Decimal > AsDecimal; - typedef ::xsd::cxx::tree::facet Facet; - - // Flags and properties. - // - typedef ::xsd::cxx::tree::flags Flags; - typedef ::xsd::cxx::tree::properties< char > Properties; - - // Parsing/serialization diagnostics. - // - typedef ::xsd::cxx::tree::severity Severity; - typedef ::xsd::cxx::tree::error< char > Error; - typedef ::xsd::cxx::tree::diagnostics< char > Diagnostics; - - // Exceptions. - // - typedef ::xsd::cxx::tree::exception< char > Exception; - typedef ::xsd::cxx::tree::bounds< char > Bounds; - typedef ::xsd::cxx::tree::duplicate_id< char > DuplicateId; - typedef ::xsd::cxx::tree::parsing< char > Parsing; - typedef ::xsd::cxx::tree::expected_element< char > ExpectedElement; - typedef ::xsd::cxx::tree::unexpected_element< char > UnexpectedElement; - typedef ::xsd::cxx::tree::expected_attribute< char > ExpectedAttribute; - typedef ::xsd::cxx::tree::unexpected_enumerator< char > UnexpectedEnumerator; - typedef ::xsd::cxx::tree::expected_text_content< char > ExpectedTextContent; - typedef ::xsd::cxx::tree::no_prefix_mapping< char > NoPrefixMapping; - typedef ::xsd::cxx::tree::serialization< char > Serialization; - - // Error handler callback interface. - // - typedef ::xsd::cxx::xml::error_handler< char > ErrorHandler; - - // DOM interaction. - // - namespace dom + namespace Xsd { - // Automatic pointer for DOMDocument. - // - using ::xsd::cxx::xml::dom::unique_ptr; + namespace XmlSchema + { + // anyType and anySimpleType. + // + typedef ::xsd::cxx::tree::type Type; + typedef ::xsd::cxx::tree::simple_type< char, Type > SimpleType; + typedef ::xsd::cxx::tree::type Container; -#ifndef XSD_CXX_TREE_TREE_NODE_KEY__XML_SCHEMA -#define XSD_CXX_TREE_TREE_NODE_KEY__XML_SCHEMA - // DOM user data key for back pointers to tree nodes. - // - const XMLCh* const treeNodeKey = ::xsd::cxx::tree::user_data_keys::node; + // 8-bit + // + typedef signed char Byte; + typedef unsigned char UnsignedByte; + + // 16-bit + // + typedef short Short; + typedef unsigned short UnsignedShort; + + // 32-bit + // + typedef int Int; + typedef unsigned int UnsignedInt; + + // 64-bit + // + typedef long long Long; + typedef unsigned long long UnsignedLong; + + // Supposed to be arbitrary-length integral types. + // + typedef long long Integer; + typedef long long NonPositiveInteger; + typedef unsigned long long NonNegativeInteger; + typedef unsigned long long PositiveInteger; + typedef long long NegativeInteger; + + // Boolean. + // + typedef bool Boolean; + + // Floating-point types. + // + typedef float Float; + typedef double Double; + typedef double Decimal; + + // String types. + // + typedef ::xsd::cxx::tree::string< char, SimpleType > String; + typedef ::xsd::cxx::tree::normalized_string< char, String > NormalizedString; + typedef ::xsd::cxx::tree::token< char, NormalizedString > Token; + typedef ::xsd::cxx::tree::name< char, Token > Name; + typedef ::xsd::cxx::tree::nmtoken< char, Token > Nmtoken; + typedef ::xsd::cxx::tree::nmtokens< char, SimpleType, Nmtoken > Nmtokens; + typedef ::xsd::cxx::tree::ncname< char, Name > Ncname; + typedef ::xsd::cxx::tree::language< char, Token > Language; + + // ID/IDREF. + // + typedef ::xsd::cxx::tree::id< char, Ncname > Id; + typedef ::xsd::cxx::tree::idref< char, Ncname, Type > Idref; + typedef ::xsd::cxx::tree::idrefs< char, SimpleType, Idref > Idrefs; + + // URI. + // + typedef ::xsd::cxx::tree::uri< char, SimpleType > Uri; + + // Qualified name. + // + typedef ::xsd::cxx::tree::qname< char, SimpleType, Uri, Ncname > Qname; + + // Binary. + // + typedef ::xsd::cxx::tree::buffer< char > Buffer; + typedef ::xsd::cxx::tree::base64_binary< char, SimpleType > Base64Binary; + typedef ::xsd::cxx::tree::hex_binary< char, SimpleType > HexBinary; + + // Date/time. + // + typedef ::xsd::cxx::tree::time_zone TimeZone; + typedef ::xsd::cxx::tree::date< char, SimpleType > Date; + typedef ::xsd::cxx::tree::date_time< char, SimpleType > DateTime; + typedef ::xsd::cxx::tree::duration< char, SimpleType > Duration; + typedef ::xsd::cxx::tree::gday< char, SimpleType > Gday; + typedef ::xsd::cxx::tree::gmonth< char, SimpleType > Gmonth; + typedef ::xsd::cxx::tree::gmonth_day< char, SimpleType > GmonthDay; + typedef ::xsd::cxx::tree::gyear< char, SimpleType > Gyear; + typedef ::xsd::cxx::tree::gyear_month< char, SimpleType > GyearMonth; + typedef ::xsd::cxx::tree::time< char, SimpleType > Time; + + // Entity. + // + typedef ::xsd::cxx::tree::entity< char, Ncname > Entity; + typedef ::xsd::cxx::tree::entities< char, SimpleType, Entity > Entities; + + typedef ::xsd::cxx::tree::content_order ContentOrder; + // Namespace information and list stream. Used in + // serialization functions. + // + typedef ::xsd::cxx::xml::dom::namespace_info< char > NamespaceInfo; + typedef ::xsd::cxx::xml::dom::namespace_infomap< char > NamespaceInfomap; + typedef ::xsd::cxx::tree::list_stream< char > ListStream; + typedef ::xsd::cxx::tree::as_double< Double > AsDouble; + typedef ::xsd::cxx::tree::as_decimal< Decimal > AsDecimal; + typedef ::xsd::cxx::tree::facet Facet; + + // Flags and properties. + // + typedef ::xsd::cxx::tree::flags Flags; + typedef ::xsd::cxx::tree::properties< char > Properties; + + // Parsing/serialization diagnostics. + // + typedef ::xsd::cxx::tree::severity Severity; + typedef ::xsd::cxx::tree::error< char > Error; + typedef ::xsd::cxx::tree::diagnostics< char > Diagnostics; + + // Exceptions. + // + typedef ::xsd::cxx::tree::exception< char > Exception; + typedef ::xsd::cxx::tree::bounds< char > Bounds; + typedef ::xsd::cxx::tree::duplicate_id< char > DuplicateId; + typedef ::xsd::cxx::tree::parsing< char > Parsing; + typedef ::xsd::cxx::tree::expected_element< char > ExpectedElement; + typedef ::xsd::cxx::tree::unexpected_element< char > UnexpectedElement; + typedef ::xsd::cxx::tree::expected_attribute< char > ExpectedAttribute; + typedef ::xsd::cxx::tree::unexpected_enumerator< char > UnexpectedEnumerator; + typedef ::xsd::cxx::tree::expected_text_content< char > ExpectedTextContent; + typedef ::xsd::cxx::tree::no_prefix_mapping< char > NoPrefixMapping; + typedef ::xsd::cxx::tree::serialization< char > Serialization; + + // Error handler callback interface. + // + typedef ::xsd::cxx::xml::error_handler< char > ErrorHandler; + + // DOM interaction. + // + namespace dom + { + // Automatic pointer for DOMDocument. + // + using ::xsd::cxx::xml::dom::unique_ptr; + +#ifndef XSD_CXX_TREE_TREE_NODE_KEY__LINPHONEPRIVATE__XSD__XMLSCHEMA +#define XSD_CXX_TREE_TREE_NODE_KEY__LINPHONEPRIVATE__XSD__XMLSCHEMA + // DOM user data key for back pointers to tree nodes. + // + const XMLCh* const treeNodeKey = ::xsd::cxx::tree::user_data_keys::node; #endif + } + } } } @@ -286,7 +290,7 @@ namespace namespace_ namespace namespace_ { - class Lang: public ::xml_schema::String + class Lang: public ::LinphonePrivate::Xsd::XmlSchema::String { public: @@ -295,28 +299,28 @@ namespace namespace_ Lang (const ::std::string& v); Lang (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); Lang (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); Lang (const ::std::string& s, const ::xercesc::DOMElement* e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); Lang (const Lang& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); virtual Lang* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; }; - class Space: public ::xml_schema::Ncname + class Space: public ::LinphonePrivate::Xsd::XmlSchema::Ncname { public: enum Value @@ -331,28 +335,28 @@ namespace namespace_ Space (const ::std::string& v); - Space (const ::xml_schema::Ncname& v); + Space (const ::LinphonePrivate::Xsd::XmlSchema::Ncname& v); Space (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); Space (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); Space (const ::std::string& s, const ::xercesc::DOMElement* e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); Space (const Space& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); virtual Space* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; Space& operator= (Value v); @@ -372,7 +376,7 @@ namespace namespace_ static const Value _xsd_Space_indexes_[2]; }; - class Lang_member: public ::xml_schema::String + class Lang_member: public ::LinphonePrivate::Xsd::XmlSchema::String { public: enum Value @@ -386,28 +390,28 @@ namespace namespace_ Lang_member (const ::std::string& v); - Lang_member (const ::xml_schema::String& v); + Lang_member (const ::LinphonePrivate::Xsd::XmlSchema::String& v); Lang_member (const ::xercesc::DOMElement& e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); Lang_member (const ::xercesc::DOMAttr& a, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); Lang_member (const ::std::string& s, const ::xercesc::DOMElement* e, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); Lang_member (const Lang_member& x, - ::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0); + ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0); virtual Lang_member* - _clone (::xml_schema::Flags f = 0, - ::xml_schema::Container* c = 0) const; + _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, + ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; Lang_member& operator= (Value v); @@ -475,7 +479,7 @@ namespace namespace_ operator<< (::xercesc::DOMAttr&, const Lang&); void - operator<< (::xml_schema::ListStream&, + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream&, const Lang&); void @@ -485,7 +489,7 @@ namespace namespace_ operator<< (::xercesc::DOMAttr&, const Space&); void - operator<< (::xml_schema::ListStream&, + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream&, const Space&); void @@ -495,7 +499,7 @@ namespace namespace_ operator<< (::xercesc::DOMAttr&, const Lang_member&); void - operator<< (::xml_schema::ListStream&, + operator<< (::LinphonePrivate::Xsd::XmlSchema::ListStream&, const Lang_member&); } @@ -503,11 +507,9 @@ namespace namespace_ // Begin epilogue. // - #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic pop #endif - // // End epilogue. From f9669959754f810b7c263272fdb2681e4757d744 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 20 Sep 2017 17:38:30 +0200 Subject: [PATCH 0105/2215] Fix missing symbols at link. --- src/conference/local-conference.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h index 30e64229b..eec26e1ef 100644 --- a/src/conference/local-conference.h +++ b/src/conference/local-conference.h @@ -36,13 +36,7 @@ public: public: /* ConferenceInterface */ std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; - void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia) override; - bool canHandleParticipants () const override; - const std::string& getId () const override; - int getNbParticipants () const override; - std::list> getParticipants () const override; void removeParticipant (const std::shared_ptr &participant) override; - void removeParticipants (const std::list> &participants) override; private: L_DISABLE_COPY(LocalConference); From 5e4cb463db81f4ed97f42a60ad2ddcfa213e502a Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 20 Sep 2017 19:40:22 +0200 Subject: [PATCH 0106/2215] feat(c-tools): remove C_TYPE parameter of L_GET_CPP_PTR_FROM_C_STRUCT --- coreapi/chat.c | 14 ++++++------ coreapi/chat_file_transfer.c | 28 ++++++++++++------------ coreapi/linphonecall.c | 14 ++++++------ coreapi/linphonecore.c | 4 ++-- coreapi/proxy.c | 6 ++--- src/c-wrapper/api/c-call-params.cpp | 10 ++++----- src/c-wrapper/api/c-chat-message.cpp | 4 ++-- src/c-wrapper/api/c-chat-room.cpp | 26 +++++++++++----------- src/c-wrapper/api/c-event-log.cpp | 10 ++++----- src/c-wrapper/api/c-participant.cpp | 10 ++++----- src/c-wrapper/c-tools.h | 21 +++++++++++------- src/chat/chat-room.cpp | 2 +- src/conference/session/call-session.cpp | 4 ++-- src/conference/session/media-session.cpp | 8 +++++-- 14 files changed, 85 insertions(+), 76 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 62b708293..5ab6d9924 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -100,7 +100,7 @@ static LinphoneChatRoom *_linphone_core_create_chat_room_from_url(LinphoneCore * } static bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from) { - LinphoneAddress *addr = linphone_address_new(L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)->getPeerAddress().asString().c_str()); + LinphoneAddress *addr = linphone_address_new(L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom)->getPeerAddress().asString().c_str()); bool_t result = linphone_address_weak_equal(addr, from); linphone_address_unref(addr); return result; @@ -166,7 +166,7 @@ void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMe linphone_chat_message_store_state(msg); if (msg->state == LinphoneChatMessageStateDelivered || msg->state == LinphoneChatMessageStateNotDelivered) { - L_GET_PRIVATE_FROM_C_STRUCT(msg->chat_room, ChatRoom, ChatRoom)->moveTransientMessageToWeakMessages(msg); + L_GET_PRIVATE_FROM_C_STRUCT(msg->chat_room, ChatRoom)->moveTransientMessageToWeakMessages(msg); } } @@ -253,7 +253,7 @@ int linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage LinphoneAddress *addr = linphone_address_new(sal_msg->from); linphone_address_clean(addr); LinphoneChatRoom *cr = linphone_core_get_chat_room(lc, addr); - LinphoneReason reason = L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)->messageReceived(op, sal_msg); + LinphoneReason reason = L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom)->messageReceived(op, sal_msg); linphone_address_unref(addr); return reason; } @@ -269,7 +269,7 @@ void _linphone_chat_message_resend(LinphoneChatMessage *msg, bool_t ref_msg) { cr = linphone_chat_message_get_chat_room(msg); if (ref_msg) linphone_chat_message_ref(msg); - L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)->sendMessage(msg); + L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom)->sendMessage(msg); } void linphone_chat_message_resend(LinphoneChatMessage *msg) { @@ -385,7 +385,7 @@ static char *linphone_chat_message_create_imdn_xml(LinphoneChatMessage *cm, Imdn void linphone_chat_message_send_imdn(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason) { char *content = linphone_chat_message_create_imdn_xml(cm, imdn_type, reason); if (content) { - L_GET_PRIVATE_FROM_C_STRUCT(linphone_chat_message_get_chat_room(cm), ChatRoom, ChatRoom)->sendImdn(content, reason); + L_GET_PRIVATE_FROM_C_STRUCT(linphone_chat_message_get_chat_room(cm), ChatRoom)->sendImdn(content, reason); ms_free(content); } } @@ -411,7 +411,7 @@ void linphone_chat_message_send_display_notification(LinphoneChatMessage *cm) { void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, uint32_t character, LinphoneCall *call) { if (linphone_core_realtime_text_enabled(lc)) { std::shared_ptr rttcr = - std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)); + std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom)); L_GET_PRIVATE(rttcr)->realtimeTextReceived(character, call); //L_GET_PRIVATE(std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)))->realtimeTextReceived(character, call); } @@ -421,7 +421,7 @@ LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg, uint32_t LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) { std::shared_ptr rttcr = - std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)); + std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom)); LinphoneCall *call = rttcr->getCall(); LinphoneCore *lc = rttcr->getCore(); const uint32_t new_line = 0x2028; diff --git a/coreapi/chat_file_transfer.c b/coreapi/chat_file_transfer.c index 0fb84a566..d85901721 100644 --- a/coreapi/chat_file_transfer.c +++ b/coreapi/chat_file_transfer.c @@ -131,7 +131,7 @@ static int on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t * linphone_core_notify_file_transfer_send(lc, msg, msg->file_transfer_information, (char *)buffer, size); } } - + imee = linphone_core_get_im_encryption_engine(lc); if (imee) { LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); @@ -158,7 +158,7 @@ static void on_send_end(belle_sip_user_body_handler_t *bh, void *data) { LinphoneChatMessage *msg = (LinphoneChatMessage *)data; LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room); LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); - + if (imee) { LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); @@ -210,7 +210,7 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(linphone_chat_room_get_core(msg->chat_room)); if (imee) { LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer_cb = + LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer_cb = linphone_im_encryption_engine_cbs_get_is_encryption_enabled_for_file_transfer(imee_cbs); if (is_encryption_enabled_for_file_transfer_cb) { is_file_encryption_enabled = is_encryption_enabled_for_file_transfer_cb(imee, msg->chat_room); @@ -219,7 +219,7 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co /* shall we encrypt the file */ if (is_file_encryption_enabled) { LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb generate_file_transfer_key_cb = + LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb generate_file_transfer_key_cb = linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(imee_cbs); if (generate_file_transfer_key_cb) { generate_file_transfer_key_cb(imee, msg->chat_room, msg); @@ -237,12 +237,12 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co /* create a user body handler to take care of the file and add the content disposition and content-type * headers */ first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new( - linphone_content_get_size(msg->file_transfer_information), + linphone_content_get_size(msg->file_transfer_information), linphone_chat_message_file_transfer_on_progress, NULL, NULL, on_send_body, on_send_end, msg); if (msg->file_transfer_filepath != NULL) { belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh; - first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(msg->file_transfer_filepath, + first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(msg->file_transfer_filepath, NULL, msg); // No need to add again the callback for progression, otherwise it will be called twice linphone_content_set_size(msg->file_transfer_information, belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh)); belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)first_part_bh, body_handler); @@ -251,7 +251,7 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co linphone_content_get_buffer(msg->file_transfer_information), linphone_content_get_size(msg->file_transfer_information), linphone_chat_message_file_transfer_on_progress, msg); } - + belle_sip_body_handler_add_header(first_part_bh, belle_sip_header_create("Content-disposition", first_part_header)); belle_sip_free(first_part_header); @@ -341,7 +341,7 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co linphone_chat_message_ref(msg); linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone); _release_http_request(msg); - L_GET_CPP_PTR_FROM_C_STRUCT(msg->chat_room, ChatRoom, ChatRoom)->sendMessage(msg); + L_GET_CPP_PTR_FROM_C_STRUCT(msg->chat_room, ChatRoom)->sendMessage(msg); file_upload_end_background_task(msg); linphone_chat_message_unref(msg); } else { @@ -391,7 +391,7 @@ static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t if (size == 0) { return; } - + decrypted_buffer = (uint8_t *)ms_malloc0(size); imee = linphone_core_get_im_encryption_engine(lc); if (imee) { @@ -405,7 +405,7 @@ static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t } } ms_free(decrypted_buffer); - + if (retval <= 0) { if (msg->file_transfer_filepath == NULL) { if (linphone_chat_message_cbs_get_file_transfer_recv(msg->callbacks)) { @@ -430,7 +430,7 @@ static void on_recv_end(belle_sip_user_body_handler_t *bh, void *data) { LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room); LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); int retval = -1; - + if (imee) { LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); @@ -438,7 +438,7 @@ static void on_recv_end(belle_sip_user_body_handler_t *bh, void *data) { retval = cb_process_downloading_file(imee, msg, 0, NULL, 0, NULL); } } - + if (retval <= 0) { if (msg->file_transfer_filepath == NULL) { if (linphone_chat_message_cbs_get_file_transfer_recv(msg->callbacks)) { @@ -504,7 +504,7 @@ static void linphone_chat_process_response_headers_from_get_file(void *data, con body_size = linphone_content_get_size(msg->file_transfer_information); } - + body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, linphone_chat_message_file_transfer_on_progress, NULL, on_recv_body, NULL, on_recv_end, msg); if (msg->file_transfer_filepath != NULL) { belle_sip_user_body_handler_t *bh = (belle_sip_user_body_handler_t *)body_handler; @@ -657,5 +657,5 @@ const char *linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage } LinphoneChatMessage *linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent *initial_content) { - return L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)->createFileTransferMessage(initial_content); + return L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom)->createFileTransferMessage(initial_content); } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 27121210c..9f7dbbc25 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -289,8 +289,8 @@ LinphoneCall * linphone_call_new_outgoing(LinphoneCore *lc, const LinphoneAddres call->remoteParamsCache = linphone_call_params_new_for_wrapper(); call->remoteAddressCache = linphone_address_new(nullptr); call->call = std::make_shared(call, lc, LinphoneCallOutgoing, - *L_GET_CPP_PTR_FROM_C_STRUCT(from, Address, Address), *L_GET_CPP_PTR_FROM_C_STRUCT(to, Address, Address), - cfg, nullptr, L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams, CallParams)); + *L_GET_CPP_PTR_FROM_C_STRUCT(from, Address), *L_GET_CPP_PTR_FROM_C_STRUCT(to, Address), + cfg, nullptr, L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams)); return call; } @@ -301,7 +301,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, const LinphoneAddres call->remoteParamsCache = linphone_call_params_new_for_wrapper(); call->remoteAddressCache = linphone_address_new(nullptr); call->call = std::make_shared(call, lc, LinphoneCallIncoming, - *L_GET_CPP_PTR_FROM_C_STRUCT(from, Address, Address), *L_GET_CPP_PTR_FROM_C_STRUCT(to, Address, Address), + *L_GET_CPP_PTR_FROM_C_STRUCT(from, Address), *L_GET_CPP_PTR_FROM_C_STRUCT(to, Address), nullptr, op, nullptr); L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->initiateIncoming(); return call; @@ -1284,7 +1284,7 @@ LinphoneStatus linphone_call_accept(LinphoneCall *call) { } LinphoneStatus linphone_call_accept_with_params(LinphoneCall *call, const LinphoneCallParams *params) { - return linphone_call_get_cpp_obj(call)->accept(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams, CallParams) : nullptr); + return linphone_call_get_cpp_obj(call)->accept(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams) : nullptr); } LinphoneStatus linphone_call_accept_early_media(LinphoneCall* call) { @@ -1292,11 +1292,11 @@ LinphoneStatus linphone_call_accept_early_media(LinphoneCall* call) { } LinphoneStatus linphone_call_accept_early_media_with_params(LinphoneCall *call, const LinphoneCallParams *params) { - return linphone_call_get_cpp_obj(call)->acceptEarlyMedia(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams, CallParams) : nullptr); + return linphone_call_get_cpp_obj(call)->acceptEarlyMedia(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams) : nullptr); } LinphoneStatus linphone_call_update(LinphoneCall *call, const LinphoneCallParams *params) { - return linphone_call_get_cpp_obj(call)->update(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams, CallParams) : nullptr); + return linphone_call_get_cpp_obj(call)->update(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams) : nullptr); } int linphone_call_start_update(LinphoneCall *call) { @@ -1327,7 +1327,7 @@ int linphone_call_start_accept_update(LinphoneCall *call, LinphoneCallState next } LinphoneStatus linphone_call_accept_update(LinphoneCall *call, const LinphoneCallParams *params) { - return linphone_call_get_cpp_obj(call)->acceptUpdate(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams, CallParams) : nullptr); + return linphone_call_get_cpp_obj(call)->acceptUpdate(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams) : nullptr); } LinphoneStatus linphone_call_transfer(LinphoneCall *call, const char *refer_to) { diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 5a6a7e229..0bda10aae 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3368,7 +3368,7 @@ static bctbx_list_t *make_routes_for_proxy(LinphoneProxyConfig *proxy, const Lin ret=bctbx_list_append(ret,sal_address_new(local_route)); } if (srv_route){ - ret=bctbx_list_append(ret,sal_address_clone(L_GET_PRIVATE_FROM_C_STRUCT(srv_route, Address, Address)->getInternalAddress())); + ret=bctbx_list_append(ret,sal_address_clone(L_GET_PRIVATE_FROM_C_STRUCT(srv_route, Address)->getInternalAddress())); } if (ret==NULL){ /*if the proxy address matches the domain part of the destination, then use the same transport @@ -6681,7 +6681,7 @@ void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m) { } void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params) { - L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams, CallParams)->initDefault(lc); + L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams)->initDefault(lc); } void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) { diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 41fbf6144..5d6e72bb0 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -500,7 +500,7 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *cfg){ linphone_configure_op(cfg->lc, cfg->op, cfg->identity_address, cfg->sent_headers, FALSE); if ((contact=guess_contact_for_register(cfg))) { - sal_op_set_contact_address(cfg->op, L_GET_PRIVATE_FROM_C_STRUCT(contact, Address, Address)->getInternalAddress()); + sal_op_set_contact_address(cfg->op, L_GET_PRIVATE_FROM_C_STRUCT(contact, Address)->getInternalAddress()); linphone_address_unref(contact); } @@ -511,7 +511,7 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *cfg){ proxy_string, cfg->reg_identity, cfg->expires, - cfg->pending_contact ? L_GET_PRIVATE_FROM_C_STRUCT(cfg->pending_contact, Address, Address)->getInternalAddress() : NULL + cfg->pending_contact ? L_GET_PRIVATE_FROM_C_STRUCT(cfg->pending_contact, Address)->getInternalAddress() : NULL )==0) { if (cfg->pending_contact) { linphone_address_unref(cfg->pending_contact); @@ -1393,7 +1393,7 @@ const char* linphone_proxy_config_get_transport(const LinphoneProxyConfig *cfg) bool_t destroy_route_addr = FALSE; if (linphone_proxy_config_get_service_route(cfg)) { - route_addr = L_GET_PRIVATE_FROM_C_STRUCT(linphone_proxy_config_get_service_route(cfg), Address, Address)->getInternalAddress(); + route_addr = L_GET_PRIVATE_FROM_C_STRUCT(linphone_proxy_config_get_service_route(cfg), Address)->getInternalAddress(); } else if (linphone_proxy_config_get_route(cfg)) { addr=linphone_proxy_config_get_route(cfg); } else if(linphone_proxy_config_get_addr(cfg)) { diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index a51c3fead..3852a7343 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -29,9 +29,9 @@ // ============================================================================= #define GET_CALL_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, CallSessionParams, CallParams) -#define GET_CALL_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, CallSessionParams, CallParams) -#define GET_MEDIA_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, MediaSessionParams, CallParams) -#define GET_MEDIA_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, MediaSessionParams, CallParams) +#define GET_CALL_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, CallSessionParams) +#define GET_MEDIA_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, MediaSessionParams) +#define GET_MEDIA_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, MediaSessionParams) L_DECLARE_C_CLONABLE_STRUCT_IMPL(MediaSessionParams, CallParams, call_params) @@ -493,11 +493,11 @@ void linphone_call_params_set_no_user_consent (LinphoneCallParams *params, bool_ // ============================================================================= void *linphone_call_params_get_user_data (const LinphoneCallParams *cp) { - return L_GET_USER_DATA_FROM_C_STRUCT(cp, MediaSessionParams, CallParams); + return L_GET_USER_DATA_FROM_C_STRUCT(cp, MediaSessionParams); } void linphone_call_params_set_user_data (LinphoneCallParams *cp, void *ud) { - L_SET_USER_DATA_FROM_C_STRUCT(cp, ud, MediaSessionParams, CallParams); + L_SET_USER_DATA_FROM_C_STRUCT(cp, ud, MediaSessionParams); } LinphoneCallParams *linphone_call_params_ref (LinphoneCallParams *cp) { diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 67d14f173..1f8d1d8b4 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -47,9 +47,9 @@ void linphone_chat_message_unref (LinphoneChatMessage *msg) { } void * linphone_chat_message_get_user_data (const LinphoneChatMessage *msg) { - return L_GET_USER_DATA_FROM_C_STRUCT(msg, ChatMessage, ChatMessage); + return L_GET_USER_DATA_FROM_C_STRUCT(msg, ChatMessage); } void linphone_chat_message_set_user_data (LinphoneChatMessage *msg, void *ud) { - L_SET_USER_DATA_FROM_C_STRUCT(msg, ud, ChatMessage, ChatMessage); + L_SET_USER_DATA_FROM_C_STRUCT(msg, ud, ChatMessage); } diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index f7798f167..65bdf0232 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -32,8 +32,8 @@ // ============================================================================= -#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, ChatRoom, ChatRoom) -#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, ChatRoom, ChatRoom) +#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, ChatRoom) +#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, ChatRoom) using namespace std; @@ -211,7 +211,7 @@ LinphoneChatRoomCbs *linphone_chat_room_get_callbacks (const LinphoneChatRoom *c LinphoneParticipant *linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr) { return L_GET_C_BACK_PTR(GET_CPP_PTR(cr)->addParticipant( - *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address, Address), nullptr, false), + *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address), nullptr, false), Participant, participant); } @@ -237,7 +237,7 @@ bctbx_list_t *linphone_chat_room_get_participants (const LinphoneChatRoom *cr) { } void linphone_chat_room_remove_participant (LinphoneChatRoom *cr, LinphoneParticipant *participant) { - GET_CPP_PTR(cr)->removeParticipant(L_GET_CPP_PTR_FROM_C_STRUCT(participant, Participant, Participant)); + GET_CPP_PTR(cr)->removeParticipant(L_GET_CPP_PTR_FROM_C_STRUCT(participant, Participant)); } void linphone_chat_room_remove_participants (LinphoneChatRoom *cr, const bctbx_list_t *participants) { @@ -258,11 +258,11 @@ void linphone_chat_room_unref (LinphoneChatRoom *cr) { } void *linphone_chat_room_get_user_data (const LinphoneChatRoom *cr) { - return L_GET_USER_DATA_FROM_C_STRUCT(cr, ChatRoom, ChatRoom); + return L_GET_USER_DATA_FROM_C_STRUCT(cr, ChatRoom); } void linphone_chat_room_set_user_data (LinphoneChatRoom *cr, void *ud) { - L_SET_USER_DATA_FROM_C_STRUCT(cr, ud, ChatRoom, ChatRoom); + L_SET_USER_DATA_FROM_C_STRUCT(cr, ud, ChatRoom); } // ============================================================================= @@ -272,12 +272,12 @@ void linphone_chat_room_set_user_data (LinphoneChatRoom *cr, void *ud) { LinphoneChatRoom *linphone_chat_room_new (LinphoneCore *core, const LinphoneAddress *addr) { LinphoneChatRoom *cr = _linphone_chat_room_init(); if (linphone_core_realtime_text_enabled(core)) - L_SET_CPP_PTR_FROM_C_STRUCT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address, Address))); + L_SET_CPP_PTR_FROM_C_STRUCT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address))); else - L_SET_CPP_PTR_FROM_C_STRUCT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address, Address))); + L_SET_CPP_PTR_FROM_C_STRUCT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address))); linphone_core_notify_chat_room_instantiated(core, cr); - L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Instantiated); - L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Created); + L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Instantiated); + L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Created); return cr; } @@ -290,7 +290,7 @@ LinphoneChatRoom *linphone_client_group_chat_room_new (LinphoneCore *core, const linphone_address_unref(factoryAddr); std::string from; if (proxy) - from = L_GET_CPP_PTR_FROM_C_STRUCT(linphone_proxy_config_get_identity_address(proxy), Address, Address)->asString(); + from = L_GET_CPP_PTR_FROM_C_STRUCT(linphone_proxy_config_get_identity_address(proxy), Address)->asString(); if (from.empty()) from = linphone_core_get_primary_contact(core); LinphonePrivate::Address me(from); @@ -298,8 +298,8 @@ LinphoneChatRoom *linphone_client_group_chat_room_new (LinphoneCore *core, const LinphoneChatRoom *cr = _linphone_chat_room_init(); L_SET_CPP_PTR_FROM_C_STRUCT(cr, make_shared(core, me, l)); linphone_core_notify_chat_room_instantiated(core, cr); - L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Instantiated); - L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::CreationPending); + L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Instantiated); + L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::CreationPending); return cr; } diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index a1bd1a12f..4d07c6741 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -53,7 +53,7 @@ LinphoneEventLog *linphone_event_log_ref (LinphoneEventLog *event_log) { LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *event_log) { return static_cast( - L_GET_CPP_PTR_FROM_C_STRUCT(event_log, EventLog, EventLog)->getType() + L_GET_CPP_PTR_FROM_C_STRUCT(event_log, EventLog)->getType() ); } @@ -67,7 +67,7 @@ LinphoneCallEvent *linphone_call_event_new (LinphoneEventLogType type, LinphoneC call_event, new LINPHONE_NAMESPACE::CallEvent( static_cast(type), - L_GET_CPP_PTR_FROM_C_STRUCT(call, Call, Call) + L_GET_CPP_PTR_FROM_C_STRUCT(call, Call) ) ); return call_event; @@ -79,7 +79,7 @@ extern LinphoneCall *_linphone_call_init (); LinphoneCall *linphone_call_event_get_call (const LinphoneCallEvent *call_event) { return L_GET_C_BACK_PTR( L_GET_CPP_PTR_FROM_C_STRUCT( - call_event, CallEvent, CallEvent + call_event, CallEvent )->getCall(), Call, call @@ -132,7 +132,7 @@ LinphoneChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage * L_SET_CPP_PTR_FROM_C_STRUCT( chat_message_event, new LINPHONE_NAMESPACE::ChatMessageEvent( - L_GET_CPP_PTR_FROM_C_STRUCT(chat_message, ChatMessage, ChatMessage) + L_GET_CPP_PTR_FROM_C_STRUCT(chat_message, ChatMessage) ) ); return chat_message_event; @@ -144,7 +144,7 @@ extern LinphoneChatMessage *_linphone_chat_message_init (); LinphoneChatMessage *linphone_chat_message_event_get_chat_message (const LinphoneChatMessageEvent *chat_message_event) { return L_GET_C_BACK_PTR( L_GET_CPP_PTR_FROM_C_STRUCT( - chat_message_event, ChatMessageEvent, ChatMessageEvent + chat_message_event, ChatMessageEvent )->getChatMessage(), ChatMessage, chat_message diff --git a/src/c-wrapper/api/c-participant.cpp b/src/c-wrapper/api/c-participant.cpp index e91677e18..cd9956427 100644 --- a/src/c-wrapper/api/c-participant.cpp +++ b/src/c-wrapper/api/c-participant.cpp @@ -39,15 +39,15 @@ void linphone_participant_unref (LinphoneParticipant *participant) { } void *linphone_participant_get_user_data(const LinphoneParticipant *participant) { - return L_GET_USER_DATA_FROM_C_STRUCT(participant, Participant, Participant); + return L_GET_USER_DATA_FROM_C_STRUCT(participant, Participant); } void linphone_participant_set_user_data(LinphoneParticipant *participant, void *ud) { - L_SET_USER_DATA_FROM_C_STRUCT(participant, ud, Participant, Participant); + L_SET_USER_DATA_FROM_C_STRUCT(participant, ud, Participant); } const LinphoneAddress *linphone_participant_get_address (const LinphoneParticipant *participant) { - LinphonePrivate::Address addr = L_GET_CPP_PTR_FROM_C_STRUCT(participant, Participant, Participant)->getAddress(); + LinphonePrivate::Address addr = L_GET_CPP_PTR_FROM_C_STRUCT(participant, Participant)->getAddress(); if (participant->addressCache) linphone_address_unref(participant->addressCache); participant->addressCache = linphone_address_new(addr.asString().c_str()); @@ -55,9 +55,9 @@ const LinphoneAddress *linphone_participant_get_address (const LinphoneParticipa } bool_t linphone_participant_is_admin (const LinphoneParticipant *participant) { - return L_GET_CPP_PTR_FROM_C_STRUCT(participant, Participant, Participant)->isAdmin(); + return L_GET_CPP_PTR_FROM_C_STRUCT(participant, Participant)->isAdmin(); } void linphone_participant_set_admin (LinphoneParticipant *participant, bool_t value) { - L_GET_CPP_PTR_FROM_C_STRUCT(participant, Participant, Participant)->setAdmin(value); + L_GET_CPP_PTR_FROM_C_STRUCT(participant, Participant)->setAdmin(value); } diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index 1ec204c15..b81a56cdb 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -339,11 +339,16 @@ LINPHONE_END_NAMESPACE return object; \ } +// String conversions between C/C++. #define L_STRING_TO_C(STR) ((STR).empty() ? NULL : (STR).c_str()) #define L_C_TO_STRING(STR) ((STR) == NULL ? std::string() : (STR)) -#define L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE, C_TYPE) \ - LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC(OBJECT) +// Get the cpp-ptr from a wrapped C object. +#define L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE) \ + LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC< \ + LINPHONE_NAMESPACE::CPP_TYPE, \ + std::remove_pointer::type \ + >(OBJECT) #define L_SET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_PTR) \ LINPHONE_NAMESPACE::Wrapper::setCppPtrFromC(OBJECT, CPP_PTR) @@ -351,21 +356,21 @@ LINPHONE_END_NAMESPACE #define L_GET_PRIVATE(OBJECT) \ LINPHONE_NAMESPACE::Wrapper::getPrivate(OBJECT) -#define L_GET_PRIVATE_FROM_C_STRUCT(OBJECT, CPP_TYPE, C_TYPE) \ +#define L_GET_PRIVATE_FROM_C_STRUCT(OBJECT, CPP_TYPE) \ L_GET_PRIVATE(LINPHONE_NAMESPACE::Wrapper::getCppPtr( \ - L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE, C_TYPE) \ + L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE) \ )) #define L_GET_C_BACK_PTR(OBJECT, C_TYPE, C_NAME) \ LINPHONE_NAMESPACE::Wrapper::getCBackPtr(OBJECT, _linphone_ ## C_NAME ## _init) -#define L_GET_USER_DATA_FROM_C_STRUCT(OBJECT, CPP_TYPE, C_TYPE) \ +#define L_GET_USER_DATA_FROM_C_STRUCT(OBJECT, CPP_TYPE) \ LINPHONE_NAMESPACE::Wrapper::getUserData( \ - L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE, C_TYPE) \ + L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE) \ ) -#define L_SET_USER_DATA_FROM_C_STRUCT(OBJECT, VALUE, CPP_TYPE, C_TYPE) \ +#define L_SET_USER_DATA_FROM_C_STRUCT(OBJECT, VALUE, CPP_TYPE) \ LINPHONE_NAMESPACE::Wrapper::setUserData( \ - L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE, C_TYPE), \ + L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE), \ VALUE \ ) diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index b3aecbf5d..37c27da34 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -832,7 +832,7 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { if (identity.empty()) { LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(d->core, peer); if (proxy) { - identity = L_GET_CPP_PTR_FROM_C_STRUCT(linphone_proxy_config_get_identity_address(proxy), Address, Address)->asString(); + identity = L_GET_CPP_PTR_FROM_C_STRUCT(linphone_proxy_config_get_identity_address(proxy), Address)->asString(); } else { identity = linphone_core_get_primary_contact(d->core); } diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index b9643220c..fb00b8990 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -676,7 +676,7 @@ void CallSessionPrivate::setContactOp () { SalAddress *salAddress = nullptr; LinphoneAddress *contact = getFixedContact(); if (contact) { - salAddress = const_cast(L_GET_PRIVATE_FROM_C_STRUCT(contact, Address, Address)->getInternalAddress()); + salAddress = const_cast(L_GET_PRIVATE_FROM_C_STRUCT(contact, Address)->getInternalAddress()); sal_address_ref(salAddress); linphone_address_unref(contact); } @@ -1042,7 +1042,7 @@ const Address& CallSession::getRemoteAddress () const { L_D(const CallSession); return *L_GET_CPP_PTR_FROM_C_STRUCT((d->direction == LinphoneCallIncoming) ? linphone_call_log_get_from(d->log) : linphone_call_log_get_to(d->log), - Address, Address); + Address); } string CallSession::getRemoteAddressAsString () const { diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 0f6ee3556..49b90280a 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -1120,7 +1120,7 @@ void MediaSessionPrivate::selectOutgoingIpVersion () { } const LinphoneAddress *to = linphone_call_log_get_to_address(log); - if (sal_address_is_ipv6(L_GET_PRIVATE_FROM_C_STRUCT(to, Address, Address)->getInternalAddress())) + if (sal_address_is_ipv6(L_GET_PRIVATE_FROM_C_STRUCT(to, Address)->getInternalAddress())) af = AF_INET6; else if (destProxy && destProxy->op) af = sal_op_get_address_family(destProxy->op); @@ -1232,7 +1232,11 @@ void MediaSessionPrivate::makeLocalMediaDescription () { md->nb_streams = (biggestDesc ? biggestDesc->nb_streams : 1); /* Re-check local ip address each time we make a new offer, because it may change in case of network reconnection */ - getLocalIp(*L_GET_CPP_PTR_FROM_C_STRUCT((direction == LinphoneCallOutgoing) ? log->to : log->from, Address, Address)); + { + LinphoneAddress *address = (direction == LinphoneCallOutgoing ? log->to : log->from); + getLocalIp(*L_GET_CPP_PTR_FROM_C_STRUCT(address, Address)); + } + strncpy(md->addr, mediaLocalIp.c_str(), sizeof(md->addr)); LinphoneAddress *addr = nullptr; if (destProxy) { From dcba61188f3ec8bae3cefc0cc821d06aa8ccef1e Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 20 Sep 2017 20:00:42 +0200 Subject: [PATCH 0107/2215] feat(c-tools): add doc on macros --- src/c-wrapper/c-tools.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index b81a56cdb..8d8efc6da 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -343,27 +343,34 @@ LINPHONE_END_NAMESPACE #define L_STRING_TO_C(STR) ((STR).empty() ? NULL : (STR).c_str()) #define L_C_TO_STRING(STR) ((STR) == NULL ? std::string() : (STR)) -// Get the cpp-ptr from a wrapped C object. +// Get the cpp-ptr of a wrapped C object. #define L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE) \ LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC< \ LINPHONE_NAMESPACE::CPP_TYPE, \ std::remove_pointer::type \ >(OBJECT) +// Set the cpp-ptr of a wrapped C object. #define L_SET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_PTR) \ LINPHONE_NAMESPACE::Wrapper::setCppPtrFromC(OBJECT, CPP_PTR) +// Get the private data of a shared or simple cpp-ptr. #define L_GET_PRIVATE(OBJECT) \ LINPHONE_NAMESPACE::Wrapper::getPrivate(OBJECT) +// Get the private data of a shared or simple cpp-ptr of a wrapped C object. #define L_GET_PRIVATE_FROM_C_STRUCT(OBJECT, CPP_TYPE) \ L_GET_PRIVATE(LINPHONE_NAMESPACE::Wrapper::getCppPtr( \ L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE) \ )) +// Get the wrapped C object of a C++ object. #define L_GET_C_BACK_PTR(OBJECT, C_TYPE, C_NAME) \ - LINPHONE_NAMESPACE::Wrapper::getCBackPtr(OBJECT, _linphone_ ## C_NAME ## _init) + LINPHONE_NAMESPACE::Wrapper::getCBackPtr( \ + OBJECT, _linphone_ ## C_NAME ## _init \ + ) +// Get/set user data on a wrapped C object. #define L_GET_USER_DATA_FROM_C_STRUCT(OBJECT, CPP_TYPE) \ LINPHONE_NAMESPACE::Wrapper::getUserData( \ L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE) \ From df2c1cd256b5580bfc62e36b0c5276af64152e63 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 21 Sep 2017 10:10:08 +0200 Subject: [PATCH 0108/2215] feat(c-tools): L_DECLARE_xxx => better code --- src/c-wrapper/c-tools.h | 102 +++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 49 deletions(-) diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index 8d8efc6da..da273b3a0 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -27,6 +27,8 @@ #include "variant/variant.h" +// ============================================================================= +// Internal. // ============================================================================= LINPHONE_BEGIN_NAMESPACE @@ -257,88 +259,90 @@ private: LINPHONE_END_NAMESPACE -// ----------------------------------------------------------------------------- - -#define L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(CPP_CLASS, C_STRUCT, C_NAME, CONSTRUCTOR, DESTRUCTOR, ...) \ - struct _Linphone ## C_STRUCT { \ - belle_sip_object_t base; \ - std::shared_ptr cppPtr; \ - __VA_ARGS__ \ - }; \ - BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_STRUCT); \ - Linphone ## C_STRUCT *_linphone_ ## C_NAME ## _init() { \ - Linphone ## C_STRUCT * object = belle_sip_object_new(Linphone ## C_STRUCT); \ +#define L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(CPP_CLASS, C_TYPE, C_NAME, CONSTRUCTOR, DESTRUCTOR) \ + BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_TYPE); \ + Linphone ## C_TYPE *_linphone_ ## C_NAME ## _init() { \ + Linphone ## C_TYPE * object = belle_sip_object_new(Linphone ## C_TYPE); \ new(&object->cppPtr) std::shared_ptr(); \ CONSTRUCTOR(object); \ return object; \ } \ - void _linphone_ ## C_NAME ## _uninit(Linphone ## C_STRUCT * object) { \ + void _linphone_ ## C_NAME ## _uninit(Linphone ## C_TYPE * object) { \ DESTRUCTOR(object); \ object->cppPtr.~shared_ptr (); \ } \ - BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## C_STRUCT); \ - BELLE_SIP_INSTANCIATE_VPTR(Linphone ## C_STRUCT, belle_sip_object_t, \ - _linphone_ ## C_NAME ## _uninit, \ - NULL, \ - NULL, \ - FALSE \ + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## C_TYPE); \ + BELLE_SIP_INSTANCIATE_VPTR( \ + Linphone ## C_TYPE, \ + belle_sip_object_t, \ + _linphone_ ## C_NAME ## _uninit, \ + NULL, \ + NULL, \ + FALSE \ ); -#define L_DECLARE_C_STRUCT_IMPL(CPP_CLASS, C_STRUCT, C_NAME, ...) \ - struct _Linphone ## C_STRUCT { \ +// ============================================================================= +// Public Wrapper API. +// ============================================================================= + +// ----------------------------------------------------------------------------- +// C object declaration. +// ----------------------------------------------------------------------------- + +#define L_C_STRUCT_NO_XTOR(OBJECT) + +#define L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(CPP_CLASS, C_TYPE, C_NAME, CONSTRUCTOR, DESTRUCTOR, ...) \ + struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ std::shared_ptr cppPtr; \ __VA_ARGS__ \ }; \ - BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_STRUCT); \ - Linphone ## C_STRUCT *_linphone_ ## C_NAME ## _init() { \ - Linphone ## C_STRUCT * object = belle_sip_object_new(Linphone ## C_STRUCT); \ - new(&object->cppPtr) std::shared_ptr(); \ - return object; \ - } \ - void _linphone_ ## C_NAME ## _uninit(Linphone ## C_STRUCT * object) { \ - object->cppPtr.~shared_ptr (); \ - } \ - BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## C_STRUCT); \ - BELLE_SIP_INSTANCIATE_VPTR(Linphone ## C_STRUCT, belle_sip_object_t, \ - _linphone_ ## C_NAME ## _uninit, \ - NULL, \ - NULL, \ - FALSE \ - ); + L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(CPP_CLASS, C_TYPE, C_NAME, CONSTRUCTOR, DESTRUCTOR) -#define L_DECLARE_C_CLONABLE_STRUCT_IMPL(CPP_CLASS, C_STRUCT, C_NAME, ...) \ - struct _Linphone ## C_STRUCT { \ +#define L_DECLARE_C_STRUCT_IMPL(CPP_CLASS, C_TYPE, C_NAME, ...) \ + struct _Linphone ## C_TYPE { \ + belle_sip_object_t base; \ + std::shared_ptr cppPtr; \ + __VA_ARGS__ \ + }; \ + L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(CPP_CLASS, C_TYPE, C_NAME, L_C_STRUCT_NO_XTOR, L_C_STRUCT_NO_XTOR) + +#define L_DECLARE_C_CLONABLE_STRUCT_IMPL(CPP_CLASS, C_TYPE, C_NAME, ...) \ + struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ LINPHONE_NAMESPACE::CPP_CLASS *cppPtr; \ __VA_ARGS__ \ }; \ - BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_STRUCT); \ - Linphone ## C_STRUCT *_linphone_ ## C_NAME ## _init() { \ - return belle_sip_object_new(Linphone ## C_STRUCT); \ + BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_TYPE); \ + Linphone ## C_TYPE *_linphone_ ## C_NAME ## _init() { \ + return belle_sip_object_new(Linphone ## C_TYPE); \ } \ - void _linphone_ ## C_NAME ## _uninit(Linphone ## C_STRUCT * object) { \ + void _linphone_ ## C_NAME ## _uninit(Linphone ## C_TYPE * object) { \ delete object->cppPtr; \ } \ - void _linphone_ ## C_NAME ## _clone(Linphone ## C_STRUCT * dest, const Linphone ## C_STRUCT * src) { \ + void _linphone_ ## C_NAME ## _clone(Linphone ## C_TYPE * dest, const Linphone ## C_TYPE * src) { \ L_ASSERT(src->cppPtr); \ dest->cppPtr = new LINPHONE_NAMESPACE::CPP_CLASS(*src->cppPtr); \ } \ - BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## C_STRUCT); \ - BELLE_SIP_INSTANCIATE_VPTR(Linphone ## C_STRUCT, belle_sip_object_t, \ + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## C_TYPE); \ + BELLE_SIP_INSTANCIATE_VPTR(Linphone ## C_TYPE, belle_sip_object_t, \ _linphone_ ## C_NAME ## _uninit, \ _linphone_ ## C_NAME ## _clone, \ NULL, \ FALSE \ ); -#define L_DECLARE_C_STRUCT_NEW_DEFAULT(STRUCT, C_NAME) \ - Linphone ## STRUCT * linphone_ ## C_NAME ## _new() { \ - Linphone ## STRUCT * object = _linphone_ ## C_NAME ## _init(); \ - object->cppPtr = std::make_shared(); \ +#define L_DECLARE_C_STRUCT_NEW_DEFAULT(C_TYPE, C_NAME) \ + Linphone ## C_TYPE * linphone_ ## C_NAME ## _new() { \ + Linphone ## C_TYPE * object = _linphone_ ## C_NAME ## _init(); \ + object->cppPtr = std::make_shared(); \ return object; \ } +// ----------------------------------------------------------------------------- +// Helpers. +// ----------------------------------------------------------------------------- + // String conversions between C/C++. #define L_STRING_TO_C(STR) ((STR).empty() ? NULL : (STR).c_str()) #define L_C_TO_STRING(STR) ((STR) == NULL ? std::string() : (STR)) From f2daaf7df1d875e52866bef149da9e0651cdd8d6 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 21 Sep 2017 10:12:56 +0200 Subject: [PATCH 0109/2215] feat(c-tools): add doc on c wrapped object creation --- src/c-wrapper/c-tools.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index da273b3a0..0f11c3c2d 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -259,6 +259,8 @@ private: LINPHONE_END_NAMESPACE +#define L_INTERNAL_C_STRUCT_NO_XTOR(OBJECT) + #define L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(CPP_CLASS, C_TYPE, C_NAME, CONSTRUCTOR, DESTRUCTOR) \ BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_TYPE); \ Linphone ## C_TYPE *_linphone_ ## C_NAME ## _init() { \ @@ -289,8 +291,7 @@ LINPHONE_END_NAMESPACE // C object declaration. // ----------------------------------------------------------------------------- -#define L_C_STRUCT_NO_XTOR(OBJECT) - +// Declare wrapped C object with constructor/destructor. #define L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(CPP_CLASS, C_TYPE, C_NAME, CONSTRUCTOR, DESTRUCTOR, ...) \ struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ @@ -299,14 +300,16 @@ LINPHONE_END_NAMESPACE }; \ L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(CPP_CLASS, C_TYPE, C_NAME, CONSTRUCTOR, DESTRUCTOR) +// Declare wrapped C object. #define L_DECLARE_C_STRUCT_IMPL(CPP_CLASS, C_TYPE, C_NAME, ...) \ struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ std::shared_ptr cppPtr; \ __VA_ARGS__ \ }; \ - L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(CPP_CLASS, C_TYPE, C_NAME, L_C_STRUCT_NO_XTOR, L_C_STRUCT_NO_XTOR) + L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(CPP_CLASS, C_TYPE, C_NAME, L_INTERNAL_C_STRUCT_NO_XTOR, L_INTERNAL_C_STRUCT_NO_XTOR) +// Declare clonable wrapped C object. #define L_DECLARE_C_CLONABLE_STRUCT_IMPL(CPP_CLASS, C_TYPE, C_NAME, ...) \ struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ From 7d6d2da2fcac6ad9b1e19a58cc980e4ab5393d19 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 21 Sep 2017 10:13:09 +0200 Subject: [PATCH 0110/2215] Add missing linphone_chat_room_get_state() API. --- include/linphone/api/c-chat-room.h | 7 +++++++ src/c-wrapper/api/c-chat-room.cpp | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index 075abca35..b6071d0da 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -230,6 +230,13 @@ LINPHONE_PUBLIC LinphoneCall *linphone_chat_room_get_call(const LinphoneChatRoom */ LINPHONE_PUBLIC LinphoneChatRoomCbs * linphone_chat_room_get_callbacks (const LinphoneChatRoom *cr); +/** + * Get the state of the chat room. + * @param[in] cr LinphoneChatRoom object + * @return The state of the chat room + */ +LINPHONE_PUBLIC LinphoneChatRoomState linphone_chat_room_get_state (const LinphoneChatRoom *cr); + /** * Add a participant to a chat room. This may fail if this type of chat room does not handle participants. * Use linphone_chat_room_can_handle_participants() to know if this chat room handles participants. diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 65bdf0232..60158d4a6 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -209,6 +209,10 @@ LinphoneChatRoomCbs *linphone_chat_room_get_callbacks (const LinphoneChatRoom *c return cr->cbs; } +LinphoneChatRoomState linphone_chat_room_get_state (const LinphoneChatRoom *cr) { + return (LinphoneChatRoomState)GET_CPP_PTR(cr)->getState(); +} + LinphoneParticipant *linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr) { return L_GET_C_BACK_PTR(GET_CPP_PTR(cr)->addParticipant( *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address), nullptr, false), From eccde9b8f1ef6184626c66989af162b8ff0b8dcc Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 21 Sep 2017 11:54:35 +0200 Subject: [PATCH 0111/2215] feat(c-tools): remove C_NAME of macros --- src/c-wrapper/api/c-address.cpp | 4 +-- src/c-wrapper/api/c-call-params.cpp | 28 +++++++++----------- src/c-wrapper/api/c-chat-room.cpp | 13 ++++----- src/c-wrapper/api/c-event-log.cpp | 26 +++++++++--------- src/c-wrapper/api/c-participant.cpp | 2 +- src/c-wrapper/c-tools.h | 38 +++++++++++++-------------- src/chat/chat-room.cpp | 4 +-- src/chat/client-group-chat-room.cpp | 16 +++++------ src/chat/real-time-text-chat-room.cpp | 4 +-- 9 files changed, 66 insertions(+), 69 deletions(-) diff --git a/src/c-wrapper/api/c-address.cpp b/src/c-wrapper/api/c-address.cpp index 32add40aa..78e166181 100644 --- a/src/c-wrapper/api/c-address.cpp +++ b/src/c-wrapper/api/c-address.cpp @@ -23,7 +23,7 @@ // ============================================================================= -L_DECLARE_C_CLONABLE_STRUCT_IMPL(Address, Address, address); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(Address, Address); using namespace std; @@ -36,7 +36,7 @@ LinphoneAddress *linphone_address_new (const char *address) { return nullptr; } - LinphoneAddress *object = _linphone_address_init(); + LinphoneAddress *object = _linphone_Address_init(); object->cppPtr = cppPtr; return object; } diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index 3852a7343..5356da94a 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -28,12 +28,10 @@ // ============================================================================= -#define GET_CALL_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, CallSessionParams, CallParams) -#define GET_CALL_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, CallSessionParams) #define GET_MEDIA_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, MediaSessionParams) #define GET_MEDIA_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, MediaSessionParams) -L_DECLARE_C_CLONABLE_STRUCT_IMPL(MediaSessionParams, CallParams, call_params) +L_DECLARE_C_CLONABLE_STRUCT_IMPL(MediaSessionParams, CallParams) using namespace std; @@ -85,7 +83,7 @@ SalStreamDir get_video_dir_from_call_params (const LinphoneCallParams *params) { } void linphone_call_params_set_custom_headers (LinphoneCallParams *params, const SalCustomHeader *ch) { - GET_CALL_CPP_PRIVATE_PTR(params)->setCustomHeaders(ch); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setCustomHeaders(ch); } void linphone_call_params_set_custom_sdp_attributes (LinphoneCallParams *params, const SalCustomSdpAttribute *csa) { @@ -381,19 +379,19 @@ void linphone_call_params_set_received_fps (LinphoneCallParams *params, float va // ============================================================================= bool_t linphone_call_params_get_in_conference (const LinphoneCallParams *params) { - return GET_CALL_CPP_PRIVATE_PTR(params)->getInConference(); + return GET_MEDIA_CPP_PRIVATE_PTR(params)->getInConference(); } void linphone_call_params_set_in_conference (LinphoneCallParams *params, bool_t value) { - GET_CALL_CPP_PRIVATE_PTR(params)->setInConference(value); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setInConference(value); } bool_t linphone_call_params_get_internal_call_update (const LinphoneCallParams *params) { - return GET_CALL_CPP_PRIVATE_PTR(params)->getInternalCallUpdate(); + return GET_MEDIA_CPP_PRIVATE_PTR(params)->getInternalCallUpdate(); } void linphone_call_params_set_internal_call_update (LinphoneCallParams *params, bool_t value) { - GET_CALL_CPP_PRIVATE_PTR(params)->setInternalCallUpdate(value); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setInternalCallUpdate(value); } bool_t linphone_call_params_implicit_rtcp_fb_enabled (const LinphoneCallParams *params) { @@ -437,7 +435,7 @@ void linphone_call_params_set_up_ptime (LinphoneCallParams *params, int value) { } SalCustomHeader *linphone_call_params_get_custom_headers (const LinphoneCallParams *params) { - return GET_CALL_CPP_PRIVATE_PTR(params)->getCustomHeaders(); + return GET_MEDIA_CPP_PRIVATE_PTR(params)->getCustomHeaders(); } SalCustomSdpAttribute *linphone_call_params_get_custom_sdp_attributes (const LinphoneCallParams *params) { @@ -449,11 +447,11 @@ SalCustomSdpAttribute *linphone_call_params_get_custom_sdp_media_attributes (con } LinphoneCall *linphone_call_params_get_referer (const LinphoneCallParams *params) { - return GET_CALL_CPP_PRIVATE_PTR(params)->getReferer(); + return GET_MEDIA_CPP_PRIVATE_PTR(params)->getReferer(); } void linphone_call_params_set_referer (LinphoneCallParams *params, LinphoneCall *referer) { - GET_CALL_CPP_PRIVATE_PTR(params)->setReferer(referer); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setReferer(referer); } bool_t linphone_call_params_get_update_call_when_ice_completed (const LinphoneCallParams *params) { @@ -481,11 +479,11 @@ void linphone_call_params_set_received_video_definition (LinphoneCallParams *par } bool_t linphone_call_params_get_no_user_consent (const LinphoneCallParams *params) { - return GET_CALL_CPP_PRIVATE_PTR(params)->getNoUserConsent(); + return GET_MEDIA_CPP_PRIVATE_PTR(params)->getNoUserConsent(); } void linphone_call_params_set_no_user_consent (LinphoneCallParams *params, bool_t value) { - GET_CALL_CPP_PRIVATE_PTR(params)->setNoUserConsent(value); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setNoUserConsent(value); } // ============================================================================= @@ -514,14 +512,14 @@ void linphone_call_params_unref (LinphoneCallParams *cp) { // ============================================================================= LinphoneCallParams *linphone_call_params_new (LinphoneCore *core) { - LinphoneCallParams *params = _linphone_call_params_init(); + LinphoneCallParams *params = _linphone_CallParams_init(); L_SET_CPP_PTR_FROM_C_STRUCT(params, new LinphonePrivate::MediaSessionParams()); GET_MEDIA_CPP_PTR(params)->initDefault(core); return params; } LinphoneCallParams *linphone_call_params_new_for_wrapper (void) { - return _linphone_call_params_init(); + return _linphone_CallParams_init(); } /* DEPRECATED */ diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 60158d4a6..b62832222 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -37,12 +37,13 @@ using namespace std; -extern LinphoneParticipant *_linphone_participant_init (); +extern LinphoneParticipant *_linphone_Participant_init (); static void _linphone_chat_room_constructor (LinphoneChatRoom *cr); static void _linphone_chat_room_destructor (LinphoneChatRoom *cr); -L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(ChatRoom, ChatRoom, chat_room, +L_DECLARE_C_STRUCT_IMPL_WITH_XTORS( + ChatRoom, ChatRoom, _linphone_chat_room_constructor, _linphone_chat_room_destructor, LinphoneChatRoomCbs *cbs; LinphoneAddress *peerAddressCache; @@ -216,7 +217,7 @@ LinphoneChatRoomState linphone_chat_room_get_state (const LinphoneChatRoom *cr) LinphoneParticipant *linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr) { return L_GET_C_BACK_PTR(GET_CPP_PTR(cr)->addParticipant( *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address), nullptr, false), - Participant, participant); + Participant); } void linphone_chat_room_add_participants (LinphoneChatRoom *cr, const bctbx_list_t *addresses) { @@ -237,7 +238,7 @@ int linphone_chat_room_get_nb_participants (const LinphoneChatRoom *cr) { } bctbx_list_t *linphone_chat_room_get_participants (const LinphoneChatRoom *cr) { - return L_GET_C_LIST_OF_STRUCT_PTR_FROM_CPP_LIST_OF_CPP_OBJ(GET_CPP_PTR(cr)->getParticipants(), Participant, Participant, participant); + return L_GET_C_LIST_OF_STRUCT_PTR_FROM_CPP_LIST_OF_CPP_OBJ(GET_CPP_PTR(cr)->getParticipants(), Participant, Participant); } void linphone_chat_room_remove_participant (LinphoneChatRoom *cr, LinphoneParticipant *participant) { @@ -274,7 +275,7 @@ void linphone_chat_room_set_user_data (LinphoneChatRoom *cr, void *ud) { // ============================================================================= LinphoneChatRoom *linphone_chat_room_new (LinphoneCore *core, const LinphoneAddress *addr) { - LinphoneChatRoom *cr = _linphone_chat_room_init(); + LinphoneChatRoom *cr = _linphone_ChatRoom_init(); if (linphone_core_realtime_text_enabled(core)) L_SET_CPP_PTR_FROM_C_STRUCT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address))); else @@ -299,7 +300,7 @@ LinphoneChatRoom *linphone_client_group_chat_room_new (LinphoneCore *core, const from = linphone_core_get_primary_contact(core); LinphonePrivate::Address me(from); std::list l = L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(addresses, Address, Address); - LinphoneChatRoom *cr = _linphone_chat_room_init(); + LinphoneChatRoom *cr = _linphone_ChatRoom_init(); L_SET_CPP_PTR_FROM_C_STRUCT(cr, make_shared(core, me, l)); linphone_core_notify_chat_room_instantiated(core, cr); L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Instantiated); diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 4d07c6741..d65bce511 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -28,11 +28,11 @@ // ============================================================================= -L_DECLARE_C_CLONABLE_STRUCT_IMPL(EventLog, EventLog, event_log); -L_DECLARE_C_CLONABLE_STRUCT_IMPL(CallEvent, CallEvent, call_event); -L_DECLARE_C_CLONABLE_STRUCT_IMPL(ConferenceEvent, ConferenceEvent, conference_event); -L_DECLARE_C_CLONABLE_STRUCT_IMPL(ConferenceParticipantEvent, ConferenceParticipantEvent, conference_participant_event); -L_DECLARE_C_CLONABLE_STRUCT_IMPL(ChatMessageEvent, ChatMessageEvent, chat_message_event); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(EventLog, EventLog); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(CallEvent, CallEvent); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(ConferenceEvent, ConferenceEvent); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(ConferenceParticipantEvent, ConferenceParticipantEvent); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(ChatMessageEvent, ChatMessageEvent); using namespace std; @@ -41,7 +41,7 @@ using namespace std; // ----------------------------------------------------------------------------- LinphoneEventLog *linphone_event_log_new () { - LinphoneEventLog *event_log = _linphone_event_log_init(); + LinphoneEventLog *event_log = _linphone_EventLog_init(); L_SET_CPP_PTR_FROM_C_STRUCT(event_log, new LINPHONE_NAMESPACE::EventLog()); return event_log; } @@ -62,7 +62,7 @@ LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *event_ // ----------------------------------------------------------------------------- LinphoneCallEvent *linphone_call_event_new (LinphoneEventLogType type, LinphoneCall *call) { - LinphoneCallEvent *call_event = _linphone_call_event_init(); + LinphoneCallEvent *call_event = _linphone_CallEvent_init(); L_SET_CPP_PTR_FROM_C_STRUCT( call_event, new LINPHONE_NAMESPACE::CallEvent( @@ -74,15 +74,14 @@ LinphoneCallEvent *linphone_call_event_new (LinphoneEventLogType type, LinphoneC } // TODO: REMOVE ME. -extern LinphoneCall *_linphone_call_init (); +extern LinphoneCall *_linphone_Call_init (); LinphoneCall *linphone_call_event_get_call (const LinphoneCallEvent *call_event) { return L_GET_C_BACK_PTR( L_GET_CPP_PTR_FROM_C_STRUCT( call_event, CallEvent )->getCall(), - Call, - call + Call ); } @@ -128,7 +127,7 @@ const LinphoneAddress *linphone_conference_participant_event_get_participant_add // ----------------------------------------------------------------------------- LinphoneChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage *chat_message) { - LinphoneChatMessageEvent *chat_message_event = _linphone_chat_message_event_init(); + LinphoneChatMessageEvent *chat_message_event = _linphone_ChatMessageEvent_init(); L_SET_CPP_PTR_FROM_C_STRUCT( chat_message_event, new LINPHONE_NAMESPACE::ChatMessageEvent( @@ -139,14 +138,13 @@ LinphoneChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage * } // TODO: REMOVE ME. -extern LinphoneChatMessage *_linphone_chat_message_init (); +extern LinphoneChatMessage *_linphone_ChatMessage_init (); LinphoneChatMessage *linphone_chat_message_event_get_chat_message (const LinphoneChatMessageEvent *chat_message_event) { return L_GET_C_BACK_PTR( L_GET_CPP_PTR_FROM_C_STRUCT( chat_message_event, ChatMessageEvent )->getChatMessage(), - ChatMessage, - chat_message + ChatMessage ); } diff --git a/src/c-wrapper/api/c-participant.cpp b/src/c-wrapper/api/c-participant.cpp index cd9956427..ea947d6f9 100644 --- a/src/c-wrapper/api/c-participant.cpp +++ b/src/c-wrapper/api/c-participant.cpp @@ -25,7 +25,7 @@ using namespace std; -L_DECLARE_C_STRUCT_IMPL(Participant, Participant, participant, +L_DECLARE_C_STRUCT_IMPL(Participant, Participant, mutable LinphoneAddress *addressCache; ); diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/c-tools.h index 0f11c3c2d..0375ad567 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/c-tools.h @@ -261,15 +261,15 @@ LINPHONE_END_NAMESPACE #define L_INTERNAL_C_STRUCT_NO_XTOR(OBJECT) -#define L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(CPP_CLASS, C_TYPE, C_NAME, CONSTRUCTOR, DESTRUCTOR) \ +#define L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(CPP_CLASS, C_TYPE, CONSTRUCTOR, DESTRUCTOR) \ BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_TYPE); \ - Linphone ## C_TYPE *_linphone_ ## C_NAME ## _init() { \ + Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init() { \ Linphone ## C_TYPE * object = belle_sip_object_new(Linphone ## C_TYPE); \ new(&object->cppPtr) std::shared_ptr(); \ CONSTRUCTOR(object); \ return object; \ } \ - void _linphone_ ## C_NAME ## _uninit(Linphone ## C_TYPE * object) { \ + static void _linphone_ ## C_TYPE ## _uninit(Linphone ## C_TYPE * object) { \ DESTRUCTOR(object); \ object->cppPtr.~shared_ptr (); \ } \ @@ -277,7 +277,7 @@ LINPHONE_END_NAMESPACE BELLE_SIP_INSTANCIATE_VPTR( \ Linphone ## C_TYPE, \ belle_sip_object_t, \ - _linphone_ ## C_NAME ## _uninit, \ + _linphone_ ## C_TYPE ## _uninit, \ NULL, \ NULL, \ FALSE \ @@ -292,52 +292,52 @@ LINPHONE_END_NAMESPACE // ----------------------------------------------------------------------------- // Declare wrapped C object with constructor/destructor. -#define L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(CPP_CLASS, C_TYPE, C_NAME, CONSTRUCTOR, DESTRUCTOR, ...) \ +#define L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(CPP_CLASS, C_TYPE, CONSTRUCTOR, DESTRUCTOR, ...) \ struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ std::shared_ptr cppPtr; \ __VA_ARGS__ \ }; \ - L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(CPP_CLASS, C_TYPE, C_NAME, CONSTRUCTOR, DESTRUCTOR) + L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(CPP_CLASS, C_TYPE, CONSTRUCTOR, DESTRUCTOR) // Declare wrapped C object. -#define L_DECLARE_C_STRUCT_IMPL(CPP_CLASS, C_TYPE, C_NAME, ...) \ +#define L_DECLARE_C_STRUCT_IMPL(CPP_CLASS, C_TYPE, ...) \ struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ std::shared_ptr cppPtr; \ __VA_ARGS__ \ }; \ - L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(CPP_CLASS, C_TYPE, C_NAME, L_INTERNAL_C_STRUCT_NO_XTOR, L_INTERNAL_C_STRUCT_NO_XTOR) + L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(CPP_CLASS, C_TYPE, L_INTERNAL_C_STRUCT_NO_XTOR, L_INTERNAL_C_STRUCT_NO_XTOR) // Declare clonable wrapped C object. -#define L_DECLARE_C_CLONABLE_STRUCT_IMPL(CPP_CLASS, C_TYPE, C_NAME, ...) \ +#define L_DECLARE_C_CLONABLE_STRUCT_IMPL(CPP_CLASS, C_TYPE, ...) \ struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ LINPHONE_NAMESPACE::CPP_CLASS *cppPtr; \ __VA_ARGS__ \ }; \ BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_TYPE); \ - Linphone ## C_TYPE *_linphone_ ## C_NAME ## _init() { \ + Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init() { \ return belle_sip_object_new(Linphone ## C_TYPE); \ } \ - void _linphone_ ## C_NAME ## _uninit(Linphone ## C_TYPE * object) { \ + static void _linphone_ ## C_TYPE ## _uninit(Linphone ## C_TYPE * object) { \ delete object->cppPtr; \ } \ - void _linphone_ ## C_NAME ## _clone(Linphone ## C_TYPE * dest, const Linphone ## C_TYPE * src) { \ + static void _linphone_ ## C_TYPE ## _clone(Linphone ## C_TYPE * dest, const Linphone ## C_TYPE * src) { \ L_ASSERT(src->cppPtr); \ dest->cppPtr = new LINPHONE_NAMESPACE::CPP_CLASS(*src->cppPtr); \ } \ BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## C_TYPE); \ BELLE_SIP_INSTANCIATE_VPTR(Linphone ## C_TYPE, belle_sip_object_t, \ - _linphone_ ## C_NAME ## _uninit, \ - _linphone_ ## C_NAME ## _clone, \ + _linphone_ ## C_TYPE ## _uninit, \ + _linphone_ ## C_TYPE ## _clone, \ NULL, \ FALSE \ ); #define L_DECLARE_C_STRUCT_NEW_DEFAULT(C_TYPE, C_NAME) \ Linphone ## C_TYPE * linphone_ ## C_NAME ## _new() { \ - Linphone ## C_TYPE * object = _linphone_ ## C_NAME ## _init(); \ + Linphone ## C_TYPE * object = _linphone_ ## C_TYPE ## _init(); \ object->cppPtr = std::make_shared(); \ return object; \ } @@ -372,9 +372,9 @@ LINPHONE_END_NAMESPACE )) // Get the wrapped C object of a C++ object. -#define L_GET_C_BACK_PTR(OBJECT, C_TYPE, C_NAME) \ +#define L_GET_C_BACK_PTR(OBJECT, C_TYPE) \ LINPHONE_NAMESPACE::Wrapper::getCBackPtr( \ - OBJECT, _linphone_ ## C_NAME ## _init \ + OBJECT, _linphone_ ## C_TYPE ## _init \ ) // Get/set user data on a wrapped C object. @@ -392,8 +392,8 @@ LINPHONE_END_NAMESPACE LINPHONE_NAMESPACE::Wrapper::getCListFromCppList(LIST) #define L_GET_CPP_LIST_FROM_C_LIST(LIST, TYPE) \ LINPHONE_NAMESPACE::Wrapper::getCppListFromCList(LIST) -#define L_GET_C_LIST_OF_STRUCT_PTR_FROM_CPP_LIST_OF_CPP_OBJ(LIST, CPP_TYPE, C_TYPE, C_NAME) \ - LINPHONE_NAMESPACE::Wrapper::getCListOfStructPtrFromCppListOfCppObj(LIST, _linphone_ ## C_NAME ## _init) +#define L_GET_C_LIST_OF_STRUCT_PTR_FROM_CPP_LIST_OF_CPP_OBJ(LIST, CPP_TYPE, C_TYPE) \ + LINPHONE_NAMESPACE::Wrapper::getCListOfStructPtrFromCppListOfCppObj(LIST, _linphone_ ## C_TYPE ## _init) #define L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(LIST, CPP_TYPE, C_TYPE) \ LINPHONE_NAMESPACE::Wrapper::getCppListOfCppObjFromCListOfStructPtr(LIST) diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 37c27da34..348d6c2fe 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -28,8 +28,8 @@ #include "chat-room.h" -extern LinphoneChatRoom * _linphone_chat_room_init(); -#define GET_BACK_PTR(object) L_GET_C_BACK_PTR(object->shared_from_this(), ChatRoom, chat_room) +extern LinphoneChatRoom * _linphone_ChatRoom_init(); +#define GET_BACK_PTR(object) L_GET_C_BACK_PTR(object->shared_from_this(), ChatRoom) // ============================================================================= diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index a267eaa57..92ad4dd72 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -23,8 +23,8 @@ // ============================================================================= -extern LinphoneChatRoom * _linphone_chat_room_init(); -extern LinphoneParticipant * _linphone_participant_init(); +extern LinphoneChatRoom * _linphone_ChatRoom_init(); +extern LinphoneParticipant * _linphone_Participant_init(); using namespace std; @@ -101,11 +101,11 @@ void ClientGroupChatRoom::onParticipantAdded (const Address &addr) { } participant = make_shared(addr); participants.push_back(participant); - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this->shared_from_this(), ChatRoom, chat_room); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this->shared_from_this(), ChatRoom); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAddedCb cb = linphone_chat_room_cbs_get_participant_added(cbs); if (cb) - cb(cr, L_GET_C_BACK_PTR(participant, Participant, participant)); + cb(cr, L_GET_C_BACK_PTR(participant, Participant)); } void ClientGroupChatRoom::onParticipantRemoved (const Address &addr) { @@ -114,11 +114,11 @@ void ClientGroupChatRoom::onParticipantRemoved (const Address &addr) { lWarning() << "Participant " << participant << " removed but not in the list of participants!"; return; } - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this->shared_from_this(), ChatRoom, chat_room); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this->shared_from_this(), ChatRoom); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantRemovedCb cb = linphone_chat_room_cbs_get_participant_removed(cbs); if (cb) - cb(cr, L_GET_C_BACK_PTR(participant, Participant, participant)); + cb(cr, L_GET_C_BACK_PTR(participant, Participant)); participants.remove(participant); } @@ -129,11 +129,11 @@ void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdm return; } participant->setAdmin(isAdmin); - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this->shared_from_this(), ChatRoom, chat_room); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this->shared_from_this(), ChatRoom); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAdminStatusChangedCb cb = linphone_chat_room_cbs_get_participant_admin_status_changed(cbs); if (cb) - cb(cr, L_GET_C_BACK_PTR(participant, Participant, participant), isAdmin); + cb(cr, L_GET_C_BACK_PTR(participant, Participant), isAdmin); } LINPHONE_END_NAMESPACE diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 8acb10ae6..9e9470f03 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -24,8 +24,8 @@ #include "c-wrapper/c-tools.h" #include "logger/logger.h" -extern LinphoneChatRoom * _linphone_chat_room_init(); -#define GET_BACK_PTR(object) L_GET_C_BACK_PTR(object->shared_from_this(), ChatRoom, chat_room) +extern LinphoneChatRoom * _linphone_ChatRoom_init(); +#define GET_BACK_PTR(object) L_GET_C_BACK_PTR(object->shared_from_this(), ChatRoom) // ============================================================================= From d9d06fa32fa89d3bed4e0ae1ec311a7c9779aa59 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 21 Sep 2017 13:13:45 +0200 Subject: [PATCH 0112/2215] Fixed compil broken due to chat message changes --- coreapi/callbacks.c | 4 +- coreapi/chat.c | 458 +------- coreapi/chat_file_transfer.c | 628 ----------- coreapi/help/examples/C/filetransfer.c | 8 +- coreapi/lime.c | 52 +- coreapi/message_storage.c | 73 +- coreapi/private.h | 42 +- include/linphone/api/c-callbacks.h | 44 + include/linphone/api/c-chat-message-cbs.h | 2 + include/linphone/api/c-chat-message.h | 364 +++++++ include/linphone/callbacks.h | 44 - include/linphone/chat.h | 295 ----- src/c-wrapper/api/c-chat-message.cpp | 1197 +++++++++++++++++++++ src/c-wrapper/api/c-chat-room.cpp | 22 +- src/chat/chat-room.cpp | 201 ++-- src/chat/real-time-text-chat-room.cpp | 23 +- 16 files changed, 1805 insertions(+), 1652 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index d26261ddc..4efc734c7 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -605,11 +605,11 @@ static void message_delivery_update(SalOp *op, SalMessageDeliveryStatus status){ return; } // check that the message does not belong to an already destroyed chat room - if so, do not invoke callbacks - if (chat_msg->chat_room != NULL) { + if (linphone_chat_message_get_chat_room(chat_msg) != NULL) { linphone_chat_message_update_state(chat_msg, chatStatusSal2Linphone(status)); } if (status != SalMessageDeliveryInProgress) { /*only release op if not in progress*/ - linphone_chat_message_destroy(chat_msg); + linphone_chat_message_unref(chat_msg); } } diff --git a/coreapi/chat.c b/coreapi/chat.c index 5ab6d9924..bb2036b65 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -42,26 +42,6 @@ #include "chat/real-time-text-chat-room-p.h" #include "content/content-type.h" -void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessageState state) { - /* do not invoke callbacks on orphan messages */ - if (state != msg->state && msg->chat_room != NULL) { - if (((msg->state == LinphoneChatMessageStateDisplayed) || (msg->state == LinphoneChatMessageStateDeliveredToUser)) - && ((state == LinphoneChatMessageStateDeliveredToUser) || (state == LinphoneChatMessageStateDelivered) || (state == LinphoneChatMessageStateNotDelivered))) { - /* If the message has been displayed or delivered to user we must not go back to the delivered or not delivered state. */ - return; - } - ms_message("Chat message %p: moving from state %s to %s", msg, linphone_chat_message_state_to_string(msg->state), - linphone_chat_message_state_to_string(state)); - msg->state = state; - if (msg->message_state_changed_cb) { - msg->message_state_changed_cb(msg, msg->state, msg->message_state_changed_user_data); - } - if (linphone_chat_message_cbs_get_msg_state_changed(msg->callbacks)) { - linphone_chat_message_cbs_get_msg_state_changed(msg->callbacks)(msg, msg->state); - } - } -} - void linphone_core_disable_chat(LinphoneCore *lc, LinphoneReason deny_reason) { lc->chat_deny_code = deny_reason; } @@ -161,22 +141,14 @@ LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const c return _linphone_core_get_or_create_chat_room(lc, to); } -void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state) { - linphone_chat_message_set_state(msg, new_state); - linphone_chat_message_store_state(msg); - - if (msg->state == LinphoneChatMessageStateDelivered || msg->state == LinphoneChatMessageStateNotDelivered) { - L_GET_PRIVATE_FROM_C_STRUCT(msg->chat_room, ChatRoom)->moveTransientMessageToWeakMessages(msg); - } -} - void create_file_transfer_information_from_vnd_gsma_rcs_ft_http_xml(LinphoneChatMessage *msg) { xmlChar *file_url = NULL; xmlDocPtr xmlMessageBody; xmlNodePtr cur; /* parse the msg body to get all informations from it */ - xmlMessageBody = xmlParseDoc((const xmlChar *)msg->message); - msg->file_transfer_information = linphone_content_new(); + xmlMessageBody = xmlParseDoc((const xmlChar *)linphone_chat_message_get_text(msg)); + LinphoneContent *content = linphone_content_new(); + linphone_chat_message_set_file_transfer_information(msg, content); cur = xmlDocGetRootElement(xmlMessageBody); if (cur != NULL) { @@ -190,13 +162,13 @@ void create_file_transfer_information_from_vnd_gsma_rcs_ft_http_xml(LinphoneChat while (cur != NULL) { if (!xmlStrcmp(cur->name, (const xmlChar *)"file-size")) { xmlChar *fileSizeString = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - linphone_content_set_size(msg->file_transfer_information, strtol((const char *)fileSizeString, NULL, 10)); + linphone_content_set_size(content, strtol((const char *)fileSizeString, NULL, 10)); xmlFree(fileSizeString); } if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) { xmlChar *filename = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - linphone_content_set_name(msg->file_transfer_information, (char *)filename); + linphone_content_set_name(content, (char *)filename); xmlFree(filename); } if (!xmlStrcmp(cur->name, (const xmlChar *)"content-type")) { @@ -209,8 +181,8 @@ void create_file_transfer_information_from_vnd_gsma_rcs_ft_http_xml(LinphoneChat } type = ms_strndup((char *)contentType, contentTypeIndex); subtype = ms_strdup(((char *)contentType + contentTypeIndex + 1)); - linphone_content_set_type(msg->file_transfer_information, type); - linphone_content_set_subtype(msg->file_transfer_information, subtype); + linphone_content_set_type(content, type); + linphone_content_set_subtype(content, subtype); ms_free(subtype); ms_free(type); xmlFree(contentType); @@ -227,7 +199,7 @@ void create_file_transfer_information_from_vnd_gsma_rcs_ft_http_xml(LinphoneChat uint8_t *keyBuffer = (uint8_t *)malloc(keyLength); /* decode the key into local key buffer */ b64::b64_decode((char *)keyb64, strlen((char *)keyb64), keyBuffer, keyLength); - linphone_content_set_key(msg->file_transfer_information, (char *)keyBuffer, keyLength); + linphone_content_set_key(content, (char *)keyBuffer, keyLength); /* duplicate key value into the linphone content private structure */ xmlFree(keyb64); free(keyBuffer); @@ -258,155 +230,7 @@ int linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage return reason; } -void _linphone_chat_message_resend(LinphoneChatMessage *msg, bool_t ref_msg) { - LinphoneChatMessageState state = linphone_chat_message_get_state(msg); - LinphoneChatRoom *cr; - if (state != LinphoneChatMessageStateNotDelivered) { - ms_warning("Cannot resend chat message in state %s", linphone_chat_message_state_to_string(state)); - return; - } - - cr = linphone_chat_message_get_chat_room(msg); - if (ref_msg) linphone_chat_message_ref(msg); - L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom)->sendMessage(msg); -} - -void linphone_chat_message_resend(LinphoneChatMessage *msg) { - _linphone_chat_message_resend(msg, FALSE); -} - -void linphone_chat_message_resend_2(LinphoneChatMessage *msg) { - _linphone_chat_message_resend(msg, TRUE); -} - -static char *linphone_chat_message_create_imdn_xml(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason) { - xmlBufferPtr buf; - xmlTextWriterPtr writer; - int err; - char *content = NULL; - char *datetime = NULL; - const char *message_id; - - /* Check that the chat message has a message id */ - message_id = linphone_chat_message_get_message_id(cm); - if (message_id == NULL) return NULL; - - buf = xmlBufferCreate(); - if (buf == NULL) { - ms_error("Error creating the XML buffer"); - return content; - } - writer = xmlNewTextWriterMemory(buf, 0); - if (writer == NULL) { - ms_error("Error creating the XML writer"); - return content; - } - - datetime = linphone_timestamp_to_rfc3339_string(linphone_chat_message_get_time(cm)); - err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); - if (err >= 0) { - err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"imdn", - (const xmlChar *)"urn:ietf:params:xml:ns:imdn"); - } - if ((err >= 0) && (reason != LinphoneReasonNone)) { - err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"linphoneimdn", NULL, (const xmlChar *)"http://www.linphone.org/xsds/imdn.xsd"); - } - if (err >= 0) { - err = xmlTextWriterWriteElement(writer, (const xmlChar *)"message-id", (const xmlChar *)message_id); - } - if (err >= 0) { - err = xmlTextWriterWriteElement(writer, (const xmlChar *)"datetime", (const xmlChar *)datetime); - } - if (err >= 0) { - if (imdn_type == ImdnTypeDelivery) { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivery-notification"); - } else { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"display-notification"); - } - } - if (err >= 0) { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"status"); - } - if (err >= 0) { - if (reason == LinphoneReasonNone) { - if (imdn_type == ImdnTypeDelivery) { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivered"); - } else { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"displayed"); - } - } else { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"error"); - } - } - if (err >= 0) { - /* Close the "delivered", "displayed" or "error" element. */ - err = xmlTextWriterEndElement(writer); - } - if ((err >= 0) && (reason != LinphoneReasonNone)) { - err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"linphoneimdn", (const xmlChar *)"reason", NULL); - if (err >= 0) { - char codestr[16]; - snprintf(codestr, 16, "%d", linphone_reason_to_error_code(reason)); - err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"code", (const xmlChar *)codestr); - } - if (err >= 0) { - err = xmlTextWriterWriteString(writer, (const xmlChar *)linphone_reason_to_string(reason)); - } - if (err >= 0) { - err = xmlTextWriterEndElement(writer); - } - } - if (err >= 0) { - /* Close the "status" element. */ - err = xmlTextWriterEndElement(writer); - } - if (err >= 0) { - /* Close the "delivery-notification" or "display-notification" element. */ - err = xmlTextWriterEndElement(writer); - } - if (err >= 0) { - /* Close the "imdn" element. */ - err = xmlTextWriterEndElement(writer); - } - if (err >= 0) { - err = xmlTextWriterEndDocument(writer); - } - if (err > 0) { - /* xmlTextWriterEndDocument returns the size of the content. */ - content = ms_strdup((char *)buf->content); - } - xmlFreeTextWriter(writer); - xmlBufferFree(buf); - ms_free(datetime); - return content; -} - -void linphone_chat_message_send_imdn(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason) { - char *content = linphone_chat_message_create_imdn_xml(cm, imdn_type, reason); - if (content) { - L_GET_PRIVATE_FROM_C_STRUCT(linphone_chat_message_get_chat_room(cm), ChatRoom)->sendImdn(content, reason); - ms_free(content); - } -} - -void linphone_chat_message_send_delivery_notification(LinphoneChatMessage *cm, LinphoneReason reason) { - LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(cm); - LinphoneCore *lc = linphone_chat_room_get_core(cr); - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); - if (linphone_im_notif_policy_get_send_imdn_delivered(policy) == TRUE) { - linphone_chat_message_send_imdn(cm, ImdnTypeDelivery, reason); - } -} - -void linphone_chat_message_send_display_notification(LinphoneChatMessage *cm) { - LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(cm); - LinphoneCore *lc = linphone_chat_room_get_core(cr); - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); - if (linphone_im_notif_policy_get_send_imdn_displayed(policy) == TRUE) { - linphone_chat_message_send_imdn(cm, ImdnTypeDisplay, LinphoneReasonNone); - } -} void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, uint32_t character, LinphoneCall *call) { if (linphone_core_realtime_text_enabled(lc)) { @@ -416,269 +240,3 @@ void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *c //L_GET_PRIVATE(std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)))->realtimeTextReceived(character, call); } } - -LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg, uint32_t character) { - LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); - if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) { - std::shared_ptr rttcr = - std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom)); - LinphoneCall *call = rttcr->getCall(); - LinphoneCore *lc = rttcr->getCore(); - const uint32_t new_line = 0x2028; - const uint32_t crlf = 0x0D0A; - const uint32_t lf = 0x0A; - - if (!call || !linphone_call_get_stream(call, LinphoneStreamTypeText)) { - return -1; - } - - if (character == new_line || character == crlf || character == lf) { - if (lc && lp_config_get_int(lc->config, "misc", "store_rtt_messages", 1) == 1) { - ms_debug("New line sent, forge a message with content %s", msg->message); - msg->time = ms_time(0); - msg->state = LinphoneChatMessageStateDisplayed; - msg->dir = LinphoneChatMessageOutgoing; - if (msg->from) linphone_address_unref(msg->from); - msg->from = linphone_address_new(linphone_core_get_identity(lc)); - msg->storage_id = linphone_chat_message_store(msg); - ms_free(msg->message); - msg->message = NULL; - } - } else { - char *value = LinphonePrivate::Utils::utf8ToChar(character); - msg->message = ms_strcat_printf(msg->message, value); - ms_debug("Sent RTT character: %s (%lu), pending text is %s", value, (unsigned long)character, msg->message); - delete value; - } - - text_stream_putchar32(reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeText)), character); - return 0; - } - return -1; -} - -const char* linphone_chat_message_get_message_id(const LinphoneChatMessage *cm) { - return cm->message_id; -} - -const char *linphone_chat_message_state_to_string(const LinphoneChatMessageState state) { - switch (state) { - case LinphoneChatMessageStateIdle: - return "LinphoneChatMessageStateIdle"; - case LinphoneChatMessageStateInProgress: - return "LinphoneChatMessageStateInProgress"; - case LinphoneChatMessageStateDelivered: - return "LinphoneChatMessageStateDelivered"; - case LinphoneChatMessageStateNotDelivered: - return "LinphoneChatMessageStateNotDelivered"; - case LinphoneChatMessageStateFileTransferError: - return "LinphoneChatMessageStateFileTransferError"; - case LinphoneChatMessageStateFileTransferDone: - return "LinphoneChatMessageStateFileTransferDone "; - case LinphoneChatMessageStateDeliveredToUser: - return "LinphoneChatMessageStateDeliveredToUser"; - case LinphoneChatMessageStateDisplayed: - return "LinphoneChatMessageStateDisplayed"; - } - return NULL; -} - -LinphoneChatRoom *linphone_chat_message_get_chat_room(LinphoneChatMessage *msg) { - return msg->chat_room; -} - -const LinphoneAddress *linphone_chat_message_get_peer_address(LinphoneChatMessage *msg) { - return linphone_chat_room_get_peer_address(msg->chat_room); -} - -const char *linphone_chat_message_get_external_body_url(const LinphoneChatMessage *msg) { - return msg->external_body_url; -} - -void linphone_chat_message_set_external_body_url(LinphoneChatMessage *msg, const char *url) { - if (msg->external_body_url) { - ms_free(msg->external_body_url); - } - msg->external_body_url = url ? ms_strdup(url) : NULL; -} - -const char * linphone_chat_message_get_content_type(const LinphoneChatMessage *msg) { - return msg->content_type; -} - -void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char *content_type) { - if (msg->content_type) { - ms_free(msg->content_type); - } - msg->content_type = content_type ? ms_strdup(content_type) : NULL; -} - -bool_t linphone_chat_message_is_file_transfer(const LinphoneChatMessage *msg) { - return LinphonePrivate::ContentType::isFileTransfer(msg->content_type); -} - -bool_t linphone_chat_message_is_text(const LinphoneChatMessage *msg) { - return LinphonePrivate::ContentType::isText(msg->content_type); -} - -bool_t linphone_chat_message_get_to_be_stored(const LinphoneChatMessage *msg) { - return msg->to_be_stored; -} - -void linphone_chat_message_set_to_be_stored(LinphoneChatMessage *msg, bool_t to_be_stored) { - msg->to_be_stored = to_be_stored; -} - -const char *linphone_chat_message_get_appdata(const LinphoneChatMessage *msg) { - return msg->appdata; -} - -void linphone_chat_message_set_appdata(LinphoneChatMessage *msg, const char *data) { - if (msg->appdata) { - ms_free(msg->appdata); - } - msg->appdata = data ? ms_strdup(data) : NULL; - linphone_chat_message_store_appdata(msg); -} - -void linphone_chat_message_set_from_address(LinphoneChatMessage *msg, const LinphoneAddress *from) { - if (msg->from) - linphone_address_unref(msg->from); - msg->from = linphone_address_clone(from); -} - -const LinphoneAddress *linphone_chat_message_get_from_address(const LinphoneChatMessage *msg) { - return msg->from; -} - -void linphone_chat_message_set_to_address(LinphoneChatMessage *msg, const LinphoneAddress *to) { - if (msg->to) - linphone_address_unref(msg->to); - msg->to = linphone_address_clone(to); -} - -const LinphoneAddress *linphone_chat_message_get_to_address(const LinphoneChatMessage *msg) { - if (msg->to) - return msg->to; - if (msg->dir == LinphoneChatMessageOutgoing) { - return linphone_chat_room_get_peer_address(msg->chat_room); - } - return NULL; -} - -void linphone_chat_message_set_is_secured(LinphoneChatMessage *msg, bool_t secured) { - msg->is_secured = secured; -} - -bool_t linphone_chat_message_is_secured(LinphoneChatMessage *msg) { - return msg->is_secured; -} - -LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessage *msg) { - return msg->dir == LinphoneChatMessageOutgoing ? msg->from : msg->to; -} - -time_t linphone_chat_message_get_time(const LinphoneChatMessage *msg) { - return msg->time; -} - -LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage *msg) { - return msg->state; -} - -const char *linphone_chat_message_get_text(const LinphoneChatMessage *msg) { - return msg->message; -} - -int linphone_chat_message_set_text(LinphoneChatMessage *msg, const char* text) { - if (msg->message) - ms_free(msg->message); - if (text) - msg->message = ms_strdup(text); - else - msg->message = NULL; - - return 0; -} - -void linphone_chat_message_add_custom_header(LinphoneChatMessage *msg, const char *header_name, - const char *header_value) { - msg->custom_headers = sal_custom_header_append(msg->custom_headers, header_name, header_value); -} - -const char *linphone_chat_message_get_custom_header(LinphoneChatMessage *msg, const char *header_name) { - return sal_custom_header_find(msg->custom_headers, header_name); -} - -void linphone_chat_message_remove_custom_header(LinphoneChatMessage *msg, const char *header_name) { - msg->custom_headers = sal_custom_header_remove(msg->custom_headers, header_name); -} - -bool_t linphone_chat_message_is_read(LinphoneChatMessage *msg) { - LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); - LinphoneCore *lc = linphone_chat_room_get_core(cr); - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); - if ((linphone_im_notif_policy_get_recv_imdn_displayed(policy) == TRUE) && (msg->state == LinphoneChatMessageStateDisplayed)) return TRUE; - if ((linphone_im_notif_policy_get_recv_imdn_delivered(policy) == TRUE) && (msg->state == LinphoneChatMessageStateDeliveredToUser || msg->state == LinphoneChatMessageStateDisplayed)) return TRUE; - return (msg->state == LinphoneChatMessageStateDelivered || msg->state == LinphoneChatMessageStateDisplayed || msg->state == LinphoneChatMessageStateDeliveredToUser); -} - -bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage *msg) { - return msg->dir == LinphoneChatMessageOutgoing; -} - -unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage *msg) { - return msg->storage_id; -} - -LinphoneChatMessage *linphone_chat_message_clone(const LinphoneChatMessage *msg) { - LinphoneChatMessage *new_message = linphone_chat_room_create_message(msg->chat_room, msg->message); - if (msg->external_body_url) - new_message->external_body_url = ms_strdup(msg->external_body_url); - if (msg->appdata) - new_message->appdata = ms_strdup(msg->appdata); - new_message->message_state_changed_cb = msg->message_state_changed_cb; - new_message->message_state_changed_user_data = msg->message_state_changed_user_data; - new_message->message_userdata = msg->message_userdata; - new_message->time = msg->time; - new_message->state = msg->state; - new_message->storage_id = msg->storage_id; - if (msg->from) - new_message->from = linphone_address_clone(msg->from); - if (msg->file_transfer_filepath) - new_message->file_transfer_filepath = ms_strdup(msg->file_transfer_filepath); - if (msg->file_transfer_information) - new_message->file_transfer_information = linphone_content_copy(msg->file_transfer_information); - return new_message; -} - -void linphone_chat_message_destroy(LinphoneChatMessage *msg) { - belle_sip_object_unref(msg); -} - -void linphone_chat_message_deactivate(LinphoneChatMessage *msg){ - if (msg->file_transfer_information != NULL) { - _linphone_chat_message_cancel_file_transfer(msg, FALSE); - } - /*mark the chat msg as orphan (it has no chat room anymore)*/ - msg->chat_room = NULL; -} - -void linphone_chat_message_release(LinphoneChatMessage *msg) { - linphone_chat_message_deactivate(msg); - linphone_chat_message_unref(msg); -} - -const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg) { - if (!msg->ei) ((LinphoneChatMessage*)msg)->ei = linphone_error_info_new(); /*let's do it mutable*/ - linphone_error_info_from_sal_op(msg->ei, msg->op); - return msg->ei; -} - -LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage *msg) { - return linphone_error_info_get_reason(linphone_chat_message_get_error_info(msg)); -} - -LinphoneChatMessageCbs *linphone_chat_message_get_callbacks(const LinphoneChatMessage *msg) { - return msg->callbacks; -} diff --git a/coreapi/chat_file_transfer.c b/coreapi/chat_file_transfer.c index d85901721..f8da29ad0 100644 --- a/coreapi/chat_file_transfer.c +++ b/coreapi/chat_file_transfer.c @@ -24,638 +24,10 @@ #include "linphone/core.h" #include "private.h" -#include "ortp/b64.h" #include "c-wrapper/c-tools.h" #include "chat/chat-room.h" -static bool_t file_transfer_in_progress_and_valid(LinphoneChatMessage* msg) { - return (msg->chat_room && linphone_chat_room_get_core(msg->chat_room) && msg->http_request && !belle_http_request_is_cancelled(msg->http_request)); -} - -static void _release_http_request(LinphoneChatMessage* msg) { - if (msg->http_request) { - belle_sip_object_unref(msg->http_request); - msg->http_request = NULL; - if (msg->http_listener){ - belle_sip_object_unref(msg->http_listener); - msg->http_listener = NULL; - // unhold the reference that the listener was holding on the message - linphone_chat_message_unref(msg); - } - } -} - -static void linphone_chat_message_process_io_error_upload(void *data, const belle_sip_io_error_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - ms_error("I/O Error during file upload of msg [%p]", msg); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); - _release_http_request(msg); - linphone_chat_room_remove_transient_message(msg->chat_room, msg); - linphone_chat_message_unref(msg); -} - -static void linphone_chat_message_process_auth_requested_upload(void *data, belle_sip_auth_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - ms_error("Error during file upload: auth requested for msg [%p]", msg); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); - _release_http_request(msg); - linphone_chat_room_remove_transient_message(msg->chat_room, msg); - linphone_chat_message_unref(msg); -} - -static void linphone_chat_message_process_io_error_download(void *data, const belle_sip_io_error_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - ms_error("I/O Error during file download msg [%p]", msg); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateFileTransferError); - _release_http_request(msg); -} - -static void linphone_chat_message_process_auth_requested_download(void *data, belle_sip_auth_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - ms_error("Error during file download : auth requested for msg [%p]", msg); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateFileTransferError); - _release_http_request(msg); -} - -static void linphone_chat_message_file_transfer_on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *m, - void *data, size_t offset, size_t total) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - if (!file_transfer_in_progress_and_valid(msg)) { - ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); - _release_http_request(msg); - return; - } - if (linphone_chat_message_cbs_get_file_transfer_progress_indication(msg->callbacks)) { - linphone_chat_message_cbs_get_file_transfer_progress_indication(msg->callbacks)( - msg, msg->file_transfer_information, offset, total); - } else { - /* Legacy: call back given by application level */ - linphone_core_notify_file_transfer_progress_indication(linphone_chat_room_get_core(msg->chat_room), msg, msg->file_transfer_information, - offset, total); - } -} - -static int on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, - void *data, size_t offset, uint8_t *buffer, size_t *size) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - LinphoneCore *lc = NULL; - LinphoneImEncryptionEngine *imee = NULL; - int retval = -1; - - if (!file_transfer_in_progress_and_valid(msg)) { - if (msg->http_request) { - ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); - _release_http_request(msg); - } - return BELLE_SIP_STOP; - } - - lc = linphone_chat_room_get_core(msg->chat_room); - /* if we've not reach the end of file yet, ask for more data */ - /* in case of file body handler, won't be called */ - if (msg->file_transfer_filepath == NULL && offset < linphone_content_get_size(msg->file_transfer_information)) { - /* get data from call back */ - LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = linphone_chat_message_cbs_get_file_transfer_send(msg->callbacks); - if (file_transfer_send_cb) { - LinphoneBuffer *lb = file_transfer_send_cb(msg, msg->file_transfer_information, offset, *size); - if (lb == NULL) { - *size = 0; - } else { - *size = linphone_buffer_get_size(lb); - memcpy(buffer, linphone_buffer_get_content(lb), *size); - linphone_buffer_unref(lb); - } - } else { - /* Legacy */ - linphone_core_notify_file_transfer_send(lc, msg, msg->file_transfer_information, (char *)buffer, size); - } - } - - imee = linphone_core_get_im_encryption_engine(lc); - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); - if (cb_process_uploading_file) { - size_t max_size = *size; - uint8_t *encrypted_buffer = (uint8_t *)ms_malloc0(max_size); - retval = cb_process_uploading_file(imee, msg, offset, (const uint8_t *)buffer, size, encrypted_buffer); - if (retval == 0) { - if (*size > max_size) { - ms_error("IM encryption engine process upload file callback returned a size bigger than the size of the buffer, so it will be truncated !"); - *size = max_size; - } - memcpy(buffer, encrypted_buffer, *size); - } - ms_free(encrypted_buffer); - } - } - - return retval <= 0 ? BELLE_SIP_CONTINUE : BELLE_SIP_STOP; -} - -static void on_send_end(belle_sip_user_body_handler_t *bh, void *data) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room); - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); - - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); - if (cb_process_uploading_file) { - cb_process_uploading_file(imee, msg, 0, NULL, NULL, NULL); - } - } -} - -static void file_upload_end_background_task(LinphoneChatMessage *obj){ - if (obj->bg_task_id){ - ms_message("channel [%p]: ending file upload background task with id=[%lx].",obj,obj->bg_task_id); - sal_end_background_task(obj->bg_task_id); - obj->bg_task_id=0; - } -} - -static void file_upload_background_task_ended(LinphoneChatMessage *obj){ - ms_warning("channel [%p]: file upload background task has to be ended now, but work isn't finished.",obj); - file_upload_end_background_task(obj); -} - -static void file_upload_begin_background_task(LinphoneChatMessage *obj){ - if (obj->bg_task_id==0){ - obj->bg_task_id=sal_begin_background_task("file transfer upload",(void (*)(void*))file_upload_background_task_ended, obj); - if (obj->bg_task_id) ms_message("channel [%p]: starting file upload background task with id=[%lx].",obj,obj->bg_task_id); - } -} - -static void linphone_chat_message_process_response_from_post_file(void *data, const belle_http_response_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - - if (msg->http_request && !file_transfer_in_progress_and_valid(msg)) { - ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); - _release_http_request(msg); - return; - } - - /* check the answer code */ - if (event->response) { - int code = belle_http_response_get_status_code(event->response); - if (code == 204) { /* this is the reply to the first post to the server - an empty msg */ - /* start uploading the file */ - belle_sip_multipart_body_handler_t *bh; - char *first_part_header; - belle_sip_body_handler_t *first_part_bh; - - bool_t is_file_encryption_enabled = FALSE; - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(linphone_chat_room_get_core(msg->chat_room)); - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer_cb = - linphone_im_encryption_engine_cbs_get_is_encryption_enabled_for_file_transfer(imee_cbs); - if (is_encryption_enabled_for_file_transfer_cb) { - is_file_encryption_enabled = is_encryption_enabled_for_file_transfer_cb(imee, msg->chat_room); - } - } - /* shall we encrypt the file */ - if (is_file_encryption_enabled) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb generate_file_transfer_key_cb = - linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(imee_cbs); - if (generate_file_transfer_key_cb) { - generate_file_transfer_key_cb(imee, msg->chat_room, msg); - } - /* temporary storage for the Content-disposition header value : use a generic filename to not leak it - * Actual filename stored in msg->file_transfer_information->name will be set in encrypted msg - * sended to the */ - first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"filename.txt\""); - } else { - /* temporary storage for the Content-disposition header value */ - first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"%s\"", - linphone_content_get_name(msg->file_transfer_information)); - } - - /* create a user body handler to take care of the file and add the content disposition and content-type - * headers */ - first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new( - linphone_content_get_size(msg->file_transfer_information), - linphone_chat_message_file_transfer_on_progress, NULL, NULL, - on_send_body, on_send_end, msg); - if (msg->file_transfer_filepath != NULL) { - belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh; - first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(msg->file_transfer_filepath, - NULL, msg); // No need to add again the callback for progression, otherwise it will be called twice - linphone_content_set_size(msg->file_transfer_information, belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh)); - belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)first_part_bh, body_handler); - } else if (linphone_content_get_buffer(msg->file_transfer_information) != NULL) { - first_part_bh = (belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer( - linphone_content_get_buffer(msg->file_transfer_information), - linphone_content_get_size(msg->file_transfer_information), linphone_chat_message_file_transfer_on_progress, msg); - } - - belle_sip_body_handler_add_header(first_part_bh, - belle_sip_header_create("Content-disposition", first_part_header)); - belle_sip_free(first_part_header); - belle_sip_body_handler_add_header(first_part_bh, - (belle_sip_header_t *)belle_sip_header_content_type_create( - linphone_content_get_type(msg->file_transfer_information), - linphone_content_get_subtype(msg->file_transfer_information))); - - /* insert it in a multipart body handler which will manage the boundaries of multipart msg */ - bh = belle_sip_multipart_body_handler_new(linphone_chat_message_file_transfer_on_progress, msg, first_part_bh, NULL); - - linphone_chat_message_ref(msg); - _release_http_request(msg); - file_upload_begin_background_task(msg); - linphone_chat_room_upload_file(msg); - belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(msg->http_request), BELLE_SIP_BODY_HANDLER(bh)); - linphone_chat_message_unref(msg); - } else if (code == 200) { /* file has been uploaded correctly, get server reply and send it */ - const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); - if (body && strlen(body) > 0) { - /* if we have an encryption key for the file, we must insert it into the msg and restore the correct - * filename */ - const char *content_key = linphone_content_get_key(msg->file_transfer_information); - size_t content_key_size = linphone_content_get_key_size(msg->file_transfer_information); - if (content_key != NULL) { - /* parse the msg body */ - xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body); - - xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody); - if (cur != NULL) { - cur = cur->xmlChildrenNode; - while (cur != NULL) { - if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { /* we found a file info node, check - it has a type="file" attribute */ - xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); - if (!xmlStrcmp(typeAttribute, - (const xmlChar *)"file")) { /* this is the node we are looking for : add a - file-key children node */ - xmlNodePtr fileInfoNodeChildren = - cur - ->xmlChildrenNode; /* need to parse the children node to update the file-name - one */ - /* convert key to base64 */ - size_t b64Size = b64::b64_encode(NULL, content_key_size, NULL, 0); - char *keyb64 = (char *)ms_malloc0(b64Size + 1); - int xmlStringLength; - - b64Size = b64::b64_encode(content_key, content_key_size, keyb64, b64Size); - keyb64[b64Size] = '\0'; /* libxml need a null terminated string */ - - /* add the node containing the key to the file-info node */ - xmlNewTextChild(cur, NULL, (const xmlChar *)"file-key", (const xmlChar *)keyb64); - xmlFree(typeAttribute); - ms_free(keyb64); - - /* look for the file-name node and update its content */ - while (fileInfoNodeChildren != NULL) { - if (!xmlStrcmp( - fileInfoNodeChildren->name, - (const xmlChar *)"file-name")) { /* we found a the file-name node, update - its content with the real filename */ - /* update node content */ - xmlNodeSetContent(fileInfoNodeChildren, - (const xmlChar *)(linphone_content_get_name( - msg->file_transfer_information))); - break; - } - fileInfoNodeChildren = fileInfoNodeChildren->next; - } - - /* dump the xml into msg->message */ - xmlDocDumpFormatMemoryEnc(xmlMessageBody, (xmlChar **)&msg->message, &xmlStringLength, - "UTF-8", 0); - - break; - } - xmlFree(typeAttribute); - } - cur = cur->next; - } - } - xmlFreeDoc(xmlMessageBody); - } else { /* no encryption key, transfer in plain, just copy the msg sent by server */ - msg->message = ms_strdup(body); - } - linphone_chat_message_set_content_type(msg, "application/vnd.gsma.rcs-ft-http+xml"); - linphone_chat_message_ref(msg); - linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone); - _release_http_request(msg); - L_GET_CPP_PTR_FROM_C_STRUCT(msg->chat_room, ChatRoom)->sendMessage(msg); - file_upload_end_background_task(msg); - linphone_chat_message_unref(msg); - } else { - ms_warning("Received empty response from server, file transfer failed"); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); - _release_http_request(msg); - file_upload_end_background_task(msg); - linphone_chat_message_unref(msg); - } - } else { - ms_warning("Unhandled HTTP code response %d for file transfer", code); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); - _release_http_request(msg); - file_upload_end_background_task(msg); - linphone_chat_message_unref(msg); - } - } -} - -const LinphoneContent *linphone_chat_message_get_file_transfer_information(const LinphoneChatMessage *msg) { - return msg->file_transfer_information; -} - -static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset, uint8_t *buffer, size_t size) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - LinphoneCore *lc = NULL; - LinphoneImEncryptionEngine *imee = NULL; - int retval = -1; - uint8_t *decrypted_buffer = NULL; - - if (!msg->chat_room) { - linphone_chat_message_cancel_file_transfer(msg); - return; - } - lc = linphone_chat_room_get_core(msg->chat_room); - - if (lc == NULL){ - return; /*might happen during linphone_core_destroy()*/ - } - - if (!msg->http_request || belle_http_request_is_cancelled(msg->http_request)) { - ms_warning("Cancelled request for msg [%p], ignoring %s", msg, __FUNCTION__); - return; - } - - /* first call may be with a zero size, ignore it */ - if (size == 0) { - return; - } - - decrypted_buffer = (uint8_t *)ms_malloc0(size); - imee = linphone_core_get_im_encryption_engine(lc); - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); - if (cb_process_downloading_file) { - retval = cb_process_downloading_file(imee, msg, offset, (const uint8_t *)buffer, size, decrypted_buffer); - if (retval == 0) { - memcpy(buffer, decrypted_buffer, size); - } - } - } - ms_free(decrypted_buffer); - - if (retval <= 0) { - if (msg->file_transfer_filepath == NULL) { - if (linphone_chat_message_cbs_get_file_transfer_recv(msg->callbacks)) { - LinphoneBuffer *lb = linphone_buffer_new_from_data(buffer, size); - linphone_chat_message_cbs_get_file_transfer_recv(msg->callbacks)(msg, msg->file_transfer_information, lb); - linphone_buffer_unref(lb); - } else { - /* Legacy: call back given by application level */ - linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, (const char *)buffer, size); - } - } - } else { - ms_warning("File transfer decrypt failed with code %d", (int)retval); - linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferError); - } - - return; -} - -static void on_recv_end(belle_sip_user_body_handler_t *bh, void *data) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room); - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); - int retval = -1; - - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); - if (cb_process_downloading_file) { - retval = cb_process_downloading_file(imee, msg, 0, NULL, 0, NULL); - } - } - - if (retval <= 0) { - if (msg->file_transfer_filepath == NULL) { - if (linphone_chat_message_cbs_get_file_transfer_recv(msg->callbacks)) { - LinphoneBuffer *lb = linphone_buffer_new(); - linphone_chat_message_cbs_get_file_transfer_recv(msg->callbacks)(msg, msg->file_transfer_information, lb); - linphone_buffer_unref(lb); - } else { - /* Legacy: call back given by application level */ - linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, NULL, 0); - } - } - } - - if (retval <= 0 && linphone_chat_message_get_state(msg) != LinphoneChatMessageStateFileTransferError) { - linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone); - } -} - -static LinphoneContent *linphone_chat_create_file_transfer_information_from_headers(const belle_sip_message_t *m) { - LinphoneContent *content = linphone_content_new(); - - belle_sip_header_content_length_t *content_length_hdr = - BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(m, "Content-Length")); - belle_sip_header_content_type_t *content_type_hdr = - BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(m, "Content-Type")); - const char *type = NULL, *subtype = NULL; - - linphone_content_set_name(content, ""); - - if (content_type_hdr) { - type = belle_sip_header_content_type_get_type(content_type_hdr); - subtype = belle_sip_header_content_type_get_subtype(content_type_hdr); - ms_message("Extracted content type %s / %s from header", type ? type : "", subtype ? subtype : ""); - if (type) - linphone_content_set_type(content, type); - if (subtype) - linphone_content_set_subtype(content, subtype); - } - - if (content_length_hdr) { - linphone_content_set_size(content, belle_sip_header_content_length_get_content_length(content_length_hdr)); - ms_message("Extracted content length %i from header", (int)linphone_content_get_size(content)); - } - - return content; -} - -static void linphone_chat_process_response_headers_from_get_file(void *data, const belle_http_response_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - if (event->response) { - /*we are receiving a response, set a specific body handler to acquire the response. - * if not done, belle-sip will create a memory body handler, the default*/ - belle_sip_message_t *response = BELLE_SIP_MESSAGE(event->response); - belle_sip_body_handler_t *body_handler = NULL; - size_t body_size = 0; - - if (msg->file_transfer_information == NULL) { - ms_warning("No file transfer information for msg %p: creating...", msg); - msg->file_transfer_information = linphone_chat_create_file_transfer_information_from_headers(response); - } - - if (msg->file_transfer_information) { - body_size = linphone_content_get_size(msg->file_transfer_information); - } - - - body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, linphone_chat_message_file_transfer_on_progress, NULL, on_recv_body, NULL, on_recv_end, msg); - if (msg->file_transfer_filepath != NULL) { - belle_sip_user_body_handler_t *bh = (belle_sip_user_body_handler_t *)body_handler; - body_handler = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new( - msg->file_transfer_filepath, linphone_chat_message_file_transfer_on_progress, msg); - if (belle_sip_body_handler_get_size((belle_sip_body_handler_t *)body_handler) == 0) { - /* If the size of the body has not been initialized from the file stat, use the one from the - * file_transfer_information. */ - belle_sip_body_handler_set_size((belle_sip_body_handler_t *)body_handler, body_size); - } - belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)body_handler, bh); - } - belle_sip_message_set_body_handler((belle_sip_message_t *)event->response, body_handler); - } -} - -static void linphone_chat_process_response_from_get_file(void *data, const belle_http_response_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - /* check the answer code */ - if (event->response) { - int code = belle_http_response_get_status_code(event->response); - if (code >= 400 && code < 500) { - ms_warning("File transfer failed with code %d", code); - linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferError); - } else if (code != 200) { - ms_warning("Unhandled HTTP code response %d for file transfer", code); - } - _release_http_request(msg); - } -} - -int _linphone_chat_room_start_http_transfer(LinphoneChatMessage *msg, const char* url, const char* action, const belle_http_request_listener_callbacks_t *cbs) { - belle_generic_uri_t *uri = NULL; - const char* ua = linphone_core_get_user_agent(linphone_chat_room_get_core(msg->chat_room)); - - if (url == NULL) { - ms_warning("Cannot process file transfer msg: no file remote URI configured."); - goto error; - } - uri = belle_generic_uri_parse(url); - if (uri == NULL || belle_generic_uri_get_host(uri)==NULL) { - ms_warning("Cannot process file transfer msg: incorrect file remote URI configured '%s'.", url); - goto error; - } - - msg->http_request = belle_http_request_create(action, uri, belle_sip_header_create("User-Agent", ua), NULL); - - if (msg->http_request == NULL) { - ms_warning("Could not create http request for uri %s", url); - goto error; - } - /* keep a reference to the http request to be able to cancel it during upload */ - belle_sip_object_ref(msg->http_request); - - /* give msg to listener to be able to start the actual file upload when server answer a 204 No content */ - msg->http_listener = belle_http_request_listener_create_from_callbacks(cbs, linphone_chat_message_ref(msg)); - belle_http_provider_send_request(linphone_chat_room_get_core(msg->chat_room)->http_provider, msg->http_request, msg->http_listener); - return 0; -error: - if (uri) { - belle_sip_object_unref(uri); - } - return -1; -} - -int linphone_chat_room_upload_file(LinphoneChatMessage *msg) { - belle_http_request_listener_callbacks_t cbs = {0}; - int err; - - if (msg->http_request){ - ms_error("linphone_chat_room_upload_file(): there is already an upload in progress."); - return -1; - } - - cbs.process_response = linphone_chat_message_process_response_from_post_file; - cbs.process_io_error = linphone_chat_message_process_io_error_upload; - cbs.process_auth_requested = linphone_chat_message_process_auth_requested_upload; - err = _linphone_chat_room_start_http_transfer(msg, linphone_core_get_file_transfer_server(linphone_chat_room_get_core(msg->chat_room)), "POST", &cbs); - if (err == -1){ - linphone_chat_message_set_state(msg, LinphoneChatMessageStateNotDelivered); - } - return err; -} - -LinphoneStatus linphone_chat_message_download_file(LinphoneChatMessage *msg) { - belle_http_request_listener_callbacks_t cbs = {0}; - int err; - - if (msg->http_request){ - ms_error("linphone_chat_message_download_file(): there is already a download in progress"); - return -1; - } - cbs.process_response_headers = linphone_chat_process_response_headers_from_get_file; - cbs.process_response = linphone_chat_process_response_from_get_file; - cbs.process_io_error = linphone_chat_message_process_io_error_download; - cbs.process_auth_requested = linphone_chat_message_process_auth_requested_download; - err = _linphone_chat_room_start_http_transfer(msg, msg->external_body_url, "GET", &cbs); - if (err == -1) return -1; - /* start the download, status is In Progress */ - linphone_chat_message_set_state(msg, LinphoneChatMessageStateInProgress); - return 0; -} - -void linphone_chat_message_start_file_download(LinphoneChatMessage *msg, - LinphoneChatMessageStateChangedCb status_cb, void *ud) { - msg->message_state_changed_cb = status_cb; - msg->message_state_changed_user_data = ud; - linphone_chat_message_download_file(msg); -} - -void _linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg, bool_t unref) { - if (msg->http_request) { - if (msg->state == LinphoneChatMessageStateInProgress) { - linphone_chat_message_set_state(msg, LinphoneChatMessageStateNotDelivered); - } - if (!belle_http_request_is_cancelled(msg->http_request)) { - if (msg->chat_room) { - ms_message("Canceling file transfer %s - msg [%p] chat room[%p]" - , (msg->external_body_url == NULL) ? linphone_core_get_file_transfer_server(linphone_chat_room_get_core(msg->chat_room)) : msg->external_body_url - , msg - , msg->chat_room); - belle_http_provider_cancel_request(linphone_chat_room_get_core(msg->chat_room)->http_provider, msg->http_request); - if ((msg->dir == LinphoneChatMessageOutgoing) && unref) { - // must release it - linphone_chat_message_unref(msg); - } - } else { - ms_message("Warning: http request still running for ORPHAN msg [%p]: this is a memory leak", msg); - } - } - _release_http_request(msg); - } else { - ms_message("No existing file transfer - nothing to cancel"); - } -} - -void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg) { - _linphone_chat_message_cancel_file_transfer(msg, TRUE); -} - -void linphone_chat_message_set_file_transfer_filepath(LinphoneChatMessage *msg, const char *filepath) { - if (msg->file_transfer_filepath != NULL) { - ms_free(msg->file_transfer_filepath); - } - msg->file_transfer_filepath = ms_strdup(filepath); -} - -const char *linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage *msg) { - return msg->file_transfer_filepath; -} - LinphoneChatMessage *linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent *initial_content) { return L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom)->createFileTransferMessage(initial_content); } diff --git a/coreapi/help/examples/C/filetransfer.c b/coreapi/help/examples/C/filetransfer.c index 485c0a662..b0cd2c08c 100644 --- a/coreapi/help/examples/C/filetransfer.c +++ b/coreapi/help/examples/C/filetransfer.c @@ -45,8 +45,8 @@ static void stop(int signum){ * function invoked to report file transfer progress. * */ static void file_transfer_progress_indication(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total) { - const LinphoneAddress* from_address = linphone_chat_message_get_from(message); - const LinphoneAddress* to_address = linphone_chat_message_get_to(message); + const LinphoneAddress* from_address = linphone_chat_message_get_from_address(message); + const LinphoneAddress* to_address = linphone_chat_message_get_to_address(message); char *address = linphone_chat_message_is_outgoing(message)?linphone_address_as_string(to_address):linphone_address_as_string(from_address); printf(" File transfer [%d%%] %s of type [%s/%s] %s [%s] \n", (int)((offset *100)/total) ,(linphone_chat_message_is_outgoing(message)?"sent":"received") @@ -70,7 +70,7 @@ static void file_transfer_received(LinphoneChatMessage *message, const LinphoneC file = (FILE*)linphone_chat_message_get_user_data(message); if (linphone_buffer_is_empty(buffer)) { printf("File transfert completed\n"); - linphone_chat_message_destroy(message); + linphone_chat_message_unref(message); fclose(file); running=FALSE; } else { /* store content on a file*/ @@ -95,7 +95,7 @@ static LinphoneBuffer * file_transfer_send(LinphoneChatMessage *message, const L * Call back to get delivery status of a message * */ static void linphone_file_transfer_state_changed(LinphoneChatMessage* msg,LinphoneChatMessageState state) { - const LinphoneAddress* to_address = linphone_chat_message_get_to(msg); + const LinphoneAddress* to_address = linphone_chat_message_get_to_address(msg); char *to = linphone_address_as_string(to_address); printf("File transfer sent to [%s] delivery status is [%s] \n" , to , linphone_chat_message_state_to_string(state)); diff --git a/coreapi/lime.c b/coreapi/lime.c index 5e4e4e209..35f1080db 100644 --- a/coreapi/lime.c +++ b/coreapi/lime.c @@ -785,7 +785,9 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEn LinphoneCore *lc = linphone_im_encryption_engine_get_core(engine); int errcode = -1; /* check if we have a xml/cipher message to be decrypted */ - if (msg->content_type && (strcmp("xml/cipher", msg->content_type) == 0 || strcmp("application/cipher.vnd.gsma.rcs-ft-http+xml", msg->content_type) == 0)) { + if (linphone_chat_message_get_content_type(msg) && + (strcmp("xml/cipher", linphone_chat_message_get_content_type(msg)) == 0 || + strcmp("application/cipher.vnd.gsma.rcs-ft-http+xml", linphone_chat_message_get_content_type(msg)) == 0)) { errcode = 0; int retval; void *zrtp_cache_db = NULL; /* use a void * instead of sqlite3 * to avoid problems and ifdef when SQLITE is not available(the get function shall return NULL in that case) */ @@ -800,9 +802,9 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEn errcode = 500; return errcode; } - peerUri = linphone_address_as_string_uri_only(msg->from); - selfUri = linphone_address_as_string_uri_only(msg->to); - retval = lime_decryptMultipartMessage(zrtp_cache_db, (uint8_t *)msg->message, selfUri, peerUri, &decrypted_body, &decrypted_content_type, + peerUri = linphone_address_as_string_uri_only(linphone_chat_message_get_from_address(msg)); + selfUri = linphone_address_as_string_uri_only(linphone_chat_message_get_to_address(msg)); + retval = lime_decryptMultipartMessage(zrtp_cache_db, (uint8_t *)linphone_chat_message_get_text(msg), selfUri, peerUri, &decrypted_body, &decrypted_content_type, bctbx_time_string_to_sec(lp_config_get_string(lc->config, "sip", "lime_key_validity", "0"))); ms_free(peerUri); ms_free(selfUri); @@ -813,15 +815,12 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEn return errcode; } else { /* swap encrypted message with plain text message */ - if (msg->message) { - ms_free(msg->message); - } - msg->message = (char *)decrypted_body; + linphone_chat_message_set_text(msg, (char *)decrypted_body); if (decrypted_content_type != NULL) { linphone_chat_message_set_content_type(msg, decrypted_content_type); ms_free(decrypted_content_type); } else { - if (strcmp("application/cipher.vnd.gsma.rcs-ft-http+xml", msg->content_type) == 0) { + if (strcmp("application/cipher.vnd.gsma.rcs-ft-http+xml", linphone_chat_message_get_content_type(msg)) == 0) { linphone_chat_message_set_content_type(msg, "application/vnd.gsma.rcs-ft-http+xml"); } else { linphone_chat_message_set_content_type(msg, "text/plain"); @@ -839,14 +838,14 @@ int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneImEncryptionEn if(linphone_core_lime_enabled(linphone_chat_room_get_core(room))) { if (linphone_chat_room_lime_available(room)) { void *zrtp_cache_db = NULL; /* use a void * instead of sqlite3 * to avoid problems and ifdef when SQLITE is not available(the get function shall return NULL in that case) */ - if (msg->content_type) { - if (strcmp(msg->content_type, "application/vnd.gsma.rcs-ft-http+xml") == 0) { + if (linphone_chat_message_get_content_type(msg)) { + if (strcmp(linphone_chat_message_get_content_type(msg), "application/vnd.gsma.rcs-ft-http+xml") == 0) { /* It's a file transfer, content type shall be set to application/cipher.vnd.gsma.rcs-ft-http+xml TODO: As of january 2017, the content type is now included in the encrypted body, this application/cipher.vnd.gsma.rcs-ft-http+xml is kept for compatibility with previous versions, but may be dropped in the future to use xml/cipher instead. */ new_content_type = "application/cipher.vnd.gsma.rcs-ft-http+xml"; - } else if (strcmp(msg->content_type, "application/im-iscomposing+xml") == 0) { + } else if (strcmp(linphone_chat_message_get_content_type(msg), "application/im-iscomposing+xml") == 0) { /* We don't encrypt composing messages */ return errcode; } @@ -861,19 +860,16 @@ int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneImEncryptionEn } else { int retval; uint8_t *crypted_body = NULL; - char *selfUri = linphone_address_as_string_uri_only(msg->from); + char *selfUri = linphone_address_as_string_uri_only(linphone_chat_message_get_from_address(msg)); char *peerUri = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(room)); - retval = lime_createMultipartMessage(zrtp_cache_db, msg->content_type, (uint8_t *)msg->message, selfUri, peerUri, &crypted_body); + retval = lime_createMultipartMessage(zrtp_cache_db, linphone_chat_message_get_content_type(msg), (uint8_t *)linphone_chat_message_get_text(msg), selfUri, peerUri, &crypted_body); if (retval != 0) { /* fail to encrypt */ ms_warning("Unable to encrypt message for %s : %s", peerUri, lime_error_code_to_string(retval)); if (crypted_body) ms_free(crypted_body); errcode = 488; } else { /* encryption ok, swap plain text message body by encrypted one */ - if (msg->message) { - ms_free(msg->message); - } - msg->message = (char *)crypted_body; + linphone_chat_message_set_text(msg, (char *)crypted_body); linphone_chat_message_set_content_type(msg, new_content_type); } ms_free(peerUri); @@ -890,23 +886,23 @@ int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneImEncryptionEn } int lime_im_encryption_engine_process_downloading_file_cb(LinphoneImEncryptionEngine *engine, LinphoneChatMessage *msg, size_t offset, const uint8_t *buffer, size_t size, uint8_t *decrypted_buffer) { - if (linphone_content_get_key(msg->file_transfer_information) == NULL) return -1; + if (linphone_content_get_key(linphone_chat_message_get_file_transfer_information(msg)) == NULL) return -1; if (buffer == NULL || size == 0) { - return lime_decryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information), NULL, 0, NULL, NULL); + return lime_decryptFile(linphone_content_get_cryptoContext_address(linphone_chat_message_get_file_transfer_information(msg)), NULL, 0, NULL, NULL); } - return lime_decryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information), - (unsigned char *)linphone_content_get_key(msg->file_transfer_information), size, (char *)decrypted_buffer, + return lime_decryptFile(linphone_content_get_cryptoContext_address(linphone_chat_message_get_file_transfer_information(msg)), + (unsigned char *)linphone_content_get_key(linphone_chat_message_get_file_transfer_information(msg)), size, (char *)decrypted_buffer, (char *)buffer); } int lime_im_encryption_engine_process_uploading_file_cb(LinphoneImEncryptionEngine *engine, LinphoneChatMessage *msg, size_t offset, const uint8_t *buffer, size_t *size, uint8_t *encrypted_buffer) { - size_t file_size = linphone_content_get_size(msg->file_transfer_information); - if (linphone_content_get_key(msg->file_transfer_information) == NULL) return -1; + size_t file_size = linphone_content_get_size(linphone_chat_message_get_file_transfer_information(msg)); + if (linphone_content_get_key(linphone_chat_message_get_file_transfer_information(msg)) == NULL) return -1; if (buffer == NULL || *size == 0) { - return lime_encryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information), NULL, 0, NULL, NULL); + return lime_encryptFile(linphone_content_get_cryptoContext_address(linphone_chat_message_get_file_transfer_information(msg)), NULL, 0, NULL, NULL); } if (file_size == 0) { @@ -915,8 +911,8 @@ int lime_im_encryption_engine_process_uploading_file_cb(LinphoneImEncryptionEngi *size -= (*size % 16); } - return lime_encryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information), - (unsigned char *)linphone_content_get_key(msg->file_transfer_information), *size, + return lime_encryptFile(linphone_content_get_cryptoContext_address(linphone_chat_message_get_file_transfer_information(msg)), + (unsigned char *)linphone_content_get_key(linphone_chat_message_get_file_transfer_information(msg)), *size, (char *)buffer, (char *)encrypted_buffer); } @@ -930,7 +926,7 @@ void lime_im_encryption_engine_generate_file_transfer_key_cb(LinphoneImEncryptio /* generate a random 192 bits key + 64 bits of initial vector and store it into the * file_transfer_information->key field of the msg */ sal_get_random_bytes((unsigned char *)keyBuffer, FILE_TRANSFER_KEY_SIZE); - linphone_content_set_key(msg->file_transfer_information, keyBuffer, FILE_TRANSFER_KEY_SIZE); /* key is duplicated in the content private structure */ + linphone_content_set_key(linphone_chat_message_get_file_transfer_information(msg), keyBuffer, FILE_TRANSFER_KEY_SIZE); /* key is duplicated in the content private structure */ } #else /* HAVE_LIME */ diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 8bf1f1e45..cad03b178 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -20,7 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "private.h" #include "linphone/core.h" - #ifdef SQLITE_STORAGE_ENABLED #include "chat/chat-room.h" @@ -133,17 +132,14 @@ int _linphone_sqlite3_open(const char *db_file, sqlite3 **db) { static int callback_content(void *data, int argc, char **argv, char **colName) { LinphoneChatMessage *message = (LinphoneChatMessage *)data; - if (message->file_transfer_information) { - linphone_content_unref(message->file_transfer_information); - message->file_transfer_information = NULL; - } - message->file_transfer_information = linphone_content_new(); - if (argv[1]) linphone_content_set_type(message->file_transfer_information, argv[1]); - if (argv[2]) linphone_content_set_subtype(message->file_transfer_information, argv[2]); - if (argv[3]) linphone_content_set_name(message->file_transfer_information, argv[3]); - if (argv[4]) linphone_content_set_encoding(message->file_transfer_information, argv[4]); - linphone_content_set_size(message->file_transfer_information, (size_t)atoi(argv[5])); - if (argv[8]) linphone_content_set_key(message->file_transfer_information, argv[8], (size_t)atol(argv[7])); + LinphoneContent *content = linphone_content_new(); + if (argv[1]) linphone_content_set_type(content, argv[1]); + if (argv[2]) linphone_content_set_subtype(content, argv[2]); + if (argv[3]) linphone_content_set_name(content, argv[3]); + if (argv[4]) linphone_content_set_encoding(content, argv[4]); + linphone_content_set_size(content, (size_t)atoi(argv[5])); + if (argv[8]) linphone_content_set_key(content, argv[8], (size_t)atol(argv[7])); + linphone_chat_message_set_file_transfer_information(message, content); return 0; } @@ -197,10 +193,10 @@ void linphone_sql_request_all(sqlite3* db,const char *stmt, LinphoneCore* lc){ } static int linphone_chat_message_store_content(LinphoneChatMessage *msg) { - LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room); + LinphoneCore *lc = linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)); int id = -1; if (lc->db) { - LinphoneContent *content = msg->file_transfer_information; + LinphoneContent *content = linphone_chat_message_get_file_transfer_information(msg); char *buf = sqlite3_mprintf("INSERT INTO content VALUES(NULL,%Q,%Q,%Q,%Q,%i,%Q,%lld,%Q);", linphone_content_get_type(content), linphone_content_get_subtype(content), @@ -219,7 +215,7 @@ static int linphone_chat_message_store_content(LinphoneChatMessage *msg) { } unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){ - LinphoneCore *lc=linphone_chat_room_get_core(msg->chat_room); + LinphoneCore *lc=linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)); int id = 0; if (lc->db){ @@ -227,27 +223,27 @@ unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){ char *peer; char *local_contact; char *buf; - if (msg->file_transfer_information) { + if (linphone_chat_message_get_file_transfer_information(msg)) { content_id = linphone_chat_message_store_content(msg); } - peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(msg->chat_room)); + peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(linphone_chat_message_get_chat_room(msg))); local_contact=linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg)); buf = sqlite3_mprintf("INSERT INTO history VALUES(NULL,%Q,%Q,%i,%Q,%Q,%i,%i,%Q,%lld,%Q,%i,%Q,%Q,%i);", local_contact, peer, - msg->dir, - msg->message, + linphone_chat_message_get_direction(msg), + linphone_chat_message_get_text(msg), "-1", /* use UTC field now */ FALSE, /* use state == LinphoneChatMessageStateDisplayed now */ - msg->state, - msg->external_body_url, - (int64_t)msg->time, - msg->appdata, + linphone_chat_message_get_state(msg), + linphone_chat_message_get_external_body_url(msg), + (int64_t)linphone_chat_message_get_time(msg), + linphone_chat_message_get_appdata(msg), content_id, - msg->message_id, - msg->content_type, - (int)msg->is_secured + linphone_chat_message_get_message_id(msg), + linphone_chat_message_get_content_type(msg), + (int)linphone_chat_message_is_secured(msg) ); linphone_sql_request(lc->db,buf); sqlite3_free(buf); @@ -255,18 +251,19 @@ unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){ ms_free(peer); id = (unsigned int) sqlite3_last_insert_rowid (lc->db); } + linphone_chat_message_set_storage_id(msg, id); return id; } void linphone_chat_message_store_update(LinphoneChatMessage *msg) { - LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room); + LinphoneCore *lc = linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)); if (lc->db) { char *peer; char *local_contact; char *buf; - peer = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(msg->chat_room)); + peer = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(linphone_chat_message_get_chat_room(msg))); local_contact = linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg)); buf = sqlite3_mprintf("UPDATE history SET" " localContact = %Q," @@ -279,12 +276,12 @@ void linphone_chat_message_store_update(LinphoneChatMessage *msg) { " WHERE (id = %u);", local_contact, peer, - msg->message, - msg->state, - msg->appdata, - msg->message_id, - msg->content_type, - msg->storage_id + linphone_chat_message_get_text(msg), + linphone_chat_message_get_state(msg), + linphone_chat_message_get_appdata(msg), + linphone_chat_message_get_message_id(msg), + linphone_chat_message_get_content_type(msg), + linphone_chat_message_get_storage_id(msg) ); linphone_sql_request(lc->db, buf); sqlite3_free(buf); @@ -294,20 +291,20 @@ void linphone_chat_message_store_update(LinphoneChatMessage *msg) { } void linphone_chat_message_store_state(LinphoneChatMessage *msg){ - LinphoneCore *lc=linphone_chat_room_get_core(msg->chat_room); + LinphoneCore *lc=linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)); if (lc->db){ char *buf=sqlite3_mprintf("UPDATE history SET status=%i WHERE (id = %u);", - msg->state,msg->storage_id); + linphone_chat_message_get_state(msg), linphone_chat_message_get_storage_id(msg)); linphone_sql_request(lc->db,buf); sqlite3_free(buf); } } void linphone_chat_message_store_appdata(LinphoneChatMessage* msg){ - LinphoneCore *lc=linphone_chat_room_get_core(msg->chat_room); + LinphoneCore *lc=linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)); if (lc->db){ char *buf=sqlite3_mprintf("UPDATE history SET appdata=%Q WHERE id=%u;", - msg->appdata,msg->storage_id); + linphone_chat_message_get_appdata(msg), linphone_chat_message_get_storage_id(msg)); linphone_sql_request(lc->db,buf); sqlite3_free(buf); } diff --git a/coreapi/private.h b/coreapi/private.h index 06652f862..2b57ff947 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -129,11 +129,6 @@ extern "C" { #define STRING_TRANSFER(field, newvalue) do{ if (field){bctbx_free(field);field=NULL;}; field=newvalue; }while(0) -typedef enum _ImdnType { - ImdnTypeDelivery, - ImdnTypeDisplay -} ImdnType; - struct _LinphoneQualityReporting{ reporting_session_report_t * reports[3]; /**Store information on audio and video media streams (RFC 6035) */ @@ -174,14 +169,9 @@ typedef struct _CallCallbackObj void * _user_data; }CallCallbackObj; -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneChatMessageCbs); +//BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneChatMessageCbs); -typedef enum _LinphoneChatMessageDir{ - LinphoneChatMessageIncoming, - LinphoneChatMessageOutgoing -} LinphoneChatMessageDir; - -struct _LinphoneChatMessage { +/*struct _LinphoneChatMessage { belle_sip_object_t base; LinphoneChatRoom* chat_room; LinphoneChatMessageCbs *callbacks; @@ -201,11 +191,11 @@ struct _LinphoneChatMessage { unsigned int storage_id; char *message_id; SalOp *op; - LinphoneContent *file_transfer_information; /**< used to store file transfer information when the message is of file transfer type */ - char *content_type; /**< is used to specified the type of message to be sent, used only for file transfer message */ + LinphoneContent *file_transfer_information; //< used to store file transfer information when the message is of file transfer type + char *content_type; //< is used to specified the type of message to be sent, used only for file transfer message bool_t to_be_stored; - belle_http_request_t *http_request; /**< keep a reference to the http_request in case of file transfer in order to be able to cancel the transfer */ - belle_http_request_listener_t *http_listener; /* our listener, only owned by us*/ + belle_http_request_t *http_request; //< keep a reference to the http_request in case of file transfer in order to be able to cancel the transfer + belle_http_request_listener_t *http_listener; // our listener, only owned by us char *file_transfer_filepath; unsigned long bg_task_id; bool_t is_secured; @@ -223,9 +213,7 @@ struct _LinphoneChatMessage { #if defined(__clang__) || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) #pragma GCC diagnostic pop #endif -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneChatMessage); +};*/ typedef struct StunCandidate{ char addr[64]; @@ -500,22 +488,6 @@ void linphone_chat_room_release(LinphoneChatRoom *cr); void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call); bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr); LinphoneChatRoomCbs * linphone_chat_room_cbs_new (void); -void linphone_chat_message_destroy(LinphoneChatMessage* msg); -void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state); -void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessageState state); -void linphone_chat_message_set_is_secured(LinphoneChatMessage *msg, bool_t secured); -void linphone_chat_message_send_delivery_notification(LinphoneChatMessage *cm, LinphoneReason reason); -void linphone_chat_message_send_display_notification(LinphoneChatMessage *cm); -void _linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg, bool_t unref); -int linphone_chat_room_upload_file(LinphoneChatMessage *msg); -LinphoneChatMessageCbs *linphone_chat_message_cbs_new(void); -LinphoneChatRoom *_linphone_core_create_chat_room_from_call(LinphoneCall *call); -void linphone_chat_room_remove_transient_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg); -void linphone_chat_message_deactivate(LinphoneChatMessage *msg); -void linphone_chat_message_release(LinphoneChatMessage *msg); -void create_file_transfer_information_from_vnd_gsma_rcs_ft_http_xml(LinphoneChatMessage *msg); -void linphone_chat_message_fetch_content_from_database(sqlite3 *db, LinphoneChatMessage *message, int content_id); -void linphone_chat_message_send_imdn(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason); /**/ struct _LinphoneProxyConfig diff --git a/include/linphone/api/c-callbacks.h b/include/linphone/api/c-callbacks.h index e1d9fd7c9..d44de7925 100644 --- a/include/linphone/api/c-callbacks.h +++ b/include/linphone/api/c-callbacks.h @@ -33,6 +33,50 @@ * @addtogroup chatroom * @{ */ + + /** + * Call back used to notify message delivery status + * @param msg #LinphoneChatMessage object + * @param status LinphoneChatMessageState + * @param ud application user data + * @deprecated Use LinphoneChatMessageCbsMsgStateChangedCb instead. + * @donotwrap + */ +typedef void (*LinphoneChatMessageStateChangedCb)(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud); + +/** + * Call back used to notify message delivery status + * @param msg #LinphoneChatMessage object + * @param status LinphoneChatMessageState + */ +typedef void (*LinphoneChatMessageCbsMsgStateChangedCb)(LinphoneChatMessage* msg, LinphoneChatMessageState state); + +/** + * File transfer receive callback prototype. This function is called by the core upon an incoming File transfer is started. This function may be call several time for the same file in case of large file. + * @param message #LinphoneChatMessage message from which the body is received. + * @param content #LinphoneContent incoming content information + * @param buffer #LinphoneBuffer holding the received data. Empty buffer means end of file. + */ +typedef void (*LinphoneChatMessageCbsFileTransferRecvCb)(LinphoneChatMessage *message, const LinphoneContent* content, const LinphoneBuffer *buffer); + +/** + * File transfer send callback prototype. This function is called by the core when an outgoing file transfer is started. This function is called until size is set to 0. + * @param message #LinphoneChatMessage message from which the body is received. + * @param content #LinphoneContent outgoing content + * @param offset the offset in the file from where to get the data to be sent + * @param size the number of bytes expected by the framework + * @return A LinphoneBuffer object holding the data written by the application. An empty buffer means end of file. + */ +typedef LinphoneBuffer * (*LinphoneChatMessageCbsFileTransferSendCb)(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t size); + +/** + * File transfer progress indication callback prototype. + * @param message #LinphoneChatMessage message from which the body is received. + * @param content #LinphoneContent incoming content information + * @param offset The number of bytes sent/received since the beginning of the transfer. + * @param total The total number of bytes to be sent/received. + */ +typedef void (*LinphoneChatMessageCbsFileTransferProgressIndicationCb)(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total); /** * Is composing notification callback prototype. diff --git a/include/linphone/api/c-chat-message-cbs.h b/include/linphone/api/c-chat-message-cbs.h index 290e13089..3bfac6b14 100644 --- a/include/linphone/api/c-chat-message-cbs.h +++ b/include/linphone/api/c-chat-message-cbs.h @@ -32,6 +32,8 @@ * @addtogroup chatroom * @{ */ + +LinphoneChatMessageCbs *linphone_chat_message_cbs_new(void); /** * Acquire a reference to the chat room callbacks object. diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index f6979295e..03cc38816 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -19,7 +19,25 @@ #ifndef _C_CHAT_MESSAGE_H_ #define _C_CHAT_MESSAGE_H_ +#include "sal/sal.h" #include "linphone/api/c-types.h" +#include "linphone/api/c-chat-message-cbs.h" + +#ifdef SQLITE_STORAGE_ENABLED +#include +#endif + +// ============================================================================= + +typedef enum _ImdnType { + ImdnTypeDelivery, + ImdnTypeDisplay +} ImdnType; + +typedef enum _LinphoneChatMessageDir{ + LinphoneChatMessageIncoming, + LinphoneChatMessageOutgoing +} LinphoneChatMessageDir; // ============================================================================= @@ -59,6 +77,352 @@ LINPHONE_PUBLIC void *linphone_chat_message_get_user_data(const LinphoneChatMess **/ LINPHONE_PUBLIC void linphone_chat_message_set_user_data(LinphoneChatMessage *msg, void *ud); +// ============================================================================= + +LINPHONE_PUBLIC const char * linphone_chat_message_get_external_body_url(const LinphoneChatMessage *msg); + +LINPHONE_PUBLIC void linphone_chat_message_set_external_body_url(LinphoneChatMessage *msg, const char *external_body_url); + +/** + * Get the time the message was sent. + */ +LINPHONE_PUBLIC time_t linphone_chat_message_get_time(const LinphoneChatMessage* msg); + +/** + * Returns TRUE if the message has been sent, returns FALSE if the message has been received. + * @param message the message +**/ +LINPHONE_PUBLIC bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage* msg); + +/** + * Set origin of the message + * @param[in] message #LinphoneChatMessage obj + * @param[in] from #LinphoneAddress origin of this message (copied) + */ +LINPHONE_PUBLIC void linphone_chat_message_set_from_address(LinphoneChatMessage* msg, const LinphoneAddress* from); + +/** + * Get origin of the message + * @param[in] message #LinphoneChatMessage obj + * @return #LinphoneAddress + */ +LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_from_address(const LinphoneChatMessage* msg); + +/** + * Set destination of the message + * @param[in] message #LinphoneChatMessage obj + * @param[in] addr #LinphoneAddress destination of this message (copied) + */ +LINPHONE_PUBLIC void linphone_chat_message_set_to_address(LinphoneChatMessage* msg, const LinphoneAddress* addr); + +/** + * Get destination of the message + * @param[in] message #LinphoneChatMessage obj + * @return #LinphoneAddress + */ +LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_to_address(const LinphoneChatMessage* msg); + +/** + * Get the content type of a chat message. + * @param[in] message LinphoneChatMessage object + * @return The content type of the chat message + */ +LINPHONE_PUBLIC const char * linphone_chat_message_get_content_type(const LinphoneChatMessage *msg); + +/** + * Set the content type of a chat message. + * This content type must match a content that is text representable, such as text/plain, text/html or image/svg+xml. + * @param[in] message LinphoneChatMessage object + * @param[in] content_type The new content type of the chat message + */ +LINPHONE_PUBLIC void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char *content_type); + +/** + * Get text part of this message + * @return text or NULL if no text. + */ +LINPHONE_PUBLIC const char* linphone_chat_message_get_text(const LinphoneChatMessage* msg); + +/** + * Returns the id used to identify this message in the storage database + * @param message the message + * @return the id + */ +LINPHONE_PUBLIC unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage* msg); + +/** + * Get the message identifier. + * It is used to identify a message so that it can be notified as delivered and/or displayed. + * @param[in] cm LinphoneChatMessage object + * @return The message identifier. + */ +LINPHONE_PUBLIC const char* linphone_chat_message_get_message_id(const LinphoneChatMessage *msg); + +/** + * Linphone message has an app-specific field that can store a text. The application might want + * to use it for keeping data over restarts, like thumbnail image path. + * @param message #LinphoneChatMessage + * @return the application-specific data or NULL if none has been stored. + */ +LINPHONE_PUBLIC const char* linphone_chat_message_get_appdata(const LinphoneChatMessage* message); + +/** + * Linphone message has an app-specific field that can store a text. The application might want + * to use it for keeping data over restarts, like thumbnail image path. + * + * Invoking this function will attempt to update the message storage to reflect the changeif it is + * enabled. + * + * @param message #LinphoneChatMessage + * @param data the data to store into the message + */ +LINPHONE_PUBLIC void linphone_chat_message_set_appdata(LinphoneChatMessage* message, const char* data); + +/** + * Returns the chatroom this message belongs to. +**/ +LINPHONE_PUBLIC LinphoneChatRoom* linphone_chat_message_get_chat_room(const LinphoneChatMessage *msg); + +/** + * Get the path to the file to read from or write to during the file transfer. + * @param[in] msg LinphoneChatMessage object + * @return The path to the file to use for the file transfer. + */ +LINPHONE_PUBLIC const char * linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage *msg); + +// ============================================================================= + +void linphone_chat_message_set_time(LinphoneChatMessage* msg, time_t time); + +void linphone_chat_message_set_incoming(LinphoneChatMessage *msg); + +void linphone_chat_message_set_outgoing(LinphoneChatMessage *msg); + +void linphone_chat_message_set_message_state_changed_cb(LinphoneChatMessage* msg, LinphoneChatMessageStateChangedCb cb); + +void linphone_chat_message_set_message_state_changed_cb_user_data(LinphoneChatMessage* msg, void *user_data); + +void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChatMessage* msg); + +void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessageState state); + +void linphone_chat_message_set_message_id(LinphoneChatMessage *msg, char *id); + +void linphone_chat_message_set_is_read(LinphoneChatMessage *msg, bool_t is_read); + +void linphone_chat_message_set_storage_id(LinphoneChatMessage *msg, unsigned int id); + +SalCustomHeader * linphone_chat_message_get_sal_custom_headers(const LinphoneChatMessage *msg); + +void linphone_chat_message_set_sal_custom_headers(LinphoneChatMessage *msg, SalCustomHeader *header); + +belle_http_request_t * linphone_chat_message_get_http_request(const LinphoneChatMessage *msg); + +void linphone_chat_message_set_http_request(LinphoneChatMessage *msg, belle_http_request_t *request); + +void linphone_chat_message_set_file_transfer_information(LinphoneChatMessage *msg, LinphoneContent *content); + +LinphoneChatMessageDir linphone_chat_message_get_direction(const LinphoneChatMessage *msg); + +SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg); + +void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, SalOp *op); + +void linphone_chat_message_set_chat_room(LinphoneChatMessage *msg, LinphoneChatRoom *room); + +// ============================================================================= + +LINPHONE_PUBLIC unsigned int linphone_chat_message_store(LinphoneChatMessage *msg); + +/** + * Get the state of the message + *@param message #LinphoneChatMessage obj + *@return #LinphoneChatMessageState + */ +LINPHONE_PUBLIC LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage* message); + +/** + * Duplicate a LinphoneChatMessage +**/ +LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* message); + +/** + * Get if the message was encrypted when transfered + * @param[in] message #LinphoneChatMessage obj + * @return whether the message was encrypted when transfered or not + */ +LINPHONE_PUBLIC bool_t linphone_chat_message_is_secured(LinphoneChatMessage *msg); + +/** + * Linphone message can carry external body as defined by rfc2017 + * @param message #LinphoneChatMessage + * @return external body url or NULL if not present. + */ +LINPHONE_PUBLIC const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message); + +/** + * Linphone message can carry external body as defined by rfc2017 + * + * @param message a LinphoneChatMessage + * @param url ex: access-type=URL; URL="http://www.foo.com/file" + */ +LINPHONE_PUBLIC void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url); + +/** + * Get the file_transfer_information (used by call backs to recover informations during a rcs file transfer) + * + * @param message #LinphoneChatMessage + * @return a pointer to the LinphoneContent structure or NULL if not present. + */ +LINPHONE_PUBLIC LinphoneContent* linphone_chat_message_get_file_transfer_information(LinphoneChatMessage* message); + +/** + * Return whether or not a chat message is a file tranfer. + * @param[in] message LinphoneChatMessage object + * @return Whether or not the message is a file tranfer + */ +LINPHONE_PUBLIC bool_t linphone_chat_message_is_file_transfer(const LinphoneChatMessage *message); + +/** + * Return whether or not a chat message is a text. + * @param[in] message LinphoneChatMessage object + * @return Whether or not the message is a text + */ +LINPHONE_PUBLIC bool_t linphone_chat_message_is_text(const LinphoneChatMessage *message); + +/** + * Get if a chat message is to be stored. + * @param[in] message LinphoneChatMessage object + * @return Whether or not the message is to be stored + */ +LINPHONE_PUBLIC bool_t linphone_chat_message_get_to_be_stored(const LinphoneChatMessage *message); + +/** + * Set if a chat message is to be stored. + * This content type must match a content that is text representable, such as text/plain, text/html or image/svg+xml. + * @param[in] message LinphoneChatMessage object + * @param[in] to_be_stored Whether or not the chat message is to be stored + */ +LINPHONE_PUBLIC void linphone_chat_message_set_to_be_stored(LinphoneChatMessage *message, bool_t to_be_stored); + +/** + * Start the download of the file from remote server + * + * @param message #LinphoneChatMessage + * @param status_cb LinphoneChatMessageStateChangeCb status callback invoked when file is downloaded or could not be downloaded + * @param ud user data + * @deprecated Use linphone_chat_message_download_file() instead. + * @donotwrap + */ +LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_chat_message_start_file_download(LinphoneChatMessage* message, LinphoneChatMessageStateChangedCb status_cb, void* ud); + +/** + * Start the download of the file referenced in a LinphoneChatMessage from remote server. + * @param[in] message LinphoneChatMessage object. + */ +LINPHONE_PUBLIC LinphoneStatus linphone_chat_message_download_file(LinphoneChatMessage *message); + +/** + * Cancel an ongoing file transfer attached to this message.(upload or download) + * @param msg #LinphoneChatMessage + */ +LINPHONE_PUBLIC void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage* msg); + +/** + * Resend a chat message if it is in the 'not delivered' state for whatever reason. + * @param[in] msg LinphoneChatMessage object + * @donotwrap + */ +LINPHONE_PUBLIC void linphone_chat_message_resend(LinphoneChatMessage *msg); + +LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, const bctbx_list_t *addresses); + +LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg); + +/** + * Returns the origin address of a message if it was a outgoing message, or the destination address if it was an incoming message. + *@param message #LinphoneChatMessage obj + *@return #LinphoneAddress + */ +LINPHONE_PUBLIC LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessage* message); + +/** + * Add custom headers to the message. + * @param message the message + * @param header_name name of the header + * @param header_value header value +**/ +LINPHONE_PUBLIC void linphone_chat_message_add_custom_header(LinphoneChatMessage* message, const char *header_name, const char *header_value); + +/** + * Retrieve a custom header value given its name. + * @param message the message + * @param header_name header name searched +**/ +LINPHONE_PUBLIC const char * linphone_chat_message_get_custom_header(LinphoneChatMessage* message, const char *header_name); + +/** + * Removes a custom header from the message. + * @param msg the message + * @param header_name name of the header to remove +**/ +LINPHONE_PUBLIC void linphone_chat_message_remove_custom_header(LinphoneChatMessage *msg, const char *header_name); + +/** + * Returns TRUE if the message has been read, otherwise returns FALSE. + * @param message the message +**/ +LINPHONE_PUBLIC bool_t linphone_chat_message_is_read(LinphoneChatMessage* message); + +LINPHONE_PUBLIC LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage* msg); + +/** + * Get full details about delivery error of a chat message. + * @param msg a LinphoneChatMessage + * @return a LinphoneErrorInfo describing the details. +**/ +LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg); + +/** + * Set the path to the file to read from or write to during the file transfer. + * @param[in] msg LinphoneChatMessage object + * @param[in] filepath The path to the file to use for the file transfer. + */ +LINPHONE_PUBLIC void linphone_chat_message_set_file_transfer_filepath(LinphoneChatMessage *msg, const char *filepath); + +/** + * Fulfill a chat message char by char. Message linked to a Real Time Text Call send char in realtime following RFC 4103/T.140 + * To commit a message, use #linphone_chat_room_send_message + * @param[in] msg LinphoneChatMessage + * @param[in] character T.140 char + * @returns 0 if succeed. + */ +LINPHONE_PUBLIC LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg,uint32_t character); + +/** + * Get the LinphoneChatMessageCbs object associated with the LinphoneChatMessage. + * @param[in] msg LinphoneChatMessage object + * @return The LinphoneChatMessageCbs object associated with the LinphoneChatMessage. + */ +LINPHONE_PUBLIC LinphoneChatMessageCbs * linphone_chat_message_get_callbacks(const LinphoneChatMessage *msg); + +// ============================================================================= + +void linphone_chat_message_destroy(LinphoneChatMessage* msg); +void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state); +void linphone_chat_message_set_is_secured(LinphoneChatMessage *msg, bool_t secured); +void linphone_chat_message_send_delivery_notification(LinphoneChatMessage *cm, LinphoneReason reason); +void linphone_chat_message_send_display_notification(LinphoneChatMessage *cm); +void _linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg, bool_t unref); +int linphone_chat_room_upload_file(LinphoneChatMessage *msg); +LinphoneChatRoom *_linphone_core_create_chat_room_from_call(LinphoneCall *call); +void linphone_chat_room_remove_transient_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg); +void linphone_chat_message_deactivate(LinphoneChatMessage *msg); +void linphone_chat_message_release(LinphoneChatMessage *msg); +void create_file_transfer_information_from_vnd_gsma_rcs_ft_http_xml(LinphoneChatMessage *msg); +void linphone_chat_message_fetch_content_from_database(sqlite3 *db, LinphoneChatMessage *message, int content_id); +void linphone_chat_message_send_imdn(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason); + /** * @} */ diff --git a/include/linphone/callbacks.h b/include/linphone/callbacks.h index f9f892570..d99128a2d 100644 --- a/include/linphone/callbacks.h +++ b/include/linphone/callbacks.h @@ -30,50 +30,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * @{ */ -/** - * Call back used to notify message delivery status - * @param msg #LinphoneChatMessage object - * @param status LinphoneChatMessageState - * @param ud application user data - * @deprecated Use LinphoneChatMessageCbsMsgStateChangedCb instead. - * @donotwrap - */ -typedef void (*LinphoneChatMessageStateChangedCb)(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud); - -/** - * Call back used to notify message delivery status - * @param msg #LinphoneChatMessage object - * @param status LinphoneChatMessageState - */ -typedef void (*LinphoneChatMessageCbsMsgStateChangedCb)(LinphoneChatMessage* msg, LinphoneChatMessageState state); - -/** - * File transfer receive callback prototype. This function is called by the core upon an incoming File transfer is started. This function may be call several time for the same file in case of large file. - * @param message #LinphoneChatMessage message from which the body is received. - * @param content #LinphoneContent incoming content information - * @param buffer #LinphoneBuffer holding the received data. Empty buffer means end of file. - */ -typedef void (*LinphoneChatMessageCbsFileTransferRecvCb)(LinphoneChatMessage *message, const LinphoneContent* content, const LinphoneBuffer *buffer); - -/** - * File transfer send callback prototype. This function is called by the core when an outgoing file transfer is started. This function is called until size is set to 0. - * @param message #LinphoneChatMessage message from which the body is received. - * @param content #LinphoneContent outgoing content - * @param offset the offset in the file from where to get the data to be sent - * @param size the number of bytes expected by the framework - * @return A LinphoneBuffer object holding the data written by the application. An empty buffer means end of file. - */ -typedef LinphoneBuffer * (*LinphoneChatMessageCbsFileTransferSendCb)(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t size); - -/** - * File transfer progress indication callback prototype. - * @param message #LinphoneChatMessage message from which the body is received. - * @param content #LinphoneContent incoming content information - * @param offset The number of bytes sent/received since the beginning of the transfer. - * @param total The total number of bytes to be sent/received. - */ -typedef void (*LinphoneChatMessageCbsFileTransferProgressIndicationCb)(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total); - /** * @} **/ diff --git a/include/linphone/chat.h b/include/linphone/chat.h index 55cd9b2ea..1aec54c01 100644 --- a/include/linphone/chat.h +++ b/include/linphone/chat.h @@ -46,302 +46,7 @@ extern "C" { **/ LINPHONE_PUBLIC const bctbx_list_t* linphone_core_get_chat_rooms(LinphoneCore *lc); -LINPHONE_PUBLIC unsigned int linphone_chat_message_store(LinphoneChatMessage *msg); -/** - * Get the state of the message - *@param message #LinphoneChatMessage obj - *@return #LinphoneChatMessageState - */ -LINPHONE_PUBLIC LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage* message); - -/** - * Duplicate a LinphoneChatMessage -**/ -LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* message); - -/** - * Destroys a LinphoneChatMessage. -**/ -LINPHONE_PUBLIC void linphone_chat_message_destroy(LinphoneChatMessage* msg); - -/** @deprecated Use linphone_chat_message_set_from_address() instead. */ -#define linphone_chat_message_set_from(msg, addr) linphone_chat_message_set_from_address(msg, addr) - -/** - * Set origin of the message - * @param[in] message #LinphoneChatMessage obj - * @param[in] from #LinphoneAddress origin of this message (copied) - */ -LINPHONE_PUBLIC void linphone_chat_message_set_from_address(LinphoneChatMessage* message, const LinphoneAddress* from); - -/** @deprecated Use linphone_chat_message_get_from_address() instead. */ -#define linphone_chat_message_get_from(msg) linphone_chat_message_get_from_address(msg) - -/** - * Get origin of the message - * @param[in] message #LinphoneChatMessage obj - * @return #LinphoneAddress - */ -LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_from_address(const LinphoneChatMessage* message); - -#define linphone_chat_message_set_to(msg, addr) linphone_chat_message_set_to_address(msg, addr) - -/** - * Set destination of the message - * @param[in] message #LinphoneChatMessage obj - * @param[in] addr #LinphoneAddress destination of this message (copied) - */ -LINPHONE_PUBLIC void linphone_chat_message_set_to_address(LinphoneChatMessage* message, const LinphoneAddress* addr); - -/** @deprecated Use linphone_chat_message_get_to_address() instead. */ -#define linphone_chat_message_get_to(msg) linphone_chat_message_get_to_address(msg) - -/** - * Get destination of the message - * @param[in] message #LinphoneChatMessage obj - * @return #LinphoneAddress - */ -LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_to_address(const LinphoneChatMessage* message); - -/** - * Get if the message was encrypted when transfered - * @param[in] message #LinphoneChatMessage obj - * @return whether the message was encrypted when transfered or not - */ -LINPHONE_PUBLIC bool_t linphone_chat_message_is_secured(LinphoneChatMessage *msg); - -/** - * Linphone message can carry external body as defined by rfc2017 - * @param message #LinphoneChatMessage - * @return external body url or NULL if not present. - */ -LINPHONE_PUBLIC const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message); - -/** - * Linphone message can carry external body as defined by rfc2017 - * - * @param message a LinphoneChatMessage - * @param url ex: access-type=URL; URL="http://www.foo.com/file" - */ -LINPHONE_PUBLIC void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url); - -/** - * Get the file_transfer_information (used by call backs to recover informations during a rcs file transfer) - * - * @param message #LinphoneChatMessage - * @return a pointer to the LinphoneContent structure or NULL if not present. - */ -LINPHONE_PUBLIC const LinphoneContent* linphone_chat_message_get_file_transfer_information(const LinphoneChatMessage* message); - -/** - * Get the content type of a chat message. - * @param[in] message LinphoneChatMessage object - * @return The content type of the chat message - */ -LINPHONE_PUBLIC const char * linphone_chat_message_get_content_type(const LinphoneChatMessage *message); - -/** - * Set the content type of a chat message. - * This content type must match a content that is text representable, such as text/plain, text/html or image/svg+xml. - * @param[in] message LinphoneChatMessage object - * @param[in] content_type The new content type of the chat message - */ -LINPHONE_PUBLIC void linphone_chat_message_set_content_type(LinphoneChatMessage *message, const char *content_type); - -/** - * Return whether or not a chat message is a file tranfer. - * @param[in] message LinphoneChatMessage object - * @return Whether or not the message is a file tranfer - */ -LINPHONE_PUBLIC bool_t linphone_chat_message_is_file_transfer(const LinphoneChatMessage *message); - -/** - * Return whether or not a chat message is a text. - * @param[in] message LinphoneChatMessage object - * @return Whether or not the message is a text - */ -LINPHONE_PUBLIC bool_t linphone_chat_message_is_text(const LinphoneChatMessage *message); - -/** - * Get if a chat message is to be stored. - * @param[in] message LinphoneChatMessage object - * @return Whether or not the message is to be stored - */ -LINPHONE_PUBLIC bool_t linphone_chat_message_get_to_be_stored(const LinphoneChatMessage *message); - -/** - * Set if a chat message is to be stored. - * This content type must match a content that is text representable, such as text/plain, text/html or image/svg+xml. - * @param[in] message LinphoneChatMessage object - * @param[in] to_be_stored Whether or not the chat message is to be stored - */ -LINPHONE_PUBLIC void linphone_chat_message_set_to_be_stored(LinphoneChatMessage *message, bool_t to_be_stored); - -/** - * Start the download of the file from remote server - * - * @param message #LinphoneChatMessage - * @param status_cb LinphoneChatMessageStateChangeCb status callback invoked when file is downloaded or could not be downloaded - * @param ud user data - * @deprecated Use linphone_chat_message_download_file() instead. - * @donotwrap - */ -LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_chat_message_start_file_download(LinphoneChatMessage* message, LinphoneChatMessageStateChangedCb status_cb, void* ud); - -/** - * Start the download of the file referenced in a LinphoneChatMessage from remote server. - * @param[in] message LinphoneChatMessage object. - */ -LINPHONE_PUBLIC LinphoneStatus linphone_chat_message_download_file(LinphoneChatMessage *message); - -/** - * Cancel an ongoing file transfer attached to this message.(upload or download) - * @param msg #LinphoneChatMessage - */ -LINPHONE_PUBLIC void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage* msg); - -/** - * Resend a chat message if it is in the 'not delivered' state for whatever reason. - * @param[in] msg LinphoneChatMessage object - * @donotwrap - */ -LINPHONE_PUBLIC void linphone_chat_message_resend(LinphoneChatMessage *msg); - -/** - * Linphone message has an app-specific field that can store a text. The application might want - * to use it for keeping data over restarts, like thumbnail image path. - * @param message #LinphoneChatMessage - * @return the application-specific data or NULL if none has been stored. - */ -LINPHONE_PUBLIC const char* linphone_chat_message_get_appdata(const LinphoneChatMessage* message); - -/** - * Linphone message has an app-specific field that can store a text. The application might want - * to use it for keeping data over restarts, like thumbnail image path. - * - * Invoking this function will attempt to update the message storage to reflect the changeif it is - * enabled. - * - * @param message #LinphoneChatMessage - * @param data the data to store into the message - */ -LINPHONE_PUBLIC void linphone_chat_message_set_appdata(LinphoneChatMessage* message, const char* data); - -/** - * Get text part of this message - * @return text or NULL if no text. - */ -LINPHONE_PUBLIC const char* linphone_chat_message_get_text(const LinphoneChatMessage* message); - -/** - * Get the time the message was sent. - */ -LINPHONE_PUBLIC time_t linphone_chat_message_get_time(const LinphoneChatMessage* message); - -/** - * Returns the chatroom this message belongs to. -**/ -LINPHONE_PUBLIC LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg); - -LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, const bctbx_list_t *addresses); - -LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg); - -/** - * Returns the origin address of a message if it was a outgoing message, or the destination address if it was an incoming message. - *@param message #LinphoneChatMessage obj - *@return #LinphoneAddress - */ -LINPHONE_PUBLIC LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessage* message); - -/** - * Add custom headers to the message. - * @param message the message - * @param header_name name of the header - * @param header_value header value -**/ -LINPHONE_PUBLIC void linphone_chat_message_add_custom_header(LinphoneChatMessage* message, const char *header_name, const char *header_value); - -/** - * Retrieve a custom header value given its name. - * @param message the message - * @param header_name header name searched -**/ -LINPHONE_PUBLIC const char * linphone_chat_message_get_custom_header(LinphoneChatMessage* message, const char *header_name); - -/** - * Removes a custom header from the message. - * @param msg the message - * @param header_name name of the header to remove -**/ -LINPHONE_PUBLIC void linphone_chat_message_remove_custom_header(LinphoneChatMessage *msg, const char *header_name); - -/** - * Returns TRUE if the message has been read, otherwise returns FALSE. - * @param message the message -**/ -LINPHONE_PUBLIC bool_t linphone_chat_message_is_read(LinphoneChatMessage* message); - -/** - * Returns TRUE if the message has been sent, returns FALSE if the message has been received. - * @param message the message -**/ -LINPHONE_PUBLIC bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage* message); - -/** - * Returns the id used to identify this message in the storage database - * @param message the message - * @return the id - */ -LINPHONE_PUBLIC unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage* message); - -LINPHONE_PUBLIC LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage* msg); - -/** - * Get full details about delivery error of a chat message. - * @param msg a LinphoneChatMessage - * @return a LinphoneErrorInfo describing the details. -**/ -LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg); - -/** - * Set the path to the file to read from or write to during the file transfer. - * @param[in] msg LinphoneChatMessage object - * @param[in] filepath The path to the file to use for the file transfer. - */ -LINPHONE_PUBLIC void linphone_chat_message_set_file_transfer_filepath(LinphoneChatMessage *msg, const char *filepath); - -/** - * Get the path to the file to read from or write to during the file transfer. - * @param[in] msg LinphoneChatMessage object - * @return The path to the file to use for the file transfer. - */ -LINPHONE_PUBLIC const char * linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage *msg); - -/** - * Fulfill a chat message char by char. Message linked to a Real Time Text Call send char in realtime following RFC 4103/T.140 - * To commit a message, use #linphone_chat_room_send_message - * @param[in] msg LinphoneChatMessage - * @param[in] character T.140 char - * @returns 0 if succeed. - */ -LINPHONE_PUBLIC LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg,uint32_t character); - -/** - * Get the message identifier. - * It is used to identify a message so that it can be notified as delivered and/or displayed. - * @param[in] cm LinphoneChatMessage object - * @return The message identifier. - */ -LINPHONE_PUBLIC const char* linphone_chat_message_get_message_id(const LinphoneChatMessage *cm); - -/** - * Get the LinphoneChatMessageCbs object associated with the LinphoneChatMessage. - * @param[in] msg LinphoneChatMessage object - * @return The LinphoneChatMessageCbs object associated with the LinphoneChatMessage. - */ -LINPHONE_PUBLIC LinphoneChatMessageCbs * linphone_chat_message_get_callbacks(const LinphoneChatMessage *msg); /** * @} diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 1f8d1d8b4..1752dd939 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -18,10 +18,16 @@ #include "linphone/chat.h" #include "linphone/wrapper_utils.h" +#include "linphone/utils/utils.h" +#include "ortp/b64.h" // TODO: Remove me later. #include "private.h" +#include "chat/chat-room.h" +#include "chat/chat-room-p.h" +#include "chat/real-time-text-chat-room-p.h" +#include "content/content-type.h" #include "c-wrapper/c-tools.h" #include "chat/chat-message.h" #include "chat/chat-message-p.h" @@ -33,6 +39,49 @@ using namespace std; +static void _linphone_chat_message_constructor (LinphoneChatMessage *msg); +static void _linphone_chat_message_destructor (LinphoneChatMessage *msg); + +L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(ChatMessage, ChatMessage, chat_message, + _linphone_chat_message_constructor, _linphone_chat_message_destructor, + LinphoneChatMessageCbs *cbs; + LinphoneChatRoom* chat_room; + LinphoneErrorInfo *ei; + LinphoneChatMessageDir dir; + char* message; + void* message_userdata; + char* appdata; + char* external_body_url; + LinphoneAddress *from; + LinphoneAddress *to; + time_t time; + SalCustomHeader *sal_custom_headers; + LinphoneChatMessageState state; + bool_t is_read; + unsigned int storage_id; + char *message_id; + SalOp *op; + LinphoneContent *file_transfer_information; //< used to store file transfer information when the message is of file transfer type + char *content_type; //< is used to specified the type of message to be sent, used only for file transfer message + bool_t to_be_stored; + belle_http_request_t *http_request; //< keep a reference to the http_request in case of file transfer in order to be able to cancel the transfer + belle_http_request_listener_t *http_listener; // our listener, only owned by us + char *file_transfer_filepath; + unsigned long bg_task_id; + bool_t is_secured; + LinphoneChatMessageStateChangedCb message_state_changed_cb; + void* message_state_changed_user_data; +) + +static void _linphone_chat_message_constructor (LinphoneChatMessage *msg) { + msg->cbs = linphone_chat_message_cbs_new(); +} + +static void _linphone_chat_message_destructor (LinphoneChatMessage *msg) { + linphone_chat_message_cbs_unref(msg->cbs); + msg->cbs = nullptr; +} + // ============================================================================= // Reference and user data handling functions. // ============================================================================= @@ -53,3 +102,1151 @@ void * linphone_chat_message_get_user_data (const LinphoneChatMessage *msg) { void linphone_chat_message_set_user_data (LinphoneChatMessage *msg, void *ud) { L_SET_USER_DATA_FROM_C_STRUCT(msg, ud, ChatMessage); } + + +// ============================================================================= +// Getter and setters +// ============================================================================= + +const char *linphone_chat_message_get_external_body_url(const LinphoneChatMessage *msg) { + return msg->external_body_url; +} + +void linphone_chat_message_set_external_body_url(LinphoneChatMessage *msg, const char *url) { + if (msg->external_body_url) { + ms_free(msg->external_body_url); + } + msg->external_body_url = url ? ms_strdup(url) : NULL; +} + +time_t linphone_chat_message_get_time(const LinphoneChatMessage *msg) { + return msg->time; +} + +void linphone_chat_message_set_time(LinphoneChatMessage *msg, time_t time) { + msg->time = time; +} + +void linphone_chat_message_set_is_secured(LinphoneChatMessage *msg, bool_t secured) { + msg->is_secured = secured; +} + +bool_t linphone_chat_message_is_secured(LinphoneChatMessage *msg) { + return msg->is_secured; +} + +bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage *msg) { + return msg->dir == LinphoneChatMessageOutgoing; +} + +void linphone_chat_message_set_incoming(LinphoneChatMessage *msg) { + msg->dir = LinphoneChatMessageIncoming; +} + +void linphone_chat_message_set_outgoing(LinphoneChatMessage *msg) { + msg->dir = LinphoneChatMessageOutgoing; +} + +void linphone_chat_message_set_from_address(LinphoneChatMessage *msg, const LinphoneAddress *from) { + if (msg->from) + linphone_address_unref(msg->from); + msg->from = linphone_address_clone(from); +} + +const LinphoneAddress *linphone_chat_message_get_from_address(const LinphoneChatMessage *msg) { + return msg->from; +} + +void linphone_chat_message_set_to_address(LinphoneChatMessage *msg, const LinphoneAddress *to) { + if (msg->to) + linphone_address_unref(msg->to); + msg->to = linphone_address_clone(to); +} + +const LinphoneAddress *linphone_chat_message_get_to_address(const LinphoneChatMessage *msg) { + if (msg->to) + return msg->to; + if (msg->dir == LinphoneChatMessageOutgoing) { + return linphone_chat_room_get_peer_address(msg->chat_room); + } + return NULL; +} + +void linphone_chat_message_set_message_state_changed_cb(LinphoneChatMessage* msg, LinphoneChatMessageStateChangedCb cb) { + msg->message_state_changed_cb = cb; +} + +void linphone_chat_message_set_message_state_changed_cb_user_data(LinphoneChatMessage* msg, void *user_data) { + msg->message_state_changed_user_data = user_data; +} + +void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChatMessage* msg) { + return msg->message_state_changed_user_data; +} + +const char * linphone_chat_message_get_content_type(const LinphoneChatMessage *msg) { + return msg->content_type; +} + +void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char *content_type) { + if (msg->content_type) { + ms_free(msg->content_type); + } + msg->content_type = content_type ? ms_strdup(content_type) : NULL; +} + +const char *linphone_chat_message_get_text(const LinphoneChatMessage *msg) { + return msg->message; +} + +int linphone_chat_message_set_text(LinphoneChatMessage *msg, const char* text) { + if (msg->message) + ms_free(msg->message); + if (text) + msg->message = ms_strdup(text); + else + msg->message = NULL; + + return 0; +} + +unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage *msg) { + return msg->storage_id; +} + +void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessageState state) { + /* do not invoke callbacks on orphan messages */ + if (state != msg->state && msg->chat_room != NULL) { + if (((msg->state == LinphoneChatMessageStateDisplayed) || (msg->state == LinphoneChatMessageStateDeliveredToUser)) + && ((state == LinphoneChatMessageStateDeliveredToUser) || (state == LinphoneChatMessageStateDelivered) || (state == LinphoneChatMessageStateNotDelivered))) { + /* If the message has been displayed or delivered to user we must not go back to the delivered or not delivered state. */ + return; + } + ms_message("Chat message %p: moving from state %s to %s", msg, linphone_chat_message_state_to_string(msg->state), + linphone_chat_message_state_to_string(state)); + msg->state = state; + if (msg->message_state_changed_cb) { + msg->message_state_changed_cb(msg, msg->state, msg->message_state_changed_user_data); + } + if (linphone_chat_message_cbs_get_msg_state_changed(msg->cbs)) { + linphone_chat_message_cbs_get_msg_state_changed(msg->cbs)(msg, msg->state); + } + } +} + +const char* linphone_chat_message_get_message_id(const LinphoneChatMessage *msg) { + return msg->message_id; +} + +void linphone_chat_message_set_message_id(LinphoneChatMessage *msg, char *id) { + msg->message_id = id; +} + +void linphone_chat_message_set_is_read(LinphoneChatMessage *msg, bool_t is_read) { + msg->is_read = is_read; +} + +void linphone_chat_message_set_storage_id(LinphoneChatMessage *msg, unsigned int id) { + msg->storage_id = id; +} + +const char *linphone_chat_message_get_appdata(const LinphoneChatMessage *msg) { + return msg->appdata; +} + +void linphone_chat_message_set_appdata(LinphoneChatMessage *msg, const char *data) { + if (msg->appdata) { + ms_free(msg->appdata); + } + msg->appdata = data ? ms_strdup(data) : NULL; + linphone_chat_message_store_appdata(msg); +} + +SalCustomHeader * linphone_chat_message_get_sal_custom_headers(const LinphoneChatMessage *msg) { + return msg->sal_custom_headers; +} + +void linphone_chat_message_set_sal_custom_headers(LinphoneChatMessage *msg, SalCustomHeader *header) { + msg->sal_custom_headers = header; +} + +belle_http_request_t * linphone_chat_message_get_http_request(LinphoneChatMessage *msg) { + return msg->http_request; +} + +void linphone_chat_message_set_http_request(LinphoneChatMessage *msg, belle_http_request_t *request) { + msg->http_request = request; +} + +void linphone_chat_message_set_file_transfer_information(LinphoneChatMessage *msg, LinphoneContent *content) { + msg->file_transfer_information = content; +} + +LinphoneChatMessageDir linphone_chat_message_get_direction(const LinphoneChatMessage *msg) { + return msg->dir; +} + +LinphoneChatRoom *linphone_chat_message_get_chat_room(const LinphoneChatMessage *msg) { + return msg->chat_room; +} + +SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg) { + return msg->op; +} + +void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, SalOp *op) { + msg->op = op; +} + +void linphone_chat_message_set_chat_room(LinphoneChatMessage *msg, LinphoneChatRoom *room) { + msg->chat_room = room; +} + +const char *linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage *msg) { + return msg->file_transfer_filepath; +} + +// ============================================================================= + +void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state) { + linphone_chat_message_set_state(msg, new_state); + linphone_chat_message_store_state(msg); + + if (msg->state == LinphoneChatMessageStateDelivered || msg->state == LinphoneChatMessageStateNotDelivered) { + L_GET_PRIVATE_FROM_C_STRUCT(msg->chat_room, ChatRoom)->moveTransientMessageToWeakMessages(msg); + } +} + +void _linphone_chat_message_resend(LinphoneChatMessage *msg, bool_t ref_msg) { + LinphoneChatMessageState state = linphone_chat_message_get_state(msg); + LinphoneChatRoom *cr; + + if (state != LinphoneChatMessageStateNotDelivered) { + ms_warning("Cannot resend chat message in state %s", linphone_chat_message_state_to_string(state)); + return; + } + + cr = linphone_chat_message_get_chat_room(msg); + if (ref_msg) linphone_chat_message_ref(msg); + L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom)->sendMessage(msg); +} + +void linphone_chat_message_resend(LinphoneChatMessage *msg) { + _linphone_chat_message_resend(msg, FALSE); +} + +void linphone_chat_message_resend_2(LinphoneChatMessage *msg) { + _linphone_chat_message_resend(msg, TRUE); +} + +static char *linphone_chat_message_create_imdn_xml(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason) { + xmlBufferPtr buf; + xmlTextWriterPtr writer; + int err; + char *content = NULL; + char *datetime = NULL; + const char *message_id; + + /* Check that the chat message has a message id */ + message_id = linphone_chat_message_get_message_id(cm); + if (message_id == NULL) return NULL; + + buf = xmlBufferCreate(); + if (buf == NULL) { + ms_error("Error creating the XML buffer"); + return content; + } + writer = xmlNewTextWriterMemory(buf, 0); + if (writer == NULL) { + ms_error("Error creating the XML writer"); + return content; + } + + datetime = linphone_timestamp_to_rfc3339_string(linphone_chat_message_get_time(cm)); + err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); + if (err >= 0) { + err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"imdn", + (const xmlChar *)"urn:ietf:params:xml:ns:imdn"); + } + if ((err >= 0) && (reason != LinphoneReasonNone)) { + err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"linphoneimdn", NULL, (const xmlChar *)"http://www.linphone.org/xsds/imdn.xsd"); + } + if (err >= 0) { + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"message-id", (const xmlChar *)message_id); + } + if (err >= 0) { + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"datetime", (const xmlChar *)datetime); + } + if (err >= 0) { + if (imdn_type == ImdnTypeDelivery) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivery-notification"); + } else { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"display-notification"); + } + } + if (err >= 0) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"status"); + } + if (err >= 0) { + if (reason == LinphoneReasonNone) { + if (imdn_type == ImdnTypeDelivery) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivered"); + } else { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"displayed"); + } + } else { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"error"); + } + } + if (err >= 0) { + /* Close the "delivered", "displayed" or "error" element. */ + err = xmlTextWriterEndElement(writer); + } + if ((err >= 0) && (reason != LinphoneReasonNone)) { + err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"linphoneimdn", (const xmlChar *)"reason", NULL); + if (err >= 0) { + char codestr[16]; + snprintf(codestr, 16, "%d", linphone_reason_to_error_code(reason)); + err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"code", (const xmlChar *)codestr); + } + if (err >= 0) { + err = xmlTextWriterWriteString(writer, (const xmlChar *)linphone_reason_to_string(reason)); + } + if (err >= 0) { + err = xmlTextWriterEndElement(writer); + } + } + if (err >= 0) { + /* Close the "status" element. */ + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + /* Close the "delivery-notification" or "display-notification" element. */ + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + /* Close the "imdn" element. */ + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + err = xmlTextWriterEndDocument(writer); + } + if (err > 0) { + /* xmlTextWriterEndDocument returns the size of the content. */ + content = ms_strdup((char *)buf->content); + } + xmlFreeTextWriter(writer); + xmlBufferFree(buf); + ms_free(datetime); + return content; +} + +void linphone_chat_message_send_imdn(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason) { + char *content = linphone_chat_message_create_imdn_xml(cm, imdn_type, reason); + if (content) { + L_GET_PRIVATE_FROM_C_STRUCT(linphone_chat_message_get_chat_room(cm), ChatRoom)->sendImdn(content, reason); + ms_free(content); + } +} + +void linphone_chat_message_send_delivery_notification(LinphoneChatMessage *cm, LinphoneReason reason) { + LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(cm); + LinphoneCore *lc = linphone_chat_room_get_core(cr); + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); + if (linphone_im_notif_policy_get_send_imdn_delivered(policy) == TRUE) { + linphone_chat_message_send_imdn(cm, ImdnTypeDelivery, reason); + } +} + +void linphone_chat_message_send_display_notification(LinphoneChatMessage *cm) { + LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(cm); + LinphoneCore *lc = linphone_chat_room_get_core(cr); + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); + if (linphone_im_notif_policy_get_send_imdn_displayed(policy) == TRUE) { + linphone_chat_message_send_imdn(cm, ImdnTypeDisplay, LinphoneReasonNone); + } +}LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg, uint32_t character) { + LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); + if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) { + std::shared_ptr rttcr = + std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom)); + LinphoneCall *call = rttcr->getCall(); + LinphoneCore *lc = rttcr->getCore(); + const uint32_t new_line = 0x2028; + const uint32_t crlf = 0x0D0A; + const uint32_t lf = 0x0A; + + if (!call || !linphone_call_get_stream(call, LinphoneStreamTypeText)) { + return -1; + } + + if (character == new_line || character == crlf || character == lf) { + if (lc && lp_config_get_int(lc->config, "misc", "store_rtt_messages", 1) == 1) { + ms_debug("New line sent, forge a message with content %s", msg->message); + msg->time = ms_time(0); + msg->state = LinphoneChatMessageStateDisplayed; + msg->dir = LinphoneChatMessageOutgoing; + if (msg->from) linphone_address_unref(msg->from); + msg->from = linphone_address_new(linphone_core_get_identity(lc)); + msg->storage_id = linphone_chat_message_store(msg); + ms_free(msg->message); + msg->message = NULL; + } + } else { + char *value = LinphonePrivate::Utils::utf8ToChar(character); + msg->message = ms_strcat_printf(msg->message, value); + ms_debug("Sent RTT character: %s (%lu), pending text is %s", value, (unsigned long)character, msg->message); + delete value; + } + + text_stream_putchar32(reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeText)), character); + return 0; + } + return -1; +} + +const char *linphone_chat_message_state_to_string(const LinphoneChatMessageState state) { + switch (state) { + case LinphoneChatMessageStateIdle: + return "LinphoneChatMessageStateIdle"; + case LinphoneChatMessageStateInProgress: + return "LinphoneChatMessageStateInProgress"; + case LinphoneChatMessageStateDelivered: + return "LinphoneChatMessageStateDelivered"; + case LinphoneChatMessageStateNotDelivered: + return "LinphoneChatMessageStateNotDelivered"; + case LinphoneChatMessageStateFileTransferError: + return "LinphoneChatMessageStateFileTransferError"; + case LinphoneChatMessageStateFileTransferDone: + return "LinphoneChatMessageStateFileTransferDone "; + case LinphoneChatMessageStateDeliveredToUser: + return "LinphoneChatMessageStateDeliveredToUser"; + case LinphoneChatMessageStateDisplayed: + return "LinphoneChatMessageStateDisplayed"; + } + return NULL; +} + +const LinphoneAddress *linphone_chat_message_get_peer_address(LinphoneChatMessage *msg) { + return linphone_chat_room_get_peer_address(msg->chat_room); +} + +bool_t linphone_chat_message_is_file_transfer(const LinphoneChatMessage *msg) { + return LinphonePrivate::ContentType::isFileTransfer(msg->content_type); +} + +bool_t linphone_chat_message_is_text(const LinphoneChatMessage *msg) { + return LinphonePrivate::ContentType::isText(msg->content_type); +} + +bool_t linphone_chat_message_get_to_be_stored(const LinphoneChatMessage *msg) { + return msg->to_be_stored; +} + +void linphone_chat_message_set_to_be_stored(LinphoneChatMessage *msg, bool_t to_be_stored) { + msg->to_be_stored = to_be_stored; +} + +LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessage *msg) { + return msg->dir == LinphoneChatMessageOutgoing ? msg->from : msg->to; +} + +LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage *msg) { + return msg->state; +} + +void linphone_chat_message_add_custom_header(LinphoneChatMessage *msg, const char *header_name, + const char *header_value) { + msg->sal_custom_headers = sal_custom_header_append(msg->sal_custom_headers, header_name, header_value); +} + +const char *linphone_chat_message_get_custom_header(LinphoneChatMessage *msg, const char *header_name) { + return sal_custom_header_find(msg->sal_custom_headers, header_name); +} + +void linphone_chat_message_remove_custom_header(LinphoneChatMessage *msg, const char *header_name) { + msg->sal_custom_headers = sal_custom_header_remove(msg->sal_custom_headers, header_name); +} + +bool_t linphone_chat_message_is_read(LinphoneChatMessage *msg) { + LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); + LinphoneCore *lc = linphone_chat_room_get_core(cr); + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); + if ((linphone_im_notif_policy_get_recv_imdn_displayed(policy) == TRUE) && (msg->state == LinphoneChatMessageStateDisplayed)) return TRUE; + if ((linphone_im_notif_policy_get_recv_imdn_delivered(policy) == TRUE) && (msg->state == LinphoneChatMessageStateDeliveredToUser || msg->state == LinphoneChatMessageStateDisplayed)) return TRUE; + return (msg->state == LinphoneChatMessageStateDelivered || msg->state == LinphoneChatMessageStateDisplayed || msg->state == LinphoneChatMessageStateDeliveredToUser); +} + +LinphoneChatMessage *linphone_chat_message_clone(const LinphoneChatMessage *msg) { + LinphoneChatMessage *new_message = linphone_chat_room_create_message(msg->chat_room, msg->message); + if (msg->external_body_url) + new_message->external_body_url = ms_strdup(msg->external_body_url); + if (msg->appdata) + new_message->appdata = ms_strdup(msg->appdata); + new_message->message_state_changed_cb = msg->message_state_changed_cb; + new_message->message_state_changed_user_data = msg->message_state_changed_user_data; + new_message->message_userdata = msg->message_userdata; + new_message->time = msg->time; + new_message->state = msg->state; + new_message->storage_id = msg->storage_id; + if (msg->from) + new_message->from = linphone_address_clone(msg->from); + if (msg->file_transfer_filepath) + new_message->file_transfer_filepath = ms_strdup(msg->file_transfer_filepath); + if (msg->file_transfer_information) + new_message->file_transfer_information = linphone_content_copy(msg->file_transfer_information); + return new_message; +} + +void linphone_chat_message_deactivate(LinphoneChatMessage *msg){ + if (msg->file_transfer_information != NULL) { + _linphone_chat_message_cancel_file_transfer(msg, FALSE); + } + /*mark the chat msg as orphan (it has no chat room anymore)*/ + msg->chat_room = NULL; +} + +void linphone_chat_message_release(LinphoneChatMessage *msg) { + linphone_chat_message_deactivate(msg); + linphone_chat_message_unref(msg); +} + +const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg) { + if (!msg->ei) ((LinphoneChatMessage*)msg)->ei = linphone_error_info_new(); /*let's do it mutable*/ + linphone_error_info_from_sal_op(msg->ei, msg->op); + return msg->ei; +} + +LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage *msg) { + return linphone_error_info_get_reason(linphone_chat_message_get_error_info(msg)); +} + +LinphoneChatMessageCbs *linphone_chat_message_get_callbacks(const LinphoneChatMessage *msg) { + return msg->cbs; +} + +static bool_t file_transfer_in_progress_and_valid(LinphoneChatMessage* msg) { + return (linphone_chat_message_get_chat_room(msg) && + linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)) && + linphone_chat_message_get_http_request(msg) && + !belle_http_request_is_cancelled(linphone_chat_message_get_http_request(msg))); +} + +static void _release_http_request(LinphoneChatMessage* msg) { + if (linphone_chat_message_get_http_request(msg)) { + belle_sip_object_unref(msg->http_request); + msg->http_request = NULL; + if (msg->http_listener){ + belle_sip_object_unref(msg->http_listener); + msg->http_listener = NULL; + // unhold the reference that the listener was holding on the message + linphone_chat_message_unref(msg); + } + } +} + +static void linphone_chat_message_process_io_error_upload(void *data, const belle_sip_io_error_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + ms_error("I/O Error during file upload of msg [%p]", msg); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); + _release_http_request(msg); + linphone_chat_room_remove_transient_message(msg->chat_room, msg); + linphone_chat_message_unref(msg); +} + +static void linphone_chat_message_process_auth_requested_upload(void *data, belle_sip_auth_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + ms_error("Error during file upload: auth requested for msg [%p]", msg); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); + _release_http_request(msg); + linphone_chat_room_remove_transient_message(msg->chat_room, msg); + linphone_chat_message_unref(msg); +} + +static void linphone_chat_message_process_io_error_download(void *data, const belle_sip_io_error_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + ms_error("I/O Error during file download msg [%p]", msg); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateFileTransferError); + _release_http_request(msg); +} + +static void linphone_chat_message_process_auth_requested_download(void *data, belle_sip_auth_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + ms_error("Error during file download : auth requested for msg [%p]", msg); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateFileTransferError); + _release_http_request(msg); +} + +static void linphone_chat_message_file_transfer_on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *m, + void *data, size_t offset, size_t total) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + if (!file_transfer_in_progress_and_valid(msg)) { + ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); + _release_http_request(msg); + return; + } + if (linphone_chat_message_cbs_get_file_transfer_progress_indication(msg->cbs)) { + linphone_chat_message_cbs_get_file_transfer_progress_indication(msg->cbs)( + msg, msg->file_transfer_information, offset, total); + } else { + /* Legacy: call back given by application level */ + linphone_core_notify_file_transfer_progress_indication(linphone_chat_room_get_core(msg->chat_room), msg, msg->file_transfer_information, + offset, total); + } +} + +static int on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, + void *data, size_t offset, uint8_t *buffer, size_t *size) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + LinphoneCore *lc = NULL; + LinphoneImEncryptionEngine *imee = NULL; + int retval = -1; + + if (!file_transfer_in_progress_and_valid(msg)) { + if (msg->http_request) { + ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); + _release_http_request(msg); + } + return BELLE_SIP_STOP; + } + + lc = linphone_chat_room_get_core(msg->chat_room); + /* if we've not reach the end of file yet, ask for more data */ + /* in case of file body handler, won't be called */ + if (msg->file_transfer_filepath == NULL && offset < linphone_content_get_size(msg->file_transfer_information)) { + /* get data from call back */ + LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = linphone_chat_message_cbs_get_file_transfer_send(msg->cbs); + if (file_transfer_send_cb) { + LinphoneBuffer *lb = file_transfer_send_cb(msg, msg->file_transfer_information, offset, *size); + if (lb == NULL) { + *size = 0; + } else { + *size = linphone_buffer_get_size(lb); + memcpy(buffer, linphone_buffer_get_content(lb), *size); + linphone_buffer_unref(lb); + } + } else { + /* Legacy */ + linphone_core_notify_file_transfer_send(lc, msg, msg->file_transfer_information, (char *)buffer, size); + } + } + + imee = linphone_core_get_im_encryption_engine(lc); + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); + if (cb_process_uploading_file) { + size_t max_size = *size; + uint8_t *encrypted_buffer = (uint8_t *)ms_malloc0(max_size); + retval = cb_process_uploading_file(imee, msg, offset, (const uint8_t *)buffer, size, encrypted_buffer); + if (retval == 0) { + if (*size > max_size) { + ms_error("IM encryption engine process upload file callback returned a size bigger than the size of the buffer, so it will be truncated !"); + *size = max_size; + } + memcpy(buffer, encrypted_buffer, *size); + } + ms_free(encrypted_buffer); + } + } + + return retval <= 0 ? BELLE_SIP_CONTINUE : BELLE_SIP_STOP; +} + +static void on_send_end(belle_sip_user_body_handler_t *bh, void *data) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room); + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); + + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); + if (cb_process_uploading_file) { + cb_process_uploading_file(imee, msg, 0, NULL, NULL, NULL); + } + } +} + +static void file_upload_end_background_task(LinphoneChatMessage *obj){ + if (obj->bg_task_id){ + ms_message("channel [%p]: ending file upload background task with id=[%lx].",obj,obj->bg_task_id); + sal_end_background_task(obj->bg_task_id); + obj->bg_task_id=0; + } +} + +static void file_upload_background_task_ended(LinphoneChatMessage *obj){ + ms_warning("channel [%p]: file upload background task has to be ended now, but work isn't finished.",obj); + file_upload_end_background_task(obj); +} + +static void file_upload_begin_background_task(LinphoneChatMessage *obj){ + if (obj->bg_task_id==0){ + obj->bg_task_id=sal_begin_background_task("file transfer upload",(void (*)(void*))file_upload_background_task_ended, obj); + if (obj->bg_task_id) ms_message("channel [%p]: starting file upload background task with id=[%lx].",obj,obj->bg_task_id); + } +} + +static void linphone_chat_message_process_response_from_post_file(void *data, const belle_http_response_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + + if (msg->http_request && !file_transfer_in_progress_and_valid(msg)) { + ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); + _release_http_request(msg); + return; + } + + /* check the answer code */ + if (event->response) { + int code = belle_http_response_get_status_code(event->response); + if (code == 204) { /* this is the reply to the first post to the server - an empty msg */ + /* start uploading the file */ + belle_sip_multipart_body_handler_t *bh; + char *first_part_header; + belle_sip_body_handler_t *first_part_bh; + + bool_t is_file_encryption_enabled = FALSE; + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(linphone_chat_room_get_core(msg->chat_room)); + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer_cb = + linphone_im_encryption_engine_cbs_get_is_encryption_enabled_for_file_transfer(imee_cbs); + if (is_encryption_enabled_for_file_transfer_cb) { + is_file_encryption_enabled = is_encryption_enabled_for_file_transfer_cb(imee, msg->chat_room); + } + } + /* shall we encrypt the file */ + if (is_file_encryption_enabled) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb generate_file_transfer_key_cb = + linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(imee_cbs); + if (generate_file_transfer_key_cb) { + generate_file_transfer_key_cb(imee, msg->chat_room, msg); + } + /* temporary storage for the Content-disposition header value : use a generic filename to not leak it + * Actual filename stored in msg->file_transfer_information->name will be set in encrypted msg + * sended to the */ + first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"filename.txt\""); + } else { + /* temporary storage for the Content-disposition header value */ + first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"%s\"", + linphone_content_get_name(msg->file_transfer_information)); + } + + /* create a user body handler to take care of the file and add the content disposition and content-type + * headers */ + first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new( + linphone_content_get_size(msg->file_transfer_information), + linphone_chat_message_file_transfer_on_progress, NULL, NULL, + on_send_body, on_send_end, msg); + if (msg->file_transfer_filepath != NULL) { + belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh; + first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(msg->file_transfer_filepath, + NULL, msg); // No need to add again the callback for progression, otherwise it will be called twice + linphone_content_set_size(msg->file_transfer_information, belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh)); + belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)first_part_bh, body_handler); + } else if (linphone_content_get_buffer(msg->file_transfer_information) != NULL) { + first_part_bh = (belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer( + linphone_content_get_buffer(msg->file_transfer_information), + linphone_content_get_size(msg->file_transfer_information), linphone_chat_message_file_transfer_on_progress, msg); + } + + belle_sip_body_handler_add_header(first_part_bh, + belle_sip_header_create("Content-disposition", first_part_header)); + belle_sip_free(first_part_header); + belle_sip_body_handler_add_header(first_part_bh, + (belle_sip_header_t *)belle_sip_header_content_type_create( + linphone_content_get_type(msg->file_transfer_information), + linphone_content_get_subtype(msg->file_transfer_information))); + + /* insert it in a multipart body handler which will manage the boundaries of multipart msg */ + bh = belle_sip_multipart_body_handler_new(linphone_chat_message_file_transfer_on_progress, msg, first_part_bh, NULL); + + linphone_chat_message_ref(msg); + _release_http_request(msg); + file_upload_begin_background_task(msg); + linphone_chat_room_upload_file(msg); + belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(msg->http_request), BELLE_SIP_BODY_HANDLER(bh)); + linphone_chat_message_unref(msg); + } else if (code == 200) { /* file has been uploaded correctly, get server reply and send it */ + const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); + if (body && strlen(body) > 0) { + /* if we have an encryption key for the file, we must insert it into the msg and restore the correct + * filename */ + const char *content_key = linphone_content_get_key(msg->file_transfer_information); + size_t content_key_size = linphone_content_get_key_size(msg->file_transfer_information); + if (content_key != NULL) { + /* parse the msg body */ + xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body); + + xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody); + if (cur != NULL) { + cur = cur->xmlChildrenNode; + while (cur != NULL) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { /* we found a file info node, check + it has a type="file" attribute */ + xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); + if (!xmlStrcmp(typeAttribute, + (const xmlChar *)"file")) { /* this is the node we are looking for : add a + file-key children node */ + xmlNodePtr fileInfoNodeChildren = + cur + ->xmlChildrenNode; /* need to parse the children node to update the file-name + one */ + /* convert key to base64 */ + size_t b64Size = b64::b64_encode(NULL, content_key_size, NULL, 0); + char *keyb64 = (char *)ms_malloc0(b64Size + 1); + int xmlStringLength; + + b64Size = b64::b64_encode(content_key, content_key_size, keyb64, b64Size); + keyb64[b64Size] = '\0'; /* libxml need a null terminated string */ + + /* add the node containing the key to the file-info node */ + xmlNewTextChild(cur, NULL, (const xmlChar *)"file-key", (const xmlChar *)keyb64); + xmlFree(typeAttribute); + ms_free(keyb64); + + /* look for the file-name node and update its content */ + while (fileInfoNodeChildren != NULL) { + if (!xmlStrcmp( + fileInfoNodeChildren->name, + (const xmlChar *)"file-name")) { /* we found a the file-name node, update + its content with the real filename */ + /* update node content */ + xmlNodeSetContent(fileInfoNodeChildren, + (const xmlChar *)(linphone_content_get_name( + msg->file_transfer_information))); + break; + } + fileInfoNodeChildren = fileInfoNodeChildren->next; + } + + /* dump the xml into msg->message */ + xmlDocDumpFormatMemoryEnc(xmlMessageBody, (xmlChar **)&msg->message, &xmlStringLength, + "UTF-8", 0); + + break; + } + xmlFree(typeAttribute); + } + cur = cur->next; + } + } + xmlFreeDoc(xmlMessageBody); + } else { /* no encryption key, transfer in plain, just copy the msg sent by server */ + msg->message = ms_strdup(body); + } + linphone_chat_message_set_content_type(msg, "application/vnd.gsma.rcs-ft-http+xml"); + linphone_chat_message_ref(msg); + linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone); + _release_http_request(msg); + L_GET_CPP_PTR_FROM_C_STRUCT(msg->chat_room, ChatRoom)->sendMessage(msg); + file_upload_end_background_task(msg); + linphone_chat_message_unref(msg); + } else { + ms_warning("Received empty response from server, file transfer failed"); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); + _release_http_request(msg); + file_upload_end_background_task(msg); + linphone_chat_message_unref(msg); + } + } else { + ms_warning("Unhandled HTTP code response %d for file transfer", code); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); + _release_http_request(msg); + file_upload_end_background_task(msg); + linphone_chat_message_unref(msg); + } + } +} + +LinphoneContent *linphone_chat_message_get_file_transfer_information(LinphoneChatMessage *msg) { + return msg->file_transfer_information; +} + +static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset, uint8_t *buffer, size_t size) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + LinphoneCore *lc = NULL; + LinphoneImEncryptionEngine *imee = NULL; + int retval = -1; + uint8_t *decrypted_buffer = NULL; + + if (!msg->chat_room) { + linphone_chat_message_cancel_file_transfer(msg); + return; + } + lc = linphone_chat_room_get_core(msg->chat_room); + + if (lc == NULL){ + return; /*might happen during linphone_core_destroy()*/ + } + + if (!msg->http_request || belle_http_request_is_cancelled(msg->http_request)) { + ms_warning("Cancelled request for msg [%p], ignoring %s", msg, __FUNCTION__); + return; + } + + /* first call may be with a zero size, ignore it */ + if (size == 0) { + return; + } + + decrypted_buffer = (uint8_t *)ms_malloc0(size); + imee = linphone_core_get_im_encryption_engine(lc); + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); + if (cb_process_downloading_file) { + retval = cb_process_downloading_file(imee, msg, offset, (const uint8_t *)buffer, size, decrypted_buffer); + if (retval == 0) { + memcpy(buffer, decrypted_buffer, size); + } + } + } + ms_free(decrypted_buffer); + + if (retval <= 0) { + if (msg->file_transfer_filepath == NULL) { + if (linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)) { + LinphoneBuffer *lb = linphone_buffer_new_from_data(buffer, size); + linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)(msg, msg->file_transfer_information, lb); + linphone_buffer_unref(lb); + } else { + /* Legacy: call back given by application level */ + linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, (const char *)buffer, size); + } + } + } else { + ms_warning("File transfer decrypt failed with code %d", (int)retval); + linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferError); + } + + return; +} + +static void on_recv_end(belle_sip_user_body_handler_t *bh, void *data) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room); + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); + int retval = -1; + + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); + if (cb_process_downloading_file) { + retval = cb_process_downloading_file(imee, msg, 0, NULL, 0, NULL); + } + } + + if (retval <= 0) { + if (msg->file_transfer_filepath == NULL) { + if (linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)) { + LinphoneBuffer *lb = linphone_buffer_new(); + linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)(msg, msg->file_transfer_information, lb); + linphone_buffer_unref(lb); + } else { + /* Legacy: call back given by application level */ + linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, NULL, 0); + } + } + } + + if (retval <= 0 && linphone_chat_message_get_state(msg) != LinphoneChatMessageStateFileTransferError) { + linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone); + } +} + +static LinphoneContent *linphone_chat_create_file_transfer_information_from_headers(const belle_sip_message_t *m) { + LinphoneContent *content = linphone_content_new(); + + belle_sip_header_content_length_t *content_length_hdr = + BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(m, "Content-Length")); + belle_sip_header_content_type_t *content_type_hdr = + BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(m, "Content-Type")); + const char *type = NULL, *subtype = NULL; + + linphone_content_set_name(content, ""); + + if (content_type_hdr) { + type = belle_sip_header_content_type_get_type(content_type_hdr); + subtype = belle_sip_header_content_type_get_subtype(content_type_hdr); + ms_message("Extracted content type %s / %s from header", type ? type : "", subtype ? subtype : ""); + if (type) + linphone_content_set_type(content, type); + if (subtype) + linphone_content_set_subtype(content, subtype); + } + + if (content_length_hdr) { + linphone_content_set_size(content, belle_sip_header_content_length_get_content_length(content_length_hdr)); + ms_message("Extracted content length %i from header", (int)linphone_content_get_size(content)); + } + + return content; +} + +static void linphone_chat_process_response_headers_from_get_file(void *data, const belle_http_response_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + if (event->response) { + /*we are receiving a response, set a specific body handler to acquire the response. + * if not done, belle-sip will create a memory body handler, the default*/ + belle_sip_message_t *response = BELLE_SIP_MESSAGE(event->response); + belle_sip_body_handler_t *body_handler = NULL; + size_t body_size = 0; + + if (msg->file_transfer_information == NULL) { + ms_warning("No file transfer information for msg %p: creating...", msg); + msg->file_transfer_information = linphone_chat_create_file_transfer_information_from_headers(response); + } + + if (msg->file_transfer_information) { + body_size = linphone_content_get_size(msg->file_transfer_information); + } + + + body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, linphone_chat_message_file_transfer_on_progress, NULL, on_recv_body, NULL, on_recv_end, msg); + if (msg->file_transfer_filepath != NULL) { + belle_sip_user_body_handler_t *bh = (belle_sip_user_body_handler_t *)body_handler; + body_handler = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new( + msg->file_transfer_filepath, linphone_chat_message_file_transfer_on_progress, msg); + if (belle_sip_body_handler_get_size((belle_sip_body_handler_t *)body_handler) == 0) { + /* If the size of the body has not been initialized from the file stat, use the one from the + * file_transfer_information. */ + belle_sip_body_handler_set_size((belle_sip_body_handler_t *)body_handler, body_size); + } + belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)body_handler, bh); + } + belle_sip_message_set_body_handler((belle_sip_message_t *)event->response, body_handler); + } +} + +static void linphone_chat_process_response_from_get_file(void *data, const belle_http_response_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + /* check the answer code */ + if (event->response) { + int code = belle_http_response_get_status_code(event->response); + if (code >= 400 && code < 500) { + ms_warning("File transfer failed with code %d", code); + linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferError); + } else if (code != 200) { + ms_warning("Unhandled HTTP code response %d for file transfer", code); + } + _release_http_request(msg); + } +} + +int _linphone_chat_room_start_http_transfer(LinphoneChatMessage *msg, const char* url, const char* action, const belle_http_request_listener_callbacks_t *cbs) { + belle_generic_uri_t *uri = NULL; + const char* ua = linphone_core_get_user_agent(linphone_chat_room_get_core(msg->chat_room)); + + if (url == NULL) { + ms_warning("Cannot process file transfer msg: no file remote URI configured."); + goto error; + } + uri = belle_generic_uri_parse(url); + if (uri == NULL || belle_generic_uri_get_host(uri)==NULL) { + ms_warning("Cannot process file transfer msg: incorrect file remote URI configured '%s'.", url); + goto error; + } + + msg->http_request = belle_http_request_create(action, uri, belle_sip_header_create("User-Agent", ua), NULL); + + if (msg->http_request == NULL) { + ms_warning("Could not create http request for uri %s", url); + goto error; + } + /* keep a reference to the http request to be able to cancel it during upload */ + belle_sip_object_ref(msg->http_request); + + /* give msg to listener to be able to start the actual file upload when server answer a 204 No content */ + msg->http_listener = belle_http_request_listener_create_from_callbacks(cbs, linphone_chat_message_ref(msg)); + belle_http_provider_send_request(linphone_chat_room_get_core(msg->chat_room)->http_provider, msg->http_request, msg->http_listener); + return 0; +error: + if (uri) { + belle_sip_object_unref(uri); + } + return -1; +} + +int linphone_chat_room_upload_file(LinphoneChatMessage *msg) { + belle_http_request_listener_callbacks_t cbs = {0}; + int err; + + if (msg->http_request){ + ms_error("linphone_chat_room_upload_file(): there is already an upload in progress."); + return -1; + } + + cbs.process_response = linphone_chat_message_process_response_from_post_file; + cbs.process_io_error = linphone_chat_message_process_io_error_upload; + cbs.process_auth_requested = linphone_chat_message_process_auth_requested_upload; + err = _linphone_chat_room_start_http_transfer(msg, linphone_core_get_file_transfer_server(linphone_chat_room_get_core(msg->chat_room)), "POST", &cbs); + if (err == -1){ + linphone_chat_message_set_state(msg, LinphoneChatMessageStateNotDelivered); + } + return err; +} + +LinphoneStatus linphone_chat_message_download_file(LinphoneChatMessage *msg) { + belle_http_request_listener_callbacks_t cbs = {0}; + int err; + + if (msg->http_request){ + ms_error("linphone_chat_message_download_file(): there is already a download in progress"); + return -1; + } + cbs.process_response_headers = linphone_chat_process_response_headers_from_get_file; + cbs.process_response = linphone_chat_process_response_from_get_file; + cbs.process_io_error = linphone_chat_message_process_io_error_download; + cbs.process_auth_requested = linphone_chat_message_process_auth_requested_download; + err = _linphone_chat_room_start_http_transfer(msg, msg->external_body_url, "GET", &cbs); + if (err == -1) return -1; + /* start the download, status is In Progress */ + linphone_chat_message_set_state(msg, LinphoneChatMessageStateInProgress); + return 0; +} + +void linphone_chat_message_start_file_download(LinphoneChatMessage *msg, + LinphoneChatMessageStateChangedCb status_cb, void *ud) { + msg->message_state_changed_cb = status_cb; + msg->message_state_changed_user_data = ud; + linphone_chat_message_download_file(msg); +} + +void _linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg, bool_t unref) { + if (msg->http_request) { + if (msg->state == LinphoneChatMessageStateInProgress) { + linphone_chat_message_set_state(msg, LinphoneChatMessageStateNotDelivered); + } + if (!belle_http_request_is_cancelled(msg->http_request)) { + if (msg->chat_room) { + ms_message("Canceling file transfer %s - msg [%p] chat room[%p]" + , (msg->external_body_url == NULL) ? linphone_core_get_file_transfer_server(linphone_chat_room_get_core(msg->chat_room)) : msg->external_body_url + , msg + , msg->chat_room); + belle_http_provider_cancel_request(linphone_chat_room_get_core(msg->chat_room)->http_provider, msg->http_request); + if ((msg->dir == LinphoneChatMessageOutgoing) && unref) { + // must release it + linphone_chat_message_unref(msg); + } + } else { + ms_message("Warning: http request still running for ORPHAN msg [%p]: this is a memory leak", msg); + } + } + _release_http_request(msg); + } else { + ms_message("No existing file transfer - nothing to cancel"); + } +} + +void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg) { + _linphone_chat_message_cancel_file_transfer(msg, TRUE); +} + +void linphone_chat_message_set_file_transfer_filepath(LinphoneChatMessage *msg, const char *filepath) { + if (msg->file_transfer_filepath != NULL) { + ms_free(msg->file_transfer_filepath); + } + msg->file_transfer_filepath = ms_strdup(filepath); +} diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index b62832222..dc5481d95 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -113,18 +113,18 @@ LinphoneChatMessage *linphone_chat_room_create_message_2 ( ) { LinphoneChatMessage *msg = linphone_chat_room_create_message(cr, message); LinphoneCore *lc = linphone_chat_room_get_core(cr); - msg->external_body_url = external_body_url ? ms_strdup(external_body_url) : NULL; - msg->time = time; - msg->is_secured = FALSE; + linphone_chat_message_set_external_body_url(msg, external_body_url ? ms_strdup(external_body_url) : NULL); + linphone_chat_message_set_time(msg, time); + linphone_chat_message_set_is_secured(msg, FALSE); linphone_chat_message_set_state(msg, state); if (is_incoming) { - msg->dir = LinphoneChatMessageIncoming; - linphone_chat_message_set_from(msg, linphone_chat_room_get_peer_address(cr)); - msg->to = linphone_address_new(linphone_core_get_identity(lc)); /*direct assignment*/ + linphone_chat_message_set_incoming(msg); + linphone_chat_message_set_from_address(msg, linphone_chat_room_get_peer_address(cr)); + linphone_chat_message_set_to_address(msg, linphone_address_new(linphone_core_get_identity(lc))); } else { - msg->dir = LinphoneChatMessageOutgoing; - linphone_chat_message_set_to(msg, linphone_chat_room_get_peer_address(cr)); - msg->from = linphone_address_new(linphone_core_get_identity(lc)); /*direct assignment*/ + linphone_chat_message_set_outgoing(msg); + linphone_chat_message_set_to_address(msg, linphone_chat_room_get_peer_address(cr)); + linphone_chat_message_set_from_address(msg, linphone_address_new(linphone_core_get_identity(lc))); } return msg; } @@ -135,8 +135,8 @@ void linphone_chat_room_send_message2 ( LinphoneChatMessageStateChangedCb status_cb, void *ud ) { - msg->message_state_changed_cb = status_cb; - msg->message_state_changed_user_data = ud; + linphone_chat_message_set_message_state_changed_cb(msg, status_cb); + linphone_chat_message_set_message_state_changed_cb_user_data(msg, ud); GET_CPP_PTR(cr)->sendMessage(msg); } diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 348d6c2fe..aad0b9e34 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -20,6 +20,7 @@ #include "linphone/utils/utils.h" +#include "linphone/api/c-chat-message.h" #include "c-wrapper/c-tools.h" #include "chat-room-p.h" #include "content/content-type.h" @@ -44,7 +45,7 @@ ChatRoomPrivate::~ChatRoomPrivate () { for (auto &message : transientMessages) linphone_chat_message_release(message); if (pendingMessage) - linphone_chat_message_destroy(pendingMessage); + linphone_chat_message_unref(pendingMessage); } // ----------------------------------------------------------------------------- @@ -140,7 +141,7 @@ void ChatRoomPrivate::sendImdn (const string &content, LinphoneReason reason) { } if (retval <= 0) { - sal_message_send(op, identity, peerAddress.asString().c_str(), msg->content_type, msg->message, nullptr); + sal_message_send(op, identity, peerAddress.asString().c_str(), linphone_chat_message_get_content_type(msg), linphone_chat_message_get_text(msg), nullptr); } linphone_chat_message_unref(msg); @@ -226,7 +227,7 @@ void ChatRoomPrivate::sendIsComposingNotification () { } if (retval <= 0) { - sal_message_send(op, identity, peerAddress.asString().c_str(), msg->content_type, msg->message, nullptr); + sal_message_send(op, identity, peerAddress.asString().c_str(), linphone_chat_message_get_content_type(msg), linphone_chat_message_get_text(msg), nullptr); } linphone_chat_message_unref(msg); @@ -273,25 +274,25 @@ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colN LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str()); if (atoi(argv[3]) == LinphoneChatMessageIncoming) { - newMessage->dir = LinphoneChatMessageIncoming; - linphone_chat_message_set_from(newMessage, peer); - newMessage->to = nullptr; /* Will be filled at the end */ + linphone_chat_message_set_incoming(newMessage); + linphone_chat_message_set_from_address(newMessage, peer); + linphone_chat_message_set_to_address(newMessage, NULL); } else { - newMessage->dir = LinphoneChatMessageOutgoing; - newMessage->from = nullptr; /* Will be filled at the end */ - linphone_chat_message_set_to(newMessage, peer); + linphone_chat_message_set_outgoing(newMessage); + linphone_chat_message_set_from_address(newMessage, NULL); + linphone_chat_message_set_to_address(newMessage, peer); } linphone_address_unref(peer); - newMessage->time = (time_t)atol(argv[9]); - newMessage->is_read = !!atoi(argv[6]); - newMessage->state = static_cast(atoi(argv[7])); - newMessage->storage_id = storageId; - newMessage->external_body_url = ms_strdup(argv[8]); - newMessage->appdata = ms_strdup(argv[10]); - newMessage->message_id = ms_strdup(argv[12]); + linphone_chat_message_set_time(newMessage, (time_t)atol(argv[9])); + linphone_chat_message_set_is_read(newMessage, !!atoi(argv[6])); + linphone_chat_message_set_state(newMessage, static_cast(atoi(argv[7]))); + linphone_chat_message_set_storage_id(newMessage, storageId); + linphone_chat_message_set_external_body_url(newMessage, ms_strdup(argv[8])); + linphone_chat_message_set_appdata(newMessage, ms_strdup(argv[10])); + linphone_chat_message_set_message_id(newMessage, ms_strdup(argv[12])); linphone_chat_message_set_content_type(newMessage, argv[13]); - newMessage->is_secured = (bool_t)atoi(argv[14]); + linphone_chat_message_set_is_secured(newMessage, (bool_t)atoi(argv[14])); if (argv[11]) { int id = atoi(argv[11]); @@ -300,13 +301,13 @@ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colN } /* Fix content type for old messages that were stored without it */ - if (!newMessage->content_type) { - if (newMessage->file_transfer_information) { - newMessage->content_type = ms_strdup("application/vnd.gsma.rcs-ft-http+xml"); - } else if (newMessage->external_body_url) { - newMessage->content_type = ms_strdup("message/external-body"); + if (!linphone_chat_message_get_content_type(newMessage)) { + if (linphone_chat_message_get_file_transfer_information(newMessage)) { + linphone_chat_message_set_content_type(newMessage, ms_strdup("application/vnd.gsma.rcs-ft-http+xml")); + } else if (linphone_chat_message_get_external_body_url(newMessage)) { + linphone_chat_message_set_content_type(newMessage, ms_strdup("message/external-body")); } else { - newMessage->content_type = ms_strdup("text/plain"); + linphone_chat_message_set_content_type(newMessage, ms_strdup("text/plain")); } } @@ -375,12 +376,12 @@ list ChatRoomPrivate::findMessages (const string &message * TODO: Should be handled directly by the LinphoneChatMessage object! */ void ChatRoomPrivate::storeOrUpdateMessage (LinphoneChatMessage *msg) { - if (msg->storage_id != 0) { + if (linphone_chat_message_get_storage_id(msg) != 0) { /* The message has already been stored (probably because of file transfer), update it */ linphone_chat_message_store_update(msg); } else { /* Store the new message */ - msg->storage_id = linphone_chat_message_store(msg); + linphone_chat_message_store(msg); } } @@ -404,19 +405,19 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa msg = q->createMessage(salMsg->text ? salMsg->text : ""); linphone_chat_message_set_content_type(msg, salMsg->content_type); LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str()); - linphone_chat_message_set_from(msg, peer); + linphone_chat_message_set_from_address(msg, peer); linphone_address_unref(peer); LinphoneAddress *to = sal_op_get_to(op) ? linphone_address_new(sal_op_get_to(op)) : linphone_address_new(linphone_core_get_identity(core)); - msg->to = to; - msg->time = salMsg->time; - msg->state = LinphoneChatMessageStateDelivered; - msg->dir = LinphoneChatMessageIncoming; - msg->message_id = ms_strdup(sal_op_get_call_id(op)); + linphone_chat_message_set_to_address(msg, to); + linphone_chat_message_set_time(msg, salMsg->time); + linphone_chat_message_set_state(msg, LinphoneChatMessageStateDelivered); + linphone_chat_message_set_incoming(msg); + linphone_chat_message_set_message_id(msg, ms_strdup(sal_op_get_call_id(op))); const SalCustomHeader *ch = sal_op_get_recv_custom_header(op); if (ch) - msg->custom_headers = sal_custom_header_clone(ch); + linphone_chat_message_set_sal_custom_headers(msg, sal_custom_header_clone(ch)); if (salMsg->url) linphone_chat_message_set_external_body_url(msg, salMsg->url); @@ -428,7 +429,7 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa if (cbProcessIncomingMessage) { retval = cbProcessIncomingMessage(imee, GET_BACK_PTR(q), msg); if (retval == 0) { - msg->is_secured = TRUE; + linphone_chat_message_set_is_secured(msg, TRUE); } else if (retval > 0) { /* Unable to decrypt message */ notifyUndecryptableMessageReceived(msg); @@ -441,9 +442,9 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa } } - if ((retval <= 0) && (linphone_core_is_content_type_supported(core, msg->content_type) == FALSE)) { + if ((retval <= 0) && (linphone_core_is_content_type_supported(core, linphone_chat_message_get_content_type(msg)) == FALSE)) { retval = 415; - lError() << "Unsupported MESSAGE (content-type " << msg->content_type << " not recognized)"; + lError() << "Unsupported MESSAGE (content-type " << linphone_chat_message_get_content_type(msg) << " not recognized)"; } if (retval > 0) { @@ -452,24 +453,24 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa goto end; } - if (ContentType::isFileTransfer(msg->content_type)) { + if (ContentType::isFileTransfer(linphone_chat_message_get_content_type(msg))) { create_file_transfer_information_from_vnd_gsma_rcs_ft_http_xml(msg); linphone_chat_message_set_to_be_stored(msg, TRUE); - } else if (ContentType::isImIsComposing(msg->content_type)) { - isComposingReceived(msg->message); + } else if (ContentType::isImIsComposing(linphone_chat_message_get_content_type(msg))) { + isComposingReceived(linphone_chat_message_get_text(msg)); linphone_chat_message_set_to_be_stored(msg, FALSE); increaseMsgCount = FALSE; if (lp_config_get_int(core->config, "sip", "deliver_imdn", 0) != 1) { goto end; } - } else if (ContentType::isImdn(msg->content_type)) { - imdnReceived(msg->message); + } else if (ContentType::isImdn(linphone_chat_message_get_content_type(msg))) { + imdnReceived(linphone_chat_message_get_text(msg)); linphone_chat_message_set_to_be_stored(msg, FALSE); increaseMsgCount = FALSE; if (lp_config_get_int(core->config, "sip", "deliver_imdn", 0) != 1) { goto end; } - } else if (ContentType::isText(msg->content_type)) { + } else if (ContentType::isText(linphone_chat_message_get_content_type(msg))) { linphone_chat_message_set_to_be_stored(msg, TRUE); } @@ -487,7 +488,7 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa chatMessageReceived(msg); if (linphone_chat_message_get_to_be_stored(msg)) { - msg->storage_id = linphone_chat_message_store(msg); + linphone_chat_message_store(msg); } pendingMessage = nullptr; @@ -502,7 +503,7 @@ end: void ChatRoomPrivate::chatMessageReceived (LinphoneChatMessage *msg) { L_Q(ChatRoom); - if (!ContentType::isImdn(msg->content_type) && !ContentType::isImIsComposing(msg->content_type)) { + if (!ContentType::isImdn(linphone_chat_message_get_content_type(msg)) && !ContentType::isImIsComposing(linphone_chat_message_get_content_type(msg))) { notifyChatMessageReceived(msg); remoteIsComposing = false; linphone_core_notify_is_composing_received(core, GET_BACK_PTR(q)); @@ -524,9 +525,9 @@ void ChatRoomPrivate::isComposingReceived (const string &text) { void ChatRoomPrivate::notifyChatMessageReceived (LinphoneChatMessage *msg) { L_Q(ChatRoom); LinphoneChatRoom *cr = GET_BACK_PTR(q); - if (msg->message) { + if (linphone_chat_message_get_text(msg)) { /* Legacy API */ - linphone_core_notify_text_message_received(core, cr, msg->from, msg->message); + linphone_core_notify_text_message_received(core, cr, linphone_chat_message_get_from_address(msg), linphone_chat_message_get_text(msg)); } LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsMessageReceivedCb cb = linphone_chat_room_cbs_get_message_received(cbs); @@ -591,36 +592,33 @@ void ChatRoom::compose () { LinphoneChatMessage *ChatRoom::createFileTransferMessage (const LinphoneContent *initialContent) { L_D(ChatRoom); - LinphoneChatMessage *cm = belle_sip_object_new(LinphoneChatMessage); - cm->callbacks = linphone_chat_message_cbs_new(); - cm->chat_room = GET_BACK_PTR(this); - cm->message = nullptr; - cm->file_transfer_information = linphone_content_copy(initialContent); - cm->dir = LinphoneChatMessageOutgoing; + LinphoneChatMessage *msg = createMessage(""); + linphone_chat_message_set_chat_room(msg, GET_BACK_PTR(this)); + linphone_chat_message_set_text(msg, NULL); + linphone_chat_message_set_file_transfer_information(msg, linphone_content_copy(initialContent)); + linphone_chat_message_set_outgoing(msg); LinphoneAddress *peer = linphone_address_new(d->peerAddress.asString().c_str()); - linphone_chat_message_set_to(cm, peer); + linphone_chat_message_set_to_address(msg, peer); linphone_address_unref(peer); - cm->from = linphone_address_new(linphone_core_get_identity(d->core)); + linphone_chat_message_set_from_address(msg, linphone_address_new(linphone_core_get_identity(d->core))); /* This will be set to application/vnd.gsma.rcs-ft-http+xml when we will transfer the xml reply from server to the peers */ - cm->content_type = nullptr; + linphone_chat_message_set_content_type(msg, NULL); /* This will store the http request during file upload to the server */ - cm->http_request = nullptr; - cm->time = ms_time(0); - return cm; + linphone_chat_message_set_http_request(msg, NULL); + linphone_chat_message_set_time(msg, ms_time(0)); + return msg; } -LinphoneChatMessage *ChatRoom::createMessage (const string &msg) { - LinphoneChatMessage *cm = belle_sip_object_new(LinphoneChatMessage); - cm->state = LinphoneChatMessageStateIdle; - cm->callbacks = linphone_chat_message_cbs_new(); - cm->chat_room = GET_BACK_PTR(this); - cm->message = msg.empty() ? nullptr : ms_strdup(msg.c_str()); - cm->content_type = ms_strdup("text/plain"); - cm->file_transfer_information = nullptr; /* this property is used only when transfering file */ - cm->http_request = nullptr; - cm->time = ms_time(0); - cm->is_secured = FALSE; - return cm; +LinphoneChatMessage *ChatRoom::createMessage (const string &message) { + LinphoneChatMessage *msg = createMessage(""); + linphone_chat_message_set_chat_room(msg, GET_BACK_PTR(this)); + linphone_chat_message_set_state(msg, LinphoneChatMessageStateIdle); + linphone_chat_message_set_text(msg, message.empty() ? nullptr : ms_strdup(message.c_str())); + linphone_chat_message_set_content_type(msg, ms_strdup("text/plain")); + linphone_chat_message_set_file_transfer_information(msg, nullptr); + linphone_chat_message_set_http_request(msg, NULL); + linphone_chat_message_set_time(msg, ms_time(0)); + return msg; } void ChatRoom::deleteHistory () { @@ -636,7 +634,7 @@ void ChatRoom::deleteHistory () { void ChatRoom::deleteMessage (LinphoneChatMessage *msg) { L_D(ChatRoom); if (!d->core->db) return; - char *buf = sqlite3_mprintf("DELETE FROM history WHERE id = %u;", msg->storage_id); + char *buf = sqlite3_mprintf("DELETE FROM history WHERE id = %u;", linphone_chat_message_get_storage_id(msg)); d->sqlRequest(d->core->db, buf); sqlite3_free(buf); @@ -663,7 +661,7 @@ LinphoneChatMessage * ChatRoom::findMessageWithDirection (const string &messageI LinphoneChatMessage *ret = nullptr; list l = d->findMessages(messageId); for (auto &message : l) { - if (message->dir == direction) { + if (linphone_chat_message_get_direction(message) == direction) { linphone_chat_message_ref(message); ret = message; break; @@ -727,11 +725,10 @@ list ChatRoom::getHistoryRange (int startm, int endm) { /* Fill local addr with core identity instead of per message */ LinphoneAddress *localAddr = linphone_address_new(linphone_core_get_identity(d->core)); for (auto &message : d->messages) { - if (message->dir == LinphoneChatMessageOutgoing) { - if (message->from != NULL) linphone_address_unref(message->from); - message->from = linphone_address_ref(localAddr); + if (linphone_chat_message_is_outgoing(message)) { + linphone_chat_message_set_from_address(message, linphone_address_ref(localAddr)); } else { - message->to = linphone_address_ref(localAddr); + linphone_chat_message_set_to_address(message, linphone_address_ref(localAddr)); } } linphone_address_unref(localAddr); @@ -784,10 +781,10 @@ void ChatRoom::markAsRead () { void ChatRoom::sendMessage (LinphoneChatMessage *msg) { L_D(ChatRoom); - msg->dir = LinphoneChatMessageOutgoing; + linphone_chat_message_set_outgoing(msg); /* Check if we shall upload a file to a server */ - if (msg->file_transfer_information && !msg->content_type) { + if (linphone_chat_message_get_file_transfer_information(msg) && !linphone_chat_message_get_content_type(msg)) { /* Open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */ if (linphone_chat_room_upload_file(msg) == 0) { /* Add to transient list only if message is going out */ @@ -799,23 +796,23 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { return; } } else { - SalOp *op = msg->op; + SalOp *op = linphone_chat_message_get_sal_op(msg); LinphoneCall *call = nullptr; string identity; char *clearTextMessage = nullptr; char *clearTextContentType = nullptr; LinphoneAddress *peer = linphone_address_new(d->peerAddress.asString().c_str()); - if (msg->message) { - clearTextMessage = ms_strdup(msg->message); + if (linphone_chat_message_get_text(msg)) { + clearTextMessage = ms_strdup(linphone_chat_message_get_text(msg)); } - if (msg->content_type) { - clearTextContentType = ms_strdup(msg->content_type); + if (linphone_chat_message_get_content_type(msg)) { + clearTextContentType = ms_strdup(linphone_chat_message_get_content_type(msg)); } /* Add to transient list */ d->addTransientMessage(msg); - msg->time = ms_time(0); + linphone_chat_message_set_time(msg, ms_time(0)); if (lp_config_get_int(d->core->config, "sip", "chat_use_call_dialogs", 0) != 0) { call = linphone_core_get_call_by_remote_address(d->core, d->peerAddress.asString().c_str()); if (call) { @@ -837,11 +834,7 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { identity = linphone_core_get_primary_contact(d->core); } } - if (msg->from) { - /* BUG: the file transfer message constructor sets the from, but doesn't do it as well as here */ - linphone_address_unref(msg->from); - } - msg->from = linphone_address_new(identity.c_str()); + linphone_chat_message_set_from_address(msg, linphone_address_new(identity.c_str())); int retval = -1; LinphoneImEncryptionEngine *imee = d->core->im_encryption_engine; @@ -851,16 +844,16 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { if (cbProcessOutgoingMessage) { retval = cbProcessOutgoingMessage(imee, GET_BACK_PTR(this), msg); if (retval == 0) { - msg->is_secured = TRUE; + linphone_chat_message_set_is_secured(msg, TRUE); } } } if (!op) { /* Sending out of call */ - msg->op = op = sal_op_new(d->core->sal); + linphone_chat_message_set_sal_op(msg, op = sal_op_new(d->core->sal)); linphone_configure_op( - d->core, op, peer, msg->custom_headers, + d->core, op, peer, linphone_chat_message_get_sal_custom_headers(msg), !!lp_config_get_int(d->core->config, "sip", "chat_msg_with_contact", 0) ); sal_op_set_user_pointer(op, msg); /* If out of call, directly store msg */ @@ -875,29 +868,27 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { return; } - if (msg->external_body_url) { - char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", msg->external_body_url); + if (linphone_chat_message_get_external_body_url(msg)) { + char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", linphone_chat_message_get_external_body_url(msg)); sal_message_send(op, identity.c_str(), d->peerAddress.asString().c_str(), content_type, nullptr, nullptr); ms_free(content_type); } else { - if (msg->content_type) { - sal_message_send(op, identity.c_str(), d->peerAddress.asString().c_str(), msg->content_type, msg->message, d->peerAddress.asStringUriOnly().c_str()); + if (linphone_chat_message_get_content_type(msg)) { + sal_message_send(op, identity.c_str(), d->peerAddress.asString().c_str(), linphone_chat_message_get_content_type(msg), linphone_chat_message_get_text(msg), d->peerAddress.asStringUriOnly().c_str()); } else { - sal_text_send(op, identity.c_str(), d->peerAddress.asString().c_str(), msg->message); + sal_text_send(op, identity.c_str(), d->peerAddress.asString().c_str(), linphone_chat_message_get_text(msg)); } } - if (msg->message && clearTextMessage && strcmp(msg->message, clearTextMessage) != 0) { + if (linphone_chat_message_get_text(msg) && clearTextMessage && strcmp(linphone_chat_message_get_text(msg), clearTextMessage) != 0) { /* We replace the encrypted message by the original one so it can be correctly stored and displayed by the application */ - ms_free(msg->message); - msg->message = ms_strdup(clearTextMessage); + linphone_chat_message_set_text(msg, ms_strdup(clearTextMessage)); } - if (msg->content_type && clearTextContentType && (strcmp(msg->content_type, clearTextContentType) != 0)) { + if (linphone_chat_message_get_content_type(msg) && clearTextContentType && (strcmp(linphone_chat_message_get_content_type(msg), clearTextContentType) != 0)) { /* We replace the encrypted content type by the original one */ - ms_free(msg->content_type); - msg->content_type = ms_strdup(clearTextContentType); + linphone_chat_message_set_content_type(msg, ms_strdup(clearTextContentType)); } - msg->message_id = ms_strdup(sal_op_get_call_id(op)); /* must be known at that time */ + linphone_chat_message_set_message_id(msg, ms_strdup(sal_op_get_call_id(op))); /* must be known at that time */ d->storeOrUpdateMessage(msg); if (d->isComposing) @@ -916,14 +907,14 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { if (call && linphone_call_get_op(call) == op) { /* In this case, chat delivery status is not notified, so unrefing chat message right now */ /* Might be better fixed by delivering status, but too costly for now */ - linphone_chat_room_remove_transient_message(msg->chat_room, msg); + linphone_chat_room_remove_transient_message(linphone_chat_message_get_chat_room(msg), msg); linphone_chat_message_unref(msg); return; } } /* If operation failed, we should not change message state */ - if (msg->dir == LinphoneChatMessageOutgoing) { + if (linphone_chat_message_is_outgoing(msg)) { linphone_chat_message_set_state(msg, LinphoneChatMessageStateInProgress); } } diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 9e9470f03..2c21e2016 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -44,7 +44,7 @@ RealTimeTextChatRoomPrivate::~RealTimeTextChatRoomPrivate () { bctbx_free(rttChars); } if (pendingMessage) - linphone_chat_message_destroy(pendingMessage); + linphone_chat_message_unref(pendingMessage); } // ----------------------------------------------------------------------------- @@ -70,18 +70,16 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp if ((character == new_line) || (character == crlf) || (character == lf)) { /* End of message */ - lDebug() << "New line received, forge a message with content " << pendingMessage->message; + lDebug() << "New line received, forge a message with content " << linphone_chat_message_get_text(pendingMessage); LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str()); - linphone_chat_message_set_from(pendingMessage, peer); + linphone_chat_message_set_from_address(pendingMessage, peer); linphone_address_unref(peer); - if (pendingMessage->to) - linphone_address_unref(pendingMessage->to); - pendingMessage->to = linphone_call_get_dest_proxy(call) + linphone_chat_message_set_to_address(pendingMessage, linphone_call_get_dest_proxy(call) ? linphone_address_clone(linphone_call_get_dest_proxy(call)->identity_address) - : linphone_address_new(linphone_core_get_identity(core)); - pendingMessage->time = ms_time(0); - pendingMessage->state = LinphoneChatMessageStateDelivered; - pendingMessage->dir = LinphoneChatMessageIncoming; + : linphone_address_new(linphone_core_get_identity(core))); + linphone_chat_message_set_time(pendingMessage, ms_time(0)); + linphone_chat_message_set_state(pendingMessage, LinphoneChatMessageStateDelivered); + linphone_chat_message_set_incoming(pendingMessage); if (lp_config_get_int(core->config, "misc", "store_rtt_messages", 1) == 1) storeOrUpdateMessage(pendingMessage); @@ -97,8 +95,9 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp receivedRttCharacters.clear(); } else { char *value = Utils::utf8ToChar(character); - pendingMessage->message = ms_strcat_printf(pendingMessage->message, value); - lDebug() << "Received RTT character: " << value << " (" << character << "), pending text is " << pendingMessage->message; + char *text = (char *)linphone_chat_message_get_text(pendingMessage); + linphone_chat_message_set_text(pendingMessage, ms_strcat_printf(text, value)); + lDebug() << "Received RTT character: " << value << " (" << character << "), pending text is " << linphone_chat_message_get_text(pendingMessage); delete value; } } From 1dae5d17426d43f18e1b866e9c304ff02a55caa4 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 21 Sep 2017 13:23:18 +0200 Subject: [PATCH 0113/2215] Fixed broken macro due to latest changes --- src/c-wrapper/api/c-chat-message.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 1752dd939..fa615343c 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -42,7 +42,7 @@ using namespace std; static void _linphone_chat_message_constructor (LinphoneChatMessage *msg); static void _linphone_chat_message_destructor (LinphoneChatMessage *msg); -L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(ChatMessage, ChatMessage, chat_message, +L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(ChatMessage, ChatMessage, _linphone_chat_message_constructor, _linphone_chat_message_destructor, LinphoneChatMessageCbs *cbs; LinphoneChatRoom* chat_room; From 48487d518fb21666e7c813162a96eba25d86cdfc Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 21 Sep 2017 14:12:08 +0200 Subject: [PATCH 0114/2215] feat(c-wrapper): avoid usage of extern init... --- coreapi/callbacks.c | 2 +- coreapi/chat.c | 2 +- coreapi/chat_file_transfer.c | 2 +- coreapi/linphonecall.c | 2 +- coreapi/linphonecore.c | 4 +-- coreapi/proxy.c | 2 +- coreapi/quality_reporting.c | 2 +- src/CMakeLists.txt | 3 +- src/address/address.cpp | 2 +- src/c-wrapper/api/c-address.cpp | 4 +-- src/c-wrapper/api/c-call-params.cpp | 8 +---- src/c-wrapper/api/c-chat-message-cbs.cpp | 5 ++-- src/c-wrapper/api/c-chat-message.cpp | 20 +++++-------- src/c-wrapper/api/c-chat-room-cbs.cpp | 3 +- src/c-wrapper/api/c-chat-room.cpp | 14 +++------ src/c-wrapper/api/c-event-log.cpp | 8 +---- src/c-wrapper/api/c-participant.cpp | 2 +- src/c-wrapper/c-wrapper.h | 38 ++++++++++++++++++++++++ src/c-wrapper/{ => internal}/c-tools.h | 2 +- src/chat/chat-room.cpp | 5 ++-- src/chat/client-group-chat-room.cpp | 5 +--- src/chat/real-time-text-chat-room.cpp | 3 +- src/conference/session/call-session.cpp | 2 +- src/conference/session/media-session.cpp | 2 +- 24 files changed, 75 insertions(+), 67 deletions(-) create mode 100644 src/c-wrapper/c-wrapper.h rename src/c-wrapper/{ => internal}/c-tools.h (99%) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 4efc734c7..e7d79f0cf 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -33,7 +33,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #endif -#include "c-wrapper/c-tools.h" +#include "c-wrapper/c-wrapper.h" #include "call/call-p.h" #include "conference/session/call-session.h" #include "conference/session/call-session-p.h" diff --git a/coreapi/chat.c b/coreapi/chat.c index bb2036b65..08c0af543 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -35,7 +35,7 @@ #include "ortp/b64.h" #include "linphone/wrapper_utils.h" -#include "c-wrapper/c-tools.h" +#include "c-wrapper/c-wrapper.h" #include "chat/basic-chat-room.h" #include "chat/client-group-chat-room.h" #include "chat/real-time-text-chat-room.h" diff --git a/coreapi/chat_file_transfer.c b/coreapi/chat_file_transfer.c index f8da29ad0..8f8e86a01 100644 --- a/coreapi/chat_file_transfer.c +++ b/coreapi/chat_file_transfer.c @@ -25,7 +25,7 @@ #include "linphone/core.h" #include "private.h" -#include "c-wrapper/c-tools.h" +#include "c-wrapper/c-wrapper.h" #include "chat/chat-room.h" LinphoneChatMessage *linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent *initial_content) { diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 9f7dbbc25..dded5e4ef 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -45,7 +45,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // For migration purpose. #include "address/address-p.h" -#include "c-wrapper/c-tools.h" +#include "c-wrapper/c-wrapper.h" #include "call/call.h" #include "call/call-p.h" #include "conference/params/media-session-params-p.h" diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 0bda10aae..4f2412b6f 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -49,7 +49,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // For migration purpose. #include "address/address-p.h" -#include "c-wrapper/c-tools.h" +#include "c-wrapper/c-wrapper.h" #ifdef INET6 #ifndef _WIN32 @@ -66,7 +66,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "TargetConditionals.h" #endif -#include "c-wrapper/c-tools.h" +#include "c-wrapper/c-wrapper.h" #include "call/call-p.h" #include "conference/params/media-session-params-p.h" diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 5d6e72bb0..db61462b2 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -31,7 +31,7 @@ Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) // For migration purpose. #include "address/address-p.h" -#include "c-wrapper/c-tools.h" +#include "c-wrapper/c-wrapper.h" /*store current config related to server location*/ static void linphone_proxy_config_store_server_config(LinphoneProxyConfig* cfg) { diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 20afecf9d..44e0b1d2d 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -34,7 +34,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // For migration purpose. #include "address/address-p.h" -#include "c-wrapper/c-tools.h" +#include "c-wrapper/c-wrapper.h" #define STR_REASSIGN(dest, src) {\ if (dest != NULL) \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a7febd197..3915f3584 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,7 +23,8 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES address/address-p.h address/address.h - c-wrapper/c-tools.h + c-wrapper/c-wrapper.h + c-wrapper/internal/c-tools.h call/call-listener.h call/call-p.h call/call.h diff --git a/src/address/address.cpp b/src/address/address.cpp index 5bd7226d8..054bad63c 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -20,7 +20,7 @@ #include "sal/sal.h" #include "address-p.h" -#include "c-wrapper/c-tools.h" +#include "c-wrapper/c-wrapper.h" #include "logger/logger.h" #include "address.h" diff --git a/src/c-wrapper/api/c-address.cpp b/src/c-wrapper/api/c-address.cpp index 78e166181..703876a33 100644 --- a/src/c-wrapper/api/c-address.cpp +++ b/src/c-wrapper/api/c-address.cpp @@ -16,10 +16,8 @@ * along with this program. If not, see . */ -#include "linphone/api/c-address.h" - #include "address/address.h" -#include "c-wrapper/c-tools.h" +#include "c-wrapper/c-wrapper.h" // ============================================================================= diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index 5356da94a..4d4c35a7f 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -16,15 +16,9 @@ * along with this program. If not, see . */ -#include "linphone/call_params.h" - -// TODO: Remove me later. -#include "private.h" - -#include "c-wrapper/c-tools.h" +#include "c-wrapper/c-wrapper.h" #include "conference/params/call-session-params-p.h" #include "conference/params/media-session-params-p.h" -#include "conference/params/media-session-params.h" // ============================================================================= diff --git a/src/c-wrapper/api/c-chat-message-cbs.cpp b/src/c-wrapper/api/c-chat-message-cbs.cpp index 3fbae1a2d..cecd05c63 100644 --- a/src/c-wrapper/api/c-chat-message-cbs.cpp +++ b/src/c-wrapper/api/c-chat-message-cbs.cpp @@ -18,8 +18,7 @@ #include "linphone/api/c-chat-message-cbs.h" -// TODO: Remove me later. -#include "private.h" +#include "c-wrapper/c-wrapper.h" // ============================================================================= @@ -66,7 +65,7 @@ void linphone_chat_message_cbs_set_user_data (LinphoneChatMessageCbs *cbs, void cbs->userData = ud; } -LinphoneChatMessageCbsMsgStateChangedCb +LinphoneChatMessageCbsMsgStateChangedCb linphone_chat_message_cbs_get_msg_state_changed(const LinphoneChatMessageCbs *cbs) { return cbs->msg_state_changed; } diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index fa615343c..afb079ff4 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -16,21 +16,17 @@ * along with this program. If not, see . */ -#include "linphone/chat.h" -#include "linphone/wrapper_utils.h" +#include "linphone/api/c-chat-message.h" #include "linphone/utils/utils.h" +#include "linphone/wrapper_utils.h" + #include "ortp/b64.h" -// TODO: Remove me later. -#include "private.h" - -#include "chat/chat-room.h" +#include "c-wrapper/c-wrapper.h" +#include "chat/chat-message-p.h" #include "chat/chat-room-p.h" #include "chat/real-time-text-chat-room-p.h" #include "content/content-type.h" -#include "c-wrapper/c-tools.h" -#include "chat/chat-message.h" -#include "chat/chat-message-p.h" // ============================================================================= @@ -626,9 +622,9 @@ LinphoneChatMessageCbs *linphone_chat_message_get_callbacks(const LinphoneChatMe } static bool_t file_transfer_in_progress_and_valid(LinphoneChatMessage* msg) { - return (linphone_chat_message_get_chat_room(msg) && - linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)) && - linphone_chat_message_get_http_request(msg) && + return (linphone_chat_message_get_chat_room(msg) && + linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)) && + linphone_chat_message_get_http_request(msg) && !belle_http_request_is_cancelled(linphone_chat_message_get_http_request(msg))); } diff --git a/src/c-wrapper/api/c-chat-room-cbs.cpp b/src/c-wrapper/api/c-chat-room-cbs.cpp index f83f5c5ea..34b78e27e 100644 --- a/src/c-wrapper/api/c-chat-room-cbs.cpp +++ b/src/c-wrapper/api/c-chat-room-cbs.cpp @@ -18,8 +18,7 @@ #include "linphone/api/c-chat-room-cbs.h" -// TODO: Remove me later. -#include "private.h" +#include "c-wrapper/c-wrapper.h" // ============================================================================= diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index dc5481d95..35bef9a47 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -16,19 +16,15 @@ * along with this program. If not, see . */ -#include "linphone/chat.h" -#include "linphone/wrapper_utils.h" - // TODO: Remove me later. -#include "private.h" +#include "linphone/chat.h" -#include "c-wrapper/c-tools.h" +#include "linphone/api/c-chat-room.h" + +#include "c-wrapper/c-wrapper.h" #include "chat/basic-chat-room.h" -#include "chat/chat-room-p.h" -#include "chat/chat-room.h" #include "chat/client-group-chat-room.h" #include "chat/real-time-text-chat-room-p.h" -#include "chat/real-time-text-chat-room.h" // ============================================================================= @@ -37,8 +33,6 @@ using namespace std; -extern LinphoneParticipant *_linphone_Participant_init (); - static void _linphone_chat_room_constructor (LinphoneChatRoom *cr); static void _linphone_chat_room_destructor (LinphoneChatRoom *cr); diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index d65bce511..77e0c53d2 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -19,7 +19,7 @@ #include "linphone/api/c-chat-message.h" #include "linphone/api/c-event-log.h" -#include "c-wrapper/c-tools.h" +#include "c-wrapper/c-wrapper.h" #include "call/call.h" #include "chat/chat-message.h" #include "event-log/call-event.h" @@ -73,9 +73,6 @@ LinphoneCallEvent *linphone_call_event_new (LinphoneEventLogType type, LinphoneC return call_event; } -// TODO: REMOVE ME. -extern LinphoneCall *_linphone_Call_init (); - LinphoneCall *linphone_call_event_get_call (const LinphoneCallEvent *call_event) { return L_GET_C_BACK_PTR( L_GET_CPP_PTR_FROM_C_STRUCT( @@ -137,9 +134,6 @@ LinphoneChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage * return chat_message_event; } -// TODO: REMOVE ME. -extern LinphoneChatMessage *_linphone_ChatMessage_init (); - LinphoneChatMessage *linphone_chat_message_event_get_chat_message (const LinphoneChatMessageEvent *chat_message_event) { return L_GET_C_BACK_PTR( L_GET_CPP_PTR_FROM_C_STRUCT( diff --git a/src/c-wrapper/api/c-participant.cpp b/src/c-wrapper/api/c-participant.cpp index ea947d6f9..05e0169ff 100644 --- a/src/c-wrapper/api/c-participant.cpp +++ b/src/c-wrapper/api/c-participant.cpp @@ -18,7 +18,7 @@ #include "linphone/api/c-participant.h" -#include "c-wrapper/c-tools.h" +#include "c-wrapper/c-wrapper.h" #include "conference/participant.h" // ============================================================================= diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h new file mode 100644 index 000000000..90f0fb112 --- /dev/null +++ b/src/c-wrapper/c-wrapper.h @@ -0,0 +1,38 @@ +/* + * c-wrapper.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _C_WRAPPER_H_ +#define _C_WRAPPER_H_ + +#include "linphone/api/c-types.h" + +#include "internal/c-tools.h" + +// ============================================================================= + +#define L_REGISTER_TYPE(C_TYPE) \ + extern Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init (); + +// ============================================================================= + +L_REGISTER_TYPE(Call); +L_REGISTER_TYPE(ChatMessage); +L_REGISTER_TYPE(ChatRoom); +L_REGISTER_TYPE(Participant); + +#endif // ifndef _C_WRAPPER_H_ diff --git a/src/c-wrapper/c-tools.h b/src/c-wrapper/internal/c-tools.h similarity index 99% rename from src/c-wrapper/c-tools.h rename to src/c-wrapper/internal/c-tools.h index 0375ad567..71294bdcd 100644 --- a/src/c-wrapper/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -1,5 +1,5 @@ /* - * c-tools.h + * c-wrapper.h * Copyright (C) 2017 Belledonne Communications SARL * * This program is free software: you can redistribute it and/or modify diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index aad0b9e34..b34123947 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -18,10 +18,10 @@ #include +#include "linphone/api/c-chat-message.h" #include "linphone/utils/utils.h" -#include "linphone/api/c-chat-message.h" -#include "c-wrapper/c-tools.h" +#include "c-wrapper/c-wrapper.h" #include "chat-room-p.h" #include "content/content-type.h" #include "imdn.h" @@ -29,7 +29,6 @@ #include "chat-room.h" -extern LinphoneChatRoom * _linphone_ChatRoom_init(); #define GET_BACK_PTR(object) L_GET_C_BACK_PTR(object->shared_from_this(), ChatRoom) // ============================================================================= diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 92ad4dd72..9cd3592e0 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -17,15 +17,12 @@ */ #include "client-group-chat-room-p.h" -#include "c-wrapper/c-tools.h" +#include "c-wrapper/c-wrapper.h" #include "conference/participant-p.h" #include "logger/logger.h" // ============================================================================= -extern LinphoneChatRoom * _linphone_ChatRoom_init(); -extern LinphoneParticipant * _linphone_Participant_init(); - using namespace std; LINPHONE_BEGIN_NAMESPACE diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 2c21e2016..b1d75d301 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -21,10 +21,9 @@ #include "linphone/utils/utils.h" #include "real-time-text-chat-room-p.h" -#include "c-wrapper/c-tools.h" +#include "c-wrapper/c-wrapper.h" #include "logger/logger.h" -extern LinphoneChatRoom * _linphone_ChatRoom_init(); #define GET_BACK_PTR(object) L_GET_C_BACK_PTR(object->shared_from_this(), ChatRoom) // ============================================================================= diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index fb00b8990..7054a20d8 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -18,7 +18,7 @@ #include -#include "c-wrapper/c-tools.h" +#include "c-wrapper/c-wrapper.h" #include "address/address-p.h" #include "conference/session/call-session-p.h" diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 49b90280a..1613e6282 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -20,7 +20,7 @@ #include #include "address/address-p.h" -#include "c-wrapper/c-tools.h" +#include "c-wrapper/c-wrapper.h" #include "conference/session/media-session-p.h" #include "call/call-p.h" #include "conference/participant-p.h" From 353e0c0cbe2207a89a5635b416e3a9c8de81a230 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 21 Sep 2017 14:30:51 +0200 Subject: [PATCH 0115/2215] fix(console): compile with new warnings --- console/commands.c | 49 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/console/commands.c b/console/commands.c index ed5462e18..e5b62d683 100644 --- a/console/commands.c +++ b/console/commands.c @@ -456,14 +456,15 @@ linphonec_parse_command_line(LinphoneCore *lc, char *cl) char * linphonec_command_generator(const char *text, int state) { - static int index, len, adv; + static size_t len; + static int index, adv; char *name; if ( ! state ) { index=0; adv=0; - len=(int)strlen(text); + len=strlen(text); } /* * Return the next name which partially matches @@ -665,8 +666,8 @@ lpc_cmd_transfer(LinphoneCore *lc, char *args) const char *refer_to=NULL; char arg1[256]={0}; char arg2[266]={0}; - long id2=0; - int n=sscanf(args,"%255s %265s %li",arg1,arg2,&id2); + int id2=0; + int n=sscanf(args,"%255s %265s %d",arg1,arg2,&id2); if (n==1 || isalpha(*arg1)){ call=linphone_core_get_current_call(lc); if (call==NULL && bctbx_list_size(linphone_core_get_calls(lc))==1){ @@ -679,13 +680,13 @@ lpc_cmd_transfer(LinphoneCore *lc, char *args) } linphone_call_transfer(call, refer_to); }else if (n==2){ - long id=atoi(arg1); + int id=atoi(arg1); refer_to=args+strlen(arg1)+1; call=linphonec_get_call(id); if (call==NULL) return 0; linphone_call_transfer(call, refer_to); }else if (n==3){ - long id=atoi(arg1); + int id=atoi(arg1); call=linphonec_get_call(id); call2=linphonec_get_call(id2); if (call==NULL || call2==NULL) return 0; @@ -723,7 +724,7 @@ lpc_cmd_terminate(LinphoneCore *lc, char *args) return 1; }else{ /*the argument is a linphonec call id */ - long id=atoi(args); + int id=atoi(args); LinphoneCall *call=linphonec_get_call(id); if (call){ if (linphone_call_terminate(call)==-1){ @@ -764,9 +765,9 @@ lpc_cmd_redirect(LinphoneCore *lc, char *args){ } } else { char space; - long id; + int id; int charRead; - if ( sscanf(args, "%li%c%n", &id, &space, &charRead) == 2 && space == ' ') { + if ( sscanf(args, "%d%c%n", &id, &space, &charRead) == 2 && space == ' ') { LinphoneCall * call = linphonec_get_call(id); if ( call != NULL ) { if (linphone_call_get_state(call)!=LinphoneCallIncomingReceived) { @@ -799,8 +800,8 @@ lpc_cmd_answer(LinphoneCore *lc, char *args){ } return 1; }else{ - long id; - if (sscanf(args,"%li",&id)==1){ + int id; + if (sscanf(args,"%d",&id)==1){ LinphoneCall *call=linphonec_get_call (id); if (linphone_call_accept(call)==-1){ linphonec_out("Fail to accept call %i\n",id); @@ -1003,14 +1004,14 @@ lpc_cmd_friend(LinphoneCore *lc, char *args) { args+=4; if ( ! *args ) return 0; - friend_num = strtol(args, NULL, 10); + friend_num = (int)strtol(args, NULL, 10); #ifndef _WIN32_WCE if ( errno == ERANGE ) { linphonec_out("Invalid friend number\n"); return 0; } #endif /*_WIN32_WCE*/ - linphonec_friend_call(lc, friend_num); + linphonec_friend_call(lc, (unsigned int)friend_num); return 1; } else if ( !strncmp(args, "delete", 6) ) @@ -1025,7 +1026,7 @@ lpc_cmd_friend(LinphoneCore *lc, char *args) } else { - friend_num = strtol(args, NULL, 10); + friend_num = (int)strtol(args, NULL, 10); #ifndef _WIN32_WCE if ( errno == ERANGE ) { linphonec_out("Invalid friend number\n"); @@ -1470,10 +1471,10 @@ static int lpc_cmd_resume(LinphoneCore *lc, char *args){ } if (args) { - long id; - int n = sscanf(args, "%li", &id); + int id; + int n = sscanf(args, "%d", &id); if (n == 1){ - LinphoneCall *call=linphonec_get_call (id); + LinphoneCall *call=linphonec_get_call(id); if (call){ if(linphone_call_resume(call)==-1){ linphonec_out("There was a problem to resume the call check the remote address you gave %s\n",args); @@ -1505,11 +1506,11 @@ static int lpc_cmd_resume(LinphoneCore *lc, char *args){ } static int lpc_cmd_conference(LinphoneCore *lc, char *args){ - long id; + int id; char subcommand[32]={0}; int n; if (args==NULL) return 0; - n=sscanf(args, "%31s %li", subcommand,&id); + n=sscanf(args, "%31s %d", subcommand,&id); if (n == 2){ LinphoneCall *call=linphonec_get_call(id); if (call==NULL) return 1; @@ -2411,12 +2412,12 @@ static int lpc_cmd_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, char *args) #ifdef VIDEO_ENABLED static int _lpc_cmd_video_window(LinphoneCore *lc, char *args, bool_t is_preview){ char subcommand[64]; - long a,b; + int a,b; int err; VideoParams *params=is_preview ? &lpc_preview_params : &lpc_video_params; if (!args) return 0; - err=sscanf(args,"%63s %ld %ld",subcommand,&a,&b); + err=sscanf(args,"%63s %d %d",subcommand,&a,&b); if (err>=1){ if (strcmp(subcommand,"pos")==0){ if (err<3) return 0; @@ -2442,11 +2443,11 @@ static int _lpc_cmd_video_window(LinphoneCore *lc, char *args, bool_t is_preview linphone_core_get_native_video_window_id (lc)); return 1; } else if (err != 2) return 0; - params->wid=(void *)a; + params->wid=(void *)(long)a; if (is_preview) - linphone_core_set_native_preview_window_id(lc, (void *)a); + linphone_core_set_native_preview_window_id(lc, (void *)(long)a); else - linphone_core_set_native_video_window_id(lc, (void *)a); + linphone_core_set_native_video_window_id(lc, (void *)(long)a); }else if (is_preview==TRUE){ if (strcmp(subcommand,"integrated")==0){ linphone_core_use_preview_window (lc,FALSE); From ab473feed159b50a87bccf308cb5f90d2fc2ddbd Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 21 Sep 2017 14:41:18 +0200 Subject: [PATCH 0116/2215] fix(daemon): compile with new cpp flags --- daemon/commands/adaptive-jitter-compensation.h | 5 +++-- daemon/commands/answer.h | 5 +++-- daemon/commands/audio-codec-get.h | 5 +++-- daemon/commands/audio-codec-move.h | 5 +++-- daemon/commands/audio-codec-set.h | 5 +++-- daemon/commands/audio-codec-toggle.h | 6 ++++-- daemon/commands/audio-stream-start.h | 5 +++-- daemon/commands/audio-stream-stats.h | 5 +++-- daemon/commands/audio-stream-stop.h | 5 +++-- daemon/commands/auth-infos-clear.h | 5 +++-- daemon/commands/call-mute.h | 5 +++-- daemon/commands/call-pause.h | 5 +++-- daemon/commands/call-resume.h | 5 +++-- daemon/commands/call-stats.h | 5 +++-- daemon/commands/call-status.h | 5 +++-- daemon/commands/call-transfer.h | 5 +++-- daemon/commands/call.h | 5 +++-- daemon/commands/cn.h | 5 +++-- daemon/commands/conference.h | 5 +++-- daemon/commands/configcommand.h | 8 +++++--- daemon/commands/contact.h | 5 +++-- daemon/commands/dtmf.h | 5 +++-- daemon/commands/firewall-policy.h | 5 +++-- daemon/commands/help.h | 5 +++-- daemon/commands/ipv6.h | 5 +++-- daemon/commands/jitterbuffer.h | 12 +++++++----- daemon/commands/media-encryption.h | 5 +++-- daemon/commands/msfilter-add-fmtp.h | 5 +++-- daemon/commands/netsim.h | 5 +++-- daemon/commands/play-wav.h | 5 +++-- daemon/commands/pop-event.h | 5 +++-- daemon/commands/port.h | 5 +++-- daemon/commands/ptime.h | 5 +++-- daemon/commands/quit.h | 5 +++-- daemon/commands/register-info.h | 5 +++-- daemon/commands/register-status.h | 5 +++-- daemon/commands/register.h | 5 +++-- daemon/commands/terminate.h | 5 +++-- daemon/commands/unregister.h | 5 +++-- daemon/commands/version.h | 5 +++-- daemon/commands/video.h | 11 +++++++---- daemon/daemon-pipetest.c | 13 ++++++------- daemon/daemon.h | 2 +- 43 files changed, 141 insertions(+), 96 deletions(-) diff --git a/daemon/commands/adaptive-jitter-compensation.h b/daemon/commands/adaptive-jitter-compensation.h index c8a901c02..cc15bd07d 100644 --- a/daemon/commands/adaptive-jitter-compensation.h +++ b/daemon/commands/adaptive-jitter-compensation.h @@ -1,6 +1,6 @@ /* adaptive-jitter-compensation.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class AdaptiveBufferCompensationCommand: public DaemonCommand { public: AdaptiveBufferCompensationCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string &args) override; }; #endif // LINPHONE_DAEMON_COMMAND_ADAPTIVE_BUFFER_COMPENSATION_H_ diff --git a/daemon/commands/answer.h b/daemon/commands/answer.h index 7dcd94972..046fd3175 100644 --- a/daemon/commands/answer.h +++ b/daemon/commands/answer.h @@ -1,6 +1,6 @@ /* answer.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class AnswerCommand: public DaemonCommand { public: AnswerCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string &args) override; }; #endif // LINPHONE_DAEMON_COMMAND_ANSWER_H_ diff --git a/daemon/commands/audio-codec-get.h b/daemon/commands/audio-codec-get.h index 8a8075321..0068fd308 100644 --- a/daemon/commands/audio-codec-get.h +++ b/daemon/commands/audio-codec-get.h @@ -1,6 +1,6 @@ /* audio-codec-get.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class AudioCodecGetCommand: public DaemonCommand { public: AudioCodecGetCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string &args) override; }; #endif // LINPHONE_DAEMON_COMMAND_AUDIO_CODEC_GET_H_ diff --git a/daemon/commands/audio-codec-move.h b/daemon/commands/audio-codec-move.h index a19fa7b84..204edc95f 100644 --- a/daemon/commands/audio-codec-move.h +++ b/daemon/commands/audio-codec-move.h @@ -1,6 +1,6 @@ /* audio-codec-move.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class AudioCodecMoveCommand: public DaemonCommand { public: AudioCodecMoveCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string &args) override; }; #endif // LINPHONE_DAEMON_COMMAND_AUDIO_CODEC_MOVE_H_ diff --git a/daemon/commands/audio-codec-set.h b/daemon/commands/audio-codec-set.h index 0d90b2842..f5667f9f5 100644 --- a/daemon/commands/audio-codec-set.h +++ b/daemon/commands/audio-codec-set.h @@ -1,6 +1,6 @@ /* audio-codec-set.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class AudioCodecSetCommand: public DaemonCommand { public: AudioCodecSetCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string &args) override; }; #endif // LINPHONE_DAEMON_COMMAND_AUDIO_CODEC_SET_H_ diff --git a/daemon/commands/audio-codec-toggle.h b/daemon/commands/audio-codec-toggle.h index 36dce4300..f625112d6 100644 --- a/daemon/commands/audio-codec-toggle.h +++ b/daemon/commands/audio-codec-toggle.h @@ -1,6 +1,6 @@ /* audio-codec-toggle.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,9 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class AudioCodecToggleCommand: public DaemonCommand { public: AudioCodecToggleCommand(const char *name, const char *proto, const char *help, bool enable); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string &args) override; + protected: bool mEnable; }; diff --git a/daemon/commands/audio-stream-start.h b/daemon/commands/audio-stream-start.h index 4d8dc878e..730d58632 100644 --- a/daemon/commands/audio-stream-start.h +++ b/daemon/commands/audio-stream-start.h @@ -1,6 +1,6 @@ /* audio-stream-start.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class AudioStreamStartCommand: public DaemonCommand { public: AudioStreamStartCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string &args) override; }; #endif // LINPHONE_DAEMON_COMMAND_AUDIO_STREAM_START_H_ diff --git a/daemon/commands/audio-stream-stats.h b/daemon/commands/audio-stream-stats.h index f63fbb17c..72e93fedd 100644 --- a/daemon/commands/audio-stream-stats.h +++ b/daemon/commands/audio-stream-stats.h @@ -1,6 +1,6 @@ /* audio-stream-stats.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class AudioStreamStatsCommand: public DaemonCommand { public: AudioStreamStatsCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string &args) override; }; #endif // LINPHONE_DAEMON_COMMAND_AUDIO_STREAM_STATS_H_ diff --git a/daemon/commands/audio-stream-stop.h b/daemon/commands/audio-stream-stop.h index 44dd7166d..ad2d0c051 100644 --- a/daemon/commands/audio-stream-stop.h +++ b/daemon/commands/audio-stream-stop.h @@ -1,6 +1,6 @@ /* audio-stream-stop.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class AudioStreamStopCommand: public DaemonCommand { public: AudioStreamStopCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_AUDIO_STREAM_STOP_H_ diff --git a/daemon/commands/auth-infos-clear.h b/daemon/commands/auth-infos-clear.h index 35df2165a..59a53be78 100644 --- a/daemon/commands/auth-infos-clear.h +++ b/daemon/commands/auth-infos-clear.h @@ -1,6 +1,6 @@ /* auth-infos-clear.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class AuthInfosClearCommand: public DaemonCommand { public: AuthInfosClearCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_AUTH_INFOS_CLEAR_H_ diff --git a/daemon/commands/call-mute.h b/daemon/commands/call-mute.h index bab2fe128..993f9a989 100644 --- a/daemon/commands/call-mute.h +++ b/daemon/commands/call-mute.h @@ -1,6 +1,6 @@ /* call-mute.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -26,7 +26,8 @@ class CallMuteCommand : public DaemonCommand { public: CallMuteCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_CALL_MUTE_H diff --git a/daemon/commands/call-pause.h b/daemon/commands/call-pause.h index 7fbb6177d..e0d96063f 100644 --- a/daemon/commands/call-pause.h +++ b/daemon/commands/call-pause.h @@ -1,6 +1,6 @@ /* call-pause.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -26,7 +26,8 @@ class CallPauseCommand : public DaemonCommand { public: CallPauseCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_CALL_PAUSE_H diff --git a/daemon/commands/call-resume.h b/daemon/commands/call-resume.h index 03ac2ae85..6c08c2856 100644 --- a/daemon/commands/call-resume.h +++ b/daemon/commands/call-resume.h @@ -1,6 +1,6 @@ /* call-resume.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -26,7 +26,8 @@ class CallResumeCommand : public DaemonCommand { public: CallResumeCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_CALL_RESUME_H diff --git a/daemon/commands/call-stats.h b/daemon/commands/call-stats.h index 465e38495..27814ec1b 100644 --- a/daemon/commands/call-stats.h +++ b/daemon/commands/call-stats.h @@ -1,6 +1,6 @@ /* call-stats.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class CallStatsCommand: public DaemonCommand { public: CallStatsCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_CALL_STATS_H_ diff --git a/daemon/commands/call-status.h b/daemon/commands/call-status.h index df5989998..308ee1823 100644 --- a/daemon/commands/call-status.h +++ b/daemon/commands/call-status.h @@ -1,6 +1,6 @@ /* call-status.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class CallStatusCommand: public DaemonCommand { public: CallStatusCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_CALL_STATUS_H_ diff --git a/daemon/commands/call-transfer.h b/daemon/commands/call-transfer.h index c0c0d977b..83e93d0c9 100644 --- a/daemon/commands/call-transfer.h +++ b/daemon/commands/call-transfer.h @@ -1,6 +1,6 @@ /* call-transfer.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -26,7 +26,8 @@ class CallTransferCommand : public DaemonCommand { public: CallTransferCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_CALL_TRANSFER_H diff --git a/daemon/commands/call.h b/daemon/commands/call.h index e2cf8700e..881ad144e 100644 --- a/daemon/commands/call.h +++ b/daemon/commands/call.h @@ -1,6 +1,6 @@ /* call.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class CallCommand: public DaemonCommand { public: CallCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_CALL_H_ diff --git a/daemon/commands/cn.h b/daemon/commands/cn.h index 6e625bea8..9b46c6cd6 100644 --- a/daemon/commands/cn.h +++ b/daemon/commands/cn.h @@ -1,6 +1,6 @@ /* cn.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class CNCommand: public DaemonCommand { public: CNCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_CN_H_ diff --git a/daemon/commands/conference.h b/daemon/commands/conference.h index c9d0719ee..cbf1cbe4b 100644 --- a/daemon/commands/conference.h +++ b/daemon/commands/conference.h @@ -1,6 +1,6 @@ /* conference.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -26,7 +26,8 @@ class ConferenceCommand : public DaemonCommand { public: ConferenceCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_CONFERENCE_H diff --git a/daemon/commands/configcommand.h b/daemon/commands/configcommand.h index 6a138b900..36feb749e 100644 --- a/daemon/commands/configcommand.h +++ b/daemon/commands/configcommand.h @@ -1,6 +1,6 @@ /* configcommand.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,13 +25,15 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class ConfigGetCommand: public DaemonCommand { public: ConfigGetCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; class ConfigSetCommand: public DaemonCommand { public: ConfigSetCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_CONFIG_H_ diff --git a/daemon/commands/contact.h b/daemon/commands/contact.h index 057472b94..4b2def6d6 100644 --- a/daemon/commands/contact.h +++ b/daemon/commands/contact.h @@ -1,6 +1,6 @@ /* contact.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class ContactCommand: public DaemonCommand { public: ContactCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_CONTACT_H_ diff --git a/daemon/commands/dtmf.h b/daemon/commands/dtmf.h index 96d52298d..ca9104b47 100644 --- a/daemon/commands/dtmf.h +++ b/daemon/commands/dtmf.h @@ -1,6 +1,6 @@ /* dtmf.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class DtmfCommand: public DaemonCommand { public: DtmfCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_DTMF_H_ diff --git a/daemon/commands/firewall-policy.h b/daemon/commands/firewall-policy.h index a19d1dfd1..475064692 100644 --- a/daemon/commands/firewall-policy.h +++ b/daemon/commands/firewall-policy.h @@ -1,6 +1,6 @@ /* firewall-policy.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class FirewallPolicyCommand: public DaemonCommand { public: FirewallPolicyCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_FIREWALL_POLICY_H_ diff --git a/daemon/commands/help.h b/daemon/commands/help.h index 6e18fd1b5..826e610f9 100644 --- a/daemon/commands/help.h +++ b/daemon/commands/help.h @@ -1,6 +1,6 @@ /* help.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class HelpCommand: public DaemonCommand { public: HelpCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_HELP_H_ diff --git a/daemon/commands/ipv6.h b/daemon/commands/ipv6.h index 31ef4899b..e3ea1e29f 100644 --- a/daemon/commands/ipv6.h +++ b/daemon/commands/ipv6.h @@ -1,6 +1,6 @@ /* ipv6.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class IPv6Command: public DaemonCommand { public: IPv6Command(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_IPV6_H_ diff --git a/daemon/commands/jitterbuffer.h b/daemon/commands/jitterbuffer.h index 76855e0aa..2ea34511a 100644 --- a/daemon/commands/jitterbuffer.h +++ b/daemon/commands/jitterbuffer.h @@ -1,6 +1,6 @@ /* jitterbuffer.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,15 +25,17 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class JitterBufferCommand : public DaemonCommand{ public: - JitterBufferCommand(); - virtual void exec(Daemon *app, const std::string& args); + JitterBufferCommand(); + + void exec(Daemon *app, const std::string& args) override; }; class JitterBufferResetCommand : public DaemonCommand{ public: - JitterBufferResetCommand(); - virtual void exec(Daemon *app, const std::string& args); + JitterBufferResetCommand(); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_JITTER_BUFFER_H diff --git a/daemon/commands/media-encryption.h b/daemon/commands/media-encryption.h index 7a35d0c27..ddd531a42 100644 --- a/daemon/commands/media-encryption.h +++ b/daemon/commands/media-encryption.h @@ -1,6 +1,6 @@ /* media-encryption.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class MediaEncryptionCommand: public DaemonCommand { public: MediaEncryptionCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_MEDIA_ENCRYPTION_H_ diff --git a/daemon/commands/msfilter-add-fmtp.h b/daemon/commands/msfilter-add-fmtp.h index ecb2969ec..c9a3d3270 100644 --- a/daemon/commands/msfilter-add-fmtp.h +++ b/daemon/commands/msfilter-add-fmtp.h @@ -1,6 +1,6 @@ /* msfilter-add-fmtp.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class MSFilterAddFmtpCommand : public DaemonCommand { public: MSFilterAddFmtpCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_MSFILTER_ADD_FMTP diff --git a/daemon/commands/netsim.h b/daemon/commands/netsim.h index e6b147c63..dcedc43e9 100644 --- a/daemon/commands/netsim.h +++ b/daemon/commands/netsim.h @@ -1,6 +1,6 @@ /* netsim.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class NetsimCommand: public DaemonCommand { public: NetsimCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_NETSIM_H_ diff --git a/daemon/commands/play-wav.h b/daemon/commands/play-wav.h index 19a245205..dd9180560 100644 --- a/daemon/commands/play-wav.h +++ b/daemon/commands/play-wav.h @@ -1,6 +1,6 @@ /* play-wav.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class PlayWavCommand: public DaemonCommand { public: PlayWavCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_PLAY_WAV_H_ diff --git a/daemon/commands/pop-event.h b/daemon/commands/pop-event.h index 66a3a8489..e05f7c67e 100644 --- a/daemon/commands/pop-event.h +++ b/daemon/commands/pop-event.h @@ -1,6 +1,6 @@ /* pop-event.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class PopEventCommand: public DaemonCommand { public: PopEventCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_POP_EVENT_H_ diff --git a/daemon/commands/port.h b/daemon/commands/port.h index 465a087e3..99c698fcc 100644 --- a/daemon/commands/port.h +++ b/daemon/commands/port.h @@ -1,6 +1,6 @@ /* port.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class PortCommand: public DaemonCommand { public: PortCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_PORT_H_ diff --git a/daemon/commands/ptime.h b/daemon/commands/ptime.h index a54a17cd6..03a390e90 100644 --- a/daemon/commands/ptime.h +++ b/daemon/commands/ptime.h @@ -1,6 +1,6 @@ /* ptime.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class PtimeCommand: public DaemonCommand { public: PtimeCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_PTIME_H_ diff --git a/daemon/commands/quit.h b/daemon/commands/quit.h index 99bf5f49a..3ff30d890 100644 --- a/daemon/commands/quit.h +++ b/daemon/commands/quit.h @@ -1,6 +1,6 @@ /* quit.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class QuitCommand: public DaemonCommand { public: QuitCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_QUIT_H_ diff --git a/daemon/commands/register-info.h b/daemon/commands/register-info.h index e6b437a57..cdbbaf663 100644 --- a/daemon/commands/register-info.h +++ b/daemon/commands/register-info.h @@ -1,6 +1,6 @@ /* register-info.h -Copyright (C) 2017 Belledonne Communications, Grenoble, France +Copyright (C) 2017 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -26,7 +26,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class RegisterInfoCommand: public DaemonCommand { public: RegisterInfoCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_REGISTER_INFO_H_ diff --git a/daemon/commands/register-status.h b/daemon/commands/register-status.h index 5e19cbe14..ce8bbbf57 100644 --- a/daemon/commands/register-status.h +++ b/daemon/commands/register-status.h @@ -1,6 +1,6 @@ /* register-status.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class RegisterStatusCommand: public DaemonCommand { public: RegisterStatusCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_REGISTER_STATUS_H_ diff --git a/daemon/commands/register.h b/daemon/commands/register.h index c29a17f2b..f7b2f4e05 100644 --- a/daemon/commands/register.h +++ b/daemon/commands/register.h @@ -1,6 +1,6 @@ /* register.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class RegisterCommand: public DaemonCommand { public: RegisterCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_REGISTER_H_ diff --git a/daemon/commands/terminate.h b/daemon/commands/terminate.h index 5733d3f21..0d58ebc59 100644 --- a/daemon/commands/terminate.h +++ b/daemon/commands/terminate.h @@ -1,6 +1,6 @@ /* terminate.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class TerminateCommand: public DaemonCommand { public: TerminateCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_TERMINATE_H_ diff --git a/daemon/commands/unregister.h b/daemon/commands/unregister.h index 09dd5521c..62f34ee87 100644 --- a/daemon/commands/unregister.h +++ b/daemon/commands/unregister.h @@ -1,6 +1,6 @@ /* unregister.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class UnregisterCommand: public DaemonCommand { public: UnregisterCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_UNREGISTER_H_ diff --git a/daemon/commands/version.h b/daemon/commands/version.h index 18c897b8c..76a6d81d0 100644 --- a/daemon/commands/version.h +++ b/daemon/commands/version.h @@ -1,6 +1,6 @@ /* version.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,7 +25,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class VersionCommand: public DaemonCommand { public: VersionCommand(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_VERSION_H_ diff --git a/daemon/commands/video.h b/daemon/commands/video.h index b45688817..a971a2360 100644 --- a/daemon/commands/video.h +++ b/daemon/commands/video.h @@ -1,6 +1,6 @@ /* video.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -26,7 +26,8 @@ class Video : public DaemonCommand { public: Video(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; @@ -34,14 +35,16 @@ class VideoSource : public DaemonCommand { public: VideoSource(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; class AutoVideo : public DaemonCommand { public: AutoVideo(); - virtual void exec(Daemon *app, const std::string& args); + + void exec(Daemon *app, const std::string& args) override; }; #endif // LINPHONE_DAEMON_COMMAND_VIDEO_H diff --git a/daemon/daemon-pipetest.c b/daemon/daemon-pipetest.c index 625312c14..f3fa70c24 100644 --- a/daemon/daemon-pipetest.c +++ b/daemon/daemon-pipetest.c @@ -1,6 +1,6 @@ /* daemon-pipetest.c -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -79,7 +79,7 @@ int main(int argc, char *argv[]){ SetConsoleMode(hin, fdwOldMode); #else struct pollfd pfds[2] = { { 0 } }; - int bytes; + ssize_t bytes; pfds[0].fd=fd; pfds[0].events=POLLIN; pfds[1].fd=1; @@ -91,11 +91,11 @@ int main(int argc, char *argv[]){ /*splice to stdout*/ if (pfds[0].revents & POLLIN){ if ((bytes=read(pfds[0].fd,buf,sizeof(buf)))>0){ - if (write(0,buf,bytes)==-1){ + if (write(0,buf,(size_t)bytes)==-1){ ortp_error("Fail to write to stdout?"); break; } - fprintf(stdout,"\n"); + fprintf(stdout,"\n"); }else if (bytes==0){ break; } @@ -103,10 +103,10 @@ int main(int argc, char *argv[]){ /*splice from stdin to pipe */ if (pfds[1].revents & POLLIN){ if ((bytes=read(pfds[1].fd,buf,sizeof(buf)))>0){ - if (write(pfds[0].fd,buf,bytes)==-1){ + if (write(pfds[0].fd,buf,(size_t)bytes)==-1){ ortp_error("Fail to write to unix socket"); break; - } + } }else if (bytes==0){ break; } @@ -117,4 +117,3 @@ int main(int argc, char *argv[]){ return 0; } - diff --git a/daemon/daemon.h b/daemon/daemon.h index 12a32c358..97591982e 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -1,6 +1,6 @@ /* daemon.h -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by From 553d8b1c3d20cc14b8bd910393d03bef337bccab Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 21 Sep 2017 15:23:06 +0200 Subject: [PATCH 0117/2215] fix(tester): repare build --- CMakeLists.txt | 27 +++++------ tester/CMakeLists.txt | 3 ++ tester/accountmanager.c | 4 +- tester/audio_bypass_tester.c | 8 ++-- tester/audio_bypass_wav_header.h | 75 ++++++++++++++---------------- tester/conference-event-tester.cpp | 10 ++-- tester/message_tester.c | 60 ++++++++++++------------ 7 files changed, 93 insertions(+), 94 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9cddd930e..1b2135c03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -282,21 +282,22 @@ if(MSVC) list(APPEND STRICT_OPTIONS_CPP "/WX") endif() else() - list(APPEND STRICT_OPTIONS_CPP "\ --Wall \ --Wcast-align \ --Wconversion \ --Werror=return-type \ --Wfloat-equal \ --Winit-self \ --Wno-error=deprecated-declarations \ --Woverloaded-virtual \ --Wpointer-arith \ --Wuninitialized \ --Wunused") + list(APPEND STRICT_OPTIONS_CPP + "-Wall" + "-Wcast-align" + "-Wconversion" + "-Werror=return-type" + "-Wfloat-equal" + "-Winit-self" + "-Wno-error=deprecated-declarations" + "-Woverloaded-virtual" + "-Wpointer-arith" + "-Wuninitialized" + "-Wunused" + ) CHECK_CXX_COMPILER_FLAG("-Wsuggest-override" SUGGEST_OVERRIDE) if (SUGGEST_OVERRIDE) - list(APPEND STRICT_OPTIONS_CPP "-Wsuggest-override -Werror=suggest-override") + list(APPEND STRICT_OPTIONS_CPP "-Wsuggest-override" "-Werror=suggest-override") endif () list(APPEND STRICT_OPTIONS_C "-Wstrict-prototypes" "-Werror=strict-prototypes") if(CMAKE_C_COMPILER_ID STREQUAL "GNU") diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index 1b71c03db..32833ac16 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -210,6 +210,9 @@ if(APPLE) endif() endif() +# TODO: Remove me later! +list(REMOVE_ITEM STRICT_OPTIONS_CPP "-Wconversion" "-Werror=conversion") + bc_apply_compile_flags(SOURCE_FILES_C STRICT_OPTIONS_CPP STRICT_OPTIONS_C) bc_apply_compile_flags(SOURCE_FILES_CXX STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX) bc_apply_compile_flags(SOURCE_FILES_OBJC STRICT_OPTIONS_CPP STRICT_OPTIONS_OBJC) diff --git a/tester/accountmanager.c b/tester/accountmanager.c index 26ebd3f75..3fc4e265a 100644 --- a/tester/accountmanager.c +++ b/tester/accountmanager.c @@ -259,8 +259,8 @@ static LinphoneAddress *account_manager_check_account(AccountManager *m, Linphon void linphone_core_manager_check_accounts(LinphoneCoreManager *m){ const bctbx_list_t *it; AccountManager *am=account_manager_get(); - int logmask = linphone_core_get_log_level_mask(); - + unsigned int logmask = linphone_core_get_log_level_mask(); + if (!liblinphonetester_show_account_manager_logs) linphone_core_set_log_level_mask(ORTP_ERROR|ORTP_FATAL); for(it=linphone_core_get_proxy_config_list(m->lc);it!=NULL;it=it->next){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig *)it->data; diff --git a/tester/audio_bypass_tester.c b/tester/audio_bypass_tester.c index c2315d813..1d85bdbef 100644 --- a/tester/audio_bypass_tester.c +++ b/tester/audio_bypass_tester.c @@ -68,9 +68,7 @@ int audio_bypass_read_wav_header_from_fd(wave_header_t *header,int fd){ format_t *format_chunk=&header->format_chunk; data_t *data_chunk=&header->data_chunk; - unsigned long len=0; - - len = read(fd, (char*)riff_chunk, sizeof(riff_t)) ; + ssize_t len = read(fd, (char*)riff_chunk, sizeof(riff_t)) ; if (len != sizeof(riff_t)){ goto not_a_wav; } @@ -85,7 +83,7 @@ int audio_bypass_read_wav_header_from_fd(wave_header_t *header,int fd){ goto not_a_wav; } - if ((skip=le_uint32(format_chunk->len)-0x10)>0) + if ((skip=(int)le_uint32(format_chunk->len)-0x10)>0) { lseek(fd,skip,SEEK_CUR); } @@ -491,7 +489,7 @@ static void audio_bypass(void) { call_ok = call(marie, pauline); BC_ASSERT_TRUE(call_ok); if (!call_ok) goto end; - + BC_ASSERT_STRING_EQUAL(linphone_call_params_get_used_audio_codec(linphone_call_get_current_params(linphone_core_get_current_call(marie_lc)))->mime_type, "L16"); diff --git a/tester/audio_bypass_wav_header.h b/tester/audio_bypass_wav_header.h index e82df007b..f1d75905c 100644 --- a/tester/audio_bypass_wav_header.h +++ b/tester/audio_bypass_wav_header.h @@ -26,54 +26,51 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #ifdef _WIN32 -# include -# ifndef R_OK -# define R_OK 0x2 -# endif -# ifndef W_OK -# define W_OK 0x6 -# endif -# ifndef F_OK -# define F_OK 0x0 -# endif + #include + #ifndef R_OK + #define R_OK 0x2 + #endif + #ifndef W_OK + #define W_OK 0x6 + #endif + #ifndef F_OK + #define F_OK 0x0 + #endif -# ifndef S_IRUSR -# define S_IRUSR S_IREAD -# endif + #ifndef S_IRUSR + #define S_IRUSR S_IREAD + #endif -# ifndef S_IWUSR -# define S_IWUSR S_IWRITE -# endif + #ifndef S_IWUSR + #define S_IWUSR S_IWRITE + #endif -# define open _open -# define read _read -# define write _write -# define close _close -# define access _access -# define lseek _lseek -#else /*_WIN32*/ - -# ifndef O_BINARY -# define O_BINARY 0 -# endif - -#endif /*!_WIN32*/ + #define open _open + #define read _read + #define write _write + #define close _close + #define access _access + #define lseek _lseek +#else + #ifndef O_BINARY + #define O_BINARY 0 + #endif +#endif #ifdef swap16 #else /* all integer in wav header must be read in least endian order */ -static MS2_INLINE uint16_t swap16(uint16_t a) -{ - return ((a & 0xFF) << 8) | ((a & 0xFF00) >> 8); +static MS2_INLINE uint16_t swap16(uint16_t a) { + return (uint16_t)(((a & 0xFF) << 8) | ((a & 0xFF00) >> 8)); } #endif #ifdef swap32 #else -static MS2_INLINE uint32_t swap32(uint32_t a) -{ - return ((a & 0xFF) << 24) | ((a & 0xFF00) << 8) | - ((a & 0xFF0000) >> 8) | ((a & 0xFF000000) >> 24); +static MS2_INLINE uint32_t swap32(uint32_t a) { + return (uint32_t)( + ((a & 0xFF) << 24) | ((a & 0xFF00) << 8) | ((a & 0xFF0000) >> 8) | ((a & 0xFF000000) >> 24) + ); } #endif @@ -82,9 +79,9 @@ static MS2_INLINE uint32_t swap32(uint32_t a) #define le_uint16(a) (swap16((a))) #define le_int16(a) ( (int16_t) swap16((uint16_t)((a))) ) #else -#define le_uint32(a) (a) -#define le_uint16(a) (a) -#define le_int16(a) (a) +#define le_uint32(a) ((uint32_t)(a)) +#define le_uint16(a) ((uint16_t)(a)) +#define le_int16(a) ((int16_t)(a)) #endif typedef struct _riff_t { diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index 9de93e4bb..e70ba8843 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -425,11 +425,11 @@ public: ~ConferenceEventTester (); private: - void onConferenceCreated (const Address &addr); - void onConferenceTerminated (const Address &addr); - void onParticipantAdded (const Address &addr); - void onParticipantRemoved (const Address &addr); - void onParticipantSetAdmin (const Address &addr, bool isAdmin); + void onConferenceCreated (const Address &addr) override; + void onConferenceTerminated (const Address &addr) override; + void onParticipantAdded (const Address &addr) override; + void onParticipantRemoved (const Address &addr) override; + void onParticipantSetAdmin (const Address &addr, bool isAdmin) override; public: RemoteConferenceEventHandler *handler; diff --git a/tester/message_tester.c b/tester/message_tester.c index ddbf20023..444010ec3 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -51,7 +51,7 @@ void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const Linph } void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage* msg) { - char* from=linphone_address_as_string(linphone_chat_message_get_from(msg)); + char* from=linphone_address_as_string(linphone_chat_message_get_from_address(msg)); stats* counters; const char *text=linphone_chat_message_get_text(msg); const char *external_body_url=linphone_chat_message_get_external_body_url(msg); @@ -80,10 +80,10 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess void file_transfer_received(LinphoneChatMessage *msg, const LinphoneContent* content, const LinphoneBuffer *buffer){ FILE* file=NULL; char *receive_file = NULL; - + // If a file path is set, we should NOT call the on_recv callback ! - BC_ASSERT_PTR_NULL(msg->file_transfer_filepath); - + BC_ASSERT_PTR_NULL(linphone_chat_message_get_file_transfer_filepath(msg)); + receive_file = bc_tester_file("receive_file.dump"); if (!linphone_chat_message_get_user_data(msg)) { /*first chunk, creating file*/ @@ -112,9 +112,9 @@ LinphoneBuffer * tester_file_transfer_send(LinphoneChatMessage *msg, const Linph size_t size_to_send; uint8_t *buf; FILE *file_to_send = linphone_chat_message_get_user_data(msg); - + // If a file path is set, we should NOT call the on_send callback ! - BC_ASSERT_PTR_NULL(msg->file_transfer_filepath); + BC_ASSERT_PTR_NULL(linphone_chat_message_get_file_transfer_filepath(msg)); BC_ASSERT_PTR_NOT_NULL(file_to_send); if (file_to_send == NULL){ @@ -141,8 +141,8 @@ LinphoneBuffer * tester_file_transfer_send(LinphoneChatMessage *msg, const Linph void file_transfer_progress_indication(LinphoneChatMessage *msg, const LinphoneContent* content, size_t offset, size_t total) { LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); LinphoneCore *lc = linphone_chat_room_get_core(cr); - const LinphoneAddress* from_address = linphone_chat_message_get_from(msg); - const LinphoneAddress* to_address = linphone_chat_message_get_to(msg); + const LinphoneAddress* from_address = linphone_chat_message_get_from_address(msg); + const LinphoneAddress* to_address = linphone_chat_message_get_to_address(msg); char *address = linphone_chat_message_is_outgoing(msg)?linphone_address_as_string(to_address):linphone_address_as_string(from_address); stats* counters = get_stats(lc); int progress = (int)((offset * 100)/total); @@ -219,7 +219,7 @@ void compare_files(const char *path1, const char *path2) { BC_ASSERT_EQUAL(memcmp(buf1, buf2, size1), 0, int, "%d"); } BC_ASSERT_EQUAL((uint8_t)size2, (uint8_t)size1, uint8_t, "%u"); - + if (buf1) ms_free(buf1); if (buf2) ms_free(buf2); } @@ -284,7 +284,7 @@ void text_message_base(LinphoneCoreManager* marie, LinphoneCoreManager* pauline) LinphoneChatMessage* msg = linphone_chat_room_create_message(linphone_core_get_chat_room(pauline->lc,marie->identity),"Bli bli bli \n blu"); LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); - linphone_chat_room_send_chat_message(msg->chat_room,msg); + linphone_chat_room_send_chat_message(linphone_chat_message_get_chat_room(msg), msg); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); @@ -461,7 +461,7 @@ static void text_message_with_external_body(void) { linphone_core_manager_destroy(pauline); } -void transfer_message_base2(LinphoneCoreManager* marie, LinphoneCoreManager* pauline, bool_t upload_error, bool_t download_error, +void transfer_message_base2(LinphoneCoreManager* marie, LinphoneCoreManager* pauline, bool_t upload_error, bool_t download_error, bool_t use_file_body_handler_in_upload, bool_t use_file_body_handler_in_download, bool_t download_from_history) { char *send_filepath = bc_tester_res("sounds/sintel_trailer_opus_h264.mkv"); char *receive_filepath = bc_tester_file("receive_file.dump"); @@ -472,7 +472,7 @@ void transfer_message_base2(LinphoneCoreManager* marie, LinphoneCoreManager* pau /* Remove any previously downloaded file */ remove(receive_filepath); - + /* Globally configure an http file transfer server. */ linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php"); @@ -485,7 +485,7 @@ void transfer_message_base2(LinphoneCoreManager* marie, LinphoneCoreManager* pau } else { msg = create_message_from_sintel_trailer(chat_room); } - + linphone_chat_room_send_chat_message(chat_room,msg); if (upload_error) { @@ -570,7 +570,7 @@ end: bc_free(receive_filepath); } -void transfer_message_base(bool_t upload_error, bool_t download_error, bool_t use_file_body_handler_in_upload, +void transfer_message_base(bool_t upload_error, bool_t download_error, bool_t use_file_body_handler_in_upload, bool_t use_file_body_handler_in_download, bool_t download_from_history) { if (transport_supported(LinphoneTransportTls)) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); @@ -724,7 +724,7 @@ static void file_transfer_2_messages_simultaneously(void) { /* Remove any previously downloaded file */ remove(receive_filepath); - + /* Globally configure an http file transfer server. */ linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php"); @@ -1343,7 +1343,7 @@ void lime_transfer_message_base(bool_t encrypt_file,bool_t download_file_from_st char *send_filepath = bc_tester_res("sounds/sintel_trailer_opus_h264.mkv"); char *receive_filepath = bc_tester_file("receive_file.dump"); MSList * msg_list = NULL; - + /* Remove any previously downloaded file */ remove(receive_filepath); @@ -1371,7 +1371,7 @@ void lime_transfer_message_base(bool_t encrypt_file,bool_t download_file_from_st msg = create_message_from_sintel_trailer(linphone_core_get_chat_room(pauline->lc, marie->identity)); } - linphone_chat_room_send_chat_message(msg->chat_room, msg); + linphone_chat_room_send_chat_message(linphone_chat_message_get_chat_room(msg), msg); BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,1, 60000)); if (marie->stat.last_received_chat_message ) { LinphoneChatMessage *recv_msg; @@ -1395,12 +1395,12 @@ void lime_transfer_message_base(bool_t encrypt_file,bool_t download_file_from_st BC_ASSERT_PTR_NOT_NULL(linphone_content_get_key(content)); else BC_ASSERT_PTR_NULL(linphone_content_get_key(content)); - + if (use_file_body_handler_in_download) { linphone_chat_message_set_file_transfer_filepath(recv_msg, receive_filepath); } linphone_chat_message_download_file(recv_msg); - + if (BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,1,55000))) { compare_files(send_filepath, receive_filepath); } @@ -1467,7 +1467,7 @@ static void lime_cache_migration(void) { linphone_proxy_config_edit(cfg); linphone_address_set_display_name(new_identity,"what about if we have a display name ?"); linphone_proxy_config_set_identity_address(cfg, new_identity); - + linphone_proxy_config_done(cfg); if (!linphone_core_lime_available(marie->lc)) { @@ -1485,7 +1485,7 @@ static void lime_cache_migration(void) { linphone_core_set_zrtp_secrets_file(marie->lc, xmlCache_filepath); /*short check*/ limeKey_t associatedKey={0}; - + char * selfURI = linphone_address_as_string_uri_only(new_identity); linphone_address_unref(new_identity); bctbx_str_to_uint8(associatedKey.peerZID, (const uint8_t *)"0987654321fedcba5a5a5a5a", (uint16_t)strlen("0987654321fedcba5a5a5a5a")); @@ -1849,7 +1849,7 @@ static void real_time_text(bool_t audio_stream_enabled, bool_t srtp_enabled, boo BC_ASSERT_PTR_NOT_NULL(marie->lc->db); BC_ASSERT_PTR_NOT_NULL(pauline->lc->db); #endif - + if (do_not_store_rtt_messages_in_sql_storage) { lp_config_set_int(marie->lc->config, "misc", "store_rtt_messages", 0); lp_config_set_int(pauline->lc->config, "misc", "store_rtt_messages", 0); @@ -1942,8 +1942,8 @@ static void real_time_text(bool_t audio_stream_enabled, bool_t srtp_enabled, boo } marie_msg = (LinphoneChatMessage *)marie_messages->data; pauline_msg = (LinphoneChatMessage *)pauline_messages->data; - BC_ASSERT_STRING_EQUAL(marie_msg->message, message); - BC_ASSERT_STRING_EQUAL(pauline_msg->message, message); + BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(marie_msg), message); + BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(pauline_msg), message); bctbx_list_free_with_data(marie_messages, (void (*)(void *))linphone_chat_message_unref); bctbx_list_free_with_data(pauline_messages, (void (*)(void *))linphone_chat_message_unref); } @@ -2194,7 +2194,7 @@ static void real_time_text_message_accented_chars(void) { linphone_chat_room_send_chat_message(pauline_chat_room, rtt_message); BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageReceived, 1)); - BC_ASSERT_EQUAL(strcmp(marie->stat.last_received_chat_message->message, "ãæçéîøùÿ"), 0, int, "%i"); + BC_ASSERT_EQUAL(strcmp(linphone_chat_message_get_text(marie->stat.last_received_chat_message), "ãæçéîøùÿ"), 0, int, "%i"); } end_call(marie, pauline); } @@ -2283,13 +2283,13 @@ void chat_message_custom_headers(void) { BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); - + if (marie->stat.last_received_chat_message) { const char *header = linphone_chat_message_get_custom_header(marie->stat.last_received_chat_message, "Test2"); BC_ASSERT_STRING_EQUAL(header, "Value2"); header = linphone_chat_message_get_custom_header(marie->stat.last_received_chat_message, "Test1"); BC_ASSERT_PTR_NULL(header); - BC_ASSERT_STRING_EQUAL(marie->stat.last_received_chat_message->message, "Lorem Ipsum"); + BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(marie->stat.last_received_chat_message), "Lorem Ipsum"); } linphone_core_manager_destroy(marie); @@ -2402,12 +2402,12 @@ void im_encryption_engine_b64(void) { LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); LinphoneImEncryptionEngine *pauline_imee = linphone_im_encryption_engine_new(); LinphoneImEncryptionEngineCbs *pauline_cbs = linphone_im_encryption_engine_get_callbacks(pauline_imee); - + linphone_im_encryption_engine_cbs_set_process_incoming_message(marie_cbs, im_encryption_engine_process_incoming_message_cb); linphone_im_encryption_engine_cbs_set_process_outgoing_message(marie_cbs, im_encryption_engine_process_outgoing_message_cb); linphone_im_encryption_engine_cbs_set_process_incoming_message(pauline_cbs, im_encryption_engine_process_incoming_message_cb); linphone_im_encryption_engine_cbs_set_process_outgoing_message(pauline_cbs, im_encryption_engine_process_outgoing_message_cb); - + linphone_core_set_im_encryption_engine(marie->lc, marie_imee); linphone_core_set_im_encryption_engine(pauline->lc, pauline_imee); @@ -2420,7 +2420,7 @@ void im_encryption_engine_b64(void) { BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(marie->stat.last_received_chat_message), "Bla bla bla bla"); } BC_ASSERT_PTR_NOT_NULL(linphone_core_get_chat_room(marie->lc,pauline->identity)); - + linphone_im_encryption_engine_unref(marie_imee); linphone_im_encryption_engine_unref(pauline_imee); linphone_core_manager_destroy(marie); From 3c28b14440ea03662085e40397967b421a1ddedb Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 21 Sep 2017 15:33:44 +0200 Subject: [PATCH 0118/2215] Use the c-tools for the Call object. --- coreapi/callbacks.c | 2 +- coreapi/info.c | 10 +- coreapi/linphonecall.c | 1528 +--------------------- coreapi/linphonecore.c | 14 +- coreapi/private.h | 67 +- include/CMakeLists.txt | 3 + include/linphone/api/c-call-cbs.h | 169 +++ include/linphone/api/c-call-stats.h | 201 +++ include/linphone/api/c-call.h | 794 +++++++++++ include/linphone/api/c-callbacks.h | 62 + include/linphone/api/c-types.h | 19 +- include/linphone/call.h | 906 +------------ include/linphone/call_stats.h | 162 +-- include/linphone/callbacks.h | 61 - include/linphone/types.h | 19 - src/CMakeLists.txt | 3 + src/c-wrapper/api/c-call-cbs.cpp | 125 ++ src/c-wrapper/api/c-call-stats.cpp | 343 +++++ src/c-wrapper/api/c-call.cpp | 1212 +++++++++++++++++ src/c-wrapper/c-wrapper.h | 2 + src/call/call-p.h | 4 - src/call/call.cpp | 12 +- src/call/call.h | 6 +- src/conference/session/call-session-p.h | 4 +- src/conference/session/call-session.cpp | 8 +- src/conference/session/call-session.h | 2 +- src/conference/session/media-session-p.h | 4 +- src/conference/session/media-session.cpp | 93 +- src/conference/session/media-session.h | 8 +- src/nat/ice-agent.cpp | 38 +- 30 files changed, 3052 insertions(+), 2829 deletions(-) create mode 100644 include/linphone/api/c-call-cbs.h create mode 100644 include/linphone/api/c-call-stats.h create mode 100644 include/linphone/api/c-call.h create mode 100644 src/c-wrapper/api/c-call-cbs.cpp create mode 100644 src/c-wrapper/api/c-call-stats.cpp create mode 100644 src/c-wrapper/api/c-call.cpp diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index e7d79f0cf..6e1e27880 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -169,7 +169,7 @@ static void call_received(SalOp *h) { LinphoneCall *call = linphone_call_new_incoming(lc, fromAddr, toAddr, h); linphone_address_unref(fromAddr); linphone_address_unref(toAddr); - L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->startIncomingNotification(); + L_GET_PRIVATE_FROM_C_STRUCT(call, Call)->startIncomingNotification(); } static void call_rejected(SalOp *h){ diff --git a/coreapi/info.c b/coreapi/info.c index e6b09b8e3..364f5cfab 100644 --- a/coreapi/info.c +++ b/coreapi/info.c @@ -76,12 +76,6 @@ LinphoneInfoMessage *linphone_core_create_info_message(LinphoneCore *lc){ return belle_sip_object_new(LinphoneInfoMessage); } -LinphoneStatus linphone_call_send_info_message(LinphoneCall *call, const LinphoneInfoMessage *info) { - SalBodyHandler *body_handler = sal_body_handler_from_content(info->content); - sal_op_set_sent_custom_header(linphone_call_get_op(call), info->headers); - return sal_send_info(linphone_call_get_op(call), NULL, NULL, body_handler); -} - void linphone_info_message_add_header(LinphoneInfoMessage *im, const char *name, const char *value){ im->headers=sal_custom_header_append(im->headers, name, value); } @@ -98,6 +92,10 @@ const LinphoneContent * linphone_info_message_get_content(const LinphoneInfoMess return (im->content && linphone_content_get_type(im->content)) ? im->content : NULL; } +SalCustomHeader *linphone_info_message_get_headers (const LinphoneInfoMessage *im) { + return im->headers; +} + void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, SalBodyHandler *body_handler){ LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); if (call){ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index dded5e4ef..9962d373a 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -18,174 +18,13 @@ 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. */ -#ifdef _WIN32 -#include -#endif -#include "linphone/core.h" -#include "linphone/sipsetup.h" -#include "linphone/lpconfig.h" + +#include +#include + +#include "linphone/types.h" + #include "private.h" -#include "conference_private.h" - -#include -#include -#include - -#include "mediastreamer2/mediastream.h" -#include "mediastreamer2/msvolume.h" -#include "mediastreamer2/msequalizer.h" -#include "mediastreamer2/msfileplayer.h" -#include "mediastreamer2/msjpegwriter.h" -#include "mediastreamer2/msogl.h" -#include "mediastreamer2/mseventqueue.h" -#include "mediastreamer2/mssndcard.h" -#include "mediastreamer2/msrtt4103.h" - -#include - -// For migration purpose. -#include "address/address-p.h" -#include "c-wrapper/c-wrapper.h" -#include "call/call.h" -#include "call/call-p.h" -#include "conference/params/media-session-params-p.h" - -struct _LinphoneCall{ - belle_sip_object_t base; - void *user_data; - bctbx_list_t *callbacks; /* A list of LinphoneCallCbs object */ - LinphoneCallCbs *current_cbs; /* The current LinphoneCallCbs object used to call a callback */ - std::shared_ptr call; - LinphoneCallParams *currentParamsCache; - LinphoneCallParams *paramsCache; - LinphoneCallParams *remoteParamsCache; - LinphoneAddress *remoteAddressCache; - char *remoteContactCache; - - struct _LinphoneCore *core; - LinphoneErrorInfo *ei; - SalMediaDescription *localdesc; - SalMediaDescription *resultdesc; - struct _LinphoneCallLog *log; - SalOp *op; - SalOp *ping_op; - LinphoneCallState transfer_state; /*idle if no transfer*/ - struct _AudioStream *audiostream; /**/ - struct _VideoStream *videostream; - struct _TextStream *textstream; - MSAudioEndpoint *endpoint; /*used for conferencing*/ - char *refer_to; - LinphoneCallParams *params; - LinphoneCallParams *current_params; - LinphoneCallParams *remote_params; - LinphoneCallStats *audio_stats; - LinphoneCallStats *video_stats; - LinphoneCallStats *text_stats; - LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/ - LinphoneCall *transfer_target;/*if this call received a transfer request, then transfer_target points to the new call created to the refer target */ - LinphonePlayer *player; - char *dtmf_sequence; /*DTMF sequence needed to be sent using #dtmfs_timer*/ - belle_sip_source_t *dtmfs_timer; /*DTMF timer needed to send a DTMF sequence*/ - LinphoneChatRoom *chat_room; - LinphoneConference *conf_ref; /**> Point on the associated conference if this call is part of a conference. NULL instead. */ - bool_t refer_pending; - bool_t defer_update; - bool_t was_automatically_paused; - bool_t paused_by_app; - bool_t broken; /*set to TRUE when the call is in broken state due to network disconnection or transport */ - bool_t need_localip_refresh; - bool_t reinvite_on_cancel_response_requested; - bool_t non_op_error; /*set when the LinphoneErrorInfo was set at higher level than sal*/ -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneCall); - - -typedef belle_sip_object_t_vptr_t LinphoneCallCbs_vptr_t; -BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCallCbs); -BELLE_SIP_INSTANCIATE_VPTR(LinphoneCallCbs, belle_sip_object_t, - NULL, // destroy - NULL, // clone - NULL, // Marshall - FALSE -); - -LinphoneCallCbs *_linphone_call_cbs_new(void) { - LinphoneCallCbs *obj = belle_sip_object_new(LinphoneCallCbs); - return obj; -} - -LinphoneCallCbs *linphone_call_cbs_ref(LinphoneCallCbs *cbs) { - return (LinphoneCallCbs *)belle_sip_object_ref(cbs); -} - -void linphone_call_cbs_unref(LinphoneCallCbs *cbs) { - belle_sip_object_unref(cbs); -} - -void *linphone_call_cbs_get_user_data(const LinphoneCallCbs *cbs) { - return cbs->user_data; -} - -void linphone_call_cbs_set_user_data(LinphoneCallCbs *cbs, void *user_data) { - cbs->user_data = user_data; -} - -LinphoneCallCbsDtmfReceivedCb linphone_call_cbs_get_dtmf_received(LinphoneCallCbs *cbs) { - return cbs->dtmf_received_cb; -} - -void linphone_call_cbs_set_dtmf_received(LinphoneCallCbs *cbs, LinphoneCallCbsDtmfReceivedCb cb) { - cbs->dtmf_received_cb = cb; -} - -LinphoneCallCbsEncryptionChangedCb linphone_call_cbs_get_encryption_changed(LinphoneCallCbs *cbs) { - return cbs->encryption_changed_cb; -} - -void linphone_call_cbs_set_encryption_changed(LinphoneCallCbs *cbs, LinphoneCallCbsEncryptionChangedCb cb) { - cbs->encryption_changed_cb = cb; -} - -LinphoneCallCbsInfoMessageReceivedCb linphone_call_cbs_get_info_message_received(LinphoneCallCbs *cbs) { - return cbs->info_message_received_cb; -} - -void linphone_call_cbs_set_info_message_received(LinphoneCallCbs *cbs, LinphoneCallCbsInfoMessageReceivedCb cb) { - cbs->info_message_received_cb = cb; -} - -LinphoneCallCbsStateChangedCb linphone_call_cbs_get_state_changed(LinphoneCallCbs *cbs) { - return cbs->state_changed_cb; -} - -void linphone_call_cbs_set_state_changed(LinphoneCallCbs *cbs, LinphoneCallCbsStateChangedCb cb) { - cbs->state_changed_cb = cb; -} - -LinphoneCallCbsStatsUpdatedCb linphone_call_cbs_get_stats_updated(LinphoneCallCbs *cbs) { - return cbs->stats_updated_cb; -} - -void linphone_call_cbs_set_stats_updated(LinphoneCallCbs *cbs, LinphoneCallCbsStatsUpdatedCb cb) { - cbs->stats_updated_cb = cb; -} - -LinphoneCallCbsTransferStateChangedCb linphone_call_cbs_get_transfer_state_changed(LinphoneCallCbs *cbs) { - return cbs->transfer_state_changed_cb; -} - -void linphone_call_cbs_set_transfer_state_changed(LinphoneCallCbs *cbs, LinphoneCallCbsTransferStateChangedCb cb) { - cbs->transfer_state_changed_cb = cb; -} - -LinphoneCallCbsAckProcessingCb linphone_call_cbs_get_ack_processing(LinphoneCallCbs *cbs){ - return cbs->ack_processing; -} - -void linphone_call_cbs_set_ack_processing(LinphoneCallCbs *cbs, LinphoneCallCbsAckProcessingCb cb){ - cbs->ack_processing = cb; -} bool_t linphone_call_state_is_early(LinphoneCallState state){ @@ -217,99 +56,6 @@ bool_t linphone_call_state_is_early(LinphoneCallState state){ return FALSE; } -MSWebCam *get_nowebcam_device(MSFactory* f){ -#ifdef VIDEO_ENABLED - return ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(f),"StaticImage: Static picture"); -#else - return NULL; -#endif -} - -LinphoneCore *linphone_call_get_core(const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->getCore(); -} - -const char * linphone_call_get_authentication_token(LinphoneCall *call) { - std::string token = linphone_call_get_cpp_obj(call)->getAuthenticationToken(); - return token.empty() ? nullptr : token.c_str(); -} - -bool_t linphone_call_get_authentication_token_verified(const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->getAuthenticationTokenVerified(); -} - -void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified) { - linphone_call_get_cpp_obj(call)->setAuthenticationTokenVerified(verified); -} - -bool_t is_payload_type_number_available(const bctbx_list_t *l, int number, const PayloadType *ignore){ - const bctbx_list_t *elem; - for (elem=l; elem!=NULL; elem=elem->next){ - const PayloadType *pt=(PayloadType*)elem->data; - if (pt!=ignore && payload_type_get_number(pt)==number) return FALSE; - } - return TRUE; -} - -void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall *call){ -} - -void linphone_call_make_local_media_description(LinphoneCall *call) { -} - -void linphone_call_create_op(LinphoneCall *call){ -#if 0 - if (call->op) sal_op_release(call->op); - call->op=sal_op_new(call->core->sal); - sal_op_set_user_pointer(call->op,call); - if (linphone_call_params_get_referer(call->params)) - sal_call_set_referer(call->op,linphone_call_params_get_referer(call->params)->op); - linphone_configure_op(call->core,call->op,call->log->to,linphone_call_params_get_custom_headers(call->params),FALSE); - if (linphone_call_params_get_privacy(call->params) != LinphonePrivacyDefault) - sal_op_set_privacy(call->op,(SalPrivacyMask)linphone_call_params_get_privacy(call->params)); - /*else privacy might be set by proxy */ -#endif -} - -static void linphone_call_destroy(LinphoneCall *obj); - -BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCall); - -BELLE_SIP_INSTANCIATE_VPTR(LinphoneCall, belle_sip_object_t, - (belle_sip_object_destroy_t)linphone_call_destroy, - NULL, // clone - NULL, // marshal - FALSE -); - -LinphoneCall * linphone_call_new_outgoing(LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){ - LinphoneCall *call = belle_sip_object_new(LinphoneCall); - call->currentParamsCache = linphone_call_params_new_for_wrapper(); - call->paramsCache = linphone_call_params_new_for_wrapper(); - call->remoteParamsCache = linphone_call_params_new_for_wrapper(); - call->remoteAddressCache = linphone_address_new(nullptr); - call->call = std::make_shared(call, lc, LinphoneCallOutgoing, - *L_GET_CPP_PTR_FROM_C_STRUCT(from, Address), *L_GET_CPP_PTR_FROM_C_STRUCT(to, Address), - cfg, nullptr, L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams)); - return call; -} - -LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, SalOp *op) { - LinphoneCall *call = belle_sip_object_new(LinphoneCall); - call->currentParamsCache = linphone_call_params_new_for_wrapper(); - call->paramsCache = linphone_call_params_new_for_wrapper(); - call->remoteParamsCache = linphone_call_params_new_for_wrapper(); - call->remoteAddressCache = linphone_address_new(nullptr); - call->call = std::make_shared(call, lc, LinphoneCallIncoming, - *L_GET_CPP_PTR_FROM_C_STRUCT(from, Address), *L_GET_CPP_PTR_FROM_C_STRUCT(to, Address), - nullptr, op, nullptr); - L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->initiateIncoming(); - return call; -} - -static void linphone_call_free_media_resources(LinphoneCall *call){ -} - const char *linphone_call_state_to_string(LinphoneCallState cs){ switch (cs){ case LinphoneCallIdle: @@ -358,266 +104,6 @@ const char *linphone_call_state_to_string(LinphoneCallState cs){ return "undefined state"; } -void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){ -} - -static void linphone_call_destroy(LinphoneCall *obj) { - ms_message("Call [%p] freed.", obj); - obj->call = nullptr; - if (obj->currentParamsCache) { - linphone_call_params_unref(obj->currentParamsCache); - obj->currentParamsCache = nullptr; - } - if (obj->paramsCache) { - linphone_call_params_unref(obj->paramsCache); - obj->paramsCache = nullptr; - } - if (obj->remoteParamsCache) { - linphone_call_params_unref(obj->remoteParamsCache); - obj->remoteParamsCache = nullptr; - } - if (obj->remoteAddressCache) { - linphone_address_unref(obj->remoteAddressCache); - obj->remoteAddressCache = nullptr; - } - bctbx_list_free_with_data(obj->callbacks, (bctbx_list_free_func)linphone_call_cbs_unref); - if (obj->audiostream || obj->videostream){ - linphone_call_free_media_resources(obj); - } - if (obj->audio_stats) { - linphone_call_stats_unref(obj->audio_stats); - obj->audio_stats = NULL; - } - if (obj->video_stats) { - linphone_call_stats_unref(obj->video_stats); - obj->video_stats = NULL; - } - if (obj->text_stats) { - linphone_call_stats_unref(obj->text_stats); - obj->text_stats = NULL; - } - if (obj->op!=NULL) { - sal_op_release(obj->op); - obj->op=NULL; - } - if (obj->resultdesc!=NULL) { - sal_media_description_unref(obj->resultdesc); - obj->resultdesc=NULL; - } - if (obj->localdesc!=NULL) { - sal_media_description_unref(obj->localdesc); - obj->localdesc=NULL; - } - if (obj->ping_op) { - sal_op_release(obj->ping_op); - obj->ping_op=NULL; - } - if (obj->refer_to){ - ms_free(obj->refer_to); - obj->refer_to=NULL; - } - if (obj->referer){ - linphone_call_unref(obj->referer); - obj->referer=NULL; - } - if (obj->transfer_target){ - linphone_call_unref(obj->transfer_target); - obj->transfer_target=NULL; - } - if (obj->log) { - linphone_call_log_unref(obj->log); - obj->log=NULL; - } - if (obj->dtmfs_timer) { - linphone_call_cancel_dtmfs(obj); - } - if (obj->params){ - linphone_call_params_unref(obj->params); - obj->params=NULL; - } - if (obj->current_params){ - linphone_call_params_unref(obj->current_params); - obj->current_params=NULL; - } - if (obj->remote_params != NULL) { - linphone_call_params_unref(obj->remote_params); - obj->remote_params=NULL; - } - if (obj->ei) linphone_error_info_unref(obj->ei); -} - -LinphoneCall * linphone_call_ref(LinphoneCall *obj){ - belle_sip_object_ref(obj); - return obj; -} - -void linphone_call_unref(LinphoneCall *obj){ - belle_sip_object_unref(obj); -} - -const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){ - L_SET_CPP_PTR_FROM_C_STRUCT(call->currentParamsCache, linphone_call_get_cpp_obj(call)->getCurrentParams()); - return call->currentParamsCache; -} - -const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call) { - const LinphonePrivate::MediaSessionParams *remoteParams = linphone_call_get_cpp_obj(call)->getRemoteParams(); - if (!remoteParams) - return nullptr; - L_SET_CPP_PTR_FROM_C_STRUCT(call->remoteParamsCache, remoteParams); - return call->remoteParamsCache; -} - -const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call) { - L_SET_CPP_PTR_FROM_C_STRUCT(call->remoteAddressCache, &linphone_call_get_cpp_obj(call)->getRemoteAddress()); - return call->remoteAddressCache; -} - -const LinphoneAddress * linphone_call_get_to_address(const LinphoneCall *call){ -#if 0 - return (const LinphoneAddress *)sal_op_get_to_address(call->op); -#else - return nullptr; -#endif -} - -const char *linphone_call_get_to_header(const LinphoneCall *call, const char *name){ -#if 0 - return sal_custom_header_find(sal_op_get_recv_custom_header(call->op),name); -#else - return nullptr; -#endif -} - -char * linphone_call_get_remote_address_as_string(const LinphoneCall *call) { - return ms_strdup(linphone_call_get_cpp_obj(call)->getRemoteAddressAsString().c_str()); -} - -const LinphoneAddress * linphone_call_get_diversion_address(const LinphoneCall *call){ -#if 0 - return call->op?(const LinphoneAddress *)sal_op_get_diversion_address(call->op):NULL; -#else - return nullptr; -#endif -} - -LinphoneCallState linphone_call_get_state(const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->getState(); -} - -LinphoneReason linphone_call_get_reason(const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->getReason(); -} - -const LinphoneErrorInfo * linphone_call_get_error_info(const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->getErrorInfo(); -} - -void *linphone_call_get_user_data(const LinphoneCall *call) { - return call->user_data; -} - -void linphone_call_set_user_data(LinphoneCall *call, void *user_pointer) { - call->user_data = user_pointer; -} - -LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){ - return linphone_call_get_cpp_obj(call)->getLog(); -} - -const char *linphone_call_get_refer_to(const LinphoneCall *call){ -#if 0 - return call->refer_to; -#else - return nullptr; -#endif -} - -LinphoneCall *linphone_call_get_transferer_call(const LinphoneCall *call){ -#if 0 - return call->referer; -#else - return nullptr; -#endif -} - -LinphoneCall *linphone_call_get_transfer_target_call(const LinphoneCall *call){ -#if 0 - return call->transfer_target; -#else - return nullptr; -#endif -} - -LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call) { - return linphone_call_log_get_dir(linphone_call_get_log(call)); -} - -const char *linphone_call_get_remote_user_agent(LinphoneCall *call){ -#if 0 - if (call->op){ - return sal_op_get_remote_ua (call->op); - } - return NULL; -#else - return nullptr; -#endif -} - -const char * linphone_call_get_remote_contact(LinphoneCall *call) { - std::string contact = linphone_call_get_cpp_obj(call)->getRemoteContact(); - if (contact.empty()) - return nullptr; - if (call->remoteContactCache) - bctbx_free(call->remoteContactCache); - call->remoteContactCache = bctbx_strdup(contact.c_str()); - return call->remoteContactCache; -} - -bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){ -#if 0 - return call->refer_pending; -#else - return FALSE; -#endif -} - -int linphone_call_get_duration(const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->getDuration(); -} - -LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){ -#if 0 - SalOp *op=sal_call_get_replaces(call->op); - if (op){ - return (LinphoneCall*)sal_op_get_user_pointer(op); - } - return NULL; -#else - return nullptr; -#endif -} - -void linphone_call_enable_camera(LinphoneCall *call, bool_t enable) { - linphone_call_get_cpp_obj(call)->enableCamera(enable); -} - -void linphone_call_send_vfu_request(LinphoneCall *call) { - linphone_call_get_cpp_obj(call)->sendVfuRequest(); -} - -LinphoneStatus linphone_call_take_video_snapshot(LinphoneCall *call, const char *file) { - return linphone_call_get_cpp_obj(call)->takeVideoSnapshot(file ? file : ""); -} - -LinphoneStatus linphone_call_take_preview_snapshot(LinphoneCall *call, const char *file) { - return linphone_call_get_cpp_obj(call)->takePreviewSnapshot(file ? file : ""); -} - -bool_t linphone_call_camera_enabled (const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->cameraEnabled(); -} - /** * @ingroup call_control * @return string value of LinphonePrivacy enum @@ -635,1010 +121,8 @@ const char* linphone_privacy_to_string(LinphonePrivacy privacy) { } } -void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) { - linphone_call_get_cpp_obj(call)->setNextVideoFrameDecodedCallback(cb, user_data); -} - -void linphone_call_init_media_streams(LinphoneCall *call){ -} - -#if 0 -static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'}; - -static void linphone_core_dtmf_received(LinphoneCall *call, int dtmf){ - if (dtmf<0 || dtmf>15){ - ms_warning("Bad dtmf value %i",dtmf); - return; - } - linphone_call_notify_dtmf_received(call, dtmf_tab[dtmf]); -} -#endif - void set_playback_gain_db(AudioStream *st, float gain){ if (st->volrecv){ ms_filter_call_method(st->volrecv,MS_VOLUME_SET_DB_GAIN,&gain); }else ms_warning("Could not apply playback gain: gain control wasn't activated."); } - -/*This function is not static because used internally in linphone-daemon project*/ -void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){ -} - -#if 0 -static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){ - int pause_time=3000; - audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone); - ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time); -} -#endif - -#if 0 -static bool_t linphone_call_sound_resources_available(LinphoneCall *call){ - LinphoneCore *lc=call->core; - LinphoneCall *current=linphone_core_get_current_call(lc); - return !linphone_core_is_in_conference(lc) && - (current==NULL || current==call); -} -#endif - -void linphone_call_delete_upnp_session(LinphoneCall *call){ -} - -void linphone_call_stop_media_streams(LinphoneCall *call){ -} - -void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) { - linphone_call_get_cpp_obj(call)->enableEchoCancellation(enable); -} - -bool_t linphone_call_echo_cancellation_enabled(const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->echoCancellationEnabled(); -} - -void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val) { - linphone_call_get_cpp_obj(call)->enableEchoLimiter(val); -} - -bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->echoLimiterEnabled(); -} - -float linphone_call_get_play_volume(const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->getPlayVolume(); -} - -float linphone_call_get_record_volume(const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->getRecordVolume(); -} - -float linphone_call_get_speaker_volume_gain(const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->getSpeakerVolumeGain(); -} - -void linphone_call_set_speaker_volume_gain(LinphoneCall *call, float volume) { - linphone_call_get_cpp_obj(call)->setSpeakerVolumeGain(volume); -} - -float linphone_call_get_microphone_volume_gain(const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->getMicrophoneVolumeGain(); -} - -void linphone_call_set_microphone_volume_gain(LinphoneCall *call, float volume) { - linphone_call_get_cpp_obj(call)->setMicrophoneVolumeGain(volume); -} - -float linphone_call_get_current_quality(const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->getCurrentQuality(); -} - -float linphone_call_get_average_quality(const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->getAverageQuality(); -} - -void linphone_call_stats_update(LinphoneCallStats *stats, MediaStream *stream) { - PayloadType *pt; - RtpSession *session = stream->sessions.rtp_session; - const MSQualityIndicator *qi = media_stream_get_quality_indicator(stream); - if (qi) { - stats->local_late_rate=ms_quality_indicator_get_local_late_rate(qi); - stats->local_loss_rate=ms_quality_indicator_get_local_loss_rate(qi); - } - media_stream_get_local_rtp_stats(stream, &stats->rtp_stats); - pt = rtp_profile_get_payload(rtp_session_get_profile(session), rtp_session_get_send_payload_type(session)); - stats->clockrate = pt ? pt->clock_rate : 8000; -} - -MediaStream * linphone_call_get_stream(LinphoneCall *call, LinphoneStreamType type) { - return L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->getMediaStream(type); -} - -void _linphone_call_stats_clone(LinphoneCallStats *dst, const LinphoneCallStats *src) { - /* - * Save the belle_sip_object_t part, copy the entire structure and restore the belle_sip_object_t part - */ - belle_sip_object_t tmp = dst->base; - memcpy(dst, src, sizeof(LinphoneCallStats)); - dst->base = tmp; - - dst->received_rtcp = NULL; - dst->sent_rtcp = NULL; -} - -LinphoneCallStats *linphone_call_get_stats(LinphoneCall *call, LinphoneStreamType type) { - return linphone_call_get_cpp_obj(call)->getStats(type); -} - -LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->getAudioStats(); -} - -LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->getVideoStats(); -} - -LinphoneCallStats *linphone_call_get_text_stats(LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->getTextStats(); -} - -bool_t linphone_call_media_in_progress(const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->mediaInProgress(); -} - -BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCallStats); - -BELLE_SIP_INSTANCIATE_VPTR(LinphoneCallStats, belle_sip_object_t, - NULL, // destroy - _linphone_call_stats_clone, // clone - NULL, // marshal - TRUE -); - -LinphoneCallStats *linphone_call_stats_new() { - LinphoneCallStats *stats = belle_sip_object_new(LinphoneCallStats); - return stats; -} - -LinphoneCallStats* linphone_call_stats_ref(LinphoneCallStats* stats) { - return (LinphoneCallStats*) belle_sip_object_ref(stats); -} - -void linphone_call_stats_unref(LinphoneCallStats* stats) { - belle_sip_object_unref(stats); -} - -void *linphone_call_stats_get_user_data(const LinphoneCallStats *stats) { - return stats->user_data; -} - -void linphone_call_stats_set_user_data(LinphoneCallStats *stats, void *data) { - stats->user_data = data; -} - -LinphoneStreamType linphone_call_stats_get_type(const LinphoneCallStats *stats) { - return stats->type; -} - -float linphone_call_stats_get_sender_loss_rate(const LinphoneCallStats *stats) { - const report_block_t *srb = NULL; - - if (!stats || !stats->sent_rtcp) - return 0.0; - /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ - if (stats->sent_rtcp->b_cont != NULL) - msgpullup(stats->sent_rtcp, -1); - - do{ - if (rtcp_is_SR(stats->sent_rtcp)) - srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0); - else if (rtcp_is_RR(stats->sent_rtcp)) - srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0); - if (srb) break; - }while (rtcp_next_packet(stats->sent_rtcp)); - rtcp_rewind(stats->sent_rtcp); - if (!srb) - return 0.0; - return 100.0f * (float)report_block_get_fraction_lost(srb) / 256.0f; -} - -float linphone_call_stats_get_receiver_loss_rate(const LinphoneCallStats *stats) { - const report_block_t *rrb = NULL; - - if (!stats || !stats->received_rtcp) - return 0.0; - /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ - if (stats->received_rtcp->b_cont != NULL) - msgpullup(stats->received_rtcp, -1); - - do{ - if (rtcp_is_RR(stats->received_rtcp)) - rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0); - else if (rtcp_is_SR(stats->received_rtcp)) - rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0); - if (rrb) break; - }while (rtcp_next_packet(stats->received_rtcp)); - rtcp_rewind(stats->received_rtcp); - if (!rrb) - return 0.0; - return 100.0f * (float)report_block_get_fraction_lost(rrb) / 256.0f; -} - -float linphone_call_stats_get_local_loss_rate(const LinphoneCallStats *stats) { - return stats->local_loss_rate; -} - -float linphone_call_stats_get_local_late_rate(const LinphoneCallStats *stats) { - return stats->local_late_rate; -} - -float linphone_call_stats_get_sender_interarrival_jitter(const LinphoneCallStats *stats) { - const report_block_t *srb = NULL; - - if (!stats || !stats->sent_rtcp) - return 0.0; - /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ - if (stats->sent_rtcp->b_cont != NULL) - msgpullup(stats->sent_rtcp, -1); - if (rtcp_is_SR(stats->sent_rtcp)) - srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0); - else if (rtcp_is_RR(stats->sent_rtcp)) - srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0); - if (!srb) - return 0.0; - if (stats->clockrate == 0) - return 0.0; - return (float)report_block_get_interarrival_jitter(srb) / (float)stats->clockrate; -} - -float linphone_call_stats_get_receiver_interarrival_jitter(const LinphoneCallStats *stats) { - const report_block_t *rrb = NULL; - - if (!stats || !stats->received_rtcp) - return 0.0; - /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ - if (stats->received_rtcp->b_cont != NULL) - msgpullup(stats->received_rtcp, -1); - if (rtcp_is_SR(stats->received_rtcp)) - rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0); - else if (rtcp_is_RR(stats->received_rtcp)) - rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0); - if (!rrb) - return 0.0; - if (stats->clockrate == 0) - return 0.0; - return (float)report_block_get_interarrival_jitter(rrb) / (float)stats->clockrate; -} - -const rtp_stats_t *linphone_call_stats_get_rtp_stats(const LinphoneCallStats *stats) { - return &stats->rtp_stats; -} - -uint64_t linphone_call_stats_get_late_packets_cumulative_number(const LinphoneCallStats *stats) { - return linphone_call_stats_get_rtp_stats(stats)->outoftime; -} - -float linphone_call_stats_get_download_bandwidth(const LinphoneCallStats *stats) { - return stats->download_bandwidth; -} - -float linphone_call_stats_get_upload_bandwidth(const LinphoneCallStats *stats) { - return stats->upload_bandwidth; -} - -LinphoneIceState linphone_call_stats_get_ice_state(const LinphoneCallStats *stats) { - return stats->ice_state; -} - -LinphoneUpnpState linphone_call_stats_get_upnp_state(const LinphoneCallStats *stats) { - return stats->upnp_state; -} - -LinphoneAddressFamily linphone_call_stats_get_ip_family_of_remote(const LinphoneCallStats *stats) { - return (LinphoneAddressFamily)stats->rtp_remote_family; -} - -float linphone_call_stats_get_jitter_buffer_size_ms(const LinphoneCallStats *stats) { - return stats->jitter_stats.jitter_buffer_size_ms; -} - -float linphone_call_stats_get_round_trip_delay(const LinphoneCallStats *stats) { - return stats->round_trip_delay; -} - -void linphone_call_start_recording(LinphoneCall *call) { - linphone_call_get_cpp_obj(call)->startRecording(); -} - -void linphone_call_stop_recording(LinphoneCall *call) { - linphone_call_get_cpp_obj(call)->stopRecording(); -} - -#if 0 -static void linphone_call_lost(LinphoneCall *call){ - LinphoneCore *lc = call->core; - char *temp = NULL; - char *from = NULL; - - from = linphone_call_get_remote_address_as_string(call); - temp = ms_strdup_printf("Media connectivity with %s is lost, call is going to be closed.", from ? from : "?"); - if (from) ms_free(from); - ms_message("LinphoneCall [%p]: %s", call, temp); - linphone_core_notify_display_warning(lc, temp); - call->non_op_error = TRUE; - linphone_error_info_set(call->ei,NULL, LinphoneReasonIOError, 503, "Media lost", NULL); - linphone_call_terminate(call); - linphone_core_play_named_tone(lc, LinphoneToneCallLost); - ms_free(temp); -} -#endif - -/*do not change the prototype of this function, it is also used internally in linphone-daemon.*/ -void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEvent *ev){ - OrtpEventType evt=ortp_event_get_type(ev); - OrtpEventData *evd=ortp_event_get_data(ev); - - if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { - stats->round_trip_delay = rtp_session_get_round_trip_propagation(ms->sessions.rtp_session); - if(stats->received_rtcp != NULL) - freemsg(stats->received_rtcp); - stats->received_rtcp = evd->packet; - stats->rtcp_received_via_mux = evd->info.socket_type == OrtpRTPSocket; - evd->packet = NULL; - stats->updated = LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE; - linphone_call_stats_update(stats,ms); - } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { - memcpy(&stats->jitter_stats, rtp_session_get_jitter_stats(ms->sessions.rtp_session), sizeof(jitter_stats_t)); - if (stats->sent_rtcp != NULL) - freemsg(stats->sent_rtcp); - stats->sent_rtcp = evd->packet; - evd->packet = NULL; - stats->updated = LINPHONE_CALL_STATS_SENT_RTCP_UPDATE; - linphone_call_stats_update(stats,ms); - } -} - -void linphone_call_stats_uninit(LinphoneCallStats *stats){ - if (stats->received_rtcp) { - freemsg(stats->received_rtcp); - stats->received_rtcp=NULL; - } - if (stats->sent_rtcp){ - freemsg(stats->sent_rtcp); - stats->sent_rtcp=NULL; - } -} - -LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) { -#if 0 - return call->transfer_state; -#else - return LinphoneCallIdle; -#endif -} - -void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) { -#if 0 - if (state != call->transfer_state) { - ms_message("Transfer state for call [%p] changed from [%s] to [%s]",call - ,linphone_call_state_to_string(call->transfer_state) - ,linphone_call_state_to_string(state)); - call->transfer_state = state; - linphone_call_notify_transfer_state_changed(call, state); - } -#endif -} - -bool_t linphone_call_is_in_conference(const LinphoneCall *call) { -#if 0 - return linphone_call_params_get_in_conference(call->params); -#else - return FALSE; -#endif -} - -LinphoneConference *linphone_call_get_conference(const LinphoneCall *call) { -#if 0 - return call->conf_ref; -#else - return nullptr; -#endif -} - -void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) { - linphone_call_get_cpp_obj(call)->zoomVideo(zoom_factor, cx, cy); -} - -LinphonePlayer *linphone_call_get_player(LinphoneCall *call){ -#if 0 - if (call->player==NULL) - call->player=linphone_call_build_player(call); - return call->player; -#else - return nullptr; -#endif -} - - -void linphone_call_set_params(LinphoneCall *call, const LinphoneCallParams *params){ -#if 0 - if ( call->state == LinphoneCallOutgoingInit || call->state == LinphoneCallIncomingReceived){ - _linphone_call_set_new_params(call, params); - } - else { - ms_error("linphone_call_set_params() invalid state %s to call this function", linphone_call_state_to_string(call->state)); - } -#endif -} - - -void _linphone_call_set_new_params(LinphoneCall *call, const LinphoneCallParams *params){ -} - -const LinphoneCallParams * linphone_call_get_params(LinphoneCall *call) { - L_SET_CPP_PTR_FROM_C_STRUCT(call->paramsCache, linphone_call_get_cpp_obj(call)->getParams()); - return call->paramsCache; -} - -#if 0 -static int send_dtmf_handler(void *data, unsigned int revents){ - LinphoneCall *call = (LinphoneCall*)data; - /*By default we send DTMF RFC2833 if we do not have enabled SIP_INFO but we can also send RFC2833 and SIP_INFO*/ - if (linphone_core_get_use_rfc2833_for_dtmf(call->core)!=0 || linphone_core_get_use_info_for_dtmf(call->core)==0) - { - /* In Band DTMF */ - if (call->audiostream!=NULL){ - audio_stream_send_dtmf(call->audiostream,*call->dtmf_sequence); - } - else - { - ms_error("Cannot send RFC2833 DTMF when we are not in communication."); - return FALSE; - } - } - if (linphone_core_get_use_info_for_dtmf(call->core)!=0){ - /* Out of Band DTMF (use INFO method) */ - sal_call_send_dtmf(call->op,*call->dtmf_sequence); - } - - /*this check is needed because linphone_call_send_dtmf does not set the timer since its a single character*/ - if (call->dtmfs_timer!=NULL) { - memmove(call->dtmf_sequence, call->dtmf_sequence+1, strlen(call->dtmf_sequence)); - } - /* continue only if the dtmf sequence is not empty*/ - if (call->dtmf_sequence!=NULL&&*call->dtmf_sequence!='\0') { - return TRUE; - } else { - linphone_call_cancel_dtmfs(call); - return FALSE; - } -} -#endif - -LinphoneStatus linphone_call_send_dtmf(LinphoneCall *call, char dtmf) { -#if 0 - if (call==NULL){ - ms_warning("linphone_call_send_dtmf(): invalid call, canceling DTMF."); - return -1; - } - call->dtmf_sequence = &dtmf; - send_dtmf_handler(call,0); - call->dtmf_sequence = NULL; - return 0; -#else - return 0; -#endif -} - -LinphoneStatus linphone_call_send_dtmfs(LinphoneCall *call,const char *dtmfs) { -#if 0 - if (call==NULL){ - ms_warning("linphone_call_send_dtmfs(): invalid call, canceling DTMF sequence."); - return -1; - } - if (call->dtmfs_timer!=NULL){ - ms_warning("linphone_call_send_dtmfs(): a DTMF sequence is already in place, canceling DTMF sequence."); - return -2; - } - if (dtmfs != NULL) { - int delay_ms = lp_config_get_int(call->core->config,"net","dtmf_delay_ms",200); - call->dtmf_sequence = ms_strdup(dtmfs); - call->dtmfs_timer = sal_create_timer(call->core->sal, send_dtmf_handler, call, delay_ms, "DTMF sequence timer"); - } - return 0; -#else - return 0; -#endif -} - -void linphone_call_cancel_dtmfs(LinphoneCall *call) { -#if 0 - /*nothing to do*/ - if (!call || !call->dtmfs_timer) return; - - sal_cancel_timer(call->core->sal, call->dtmfs_timer); - belle_sip_object_unref(call->dtmfs_timer); - call->dtmfs_timer = NULL; - if (call->dtmf_sequence != NULL) { - ms_free(call->dtmf_sequence); - call->dtmf_sequence = NULL; - } -#endif -} - -void * linphone_call_get_native_video_window_id(const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->getNativeVideoWindowId(); -} - -void linphone_call_set_native_video_window_id(LinphoneCall *call, void *id) { - linphone_call_get_cpp_obj(call)->setNativeVideoWindowId(id); -} - -void linphone_call_set_audio_route(LinphoneCall *call, LinphoneAudioRoute route) { -#if 0 - if (call != NULL && call->audiostream != NULL){ - audio_stream_set_audio_route(call->audiostream, (MSAudioRoute) route); - } -#endif -} - -LinphoneChatRoom * linphone_call_get_chat_room(LinphoneCall *call) { -#if 0 - if (!call->chat_room){ - if (call->state != LinphoneCallReleased && call->state != LinphoneCallEnd){ - call->chat_room = _linphone_core_create_chat_room_from_call(call); - } - } - return call->chat_room; -#else - return nullptr; -#endif -} - -int linphone_call_get_stream_count(const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->getStreamCount(); -} - -MSFormatType linphone_call_get_stream_type(const LinphoneCall *call, int stream_index) { - return linphone_call_get_cpp_obj(call)->getStreamType(stream_index); -} - -RtpTransport * linphone_call_get_meta_rtp_transport(const LinphoneCall *call, int stream_index) { - return linphone_call_get_cpp_obj(call)->getMetaRtpTransport(stream_index); -} - -RtpTransport * linphone_call_get_meta_rtcp_transport(const LinphoneCall *call, int stream_index) { - return linphone_call_get_cpp_obj(call)->getMetaRtcpTransport(stream_index); -} - -LinphoneStatus linphone_call_pause(LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->pause(); -} - -/* Internal version that does not play tone indication*/ -int _linphone_call_pause(LinphoneCall *call) { - return 0; -} - -LinphoneStatus linphone_call_resume(LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->resume(); -} - -#if 0 -static void terminate_call(LinphoneCall *call) { -} -#endif - -LinphoneStatus linphone_call_terminate(LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->terminate(); -} - -LinphoneStatus linphone_call_terminate_with_error_info(LinphoneCall *call , const LinphoneErrorInfo *ei) { - return linphone_call_get_cpp_obj(call)->terminate(ei); -} - -LinphoneStatus linphone_call_redirect(LinphoneCall *call, const char *redirect_uri) { -#if 0 - char *real_url = NULL; - LinphoneCore *lc; - LinphoneAddress *real_parsed_url; - SalErrorInfo sei; - - if (call->state != LinphoneCallIncomingReceived) { - ms_error("Bad state for call redirection."); - return -1; - } - - lc = linphone_call_get_core(call); - real_parsed_url = linphone_core_interpret_url(lc, redirect_uri); - if (!real_parsed_url) { - /* Bad url */ - ms_error("Bad redirect URI: %s", redirect_uri ? redirect_uri : "NULL"); - return -1; - } - - memset(&sei, 0, sizeof(sei)); - real_url = linphone_address_as_string(real_parsed_url); - sal_error_info_set(&sei,SalReasonRedirect, "SIP", 0, NULL, NULL); - sal_call_decline_with_error_info(call->op, &sei, real_url); - ms_free(real_url); - linphone_error_info_set(call->ei, NULL, LinphoneReasonMovedPermanently, 302, "Call redirected", NULL); - call->non_op_error = TRUE; - terminate_call(call); - linphone_address_unref(real_parsed_url); - sal_error_info_reset(&sei); - return 0; -#else - return 0; -#endif -} - -LinphoneStatus linphone_call_decline(LinphoneCall *call, LinphoneReason reason) { - return linphone_call_get_cpp_obj(call)->decline(reason); -} - -LinphoneStatus linphone_call_decline_with_error_info(LinphoneCall *call, const LinphoneErrorInfo *ei) { - return linphone_call_get_cpp_obj(call)->decline(ei); -} - -LinphoneStatus linphone_call_accept(LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->accept(nullptr); -} - -LinphoneStatus linphone_call_accept_with_params(LinphoneCall *call, const LinphoneCallParams *params) { - return linphone_call_get_cpp_obj(call)->accept(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams) : nullptr); -} - -LinphoneStatus linphone_call_accept_early_media(LinphoneCall* call) { - return linphone_call_get_cpp_obj(call)->acceptEarlyMedia(); -} - -LinphoneStatus linphone_call_accept_early_media_with_params(LinphoneCall *call, const LinphoneCallParams *params) { - return linphone_call_get_cpp_obj(call)->acceptEarlyMedia(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams) : nullptr); -} - -LinphoneStatus linphone_call_update(LinphoneCall *call, const LinphoneCallParams *params) { - return linphone_call_get_cpp_obj(call)->update(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams) : nullptr); -} - -int linphone_call_start_update(LinphoneCall *call) { - return 0; -} - -LinphoneStatus linphone_call_defer_update(LinphoneCall *call) { -#if 0 - if (call->state != LinphoneCallUpdatedByRemote) { - ms_error("linphone_call_defer_update() not done in state LinphoneCallUpdatedByRemote"); - return -1; - } - - if (call->expect_media_in_ack) { - ms_error("linphone_call_defer_update() is not possible during a late offer incoming reINVITE (INVITE without SDP)"); - return -1; - } - - call->defer_update=TRUE; - return 0; -#else - return 0; -#endif -} - -int linphone_call_start_accept_update(LinphoneCall *call, LinphoneCallState next_state, const char *state_info) { - return 0; -} - -LinphoneStatus linphone_call_accept_update(LinphoneCall *call, const LinphoneCallParams *params) { - return linphone_call_get_cpp_obj(call)->acceptUpdate(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams) : nullptr); -} - -LinphoneStatus linphone_call_transfer(LinphoneCall *call, const char *refer_to) { -#if 0 - char *real_url = NULL; - LinphoneCore *lc = linphone_call_get_core(call); - LinphoneAddress *real_parsed_url = linphone_core_interpret_url(lc, refer_to); - - if (!real_parsed_url) { - /* bad url */ - return -1; - } - //lc->call = NULL; // Do not do that you will lose the call afterward... - real_url = linphone_address_as_string(real_parsed_url); - sal_call_refer(call->op, real_url); - ms_free(real_url); - linphone_address_unref(real_parsed_url); - linphone_call_set_transfer_state(call, LinphoneCallOutgoingInit); - return 0; -#else - return 0; -#endif -} - -LinphoneStatus linphone_call_transfer_to_another(LinphoneCall *call, LinphoneCall *dest) { -#if 0 - int result = sal_call_refer_with_replaces (call->op, dest->op); - linphone_call_set_transfer_state(call, LinphoneCallOutgoingInit); - return result; -#else - return 0; -#endif -} - -int linphone_call_proceed_with_invite_if_ready(LinphoneCall *call, LinphoneProxyConfig *dest_proxy) { - return 0; -} - -int linphone_call_start_invite(LinphoneCall *call, const LinphoneAddress *destination /* = NULL if to be taken from the call log */) { - return 0; -} - -void linphone_call_set_broken(LinphoneCall *call){ -#if 0 - switch(call->state){ - /*for all the early states, we prefer to drop the call*/ - case LinphoneCallOutgoingInit: - case LinphoneCallOutgoingProgress: - case LinphoneCallOutgoingRinging: - case LinphoneCallOutgoingEarlyMedia: - case LinphoneCallIncomingReceived: - case LinphoneCallIncomingEarlyMedia: - /*during the early states, the SAL layer reports the failure from the dialog or transaction layer, - * hence, there is nothing special to do*/ - //break; - case LinphoneCallStreamsRunning: - case LinphoneCallUpdating: - case LinphoneCallPausing: - case LinphoneCallResuming: - case LinphoneCallPaused: - case LinphoneCallPausedByRemote: - case LinphoneCallUpdatedByRemote: - /*during these states, the dialog is established. A failure of a transaction is not expected to close it. - * Instead we have to repair the dialog by sending a reINVITE*/ - call->broken = TRUE; - call->need_localip_refresh = TRUE; - break; - default: - ms_error("linphone_call_set_broken() unimplemented case."); - break; - } -#endif -} - -#if 0 -static void linphone_call_repair_by_invite_with_replaces(LinphoneCall *call) { - const char *call_id = sal_op_get_call_id(call->op); - const char *from_tag = sal_call_get_local_tag(call->op); - const char *to_tag = sal_call_get_remote_tag(call->op); - sal_op_kill_dialog(call->op); - linphone_call_create_op(call); - sal_call_set_replaces(call->op, call_id, from_tag, to_tag); - linphone_call_start_invite(call, NULL); -} -#endif - -void linphone_call_reinvite_to_recover_from_connection_loss(LinphoneCall *call) { -#if 0 - LinphoneCallParams *params; - ms_message("LinphoneCall[%p] is going to be updated (reINVITE) in order to recover from lost connectivity", call); - if (call->ice_session){ - ice_session_reset(call->ice_session, IR_Controlling); - } - params = linphone_core_create_call_params(call->core, call); - linphone_call_update(call, params); - linphone_call_params_unref(params); -#endif -} - -void linphone_call_repair_if_broken(LinphoneCall *call){ -#if 0 - SalErrorInfo sei; - if (!call->broken) return; - if (!call->core->media_network_reachable) return; - - memset(&sei, 0, sizeof(sei)); - - /*Make sure that the proxy from which we received this call, or to which we routed this call is registered first*/ - if (call->dest_proxy){ - /*in all other cases, ie no proxy config, or a proxy config for which no registration was requested, we can start the - * call repair immediately.*/ - if (linphone_proxy_config_register_enabled(call->dest_proxy) - && linphone_proxy_config_get_state(call->dest_proxy) != LinphoneRegistrationOk) return; - } - - switch (call->state){ - case LinphoneCallUpdating: - case LinphoneCallPausing: - if (sal_call_dialog_request_pending(call->op)) { - /* Need to cancel first re-INVITE as described in section 5.5 of RFC 6141 */ - sal_call_cancel_invite(call->op); - call->reinvite_on_cancel_response_requested = TRUE; - } - break; - case LinphoneCallStreamsRunning: - case LinphoneCallPaused: - case LinphoneCallPausedByRemote: - if (!sal_call_dialog_request_pending(call->op)) { - linphone_call_reinvite_to_recover_from_connection_loss(call); - } - break; - case LinphoneCallUpdatedByRemote: - if (sal_call_dialog_request_pending(call->op)) { - sal_error_info_set(&sei, SalReasonServiceUnavailable,"SIP", 0, NULL, NULL); - sal_call_decline_with_error_info(call->op, &sei,NULL); - } - linphone_call_reinvite_to_recover_from_connection_loss(call); - break; - case LinphoneCallOutgoingInit: - case LinphoneCallOutgoingProgress: - sal_call_cancel_invite(call->op); - call->reinvite_on_cancel_response_requested = TRUE; - break; - case LinphoneCallOutgoingEarlyMedia: - case LinphoneCallOutgoingRinging: - linphone_call_repair_by_invite_with_replaces(call); - break; - case LinphoneCallIncomingEarlyMedia: - case LinphoneCallIncomingReceived: - /* Keep the call broken until a forked INVITE is received from the server. */ - break; - default: - ms_warning("linphone_call_repair_if_broken(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state)); - call->broken = FALSE; - break; - } - sal_error_info_reset(&sei); -#endif -} - -void linphone_call_refresh_sockets(LinphoneCall *call){ -#if 0 - int i; - for (i=0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i){ - MSMediaStreamSessions *mss = &call->sessions[i]; - if (mss->rtp_session){ - rtp_session_refresh_sockets(mss->rtp_session); - } - } -#endif -} - -void linphone_call_replace_op(LinphoneCall *call, SalOp *op) { -#if 0 - SalOp *oldop = call->op; - LinphoneCallState oldstate = linphone_call_get_state(call); - call->op = op; - sal_op_set_user_pointer(call->op, call); - sal_call_set_local_media_description(call->op, call->localdesc); - switch (linphone_call_get_state(call)) { - case LinphoneCallIncomingEarlyMedia: - case LinphoneCallIncomingReceived: - sal_call_notify_ringing(call->op, (linphone_call_get_state(call) == LinphoneCallIncomingEarlyMedia) ? TRUE : FALSE); - break; - case LinphoneCallConnected: - case LinphoneCallStreamsRunning: - sal_call_accept(call->op); - break; - default: - ms_warning("linphone_call_replace_op(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state)); - break; - } - switch (oldstate) { - case LinphoneCallIncomingEarlyMedia: - case LinphoneCallIncomingReceived: - sal_op_set_user_pointer(oldop, NULL); /* To make the call does not get terminated by terminating this op. */ - /* Do not terminate a forked INVITE */ - if (sal_call_get_replaces(op)) { - sal_call_terminate(oldop); - } else { - sal_op_kill_dialog(oldop); - } - break; - case LinphoneCallConnected: - case LinphoneCallStreamsRunning: - sal_call_terminate(oldop); - sal_op_kill_dialog(oldop); - break; - default: - break; - } - sal_op_release(oldop); -#endif -} - -void linphone_call_ogl_render(const LinphoneCall *call) { -#if 0 - #ifdef VIDEO_ENABLED - - VideoStream *stream = call->videostream; - if (stream && stream->output && ms_filter_get_id(stream->output) == MS_OGL_ID) - ms_filter_call_method(stream->output, MS_OGL_RENDER, NULL); - - #endif -#endif -} - -void linphone_call_add_callbacks(LinphoneCall *call, LinphoneCallCbs *cbs) { - call->callbacks = bctbx_list_append(call->callbacks, linphone_call_cbs_ref(cbs)); -} - -void linphone_call_remove_callbacks(LinphoneCall *call, LinphoneCallCbs *cbs) { - call->callbacks = bctbx_list_remove(call->callbacks, cbs); - linphone_call_cbs_unref(cbs); -} - -LinphoneCallCbs *linphone_call_get_current_callbacks(const LinphoneCall *call) { - return call->current_cbs; -} - -#define NOTIFY_IF_EXIST(function_name, ...) \ - bctbx_list_t* iterator; \ - for (iterator = call->callbacks; iterator != NULL; iterator = bctbx_list_next(iterator)) { \ - call->current_cbs = (LinphoneCallCbs *)bctbx_list_get_data(iterator); \ - if (call->current_cbs->function_name != NULL) { \ - call->current_cbs->function_name(__VA_ARGS__); \ - } \ - } - -void linphone_call_notify_state_changed(LinphoneCall *call, LinphoneCallState cstate, const char *message) { - NOTIFY_IF_EXIST(state_changed_cb, call, cstate, message) - linphone_core_notify_call_state_changed(linphone_call_get_core(call), call, cstate, message); -} - -void linphone_call_notify_dtmf_received(LinphoneCall *call, int dtmf) { - NOTIFY_IF_EXIST(dtmf_received_cb, call, dtmf) - linphone_core_notify_dtmf_received(linphone_call_get_core(call), call, dtmf); -} - -void linphone_call_notify_encryption_changed(LinphoneCall *call, bool_t on, const char *authentication_token) { - NOTIFY_IF_EXIST(encryption_changed_cb, call, on, authentication_token) - linphone_core_notify_call_encryption_changed(linphone_call_get_core(call), call, on, authentication_token); -} - -void linphone_call_notify_transfer_state_changed(LinphoneCall *call, LinphoneCallState cstate) { - NOTIFY_IF_EXIST(transfer_state_changed_cb, call, cstate) - linphone_core_notify_transfer_state_changed(linphone_call_get_core(call), call, cstate); -} - -void linphone_call_notify_stats_updated(LinphoneCall *call, const LinphoneCallStats *stats) { - NOTIFY_IF_EXIST(stats_updated_cb, call, stats) - linphone_core_notify_call_stats_updated(linphone_call_get_core(call), call, stats); -} - -void linphone_call_notify_info_message_received(LinphoneCall *call, const LinphoneInfoMessage *msg) { - NOTIFY_IF_EXIST(info_message_received_cb, call, msg) - linphone_core_notify_info_received(linphone_call_get_core(call), call, msg); -} - -void linphone_call_notify_ack_processing(LinphoneCall *call, LinphoneHeaders *msg, bool_t is_received) { - NOTIFY_IF_EXIST(ack_processing, call, msg, is_received) -} - -SalOp * linphone_call_get_op(const LinphoneCall *call) { - return L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->getOp(); -} - -LinphoneProxyConfig * linphone_call_get_dest_proxy(const LinphoneCall *call) { - return L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->getDestProxy(); -} - -LinphoneCallLog * linphone_call_get_log(const LinphoneCall *call) { - return linphone_call_get_call_log(call); -} - -IceSession * linphone_call_get_ice_session(const LinphoneCall *call) { - return L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->getIceSession(); -} - -bool_t linphone_call_get_audio_muted(const LinphoneCall *call) { - return L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->getAudioMuted(); -} - -void linphone_call_set_audio_muted(LinphoneCall *call, bool_t value) { - L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->setAudioMuted(value); -} - -bool_t linphone_call_get_all_muted(const LinphoneCall *call) { - return linphone_call_get_cpp_obj(call)->getAllMuted(); -} - -std::shared_ptr linphone_call_get_cpp_obj(const LinphoneCall *call) { - return call->call; -} diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 4f2412b6f..c646bfbdc 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -454,14 +454,6 @@ int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){ return 0; } -bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call){ - //return TRUE if the unique(for the moment) incoming call asked to be autoanswered - if(call) - return sal_call_autoanswer_asked(linphone_call_get_op(call)); - else - return FALSE; -} - int linphone_core_get_current_call_duration(const LinphoneCore *lc){ LinphoneCall *call=linphone_core_get_current_call((LinphoneCore *)lc); if (call) return linphone_call_get_duration(call); @@ -3232,7 +3224,7 @@ void linphone_core_iterate(LinphoneCore *lc){ /* Get immediately a reference to next one in case the one we are going to examine is destroyed * and removed during linphone_call_start_invite() */ calls = bctbx_list_next(calls); - L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->iterate(current_real_time, one_second_elapsed); + L_GET_PRIVATE_FROM_C_STRUCT(call, Call)->iterate(current_real_time, one_second_elapsed); } if (linphone_core_video_preview_enabled(lc)){ @@ -3558,9 +3550,9 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const if (linphone_call_params_get_local_conference_mode(params) == FALSE) #endif lc->current_call=call; - bool defer = L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->initiateOutgoing(); + bool defer = L_GET_PRIVATE_FROM_C_STRUCT(call, Call)->initiateOutgoing(); if (!defer) { - if (L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->startInvite(nullptr) != 0) { + if (L_GET_PRIVATE_FROM_C_STRUCT(call, Call)->startInvite(nullptr) != 0) { /* The call has already gone to error and released state, so do not return it */ call = nullptr; } diff --git a/coreapi/private.h b/coreapi/private.h index 2b57ff947..fab87f38f 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -228,19 +228,7 @@ typedef struct _PortConfig{ int rtcp_port; }PortConfig; -struct _LinphoneCallCbs { - belle_sip_object_t base; - void *user_data; - LinphoneCallCbsDtmfReceivedCb dtmf_received_cb; - LinphoneCallCbsEncryptionChangedCb encryption_changed_cb; - LinphoneCallCbsInfoMessageReceivedCb info_message_received_cb; - LinphoneCallCbsStateChangedCb state_changed_cb; - LinphoneCallCbsStatsUpdatedCb stats_updated_cb; - LinphoneCallCbsTransferStateChangedCb transfer_state_changed_cb; - LinphoneCallCbsAckProcessingCb ack_processing; -}; - -LinphoneCallCbs * _linphone_call_cbs_new(void); +LinphoneCallCbs *_linphone_call_cbs_new(void); void linphone_call_notify_state_changed(LinphoneCall *call, LinphoneCallState cstate, const char *message); @@ -416,8 +404,21 @@ LINPHONE_PUBLIC void linphone_core_enable_short_turn_refresh(LinphoneCore *lc, b void linphone_call_update_ice_state_in_call_stats(LinphoneCall *call); LINPHONE_PUBLIC void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEvent *ev); void linphone_call_stats_update(LinphoneCallStats *stats, MediaStream *stream); -void linphone_call_stats_uninit(LinphoneCallStats *stats); +LinphoneCallStats *_linphone_call_stats_new(void); +void _linphone_call_stats_uninit(LinphoneCallStats *stats); void _linphone_call_stats_clone(LinphoneCallStats *dst, const LinphoneCallStats *src); +void _linphone_call_stats_set_ice_state (LinphoneCallStats *stats, LinphoneIceState state); +void _linphone_call_stats_set_type (LinphoneCallStats *stats, LinphoneStreamType type); +void _linphone_call_stats_set_received_rtcp (LinphoneCallStats *stats, mblk_t *m); +void _linphone_call_stats_set_sent_rtcp (LinphoneCallStats *stats, mblk_t *m); +int _linphone_call_stats_get_updated (const LinphoneCallStats *stats); +void _linphone_call_stats_set_updated (LinphoneCallStats *stats, int updated); +void _linphone_call_stats_set_rtp_stats (LinphoneCallStats *stats, const rtp_stats_t *rtpStats); +void _linphone_call_stats_set_download_bandwidth (LinphoneCallStats *stats, float bandwidth); +void _linphone_call_stats_set_upload_bandwidth (LinphoneCallStats *stats, float bandwidth); +void _linphone_call_stats_set_rtcp_download_bandwidth (LinphoneCallStats *stats, float bandwidth); +void _linphone_call_stats_set_rtcp_upload_bandwidth (LinphoneCallStats *stats, float bandwidth); +void _linphone_call_stats_set_ip_family_of_remote (LinphoneCallStats *stats, LinphoneAddressFamily family); void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall *call); void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md, bool_t is_offer); void linphone_call_clear_unused_ice_candidates(LinphoneCall *call, const SalMediaDescription *md); @@ -1520,7 +1521,6 @@ void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const SalOp *op); void payload_type_set_enable(OrtpPayloadType *pt, bool_t value); bool_t payload_type_enabled(const OrtpPayloadType *pt); -bool_t is_payload_type_number_available(const MSList *l, int number, const OrtpPayloadType *ignore); LinphonePayloadType *linphone_payload_type_new(LinphoneCore *lc, OrtpPayloadType *ortp_pt); bool_t _linphone_core_check_payload_type_usability(const LinphoneCore *lc, const OrtpPayloadType *pt); OrtpPayloadType *linphone_payload_type_get_ortp_pt(const LinphonePayloadType *pt); @@ -1592,40 +1592,6 @@ BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneVideoActivationPolicy); LINPHONE_PUBLIC LinphoneVideoActivationPolicy *linphone_video_activation_policy_new(void); -/** - * The LinphoneCallStats objects carries various statistic informations regarding quality of audio or video streams. - * - * To receive these informations periodically and as soon as they are computed, the application is invited to place a #LinphoneCoreCallStatsUpdatedCb callback in the LinphoneCoreVTable structure - * it passes for instantiating the LinphoneCore object (see linphone_core_new() ). - * - * At any time, the application can access last computed statistics using linphone_call_get_audio_stats() or linphone_call_get_video_stats(). -**/ -struct _LinphoneCallStats { - belle_sip_object_t base; - void *user_data; - LinphoneStreamType type; /**< Type of the stream which the stats refer to */ - jitter_stats_t jitter_stats; /**. + */ + +#ifndef _C_CALL_CBS_H_ +#define _C_CALL_CBS_H_ + +#include "linphone/api/c-callbacks.h" +#include "linphone/api/c-types.h" + +// ============================================================================= + +#ifdef __cplusplus + extern "C" { +#endif // ifdef __cplusplus + +/** + * @addtogroup call_control + * @{ + */ + +/** + * Acquire a reference to the LinphoneCallCbs object. + * @param[in] cbs LinphoneCallCbs object. + * @return The same LinphoneCallCbs object. + */ +LINPHONE_PUBLIC LinphoneCallCbs *linphone_call_cbs_ref (LinphoneCallCbs *cbs); + +/** + * Release reference to the LinphoneCallCbs object. + * @param[in] cbs LinphoneCallCbs object. + */ +LINPHONE_PUBLIC void linphone_call_cbs_unref (LinphoneCallCbs *cbs); + +/** + * Retrieve the user pointer associated with the LinphoneCallCbs object. + * @param[in] cbs LinphoneCallCbs object. + * @return The user pointer associated with the LinphoneCallCbs object. + */ +LINPHONE_PUBLIC void *linphone_call_cbs_get_user_data (const LinphoneCallCbs *cbs); + +/** + * Assign a user pointer to the LinphoneCallCbs object. + * @param[in] cbs LinphoneCallCbs object. + * @param[in] ud The user pointer to associate with the LinphoneCallCbs object. + */ +LINPHONE_PUBLIC void linphone_call_cbs_set_user_data (LinphoneCallCbs *cbs, void *ud); + +/** + * Get the dtmf received callback. + * @param[in] cbs LinphoneCallCbs object. + * @return The current dtmf received callback. + */ +LINPHONE_PUBLIC LinphoneCallCbsDtmfReceivedCb linphone_call_cbs_get_dtmf_received (LinphoneCallCbs *cbs); + +/** + * Set the dtmf received callback. + * @param[in] cbs LinphoneCallCbs object. + * @param[in] cb The dtmf received callback to be used. + */ +LINPHONE_PUBLIC void linphone_call_cbs_set_dtmf_received (LinphoneCallCbs *cbs, LinphoneCallCbsDtmfReceivedCb cb); + +/** + * Get the encryption changed callback. + * @param[in] cbs LinphoneCallCbs object. + * @return The current encryption changed callback. + */ +LINPHONE_PUBLIC LinphoneCallCbsEncryptionChangedCb linphone_call_cbs_get_encryption_changed (LinphoneCallCbs *cbs); + +/** + * Set the encryption changed callback. + * @param[in] cbs LinphoneCallCbs object. + * @param[in] cb The encryption changed callback to be used. + */ +LINPHONE_PUBLIC void linphone_call_cbs_set_encryption_changed (LinphoneCallCbs *cbs, LinphoneCallCbsEncryptionChangedCb cb); + +/** + * Get the info message received callback. + * @param[in] cbs LinphoneCallCbs object. + * @return The current info message received callback. + */ +LINPHONE_PUBLIC LinphoneCallCbsInfoMessageReceivedCb linphone_call_cbs_get_info_message_received (LinphoneCallCbs *cbs); + +/** + * Set the info message received callback. + * @param[in] cbs LinphoneCallCbs object. + * @param[in] cb The info message received callback to be used. + */ +LINPHONE_PUBLIC void linphone_call_cbs_set_info_message_received (LinphoneCallCbs *cbs, LinphoneCallCbsInfoMessageReceivedCb cb); + +/** + * Get the state changed callback. + * @param[in] cbs LinphoneCallCbs object. + * @return The current state changed callback. + */ +LINPHONE_PUBLIC LinphoneCallCbsStateChangedCb linphone_call_cbs_get_state_changed (LinphoneCallCbs *cbs); + +/** + * Set the state changed callback. + * @param[in] cbs LinphoneCallCbs object. + * @param[in] cb The state changed callback to be used. + */ +LINPHONE_PUBLIC void linphone_call_cbs_set_state_changed (LinphoneCallCbs *cbs, LinphoneCallCbsStateChangedCb cb); + +/** + * Get the stats updated callback. + * @param[in] cbs LinphoneCallCbs object. + * @return The current stats updated callback. + */ +LINPHONE_PUBLIC LinphoneCallCbsStatsUpdatedCb linphone_call_cbs_get_stats_updated (LinphoneCallCbs *cbs); + +/** + * Set the stats updated callback. + * @param[in] cbs LinphoneCallCbs object. + * @param[in] cb The stats updated callback to be used. + */ +LINPHONE_PUBLIC void linphone_call_cbs_set_stats_updated (LinphoneCallCbs *cbs, LinphoneCallCbsStatsUpdatedCb cb); + +/** + * Get the transfer state changed callback. + * @param[in] cbs LinphoneCallCbs object. + * @return The current transfer state changed callback. + */ +LINPHONE_PUBLIC LinphoneCallCbsTransferStateChangedCb linphone_call_cbs_get_transfer_state_changed (LinphoneCallCbs *cbs); + +/** + * Set the transfer state changed callback. + * @param[in] cbs LinphoneCallCbs object. + * @param[in] cb The transfer state changed callback to be used. + */ +LINPHONE_PUBLIC void linphone_call_cbs_set_transfer_state_changed (LinphoneCallCbs *cbs, LinphoneCallCbsTransferStateChangedCb cb); + +/** + * Get the ACK processing callback. + * @param[in] cbs LinphoneCallCbs object. + * @return The current ack processing callback. + */ +LINPHONE_PUBLIC LinphoneCallCbsAckProcessingCb linphone_call_cbs_get_ack_processing (LinphoneCallCbs *cbs); + +/** + * Set ACK processing callback. + * @param[in] cbs LinphoneCallCbs object. + * @param[in] cb The ack processing callback to be used. + */ +LINPHONE_PUBLIC void linphone_call_cbs_set_ack_processing (LinphoneCallCbs *cbs, LinphoneCallCbsAckProcessingCb cb); + +/** + * @} + */ + +#ifdef __cplusplus + } +#endif // ifdef __cplusplus + +#endif // ifndef _C_CALL_CBS_H_ diff --git a/include/linphone/api/c-call-stats.h b/include/linphone/api/c-call-stats.h new file mode 100644 index 000000000..0d631f652 --- /dev/null +++ b/include/linphone/api/c-call-stats.h @@ -0,0 +1,201 @@ +/* + * c-call-stats.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _C_CALL_STATS_H_ +#define _C_CALL_STATS_H_ + +#include + +#include "linphone/api/c-callbacks.h" +#include "linphone/api/c-types.h" + +// ============================================================================= + +#ifdef __cplusplus + extern "C" { +#endif // ifdef __cplusplus + +/** + * @addtogroup call_misc + * @{ + */ + +#define LINPHONE_CALL_STATS_AUDIO ((int)LinphoneStreamTypeAudio) +#define LINPHONE_CALL_STATS_VIDEO ((int)LinphoneStreamTypeVideo) +#define LINPHONE_CALL_STATS_TEXT ((int)LinphoneStreamTypeText) + +#define LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE (1 << 0) /**< received_rtcp field of LinphoneCallStats object has been updated */ +#define LINPHONE_CALL_STATS_SENT_RTCP_UPDATE (1 << 1) /**< sent_rtcp field of LinphoneCallStats object has been updated */ +#define LINPHONE_CALL_STATS_PERIODICAL_UPDATE (1 << 2) /**< Every seconds LinphoneCallStats object has been updated */ + +/** + * Increment refcount. + * @param[in] stats LinphoneCallStats object + * @ingroup misc +**/ +LINPHONE_PUBLIC LinphoneCallStats *linphone_call_stats_ref (LinphoneCallStats *stats); + +/** + * Decrement refcount and possibly free the object. + * @param[in] stats LinphoneCallStats object + * @ingroup misc +**/ +LINPHONE_PUBLIC void linphone_call_stats_unref (LinphoneCallStats *stats); + +/** + * Gets the user data in the LinphoneCallStats object + * @param[in] stats the LinphoneCallStats + * @return the user data + * @ingroup misc +*/ +LINPHONE_PUBLIC void *linphone_call_stats_get_user_data (const LinphoneCallStats *stats); + +/** + * Sets the user data in the LinphoneCallStats object + * @param[in] stats the LinphoneCallStats object + * @param[in] data the user data + * @ingroup misc +*/ +LINPHONE_PUBLIC void linphone_call_stats_set_user_data (LinphoneCallStats *stats, void *data); + +/** + * Get the type of the stream the stats refer to. + * @param[in] stats LinphoneCallStats object + * @return The type of the stream the stats refer to + */ +LINPHONE_PUBLIC LinphoneStreamType linphone_call_stats_get_type (const LinphoneCallStats *stats); + +/** + * Get the local loss rate since last report + * @return The sender loss rate +**/ +LINPHONE_PUBLIC float linphone_call_stats_get_sender_loss_rate (const LinphoneCallStats *stats); + +/** + * Gets the remote reported loss rate since last report + * @return The receiver loss rate +**/ +LINPHONE_PUBLIC float linphone_call_stats_get_receiver_loss_rate (const LinphoneCallStats *stats); + +/** + * Get the local loss rate since last report + * @return The local loss rate +**/ +LINPHONE_PUBLIC float linphone_call_stats_get_local_loss_rate (const LinphoneCallStats *stats); + +/** + * Gets the local late rate since last report + * @return The local late rate +**/ +LINPHONE_PUBLIC float linphone_call_stats_get_local_late_rate (const LinphoneCallStats *stats); + +/** + * Gets the local interarrival jitter + * @param[in] stats LinphoneCallStats object + * @return The interarrival jitter at last emitted sender report +**/ +LINPHONE_PUBLIC float linphone_call_stats_get_sender_interarrival_jitter (const LinphoneCallStats *stats); + +/** + * Gets the remote reported interarrival jitter + * @param[in] stats LinphoneCallStats object + * @return The interarrival jitter at last received receiver report +**/ +LINPHONE_PUBLIC float linphone_call_stats_get_receiver_interarrival_jitter (const LinphoneCallStats *stats); + +LINPHONE_PUBLIC const rtp_stats_t *linphone_call_stats_get_rtp_stats (const LinphoneCallStats *stats); + +/** + * Gets the cumulative number of late packets + * @param[in] stats LinphoneCallStats object + * @return The cumulative number of late packets +**/ +LINPHONE_PUBLIC uint64_t linphone_call_stats_get_late_packets_cumulative_number (const LinphoneCallStats *stats); + +/** + * Get the bandwidth measurement of the received stream, expressed in kbit/s, including IP/UDP/RTP headers. + * @param[in] stats LinphoneCallStats object + * @return The bandwidth measurement of the received stream in kbit/s. + */ +LINPHONE_PUBLIC float linphone_call_stats_get_download_bandwidth (const LinphoneCallStats *stats); + +/** + * Get the bandwidth measurement of the sent stream, expressed in kbit/s, including IP/UDP/RTP headers. + * @param[in] stats LinphoneCallStats object + * @return The bandwidth measurement of the sent stream in kbit/s. + */ +LINPHONE_PUBLIC float linphone_call_stats_get_upload_bandwidth (const LinphoneCallStats *stats); + +/** + * Get the bandwidth measurement of the received RTCP, expressed in kbit/s, including IP/UDP/RTP headers. + * @param[in] stats LinphoneCallStats object + * @return The bandwidth measurement of the received RTCP in kbit/s. + */ +LINPHONE_PUBLIC float linphone_call_stats_get_rtcp_download_bandwidth (const LinphoneCallStats *stats); + +/** + * Get the bandwidth measurement of the sent RTCP, expressed in kbit/s, including IP/UDP/RTP headers. + * @param[in] stats LinphoneCallStats object + * @return The bandwidth measurement of the sent RTCP in kbit/s. + */ +LINPHONE_PUBLIC float linphone_call_stats_get_rtcp_upload_bandwidth( const LinphoneCallStats *stats); + +/** + * Get the state of ICE processing. + * @param[in] stats LinphoneCallStats object + * @return The state of ICE processing. + */ +LINPHONE_PUBLIC LinphoneIceState linphone_call_stats_get_ice_state (const LinphoneCallStats *stats); + +/** + * Get the state of uPnP processing. + * @param[in] stats LinphoneCallStats object + * @return The state of uPnP processing. + */ +LINPHONE_PUBLIC LinphoneUpnpState linphone_call_stats_get_upnp_state (const LinphoneCallStats *stats); + +/** + * Get the IP address family of the remote peer. + * @param[in] stats LinphoneCallStats object + * @return The IP address family of the remote peer. + */ +LINPHONE_PUBLIC LinphoneAddressFamily linphone_call_stats_get_ip_family_of_remote (const LinphoneCallStats *stats); + +/** + * Get the jitter buffer size in ms. + * @param[in] stats LinphoneCallStats object + * @return The jitter buffer size in ms. + */ +LINPHONE_PUBLIC float linphone_call_stats_get_jitter_buffer_size_ms (const LinphoneCallStats *stats); + +/** + * Get the round trip delay in s. + * @param[in] stats LinphoneCallStats object + * @return The round trip delay in s. + */ +LINPHONE_PUBLIC float linphone_call_stats_get_round_trip_delay (const LinphoneCallStats *stats); + +/** + * @} + */ + +#ifdef __cplusplus + } +#endif // ifdef __cplusplus + +#endif // ifndef _C_CALL_STATS_H_ diff --git a/include/linphone/api/c-call.h b/include/linphone/api/c-call.h new file mode 100644 index 000000000..4087a6480 --- /dev/null +++ b/include/linphone/api/c-call.h @@ -0,0 +1,794 @@ +/* + * c-call.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _C_CALL_H_ +#define _C_CALL_H_ + +#include + +#include "linphone/api/c-types.h" + +// ============================================================================= + +#ifdef __cplusplus + extern "C" { +#endif // ifdef __cplusplus + +/** + * @addtogroup call_control + * @{ + */ + +/** + * Acquire a reference to the call. + * An application that wishes to retain a pointer to call object + * must use this function to unsure the pointer remains + * valid. Once the application no more needs this pointer, + * it must call linphone_call_unref(). + * @param[in] call The call. + * @return The same call. +**/ +LINPHONE_PUBLIC LinphoneCall *linphone_call_ref (LinphoneCall *call); + +/** + * Release reference to the call. + * @param[in] call The call. +**/ +LINPHONE_PUBLIC void linphone_call_unref (LinphoneCall *call); + +/** + * Retrieve the user pointer associated with the call. + * @param[in] call The call. + * @return The user pointer associated with the call. +**/ +LINPHONE_PUBLIC void *linphone_call_get_user_data (const LinphoneCall *call); + +/** + * Assign a user pointer to the call. + * @param[in] call The call. + * @param[in] ud The user pointer to associate with the call. +**/ +LINPHONE_PUBLIC void linphone_call_set_user_data (LinphoneCall *call, void *ud); + +/** + * Get the core that has created the specified call. + * @param[in] call LinphoneCall object + * @return The LinphoneCore object that has created the specified call. + */ +LINPHONE_PUBLIC LinphoneCore * linphone_call_get_core (const LinphoneCall *call); + +/** + * Retrieves the call's current state. +**/ +LINPHONE_PUBLIC LinphoneCallState linphone_call_get_state (const LinphoneCall *call); + +/** + * Tell whether a call has been asked to autoanswer + * @param[in] call LinphoneCall object + * @return A boolean value telling whether the call has been asked to autoanswer +**/ +LINPHONE_PUBLIC bool_t linphone_call_asked_to_autoanswer (LinphoneCall *call); + +/** + * Returns the remote address associated to this call +**/ +LINPHONE_PUBLIC const LinphoneAddress *linphone_call_get_remote_address (const LinphoneCall *call); + +/** + * Returns the to address with its headers associated to this call +**/ +LINPHONE_PUBLIC const LinphoneAddress *linphone_call_get_to_address (const LinphoneCall * call); + +/** + * Returns the value of the header name +**/ +LINPHONE_PUBLIC const char *linphone_call_get_to_header (const LinphoneCall *call, const char *name); + +/** + * Returns the remote address associated to this call as a string. + * The result string must be freed by user using ms_free(). +**/ +LINPHONE_PUBLIC char *linphone_call_get_remote_address_as_string (const LinphoneCall *call); + +/** + * Returns the diversion address associated to this call +**/ +LINPHONE_PUBLIC const LinphoneAddress * linphone_call_get_diversion_address (const LinphoneCall *call); + +/** + * Returns direction of the call (incoming or outgoing). +**/ +LINPHONE_PUBLIC LinphoneCallDir linphone_call_get_dir (const LinphoneCall *call); + +/** + * Gets the call log associated to this call. + * @param[in] call LinphoneCall object + * @return The LinphoneCallLog associated with the specified LinphoneCall +**/ +LINPHONE_PUBLIC LinphoneCallLog *linphone_call_get_call_log (const LinphoneCall *call); + +/** + * Gets the refer-to uri (if the call was transfered). + * @param[in] call LinphoneCall object + * @return The refer-to uri of the call (if it was transfered) +**/ +LINPHONE_PUBLIC const char *linphone_call_get_refer_to (const LinphoneCall *call); + +/** + * Returns true if this calls has received a transfer that has not been + * executed yet. + * Pending transfers are executed when this call is being paused or closed, + * locally or by remote endpoint. + * If the call is already paused while receiving the transfer request, the + * transfer immediately occurs. +**/ +LINPHONE_PUBLIC bool_t linphone_call_has_transfer_pending (const LinphoneCall *call); + +/** + * Gets the transferer if this call was started automatically as a result of an incoming transfer request. + * The call in which the transfer request was received is returned in this case. + * @param[in] call LinphoneCall object + * @return The transferer call if the specified call was started automatically as a result of an incoming transfer request, NULL otherwise +**/ +LINPHONE_PUBLIC LinphoneCall *linphone_call_get_transferer_call (const LinphoneCall *call); + +/** + * When this call has received a transfer request, returns the new call that was automatically created as a result of the transfer. +**/ +LINPHONE_PUBLIC LinphoneCall *linphone_call_get_transfer_target_call (const LinphoneCall *call); + +/** + * Returns the call object this call is replacing, if any. + * Call replacement can occur during call transfers. + * By default, the core automatically terminates the replaced call and accept the new one. + * This function allows the application to know whether a new incoming call is a one that replaces another one. +**/ +LINPHONE_PUBLIC LinphoneCall *linphone_call_get_replaced_call (LinphoneCall *call); + +/** + * Returns call's duration in seconds. +**/ +LINPHONE_PUBLIC int linphone_call_get_duration (const LinphoneCall *call); + +/** + * Returns current parameters associated to the call. +**/ +LINPHONE_PUBLIC const LinphoneCallParams *linphone_call_get_current_params (LinphoneCall *call); + +/** + * Returns call parameters proposed by remote. + * + * This is useful when receiving an incoming call, to know whether the remote party + * supports video, encryption or whatever. +**/ +LINPHONE_PUBLIC const LinphoneCallParams *linphone_call_get_remote_params (LinphoneCall *call); + +/** + * Indicate whether camera input should be sent to remote end. +**/ +LINPHONE_PUBLIC void linphone_call_enable_camera (LinphoneCall *lc, bool_t enabled); + +/** + * Returns TRUE if camera pictures are allowed to be sent to the remote party. +**/ +LINPHONE_PUBLIC bool_t linphone_call_camera_enabled (const LinphoneCall *lc); + +/** + * Take a photo of currently received video and write it into a jpeg file. + * Note that the snapshot is asynchronous, an application shall not assume that the file is created when the function returns. + * @param call a LinphoneCall + * @param file a path where to write the jpeg content. + * @return 0 if successfull, -1 otherwise (typically if jpeg format is not supported). +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_call_take_video_snapshot (LinphoneCall *call, const char *file); + +/** + * Take a photo of currently captured video and write it into a jpeg file. + * Note that the snapshot is asynchronous, an application shall not assume that the file is created when the function returns. + * @param call a LinphoneCall + * @param file a path where to write the jpeg content. + * @return 0 if successfull, -1 otherwise (typically if jpeg format is not supported). +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_call_take_preview_snapshot (LinphoneCall *call, const char *file); + +/** + * Returns the reason for a call termination (either error or normal termination) +**/ +LINPHONE_PUBLIC LinphoneReason linphone_call_get_reason (const LinphoneCall *call); + +/** + * Returns full details about call errors or termination reasons. + * @param call LinphoneCall object on which we want the information error + * @return LinphoneErrorInfo object holding the reason error. + */ +LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_call_get_error_info (const LinphoneCall *call); + +/** + * Returns the far end's user agent description string, if available. +**/ +LINPHONE_PUBLIC const char *linphone_call_get_remote_user_agent (LinphoneCall *call); + +/** + * Returns the far end's sip contact as a string, if available. +**/ +LINPHONE_PUBLIC const char *linphone_call_get_remote_contact (LinphoneCall *call); + +/** + * Returns the ZRTP authentication token to verify. + * @param call the LinphoneCall + * @return the authentication token to verify. +**/ +LINPHONE_PUBLIC const char *linphone_call_get_authentication_token (LinphoneCall *call); + +/** + * Returns whether ZRTP authentication token is verified. + * If not, it must be verified by users as described in ZRTP procedure. + * Once done, the application must inform of the results with linphone_call_set_authentication_token_verified(). + * @param call the LinphoneCall + * @return TRUE if authentication token is verifed, false otherwise. +**/ +LINPHONE_PUBLIC bool_t linphone_call_get_authentication_token_verified (const LinphoneCall *call); + +/** + * Set the result of ZRTP short code verification by user. + * If remote party also does the same, it will update the ZRTP cache so that user's verification will not be required for the two users. + * @param call the LinphoneCall + * @param verified whether the ZRTP SAS is verified. +**/ +LINPHONE_PUBLIC void linphone_call_set_authentication_token_verified (LinphoneCall *call, bool_t verified); + +/** + * Request remote side to send us a Video Fast Update. +**/ +LINPHONE_PUBLIC void linphone_call_send_vfu_request (LinphoneCall *call); + +LINPHONE_PUBLIC void linphone_call_set_next_video_frame_decoded_callback (LinphoneCall *call, LinphoneCallCbFunc cb, void *ud); + +/** + * Returns the current transfer state, if a transfer has been initiated from this call. + * @see linphone_core_transfer_call() , linphone_core_transfer_call_to_another() +**/ +LINPHONE_PUBLIC LinphoneCallState linphone_call_get_transfer_state (LinphoneCall *call); + +/** + * Perform a zoom of the video displayed during a call. + * @param call the call. + * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied. + * @param cx a floating point number pointing the horizontal center of the zoom to be applied. This value should be between 0.0 and 1.0. + * @param cy a floating point number pointing the vertical center of the zoom to be applied. This value should be between 0.0 and 1.0. + * + * cx and cy are updated in return in case their coordinates were too excentrated for the requested zoom factor. The zoom ensures that all the screen is fullfilled with the video. +**/ +LINPHONE_PUBLIC void linphone_call_zoom_video (LinphoneCall *call, float zoom_factor, float *cx, float *cy); + +/** + * Send the specified dtmf. + * + * The dtmf is automatically played to the user. + * @param call The LinphoneCall object + * @param dtmf The dtmf name specified as a char, such as '0', '#' etc... + * @return 0 if successful, -1 on error. +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_call_send_dtmf (LinphoneCall *call, char dtmf); + +/** + * Send a list of dtmf. + * + * The dtmfs are automatically sent to remote, separated by some needed customizable delay. + * Sending is canceled if the call state changes to something not LinphoneCallStreamsRunning. + * @param call The LinphoneCall object + * @param dtmfs A dtmf sequence such as '123#123123' + * @return -2 if there is already a DTMF sequence, -1 if call is not ready, 0 otherwise. +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_call_send_dtmfs (LinphoneCall *call, const char *dtmfs); + +/** + * Stop current DTMF sequence sending. + * + * Please note that some DTMF could be already sent, + * depending on when this function call is delayed from #linphone_call_send_dtmfs. This + * function will be automatically called if call state change to anything but LinphoneCallStreamsRunning. + * @param call The LinphoneCall object +**/ +LINPHONE_PUBLIC void linphone_call_cancel_dtmfs (LinphoneCall *call); + +/** + * Return TRUE if this call is currently part of a conference + * @param call #LinphoneCall + * @return TRUE if part of a conference. + * @deprecated Use linphone_call_get_conference() instead. + * @donotwrap + */ +LINPHONE_PUBLIC LINPHONE_DEPRECATED bool_t linphone_call_is_in_conference (const LinphoneCall *call); + +/** + * Return the associated conference object + * @param call #LinphoneCall + * @return A pointer on #LinphoneConference or NULL if the call is not part of any conference. + */ +LINPHONE_PUBLIC LinphoneConference *linphone_call_get_conference (const LinphoneCall *call); + +/** + * Change the playback output device (currently only used for blackberry) + * @param call + * @param route the wanted audio route (earpiece, speaker, ...) +**/ +LINPHONE_PUBLIC void linphone_call_set_audio_route (LinphoneCall *call, LinphoneAudioRoute route); + +/** + * Returns the number of stream for the given call. + * Currently there is only two (Audio, Video), but later there will be more. + * @param call + * @return 2 +**/ +LINPHONE_PUBLIC int linphone_call_get_stream_count (const LinphoneCall *call); + +/** + * Returns the type of stream for the given stream index. + * @param call + * @param stream_index + * @return the type (MSAudio, MSVideo, MSText) of the stream of given index. +**/ +LINPHONE_PUBLIC MSFormatType linphone_call_get_stream_type (const LinphoneCall *call, int stream_index); + +/** + * Returns the meta rtp transport for the given stream index. + * @param call + * @param stream_index + * @return a pointer to the meta rtp transport if it exists, NULL otherwise +**/ +LINPHONE_PUBLIC RtpTransport *linphone_call_get_meta_rtp_transport (const LinphoneCall *call, int stream_index); + +/** + * Returns the meta rtcp transport for the given stream index. + * @param call + * @param stream_index + * @return a pointer to the meta rtcp transport if it exists, NULL otherwise +**/ +LINPHONE_PUBLIC RtpTransport *linphone_call_get_meta_rtcp_transport (const LinphoneCall *call, int stream_index); + +/** + * Pauses the call. If a music file has been setup using linphone_core_set_play_file(), + * this file will be played to the remote user. + * The only way to resume a paused call is to call linphone_call_resume(). + * @param[in] call LinphoneCall object + * @return 0 on success, -1 on failure + * @see linphone_call_resume() +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_call_pause (LinphoneCall *call); + +/** + * Resumes a call. + * The call needs to have been paused previously with linphone_call_pause(). + * @param[in] call LinphoneCall object + * @return 0 on success, -1 on failure + * @see linphone_call_pause() +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_call_resume (LinphoneCall *call); + +/** + * Terminates a call. + * @param[in] call LinphoneCall object + * @return 0 on success, -1 on failure +**/LINPHONE_PUBLIC LinphoneStatus linphone_call_terminate (LinphoneCall *call); + +/** + * Terminates a call. + * @param[in] call LinphoneCall object + * @param[in] ei LinphoneErrorInfo + * @return 0 on success, -1 on failure +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_call_terminate_with_error_info (LinphoneCall *call, const LinphoneErrorInfo *ei); + +/** + * Redirect the specified call to the given redirect URI. + * @param[in] call A LinphoneCall object + * @param[in] redirect_uri The URI to redirect the call to + * @return 0 if successful, -1 on error. + */ +LINPHONE_PUBLIC LinphoneStatus linphone_call_redirect (LinphoneCall *call, const char *redirect_uri); + +/** + * Decline a pending incoming call, with a reason. + * @param[in] call A LinphoneCall object that must be in the IncomingReceived state + * @param[in] reason The reason for rejecting the call: LinphoneReasonDeclined or LinphoneReasonBusy + * @return 0 on success, -1 on failure +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_call_decline (LinphoneCall *call, LinphoneReason reason); + +/** + * Decline a pending incoming call, with a LinphoneErrorInfo object. + * @param[in] call A LinphoneCall object that must be in the IncomingReceived state + * @param[in] ei LinphoneErrorInfo containing more information on the call rejection. + * @return 0 on success, -1 on failure + */ +LINPHONE_PUBLIC int linphone_call_decline_with_error_info (LinphoneCall *call, const LinphoneErrorInfo *ei); + +/** + * Accept an incoming call. + * + * Basically the application is notified of incoming calls within the + * call_state_changed callback of the #LinphoneCoreVTable structure, where it will receive + * a LinphoneCallIncoming event with the associated LinphoneCall object. + * The application can later accept the call using this method. + * @param[in] call A LinphoneCall object + * @return 0 on success, -1 on failure +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_call_accept (LinphoneCall *call); + +/** + * Accept an incoming call, with parameters. + * + * Basically the application is notified of incoming calls within the + * call_state_changed callback of the #LinphoneCoreVTable structure, where it will receive + * a LinphoneCallIncoming event with the associated LinphoneCall object. + * The application can later accept the call using this method. + * @param[in] call A LinphoneCall object + * @param[in] params The specific parameters for this call, for example whether video is accepted or not. Use NULL to use default parameters + * @return 0 on success, -1 on failure +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_call_accept_with_params (LinphoneCall *call, const LinphoneCallParams *params); + +/** + * Accept an early media session for an incoming call. + * This is identical as calling linphone_call_accept_early_media_with_params() with NULL parameters. + * @param[in] call A LinphoneCall object + * @return 0 if successful, -1 otherwise + * @see linphone_call_accept_early_media_with_params() +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_call_accept_early_media (LinphoneCall *call); + +/** + * When receiving an incoming, accept to start a media session as early-media. + * This means the call is not accepted but audio & video streams can be established if the remote party supports early media. + * However, unlike after call acceptance, mic and camera input are not sent during early-media, though received audio & video are played normally. + * The call can then later be fully accepted using linphone_call_accept() or linphone_call_accept_with_params(). + * @param[in] call A LinphoneCall object + * @param[in] params The call parameters to use (can be NULL) + * @return 0 if successful, -1 otherwise +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_call_accept_early_media_with_params (LinphoneCall *call, const LinphoneCallParams *params); + +/** + * Updates a running call according to supplied call parameters or parameters changed in the LinphoneCore. + * In this version this is limited to the following use cases: + * - setting up/down the video stream according to the video parameter of the LinphoneCallParams (see linphone_call_params_enable_video() ). + * - changing the size of the transmitted video after calling linphone_core_set_preferred_video_size() + * In case no changes are requested through the LinphoneCallParams argument, then this argument can be omitted and set to NULL. + * WARNING: Updating a call in the LinphoneCallPaused state will still result in a paused call even if the media directions set in the + * params are sendrecv. To resume a paused call, you need to call linphone_call_resume(). + * + * @param[in] call A LinphoneCall object + * @param[in] params The new call parameters to use (may be NULL) + * @return 0 if successful, -1 otherwise. +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_call_update (LinphoneCall *call, const LinphoneCallParams *params); + +/** + * When receiving a #LinphoneCallUpdatedByRemote state notification, prevent LinphoneCore from performing an automatic answer. + * + * When receiving a #LinphoneCallUpdatedByRemote state notification (ie an incoming reINVITE), the default behaviour of + * LinphoneCore is defined by the "defer_update_default" option of the "sip" section of the config. If this option is 0 (the default) + * then the LinphoneCore automatically answers the reINIVTE with call parameters unchanged. + * However when for example when the remote party updated the call to propose a video stream, it can be useful + * to prompt the user before answering. This can be achieved by calling linphone_core_defer_call_update() during + * the call state notification, to deactivate the automatic answer that would just confirm the audio but reject the video. + * Then, when the user responds to dialog prompt, it becomes possible to call linphone_call_accept_update() to answer + * the reINVITE, with eventually video enabled in the LinphoneCallParams argument. + * + * The #LinphoneCallUpdatedByRemote notification can also arrive when receiving an INVITE without SDP. In such case, an unchanged offer is made + * in the 200Ok, and when the ACK containing the SDP answer is received, #LinphoneCallUpdatedByRemote is triggered to notify the application of possible + * changes in the media session. However in such case defering the update has no meaning since we just generating an offer. + * + * @param[in] call A LinphoneCall object + * @return 0 if successful, -1 if the linphone_call_defer_update() was done outside a valid #LinphoneCallUpdatedByRemote notification +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_call_defer_update (LinphoneCall *call); + +/** + * Accept call modifications initiated by other end. + * + * This call may be performed in response to a #LinphoneCallUpdatedByRemote state notification. + * When such notification arrives, the application can decide to call linphone_call_defer_update() so that it can + * have the time to prompt the user. linphone_call_get_remote_params() can be used to get information about the call parameters + * requested by the other party, such as whether a video stream is requested. + * + * When the user accepts or refuse the change, linphone_call_accept_update() can be done to answer to the other party. + * If params is NULL, then the same call parameters established before the update request will continue to be used (no change). + * If params is not NULL, then the update will be accepted according to the parameters passed. + * Typical example is when a user accepts to start video, then params should indicate that video stream should be used + * (see linphone_call_params_enable_video()). + * @param[in] call A LinphoneCall object + * @param[in] params A LinphoneCallParams object describing the call parameters to accept + * @return 0 if successful, -1 otherwise (actually when this function call is performed outside ot #LinphoneCallUpdatedByRemote state) +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_call_accept_update (LinphoneCall *call, const LinphoneCallParams *params); + +/** + * Performs a simple call transfer to the specified destination. + * The remote endpoint is expected to issue a new call to the specified destination. + * The current call remains active and thus can be later paused or terminated. + * It is possible to follow the progress of the transfer provided that transferee sends notification about it. + * In this case, the transfer_state_changed callback of the #LinphoneCoreVTable is invoked to notify of the state of the new call at the other party. + * The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallConnected. + * @param[in] call The call to be transfered + * @param[in] refer_to The destination the call is to be refered to + * @return 0 on success, -1 on failure +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_call_transfer (LinphoneCall *call, const char *refer_to); + +/** + * Transfers a call to destination of another running call. This is used for "attended transfer" scenarios. + * The transfered call is supposed to be in paused state, so that it is able to accept the transfer immediately. + * The destination call is a call previously established to introduce the transfered person. + * This method will send a transfer request to the transfered person. The phone of the transfered is then + * expected to automatically call to the destination of the transfer. The receiver of the transfer will then automatically + * close the call with us (the 'dest' call). + * It is possible to follow the progress of the transfer provided that transferee sends notification about it. + * In this case, the transfer_state_changed callback of the #LinphoneCoreVTable is invoked to notify of the state of the new call at the other party. + * The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallConnected. + * @param[in] call A running call you want to transfer + * @param[in] dest A running call whose remote person will receive the transfer + * @return 0 on success, -1 on failure +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_call_transfer_to_another (LinphoneCall *call, LinphoneCall *dest); + +/** + * @} + */ + +/** + * @addtogroup media_parameters + * @{ + */ + +/** + * Get the native window handle of the video window, casted as an unsigned long. +**/ +LINPHONE_PUBLIC void * linphone_call_get_native_video_window_id(const LinphoneCall *call); + +/** + * Set the native video window id where the video is to be displayed. + * For MacOS, Linux, Windows: if not set or 0 a window will be automatically created, unless the special id -1 is given. +**/ +LINPHONE_PUBLIC void linphone_call_set_native_video_window_id(LinphoneCall *call, void * id); + +/** + * Enables or disable echo cancellation for this call + * @param call + * @param val +**/ +LINPHONE_PUBLIC void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t val) ; + +/** + * Returns TRUE if echo cancellation is enabled. +**/ +LINPHONE_PUBLIC bool_t linphone_call_echo_cancellation_enabled(const LinphoneCall *call); + +/** + * Enables or disable echo limiter for this call + * @param call + * @param val +**/ +LINPHONE_PUBLIC void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val); + +/** + * Returns TRUE if echo limiter is enabled. +**/ +LINPHONE_PUBLIC bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call); + +/** + * @} + */ + +/** + * @addtogroup call_misc + * @{ + */ + +/** + * Create a new chat room for messaging from a call if not already existing, else return existing one. + * No reference is given to the caller: the chat room will be deleted when the call is ended. + * @param call #LinphoneCall object + * @return #LinphoneChatRoom where messaging can take place. + */ +LINPHONE_PUBLIC LinphoneChatRoom * linphone_call_get_chat_room(LinphoneCall *call); + +/** + * Get the mesured playback volume level (received from remote) in dbm0. + * @param call The call. + * @return float Volume level in percentage. + */ +LINPHONE_PUBLIC float linphone_call_get_play_volume(const LinphoneCall *call); + +/** + * Get the mesured record volume level (sent to remote) in dbm0. + * @param call The call. + * @return float Volume level in percentage. + */ +LINPHONE_PUBLIC float linphone_call_get_record_volume(const LinphoneCall *call); + +/** + * Get speaker volume gain. + * If the sound backend supports it, the returned gain is equal to the gain set + * with the system mixer. + * @param call The call. + * @return Percenatge of the max supported volume gain. Valid values are in [ 0.0 : 1.0 ]. + * In case of failure, a negative value is returned + */ +LINPHONE_PUBLIC float linphone_call_get_speaker_volume_gain(const LinphoneCall *call); + +/** + * Set speaker volume gain. + * If the sound backend supports it, the new gain will synchronized with the system mixer. + * @param call The call. + * @param volume Percentage of the max supported gain. Valid values are in [ 0.0 : 1.0 ]. + */ +LINPHONE_PUBLIC void linphone_call_set_speaker_volume_gain(LinphoneCall *call, float volume); + +/** + * Get microphone volume gain. + * If the sound backend supports it, the returned gain is equal to the gain set + * with the system mixer. + * @param call The call. + * @return double Percenatge of the max supported volume gain. Valid values are in [ 0.0 : 1.0 ]. + * In case of failure, a negative value is returned + */ +LINPHONE_PUBLIC float linphone_call_get_microphone_volume_gain(const LinphoneCall *call); + +/** + * Set microphone volume gain. + * If the sound backend supports it, the new gain will synchronized with the system mixer. + * @param call The call. + * @param volume Percentage of the max supported gain. Valid values are in [ 0.0 : 1.0 ]. + */ +LINPHONE_PUBLIC void linphone_call_set_microphone_volume_gain(LinphoneCall *call, float volume); + +/** + * Obtain real-time quality rating of the call + * + * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated + * during all the duration of the call. This function returns its value at the time of the function call. + * It is expected that the rating is updated at least every 5 seconds or so. + * The rating is a floating point number comprised between 0 and 5. + * + * 4-5 = good quality
+ * 3-4 = average quality
+ * 2-3 = poor quality
+ * 1-2 = very poor quality
+ * 0-1 = can't be worse, mostly unusable
+ * + * @return The function returns -1 if no quality measurement is available, for example if no + * active audio stream exist. Otherwise it returns the quality rating. +**/ +LINPHONE_PUBLIC float linphone_call_get_current_quality(const LinphoneCall *call); + +/** + * Returns call quality averaged over all the duration of the call. + * + * See linphone_call_get_current_quality() for more details about quality measurement. +**/ +LINPHONE_PUBLIC float linphone_call_get_average_quality(const LinphoneCall *call); + +/** + * Start call recording. + * The output file where audio is recorded must be previously specified with linphone_call_params_set_record_file(). +**/ +LINPHONE_PUBLIC void linphone_call_start_recording(LinphoneCall *call); + +/** + * Stop call recording. +**/ +LINPHONE_PUBLIC void linphone_call_stop_recording(LinphoneCall *call); + +/** + * Get a player associated with the call to play a local file and stream it to the remote peer. + * @param[in] call LinphoneCall object + * @return A LinphonePlayer object + */ +LINPHONE_PUBLIC LinphonePlayer * linphone_call_get_player(LinphoneCall *call); + +/** + * Indicates whether an operation is in progress at the media side. + * It can be a bad idea to initiate signaling operations (adding video, pausing the call, removing video, changing video parameters) while + * the media is busy in establishing the connection (typically ICE connectivity checks). It can result in failures generating loss of time + * in future operations in the call. + * Applications are invited to check this function after each call state change to decide whether certain operations are permitted or not. + * @param call the call + * @return TRUE if media is busy in establishing the connection, FALSE otherwise. +**/ +LINPHONE_PUBLIC bool_t linphone_call_media_in_progress(const LinphoneCall *call); + +/** + * Call generic OpenGL render for a given call. + * @param call The call. + */ +LINPHONE_PUBLIC void linphone_call_ogl_render(const LinphoneCall *call); + +/** + * Send a LinphoneInfoMessage through an established call + * @param call the call + * @param info the info message +**/ +LINPHONE_PUBLIC LinphoneStatus linphone_call_send_info_message(LinphoneCall *call, const LinphoneInfoMessage *info); + +/** + * Return a copy of the call statistics for a particular stream type. + * @param call the call + * @param type the stream type +**/ +LINPHONE_PUBLIC LinphoneCallStats *linphone_call_get_stats(LinphoneCall *call, LinphoneStreamType type); + +LINPHONE_PUBLIC LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call); + +LINPHONE_PUBLIC LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call); + +LINPHONE_PUBLIC LinphoneCallStats *linphone_call_get_text_stats(LinphoneCall *call); + +/** + * Add a listener in order to be notified of LinphoneCall events. Once an event is received, registred LinphoneCallCbs are + * invoked sequencially. + * @param[in] call LinphoneCall object to monitor. + * @param[in] cbs A LinphoneCallCbs object holding the callbacks you need. A reference is taken by the LinphoneCall until you invoke linphone_call_remove_callbacks(). + */ +LINPHONE_PUBLIC void linphone_call_add_callbacks(LinphoneCall *call, LinphoneCallCbs *cbs); + +/** + * Remove a listener from a LinphoneCall + * @param[in] call LinphoneCall object + * @param[in] cbs LinphoneCallCbs object to remove. + */ +LINPHONE_PUBLIC void linphone_call_remove_callbacks(LinphoneCall *call, LinphoneCallCbs *cbs); + +/** + * Gets the current LinphoneCallCbs. + * This is meant only to be called from a callback to be able to get the user_data associated with the LinphoneCallCbs that is calling the callback. + * @param[in] call LinphoneCall object + * @return The LinphoneCallCbs that has called the last callback + */ +LINPHONE_PUBLIC LinphoneCallCbs *linphone_call_get_current_callbacks(const LinphoneCall *call); + +/** + * Set call parameters - advanced and not recommended feature - use with caution. + * Local call parameters applicable to an outgoing or incoming shall usually be passed to linphone_core_invite_address_with_params() or + * linphone_call_accept_with_params(). + * However, in some cases it might be desirable from a software design standpoint to modify local parameters outside of the application layer, typically + * in the purpose of implementing a custom logic including special headers in INVITE or 200Ok requests, driven by a call_state_changed listener method. + * This function accepts to assign a new LinphoneCallParams only in LinphoneCallOutgoingInit and LinphoneCallIncomingReceived states. + * @param call the LinphoneCall object +**/ +LINPHONE_PUBLIC void linphone_call_set_params(LinphoneCall *call, const LinphoneCallParams *params); + +/** + * Returns local parameters associated with the call. + * This is typically the parameters passed at call initiation to linphone_core_invite_address_with_params() or linphone_call_accept_with_params(), or some default + * parameters if no LinphoneCallParams was explicitely passed during call initiation. + * @param call the LinphoneCall object + * @return the call's local parameters. + **/ +LINPHONE_PUBLIC const LinphoneCallParams * linphone_call_get_params(LinphoneCall *call); + +/** + * @} + */ + +#ifdef __cplusplus + } +#endif // ifdef __cplusplus + +#endif // ifndef _C_CALL_H_ diff --git a/include/linphone/api/c-callbacks.h b/include/linphone/api/c-callbacks.h index d44de7925..347f03552 100644 --- a/include/linphone/api/c-callbacks.h +++ b/include/linphone/api/c-callbacks.h @@ -29,6 +29,68 @@ extern "C" { #endif // ifdef __cplusplus +/** + * @addtogroup call_control + * @{ +**/ + +/** + * Callback for being notified of received DTMFs. + * @param call LinphoneCall object that received the dtmf + * @param dtmf The ascii code of the dtmf + */ +typedef void (*LinphoneCallCbsDtmfReceivedCb)(LinphoneCall *call, int dtmf); + +/** + * Call encryption changed callback. + * @param call LinphoneCall object whose encryption is changed. + * @param on Whether encryption is activated. + * @param authentication_token An authentication_token, currently set for ZRTP kind of encryption only. + */ +typedef void (*LinphoneCallCbsEncryptionChangedCb)(LinphoneCall *call, bool_t on, const char *authentication_token); + +/** + * Callback for receiving info messages. + * @param call LinphoneCall whose info message belongs to. + * @param msg LinphoneInfoMessage object. + */ +typedef void (*LinphoneCallCbsInfoMessageReceivedCb)(LinphoneCall *call, const LinphoneInfoMessage *msg); + +/** + * Call state notification callback. + * @param call LinphoneCall whose state is changed. + * @param cstate The new state of the call + * @param message An informational message about the state. + */ +typedef void (*LinphoneCallCbsStateChangedCb)(LinphoneCall *call, LinphoneCallState cstate, const char *message); + +/** + * Callback for receiving quality statistics for calls. + * @param call LinphoneCall object whose statistics are notified + * @param stats LinphoneCallStats object + */ +typedef void (*LinphoneCallCbsStatsUpdatedCb)(LinphoneCall *call, const LinphoneCallStats *stats); + +/** + * Callback for notifying progresses of transfers. + * @param call LinphoneCall that was transfered + * @param cstate The state of the call to transfer target at the far end. + */ +typedef void (*LinphoneCallCbsTransferStateChangedCb)(LinphoneCall *call, LinphoneCallState cstate); + +/** + * Callback for notifying the processing SIP ACK messages. + * @param call LinphoneCall for which an ACK is being received or sent + * @param ack the ACK message + * @param is_received if TRUE this ACK is an incoming one, otherwise it is an ACK about to be sent. + */ +typedef void (*LinphoneCallCbsAckProcessingCb)(LinphoneCall *call, LinphoneHeaders *ack, bool_t is_received); + +/** + * @} +**/ + + /** * @addtogroup chatroom * @{ diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index be2d44f2b..7cf35f798 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -69,11 +69,24 @@ typedef unsigned char bool_t; */ typedef struct _LinphoneAddress LinphoneAddress; +/** + * The LinphoneCall object represents a call issued or received by the LinphoneCore + * @ingroup call_control +**/ typedef struct _LinphoneCall LinphoneCall; -// ----------------------------------------------------------------------------- -// Chatroom. -// ----------------------------------------------------------------------------- +/** Callback prototype */ +typedef void (*LinphoneCallCbFunc) (LinphoneCall *call, void *ud); + +/** + * That class holds all the callbacks which are called by LinphoneCall objects. + * + * Use linphone_factory_create_call_cbs() to create an instance. Then, call the + * callback setters on the events you need to monitor and pass the object to + * a LinphoneCall instance through linphone_call_add_callbacks(). + * @ingroup call_control + */ +typedef struct _LinphoneCallCbs LinphoneCallCbs; /** * A chat room is the place where text messages are exchanged. diff --git a/include/linphone/call.h b/include/linphone/call.h index 94ffd09c1..9446df88e 100644 --- a/include/linphone/call.h +++ b/include/linphone/call.h @@ -20,910 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef LINPHONE_CALL_H #define LINPHONE_CALL_H -#include -#include "linphone/types.h" - -/** - * @addtogroup call_control - * @{ - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Acquire a reference to the call. - * An application that wishes to retain a pointer to call object - * must use this function to unsure the pointer remains - * valid. Once the application no more needs this pointer, - * it must call linphone_call_unref(). - * @param[in] call The call. - * @return The same call. -**/ -LINPHONE_PUBLIC LinphoneCall * linphone_call_ref(LinphoneCall *call); - -/** - * Release reference to the call. - * @param[in] call The call. -**/ -LINPHONE_PUBLIC void linphone_call_unref(LinphoneCall *call); - -/** - * Retrieve the user pointer associated with the call. - * @param[in] call The call. - * @return The user pointer associated with the call. -**/ -LINPHONE_PUBLIC void * linphone_call_get_user_data(const LinphoneCall *call); - -/** - * Assign a user pointer to the call. - * @param[in] call The call. - * @param[in] ud The user pointer to associate with the call. -**/ -LINPHONE_PUBLIC void linphone_call_set_user_data(LinphoneCall *call, void *ud); - -/** - * Get the core that has created the specified call. - * @param[in] call LinphoneCall object - * @return The LinphoneCore object that has created the specified call. - */ -LINPHONE_PUBLIC LinphoneCore * linphone_call_get_core(const LinphoneCall *call); - -/** - * Retrieves the call's current state. -**/ -LINPHONE_PUBLIC LinphoneCallState linphone_call_get_state(const LinphoneCall *call); - -/** - * Tell whether a call has been asked to autoanswer - * @param[in] call LinphoneCall object - * @return A boolean value telling whether the call has been asked to autoanswer -**/ -LINPHONE_PUBLIC bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call); - -/** - * Returns the remote address associated to this call -**/ -LINPHONE_PUBLIC const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call); - -/** - * Returns the to address with its headers associated to this call -**/ -LINPHONE_PUBLIC const LinphoneAddress * linphone_call_get_to_address(const LinphoneCall * call); - -/** - * Returns the value of the header name -**/ -LINPHONE_PUBLIC const char * linphone_call_get_to_header(const LinphoneCall *call, const char *name); - -/** - * Returns the remote address associated to this call as a string. - * The result string must be freed by user using ms_free(). -**/ -LINPHONE_PUBLIC char * linphone_call_get_remote_address_as_string(const LinphoneCall *call); - -/** - * Returns the diversion address associated to this call -**/ -LINPHONE_PUBLIC const LinphoneAddress * linphone_call_get_diversion_address(const LinphoneCall *call); - -/** - * Returns direction of the call (incoming or outgoing). -**/ -LINPHONE_PUBLIC LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call); - -/** - * Gets the call log associated to this call. - * @param[in] call LinphoneCall object - * @return The LinphoneCallLog associated with the specified LinphoneCall -**/ -LINPHONE_PUBLIC LinphoneCallLog * linphone_call_get_call_log(const LinphoneCall *call); - -/** - * Gets the refer-to uri (if the call was transfered). - * @param[in] call LinphoneCall object - * @return The refer-to uri of the call (if it was transfered) -**/ -LINPHONE_PUBLIC const char * linphone_call_get_refer_to(const LinphoneCall *call); - -/** - * Returns true if this calls has received a transfer that has not been - * executed yet. - * Pending transfers are executed when this call is being paused or closed, - * locally or by remote endpoint. - * If the call is already paused while receiving the transfer request, the - * transfer immediately occurs. -**/ -LINPHONE_PUBLIC bool_t linphone_call_has_transfer_pending(const LinphoneCall *call); - -/** - * Gets the transferer if this call was started automatically as a result of an incoming transfer request. - * The call in which the transfer request was received is returned in this case. - * @param[in] call LinphoneCall object - * @return The transferer call if the specified call was started automatically as a result of an incoming transfer request, NULL otherwise -**/ -LINPHONE_PUBLIC LinphoneCall * linphone_call_get_transferer_call(const LinphoneCall *call); - -/** - * When this call has received a transfer request, returns the new call that was automatically created as a result of the transfer. -**/ -LINPHONE_PUBLIC LinphoneCall * linphone_call_get_transfer_target_call(const LinphoneCall *call); - -/** - * Returns the call object this call is replacing, if any. - * Call replacement can occur during call transfers. - * By default, the core automatically terminates the replaced call and accept the new one. - * This function allows the application to know whether a new incoming call is a one that replaces another one. -**/ -LINPHONE_PUBLIC LinphoneCall * linphone_call_get_replaced_call(LinphoneCall *call); - -/** - * Returns call's duration in seconds. -**/ -LINPHONE_PUBLIC int linphone_call_get_duration(const LinphoneCall *call); - -/** - * Returns current parameters associated to the call. -**/ -LINPHONE_PUBLIC const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call); - -/** - * Returns call parameters proposed by remote. - * - * This is useful when receiving an incoming call, to know whether the remote party - * supports video, encryption or whatever. -**/ -LINPHONE_PUBLIC const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call); - -/** - * Indicate whether camera input should be sent to remote end. -**/ -LINPHONE_PUBLIC void linphone_call_enable_camera(LinphoneCall *lc, bool_t enabled); - -/** - * Returns TRUE if camera pictures are allowed to be sent to the remote party. -**/ -LINPHONE_PUBLIC bool_t linphone_call_camera_enabled(const LinphoneCall *lc); - -/** - * Take a photo of currently received video and write it into a jpeg file. - * Note that the snapshot is asynchronous, an application shall not assume that the file is created when the function returns. - * @param call a LinphoneCall - * @param file a path where to write the jpeg content. - * @return 0 if successfull, -1 otherwise (typically if jpeg format is not supported). -**/ -LINPHONE_PUBLIC LinphoneStatus linphone_call_take_video_snapshot(LinphoneCall *call, const char *file); - -/** - * Take a photo of currently captured video and write it into a jpeg file. - * Note that the snapshot is asynchronous, an application shall not assume that the file is created when the function returns. - * @param call a LinphoneCall - * @param file a path where to write the jpeg content. - * @return 0 if successfull, -1 otherwise (typically if jpeg format is not supported). -**/ -LINPHONE_PUBLIC LinphoneStatus linphone_call_take_preview_snapshot(LinphoneCall *call, const char *file); - -/** - * Returns the reason for a call termination (either error or normal termination) -**/ -LINPHONE_PUBLIC LinphoneReason linphone_call_get_reason(const LinphoneCall *call); - - -/** - * Returns full details about call errors or termination reasons. - * @param call LinphoneCall object on which we want the information error - * @return LinphoneErrorInfo object holding the reason error. - */ -LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_call_get_error_info(const LinphoneCall *call); - -/** - * Returns the far end's user agent description string, if available. -**/ -LINPHONE_PUBLIC const char *linphone_call_get_remote_user_agent(LinphoneCall *call); - -/** - * Returns the far end's sip contact as a string, if available. -**/ -LINPHONE_PUBLIC const char *linphone_call_get_remote_contact(LinphoneCall *call); - -/** - * Returns the ZRTP authentication token to verify. - * @param call the LinphoneCall - * @return the authentication token to verify. -**/ -LINPHONE_PUBLIC const char * linphone_call_get_authentication_token(LinphoneCall *call); - -/** - * Returns whether ZRTP authentication token is verified. - * If not, it must be verified by users as described in ZRTP procedure. - * Once done, the application must inform of the results with linphone_call_set_authentication_token_verified(). - * @param call the LinphoneCall - * @return TRUE if authentication token is verifed, false otherwise. -**/ -LINPHONE_PUBLIC bool_t linphone_call_get_authentication_token_verified(const LinphoneCall *call); - -/** - * Set the result of ZRTP short code verification by user. - * If remote party also does the same, it will update the ZRTP cache so that user's verification will not be required for the two users. - * @param call the LinphoneCall - * @param verified whether the ZRTP SAS is verified. -**/ -LINPHONE_PUBLIC void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified); - -/** - * Request remote side to send us a Video Fast Update. -**/ -LINPHONE_PUBLIC void linphone_call_send_vfu_request(LinphoneCall *call); - -/** @deprecated Use linphone_call_get_user_data() instead. */ -#define linphone_call_get_user_pointer(call) linphone_call_get_user_data(call) - -/** @deprecated Use linphone_call_set_user_data() instead. */ -#define linphone_call_set_user_pointer(call, ud) linphone_call_set_user_data(call, ud) - -LINPHONE_PUBLIC void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void *user_data); - -/** - * Returns the current transfer state, if a transfer has been initiated from this call. - * @see linphone_core_transfer_call() , linphone_core_transfer_call_to_another() -**/ -LINPHONE_PUBLIC LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call); - -/** - * Perform a zoom of the video displayed during a call. - * @param call the call. - * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied. - * @param cx a floating point number pointing the horizontal center of the zoom to be applied. This value should be between 0.0 and 1.0. - * @param cy a floating point number pointing the vertical center of the zoom to be applied. This value should be between 0.0 and 1.0. - * - * cx and cy are updated in return in case their coordinates were too excentrated for the requested zoom factor. The zoom ensures that all the screen is fullfilled with the video. -**/ -LINPHONE_PUBLIC void linphone_call_zoom_video(LinphoneCall *call, float zoom_factor, float *cx, float *cy); - -/** - * Send the specified dtmf. - * - * The dtmf is automatically played to the user. - * @param call The LinphoneCall object - * @param dtmf The dtmf name specified as a char, such as '0', '#' etc... - * @return 0 if successful, -1 on error. -**/ -LINPHONE_PUBLIC LinphoneStatus linphone_call_send_dtmf(LinphoneCall *call, char dtmf); - -/** - * Send a list of dtmf. - * - * The dtmfs are automatically sent to remote, separated by some needed customizable delay. - * Sending is canceled if the call state changes to something not LinphoneCallStreamsRunning. - * @param call The LinphoneCall object - * @param dtmfs A dtmf sequence such as '123#123123' - * @return -2 if there is already a DTMF sequence, -1 if call is not ready, 0 otherwise. -**/ -LINPHONE_PUBLIC LinphoneStatus linphone_call_send_dtmfs(LinphoneCall *call, const char *dtmfs); - -/** - * Stop current DTMF sequence sending. - * - * Please note that some DTMF could be already sent, - * depending on when this function call is delayed from #linphone_call_send_dtmfs. This - * function will be automatically called if call state change to anything but LinphoneCallStreamsRunning. - * @param call The LinphoneCall object -**/ -LINPHONE_PUBLIC void linphone_call_cancel_dtmfs(LinphoneCall *call); - -/** - * Return TRUE if this call is currently part of a conference - * @param call #LinphoneCall - * @return TRUE if part of a conference. - * @deprecated Use linphone_call_get_conference() instead. - * @donotwrap - */ -LINPHONE_PUBLIC LINPHONE_DEPRECATED bool_t linphone_call_is_in_conference(const LinphoneCall *call); - -/** - * Return the associated conference object - * @param call #LinphoneCall - * @return A pointer on #LinphoneConference or NULL if the call is not part of any conference. - */ -LINPHONE_PUBLIC LinphoneConference * linphone_call_get_conference(const LinphoneCall *call); - -/** - * Change the playback output device (currently only used for blackberry) - * @param call - * @param route the wanted audio route (earpiece, speaker, ...) -**/ -LINPHONE_PUBLIC void linphone_call_set_audio_route(LinphoneCall *call, LinphoneAudioRoute route); - -/** - * Returns the number of stream for the given call. - * Currently there is only two (Audio, Video), but later there will be more. - * @param call - * @return 2 -**/ -LINPHONE_PUBLIC int linphone_call_get_stream_count(const LinphoneCall *call); - -/** - * Returns the type of stream for the given stream index. - * @param call - * @param stream_index - * @return the type (MSAudio, MSVideo, MSText) of the stream of given index. -**/ -LINPHONE_PUBLIC MSFormatType linphone_call_get_stream_type(const LinphoneCall *call, int stream_index); - -/** - * Returns the meta rtp transport for the given stream index. - * @param call - * @param stream_index - * @return a pointer to the meta rtp transport if it exists, NULL otherwise -**/ -LINPHONE_PUBLIC RtpTransport * linphone_call_get_meta_rtp_transport(const LinphoneCall *call, int stream_index); - -/** - * Returns the meta rtcp transport for the given stream index. - * @param call - * @param stream_index - * @return a pointer to the meta rtcp transport if it exists, NULL otherwise -**/ -LINPHONE_PUBLIC RtpTransport * linphone_call_get_meta_rtcp_transport(const LinphoneCall *call, int stream_index); - -/** - * Pauses the call. If a music file has been setup using linphone_core_set_play_file(), - * this file will be played to the remote user. - * The only way to resume a paused call is to call linphone_call_resume(). - * @param[in] call LinphoneCall object - * @return 0 on success, -1 on failure - * @see linphone_call_resume() -**/ -LINPHONE_PUBLIC LinphoneStatus linphone_call_pause(LinphoneCall *call); - -/** - * Resumes a call. - * The call needs to have been paused previously with linphone_call_pause(). - * @param[in] call LinphoneCall object - * @return 0 on success, -1 on failure - * @see linphone_call_pause() -**/ -LINPHONE_PUBLIC LinphoneStatus linphone_call_resume(LinphoneCall *call); - -/** - * Terminates a call. - * @param[in] call LinphoneCall object - * @return 0 on success, -1 on failure -**/LINPHONE_PUBLIC LinphoneStatus linphone_call_terminate(LinphoneCall *call); - - -/** - * Terminates a call. - * @param[in] call LinphoneCall object - * @param[in] ei LinphoneErrorInfo - * @return 0 on success, -1 on failure -**/ -LINPHONE_PUBLIC LinphoneStatus linphone_call_terminate_with_error_info(LinphoneCall *call, const LinphoneErrorInfo *ei); - -/** - * Redirect the specified call to the given redirect URI. - * @param[in] call A LinphoneCall object - * @param[in] redirect_uri The URI to redirect the call to - * @return 0 if successful, -1 on error. - */ -LINPHONE_PUBLIC LinphoneStatus linphone_call_redirect(LinphoneCall *call, const char *redirect_uri); - -/** - * Decline a pending incoming call, with a reason. - * @param[in] call A LinphoneCall object that must be in the IncomingReceived state - * @param[in] reason The reason for rejecting the call: LinphoneReasonDeclined or LinphoneReasonBusy - * @return 0 on success, -1 on failure -**/ -LINPHONE_PUBLIC LinphoneStatus linphone_call_decline(LinphoneCall * call, LinphoneReason reason); - -/** - * Decline a pending incoming call, with a LinphoneErrorInfo object. - * @param[in] call A LinphoneCall object that must be in the IncomingReceived state - * @param[in] ei LinphoneErrorInfo containing more information on the call rejection. - * @return 0 on success, -1 on failure - */ -LINPHONE_PUBLIC int linphone_call_decline_with_error_info(LinphoneCall * call, const LinphoneErrorInfo *ei); - -/** - * Accept an incoming call. - * - * Basically the application is notified of incoming calls within the - * call_state_changed callback of the #LinphoneCoreVTable structure, where it will receive - * a LinphoneCallIncoming event with the associated LinphoneCall object. - * The application can later accept the call using this method. - * @param[in] call A LinphoneCall object - * @return 0 on success, -1 on failure -**/ -LINPHONE_PUBLIC LinphoneStatus linphone_call_accept(LinphoneCall *call); - -/** - * Accept an incoming call, with parameters. - * - * Basically the application is notified of incoming calls within the - * call_state_changed callback of the #LinphoneCoreVTable structure, where it will receive - * a LinphoneCallIncoming event with the associated LinphoneCall object. - * The application can later accept the call using this method. - * @param[in] call A LinphoneCall object - * @param[in] params The specific parameters for this call, for example whether video is accepted or not. Use NULL to use default parameters - * @return 0 on success, -1 on failure -**/ -LINPHONE_PUBLIC LinphoneStatus linphone_call_accept_with_params(LinphoneCall *call, const LinphoneCallParams *params); - -/** - * Accept an early media session for an incoming call. - * This is identical as calling linphone_call_accept_early_media_with_params() with NULL parameters. - * @param[in] call A LinphoneCall object - * @return 0 if successful, -1 otherwise - * @see linphone_call_accept_early_media_with_params() -**/ -LINPHONE_PUBLIC LinphoneStatus linphone_call_accept_early_media(LinphoneCall *call); - -/** - * When receiving an incoming, accept to start a media session as early-media. - * This means the call is not accepted but audio & video streams can be established if the remote party supports early media. - * However, unlike after call acceptance, mic and camera input are not sent during early-media, though received audio & video are played normally. - * The call can then later be fully accepted using linphone_call_accept() or linphone_call_accept_with_params(). - * @param[in] call A LinphoneCall object - * @param[in] params The call parameters to use (can be NULL) - * @return 0 if successful, -1 otherwise -**/ -LINPHONE_PUBLIC LinphoneStatus linphone_call_accept_early_media_with_params(LinphoneCall *call, const LinphoneCallParams *params); - -/** - * Updates a running call according to supplied call parameters or parameters changed in the LinphoneCore. - * In this version this is limited to the following use cases: - * - setting up/down the video stream according to the video parameter of the LinphoneCallParams (see linphone_call_params_enable_video() ). - * - changing the size of the transmitted video after calling linphone_core_set_preferred_video_size() - * In case no changes are requested through the LinphoneCallParams argument, then this argument can be omitted and set to NULL. - * WARNING: Updating a call in the LinphoneCallPaused state will still result in a paused call even if the media directions set in the - * params are sendrecv. To resume a paused call, you need to call linphone_call_resume(). - * - * @param[in] call A LinphoneCall object - * @param[in] params The new call parameters to use (may be NULL) - * @return 0 if successful, -1 otherwise. -**/ -LINPHONE_PUBLIC LinphoneStatus linphone_call_update(LinphoneCall *call, const LinphoneCallParams *params); - -/** - * When receiving a #LinphoneCallUpdatedByRemote state notification, prevent LinphoneCore from performing an automatic answer. - * - * When receiving a #LinphoneCallUpdatedByRemote state notification (ie an incoming reINVITE), the default behaviour of - * LinphoneCore is defined by the "defer_update_default" option of the "sip" section of the config. If this option is 0 (the default) - * then the LinphoneCore automatically answers the reINIVTE with call parameters unchanged. - * However when for example when the remote party updated the call to propose a video stream, it can be useful - * to prompt the user before answering. This can be achieved by calling linphone_core_defer_call_update() during - * the call state notification, to deactivate the automatic answer that would just confirm the audio but reject the video. - * Then, when the user responds to dialog prompt, it becomes possible to call linphone_call_accept_update() to answer - * the reINVITE, with eventually video enabled in the LinphoneCallParams argument. - * - * The #LinphoneCallUpdatedByRemote notification can also arrive when receiving an INVITE without SDP. In such case, an unchanged offer is made - * in the 200Ok, and when the ACK containing the SDP answer is received, #LinphoneCallUpdatedByRemote is triggered to notify the application of possible - * changes in the media session. However in such case defering the update has no meaning since we just generating an offer. - * - * @param[in] call A LinphoneCall object - * @return 0 if successful, -1 if the linphone_call_defer_update() was done outside a valid #LinphoneCallUpdatedByRemote notification -**/ -LINPHONE_PUBLIC LinphoneStatus linphone_call_defer_update(LinphoneCall *call); - -/** - * Accept call modifications initiated by other end. - * - * This call may be performed in response to a #LinphoneCallUpdatedByRemote state notification. - * When such notification arrives, the application can decide to call linphone_call_defer_update() so that it can - * have the time to prompt the user. linphone_call_get_remote_params() can be used to get information about the call parameters - * requested by the other party, such as whether a video stream is requested. - * - * When the user accepts or refuse the change, linphone_call_accept_update() can be done to answer to the other party. - * If params is NULL, then the same call parameters established before the update request will continue to be used (no change). - * If params is not NULL, then the update will be accepted according to the parameters passed. - * Typical example is when a user accepts to start video, then params should indicate that video stream should be used - * (see linphone_call_params_enable_video()). - * @param[in] call A LinphoneCall object - * @param[in] params A LinphoneCallParams object describing the call parameters to accept - * @return 0 if successful, -1 otherwise (actually when this function call is performed outside ot #LinphoneCallUpdatedByRemote state) -**/ -LINPHONE_PUBLIC LinphoneStatus linphone_call_accept_update(LinphoneCall *call, const LinphoneCallParams *params); - -/** - * Performs a simple call transfer to the specified destination. - * The remote endpoint is expected to issue a new call to the specified destination. - * The current call remains active and thus can be later paused or terminated. - * It is possible to follow the progress of the transfer provided that transferee sends notification about it. - * In this case, the transfer_state_changed callback of the #LinphoneCoreVTable is invoked to notify of the state of the new call at the other party. - * The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallConnected. - * @param[in] call The call to be transfered - * @param[in] refer_to The destination the call is to be refered to - * @return 0 on success, -1 on failure -**/ -LINPHONE_PUBLIC LinphoneStatus linphone_call_transfer(LinphoneCall *call, const char *refer_to); - -/** - * Transfers a call to destination of another running call. This is used for "attended transfer" scenarios. - * The transfered call is supposed to be in paused state, so that it is able to accept the transfer immediately. - * The destination call is a call previously established to introduce the transfered person. - * This method will send a transfer request to the transfered person. The phone of the transfered is then - * expected to automatically call to the destination of the transfer. The receiver of the transfer will then automatically - * close the call with us (the 'dest' call). - * It is possible to follow the progress of the transfer provided that transferee sends notification about it. - * In this case, the transfer_state_changed callback of the #LinphoneCoreVTable is invoked to notify of the state of the new call at the other party. - * The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallConnected. - * @param[in] call A running call you want to transfer - * @param[in] dest A running call whose remote person will receive the transfer - * @return 0 on success, -1 on failure -**/ -LINPHONE_PUBLIC LinphoneStatus linphone_call_transfer_to_another(LinphoneCall *call, LinphoneCall *dest); - - -/** - * Acquire a reference to the LinphoneCallCbs object. - * @param[in] cbs LinphoneCallCbs object. - * @return The same LinphoneCallCbs object. - */ -LINPHONE_PUBLIC LinphoneCallCbs *linphone_call_cbs_ref(LinphoneCallCbs *cbs); - -/** - * Release reference to the LinphoneCallCbs object. - * @param[in] cbs LinphoneCallCbs object. - */ -LINPHONE_PUBLIC void linphone_call_cbs_unref(LinphoneCallCbs *cbs); - -/** - * Retrieve the user pointer associated with the LinphoneCallCbs object. - * @param[in] cbs LinphoneCallCbs object. - * @return The user pointer associated with the LinphoneCallCbs object. - */ -LINPHONE_PUBLIC void *linphone_call_cbs_get_user_data(const LinphoneCallCbs *cbs); - -/** - * Assign a user pointer to the LinphoneCallCbs object. - * @param[in] cbs LinphoneCallCbs object. - * @param[in] ud The user pointer to associate with the LinphoneCallCbs object. - */ -LINPHONE_PUBLIC void linphone_call_cbs_set_user_data(LinphoneCallCbs *cbs, void *user_data); - -/** - * Get the dtmf received callback. - * @param[in] cbs LinphoneCallCbs object. - * @return The current dtmf received callback. - */ -LINPHONE_PUBLIC LinphoneCallCbsDtmfReceivedCb linphone_call_cbs_get_dtmf_received(LinphoneCallCbs *cbs); - -/** - * Set the dtmf received callback. - * @param[in] cbs LinphoneCallCbs object. - * @param[in] cb The dtmf received callback to be used. - */ -LINPHONE_PUBLIC void linphone_call_cbs_set_dtmf_received(LinphoneCallCbs *cbs, LinphoneCallCbsDtmfReceivedCb cb); - -/** - * Get the encryption changed callback. - * @param[in] cbs LinphoneCallCbs object. - * @return The current encryption changed callback. - */ -LINPHONE_PUBLIC LinphoneCallCbsEncryptionChangedCb linphone_call_cbs_get_encryption_changed(LinphoneCallCbs *cbs); - -/** - * Set the encryption changed callback. - * @param[in] cbs LinphoneCallCbs object. - * @param[in] cb The encryption changed callback to be used. - */ -LINPHONE_PUBLIC void linphone_call_cbs_set_encryption_changed(LinphoneCallCbs *cbs, LinphoneCallCbsEncryptionChangedCb cb); - -/** - * Get the info message received callback. - * @param[in] cbs LinphoneCallCbs object. - * @return The current info message received callback. - */ -LINPHONE_PUBLIC LinphoneCallCbsInfoMessageReceivedCb linphone_call_cbs_get_info_message_received(LinphoneCallCbs *cbs); - -/** - * Set the info message received callback. - * @param[in] cbs LinphoneCallCbs object. - * @param[in] cb The info message received callback to be used. - */ -LINPHONE_PUBLIC void linphone_call_cbs_set_info_message_received(LinphoneCallCbs *cbs, LinphoneCallCbsInfoMessageReceivedCb cb); - -/** - * Get the state changed callback. - * @param[in] cbs LinphoneCallCbs object. - * @return The current state changed callback. - */ -LINPHONE_PUBLIC LinphoneCallCbsStateChangedCb linphone_call_cbs_get_state_changed(LinphoneCallCbs *cbs); - -/** - * Set the state changed callback. - * @param[in] cbs LinphoneCallCbs object. - * @param[in] cb The state changed callback to be used. - */ -LINPHONE_PUBLIC void linphone_call_cbs_set_state_changed(LinphoneCallCbs *cbs, LinphoneCallCbsStateChangedCb cb); - -/** - * Get the stats updated callback. - * @param[in] cbs LinphoneCallCbs object. - * @return The current stats updated callback. - */ -LINPHONE_PUBLIC LinphoneCallCbsStatsUpdatedCb linphone_call_cbs_get_stats_updated(LinphoneCallCbs *cbs); - -/** - * Set the stats updated callback. - * @param[in] cbs LinphoneCallCbs object. - * @param[in] cb The stats updated callback to be used. - */ -LINPHONE_PUBLIC void linphone_call_cbs_set_stats_updated(LinphoneCallCbs *cbs, LinphoneCallCbsStatsUpdatedCb cb); - -/** - * Get the transfer state changed callback. - * @param[in] cbs LinphoneCallCbs object. - * @return The current transfer state changed callback. - */ -LINPHONE_PUBLIC LinphoneCallCbsTransferStateChangedCb linphone_call_cbs_get_transfer_state_changed(LinphoneCallCbs *cbs); - -/** - * Set the transfer state changed callback. - * @param[in] cbs LinphoneCallCbs object. - * @param[in] cb The transfer state changed callback to be used. - */ -LINPHONE_PUBLIC void linphone_call_cbs_set_transfer_state_changed(LinphoneCallCbs *cbs, LinphoneCallCbsTransferStateChangedCb cb); - -/** - * Get the ACK processing callback. - * @param[in] cbs LinphoneCallCbs object. - * @return The current ack processing callback. - */ -LINPHONE_PUBLIC LinphoneCallCbsAckProcessingCb linphone_call_cbs_get_ack_processing(LinphoneCallCbs *cbs); - -/** - * Set ACK processing callback. - * @param[in] cbs LinphoneCallCbs object. - * @param[in] cb The ack processing callback to be used. - */ -LINPHONE_PUBLIC void linphone_call_cbs_set_ack_processing(LinphoneCallCbs *cbs, LinphoneCallCbsAckProcessingCb cb); - -/** - * @} - */ - - -/** - * @addtogroup media_parameters - * @{ - */ - -/** - * Get the native window handle of the video window, casted as an unsigned long. -**/ -LINPHONE_PUBLIC void * linphone_call_get_native_video_window_id(const LinphoneCall *call); - -/** - * Set the native video window id where the video is to be displayed. - * For MacOS, Linux, Windows: if not set or 0 a window will be automatically created, unless the special id -1 is given. -**/ -LINPHONE_PUBLIC void linphone_call_set_native_video_window_id(LinphoneCall *call, void * id); - -/** - * Enables or disable echo cancellation for this call - * @param call - * @param val -**/ -LINPHONE_PUBLIC void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t val) ; - -/** - * Returns TRUE if echo cancellation is enabled. -**/ -LINPHONE_PUBLIC bool_t linphone_call_echo_cancellation_enabled(const LinphoneCall *call); - -/** - * Enables or disable echo limiter for this call - * @param call - * @param val -**/ -LINPHONE_PUBLIC void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val); - -/** - * Returns TRUE if echo limiter is enabled. -**/ -LINPHONE_PUBLIC bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call); - -/** - * @} - */ - -/** - * @addtogroup call_misc - * @{ - */ - -/** - * Create a new chat room for messaging from a call if not already existing, else return existing one. - * No reference is given to the caller: the chat room will be deleted when the call is ended. - * @param call #LinphoneCall object - * @return #LinphoneChatRoom where messaging can take place. - */ -LINPHONE_PUBLIC LinphoneChatRoom * linphone_call_get_chat_room(LinphoneCall *call); - -/** - * Get the mesured playback volume level (received from remote) in dbm0. - * @param call The call. - * @return float Volume level in percentage. - */ -LINPHONE_PUBLIC float linphone_call_get_play_volume(const LinphoneCall *call); - -/** - * Get the mesured record volume level (sent to remote) in dbm0. - * @param call The call. - * @return float Volume level in percentage. - */ -LINPHONE_PUBLIC float linphone_call_get_record_volume(const LinphoneCall *call); - -/** - * Get speaker volume gain. - * If the sound backend supports it, the returned gain is equal to the gain set - * with the system mixer. - * @param call The call. - * @return Percenatge of the max supported volume gain. Valid values are in [ 0.0 : 1.0 ]. - * In case of failure, a negative value is returned - */ -LINPHONE_PUBLIC float linphone_call_get_speaker_volume_gain(const LinphoneCall *call); - -/** - * Set speaker volume gain. - * If the sound backend supports it, the new gain will synchronized with the system mixer. - * @param call The call. - * @param volume Percentage of the max supported gain. Valid values are in [ 0.0 : 1.0 ]. - */ -LINPHONE_PUBLIC void linphone_call_set_speaker_volume_gain(LinphoneCall *call, float volume); - -/** - * Get microphone volume gain. - * If the sound backend supports it, the returned gain is equal to the gain set - * with the system mixer. - * @param call The call. - * @return double Percenatge of the max supported volume gain. Valid values are in [ 0.0 : 1.0 ]. - * In case of failure, a negative value is returned - */ -LINPHONE_PUBLIC float linphone_call_get_microphone_volume_gain(const LinphoneCall *call); - -/** - * Set microphone volume gain. - * If the sound backend supports it, the new gain will synchronized with the system mixer. - * @param call The call. - * @param volume Percentage of the max supported gain. Valid values are in [ 0.0 : 1.0 ]. - */ -LINPHONE_PUBLIC void linphone_call_set_microphone_volume_gain(LinphoneCall *call, float volume); - -/** - * Obtain real-time quality rating of the call - * - * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated - * during all the duration of the call. This function returns its value at the time of the function call. - * It is expected that the rating is updated at least every 5 seconds or so. - * The rating is a floating point number comprised between 0 and 5. - * - * 4-5 = good quality
- * 3-4 = average quality
- * 2-3 = poor quality
- * 1-2 = very poor quality
- * 0-1 = can't be worse, mostly unusable
- * - * @return The function returns -1 if no quality measurement is available, for example if no - * active audio stream exist. Otherwise it returns the quality rating. -**/ -LINPHONE_PUBLIC float linphone_call_get_current_quality(const LinphoneCall *call); - -/** - * Returns call quality averaged over all the duration of the call. - * - * See linphone_call_get_current_quality() for more details about quality measurement. -**/ -LINPHONE_PUBLIC float linphone_call_get_average_quality(const LinphoneCall *call); - -/** - * Start call recording. - * The output file where audio is recorded must be previously specified with linphone_call_params_set_record_file(). -**/ -LINPHONE_PUBLIC void linphone_call_start_recording(LinphoneCall *call); - -/** - * Stop call recording. -**/ -LINPHONE_PUBLIC void linphone_call_stop_recording(LinphoneCall *call); - -/** - * Get a player associated with the call to play a local file and stream it to the remote peer. - * @param[in] call LinphoneCall object - * @return A LinphonePlayer object - */ -LINPHONE_PUBLIC LinphonePlayer * linphone_call_get_player(LinphoneCall *call); - -/** - * Indicates whether an operation is in progress at the media side. - * It can be a bad idea to initiate signaling operations (adding video, pausing the call, removing video, changing video parameters) while - * the media is busy in establishing the connection (typically ICE connectivity checks). It can result in failures generating loss of time - * in future operations in the call. - * Applications are invited to check this function after each call state change to decide whether certain operations are permitted or not. - * @param call the call - * @return TRUE if media is busy in establishing the connection, FALSE otherwise. -**/ -LINPHONE_PUBLIC bool_t linphone_call_media_in_progress(const LinphoneCall *call); - -/** - * Call generic OpenGL render for a given call. - * @param call The call. - */ -LINPHONE_PUBLIC void linphone_call_ogl_render(const LinphoneCall *call); - - - -/** - * Send a LinphoneInfoMessage through an established call - * @param call the call - * @param info the info message -**/ -LINPHONE_PUBLIC LinphoneStatus linphone_call_send_info_message(LinphoneCall *call, const LinphoneInfoMessage *info); - -/** - * Return a copy of the call statistics for a particular stream type. - * @param call the call - * @param type the stream type -**/ -LINPHONE_PUBLIC LinphoneCallStats *linphone_call_get_stats(LinphoneCall *call, LinphoneStreamType type); - -LINPHONE_PUBLIC LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call); - -LINPHONE_PUBLIC LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call); - -LINPHONE_PUBLIC LinphoneCallStats *linphone_call_get_text_stats(LinphoneCall *call); - -/** - * Add a listener in order to be notified of LinphoneCall events. Once an event is received, registred LinphoneCallCbs are - * invoked sequencially. - * @param[in] call LinphoneCall object to monitor. - * @param[in] cbs A LinphoneCallCbs object holding the callbacks you need. A reference is taken by the LinphoneCall until you invoke linphone_call_remove_callbacks(). - */ -LINPHONE_PUBLIC void linphone_call_add_callbacks(LinphoneCall *call, LinphoneCallCbs *cbs); - -/** - * Remove a listener from a LinphoneCall - * @param[in] call LinphoneCall object - * @param[in] cbs LinphoneCallCbs object to remove. - */ -LINPHONE_PUBLIC void linphone_call_remove_callbacks(LinphoneCall *call, LinphoneCallCbs *cbs); - -/** - * Gets the current LinphoneCallCbs. - * This is meant only to be called from a callback to be able to get the user_data associated with the LinphoneCallCbs that is calling the callback. - * @param[in] call LinphoneCall object - * @return The LinphoneCallCbs that has called the last callback - */ -LINPHONE_PUBLIC LinphoneCallCbs *linphone_call_get_current_callbacks(const LinphoneCall *call); - -/** - * Set call parameters - advanced and not recommended feature - use with caution. - * Local call parameters applicable to an outgoing or incoming shall usually be passed to linphone_core_invite_address_with_params() or - * linphone_call_accept_with_params(). - * However, in some cases it might be desirable from a software design standpoint to modify local parameters outside of the application layer, typically - * in the purpose of implementing a custom logic including special headers in INVITE or 200Ok requests, driven by a call_state_changed listener method. - * This function accepts to assign a new LinphoneCallParams only in LinphoneCallOutgoingInit and LinphoneCallIncomingReceived states. - * @param call the LinphoneCall object -**/ -LINPHONE_PUBLIC void linphone_call_set_params(LinphoneCall *call, const LinphoneCallParams *params); - -/** - * Returns local parameters associated with the call. - * This is typically the parameters passed at call initiation to linphone_core_invite_address_with_params() or linphone_call_accept_with_params(), or some default - * parameters if no LinphoneCallParams was explicitely passed during call initiation. - * @param call the LinphoneCall object - * @return the call's local parameters. - **/ -LINPHONE_PUBLIC const LinphoneCallParams * linphone_call_get_params(LinphoneCall *call); - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif +#include "linphone/api/c-call.h" #endif /* LINPHONE_CALL_H */ diff --git a/include/linphone/call_stats.h b/include/linphone/call_stats.h index ff2074dba..bbed92e75 100644 --- a/include/linphone/call_stats.h +++ b/include/linphone/call_stats.h @@ -20,164 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef LINPHONE_CALL_STATS_H #define LINPHONE_CALL_STATS_H -#include "linphone/types.h" +#include "linphone/api/c-call-stats.h" -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @addtogroup call_misc - * @{ - */ - -#define LINPHONE_CALL_STATS_AUDIO ((int)LinphoneStreamTypeAudio) -#define LINPHONE_CALL_STATS_VIDEO ((int)LinphoneStreamTypeVideo) -#define LINPHONE_CALL_STATS_TEXT ((int)LinphoneStreamTypeText) - -#define LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE (1 << 0) /**< received_rtcp field of LinphoneCallStats object has been updated */ -#define LINPHONE_CALL_STATS_SENT_RTCP_UPDATE (1 << 1) /**< sent_rtcp field of LinphoneCallStats object has been updated */ -#define LINPHONE_CALL_STATS_PERIODICAL_UPDATE (1 << 2) /**< Every seconds LinphoneCallStats object has been updated */ - -/** - * Increment refcount. - * @param[in] stats LinphoneCallStats object - * @ingroup misc -**/ -LINPHONE_PUBLIC LinphoneCallStats *linphone_call_stats_ref(LinphoneCallStats *stats); - -/** - * Decrement refcount and possibly free the object. - * @param[in] stats LinphoneCallStats object - * @ingroup misc -**/ -LINPHONE_PUBLIC void linphone_call_stats_unref(LinphoneCallStats *stats); - -/** - * Gets the user data in the LinphoneCallStats object - * @param[in] stats the LinphoneCallStats - * @return the user data - * @ingroup misc -*/ -LINPHONE_PUBLIC void *linphone_call_stats_get_user_data(const LinphoneCallStats *stats); - -/** - * Sets the user data in the LinphoneCallStats object - * @param[in] stats the LinphoneCallStats object - * @param[in] data the user data - * @ingroup misc -*/ -LINPHONE_PUBLIC void linphone_call_stats_set_user_data(LinphoneCallStats *stats, void *data); - -/** - * Get the type of the stream the stats refer to. - * @param[in] stats LinphoneCallStats object - * @return The type of the stream the stats refer to - */ -LINPHONE_PUBLIC LinphoneStreamType linphone_call_stats_get_type(const LinphoneCallStats *stats); - -/** - * Get the local loss rate since last report - * @return The sender loss rate -**/ -LINPHONE_PUBLIC float linphone_call_stats_get_sender_loss_rate(const LinphoneCallStats *stats); - -/** - * Gets the remote reported loss rate since last report - * @return The receiver loss rate -**/ -LINPHONE_PUBLIC float linphone_call_stats_get_receiver_loss_rate(const LinphoneCallStats *stats); - -/** - * Get the local loss rate since last report - * @return The local loss rate -**/ -LINPHONE_PUBLIC float linphone_call_stats_get_local_loss_rate(const LinphoneCallStats *stats); - -/** - * Gets the local late rate since last report - * @return The local late rate -**/ -LINPHONE_PUBLIC float linphone_call_stats_get_local_late_rate(const LinphoneCallStats *stats); - -/** - * Gets the local interarrival jitter - * @param[in] stats LinphoneCallStats object - * @return The interarrival jitter at last emitted sender report -**/ -LINPHONE_PUBLIC float linphone_call_stats_get_sender_interarrival_jitter(const LinphoneCallStats *stats); - -/** - * Gets the remote reported interarrival jitter - * @param[in] stats LinphoneCallStats object - * @return The interarrival jitter at last received receiver report -**/ -LINPHONE_PUBLIC float linphone_call_stats_get_receiver_interarrival_jitter(const LinphoneCallStats *stats); - -LINPHONE_PUBLIC const rtp_stats_t *linphone_call_stats_get_rtp_stats(const LinphoneCallStats *stats); - -/** - * Gets the cumulative number of late packets - * @param[in] stats LinphoneCallStats object - * @return The cumulative number of late packets -**/ -LINPHONE_PUBLIC uint64_t linphone_call_stats_get_late_packets_cumulative_number(const LinphoneCallStats *stats); - -/** - * Get the bandwidth measurement of the received stream, expressed in kbit/s, including IP/UDP/RTP headers. - * @param[in] stats LinphoneCallStats object - * @return The bandwidth measurement of the received stream in kbit/s. - */ -LINPHONE_PUBLIC float linphone_call_stats_get_download_bandwidth(const LinphoneCallStats *stats); - -/** - * Get the bandwidth measurement of the sent stream, expressed in kbit/s, including IP/UDP/RTP headers. - * @param[in] stats LinphoneCallStats object - * @return The bandwidth measurement of the sent stream in kbit/s. - */ -LINPHONE_PUBLIC float linphone_call_stats_get_upload_bandwidth(const LinphoneCallStats *stats); - -/** - * Get the state of ICE processing. - * @param[in] stats LinphoneCallStats object - * @return The state of ICE processing. - */ -LINPHONE_PUBLIC LinphoneIceState linphone_call_stats_get_ice_state(const LinphoneCallStats *stats); - -/** - * Get the state of uPnP processing. - * @param[in] stats LinphoneCallStats object - * @return The state of uPnP processing. - */ -LINPHONE_PUBLIC LinphoneUpnpState linphone_call_stats_get_upnp_state(const LinphoneCallStats *stats); - -/** - * Get the IP address family of the remote peer. - * @param[in] stats LinphoneCallStats object - * @return The IP address family of the remote peer. - */ -LINPHONE_PUBLIC LinphoneAddressFamily linphone_call_stats_get_ip_family_of_remote(const LinphoneCallStats *stats); - -/** - * Get the jitter buffer size in ms. - * @param[in] stats LinphoneCallStats object - * @return The jitter buffer size in ms. - */ -LINPHONE_PUBLIC float linphone_call_stats_get_jitter_buffer_size_ms(const LinphoneCallStats *stats); - -/** - * Get the round trip delay in s. - * @param[in] stats LinphoneCallStats object - * @return The round trip delay in s. - */ -LINPHONE_PUBLIC float linphone_call_stats_get_round_trip_delay(const LinphoneCallStats *stats); - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* LINPHONE_ADDRESS_H */ +#endif /* LINPHONE_CALL_STATS_H */ diff --git a/include/linphone/callbacks.h b/include/linphone/callbacks.h index d99128a2d..1c9b8b9ba 100644 --- a/include/linphone/callbacks.h +++ b/include/linphone/callbacks.h @@ -34,67 +34,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * @} **/ -/** - * @addtogroup call_control - * @{ -**/ - -/** - * Callback for being notified of received DTMFs. - * @param call LinphoneCall object that received the dtmf - * @param dtmf The ascii code of the dtmf - */ -typedef void (*LinphoneCallCbsDtmfReceivedCb)(LinphoneCall *call, int dtmf); - -/** - * Call encryption changed callback. - * @param call LinphoneCall object whose encryption is changed. - * @param on Whether encryption is activated. - * @param authentication_token An authentication_token, currently set for ZRTP kind of encryption only. - */ -typedef void (*LinphoneCallCbsEncryptionChangedCb)(LinphoneCall *call, bool_t on, const char *authentication_token); - -/** - * Callback for receiving info messages. - * @param call LinphoneCall whose info message belongs to. - * @param msg LinphoneInfoMessage object. - */ -typedef void (*LinphoneCallCbsInfoMessageReceivedCb)(LinphoneCall *call, const LinphoneInfoMessage *msg); - -/** - * Call state notification callback. - * @param call LinphoneCall whose state is changed. - * @param cstate The new state of the call - * @param message An informational message about the state. - */ -typedef void (*LinphoneCallCbsStateChangedCb)(LinphoneCall *call, LinphoneCallState cstate, const char *message); - -/** - * Callback for receiving quality statistics for calls. - * @param call LinphoneCall object whose statistics are notified - * @param stats LinphoneCallStats object - */ -typedef void (*LinphoneCallCbsStatsUpdatedCb)(LinphoneCall *call, const LinphoneCallStats *stats); - -/** - * Callback for notifying progresses of transfers. - * @param call LinphoneCall that was transfered - * @param cstate The state of the call to transfer target at the far end. - */ -typedef void (*LinphoneCallCbsTransferStateChangedCb)(LinphoneCall *call, LinphoneCallState cstate); - -/** - * Callback for notifying the processing SIP ACK messages. - * @param call LinphoneCall for which an ACK is being received or sent - * @param ack the ACK message - * @param is_received if TRUE this ACK is an incoming one, otherwise it is an ACK about to be sent. - */ -typedef void (*LinphoneCallCbsAckProcessingCb)(LinphoneCall *call, LinphoneHeaders *ack, bool_t is_received); - -/** - * @} -**/ - /** * @addtogroup initializing * @{ diff --git a/include/linphone/types.h b/include/linphone/types.h index 3abe0f1bd..9690ed1d2 100644 --- a/include/linphone/types.h +++ b/include/linphone/types.h @@ -241,25 +241,6 @@ typedef enum _LinphoneAVPFMode { **/ typedef struct _LinphoneBuffer LinphoneBuffer; -/** - * The LinphoneCall object represents a call issued or received by the LinphoneCore - * @ingroup call_control -**/ -typedef struct _LinphoneCall LinphoneCall; - -/** - * That class holds all the callbacks which are called by LinphoneCall objects. - * - * Use linphone_factory_create_call_cbs() to create an instance. Then, call the - * callback setters on the events you need to monitor and pass the object to - * a LinphoneCall instance through linphone_call_add_callbacks(). - * @ingroup call_control - */ -typedef struct _LinphoneCallCbs LinphoneCallCbs; - -/** Callback prototype */ -typedef void (*LinphoneCallCbFunc)(LinphoneCall *call, void *user_data); - /** * Enum representing the direction of a call. * @ingroup call_logs diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3915f3584..edda58ab5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -103,7 +103,10 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES set(LINPHONE_CXX_OBJECTS_SOURCE_FILES address/address.cpp c-wrapper/api/c-address.cpp + c-wrapper/api/c-call.cpp + c-wrapper/api/c-call-cbs.cpp c-wrapper/api/c-call-params.cpp + c-wrapper/api/c-call-stats.cpp c-wrapper/api/c-chat-message.cpp c-wrapper/api/c-chat-message-cbs.cpp c-wrapper/api/c-chat-room.cpp diff --git a/src/c-wrapper/api/c-call-cbs.cpp b/src/c-wrapper/api/c-call-cbs.cpp new file mode 100644 index 000000000..241be5ab7 --- /dev/null +++ b/src/c-wrapper/api/c-call-cbs.cpp @@ -0,0 +1,125 @@ +/* + * c-call-cbs.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "linphone/api/c-call-cbs.h" + +#include "c-wrapper/c-wrapper.h" + +// ============================================================================= + +struct _LinphoneCallCbs { + belle_sip_object_t base; + void *userData; + LinphoneCallCbsDtmfReceivedCb dtmfReceivedCb; + LinphoneCallCbsEncryptionChangedCb encryptionChangedCb; + LinphoneCallCbsInfoMessageReceivedCb infoMessageReceivedCb; + LinphoneCallCbsStateChangedCb stateChangedCb; + LinphoneCallCbsStatsUpdatedCb statsUpdatedCb; + LinphoneCallCbsTransferStateChangedCb transferStateChangedCb; + LinphoneCallCbsAckProcessingCb ackProcessing; +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneCallCbs); + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCallCbs); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneCallCbs, belle_sip_object_t, + NULL, // destroy + NULL, // clone + NULL, // marshal + FALSE +); + +// ============================================================================= + +LinphoneCallCbs *_linphone_call_cbs_new (void) { + return belle_sip_object_new(LinphoneCallCbs); +} + +LinphoneCallCbs *linphone_call_cbs_ref (LinphoneCallCbs *cbs) { + belle_sip_object_ref(cbs); + return cbs; +} + +void linphone_call_cbs_unref (LinphoneCallCbs *cbs) { + belle_sip_object_unref(cbs); +} + +void *linphone_call_cbs_get_user_data (const LinphoneCallCbs *cbs) { + return cbs->userData; +} + +void linphone_call_cbs_set_user_data (LinphoneCallCbs *cbs, void *ud) { + cbs->userData = ud; +} + +LinphoneCallCbsDtmfReceivedCb linphone_call_cbs_get_dtmf_received (LinphoneCallCbs *cbs) { + return cbs->dtmfReceivedCb; +} + +void linphone_call_cbs_set_dtmf_received (LinphoneCallCbs *cbs, LinphoneCallCbsDtmfReceivedCb cb) { + cbs->dtmfReceivedCb = cb; +} + +LinphoneCallCbsEncryptionChangedCb linphone_call_cbs_get_encryption_changed (LinphoneCallCbs *cbs) { + return cbs->encryptionChangedCb; +} + +void linphone_call_cbs_set_encryption_changed (LinphoneCallCbs *cbs, LinphoneCallCbsEncryptionChangedCb cb) { + cbs->encryptionChangedCb = cb; +} + +LinphoneCallCbsInfoMessageReceivedCb linphone_call_cbs_get_info_message_received (LinphoneCallCbs *cbs) { + return cbs->infoMessageReceivedCb; +} + +void linphone_call_cbs_set_info_message_received (LinphoneCallCbs *cbs, LinphoneCallCbsInfoMessageReceivedCb cb) { + cbs->infoMessageReceivedCb = cb; +} + +LinphoneCallCbsStateChangedCb linphone_call_cbs_get_state_changed (LinphoneCallCbs *cbs) { + return cbs->stateChangedCb; +} + +void linphone_call_cbs_set_state_changed (LinphoneCallCbs *cbs, LinphoneCallCbsStateChangedCb cb) { + cbs->stateChangedCb = cb; +} + +LinphoneCallCbsStatsUpdatedCb linphone_call_cbs_get_stats_updated (LinphoneCallCbs *cbs) { + return cbs->statsUpdatedCb; +} + +void linphone_call_cbs_set_stats_updated (LinphoneCallCbs *cbs, LinphoneCallCbsStatsUpdatedCb cb) { + cbs->statsUpdatedCb = cb; +} + +LinphoneCallCbsTransferStateChangedCb linphone_call_cbs_get_transfer_state_changed (LinphoneCallCbs *cbs) { + return cbs->transferStateChangedCb; +} + +void linphone_call_cbs_set_transfer_state_changed (LinphoneCallCbs *cbs, LinphoneCallCbsTransferStateChangedCb cb) { + cbs->transferStateChangedCb = cb; +} + +LinphoneCallCbsAckProcessingCb linphone_call_cbs_get_ack_processing (LinphoneCallCbs *cbs){ + return cbs->ackProcessing; +} + +void linphone_call_cbs_set_ack_processing (LinphoneCallCbs *cbs, LinphoneCallCbsAckProcessingCb cb){ + cbs->ackProcessing = cb; +} diff --git a/src/c-wrapper/api/c-call-stats.cpp b/src/c-wrapper/api/c-call-stats.cpp new file mode 100644 index 000000000..a4cbe1c9f --- /dev/null +++ b/src/c-wrapper/api/c-call-stats.cpp @@ -0,0 +1,343 @@ +/* + * c-call-stats.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "linphone/api/c-call-stats.h" + +#include "c-wrapper/c-wrapper.h" + +// ============================================================================= + +void _linphone_call_stats_clone (LinphoneCallStats *dst, const LinphoneCallStats *src); + +/** + * The LinphoneCallStats objects carries various statistic informations regarding quality of audio or video streams. + * + * To receive these informations periodically and as soon as they are computed, the application is invited to place a #LinphoneCoreCallStatsUpdatedCb callback in the LinphoneCoreVTable structure + * it passes for instantiating the LinphoneCore object (see linphone_core_new() ). + * + * At any time, the application can access last computed statistics using linphone_call_get_audio_stats() or linphone_call_get_video_stats(). +**/ +struct _LinphoneCallStats { + belle_sip_object_t base; + void *user_data; + LinphoneStreamType type; /**< Type of the stream which the stats refer to */ + jitter_stats_t jitter_stats; /**received_rtcp) { + freemsg(stats->received_rtcp); + stats->received_rtcp=NULL; + } + if (stats->sent_rtcp){ + freemsg(stats->sent_rtcp); + stats->sent_rtcp=NULL; + } +} + +void _linphone_call_stats_clone (LinphoneCallStats *dst, const LinphoneCallStats *src) { + /* + * Save the belle_sip_object_t part, copy the entire structure and restore the belle_sip_object_t part + */ + belle_sip_object_t tmp = dst->base; + memcpy(dst, src, sizeof(LinphoneCallStats)); + dst->base = tmp; + + dst->received_rtcp = NULL; + dst->sent_rtcp = NULL; +} + +void _linphone_call_stats_set_ice_state (LinphoneCallStats *stats, LinphoneIceState state) { + stats->ice_state = state; +} + +void _linphone_call_stats_set_type (LinphoneCallStats *stats, LinphoneStreamType type) { + stats->type = type; +} + +void _linphone_call_stats_set_received_rtcp (LinphoneCallStats *stats, mblk_t *m) { + stats->received_rtcp = m; +} + +void _linphone_call_stats_set_sent_rtcp (LinphoneCallStats *stats, mblk_t *m) { + stats->sent_rtcp = m; +} + +int _linphone_call_stats_get_updated (const LinphoneCallStats *stats) { + return stats->updated; +} + +void _linphone_call_stats_set_updated (LinphoneCallStats *stats, int updated) { + stats->updated = updated; +} + +void _linphone_call_stats_set_rtp_stats (LinphoneCallStats *stats, const rtp_stats_t *rtpStats) { + memcpy(&(stats->rtp_stats), rtpStats, sizeof(*rtpStats)); +} + +void _linphone_call_stats_set_download_bandwidth (LinphoneCallStats *stats, float bandwidth) { + stats->download_bandwidth = bandwidth; +} + +void _linphone_call_stats_set_upload_bandwidth (LinphoneCallStats *stats, float bandwidth) { + stats->upload_bandwidth = bandwidth; +} + +void _linphone_call_stats_set_rtcp_download_bandwidth (LinphoneCallStats *stats, float bandwidth) { + stats->rtcp_download_bandwidth = bandwidth; +} + +void _linphone_call_stats_set_rtcp_upload_bandwidth (LinphoneCallStats *stats, float bandwidth) { + stats->rtcp_upload_bandwidth = bandwidth; +} + +void _linphone_call_stats_set_ip_family_of_remote (LinphoneCallStats *stats, LinphoneAddressFamily family) { + stats->rtp_remote_family = family; +} + +// ============================================================================= +// Public functions +// ============================================================================= + +LinphoneCallStats *linphone_call_stats_ref (LinphoneCallStats* stats) { + return (LinphoneCallStats*) belle_sip_object_ref(stats); +} + +void linphone_call_stats_unref (LinphoneCallStats* stats) { + belle_sip_object_unref(stats); +} + +void *linphone_call_stats_get_user_data (const LinphoneCallStats *stats) { + return stats->user_data; +} + +void linphone_call_stats_set_user_data (LinphoneCallStats *stats, void *data) { + stats->user_data = data; +} + +void linphone_call_stats_update (LinphoneCallStats *stats, MediaStream *stream) { + PayloadType *pt; + RtpSession *session = stream->sessions.rtp_session; + const MSQualityIndicator *qi = media_stream_get_quality_indicator(stream); + if (qi) { + stats->local_late_rate=ms_quality_indicator_get_local_late_rate(qi); + stats->local_loss_rate=ms_quality_indicator_get_local_loss_rate(qi); + } + media_stream_get_local_rtp_stats(stream, &stats->rtp_stats); + pt = rtp_profile_get_payload(rtp_session_get_profile(session), rtp_session_get_send_payload_type(session)); + stats->clockrate = pt ? pt->clock_rate : 8000; +} + +/*do not change the prototype of this function, it is also used internally in linphone-daemon.*/ +void linphone_call_stats_fill (LinphoneCallStats *stats, MediaStream *ms, OrtpEvent *ev) { + OrtpEventType evt=ortp_event_get_type(ev); + OrtpEventData *evd=ortp_event_get_data(ev); + + if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { + stats->round_trip_delay = rtp_session_get_round_trip_propagation(ms->sessions.rtp_session); + if(stats->received_rtcp != NULL) + freemsg(stats->received_rtcp); + stats->received_rtcp = evd->packet; + stats->rtcp_received_via_mux = evd->info.socket_type == OrtpRTPSocket; + evd->packet = NULL; + stats->updated = LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE; + linphone_call_stats_update(stats,ms); + } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { + memcpy(&stats->jitter_stats, rtp_session_get_jitter_stats(ms->sessions.rtp_session), sizeof(jitter_stats_t)); + if (stats->sent_rtcp != NULL) + freemsg(stats->sent_rtcp); + stats->sent_rtcp = evd->packet; + evd->packet = NULL; + stats->updated = LINPHONE_CALL_STATS_SENT_RTCP_UPDATE; + linphone_call_stats_update(stats,ms); + } +} + +LinphoneStreamType linphone_call_stats_get_type (const LinphoneCallStats *stats) { + return stats->type; +} + +float linphone_call_stats_get_sender_loss_rate (const LinphoneCallStats *stats) { + const report_block_t *srb = NULL; + + if (!stats || !stats->sent_rtcp) + return 0.0; + /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ + if (stats->sent_rtcp->b_cont != NULL) + msgpullup(stats->sent_rtcp, -1); + + do{ + if (rtcp_is_SR(stats->sent_rtcp)) + srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0); + else if (rtcp_is_RR(stats->sent_rtcp)) + srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0); + if (srb) break; + }while (rtcp_next_packet(stats->sent_rtcp)); + rtcp_rewind(stats->sent_rtcp); + if (!srb) + return 0.0; + return 100.0f * (float)report_block_get_fraction_lost(srb) / 256.0f; +} + +float linphone_call_stats_get_receiver_loss_rate (const LinphoneCallStats *stats) { + const report_block_t *rrb = NULL; + + if (!stats || !stats->received_rtcp) + return 0.0; + /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ + if (stats->received_rtcp->b_cont != NULL) + msgpullup(stats->received_rtcp, -1); + + do{ + if (rtcp_is_RR(stats->received_rtcp)) + rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0); + else if (rtcp_is_SR(stats->received_rtcp)) + rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0); + if (rrb) break; + }while (rtcp_next_packet(stats->received_rtcp)); + rtcp_rewind(stats->received_rtcp); + if (!rrb) + return 0.0; + return 100.0f * (float)report_block_get_fraction_lost(rrb) / 256.0f; +} + +float linphone_call_stats_get_local_loss_rate (const LinphoneCallStats *stats) { + return stats->local_loss_rate; +} + +float linphone_call_stats_get_local_late_rate (const LinphoneCallStats *stats) { + return stats->local_late_rate; +} + +float linphone_call_stats_get_sender_interarrival_jitter (const LinphoneCallStats *stats) { + const report_block_t *srb = NULL; + + if (!stats || !stats->sent_rtcp) + return 0.0; + /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ + if (stats->sent_rtcp->b_cont != NULL) + msgpullup(stats->sent_rtcp, -1); + if (rtcp_is_SR(stats->sent_rtcp)) + srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0); + else if (rtcp_is_RR(stats->sent_rtcp)) + srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0); + if (!srb) + return 0.0; + if (stats->clockrate == 0) + return 0.0; + return (float)report_block_get_interarrival_jitter(srb) / (float)stats->clockrate; +} + +float linphone_call_stats_get_receiver_interarrival_jitter (const LinphoneCallStats *stats) { + const report_block_t *rrb = NULL; + + if (!stats || !stats->received_rtcp) + return 0.0; + /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ + if (stats->received_rtcp->b_cont != NULL) + msgpullup(stats->received_rtcp, -1); + if (rtcp_is_SR(stats->received_rtcp)) + rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0); + else if (rtcp_is_RR(stats->received_rtcp)) + rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0); + if (!rrb) + return 0.0; + if (stats->clockrate == 0) + return 0.0; + return (float)report_block_get_interarrival_jitter(rrb) / (float)stats->clockrate; +} + +const rtp_stats_t *linphone_call_stats_get_rtp_stats (const LinphoneCallStats *stats) { + return &stats->rtp_stats; +} + +uint64_t linphone_call_stats_get_late_packets_cumulative_number (const LinphoneCallStats *stats) { + return linphone_call_stats_get_rtp_stats(stats)->outoftime; +} + +float linphone_call_stats_get_download_bandwidth (const LinphoneCallStats *stats) { + return stats->download_bandwidth; +} + +float linphone_call_stats_get_upload_bandwidth (const LinphoneCallStats *stats) { + return stats->upload_bandwidth; +} + +float linphone_call_stats_get_rtcp_download_bandwidth (const LinphoneCallStats *stats) { + return stats->rtcp_download_bandwidth; +} + +float linphone_call_stats_get_rtcp_upload_bandwidth (const LinphoneCallStats *stats) { + return stats->rtcp_upload_bandwidth; +} + +LinphoneIceState linphone_call_stats_get_ice_state (const LinphoneCallStats *stats) { + return stats->ice_state; +} + +LinphoneUpnpState linphone_call_stats_get_upnp_state (const LinphoneCallStats *stats) { + return stats->upnp_state; +} + +LinphoneAddressFamily linphone_call_stats_get_ip_family_of_remote (const LinphoneCallStats *stats) { + return (LinphoneAddressFamily)stats->rtp_remote_family; +} + +float linphone_call_stats_get_jitter_buffer_size_ms (const LinphoneCallStats *stats) { + return stats->jitter_stats.jitter_buffer_size_ms; +} + +float linphone_call_stats_get_round_trip_delay (const LinphoneCallStats *stats) { + return stats->round_trip_delay; +} diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp new file mode 100644 index 000000000..717dd83e0 --- /dev/null +++ b/src/c-wrapper/api/c-call.cpp @@ -0,0 +1,1212 @@ +/* + * c-call.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "linphone/api/c-call.h" +#include "linphone/api/c-call-cbs.h" +#include "linphone/api/c-call-stats.h" +#include "linphone/wrapper_utils.h" + +#include "c-wrapper/c-wrapper.h" +#include "call/call-p.h" +#include "call/call.h" +#include "conference/params/media-session-params-p.h" + +// ============================================================================= + +#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, Call) +#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, Call) + +using namespace std; + +static void _linphone_call_constructor (LinphoneCall *call); +static void _linphone_call_destructor (LinphoneCall *call); + +L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(Call, Call, + _linphone_call_constructor, _linphone_call_destructor, + bctbx_list_t *callbacks; /* A list of LinphoneCallCbs object */ + LinphoneCallCbs *currentCbs; /* The current LinphoneCallCbs object used to call a callback */ + LinphoneCallParams *currentParamsCache; + LinphoneCallParams *paramsCache; + LinphoneCallParams *remoteParamsCache; + LinphoneAddress *remoteAddressCache; + char *remoteContactCache; + /* TODO: all the fields need to be removed */ + struct _LinphoneCore *core; + LinphoneErrorInfo *ei; + SalMediaDescription *localdesc; + SalMediaDescription *resultdesc; + struct _LinphoneCallLog *log; + SalOp *op; + SalOp *ping_op; + LinphoneCallState transfer_state; /*idle if no transfer*/ + struct _AudioStream *audiostream; /**/ + struct _VideoStream *videostream; + struct _TextStream *textstream; + MSAudioEndpoint *endpoint; /*used for conferencing*/ + char *refer_to; + LinphoneCallParams *params; + LinphoneCallParams *current_params; + LinphoneCallParams *remote_params; + LinphoneCallStats *audio_stats; + LinphoneCallStats *video_stats; + LinphoneCallStats *text_stats; + LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/ + LinphoneCall *transfer_target;/*if this call received a transfer request, then transfer_target points to the new call created to the refer target */ + LinphonePlayer *player; + char *dtmf_sequence; /*DTMF sequence needed to be sent using #dtmfs_timer*/ + belle_sip_source_t *dtmfs_timer; /*DTMF timer needed to send a DTMF sequence*/ + LinphoneChatRoom *chat_room; + LinphoneConference *conf_ref; /**> Point on the associated conference if this call is part of a conference. NULL instead. */ + bool_t refer_pending; + bool_t defer_update; + bool_t was_automatically_paused; + bool_t paused_by_app; + bool_t broken; /*set to TRUE when the call is in broken state due to network disconnection or transport */ + bool_t need_localip_refresh; + bool_t reinvite_on_cancel_response_requested; + bool_t non_op_error; /*set when the LinphoneErrorInfo was set at higher level than sal*/ +) + +static void _linphone_call_constructor (LinphoneCall *call) { +} + +static void _linphone_call_destructor (LinphoneCall *call) { + if (call->currentParamsCache) { + linphone_call_params_unref(call->currentParamsCache); + call->currentParamsCache = nullptr; + } + if (call->paramsCache) { + linphone_call_params_unref(call->paramsCache); + call->paramsCache = nullptr; + } + if (call->remoteParamsCache) { + linphone_call_params_unref(call->remoteParamsCache); + call->remoteParamsCache = nullptr; + } + if (call->remoteAddressCache) { + linphone_address_unref(call->remoteAddressCache); + call->remoteAddressCache = nullptr; + } + bctbx_list_free_with_data(call->callbacks, (bctbx_list_free_func)linphone_call_cbs_unref); + if (call->audio_stats) { + linphone_call_stats_unref(call->audio_stats); + call->audio_stats = nullptr; + } + if (call->video_stats) { + linphone_call_stats_unref(call->video_stats); + call->video_stats = nullptr; + } + if (call->text_stats) { + linphone_call_stats_unref(call->text_stats); + call->text_stats = nullptr; + } + if (call->op) { + sal_op_release(call->op); + call->op=nullptr; + } + if (call->resultdesc) { + sal_media_description_unref(call->resultdesc); + call->resultdesc=nullptr; + } + if (call->localdesc) { + sal_media_description_unref(call->localdesc); + call->localdesc=nullptr; + } + if (call->ping_op) { + sal_op_release(call->ping_op); + call->ping_op=nullptr; + } + if (call->refer_to){ + ms_free(call->refer_to); + call->refer_to=nullptr; + } + if (call->referer){ + linphone_call_unref(call->referer); + call->referer=nullptr; + } + if (call->transfer_target){ + linphone_call_unref(call->transfer_target); + call->transfer_target=nullptr; + } + if (call->log) { + linphone_call_log_unref(call->log); + call->log=nullptr; + } + if (call->dtmfs_timer) { + linphone_call_cancel_dtmfs(call); + } + if (call->params){ + linphone_call_params_unref(call->params); + call->params=nullptr; + } + if (call->current_params){ + linphone_call_params_unref(call->current_params); + call->current_params=nullptr; + } + if (call->remote_params) { + linphone_call_params_unref(call->remote_params); + call->remote_params=nullptr; + } + if (call->ei) linphone_error_info_unref(call->ei); +} + + +// ============================================================================= +// TODO: To remove! +// ============================================================================= + +MSWebCam *get_nowebcam_device (MSFactory* f) { +#ifdef VIDEO_ENABLED + return ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(f),"StaticImage: Static picture"); +#else + return nullptr; +#endif +} + +void linphone_call_update_local_media_description_from_ice_or_upnp (LinphoneCall *call) {} + +void linphone_call_make_local_media_description (LinphoneCall *call) {} + +void linphone_call_create_op (LinphoneCall *call) { +#if 0 + if (call->op) sal_op_release(call->op); + call->op=sal_op_new(call->core->sal); + sal_op_set_user_pointer(call->op,call); + if (linphone_call_params_get_referer(call->params)) + sal_call_set_referer(call->op,linphone_call_params_get_referer(call->params)->op); + linphone_configure_op(call->core,call->op,call->log->to,linphone_call_params_get_custom_headers(call->params),FALSE); + if (linphone_call_params_get_privacy(call->params) != LinphonePrivacyDefault) + sal_op_set_privacy(call->op,(SalPrivacyMask)linphone_call_params_get_privacy(call->params)); + /*else privacy might be set by proxy */ +#endif +} + +void linphone_call_set_state (LinphoneCall *call, LinphoneCallState cstate, const char *message) {} + +void linphone_call_init_media_streams (LinphoneCall *call) {} + +#if 0 +static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'}; + +static void linphone_core_dtmf_received (LinphoneCall *call, int dtmf) { + if (dtmf<0 || dtmf>15){ + ms_warning("Bad dtmf value %i",dtmf); + return; + } + linphone_call_notify_dtmf_received(call, dtmf_tab[dtmf]); +} +#endif + +/*This function is not static because used internally in linphone-daemon project*/ +void _post_configure_audio_stream (AudioStream *st, LinphoneCore *lc, bool_t muted) {} + +#if 0 +static void setup_ring_player (LinphoneCore *lc, LinphoneCall *call) { + int pause_time=3000; + audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone); + ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time); +} +#endif + +#if 0 +static bool_t linphone_call_sound_resources_available (LinphoneCall *call) { + LinphoneCore *lc=call->core; + LinphoneCall *current=linphone_core_get_current_call(lc); + return !linphone_core_is_in_conference(lc) && + (current==nullptr || current==call); +} +#endif + +void linphone_call_delete_upnp_session (LinphoneCall *call) {} + +void linphone_call_stop_media_streams (LinphoneCall *call) {} + +#if 0 +static void linphone_call_lost (LinphoneCall *call) { + LinphoneCore *lc = call->core; + char *temp = nullptr; + char *from = nullptr; + + from = linphone_call_get_remote_address_as_string(call); + temp = ms_strdup_printf("Media connectivity with %s is lost, call is going to be closed.", from ? from : "?"); + if (from) ms_free(from); + ms_message("LinphoneCall [%p]: %s", call, temp); + linphone_core_notify_display_warning(lc, temp); + call->non_op_error = TRUE; + linphone_error_info_set(call->ei,nullptr, LinphoneReasonIOError, 503, "Media lost", nullptr); + linphone_call_terminate(call); + linphone_core_play_named_tone(lc, LinphoneToneCallLost); + ms_free(temp); +} +#endif + +void linphone_call_set_transfer_state (LinphoneCall *call, LinphoneCallState state) { +#if 0 + if (state != call->transfer_state) { + ms_message("Transfer state for call [%p] changed from [%s] to [%s]",call + ,linphone_call_state_to_string(call->transfer_state) + ,linphone_call_state_to_string(state)); + call->transfer_state = state; + linphone_call_notify_transfer_state_changed(call, state); + } +#endif +} + +void _linphone_call_set_new_params (LinphoneCall *call, const LinphoneCallParams *params) {} + +#if 0 +static int send_dtmf_handler (void *data, unsigned int revents) { + LinphoneCall *call = (LinphoneCall*)data; + /*By default we send DTMF RFC2833 if we do not have enabled SIP_INFO but we can also send RFC2833 and SIP_INFO*/ + if (linphone_core_get_use_rfc2833_for_dtmf(call->core)!=0 || linphone_core_get_use_info_for_dtmf(call->core)==0) + { + /* In Band DTMF */ + if (call->audiostream){ + audio_stream_send_dtmf(call->audiostream,*call->dtmf_sequence); + } + else + { + ms_error("Cannot send RFC2833 DTMF when we are not in communication."); + return FALSE; + } + } + if (linphone_core_get_use_info_for_dtmf(call->core)!=0){ + /* Out of Band DTMF (use INFO method) */ + sal_call_send_dtmf(call->op,*call->dtmf_sequence); + } + + /*this check is needed because linphone_call_send_dtmf does not set the timer since its a single character*/ + if (call->dtmfs_timer) { + memmove(call->dtmf_sequence, call->dtmf_sequence+1, strlen(call->dtmf_sequence)); + } + /* continue only if the dtmf sequence is not empty*/ + if (call->dtmf_sequence && *call->dtmf_sequence!='\0') { + return TRUE; + } else { + linphone_call_cancel_dtmfs(call); + return FALSE; + } +} +#endif + +/* Internal version that does not play tone indication*/ +int _linphone_call_pause (LinphoneCall *call) { + return 0; +} + +#if 0 +static void terminate_call (LinphoneCall *call) {} +#endif + +int linphone_call_start_update (LinphoneCall *call) { + return 0; +} + +int linphone_call_start_accept_update (LinphoneCall *call, LinphoneCallState next_state, const char *state_info) { + return 0; +} + +int linphone_call_proceed_with_invite_if_ready (LinphoneCall *call, LinphoneProxyConfig *dest_proxy) { + return 0; +} + +int linphone_call_start_invite (LinphoneCall *call, const LinphoneAddress *destination /* = NULL if to be taken from the call log */) { + return 0; +} + +void linphone_call_replace_op (LinphoneCall *call, SalOp *op) { +#if 0 + SalOp *oldop = call->op; + LinphoneCallState oldstate = linphone_call_get_state(call); + call->op = op; + sal_op_set_user_pointer(call->op, call); + sal_call_set_local_media_description(call->op, call->localdesc); + switch (linphone_call_get_state(call)) { + case LinphoneCallIncomingEarlyMedia: + case LinphoneCallIncomingReceived: + sal_call_notify_ringing(call->op, (linphone_call_get_state(call) == LinphoneCallIncomingEarlyMedia) ? TRUE : FALSE); + break; + case LinphoneCallConnected: + case LinphoneCallStreamsRunning: + sal_call_accept(call->op); + break; + default: + ms_warning("linphone_call_replace_op(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state)); + break; + } + switch (oldstate) { + case LinphoneCallIncomingEarlyMedia: + case LinphoneCallIncomingReceived: + sal_op_set_user_pointer(oldop, nullptr); /* To make the call does not get terminated by terminating this op. */ + /* Do not terminate a forked INVITE */ + if (sal_call_get_replaces(op)) { + sal_call_terminate(oldop); + } else { + sal_op_kill_dialog(oldop); + } + break; + case LinphoneCallConnected: + case LinphoneCallStreamsRunning: + sal_call_terminate(oldop); + sal_op_kill_dialog(oldop); + break; + default: + break; + } + sal_op_release(oldop); +#endif +} + + +// ============================================================================= +// Private functions. +// ============================================================================= + +#if 0 +static void linphone_call_repair_by_invite_with_replaces (LinphoneCall *call) { + const char *call_id = sal_op_get_call_id(call->op); + const char *from_tag = sal_call_get_local_tag(call->op); + const char *to_tag = sal_call_get_remote_tag(call->op); + sal_op_kill_dialog(call->op); + linphone_call_create_op(call); + sal_call_set_replaces(call->op, call_id, from_tag, to_tag); + linphone_call_start_invite(call, nullptr); +} +#endif + +MediaStream *linphone_call_get_stream (LinphoneCall *call, LinphoneStreamType type) { + return GET_CPP_PRIVATE_PTR(call)->getMediaStream(type); +} + +void linphone_call_set_broken (LinphoneCall *call) { +#if 0 + switch(call->state){ + /*for all the early states, we prefer to drop the call*/ + case LinphoneCallOutgoingInit: + case LinphoneCallOutgoingProgress: + case LinphoneCallOutgoingRinging: + case LinphoneCallOutgoingEarlyMedia: + case LinphoneCallIncomingReceived: + case LinphoneCallIncomingEarlyMedia: + /*during the early states, the SAL layer reports the failure from the dialog or transaction layer, + * hence, there is nothing special to do*/ + //break; + case LinphoneCallStreamsRunning: + case LinphoneCallUpdating: + case LinphoneCallPausing: + case LinphoneCallResuming: + case LinphoneCallPaused: + case LinphoneCallPausedByRemote: + case LinphoneCallUpdatedByRemote: + /*during these states, the dialog is established. A failure of a transaction is not expected to close it. + * Instead we have to repair the dialog by sending a reINVITE*/ + call->broken = TRUE; + call->need_localip_refresh = TRUE; + break; + default: + ms_error("linphone_call_set_broken() unimplemented case."); + break; + } +#endif +} + +void linphone_call_reinvite_to_recover_from_connection_loss (LinphoneCall *call) { +#if 0 + LinphoneCallParams *params; + ms_message("LinphoneCall[%p] is going to be updated (reINVITE) in order to recover from lost connectivity", call); + if (call->ice_session){ + ice_session_reset(call->ice_session, IR_Controlling); + } + params = linphone_core_create_call_params(call->core, call); + linphone_call_update(call, params); + linphone_call_params_unref(params); +#endif +} + +void linphone_call_repair_if_broken (LinphoneCall *call) { +#if 0 + SalErrorInfo sei; + if (!call->broken) return; + if (!call->core->media_network_reachable) return; + + memset(&sei, 0, sizeof(sei)); + + /*Make sure that the proxy from which we received this call, or to which we routed this call is registered first*/ + if (call->dest_proxy){ + /*in all other cases, ie no proxy config, or a proxy config for which no registration was requested, we can start the + * call repair immediately.*/ + if (linphone_proxy_config_register_enabled(call->dest_proxy) + && linphone_proxy_config_get_state(call->dest_proxy) != LinphoneRegistrationOk) return; + } + + switch (call->state){ + case LinphoneCallUpdating: + case LinphoneCallPausing: + if (sal_call_dialog_request_pending(call->op)) { + /* Need to cancel first re-INVITE as described in section 5.5 of RFC 6141 */ + sal_call_cancel_invite(call->op); + call->reinvite_on_cancel_response_requested = TRUE; + } + break; + case LinphoneCallStreamsRunning: + case LinphoneCallPaused: + case LinphoneCallPausedByRemote: + if (!sal_call_dialog_request_pending(call->op)) { + linphone_call_reinvite_to_recover_from_connection_loss(call); + } + break; + case LinphoneCallUpdatedByRemote: + if (sal_call_dialog_request_pending(call->op)) { + sal_error_info_set(&sei, SalReasonServiceUnavailable,"SIP", 0, nullptr, nullptr); + sal_call_decline_with_error_info(call->op, &sei,nullptr); + } + linphone_call_reinvite_to_recover_from_connection_loss(call); + break; + case LinphoneCallOutgoingInit: + case LinphoneCallOutgoingProgress: + sal_call_cancel_invite(call->op); + call->reinvite_on_cancel_response_requested = TRUE; + break; + case LinphoneCallOutgoingEarlyMedia: + case LinphoneCallOutgoingRinging: + linphone_call_repair_by_invite_with_replaces(call); + break; + case LinphoneCallIncomingEarlyMedia: + case LinphoneCallIncomingReceived: + /* Keep the call broken until a forked INVITE is received from the server. */ + break; + default: + ms_warning("linphone_call_repair_if_broken(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state)); + call->broken = FALSE; + break; + } + sal_error_info_reset(&sei); +#endif +} + +void linphone_call_refresh_sockets (LinphoneCall *call) { +#if 0 + int i; + for (i=0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i){ + MSMediaStreamSessions *mss = &call->sessions[i]; + if (mss->rtp_session){ + rtp_session_refresh_sockets(mss->rtp_session); + } + } +#endif +} + +SalOp * linphone_call_get_op (const LinphoneCall *call) { + return GET_CPP_PRIVATE_PTR(call)->getOp(); +} + +LinphoneProxyConfig * linphone_call_get_dest_proxy (const LinphoneCall *call) { + return GET_CPP_PRIVATE_PTR(call)->getDestProxy(); +} + +LinphoneCallLog * linphone_call_get_log (const LinphoneCall *call) { + return linphone_call_get_call_log(call); +} + +IceSession * linphone_call_get_ice_session (const LinphoneCall *call) { + return GET_CPP_PRIVATE_PTR(call)->getIceSession(); +} + +bool_t linphone_call_get_audio_muted (const LinphoneCall *call) { + return GET_CPP_PRIVATE_PTR(call)->getAudioMuted(); +} + +void linphone_call_set_audio_muted (LinphoneCall *call, bool_t value) { + GET_CPP_PRIVATE_PTR(call)->setAudioMuted(value); +} + +bool_t linphone_call_get_all_muted (const LinphoneCall *call) { + return GET_CPP_PTR(call)->getAllMuted(); +} + +#define NOTIFY_IF_EXIST(cbName, functionName, ...) \ + for (bctbx_list_t *it = call->callbacks; it; it = bctbx_list_next(it)) { \ + call->currentCbs = reinterpret_cast(bctbx_list_get_data(it)); \ + LinphoneCallCbs ## cbName ## Cb cb = linphone_call_cbs_get_ ## functionName (call->currentCbs); \ + if (cb) \ + cb(__VA_ARGS__); \ + } + +void linphone_call_notify_state_changed (LinphoneCall *call, LinphoneCallState cstate, const char *message) { + NOTIFY_IF_EXIST(StateChanged, state_changed, call, cstate, message) + linphone_core_notify_call_state_changed(linphone_call_get_core(call), call, cstate, message); +} + +void linphone_call_notify_dtmf_received (LinphoneCall *call, int dtmf) { + NOTIFY_IF_EXIST(DtmfReceived, dtmf_received, call, dtmf) + linphone_core_notify_dtmf_received(linphone_call_get_core(call), call, dtmf); +} + +void linphone_call_notify_encryption_changed (LinphoneCall *call, bool_t on, const char *authentication_token) { + NOTIFY_IF_EXIST(EncryptionChanged, encryption_changed, call, on, authentication_token) + linphone_core_notify_call_encryption_changed(linphone_call_get_core(call), call, on, authentication_token); +} + +void linphone_call_notify_transfer_state_changed (LinphoneCall *call, LinphoneCallState cstate) { + NOTIFY_IF_EXIST(TransferStateChanged, transfer_state_changed, call, cstate) + linphone_core_notify_transfer_state_changed(linphone_call_get_core(call), call, cstate); +} + +void linphone_call_notify_stats_updated (LinphoneCall *call, const LinphoneCallStats *stats) { + NOTIFY_IF_EXIST(StatsUpdated, stats_updated, call, stats) + linphone_core_notify_call_stats_updated(linphone_call_get_core(call), call, stats); +} + +void linphone_call_notify_info_message_received (LinphoneCall *call, const LinphoneInfoMessage *msg) { + NOTIFY_IF_EXIST(InfoMessageReceived, info_message_received, call, msg) + linphone_core_notify_info_received(linphone_call_get_core(call), call, msg); +} + +void linphone_call_notify_ack_processing (LinphoneCall *call, LinphoneHeaders *msg, bool_t is_received) { + NOTIFY_IF_EXIST(AckProcessing, ack_processing, call, msg, is_received) +} + + +// ============================================================================= +// Public functions. +// ============================================================================= + +LinphoneCore *linphone_call_get_core (const LinphoneCall *call) { + return GET_CPP_PTR(call)->getCore(); +} + +LinphoneCallState linphone_call_get_state (const LinphoneCall *call) { + return GET_CPP_PTR(call)->getState(); +} + +bool_t linphone_call_asked_to_autoanswer (LinphoneCall *call) { + //return TRUE if the unique(for the moment) incoming call asked to be autoanswered + if (call) + return sal_call_autoanswer_asked(linphone_call_get_op(call)); + return FALSE; +} + +const LinphoneAddress *linphone_call_get_remote_address (const LinphoneCall *call) { + L_SET_CPP_PTR_FROM_C_STRUCT(call->remoteAddressCache, &GET_CPP_PTR(call)->getRemoteAddress()); + return call->remoteAddressCache; +} + +const LinphoneAddress *linphone_call_get_to_address (const LinphoneCall *call){ +#if 0 + return (const LinphoneAddress *)sal_op_get_to_address(call->op); +#else + return nullptr; +#endif +} + +const char *linphone_call_get_to_header (const LinphoneCall *call, const char *name) { +#if 0 + return sal_custom_header_find(sal_op_get_recv_custom_header(call->op),name); +#else + return nullptr; +#endif +} + +char *linphone_call_get_remote_address_as_string (const LinphoneCall *call) { + return ms_strdup(GET_CPP_PTR(call)->getRemoteAddressAsString().c_str()); +} + +const LinphoneAddress *linphone_call_get_diversion_address (const LinphoneCall *call) { +#if 0 + return call->op?(const LinphoneAddress *)sal_op_get_diversion_address(call->op):nullptr; +#else + return nullptr; +#endif +} + +LinphoneCallDir linphone_call_get_dir (const LinphoneCall *call) { + return linphone_call_log_get_dir(linphone_call_get_log(call)); +} + +LinphoneCallLog *linphone_call_get_call_log (const LinphoneCall *call) { + return GET_CPP_PTR(call)->getLog(); +} + +const char *linphone_call_get_refer_to (const LinphoneCall *call) { +#if 0 + return call->refer_to; +#else + return nullptr; +#endif +} + +bool_t linphone_call_has_transfer_pending (const LinphoneCall *call) { +#if 0 + return call->refer_pending; +#else + return FALSE; +#endif +} + +LinphoneCall *linphone_call_get_transferer_call (const LinphoneCall *call) { +#if 0 + return call->referer; +#else + return nullptr; +#endif +} + +LinphoneCall *linphone_call_get_transfer_target_call (const LinphoneCall *call) { +#if 0 + return call->transfer_target; +#else + return nullptr; +#endif +} + +LinphoneCall *linphone_call_get_replaced_call (LinphoneCall *call) { +#if 0 + SalOp *op=sal_call_get_replaces(call->op); + if (op){ + return (LinphoneCall*)sal_op_get_user_pointer(op); + } + return nullptr; +#else + return nullptr; +#endif +} + +int linphone_call_get_duration (const LinphoneCall *call) { + return GET_CPP_PTR(call)->getDuration(); +} + +const LinphoneCallParams *linphone_call_get_current_params(LinphoneCall *call) { + L_SET_CPP_PTR_FROM_C_STRUCT(call->currentParamsCache, GET_CPP_PTR(call)->getCurrentParams()); + return call->currentParamsCache; +} + +const LinphoneCallParams *linphone_call_get_remote_params(LinphoneCall *call) { + const LinphonePrivate::MediaSessionParams *remoteParams = GET_CPP_PTR(call)->getRemoteParams(); + if (!remoteParams) + return nullptr; + L_SET_CPP_PTR_FROM_C_STRUCT(call->remoteParamsCache, remoteParams); + return call->remoteParamsCache; +} + +void linphone_call_enable_camera (LinphoneCall *call, bool_t enable) { + GET_CPP_PTR(call)->enableCamera(enable); +} + +bool_t linphone_call_camera_enabled (const LinphoneCall *call) { + return GET_CPP_PTR(call)->cameraEnabled(); +} + +LinphoneStatus linphone_call_take_video_snapshot (LinphoneCall *call, const char *file) { + return GET_CPP_PTR(call)->takeVideoSnapshot(file ? file : ""); +} + +LinphoneStatus linphone_call_take_preview_snapshot (LinphoneCall *call, const char *file) { + return GET_CPP_PTR(call)->takePreviewSnapshot(file ? file : ""); +} + +LinphoneReason linphone_call_get_reason (const LinphoneCall *call) { + return GET_CPP_PTR(call)->getReason(); +} + +const LinphoneErrorInfo *linphone_call_get_error_info (const LinphoneCall *call) { + return GET_CPP_PTR(call)->getErrorInfo(); +} + +const char *linphone_call_get_remote_user_agent (LinphoneCall *call) { +#if 0 + if (call->op){ + return sal_op_get_remote_ua (call->op); + } + return nullptr; +#else + return nullptr; +#endif +} + +const char * linphone_call_get_remote_contact (LinphoneCall *call) { + std::string contact = GET_CPP_PTR(call)->getRemoteContact(); + if (contact.empty()) + return nullptr; + if (call->remoteContactCache) + bctbx_free(call->remoteContactCache); + call->remoteContactCache = bctbx_strdup(contact.c_str()); + return call->remoteContactCache; +} + +const char *linphone_call_get_authentication_token (LinphoneCall *call) { + std::string token = GET_CPP_PTR(call)->getAuthenticationToken(); + return token.empty() ? nullptr : token.c_str(); +} + +bool_t linphone_call_get_authentication_token_verified (const LinphoneCall *call) { + return GET_CPP_PTR(call)->getAuthenticationTokenVerified(); +} + +void linphone_call_set_authentication_token_verified (LinphoneCall *call, bool_t verified) { + GET_CPP_PTR(call)->setAuthenticationTokenVerified(verified); +} + +void linphone_call_send_vfu_request (LinphoneCall *call) { + GET_CPP_PTR(call)->sendVfuRequest(); +} + +void linphone_call_set_next_video_frame_decoded_callback (LinphoneCall *call, LinphoneCallCbFunc cb, void *ud) { + GET_CPP_PTR(call)->setNextVideoFrameDecodedCallback(cb, ud); +} + +LinphoneCallState linphone_call_get_transfer_state (LinphoneCall *call) { +#if 0 + return call->transfer_state; +#else + return LinphoneCallIdle; +#endif +} + +void linphone_call_zoom_video (LinphoneCall* call, float zoom_factor, float* cx, float* cy) { + GET_CPP_PTR(call)->zoomVideo(zoom_factor, cx, cy); +} + +LinphoneStatus linphone_call_send_dtmf (LinphoneCall *call, char dtmf) { +#if 0 + if (!call){ + ms_warning("linphone_call_send_dtmf(): invalid call, canceling DTMF."); + return -1; + } + call->dtmf_sequence = &dtmf; + send_dtmf_handler(call,0); + call->dtmf_sequence = nullptr; + return 0; +#else + return 0; +#endif +} + +LinphoneStatus linphone_call_send_dtmfs (LinphoneCall *call, const char *dtmfs) { +#if 0 + if (!call){ + ms_warning("linphone_call_send_dtmfs(): invalid call, canceling DTMF sequence."); + return -1; + } + if (call->dtmfs_timer){ + ms_warning("linphone_call_send_dtmfs(): a DTMF sequence is already in place, canceling DTMF sequence."); + return -2; + } + if (dtmfs) { + int delay_ms = lp_config_get_int(call->core->config,"net","dtmf_delay_ms",200); + call->dtmf_sequence = ms_strdup(dtmfs); + call->dtmfs_timer = sal_create_timer(call->core->sal, send_dtmf_handler, call, delay_ms, "DTMF sequence timer"); + } + return 0; +#else + return 0; +#endif +} + +void linphone_call_cancel_dtmfs (LinphoneCall *call) { +#if 0 + /*nothing to do*/ + if (!call || !call->dtmfs_timer) return; + + sal_cancel_timer(call->core->sal, call->dtmfs_timer); + belle_sip_object_unref(call->dtmfs_timer); + call->dtmfs_timer = nullptr; + if (call->dtmf_sequence) { + ms_free(call->dtmf_sequence); + call->dtmf_sequence = nullptr; + } +#endif +} + +bool_t linphone_call_is_in_conference (const LinphoneCall *call) { +#if 0 + return linphone_call_params_get_in_conference(call->params); +#else + return FALSE; +#endif +} + +LinphoneConference *linphone_call_get_conference (const LinphoneCall *call) { +#if 0 + return call->conf_ref; +#else + return nullptr; +#endif +} + +void linphone_call_set_audio_route (LinphoneCall *call, LinphoneAudioRoute route) { +#if 0 + if (call && call->audiostream){ + audio_stream_set_audio_route(call->audiostream, (MSAudioRoute) route); + } +#endif +} + +int linphone_call_get_stream_count (const LinphoneCall *call) { + return GET_CPP_PTR(call)->getStreamCount(); +} + +MSFormatType linphone_call_get_stream_type (const LinphoneCall *call, int stream_index) { + return GET_CPP_PTR(call)->getStreamType(stream_index); +} + +RtpTransport *linphone_call_get_meta_rtp_transport (const LinphoneCall *call, int stream_index) { + return GET_CPP_PTR(call)->getMetaRtpTransport(stream_index); +} + +RtpTransport *linphone_call_get_meta_rtcp_transport (const LinphoneCall *call, int stream_index) { + return GET_CPP_PTR(call)->getMetaRtcpTransport(stream_index); +} + +LinphoneStatus linphone_call_pause (LinphoneCall *call) { + return GET_CPP_PTR(call)->pause(); +} + +LinphoneStatus linphone_call_resume (LinphoneCall *call) { + return GET_CPP_PTR(call)->resume(); +} + +LinphoneStatus linphone_call_terminate (LinphoneCall *call) { + return GET_CPP_PTR(call)->terminate(); +} + +LinphoneStatus linphone_call_terminate_with_error_info (LinphoneCall *call , const LinphoneErrorInfo *ei) { + return GET_CPP_PTR(call)->terminate(ei); +} + +LinphoneStatus linphone_call_redirect (LinphoneCall *call, const char *redirect_uri) { +#if 0 + char *real_url = nullptr; + LinphoneCore *lc; + LinphoneAddress *real_parsed_url; + SalErrorInfo sei; + + if (call->state != LinphoneCallIncomingReceived) { + ms_error("Bad state for call redirection."); + return -1; + } + + lc = linphone_call_get_core(call); + real_parsed_url = linphone_core_interpret_url(lc, redirect_uri); + if (!real_parsed_url) { + /* Bad url */ + ms_error("Bad redirect URI: %s", redirect_uri ? redirect_uri : "NULL"); + return -1; + } + + memset(&sei, 0, sizeof(sei)); + real_url = linphone_address_as_string(real_parsed_url); + sal_error_info_set(&sei,SalReasonRedirect, "SIP", 0, nullptr, nullptr); + sal_call_decline_with_error_info(call->op, &sei, real_url); + ms_free(real_url); + linphone_error_info_set(call->ei, nullptr, LinphoneReasonMovedPermanently, 302, "Call redirected", nullptr); + call->non_op_error = TRUE; + terminate_call(call); + linphone_address_unref(real_parsed_url); + sal_error_info_reset(&sei); + return 0; +#else + return 0; +#endif +} + +LinphoneStatus linphone_call_decline (LinphoneCall *call, LinphoneReason reason) { + return GET_CPP_PTR(call)->decline(reason); +} + +LinphoneStatus linphone_call_decline_with_error_info (LinphoneCall *call, const LinphoneErrorInfo *ei) { + return GET_CPP_PTR(call)->decline(ei); +} + +LinphoneStatus linphone_call_accept (LinphoneCall *call) { + return GET_CPP_PTR(call)->accept(nullptr); +} + +LinphoneStatus linphone_call_accept_with_params (LinphoneCall *call, const LinphoneCallParams *params) { + return GET_CPP_PTR(call)->accept(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams) : nullptr); +} + +LinphoneStatus linphone_call_accept_early_media (LinphoneCall* call) { + return GET_CPP_PTR(call)->acceptEarlyMedia(); +} + +LinphoneStatus linphone_call_accept_early_media_with_params (LinphoneCall *call, const LinphoneCallParams *params) { + return GET_CPP_PTR(call)->acceptEarlyMedia(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams) : nullptr); +} + +LinphoneStatus linphone_call_update (LinphoneCall *call, const LinphoneCallParams *params) { + return GET_CPP_PTR(call)->update(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams) : nullptr); +} + +LinphoneStatus linphone_call_defer_update (LinphoneCall *call) { +#if 0 + if (call->state != LinphoneCallUpdatedByRemote) { + ms_error("linphone_call_defer_update() not done in state LinphoneCallUpdatedByRemote"); + return -1; + } + + if (call->expect_media_in_ack) { + ms_error("linphone_call_defer_update() is not possible during a late offer incoming reINVITE (INVITE without SDP)"); + return -1; + } + + call->defer_update=TRUE; + return 0; +#else + return 0; +#endif +} + +LinphoneStatus linphone_call_accept_update (LinphoneCall *call, const LinphoneCallParams *params) { + return GET_CPP_PTR(call)->acceptUpdate(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams) : nullptr); +} + +LinphoneStatus linphone_call_transfer (LinphoneCall *call, const char *refer_to) { +#if 0 + char *real_url = nullptr; + LinphoneCore *lc = linphone_call_get_core(call); + LinphoneAddress *real_parsed_url = linphone_core_interpret_url(lc, refer_to); + + if (!real_parsed_url) { + /* bad url */ + return -1; + } + //lc->call = nullptr; // Do not do that you will lose the call afterward... + real_url = linphone_address_as_string(real_parsed_url); + sal_call_refer(call->op, real_url); + ms_free(real_url); + linphone_address_unref(real_parsed_url); + linphone_call_set_transfer_state(call, LinphoneCallOutgoingInit); + return 0; +#else + return 0; +#endif +} + +LinphoneStatus linphone_call_transfer_to_another (LinphoneCall *call, LinphoneCall *dest) { +#if 0 + int result = sal_call_refer_with_replaces (call->op, dest->op); + linphone_call_set_transfer_state(call, LinphoneCallOutgoingInit); + return result; +#else + return 0; +#endif +} + +void *linphone_call_get_native_video_window_id (const LinphoneCall *call) { + return GET_CPP_PTR(call)->getNativeVideoWindowId(); +} + +void linphone_call_set_native_video_window_id (LinphoneCall *call, void *id) { + GET_CPP_PTR(call)->setNativeVideoWindowId(id); +} + +void linphone_call_enable_echo_cancellation (LinphoneCall *call, bool_t enable) { + GET_CPP_PTR(call)->enableEchoCancellation(enable); +} + +bool_t linphone_call_echo_cancellation_enabled (const LinphoneCall *call) { + return GET_CPP_PTR(call)->echoCancellationEnabled(); +} + +void linphone_call_enable_echo_limiter (LinphoneCall *call, bool_t val) { + GET_CPP_PTR(call)->enableEchoLimiter(val); +} + +bool_t linphone_call_echo_limiter_enabled (const LinphoneCall *call) { + return GET_CPP_PTR(call)->echoLimiterEnabled(); +} + +LinphoneChatRoom *linphone_call_get_chat_room (LinphoneCall *call) { +#if 0 + if (!call->chat_room){ + if (call->state != LinphoneCallReleased && call->state != LinphoneCallEnd){ + call->chat_room = _linphone_core_create_chat_room_from_call(call); + } + } + return call->chat_room; +#else + return nullptr; +#endif +} + +float linphone_call_get_play_volume (const LinphoneCall *call) { + return GET_CPP_PTR(call)->getPlayVolume(); +} + +float linphone_call_get_record_volume (const LinphoneCall *call) { + return GET_CPP_PTR(call)->getRecordVolume(); +} + +float linphone_call_get_speaker_volume_gain (const LinphoneCall *call) { + return GET_CPP_PTR(call)->getSpeakerVolumeGain(); +} + +void linphone_call_set_speaker_volume_gain( LinphoneCall *call, float volume) { + GET_CPP_PTR(call)->setSpeakerVolumeGain(volume); +} + +float linphone_call_get_microphone_volume_gain (const LinphoneCall *call) { + return GET_CPP_PTR(call)->getMicrophoneVolumeGain(); +} + +void linphone_call_set_microphone_volume_gain (LinphoneCall *call, float volume) { + GET_CPP_PTR(call)->setMicrophoneVolumeGain(volume); +} + +float linphone_call_get_current_quality (const LinphoneCall *call) { + return GET_CPP_PTR(call)->getCurrentQuality(); +} + +float linphone_call_get_average_quality (const LinphoneCall *call) { + return GET_CPP_PTR(call)->getAverageQuality(); +} + +void linphone_call_start_recording (LinphoneCall *call) { + GET_CPP_PTR(call)->startRecording(); +} + +void linphone_call_stop_recording (LinphoneCall *call) { + GET_CPP_PTR(call)->stopRecording(); +} + +LinphonePlayer *linphone_call_get_player (LinphoneCall *call) { +#if 0 + if (!call->player) + call->player=linphone_call_build_player(call); + return call->player; +#else + return nullptr; +#endif +} + +bool_t linphone_call_media_in_progress (const LinphoneCall *call) { + return GET_CPP_PTR(call)->mediaInProgress(); +} + +void linphone_call_ogl_render (const LinphoneCall *call) { +#if 0 + #ifdef VIDEO_ENABLED + + VideoStream *stream = call->videostream; + if (stream && stream->output && ms_filter_get_id(stream->output) == MS_OGL_ID) + ms_filter_call_method(stream->output, MS_OGL_RENDER, nullptr); + + #endif +#endif +} + +LinphoneStatus linphone_call_send_info_message (LinphoneCall *call, const LinphoneInfoMessage *info) { + SalBodyHandler *body_handler = sal_body_handler_from_content(linphone_info_message_get_content(info)); + sal_op_set_sent_custom_header(linphone_call_get_op(call), linphone_info_message_get_headers(info)); + return sal_send_info(linphone_call_get_op(call), nullptr, nullptr, body_handler); +} + +LinphoneCallStats *linphone_call_get_stats (LinphoneCall *call, LinphoneStreamType type) { + return GET_CPP_PTR(call)->getStats(type); +} + +LinphoneCallStats *linphone_call_get_audio_stats (LinphoneCall *call) { + return GET_CPP_PTR(call)->getAudioStats(); +} + +LinphoneCallStats *linphone_call_get_video_stats (LinphoneCall *call) { + return GET_CPP_PTR(call)->getVideoStats(); +} + +LinphoneCallStats *linphone_call_get_text_stats (LinphoneCall *call) { + return GET_CPP_PTR(call)->getTextStats(); +} + +void linphone_call_add_callbacks (LinphoneCall *call, LinphoneCallCbs *cbs) { + call->callbacks = bctbx_list_append(call->callbacks, linphone_call_cbs_ref(cbs)); +} + +void linphone_call_remove_callbacks (LinphoneCall *call, LinphoneCallCbs *cbs) { + call->callbacks = bctbx_list_remove(call->callbacks, cbs); + linphone_call_cbs_unref(cbs); +} + +LinphoneCallCbs *linphone_call_get_current_callbacks (const LinphoneCall *call) { + return call->currentCbs; +} + +void linphone_call_set_params (LinphoneCall *call, const LinphoneCallParams *params) { +#if 0 + if ( call->state == LinphoneCallOutgoingInit || call->state == LinphoneCallIncomingReceived){ + _linphone_call_set_new_params(call, params); + } + else { + ms_error("linphone_call_set_params() invalid state %s to call this function", linphone_call_state_to_string(call->state)); + } +#endif +} + +const LinphoneCallParams *linphone_call_get_params (LinphoneCall *call) { + L_SET_CPP_PTR_FROM_C_STRUCT(call->paramsCache, GET_CPP_PTR(call)->getParams()); + return call->paramsCache; +} + +// ============================================================================= +// Reference and user data handling functions. +// ============================================================================= + +LinphoneCall *linphone_call_ref (LinphoneCall *call) { + belle_sip_object_ref(call); + return call; +} + +void linphone_call_unref (LinphoneCall *call) { + belle_sip_object_unref(call); +} + +void *linphone_call_get_user_data (const LinphoneCall *call) { + return L_GET_USER_DATA_FROM_C_STRUCT(call, Call); +} + +void linphone_call_set_user_data (LinphoneCall *call, void *ud) { + L_SET_USER_DATA_FROM_C_STRUCT(call, ud, Call); +} + +// ============================================================================= +// Constructor and destructor functions. +// ============================================================================= + +LinphoneCall *linphone_call_new_outgoing (LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg) { + LinphoneCall *call = L_INIT(Call); + L_SET_CPP_PTR_FROM_C_STRUCT(call, std::make_shared(call, lc, LinphoneCallOutgoing, + *L_GET_CPP_PTR_FROM_C_STRUCT(from, Address), *L_GET_CPP_PTR_FROM_C_STRUCT(to, Address), + cfg, nullptr, L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams))); + call->currentParamsCache = linphone_call_params_new_for_wrapper(); + call->paramsCache = linphone_call_params_new_for_wrapper(); + call->remoteParamsCache = linphone_call_params_new_for_wrapper(); + call->remoteAddressCache = linphone_address_new(nullptr); + return call; +} + +LinphoneCall *linphone_call_new_incoming (LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, SalOp *op) { + LinphoneCall *call = L_INIT(Call); + L_SET_CPP_PTR_FROM_C_STRUCT(call, std::make_shared(call, lc, LinphoneCallIncoming, + *L_GET_CPP_PTR_FROM_C_STRUCT(from, Address), *L_GET_CPP_PTR_FROM_C_STRUCT(to, Address), + nullptr, op, nullptr)); + call->currentParamsCache = linphone_call_params_new_for_wrapper(); + call->paramsCache = linphone_call_params_new_for_wrapper(); + call->remoteParamsCache = linphone_call_params_new_for_wrapper(); + call->remoteAddressCache = linphone_address_new(nullptr); + GET_CPP_PRIVATE_PTR(call)->initiateIncoming(); + return call; +} diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index 90f0fb112..704f78866 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -27,6 +27,8 @@ #define L_REGISTER_TYPE(C_TYPE) \ extern Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init (); +#define L_INIT(C_TYPE) \ + _linphone_ ## C_TYPE ## _init () // ============================================================================= diff --git a/src/call/call-p.h b/src/call/call-p.h index d0035ac9c..29b4236ba 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -30,10 +30,6 @@ // ============================================================================= -extern std::shared_ptr linphone_call_get_cpp_obj(const LinphoneCall *call); - -// ============================================================================= - LINPHONE_BEGIN_NAMESPACE class CallPrivate : public ObjectPrivate, CallListener { diff --git a/src/call/call.cpp b/src/call/call.cpp index 678468ea4..994be2887 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -372,13 +372,13 @@ LinphoneCallLog * Call::getLog () const { return d->getActiveSession()->getLog(); } -RtpTransport * Call::getMetaRtcpTransport (int streamIndex) { - L_D(Call); +RtpTransport * Call::getMetaRtcpTransport (int streamIndex) const { + L_D(const Call); return static_cast(d->getActiveSession().get())->getMetaRtcpTransport(streamIndex); } -RtpTransport * Call::getMetaRtpTransport (int streamIndex) { - L_D(Call); +RtpTransport * Call::getMetaRtpTransport (int streamIndex) const { + L_D(const Call); return static_cast(d->getActiveSession().get())->getMetaRtpTransport(streamIndex); } @@ -447,8 +447,8 @@ LinphoneCallStats * Call::getStats (LinphoneStreamType type) const { return static_cast(d->getActiveSession().get())->getStats(type); } -int Call::getStreamCount () { - L_D(Call); +int Call::getStreamCount () const { + L_D(const Call); return static_cast(d->getActiveSession().get())->getStreamCount(); } diff --git a/src/call/call.h b/src/call/call.h index 2cb14bf3d..ad13c8b9c 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -76,8 +76,8 @@ public: int getDuration () const; const LinphoneErrorInfo * getErrorInfo () const; LinphoneCallLog * getLog () const; - RtpTransport * getMetaRtcpTransport (int streamIndex); - RtpTransport * getMetaRtpTransport (int streamIndex); + RtpTransport * getMetaRtcpTransport (int streamIndex) const; + RtpTransport * getMetaRtpTransport (int streamIndex) const; float getMicrophoneVolumeGain () const; void * getNativeVideoWindowId () const; const MediaSessionParams * getParams () const; @@ -91,7 +91,7 @@ public: float getSpeakerVolumeGain () const; LinphoneCallState getState () const; LinphoneCallStats * getStats (LinphoneStreamType type) const; - int getStreamCount (); + int getStreamCount () const; MSFormatType getStreamType (int streamIndex) const; LinphoneCallStats * getTextStats () const; LinphoneCallStats * getVideoStats () const; diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index 857c33105..34de3ea3f 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -67,7 +67,7 @@ protected: virtual LinphoneStatus startAcceptUpdate (LinphoneCallState nextState, const std::string &stateInfo); virtual LinphoneStatus startUpdate (); virtual void terminate (); - virtual void updateCurrentParams (); + virtual void updateCurrentParams () const; void setContactOp (); @@ -83,7 +83,7 @@ protected: CallSessionListener *listener = nullptr; CallSessionParams *params = nullptr; - CallSessionParams *currentParams = nullptr; + mutable CallSessionParams *currentParams = nullptr; CallSessionParams *remoteParams = nullptr; LinphoneCallDir direction = LinphoneCallOutgoing; diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 7054a20d8..481db6bd2 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -512,7 +512,7 @@ LinphoneStatus CallSessionPrivate::checkForAcceptation () const { bctbx_list_t *copy = bctbx_list_copy(linphone_core_get_calls(core)); for (bctbx_list_t *it = copy; it != nullptr; it = bctbx_list_next(it)) { LinphoneCall *call = reinterpret_cast(bctbx_list_get_data(it)); - shared_ptr session = linphone_call_get_cpp_obj(call)->getPrivate()->getActiveSession(); + shared_ptr session = L_GET_PRIVATE_FROM_C_STRUCT(call, Call)->getActiveSession(); if (session.get() == q) continue; switch (session->getState()) { case LinphoneCallOutgoingInit: @@ -668,7 +668,7 @@ void CallSessionPrivate::terminate () { setState(LinphoneCallEnd, "Call terminated"); } -void CallSessionPrivate::updateCurrentParams () {} +void CallSessionPrivate::updateCurrentParams () const {} // ----------------------------------------------------------------------------- @@ -1087,8 +1087,8 @@ string CallSession::getRemoteUserAgent () const { return string(); } -CallSessionParams * CallSession::getCurrentParams () { - L_D(CallSession); +CallSessionParams * CallSession::getCurrentParams () const { + L_D(const CallSession); d->updateCurrentParams(); return d->currentParams; } diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index db46a9871..96dcbf2bf 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -51,7 +51,7 @@ public: LinphoneStatus terminate (const LinphoneErrorInfo *ei = nullptr); LinphoneStatus update (const CallSessionParams *csp); - CallSessionParams *getCurrentParams (); + CallSessionParams *getCurrentParams () const; LinphoneCallDir getDirection () const; int getDuration () const; const LinphoneErrorInfo * getErrorInfo () const; diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index 210f2df2a..8a65ea4ca 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -219,7 +219,7 @@ private: LinphoneStatus startAcceptUpdate (LinphoneCallState nextState, const std::string &stateInfo) override; LinphoneStatus startUpdate () override; void terminate () override; - void updateCurrentParams () override; + void updateCurrentParams () const override; void accept (const MediaSessionParams *params); LinphoneStatus acceptUpdate (const CallSessionParams *csp, LinphoneCallState nextState, const std::string &stateInfo) override; @@ -236,7 +236,7 @@ private: static const int ecStateMaxLen; MediaSessionParams *params = nullptr; - MediaSessionParams *currentParams = nullptr; + mutable MediaSessionParams *currentParams = nullptr; MediaSessionParams *remoteParams = nullptr; AudioStream *audioStream = nullptr; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 1613e6282..b079be8b1 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -72,11 +72,11 @@ MediaSessionPrivate::MediaSessionPrivate (const Conference &conference, const Ca params = new MediaSessionParams(*(reinterpret_cast(csp))); currentParams = new MediaSessionParams(); - audioStats = linphone_call_stats_ref(linphone_call_stats_new()); + audioStats = linphone_call_stats_ref(_linphone_call_stats_new()); initStats(audioStats, LinphoneStreamTypeAudio); - videoStats = linphone_call_stats_ref(linphone_call_stats_new()); + videoStats = linphone_call_stats_ref(_linphone_call_stats_new()); initStats(videoStats, LinphoneStreamTypeVideo); - textStats = linphone_call_stats_ref(linphone_call_stats_new()); + textStats = linphone_call_stats_ref(_linphone_call_stats_new()); initStats(textStats, LinphoneStreamTypeText); int minPort, maxPort; @@ -498,9 +498,9 @@ void MediaSessionPrivate::deactivateIce () { videoStream->ms.ice_check_list = nullptr; if (textStream) textStream->ms.ice_check_list = nullptr; - audioStats->ice_state = LinphoneIceStateNotActivated; - videoStats->ice_state = LinphoneIceStateNotActivated; - textStats->ice_state = LinphoneIceStateNotActivated; + _linphone_call_stats_set_ice_state(audioStats, LinphoneIceStateNotActivated); + _linphone_call_stats_set_ice_state(videoStats, LinphoneIceStateNotActivated); + _linphone_call_stats_set_ice_state(textStats, LinphoneIceStateNotActivated); stopStreamsForIceGathering(); } @@ -845,10 +845,10 @@ void MediaSessionPrivate::updateRemoteSessionIdAndVer () { // ----------------------------------------------------------------------------- void MediaSessionPrivate::initStats (LinphoneCallStats *stats, LinphoneStreamType type) { - stats->type = type; - stats->received_rtcp = nullptr; - stats->sent_rtcp = nullptr; - stats->ice_state = LinphoneIceStateNotActivated; + _linphone_call_stats_set_type(stats, type); + _linphone_call_stats_set_received_rtcp(stats, nullptr); + _linphone_call_stats_set_sent_rtcp(stats, nullptr); + _linphone_call_stats_set_ice_state(stats, LinphoneIceStateNotActivated); } void MediaSessionPrivate::notifyStatsUpdated (int streamIndex) const { @@ -861,8 +861,8 @@ void MediaSessionPrivate::notifyStatsUpdated (int streamIndex) const { stats = textStats; else return; - if (stats->updated) { - switch (stats->updated) { + if (_linphone_call_stats_get_updated(stats)) { + switch (_linphone_call_stats_get_updated(stats)) { case LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE: case LINPHONE_CALL_STATS_SENT_RTCP_UPDATE: #if 0 @@ -874,7 +874,7 @@ void MediaSessionPrivate::notifyStatsUpdated (int streamIndex) const { } if (listener) listener->onStatsUpdated(stats); - stats->updated = 0; + _linphone_call_stats_set_updated(stats, 0); } } @@ -924,8 +924,7 @@ int MediaSessionPrivate::selectFixedPort (int streamIndex, pair portRa bool alreadyUsed = false; for (const bctbx_list_t *elem = linphone_core_get_calls(core); elem != nullptr; elem = bctbx_list_next(elem)) { LinphoneCall *lcall = reinterpret_cast(bctbx_list_get_data(elem)); - CallPrivate *callp = linphone_call_get_cpp_obj(lcall)->getPrivate(); - MediaSession *session = dynamic_cast(callp->getConference()->getActiveParticipant()->getPrivate()->getSession().get()); + MediaSession *session = dynamic_cast(L_GET_PRIVATE_FROM_C_STRUCT(lcall, Call)->getConference()->getActiveParticipant()->getPrivate()->getSession().get()); int existingPort = session->getPrivate()->mediaPorts[streamIndex].rtpPort; if (existingPort == triedPort) { alreadyUsed = true; @@ -947,8 +946,7 @@ int MediaSessionPrivate::selectRandomPort (int streamIndex, pair portR if (triedPort < portRange.first) triedPort = portRange.first + 2; for (const bctbx_list_t *elem = linphone_core_get_calls(core); elem != nullptr; elem = bctbx_list_next(elem)) { LinphoneCall *lcall = reinterpret_cast(bctbx_list_get_data(elem)); - CallPrivate *callp = linphone_call_get_cpp_obj(lcall)->getPrivate(); - MediaSession *session = dynamic_cast(callp->getConference()->getActiveParticipant()->getPrivate()->getSession().get()); + MediaSession *session = dynamic_cast(L_GET_PRIVATE_FROM_C_STRUCT(lcall, Call)->getConference()->getActiveParticipant()->getPrivate()->getSession().get()); int existingPort = session->getPrivate()->mediaPorts[streamIndex].rtpPort; if (existingPort == triedPort) { alreadyUsed = true; @@ -2069,9 +2067,9 @@ void MediaSessionPrivate::freeResources () { iceAgent->deleteSession(); for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) ms_media_stream_sessions_uninit(&sessions[i]); - linphone_call_stats_uninit(audioStats); - linphone_call_stats_uninit(videoStats); - linphone_call_stats_uninit(textStats); + _linphone_call_stats_uninit(audioStats); + _linphone_call_stats_uninit(videoStats); + _linphone_call_stats_uninit(textStats); } void MediaSessionPrivate::handleIceEvents (OrtpEvent *ev) { @@ -3409,8 +3407,8 @@ void MediaSessionPrivate::fillLogStats (MediaStream *st) { void MediaSessionPrivate::updateRtpStats (LinphoneCallStats *stats, int streamIndex) { if (sessions[streamIndex].rtp_session) { const rtp_stats_t *rtpStats = rtp_session_get_stats(sessions[streamIndex].rtp_session); - if (stats) - memcpy(&(stats->rtp_stats), rtpStats, sizeof(*rtpStats)); + if (rtpStats) + _linphone_call_stats_set_rtp_stats(stats, rtpStats); } } @@ -3604,12 +3602,12 @@ void MediaSessionPrivate::reportBandwidth () { reportBandwidthForStream(&textStream->ms, LinphoneStreamTypeText); lInfo() << "Bandwidth usage for CallSession [" << q << "]:\n" << fixed << setprecision(2) << - "\tRTP audio=[d=" << audioStats->download_bandwidth << ",u=" << audioStats->upload_bandwidth << - "], video=[d=" << videoStats->download_bandwidth << ",u=" << videoStats->upload_bandwidth << - "], text=[d=" << textStats->download_bandwidth << ",u=" << textStats->upload_bandwidth << "] kbits/sec\n" << - "\tRTCP audio=[d=" << audioStats->rtcp_download_bandwidth << ",u=" << audioStats->rtcp_upload_bandwidth << - "], video=[d=" << videoStats->rtcp_download_bandwidth << ",u=" << videoStats->rtcp_upload_bandwidth << - "], text=[d=" << textStats->rtcp_download_bandwidth << ",u=" << textStats->rtcp_upload_bandwidth << "] kbits/sec"; + "\tRTP audio=[d=" << linphone_call_stats_get_download_bandwidth(audioStats) << ",u=" << linphone_call_stats_get_upload_bandwidth(audioStats) << + "], video=[d=" << linphone_call_stats_get_download_bandwidth(videoStats) << ",u=" << linphone_call_stats_get_upload_bandwidth(videoStats) << + "], text=[d=" << linphone_call_stats_get_download_bandwidth(textStats) << ",u=" << linphone_call_stats_get_upload_bandwidth(textStats) << "] kbits/sec\n" << + "\tRTCP audio=[d=" << linphone_call_stats_get_rtcp_download_bandwidth(audioStats) << ",u=" << linphone_call_stats_get_rtcp_upload_bandwidth(audioStats) << + "], video=[d=" << linphone_call_stats_get_rtcp_download_bandwidth(videoStats) << ",u=" << linphone_call_stats_get_rtcp_upload_bandwidth(videoStats) << + "], text=[d=" << linphone_call_stats_get_rtcp_download_bandwidth(textStats) << ",u=" << linphone_call_stats_get_rtcp_upload_bandwidth(textStats) << "] kbits/sec"; } void MediaSessionPrivate::reportBandwidthForStream (MediaStream *ms, LinphoneStreamType type) { @@ -3624,19 +3622,20 @@ void MediaSessionPrivate::reportBandwidthForStream (MediaStream *ms, LinphoneStr return; bool active = ms ? (media_stream_get_state(ms) == MSStreamStarted) : false; - stats->download_bandwidth = active ? (float)(media_stream_get_down_bw(ms) * 1e-3) : 0.f; - stats->upload_bandwidth = active ? (float)(media_stream_get_up_bw(ms) * 1e-3) : 0.f; - stats->rtcp_download_bandwidth = active ? (float)(media_stream_get_rtcp_down_bw(ms) * 1e-3) : 0.f; - stats->rtcp_upload_bandwidth = active ? (float)(media_stream_get_rtcp_up_bw(ms) * 1e-3) : 0.f; - stats->rtp_remote_family = active ? (ortp_stream_is_ipv6(&ms->sessions.rtp_session->rtp.gs) ? LinphoneAddressFamilyInet6 : LinphoneAddressFamilyInet) : LinphoneAddressFamilyUnspec; + _linphone_call_stats_set_download_bandwidth(stats, active ? (float)(media_stream_get_down_bw(ms) * 1e-3) : 0.f); + _linphone_call_stats_set_upload_bandwidth(stats, active ? (float)(media_stream_get_up_bw(ms) * 1e-3) : 0.f); + _linphone_call_stats_set_rtcp_download_bandwidth(stats, active ? (float)(media_stream_get_rtcp_down_bw(ms) * 1e-3) : 0.f); + _linphone_call_stats_set_rtcp_upload_bandwidth(stats, active ? (float)(media_stream_get_rtcp_up_bw(ms) * 1e-3) : 0.f); + _linphone_call_stats_set_ip_family_of_remote(stats, + active ? (ortp_stream_is_ipv6(&ms->sessions.rtp_session->rtp.gs) ? LinphoneAddressFamilyInet6 : LinphoneAddressFamilyInet) : LinphoneAddressFamilyUnspec); if (core->send_call_stats_periodical_updates) { if (active) linphone_call_stats_update(stats, ms); - stats->updated |= LINPHONE_CALL_STATS_PERIODICAL_UPDATE; + _linphone_call_stats_set_updated(stats, _linphone_call_stats_get_updated(stats) | LINPHONE_CALL_STATS_PERIODICAL_UPDATE); if (listener) listener->onStatsUpdated(stats); - stats->updated = 0; + _linphone_call_stats_set_updated(stats, 0); } } @@ -3767,7 +3766,7 @@ void MediaSessionPrivate::terminate () { CallSessionPrivate::terminate(); } -void MediaSessionPrivate::updateCurrentParams () { +void MediaSessionPrivate::updateCurrentParams () const { CallSessionPrivate::updateCurrentParams(); LinphoneVideoDefinition *vdef = linphone_video_definition_new(MS_VIDEO_SIZE_UNKNOWN_W, MS_VIDEO_SIZE_UNKNOWN_H, nullptr); @@ -4516,8 +4515,8 @@ float MediaSession::getAverageQuality () const { return MediaSessionPrivate::aggregateQualityRatings(audioRating, videoRating); } -MediaSessionParams * MediaSession::getCurrentParams () { - L_D(MediaSession); +MediaSessionParams * MediaSession::getCurrentParams () const { + L_D(const MediaSession); d->updateCurrentParams(); return d->currentParams; } @@ -4538,8 +4537,8 @@ const MediaSessionParams * MediaSession::getMediaParams () const { return d->params; } -RtpTransport * MediaSession::getMetaRtcpTransport (int streamIndex) { - L_D(MediaSession); +RtpTransport * MediaSession::getMetaRtcpTransport (int streamIndex) const { + L_D(const MediaSession); if ((streamIndex < 0) || (streamIndex >= getStreamCount())) return nullptr; RtpTransport *metaRtp; @@ -4548,8 +4547,8 @@ RtpTransport * MediaSession::getMetaRtcpTransport (int streamIndex) { return metaRtcp; } -RtpTransport * MediaSession::getMetaRtpTransport (int streamIndex) { - L_D(MediaSession); +RtpTransport * MediaSession::getMetaRtpTransport (int streamIndex) const { + L_D(const MediaSession); if ((streamIndex < 0) || (streamIndex >= getStreamCount())) return nullptr; RtpTransport *metaRtp; @@ -4676,7 +4675,7 @@ LinphoneCallStats * MediaSession::getStats (LinphoneStreamType type) const { if (type == LinphoneStreamTypeUnknown) return nullptr; LinphoneCallStats *stats = nullptr; - LinphoneCallStats *statsCopy = linphone_call_stats_new(); + LinphoneCallStats *statsCopy = _linphone_call_stats_new(); if (type == LinphoneStreamTypeAudio) stats = d->audioStats; else if (type == LinphoneStreamTypeVideo) @@ -4690,7 +4689,7 @@ LinphoneCallStats * MediaSession::getStats (LinphoneStreamType type) const { return statsCopy; } -int MediaSession::getStreamCount () { +int MediaSession::getStreamCount () const { /* TODO: Revisit when multiple media streams will be implemented */ #ifdef VIDEO_ENABLED if (getCurrentParams()->realtimeTextEnabled()) @@ -4725,9 +4724,9 @@ LinphoneCallStats * MediaSession::getVideoStats () const { bool MediaSession::mediaInProgress () const { L_D(const MediaSession); - if ((d->audioStats->ice_state == LinphoneIceStateInProgress) - || (d->videoStats->ice_state == LinphoneIceStateInProgress) - || (d->textStats->ice_state == LinphoneIceStateInProgress)) + if ((linphone_call_stats_get_ice_state(d->audioStats) == LinphoneIceStateInProgress) + || (linphone_call_stats_get_ice_state(d->videoStats) == LinphoneIceStateInProgress) + || (linphone_call_stats_get_ice_state(d->textStats) == LinphoneIceStateInProgress)) return true; /* TODO: could check zrtp state */ return false; diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index 3403746ea..e27c1c7e2 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -69,11 +69,11 @@ public: std::string getAuthenticationToken () const; bool getAuthenticationTokenVerified () const; float getAverageQuality () const; - MediaSessionParams *getCurrentParams (); + MediaSessionParams *getCurrentParams () const; float getCurrentQuality () const; const MediaSessionParams *getMediaParams () const; - RtpTransport * getMetaRtcpTransport (int streamIndex); - RtpTransport * getMetaRtpTransport (int streamIndex); + RtpTransport * getMetaRtcpTransport (int streamIndex) const; + RtpTransport * getMetaRtpTransport (int streamIndex) const; float getMicrophoneVolumeGain () const; void * getNativeVideoWindowId () const; const CallSessionParams *getParams () const override; @@ -82,7 +82,7 @@ public: const MediaSessionParams *getRemoteParams (); float getSpeakerVolumeGain () const; LinphoneCallStats * getStats (LinphoneStreamType type) const; - int getStreamCount (); + int getStreamCount () const; MSFormatType getStreamType (int streamIndex) const; LinphoneCallStats * getTextStats () const; LinphoneCallStats * getVideoStats () const; diff --git a/src/nat/ice-agent.cpp b/src/nat/ice-agent.cpp index 00cc5219a..63605b3bd 100644 --- a/src/nat/ice-agent.cpp +++ b/src/nat/ice-agent.cpp @@ -233,35 +233,35 @@ void IceAgent::updateIceStateInCallStats () { LinphoneCallStats *textStats = mediaSession.getPrivate()->getStats(LinphoneStreamTypeText); IceSessionState sessionState = ice_session_state(iceSession); if ((sessionState == IS_Completed) || ((sessionState == IS_Failed) && ice_session_has_completed_check_list(iceSession))) { - audioStats->ice_state = LinphoneIceStateNotActivated; + _linphone_call_stats_set_ice_state(audioStats, LinphoneIceStateNotActivated); if (audioCheckList && mediaSession.getMediaParams()->audioEnabled()) updateIceStateInCallStatsForStream(audioStats, audioCheckList); - videoStats->ice_state = LinphoneIceStateNotActivated; + _linphone_call_stats_set_ice_state(videoStats, LinphoneIceStateNotActivated); if (videoCheckList && mediaSession.getMediaParams()->videoEnabled()) updateIceStateInCallStatsForStream(videoStats, videoCheckList); - textStats->ice_state = LinphoneIceStateNotActivated; + _linphone_call_stats_set_ice_state(textStats, LinphoneIceStateNotActivated); if (textCheckList && mediaSession.getMediaParams()->realtimeTextEnabled()) updateIceStateInCallStatsForStream(textStats, textCheckList); } else if (sessionState == IS_Running) { if (audioCheckList && mediaSession.getMediaParams()->audioEnabled()) - audioStats->ice_state = LinphoneIceStateInProgress; + _linphone_call_stats_set_ice_state(audioStats, LinphoneIceStateInProgress); if (videoCheckList && mediaSession.getMediaParams()->videoEnabled()) - videoStats->ice_state = LinphoneIceStateInProgress; + _linphone_call_stats_set_ice_state(videoStats, LinphoneIceStateInProgress); if (textCheckList && mediaSession.getMediaParams()->realtimeTextEnabled()) - textStats->ice_state = LinphoneIceStateInProgress; + _linphone_call_stats_set_ice_state(textStats, LinphoneIceStateInProgress); } else { if (audioCheckList && mediaSession.getMediaParams()->audioEnabled()) - audioStats->ice_state = LinphoneIceStateFailed; + _linphone_call_stats_set_ice_state(audioStats, LinphoneIceStateFailed); if (videoCheckList && mediaSession.getMediaParams()->videoEnabled()) - videoStats->ice_state = LinphoneIceStateFailed; + _linphone_call_stats_set_ice_state(videoStats, LinphoneIceStateFailed); if (textCheckList && mediaSession.getMediaParams()->realtimeTextEnabled()) - textStats->ice_state = LinphoneIceStateFailed; + _linphone_call_stats_set_ice_state(textStats, LinphoneIceStateFailed); } - lInfo() << "CallSession [" << &mediaSession << "] New ICE state: audio: [" << linphone_ice_state_to_string(audioStats->ice_state) - << "] video: [" << linphone_ice_state_to_string(videoStats->ice_state) - << "] text: [" << linphone_ice_state_to_string(textStats->ice_state) << "]"; + lInfo() << "CallSession [" << &mediaSession << "] New ICE state: audio: [" << linphone_ice_state_to_string(linphone_call_stats_get_ice_state(audioStats)) + << "] video: [" << linphone_ice_state_to_string(linphone_call_stats_get_ice_state(videoStats)) + << "] text: [" << linphone_ice_state_to_string(linphone_call_stats_get_ice_state(textStats)) << "]"; } void IceAgent::updateLocalMediaDescriptionFromIce (SalMediaDescription *desc) { @@ -387,7 +387,7 @@ void IceAgent::addLocalIceCandidates (int family, const char *addr, IceCheckList ice_add_local_candidate(audioCl, "host", family, addr, rtpPort, 1, nullptr); ice_add_local_candidate(audioCl, "host", family, addr, rtcpPort, 2, nullptr); LinphoneCallStats *audioStats = mediaSession.getPrivate()->getStats(LinphoneStreamTypeAudio); - audioStats->ice_state = LinphoneIceStateInProgress; + _linphone_call_stats_set_ice_state(audioStats, LinphoneIceStateInProgress); } LinphoneCore *core = mediaSession.getPrivate()->getCore(); if (linphone_core_video_enabled(core) && videoCl && (ice_check_list_state(videoCl) != ICL_Completed) && !ice_check_list_candidates_gathered(videoCl)) { @@ -396,7 +396,7 @@ void IceAgent::addLocalIceCandidates (int family, const char *addr, IceCheckList ice_add_local_candidate(videoCl, "host", family, addr, rtpPort, 1, nullptr); ice_add_local_candidate(videoCl, "host", family, addr, rtcpPort, 2, nullptr); LinphoneCallStats *videoStats = mediaSession.getPrivate()->getStats(LinphoneStreamTypeVideo); - videoStats->ice_state = LinphoneIceStateInProgress; + _linphone_call_stats_set_ice_state(videoStats, LinphoneIceStateInProgress); } if (mediaSession.getMediaParams()->realtimeTextEnabled() && textCl && (ice_check_list_state(textCl) != ICL_Completed) && !ice_check_list_candidates_gathered(textCl)) { int rtpPort = mediaSession.getPrivate()->getRtpPort(LinphoneStreamTypeText); @@ -404,7 +404,7 @@ void IceAgent::addLocalIceCandidates (int family, const char *addr, IceCheckList ice_add_local_candidate(textCl, "host", family, addr, rtpPort, 1, nullptr); ice_add_local_candidate(textCl, "host", family, addr, rtcpPort, 2, nullptr); LinphoneCallStats *textStats = mediaSession.getPrivate()->getStats(LinphoneStreamTypeText); - textStats->ice_state = LinphoneIceStateInProgress; + _linphone_call_stats_set_ice_state(textStats, LinphoneIceStateInProgress); } } @@ -671,14 +671,14 @@ void IceAgent::updateIceStateInCallStatsForStream (LinphoneCallStats *stats, Ice if (ice_check_list_state(cl) == ICL_Completed) { switch (ice_check_list_selected_valid_candidate_type(cl)) { case ICT_HostCandidate: - stats->ice_state = LinphoneIceStateHostConnection; + _linphone_call_stats_set_ice_state(stats, LinphoneIceStateHostConnection); break; case ICT_ServerReflexiveCandidate: case ICT_PeerReflexiveCandidate: - stats->ice_state = LinphoneIceStateReflexiveConnection; + _linphone_call_stats_set_ice_state(stats, LinphoneIceStateReflexiveConnection); break; case ICT_RelayedCandidate: - stats->ice_state = LinphoneIceStateRelayConnection; + _linphone_call_stats_set_ice_state(stats, LinphoneIceStateRelayConnection); break; case ICT_CandidateInvalid: case ICT_CandidateTypeMax: @@ -686,7 +686,7 @@ void IceAgent::updateIceStateInCallStatsForStream (LinphoneCallStats *stats, Ice break; } } else - stats->ice_state = LinphoneIceStateFailed; + _linphone_call_stats_set_ice_state(stats, LinphoneIceStateFailed); } LINPHONE_END_NAMESPACE From 6f14954482e26fd8178ad9a74421960c48324ef3 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 21 Sep 2017 16:26:14 +0200 Subject: [PATCH 0119/2215] Do not set C++ compilation options when compiling C files. --- CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b2135c03..d4d620c84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -290,14 +290,16 @@ else() "-Wfloat-equal" "-Winit-self" "-Wno-error=deprecated-declarations" - "-Woverloaded-virtual" "-Wpointer-arith" "-Wuninitialized" "-Wunused" ) + list(APPEND STRICT_OPTIONS_CXX + "-Woverloaded-virtual" + ) CHECK_CXX_COMPILER_FLAG("-Wsuggest-override" SUGGEST_OVERRIDE) if (SUGGEST_OVERRIDE) - list(APPEND STRICT_OPTIONS_CPP "-Wsuggest-override" "-Werror=suggest-override") + list(APPEND STRICT_OPTIONS_CXX "-Wsuggest-override" "-Werror=suggest-override") endif () list(APPEND STRICT_OPTIONS_C "-Wstrict-prototypes" "-Werror=strict-prototypes") if(CMAKE_C_COMPILER_ID STREQUAL "GNU") From 4272b608a906a0759fb2a18a3bf88499ddb070e5 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 21 Sep 2017 16:36:02 +0200 Subject: [PATCH 0120/2215] fix(core): remove useless typedef --- include/linphone/api/c-types.h | 2 +- include/linphone/types.h | 13 ------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index 7cf35f798..b1d48dc13 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -105,7 +105,7 @@ typedef struct _LinphoneChatRoomCbs LinphoneChatRoomCbs; * An chat message is the object that is sent and received through LinphoneChatRooms. * @ingroup chatroom */ -typedef struct _LinphoneMessage LinphoneMessage; +typedef struct _LinphoneChatMessage LinphoneChatMessage; /** * An object to handle the callbacks for the handling a LinphoneChatMessage objects. diff --git a/include/linphone/types.h b/include/linphone/types.h index 9690ed1d2..c8043e4f5 100644 --- a/include/linphone/types.h +++ b/include/linphone/types.h @@ -318,19 +318,6 @@ typedef enum _LinphoneCallStatus { LinphoneCallDeclinedElsewhere /** Date: Thu, 21 Sep 2017 16:48:05 +0200 Subject: [PATCH 0121/2215] cast to fix build --- coreapi/account_creator.c | 2 +- coreapi/bellesip_sal/sal_impl.c | 10 +++--- coreapi/bellesip_sal/sal_op_events.c | 2 +- coreapi/bellesip_sal/sal_op_publish.c | 2 +- coreapi/bellesip_sal/sal_op_registration.c | 2 +- coreapi/bellesip_sal/sal_sdp.c | 4 +-- coreapi/call_log.c | 2 +- coreapi/chat.c | 2 +- coreapi/ec-calibrator.c | 2 +- coreapi/enum.c | 2 +- coreapi/lime.c | 20 ++++++------ coreapi/linphonecall.c | 2 +- coreapi/linphonecore.c | 34 ++++++++++---------- coreapi/lpc2xml.c | 2 +- coreapi/message_storage.c | 4 +-- coreapi/misc.c | 4 +-- coreapi/presence.c | 20 ++++++------ coreapi/proxy.c | 22 ++++++------- coreapi/sal/sal.c | 2 +- coreapi/sipsetup.c | 2 +- coreapi/sqlite3_bctbx_vfs.c | 6 ++-- include/linphone/utils/utils.h | 4 +++ src/c-wrapper/api/c-call-params.cpp | 12 ++++---- src/chat/is-composing.cpp | 23 ++++++++------ src/chat/is-composing.h | 6 ++-- src/conference/session/media-session-p.h | 2 +- src/conference/session/media-session.cpp | 18 +++++------ src/nat/ice-agent.cpp | 4 +-- src/nat/stun-client.cpp | 4 +-- src/utils/utils.cpp | 36 ++++++++++++++++++++-- 30 files changed, 147 insertions(+), 110 deletions(-) diff --git a/coreapi/account_creator.c b/coreapi/account_creator.c index e6902ef2b..791201466 100644 --- a/coreapi/account_creator.c +++ b/coreapi/account_creator.c @@ -45,7 +45,7 @@ static const char* ha1_for_passwd(const char* username, const char* realm, const static unsigned int validate_uri(const char* username, const char* domain, const char* display_name) { LinphoneAddress* addr; - int status = 0; + unsigned int status = 0; LinphoneProxyConfig* proxy = linphone_proxy_config_new(); linphone_proxy_config_set_identity(proxy, "sip:?@domain.com"); diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index ccdb2d197..da8ce0f7d 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -641,7 +641,7 @@ static int sal_add_listen_port(Sal *ctx, SalAddress* addr, bool_t is_tunneled){ sal_transport_to_string(sal_address_get_transport(addr))); } if (lp) { - belle_sip_listening_point_set_keep_alive(lp,ctx->keep_alive); + belle_sip_listening_point_set_keep_alive(lp,(int)ctx->keep_alive); result = belle_sip_provider_add_listening_point(ctx->prov,lp); if (sal_address_get_transport(addr)==SalTransportTLS) { set_tls_properties(ctx); @@ -716,7 +716,7 @@ void sal_set_keepalive_period(Sal *ctx,unsigned int value){ for (iterator=belle_sip_provider_get_listening_points(ctx->prov);iterator!=NULL;iterator=iterator->next) { lp=(belle_sip_listening_point_t*)iterator->data; if (ctx->use_tcp_tls_keep_alive || strcasecmp(belle_sip_listening_point_get_transport(lp),"udp")==0) { - belle_sip_listening_point_set_keep_alive(lp,ctx->keep_alive); + belle_sip_listening_point_set_keep_alive(lp,(int)ctx->keep_alive); } } } @@ -1079,7 +1079,7 @@ int sal_generate_uuid(char *uuid, size_t len) { return -1; } for (i = 0; i < 6; i++) - written+=snprintf(uuid+written,len-written,"%2.2x", uuid_struct.node[i]); + written+=snprintf(uuid+written,len-(size_t)written,"%2.2x", uuid_struct.node[i]); uuid[len-1]='\0'; return 0; } @@ -1106,7 +1106,7 @@ static void make_supported_header(Sal *sal){ const char *tag=(const char*)it->data; size_t taglen=strlen(tag); if (alltags==NULL || (written+taglen+1>=buflen)) alltags=reinterpret_cast(ms_realloc(alltags,(buflen=buflen*2))); - written+=snprintf(alltags+written,buflen-written,it->next ? "%s, " : "%s",tag); + written+=(size_t)snprintf(alltags+written,buflen-written,it->next ? "%s, " : "%s",tag); } if (alltags){ sal->supported=belle_sip_header_create("Supported",alltags); @@ -1287,7 +1287,7 @@ unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size){ } char *sal_get_random_token(int size){ - return belle_sip_random_token(reinterpret_cast(ms_malloc(size)),size); + return belle_sip_random_token(reinterpret_cast(ms_malloc((size_t)size)),(size_t)size); } unsigned int sal_get_random(void){ diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c index d3198fde9..ef0a2cb17 100644 --- a/coreapi/bellesip_sal/sal_op_events.c +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -52,7 +52,7 @@ static void subscribe_refresher_listener (belle_sip_refresher_t* refresher if (status_code == 503) { /*refresher returns 503 for IO error*/ reason = SalReasonIOError; } - sal_error_info_set(&op->error_info, reason, "SIP", status_code,reason_phrase,NULL); + sal_error_info_set(&op->error_info, reason, "SIP", (int)status_code,reason_phrase,NULL); op->base.root->callbacks.subscribe_response(op,sss, will_retry); }else if (status_code==0){ op->base.root->callbacks.on_expire(op); diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c index 2de596519..5907c2cd6 100644 --- a/coreapi/bellesip_sal/sal_op_publish.c +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -36,7 +36,7 @@ static void publish_refresher_listener (belle_sip_refresher_t* refresher sip_etag_string = belle_sip_header_get_unparsed_value(sip_etag); } sal_op_set_entity_tag(op, sip_etag_string); - sal_error_info_set(&op->error_info,SalReasonUnknown, "SIP", status_code,reason_phrase,NULL); + sal_error_info_set(&op->error_info,SalReasonUnknown, "SIP", (int)status_code,reason_phrase,NULL); sal_op_assign_recv_headers(op,(belle_sip_message_t*)response); op->base.root->callbacks.on_publish_response(op); } diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 0bff2470d..e21e88803 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -32,7 +32,7 @@ static void register_refresher_listener (belle_sip_refresher_t* refresher /*only take first one for now*/ op->auth_info=sal_auth_info_create((belle_sip_auth_event_t*)(belle_sip_refresher_get_auth_events(refresher)->data)); } - sal_error_info_set(&op->error_info,SalReasonUnknown, "SIP", status_code,reason_phrase,NULL); + sal_error_info_set(&op->error_info,SalReasonUnknown, "SIP", (int)status_code,reason_phrase,NULL); if (status_code>=200){ sal_op_assign_recv_headers(op,(belle_sip_message_t*)response); } diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index c2a059d22..ab3478fb6 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -42,7 +42,7 @@ static void add_ice_candidates(belle_sdp_media_description_t *md, const SalStrea return; } if (candidate->raddr[0] != '\0') { - nb = snprintf(buffer + nb, sizeof(buffer) - nb, " raddr %s rport %d", candidate->raddr, candidate->rport); + nb = snprintf(buffer + nb, sizeof(buffer) - (size_t)nb, " raddr %s rport %d", candidate->raddr, candidate->rport); if (nb < 0) { ms_error("Cannot add ICE candidate attribute!"); return; @@ -63,7 +63,7 @@ static void add_ice_remote_candidates(belle_sdp_media_description_t *md, const S for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; i++) { candidate = &desc->ice_remote_candidates[i]; if ((candidate->addr[0] != '\0') && (candidate->port != 0)) { - offset = snprintf(ptr, buffer + sizeof(buffer) - ptr, "%s%d %s %d", (i > 0) ? " " : "", i + 1, candidate->addr, candidate->port); + offset = snprintf(ptr, (size_t)(buffer + sizeof(buffer) - ptr), "%s%d %s %d", (i > 0) ? " " : "", i + 1, candidate->addr, candidate->port); if (offset < 0) { ms_error("Cannot add ICE remote-candidates attribute!"); return; diff --git a/coreapi/call_log.c b/coreapi/call_log.c index b1c98aeab..479c0a5d6 100644 --- a/coreapi/call_log.c +++ b/coreapi/call_log.c @@ -137,7 +137,7 @@ bctbx_list_t * call_logs_read_from_config_file(LinphoneCore *lc){ continue; cl=linphone_call_log_new(static_cast(lp_config_get_int(cfg,logsection,"dir",0)),from,to); cl->status=static_cast(lp_config_get_int(cfg,logsection,"status",0)); - sec=lp_config_get_int64(cfg,logsection,"start_date_time",0); + sec=(uint64_t)lp_config_get_int64(cfg,logsection,"start_date_time",0); if (sec) { /*new call log format with date expressed in seconds */ cl->start_date_time=(time_t)sec; diff --git a/coreapi/chat.c b/coreapi/chat.c index 08c0af543..6d69e0788 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -162,7 +162,7 @@ void create_file_transfer_information_from_vnd_gsma_rcs_ft_http_xml(LinphoneChat while (cur != NULL) { if (!xmlStrcmp(cur->name, (const xmlChar *)"file-size")) { xmlChar *fileSizeString = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - linphone_content_set_size(content, strtol((const char *)fileSizeString, NULL, 10)); + linphone_content_set_size(content, (size_t)strtol((const char *)fileSizeString, NULL, 10)); xmlFree(fileSizeString); } diff --git a/coreapi/ec-calibrator.c b/coreapi/ec-calibrator.c index 10578af9a..4a8ee1282 100644 --- a/coreapi/ec-calibrator.c +++ b/coreapi/ec-calibrator.c @@ -318,7 +318,7 @@ int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibration ms_error("Echo calibration is still on going !"); return -1; } - rate = lp_config_get_int(lc->config,"sound","echo_cancellation_rate",8000); + rate = (unsigned int)lp_config_get_int(lc->config,"sound","echo_cancellation_rate",8000); lc->ecc=ec_calibrator_new(lc->factory, lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard,rate,cb,audio_init_cb,audio_uninit_cb,cb_data); lc->ecc->play_cool_tones = !!lp_config_get_int(lc->config, "sound", "ec_calibrator_cool_tones", 0); ec_calibrator_start(lc->ecc); diff --git a/coreapi/enum.c b/coreapi/enum.c index 9b18bc1a0..3444efbba 100644 --- a/coreapi/enum.c +++ b/coreapi/enum.c @@ -32,7 +32,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. static char *create_enum_domain(const char *number){ long len=(long)strlen(number); - char *domain=reinterpret_cast(ms_malloc((len*2)+10)); + char *domain=reinterpret_cast(ms_malloc((size_t)(len*2)+10)); long i,j; for (i=0,j=len-1;j>=0;j--){ diff --git a/coreapi/lime.c b/coreapi/lime.c index 35f1080db..9deb4cbdf 100644 --- a/coreapi/lime.c +++ b/coreapi/lime.c @@ -93,21 +93,21 @@ int lime_getCachedSndKeysByURI(void *cachedb, limeURIKeys_t *associatedKeys) { /* retrieve values : peerZid, sndKey, sndSId, sndIndex, valid from columns 1,2,3,4,5 */ length = sqlite3_column_bytes(sqlStmt, 1); if (length==12) { /* peerZID */ - memcpy(currentPeerKey->peerZID, sqlite3_column_blob(sqlStmt, 1), length); + memcpy(currentPeerKey->peerZID, sqlite3_column_blob(sqlStmt, 1), (size_t)length); } else { /* something wrong with that one, skip it */ continue; } length = sqlite3_column_bytes(sqlStmt, 2); if (length==32) { /* sndKey */ - memcpy(currentPeerKey->key, sqlite3_column_blob(sqlStmt, 2), length); + memcpy(currentPeerKey->key, sqlite3_column_blob(sqlStmt, 2), (size_t)length); } else { /* something wrong with that one, skip it */ continue; } length = sqlite3_column_bytes(sqlStmt, 3); if (length==32) { /* sndSId */ - memcpy(currentPeerKey->sessionId, sqlite3_column_blob(sqlStmt, 3), length); + memcpy(currentPeerKey->sessionId, sqlite3_column_blob(sqlStmt, 3), (size_t)length); } else { /* something wrong with that one, skip it */ continue; } @@ -126,14 +126,14 @@ int lime_getCachedSndKeysByURI(void *cachedb, limeURIKeys_t *associatedKeys) { length = sqlite3_column_bytes(sqlStmt, 5); if (length==8) { /* sndIndex : 8 bytes of a int64_t, stored as a blob in big endian */ uint8_t *validity = (uint8_t *)sqlite3_column_blob(sqlStmt, 5); - validityTimeSpec.tv_sec = ((uint64_t)(validity[0]))<<56 | + validityTimeSpec.tv_sec = (int64_t)(((uint64_t)(validity[0]))<<56 | ((uint64_t)(validity[1]))<<48 | ((uint64_t)(validity[2]))<<40 | ((uint64_t)(validity[3]))<<32 | ((uint64_t)(validity[4]))<<24 | ((uint64_t)(validity[5]))<<16 | ((uint64_t)(validity[6]))<<8 | - ((uint64_t)(validity[7])); + ((uint64_t)(validity[7]))); } else { /* something wrong with that one, skip it */ continue; } @@ -210,7 +210,7 @@ int lime_getCachedRcvKeyByZid(void *cachedb, limeKey_t *associatedKey, const cha /* retrieve values : rcvKey, rcvSId, rcvIndex from columns 1,2,3 */ length = sqlite3_column_bytes(sqlStmt, 1); if (length==32) { /* rcvKey */ - memcpy(associatedKey->key, sqlite3_column_blob(sqlStmt, 1), length); + memcpy(associatedKey->key, sqlite3_column_blob(sqlStmt, 1), (size_t)length); } else { /* something wrong */ sqlite3_finalize(sqlStmt); return LIME_NO_VALID_KEY_FOUND_FOR_PEER; @@ -218,7 +218,7 @@ int lime_getCachedRcvKeyByZid(void *cachedb, limeKey_t *associatedKey, const cha length = sqlite3_column_bytes(sqlStmt, 2); if (length==32) { /* rcvSId */ - memcpy(associatedKey->sessionId, sqlite3_column_blob(sqlStmt, 2), length); + memcpy(associatedKey->sessionId, sqlite3_column_blob(sqlStmt, 2), (size_t)length); } else { /* something wrong */ sqlite3_finalize(sqlStmt); return LIME_NO_VALID_KEY_FOUND_FOR_PEER; @@ -275,7 +275,7 @@ int lime_setCachedKey(void *cachedb, limeKey_t *associatedKey, uint8_t role, uin /* shall we update valid column? Enforce only when receiver, if timeSpan is 0, just ignore */ if (validityTimeSpan > 0 && role == LIME_RECEIVER) { bctbx_get_utc_cur_time(¤tTime); - bctbx_timespec_add(¤tTime, validityTimeSpan); + bctbx_timespec_add(¤tTime, (int64_t)validityTimeSpan); /* store the int64_t in big endian in the cache(cache is not typed, all data seen as blob) */ colValues[3][0] = (uint8_t)((currentTime.tv_sec>>56)&0xFF); colValues[3][1] = (uint8_t)((currentTime.tv_sec>>48)&0xFF); @@ -566,8 +566,8 @@ int lime_createMultipartMessage(void *cachedb, const char *contentType, uint8_t /* dump the whole message doc into the output */ xmlDocDumpFormatMemoryEnc(xmlOutputMessage, &local_output, &xmlStringLength, "UTF-8", 0); - *output = (uint8_t *)ms_malloc(xmlStringLength + 1); - memcpy(*output, local_output, xmlStringLength); + *output = (uint8_t *)ms_malloc((size_t)xmlStringLength + 1); + memcpy(*output, local_output, (size_t)xmlStringLength); (*output)[xmlStringLength] = '\0'; xmlFree(local_output); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 9962d373a..6afea2b22 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -125,4 +125,4 @@ void set_playback_gain_db(AudioStream *st, float gain){ if (st->volrecv){ ms_filter_call_method(st->volrecv,MS_VOLUME_SET_DB_GAIN,&gain); }else ms_warning("Could not apply playback gain: gain control wasn't activated."); -} +} \ No newline at end of file diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index c646bfbdc..43c4520c4 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -510,8 +510,8 @@ void linphone_core_set_log_level(OrtpLogLevel loglevel) { void linphone_core_set_log_level_mask(unsigned int loglevel) { //we only have 2 domain for now ortp and belle-sip - bctbx_set_log_level_mask(ORTP_LOG_DOMAIN, loglevel); - bctbx_set_log_level_mask("bzrtp", loglevel); /*need something to set log lvel for all domains*/ + bctbx_set_log_level_mask(ORTP_LOG_DOMAIN, (int)loglevel); + bctbx_set_log_level_mask("bzrtp", (int)loglevel); /*need something to set log lvel for all domains*/ sal_set_log_level((OrtpLogLevel)loglevel); } unsigned int linphone_core_get_log_level_mask(void) { @@ -535,7 +535,7 @@ static int _open_log_collection_file_with_idx(int idx) { return -1; } - liblinphone_log_collection_file_size = statbuf.st_size; + liblinphone_log_collection_file_size = (size_t)statbuf.st_size; return 0; } @@ -623,7 +623,7 @@ static void linphone_core_log_collection_handler(const char *domain, OrtpLogLeve 1900 + lt->tm_year, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec, (int)(tp.tv_usec / 1000), lname, msg); fflush(liblinphone_log_collection_file); if (ret > 0) { - liblinphone_log_collection_file_size += ret; + liblinphone_log_collection_file_size += (size_t)ret; if (liblinphone_log_collection_file_size > liblinphone_log_collection_max_file_size) { _close_log_collection_file(); _open_log_collection_file(); @@ -945,7 +945,7 @@ static size_t get_size_of_file_to_upload(const char *filename) { fstat(fileno(output_file), &statbuf); fclose(output_file); ms_free(output_filename); - return statbuf.st_size; + return (size_t)statbuf.st_size; } void linphone_core_upload_log_collection(LinphoneCore *core) { @@ -1382,7 +1382,7 @@ static void sip_config_read(LinphoneCore *lc) { !!lp_config_get_int(lc->config,"sip","register_only_when_upnp_is_ok",1); lc->sip_conf.ping_with_options= !!lp_config_get_int(lc->config,"sip","ping_with_options",0); lc->sip_conf.auto_net_state_mon = !!lp_config_get_int(lc->config,"sip","auto_net_state_mon",1); - lc->sip_conf.keepalive_period = lp_config_get_int(lc->config,"sip","keepalive_period",10000); + lc->sip_conf.keepalive_period = (unsigned int)lp_config_get_int(lc->config,"sip","keepalive_period",10000); lc->sip_conf.tcp_tls_keepalive = !!lp_config_get_int(lc->config,"sip","tcp_tls_keepalive",0); linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0)); sal_use_one_matching_codec_policy(lc->sal, !!lp_config_get_int(lc->config,"sip","only_one_codec",0)); @@ -3161,7 +3161,7 @@ void linphone_core_iterate(LinphoneCore *lc){ if (lc->prevtime_ms == 0){ lc->prevtime_ms = curtime_ms; } - if ((diff_time=curtime_ms-lc->prevtime_ms) >= 1000){ + if ((diff_time=(int64_t)(curtime_ms-lc->prevtime_ms)) >= 1000){ one_second_elapsed=TRUE; if (diff_time>3000){ /*since monotonic time doesn't increment while machine is sleeping, we don't want to catchup too much*/ @@ -3199,7 +3199,7 @@ void linphone_core_iterate(LinphoneCore *lc){ } if (lc->ringstream && lc->ringstream_autorelease && lc->dmfs_playing_start_time!=0 - && (curtime_ms/1000 - lc->dmfs_playing_start_time)>5){ + && (curtime_ms/1000 - (uint64_t)lc->dmfs_playing_start_time)>5){ MSPlayerState state; bool_t stop=TRUE; if (lc->ringstream->source && ms_filter_call_method(lc->ringstream->source,MS_PLAYER_GET_STATE,&state)==0){ @@ -4762,8 +4762,8 @@ static void toggle_video_preview(LinphoneCore *lc, bool_t val){ if (!vdef || linphone_video_definition_is_undefined(vdef)) { vdef = linphone_core_get_preferred_video_definition(lc); } - vsize.width = linphone_video_definition_get_width(vdef); - vsize.height = linphone_video_definition_get_height(vdef); + vsize.width = (int)linphone_video_definition_get_width(vdef); + vsize.height = (int)linphone_video_definition_get_height(vdef); lc->previewstream=video_preview_new(lc->factory); video_preview_set_size(lc->previewstream,vsize); if (display_filter) @@ -5325,7 +5325,7 @@ void linphone_core_set_preferred_video_definition(LinphoneCore *lc, LinphoneVide void linphone_core_set_preferred_video_size(LinphoneCore *lc, MSVideoSize vsize) { linphone_core_set_preferred_video_definition(lc, - linphone_factory_find_supported_video_definition(linphone_factory_get(), vsize.width, vsize.height)); + linphone_factory_find_supported_video_definition(linphone_factory_get(), (unsigned int)vsize.width, (unsigned int)vsize.height)); } void linphone_core_set_preview_video_definition(LinphoneCore *lc, LinphoneVideoDefinition *vdef) { @@ -5354,7 +5354,7 @@ void linphone_core_set_preview_video_definition(LinphoneCore *lc, LinphoneVideoD void linphone_core_set_preview_video_size(LinphoneCore *lc, MSVideoSize vsize) { linphone_core_set_preview_video_definition(lc, - linphone_factory_find_supported_video_definition(linphone_factory_get(), vsize.width, vsize.height)); + linphone_factory_find_supported_video_definition(linphone_factory_get(), (unsigned int)vsize.width, (unsigned int)vsize.height)); } const LinphoneVideoDefinition * linphone_core_get_preview_video_definition(const LinphoneCore *lc) { @@ -5363,8 +5363,8 @@ const LinphoneVideoDefinition * linphone_core_get_preview_video_definition(const MSVideoSize linphone_core_get_preview_video_size(const LinphoneCore *lc) { MSVideoSize vsize = { 0 }; - vsize.width = linphone_video_definition_get_width(lc->video_conf.preview_vdef); - vsize.height = linphone_video_definition_get_height(lc->video_conf.preview_vdef); + vsize.width = (int)linphone_video_definition_get_width(lc->video_conf.preview_vdef); + vsize.height = (int)linphone_video_definition_get_height(lc->video_conf.preview_vdef); return vsize; } @@ -5386,7 +5386,7 @@ LinphoneVideoDefinition * linphone_core_get_current_preview_video_definition(con if (lc->previewstream) { vsize = video_preview_get_current_size(lc->previewstream); } - return linphone_factory_find_supported_video_definition(linphone_factory_get(), vsize.width, vsize.height); + return linphone_factory_find_supported_video_definition(linphone_factory_get(), (unsigned int)vsize.width, (unsigned int)vsize.height); #else ms_error("Video support is disabled"); return NULL; @@ -5429,8 +5429,8 @@ const LinphoneVideoDefinition * linphone_core_get_preferred_video_definition(con MSVideoSize linphone_core_get_preferred_video_size(const LinphoneCore *lc) { MSVideoSize vsize = { 0 }; - vsize.width = linphone_video_definition_get_width(lc->video_conf.vdef); - vsize.height = linphone_video_definition_get_height(lc->video_conf.vdef); + vsize.width = (int)linphone_video_definition_get_width(lc->video_conf.vdef); + vsize.height = (int)linphone_video_definition_get_height(lc->video_conf.vdef); return vsize; } diff --git a/coreapi/lpc2xml.c b/coreapi/lpc2xml.c index 0fe709116..52f1f2dd8 100644 --- a/coreapi/lpc2xml.c +++ b/coreapi/lpc2xml.c @@ -48,7 +48,7 @@ static xmlChar* convert_iso_to_utf8(const char *in) { ms_free(out); return NULL; } else { - out = reinterpret_cast(ms_realloc(out, out_size + 1)); + out = reinterpret_cast(ms_realloc(out, (size_t)out_size + 1)); out[out_size] = '\0'; } } diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index cad03b178..ee3b9b2f8 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -209,14 +209,14 @@ static int linphone_chat_message_store_content(LinphoneChatMessage *msg) { ); linphone_sql_request(lc->db, buf); sqlite3_free(buf); - id = (unsigned int) sqlite3_last_insert_rowid (lc->db); + id = (int) sqlite3_last_insert_rowid (lc->db); } return id; } unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){ LinphoneCore *lc=linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)); - int id = 0; + unsigned int id = 0; if (lc->db){ int content_id = -1; diff --git a/coreapi/misc.c b/coreapi/misc.c index f8c639a34..f7c0cb7bf 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -320,7 +320,7 @@ unsigned int linphone_core_get_audio_features(LinphoneCore *lc){ if (ret==AUDIO_STREAM_FEATURE_ALL){ /*since call recording is specified before creation of the stream in linphonecore, * it will be requested on demand. It is not necessary to include it all the time*/ - ret&=~AUDIO_STREAM_FEATURE_MIXED_RECORDING; + ret&=(unsigned int) ~AUDIO_STREAM_FEATURE_MIXED_RECORDING; } return ret; } @@ -640,7 +640,7 @@ const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc){ char *pos; char *nextpos; char *params; - int found=0; + unsigned long found=0; MSCryptoSuite *result=NULL; pos=tmp; do{ diff --git a/coreapi/presence.c b/coreapi/presence.c index 43c7a8ffd..e8e87f181 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -373,7 +373,7 @@ static void presence_model_get_activity(const LinphonePresencePerson *person, st if (st->current_idx != (unsigned)-1) { unsigned int size = (unsigned int)bctbx_list_size(person->activities); if (st->requested_idx < (st->current_idx + size)) { - st->activity = (LinphonePresenceActivity *)bctbx_list_nth_data(person->activities, st->requested_idx - st->current_idx); + st->activity = (LinphonePresenceActivity *)bctbx_list_nth_data(person->activities, (int)(st->requested_idx - st->current_idx)); st->current_idx = (unsigned)-1; } else { st->current_idx += size; @@ -621,7 +621,7 @@ LinphonePresenceService * linphone_presence_model_get_nth_service(const Linphone if ((model == NULL) || (idx >= linphone_presence_model_get_nb_services(model))) return NULL; - return (LinphonePresenceService *)bctbx_list_nth_data(model->services, idx); + return (LinphonePresenceService *)bctbx_list_nth_data(model->services, (int)idx); } LinphoneStatus linphone_presence_model_add_service(LinphonePresenceModel *model, LinphonePresenceService *service) { @@ -647,7 +647,7 @@ LinphonePresencePerson * linphone_presence_model_get_nth_person(const LinphonePr if ((model == NULL) || (idx >= linphone_presence_model_get_nb_persons(model))) return NULL; - return (LinphonePresencePerson *)bctbx_list_nth_data(model->persons, idx); + return (LinphonePresencePerson *)bctbx_list_nth_data(model->persons, (int)idx); } LinphoneStatus linphone_presence_model_add_person(LinphonePresenceModel *model, LinphonePresencePerson *person) { @@ -783,7 +783,7 @@ LinphonePresenceNote * linphone_presence_service_get_nth_note(const LinphonePres if ((service == NULL) || (idx >= linphone_presence_service_get_nb_notes(service))) return NULL; - return (LinphonePresenceNote *)bctbx_list_nth_data(service->notes, idx); + return (LinphonePresenceNote *)bctbx_list_nth_data(service->notes, (int)idx); } LinphoneStatus linphone_presence_service_add_note(LinphonePresenceService *service, LinphonePresenceNote *note) { @@ -844,7 +844,7 @@ unsigned int linphone_presence_person_get_nb_activities(const LinphonePresencePe LinphonePresenceActivity * linphone_presence_person_get_nth_activity(const LinphonePresencePerson *person, unsigned int idx) { if ((person == NULL) || (idx >= linphone_presence_person_get_nb_activities(person))) return NULL; - return (LinphonePresenceActivity *)bctbx_list_nth_data(person->activities, idx); + return (LinphonePresenceActivity *)bctbx_list_nth_data(person->activities, (int)idx); } LinphoneStatus linphone_presence_person_add_activity(LinphonePresencePerson *person, LinphonePresenceActivity *activity) { @@ -870,7 +870,7 @@ unsigned int linphone_presence_person_get_nb_notes(const LinphonePresencePerson LinphonePresenceNote * linphone_presence_person_get_nth_note(const LinphonePresencePerson *person, unsigned int idx) { if ((person == NULL) || (idx >= linphone_presence_person_get_nb_notes(person))) return NULL; - return (LinphonePresenceNote *)bctbx_list_nth_data(person->notes, idx); + return (LinphonePresenceNote *)bctbx_list_nth_data(person->notes, (int)idx); } LinphoneStatus linphone_presence_person_add_note(LinphonePresencePerson *person, LinphonePresenceNote *note) { @@ -895,7 +895,7 @@ unsigned int linphone_presence_person_get_nb_activities_notes(const LinphonePres LinphonePresenceNote * linphone_presence_person_get_nth_activities_note(const LinphonePresencePerson *person, unsigned int idx) { if ((person == NULL) || (idx >= linphone_presence_person_get_nb_activities_notes(person))) return NULL; - return (LinphonePresenceNote *)bctbx_list_nth_data(person->activities_notes, idx); + return (LinphonePresenceNote *)bctbx_list_nth_data(person->activities_notes, (int)idx); } LinphoneStatus linphone_presence_person_add_activities_note(LinphonePresencePerson *person, LinphonePresenceNote *note) { @@ -1275,7 +1275,7 @@ static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, Lin if (service != NULL) { if (timestamp_str != NULL) presence_service_set_timestamp(service, parse_timestamp(timestamp_str)); if (contact_str != NULL) linphone_presence_service_set_contact(service, contact_str); - process_pidf_xml_presence_service_notes(xml_ctx, service, i); + process_pidf_xml_presence_service_notes(xml_ctx, service, (unsigned int)i); linphone_presence_model_add_service(model, service); linphone_presence_service_unref(service); } @@ -1415,9 +1415,9 @@ static int process_pidf_xml_presence_persons(xmlparsing_context_t *xml_ctx, Linp person = presence_person_new(person_id_str, timestamp); if (person != NULL) { - err = process_pidf_xml_presence_person_activities(xml_ctx, person, i); + err = process_pidf_xml_presence_person_activities(xml_ctx, person, (unsigned int)i); if (err == 0) { - err = process_pidf_xml_presence_person_notes(xml_ctx, person, i); + err = process_pidf_xml_presence_person_notes(xml_ctx, person, (unsigned int)i); } if (err == 0) { presence_model_add_person(model, person); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index db61462b2..ce6d4aa21 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -119,7 +119,7 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *cf cfg->reg_sendregister = lc ? !!lp_config_get_default_int(lc->config, "proxy", "reg_sendregister", 1) : 1; cfg->dial_prefix = dial_prefix ? ms_strdup(dial_prefix) : NULL; cfg->dial_escape_plus = lc ? !!lp_config_get_default_int(lc->config, "proxy", "dial_escape_plus", 0) : 0; - cfg->privacy = lc ? lp_config_get_default_int(lc->config, "proxy", "privacy", LinphonePrivacyDefault) : LinphonePrivacyDefault; + cfg->privacy = lc ? (LinphonePrivacyMask)lp_config_get_default_int(lc->config, "proxy", "privacy", LinphonePrivacyDefault) : LinphonePrivacyDefault; cfg->identity_address = identity ? linphone_address_new(identity) : NULL; cfg->reg_identity = cfg->identity_address ? linphone_address_as_string(cfg->identity_address) : NULL; cfg->reg_proxy = proxy ? ms_strdup(proxy) : NULL; @@ -1146,7 +1146,7 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC lp_config_set_int(config, key, "avpf_rr_interval", cfg->avpf_rr_interval); lp_config_set_int(config,key,"dial_escape_plus",cfg->dial_escape_plus); lp_config_set_string(config,key,"dial_prefix",cfg->dial_prefix); - lp_config_set_int(config,key,"privacy",cfg->privacy); + lp_config_set_int(config,key,"privacy",(int)cfg->privacy); if (cfg->refkey) lp_config_set_string(config,key,"refkey",cfg->refkey); lp_config_set_int(config, key, "publish_expires", cfg->publish_expires); @@ -1167,8 +1167,8 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC #define CONFIGURE_BOOL_VALUE(cfg,config,key,param,param_name) \ linphone_proxy_config_enable_##param(cfg, !!lp_config_get_int(config,key,param_name,linphone_proxy_config_##param##_enabled(cfg))); -#define CONFIGURE_INT_VALUE(cfg,config,key,param,param_name) \ - linphone_proxy_config_set_##param(cfg, !!lp_config_get_int(config,key,param_name,linphone_proxy_config_get_##param(cfg))); +#define CONFIGURE_INT_VALUE(cfg,config,key,param,param_name, param_type) \ + linphone_proxy_config_set_##param(cfg, (param_type)lp_config_get_int(config,key,param_name,(int)linphone_proxy_config_get_##param(cfg))); LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore* lc, int index) { @@ -1194,26 +1194,26 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore* lc CONFIGURE_BOOL_VALUE(cfg,config,key,quality_reporting,"quality_reporting_enabled") CONFIGURE_STRING_VALUE(cfg,config,key,quality_reporting_collector,"quality_reporting_collector") - CONFIGURE_INT_VALUE(cfg,config,key,quality_reporting_interval,"quality_reporting_interval") + CONFIGURE_INT_VALUE(cfg,config,key,quality_reporting_interval,"quality_reporting_interval",int) CONFIGURE_STRING_VALUE(cfg,config,key,contact_parameters,"contact_parameters") CONFIGURE_STRING_VALUE(cfg,config,key,contact_uri_parameters,"contact_uri_parameters") - CONFIGURE_INT_VALUE(cfg,config,key,expires,"reg_expires") + CONFIGURE_INT_VALUE(cfg,config,key,expires,"reg_expires", int) CONFIGURE_BOOL_VALUE(cfg,config,key,register,"reg_sendregister") CONFIGURE_BOOL_VALUE(cfg,config,key,publish,"publish") linphone_proxy_config_set_avpf_mode(cfg,static_cast(lp_config_get_int(config,key,"avpf",linphone_proxy_config_get_avpf_mode(cfg)))); - CONFIGURE_INT_VALUE(cfg,config,key,avpf_rr_interval,"avpf_rr_interval") - CONFIGURE_INT_VALUE(cfg,config,key,dial_escape_plus,"dial_escape_plus") + CONFIGURE_INT_VALUE(cfg,config,key,avpf_rr_interval,"avpf_rr_interval",uint8_t) + CONFIGURE_INT_VALUE(cfg,config,key,dial_escape_plus,"dial_escape_plus",bool_t) CONFIGURE_STRING_VALUE(cfg,config,key,dial_prefix,"dial_prefix") tmp=lp_config_get_string(config,key,"type",NULL); if (tmp!=NULL && strlen(tmp)>0) linphone_proxy_config_set_sip_setup(cfg,tmp); - CONFIGURE_INT_VALUE(cfg,config,key,privacy,"privacy") + CONFIGURE_INT_VALUE(cfg,config,key,privacy,"privacy",LinphonePrivacyMask) CONFIGURE_STRING_VALUE(cfg,config,key,ref_key,"refkey") - CONFIGURE_INT_VALUE(cfg,config,key,publish_expires,"publish_expires") + CONFIGURE_INT_VALUE(cfg,config,key,publish_expires,"publish_expires",int) nat_policy_ref = lp_config_get_string(config, key, "nat_policy_ref", NULL); if (nat_policy_ref != NULL) { @@ -1235,7 +1235,7 @@ static void linphone_proxy_config_activate_sip_setup(LinphoneProxyConfig *cfg){ ms_error("Invalid identity for this proxy configuration."); return; } - caps=sip_setup_context_get_capabilities(ssc); + caps=(unsigned int)sip_setup_context_get_capabilities(ssc); if (caps & SIP_SETUP_CAP_ACCOUNT_MANAGER){ if (sip_setup_context_login_account(ssc,cfg->reg_identity,NULL,NULL)!=0){ { diff --git a/coreapi/sal/sal.c b/coreapi/sal/sal.c index 3870e59e3..28cc29f5f 100644 --- a/coreapi/sal/sal.c +++ b/coreapi/sal/sal.c @@ -896,7 +896,7 @@ static int line_get_value(const char *input, const char *key, char *value, size_ char *equal; size_t len; if (!end) len=strlen(input); - else len=end +1 -input; + else len=(size_t)(end + 1 - input); *read=len; strncpy(line,input,MIN(len,sizeof(line))); equal=strchr(line,'='); diff --git a/coreapi/sipsetup.c b/coreapi/sipsetup.c index a1f22f7d7..fbbbd5c59 100644 --- a/coreapi/sipsetup.c +++ b/coreapi/sipsetup.c @@ -121,7 +121,7 @@ unsigned int sip_setup_get_capabilities(SipSetup *s){ } int sip_setup_context_get_capabilities(SipSetupContext *ctx){ - return ctx->funcs->capabilities; + return (int)ctx->funcs->capabilities; } LinphoneStatus sip_setup_context_create_account(SipSetupContext * ctx, const char *uri, const char *passwd, const char *email, int suscribe){ diff --git a/coreapi/sqlite3_bctbx_vfs.c b/coreapi/sqlite3_bctbx_vfs.c index e43f961e8..d4f122ee6 100755 --- a/coreapi/sqlite3_bctbx_vfs.c +++ b/coreapi/sqlite3_bctbx_vfs.c @@ -77,13 +77,13 @@ static int sqlite3bctbx_Read(sqlite3_file *p, void *buf, int count, sqlite_int64 int ret; sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t*) p; if (pFile){ - ret = (int)bctbx_file_read(pFile->pbctbx_file, buf, count, (off_t)offset); + ret = (int)bctbx_file_read(pFile->pbctbx_file, buf, (size_t)count, (off_t)offset); if( ret==count ){ return SQLITE_OK; } else if( ret >= 0 ){ /*fill in unread portion of buffer, as requested by sqlite3 documentation*/ - memset(((uint8_t*)buf) + ret, 0, count-ret); + memset(((uint8_t*)buf) + ret, 0, (size_t)(count-ret)); return SQLITE_IOERR_SHORT_READ; }else { @@ -106,7 +106,7 @@ static int sqlite3bctbx_Write(sqlite3_file *p, const void *buf, int count, sqlit sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t*) p; int ret; if (pFile ){ - ret = (int)bctbx_file_write(pFile->pbctbx_file, buf, count, (off_t)offset); + ret = (int)bctbx_file_write(pFile->pbctbx_file, buf, (size_t)count, (off_t)offset); if(ret > 0 ) return SQLITE_OK; else { return SQLITE_IOERR_WRITE; diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h index bbdeccc68..eb2ae8336 100644 --- a/include/linphone/utils/utils.h +++ b/include/linphone/utils/utils.h @@ -53,6 +53,10 @@ namespace Utils { LINPHONE_PUBLIC float stof (const std::string &str, size_t *idx = 0); LINPHONE_PUBLIC bool stob (const std::string &str); + LINPHONE_PUBLIC int stoi (const char *str, size_t *idx = 0, int base = 10); + LINPHONE_PUBLIC double stod (const char *str, size_t *idx = 0); + LINPHONE_PUBLIC float stof (const char *str, size_t *idx = 0); + LINPHONE_PUBLIC std::string stringToLower (const std::string &str); // Return a buffer allocated with new. diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index 4d4c35a7f..9db253605 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -176,8 +176,8 @@ MSVideoSize linphone_call_params_get_received_video_size (const LinphoneCallPara MSVideoSize vsize; LinphoneVideoDefinition *vdef = GET_MEDIA_CPP_PTR(params)->getReceivedVideoDefinition(); if (vdef) { - vsize.width = linphone_video_definition_get_width(vdef); - vsize.height = linphone_video_definition_get_height(vdef); + vsize.width = static_cast(linphone_video_definition_get_width(vdef)); + vsize.height = static_cast(linphone_video_definition_get_height(vdef)); } else { vsize.width = MS_VIDEO_SIZE_UNKNOWN_W; vsize.height = MS_VIDEO_SIZE_UNKNOWN_H; @@ -206,8 +206,8 @@ MSVideoSize linphone_call_params_get_sent_video_size (const LinphoneCallParams * MSVideoSize vsize; LinphoneVideoDefinition *vdef = GET_MEDIA_CPP_PTR(params)->getSentVideoDefinition(); if (vdef) { - vsize.width = linphone_video_definition_get_width(vdef); - vsize.height = linphone_video_definition_get_height(vdef); + vsize.width = static_cast(linphone_video_definition_get_width(vdef)); + vsize.height = static_cast(linphone_video_definition_get_height(vdef)); } else { vsize.width = MS_VIDEO_SIZE_UNKNOWN_W; vsize.height = MS_VIDEO_SIZE_UNKNOWN_H; @@ -457,11 +457,11 @@ void linphone_call_params_set_update_call_when_ice_completed (LinphoneCallParams } void linphone_call_params_set_sent_vsize (LinphoneCallParams *params, MSVideoSize vsize) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setSentVideoDefinition(linphone_video_definition_new(vsize.width, vsize.height, nullptr)); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setSentVideoDefinition(linphone_video_definition_new(static_cast(vsize.width), static_cast(vsize.height), nullptr)); } void linphone_call_params_set_recv_vsize (LinphoneCallParams *params, MSVideoSize vsize) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setReceivedVideoDefinition(linphone_video_definition_new(vsize.width, vsize.height, nullptr)); + GET_MEDIA_CPP_PRIVATE_PTR(params)->setReceivedVideoDefinition(linphone_video_definition_new(static_cast(vsize.width), static_cast(vsize.height), nullptr)); } void linphone_call_params_set_sent_video_definition (LinphoneCallParams *params, LinphoneVideoDefinition *vdef) { diff --git a/src/chat/is-composing.cpp b/src/chat/is-composing.cpp index 09bd1ba2a..7a4560aa5 100644 --- a/src/chat/is-composing.cpp +++ b/src/chat/is-composing.cpp @@ -105,7 +105,7 @@ void IsComposing::parse (const string &text) { } void IsComposing::startIdleTimer () { - int duration = getIdleTimerDuration(); + unsigned int duration = getIdleTimerDuration(); if (!idleTimer) { idleTimer = sal_create_timer(core->sal, idleTimerExpired, this, duration * 1000, "composing idle timeout"); @@ -115,7 +115,7 @@ void IsComposing::startIdleTimer () { } void IsComposing::startRefreshTimer () { - int duration = getRefreshTimerDuration(); + unsigned int duration = getRefreshTimerDuration(); if (!refreshTimer) { refreshTimer = sal_create_timer(core->sal, refreshTimerExpired, this, duration * 1000, "composing refresh timeout"); @@ -125,9 +125,9 @@ void IsComposing::startRefreshTimer () { } void IsComposing::startRemoteRefreshTimer (const char *refreshStr) { - int duration = getRemoteRefreshTimerDuration(); + unsigned int duration = getRemoteRefreshTimerDuration(); if (refreshStr) - duration = atoi(refreshStr); + duration = static_cast(stoi(refreshStr)); if (!remoteRefreshTimer) { remoteRefreshTimer = sal_create_timer(core->sal, remoteRefreshTimerExpired, this, duration * 1000, "composing remote refresh timeout"); @@ -180,16 +180,19 @@ void IsComposing::stopRemoteRefreshTimer () { // ----------------------------------------------------------------------------- -int IsComposing::getIdleTimerDuration () { - return lp_config_get_int(core->config, "sip", "composing_idle_timeout", defaultIdleTimeout); +unsigned int IsComposing::getIdleTimerDuration () { + int idleTimerDuration = lp_config_get_int(core->config, "sip", "composing_idle_timeout", defaultIdleTimeout); + return idleTimerDuration < 0 ? 0 : static_cast(idleTimerDuration); } -int IsComposing::getRefreshTimerDuration () { - return lp_config_get_int(core->config, "sip", "composing_refresh_timeout", defaultRefreshTimeout); +unsigned int IsComposing::getRefreshTimerDuration () { + int refreshTimerDuration = lp_config_get_int(core->config, "sip", "composing_refresh_timeout", defaultRefreshTimeout); + return refreshTimerDuration < 0 ? 0 : static_cast(refreshTimerDuration); } -int IsComposing::getRemoteRefreshTimerDuration () { - return lp_config_get_int(core->config, "sip", "composing_remote_refresh_timeout", defaultRemoteRefreshTimeout); +unsigned int IsComposing::getRemoteRefreshTimerDuration () { + int remoteRefreshTimerDuration = lp_config_get_int(core->config, "sip", "composing_remote_refresh_timeout", defaultRemoteRefreshTimeout); + return remoteRefreshTimerDuration < 0 ? 0 : static_cast(remoteRefreshTimerDuration); } void IsComposing::parse (xmlparsing_context_t *xmlCtx) { diff --git a/src/chat/is-composing.h b/src/chat/is-composing.h index f9cc44d7c..d2ea49ded 100644 --- a/src/chat/is-composing.h +++ b/src/chat/is-composing.h @@ -46,9 +46,9 @@ public: void stopTimers (); private: - int getIdleTimerDuration (); - int getRefreshTimerDuration (); - int getRemoteRefreshTimerDuration (); + unsigned int getIdleTimerDuration (); + unsigned int getRefreshTimerDuration (); + unsigned int getRemoteRefreshTimerDuration (); void parse (xmlparsing_context_t *xmlCtx); int idleTimerExpired (unsigned int revents); int refreshTimerExpired (unsigned int revents); diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index 8a65ea4ca..fa96cf675 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -193,7 +193,7 @@ private: void audioStreamAuthTokenReady (const std::string &authToken, bool verified); void audioStreamEncryptionChanged (bool encrypted); uint16_t getAvpfRrInterval () const; - int getNbActiveStreams () const; + unsigned int getNbActiveStreams () const; bool isEncryptionMandatory () const; int mediaParametersChanged (SalMediaDescription *oldMd, SalMediaDescription *newMd); void propagateEncryptionChanged (); diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index b079be8b1..a3f967873 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -942,7 +942,7 @@ int MediaSessionPrivate::selectFixedPort (int streamIndex, pair portRa int MediaSessionPrivate::selectRandomPort (int streamIndex, pair portRange) { for (int nbTries = 0; nbTries < 100; nbTries++) { bool alreadyUsed = false; - int triedPort = (ortp_random() % (portRange.second - portRange.first) + portRange.first) & ~0x1; + int triedPort = (static_cast(ortp_random()) % (portRange.second - portRange.first) + portRange.first) & ~0x1; if (triedPort < portRange.first) triedPort = portRange.first + 2; for (const bctbx_list_t *elem = linphone_core_get_calls(core); elem != nullptr; elem = bctbx_list_next(elem)) { LinphoneCall *lcall = reinterpret_cast(bctbx_list_get_data(elem)); @@ -1516,7 +1516,7 @@ void MediaSessionPrivate::setupEncryptionKeys (SalMediaDescription *md) { } else { const MSCryptoSuite *suites = linphone_core_get_srtp_crypto_suites(core); for (int j = 0; (suites != nullptr) && (suites[j] != MS_CRYPTO_SUITE_INVALID) && (j < SAL_CRYPTO_ALGO_MAX); j++) { - setupEncryptionKey(&md->streams[i].crypto[j], suites[j], j + 1); + setupEncryptionKey(&md->streams[i].crypto[j], suites[j], static_cast(j) + 1); } } } @@ -2850,8 +2850,8 @@ void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { videoStream->staticimage_webcam_fps_optimization = false; const LinphoneVideoDefinition *vdef = linphone_core_get_preferred_video_definition(core); MSVideoSize vsize; - vsize.width = linphone_video_definition_get_width(vdef); - vsize.height = linphone_video_definition_get_height(vdef); + vsize.width = static_cast(linphone_video_definition_get_width(vdef)); + vsize.height = static_cast(linphone_video_definition_get_height(vdef)); video_stream_set_sent_video_size(videoStream, vsize); video_stream_enable_self_view(videoStream, core->video_conf.selfview); if (videoWindowId) @@ -3326,7 +3326,7 @@ uint16_t MediaSessionPrivate::getAvpfRrInterval () const { return rrInterval; } -int MediaSessionPrivate::getNbActiveStreams () const { +unsigned int MediaSessionPrivate::getNbActiveStreams () const { SalMediaDescription *md = nullptr; if (op) md = sal_call_get_remote_media_description(op); @@ -3776,11 +3776,11 @@ void MediaSessionPrivate::updateCurrentParams () const { #ifdef VIDEO_ENABLED if (videoStream) { MSVideoSize vsize = video_stream_get_sent_video_size(videoStream); - vdef = linphone_video_definition_new(vsize.width, vsize.height, nullptr); + vdef = linphone_video_definition_new(static_cast(vsize.width), static_cast(vsize.height), nullptr); currentParams->getPrivate()->setSentVideoDefinition(vdef); linphone_video_definition_unref(vdef); vsize = video_stream_get_received_video_size(videoStream); - vdef = linphone_video_definition_new(vsize.width, vsize.height, nullptr); + vdef = linphone_video_definition_new(static_cast(vsize.width), static_cast(vsize.height), nullptr); currentParams->getPrivate()->setReceivedVideoDefinition(vdef); linphone_video_definition_unref(vdef); currentParams->getPrivate()->setSentFps(video_stream_get_sent_framerate(videoStream)); @@ -4350,8 +4350,8 @@ LinphoneStatus MediaSession::update (const MediaSessionParams *msp) { if (d->videoStream && (d->state == LinphoneCallStreamsRunning)) { const LinphoneVideoDefinition *vdef = linphone_core_get_preferred_video_definition(d->core); MSVideoSize vsize; - vsize.width = linphone_video_definition_get_width(vdef); - vsize.height = linphone_video_definition_get_height(vdef); + vsize.width = static_cast(linphone_video_definition_get_width(vdef)); + vsize.height = static_cast(linphone_video_definition_get_height(vdef)); video_stream_set_sent_video_size(d->videoStream, vsize); video_stream_set_fps(d->videoStream, linphone_core_get_preferred_framerate(d->core)); if (d->cameraEnabled && (d->videoStream->cam != d->core->video_conf.device)) diff --git a/src/nat/ice-agent.cpp b/src/nat/ice-agent.cpp index 63605b3bd..46c686f31 100644 --- a/src/nat/ice-agent.cpp +++ b/src/nat/ice-agent.cpp @@ -152,7 +152,7 @@ void IceAgent::prepareIceForStream (MediaStream *ms, bool createChecklist) { IceCheckList *cl = ice_session_check_list(iceSession, streamIndex); if (!cl && createChecklist) { cl = ice_check_list_new(); - ice_session_add_check_list(iceSession, cl, streamIndex); + ice_session_add_check_list(iceSession, cl, static_cast(streamIndex)); lInfo() << "Created new ICE check list for stream [" << streamIndex << "]"; } if (cl) @@ -206,7 +206,7 @@ void IceAgent::updateFromRemoteMediaDescription (const SalMediaDescription *loca IceCheckList *cl = ice_session_check_list(iceSession, i); if (!cl) continue; if (!sal_stream_description_active(stream)) { - ice_session_remove_check_list_from_idx(iceSession, i); + ice_session_remove_check_list_from_idx(iceSession, static_cast(i)); mediaSession.getPrivate()->clearIceCheckList(cl); } } diff --git a/src/nat/stun-client.cpp b/src/nat/stun-client.cpp index 9f7003fb4..b9dc162af 100644 --- a/src/nat/stun-client.cpp +++ b/src/nat/stun-client.cpp @@ -182,7 +182,7 @@ ortp_socket_t StunClient::createStunSocket (int localPort) { laddr.sin_family = AF_INET; laddr.sin_addr.s_addr = INADDR_ANY; laddr.sin_port = htons(static_cast(localPort)); - if (bind(sock, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) { + if (::bind(sock, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) { lError() << "Bind socket to 0.0.0.0:" << localPort << " failed: " << getSocketError(); close_socket(sock); return -1; @@ -198,7 +198,7 @@ int StunClient::recvStunResponse(ortp_socket_t sock, Candidate &candidate, int & char buf[MS_STUN_MAX_MESSAGE_SIZE]; int len = MS_STUN_MAX_MESSAGE_SIZE; - len = static_cast(recv(sock, buf, len, 0)); + len = static_cast(recv(sock, buf, static_cast(len), 0)); if (len > 0) { struct in_addr ia; MSStunMessage *resp = ms_stun_message_create_from_buffer_parsing((uint8_t *)buf, (ssize_t)len); diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index dda5139b0..877206952 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -89,7 +89,7 @@ int Utils::stoi (const string &str, size_t *idx, int base) { int v = static_cast(strtol(str.c_str(), &p, base)); if (idx) - *idx = p - str.c_str(); + *idx = static_cast(p - str.c_str()); return v; } @@ -99,7 +99,7 @@ double Utils::stod (const string &str, size_t *idx) { double v = strtod(str.c_str(), &p); if (idx) - *idx = p - str.c_str(); + *idx = static_cast(p - str.c_str()); return v; } @@ -109,7 +109,7 @@ float Utils::stof (const string &str, size_t *idx) { float v = strtof(str.c_str(), &p); if (idx) - *idx = p - str.c_str(); + *idx = static_cast(p - str.c_str()); return v; } @@ -119,6 +119,36 @@ bool Utils::stob (const string &str) { return !lowerStr.empty() && (lowerStr == "true" || lowerStr == "1"); } +int Utils::stoi (const char *str, size_t *idx, int base) { + char *p; + int v = static_cast(strtol(str, &p, base)); + + if (idx) + *idx = static_cast(p - str); + + return v; +} + +double Utils::stod (const char *str, size_t *idx) { + char *p; + double v = strtod(str, &p); + + if (idx) + *idx = static_cast(p - str); + + return v; +} + +float Utils::stof (const char *str, size_t *idx) { + char *p; + float v = strtof(str, &p); + + if (idx) + *idx = static_cast(p - str); + + return v; +} + string Utils::stringToLower (const string &str) { string result(str.size(), ' '); transform(str.cbegin(), str.cend(), result.begin(), ::tolower); From 448f5246312f5f42f6781b8fd732ba6056db6389 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 21 Sep 2017 16:55:24 +0200 Subject: [PATCH 0122/2215] feat(c-wrapper): provide a way to link cpp type and c type --- src/c-wrapper/c-wrapper.h | 32 ++++++++++++++++++++++++-------- src/c-wrapper/internal/c-tools.h | 3 +++ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index 704f78866..bc9e24bff 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -25,16 +25,32 @@ // ============================================================================= -#define L_REGISTER_TYPE(C_TYPE) \ - extern Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init (); -#define L_INIT(C_TYPE) \ - _linphone_ ## C_TYPE ## _init () +LINPHONE_BEGIN_NAMESPACE + +template +struct CppTypeToCType { + enum { Defined = false }; +}; + +LINPHONE_END_NAMESPACE + +#define L_REGISTER_TYPE(CPP_TYPE, C_TYPE) \ + extern Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init (); \ + namespace LINPHONE_NAMESPACE { \ + class CPP_TYPE; \ + }; \ + template<> \ + struct LINPHONE_NAMESPACE::CppTypeToCType { \ + enum { Defined = true }; \ + typedef C_TYPE cType; \ + typedef LINPHONE_NAMESPACE::CPP_TYPE cppType; \ + }; // ============================================================================= -L_REGISTER_TYPE(Call); -L_REGISTER_TYPE(ChatMessage); -L_REGISTER_TYPE(ChatRoom); -L_REGISTER_TYPE(Participant); +L_REGISTER_TYPE(Call, Call); +L_REGISTER_TYPE(ChatMessage, ChatMessage); +L_REGISTER_TYPE(ChatRoom, ChatRoom); +L_REGISTER_TYPE(Participant, Participant); #endif // ifndef _C_WRAPPER_H_ diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 71294bdcd..2af90255f 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -350,6 +350,9 @@ LINPHONE_END_NAMESPACE #define L_STRING_TO_C(STR) ((STR).empty() ? NULL : (STR).c_str()) #define L_C_TO_STRING(STR) ((STR) == NULL ? std::string() : (STR)) +// Call the init function of wrapped C object. +#define L_INIT(C_TYPE) _linphone_ ## C_TYPE ## _init () + // Get the cpp-ptr of a wrapped C object. #define L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE) \ LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC< \ From b06df6331a109f74a3eb7063ee6914b68549e8a0 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 21 Sep 2017 17:08:22 +0200 Subject: [PATCH 0123/2215] keep casting --- src/c-wrapper/api/c-call-stats.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/c-wrapper/api/c-call-stats.cpp b/src/c-wrapper/api/c-call-stats.cpp index a4cbe1c9f..e639862e7 100644 --- a/src/c-wrapper/api/c-call-stats.cpp +++ b/src/c-wrapper/api/c-call-stats.cpp @@ -215,7 +215,7 @@ float linphone_call_stats_get_sender_loss_rate (const LinphoneCallStats *stats) return 0.0; /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ if (stats->sent_rtcp->b_cont != NULL) - msgpullup(stats->sent_rtcp, -1); + msgpullup(stats->sent_rtcp, (size_t)-1); do{ if (rtcp_is_SR(stats->sent_rtcp)) @@ -237,7 +237,7 @@ float linphone_call_stats_get_receiver_loss_rate (const LinphoneCallStats *stats return 0.0; /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ if (stats->received_rtcp->b_cont != NULL) - msgpullup(stats->received_rtcp, -1); + msgpullup(stats->received_rtcp, (size_t)-1); do{ if (rtcp_is_RR(stats->received_rtcp)) @@ -267,7 +267,7 @@ float linphone_call_stats_get_sender_interarrival_jitter (const LinphoneCallStat return 0.0; /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ if (stats->sent_rtcp->b_cont != NULL) - msgpullup(stats->sent_rtcp, -1); + msgpullup(stats->sent_rtcp, (size_t)-1); if (rtcp_is_SR(stats->sent_rtcp)) srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0); else if (rtcp_is_RR(stats->sent_rtcp)) @@ -286,7 +286,7 @@ float linphone_call_stats_get_receiver_interarrival_jitter (const LinphoneCallSt return 0.0; /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ if (stats->received_rtcp->b_cont != NULL) - msgpullup(stats->received_rtcp, -1); + msgpullup(stats->received_rtcp, (size_t)-1); if (rtcp_is_SR(stats->received_rtcp)) rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0); else if (rtcp_is_RR(stats->received_rtcp)) From 24c2a4cf87ca5566854ee92608f87b42ebf6faf5 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 21 Sep 2017 17:30:03 +0200 Subject: [PATCH 0124/2215] Fix build of linphonec, linphone-daemon and testers. --- console/commands.c | 2 +- console/linphonec.c | 14 +++---- coreapi/private.h | 2 + coreapi/proxy.c | 2 +- daemon/daemon.cc | 14 +++---- include/linphone/call.h | 2 + src/c-wrapper/api/c-call-stats.cpp | 8 ++++ tester/call_single_tester.c | 66 +++++++++++++++--------------- tester/tester.c | 14 +++---- 9 files changed, 68 insertions(+), 56 deletions(-) diff --git a/console/commands.c b/console/commands.c index e5b62d683..cd178daed 100644 --- a/console/commands.c +++ b/console/commands.c @@ -2492,7 +2492,7 @@ static void lpc_display_call_states(LinphoneCore *lc){ tmp=linphone_call_get_remote_address_as_string (call); flag=in_conference ? "conferencing" : ""; flag=linphone_call_has_transfer_pending(call) ? "transfer pending" : flag; - linphonec_out("%-2i | %-35s | %-15s | %s\n",VOIDPTR_TO_INT(linphone_call_get_user_pointer(call)), + linphonec_out("%-2i | %-35s | %-15s | %s\n",VOIDPTR_TO_INT(linphone_call_get_user_data(call)), tmp,linphone_call_state_to_string(linphone_call_get_state(call))+strlen("LinphoneCall"),flag); ms_free(tmp); } diff --git a/console/linphonec.c b/console/linphonec.c index 8b1fe317b..28124a53f 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -175,7 +175,7 @@ bool_t linphonec_camera_enabled=TRUE; void linphonec_call_identify(LinphoneCall* call){ static int callid=1; - linphone_call_set_user_pointer (call,INT_TO_VOIDPTR(callid)); + linphone_call_set_user_data (call,INT_TO_VOIDPTR(callid)); callid++; } @@ -183,7 +183,7 @@ LinphoneCall *linphonec_get_call(int id){ const MSList *elem=linphone_core_get_calls(linphonec); for (;elem!=NULL;elem=elem->next){ LinphoneCall *call=(LinphoneCall*)elem->data; - if (VOIDPTR_TO_INT(linphone_call_get_user_pointer(call))==id){ + if (VOIDPTR_TO_INT(linphone_call_get_user_data(call))==id){ return call; } } @@ -279,7 +279,7 @@ linphonec_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneC char *remote=linphone_call_get_remote_address_as_string(call); if (new_call_state==LinphoneCallConnected){ linphonec_out("The distant endpoint %s of call %i has been transfered, you can safely close the call.\n", - remote,VOIDPTR_TO_INT(linphone_call_get_user_pointer(call))); + remote,VOIDPTR_TO_INT(linphone_call_get_user_data(call))); } ms_free(remote); } @@ -322,7 +322,7 @@ static void linphonec_call_updated(LinphoneCall *call){ } static void linphonec_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t encrypted, const char *auth_token) { - int id=VOIDPTR_TO_INT(linphone_call_get_user_pointer(call)); + int id=VOIDPTR_TO_INT(linphone_call_get_user_data(call)); if (!encrypted) { linphonec_out("Call %i is not fully encrypted and auth token is %s.\n", id, (auth_token != NULL) ? auth_token : "absent"); @@ -334,7 +334,7 @@ static void linphonec_call_encryption_changed(LinphoneCore *lc, LinphoneCall *ca static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState st, const char *msg){ char *from=linphone_call_get_remote_address_as_string(call); - int id=VOIDPTR_TO_INT(linphone_call_get_user_pointer(call)); + int id=VOIDPTR_TO_INT(linphone_call_get_user_data(call)); switch(st){ case LinphoneCallEnd: linphonec_out("Call %i with %s ended (%s).\n", id, from, linphone_reason_to_string(linphone_call_get_reason(call))); @@ -357,7 +357,7 @@ static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, L case LinphoneCallIncomingReceived: linphonec_call_identify(call); linphone_call_enable_camera (call,linphonec_camera_enabled); - id=VOIDPTR_TO_INT(linphone_call_get_user_pointer(call)); + id=VOIDPTR_TO_INT(linphone_call_get_user_data(call)); linphonec_set_caller(from); linphonec_out("Receiving new incoming call from %s, assigned id %i\n", from,id); if ( auto_answer) { @@ -373,7 +373,7 @@ static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, L break; case LinphoneCallOutgoingInit: linphonec_call_identify(call); - id=VOIDPTR_TO_INT(linphone_call_get_user_pointer(call)); + id=VOIDPTR_TO_INT(linphone_call_get_user_data(call)); linphonec_out("Establishing call id to %s, assigned id %i\n", from,id); break; case LinphoneCallUpdatedByRemote: diff --git a/coreapi/private.h b/coreapi/private.h index fab87f38f..e31361ed1 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -409,6 +409,7 @@ void _linphone_call_stats_uninit(LinphoneCallStats *stats); void _linphone_call_stats_clone(LinphoneCallStats *dst, const LinphoneCallStats *src); void _linphone_call_stats_set_ice_state (LinphoneCallStats *stats, LinphoneIceState state); void _linphone_call_stats_set_type (LinphoneCallStats *stats, LinphoneStreamType type); +mblk_t *_linphone_call_stats_get_received_rtcp (const LinphoneCallStats *stats); void _linphone_call_stats_set_received_rtcp (LinphoneCallStats *stats, mblk_t *m); void _linphone_call_stats_set_sent_rtcp (LinphoneCallStats *stats, mblk_t *m); int _linphone_call_stats_get_updated (const LinphoneCallStats *stats); @@ -419,6 +420,7 @@ void _linphone_call_stats_set_upload_bandwidth (LinphoneCallStats *stats, float void _linphone_call_stats_set_rtcp_download_bandwidth (LinphoneCallStats *stats, float bandwidth); void _linphone_call_stats_set_rtcp_upload_bandwidth (LinphoneCallStats *stats, float bandwidth); void _linphone_call_stats_set_ip_family_of_remote (LinphoneCallStats *stats, LinphoneAddressFamily family); +bool_t _linphone_call_stats_rtcp_received_via_mux (const LinphoneCallStats *stats); void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall *call); void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md, bool_t is_offer); void linphone_call_clear_unused_ice_candidates(LinphoneCall *call, const SalMediaDescription *md); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index ce6d4aa21..c56877c2f 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -119,7 +119,7 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *cf cfg->reg_sendregister = lc ? !!lp_config_get_default_int(lc->config, "proxy", "reg_sendregister", 1) : 1; cfg->dial_prefix = dial_prefix ? ms_strdup(dial_prefix) : NULL; cfg->dial_escape_plus = lc ? !!lp_config_get_default_int(lc->config, "proxy", "dial_escape_plus", 0) : 0; - cfg->privacy = lc ? (LinphonePrivacyMask)lp_config_get_default_int(lc->config, "proxy", "privacy", LinphonePrivacyDefault) : LinphonePrivacyDefault; + cfg->privacy = lc ? (LinphonePrivacyMask)lp_config_get_default_int(lc->config, "proxy", "privacy", LinphonePrivacyDefault) : (LinphonePrivacyMask)LinphonePrivacyDefault; cfg->identity_address = identity ? linphone_address_new(identity) : NULL; cfg->reg_identity = cfg->identity_address ? linphone_address_as_string(cfg->identity_address) : NULL; cfg->reg_proxy = proxy ? ms_strdup(proxy) : NULL; diff --git a/daemon/daemon.cc b/daemon/daemon.cc index 907972976..af2474cb8 100644 --- a/daemon/daemon.cc +++ b/daemon/daemon.cc @@ -166,19 +166,19 @@ CallStatsResponse::CallStatsResponse(Daemon *daemon, LinphoneCall *call, const L ostr << "Event-type: call-stats\n"; ostr << "Id: " << daemon->updateCallId(call) << "\n"; ostr << "Type: "; - if (stats->type == LINPHONE_CALL_STATS_AUDIO) { + if (linphone_call_stats_get_type(stats) == LINPHONE_CALL_STATS_AUDIO) { ostr << "Audio"; } else { ostr << "Video"; } ostr << "\n"; } else { - prefix = ((stats->type == LINPHONE_CALL_STATS_AUDIO) ? "Audio-" : "Video-"); + prefix = ((linphone_call_stats_get_type(stats) == LINPHONE_CALL_STATS_AUDIO) ? "Audio-" : "Video-"); } printCallStatsHelper(ostr, stats, prefix); - if (stats->type == LINPHONE_CALL_STATS_AUDIO) { + if (linphone_call_stats_get_type(stats) == LINPHONE_CALL_STATS_AUDIO) { const PayloadType *audioCodec = linphone_call_params_get_used_audio_codec(callParams); ostr << PayloadTypeResponse(linphone_call_get_core(call), audioCodec, -1, prefix, false).getBody() << "\n"; } else { @@ -353,9 +353,9 @@ LinphoneSoundDaemon *Daemon::getLSD() { } int Daemon::updateCallId(LinphoneCall *call) { - int val = VOIDPTR_TO_INT(linphone_call_get_user_pointer(call)); + int val = VOIDPTR_TO_INT(linphone_call_get_user_data(call)); if (val == 0) { - linphone_call_set_user_pointer(call, INT_TO_VOIDPTR(++mCallIds)); + linphone_call_set_user_data(call, INT_TO_VOIDPTR(++mCallIds)); return mCallIds; } return val; @@ -365,7 +365,7 @@ LinphoneCall *Daemon::findCall(int id) { const bctbx_list_t *elem = linphone_core_get_calls(mLc); for (; elem != NULL; elem = elem->next) { LinphoneCall *call = (LinphoneCall *) elem->data; - if (VOIDPTR_TO_INT(linphone_call_get_user_pointer(call)) == id) + if (VOIDPTR_TO_INT(linphone_call_get_user_data(call)) == id) return call; } return NULL; @@ -518,7 +518,7 @@ void Daemon::callStateChanged(LinphoneCall *call, LinphoneCallState state, const void Daemon::callStatsUpdated(LinphoneCall *call, const LinphoneCallStats *stats) { if (mUseStatsEvents) { /* don't queue periodical updates (3 per seconds for just bandwidth updates) */ - if (!(stats->updated & LINPHONE_CALL_STATS_PERIODICAL_UPDATE)){ + if (!(_linphone_call_stats_get_updated(stats) & LINPHONE_CALL_STATS_PERIODICAL_UPDATE)){ mEventQueue.push(new CallStatsResponse(this, call, stats, true)); } } diff --git a/include/linphone/call.h b/include/linphone/call.h index 9446df88e..990d2b360 100644 --- a/include/linphone/call.h +++ b/include/linphone/call.h @@ -21,5 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define LINPHONE_CALL_H #include "linphone/api/c-call.h" +#include "linphone/api/c-call-cbs.h" +#include "linphone/api/c-call-stats.h" #endif /* LINPHONE_CALL_H */ diff --git a/src/c-wrapper/api/c-call-stats.cpp b/src/c-wrapper/api/c-call-stats.cpp index e639862e7..aa63cd2fd 100644 --- a/src/c-wrapper/api/c-call-stats.cpp +++ b/src/c-wrapper/api/c-call-stats.cpp @@ -106,6 +106,10 @@ void _linphone_call_stats_set_type (LinphoneCallStats *stats, LinphoneStreamType stats->type = type; } +mblk_t *_linphone_call_stats_get_received_rtcp (const LinphoneCallStats *stats) { + return stats->received_rtcp; +} + void _linphone_call_stats_set_received_rtcp (LinphoneCallStats *stats, mblk_t *m) { stats->received_rtcp = m; } @@ -146,6 +150,10 @@ void _linphone_call_stats_set_ip_family_of_remote (LinphoneCallStats *stats, Lin stats->rtp_remote_family = family; } +bool_t _linphone_call_stats_rtcp_received_via_mux (const LinphoneCallStats *stats) { + return stats->rtcp_received_via_mux; +} + // ============================================================================= // Public functions // ============================================================================= diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index 472b2072a..cf7f0969c 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -101,28 +101,28 @@ static void rtcp_received(stats* counters, mblk_t *packet) { void call_stats_updated(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *lstats) { stats* counters = get_stats(lc); counters->number_of_LinphoneCallStatsUpdated++; - if (lstats->updated & LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE) { + if (_linphone_call_stats_get_updated(lstats) & LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE) { counters->number_of_rtcp_received++; - if (lstats->rtcp_received_via_mux){ + if (_linphone_call_stats_rtcp_received_via_mux(lstats)){ counters->number_of_rtcp_received_via_mux++; } - rtcp_received(counters, lstats->received_rtcp); + rtcp_received(counters, _linphone_call_stats_get_received_rtcp(lstats)); } - if (lstats->updated & LINPHONE_CALL_STATS_SENT_RTCP_UPDATE ) { + if (_linphone_call_stats_get_updated(lstats) & LINPHONE_CALL_STATS_SENT_RTCP_UPDATE ) { counters->number_of_rtcp_sent++; } - if (lstats->updated & LINPHONE_CALL_STATS_PERIODICAL_UPDATE ) { + if (_linphone_call_stats_get_updated(lstats) & LINPHONE_CALL_STATS_PERIODICAL_UPDATE ) { int tab_size = sizeof (counters->audio_download_bandwidth)/sizeof(int); - int index = (counters->current_bandwidth_index[lstats->type]++) % tab_size; + int index = (counters->current_bandwidth_index[linphone_call_stats_get_type(lstats)]++) % tab_size; LinphoneCallStats *audio_stats, *video_stats; audio_stats = linphone_call_get_audio_stats(call); video_stats = linphone_call_get_video_stats(call); - if (lstats->type == LINPHONE_CALL_STATS_AUDIO) { - counters->audio_download_bandwidth[index] = (int)audio_stats->download_bandwidth; - counters->audio_upload_bandwidth[index] = (int)audio_stats->upload_bandwidth; + if (linphone_call_stats_get_type(lstats) == LINPHONE_CALL_STATS_AUDIO) { + counters->audio_download_bandwidth[index] = (int)linphone_call_stats_get_download_bandwidth(audio_stats); + counters->audio_upload_bandwidth[index] = (int)linphone_call_stats_get_upload_bandwidth(audio_stats); } else { - counters->video_download_bandwidth[index] = (int)video_stats->download_bandwidth; - counters->video_upload_bandwidth[index] = (int)video_stats->upload_bandwidth; + counters->video_download_bandwidth[index] = (int)linphone_call_stats_get_download_bandwidth(video_stats); + counters->video_upload_bandwidth[index] = (int)linphone_call_stats_get_upload_bandwidth(video_stats); } linphone_call_stats_unref(audio_stats); linphone_call_stats_unref(video_stats); @@ -207,10 +207,10 @@ void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreMana video_stats1 = linphone_call_get_video_stats(c1); audio_stats2 = linphone_call_get_audio_stats(c2); video_stats2 = linphone_call_get_video_stats(c2); - if (audio_stats1->round_trip_delay > 0.0 - && audio_stats2->round_trip_delay > 0.0 - && (!linphone_call_log_video_enabled(linphone_call_get_call_log(c1)) || video_stats1->round_trip_delay>0.0) - && (!linphone_call_log_video_enabled(linphone_call_get_call_log(c2)) || video_stats2->round_trip_delay>0.0)) { + if (linphone_call_stats_get_round_trip_delay(audio_stats1) > 0.0 + && linphone_call_stats_get_round_trip_delay(audio_stats2) > 0.0 + && (!linphone_call_log_video_enabled(linphone_call_get_call_log(c1)) || linphone_call_stats_get_round_trip_delay(video_stats1)>0.0) + && (!linphone_call_log_video_enabled(linphone_call_get_call_log(c2)) || linphone_call_stats_get_round_trip_delay(video_stats2)>0.0)) { break; } @@ -228,33 +228,33 @@ void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreMana if (linphone_core_rtcp_enabled(caller->lc) && linphone_core_rtcp_enabled(callee->lc)) { BC_ASSERT_GREATER(caller->stat.number_of_rtcp_received, 1, int, "%i"); BC_ASSERT_GREATER(callee->stat.number_of_rtcp_received, 1, int, "%i"); - BC_ASSERT_GREATER(audio_stats1->round_trip_delay,0.0,float,"%f"); - BC_ASSERT_GREATER(audio_stats2->round_trip_delay,0.0,float,"%f"); + BC_ASSERT_GREATER(linphone_call_stats_get_round_trip_delay(audio_stats1),0.0,float,"%f"); + BC_ASSERT_GREATER(linphone_call_stats_get_round_trip_delay(audio_stats2),0.0,float,"%f"); if (linphone_call_log_video_enabled(linphone_call_get_call_log(c1))) { - BC_ASSERT_GREATER(video_stats1->round_trip_delay,0.0,float,"%f"); + BC_ASSERT_GREATER(linphone_call_stats_get_round_trip_delay(video_stats1),0.0,float,"%f"); } if (linphone_call_log_video_enabled(linphone_call_get_call_log(c2))) { - BC_ASSERT_GREATER(video_stats2->round_trip_delay,0.0,float,"%f"); + BC_ASSERT_GREATER(linphone_call_stats_get_round_trip_delay(video_stats2),0.0,float,"%f"); } } else { if (linphone_core_rtcp_enabled(caller->lc)) { - BC_ASSERT_EQUAL(audio_stats1->rtp_stats.sent_rtcp_packets, 0, unsigned long long, "%llu"); - BC_ASSERT_EQUAL(audio_stats2->rtp_stats.recv_rtcp_packets, 0, unsigned long long, "%llu"); + BC_ASSERT_EQUAL(linphone_call_stats_get_rtp_stats(audio_stats1)->sent_rtcp_packets, 0, unsigned long long, "%llu"); + BC_ASSERT_EQUAL(linphone_call_stats_get_rtp_stats(audio_stats2)->recv_rtcp_packets, 0, unsigned long long, "%llu"); if (linphone_call_log_video_enabled(linphone_call_get_call_log(c1))) { - BC_ASSERT_EQUAL(video_stats1->rtp_stats.sent_rtcp_packets, 0, unsigned long long, "%llu"); + BC_ASSERT_EQUAL(linphone_call_stats_get_rtp_stats(video_stats1)->sent_rtcp_packets, 0, unsigned long long, "%llu"); } if (linphone_call_log_video_enabled(linphone_call_get_call_log(c2))) { - BC_ASSERT_EQUAL(video_stats2->rtp_stats.recv_rtcp_packets, 0, unsigned long long, "%llu"); + BC_ASSERT_EQUAL(linphone_call_stats_get_rtp_stats(video_stats2)->recv_rtcp_packets, 0, unsigned long long, "%llu"); } } if (linphone_core_rtcp_enabled(callee->lc)) { - BC_ASSERT_EQUAL(audio_stats2->rtp_stats.sent_rtcp_packets, 0, unsigned long long, "%llu"); - BC_ASSERT_EQUAL(audio_stats1->rtp_stats.recv_rtcp_packets, 0, unsigned long long, "%llu"); + BC_ASSERT_EQUAL(linphone_call_stats_get_rtp_stats(audio_stats2)->sent_rtcp_packets, 0, unsigned long long, "%llu"); + BC_ASSERT_EQUAL(linphone_call_stats_get_rtp_stats(audio_stats1)->recv_rtcp_packets, 0, unsigned long long, "%llu"); if (linphone_call_log_video_enabled(linphone_call_get_call_log(c1))) { - BC_ASSERT_EQUAL(video_stats1->rtp_stats.recv_rtcp_packets, 0, unsigned long long, "%llu"); + BC_ASSERT_EQUAL(linphone_call_stats_get_rtp_stats(video_stats1)->recv_rtcp_packets, 0, unsigned long long, "%llu"); } if (linphone_call_log_video_enabled(linphone_call_get_call_log(c2))) { - BC_ASSERT_EQUAL(video_stats2->rtp_stats.sent_rtcp_packets, 0, unsigned long long, "%llu"); + BC_ASSERT_EQUAL(linphone_call_stats_get_rtp_stats(video_stats2)->sent_rtcp_packets, 0, unsigned long long, "%llu"); } } @@ -3622,14 +3622,14 @@ void check_media_direction(LinphoneCoreManager* mgr, LinphoneCall *call, bctbx_l } switch (video_dir) { case LinphoneMediaDirectionInactive: - BC_ASSERT_LOWER((int)stats->upload_bandwidth, 5, int, "%i"); + BC_ASSERT_LOWER((int)linphone_call_stats_get_upload_bandwidth(stats), 5, int, "%i"); break; case LinphoneMediaDirectionSendOnly: expected_recv_iframe = 0; - BC_ASSERT_LOWER((int)stats->download_bandwidth, 5, int, "%i"); + BC_ASSERT_LOWER((int)linphone_call_stats_get_download_bandwidth(stats), 5, int, "%i"); break; case LinphoneMediaDirectionRecvOnly: - BC_ASSERT_LOWER((int)stats->upload_bandwidth, 5, int, "%i"); + BC_ASSERT_LOWER((int)linphone_call_stats_get_upload_bandwidth(stats), 5, int, "%i"); BCTBX_NO_BREAK; /*intentionally no break*/ case LinphoneMediaDirectionSendRecv: expected_recv_iframe = 1; @@ -4018,7 +4018,7 @@ static void call_with_paused_no_sdp_on_resume(void) { wait_for_until(marie->lc, pauline->lc, &dummy, 1, 3000); BC_ASSERT_GREATER(linphone_core_manager_get_max_audio_down_bw(marie),70,int,"%i"); stats = linphone_call_get_audio_stats(linphone_core_get_current_call(pauline->lc)); - BC_ASSERT_TRUE(stats->download_bandwidth>70); + BC_ASSERT_TRUE(linphone_call_stats_get_download_bandwidth(stats)>70); linphone_call_stats_unref(stats); end_call(marie,pauline); end: @@ -5952,8 +5952,8 @@ static void call_with_encryption_mandatory(bool_t caller_has_encryption_mandator /*however we can trust packet_recv from the other party instead */ marie_stats = linphone_call_get_audio_stats(linphone_core_get_current_call(marie->lc)); pauline_stats = linphone_call_get_audio_stats(linphone_core_get_current_call(pauline->lc)); - BC_ASSERT_EQUAL((int)marie_stats->rtp_stats.packet_recv, 0, int, "%i"); - BC_ASSERT_EQUAL((int)pauline_stats->rtp_stats.packet_recv, 0, int, "%i"); + BC_ASSERT_EQUAL((int)linphone_call_stats_get_rtp_stats(marie_stats)->packet_recv, 0, int, "%i"); + BC_ASSERT_EQUAL((int)linphone_call_stats_get_rtp_stats(pauline_stats)->packet_recv, 0, int, "%i"); linphone_call_stats_unref(marie_stats); linphone_call_stats_unref(pauline_stats); end_call(marie, pauline); diff --git a/tester/tester.c b/tester/tester.c index 02771dde2..1f8f94288 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -699,7 +699,7 @@ static void check_ice_from_rtp(LinphoneCall *c1, LinphoneCall *c2, LinphoneStrea } stats = linphone_call_get_audio_stats(c1); - if (stats->ice_state == LinphoneIceStateHostConnection && media_stream_started(ms)) { + if (linphone_call_stats_get_ice_state(stats) == LinphoneIceStateHostConnection && media_stream_started(ms)) { struct sockaddr_storage remaddr; socklen_t remaddrlen = sizeof(remaddr); char ip[NI_MAXHOST] = { 0 }; @@ -758,8 +758,8 @@ bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee, Linph if ((c1 != NULL) && (c2 != NULL)) { LinphoneCallStats *stats1 = linphone_call_get_audio_stats(c1); LinphoneCallStats *stats2 = linphone_call_get_audio_stats(c2); - if (stats1->ice_state==state && - stats2->ice_state==state){ + if (linphone_call_stats_get_ice_state(stats1)==state && + linphone_call_stats_get_ice_state(stats2)==state){ audio_success=TRUE; check_ice_from_rtp(c1,c2,LinphoneStreamTypeAudio); check_ice_from_rtp(c2,c1,LinphoneStreamTypeAudio); @@ -780,8 +780,8 @@ bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee, Linph if ((c1 != NULL) && (c2 != NULL)) { LinphoneCallStats *stats1 = linphone_call_get_video_stats(c1); LinphoneCallStats *stats2 = linphone_call_get_video_stats(c2); - if (stats1->ice_state==state && - stats2->ice_state==state){ + if (linphone_call_stats_get_ice_state(stats1)==state && + linphone_call_stats_get_ice_state(stats2)==state){ video_success=TRUE; check_ice_from_rtp(c1,c2,LinphoneStreamTypeVideo); check_ice_from_rtp(c2,c1,LinphoneStreamTypeVideo); @@ -802,8 +802,8 @@ bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee, Linph if ((c1 != NULL) && (c2 != NULL)) { LinphoneCallStats *stats1 = linphone_call_get_text_stats(c1); LinphoneCallStats *stats2 = linphone_call_get_text_stats(c2); - if (stats1->ice_state==state && - stats2->ice_state==state){ + if (linphone_call_stats_get_ice_state(stats1)==state && + linphone_call_stats_get_ice_state(stats2)==state){ text_success=TRUE; check_ice_from_rtp(c1,c2,LinphoneStreamTypeText); check_ice_from_rtp(c2,c1,LinphoneStreamTypeText); From 770c8c8e155a75977f684a4870b5943c6e15ec67 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 21 Sep 2017 17:44:12 +0200 Subject: [PATCH 0125/2215] Do not put private chat message stuff in the public headers. --- coreapi/private.h | 34 ++++++++++++++++ include/linphone/api/c-chat-message.h | 58 --------------------------- src/c-wrapper/api/c-chat-room.cpp | 1 + 3 files changed, 35 insertions(+), 58 deletions(-) diff --git a/coreapi/private.h b/coreapi/private.h index e31361ed1..914685918 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -1108,6 +1108,40 @@ void linphone_core_message_storage_init(LinphoneCore *lc); void linphone_core_message_storage_close(LinphoneCore *lc); void linphone_core_message_storage_set_debug(LinphoneCore *lc, bool_t debug); +void linphone_chat_message_set_time(LinphoneChatMessage* msg, time_t time); +void linphone_chat_message_set_incoming(LinphoneChatMessage *msg); +void linphone_chat_message_set_outgoing(LinphoneChatMessage *msg); +void linphone_chat_message_set_message_state_changed_cb(LinphoneChatMessage* msg, LinphoneChatMessageStateChangedCb cb); +void linphone_chat_message_set_message_state_changed_cb_user_data(LinphoneChatMessage* msg, void *user_data); +void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChatMessage* msg); +void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessageState state); +void linphone_chat_message_set_message_id(LinphoneChatMessage *msg, char *id); +void linphone_chat_message_set_is_read(LinphoneChatMessage *msg, bool_t is_read); +void linphone_chat_message_set_storage_id(LinphoneChatMessage *msg, unsigned int id); +SalCustomHeader * linphone_chat_message_get_sal_custom_headers(const LinphoneChatMessage *msg); +void linphone_chat_message_set_sal_custom_headers(LinphoneChatMessage *msg, SalCustomHeader *header); +belle_http_request_t * linphone_chat_message_get_http_request(const LinphoneChatMessage *msg); +void linphone_chat_message_set_http_request(LinphoneChatMessage *msg, belle_http_request_t *request); +void linphone_chat_message_set_file_transfer_information(LinphoneChatMessage *msg, LinphoneContent *content); +LinphoneChatMessageDir linphone_chat_message_get_direction(const LinphoneChatMessage *msg); +SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg); +void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, SalOp *op); +void linphone_chat_message_set_chat_room(LinphoneChatMessage *msg, LinphoneChatRoom *room); +void linphone_chat_message_destroy(LinphoneChatMessage* msg); +void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state); +void linphone_chat_message_set_is_secured(LinphoneChatMessage *msg, bool_t secured); +void linphone_chat_message_send_delivery_notification(LinphoneChatMessage *cm, LinphoneReason reason); +void linphone_chat_message_send_display_notification(LinphoneChatMessage *cm); +void _linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg, bool_t unref); +int linphone_chat_room_upload_file(LinphoneChatMessage *msg); +LinphoneChatRoom *_linphone_core_create_chat_room_from_call(LinphoneCall *call); +void linphone_chat_room_remove_transient_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg); +void linphone_chat_message_deactivate(LinphoneChatMessage *msg); +void linphone_chat_message_release(LinphoneChatMessage *msg); +void create_file_transfer_information_from_vnd_gsma_rcs_ft_http_xml(LinphoneChatMessage *msg); +void linphone_chat_message_fetch_content_from_database(sqlite3 *db, LinphoneChatMessage *message, int content_id); +void linphone_chat_message_send_imdn(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason); + void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID id); bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc); const char *linphone_core_create_uuid(LinphoneCore *lc); diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index 03cc38816..bf69e0df7 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -19,7 +19,6 @@ #ifndef _C_CHAT_MESSAGE_H_ #define _C_CHAT_MESSAGE_H_ -#include "sal/sal.h" #include "linphone/api/c-types.h" #include "linphone/api/c-chat-message-cbs.h" @@ -192,46 +191,6 @@ LINPHONE_PUBLIC const char * linphone_chat_message_get_file_transfer_filepath(Li // ============================================================================= -void linphone_chat_message_set_time(LinphoneChatMessage* msg, time_t time); - -void linphone_chat_message_set_incoming(LinphoneChatMessage *msg); - -void linphone_chat_message_set_outgoing(LinphoneChatMessage *msg); - -void linphone_chat_message_set_message_state_changed_cb(LinphoneChatMessage* msg, LinphoneChatMessageStateChangedCb cb); - -void linphone_chat_message_set_message_state_changed_cb_user_data(LinphoneChatMessage* msg, void *user_data); - -void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChatMessage* msg); - -void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessageState state); - -void linphone_chat_message_set_message_id(LinphoneChatMessage *msg, char *id); - -void linphone_chat_message_set_is_read(LinphoneChatMessage *msg, bool_t is_read); - -void linphone_chat_message_set_storage_id(LinphoneChatMessage *msg, unsigned int id); - -SalCustomHeader * linphone_chat_message_get_sal_custom_headers(const LinphoneChatMessage *msg); - -void linphone_chat_message_set_sal_custom_headers(LinphoneChatMessage *msg, SalCustomHeader *header); - -belle_http_request_t * linphone_chat_message_get_http_request(const LinphoneChatMessage *msg); - -void linphone_chat_message_set_http_request(LinphoneChatMessage *msg, belle_http_request_t *request); - -void linphone_chat_message_set_file_transfer_information(LinphoneChatMessage *msg, LinphoneContent *content); - -LinphoneChatMessageDir linphone_chat_message_get_direction(const LinphoneChatMessage *msg); - -SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg); - -void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, SalOp *op); - -void linphone_chat_message_set_chat_room(LinphoneChatMessage *msg, LinphoneChatRoom *room); - -// ============================================================================= - LINPHONE_PUBLIC unsigned int linphone_chat_message_store(LinphoneChatMessage *msg); /** @@ -406,23 +365,6 @@ LINPHONE_PUBLIC LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessag */ LINPHONE_PUBLIC LinphoneChatMessageCbs * linphone_chat_message_get_callbacks(const LinphoneChatMessage *msg); -// ============================================================================= - -void linphone_chat_message_destroy(LinphoneChatMessage* msg); -void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state); -void linphone_chat_message_set_is_secured(LinphoneChatMessage *msg, bool_t secured); -void linphone_chat_message_send_delivery_notification(LinphoneChatMessage *cm, LinphoneReason reason); -void linphone_chat_message_send_display_notification(LinphoneChatMessage *cm); -void _linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg, bool_t unref); -int linphone_chat_room_upload_file(LinphoneChatMessage *msg); -LinphoneChatRoom *_linphone_core_create_chat_room_from_call(LinphoneCall *call); -void linphone_chat_room_remove_transient_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg); -void linphone_chat_message_deactivate(LinphoneChatMessage *msg); -void linphone_chat_message_release(LinphoneChatMessage *msg); -void create_file_transfer_information_from_vnd_gsma_rcs_ft_http_xml(LinphoneChatMessage *msg); -void linphone_chat_message_fetch_content_from_database(sqlite3 *db, LinphoneChatMessage *message, int content_id); -void linphone_chat_message_send_imdn(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason); - /** * @} */ diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 35bef9a47..f2662f08c 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -19,6 +19,7 @@ // TODO: Remove me later. #include "linphone/chat.h" +#include "linphone/wrapper_utils.h" #include "linphone/api/c-chat-room.h" #include "c-wrapper/c-wrapper.h" From be604611b3e490376fa8e69905268335847a6bb7 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 21 Sep 2017 17:51:31 +0200 Subject: [PATCH 0126/2215] Remove deprecated GTK user interface code. --- CMakeLists.txt | 25 - cmake/FindGtkMacIntegration.cmake | 54 - gtk/.gitignore | 5 - gtk/CMakeLists.txt | 133 - gtk/Makefile.am | 118 - gtk/about.ui | 61 - gtk/audio_assistant.c | 551 --- gtk/audio_assistant.ui | 21 - gtk/buddylookup.c | 305 -- gtk/buddylookup.ui | 159 - gtk/call_logs.ui | 119 - gtk/call_statistics.ui | 293 -- gtk/callee_frame.ui | 84 - gtk/calllogs.c | 424 --- gtk/chat.c | 683 ---- gtk/chatroom_frame.ui | 127 - gtk/conf_frame.ui | 85 - gtk/conference.c | 183 - gtk/config-fetching.c | 97 - gtk/config-uri.ui | 97 - gtk/contact.ui | 216 -- gtk/dscp_settings.ui | 178 - gtk/fonis.c | 22 - gtk/friendlist.c | 1104 ------ gtk/gtkrc | 4 - gtk/gtkrc.mac | 1 - gtk/in_call_frame.ui | 433 --- gtk/incall_view.c | 1027 ------ gtk/keypad.ui | 265 -- gtk/ldap.ui | 669 ---- gtk/linphone.h | 379 -- gtk/linphone.ico | Bin 97566 -> 0 bytes gtk/linphone.iss | 90 - gtk/linphone.rc | 5 - gtk/log.ui | 113 - gtk/logging.c | 373 -- gtk/login_frame.ui | 250 -- gtk/loginframe.c | 185 - gtk/mac.m | 47 - gtk/main.c | 2383 ------------ gtk/main.ui | 1056 ------ gtk/p2pwizard.ui | 129 - gtk/parameters.ui | 3183 ----------------- gtk/password.ui | 139 - gtk/propertybox.c | 1966 ---------- gtk/provisioning-fetch.ui | 53 - gtk/regex.h | 67 - gtk/setup_wizard.ui | 736 ---- gtk/setupwizard.c | 360 -- gtk/setupwizard.h | 35 - gtk/singleinstance.c | 127 - gtk/sip_account.ui | 395 -- gtk/status_icon.c | 546 --- gtk/status_icon.h | 65 - gtk/status_notifier.c | 643 ---- gtk/status_notifier.h | 163 - gtk/stock_people.png | Bin 764 -> 0 bytes gtk/support.c | 257 -- gtk/tunnel_config.ui | 407 --- gtk/update.c | 157 - gtk/utils.c | 178 - gtk/videowindow.c | 394 -- gtk/waiting.ui | 56 - pixmaps/.gitignore | 2 - pixmaps/CMakeLists.txt | 140 - pixmaps/Makefile.am | 104 - pixmaps/index.theme | 1836 ---------- pixmaps/linphone-add-call.png | Bin 2808 -> 0 bytes pixmaps/linphone-banner.png | Bin 8708 -> 0 bytes pixmaps/linphone-call-status-incoming.png | Bin 2077 -> 0 bytes pixmaps/linphone-call-status-missed.png | Bin 2122 -> 0 bytes pixmaps/linphone-call-status-outgoing.png | Bin 2140 -> 0 bytes pixmaps/linphone-call-transfer.png | Bin 2713 -> 0 bytes pixmaps/linphone-camera-disabled.png | Bin 1599 -> 0 bytes pixmaps/linphone-camera-enabled.png | Bin 871 -> 0 bytes .../linphone-chat-new-message-and-writing.png | Bin 2029 -> 0 bytes pixmaps/linphone-chat-new-message.png | Bin 1901 -> 0 bytes pixmaps/linphone-chat-nothing.png | Bin 2222 -> 0 bytes pixmaps/linphone-chat-send.png | Bin 1436 -> 0 bytes pixmaps/linphone-chat-writing.png | Bin 2372 -> 0 bytes pixmaps/linphone-conference-start.png | Bin 2691 -> 0 bytes pixmaps/linphone-contact-add.png | Bin 2006 -> 0 bytes pixmaps/linphone-delete.png | Bin 1190 -> 0 bytes pixmaps/linphone-edit.png | Bin 1758 -> 0 bytes pixmaps/linphone-failed.png | Bin 1998 -> 0 bytes pixmaps/linphone-history.png | Bin 1726 -> 0 bytes pixmaps/linphone-hold-off.png | Bin 338 -> 0 bytes pixmaps/linphone-hold-on.png | Bin 364 -> 0 bytes pixmaps/linphone-inprogress.png | Bin 2219 -> 0 bytes pixmaps/linphone-media-pause.png | Bin 1947 -> 0 bytes pixmaps/linphone-media-play.png | Bin 2357 -> 0 bytes pixmaps/linphone-micro-enabled.png | Bin 1714 -> 0 bytes pixmaps/linphone-micro-muted.png | Bin 1745 -> 0 bytes pixmaps/linphone-ok.png | Bin 1326 -> 0 bytes pixmaps/linphone-record.png | Bin 2409 -> 0 bytes pixmaps/linphone-security-ok.png | Bin 694 -> 0 bytes pixmaps/linphone-security-pending.png | Bin 707 -> 0 bytes pixmaps/linphone-speaker-enabled.png | Bin 1294 -> 0 bytes pixmaps/linphone-speaker-muted.png | Bin 1976 -> 0 bytes pixmaps/linphone-start-call.png | Bin 2587 -> 0 bytes pixmaps/linphone-start-call2.png | Bin 2899 -> 0 bytes pixmaps/linphone-start-chat.png | Bin 2079 -> 0 bytes pixmaps/linphone-status-away.png | Bin 1074 -> 0 bytes pixmaps/linphone-status-donotdisturb.png | Bin 755 -> 0 bytes pixmaps/linphone-status-offline.png | Bin 1071 -> 0 bytes pixmaps/linphone-status-online.png | Bin 1143 -> 0 bytes pixmaps/linphone-stop-call.png | Bin 1092 -> 0 bytes pixmaps/linphone-take-screenshot.png | Bin 1865 -> 0 bytes pixmaps/linphone-warning.png | Bin 1004 -> 0 bytes pixmaps/linphone.icns | Bin 36705 -> 0 bytes pixmaps/linphone.png | Bin 2733 -> 0 bytes pixmaps/svg/linphone-add-call.svg | 89 - pixmaps/svg/linphone-call-status-incoming.svg | 80 - pixmaps/svg/linphone-call-status-missed.svg | 86 - pixmaps/svg/linphone-call-status-outgoing.svg | 78 - pixmaps/svg/linphone-call-transfer.svg | 104 - pixmaps/svg/linphone-camera-disabled.svg | 95 - pixmaps/svg/linphone-camera-enabled.svg | 90 - .../linphone-chat-new-message-and-writing.svg | 76 - pixmaps/svg/linphone-chat-new-message.svg | 69 - pixmaps/svg/linphone-chat-nothing.svg | 69 - pixmaps/svg/linphone-chat-send.svg | 70 - pixmaps/svg/linphone-chat-writing.svg | 73 - pixmaps/svg/linphone-conference-start.svg | 66 - pixmaps/svg/linphone-contact-add.svg | 17 - pixmaps/svg/linphone-delete.svg | 17 - pixmaps/svg/linphone-edit.svg | 15 - pixmaps/svg/linphone-failed.svg | 73 - pixmaps/svg/linphone-history.svg | 96 - pixmaps/svg/linphone-hold-off.svg | 66 - pixmaps/svg/linphone-hold-on.svg | 65 - pixmaps/svg/linphone-inprogress.svg | 66 - pixmaps/svg/linphone-logo.svg | 96 - pixmaps/svg/linphone-media-pause.svg | 72 - pixmaps/svg/linphone-media-play.svg | 73 - pixmaps/svg/linphone-micro-enabled.svg | 78 - pixmaps/svg/linphone-micro-muted.svg | 90 - pixmaps/svg/linphone-ok.svg | 95 - pixmaps/svg/linphone-record.svg | 78 - pixmaps/svg/linphone-security-ok.svg | 76 - pixmaps/svg/linphone-security-pending.svg | 76 - pixmaps/svg/linphone-speaker-enabled.svg | 87 - pixmaps/svg/linphone-speaker-muted.svg | 76 - pixmaps/svg/linphone-start-call.svg | 73 - pixmaps/svg/linphone-start-call2.svg | 69 - pixmaps/svg/linphone-start-chat.svg | 77 - pixmaps/svg/linphone-status-away.svg | 66 - pixmaps/svg/linphone-status-donotdisturb.svg | 72 - pixmaps/svg/linphone-status-offline.svg | 72 - pixmaps/svg/linphone-status-online.svg | 66 - pixmaps/svg/linphone-stop-call.svg | 70 - pixmaps/svg/linphone-warning.svg | 106 - pixmaps/svg/linphone.svg | 83 - po/.gitignore | 7 - po/CMakeLists.txt | 32 - po/ChangeLog | 97 - po/Makevars | 41 - po/Makevars.template | 41 - po/POTFILES.in | 50 - po/POTFILES.skip | 56 - po/README | 13 - po/Rules-quot | 47 - po/ar.po | 2107 ----------- po/boldquot.sed | 10 - po/cs.po | 2095 ----------- po/de.po | 2094 ----------- po/en@boldquot.header | 25 - po/en@quot.header | 22 - po/es.po | 2090 ----------- po/fi.po | 2090 ----------- po/fr.po | 2094 ----------- po/he.po | 2094 ----------- po/hu.po | 2090 ----------- po/insert-header.sin | 23 - po/it.po | 2091 ----------- po/ja.po | 2087 ----------- po/lt.po | 2094 ----------- po/nb_NO.po | 2090 ----------- po/nl.po | 2090 ----------- po/pl.po | 2093 ----------- po/pt_BR.po | 2089 ----------- po/quot.sed | 6 - po/remove-potcdate.sin | 19 - po/ru.po | 2102 ----------- po/sr.po | 2094 ----------- po/sv.po | 2091 ----------- po/tr.po | 2091 ----------- po/zh_CN.po | 2085 ----------- po/zh_TW.po | 2085 ----------- 189 files changed, 72098 deletions(-) delete mode 100644 cmake/FindGtkMacIntegration.cmake delete mode 100644 gtk/.gitignore delete mode 100644 gtk/CMakeLists.txt delete mode 100644 gtk/Makefile.am delete mode 100644 gtk/about.ui delete mode 100644 gtk/audio_assistant.c delete mode 100644 gtk/audio_assistant.ui delete mode 100644 gtk/buddylookup.c delete mode 100644 gtk/buddylookup.ui delete mode 100644 gtk/call_logs.ui delete mode 100644 gtk/call_statistics.ui delete mode 100644 gtk/callee_frame.ui delete mode 100644 gtk/calllogs.c delete mode 100644 gtk/chat.c delete mode 100644 gtk/chatroom_frame.ui delete mode 100644 gtk/conf_frame.ui delete mode 100644 gtk/conference.c delete mode 100644 gtk/config-fetching.c delete mode 100644 gtk/config-uri.ui delete mode 100644 gtk/contact.ui delete mode 100644 gtk/dscp_settings.ui delete mode 100644 gtk/fonis.c delete mode 100644 gtk/friendlist.c delete mode 100644 gtk/gtkrc delete mode 100644 gtk/gtkrc.mac delete mode 100644 gtk/in_call_frame.ui delete mode 100644 gtk/incall_view.c delete mode 100644 gtk/keypad.ui delete mode 100644 gtk/ldap.ui delete mode 100644 gtk/linphone.h delete mode 100755 gtk/linphone.ico delete mode 100755 gtk/linphone.iss delete mode 100755 gtk/linphone.rc delete mode 100644 gtk/log.ui delete mode 100644 gtk/logging.c delete mode 100644 gtk/login_frame.ui delete mode 100644 gtk/loginframe.c delete mode 100644 gtk/mac.m delete mode 100644 gtk/main.c delete mode 100644 gtk/main.ui delete mode 100644 gtk/p2pwizard.ui delete mode 100644 gtk/parameters.ui delete mode 100644 gtk/password.ui delete mode 100644 gtk/propertybox.c delete mode 100644 gtk/provisioning-fetch.ui delete mode 100644 gtk/regex.h delete mode 100644 gtk/setup_wizard.ui delete mode 100644 gtk/setupwizard.c delete mode 100644 gtk/setupwizard.h delete mode 100644 gtk/singleinstance.c delete mode 100644 gtk/sip_account.ui delete mode 100644 gtk/status_icon.c delete mode 100644 gtk/status_icon.h delete mode 100644 gtk/status_notifier.c delete mode 100644 gtk/status_notifier.h delete mode 100644 gtk/stock_people.png delete mode 100644 gtk/support.c delete mode 100644 gtk/tunnel_config.ui delete mode 100644 gtk/update.c delete mode 100644 gtk/utils.c delete mode 100644 gtk/videowindow.c delete mode 100644 gtk/waiting.ui delete mode 100644 pixmaps/.gitignore delete mode 100644 pixmaps/CMakeLists.txt delete mode 100644 pixmaps/Makefile.am delete mode 100644 pixmaps/index.theme delete mode 100644 pixmaps/linphone-add-call.png delete mode 100644 pixmaps/linphone-banner.png delete mode 100644 pixmaps/linphone-call-status-incoming.png delete mode 100644 pixmaps/linphone-call-status-missed.png delete mode 100644 pixmaps/linphone-call-status-outgoing.png delete mode 100644 pixmaps/linphone-call-transfer.png delete mode 100644 pixmaps/linphone-camera-disabled.png delete mode 100644 pixmaps/linphone-camera-enabled.png delete mode 100644 pixmaps/linphone-chat-new-message-and-writing.png delete mode 100644 pixmaps/linphone-chat-new-message.png delete mode 100644 pixmaps/linphone-chat-nothing.png delete mode 100644 pixmaps/linphone-chat-send.png delete mode 100644 pixmaps/linphone-chat-writing.png delete mode 100644 pixmaps/linphone-conference-start.png delete mode 100644 pixmaps/linphone-contact-add.png delete mode 100644 pixmaps/linphone-delete.png delete mode 100644 pixmaps/linphone-edit.png delete mode 100644 pixmaps/linphone-failed.png delete mode 100644 pixmaps/linphone-history.png delete mode 100644 pixmaps/linphone-hold-off.png delete mode 100644 pixmaps/linphone-hold-on.png delete mode 100644 pixmaps/linphone-inprogress.png delete mode 100644 pixmaps/linphone-media-pause.png delete mode 100644 pixmaps/linphone-media-play.png delete mode 100644 pixmaps/linphone-micro-enabled.png delete mode 100644 pixmaps/linphone-micro-muted.png delete mode 100644 pixmaps/linphone-ok.png delete mode 100644 pixmaps/linphone-record.png delete mode 100644 pixmaps/linphone-security-ok.png delete mode 100644 pixmaps/linphone-security-pending.png delete mode 100644 pixmaps/linphone-speaker-enabled.png delete mode 100644 pixmaps/linphone-speaker-muted.png delete mode 100644 pixmaps/linphone-start-call.png delete mode 100644 pixmaps/linphone-start-call2.png delete mode 100644 pixmaps/linphone-start-chat.png delete mode 100644 pixmaps/linphone-status-away.png delete mode 100644 pixmaps/linphone-status-donotdisturb.png delete mode 100644 pixmaps/linphone-status-offline.png delete mode 100644 pixmaps/linphone-status-online.png delete mode 100644 pixmaps/linphone-stop-call.png delete mode 100644 pixmaps/linphone-take-screenshot.png delete mode 100644 pixmaps/linphone-warning.png delete mode 100644 pixmaps/linphone.icns delete mode 100644 pixmaps/linphone.png delete mode 100644 pixmaps/svg/linphone-add-call.svg delete mode 100644 pixmaps/svg/linphone-call-status-incoming.svg delete mode 100644 pixmaps/svg/linphone-call-status-missed.svg delete mode 100644 pixmaps/svg/linphone-call-status-outgoing.svg delete mode 100644 pixmaps/svg/linphone-call-transfer.svg delete mode 100644 pixmaps/svg/linphone-camera-disabled.svg delete mode 100644 pixmaps/svg/linphone-camera-enabled.svg delete mode 100644 pixmaps/svg/linphone-chat-new-message-and-writing.svg delete mode 100644 pixmaps/svg/linphone-chat-new-message.svg delete mode 100644 pixmaps/svg/linphone-chat-nothing.svg delete mode 100644 pixmaps/svg/linphone-chat-send.svg delete mode 100644 pixmaps/svg/linphone-chat-writing.svg delete mode 100644 pixmaps/svg/linphone-conference-start.svg delete mode 100644 pixmaps/svg/linphone-contact-add.svg delete mode 100644 pixmaps/svg/linphone-delete.svg delete mode 100644 pixmaps/svg/linphone-edit.svg delete mode 100644 pixmaps/svg/linphone-failed.svg delete mode 100644 pixmaps/svg/linphone-history.svg delete mode 100644 pixmaps/svg/linphone-hold-off.svg delete mode 100644 pixmaps/svg/linphone-hold-on.svg delete mode 100644 pixmaps/svg/linphone-inprogress.svg delete mode 100644 pixmaps/svg/linphone-logo.svg delete mode 100644 pixmaps/svg/linphone-media-pause.svg delete mode 100644 pixmaps/svg/linphone-media-play.svg delete mode 100644 pixmaps/svg/linphone-micro-enabled.svg delete mode 100644 pixmaps/svg/linphone-micro-muted.svg delete mode 100644 pixmaps/svg/linphone-ok.svg delete mode 100644 pixmaps/svg/linphone-record.svg delete mode 100644 pixmaps/svg/linphone-security-ok.svg delete mode 100644 pixmaps/svg/linphone-security-pending.svg delete mode 100644 pixmaps/svg/linphone-speaker-enabled.svg delete mode 100644 pixmaps/svg/linphone-speaker-muted.svg delete mode 100644 pixmaps/svg/linphone-start-call.svg delete mode 100644 pixmaps/svg/linphone-start-call2.svg delete mode 100644 pixmaps/svg/linphone-start-chat.svg delete mode 100644 pixmaps/svg/linphone-status-away.svg delete mode 100644 pixmaps/svg/linphone-status-donotdisturb.svg delete mode 100644 pixmaps/svg/linphone-status-offline.svg delete mode 100644 pixmaps/svg/linphone-status-online.svg delete mode 100644 pixmaps/svg/linphone-stop-call.svg delete mode 100644 pixmaps/svg/linphone-warning.svg delete mode 100644 pixmaps/svg/linphone.svg delete mode 100644 po/.gitignore delete mode 100644 po/CMakeLists.txt delete mode 100644 po/ChangeLog delete mode 100644 po/Makevars delete mode 100644 po/Makevars.template delete mode 100644 po/POTFILES.in delete mode 100755 po/POTFILES.skip delete mode 100644 po/README delete mode 100644 po/Rules-quot delete mode 100644 po/ar.po delete mode 100644 po/boldquot.sed delete mode 100644 po/cs.po delete mode 100644 po/de.po delete mode 100644 po/en@boldquot.header delete mode 100644 po/en@quot.header delete mode 100644 po/es.po delete mode 100644 po/fi.po delete mode 100644 po/fr.po delete mode 100644 po/he.po delete mode 100644 po/hu.po delete mode 100644 po/insert-header.sin delete mode 100644 po/it.po delete mode 100644 po/ja.po delete mode 100644 po/lt.po delete mode 100644 po/nb_NO.po delete mode 100644 po/nl.po delete mode 100644 po/pl.po delete mode 100644 po/pt_BR.po delete mode 100644 po/quot.sed delete mode 100644 po/remove-potcdate.sin delete mode 100644 po/ru.po delete mode 100644 po/sr.po delete mode 100644 po/sv.po delete mode 100644 po/tr.po delete mode 100644 po/zh_CN.po delete mode 100644 po/zh_TW.po diff --git a/CMakeLists.txt b/CMakeLists.txt index d4d620c84..3b8f861b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,6 @@ option(ENABLE_DAEMON "Enable the linphone daemon interface." YES) option(ENABLE_DATE "Use build date in internal version number." NO) option(ENABLE_DEBUG_LOGS "Turn on or off debug level logs." NO) option(ENABLE_DOC "Enable documentation generation with Doxygen." YES) -option(ENABLE_GTK_UI "Turn on or off compilation of gtk interface." NO) option(ENABLE_JAVADOC "Add a target to generate documentation for Java API" NO) option(ENABLE_LDAP "Enable LDAP support." NO) option(ENABLE_NLS "Build with internationalisation support" YES) @@ -160,25 +159,6 @@ if(ENABLE_NOTIFY) set(ENABLE_NOTIFY OFF CACHE BOOL "Enable libnotify support." FORCE) endif() endif() -if(ENABLE_GTK_UI) - if(WIN32) - set(GTK2_ADDITIONAL_SUFFIXES "../lib/glib-2.0/include" "../lib/gtk-2.0/include") - endif() - find_package(GTK2 2.18 REQUIRED gtk) - if(ENABLE_ASSISTANT AND GTK2_VERSION VERSION_LESS 2.22) - message(WARNING "You need at least GTK 2.22 to enable the assistant") - set(ENABLE_ASSISTANT OFF CACHE BOOL "Turn on assistant compiling." FORCE) - endif() - if(APPLE) - find_package(GtkMacIntegration) - if(GTKMACINTEGRATION_FOUND) - set(HAVE_GTK_OSX 1) - add_definitions("${GTKMACINTEGRATION_CPPFLAGS}") - else() - message(WARNING "gtk-mac-integration not found. Please install gtk-osx-application package.") - endif() - endif() -endif() if(ENABLE_ASSISTANT) set(BUILD_WIZARD 1) endif() @@ -368,11 +348,6 @@ endif() if(ENABLE_DAEMON) add_subdirectory(daemon) endif() -if(ENABLE_GTK_UI) - add_subdirectory(gtk) - add_subdirectory(pixmaps) - add_subdirectory(po) -endif() if(ENABLE_TOOLS) add_subdirectory(tools) endif() diff --git a/cmake/FindGtkMacIntegration.cmake b/cmake/FindGtkMacIntegration.cmake deleted file mode 100644 index 17c8efc8c..000000000 --- a/cmake/FindGtkMacIntegration.cmake +++ /dev/null @@ -1,54 +0,0 @@ -############################################################################ -# FindGtkMacIntegration.txt -# Copyright (C) 2015 Belledonne Communications, Grenoble France -# -############################################################################ -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -############################################################################ -# -# - Find the libgtkmacintegration include file and library -# -# GTKMACINTEGRATION_FOUND - system has libgtkmacintegration -# GTKMACINTEGRATION_INCLUDE_DIRS - the libgtkmacintegration include directory -# GTKMACINTEGRATION_LIBRARIES - The libraries needed to use libgtkmacintegration -# GTKMACINTEGRATION_CPPFLAGS - The cflags needed to use libgtkmacintegration - -set(_GTKMACINTEGRATION_ROOT_PATHS - ${CMAKE_INSTALL_PREFIX} -) - -find_path(GTKMACINTEGRATION_INCLUDE_DIRS - NAMES gtkosxapplication.h - HINTS _GTKMACINTEGRATION_ROOT_PATHS - PATH_SUFFIXES include/gtkmacintegration-gtk2 include/gtkmacintegration -) - -find_library(GTKMACINTEGRATION_LIBRARIES - NAMES gtkmacintegration-gtk2 gtkmacintegration - HINTS ${_GTKMACINTEGRATION_ROOT_PATHS} - PATH_SUFFIXES bin lib -) - -set(GTKMACINTEGRATION_CPPFLAGS "-DMAC_INTEGRATION") - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(GTKMACINTEGRATION - DEFAULT_MSG - GTKMACINTEGRATION_INCLUDE_DIRS GTKMACINTEGRATION_LIBRARIES GTKMACINTEGRATION_CPPFLAGS -) - -mark_as_advanced(GTKMACINTEGRATION_INCLUDE_DIRS GTKMACINTEGRATION_LIBRARIES GTKMACINTEGRATION_CPPFLAGS) diff --git a/gtk/.gitignore b/gtk/.gitignore deleted file mode 100644 index b1b1529c6..000000000 --- a/gtk/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -linphone -.libs -.deps -linphone.res - diff --git a/gtk/CMakeLists.txt b/gtk/CMakeLists.txt deleted file mode 100644 index a30704778..000000000 --- a/gtk/CMakeLists.txt +++ /dev/null @@ -1,133 +0,0 @@ -############################################################################ -# CMakeLists.txt -# Copyright (C) 2014 Belledonne Communications, Grenoble France -# -############################################################################ -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -############################################################################ - -set(UI_FILES - about.ui - audio_assistant.ui - buddylookup.ui - callee_frame.ui - call_logs.ui - call_statistics.ui - chatroom_frame.ui - conf_frame.ui - config-uri.ui - contact.ui - dscp_settings.ui - in_call_frame.ui - keypad.ui - ldap.ui - login_frame.ui - log.ui - main.ui - parameters.ui - password.ui - provisioning-fetch.ui - setup_wizard.ui - sip_account.ui - tunnel_config.ui - waiting.ui -) - -set(PIXMAPS stock_people.png) -set(LICENSE ../COPYING) - -set(SOURCE_FILES - audio_assistant.c - buddylookup.c - calllogs.c - chat.c - conference.c - config-fetching.c - friendlist.c - incall_view.c - logging.c - loginframe.c - main.c - propertybox.c - singleinstance.c - status_icon.c - status_notifier.c - support.c - update.c - utils.c - videowindow.c -) - -if(ENABLE_ASSISTANT) - list(APPEND SOURCE_FILES setupwizard.c) -endif() -if(WIN32) - list(APPEND SOURCE_FILES linphone.rc) -endif() - -set(OBJC_FILES) -if (APPLE) - list(APPEND OBJC_FILES mac.m) -endif() - -bc_apply_compile_flags(OBJC_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_OBJC) -bc_apply_compile_flags(SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_C) - -if(WIN32) - add_executable(linphone-gtk WIN32 ${SOURCE_FILES}) -else() - add_executable(linphone-gtk ${SOURCE_FILES} ${OBJC_FILES}) -endif() -set_target_properties(linphone-gtk PROPERTIES OUTPUT_NAME linphone LINKER_LANGUAGE CXX) -target_include_directories(linphone-gtk PUBLIC ${GTK2_INCLUDE_DIRS} ${INTL_INCLUDE_DIRS}) -target_link_libraries(linphone-gtk ${LINPHONE_LIBS_FOR_TOOLS} ${GTK2_LIBRARIES} ${BCTOOLBOX_CORE_LIBRARIES} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES}) -set_target_properties(linphone-gtk PROPERTIES LINK_FLAGS "${LINPHONE_LDFLAGS}") -if(INTL_FOUND) - target_link_libraries(linphone-gtk ${INTL_LIBRARIES}) -endif() -if(WIN32) - target_link_libraries(linphone-gtk Wininet) -endif() -if(ENABLE_NOTIFY) - target_include_directories(linphone-gtk PUBLIC ${NOTIFY_INCLUDE_DIRS}) - target_link_libraries(linphone-gtk ${NOTIFY_LIBRARIES}) -endif() -if(HAVE_LIBUDEV_H) - target_link_libraries(linphone-gtk udev) -endif() -if(GTKMACINTEGRATION_FOUND) - target_include_directories(linphone-gtk PUBLIC ${GTKMACINTEGRATION_INCLUDE_DIRS}) - target_link_libraries(linphone-gtk ${GTKMACINTEGRATION_LIBRARIES}) -endif() -if(APPLE) - target_link_libraries(linphone-gtk "-framework Cocoa") -endif() - -set_target_properties(linphone-gtk PROPERTIES XCODE_ATTRIBUTE_WARNING_CFLAGS "") - - -install(TARGETS linphone-gtk - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE -) - -install(FILES ${UI_FILES} ${PIXMAPS} ${LICENSE} - DESTINATION ${PACKAGE_DATA_DIR}/linphone - PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ -) diff --git a/gtk/Makefile.am b/gtk/Makefile.am deleted file mode 100644 index 82439e3ab..000000000 --- a/gtk/Makefile.am +++ /dev/null @@ -1,118 +0,0 @@ -UI_FILES= about.ui \ - main.ui \ - password.ui \ - contact.ui \ - parameters.ui \ - sip_account.ui \ - call_logs.ui \ - keypad.ui \ - log.ui \ - buddylookup.ui \ - tunnel_config.ui \ - waiting.ui \ - dscp_settings.ui \ - call_statistics.ui \ - ldap.ui \ - config-uri.ui \ - provisioning-fetch.ui \ - audio_assistant.ui \ - chatroom_frame.ui \ - in_call_frame.ui \ - conf_frame.ui \ - callee_frame.ui \ - login_frame.ui \ - setup_wizard.ui - -PIXMAPS= \ - stock_people.png - -LINPHONE_ICO_RC_FILE=linphone.rc -LINPHONE_ICO_FILE=linphone.ico - -EXTRA_DIST= \ - linphone.iss \ - $(LINPHONE_ICO_RC_FILE) \ - $(LINPHONE_ICO_FILE) - gtkrc \ - gtkrc.mac - -if BUILD_GTK_UI - -BUILT_SOURCES=version_date.h - -bin_PROGRAMS=linphone - -linphone_SOURCES= \ - main.c \ - propertybox.c \ - friendlist.c \ - support.c \ - chat.c \ - calllogs.c \ - logging.c \ - update.c \ - buddylookup.c \ - utils.c \ - incall_view.c \ - loginframe.c \ - singleinstance.c \ - conference.c \ - config-fetching.c \ - audio_assistant.c \ - videowindow.c \ - status_icon.c status_icon.h \ - linphone.h regex.h - -if BUILD_WIZARD -linphone_SOURCES+= \ - setupwizard.c setupwizard.h -endif - -if BUILD_STATUS_NOTIFIER -linphone_SOURCES+= \ - status_notifier.c \ - status_notifier.h -endif - - -linphone_LDADD= $(top_builddir)/coreapi/liblinphone.la \ - $(LIBGTK_LIBS) $(NOTIFY1_LIBS) $(NOTIFY4_LIBS) $(LIBGTKMAC_LIBS) $(INTLLIBS) $(SQLITE3_LIBS) $(BELLESIP_LIBS) $(BCTOOLBOX_LIBS) - - -if BUILD_WIN32 - -linphone.res: $(LINPHONE_ICO_RC_FILE) $(LINPHONE_ICO_FILE) - $(WINDRES) $(srcdir)/$(LINPHONE_ICO_RC_FILE) -O coff -o linphone.res - -linphone_LDADD+=linphone.res -lwininet -linphone_LDFLAGS=-Wl,--export-all-symbols -mwindows -else -linphone_LDFLAGS=-export-dynamic -endif - -uidir=$(datadir)/linphone -dist_ui_DATA=$(UI_FILES) $(PIXMAPS) $(top_srcdir)/COPYING - -if BUILD_MACOS -linphone_SOURCES+=mac.m -linphone_LDFLAGS+=-framework Cocoa -endif -endif - - -AM_CPPFLAGS= -I$(top_srcdir)/include/ -I$(top_builddir)/coreapi/ -I$(top_srcdir)/coreapi/ \ - $(MEDIASTREAMER_CFLAGS) \ - $(ORTP_CFLAGS) $(BELLESIP_CFLAGS) \ - $(STRICT_OPTIONS) $(STRICT_OPTIONS_CC) $(LIBGTK_CFLAGS) $(LIBGTKMAC_CFLAGS) $(IPV6_CFLAGS) \ - $(TUNNEL_CFLAGS) \ - $(SQLITE3_CFLAGS) \ - $(BCTOOLBOX_CFLAGS) - -version_date.h: $(top_srcdir)/configure.ac - echo "#define LINPHONE_VERSION_DATE \"$(VERSION)-`date +%y%m%d`\"" > $@ - -newdate: - rm -f version_date.h - -CLEANFILES=version_date.h linphone.res - diff --git a/gtk/about.ui b/gtk/about.ui deleted file mode 100644 index d647724b2..000000000 --- a/gtk/about.ui +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - About Linphone - False - center-on-parent - dialog - False - Linphone - undef - (C) Belledonne Communications, 2010 - - An internet video phone using the standard SIP (rfc3261) protocol. - http://www.linphone.org - GPL - Simon Morlat - - fr: Simon Morlat -en: Simon Morlat and Delphine Perreau -it: Alberto Zanoni <alberto.zanoni@-NO-SPAM-PLEASE!-tiscalinet.it> -de: Jean-Jacques Sarton <jj.sarton@-NO-SPAM-PLEASE-t-online.de> -sv: Daniel Nylander <po@danielnylander.se> -es: Jesus Benitez <gnelson at inMail dot sk> -ja: YAMAGUCHI YOSHIYA <yushiya@anet.ne.jp> -pt_BR: Rafael Caesar Lenzi <rc_lenzi@yahoo.com.br> -pl: Robert Nasiadek <darkone@darkone.pl> -cs: Petr Pisar <petr.pisar@atlas.cz> -hu: anonymous -he: Eli Zaretskii <eliz@gnu.org> - - Icons by kerosine.fr - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - vertical - 2 - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - end - - - False - end - 0 - - - - - - diff --git a/gtk/audio_assistant.c b/gtk/audio_assistant.c deleted file mode 100644 index b9f6d7241..000000000 --- a/gtk/audio_assistant.c +++ /dev/null @@ -1,551 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include - -#include "linphone.h" -#include "linphone/core_utils.h" -#include "mediastreamer2/mediastream.h" -#include "mediastreamer2/msvolume.h" - -static GtkWidget *audio_assistant=NULL; -static void prepare(GtkAssistant *w); - -GtkWidget *get_widget_from_assistant(const char *name){ - return (GtkWidget *)g_object_get_data(G_OBJECT(audio_assistant),name); -} - -static void set_widget_to_assistant(const char *name,GtkWidget *w){ - g_object_set_data(G_OBJECT(audio_assistant),name,w); -} - -static void update_record_button(gboolean is_visible){ - GtkWidget *rec_button = get_widget_from_assistant("rec_button"); - gtk_widget_set_sensitive(rec_button,is_visible); -} - -#if 0 -static void activate_record_button(gboolean is_active){ - GtkWidget *rec_button = get_widget_from_assistant("rec_button"); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rec_button),is_active); -} -#endif - -static void update_play_button(gboolean is_visible){ - GtkWidget *play_button = get_widget_from_assistant("play_button"); - gtk_widget_set_sensitive(play_button,is_visible); -} - -static void activate_play_button(gboolean is_active){ - GtkWidget *play_button = get_widget_from_assistant("play_button"); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(play_button),is_active); -} - -static gboolean deactivate_play_button(void){ - activate_play_button(FALSE); - return FALSE; -} - -static gchar *get_record_file(void){ - char filename[256]={0}; - char date[64]={0}; - time_t curtime=time(NULL); - struct tm loctime; - - #ifdef _WIN32 - loctime=*localtime(&curtime); - #else - localtime_r(&curtime,&loctime); - #endif - snprintf(date,sizeof(date)-1,"%i%02i%02i-%02i%02i%2i",loctime.tm_year+1900,loctime.tm_mon+1,loctime.tm_mday, loctime.tm_hour, loctime.tm_min, loctime.tm_sec); - - snprintf(filename,sizeof(filename)-1,"record-%s.wav",date); - return g_build_path(G_DIR_SEPARATOR_S,g_get_tmp_dir(),filename,NULL);; -} - -static float audio_stream_get_record_volume(AudioStream *st){ - if (st && st->volsend){ - float vol=0; - ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol); - return vol; - } - return LINPHONE_VOLUME_DB_LOWEST; -} - -static float audio_stream_get_max_volume(AudioStream *st){ - if (st && st->volsend){ - float vol=0; - ms_filter_call_method(st->volsend,MS_VOLUME_GET_MAX,&vol); - return vol; - } - return LINPHONE_VOLUME_DB_LOWEST; -} - -static gboolean update_audio_label(volume_ctx_t *ctx){ - float volume_db=ctx->get_volume(ctx->data); - gchar *result; - if (volume_db < -20) result = _("No voice detected"); - else if (volume_db <= -10) result = _("Too low"); - else if (volume_db < -6) result = _("Good"); - else result = _("Too loud"); - g_message("volume_max_db=%f, text=%s",volume_db,result); - gtk_label_set_text(GTK_LABEL(ctx->widget),result); - return TRUE; -} - -static void on_audio_label_destroy(guint task_id){ - g_source_remove(task_id); -} - -void linphone_gtk_init_audio_label(GtkWidget *w, get_volume_t get_volume, void *data){ - guint task_id=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"task_id_t")); - if (task_id==0){ - volume_ctx_t *ctx=g_new(volume_ctx_t,1); - ctx->widget=w; - ctx->get_volume=get_volume; - ctx->data=data; - ctx->last_value=0; - g_object_set_data_full(G_OBJECT(w),"ctx_t",ctx,g_free); - task_id=g_timeout_add(200,(GSourceFunc)update_audio_label,ctx); - g_object_set_data_full(G_OBJECT(w),"task_id_t",GINT_TO_POINTER(task_id),(GDestroyNotify)on_audio_label_destroy); - } -} - -void linphone_gtk_uninit_audio_label(GtkWidget *w){ - guint task_id=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"task_id_t")); - if (task_id!=0){ - g_object_set_data(G_OBJECT(w),"ctx_t",NULL); - g_object_set_data(G_OBJECT(w),"task_id_t",NULL); - } -} - -static void playback_device_changed(GtkWidget *w){ - gchar *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w)); - linphone_core_set_playback_device(linphone_gtk_get_core(),sel); - g_free(sel); -} - -static void capture_device_changed(GtkWidget *capture_device){ - gchar *sel; - GtkWidget *mic_audiolevel; - GtkWidget *label_audiolevel; - GtkWidget *assistant=gtk_widget_get_toplevel(capture_device); - AudioStream *audio_stream; - - mic_audiolevel = get_widget_from_assistant("mic_audiolevel"); - label_audiolevel = get_widget_from_assistant("label_audiolevel"); - audio_stream = (AudioStream *) g_object_get_data(G_OBJECT(assistant),"stream"); - sel = gtk_combo_box_get_active_text(GTK_COMBO_BOX(capture_device)); - linphone_core_set_capture_device(linphone_gtk_get_core(),sel); - linphone_gtk_uninit_audio_meter(mic_audiolevel); - linphone_gtk_uninit_audio_label(label_audiolevel); - audio_stream_stop(audio_stream); - g_free(sel); - /*now restart the audio stream*/ - prepare(GTK_ASSISTANT(assistant)); -} - -static void dialog_click(GtkWidget *dialog, guint response_id, GtkWidget *page){ - switch(response_id){ - case GTK_RESPONSE_YES: - gtk_assistant_set_page_complete(GTK_ASSISTANT(audio_assistant),page,TRUE); - break; - default: - break; - } - gtk_widget_destroy(dialog); -} - -static void calibration_finished(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay, void *data){ - GtkWidget * dialog; - GtkWidget *speaker_page; - ms_message("echo calibration finished %s.",status==LinphoneEcCalibratorDone ? "successfully" : "with faillure"); - if (status==LinphoneEcCalibratorDone) ms_message("Measured delay is %i",delay); - - speaker_page = get_widget_from_assistant("speaker_page"); - - dialog = gtk_message_dialog_new ( - GTK_WINDOW(audio_assistant), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_YES_NO, - "%s",_("Did you hear three beeps ?")); - - g_signal_connect(G_OBJECT (dialog), "response", - G_CALLBACK (dialog_click),speaker_page); - gtk_widget_show(dialog); -} - -void linphone_gtk_start_sound(GtkWidget *w){ - LinphoneCore *lc = linphone_gtk_get_core(); - linphone_core_start_echo_calibration(lc,calibration_finished,NULL,NULL,NULL); -} - -static gboolean linphone_gtk_stop_record(gpointer data){ - AudioStream *stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant),"record_stream"); - if(stream != NULL){ - audio_stream_stop(stream); - g_object_set_data(G_OBJECT(audio_assistant),"record_stream",NULL); - } - update_record_button(FALSE); - update_play_button(TRUE); - return FALSE; -} - - -void linphone_gtk_start_record_sound(GtkWidget *w, gpointer data){ - LinphoneCore *lc = linphone_gtk_get_core(); - MSFactory *factory = linphone_core_get_ms_factory(lc); - AudioStream *stream = NULL; - MSSndCardManager *manager = ms_factory_get_snd_card_manager(factory); - gboolean active=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)); - gint timeout_id; - - if(active){ - gchar *path = get_record_file(); - stream=audio_stream_new(factory, 8888, 8889, FALSE); - if(stream != NULL){ - audio_stream_start_full(stream,&av_profile,"127.0.0.1",8888,"127.0.0.1",8889,0,0,NULL, - path,NULL,ms_snd_card_manager_get_card(manager,linphone_core_get_capture_device(lc)),FALSE); - g_object_set_data(G_OBJECT(audio_assistant),"record_stream",stream); - } - timeout_id = gtk_timeout_add(6000,(GtkFunction)linphone_gtk_stop_record,NULL); - g_object_set_data(G_OBJECT(audio_assistant),"timeout_id",GINT_TO_POINTER(timeout_id)); - g_object_set_data(G_OBJECT(audio_assistant),"path",path); - } else { - stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant),"record_stream"); - timeout_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(audio_assistant),"timeout_id")); - gtk_timeout_remove(timeout_id); - if(stream != NULL){ - audio_stream_stop(stream); - g_object_set_data(G_OBJECT(audio_assistant),"record_stream",NULL); - } - update_record_button(FALSE); - update_play_button(TRUE); - } -} - -static void endoffile_cb(void *ud, MSFilter *f, unsigned int ev,void * arg){ - switch (ev) { - case MS_PLAYER_EOF: { - ms_message("EndOfFile received"); - /*workaround for a mediastreamer2 bug. Don't deactivate the play button, because it will stop the graph from the end of file callback, - * which is sometimes crashing. On master branch it is fixed in mediastreamer2, the workaround is only valid in 3.8.x branch*/ - g_timeout_add(0, (GSourceFunc)deactivate_play_button, NULL); - break; - } - break; - } -} - -void linphone_gtk_start_play_record_sound(GtkWidget *w,gpointer data){ - LinphoneCore *lc = linphone_gtk_get_core(); - MSFactory *factory = linphone_core_get_ms_factory(lc); - gboolean active=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)); - AudioStream *stream = NULL; - MSSndCardManager *manager = ms_factory_get_snd_card_manager(factory); - - if(active){ - gchar *path = g_object_get_data(G_OBJECT(audio_assistant),"path"); - stream=audio_stream_new(factory, 8888, 8889, FALSE); - if(path != NULL){ - audio_stream_start_full(stream,&av_profile,"127.0.0.1",8888,"127.0.0.1",8889,0,0,path, - NULL,ms_snd_card_manager_get_card(manager,linphone_core_get_playback_device(lc)),NULL,FALSE); - ms_filter_add_notify_callback(stream->soundread,endoffile_cb,stream,FALSE); - g_object_set_data(G_OBJECT(audio_assistant),"play_stream",stream); - } - } else { - stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant),"play_stream"); - if(stream != NULL){ - audio_stream_stop(stream); - g_object_set_data(G_OBJECT(audio_assistant),"play_stream",NULL); - } - } -} - -void display_popup(GtkMessageType type,const gchar *message){ - GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(audio_assistant), - GTK_DIALOG_DESTROY_WITH_PARENT, - type, - GTK_BUTTONS_CLOSE, - "%s", - (const gchar*)message); - /* Destroy the dialog when the user responds to it (e.g. clicks a button) */ - g_signal_connect_swapped (G_OBJECT (dialog), "response", - G_CALLBACK (gtk_widget_destroy), - G_OBJECT (dialog)); - gtk_widget_show(dialog); -} - -static void open_mixer(void){ - GError *error = NULL; - -#ifdef _WIN32 - if(!g_spawn_command_line_async("control mmsys.cpl",&error)){ - display_popup(GTK_MESSAGE_WARNING,_("Sound preferences not found ")); - g_error_free(error); - } -#elif __APPLE__ - if(!g_spawn_command_line_async("open /System/Library/PreferencePanes/Sound.prefPane",&error)){ - display_popup(GTK_MESSAGE_WARNING,_("Sound preferences not found ")); - g_error_free(error); - } -#else - if(!g_spawn_command_line_async("gnome-volume-control",&error)){ - if(!g_spawn_command_line_async("gnome-control-center sound",&error)){ - if(!g_spawn_command_line_async("kmix",&error)){ - if(!g_spawn_command_line_async("mate-volume-control",&error)){ - if(!g_spawn_command_line_async("xterm alsamixer",&error)){ - display_popup(GTK_MESSAGE_WARNING,_("Cannot launch system sound control ")); - g_error_free(error); - } - } - } - } - } -#endif -} - -static GtkWidget *create_intro(void){ - GtkWidget *vbox=gtk_vbox_new(FALSE,2); - GtkWidget *label=gtk_label_new(_("Welcome!\nThis assistant will help you to configure audio settings for Linphone")); - gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 2); - gtk_widget_show_all(vbox); - return vbox; -} - -static GtkWidget *create_mic_page(void){ - GtkWidget *vbox=gtk_table_new(3,2,FALSE); - LinphoneCore *lc=linphone_gtk_get_core(); - const char **sound_devices; - GtkWidget *labelMicChoice=gtk_label_new(_("Capture device")); - GtkWidget *labelMicLevel=gtk_label_new(_("Recorded volume")); - GtkWidget *mic_audiolevel=gtk_progress_bar_new(); - GtkWidget *capture_device=gtk_combo_box_new(); - GtkWidget *box = gtk_vbox_new(FALSE,0); - GtkWidget *label_audiolevel=gtk_label_new(_("No voice")); - GtkWidget *mixer_button=gtk_button_new_with_label(_("System sound preferences")); - GtkWidget *image; - - image=gtk_image_new_from_stock(GTK_STOCK_PREFERENCES,GTK_ICON_SIZE_MENU); - gtk_button_set_image(GTK_BUTTON(mixer_button),image); - - gtk_box_pack_start(GTK_BOX(box),mic_audiolevel,TRUE,TRUE,1); - gtk_box_pack_start(GTK_BOX(box),label_audiolevel,FALSE,FALSE,1); - - gtk_table_attach_defaults(GTK_TABLE(vbox), labelMicChoice, 0, 1, 0, 1); - gtk_table_attach_defaults(GTK_TABLE(vbox), capture_device, 1, 2, 0, 1); - gtk_table_attach_defaults(GTK_TABLE(vbox), labelMicLevel, 0, 1, 1, 2); - gtk_table_attach_defaults(GTK_TABLE(vbox), box, 1, 2, 1, 2); - gtk_table_attach(GTK_TABLE(vbox), mixer_button, 0, 2, 2, 3, GTK_SHRINK, GTK_SHRINK, 0,0); - - gtk_table_set_row_spacings(GTK_TABLE(vbox),10); - - set_widget_to_assistant("mic_audiolevel",mic_audiolevel); - set_widget_to_assistant("label_audiolevel",label_audiolevel); - - sound_devices=linphone_core_get_sound_devices(lc); - linphone_gtk_fill_combo_box(capture_device, sound_devices, - linphone_core_get_capture_device(lc), CAP_CAPTURE); - gtk_widget_show_all(vbox); - - g_signal_connect(G_OBJECT(capture_device),"changed",(GCallback)capture_device_changed,capture_device); - g_signal_connect(G_OBJECT(mixer_button),"clicked",(GCallback)open_mixer,vbox); - - return vbox; -} - -static GtkWidget *create_speaker_page(void){ - GtkWidget *vbox=gtk_table_new(3,2,FALSE); - LinphoneCore *lc=linphone_gtk_get_core(); - - GtkWidget *labelSpeakerChoice=gtk_label_new(_("Playback device")); - GtkWidget *labelSpeakerLevel=gtk_label_new(_("Play three beeps")); - GtkWidget *spk_button=gtk_button_new_from_stock(GTK_STOCK_MEDIA_PLAY); - GtkWidget *playback_device=gtk_combo_box_new(); - GtkWidget *mixer_button=gtk_button_new_with_label(_("System sound preferences")); - GtkWidget *image; - const char **sound_devices; - - image=gtk_image_new_from_stock(GTK_STOCK_PREFERENCES,GTK_ICON_SIZE_MENU); - gtk_button_set_image(GTK_BUTTON(mixer_button),image); - - gtk_table_attach_defaults(GTK_TABLE(vbox), labelSpeakerChoice, 0, 1, 0, 1); - gtk_table_attach(GTK_TABLE(vbox), playback_device, 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0,0); - gtk_table_attach_defaults(GTK_TABLE(vbox), labelSpeakerLevel, 0, 1, 1, 2); - gtk_table_attach(GTK_TABLE(vbox), spk_button, 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0,0); - gtk_table_attach(GTK_TABLE(vbox), mixer_button, 0, 2, 2, 3, GTK_SHRINK, GTK_SHRINK, 0,0); - - gtk_table_set_row_spacings(GTK_TABLE(vbox),10); - - sound_devices=linphone_core_get_sound_devices(lc); - linphone_gtk_fill_combo_box(playback_device, sound_devices, - linphone_core_get_playback_device(lc),CAP_PLAYBACK); - gtk_widget_show_all(vbox); - - set_widget_to_assistant("speaker_page",vbox); - g_signal_connect(G_OBJECT(playback_device),"changed",(GCallback)playback_device_changed,playback_device); - g_signal_connect(G_OBJECT(spk_button),"clicked",(GCallback)linphone_gtk_start_sound,vbox); - g_signal_connect(G_OBJECT(mixer_button),"clicked",(GCallback)open_mixer,vbox); - - return vbox; -} - -static GtkWidget *create_play_record_page(void){ - GtkWidget *vbox=gtk_table_new(2,2,FALSE); - GtkWidget *labelRecord=gtk_label_new(_("Press the record button and say some words")); - GtkWidget *labelPlay=gtk_label_new(_("Listen to your record voice")); - GtkWidget *rec_button=gtk_toggle_button_new_with_label(_("Record")); - GtkWidget *play_button=gtk_toggle_button_new_with_label(_("Play")); - GtkWidget *image; - - image=gtk_image_new_from_stock(GTK_STOCK_MEDIA_RECORD,GTK_ICON_SIZE_MENU); - gtk_button_set_image(GTK_BUTTON(rec_button),image); - - image=gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY,GTK_ICON_SIZE_MENU); - gtk_button_set_image(GTK_BUTTON(play_button),image); - gtk_widget_set_sensitive(play_button,FALSE); - - gtk_table_attach_defaults(GTK_TABLE(vbox), labelRecord, 0, 1, 0, 1); - gtk_table_attach(GTK_TABLE(vbox), rec_button, 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0,0); - gtk_table_attach_defaults(GTK_TABLE(vbox), labelPlay, 0, 1, 1, 2); - gtk_table_attach(GTK_TABLE(vbox), play_button, 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0,0); - - gtk_widget_show_all(vbox); - - set_widget_to_assistant("rec_button",rec_button); - set_widget_to_assistant("play_button",play_button); - g_signal_connect(G_OBJECT(rec_button),"toggled",(GCallback)linphone_gtk_start_record_sound,vbox); - g_signal_connect(G_OBJECT(play_button),"toggled",(GCallback)linphone_gtk_start_play_record_sound,vbox); - - return vbox; -} - -static GtkWidget *create_end_page(void){ - GtkWidget *vbox=gtk_vbox_new(FALSE,2); - GtkWidget *label=gtk_label_new(_("Let's start Linphone now")); - gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 2); - gtk_widget_show_all(vbox); - return vbox; -} - -static void prepare(GtkAssistant *w){ - AudioStream *audio_stream = NULL; - LinphoneCore *lc=linphone_gtk_get_core(); - MSFactory *factory = linphone_core_get_ms_factory(lc); - int page = gtk_assistant_get_current_page(w); - GtkWidget *mic_audiolevel = get_widget_from_assistant("mic_audiolevel"); - GtkWidget *label_audiolevel = get_widget_from_assistant("label_audiolevel"); - - //Speaker page - if(page == 1){ - MSSndCardManager *manager = ms_factory_get_snd_card_manager(factory); - audio_stream = audio_stream_start_with_sndcards(factory, &av_profile,9898,"127.0.0.1",19898,0,0,ms_snd_card_manager_get_card(manager,linphone_core_get_playback_device(lc)),ms_snd_card_manager_get_card(manager,linphone_core_get_capture_device(lc)),FALSE); - if (mic_audiolevel != NULL && audio_stream != NULL){ - g_object_set_data(G_OBJECT(audio_assistant),"stream",audio_stream); - linphone_gtk_init_audio_meter(mic_audiolevel,(get_volume_t)audio_stream_get_record_volume,audio_stream); - linphone_gtk_init_audio_label(label_audiolevel,(get_volume_t)audio_stream_get_max_volume,audio_stream); - } - } else if(page == 2 || page == 0){ - if(mic_audiolevel != NULL && label_audiolevel != NULL){ - audio_stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant),"stream"); - if(audio_stream != NULL){ - linphone_gtk_uninit_audio_meter(mic_audiolevel); - linphone_gtk_uninit_audio_label(label_audiolevel); - audio_stream_stop(audio_stream); - g_object_set_data(G_OBJECT(audio_assistant),"stream",NULL); - } - } - } -} - -void linphone_gtk_close_audio_assistant(GtkWidget *w){ - gchar *path; - AudioStream *stream; - - path = g_object_get_data(G_OBJECT(audio_assistant),"path"); - if(path != NULL){ - g_unlink(path); - } - stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant), "stream"); - if(stream) { - audio_stream_stop(stream); - } - gtk_widget_destroy(w); - if(linphone_gtk_get_audio_assistant_option()){ - gtk_main_quit(); - } - audio_assistant = NULL; -} - -void linphone_gtk_audio_assistant_apply(GtkWidget *w){ - linphone_gtk_close_audio_assistant(w); -} - -void linphone_gtk_show_audio_assistant(void){ - GtkWidget *w; - GtkWidget *welcome; - GtkWidget *mic_page; - GtkWidget *speaker_page; - GtkWidget *play_record_page; - GtkWidget *end_page; - if(audio_assistant!=NULL) - return; - w=audio_assistant=linphone_gtk_create_window("audio_assistant", linphone_gtk_get_main_window()); - - gtk_window_set_resizable (GTK_WINDOW(w), FALSE); - gtk_window_set_title(GTK_WINDOW(w),_("Audio Assistant")); - - welcome=create_intro(); - mic_page=create_mic_page(); - speaker_page=create_speaker_page(); - play_record_page=create_play_record_page(); - end_page=create_end_page(); - - gtk_assistant_append_page(GTK_ASSISTANT(w),welcome); - gtk_assistant_set_page_type(GTK_ASSISTANT(w),welcome,GTK_ASSISTANT_PAGE_INTRO); - gtk_assistant_set_page_title(GTK_ASSISTANT(w),welcome,_("Audio assistant")); - gtk_assistant_set_page_complete(GTK_ASSISTANT(w),welcome,TRUE); - - gtk_assistant_append_page(GTK_ASSISTANT(w),mic_page); - gtk_assistant_set_page_type(GTK_ASSISTANT(w),mic_page,GTK_ASSISTANT_PAGE_CONTENT); - gtk_assistant_set_page_title(GTK_ASSISTANT(w),mic_page,_("Mic Gain calibration")); - gtk_assistant_set_page_complete(GTK_ASSISTANT(w),mic_page,TRUE); - - gtk_assistant_append_page(GTK_ASSISTANT(w),speaker_page); - gtk_assistant_set_page_type(GTK_ASSISTANT(w),speaker_page,GTK_ASSISTANT_PAGE_CONTENT); - gtk_assistant_set_page_complete(GTK_ASSISTANT(w),speaker_page,FALSE); - gtk_assistant_set_page_title(GTK_ASSISTANT(w),speaker_page,_("Speaker volume calibration")); - - gtk_assistant_append_page(GTK_ASSISTANT(w),play_record_page); - gtk_assistant_set_page_type(GTK_ASSISTANT(w),play_record_page,GTK_ASSISTANT_PAGE_CONTENT); - gtk_assistant_set_page_complete(GTK_ASSISTANT(w),play_record_page,TRUE); - gtk_assistant_set_page_title(GTK_ASSISTANT(w),play_record_page,_("Record and Play")); - - gtk_assistant_append_page(GTK_ASSISTANT(w),end_page); - gtk_assistant_set_page_type(GTK_ASSISTANT(w),end_page,GTK_ASSISTANT_PAGE_SUMMARY); - gtk_assistant_set_page_complete(GTK_ASSISTANT(w),end_page,TRUE); - gtk_assistant_set_page_title(GTK_ASSISTANT(w),end_page,_("Terminating")); - - g_signal_connect(G_OBJECT(w),"close",(GCallback)linphone_gtk_close_audio_assistant,w); - g_signal_connect(G_OBJECT(w),"cancel",(GCallback)linphone_gtk_close_audio_assistant,w); - g_signal_connect(G_OBJECT(w),"prepare",(GCallback)prepare,NULL); - - gtk_widget_show(w); -} diff --git a/gtk/audio_assistant.ui b/gtk/audio_assistant.ui deleted file mode 100644 index b8390f5d8..000000000 --- a/gtk/audio_assistant.ui +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - False - 12 - - - - - - - - - - - - - - diff --git a/gtk/buddylookup.c b/gtk/buddylookup.c deleted file mode 100644 index 73d8780db..000000000 --- a/gtk/buddylookup.c +++ /dev/null @@ -1,305 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "linphone.h" -#include "linphone/sipsetup.h" - -static void linphone_gtk_display_lookup_results(GtkWidget *w, const bctbx_list_t *results); - -enum { - LOOKUP_RESULT_NAME, - LOOKUP_RESULT_SIP_URI, - LOOKUP_RESULT_ADDRESS, - LOOKUP_RESULT_ICON, - LOOKUP_RESULT_NCOL -}; - -void linphone_gtk_buddy_lookup_window_destroyed(GtkWidget *w){ - guint tid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"typing_timeout")); - if (tid!=0){ - g_source_remove(tid); - } - tid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"buddylookup_processing")); - if (tid!=0){ - g_source_remove(tid); - } -} - -static void enable_add_buddy_button(GtkWidget *w){ - gtk_widget_set_sensitive(linphone_gtk_get_widget(w,"add_buddy"),TRUE); -} - -static void disable_add_buddy_button(GtkWidget *w){ - gtk_widget_set_sensitive(linphone_gtk_get_widget(w,"add_buddy"),FALSE); -} - -static void buddy_selection_changed(GtkWidget *w){ - GtkWidget *results=linphone_gtk_get_widget(w,"search_results"); - GtkTreeSelection *select; - GtkTreeIter iter; - GtkTreeModel *model; - enable_add_buddy_button(w); - - select = gtk_tree_view_get_selection(GTK_TREE_VIEW(results)); - if (gtk_tree_selection_get_selected (select, &model, &iter)) - { - GtkTreePath *path=gtk_tree_model_get_path(model,&iter); - gtk_tree_view_collapse_all(GTK_TREE_VIEW(results)); - gtk_tree_view_expand_row(GTK_TREE_VIEW(results),path,FALSE); - gtk_tree_path_free(path); - } -} - -GtkWidget * linphone_gtk_show_buddy_lookup_window(SipSetupContext *ctx){ - GtkTreeStore *store; - GtkCellRenderer *renderer,*pbuf_renderer; - GtkTreeViewColumn *column; - GtkTreeSelection *select; - GtkWidget *w=linphone_gtk_create_window("buddylookup", NULL); - GtkWidget *results=linphone_gtk_get_widget(w,"search_results"); - GtkProgressBar *pb=GTK_PROGRESS_BAR(linphone_gtk_get_widget(w,"progressbar")); - - store = gtk_tree_store_new(LOOKUP_RESULT_NCOL, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_PIXBUF); - - /*gtk_tree_view_set_hover_expand(GTK_TREE_VIEW(results),TRUE);*/ - gtk_tree_view_set_model(GTK_TREE_VIEW(results),GTK_TREE_MODEL(store)); - g_object_unref(G_OBJECT(store)); - - renderer = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes (_("Firstname, Lastname"), - renderer, - "markup", LOOKUP_RESULT_NAME, - NULL); - g_object_set (G_OBJECT(column), "resizable", TRUE, NULL); - - - pbuf_renderer=gtk_cell_renderer_pixbuf_new(); - g_object_set(G_OBJECT(renderer),"is-expander",TRUE,NULL); - gtk_tree_view_column_pack_start(column,pbuf_renderer,FALSE); - gtk_tree_view_column_add_attribute (column,pbuf_renderer, - "pixbuf", - LOOKUP_RESULT_ICON); - gtk_tree_view_append_column (GTK_TREE_VIEW (results), column); - -/* - column = gtk_tree_view_column_new_with_attributes (_("SIP address"), - renderer, - "text", LOOKUP_RESULT_SIP_URI, - NULL); - g_object_set (G_OBJECT(column), "resizable", TRUE, NULL); - gtk_tree_view_append_column (GTK_TREE_VIEW (results), column); -*/ - - select = gtk_tree_view_get_selection (GTK_TREE_VIEW (results)); - gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); - g_signal_connect_swapped(G_OBJECT(select),"changed",(GCallback)buddy_selection_changed,w); -/* -#if GTK_CHECK_VERSION(2,12,0) - gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(results),LOOKUP_RESULT_ADDRESS); -#endif -*/ - g_object_set_data(G_OBJECT(w),"SipSetupContext",ctx); - g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_gtk_buddy_lookup_window_destroyed,w); - //g_signal_connect_swapped(G_OBJECT(w),"destroy",(GCallback)linphone_gtk_buddy_lookup_window_destroyed,w); - gtk_progress_bar_set_fraction(pb,0); - gtk_progress_bar_set_text(pb,NULL); - gtk_dialog_add_button(GTK_DIALOG(w),GTK_STOCK_CLOSE,GTK_RESPONSE_CLOSE); - g_object_set_data(G_OBJECT(w),"last_state",GINT_TO_POINTER(-1)); - - gtk_widget_show(w); - return w; -} - - -void linphone_gtk_buddy_lookup_set_keyword(GtkWidget *w, const char *kw){ - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"keyword")),kw); -} - -static gboolean linphone_gtk_process_buddy_lookup(GtkWidget *w){ - BuddyLookupStatus bls; - SipSetupContext *ctx; - int last_state; - gchar *tmp; - bctbx_list_t *results=NULL; - GtkProgressBar *pb=GTK_PROGRESS_BAR(linphone_gtk_get_widget(w,"progressbar")); - BuddyLookupRequest *req=(BuddyLookupRequest*)g_object_get_data(G_OBJECT(w),"buddylookup_request"); - - ctx=(SipSetupContext*)g_object_get_data(G_OBJECT(w),"SipSetupContext"); - last_state=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"last_state")); - - if (req==NULL) { - g_object_set_data(G_OBJECT(w),"buddylookup_processing",GINT_TO_POINTER(0)); - return FALSE; - } - bls=req->status; - if (last_state==(int)bls) return TRUE; - - switch(bls){ - case BuddyLookupNone: - gtk_progress_bar_set_fraction(pb,0); - gtk_progress_bar_set_text(pb,NULL); - break; - case BuddyLookupFailure: - gtk_progress_bar_set_fraction(pb,0); - gtk_progress_bar_set_text(pb,_("Error communicating with server.")); - break; - case BuddyLookupConnecting: - gtk_progress_bar_set_fraction(pb,0.2); - gtk_progress_bar_set_text(pb,_("Connecting...")); - break; - case BuddyLookupConnected: - gtk_progress_bar_set_fraction(pb,0.4); - gtk_progress_bar_set_text(pb,_("Connected")); - break; - case BuddyLookupReceivingResponse: - gtk_progress_bar_set_fraction(pb,0.8); - gtk_progress_bar_set_text(pb,_("Receiving data...")); - break; - case BuddyLookupDone: - results=req->results; - linphone_gtk_display_lookup_results( - linphone_gtk_get_widget(w,"search_results"), - results); - gtk_progress_bar_set_fraction(pb,1); - tmp=g_strdup_printf(ngettext("Found %u contact", "Found %u contacts", - (unsigned int)bctbx_list_size(results)), (unsigned int)bctbx_list_size(results)); - gtk_progress_bar_set_text(pb,tmp); - g_free(tmp); - sip_setup_context_buddy_lookup_free(ctx,req); - g_object_set_data(G_OBJECT(w),"buddylookup_request",NULL); - break; - } - g_object_set_data(G_OBJECT(w),"last_state",GINT_TO_POINTER(bls)); - return TRUE; -} - -static gboolean keyword_typing_finished(GtkWidget *w){ - guint tid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"typing_timeout")); - const char *keyword; - SipSetupContext *ctx; - if (tid!=0){ - g_source_remove(tid); - } - keyword=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"keyword"))); - if (strlen(keyword)>=1){ - BuddyLookupRequest *req; - guint tid2; - ctx=(SipSetupContext*)g_object_get_data(G_OBJECT(w),"SipSetupContext"); - req=(BuddyLookupRequest*)g_object_get_data(G_OBJECT(w),"buddylookup_request"); - if (req!=NULL){ - sip_setup_context_buddy_lookup_free(ctx,req); - } - req=sip_setup_context_create_buddy_lookup_request(ctx); - buddy_lookup_request_set_key(req,keyword); - sip_setup_context_buddy_lookup_submit(ctx,req); - g_object_set_data(G_OBJECT(w),"buddylookup_request",req); - if (g_object_get_data(G_OBJECT(w),"buddylookup_processing")==NULL){ - tid2=g_timeout_add(20,(GSourceFunc)linphone_gtk_process_buddy_lookup,w); - g_object_set_data(G_OBJECT(w),"buddylookup_processing",GINT_TO_POINTER(tid2)); - } - } - return FALSE; -} - -void linphone_gtk_keyword_changed(GtkEditable *e){ - GtkWidget *w=gtk_widget_get_toplevel(GTK_WIDGET(e)); - guint tid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"typing_timeout")); - if (tid!=0){ - g_source_remove(tid); - } - tid=g_timeout_add(2000,(GSourceFunc)keyword_typing_finished,w); - g_object_set_data(G_OBJECT(w),"typing_timeout",GINT_TO_POINTER(tid)); -} - -static void linphone_gtk_display_lookup_results(GtkWidget *w, const bctbx_list_t *results){ - GtkTreeStore *store; - GtkTreeIter iter; - gchar *tmp; - const bctbx_list_t *elem; - store=GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(w))); - gtk_tree_store_clear(store); - disable_add_buddy_button(gtk_widget_get_toplevel(w)); - for(elem=results;elem!=NULL;elem=elem->next){ - BuddyInfo *bi=(BuddyInfo*)elem->data; - GdkPixbuf *pbuf; - GtkTreeIter depth1; - gtk_tree_store_append(store,&iter,NULL); - tmp=g_strdup_printf("%s, %s (%s)",bi->firstname,bi->lastname,bi->displayname); - gtk_tree_store_set(store,&iter,LOOKUP_RESULT_NAME, tmp,-1); - g_free(tmp); - gtk_tree_store_set(store,&iter,LOOKUP_RESULT_SIP_URI, bi->sip_uri,-1); - tmp=g_strdup_printf("%s, %s %s\n%s",bi->address.street, bi->address.zip, bi->address.town, bi->address.country); - gtk_tree_store_set(store,&iter,LOOKUP_RESULT_ADDRESS, tmp,-1); - g_free(tmp); - if (bi->image_data!=NULL){ - pbuf=_gdk_pixbuf_new_from_memory_at_scale(bi->image_data,bi->image_length,-1,40,TRUE); - if (pbuf) { - gtk_tree_store_set(store,&iter,LOOKUP_RESULT_ICON,pbuf,-1); - g_object_unref(G_OBJECT(pbuf)); - } - } - gtk_tree_store_append(store,&depth1,&iter); - tmp=g_strdup_printf("%s, %s (%s)\n%s, %s %s\n%s\n%s", - bi->firstname,bi->lastname,bi->displayname,bi->address.street, - bi->address.zip, bi->address.town, bi->address.country,bi->sip_uri); - gtk_tree_store_set(store,&depth1,LOOKUP_RESULT_NAME,tmp,-1); - g_free(tmp); - if (bi->image_data!=NULL){ - pbuf=_gdk_pixbuf_new_from_memory_at_scale(bi->image_data,bi->image_length,-1,-1,TRUE); - if (pbuf) { - gtk_tree_store_set(store,&depth1,LOOKUP_RESULT_ICON,pbuf,-1); - g_object_unref(G_OBJECT(pbuf)); - } - } - } -} - -void linphone_gtk_add_buddy_from_database(GtkWidget *button){ - GtkWidget *w=gtk_widget_get_toplevel(button); - GtkTreeSelection *select; - GtkTreeIter iter; - GtkTreeModel *model; - select = gtk_tree_view_get_selection(GTK_TREE_VIEW(linphone_gtk_get_widget(w,"search_results"))); - if (gtk_tree_selection_get_selected (select, &model, &iter)) - { - char *uri; - char *name; - char *addr; - LinphoneFriend *lf; - LinphoneCore *lc = linphone_gtk_get_core(); - int presence=linphone_gtk_get_ui_config_int("use_subscribe_notify",1); - gtk_tree_model_get (model, &iter,LOOKUP_RESULT_SIP_URI , &uri,LOOKUP_RESULT_NAME, &name, -1); - addr=g_strdup_printf("%s <%s>",name,uri); - - lf=linphone_core_create_friend_with_address(lc, addr); - linphone_friend_set_inc_subscribe_policy(lf,presence ? LinphoneSPAccept : LinphoneSPDeny); - linphone_friend_send_subscribe(lf,presence); - linphone_core_add_friend(lc, lf); - linphone_gtk_show_friends(); - g_free(addr); - g_free(uri); - g_free(name); - } -} - -/*called when double clicking on a contact */ -void linphone_gtk_buddy_lookup_contact_activated(GtkWidget *treeview){ - linphone_gtk_add_buddy_from_database(treeview); - gtk_widget_destroy(gtk_widget_get_toplevel(treeview)); -} diff --git a/gtk/buddylookup.ui b/gtk/buddylookup.ui deleted file mode 100644 index c32727b05..000000000 --- a/gtk/buddylookup.ui +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - 5 - Search contacts in directory - center-on-parent - dialog - False - - - - True - 2 - - - True - 5 - 0 - - - True - 12 - - - True - - - True - True - True - - - - False - 0 - - - - - True - True - automatic - automatic - etched-in - - - 512 - 140 - True - True - - - - - - 6 - 1 - - - - - True - True - True - - - False - 2 - - - - - True - - - True - False - True - True - - - - True - - - True - gtk-add - - - False - False - 0 - - - - - True - Add to my list - - - 1 - - - - - - - False - False - 5 - 0 - - - - - False - False - 3 - - - - - - - - - True - <b>Search somebody</b> - True - - - - - 1 - - - - - True - end - - - - - - - - - False - end - 0 - - - - - - diff --git a/gtk/call_logs.ui b/gtk/call_logs.ui deleted file mode 100644 index 23184841a..000000000 --- a/gtk/call_logs.ui +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - 500 - 370 - False - 5 - Call history - center-on-parent - dialog - - - True - False - 2 - - - True - False - end - - - Clear all - True - True - True - False - image1 - - - False - False - 0 - - - - - Call back - True - True - True - False - - - False - False - 1 - - - - - gtk-close - True - True - True - False - True - - - False - False - 2 - - - - - False - True - end - 0 - - - - - True - True - never - automatic - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - - - - - True - True - 1 - - - - - - button1 - call_back_button - call_logs_close - - - - - - - - - - - - True - False - gtk-clear - - diff --git a/gtk/call_statistics.ui b/gtk/call_statistics.ui deleted file mode 100644 index d53c93a1f..000000000 --- a/gtk/call_statistics.ui +++ /dev/null @@ -1,293 +0,0 @@ - - - - - - 5 - Call statistics - dialog - - - - True - 2 - - - True - 0 - none - - - True - 12 - - - True - 10 - 2 - True - - - True - Audio codec - - - 1 - 2 - - - - - - True - Video codec - - - 2 - 3 - - - - - - True - Audio IP bandwidth usage - - - 3 - 4 - - - - - - True - - - 1 - 2 - 1 - 2 - - - - - True - - - 1 - 2 - 2 - 3 - - - - - True - - - 1 - 2 - 3 - 4 - - - - - True - Audio Media connectivity - - - 5 - 6 - - - - - - True - - - 1 - 2 - 5 - 6 - - - - - True - Video IP bandwidth usage - - - 4 - 5 - - - - - - True - - - 1 - 2 - 4 - 5 - - - - - True - Video Media connectivity - - - 6 - 7 - - - - - True - - - 1 - 2 - 6 - 7 - - - - - True - Round trip time - - - 7 - 8 - - - - - True - - - 1 - 2 - 7 - 8 - - - - - True - Video resolution received - - - 8 - 9 - - - - - True - - - 1 - 2 - 8 - 9 - - - - - True - Video resolution sent - - - 9 - 10 - - - - - True - - - 1 - 2 - 9 - 10 - - - - - True - RTP profile - - - - - - - - True - - - 1 - 2 - - - - - - - - - True - <b>Call statistics and information</b> - True - - - - - False - False - 1 - - - - - True - end - - - - - - gtk-close - True - True - True - True - - - False - False - 1 - - - - - False - end - 0 - - - - - - button1 - - - diff --git a/gtk/callee_frame.ui b/gtk/callee_frame.ui deleted file mode 100644 index 4ae4d90ef..000000000 --- a/gtk/callee_frame.ui +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - True - False - 0 - none - - - True - False - 12 - - - True - False - 12 - - - True - False - - - True - False - - - True - True - - - False - False - 0 - - - - - False - True - 0 - - - - - True - False - <b>Callee name</b> - True - right - end - - - True - True - 1 - - - - - 90 - 30 - True - False - - - False - True - 2 - - - - - - - - - - - - - diff --git a/gtk/calllogs.c b/gtk/calllogs.c deleted file mode 100644 index 9ee24eba8..000000000 --- a/gtk/calllogs.c +++ /dev/null @@ -1,424 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "linphone.h" -#include - -#define CONFIG_FILE ".linphone-call-history.db" - -char *linphone_gtk_call_logs_storage_get_db_file(const char *filename){ - const int path_max=1024; - char *db_file=NULL; - - db_file=(char *)g_malloc(path_max*sizeof(char)); - if (filename==NULL) filename=CONFIG_FILE; - /*try accessing a local file first if exists*/ - if (bctbx_file_exist(CONFIG_FILE)==0){ - snprintf(db_file,path_max,"%s",filename); - }else{ -#ifdef _WIN32 - const char *appdata=getenv("APPDATA"); - if (appdata){ - snprintf(db_file,path_max,"%s\\%s",appdata,LINPHONE_CONFIG_DIR); - CreateDirectory(db_file,NULL); - snprintf(db_file,path_max,"%s\\%s\\%s",appdata,LINPHONE_CONFIG_DIR,filename); - } -#else - const char *home=getenv("HOME"); - if (home==NULL) home="."; - snprintf(db_file,path_max,"%s/%s",home,filename); -#endif - } - return db_file; -} - -static void fill_renderers(GtkTreeView *v){ - GtkTreeViewColumn *c; - GtkCellRenderer *r; - - r=gtk_cell_renderer_pixbuf_new(); - c=gtk_tree_view_column_new_with_attributes("icon",r,"icon-name",0,NULL); - gtk_tree_view_append_column (v,c); - - r=gtk_cell_renderer_text_new (); - c=gtk_tree_view_column_new_with_attributes("sipaddress",r,"markup",1,NULL); - gtk_tree_view_append_column (v,c); -} - -void call_log_selection_changed(GtkTreeView *v){ - GtkTreeSelection *select; - GtkTreeIter iter; - GtkTreeModel *model=NULL; - - select = gtk_tree_view_get_selection(v); - if (select!=NULL){ - if (gtk_tree_selection_get_selected (select, &model, &iter)){ - GtkTreePath *path=gtk_tree_model_get_path(model,&iter); - gtk_tree_view_collapse_all(v); - gtk_tree_view_expand_row(v,path,TRUE); - gtk_tree_path_free(path); - } - } -} - -void linphone_gtk_call_log_chat_selected(GtkWidget *w){ - GtkTreeSelection *select; - GtkTreeIter iter; - - select=gtk_tree_view_get_selection(GTK_TREE_VIEW(w)); - if (select!=NULL){ - GtkTreeModel *model=NULL; - if (gtk_tree_selection_get_selected (select,&model,&iter)){ - gpointer pcl; - LinphoneAddress *la; - LinphoneCallLog *cl; - gtk_tree_model_get(model,&iter,2,&pcl,-1); - cl = (LinphoneCallLog *)pcl; - la = linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl); - if (la != NULL){ - linphone_gtk_friend_list_set_chat_conversation(la); - } - } - } -} - -void linphone_gtk_call_log_add_contact(GtkWidget *w){ - GtkWidget *main_window = gtk_widget_get_toplevel(w); - GtkTreeSelection *select; - GtkTreeIter iter; - - select=gtk_tree_view_get_selection(GTK_TREE_VIEW(w)); - if (select!=NULL){ - GtkTreeModel *model=NULL; - if (gtk_tree_selection_get_selected (select,&model,&iter)){ - gpointer pcl; - LinphoneAddress *la; - LinphoneCallLog *cl; - LinphoneFriend *lf; - gtk_tree_model_get(model,&iter,2,&pcl,-1); - cl = (LinphoneCallLog *)pcl; - la = linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl); - if (la != NULL){ - char *uri=linphone_address_as_string(la); - lf=linphone_core_create_friend_with_address(linphone_gtk_get_core(), uri); - linphone_gtk_show_contact(lf, main_window); - ms_free(uri); - } - } - } -} - -static bool_t put_selection_to_uribar(GtkWidget *treeview){ - GtkTreeSelection *sel; - sel=gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); - if (sel!=NULL){ - GtkTreeModel *model=NULL; - GtkTreeIter iter; - if (gtk_tree_selection_get_selected (sel,&model,&iter)){ - char *tmp; - gpointer pcl; - LinphoneAddress *la; - LinphoneCallLog *cl; - gtk_tree_model_get(model,&iter,2,&pcl,-1); - cl = (LinphoneCallLog *)pcl; - la = linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl); - tmp = linphone_address_as_string(la); - if(tmp!=NULL) - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")),tmp); - ms_free(tmp); - return TRUE; - } - } - return FALSE; -} - -static void linphone_gtk_call_selected(GtkTreeView *treeview){ - put_selection_to_uribar(GTK_WIDGET(treeview)); - linphone_gtk_start_call(linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(treeview)), - "start_call")); -} - -static GtkWidget *linphone_gtk_create_call_log_menu(GtkWidget *call_log){ - GtkWidget *menu=NULL; - GtkWidget *menu_item; - gchar *call_label=NULL; - gchar *text_label=NULL; - gchar *add_contact_label=NULL; - gchar *name=NULL; - GtkWidget *image; - GtkTreeSelection *select; - GtkTreeIter iter; - - select=gtk_tree_view_get_selection(GTK_TREE_VIEW(call_log)); - if (select!=NULL){ - GtkTreeModel *model=NULL; - if (gtk_tree_selection_get_selected (select,&model,&iter)){ - gpointer pcl; - LinphoneAddress *la; - LinphoneCallLog *cl; - gtk_tree_model_get(model,&iter,2,&pcl,-1); - cl = (LinphoneCallLog *)pcl; - la = linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl); - name=linphone_address_as_string(la); - call_label=g_strdup_printf(_("Call %s"),name); - text_label=g_strdup_printf(_("Send text to %s"),name); - if (!linphone_gtk_is_friend(linphone_gtk_get_core(), name)) { - add_contact_label=g_strdup_printf(_("Add %s to your contact list"),name); - } - ms_free(name); - menu=gtk_menu_new(); - } - } - if (menu && call_label){ - menu_item=gtk_image_menu_item_new_with_label(call_label); - image=gtk_image_new_from_icon_name("linphone-start-call",GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image); - gtk_widget_show(image); - gtk_widget_show(menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); - g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_call_selected,call_log); - } - if (menu && text_label){ - menu_item=gtk_image_menu_item_new_with_label(text_label); - image=gtk_image_new_from_icon_name("linphone-start-chat",GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image); - gtk_widget_show(image); - gtk_widget_show(menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); - g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_call_log_chat_selected,call_log); - } - if (menu && add_contact_label){ - menu_item=gtk_image_menu_item_new_with_label(add_contact_label); - image=gtk_image_new_from_icon_name("linphone-contact-add",GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image); - gtk_widget_show(image); - gtk_widget_show(menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); - g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_call_log_add_contact,call_log); - } - if (menu) { - gtk_widget_show(menu); - gtk_menu_attach_to_widget(GTK_MENU(menu),call_log, NULL); - } - - if (add_contact_label) g_free(add_contact_label); - if (call_label) g_free(call_label); - if (text_label) g_free(text_label); - return menu; -} - -gboolean linphone_gtk_call_log_popup_contact(GtkWidget *list, GdkEventButton *event){ - GtkWidget *m=linphone_gtk_create_call_log_menu(list); - if (m) { - gtk_menu_popup (GTK_MENU (m), NULL, NULL, NULL, NULL, - event ? event->button : 0, event ? event->time : gtk_get_current_event_time()); - return TRUE; - } - return FALSE; -} - -gboolean linphone_gtk_call_log_button_pressed(GtkWidget *widget, GdkEventButton *event){ - if (event->button == 3 && event->type == GDK_BUTTON_PRESS){ - return linphone_gtk_call_log_popup_contact(widget, event); - } - return FALSE; -} - -void linphone_gtk_call_log_clear_missed_call(void){ - GtkWidget *mw = linphone_gtk_get_main_window(); - GtkWidget *label = linphone_gtk_get_widget(mw, "history_tab_label"); - gtk_label_set_text(GTK_LABEL(label), _("Recent calls")); -} - -gboolean linphone_gtk_call_log_reset_missed_call(GtkWidget *w, GdkEvent *event,gpointer user_data){ - GtkWidget *mw=linphone_gtk_get_main_window(); - GtkNotebook *notebook=GTK_NOTEBOOK(linphone_gtk_get_widget(mw,"viewswitch")); - gtk_notebook_set_current_page(notebook,0); - linphone_core_reset_missed_calls_count(linphone_gtk_get_core()); - linphone_gtk_call_log_clear_missed_call(); - return TRUE; -} - -void linphone_gtk_call_log_display_missed_call(int nb){ - GtkWidget *mw = linphone_gtk_get_main_window(); - GtkWidget *label = linphone_gtk_get_widget(mw, "history_tab_label"); - gchar *buf = g_markup_printf_escaped(_("Recent calls (%i)"), nb); - gtk_label_set_markup(GTK_LABEL(label), buf); -} - -void linphone_gtk_call_log_update(GtkWidget *w){ - GtkTreeView *v=GTK_TREE_VIEW(linphone_gtk_get_widget(w,"logs_view")); - GtkTreeStore *store; - const MSList *logs; - GtkTreeSelection *select; - GtkWidget *notebook=linphone_gtk_get_widget(w,"viewswitch"); - gint nb; - - store=(GtkTreeStore*)gtk_tree_view_get_model(v); - if (store==NULL){ - store=gtk_tree_store_new(3,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_POINTER,G_TYPE_STRING); - gtk_tree_view_set_model(v,GTK_TREE_MODEL(store)); - g_object_unref(G_OBJECT(store)); - fill_renderers(GTK_TREE_VIEW(linphone_gtk_get_widget(w,"logs_view"))); - select=gtk_tree_view_get_selection(v); - gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE); - g_signal_connect_swapped(G_OBJECT(select),"changed",(GCallback)call_log_selection_changed,v); - g_signal_connect(G_OBJECT(notebook),"focus-tab",(GCallback)linphone_gtk_call_log_reset_missed_call,NULL); - g_signal_connect(G_OBJECT(v),"button-press-event",(GCallback)linphone_gtk_call_log_button_pressed,NULL); - } - nb=linphone_core_get_missed_calls_count(linphone_gtk_get_core()); - if(nb > 0) - linphone_gtk_call_log_display_missed_call(nb); - gtk_tree_store_clear (store); - - for (logs=linphone_core_get_call_logs(linphone_gtk_get_core());logs!=NULL;logs=logs->next){ - LinphoneCallLog *cl=(LinphoneCallLog*)logs->data; - GtkTreeIter iter, iter2; - LinphoneAddress *la=linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl); - char *addr= linphone_address_as_string(la); - const char *display; - gchar *logtxt, *headtxt, *minutes, *seconds; - gchar quality[20]; - const char *status=NULL; - gchar *start_date=NULL; - LinphoneFriend *lf=NULL; - int duration=linphone_call_log_get_duration(cl); - time_t start_date_time=linphone_call_log_get_start_date(cl); - const gchar *call_status_icon_name; - -#if GLIB_CHECK_VERSION(2,30,0) // The g_date_time_format function exists since 2.26.0 but the '%c' format is only supported since 2.30.0 - if (start_date_time){ - GDateTime *dt=g_date_time_new_from_unix_local(start_date_time); - start_date=g_date_time_format(dt,"%c"); - g_date_time_unref(dt); - } -#else - start_date=g_strdup(ctime(&start_date_time)); - if (start_date[strlen(start_date) - 1] == '\n') { - start_date[strlen(start_date) - 1] = '\0'; - } -#endif - lf=linphone_core_find_friend(linphone_gtk_get_core(),la); - if(lf != NULL){ - /*update display name from friend*/ - display = linphone_friend_get_name(lf); - if (display != NULL) linphone_address_set_display_name(la, display); - } else { - display=linphone_address_get_display_name(la); - } - if (display==NULL){ - display=linphone_address_get_username (la); - if (display==NULL){ - display=linphone_address_get_domain (la); - } - } - - if (linphone_call_log_get_quality(cl)!=-1){ - snprintf(quality,sizeof(quality),"%.1f",linphone_call_log_get_quality(cl)); - }else snprintf(quality,sizeof(quality)-1,"%s",_("n/a")); - switch(linphone_call_log_get_status(cl)){ - case LinphoneCallAborted: - status=_("Aborted"); - break; - case LinphoneCallMissed: - status=_("Missed"); - break; - case LinphoneCallDeclined: - status=_("Declined"); - break; - case LinphoneCallAnsweredElsewhere: - status=_("Answered elsewhere"); - break; - case LinphoneCallDeclinedElsewhere: - status=_("Declined elsewhere"); - break; - default: - break; - } - minutes=g_markup_printf_escaped( - ngettext("%i minute", "%i minutes", duration/60), - duration/60); - seconds=g_markup_printf_escaped( - ngettext("%i second", "%i seconds", duration%60), - duration%60); - if (status==NULL) { - headtxt=g_markup_printf_escaped("%s\t%s",display,start_date ? start_date : ""); - logtxt=g_markup_printf_escaped( - _("%s\t" - "Quality: %s\n%s\t%s\t"), - addr, quality, minutes, seconds); - } else { - headtxt=g_markup_printf_escaped(_("%s\t%s"),display,start_date ? start_date : ""); - logtxt=g_markup_printf_escaped( - "%s\t" - "\n%s",addr, status); - } - g_free(minutes); - g_free(seconds); - if (start_date) g_free(start_date); - gtk_tree_store_append (store,&iter,NULL); - call_status_icon_name = linphone_call_log_get_dir(cl) == LinphoneCallOutgoing ? - "linphone-call-status-outgoing" : "linphone-call-status-incoming"; - gtk_tree_store_set (store,&iter, - 0, call_status_icon_name, - 1, headtxt,2,cl,-1); - gtk_tree_store_append (store,&iter2,&iter); - gtk_tree_store_set (store,&iter2,1,logtxt,-1); - ms_free(addr); - g_free(logtxt); - g_free(headtxt); - } -} - -void linphone_gtk_history_row_activated(GtkWidget *treeview){ - if (put_selection_to_uribar(treeview)){ - GtkWidget *mw=linphone_gtk_get_main_window(); - linphone_gtk_start_call(linphone_gtk_get_widget(mw,"start_call")); - } -} - -void linphone_gtk_history_row_selected(GtkWidget *treeview){ - put_selection_to_uribar(treeview); -} - -void linphone_gtk_clear_call_logs(GtkWidget *button){ - linphone_core_clear_call_logs (linphone_gtk_get_core()); - linphone_gtk_call_log_clear_missed_call(); - linphone_gtk_call_log_update(gtk_widget_get_toplevel(button)); -} - -void linphone_gtk_call_log_callback(GtkWidget *button){ - GtkWidget *mw=linphone_gtk_get_main_window(); - if (put_selection_to_uribar(linphone_gtk_get_widget(mw,"logs_view"))) - linphone_gtk_start_call(linphone_gtk_get_widget(mw,"start_call")); -} - -void linphone_gtk_call_log_response(GtkWidget *w, guint response_id){ - GtkWidget *mw=linphone_gtk_get_main_window(); - if (response_id==1){ - if (put_selection_to_uribar(linphone_gtk_get_widget(w,"logs_view"))) - linphone_gtk_start_call(linphone_gtk_get_widget(mw,"start_call")); - }else if (response_id==2){ - linphone_core_clear_call_logs (linphone_gtk_get_core()); - linphone_gtk_call_log_update(w); - return; - } - g_object_set_data(G_OBJECT(mw),"call_logs",NULL); - gtk_widget_destroy(w); -} diff --git a/gtk/chat.c b/gtk/chat.c deleted file mode 100644 index 9a15c8236..000000000 --- a/gtk/chat.c +++ /dev/null @@ -1,683 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "linphone.h" -#include - -#ifdef HAVE_GTK_OSX -#include -#endif - -#if defined(_WIN32) && !defined(F_OK) -#define F_OK 00 /*visual studio does not define F_OK*/ -#endif - -#define NB_MSG_HIST 250000 - -#define CONFIG_FILE ".linphone-history.db" - -#include "regex.h" - -GRegex *uri_regex = NULL; - -static void free_uri_regex(void) { - if(uri_regex) g_regex_unref(uri_regex); -} - -static const GRegex *get_uri_regex(void) { - const gchar *pattern = BC_REGEX_URI; - GError *error = NULL; - if(uri_regex == NULL) { - uri_regex = g_regex_new(pattern, G_REGEX_OPTIMIZE, 0, &error); - if(error) { - g_warning("Could not parse regex pattern for URIs: %s", error->message); - g_error_free(error); - uri_regex = NULL; - return NULL; - } - atexit(free_uri_regex); - } - return uri_regex; -} - -char *linphone_gtk_message_storage_get_db_file(const char *filename){ - const int path_max=1024; - char *db_file=NULL; - - db_file=(char *)g_malloc(path_max*sizeof(char)); - if (filename==NULL) filename=CONFIG_FILE; - /*try accessing a local file first if exists*/ - if (bctbx_file_exist(CONFIG_FILE)==0){ - snprintf(db_file,path_max,"%s",filename); - }else{ -#ifdef _WIN32 - const char *appdata=getenv("APPDATA"); - if (appdata){ - snprintf(db_file,path_max,"%s\\%s",appdata,LINPHONE_CONFIG_DIR); - CreateDirectory(db_file,NULL); - snprintf(db_file,path_max,"%s\\%s\\%s",appdata,LINPHONE_CONFIG_DIR,filename); - } -#else - const char *home=getenv("HOME"); - if (home==NULL) home="."; - snprintf(db_file,path_max,"%s/%s",home,filename); -#endif - } - return db_file; -} - -void linphone_gtk_mark_chat_read(LinphoneChatRoom *cr) { - linphone_chat_room_mark_as_read(cr); -#ifdef __APPLE__ - linphone_gtk_update_badge_count(); -#endif -} - -void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) { - GtkWidget *main_window=linphone_gtk_get_main_window (); - GtkWidget *nb=linphone_gtk_get_widget(main_window,"viewswitch"); - GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list"); - GtkWidget *w=g_object_get_data(G_OBJECT(friendlist),"chatview"); - gchar *from; - - g_return_if_fail(w!=NULL); - gtk_notebook_remove_page(GTK_NOTEBOOK(nb),gtk_notebook_page_num(GTK_NOTEBOOK(nb),w)); - linphone_gtk_mark_chat_read(cr); - g_object_set_data(G_OBJECT(friendlist),"chatview",NULL); - from=g_object_get_data(G_OBJECT(w),"from_message"); - if (from){ - g_object_set_data(G_OBJECT(w),"from_message",NULL); - g_free(from); - } - g_object_set_data(G_OBJECT(w),"cr",NULL); - linphone_gtk_friend_list_set_active_address(NULL); - gtk_widget_destroy(w); -} - -const char* get_display_name(const LinphoneAddress *from){ - const char *display; - display=linphone_address_get_display_name(from); - if (display==NULL || display[0]=='\0') { - display=linphone_address_get_username(from); - } - return display; -} - -GtkWidget *create_tab_chat_header(LinphoneChatRoom *cr, const LinphoneAddress *uri){ - GtkWidget *tab_header = linphone_gtk_make_tab_header(get_display_name(uri), "linphone-start-chat", TRUE, G_CALLBACK(linphone_gtk_quit_chatroom), cr); - gtk_widget_show_all(tab_header); - return tab_header; -} - -void update_chat_header(GtkNotebook *notebook, GtkWidget *chat_view, LinphoneChatRoom *cr, const LinphoneAddress *uri) { - GtkWidget *header = linphone_gtk_make_tab_header(get_display_name(uri), "linphone-start-chat", TRUE, G_CALLBACK(linphone_gtk_quit_chatroom), cr); - gtk_widget_show_all(header); - gtk_notebook_set_tab_label(notebook, chat_view, header); -} - -static gboolean scroll_to_end(GtkTextView *w){ - GtkTextBuffer *buffer=gtk_text_view_get_buffer(w); - GtkTextIter iter; - gtk_text_buffer_get_end_iter(buffer,&iter); - gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (w), &iter, 0.0, FALSE, 0, 0); - return FALSE; -} - -static void write_body(GtkTextBuffer *buffer, GtkTextIter *iter, const gchar *text, gint len, gboolean is_me, gboolean is_link) { - const char *me_tag_name = is_me ? "me" : NULL; - const char *link_tag_name = is_link ? "link" : NULL; - if(me_tag_name) { - gtk_text_buffer_insert_with_tags_by_name(buffer, iter, text, len, "body", me_tag_name, link_tag_name, NULL); - } else { - gtk_text_buffer_insert_with_tags_by_name(buffer, iter, text, len, "body", link_tag_name, NULL); - } -} - -void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, - gboolean me,LinphoneChatRoom *cr,LinphoneChatMessage *msg, gboolean hist){ - GtkTextView *text=GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"textview")); - GtkTextBuffer *buffer=gtk_text_view_get_buffer(text); - GtkTextIter iter; - char *from_str=linphone_address_as_string_uri_only(from); - gchar *from_message=(gchar *)g_object_get_data(G_OBJECT(w),"from_message"); - GHashTable *table=(GHashTable*)g_object_get_data(G_OBJECT(w),"table"); - const GRegex *uri_regex = get_uri_regex(); - GMatchInfo *match_info = NULL; - const char *message = linphone_chat_message_get_text(msg); - const char *external_body_url = linphone_chat_message_get_external_body_url(msg); - time_t t; - char buf[80]; - time_t tnow; - struct tm *tm; - int tnow_day; - int tnow_year; - int pos = 0, start, end; - - gtk_text_buffer_get_end_iter(buffer, &iter); - if (g_strcmp0(from_message,from_str)!=0){ - gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, get_display_name(from), -1, - "from", me ? "me" : NULL, NULL); - gtk_text_buffer_insert_with_tags_by_name(buffer,&iter, " : ", -1, - "from", me ? "me" : NULL, NULL); - gtk_text_buffer_insert(buffer,&iter,"\n",-1); - g_free(from_message); - g_object_set_data(G_OBJECT(w),"from_message",g_strdup(from_str)); - } - ms_free(from_str); - - if (external_body_url) message = external_body_url; - - // Inserts message body and tags URIs as hypertext links - if(message) { - g_regex_match(uri_regex, message, 0, &match_info); - while(g_match_info_matches(match_info)) { - g_match_info_fetch_pos(match_info, 0, &start, &end); - if(pos < start) write_body(buffer, &iter, &message[pos], start-pos, me, FALSE); - write_body(buffer, &iter, &message[start], end-start, me, TRUE); - pos = end; - g_match_info_next(match_info, NULL); - } - if((size_t)pos < strlen(message)) write_body(buffer, &iter, &message[pos], -1, me, FALSE); - gtk_text_buffer_insert(buffer,&iter,"\n",-1); - g_match_info_free(match_info); - } - - g_hash_table_insert(table,GUINT_TO_POINTER(linphone_chat_message_get_storage_id(msg)),GINT_TO_POINTER(gtk_text_iter_get_line(&iter))); - switch (linphone_chat_message_get_state (msg)){ - case LinphoneChatMessageStateInProgress: - gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,_("Sending..."),-1,"status", me ? "me" : NULL, NULL); - break; - case LinphoneChatMessageStateDelivered: - t=linphone_chat_message_get_time(msg); - tnow=time(NULL); - tm=localtime(&tnow); - tnow_day=tm->tm_yday; - tnow_year=tm->tm_year; - tm=localtime(&t); - if(tnow_day != tm->tm_yday || (tnow_day == tm->tm_yday && tnow_year != tm->tm_year)) { - strftime(buf,80,"%a %x, %H:%M",tm); - } else { - strftime(buf,80,"%H:%M:%S",tm); - } - gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,buf,-1,"status", me ? "me" : NULL, NULL); - break; - case LinphoneChatMessageStateNotDelivered: - gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,_("Message not sent"),-1,"status", me ? "me" : NULL, NULL); - break; - default: - break; - } - gtk_text_buffer_insert(buffer,&iter,"\n",-1); - g_idle_add((GSourceFunc)scroll_to_end,text); -} - -void update_chat_state_message(LinphoneChatMessageState state,LinphoneChatMessage *msg){ - GtkWidget *main_window=linphone_gtk_get_main_window(); - GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list"); - GtkWidget *page=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); - GHashTable *table=(GHashTable*)g_object_get_data(G_OBJECT(page),"table"); - - if (page!=NULL) { - char buf[80]; - time_t t; - struct tm *tm; - GtkTextView *text=GTK_TEXT_VIEW(linphone_gtk_get_widget(page,"textview")); - GtkTextBuffer *b=gtk_text_view_get_buffer(text); - GtkTextIter iter; - GtkTextIter end; - GtkTextIter start; - gint line; - gpointer hash_table_ptr = g_hash_table_lookup(table,GUINT_TO_POINTER(linphone_chat_message_get_storage_id(msg))); - if (hash_table_ptr != NULL) { - line = GPOINTER_TO_INT(hash_table_ptr); - gtk_text_buffer_get_iter_at_line(b,&iter,line); - if(gtk_text_iter_get_chars_in_line(&iter) >0) { - gtk_text_buffer_get_iter_at_line_offset(b,&start,line, - gtk_text_iter_get_chars_in_line(&iter)-1); - }else{ - gtk_text_buffer_get_iter_at_line_offset(b,&start,line,0); - } - gtk_text_buffer_get_iter_at_line_offset(b,&end,line,0); - gtk_text_buffer_delete(b,&start,&end); - gtk_text_buffer_get_iter_at_line(b,&iter,line); - - switch (state) { - case LinphoneChatMessageStateInProgress: - gtk_text_buffer_insert_with_tags_by_name(b,&iter,_("Sending..."),-1,"status", "me", NULL); - break; - case LinphoneChatMessageStateDelivered: - t=time(NULL); - tm=localtime(&t); - strftime(buf,80,"%H:%M:%S",tm); - gtk_text_buffer_insert_with_tags_by_name(b,&iter,(gchar*)buf,-1,"status", "me", NULL); - break; - case LinphoneChatMessageStateNotDelivered: - gtk_text_buffer_insert_with_tags_by_name(b,&iter,_("Message not sent"),-1,"status", "me", NULL); - break; - default: - break; - } - } - } -} - -static void on_chat_state_changed(LinphoneChatMessage *msg, LinphoneChatMessageState state){ - update_chat_state_message(state,msg); -} - -void linphone_gtk_compose_text(void) { - GtkWidget *main_window=linphone_gtk_get_main_window(); - GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list"); - GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); - LinphoneChatRoom *cr=g_object_get_data(G_OBJECT(w),"cr"); - if (cr) { - linphone_chat_room_compose(cr); - linphone_gtk_mark_chat_read(cr); - linphone_gtk_friend_list_update_button_display(GTK_TREE_VIEW(friendlist)); - } -} - -void linphone_gtk_send_text(void){ - GtkWidget *main_window=linphone_gtk_get_main_window(); - GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list"); - GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); - GtkWidget *entry=linphone_gtk_get_widget(w,"text_entry"); - const gchar *entered; - LinphoneChatRoom *cr=g_object_get_data(G_OBJECT(w),"cr"); - entered=gtk_entry_get_text(GTK_ENTRY(entry)); - if (strlen(entered)>0) { - LinphoneChatMessage *msg; - LinphoneChatMessageCbs *cbs; - msg=linphone_chat_message_ref(linphone_chat_room_create_message(cr,entered)); - cbs=linphone_chat_message_get_callbacks(msg); - linphone_chat_message_cbs_set_msg_state_changed(cbs,on_chat_state_changed); - linphone_chat_room_send_chat_message(cr,msg); - linphone_gtk_push_text(w,linphone_chat_message_get_from(msg), - TRUE,cr,msg,FALSE); - - // Disconnect and reconnect the "changed" signal to prevent triggering it when clearing the text entry. - g_signal_handlers_disconnect_by_func(G_OBJECT(entry),(GCallback)linphone_gtk_compose_text,NULL); - gtk_entry_set_text(GTK_ENTRY(entry),""); - g_signal_connect_swapped(G_OBJECT(entry),"changed",(GCallback)linphone_gtk_compose_text,NULL); - - linphone_chat_message_unref(msg); - } -} - -static void linphone_gtk_chat_message_destroy(LinphoneChatMessage *msg){ - linphone_chat_message_destroy(msg); -} - -void linphone_gtk_free_list(bctbx_list_t *messages){ - bctbx_list_for_each(messages,(void (*)(void*))linphone_gtk_chat_message_destroy); - bctbx_list_free(messages); -} - -void display_history_message(GtkWidget *chat_view,bctbx_list_t *messages,const LinphoneAddress *with){ - if (messages != NULL){ - bctbx_list_t *it; - char *from_str; - char *with_str; - gchar *tmp; - for(it=messages;it!=NULL;it=it->next){ - LinphoneChatMessage *msg=(LinphoneChatMessage *)it->data; - from_str=linphone_address_as_string_uri_only(linphone_chat_message_get_from(msg)); - with_str=linphone_address_as_string_uri_only(with); - linphone_gtk_push_text(chat_view,strcmp(from_str,with_str)==0? with : - linphone_chat_message_get_from(msg), - strcmp(from_str,with_str)==0? FALSE : TRUE, - linphone_chat_message_get_chat_room(msg),msg,TRUE); - ms_free(from_str); - ms_free(with_str); - } - tmp=g_object_get_data(G_OBJECT(chat_view),"from_message"); - if (tmp){ - g_object_set_data(G_OBJECT(chat_view),"from_message",NULL); - g_free(tmp); - } - - linphone_gtk_free_list(messages); - } -} - -static void linphone_gtk_chat_add_contact(const LinphoneAddress *addr){ - LinphoneFriend *lf=NULL; - LinphoneCore *lc = linphone_gtk_get_core(); - gboolean show_presence=FALSE; - char *uri=linphone_address_as_string(addr); - - lf=linphone_core_create_friend_with_address(lc, uri); - ms_free(uri); - - linphone_friend_set_inc_subscribe_policy(lf,LinphoneSPWait); - linphone_friend_send_subscribe(lf,show_presence); - - linphone_friend_set_address(lf,addr); - linphone_core_add_friend(lc, lf); - linphone_gtk_show_friends(); -} - -static GdkColor *_linphone_gtk_chatroom_get_link_color(GtkWidget *chatview) { - GValue color_value = {0}; - g_value_init(&color_value, GDK_TYPE_COLOR); - gtk_style_get_style_property( - gtk_widget_get_style(chatview), - G_OBJECT_TYPE(chatview), - "link-color", &color_value); - - return (GdkColor *)g_value_get_boxed(&color_value); -} - -static gboolean link_event_handler(GtkTextTag *tag, GObject *text_view,GdkEvent *event, GtkTextIter *iter, GtkWidget *chat_view) { - if(event->type == GDK_BUTTON_PRESS) { - GtkTextIter uri_begin = *iter; - GtkTextIter uri_end = *iter; - gchar *uri = NULL; - LinphoneChatRoom *chat_room = (LinphoneChatRoom *)g_object_get_data(G_OBJECT(chat_view), "cr"); - GtkWidget *main_window = linphone_gtk_get_main_window(); - GtkWidget *friendlist = linphone_gtk_get_widget(main_window, "contact_list"); - - gtk_text_iter_backward_to_tag_toggle(&uri_begin, tag); - gtk_text_iter_forward_to_tag_toggle(&uri_end, tag); - uri = gtk_text_iter_get_slice(&uri_begin, &uri_end); - if(((GdkEventButton *)event)->button == 1) { - linphone_gtk_open_browser(uri); - } else if(((GdkEventButton *)event)->button == 3) { - GtkMenu *menu = GTK_MENU(g_object_get_data(text_view, "link_ctx_menu")); - g_object_set_data_full(G_OBJECT(menu), "uri", g_strdup(uri), g_free); - gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 3, gdk_event_get_time(event)); - } - g_free(uri); - - linphone_gtk_mark_chat_read(chat_room); - linphone_gtk_friend_list_update_button_display(GTK_TREE_VIEW(friendlist)); - - return TRUE; - } - return FALSE; -} - -static void chatroom_enable_hand_cursor(GdkWindow *window, gboolean hand_cursor_enabled) { -#if GTK_CHECK_VERSION(2,22,0) - GdkCursor *cursor = gdk_window_get_cursor(window); - GdkCursor *new_cursor = NULL; - if(!hand_cursor_enabled && gdk_cursor_get_cursor_type(cursor) != GDK_XTERM) { - new_cursor = gdk_cursor_new(GDK_XTERM); - } else if(hand_cursor_enabled && gdk_cursor_get_cursor_type(cursor) != GDK_HAND1) { - new_cursor = gdk_cursor_new(GDK_HAND1); - } - if(new_cursor) { - gdk_window_set_cursor(window, new_cursor); - gdk_cursor_unref(new_cursor); - } -#endif -} - -static gboolean chatroom_event(GtkWidget *widget, GdkEvent *event, gpointer user_data) { - gint wx, wy, bx, by; - GtkTextView *chatroom = GTK_TEXT_VIEW(widget); - GtkTextBuffer *buffer = gtk_text_view_get_buffer(chatroom); - GtkTextTag *link_tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), "link"); - GdkWindow *window = gtk_text_view_get_window(chatroom, GTK_TEXT_WINDOW_TEXT); - GtkTextIter iter; - if(event->type == GDK_MOTION_NOTIFY) { - GdkEventMotion *motion_ev = (GdkEventMotion *)event; - wx = (gint)motion_ev->x; - wy = (gint)motion_ev->y; - gtk_text_view_window_to_buffer_coords(chatroom, GTK_TEXT_WINDOW_TEXT, wx, wy, &bx, &by); - gtk_text_view_get_iter_at_location(chatroom, &iter, bx, by); - if(gtk_text_iter_has_tag(&iter, link_tag)) { - chatroom_enable_hand_cursor(window, TRUE); - } else { - chatroom_enable_hand_cursor(window, FALSE); - } - } - return FALSE; -} - -static gboolean copy_uri_into_clipboard_handler(GtkMenuItem *menuitem, gpointer user_data) { - GtkWidget *menu = gtk_widget_get_parent(GTK_WIDGET(menuitem)); - const gchar *uri = (const gchar *)g_object_get_data(G_OBJECT(menu), "uri"); - GtkClipboard *clipboard = NULL; - GdkAtom clipboard_atom = gdk_atom_intern("CLIPBOARD", TRUE); - if(clipboard_atom == GDK_NONE) { - g_warning("Could not find CLIPBOARD atom"); - return FALSE; - } - clipboard = gtk_clipboard_get(clipboard_atom); - if(uri) gtk_clipboard_set_text(clipboard, uri, -1); - return FALSE; -} - -static void refresh_lime_icon(GtkWidget* chat_view, LinphoneChatRoom*cr) { - GtkWidget *lime_icon = linphone_gtk_get_widget(chat_view, "lime_icon"); - if (linphone_chat_room_lime_available(cr)) { - gtk_widget_show(lime_icon); - } else { - gtk_widget_hide(lime_icon); - } -} - -static gint linphone_gtk_window_focused(GtkWidget* widget, GdkEvent *event, gpointer user_data) { - // if we are in a chat, mark it as read - GtkWidget *main_window=linphone_gtk_get_main_window(); - GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list"); - GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); - LinphoneChatRoom *cr=w?g_object_get_data(G_OBJECT(w),"cr"):NULL; - if (cr) { - linphone_gtk_mark_chat_read(cr); - } - refresh_lime_icon(w, cr); - return FALSE; -} - -GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddress *with){ - GtkWidget *chat_view=linphone_gtk_create_widget("chatroom_frame"); - GtkWidget *main_window=linphone_gtk_get_main_window(); - GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch"); - GtkWidget *text=linphone_gtk_get_widget(chat_view,"textview"); - GdkColor color_grey = {0, 32512, 32512, 32512}; - GdkColor color_light_grey = {0, 56832, 60928, 61952}; - GdkColor color_black = {0}; - int idx; - GtkWidget *button; - GtkWidget *entry = linphone_gtk_get_widget(chat_view,"text_entry"); - bctbx_list_t *messages; - GHashTable *table; - GtkTextTag *tmp_tag; - GtkWidget *link_ctx_menu = gtk_menu_new(); - GtkWidget *link_ctx_menu_copy_item = gtk_menu_item_new_with_label(_("Copy")); - - gtk_notebook_append_page(notebook,chat_view,create_tab_chat_header(cr,with)); - idx = gtk_notebook_page_num(notebook, chat_view); - gtk_notebook_set_current_page(notebook, idx); - gtk_widget_show(chat_view); - table=g_hash_table_new_full(g_direct_hash,g_direct_equal,NULL,NULL); - g_object_set_data(G_OBJECT(chat_view),"cr",cr); - g_object_set_data(G_OBJECT(chat_view),"from_message",NULL); - g_object_set_data_full(G_OBJECT(chat_view),"table",table,(GDestroyNotify)g_hash_table_destroy); - - gtk_text_buffer_create_tag( - gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), - "me", - "foreground_gdk", &color_black, - "paragraph-background-gdk", &color_light_grey, - NULL); - - gtk_text_buffer_create_tag( - gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), - "from", - "weight", PANGO_WEIGHT_BOLD, - NULL); - - gtk_text_buffer_create_tag( - gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), - "body", - "indent", 10, - NULL); - - gtk_text_buffer_create_tag( - gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), - "status", - "size-points", 9.0, - "foreground_gdk", &color_grey, - "style", PANGO_STYLE_ITALIC, - "justification", GTK_JUSTIFY_RIGHT, - NULL); - - tmp_tag = gtk_text_buffer_create_tag( - gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), - "link", - "underline", PANGO_UNDERLINE_SINGLE, - "foreground_gdk", _linphone_gtk_chatroom_get_link_color(chat_view), - NULL); - g_signal_connect(G_OBJECT(tmp_tag), "event", G_CALLBACK(link_event_handler), chat_view); - g_signal_connect(G_OBJECT(text), "event", G_CALLBACK(chatroom_event), NULL); - gtk_menu_shell_append(GTK_MENU_SHELL(link_ctx_menu), link_ctx_menu_copy_item); - g_signal_connect(G_OBJECT(link_ctx_menu_copy_item), "activate", G_CALLBACK(copy_uri_into_clipboard_handler), NULL); - gtk_widget_show_all(link_ctx_menu); - g_object_set_data_full(G_OBJECT(text), "link_ctx_menu", link_ctx_menu, g_object_unref); - g_object_ref_sink(G_OBJECT(link_ctx_menu)); - - messages = linphone_chat_room_get_history(cr,NB_MSG_HIST); - display_history_message(chat_view,messages,with); - button = linphone_gtk_get_widget(chat_view,"send"); - g_signal_connect_swapped(G_OBJECT(button),"clicked",(GCallback)linphone_gtk_send_text,NULL); - - g_signal_connect_swapped(G_OBJECT(entry),"activate",(GCallback)linphone_gtk_send_text,NULL); - g_signal_connect_swapped(G_OBJECT(entry),"changed",(GCallback)linphone_gtk_compose_text,NULL); - g_signal_connect(G_OBJECT(notebook),"switch_page",(GCallback)linphone_gtk_notebook_tab_select,NULL); - - gtk_signal_connect(GTK_OBJECT(main_window), "focus-in-event", GTK_SIGNAL_FUNC(linphone_gtk_window_focused), NULL); - - refresh_lime_icon(chat_view, cr); - - return chat_view; -} - -LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with){ - LinphoneChatRoom *cr=linphone_core_get_chat_room(linphone_gtk_get_core(), with); - return cr; -} - -void linphone_gtk_load_chatroom(LinphoneChatRoom *cr,const LinphoneAddress *uri,GtkWidget *chat_view){ - GtkWidget *main_window=linphone_gtk_get_main_window (); - GtkWidget *notebook = linphone_gtk_get_widget(main_window, "viewswitch"); - LinphoneChatRoom *cr2=(LinphoneChatRoom *)g_object_get_data(G_OBJECT(chat_view),"cr"); - const LinphoneAddress *from=linphone_chat_room_get_peer_address(cr2); - char *from_str=linphone_address_as_string_uri_only(from); - char *uri_str=linphone_address_as_string(uri); - char *uri_only=linphone_address_as_string_uri_only(uri); - bctbx_list_t *messages=NULL; - - if(g_strcmp0(from_str,uri_only)!=0){ - GtkTextView *text_view=GTK_TEXT_VIEW(linphone_gtk_get_widget(chat_view,"textview")); - GtkTextIter start; - GtkTextIter end; - GtkTextBuffer *text_buffer; - - text_buffer=gtk_text_view_get_buffer(text_view); - gtk_text_buffer_get_bounds(text_buffer, &start, &end); - gtk_text_buffer_delete (text_buffer, &start, &end); - update_chat_header(GTK_NOTEBOOK(notebook), chat_view, cr, uri); - g_object_set_data(G_OBJECT(chat_view),"cr",cr); - g_object_set_data(G_OBJECT(linphone_gtk_get_widget(main_window,"contact_list")),"chatview",(gpointer)chat_view); - messages=linphone_chat_room_get_history(cr,NB_MSG_HIST); - g_object_set_data(G_OBJECT(chat_view),"from_message",g_strdup(uri_str)); - display_history_message(chat_view,messages,uri); - gtk_text_buffer_get_end_iter(text_buffer,&end); - gtk_text_view_scroll_to_iter(text_view,&end,0,FALSE,1.0,0); - } - refresh_lime_icon(chat_view, cr); - - ms_free(from_str); - ms_free(uri_str); - ms_free(uri_only); -} - -void linphone_gtk_chat_destroyed(GtkWidget *w){ - /* - LinphoneChatRoom *cr=(LinphoneChatRoom*)g_object_get_data(G_OBJECT(w),"cr"); - */ -} - - -void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, - LinphoneChatMessage *msg ) { - GtkWidget *main_window=linphone_gtk_get_main_window(); - GtkWidget *friendlist=linphone_gtk_get_widget ( main_window,"contact_list" ); - GtkWidget *w; - gboolean send=TRUE; - /*GtkNotebook *notebook= ( GtkNotebook * ) linphone_gtk_get_widget ( main_window,"viewswitch" );*/ - const LinphoneAddress *from= linphone_chat_message_get_from ( msg ); - - w= ( GtkWidget* ) g_object_get_data ( G_OBJECT ( friendlist ),"chatview" ); - if ( w!=NULL ) { - /* Chat window opened */ - const LinphoneAddress *from_chatview=linphone_gtk_friend_list_get_active_address(); - if (linphone_address_weak_equal(from,from_chatview)) { - send=TRUE; - } else { - if ( !linphone_gtk_friend_list_is_contact ( linphone_chat_message_get_from ( msg ) ) ) { - linphone_gtk_chat_add_contact ( linphone_chat_message_get_from ( msg ) ); - } - send=FALSE; - } - } else { - /* Chat window closed */ -#ifdef SQLITE_STORAGE_ENABLED - send=FALSE; -#else - send=TRUE; -#endif - if ( !linphone_gtk_friend_list_is_contact ( linphone_chat_message_get_from ( msg ) ) ) { - linphone_gtk_chat_add_contact ( linphone_chat_message_get_from ( msg ) ); - } - w=linphone_gtk_init_chatroom ( room,linphone_chat_message_get_from ( msg ) ); - g_object_set_data ( G_OBJECT ( friendlist ),"chatview", ( gpointer ) w ); - linphone_gtk_friend_list_set_active_address(from); - } - -#ifdef HAVE_GTK_OSX - /* Notified when a new message is sent */ - linphone_gtk_status_icon_set_blinking ( TRUE ); -#else - if ( !gtk_window_is_active ( GTK_WINDOW ( main_window ) ) ) { - if ( !GPOINTER_TO_INT ( g_object_get_data ( G_OBJECT ( w ),"is_notified" ) ) ) { - linphone_gtk_notify ( NULL, msg, NULL ); - g_object_set_data ( G_OBJECT ( w ),"is_notified",GINT_TO_POINTER ( TRUE ) ); - } else { - g_object_set_data ( G_OBJECT ( w ),"is_notified",GINT_TO_POINTER ( FALSE ) ); - } - } -#endif - if ( send ) { - linphone_gtk_push_text ( w,linphone_chat_message_get_from ( msg ), - FALSE,room,msg,FALSE ); - } - linphone_core_play_local(lc,linphone_gtk_get_sound_path("incoming_chat.wav")); - linphone_gtk_show_friends(); - -} - -void linphone_gtk_is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) { - GtkWidget *main_window = linphone_gtk_get_main_window(); - GtkWidget *friendlist = linphone_gtk_get_widget(main_window, "contact_list"); - linphone_gtk_friend_list_update_button_display(GTK_TREE_VIEW(friendlist)); -} diff --git a/gtk/chatroom_frame.ui b/gtk/chatroom_frame.ui deleted file mode 100644 index d7b8137a3..000000000 --- a/gtk/chatroom_frame.ui +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - True - False - 0 - none - - - True - False - - - True - True - never - - - True - True - 4 - False - word-char - False - - - - - True - True - 0 - - - - - True - False - 10 - - - True - False - 16 - linphone-security-ok - - - False - False - 0 - - - - - True - True - - True - False - False - True - True - - - True - True - 1 - - - - - True - True - True - - - True - False - - - True - False - linphone-chat-send - - - True - True - 0 - - - - - True - False - Send - - - True - True - 7 - 1 - - - - - - - False - False - 2 - - - - - False - False - 1 - - - - - - - - - diff --git a/gtk/conf_frame.ui b/gtk/conf_frame.ui deleted file mode 100644 index c9503e7f6..000000000 --- a/gtk/conf_frame.ui +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - True - False - 0 - none - - - True - False - - - True - False - - - End conference - True - True - True - - - False - False - end - 0 - - - - - True - True - end - 0 - - - - - True - False - - - Record - True - True - True - - - - False - False - 0 - - - - - True - False - True - char - - - True - True - 1 - - - - - False - False - end - 1 - - - - - - - - - diff --git a/gtk/conference.c b/gtk/conference.c deleted file mode 100644 index 9073d629e..000000000 --- a/gtk/conference.c +++ /dev/null @@ -1,183 +0,0 @@ -/*************************************************************************** - * gtk/conference.c - * - * Mon Sep 12, 2011 - * Copyright 2011 Belledonne Communications - * Author: Simon Morlat - * Email simon dot morlat at linphone dot org - ****************************************************************************/ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include "linphone.h" - -#define PADDING_PIXELS 4 - -/* - * conferencee_box = a vbox where participants are added or removed - * conf_frame = the conference tab - */ - -static GtkWidget *create_conference_label(void){ - GtkWidget *box=gtk_hbox_new(FALSE,0); - gtk_box_pack_start(GTK_BOX(box),gtk_image_new_from_icon_name("linphone-conference-start",GTK_ICON_SIZE_MENU),FALSE,FALSE,0); - gtk_box_pack_end(GTK_BOX(box),gtk_label_new(_("Conference")),TRUE,FALSE,0); - gtk_widget_show_all(box); - return box; -} - -static void init_local_participant(GtkWidget *participant){ - GtkWidget *sound_meter; - GtkWidget *button=linphone_gtk_get_widget(participant,"conference_control"); - gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(participant,"callee_name_label")),_("Me")); - sound_meter=linphone_gtk_get_widget(participant,"sound_indicator"); - linphone_gtk_enable_mute_button(GTK_BUTTON(button),TRUE); - g_signal_connect(G_OBJECT(button),"clicked",(GCallback)linphone_gtk_mute_clicked,NULL); - gtk_widget_show(button); - linphone_gtk_init_audio_meter(sound_meter, (get_volume_t) linphone_core_get_conference_local_input_volume, linphone_gtk_get_core()); -} - -static GtkWidget *get_conferencee_box(GtkWidget *mw){ - GtkWidget *box=(GtkWidget*)g_object_get_data(G_OBJECT(mw),"conferencee_box"); - return box; -} - -static GtkWidget *find_conferencee_from_call(LinphoneCall *call){ - GtkWidget *mw=linphone_gtk_get_main_window(); - GtkWidget *conferencee_box=get_conferencee_box(mw); - GList *elem; - GtkWidget *ret=NULL; - - if (conferencee_box==NULL) return NULL; - - if (call!=NULL){ - GList *l=gtk_container_get_children(GTK_CONTAINER(conferencee_box)); - for(elem=l;elem!=NULL;elem=elem->next){ - GtkWidget *frame=(GtkWidget*)elem->data; - if (call==g_object_get_data(G_OBJECT(frame),"call")){ - ret=frame; - break; - } - } - g_list_free(l); - } - //g_message("find_conferencee_from_call(): found widget %p for call %p",ret,call); - return ret; -} - -static GtkWidget * create_conference_panel(void){ - GtkWidget *mw=linphone_gtk_get_main_window(); - GtkWidget *conf_frame=linphone_gtk_create_widget("conf_frame"); - GtkWidget *conf_box=linphone_gtk_get_widget(conf_frame,"conf_box"); - GtkWidget *button_conf=linphone_gtk_get_widget(conf_frame,"terminate_conf"); - GtkWidget *image=gtk_image_new_from_icon_name("linphone-stop-call", GTK_ICON_SIZE_BUTTON); - GtkWidget *box; - GtkWidget *viewswitch=linphone_gtk_get_widget(mw,"viewswitch"); - GtkWidget *participant; - GtkWidget *record = linphone_gtk_get_widget(conf_frame, "conf_record_button"); - - gtk_button_set_image(GTK_BUTTON(record), gtk_image_new_from_icon_name("linphone-record", GTK_ICON_SIZE_BUTTON)); - gtk_button_set_image(GTK_BUTTON(button_conf),image); - g_signal_connect_swapped(G_OBJECT(button_conf),"clicked",(GCallback)linphone_gtk_terminate_call,NULL); - g_object_set_data(G_OBJECT(mw),"conf_frame",(gpointer)conf_frame); - - box=gtk_vbox_new(FALSE,0); - participant=linphone_gtk_create_widget("callee_frame"); - gtk_widget_show(participant); - gtk_box_set_homogeneous(GTK_BOX(box),TRUE); - init_local_participant(participant); - gtk_box_pack_start(GTK_BOX(box),participant,FALSE,FALSE,PADDING_PIXELS); - gtk_widget_show(box); - g_object_set_data(G_OBJECT(mw),"conferencee_box",box); - gtk_box_pack_start(GTK_BOX(conf_box),box,FALSE,FALSE,PADDING_PIXELS); - - gtk_notebook_append_page(GTK_NOTEBOOK(viewswitch),conf_frame, - create_conference_label()); - return conf_frame; -} - -void linphone_gtk_set_in_conference(LinphoneCall *call){ - GtkWidget *mw=linphone_gtk_get_main_window(); - GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame"); - GtkWidget *viewswitch=linphone_gtk_get_widget(mw,"viewswitch"); - GtkWidget *participant; - - if(conf_frame==NULL){ - conf_frame=create_conference_panel(); - } - participant=find_conferencee_from_call(call); - - if (participant==NULL){ - /*create and add it */ - GtkWidget *conferencee_box=get_conferencee_box(mw); - GtkWidget *sound_meter; - const LinphoneAddress *addr=linphone_call_get_remote_address(call); - gchar *markup; - - participant=linphone_gtk_create_widget("callee_frame"); - gtk_widget_show(participant); - if (linphone_address_get_display_name(addr)!=NULL){ - markup=g_strdup_printf("%s",linphone_address_get_display_name(addr)); - }else{ - char *tmp=linphone_address_as_string_uri_only(addr); - markup=g_strdup_printf("%s",tmp); - ms_free(tmp); - } - gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(participant,"callee_name_label")),markup); - g_free(markup); - sound_meter=linphone_gtk_get_widget(participant,"sound_indicator"); - linphone_gtk_init_audio_meter(sound_meter, (get_volume_t) linphone_call_get_play_volume, call); - gtk_box_pack_start(GTK_BOX(conferencee_box),participant,FALSE,FALSE,PADDING_PIXELS); - g_object_set_data_full(G_OBJECT(participant),"call",linphone_call_ref(call),(GDestroyNotify)linphone_call_unref); - gtk_notebook_set_current_page(GTK_NOTEBOOK(viewswitch), - gtk_notebook_page_num(GTK_NOTEBOOK(viewswitch),conf_frame)); - } -} - -void linphone_gtk_terminate_conference_participant(LinphoneCall *call){ - GtkWidget *frame=find_conferencee_from_call(call); - if (frame){ - gtk_widget_set_sensitive(frame,FALSE); - } -} - -void linphone_gtk_unset_from_conference(LinphoneCall *call){ - GtkWidget *frame=find_conferencee_from_call(call); - - if (frame){ - GtkWidget *mw=linphone_gtk_get_main_window(); - GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame"); - GtkWidget *conferencee_box=g_object_get_data(G_OBJECT(mw),"conferencee_box"); - GList *children; - - g_message("Removing a participant from conference"); - gtk_widget_destroy(frame); - children=gtk_container_get_children(GTK_CONTAINER(conferencee_box)); - if (g_list_length(children)==1){ /* only local participant */ - /*the conference is terminated */ - g_message("The conference is terminated"); - g_object_set_data(G_OBJECT(mw),"conferencee_box",NULL); - gtk_widget_destroy(conf_frame); - g_object_set_data(G_OBJECT(mw),"conf_frame",NULL); - } - g_list_free(children); - } -} - -bool_t linphone_gtk_call_is_in_conference_view(LinphoneCall *call) { - return (find_conferencee_from_call(call) != NULL); -} diff --git a/gtk/config-fetching.c b/gtk/config-fetching.c deleted file mode 100644 index 59a40a0ca..000000000 --- a/gtk/config-fetching.c +++ /dev/null @@ -1,97 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "linphone.h" -#include "linphone/lpconfig.h" - - -void linphone_gtk_set_configuration_uri(void){ - GtkWidget *w=linphone_gtk_create_window("config-uri", linphone_gtk_get_main_window()); - GtkWidget *entry=linphone_gtk_get_widget(w,"uri_entry"); - const char *uri=linphone_core_get_provisioning_uri(linphone_gtk_get_core()); - if (uri) gtk_entry_set_text(GTK_ENTRY(entry),uri); - gtk_widget_show(w); -} - -void linphone_gtk_config_uri_changed(GtkWidget *button){ - GtkWidget *w=gtk_widget_get_toplevel(button); - GtkWidget *entry=linphone_gtk_get_widget(w,"uri_entry"); - const char *uri=gtk_entry_get_text(GTK_ENTRY(entry)); - - if (uri && (strlen(uri)==0 || strcmp(uri,"https://")==0)) uri=NULL; - - if(linphone_core_set_provisioning_uri(linphone_gtk_get_core(),uri) == 0) { - gtk_widget_destroy(w); - if (uri){ -#ifndef _WIN32 - linphone_gtk_schedule_restart(); - gtk_main_quit(); -#else - GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(linphone_gtk_get_main_window()), - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_INFO, - GTK_BUTTONS_OK, - _("Remote provisioning URI successfully set. Please restart Linphone in order to load the new remote settings")); - g_signal_connect_swapped(G_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), dialog); - gtk_widget_show(dialog); -#endif - } - } else { - GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(w), - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - _("Invalid remote provisioning URI")); - g_signal_connect_swapped(G_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), dialog); - gtk_widget_show(dialog); - } -} - -void linphone_gtk_config_uri_cancel(GtkWidget *button){ - GtkWidget *w=gtk_widget_get_toplevel(button); - gtk_widget_destroy(w); -} - -GtkWidget * linphone_gtk_show_config_fetching(void){ - LinphoneCore *lc=linphone_gtk_get_core(); - GtkWidget *w=linphone_gtk_create_window("provisioning-fetch", linphone_gtk_get_main_window()); - g_message("Fetching started"); - gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(w),_("fetching from %s"),linphone_core_get_provisioning_uri(lc)); -#if GTK_CHECK_VERSION(2,20,0) - { - GtkWidget *spinner=gtk_spinner_new(); - gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(w),spinner); - } -#endif - gtk_widget_show(w); - return w; -} - -void linphone_gtk_close_config_fetching(GtkWidget *w, LinphoneConfiguringState state){ - LinphoneCore *lc=linphone_gtk_get_core(); - gtk_widget_destroy(w); - g_message("Fetching finished"); - if (state==LinphoneConfiguringFailed){ - GtkWidget *msg=gtk_message_dialog_new(NULL,0,GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,_("Downloading of remote configuration from %s failed."), - linphone_core_get_provisioning_uri(lc)); - g_signal_connect(G_OBJECT(msg),"response",(GCallback)gtk_widget_destroy,NULL); - gtk_widget_show(msg); - } -} - diff --git a/gtk/config-uri.ui b/gtk/config-uri.ui deleted file mode 100644 index 26c1fef0e..000000000 --- a/gtk/config-uri.ui +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - False - 5 - Specifying a remote configuration URI - dialog - - - True - False - 2 - - - True - False - end - - - gtk-cancel - True - True - True - True - - - - False - False - 0 - - - - - gtk-ok - True - True - True - True - - - - False - False - 1 - - - - - False - True - end - 0 - - - - - True - False - This dialog allows to set an http or https address when configuration is to be fetched at startup. -Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. - True - 80 - - - True - True - 1 - - - - - True - True - - https:// - False - False - True - True - - - True - True - 2 - - - - - - button2 - button1 - - - diff --git a/gtk/contact.ui b/gtk/contact.ui deleted file mode 100644 index db22d9310..000000000 --- a/gtk/contact.ui +++ /dev/null @@ -1,216 +0,0 @@ - - - - - - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - center-on-parent - dialog - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 2 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - end - - - gtk-cancel - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - True - - - - False - False - 0 - - - - - gtk-ok - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - True - - - - False - False - 1 - - - - - False - True - end - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 2 - 2 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Name - - - GTK_FILL - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - SIP Address - - - 1 - 2 - GTK_FILL - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - False - True - True - - - 1 - 2 - GTK_FILL - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - False - True - True - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - True - False - 0 - - - - - Show this contact presence status - True - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - True - True - - - True - True - 1 - - - - - Allow this contact to see my presence status - True - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - True - True - - - True - True - 2 - - - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Contact information</b> - True - - - - - True - True - 1 - - - - - - cancel_button - ok_button - - - diff --git a/gtk/dscp_settings.ui b/gtk/dscp_settings.ui deleted file mode 100644 index 7f5061f72..000000000 --- a/gtk/dscp_settings.ui +++ /dev/null @@ -1,178 +0,0 @@ - - - - - - False - 5 - DSCP settings - True - dialog - - - - True - False - 2 - - - True - False - end - - - gtk-close - True - True - True - False - True - - - False - False - 0 - - - - - gtk-ok - True - True - True - False - True - - - False - False - 1 - - - - - False - True - end - 0 - - - - - True - False - 0 - none - - - True - False - 3 - 2 - True - - - True - True - - True - False - False - True - True - - - 1 - 2 - - - - - True - True - - True - False - False - True - True - - - 1 - 2 - 1 - 2 - - - - - True - True - - True - False - False - True - True - - - 1 - 2 - 2 - 3 - - - - - True - False - SIP - - - - - True - False - Audio RTP stream - - - 1 - 2 - - - - - True - False - Video RTP stream - - - 2 - 3 - - - - - - - True - False - <b>Set DSCP values (in hexadecimal)</b> - True - - - - - False - False - 1 - - - - - - button2 - button1 - - - diff --git a/gtk/fonis.c b/gtk/fonis.c deleted file mode 100644 index ebd3e4d94..000000000 --- a/gtk/fonis.c +++ /dev/null @@ -1,22 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#include "linphone.h" - diff --git a/gtk/friendlist.c b/gtk/friendlist.c deleted file mode 100644 index 239ba9477..000000000 --- a/gtk/friendlist.c +++ /dev/null @@ -1,1104 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "linphone.h" -#include -#include - -static GtkWidget *linphone_gtk_create_contact_menu(GtkWidget *contact_list); - -enum{ - FRIEND_PRESENCE_IMG, - FRIEND_NAME, - FRIEND_ID, - FRIEND_CHATROOM, - FRIEND_SIP_ADDRESS, - FRIEND_CHAT, - FRIEND_CALL_BUTTON_VISIBLE, - FRIEND_CHAT_BUTTON_VISIBLE, - FRIEND_LIST_NCOL -}; - -typedef struct _status_picture_tab_t{ - LinphoneOnlineStatus status; - const char *img; -} status_picture_tab_t; - -status_picture_tab_t status_picture_tab[]={ - { LinphoneStatusOnline , "linphone-status-online" }, - { LinphoneStatusBusy , "linphone-status-away" }, - { LinphoneStatusBeRightBack , "linphone-status-away" }, - { LinphoneStatusAway , "linphone-status-away" }, - { LinphoneStatusOnThePhone , "linphone-status-away" }, - { LinphoneStatusOutToLunch , "linphone-status-away" }, - { LinphoneStatusDoNotDisturb , "linphone-status-donotdisturb" }, - { LinphoneStatusMoved , "linphone-status-away" }, - { LinphoneStatusAltService , "linphone-status-away" }, - { LinphoneStatusOffline , "linphone-status-offline" }, - { LinphoneStatusPending , "linphone-status-offline" }, - { LinphoneStatusEnd , NULL } -}; - -static const char *status_to_icon_name(LinphoneOnlineStatus ss) { - status_picture_tab_t *t=status_picture_tab; - while(t->img!=NULL){ - if (ss==t->status) { - return t->img; - } - ++t; - } - g_error("No icon name defined for status %i",ss); - return NULL; -} - -static GtkWidget *create_status_picture(LinphoneOnlineStatus ss, GtkIconSize icon_size){ - const char *icon_name = status_to_icon_name(ss); - if(icon_name) return gtk_image_new_from_icon_name(icon_name, icon_size); - else return NULL; -} - -gboolean linphone_gtk_friend_list_is_contact(const LinphoneAddress *addr){ - LinphoneFriend *lf; - char *addr_str=linphone_address_as_string(addr); - lf=linphone_core_get_friend_by_address(linphone_gtk_get_core(),addr_str); - if(lf == NULL){ - return FALSE; - } return TRUE; -} - -static void linphone_gtk_set_selection_to_uri_bar(GtkTreeView *treeview){ - GtkTreeSelection *select; - GtkTreeIter iter; - GtkTreeModel *model; - LinphoneFriend *lf=NULL; - gchar* friend; - select = gtk_tree_view_get_selection (treeview); - if (gtk_tree_selection_get_selected (select, &model, &iter)) { - const LinphoneAddress *addr; - gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); - addr = linphone_friend_get_address(lf); - if (addr) { - friend=linphone_address_as_string(addr); - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")),friend); - ms_free(friend); - } - } -} - -void linphone_gtk_add_contact(void){ - GtkWidget *w=linphone_gtk_create_window("contact", linphone_gtk_get_main_window()); - int presence_enabled=linphone_gtk_get_ui_config_int("use_subscribe_notify",1); - - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"show_presence")),presence_enabled); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"allow_presence")), - presence_enabled); - gtk_widget_show(w); -} - -void linphone_gtk_edit_contact(GtkWidget *button){ - GtkWidget *w=gtk_widget_get_toplevel(button); - GtkTreeSelection *select; - GtkTreeIter iter; - GtkTreeModel *model; - LinphoneFriend *lf=NULL; - select = gtk_tree_view_get_selection(GTK_TREE_VIEW(linphone_gtk_get_widget(w,"contact_list"))); - if (gtk_tree_selection_get_selected (select, &model, &iter)) - { - gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); - linphone_gtk_show_contact(lf, w); - } -} - -void linphone_gtk_remove_contact(GtkWidget *button){ - GtkWidget *w=gtk_widget_get_toplevel(button); - GtkTreeSelection *select; - GtkTreeIter iter; - GtkTreeModel *model; - LinphoneFriend *lf=NULL; - LinphoneChatRoom *cr=NULL; - select = gtk_tree_view_get_selection(GTK_TREE_VIEW(linphone_gtk_get_widget(w,"contact_list"))); - if (gtk_tree_selection_get_selected (select, &model, &iter)) - { - gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); - linphone_core_remove_friend(linphone_gtk_get_core(),lf); - gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); - linphone_chat_room_delete_history(cr); - linphone_gtk_show_friends(); - } -} - -gboolean linphone_gtk_on_key_press(GtkWidget *widget, GdkEvent *event, gpointer user_data) { - - if (event->type == GDK_KEY_PRESS && ((GdkEventKey*)event)->state & GDK_CONTROL_MASK) { - int cpt; - int key = -1; - static int key_map[9] = {0}; - if (key_map[0] == 0) { - GdkKeymapKey *keys = NULL; - gint n_keys = 0; - for (cpt = 0; cpt < 9; cpt++) { - if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), - GDK_KEY_1+cpt, &keys, &n_keys)) - key_map[cpt] = keys->keycode; - } - } - - for(cpt = 0; cpt < 9 ; cpt++) { - if (key_map[cpt] == (((GdkEventKey*)event)->hardware_keycode)) { - key = cpt; - break; - } - } - - if (key != -1) { - GtkWidget *main_window = linphone_gtk_get_main_window(); - GtkWidget *friendlist = linphone_gtk_get_widget(main_window,"contact_list"); - GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist)); - GtkTreeIter iter; - - if (gtk_tree_model_get_iter_first(model, &iter)) { - int index = 0; - LinphoneFriend *lf = NULL; - LinphoneChatRoom *cr; - do{ - if (index == key) { - const LinphoneAddress *addr; - gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); - gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); - if (lf != NULL) { - addr = linphone_friend_get_address(lf); - if (addr != NULL) { - linphone_gtk_friend_list_set_chat_conversation(addr); - } - } - if (cr != NULL){ - linphone_gtk_mark_chat_read(cr); - linphone_gtk_friend_list_update_button_display(GTK_TREE_VIEW(friendlist)); - } - return TRUE; - } - index++; - }while(gtk_tree_model_iter_next(model,&iter) && index <= 9); - } - } - } - return FALSE; -} - -void linphone_gtk_delete_history(GtkWidget *button){ - GtkWidget *w=linphone_gtk_get_main_window(); - GtkTreeSelection *select; - GtkTreeIter iter; - GtkTreeModel *model; - GtkWidget *chat_view; - LinphoneFriend *lf=NULL; - GtkWidget *friendlist; - - friendlist=linphone_gtk_get_widget(w,"contact_list"); - chat_view=(GtkWidget *)g_object_get_data(G_OBJECT(friendlist),"chatview"); - select = gtk_tree_view_get_selection(GTK_TREE_VIEW(friendlist)); - if (gtk_tree_selection_get_selected (select, &model, &iter)) - { - LinphoneChatRoom *cr; - gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); - gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); - linphone_chat_room_delete_history(cr); - if(chat_view!=NULL){ - const LinphoneAddress *from=linphone_gtk_friend_list_get_active_address(); - const LinphoneAddress *addr=linphone_friend_get_address(lf); - if (addr != NULL) { - if(linphone_address_weak_equal(from,addr)){ - GtkTextView *text_view=GTK_TEXT_VIEW(linphone_gtk_get_widget(chat_view,"textview")); - GtkTextIter start; - GtkTextIter end; - GtkTextBuffer *text_buffer; - - text_buffer=gtk_text_view_get_buffer(text_view); - gtk_text_buffer_get_bounds(text_buffer, &start, &end); - gtk_text_buffer_delete (text_buffer, &start, &end); - g_object_set_data(G_OBJECT(chat_view),"from_message",NULL); - } - } - } - linphone_gtk_show_friends(); - } -} - -static void linphone_gtk_call_selected(GtkTreeView *treeview){ - linphone_gtk_set_selection_to_uri_bar(treeview); - linphone_gtk_start_call(linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(treeview)), - "start_call")); -} - -void linphone_gtk_friend_list_update_button_display(GtkTreeView *friendlist){ - GtkTreeIter iter, selected_iter; - GtkTreeModel *model=gtk_tree_view_get_model(friendlist); - GtkTreeSelection *select=gtk_tree_view_get_selection(friendlist); - LinphoneChatRoom *cr=NULL; - gboolean is_composing; - int nbmsg=0; - GtkTreePath *selected_path = NULL; - GtkTreePath *hovered_row = (GtkTreePath *)g_object_get_data(G_OBJECT(friendlist), "hovered_row"); - - if (gtk_tree_selection_get_selected(select, &model, &selected_iter)){ - selected_path = gtk_tree_model_get_path(model, &selected_iter); - } - - if (gtk_tree_model_get_iter_first(model,&iter)) { - do{ - const char *icon_name = NULL; - gboolean show_chat_button = FALSE; - gboolean show_call_button = FALSE; - GtkTreePath *path = gtk_tree_model_get_path(model, &iter); - - gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); - nbmsg=linphone_chat_room_get_unread_messages_count(cr); - is_composing=linphone_chat_room_is_remote_composing(cr); - if(nbmsg != 0){ - if (is_composing) icon_name = "linphone-chat-new-message-and-writing"; - else icon_name = "linphone-chat-new-message"; - show_chat_button = TRUE; - } else { - if (is_composing) { - icon_name = "linphone-chat-writing"; - show_chat_button = TRUE; - } else { - icon_name = "linphone-chat-nothing"; - } - } - - if ((selected_path && gtk_tree_path_compare(path, selected_path) == 0) - || (hovered_row && gtk_tree_path_compare(path, hovered_row) == 0)){ - show_chat_button = TRUE; - show_call_button = TRUE; - } - - gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,icon_name, - FRIEND_CHAT_BUTTON_VISIBLE, show_chat_button, -1); - gtk_list_store_set(GTK_LIST_STORE(model), &iter, FRIEND_CALL_BUTTON_VISIBLE, show_call_button, -1); - - gtk_tree_path_free(path); - }while(gtk_tree_model_iter_next(model,&iter)); - } - if (selected_path) gtk_tree_path_free(selected_path); -} - -static gboolean grab_focus(GtkWidget *w){ - gtk_widget_grab_focus(w); - return FALSE; -} - -void linphone_gtk_friend_list_set_active_address(const LinphoneAddress *addr){ - GtkWidget *w=linphone_gtk_get_main_window(); - GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list"); - g_object_set_data_full(G_OBJECT(friendlist),"from", addr ? linphone_address_clone(addr) : NULL, (GDestroyNotify)linphone_address_unref); -} - -const LinphoneAddress *linphone_gtk_friend_list_get_active_address(void){ - GtkWidget *w=linphone_gtk_get_main_window(); - GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list"); - return (const LinphoneAddress*)g_object_get_data(G_OBJECT(friendlist),"from"); -} - -void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la){ - GtkTreeIter iter; - GtkListStore *store=NULL; - GtkWidget *w = linphone_gtk_get_main_window(); - GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list"); - GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist)); - GtkWidget *chat_view=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); - LinphoneFriend *lf=NULL; - LinphoneChatRoom *cr=NULL; - GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(w,"viewswitch"); - GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(friendlist)); - - lf=linphone_core_find_friend(linphone_gtk_get_core(),la); - if(lf==NULL){ - cr=linphone_gtk_create_chatroom(la); - linphone_gtk_friend_list_set_active_address(la); - } else { - store=GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist))); - if (gtk_tree_model_get_iter_first(model,&iter)) { - do{ - const LinphoneAddress *addr; - gtk_tree_model_get(model, &iter,FRIEND_ID , &lf, -1); - addr=linphone_friend_get_address(lf); - if (addr != NULL) { - if (linphone_address_weak_equal(addr,la)){ - gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); - if(cr==NULL){ - cr=linphone_gtk_create_chatroom(addr); - gtk_list_store_set(store,&iter,FRIEND_CHATROOM,cr,-1); - } - linphone_gtk_friend_list_set_active_address(addr); - gtk_tree_selection_select_iter(selection, &iter); - break; - } - } - }while(gtk_tree_model_iter_next(model,&iter)); - } - } - if(cr) { - if(chat_view == NULL){ - chat_view=linphone_gtk_init_chatroom(cr,la); - g_object_set_data(G_OBJECT(friendlist),"chatview",(gpointer)chat_view); - } else { - linphone_gtk_load_chatroom(cr,la,chat_view); - } - gtk_notebook_set_current_page(notebook,gtk_notebook_page_num(notebook,chat_view)); - g_idle_add((GSourceFunc)grab_focus,linphone_gtk_get_widget(chat_view,"text_entry")); - } -} - -void linphone_gtk_notebook_tab_select(GtkNotebook *notebook,GtkWidget *page,guint page_num, gpointer data){ - GtkWidget *w=linphone_gtk_get_main_window(); - GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list"); - GtkWidget *chat_view; - LinphoneChatRoom *cr=NULL; - chat_view=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); - if(page != NULL){ - notebook=(GtkNotebook *)linphone_gtk_get_widget(w,"viewswitch"); - if(gtk_notebook_page_num(notebook,page)==gtk_notebook_page_num(notebook,chat_view)){ - cr=g_object_get_data(G_OBJECT(chat_view),"cr"); - if(cr!=NULL){ - linphone_gtk_mark_chat_read(cr); - linphone_gtk_show_friends(); - } - } - } -} - -void linphone_gtk_chat_selected(GtkWidget *item){ - GtkWidget *w=gtk_widget_get_toplevel(item); - GtkTreeSelection *select; - GtkListStore *store=NULL; - GtkTreeIter iter; - GtkTreeModel *model; - LinphoneFriend *lf=NULL; - LinphoneChatRoom *cr=NULL; - GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list"); - GtkWidget *page; - - select=gtk_tree_view_get_selection(GTK_TREE_VIEW(friendlist)); - store=GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(item))); - if (gtk_tree_selection_get_selected (select, &model, &iter)){ - GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(w,"viewswitch"); - const LinphoneAddress *addr; - gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); - gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); - addr=linphone_friend_get_address(lf); - if (addr != NULL) { - if(cr==NULL){ - cr=linphone_gtk_create_chatroom(addr); - gtk_list_store_set(store,&iter,FRIEND_CHATROOM,cr,-1); - } - page=GTK_WIDGET(g_object_get_data(G_OBJECT(friendlist),"chatview")); - linphone_gtk_friend_list_set_active_address(addr); - if(page==NULL){ - page=linphone_gtk_init_chatroom(cr,addr); - g_object_set_data(G_OBJECT(friendlist),"chatview",(gpointer)page); - } else { - linphone_gtk_load_chatroom(cr,addr,page); - } - linphone_gtk_mark_chat_read(cr); - gtk_notebook_set_current_page(notebook,gtk_notebook_page_num(notebook,page)); - g_idle_add((GSourceFunc)grab_focus,linphone_gtk_get_widget(page,"text_entry")); - } - } -} - -void linphone_gtk_contact_clicked(GtkTreeSelection *selection){ - GtkTreeView *friendlist = gtk_tree_selection_get_tree_view(selection); - GtkWidget *mw = linphone_gtk_get_main_window(); - GtkWidget *edit_button = linphone_gtk_get_widget(mw, "edit_button"); - GtkWidget *remove_button = linphone_gtk_get_widget(mw, "remove_button"); - - linphone_gtk_set_selection_to_uri_bar(friendlist); - linphone_gtk_friend_list_update_button_display(friendlist); - if(gtk_tree_selection_get_selected(selection, NULL, NULL)) { - gtk_widget_set_sensitive(edit_button, TRUE); - gtk_widget_set_sensitive(remove_button, TRUE); - } else { - gtk_widget_set_sensitive(edit_button, FALSE); - gtk_widget_set_sensitive(remove_button, FALSE); - } -} - - -void linphone_gtk_add_button_clicked(void){ - linphone_gtk_add_contact(); -} - -void linphone_gtk_edit_button_clicked(GtkWidget *button){ - linphone_gtk_edit_contact(button); -} - -void linphone_gtk_remove_button_clicked(GtkWidget *button){ - linphone_gtk_remove_contact(button); -} - -static GtkWidget * create_presence_menu(void){ - GtkWidget *menu=gtk_menu_new(); - GtkWidget *menu_item; - status_picture_tab_t *t; - for(t=status_picture_tab;t->img!=NULL;++t){ - if (t->status==LinphoneStatusPending){ - continue; - } - menu_item=gtk_image_menu_item_new_with_label(linphone_online_status_to_string(t->status)); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), - gtk_image_new_from_icon_name(t->img, GTK_ICON_SIZE_LARGE_TOOLBAR)); - gtk_widget_show(menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); - g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_set_my_presence,GINT_TO_POINTER(t->status)); - } - return menu; -} - -void linphone_gtk_set_my_presence(LinphoneOnlineStatus ss){ - GtkWidget *button=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"presence_button"); - GtkWidget *image=create_status_picture(ss, GTK_ICON_SIZE_LARGE_TOOLBAR); - GtkWidget *menu; - - gtk_widget_set_tooltip_text(button,linphone_online_status_to_string(ss)); - gtk_button_set_image(GTK_BUTTON(button),image); - /*prepare menu*/ - menu=(GtkWidget*)g_object_get_data(G_OBJECT(button),"presence_menu"); - if (menu==NULL){ - menu=create_presence_menu(); - /*the menu is destroyed when the button is destroyed*/ - g_object_weak_ref(G_OBJECT(button),(GWeakNotify)gtk_widget_destroy,menu); - g_object_set_data(G_OBJECT(button),"presence_menu",menu); - } - linphone_core_set_presence_info(linphone_gtk_get_core(),0,NULL,ss); -} - -void linphone_gtk_my_presence_clicked(GtkWidget *button){ - GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(button),"presence_menu"); - gtk_menu_popup(GTK_MENU(menu),NULL,NULL,NULL,NULL,0, - gtk_get_current_event_time()); - gtk_widget_show(menu); -} - -static void icon_press_handler(GtkEntry *entry){ - GtkWidget *w = gtk_widget_get_toplevel(GTK_WIDGET(entry)); - const char *text=gtk_entry_get_text(entry); - if (text && strlen(text)>0){ - LinphoneAddress *addr; - LinphoneFriend *lf; - char *uri; - addr=linphone_core_interpret_url(linphone_gtk_get_core(),text); - if (addr==NULL){ - return ; - } - uri=linphone_address_as_string_uri_only(addr); - lf=linphone_core_get_friend_by_address(linphone_gtk_get_core(),uri); - ms_free(uri); - if (lf==NULL) - lf=linphone_core_create_friend(linphone_gtk_get_core()); - if (lf!=NULL){ - linphone_friend_set_address(lf,addr); - linphone_gtk_show_contact(lf, w); - } - linphone_address_unref(addr); - } -} - -static void update_star(GtkEntry *entry, gboolean is_known){ - if (is_known){ - gtk_entry_set_icon_from_icon_name(entry,GTK_ENTRY_ICON_SECONDARY,NULL); - gtk_entry_set_icon_sensitive(GTK_ENTRY(entry),GTK_ENTRY_ICON_SECONDARY,FALSE); - gtk_entry_set_icon_tooltip_text(GTK_ENTRY(entry),GTK_ENTRY_ICON_SECONDARY,NULL); - }else{ - gtk_entry_set_icon_from_icon_name(entry,GTK_ENTRY_ICON_SECONDARY,"linphone-contact-add"); - gtk_entry_set_icon_sensitive(GTK_ENTRY(entry),GTK_ENTRY_ICON_SECONDARY,TRUE); - gtk_entry_set_icon_tooltip_text(GTK_ENTRY(entry),GTK_ENTRY_ICON_SECONDARY,_("Add to addressbook")); - } -} - -static void check_contact(GtkEditable *editable, LinphoneCore *lc){ - bool_t known = TRUE; - char *tmp = gtk_editable_get_chars(editable, 0, -1); - if (tmp != NULL) { - if (strlen(tmp) > 0) { - known = linphone_gtk_is_friend(lc, tmp); - } - g_free(tmp); - } - update_star(GTK_ENTRY(editable), known); -} - -static void linphone_gtk_init_bookmark_icon(void){ - GtkWidget *entry = linphone_gtk_get_widget(linphone_gtk_get_main_window(), "uribar"); - g_signal_connect(G_OBJECT(entry),"icon-release",(GCallback)icon_press_handler,NULL); - g_signal_connect(G_OBJECT(GTK_EDITABLE(entry)),"changed",(GCallback)check_contact,linphone_gtk_get_core()); -} - -static gboolean friend_search_func(GtkTreeModel *model, gint column, - const gchar *key, - GtkTreeIter *iter, - gpointer search_data){ - char *name=NULL; - gboolean ret=TRUE; - gtk_tree_model_get(model,iter,FRIEND_NAME,&name,-1); - if (name!=NULL){ - gchar *uname=g_utf8_casefold(name,-1); /* need that to perform case-insensitive search in utf8 */ - gchar *ukey=g_utf8_casefold(key,-1); - ret=strstr(uname,ukey)==NULL; - g_free(uname); - g_free(ukey); - g_free(name); - } - return ret; -} - -static gint friend_sort(GtkTreeModel *model, GtkTreeIter *a,GtkTreeIter *b,gpointer user_data){ - char *n1=NULL,*n2=NULL; - int ret; - gtk_tree_model_get(model,a,FRIEND_NAME,&n1,-1); - gtk_tree_model_get(model,b,FRIEND_NAME,&n2,-1); - if (n1 && n2) { - ret=strcmp(n1,n2); - g_free(n1); - g_free(n2); - }else if (n1){ - g_free(n1); - ret=-1; - }else if (n2){ - g_free(n2); - ret=1; - }else ret=0; - return ret; -} - -void linphone_gtk_friend_list_on_name_column_clicked(GtkTreeModel *model){ - GtkSortType st; - gint column; - - gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(model),&column,&st); - if (column==FRIEND_NAME){ - if (st==GTK_SORT_ASCENDING) st=GTK_SORT_DESCENDING; - else st=GTK_SORT_ASCENDING; - }else st=GTK_SORT_ASCENDING; - gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model),FRIEND_NAME,st); -} - -static int get_friend_weight(const LinphoneFriend *lf){ - int w=0; - LinphoneCore *lc=linphone_gtk_get_core(); - const LinphoneAddress *addr = linphone_friend_get_address(lf); - LinphoneChatRoom *cr = NULL; - - if (addr != NULL) { - cr = linphone_core_get_chat_room(lc, addr); - } - if (cr && linphone_chat_room_get_unread_messages_count(cr)>0){ - w+=2000; - } - - switch(linphone_friend_get_status(lf)){ - case LinphoneStatusOnline: - w+=1000; - break; - case LinphoneStatusOffline: - if (linphone_friend_get_send_subscribe(lf)) - w+=100; - break; - default: - w+=500; - break; - } - return w; -} - -static int friend_compare_func(const LinphoneFriend *lf1, const LinphoneFriend *lf2){ - int w1,w2,ret; - w1=get_friend_weight(lf1); - w2=get_friend_weight(lf2); - if (w1==w2){ - const char *u1,*u2; - const LinphoneAddress *addr1,*addr2; - addr1=linphone_friend_get_address(lf1); - addr2=linphone_friend_get_address(lf2); - if ((addr1 == NULL) && (addr2 == NULL)) return 0; - if ((addr1 == NULL) && (addr2 != NULL)) return -1; - if ((addr1 != NULL) && (addr2 == NULL)) return 1; - u1=linphone_friend_get_name(lf1) ? linphone_friend_get_name(lf1) : linphone_address_get_display_name(addr1) ? linphone_address_get_display_name(addr1) : linphone_address_get_username(addr1); - u2=linphone_friend_get_name(lf2) ? linphone_friend_get_name(lf2) :linphone_address_get_display_name(addr2) ? linphone_address_get_display_name(addr2) : linphone_address_get_username(addr2); - if (u1 && u2) { - ret = strcasecmp(u1,u2); - } else if (u1) { - ret = 1; - } else { - ret = -1; - } - } else { - ret = w2-w1; - } - return ret; -} - -static bctbx_list_t *sort_friend_list(const bctbx_list_t *friends){ - bctbx_list_t *ret=NULL; - const bctbx_list_t *elem; - LinphoneFriend *lf; - - for(elem=friends;elem!=NULL;elem=elem->next){ - lf=(LinphoneFriend*)elem->data; - ret=bctbx_list_insert_sorted(ret,lf,(bctbx_compare_func)friend_compare_func); - } - return ret; -} - -#if 0 -void linphone_gtk_friend_list_on_presence_column_clicked(GtkTreeModel *model){ - GtkSortType st; - gint column; - - gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(model),&column,&st); - if (column==FRIEND_ID){ - if (st==GTK_SORT_ASCENDING) st=GTK_SORT_DESCENDING; - else st=GTK_SORT_ASCENDING; - }else st=GTK_SORT_ASCENDING; - gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model),FRIEND_ID,st); -} -#endif - -static void linphone_gtk_friend_list_init(GtkWidget *friendlist){ - GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist)); - GtkTreeSelection *select = gtk_tree_view_get_selection (GTK_TREE_VIEW (friendlist)); - - linphone_gtk_init_bookmark_icon(); - gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(friendlist),friend_search_func,NULL,NULL); - gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store),FRIEND_NAME,friend_sort,NULL,NULL); - gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); - g_signal_connect(G_OBJECT(select), "changed", G_CALLBACK(linphone_gtk_contact_clicked), NULL); - - g_object_set_data(G_OBJECT(friendlist), "friendlist_initialized", (gpointer)TRUE); -} - -void linphone_gtk_show_directory_search(void){ - LinphoneProxyConfig *cfg=NULL; - SipSetupContext * ssc=NULL; - GtkWidget *mw=linphone_gtk_get_main_window(); - GtkWidget *search_box=linphone_gtk_get_widget(mw,"directory_search_box"); - - cfg = linphone_core_get_default_proxy_config(linphone_gtk_get_core()); - if (cfg){ - ssc=linphone_proxy_config_get_sip_setup_context(cfg); - if (ssc!=NULL && sip_setup_context_get_capabilities(ssc) & SIP_SETUP_CAP_BUDDY_LOOKUP){ - GtkWidget *entry=linphone_gtk_get_widget(mw,"directory_search_entry"); - gchar *tooltip; - GdkColor grey={0,40000,40000,40000}; - gtk_widget_show(search_box); - tooltip=g_strdup_printf(_("Search in %s directory"),linphone_proxy_config_get_domain(cfg)); - gtk_widget_modify_text(entry,GTK_STATE_NORMAL,&grey); - gtk_entry_set_text(GTK_ENTRY(entry),tooltip); - g_object_set_data(G_OBJECT(entry),"active",GINT_TO_POINTER(0)); - g_free(tooltip); - return; - } - } - gtk_widget_hide(search_box); -} - -gboolean linphone_gtk_directory_search_focus_out(GtkWidget *entry){ - if (gtk_entry_get_text_length(GTK_ENTRY(entry))==0) - linphone_gtk_show_directory_search(); - return FALSE; -} - -gboolean linphone_gtk_directory_search_focus_in(GtkWidget *entry){ - if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(entry),"active"))==0){ - gtk_entry_set_text(GTK_ENTRY(entry),""); - gtk_widget_modify_text(entry,GTK_STATE_NORMAL,NULL); - g_object_set_data(G_OBJECT(entry),"active",GINT_TO_POINTER(1)); - } - return FALSE; -} - -void linphone_gtk_directory_search_activate(GtkWidget *entry){ - LinphoneProxyConfig *cfg; - GtkWidget *w; - cfg = linphone_core_get_default_proxy_config(linphone_gtk_get_core()); - w=linphone_gtk_show_buddy_lookup_window(linphone_proxy_config_get_sip_setup_context(cfg)); - if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(entry),"active"))==1) - linphone_gtk_buddy_lookup_set_keyword(w,gtk_entry_get_text(GTK_ENTRY(entry))); -} - -void linphone_gtk_directory_search_button_clicked(GtkWidget *button){ - linphone_gtk_directory_search_activate( - linphone_gtk_get_widget(gtk_widget_get_toplevel(button),"directory_search_entry")); -} - -void linphone_gtk_show_friends(void){ - GtkWidget *mw=linphone_gtk_get_main_window(); - GtkWidget *friendlist=linphone_gtk_get_widget(mw,"contact_list"); - GtkListStore *store=NULL; - GtkTreeIter iter; - const bctbx_list_t *itf; - LinphoneCore *core=linphone_gtk_get_core(); - bctbx_list_t *sorted; - LinphoneChatRoom *cr=NULL; - - linphone_gtk_show_directory_search(); - if (!g_object_get_data(G_OBJECT(friendlist), "friendlist_initialized")) { - linphone_gtk_friend_list_init(friendlist); - } - - store=GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist))); - gtk_list_store_clear(store); - - sorted=sort_friend_list(linphone_core_get_friend_list(core)); - - for(itf=sorted;itf!=NULL;itf=bctbx_list_next(itf)){ - LinphoneFriend *lf=(LinphoneFriend*)itf->data; - const LinphoneAddress *f_addr=linphone_friend_get_address(lf); - const char *name=linphone_friend_get_name(lf); - char *uri = NULL; - const char *display=name; - char *escaped=NULL; - int nbmsg=0; - - //BuddyInfo *bi; - gboolean send_subscribe=linphone_friend_get_send_subscribe(lf); - if (f_addr != NULL) uri = linphone_address_as_string(f_addr); - if ((display==NULL || display[0]=='\0') && (f_addr != NULL)) { - display=linphone_address_get_username(f_addr); - } - gtk_list_store_append(store,&iter); - gtk_list_store_set(store,&iter,FRIEND_NAME, display,FRIEND_ID,lf, - FRIEND_PRESENCE_IMG, send_subscribe ? status_to_icon_name(linphone_friend_get_status(lf)) : NULL, - FRIEND_CHAT,"linphone-chat-nothing", -1); - - if (f_addr != NULL) { - cr=linphone_gtk_create_chatroom(f_addr); - gtk_list_store_set(store,&iter,FRIEND_CHATROOM,cr,-1); - nbmsg=linphone_chat_room_get_unread_messages_count(cr); - if(nbmsg != 0){ - gtk_list_store_set(store,&iter,FRIEND_CHAT,"linphone-chat-new-message", - FRIEND_CHAT_BUTTON_VISIBLE, TRUE, -1); - } - escaped=g_markup_escape_text(uri,-1); - gtk_list_store_set(store,&iter,FRIEND_SIP_ADDRESS,escaped,-1); - g_free(escaped); - ms_free(uri); - } - } - bctbx_list_free(sorted); -} - -void linphone_gtk_show_contact(LinphoneFriend *lf, GtkWidget *parent){ - GtkWidget *w = linphone_gtk_create_window("contact", parent); - char *uri; - const char *name = linphone_friend_get_name(lf); - const LinphoneAddress *f_addr = linphone_friend_get_address(lf); - - if (f_addr != NULL) { - uri=linphone_address_as_string_uri_only(f_addr); - if (uri) { - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"sip_address")),uri); - ms_free(uri); - } - } - - if (name){ - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"name")),name); - } - - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"show_presence")), - linphone_friend_get_send_subscribe(lf)); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"allow_presence")), - linphone_friend_get_inc_subscribe_policy(lf)==LinphoneSPAccept); - g_object_set_data(G_OBJECT(w),"friend_ref",(gpointer)lf); - - gtk_widget_show(w); -} - -void linphone_gtk_contact_cancel(GtkWidget *button){ - gtk_widget_destroy(gtk_widget_get_toplevel(button)); -} - -void linphone_gtk_contact_ok(GtkWidget *button){ - GtkWidget *w=gtk_widget_get_toplevel(button); - LinphoneFriend *lf=(LinphoneFriend*)g_object_get_data(G_OBJECT(w),"friend_ref"); - LinphoneFriend *lf2; - gboolean show_presence=FALSE,allow_presence=FALSE; - const gchar *name,*uri; - LinphoneAddress* friend_address; - if (lf==NULL){ - lf=linphone_core_create_friend(linphone_gtk_get_core()); - if (linphone_gtk_get_ui_config_int("use_subscribe_notify",1)==1){ - show_presence=FALSE; - allow_presence=FALSE; - } - linphone_friend_set_inc_subscribe_policy(lf,allow_presence ? LinphoneSPAccept : LinphoneSPDeny); - linphone_friend_send_subscribe(lf,show_presence); - } - - name = NULL; - if(gtk_entry_get_text_length(GTK_ENTRY(linphone_gtk_get_widget(w,"name"))) != 0){ - name=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"name"))); - } - uri=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"sip_address"))); - show_presence=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"show_presence"))); - allow_presence=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"allow_presence"))); - friend_address=linphone_core_interpret_url(linphone_gtk_get_core(),uri); - if (friend_address==NULL){ - linphone_gtk_display_something(GTK_MESSAGE_WARNING,_("Invalid sip contact !")); - return ; - } - - linphone_friend_set_address(lf,friend_address); - linphone_friend_set_name(lf,name); - linphone_friend_send_subscribe(lf,show_presence); - linphone_friend_set_inc_subscribe_policy(lf,allow_presence==TRUE ? LinphoneSPAccept : LinphoneSPDeny); - if (linphone_friend_in_list(lf)) { - linphone_friend_done(lf); - } else { - char *uri=linphone_address_as_string_uri_only(friend_address); - lf2=linphone_core_get_friend_by_address(linphone_gtk_get_core(),uri); - ms_free(uri); - if(lf2==NULL){ - linphone_core_add_friend(linphone_gtk_get_core(),lf); - } - } - linphone_address_unref(friend_address); - linphone_gtk_show_friends(); - gtk_widget_destroy(w); -} - -static GtkWidget *linphone_gtk_create_contact_menu(GtkWidget *contact_list){ - GtkWidget *menu=gtk_menu_new(); - GtkWidget *menu_item; - gchar *edit_label=NULL; - gchar *delete_label=NULL; - gchar *delete_hist_label=NULL; - gchar *add_contact_label=NULL; - gchar *name=NULL; - GtkTreeSelection *select; - GtkTreeIter iter; - GtkTreeModel *model; - GtkWidget *image; - LinphoneCore *lc=linphone_gtk_get_core(); - LinphoneProxyConfig *cfg=NULL; - SipSetupContext * ssc=NULL; - bool_t show_menu_separator=FALSE; - - cfg = linphone_core_get_default_proxy_config(lc); - if (cfg){ - ssc=linphone_proxy_config_get_sip_setup_context(cfg); - } - - g_signal_connect(G_OBJECT(menu), "selection-done", G_CALLBACK (gtk_widget_destroy), NULL); - select = gtk_tree_view_get_selection(GTK_TREE_VIEW(contact_list)); - add_contact_label=g_strdup_printf(_("Add a new contact")); - if (gtk_tree_selection_get_selected (select, &model, &iter)){ - gtk_tree_model_get(model, &iter,FRIEND_NAME , &name, -1); - edit_label=g_strdup_printf(_("Edit contact '%s'"),name); - delete_label=g_strdup_printf(_("Delete contact '%s'"),name); - delete_hist_label=g_strdup_printf(_("Delete chat history of '%s'"),name); - g_free(name); - show_menu_separator=TRUE; - } - if (edit_label){ - menu_item=gtk_image_menu_item_new_with_label(edit_label); - image=gtk_image_new_from_icon_name("linphone-edit",GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image); - gtk_widget_show(image); - gtk_widget_show(menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); - g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_edit_contact,contact_list); - } - if (delete_label){ - menu_item=gtk_image_menu_item_new_with_label(delete_label); - image=gtk_image_new_from_icon_name("linphone-delete",GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image); - gtk_widget_show(image); - gtk_widget_show(menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); - g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_remove_contact,contact_list); - } - - if (delete_hist_label){ - GtkWidget *menu_item_separator=gtk_separator_menu_item_new(); - gtk_widget_show(menu_item_separator); - gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item_separator); - menu_item=gtk_image_menu_item_new_with_label(delete_hist_label); - image=gtk_image_new_from_icon_name("linphone-delete",GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image); - gtk_widget_show(image); - gtk_widget_show(menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); - g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_delete_history,contact_list); - } - - if (ssc && (sip_setup_context_get_capabilities(ssc) & SIP_SETUP_CAP_BUDDY_LOOKUP)) { - gchar *tmp=g_strdup_printf(_("Add new contact from %s directory"),linphone_proxy_config_get_domain(cfg)); - menu_item=gtk_image_menu_item_new_with_label(tmp); - g_free(tmp); - image=gtk_image_new_from_icon_name("linphone-contact-add",GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image); - gtk_widget_show(image); - gtk_widget_show(menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); - g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_buddy_lookup_window,ssc); - } - - if (show_menu_separator) { - GtkWidget *menu_item_separator=gtk_separator_menu_item_new(); - gtk_widget_show(menu_item_separator); - gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item_separator); - } - - menu_item=gtk_image_menu_item_new_with_label(add_contact_label); - image=gtk_image_new_from_icon_name("linphone-contact-add",GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image); - gtk_widget_show(image); - gtk_widget_show(menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); - g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_add_contact,contact_list); - gtk_widget_show(menu); - gtk_menu_attach_to_widget (GTK_MENU (menu), contact_list, NULL); - - g_free(add_contact_label); - if (edit_label) g_free(edit_label); - if (delete_label) g_free(delete_label); - return menu; -} - -gboolean linphone_gtk_popup_contact_menu(GtkWidget *list, GdkEventButton *event){ - GtkWidget *m=linphone_gtk_create_contact_menu(list); - gtk_menu_popup (GTK_MENU (m), NULL, NULL, NULL, NULL, - event ? event->button : 0, event ? event->time : gtk_get_current_event_time()); - return TRUE; -} - -static int get_column_index(GtkTreeView *friendlist, const GtkTreeViewColumn *column) { - GList *columns = gtk_tree_view_get_columns(friendlist); - int i = g_list_index(columns, column); - g_list_free(columns); - return i; -} - -static void select_row(GtkTreeView *treeview, GtkTreePath *path) { - GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); - gtk_tree_selection_select_path(selection, path); -} - -gboolean linphone_gtk_contact_list_button_pressed(GtkTreeView *friendlist, GdkEventButton *event){ - /* Ignore double-clicks and triple-clicks */ - gboolean ret = FALSE; - int x_bin, y_bin; - GtkTreePath *path; - GtkTreeViewColumn *column; - GtkTreeSelection *selection = gtk_tree_view_get_selection(friendlist); - - gtk_tree_view_convert_widget_to_bin_window_coords(friendlist, (gint)event->x, (gint)event->y, &x_bin, &y_bin); - gtk_tree_view_get_path_at_pos(friendlist, x_bin, y_bin, &path, &column, NULL, NULL); - - if (event->button == 3 && event->type == GDK_BUTTON_PRESS) { - if(path) gtk_tree_selection_select_path(selection, path); - ret = linphone_gtk_popup_contact_menu(GTK_WIDGET(friendlist), event); - } else if(event->button == 1 && event->type == GDK_BUTTON_PRESS){ - if(path && column) { - int numcol = get_column_index(friendlist, column); - if(numcol == 2) { - select_row(friendlist, path); - linphone_gtk_call_selected(friendlist); - ret = TRUE; - } else if(numcol == 3) { - select_row(friendlist, path); - linphone_gtk_chat_selected(GTK_WIDGET(friendlist)); - ret = TRUE; - } - } - } - if(path) gtk_tree_path_free(path); - return ret; -} - -void linphone_gtk_buddy_info_updated(LinphoneCore *lc, LinphoneFriend *lf){ - /*refresh the entire list*/ - linphone_gtk_show_friends(); -} - -static gboolean update_hovered_row_path(GtkTreeView *friendlist, int x_window, int y_window) { - int x_bin, y_bin; - GtkTreePath *new_path; - GtkTreePath *old_path = (GtkTreePath *)g_object_get_data(G_OBJECT(friendlist), "hovered_row"); - gtk_tree_view_convert_widget_to_bin_window_coords(friendlist, x_window, y_window, &x_bin, &y_bin); - gtk_tree_view_get_path_at_pos(friendlist, x_bin, y_bin, &new_path, NULL, NULL, NULL); - if((new_path == NULL && old_path == NULL) || (new_path && old_path && gtk_tree_path_compare(new_path, old_path) == 0)) { - if(new_path) gtk_tree_path_free(new_path); - return FALSE; - } else { - g_object_set_data_full(G_OBJECT(friendlist), "hovered_row", new_path, (GDestroyNotify)gtk_tree_path_free); - return TRUE; - } -} - -gboolean linphone_gtk_friend_list_enter_event_handler(GtkTreeView *friendlist, GdkEventCrossing *event) { - gboolean path_has_changed = update_hovered_row_path(friendlist, (int)event->x, (int)event->y); - if(path_has_changed) linphone_gtk_friend_list_update_button_display(friendlist); - return FALSE; -} - -gboolean linphone_gtk_friend_list_leave_event_handler(GtkTreeView *friendlist, GdkEventCrossing *event) { - GtkTreePath *hovered_row = (GtkTreePath *)g_object_get_data(G_OBJECT(friendlist), "hovered_row"); - if(hovered_row) { - g_object_set_data(G_OBJECT(friendlist), "hovered_row", NULL); - linphone_gtk_friend_list_update_button_display(friendlist); - } - return FALSE; -} - -gboolean linphone_gtk_friend_list_motion_event_handler(GtkTreeView *friendlist, GdkEventMotion *event) { - gboolean path_has_changed = update_hovered_row_path(friendlist, (int)event->x, (int)event->y); - if(path_has_changed) linphone_gtk_friend_list_update_button_display(friendlist); - return FALSE; -} - -#define CONFIG_FILE ".linphone-friends.db" - -char *linphone_gtk_friends_storage_get_db_file(const char *filename){ - const int path_max=1024; - char *db_file=NULL; - - db_file=(char *)g_malloc(path_max*sizeof(char)); - if (filename==NULL) filename=CONFIG_FILE; - /*try accessing a local file first if exists*/ - if (bctbx_file_exist(CONFIG_FILE)==0){ - snprintf(db_file,path_max,"%s",filename); - }else{ -#ifdef _WIN32 - const char *appdata=getenv("APPDATA"); - if (appdata){ - snprintf(db_file,path_max,"%s\\%s",appdata,LINPHONE_CONFIG_DIR); - CreateDirectory(db_file,NULL); - snprintf(db_file,path_max,"%s\\%s\\%s",appdata,LINPHONE_CONFIG_DIR,filename); - } -#else - const char *home=getenv("HOME"); - if (home==NULL) home="."; - snprintf(db_file,path_max,"%s/%s",home,filename); -#endif - } - return db_file; -} diff --git a/gtk/gtkrc b/gtk/gtkrc deleted file mode 100644 index 73d21744f..000000000 --- a/gtk/gtkrc +++ /dev/null @@ -1,4 +0,0 @@ -#include "share/themes/XLiquid_GTK-1.0.3/gtk-2.0/gtkrc" -#include "share/themes/Aero-ion3.1/gtk-2.0/gtkrc" -include "share/themes/Outcrop/gtk-2.0/gtkrc" - diff --git a/gtk/gtkrc.mac b/gtk/gtkrc.mac deleted file mode 100644 index da38efafc..000000000 --- a/gtk/gtkrc.mac +++ /dev/null @@ -1 +0,0 @@ -include "../../share/themes/Quartz/gtk-2.0/gtkrc" diff --git a/gtk/in_call_frame.ui b/gtk/in_call_frame.ui deleted file mode 100644 index 1e713d19c..000000000 --- a/gtk/in_call_frame.ui +++ /dev/null @@ -1,433 +0,0 @@ - - - - - - True - False - 16 - linphone-security-pending - - - False - cursor - 0.5 - none - - - True - False - 12 - 12 - - - True - False - - - True - False - center - - - True - True - 0 - - - - - True - False - - - - - - False - False - 1 - - - - - False - - - True - True - True - zrtp_button_icon - none - - - - True - False - 0 - - - - - False - False - 2 - - - - - False - 4 - - - True - False - 1 - 16 - linphone-security-ok - - - True - True - 0 - - - - - True - False - 0 - Encryption status - - - True - True - 1 - - - - - True - True - 3 - - - - - True - False - - - True - False - - - True - True - True - True - none - False - vertical - linphone-micro-enabled - - - False - False - 5 - 0 - - - - - True - False - - - False - False - 5 - 1 - - - - - True - False - 10 - 0 - - - - - True - False - - - True - True - True - True - Click here to set the speakers volume - none - False - vertical - linphone-speaker-enabled - - - False - False - 5 - 0 - - - - - True - False - - - False - False - 5 - 1 - - - - - True - False - 10 - 1 - - - - - False - False - 5 - 4 - - - - - False - spread - - - Answer - True - True - True - - - - False - False - 0 - - - - - Decline - True - True - True - - - - False - False - 1 - - - - - False - False - 5 - - - - - False - - - Record - True - True - True - Record this call to an audio file - - - - False - False - 0 - - - - - True - False - True - char - - - True - True - 1 - - - - - False - False - 6 - - - - - True - False - 2 - 3 - True - - - Video - True - True - True - - - - - Pause - True - True - True - - - - 1 - 2 - - - - - Mute - True - True - True - - - - 2 - 3 - - - - - Transfer - True - True - True - - - 1 - 2 - - - - - Hang up - True - True - True - - - - 1 - 2 - 1 - 2 - - - - - Conference - True - True - True - - - 2 - 3 - 1 - 2 - - - - - False - False - 7 - 7 - - - - - - - - - True - False - True - - - True - False - In call - True - center - - - True - True - 0 - - - - - True - False - Duration - center - - - True - True - 1 - - - - - 90 - 10 - True - False - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK - Call quality rating - - - False - False - 2 - - - - - - diff --git a/gtk/incall_view.c b/gtk/incall_view.c deleted file mode 100644 index 174e39d69..000000000 --- a/gtk/incall_view.c +++ /dev/null @@ -1,1027 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2009 Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -/* -* C Implementation: incall_frame -* -* Description: -* -* -* Author: Simon Morlat , (C) 2009 -* -* -*/ - -#include "linphone.h" - -gboolean linphone_gtk_use_in_call_view(void){ - static int val=-1; - if (val==-1) val=linphone_gtk_get_ui_config_int("use_incall_view",1); - return val; -} - -LinphoneCall *linphone_gtk_get_currently_displayed_call(gboolean *is_conf){ - LinphoneCore *lc=linphone_gtk_get_core(); - GtkWidget *main_window=linphone_gtk_get_main_window (); - GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch"); - const bctbx_list_t *calls=linphone_core_get_calls(lc); - if (is_conf) *is_conf=FALSE; - if (!linphone_gtk_use_in_call_view() || bctbx_list_size(calls)==1){ - if (calls) return (LinphoneCall*)calls->data; - }else{ - int idx=gtk_notebook_get_current_page (notebook); - GtkWidget *page=gtk_notebook_get_nth_page(notebook,idx); - if (page!=NULL){ - LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(page),"call"); - if (call==NULL){ - GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(main_window),"conf_frame"); - if (conf_frame==page){ - if (is_conf) - *is_conf=TRUE; - return NULL; - } - } - return call; - } - } - return NULL; -} - -static GtkWidget *make_tab_header(int number){ - gchar text[20]; - g_snprintf(text, sizeof(text), _("Call #%i"), number); - return linphone_gtk_make_tab_header(text, "linphone-start-call", FALSE, NULL, NULL); -} - -void linphone_gtk_call_update_tab_header(LinphoneCall *call,gboolean pause){ - GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer(call); - GtkWidget *main_window=linphone_gtk_get_main_window(); - GtkNotebook *notebook=GTK_NOTEBOOK(linphone_gtk_get_widget(main_window,"viewswitch")); - gint call_index=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"call_index")); - GtkWidget *new_label=gtk_hbox_new (FALSE,0); - GtkWidget *i=NULL; - GtkWidget *l; - gchar *text; - - if(pause){ - i=gtk_image_new_from_icon_name("linphone-hold-off",GTK_ICON_SIZE_BUTTON); - } else { - i=gtk_image_new_from_icon_name("linphone-start-call", GTK_ICON_SIZE_BUTTON); - } - - text=g_strdup_printf(_("Call #%i"),call_index); - l=gtk_label_new (text); - gtk_box_pack_start (GTK_BOX(new_label),i,FALSE,FALSE,0); - gtk_box_pack_end(GTK_BOX(new_label),l,TRUE,TRUE,0); - - gtk_notebook_set_tab_label(notebook,w,new_label); - gtk_widget_show_all(new_label); - g_free(text); -} - -static void linphone_gtk_in_call_set_animation_image(GtkWidget *callview, const char *image_name){ - GtkWidget *container=linphone_gtk_get_widget(callview,"in_call_animation"); - GList *elem=gtk_container_get_children(GTK_CONTAINER(container)); - GtkWidget *image; - - if (image_name==NULL){ - gtk_widget_hide(container); - } - image=gtk_image_new_from_icon_name(image_name,GTK_ICON_SIZE_DIALOG); - if (elem) - gtk_widget_destroy((GtkWidget*)elem->data); - gtk_widget_show(image); - gtk_container_add(GTK_CONTAINER(container),image); - gtk_widget_show_all(container); -} - -static void linphone_gtk_in_call_set_animation_spinner(GtkWidget *callview){ -#if GTK_CHECK_VERSION(2,20,0) - GtkWidget *container=linphone_gtk_get_widget(callview,"in_call_animation"); - GList *elem=gtk_container_get_children(GTK_CONTAINER(container)); - GtkWidget *spinner=gtk_spinner_new(); - if (elem) - gtk_widget_destroy((GtkWidget*)elem->data); - gtk_widget_show(spinner); - gtk_container_add(GTK_CONTAINER(container),spinner); - gtk_widget_set_size_request(spinner, 20,20); - gtk_spinner_start(GTK_SPINNER(spinner)); -#endif -} - -static void linphone_gtk_transfer_call(LinphoneCall *dest_call){ - LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL); - if (call) linphone_call_transfer_to_another(call,dest_call); -} - -void transfer_button_clicked(GtkWidget *button, gpointer call_ref){ - GtkWidget *menu_item; - GtkWidget *menu=gtk_menu_new(); - LinphoneCall *call=(LinphoneCall*)call_ref; - LinphoneCore *lc=linphone_gtk_get_core(); - const bctbx_list_t *elem=linphone_core_get_calls(lc); - - for(;elem!=NULL;elem=elem->next){ - LinphoneCall *other_call=(LinphoneCall*)elem->data; - GtkWidget *call_view=(GtkWidget*)linphone_call_get_user_pointer(other_call); - if (other_call!=call){ - int call_index=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(call_view),"call_index")); - char *remote_uri=linphone_call_get_remote_address_as_string (other_call); - char *text=g_strdup_printf(_("Transfer to call #%i with %s"),call_index,remote_uri); - GtkWidget *image = gtk_image_new_from_icon_name("linphone-start-call", GTK_ICON_SIZE_MENU); - menu_item=gtk_image_menu_item_new_with_label(text); - ms_free(remote_uri); - g_free(text); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), image); - gtk_widget_show(menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); - g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_transfer_call,other_call); - } - } - gtk_menu_popup(GTK_MENU(menu),NULL,NULL,NULL,NULL,0,gtk_get_current_event_time()); - gtk_widget_show(menu); -} - -void linphone_gtk_enable_transfer_button(LinphoneCore *lc, gboolean value){ - const bctbx_list_t *elem=linphone_core_get_calls(lc); - for(;elem!=NULL;elem=elem->next){ - LinphoneCall *call=(LinphoneCall*)elem->data; - GtkWidget *call_view=(GtkWidget*)linphone_call_get_user_pointer(call); - GtkWidget *button=linphone_gtk_get_widget (call_view,"transfer_button"); - if(button != NULL){ - gtk_widget_set_sensitive(button,value); - } - } -} - -static void conference_button_clicked(GtkWidget *button, gpointer call_ref){ - gtk_widget_set_sensitive(button,FALSE); - linphone_core_add_all_to_conference(linphone_gtk_get_core()); - -} - -void linphone_gtk_enable_conference_button(LinphoneCore *lc, gboolean value){ - const bctbx_list_t *elem=linphone_core_get_calls(lc); - for(;elem!=NULL;elem=elem->next){ - LinphoneCall *call=(LinphoneCall*)elem->data; - GtkWidget *call_view=(GtkWidget*)linphone_call_get_user_pointer(call); - GtkWidget *button=linphone_gtk_get_widget (call_view,"conference_button"); - if (button != NULL){ - gtk_widget_set_sensitive(button,value); - } - } -} - -static void show_used_codecs(GtkWidget *callstats, LinphoneCall *call){ - const LinphoneCallParams *params=linphone_call_get_current_params(call); - if (params){ - const PayloadType *acodec=linphone_call_params_get_used_audio_codec(params); - const PayloadType *vcodec=linphone_call_params_get_used_video_codec(params); - GtkWidget *acodec_ui=linphone_gtk_get_widget(callstats,"audio_codec"); - GtkWidget *vcodec_ui=linphone_gtk_get_widget(callstats,"video_codec"); - if (acodec){ - char tmp[64]={0}; - snprintf(tmp,sizeof(tmp)-1,"%s/%i/%i",acodec->mime_type,acodec->clock_rate,acodec->channels); - gtk_label_set_label(GTK_LABEL(acodec_ui),tmp); - }else gtk_label_set_label(GTK_LABEL(acodec_ui),_("Not used")); - if (vcodec){ - gtk_label_set_label(GTK_LABEL(vcodec_ui),vcodec->mime_type); - }else gtk_label_set_label(GTK_LABEL(vcodec_ui),_("Not used")); - } -} - -static const char *ice_state_to_string(LinphoneIceState ice_state){ - switch(ice_state){ - case LinphoneIceStateNotActivated: - return _("ICE not activated"); - case LinphoneIceStateFailed: - return _("ICE failed"); - case LinphoneIceStateInProgress: - return _("ICE in progress"); - case LinphoneIceStateReflexiveConnection: - return _("Going through one or more NATs"); - case LinphoneIceStateHostConnection: - return _("Direct"); - case LinphoneIceStateRelayConnection: - return _("Through a relay server"); - } - return "invalid"; -} - -static const char *upnp_state_to_string(LinphoneUpnpState ice_state){ - switch(ice_state){ - case LinphoneUpnpStateIdle: - return _("uPnP not activated"); - case LinphoneUpnpStatePending: - return _("uPnP in progress"); - case LinphoneUpnpStateNotAvailable: - return _("uPnp not available"); - case LinphoneUpnpStateOk: - return _("uPnP is running"); - case LinphoneUpnpStateKo: - return _("uPnP failed"); - default: - break; - } - return "invalid"; -} - -static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){ - LinphoneUpnpState upnp_state; - LinphoneIceState ice_state; - LinphoneCallStats *as=linphone_call_get_audio_stats(call); - LinphoneCallStats *vs=linphone_call_get_video_stats(call); - const char *audio_media_connectivity = _("Direct or through server"); - const char *video_media_connectivity = _("Direct or through server"); - const LinphoneCallParams *curparams=linphone_call_get_current_params(call); - gboolean has_video=linphone_call_params_video_enabled(curparams); - MSVideoSize size_received = linphone_call_params_get_received_video_size(curparams); - MSVideoSize size_sent = linphone_call_params_get_sent_video_size(curparams); - const char *rtp_profile = linphone_call_params_get_rtp_profile(curparams); - gchar *tmp = g_strdup_printf("%s", rtp_profile); - gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"rtp_profile")),tmp); - g_free(tmp); - tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"), - linphone_call_stats_get_download_bandwidth(as),linphone_call_stats_get_upload_bandwidth(as)); - gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"audio_bandwidth_usage")),tmp); - g_free(tmp); - if (has_video){ - gchar *size_r=g_strdup_printf(_("%ix%i @ %f fps"),size_received.width,size_received.height, - linphone_call_params_get_received_framerate(curparams)); - gchar *size_s=g_strdup_printf(_("%ix%i @ %f fps"),size_sent.width,size_sent.height, - linphone_call_params_get_sent_framerate(curparams)); - gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_size_recv")),size_r); - gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_size_sent")),size_s); - - tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),linphone_call_stats_get_download_bandwidth(vs),linphone_call_stats_get_upload_bandwidth(vs)); - g_free(size_r); - g_free(size_s); - } else { - tmp=NULL; - } - gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_bandwidth_usage")),tmp); - if (tmp) g_free(tmp); - upnp_state = linphone_call_stats_get_upnp_state(as); - ice_state = linphone_call_stats_get_ice_state(as); - if(upnp_state != LinphoneUpnpStateNotAvailable && upnp_state != LinphoneUpnpStateIdle) { - audio_media_connectivity = upnp_state_to_string(upnp_state); - } else if(ice_state != LinphoneIceStateNotActivated) { - audio_media_connectivity = ice_state_to_string(ice_state); - } - gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"audio_media_connectivity")),audio_media_connectivity); - - if (has_video){ - upnp_state = linphone_call_stats_get_upnp_state(vs); - ice_state = linphone_call_stats_get_ice_state(vs); - if(upnp_state != LinphoneUpnpStateNotAvailable && upnp_state != LinphoneUpnpStateIdle) { - video_media_connectivity = upnp_state_to_string(upnp_state); - } else if(ice_state != LinphoneIceStateNotActivated) { - video_media_connectivity = ice_state_to_string(ice_state); - } - }else video_media_connectivity=NULL; - gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_media_connectivity")),video_media_connectivity); - - if (linphone_call_stats_get_round_trip_delay(as)>0){ - tmp=g_strdup_printf(_("%.3f seconds"),linphone_call_stats_get_round_trip_delay(as)); - gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"round_trip_time")),tmp); - g_free(tmp); - } - linphone_call_stats_unref(as); - linphone_call_stats_unref(vs); -} - -static gboolean refresh_call_stats(GtkWidget *callstats){ - LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(callstats),"call"); - switch (linphone_call_get_state(call)){ - case LinphoneCallError: - case LinphoneCallEnd: - case LinphoneCallReleased: - gtk_widget_destroy(callstats); - return FALSE; - break; - case LinphoneCallStreamsRunning: - _refresh_call_stats(callstats,call); - break; - default: - break; - } - return TRUE; -} - -static void on_call_stats_destroyed(GtkWidget *call_view){ - GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(call_view),"call_stats"); - LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(call_stats),"call"); - g_source_remove(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(call_stats),"tid"))); - g_object_set_data(G_OBJECT(call_view),"call_stats",NULL); - linphone_call_unref(call); -} - -static void linphone_gtk_show_call_stats(LinphoneCall *call){ - GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer(call); - GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(w),"call_stats"); - if (call_stats==NULL){ - guint tid; - call_stats=linphone_gtk_create_window("call_statistics", NULL); - g_object_set_data(G_OBJECT(w),"call_stats",call_stats); - g_object_set_data(G_OBJECT(call_stats),"call",linphone_call_ref(call)); - tid=g_timeout_add(1000,(GSourceFunc)refresh_call_stats,call_stats); - g_object_set_data(G_OBJECT(call_stats),"tid",GINT_TO_POINTER(tid)); - g_signal_connect_swapped(G_OBJECT(call_stats),"destroy",(GCallback)on_call_stats_destroyed,(gpointer)w); - show_used_codecs(call_stats,call); - refresh_call_stats(call_stats); - gtk_widget_show(call_stats); - } - -} - -void linphone_gtk_enable_video_button(LinphoneCall *call, gboolean sensitive, gboolean holdon){ - GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer (call); - GtkWidget *button; - g_return_if_fail(callview!=NULL); - button=linphone_gtk_get_widget(callview,"video_button"); - gtk_widget_set_sensitive(GTK_WIDGET(button),sensitive); - gtk_widget_set_visible(GTK_WIDGET(button),sensitive); -} - - -typedef enum { VOLUME_CTRL_PLAYBACK, VOLUME_CTRL_RECORD } VolumeControlType; - -static void volume_control_value_changed(GtkScaleButton *button, gdouble value, gpointer user_data) { - LinphoneCall *call = (LinphoneCall *)g_object_get_data(G_OBJECT(button), "call"); - VolumeControlType type = (VolumeControlType)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "type")); - - if(type == VOLUME_CTRL_PLAYBACK) { - linphone_call_set_speaker_volume_gain(call, (float)value); - } else if(type == VOLUME_CTRL_RECORD) { - linphone_call_set_microphone_volume_gain(call, (float)value); - } -} - -static gboolean volume_control_button_update_value(GtkWidget *widget) { - LinphoneCall *call = (LinphoneCall *)g_object_get_data(G_OBJECT(widget), "call"); - VolumeControlType type = (VolumeControlType)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "type")); - float gain = -1; - - if(type == VOLUME_CTRL_PLAYBACK) { - gain = linphone_call_get_speaker_volume_gain(call); - } else if(type == VOLUME_CTRL_RECORD) { - gain = linphone_call_get_microphone_volume_gain(call); - } - if(gain >= 0.0f) { - gtk_scale_button_set_value(GTK_SCALE_BUTTON(widget), gain); - return TRUE; - } else { - return FALSE; - } -} - -static gboolean volume_control_button_enter_event_handler(GtkWidget *widget) { - volume_control_button_update_value(widget); - return FALSE; -} - -static void volume_control_init(GtkWidget *vol_ctrl, VolumeControlType type, LinphoneCall *call) { - g_object_set_data(G_OBJECT(vol_ctrl), "call", call); - g_object_set_data(G_OBJECT(vol_ctrl), "type", GINT_TO_POINTER(type)); - if(!volume_control_button_update_value(vol_ctrl)) { - gtk_widget_set_sensitive(vol_ctrl, FALSE); - } else { - gtk_widget_set_sensitive(vol_ctrl, TRUE); - g_signal_connect(G_OBJECT(vol_ctrl), "enter-notify-event", G_CALLBACK(volume_control_button_enter_event_handler), NULL); - g_signal_connect(G_OBJECT(vol_ctrl), "value-changed", G_CALLBACK(volume_control_value_changed), NULL); - } -} - -void linphone_gtk_create_in_call_view(LinphoneCall *call){ - GtkWidget *call_view=linphone_gtk_create_widget("in_call_frame"); - GtkWidget *main_window=linphone_gtk_get_main_window (); - GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch"); - GtkWidget *audio_bar = linphone_gtk_get_widget(call_view, "incall_audioview"); - static int call_index=1; - int idx; - GtkWidget *record; - GtkWidget *transfer; - GtkWidget *conf; - GtkWidget *button; - GtkWidget *image; - - if (bctbx_list_size(linphone_core_get_calls(linphone_gtk_get_core()))==1){ - /*this is the only call at this time */ - call_index=1; - } - g_object_set_data(G_OBJECT(call_view),"call",call); - g_object_set_data(G_OBJECT(call_view),"call_index",GINT_TO_POINTER(call_index)); - - linphone_call_set_user_pointer (call,call_view); - linphone_call_ref(call); - gtk_notebook_append_page (notebook,call_view,make_tab_header(call_index)); - gtk_widget_show(call_view); - idx = gtk_notebook_page_num(notebook, call_view); - gtk_notebook_set_current_page(notebook, idx); - call_index++; - linphone_gtk_enable_hold_button (call,FALSE,TRUE); - linphone_gtk_enable_video_button (call,FALSE,TRUE); - linphone_gtk_enable_mute_button( - GTK_BUTTON(linphone_gtk_get_widget(call_view,"incall_mute")),FALSE); - - record = linphone_gtk_get_widget(call_view, "record_button"); - gtk_button_set_image(GTK_BUTTON(record), gtk_image_new_from_icon_name("linphone-record", GTK_ICON_SIZE_BUTTON)); - gtk_widget_hide(record); - transfer = linphone_gtk_get_widget(call_view,"transfer_button"); - gtk_button_set_image(GTK_BUTTON(transfer),gtk_image_new_from_icon_name("linphone-call-transfer",GTK_ICON_SIZE_BUTTON)); - g_signal_connect(G_OBJECT(transfer),"clicked",(GCallback)transfer_button_clicked,call); - gtk_widget_hide(transfer); - - conf = linphone_gtk_get_widget(call_view,"conference_button"); - gtk_button_set_image(GTK_BUTTON(conf),gtk_image_new_from_icon_name("linphone-conference-start",GTK_ICON_SIZE_BUTTON)); - g_signal_connect(G_OBJECT(conf),"clicked",(GCallback)conference_button_clicked,call); - gtk_widget_hide(conf); - - button=linphone_gtk_get_widget(call_view,"terminate_call"); - image=gtk_image_new_from_icon_name( - linphone_gtk_get_ui_config("stop_call_icon_name","linphone-stop-call"), - GTK_ICON_SIZE_BUTTON - ); - gtk_button_set_label(GTK_BUTTON(button),_("Hang up")); - gtk_button_set_image(GTK_BUTTON(button),image); - gtk_widget_show(image); - g_signal_connect_swapped(G_OBJECT(linphone_gtk_get_widget(call_view,"quality_indicator")),"button-press-event",(GCallback)linphone_gtk_show_call_stats,call); - - gtk_widget_hide(audio_bar); -} - -static void video_button_clicked(GtkWidget *button, LinphoneCall *call){ - gboolean adding=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button),"adding_video")); - LinphoneCore *lc=linphone_call_get_core(call); - LinphoneCallParams *params = linphone_core_create_call_params(lc, call); - gtk_widget_set_sensitive(button,FALSE); - linphone_call_params_enable_video(params, adding); - linphone_call_update(call,params); - linphone_call_params_unref(params); -} - -void linphone_gtk_update_video_button(LinphoneCall *call){ - GtkWidget *call_view=(GtkWidget*)linphone_call_get_user_pointer(call); - GtkWidget *button; - GtkWidget *conf_frame; - const LinphoneCallParams *params=linphone_call_get_current_params(call); - gboolean has_video=linphone_call_params_video_enabled(params); - gboolean button_sensitive=FALSE; - if (call_view==NULL) return; - - button=linphone_gtk_get_widget(call_view,"video_button"); - - gtk_button_set_image(GTK_BUTTON(button), - gtk_image_new_from_icon_name(has_video ? "linphone-camera-disabled" : "linphone-camera-enabled",GTK_ICON_SIZE_BUTTON)); - g_object_set_data(G_OBJECT(button),"adding_video",GINT_TO_POINTER(!has_video)); - if (!linphone_core_video_supported(linphone_call_get_core(call))){ - gtk_widget_set_sensitive(button,FALSE); - return; - } - switch(linphone_call_get_state(call)){ - case LinphoneCallStreamsRunning: - button_sensitive=!linphone_call_media_in_progress(call); - break; - default: - button_sensitive=FALSE; - break; - } - gtk_widget_set_sensitive(button,button_sensitive); - if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button),"signal_connected"))==0){ - g_signal_connect(G_OBJECT(button),"clicked",(GCallback)video_button_clicked,call); - g_object_set_data(G_OBJECT(button),"signal_connected",GINT_TO_POINTER(1)); - } - conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"conf_frame"); - if(conf_frame!=NULL){ - gtk_widget_set_sensitive(button,FALSE); - } -} - -void linphone_gtk_remove_in_call_view(LinphoneCall *call){ - GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer (call); - GtkWidget *main_window=linphone_gtk_get_main_window (); - GtkWidget *nb=linphone_gtk_get_widget(main_window,"viewswitch"); - int idx,id_current_page; - g_return_if_fail(w!=NULL); - idx=gtk_notebook_page_num(GTK_NOTEBOOK(nb),w); - if (linphone_gtk_call_is_in_conference_view(call)){ - linphone_gtk_unset_from_conference(call); - } - linphone_call_set_user_pointer (call,NULL); - linphone_call_unref(call); - call=linphone_core_get_current_call(linphone_gtk_get_core()); - id_current_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(nb)); - if (id_current_page == idx) { - if (call==NULL){ - if (linphone_core_is_in_conference(linphone_gtk_get_core())){ - /*show the conference*/ - gtk_notebook_set_current_page(GTK_NOTEBOOK(nb),gtk_notebook_page_num(GTK_NOTEBOOK(nb), - g_object_get_data(G_OBJECT(main_window),"conf_frame"))); - } else { - gtk_notebook_set_current_page(GTK_NOTEBOOK(nb),0); - } - }else{ - /*show the active call*/ - gtk_notebook_set_current_page(GTK_NOTEBOOK(nb),gtk_notebook_page_num(GTK_NOTEBOOK(nb), - linphone_call_get_user_pointer(call))); - } - } - gtk_notebook_remove_page (GTK_NOTEBOOK(nb),idx); - gtk_widget_destroy(w); -} - -static void display_peer_name_in_label(GtkWidget *label, const LinphoneAddress *from){ - const char *displayname=NULL; - char *id; - char *uri_label; - displayname=linphone_address_get_display_name(from); - id=linphone_address_as_string_uri_only(from); - - if (displayname!=NULL){ - uri_label=g_markup_printf_escaped("%s\n%s", - displayname,id); - }else - uri_label=g_markup_printf_escaped("%s\n",id); - gtk_label_set_markup(GTK_LABEL(label),uri_label); - g_free(uri_label); - ms_free(id); -} - -void linphone_gtk_in_call_view_set_calling(LinphoneCall *call){ - GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); - GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status"); - GtkWidget *callee=linphone_gtk_get_widget(callview,"in_call_uri"); - GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration"); - - gtk_label_set_markup(GTK_LABEL(status),_("Calling...")); - display_peer_name_in_label(callee,linphone_call_get_remote_address (call)); - - gtk_label_set_text(GTK_LABEL(duration),_("00:00:00")); - linphone_gtk_in_call_set_animation_spinner(callview); -} - -void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call){ - GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); - GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status"); - GtkWidget *callee=linphone_gtk_get_widget(callview,"in_call_uri"); - GtkWidget *answer_button; - GtkWidget *image; - - gtk_label_set_markup(GTK_LABEL(status),_("Incoming call")); - gtk_widget_show_all(linphone_gtk_get_widget(callview,"answer_decline_panel")); - gtk_widget_hide(linphone_gtk_get_widget(callview,"buttons_panel")); - display_peer_name_in_label(callee,linphone_call_get_remote_address (call)); - - answer_button=linphone_gtk_get_widget(callview,"accept_call"); - image=gtk_image_new_from_icon_name("linphone-start-call", GTK_ICON_SIZE_BUTTON); - gtk_button_set_label(GTK_BUTTON(answer_button),_("Answer")); - gtk_button_set_image(GTK_BUTTON(answer_button),image); - gtk_widget_show(image); - - image=gtk_image_new_from_icon_name("linphone-stop-call", GTK_ICON_SIZE_BUTTON); - gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(callview,"decline_call")),image); - gtk_widget_show(image); - - linphone_gtk_in_call_set_animation_image(callview,"linphone-call-status-incoming"); -} - -static void rating_to_color(float rating, GdkColor *color){ - const char *colorname="grey"; - if (rating>=4.0) - colorname="green"; - else if (rating>=3.0) - colorname="white"; - else if (rating>=2.0) - colorname="yellow"; - else if (rating>=1.0) - colorname="orange"; - else if (rating>=0) - colorname="red"; - if (!gdk_color_parse(colorname,color)){ - g_warning("Fail to parse color %s",colorname); - } -} - -static const char *rating_to_text(float rating){ - if (rating>=4.0) - return _("good"); - if (rating>=3.0) - return _("average"); - if (rating>=2.0) - return _("poor"); - if (rating>=1.0) - return _("very poor"); - if (rating>=0) - return _("too bad"); - return _("unavailable"); -} - -static gboolean linphone_gtk_in_call_view_refresh(LinphoneCall *call){ - GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); - GtkWidget *qi=linphone_gtk_get_widget(callview,"quality_indicator"); - float rating=linphone_call_get_current_quality(call); - GdkColor color; - gchar tmp[50]; - linphone_gtk_in_call_view_update_duration(call); - if (rating>=0){ - gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(qi),rating/5.0); - snprintf(tmp,sizeof(tmp),"%.1f (%s)",rating,rating_to_text(rating)); - gtk_progress_bar_set_text(GTK_PROGRESS_BAR(qi),tmp); - }else{ - gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(qi),0); - gtk_progress_bar_set_text(GTK_PROGRESS_BAR(qi),_("unavailable")); - } - rating_to_color(rating,&color); - gtk_widget_modify_bg(qi,GTK_STATE_NORMAL,&color); - - linphone_gtk_update_video_button(call); /*in case of no ice re-invite, video button status shall be checked by polling*/ - return TRUE; -} - -#define UNSIGNIFICANT_VOLUME (-23) -#define SMOOTH 0.15f - -static gboolean update_audio_meter(volume_ctx_t *ctx){ - float volume_db=ctx->get_volume(ctx->data); - float frac=(volume_db-UNSIGNIFICANT_VOLUME)/(float)(-UNSIGNIFICANT_VOLUME-3.0); - if (frac<0) frac=0; - if (frac>1.0) frac=1.0; - if (fraclast_value){ - frac=(frac*SMOOTH)+(ctx->last_value*(1-SMOOTH)); - } - ctx->last_value=frac; - //g_message("volume_db=%f, frac=%f",volume_db,frac); - gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ctx->widget),frac); - return TRUE; -} - -static void on_audio_meter_destroy(GtkWidget *w, gpointer data){ - guint task_id = GPOINTER_TO_INT(data); - g_source_remove(task_id); -} - - -void linphone_gtk_init_audio_meter(GtkWidget *w, get_volume_t get_volume, void *data){ - guint task_id=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"task_id")); - if (task_id==0){ - volume_ctx_t *ctx=g_new(volume_ctx_t,1); - ctx->widget=w; - ctx->get_volume=get_volume; - ctx->data=data; - ctx->last_value=0; - g_object_set_data_full(G_OBJECT(w),"ctx",ctx,g_free); - task_id=g_timeout_add(50,(GSourceFunc)update_audio_meter,ctx); - g_object_set_data(G_OBJECT(w), "task_id", GINT_TO_POINTER(task_id)); - g_signal_connect(G_OBJECT(w), "destroy", (GCallback)on_audio_meter_destroy, GINT_TO_POINTER(task_id)); - } -} - -void linphone_gtk_uninit_audio_meter(GtkWidget *w){ - guint task_id=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"task_id")); - if (task_id!=0){ - g_object_set_data(G_OBJECT(w),"ctx",NULL); - g_object_set_data(G_OBJECT(w),"task_id",NULL); - g_source_remove(task_id); - } -} - -void linphone_gtk_in_call_view_enable_audio_view(LinphoneCall *call, gboolean val){ - GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); - GtkWidget *audio_view=linphone_gtk_get_widget(callview,"incall_audioview"); - GtkWidget *mic_level=linphone_gtk_get_widget(callview,"mic_audiolevel"); - GtkWidget *spk_level=linphone_gtk_get_widget(callview,"spk_audiolevel"); - GtkWidget *mic_ctrl = linphone_gtk_get_widget(callview, "incall_mic_vol_ctrl_button"); - GtkWidget *spk_ctrl = linphone_gtk_get_widget(callview, "incall_spk_vol_ctrl_button"); - - if (val){ - linphone_gtk_init_audio_meter(mic_level,(get_volume_t)linphone_call_get_record_volume,call); - linphone_gtk_init_audio_meter(spk_level,(get_volume_t)linphone_call_get_play_volume,call); - volume_control_init(mic_ctrl, VOLUME_CTRL_RECORD, call); - volume_control_init(spk_ctrl, VOLUME_CTRL_PLAYBACK, call); - gtk_widget_show_all(audio_view); - }else{ - linphone_gtk_uninit_audio_meter(mic_level); - linphone_gtk_uninit_audio_meter(spk_level); - gtk_widget_hide(audio_view); - } -} - -void linphone_gtk_auth_token_verified_clicked(GtkButton *button){ - LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL); - if (call){ - linphone_call_set_authentication_token_verified(call,!linphone_call_get_authentication_token_verified(call)); - } -} - -void linphone_gtk_in_call_view_show_encryption(LinphoneCall *call){ - GtkWidget *callview = (GtkWidget*)linphone_call_get_user_pointer(call); - GtkWidget *encryption_status_box = linphone_gtk_get_widget(callview, "encryption_status_box"); - GtkWidget *encryption_status_label = linphone_gtk_get_widget(callview, "encryption_status_label"); - GtkWidget *encryption_status_icon = linphone_gtk_get_widget(callview, "encryption_status_icon"); - GtkWidget *zrtp_box = linphone_gtk_get_widget(callview, "zrtp_box"); - GtkWidget *zrtp_button = linphone_gtk_get_widget(callview, "zrtp_button"); - GtkWidget *zrtp_status_icon = gtk_button_get_image(GTK_BUTTON(zrtp_button)); - LinphoneMediaEncryption me = linphone_call_params_get_media_encryption(linphone_call_get_current_params(call)); - - switch (me) { - case LinphoneMediaEncryptionSRTP: - gtk_widget_hide_all(zrtp_box); - gtk_widget_show_all(encryption_status_box); - gtk_label_set_markup(GTK_LABEL(encryption_status_label), _("Secured by SRTP")); - gtk_image_set_from_icon_name(GTK_IMAGE(encryption_status_icon), "linphone-security-ok", GTK_ICON_SIZE_MENU); - break; - case LinphoneMediaEncryptionDTLS: - gtk_widget_hide_all(zrtp_box); - gtk_widget_show_all(encryption_status_box); - gtk_label_set_markup(GTK_LABEL(encryption_status_label), _("Secured by DTLS")); - gtk_image_set_from_icon_name(GTK_IMAGE(encryption_status_icon), "linphone-security-ok", GTK_ICON_SIZE_MENU); - break; - case LinphoneMediaEncryptionZRTP: - { - bool_t verified = linphone_call_get_authentication_token_verified(call); - gchar *text = g_strdup_printf(_("Secured by ZRTP - [auth token: %s]"), linphone_call_get_authentication_token(call)); - gtk_button_set_label(GTK_BUTTON(zrtp_button), text); - g_free(text); - gtk_image_set_from_icon_name(GTK_IMAGE(zrtp_status_icon), verified ? "linphone-security-ok" : "linphone-security-pending", GTK_ICON_SIZE_MENU); - gtk_widget_set_tooltip_text(zrtp_button, verified ? _("Set unverified") : _("Set verified")); - gtk_widget_hide_all(encryption_status_box); - gtk_widget_show_all(zrtp_box); - } - break; - default: - gtk_widget_hide_all(encryption_status_box); - gtk_widget_hide_all(zrtp_box); - break; - } -} - -void linphone_gtk_in_call_view_hide_encryption(LinphoneCall *call) { - GtkWidget *callview = (GtkWidget*)linphone_call_get_user_pointer(call); - GtkWidget *encryption_status_box = linphone_gtk_get_widget(callview, "encryption_status_box"); - GtkWidget *zrtp_box = linphone_gtk_get_widget(callview, "zrtp_box"); - gtk_widget_hide_all(encryption_status_box); - gtk_widget_hide_all(zrtp_box); -} - -char *linphone_gtk_address(const LinphoneAddress *addr){ - const char *displayname=linphone_address_get_display_name(addr); - if (!displayname) return linphone_address_as_string_uri_only(addr); - return ms_strdup(displayname); -} - -void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){ - GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); - GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status"); - GtkWidget *callee=linphone_gtk_get_widget(callview,"in_call_uri"); - GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration"); - guint taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid")); - gboolean in_conf=(linphone_call_get_conference(call) != NULL); - GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"call_stats"); - - linphone_gtk_in_call_show_video(call); - - display_peer_name_in_label(callee,linphone_call_get_remote_address (call)); - - gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel")); - gtk_label_set_markup(GTK_LABEL(status),in_conf ? _("In conference") : _("In call")); - - gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"conference_button"),!in_conf); - gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"transfer_button"),!in_conf); - - gtk_label_set_text(GTK_LABEL(duration),_("00:00:00")); - linphone_gtk_in_call_set_animation_image(callview,"linphone-media-play"); - linphone_gtk_call_update_tab_header(call,FALSE); - linphone_gtk_enable_mute_button( - GTK_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),TRUE); - - if (taskid==0){ - taskid=g_timeout_add(250,(GSourceFunc)linphone_gtk_in_call_view_refresh,call); - g_object_set_data(G_OBJECT(callview),"taskid",GINT_TO_POINTER(taskid)); - } - linphone_gtk_in_call_view_enable_audio_view(call, !in_conf); - linphone_gtk_in_call_view_show_encryption(call); - if (in_conf){ - linphone_gtk_set_in_conference(call); - gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"incall_mute"),FALSE); - gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"hold_call"),FALSE); - }else{ - linphone_gtk_unset_from_conference(call); /*in case it was previously*/ - gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"incall_mute"),TRUE); - gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"hold_call"),TRUE); - } - gtk_widget_show_all(linphone_gtk_get_widget(callview,"buttons_panel")); - if (!in_conf) gtk_widget_show_all(linphone_gtk_get_widget(callview,"record_hbox")); - else gtk_widget_hide(linphone_gtk_get_widget(callview,"record_hbox")); - if (call_stats) show_used_codecs(call_stats,call); -} - -void linphone_gtk_in_call_view_set_paused(LinphoneCall *call){ - GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); - GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status"); - GtkWidget *record_bar = linphone_gtk_get_widget(callview, "record_hbox"); - gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel")); - gtk_label_set_markup(GTK_LABEL(status),_("Paused call")); - linphone_gtk_in_call_show_video(call); - linphone_gtk_in_call_set_animation_image(callview,"linphone-media-pause"); - gtk_widget_show_all(record_bar); -} - -void linphone_gtk_in_call_view_update_duration(LinphoneCall *call){ - GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); - GtkWidget *duration_label=linphone_gtk_get_widget(callview,"in_call_duration"); - int duration=linphone_call_get_duration(call); - char tmp[256]={0}; - int seconds=duration%60; - int minutes=(duration/60)%60; - int hours=duration/3600; - snprintf(tmp,sizeof(tmp)-1,"%02i:%02i:%02i",hours,minutes,seconds); - gtk_label_set_text(GTK_LABEL(duration_label),tmp); -} - -static gboolean in_call_view_terminated(LinphoneCall *call){ - linphone_gtk_remove_in_call_view(call); - return FALSE; -} - -void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_msg){ - GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); - GtkWidget *status; - GtkWidget *video_window; - gboolean in_conf; - guint taskid; - if(callview==NULL) return; - video_window=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"video_window"); - status=linphone_gtk_get_widget(callview,"in_call_status"); - taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid")); - in_conf=(linphone_call_get_conference(call) != NULL); - if (video_window) gtk_widget_destroy(video_window); - if (status==NULL) return; - if (error_msg==NULL) - gtk_label_set_markup(GTK_LABEL(status),_("Call ended.")); - else{ - char *msg=g_markup_printf_escaped("%s",error_msg); - gtk_label_set_markup(GTK_LABEL(status),msg); - g_free(msg); - } - - linphone_gtk_in_call_set_animation_image(callview, linphone_gtk_get_ui_config("stop_call_icon_name","linphone-stop-call")); - linphone_gtk_in_call_view_hide_encryption(call); - - gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel")); - gtk_widget_hide(linphone_gtk_get_widget(callview,"record_hbox")); - gtk_widget_hide(linphone_gtk_get_widget(callview,"buttons_panel")); - gtk_widget_hide(linphone_gtk_get_widget(callview,"incall_audioview")); - gtk_widget_hide(linphone_gtk_get_widget(callview,"quality_indicator")); - linphone_gtk_enable_mute_button( - GTK_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),FALSE); - linphone_gtk_enable_hold_button(call,FALSE,TRUE); - - if (taskid!=0) g_source_remove(taskid); - g_timeout_add_seconds(2,(GSourceFunc)in_call_view_terminated,call); - if (in_conf) - linphone_gtk_terminate_conference_participant(call); -} - -void linphone_gtk_in_call_view_set_transfer_status(LinphoneCall *call,LinphoneCallState cstate){ - GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); - if (callview){ - GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration"); - const char *transfer_status="unknown"; - switch(cstate){ - case LinphoneCallOutgoingProgress: - transfer_status=_("Transfer in progress"); - break; - case LinphoneCallConnected: - transfer_status=_("Transfer done."); - break; - case LinphoneCallError: - transfer_status=_("Transfer failed."); - break; - default: - break; - } - gtk_label_set_text(GTK_LABEL(duration),transfer_status); - } -} - -void linphone_gtk_draw_mute_button(GtkButton *button, gboolean active){ - const char *icon_name = active ? "linphone-micro-muted" : "linphone-micro-enabled"; - GtkWidget *image = gtk_image_new_from_icon_name(icon_name, GTK_ICON_SIZE_BUTTON); - gtk_button_set_image(button, image); - gtk_widget_show(image); - g_object_set_data(G_OBJECT(button),"active",GINT_TO_POINTER(active)); -} - -void linphone_gtk_mute_clicked(GtkButton *button){ - int active=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button),"active")); - linphone_core_enable_mic(linphone_gtk_get_core(),active); - linphone_gtk_draw_mute_button(button,!active); -} - -void linphone_gtk_enable_mute_button(GtkButton *button, gboolean sensitive){ - /*gtk_widget_set_sensitive(GTK_WIDGET(button),sensitive);*/ - gtk_widget_set_visible(GTK_WIDGET(button),sensitive); - linphone_gtk_draw_mute_button(button,FALSE); -} - -void linphone_gtk_draw_hold_button(GtkButton *button, gboolean active){ - const gchar *icon_name = active ? "linphone-hold-on" : "linphone-hold-off"; - const gchar *label = active ? _("Resume") : _("Pause"); - GtkWidget *image = gtk_image_new_from_icon_name(icon_name, GTK_ICON_SIZE_BUTTON); - g_object_set_data(G_OBJECT(button),"active",GINT_TO_POINTER(active)); - gtk_button_set_label(GTK_BUTTON(button),label); - gtk_button_set_image(GTK_BUTTON(button),image); - gtk_widget_show(image); -} - -void linphone_gtk_hold_clicked(GtkButton *button){ - int active=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button),"active")); - LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL); - linphone_gtk_call_update_tab_header(call,active); - if (!call) return; - if(!active) - { - linphone_call_pause(call); - } - else - { - linphone_call_resume(call); - } -} - -void linphone_gtk_enable_hold_button(LinphoneCall *call, gboolean sensitive, gboolean holdon){ - GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer (call); - GtkWidget *button; - g_return_if_fail(callview!=NULL); - linphone_gtk_call_update_tab_header(call,!holdon); - button=linphone_gtk_get_widget(callview,"hold_call"); - gtk_widget_set_sensitive(GTK_WIDGET(button),sensitive); - gtk_widget_set_visible(GTK_WIDGET(button),sensitive); - linphone_gtk_draw_hold_button(GTK_BUTTON(button),!holdon); -} - -void linphone_gtk_call_statistics_closed(GtkWidget *call_stats){ - gtk_widget_destroy(call_stats); -} - -void linphone_gtk_record_call_toggled(GtkWidget *button){ - gboolean active=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)); - gboolean is_conf=FALSE; - const char *filepath; - gchar *message; - LinphoneCore *lc=linphone_gtk_get_core(); - LinphoneCall *call=linphone_gtk_get_currently_displayed_call(&is_conf); - GtkWidget *callview; - GtkWidget *label; - if (call){ - const LinphoneCallParams *params; - callview=(GtkWidget*)linphone_call_get_user_pointer (call); - params=linphone_call_get_current_params(call); - filepath=linphone_call_params_get_record_file(params); - label=linphone_gtk_get_widget(callview,"record_status"); - }else if (is_conf){ - GtkWidget *mw=linphone_gtk_get_main_window(); - callview=(GtkWidget *)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"conf_frame"); - label=linphone_gtk_get_widget(callview,"conf_record_status"); - filepath=(const char*)g_object_get_data(G_OBJECT(mw),"conf_record_path"); - if (filepath==NULL){ - filepath=linphone_gtk_get_record_path(NULL,TRUE); - g_object_set_data_full(G_OBJECT(mw),"conf_record_path",(char*)filepath,g_free); - } - }else{ - g_warning("linphone_gtk_record_call_toggled(): bug."); - return; - } - message=g_strdup_printf(_("Recording into\n%s %s"),filepath,active ? "" : _("(Paused)")); - - if (active){ - if (call) - linphone_call_start_recording(call); - else - linphone_core_start_conference_recording(lc,filepath); - }else { - if (call) - linphone_call_stop_recording(call); - else - linphone_core_stop_conference_recording(lc); - - } - gtk_label_set_markup(GTK_LABEL(label),g_locale_to_utf8(message, -1, NULL, NULL, NULL)); - g_free(message); -} - diff --git a/gtk/keypad.ui b/gtk/keypad.ui deleted file mode 100644 index 020204f2b..000000000 --- a/gtk/keypad.ui +++ /dev/null @@ -1,265 +0,0 @@ - - - - - - False - - - - True - False - GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK - 0.5 - none - - - - - True - False - 0 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 4 - 4 - 4 - True - - - D - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - 3 - 4 - 3 - 4 - - - - - # - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - 2 - 3 - 3 - 4 - - - - - 0 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - 1 - 2 - 3 - 4 - - - - - * - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - 3 - 4 - - - - - C - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - 3 - 4 - 2 - 3 - - - - - 9 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - 2 - 3 - 2 - 3 - - - - - 8 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - 1 - 2 - 2 - 3 - - - - - 7 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - 2 - 3 - - - - - B - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - 3 - 4 - 1 - 2 - - - - - 6 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - 2 - 3 - 1 - 2 - - - - - 5 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - 1 - 2 - 1 - 2 - - - - - 4 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - 1 - 2 - - - - - A - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - 3 - 4 - - - - - 3 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - 2 - 3 - - - - - 2 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - 1 - 2 - - - - - 1 - 40 - 40 - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - - - - - - - - - - diff --git a/gtk/ldap.ui b/gtk/ldap.ui deleted file mode 100644 index a5df241d1..000000000 --- a/gtk/ldap.ui +++ /dev/null @@ -1,669 +0,0 @@ - - - - - - False - LDAP Settings - - - True - False - - - True - False - 0 - none - - - True - False - 12 - - - True - False - 5 - 2 - - - True - False - 1 - Server address: - - - - - True - False - Authentication method: - - - 1 - 2 - - - - - True - False - Username: - - - 2 - 3 - - - - - True - False - Password: - - - 3 - 4 - - - - - Use TLS Connection - True - False - True - False - Not yet available - False - True - - - 1 - 2 - 4 - 5 - - - - - True - True - - True - False - False - True - True - - - 1 - 2 - - - - - True - True - - True - False - False - True - True - - - 1 - 2 - 2 - 3 - - - - - True - True - False - False - False - True - True - - - 1 - 2 - 3 - 4 - - - - - True - False - liststore2 - 0 - - - - 0 - - - - - 1 - 2 - 1 - 2 - - - - - - - - - - - - True - False - <b>Connection</b> - True - - - - - True - True - 0 - - - - - True - False - 0 - none - - - True - False - 12 - - - True - False - 3 - 2 - - - True - False - Bind DN - - - - - True - False - Authname - - - 1 - 2 - - - - - True - False - Realm - - - 2 - 3 - - - - - True - True - - False - False - True - True - - - 1 - 2 - - - - - True - True - - True - False - False - True - True - - - 1 - 2 - 1 - 2 - - - - - True - True - - True - False - False - True - True - - - 1 - 2 - 2 - 3 - - - - - - - - - True - False - <b>SASL</b> - True - - - - - True - True - 1 - - - - - True - False - 0 - none - - - True - False - 12 - - - True - False - 5 - 2 - - - True - False - Base object: - - - - - True - False - Filter (%s for name): - - - 1 - 2 - - - - - True - False - Name Attribute: - - - 2 - 3 - - - - - True - False - SIP address attribute: - - - 3 - 4 - - - - - True - False - Attributes to query: - - - 4 - 5 - - - - - True - True - - True - False - False - True - True - - - 1 - 2 - - - - - True - True - - True - False - False - True - True - - - 1 - 2 - 1 - 2 - - - - - True - True - - True - False - False - True - True - - - 1 - 2 - 2 - 3 - - - - - True - True - - True - False - False - True - True - - - 1 - 2 - 3 - 4 - - - - - True - True - - True - False - False - True - True - - - 1 - 2 - 4 - 5 - - - - - - - - - True - False - <b>Search</b> - True - - - - - True - True - 2 - - - - - True - False - 0 - none - - - True - False - 12 - - - True - False - 3 - 2 - - - True - False - Timeout for search: - - - - - True - False - Max results: - - - 1 - 2 - - - - - True - True - - True - False - False - True - True - timeout_adjustment - - - 1 - 2 - - - - - True - True - 3 - - True - False - False - True - True - result_adjustment - True - - - 1 - 2 - 1 - 2 - - - - - Follow Aliases - True - True - False - False - True - - - 1 - 2 - 2 - 3 - - - - - - - - - - - - True - False - <b>Miscellaneous</b> - True - - - - - True - True - 3 - - - - - True - False - 2 - - - - - - gtk-apply - True - True - True - False - True - - - - False - False - end - 1 - - - - - gtk-cancel - True - True - True - False - True - - - - False - False - end - 2 - - - - - False - True - 4 - - - - - - - - - - - - - ANONYMOUS - - - SIMPLE - - - DIGEST-MD5 - - - NTLM - - - - - 1 - 100 - 50 - 1 - 10 - - - 1 - 100 - 10 - 1 - 10 - - diff --git a/gtk/linphone.h b/gtk/linphone.h deleted file mode 100644 index 796ee8fb2..000000000 --- a/gtk/linphone.h +++ /dev/null @@ -1,379 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) -#pragma GCC diagnostic push -#endif -#ifndef _MSC_VER -#pragma GCC diagnostic ignored "-Wstrict-prototypes" -#endif - -#include - -#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) -#pragma GCC diagnostic pop -#endif - -#ifdef _WIN32 -// alloca is already defined by gtk -#undef alloca -#endif -#include "linphone/core.h" - -#include "linphone/ldapprovider.h" - -#ifdef ENABLE_NLS - -#ifdef _MSC_VER -// prevent libintl.h from re-defining fprintf and vfprintf -#ifndef fprintf -#define fprintf fprintf -#endif -#ifndef vfprintf -#define vfprintf vfprintf -#endif -#define _GL_STDIO_H -#endif - -# include -# undef _ -# define _(String) dgettext (GETTEXT_PACKAGE,String) -#else -# define _(String) (String) -# define ngettext(singular,plural,number) ((number>1) ? (plural) : (singular) ) -#endif // ENABLE_NLS - -#undef N_ -#define N_(str) (str) - -#ifdef USE_BUILDDATE_VERSION -#include "version_date.h" -#undef LINPHONE_VERSION -#define LINPHONE_VERSION LINPHONE_VERSION_DATE -#endif - -#include "setupwizard.h" - -#define LINPHONE_ICON "linphone.png" -#define LINPHONE_ICON_NAME "linphone" - -enum { - COMPLETION_HISTORY, - COMPLETION_LDAP -}; - -typedef float (*get_volume_t)(void *data); - -typedef struct _volume_ctx{ - GtkWidget *widget; - get_volume_t get_volume; - void *data; - float last_value; -}volume_ctx_t; - -typedef enum { - CAP_IGNORE, - CAP_PLAYBACK, - CAP_CAPTURE -}DeviceCap; - -enum { - START_LINPHONE, - START_AUDIO_ASSISTANT, - START_LINPHONE_WITH_CALL -}; - -GdkPixbuf * create_pixbuf(const gchar *filename); -GdkPixbufAnimation *create_pixbuf_animation(const gchar *filename); -void add_pixmap_directory(const gchar *directory); -GtkWidget*create_pixmap(const gchar *filename); -GtkWidget *_gtk_image_new_from_memory_at_scale(const void *data, gint len, gint w, gint h, gboolean preserve_ratio); -GdkPixbuf *_gdk_pixbuf_new_from_memory_at_scale(const void *data, gint len, gint w, gint h, gboolean preserve_ratio); - -LINPHONE_PUBLIC void linphone_gtk_destroy_window(GtkWidget *window); -LINPHONE_PUBLIC GtkWidget *linphone_gtk_create_window(const char *window_name, GtkWidget *parent); -LINPHONE_PUBLIC GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name); -LINPHONE_PUBLIC GtkWidget *linphone_gtk_create_widget(const char* widget_name); -LINPHONE_PUBLIC GtkWidget *linphone_gtk_make_tab_header(const gchar *label, const gchar *icon_name, gboolean show_quit_button, GCallback cb, gpointer user_data); - -char *linphone_gtk_message_storage_get_db_file(const char *filename); -char *linphone_gtk_call_logs_storage_get_db_file(const char *filename); -char *linphone_gtk_friends_storage_get_db_file(const char* filename); -LINPHONE_PUBLIC void linphone_gtk_close_assistant(void); - -LINPHONE_PUBLIC LinphoneCore *linphone_gtk_get_core(void); -LINPHONE_PUBLIC GtkWidget *linphone_gtk_get_main_window(void); -LINPHONE_PUBLIC void linphone_gtk_display_something(GtkMessageType type, const gchar *message); -LINPHONE_PUBLIC void linphone_gtk_call_terminated(LinphoneCall *call, const char *error); -LINPHONE_PUBLIC void linphone_gtk_set_my_presence(LinphoneOnlineStatus ss); -LINPHONE_PUBLIC void linphone_gtk_show_parameters(void); -LINPHONE_PUBLIC void linphone_gtk_fill_soundcards(GtkWidget *pb); -LINPHONE_PUBLIC void linphone_gtk_fill_webcams(GtkWidget *pb); -LINPHONE_PUBLIC void linphone_gtk_load_identities(void); -LINPHONE_PUBLIC void linphone_gtk_call_log_update(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_create_log_window(void); -LINPHONE_PUBLIC void linphone_gtk_log_show(void); -LINPHONE_PUBLIC void linphone_gtk_show_main_window(void); -LINPHONE_PUBLIC void linphone_gtk_log_push(OrtpLogLevel lev, const char *fmt, va_list args); -LINPHONE_PUBLIC void linphone_gtk_destroy_log_window(void); -LINPHONE_PUBLIC void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to); -LINPHONE_PUBLIC gboolean linphone_gtk_check_logs(void); -LINPHONE_PUBLIC const gchar *linphone_gtk_get_ui_config(const char *key, const char *def); -LINPHONE_PUBLIC int linphone_gtk_get_ui_config_int(const char *key, int def); -LINPHONE_PUBLIC void linphone_gtk_set_ui_config_int(const char *key, int val); -LINPHONE_PUBLIC void linphone_gtk_visibility_set(const char *hiddens, const char *window_name, GtkWidget *w, gboolean show); - -LINPHONE_PUBLIC LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void); -LINPHONE_PUBLIC void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap); -LINPHONE_PUBLIC int linphone_gtk_is_ldap_supported(void); - -LINPHONE_PUBLIC void linphone_gtk_open_browser(const char *url); -LINPHONE_PUBLIC void linphone_gtk_check_for_new_version(void); -LINPHONE_PUBLIC const char *linphone_gtk_get_lang(const char *config_file); -LINPHONE_PUBLIC void linphone_gtk_set_lang(const char *code); -LINPHONE_PUBLIC SipSetupContext* linphone_gtk_get_default_sip_setup_context(void); -LINPHONE_PUBLIC GtkWidget * linphone_gtk_show_buddy_lookup_window(SipSetupContext *ctx); -LINPHONE_PUBLIC void linphone_gtk_buddy_lookup_set_keyword(GtkWidget *w, const char *kw); -LINPHONE_PUBLIC void * linphone_gtk_wait(LinphoneCore *lc, void *ctx, LinphoneWaitingState ws, const char *purpose, float progress); -LINPHONE_PUBLIC void linphone_gtk_terminate_call(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_call_update_tab_header(LinphoneCall *call, gboolean pause); -LINPHONE_PUBLIC void linphone_gtk_show_directory_search(void); -LINPHONE_PUBLIC void linphone_gtk_status_icon_set_blinking(gboolean val); -LINPHONE_PUBLIC void linphone_gtk_notify(LinphoneCall *call, LinphoneChatMessage *chat_message, const char *msg); - -LINPHONE_PUBLIC void linphone_gtk_load_chatroom(LinphoneChatRoom *cr, const LinphoneAddress *uri, GtkWidget *chat_view); -LINPHONE_PUBLIC void linphone_gtk_send_text(void); -LINPHONE_PUBLIC GtkWidget * linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddress *with); -LINPHONE_PUBLIC LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with); -LINPHONE_PUBLIC void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg); -LINPHONE_PUBLIC void linphone_gtk_is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room); - -LINPHONE_PUBLIC void linphone_gtk_friend_list_update_button_display(GtkTreeView *friendlist); -LINPHONE_PUBLIC void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la); -LINPHONE_PUBLIC gboolean linphone_gtk_friend_list_is_contact(const LinphoneAddress *addr); -LINPHONE_PUBLIC void linphone_gtk_friend_list_set_active_address(const LinphoneAddress *addr); -LINPHONE_PUBLIC const LinphoneAddress *linphone_gtk_friend_list_get_active_address(void); -LINPHONE_PUBLIC gboolean linphone_gtk_friend_list_enter_event_handler(GtkTreeView *friendlist, GdkEventCrossing *event); -LINPHONE_PUBLIC gboolean linphone_gtk_friend_list_leave_event_handler(GtkTreeView *friendlist, GdkEventCrossing *event); -LINPHONE_PUBLIC gboolean linphone_gtk_friend_list_motion_event_handler(GtkTreeView *friendlist, GdkEventMotion *event); -LINPHONE_PUBLIC void linphone_gtk_friend_list_on_name_column_clicked(GtkTreeModel *model); -LINPHONE_PUBLIC void linphone_gtk_notebook_tab_select(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer data); -LINPHONE_PUBLIC void linphone_gtk_show_friends(void); -LINPHONE_PUBLIC void linphone_gtk_show_contact(LinphoneFriend *lf, GtkWidget *parent); -LINPHONE_PUBLIC void linphone_gtk_buddy_info_updated(LinphoneCore *lc, LinphoneFriend *lf); - -/*functions controlling the different views*/ -LINPHONE_PUBLIC gboolean linphone_gtk_use_in_call_view(void); -LINPHONE_PUBLIC LinphoneCall *linphone_gtk_get_currently_displayed_call(gboolean *is_conf); -LINPHONE_PUBLIC void linphone_gtk_create_in_call_view(LinphoneCall *call); -LINPHONE_PUBLIC void linphone_gtk_in_call_view_set_calling(LinphoneCall *call); -LINPHONE_PUBLIC void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call); -LINPHONE_PUBLIC void linphone_gtk_in_call_view_update_duration(LinphoneCall *call); -LINPHONE_PUBLIC void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_msg); -LINPHONE_PUBLIC void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call); -LINPHONE_PUBLIC void linphone_gtk_in_call_view_set_paused(LinphoneCall *call); -LINPHONE_PUBLIC void linphone_gtk_in_call_view_set_transfer_status(LinphoneCall *call, LinphoneCallState cstate); -LINPHONE_PUBLIC void linphone_gtk_mute_clicked(GtkButton *button); -LINPHONE_PUBLIC void transfer_button_clicked(GtkWidget *button, gpointer call_ref); -LINPHONE_PUBLIC void linphone_gtk_enable_mute_button(GtkButton *button, gboolean sensitive); -LINPHONE_PUBLIC void linphone_gtk_enable_hold_button(LinphoneCall *call, gboolean sensitive, gboolean holdon); -LINPHONE_PUBLIC void linphone_gtk_enable_transfer_button(LinphoneCore *lc, gboolean value); -LINPHONE_PUBLIC void linphone_gtk_enable_conference_button(LinphoneCore *lc, gboolean value); -LINPHONE_PUBLIC void linphone_gtk_set_in_conference(LinphoneCall *call); -LINPHONE_PUBLIC void linphone_gtk_unset_from_conference(LinphoneCall *call); -LINPHONE_PUBLIC bool_t linphone_gtk_call_is_in_conference_view(LinphoneCall *call); -LINPHONE_PUBLIC void linphone_gtk_terminate_conference_participant(LinphoneCall *call); -LINPHONE_PUBLIC void linphone_gtk_in_call_view_show_encryption(LinphoneCall *call); -LINPHONE_PUBLIC void linphone_gtk_in_call_view_hide_encryption(LinphoneCall *call); -LINPHONE_PUBLIC void linphone_gtk_update_video_button(LinphoneCall *call); -LINPHONE_PUBLIC void linphone_gtk_init_audio_meter(GtkWidget *w, get_volume_t get_volume, void *data); -LINPHONE_PUBLIC void linphone_gtk_uninit_audio_meter(GtkWidget *w); - -LINPHONE_PUBLIC void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg, gboolean disable_auto_login); -LINPHONE_PUBLIC void linphone_gtk_exit_login_frame(void); -LINPHONE_PUBLIC void linphone_gtk_set_ui_config(const char *key, const char *value); - -LINPHONE_PUBLIC void linphone_gtk_log_uninit(void); - -LINPHONE_PUBLIC bool_t linphone_gtk_init_instance(const char *app_name, int option, const char *addr_to_call); -LINPHONE_PUBLIC void linphone_gtk_uninit_instance(void); -LINPHONE_PUBLIC void linphone_gtk_monitor_usb(void); -LINPHONE_PUBLIC void linphone_gtk_unmonitor_usb(void); - -LINPHONE_PUBLIC void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, const char *selected, DeviceCap cap); -LINPHONE_PUBLIC gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference); -LINPHONE_PUBLIC gchar *linphone_gtk_get_snapshot_path(void); -LINPHONE_PUBLIC void linphone_gtk_schedule_restart(void); - -LINPHONE_PUBLIC void linphone_gtk_show_audio_assistant(void); -LINPHONE_PUBLIC gboolean linphone_gtk_get_audio_assistant_option(void); - -LINPHONE_PUBLIC void linphone_gtk_set_configuration_uri(void); -LINPHONE_PUBLIC GtkWidget * linphone_gtk_show_config_fetching(void); -LINPHONE_PUBLIC void linphone_gtk_close_config_fetching(GtkWidget *w, LinphoneConfiguringState state); -LINPHONE_PUBLIC const char *linphone_gtk_get_sound_path(const char *file); -LINPHONE_PUBLIC void linphone_gtk_in_call_show_video(LinphoneCall *call); -LINPHONE_PUBLIC char *linphone_gtk_address(const LinphoneAddress *addr);/*return human readable identifier for a LinphoneAddress */ -LINPHONE_PUBLIC GtkWidget *linphone_gtk_get_camera_preview_window(void); - -LINPHONE_PUBLIC void linphone_gtk_login_frame_connect_clicked(GtkWidget *button, GtkWidget *login_frame); - -LINPHONE_PUBLIC gboolean linphone_gtk_call_log_reset_missed_call(GtkWidget *w, GdkEvent *event, gpointer user_data); -LINPHONE_PUBLIC void linphone_gtk_history_row_activated(GtkWidget *treeview); -LINPHONE_PUBLIC void linphone_gtk_history_row_selected(GtkWidget *treeview); -LINPHONE_PUBLIC void linphone_gtk_clear_call_logs(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_add_contact(void); -LINPHONE_PUBLIC void linphone_gtk_contact_clicked(GtkTreeSelection *selection); -LINPHONE_PUBLIC void linphone_gtk_add_button_clicked(void); -LINPHONE_PUBLIC void linphone_gtk_edit_button_clicked(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_remove_button_clicked(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_my_presence_clicked(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_directory_search_button_clicked(GtkWidget *button); -LINPHONE_PUBLIC gboolean linphone_gtk_popup_contact_menu(GtkWidget *list, GdkEventButton *event); -LINPHONE_PUBLIC gboolean linphone_gtk_contact_list_button_pressed(GtkTreeView* firendlist, GdkEventButton* event); -LINPHONE_PUBLIC void linphone_gtk_auth_token_verified_clicked(GtkButton *button); -LINPHONE_PUBLIC void linphone_gtk_hold_clicked(GtkButton *button); -LINPHONE_PUBLIC void linphone_gtk_record_call_toggled(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_log_hide(void); -LINPHONE_PUBLIC void linphone_gtk_log_scroll_to_end(GtkToggleButton *button); -LINPHONE_PUBLIC void linphone_gtk_log_clear(void); -LINPHONE_PUBLIC void linphone_gtk_logout_clicked(void); - -LINPHONE_PUBLIC void linphone_gtk_about_response(GtkDialog *dialog, gint id); -LINPHONE_PUBLIC void linphone_gtk_show_about(void); -LINPHONE_PUBLIC void linphone_gtk_start_call(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_start_chat(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_uri_bar_activate(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_terminate_call(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_decline_clicked(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_answer_clicked(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_enable_video(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_enable_self_view(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_used_identity_changed(GtkWidget *w); -LINPHONE_PUBLIC void on_proxy_refresh_button_clicked(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_link_to_website(GtkWidget *item); -LINPHONE_PUBLIC void linphone_gtk_options_activate(GtkWidget *item); -LINPHONE_PUBLIC void linphone_gtk_show_keypad_checked(GtkCheckMenuItem *check_menu_item); -LINPHONE_PUBLIC gboolean linphone_gtk_keypad_destroyed_handler(void); - -LINPHONE_PUBLIC void linphone_gtk_keyword_changed(GtkEditable *e); -LINPHONE_PUBLIC void linphone_gtk_buddy_lookup_contact_activated(GtkWidget *treeview); -LINPHONE_PUBLIC void linphone_gtk_add_buddy_from_database(GtkWidget *button); -LINPHONE_PUBLIC gboolean linphone_gtk_call_log_button_pressed(GtkWidget *widget, GdkEventButton *event); -LINPHONE_PUBLIC void linphone_gtk_call_statistics_closed(GtkWidget *call_stats); -LINPHONE_PUBLIC void linphone_gtk_config_uri_cancel(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_config_uri_changed(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_contact_cancel(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_contact_ok(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_dscp_edit(void); -LINPHONE_PUBLIC void linphone_gtk_dscp_edit_response(GtkWidget *dialog, guint response_id); -LINPHONE_PUBLIC void linphone_gtk_keypad_key_released(GtkWidget *w, GdkEvent *event, gpointer userdata); -LINPHONE_PUBLIC void linphone_gtk_keypad_key_pressed(GtkWidget *w, GdkEvent *event, gpointer userdata); -LINPHONE_PUBLIC void linphone_gtk_ldap_save(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_ldap_reset(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_parameters_destroyed(GtkWidget *pb); -LINPHONE_PUBLIC void linphone_gtk_mtu_set(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_mtu_changed(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_use_sip_info_dtmf_toggled(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_ipv6_toggled(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_lime_changed(GtkComboBoxText *comboext); -LINPHONE_PUBLIC void linphone_gtk_disabled_udp_port_toggle(GtkCheckButton *button); -LINPHONE_PUBLIC void linphone_gtk_random_udp_port_toggle(GtkCheckButton *button); -LINPHONE_PUBLIC void linphone_gtk_udp_port_value_changed(GtkSpinButton *button); -LINPHONE_PUBLIC void linphone_gtk_disabled_tcp_port_toggle(GtkCheckButton *button); -LINPHONE_PUBLIC void linphone_gtk_random_tcp_port_toggle(GtkCheckButton *button); -LINPHONE_PUBLIC void linphone_gtk_tcp_port_value_changed(GtkSpinButton *button); -LINPHONE_PUBLIC void linphone_gtk_min_audio_port_changed(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_max_audio_port_changed(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_fixed_audio_port_toggle(void); -LINPHONE_PUBLIC void linphone_gtk_min_video_port_changed(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_max_video_port_changed(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_fixed_video_port_toggle(void); -LINPHONE_PUBLIC void linphone_gtk_set_media_encryption_mandatory(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_edit_tunnel(GtkButton *button); -LINPHONE_PUBLIC void linphone_gtk_no_firewall_toggled(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_use_nat_address_toggled(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_use_stun_toggled(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_use_ice_toggled(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_use_upnp_toggled(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_nat_address_changed(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_stun_server_changed(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_ring_file_set(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_play_ring_file(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_alsa_special_device_changed(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_capture_device_changed(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_ring_device_changed(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_playback_device_changed(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_echo_cancelation_toggled(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_cam_changed(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_video_size_changed(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_video_renderer_changed(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_video_preset_changed(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_show_camera_preview_clicked(GtkButton *button); -LINPHONE_PUBLIC void linphone_gtk_update_my_contact(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_add_proxy(GtkButton *button); -LINPHONE_PUBLIC void linphone_gtk_show_sip_accounts(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_edit_proxy(GtkButton *button); -LINPHONE_PUBLIC void linphone_gtk_remove_proxy(GtkButton *button); -LINPHONE_PUBLIC void linphone_gtk_clear_passwords(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_audio_codec_up(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_audio_codec_down(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_audio_codec_enable(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_audio_codec_disable(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_video_codec_up(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_video_codec_down(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_video_codec_enable(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_video_codec_disable(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_video_framerate_changed(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_upload_bw_changed(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_download_bw_changed(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_adaptive_rate_control_toggled(GtkToggleButton *button); -LINPHONE_PUBLIC void linphone_gtk_lang_changed(GtkComboBox *combo); -LINPHONE_PUBLIC void linphone_gtk_ui_level_toggled(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_show_ldap_config(GtkWidget* button); -LINPHONE_PUBLIC void linphone_gtk_parameters_closed(GtkWidget *button); -LINPHONE_PUBLIC void linphone_gtk_password_ok(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_password_cancel(GtkWidget *w); -LINPHONE_PUBLIC void linphone_gtk_proxy_ok(GtkButton *button); -LINPHONE_PUBLIC void linphone_gtk_proxy_cancel(GtkButton *button); -LINPHONE_PUBLIC void linphone_gtk_proxy_address_changed(GtkEditable *editable); -LINPHONE_PUBLIC void linphone_gtk_proxy_transport_changed(GtkWidget *combo); -LINPHONE_PUBLIC void linphone_gtk_tunnel_ok(GtkButton *button); -LINPHONE_PUBLIC void linphone_gtk_notebook_current_page_changed(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data); -LINPHONE_PUBLIC void linphone_gtk_reload_sound_devices(void); -LINPHONE_PUBLIC void linphone_gtk_reload_video_devices(void); -LINPHONE_PUBLIC bool_t linphone_gtk_is_friend(LinphoneCore *lc, const char *contact); -LINPHONE_PUBLIC gboolean linphone_gtk_auto_answer_enabled(void); -LINPHONE_PUBLIC void linphone_gtk_auto_answer_delay_changed(GtkSpinButton *spinbutton, gpointer user_data); -LINPHONE_PUBLIC void linphone_gtk_update_status_bar_icons(void); -LINPHONE_PUBLIC void linphone_gtk_enable_auto_answer(GtkToggleButton *checkbox, gpointer user_data); - -LINPHONE_PUBLIC void linphone_gtk_import_contacts(void); -LINPHONE_PUBLIC void linphone_gtk_export_contacts(void); - -LINPHONE_PUBLIC void linphone_gtk_mark_chat_read(LinphoneChatRoom *cr); -#ifdef __APPLE__ -LINPHONE_PUBLIC void linphone_gtk_update_badge_count(); -#endif - -LINPHONE_PUBLIC gboolean linphone_gtk_on_key_press(GtkWidget *widget, GdkEvent *event, gpointer user_data); diff --git a/gtk/linphone.ico b/gtk/linphone.ico deleted file mode 100755 index 2633d58f3abe625df023391acf491cbe6beafa6b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 97566 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�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 diff --git a/gtk/linphone.iss b/gtk/linphone.iss deleted file mode 100755 index f69104659..000000000 --- a/gtk/linphone.iss +++ /dev/null @@ -1,90 +0,0 @@ -; Script generated by the Inno Setup Script Wizard. -; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! - -[Setup] -AppName=Linphone -AppVerName=Linphone version 3.1.2 -AppPublisher=linphone.org -AppPublisherURL=http://www.linphone.org -AppSupportURL=http://www.linphone.org -AppUpdatesURL=http://www.linphone.org -DefaultDirName={pf}\Linphone -DefaultGroupName=Linphone -LicenseFile=..\COPYING -;InfoBeforeFile=..\README -OutputBaseFilename=setup -Compression=lzma -SolidCompression=yes - -[Languages] -Name: "english"; MessagesFile: "compiler:Default.isl" - -[Tasks] -Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked - -[Files] -Source: "linphone.exe"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\mediastreamer2\build\win32native\mediastream.exe"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\console\linphonec.exe"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\console\linphonecsh.exe"; DestDir: "{app}"; Flags: ignoreversion -Source: "*.glade"; DestDir: "{app}/linphone"; Flags: ignoreversion -Source: "..\pixmaps\*.png"; DestDir: "{app}/linphone"; Flags: ignoreversion -Source: "*.png"; DestDir: "{app}/linphone"; Flags: ignoreversion -Source: "..\mediastreamer2\src\nowebcamCIF.jpg"; DestDir: "{app}\images"; Flags: ignoreversion -;;internal linphone dlls: -Source: "..\..\linphone-deps\bin\osipparser2.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\..\linphone-deps\bin\osip2.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\..\linphone-deps\bin\exosip2.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\..\linphone-deps\bin\libogg.dll"; DestDir: "{app}"; Flags: ignoreversion -;;Source: "..\..\linphone-deps\bin\speex.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\..\linphone-deps\bin\avcodec.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\..\linphone-deps\bin\avutil-49.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\..\linphone-deps\bin\swscale.dll"; DestDir: "{app}"; Flags: ignoreversion -;;Source: "..\..\linphone-deps\bin\libspeex-1.dll"; DestDir: "{app}"; Flags: ignoreversion -;;Source: "..\..\linphone-deps\bin\libspeexdsp-1.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\coreapi\linphone.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\mediastreamer2\build\win32native\mediastreamer2.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\oRTP\build\win32native\ortp.dll"; DestDir: "{app}"; Flags: ignoreversion -;;Sound files: -Source: "..\COPYING"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\share\ringback.wav"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\share\rings\orig.wav"; DestDir: "{app}\rings"; Flags: ignoreversion -Source: "..\share\rings\bigben.wav"; DestDir: "{app}\rings"; Flags: ignoreversion -Source: "..\share\rings\toy.wav"; DestDir: "{app}\rings"; Flags: ignoreversion -Source: "..\share\rings\tapping.wav"; DestDir: "{app}\rings"; Flags: ignoreversion -Source: "..\share\rings\oldphone.wav"; DestDir: "{app}\rings"; Flags: ignoreversion -;;Default my preferred gtk theme on windows: -Source: "..\gtk-glade\gtkrc"; DestDir: "{app}"; Flags: ignoreversion -;;Locales for linphone: -Source: "..\po\fr.gmo"; DestDir: "{app}\share\locale\fr\LC_MESSAGES"; DestName: "linphone.mo"; Flags: ignoreversion -Source: "..\po\sv.gmo"; DestDir: "{app}\share\locale\sv\LC_MESSAGES"; DestName: "linphone.mo"; Flags: ignoreversion - -;;GTK stuff: -Source: "..\..\gtk+-2.14.7\bin\*.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\..\libglade-2.6.3\bin\*.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\..\gtk+-2.14.7\etc\gtk-2.0\*"; DestDir: "{app}\etc\gtk-2.0\"; Flags: ignoreversion -Source: "..\..\linphone-deps\bin\libxml2.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\..\iconv-1.9.2.win32\bin\*.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\..\gtk+-2.14.7\lib\gtk-2.0\2.10.0\engines\*"; DestDir: "{app}\lib\gtk-2.0\2.10.0\engines"; Flags: ignoreversion -Source: "..\..\gtk+-2.14.7\lib\gtk-2.0\2.10.0\loaders\*"; DestDir: "{app}\lib\gtk-2.0\2.10.0\loaders"; Flags: ignoreversion -;;Source: "..\..\gtk+-2.14.7\lib\gtk-2.0\2.10.0\immodules\*"; DestDir: "{app}\lib\gtk-2.0\2.10.0\immodules"; Flags: ignoreversion -Source: "..\..\gtk+-2.14.7\share\locale\fr\LC_MESSAGES\*"; DestDir: "{app}\share\locale\fr\LC_MESSAGES"; Flags: ignoreversion -Source: "..\..\gtk+-2.14.7\share\locale\sv\LC_MESSAGES\*"; DestDir: "{app}\share\locale\sv\LC_MESSAGES"; Flags: ignoreversion -Source: "..\..\XLiquid_GTK-1.0.3\gtk-2.0\*"; DestDir: "{app}\share\themes\XLiquid_GTK-1.0.3\gtk-2.0"; Flags: ignoreversion -; NOTE: Don't use "Flags: ignoreversion" on any shared system files - -;; BuddyLookup plugin -Source: "..\coreapi\plugins\buddylookup\libbuddylookup.dll"; DestDir: "{app}\liblinphone\plugins"; Flags: ignoreversion -Source: "..\..\libsoup\bin\libsoup-2.4-1.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\..\gnutls-2.6.4\bin\*.dll"; DestDir: "{app}"; Flags: ignoreversion - -;;Directshow capture plugin -Source: "..\mediastreamer2\plugins\msdscap\libmsdscap.dll"; DestDir: "{app}\plugins" ; Flags: ignoreversion - -[Icons] -Name: "{group}\Linphone"; Filename: "{app}\linphone.exe" ; WorkingDir: "{app}" -Name: "{userdesktop}\Linphone"; Filename: "{app}\linphone.exe"; WorkingDir: "{app}" ; Tasks: desktopicon - -[Run] -Filename: "{app}\linphone.exe"; Description: "{cm:LaunchProgram,Linphone}"; WorkingDir: "{app}" ; Flags: nowait postinstall skipifsilent - diff --git a/gtk/linphone.rc b/gtk/linphone.rc deleted file mode 100755 index 9455ab6b3..000000000 --- a/gtk/linphone.rc +++ /dev/null @@ -1,5 +0,0 @@ -// This file is automatically generated by wxDev-C++. -// All changes to this file will be lost when the project is recompiled. - -A ICON MOVEABLE PURE LOADONCALL DISCARDABLE "linphone.ico" - diff --git a/gtk/log.ui b/gtk/log.ui deleted file mode 100644 index 40658b7db..000000000 --- a/gtk/log.ui +++ /dev/null @@ -1,113 +0,0 @@ - - - - - 540 - 290 - False - 5 - Linphone debug window - center-on-parent - normal - False - - - True - False - vertical - 2 - - - True - False - True - spread - - - Scroll to end - True - True - False - False - 0 - False - True - - - - False - True - 0 - - - - - gtk-clear - True - True - True - False - True - - - - False - True - 1 - - - - - gtk-close - True - True - True - False - True - - - - False - True - 2 - - - - - False - True - 0 - - - - - True - True - never - bottom-left - True - in - - - True - True - False - word - - - - - True - True - 1 - - - - - - scroll_to_end - button2 - button1 - - - diff --git a/gtk/logging.c b/gtk/logging.c deleted file mode 100644 index 068428564..000000000 --- a/gtk/logging.c +++ /dev/null @@ -1,373 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "linphone.h" - -#ifdef _WIN32 -#include -#define mkdir _mkdir -#else -#include -#include -#endif - -#ifdef _MSC_VER -#pragma warning(disable : 4996) -#else -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif - -extern gchar *linphone_logfile; - -static GtkWidget *log_window=NULL; -static GStaticMutex log_mutex=G_STATIC_MUTEX_INIT; -static GList *log_queue=NULL; -static const char *dateformat="%Y%m%d-%H:%M:%S"; - -#define LOG_MAX_CHARS 1000000 /*1 mega bytes of traces*/ - -typedef struct _LinphoneGtkLog{ - OrtpLogLevel lev; - gchar *msg; -}LinphoneGtkLog; - - -/****** - * Module to log to a file - ******/ - -/* Marker to insert as a line at the start of every log file */ -#define LOGFILE_MARKER_START "--------" -/* Marker to insert as a line at the end of every log file */ -#define LOGFILE_MARKER_STOP "--------" -/* Number of files to keep in history, log file rotation will be - performed. */ -#define LOGFILE_ROTATION 4 -/* Pointer to opened log file */ -static FILE *_logfile = NULL; - - -/* Called on exit, print out the marker, close the file and avoid to - continue logging. */ -void linphone_gtk_log_uninit(void) -{ - if (_logfile != NULL) { - fprintf(_logfile, "%s\n", LOGFILE_MARKER_STOP); - fclose(_logfile); - _logfile = NULL; - } -} - -/* Called when we start logging, find a good place for the log files, - perform rotation, insert the start marker and return the pointer to - the file that should be used for logging, or NULL on errors or if - disabled. */ -static FILE *linphone_gtk_log_init(void) -{ - static char _logdir[1024]; - static char _logfname[1024]; - static gboolean _log_init = FALSE; - const char *dst_fname=NULL; - - if (!_log_init) { - if (linphone_gtk_get_core()!=NULL){ - dst_fname = linphone_gtk_get_ui_config("logfile",NULL); - dateformat=linphone_gtk_get_ui_config("logfile_date_format",dateformat); - } - /* For anything to happen, we need a logfile configuration variable, - this is our trigger */ - if (dst_fname) { - /* arrange for _logdir to contain a - directory that has been created and _logfname to contain the - path to a file to which we will log */ -#ifdef _WIN32 - const char *appdata=getenv("LOCALAPPDATA"); - if (appdata) { - snprintf(_logdir, sizeof(_logdir),"%s\\Linphone", appdata); - mkdir(_logdir); - } else { - _logdir[0] = '\0'; - } -#define PATH_SEPARATOR '\\' -#else - const char *home=getenv("HOME"); - if (home) { - snprintf(_logdir, sizeof(_logdir),"%s/.linphone", home); - mkdir(_logdir,S_IRUSR | S_IWUSR | S_IRGRP); - } else { - _logdir[0] = '\0'; - } -#define PATH_SEPARATOR '/' -#endif - if (_logdir[0] != '\0') { - /* We have a directory, fix the path to the log file in it and - open the file so that we will be appending to it. */ - snprintf(_logfname, sizeof(_logfname), "%s%c%s",_logdir, PATH_SEPARATOR, dst_fname); - } - }else if (linphone_logfile!=NULL){ - snprintf(_logfname,sizeof(_logfname),"%s",linphone_logfile); - } - - if (_logfname[0]!='\0'){ - /* If the constant LOGFILE_ROTATION is greater than zero, then - we kick away a simple rotation that will ensure that there - are never more than LOGFILE_ROTATION+1 old copies of the - log file on the disk. The oldest file is always rotated - "away" as expected. Rotated files have the same name as - the main log file, though with a number 0..LOGFILE_ROTATION - at the end, where the greater the number is, the older the - file is. */ - if (ortp_file_exist(_logfname)==0 && LOGFILE_ROTATION > 0) { - int i; - char old_fname[1024]; - char new_fname[1024]; - - /* Rotate away existing files. We make sure to remove the - old files otherwise rename() would not work properly. We - have to loop in reverse here. */ - for (i=LOGFILE_ROTATION-1;i>=0;i--) { - snprintf(old_fname, sizeof(old_fname), "%s%c%s.%d", - _logdir, PATH_SEPARATOR, dst_fname, i); - snprintf(new_fname, sizeof(new_fname), "%s%c%s.%d", - _logdir, PATH_SEPARATOR, dst_fname, i+1); - if (ortp_file_exist(old_fname)==0) { - if (ortp_file_exist(new_fname)==0) - unlink(new_fname); - rename(old_fname, new_fname); - } - } - /* Move current log file as the first of the rotation. Make - sure to remove the old .0 also, since otherwise rename() - would not work as expected. */ - snprintf(new_fname, sizeof(new_fname), "%s%c%s.%d", - _logdir, PATH_SEPARATOR, dst_fname, 0); - if (ortp_file_exist(new_fname)==0) - unlink(new_fname); - rename(_logfname, new_fname); - } - /* Start a new log file and mark that we have now initialised */ - _logfile = fopen(_logfname, "w"); - fprintf(_logfile, "%s\n", LOGFILE_MARKER_START); - } - _log_init = TRUE; - } - return _logfile; -} - -static void linphone_gtk_log_file(OrtpLogLevel lev, const char *msg) -{ - FILE *outlog; - - outlog = linphone_gtk_log_init(); - if (outlog != NULL) { - /* We have an opened file and we have initialised properly, it's - time to write all these log messages. We convert the log level - from oRTP into something readable and timestamp each log - message. The format of the time stamp can be controlled by - logfile_date_format in the GtkUi section of the config file, - but it defaults to something compact, but yet readable. */ - const char *lname="undef"; - - /* Convert level constant to text */ - switch(lev){ - case ORTP_DEBUG: - lname="debug "; - break; - case ORTP_MESSAGE: - lname="message"; - break; - case ORTP_WARNING: - lname="warning"; - break; - case ORTP_ERROR: - lname="error "; - break; - case ORTP_FATAL: - lname="fatal "; - break; - default: - lname="undef "; - break; - } - fprintf(outlog, "[%s] %s\n", lname, msg); - fflush(outlog); - } -} - -void linphone_gtk_log_hide(void){ - if (log_window) - gtk_widget_hide(log_window); -} - -void linphone_gtk_create_log_window(void){ - GtkTextBuffer *b; - log_window=linphone_gtk_create_window("log", NULL); - b=gtk_text_view_get_buffer(GTK_TEXT_VIEW(linphone_gtk_get_widget(log_window,"textview"))); - gtk_text_buffer_create_tag(b,"red","foreground","red",NULL); - gtk_text_buffer_create_tag(b,"orange","foreground","orange",NULL); - /*prevent the log window from being destroyed*/ - g_signal_connect (G_OBJECT (log_window), "delete-event", - G_CALLBACK (gtk_widget_hide_on_delete), log_window); -} - -void linphone_gtk_destroy_log_window(void){ - GtkWidget *w=log_window; - g_static_mutex_lock(&log_mutex); - log_window=NULL; - gtk_widget_destroy(w); - g_static_mutex_unlock(&log_mutex); -} - -void linphone_gtk_log_show(void){ - gtk_widget_show(log_window); - gtk_window_present(GTK_WINDOW(log_window)); -} - -static void linphone_gtk_display_log(GtkTextView *v, OrtpLogLevel lev, const char *msg){ - GtkTextIter iter,begin; - int off; - GtkTextBuffer *b; - const char *lname="undef"; - - b=gtk_text_view_get_buffer(v); - switch(lev){ - case ORTP_DEBUG: - lname="debug"; - break; - case ORTP_MESSAGE: - lname="message"; - break; - case ORTP_WARNING: - lname="warning"; - break; - case ORTP_ERROR: - lname="error"; - break; - case ORTP_FATAL: - lname="fatal"; - break; - default: - g_error("Bad level !"); - } - - gtk_text_buffer_get_end_iter(b,&iter); - off=gtk_text_iter_get_offset(&iter); - gtk_text_buffer_insert(b,&iter,lname,-1); - gtk_text_buffer_get_end_iter(b,&iter); - gtk_text_buffer_insert(b,&iter,": ",-1); - gtk_text_buffer_get_end_iter(b,&iter); - gtk_text_buffer_insert(b,&iter,msg,-1); - gtk_text_buffer_get_end_iter(b,&iter); - gtk_text_buffer_insert(b,&iter,"\n",-1); - gtk_text_buffer_get_end_iter(b,&iter); - gtk_text_buffer_get_iter_at_offset(b,&begin,off); - if (lev==ORTP_ERROR || lev==ORTP_FATAL) gtk_text_buffer_apply_tag_by_name(b,"red",&begin,&iter); - else if (lev==ORTP_WARNING) gtk_text_buffer_apply_tag_by_name(b,"orange",&begin,&iter); - - while(gtk_text_buffer_get_char_count(b)>LOG_MAX_CHARS){ - GtkTextIter iter_line_after; - gtk_text_buffer_get_start_iter(b,&iter); - iter_line_after=iter; - if (gtk_text_iter_forward_line(&iter_line_after)){ - gtk_text_buffer_delete(b,&iter,&iter_line_after); - } - } - -} - -static void stick_to_end(GtkTextView *v){ - GtkTextBuffer *b; - GtkTextIter iter; - b=gtk_text_view_get_buffer(v); - gtk_text_buffer_get_end_iter(b,&iter); - gtk_text_view_scroll_to_iter(v,&iter,0,FALSE,1.0,0); -} - -void linphone_gtk_log_scroll_to_end(GtkToggleButton *button) { - if (gtk_toggle_button_get_active(button)){ - GtkTextView *v=GTK_TEXT_VIEW(linphone_gtk_get_widget(log_window,"textview")); - stick_to_end(v); - } - lp_config_set_int(linphone_core_get_config(linphone_gtk_get_core()), "GtkUi", "logs_scroll_to_end", gtk_toggle_button_get_active(button) ? 1 : 0); -} - -/* - * called from Gtk main loop. -**/ -gboolean linphone_gtk_check_logs(void){ - GList *elem; - GtkTextView *v=NULL; - if (log_window) v=GTK_TEXT_VIEW(linphone_gtk_get_widget(log_window,"textview")); - g_static_mutex_lock(&log_mutex); - for(elem=log_queue;elem!=NULL;elem=elem->next){ - LinphoneGtkLog *lgl=(LinphoneGtkLog*)elem->data; - if (v) linphone_gtk_display_log(v,lgl->lev,lgl->msg); - g_free(lgl->msg); - g_free(lgl); - } - if (log_queue) g_list_free(log_queue); - log_queue=NULL; - g_static_mutex_unlock(&log_mutex); - if (v) { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(log_window,"scroll_to_end")), lp_config_get_int(linphone_core_get_config(linphone_gtk_get_core()), "GtkUi", "logs_scroll_to_end", 0) == 1); - linphone_gtk_log_scroll_to_end(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(log_window,"scroll_to_end"))); - } - return TRUE; -} - - -/* - * Called from any linphone thread. - */ -void linphone_gtk_log_push(OrtpLogLevel lev, const char *fmt, va_list args){ - LinphoneGtkLog *lgl=g_new(LinphoneGtkLog,1); - gchar *msg=g_strdup_vprintf(fmt,args); - gchar *dated_msg; - struct timeval tp; - struct tm *lt; - time_t tt; - - ortp_gettimeofday(&tp, NULL); - tt = (time_t)tp.tv_sec; - lt = localtime((const time_t*)&tt); - dated_msg=g_strdup_printf("%i-%.2i-%.2i %.2i:%.2i:%.2i:%.3i %s", - 1900 + lt->tm_year, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec, (int)(tp.tv_usec / 1000), msg); - g_free(msg); - lgl->lev=lev; - lgl->msg=dated_msg; - linphone_gtk_log_file(lev, dated_msg); - g_static_mutex_lock(&log_mutex); - log_queue=g_list_append(log_queue,lgl); - g_static_mutex_unlock(&log_mutex); -} - -void linphone_gtk_log_clear(void){ - if (log_window){ - GtkTextIter end,begin; - GtkTextView *v; - GtkTextBuffer *b; - v=GTK_TEXT_VIEW(linphone_gtk_get_widget(log_window,"textview")); - b=gtk_text_view_get_buffer(v); - gtk_text_buffer_get_start_iter(b,&begin); - gtk_text_buffer_get_end_iter(b,&end); - gtk_text_buffer_delete(b,&begin,&end); - } -} - - diff --git a/gtk/login_frame.ui b/gtk/login_frame.ui deleted file mode 100644 index f65229f14..000000000 --- a/gtk/login_frame.ui +++ /dev/null @@ -1,250 +0,0 @@ - - - - - - False - 0 - etched-out - - - True - False - 12 - - - True - False - - - True - False - gtk-missing-image - - - True - True - 0 - - - - - True - False - 0 - none - - - True - False - 12 - 12 - - - True - False - 5 - 2 - - - - - - True - False - Username - - - - - True - False - Password - - - 1 - 2 - - - - - False - Internet connection: - - - 3 - 4 - - - - - True - True - - True - False - False - True - True - - - 1 - 2 - - - - - True - True - False - - True - False - False - True - True - - - 1 - 2 - 1 - 2 - - - - - False - 0 - - - - 0 - - - - - 1 - 2 - 3 - 4 - - - - - Automatically log me in - True - True - False - True - - - 1 - 2 - 4 - 5 - - - - - False - UserID - - - 2 - 3 - - - - - True - - True - False - False - True - True - - - 1 - 2 - 2 - 3 - - - - - - - - - True - False - Login information - True - - - - - True - True - 10 - 1 - - - - - True - False - - - gtk-connect - True - True - True - True - - - - False - False - 0 - - - - - - - - True - True - 2 - - - - - - - - - True - False - <b>Welcome!</b> - True - - - - - - - - - - - ADSL - - - Fiber Channel - - - - diff --git a/gtk/loginframe.c b/gtk/loginframe.c deleted file mode 100644 index 85174a18b..000000000 --- a/gtk/loginframe.c +++ /dev/null @@ -1,185 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2009 Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "linphone.h" - -void test_button_clicked_cb(GtkWidget *button); -void linphone_gtk_exit_login_frame(void); - - -static void do_login(SipSetupContext *ssctx, const char *identity, const char * passwd, const char *userid){ - if (sip_setup_context_login_account(ssctx,identity,passwd,userid)==0){ - } -} - -static gboolean do_login_noprompt(LinphoneProxyConfig *cfg){ - SipSetupContext *ssctx=linphone_proxy_config_get_sip_setup_context(cfg); - LinphoneAddress *addr; - const char *username; - char *tmp; - if (ssctx==NULL) return TRUE;/*not ready ?*/ - username=linphone_gtk_get_ui_config ("login_username",NULL); - if (username==NULL) { - linphone_gtk_show_login_frame(cfg,TRUE); - return FALSE; - } - addr=linphone_address_clone(linphone_proxy_config_get_identity_address(cfg)); - linphone_address_set_username(addr,username); - tmp=linphone_address_as_string (addr); - do_login(ssctx,tmp,NULL,NULL); - linphone_address_unref(addr); - linphone_gtk_load_identities(); - return FALSE; -} - -static void linphone_gtk_init_login_frame(GtkWidget *login_frame, LinphoneProxyConfig *cfg) { - gboolean auto_login=linphone_gtk_get_ui_config_int("automatic_login",0); - const char *login_image=linphone_gtk_get_ui_config("login_image","linphone-banner.png"); - GtkWidget *label=linphone_gtk_get_widget(login_frame,"login_label"); - LinphoneCore *lc=linphone_gtk_get_core(); - gchar *str; - LinphoneAddress *from; - const LinphoneAuthInfo *ai; - const char *passwd=NULL; - const char *userid=NULL; - - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(login_frame, "automatic_login")),auto_login); - - if (login_image){ - GdkPixbuf *pbuf=create_pixbuf (login_image); - gtk_image_set_from_pixbuf (GTK_IMAGE(linphone_gtk_get_widget(login_frame, "login_image")), pbuf); - g_object_unref(G_OBJECT(pbuf)); - } - - if (linphone_gtk_get_ui_config_int("login_needs_userid",FALSE)){ - gtk_widget_show(linphone_gtk_get_widget(login_frame,"userid")); - gtk_widget_show(linphone_gtk_get_widget(login_frame,"login_userid")); - } - - str=g_strdup_printf(_("Please enter login information for %s"),linphone_proxy_config_get_domain(cfg)); - gtk_label_set_text(GTK_LABEL(label),str); - g_object_set_data(G_OBJECT(login_frame),"login_proxy_config",cfg); - g_free(str); - - from=linphone_address_new(linphone_proxy_config_get_identity(cfg)); - if (linphone_address_get_username(from)[0]=='?'){ - const char *username=linphone_gtk_get_ui_config ("login_username",NULL); - if (username) - linphone_address_set_username(from,username); - } - - ai=linphone_core_find_auth_info(lc,linphone_proxy_config_get_domain(cfg),linphone_address_get_username(from),NULL); - /*display the last entered username, if not '?????'*/ - if (linphone_address_get_username(from)[0]!='?') - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(login_frame,"login_username")), - linphone_address_get_username(from)); - if (ai) { - passwd=linphone_auth_info_get_passwd(ai); - userid=linphone_auth_info_get_userid(ai); - } - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(login_frame,"login_password")), - passwd!=NULL ? passwd : ""); - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(login_frame,"login_userid")), - userid ? userid : ""); - - linphone_address_unref(from); -} - -void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg, gboolean disable_auto_login){ - GtkWidget *mw=linphone_gtk_get_main_window(); - gboolean auto_login=linphone_gtk_get_ui_config_int("automatic_login",0); - GtkWidget *main_frame = linphone_gtk_get_widget(mw, "main_frame"); - GtkWidget *main_layout = linphone_gtk_get_widget(mw, "main_layout"); - GtkWidget *login_frame; - - if (auto_login && !disable_auto_login){ - g_timeout_add(250,(GSourceFunc)do_login_noprompt,cfg); - return; - } - - login_frame = linphone_gtk_create_widget("login_frame"); - linphone_gtk_init_login_frame(login_frame, cfg); - g_object_set_data_full(G_OBJECT(mw), "main_frame", g_object_ref(main_frame), g_object_unref); - g_object_set_data(G_OBJECT(mw), "login_frame", login_frame); - gtk_container_remove(GTK_CONTAINER(main_layout), main_frame); - gtk_box_pack_start(GTK_BOX(main_layout), login_frame, TRUE, TRUE, 0); - gtk_widget_show(login_frame); - - gtk_widget_hide(linphone_gtk_get_widget(mw,"disconnect_item")); - gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"options_menu"),FALSE); -} - -void linphone_gtk_exit_login_frame(void){ - GtkWidget *mw=linphone_gtk_get_main_window(); - GtkWidget *main_layout = linphone_gtk_get_widget(mw, "main_layout"); - GtkWidget *main_frame = GTK_WIDGET(g_object_get_data(G_OBJECT(mw), "main_frame")); - GtkWidget *login_frame = GTK_WIDGET(g_object_get_data(G_OBJECT(mw), "login_frame")); - - gtk_container_remove(GTK_CONTAINER(main_layout), login_frame); - gtk_box_pack_start(GTK_BOX(main_layout), main_frame, TRUE, TRUE, 0); - g_object_set_data(G_OBJECT(mw), "login_frame", NULL); - g_object_set_data(G_OBJECT(mw), "main_frame", NULL); - - gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"options_menu"),TRUE); - gtk_widget_show(linphone_gtk_get_widget(mw,"disconnect_item")); -} - -void linphone_gtk_logout_clicked(void){ - LinphoneCore *lc=linphone_gtk_get_core(); - LinphoneProxyConfig *cfg=NULL; - cfg = linphone_core_get_default_proxy_config(lc); - if (cfg){ - SipSetupContext *ss=linphone_proxy_config_get_sip_setup_context(cfg); - if (ss){ - sip_setup_context_logout(ss); - linphone_gtk_show_login_frame(cfg,TRUE); - } - } -} - - - -void linphone_gtk_login_frame_connect_clicked(GtkWidget *button, GtkWidget *login_frame){ - const char *username; - const char *password; - const char *userid; - char *identity; - gboolean autologin; - LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)g_object_get_data(G_OBJECT(login_frame),"login_proxy_config"); - LinphoneAddress *from; - SipSetupContext *ssctx=linphone_proxy_config_get_sip_setup_context(cfg); - - username=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(login_frame,"login_username"))); - password=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(login_frame,"login_password"))); - userid=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(login_frame,"login_userid"))); - - if (username==NULL || username[0]=='\0') - return; - - autologin=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(login_frame,"automatic_login"))); - linphone_gtk_set_ui_config_int("automatic_login",autologin); - linphone_gtk_set_ui_config("login_username",username); - - from=linphone_address_new(linphone_proxy_config_get_identity(cfg)); - linphone_address_set_username(from,username); - identity=linphone_address_as_string(from); - do_login(ssctx,identity,password,userid); - /*we need to refresh the identities since the proxy config may have changed.*/ - linphone_gtk_load_identities(); -} diff --git a/gtk/mac.m b/gtk/mac.m deleted file mode 100644 index 7a45d0d48..000000000 --- a/gtk/mac.m +++ /dev/null @@ -1,47 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifdef __APPLE__ - -#import -#import "linphone.h" - - -static int unread_messages_count() { - LinphoneCore* lc = linphone_gtk_get_core(); - int count = 0; - const MSList *rooms = linphone_core_get_chat_rooms(lc); - const MSList *item = rooms; - while (item) { - LinphoneChatRoom *room = (LinphoneChatRoom *)item->data; - if (room) { - count += linphone_chat_room_get_unread_messages_count(room); - } - item = item->next; - } - return count; -} - -void linphone_gtk_update_badge_count() { - int count = unread_messages_count(); - NSString* badgeStr = (count > 0) ? [NSString stringWithFormat:@"%d", count] : @""; - [[NSApp dockTile] setBadgeLabel:badgeStr]; -} - -#endif diff --git a/gtk/main.c b/gtk/main.c deleted file mode 100644 index 579fc8296..000000000 --- a/gtk/main.c +++ /dev/null @@ -1,2383 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#define VIDEOSELFVIEW_DEFAULT 0 - -#include "linphone.h" -#include "linphone/lpconfig.h" -#include "liblinphone_gitversion.h" -#include -#include - -#include -#include -#ifndef _WIN32 -#include -#endif - -#ifdef HAVE_GTK_OSX -#include -#endif - -#ifdef _WIN32 -#include "direct.h" -#define chdir _chdir -#ifndef F_OK -#define F_OK 00 /*visual studio does not define F_OK*/ -#endif -#endif - -#if defined(HAVE_NOTIFY1) || defined(HAVE_NOTIFY4) -#define HAVE_NOTIFY -#endif - -#ifdef HAVE_NOTIFY -#include -#endif - -#ifdef ENABLE_NLS -#include -#endif - -#include "status_icon.h" - - -const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION; - -static LinphoneCore *the_core=NULL; -static GtkWidget *the_ui=NULL; -static LinphoneLDAPContactProvider* ldap_provider = NULL; - -static void linphone_gtk_global_state_changed(LinphoneCore *lc, LinphoneGlobalState state, const char*str); -static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState rs, const char *msg); -static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid); -static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url); -static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain); -static void linphone_gtk_configuring_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message); -static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl); -static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg); -static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token); -static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate); -static void linphone_gtk_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf); -void linphone_gtk_save_main_window_position(GtkWindow* mw, GdkEvent *event, gpointer data); -static gboolean linphone_gtk_auto_answer(LinphoneCall *call); -void linphone_gtk_status_icon_set_blinking(gboolean val); -void _linphone_gtk_enable_video(gboolean val); -void linphone_gtk_on_uribar_changed(GtkEditable *uribar, gpointer user_data); -static void linphone_gtk_init_ui(void); -static void linphone_gtk_quit(void); - -#ifndef HAVE_GTK_OSX -static gint main_window_x=0; -static gint main_window_y=0; -#endif -static gboolean verbose=0; -static gboolean quit_done=FALSE; -static gchar * addr_to_call = NULL; -static int start_option = START_LINPHONE; -static gboolean no_video=FALSE; -static gboolean iconified=FALSE; -static gboolean run_audio_assistant=FALSE; -static gboolean version=FALSE; -static gboolean selftest=FALSE; -static gchar *workingdir=NULL; -static char *progpath=NULL; -gchar *linphone_logfile=NULL; -static gboolean workaround_gtk_entry_chinese_bug=FALSE; -static gchar *custom_config_file=NULL; -static gboolean restart=FALSE; -static GtkWidget *config_fetching_dialog=NULL; - -#if _MSC_VER - -#define LINPHONE_OPTION(optlname, optsname, optarg, optargdata, optdesc) \ -{ \ - optlname, \ - optsname, \ - 0, \ - optarg, \ - optargdata, \ - optdesc, \ - NULL \ -} - -#else - -#define LINPHONE_OPTION(optlname, optsname, optarg, optargdata, optdesc) \ -{ \ - .long_name = optlname, \ - .short_name = optsname, \ - .arg = optarg, \ - .arg_data = optargdata, \ - .description = optdesc, \ -} - -#endif - -static GOptionEntry linphone_options[]={ - LINPHONE_OPTION("verbose", '\0', G_OPTION_ARG_NONE, (gpointer)&verbose, N_("log to stdout some debug information while running.")), - LINPHONE_OPTION("version", '\0', G_OPTION_ARG_NONE, (gpointer)&version, N_("display version and exit.")), - LINPHONE_OPTION("logfile", 'l', G_OPTION_ARG_STRING, &linphone_logfile, N_("path to a file to write logs into.")), - LINPHONE_OPTION("no-video", '\0', G_OPTION_ARG_NONE, (gpointer)&no_video, N_("Start linphone with video disabled.")), - LINPHONE_OPTION("iconified", '\0', G_OPTION_ARG_NONE, (gpointer)&iconified, N_("Start only in the system tray, do not show the main interface.")), - LINPHONE_OPTION("call", 'c', G_OPTION_ARG_STRING, &addr_to_call, N_("address to call right now")), - LINPHONE_OPTION("workdir", '\0', G_OPTION_ARG_STRING, (gpointer) & workingdir, N_("Specifiy a working directory (should be the base of the installation, eg: c:\\Program Files\\Linphone)")), - LINPHONE_OPTION("config", '\0', G_OPTION_ARG_FILENAME, (gpointer) &custom_config_file, N_("Configuration file")), - LINPHONE_OPTION("run-audio-assistant", '\0', G_OPTION_ARG_NONE, (gpointer) &run_audio_assistant, N_("Run the audio assistant")), - LINPHONE_OPTION("selftest", '\0', G_OPTION_ARG_NONE, (gpointer) &selftest, N_("Run self test and exit 0 if succeed")), - {0} -}; - -#define RELATIVE_XML_DIR -#define BUILD_TREE_XML_DIR "gtk" - -#ifndef _WIN32 -#define CONFIG_FILE ".linphonerc" -#define SECRETS_FILE ".linphone-zidcache" -#define CERTIFICATES_PATH ".linphone-usr-crt" -#else -#define CONFIG_FILE "linphonerc" -#define SECRETS_FILE "linphone-zidcache" -#define CERTIFICATES_PATH "linphone-usr-crt" -#endif - -char *linphone_gtk_get_config_file(const char *filename){ - const int path_max=1024; - char *config_file=g_malloc0(path_max); - if (filename==NULL) filename=CONFIG_FILE; - if (g_path_is_absolute(filename)) { - snprintf(config_file,path_max,"%s",filename); - } else{ -#ifdef _WIN32 - const char *appdata=getenv("APPDATA"); - if (appdata){ - snprintf(config_file,path_max,"%s\\%s",appdata,LINPHONE_CONFIG_DIR); - CreateDirectory(config_file,NULL); - snprintf(config_file,path_max,"%s\\%s\\%s",appdata,LINPHONE_CONFIG_DIR,filename); - } -#else - const char *home=getenv("HOME"); - if (home==NULL) home="."; - snprintf(config_file,path_max,"%s/%s",home,filename); -#endif - } - return config_file; -} - -#define FACTORY_CONFIG_FILE "linphonerc.factory" -static char _factory_config_file[1024]; -static const char *linphone_gtk_get_factory_config_file(void){ - char* path = NULL; - /*try accessing a local file first if exists*/ - if (bctbx_file_exist(FACTORY_CONFIG_FILE)==0){ - path = ms_strdup(FACTORY_CONFIG_FILE); - } else { - char *progdir; - - if (progpath != NULL) { - char *basename; - progdir = strdup(progpath); -#ifdef _WIN32 - basename = strrchr(progdir, '\\'); - if (basename != NULL) { - basename ++; - *basename = '\0'; - path = ms_strdup_printf("%s\\..\\%s", progdir, FACTORY_CONFIG_FILE); - } else if (workingdir!=NULL) { - path = ms_strdup_printf("%s\\%s", workingdir, FACTORY_CONFIG_FILE); - } -#else - basename = strrchr(progdir, '/'); - if (basename != NULL) { - basename ++; - *basename = '\0'; - path = ms_strdup_printf("%s/../share/linphone/%s", progdir, FACTORY_CONFIG_FILE); - } -#endif - free(progdir); - } - } - if (path) { - ms_message("Factory config file expected at %s", path); - //use factory file only if it exists - if (bctbx_file_exist(path)==0){ - snprintf(_factory_config_file, sizeof(_factory_config_file), "%s", path); - ms_free(path); - return _factory_config_file; - } - ms_free(path); - } - return NULL; -} - -LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void){ - return ldap_provider; -} - -int linphone_gtk_is_ldap_supported(void){ - return linphone_ldap_contact_provider_available(); -} - -void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap) -{ - if( ldap_provider ) - linphone_contact_provider_unref(ldap_provider); - - ldap_provider = ldap ? linphone_ldap_contact_provider_ref( ldap ) - : NULL; -} - -void linphone_gtk_schedule_restart(void){ - restart=TRUE; -} - -gboolean linphone_gtk_get_audio_assistant_option(void){ - return run_audio_assistant; -} - -static void linphone_gtk_init_liblinphone(const char *config_file, - const char *factory_config_file, const char *chat_messages_db_file, - const char *call_logs_db_file, const char *friends_db_file) { - LinphoneCoreVTable vtable={0}; - gchar *secrets_file=linphone_gtk_get_config_file(SECRETS_FILE); - gchar *user_certificates_dir=linphone_gtk_get_config_file(CERTIFICATES_PATH); - MSFactory *msfactory = NULL; - MSFilterDesc *ogl_filter_desc; - - vtable.global_state_changed=linphone_gtk_global_state_changed; - vtable.call_state_changed=linphone_gtk_call_state_changed; - vtable.registration_state_changed=linphone_gtk_registration_state_changed; - vtable.notify_presence_received=linphone_gtk_notify_recv; - vtable.new_subscription_requested=linphone_gtk_new_unknown_subscriber; - vtable.auth_info_requested=linphone_gtk_auth_info_requested; - vtable.call_log_updated=linphone_gtk_call_log_updated; - vtable.message_received=linphone_gtk_text_received; - vtable.is_composing_received=linphone_gtk_is_composing_received; - vtable.refer_received=linphone_gtk_refer_received; - vtable.buddy_info_updated=linphone_gtk_buddy_info_updated; - vtable.call_encryption_changed=linphone_gtk_call_encryption_changed; - vtable.transfer_state_changed=linphone_gtk_transfer_state_changed; - vtable.dtmf_received=linphone_gtk_dtmf_received; - vtable.configuring_status=linphone_gtk_configuring_status; - - the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL); - linphone_core_migrate_to_multi_transport(the_core); - //lp_config_set_int(linphone_core_get_config(the_core), "sip", "store_auth_info", 0); - - - if( lp_config_has_section(linphone_core_get_config(the_core),"ldap") ){ - LpConfig* cfg = linphone_core_get_config(the_core); - LinphoneDictionary* ldap_cfg = lp_config_section_to_dict(cfg, "ldap"); - linphone_gtk_set_ldap( linphone_ldap_contact_provider_create(the_core, ldap_cfg) ); - } - - linphone_core_set_user_agent(the_core,"Linphone", LINPHONE_VERSION); - linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL); - linphone_core_set_zrtp_secrets_file(the_core,secrets_file); /* XML cache is superseeded by the sqlite one, keep it for migration purpose but it shall be removed in future version */ - g_free(secrets_file); - linphone_core_set_user_certificates_path(the_core,user_certificates_dir); - g_free(user_certificates_dir); - linphone_core_enable_video_capture(the_core, TRUE); - linphone_core_enable_video_display(the_core, TRUE); - linphone_core_set_native_video_window_id(the_core,LINPHONE_VIDEO_DISPLAY_NONE);/*don't create the window*/ - if (no_video) { - _linphone_gtk_enable_video(FALSE); - linphone_gtk_set_ui_config_int("videoselfview",0); - } - if (chat_messages_db_file) linphone_core_set_chat_database_path(the_core,chat_messages_db_file); - if (call_logs_db_file) linphone_core_set_call_logs_database_path(the_core, call_logs_db_file); - if (friends_db_file) linphone_core_set_friends_database_path(the_core, friends_db_file); - - // Disable the generic OpenGL displaying filter - msfactory = linphone_core_get_ms_factory(the_core); - ogl_filter_desc = ms_factory_lookup_filter_by_id(msfactory, MS_OGL_ID); - if (ogl_filter_desc != NULL) ogl_filter_desc->flags &= ~MS_FILTER_IS_ENABLED; -} - -LinphoneCore *linphone_gtk_get_core(void){ - return the_core; -} - -GtkWidget *linphone_gtk_get_main_window(void){ - return the_ui; -} - -void linphone_gtk_destroy_main_window(void) { - linphone_gtk_destroy_window(the_ui); - the_ui = NULL; -} - -static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name){ - static const char *hiddens=NULL; - static const char *shown=NULL; - static bool_t config_loaded=FALSE; - if (linphone_gtk_get_core()==NULL) return; - if (config_loaded==FALSE){ - hiddens=linphone_gtk_get_ui_config("hidden_widgets",NULL); - shown=linphone_gtk_get_ui_config("shown_widgets",NULL); - config_loaded=TRUE; - } - if (hiddens) linphone_gtk_visibility_set(hiddens,window_name,w,FALSE); - if (shown) linphone_gtk_visibility_set(shown,window_name,w,TRUE); -} - -static int get_ui_file(const char *name, char *path, int pathsize){ - snprintf(path,pathsize,"%s/%s.ui",BUILD_TREE_XML_DIR,name); - if (bctbx_file_exist(path)!=0){ - LinphoneFactory *factory = linphone_factory_get(); - const char *data_dir = linphone_factory_get_data_resources_dir(factory); - snprintf(path,pathsize,"%s/%s.ui",data_dir,name); - if (bctbx_file_exist(path)!=0){ - g_error("Could not locate neither %s/%s.ui nor %s/%s.ui",BUILD_TREE_XML_DIR,name,data_dir,name); - return -1; - } - } - return 0; -} - -void linphone_gtk_destroy_window(GtkWidget *widget) { - GtkBuilder* builder = g_object_get_data(G_OBJECT(widget), "builder"); - gtk_widget_destroy(widget); - g_object_unref (G_OBJECT (builder)); -} - -GtkWidget *linphone_gtk_create_widget(const char *widget_name) { - char path[2048]; - GtkBuilder *builder = gtk_builder_new(); - GError *error = NULL; - GObject *obj; - - if(get_ui_file(widget_name, path, sizeof(path)) == -1) goto fail; - - gtk_builder_set_translation_domain(builder, GETTEXT_PACKAGE); - - if(gtk_builder_add_from_file(builder, path, &error) == 0) { - g_error("Couldn't load builder file: %s", error->message); - g_error_free(error); - goto fail; - } - - obj = gtk_builder_get_object(builder, widget_name); - if(obj == NULL) { - g_error("'%s' widget not found", widget_name); - goto fail; - } - g_object_set_data(G_OBJECT(obj), "builder", builder); - g_signal_connect_data(G_OBJECT(obj),"destroy",(GCallback)g_object_unref,builder, NULL, G_CONNECT_AFTER|G_CONNECT_SWAPPED); - gtk_builder_connect_signals(builder, obj); - - return GTK_WIDGET(obj); - -fail: - g_object_unref(builder); - return NULL; -} - -GtkWidget *linphone_gtk_create_window(const char *window_name, GtkWidget *parent){ - GtkWidget *w = linphone_gtk_create_widget(window_name); - if(w) { - linphone_gtk_configure_window(w,window_name); - if(parent) { - gtk_window_set_transient_for(GTK_WINDOW(w), GTK_WINDOW(parent)); - gtk_window_set_position(GTK_WINDOW(w), GTK_WIN_POS_CENTER_ON_PARENT); - } - } - return w; -} - -static void entry_unmapped(GtkWidget *widget){ - ms_message("%s is unmapped, calling unrealize to workaround chinese bug.",G_OBJECT_TYPE_NAME(widget)); - gtk_widget_unrealize(widget); -} - -GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){ - GtkBuilder *builder; - GObject *w; - if (window==NULL) return NULL; - builder=(GtkBuilder*)g_object_get_data(G_OBJECT(window),"builder"); - if (builder==NULL){ - g_error("Fail to retrieve builder from window !"); - return NULL; - } - w=gtk_builder_get_object(builder,name); - if (w==NULL){ - g_error("No widget named %s found in xml interface.",name); - } - if (workaround_gtk_entry_chinese_bug){ - if (strcmp(G_OBJECT_TYPE_NAME(w),"GtkEntry")==0 || strcmp(G_OBJECT_TYPE_NAME(w),"GtkTextView")==0){ - if (g_object_get_data(G_OBJECT(w),"entry_bug_workaround")==NULL){ - g_object_set_data(G_OBJECT(w),"entry_bug_workaround",GINT_TO_POINTER(1)); - ms_message("%s is a %s",name,G_OBJECT_TYPE_NAME(w)); - g_signal_connect(G_OBJECT(w),"unmap",(GCallback)entry_unmapped,NULL); - } - } - } - return GTK_WIDGET(w); -} - - -void linphone_gtk_display_something(GtkMessageType type,const gchar *message){ - GtkWidget *dialog; - GtkWidget *main_window=linphone_gtk_get_main_window(); - - gtk_widget_show(main_window); - if (type==GTK_MESSAGE_QUESTION) - { - /* draw a question box. link to dialog_click callback */ - dialog = gtk_message_dialog_new ( - GTK_WINDOW(main_window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_YES_NO, - "%s", - (const gchar*)message); - /* connect to some callback : REVISIT */ - /* - g_signal_connect_swapped (G_OBJECT (dialog), "response", - G_CALLBACK (dialog_click), - G_OBJECT (dialog)); - */ - /* actually show the box */ - gtk_widget_show(dialog); - } - else - { - dialog = gtk_message_dialog_new (GTK_WINDOW(main_window), - GTK_DIALOG_DESTROY_WITH_PARENT, - type, - GTK_BUTTONS_CLOSE, - "%s", - (const gchar*)message); - /* Destroy the dialog when the user responds to it (e.g. clicks a button) */ - g_signal_connect_swapped (G_OBJECT (dialog), "response", - G_CALLBACK (gtk_widget_destroy), - G_OBJECT (dialog)); - gtk_widget_show(dialog); - } -} - -void linphone_gtk_about_response(GtkDialog *dialog, gint id){ - if (id==GTK_RESPONSE_CANCEL){ - gtk_widget_destroy(GTK_WIDGET(dialog)); - } -} - -static void about_url_clicked(GtkAboutDialog *dialog, const char *url, gpointer data){ - g_message("About url clicked"); - linphone_gtk_open_browser(url); -} - -void linphone_gtk_show_about(void){ - struct stat filestat; - const char *data_dir; - char *license_file; - GtkWidget *about; - const char *tmp; - GdkPixbuf *logo=create_pixbuf( - linphone_gtk_get_ui_config("logo","linphone-banner.png")); - static const char *defcfg="defcfg"; - LinphoneFactory *factory = linphone_factory_get(); - - about=linphone_gtk_create_window("about", the_ui); - - gtk_about_dialog_set_url_hook(about_url_clicked,NULL,NULL); - - data_dir = linphone_factory_get_data_resources_dir(factory); - license_file = bctbx_strdup_printf("%s/COPYING", data_dir); - memset(&filestat,0,sizeof(filestat)); - if (stat(license_file,&filestat)!=0){ - license_file="COPYING"; - stat(license_file,&filestat); - } - if (filestat.st_size>0){ - char *license=g_malloc(filestat.st_size+1); - FILE *f=fopen(license_file,"r"); - if (f && fread(license,1,filestat.st_size,f)>0){ - license[filestat.st_size]='\0'; - gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about),license); - } - g_free(license); - } - bctbx_free(license_file); - gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),linphone_core_get_version()); - gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("title","Linphone")); - gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("home","http://www.linphone.org")); - if (logo) { - gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), logo); - g_object_unref(logo); - } - tmp=linphone_gtk_get_ui_config("artists",defcfg); - if (tmp!=defcfg){ - const char *tmp2[2]; - tmp2[0]=tmp; - tmp2[1]=NULL; - gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about),tmp2); - } - tmp=linphone_gtk_get_ui_config("translators",defcfg); - if (tmp!=defcfg) - gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG(about),tmp); - tmp=linphone_gtk_get_ui_config("comments",defcfg); - if (tmp!=defcfg) - gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about),tmp); - gtk_widget_show(about); -} - - -static gboolean linphone_gtk_iterate(LinphoneCore *lc){ - static gboolean first_time=TRUE; - static gboolean in_iterate=FALSE; - - /*avoid reentrancy*/ - if (in_iterate) return TRUE; - in_iterate=TRUE; - linphone_core_iterate(lc); - if (first_time){ - /*after the first call to iterate, SipSetupContexts should be ready, so take actions:*/ - linphone_gtk_show_directory_search(); - first_time=FALSE; - } - - if (addr_to_call!=NULL){ - /*make sure we are not showing the login screen*/ - GtkWidget *mw=linphone_gtk_get_main_window(); - if (g_object_get_data(G_OBJECT(mw), "login_frame") == NULL){ - GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar"); - gtk_entry_set_text(GTK_ENTRY(uri_bar),addr_to_call); - addr_to_call=NULL; - linphone_gtk_start_call(uri_bar); - } - } - in_iterate=FALSE; - return TRUE; -} - -static gboolean uribar_completion_matchfunc(GtkEntryCompletion *completion, const gchar *key, GtkTreeIter *iter, gpointer user_data){ - char* address = NULL; - gboolean ret = FALSE; - gtk_tree_model_get(gtk_entry_completion_get_model(completion),iter,0,&address,-1); - - if(address) { - gchar *tmp = g_utf8_casefold(address,-1); - if (strstr(tmp,key)) ret=TRUE; - g_free(tmp); - g_free(address); - } - - return ret; -} - -static void load_uri_history(void){ - GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")); - char key[20]; - int i; - GtkEntryCompletion *gep=gtk_entry_completion_new(); - GtkListStore *model=gtk_list_store_new(2,G_TYPE_STRING,G_TYPE_INT); - for (i=0;;i++){ - const char *uri; - snprintf(key,sizeof(key),"uri%i",i); - uri=linphone_gtk_get_ui_config(key,NULL); - if (uri!=NULL) { - GtkTreeIter iter; - gtk_list_store_append(model,&iter); - gtk_list_store_set(model,&iter,0,uri,1,COMPLETION_HISTORY,-1); - if (i==0) gtk_entry_set_text(uribar,uri); - } - else break; - } - gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model)); - gtk_entry_completion_set_text_column(gep,0); - gtk_entry_completion_set_popup_completion(gep, TRUE); - gtk_entry_completion_set_match_func(gep,uribar_completion_matchfunc, NULL, NULL); - gtk_entry_completion_set_minimum_key_length(gep,3); - gtk_entry_set_completion(uribar,gep); - g_signal_connect (G_OBJECT (uribar), "changed", G_CALLBACK(linphone_gtk_on_uribar_changed), NULL); -} - -static void save_uri_history(void){ - LinphoneCore *lc=linphone_gtk_get_core(); - LpConfig *cfg=linphone_core_get_config(lc); - GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")); - char key[20]; - int i=0; - char *uri=NULL; - GtkTreeIter iter; - GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(uribar)); - - if (!gtk_tree_model_get_iter_first(model,&iter)) return; - do { - gtk_tree_model_get(model,&iter,0,&uri,-1); - if (uri) { - snprintf(key,sizeof(key),"uri%i",i); - lp_config_set_string(cfg,"GtkUi",key,uri); - g_free(uri); - }else break; - i++; - if (i>5) break; - }while(gtk_tree_model_iter_next(model,&iter)); - lp_config_sync(cfg); -} - -static void completion_add_text(GtkEntry *entry, const char *text){ - GtkTreeIter iter; - GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(entry)); - - if (gtk_tree_model_get_iter_first(model,&iter)){ - do { - gchar *uri=NULL; - gtk_tree_model_get(model,&iter,0,&uri,-1); - if (uri!=NULL){ - if (strcmp(uri,text)==0) { - /*remove text */ - gtk_list_store_remove(GTK_LIST_STORE(model),&iter); - g_free(uri); - break; - } - g_free(uri); - } - }while (gtk_tree_model_iter_next(model,&iter)); - } - /* and prepend it on top of the list */ - gtk_list_store_prepend(GTK_LIST_STORE(model),&iter); - gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,1,COMPLETION_HISTORY,-1); - save_uri_history(); -} - -void on_contact_provider_search_results( LinphoneContactSearch* req, bctbx_list_t* friends, void* data ) -{ - GtkTreeIter iter; - GtkEntry* uribar = GTK_ENTRY(data); - GtkEntryCompletion* compl = gtk_entry_get_completion(uribar); - GtkTreeModel* model = gtk_entry_completion_get_model(compl); - GtkListStore* list = GTK_LIST_STORE(model); - LinphoneLDAPContactSearch* search = linphone_ldap_contact_search_cast(req); - gboolean valid; - - // clear completion list from previous non-history entries - valid = gtk_tree_model_get_iter_first(model,&iter); - while(valid) - { - char* url; - int type; - gtk_tree_model_get(model,&iter, 0,&url, 1,&type, -1); - - if (type != COMPLETION_HISTORY) { - valid = gtk_list_store_remove(list, &iter); - } else { - valid = gtk_tree_model_iter_next(model,&iter); - } - - if( url ) g_free(url); - if( !valid ) break; - } - - // add new non-history related matches - while( friends ){ - LinphoneFriend* lf = friends->data; - if( lf ) { - const LinphoneAddress* la = linphone_friend_get_address(lf); - if( la ){ - char *addr = linphone_address_as_string(la); - - if( addr ){ - ms_message("[LDAP]Insert match: %s", addr); - gtk_list_store_insert_with_values(list, &iter, -1, - 0, addr, - 1, COMPLETION_LDAP, -1); - ms_free(addr); - } - } - } - friends = friends->next; - } - gtk_entry_completion_complete(compl); - // save the number of LDAP results to better decide if new results should be fetched when search predicate gets bigger - gtk_object_set_data(GTK_OBJECT(uribar), "ldap_res_cout", - GINT_TO_POINTER( - linphone_ldap_contact_search_result_count(search) - ) - ); - - // Gtk bug? we need to emit a "changed" signal so that the completion appears if - // the list of results was previously empty - g_signal_handlers_block_by_func(uribar, linphone_gtk_on_uribar_changed, NULL); - g_signal_emit_by_name(uribar, "changed"); - g_signal_handlers_unblock_by_func(uribar, linphone_gtk_on_uribar_changed, NULL); -} - -struct CompletionTimeout { - guint timeout_id; -}; - -static gboolean launch_contact_provider_search(void *userdata) -{ - LinphoneLDAPContactProvider* ldap = linphone_gtk_get_ldap(); - GtkWidget* uribar = GTK_WIDGET(userdata); - const gchar* predicate = gtk_entry_get_text(GTK_ENTRY(uribar)); - gchar* previous_search = gtk_object_get_data(GTK_OBJECT(uribar), "previous_search"); - unsigned int prev_res_count = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(uribar), "ldap_res_cout")); - - if( ldap && strlen(predicate) >= 3 ){ // don't search too small predicates - unsigned int max_res_count = linphone_ldap_contact_provider_get_max_result(ldap); - LinphoneContactSearch* search; - if( previous_search && - (strstr(predicate, previous_search) == predicate) && // last search contained results from this one - (prev_res_count != max_res_count) ){ // and we didn't reach the max result limit - - ms_message("Don't launch search on already searched data (current: %s, old search: %s), (%d/%d results)", - predicate, previous_search, prev_res_count, max_res_count); - return FALSE; - } - - // save current search - if( previous_search ) ms_free(previous_search); - gtk_object_set_data(GTK_OBJECT(uribar), "previous_search", ms_strdup(predicate)); - - ms_message("launch_contact_provider_search"); - search =linphone_contact_provider_begin_search( - linphone_contact_provider_cast(ldap_provider), - predicate, on_contact_provider_search_results, uribar - ); - - if(search) - linphone_contact_search_ref(search); - } - return FALSE; -} - -void linphone_gtk_on_uribar_changed(GtkEditable *uribar, gpointer user_data) -{ - if( linphone_gtk_get_ldap() ) { - gchar* text = gtk_editable_get_chars(uribar, 0,-1); - gint timeout = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(uribar), "complete_timeout")); - if( text ) g_free(text); - - if( timeout != 0 ) { - g_source_remove(timeout); - } - - timeout = g_timeout_add_seconds(1,(GSourceFunc)launch_contact_provider_search, uribar); - - gtk_object_set_data(GTK_OBJECT(uribar),"complete_timeout", GINT_TO_POINTER(timeout) ); - } -} - -bool_t linphone_gtk_video_enabled(void){ - const LinphoneVideoPolicy *vpol=linphone_core_get_video_policy(linphone_gtk_get_core()); - return vpol->automatically_accept && vpol->automatically_initiate; -} - -void linphone_gtk_show_main_window(){ - GtkWidget *w=linphone_gtk_get_main_window(); -#ifdef HAVE_GTK_OSX - GtkWidget *icon = linphone_gtk_get_widget(w, "history_tab_icon"); - GtkWidget *label = linphone_gtk_get_widget(w, "history_tab_label"); - gtk_misc_set_alignment(GTK_MISC(icon), 0.5f, 0.25f); - gtk_misc_set_alignment(GTK_MISC(label), 0.5f, 0.f); -#endif - gtk_widget_show(w); - gtk_window_present(GTK_WINDOW(w)); -} - -void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){ - GtkWidget *mw=linphone_gtk_get_main_window(); - if (linphone_core_get_calls(linphone_gtk_get_core())==NULL){ - gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE); - } - if (linphone_gtk_use_in_call_view() && call) - linphone_gtk_in_call_view_terminate(call,error); -} - -static void linphone_gtk_update_call_buttons(LinphoneCall *call){ - LinphoneCore *lc=linphone_gtk_get_core(); - GtkWidget *mw=linphone_gtk_get_main_window(); - const bctbx_list_t *calls=linphone_core_get_calls(lc); - GtkWidget *button; - bool_t add_call=(calls!=NULL); - int call_list_size=bctbx_list_size(calls); - GtkWidget *conf_frame; - - button=linphone_gtk_get_widget(mw,"start_call"); - gtk_widget_set_sensitive(button,TRUE); - gtk_widget_set_visible(button,!add_call); - - button=linphone_gtk_get_widget(mw,"add_call"); - - if (linphone_core_sound_resources_locked(lc) || (call && linphone_call_get_state(call)==LinphoneCallIncomingReceived)) { - gtk_widget_set_sensitive(button,FALSE); - } else { - gtk_widget_set_sensitive(button,TRUE); - } - gtk_widget_set_visible(button,add_call); - - //gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),stop_active); - conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame"); - if(conf_frame==NULL){ - linphone_gtk_enable_transfer_button(lc,call_list_size>1); - } else { - linphone_gtk_enable_transfer_button(lc,FALSE); - } - if (call) { - bool_t enable_conference = call_list_size>1 && linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call)) == FALSE; - linphone_gtk_enable_conference_button(lc,enable_conference); - linphone_gtk_update_video_button(call); - } -} - -gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference){ - const char *dir=g_get_user_special_dir(G_USER_DIRECTORY_MUSIC); - const char *id="unknown"; - char filename[256]={0}; - char date[64]={0}; - time_t curtime=time(NULL); - struct tm loctime; - const char **fmts=linphone_core_get_supported_file_formats(linphone_gtk_get_core()); - int i; - const char *ext="wav"; - char *record_path_utf8, *record_path; - -#ifdef _WIN32 - loctime=*localtime(&curtime); -#else - localtime_r(&curtime,&loctime); -#endif - snprintf(date,sizeof(date)-1,"%i%02i%02i-%02i%02i",loctime.tm_year+1900,loctime.tm_mon+1,loctime.tm_mday, loctime.tm_hour, loctime.tm_min); - - for (i=0;fmts[i]!=NULL;++i){ - if (strcmp(fmts[i],"mkv")==0){ - ext="mkv"; - break; - } - } - - if (address){ - id=linphone_address_get_username(address); - if (id==NULL) id=linphone_address_get_domain(address); - } - if (is_conference){ - snprintf(filename,sizeof(filename)-1,"%s-conference-%s.%s", - linphone_gtk_get_ui_config("title","Linphone"), - date,ext); - }else{ - snprintf(filename,sizeof(filename)-1,"%s-call-%s-%s.%s", - linphone_gtk_get_ui_config("title","Linphone"), - date, - id,ext); - } - if (!dir) { - ms_message ("No directory for music, using [%s] instead",dir=getenv("HOME")); - } - record_path_utf8 = g_build_filename(dir,filename,NULL); - record_path = g_locale_from_utf8(record_path_utf8, -1, NULL, NULL, NULL); - g_free(record_path_utf8); - return record_path; -} - -gchar *linphone_gtk_get_snapshot_path(void) { - const char *dir=g_get_user_special_dir(G_USER_DIRECTORY_PICTURES); - char filename[256]={0}; - char date[64]={0}; - time_t curtime=time(NULL); - struct tm loctime; - const char *ext="jpg"; - char *snapshot_path_utf8, *snapshot_path; - -#ifdef _WIN32 - loctime=*localtime(&curtime); -#else - localtime_r(&curtime,&loctime); -#endif - snprintf(date,sizeof(date)-1,"%i%02i%02i-%02i%02i%02i",loctime.tm_year+1900,loctime.tm_mon+1,loctime.tm_mday, loctime.tm_hour, loctime.tm_min, loctime.tm_sec); - snprintf(filename,sizeof(filename)-1,"%s-snapshot-%s.%s", - linphone_gtk_get_ui_config("title","Linphone"), - date, ext); - if (!dir) { - ms_message ("No directory for pictures, using [%s] instead",dir=getenv("HOME")); - } - snapshot_path_utf8 = g_build_filename(dir,filename,NULL); - snapshot_path = g_locale_from_utf8(snapshot_path_utf8, -1, NULL, NULL, NULL); - g_free(snapshot_path_utf8); - return snapshot_path; -} - -static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){ - const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar)); - LinphoneCore *lc=linphone_gtk_get_core(); - LinphoneAddress *addr=linphone_core_interpret_url(lc,entered); - - if (addr!=NULL){ - LinphoneCallParams *params=linphone_core_create_call_params(lc, NULL); - gchar *record_file=linphone_gtk_get_record_path(addr,FALSE); - linphone_call_params_set_record_file(params,record_file); - linphone_core_invite_address_with_params(lc,addr,params); - completion_add_text(GTK_ENTRY(uri_bar),entered); - linphone_address_unref(addr); - linphone_call_params_unref(params); - g_free(record_file); - }else{ - linphone_gtk_call_terminated(NULL,NULL); - } - return FALSE; -} - -static void accept_incoming_call(LinphoneCall *call){ - LinphoneCore *lc=linphone_gtk_get_core(); - LinphoneCallParams *params = linphone_core_create_call_params(lc, call); - gchar *record_file=linphone_gtk_get_record_path(linphone_call_get_remote_address(call),FALSE); - linphone_call_params_set_record_file(params,record_file); - linphone_call_accept_with_params(call,params); - linphone_call_params_unref(params); -} - -static gboolean linphone_gtk_auto_answer(LinphoneCall *call){ - LinphoneCallState state=linphone_call_get_state(call); - if (state==LinphoneCallIncomingReceived || state==LinphoneCallIncomingEarlyMedia){ - accept_incoming_call(call); - } - return FALSE; -} - -void linphone_gtk_start_call(GtkWidget *w){ - LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL); - /*change into in-call mode, then do the work later as it might block a bit */ - GtkWidget *mw=gtk_widget_get_toplevel(w); - GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar"); - LinphoneCallState state= call ? linphone_call_get_state(call) : LinphoneCallIdle; - - if (state == LinphoneCallIncomingReceived || state == LinphoneCallIncomingEarlyMedia){ - accept_incoming_call(call); - }else{ - /*immediately disable the button and delay a bit the execution the linphone_core_invite() - so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/ - gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE); - g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar); - } - -} - -void linphone_gtk_start_chat(GtkWidget *w){ - GtkWidget *mw=gtk_widget_get_toplevel(w); - GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar"); - const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar)); - LinphoneCore *lc=linphone_gtk_get_core(); - LinphoneAddress *addr=linphone_core_interpret_url(lc,entered); - if (addr) { - linphone_gtk_friend_list_set_chat_conversation(addr); - linphone_address_unref(addr); - } -} - -void linphone_gtk_uri_bar_activate(GtkWidget *w){ - linphone_gtk_start_call(w); -} - -void linphone_gtk_terminate_call(GtkWidget *button){ - gboolean is_conf; - LinphoneCall *call=linphone_gtk_get_currently_displayed_call(&is_conf); - if (call){ - linphone_call_terminate(call); - }else if (is_conf){ - linphone_core_terminate_conference(linphone_gtk_get_core()); - } -} - -void linphone_gtk_decline_clicked(GtkWidget *button){ - LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL); - if (call) - linphone_call_terminate(call); -} - -void linphone_gtk_answer_clicked(GtkWidget *button){ - LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL); - if (call){ - accept_incoming_call(call); - linphone_gtk_show_main_window(); /* useful when the button is clicked on a notification */ - } -} - -void _linphone_gtk_enable_video(gboolean val){ - LinphoneVideoPolicy policy={0}; - policy.automatically_initiate=policy.automatically_accept=val; - linphone_core_enable_video_capture(linphone_gtk_get_core(), TRUE); - linphone_core_enable_video_display(linphone_gtk_get_core(), TRUE); - linphone_core_set_video_policy(linphone_gtk_get_core(),&policy); -} - -void linphone_gtk_enable_video(GtkWidget *w){ - gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)); - //GtkWidget *selfview_item=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"selfview_item"); - _linphone_gtk_enable_video(val); -} - -void linphone_gtk_enable_self_view(GtkWidget *w){ - gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)); - LinphoneCore *lc=linphone_gtk_get_core(); - linphone_core_enable_self_view(lc,val); - linphone_gtk_set_ui_config_int("videoselfview",val); -} - -void linphone_gtk_used_identity_changed(GtkWidget *w){ - int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w)); - char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w)); - if (sel && strlen(sel)>0){ //avoid a dummy "changed" at gui startup - linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1)); - linphone_gtk_show_directory_search(); - } - if (sel) g_free(sel); -} - -void on_proxy_refresh_button_clicked(GtkWidget *w){ - LinphoneCore *lc=linphone_gtk_get_core(); - linphone_core_refresh_registers(lc); -} - -static gboolean grab_focus(GtkWidget *w){ - gtk_widget_grab_focus(w); - return FALSE; -} - -void linphone_gtk_viewswitch_changed(GtkNotebook *notebook, GtkWidget *page, gint page_num, gpointer user_data){ - GtkWidget *main_window = linphone_gtk_get_main_window(); - GtkWidget *friendlist = linphone_gtk_get_widget(main_window,"contact_list"); - GtkWidget *w = (GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); - - if (page_num == gtk_notebook_page_num(GTK_NOTEBOOK(notebook),w)) { - g_idle_add((GSourceFunc)grab_focus,linphone_gtk_get_widget(page,"text_entry")); - } -} - -static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){ - linphone_gtk_show_friends(); -} - -static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){ - switch(response_id){ - case GTK_RESPONSE_YES: - linphone_gtk_show_contact(lf, the_ui); - break; - default: - linphone_core_reject_subscriber(linphone_gtk_get_core(),lf); - } - gtk_widget_destroy(dialog); -} - -static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){ - GtkWidget *dialog; - gchar *message; - - if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){ - linphone_core_reject_subscriber(linphone_gtk_get_core(),lf); - return; - } - - message=g_strdup_printf(_("%s would like to add you to his/her contact list.\nWould you add him/her to your contact list and allow him/her to see your presence status?\nIf you answer no, this person will be temporarily blacklisted."),url); - dialog = gtk_message_dialog_new ( - GTK_WINDOW(linphone_gtk_get_main_window()), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_YES_NO, - "%s", - message); - g_free(message); - g_signal_connect(G_OBJECT (dialog), "response", - G_CALLBACK (linphone_gtk_new_subscriber_response),lf); - /* actually show the box */ - gtk_widget_show(dialog); -} - -typedef struct _AuthTimeout{ - GtkWidget *w; -} AuthTimeout; - -static void auth_timeout_clean(AuthTimeout *tout){ - tout->w=NULL; -} - -static gboolean auth_timeout_destroy(AuthTimeout *tout){ - if (tout->w) { - g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout); - gtk_widget_destroy(tout->w); - } - g_free(tout); - return FALSE; -} - -static AuthTimeout * auth_timeout_new(GtkWidget *w){ - AuthTimeout *tout=g_new(AuthTimeout,1); - tout->w=w; - /*so that the timeout no more references the widget when it is destroyed:*/ - g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout); - /*so that the widget is automatically destroyed after some time */ - g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout); - return tout; -} - -void linphone_gtk_password_cancel(GtkWidget *w){ - LinphoneAuthInfo *info; - GtkWidget *window=gtk_widget_get_toplevel(w); - info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info"); - linphone_core_abort_authentication(linphone_gtk_get_core(),info); - gtk_widget_destroy(window); -} - -void linphone_gtk_password_ok(GtkWidget *w){ - GtkWidget *entry; - GtkWidget *window=gtk_widget_get_toplevel(w); - LinphoneAuthInfo *info; - info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info"); - g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info); - entry=linphone_gtk_get_widget(window,"password_entry"); - linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry))); - linphone_auth_info_set_userid(info, - gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"userid_entry")))); - linphone_core_add_auth_info(linphone_gtk_get_core(),info); - gtk_widget_destroy(window); -} - -static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain){ - GtkWidget *w=linphone_gtk_create_window("password", the_ui); - GtkWidget *label=linphone_gtk_get_widget(w,"message"); - LinphoneAuthInfo *info; - gchar *msg; - GtkWidget *mw=linphone_gtk_get_main_window(); - - if (mw && g_object_get_data(G_OBJECT(mw), "login_frame") != NULL){ - /*don't prompt for authentication when login frame is visible*/ - linphone_core_abort_authentication(lc,NULL); - return; - } - - msg=g_strdup_printf(_("Please enter your password for username %s\n at realm %s:"), - username,realm); - gtk_label_set_markup(GTK_LABEL(label),msg); - g_free(msg); - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username); - info=linphone_auth_info_new(username, NULL, NULL, NULL,realm,domain); - g_object_set_data(G_OBJECT(w),"auth_info",info); - g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info); - gtk_widget_show(w); - auth_timeout_new(w); -} - -static void linphone_gtk_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf){ - ms_message("Dtmf %c received.",dtmf); -} - - -static void linphone_gtk_configuring_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) { - if (config_fetching_dialog) linphone_gtk_close_config_fetching(config_fetching_dialog, status); - config_fetching_dialog=NULL; -} - -static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){ - GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs"); - if (w) linphone_gtk_call_log_update(w); - linphone_gtk_call_log_update(linphone_gtk_get_main_window()); -} - -#ifdef HAVE_NOTIFY -static bool_t notify_actions_supported(void) { - bool_t accepts_actions = FALSE; - GList *capabilities = notify_get_server_caps(); - GList *c; - if(capabilities != NULL) { - for(c = capabilities; c != NULL; c = c->next) { - if(strcmp((char*)c->data, "actions") == 0 ) { - accepts_actions = TRUE; - break; - } - } - g_list_foreach(capabilities, (GFunc)g_free, NULL); - g_list_free(capabilities); - } - return accepts_actions; -} - -static NotifyNotification* build_notification(const char *title, const char *body) { - NotifyNotification *n = notify_notification_new(title, body, NULL -#ifdef HAVE_NOTIFY1 - ,NULL -#endif - ); -#ifndef HAVE_NOTIFY1 - { - GError *error = NULL; - const char *icon_name = linphone_gtk_get_ui_config("icon_name", LINPHONE_ICON_NAME); - GdkPixbuf *pbuf = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), icon_name, 48, 0, &error); - if(error) { - g_warning("Could not load '%s' icon: %s", icon_name, error->message); - g_error_free(error); - } - notify_notification_set_image_from_pixbuf(n, pbuf); - } -#endif - return n; -} - -static void show_notification(NotifyNotification* n){ - if (n && !notify_notification_show(n,NULL)) - ms_error("Failed to send notification."); -} - -static void make_notification(const char *title, const char *body){ - show_notification(build_notification(title,body)); -} - -#endif - -void linphone_gtk_notify(LinphoneCall *call, LinphoneChatMessage *chat_message, const char *msg){ -#ifdef HAVE_NOTIFY - if (!notify_is_initted()) - if (!notify_init ("Linphone")) ms_error("Libnotify failed to init."); -#endif - if (!call) { -#ifdef HAVE_NOTIFY - if (chat_message) { - const LinphoneAddress *address = linphone_chat_message_get_peer_address(chat_message); - char *remote = linphone_address_as_string(address); - make_notification(remote, linphone_chat_message_get_text(chat_message)); - } else { - if (!notify_notification_show(notify_notification_new("Linphone",msg,NULL -#ifdef HAVE_NOTIFY1 - ,NULL -#endif - ),NULL)) { - ms_error("Failed to send notification."); - } - } -#else - linphone_gtk_show_main_window(); -#endif - } else if (!gtk_window_is_active((GtkWindow*)linphone_gtk_get_main_window())) { - gboolean show_main_window = FALSE; -#ifdef HAVE_NOTIFY - char *body=NULL; - char *remote=call!=NULL ? linphone_call_get_remote_address_as_string(call) : NULL; - NotifyNotification *n; - switch(linphone_call_get_state(call)){ - case LinphoneCallError: - make_notification(_("Call error"),body=g_markup_printf_escaped("%s\n%s",msg,remote)); - break; - case LinphoneCallEnd: - make_notification(_("Call ended"),body=g_markup_printf_escaped("%s",remote)); - break; - case LinphoneCallIncomingReceived: - n=build_notification(_("Incoming call"),body=g_markup_printf_escaped("%s",remote)); - if (n){ - if (notify_actions_supported()) { - notify_notification_add_action (n,"answer", _("Answer"), - NOTIFY_ACTION_CALLBACK(linphone_gtk_answer_clicked),NULL,NULL); - notify_notification_add_action (n,"decline",_("Decline"), - NOTIFY_ACTION_CALLBACK(linphone_gtk_decline_clicked),NULL,NULL); - } - show_notification(n); - }else show_main_window = TRUE; - break; - case LinphoneCallPausedByRemote: - make_notification(_("Call paused"),body=g_markup_printf_escaped(_("by %s"),remote)); - break; - default: - break; - } - if (body) g_free(body); - if (remote) g_free(remote); -#else - if (linphone_call_get_state(call) == LinphoneCallIncomingReceived) - show_main_window = TRUE; -#endif - if (show_main_window) linphone_gtk_show_main_window(); - } -} - -static void linphone_gtk_global_state_changed(LinphoneCore *lc, LinphoneGlobalState state, const char*str){ - switch(state){ - case LinphoneGlobalStartup: - the_core=lc; - break; - case LinphoneGlobalConfiguring: - if (linphone_core_get_provisioning_uri(lc)){ - config_fetching_dialog=linphone_gtk_show_config_fetching(); - } - break; - case LinphoneGlobalOn: - linphone_gtk_init_ui(); - if (selftest) { - gtk_timeout_add(300,(GtkFunction)gtk_main_quit,NULL); - } - break; - default: - break; - } -} - -static void on_call_updated_response(GtkWidget *dialog, gint responseid, gpointer user_data){ - LinphoneCall *call = (LinphoneCall *)g_object_get_data(G_OBJECT(dialog), "call"); - if (linphone_call_get_state(call)==LinphoneCallUpdatedByRemote){ - LinphoneCore *lc=linphone_call_get_core(call); - LinphoneCallParams *params = linphone_core_create_call_params(lc, call); - linphone_call_params_enable_video(params,responseid==GTK_RESPONSE_YES); - linphone_call_accept_update(call,params); - linphone_call_params_unref(params); - } - g_source_remove_by_user_data(dialog); - gtk_widget_destroy(dialog); -} - -static void on_call_updated_timeout(GtkWidget *dialog){ - on_call_updated_response(dialog, GTK_RESPONSE_NO, NULL); -} - -static void linphone_gtk_call_updated_by_remote(LinphoneCall *call){ - LinphoneCore *lc=linphone_call_get_core(call); - const LinphoneVideoPolicy *pol=linphone_core_get_video_policy(lc); - const LinphoneCallParams *rparams=linphone_call_get_remote_params(call); - const LinphoneCallParams *current_params=linphone_call_get_current_params(call); - gboolean video_requested=linphone_call_params_video_enabled(rparams); - gboolean video_used=linphone_call_params_video_enabled(current_params); - g_message("Video used=%i, video requested=%i, automatically_accept=%i", - video_used,video_requested,pol->automatically_accept); - if (!video_used && video_requested && !pol->automatically_accept){ - linphone_call_defer_update(call); - { - const LinphoneAddress *addr=linphone_call_get_remote_address(call); - GtkWidget *dialog; - const char *dname=linphone_address_get_display_name(addr); - if (dname==NULL) dname=linphone_address_get_username(addr); - if (dname==NULL) dname=linphone_address_get_domain(addr); - dialog=gtk_message_dialog_new(GTK_WINDOW(linphone_gtk_get_main_window()), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_WARNING, - GTK_BUTTONS_YES_NO, - _("%s proposed to start video. Do you accept ?"),dname); - g_object_set_data_full(G_OBJECT(dialog), "call", linphone_call_ref(call), (GDestroyNotify)linphone_call_unref); - g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(on_call_updated_response), NULL); - g_timeout_add(20000,(GSourceFunc)on_call_updated_timeout,dialog); - gtk_widget_show(dialog); - } - } -} - -static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){ - const LinphoneErrorInfo *ei; - - switch(cs){ - case LinphoneCallOutgoingInit: - linphone_gtk_create_in_call_view (call); - break; - case LinphoneCallOutgoingProgress: - linphone_gtk_in_call_view_set_calling (call); - break; - case LinphoneCallStreamsRunning: - linphone_gtk_in_call_view_set_in_call(call); - break; - case LinphoneCallUpdatedByRemote: - linphone_gtk_call_updated_by_remote(call); - break; - case LinphoneCallError: - linphone_gtk_in_call_view_terminate (call,msg); - break; - case LinphoneCallEnd: - ei = linphone_call_get_error_info(call); - if (ei && linphone_error_info_get_reason(ei) != LinphoneReasonNone) { - linphone_gtk_in_call_view_terminate(call, linphone_error_info_get_phrase(ei)); - } else { - linphone_gtk_in_call_view_terminate(call, NULL); - } - linphone_gtk_status_icon_set_blinking(FALSE); - break; - case LinphoneCallIncomingReceived: - linphone_gtk_create_in_call_view(call); - linphone_gtk_in_call_view_set_incoming(call); - linphone_gtk_status_icon_set_blinking(TRUE); - if (linphone_gtk_auto_answer_enabled()) { - int delay = linphone_gtk_get_ui_config_int("auto_answer_delay", 2000); - linphone_call_ref(call); - g_timeout_add(delay, (GSourceFunc)linphone_gtk_auto_answer, call); - } - break; - case LinphoneCallResuming: - linphone_gtk_enable_hold_button(call,TRUE,TRUE); - linphone_gtk_in_call_view_set_in_call (call); - break; - case LinphoneCallPausing: - linphone_gtk_enable_hold_button(call,TRUE,FALSE); - linphone_gtk_call_update_tab_header(call,FALSE); - BCTBX_NO_BREAK; - case LinphoneCallPausedByRemote: - linphone_gtk_in_call_view_set_paused(call); - linphone_gtk_call_update_tab_header(call,TRUE); - break; - case LinphoneCallConnected: - linphone_gtk_enable_hold_button (call,TRUE,TRUE); - linphone_gtk_status_icon_set_blinking(FALSE); - break; - default: - break; - } - linphone_gtk_notify(call, NULL, msg); - linphone_gtk_update_call_buttons (call); -} - -static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token){ - linphone_gtk_in_call_view_show_encryption(call); -} - -static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate){ - linphone_gtk_in_call_view_set_transfer_status(call,cstate); -} - -static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistrationState rs){ - GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities")); - GtkTreeModel *model=gtk_combo_box_get_model(box); - GtkTreeIter iter; - gboolean found=FALSE; - const char *icon_name=NULL; - - if (gtk_tree_model_get_iter_first(model,&iter)){ - gpointer p; - do{ - gtk_tree_model_get(model,&iter,2,&p,-1); - if (p==cfg) { - found=TRUE; - break; - } - }while(gtk_tree_model_iter_next(model,&iter)); - } - if (!found) { - /*ignored, this is a notification for a removed proxy config.*/ - return; - } - switch (rs){ - case LinphoneRegistrationOk: - icon_name="linphone-ok"; - break; - case LinphoneRegistrationProgress: - icon_name="linphone-inprogress"; - break; - case LinphoneRegistrationCleared: - icon_name=NULL; - break; - case LinphoneRegistrationFailed: - icon_name="linphone-failed"; - break; - default: - break; - } - gtk_list_store_set(GTK_LIST_STORE(model),&iter,1,icon_name,-1); -} - -static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, - LinphoneRegistrationState rs, const char *msg){ - switch (rs){ - case LinphoneRegistrationOk: - if (cfg){ - SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg); - if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){ - linphone_gtk_exit_login_frame(); - } - } - break; - default: - break; - } - update_registration_status(cfg,rs); -} - -void linphone_gtk_open_browser(const char *uri) { -#ifdef __APPLE__ - GError *error = NULL; - char cmd_line[256]; - - g_snprintf(cmd_line, sizeof(cmd_line), "%s %s", "/usr/bin/open", uri); - g_spawn_command_line_async(cmd_line, &error); - if (error) { - g_warning("Could not open %s: %s", uri, error->message); - g_error_free(error); - } -#elif defined(_WIN32) - HINSTANCE instance = ShellExecute(NULL, "open", uri, NULL, NULL, SW_SHOWNORMAL); - if ((int)instance <= 32) { - g_warning("Could not open %s (error #%i)", uri, (int)instance); - } -#else - GError *error = NULL; - gtk_show_uri(NULL, uri, GDK_CURRENT_TIME, &error); - if (error) { - g_warning("Could not open %s: %s", uri, error->message); - g_error_free(error); - } -#endif -} - -void linphone_gtk_link_to_website(GtkWidget *item){ - const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home"); - linphone_gtk_open_browser(home); -} - -static GtkWidget *create_icon_menu(void){ - GtkWidget *menu=gtk_menu_new(); - GtkWidget *menu_item; - GtkWidget *image; - gchar *tmp; - const gchar *homesite; - - homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org"); - menu_item=gtk_image_menu_item_new_with_label(_("Website link")); - tmp=g_strdup(homesite); - g_object_set_data(G_OBJECT(menu_item),"home",tmp); - g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp); - - image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU); - gtk_widget_show(image); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image); - //g_object_unref(G_OBJECT(image)); - gtk_widget_show(menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); - g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL); - - menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,NULL); - gtk_widget_show(menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); - g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_about,NULL); - menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL); - gtk_widget_show(menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); - g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)gtk_main_quit,NULL); - gtk_widget_show(menu); - return menu; -} - -#ifndef HAVE_GTK_OSX -void linphone_gtk_save_main_window_position(GtkWindow* mw, GdkEvent *event, gpointer data){ - gtk_window_get_position(GTK_WINDOW(mw), &main_window_x, &main_window_y); -} -#endif - -static void handle_icon_click(LinphoneStatusIcon *si, void *user_data) { -#ifndef HAVE_GTK_OSX - GtkWidget *mw=linphone_gtk_get_main_window(); - if (!gtk_window_is_active((GtkWindow*)mw)) { - if(!gtk_widget_is_drawable(mw)){ - //we only move if window was hidden. If it was simply behind the window stack, ie, drawable, we keep it as it was - gtk_window_move (GTK_WINDOW(mw), main_window_x, main_window_y); - } - linphone_gtk_show_main_window(); - } else { - linphone_gtk_save_main_window_position((GtkWindow*)mw, NULL, NULL); - gtk_widget_hide(mw); - } -#endif -} - -static void linphone_gtk_status_icon_initialised_cb(LinphoneStatusIconParams *params) { - LinphoneStatusIcon *icon = linphone_status_icon_get(); - if(icon) { - linphone_status_icon_start(icon, params); - } - linphone_status_icon_params_unref(params); -} - -static void linphone_gtk_init_status_icon(void) { - GtkWidget *menu = create_icon_menu(); - LinphoneStatusIconParams *params = linphone_status_icon_params_new(); - linphone_status_icon_params_set_menu(params, menu); - linphone_status_icon_params_set_title(params, _("Linphone")); - linphone_status_icon_params_set_description(params, _("A video internet phone")); - linphone_status_icon_params_set_on_click_cb(params, handle_icon_click, NULL); - - if(linphone_status_icon_init( - (LinphoneStatusIconReadyCb)linphone_gtk_status_icon_initialised_cb, - params)) { - - LinphoneStatusIcon *icon = linphone_status_icon_get(); - if(icon) { - linphone_status_icon_start(icon, params); - } - linphone_status_icon_params_unref(params); - } -} - -void linphone_gtk_status_icon_set_blinking(gboolean val) { - LinphoneStatusIcon *icon = linphone_status_icon_get(); - if(icon) { - linphone_status_icon_enable_blinking(icon, val); - } -#ifdef __APPLE__ - linphone_gtk_update_badge_count(); -#endif -} - -void linphone_gtk_options_activate(GtkWidget *item){ -#ifndef HAVE_GTK_OSX - gtk_widget_set_visible(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"quit_item"), - TRUE); -#endif -} - -static void init_identity_combo(GtkComboBox *box){ - GtkListStore *store; - GtkCellRenderer *r1,*r2; - store=gtk_list_store_new(3,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_POINTER); - gtk_cell_layout_clear(GTK_CELL_LAYOUT(box)); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(box),(r1=gtk_cell_renderer_text_new()),TRUE); - gtk_cell_layout_pack_end(GTK_CELL_LAYOUT(box),(r2=gtk_cell_renderer_pixbuf_new()),FALSE); - gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r1,"text",0); - gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r2,"icon-name",1); - g_object_set(G_OBJECT(r1),"ellipsize",PANGO_ELLIPSIZE_END,NULL); - gtk_combo_box_set_model(box,GTK_TREE_MODEL(store)); -} - -void linphone_gtk_load_identities(void){ - const bctbx_list_t *elem; - GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities")); - char *def_identity; - LinphoneProxyConfig *def=NULL; - int def_index=0,i; - GtkListStore *store; - GtkTreeIter iter; - - store=GTK_LIST_STORE(gtk_combo_box_get_model(box)); - if (gtk_tree_model_get_n_columns(GTK_TREE_MODEL(store))==1){ - /* model is empty, this is the first time we go here */ - init_identity_combo(box); - store=GTK_LIST_STORE(gtk_combo_box_get_model(box)); - } - gtk_list_store_clear(store); - def = linphone_core_get_default_proxy_config(linphone_gtk_get_core()); - def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core())); - gtk_list_store_append(store,&iter); - gtk_list_store_set(store,&iter,0,def_identity,1,NULL,2,NULL,-1); - g_free(def_identity); - for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core()); - elem!=NULL; - elem=bctbx_list_next(elem),i++){ - LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; - gtk_list_store_append(store,&iter); - gtk_list_store_set(store,&iter,0,linphone_proxy_config_get_identity(cfg),1, - linphone_proxy_config_is_registered(cfg) ? "linphone-ok" : NULL, - 2,cfg,-1); - if (cfg==def) { - def_index=i; - } - } - gtk_combo_box_set_active(box,def_index); -} - -static void linphone_gtk_dtmf_pressed(GtkButton *button){ - const char *label=(char *)g_object_get_data(G_OBJECT(button),"label"); - GtkWidget *uri_bar=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"); - int pos=-1; - gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos); - linphone_core_play_dtmf (linphone_gtk_get_core(),label[0],-1); - if (linphone_core_in_call(linphone_gtk_get_core())){ - linphone_call_send_dtmf(linphone_core_get_current_call(linphone_gtk_get_core()),label[0]); - } -} - -static void linphone_gtk_dtmf_released(GtkButton *button){ - linphone_core_stop_dtmf (linphone_gtk_get_core()); -} - - -static void linphone_gtk_connect_digits(GtkWidget *w){ - GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(w,"dtmf_table")); - GList *children=gtk_container_get_children(cont); - GList *elem; - for(elem=children;elem!=NULL;elem=elem->next){ - GtkButton *button=GTK_BUTTON(elem->data); - g_signal_connect(G_OBJECT(button),"pressed",(GCallback)linphone_gtk_dtmf_pressed,NULL); - g_signal_connect(G_OBJECT(button),"released",(GCallback)linphone_gtk_dtmf_released,NULL); - } -} - -static void linphone_gtk_check_menu_items(void){ - bool_t video_enabled=linphone_gtk_video_enabled(); - bool_t selfview=linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT); - GtkWidget *selfview_item=linphone_gtk_get_widget( - linphone_gtk_get_main_window(),"selfview_item"); - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget( - linphone_gtk_get_main_window(),"enable_video_item")), video_enabled); - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(selfview_item),selfview); -} - -static gboolean linphone_gtk_can_manage_accounts(void){ - LinphoneCore *lc=linphone_gtk_get_core(); - const bctbx_list_t *elem; - for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){ - SipSetup *ss=(SipSetup*)elem->data; - if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){ - return TRUE; - } - } - return FALSE; -} - -static void linphone_gtk_configure_main_window(void){ - static gboolean config_loaded=FALSE; - static const char *title; - static const char *home; - static const char *search_icon; - static gboolean update_check_menu; - static gboolean show_abcd; - GtkWidget *w=linphone_gtk_get_main_window(); - - if (!config_loaded){ - title=linphone_gtk_get_ui_config("title","Linphone"); - home=linphone_gtk_get_ui_config("home","http://www.linphone.org"); - search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL); - update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0); - show_abcd=linphone_gtk_get_ui_config_int("show_abcd",1); - config_loaded=TRUE; - } - linphone_gtk_configure_window(w,"main_window"); - if (title) { - gtk_window_set_title(GTK_WINDOW(w),title); - } - if (search_icon){ - GdkPixbuf *pbuf=create_pixbuf(search_icon); - if(pbuf) { - gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf); - g_object_unref(G_OBJECT(pbuf)); - } - } - if (home){ - gchar *tmp; - GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item"); - tmp=g_strdup(home); - g_object_set_data_full(G_OBJECT(menu_item),"home",tmp, (GDestroyNotify)g_free); - } - if (linphone_gtk_can_manage_accounts()) { - gtk_widget_show(linphone_gtk_get_widget(w,"assistant_item")); - } - if (update_check_menu){ - gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck_item")); - } - g_object_set_data(G_OBJECT(w),"show_abcd",GINT_TO_POINTER(show_abcd)); -} - -void linphone_gtk_manage_login(void){ - LinphoneCore *lc=linphone_gtk_get_core(); - LinphoneProxyConfig *cfg=linphone_core_get_default_proxy_config(lc); - if (cfg){ - SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg); - if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){ - linphone_gtk_show_login_frame(cfg,FALSE); - } - } -} - -gboolean linphone_gtk_close(GtkWidget *mw){ - /*shutdown calls if any*/ - LinphoneCore *lc=linphone_gtk_get_core(); - GtkWidget *camera_preview=linphone_gtk_get_camera_preview_window(); - if (linphone_core_in_call(lc)){ - linphone_core_terminate_all_calls(lc); - } - if (camera_preview) gtk_widget_destroy(camera_preview); -#ifdef __APPLE__ /*until with have a better option*/ - gtk_window_iconify(GTK_WINDOW(mw)); -#else - gtk_widget_hide(mw); -#endif - return TRUE; -} - -#ifdef HAVE_GTK_OSX -static gboolean on_window_state_event(GtkWidget *w, GdkEventWindowState *event){ - return FALSE; -} -#endif - -void linphone_gtk_init_dtmf_table(GtkWidget *mw){ - GtkWidget *dtmf_table=linphone_gtk_get_widget(mw,"dtmf_table"); - gtk_widget_set_direction(dtmf_table, GTK_TEXT_DIR_LTR); - - g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_A")),"label","A"); - g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_B")),"label","B"); - g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_C")),"label","C"); - g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_D")),"label","D"); - g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_1")),"label","1"); - g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_2")),"label","2"); - g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_3")),"label","3"); - g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_4")),"label","4"); - g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_5")),"label","5"); - g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_6")),"label","6"); - g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_7")),"label","7"); - g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_8")),"label","8"); - g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_9")),"label","9"); - g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_0")),"label","0"); - g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_#")),"label","#"); - g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_*")),"label","*"); -} - -static gboolean key_allowed(guint32 code){ - static const char *allowed="1234567890#*ABCD"; - return code!=0 && strchr(allowed,(char)code)!=NULL; -} - -static GtkButton *get_button_from_key(GtkWidget *w, GdkEvent *event){ - guint keyval=event->key.keyval; - guint32 code=gdk_keyval_to_unicode(keyval); - code=g_unichar_toupper(code); - if (key_allowed(code)){ - char widgetname[16]; - w=gtk_widget_get_toplevel(w); - snprintf(widgetname,sizeof(widgetname),"dtmf_%c",code); - return GTK_BUTTON(linphone_gtk_get_widget(w,widgetname)); - } - return NULL; -} - -void linphone_gtk_keypad_key_pressed(GtkWidget *w, GdkEvent *event, gpointer userdata){ - GtkButton *button=get_button_from_key(w,event); - if (button) { - linphone_gtk_dtmf_pressed(button); - /*g_signal_emit_by_name(button, "button-press-event");*/ - } -} - -void linphone_gtk_keypad_key_released(GtkWidget *w, GdkEvent *event, gpointer userdata){ - GtkButton *button=get_button_from_key(w,event); - if (button) { - linphone_gtk_dtmf_released(button); - /*g_signal_emit_by_name(button, "button-release-event");*/ - } -} - -static void linphone_gtk_show_keypad(void){ - GtkWidget *mw=linphone_gtk_get_main_window(); - GtkWidget *k=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"keypad"); - GtkWidget *keypad; - if(k!=NULL){ - gtk_widget_destroy(k); - } - keypad=linphone_gtk_create_window("keypad", NULL); - linphone_gtk_connect_digits(keypad); - linphone_gtk_init_dtmf_table(keypad); - g_object_set_data(G_OBJECT(mw),"keypad", keypad); - if(!GPOINTER_TO_INT(g_object_get_data(G_OBJECT(mw),"show_abcd"))){ - gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_A")); - gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_B")); - gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_C")); - gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_D")); - gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(keypad,"dtmf_table")),4,3); - } - gtk_widget_show(keypad); -} - -static void linphone_gtk_destroy_keypad(void) { - GtkWidget *mw = linphone_gtk_get_main_window(); - GtkWidget *keypad = GTK_WIDGET(g_object_get_data(G_OBJECT(mw), "keypad")); - if(keypad) { - gtk_widget_destroy(keypad); - g_object_set_data(G_OBJECT(mw), "keypad", NULL); - } -} - -void linphone_gtk_show_keypad_checked(GtkCheckMenuItem *check_menu_item) { - if(gtk_check_menu_item_get_active(check_menu_item)) { - linphone_gtk_show_keypad(); - } else { - linphone_gtk_destroy_keypad(); - } -} - -void linphone_gtk_import_contacts(void) { - GtkWidget *mw = linphone_gtk_get_main_window(); - GtkWidget *dialog = gtk_file_chooser_dialog_new("Open vCard file", (GtkWindow *)mw, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); - - if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { - LinphoneCore *lc = linphone_gtk_get_core(); - char *filename_utf8 = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - char *filename = g_locale_from_utf8(filename_utf8, -1, NULL, NULL, NULL); - LinphoneFriendList *list = linphone_core_get_default_friend_list(lc); - linphone_friend_list_import_friends_from_vcard4_file(list, filename); - linphone_gtk_show_friends(); - g_free(filename_utf8); - g_free(filename); - } - gtk_widget_destroy(dialog); -} - -void linphone_gtk_export_contacts(void) { - GtkWidget *mw = linphone_gtk_get_main_window(); - GtkWidget *dialog = gtk_file_chooser_dialog_new("Save vCards as", (GtkWindow *)mw, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); - gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); - - if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { - LinphoneCore *lc = linphone_gtk_get_core(); - char *filename_utf8 = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - char *filename = g_locale_from_utf8(filename_utf8, -1, NULL, NULL, NULL); - LinphoneFriendList *list = linphone_core_get_default_friend_list(lc); - linphone_friend_list_export_friends_as_vcard4_file(list, filename); - g_free(filename_utf8); - g_free(filename); - } - gtk_widget_destroy(dialog); -} - -gboolean linphone_gtk_keypad_destroyed_handler(void) { - GtkWidget *mw = linphone_gtk_get_main_window(); - GtkWidget *show_keypad_item = linphone_gtk_get_widget(mw, "show_keypad_menu_item"); - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(show_keypad_item), FALSE); - return FALSE; -} - -void linphone_gtk_update_status_bar_icons(void) { - GtkWidget *mw = linphone_gtk_get_main_window(); - GtkWidget *icon = linphone_gtk_get_widget(mw, "autoanswer_icon"); - gtk_widget_set_visible(icon, linphone_gtk_auto_answer_enabled()); -} - -static void linphone_gtk_init_main_window(void){ - GtkWidget *main_window; - linphone_gtk_configure_main_window(); - linphone_gtk_manage_login(); - linphone_gtk_load_identities(); - linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core())); - linphone_gtk_show_friends(); - linphone_gtk_update_status_bar_icons(); - load_uri_history(); - linphone_core_reset_missed_calls_count(linphone_gtk_get_core()); - main_window=linphone_gtk_get_main_window(); - linphone_gtk_call_log_update(main_window); - - linphone_gtk_update_call_buttons (NULL); - g_object_set_data(G_OBJECT(main_window),"keypad",NULL); - g_object_set_data(G_OBJECT(main_window),"is_conf",GINT_TO_POINTER(FALSE)); - /*prevent the main window from being destroyed by a user click on WM controls, instead we hide it*/ - g_signal_connect (G_OBJECT (main_window), "delete-event", - G_CALLBACK (linphone_gtk_close), main_window); -#ifdef HAVE_GTK_OSX - { - gtk_widget_show(main_window); - GtkWidget *menubar=linphone_gtk_get_widget(main_window,"menubar1"); - GtkosxApplication *theMacApp = gtkosx_application_get(); - gtkosx_application_set_menu_bar(theMacApp,GTK_MENU_SHELL(menubar)); - gtk_widget_hide(menubar); - gtkosx_application_ready(theMacApp); - } - g_signal_connect(G_OBJECT(main_window), "window-state-event",G_CALLBACK(on_window_state_event), NULL); -#endif - linphone_gtk_check_menu_items(); - linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE); -#ifdef BUILD_WIZARD - gtk_widget_set_visible(linphone_gtk_get_widget(main_window, "assistant_item"), TRUE); -#else - gtk_widget_set_visible(linphone_gtk_get_widget(main_window, "assistant_item"), FALSE); -#endif -} - -void linphone_gtk_log_handler(const char*domain, OrtpLogLevel lev, const char *fmt, va_list args){ - if (verbose){ - const char *lname="undef"; - char *msg; -#if defined(__linux) || defined(__APPLE__) - va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/ -#endif - switch(lev){ - case ORTP_DEBUG: - lname="debug"; - break; - case ORTP_MESSAGE: - lname="message"; - break; - case ORTP_WARNING: - lname="warning"; - break; - case ORTP_ERROR: - lname="error"; - break; - case ORTP_FATAL: - lname="fatal"; - break; - default: - g_error("Bad level !"); - } -#if defined(__linux) || defined(__APPLE__) - va_copy(cap,args); - msg=g_strdup_vprintf(fmt,cap); - va_end(cap); -#else - msg=g_strdup_vprintf(fmt,args); -#endif - fprintf(stdout,"linphone-%s : %s\n",lname,msg); - ortp_free(msg); - } - linphone_gtk_log_push(lev,fmt,args); -} - - -void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){ - char method[20] = ""; - LinphoneAddress *addr = linphone_address_new(refer_to); - if(addr) { - const char *tmp = linphone_address_get_method_param(addr); - strncpy(method, tmp, sizeof(20)); - linphone_address_unref(addr); - } - if(strlen(method) == 0 || strcmp(method, "INVITE") == 0) { - GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget( - linphone_gtk_get_main_window(), "uribar")); - char *text; - linphone_gtk_notify(NULL,NULL,(text=ms_strdup_printf(_("We are transferred to %s"),refer_to))); - g_free(text); - gtk_entry_set_text(uri_bar, refer_to); - linphone_gtk_start_call(linphone_gtk_get_main_window()); - } -} - -static void linphone_gtk_check_soundcards(void){ - const char **devices=linphone_core_get_sound_devices(linphone_gtk_get_core()); - if (devices==NULL || devices[0]==NULL){ - linphone_gtk_display_something(GTK_MESSAGE_WARNING, - _("No sound cards have been detected on this computer.\n" - "You won't be able to send or receive audio calls.")); - } -} - -static void linphone_gtk_quit_core(void){ -#ifdef HAVE_GTK_OSX - { - GtkosxApplication *theMacApp = gtkosx_application_get(); - gtkosx_application_set_menu_bar(theMacApp,NULL); - } -#endif - linphone_gtk_unmonitor_usb(); - g_source_remove_by_user_data(linphone_gtk_get_core()); -#ifdef BUILD_WIZARD - linphone_gtk_close_assistant(); -#endif - linphone_gtk_set_ldap(NULL); - linphone_gtk_destroy_log_window(); - linphone_core_destroy(the_core); - linphone_gtk_log_uninit(); -} - -static void linphone_gtk_quit(void){ - if (!quit_done){ - quit_done=TRUE; - linphone_gtk_quit_core(); - linphone_gtk_uninit_instance(); -#ifdef HAVE_NOTIFY - notify_uninit(); -#endif - linphone_status_icon_uninit(); - gtk_widget_destroy(the_ui); - the_ui=NULL; - gdk_threads_leave(); - } -} - -#ifdef HAVE_GTK_OSX -/* -This is not the correct way to implement block termination. -The good way would be to call gtk_main_quit(), and return TRUE. -Unfortunately this does not work, because if we return TRUE the NSApplication sometimes calls the CFRunLoop recursively, which prevents gtk_main() to exit. -As a result the program cannot exit at all. -As a workaround we do all the cleanup (unregistration and config save) within the handler. -*/ -static gboolean on_block_termination(void){ - gtk_main_quit(); - linphone_gtk_quit(); - return FALSE; -} -#endif - -static void linphone_gtk_init_ui(void){ - linphone_gtk_init_main_window(); - -#ifdef BUILD_WIZARD - // Veryfing if at least one sip account is configured. If not, show wizard - if (linphone_core_get_proxy_config_list(linphone_gtk_get_core()) == NULL) { - linphone_gtk_show_assistant(); - } -#endif - - if(run_audio_assistant){ - linphone_gtk_show_audio_assistant(); - start_option=START_AUDIO_ASSISTANT; - iconified = TRUE; - } - - linphone_gtk_init_status_icon(); - - if (!iconified){ - linphone_gtk_show_main_window(); - linphone_gtk_check_soundcards(); - } - if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0) - linphone_gtk_check_for_new_version(); - linphone_gtk_monitor_usb(); -} - -static void sigint_handler(int signum){ - gtk_main_quit(); -} - -static void populate_xdg_data_dirs_envvar(void) { -#ifndef _WIN32 - int i; - gchar *value; - gchar **paths; - const char *data_dir; - LinphoneFactory *factory = linphone_factory_get(); - - if(g_getenv("XDG_DATA_DIRS") == NULL) { - value = g_strdup("/usr/share:/usr/local/share:/opt/local/share"); - } else { - value = g_strdup(g_getenv("XDG_DATA_DIRS")); - } - paths = g_strsplit(value, ":", -1); - data_dir = linphone_factory_get_top_resources_dir(factory); - for(i=0; paths[i] && strcmp(paths[i], data_dir) != 0; i++); - if(paths[i] == NULL) { - gchar *new_value = g_strdup_printf("%s:%s", data_dir, value); - g_setenv("XDG_DATA_DIRS", new_value, TRUE); - g_free(new_value); - } - g_strfreev(paths); -#endif -} -#define ZRTP_CACHE_CONFIG_FILE ".linphone-zidcache.db" - - -int main(int argc, char *argv[]){ - char *config_file; - const char *factory_config_file; - const char *lang; - GtkSettings *settings; - const char *icon_name=LINPHONE_ICON_NAME; - const char *app_name="Linphone"; - LpConfig *factory_config; - char *chat_messages_db_file, *call_logs_db_file, *friends_db_file; - GError *error=NULL; - const char *tmp; - const char *resources_dir; - char *pixmaps_dir; - LinphoneFactory *factory; - -#if !GLIB_CHECK_VERSION(2, 31, 0) - g_thread_init(NULL); -#endif - gdk_threads_init(); - - progpath = strdup(argv[0]); - - config_file=linphone_gtk_get_config_file(NULL); - - workingdir= (tmp=g_getenv("LINPHONE_WORKDIR")) ? g_strdup(tmp) : NULL; - -#ifdef __linux - /*for pulseaudio:*/ - g_setenv("PULSE_PROP_media.role", "phone", TRUE); -#endif - - populate_xdg_data_dirs_envvar(); - - lang=linphone_gtk_get_lang(config_file); - if (lang == NULL || lang[0]=='\0'){ - lang = g_getenv("LANGUAGE"); - if (!lang) lang = g_getenv("LANG"); - } - if (lang && lang[0]!='\0'){ -#ifdef _WIN32 - if (strncmp(lang,"zh",2)==0){ - workaround_gtk_entry_chinese_bug=TRUE; - } -#endif - g_setenv("LANGUAGE",lang,1); - } - -#ifdef ENABLE_NLS - setlocale(LC_ALL, ""); - bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - - /*do not use textdomain(): this sets a global default domain. On Mac OS bundle, it breaks gtk translations (obscure bug somewhere)*/ - /*textdomain (GETTEXT_PACKAGE);*/ -#else - g_message("NLS disabled.\n"); -#endif -#ifdef _WIN32 - gtk_rc_add_default_file("./gtkrc"); -#endif - gdk_threads_enter(); - - if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"), - linphone_options,NULL,&error)){ - gdk_threads_leave(); - g_critical("%s", error->message); - return -1; - } - if(version) { - g_message("Linphone version %s.", linphone_core_get_version()); - return 0; - } - - if (config_file) g_free(config_file); - if (custom_config_file && !g_path_is_absolute(custom_config_file)) { - gchar *res = g_get_current_dir(); - res = g_strjoin(G_DIR_SEPARATOR_S, res, custom_config_file, NULL); - free(custom_config_file); - custom_config_file = res; - } - config_file=linphone_gtk_get_config_file(custom_config_file); - - if(run_audio_assistant) start_option=START_AUDIO_ASSISTANT; - if(addr_to_call != NULL) start_option=START_LINPHONE_WITH_CALL; - - settings=gtk_settings_get_default(); - g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM)); - g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON)); - g_object_set(settings, "gtk-menu-images", TRUE, NULL); - g_object_set(settings, "gtk-button-images", TRUE, NULL); - - if (workingdir!=NULL){ - if (chdir(workingdir)==-1){ - g_error("Could not change directory to %s : %s",workingdir,strerror(errno)); - } - } - -#if defined(__APPLE__) && defined(ENABLE_NLS) - /*workaround for bundles. GTK is unable to find translations in the bundle (obscure bug again). - So we help it:*/ - { - if (g_file_test(PACKAGE_LOCALE_DIR, G_FILE_TEST_IS_DIR)){ - bindtextdomain("gtk20",PACKAGE_LOCALE_DIR); - bindtextdomain("gdk-pixbuf",PACKAGE_LOCALE_DIR); - bindtextdomain("glib20",PACKAGE_LOCALE_DIR); - } - } -#endif - add_pixmap_directory("pixmaps"); - factory = linphone_factory_get(); - resources_dir = linphone_factory_get_top_resources_dir(factory); - pixmaps_dir = bctbx_strdup_printf("%s/pixmaps/linphone", resources_dir); - add_pixmap_directory(pixmaps_dir); - bctbx_free(pixmaps_dir); - - /* Now, look for the factory configuration file, we do it this late - since we want to have had time to change directory and to parse - the options, in case we needed to access the working directory */ - factory_config_file = linphone_gtk_get_factory_config_file(); - if (factory_config_file){ - factory_config=lp_config_new(NULL); - lp_config_read_file(factory_config,factory_config_file); - app_name=lp_config_get_string(factory_config,"GtkUi","title","Linphone"); - icon_name=lp_config_get_string(factory_config,"GtkUi","icon_name",LINPHONE_ICON_NAME); - } - g_set_application_name(app_name); - gtk_window_set_default_icon_name(icon_name); - -#ifdef HAVE_GTK_OSX - GtkosxApplication *theMacApp = gtkosx_application_get(); - g_signal_connect(G_OBJECT(theMacApp),"NSApplicationDidBecomeActive",(GCallback)linphone_gtk_show_main_window,NULL); - g_signal_connect(G_OBJECT(theMacApp),"NSApplicationWillTerminate",(GCallback)gtk_main_quit,NULL); - /*never block termination:*/ - g_signal_connect(G_OBJECT(theMacApp),"NSApplicationBlockTermination",(GCallback)on_block_termination,NULL); -#endif - -core_start: - if (linphone_gtk_init_instance(app_name, start_option, addr_to_call) == FALSE){ - g_warning("Another running instance of Linphone has been detected. It has been woken-up."); - g_warning("This instance is going to exit now."); - gdk_threads_leave(); - return 0; - } - the_ui=linphone_gtk_create_window("main", NULL); - - g_object_set_data(G_OBJECT(the_ui),"is_created",GINT_TO_POINTER(FALSE)); - g_signal_connect(G_OBJECT (the_ui), "key_press_event", G_CALLBACK (linphone_gtk_on_key_press), NULL); - - linphone_gtk_create_log_window(); - linphone_core_enable_logs_with_cb(linphone_gtk_log_handler); - /*it is possible to filter in or out some logs by configuring per log domain:*/ - /*ortp_set_log_level_mask("belle-sip", ORTP_ERROR);*/ - - chat_messages_db_file=linphone_gtk_message_storage_get_db_file(NULL); - call_logs_db_file = linphone_gtk_call_logs_storage_get_db_file(NULL); - friends_db_file = linphone_gtk_friends_storage_get_db_file(NULL); - linphone_gtk_init_liblinphone(config_file, factory_config_file, chat_messages_db_file, call_logs_db_file, friends_db_file); - g_free(chat_messages_db_file); - g_free(call_logs_db_file); - g_free(friends_db_file); - - linphone_gtk_call_log_update(the_ui); - linphone_gtk_show_friends(); - - /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/ - gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core()); - gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)linphone_gtk_get_core()); - - signal(SIGINT, sigint_handler); - - gtk_main(); - linphone_gtk_quit(); - - if (restart){ - quit_done=FALSE; - restart=FALSE; - goto core_start; - } - if (config_file) g_free(config_file); - free(progpath); - /*output a translated "hello" string to the terminal, which allows the builder to check that translations are working.*/ - if (selftest){ - printf(_("Hello\n")); - } - return 0; -} - -#ifdef _MSC_VER -int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { - return main(__argc, __argv); -} -#endif - -GtkWidget *linphone_gtk_make_tab_header(const gchar *label, const gchar *icon_name, gboolean show_quit_button, GCallback cb, gpointer user_data) { - GtkWidget *tab_header=gtk_hbox_new (FALSE,0); - GtkWidget *label_widget = gtk_label_new (label); - - if(icon_name) { - GtkWidget *icon=gtk_image_new_from_icon_name(icon_name, GTK_ICON_SIZE_MENU); -#ifdef HAVE_GTK_OSX - gtk_misc_set_alignment(GTK_MISC(icon), 0.5f, 0.25f); -#endif - gtk_box_pack_start (GTK_BOX(tab_header),icon,FALSE,FALSE,4); - } -#ifdef HAVE_GTK_OSX - gtk_misc_set_alignment(GTK_MISC(label_widget), 0.5f, 0.f); -#endif - gtk_box_pack_start (GTK_BOX(tab_header),label_widget,FALSE,FALSE,0); - if(show_quit_button) { - GtkWidget *button = gtk_button_new(); - GtkWidget *button_image=gtk_image_new_from_stock(GTK_STOCK_CLOSE,GTK_ICON_SIZE_MENU); - gtk_button_set_image(GTK_BUTTON(button),button_image); - gtk_button_set_relief(GTK_BUTTON(button),GTK_RELIEF_NONE); -#ifdef HAVE_GTK_OSX - gtk_misc_set_alignment(GTK_MISC(button_image), 0.5f, 0.f); -#endif - g_signal_connect_swapped(G_OBJECT(button),"clicked",cb,user_data); - gtk_box_pack_end(GTK_BOX(tab_header),button,FALSE,FALSE,4); - g_object_set_data(G_OBJECT(tab_header), "button", button); - } - g_object_set_data(G_OBJECT(tab_header), "label", label_widget); - return tab_header; -} diff --git a/gtk/main.ui b/gtk/main.ui deleted file mode 100644 index e7360e215..000000000 --- a/gtk/main.ui +++ /dev/null @@ -1,1056 +0,0 @@ - - - - - - - True - False - 2 - 30 - linphone-add-call - - - True - False - linphone-contact-add - - - True - False - 4 - linphone-delete - - - True - False - gtk-connect - 1 - - - - - - - - - - - - - - - - - - - - - - - linphone-status-online - Toto - toto@sip.linphone.org - linphone-chat-nothing - False - False - - - linphone-status-offline - Toto2 - toto2@sip.linphone.org - linphone-chat-nothing - False - False - - - linphone-status-offline - Toto3 - toto3@sip.linphone.org - linphone-chat-nothing - False - False - - - - - True - False - linphone-edit - - - True - False - gtk-execute - 1 - - - True - False - gtk-home - 1 - - - True - False - gtk-info - 1 - - - - - - - - - Default - - - - - True - False - gtk-properties - 1 - - - True - False - Delete - linphone-delete - - - True - False - 2 - 30 - linphone-start-call - - - True - False - 2 - 30 - linphone-start-chat - - - 640 - 480 - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 660 - 450 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - - - True - False - _Options - True - - - - True - False - - - gtk-preferences - True - False - True - True - - - - - - - True - False - Set configuration URI - True - - - - - - gtk-disconnect - False - True - True - - - - - - True - False - - - - - True - False - Always start video - True - - - - - - True - False - Enable self-view - True - True - - - - - - True - False - Show keypad - True - - - - - - True - False - - - - - True - False - Import contacts from vCards - True - - - - - - True - False - Export contacts as vCards - True - - - - - - True - False - - - - - gtk-quit - False - True - True - - - - - - - - - - - True - False - _Help - True - - - True - False - - - gtk-about - True - False - True - True - - - - - - Show debug window - True - False - info_image - False - - - - - - - _Homepage - True - False - True - home_image - False - - - - - - Check _Updates - False - True - execute_image - False - - - - - - Account assistant - False - connect_image - False - - - - - - Audio assistant - True - False - properties_image - False - - - - - - - - - - False - True - 0 - - - - - True - False - 8 - - - True - False - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - 5 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - True - - True - linphone-contact-add - False - True - True - False - - - - True - True - 0 - - - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - SIP address or phone number: - True - - - - - True - True - 2 - 0 - - - - - True - True - Initiate a new call - add_call_image - - - - False - False - 1 - - - - - True - True - True - start_call_image - - - - False - True - 2 - - - - - True - True - True - start_chat_image - - - - False - True - end - 3 - - - - - False - True - 8 - 0 - - - - - True - True - 200 - True - - - True - False - 4 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_STRUCTURE_MASK - 0 - Contacts - True - - - False - False - 3 - 0 - - - - - True - True - automatic - automatic - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - contact_list_model - False - True - 1 - 4 - - - - - - - - - - 3 - - - 0 - - - - - - - 60 - True - - - - 1 - - - - - - - - - linphone-start-call2 - 3 - - - 6 - - - - - - - - - 3 - - - 7 - 5 - - - - - - - - - True - True - 1 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 2 - - - 32 - 32 - True - True - True - immediate - add_image1 - - - - False - False - 0 - - - - - 32 - 32 - True - False - True - True - edit_image1 - - - - False - False - 1 - - - - - 32 - 32 - True - False - True - True - remove_image1 - - - - False - False - 2 - - - - - False - False - 4 - 2 - - - - - True - True - - - - - True - True - - - - - - - - - - True - False - - - True - False - 2 - - - True - True - never - - - 350 - True - True - False - False - - - - - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - False - 0 - none - - - False - - - True - True - - True - False - False - True - True - - - True - True - 0 - - - - - True - True - True - none - - - - True - False - - - True - False - gtk-find - - - True - True - 0 - - - - - True - False - Search - - - True - True - 1 - - - - - - - False - True - 1 - - - - - - - True - False - <b>Add contacts from directory</b> - True - - - - - False - False - 5 - 0 - - - - - True - False - - - Add contact - True - True - - - - False - False - 0 - - - - - False - False - 1 - - - - - False - False - 1 - - - - - True - False - end - - - Clear call history - True - True - True - clear_call_history_image - - - - False - False - 0 - - - - - False - True - 2 - - - - - True - True - 0 - - - - - 1 - - - - - True - False - GDK_BUTTON_PRESS_MASK | GDK_STRUCTURE_MASK - False - - - - True - False - - - True - False - linphone-history - 1 - - - True - True - 4 - 0 - - - - - True - False - Recent calls - - - True - True - 1 - - - - - - - 1 - False - - - - - - - - - - - True - True - - - - - True - True - 1 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - model3 - 0 - - - - - 0 - - - - - True - True - 0 - - - - - True - True - True - none - - - - False - True - 5 - 1 - - - - - - - True - False - 5 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - My current identity: - True - - - True - True - 0 - - - - - True - True - True - none - - - - True - True - 1 - - - - - - - False - False - 2 - - - - - True - True - 1 - - - - - True - False - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - True - True - 0 - - - - - False - Autoanswer is enabled - 16 - linphone-warning - - - False - True - 1 - - - - - False - True - 2 - - - - - - diff --git a/gtk/p2pwizard.ui b/gtk/p2pwizard.ui deleted file mode 100644 index 111f46ff5..000000000 --- a/gtk/p2pwizard.ui +++ /dev/null @@ -1,129 +0,0 @@ - - - - - Creating a FONICS account - - - - - True - Welcome! -This wizard will help you to setup a SIP account. - - True - GTK_JUSTIFY_CENTER - True - True - - - GTK_ASSISTANT_PAGE_INTRO - Introduction - - - - - True - - - True - Please choose a username: - - - - - True - 0 - - - True - 12 - - - True - - - True - - - True - True - - - - - True - True - True - - - - True - - - True - gtk-apply - - - - - True - Check availability - - - 1 - - - - - - - False - 1 - - - - - False - - - - - True - - - 1 - - - - - - - - - True - True - - - - - 1 - - - - - Create your account ! - - - - - True - Done ! Your account is now created and ready to use. - - - GTK_ASSISTANT_PAGE_CONFIRM - Finished ! - - - - diff --git a/gtk/parameters.ui b/gtk/parameters.ui deleted file mode 100644 index ee93560bb..000000000 --- a/gtk/parameters.ui +++ /dev/null @@ -1,3183 +0,0 @@ - - - - - - -1 - 100000 - 1 - 10 - - - 65535 - 2 - 10 - - - 65535 - 2 - 10 - - - 65535 - 2 - 10 - - - 65535 - 2 - 10 - - - 500 - 3001 - 500 - 1 - 10 - - - 65535 - 5060 - 1 - 10 - - - -1 - 100000 - 1 - 10 - - - 30 - 1 - 10 - - - 30000 - 2000 - 100 - 500 - - - - - - - - - - anonymous - - - GSSAPI - - - SASL - - - - - - - - - - - default soundcard - - - - - - - - - - - default soundcard - - - - - - - - - - - a sound card - - - - - - - - - - - default camera - - - - - - - - - - - CIF - - - - - - - - - - - Audio codecs - - - Video codecs - - - - - - - - - - - C - - - - - - - - - - - SIP (UDP) - - - SIP (TCP) - - - SIP (TLS) - - - - - 65535 - 5060 - 1 - 9.9999999995529656 - - - - - - - - - default - - - high-fps - - - custom - - - - - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Settings - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 10 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - This section defines your SIP address when not using a SIP account - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 3 - 2 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Your display name (eg: John Doe): - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - False - True - True - - - - 1 - 2 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Your username: - - - 1 - 2 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Your resulting SIP address: - - - 2 - 3 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - False - True - True - - - - 1 - 2 - 1 - 2 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - False - False - True - True - - - 1 - 2 - 2 - 3 - - - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Default identity</b> - True - - - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - True - True - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-add - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Wizard - - - True - True - 1 - - - - - - - False - False - 0 - - - - - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-add - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Add - - - True - True - 1 - - - - - - - False - False - 1 - - - - - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-edit - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Edit - - - True - True - 1 - - - - - - - False - False - 2 - - - - - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-delete - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Remove - - - True - True - 1 - - - - - - - False - False - 3 - - - - - False - False - 1 - - - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Proxy accounts</b> - True - - - - - True - True - 1 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-delete - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Erase all passwords - - - True - True - 1 - - - - - - - False - False - 0 - - - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Privacy</b> - True - - - - - True - True - 2 - - - - - True - False - 0 - none - - - True - False - 12 - - - True - False - 2 - 2 - - - Automatically answer when a call is received - True - True - False - True - - - - 2 - - - - - True - False - Delay before answering (ms) - - - 1 - 2 - - - - - True - True - - False - False - True - True - ajustment_auto_answer_delay - True - - - - 1 - 2 - 1 - 2 - - - - - - - - - True - False - <b>Auto-answer</b> - True - - - - - True - True - 3 - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - stock_people.png - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Manage SIP Accounts - - - True - True - 1 - - - - - 2 - False - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 10 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 6 - 2 - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - True - True - 0 - - - - - gtk-media-play - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - - True - True - 1 - - - - - 1 - 2 - 4 - 5 - GTK_FILL - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Ring sound: - right - - - 4 - 5 - GTK_FILL - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - False - True - True - - - - 1 - 2 - 3 - 4 - GTK_FILL - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - model1 - - - - end - 80 - - - 0 - - - - - 1 - 2 - 2 - 3 - GTK_FILL - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - model2 - - - - end - 80 - - - 0 - - - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - ALSA special device (optional): - right - - - 3 - 4 - GTK_FILL - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Capture device: - right - - - 2 - 3 - GTK_FILL - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Ring device: - right - - - 1 - 2 - GTK_FILL - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Playback device: - right - - - GTK_FILL - GTK_FILL - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - model3 - - - - end - 80 - - - 0 - - - - - 1 - 2 - GTK_FILL - GTK_FILL - - - - - Enable echo cancellation - True - True - False - True - - - - 1 - 2 - 5 - 6 - - - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Audio</b> - True - - - - - True - True - 0 - - - - - True - False - 0 - none - - - True - False - 12 - - - True - False - 5 - 3 - - - True - False - Video input device: - right - - - GTK_EXPAND - - - - - True - False - model4 - - - - - 0 - - - - - 1 - 2 - GTK_EXPAND - - - - - True - False - Preferred video resolution: - - - 3 - 4 - - - - - True - False - model5 - 0 - - - - - 0 - - - - - 1 - 2 - 3 - 4 - - - - - True - False - Video output method: - right - - - 1 - 2 - GTK_EXPAND - - - - - True - False - - - - - 0 - - - - - 1 - 2 - 1 - 2 - GTK_EXPAND - - - - - Show camera preview - True - True - True - - - - 2 - 3 - 5 - - GTK_EXPAND - 10 - - - - - True - False - Video preset: - - - 2 - 3 - - - - - True - False - video_preset_model - 0 - - - - - 0 - - - - - 1 - 2 - 2 - 3 - - - - - True - False - Preferred video framerate: - - - 4 - 5 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 stands for "unlimited" - - False - False - True - True - adjustment_video_framerate - - - - 1 - 2 - 4 - 5 - GTK_FILL - GTK_EXPAND - - - - - - - - - True - False - <b>Video</b> - True - - - - - True - False - 1 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 3 - 2 - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 stands for "unlimited" - - False - False - True - True - adjustment_upload_bw - - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 stands for "unlimited" - - False - False - True - True - adjustment_download_bw - - - - 1 - 2 - GTK_FILL - GTK_EXPAND - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Upload speed limit in Kbit/sec: - right - - - 1 - 2 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Download speed limit in Kbit/sec: - right - - - - - Enable adaptive rate control - True - True - False - 0 - True - - - - 1 - 2 - 2 - 3 - GTK_FILL - - - - - - True - False - <i>Adaptive rate control is a technique to dynamically guess the available bandwidth during a call.</i> - True - True - - - 2 - 3 - GTK_FILL - - - - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Bandwidth control</b> - True - - - - - True - True - 2 - - - - - 1 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-media-play - 1 - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Multimedia settings - - - True - True - 1 - - - - - 1 - False - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 10 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - - True - False - - - True - False - - - Set Maximum Transmission Unit: - True - True - False - True - - - - True - True - 0 - - - - - True - True - False - False - True - True - adjustment_mtu - - - - True - True - 1 - - - - - True - True - 0 - - - - - Send DTMFs as SIP info - True - True - False - True - - - - True - True - 1 - - - - - Allow IPv6 - True - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - - True - True - 2 - - - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Transport</b> - True - - - - - False - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 6 - 2 - - - True - False - SIP/UDP port - - - - - True - False - - - Disabled - True - True - False - True - - - - True - True - 0 - - - - - Random - True - True - False - True - - - - True - True - 1 - - - - - True - True - - True - False - False - True - True - udp_port_adjustment - - - - True - True - 2 - - - - - 1 - 2 - - - - - True - False - SIP/TCP port - - - 1 - 2 - - - - - True - False - - - Disabled - True - True - False - True - - - - True - True - 0 - - - - - Random - True - True - False - True - - - - True - True - 1 - - - - - True - True - - True - False - False - True - True - adjustment_tcp_port - - - - True - True - 2 - - - - - 1 - 2 - 1 - 2 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Audio RTP/UDP: - right - - - 2 - 3 - - - - - True - False - - - True - True - - False - False - True - True - adjustment_min_audio_port - True - - - - True - True - 0 - - - - - True - True - - True - False - False - True - True - adjustment_max_audio_port - True - - - - True - True - 1 - - - - - Fixed - True - True - False - True - - - - True - True - 2 - - - - - 1 - 2 - 2 - 3 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Video RTP/UDP: - right - - - 3 - 4 - - - - - True - False - - - True - True - - False - False - True - True - adjustment_min_video_port - True - - - - True - True - 0 - - - - - True - True - - True - False - False - True - True - adjustment_max_video_port - True - - - - True - True - 1 - - - - - Fixed - True - True - False - True - - - - True - True - 2 - - - - - 1 - 2 - 3 - 4 - - - - - False - Tunnel - - - 5 - 6 - - - - - gtk-edit - True - True - True - - - - 1 - 2 - 5 - 6 - - - - - True - False - DSCP fields - - - 4 - 5 - - - - - gtk-edit - True - True - True - True - - - - 1 - 2 - 4 - 5 - - - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Network protocol and ports</b> - True - - - - - False - True - 1 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - - - True - False - - - Direct connection to the Internet - True - True - False - True - True - - - - False - False - 0 - - - - - Behind NAT / Firewall (specify gateway IP ) - True - True - False - True - no_nat - - - - True - True - 1 - - - - - Behind NAT / Firewall (use STUN to resolve) - True - True - False - True - no_nat - - - - True - True - 2 - - - - - Behind NAT / Firewall (use ICE) - True - True - False - True - no_nat - - - - True - True - 3 - - - - - Behind NAT / Firewall (use uPnP) - True - True - False - True - no_nat - - - - True - True - 4 - - - - - True - True - 0 - - - - - True - False - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Public IP address: - right - - - True - True - 0 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - True - False - False - True - True - - - - True - True - 1 - - - - - True - False - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Stun server: - right - - - True - True - 0 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - True - False - False - True - True - - - - True - True - 1 - - - - - True - False - 1 - - - - - False - False - 1 - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>NAT and Firewall</b> - True - - - - - False - True - 2 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 3 - 2 - - - True - False - Media encryption type - - - 1 - 2 - - - - - True - False - 0 - - - 1 - 2 - 1 - 2 - - - - - True - False - 0.51999998092651367 - Use Lime for outgoing chat messages - - - - - True - False - Media encryption is mandatory - - - 2 - 3 - - - - - True - True - False - 0.40000000596046448 - True - - - - 1 - 2 - 2 - 3 - - - - - True - False - - Disabled - Mandatory - Preferred - - - - - 1 - 2 - - - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Encryption</b> - True - - - - - False - True - 3 - - - - - 2 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-network - 1 - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Network settings - - - True - True - 1 - - - - - 2 - False - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 10 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - out - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 10 - center - - - gtk-go-up - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - - False - False - 0 - - - - - gtk-go-down - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - - False - False - 1 - - - - - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-yes - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Enable - - - True - True - 1 - - - - - - - False - False - 2 - - - - - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-no - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Disable - - - True - True - 1 - - - - - - - False - False - 3 - - - - - False - True - 1 - - - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Audio codecs</b> - True - - - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - out - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 10 - center - - - gtk-go-up - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - - False - False - 0 - - - - - gtk-go-down - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - - False - False - 1 - - - - - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-yes - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Enable - - - True - True - 1 - - - - - - - False - False - 2 - - - - - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-no - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Disable - - - True - True - 1 - - - - - - - False - False - 3 - - - - - False - True - 1 - - - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Video codecs</b> - True - - - - - False - True - 1 - - - - - 3 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-execute - 1 - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Codecs - - - True - True - 1 - - - - - 3 - False - - - - - True - False - 10 - - - True - False - 0 - none - - - True - False - 12 - - - True - False - model7 - - - - - 0 - - - - - - - - - True - False - <b>Language</b> - True - - - - - False - True - 0 - - - - - True - False - 0 - none - - - True - False - 12 - - - Show advanced settings - True - True - False - True - - - - - - - - True - False - <b>Level</b> - True - - - - - False - True - 1 - - - - - 4 - - - - - True - False - - - True - False - gtk-properties - 1 - - - True - True - 0 - - - - - True - False - User interface - - - True - True - 1 - - - - - 4 - False - - - - - True - False - 10 - - - True - False - 0 - none - - - True - False - 0 - 0 - - - True - False - 4 - 2 - True - - - - - - True - False - 1 - Server address: - - - GTK_SHRINK - GTK_SHRINK - - - - - True - False - Authentication method: - - - 1 - 2 - GTK_EXPAND | GTK_SHRINK - - - - - True - False - Username: - - - 2 - 3 - GTK_SHRINK - - - - - gtk-edit - True - True - True - True - - - - 1 - 2 - 3 - 4 - GTK_SHRINK - GTK_SHRINK - - - - - True - False - - - 1 - 2 - GTK_SHRINK - - - - - True - False - - - 1 - 2 - 1 - 2 - GTK_SHRINK - - - - - True - False - - - 1 - 2 - 2 - 3 - GTK_SHRINK - - - - - - - - - True - False - <b>LDAP Account setup</b> - True - - - - - False - True - 0 - - - - - - - - 5 - - - - - True - False - - - True - False - gtk-disconnect - - - True - True - 0 - - - - - True - False - LDAP - - - True - True - 1 - - - - - 5 - False - - - - - - - - - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - end - - - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - True - False - - - True - False - gtk-apply - - - True - True - 0 - - - - - True - False - Done - - - True - True - 1 - - - - - - - False - False - 10 - 0 - - - - - True - True - 5 - 1 - - - - - - diff --git a/gtk/password.ui b/gtk/password.ui deleted file mode 100644 index d9ce720aa..000000000 --- a/gtk/password.ui +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - Linphone - Authentication required - True - center-on-parent - dialog - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 2 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Please enter the domain password - center - True - - - 0 - - - - - True - 2 - 2 - - - True - UserID - - - - - True - True - - - - 1 - 2 - - - - - True - Password: - right - - - 1 - 2 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - - - 1 - 2 - 1 - 2 - - - - - 1 - - - - - 1 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - end - - - gtk-ok - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - - False - False - 0 - - - - - gtk-cancel - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - - False - False - 1 - - - - - False - end - 0 - - - - - - diff --git a/gtk/propertybox.c b/gtk/propertybox.c deleted file mode 100644 index 9e417f88f..000000000 --- a/gtk/propertybox.c +++ /dev/null @@ -1,1966 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2008-2009 Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "linphone.h" -#include "linphone/tunnel.h" -#include "linphone/lpconfig.h" -#include "config.h" - -void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, const char *selected, DeviceCap cap){ - const char **p=devices; - int i=0,active=-1; - GtkTreeModel *model; - - - if ((model=gtk_combo_box_get_model(GTK_COMBO_BOX(combo)))==NULL){ - /*case where combo box is created with no model*/ - GtkCellRenderer *renderer=gtk_cell_renderer_text_new(); - model=GTK_TREE_MODEL(gtk_list_store_new(1,G_TYPE_STRING)); - gtk_combo_box_set_model(GTK_COMBO_BOX(combo),model); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo),renderer,TRUE); - gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo),renderer,"text",0,NULL); - }else{ - gtk_list_store_clear(GTK_LIST_STORE(model)); - /* glade creates a combo box without list model and text renderer, - unless we fill it with a dummy text. - This dummy text needs to be removed first*/ - } - - for(;*p!=NULL;++p){ - if ( cap==CAP_IGNORE - || (cap==CAP_CAPTURE && linphone_core_sound_device_can_capture(linphone_gtk_get_core(),*p)) - || (cap==CAP_PLAYBACK && linphone_core_sound_device_can_playback(linphone_gtk_get_core(),*p)) ){ - gtk_combo_box_append_text(GTK_COMBO_BOX(combo),*p); - if (selected && strcmp(selected,*p)==0) active=i; - i++; - } - } - if (active!=-1) - gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active); -} - -static void linphone_gtk_ldap_display( GtkWidget* param ) -{ - LpConfig* config = linphone_core_get_config(linphone_gtk_get_core()); - LinphoneDictionary* ldap_conf = lp_config_section_to_dict(config,"ldap"); - GtkLabel* label; - - ms_message("linphone_gtk_ldap_display"); - label= GTK_LABEL(linphone_gtk_get_widget(param,"ldap_server")); - gtk_label_set_text(label, linphone_dictionary_get_string(ldap_conf,"server", "ldap://localhost") ); - - label = GTK_LABEL(linphone_gtk_get_widget(param,"ldap_auth_method")); - gtk_label_set_text(label, linphone_dictionary_get_string(ldap_conf,"auth_method", "ANONYMOUS") ); - - label = GTK_LABEL(linphone_gtk_get_widget(param,"ldap_username")); - gtk_label_set_text(label, linphone_dictionary_get_string(ldap_conf,"username", "") ); -} - -static void linphone_gtk_ldap_set_authcombo( GtkComboBox* box, const char* authmethod ) -{ - GtkTreeModel* model = GTK_TREE_MODEL(gtk_combo_box_get_model(box)); - GtkTreeIter iter; - g_return_if_fail(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter) ); - - do{ - const char* value; - - gtk_tree_model_get(model,&iter,0,&value,-1); - if( value && strcmp(value, authmethod) == 0){ - gtk_combo_box_set_active_iter(box, &iter); - break; - } - - }while(gtk_tree_model_iter_next(model,&iter)); -} - -static void linphone_gtk_ldap_load_settings(GtkWidget* param) -{ - LpConfig* config = linphone_core_get_config(linphone_gtk_get_core()); - LinphoneDictionary* ldap_conf = lp_config_section_to_dict(config,"ldap"); - GtkEntry* entry; - GtkToggleButton* toggle; - GtkSpinButton* spin; - GtkComboBox* cbox; - - - toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(param,"ldap_use_tls")); - gtk_toggle_button_set_active(toggle, linphone_dictionary_get_int(ldap_conf,"use_tls", 0) ); - - entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_server")); - gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"server", "ldap://localhost") ); - - entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_username")); - gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"username", "") ); - - entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_password")); - gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"password", "") ); - - // SASL - entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_bind_dn")); - gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"bind_dn", "") ); - entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_sasl_authname")); - gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"sasl_authname", "") ); - entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_sasl_realm")); - gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"sasl_realm", "") ); - - cbox = GTK_COMBO_BOX(linphone_gtk_get_widget(param,"ldap_auth_method")); - linphone_gtk_ldap_set_authcombo(cbox, linphone_dictionary_get_string(ldap_conf,"auth_method", "ANONYMOUS")); - - entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_base_object")); - gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"base_object", "dc=example,dc=com") ); - - entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_filter")); - gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"filter", "uid=*%s*") ); - - entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_name_attribute")); - gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"name_attribute", "cn") ); - - entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_sip_attribute")); - gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"sip_attribute", "mobile") ); - - entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_attributes")); - gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"attributes", "cn,givenName,sn,mobile,homePhone") ); - - - toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(param,"ldap_deref_aliases")); - gtk_toggle_button_set_active(toggle, linphone_dictionary_get_int(ldap_conf,"deref_aliases", 0) ); - - spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(param,"ldap_max_results")); - gtk_spin_button_set_value(spin, linphone_dictionary_get_int(ldap_conf,"max_results", 50) ); - - spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(param,"ldap_timeout")); - gtk_spin_button_set_value(spin, linphone_dictionary_get_int(ldap_conf,"timeout", 10) ); - -} - - -void linphone_gtk_show_ldap_config(GtkWidget* button) -{ - GtkWidget* param = gtk_widget_get_toplevel(button); - GtkWidget* ldap_config = linphone_gtk_create_window("ldap", param); - linphone_gtk_ldap_load_settings(ldap_config); - - // to refresh parameters when the ldap config is destroyed - g_object_weak_ref(G_OBJECT(ldap_config), (GWeakNotify)linphone_gtk_ldap_display, (gpointer)param); - - gtk_widget_show(ldap_config); -} - -void linphone_gtk_ldap_reset(GtkWidget *button) -{ - GtkWidget *w=gtk_widget_get_toplevel(GTK_WIDGET(button)); - ms_message("RESET LDAP"); - gtk_widget_destroy(w); -} - -void linphone_gtk_ldap_save(GtkWidget *button) -{ - LinphoneCore *lc = linphone_gtk_get_core(); - LpConfig* conf = linphone_core_get_config(lc); - LinphoneDictionary* dict = linphone_dictionary_new(); - - GtkWidget *ldap_widget = gtk_widget_get_toplevel(button); - GtkEntry* entry; - GtkToggleButton* toggle; - GtkSpinButton* spin; - GtkComboBox* cbox; - - ms_message("SAVE LDAP"); - - toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(ldap_widget,"ldap_use_tls")); - linphone_dictionary_set_int(dict, "use_tls", gtk_toggle_button_get_active(toggle)); - - - entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_server")); - linphone_dictionary_set_string(dict, "server", gtk_entry_get_text(entry)); - - entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_username")); - linphone_dictionary_set_string(dict, "username", gtk_entry_get_text(entry)); - - entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_password")); - linphone_dictionary_set_string(dict, "password", gtk_entry_get_text(entry)); - - // SASL - entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_bind_dn")); - linphone_dictionary_set_string(dict, "bind_dn", gtk_entry_get_text(entry)); - entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_sasl_authname")); - linphone_dictionary_set_string(dict, "sasl_authname", gtk_entry_get_text(entry)); - entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_sasl_realm")); - linphone_dictionary_set_string(dict, "sasl_realm", gtk_entry_get_text(entry)); - - - cbox = GTK_COMBO_BOX(linphone_gtk_get_widget(ldap_widget,"ldap_auth_method")); - linphone_dictionary_set_string(dict, "auth_method", gtk_combo_box_get_active_text(cbox)); - - entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_base_object")); - linphone_dictionary_set_string(dict, "base_object", gtk_entry_get_text(entry)); - - entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_filter")); - linphone_dictionary_set_string(dict, "filter", gtk_entry_get_text(entry)); - - entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_name_attribute")); - linphone_dictionary_set_string(dict, "name_attribute", gtk_entry_get_text(entry)); - - entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_sip_attribute")); - linphone_dictionary_set_string(dict, "sip_attribute", gtk_entry_get_text(entry)); - - entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_attributes")); - linphone_dictionary_set_string(dict, "attributes", gtk_entry_get_text(entry)); - - toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(ldap_widget,"ldap_deref_aliases")); - linphone_dictionary_set_int(dict, "deref_aliases", gtk_toggle_button_get_active(toggle)); - - spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(ldap_widget,"ldap_max_results")); - linphone_dictionary_set_int(dict, "max_results", (int)gtk_spin_button_get_value(spin) ); - - spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(ldap_widget,"ldap_timeout")); - linphone_dictionary_set_int(dict, "timeout", (int)gtk_spin_button_get_value(spin) ); - - ms_message("Create LDAP from config"); - // create new LDAP according to the validated config - linphone_gtk_set_ldap( linphone_ldap_contact_provider_create(lc, dict) ); - // save the config to linphonerc: - lp_config_load_dict_to_section(conf, "ldap", dict); - - linphone_dictionary_unref(dict); - - // close widget - gtk_widget_destroy(ldap_widget); - -} - -void linphone_gtk_fill_video_sizes(GtkWidget *combo){ - int i; - int active=0; - char vsize_def[256]; - MSVideoSize cur=linphone_core_get_preferred_video_size(linphone_gtk_get_core()); - const MSVideoSizeDef *def=linphone_core_get_supported_video_sizes(linphone_gtk_get_core());; - /* glade creates a combo box without list model and text renderer, - unless we fill it with a dummy text. - This dummy text needs to be removed first*/ - gtk_combo_box_remove_text(GTK_COMBO_BOX(combo),0); - for(i=0;def->name!=NULL;++def,++i){ - snprintf(vsize_def,sizeof(vsize_def),"%s (%ix%i)",def->name,def->vsize.width,def->vsize.height); - gtk_combo_box_append_text(GTK_COMBO_BOX(combo),vsize_def); - if (cur.width==def->vsize.width && cur.height==def->vsize.height) active=i; - } - gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active); -} - -void linphone_gtk_parameters_closed(GtkWidget *button){ - GtkWidget *pb=gtk_widget_get_toplevel(button); - gtk_widget_destroy(pb); - linphone_gtk_update_status_bar_icons(); -} - -void linphone_gtk_update_my_contact(GtkWidget *w){ - GtkWidget *pb=gtk_widget_get_toplevel(w); - const char *username=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"username"))); - const char *displayname=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"displayname"))); - int port=linphone_core_get_sip_port(linphone_gtk_get_core()); - LinphoneAddress *parsed=linphone_core_get_primary_contact_parsed(linphone_gtk_get_core()); - char *contact; - g_return_if_fail(parsed!=NULL); - if (username[0]=='\0') return; - - linphone_address_set_display_name(parsed,displayname); - linphone_address_set_username(parsed,username); - linphone_address_set_port(parsed,port); - contact=linphone_address_as_string(parsed); - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"sip_address")),contact); - linphone_core_set_primary_contact(linphone_gtk_get_core(),contact); - ms_free(contact); - linphone_address_unref(parsed); - linphone_gtk_load_identities(); -} - -void linphone_gtk_set_propety_entry(GtkWidget *w, gboolean stunServer, gboolean ip){ - GtkWidget *stun_entry=linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"stun_server"); - GtkWidget *ip_entry=linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"nat_address"); - gtk_widget_set_sensitive(stun_entry,stunServer); - gtk_widget_set_sensitive(ip_entry,ip); -} - -void linphone_gtk_stun_server_changed(GtkWidget *w){ - const gchar *addr=gtk_entry_get_text(GTK_ENTRY(w)); - linphone_core_set_stun_server(linphone_gtk_get_core(),addr); -} - -void linphone_gtk_nat_address_changed(GtkWidget *w){ - const gchar *addr=gtk_entry_get_text(GTK_ENTRY(w)); - linphone_core_set_nat_address(linphone_gtk_get_core(),addr); -} - -void linphone_gtk_ipv6_toggled(GtkWidget *w){ - linphone_core_enable_ipv6(linphone_gtk_get_core(), - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))); -} - -void linphone_gtk_min_audio_port_changed(GtkWidget *w){ - GtkWidget *mw = linphone_gtk_get_main_window(); - GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters"); - GtkSpinButton *min_button = GTK_SPIN_BUTTON(w); - GtkSpinButton *max_button = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_max_rtp_port")); - gboolean fixed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "fixed_audio_port"))); - - if (fixed) { - linphone_core_set_audio_port(linphone_gtk_get_core(), (gint) gtk_spin_button_get_value(min_button)); - gtk_spin_button_set_value(max_button, gtk_spin_button_get_value(min_button)); - } else { - gint min_port = (gint)gtk_spin_button_get_value(min_button); - gint max_port = (gint)gtk_spin_button_get_value(max_button); - if (min_port > max_port) { - gtk_spin_button_set_value(max_button, min_port); - max_port = min_port; - } - linphone_core_set_audio_port_range(linphone_gtk_get_core(), min_port, max_port); - } -} - -void linphone_gtk_max_audio_port_changed(GtkWidget *w){ - GtkWidget *mw = linphone_gtk_get_main_window(); - GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters"); - GtkSpinButton *min_button = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_min_rtp_port")); - GtkSpinButton *max_button = GTK_SPIN_BUTTON(w); - gint min_port = (gint)gtk_spin_button_get_value(min_button); - gint max_port = (gint)gtk_spin_button_get_value(max_button); - if (max_port < min_port) { - gtk_spin_button_set_value(min_button, max_port); - min_port = max_port; - } - linphone_core_set_audio_port_range(linphone_gtk_get_core(), min_port, max_port); -} - -void linphone_gtk_min_video_port_changed(GtkWidget *w){ - GtkWidget *mw = linphone_gtk_get_main_window(); - GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters"); - GtkSpinButton *min_button = GTK_SPIN_BUTTON(w); - GtkSpinButton *max_button = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "video_max_rtp_port")); - gboolean fixed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "fixed_video_port"))); - - if (fixed) { - linphone_core_set_video_port(linphone_gtk_get_core(), (gint) gtk_spin_button_get_value(min_button)); - gtk_spin_button_set_value(max_button, gtk_spin_button_get_value(min_button)); - } else { - gint min_port = (gint)gtk_spin_button_get_value(min_button); - gint max_port = (gint)gtk_spin_button_get_value(max_button); - if (min_port > max_port) { - gtk_spin_button_set_value(max_button, min_port); - max_port = min_port; - } - linphone_core_set_video_port_range(linphone_gtk_get_core(), min_port, max_port); - } -} - -void linphone_gtk_max_video_port_changed(GtkWidget *w){ - GtkWidget *mw = linphone_gtk_get_main_window(); - GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters"); - GtkSpinButton *min_button = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "video_min_rtp_port")); - GtkSpinButton *max_button = GTK_SPIN_BUTTON(w); - gint min_port = (gint)gtk_spin_button_get_value(min_button); - gint max_port = (gint)gtk_spin_button_get_value(max_button); - if (max_port < min_port) { - gtk_spin_button_set_value(min_button, max_port); - min_port = max_port; - } - linphone_core_set_video_port_range(linphone_gtk_get_core(), min_port, max_port); -} - -void linphone_gtk_no_firewall_toggled(GtkWidget *w){ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))){ - linphone_gtk_set_propety_entry(w,FALSE,FALSE); - linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyNoFirewall); - } -} - -void linphone_gtk_use_nat_address_toggled(GtkWidget *w){ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))){ - linphone_gtk_set_propety_entry(w,FALSE,TRUE); - linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseNatAddress); - } -} - -void linphone_gtk_use_stun_toggled(GtkWidget *w){ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))){ - linphone_gtk_set_propety_entry(w,TRUE,FALSE); - linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseStun); - } -} - -void linphone_gtk_use_ice_toggled(GtkWidget *w){ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))){ - linphone_gtk_set_propety_entry(w,TRUE,FALSE); - linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseIce); - } -} - -void linphone_gtk_use_upnp_toggled(GtkWidget *w){ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))){ - linphone_gtk_set_propety_entry(w,FALSE,FALSE); - linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseUpnp); - } -} - -void linphone_gtk_mtu_changed(GtkWidget *w){ - if (GTK_WIDGET_SENSITIVE(w)) - linphone_core_set_mtu(linphone_gtk_get_core(),(int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w))); -} - -void linphone_gtk_use_sip_info_dtmf_toggled(GtkWidget *w){ - linphone_core_set_use_info_for_dtmf(linphone_gtk_get_core(), - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))); -} - -void linphone_gtk_mtu_set(GtkWidget *w){ - GtkWidget *mtu=linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"mtu"); - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))){ - gtk_widget_set_sensitive(mtu,TRUE); - linphone_gtk_mtu_changed(mtu); - }else{ - gtk_widget_set_sensitive(mtu,FALSE); - linphone_core_set_mtu(linphone_gtk_get_core(),0); - } -} - -void linphone_gtk_playback_device_changed(GtkWidget *w){ - gchar *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w)); - linphone_core_set_playback_device(linphone_gtk_get_core(),sel); - g_free(sel); -} - -void linphone_gtk_capture_device_changed(GtkWidget *w){ - gchar *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w)); - linphone_core_set_capture_device(linphone_gtk_get_core(),sel); - g_free(sel); -} - -void linphone_gtk_ring_device_changed(GtkWidget *w){ - gchar *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w)); - linphone_core_set_ringer_device(linphone_gtk_get_core(),sel); - g_free(sel); -} - -void linphone_gtk_alsa_special_device_changed(GtkWidget *w){ - /* - const gchar *dev=gtk_entry_get_text(GTK_ENTRY(w)); - ...*/ -} - -void linphone_gtk_cam_changed(GtkWidget *w){ - LinphoneCall *call; - LinphoneCore *lc = linphone_gtk_get_core(); - gchar *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w)); - if (sel){ - if (strcmp(sel, linphone_core_get_video_device(lc)) != 0){ - linphone_core_set_video_device(lc,sel); - if ((call = linphone_core_get_current_call(lc)) != NULL) { - linphone_call_update(call, NULL); - } - } - } - g_free(sel); -} - -void linphone_gtk_video_size_changed(GtkWidget *w){ - int sel=gtk_combo_box_get_active(GTK_COMBO_BOX(w)); - const MSVideoSizeDef *defs=linphone_core_get_supported_video_sizes(linphone_gtk_get_core()); - if (sel<0) return; - linphone_core_set_preferred_video_size(linphone_gtk_get_core(), - defs[sel].vsize); -} - -void linphone_gtk_video_renderer_changed(GtkWidget *w){ - GtkTreeIter iter; - if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(w),&iter)){ - GtkTreeModel *model=gtk_combo_box_get_model(GTK_COMBO_BOX(w)); - gchar *name; - gtk_tree_model_get(model,&iter,0,&name,-1); - linphone_core_set_video_display_filter(linphone_gtk_get_core(),name); - } -} - -void linphone_gtk_video_preset_changed(GtkWidget *w) { - gchar *sel = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w)); - GtkSpinButton *framerate = GTK_SPIN_BUTTON(linphone_gtk_get_widget(gtk_widget_get_toplevel(w), "video_framerate")); - LinphoneCore *lc = linphone_gtk_get_core(); - if (g_strcmp0(sel, "default") == 0) { - linphone_core_set_video_preset(lc, NULL); - gtk_spin_button_set_value(framerate, 0); - gtk_widget_set_sensitive(GTK_WIDGET(framerate), FALSE); - } else if (g_strcmp0(sel, "high-fps") == 0) { - linphone_core_set_video_preset(lc, "high-fps"); - gtk_spin_button_set_value(framerate, 30); - gtk_widget_set_sensitive(GTK_WIDGET(framerate), FALSE); - } else if (g_strcmp0(sel, "custom") == 0) { - linphone_core_set_video_preset(lc, "custom"); - gtk_spin_button_set_value(framerate, 30); - gtk_widget_set_sensitive(GTK_WIDGET(framerate), TRUE); - } - g_free(sel); -} - -void linphone_gtk_ring_file_set(GtkWidget *w){ - gchar *file=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(w)); - linphone_core_set_ring(linphone_gtk_get_core(),file); - g_free(file); -} - -static void linphone_gtk_end_of_ring(LinphoneCore *lc, void *user_data){ - gtk_widget_set_sensitive((GtkWidget*)user_data,TRUE); -} - -void linphone_gtk_play_ring_file(GtkWidget *w){ - if (linphone_core_preview_ring(linphone_gtk_get_core(), - linphone_core_get_ring(linphone_gtk_get_core()), - linphone_gtk_end_of_ring, - w)==0){ - gtk_widget_set_sensitive(w,FALSE); - } -} - -void linphone_gtk_echo_cancelation_toggled(GtkWidget *w){ - linphone_core_enable_echo_cancellation(linphone_gtk_get_core(), - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))); -} - -enum { - CODEC_NAME, - CODEC_RATE, - CODEC_BITRATE, - CODEC_STATUS, - CODEC_PARAMS, - CODEC_PRIVDATA, - CODEC_COLOR, - CODEC_INFO, - CODEC_NCOLUMNS -}; - -static void fmtp_edited(GtkCellRendererText *renderer, gchar *path, gchar *new_text, gpointer userdata){ - GtkListStore *store=(GtkListStore*)userdata; - GtkTreeIter iter; - if (gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store),&iter,path)){ - PayloadType *pt; - gtk_list_store_set(store,&iter,CODEC_PARAMS,new_text,-1); - gtk_tree_model_get(GTK_TREE_MODEL(store),&iter,CODEC_PRIVDATA,&pt,-1); - payload_type_set_recv_fmtp(pt,new_text); - } -} - -static void bitrate_edited(GtkCellRendererText *renderer, gchar *path, gchar *new_text, gpointer userdata){ - GtkListStore *store=(GtkListStore*)userdata; - GtkTreeIter iter; - float newbitrate=0; - - if (!new_text) return; - - if (sscanf(new_text, "%f", &newbitrate)!=1) return; - - if (gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store),&iter,path)){ - PayloadType *pt; - gtk_list_store_set(store,&iter,CODEC_BITRATE,newbitrate,-1); - gtk_tree_model_get(GTK_TREE_MODEL(store),&iter,CODEC_PRIVDATA,&pt,-1); - linphone_core_set_payload_type_bitrate(linphone_gtk_get_core(), pt, (int)newbitrate); - } -} - -static void linphone_gtk_init_codec_list(GtkTreeView *listview){ - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - GtkTreeSelection *select; - GValue editable = {0}; - - GtkListStore *store = gtk_list_store_new (CODEC_NCOLUMNS, G_TYPE_STRING,G_TYPE_INT, - G_TYPE_FLOAT, - G_TYPE_STRING, - G_TYPE_STRING, - G_TYPE_POINTER, - G_TYPE_STRING, - G_TYPE_STRING); - - gtk_tree_view_set_model(listview,GTK_TREE_MODEL(store)); - g_object_unref(G_OBJECT(store)); - - renderer = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes (_("Name"), - renderer, - "text", CODEC_NAME, - "foreground",CODEC_COLOR, - NULL); - gtk_tree_view_append_column (listview, column); - column = gtk_tree_view_column_new_with_attributes (_("Rate (Hz)"), - renderer, - "text", CODEC_RATE, - "foreground",CODEC_COLOR, - NULL); - gtk_tree_view_append_column (listview, column); - column = gtk_tree_view_column_new_with_attributes (_("Status"), - renderer, - "text", CODEC_STATUS, - "foreground",CODEC_COLOR, - NULL); - gtk_tree_view_append_column (listview, column); - - g_value_init(&editable, G_TYPE_BOOLEAN); - g_value_set_boolean(&editable, TRUE); - - renderer = gtk_cell_renderer_text_new (); - g_object_set_property(G_OBJECT(renderer), "editable", &editable); - column = gtk_tree_view_column_new_with_attributes ( - _("IP Bitrate (kbit/s)"), - renderer, - "text", CODEC_BITRATE, - "foreground",CODEC_COLOR, - NULL); - g_signal_connect(G_OBJECT(renderer),"edited",G_CALLBACK(bitrate_edited),store); - gtk_tree_view_append_column (listview, column); - - renderer = gtk_cell_renderer_text_new (); - g_object_set_property(G_OBJECT(renderer), "editable", &editable); - column = gtk_tree_view_column_new_with_attributes ( - _("Parameters"), - renderer, - "text", CODEC_PARAMS, - "foreground",CODEC_COLOR, - NULL); - g_signal_connect(G_OBJECT(renderer),"edited",G_CALLBACK(fmtp_edited),store); - gtk_tree_view_append_column (listview, column); - /* Setup the selection handler */ - select = gtk_tree_view_get_selection (listview); - gtk_tree_selection_set_mode (select, GTK_SELECTION_MULTIPLE); -} - - -const char *get_codec_color(LinphoneCore *lc, OrtpPayloadType *pt){ - const gchar *color; - if (linphone_core_check_payload_type_usability(lc,pt)) color="blue"; - else color="red"; - if (!linphone_core_payload_type_enabled(lc,pt)) { - color="grey"; - } - return color; -} - -static void linphone_gtk_show_codecs(GtkTreeView *listview, const bctbx_list_t *codeclist) -{ - const bctbx_list_t *elem; - GtkTreeIter iter; - GtkListStore *store=GTK_LIST_STORE(gtk_tree_view_get_model(listview)); -// GtkTreeSelection *selection; - - gtk_list_store_clear(store); - - for(elem=codeclist; elem!=NULL; elem=elem->next){ - gchar *status; - gint rate; - gfloat bitrate; - const gchar *color; - const char *params=""; - - OrtpPayloadType *pt=(OrtpPayloadType *)elem->data; - - color=get_codec_color(linphone_gtk_get_core(),pt); - if (linphone_core_payload_type_enabled(linphone_gtk_get_core(),pt)) status=_("Enabled"); - else { - status=_("Disabled"); - } - /* get an iterator */ - gtk_list_store_append(store,&iter); - bitrate=(gfloat)linphone_core_get_payload_type_bitrate(linphone_gtk_get_core(),pt); - rate=payload_type_get_rate(pt); - if (pt->recv_fmtp!=NULL) params=pt->recv_fmtp; - gtk_list_store_set(store,&iter, CODEC_NAME,payload_type_get_mime(pt), - CODEC_RATE,rate, - CODEC_BITRATE,bitrate, - CODEC_STATUS,status, - CODEC_PARAMS,params, - CODEC_PRIVDATA,(gpointer)pt, - CODEC_COLOR,(gpointer)color, - CODEC_INFO,(gpointer)linphone_core_get_payload_type_description(linphone_gtk_get_core(),pt), - -1); - } - - - - /* Setup the selection handler */ -// selection = gtk_tree_view_get_selection (listview); -// gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); - //gtk_tree_view_columns_autosize(GTK_TREE_VIEW (sec->interfaces)); -#if GTK_CHECK_VERSION(2,12,0) - gtk_tree_view_set_tooltip_column(listview,CODEC_INFO); -#endif -} - -static void linphone_gtk_check_codec_bandwidth(GtkTreeView *v){ - GtkTreeIter iter; - GtkTreeModel *model; - model=gtk_tree_view_get_model(v); - g_return_if_fail(gtk_tree_model_get_iter_first(model,&iter)); - do{ - PayloadType *pt=NULL; - - gfloat bitrate; - gtk_tree_model_get(model,&iter,CODEC_PRIVDATA,&pt,-1); - - bitrate=(gfloat)linphone_core_get_payload_type_bitrate(linphone_gtk_get_core(),pt); - gtk_list_store_set(GTK_LIST_STORE(model),&iter,CODEC_COLOR, (gpointer)get_codec_color(linphone_gtk_get_core(),pt), - CODEC_BITRATE, bitrate,-1); - }while(gtk_tree_model_iter_next(model,&iter)); -} - -static void linphone_gtk_select_codec(GtkTreeView *v, PayloadType *ref){ - GtkTreeIter iter; - GtkTreeModel *model; - GtkTreeSelection *selection; - selection=gtk_tree_view_get_selection(v); - model=gtk_tree_view_get_model(v); - g_return_if_fail(gtk_tree_model_get_iter_first(model,&iter)); - do{ - PayloadType *pt=NULL; - gtk_tree_model_get(model,&iter,CODEC_PRIVDATA,&pt,-1); - if (pt==ref){ - gtk_tree_selection_select_iter(selection,&iter); - } - - }while(gtk_tree_model_iter_next(model,&iter)); -} - -static void linphone_gtk_draw_codec_list(GtkTreeView *v, int type){ /* 0=audio, 1=video*/ - const bctbx_list_t *list; - if (type==0) list=linphone_core_get_audio_codecs(linphone_gtk_get_core()); - else list=linphone_core_get_video_codecs(linphone_gtk_get_core()); - linphone_gtk_show_codecs(v,list); -} - -void linphone_gtk_download_bw_changed(GtkWidget *w){ - GtkTreeView *audiov=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"audio_codec_list")); - GtkTreeView *videov=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"video_codec_list")); - linphone_core_set_download_bandwidth(linphone_gtk_get_core(), - (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w))); - linphone_gtk_check_codec_bandwidth(audiov); - linphone_gtk_check_codec_bandwidth(videov); -} - -void linphone_gtk_upload_bw_changed(GtkWidget *w){ - GtkTreeView *audiov=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"audio_codec_list")); - GtkTreeView *videov=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"video_codec_list")); - linphone_core_set_upload_bandwidth(linphone_gtk_get_core(), - (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w))); - linphone_gtk_check_codec_bandwidth(audiov); - linphone_gtk_check_codec_bandwidth(videov); -} - -void linphone_gtk_video_framerate_changed(GtkWidget *w) { - linphone_core_set_preferred_framerate(linphone_gtk_get_core(), - (float)(int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w))); -} - -void linphone_gtk_adaptive_rate_control_toggled(GtkToggleButton *button){ - gboolean active=gtk_toggle_button_get_active(button); - linphone_core_enable_adaptive_rate_control(linphone_gtk_get_core(),active); -} - -static void _g_list_func_destroy_tree_path(gpointer data, gpointer user_data) { - GtkTreePath *tree_path = (GtkTreePath *)data; - gtk_tree_path_free(tree_path); -} - -static void linphone_gtk_codec_move(GtkWidget *button, int dir, int type){ /* 0=audio, 1=video*/ - GtkTreeView *v; - GtkTreeSelection *sel; - GtkTreeModel *mod; - GtkTreeIter iter; - PayloadType *pt=NULL; - LinphoneCore *lc=linphone_gtk_get_core(); - - if (type == 0) v=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(button),"audio_codec_list")); - else v=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(button),"video_codec_list")); - sel=gtk_tree_view_get_selection(v); - if (gtk_tree_selection_count_selected_rows(sel) == 1){ - bctbx_list_t *sel_elem,*before; - bctbx_list_t *codec_list; - - GList *selected_rows = gtk_tree_selection_get_selected_rows(sel, &mod); - gtk_tree_model_get_iter(mod, &iter, (GtkTreePath *)g_list_nth_data(selected_rows, 0)); - gtk_tree_model_get(mod,&iter,CODEC_PRIVDATA,&pt,-1); - g_list_foreach(selected_rows, _g_list_func_destroy_tree_path, NULL); - g_list_free(selected_rows); - - if (pt->type==PAYLOAD_VIDEO) - codec_list=bctbx_list_copy(linphone_core_get_video_codecs(lc)); - else codec_list=bctbx_list_copy(linphone_core_get_audio_codecs(lc)); - sel_elem=bctbx_list_find(codec_list,pt); - if (dir>0) { - if (sel_elem->prev) before=sel_elem->prev; - else before=sel_elem; - codec_list=bctbx_list_insert(codec_list,before,pt); - } - else{ - if (sel_elem->next) before=sel_elem->next->next; - else before=sel_elem; - codec_list=bctbx_list_insert(codec_list,before,pt); - } - codec_list=bctbx_list_erase_link(codec_list,sel_elem); - if (pt->type==PAYLOAD_VIDEO) - linphone_core_set_video_codecs(lc,codec_list); - else linphone_core_set_audio_codecs(lc,codec_list); - linphone_gtk_show_codecs(v,codec_list); - linphone_gtk_select_codec(v,pt); - } -} - -static void linphone_gtk_codec_set_enable(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { - PayloadType *pt=NULL; - gboolean *enabled = (gboolean *)data; - gtk_tree_model_get(model, iter, CODEC_PRIVDATA, &pt, -1); - linphone_core_enable_payload_type(linphone_gtk_get_core(), pt, *enabled); - gtk_list_store_set(GTK_LIST_STORE(model), iter, CODEC_STATUS, *enabled ? _("Enabled") : _("Disabled"), - CODEC_COLOR,(gpointer)get_codec_color(linphone_gtk_get_core(),pt), -1); -} - -static void linphone_gtk_codec_set_enable_all_selected(GtkWidget *button, gboolean enabled, int type){ /* 0=audio, 1=video*/ - GtkTreeView *v; - GtkTreeSelection *sel; - if (type == 0) v=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(button),"audio_codec_list")); - else v=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(button),"video_codec_list")); - sel=gtk_tree_view_get_selection(v); - gtk_tree_selection_selected_foreach(sel, linphone_gtk_codec_set_enable, &enabled); - if (type == 0){ - /*activating audio and video codecs has consequences on video bandwidth*/ - GtkTreeView *videov=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(button),"video_codec_list")); - linphone_gtk_check_codec_bandwidth(videov); - } -} - -void linphone_gtk_audio_codec_up(GtkWidget *button){ - linphone_gtk_codec_move(button,+1,0); -} - -void linphone_gtk_audio_codec_down(GtkWidget *button){ - linphone_gtk_codec_move(button,-1,0); -} - -void linphone_gtk_audio_codec_enable(GtkWidget *button){ - linphone_gtk_codec_set_enable_all_selected(button,TRUE,0); -} - -void linphone_gtk_audio_codec_disable(GtkWidget *button){ - linphone_gtk_codec_set_enable_all_selected(button,FALSE,0); -} - -void linphone_gtk_video_codec_up(GtkWidget *button){ - linphone_gtk_codec_move(button,+1,1); -} - -void linphone_gtk_video_codec_down(GtkWidget *button){ - linphone_gtk_codec_move(button,-1,1); -} - -void linphone_gtk_video_codec_enable(GtkWidget *button){ - linphone_gtk_codec_set_enable_all_selected(button,TRUE,1); -} - -void linphone_gtk_video_codec_disable(GtkWidget *button){ - linphone_gtk_codec_set_enable_all_selected(button,FALSE,1); -} - -void linphone_gtk_clear_passwords(GtkWidget *button){ - linphone_core_clear_all_auth_info(linphone_gtk_get_core()); -} - -enum{ - PROXY_CONFIG_IDENTITY, - PROXY_CONFIG_REF, - PROXY_CONFIG_NCOL -}; - -void linphone_gtk_show_sip_accounts(GtkWidget *w){ - GtkTreeView *v=GTK_TREE_VIEW(linphone_gtk_get_widget(w,"proxy_list")); - GtkTreeModel *model=gtk_tree_view_get_model(v); - GtkListStore *store; - GtkTreeSelection *select; - const LinphoneProxyConfig *default_pc = linphone_core_get_default_proxy_config(linphone_gtk_get_core()); - GtkTreePath *default_pc_path = NULL; - - const bctbx_list_t *elem; - if (!model){ - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - /* create the proxy list */ - store = gtk_list_store_new (PROXY_CONFIG_NCOL, G_TYPE_STRING, G_TYPE_POINTER); - - gtk_tree_view_set_model(v,GTK_TREE_MODEL(store)); - g_object_unref(G_OBJECT(store)); - renderer = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes (_("Account"), - renderer, - "text", PROXY_CONFIG_IDENTITY, - NULL); - gtk_tree_view_append_column (v, column); - - select = gtk_tree_view_get_selection (v); - gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); - model=GTK_TREE_MODEL(store); - }else { - store=GTK_LIST_STORE(model); - } - gtk_list_store_clear(store); - for(elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());elem!=NULL;elem=bctbx_list_next(elem)){ - LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; - GtkTreeIter iter; - gtk_list_store_append(store,&iter); - gtk_list_store_set(store,&iter,PROXY_CONFIG_IDENTITY,linphone_proxy_config_get_identity(cfg), - PROXY_CONFIG_REF,cfg,-1); - if(cfg == default_pc) default_pc_path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter); - } - if(default_pc_path) { - gtk_tree_selection_select_path(gtk_tree_view_get_selection(v), default_pc_path); - gtk_tree_path_free(default_pc_path); - } -} - -static void linphone_gtk_proxy_closed(GtkWidget *w){ - LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)g_object_get_data(G_OBJECT(w),"config"); - gboolean was_editing=! GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"is_new")); - if (cfg){ - if (was_editing){ - linphone_proxy_config_done(cfg); - }else linphone_proxy_config_destroy(cfg); - } -} - -static void fill_transport_combo_box(GtkWidget *combo, LinphoneTransportType choice, gboolean is_sensitive){ - GtkTreeModel *model; - GtkTreeIter iter; - - if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(combo),"combo-updating"))) return; - - if ((model=gtk_combo_box_get_model(GTK_COMBO_BOX(combo)))==NULL){ - /*case where combo box is created with no model*/ - GtkCellRenderer *renderer=gtk_cell_renderer_text_new(); - model=GTK_TREE_MODEL(gtk_list_store_new(1,G_TYPE_STRING)); - gtk_combo_box_set_model(GTK_COMBO_BOX(combo),model); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo),renderer,TRUE); - gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo),renderer,"markup",0,NULL); - } - if (!gtk_tree_model_get_iter_first(model,&iter)){ - gtk_list_store_append(GTK_LIST_STORE(model),&iter); - gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,"UDP",-1); - gtk_list_store_append(GTK_LIST_STORE(model),&iter); - gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,"TCP",-1); - if (linphone_core_sip_transport_supported(linphone_gtk_get_core(),LinphoneTransportTls)){ - gtk_list_store_append(GTK_LIST_STORE(model),&iter); - gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,"TLS",-1); - } - } - gtk_combo_box_set_active(GTK_COMBO_BOX(combo),(int)choice); - gtk_widget_set_sensitive(combo,is_sensitive); -} - -static void update_proxy_transport(GtkWidget *w){ - const char *addr=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy"))); - LinphoneAddress *laddr=linphone_address_new(addr); - if (laddr){ - GtkWidget *combo=linphone_gtk_get_widget(w,"transport"); - if (linphone_address_is_secure(laddr)){ - fill_transport_combo_box(combo,LinphoneTransportTls,FALSE); - }else{ - fill_transport_combo_box(combo,linphone_address_get_transport(laddr),TRUE); - } - linphone_address_unref(laddr); - } -} - -void linphone_gtk_proxy_transport_changed(GtkWidget *combo){ - GtkWidget *w=gtk_widget_get_toplevel(combo); - int index=gtk_combo_box_get_active(GTK_COMBO_BOX(combo)); - GtkWidget *proxy=linphone_gtk_get_widget(w,"proxy"); - const char *addr=gtk_entry_get_text(GTK_ENTRY(proxy)); - LinphoneAddress *laddr; - LinphoneTransportType new_transport=(LinphoneTransportType)index; - - if (index==-1) return; - - g_object_set_data(G_OBJECT(w),"combo-updating",GINT_TO_POINTER(1)); - laddr=linphone_address_new(addr); - if (laddr){ - if (linphone_address_get_transport(laddr)!=new_transport){ - char *newaddr; - linphone_address_set_transport(laddr,new_transport); - newaddr=linphone_address_as_string(laddr); - gtk_entry_set_text(GTK_ENTRY(proxy),newaddr); - ms_free(newaddr); - } - linphone_address_unref(laddr); - } - g_object_set_data(G_OBJECT(w),"combo-updating",GINT_TO_POINTER(0)); -} - -void linphone_gtk_proxy_address_changed(GtkEditable *editable){ - update_proxy_transport(gtk_widget_get_toplevel(GTK_WIDGET(editable))); -} - -void linphone_gtk_show_proxy_config(GtkWidget *pb, LinphoneProxyConfig *cfg){ - GtkWidget *w=linphone_gtk_create_window("sip_account", gtk_widget_get_toplevel(pb)); - const char *tmp; - gboolean is_new=FALSE; - - if (!cfg) { - cfg=linphone_core_create_proxy_config(linphone_gtk_get_core()); - is_new=TRUE; - g_object_set_data(G_OBJECT(w),"is_new",GINT_TO_POINTER(TRUE)); - } - - if (!is_new){ - linphone_proxy_config_edit(cfg); - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"identity")), - linphone_proxy_config_get_identity(cfg)); - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy")),linphone_proxy_config_get_addr(cfg)); - tmp=linphone_proxy_config_get_route(cfg); - if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"route")),tmp); - tmp=linphone_proxy_config_get_contact_parameters(cfg); - if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"params")),tmp); - } - - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"regperiod")), - linphone_proxy_config_get_expires(cfg)); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"register")), - linphone_proxy_config_register_enabled(cfg)); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"publish")), - linphone_proxy_config_publish_enabled(cfg)); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"avpf")), - linphone_proxy_config_avpf_enabled(cfg)); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"avpf_rr_interval")), - linphone_proxy_config_get_avpf_rr_interval(cfg)); - - g_object_set_data(G_OBJECT(w),"config",(gpointer)cfg); - g_object_set_data(G_OBJECT(w),"parameters",(gpointer)pb); - g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_gtk_proxy_closed,w); - gtk_widget_show(w); -} - -void linphone_gtk_proxy_cancel(GtkButton *button){ - GtkWidget *w=gtk_widget_get_toplevel(GTK_WIDGET(button)); - gtk_widget_destroy(w); -} - -void linphone_gtk_proxy_ok(GtkButton *button){ - LinphoneCore *lc=linphone_gtk_get_core(); - GtkWidget *w=gtk_widget_get_toplevel(GTK_WIDGET(button)); - LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)g_object_get_data(G_OBJECT(w),"config"); - int index=gtk_combo_box_get_active(GTK_COMBO_BOX(linphone_gtk_get_widget(w,"transport"))); - LinphoneTransportType tport=(LinphoneTransportType)index; - gboolean was_editing=! GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"is_new")); - - linphone_proxy_config_set_identity(cfg, - gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"identity")))); - if (linphone_proxy_config_set_server_addr(cfg, - gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy"))))==0){ - if (index!=-1){ - /*make sure transport was added to proxy address*/ - LinphoneAddress *laddr=linphone_address_new(linphone_proxy_config_get_addr(cfg)); - if (laddr){ - if (linphone_address_get_transport(laddr)!=tport){ - char *tmp; - linphone_address_set_transport(laddr,tport); - tmp=linphone_address_as_string(laddr); - linphone_proxy_config_set_server_addr(cfg,tmp); - ms_free(tmp); - } - linphone_address_unref(laddr); - } - } - } - linphone_proxy_config_set_route(cfg, - gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"route")))); - linphone_proxy_config_set_contact_parameters(cfg, - gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"params")))); - linphone_proxy_config_set_expires(cfg, - (int)gtk_spin_button_get_value( - GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"regperiod")))); - linphone_proxy_config_enable_publish(cfg, - gtk_toggle_button_get_active( - GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"publish")))); - linphone_proxy_config_enable_register(cfg, - gtk_toggle_button_get_active( - GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"register")))); - linphone_proxy_config_enable_avpf(cfg, - gtk_toggle_button_get_active( - GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"avpf")))); - linphone_proxy_config_set_avpf_rr_interval(cfg, - (int)gtk_spin_button_get_value( - GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"avpf_rr_interval")))); - - /* check if tls was asked but is not enabled in transport configuration*/ - if (tport==LinphoneTransportTls){ - LCSipTransports tports; - linphone_core_get_sip_transports(lc,&tports); - if (tports.tls_port==LC_SIP_TRANSPORT_DISABLED){ - tports.tls_port=LC_SIP_TRANSPORT_RANDOM; - } - linphone_core_set_sip_transports(lc,&tports); - } - - if (was_editing){ - if (linphone_proxy_config_done(cfg)==-1) - return; - } - else { - if (linphone_core_add_proxy_config(linphone_gtk_get_core(),cfg)==-1) return; - linphone_core_set_default_proxy(linphone_gtk_get_core(),cfg); - } - g_object_set_data(G_OBJECT(w),"config",NULL); - linphone_gtk_show_sip_accounts(GTK_WIDGET(g_object_get_data(G_OBJECT(w),"parameters"))); - gtk_widget_destroy(w); - /* also update the main window's list of identities*/ - linphone_gtk_load_identities(); -} - -static LinphoneProxyConfig *linphone_gtk_get_selected_proxy_config(GtkWidget* pb){ - GtkTreeView *v=GTK_TREE_VIEW(linphone_gtk_get_widget(pb,"proxy_list")); - GtkTreeSelection *selection=gtk_tree_view_get_selection(v); - GtkTreeIter iter; - GtkTreeModel *model; - if (gtk_tree_selection_get_selected(selection,&model,&iter)){ - LinphoneProxyConfig *cfg=NULL; - gtk_tree_model_get(model,&iter,PROXY_CONFIG_REF,&cfg,-1); - return cfg; - } - return NULL; -} - -void linphone_gtk_add_proxy(GtkButton *button){ - linphone_gtk_show_proxy_config(gtk_widget_get_toplevel(GTK_WIDGET(button)),NULL); -} - -void linphone_gtk_remove_proxy(GtkButton *button){ - LinphoneProxyConfig *cfg=linphone_gtk_get_selected_proxy_config( - gtk_widget_get_toplevel(GTK_WIDGET(button))); - if (cfg){ - linphone_core_remove_proxy_config(linphone_gtk_get_core(),cfg); - linphone_gtk_show_sip_accounts(gtk_widget_get_toplevel(GTK_WIDGET(button))); - /* also update the main window's list of identities*/ - linphone_gtk_load_identities(); - } -} - -void linphone_gtk_edit_proxy(GtkButton *button){ - GtkWidget *pb=gtk_widget_get_toplevel(GTK_WIDGET(button)); - LinphoneProxyConfig *cfg=linphone_gtk_get_selected_proxy_config(pb); - if (cfg){ - linphone_gtk_show_proxy_config(pb,cfg); - /* also update the main window's list of identities*/ - linphone_gtk_load_identities(); - } -} - -typedef struct _LangCodes{ - const char *code; - const char *name; -}LangCodes; - -static LangCodes supported_langs[]={ - { "C" , N_("English") }, - { "fr" , N_("French") }, - { "sv" , N_("Swedish") }, - { "it" , N_("Italian") }, - { "es" , N_("Spanish") }, - { "pt_BR" , N_("Brazilian Portugese") }, - { "pl" , N_("Polish") }, - { "de" , N_("German") }, - { "ru" , N_("Russian") }, - { "ja" , N_("Japanese") }, - { "nl" , N_("Dutch") }, - { "hu" , N_("Hungarian") }, - { "cs" , N_("Czech") }, - { "zh_CN" , N_("Chinese") }, - { "zh_TW" , N_("Traditional Chinese") }, - { "nb_NO" , N_("Norwegian") }, - { "he" , N_("Hebrew") }, - { "sr" , N_("Serbian") }, - { "ar" , N_("Arabic") }, - { "tr" , N_("Turkish") }, - { "fi" , N_("Finnish") }, - { "lt" , N_("Lithuanian") }, - { NULL , NULL } -}; - -static const char *lang_get_name(const char *code){ - LangCodes *p=supported_langs; - while(p->code!=NULL){ - if (strcmp(p->code,code)==0) return p->name; - p++; - } - return NULL; -} - -static gboolean lang_equals(const char *l1, const char *l2){ - return ((strncmp(l1,l2,5)==0 || strncmp(l1,l2,2)==0)); -} - -static void linphone_gtk_fill_langs(GtkWidget *pb){ - GtkWidget *combo=linphone_gtk_get_widget(pb,"lang_combo"); - char code[10]; - const char *all_langs="C " LINPHONE_ALL_LANGS; - const char *name; - int i=0,index=0; - int cur_lang_index=-1; - char text[256]={0}; - const char *cur_lang = g_getenv("LANGUAGE"); - if (cur_lang==NULL) cur_lang="C"; - /* glade creates a combo box without list model and text renderer, - unless we fill it with a dummy text. - This dummy text needs to be removed first*/ - gtk_combo_box_remove_text(GTK_COMBO_BOX(combo),0); - while(sscanf(all_langs+i,"%s",code)==1){ - i+=strlen(code); - while(all_langs[i]==' ') ++i; - name=lang_get_name(code); - snprintf(text,sizeof(text)-1,"%s : %s",code,name!=NULL ? _(name) : code); - gtk_combo_box_append_text(GTK_COMBO_BOX(combo),text); - if (cur_lang_index==-1 && lang_equals(cur_lang,code)) - cur_lang_index=index; - index++; - } - gtk_combo_box_set_active(GTK_COMBO_BOX(combo),cur_lang_index); -} - -void linphone_gtk_lang_changed(GtkComboBox *combo){ - const char *selected=gtk_combo_box_get_active_text(combo); - char code[10]; - const char *cur_lang=g_getenv("LANGUAGE"); - if (selected!=NULL){ - sscanf(selected,"%s",code); - if (cur_lang==NULL) cur_lang="C"; - if (!lang_equals(cur_lang,code)){ - GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(combo))), - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_INFO, - GTK_BUTTONS_CLOSE, - "%s", - (const gchar*)_("You need to restart linphone for the new language selection to take effect.")); - /* Destroy the dialog when the user responds to it (e.g. clicks a button) */ - g_signal_connect_swapped (G_OBJECT (dialog), "response", - G_CALLBACK (gtk_widget_destroy), - G_OBJECT (dialog)); - gtk_widget_show(dialog); - linphone_gtk_set_lang(code); - } - } -} - -static void linphone_gtk_ui_level_adapt(GtkWidget *top) { - gboolean ui_advanced; - const char *simple_ui = linphone_gtk_get_ui_config("simple_ui", "parameters.codec_tab parameters.transport_frame parameters.ports_frame parameters.bandwidth_frame"); - - ui_advanced = linphone_gtk_get_ui_config_int("advanced_ui", FALSE); - if (ui_advanced) { - linphone_gtk_visibility_set(simple_ui, "parameters", top, TRUE); - } else { - linphone_gtk_visibility_set(simple_ui, "parameters", top, FALSE); - } -} - -void linphone_gtk_ui_level_toggled(GtkWidget *w) { - gint ui_advanced; - GtkWidget *top; - - top = gtk_widget_get_toplevel(w); - ui_advanced = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)); - linphone_gtk_set_ui_config_int("advanced_ui", ui_advanced); - linphone_gtk_ui_level_adapt(top); -} - -static void linphone_gtk_set_media_encryption_mandatory_sensitive(GtkWidget *propbox, gboolean val){ - GtkWidget *w=linphone_gtk_get_widget(propbox,"media_encryption_mandatory_checkbox"); - gtk_widget_set_sensitive(w,val); -} - -static void linphone_gtk_media_encryption_changed(GtkWidget *combo){ - char *selected=gtk_combo_box_get_active_text(GTK_COMBO_BOX(combo)); - LinphoneCore *lc=linphone_gtk_get_core(); - GtkWidget *toplevel=gtk_widget_get_toplevel(combo); - GtkWidget *mandatory_box = linphone_gtk_get_widget(toplevel,"media_encryption_mandatory_checkbox"); - if (selected!=NULL){ - if (strcasecmp(selected,"SRTP")==0){ - linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionSRTP); - gtk_widget_set_sensitive(mandatory_box,TRUE); - }else if (strcasecmp(selected,"DTLS")==0){ - linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionDTLS); - gtk_widget_set_sensitive(mandatory_box,TRUE); - }else if (strcasecmp(selected,"ZRTP")==0){ - linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionZRTP); - gtk_widget_set_sensitive(mandatory_box,TRUE); - } else { - linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionNone); - gtk_widget_set_sensitive(mandatory_box,FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mandatory_box), FALSE); - } - g_free(selected); - }else g_warning("gtk_combo_box_get_active_text() returned NULL"); -} - -void linphone_gtk_set_media_encryption_mandatory(GtkWidget *button){ - linphone_core_set_media_encryption_mandatory(linphone_gtk_get_core(),gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))); -} - -void linphone_gtk_lime_changed(GtkComboBoxText *combotext) { - linphone_core_enable_lime(linphone_gtk_get_core(), gtk_combo_box_get_active(GTK_COMBO_BOX(combotext))); -} - -static void linphone_gtk_show_media_encryption(GtkWidget *pb){ - LinphoneCore *lc=linphone_gtk_get_core(); - GtkWidget *combo=linphone_gtk_get_widget(pb,"media_encryption_combo"); - bool_t no_enc=TRUE; - int srtp_id=-1,zrtp_id=-1,dtls_id=-1; - GtkTreeModel *model; - GtkListStore *store; - GtkTreeIter iter; - GtkCellRenderer *renderer=gtk_cell_renderer_text_new(); - - model=GTK_TREE_MODEL((store=gtk_list_store_new(1,G_TYPE_STRING))); - gtk_combo_box_set_model(GTK_COMBO_BOX(combo),model); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo),renderer,TRUE); - gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo),renderer,"text",0,NULL); - - gtk_list_store_append(store,&iter); - gtk_list_store_set(store,&iter,0,_("None"),-1); - - if (linphone_core_media_encryption_supported(lc,LinphoneMediaEncryptionSRTP)){ - gtk_list_store_append(store,&iter); - gtk_list_store_set(store,&iter,0,_("SRTP"),-1); - srtp_id=1; - no_enc=FALSE; - } - if (linphone_core_media_encryption_supported(lc,LinphoneMediaEncryptionDTLS)){ - gtk_list_store_append(store,&iter); - gtk_list_store_set(store,&iter,0,_("DTLS"),-1); - if (srtp_id!=-1) dtls_id=2; - else dtls_id=1; - no_enc=FALSE; - } - if (linphone_core_media_encryption_supported(lc,LinphoneMediaEncryptionZRTP)){ - gtk_list_store_append(store,&iter); - gtk_list_store_set(store,&iter,0,_("ZRTP"),-1); - no_enc=FALSE; - if (srtp_id!=-1) { - if (dtls_id!=-1) - zrtp_id=3; - else zrtp_id=2; - } else { - if (dtls_id!=-1) - zrtp_id=2; - else zrtp_id=1; - } - } - if (no_enc){ - /*hide this setting*/ - gtk_widget_hide(linphone_gtk_get_widget(pb,"encryption_label")); - gtk_widget_hide(linphone_gtk_get_widget(pb,"encryption_table")); - }else{ - LinphoneMediaEncryption menc=linphone_core_get_media_encryption(lc); - gtk_widget_show(linphone_gtk_get_widget(pb,"encryption_label")); - gtk_widget_show(linphone_gtk_get_widget(pb,"encryption_table")); - - switch(menc){ - case LinphoneMediaEncryptionNone: - gtk_combo_box_set_active(GTK_COMBO_BOX(combo),0); - linphone_gtk_set_media_encryption_mandatory_sensitive(pb,FALSE); - break; - case LinphoneMediaEncryptionSRTP: - if (srtp_id!=-1) { - gtk_combo_box_set_active(GTK_COMBO_BOX(combo),srtp_id); - linphone_gtk_set_media_encryption_mandatory_sensitive(pb,TRUE); - } - break; - case LinphoneMediaEncryptionDTLS: - if (dtls_id!=-1) { - gtk_combo_box_set_active(GTK_COMBO_BOX(combo),dtls_id); - linphone_gtk_set_media_encryption_mandatory_sensitive(pb,TRUE); - } - break; - case LinphoneMediaEncryptionZRTP: - if (zrtp_id!=-1) { - gtk_combo_box_set_active(GTK_COMBO_BOX(combo),zrtp_id); - linphone_gtk_set_media_encryption_mandatory_sensitive(pb,TRUE); - } - break; - } - g_signal_connect(G_OBJECT(combo),"changed",(GCallback)linphone_gtk_media_encryption_changed,NULL); - } - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"media_encryption_mandatory_checkbox")), - linphone_core_is_media_encryption_mandatory(lc)); - - gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"chat_lime_combo")), linphone_core_lime_enabled(lc)); - gtk_widget_set_sensitive(linphone_gtk_get_widget(pb,"chat_lime_combo"), linphone_core_lime_available(lc)); - - g_object_unref(G_OBJECT(model)); -} - -void linphone_gtk_parameters_destroyed(GtkWidget *pb){ - GtkWidget *mw=linphone_gtk_get_main_window(); - g_object_set_data(G_OBJECT(mw),"parameters",NULL); -} - -void linphone_gtk_fill_soundcards(GtkWidget *pb){ - LinphoneCore *lc=linphone_gtk_get_core(); - const char **sound_devices=linphone_core_get_sound_devices(lc); - linphone_gtk_fill_combo_box(linphone_gtk_get_widget(pb,"playback_device"), sound_devices, - linphone_core_get_playback_device(lc),CAP_PLAYBACK); - linphone_gtk_fill_combo_box(linphone_gtk_get_widget(pb,"ring_device"), sound_devices, - linphone_core_get_ringer_device(lc),CAP_PLAYBACK); - linphone_gtk_fill_combo_box(linphone_gtk_get_widget(pb,"capture_device"), sound_devices, - linphone_core_get_capture_device(lc), CAP_CAPTURE); -} - -void linphone_gtk_fill_webcams(GtkWidget *pb){ -#ifdef VIDEO_ENABLED - LinphoneCore *lc=linphone_gtk_get_core(); - linphone_gtk_fill_combo_box(linphone_gtk_get_widget(pb,"webcams"),linphone_core_get_video_devices(lc), - linphone_core_get_video_device(lc),CAP_IGNORE); -#endif -} - -void linphone_gtk_fill_video_renderers(GtkWidget *pb){ -#ifdef VIDEO_ENABLED /* video_stream_get_default_video_renderer requires video enabled */ - LinphoneCore *lc=linphone_gtk_get_core(); - MSFactory *factory = linphone_core_get_ms_factory(lc); - GtkWidget *combo=linphone_gtk_get_widget(pb,"renderers"); - bctbx_list_t *l=ms_factory_lookup_filter_by_interface(factory, MSFilterVideoDisplayInterface); - bctbx_list_t *elem; - int i; - int active=-1; - const char *current_renderer=linphone_core_get_video_display_filter(lc); - GtkListStore *store; - GtkCellRenderer *renderer=gtk_cell_renderer_text_new(); - GtkTreeModel *model=GTK_TREE_MODEL(store=gtk_list_store_new(2,G_TYPE_STRING,G_TYPE_STRING)); - - if (current_renderer==NULL) current_renderer=video_stream_get_default_video_renderer(); - - gtk_combo_box_set_model(GTK_COMBO_BOX(combo),model); - gtk_cell_layout_clear(GTK_CELL_LAYOUT(combo)); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo),renderer,TRUE); - gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo),renderer,"text",1,NULL); - - for(i=0,elem=l;elem!=NULL && i<4 ;elem=elem->next){ - MSFilterDesc *desc=(MSFilterDesc *)elem->data; - GtkTreeIter iter; - - /* do not offer the user to select combo 'decoding/rendering' filter */ - if (desc->enc_fmt != NULL || (desc->flags & MS_FILTER_IS_ENABLED) == 0) - continue; - - gtk_list_store_append(store,&iter); - gtk_list_store_set(store,&iter,0,desc->name,1,desc->text,-1); - if (current_renderer && strcmp(current_renderer,desc->name)==0) - active=i; - - i++; - } - bctbx_list_free(l); - if (active!=-1) gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active); -#endif -} - -void linphone_gtk_fill_video_presets(GtkWidget *pb) { - GtkComboBox *combo = GTK_COMBO_BOX(linphone_gtk_get_widget(pb, "video_preset")); - const char *preset = linphone_core_get_video_preset(linphone_gtk_get_core()); - if (preset == NULL) { - gtk_combo_box_set_active(combo, -1); - gtk_combo_box_set_active(combo, 0); - } else { - gboolean valid; - GtkTreeIter iter; - gchar *str_data; - GtkTreeModel *model = gtk_combo_box_get_model(combo); - valid = gtk_tree_model_get_iter_first(model, &iter); - while (valid) { - gtk_tree_model_get(model, &iter, 0, &str_data, -1); - if (g_strcmp0(preset, str_data) == 0) { - gtk_combo_box_set_active_iter(combo, &iter); - break; - } - valid = gtk_tree_model_iter_next(model, &iter); - } - } -} - -typedef struct { - guint timeout_id; - LCSipTransports tp; -}PortConfigCtx; - -static void port_config_free(PortConfigCtx *ctx){ - g_free(ctx); -} - -static gboolean apply_transports(PortConfigCtx *ctx){ - GtkWidget *mw=linphone_gtk_get_main_window(); - LCSipTransports tp; - LinphoneCore *lc=linphone_gtk_get_core(); - linphone_core_get_sip_transports(lc,&tp); - tp.udp_port=ctx->tp.udp_port; - tp.tcp_port=ctx->tp.tcp_port; - linphone_core_set_sip_transports(lc,&tp); - g_object_set_data(G_OBJECT(mw),"port_config",NULL); - return FALSE; -} - -static PortConfigCtx* get_port_config(void) { - GtkWidget *mw=linphone_gtk_get_main_window(); - PortConfigCtx *cfg=(PortConfigCtx*)g_object_get_data(G_OBJECT(mw),"port_config"); - if (cfg==NULL){ - cfg=g_new0(PortConfigCtx,1); - g_object_set_data_full(G_OBJECT(mw),"port_config",cfg,(GDestroyNotify)port_config_free); - } - if (cfg->timeout_id!=0) { - g_source_remove(cfg->timeout_id); - } - cfg->timeout_id=g_timeout_add_seconds(2,(GSourceFunc)apply_transports,cfg); - return cfg; -} - -static void transport_changed(GtkWidget *parameters){ - PortConfigCtx *cfg = get_port_config(); - - GtkWidget *udp_random_port=linphone_gtk_get_widget(parameters,"random_udp_port"); - GtkWidget *tcp_random_port=linphone_gtk_get_widget(parameters,"random_tcp_port"); - - GtkWidget *sip_udp_port=linphone_gtk_get_widget(parameters,"sip_udp_port"); - GtkWidget *sip_tcp_port=linphone_gtk_get_widget(parameters,"sip_tcp_port"); - - gboolean udp_is_disabled=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(parameters,"disabled_udp_port"))); - gboolean tcp_is_disabled=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(parameters,"disabled_tcp_port"))); - - gboolean udp_is_random=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(udp_random_port)); - gboolean tcp_is_random=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tcp_random_port)); - - int udp_port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(sip_udp_port)); - int tcp_port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(sip_tcp_port)); - - - gtk_widget_set_sensitive(udp_random_port, !udp_is_disabled); - gtk_widget_set_sensitive(tcp_random_port, !tcp_is_disabled); - gtk_widget_set_sensitive(sip_udp_port, !udp_is_disabled && !udp_is_random); - gtk_widget_set_sensitive(sip_tcp_port, !tcp_is_disabled && !tcp_is_random); - - cfg->tp.udp_port=udp_is_disabled?0:udp_is_random?-1:udp_port; - cfg->tp.tcp_port=tcp_is_disabled?0:tcp_is_random?-1:tcp_port; -} - -void linphone_gtk_disabled_udp_port_toggle(GtkCheckButton *button){ - GtkWidget *parameters = gtk_widget_get_toplevel((GtkWidget*)button); - transport_changed(parameters); -} - -void linphone_gtk_random_udp_port_toggle(GtkCheckButton *button){ - GtkWidget *parameters = gtk_widget_get_toplevel((GtkWidget*)button); - transport_changed(parameters); -} - -void linphone_gtk_udp_port_value_changed(GtkSpinButton *button){ - GtkWidget *parameters = gtk_widget_get_toplevel((GtkWidget*)button); - transport_changed(parameters); -} - -void linphone_gtk_disabled_tcp_port_toggle(GtkCheckButton *button){ - GtkWidget *parameters = gtk_widget_get_toplevel((GtkWidget*)button); - transport_changed(parameters); -} - -void linphone_gtk_random_tcp_port_toggle(GtkCheckButton *button){ - GtkWidget *parameters = gtk_widget_get_toplevel((GtkWidget*)button); - transport_changed(parameters); -} - -void linphone_gtk_tcp_port_value_changed(GtkSpinButton *button){ - GtkWidget *parameters = gtk_widget_get_toplevel((GtkWidget*)button); - transport_changed(parameters); -} - -void linphone_gtk_show_parameters(void){ - GtkWidget *mw=linphone_gtk_get_main_window(); - GtkWidget *pb=(GtkWidget*)g_object_get_data(G_OBJECT(mw),"parameters"); - LinphoneCore *lc=linphone_gtk_get_core(); - const char *tmp; - LinphoneAddress *contact; - LinphoneFirewallPolicy pol; - GtkWidget *audio_codec_list; - GtkWidget *video_codec_list; - int mtu; - int ui_advanced; - LCSipTransports tr; - int min_port = 0, max_port = 0; - - if (pb==NULL) { - pb=linphone_gtk_create_window("parameters", linphone_gtk_get_main_window()); - g_object_set_data(G_OBJECT(mw),"parameters",pb); - }else { - gtk_widget_show(pb); - return; - } - audio_codec_list=linphone_gtk_get_widget(pb,"audio_codec_list"); - video_codec_list=linphone_gtk_get_widget(pb,"video_codec_list"); - - /* NETWORK CONFIG */ - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"ipv6_enabled")), - linphone_core_ipv6_enabled(lc)); - linphone_core_get_sip_transports(lc,&tr); - - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"disabled_udp_port")), tr.udp_port==0); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"disabled_tcp_port")), tr.tcp_port==0); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"random_udp_port")), tr.udp_port==-1); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"random_tcp_port")), tr.tcp_port==-1); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"sip_udp_port")), tr.udp_port); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"sip_tcp_port")), tr.tcp_port); - - linphone_core_get_audio_port_range(lc, &min_port, &max_port); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_min_rtp_port")), min_port); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_max_rtp_port")), max_port); - if (min_port == max_port) { - gtk_widget_set_sensitive(GTK_WIDGET(linphone_gtk_get_widget(pb, "audio_max_rtp_port")), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "fixed_audio_port")), TRUE); - } - linphone_core_get_video_port_range(lc, &min_port, &max_port); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "video_min_rtp_port")), min_port); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "video_max_rtp_port")), max_port); - if (min_port == max_port) { - gtk_widget_set_sensitive(GTK_WIDGET(linphone_gtk_get_widget(pb, "video_max_rtp_port")), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "fixed_video_port")), TRUE); - } - - linphone_gtk_show_media_encryption(pb); - - tmp=linphone_core_get_nat_address(lc); - if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"nat_address")),tmp); - tmp=linphone_core_get_stun_server(lc); - if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"stun_server")),tmp); - pol=linphone_core_get_firewall_policy(lc); - switch(pol){ - case LinphonePolicyNoFirewall: - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"no_nat")),TRUE); - break; - case LinphonePolicyUseNatAddress: - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_nat_address")),TRUE); - break; - case LinphonePolicyUseStun: - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_stun")),TRUE); - break; - case LinphonePolicyUseIce: - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_ice")),TRUE); - break; - case LinphonePolicyUseUpnp: - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_upnp")),TRUE); - break; - } - if(!linphone_core_upnp_available()) { - gtk_widget_hide(linphone_gtk_get_widget(pb,"use_upnp")); - } - gtk_widget_hide(linphone_gtk_get_widget(pb, "use_nat_address")); - gtk_widget_hide(linphone_gtk_get_widget(pb, "nat_address")); - gtk_widget_hide(linphone_gtk_get_widget(pb, "nat_address_label")); - - mtu=linphone_core_get_mtu(lc); - if (mtu<=0){ - gtk_widget_set_sensitive(linphone_gtk_get_widget(pb,"mtu"),FALSE); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"mtu")),1500); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"mtu_set")),FALSE); - }else{ - gtk_widget_set_sensitive(linphone_gtk_get_widget(pb,"mtu"),TRUE); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"mtu")),mtu); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"mtu_set")),TRUE); - } - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"dtmf_sipinfo")), - linphone_core_get_use_info_for_dtmf(lc)); - /* MUTIMEDIA CONFIG */ - linphone_gtk_fill_soundcards(pb); - linphone_gtk_fill_webcams(pb); - linphone_gtk_fill_video_renderers(pb); - linphone_gtk_fill_video_presets(pb); - linphone_gtk_fill_video_sizes(linphone_gtk_get_widget(pb,"video_size")); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"video_framerate")), - linphone_core_get_preferred_framerate(lc)); -#ifndef VIDEO_ENABLED - gtk_widget_set_visible(linphone_gtk_get_widget(pb, "camera_preview_button"),FALSE); -#endif - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"echo_cancelation")), - linphone_core_echo_cancellation_enabled(lc)); - - gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(linphone_gtk_get_widget(pb,"ring_chooser")), - linphone_core_get_ring(lc)); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"adaptive_rate_control")), - linphone_core_adaptive_rate_control_enabled(lc)); - /* SIP CONFIG */ - contact=linphone_core_get_primary_contact_parsed(lc); - if (contact){ - if (linphone_address_get_display_name(contact)) { - const char *dn=linphone_address_get_display_name(contact); - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"displayname")),dn); - } - if (linphone_address_get_username(contact)) - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"username")),linphone_address_get_username(contact)); - linphone_address_unref(contact); - } -#ifdef BUILD_WIZARD - gtk_widget_show(linphone_gtk_get_widget(pb,"wizard")); -#else - gtk_widget_hide(linphone_gtk_get_widget(pb,"wizard")); -#endif - linphone_gtk_show_sip_accounts(pb); - /* CODECS CONFIG */ - linphone_gtk_init_codec_list(GTK_TREE_VIEW(audio_codec_list)); - linphone_gtk_init_codec_list(GTK_TREE_VIEW(video_codec_list)); - linphone_gtk_draw_codec_list(GTK_TREE_VIEW(audio_codec_list), 0); - linphone_gtk_draw_codec_list(GTK_TREE_VIEW(video_codec_list), 1); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"download_bw")), - linphone_core_get_download_bandwidth(lc)); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"upload_bw")), - linphone_core_get_upload_bandwidth(lc)); - - /* CALL PARAMS CONFIG */ - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "auto_answer_checkbox")), linphone_gtk_auto_answer_enabled()); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "auto_answer_delay_spinbutton")), linphone_gtk_get_ui_config_int("auto_answer_delay", 2000)); - - /* UI CONFIG */ - linphone_gtk_fill_langs(pb); - ui_advanced = linphone_gtk_get_ui_config_int("advanced_ui", 1); - linphone_gtk_set_ui_config_int("advanced_ui", ui_advanced); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"ui_level")), - ui_advanced); - linphone_gtk_ui_level_adapt(pb); - - if (linphone_core_tunnel_available()){ - gtk_widget_set_visible(GTK_WIDGET(linphone_gtk_get_widget(pb,"tunnel_edit_button")), TRUE); - gtk_widget_set_visible(GTK_WIDGET(linphone_gtk_get_widget(pb,"tunnel_label")), TRUE); - } - - /* LDAP CONFIG */ - if( linphone_gtk_is_ldap_supported() ) { // if LDAP provider is available - linphone_gtk_ldap_display(pb); - } else { - // hide the LDAP tab - GtkNotebook* notebook = GTK_NOTEBOOK(linphone_gtk_get_widget(pb, "notebook1")); - gtk_notebook_remove_page(notebook,5); - } - - gtk_widget_show(pb); -} - - -void linphone_gtk_fixed_audio_port_toggle(void) { - GtkWidget *mw = linphone_gtk_get_main_window(); - GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters"); - gboolean fixed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "fixed_audio_port"))); - gint min_port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_min_rtp_port"))); - gint max_port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_max_rtp_port"))); - gtk_widget_set_sensitive(GTK_WIDGET(linphone_gtk_get_widget(pb, "audio_max_rtp_port")), !fixed); - if (fixed) { - linphone_core_set_audio_port(linphone_gtk_get_core(), min_port); - } else { - linphone_core_set_audio_port_range(linphone_gtk_get_core(), min_port, max_port); - } -} - - -void linphone_gtk_fixed_video_port_toggle(void) { - GtkWidget *mw = linphone_gtk_get_main_window(); - GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters"); - gboolean fixed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "fixed_video_port"))); - gint min_port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "video_min_rtp_port"))); - gint max_port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "video_max_rtp_port"))); - gtk_widget_set_sensitive(GTK_WIDGET(linphone_gtk_get_widget(pb, "video_max_rtp_port")), !fixed); - if (fixed) { - linphone_core_set_video_port(linphone_gtk_get_core(), min_port); - } else { - linphone_core_set_video_port_range(linphone_gtk_get_core(), min_port, max_port); - } -} - - -void linphone_gtk_edit_tunnel_closed(GtkWidget *button){ - GtkWidget *pb=gtk_widget_get_toplevel(button); - gtk_widget_destroy(pb); -} - -void linphone_gtk_edit_tunnel(GtkButton *button){ - GtkWidget *w=linphone_gtk_create_window("tunnel_config", gtk_widget_get_toplevel(GTK_WIDGET(button))); - LinphoneCore *lc=linphone_gtk_get_core(); - LinphoneTunnel *tunnel=linphone_core_get_tunnel(lc); - const bctbx_list_t *configs; - const char *host = NULL; - int port=0; - - if (!tunnel) return; - - configs = linphone_tunnel_get_servers(tunnel); - if(configs != NULL) { - LinphoneTunnelConfig *ltc = (LinphoneTunnelConfig *)configs->data; - host = linphone_tunnel_config_get_host(ltc); - port = linphone_tunnel_config_get_port(ltc); - } - - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"host")),host); - if (port==0) port=443; - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"port")), port); - - switch(linphone_tunnel_get_mode(tunnel)){ - case LinphoneTunnelModeDisable: - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"radio_disable")),1); - break; - case LinphoneTunnelModeEnable: - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"radio_enable")),1); - break; - case LinphoneTunnelModeAuto: - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"tunnel_autodetect")),1); - break; - } - { - const char *proxy=NULL,*username=NULL,*password=NULL; - port=0; - linphone_tunnel_get_http_proxy(tunnel,&proxy,&port,&username,&password); - if (proxy) - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"http_host")),proxy); - if (port>0) - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"http_port")), port); - if (username) - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"username")),username); - if (password) - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"password")),password); - } - - g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_gtk_edit_tunnel_closed,w); - gtk_widget_show(w); -} - -void linphone_gtk_tunnel_ok(GtkButton *button){ - GtkWidget *w=gtk_widget_get_toplevel(GTK_WIDGET(button)); - LinphoneCore *lc=linphone_gtk_get_core(); - LinphoneTunnel *tunnel=linphone_core_get_tunnel(lc); - LinphoneTunnelConfig *config=linphone_tunnel_config_new(); - - gint port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"port"))); - gboolean enabled=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"radio_enable"))); - gboolean autodetect=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"tunnel_autodetect"))); - const char *host=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"host"))); - const char *http_host=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"http_host"))); - gint http_port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"http_port"))); - const char *username=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"username"))); - const char *password=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"password"))); - LinphoneTunnelMode mode = LinphoneTunnelModeDisable; - - if (tunnel==NULL) return; - if (host && *host=='\0') host=NULL; - if (http_port==0) http_port=8080; - linphone_tunnel_clean_servers(tunnel); - linphone_tunnel_config_set_host(config, host); - linphone_tunnel_config_set_port(config, port); - linphone_tunnel_add_server(tunnel, config); - - if (enabled){ - mode = LinphoneTunnelModeEnable; - }else if (autodetect){ - mode = LinphoneTunnelModeAuto; - } - linphone_tunnel_set_mode(tunnel, mode); - linphone_tunnel_set_http_proxy(tunnel,http_host,http_port,username,password); - - gtk_widget_destroy(w); -} - - -void linphone_gtk_tunnel_cancel(GtkButton *button){ - -} - -static void show_dscp(GtkWidget *entry, int val){ - char tmp[20]; - snprintf(tmp,sizeof(tmp),"0x%x",val); - gtk_entry_set_text(GTK_ENTRY(entry),tmp); - -} - -static int read_dscp(GtkWidget *entry){ - const char *val=gtk_entry_get_text(GTK_ENTRY(entry)); - const char *begin; - int ret=0; - if (val==NULL || val[0]=='\0') return 0; - /*skip potential 0x*/ - begin=strstr(val,"0x"); - if (begin) begin+=2; - else begin=val; - if (sscanf(begin,"%x",&ret)==1) - return ret; - return -1; -} - -void linphone_gtk_dscp_edit(void){ - LinphoneCore *lc=linphone_gtk_get_core(); - GtkWidget *widget=linphone_gtk_create_window("dscp_settings", linphone_gtk_get_main_window()); - show_dscp(linphone_gtk_get_widget(widget,"sip_dscp"), - linphone_core_get_sip_dscp(lc)); - show_dscp(linphone_gtk_get_widget(widget,"audio_dscp"), - linphone_core_get_audio_dscp(lc)); - show_dscp(linphone_gtk_get_widget(widget,"video_dscp"), - linphone_core_get_video_dscp(lc)); - gtk_widget_show(widget); -} - -void linphone_gtk_dscp_edit_response(GtkWidget *dialog, guint response_id){ - LinphoneCore *lc=linphone_gtk_get_core(); - switch(response_id){ - case GTK_RESPONSE_OK: - linphone_core_set_sip_dscp(lc, - read_dscp(linphone_gtk_get_widget(dialog,"sip_dscp"))); - linphone_core_set_audio_dscp(lc, - read_dscp(linphone_gtk_get_widget(dialog,"audio_dscp"))); - linphone_core_set_video_dscp(lc, - read_dscp(linphone_gtk_get_widget(dialog,"video_dscp"))); - - break; - default: - break; - } - gtk_widget_destroy(dialog); -} - -void linphone_gtk_enable_auto_answer(GtkToggleButton *checkbox, gpointer user_data) { - gboolean auto_answer_enabled = gtk_toggle_button_get_active(checkbox); - linphone_gtk_set_ui_config_int("auto_answer", auto_answer_enabled ? 1 : 0); -} - -gboolean linphone_gtk_auto_answer_enabled(void) { - return (gboolean)linphone_gtk_get_ui_config_int("auto_answer", 0); -} - -void linphone_gtk_auto_answer_delay_changed(GtkSpinButton *spinbutton, gpointer user_data) { - int delay = (int)gtk_spin_button_get_value(spinbutton); - linphone_gtk_set_ui_config_int("auto_answer_delay", delay); -} - -void linphone_gtk_notebook_current_page_changed (GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data) { -#ifndef HAVE_LIBUDEV_H - if (page_num == 1) { - // Multimedia settings - we reload audio and video devices to detect - // hot-plugged devices - g_message("Opened multimedia page... reloading audio and video devices!"); - linphone_gtk_reload_sound_devices(); - linphone_gtk_reload_video_devices(); - } -#endif -} diff --git a/gtk/provisioning-fetch.ui b/gtk/provisioning-fetch.ui deleted file mode 100644 index e2d6a0203..000000000 --- a/gtk/provisioning-fetch.ui +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - False - 5 - Configuring... - dialog - True - Please wait while fetching configuration from server... - - - True - False - 2 - - - True - False - end - - - - - - - - - False - True - end - 0 - - - - - True - False - - - - - - True - True - 2 - - - - - - diff --git a/gtk/regex.h b/gtk/regex.h deleted file mode 100644 index f5b41d40d..000000000 --- a/gtk/regex.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2015 Belledonne Communications - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -/* - * Regex matching with any URI that respects the RFC 3986 - */ -#define BC_REGEX_URI_PCT_ENCODED "(%[[:xdigit:]]{2})" -#define BC_REGEX_URI_SUB_DELIMS "[!$&'()*+,;=]" -#define BC_REGEX_URI_UNRESERVED "[[:alnum:]\\-._~]" -#define BC_REGEX_URI_PCHAR "(" BC_REGEX_URI_UNRESERVED "|" BC_REGEX_URI_PCT_ENCODED "|" BC_REGEX_URI_SUB_DELIMS "|" "[:@]" ")" -#define BC_REGEX_URI_SCHEME "(" "[[:alpha:]][[:alnum:]+\\-.]*" ")" -#define BC_REGEX_URI_USERINFO "(" "(" BC_REGEX_URI_UNRESERVED "|" BC_REGEX_URI_PCT_ENCODED "|" BC_REGEX_URI_SUB_DELIMS "|" ":" ")*" ")" -#define BC_REGEX_URI_HOST "(" "(" BC_REGEX_URI_UNRESERVED "|" BC_REGEX_URI_PCT_ENCODED "|" BC_REGEX_URI_SUB_DELIMS ")*" ")" -#define BC_REGEX_URI_PORT "(" "[\\d]*" ")" -#define BC_REGEX_URI_AUTHORITY "(" "(" BC_REGEX_URI_USERINFO "@" ")?" BC_REGEX_URI_HOST "(" ":" BC_REGEX_URI_PORT ")?" ")" -#define BC_REGEX_URI_SEGMENT "(" BC_REGEX_URI_PCHAR "*" ")" -#define BC_REGEX_URI_SEGMENT_NZ "(" BC_REGEX_URI_PCHAR "+" ")" -#define BC_REGEX_URI_PATH_ABEMPTY "(" "(" "/" BC_REGEX_URI_SEGMENT ")*" ")" -#define BC_REGEX_URI_PATH_ABSOLUTE "(" "/" "(" BC_REGEX_URI_SEGMENT_NZ "(" "/" BC_REGEX_URI_SEGMENT ")*" ")?" ")" -#define BC_REGEX_URI_PATH_ROOTLESS "(" BC_REGEX_URI_SEGMENT_NZ "(" "/" BC_REGEX_URI_SEGMENT ")*" ")" -#define BC_REGEX_URI_HIER_PART "(" "//" BC_REGEX_URI_AUTHORITY BC_REGEX_URI_PATH_ABEMPTY "|" BC_REGEX_URI_PATH_ABSOLUTE "|" BC_REGEX_URI_PATH_ROOTLESS ")" -#define BC_REGEX_URI_QUERY "(" "(" BC_REGEX_URI_PCHAR "|" "[/?]" ")*" ")" -#define BC_REGEX_URI_FRAGMENT "(" "(" BC_REGEX_URI_PCHAR "|" "[/?]" ")*" ")" -#define BC_REGEX_URI "(" BC_REGEX_URI_SCHEME ":" BC_REGEX_URI_HIER_PART "(" "\\?" BC_REGEX_URI_QUERY ")?" "(" "#" BC_REGEX_URI_FRAGMENT ")?" ")" - -/* - * Regex matching with any domain name (RFC 1034) - */ -#define BC_REGEX_DOMAIN_LDH "[[:alnum:]-]" -#define BC_REGEX_DOMAIN_LABEL "(" "[[:alpha:]]" "(" BC_REGEX_DOMAIN_LDH "*" "[[:alnum:]]" ")?" ")" -#define BC_REGEX_DOMAIN "(" BC_REGEX_DOMAIN_LABEL "(" "\\." BC_REGEX_DOMAIN_LABEL ")*" ")" - -/* - * Regex matching with email addresses (RFC 5322) - */ -#define BC_REGEX_EMAIL_ATEXT "[[:alnum:]!#$%&'*+\\-/=?\\^_`{}|~]" -#define BC_REGEX_EMAIL_DOT_ATOM_TEXT "(" BC_REGEX_EMAIL_ATEXT "+" "(" "." BC_REGEX_EMAIL_ATEXT "+" ")*" ")" -#define BC_REGEX_EMAIL_LOCAL_PART BC_REGEX_EMAIL_DOT_ATOM_TEXT -#define BC_REGEX_EMAIL_DTEXT_NO_OBS "[!-Z\\^-~]" -#define BC_REGEX_EMAIL_DOMAIN "(" BC_REGEX_EMAIL_DOT_ATOM_TEXT "|" "\\[" BC_REGEX_EMAIL_DTEXT_NO_OBS "*" "\\]" ")" -#define BC_REGEX_EMAIL_ADDR_SPEC "(" BC_REGEX_EMAIL_LOCAL_PART "@" BC_REGEX_EMAIL_DOMAIN ")" - -/* - * Regex matching with email addresses but with more constraints than RFC 5322. - * The additionnal constraints are the folowings: - * + the domain part is a domain name as describe in RFC 1034 - * + the domain part must have two label at least - * + the last label of the domain part must have two letter (without digit and hyphen) at least. - */ -#define BC_REGEX_RESTRICTIVE_EMAIL_TLD "(" "[[:alpha:]]" BC_REGEX_DOMAIN_LDH "*" "[[:alnum:]]" ")" -#define BC_REGEX_RESTRICTIVE_EMAIL_ADDR "(" BC_REGEX_EMAIL_LOCAL_PART "@" "(" BC_REGEX_DOMAIN_LABEL "\\." ")+" BC_REGEX_RESTRICTIVE_EMAIL_TLD ")" diff --git a/gtk/setup_wizard.ui b/gtk/setup_wizard.ui deleted file mode 100644 index 95cdcc4e2..000000000 --- a/gtk/setup_wizard.ui +++ /dev/null @@ -1,736 +0,0 @@ - - - - - - False - 8 - SIP account configuration assistant - False - - - - - - - - - - - - - - - - - - - - - - - - - - - True - False - Welcome! -This assistant will help you to use a SIP account for your calls. - - - intro - Welcome to the account setup assistant - True - - - - - True - False - 20 - 30 - 30 - - - True - False - True - - - Create an account on linphone.org - True - True - False - True - True - - - False - True - 0 - - - - - I have already a linphone.org account and I just want to use it - True - True - False - True - radio_create_account - - - False - True - 1 - - - - - I have already a sip account and I just want to use it - True - True - False - True - radio_create_account - - - False - True - 2 - - - - - I want to specify a remote configuration URI - True - True - False - True - radio_create_account - - - False - True - 3 - - - - - - - Account setup assistant - True - - - - - True - False - 0 - 0 - 0.5 - 30 - 10 - 30 - - - True - False - 6 - 2 - 8 - 4 - - - True - False - 8 - Enter your account information - - - 2 - GTK_FILL - - - - - True - False - 1 - Username* - - - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - True - - True - False - False - True - True - - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - True - False - 1 - Password* - - - 2 - 3 - GTK_FILL - GTK_FILL - - - - - True - True - False - - True - False - False - True - True - - - - 1 - 2 - 2 - 3 - GTK_FILL - - - - - True - False - 1 - Domain* - - - 3 - 4 - GTK_FILL - GTK_FILL - - - - - True - True - - True - False - False - True - True - - - - 1 - 2 - 3 - 4 - GTK_FILL - - - - - True - False - 1 - Proxy - - - 4 - 5 - GTK_FILL - GTK_FILL - - - - - True - True - - True - False - False - True - True - - - - 1 - 2 - 4 - 5 - GTK_FILL - GTK_FILL - - - - - True - False - - - - - - 2 - 5 - 6 - GTK_FILL - - - - - - - confirm - Configure your account (step 1/1) - - - - - True - False - 0 - 0.5 - 30 - 10 - 30 - 30 - - - True - False - 8 - 3 - 2 - 8 - 4 - - - True - False - 8 - Enter your linphone.org username - - - 2 - GTK_FILL - - - - - True - False - 1 - Username: - - - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - True - - True - False - False - True - True - - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - True - False - 1 - Password: - - - 2 - 3 - GTK_FILL - GTK_FILL - - - - - True - True - False - - True - False - False - True - True - - - 1 - 2 - 2 - 3 - GTK_FILL - - - - - - - confirm - Enter your sip username (step 1/1) - - - - - True - False - 0 - 0.5 - 10 - 10 - 30 - 30 - - - True - False - 8 - 7 - 3 - 8 - 4 - - - True - False - (*) Required fields - - - 3 - 8 - - - - - True - False - 1 - Email: (*) - - - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - True - - True - False - False - True - True - - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - True - False - gtk-no - 3 - - - 2 - 3 - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - False - 1 - Username: (*) - - - 2 - 3 - GTK_FILL - GTK_FILL - - - - - True - True - - True - False - False - True - True - - - - 1 - 2 - 2 - 3 - GTK_FILL - - - - - True - False - gtk-no - 3 - - - 2 - 3 - 2 - 3 - - - - - - - True - False - 1 - Password: (*) - - - 3 - 4 - GTK_FILL - GTK_FILL - - - - - True - True - False - - True - False - False - True - True - - - - 1 - 2 - 3 - 4 - GTK_FILL - - - - - True - False - 1 - Confirm your password: (*) - - - 4 - 5 - GTK_FILL - GTK_FILL - - - - - True - True - False - - True - False - False - True - True - - - - 1 - 2 - 4 - 5 - GTK_FILL - - - - - True - False - gtk-no - 3 - - - 2 - 3 - 3 - 5 - - - - - - - True - False - - - - - - 3 - 5 - 6 - - - - - - - - confirm - Enter account information (step 1/2) - - - - - True - False - Your account is being created, please wait. - - - progress - Account creation in progress - - - - - True - False - Please validate your account by clicking on the link we just sent you by email. -Then come back here and press Next button. - - - Validation (step 2/2) - True - - - - - True - False - Checking if your account is been validated, please wait. - - - progress - Account validation check in progress - True - - - - - True - False - Error, account not validated, username already used or server unreachable. -Please go back and try again. - - - Error - - - - - True - False - Thank you. Your account is now configured and ready for use. - - - summary - Terminating - True - - - - diff --git a/gtk/setupwizard.c b/gtk/setupwizard.c deleted file mode 100644 index 4ea81bac9..000000000 --- a/gtk/setupwizard.c +++ /dev/null @@ -1,360 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "linphone.h" -#include "regex.h" -#include -#include - -static const int PASSWORD_MIN_SIZE = 6; -static const int LOGIN_MIN_SIZE = 4; -static GtkWidget *the_assistant = NULL; - - -static LinphoneAccountCreator * linphone_gtk_assistant_get_creator(GtkWidget *w) { - return (LinphoneAccountCreator *)g_object_get_data(G_OBJECT(w), "creator"); -} - -static void linphone_gtk_create_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreatorStatus status, const char* resp) { - GtkWidget *assistant = (GtkWidget *)linphone_account_creator_get_user_data(creator); - if (status == LinphoneAccountCreatorStatusAccountCreated) { - // Go to page_6_linphone_account_validation_wait - gtk_assistant_set_current_page(GTK_ASSISTANT(assistant), 6); - } else { // Error when attempting to create the account - // Go to page_8_error - gtk_assistant_set_current_page(GTK_ASSISTANT(assistant), 8); - } - gtk_assistant_commit(GTK_ASSISTANT(assistant)); -} - -static void create_account(GtkWidget *assistant) { - LinphoneAccountCreator *creator = linphone_gtk_assistant_get_creator(assistant); - linphone_account_creator_create_account(creator); -} - -static void linphone_gtk_test_account_validation_cb(LinphoneAccountCreator *creator, LinphoneAccountCreatorStatus status, const char* resp) { - GtkWidget *assistant = (GtkWidget *)linphone_account_creator_get_user_data(creator); - if (status == LinphoneAccountCreatorStatusAccountActivated) { - // Go to page_9_finish - gtk_assistant_set_current_page(GTK_ASSISTANT(assistant), 9); - } else { - // Go to page_8_error - gtk_assistant_set_current_page(GTK_ASSISTANT(assistant), 8); - } -} - -static void check_account_validation(GtkWidget *assistant) { - LinphoneAccountCreator *creator = linphone_gtk_assistant_get_creator(assistant); - linphone_account_creator_is_account_activated(creator); -} - -void linphone_gtk_assistant_closed(GtkWidget *w) { - linphone_gtk_close_assistant(); -} - -void linphone_gtk_assistant_prepare(GtkWidget *assistant) { - int pagenum = gtk_assistant_get_current_page(GTK_ASSISTANT(assistant)); - - switch (pagenum) { - case 5: - create_account(assistant); - break; - case 7: - check_account_validation(assistant); - break; - case 9: - if (linphone_account_creator_configure(linphone_gtk_assistant_get_creator(assistant)) != NULL) { - linphone_gtk_load_identities(); - } - gtk_assistant_commit(GTK_ASSISTANT(assistant)); - break; - default: - break; - } -} - -static gint destroy_assistant(GtkWidget* w){ - gtk_widget_destroy(w); - the_assistant = NULL; - return FALSE; -} - -static int linphone_gtk_assistant_forward(int curpage, gpointer data) { - GtkWidget *w = GTK_WIDGET(data); - LinphoneAccountCreator *creator = linphone_gtk_assistant_get_creator(w); - - switch (curpage) { - case 0: - curpage = 1; // Go to page_1_choice - break; - case 1: - { - GtkWidget *create_button = linphone_gtk_get_widget(w, "radio_create_account"); - GtkWidget *setup_linphone_account = linphone_gtk_get_widget(w, "radio_setup_lp_account"); - GtkWidget *setup_account = linphone_gtk_get_widget(w, "radio_setup_account"); - GtkWidget *config_uri = linphone_gtk_get_widget(w, "radio_config_uri"); - - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(create_button))) { - curpage = 4; // Go to page_4_linphone_account_creation_configuration - } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(setup_linphone_account))) { - curpage = 3; // Go to page_3_linphone_account_configuration - } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(setup_account))) { - curpage = 2; // Go to page_2_external_account_configuration - } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_uri))) { - /* Destroy the assistant and popup config-uri dialog */ - gtk_widget_hide(w); - linphone_gtk_set_configuration_uri(); - curpage = 0; - g_idle_add((GSourceFunc)destroy_assistant, w); - } - } - break; - case 2: - { - GtkEntry *username_entry = GTK_ENTRY(linphone_gtk_get_widget(w, "p2_entry_username")); - GtkEntry *domain_entry = GTK_ENTRY(linphone_gtk_get_widget(w, "p2_entry_domain")); - GtkEntry *proxy_entry = GTK_ENTRY(linphone_gtk_get_widget(w, "p2_entry_proxy")); - GtkEntry *password_entry = GTK_ENTRY(linphone_gtk_get_widget(w, "p2_entry_password")); - linphone_account_creator_set_username(creator, gtk_entry_get_text(username_entry)); - linphone_account_creator_set_domain(creator, gtk_entry_get_text(domain_entry)); - linphone_account_creator_set_route(creator, gtk_entry_get_text(proxy_entry)); - linphone_account_creator_set_password(creator, gtk_entry_get_text(password_entry)); - curpage = 9; // Go to page_9_finish - break; - } - case 3: - { - GtkEntry *username_entry = GTK_ENTRY(linphone_gtk_get_widget(w, "p3_entry_username")); - GtkEntry *password_entry = GTK_ENTRY(linphone_gtk_get_widget(w, "p3_entry_password")); - linphone_account_creator_set_username(creator, gtk_entry_get_text(username_entry)); - linphone_account_creator_set_domain(creator, "sip.linphone.org"); - linphone_account_creator_set_route(creator, "sip.linphone.org"); - linphone_account_creator_set_password(creator, gtk_entry_get_text(password_entry)); - curpage = 9; // Go to page_9_finish - break; - } - case 4: - { - GtkEntry *password_entry = GTK_ENTRY(linphone_gtk_get_widget(w, "p4_entry_password1")); - GtkEntry *username_entry = GTK_ENTRY(linphone_gtk_get_widget(w, "p4_entry_username")); - GtkEntry *email_entry = GTK_ENTRY(linphone_gtk_get_widget(w, "p4_entry_email")); - //GtkToggleButton *newsletter = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w, "p4_check_newsletter")); - linphone_account_creator_set_username(creator, gtk_entry_get_text(username_entry)); - linphone_account_creator_set_password(creator, gtk_entry_get_text(password_entry)); - linphone_account_creator_set_email(creator, gtk_entry_get_text(email_entry)); - //linphone_account_creator_enable_newsletter_subscription(creator, gtk_toggle_button_get_active(newsletter)); - curpage = 5; // Go to page_5_linphone_account_creation_in_progress - break; - } - case 6: - curpage = 7; // Go to page_7_linphone_account_validation_check_in_progress - break; - default: - break; - } - return curpage; -} - -static int external_account_configuration_complete(GtkWidget *page) { - GtkWidget *assistant = gtk_widget_get_toplevel(page); - GtkEntry* username = GTK_ENTRY(linphone_gtk_get_widget(assistant, "p2_entry_username")); - GtkEntry* domain = GTK_ENTRY(linphone_gtk_get_widget(assistant, "p2_entry_domain")); - - if ((gtk_entry_get_text_length(username) > 0) - && (gtk_entry_get_text_length(domain) > 0) - && (g_regex_match_simple("^[a-zA-Z0-9+]+[a-zA-Z0-9.\\+\\-_]{2,}$", gtk_entry_get_text(username), 0, 0)) - && (g_regex_match_simple("^(sip:)?([a-zA-Z0-9\\+]+([\\.-][a-zA-Z0-9+]+)*)$", gtk_entry_get_text(domain), 0, 0))) { - return 1; - } - return 0; -} - -void linphone_gtk_external_account_configuration_changed(GtkEntry *entry) { - GtkWidget *assistant = gtk_widget_get_toplevel(GTK_WIDGET(entry)); - gint current_page_num = gtk_assistant_get_current_page(GTK_ASSISTANT(assistant)); - GtkWidget *page = gtk_assistant_get_nth_page(GTK_ASSISTANT(assistant), current_page_num); - gtk_assistant_set_page_complete(GTK_ASSISTANT(assistant), page, external_account_configuration_complete(page) > 0); -} - -static bool_t check_username_validity(const char *username) { - return username && g_regex_match_simple("^[a-zA-Z]+[a-zA-Z0-9.\\-_]{3,}$", username, 0, 0); -} - -void linphone_gtk_account_configuration_changed(GtkEntry *entry, GtkAssistant *assistant) { - gboolean complete = check_username_validity(gtk_entry_get_text(entry)); - GtkWidget *page = gtk_assistant_get_nth_page(assistant, gtk_assistant_get_current_page(assistant)); - gtk_assistant_set_page_complete(assistant, page, complete); -} - -static gboolean linphone_account_creation_configuration_correct(GtkWidget *w) { - gint is_username_available = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "is_username_available")); - gint is_email_correct = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "is_email_correct")); - gint is_password_correct = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "is_password_correct")); - return (is_username_available && is_email_correct && is_password_correct); -} - -static gboolean update_interface_with_username_availability(GtkWidget *page) { - GtkWidget *assistant = gtk_widget_get_toplevel(page); - GtkImage* isUsernameOk = GTK_IMAGE(linphone_gtk_get_widget(assistant, "p4_image_username_ok")); - GtkLabel* usernameError = GTK_LABEL(linphone_gtk_get_widget(assistant, "p4_label_error")); - int account_status = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(page), "is_username_used")); - - if (account_status == LinphoneAccountCreatorStatusAccountNotExist) { - g_object_set_data(G_OBJECT(page), "is_username_available", GINT_TO_POINTER(1)); - gtk_image_set_from_stock(isUsernameOk, GTK_STOCK_OK, GTK_ICON_SIZE_LARGE_TOOLBAR); - gtk_label_set_text(usernameError, ""); - } else if (account_status == LinphoneAccountCreatorStatusAccountExist) { - gtk_label_set_text(usernameError, _("Username is already in use!")); - g_object_set_data(G_OBJECT(page), "is_username_available", GINT_TO_POINTER(0)); - gtk_image_set_from_stock(isUsernameOk, GTK_STOCK_NO, GTK_ICON_SIZE_LARGE_TOOLBAR); - } else { - gtk_label_set_text(usernameError, _("Failed to check username availability. Please try again later.")); - g_object_set_data(G_OBJECT(page), "is_username_available", GINT_TO_POINTER(0)); - gtk_image_set_from_stock(isUsernameOk, GTK_STOCK_NO, GTK_ICON_SIZE_LARGE_TOOLBAR); - } - gtk_assistant_set_page_complete(GTK_ASSISTANT(assistant), page, linphone_account_creation_configuration_correct(page) > 0); - return FALSE; -} - -static void linphone_gtk_test_account_existence_cb(LinphoneAccountCreator *creator, LinphoneAccountCreatorStatus status, const char* resp) { - GtkWidget *assistant = (GtkWidget *)linphone_account_creator_get_user_data(creator); - GtkWidget *page = gtk_assistant_get_nth_page(GTK_ASSISTANT(assistant), gtk_assistant_get_current_page(GTK_ASSISTANT(assistant))); - g_object_set_data(G_OBJECT(page), "is_username_used", GINT_TO_POINTER(status)); - gdk_threads_add_idle((GSourceFunc)update_interface_with_username_availability, page); -} - -static gboolean check_username_availability(GtkWidget *assistant) { - LinphoneAccountCreator *creator = linphone_gtk_assistant_get_creator(assistant); - GtkWidget *page = gtk_assistant_get_nth_page(GTK_ASSISTANT(assistant), gtk_assistant_get_current_page(GTK_ASSISTANT(assistant))); - g_object_set_data(G_OBJECT(page), "usernameAvailabilityTimerID", GUINT_TO_POINTER(0)); - linphone_account_creator_is_account_exist(creator); - return FALSE; -} - -void linphone_gtk_account_creation_username_changed(GtkEntry *entry) { - GtkWidget *assistant = gtk_widget_get_toplevel(GTK_WIDGET(entry)); - GtkEntry* username = GTK_ENTRY(linphone_gtk_get_widget(assistant, "p4_entry_username")); - GtkImage* isUsernameOk = GTK_IMAGE(linphone_gtk_get_widget(assistant, "p4_image_username_ok")); - GtkLabel* usernameError = GTK_LABEL(linphone_gtk_get_widget(assistant, "p4_label_error")); - gint current_page_num = gtk_assistant_get_current_page(GTK_ASSISTANT(assistant)); - GtkWidget *page = gtk_assistant_get_nth_page(GTK_ASSISTANT(assistant), current_page_num); - - LinphoneAccountCreator *creator = linphone_gtk_assistant_get_creator(assistant); - linphone_account_creator_set_username(creator, gtk_entry_get_text(username)); - linphone_account_creator_set_domain(creator, "sip.linphone.org"); - linphone_account_creator_set_route(creator, "sip.linphone.org"); - - if (check_username_validity(gtk_entry_get_text(username))) { - guint timerID = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(page), "usernameAvailabilityTimerID")); - if (timerID > 0) { - g_source_remove(timerID); - } - timerID = g_timeout_add(500, (GSourceFunc)check_username_availability, assistant); - g_object_set_data(G_OBJECT(page), "usernameAvailabilityTimerID", GUINT_TO_POINTER(timerID)); - } else { - if (gtk_entry_get_text_length(username) < LOGIN_MIN_SIZE) { - gtk_label_set_text(usernameError, "Username is too short"); - } else if (!check_username_validity(gtk_entry_get_text(username))) { - gtk_label_set_text(usernameError, "Unauthorized username"); - } - g_object_set_data(G_OBJECT(page), "is_username_available", GINT_TO_POINTER(0)); - gtk_image_set_from_stock(isUsernameOk, GTK_STOCK_NO, GTK_ICON_SIZE_LARGE_TOOLBAR); - gtk_assistant_set_page_complete(GTK_ASSISTANT(assistant), page, linphone_account_creation_configuration_correct(page) > 0); - } -} - -void linphone_gtk_account_creation_email_changed(GtkEntry *entry) { - GtkWidget *assistant = gtk_widget_get_toplevel(GTK_WIDGET(entry)); - GtkEntry* email = GTK_ENTRY(linphone_gtk_get_widget(assistant, "p4_entry_email")); - GtkImage* isEmailOk = GTK_IMAGE(linphone_gtk_get_widget(assistant, "p4_image_email_ok")); - gint current_page_num = gtk_assistant_get_current_page(GTK_ASSISTANT(assistant)); - GtkWidget *page = gtk_assistant_get_nth_page(GTK_ASSISTANT(assistant), current_page_num); - - if (g_regex_match_simple("^" BC_REGEX_RESTRICTIVE_EMAIL_ADDR "$", gtk_entry_get_text(email), 0, 0)) { - g_object_set_data(G_OBJECT(page), "is_email_correct", GINT_TO_POINTER(1)); - gtk_image_set_from_stock(isEmailOk, GTK_STOCK_OK, GTK_ICON_SIZE_LARGE_TOOLBAR); - } else { - g_object_set_data(G_OBJECT(page), "is_email_correct", GINT_TO_POINTER(0)); - gtk_image_set_from_stock(isEmailOk, GTK_STOCK_NO, GTK_ICON_SIZE_LARGE_TOOLBAR); - } - gtk_assistant_set_page_complete(GTK_ASSISTANT(assistant), page, linphone_account_creation_configuration_correct(page) > 0); -} - -void linphone_gtk_account_creation_password_changed(GtkEntry *entry) { - GtkWidget *assistant = gtk_widget_get_toplevel(GTK_WIDGET(entry)); - GtkEntry* password = GTK_ENTRY(linphone_gtk_get_widget(assistant, "p4_entry_password1")); - GtkEntry* password_confirm = GTK_ENTRY(linphone_gtk_get_widget(assistant, "p4_entry_password2")); - GtkImage* isPasswordOk = GTK_IMAGE(linphone_gtk_get_widget(assistant, "p4_image_password_ok")); - GtkLabel* passwordError = GTK_LABEL(linphone_gtk_get_widget(assistant, "p4_label_error")); - gint current_page_num = gtk_assistant_get_current_page(GTK_ASSISTANT(assistant)); - GtkWidget *page = gtk_assistant_get_nth_page(GTK_ASSISTANT(assistant), current_page_num); - - if ((gtk_entry_get_text_length(password) >= PASSWORD_MIN_SIZE) - && (g_ascii_strcasecmp(gtk_entry_get_text(password), gtk_entry_get_text(password_confirm)) == 0)) { - g_object_set_data(G_OBJECT(page), "is_password_correct", GINT_TO_POINTER(1)); - gtk_image_set_from_stock(isPasswordOk, GTK_STOCK_OK, GTK_ICON_SIZE_LARGE_TOOLBAR); - gtk_label_set_text(passwordError, ""); - } else { - if (gtk_entry_get_text_length(password) < PASSWORD_MIN_SIZE) { - gtk_label_set_text(passwordError, "Password is too short !"); - } else if (g_ascii_strcasecmp(gtk_entry_get_text(password), gtk_entry_get_text(password_confirm)) != 0) { - gtk_label_set_text(passwordError, "Passwords don't match !"); - } - g_object_set_data(G_OBJECT(page), "is_password_correct", GINT_TO_POINTER(0)); - gtk_image_set_from_stock(isPasswordOk, GTK_STOCK_NO, GTK_ICON_SIZE_LARGE_TOOLBAR); - } - gtk_assistant_set_page_complete(GTK_ASSISTANT(assistant), page, linphone_account_creation_configuration_correct(page) > 0); -} - -static void linphone_gtk_assistant_init(GtkWidget *w) { - LinphoneAccountCreator *creator = linphone_account_creator_new(linphone_gtk_get_core(), "https://subscribe.linphone.org:444/wizard.php"); - LinphoneAccountCreatorCbs *cbs = linphone_account_creator_get_callbacks(creator); - linphone_account_creator_set_user_data(creator, w); - linphone_account_creator_cbs_set_is_account_exist(cbs, linphone_gtk_test_account_existence_cb); - linphone_account_creator_cbs_set_is_account_activated(cbs, linphone_gtk_test_account_validation_cb); - linphone_account_creator_cbs_set_create_account(cbs, linphone_gtk_create_account_cb); - g_object_set_data(G_OBJECT(w), "creator", creator); - - gtk_assistant_set_forward_page_func(GTK_ASSISTANT(w), linphone_gtk_assistant_forward, w, NULL); -} - -void linphone_gtk_show_assistant(void) { - if (the_assistant != NULL) return; - the_assistant = linphone_gtk_create_window("setup_wizard", linphone_gtk_get_main_window()); - linphone_gtk_assistant_init(the_assistant); - gtk_widget_show(the_assistant); -} - -void linphone_gtk_close_assistant(void) { - GtkWidget *mw; - if (the_assistant == NULL) { - return; - } - gtk_widget_destroy(the_assistant); - the_assistant = NULL; - - //reload list of proxy configs because a new one was probably created... - mw=linphone_gtk_get_main_window(); - if (mw) { - GtkWidget* pb = (GtkWidget*)g_object_get_data(G_OBJECT(mw),"parameters"); - if (pb) { - linphone_gtk_show_sip_accounts(pb); - } - } -} diff --git a/gtk/setupwizard.h b/gtk/setupwizard.h deleted file mode 100644 index ac833f20e..000000000 --- a/gtk/setupwizard.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef SETUP_WIZARD_H -#define SETUP_WIZARD_H - -#include "linphone/sipsetup.h" - -LINPHONE_PUBLIC void linphone_gtk_show_assistant(void); -LINPHONE_PUBLIC void linphone_gtk_assistant_prepare(GtkWidget *assistant); -LINPHONE_PUBLIC void linphone_gtk_assistant_closed(GtkWidget *w); - -LINPHONE_PUBLIC void linphone_gtk_external_account_configuration_changed(GtkEntry* entry); -LINPHONE_PUBLIC void linphone_gtk_account_configuration_changed(GtkEntry *entry, GtkAssistant *assistant); -LINPHONE_PUBLIC void linphone_gtk_account_creation_username_changed(GtkEntry *entry); -LINPHONE_PUBLIC void linphone_gtk_account_creation_password_changed(GtkEntry *entry); -LINPHONE_PUBLIC void linphone_gtk_account_creation_email_changed(GtkEntry *entry); - -#endif diff --git a/gtk/singleinstance.c b/gtk/singleinstance.c deleted file mode 100644 index d41b22bec..000000000 --- a/gtk/singleinstance.c +++ /dev/null @@ -1,127 +0,0 @@ -/* -linphone, gtk interface. -Copyright (C) 2011 Belledonne Communications SARL -Author: Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "linphone.h" - -static ms_thread_t pipe_thread; -static ortp_pipe_t server_pipe=(ortp_pipe_t)-1; -static gboolean server_pipe_running=TRUE; -static char *pipe_name=NULL; - -gchar *make_name(const char *appname){ - const char *username=getenv("USER"); - if (username){ - return g_strdup_printf("%s-%s",appname,username); - } - return g_strdup(appname); -} - -static gboolean execute_wakeup(char *buf){ - char uri[255]={0}; - int option; - - if (strlen(buf)>1) sscanf(buf,"%i%s",&option,uri); - else sscanf(buf,"%i",&option); - - switch(option){ - case START_LINPHONE: - linphone_gtk_show_main_window(); - break; - case START_AUDIO_ASSISTANT: - linphone_gtk_show_audio_assistant(); - break; - case START_LINPHONE_WITH_CALL: - linphone_gtk_refer_received(linphone_gtk_get_core(),uri); - break; - }; - - g_free(buf); - return FALSE; -} - -static void * server_pipe_thread(void *pointer){ - ortp_pipe_t child; - - do{ - child=ortp_server_pipe_accept_client(server_pipe); - if (server_pipe_running && child!=(ortp_pipe_t)-1){ - char buf[256]={0}; - if (ortp_pipe_read(child,(uint8_t*)buf,sizeof(buf))>0){ - g_message("Received wakeup command with arg %s",buf); - gdk_threads_enter(); - g_timeout_add(20,(GSourceFunc)execute_wakeup,g_strdup(buf)); - gdk_threads_leave(); - } - ortp_server_pipe_close_client(child); - } - }while(server_pipe_running); - ortp_server_pipe_close(server_pipe); - return NULL; -} - -static void linphone_gtk_init_pipe(const char *name){ - server_pipe=ortp_server_pipe_create(name); - if (server_pipe==(ortp_pipe_t)-1){ - g_warning("Fail to create server pipe for name %s: %s",name,strerror(errno)); - return; - } - server_pipe_running=TRUE; - ms_thread_create(&pipe_thread,NULL,server_pipe_thread,NULL); -} - -bool_t linphone_gtk_init_instance(const char *app_name, int option, const char *addr_to_call){ - ortp_pipe_t p; - pipe_name=make_name(app_name); - p=ortp_client_pipe_connect(pipe_name); - if (p!=(ortp_pipe_t)-1){ - uint8_t buf[256]={0}; - g_message("There is already a running instance."); - if (addr_to_call!=NULL){ - sprintf((char *)buf,"%i%s",option,addr_to_call); - } else { - sprintf((char *)buf,"%i",option); - } - if (ortp_pipe_write(p,buf,sizeof(buf))==-1){ - g_error("Fail to send wakeup command to running instance: %s",strerror(errno)); - }else{ - g_message("Message to running instance sent."); - } - ortp_client_pipe_close(p); - return FALSE; - }else{ - linphone_gtk_init_pipe(pipe_name); - } - return TRUE; -} - -void linphone_gtk_uninit_instance(void){ - if (server_pipe!=(ortp_pipe_t)-1){ - ortp_pipe_t client; - server_pipe_running=FALSE; - /*this is to unblock the accept() of the server pipe*/ - client=ortp_client_pipe_connect(pipe_name); - ortp_pipe_write(client,(uint8_t*)" ",1); - ortp_client_pipe_close(client); - ms_thread_join(pipe_thread,NULL); - server_pipe=(ortp_pipe_t)-1; - g_free(pipe_name); - pipe_name=NULL; - } -} diff --git a/gtk/sip_account.ui b/gtk/sip_account.ui deleted file mode 100644 index 6d03932d1..000000000 --- a/gtk/sip_account.ui +++ /dev/null @@ -1,395 +0,0 @@ - - - - - - 100000 - 3600 - 1 - 10 - - - 5 - 1 - 5 - 1 - 1 - - - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - Linphone - Configure a SIP account - center-on-parent - dialog - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 2 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - end - - - gtk-ok - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - True - - - - False - False - 0 - - - - - gtk-cancel - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - True - - - - False - False - 1 - - - - - False - True - end - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 6 - 2 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Your SIP identity: - right - - - - - 275 - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Looks like sip:<username>@<domain> - sip: - False - False - True - True - - - 1 - 2 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - SIP Proxy address: - right - - - 1 - 2 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Looks like sip:<proxy hostname> - sip: - False - False - True - True - - - - 1 - 2 - 1 - 2 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - False - True - True - - - 1 - 2 - 4 - 5 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Registration duration (sec): - right - - - 2 - 3 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - False - True - True - adjustment1 - - - 1 - 2 - 2 - 3 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Contact params (optional): - right - - - 5 - 6 - - - - - 275 - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - True - False - False - True - True - - - 1 - 2 - 5 - 6 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - AVPF regular RTCP interval (sec): - right - - - 6 - 7 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - False - True - True - adjustment2 - - - 1 - 2 - 6 - 7 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Route (optional): - right - - - 4 - 5 - - - - - True - False - Transport - - - 3 - 4 - - - - - True - False - - - - 1 - 2 - 3 - 4 - - - - - True - True - 0 - - - - - Register - True - True - False - False - True - True - - - True - True - 1 - - - - - Publish presence information - True - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - True - - - False - True - 2 - - - - - Enable AVPF - True - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - True - - - False - True - 3 - - - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Configure a SIP account - True - - - - - True - True - 1 - - - - - - button6 - button7 - - - diff --git a/gtk/status_icon.c b/gtk/status_icon.c deleted file mode 100644 index 22852f38f..000000000 --- a/gtk/status_icon.c +++ /dev/null @@ -1,546 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2015 Belledonne Communications - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "status_icon.h" -#include "linphone.h" - -#ifdef HAVE_GTK_OSX -#include -#endif - -#if !defined(_WIN32) && !defined(__APPLE__) && GLIB_CHECK_VERSION(2, 26, 0) -#define STATUS_NOTIFIER_IS_USABLE 1 -#endif - -#include "status_notifier.h" -#include - -typedef struct __LinphoneStatusIconDesc _LinphoneStatusIconDesc; - -static LinphoneStatusIcon *_linphone_status_icon_instance = NULL; -static const _LinphoneStatusIconDesc *_linphone_status_icon_selected_desc = NULL; -static GSList *_linphone_status_icon_impls = NULL; - - -struct _LinphoneStatusIconParams { - char *title; - char *desc; - GtkWidget *menu; - LinphoneStatusIconOnClickCallback on_click_cb; - void *user_data; - int ref; -}; - -LinphoneStatusIconParams *linphone_status_icon_params_new(void) { - return g_new0(LinphoneStatusIconParams, 1); -} - -LinphoneStatusIconParams *linphone_status_icon_params_ref(LinphoneStatusIconParams *obj) { - obj->ref++; - return obj; -} - -void linphone_status_icon_params_unref(LinphoneStatusIconParams *obj) { - obj->ref--; - if(obj->ref < 0) { - if(obj->title) g_free(obj->title); - if(obj->menu) g_object_unref(obj->menu); - if(obj->desc) g_free(obj->desc); - g_free(obj); - } -} - -void linphone_status_icon_params_set_title(LinphoneStatusIconParams *obj, const char *title) { - if(obj->title) g_free(obj->title); - if(title) obj->title = g_strdup(title); - else obj->title = NULL; -} - -void linphone_status_icon_params_set_description(LinphoneStatusIconParams *obj, const char *desc) { - if(obj->desc) g_free(obj->desc); - if(desc) obj->desc = g_strdup(desc); - else obj->desc = NULL; -} - -void linphone_status_icon_params_set_menu(LinphoneStatusIconParams *obj, GtkWidget *menu) { - if(obj->menu) g_object_unref(obj->menu); - if(menu) obj->menu = g_object_ref_sink(menu); - else obj->menu = NULL; -} - -void linphone_status_icon_params_set_on_click_cb(LinphoneStatusIconParams *obj, LinphoneStatusIconOnClickCallback cb, void *user_data) { - obj->on_click_cb = cb; - obj->user_data = user_data; -} - - -typedef void (*LinphoneStatusIconDescInitFunc)(LinphoneStatusIcon *obj); -typedef void (*LinphoneStatusIconDescUninitFunc)(LinphoneStatusIcon *obj); -typedef void (*LinphoneStatusIconDescStartFunc)(LinphoneStatusIcon *obj); -typedef void (*LinphoneStatusIconDescEnableBlinkingFunc)(LinphoneStatusIcon *obj, gboolean enable); -typedef void (*LinphoneStatusIconDescIsSupportedResultCb)(const _LinphoneStatusIconDesc *obj, gboolean result, void *user_data); -typedef gboolean (*LinphoneStatusIconDescIsSupportedFunc)( - const _LinphoneStatusIconDesc *desc, - gboolean *result, - LinphoneStatusIconDescIsSupportedResultCb cb, - void *user_data -); -typedef void (*LinphoneStatusIconDescFindResultCb)(const _LinphoneStatusIconDesc *desc, void *user_data); - -struct __LinphoneStatusIconDesc { - const char *impl_name; - LinphoneStatusIconDescInitFunc init; - LinphoneStatusIconDescUninitFunc uninit; - LinphoneStatusIconDescStartFunc start; - LinphoneStatusIconDescEnableBlinkingFunc enable_blinking; - LinphoneStatusIconDescIsSupportedFunc is_supported; -}; - -static gboolean _linphone_status_icon_desc_is_supported( - const _LinphoneStatusIconDesc *desc, - gboolean *result, - LinphoneStatusIconDescIsSupportedResultCb cb, - void *user_data) { - - return desc->is_supported(desc, result, cb, user_data); -} - -typedef struct { - GSList *i; - LinphoneStatusIconDescFindResultCb cb; - void *user_data; -} _LinphoneStatusIconDescSearchCtx; - -static void _linphone_status_icon_desc_is_supported_result_cb( - const _LinphoneStatusIconDesc *desc, - gboolean result, - _LinphoneStatusIconDescSearchCtx *ctx) { - - if(!result) { - ctx->i = g_slist_next(ctx->i); - for(; ctx->i; ctx->i = g_slist_next(ctx->i)) { - if(_linphone_status_icon_desc_is_supported( - (const _LinphoneStatusIconDesc *)g_slist_nth_data(ctx->i, 0), - &result, - (LinphoneStatusIconDescIsSupportedResultCb)_linphone_status_icon_desc_is_supported_result_cb, - ctx)) { - - if(result) break; - } else return; - } - } - - if(ctx->i) { - const _LinphoneStatusIconDesc *desc = (const _LinphoneStatusIconDesc *)g_slist_nth_data(ctx->i, 0); - ms_message("StatusIcon: found implementation: %s", desc->impl_name); - if(ctx->cb) ctx->cb(desc, ctx->user_data); - } else { - g_warning("StatusIcon: no implementation found"); - } - - g_free(ctx); -} - -static gboolean _linphone_status_icon_find_first_available_impl( - const _LinphoneStatusIconDesc **desc, - LinphoneStatusIconDescFindResultCb cb, - void *user_data) { - - gboolean result; - _LinphoneStatusIconDescSearchCtx *ctx = g_new0(_LinphoneStatusIconDescSearchCtx, 1); - ctx->cb = cb; - ctx->user_data = user_data; - - ms_message("StatusIcon: looking for implementation..."); - - for(ctx->i=_linphone_status_icon_impls; ctx->i; ctx->i = g_slist_next(ctx->i)) { - if(_linphone_status_icon_desc_is_supported( - (const _LinphoneStatusIconDesc *)g_slist_nth_data(ctx->i, 0), - &result, - (LinphoneStatusIconDescIsSupportedResultCb)_linphone_status_icon_desc_is_supported_result_cb, - ctx)) { - - if(result) { - *desc = (const _LinphoneStatusIconDesc *)g_slist_nth_data(ctx->i, 0); - ms_message("StatusIcon: found implementation: %s", (*desc)->impl_name); - goto sync_return; - } - } else { - return 0; - } - } - g_warning("StatusIcon: no implementation found"); - *desc = NULL; - -sync_return: - g_free(ctx); - return 1; -} - - -struct _LinphoneStatusIcon { - const _LinphoneStatusIconDesc *desc; - LinphoneStatusIconParams *params; - void *data; -}; - -static LinphoneStatusIcon *_linphone_status_icon_new(const _LinphoneStatusIconDesc *desc) { - LinphoneStatusIcon *si = (LinphoneStatusIcon *)g_new0(LinphoneStatusIcon, 1); - si->desc = desc; - if(desc->init) desc->init(si); - return si; -} - -static void _linphone_status_icon_free(LinphoneStatusIcon *obj) { - if(obj->desc->uninit) obj->desc->uninit(obj); - if(obj->params) linphone_status_icon_params_unref(obj->params); - g_free(obj); -} - -const char *linphone_status_icon_get_implementation_name(const LinphoneStatusIcon *obj) { - return obj->desc->impl_name; -} - -void linphone_status_icon_start(LinphoneStatusIcon *obj, LinphoneStatusIconParams *params) { - ms_message("StatusIcon: starting status icon"); - obj->params = linphone_status_icon_params_ref(params); - if(obj->desc->start) obj->desc->start(obj); -} - -void linphone_status_icon_enable_blinking(LinphoneStatusIcon *obj, gboolean enable) { - ms_message("StatusIcon: blinking set to %s", enable ? "TRUE" : "FALSE"); - if(obj->desc->enable_blinking) obj->desc->enable_blinking(obj, enable); -} - -static void _linphone_status_icon_notify_click(LinphoneStatusIcon *obj) { - if(obj->params->on_click_cb) { - obj->params->on_click_cb(obj, obj->params->user_data); - } -} - - -void _linphone_status_icon_init_cb(const _LinphoneStatusIconDesc *desc, void *user_data) { - void **ctx = (void **)user_data; - LinphoneStatusIconReadyCb cb = (LinphoneStatusIconReadyCb)ctx[0]; - _linphone_status_icon_selected_desc = desc; - if(cb) cb(ctx[1]); - g_free(ctx); -} - -#ifdef STATUS_NOTIFIER_IS_USABLE -static const _LinphoneStatusIconDesc _linphone_status_icon_impl_status_notifier; -#endif -#ifdef HAVE_GTK_OSX -static const _LinphoneStatusIconDesc _linphone_status_icon_impl_gtkosx_app_desc; -#else -static const _LinphoneStatusIconDesc _linphone_status_icon_impl_gtk_desc; -#endif - -void _linphone_status_icon_create_implementations_list(void) { -#ifdef STATUS_NOTIFIER_IS_USABLE - _linphone_status_icon_impls = g_slist_append(_linphone_status_icon_impls, (void *)&_linphone_status_icon_impl_status_notifier); -#endif -#if HAVE_GTK_OSX - _linphone_status_icon_impls = g_slist_append(_linphone_status_icon_impls, (void *)&_linphone_status_icon_impl_gtkosx_app_desc); -#else - _linphone_status_icon_impls = g_slist_append(_linphone_status_icon_impls, (void *)&_linphone_status_icon_impl_gtk_desc); -#endif -} - -gboolean linphone_status_icon_init(LinphoneStatusIconReadyCb ready_cb, void *user_data) { - const _LinphoneStatusIconDesc *desc; - void **ctx; - - ms_message("StatusIcon: Initialising"); - - _linphone_status_icon_create_implementations_list(); - - ctx = g_new(void *, 2); - ctx[0] = ready_cb; - ctx[1] = user_data; - - if(_linphone_status_icon_find_first_available_impl(&desc, _linphone_status_icon_init_cb, ctx)) { - _linphone_status_icon_selected_desc = desc; - g_free(ctx); - return 1; - } else return 0; -} - -void linphone_status_icon_uninit(void) { - if(_linphone_status_icon_instance) { - _linphone_status_icon_free(_linphone_status_icon_instance); - _linphone_status_icon_instance = NULL; - } - if(_linphone_status_icon_impls) { - g_slist_free(_linphone_status_icon_impls); - _linphone_status_icon_impls = NULL; - } - _linphone_status_icon_selected_desc = NULL; -} - -LinphoneStatusIcon *linphone_status_icon_get(void) { - if(_linphone_status_icon_instance == NULL) { - if(_linphone_status_icon_selected_desc) - ms_message("StatusIcon: instanciating singleton"); - _linphone_status_icon_instance = _linphone_status_icon_new(_linphone_status_icon_selected_desc); - } - return _linphone_status_icon_instance; -} - - -/* GtkStatusIcon implementation */ -#ifndef HAVE_GTK_OSX -static void _linphone_status_icon_impl_gtk_on_click_cb(LinphoneStatusIcon *si) { - _linphone_status_icon_notify_click(si); -} - -static void _linphone_status_icon_impl_gtk_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, LinphoneStatusIcon *si){ - GtkWidget *menu = si->params->menu; - gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time); -} - -static void _linphone_status_icon_impl_gtk_init(LinphoneStatusIcon *si) { - const char *icon_name=linphone_gtk_get_ui_config("icon_name",LINPHONE_ICON_NAME); - const char *blinking_icon_name=linphone_gtk_get_ui_config("binking_status_icon_name","linphone-start-call"); - GtkStatusIcon *icon=gtk_status_icon_new_from_icon_name(icon_name); - g_signal_connect_swapped(G_OBJECT(icon),"activate", G_CALLBACK(_linphone_status_icon_impl_gtk_on_click_cb), si); - g_signal_connect(G_OBJECT(icon), "popup-menu", G_CALLBACK(_linphone_status_icon_impl_gtk_popup_menu), si); - g_object_set_data_full(G_OBJECT(icon), "icon", g_strdup(icon_name), g_free); - g_object_set_data_full(G_OBJECT(icon), "call_icon", g_strdup(blinking_icon_name), g_free); - si->data = icon; -} - -static void _linphone_status_icon_impl_gtk_uninit(LinphoneStatusIcon *si) { - GtkStatusIcon *icon = GTK_STATUS_ICON(si->data); - gtk_status_icon_set_visible(icon, FALSE); -} - -static void _linphone_status_icon_impl_gtk_start(LinphoneStatusIcon *si) { - GtkStatusIcon *icon = GTK_STATUS_ICON(si->data); -#if GTK_CHECK_VERSION(2,20,2) - char *name = g_strdup_printf("%s - %s", si->params->title, si->params->desc); - gtk_status_icon_set_name(icon, name); - g_free(name); -#endif - gtk_status_icon_set_visible(icon,TRUE); -} - -static gboolean _linphone_status_icon_impl_gtk_do_icon_blink_cb(GtkStatusIcon *gi){ - const gchar *call_icon = (const gchar *)g_object_get_data(G_OBJECT(gi),"call_icon"); - const gchar *normal_icon = (const gchar *)g_object_get_data(G_OBJECT(gi),"icon"); - const gchar *cur_icon = (const gchar *)gtk_status_icon_get_icon_name(gi); - if (cur_icon == call_icon){ - gtk_status_icon_set_from_icon_name(gi,normal_icon); - }else{ - gtk_status_icon_set_from_icon_name(gi,call_icon); - } - return TRUE; -} - -static void _linphone_status_icon_impl_enable_blinking(LinphoneStatusIcon *si, gboolean val) { - GtkStatusIcon *icon = GTK_STATUS_ICON(si->data); - guint tout; - tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout")); - if (val && tout==0){ - tout=g_timeout_add(500,(GSourceFunc)_linphone_status_icon_impl_gtk_do_icon_blink_cb,icon); - g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout)); - }else if (!val && tout!=0){ - const gchar *normal_icon = (const gchar *)g_object_get_data(G_OBJECT(icon),"icon"); - g_source_remove(tout); - g_object_set_data(G_OBJECT(icon),"timeout",NULL); - gtk_status_icon_set_from_icon_name(icon,normal_icon); - } -} - -static gboolean _linphone_status_icon_impl_is_supported( - const _LinphoneStatusIconDesc *desc, - gboolean *result, - LinphoneStatusIconDescIsSupportedResultCb cb, - void *user_data) { - - *result = 1; - return 1; -} - -static const _LinphoneStatusIconDesc _linphone_status_icon_impl_gtk_desc = { - "gtk_status_icon", - _linphone_status_icon_impl_gtk_init, - _linphone_status_icon_impl_gtk_uninit, - _linphone_status_icon_impl_gtk_start, - _linphone_status_icon_impl_enable_blinking, - _linphone_status_icon_impl_is_supported -}; -#endif - - -/* GtkosxApplication implementation */ -#ifdef HAVE_GTK_OSX -static void _linphone_status_icon_impl_gtkosx_app_enable_blinking(LinphoneStatusIcon *si, gboolean val) { - GtkosxApplication *theMacApp=gtkosx_application_get(); - gint *attention_id = (gint *)&si->data; - if (val) { - *attention_id=gtkosx_application_attention_request(theMacApp, CRITICAL_REQUEST); - } else if (*attention_id != 0) { - gtkosx_application_cancel_attention_request(theMacApp, *attention_id); - *attention_id = 0; - } -} - -static gboolean _linphone_status_icon_impl_gtkosx_app_is_supported( - const _LinphoneStatusIconDesc *desc, - gboolean *result, - LinphoneStatusIconDescIsSupportedResultCb cb, - void *user_data) { - - *result = 1; - return 1; -} - -static const _LinphoneStatusIconDesc _linphone_status_icon_impl_gtkosx_app_desc = { - .impl_name = "gtkosx_application", - .init = NULL, - .uninit = NULL, - .start = NULL, - .enable_blinking = _linphone_status_icon_impl_gtkosx_app_enable_blinking, - .is_supported = _linphone_status_icon_impl_gtkosx_app_is_supported -}; -#endif - - -/* Implementation based on the StatusNotifier Freedesktop standard */ -#ifdef STATUS_NOTIFIER_IS_USABLE -typedef struct { - int x; - int y; -} _LinphoneStatusIconPosition; - -static void _linphone_status_icon_impl_sn_init(LinphoneStatusIcon *si) { - si->data = bc_status_notifier_new(); -} - -// static void _linphone_status_icon_impl_sn_uninit(LinphoneStatusIcon *si) { -// bc_status_notifier_unref((BcStatusNotifier *)si->data); -// } - -static void _linphone_status_icon_impl_sn_activated_cb(BcStatusNotifier *sn, int x, int y, void *user_data) { - LinphoneStatusIcon *si = (LinphoneStatusIcon *)user_data; - _linphone_status_icon_notify_click(si); -} - -static void _linphone_status_icon_impr_sn_get_position(GtkMenu *menu, int *x, int *y, gboolean *push_in, gpointer data) { - _LinphoneStatusIconPosition *pos = (_LinphoneStatusIconPosition *)data; - *x = pos->x; - *y = pos->y; - *push_in = TRUE; -} - -static void _linphone_status_icon_impl_sn_menu_called_cb(BcStatusNotifier *sn, int x, int y, void *user_data) { - LinphoneStatusIcon *si = (LinphoneStatusIcon *)user_data; - GtkWidget *menu = si->params->menu; - _LinphoneStatusIconPosition pos = {x, y}; - gtk_menu_popup( - GTK_MENU(menu), - NULL, - NULL, - _linphone_status_icon_impr_sn_get_position, - &pos, - 0, - gtk_get_current_event_time() - ); -} - -static void _linphone_status_icon_impl_sn_start(LinphoneStatusIcon *si) { - BcStatusNotifier *sn = (BcStatusNotifier *)si->data; - BcStatusNotifierParams *params; - BcStatusNotifierToolTip *tooltip = bc_status_notifier_tool_tip_new("linphone", si->params->title, si->params->desc); - BcStatusNotifierSignalsVTable vtable = {NULL}; - - vtable.activate_called_cb = _linphone_status_icon_impl_sn_activated_cb; - vtable.context_menu_called_cb = _linphone_status_icon_impl_sn_menu_called_cb; - - params = bc_status_notifier_params_new(); - bc_status_notifier_params_set_dbus_prefix(params, "org.kde"); - bc_status_notifier_params_set_category(params, BcStatusNotifierCategoryCommunications); - bc_status_notifier_params_set_id(params, "linphone"); - bc_status_notifier_params_set_title(params, si->params->title); - bc_status_notifier_params_set_icon_name(params, "linphone"); - bc_status_notifier_params_set_tool_tip(params, tooltip); - bc_status_notifier_params_set_vtable(params, &vtable, si); - - bc_status_notifier_start(sn, params, NULL, NULL); - - bc_status_notifier_tool_tip_unref(tooltip); - bc_status_notifier_params_unref(params); -} - -static void _linphone_status_icon_impl_sn_enable_blinking(LinphoneStatusIcon *si, gboolean val) { - BcStatusNotifier *sn = (BcStatusNotifier *)si->data; - if(val) { - bc_status_notifier_update_status(sn, BcStatusNotifierStatusNeedsAttention); - } else { - bc_status_notifier_update_status(sn, BcStatusNotifierStatusPassive); - } -} - -static void _linphone_status_icon_impl_is_supported_cb(const char *prefix, gboolean result, void **data) { - _LinphoneStatusIconDesc *desc = (_LinphoneStatusIconDesc *)data[0]; - LinphoneStatusIconDescIsSupportedResultCb cb = (LinphoneStatusIconDescIsSupportedResultCb)data[1]; - if(cb) cb(desc, result, data[2]); - g_free(data); - g_free(desc); -} - -static gboolean _linphone_status_icon_impl_sn_is_supported( - const _LinphoneStatusIconDesc *desc, - gboolean *result, - LinphoneStatusIconDescIsSupportedResultCb cb, - void *user_data) { - - _LinphoneStatusIconDesc *desc2; - void **data; - const char *desktop = g_getenv("XDG_CURRENT_DESKTOP"); - - if(desktop == NULL || g_strcmp0(desktop, "KDE") != 0) { - *result = FALSE; - return TRUE; - } - - desc2 = g_new(_LinphoneStatusIconDesc, 1); - *desc2 = *desc; - data = g_new(void *, 3); - data[0] = desc2; - data[1] = cb; - data[2] = user_data; - bc_status_notifier_is_supported( - "org.kde", - (BcStatusNotifierSupportDetectionCb)_linphone_status_icon_impl_is_supported_cb, - data - ); - return FALSE; -} - -static const _LinphoneStatusIconDesc _linphone_status_icon_impl_status_notifier = { - .impl_name = "status_notifier", - .init = _linphone_status_icon_impl_sn_init, - .uninit = NULL, - .start = _linphone_status_icon_impl_sn_start, - .enable_blinking = _linphone_status_icon_impl_sn_enable_blinking, - .is_supported = _linphone_status_icon_impl_sn_is_supported -}; -#endif diff --git a/gtk/status_icon.h b/gtk/status_icon.h deleted file mode 100644 index 52d28d4e6..000000000 --- a/gtk/status_icon.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2015 Belledonne Communications - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -/* - * LinphoneStatusIcon is an singleton interface which abstracts the - * technology used to manage the status icon. - */ - -#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) -#pragma GCC diagnostic push -#endif -#ifndef _MSC_VER -#pragma GCC diagnostic ignored "-Wstrict-prototypes" -#endif - -#include -#include - -#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) -#pragma GCC diagnostic pop -#endif - - -struct _LinphoneStatusIcon; -typedef void (*LinphoneStatusIconOnClickCallback)(struct _LinphoneStatusIcon *si, void *user_data); - - -typedef struct _LinphoneStatusIconParams LinphoneStatusIconParams; - -LinphoneStatusIconParams *linphone_status_icon_params_new(void); -LinphoneStatusIconParams *linphone_status_icon_params_ref(LinphoneStatusIconParams *obj); -void linphone_status_icon_params_unref(LinphoneStatusIconParams *obj); - -void linphone_status_icon_params_set_title(LinphoneStatusIconParams *obj, const char *title); -void linphone_status_icon_params_set_description(LinphoneStatusIconParams *obj, const char *desc); -void linphone_status_icon_params_set_menu(LinphoneStatusIconParams *obj, GtkWidget *menu); -void linphone_status_icon_params_set_on_click_cb(LinphoneStatusIconParams* obj, LinphoneStatusIconOnClickCallback cb, void *user_data); - - -typedef void (*LinphoneStatusIconReadyCb)(void *user_data); - -typedef struct _LinphoneStatusIcon LinphoneStatusIcon; - -gboolean linphone_status_icon_init(LinphoneStatusIconReadyCb ready_cb, void* user_data); -void linphone_status_icon_uninit(void); -LinphoneStatusIcon *linphone_status_icon_get(void); -const char *linphone_status_icon_get_implementation_name(const LinphoneStatusIcon *obj); -void linphone_status_icon_start(LinphoneStatusIcon *obj, LinphoneStatusIconParams *params); -void linphone_status_icon_enable_blinking(LinphoneStatusIcon *obj, gboolean enable); diff --git a/gtk/status_notifier.c b/gtk/status_notifier.c deleted file mode 100644 index 1cff84f45..000000000 --- a/gtk/status_notifier.c +++ /dev/null @@ -1,643 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2015 Belledonne Communications - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "status_notifier.h" -#include -#include - -#ifdef _MSC_VER -#include -#define getpid() _getpid() -typedef int lppid_t; -#else -#include -typedef pid_t lppid_t; -#endif - -const gchar *bc_status_notifier_category_to_string(BcStatusNotifierCategory c) { - switch(c){ - case BcStatusNotifierCategoryApplicationStatus: - return "ApplicationStatus"; - case BcStatusNotifierCategoryCommunications: - return "Communications"; - case BcStatusNotifierCategorySystemService: - return "SystemServices"; - case BcStatusNotifierCategoryHardware: - return "Hardware"; - } - return "bad category"; -} - -const gchar *bc_status_notifier_status_to_string(BcStatusNotifierStatus s) { - switch(s){ - case BcStatusNotifierStatusPassive: - return "Passive"; - case BcStatusNotifierStatusActive: - return "Active"; - case BcStatusNotifierStatusNeedsAttention: - return "NeedsAttention"; - } - return "badstatus"; -}; - - -struct _BcStatusNotifierToolTip { - char *icon_name; - char *title; - char *text; - int ref; -}; - -BcStatusNotifierToolTip *bc_status_notifier_tool_tip_new(const char *icon_name, const char *title, const char *text) { - BcStatusNotifierToolTip *obj = (BcStatusNotifierToolTip *)g_new0(BcStatusNotifierToolTip, 1); - if(icon_name) obj->icon_name = g_strdup(icon_name); - if(title) obj->title = g_strdup(title); - if(text) obj->text = g_strdup(text); - return obj; -} - -BcStatusNotifierToolTip *bc_status_notifier_tool_tip_ref(BcStatusNotifierToolTip *obj) { - obj->ref++; - return obj; -} - -void bc_status_notifier_tool_tip_unref(BcStatusNotifierToolTip *obj) { - obj->ref--; - if(obj->ref < 0) { - if(obj->icon_name) g_free(obj->icon_name); - if(obj->title) g_free(obj->title); - if(obj->text) g_free(obj->text); - g_free(obj); - } -} - -static GVariant *_bc_status_notifier_tool_tip_to_variant(const BcStatusNotifierToolTip *obj) { - GVariant *attr[] = { - g_variant_new_string(obj->icon_name ? obj->icon_name : ""), - g_variant_new_array(G_VARIANT_TYPE_VARIANT, NULL, 0), - g_variant_new_string(obj->title ? obj->title : ""), - g_variant_new_string(obj->text ? obj->text : ""), - }; - return g_variant_new_tuple(attr, 4); -} - - -static const char *_bc_status_notifier_to_string[] = { - "vertical", - "horizontal", - NULL -}; - -static BcStatusNotifierOrientation _bc_status_notifier_orientation_from_string(const char *s) { - int i; - for(i=0; _bc_status_notifier_to_string[i] && g_strcmp0(s, _bc_status_notifier_to_string[i]) == 0; i++); - if(_bc_status_notifier_to_string[i]) return i; - else return BcStatusNotifierOrientationVertical; -} - - -struct _BcStatusNotifierParams{ - char *prefix; - int item_id; - BcStatusNotifierCategory category; - char *id; - char *title; - BcStatusNotifierStatus status; - guint32 window_id; - char *icon_name; - char *overlay_icon_name; - char *attention_icon_name; - char *attention_movie_name; - BcStatusNotifierToolTip *tool_tip; - BcStatusNotifierSignalsVTable vtable; - void *user_data; - int ref; -}; - -#define DEFAULT_PREFIX "org.freedesktop" - -BcStatusNotifierParams *bc_status_notifier_params_new(void) { - BcStatusNotifierParams *obj = (BcStatusNotifierParams *)g_new0(BcStatusNotifierParams, 1); - obj->prefix = g_strdup(DEFAULT_PREFIX); - return obj; -} - -BcStatusNotifierParams *bc_status_notifier_params_ref(BcStatusNotifierParams *obj) { - obj->ref++; - return obj; -} - -void bc_status_notifier_params_unref(BcStatusNotifierParams *obj) { - obj->ref--; - if(obj->ref < 0) { - if(obj->prefix) g_free(obj->prefix); - if(obj->id) g_free(obj->id); - if(obj->title) g_free(obj->title); - if(obj->icon_name) g_free(obj->icon_name); - if(obj->overlay_icon_name) g_free(obj->overlay_icon_name); - if(obj->attention_icon_name) g_free(obj->attention_icon_name); - if(obj->attention_movie_name) g_free(obj->attention_movie_name); - if(obj->tool_tip) bc_status_notifier_tool_tip_unref(obj->tool_tip); - g_free(obj); - } -} - -void bc_status_notifier_params_set_dbus_prefix(BcStatusNotifierParams *obj, const char *prefix) { - if(obj->prefix) g_free(obj->prefix); - if(prefix) obj->prefix = g_strdup(prefix); - else obj->prefix = NULL; -} - -const char *bc_satus_notifier_params_get_dbus_prefix(const BcStatusNotifierParams *obj) { - return obj->prefix; -} - -void bc_status_notifier_params_set_item_id(BcStatusNotifierParams *obj, int item_id) { - obj->item_id = item_id; -} - -int bc_status_notifier_params_get_item_id(const BcStatusNotifierParams *obj) { - return obj->item_id; -} - -void bc_status_notifier_params_set_category(BcStatusNotifierParams *obj, BcStatusNotifierCategory category) { - obj->category = category; -} - -BcStatusNotifierCategory bc_status_notifier_params_get_category(const BcStatusNotifierParams *obj) { - return obj->category; -} - -void bc_status_notifier_params_set_id(BcStatusNotifierParams *obj, const char *id) { - if(obj->id) g_free(obj->id); - if(id) obj->id = g_strdup(id); - else obj->id = NULL; -} - -const char *bc_status_notifier_params_get_id(const BcStatusNotifierParams *obj) { - return obj->id; -} - -void bc_status_notifier_params_set_title(BcStatusNotifierParams *obj, const char *title) { - if(obj->title) g_free(obj->title); - if(title) obj->title = g_strdup(title); - else obj->title = NULL; -} - -const char *bc_status_notifier_params_get_title(const BcStatusNotifierParams *obj) { - return obj->title; -} - -void bc_status_notifier_params_set_status(BcStatusNotifierParams *obj, BcStatusNotifierStatus status) { - obj->status = status; -} - -BcStatusNotifierStatus bc_status_notifier_params_get_status(const BcStatusNotifierParams *obj) { - return obj->status; -} - -void bc_status_notifier_params_set_window_id(BcStatusNotifierParams *obj, guint32 window_id) { - obj->window_id = window_id; -} - -guint32 bc_status_notifier_params_get_window_id(const BcStatusNotifierParams *obj) { - return obj->window_id; -} - -void bc_status_notifier_params_set_icon_name(BcStatusNotifierParams *obj, const char *name) { - if(obj->icon_name) g_free(obj->icon_name); - if(name) obj->icon_name = g_strdup(name); - else obj->icon_name = NULL; -} - -const char *bc_status_notifier_params_get_icon_name(const BcStatusNotifierParams *obj) { - return obj->icon_name; -} - -void bc_status_notifier_params_set_overlay_icon_name(BcStatusNotifierParams *obj, const char *name) { - if(obj->overlay_icon_name) g_free(obj->overlay_icon_name); - if(name) obj->overlay_icon_name = g_strdup(name); - else obj->overlay_icon_name = NULL; -} - -const char *bc_status_notifier_params_get_overlay_icon_name(const BcStatusNotifierParams *obj) { - return obj->overlay_icon_name; -} - -void bc_status_notifier_params_set_attention_icon_name(BcStatusNotifierParams *obj, const char *name) { - if(obj->attention_icon_name) g_free(obj->attention_icon_name); - if(name) obj->attention_icon_name = g_strdup(name); - else obj->attention_icon_name = NULL; -} - -const char *bc_status_notifier_params_get_attention_icon_name(const BcStatusNotifierParams *obj) { - return obj->attention_icon_name; -} - -void bc_status_notifier_params_set_attention_movie_name(BcStatusNotifierParams *obj, const char *name) { - if(obj->attention_movie_name) g_free(obj->attention_movie_name); - if(name) obj->attention_movie_name = g_strdup(name); - else obj->attention_movie_name = NULL; -} - -const char *bc_status_notifier_params_get_attention_movie_name(const BcStatusNotifierParams *obj) { - return obj->attention_movie_name; -} - -void bc_status_notifier_params_set_tool_tip(BcStatusNotifierParams *obj, BcStatusNotifierToolTip *tool_tip) { - if(obj->tool_tip) bc_status_notifier_tool_tip_unref(obj->tool_tip); - if(tool_tip) obj->tool_tip = bc_status_notifier_tool_tip_ref(tool_tip); - else obj->tool_tip = NULL; -} - -const BcStatusNotifierToolTip *bc_status_notifier_params_get_tool_tip(const BcStatusNotifierParams *obj) { - return obj->tool_tip; -} - -void bc_status_notifier_params_set_vtable(BcStatusNotifierParams *obj, const BcStatusNotifierSignalsVTable *vtable, void *user_data) { - obj->vtable = *vtable; - obj->user_data = user_data; -} - - -struct _BcStatusNotifier { - BcStatusNotifierParams *params; - guint bus_owner_id; - GDBusConnection *conn; - BcStatusNotifierState state; - BcStatusNotifierStateVTable vtable; - void *user_data; - int ref; -}; - -#define ITEM_NAME "StatusNotifierItem" -#define WATCHER_NAME "StatusNotifierWatcher" -#define CALL_TIMEOUT 1000 - -#define STATUS_NOTIFIER_INTROSPECTION_DATA \ - " \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - " - -BcStatusNotifier *bc_status_notifier_new(void) { - return (BcStatusNotifier *)g_new0(BcStatusNotifier, 1); -} - -BcStatusNotifier *bc_status_notifier_ref(BcStatusNotifier *obj) { - obj->ref++; - return obj; -} - -void bc_status_notifier_unref(BcStatusNotifier *obj) { - obj->ref--; - if(obj->ref < 0) { - bc_status_notifier_stop(obj); - if(obj->params) bc_status_notifier_params_unref(obj->params); - g_free(obj); - } -} - -static GVariant *_bc_status_notifier_get_property_cb( - GDBusConnection *connection, - const gchar *sender, - const gchar *object_path, - const gchar *interface_name, - const gchar *property_name, - GError **error, - BcStatusNotifier *sn) { - - - GVariant *value = NULL; - if(g_strcmp0(property_name, "Category") == 0) { - value = g_variant_new_string(bc_status_notifier_category_to_string(sn->params->category)); - } else if(g_strcmp0(property_name, "Id") == 0) { - value = g_variant_new_string(sn->params->id ? sn->params->id : ""); - } else if(g_strcmp0(property_name, "Title") == 0) { - value = g_variant_new_string(sn->params->title ? sn->params->title : ""); - } else if(g_strcmp0(property_name, "Status") == 0) { - value = g_variant_new_string(bc_status_notifier_status_to_string(sn->params->status)); - } else if(g_strcmp0(property_name, "WindowId") == 0) { - value = g_variant_new_uint32(sn->params->window_id); - } else if(g_strcmp0(property_name, "IconName") == 0) { - value = g_variant_new_string(sn->params->icon_name ? sn->params->icon_name : ""); - } else if(g_strcmp0(property_name, "IconPixmap") == 0) { - value = g_variant_new_array(G_VARIANT_TYPE_VARIANT, NULL, 0); - } else if(g_strcmp0(property_name, "OverlayIconName") == 0) { - value = g_variant_new_string(sn->params->overlay_icon_name ? sn->params->overlay_icon_name : ""); - } else if(g_strcmp0(property_name, "OverlayIconPixmap") == 0) { - value = g_variant_new_array(G_VARIANT_TYPE_VARIANT, NULL, 0); - } else if(g_strcmp0(property_name, "AttentionIconName") == 0) { - value = g_variant_new_string(sn->params->attention_icon_name ? sn->params->attention_icon_name : ""); - } else if(g_strcmp0(property_name, "AttentionIconPixmap") == 0) { - value = g_variant_new_array(G_VARIANT_TYPE_VARIANT, NULL, 0); - } else if(g_strcmp0(property_name, "AttentionMovieName") == 0) { - value = g_variant_new_string(sn->params->attention_movie_name ? sn->params->attention_movie_name : ""); - } else if(g_strcmp0(property_name, "ToolTip") == 0) { - if(sn->params->tool_tip) { - value = _bc_status_notifier_tool_tip_to_variant(sn->params->tool_tip); - } else { - BcStatusNotifierToolTip *tool_tip = bc_status_notifier_tool_tip_new("", "", ""); - value = _bc_status_notifier_tool_tip_to_variant(tool_tip); - bc_status_notifier_tool_tip_unref(tool_tip); - } - } - return value; -} - -static void _bc_status_notifier_method_call_cb( - GDBusConnection *connection, - const gchar *sender, - const gchar *object_path, - const gchar *interface_name, - const gchar *method_name, - GVariant *parameters, - GDBusMethodInvocation *invocation, - BcStatusNotifier *sn) { - - if(g_strcmp0(method_name, "ContextMenu") == 0) { - if(sn->params->vtable.context_menu_called_cb) { - int x, y; - g_variant_get_child(parameters, 0, "i", &x); - g_variant_get_child(parameters, 1, "i", &y); - sn->params->vtable.context_menu_called_cb(sn, x, y, sn->params->user_data); - } - } else if(g_strcmp0(method_name, "Activate") == 0) { - if(sn->params->vtable.activate_called_cb) { - int x, y; - g_variant_get_child(parameters, 0, "i", &x); - g_variant_get_child(parameters, 1, "i", &y); - sn->params->vtable.activate_called_cb(sn, x, y, sn->params->user_data); - } - } else if(g_strcmp0(method_name, "SecondaryActivate") == 0) { - if(sn->params->vtable.secondary_activate_called_cb) { - int x, y; - g_variant_get_child(parameters, 0, "i", &x); - g_variant_get_child(parameters, 1, "i", &y); - sn->params->vtable.secondary_activate_called_cb(sn, x, y, sn->params->user_data); - } - } else if(g_strcmp0(method_name, "Scroll") == 0) { - if(sn->params->vtable.scroll_called_cb) { - int delta; - BcStatusNotifierOrientation orient; - char *orient_str; - g_variant_get_child(parameters, 0, "i", &delta); - g_variant_get_child(parameters, 1, "&s", &orient_str); - orient = _bc_status_notifier_orientation_from_string(orient_str); - sn->params->vtable.scroll_called_cb(sn, delta, orient, sn->params->user_data); - } - } - g_dbus_method_invocation_return_value(invocation, NULL); -} - -static void _bc_status_notifier_bus_acquired_cb(GDBusConnection *conn, const gchar *name, BcStatusNotifier *sn) { - char *interface_name = g_strdup_printf("%s.%s", sn->params->prefix, ITEM_NAME); - char *item_path = g_strdup_printf("/%s", ITEM_NAME); - GDBusInterfaceVTable vtable; - GDBusNodeInfo *node_info = g_dbus_node_info_new_for_xml(STATUS_NOTIFIER_INTROSPECTION_DATA, NULL); - GDBusInterfaceInfo *interface = g_dbus_node_info_lookup_interface( - node_info, - interface_name - ); - - memset(&vtable, 0, sizeof(vtable)); - vtable.method_call = (GDBusInterfaceMethodCallFunc)_bc_status_notifier_method_call_cb; - vtable.get_property = (GDBusInterfaceGetPropertyFunc)_bc_status_notifier_get_property_cb; - g_free(interface_name); - - sn->conn = conn; - - g_dbus_connection_register_object( - conn, - item_path, - interface, - &vtable, - bc_status_notifier_ref(sn), - (GDestroyNotify)bc_status_notifier_unref, - NULL - ); - g_free(item_path); - - g_dbus_node_info_unref(node_info); -} - -static void _bc_status_notifier_name_acquired_cb(GDBusConnection *conn, const gchar *name, BcStatusNotifier *sn) { - GVariant *item_name = g_variant_new_string(name); - GVariant *parameters = g_variant_new_tuple(&item_name, 1); - char *watcher_bus_name = g_strdup_printf("%s.%s", sn->params->prefix, WATCHER_NAME); - char *watcher_interface_name = watcher_bus_name; - char *watcher_path = g_strdup_printf("/%s", WATCHER_NAME); - - g_dbus_connection_call( - conn, - watcher_bus_name, - watcher_path, - watcher_interface_name, - "RegisterStatusNotifierItem", - parameters, - NULL, - G_DBUS_CALL_FLAGS_NONE, - CALL_TIMEOUT, - NULL, - NULL, - NULL - ); - g_free(watcher_bus_name); - g_free(watcher_path); - - sn->state = BcStatusNotifierStateRunning; - if(sn->vtable.success) sn->vtable.success(sn, sn->user_data); -} - -static void _bc_status_notifier_name_lost(GDBusConnection *conn, const gchar *name, BcStatusNotifier *sn) { - if(conn == NULL) { - sn->state = BcStatusNotifierStateStopped; - if(sn->vtable.fail) sn->vtable.fail(sn, sn->user_data); - } -} - -void bc_status_notifier_start(BcStatusNotifier* obj, BcStatusNotifierParams* params, const BcStatusNotifierStateVTable *vtable, void *user_data) { - if(obj->state == BcStatusNotifierStateStopped) { - lppid_t pid = getpid(); - char *dbus_name = g_strdup_printf("%s.%s-%d-%d", params->prefix, ITEM_NAME, pid, params->item_id); - - if(obj->params) bc_status_notifier_params_unref(obj->params); - obj->params = bc_status_notifier_params_ref(params); - if(vtable) obj->vtable = *vtable; - else { - obj->vtable.success = NULL; - obj->vtable.fail = NULL; - } - obj->user_data = user_data; - obj->state = BcStatusNotifierStateStarting; - obj->bus_owner_id = g_bus_own_name( - G_BUS_TYPE_SESSION, - dbus_name, - G_BUS_NAME_OWNER_FLAGS_NONE, - (GBusAcquiredCallback)_bc_status_notifier_bus_acquired_cb, - (GBusNameAcquiredCallback)_bc_status_notifier_name_acquired_cb, - (GBusNameLostCallback)_bc_status_notifier_name_lost, - bc_status_notifier_ref(obj), - (GDestroyNotify)bc_status_notifier_unref - ); - g_free(dbus_name); - } -} - -void bc_status_notifier_stop(BcStatusNotifier *obj) { - if(obj->state == BcStatusNotifierStateRunning) { - g_bus_unown_name(obj->bus_owner_id); - obj->bus_owner_id = 0; - obj->conn = NULL; - obj->state = BcStatusNotifierStateStopped; - } -} - -const BcStatusNotifierParams *bc_status_notifier_get_params(const BcStatusNotifier *obj) { - return obj->params; -} - -static void _bc_status_notifier_emit_signal(const BcStatusNotifier *obj, const char *sig_name, GVariant *parameters) { - char *item_interface_name = g_strdup_printf("%s.%s", obj->params->prefix, ITEM_NAME); - char *item_path = g_strdup_printf("/%s", ITEM_NAME); - g_dbus_connection_emit_signal( - obj->conn, - NULL, - item_path, - item_interface_name, - sig_name, - parameters, - NULL - ); - g_free(item_interface_name); - g_free(item_path); -} - -void bc_status_notifier_update_title(BcStatusNotifier *obj, const char *title) { - bc_status_notifier_params_set_title(obj->params, title); - _bc_status_notifier_emit_signal(obj, "NewTitle", NULL); -} - -void bc_status_notifier_update_icon(BcStatusNotifier *obj, const char *icon_name) { - bc_status_notifier_params_set_icon_name(obj->params, icon_name); - _bc_status_notifier_emit_signal(obj, "NewIcon", NULL); -} - -void bc_status_notifier_update_attention_icon(BcStatusNotifier *obj, const char *icon_name) { - bc_status_notifier_params_set_attention_icon_name(obj->params, icon_name); - _bc_status_notifier_emit_signal(obj, "NewAttentionIcon", NULL); -} - -void bc_status_notifier_update_overlay_icon(BcStatusNotifier *obj, const char *icon_name) { - bc_status_notifier_params_set_overlay_icon_name(obj->params, icon_name); - _bc_status_notifier_emit_signal(obj, "NewOverlayIcon", NULL); -} - -void bc_status_notifier_update_tool_tip(BcStatusNotifier *obj, BcStatusNotifierToolTip *tool_tip) { - bc_status_notifier_params_set_tool_tip(obj->params, tool_tip); - _bc_status_notifier_emit_signal(obj, "NewToolTip", NULL); -} - -void bc_status_notifier_update_status(BcStatusNotifier *obj, BcStatusNotifierStatus status) { - GVariant *status_var = g_variant_new_string(bc_status_notifier_status_to_string(status)); - GVariant *parameter = g_variant_new_tuple(&status_var, 1); - bc_status_notifier_params_set_status(obj->params, status); - _bc_status_notifier_emit_signal(obj, "NewStatus", parameter); -} - - -typedef struct _BcWatcherDetectionCtx { - char *prefix; - guint watcher_id; - BcStatusNotifierSupportDetectionCb cb; - void *user_data; -} BcWatcherDetectionCtx; - -static void _bc_watcher_detection_ctx_free(BcWatcherDetectionCtx *obj) { - g_free(obj->prefix); - g_free(obj); -} - -static void _bc_watcher_name_appeared_cb(GDBusConnection *conn, const char *name, const char *name_owner, BcWatcherDetectionCtx *ctx) { - g_bus_unwatch_name(ctx->watcher_id); - if(ctx->cb) ctx->cb(ctx->prefix, 1, ctx->user_data); -} - -static void _bc_watcher_name_vannished_cb(GDBusConnection *conn, const char *name, BcWatcherDetectionCtx *ctx) { - g_bus_unwatch_name(ctx->watcher_id); - if(ctx->cb) ctx->cb(ctx->prefix, 0, ctx->user_data); -} - -void bc_status_notifier_is_supported(const char* prefix, BcStatusNotifierSupportDetectionCb cb, void *user_data) { - char *bus_name = g_strdup_printf("%s.%s", prefix, WATCHER_NAME); - BcWatcherDetectionCtx *ctx = (BcWatcherDetectionCtx *)g_new0(BcWatcherDetectionCtx, 1); - ctx->prefix = g_strdup(prefix); - ctx->cb = cb; - ctx->user_data = user_data; - - ctx->watcher_id = g_bus_watch_name( - G_BUS_TYPE_SESSION, - bus_name, - G_BUS_NAME_WATCHER_FLAGS_NONE, - (GBusNameAppearedCallback)_bc_watcher_name_appeared_cb, - (GBusNameVanishedCallback)_bc_watcher_name_vannished_cb, - ctx, - (GDestroyNotify)_bc_watcher_detection_ctx_free - ); - g_free(bus_name); -} diff --git a/gtk/status_notifier.h b/gtk/status_notifier.h deleted file mode 100644 index 22d95ebae..000000000 --- a/gtk/status_notifier.h +++ /dev/null @@ -1,163 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2015 Belledonne Communications - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -/** - * BcStatusNotifier is an implementation of the StatusNotiferItem standard defined by freedesktop.org. - * It is a new way to manage status icons on GNU/Linux systems by using D-Bus. It is implemented by - * Unity desktop environmemt and it is the only way to create status icons on KDE 5. - * Visit http://freedesktop.org/wiki/Specifications/StatusNotifierItem/ for more information. - */ - -#ifndef STATUS_NOTIFIER_H -#define STATUS_NOTIFIER_H - -#include - -struct _BcStatusNotifier; - - -typedef enum { - BcStatusNotifierCategoryApplicationStatus, - BcStatusNotifierCategoryCommunications, - BcStatusNotifierCategorySystemService, - BcStatusNotifierCategoryHardware -} BcStatusNotifierCategory; - -const gchar *bc_status_notifier_category_to_string(BcStatusNotifierCategory c); - - -typedef enum { - BcStatusNotifierStatusPassive, - BcStatusNotifierStatusActive, - BcStatusNotifierStatusNeedsAttention -} BcStatusNotifierStatus; - -const gchar *bc_status_notifier_status_to_string(BcStatusNotifierStatus s); - - -typedef struct _BcStatusNotifierToolTip BcStatusNotifierToolTip; - -BcStatusNotifierToolTip *bc_status_notifier_tool_tip_new(const char *icon_name, const char *title, const char *text); -BcStatusNotifierToolTip *bc_status_notifier_tool_tip_ref(BcStatusNotifierToolTip *obj); -void bc_status_notifier_tool_tip_unref(BcStatusNotifierToolTip *obj); - - -typedef enum _BcStatusNotifierOrientation { - BcStatusNotifierOrientationVertical, - BcStatusNotifierOrientationHorizontal -} BcStatusNotifierOrientation; - - -typedef void (*BcStatusNotifierContextMenuCalledCb)(struct _BcStatusNotifier *sn, int x, int y, void *user_data); -typedef void (*BcStatusNotifierActivateCalledCb)(struct _BcStatusNotifier *sn, int x, int y, void *user_data); -typedef void (*BcStatusNotifierSecondaryActivateCb)(struct _BcStatusNotifier *sn, int x, int y, void *user_data); -typedef void (*BcStatusNotifierScrollCalledCb)(struct _BcStatusNotifier *sn, int delta, BcStatusNotifierOrientation o, void *user_data); - -typedef struct _BcStatusNotifierSignalsVTable { - BcStatusNotifierContextMenuCalledCb context_menu_called_cb; - BcStatusNotifierActivateCalledCb activate_called_cb; - BcStatusNotifierSecondaryActivateCb secondary_activate_called_cb; - BcStatusNotifierScrollCalledCb scroll_called_cb; -} BcStatusNotifierSignalsVTable; - - -typedef struct _BcStatusNotifierParams BcStatusNotifierParams; - -BcStatusNotifierParams *bc_status_notifier_params_new(void); -BcStatusNotifierParams *bc_status_notifier_params_ref(BcStatusNotifierParams *obj); -void bc_status_notifier_params_unref(BcStatusNotifierParams *obj); - -void bc_status_notifier_params_set_dbus_prefix(BcStatusNotifierParams *obj, const char *prefix); -const char *bc_satus_notifier_params_get_dbus_prefix(const BcStatusNotifierParams *obj); - -void bc_status_notifier_params_set_item_id(BcStatusNotifierParams *obj, int item_id); -int bc_status_notifier_params_get_item_id(const BcStatusNotifierParams *obj); - -void bc_status_notifier_params_set_category(BcStatusNotifierParams *obj, BcStatusNotifierCategory category); -BcStatusNotifierCategory bc_status_notifier_params_get_category(const BcStatusNotifierParams *obj); - -void bc_status_notifier_params_set_id(BcStatusNotifierParams *obj, const char *id); -const char *bc_status_notifier_params_get_id(const BcStatusNotifierParams *obj); - -void bc_status_notifier_params_set_title(BcStatusNotifierParams *obj, const char *title); -const char *bc_status_notifier_params_get_title(const BcStatusNotifierParams *obj); - -void bc_status_notifier_params_set_status(BcStatusNotifierParams *obj, BcStatusNotifierStatus status); -BcStatusNotifierStatus bc_status_notifier_params_get_status(const BcStatusNotifierParams *obj); - -void bc_status_notifier_params_set_window_id(BcStatusNotifierParams *obj, guint32 window_id); -guint32 bc_status_notifier_params_get_window_id(const BcStatusNotifierParams *obj); - -void bc_status_notifier_params_set_icon_name(BcStatusNotifierParams *obj, const char *name); -const char *bc_status_notifier_params_get_icon_name(const BcStatusNotifierParams *obj); - -void bc_status_notifier_params_set_overlay_icon_name(BcStatusNotifierParams *obj, const char *name); -const char *bc_status_notifier_params_get_overlay_icon_name(const BcStatusNotifierParams *obj); - -void bc_status_notifier_params_set_attention_icon_name(BcStatusNotifierParams *obj, const char *icon_name); -const char *bc_status_notifier_params_get_attention_icon_name(const BcStatusNotifierParams *obj); - -void bc_status_notifier_params_set_attention_movie_name(BcStatusNotifierParams *obj, const char *name); -const char *bc_status_notifier_params_get_attention_movie_name(const BcStatusNotifierParams *obj); - -void bc_status_notifier_params_set_tool_tip(BcStatusNotifierParams *obj, BcStatusNotifierToolTip *tool_tip); -const BcStatusNotifierToolTip *bc_status_notifier_params_get_tool_tip(const BcStatusNotifierParams *obj); - -void bc_status_notifier_params_set_vtable(BcStatusNotifierParams *obj, const BcStatusNotifierSignalsVTable *vtable, void *user_data); - - -typedef enum _BcStatusNotifierState { - BcStatusNotifierStateStopped, - BcStatusNotifierStateStarting, - BcStatusNotifierStateRunning -} BcStatusNotifierState; - - -typedef void (*BcStatusNotifierStartedCb)(struct _BcStatusNotifier *sn, void *user_data); -typedef void (*BcStatusNotifierStartingFailedCb)(struct _BcStatusNotifier *sn, void *user_data); - -typedef struct _BcStatusNotifierStateVTable { - BcStatusNotifierStartedCb success; - BcStatusNotifierStartingFailedCb fail; -} BcStatusNotifierStateVTable; - - -typedef struct _BcStatusNotifier BcStatusNotifier; - -BcStatusNotifier *bc_status_notifier_new(void); -BcStatusNotifier *bc_status_notifier_ref(BcStatusNotifier *obj); -void bc_status_notifier_unref(BcStatusNotifier *obj); - -void bc_status_notifier_start(BcStatusNotifier* obj, BcStatusNotifierParams* params, const BcStatusNotifierStateVTable* vtable, void* user_data); -void bc_status_notifier_stop(BcStatusNotifier* obj); - -const BcStatusNotifierParams *bc_status_notifier_get_params(const BcStatusNotifier *obj); -void bc_status_notifier_update_title(BcStatusNotifier* obj, const char* title); -void bc_status_notifier_update_icon(BcStatusNotifier* obj, const char* icon_name); -void bc_status_notifier_update_attention_icon(BcStatusNotifier* obj, const char* icon_name); -void bc_status_notifier_update_overlay_icon(BcStatusNotifier* obj, const char* icon_name); -void bc_status_notifier_update_tool_tip(BcStatusNotifier* obj, BcStatusNotifierToolTip* tool_tip); -void bc_status_notifier_update_status(BcStatusNotifier* obj, BcStatusNotifierStatus status); - - -typedef void (*BcStatusNotifierSupportDetectionCb)(const char *prefix, gboolean is_supported, void *user_data); - -void bc_status_notifier_is_supported(const char* prefix, BcStatusNotifierSupportDetectionCb cb, void *user_data); - -#endif \ No newline at end of file diff --git a/gtk/stock_people.png b/gtk/stock_people.png deleted file mode 100644 index ed2d33b9f861db2daebf5d371047f3af5884f869..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 764 zcmVWFU8GbZ8({Xk{QrNlj4iWF>9@00Ll1L_t(|+O3mINK|1I z$A90wGmbNkI?d?hBOMtHja&p#1Z|_GElS%(3(>#~$u^16GH4UjqI}RQF^e8Vn+he0 zYK%xrdQzB4=A$v4JJ&mpd+*mG6-|j2{oyRm;e3Do=lstHe@8LU4#>r5Uab8yns4-V z%ZagJdv5xJ-PdzT0@qhIh?Pl2MY%5;ovl$-XSJdzo>*+YY2@Vq`FZ~39$&C>)jP*Z z0>enQ$K&zl+S*!Yc6K&hU0w9_-r_(>1lzJG-G6zFL}g_%H8oLxq@f|BEEE#mogG4v zHdn9R#BFP2%J{l7t|AC}q-URUn>~6b4~_=7*AyU_?FGiT3Z?cwy#T&FcAT- zz?bDF*X_dP0Iw6CkLx`7qyccM?Kr>-#iedrv&5|h4&z)+ZszOB6bTb{muGOeKgEV! z0Ybhoda=T^HjQW2V@1wKR6r~#5aDn|-F(_L7E2}hHgEB5&SEBJkP<3}kwM{(O6IK? z0D3@I|8$`$rfHpr8cuk6N1pNO-D9NUWYoKpO(8eKckWZQc>+hCN+K;WQzokj@`DAD zgAJ`Y_)GDGl3Y1`hO`O&gKzlwb&A5GY94iTQPxson@LOBhO`0aGJ((U_m+mY@MSWJ zDIMeoHzI|K+dE2*H;Yu-L`pY9Cx@0sR)rA9q?Es1uu+wTgn_2%q-?=lOy}pE4pLHI zx0g(p6QQVbap?jOQpyX<3QWspX66SAaScO{ad+S;LUHo`^EeL&-;z!yu&lJT-XSg7 u*qD=7baCzXkRXu~DYfYLHsCD(8@~V#yY_XBcII;c0000data, - G_DIR_SEPARATOR_S, filename); - if (g_file_test (pathname, G_FILE_TEST_EXISTS)) - return pathname; - g_free (pathname); - elem = elem->next; - } - return NULL; -} - -/* This is an internally used function to create pixmaps. */ -GtkWidget* -create_pixmap (const gchar *filename) -{ - gchar *pathname = NULL; - GtkWidget *pixmap; - - if (!filename || !filename[0]) - return gtk_image_new (); - - pathname = find_pixmap_file (filename); - - if (!pathname) - { - g_warning (_("Couldn't find pixmap file: %s"), filename); - return gtk_image_new (); - } - - pixmap = gtk_image_new_from_file (pathname); - g_free (pathname); - return pixmap; -} - -/* This is an internally used function to create pixmaps. */ -GdkPixbuf* -create_pixbuf (const gchar *filename) -{ - gchar *pathname = NULL; - GdkPixbuf *pixbuf; - GError *error = NULL; - - if (!filename || !filename[0]) - return NULL; - - pathname = find_pixmap_file (filename); - - if (!pathname) - { - g_warning (_("Couldn't find pixmap file: %s"), filename); - return NULL; - } - - pixbuf = gdk_pixbuf_new_from_file (pathname, &error); - if (!pixbuf) - { - fprintf (stderr, "Failed to load pixbuf file: %s: %s\n", - pathname, error->message); - g_error_free (error); - } - g_free (pathname); - return pixbuf; -} - -/* This is an internally used function to create animations */ -GdkPixbufAnimation * -create_pixbuf_animation(const gchar *filename) -{ - gchar *pathname = NULL; - GdkPixbufAnimation *pixbuf; - GError *error = NULL; - - if (!filename || !filename[0]) - return NULL; - - pathname = find_pixmap_file (filename); - - if (!pathname){ - g_warning (_("Couldn't find pixmap file: %s"), filename); - return NULL; - } - - pixbuf = gdk_pixbuf_animation_new_from_file (pathname, &error); - if (!pixbuf){ - fprintf (stderr, "Failed to load pixbuf file: %s: %s\n", - pathname, error->message); - g_error_free (error); - } - g_free (pathname); - return pixbuf; -} - - - -/* This is used to set ATK action descriptions. */ -void -glade_set_atk_action_description (AtkAction *action, - const gchar *action_name, - const gchar *description) -{ - gint n_actions, i; - - n_actions = atk_action_get_n_actions (action); - for (i = 0; i < n_actions; i++) - { - if (!strcmp (atk_action_get_name (action, i), action_name)) - atk_action_set_description (action, i, description); - } -} - - -static char linphone_lang[256]={0}; - -/*lang has to be read before the config file is parsed...*/ -const char *linphone_gtk_get_lang(const char *config_file){ - FILE *f=fopen(config_file,"r"); - if (f){ - char tmp[256]; - while(fgets(tmp,sizeof(tmp),f)!=NULL){ - char *p; - if ((p=strstr(tmp,"lang="))!=NULL){ - p+=5; - sscanf(p,"%s",linphone_lang); - g_message("Found lang %s",linphone_lang); - break; - } - } - fclose(f); - } - return linphone_lang; -} - -void linphone_gtk_set_lang(const char *code){ - LpConfig *cfg=linphone_core_get_config(linphone_gtk_get_core()); - const char *curlang=g_getenv("LANGUAGE"); - if (curlang!=NULL && strncmp(curlang,code,2)==0) { - /* do not loose the _territory@encoding part*/ - return; - } - lp_config_set_string(cfg,"GtkUi","lang",code); - g_setenv("LANGUAGE",code,1); -} - -const gchar *linphone_gtk_get_ui_config(const char *key, const char *def){ - LinphoneCore *lc=linphone_gtk_get_core(); - if (lc){ - LpConfig *cfg=linphone_core_get_config(linphone_gtk_get_core()); - return lp_config_get_string(cfg,"GtkUi",key,def); - }else{ - g_error ("Cannot read config, no core created yet."); - return NULL; - } -} - -int linphone_gtk_get_ui_config_int(const char *key, int def){ - LpConfig *cfg=linphone_core_get_config(linphone_gtk_get_core()); - return lp_config_get_int(cfg,"GtkUi",key,def); -} - -void linphone_gtk_set_ui_config_int(const char *key , int val){ - LpConfig *cfg=linphone_core_get_config(linphone_gtk_get_core()); - lp_config_set_int(cfg,"GtkUi",key,val); -} - -void linphone_gtk_set_ui_config(const char *key , const char * val){ - LpConfig *cfg=linphone_core_get_config(linphone_gtk_get_core()); - lp_config_set_string(cfg,"GtkUi",key,val); -} - -const char *linphone_gtk_get_sound_path(const char *name){ - static char *ret=NULL; - const char *file; - const char *sound_dir; - LinphoneFactory *factory = linphone_factory_get(); - - file=linphone_gtk_get_ui_config(name,NULL); - if (file==NULL){ - char *dirname=g_path_get_dirname(name); - if (strcmp(dirname,".")!=0){ - g_free(dirname); - return name; - } - g_free(dirname); - file=name; - } - if (ret){ - g_free(ret); - ret=NULL; - } - sound_dir = linphone_factory_get_sound_resources_dir(factory); - ret=g_build_filename(sound_dir,name,NULL); - return ret; -} - -static void parse_item(const char *item, const char *window_name, GtkWidget *w, gboolean show){ - char tmp[64]; - char *dot; - strcpy(tmp,item); - dot=strchr(tmp,'.'); - if (dot){ - *dot='\0'; - dot++; - if (strcmp(window_name,tmp)==0){ - GtkWidget *wd=linphone_gtk_get_widget(w,dot); - if (wd) { - if (!show) gtk_widget_hide(wd); - else gtk_widget_show(wd); - } - } - } -} - -void linphone_gtk_visibility_set(const char *hiddens, const char *window_name, GtkWidget *w, gboolean show){ - char item[64]; - const char *i; - const char *b; - int len; - for(b=i=hiddens;*i!='\0';++i){ - if (*i==' '){ - len=MIN(i-b,(int)sizeof(item)-1); - strncpy(item,b,len); - item[len]='\0'; - b=i+1; - parse_item(item,window_name,w,show); - } - } - len=MIN(i-b,(int)sizeof(item)-1); - if (len>0){ - strncpy(item,b,len); - item[len]='\0'; - parse_item(item,window_name,w,show); - } -} - diff --git a/gtk/tunnel_config.ui b/gtk/tunnel_config.ui deleted file mode 100644 index af7eafd29..000000000 --- a/gtk/tunnel_config.ui +++ /dev/null @@ -1,407 +0,0 @@ - - - - - - 1 - 65535 - 443 - 1 - 10 - - - 1 - 65535 - 8080 - 1 - 10 - - - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - Configure VoIP tunnel - center-on-parent - dialog - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 2 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - 2 - True - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Host - right - - - - - 275 - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - False - True - True - - - 1 - 2 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Port - right - - - 1 - 2 - - - - - True - True - - False - False - True - True - adjustment1 - - - 1 - 2 - 1 - 2 - - - - - Enabled - True - True - False - False - 0 - True - True - radio_disable - - - 1 - 2 - 2 - 3 - - - - - Disabled - True - True - False - False - 0 - True - True - radio_enable - - - 1 - 2 - 4 - 5 - - - - - Enable on purpose - True - True - False - False - 0 - True - True - radio_enable - - - 1 - 2 - 3 - 4 - - - - - - - - - - - - - - True - True - 0 - - - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>VoIP anti-blocking (tunnel server)</b> - True - - - - - False - True - 0 - - - - - True - False - 0 - none - - - True - False - 12 - - - True - False - 4 - 2 - True - - - True - False - Host - - - - - True - False - Port - - - 1 - 2 - - - - - True - False - Username - - - 2 - 3 - - - - - True - False - Password - - - 3 - 4 - - - - - True - True - - False - False - True - True - adjustment2 - - - 1 - 2 - 1 - 2 - - - - - True - True - - False - False - True - True - - - 1 - 2 - - - - - True - True - - False - False - True - True - - - 1 - 2 - 2 - 3 - - - - - True - True - False - - False - False - True - True - - - 1 - 2 - 3 - 4 - - - - - - - - - True - False - <b>Http proxy (optional)</b> - True - - - - - True - True - 1 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - end - - - gtk-ok - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - True - - - - False - False - 0 - - - - - gtk-cancel - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - True - - - - False - False - 1 - - - - - False - True - end - 2 - - - - - - button6 - button7 - - - diff --git a/gtk/update.c b/gtk/update.c deleted file mode 100644 index 9704b6c9e..000000000 --- a/gtk/update.c +++ /dev/null @@ -1,157 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "linphone.h" - -#ifdef _WIN32 - -#include - -static int linphone_gtk_create_version(const char *version_url, char *version, size_t size){ - DWORD dwDownloaded = 0; - HINTERNET hSession = NULL, hConnect = NULL; - int ret=-1; - - hSession=InternetOpen("Linphone",INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0); - - if (hSession==NULL) return -1; - - hConnect=InternetOpenUrl(hSession,version_url,NULL,0,0,0); - - if (hConnect==NULL) { - InternetCloseHandle(hSession); - return -1; - } - dwDownloaded=0; - if (InternetReadFile(hConnect,version,size,&dwDownloaded) && dwDownloaded>0){ - version[dwDownloaded]='\0'; - ms_message("Got response: %s", version); - /*check this not just html containing 404 not found*/ - if (strstr(version,"html")==0) - ret=0; - } - - // Close any open handles. - if (hConnect) InternetCloseHandle(hConnect); - if (hSession) InternetCloseHandle(hSession); - return ret; -} - -#else - -static int linphone_gtk_create_version(const char *url, char *version, size_t size){ - - return -1; -} - -#endif - -static void new_version_response(GtkWidget *dialog, int response_id, gpointer download_site){ - if (response_id==GTK_RESPONSE_YES){ - linphone_gtk_open_browser((const char*)download_site); - } - gtk_widget_destroy(dialog); -} - -static gboolean popup_new_version(const char *download_site){ - GtkWidget *dialog; - /* draw a question box. link to dialog_click callback */ - dialog = gtk_message_dialog_new ( - GTK_WINDOW(linphone_gtk_get_main_window()), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_YES_NO, - _("A more recent version is availalble from %s.\nWould you like to open a browser to download it ?"), - download_site); - g_signal_connect(G_OBJECT (dialog), "response", - G_CALLBACK (new_version_response), - (gpointer)download_site); - /* actually show the box */ - gtk_widget_show(dialog); - return FALSE; -} - -static gboolean popup_version_ok(void){ - linphone_gtk_display_something(GTK_MESSAGE_INFO,_("You are running the lastest version.")); - return FALSE; -} - -static int copytilldot(char *n, const char *v){ - int ret=0; - while(*v!='\0' && *v!='.' && *v!='-' && *v!='\n' && *v!='\r' && *v!='\t'){ - *n=*v; - ret++; - v++; - n++; - } - *n='\0'; - if (*v!='\0') ret=ret+1; - return ret; -} - -static int version_compare(const char *v1, const char *v2){ - char n1[16]; - char n2[16]; - int ret; - if (*v1=='\0' && *v2=='\0') return 0; - v1+=copytilldot(n1,v1); - v2+=copytilldot(n2,v2); - ms_message("Comparing %s <> %s",n1,n2); - ret=strcmp(n1,n2); - if (ret==0) return version_compare(v1,v2); - else return ret; -} - -static void *check_for_new_version(void *d){ - const char *version_url=(const char *)d; - char version[256]; - if (linphone_gtk_create_version(version_url,version,sizeof(version))==0){ - if (version_compare(version,LINPHONE_VERSION)>0){ - const char *download_site=linphone_gtk_get_ui_config("download_site",NULL); - if (download_site) { - gdk_threads_enter(); - g_idle_add((GSourceFunc)popup_new_version,(gpointer)download_site); - gdk_threads_leave(); - } - }else{ - if (linphone_gtk_get_ui_config_int("update_check_menu",0)){ - gdk_threads_enter(); - g_idle_add((GSourceFunc)popup_version_ok,NULL); - gdk_threads_leave(); - } - } - } - return NULL; -} - -void linphone_gtk_check_for_new_version(void){ - ortp_thread_t thread; - static gboolean done=FALSE; - const char *version_url; - if (done) return; - done=TRUE; - version_url=linphone_gtk_get_ui_config("last_version_url",NULL); - if (version_url==NULL) return ; - ortp_thread_create(&thread,NULL,check_for_new_version,(void*)version_url); -} - -/*called when the user clicks on the "Check for updates" menu item */ -void linphone_gtk_check_for_updates(void){ - linphone_gtk_check_for_new_version(); -} diff --git a/gtk/utils.c b/gtk/utils.c deleted file mode 100644 index f3e19efda..000000000 --- a/gtk/utils.c +++ /dev/null @@ -1,178 +0,0 @@ -/* -linphone, gtk-glade interface. -Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "linphone.h" - -static void run_gtk(void){ - while (gtk_events_pending ()) - gtk_main_iteration (); - -} - -void *linphone_gtk_wait(LinphoneCore *lc, void *ctx, LinphoneWaitingState ws, const char *purpose, float progress){ - GtkWidget *w; - switch(ws){ - case LinphoneWaitingStart: - gdk_threads_enter(); - w=linphone_gtk_create_window("waiting", NULL); - gtk_window_set_transient_for(GTK_WINDOW(w),GTK_WINDOW(linphone_gtk_get_main_window())); - gtk_window_set_position(GTK_WINDOW(w),GTK_WIN_POS_CENTER_ON_PARENT); - if (purpose) { - gtk_progress_bar_set_text( - GTK_PROGRESS_BAR(linphone_gtk_get_widget(w,"progressbar")), - purpose); - } - gtk_widget_show(w); - /*g_message("Creating waiting window");*/ - run_gtk(); - gdk_threads_leave(); - return w; - break; - case LinphoneWaitingProgress: - w=(GtkWidget*)ctx; - gdk_threads_enter(); - if (progress>=0){ - gtk_progress_bar_set_fraction( - GTK_PROGRESS_BAR(linphone_gtk_get_widget(w,"progressbar")), - progress); - - - }else { - gtk_progress_bar_pulse( - GTK_PROGRESS_BAR(linphone_gtk_get_widget(w,"progressbar")) - ); - } - /*g_message("Updating progress");*/ - run_gtk(); - gdk_threads_leave(); - g_usleep(50000); - return w; - break; - case LinphoneWaitingFinished: - w=(GtkWidget*)ctx; - gdk_threads_enter(); - gtk_widget_destroy(w); - run_gtk(); - gdk_threads_leave(); - return NULL; - break; - } - return NULL; -} - -GdkPixbuf *_gdk_pixbuf_new_from_memory_at_scale(const void *data, gint len, gint w, gint h, gboolean preserve_ratio){ - GInputStream *stream=g_memory_input_stream_new_from_data (data,len,NULL); - GError *error=NULL; - - GdkPixbuf *pbuf=gdk_pixbuf_new_from_stream_at_scale (stream,w,h,preserve_ratio,NULL,&error); - g_input_stream_close(stream,NULL,NULL); - g_object_unref(G_OBJECT(stream)); - if (pbuf==NULL){ - g_warning("Could not open image from memory"); - } - return pbuf; -} - -GtkWidget * _gtk_image_new_from_memory_at_scale(const void *data, gint len, gint w, gint h, gboolean preserve_ratio){ - GtkWidget *image; - GdkPixbuf *pbuf=_gdk_pixbuf_new_from_memory_at_scale(data,len,w,h,preserve_ratio); - if (pbuf==NULL) return NULL; - image=gtk_image_new_from_pixbuf(pbuf); - g_object_unref(G_OBJECT(pbuf)); - return image; -} - -void linphone_gtk_reload_sound_devices(void){ - GtkWidget *mw=linphone_gtk_get_main_window(); - GtkWidget *pb=(GtkWidget*)g_object_get_data(G_OBJECT(mw),"parameters"); - linphone_core_reload_sound_devices(linphone_gtk_get_core()); - if (pb) linphone_gtk_fill_soundcards(pb); -} - -void linphone_gtk_reload_video_devices(void){ - GtkWidget *mw=linphone_gtk_get_main_window(); - GtkWidget *pb=(GtkWidget*)g_object_get_data(G_OBJECT(mw),"parameters"); - linphone_core_reload_video_devices(linphone_gtk_get_core()); - if (pb) linphone_gtk_fill_webcams(pb); -} - -bool_t linphone_gtk_is_friend(LinphoneCore *lc, const char *contact) { - LinphoneAddress *addr = linphone_core_interpret_url(lc, contact); - if (addr) { - char *uri = linphone_address_as_string_uri_only(addr); - LinphoneFriend *lf = linphone_core_get_friend_by_address(lc, uri); - linphone_address_unref(addr); - if (uri) ms_free(uri); - if (lf) return TRUE; - } - return FALSE; -} - -#ifdef HAVE_LIBUDEV_H - -static struct udev *udevroot=NULL; -static struct udev_monitor *monitor=NULL; -static GIOChannel *monitor_channel=NULL; -static guint monitor_src_id; - -#include - -static gboolean on_monitor_data(GIOChannel *chan, GIOCondition cond, void *userdata){ - struct udev_device *dev=udev_monitor_receive_device(monitor); - const char *subsys=udev_device_get_subsystem(dev); - const char *type=udev_device_get_action(dev); - g_message("USB event arrived for class %s of action type %s",subsys,type); - if (strcmp(subsys,"sound")==0) linphone_gtk_reload_sound_devices(); - if (strcmp(subsys,"video4linux")==0) linphone_gtk_reload_video_devices(); - udev_device_unref(dev); - return TRUE; -} - -void linphone_gtk_monitor_usb(void){ - int fd; - udevroot=udev_new(); - if (!udevroot) return; - monitor=udev_monitor_new_from_netlink(udevroot,"udev"); - udev_monitor_filter_add_match_subsystem_devtype(monitor,"sound",NULL); - udev_monitor_filter_add_match_subsystem_devtype(monitor,"video4linux",NULL); - fd=udev_monitor_get_fd(monitor); - monitor_channel=g_io_channel_unix_new(fd); - monitor_src_id=g_io_add_watch(monitor_channel,G_IO_IN,on_monitor_data,NULL); - udev_monitor_enable_receiving(monitor); -} - -void linphone_gtk_unmonitor_usb(void){ - if (monitor) udev_monitor_unref(monitor); - if (udevroot) udev_unref(udevroot); - if (monitor_channel) { - g_source_remove(monitor_src_id); - g_io_channel_unref(monitor_channel); - } -} - -#else - -void linphone_gtk_monitor_usb(void){ -} -void linphone_gtk_unmonitor_usb(void){ -} - -#endif - - diff --git a/gtk/videowindow.c b/gtk/videowindow.c deleted file mode 100644 index f7077041b..000000000 --- a/gtk/videowindow.c +++ /dev/null @@ -1,394 +0,0 @@ -/* -linphone, gtk interface. -Copyright (C) 2014 Belledonne Communications SARL - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "linphone.h" - -#ifdef GDK_WINDOWING_X11 -#include -#elif defined(_WIN32) -#include -#elif defined(__APPLE__) -extern void *gdk_quartz_window_get_nswindow(GdkWindow *window); -extern void *gdk_quartz_window_get_nsview(GdkWindow *window); -#endif - -#include - -enum { - TARGET_STRING, - TARGET_TEXT, - TARGET_URILIST -}; - -static GtkTargetEntry targets[] = { - { "text/uri-list", GTK_TARGET_OTHER_APP, TARGET_URILIST }, -}; - -static void set_video_controls_position(GtkWidget *video_window); - -static void on_end_of_play(LinphonePlayer *player){ - linphone_player_close(player); -} - -static void drag_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y, - GtkSelectionData *selection_data, guint target_type, guint time, gpointer user_data){ - int datalen=gtk_selection_data_get_length(selection_data); - const void *data=gtk_selection_data_get_data(selection_data); - LinphoneCall *call=g_object_get_data(G_OBJECT(widget),"call"); - - ms_message("target_type=%i, datalen=%i, data=%p",target_type,datalen,data); - if (target_type==TARGET_URILIST && data){ - LinphonePlayer *player=linphone_call_get_player(call); - char *path=ms_strdup(data); - while (datalen&&(path[datalen-1]=='\r'||path[datalen-1]=='\n')) { - path[datalen-1]='\0'; - datalen--; - } - if (player){ - LinphonePlayerCbs *cbs = linphone_player_get_callbacks(player); - linphone_player_cbs_set_eof_reached(cbs, on_end_of_play); - const char* filepath = (strstr(path,"file://")==path) ? path+strlen("file://") : path; - if (linphone_player_open(player,filepath)==0){ - - linphone_player_start(player); - }else{ - GtkWidget *warn=gtk_message_dialog_new(GTK_WINDOW(widget),GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE, - _("Cannot play %s."),filepath); - g_signal_connect(warn,"response",(GCallback)gtk_widget_destroy,NULL); - gtk_widget_show(warn); - } - } - ms_free(path); - } - gtk_drag_finish (context, TRUE, FALSE, time); -} - -static gboolean drag_drop(GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y, guint time, gpointer user_data){ -#if GTK_CHECK_VERSION(2,21,0) - GList *l=gdk_drag_context_list_targets(drag_context); - GList *elem; - - if (l){ - ms_message("drag_drop"); - /* Choose the best target type */ - for(elem=l;elem!=NULL;elem=g_list_next(elem)){ - char *name=gdk_atom_name(GDK_POINTER_TO_ATOM(elem->data)); - ms_message("target: %s",name); - g_free(name); - } - }else{ - ms_warning("drag_drop no targets"); - return FALSE; - } -#endif - return TRUE; -} - -static void *get_native_handle(GdkWindow *gdkw){ -#ifdef GDK_WINDOWING_X11 - return (void *)GDK_WINDOW_XID(gdkw); -#elif defined(_WIN32) - return (void *)GDK_WINDOW_HWND(gdkw); -#elif defined(__APPLE__) - return (void *)gdk_quartz_window_get_nsview(gdkw); -#endif - g_warning("No way to get the native handle from gdk window"); - return 0; -} - -static void _resize_video_window(GtkWidget *video_window, MSVideoSize vsize){ - MSVideoSize cur; - gtk_window_get_size(GTK_WINDOW(video_window),&cur.width,&cur.height); - if (vsize.width*vsize.height > cur.width*cur.height || - ms_video_size_get_orientation(vsize)!=ms_video_size_get_orientation(cur) ){ - gtk_window_resize(GTK_WINDOW(video_window),vsize.width,vsize.height); - } -} - -static gboolean resize_video_window(LinphoneCall *call){ - const LinphoneCallParams *params=linphone_call_get_current_params(call); - if (params){ - MSVideoSize vsize=linphone_call_params_get_received_video_size(params); - if (vsize.width>0 && vsize.height>0){ - GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); - GtkWidget *video_window=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"video_window"); - if (video_window){ - _resize_video_window(video_window,vsize); - } - } - } - return TRUE; -} - -static void on_video_window_destroy(GtkWidget *w, guint timeout){ - g_source_remove(timeout); - linphone_core_set_native_video_window_id(linphone_gtk_get_core(),LINPHONE_VIDEO_DISPLAY_NONE); -} - -static void video_window_set_fullscreen(GtkWidget *w, gboolean val){ - if (val){ - g_object_set_data(G_OBJECT(w),"fullscreen",GINT_TO_POINTER(1)); - gtk_window_fullscreen(GTK_WINDOW(w)); - }else{ - g_object_set_data(G_OBJECT(w),"fullscreen",GINT_TO_POINTER(0)); - gtk_window_unfullscreen(GTK_WINDOW(w)); - } -} -/*old names in old version of gdk*/ -#ifndef GDK_KEY_Escape -#define GDK_KEY_Escape GDK_Escape -#define GDK_KEY_F GDK_F -#define GDK_KEY_f GDK_f -#endif - -static void on_video_window_key_press(GtkWidget *w, GdkEvent *ev, gpointer up){ - g_message("Key press event"); - switch(ev->key.keyval){ - case GDK_KEY_f: - case GDK_KEY_F: - video_window_set_fullscreen(w,TRUE); - break; - case GDK_KEY_Escape: - video_window_set_fullscreen(w,FALSE); - break; - } -} - -static void on_controls_response(GtkWidget *dialog, int response_id, GtkWidget *video_window){ - - gtk_widget_destroy(dialog); - switch(response_id){ - case GTK_RESPONSE_YES: - video_window_set_fullscreen(video_window,TRUE); - break; - case GTK_RESPONSE_NO: - video_window_set_fullscreen(video_window,FALSE); - break; - case GTK_RESPONSE_REJECT: - { - LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(video_window),"call"); - linphone_call_terminate(call); - } - break; - case GTK_RESPONSE_APPLY: - { - LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(video_window),"call"); - char *path = (char *)linphone_gtk_get_snapshot_path(); - linphone_call_take_video_snapshot(call, path); - } - } - -} - -static gboolean on_controls_destroy(GtkWidget *w){ - GtkWidget *video_window=(GtkWidget*)g_object_get_data(G_OBJECT(w),"video_window"); - gint timeout=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"timeout")); - if (timeout!=0){ - g_source_remove(timeout); - g_object_set_data(G_OBJECT(w),"timeout",GINT_TO_POINTER(0)); - } - if (video_window) { - g_object_set_data(G_OBJECT(video_window),"controls",NULL); - } - return FALSE; -} - -static gboolean _set_video_controls_position(GtkWidget *video_window){ - GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(video_window),"controls"); - if (w){ - gint vw,vh; - gint cw,ch; - gint x,y; - gtk_window_get_size(GTK_WINDOW(video_window),&vw,&vh); - gtk_window_get_position(GTK_WINDOW(video_window),&x,&y); - gtk_window_get_size(GTK_WINDOW(w),&cw,&ch); - gtk_window_move(GTK_WINDOW(w),x+vw/2 - cw/2, y + vh - ch); - } - return FALSE; -} - -static void set_video_controls_position(GtkWidget *video_window){ - /*do it a first time*/ - _set_video_controls_position(video_window); - /*and schedule to do it a second time in order to workaround a bug in fullscreen mode, where poistion is not taken into account the first time*/ - g_timeout_add(0,(GSourceFunc)_set_video_controls_position,video_window); -} - -static gboolean video_window_moved(GtkWidget *widget, GdkEvent *event, gpointer user_data){ - /*Workaround to Video window bug on Windows. */ - /* set_video_controls_position(widget); */ - return FALSE; -} - -static gint do_gtk_widget_destroy(GtkWidget *w){ - gtk_widget_destroy(w); - return FALSE; -} - -static void schedule_video_controls_disapearance(GtkWidget *w){ - gint timeout=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"timeout")); - if (timeout != 0) g_source_remove(timeout); - timeout=g_timeout_add(3000,(GSourceFunc)do_gtk_widget_destroy,w); - g_object_set_data(G_OBJECT(w),"timeout",GINT_TO_POINTER(timeout)); -} - -static GtkWidget *show_video_controls(GtkWidget *video_window){ - GtkWidget *w; - w=(GtkWidget*)g_object_get_data(G_OBJECT(video_window),"controls"); - if (!w){ - gboolean isfullscreen=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(video_window),"fullscreen")); - const char *stock_button=isfullscreen ? GTK_STOCK_LEAVE_FULLSCREEN : GTK_STOCK_FULLSCREEN; - gint response_id=isfullscreen ? GTK_RESPONSE_NO : GTK_RESPONSE_YES ; - GtkWidget *image = gtk_image_new_from_icon_name(linphone_gtk_get_ui_config("stop_call_icon_name","linphone-stop-call"), GTK_ICON_SIZE_BUTTON); - GtkWidget *button; - w=gtk_dialog_new_with_buttons("",GTK_WINDOW(video_window),GTK_DIALOG_DESTROY_WITH_PARENT,stock_button,response_id,NULL); - gtk_window_set_opacity(GTK_WINDOW(w),0.5); - gtk_window_set_decorated(GTK_WINDOW(w),FALSE); - button=gtk_button_new_with_label(_("Hang up")); - gtk_button_set_image(GTK_BUTTON(button), image); - gtk_widget_show(button); - gtk_dialog_add_action_widget(GTK_DIALOG(w),button,GTK_RESPONSE_REJECT); - button=gtk_button_new_with_label(_("Take screenshot")); - image = gtk_image_new_from_icon_name("linphone-take-screenshot", GTK_ICON_SIZE_BUTTON); - gtk_button_set_image(GTK_BUTTON(button), image); - gtk_widget_show(button); - gtk_dialog_add_action_widget(GTK_DIALOG(w),button,GTK_RESPONSE_APPLY); - g_signal_connect(w,"response",(GCallback)on_controls_response,video_window); - schedule_video_controls_disapearance(w); - g_signal_connect(w,"destroy",(GCallback)on_controls_destroy,NULL); - g_object_set_data(G_OBJECT(w),"video_window",video_window); - g_object_set_data(G_OBJECT(video_window),"controls",w); - set_video_controls_position(video_window); - gtk_widget_show(w); - }else{ - schedule_video_controls_disapearance(w); - } - return w; -} - -static GtkWidget *create_video_window(LinphoneCall *call){ - char *remote,*title; - GtkWidget *video_window; - const LinphoneAddress *addr; - guint timeout; - MSVideoSize vsize={MS_VIDEO_SIZE_CIF_W,MS_VIDEO_SIZE_CIF_H}; - GdkColor color; - - addr=linphone_call_get_remote_address(call); - remote=linphone_gtk_address(addr); - video_window=gtk_window_new(GTK_WINDOW_TOPLEVEL); - /*gtk_window_set_transient_for(GTK_WINDOW(video_window), GTK_WINDOW(linphone_gtk_get_main_window()));*/ - title=g_strdup_printf("%s - Video call with %s",linphone_gtk_get_ui_config("title","Linphone"),remote); - ms_free(remote); - gtk_window_set_title(GTK_WINDOW(video_window),title); - g_free(title); - gtk_window_resize(GTK_WINDOW(video_window),vsize.width,vsize.height); - gdk_color_parse("black",&color); - gtk_widget_modify_bg(video_window,GTK_STATE_NORMAL,&color); - - gtk_drag_dest_set(video_window, GTK_DEST_DEFAULT_ALL, targets, sizeof(targets)/sizeof(GtkTargetEntry), GDK_ACTION_COPY); - gtk_widget_show(video_window); - gdk_window_set_events(gtk_widget_get_window(video_window), - gdk_window_get_events(gtk_widget_get_window(video_window)) | GDK_POINTER_MOTION_MASK); - timeout=g_timeout_add(500,(GSourceFunc)resize_video_window,call); - g_signal_connect(video_window,"destroy",(GCallback)on_video_window_destroy,GINT_TO_POINTER(timeout)); - g_signal_connect(video_window,"key-press-event",(GCallback)on_video_window_key_press,NULL); - g_signal_connect_swapped(video_window,"motion-notify-event",(GCallback)show_video_controls,video_window); - g_signal_connect(video_window,"configure-event",(GCallback)video_window_moved,NULL); - g_signal_connect(video_window, "drag-data-received",(GCallback)drag_data_received, NULL); - g_signal_connect(video_window, "drag-drop",(GCallback)drag_drop, NULL); - g_object_set_data(G_OBJECT(video_window),"call",call); - return video_window; -} - -void linphone_gtk_in_call_show_video(LinphoneCall *call){ - GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); - GtkWidget *video_window=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"video_window"); - const LinphoneCallParams *params=linphone_call_get_current_params(call); - LinphoneCore *lc=linphone_gtk_get_core(); - - if (((bool_t)lp_config_get_int(linphone_core_get_config(lc), "video", "rtp_io", FALSE)) == FALSE) { - if (linphone_call_get_state(call)!=LinphoneCallPaused && params && linphone_call_params_video_enabled(params)){ - if (video_window==NULL){ - video_window=create_video_window(call); - g_object_set_data(G_OBJECT(callview),"video_window",video_window); - } - linphone_core_set_native_video_window_id(lc,get_native_handle(gtk_widget_get_window(video_window))); - gtk_window_present(GTK_WINDOW(video_window)); - }else{ - if (video_window){ - gtk_widget_destroy(video_window); - g_object_set_data(G_OBJECT(callview),"video_window",NULL); - } - } - } -} - -static void on_video_preview_destroyed(GtkWidget *video_preview, GtkWidget *mw){ - LinphoneCore *lc=linphone_gtk_get_core(); - guint timeout_id=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(video_preview),"timeout-id")); - g_object_set_data(G_OBJECT(mw),"video_preview",NULL); - linphone_core_enable_video_preview(lc,FALSE); - linphone_core_set_native_preview_window_id(lc,(void *)(unsigned long)-1); - g_source_remove(timeout_id); -} - -GtkWidget *linphone_gtk_get_camera_preview_window(void){ - return (GtkWidget *)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"video_preview"); -} - -static gboolean check_preview_size(GtkWidget *video_preview){ - MSVideoSize vsize=linphone_core_get_current_preview_video_size(linphone_gtk_get_core()); - if (vsize.width && vsize.height){ - MSVideoSize cur; - gtk_window_get_size(GTK_WINDOW(video_preview),&cur.width,&cur.height); - if (cur.width!=vsize.width || cur.height!=vsize.height){ - gtk_window_resize(GTK_WINDOW(video_preview),vsize.width,vsize.height); - } - } - return TRUE; -} - -void linphone_gtk_show_camera_preview_clicked(GtkButton *button){ - GtkWidget *mw=linphone_gtk_get_main_window(); - GtkWidget *video_preview=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"video_preview"); - - if (!video_preview){ - gchar *title; - LinphoneCore *lc=linphone_gtk_get_core(); - GdkColor color; - guint tid; - - video_preview=gtk_window_new(GTK_WINDOW_TOPLEVEL); - title=g_strdup_printf("%s - Video preview",linphone_gtk_get_ui_config("title","Linphone")); - gtk_window_set_title(GTK_WINDOW(video_preview),title); - gdk_color_parse("black",&color); - gtk_widget_modify_bg(video_preview,GTK_STATE_NORMAL,&color); - g_free(title); - g_object_set_data(G_OBJECT(mw),"video_preview",video_preview); - g_signal_connect(video_preview,"destroy",(GCallback)on_video_preview_destroyed,mw); - gtk_widget_show(video_preview); - linphone_core_set_native_preview_window_id(lc,get_native_handle(gtk_widget_get_window(video_preview))); - linphone_core_enable_video_preview(lc,TRUE); - tid=g_timeout_add(100,(GSourceFunc)check_preview_size,video_preview); - g_object_set_data(G_OBJECT(video_preview),"timeout-id",GINT_TO_POINTER(tid)); - } -} - diff --git a/gtk/waiting.ui b/gtk/waiting.ui deleted file mode 100644 index d2ca9ad89..000000000 --- a/gtk/waiting.ui +++ /dev/null @@ -1,56 +0,0 @@ - - - - - Linphone - False - True - GTK_WIN_POS_CENTER_ON_PARENT - False - - - True - 0 - - - True - 12 - - - True - 5 - - - True - gtk-dialog-info - - - False - False - - - - - True - - - 5 - 1 - - - - - - - - - True - Please wait - True - GTK_JUSTIFY_CENTER - - - - - - diff --git a/pixmaps/.gitignore b/pixmaps/.gitignore deleted file mode 100644 index 282522db0..000000000 --- a/pixmaps/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -Makefile -Makefile.in diff --git a/pixmaps/CMakeLists.txt b/pixmaps/CMakeLists.txt deleted file mode 100644 index 68a33b22e..000000000 --- a/pixmaps/CMakeLists.txt +++ /dev/null @@ -1,140 +0,0 @@ -############################################################################ -# CMakeLists.txt -# Copyright (C) 2014 Belledonne Communications, Grenoble France -# -############################################################################ -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -############################################################################ - -set(ICONS_INSTALL_DIR ${PACKAGE_DATA_DIR}/icons/hicolor) - -install(FILES "linphone.icns" "linphone-banner.png" - DESTINATION ${PACKAGE_DATA_DIR}/pixmaps/linphone - PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ -) - -install(FILES - svg/linphone-micro-muted.svg - svg/linphone-speaker-muted.svg - svg/linphone-micro-enabled.svg - svg/linphone-speaker-enabled.svg - svg/linphone-status-online.svg - svg/linphone-status-away.svg - svg/linphone-status-donotdisturb.svg - svg/linphone-status-offline.svg - svg/linphone-call-status-incoming.svg - svg/linphone-call-status-missed.svg - svg/linphone-call-status-outgoing.svg - svg/linphone-chat-new-message-and-writing.svg - svg/linphone-chat-new-message.svg - svg/linphone-chat-nothing.svg - svg/linphone-chat-writing.svg - svg/linphone-ok.svg - svg/linphone-inprogress.svg - svg/linphone-failed.svg - svg/linphone-camera-enabled.svg - svg/linphone-camera-disabled.svg - svg/linphone-security-ok.svg - svg/linphone-security-pending.svg - svg/linphone-media-play.svg - svg/linphone-media-pause.svg - svg/linphone-warning.svg - DESTINATION ${ICONS_INSTALL_DIR}/scalable/status - PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ -) - -install(FILES - svg/linphone-start-call.svg - svg/linphone-add-call.svg - svg/linphone-hold-off.svg - svg/linphone-hold-on.svg - svg/linphone-start-call2.svg - svg/linphone-start-chat.svg - svg/linphone-history.svg - svg/linphone-edit.svg - svg/linphone-delete.svg - svg/linphone-contact-add.svg - svg/linphone-conference-start.svg - svg/linphone-call-transfer.svg - svg/linphone-record.svg - svg/linphone-chat-send.svg - DESTINATION ${ICONS_INSTALL_DIR}/scalable/actions - PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ -) - -install(FILES - linphone-micro-muted.png - linphone-speaker-muted.png - linphone-micro-enabled.png - linphone-speaker-enabled.png - linphone-status-online.png - linphone-status-away.png - linphone-status-donotdisturb.png - linphone-status-offline.png - linphone-chat-nothing.png - linphone-chat-new-message.png - linphone-chat-writing.png - linphone-chat-new-message-and-writing.png - linphone-call-status-incoming.png - linphone-call-status-outgoing.png - linphone-call-status-missed.png - linphone-ok.png - linphone-inprogress.png - linphone-failed.png - linphone-camera-enabled.png - linphone-camera-disabled.png - linphone-security-ok.png - linphone-security-pending.png - linphone-media-play.png - linphone-media-pause.png - linphone-warning.png - DESTINATION ${ICONS_INSTALL_DIR}/48x48/status - PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ -) - -install(FILES - linphone-start-call2.png - linphone-add-call.png - linphone-start-call.png - linphone-start-chat.png - linphone-stop-call.png - linphone-hold-on.png - linphone-hold-off.png - linphone-history.png - linphone-edit.png - linphone-delete.png - linphone-contact-add.png - linphone-conference-start.png - linphone-call-transfer.png - linphone-record.png - linphone-chat-send.png - linphone-take-screenshot.png - DESTINATION ${ICONS_INSTALL_DIR}/48x48/actions - PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ -) - -install(FILES linphone.png - DESTINATION ${ICONS_INSTALL_DIR}/48x48/apps - PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ -) - -if(WIN32) - install(FILES index.theme - DESTINATION ${ICONS_INSTALL_DIR} - PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ - ) -endif() diff --git a/pixmaps/Makefile.am b/pixmaps/Makefile.am deleted file mode 100644 index 18dab92fa..000000000 --- a/pixmaps/Makefile.am +++ /dev/null @@ -1,104 +0,0 @@ -pixmapdir=$(datadir)/pixmaps/linphone -dist_pixmap_DATA= \ - linphone-banner.png \ - linphone.icns - -iconsdir=$(datadir)/icons/hicolor -if BUILD_WIN32 - dist_icons_DATA=index.theme -endif - -appiconsdir=$(iconsdir)/48x48/apps -dist_appicons_DATA= linphone.png - -status48iconsdir=$(iconsdir)/48x48/status -dist_status48icons_DATA= \ - linphone-micro-muted.png \ - linphone-speaker-muted.png \ - linphone-micro-enabled.png \ - linphone-speaker-enabled.png \ - linphone-status-online.png \ - linphone-status-away.png \ - linphone-status-donotdisturb.png \ - linphone-status-offline.png \ - linphone-chat-nothing.png \ - linphone-chat-new-message.png \ - linphone-chat-writing.png \ - linphone-chat-new-message-and-writing.png \ - linphone-call-status-incoming.png \ - linphone-call-status-outgoing.png \ - linphone-call-status-missed.png \ - linphone-ok.png \ - linphone-inprogress.png \ - linphone-failed.png \ - linphone-camera-enabled.png \ - linphone-camera-disabled.png \ - linphone-security-ok.png \ - linphone-security-pending.png \ - linphone-media-play.png \ - linphone-media-pause.png \ - linphone-warning.png \ - linphone-take-screenshot.png - -statussvgiconsdir=$(iconsdir)/scalable/status -dist_statussvgicons_DATA= \ - svg/linphone-micro-muted.svg \ - svg/linphone-speaker-muted.svg \ - svg/linphone-micro-enabled.svg \ - svg/linphone-speaker-enabled.svg \ - svg/linphone-status-online.svg \ - svg/linphone-status-away.svg \ - svg/linphone-status-donotdisturb.svg \ - svg/linphone-status-offline.svg \ - svg/linphone-call-status-incoming.svg \ - svg/linphone-call-status-missed.svg \ - svg/linphone-call-status-outgoing.svg \ - svg/linphone-chat-new-message-and-writing.svg \ - svg/linphone-chat-new-message.svg \ - svg/linphone-chat-nothing.svg \ - svg/linphone-chat-writing.svg \ - svg/linphone-ok.svg \ - svg/linphone-inprogress.svg \ - svg/linphone-failed.svg \ - svg/linphone-camera-enabled.svg \ - svg/linphone-camera-disabled.svg \ - svg/linphone-security-ok.svg \ - svg/linphone-security-pending.svg \ - svg/linphone-media-play.svg \ - svg/linphone-media-pause.svg \ - svg/linphone-warning.svg - -actions48iconsdir=$(iconsdir)/48x48/actions -dist_actions48icons_DATA= \ - linphone-start-call2.png \ - linphone-add-call.png \ - linphone-start-call.png \ - linphone-start-chat.png \ - linphone-stop-call.png \ - linphone-hold-on.png \ - linphone-hold-off.png \ - linphone-history.png \ - linphone-edit.png \ - linphone-delete.png \ - linphone-contact-add.png \ - linphone-conference-start.png \ - linphone-call-transfer.png \ - linphone-record.png \ - linphone-chat-send.png - -actionssvgiconsdir=$(iconsdir)/scalable/actions -dist_actionssvgicons_DATA= \ - svg/linphone-start-call.svg \ - svg/linphone-add-call.svg \ - svg/linphone-hold-off.svg \ - svg/linphone-hold-on.svg \ - svg/linphone-start-call2.svg \ - svg/linphone-start-chat.svg \ - svg/linphone-history.svg \ - svg/linphone-edit.svg \ - svg/linphone-delete.svg \ - svg/linphone-contact-add.svg \ - svg/linphone-conference-start.svg \ - svg/linphone-call-transfer.svg \ - svg/linphone-record.svg \ - svg/linphone-chat-send.svg diff --git a/pixmaps/index.theme b/pixmaps/index.theme deleted file mode 100644 index d17354741..000000000 --- a/pixmaps/index.theme +++ /dev/null @@ -1,1836 +0,0 @@ -[Icon Theme] -Name=Hicolor -Comment=Fallback icon theme -Hidden=true -Directories=16x16/actions,16x16/animations,16x16/apps,16x16/categories,16x16/devices,16x16/emblems,16x16/emotes,16x16/filesystems,16x16/intl,16x16/mimetypes,16x16/places,16x16/status,16x16/stock/chart,16x16/stock/code,16x16/stock/data,16x16/stock/form,16x16/stock/image,16x16/stock/io,16x16/stock/media,16x16/stock/navigation,16x16/stock/net,16x16/stock/object,16x16/stock/table,16x16/stock/text,22x22/actions,22x22/animations,22x22/apps,22x22/categories,22x22/devices,22x22/emblems,22x22/emotes,22x22/filesystems,22x22/intl,22x22/mimetypes,22x22/places,22x22/status,22x22/stock/chart,22x22/stock/code,22x22/stock/data,22x22/stock/form,22x22/stock/image,22x22/stock/io,22x22/stock/media,22x22/stock/navigation,22x22/stock/net,22x22/stock/object,22x22/stock/table,22x22/stock/text,24x24/actions,24x24/animations,24x24/apps,24x24/categories,24x24/devices,24x24/emblems,24x24/emotes,24x24/filesystems,24x24/intl,24x24/mimetypes,24x24/places,24x24/status,24x24/stock/chart,24x24/stock/code,24x24/stock/data,24x24/stock/form,24x24/stock/image,24x24/stock/io,24x24/stock/media,24x24/stock/navigation,24x24/stock/net,24x24/stock/object,24x24/stock/table,24x24/stock/text,32x32/actions,32x32/animations,32x32/apps,32x32/categories,32x32/devices,32x32/emblems,32x32/emotes,32x32/filesystems,32x32/intl,32x32/mimetypes,32x32/places,32x32/status,32x32/stock/chart,32x32/stock/code,32x32/stock/data,32x32/stock/form,32x32/stock/image,32x32/stock/io,32x32/stock/media,32x32/stock/navigation,32x32/stock/net,32x32/stock/object,32x32/stock/table,32x32/stock/text,36x36/actions,36x36/animations,36x36/apps,36x36/categories,36x36/devices,36x36/emblems,36x36/emotes,36x36/filesystems,36x36/intl,36x36/mimetypes,36x36/places,36x36/status,36x36/stock/chart,36x36/stock/code,36x36/stock/data,36x36/stock/form,36x36/stock/image,36x36/stock/io,36x36/stock/media,36x36/stock/navigation,36x36/stock/net,36x36/stock/object,36x36/stock/table,36x36/stock/text,48x48/actions,48x48/animations,48x48/apps,48x48/categories,48x48/devices,48x48/emblems,48x48/emotes,48x48/filesystems,48x48/intl,48x48/mimetypes,48x48/places,48x48/status,48x48/stock/chart,48x48/stock/code,48x48/stock/data,48x48/stock/form,48x48/stock/image,48x48/stock/io,48x48/stock/media,48x48/stock/navigation,48x48/stock/net,48x48/stock/object,48x48/stock/table,48x48/stock/text,64x64/actions,64x64/animations,64x64/apps,64x64/categories,64x64/devices,64x64/emblems,64x64/emotes,64x64/filesystems,64x64/intl,64x64/mimetypes,64x64/places,64x64/status,64x64/stock/chart,64x64/stock/code,64x64/stock/data,64x64/stock/form,64x64/stock/image,64x64/stock/io,64x64/stock/media,64x64/stock/navigation,64x64/stock/net,64x64/stock/object,64x64/stock/table,64x64/stock/text,72x72/actions,72x72/animations,72x72/apps,72x72/categories,72x72/devices,72x72/emblems,72x72/emotes,72x72/filesystems,72x72/intl,72x72/mimetypes,72x72/places,72x72/status,72x72/stock/chart,72x72/stock/code,72x72/stock/data,72x72/stock/form,72x72/stock/image,72x72/stock/io,72x72/stock/media,72x72/stock/navigation,72x72/stock/net,72x72/stock/object,72x72/stock/table,72x72/stock/text,96x96/actions,96x96/animations,96x96/apps,96x96/categories,96x96/devices,96x96/emblems,96x96/emotes,96x96/filesystems,96x96/intl,96x96/mimetypes,96x96/places,96x96/status,96x96/stock/chart,96x96/stock/code,96x96/stock/data,96x96/stock/form,96x96/stock/image,96x96/stock/io,96x96/stock/media,96x96/stock/navigation,96x96/stock/net,96x96/stock/object,96x96/stock/table,96x96/stock/text,128x128/actions,128x128/animations,128x128/apps,128x128/categories,128x128/devices,128x128/emblems,128x128/emotes,128x128/filesystems,128x128/intl,128x128/mimetypes,128x128/places,128x128/status,128x128/stock/chart,128x128/stock/code,128x128/stock/data,128x128/stock/form,128x128/stock/image,128x128/stock/io,128x128/stock/media,128x128/stock/navigation,128x128/stock/net,128x128/stock/object,128x128/stock/table,128x128/stock/text,192x192/actions,192x192/animations,192x192/apps,192x192/categories,192x192/devices,192x192/emblems,192x192/emotes,192x192/filesystems,192x192/intl,192x192/mimetypes,192x192/places,192x192/status,192x192/stock/chart,192x192/stock/code,192x192/stock/data,192x192/stock/form,192x192/stock/image,192x192/stock/io,192x192/stock/media,192x192/stock/navigation,192x192/stock/net,192x192/stock/object,192x192/stock/table,192x192/stock/text,256x256/actions,256x256/animations,256x256/apps,256x256/categories,256x256/devices,256x256/emblems,256x256/emotes,256x256/filesystems,256x256/intl,256x256/mimetypes,256x256/places,256x256/status,256x256/stock/chart,256x256/stock/code,256x256/stock/data,256x256/stock/form,256x256/stock/image,256x256/stock/io,256x256/stock/media,256x256/stock/navigation,256x256/stock/net,256x256/stock/object,256x256/stock/table,256x256/stock/text,512x512/actions,512x512/animations,512x512/apps,512x512/categories,512x512/devices,512x512/emblems,512x512/emotes,512x512/filesystems,512x512/intl,512x512/mimetypes,512x512/places,512x512/status,512x512/stock/chart,512x512/stock/code,512x512/stock/data,512x512/stock/form,512x512/stock/image,512x512/stock/io,512x512/stock/media,512x512/stock/navigation,512x512/stock/net,512x512/stock/object,512x512/stock/table,512x512/stock/text,scalable/actions,scalable/animations,scalable/apps,scalable/categories,scalable/devices,scalable/emblems,scalable/emotes,scalable/filesystems,scalable/intl,scalable/mimetypes,scalable/places,scalable/status,scalable/stock/chart,scalable/stock/code,scalable/stock/data,scalable/stock/form,scalable/stock/image,scalable/stock/io,scalable/stock/media,scalable/stock/navigation,scalable/stock/net,scalable/stock/object,scalable/stock/table,scalable/stock/text,symbolic/apps - - -[16x16/actions] -Size=16 -Context=Actions -Type=Threshold - -[16x16/animations] -Size=16 -Context=Animations -Type=Threshold - -[16x16/apps] -Size=16 -Context=Applications -Type=Threshold - -[16x16/categories] -Size=16 -Context=Categories -Type=Threshold - -[16x16/devices] -Size=16 -Context=Devices -Type=Threshold - -[16x16/emblems] -Size=16 -Context=Emblems -Type=Threshold - -[16x16/emotes] -Size=16 -Context=Emotes -Type=Threshold - -[16x16/filesystems] -Size=16 -Context=FileSystems -Type=Threshold - -[16x16/intl] -Size=16 -Context=International -Type=Threshold - -[16x16/mimetypes] -Size=16 -Context=MimeTypes -Type=Threshold - -[16x16/places] -Size=16 -Context=Places -Type=Threshold - -[16x16/status] -Size=16 -Context=Status -Type=Threshold - -[16x16/stock/chart] -Size=16 -Context=Stock -Type=Threshold - -[16x16/stock/code] -Size=16 -Context=Stock -Type=Threshold - -[16x16/stock/data] -Size=16 -Context=Stock -Type=Threshold - -[16x16/stock/form] -Size=16 -Context=Stock -Type=Threshold - -[16x16/stock/image] -Size=16 -Context=Stock -Type=Threshold - -[16x16/stock/io] -Size=16 -Context=Stock -Type=Threshold - -[16x16/stock/media] -Size=16 -Context=Stock -Type=Threshold - -[16x16/stock/navigation] -Size=16 -Context=Stock -Type=Threshold - -[16x16/stock/net] -Size=16 -Context=Stock -Type=Threshold - -[16x16/stock/object] -Size=16 -Context=Stock -Type=Threshold - -[16x16/stock/table] -Size=16 -Context=Stock -Type=Threshold - -[16x16/stock/text] -Size=16 -Context=Stock -Type=Threshold - -[22x22/actions] -Size=22 -Context=Actions -Type=Threshold - -[22x22/animations] -Size=22 -Context=Animations -Type=Threshold - -[22x22/apps] -Size=22 -Context=Applications -Type=Threshold - -[22x22/categories] -Size=22 -Context=Categories -Type=Threshold - -[22x22/devices] -Size=22 -Context=Devices -Type=Threshold - -[22x22/emblems] -Size=22 -Context=Emblems -Type=Threshold - -[22x22/emotes] -Size=22 -Context=Emotes -Type=Threshold - -[22x22/filesystems] -Size=22 -Context=FileSystems -Type=Threshold - -[22x22/intl] -Size=22 -Context=International -Type=Threshold - -[22x22/mimetypes] -Size=22 -Context=MimeTypes -Type=Threshold - -[22x22/places] -Size=22 -Context=Places -Type=Threshold - -[22x22/status] -Size=22 -Context=Status -Type=Threshold - -[22x22/stock/chart] -Size=22 -Context=Stock -Type=Threshold - -[22x22/stock/code] -Size=22 -Context=Stock -Type=Threshold - -[22x22/stock/data] -Size=22 -Context=Stock -Type=Threshold - -[22x22/stock/form] -Size=22 -Context=Stock -Type=Threshold - -[22x22/stock/image] -Size=22 -Context=Stock -Type=Threshold - -[22x22/stock/io] -Size=22 -Context=Stock -Type=Threshold - -[22x22/stock/media] -Size=22 -Context=Stock -Type=Threshold - -[22x22/stock/navigation] -Size=22 -Context=Stock -Type=Threshold - -[22x22/stock/net] -Size=22 -Context=Stock -Type=Threshold - -[22x22/stock/object] -Size=22 -Context=Stock -Type=Threshold - -[22x22/stock/table] -Size=22 -Context=Stock -Type=Threshold - -[22x22/stock/text] -Size=22 -Context=Stock -Type=Threshold - -[24x24/actions] -Size=24 -Context=Actions -Type=Threshold - -[24x24/animations] -Size=24 -Context=Animations -Type=Threshold - -[24x24/apps] -Size=24 -Context=Applications -Type=Threshold - -[24x24/categories] -Size=24 -Context=Categories -Type=Threshold - -[24x24/devices] -Size=24 -Context=Devices -Type=Threshold - -[24x24/emblems] -Size=24 -Context=Emblems -Type=Threshold - -[24x24/emotes] -Size=24 -Context=Emotes -Type=Threshold - -[24x24/filesystems] -Size=24 -Context=FileSystems -Type=Threshold - -[24x24/intl] -Size=24 -Context=International -Type=Threshold - -[24x24/mimetypes] -Size=24 -Context=MimeTypes -Type=Threshold - -[24x24/places] -Size=24 -Context=Places -Type=Threshold - -[24x24/status] -Size=24 -Context=Status -Type=Threshold - -[24x24/stock/chart] -Size=24 -Context=Stock -Type=Threshold - -[24x24/stock/code] -Size=24 -Context=Stock -Type=Threshold - -[24x24/stock/data] -Size=24 -Context=Stock -Type=Threshold - -[24x24/stock/form] -Size=24 -Context=Stock -Type=Threshold - -[24x24/stock/image] -Size=24 -Context=Stock -Type=Threshold - -[24x24/stock/io] -Size=24 -Context=Stock -Type=Threshold - -[24x24/stock/media] -Size=24 -Context=Stock -Type=Threshold - -[24x24/stock/navigation] -Size=24 -Context=Stock -Type=Threshold - -[24x24/stock/net] -Size=24 -Context=Stock -Type=Threshold - -[24x24/stock/object] -Size=24 -Context=Stock -Type=Threshold - -[24x24/stock/table] -Size=24 -Context=Stock -Type=Threshold - -[24x24/stock/text] -Size=24 -Context=Stock -Type=Threshold - -[32x32/actions] -Size=32 -Context=Actions -Type=Threshold - -[32x32/animations] -Size=32 -Context=Animations -Type=Threshold - -[32x32/apps] -Size=32 -Context=Applications -Type=Threshold - -[32x32/categories] -Size=32 -Context=Categories -Type=Threshold - -[32x32/devices] -Size=32 -Context=Devices -Type=Threshold - -[32x32/emblems] -Size=32 -Context=Emblems -Type=Threshold - -[32x32/emotes] -Size=32 -Context=Emotes -Type=Threshold - -[32x32/filesystems] -Size=32 -Context=FileSystems -Type=Threshold - -[32x32/intl] -Size=32 -Context=International -Type=Threshold - -[32x32/mimetypes] -Size=32 -Context=MimeTypes -Type=Threshold - -[32x32/places] -Size=32 -Context=Places -Type=Threshold - -[32x32/status] -Size=32 -Context=Status -Type=Threshold - -[32x32/stock/chart] -Size=32 -Context=Stock -Type=Threshold - -[32x32/stock/code] -Size=32 -Context=Stock -Type=Threshold - -[32x32/stock/data] -Size=32 -Context=Stock -Type=Threshold - -[32x32/stock/form] -Size=32 -Context=Stock -Type=Threshold - -[32x32/stock/image] -Size=32 -Context=Stock -Type=Threshold - -[32x32/stock/io] -Size=32 -Context=Stock -Type=Threshold - -[32x32/stock/media] -Size=32 -Context=Stock -Type=Threshold - -[32x32/stock/navigation] -Size=32 -Context=Stock -Type=Threshold - -[32x32/stock/net] -Size=32 -Context=Stock -Type=Threshold - -[32x32/stock/object] -Size=32 -Context=Stock -Type=Threshold - -[32x32/stock/table] -Size=32 -Context=Stock -Type=Threshold - -[32x32/stock/text] -Size=32 -Context=Stock -Type=Threshold - -[36x36/actions] -Size=36 -Context=Actions -Type=Threshold - -[36x36/animations] -Size=36 -Context=Animations -Type=Threshold - -[36x36/apps] -Size=36 -Context=Applications -Type=Threshold - -[36x36/categories] -Size=36 -Context=Categories -Type=Threshold - -[36x36/devices] -Size=36 -Context=Devices -Type=Threshold - -[36x36/emblems] -Size=36 -Context=Emblems -Type=Threshold - -[36x36/emotes] -Size=36 -Context=Emotes -Type=Threshold - -[36x36/filesystems] -Size=36 -Context=FileSystems -Type=Threshold - -[36x36/intl] -Size=36 -Context=International -Type=Threshold - -[36x36/mimetypes] -Size=36 -Context=MimeTypes -Type=Threshold - -[36x36/places] -Size=36 -Context=Places -Type=Threshold - -[36x36/status] -Size=36 -Context=Status -Type=Threshold - -[36x36/stock/chart] -Size=36 -Context=Stock -Type=Threshold - -[36x36/stock/code] -Size=36 -Context=Stock -Type=Threshold - -[36x36/stock/data] -Size=36 -Context=Stock -Type=Threshold - -[36x36/stock/form] -Size=36 -Context=Stock -Type=Threshold - -[36x36/stock/image] -Size=36 -Context=Stock -Type=Threshold - -[36x36/stock/io] -Size=36 -Context=Stock -Type=Threshold - -[36x36/stock/media] -Size=36 -Context=Stock -Type=Threshold - -[36x36/stock/navigation] -Size=36 -Context=Stock -Type=Threshold - -[36x36/stock/net] -Size=36 -Context=Stock -Type=Threshold - -[36x36/stock/object] -Size=36 -Context=Stock -Type=Threshold - -[36x36/stock/table] -Size=36 -Context=Stock -Type=Threshold - -[36x36/stock/text] -Size=36 -Context=Stock -Type=Threshold - -[48x48/actions] -Size=48 -Context=Actions -Type=Threshold - -[48x48/animations] -Size=48 -Context=Animations -Type=Threshold - -[48x48/apps] -Size=48 -Context=Applications -Type=Threshold - -[48x48/categories] -Size=48 -Context=Categories -Type=Threshold - -[48x48/devices] -Size=48 -Context=Devices -Type=Threshold - -[48x48/emblems] -Size=48 -Context=Emblems -Type=Threshold - -[48x48/emotes] -Size=48 -Context=Emotes -Type=Threshold - -[48x48/filesystems] -Size=48 -Context=FileSystems -Type=Threshold - -[48x48/intl] -Size=48 -Context=International -Type=Threshold - -[48x48/mimetypes] -Size=48 -Context=MimeTypes -Type=Threshold - -[48x48/places] -Size=48 -Context=Places -Type=Threshold - -[48x48/status] -Size=48 -Context=Status -Type=Threshold - -[48x48/stock/chart] -Size=48 -Context=Stock -Type=Threshold - -[48x48/stock/code] -Size=48 -Context=Stock -Type=Threshold - -[48x48/stock/data] -Size=48 -Context=Stock -Type=Threshold - -[48x48/stock/form] -Size=48 -Context=Stock -Type=Threshold - -[48x48/stock/image] -Size=48 -Context=Stock -Type=Threshold - -[48x48/stock/io] -Size=48 -Context=Stock -Type=Threshold - -[48x48/stock/media] -Size=48 -Context=Stock -Type=Threshold - -[48x48/stock/navigation] -Size=48 -Context=Stock -Type=Threshold - -[48x48/stock/net] -Size=48 -Context=Stock -Type=Threshold - -[48x48/stock/object] -Size=48 -Context=Stock -Type=Threshold - -[48x48/stock/table] -Size=48 -Context=Stock -Type=Threshold - -[48x48/stock/text] -Size=48 -Context=Stock -Type=Threshold - -[64x64/actions] -Size=64 -Context=Actions -Type=Threshold - -[64x64/animations] -Size=64 -Context=Animations -Type=Threshold - -[64x64/apps] -Size=64 -Context=Applications -Type=Threshold - -[64x64/categories] -Size=64 -Context=Categories -Type=Threshold - -[64x64/devices] -Size=64 -Context=Devices -Type=Threshold - -[64x64/emblems] -Size=64 -Context=Emblems -Type=Threshold - -[64x64/emotes] -Size=64 -Context=Emotes -Type=Threshold - -[64x64/filesystems] -Size=64 -Context=FileSystems -Type=Threshold - -[64x64/intl] -Size=64 -Context=International -Type=Threshold - -[64x64/mimetypes] -Size=64 -Context=MimeTypes -Type=Threshold - -[64x64/places] -Size=64 -Context=Places -Type=Threshold - -[64x64/status] -Size=64 -Context=Status -Type=Threshold - -[64x64/stock/chart] -Size=64 -Context=Stock -Type=Threshold - -[64x64/stock/code] -Size=64 -Context=Stock -Type=Threshold - -[64x64/stock/data] -Size=64 -Context=Stock -Type=Threshold - -[64x64/stock/form] -Size=64 -Context=Stock -Type=Threshold - -[64x64/stock/image] -Size=64 -Context=Stock -Type=Threshold - -[64x64/stock/io] -Size=64 -Context=Stock -Type=Threshold - -[64x64/stock/media] -Size=64 -Context=Stock -Type=Threshold - -[64x64/stock/navigation] -Size=64 -Context=Stock -Type=Threshold - -[64x64/stock/net] -Size=64 -Context=Stock -Type=Threshold - -[64x64/stock/object] -Size=64 -Context=Stock -Type=Threshold - -[64x64/stock/table] -Size=64 -Context=Stock -Type=Threshold - -[64x64/stock/text] -Size=64 -Context=Stock -Type=Threshold -[72x72/actions] -Size=72 -Context=Actions -Type=Threshold - -[72x72/animations] -Size=72 -Context=Animations -Type=Threshold - -[72x72/apps] -Size=72 -Context=Applications -Type=Threshold - -[72x72/categories] -Size=72 -Context=Categories -Type=Threshold - -[72x72/devices] -Size=72 -Context=Devices -Type=Threshold - -[72x72/emblems] -Size=72 -Context=Emblems -Type=Threshold - -[72x72/emotes] -Size=72 -Context=Emotes -Type=Threshold - -[72x72/filesystems] -Size=72 -Context=FileSystems -Type=Threshold - -[72x72/intl] -Size=72 -Context=International -Type=Threshold - -[72x72/mimetypes] -Size=72 -Context=MimeTypes -Type=Threshold - -[72x72/places] -Size=72 -Context=Places -Type=Threshold - -[72x72/status] -Size=72 -Context=Status -Type=Threshold - -[72x72/stock/chart] -Size=72 -Context=Stock -Type=Threshold - -[72x72/stock/code] -Size=72 -Context=Stock -Type=Threshold - -[72x72/stock/data] -Size=72 -Context=Stock -Type=Threshold - -[72x72/stock/form] -Size=72 -Context=Stock -Type=Threshold - -[72x72/stock/image] -Size=72 -Context=Stock -Type=Threshold - -[72x72/stock/io] -Size=72 -Context=Stock -Type=Threshold - -[72x72/stock/media] -Size=72 -Context=Stock -Type=Threshold - -[72x72/stock/navigation] -Size=72 -Context=Stock -Type=Threshold - -[72x72/stock/net] -Size=72 -Context=Stock -Type=Threshold - -[72x72/stock/object] -Size=72 -Context=Stock -Type=Threshold - -[72x72/stock/table] -Size=72 -Context=Stock -Type=Threshold - -[72x72/stock/text] -Size=72 -Context=Stock -Type=Threshold - -[96x96/actions] -Size=96 -Context=Actions -Type=Threshold - -[96x96/animations] -Size=96 -Context=Animations -Type=Threshold - -[96x96/apps] -Size=96 -Context=Applications -Type=Threshold - -[96x96/categories] -Size=96 -Context=Categories -Type=Threshold - -[96x96/devices] -Size=96 -Context=Devices -Type=Threshold - -[96x96/emblems] -Size=96 -Context=Emblems -Type=Threshold - -[96x96/emotes] -Size=96 -Context=Emotes -Type=Threshold - -[96x96/filesystems] -Size=96 -Context=FileSystems -Type=Threshold - -[96x96/intl] -Size=96 -Context=International -Type=Threshold - -[96x96/mimetypes] -Size=96 -Context=MimeTypes -Type=Threshold - -[96x96/places] -Size=96 -Context=Places -Type=Threshold - -[96x96/status] -Size=96 -Context=Status -Type=Threshold - -[96x96/stock/chart] -Size=96 -Context=Stock -Type=Threshold - -[96x96/stock/code] -Size=96 -Context=Stock -Type=Threshold - -[96x96/stock/data] -Size=96 -Context=Stock -Type=Threshold - -[96x96/stock/form] -Size=96 -Context=Stock -Type=Threshold - -[96x96/stock/image] -Size=96 -Context=Stock -Type=Threshold - -[96x96/stock/io] -Size=96 -Context=Stock -Type=Threshold - -[96x96/stock/media] -Size=96 -Context=Stock -Type=Threshold - -[96x96/stock/navigation] -Size=96 -Context=Stock -Type=Threshold - -[96x96/stock/net] -Size=96 -Context=Stock -Type=Threshold - -[96x96/stock/object] -Size=96 -Context=Stock -Type=Threshold - -[96x96/stock/table] -Size=96 -Context=Stock -Type=Threshold - -[96x96/stock/text] -Size=96 -Context=Stock -Type=Threshold - -[128x128/actions] -Size=128 -Context=Actions -Type=Threshold - -[128x128/animations] -Size=128 -Context=Animations -Type=Threshold - -[128x128/apps] -Size=128 -Context=Applications -Type=Threshold - -[128x128/categories] -Size=128 -Context=Categories -Type=Threshold - -[128x128/devices] -Size=128 -Context=Devices -Type=Threshold - -[128x128/emblems] -Size=128 -Context=Emblems -Type=Threshold - -[128x128/emotes] -Size=128 -Context=Emotes -Type=Threshold - -[128x128/filesystems] -Size=128 -Context=FileSystems -Type=Threshold - -[128x128/intl] -Size=128 -Context=International -Type=Threshold - -[128x128/mimetypes] -Size=128 -Context=MimeTypes -Type=Threshold - -[128x128/places] -Size=128 -Context=Places -Type=Threshold - -[128x128/status] -Size=128 -Context=Status -Type=Threshold - -[128x128/stock/chart] -Size=128 -Context=Stock -Type=Threshold - -[128x128/stock/code] -Size=128 -Context=Stock -Type=Threshold - -[128x128/stock/data] -Size=128 -Context=Stock -Type=Threshold - -[128x128/stock/form] -Size=128 -Context=Stock -Type=Threshold - -[128x128/stock/image] -Size=128 -Context=Stock -Type=Threshold - -[128x128/stock/io] -Size=128 -Context=Stock -Type=Threshold - -[128x128/stock/media] -Size=128 -Context=Stock -Type=Threshold - -[128x128/stock/navigation] -Size=128 -Context=Stock -Type=Threshold - -[128x128/stock/net] -Size=128 -Context=Stock -Type=Threshold - -[128x128/stock/object] -Size=128 -Context=Stock -Type=Threshold - -[128x128/stock/table] -Size=128 -Context=Stock -Type=Threshold - -[128x128/stock/text] -Size=128 -Context=Stock -Type=Threshold - -[192x192/actions] -Size=192 -Context=Actions -Type=Threshold - -[192x192/animations] -Size=192 -Context=Animations -Type=Threshold - -[192x192/apps] -Size=192 -Context=Applications -Type=Threshold - -[192x192/categories] -Size=192 -Context=Categories -Type=Threshold - -[192x192/devices] -Size=192 -Context=Devices -Type=Threshold - -[192x192/emblems] -Size=192 -Context=Emblems -Type=Threshold - -[192x192/emotes] -Size=192 -Context=Emotes -Type=Threshold - -[192x192/filesystems] -Size=192 -Context=FileSystems -Type=Threshold - -[192x192/intl] -Size=192 -Context=International -Type=Threshold - -[192x192/mimetypes] -Size=192 -Context=MimeTypes -Type=Threshold - -[192x192/places] -Size=192 -Context=Places -Type=Threshold - -[192x192/status] -Size=192 -Context=Status -Type=Threshold - -[192x192/stock/chart] -Size=192 -Context=Stock -Type=Threshold - -[192x192/stock/code] -Size=192 -Context=Stock -Type=Threshold - -[192x192/stock/data] -Size=192 -Context=Stock -Type=Threshold - -[192x192/stock/form] -Size=192 -Context=Stock -Type=Threshold - -[192x192/stock/image] -Size=192 -Context=Stock -Type=Threshold - -[192x192/stock/io] -Size=192 -Context=Stock -Type=Threshold - -[192x192/stock/media] -Size=192 -Context=Stock -Type=Threshold - -[192x192/stock/navigation] -Size=192 -Context=Stock -Type=Threshold - -[192x192/stock/net] -Size=192 -Context=Stock -Type=Threshold - -[192x192/stock/object] -Size=192 -Context=Stock -Type=Threshold - -[192x192/stock/table] -Size=192 -Context=Stock -Type=Threshold - -[192x192/stock/text] -Size=192 -Context=Stock -Type=Threshold - -[256x256/actions] -MinSize=64 -Size=256 -MaxSize=256 -Context=Actions -Type=Scalable - -[256x256/animations] -MinSize=64 -Size=256 -MaxSize=256 -Context=Animations -Type=Scalable - -[256x256/apps] -MinSize=64 -Size=256 -MaxSize=256 -Context=Applications -Type=Scalable - -[256x256/categories] -MinSize=64 -Size=256 -MaxSize=256 -Context=Categories -Type=Scalable - -[256x256/devices] -MinSize=64 -Size=256 -MaxSize=256 -Context=Devices -Type=Scalable - -[256x256/emblems] -MinSize=64 -Size=256 -MaxSize=256 -Context=Emblems -Type=Scalable - -[256x256/emotes] -MinSize=64 -Size=256 -MaxSize=256 -Context=Emotes -Type=Scalable - -[256x256/filesystems] -MinSize=64 -Size=256 -MaxSize=256 -Context=FileSystems -Type=Scalable - -[256x256/intl] -MinSize=64 -Size=256 -MaxSize=256 -Context=International -Type=Scalable - -[256x256/mimetypes] -MinSize=64 -Size=256 -MaxSize=256 -Context=MimeTypes -Type=Scalable - -[256x256/places] -MinSize=64 -Size=256 -MaxSize=256 -Context=Places -Type=Scalable - -[256x256/status] -MinSize=64 -Size=256 -MaxSize=256 -Context=Status -Type=Scalable - -[256x256/stock/chart] -MinSize=64 -Size=256 -MaxSize=256 -Context=Stock -Type=Scalable - -[256x256/stock/code] -MinSize=64 -Size=256 -MaxSize=256 -Context=Stock -Type=Scalable - -[256x256/stock/data] -MinSize=64 -Size=256 -MaxSize=256 -Context=Stock -Type=Scalable - -[256x256/stock/form] -MinSize=64 -Size=256 -MaxSize=256 -Context=Stock -Type=Scalable - -[256x256/stock/image] -MinSize=64 -Size=256 -MaxSize=256 -Context=Stock -Type=Scalable - -[256x256/stock/io] -MinSize=64 -Size=256 -MaxSize=256 -Context=Stock -Type=Scalable - -[256x256/stock/media] -MinSize=64 -Size=256 -MaxSize=256 -Context=Stock -Type=Scalable - -[256x256/stock/navigation] -MinSize=64 -Size=256 -MaxSize=256 -Context=Stock -Type=Scalable - -[256x256/stock/net] -MinSize=64 -Size=256 -MaxSize=256 -Context=Stock -Type=Scalable - -[256x256/stock/object] -MinSize=64 -Size=256 -MaxSize=256 -Context=Stock -Type=Scalable - -[256x256/stock/table] -MinSize=64 -Size=256 -MaxSize=256 -Context=Stock -Type=Scalable - -[256x256/stock/text] -MinSize=64 -Size=256 -MaxSize=256 -Context=Stock -Type=Scalable - -[512x512/actions] -MinSize=64 -Size=512 -MaxSize=512 -Context=Actions -Type=Scalable - -[512x512/animations] -MinSize=64 -Size=512 -MaxSize=512 -Context=Animations -Type=Scalable - -[512x512/apps] -MinSize=64 -Size=512 -MaxSize=512 -Context=Applications -Type=Scalable - -[512x512/categories] -MinSize=64 -Size=512 -MaxSize=512 -Context=Categories -Type=Scalable - -[512x512/devices] -MinSize=64 -Size=512 -MaxSize=512 -Context=Devices -Type=Scalable - -[512x512/emblems] -MinSize=64 -Size=512 -MaxSize=512 -Context=Emblems -Type=Scalable - -[512x512/emotes] -MinSize=64 -Size=512 -MaxSize=512 -Context=Emotes -Type=Scalable - -[512x512/filesystems] -MinSize=64 -Size=512 -MaxSize=512 -Context=FileSystems -Type=Scalable - -[512x512/intl] -MinSize=64 -Size=512 -MaxSize=512 -Context=International -Type=Scalable - -[512x512/mimetypes] -MinSize=64 -Size=512 -MaxSize=512 -Context=MimeTypes -Type=Scalable - -[512x512/places] -MinSize=64 -Size=512 -MaxSize=512 -Context=Places -Type=Scalable - -[512x512/status] -MinSize=64 -Size=512 -MaxSize=512 -Context=Status -Type=Scalable - -[512x512/stock/chart] -MinSize=64 -Size=512 -MaxSize=512 -Context=Stock -Type=Scalable - -[512x512/stock/code] -MinSize=64 -Size=512 -MaxSize=512 -Context=Stock -Type=Scalable - -[512x512/stock/data] -MinSize=64 -Size=512 -MaxSize=512 -Context=Stock -Type=Scalable - -[512x512/stock/form] -MinSize=64 -Size=512 -MaxSize=512 -Context=Stock -Type=Scalable - -[512x512/stock/image] -MinSize=64 -Size=512 -MaxSize=512 -Context=Stock -Type=Scalable - -[512x512/stock/io] -MinSize=64 -Size=512 -MaxSize=512 -Context=Stock -Type=Scalable - -[512x512/stock/media] -MinSize=64 -Size=512 -MaxSize=512 -Context=Stock -Type=Scalable - -[512x512/stock/navigation] -MinSize=64 -Size=512 -MaxSize=512 -Context=Stock -Type=Scalable - -[512x512/stock/net] -MinSize=64 -Size=512 -MaxSize=512 -Context=Stock -Type=Scalable - -[512x512/stock/object] -MinSize=64 -Size=512 -MaxSize=512 -Context=Stock -Type=Scalable - -[512x512/stock/table] -MinSize=64 -Size=512 -MaxSize=512 -Context=Stock -Type=Scalable - -[512x512/stock/text] -MinSize=64 -Size=512 -MaxSize=512 -Context=Stock -Type=Scalable - -[scalable/actions] -MinSize=1 -Size=128 -MaxSize=256 -Context=Actions -Type=Scalable - -[scalable/animations] -MinSize=1 -Size=128 -MaxSize=256 -Context=Animations -Type=Scalable - -[scalable/apps] -MinSize=1 -Size=128 -MaxSize=256 -Context=Applications -Type=Scalable - -[scalable/categories] -MinSize=1 -Size=128 -MaxSize=256 -Context=Categories -Type=Scalable - -[scalable/devices] -MinSize=1 -Size=128 -MaxSize=512 -Context=Devices -Type=Scalable - -[scalable/emblems] -MinSize=1 -Size=128 -MaxSize=256 -Context=Emblems -Type=Scalable - -[scalable/emotes] -MinSize=1 -Size=128 -MaxSize=512 -Context=Emotes -Type=Scalable - -[scalable/filesystems] -MinSize=1 -Size=128 -MaxSize=256 -Context=FileSystems -Type=Scalable - -[scalable/intl] -MinSize=1 -Size=128 -MaxSize=512 -Context=International -Type=Scalable - -[scalable/mimetypes] -MinSize=1 -Size=128 -MaxSize=256 -Context=MimeTypes -Type=Scalable - -[scalable/places] -MinSize=1 -Size=128 -MaxSize=512 -Context=Places -Type=Scalable - -[scalable/status] -MinSize=1 -Size=128 -MaxSize=256 -Context=Status -Type=Scalable - -[scalable/stock/chart] -MinSize=1 -Size=128 -MaxSize=512 -Context=Stock -Type=Scalable - -[scalable/stock/code] -MinSize=1 -Size=128 -MaxSize=256 -Context=Stock -Type=Scalable - -[scalable/stock/data] -MinSize=1 -Size=128 -MaxSize=512 -Context=Stock -Type=Scalable - -[scalable/stock/form] -MinSize=1 -Size=128 -MaxSize=256 -Context=Stock -Type=Scalable - -[scalable/stock/image] -MinSize=1 -Size=128 -MaxSize=512 -Context=Stock -Type=Scalable - -[scalable/stock/io] -MinSize=1 -Size=128 -MaxSize=256 -Context=Stock -Type=Scalable - -[scalable/stock/media] -MinSize=1 -Size=128 -MaxSize=512 -Context=Stock -Type=Scalable - -[scalable/stock/navigation] -MinSize=1 -Size=128 -MaxSize=256 -Context=Stock -Type=Scalable - -[scalable/stock/net] -MinSize=1 -Size=128 -MaxSize=512 -Context=Stock -Type=Scalable - -[scalable/stock/object] -MinSize=1 -Size=128 -MaxSize=256 -Context=Stock -Type=Scalable - -[scalable/stock/table] -MinSize=1 -Size=128 -MaxSize=512 -Context=Stock -Type=Scalable - -[scalable/stock/text] -MinSize=1 -Size=128 -MaxSize=256 -Context=Stock -Type=Scalable - -[symbolic/apps] -MinSize=8 -Size=16 -MaxSize=512 -Context=Applications -Type=Scalable diff --git a/pixmaps/linphone-add-call.png b/pixmaps/linphone-add-call.png deleted file mode 100644 index 9c9edeef86d112caacbc87d3df3ccbc7b256e390..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2808 zcmVmd!Xm9YHRzwe(%k%r@N1kATuMau0XT06)0dd}9?$cfQk5g#0A1H7 zsjB(}fQw61N62$Jju#QF&StaM`@a8Spt9q=bt`}~0ED?*Zsz*+>;E$%J;2O&L%u8_#I42TB{ca@LWr8;O5gYQ644K(s49wb z7cc@tXz}93V*oS(05iYpIL<##G**3m{SyG*}Z8fS#V7ivUyufDq!TlZn;b z+#C_n8Yw1)5OdX`oSK@NP6@*>1EAIOymyEDP$9&$xSY%7j!s&`Fs>n@g$1TxiVH;a z9n&<^QtV^qcF*&k0e~oqwh&QlS5vkDmSxS!<#MZuXexj=Ez8m!$JsZ`Hk?*aJ^Ou z#RVb67y#(&>w6c#o5P5){m`L9AIS390)5YM4bXLcv}IW2&%m zW?s$AbEPT=;QmpgMm^Zq*XIC8G4nauY}PdlV__w8f|*~A%TW|H0eBn$eBTcN1aX~V z7zYc+_5s&*1C&4%MNQI2?} zJ4*#BhH0Aj0=Pno`vBZpiJ$Ab4_KDOlB_WLquDc`BukqHW$~4TrM{z7MS^?VuK>`=L2{Y`EkquZm@0prAo=ia9!7L zXlR&CL{|g&JAe;Lm>mJ|S0cLHah!Rs>mElQ$oIhe1wAlnu!qVN;u*-LoSA>_dES%5 zB_E@?xj6!`3c#vVDwUWxapGhmnoLA2gm}BZzrR~9c4eUwQDOH_E@h5EJ5m0}K&AbDNu+k4x|rMcD=*&S?}O#M8R2e}1G$mP1T-qx_$=Y15`z#YQbHEq!4aS^zqv zYL=oXu3SStQwRW%c|QOk3`3)oq3`=g5{X2Hh_(X&5uHm!t)^*C92u&mApoGNs>%Zp z=iA>J%($hcfz zue!SW*`X4;7^Z1z>2x}EQmhMbbixWD9*fJ0qTF20$#I;0LI?xEZmC+Js_I&Kgfb{B z%UTLxdlW@4o2L2Wli+<6M;nmMX4eAfmg0@Yhp5G{ZTl@%RTpC5+pYKZ_O8)&eRL^% z%d+lb<|i<)O})>utUFJR{=gmpU0q$FrfE3vmOO?y8Gf|6-MB{=3-L)Z1u zs;YJZI1~B2d!B9E9i?3dU|H7L%ickkY& zY1#th4_m*WC`uv-f+3ThAP5dkpFX{nnXd*ghKTAgu*VLB5QgJ89R>E=G)>zN;8FlY zL>FtC_Er!C+lJGCQU_Zsgt!Sn4*)Rpk4)2CR!K11wqGM63&7z5^=2W&eA~9)D7JT9 z_aP$s9`eIT09avJ*0sZFz;QhQ0K0bWI-+UX8vwo`17BQQTe~F)g0eS;01yPh{^`@F zd(4~y(Av|}bIpbg8{R8pzg5$;_mKa15P-{TYipkkf}o;JQrQa*%d+ld=3hv$pNMX7 z9Ov;$0uKlE_4VVctE+b+e|Z6BUhH|^KP&Mq*#j|xAb6psrY1>5^Q7$+nx-X^$>hfF z?(R=4ovy2^dj!CIDX#N8@28de4tYP|dERYAbQ=b)K<`c_lO2|24Rya;5lqv(3BXbS zAfmlt7+#0`oTvyD-;r6CwUn9vi2Q;D0Q~?~D2j4_TU%Rq8P`E!n&vD3FCl*c5;F5b z&+|48;dTs$b;-AA(V}T#82%Z6UZDO6z)D3?R<^aZy;^CkbUHmYilVImz6=0FbhqO; zKN}7oV2C+TjLy!^Bg>X8du-31J>5h!8^Cw~2>=%|^Ua#3U8ZT;shXy7DwW#5W5-P+#5mz=*7@`2SC1V#b~%7MkUtzNMlbT&>Rux1X67+O zG!DQNX8uaSv%7^5=h?RX&WZ3i>3iZ-DwUWtY0@PCzD-0K$RofCk!9v4&-2!w=<`3( zi|$M&Ga(Ga1pqE$<_iH#K|aBYkHkX&2LWtl<_$#DBJU4Q82<;)Vfl!d(P$F@0000< KMNUMnLSTa3WEIr_ diff --git a/pixmaps/linphone-banner.png b/pixmaps/linphone-banner.png deleted file mode 100644 index 6fe99ab776cc3efb84701439fd675e049a376cfe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8708 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�k9z7aqnXQJ!ix+=aMArG{NfAlz+qdsMpJl7g zfyqdvQXR&a?M!?>eiPWz(9p2GzrX)N`RLF&RvTk}2&&7nDKggdOlDn6kY^A?z?uix3}Nb+uK`qv6zv70FL9_VT{=s9?SS=%(AWHOmh-x)56fXPUu zQuW1R@n#WO2rLkhg{oQujEcy=RQ0r~z9u4vT-S~CA1wa`1U5+o*Q0i>00000NkvXX Hu0mjf9~bz! diff --git a/pixmaps/linphone-call-status-missed.png b/pixmaps/linphone-call-status-missed.png deleted file mode 100644 index ba6bee6eed9deaa42cc9ccf3723eed9ca2238dfb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2122 zcmV-Q2(|Z#P)zxYPL?xc3!nO78=Erihrh;6HVj?1c=pX(z zrZGmBCPr(cMvR0S6$wF!C)RQe_hV=F4oVY+)G8H|N^?brKwR>5WCnqqz$Jm{Dc}|b=NgdzMjiPr02gJTP$(F-ZGQ_Gt0Digh};Dn z493e?SSCh+Td8JZ9k4U%acV?9h*d>jU*FPnI{h$kbB%c)u*r4ZY11@2l~N^OWpM43 zh*+NIJ=cnmh)fiLjS9}kArCbfFimq+DwTS+j{MJZx!g^z>rMlBo_9h-27tc@*Ow`! zT+=k)*NT9MOw2CqIOKyEVB7YPh&%#h0{g4LJ+ABiHfmzqwyzSA5^!B$TI@A(80cz7 z9)b*rNTG)O0pIsm%|{-fSS%h>N)7PFt%+FV0hHr7U0UnuV0&AxwRWaRZY6Gvsj z_x=9K$;syvY5+jsQDAe8=|x~=xF(`t_`ZKbI8aJG5tls7$;6Ssv@D%Ye=`~F3W8^T zbDjC^GR4WR={ubtb50w{Oh(9I`5V2r~iCEZCzJ^k2NzM3Jl8O8K`>zv`VXEtA zxL7RSmn6nK)n*g(RHu4>LqskM2fpvW7I)%&KEEWDN{s-y!1Qc3o4t$bUZ+*^TcB}? zog+Xg)e#PqQn3W|^z>xPbM#3tZB zbt2jfrPQnd5osvEvaIz~{=E=i@;q;M0`gtVCA(F@x8wLKcpMmFu85BrK&^lkP2zll z>i+47VHgj_nY;!ksl1#33USGYs1b1icpZ4&FbrdMCn+K~H40!D#*V-l;2N#_a1t`n1P6A7TnR2;&`P9_Zh4}*5w(W?>F5pdp>FIL0 zJUBHq6}tp4CJZWd`{`hONhXt7-N>O>EKZ2XtyD9yCY?@?EcC$ND#GXa$r{^j&73^X z8>tVnL5Rp5FhK8EL1rcjet$Qy|=w^;?#ek1rv<2*+_&1AhX-$K||I>T}ebvEz!E zBOu7a_i9W#dV702NPuP{Ow-(~wVtGUiu#a_)04^Na!&wOU^=d~zOhs){WGbMAQQg_(jxMC&+~S~ z@yqA)SNgs`$=pnQ*z>%wwHciOfPMS+{TH|$_*-DQ(lCrk$8p}BRDkDsW0_25MJknA z5tlr``1ttoR4UaEgn!ynrBrltHwv!no~2T!j|ZkMt@U2Van>c^55VZ?=&AAX@#D?! zoD1Lgub}dR3$ds6decu#uIv8G_x*k#Y(Fm1T2Gj!`GrEE(A0k+2=+$9RExl4uIv81 z_MTV-CMPEkipUMroEwxLE@8KgeV(}RIW@hdHJ_W2I zW~HlxFCuq%p7*TIBQjC0gq>TI+R&VcaMpT~uC5QKDW3_A8}ITI)a5ZWkKi z4HXcDo}QjeM@L6zTU%Raxm-S@wLS;D)@ozye?~%j8Pq+~Jpcdz07*qoM6N<$f-hDB AwEzGB diff --git a/pixmaps/linphone-call-status-outgoing.png b/pixmaps/linphone-call-status-outgoing.png deleted file mode 100644 index 73587dc7a79ce1c894f3f4986f233f5095c0fbc8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2140 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 T?#Q9e00000NkvXXu0mjf^f@!2 diff --git a/pixmaps/linphone-camera-disabled.png b/pixmaps/linphone-camera-disabled.png deleted file mode 100644 index dfcc711cde58168018c6c163ee0f36d36cfb3c7b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1599 zcmV-F2Eh4=P)iAhcy5I1)NDlK~!jg z)tOt2Tg4g2f1mA8LMYN!1R+4GK%zG!hH`_6Y}exK)?@tHBqLj^%_g0=QE0O>YNt1`wc7m?S1MXI_w*KMFy6a>Kv5!nxX z8_4Byxl`uN2v}=-fqlTD)b;0bxx8*(jDRs_Ik1;H{GM{Tyl!M}F<*R&J_!3tnM za4dj`yjm`oFB=&dsQ}FB5pd3(pCrjRJkVdMRMywvVGbwYoC{QSfO^^Nj^p^UQmGVY ziS~g+LbmPjMVyF%dj~1VOMONs_yOLZ={`=#YpE zs_H|)(EuXy$4aGgbegt_s?@9Em7boSEBpKVtJ#1c2o|a8 zGpc$Oa9061D!o<)MmooOn0^c#LmmFbWy_Xb+t=5ZWP^&u;u%Sj^aDRkT^D4_=I`En zcjQ?Qm$i1asv42;^<+YL=iCNWeTK0_$JN!kx7Mx(_DD)EBA+f@y7VykHEY%!Gdeo@ zw5o1QT~**q;5g{w?|`-TV&E^pw=(Vzvhc-X@%y8rqi+H=_rmi|rOyxv;-b{cX@KA(R}RnJQ8FI4r4D2l>n zZFVdHYwb@|^$(docZ6Yh17qKCO-nMX(ch9JSwA#1^x0(Xc4Q71V=e`<@Q-`%8{unG z5qU6<#B>HEKvB>Cyk(9pni+drZSIOo=@>Q2&M zSXF)0d;jysxLhu`xmvAWQms~Zl}e?5w$jHDOTb#YQB{9Oy-Xj8qUaYB#SRV*egbTt zNk2zq4p?h90a^Hmz4sHs&sJ?80b|V7jIHfC01??9hT$EP-4g`CsWUC1wvK>v?ivvp zhX=Mz1rLxU$qo_ORwxt>I_EBGrO&n{V6DAYRiDqaxy^fj=QMBsPWpbls_wJaKG@sa zJFV(yO9Ix~>wq1Z_WD|YZGCK1=;*=I$tp?w@IUHI+)Gufs6B8CVPa7Z6q5QYaL>bMBSp@4-bE|aN)x9 zfZwOC#j3iWvHb(kVgk;&+ePHjnysq848!oZZJ}+Vy?gh5<-Omesv8*F3+GAq!vJEf z9R_-t`dH<=!08$LW8l*^ah{Vx?epHRX%|)7LltA8^jy$2@_Dh6Jp&_XBsQrUExcQS@BLsanwZB(~N* z0BlXoL`1F*!|&%vSB{Kk1Gg*9~fiW{aDZu{U3Y-FwszhCGG$K002ovPDHLkV1n7l{piAhcy5I0>nu~K~!jg z?Uz4j)L$ zr;1mSTrT3EVzpIpaB{JOe^4Ci)tY>-LvwHz?@tTY`-c3Me0lS{@H~8PNIoDXB_$;# zC8c$c<2a|Jlw$yl7JFIMH0_q_x-T0Mo2JviYw> zGzj2LS)*)#{{H@px~|UyIGU865>b!md2Xdnxe+o=v%RgYZIYRb{Y*-EAqaw{S`8|`1588{Q50qCnFrL_ zf$z!no0Rf$5Cr)~81OG>Aid2#(nDH{L)ipAoGj*gB#0QZto7c)Nr zaICCRIsgF7&d&bweg7&m4`b~ttRp!O1OI-ByKUR9dT?km2kHq5g~ENyvgUPNe+b}k zxo!aXoUAhd?B@7unAKVji^bx5$8mb&IG!e=VIrC{bX~s@MbRH3+PzgStFWqRTHQZV x*L9Zxj0_A6jOO$C-&^1-B_$;#B_*XQe*xuY^1Gr|+86);002ovPDHLkV1hC#crgF~ diff --git a/pixmaps/linphone-chat-new-message-and-writing.png b/pixmaps/linphone-chat-new-message-and-writing.png deleted file mode 100644 index f64f525bb0fbaca31e0420f040b860292f5d36bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2029 zcmV@ zRg!en{E#1!cG5;`n#7@Fn`Wl%*rZ8j(#D!LPNl$;s2Dr7Gir%VO>K~(wzknIps^5% z7^)CJ1?9cF{p0Y$6E64O_ke!?*?qfvcE9J|-E+>K`xFBJol7K;ib*Ppsc5DE(P%~j zplAbHfNG!$gTvHvOudV*ziX?0k@m9`MK-V)hzxOxHWYg?@zOz=+J!$H9w95BmlMTs z@_>9GF`Pv$PzSt9J6qH)+CvcxNdcY3att=1NeGFa>jgN6!8%pMUbiBy6wtYh$Ha?l zmH!9c#KX5$0c}nL9Tm{4NGF0_gZ9+>#u@xPph`GpH^^22oyAfVJAvT?O3gi*Q7lzO zl=n5DPX%-~nZR3sXE2zBfU9U0DKC{)ot6sdRitC^Hldrw!NO%s($qGpdv^3vKtDnP zLpTn6F63p#Pl1%L!nAu}Y!Zwb2hn4pvmKf*K-+)eKS$w28B`yF8zERs#VLj{S8d^1 zp9*MDWOD#m~3!0&^z6>zc)&YytRMtSN(hr_4@h?@x0?uHrn!RYZKNZ7^8^b3^2}-xDf%F&qL;OpbWV7DZKp}9C!_`Ty|DmDN!QxN06K*ZS^N$ z^GdjI+DZBY+L;vyJ-QXhVFQ|tL4=fJ^_C#43Bs)#!P@Ur7(Gcyupp> zPH*CURm>~^0|1juNAdvoeNV`16Siaz40(X2dUz!R>W)KH96YlZhK{h4n5naw2LS~j z%W;v|Ti~G|OMPcPRPO8_>7HnB6(yQK78AVehfWe%07lnk#Mx}Fco8C_q4pn8_KW@# zwnA$oy!njOm#l|zci4?y24LXlPMkdM$XJ-SLh9R|0yC_;hdUf86({Ez3h9sAjl5N_ zW|9Yk`Dlkp=R716HdMhGi?}K>3Zk8lP%rqd%a-Yhzix%83&lb1e$GaoR1YSfcMPg$ zXG&?c??=SI%V*{Ag@bKRiT?=3Klg}o36sUU*PpbORZKNd*lsicCeDi5cYjKT^oI&qHPr{6FkdQ2qXip?gm-3UdcG9gL!1)B$9f#yQ zVb&6;D7m?>$da$v6n6AO60*cl(4Ch`&t^`MINZGccdi=JYc=O0#MW#m^cRD)VwF#C^8!ET{l21`#@A2-2H^qD|gtB z)l?a1DjX-(Cj6l*kbB_y@D8k7EPp|ixL5;~rB0(O4C*<8n}d9)0L~qeF!#wFPT_8N zSnw!(B~R)_Pj;J9YgDOXJ~p~i-1{9T*CuSu6E8V=fhZC14+DXe4ER=|Tv6Y79ZtRD zB(Vnq_W?z*t3~Qh!Y?0`Co_Agq)_?`rQrU2c>0eJF$9k7hHWm+nL&vZ0CkiBwXPOC zeNgf`0CBg4L%ADCb0Pl#to(U5`CmWg#^aZ(LQX(e+EBfVPiONou-VnZ*RM)BqDL4t zIzcRzo%4x`gBkZiS~kpFB5l6wuzfxJ`B$!%2Q~&O-FZ)g0!-EeNw%V%VKC*(Qa}Ii z?)K^Tz;}0xQf-$c1J~Lpm-NVJ$pghrl*m?f-DI^XmS)dS+@wR9Jrrq?3WSV=Tp-LRwUw#7}&c3i8sKrB?D&RuTj=n!|Zo5Eih@G zWYClWP3OfYT&x*P(g8FA>8cpZ#q2*Zj>r0|OfVenp7L@U&0L@WH`mYp!w0;`N8Dw#=X)Zw58b)kg=RCF>0#5e$6*ZC z1lxHhg!5N}2u831%?7|GX%i9-quGd;{VK$_9QL0*0CX;?XjY;58gP4v;#I&N6kb)t z2jOz)mjc1itC@tK`DmsAcL1>{qR^PY6`%=44JOqLq1?^>c7y)`q6SFT%+0veII864KrW$+CSeZSj2)I!SIg`zpp`~S^gW6bO3Rnh4TBwkqp~5}84~rXw z_nvd^gZ^LEKKrh<_kZoP&)#e8eH9^q&L#p##3T{L7&N1S7&K7;D4K!eKowAl!8U5x zrM{vq*uGUzq}`;U$ONVV5q>t&jAA_|E>2OZN^l3l!*2)lOrnWoA&>(M38Ygms0CKg zLar*I#UDez9MBoe#9$?wL4MJ5+yMtLct{nn-l>Tr2Xr=rF>xVN<^RBkgmbUTquEZ; z)&V__WWp%vwo&(u{kXYR6|vV!$lqleFuZ+!EWGOzq=Vc8WL`R zu~T6{Jj4!!m;un*0*!~D`3U^F6DmrfYAc-aW5rbLr5BS`E`R%UK!YNaO+bp{hK(?o zG8=AL21Ca?Cv>I-w&ub57og!cXEuuWQ~`JWx2h9#2H7aycT8ej3S_+@BM;zigP*s< zo>KU&0-EY&)O$uk>>!9624k;<@z=vSgTOp#Pla%RFc%yRlus*aA=>M^-r{Li6`{v za3G6iXr6UM{(%y>bcQ^axxn=xv>dl5?hO;uU|}A_^oLU?;Kgb1i`NCG1DZROi`D-+ zptFg|$z|Yi05WVl=`#dwdrHb{a-e)o zaHPAUrAeG<{9Tsd^vCQhG60PBWW;{ioc#hs#K5n+;PVy16ZVFtdiZdOly6)L14meC zrvn(cxdOW#H>xjOHcQGyi)9LR7j_iOCKuillIL4#p05`$+`wRpZKIQJmj(}4!hWA| zRp_uaPh{d8SvY*5jYI>Ji)cb6ymQ~)pc!cZeQX;%r#+WBb})EyPI0WZz3;(RT73*4+O{zxOr#mm!9ieX zJtZ={mv0?KjDZA5*7)nN$iAUEgm8eUej=?x6pc2(K5?d@PGsB#!4q?eA!9|>|6--p zWB`q}jn(cJIUzMzTFx*u0s3DE?p8Rk(@L|^K(XJp!5zgSC#Fkm-`z-@BXZ9sIN9J^ zPf=}PVjF-{{jE%+h#0u;p%Ah3f#^86_8uvhueR3JR2pcu+cv6ASogG)(;tVv=LN~q z0yCczC;q60@?tyf?FM!1z{!XF^?Q<#M?_2PZXNChhRg4ia2=rFKG}_Zqf!;}yU~8c zy}`C|ZNj??Wmy|_1>C>7V}A$*5>nyrd`VHid;|7wwzF6Vo_s)2=%|yr3V3yfjLgI| z$!mj!QgBlaJp3ty^?+S#;R6TXnL&{VfLcm{8b=-O+X59ErQAQreIb4_zL)uV~YmyacRr)bZ()B71iUqhbd_WGwvovv1qzI2eB&BxS;c8>O!8 zG<>uazIfeH_rP*bq2t`sAPo7fJn1OJTrp zDQ_==qK74p8I~Z^C90n!?9E5S=>t3AXpKLlJCWl#<>JxKRcAXOcVN4KG5=Q1&xNZN zbS#_hRvB&2bMsLsydQRy1V+pm%84LZ<ZW;VGyVxoFtXUp{_spzTn6r2~8;wMcnxiKS@FeWyooA-5%NQyC3yHvMR)DXVzCt z*-XadGoXKWFmr$!Oj5mFY2aHMU`}sPj5+hd};n5Jqoip;-nb_-pS2+t4h> z#Rlc)TMqco9soLsS1K|E0|uY#KmcU*D_1 z-+_YdP?iI$BGT5`*?Be7&5Qx`_xHbSS=M=SPmS9}SSi)g(a|yb_>Ct5ICt*c^RZa$ zKR{)!UdqbKsH&=>va%Ad*NfZj#_e_!kH?8dqnM`2{QNvKGc(N2&XPztPyJf!&)3%0 z4!{2T>yb?Z&{|6<6#5s?=CorGp|-Y`#>Pg<%gY@LN+c4DkB{@|r=POAy6VVAYyC&R z-~atb{BQgc3WfYy>!4E+m6eqoJ$jU~va*x|?%lh`^z<}KOG}uhiD{Y`hCy+0F&>YH zii!%Vs;Ve1PUZ#6vKSp5<&#f7aq^33pslN`>)%fV@XkB$lqC|0TflR6y@&|S&CN76 zHX5yCt{n3S|hATJZUNoH=ub^XJbq zKR=(%w81pZ*MPqOC`cA&BJvX_j*lNdPEAb>mSr(GILN@jK+fVf^5vIb^8WkpbMM|g z3JMBnYinc2jvZNTwAOE?J}UsF)T=m{I`#GS)Ya9YwPs*ofbsG1EeqdBBog7mg$pb! zEZ}mvXlrYupdjn=)7013cO)Hvh;-OF@pwEmH#Y-t{rYt#Cnuj?`37RK7#A*FAQFk- z^?GS+Y_v1!08qhT(5Nu=m#t|{PfyPa%CfAZcAf6o zvj?RV%gf8m&CTUc?Ixt2t<<1xMnOTrF{PCHx?P96ckc$s`@G+bFTVJKL?S_HX=&Eg z-Lk9~mDYNnU57rO58x{qeSr1#b(WTv9`T(C5vfyvZ2{wUCm#`~HA_Bt@ZbSJy5!h| zas_zpIul7&9NYQuK2EAGG7MwWHd^aaMY2H3N;H~0D6kogyy9}X0J5&~BBGUu*lwI7 zkz@((_1gYec_UR$+`pey-ip#%FWPmsu&@9mE6A?`pU;Qa>&3Dx!r^eXri)5zeao)H zRQlY#dw143nJ-fL|IVE|S<7>+^_Wsh+13Sfb8|!@5ef?nIdI@W-h^ht<#Mrq|9${& z-@cu-t%!^$5xH#Fsn(hsH*NsX)YOE>{6%p5#;5SPov%E}5;Q&V=$FRSY6>LI}P zK^`9;XMTR3f`S50o;+z+?rw>_d-ta6pDS0c*ljUKy1Kfi)x#t15A8bFT66jGW!Bf% zdG^_7IdS4ddVR_#{2sEehs|s#Bn^He6dngRP@Mox7$r& zVPV$A$K`TSSy{=xef!w8YZs6#8?Il!&dA7!6ZZgbr9PyeM9Z>zlu|zh_GYs*4C9fb zkQ5aa6`VSCilU+-Ow%MB4r7`oYiny178a(@g?v8WBem7k)D$;v+;DQ7l47v4v-6)_ zU0sg`5C{a!U@-V2rBv1j`p}_6csw4W(I~UCvlxcKOE0}deSLjenA`16k8UPbR#upv zo@Q)pEEnMb3CptH5Rvp8dm@eW_V)f+M85a%_za z!^6Yu*s+81@^V}*7cQ5JSS*HVnna^f!r^ebRL&I<`Bi6U=g&7@dm@>8Jf0s!qtR~w zFQ%>?KYpCLy1MiTTb9LZadwY6QvytWHWyZ(H85?Eu)4a+($W$uD=XV6I>j9Da#vT^Sf-my$0c_7nR(3AM0Rg8rPeB~`O-)VB zFP!`pAty1xVDOZPye%U2Tb7rdLCdn<2m}KEb!xDczZw{kNTgjU^`_R^_5{`;gCg=) zM@Pqp8y6`jJk@jv27|{$ExyrPNUoIRNYf wd|GR-h*%=>Kx@75a1T2gi^VQw%IRC-|KIc`66x1P0ssI207*qoM6N<$f(pA}ng9R* diff --git a/pixmaps/linphone-chat-send.png b/pixmaps/linphone-chat-send.png deleted file mode 100644 index 9a9f9d731a7c85ea9ea9e35f188dbbbbf0622617..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1436 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 diff --git a/pixmaps/linphone-delete.png b/pixmaps/linphone-delete.png deleted file mode 100644 index d8ff8da4a0474868855c6032741a4e6309c53254..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1190 zcmV;X1X=ruP)33OYzQHTs(a9*dQs@flMo~z zLM`nl%PpRI{Q$B+4TS-m>($tpuQHT3doCk0^M{ z`yFT`fZg5QH2@sYPac$R(;C%k^#K4+1mccmS-&a)tgNi;00<`)E0xNlgEpO;n=2WH z@sbeY!Tr9kR4OM;)4UKUH)u?Rx)ITOc$iAXoNP8-*9W?h<2c^}xTfp+J;jX>BByEE zb!PtB_x;ZYt>ycEB=>e4h5j= zdV9YU$wGf-o(PTK?RIYr1<-6Ze*>@`h^K`R<5_55sZ>q_I39?%Y}@{8*p7?=tcSnT zbv={%NYgag+U-~^r5p!+3#U0I69bSl5i?I_1Q0m`4FvFge-xRhd_W>m2k3M<>j1pa z0*i}_sdi|yv$MwmJQj#|n$70zSOBe7s{`OxAdW9DFF&3pK(E)6>#o(qN(hzbLYW1! z?50utKN3J+Ag2l-uYXt%pahU*Ng=N|n16Tzh^*D&y0}lm|MJ9^+6k;fV zEHaV2uADd$0m$d`8vuG?!(FS@^dyy^nVC7k%#Q@(pSErPo+v=0(Qp9V48)_`+uKhi z3E;Y}>^`eX{e!}9|1qoQdF8a+Mgjh=jpf3}hOV|R>Nr#gTfa|)~ zr9ghMTCF~mgz|=AJR?0T+HxG{Mk)ZdZQlXV48$?d^WICyeLj$SfUj)ZcGC)C0JwyI zANsy!7{+UHls8TD9U{6Ah+SsBqPm9Cdt%G7zB5hpQ)Yf6fdA4o&2phoxa2rat5;r0mOJNm-`67>oG&X2XM7iDlHuJ8Z{LF$%m`V{5F6&MR(i-@C`G6ytK5` zij{(ss%2c)eHy@-!~QoxL|xDGHpa%rer_}xcazxrZ(>}ljksTe{Qv*}07*qoM6N<$ Eg67~NY5)KL diff --git a/pixmaps/linphone-edit.png b/pixmaps/linphone-edit.png deleted file mode 100644 index 7727709884010a4630edbbd16af0855dab088a2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1758 zcmV<41|j*0P)Ga{DY{V2IZ`-#0fk7Ss>MYAjhr{7>rn&=U+xFW4T6BK^z+nI&qWQLMe;$v= z=S*1#qS5H90PfP=91-2Z%u4|Lrm?w7sjh~GhD)cM1F=}_St5EwcbSOp@jUM%-}iSa zrRo9n=&@OrWqlft$FH0+MeI1v!vNkW^qKh)-}hf1CHLQ{GH1us*S=kb+ROA~Q8|N~!4`7Cdz7#^VR8>{IJ1{VC5r9i| zO}5OLGpE0&r>EP<+Sx*gP9nNcLwj<$TvST=XGt80L?W}9IZZ_8X=rCC6pAO4$s@aW z@6In;v}o(Vz`(fx7MpUGsrnwpxdCQLdbHG24{QmV1Dv-4Zi#+ty$pHW_3-cCgI8tMfQ@qK^K zaCVtYrmMEL_ICiy2An0L7T@=~N+Kn+vV5P2B8BJ?(NZbp4?*meQgh8N5#8x|o`1S$ z?TJv9mSt@Oa6>^^GV}FP%5MT{qo*Nmt79v%~LNX zdffB8R|48P06x~cG61ZXQZ5f-Ta*mMVzJu*tTmP8D9B%>g!g$`0+PQRKpMbV8j@vYWz8KO9oeA2FUC1-t|B5cdhgZO*9VGTBoe6wkTS@B zC4{(PG~~yX0UfgG9jSZ3fU-h@Mia#XMAuu;Q!+ zaDPD?5z!sK?!jQ)*0Qt+5QlH@DQJ>s&5( zqm(j>32uQh06+~B`I!JZ0Gz9#?=8!^E}c#vE5)s!7*7V8nwqMWQWC(t!nKZNS@BdV zbqFPD_Aqxdg6NbFb&lg~V&)k{Gy^9uXlG`#+3AMK0RXYF%HpCsU|AL^b!z4;1hCL> zXmINT&?u$Mpu}ysBK{F4zei0w&2Sb#FEjTN(Ox0MbFS;|!Xz{rLI2MaLR_ts>LsFH zrPLqUZ1!MxclS|Dkw(TzDKw^4K#1%}|IaX?4mgf;7l60$|8G{KY5(YNyPGG&0RfqHxq^r)#_|GY?iWI=nk)zY1$SnL!e1yeFaQ7m07*qoM6N<$f~&Mg As{jB1 diff --git a/pixmaps/linphone-failed.png b/pixmaps/linphone-failed.png deleted file mode 100644 index f724121390091208c115672f141711af11ff1eae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1998 zcmV;<2Qm1GP)!CHa8>00%BfL_t(&fz_FP zY+F|u#-I1vZqsIzq#!!>5#oEzKzvl7Y+{80j?cO71j{cWSdEfJUeD68;>X`6g!uT{;5C*IVmCA2fht=g zJp@$Yeg$C0VkRQ`u9WiAYXMnLzVGLV=uWJ7=4)ss48t!1K&)IY&n1(|Ng~Pth+7J? zp68u4#*D22?>Q1eTnFG@EZc4BXx4F@Ym`!t0t-pY%$*L@hk&Ik>J>$)3^F{)kY zMM){Q6VV|6>nzq;X1+!#b!_p%(ycPalv1hG7>0G`h-l-A-dnzIE)Xgb+Rv{SrWj z#roec40jd^g>&XS=UFS2N>i@ujsX}1u-?+}9j@zcF~;2AH1&d{lvfeauK{edSYKe~ z!9t<1YOYm_#TfH9&+`NM3hrX z9j-N4bF~{|p6>1KRYWuh`>%8P)YR0)LqkJHqK1%CUbz7OGK)1}<_{{R4%IU>dQrgl z{kJf49>6Oja2>2vDtn8?VkJUP4PdjSU%<>mTI-)QGBtcz- z_&w=#y6#pigxJc=3U+uVq8n}SfcqHk(ZbK~Nx~-U#+1l}cr>SS-#1fDqy`A}RuSwWW@k z`6jLPtx>rm2LOOfCi5D{aS8z32=)igoH=v-rcIkJ4uaqqfQxJe%=|g6^*5VgYAOH# zNGW>&XaK1Q_6M2yA|mRs8JYQJt@YQN|G(A4)+EwyzAmWzlY{}{~t zR^Rt+?}SKdJ3uy@?F4X`nHwDrtkmn7`Di+wzNFpx+X^r+Ft9NU!y^FR*+Thcu~=*@ zo6RQMVQ4wPwr$%s%+Agp2Jr4ydk|4?7>316CgZi*qon}3Ty9-wXXkxHlxcP1W$JMp z=cw=duWhBc=>WN0Zr$nAr|(1U)4X%U%y}ZZH$vM>nRzUm&AzEwo~8oia=F;_^z_|C zG!VhAXJ==3bai#@0r2Ap{w-k`Y9YkdW|$%eScC`gz6kd5N~Ln$#Kgqh@bGZZ-Q9fy zGv67Z?o~uo6hd4Pl`GQTy?_6HXKZZjE+X0!!9FoJH@AI!eEi=l=MqAEkBB}Np~sBl zI9HF3jy_~F+K%u5fa3A^4~XbP5xkGAU%!64*82HcgXMC0#Phsv0B^JO>0stuGMPM9 zE|;HbWV8h!DdqP8SWl;!c`_c4i;Zy+4&oJy_&&I{^ILQV0Og zFmqaKy=pP7m4pxHv{UajU2OzLmy8xsY1H8dv zehz@tTAyr_FOu^4{N2pF8$iR8Zf5RS4A5vNnFio1r5;-=z$nsM{}jM3058ULno!p&y0mj*%5M?^Ez)6?T8 gPMkPmFPvsD5BCL*7iyL{izloWvL zx;GNh%K#cD3jyF0X6`4VkCjq`LWm!kc@zMMXdV$=$;@@kd@B*H0dVu={h7Ish#v8M z|Ffb3XlrXr4G#}*0?+}#PD~wT=2zl4-j&H@j-QS)q?8NeIBqAR2LaS3rb1?Zrnz!A^DJfR*H_M+ zJ9iTiJpmx4hmTm6wf4}VLtp3nP81M6n-KncA%yGu{^ml$YpPB7c5R`>xm@mK5Ck0n z(g1$Y!%L$m$~HGQFFq{*+HHCOT&0Hw0n~e*_clsQzVBz0QuP3a^w8B&6!o;Uv|KhL z0Bvn;Dedz{^Mkf+ul9Za8=NKT>+3rvgjk&bu`~?B-JPACq96dBZA`#^4`6MfKq>`! zp7*m-YHh-u+-x?xaasVb>)xnSB>*TP#D=q}`Kc^HMC$>Vbh=qexhyXLBHEeA^UoE^ z9A|@idwbsk@VsU(VCEO61R$kc1HjSjvC7KIE|dw4j*e~v@RiPJO|I*%It2hTKbiQu zDkO0VHK)<~qU5*Cl*x=sd8%V1m8g zBBCn8*|z<2i8j4PO1WaD>uuXUny+g?L_aZ`I7YPvV7}qT$Hz~UNO7B#Qk!PFczk^P z$Cj3sy6*1oKPS(HVfdG2S%$q(l+e_(v1Uyeh6`r0&;l@_^@@s$`NaaTYSpU!hYufq zgqatf!RPPitAbOh)I|yQFN>LniO86z2EZ4^0MOalsQ~OOK^Ce>u)hl;nh;nBQFk7s z(d2#LbCFC-M0DGEkVcm$9l$l3?J@1f8Uf)5SF*8HT0l|g2{I|zc`Ca)EFdN99Q zmema4J3X{CilUtBx{ak4zNx9nRZ8WI@I-W6Db+lc@OdqeJi4POI+U`GM^SX85Mtt? zo0)H#VhfL%9}R-w$c!&IXXvl1l~Nl4NEG2;4FL22*zWs&_Ox$kv#rm=Fx)^ytpM&w z1YaSFiD-bC51fhn6%D|oBmZI|TFK0HIt5lIdQK+*{0`uAA{t`m_k7>~qZs@C3(?H% U!3;#JbpQYW07*qoM6N<$g5zv3)Bpeg diff --git a/pixmaps/linphone-hold-off.png b/pixmaps/linphone-hold-off.png deleted file mode 100644 index b008a6896e7389025e1191e9a26a27591fdb1533..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 338 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmSQK*5Dp-y;YjHK@;M7UB8!2- zc_7SqVezI6prB-lYeY$Kep*R+Vo@qXd3m{BW?pu2a$-TMUVc&f>~}U&KtEalY(fIbfAs3UOi0egh_2%BzxxKyI z1^kVklaEI1P@2AAw!oUVYjW=#K5(Q=!sGi#sMA?FgCGUU#+bNT^Hr#W4=B&J9=8OysAJ*^N WzD4TNTcL+pV4Ge2T-G@yGywn`5P)0& diff --git a/pixmaps/linphone-hold-on.png b/pixmaps/linphone-hold-on.png deleted file mode 100644 index 1590a63b04d2f7253865292329b9f19eab65db86..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 364 zcmeAS@N?(olHy`uVBq!ia0vp^20*OO!3HFkHhG=|QY^(zo*^7SP{WbZ0pxQQctjR6 zFt9BJVMg(p)9(TWB}-f*N`mv#O3D+9QW?t2%k?tzvWt@w3sUv+i_&MmvylQSdg@7=+ z<6p`bFEcaY&!vUs#@T^SPs}+oVNT>PmG8G+i!toEYw3JUJHYyW+>gcYwq7wl@NSNx z_M6I2ze{YHoir3?F)h+WC4RC>oL+rZ`B0X@y&>FVdQ&MBb@00F&{6#xJL diff --git a/pixmaps/linphone-inprogress.png b/pixmaps/linphone-inprogress.png deleted file mode 100644 index 4a43714306708baac99016f89905b5470a68fe28..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2219 zcmV;c2vqlpP)c!3Qo0?4LY&LtOh#cy9-s{e} zx2tX2w{PzN4mZX;-e{gANgfxG%O=TnOiW0C@B5dD$aTP{Dotf;ZBay4wpJU_0%|yk1@t{0&l5me-H#00L-61e+U?i%t*VBFLSbvIJqUsuRCReOl{#tDrcEzfYkvUvaU9R9w+On-m>VpW|ZBENUeJ=#b>qbG2ks@^gdd4POAzY2J+R4QE!V2rsDI5d??J+NTG zf=q4yFbt3LJa4^-6r6Lvt})Bjty>=feqLE0{npwQ`z@fev-1( zh@$8XpbI#&wYBv*-}hIBVYt{@yVUpnJCY=M3fQTt7f}-feBb|~i1;FMnse?{RlNjQ z)z#H?_0A4*i-pT z2%hKtE=iKxthJY>)9KuvJ$tSP-fU@U8F#VQeF7UdZu}>(RYbmCug^K>oHI*RF9X)s z>oZYAQ8WO23;1!VRC=TGnvEIJtI=o?uTa%5`@X-j){xC+56)yV4+8HQW7h6B^C~#! zZja;mh{|?7+d1bNjcJ(71wqiQs`s%s9qvt%~2gsAKl}ejMWDc;hR4O@uR4Nq$tARhY zx3_=3x3_oCbdwCj@YCgTdA>1buv9AbRp(jz0$Hh4S^=COB4$RfJ!iW8dy?qG7(v#s!uk`O_~W2c^H^&t-Uo2!{e;AR#n#k_ftv7t8<|>s(Q7x z*49oG1VIQ~1+1A4;-iS7=p_+Z3S5{Z$%{aws(qPEX5T^QeR05AdkcH71n(7*ysC2&8zORgrRfi8f zierJdYBvVY^PU9`8XO#~dpkF-fFwy?20Y*QPps4B6yW800S2!ie)2#%`P z&-1)zfc7v9=hgVPz+kah9P-c#9I2X7Ec&?Jd+$~cV~sI41B==FYwiGknog%z*B;N5?b3E5?``s@uD| zx>{6qIeQD;Q!a3i;(+{DA`HXMBuRb?Yz7_?kyhYJRXrq~PS4Bba)ZtCbwC6FEL^zo tBxB5~N=5QtKwnEs%k`DI!$%m!e*g=KUCZoE*xCR9002ovPDHLkV1mr5HvRwr diff --git a/pixmaps/linphone-media-pause.png b/pixmaps/linphone-media-pause.png deleted file mode 100644 index f9e062f38071857756e01a7141ae8c28b3943f65..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1947 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 bf8po9tbA)A9x*oG00000NkvXXu0mjfV76Qy diff --git a/pixmaps/linphone-micro-enabled.png b/pixmaps/linphone-micro-enabled.png deleted file mode 100644 index 44ba551af7084db8c39cbea485bbc828142ef9a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1714 zcmV;j22J^iP))U^fGB$&onkfsSV*br1CslDbhLGFsM3n`n#EENj|gY1t%2}&dqPJ4U%CoRjmljMl1ZY3!IR8^Nr9y7-Lad~<9*GG;Vc{QkhtssO9 z4Go1mJ3GH&S=M(+CIM7PzO1T8NxlXkMDlu)S;uj<#bUAI%*@Q0jRIiBx8BEXnti{3w8){{H@{+1c3(S6qeC>Ga1f%la9~s{uSw zE|(wA=kw>@4m6X=+(GjDBnON!j~ZjXGd@1n%!rc^4erJYyX*p*6!R}5eylqNtEpb5~px7ik?_Zn0`4FO~_nGbYybUc#D zWWIPgS1p}R-w=sJewfK*KG!Hjqk~D1{ECQ-rqk)jWm5-{VG+4cL~c)|Qtd$kw5)nw zmO|3;KejeEaTA~k&;ut;*+uGXJVlKshnouaD zbqR)=`7AFkE}FmqNM2A?mt>dgx|`}=tpF$k*i@}n8zM-j(NT}`*L7b5@H&8A5gBSkmgjk0s=5P!NAg51t&&J2TKse* zRJC~G#EEi{dteU0agyDR!>V zMVjl6*1HJ#gT_fq7Lu3_w&hyKC33Za+XT8DpLS@H)xSNF;K9GMU`;PI7kd z-u(%ZUj+~b@Z8+o+zWNDvjDCEaJ*8fOg9S9XhuL|v6x44FUjj#T3SvPi^XX_wK5Zl zL?R?dNZ#x?PFFMg&Z{8y!qat!2$I0POcX@6oZb zvA@?;c<0WYUl5Up0NBQuALVkn=hku#tU1EkvuDrUmSsH*V5_P=S*cVW&*$_1uE|TK zQhlwhtsn9&%@&f&08WX>^!)t%%Y{OrTATTfj*h!YeiOhp08f_7<$d{letu0Z_$5S5 zwr$&A1F#Q3x2pcd81vJGg@uE)!PUtYe>Uq6C60`YYz9ufI6fGw)}8&&;wE|)vG z<{08qj{JB$9_sDw{gQ}0NOBOstg8OO^SnQmN~NPyQ&aP+)gYNnwuVBXm~Gp80epsJ z3P4p=f91OFV-ph-$1f=eT2BC#&1P=_a4&#cNNxgf&fkbf0n7nd0${6ZuZUa+;DZ3R z1F!)cQ`KL1p0|H|eEgCxI)b?1*eW8olKeD)B*`w{IGDOssGT>DVeP6BwbTrU6f@ZrOA>m7LD0IOs&lgT_F zB98&cm&@hRd_I2x0bjAg*Tulydf)Y~)V^DmRlOX8Z-$gjfDO0@SQkV5x3XHTvhLl+ z{I5hZne1+DZM~Ibj~|96N#3TaMF784)iTKyW6V^YGq-U7vf1osN&dVpFegdNcg5X0 zxBTgqm6Zo3Cnpy+lnSZpzeqj>ptr7W_0L=Y<{9 diff --git a/pixmaps/linphone-micro-muted.png b/pixmaps/linphone-micro-muted.png deleted file mode 100644 index cf666ebd0299b35902c8d94bf579df82b50e13f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1745 zcmV;?1}^!DP)7_h-#I)m zTWuHH_11S&dtUC|IrH)V&zy7S%(*Kxp`=o&E@RB+MP#Ef=8~$O48!mxK;xcE;v6iO z%k`@20pL!+)QP8nA9Qwh9vm7Pnq6@Oa=F|Cs`^+B@P7jTcJH?Wt*-tVRoz`Gl`gIr z0-opX1AYu3BEur`9pCp~s>%z6!rDru@-5(D;2PkMmoHyVPfku=`Opbuv)Sz;avVqk zkB4D+|3bR%dEOm>545Z5qoq>mq2Jhjv$JLM;y6ntli6g9DFfSq3nJnLLGah6dZ8wO{{(O$kx0BR_!UE7KJdk2 z@o!h<9Ec(C+x$VnuLJ_?lgXs-z`rRXg+{>RPS6jtc)p>Kr(BjAN}O@e8{94^z}(#2g+w9& zux8JmJ*_h{GwYqJ{5WtP$d*c_7w0)wHmE8ha=z}s+$bWo^To3R#+cI%bZa`D-d?kk zr+~KsGd(@Mw;p^LhA+;mAF6k{=kYqx4p;wbtOSb1;xzDQfMhbcyIMasHujE){K2j2 z6At_v#+b}P;IrB6J-{}gVvPA+?Im7BdfkHg&G16Mb*ppV;NW0wzb9%8{E{&yTbq@e zCkb}Qy&m#?|Bb3_c6N5JyCa_tf}kn)fnNi&z>e|p@x9JfZdKKv*0fn`t^H78UDJ0& zWL#CN$=#j6CMSCtD1>47ubQ3tk%;UE&bPF*+&nxye5ol1nK9-O=Tf&io9G74scI$+ z!vWwv;1qC;s^)+_z*ijjimD!LYirwC3*Pg*uQ~7l4>tn7;T>=j4ggP9J)f%XER{;n zRpo<&gJyhuyvG=Go3-}c4;;W)7=|--LEc_fJq)x1N8KXOGy?to{Wn!Am9mK3R8##z zB9Rzqt%AJbzY1zNe~>0&CrgdL)XXAC}AI zT4oW41(Z!V*FaUAc1T)`$-WQ zb-MbBwKhFEI(n)BZ}kn}u!#IA2!h+2b?-0>c^eTKap2FWYJVf(uV$H-Koms-z!uk*4iiIRH6R@LrST!l;n!500000NkvXXu0mjf-q~JO diff --git a/pixmaps/linphone-ok.png b/pixmaps/linphone-ok.png deleted file mode 100644 index 4bcd6f6345fd070852ee8358243cbc5ca82c1a1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1326 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 b{J-Hp#zQ58zlEGa00000NkvXXu0mjfpsJDB diff --git a/pixmaps/linphone-security-ok.png b/pixmaps/linphone-security-ok.png deleted file mode 100644 index 38d2ec61cee93e0b298dd29d4956b7940ba4619e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 694 zcmV;n0!jUeP)4CBvmS#6lv0kHY!m}7r`dYilAF; zhBvz*1WSV;7$lO|NJKON3kfni&mup>$?Rr>r+VDW`8fBz`$QW}PEI%IhrfDhK%rX&ko2F?IsZ*T97TCMgw?RB$&uIoMl z1|^LdW2OPS8=zb+k4k#BwY4=3+)jIQ=|ZVgI_)^ljJ5W06h-&a{k65VcZEXX7%)~W z7GJHdu72O&chUyOajpV#UH4&D`W-z25^L?X1O9YDQUUl8hT(cUTBFhU348^L2mHH- zAPD-cwZp(5PynVoBm@`*z5#C})r~O=umZB&+ z-vww-K@hyP*6vMu;12&+nS0ntl}hDAtJRv4G+~TcN%xPG(D(i0aU9oy!8ndHy_pHi z<#HhDX_6$jn$6}CY=1}KwWL1a%KZHNr>=qde10X4;~vLx7JT2o>3LqXv9U1=Tm(j< zC<@z6kr{h#ZthDim%9Lb25Os|n?}-gNq3_tnr#Pb3j_$ma6O;TUt)W|N|NpyW2QR6 zIsyUe_4+T*^M)k(#+Zr2V9>?dRIAlLK%*O27VxC+`wzM`16XTM0n1syWuTw!Pk$sy c`nY@k3#%}w5W`iy-v9sr07*qoM6N<$g5(P&(f|Me diff --git a/pixmaps/linphone-security-pending.png b/pixmaps/linphone-security-pending.png deleted file mode 100644 index d61faa39a35366e7efbaec488618d67d6371732c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 707 zcmV;!0zCbRP)9v;46j41(e5%E-Y0oVXifCKzc)$5+;RYQT6 zWeo!Jz&BORdY<>Ly>Hw0Syg=wB!P_Uy6@ZjCLrJxAe)<;BfDV$<#KsZRc+v>h&
  • ;XByw9-i9{l& zfxFv41N?GbH`XnvU6y5iW$XH)Vdl}%(RebMyljl=Z?#&DVzF56+9lp1o&2E*0Sbk}^w`+go!QyhSEW+v{(l2iwSQ)2=3_pe&jQ-X8@e*U+S=Np zG3LYMwfTIBJ`D^)!ZZGw{T9tx-8o-1ae7U6307wY&Du8|fw@4e8a{{A+ zo3+6(jKcsPRm|T2I0WFmNUwkpVzpry6Ke28H0b+&oSDx?nnIRkJq}9u=#ry*^KjApe zkCn_4B~z%gv-9pkp^z&Ie#kVqY)mYFXCXaLX>i^ci@Y`O*j5q)Rdw)0;$DDilFsjll? zK@c4GJntd^WV6|`$z*af5uK1RZ?r5cY1_7|A!1^hrbk2{8;0?vN)^|2Z2)g8d+^Pw zmD7u13o|d1^kpm#*s4{-A$oG>nULHvRnxCq|<4QhIAtdZ(u5Cq4HR$zm&0;eJe zfSGqF>gx-qF#x1esTO8VEii30SwCje#dbRs?-X@@PN{;4tkz&vFRO~XIm@zInYmA;Rwk1< zbG>qUm;5cJt+X{w+aizoN=Y65zDXZ&9A~exskKWba@GohU?P!7G*>Em+qS`tfCVO7eG5;Mja5w#N0gt96-bGh8-@p!x;@&M%0{%RP; zdS>od_C>d07~?{S)sY7v)7}-Cw|fCBH2C)c_&SwJ^+X8!y}eu z?W_p^5=2JV^@jm`ztH(H^FATOCv9zQvB(3Ez3Z7mp|B2sno_sc)z#$yG({eOEQ_ao z-+zjk52`&Z5gn)r007{5p6|NuEAs074{5%sW&kMX#Q-x40Ox9A58UX`3&U_NfYVBQ zSn@YBy_&UtKA)d%YHIpO)3iDO=b3p=KA)e&|5C&9Cr0Gc;U5Q&egFUf07*qoM6N<$ Ef<7)!_y7O^ diff --git a/pixmaps/linphone-speaker-muted.png b/pixmaps/linphone-speaker-muted.png deleted file mode 100644 index 91e96eddb08dd036e31714fbd9d9198a1c8a7cdc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1976 zcmV;p2S@mcP)NQJ7eN~HrB3PYqqzyuj%aURKvr=Cuyz$BoYZL5{cZ; z%*&Kg_Y{l8f7H6Sx3{--baZqNGiL#m0W7oT5_~$Hz6`)_W=;WsVHjrsY^-H(JRYA{ zE|&)Y+!&IghGASfX9C!^{Yd~X0qCgEi0Fg0?Ct64iH(hoNDIWg*FD=DVbn&jWzbWb94 z`+kC%|6T+5Yl!HG2L3F7tPtWr_1cCD;5g1L0A2;q8Ilwc-RHXQ?VjhIoo;_7lewOV zJOGPA(&-SqH`)3|3P6tIY+>fT0Op0XQ$*D3y6)CmeBW`LxKb()AQqDTWf(?E2r)R- zo`%Fgc)&cz%%9iDe`My>LWn=tXt@kC?*q^pl1?zQT__ZeU1;B|Es#p3K2|Q5OI6_a zMD&UFejUWh;Qp#h~?KNiU?>8ET@fv_nX(@7REEfA*E|)u9BaijW zyc@tJA!#@Wg6_kI5C5r_{g!Rp^O^ZUB3fLR!xIrR_W+27q%iSWWU@%z1D7@2%N|917FY&QD= z-}j$l<_{Z&v8hlf{8e|M56vp|5FI6=t{H&W$15!@Ey+Tm@b+YrzVEMM<_!Q=DW&$u zGU&1^yP5jde?P#Hmfd5r_+xU(bqKEThVB=V_;z5J*@<}+%(NqK@c49JnvoY zbasg7U`6RfWV@~_n_bKS0Q&m+4BNJ!tO5@rD(T<>AQFjqM6}bgtY7J_BBgWzd|$KN z_vWG+MIw=~1_uXs0{F@#)2iA^%)BssUJ;E(f2dEIrui6vQ{n4%$z*b=(PZ!~rfKd4 zuujvud!gh8;BHN@yOPP|(#m8$pZ_<2{hC0%O%q_{%9YVbB(j%?dNs3e4}#$F3+)Rl z&Rvx}VVdTxRY9NEUaxJ60P%QyUTbUXp|JU`X#TrW%FRSnOGERL_Iyp%+=%wv-tdMd zolajyM2GZ4DlDhB){&l1D)ry+m|r!0N_(E)Pzz+U*@dBxcWFNT^?JYqKoA6-+UuKD z!Y$Mk^H#$INTpI&OiWB10dQ?4!!YwEA;c5)rd%T0sQLVn^U{`5%eA>TtOkK!685iG zR!)Ba8>Ey!ua{S;RO-`|@JRmKtWZj2DxNkmF>%P4CHU&*yG%r@X9_+PU{CnDLkO{5cP*vVwo2&@V2|f{Cuc0c zB+d63BFeh1dvG>Nky5UYL?ZL0lwZ{Q=)u9kM*!FrE1RbI?fAQpw z4{JefoSr4~2!Lmk$>j28p?6*Pmqhdh0N*%w?%a8FvTb`afM>Pz^}6r-pDq@Qf0I%U5m6Tr9jzD&z?M>}^ov9y zvEZT$;5g2A0BqAV|2xAl(w^tNshRelmSug0nRjSGp0zCNRok|&zGwp2w*4qGKd6z0 zeBYn+<{+2LjfHu8V^~H2z*PWV$z(FUb1eX+)9EJwY|+mb!!R8ESf8R9c^bgY0Nx2n zmnx<9IgYcXSpt~Vm7rx=PZH54jhv50qpNed+hJFl zX2aa`JYPz=IlOwWSn-l(1hEeOneOiHJL|kIoUX#$6~@GgW@VuV0Q`lS9}+@rY{n@n zr5sX9T?gPbtvx(DTfP_Lw-POuWjzAm<4UP-6^q4T{C~WU$A186t`#WAKLTR_0000< KMNUMnLSTZE;?ZmX diff --git a/pixmaps/linphone-start-call.png b/pixmaps/linphone-start-call.png deleted file mode 100644 index ade0e15a4c1382c72168425a9db555230395dd5f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2587 zcmV+$3gq>PP) z%p^y75GXE|6d)o7K_itCOF%wWN(mNLDG?E{1OkLAa!>_D!FjtqcN?=LB8UQ-fPuY} z5CR%k{VB8xYMD#;uUS6pznM@86(IWuXN-4KCVplsL-qnFQbLNDY`8-tkXhifm z0E+-z8I49yZfk3MC7;i~U5{Nlz<$<5EEWqlH8mZs>-sbzI#ww)A3&Ul&HxY!RCNK| zDTKH-olcL`viXS;s0Pcjj%4PGn0Xa|S%IRhLWt$*bow9FbPoywJ~}!&nhJ%&DgZYC zX!gYK0azxb%vRDFm%ze>3qz4eeOwfX7cE-UY1{U@{r&x~ z5>Xt$4zK*gLZPrB9*<9-3;`+SRw?B&BDw&;2LQm#9lEan%CFPk-~TFrTfD61IL=Ka zvH)P3=0(hWFUq^*+su4{ZQK208}za}DtSz4LAW%3F?FNC-?7K?=eAe+tZ1K{@xG4sU$AWYMo zkMi!f!Eqd;x3_m^EoW+wIJAb^oy`2FfDQmmBcj_4!}x80#C^>CBmgk;(ap`xEB!KN zeh`4;rN0gUf|f5%x#kTD;rIfRT5K#bk0bsBA zO2aT#2C84<+a;n)12*0Pkn^(9rAwE7K``@Nzk(3rrFxwAq3ilel$XF=%$%)9FP%;g zNGY!%qHhLB{LCMQwry_#u+fvxwJht40rgTFj^msrh^W-(4fO?AnP}-Uu$Jtwl^Ye)4VR%D_ zh*sOSy>=qb13+J2-|GN&dbZjE1l|gy{SyF2M@NVKG!Y#t00aex*J>;tk54C}Cjm_J zM30?*`svqC)cJse+k6*%SyNNfoAAy~L=-$R>;kagOYajzR2sKJh?%H@SS%I}g+fmN zXz@hPhr{8EQ>m1iECHp|l>qJ#LVUxQ_4M@Y2XHcX7@4k`9!ovDRmtg zhVgv>zwyd1l~UeUsS(34Rsgu$%kEW59oOij{Wu_)IXEd!saBDQ{)zIM-zQLVC+ zay=1!3m#!+{&p^x`yD>To)DfR8@xPens!c&`p9H54-wHNDEHb5!!Yi`r$j;k01-Xv z3%u>UCNi1KLpVr=Q|YT2hOq^}@c>vUb*#6+)P!l87c%qxD4&P!ky3sa@*FfbC0Mk4@D1E3R8IG@iyRgaN; zKL1i%TU#E*z+3=W7>!0}jMY!2QbO1DTLAnr(6;O893_NU+S1bU=-}YsxMwmSADVQI z~L?W?3 z2=Oe6Hx&xNaw+9wjS#8O69DiAGk4myT`_d6aAh-YPgH!N85kJY8I492fCP#pJEPI4 zozLgrtd~HAiT$kOI7WYef7ShEaB%S5*|TRqC4@K+#hBwLrPR`vmX_{n6T9jYQ$C;1 zMWfLufcYrCo}Am-+PZOIV4xuqt*x#7LWsYNjEt}aX=zy}gqRLs zA&PV2%y2k-Zd+U1bNPJ!t#M2=1YOs!1K?lR>{d!yn>KCQU9Em2M_@8d^IB$3q5Ps) z0PqLLaeki7X6v3C)sRdk+leTH;)hiL&XQ90)^w`TMhwF^8NmGj<^{z2iRf+scVse| zZ50*A!IC9QX1K2V0)XiNz|1$>wtdq$Y7+}Wy1Kfi3=a=q!^~Hse8mD3kI~N%(OU0_ zT-W1AJRa9|U6%mP^h9SNNY`~Q@uImCCSl3} z&@QFSja$>h0gq!7iNvWwh%O>p%*+c==MN=B^d>X^L`wNUBkg^xfp|O~KSbB{uL3w0 xz)T`KhM5mR@oI1nfZYJL0eDVI`SL{C_&-H36`?>v%TE9R002ovPDHLkV1nq1xk>;4 diff --git a/pixmaps/linphone-start-call2.png b/pixmaps/linphone-start-call2.png deleted file mode 100644 index 097271ce2f0d1c95cc9c92bac0fb54a8d77fcc0f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2899 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 diff --git a/pixmaps/linphone-start-chat.png b/pixmaps/linphone-start-chat.png deleted file mode 100644 index 15b050f6f286c104b36fcaefaeda8eee2117f13a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2079 zcmV+)2;ldLP);M1&8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H101obStGk0B`~TeBYl9U?G4g z$x8uT4PZfzK8651lS-wYNF)*iMN7c8?aN5M1mLQy&;WoY5oz)~@AX6?acUy{H8eD+ zUAuN&LGtS)Zvn6*i*i&%Hng|5|7qF@IF7RpKqG*;A@_SC@`UGkzeyw#$0s5>9~v4O zRA*=B8UT+V{ba&;w!gpsfv&DDH(&cg3DCCfr$~M`JLh;c zH8nSh$YuZ+g!~- z+z#NWj4dKBmX(#=-rU?grT6qykxV8#qtWP50AE2miN!-hL+2-x$>uO`Oaj%_)fbU$ z1~3}{L}bURRjY1mY;5#rN_ZGOJw08~X!HbtS^ywow1%>NmNQQ6ws+6MqCLvkGF1_a^(qyVh_IEV*;*|TSV2f*RL ztnfVVkxXnP0TKC8sLe0p@%Z0nNZ+_%)ZzrfL4sb=?5~5dce8uU`EHI*#*20Q&>Z`&#P@07$-0Y}>w%2*r1yfOr5Pc^%G3E}%T!-R|2LMAv?jDb%lv)-t z4=UgHyF%iwsj8})Rj30I*#e+%>N@jc2*A%Kz_UZw`w0M!l@5z%Ve+P`+k$oSdh1@r6+y3gz zO3aVy>go$cWaOrb$fn)9cMk%g1lrr%-vsb-#wNMNvaHX{sL~t=rq1t?-U9%@yPoGY zX5uPLHVk7UMi;h4rfKe2v0}x1oI5ZQi8PYDCa^sK>%xb~V-jd>ZS7M^-3%aen0i%7 zNy%R<%lgF3=p6&r)YNPydFP0O{DIbbUzl`8@z&kleJC1@zK_upvCop6lT0St&bs6P z%a<=NsjRGg5kOe{OYwO8p=_?ob^w6Z`d1?I@CZq%RcAwJE;x>}bl$vqdjQ;;@sZr_ zy6&C1_-4M2JkQ%^n&y)LAR?7TSDJ-bEOwsjy59rvAb>fc&=%Kq?@J^Ssa);yCSX}s zUuS1$#ylIv8vq~{i&dOHefnJMTBv>A1orINb79Er&&8>)uQ&Sp z`!@iXqmc%JuazPX+cXFP#e zELP#VZW{ve!7=+bAiXM1T+GQn|=k=zZS-7t(-ckbNz-^qv$ zBm4Wn4FI+P$UI_KDdh|f4!&7hTDp$pgBbfsbO^vbTI+29U|H5D4Z~PUvI6Pv!V3Y+ zB{}H({s4eON~!KhB+}E=)Z|T7^q2(d>+6kyfq`2@l~Rw2$dHIE1F#tBvUQkbuZX-0U?0iX;_>)@&aKqk_&-*VtO;goq?-T$002ov JPDHLkV1oO?*}4D# diff --git a/pixmaps/linphone-status-away.png b/pixmaps/linphone-status-away.png deleted file mode 100644 index 56c7fb3678c580670f044e7c9439b9c9c2c3fded..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1074 zcmV-21kL-2P)!T>t<88FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H1026dYSaeirbZlh+b97;Jb#z~0Vsm9~bPUlc$^ZZZkV!;ARA_|%h$xbHkkmA3K-$t8xNu@qyVVGd7d_yOjgYWjG+xw; z6u6K;TM)#92T99PI6%^an%HU-2pBcNhzZ8}ru1j zp4q*ErQZh;*#o>_Io{6*CkcwjBs2Y^s|F_nn#*}?xcVA!fcyV+Ei8eaq}Xy$UY`8L zw%FQ$j`cl*=N$*0x2=s}9@VU5@}o9IRt9vUe;7CdwAs{I@(Bwo_sYm;f5u6UZ9vES z_aS^>Q&R(9;`=)!eg3zo#8_f^ zBMlYfg3_fEFK#LiR~XPUy=#CiiHNdAb$5BFat4Ymy)55jGaOI1SA;5(lqmI3cu`HVp=3Wl~xkdEi^b zw1oamNQfJv|CBaO214JzmmOigv}rQ%LqbyAQ151G(`4ZLgrvAoU~w_RfO0i4IkpI2 z$ezm&?9oaCDV+v1DNR4kAD4%!yiNzl8!pBc)vshYKUW?$ z8)#3R0B$#0lNG{yrm)d~>^#4SYQpD0VaP0g$2n6^^^f|;3P*si8zspCh2RZIpDmg? zs~V7=%LP0c1{NA7Ee@(5%257FweHY^Eg78p29-DKuPP?O45^N6SW4v4qGYCyAuPku zqTFOjc1il|y|AoE0{{$OIEc#IbR1FwU=541)myEBRJ4M}?P zZk*(JGw?q$GX(Lu@9B~z#}eWln@}CBhaj5 z^0#b@YrCa9G0=t|>_vGMk>@PS@1mSSyipmNbe_@r-4mbgT~E>PL$nKFBg$G}75Dec sU%(yU8Zd{-MN;iEQBRmAO`1gWAIswJ6ZNGuv;Y7A07*qoM6N<$g5t^Kt^fc4 diff --git a/pixmaps/linphone-status-donotdisturb.png b/pixmaps/linphone-status-donotdisturb.png deleted file mode 100644 index d5a1391de54fe45a410f7d871602f5c06ae901f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 755 zcmVcWDptx(oESLed1OjnY z7oQnmb082`b+w^pfIopiT=m;5m;rtT0&!IrpBZ325QwX4X2JX)*bXcP!%3$mFcQIX zvbbsmBKU+QWl8kLga`Xp;#mL~7g@P%0eWs-3)cF$1Qo$t33`B}U-#neT7d{!zzz3_ z@}j9!R|^IN?@KWA61y}mZ^_gl zMg?yJ!@m>^Wrk0Ls0v;Lf`6j8war(8LBTDL;7!4l;u8pe5}Xv&a)zH3OnL=3LJSEm z3l=ki&kHUHHU)z>f(!~y2_6cT)(QPpFr)Z$Rp!Sfw-Y$U$1(eXJ;bL6!^9u%eh_z3 lbHFU{E&}Cs-@f|FsK0s3F|5@vQGNgb002ovPDHLkV1o5OI}QK< diff --git a/pixmaps/linphone-status-offline.png b/pixmaps/linphone-status-offline.png deleted file mode 100644 index c4f236f556f5daacf7cac28f9dedc7be77b8b9f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1071 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 Dfcdc} diff --git a/pixmaps/linphone-warning.png b/pixmaps/linphone-warning.png deleted file mode 100644 index 044bcd8f0269af1ec615376cd2c76bb8a5780d7b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1004 zcmV**JIRo^x;A0$(_bx%YhM zd*1WSJ?GpRSkAi?#pIb9{_ z&j2sMtYB+UIRksB1P6eD#F+6o)YU;W3eTRw$jI{Uk0Nk9sNB9K$QHa#%<{>T((J4f zT3C?U+mkDCC~WS81g#0M;$mrfS}9div)sTN!P>Cd5o{7nCcqjSQ^QNrojb`@xac?k zngBd>0vi&a3JTnN#$w4=t_e2!N$$&lpc**iV~7}V!w-YC0XeZ<_+QDI1bb|Q{Z!xr zJ`yJ}blIMhtPBVW2zE!U22R-o+E(Bu!M~(*3f7wj856 z8^|(E-V8 zFM{GA;7=PSc3Nqv)Z8q!v`AG|=J8JJ^$VXT_-L6th_)cu>&L+D5aE~FOQks{x!#bo zp^N}I#?GTrXlQ`iTFB0Z!9nQlg{djyp%!&E0uPKL1W&DIEEbbqy;`{njgCt3xNQ|a z%h`uK!ymUUd0(IVE9Jm|pRdv_ukg8o_f|>r@}#*rcLS1CQDJM~n_zn~Z>pWR4Jh+m zuH`BzfwdVn&@#KBan4D1)AkT-lk>}&-7MwjOY`&TD^OYKcU3x)&cG9&gG>GW?(joH ze&Hn;RjQRya43MmrNTmKcz7lJ*qBsa9)tl2E-i6K7U6S%VNyIKR?5wVrY2_}$jXAD zA?WFW$;m*52fhN85%>gvpgo|O`J3%NKt!+wc+0>1$3tof*q@E_iuf>O7+dWM8(>xc ay?z3stWO~_gA2Wb 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 diff --git a/pixmaps/svg/linphone-add-call.svg b/pixmaps/svg/linphone-add-call.svg deleted file mode 100644 index ed8da23bc..000000000 --- a/pixmaps/svg/linphone-add-call.svg +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - image/svg+xml - - options_add_call + Rectangle 250 Copy 19 - - - - - - options_add_call + Rectangle 250 Copy 19 - Created with Sketch. - - - - - - - - diff --git a/pixmaps/svg/linphone-call-status-incoming.svg b/pixmaps/svg/linphone-call-status-incoming.svg deleted file mode 100644 index af9dd9bf6..000000000 --- a/pixmaps/svg/linphone-call-status-incoming.svg +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - image/svg+xml - - - - - - - call_status_incoming - Created with Sketch. - - - - - - - diff --git a/pixmaps/svg/linphone-call-status-missed.svg b/pixmaps/svg/linphone-call-status-missed.svg deleted file mode 100644 index abb146cf1..000000000 --- a/pixmaps/svg/linphone-call-status-missed.svg +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - image/svg+xml - - call_status_missed - - - - - - call_status_missed - Created with Sketch. - - - - - - - - diff --git a/pixmaps/svg/linphone-call-status-outgoing.svg b/pixmaps/svg/linphone-call-status-outgoing.svg deleted file mode 100644 index cc8c66efb..000000000 --- a/pixmaps/svg/linphone-call-status-outgoing.svg +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - image/svg+xml - - call_status_outgoing - - - - - - call_status_outgoing - Created with Sketch. - - - - - diff --git a/pixmaps/svg/linphone-call-transfer.svg b/pixmaps/svg/linphone-call-transfer.svg deleted file mode 100644 index 357ccfad7..000000000 --- a/pixmaps/svg/linphone-call-transfer.svg +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - image/svg+xml - - call_transfer - - - - - - call_transfer - Created with Sketch. - - - - - - - - - - - - - - - - - diff --git a/pixmaps/svg/linphone-camera-disabled.svg b/pixmaps/svg/linphone-camera-disabled.svg deleted file mode 100644 index f5ddde244..000000000 --- a/pixmaps/svg/linphone-camera-disabled.svg +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - image/svg+xml - - camera_default - - - - - - camera_default - Created with Sketch. - - - - - - - - - - - diff --git a/pixmaps/svg/linphone-camera-enabled.svg b/pixmaps/svg/linphone-camera-enabled.svg deleted file mode 100644 index 5138510e3..000000000 --- a/pixmaps/svg/linphone-camera-enabled.svg +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - image/svg+xml - - camera_default - - - - - - camera_default - Created with Sketch. - - - - - - - - - - diff --git a/pixmaps/svg/linphone-chat-new-message-and-writing.svg b/pixmaps/svg/linphone-chat-new-message-and-writing.svg deleted file mode 100644 index 9cd538ea3..000000000 --- a/pixmaps/svg/linphone-chat-new-message-and-writing.svg +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - image/svg+xml - - - - - - - chat_start_body_over - Created with Sketch. - - - - - - diff --git a/pixmaps/svg/linphone-chat-new-message.svg b/pixmaps/svg/linphone-chat-new-message.svg deleted file mode 100644 index 8ad456ca2..000000000 --- a/pixmaps/svg/linphone-chat-new-message.svg +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - image/svg+xml - - - - - - - chat_start_body_over - Created with Sketch. - - - - diff --git a/pixmaps/svg/linphone-chat-nothing.svg b/pixmaps/svg/linphone-chat-nothing.svg deleted file mode 100644 index 4835b5255..000000000 --- a/pixmaps/svg/linphone-chat-nothing.svg +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - image/svg+xml - - - - - - - chat_start_body_over - Created with Sketch. - - - - diff --git a/pixmaps/svg/linphone-chat-send.svg b/pixmaps/svg/linphone-chat-send.svg deleted file mode 100644 index 4f0924ab7..000000000 --- a/pixmaps/svg/linphone-chat-send.svg +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - image/svg+xml - - chat_send - - - - - - chat_send - Created with Sketch. - - - - diff --git a/pixmaps/svg/linphone-chat-writing.svg b/pixmaps/svg/linphone-chat-writing.svg deleted file mode 100644 index 7183818a1..000000000 --- a/pixmaps/svg/linphone-chat-writing.svg +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - image/svg+xml - - - - - - - chat_start_body_over - Created with Sketch. - - - - - - diff --git a/pixmaps/svg/linphone-conference-start.svg b/pixmaps/svg/linphone-conference-start.svg deleted file mode 100644 index eedb7136b..000000000 --- a/pixmaps/svg/linphone-conference-start.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - conference_start - - - - - - conference_start - Created with Sketch. - - - diff --git a/pixmaps/svg/linphone-contact-add.svg b/pixmaps/svg/linphone-contact-add.svg deleted file mode 100644 index 08882723a..000000000 --- a/pixmaps/svg/linphone-contact-add.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - contact_add - Created with Sketch. - - - - - - - - - - - - \ No newline at end of file diff --git a/pixmaps/svg/linphone-delete.svg b/pixmaps/svg/linphone-delete.svg deleted file mode 100644 index 51b051ac0..000000000 --- a/pixmaps/svg/linphone-delete.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - delete - Created with Sketch. - - - - - - - - - - - - \ No newline at end of file diff --git a/pixmaps/svg/linphone-edit.svg b/pixmaps/svg/linphone-edit.svg deleted file mode 100644 index 21d72cfbc..000000000 --- a/pixmaps/svg/linphone-edit.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - edit - Created with Sketch. - - - - - - - - - - \ No newline at end of file diff --git a/pixmaps/svg/linphone-failed.svg b/pixmaps/svg/linphone-failed.svg deleted file mode 100644 index 98e3fc67f..000000000 --- a/pixmaps/svg/linphone-failed.svg +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - image/svg+xml - - call_missed - - - - - - call_missed - Created with Sketch. - - - - - - diff --git a/pixmaps/svg/linphone-history.svg b/pixmaps/svg/linphone-history.svg deleted file mode 100644 index c4b4f4936..000000000 --- a/pixmaps/svg/linphone-history.svg +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - image/svg+xml - - - - - - - footer_history - Created with Sketch. - - - - - - - - - - diff --git a/pixmaps/svg/linphone-hold-off.svg b/pixmaps/svg/linphone-hold-off.svg deleted file mode 100644 index bd44bbf3a..000000000 --- a/pixmaps/svg/linphone-hold-off.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - pause_big_default - - - - - - pause_big_default - Created with Sketch. - - - diff --git a/pixmaps/svg/linphone-hold-on.svg b/pixmaps/svg/linphone-hold-on.svg deleted file mode 100644 index b25a411fd..000000000 --- a/pixmaps/svg/linphone-hold-on.svg +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - image/svg+xml - - - - - - - pause_small_over_selected - Created with Sketch. - - - diff --git a/pixmaps/svg/linphone-inprogress.svg b/pixmaps/svg/linphone-inprogress.svg deleted file mode 100644 index 871be13b5..000000000 --- a/pixmaps/svg/linphone-inprogress.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - chat_message_inprogress - - - - - - chat_message_inprogress - Created with Sketch. - - - diff --git a/pixmaps/svg/linphone-logo.svg b/pixmaps/svg/linphone-logo.svg deleted file mode 100644 index 6861fef41..000000000 --- a/pixmaps/svg/linphone-logo.svg +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pixmaps/svg/linphone-media-pause.svg b/pixmaps/svg/linphone-media-pause.svg deleted file mode 100644 index 0e8ed0de7..000000000 --- a/pixmaps/svg/linphone-media-pause.svg +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - image/svg+xml - - pause_big_default - - - - - - pause_big_default - Created with Sketch. - - - - diff --git a/pixmaps/svg/linphone-media-play.svg b/pixmaps/svg/linphone-media-play.svg deleted file mode 100644 index 3eb7f0066..000000000 --- a/pixmaps/svg/linphone-media-play.svg +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - image/svg+xml - - pause_big_default - - - - - - pause_big_default - Created with Sketch. - - - - diff --git a/pixmaps/svg/linphone-micro-enabled.svg b/pixmaps/svg/linphone-micro-enabled.svg deleted file mode 100644 index a23354bc1..000000000 --- a/pixmaps/svg/linphone-micro-enabled.svg +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - image/svg+xml - - micro_default - - - - - - micro_default - Created with Sketch. - - - - - - diff --git a/pixmaps/svg/linphone-micro-muted.svg b/pixmaps/svg/linphone-micro-muted.svg deleted file mode 100644 index 09d505c59..000000000 --- a/pixmaps/svg/linphone-micro-muted.svg +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - image/svg+xml - - micro_default - - - - - - micro_default - Created with Sketch. - - - - - - - - - - diff --git a/pixmaps/svg/linphone-ok.svg b/pixmaps/svg/linphone-ok.svg deleted file mode 100644 index db08198f7..000000000 --- a/pixmaps/svg/linphone-ok.svg +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - image/svg+xml - - valid - valid - - - - - - valid - Created with Sketch. - - - - - - - - - - - - diff --git a/pixmaps/svg/linphone-record.svg b/pixmaps/svg/linphone-record.svg deleted file mode 100644 index 8709e9509..000000000 --- a/pixmaps/svg/linphone-record.svg +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - image/svg+xml - - status_busy - - - - - - status_busy - Created with Sketch. - - - - - diff --git a/pixmaps/svg/linphone-security-ok.svg b/pixmaps/svg/linphone-security-ok.svg deleted file mode 100644 index 83e518e9b..000000000 --- a/pixmaps/svg/linphone-security-ok.svg +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - image/svg+xml - - security_ok - - - - - - security_ok - Created with Sketch. - - - - - - diff --git a/pixmaps/svg/linphone-security-pending.svg b/pixmaps/svg/linphone-security-pending.svg deleted file mode 100644 index 084755a29..000000000 --- a/pixmaps/svg/linphone-security-pending.svg +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - image/svg+xml - - security_pending - - - - - - security_pending - Created with Sketch. - - - - - - diff --git a/pixmaps/svg/linphone-speaker-enabled.svg b/pixmaps/svg/linphone-speaker-enabled.svg deleted file mode 100644 index 8a122795d..000000000 --- a/pixmaps/svg/linphone-speaker-enabled.svg +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - image/svg+xml - - speaker_default - - - - - - speaker_default - Created with Sketch. - - - - - - - - - - diff --git a/pixmaps/svg/linphone-speaker-muted.svg b/pixmaps/svg/linphone-speaker-muted.svg deleted file mode 100644 index 1e85b85be..000000000 --- a/pixmaps/svg/linphone-speaker-muted.svg +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - image/svg+xml - - speaker_default - - - - - - speaker_default - Created with Sketch. - - - - - diff --git a/pixmaps/svg/linphone-start-call.svg b/pixmaps/svg/linphone-start-call.svg deleted file mode 100644 index b7783041a..000000000 --- a/pixmaps/svg/linphone-start-call.svg +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - image/svg+xml - - - - - - - call_alt_start - Created with Sketch. - - - - diff --git a/pixmaps/svg/linphone-start-call2.svg b/pixmaps/svg/linphone-start-call2.svg deleted file mode 100644 index 4e6f22d9a..000000000 --- a/pixmaps/svg/linphone-start-call2.svg +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - image/svg+xml - - - - - - - call_start_body_over - Created with Sketch. - - - - diff --git a/pixmaps/svg/linphone-start-chat.svg b/pixmaps/svg/linphone-start-chat.svg deleted file mode 100644 index aa71e6c0f..000000000 --- a/pixmaps/svg/linphone-start-chat.svg +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - image/svg+xml - - footer_chat - - - - - - footer_chat - Created with Sketch. - - - - - - diff --git a/pixmaps/svg/linphone-status-away.svg b/pixmaps/svg/linphone-status-away.svg deleted file mode 100644 index 46beec033..000000000 --- a/pixmaps/svg/linphone-status-away.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - statut_absent - - - - - - statut_absent - Created with Sketch. - - - diff --git a/pixmaps/svg/linphone-status-donotdisturb.svg b/pixmaps/svg/linphone-status-donotdisturb.svg deleted file mode 100644 index 54e2ef8fe..000000000 --- a/pixmaps/svg/linphone-status-donotdisturb.svg +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - image/svg+xml - - - - - - - led_error - Created with Sketch. - - - - diff --git a/pixmaps/svg/linphone-status-offline.svg b/pixmaps/svg/linphone-status-offline.svg deleted file mode 100644 index 890ee2f7f..000000000 --- a/pixmaps/svg/linphone-status-offline.svg +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - image/svg+xml - - - - - - - led_disconnected - Created with Sketch. - - - - diff --git a/pixmaps/svg/linphone-status-online.svg b/pixmaps/svg/linphone-status-online.svg deleted file mode 100644 index 5f7149e4d..000000000 --- a/pixmaps/svg/linphone-status-online.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - status_available - - - - - - status_available - Created with Sketch. - - - diff --git a/pixmaps/svg/linphone-stop-call.svg b/pixmaps/svg/linphone-stop-call.svg deleted file mode 100644 index ab4fa3b28..000000000 --- a/pixmaps/svg/linphone-stop-call.svg +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - image/svg+xml - - call_hangup - - - - - - call_hangup - Created with Sketch. - - - - - diff --git a/pixmaps/svg/linphone-warning.svg b/pixmaps/svg/linphone-warning.svg deleted file mode 100644 index e1cbb91d9..000000000 --- a/pixmaps/svg/linphone-warning.svg +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - image/svg+xml - - chat_message_not_delivered - - - - - - chat_message_not_delivered - Created with Sketch. - - - - - - - - - - - - - - diff --git a/pixmaps/svg/linphone.svg b/pixmaps/svg/linphone.svg deleted file mode 100644 index 528247c89..000000000 --- a/pixmaps/svg/linphone.svg +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/po/.gitignore b/po/.gitignore deleted file mode 100644 index 5af53230f..000000000 --- a/po/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.intltool-merge-cache -Makefile -Makefile.in -Makefile.in.in -POTFILES -*.gmo -stamp-* diff --git a/po/CMakeLists.txt b/po/CMakeLists.txt deleted file mode 100644 index b51481639..000000000 --- a/po/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -############################################################################ -# CMakeLists.txt -# Copyright (C) 2014 Belledonne Communications, Grenoble France -# -############################################################################ -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -############################################################################ - -if(GETTEXT_FOUND) - foreach(language ${LINPHONE_ALL_LANGS_LIST}) - GETTEXT_PROCESS_PO_FILES(${language} ALL PO_FILES ${language}.po) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${language}.gmo - DESTINATION ${PACKAGE_LOCALE_DIR}/${language}/LC_MESSAGES - RENAME linphone.mo - PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ - ) - endforeach() -endif() diff --git a/po/ChangeLog b/po/ChangeLog deleted file mode 100644 index 63269d9a1..000000000 --- a/po/ChangeLog +++ /dev/null @@ -1,97 +0,0 @@ -2007-01-17 gettextize - - * Makefile.in.in: Upgrade to gettext-0.16.1. - * cat-id-tbl.c: Remove file. - -2006-07-20 gettextize - - * Makefile.in.in: Upgrade to gettext-0.14.6. - * boldquot.sed: New file, from gettext-0.14.6. - * en@boldquot.header: New file, from gettext-0.14.6. - * en@quot.header: New file, from gettext-0.14.6. - * insert-header.sin: New file, from gettext-0.14.6. - * quot.sed: New file, from gettext-0.14.6. - * remove-potcdate.sin: New file, from gettext-0.14.6. - * Rules-quot: New file, from gettext-0.14.6. - * cat-id-tbl.c: Remove file. - -2002-10-15 gettextize - - * cat-id-tbl.c: Remove file. - * stamp-cat-id: Remove file. - -2002-10-08 gettextize - - * cat-id-tbl.c: Remove file. - * stamp-cat-id: Remove file. - -2002-10-08 gettextize - - * boldquot.sed: New file, from gettext-0.11.5. - * en@boldquot.header: New file, from gettext-0.11.5. - * en@quot.header: New file, from gettext-0.11.5. - * insert-header.sin: New file, from gettext-0.11.5. - * quot.sed: New file, from gettext-0.11.5. - * remove-potcdate.sin: New file, from gettext-0.11.5. - * Rules-quot: New file, from gettext-0.11.5. - * cat-id-tbl.c: Remove file. - * stamp-cat-id: Remove file. - -2002-10-04 gettextize - - * cat-id-tbl.c: Remove file. - * stamp-cat-id: Remove file. - -2002-10-04 gettextize - - * Makefile.in.in: Upgrade to gettext-0.11.5. - -2002-10-04 gettextize - - * Makefile.in.in: New file, from gettext-0.11.5. - -2002-10-01 gettextize - - * Makefile.in.in: Upgrade to gettext-0.11.5. - * boldquot.sed: New file, from gettext-0.11.5. - * en@boldquot.header: New file, from gettext-0.11.5. - * en@quot.header: New file, from gettext-0.11.5. - * insert-header.sin: New file, from gettext-0.11.5. - * quot.sed: New file, from gettext-0.11.5. - * remove-potcdate.sin: New file, from gettext-0.11.5. - * Rules-quot: New file, from gettext-0.11.5. - * cat-id-tbl.c: Remove file. - * stamp-cat-id: Remove file. - -2002-08-04 gettextize - - * Makefile.in.in: Upgrade to gettext-0.10.40. - -2002-08-04 gettextize - - * Makefile.in.in: Upgrade to gettext-0.10.40. - * cat-id-tbl.c: Remove file. - * stamp-cat-id: Remove file. - -2002-07-16 gettextize - - * Makefile.in.in: Upgrade to gettext-0.10.40. - * cat-id-tbl.c: Remove file. - * stamp-cat-id: Remove file. - -2002-02-16 gettextize - - * Makefile.in.in: Upgrade to gettext-0.10.40. - * cat-id-tbl.c: Remove file. - * stamp-cat-id: Remove file. - -2002-02-10 gettextize - - * Makefile.in.in: Upgrade to gettext-0.10.40. - -2002-02-10 gettextize - - * Makefile.in.in: Upgrade to gettext-0.10.40. - * cat-id-tbl.c: Remove file. - * stamp-cat-id: Remove file. - diff --git a/po/Makevars b/po/Makevars deleted file mode 100644 index 32692ab4b..000000000 --- a/po/Makevars +++ /dev/null @@ -1,41 +0,0 @@ -# Makefile variables for PO directory in any package using GNU gettext. - -# Usually the message domain is the same as the package name. -DOMAIN = $(PACKAGE) - -# These two variables depend on the location of this directory. -subdir = po -top_builddir = .. - -# These options get passed to xgettext. -XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ - -# This is the copyright holder that gets inserted into the header of the -# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding -# package. (Note that the msgstr strings, extracted from the package's -# sources, belong to the copyright holder of the package.) Translators are -# expected to transfer the copyright for their translations to this person -# or entity, or to disclaim their copyright. The empty string stands for -# the public domain; in this case the translators are expected to disclaim -# their copyright. -COPYRIGHT_HOLDER = Free Software Foundation, Inc. - -# This is the email address or URL to which the translators shall report -# bugs in the untranslated strings: -# - Strings which are not entire sentences, see the maintainer guidelines -# in the GNU gettext documentation, section 'Preparing Strings'. -# - Strings which use unclear terms or require additional context to be -# understood. -# - Strings which make invalid assumptions about notation of date, time or -# money. -# - Pluralisation problems. -# - Incorrect English spelling. -# - Incorrect formatting. -# It can be your email address, or a mailing list address where translators -# can write to without being subscribed, or the URL of a web page through -# which the translators can contact you. -MSGID_BUGS_ADDRESS = - -# This is the list of locale categories, beyond LC_MESSAGES, for which the -# message catalogs shall be used. It is usually empty. -EXTRA_LOCALE_CATEGORIES = diff --git a/po/Makevars.template b/po/Makevars.template deleted file mode 100644 index 32692ab4b..000000000 --- a/po/Makevars.template +++ /dev/null @@ -1,41 +0,0 @@ -# Makefile variables for PO directory in any package using GNU gettext. - -# Usually the message domain is the same as the package name. -DOMAIN = $(PACKAGE) - -# These two variables depend on the location of this directory. -subdir = po -top_builddir = .. - -# These options get passed to xgettext. -XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ - -# This is the copyright holder that gets inserted into the header of the -# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding -# package. (Note that the msgstr strings, extracted from the package's -# sources, belong to the copyright holder of the package.) Translators are -# expected to transfer the copyright for their translations to this person -# or entity, or to disclaim their copyright. The empty string stands for -# the public domain; in this case the translators are expected to disclaim -# their copyright. -COPYRIGHT_HOLDER = Free Software Foundation, Inc. - -# This is the email address or URL to which the translators shall report -# bugs in the untranslated strings: -# - Strings which are not entire sentences, see the maintainer guidelines -# in the GNU gettext documentation, section 'Preparing Strings'. -# - Strings which use unclear terms or require additional context to be -# understood. -# - Strings which make invalid assumptions about notation of date, time or -# money. -# - Pluralisation problems. -# - Incorrect English spelling. -# - Incorrect formatting. -# It can be your email address, or a mailing list address where translators -# can write to without being subscribed, or the URL of a web page through -# which the translators can contact you. -MSGID_BUGS_ADDRESS = - -# This is the list of locale categories, beyond LC_MESSAGES, for which the -# message catalogs shall be used. It is usually empty. -EXTRA_LOCALE_CATEGORIES = diff --git a/po/POTFILES.in b/po/POTFILES.in deleted file mode 100644 index c44eab3a2..000000000 --- a/po/POTFILES.in +++ /dev/null @@ -1,50 +0,0 @@ -# List of source files containing translatable strings. -gtk/calllogs.c -gtk/conference.c -gtk/logging.c -gtk/support.c -gtk/chat.c -gtk/main.c -gtk/friendlist.c -gtk/propertybox.c -gtk/update.c -gtk/buddylookup.c -gtk/setupwizard.c -gtk/incall_view.c -gtk/loginframe.c -gtk/config-fetching.c -gtk/audio_assistant.c -[type: gettext/glade]gtk/about.ui -[type: gettext/glade]gtk/audio_assistant.ui -[type: gettext/glade]gtk/buddylookup.ui -[type: gettext/glade]gtk/callee_frame.ui -[type: gettext/glade]gtk/call_logs.ui -[type: gettext/glade]gtk/call_statistics.ui -[type: gettext/glade]gtk/chatroom_frame.ui -[type: gettext/glade]gtk/conf_frame.ui -[type: gettext/glade]gtk/config-uri.ui -[type: gettext/glade]gtk/contact.ui -[type: gettext/glade]gtk/dscp_settings.ui -[type: gettext/glade]gtk/in_call_frame.ui -[type: gettext/glade]gtk/keypad.ui -[type: gettext/glade]gtk/ldap.ui -[type: gettext/glade]gtk/login_frame.ui -[type: gettext/glade]gtk/log.ui -[type: gettext/glade]gtk/main.ui -[type: gettext/glade]gtk/parameters.ui -[type: gettext/glade]gtk/password.ui -[type: gettext/glade]gtk/provisioning-fetch.ui -[type: gettext/glade]gtk/setup_wizard.ui -[type: gettext/glade]gtk/sip_account.ui -[type: gettext/glade]gtk/tunnel_config.ui -[type: gettext/glade]gtk/waiting.ui -coreapi/linphonecore.c -coreapi/misc.c -coreapi/presence.c -coreapi/friend.c -coreapi/proxy.c -coreapi/callbacks.c -coreapi/linphonecall.c - -coreapi/call_log.c -gtk/videowindow.c diff --git a/po/POTFILES.skip b/po/POTFILES.skip deleted file mode 100755 index 573d0bea5..000000000 --- a/po/POTFILES.skip +++ /dev/null @@ -1,56 +0,0 @@ -gtk/p2pwizard.ui -mediastreamer2/src/otherfilters/mspcapfileplayer.c -mediastreamer2/src/android/androidsound_depr.cpp -mediastreamer2/src/android/androidvideo.cpp -mediastreamer2/src/audiofilters/alaw.c -mediastreamer2/src/audiofilters/alsa.c -mediastreamer2/src/audiofilters/aqsnd.m -mediastreamer2/src/audiofilters/audiomixer.c -mediastreamer2/src/audiofilters/chanadapt.c -mediastreamer2/src/audiofilters/dtmfgen.c -mediastreamer2/src/audiofilters/equalizer.c -mediastreamer2/src/audiofilters/gsm.c -mediastreamer2/src/audiofilters/genericplc.c -mediastreamer2/src/audiofilters/msgenericplc.c -mediastreamer2/src/audiofilters/macsnd.c -mediastreamer2/src/audiofilters/msconf.c -mediastreamer2/src/audiofilters/msfileplayer.c -mediastreamer2/src/audiofilters/msfilerec.c -mediastreamer2/src/audiofilters/msfilerec_win.c -mediastreamer2/src/audiofilters/msiounit.m -mediastreamer2/src/audiofilters/msresample.c -mediastreamer2/src/audiofilters/msspeex.c -mediastreamer2/src/audiofilters/msvolume.c -mediastreamer2/src/audiofilters/oss.c -mediastreamer2/src/audiofilters/speexec.c -mediastreamer2/src/audiofilters/ulaw.c -mediastreamer2/src/audiofilters/webrtc_aec.c -mediastreamer2/src/otherfilters/itc.c -mediastreamer2/src/otherfilters/join.c -mediastreamer2/src/otherfilters/msrtp.c -mediastreamer2/src/otherfilters/tee.c -mediastreamer2/src/otherfilters/void.c -mediastreamer2/src/videofilters/drawdib-display.c -mediastreamer2/src/videofilters/extdisplay.c -mediastreamer2/src/videofilters/msdscap-mingw.cc -mediastreamer2/src/videofilters/msv4l.c -mediastreamer2/src/videofilters/msv4l2.c -mediastreamer2/src/videofilters/nowebcam.c -mediastreamer2/src/videofilters/pixconv.c -mediastreamer2/src/videofilters/sizeconv.c -mediastreamer2/src/videofilters/theora.c -mediastreamer2/src/videofilters/videodec.c -mediastreamer2/src/videofilters/videoenc.c -mediastreamer2/src/videofilters/videoout.c -mediastreamer2/src/videofilters/vp8.c -mediastreamer2/src/videofilters/wincevideods.c -mediastreamer2/src/videofilters/winvideo.c -mediastreamer2/src/videofilters/winvideods.c -mediastreamer2/src/videofilters/winvideo2.c -mediastreamer2/src/videofilters/x11video.c -mediastreamer2/src/videofilters/msdscap.cc -mediastreamer2/src/voip/ice.c -build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs -build/wp8/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs -mediastreamer2/build/wp8/mediastreamer2-tester-wp8/Resources/AppResources.Designer.cs -share/linphone.desktop.in diff --git a/po/README b/po/README deleted file mode 100644 index 68c47a874..000000000 --- a/po/README +++ /dev/null @@ -1,13 +0,0 @@ -How to add a translation file -***************************** -To add a translation file in linphone project you should first : - - add the file .po in the directory /po - - run ./autogen.sh - -Update the translation files -*************************** -To update all the translation files, in the directory /po run the following command - $ make update-po - - - diff --git a/po/Rules-quot b/po/Rules-quot deleted file mode 100644 index 9c2a995e3..000000000 --- a/po/Rules-quot +++ /dev/null @@ -1,47 +0,0 @@ -# Special Makefile rules for English message catalogs with quotation marks. - -DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot - -.SUFFIXES: .insert-header .po-update-en - -en@quot.po-create: - $(MAKE) en@quot.po-update -en@boldquot.po-create: - $(MAKE) en@boldquot.po-update - -en@quot.po-update: en@quot.po-update-en -en@boldquot.po-update: en@boldquot.po-update-en - -.insert-header.po-update-en: - @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \ - if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - ll=`echo $$lang | sed -e 's/@.*//'`; \ - LC_ALL=C; export LC_ALL; \ - cd $(srcdir); \ - if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$ll -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "creation of $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - -en@quot.insert-header: insert-header.sin - sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header - -en@boldquot.insert-header: insert-header.sin - sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header - -mostlyclean: mostlyclean-quot -mostlyclean-quot: - rm -f *.insert-header diff --git a/po/ar.po b/po/ar.po deleted file mode 100644 index 6fff00113..000000000 --- a/po/ar.po +++ /dev/null @@ -1,2107 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -# محيي الدين , 2014 -# محيي الدين , 2014-2016 -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: Arabic (http://www.transifex.com/belledonne-communications/linphone-gtk/language/ar/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ar\n" -"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "اتصل بـ %s" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "أرسل رسالة إلى %s" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "إضافة %s إلى قائمة جهات اتصالك" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "المكالمات السابقة" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "المكالمات الفائتة (%i)" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "—" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "أُلغيت" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "فائتة" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "مرفوضة" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "%i دقيقة" -msgstr[1] "دقيقة واحدة" -msgstr[2] "دقيقتان" -msgstr[3] "%i دقائق" -msgstr[4] "%i دقيقة" -msgstr[5] "%i دقيقة" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "%i ثانية" -msgstr[1] "ثانية واحدة" -msgstr[2] "ثانيتان" -msgstr[3] "%i ثوان" -msgstr[4] "%i ثانية" -msgstr[5] "%i ثانية" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "%s\tالجودة : %s\n%s\t%s\t" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "%s\t%s" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "اجتماع" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "أنا" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "أيقونة غير موجودة : %s" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "يجري الإرسال...‏" - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "لم تُرسَل الرسالة" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "نسخ" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "أظهِرْ بعض معلومات التنقيح خلال التشغيل." - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "عرض الإصدار ثم المغادرة" - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "الدليل إلى الملف الذي سيُكتَب فيه سجل الوقائع." - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "ابدأ لِنْفُونْ لكن دون تفعيل الفيديو." - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "شغِّله مُصغَّرا، ولا تُظهِر الواجهة الرئيسية." - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "العنوان المُراد الاتصال به الآن" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "حدِّد مجلد العمل (الذي سيكون مجلد التثبيت، مثلا c:\\Program Files\\Linphone)" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "ملف التهيئة" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "ابدأ مرشد الصوت" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "شغِّل الاختبار الذاتي ثم اخرِجْ 0 إذا نجح" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "يود %s إضافتك إلى جهات اتصاله.\nهل تريد إضافته إلى جهات اتصالك والسماح له برؤية حالة حضورك ؟\nإن كان الجواب بالرفض، سوف يجري حظر هذا الشخص مؤقتا." - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "ادخل كلمة السر لـ %s\n في نطاق %s:" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "خطأ في المكالمة" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "إنتهت المكالمة" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "مكالمة واردة" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "أجِبْ" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "ارفضْ" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "المكالمة متوقفة" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "بواسطة %s" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "يود %s تشغيل الفيديو. هل تقبل ذلك ؟" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "وصلة إلى الموقع وِبْ" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "لِنْفُونْ" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "الهاتف المرئي عبر الإنترنت" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "%s (افتراضي)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "التحويل إلى %s" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "لا وجود للوحة الصوت على هذا الحاسوب.\nلن تتمكن من تلقي أو إجراء أي مكالمة." - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "هاتف SIP المرئي الحر" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "أهلا\n" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "أضف إلى دفتر العناوين" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "ابحث في دليل %s" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "جهة اتصال sip غير صالحة !" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "إضافة جهة الاتصال جديدة" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "حرر جهة الاتصال '%s'" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "احذف جهة الاتصال '%s'" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "احذف تاريخ دردشات '%s'" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "اضف جهة اتصال انطلاقا من الدليل %s" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "الاسم" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "التردد (هرتز)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "الحالة" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "صبيب IP (ك.بِتْ/ثانية)" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "الإعدادات" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "مفعَّل" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "غير مفعَّل" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "الحساب" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "English" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "Français" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "Svenska" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "Italiano" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "Español" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "Português do Brasil" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "Polski" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "Deutsch" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "Русский" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "日本語" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "Nederlands" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "Magyar" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "Čeština" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "简体中文" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "繁体中文" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "Norsk bokmål" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "עברית" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "Српски" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "العربية" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "Türkçe" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "يجب إعادة تشغيل لِنْفُونْ لكي تٌفعَّل اللغة المختارة." - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "بدون" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "SRTP" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "DTLS" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "ZRTP" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "يوجد إصدار حديث من طرف %s.\nهل تريد فتح المتصفح لتنزيله ؟" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "أنت تستخدم الإصدار الأحدث." - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "الاسم، اللقب" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "خطأ في الاتصال مع الخادم." - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "يجري الاتصال..." - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "متصل" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "يجري تلقي البيانات..." - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "لم يُعثَر على أي جهة اتصال" -msgstr[1] "عُثِر على جهة اتصال واحدة" -msgstr[2] "عُثِر على جهتي اتصال" -msgstr[3] "عُثِر على %i جهات اتصال" -msgstr[4] "عُثِر على %i جهة اتصال" -msgstr[5] "عُثِر على %i جهة اتصال" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "إن اسم المستخدم يُستخدَم مسبقا !" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "فشل التحقق من إمكانية إتاحة اسم المستخدم. يُرجى الإعادة لاحقا." - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "مكالمة #%i" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "حوِّل إلى المكالمة #%i مع %s" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "غير مستخدَم" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "ICE غير مفعَّل" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "فَشِل ICE" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "تجري مساومة ICE" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "المرور عبد واحد أو عدة NAT" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "مباشر" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "عبر خادم بديل" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "uPnP غير مفعَّل" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "يجري uPnP" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "uPnP غير متوفر" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "uPnP مشغَّل" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "فَشِل uPnP" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "مباشرة أو عبر خادم" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "التنزيل % f\nالرفع : %f (ك.بِتْ/الثانية)" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "%ix%i @ %f fps" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "%.3f ثانية" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "ضع السماعة" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "يجري الاتصال..." - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "00:00:00" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "المكالمة الواردة" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "جيدة" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "متوسطة" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "ضعيفة" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "ضعيفة جدا" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "سيِّئة جيدا" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "غير متاحة" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "آمن بواسطة SRTP" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "مُؤمَّن بواسطة DTLS" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "آمن بواسطة ZRTP - [شارة الهوية : %s]" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "أكِّدْ عدم تحقُّقك" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "أكِّدْ تحقُّقَك" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "في اجتماع" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "المكالمة جارية" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "المكالمة متوقفة مؤقتا" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "إنتهت المكالمة." - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "يجري الإرسال" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "انتهى الإرسال." - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "فَشِل الإرسال." - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "استأنِفْ" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "إيقاف مؤقت" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "يسجل في\n%s %s" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "(متوقف)" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "يُرجى إدخال معلومات الولوج ل %s" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "يجلب من %s" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "فَشِل تنزيل التهيئة عن بعد من %s ." - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "لم يكتشف صوتاً" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "خافِت" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "جيد" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "صاخب" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "هل سمعت ثلاث رنات ؟" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "لم يعثر على تفضيلات الصوت" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "لم يتمكن من تشغيل التحكم في الصوت للنظام" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "مرحبا !\nسيمكنك هذا المرشد من تهيئة إعدادات الصوت من أجل لِنْفُونْ" - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "جهاز الالتقاط" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "الحجم المسجَّل" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "صامت" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "تفضيلات الصوت للنظام" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "جهاز السماع" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "شغِّل ثلاث رنَّات" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "اضغط على زر التسجيل وانطق ببعض الكلمات" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "استمع لصوتك المسجَّل" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "تسجيل" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "تشغيل" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "لنُشغِّل لِنْفُونْ الآن" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "مرشد الصوت" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "مرشد الصوت" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "معايرة كسب الميكروفون" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "معايرة شدة مكبر الصوت" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "سَجِّل واقرأ " - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "في طور الإنهاء" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "حول لِنْفُونْ" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "(C) Belledonne Communications, 2010\n" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "الهاتف المرئي للإنترنت الموافق للبروتوكول المعياري SIP (rfc3261)‎." - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "fr: Simon Morlat\nen: Simon Morlat and Delphine Perreau\nit: Alberto Zanoni \nde: Jean-Jacques Sarton \nsv: Daniel Nylander \nes: Jesus Benitez \nja: YAMAGUCHI YOSHIYA \npt_BR: Rafael Caesar Lenzi \npl: Robert Nasiadek \ncs: Petr Pisar \nhu: anonymous\nhe: Eli Zaretskii \nar: Muhiyeddine Cherik \n" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "البحث عن جهات الاتصال في الدليل" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "الإضافة إلى قائمتي" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "البحث عن شخص" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "اسم المنادَى" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "تاريخ المكالمات" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "أفْرِغ الكل" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "إعادة الاتصال" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "إحصاء المكالمات" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "مرمازات الصوت" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "مرمازات الفيديو" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "سعة القناة الصوتية" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "اتصالات الصوت" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "سعة قناة الفيديو" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "اتصالات الفيديو" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "مدة الذهاب والإياب" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "حجم الفيديو المستلَم" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "حجم الفيديو المرسَل" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "تشكيلة RTP" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "إحصاء المكالمات والمعلومات" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "أرسِلْ" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "أنْهِ الاجتماع" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "تحديد عنوان URI التهيئة عن بعد" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "يسمح لك مربع الحوار هذا بإعداد عنوان http أو https الذي من خلاله تود جلب التهيئة عند بدء البرنامج.\nأدخل العنوان أسفله. بعد تأكيد الأمر، ستجري إعادة تشغيل لِنْفُونْ تلقائيا من أجل جلب والأخذ بعين الاعتبار الإعدادات الحديثة." - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "عنوان SIP" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "رؤية حالة حضور جهة الاتصال هذه" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "السماح لجهة الاتصال هذه برؤية حالة حضوري" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "معلومات جهة الاتصال" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "إعدادات DSCP" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "SIP" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "تدفق RTP الصوتي" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "تدفق RTP المرئي" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "حدد قيم DSCP (بالنظام الست-عشري)" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "اضغط هنا لتحديد شدة مكبر الصوت" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "سَجِّل هذه المكالمة في ملف صوتي" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "مرئي" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "اصمُتْ" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "إرسال" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "المكالمة جارية" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "المدة" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "تقييم جودة المكالمة" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "إعدادات LDAP" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "عنوان الخادم :" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "طريقة التحقق من الهوية :" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "اسم المستخدم :" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "كلمة السر :" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "استخدم TLS" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "غير متاح" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "الاتصال " - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "ربط DN" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "اسم الهوية" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "النطاق" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "الكائن الأساسي :" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "رشِّح (%s كاسم) :" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "خاصية الاسم :" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "خاصية عنوان SIP :" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "الخاصيات المبحوث عنها :" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "البحث" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "المهلة القصوى للبحث :" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "العدد الأقصى للنتائج :" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "متابعة الكنية" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "متفرقات" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "مجهول الهوية" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "بسيط" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "DIGEST-MD5" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "NTLM" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "اسم المستخدم" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "كلمة السر" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "الاتصال بالإنترنت :" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "سَجِّل دخولي تلقائيا" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "مُعرِّف المستخدم" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "معلومات الولوج" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "مرحبا !" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "قناة الألياف الضوئية" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "نافذة تنقيح لِنْفُونْ" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "مرِّر إلى الآخر" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "افتراضي" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "احذف" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "الخ_يارات" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "عنوان URI للتهيئة" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "شغِّل الفيديو دائما" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "فعِّل رؤية نفسي" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "إظهار لوحة الأرقام" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "استورد جهات الاتصال من أنساق vCard" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "صدِّر جهات الاتصال بنسق vCard" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "ال_مساعدة" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "أظهِر نافذة التنقيح" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "موق_ع الوِبْ" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "تحقق من التح_ديثات" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "مرشد الحساب" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "عنوان SIP أو رقم الهاتف :" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "ابدأ مكالمة جديدة" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "جهات الاتصال" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "بحث" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "إضافة جهات الاتصال من الدليل" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "إضافة جهة الاتصال" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "محو تاريخ المكالمات" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "هويتي الحالية :" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "الإجابة التلقائية مُفعَّلة" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "مجهول" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "GSSAPI" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "لوحة الصوت الافتراضية" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "لوحة الصوت" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "الكاميرا الافتراضية" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "CIF" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "مرمازات الصوت" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "مرمازات الفيديو" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "C" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "SIP (UDP)" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "SIP (TCP)" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "SIP (TLS)" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "الإعدادات" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "هذه الفقرة تحدد عنوانك SIP إن كنت لا تستخدم حساب SIP" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "اسمك المعروض (مثلا : زيد عمرو) :" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "اسم المستخدم :" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "عنوانك SIP :" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "الهوية الافتراضية" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "المرشد" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "إضافة" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "حرر" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "أزل" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "حسابات الوكيل" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "احذف جميع كلمات السر" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "الأمان" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "الإجابة تلقائيا فور تلقي المكالمة" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "التأخير قبل الإجابة (ميلي ث,)" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "الإجابة تلقائيا" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "إدارة حسابات SIP" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "صوت الجرس :" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "عتاد ALSA الخصوصي (اختياري) :" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "جهاز الالتقاط :" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "جهاز الرنين :" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "جهاز السمع :" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "فعِّل إزالة الصدى" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "الصوت" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "جهاز إدخال الفيديو :" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "المقدار المُراد لدقة الفيديو :" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "طريقة إخراج الفيديو :" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "اظهر معاينة الكاميرا" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "الفيديو المُسبَق :" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "المقدار المُراد لمعدل إطارات الفيديو :" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "حدِّد 0 لعدم وضع أي حد" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "الفيديو" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "حد سرعة الرفع بالكيلوبِتْ/الثانية :" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "حد سرعة التنزيل بالكيلوبِتْ/الثانية :" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "فعِّل التحكم المتكيف مع الصبيب" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "التحكم المتكيف مع الصبيب هو تقنية لملائمة جودة الصوت والصورة بناءً على سعة قناة الاتصال المتاحة خلال المكالمة." - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "إدارة سعة القناة" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "إعدادات الوسائط المتعددة" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "حدِّد Maximum Transmission Unit :" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "أرسِل الأرقام الهاتفية على هيئة SIP INFO" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "السماح باستخدام IPv6" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "النقل" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "منفذ SIP/UDP" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "عشوائي" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "منفذ SIP/TCP" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "صوت RTP/UDP :" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "ثابت" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "فيديو RTP/UDP :" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "النفق" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "حقول DSCP" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "بروتوكول الشبكة والمنافذ" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "الاتصال مباشر بالإنترنت" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "وراء جدار ناري (حدِّد عنوان IP البوابة)" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "وراء جدار ناري (استخدم STUN)" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "وراء جدار ناري (استخدم ICE)" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "وراء جدار ناري (استخدم uPnP)" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "عنوان IP العمومي :" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "خادم STUN :" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "إعدادات حول الجدار الناري" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "نوع وسيط التعمية" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "‫استخدم Lime لرسائل المحادثات الصادرة‬" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "وسيط التعمية إجباري" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "واجب" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "مستحب" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "التعمية" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "إعدادات الشبكة" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "فعِّل" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "إلغاء التفعيل" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "مرمازات الصوت" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "مرمازات الفيديو" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "المراميز" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "اللغة" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "أظهر الإعدادات المتقدمة" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "المستوى" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "واجهة المستخدم" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "تهيئة LDAP" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "LDAP" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "أغلق" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "لِنْفُونْ - يجب التحقق من الهوية" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "أدخل كلمة سر النطاق" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "تجري التهيئة..." - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "رجاءً انتظر ريثما ينتهي من جلب الإعدادات من الخادم..." - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "مرشد تهيئة حساب SIP" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "مرحبا !\nسيمكنك هذا المرشد من إعداد حسابك SIP لإجراء المكالمات." - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "مرحبا بك في مرشد إعداد الحساب" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "إنشاء حساب في linphone.org" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "أتوفر مسبقا على حساب في linphone.org وأريد فقط استخدامه" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "أتوفر مسبقا على حساب sip وأريد فقط استخدامه" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "أريد تحديد عنوان التهيئة عن بعد" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "مرشد تهيئة الحساب" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "ادخل معلومات حسابك" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "اسم المستخدم*" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "كلمة السر*" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "النطاق*" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "الوكيل" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "تهيئة حسابك (المرحلة 1/1)" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "أدخِل اسم المستخدم في linphone.org" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "أدخل اسم المستخدم SIP (المرحلة 1/1)" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "(*) حقول ضرورية" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "البريد الالكتروني : (*)" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "اسم المستخدم* : (*)" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "كلمة السر* : (*)" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "أكِّد كلمة السر : (*)" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "أحطني علما بتحديثات لِنْفُونْ" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "أدخل معلومات حسابك (المرحلة 1/2)" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "يُرجى الانتظار، يجري الآن إنشاء حسابك." - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "إنشاء الحساب في تقدم" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "يُرجى تأكيد حسابك وذلك بالضغط على الوصلة التي أرسلناها لك بالبريد الإلكتروني.\nثم ارجع إلى هنا واضغط على زر التالي." - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "تأكيد (المرحلة 2/2)" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "يُرجى الانتظار، يجري الآن فحص التحقق من صحة حسابك." - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "التحقق من الحساب في تقدم" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "خطأ، لم يتم تأكيد الحساب، سبق استخدام اسم المستخدم أو تعذر الوصول للخادم.\nيُرجى إعادة المحاولة لاحقا." - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "خطأ" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "شكرا لك، لقد جرت تهيئة حسابك وهو الآن قابل للاستخدام." - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "لِنْفُونْ - تهيئة حساب SIP" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "هوية SIP لديك :" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "يشبه sip:@" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "sip:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "عنوان وكيل SIP :" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "يشبه sip:" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "مدة التسجيل (بالثواني) :" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "إعدادات جهة الاتصال (اختيارية) :" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "مجال RTCP الاعتيادي ل AVPF (بالثواني) :" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "التوجيه (اختياري) :" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "النقل" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "التسجيل" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "انشر معلومات الحضور" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "فعِّل AVPF " - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "تهيئة حساب SIP" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "تهيئة نفق VoIP" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "المضيف" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "المنفذ" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "تهيئة النفق" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "تهيئة وكيل http (اختياري)" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "يُرجى الانتظار" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "جاهز" - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "تجري التهيئة" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "يتصل ب" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "لم يتمكن من الاتصال" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "آسف، وصل عدد المكالمات الآنية إلى حده الأقصى" - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "يتصل بك" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr "ويطلب ردا تلقائيا." - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "يجري تعديل إعدادات المكالمة..." - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "متصل." - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "أُلغيت المكالمة" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "لم يتمكن من توقيف المكالمة مؤقتا" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "وضع المكالمة قيد الانتظار..." - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "يجري بحث STUN..." - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "يجري جلب مرشَّحي ICE المحلين..." - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "على الخط" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "مشغول" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "سأعود" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "غائب" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "على الهاتف" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "أمام مائدة الطعام" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "لا تزعجني" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "ذهبتُ" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "أستخدم خدمة أخرى للتراسل الفوري" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "غير متصل" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "قيد الانتظار" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "في عطلة" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "حالة مجهولة" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "إن عنوان SIP الذي أدخلت غير صحيح، يجب أن يبدأ بـ \"sip:‎\" متبوعا باسم المضيف." - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "إن هوية SIP التي أدخلت غير صحيحة.\nيجب أن تكون بهذا النمط sip:username@proxydomain، مثلا sip:alice@example.net" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "يجري البحث عن وجهة رقم الهاتف..." - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "لم يتمكن من إيجاد هذا الرقم." - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "تعذر الولوج بالهوية %s" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "‫يجري إنعاش في %s...‬" - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "يرن الجرس عن بعد..." - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "يرن الجرس عن بعد..." - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "أخذ المكالمة مبكرا." - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "‫أجاب عن المكالمة %s‬" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "استُعيدت المكالمة." - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "غير موائم، تحقق من المراميز أو إعدادات الأمان..." - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "إعدادات الوسائط غير موائمة." - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "استُأنِفت المكالمة." - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "وُقِّفت المكالمة مؤقتا من طرف آخر." - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "حُدِّث الاتصال من البعيد." - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "أُنهيت المكالمة." - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "المستخدم مشغول." - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "المستخدم غير متاح مؤقتا." - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "لا يريد المستخدم أي إزعاج." - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "تم تجاهل المكالمة." - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "انتهت مهلة الطلب." - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "مُوجَّه" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "فشل الاتصال." - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "تم التسجيل في %s بنجاح." - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "أُلغي التسجيل في %s ." - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "لا إجابة قبل انتهاء المهلة" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "فَشِل التسجيل في %s: %s" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "خدمة غير متاحة، تجري الإعادة" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "شارة التحقق من الهوية هي %s" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "‫لم تُعدَّل معاملات المكالمات : %s.‬" - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "عُدِّلت معاملات المكالمات بنجاج." - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "لم تفتك أي مكالمة." -msgstr[1] "فاتتك مكالمة واحدة." -msgstr[2] "فاتتك مكالمتان." -msgstr[3] "فاتتك %i مكالمات." -msgstr[4] "فاتتك %i مكالمة." -msgstr[5] "فاتتك %i مكالمة." - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "أُجهِضت" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "اكتملت" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "فاتت" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "مجهول" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "%s في %s\nمن : %s\nإلى : %s\nالحالة : %s\nالمدة : %i دقيقة %i ثانية\n" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "المكالمة الصادرة" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "لم يتمكن من تشغيل %s" - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" diff --git a/po/boldquot.sed b/po/boldquot.sed deleted file mode 100644 index 4b937aa51..000000000 --- a/po/boldquot.sed +++ /dev/null @@ -1,10 +0,0 @@ -s/"\([^"]*\)"/“\1”/g -s/`\([^`']*\)'/‘\1’/g -s/ '\([^`']*\)' / ‘\1’ /g -s/ '\([^`']*\)'$/ ‘\1’/g -s/^'\([^`']*\)' /‘\1’ /g -s/“”/""/g -s/“/“/g -s/”/”/g -s/‘/‘/g -s/’/’/g diff --git a/po/cs.po b/po/cs.po deleted file mode 100644 index 70d394fa7..000000000 --- a/po/cs.po +++ /dev/null @@ -1,2095 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -# Klara Cihlarova , 2005 -# Petr Pisar , 2006-2011,2013 -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: Czech (http://www.transifex.com/belledonne-communications/linphone-gtk/language/cs/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: cs\n" -"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "Volat komu: %s" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "Poslat text komu: %s" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "Nedávné hovory" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "Nedávné hovory (%i)" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "–" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "Přerušen" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "Zmeškán" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "Odmítnut" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "%i minuta" -msgstr[1] "%i minuty" -msgstr[2] "%i minut" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "%i sekunda" -msgstr[1] "%i sekundy" -msgstr[2] "%i sekund" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "%s\tKvalita: %s\n%s\t%s\t" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "%s\t%s" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "Konference" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "Já" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "Nelze najít soubor s obrázkem: %s" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "" - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "Za běhu vypisuje některé ladicí informace na standardní výstup." - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "" - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "Soubor, kam zapisovat protokol." - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "Spustí linphone se zakázaným obrazem." - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "Spustí se pouze do systémové oblasti, nezobrazí hlavní okno." - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "Zavolá právě teď na tuto adresu" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "Zadejte pracovní adresář (měl by být základní instalační adresář, například c:\\Program Files\\Linphone)" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "" - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "Chyba hovoru" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "Hovor ukončen" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "Příchozí hovor" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "Odpovědět" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "Odmítnout" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "Hovor odložen" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "kým: %s" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "%s navrhuje začít videohovor. Přijímáte?" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "Odkaz na webovou stránku" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "%s (Výchozí)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "Byly jsme přepojeni na %s" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "Na tomto počítači nebyla objevena žádná zvuková karta.\nNebudete moci vytáčet a přijímat a zvukové hovory." - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "Volný SIP videofon" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "Přidat do adresáře" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "Hledat v adresáři %s" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "Neplatný sipový kontakt!" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "Upravit kontakt „%s“" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "Odstranit kontakt „%s“" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "Odstranit historii diskuze u kontaktu „%s“" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "Přidat nový kontakt z adresáře %s" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "Jméno" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "Kmitočet (Hz)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "Stav" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "Parametry" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "Povoleno" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "Zakázáno" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "Účet" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "angličtina" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "francouzština" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "švédština" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "italština" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "španělština" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "brazilská portugalština" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "polština" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "němčina" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "ruština" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "japonština" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "dánština" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "maďarština" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "čeština" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "čínština" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "tradiční čínština" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "norština" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "hebrejština" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "srbština" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "Aby se projevil výběr nového jazyka, je nutné znovu spustit linphone." - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "Žádné" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "SRTP" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "ZRTP" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "Na %s je dostupná novější verze.\nPřejete si otevřít prohlížeč, abyste si ji mohli stáhnout?" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "Máte spuštěnou poslední verzi." - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "První jméno, Poslední jméno" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "Chyba komunikace se serverem." - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "Připojuje se…" - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "Připojeno" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "Přijímají se data…" - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "Nalezen %i kontakt" -msgstr[1] "Nalezeny %i kontakty" -msgstr[2] "Nalezeno %i kontaktů" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "" - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "Hovor č. %i" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "Přepojit hovor č. %i s %s" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "Nepoužito" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "ICE není zapnuto" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "ICE selhalo" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "Probíhá ICE" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "Prochází se jedním nebo více NATy" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "Přímé" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "Skrze relay server" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "UPnP není zapnuto" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "Probíhá UPnP" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "UPnP není nedostupné" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "UPnP běží" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "UPnP selhalo" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "Přímé nebo skrze server" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "příchozí: %f\nodchozí: %f (kb/s)" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "%.3f sekund" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "Zavěsit" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "Volá se…" - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "Příchozí hovor" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "dobrá" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "průměrná" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "slabá" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "velmi slabá" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "příliš špatná" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "nedostupná" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "Zabezpečeno pomocí SRTP" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "Zabezpečeno pomocí ZRTP – [ověřovací klíč: %s]" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "Nastavit na neověřeno" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "Nastavit na ověřeno" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "Probíhá konference" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "Probíhá hovor" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "Odložený hovor" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "Hovor skončil." - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "Probíhá přepojení" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "Přepojení dokončeno." - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "Přepojení selhalo." - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "Obnovit" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "Odložit" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "Nahrává se do\n%s %s" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "(Odloženo)" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "Prosím, zadejte své přihlašovací jméno pro %s:" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "" - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "" - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "Ukončuje se" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "Internetový videofon používající standardní protokol SIP (RFC 3261)." - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "Hledat kontakty v adresáři" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "Přidat na svůj seznam" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "Hledat někoho" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "Jméno volaného" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "Historie volání" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "Vše smazat" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "Zavolat zpátky" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "Statistické údaje o hovoru" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "Kodek zvuku" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "Kodek obrazu" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "Přenosová rychlost zvuku na úrovni IP" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "Zvukové spojení" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "Přenosová rychlost obrazu na úrovni IP" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "Obrazové spojení" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "Odezva" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "Statistické a ostatní údaje o hovoru" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "Odeslat" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "Ukončit konferenci" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "" - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "SIP adresa" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "U tohoto kontaktu zobrazovat stav přítomnosti" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "Dovolit tomuto kontaktu, aby viděl můj stav přítomnosti" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "Informace o kontaktu" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "SIP" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "RTP proud zvuku" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "RTP proud obrazu" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "Nastavit hodnoty DSCP (šestnáctkově)" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "Nahrát tento hovor do zvukového souboru" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "Obraz" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "Ztišit" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "Přepojit" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "Telefonuje se" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "Délka" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "Hodnocení kvality hovoru" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "Uživatelské jméno:" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "Heslo:" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Uživatelské jméno" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Heslo" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "Připojení k Internetu:" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "Přihlašovat mě automaticky" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "Identifikátor uživatele" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "Informace o přihlášení" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "Fiber Channel" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "Ladicí okno Linphonu" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "Přejít na konec" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "Výchozí" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "Smazat" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "V_olby" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "Vždy spustit obraz" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "Zobrazovat sám sebe" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "Nápo_věda" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "Zobrazit ladicí okno" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "_Domovská stránka" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "Vyhledat akt_ualizace" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "Průvodce účtem" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "SIP adresa nebo telefonní číslo:" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "Zahájit nový hovor" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "Kontakty" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "Hledat" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "Přidat kontakty z adresáře" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "Přidat kontakt" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "Moje současná totožnost:" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "implicitní zvuková karta" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "zvuková karta" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "implicitní kamera" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "CIF" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "Kodeky zvuku" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "Kodeky obrazu" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "C" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "SIP (UDP)" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "SIP (TCP)" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "SIP (TLS)" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "Nastavení" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "Tento oddíl určuje vaši SIP adresu, když se nepoužívá žádný účet" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "Vaše zobrazované jméno (např. Jan Novák):" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "Vaše uživatelské jméno:" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "Vaše výsledná SIP adresa:" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "Implicitní totožnost" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "Průvodce" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "Přidat" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "Upravit" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "Odstranit" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "Proxy účty" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "Vymazat všechna hesla" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "Soukromí" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "Nastavení SIP účtů" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Vyzvánění:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "Zvláštní ALSA zařízení (volitelné):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Zařízení pro nahrávání:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Zařízení pro vyzvánění:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Zařízení pro přehrávání:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Zapnout potlačení ozvěny" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Zvuk" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Vstupní zařízení obrazu:" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "0 znamená „neomezeno“" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "Obraz" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "Omezení odchozí rychlosti (kb/s):" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "Omezení příchozí rychlosti (kb/s):" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "Zapnout přizpůsobující se řízení rychlosti" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "Přizpůsobující se řízení rychlosti je technika dynamického odhadu dostupného pásma během hovoru." - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "Využití šířky pásma" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "Nastavení multimédií" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "Nastavit MTU (největší přenositelná zpráva):" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "Odesílat tóny DTMF jako SIP INFO zprávy" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "Přenos" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "Zvukový RTP/UDP:" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "Stálý" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "Obrazový RTP/UDP:" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "Tunel" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "Položky DSCP" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "Síťové protokoly a porty" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "Přímé připojení do Internetu" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "Za NAT/firewallem (adresu určí STUN)" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "Za NAT/firewallem (adresu určí ICE)" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "Za NAT/firewallem (adresu určí UPnP)" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "Veřejná IP adresa:" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "STUN server:" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "NAT a firewall" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "Druh šifrování médií" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "Šifrování médií je povinné" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "Nastavení sítě" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Povolit" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Zakázat" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "Kodeky" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "Jazyk" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "Zobrazit podrobnější nastavení" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "Úroveň" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "Uživatelské rozhraní" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "Hotovo" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "Linphone – Ověření totožnosti vyžadováno" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "Prosím, zadejte heslo pro doménu" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "" - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "Vítejte v průvodci nastavení účtu" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "Vytvořit účet na linphone.org" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "Účet na linphone.org již mám a chci jej použít" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "SIP účet již mám a chci jej použít" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "Průvodce nastavením účtu" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "Uživatelské jméno*" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "Heslo*" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "Doména*" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "Proxy" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "Nastavit účet (krok 1/1)" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "Zadejte uživatelské jméno na linphone.org" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "Zadejte vaše sipové uživatelské jméno (krok 1/1)" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "(*) Povinné položky" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "E-mail: (*)" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "Uživatelské jméno: (*)" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "Heslo: (*)" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "Potvrďte heslo: (*)" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "Zadejte údaje o účtu (krok 1/2)" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "Prosím, ověřte svůj účet tak, že kliknete na odkaz, který jsme vám právě zaslali e-mailem.\nPak se sem vraťte a stiskněte tlačítko Další." - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "Ověření (krok 2/2)" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "Došlo k chybě (účet nebyl ověřen, uživatelské jméno již existuje nebo server není dostupný).\nProsím, vraťte se a zkoste to znovu." - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "Chyba" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Děkujeme vám. Váš účet je nyní nastaven a připraven k použití." - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "Linphone – Nastav SIP účet" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "Vaše SIP totožnost:" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "Vypadá jako sip:@" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "sip:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "Adresa SIP proxy:" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "Vypadá jako sip:" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "Registrační období (s):" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "Směrování (volitelné):" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "Zaregistrovat se" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "Zveřejnit stav přítomnosti" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "Nastavit SIP účet" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "Nastavit VoIP tunel" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "Stroj" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "Port" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "Nastavit tunel" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "Nastavit HTTP proxy (volitelné)" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "Prosím, čekejte" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "Připraven." - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "Navazuje se spojení" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "Nelze volat" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "Je nám líto, ale byl dosažen maximální počet současných hovorů." - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "vás volá" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr " a požaduje automatickou zvednutí." - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "Upravují se parametry hovoru…" - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "Připojeno." - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "Hovor přerušen" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "Hovor nebylo možné odložit" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "Současný hovor se odkládá…" - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "Hledá se adresa pomocí STUN…" - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "Shromažďují se místní kandidáti ICE…" - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "Připojen" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "Zaneprázdněn" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "Za chvíli se vrátím" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "Pryč" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "U telefonu" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "Na obědě" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "Nerušit" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "Přestěhoval jsem se" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "Používám jinou službu přenosu zpráv" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "Odpojen" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "Čekám" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "Adresa SIP proxy, kterou jste zadali, není platná. Musí začínat na „sip:“ a pak musí následovat jméno stroje." - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "SIP identita, kterou jste zadali, není platná.\nMěla by mít tvar sip:uživatel@proxydoména, například sip:alice@example.net" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "Vyhledává se umístění čísla…" - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "Toto číslo nelze vyhledat." - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "Nelze se přihlásit jako %s" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "" - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "Vyzvání na druhé straně." - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "Vyzvání na druhé straně…" - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "Časná média." - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "Hovor obnoven." - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "Není slučitelné. Zkontrolujte nastavení kodeků a zabezpečení…" - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "Neslučitelné parametry médií." - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "Byli jsme obnoveni." - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "Byli jsme odloženi protistranou." - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "Hovor byl aktualizován protistranou." - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "Hovor ukončen." - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "Uživatel je zaneprázdněn." - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "Uživatel je dočasně nedostupný." - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "Uživatel si nepřeje být rušen." - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "Volání odmítnuto." - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "" - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "Přesměrováno" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "Volání se nezdařilo." - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "Registrace na %s byla úspěšná." - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "Odregistrování z %s hotovo." - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "odpověď nedorazila včas" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "Registrace na %s selhala: %s" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "Klíč k ověření totožnosti je %s" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "" - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "" - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "Máte %i zmeškaný hovor." -msgstr[1] "Máte %i zmeškané hovory." -msgstr[2] "Máte %i zmeškaných hovorů." - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "" - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" diff --git a/po/de.po b/po/de.po deleted file mode 100644 index 50aef056b..000000000 --- a/po/de.po +++ /dev/null @@ -1,2094 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -# andreas, 2014 -# andreas, 2014 -# Ettore Atalan , 2015-2016 -# Gerhard Stengel , 2011-2012 -# Simon Morlat , 2001 -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: German (http://www.transifex.com/belledonne-communications/linphone-gtk/language/de/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: de\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "„%s“ anrufen" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "Text zu „%s“ schicken" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "%s zu Ihrer Kontaktliste hinzufügen" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "Letzte Gespräche" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "Letzte Anrufe (%i)" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "n/v" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "Abgebrochen" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "Verpasst" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "Abgewiesen" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "%i Minute" -msgstr[1] "%i Minuten" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "%i Sekunde" -msgstr[1] "%i Sekunden" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "%s\tQualität: %s\n%s\t%s\t" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "%s\t%s" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "Konferenz" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "Eigenes Telefon" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "Pixmapdatei %s kann nicht gefunden werden." - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "Sendevorgang..." - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "Nachricht nicht gesendet" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "Kopieren" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "Ausgabe von Debug-Informationen auf stdout während der Laufzeit" - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "Version anzeigen und beenden." - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "Pfad zu einer Datei, in die Protokolle geschrieben werden." - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "Linphone mit ausgeschaltetem Video starten." - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "Nur im Systemabschnitt der Kontrollleiste starten, aber das Hauptfenster nicht zeigen." - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "Im Moment anzurufende Adresse" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "Geben Sie einen Arbeitsordner an (sollte der Installationsordner sein, z. B. C:\\Programme\\Linphone)" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "Konfigurationsdatei" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "Starte den Audio-Assistent" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "Selbsttest ausführen und mit 0 beenden, wenn erfolgreich" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "" - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "Bitte geben Sie Ihr Passwort für den Benutzernamen %s\n für Bereich %s ein:" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "Anruf fehlgeschlagen" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "Anruf beendet" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "Eingehender Anruf" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "Annehmen" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "Abweisen" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "Anruf wird gehalten" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "von %s" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "%s schlägt vor, eine Videoübertragung zu starten. Nehmen Sie an?" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "Website-Verknüpfung" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "Ein Internet-Video-Telefon" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "%s (Vorgabe)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "Vermittlung nach %s" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "Auf diesem Rechner können keine Soundkarten gefunden werden.\nSie können keine Audio-Anrufe tätigen oder entgegennehmen." - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "Ein freies SIP-Video-Telefon" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "Hallo\n" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "Zum Adressbuch hinzufügen" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "Im %s-Verzeichnis suchen" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "Ungültiger SIP-Kontakt!" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "Neuen Kontakt hinzufügen" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "Kontakt „%s“ bearbeiten" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "Kontakt „%s“ löschen" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "Lösche Gesprächshistorie von '%s'" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "Einen neuen Kontakt aus dem %s-Verzeichnis hinzufügen" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "Name" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "Rate (Hz)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "Status" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "IP Bit-Rate (kbit/s)" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "Parameter" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "Freigegeben" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "Gesperrt" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "Konto" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "Englisch" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "Französisch" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "Schwedisch" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "Italienisch" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "Spanisch" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "Brasilianisches Portugiesisch" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "Polnisch" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "Deutsch" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "Russisch" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "Japanisch" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "Niederländisch" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "Ungarisch" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "Tschechisch" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "Chinesisch" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "Traditionelles Chinesisch" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "Norwegisch" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "Hebräisch" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "Serbisch" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "Arabisch" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "Türkisch" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "Linphone muss neu gestartet werden, damit die neue Spracheinstellung wirksam wird." - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "Keinen" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "SRTP" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "DTLS" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "ZRTP" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "Eine neuere Version ist von %s verfügbar.\nMöchten Sie einen Browser zum Herunterladen öffnen?" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "Sie verwenden bereits die aktuellste Version." - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "Vorname, Nachname" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "Fehler bei der Kommunikation mit dem Server." - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "Verbinden..." - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "Verbunden" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "Daten werden empfangen..." - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "%i Kontakt gefunden" -msgstr[1] "%i Kontakte gefunden" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "Benutzername wird bereits verwendet!" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "Fehler beim Überprüfen der Benutzernamenverfügbarkeit. Bitte versuchen Sie es später erneut." - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "Anruf #%i" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "Vermittlung zum Anruf #%i mit %s" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "Nicht verwendet" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "ICE nicht aktiviert" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "ICE fehlgeschlagen" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "ICE läuft" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "Ein oder mehrere NATs werden durchquert" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "Direkt" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "Über einen Relay-Server" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "uPnP nicht aktiviert" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "uPnP läuft" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "uPnp nicht verfügbar" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "uPnP läuft" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "uPnP fehlgeschlagen" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "Direkt oder über Server" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "Herunterladen: %f\nHochladen: %f (kbit/s)" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "%ix%i @ %f bps" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "%.3f Sekunden" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "Auflegen" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "Verbindungsaufbau..." - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "00:00:00" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "Eingehender Anruf" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "gut" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "durchschnittlich" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "schlecht" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "sehr schlecht" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "zu schlecht" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "nicht verfügbar" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "Gesichert durch SRTP" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "Gesichert durch DTLS" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "Gesichert durch ZRTP - [Auth.-Token: %s]" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "Auf „Ungeprüft“ setzen" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "Auf „Geprüft“ setzen" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "In Konferenz" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "Im Gespräch" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "Gehaltener Anruf" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "Anruf beendet." - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "Vermittlung läuft" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "Vermittlung abgeschlossen." - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "Vermittlung fehlgeschlagen." - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "Fortsetzen" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "Halten" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "Recording into\n%s %s" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "(pausiert)" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "Bitte geben Sie die Anmeldeinformationen für %s ein." - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "abrufen von %s" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "Herunterladen der Fernkonfiguration von %s fehlgeschlagen" - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "Keine Stimme ermittelt" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "zu gering" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "gut" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "zu laut" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "Haben Sie die drei Signaltöne gehört?" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "Toneinstellungen nicht gefunden" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "Systemtonsteuerung kann nicht gestartet werden" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "Willkommen!\nDieser Assistent hilft Ihnen die Audioeinstellungen für Linphone einzurichten." - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "Aufnahmegerät" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "aufgenommene Lautstärke" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "Keine Stimme" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "Systemtoneinstellungen" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "Wiedergabegerät" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "spiele drei Pieptöne ab" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "Drücken Sie den Aufnahmeknopf und sagen Sie etwas" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "Hören Sie das Aufgenommene" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "Aufnahme" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "Wiedergabe" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "Linphone jetzt starten" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "Audio-Assistant" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "Audio-Assistant" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "Einrichtung MIkrofonverstärker" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "Einrichtung Lautstärke" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "aufnehmen und abspielen" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "Fertigstellen" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "Über Linphone" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "(C) Belledonne Communications, 2010\n" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "Ein Internet-Video-Telefon, das das Standard-SIP-Protokoll (RFC3261) verwendet." - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "fr: Simon Morlat\nen: Simon Morlat and Delphine Perreau\nit: Alberto Zanoni \nde: Jean-Jacques Sarton \nsv: Daniel Nylander \nes: Jesus Benitez \nja: YAMAGUCHI YOSHIYA \npt_BR: Rafael Caesar Lenzi \npl: Robert Nasiadek \ncs: Petr Pisar \nhu: anonymous\nhe: Eli Zaretskii \n" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "Kontakte im Verzeichnis suchen" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "Zur Kontaktliste hinzufügen" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "Kontaktsuche" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "Name des Angerufenen" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "Anrufchronik" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "Alle löschen" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "Anrufen" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "Anrufstatistik" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "Audiocodec" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "Videocodec" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "Genutzte IP-Bandbreite Audio" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "Audio-Konnektivität" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "Genutzte IP-Bandbreite Video" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "Video-Konnektivität" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "Umlaufzeit" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "Videoauflösung empfangen" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "Videoauflösung gesendet" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "RTP-Profil" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "Anrufstatistik und -informationen" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "Senden" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "Konferenz beenden" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "Eine URI zur FErnkonfiguration angeben" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "Diese Maske erlaubt Ihnen für das Laden der Konfiguration beim Programmstart eine http- oder https-Adresse anzugeben.\nBitte geben Sie unten die Konfigurations-URI ein oder ändern diese. Nach dem Bestätigen mit OK wird Linphone automatisch neustarten, um die neuen Einstellungen zu übernehmen." - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "SIP-Adresse" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "Anwesenheitsstatus dieses Kontakts zeigen" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "Diesem Kontakt erlauben, meinen Anwesenheitsstatus zu sehen" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "Kontaktinformationen" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "DSCP-Einstellungen" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "SIP" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "Audio-RTP-Datenstrom" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "Video-RTP-Datenstrom" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "DSCP-Werte setzen (hexadezimal)" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "Klicken Sie hier, um die Lautsprecherlautstärke festzulegen" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "Speichere den Anruf in eine Audio-Datei" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "Video" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "Stumm" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "Vermittlung" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "Im Gespräch" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "Dauer" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "Bewertung der Verbindungsqualität" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "LDAP-Einstellungen" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "Server-Adresse" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "Authentifizierungsmethode" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "Benutzername:" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "Passwort:" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "TLS-Verbindung verwenden" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "Aktuell nicht verfügbar" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "Verbindung" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "Bind-DN" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "Authentifizierungsname" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "Bereich" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "Basis-Objekt:" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "Filter (%s nach Name):" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "Name:" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "SIP-Adresse:" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "Sucheigenschaft:" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "Suche" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "Zeitüberschreitung bei der Suche:" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "Max Ergebnisse:" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "folge Pseudonymen" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "Sonstiges" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "ANONYMOUS" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "SIMPLE" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "DIGEST-MD5" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "NTLM" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Benutzername" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Passwort" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "Internetverbindung:" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "Automatisch anmelden" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "Benutzer-ID" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "Anmeldeinformationen" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "Willkommen!" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "Glasfaserkabel" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "Linphone Debug-Fenster" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "Ans Ende rollen" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "Vorgabe" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "Löschen" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "_Optionen" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "Konfigurations URI angeben" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "Video immer starten" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "Selbstansicht ein" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "Tastatur anzeigen" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "Kontakte aus vCards importieren" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "Kontakte als vCards exportieren" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "_Hilfe" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "Debug-Fenster anzeigen" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "_Homepage" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "Auf _Aktualisierungen überprüfen" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "Konto-Einrichtungsassistent" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "SIP-Adresse oder Telefonnummer:" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "Einen neuen Anruf beginnen" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "Kontakte" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "Suchen" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "Kontakte aus einem Verzeichnis hinzufügen" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "Kontakt hinzufügen" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "Anrufchronik löschen" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "Aktuelle Identität:" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "Automatische Antwort ist aktiviert" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "Anonym" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "GSSAPI" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "Standard-Soundkarte" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "eine Soundkarte" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "Standard-Kamera" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "CIF" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "Audiocodecs" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "Videocodecs" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "C" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "SIP (UDP)" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "SIP (TCP)" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "SIP (TLS)" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "Einstellungen" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "In diesem Bereich legen Sie Ihre SIP-Adresse fest, wenn Sie kein SIP-Konto verwenden." - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "Ihr angezeigter Name (z. B. Heinz Müller):" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "Ihr Benutzername:" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "Sich ergebende SIP-Adresse:" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "Standard-Identität" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "Assistent" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "Hinzufügen" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "Bearbeiten" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "Entfernen" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "Proxy-Konten" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "Alle Passwörter löschen" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "Privatsphäre" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "Automatisch antworten, wenn ein Anruf eingeht" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "Verzögerung vor der Beantwortung (ms)" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "Automatische Antwort" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "SIP-Konten verwalten" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Klingelton:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "Spezielles ALSA-Gerät (optional):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Aufnahmegerät:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Gerät für Klingelton:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Wiedergabegerät:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Echounterdrückung ein" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Audio" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Video-Aufnahmegerät:" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "Bevorzugte Videoauflösung:" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "Methode zur Videoausgabe" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "Kameravorschau anzeigen" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "Videovoreinstellung:" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "Bevorzugte Videobildfrequenz:" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "0 bedeutet „unbegrenzt“" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "Video" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "Upload-Bandbreite (kbit/sec):" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "Download-Bandbreite (kbit/sec):" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "Adaptive Ratenregelung ein" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "Adaptive Ratenregelung ist eine Technik zur dynamischen Abschätzung der zur Verfügung stehenden Bandbreite während eines Anrufs." - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "Bandbreiten-Einstellungen" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "Multimedia-Einstellungen" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "Maximum Transmission Unit setzen:" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "DTMFs als SIP-Info senden" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "IPv6 erlauben" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "Übertragung" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "SIP/UDP Port" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "Zufällig" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "SIP/TCP Port" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "Audio RTP/UDP:" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "Fest" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "Video RTP/UDP:" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "Tunnel" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "DSCP-Felder" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "Netzwerkprotokoll und Ports" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "Direkte Verbindung ins Internet" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "Hinter NAT / Firewall (Gateway IP angeben)" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "Hinter NAT / Firewall (STUN verwenden)" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "Hinter NAT / Firewall (ICE verwenden)" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "Hinter NAT / Firewall (uPnP verwenden)" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "Öffentliche IP-Adresse:" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "STUN-Server:" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "NAT und Firewall" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "Verschlüsselungstyp der Medien" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "Lime für ausgehende Chatnachrichten verwenden" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "Medienverschlüsselung erzwingen" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "Verbindlich" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "Bevorzugt" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "Verschlüsselung" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "Netzwerkeinstellungen" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Freigeben" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Sperren" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "Audiocodecs" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "Videocodecs" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "Codecs" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "Sprache" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "Fortgeschrittene Einstellungen anzeigen" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "Detaillierung" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "Benutzeroberfläche" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "LDAP-Kontoeinrichtung" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "LDAP" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "Fertig" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "Linphone - Authentifikation erforderlich" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "Bitte das Passwort der Domäne eingeben" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "Einstellen..." - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "Bitte warten Sie während die Einstellungen vom Server abgerufen werden..." - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "SIP-Konto-Einrichtungsassistent" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "Willkommen!\nDieser Assistent hilft Ihnen dabei ein SIP-Konto einzurichten." - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "Willkommen zum Konto-Einrichtungsassistenten" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "Ein Konto bei linphone.org erstellen." - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "Ich habe bereits ein Konto bei linphone.org und möchte es jetzt benutzen." - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "Ich habe bereits ein SIP-Konto und möchte es jetzt benutzen." - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "Ich möchte eine URI zur Fernkonfiguration angeben" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "Konto-Einrichtungsassistent" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "Geben Sie Ihre Zugangsdaten ein" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "Benutzername*" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "Passwort*" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "Domäne*" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "Proxy" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "Konto einrichten (Schritt 1/1)" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "Geben Sie Ihren Benutzernamen bei linphone.org ein." - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "Geben Sie Ihren SIP-Benutzernamen ein (Schritt 1/1)" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "(*) erforderliche Felder" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "E-Mail: (*)" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "Benutzername: (*)" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "Passwort: (*)" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "Bestätigen Sie Ihr Passwort: (*)" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "Halte mich über linphone Aktualisierungen auf dem laufenden" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "Geben Sie Ihre Zugangsdaten ein (Schritt 1/2)" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "Ihr Konto wird erstellt, bitte warten." - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "Kontoerstellung läuft" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "Bitte bestätigen Sie Ihr Konto, indem Sie auf die Verknüpfung klicken, die wir Ihnen soeben per E-Mail geschickt haben.\nDanach gehen Sie hierher zurück und drücken auf „Vor“." - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "Bestätigung (Schritt 2/2)" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "Es wird überprüft, ob Ihr Konto gültig ist, bitte warten." - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "Kontogültigkeitsprüfung läuft" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "Fehler, Konto kann nicht bestätigt werden. Der Benutzername wird bereits\nverwendet oder der Server ist unerreichbar.\nBitte gehen Sie zurück und versuchen Sie es noch einmal." - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "Fehler" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Danke. Ihr Konto ist nun fertig eingerichtet und kann verwendet werden." - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "Linphone - SIP-Konto einrichten" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "Ihre SIP-Identität:" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "Sieht aus wie sip:@" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "sip:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "SIP-Proxy-Adresse:" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "Sieht aus wie sip:" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "Registrierungsdauer (sec):" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "Kontaktdetails (optional)" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "AVPF Standard RTCP Interval (sek):" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "Route (optional):" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "Übertragung" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "Registrieren" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "Anwesenheitsstatus veröffentlichen" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "Aktiviere AVPF" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "SIP-Konto einrichten" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "VoIP-Tunnel einrichten" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "Host" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "Port" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "Tunnel einrichten" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "Configure http proxy (optional)" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "Bitte warten" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "Bereit" - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "Einstellen" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "Verbindungsaufbau" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "Anruf kann nicht getätigt werden." - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "Die maximale Anzahl der gleichzeitigen Anrufe ist erreicht." - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "ruft Sie an" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr " und fragt nach automatischer Antwort." - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "Die Anrufparameter werden verändert..." - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "Verbunden." - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "Anruf abgebrochen" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "Anruf kann nicht gehalten werden" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "Aktueller Anruf wird gehalten..." - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "STUN-Ermittlung läuft..." - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "Lokale Kandidaten für ICE werden zusammengestellt..." - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "Angemeldet" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "Besetzt" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "Bald wieder da" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "Abwesend" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "Im Gespräch" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "Beim Essen" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "Nicht stören" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "Umgezogen" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "Ein anderer Nachrichtendienst wird benutzt" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "Abgemeldet" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "Ausstehend" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "Urlaub" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "Unbekannter Status" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "Die von Ihnen eingegebene SIP-Proxy-Adresse ist ungültig, sie muss mit „sip:“ gefolgt vom Hostnamen beginnen." - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "Die von Ihnen eingegebene SIP-Identität ist ungültig.\nSie sollte wie sip:benutzername@proxydomain aussehen, also z.B. sip:alice@beispiel.net" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "Telefonnummernziel wird gesucht..." - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "Diese Nummer kann nicht aufgelöst werden." - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "Anmeldung als %s fehlgeschlagen" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "Wird auf %s aktualisiert..." - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "Klingeln bei der Gegenseite." - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "Klingeln bei der Gegenseite..." - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "nicht kompatibel, prüfe Codecs oder Sicherheitseinstellungen..." - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "Anruf wird von %s entgegengenommen" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "Anruf fortgesetzt." - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "Inkompatibel, überprüfen Sie die Codecs oder die Sicherheitseinstellungen..." - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "Inkompatible Medienparameter." - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "Anruf wird fortgesetzt." - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "Anruf wird von der Gegenseite gehalten." - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "Anruf ist von der Gegenseite aktualisiert worden." - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "Anruf beendet." - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "Teilnehmer ist besetzt." - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "Teilnehmer zur Zeit nicht verfügbar." - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "Teilnehmer möchte nicht gestört werden." - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "Anruf abgewiesen" - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "Zeitüberschreitung bei der Anfrage" - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "Umgeleitet" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "Anruf fehlgeschlagen." - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "Registrierung auf %s erfolgreich." - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "Abmeldung von %s ist erfolgt." - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "Zeitüberschreitung bei der Antwort" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "Registrierung auf %s fehlgeschlagen: %s" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "Service nicht verfügbar, versuche erneut" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "Authentifizierungs-Token ist %s" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "Anrufparameter konnten nicht geändert werden: %s." - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "Anrufparameter wurden erfolgreich geändert." - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "Sie haben %i Anruf in Abwesenheit." -msgstr[1] "Sie haben %i Anrufe in Abwesenheit." - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "abgebrochen" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "abgeschlossen" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "verpasst" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "unbekannt" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "%s um %s\nVon: %s\nAn: %s\nStatus: %s\nDauer: %i Min. %i Sek.\n" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "Ausgehender Anruf" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "Kann %s nicht wiedergeben." - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" diff --git a/po/en@boldquot.header b/po/en@boldquot.header deleted file mode 100644 index fedb6a06d..000000000 --- a/po/en@boldquot.header +++ /dev/null @@ -1,25 +0,0 @@ -# All this catalog "translates" are quotation characters. -# The msgids must be ASCII and therefore cannot contain real quotation -# characters, only substitutes like grave accent (0x60), apostrophe (0x27) -# and double quote (0x22). These substitutes look strange; see -# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html -# -# This catalog translates grave accent (0x60) and apostrophe (0x27) to -# left single quotation mark (U+2018) and right single quotation mark (U+2019). -# It also translates pairs of apostrophe (0x27) to -# left single quotation mark (U+2018) and right single quotation mark (U+2019) -# and pairs of quotation mark (0x22) to -# left double quotation mark (U+201C) and right double quotation mark (U+201D). -# -# When output to an UTF-8 terminal, the quotation characters appear perfectly. -# When output to an ISO-8859-1 terminal, the single quotation marks are -# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to -# grave/acute accent (by libiconv), and the double quotation marks are -# transliterated to 0x22. -# When output to an ASCII terminal, the single quotation marks are -# transliterated to apostrophes, and the double quotation marks are -# transliterated to 0x22. -# -# This catalog furthermore displays the text between the quotation marks in -# bold face, assuming the VT100/XTerm escape sequences. -# diff --git a/po/en@quot.header b/po/en@quot.header deleted file mode 100644 index a9647fc35..000000000 --- a/po/en@quot.header +++ /dev/null @@ -1,22 +0,0 @@ -# All this catalog "translates" are quotation characters. -# The msgids must be ASCII and therefore cannot contain real quotation -# characters, only substitutes like grave accent (0x60), apostrophe (0x27) -# and double quote (0x22). These substitutes look strange; see -# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html -# -# This catalog translates grave accent (0x60) and apostrophe (0x27) to -# left single quotation mark (U+2018) and right single quotation mark (U+2019). -# It also translates pairs of apostrophe (0x27) to -# left single quotation mark (U+2018) and right single quotation mark (U+2019) -# and pairs of quotation mark (0x22) to -# left double quotation mark (U+201C) and right double quotation mark (U+201D). -# -# When output to an UTF-8 terminal, the quotation characters appear perfectly. -# When output to an ISO-8859-1 terminal, the single quotation marks are -# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to -# grave/acute accent (by libiconv), and the double quotation marks are -# transliterated to 0x22. -# When output to an ASCII terminal, the single quotation marks are -# transliterated to apostrophes, and the double quotation marks are -# transliterated to 0x22. -# diff --git a/po/es.po b/po/es.po deleted file mode 100644 index d166e8cb1..000000000 --- a/po/es.po +++ /dev/null @@ -1,2090 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -# Daniel S , 2016 -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: Spanish (http://www.transifex.com/belledonne-communications/linphone-gtk/language/es/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: es\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "Llamar a %s" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "Enviar mensaje a %s" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "Añadir %s a la lista de contactos" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "Llamadas recientes" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "Llamadas recientes (%i)" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "n/a" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "Abortado" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "Perdida" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "Rechazado" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "%i minuto" -msgstr[1] "%i minutos" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "%i segundo" -msgstr[1] "%i segundos" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "%sCalidad: %s\n%s⇥%s⇥" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "%s⇥%s" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "Conferencia" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "Yo" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "No se pudo encontrar el archivo pixmap: %s" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "Enviando..." - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "Mensaje no enviado" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "Copiar" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "registra a stdout cierta información de depuración durante la ejecución." - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "mostrar versión y salir" - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "ruta a un fichero donde escribir logs." - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "Iniciar linphone con el vídeo desactivado" - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "Iniciar sólo en la barra de tareas, no mostrar la interfaz principal." - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "dirección a la que llamar inmediatamente" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "Especifique un directorio de trabajo (debería ser la raíz de la instalación, ej: c:\\Archivos de Programa\\Linphone)" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "Fichero de configuración" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "Iniciar el asistente de audio" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "%s quiere añadirle a su lista de contactos.\nQuieres añadirle a tu lista de contactos y permitirle que vea su estado de presencia?\nSi contesta no, esta persona será bloqueada temporalmente." - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "Por favor, introduzca la contraseña para el usuario %s\n en el dominio %s:" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "Error en llamada" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "Llamada terminada" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "Llamada entrante" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "Contestar" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "Rechazar" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "Llamada en pausa" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "por %s" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "%s solicita iniciar vídeo. ¿Acepta?" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "Enlace a la Web" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "%s (Opción predeterminada)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "Somos transferidos a %s" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "No se ha encontrado una tarjeta de sonido en este equipo.\nNo será posible realizar o recibir llamadas de audio." - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "Un video-teléfono SIP gratuito" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "Hola\n" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "Añadir a la agenda" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "Buscar en el directorio %s" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "¡Contacto SIP no válido!" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "Añadir un contacto nuevo" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "Editar contacto '%s'" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "Eliminar contacto '%s'" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "Eliminar histórico de '%s'" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "Añadir nuevo contacto desde el directorio %s" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "Nombre" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "Frecuencia (Hz)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "Estado" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "Parámetros" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "Activado" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "Desactivado" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "Cuenta" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "Inglés" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "Francés" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "Sueco" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "Italiano" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "Español" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "Portugués de Brasil" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "Polaco" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "Alemán" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "Ruso" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "Japonés" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "Holandés" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "Húngaro" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "Checo" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "Chino" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "Chino Tradicional" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "Noruego" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "Hebreo" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "Serbio" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "Árabe" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "Turco" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "Deberá reiniciar linphone para aplicar la nueva selección de lenguaje" - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "Ninguno." - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "SRTP" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "DTLS" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "ZRTP" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "Una nueva versión está disponible en %s.\n¿Desea abrir el navegador para descargarla?" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "Ya está corriendo la última versión disponible." - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "Nombre, Apellidos" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "Error al comunicar con el servidor." - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "Conectando..." - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "Conectado" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "Recibiendo datos..." - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "Se encontró %i contacto" -msgstr[1] "Se encontraron %i contactos" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "" - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "Llamar a #%i" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "Transferir a llamada #%i con %s" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "Sin uso" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "ICE no activo" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "ICE ha fallado" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "ICE en progreso" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "Atravesando uno o más NATs" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "Directo" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "A través de un servidor de relay" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "uPnP no activado" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "uPnP en progreso" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "uPnp not disponible" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "uPnP en ejecución" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "uPnP ha fallado" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "Directo o a través del servidor" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "bajada: %f\nsubida: %f (kbit/s)" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "%.3f segundos" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "Colgar" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "Llamando..." - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "00:00:00" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "Llamada entrante" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "buena" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "media" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "mala" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "muy mala" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "demasiado mala" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "no disponible" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "Cifrada con SRTP" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "Cifrada con DTLS" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "Cifrada con ZRTP - [token de autenticación: %s]" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "Set sin verificar" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "Set verificado" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "En conferencia" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "En conversación" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "Llamada en pausa" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "Llamada finalizada." - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "Transfiriendo llamada" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "Transferido correctamente" - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "Transferencia fallida" - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "Reanudar" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "Pausar" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "Grabando en\n%s %s" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "(Pausada)" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "Por favor, introduzca los datos de inicio de sesión para %s" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "cargando desde %s" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "Descarga de la configuración remota desde %s fallida." - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "No se detectó voz" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "Demasiado bajo" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "Buena" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "Demasiado alto" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "¿Escuchaste los tres pitidos?" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "Preferencias de sonido no encontradas" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "No se pudo arrancar el control de sonido del sistema" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "Bienvenido!\nEste asistente le ayudará a configurar el audio para Linphone." - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "Dispositivo de captura:" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "Volumen grabado" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "No hay voz" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "Preferencias de audio del sistema" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "Dispositivo de reproducción:" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "Reproducir tres pitidos" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "Use el botón de grabar y diga unas palabras" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "Escucha tu grabación de voz" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "Grabar" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "Reproducir" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "Iniciar Linphone ahora" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "Asistente de sonido" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "Asistente de sonido" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "Calibración de ganancia de microfono" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "Calibración de volumen de altavoz" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "Grabar y reproducir" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "Finalizando" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "Sobre Linphone" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "(C) Belledonne Communications, 2010\n" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "Un vídeo-teléfono a través de Internet que usa el protocolo estándar SIP (rfc3261)" - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "fr: Simon Morlat\nen: Simon Morlat and Delphine Perreau\nit: Alberto Zanoni \nde: Jean-Jacques Sarton \nsv: Daniel Nylander \nes: Jesus Benitez \nja: YAMAGUCHI YOSHIYA \npt_BR: Rafael Caesar Lenzi \npl: Robert Nasiadek \ncs: Petr Pisar \nhu: anonymous\nhe: Eli Zaretskii \n" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "Buscar contactos en directorio" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "Añadir a mi lista" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "Buscar a alguien" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "Nombre del destinatario" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "Registro de llamadas" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "Borrar todos" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "Devolver llamada" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "Estadística de llamada" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "Códec de Audio" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "Códec de vídeo" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "Resolución de vídeo recivida" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "Resolución de vídeo enviada" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "Perfil RTP" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "Estadísticas de llamada e información" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "Enviar" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "Terminar conferencia" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "Especificando una URI remota de configuración" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "Esta ventana le permite fijar una dirección http o https para que la configuración sea cargada en el arranque.\nPor favor, introduzca o modifique la URI. Después de aceptar, Linphone se reiniciará automáticamente para cargar la configuración y la nueva cuenta." - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "Dirección SIP" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "Mostrar el estado de presencia de este contacto" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "Permitir que este contacto vea mi estado de presencia" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "Información de contacto" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "Configuración DSCP" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "SIP" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "Volumen del altavoz" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "Graba esta llamada a un fichero de audio" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "Vídeo" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "Silenciar" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "Transferir" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "En conversación" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "Duración" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "Calidad de la llamada" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "Configuración LDAP" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "Dirección del Servidor:" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "Método de autenticación:" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "Nombre de usuario:" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "Contraseña:" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "Usar conexión TLS" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "No disponible" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "Conexión" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "Buscar" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "Otros" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "ANONIMO" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "SIMPLE" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "DIGEST-MD5" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "NTLM" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Nombre de usuario" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Contraseña" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "Conexión a Internet" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "Iniciar sesión automáticamente" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "UserID" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "Datos de inicio de sesión" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "Bienvenido/a!" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "Canal de Fibra" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "Ventana de depuración de linphone" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "Ir al final" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "Por defecto" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "Borrar" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "_Opciones" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "Especificar URI de configuración" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "Siempre iniciar vídeo" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "Activar vista propia" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "Mostrar marcador" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "_Ayuda" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "Mostrar ventana de depuración" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "_Pagina_de_Inicio" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "Buscar_Actualizaciones" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "Asistente de configuración de cuenta" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "Dirección SIP o número de teléfono" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "Iniciar nueva llamada" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "Contactos" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "Buscar" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "Añadir contactos desde un directorio" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "Añadir contacto" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "Borrar registro de llamadas" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "Mi identidad actual:" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "Autoanswer está activado" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "anónimo" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "GSSAPI" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "tarjeta de sonido predeterminada" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "una tarjeta de sonido" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "cámara predeterminada" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "CIF" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "Códecs de Audio" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "Códecs de Vídeo" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "C" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "SIP (UDP)" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "SIP (TCP)" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "SIP (TLS)" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "Configuración" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "Esta sección define su dirección SIP cuando no utiliza una cuenta SIP" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "Su nombre a mostrar (x ej: Pepito Pérez):" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "Su nombre de usuario:" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "Su dirección SIP resultante:" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "Identidad predeterminada" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "Asistente" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "Añadir" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "Editar" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "Eliminar" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "Cuentas Proxy" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "Borrar todas las contraseñas" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "Privacidad" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "si está activo, responder a llamadas entrantes automáticamente" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "Retraso antes de contestar (ms)" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "Auto-answer" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "Gestionar cuentas SIP" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Tono de llamada:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "Dispositivo especial ALSA (opcional):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Dispositivo de captura:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Dispositivo de Ring:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Dispositivo de reproducción:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Activar cancelación de eco" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Audio" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Dispositivo de entrada de vídeo:" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "Resolución de vídeo preferida:" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "Dispositivo de salida de vídeo:" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "Mostrar vista previa de la cámara" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "Framerate de vídeo preferido:" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "0 significa \"ilimitado\"" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "Vídeo " - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "Velocidad límite de subida en Kbit/seg" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "Velocidad límite de descarga en Kbit/seg:" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "Activar control de frecuencia adaptativo" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "Control de frecuencia adaptativo es una técnica que estima dinámicamente el ancho de banda disponible durante la llamada." - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "Control de ancho de banda" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "Configuración multimedia" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "Fijar Unidad de Transmisión Máxima:" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "Enviar DTMFs como información SIP" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "Soportar IPv6" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "Transporte " - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "Puerto SIP/UDP" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "Aleatorio" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "Puerto SIP/TCP" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "Audio RTP/UDP:" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "Fijo" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "Vídeo RTP/UDP" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "Tunel" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "Campos DSCP" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "Protocolo de red y puertos" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "Conexión directa a Internet" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "Tras un NAT/Firewall (especificar la IP de la puerta de enlace)" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "Tras un NAT/Firewall (utilizar STUN para resolver)" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "Tras un NAT/Firewall (utilizar ICE)" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "Tras un NAT/Firewall (utilizar uPnP)" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "Dirección IP pública:" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "Servidor STUN" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "NAT y Firewall" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "Tipo de cifrado de medios" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "Es obligatorio el cifrado de medios" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "Configuración de red" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Activar" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Desactivar" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "Códecs de audio" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "Códecs de vídeo" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "Códecs" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "Idioma" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "Mostrar opciones avanzadas" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "Nivel" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "Interfaz de Usuario" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "Configuración de cuenta LDAP" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "LDAP" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "Hecho" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "Linphone - Autenticación necesaria" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "Por favor introduzca la contraseña del dominio" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "Configurando..." - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "Por favor, espere mientras se carga la configuración del servidor..." - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "Asistente de configuración de cuenta" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "¡Bienvenido/a !\nEste asistente le ayudará a utilizar una cuenta SIP para sus llamadas." - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "Bienvenido al asistente de configuración de cuenta" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "Crear una cuenta en linphone.org" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "Ya tengo una cuenta en linphone.org y quiero usarla" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "Ya tengo una cuenta SIP y quiero usarla" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "Quiero indicar una URI remota de configuración" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "Asistente de configuración de cuenta" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "Información de cuenta" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "Nombre de usuario*" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "Contraseña*" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "Dominio*" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "Proxy" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "Configurar una cuenta (paso 1/1)" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "Introduzca su nombre de usuario de linphone.org" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "Introduzca su nombre de usuario SIP (paso 1/1)" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "(*) Campos obligatorios" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "Email: (*)" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "Nombre de usuario: (*)" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "Contraseña: (*)" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "Confirme su contraseña: (*)" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "Informame de las actualizaciones de linphone" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "Introduzca la información de su cuenta (paso 1/2)" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "Su cuenta esta siendo creada, por favor espere." - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "Creando cuenta" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "Por favor confirme su cuenta haciendo click en el link que la hemos enviado a su email.\nLuego vuelva y presione el botón Siguiente." - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "Validación (paso 2/2)" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "Comprobando si su cuenta ha sido validada, por favor espere." - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "Validación de cuenta en progreso" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "Error, cuenta no validada, el nombre de usuario esta en uso o no se puede acceder al servidor.\nPor favor, vaya atrás y vuelva a intentarlo." - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "Error" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Gracias. Su cuenta está configurada y lista para su utilización." - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "Linphone - Configurar una cuenta SIP" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "Su identidad SIP" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "Del tipo sip:@" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "sip:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "Dirección del SIP Proxy" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "Del tipo sip:" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "Duración del registro (seg):" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "Ruta (opcional):" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "Transporte" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "Registrarse" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "Publicar información de presencia" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "Activar AVPF" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "Configurar una cuenta SIP" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "Configurar tunel VoIP" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "Puerto" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "Configurar tunel" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "Configurara el proxy http (opcional)" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "Espere por favor" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "Preparado" - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "Configurando" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "Contactando" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "No se pudo llamar" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "Disculpe, se ha alcanzado el máximo número de llamadas simultáneas" - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "le está llamando" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr "y ha solicitado auto respuesta." - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "Modificando parámetros de llamada…" - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "Conectado." - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "Llamada abortada" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "No se pudo pausar la llamada" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "Pausando la llamada actual..." - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "Búsqueda STUN en proceso…" - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "Recolección de candidatos ICE locales en progreso..." - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "Conectado" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "Ocupado" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "Vuelvo enseguida" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "Ausente" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "Al teléfono" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "A comer" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "No molestar" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "Fuera" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "Utilizando otro servicio de mensajería" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "Desconectado" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "Pendiente" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "Estado desconocido" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "La dirección del Proxy SIP que ha introducido no es válida, debe empezar con \"sip:\" seguido del hostname." - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "La identidad SIP que ha introducido no es válida.\nDebe ser del tipo sip:username@proxydomain, como por ejemplo sip:alice@example.net" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "Buscando el número de teléfono del destinatario…" - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "No se ha podido resolver este número." - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "No se pudo iniciar sesión como %s" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "Cargando desde %s" - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "El destinatario está sonando..." - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "El destinatario está sonando..." - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "Medios iniciales." - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "Llamada respondida por %s" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "Llamada reanudada." - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "Incompatible, compruebe la configuración de códecs o de seguridad..." - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "Parámetros de media incompatibles" - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "Nos han reanudado..." - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "Nos han pausado." - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "La llamada ha sido actualizada por el destinatario." - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "Llamada finalizada." - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "El usuario está ocupado." - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "El usuario no está disponible temporalmente." - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "El usuario no quiere que le molesten." - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "Llamada rechazada." - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "Petición caducada (timeout)" - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "Redigirida" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "La llamada ha fallado." - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "Se ha registrado con éxito en %s." - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "Cancelación de registro en %s completada." - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "timeout sin respuesta" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "El registro en %s ha fallado: %s." - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "Servicio no disponible, reintentando" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "El tóken de autenticación es%s" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "Parámetros de llamada no pudieron ser modificados: %s." - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "Parámetros de llamada modificados correctamente." - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "Tiene %i llamada perdida." -msgstr[1] "Tiene %i llamadas perdidas." - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "abortado" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "terminado" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "perdida" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "desconocido" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "%s a las %s\nDe: %s\nPara: %s\nEstado: %s\nDuración: %i mn %i sec\n" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "Llamada saliente" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "No se puede reproducir %s" - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" diff --git a/po/fi.po b/po/fi.po deleted file mode 100644 index 5f8ffbe18..000000000 --- a/po/fi.po +++ /dev/null @@ -1,2090 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -# Matti Koivunen , 2016 -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: Finnish (http://www.transifex.com/belledonne-communications/linphone-gtk/language/fi/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: fi\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "Soita %s:lle" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "Lähetä tekstiviesti %s:lle" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "Lisää %s yhtestietoihin" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "Viimeiset puhelut" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "Viimeiset puhelut (%i)" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "tyhjä" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "Kesketetty" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "Puuttuu" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "Estetty" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "%i minuuttia" -msgstr[1] "%i minuuttia" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "%i sekunttia" -msgstr[1] "%i sekunttia" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "%s\tLaatu: %s\n%s\t%s\t" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "%s\t%s" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "Kokous" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "Minä" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "Ei kyennyt lyötämään Pixmap kuvatiedostoa: %s" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "Lähetetään..." - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "Viesti ei lähetetty" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "Kopio" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "Kirjaudu 'stadardi viestin palautukseen' 'stdout' saadaksesi tietoja virheestä käytön aikana." - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "Näytä versio ja poistu." - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "polku tiedostolle johon loki kirjoitetaan." - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "Aloita linphone ilman videota." - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "Käynnistä vain tehtäväpalkki, älä pääkäyttöliittymää." - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "osoite mihin nyt soitetaan" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "Määritä työkansio (eli mihin asennus tehdään, kuten: c:\\Program Files\\Linphone)" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "Kokoonpano tiedosto" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "Käytä ääni avustajaa" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "Käytä omaa testiä ja poistu 0 jo valmis" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "%s haluaa lisätä sinut yhteystitohinsa.\nHaluatko hänen näkevän sinun läsnäolosi?\nJos ei, niin hänet lisätään hetkeksi mustalle listalle." - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "Anna salasana käyttäjänimelle %s\nmaasta %s:" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "Virhe puhelussa" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "Puhelu päättyi" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "Tuleva puhelu" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "Vastaa" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "Hylkää" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "Puhelu laitettu tauolle" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "%s toimesta" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "%s pyytää video kuvaa. Sallitaanko?" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "Internet linkki" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "Internet video puhelu" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "%s (Vakio)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "Olemme siirtyneet %s" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "Tähässä tietokeneessa ei ole havaittavissa ääni korttia.\nEt voi lähettää tai vastaanottaa äänellisiä puheluita." - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "Ilmainen SIP video puhelin." - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "Hei\n" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "Lisää osoitekirjaan" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "Etsi %s hakemistosta" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "Kelvoton sip yhtyestieto !" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "Lisää uusi yhteystieto" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "Muokkaa yhteystietoa '%s'" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "Poista yhteysto '%s'" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "Poista '%s'n keskustelu historia" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "Lisää uusi yhteystieto %s hakemistoon" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "Nimi" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "Laatutaso (Hz)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "Tila" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "IP Siirtonopeus (kbit/s)" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "Raja-arvot" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "Sallittu" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "Kielletty" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "Tili" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "eglaniksi" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "French" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "Swedish" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "Italian" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "Spanish" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "Brazilian Portugese" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "Polish" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "German" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "Russian" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "Japanese" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "Dutch" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "Hungarian" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "Czech" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "Chinese" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "Traditional Chinese" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "Norwegian" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "Hebrew" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "Serbian" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "Arabic" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "Turkish" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "Sinun tarvitsee uudelleen käynnistää linphone, että uudet kieliasetukset tulevat voimaan." - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "Ei mitään" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "SRTP 'realiaikainen salaus'" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "DTLS 'paketti kytketty salaus'" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "ZRTP 'tunnusteleva realiaikainen salaus'" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "Uudempi versio on saatavilla: %s\nHaluatko avata selaimen ja ladata sen? " - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "Käytät viimeisintä versiota." - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "Etunimi,Sukunimi" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "Virhe palvelimen yhteyden pidossa" - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "Yhdistää..." - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "Yhdistetty" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "Vastaanottaa tietoa..." - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "Lydetty %i yhteystietoa" -msgstr[1] "Lydetty %i yhteystietoa" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "Käyttäjätunnus on jo käytössä!" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "Käyttäjätunnuksen saatavuuden tarkistus epäonnistui. Yritä uudelleen myöhemmin. " - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "Puhelu #%i" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "Siirrä puhelu #%i %s kanssa" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "Ei ole käytössä" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "ICE 'vuorovaikutteinen yhteys' ei ole toiminnassa" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "ICE 'vuorovaikutteinen yhteys' epäonnistui" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "ICE 'vuorovaikutteinen yhteys' toiminnassa" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "Menee läpi yhden tai useamman NAT-ositemuutoksen" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "Suoraan" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "Läpi välityspalvelimen" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "uPnP 'laite tunnistus' ei ole toiminnassa" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "uPnP 'laite tunnistus' on toiminnassa" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "uPnP 'laite tunnistus' ei ole saatavilla" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "uPnP 'laite tunnistus' on käytössä" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "uPnP 'laite tunnistus' epäonnistui" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "Suoraan tai palvelimen kautta" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "lataa: %f\nlähettää: %f (kbit/s)" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "%ix%i @ %f fps" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "%.3f sekunttia" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "Katkaise puhelu" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "Soittaa..." - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "00:00:00" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "tuleva puhelu" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "hyvä" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "keskiverto" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "heikko" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "todella heikko" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "liian huono" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "saavuttamattomissa" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "Käytä SRTP salausta" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "Käytä DTLS salausta" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "Käytä ZRTP salausta - [todennustunnus: %s]" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "Aseta vahvistamattomaksi" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "Aseta vahvistetuksi" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "Kokouksessa" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "Puhuu puhelua" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "Puhelu laitettu tauolle" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "Puhelu loppu." - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "Siirto käynnissä" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "Siirto tehty." - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "Siirto epäonnistui." - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "Yritä uudelleen" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "Pysäytä" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "Nauhoita\n%s %s" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "(Pysäytetty)" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "Anna kirjautumistiedot %s" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "hae: %s" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "Etäsäätöjen lataus %s :stä epäonnistui." - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "Laitetta ei havaittu" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "Liian hiljainen" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "Hyvä" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "Liian kova ääninen" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "Kuulitko kolme piippausta ?" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "Toivottuja ääniasetuksia ei löytynyt" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "Ei voi käynnistää järjestelmän äänien hallintaa" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "Tervetuloa!\nTämä avustaja auttaa sinua Linphonen ääniasetuksissa" - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "Tallennus laite" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "Tallennuksen äänen voimakkuus" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "Äänetön" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "Järjestelmän toivotut ääni asetukset" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "Kaiutin laite" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "Anna kolme piippausta" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "Paina nauhoita nappulaa ja sano muutamia sanoja" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "Kuuntele nauhoittamasi puhe" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "Nauhoita" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "Toista" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "Käynnitetäänpä Linphone nyt" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "Ääni avustaja" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "Ääni avustaja" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "Mikrofooni tulon kalibrointi" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "Kaiuttimen kalibrointi" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "Nauhoita ja Toista" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "Lopeta" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "Tietoja Linphonesta" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "(C) Belledonne Communications, 2010\n" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "Internet video puhelin, joka kyttää SIP (rfc3261) protokollaa." - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "fr: Simon Morlat\nen: Simon Morlat and Delphine Perreau\nit: Alberto Zanoni \nde: Jean-Jacques Sarton \nsv: Daniel Nylander \nes: Jesus Benitez \nja: YAMAGUCHI YOSHIYA \npt_BR: Rafael Caesar Lenzi \npl: Robert Nasiadek \ncs: Petr Pisar \nhu: anonymous\nhe: Eli Zaretskii \nfi: Matti Koivunen\n" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "Etsi yhteystietoja hakemistosta" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "Lisää minun listaan" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "Etsi henkilöä" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "Soitettu" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "Soitetut" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "Tyhjennä kaikki" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "Soita takaisin" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "Soitto tilastot" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "Äänen codec 'pakkaus'" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "Videon codec 'pakkaus'" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "Äänen käyttämä IP kaistaleveys " - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "Ääni tiedon yhdistettävyys" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "Videon käyttämä IP kaistaleveys" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "Video tiedon yhdistettävyys" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "Kierto aika" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "Saatu videon tarkkuus" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "Lähetetty videon tarkkuus" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "RTP 'realiaikaisen videon' profiili" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "Puhelu tilastot ja tiedot" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "Lähetä" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "Päätä kokous" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "Määritetään etäsäätöjä, URI-osoite" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "Anna alapuolelle muokattu URI, eli http tai https. Kun olet painanut OK, Linphone uudelleen käynnistyy ja hakee tilin uudet säädöt." - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "SIP osoite" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "Näytä henkilön läsnäolo" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "Anna lupa tälle henkilölle nähdä läsnäoloni" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "Yhteystiedot" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "DSCP 'pakettien erittely' asetukset" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "SIP" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "Äänen RTP stream 'realiaikainen virta'" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "Videon RTP stream 'realiaikainen virta'" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "Aseta DSCP 'pakettien erittely' arvot (heksadesimaaleina)" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "Paina tästä asettaaksesi kaiuttimien äänen voimakkuuden" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "Nauhoita tämä puhelu äänitiedostoksi" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "Video" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "Mykkä" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "Siirto" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "Puhelussa" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "Pituus" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "Puhelun laadun luokitus" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "LDAP 'Käyttäjän tunnistus' asetukset" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "Palvelimen osoite:" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "Todennus menetelmä:" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "Käyttäjätunnus:" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "Salasana:" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "Käytä TLS 'lähetyksen salaus' yhteyttä" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "Ei vielä saatavilla" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "Yhteys" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "Käyttäjän tunnistus: yhdistä DN nimeen" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "Valtuutettu nimi" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "Realm 'hallittu alue'" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "SASL 'yksinkertainen tunnistus ja salaus'" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "Perus kohde:" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "Suodatin (%s nimelle)" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "Nimen tuntomerkit" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "SIP osoitteen tuntomerkki:" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "Tuntomerkkiä jonossa" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "Hae" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "Haun aikakatkaisu:" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "Tulosten yläraja:" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "Seuraa peitenimiä" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "Sekalaiset" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "ANONYYMI" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "YKSINKERTAINEN" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "DIGEST-MD5 'tiivistetty käyttäjän tunnistus '" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "NTLM 'Microsoft käyttäjän tunnistus'" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Käyttäjätunnus" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Salasana" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "Internet yhteys:" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "Automaattisesti kirjaudu sisään" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "Käyttäjän tiedot" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "Kirjautumistiedot" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "Tervetuloa!" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "Kuitu kanava" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "Linphone virheen korjaus ikkuna" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "Vieritä loppuun" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "Vakio" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "Poista" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "_Valinnat" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "Aseta URI säädöt" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "Aloita aina videon kanssa" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "Näytä omakuva" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "Näytä näppäimistö" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "_Apua" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "Näytä virheen korjaus ikkuna" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "_Kotisivu" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "Tarkista _Päivitykset" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "Käyttäjätili avustaja" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "SIP osoite tai puhelin numero" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "Aloita uusi puhelu" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "Yhteystiedot" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "Hae" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "Lisää yhteystiedot hakemistosta" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "Lisää yhteystieto" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "Tyhjennä puhelu historia" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "Minun nykyinen henkilllisyys" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "Automaattinen vastaaminen käytössä" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "anonyymi" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "GSSAPI 'tietoturva ohjelmointi käskypohja'" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "SASL 'yksinkertainen salaus'" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "vakio äänikortti" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "äänikortti" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "vakio kamera" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "CIF 'keskimääräinen kuvan tarkkuus'" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "Ääni pakkaukset 'codecs'" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "Video pakkaukset 'codecs'" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "C" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "SIP (UDP 'siirto ilman yhteyttä')" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "SIP (TCP 'luotettu siirto tavuttain')" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "SIP (TLS 'siirto SSL varmentimilla')" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "Asetukset" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "Tämä osio märittää sinun SIP osoitteen kun et käytä SIP tiliä" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "Sinun näyttö nimi (esim: Matti Meikäläinen):" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "Sinun käyttäjänimi:" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "Tuloksena sinun SIP osoitteesi on:" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "Vakio henkilöllisyys" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "Velho - automaattisäätö" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "Lisää" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "Muokkaa" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "Poista" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "Välityspalvelin tilit" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "Poista kaikki salasanat" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "Yksityisyys" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "Automaattinen vastaus kun puhelu on saapunut" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "Odota ennen vastaamista (ms)" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "Automaattinen vastaaja" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "Hallitse SIP tilejä" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Soittoääni:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "ALSA-'ääne parannus' erikoilaite (valinnainen):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Tallennus laite:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Soittoäänen laite:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Äänentoistolaite:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Käytä kaiun poistoa" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Ääni" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Videokuvan lähde:" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "Toivottu videon tarkkuus:" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "Videon ulostulo:" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "Näytä kameran esikatselu" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "Video esiasetus:" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "Toivottu videon kuvataajuus:" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "0 tarkoittaa \"rajoittamaton\"" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "Video" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "Lähetys nopeus raja Kbit/sec:" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "Lataus raja Kbit/sec:" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "Käytä mukautuvaa tason säätöä" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "Mukautuva tason säätö arvailee käytettävissä olevan kastaleveyden puheun aikana." - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "Kastaleveyden hallinta" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "Multimedia asetukset" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "Aseta suurin siirto yksikkö:" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "Lähetä DTMF:t SIP infona" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "Salli IPv6" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "Siirto" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "SIP/UDP portti" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "Satunnainen" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "SIP/TCP portti" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "Ääni RTP/UDP:" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "Korjattu" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "Video RTP/UDP:" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "Tunneli" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "DSCP kentät" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "Veskko protokolla ja portti" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "Suora yhteys internettiin " - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "NAT / Palomuurin takaa (määritä yhdyskäytävä IP)" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "NAT-osoitteenmuunnoksen / Palomuurin takaa (käytä STUN:nia)" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "NAT-osoitteenmuunnoksen / Palomuurin takaa (käytä ICE:tä)" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "NAT-osoitteenmuunnoksen / Palomuurin takaa (käytä uPnP:tä)" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "Julkinen IP osoite:" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "Stun-palvelin eli 'osoitteenmuunoksen takaisin haku'-palvelin:" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "NAT-osoitteenmuunos ja Palomuuri" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "Median salaus tyyppi" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "Käytä Lime:ä lähteviin viesteihin " - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "Median salaus on pakollinen" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "Salaus" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "Verkko asetukset:" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Käytössä" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Poissa käytöstä" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "Ääni codecs" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "Video codecs" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "Codecs" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "Kieli" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "Näytä edistyneet asetukset" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "Taso" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "Käyttöliittymä" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "LDAP Tili asetukset" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "LDAP" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "Tehty" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "Linhone - Tunnistautuminen vaaditaan" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "Anna domain/verkkotunnussen salasana" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "Säädetään..." - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "Odota, säätöjä noudetaan palvelimelta..." - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "SIP tilin säätö avustaja" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "Tervetuoa!\nTämä avustaja auttaa sinua käyttämään SIP tiliä puheluissasi. " - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "Tervetuloa tili asetusten avustajaan" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "Luo linphone.org tili" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "Minulla on jo linphone.org tili ja haluan kayttää sitä" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "Minulla on jo sip tilli ja haluan käyttää sitä" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "Haluan täsmentää etäsäätöjä; URI-osoite" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "Tili asetusten avustaja" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "Anna tili tietosi" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "Käyttäjätunnus*" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "Salasana*" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "Domain/verkkotunnus*" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "Välitysavelin" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "Muokkaa tiliäsi (osa 1/1)" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "Anna linphone.org käyttäjätunnus" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "Anna sip käyttäjätunnus (osa 1/1)" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "(*) Vaaditus kohdat" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "Sähköposti: (*)" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "Käyttäjätunnus: (*)" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "Salasana: (*)" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "Vahvista salasana: (*)" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "Ilmoita linphone päivityksistä" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "Anna tili tiedot (osa 1/2)" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "Sinun tiliäsi luodaan, pyydän odota." - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "Tilin luominen edistyy" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "Vahvista tilisi avaamala linkin, joka on juuri lähetetty sähköpostiisi.\nSitten palaa ja paina seuraava." - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "Vahvistus (osa 2/2)" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "Tarkistetaan että tilisi on vahvistettu, pyydän odota." - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "Tarkistetaan tilin vahvistusta " - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "Virhe, tili ei ole vahvistettu, käyttäjätunnus oli jo käytössä tai palvelin tavoittamattomissa.\nPyydän palaa ja yritä uudelleen." - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "Virhe" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Kiitos. Tilisi on muokattu ja valmis käyttöön." - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "Linphone - Muokkaa SIP tiliä" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "Sinun SIP henkilöllisyys:" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "Näyttää seuraavalta sip:@" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "sip:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "SIP välityspalvelin osoite:" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "Näyttää seuraavalta sip:" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "Rekisteröinnin kesto (sekunttia):" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "Yhteystiedot (valinnainen):" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "AVPF-'media siirto' tahdistusväli RTCP-'realiaikaisen tiedonsiirron' kanssa (sekunttia):" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "Reitti (valinnainen):" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "Siirto" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "Rekisteri" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "Julkaise läsnäolo tiedot" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "Käytä AVPF:ää" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "Muokkaa SIP tiliä" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "Muokkaa VoIP tunnelia" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "Host eli Verkon solmu" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "Portti" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "Muokkaa tunnelia" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "Muokkaa http välityspalinta (valinnainen)" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "Odota" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "Valmis" - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "Säädetään" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "Yhdistetään" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "Ei voinut soittaa" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "Olen pahoillani, suurin yhtäaikaisten puheluiden määrä on saavutettu" - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "on ottamassa yhteyttä sinuun" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr "ja pyytää automaattista vastausta." - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "Maukataan soiton raja-arvoja..." - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "Yhdistetty" - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "Puhelu keskeytetty" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "Ei voinut laittaa puhelua tauolle" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "Laitetaan tauolle nykyinen puhelu..." - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "Stun-'osoite haun' lukkiutuminen käynnissä..." - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "ICE paikallisia ehdokkaita kerätään..." - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "Verkossa" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "Kiireinen" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "Palaan pian" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "Poissa" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "Puhuu puhelua" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "Syömässä" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "Älä häiritse" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "Siirtynyt" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "Käyttää toista yhteys ohjelmaa" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "Verkossa" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "Odottaa" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "Lomalla" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "Tuntematon tila" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "Antamasi välityspalvelin osoite on kelvoton. Se täytyy alkaa \"sip:\" minkä jälkeen tulee host-verkkosolmuntunnus." - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "Antamasi sip tiedot ovat kelvoton.\nSen pitäisi näyttää sip:käyttäjätunnus@välityspalvelin, kuten sip:alice@esimerkki.net" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "Etsitään puhelinnumeron kohdetta..." - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "Ei voi käsittää tätä numeroa." - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "%s ei pystynyt kirjautumaan" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "%s on huilaamassa..." - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "vastapuoli pirisee" - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "vastapuoli pirisee..." - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "Aikainen media eli aloita puhelu ennen yhteyden lukittautumista" - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "Puheluun vastasi %s" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "Puhelu jaettiin." - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "Yhteensopimaton, tarkista kodekit tai suojaus asetukset..." - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "Yhteensopimattomat media raja-arvot." - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "Meidän puhelu on jaettu." - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "Meidän puhelu on laitettu taauolle toisen osapuolen taholta." - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "Vastapuoli on päivittänyt puhelun." - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "Puhelu keskeytetty." - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "Käyttäjä on kiireinen." - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "Käyttäjä hetkellisesti tavoittamattomissa." - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "Käyttäjä ei halua tulla häirityksi." - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "Soitto evätty." - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "Soitto yritys aikakatkaistiin." - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "Uudelleen ohjattu" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "Puhelu epäonnistui." - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "Rekitöröityminen %sn onnistui." - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "Rekisterin poisto %s:stä on tehty." - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "ei vastausta, aikakatkaistiin" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "Rekistöröityminen %sn epäonnistui: %s" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "Palvelin saavuttamattomissa, uudelleen yritetään" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "Todennus merkki on %s" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "Soiton raja-arvoja ei voitu muokata: %s." - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "Soiton raja-arvot ovat onnistuneesti muokattu." - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "Sinulla on %i vastaamaton puhelu." -msgstr[1] "Sinulla on %i vastaamatonta puhelua." - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "keskeytetty" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "valmis" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "vastaamaton" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "tuntematon" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "%s at %s\nMistä: %s\nMihin: %s\nTila: %s\nKasto: %i minuuttia %i sekunttia\n" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "Lähtevä puhelu" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "Ei voi toistaa %s." - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" diff --git a/po/fr.po b/po/fr.po deleted file mode 100644 index 0b8c6ae59..000000000 --- a/po/fr.po +++ /dev/null @@ -1,2094 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -# Belledonne Communications , 2015-2016 -# Gautier Pelloux , 2014 -# Gautier Pelloux , 2014 -# Gautier Pelloux , 2014-2016 -# Simon Morlat , 2001 -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:59+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: French (http://www.transifex.com/belledonne-communications/linphone-gtk/language/fr/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: fr\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "Appeler %s" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "Chatter avec %s" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "Ajouter %s à la liste de contacts" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "Appels récents" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "Appels récents (%i)" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "inconnu" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "Abandonné" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "Manqué" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "Refusé" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "%i minute" -msgstr[1] "%i minutes" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "%i seconde" -msgstr[1] "%i secondes" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "%s\tQualité: %s\n%s\t%s\t" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "%s\t%s" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "Conférence" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "Moi" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "Icone non trouvée: %s" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "Envoi en cours..." - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "Message non envoyé" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "Copier" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "affiche des informations de debogage" - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "Afficher la version et quitter." - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "chemin vers le fichier de logs." - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "Démarrer linphone avec la vidéo désactivée." - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "Démarre iconifié, sans interface principale." - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "adresse à appeler maintenant" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "Spécifie un répertoire de travail (qui devrait être le répertoire d'installation, par exemple c:\\Program Files\\Linphone)" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "Ficher de configuration" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "Démarre l'assistant audio" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "Exécuter le test local et retourner 0 en cas de succès" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "%s souhaite vous ajouter à sa liste de contact.\nSouhaitez vous l'ajouter à votre liste également et l'autoriser à voir votre information de présence ?\nSi vous répondez non, cette personne sera mise temporairement sur liste noire." - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "Entrez le mot de passe pour %s\n sur le domaine %s:" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "Erreur lors de l'appel" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "Appel terminé." - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "Appel entrant" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "Répondre" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "Refuser" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "Appel en pause" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "b>par %s" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "%s propose de démarrer la vidéo. Acceptez-vous ?" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "Lien site web" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "Appels vidéo via internet" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "%s (par défaut)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "Transfert vers %s" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "Aucune carte son n'a été détectée sur cet ordinateur.\nVous ne pourrez pas effectuer d'appels audio." - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "Un visiophone libre" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "Bonjour\n" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "Ajouter au carnet d'adresse" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "Rechercher dans l'annuaire de %s" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "Contact sip invalide !" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "Ajouter un nouveau contact" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "Editer le contact '%s'" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "Supprimer le contact '%s'" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "Supprimer l'historique de chat de '%s'" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "Ajouter un contact depuis l'annuaire %s" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "Nom" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "Fréquence (Hz)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "Etat" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "Débit IP (kbit/s)" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "Paramètres" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "Activé" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "Désactivé" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "Compte" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "Anglais" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "Français" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "Suédois" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "Italien" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "Espagnol" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "Portugais brésilien" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "Polonais" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "Allemand" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "Russe" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "日本語" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "Néérlandais" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "Hongrois" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "Tchèque" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "简体中文" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "Chinois traditionnel" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "Norvégien" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "Hébreu" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "Serbe" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "Arabe" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "Turc" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "La nouvelle selection de langue prendra effet au prochain démarrage de linphone." - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "Aucun" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "SRTP" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "DTLS" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "ZRTP" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "Une version plus récente est disponible sur %s.\nVoulez vous ouvrir le navigateur afin de pouvoir télécharger la dernière version ?" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "Vous utilisez la dernière version." - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "Prénom, Nom" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "Erreur de communication avec le serveur." - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "Connexion..." - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "Connecté" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "Reception des données" - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "%i contact trouvé." -msgstr[1] "%i contacts trouvés." - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "Ce nom d'utilisateur est déjà pris." - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "Impossible de vérifier la disponibilité de ce nom d'utilisateur. Veuillez réessayer plus tard." - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "Appel #%i" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "Transférer vers l'appel #%i avec %s" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "Non utilisé" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "ICE non activé" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "Erreur ICE" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "Négociation ICE en cours" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "Via un ou plusieurs NATs" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "En direct" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "Via un serveur relais" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "uPnP non activé" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "uPnP en cours" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "uPnP est indisponible" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "uPnP en cours d’exécution" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "uPnP a échoué." - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "Directe ou via un serveur" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "débit descendant : %f\ndébit ascendant : %f (kbits/s)" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "%ix%i @ %f fps" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "%.3f secondes" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "Raccrocher" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "Tentative d'appel..." - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "00:00:00" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "Appel entrant" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "bon" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "moyen" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "faible" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "très faible" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "nulle" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "indisponible" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "Sécurisé par SRTP" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "Sécurisé par DTLS" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "Sécurisé par ZRTP- [jeton: %s]" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "Marquer comme non vérifié" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "Marquer comme vérifié" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "En conférence" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "Appel en cours" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "Appel en attente" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "Appel terminé." - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "Transfert en cours" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "Transfert terminé" - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "Transfert échoué" - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "Reprendre" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "Pause" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "Enregistrement dans\n%s %s" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "(en attente)" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "Entrez vos identifiants pour %s" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "chargement depuis %s" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "Le chargement de la configuration depuis %s a échoué." - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "Voix non détectée" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "Trop bas" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "Bien" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "Trop bruyant" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "Avez-vous entendu trois bips ?" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "Préférences son non trouvé" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "Impossible de démarrer le contrôleur système du son" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "Bienvenue !\nCet assistant va vous aider à régler les paramètres audio de votre ordinateur pour une utilisation optimale avec Linphone." - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "Périphérique de capture" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "Volume enregistré" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "Silencieux" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "Préférences son système" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "Périphérique d'écoute" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "Joue trois bips" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "Appuyer sur le bouton enregistrer et dites quelques mots" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "Ecoutez votre voix enregistrée" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "Enregistrer" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "Jouer" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "Démarrons Linphone maintenant" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "Assistant audio" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "Assistant audio" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "Calibration du gain du microphone" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "Calibration du volume du haut parleur" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "Enregistrer et joue" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "En cours d’arrêt." - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "À propos de Linphone" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "(C) Belledonne Communications, 2010\n" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "Un visiophone pour l'internet, compatible SIP (rfc3261)" - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "fr: Simon Morlat\nen: Simon Morlat and Delphine Perreau\nit: Alberto Zanoni \nde: Jean-Jacques Sarton \nsv: Daniel Nylander \nes: Jesus Benitez \nja: YAMAGUCHI YOSHIYA \npt_BR: Rafael Caesar Lenzi \npl: Robert Nasiadek \ncs: Petr Pisar \nhu: anonymous\nhe: Eli Zaretskii \n" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "Rechercher dans l'annuaire" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "Ajouter à ma liste" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "Rechercher une personne" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "Nom du correspondant" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "Historique des appels" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "Tout vider" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "Rappeler" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "Statistiques de l'appel" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "Codec audio" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "Codec vidéo" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "Bande passante audio" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "Connectivité audio" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "Bande passante video" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "Connectivité video" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "Temps d'aller retour" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "Taille de video reçue" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "Taille de video envoyée" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "Profil RTP" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "Statistiques de l'appel et informations" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "Envoyer" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "Fin de conférence" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "Spécifier une URI de configuration" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "Cette boite de dialogue vous permet de spécifier une addresse http ou https où la configuration doit être téléchargée au démarrage.\nVeuillez entrer l'URI http(s) ci dessous. Après avoir validé, Linphone va redémarrer automatiquement pour charger et prendre en compte la nouvelle configuration." - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "Adresse SIP" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "Voir l'état de présence de ce contact" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "Autoriser ce contact à voir ma présence" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "Information sur le contact" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "Réglages DSCP" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "SIP" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "Flux RTP audio" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "Flux RTP vidéo" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "Indiquez les valeurs DSCP (en hexacdécimal)" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "Cliquer ici pour modifier le volume des haut-parleurs" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "Enregistrement de l'appel dans un fichier audio." - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "Vidéo" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "Couper le micro" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "Transférer" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "Appel en cours" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "Durée" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "Qualité de l'appel" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "Paramètres LDAP" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "Adresse du serveur:" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "Méthode d'authentification:" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "Nom d'utilisateur:" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "Mot de passe:" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "Utiliser TLS" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "Non disponible" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "Connexion" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "Assigner ND" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "Nom d'authentification" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "Realm" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "Object de base :" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "Filtre (nom avec %s) : " - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "Attribut nom :" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "Attribut pour l'addresse SIP:" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "Attributs à chercher:" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "Rechercher" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "Temps de recherche maximum:" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "Nombre de résultats maximum:" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "Suivre les alias" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "Divers" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "ANONYME" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "SIMPLE" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "DIGEST-MD5" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "NTLM" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Nom d'utilisateur" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Mot de passe" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "Connexion internet:" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "Me connecter automatiquement" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "ID utilisateur" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "Information de login" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "Bienvenue !" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "Fibre optique" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "Fenêtre de débogage de linphone" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "Défiler jusqu'à la fin" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "Par défaut" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "Supprimer" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "_Options" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "URI de configuration" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "Toujours activer la vidéo" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "Se voir" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "Afficher le pavé numérique" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "Importer des contacts depuis des vCards" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "Exporter les contacts en vCards" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "_Aide" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "Fenêtre de débogage" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "_Site web" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "_Mises à jour" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "Assistant de compte" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "Adresse SIP ou numéro" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "Démarrer un nouvel appel" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "Contacts" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "Rechercher" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "Ajouter un contact depuis l'annuaire" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "Ajouter un contact." - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "Effacer l'historique d'appel" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "Mon identité SIP :" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "Décrochage automatique activé" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "anonyme" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "GSSAPI" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "Carte son par défaut" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "une carte son" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "camera par défaut" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "CIF" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "Codecs audio" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "Codecs vidéo" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "C" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "SIP (UDP)" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "SIP (TCP)" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "SIP (TLS)" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "Réglages" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "Cette rubrique permet de définir son adresse SIP lorsqu'on ne possède pas de compte SIP" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "Votre nom d'affichage (ex: John Doe)" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "Votre nom d'utilisateur:" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "Votre adresse SIP:" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "Identité par défaut" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "Assistant" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "Ajouter" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "Editer" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "Enlever" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "Comptes SIP via des proxy" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "Effacer tous les mots de passe" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "Sécurité" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "Répondre automatiquement aux appels entrants" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "Temps d'attente avant réponse (ms)" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "Décrochage automatique" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "Gérer mes comptes SIP" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Sonnerie:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "Appareil ALSA spécifique (optionnel) :" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Périphérique de capture:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Périphérique de sonnerie:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Périphérique d'écoute:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Activer l'annulation d'écho" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Son" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Périphérique d'entrée vidéo" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "Résolution vidéo préférée :" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "Type de rendu video:" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "Afficher la vidéo" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "Profile vidéo:" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "Fréquence d'images préférée" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "Indiquez 0 pour ne pas mettre de limite" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "Video" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "Limite de débit montant en kbits/sec:" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "Limite de débit descendant en kbits/sec:" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "Activer le control de débit adaptatif." - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "Le control de débit adaptatif est une technique pour adapter la qualité de l'audio et de la video en fonction de la bande passante disponible, durant l'appel." - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "Gestion de la bande passante" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "Paramètres multimedia" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "Spécifier la Maximum Transmission Unit" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "Envoyer les digits en tant que SIP INFO" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "Utiliser IPv6" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "Transport" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "Port SIP / UDP" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "Aléatoire" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "Port SIP / TCP" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "Audio RTP / UDP :" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "Fixe" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "Vidéo RTP / UDP :" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "Tunnel" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "Champs DSCP" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "Protocoles réseaux et ports" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "Connexion directe à l'Internet" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "Derrière un pare-feu (spécifier la passerelle ci dessous)" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "Derrière un pare-feu (utiliser STUN)" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "Derrière un pare-feu (utiliser ICE)" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "Derrière un pare-feu (utiliser uPnP)" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "Adresse IP publique:" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "Serveur STUN:" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "Paramètres liés au pare-feu" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "Type d'encryption media" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "Utiliser Lime pour les messages de discussions sortants" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "Le chiffrement media est obligatoire" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "Obligatoire" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "Privilégié" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "Chiffrement" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "Paramètres réseau" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Activer" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Désactiver" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "Codecs audio" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "Codecs vidéo" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "Codecs" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "Langue" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "Montrer les réglages avancés" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "Niveau" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "Interface utilisateur" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "Configuration LDAP" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "LDAP" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "Fermer" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "Linphone - Authentification demandée" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "Entrez votre mot de passe pour le domaine" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "Configuration en cours" - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "Veuillez patenter un instant pendant le chargement de la configuration distante..." - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "Assistant de configuration de compte." - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "Bienvenue !\nCet assistant va vous aider à utiliser un compte SIP pour vos appels." - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "Bienvenue dans l'assistant de configuration de compte." - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "Créer un compte sur linphone.org" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "J'ai déjà un compte linphone.org et je souhaite l'utiliser" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "J'ai déjà un compte Sip et je souhaite l'utiliser" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "Je veux spécifier une URI de configuration" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "Assistant de configuration de compte." - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "Entrez vos paramètres de compte" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "Nom d'utilisateur*" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "Mot de passe*" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "Domaine*" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "Proxy" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "Configurez votre compte (étape 1/1)" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "Entrez votre identifiant linphone.org" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "Entrez votre identifiant sip (étape 1/1)" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "(*) Champs requis" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "Email : (*)" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "Nom d'utilisateur: (*)" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "Mot de passe: (*)" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "Confirmez votre mot de passe: (*)" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "Me tenir informé des mises à jour de Linphone " - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "Entrez les informations concernant votre compte (étape 1/2)" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "Votre compte est en cours de création. Veuillez patienter." - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "Création du compte en cours" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "Merci de valider votre compte en cliquant sur le lien que nous avons envoyé par email.\nPuis appuyez sur suivant." - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "Validation (étape 2/2)" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "Vérification que le compte a été validé. Veuillez patienter." - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "Vérification de la validité du compte en cours" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "Erreur, le compte n'est pas validé, l'identifiant est déjà utilisé ou le serveur n'est pas accessible.\nMerci d'essayer à nouveau." - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "Erreur" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Merci. Votre compte est maintenant configuré et prêt à être utilisé." - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "Linphone - Configurer un compte SIP" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "Votre identité SIP :" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "De la forme sip:@" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "sip:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "Adresse du proxy SIP:" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "De la forme sip:" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "Période d'enregistrement (secondes):" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "Paramètres de contact (optionnel):" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "Intervalle standard RTCP AVPF (sec) :" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "Route (optionnel):" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "Transport" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "S'enregistrer" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "Publier la présence" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "Activer AVPF" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "Configurer un compte SIP" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "Configuer le mode tunnel" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "Hôte" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "Port" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "Configuration du tunnel" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "Configuration d'un proxy http (optionel)" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "En attente" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "Prêt." - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "Configuration en cours" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "Appel de" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "Echec de l'appel" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "Désolé, le nombre maximum d'appels simultanés est atteint." - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "vous appelle" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr "et sollicite un décrochage automatique." - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "Modifications des paramètres d'appels..." - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "En ligne." - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "Appel abandonné" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "La mise en attente a échoué" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "Mise en attente de l'appel..." - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "Découverte STUN en cours" - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "Collection des candidats locaux ICE en cours..." - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "Disponible" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "Occupé" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "De retour" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "Absent" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "Au téléphone" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "A table" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "Ne pas déranger" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "Parti" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "Utilisation d'un autre service de messagerie" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "Non connecté" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "En attente" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "En congé" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "Status inconnu" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "L'adresse SIP du proxy est invalide. Elle doit commencer par \"sip:\" suivie par un nom de domaine." - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "L'identité SIP que vous avez fourni est invalide.\nElle doit être de la forme sip:utilisateur@domaine, comme par exemple sip:alice@example.net" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "Recherche de la destination du numéro de téléphone..." - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "La destination n'a pu être trouvée." - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "Echec de la connexion en tant que %s" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "Rafraichissement de %s..." - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "Sonnerie distante." - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "Sonnerie distante..." - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "Prise d'appel anticipée." - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "Appel répondu par %s" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "Appel repris." - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "Incompatible, vérfiez les codecs ou les paramètres de sécurité..." - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "Paramètres media incompatibles." - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "Appel repris." - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "L'appel a été mis en attente." - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "L'appel est modifié par la partie distante." - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "Appel terminé." - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "Occupé..." - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "L'usager est temporairement indisponible." - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "L'usager ne souhaite pas être dérangé" - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "Appel décliné." - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "Délai d'attente de la requête dépassé." - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "Redirection" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "L'appel a échoué." - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "Enregistrement sur %s effectué." - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "Désenregistrement sur %s effectué." - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "Pas de réponse" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "Echec de l'enregistrement sur %s: %s" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "Service indisponible, nouvelle tentative" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "Le jeton d'authentification est %s" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "Les paramètres d'appel n'ont pas pu être modifiés : %s." - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "Les paramètres d'appel ont été modifiés avec succès." - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "Vous avez manqué %i appel" -msgstr[1] "Vous avez manqué %i appels" - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "interrompu" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "terminé" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "manqué" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "inconnu" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "%s à %s\nDe : %s\nVers : %s\nStatus : %s\nDurée : %i min %i sec\n" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "Appel sortant" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "Impossible de jouer %s." - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "Capture d'écran" diff --git a/po/he.po b/po/he.po deleted file mode 100644 index bb53d7e06..000000000 --- a/po/he.po +++ /dev/null @@ -1,2094 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -# Eli Zaretskii , 2012 -# Gautier Pelloux , 2015 -# GenghisKhan , 2014 -# GenghisKhan , 2014,2016 -# GenghisKhan , 2012-2013 -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: Hebrew (http://www.transifex.com/belledonne-communications/linphone-gtk/language/he/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: he\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "התקשר %s" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "שלח טקסט אל %s" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "הוסף את %s לרשימת הקשר שלך" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "שיחות אחרונות" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "שיחות אחרונות (%i)" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "לא זמין (n/a)" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "ננטשה" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "הוחמצה" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "נדחתה" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "דקה %i" -msgstr[1] "%i דקות" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "שניה %i" -msgstr[1] "%i שניות" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "%s\tאיכות: %s\n%s\t%s\t" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "ועידה" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "אני" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "לא ניתן למצוא קובץ ‫pixmap: ‫%s" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "כעת שולח..." - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "הודעה לא נשלחה" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "העתק" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "" - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "" - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "נתיב לקובץ שברצונך לרשום אליו את הרשומות." - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "התחל את לינפון עם וידאו מנוטרל." - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "" - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "קובץ תצורה" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "" - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "אנא הזן סיסמה עבור משתמש %s\nבמתחם %s:" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "שגיאת קריאה" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "שיחה הסתיימה" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "קריאה נכנסת" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "לענות" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "לדחות" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "שיחה הושהתה" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "על ידי %s" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "‏%s רוצה להתחיל וידאו. האם אתה מסכים ?" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "קישור אתר רשת" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "וידאופון אינטרנטי" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "‫%s (ברירת מחדל)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "אנחנו מועברים אל %s" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "לא אותרו כרטיסי קול במחשב זה.\nלא תהיה ביכולתך לשלוח או לקבל שיחות אודיו." - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "וידאופון SIP חופשי" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "שלום\n" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "הוסף אל ספר כתובות" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "חיפוש במדור %s" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "כתובת sip לא תקפה !" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "הוסף איש קשר חדש" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "ערוך איש קשר '%s'" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "מחק איש קשר '%s'" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "מחק היסטוריית שיחה של '%s'" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "הוסף איש קשר חדש מן מדור %s" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "שם" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "שיעור (הרץ)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "מצב" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "פרמטרים" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "מופעל" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "לא מופעל" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "חשבון" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "English" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "Français" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "Svenska" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "Italiano" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "Español" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "português brasileiro" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "Polski" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "Deutsch" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "Русский" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "日本語" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "Nederlands" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "Magyar" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "Česky" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "中文" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "繁體字" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "norsk" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "עברית" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "српски srpski" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "עליך לאתחל את לינפון כדי שהשפה החדשה תיכנס לתוקף." - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "ללא" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "גרסא מאוחרת יותר זמינה מן %s.\nהאם ברצונך לפתוח דפדפן בכדי להורידה ?" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "ברשותך הגרסא האחרונה של לינפון." - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "שם פרטי , שם משפחה" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "שגיאה בהתקשרות עם שרת." - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "מתחבר כעת..." - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "מקושר" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "מאחזר כעת מידע..." - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "נמצא איש קשר %i" -msgstr[1] "נמצאו %i אנשי קשר" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "שם משתמש כבר מצוי בשימוש!" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "" - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "שיחה מס׳ %i" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "העברה אל שיחה מס׳ %i עם %s" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "לא בשימוש" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "‏ICE לא מופעלת" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "‏ICE נכשלה" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "‏ICE מצויה כעת בעיצומה" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "עובר דרך NAT אחד או יותר" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "ישיר" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "דרך שרת ממסר" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "‏uPnP לא מופעלת" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "‏uPnP מצויה כעת בעיצומה" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "‏uPnp לא זמינה" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "‏uPnP מורצת כעת" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "‏uPnP נכשלה" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "ישיר או דרך שרת" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "הורדה: %f\nהעלאה: %f (קי״ב/שנ׳)" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "%.3f שניות" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "נתק" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "מתקשר כעת..." - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "קריאה נכנסת" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "טובה" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "ממוצעת" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "דלה" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "דלה מאוד" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "גרועה מדי" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "לא זמינה" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "מאובטחת על ידי SRTP" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "מאובטח על ידי DTLS" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "מאובטחת על ידי ZRTP - [אות אימות: %s]" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "הגדר כלא מאומתת" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "הגדר כמאומתת" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "בשיחת ועידה" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "בשיחה כעת" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "שיחה מושהית" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "שיחה הסתיימה." - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "העברה מצויה כעת בעיצומה" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "העברה הסתיימה." - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "העברה נכשלה." - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "חזור" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "השהה" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "מקליט אל תוך\n%s %s" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "(מושהה)" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "נא להזין מידע התחברות עבור %s" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "" - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "נמוך מדי" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "טוב" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "חזק מדי" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "האם שמעת שלושה צפצופים ?" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "" - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "התקן לכידה" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "אין קול" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "התקן השמעה" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "נגן שלושה צפצופים" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "הקלט" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "נגן" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "הבא נתחיל את Linphone עכשיו" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "מסיים כעת" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "אודות Linphone" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "וידאופון אינטרנטי באמצעות תקן הפרוטוקול SIP (‫rfc3261)." - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "חיפוש אנשי קשר בתוך מדור" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "הוסף אל הרשימה שלי" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "חיפוש אחר מישהו" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "שם מקבל" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "היסטוריית שיחות" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "טיהור מוחלט" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "חיוג חוזר" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "סטטיסטיקות שיחה" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "קודק של אודיו" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "קודק של וידאו" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "ניצול רוחב פס IP אודיו" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "קישוריות מדיום אודיו" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "ניצול רוחב פס IP וידאו" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "קישוריות מדיום וידאו" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "זמן הלוך ושוב" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "פרופיל RTP" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "סטטיסטיקות ומידע שיחה" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "שלח" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "סיים ועידה" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "" - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "כתובת ‫SIP" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "הצג את מצב נוכחותו של איש קשר זה" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "הרשה לאיש קשר זה לראות את מצב הנוכחות שלי" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "מידע איש קשר" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "אפשרויות DSCP" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "זרם RTP אודיו" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "זרם RTP וידאו" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "קבע ערכי DSCP (בהקסדצימלי)" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "הקלט את שיחה זו אל קובץ אודיו" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "וידאו" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "השתק" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "העבר" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "בשיחה כעת" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "משך זמן" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "אומדן איכות שיחה" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "הגדרות LDAP" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "כתובת שרת:" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "שם משתמש:" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "סיסמה:" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "חיבור" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "חיפוש" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "שונות" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "שם משתמש" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "סיסמה" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "חיבור אינטרנט:" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "חבר אותי אוטומטית" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "מזהה משתמש" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "מידע התחברות" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "ברוכים הבאים!" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "‫ADSL" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "ערוץ סיב" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "חלון ניפוי שגיאות ‫Linphone" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "גלול אוטומטית לסוף" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "ברירת מחדל" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "מחק" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "_אפשרויות" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "התחל תמיד וידאו" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "אפשר ראות-עצמית" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "הצג לוח חיוג" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "_עזרה" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "הצג חלון ניפוי שגיאות" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "_עמוד הבית" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "בדיקת _עדכונים" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "אשף חשבון" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "כתובת SIP או מספר טלפון" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "התחל שיחה חדשה" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "אנשי קשר" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "חיפוש" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "הוסף אנשי קשר מן מדור" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "הוסף איש קשר" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "טהר היסטוריית שיחות" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "זהותי הנוכחית:" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "מענה אוטומטי הינו מאופשר" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "אנונימי" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "כרטיס קול משתמט" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "כרטיס קול" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "מצלמה משתמטת" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "קודקים של אודיו" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "קודקים של וידאו" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "‏SIP ‏(UDP)" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "‏SIP ‏(TCP)" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "‏SIP ‏(TLS)" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "הגדרות" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "חלק זה מגדיר את כתובת ה־SIP כאשר אינך עושה שימוש בחשבון SIP" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "שם התצוגה שלך (למשל: יורם יהודה):" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "שם המשתמש שלך:" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "כתובת SIP נובעת:" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "זהות משתמטת" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "אשף" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "הוסף" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "ערוך" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "הסר" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "חשבונות Proxy" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "מחק סיסמאות" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "פרטיות" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "מענה-אוטומטי" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "ניהול חשבונות ‫SIP" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "צליל צלצול:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "התקן ALSA מיוחד (רשות):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "התקן לכידה:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "התקן צלצול:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "התקן פס קול:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "אפשר ביטול הד" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "אודיו" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "התקן קלט וידאו:" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "0 מסמל \"בלי הגבלה\"" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "וידאו" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "מגבלת מהירות העלאה בקי״ב/שנ׳:" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "מגבלת מהירות הורדה בקי״ב/שנ׳:" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "אפשר בקרת קצב מסתגלת" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "בקרת קצב מסתגלת הינה טכניקה להשערה דינמית של רוחב הפס הזמין במהלך שיחה." - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "בקרת רוחב פס" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "הגדרות מולטימדיה" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "הגדר יחידת תמסורת מרבית:" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "שלח טזמ״תים (DTMFs) כמידע SIP" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "התר IPv6" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "טרנספורט" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "פורט SIP/UDP" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "אקראי" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "פורט SIP/TCP" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "אודיו RTP/UDP:" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "מקובע" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "וידאו RTP/UDP:" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "מינהור" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "שדות DSCP" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "פרוטוקולי רשת תקשורת ופורטים" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "חיבור ישיר אל האינטרנט" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "מאחורי NAT / חומת אש (בעזרת STUN לפתירה)" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "מאחורי NAT / חומת אש (בעזרת ICE)" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "מאחורי NAT / חומת אש (בעזרת uPnP)" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "כתובת IP פומבית:" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "שרת STUN:" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "‫NAT וחומת אש" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "סוג הצפנת מדיה" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "הצפנת מדיה הינה מנדטורית" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "הגדרות רשת תקשורת" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "אפשר" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "נטרל" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "קודקים" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "שפה" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "הצג הגדרות מתקדמות" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "רמה" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "ממשק משתמש" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "הבניית חשבון LDAP" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "סיום" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "‫Linphone - נדרש אימות" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "נא להזין את סיסמת המתחם" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "כעת מגדיר..." - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "ברוך בואך אל אשף הגדרת החשבון" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "צור חשבון אצל linphone.org" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "כבר קיים חשבון linphone.org ברשותי וברצוני לעשות בו שימוש" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "כבר קיים חשבון sip ברשותי וברצוני לעשות בו שימוש" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "אשף הגדרת חשבון" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "שם משתמש*" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "סיסמה*" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "מתחם*" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "פרוקסי" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "הגדרת חשבונך (צעד 1/1)" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "הזן את שם משתמשך אצל linphone.org" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "הזנת שם משתמש sip (צעד 1/1)" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "(*) שדות חובה" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "דוא״ל: (*)" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "שם משתמש: (*)" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "סיסמה: (*)" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "אימות סיסמתך: (*)" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "הזנת מידע חשבון (צעד 1/2)" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "נא לאמת את חשבונך באמצעות הקלקה על הקישור ששלחנו לך עתה באמצעות דוא״ל.\nאחרי כן נא לחזור לכאן וללחוץ על הלחצן 'קדימה'." - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "אימות (צעד 2/2)" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "שגיאה, חשבון לא אומת, שם משתמש כבר בשימוש או שרת לא ניתן להשגה.\nנא לחזור ולנסות שוב." - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "שגיאה" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "תודה לך. חשבונך מוגדר ומוכן לשימוש כעת." - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "‫Linphone - הגדרת חשבון ‫SIP" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "זהות ה־SIP שלך:" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "נראה כמו ‪sip:@" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "כתובת SIP Proxy:" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "נראה כמו ‪sip:" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "משך רישום (בשניות):" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "ניתוב (רשות):" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "טרנספורט" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "רישום" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "פרסם מידע נוכחות" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "אפשר AVPF" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "הגדרת חשבון ‫SIP" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "הגדר תיעול VoIP" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "מארח" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "פורט" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "הגדר מינהור" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "הגדר http proxy (רשות)" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "נא להמתין" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "מוכן" - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "תצורה" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "מתקשר כעת" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "לא ניתן להתקשר" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "הגענו אל המספר המרבי של שיחות מקבילות, עמך הסליחה" - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "מתקשר/ת אליך" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr " ומבקש/ת מענה אוטומטי." - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "מתאים כעת פרמטרים של שיחה..." - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "מקושר." - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "קריאה בוטלה" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "לא ניתן להשהות את השיחה" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "משהה כעת שיחה נוכחית..." - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "בדיקת STUN מצויה כעת בעיצומה..." - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "צבירת מועמדים מקומיים של ICE מצויה כעת בעיצומה..." - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "מקוון" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "עסוק" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "כבר אשוב" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "נעדר" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "בטלפון" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "בארוחת צהריים" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "נא לא להפריע" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "עברתי דירה" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "אני עושה כעת שימוש בשירות מסרים אחר" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "לא מקוון" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "בהמתנה" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "חופשה" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "מצב לא ידוע" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "כתובת sip proxy שהזנת הינה שגויה, זו צריכה להתחיל עם‭\"sip:\" ‬ לאחר שם מארח." - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "זהות sip שהוזנה הינה שגויה.\nזו צריכה להיראות כמו sip:username@proxydomain, למשל sip:alice@example.net" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "מחפש כעת עבור יעד מספר טלפון..." - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "לא ניתן לפתור את מספר זה." - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "לא ניתן להתחבר בזהות %s" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "" - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "צלצול מרוחק." - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "צלצול מרוחק..." - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "מדיה מוקדמת." - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "קריאה חודשה." - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "חוסר תאימות, בדוק קודקים או הגדרות אבטחה..." - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "פרמטריי מדיה חסרי תואמים." - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "חזרנו." - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "אנו מושהים על ידי צד אחר." - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "שיחה עודכנה מרחוק." - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "קריאה הסתיימה." - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "משתמש עסוק כעת." - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "משתמש לא זמין זמנית." - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "משתמש לא מעוניין שיפריעו לו." - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "קריאה סורבה." - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "" - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "מכוון מחדש" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "קריאה נכשלה." - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "רישום אצל %s הושלם בהצלחה." - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "אי רישום אצל %s סוים." - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "אין היענות תוך זמן מוגדר" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "רישום אצל %s נכשל: %s" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "אות האימות הינה %s" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "" - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "" - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "החמצת שיחה %i." -msgstr[1] "החמצת %i שיחות." - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "" - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" diff --git a/po/hu.po b/po/hu.po deleted file mode 100644 index bee6d8fdf..000000000 --- a/po/hu.po +++ /dev/null @@ -1,2090 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -# Free Bill , 2015 -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: Hungarian (http://www.transifex.com/belledonne-communications/linphone-gtk/language/hu/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: hu\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "%s hívása" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "Szöveg küldése a következőnek: %s" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "Legutóbbi hívások" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "-" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "Megszakítva" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "Nem fogadott" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "Elutasítva" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "%i perc" -msgstr[1] "%i perc" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "%i másodperc" -msgstr[1] "%i másodperc" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "%s\tMinőség: %s\n%s\t%s\t" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "%s\t%s" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "Konferencia" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "én" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "Nemtalálható a pixmap fájl: %s" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "" - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "Futás közben némi hibakeresési információ az stdout-ra naplózása." - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "" - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "fájl elérési útja, melybe a naplók kerülnek." - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "Linphone indítása, videó kikpacsolva. " - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "Csak a tálcaikon indítása, ne mutassa a fő ablakot." - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "Cím azonnali híváshoz" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "Adjon meg egy munkakönyvtárat (ennek az installációs könyvtárnak kéne lennie, pl. C:\\Program Files\\Linphone)" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "" - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "Hiba a hívás közben" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "Hívás vége" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "Beérkező hívás" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "Hívás fogadása" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "Elutasítás" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "Hívás várakoztatva" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "a következő által: %s" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "%s szerené elidítani a videót. Elfogadja?" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "Internetes oldal" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "%s (Alapértelmezett)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "Át vagyunk irányítva ide: %s" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "Hangkártya nincs érzékelve ezen a számítógépen.\nNem fog tudni hang hívásokat küldeni vagy fogadni." - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "Egy ingyenes SIP video-telefon" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "Hozzáadás címjegyzékhez" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "Keresés ebben a könyvtárban: %s" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "Érvénytelen sip partner !" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "Kapcsolatinformációk szerkesztése: '%s'" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "'%s' partner törlése" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "Új partner hozzáadása ebből a könyvtárból: %s" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "Név" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "Érték (Hz)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "Állapot" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "Paraméterek" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "Engedélyezve" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "Tiltva" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "Hozzáférés" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "angol" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "francia" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "svéd" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "olasz" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "spanyol" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "brazil-portugál" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "lengyel" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "német" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "orosz" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "japán" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "holland" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "magyar" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "cseh" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "egyszerúsített kínai" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "tradícionális kínai" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "norvég" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "héber" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "szerb" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "arab" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "török" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "Újra kell indítania a linphone-t, hogy az új nyelv kiválasztása érvényre jusson. " - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "Nincs" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "SRTP" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "ZRTP" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "Elérhető egy újabb verzió a következőn: %s.\nSzeretné, hogy a letöltéshez egy új böngésző ablak nyíljon?" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "Ön a legfrissebb verziót használja." - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "Utónév, Családnév" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "Hiba a kiszolgálóval történő kommunikáció során." - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "Kapcsolódás..." - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "Kapcsolódva" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "Adatok fogadása..." - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "" -msgstr[1] "" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "" - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "Hívás #%i" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "Átirányítás #%i híváshoz ezzel: %s " - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "Nem használt" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "ICE nincs aktiválva" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "ICE nem sikerült" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "ICE folyamatban" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "Átmegy egy vagy több NAT-on" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "Közvetlen" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "Közvetítő kiszolgálón keresztül" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "uPnP nincs aktiválva" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "uPnP folyamatban" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "uPnP nem elérhető" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "uPnP fut" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "uPnP nem sikerült" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "közvetlen vagy kiszolgálón keresztül" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "letöltés: %f\nfeltöltés: %f (kbit/mp)" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "%.3f másodperc" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "Befejezés" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "Hívás folyamatban..." - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "00:00:00" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "Beérkező hívás" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "jó" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "közepes" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "gyenge" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "nagyon gyenge" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "rossz" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "nem elérhető" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "SRTP-vel titkosítva" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "ZRTP-vel titkosítva - [hitelesítési jel: %s]" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "Beállítás ellenőrizetlenként" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "Beállítás ellenőrzöttként" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "Konferencián" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "vonalban" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "Várakoztatott hívás" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "Hívás vége." - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "Átvitel folyamatban" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "Átvitel befejezve." - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "Az átvitel sikertelen." - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "Visszatérés" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "Várakoztatás" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "Felvétel a következőbe\n%s %s" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "(Várakoztatva)" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "Kérem, adja meg a bejelentkezési információt %s -hoz" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "" - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "Jó" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "" - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "Befejezés" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "Internetes videó telefon, mely a szabványos SIP (rfc3261) protokolt használja." - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "Partnerek keresése könyvtárban" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "Hozzáadása a listámhoz" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "Keres valakit" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "Hívott neve" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "Híváselőzmények" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "Mind törlése" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "Visszahívás" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "Hívási statisztika" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "Audió kódek" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "Videó kódek" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "Audió IP sávszélesség használat" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "Audió média kapcsolat" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "Videó IP sávszélesség használat" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "Videó média kapcsolat" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "Körbeérés ideje" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "Hívási statisztika és információ" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "Küld" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "Konferencia vége" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "" - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "SIP cím" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "A partner jelenlétének mutatása" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "Megengedem ennek a partnernek, hogy lássa a jelenlétemet" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "Partner információ" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "SIP" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "Audió RTP folyam" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "Videó RTP folyam" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "DSCP értékek beállítása (hexadecimális)" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "Beszélgetés felvétele hangfájlba" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "Videó" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "Elnémítás" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "Átvitel" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "vonalban" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "Időtartam" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "Hívásminőség" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "Felhasználónév:" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "Jelszó:" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Felhasználónév" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Jelszó" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "Internet kapcsolat:" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "Jelentkeztessen be automatikusan" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "Felhasználó azonosító" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "Bejelentkezési információ" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "Fiber csatorna" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "Linphone Hibakereső Ablak" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "Görgetés a végéhez" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "Alapértelmezett" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "Törlés" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "_Beállítások" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "Videó indítása mindig" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "Saját nézet" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "_Segítség" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "Hibakeresési ablak mutatása" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "_Honlap" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "Frissítések keresése" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "Fiók varázsló" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "Adja meg a SIP címet vagy a telefonszámot:" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "Új hívás kezdeményezése" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "Partnerek" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "Keresés" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "Partnerek hozzáadása könyvtárból" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "Partner hozzáadása" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "Jelenlegi identitásom:" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "alapértelmezett hangkártya" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "egy hangkártya" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "alapértelmezett kamera" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "CIF" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "Audió kódekek" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "Videó kódekek" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "C" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "SIP (UDP)" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "SIP (TCP)" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "SIP (TLS)" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "Beállítások" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "Ez a rész határozza meg az Ön SIP címét, amikor nem használ SIP fiókot" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "Az Ön megjelenített neve (pl. Kis József):" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "Az Ön felhasználóneve:" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "Az Ön így keletkezett SIP címe:" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "Alapértelmezett identitás" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "Varázsló" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "Hozzáadás" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "Szerkesztés" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "Eltávolítás" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "Proxy fiókok" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "Minden kulcsszó törlése" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "Titoktartás" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "SIP fiókok beállítása" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Csengőhang:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "Különleges ALSA eszköz (nem kötelező):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Felvevő hang eszköz:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Csengőhang eszköz:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Lejátszó hang eszköz:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Visszhang-elnyomás engedélyezése" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Audió" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Videó bemeneti eszköz:" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "A 0 jelentése \"végtelen\"" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "Videó" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "Feltöltési sebesség korlát (kbit/mp):" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "Letöltési sebesség korlát (kbit/mp):" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "Alkalmazkodó mérték-szabályozás engedélyezése" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "Az alkalmazkodó mérték-szabályozás egy módszer, mely erőteljesen próbálja megállapítani a rendelkezésre álló sávszélességet hívás alatt." - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "Sávszélesség szabályozása" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "Multimédia beállítások" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "Maximum Továbbítási Egység beállítása:" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "DTMF küldése SIP infóként" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "Átvitel" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "Audió RTP/UDP:" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "Javítva" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "Videó RTP/UDP:" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "Alagút" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "DSCP mezők" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "Hálózati protokoll és port" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "Közvetlen Internet kapcsolat" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "NAT / tűzfal mögött (STUN használata a feloldáshoz)" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "NAT / tűzfal mögött (ICE használata)" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "NAT / tűzfal mögött (uPnP használata)" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "Publikus IP cím:" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "STUN kiszolgáló:" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "NAT és tűzfal" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "Média titkosítás típusa" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "Média titkosítás kötelező" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "Hálózati beállítások" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Engedélyezés" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Tiltás" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "Kódekek" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "Nyelv" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "Haladó beállítások megjelenítése" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "Szint" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "Felhasználói környezet" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "Kész" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "Linphone - Hitelesítés szükséges" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "Kérem adja meg a tartomány jelszavát" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "" - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "A fiók beállítása varázsló üdvözli Önt" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "Fiók létrehozása a linphone.org -on" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "Már rendelkezem linphone.org fiókkal, azt szeretném használni" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "Már rendelkezem sip fiókkal, azt szeretném használni" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "Fiók beállítása varázsló" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "Felhasználónév*" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "Jelszó*" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "Tartomány" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "Proxy" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "Az Ön fiókjának beállítása (1/1 lépés)" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "Adja meg linphone.org felhasználónevét" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "Adja meg sip felhasználónevét (1/2 lépés)" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "(*) Mező kitöltése szükséges" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "E-mail: (*)" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "Felhasználónév: (*)" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "Jelszó: (*)" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "Jelszó megerősítése: (*)" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "Adja meg a fiókinformációt (1/2 lépés)" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "Kérjük, érvényesítse fiókját az általunk elektronikus levélben küldött hivatkozásra kattintva.\nAzután térjen vissza ide és kattintson a Következő gombra." - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "Érvényesítés (2/2 lépés)" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "Hiba, a fiók nincs érvényesítve. Valaki már használja ezt a felhasználónevet vagy a kiszolgáló nem elérhető.\nKérjük, lépjen vissza és próbálja újra." - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "Hiba" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Köszönjük! Az Ön fiókját beállítottuk és használatra kész." - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "Linphone - SIP fiók beállítása" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "Az Ön SIP azonosítója:" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "Így néz ki: sip:@" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "sip:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "SIP Proxy cím:" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "Így néz ki: sip:" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "Regisztrálási Időköz (mp):" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "Út (nem kötelező):" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "Regisztráció" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "Jelenléti információ közlése" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "SIP fiók beállítása" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "VoIP alagút beállítása" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "Hoszt" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "Port" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "Alagút beállítása" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "http proxy beállítása (nem kötelező)" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "Kérem várjon" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "Kész" - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "Kapcsolódás" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "Nem sikerült hívni" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "Elnézést, elértük a egyidejű hívások maximális számát" - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "kapcsolatba lépett veled." - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr "és automatikus választ kért." - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "A hívási jellemzők módosítása..." - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "Kapcsolódva." - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "Hívás megszakítva" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "Nem sikerült várakoztatni a hívást" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "Jelenlegi hívás várakoztatásának aktiválása..." - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "Stun keresés folyamatban..." - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "ICE helyi jelentkezők begyűjtése folyamatban..." - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "Elérhető" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "Foglalt" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "Mindjárt visszajön" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "Nem elérhető" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "Vonalban" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "Ebédelni ment" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "Ne zavarj" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "Elment" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "Másik üzenő szolgáltatás használata" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "Nem elérhető" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "Függőben" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "Az Ön által megadott SIP proxy cím érvénytelen. \"sip:\"-tal kell kezdődnie, ezt egy hosztnév követi." - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "Az Ön által megadott SIP identitás érvénytelen.\nÍgy kéne kinéznie: sip:felhasznalonev@proxytartomany, például sip:aladar@pelda.hu" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "Telefonszám-cél keresése..." - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "Nem sikkerült értelmezni a számot." - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "Nem sikerült belépni ezzel: %s" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "" - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "Távoli csengés." - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "Távoli csengés..." - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "Korai médiák." - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "Hívás visszatért" - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "Nem kompatibilis, ellenőrizze a kódek- vagy a biztonsági beállításokat..." - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "Nem kompatibilis médiajellemzők." - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "Visszatértünk." - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "Megállítva a másik fél által." - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "A hívás távolról frissítve." - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "A hívás befejezve." - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "A felhasználó foglalt." - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "A felhasználó ideiglenesen nem elérhető" - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "A felhasználó nem akarja, hogy zavarják." - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "Hívás elutasítva" - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "" - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "Átirányítva" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "Nem sikerült a hívás." - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "A regisztáció a %s -n sikerült." - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "A kiregisztrálás kész a következőn: %s ." - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "időtúllépés után nincs válasz" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "A regisztáció a %s -n nem sikerült: %s" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "Hitelesítési jel: %s" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "" - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "" - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "" -msgstr[1] "" - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "" - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" diff --git a/po/insert-header.sin b/po/insert-header.sin deleted file mode 100644 index b26de01f6..000000000 --- a/po/insert-header.sin +++ /dev/null @@ -1,23 +0,0 @@ -# Sed script that inserts the file called HEADER before the header entry. -# -# At each occurrence of a line starting with "msgid ", we execute the following -# commands. At the first occurrence, insert the file. At the following -# occurrences, do nothing. The distinction between the first and the following -# occurrences is achieved by looking at the hold space. -/^msgid /{ -x -# Test if the hold space is empty. -s/m/m/ -ta -# Yes it was empty. First occurrence. Read the file. -r HEADER -# Output the file's contents by reading the next line. But don't lose the -# current line while doing this. -g -N -bb -:a -# The hold space was nonempty. Following occurrences. Do nothing. -x -:b -} diff --git a/po/it.po b/po/it.po deleted file mode 100644 index 63dc17acb..000000000 --- a/po/it.po +++ /dev/null @@ -1,2091 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -# Daniele , 2015 -# Fabrizio Carrai, 2015 -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: Italian (http://www.transifex.com/belledonne-communications/linphone-gtk/language/it/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: it\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "Chiama %s" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "Invia messaggio a %s" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "Aggiungi %s alla tua lista dei contatti" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "Chiamate recenti" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "Chiamate recenti (%i)" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "n/d" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "Annullata" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "Persa" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "Rifiutata" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "%i minuto" -msgstr[1] "%i minuti" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "%i secondo" -msgstr[1] "%i secondi" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "%s\tQualità: %s\n%s\t%s\t" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "%s\t%s" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "Conferenza" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "Me" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "Impossibile trovare il file pixmap %s" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "Invio in corso..." - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "Messaggio non inviato" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "Copia" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "alcune informazioni di debug verranno registrate sullo stdout durante l'esecuzione" - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "mostra la versione e termina." - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "percorso del file di log." - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "Avvia linphone con il video disabilitato." - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "Avvia solo nel system tray, non mostrare l'interfaccia principale." - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "indirizzo da chiamare adesso" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "Specificare una directory di lavoro (dovrebbe essere quella di installazione, es: c:\\Program Files\\Linphone)" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "File di configurazione" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "Avvia l'assistente audio" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "Esegui il self test e esci con 0 in caso di successo" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "%s vorrebbe aggiungerti alla sua lista dei contatti.\nVuoi aggiungerlo/a ai tuoi contatti e pemettergli di conoscere la tua presenza?\nSe rispondi NO questa persona verrà temporaneamente bloccata." - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "Digitare la password per l'utente %s\nnel dominio %s:" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "Errore durante la chiamata" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "Chiamata terminata" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "Chiamata in arrivo" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "Risposta" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "Rifiuta" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "Chiamata in pausa" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "da %s" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "%s chiede di avviare il video. Accetti ?" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "Collegamento al sito web" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "Un videotelefono su internet" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "%s (Default)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "Siamo trasferiti verso %s" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "Non è stata trovata nessuna scheda audio.\nNon sarà possibile effettuare o ricevere chiamate in voce." - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "Un videotelefono SIP free" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "Salve\n" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "Aggiungi alla rubrica" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "Cerca contatti nella directory %s" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "Contatto SIP non valido" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "Aggiungi un nuovo contatto" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "Modifica contatto %s" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "Elimina il contatto %s" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "Cancella la cronologia della chat con '%s'" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "Aggiungi nuovo contatto dalla directory %s" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "Nome" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "Frequenza (Hz)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "Stato" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "IP Bitrate (kbit/s)" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "Parametri" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "Attivato" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "Disattivato" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "Account" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "Inglese" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "Francese" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "Svedese" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "Italiano" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "Spagnolo" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "Portoghese brasiliano" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "Polacco" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "Tedesco" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "Russo" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "Giapponese" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "Olandese" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "Ungherese" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "Ceco" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "Cinese" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "Cinese tradizionale" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "Norvegese" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "Ebraico" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "Serbo" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "Arabo" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "Turco" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "Riavviare il software per utilizzare la nuova lingua selezionata" - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "Nessuno" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "SRTP" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "DTLS" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "ZRTP" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "Una versione più recente è disponibile su %s.\nVuoi aprire un browser per eseguire il download ?" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "Stai eseguendo la versione più aggiornata." - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "Nome, Cognome" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "Errore di comunicazione con il server." - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "In connessione..." - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "Connesso" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "Ricezione dei dati..." - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "Trovato %i contatto" -msgstr[1] "Trovati %i contatti" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "" - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "Chiamata #%i" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "Trasferimento per chiamare #%i con %s" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "Non usato" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "ICE non attivato" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "ICE fallito" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "ICE in corso" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "Attraversando uno o più NAT" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "Diretto" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "Attraverso un relay server" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "uPnP non attivo" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "uPnP in corso" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "uPnP non disponibile" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "uPnP in esecuzione" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "uPnP ha fallito" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "Diretto o attraverso un server" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "download: %f\nupload: %f (kbit/s)" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "%ix%i @ %f fps" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "%.3f secondi" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "Riagganciare" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "Chiamando..." - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "00:00:00" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "Chiamata in ingresso" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "bene" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "media" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "ridotto" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "molto poco" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "troppo brutto" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "non disponibile" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "Trasmissione sicura con SRTP" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "Trasmissione sicura con DTLS" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "Trasmissione sicura con ZRTP - [auth token: %s]" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "Marcato come non verificato" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "Marcato come verificato" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "In conferenza" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "Chiamata in corso" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "Chiamata sospesa" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "Chiamata terminata." - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "Trasferimento in corso" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "Trasferimento completato." - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "Trasferimento fallito." - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "Riprendere" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "Pausa" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "Registrare in\n%s %s" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "(Sospeso)" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "Prego inserire le proprie credenziali di accesso per %s" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "prelevando da %s" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "Il trasferimento della configurazione remota da %s è fallito." - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "Non è stata riconosciuta nessuna voce" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "Troppo basso" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "Bene" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "Troppo forte" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "Hai sentito tre segnali ?" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "Le preferenze sui suoni non sono state trovate" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "Non è possibile eseguire il controllo dell'audio di sistema" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "Benvenuto!\nL'assistente ti aiuterà a configurare i settaggi audio di Linphone" - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "Dispositivo di acquisizione" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "Volume di registrazione" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "Nessuna voce" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "Preferenze per l'audio di sistema" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "Dispositivo di riproduzione" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "Riproduci tre segnali" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "Premere il pulsante registrazione e parlare" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "Ascoltare la voce registrata" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "Registra" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "Riproduci" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "Ora è possibile usare Linphone" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "Assistente Audio" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "Assistente Audio" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "Calibrazione del guadagano del microfono" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "Calibrazione del volume di riproduzione" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "Registra e Riproduci" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "Procedura completata" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "Su Linphone" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "(C) Belledonne Communications, 2010\n" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "Un videotelefono con protocollo standard SIP (RFC 3261) " - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "fr: Simon Morlat\nen: Simon Morlat and Delphine Perreau\nit: Alberto Zanoni \nit: Fabrizio Carrai\nde: Jean-Jacques Sarton \nsv: Daniel Nylander \nes: Jesus Benitez \nja: YAMAGUCHI YOSHIYA \npt_BR: Rafael Caesar Lenzi \npl: Robert Nasiadek \ncs: Petr Pisar \nhu: anonymous\nhe: Eli Zaretskii \n" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "Cerca contatti nella directory" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "Aggiungi alla mia lista" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "Cerca" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "Nome del chiamato" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "Cronologia" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "Pulisci tutto" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "Richiamata" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "Statistiche della chiamata" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "Codec audio" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "Codec video" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "Banda IP impiegata per l'audio" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "Supporto audio" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "Banda IP impiegata per il video" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "Supporto video" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "Tempo di andata/ritorno" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "Risoluzione video ricevuta" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "Risoluzione video trasmessa" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "Profilo RTP" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "Statistiche della chiamata e informazioni" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "Invia" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "Fine della conferenza" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "Specificare un URI per la configurazione remota" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "Questo modulo permette di impostare un indirizzo http o https da cui prelevare la configurazione all'avvio.\nDi seguito inserire o modificare l' URI della configurazione. Dopo aver selezionato OK Linphone verrà automaticamente riavvato per leggere ed usare la nuova configurazione." - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "Indirizzo SIP" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "Mostra lo stato di presenza del contatto" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "Permetti al contatto di vedere il mio stato di presenza" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "Informazioni sul contatto" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "Configurazione DSCP" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "SIP" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "Stream audio RTP" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "Stream video RTP" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "Valore DSCP (in esadecimale)" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "Selezionare qui per regolare il volume" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "Registra questa chiamata su un file audio" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "Video" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "Silenzia" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "Trasferimento" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "In chiamata" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "Durata" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "Giudizio della qualità della chiamata" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "Configurazione LDAP" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "Indirizzo del server:" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "Metodo di autenticazione" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "Nome utente:" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "Password:" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "Usa connessione TLS" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "Not ancora disponibile" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "Connessione" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "Bind DN" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "Authname" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "Dominio" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "Oggetto di base" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "Filtro (%s per il nome):" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "Attributo Nome:" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "Attributo SIP address" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "Attributo da cercare:" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "Ricerca" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "Tempo limite per la ricerca:" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "Massimo numero di risultati:" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "Segui gli Aliases" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "Varie" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "ANONYMOUS" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "SEMPLICE" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "DIGEST-MD5" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "NTLM" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Nome utente" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Password" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "Connessione Internet:" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "Login Automatico" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "Identificativo utente" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "Credenziali di accesso" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "Benvenuto!" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "Fibra ottica" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "Linphone debug window" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "Vai in fondo" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "Default" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "Cancellare" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "_Opzioni" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "Imposta l' URI di configurazione" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "Avvia sempre il video" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "Self-view abilitato" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "Mostra il tastierino" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "_Aiuto" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "Mostra la finestra di debug" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "_Homepage" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "Check _Updates" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "Assistente per l'account" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "Indirizzo sip o numero." - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "Inizia una nuova chiamata" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "Contatti" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "Ricerca" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "Aggiungi contatti dalla directory" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "Aggiungi un contatto" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "Cancella la cronologia della chiamate" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "Identità corrente" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "Risponditore automatico attivato" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "anonimo" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "GSSAPI" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "default scheda audio" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "una scheda audio" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "default videocamera" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "CIF" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "Codificatori audio" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "Codificatori video" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "C" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "SIP (UDP)" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "SIP (TCP)" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "SIP (TLS)" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "Preferenze" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "questa sezione definisce il tuo indirizzo SIP se non hai account attivi" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "Nome visualizzato (es: Mario Rossi):" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "Nome utente:" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "Il tuo indirizzo sip:" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "Identità di default" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "Wizard" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "Aggiungi" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "Edita" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "Rimuovi" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "Account proxy" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "Cancella tutte le password" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "Privacy" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "Rispondi automaticamente alla chiamata in arrivo" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "Ritardo prima della risposta (ms)" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "Risposta automatica" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "Gestici SIP Account" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Suoneria:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "Dispositivo ALSA (optional):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Dispositivo microfono:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Dispositivo squillo:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Dispositivo uscita audio:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Attiva cancellazione eco" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Audio" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Dispositivo Video:" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "Risoluzione video preferita:" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "Modalità video in uscita:" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "Mostra il preview della videocamera" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "Preconfigurazione del video:" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "Frame rate video preferito:" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "0 sta per illimitato" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "Video" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "Velocità massima in upload Kbit/sec:" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "Velocita massima in Dowload Kbit/sec" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "Abilita il controllo adattivo del rate" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "Il controllo adattivo del rate è una tecnica per la stima dinamica della banda disponibile durante una chiamata" - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "Gestione banda" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "Impostazioni multimediali" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "Imposta Maximum Transmission Unit:" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "Invia DTMF come SIP info" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "Permetti IPv6" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "Transporto" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "Porta SIP/UDP" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "Casuale" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "Porta SIP/TCP" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "Audio RTP/UDP:" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "Fissa" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "Video RTP/UDP:" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "Tunnel" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "Campi DSCP" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "Protocollo di rete e porte" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "Connessione diretta a internet" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "Dietro ad un NAT / Firewall (specificare IP del gateway)" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "Dietro NAT / Firewall (utilizza STUN)" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "Dietro ad un NAT / Firewall (usa ICE)" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "Dietro ad un NAT / Fiewall (usa uPnP)" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "Indirizzo IP pubblico:" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "Server STUN:" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "NAT and Firewall" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "Tipo di cifratura" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "La cifratura è obbligatoria" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "Impostazioni di rete" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Attivato" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Disattivato" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "Codificatori audio" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "Codificatori video" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "Codec" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "Linguaggio" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "Mostra la configurazione avanzata" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "Livello" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "Interfaccia utente" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "Configurazione dell' account LDAP" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "LDAP" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "Fatto" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "Linphone - E' richiesta l'autenticazione" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "Prego inserire la password di dominio" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "Configurando..." - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "Caricamento della configurazione dal server, attendere..." - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "Assistente per la configurazione di un account SIP" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "Benvenuto!\nL'assistente vi aiuterà ad usare un indirizzo SIP per le vostre chiamate." - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "Benvenuto nel configuratore di account" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "Creare un account su linphone.org" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "Ho già un account su linphone.org che voglio usare." - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "Ho già un account SIP e voglio usarlo" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "Voglio specificare un URI per la configurazione remota" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "Configuratore di account" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "Inserire i dati del vostro account" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "Nome utente*" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "Password*" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "Dominio*" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "Proxy" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "Configurare il tuo account (passo 1/1)" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "Immettere il vostro nome utente su linphone.org" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "Introdurre il vostro nome utente SIP (passo 1/1)" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "(*) Campi obbligatori" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "Email: (*)" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "Nome utente: (*)" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "Password: (*)" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "Confermare la password: (*)" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "Mantenetemi aggiornato sugli aggiornamenti di linphone" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "Introdurre le informazioni dell'account (passo 1/2)" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "Il vostro account è stato creato, attendere." - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "Creazione dell'account in corso" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "Attivate il vostro account cin il link che vi è appena stato inviato per posta elettronica.\nQuindi tornare qui e premere il tasto \"Avanti\"." - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "Validazione (passo 2/2)" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "Verifica della validazione dell'account, attendere." - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "Controllo della validazione dell'account in corso" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "Errore, account non valido, nome utente già in uso o server non raggiungibile.\nTornare indietro e riprovare." - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "Errore" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Grazie. Il tuo account è configurato e pronto all'uso" - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "Linphone - Configurazione SIP account" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "Identità SIP" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "Simile a sip:@" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "sip:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "Indirizzo sip proxy:" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "Simile a sip:" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "Durata registrazione (sec)" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "Parametri del contatto (opzionali)" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "AVPF regular RTCP interval (sec):" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "Rotta (opzionale)" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "Trasporto" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "Registro" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "Pubblica stato della presenza" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "Abilita AVPF" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "Configurazione SIP account" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "Configurare il tunnel VoIP" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "Host" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "Porta" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "Configurazione del tunnel" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "Configurazione del proxy http (opzionale)" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "Prego attendere" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "Pronto" - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "Configurando" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "In connessione" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "Impossibile chiamare" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "Spiacenti, è stato raggiunto il massimo numero di chiamate simultanee" - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "ti sta contattando" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr "e ha richiesto la risposta automatica" - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "Modificando i parametri di chiamata..." - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "Connessione" - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "Chiamata annullata" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "Impossibile sospendere la chiamata" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "Sospensione della chiamata in corso..." - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "Ricerca Stun in progresso ..." - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "Raccolta dei candidati ICE locali in corso..." - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "In linea" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "Occupato" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "Torno subito" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "Assente" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "Al telefono" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "Fuori per pranzo" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "Non disturbare" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "Trasferito" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "Utilizza una altro servizio di messaggistica" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "Offline" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "Pendente" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "Assente" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "Stato sconosciuto" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "L'indirizzo sip proxy utilizzato è invalido, deve iniziare con \"sip:\" seguito dall' hostaname." - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "L'identità sip utilizza è invalida.\nDovrebbre essere sip:username@proxydomain, esempio: sip:alice@example.net" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "Ricerca numero destinazione..." - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "Impossibile risolvere il numero." - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "impossibile login come %s" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "Aggiornamento da %s..." - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "Il chiamato sta squillando." - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "Il chiamato sta squillando..." - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "Early media." - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "Risposta da %s." - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "Prosecuzione della chiamata." - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "Incompatibile, controllare i codecs o i parametri della sicurezza..." - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "Parametri di comunicazione incompatibili." - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "La comunicazione è stata ripresa." - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "L'interlocutore ci ha messi in attesa." - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "Aggiornamento della chiamata dalla parte remota." - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "Chiamata terminata." - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "Utente occupato" - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "Utente non disponibile" - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "L'utente non vuole essere disturbato" - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "Chiamata rifiutata" - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "Richiesta scaduta" - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "Trasferito" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "Chiamata non riuscita." - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "Registrazione su %s attiva" - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "Unregistrazione su %s" - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "timeout no risposta" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "Registrazione su %s fallita: %s" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "Servizio non disponibile, nuovo tentativo in corso" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "Il codice di autenticazione è %s" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "I parametri della chiamata sono stati modificati con successo: %s." - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "I parametri della chiamata sono stati modificati con successo." - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "%i chiamata persa." -msgstr[1] "%i chiamate perse." - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "annulata" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "completata" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "persa" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "sconosciuto" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "%s a %s\nDa: %s\nA: %s\nStato: %s\nDurata: %i min %i sec\n" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "chiamata in uscita" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "Impossibile riprodurre %s." - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" diff --git a/po/ja.po b/po/ja.po deleted file mode 100644 index 851003f4e..000000000 --- a/po/ja.po +++ /dev/null @@ -1,2087 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -# Alexander, 2014 -# Alexander, 2014-2015 -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: Japanese (http://www.transifex.com/belledonne-communications/linphone-gtk/language/ja/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ja\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "%s を呼び出し中" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "%s に文章を送信" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "%sを連絡先に追加" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "通話時間" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "通話時間 (%i)" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "n/a" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "中断" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "失敗" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "辞退" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "%i 分" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "%i 秒" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "%s品質: %s\n%s⇥%s⇥" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "%s⇥%s" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "会議" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "自分" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "pixmapファイルが見つかりません %s" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "" - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "コピー" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "実行中にいくつかのデバッグ情報をstdoutに送信します。" - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "バージョン表示と退出" - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "ログを書き込むファイルへのパス。" - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "ビデオを無効にしてLinphoneを開始します。" - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "主なインターフェイスを表示しないでシステムトレイに移動します。" - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "今すぐに呼び出す" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "作業ディレクトリをSpecifiy (インストールした時のベースである必要があります。例:c:\\Program Files\\Linphone)" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "設定ファイル" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "オーディオアシスタントを実行" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "セルフテストは0で終了したら成功です" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "相手が自分の連絡先に%sを追加したいそうです。\nあなたが自分の連絡先に相手を追加したらできるようになり相手のステータスも表示されるようになります。\n拒否した場合その相手は一時的にブラックリストに登録されます。" - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "パスワードを入力してください %s\nrealm %s:" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "呼出エラー" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "呼出終了" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "着信" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "応答" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "拒否" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "呼び出しの一時停止" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "%s" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "%sがテレビ電話をしたいそうですが受け入れますか?" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "ウェブサイトリンク" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "テレビ電話" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "%s (デフォルト)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "%s に転送しました" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "サウンドカードが検出されていません。\n音声通話の送受信はできません。" - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "無料 SIP ビデオ-電話" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "こんにちは\n" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "電話帳に追加する" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "%s のディレクトリ内を検索" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "無効なSIP接続です!" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "新しい連絡先を追加する" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "'%s' の連絡先を編集" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "'%s' の連絡先を削除" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "'%s' のチャット履歴を削除" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "フォルダ %s から連絡先を追加する" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "名前" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "レート (Hz)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "状態" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "IP ビットレート (kbit/s)" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "パラメーター" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "使用する" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "使用しない" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "アカウント" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "English" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "Français" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "Svenska" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "Italiano" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "Español" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "Português do Brasil" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "Polski" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "Deutsch" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "Pусский" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "日本語" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "Nederlands" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "Magyar" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "čeština" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "简体中文" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "繁体中文" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "Norsk" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "עברית" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "Cрпски" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "アラビア語" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "トルコ語" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "言語の選択を有効にするには、 Linphoneを再起動する必要があります。" - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "なし" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "SRTP" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "DTLS" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "ZRTP" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "%s よりも新しいバージョンが利用可能です。\nダウンロードするために、ブラウザを開きますか?" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "最新版です。" - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "名前、名字" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "サーバーとの通信エラーが発生しました。" - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "接続中..." - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "接続" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "データを受信中…" - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "%i 件発見" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "" - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "呼び出し #%i" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "通話 #%i を %s に転送する" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "使用しない" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "ICE 未認証" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "ICE 失敗" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "ICE 進行中" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "NATを通ります" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "直接" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "間接的にリレーサーバーを使う" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "uPnPは作動しておりません" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "uPnPを使用中" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "uPnPは利用できません" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "uPnP作動中" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "uPnP失敗" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "直接またはサーバー経由" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "ダウンロード: %f\nアップロード: %f (kbit/s)" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "%ix%i @ %f fps" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "%.3f 秒" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "電話を切る" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "かけています…" - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "00:00:00" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "着信" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "良い" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "アベレージ" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "悪い" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "非常にプアな" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "非常にバッドな" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "利用できません" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "SRTPのセキュリティ" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "DTLSセキュリティ" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "ZRTP によるセキュリティ - [auth token: %s]" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "セット未検証" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "セット検証済" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "会議で" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "呼び出し中" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "呼び出し停止" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "呼び出し終了" - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "進行中の転送" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "転送完了。" - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "転送失敗。" - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "レジューム" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "一時停止" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "記録\n%s %s" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "(停止中)" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "%sの情報はログインしてご確認ください" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "%sからのフェッチ" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "" - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "音声が検出できません" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "小さい" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "丁度よい" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "大きい" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "3回のビープ音が聞こえましたか?" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "音声の設定が見つかりません" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "音声制御システムを起動できません" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "" - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "キャプチャーデバイス" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "録音音量" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "音声なし" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "システムサウンド設定" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "3回分のビープ音を再生する" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "録音した音声を聞く" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "録音" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "再生" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "Linphoneをはじめる" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "音声アシスタント" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "音声アシスタント" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "マイクのゲイン測定" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "スピーカーの音量測定" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "録音して再生" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "終了" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "Linphoneについて" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "(C) Belledonne Communications, 2010\n" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "インターネットによる動画送信には標準的なSIPプロトコル (rfc3261) を使用しています。" - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "fr: Simon Morlat\nen: Simon Morlat and Delphine Perreau\nit: Alberto Zanoni \nde: Jean-Jacques Sarton \nsv: Daniel Nylander \nes: Jesus Benitez \nja: YAMAGUCHI YOSHIYA \npt_BR: Rafael Caesar Lenzi \npl: Robert Nasiadek \ncs: Petr Pisar \nhu: anonymous\nhe: Eli Zaretskii \n" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "呼出履歴" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "すべて消去する" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "通信統計" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "オーディオのコーデック" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "ビデオのコーデック" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "音声で使用しているIP通信帯域" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "接続している音声用メディア" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "ビデオで使用しているIP通信帯域" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "接続しているビデオ用メディア" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "RTT" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "RTPプロファイル" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "送信" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "会議を終了する" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "" - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "SIPアドレス" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "DSCP設定" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "SIP" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "オーディオのRTP" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "ビデオのRTP" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "この通話をファイルに録音する" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "ビデオ" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "消音" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "転送" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "着信" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "期限" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "LDAP設定" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "サーバーアドレス:" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "ユーザー名:" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "パスワード:" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "TLS接続を使用する" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "接続" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "Authname" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "Realm" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "検索" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "種々" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "匿名" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "シンプル" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "ダイジェスト-MD5" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "NTLM" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "ユーザー名" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "パスワード" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "インターネット接続:" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "自動的にログインする" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "ユーザーID" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "ログイン情報" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "ようこそ!" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "Linphoneデバッグウインドウ" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "最下部までスクロールする" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "デフォルト" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "削除" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "_オプション" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "いつでもビデオをスタートする" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "セルフビューを有効にする" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "キーパッドを表示する" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "_ヘルプ" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "デバッグウインドウを見る" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "_ホームページ" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "チェック _アップデート" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "アカウントのアシスタント" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "SIPアドレスもしくは電話番号:" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "連絡相手" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "検索" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "連絡相手に追加する" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "通話履歴を削除する" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "anonymous" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "GSSAPI" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "サウンドカード" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "デフォルトのカメラ" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "CIF" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "オーディオのコーデック" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "ビデオのコーデック" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "C" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "SIP (UDP)" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "SIP (TCP)" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "SIP (TLS)" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "設定" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "あなたの表示名 (例: John Doe):" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "あなたのユーザー名:" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "ウィザード" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "追加する" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "編集する" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "削除する" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "プロキシアカウント" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "すべてのパスワードを消去する" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "プライバシー" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "鳴動音:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "エコーキャンセラーを有効にする" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "オーディオ" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "0で制限なしになります" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "ビデオ" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "アップロード速度制限 Kbit/sec:" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "ダウンロード速度制限 Kbit/sec:" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "" - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "帯域幅制御" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "マルチメディア設定" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "DTMFをSIP情報で送信する" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "IPv6を有効にする" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "転送" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "SIP/UDP ポート" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "ランダム" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "SIP/TCP ポート" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "オーディオ RTP/UDP:" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "ビデオ RTP/UDP:" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "トンネル" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "DSCP値" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "ネットワークのプロトコルとポート" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "NAT / ファイヤーウォール (ICEを使う)" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "NAT / ファイヤーウォール (uPnPを使う)" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "パブリック IP アドレス:" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "Stunサーバー:" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "NAT と ファイヤーウォール" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "メディアの暗号化の種類" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "ネットワーク設定" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "使用する" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "使用しない" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "音声コーデック" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "動画コーデック" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "コーデック" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "言語" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "拡張設定を表示する" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "レベル" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "ユーザーインターフェイス" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "LDAP" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "完了" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "" - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "SIPアカウント設定アシスタント" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "ようこそ!\nあなたの通話のためのSIPアカウント設定をお手伝いします。" - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "アカウント設定アシスタントへようこそ" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "linphone.orgのアカウントを作成" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "linphone.orgのアカウントを持っているのでそれを使います" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "SIPアカウントを持っているのでそれを使います" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "アカウント設定アシスタント" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "ユーザー名*" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "パスワード*" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "ドメイン*" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "プロキシ*" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "アカウントを設定します (1/1)" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "linphone.orgで取得したユーザー名を入力" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "SIPのユーザー名を入力してください (1/1)" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "(*) 必須" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "メールアドレス: (*)" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "ユーザー名: (*)" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "パスワード: (*)" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "パスワードを再入力: (*)" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "アップデートでLinphoneを常に最新にする" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "アカウント情報を入力してください (1/2)" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "送信されたメールの本文内にあるリンクをクリックしてアカウントを有効にしてください。\nその後こちらへ戻って「次へ」を押してください。" - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "検証します (2/2)" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "エラー" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "ありがとう。あなたのアカウントは無事に設定され、使用する準備ができました。" - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "Linphone - SIPアカウントを設定します" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "sip:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "SIP プロキシ:" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "転送" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "登録" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "パブリッシュ情報" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "AVPFを有効にする" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "ホスト" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "ポート" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "お待ちください" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "準備" - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "" - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr "と自動応答を尋ねる" - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "コールパラメーターの変更..." - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "接続しました。" - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "呼び出しを打ち切る" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "呼び出しを一時停止できませんでした" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "現在の通話を一時停止..." - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "Stunによるルックアップの進行中…" - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "" - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "オンライン" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "ビジー" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "離席中" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "手が離せません" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "移動中" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "オフライン" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "保留" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "休暇中" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "不明なステータス" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "" - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "" - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "" - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "" - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "" - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "" - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "Early media." - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "" - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "" - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "" - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "" - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "" - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "" - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "呼び出し終了。" - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "相手はビジーです。" - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "相手は、今出られません。" - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "相手は手が離せないようです。" - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "通話は拒否されました。" - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "リクエストは時間切れです。" - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "" - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "" - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "" - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "" - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "" - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "" - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "不明" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "%s が再生出来ません。" - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" diff --git a/po/lt.po b/po/lt.po deleted file mode 100644 index 70a798dbf..000000000 --- a/po/lt.po +++ /dev/null @@ -1,2094 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -# Moo, 2015-2016 -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: Lithuanian (http://www.transifex.com/belledonne-communications/linphone-gtk/language/lt/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: lt\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "Skambinti %s" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "Siųsti tekstą į %s" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "Pridėti %s į jūsų kontaktų sąrašą" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "Paskiausi skambučiai" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "Paskiausi skambučiai (%i)" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "—" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "Nutrauktas" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "Praleistas" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "Atmestas" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "%i minutė" -msgstr[1] "%i minutės" -msgstr[2] "%i minučių" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "%i sekundė" -msgstr[1] "%i sekundės" -msgstr[2] "%i sekundžių" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "%s\tKokybė: %s\n%s\t%s\t" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "%s\t%s" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "Konferencija" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "Nepavyko rasti paveikslo žemėlapio failo: %s" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "Siunčiama..." - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "Pranešimas neišsiųstas" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "Kopijuoti" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "kol vykdoma, registruoti į stdout kai kurią derinimo informaciją." - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "parodyti versiją ir išeiti." - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "kelias į failą, į kurį rašyti žurnalus." - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "Paleisti linphone su išjungtu vaizdu." - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "Paleisti tik sistemos dėkle, nerodyti pagrindinės sąsajos." - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "adresas, į kurį tuoj pat skambinti" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "Nurodyti darbinį katalogą (turėtų būti diegimo bazė, pvz.,: c:\\Program Files\\Linphone)" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "Konfigūracijos failas" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "Vykdyti garso pagelbiklį" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "Vykdyti savikontrolę ir išeiti 0, jei pavyks" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "%s norėtų jus pridėti į savo kontaktų sąrašą.\nAr jūs norėtumėte taip pat pridėti jį/ją į savo kontaktų sąrašą ir leisti jam/jai matyti jūsų prisijungimo būseną?\nJeigu atsakysite ne, šis asmuo bus laikinai pridėtas į juodąjį sąrašą." - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "Skambučio klaida" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "Skambutis užbaigtas" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "Įeinantis skambutis" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "Atsiliepti" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "Atmesti" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "Skambutis pristabdytas" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "naudotojo %s" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "%s pasiūlė pradėti vaizdą. Jūs sutinkate ?" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "Svetainės nuoroda" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "Internetinis vaizdo telefonas" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "%s (Numatytoji)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "Šiame kompiuteryje nebuvo aptikta jokių garso plokščių.\nJūs negalėsite siųsti ir priimti garso skambučių." - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "Nemokamas SIP vaizdo telefonas" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "Sveiki\n" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "Pridėti į adresų knygą" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "Netaisyklingas sip kontaktas !" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "Pridėti naują kontaktą" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "Redaguoti kontaktą \"%s\"" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "Ištrinti kontaktą \"%s\"" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "Ištrinti \"%s\" pokalbių istoriją" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "Pridėti naują kontaktą iš %s katalogo" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "Vardas" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "Sparta (Hz)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "Būsena" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "IP Pralaidumas (kbit/s)" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "Parametrai" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "Įjungta" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "Išjungta" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "Paskyra" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "Anglų" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "Prancūzų" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "Švedų" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "Italų" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "Ispanų" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "Brazilijos Portugalų" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "Lenkų" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "Vokiečių" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "Rusų" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "Japonų" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "Olandų" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "Vengrų" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "Čekų" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "Kinų" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "Tradicinė Kinų" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "Norvegų" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "Hebrajų" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "Serbų" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "Arabų" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "Turkų" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "Tam, kad įsigaliotų naujas kalbos pasirinkimas, turite iš naujo paleisti programą linphone." - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "Nėra" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "SRTP" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "DTLS" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "ZRTP" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "Yra prieinama naujesnė versija iš %s.\nAr norėtumėte atverti naršyklę ir ją atsisiųsti?" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "Jūs naudojatės paskiausia versija." - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "Vardas, Pavardė" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "Klaida, susisiekiant su serveriu." - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "Jungiamasi..." - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "Prisijungta" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "Gaunami duomenys..." - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "Rastas %i kontaktas" -msgstr[1] "Rasti %i kontaktai" -msgstr[2] "Rasta %i kontaktų" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "Naudotojo vardas jau yra naudojamas!" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "Nepavyko patikrinti naudotojo vardo prieinamumą. Prašome vėliau bandyti dar kartą." - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "Skambutis #%i" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "Nenaudojama" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "ICE neaktyvuota" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "ICE nepavyko" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "ICE yra eigoje" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "uPnP neaktyvuota" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "uPnP yra eigoje" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "uPnp neprieinama" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "uPnP yra vykdoma" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "uPnP nepavyko" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "atsiuntimas: %f\nišsiuntimas: %f (kbit/s)" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "%ix%i @ %f kadr./s" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "%.3f sekundžių" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "Padėti ragelį" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "Skambinama..." - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "00:00:00" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "Įeinantis skambutis" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "geras" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "vidutinis" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "žemas" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "labai žemas" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "pernelyg blogas" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "neprieinama" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "Konferencijoje" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "Skambutyje" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "Skambutis pristabdytas" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "Skambutis užbaigtas." - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "" - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "" - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "Tęsti" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "Pristabdyti" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "Įrašoma į\n%s %s" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "(Pristabdyta)" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "Prašome įvesti %s prisijungimo informaciją" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "gaunama iš %s" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "Nuotolinės konfigūracijos atsiuntimas iš %s nepavyko." - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "Neaptikta jokio balso" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "Per tyliai" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "Gerai" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "Per garsiai" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "Ar girdėjote tris byptelėjimus?" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "Garso nuostatos nerastos" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "Nepavyko paleisti sistemos garso valdymą" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "Sveiki!\nŠis pagelbiklis padės jums sukonfigūruoti Linphone garso nustatymus" - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "Mikrofonas" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "Įrašomas garsis" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "Nėra balso" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "Sistemos garso nuostatos" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "Atkūrimo įrenginys" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "Groti tris byptelėjimus" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "Spustelėkite įrašymo mygtuką ir tarkite kelis žodžius" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "Klausytis savo įrašyto balso" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "Įrašyti" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "Groti" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "Dabar, paleiskime Linphone" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "Garso Pagelbiklis" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "Garso pagelbiklis" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "Mikrofono stiprinimo gradavimas" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "Garsiakalbių garsio gradavimas" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "Įrašykite ir Grokite" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "Baigiama" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "Apie Linphone" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "(C) Belledonne Communications, 2010\n" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "Internetinis vaizdo telefonas, naudojantis standartinį SIP (rfc3261) protokolą." - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "fr: Simon Morlat\nen: Simon Morlat and Delphine Perreau\nit: Alberto Zanoni \nde: Jean-Jacques Sarton \nsv: Daniel Nylander \nes: Jesus Benitez \nja: YAMAGUCHI YOSHIYA \npt_BR: Rafael Caesar Lenzi \npl: Robert Nasiadek \ncs: Petr Pisar \nhu: anonymous\nhe: Eli Zaretskii \n" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "Pridėti į mano sąrašą" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "Išvalyti viską" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "Skambučio statistika" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "Garso kodekas" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "Vaizdo kodekas" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "Garso IP pralaidumo naudojimas" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "Vaizdo IP pralaidumo naudojimas" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "Gaunamo vaizdo raiška" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "Siunčiamo vaizdo raiška" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "RTP profilis" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "Skambučio statistika ir informacija" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "Siųsti" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "Užbaigti konferenciją" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "Nuotolinės konfigūracijos URI nurodymas" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "Šis dialogas leidžia nustatyti http ar https adresą, kai konfigūracija bus gaunama paleisties metu.\nPrašome žemiau įvesti ar pakeisti konfigūracijos URI. Po to, kai nuspausite mygtuką Gerai, programa Linphone bus automatiškai paleista iš naujo, kad gautų ir naudotų naująją konfigūraciją." - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "SIP adresas" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "Rodyti šio kontakto prisijungimo būseną" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "Leisti šiam kontaktui matyti mano prisijungimo būseną" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "Kontakto informacija" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "DSCP nustatymai" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "SIP" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "Garso RTP srautas" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "Vaizdo RTP srautas" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "Nustatykite DSCP reikšmes (šešioliktainiais)" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "Spustelėkite čia, kad nustatytumėte garsiakalbių garsį" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "Įrašyti šį skambutį į garso įrašo failą" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "Vaizdas" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "Nutildyti" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "Trukmė" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "Skambučio kokybės įvertinimas" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "LDAP nustatymai" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "Serverio adresas:" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "Tapatybės nustatymo metodas:" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "Naudotojo vardas:" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "Slaptažodis:" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "Kol kas neprieinama" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "Ryšys" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "NTLM" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Naudotojo vardas" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Slaptažodis" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "Interneto ryšys:" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "Prijungti mane automatiškai" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "Naudotojo ID" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "Prisijungimo informacija" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "Sveiki!" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "Linphone derinimo langas" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "Slinkti į pabaigą" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "Ištrinti" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "_Parinktys" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "Nustatyti konfigūracijos URI" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "Visada pradėti vaizdą" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "Rodyti pagalbinę klaviatūrą" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "P_agalba" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "Rodyti derinimo langą" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "_Internetinė svetainė" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "Tikrinti ar yra at_naujinimų" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "Paskyros pagelbiklis" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "SIP adresas arba telefono numeris:" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "Inicijuoti naują skambutį" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "Kontaktai" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "Pridėti kontaktą" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "Išvalyti skambučių istoriją" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "Mano esama tapatybė:" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "Automatinis atsiliepimas yra įjungtas" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "GSSAPI" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "numatytoji garso plokštė" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "garso plokštė" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "numatytoji kamera" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "CIF" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "Garso kodekai" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "Vaizdo kodekai" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "C" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "SIP (UDP)" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "SIP (TCP)" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "SIP (TLS)" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "Nustatymai" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "Ši sekcija apibrėžia jūsų SIP adresą tais atvejais, kai nenaudojate SIP paskyros" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "Jūsų rodomas vardas (pvz., Džonas Do):" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "Jūsų naudotojo vardas:" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "Jūsų galutinis SIP adresas:" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "Numatytoji tapatybė" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "Vediklis" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "Pridėti" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "Keisti" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "Šalinti" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "Įgaliotojo serverio paskyros" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "Ištrinti visus slaptažodžius" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "Privatumas" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "Automatiškai atsiliepti, kai yra gaunamas skambutis" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "Delsa, prieš atsiliepiant (ms)" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "Automatinis atsiliepimas" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "Tvarkyti SIP paskyras" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Skambinimo garsas:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "Specialus ALSA įrenginys (nebūtina):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Mikrofonas:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Skambinimo įrenginys:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Atkūrimo įrenginys:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Įjungti aido panaikinimą" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Garsas" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Vaizdo įvesties įrenginys:" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "Pageidaujama vaizdo raiška:" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "Vaizdo išvesties metodas:" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "Rodyti kameros peržiūrą" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "Vaizdo išankstinė parinktis:" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "Pageidaujamas vaizdo kadrų dažnis:" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "0 reiškia \"neribota\"" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "Vaizdas" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "Išsiuntimo greičio riba, Kbit/sek.:" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "Atsiuntimo greičio riba, Kbit/sek.:" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "Įjungti adaptyvų spartos valdymą" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "Adaptyvus spartos valdymas yra technika, skirta, skambučio metu, dinamiškai atspėti prieinamą pralaidumą." - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "Pralaidumo valdymas" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "Multimedijos nustatymai" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "Nustatyti didžiausią duomenų persiuntimo įtaisą:" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "Siųsti DTMF kaip SIP informaciją" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "Leisti IPv6" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "Perdavimas" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "SIP/UDP prievadas" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "Atsitiktinis" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "SIP/TCP prievadas" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "Garso RTP/UDP:" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "Fiksuotas" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "Vaizdo RTP/UDP:" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "DSCP laukai" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "Tinklo protokolas ir prievadai" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "Tiesioginis sujungimas su internetu" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "Už NAT / Užkardos (nurodyti tinklų sietuvo IP )" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "Už NAT / Užkardos (naudoti STUN, siekiant išspręsti)" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "Už NAT / Užkardos (naudoti ICE)" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "Už NAT / Užkardos (naudoti uPnP)" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "Viešas IP adresas:" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "Stun serveris:" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "NAT ir Užkarda" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "Medijos šifravimo tipas" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "Medijos šifravimas yra privalomas" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "Šifravimas" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "Tinklo nustatymai" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Įjungti" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Išjungti" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "Garso kodekai" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "Vaizdo kodekai" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "Kodekai" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "Kalba" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "Rodyti išplėstinius nustatymus" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "Lygmuo" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "Naudotojo sąsaja" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "LDAP paskyros sąranka" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "LDAP" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "Atlikta" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "Linphone - Reikalingas tapatybės nustatymas" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "Prašome įvesti srities slaptažodį" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "Konfigūruojama..." - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "Prašome palaukti kol iš serverio yra gaunama konfigūracija..." - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "SIP paskyros konfigūravimo pagelbiklis" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "Sveiki!\nŠis pagelbiklis padės jums savo skambučiams naudoti SIP paskyrą." - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "Sveiki atvykę į paskyros sąrankos pagelbiklį" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "Susikurti linphone.org paskyrą" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "Aš jau turiu linphone.org paskyrą ir, tiesiog, noriu ją naudoti" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "Aš jau turiu sip paskyrą ir, tiesiog, noriu ją naudoti" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "Aš noriu nurodyti nuotolinės konfigūracijos URI" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "Paskyros sąrankos pagelbiklis" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "Įveskite savo paskyros informaciją" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "Naudotojo vardas*" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "Slaptažodis*" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "Sritis*" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "Įgaliotasis serveris" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "Konfigūruokite savo paskyrą (žingsnis 1/1)" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "Įveskite savo linphone.org naudotojo vardą" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "Įveskite savo sip paskyros naudotojo vardą (žingsnis 1/1)" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "(*) Būtini laukai" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "El. paštas: (*)" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "Naudotojo vardas: (*)" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "Slaptažodis: (*)" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "Patvirtinkite savo slaptažodį: (*)" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "Informuokite mane apie linphone atnaujinimus" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "Įveskite paskyros informaciją (žingsnis 1/2)" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "Jūsų paskyra yra kuriama, prašome palaukti." - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "Paskyra kūrimo eigoje" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "Prašome patvirtinti savo paskyrą, nuspaudžiant nuorodą, kurią ką tik atsiuntėme jums el. paštu.\nTuomet grįžkite čia ir spauskite mygtuką Pirmyn." - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "Patvirtinimas (žingsnis 2/2)" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "Tikrinama ar jūsų paskyra buvo patvirtinta, prašome palaukti." - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "Pakyros patvirtinimo patikrinimas eigoje" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "Klaida, paskyra nepatvirtinta, naudotojo vardas jau yra naudojamas arba serveris nepasiekiamas.\nPrašome grįžti atgal ir bandyti dar kartą." - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "Klaida" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Dėkojame. Jūsų paskyra yra sukonfigūruota ir paruošta naudoti." - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "Linphone - SIP paskyros konfigūravimas" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "Jūsų SIP tapatybė:" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "Atrodo taip sip:@" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "sip:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "SIP Įgaliotojo serverio adresas:" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "Registravimo trukmė (sek.):" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "Kontakto parametrai (nebūtinai):" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "AVPF reguliarus RTCP intervalas (sek.):" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "Maršrutas (nebūtinai):" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "Perdavimas" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "Registruoti" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "Skelbti prisijungimo būsenos informaciją" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "Įjungti AVPF" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "Konfigūruokite SIP paskyrą" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "Prievadas" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "Prašome palaukti" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "Pasiruošę" - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "Konfigūruojama" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "Susisiekiama su" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "Nepavyko skambinti" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "" - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "bando su jumis susisiekti" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr "" - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "Modifikuojami skambučio parametrai..." - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "Prisijungta." - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "Skambutis nutrauktas" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "Nepavyko pristabdyti skambučio" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "Pristabdomas esamas skambutis..." - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "" - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "" - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "Prisijungęs" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "Užimtas" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "Netrukus sugrįš" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "Pasišalinęs" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "Kalba telefonu" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "Pietauja" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "Netrukdyti" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "Perkeltas" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "Naudoja kitą pokalbių tarnybą" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "Atsijungęs" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "Nežinoma būsena" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "" - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "jūsų įvesta sip tapatybė yra neteisinga.\nJi turėtų atrodyti taip sip:naudotojovardas@įgaliotojoserveriosritis, kaip, pavyzdžiui, sip:alice@example.net" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "" - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "" - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "Nepavyko prisijungti kaip %s" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "" - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "" - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "" - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "" - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "%s atsiliepė į skambutį" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "Skambutis pratęstas." - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "Nesuderinama, patikrinkite kodekus ar saugos nustatymus..." - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "Nesuderinami medijos parametrai." - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "Mūsų skambutis yra pratęstas." - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "Kita šalis pristabdė skambutį." - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "" - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "Skambutis baigtas." - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "Naudotojas yra užimtas." - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "Naudotojas laikinai neprieinamas." - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "Naudotojas nenori būti trukdomas." - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "Skambutis atmestas." - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "Baigėsi užklausos laikas." - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "Skambutis nepavyko." - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "" - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "" - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "Paslauga neprieinama, bandoma iš naujo" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "Nepavyko modifikuoti skambučio parametrų: %s." - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "Skambučio parametrai buvo sėkmingai modifikuoti." - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "Jūs turite %i praleistą skambutį." -msgstr[1] "Jūs turite %i praleistus skambučius." -msgstr[2] "Jūs turite %i praleistų skambučių." - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "nutrauktas" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "užbaigtas" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "praleistas" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "nežinoma" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "%s ties %s\nNuo: %s\nKam: %s\nBūsena: %s\nTrukmė: %i min. %i sek.\n" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "Išeinantis skambutis" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "Nepavyksta groti %s." - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" diff --git a/po/nb_NO.po b/po/nb_NO.po deleted file mode 100644 index 87aff17c0..000000000 --- a/po/nb_NO.po +++ /dev/null @@ -1,2090 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -# Øyvind Sæther , 2011 -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: Norwegian Bokmål (Norway) (http://www.transifex.com/belledonne-communications/linphone-gtk/language/nb_NO/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: nb_NO\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "Ring %s" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "Send tekst til %s" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "" -msgstr[1] "" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "" -msgstr[1] "" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "Fant ikke pixmap fli: %s" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "" - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "skriv logg-informasjon under kjøring" - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "" - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "" - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "" - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "Start skjult i systemkurven, ikke vis programbildet." - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "address som skal ringes nå" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "Spesifiser arbeidsmappe (bør være base for installasjonen, f.eks: c:\\Programfiler\\Linphone)" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "" - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "Samtale avsluttet" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "Innkommende samtale" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "Svarer" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "Avvis" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "Peker til nettsted" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "%s (Standard)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "Vi er overført til %s" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "Klarte ikke å finne noe lydkort på denne datamaskinen.\nDu vil ikke kunne sende eller motta lydsamtaler." - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "En gratis SIP video-telefon" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "Søk i %s katalogen" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "Ugyldig SIP kontakt !" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "Rediger kontakt '%s'" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "Slett kontakt '%s'" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "Legg til kontakt fra %s katalogen" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "Navn" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "Frekvens (Hz)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "Status" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "Parametere" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "På" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "Av" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "Konto" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "Engelsk" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "Fransk" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "Svensk" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "Italisensk" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "Spansk" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "Portugisisk" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "Polsk" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "Tysk" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "Russisk" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "Japansk" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "Nederlandsk" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "Ungarsk" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "Tjekkisk" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "Kinesisk" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "Du må restarte linphone for at det nye språkvalget skal iverksettes." - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "En nyere utgave er tilgjengelig fra %s.\nVil du åpne en nettleser og laste den ned ?" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "Du kjører siste utgave." - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "Fornavn, Etternavn" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "Feil med forbindelsen til serveren." - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "Tilknytter..." - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "Tilknyttet" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "Mottar data..." - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "Fant kontakt %i" -msgstr[1] "Hittat kontakt %i" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "" - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "Ringer..." - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "Innkommende samtale" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "I samtale med" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "Pauset samtale" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "Samtale avsluttet." - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "" - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "" - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "Fortsett" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "Pause" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "Skriv inn påloggingsinformasjon for %s:" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "" - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "" - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "En Internet Videotelefon som bruker den standardiserte SIP-protokollen (rfc3261)." - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "Søk kontakter i katalogen" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "Legg til listen min" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "Søk noen" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "Samtalehistorikk" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "Fjern alle" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "Ring tilbake" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "Send" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "" - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "SIP Addresse" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "Vis kontaktens tilstedestatus" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "La denne kontakten se min tilstedestatus" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "Kontaktinformasjon" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "Overfører" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "I samtale" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "Varighet" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "Brukernavn:" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "Passord:" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Brukernavn" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Passord" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "Internet forbindelse:" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "Logg meg på automatisk" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "BrukerID" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "Innlogginsinformasjon" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "Fiber Kanal" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "Linphone avlusningsvindu" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "Standard" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "_Alternativer" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "Vis video av deg selv" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "_Hjelp" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "Vis avlusningsvindu" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "H_jemmeside" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "Sjekk _Oppdateringer" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "Sip adresse eller telefonnummer:" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "Start en ny samtale" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "Kontakter" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "Søk" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "Legg til kontakter fra katalogen" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "Legg til kontakt" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "Min nåværende identitet:" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "standard lydkort" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "ett lydkort" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "standard kamera" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "CIF" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "Lyd kodek" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "Video kodek" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "C" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "Innstillinger" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "Denne seksjonen velger SIP-addresse når du ikke bruker en SIP-konto" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "Vist navn (eks: Ola Nordmann):" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "Ditt brukernavn:" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "Din resulterende SIP addresse:" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "Standard identitet" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "Legg til" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "Rediger" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "Fjern" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "Proxy kontoer" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "Slett alle passord" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "Personvern" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "Behandle SIP-kontoer" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Ringelyd:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "Spesiell ALSA enhet (valgfritt):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Mikrofonenhet:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Ringe-enhet:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Avspillingsenhet:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Bruk ekko-kansellering" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Lyd" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Videoenhet:" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "0 betyr \"ubegrenset\"" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "Video" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "Maks opplastningshastighet i Kbit/sek:" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "Nedlastningsbegrensning i Kbit/sek:" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "" - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "Båndbreddekontrol" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "Multimediainnstillinger" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "Velg MTU (Maximum Transmission Unit):" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "Send DTMF som SIP-info" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "Transport" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "Lyd RTP/UDP:" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "Video RTP/UDP:" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "Tilkoblet Internett direkte" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "Bak NAT / Brannmur (bruk STUN for å avgjøre)" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "Offentlig IP-addresse:" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "STUN tjener:" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "NAT og Brannvegg" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "Nettverksinnstillinger" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Aktiver" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Deaktiver" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "Kodek" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "Språk" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "Vis avanserte innstillinger" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "Nivå" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "Brukergrensesnitt" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "Ferdig" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "Linphone - Autorisering kreves" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "Skriv inn passordet for domenet" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "" - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "Velkommen til brukerkontoveiviseren" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "Brukerkontoveiviser" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Takk. Ditt konto er nå satt opp og klart til bruk." - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "Linphone - Konfigurer en SIP konto" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "Din SIP identitet:" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "Ser ut som sip:@" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "sip:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "SIP Proxy addresse:" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "Ser ut som sip:" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "Registreringsfrekvens (sek.):" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "Route (valgfritt):" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "Publiser tilstedestatus" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "Konfigurer en SIP konto" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "Vennligst vent" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "Klar" - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "Tilknytter" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "Kunne ikke ringe" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "Beklager, du har nådd maksimalt antall samtidige samtaler" - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "Kontakter deg." - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr " og ba om autosvar." - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "Endrer ringeparametre..." - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "Tilkoblet" - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "Samtale avbrutt" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "Kunne ikke pause samtalen" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "Pauser nåværende samtale" - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "STUN oppslag pågår..." - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "" - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "Tilknyttet" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "Opptatt" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "Kommer plutselig tilbake" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "Borte" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "I telefonen" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "Ute til lunsj" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "Ikke forstyrr" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "Flyttet" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "Bruker en annen tjeneste" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "Frakoblet" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "Pågående" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "SIP proxy adressen du har angitt er ugyldig, den må begynne med \"sip:\" etterfult av vertsnavn." - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "SIP adressen du har angitt er feil. Adressen bør se ut som sip: brukernavn@domenenavn, f.eks sip:ola@eksempel.no" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "Ser etter telefonnummer for destinasjonen..." - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "Kan ikke tilkoble dette nummeret." - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "Ikke ikke logge inn som %s" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "" - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "Ringer hos motparten." - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "" - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "Tidlig media" - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "Samtale gjenopptatt." - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "" - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "" - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "" - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "" - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "" - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "Samtale avsluttet." - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "Brukeren er opptatt." - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "Brukeren er midlertidig ikke tilgjengelig." - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "Brukeren vil ikke bli forstyrret." - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "Samtale avvist." - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "" - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "Omdirigert" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "Samtale feilet." - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "Registrering hos %s lykkes." - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "Avregistrering hos %s lykkes." - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "ingen svar innen angitt tid" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "Registrering hos %s mislykkes: %s" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "" - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "" - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "Du har %i ubesvarte anrop." -msgstr[1] "Du har %i missade samtal" - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "" - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" diff --git a/po/nl.po b/po/nl.po deleted file mode 100644 index a833e03b7..000000000 --- a/po/nl.po +++ /dev/null @@ -1,2090 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -# Heimen Stoffels , 2015 -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: Dutch (http://www.transifex.com/belledonne-communications/linphone-gtk/language/nl/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: nl\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "%s bellen" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "SMS versturen aan %s" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "Recente gesprekken" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "Recent oproepen (%i)" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "n.v.t." - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "Afgebroken" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "Gemist" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "Geweigerd" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "%i minuut" -msgstr[1] "%i minuten" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "%i seconde" -msgstr[1] "%i seconden" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "%s\tKwaliteit: %s\n%s\t%s\t" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "%s\t%s" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "Vergadering" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "Ik" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "Het pixmap-bestand %s kon niet worden gevonden" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "" - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "loggen naar stdout om wat foutopsporingsinformatie te verkrijgen tijdens uitvoeren." - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "" - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "Pad naar een bestand om logbestanden heen te schrijven." - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "Linphone opstarten met uitgeschakelde video." - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "Alleen in het systeemvak opstarten, niet met venster en al." - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "adres om nu naar toe te bellen" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "Specificeer een werkmap (dit moet de basis van uw installatie zijn, bijv.: C:\\Program Files\\Linphone)" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "Configuratiebestand" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "Doorloop de audio-instelwizard" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "Draai een zelftest en exit 0 wanneer succesvol" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "" - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "Vul uw wachtwoord in voor gebruikersnaam %s\nop realm %s" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "Oproepfout" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "Oproep beëindigd" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "Inkomende oproep" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "Opnemen" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "Weigeren" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "Oproep gepauzeerd" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "door %s" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "%s stelt u voor om video in te schakelen. Wilt u dit accepteren?" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "Websitelink" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "%s (Standaard)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "We zijn overgeschakeld naar %s" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "Er zijn geluidskaarten aangetroffen op deze computer.\nU zult niet in staat zijn om audio-oproepen te ontvangen of versturen." - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "Een gratis SIP-videotelefoon" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "Toevoegen aan adresboek" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "Zoeken in de map %s" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "Ongeldig SIP-contactpersoon" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "Contactpersoon '%s' bewerken" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "Contactpersoon '%s' verwijderen" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "Chatgeschiedenis van '%s' verwijderen" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "Nieuw contactpersoon toevoegen vanuit de map %s" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "Naam" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "Frequentie (Hz)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "Status" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "IP-bitrate (kbit/s)" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "Argumenten" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "Ingeschakeld" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "Uitgeschakeld" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "Account" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "Engels" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "Frans" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "Zweeds" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "Italiaans" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "Spaans" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "Braziliaans Portugees" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "Pools" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "Duits" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "Russisch" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "Japans" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "Nederlands" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "Hongaars" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "Tjechisch" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "Chinees" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "Traditioneel Chinees" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "Noors" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "Hebreeuws" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "Servisch" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "U moet linphone herstarten om de nieuw geselecteerde taal toe te passen." - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "Geen" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "SRTP" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "DTLS" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "ZRTP" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "Er is een nieuwere versie beschikbaar op %s.\nWilt een webbrowser openen en deze downloaden?" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "U gebruikt de nieuwste versie." - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "Voornaam, Achternaam" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "Er is een fout opgetreden tijdens het communiceren met de server." - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "Bezig met verbinden..." - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "Verbonden" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "Bezig met ontvangen van gegevens..." - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "%i contactpersoon gevonden" -msgstr[1] "%i contactpersonen gevonden" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "" - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "#%i bellen" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "Overschakelen naar gesprek #%i met %s" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "Niet in gebruik" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "ICE is niet geactiveerd" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "ICE is mislukt" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "ICE is bezig" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "Die door één of meer NATs gaan" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "Direct" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "Via een relay-server" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "uPnP is niet geactiveerd" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "uPnP is bezig" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "uPnP is niet beschikbaar" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "uPnP wordt uitgevoerd" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "uPnP is mislukt" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "Direct of via een server" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "download: %f\nupload: %f (kbit/s)" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "%ix%i @ %f fps" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "%.3f seconden" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "Ophangen" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "Bezig met bellen..." - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "Inkomende oproep" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "goed" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "gemiddeld" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "slecht" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "erg slecht" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "verschrikkelijk" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "niet beschikbaar" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "Beveiligd door SRTP" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "Beveiligd door DTLS" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "Beveiligd door ZRTP - [authenticatiesleutel: %s]" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "Instellen als niet-geverifieerd" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "Instellen als geverifieerd" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "In een vergadering" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "In gesprek" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "Gepauzeerde oproep" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "Oproep is beëindigd." - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "De overdracht is bezig" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "De overdracht is voltooid." - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "De overdracht is mislukt." - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "Hervatten" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "Pauzeren" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "Bezig met opnemen naar%s %s" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "(Gepauzeerd)" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "Vul uw inloggegevens in voor %s" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "bezig met ophalen van %s" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "Het downloaden van de externe configuratie van %s is mislukt." - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "Er is geen stem gedetecteerd" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "Te zacht" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "Goed" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "Te hard" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "Heeft u drie pieptonen gehoord?" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "De geluidsvoorkeuren zijn niet gevonden" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "Het systeemgeluidspaneel kon niet worden gestart" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "Welkom!\nDeze instelwizard zal u begeleiden bij het instellen van de audio-instellingen van Linphone" - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "Opname-apparaat" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "Opgenomen volume" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "Geen stem" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "Systeemgeluidsinstellingen" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "Afspeelapparaat" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "Drie pieptonen afspelen" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "Klik op de opnameknop en zeg enkele woorden" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "Luister naar uw opgenomen stem" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "Opnemen" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "Afspelen" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "Laten we nu Linphone opstarten" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "Audio-instelwizard" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "Audio-instelwizard" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "Kalibratie van het microfoonbereik" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "Kalibratie van het luidsprekervolume" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "Opnemen en afspelen" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "Bezig met vernietigen" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "Over Linphone" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "(C) Belledonne Communications, 2010\n" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "Een internetvideotelefoon gebruikmakende van het standaard SIP (rfc3261) protocol." - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "fr: Simon Morlat\nen: Simon Morlat and Delphine Perreau\nit: Alberto Zanoni \nde: Jean-Jacques Sarton \nsv: Daniel Nylander \nes: Jesus Benitez \nja: YAMAGUCHI YOSHIYA \npt_BR: Rafael Caesar Lenzi \npl: Robert Nasiadek \ncs: Petr Pisar \nhu: anonymous\nhe: Eli Zaretskii \n" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "Bellernaam" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "Gespreksgeschiedenis" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "Alles wissen" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "Terugbellen" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "Verzenden" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "Vergadering beëindigen" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "" - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "SIP-adres" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "De aanwezigheidsstatus van dit contactpersoon weergeven" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "Toestaan dat deze contactpersoon mijn aanwezigheidsstatus kan weergeven" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "Contactinformatie" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "SIP" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "Deze oproep opnemen naar een audiobestand" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "Video" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "Dempen" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "Overdracht" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "In gesprek" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "Duur" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "Waardering van de gesprekskwaliteit" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "Gebruikersnaam:" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "Wachtwoord:" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Gebruikersnaam" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Wachtwoord" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "Internetverbinding:" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "Automatisch inloggen" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "Gebruikersidentificatie" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "Inloginformatie" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "Welkom!" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "Fiber-kanaal" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "Linphone-foutopsporingsvenster" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "Scroll naar het einde" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "Standaard" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "Verwijderen" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "_Opties" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "Configuratie-URI instellen" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "Video altijd starten" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "Eigen weergave inschakelen" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "_Hulp" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "Foutopsporingsvenster weergeven" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "_Website" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "Controleren op _updates" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "Account-instelwizard" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "SIP-adres of telefoonnummer:" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "Een nieuw gesprek beginnen" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "Contactpersonen" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "Zoeken" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "Voeg contactpersonen toe uit map" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "Contactpersoon toevoegen" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "Mijn huidige identiteit:" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "anoniem" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "GSSAPI" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "standaard geluidskaart" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "een geluidskaart" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "standaard camera" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "CIF" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "Audio-codecs" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "Video-codecs" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "C" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "Instellingen" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "Uw weergavenaam (bijv.: Jan Noniem):" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "Uw gebruikersnaam:" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "Standaardidentiteit" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "Instelhulp" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "Toevoegen" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "Bewerken" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "Verwijderen" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Belgeluid:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "ALSA speciaal apparaat (optioneel)" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Opnameapparaat:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Belapparaat:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Afspeelapparaat:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Echo-onderdrukking inschakelen" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Audio" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Videoingang-apparaat:" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "Videouitgangsmethode:" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "Cameravoorbeeld weergeven" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "Video" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "" - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "Multimedia-instellingen" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "Maximale Transmissie-unit instellen:" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "DTMF's als SIP-informatie versturen" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "Overdracht" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "SIP/UDP-poort" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "Willekeurig" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "SIP/TCP-poort" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "AUDIO RTP/UDP:" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "Vastgezet" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "Video RTP/UDP:" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "Tunnel" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "DSCP-velden" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "Netwerkprotocol en -poorten" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "Directe verbinding met het internet" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "Achter een NAT / Firewall (specificeer de gateway IP)" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "Openbaar IP-adres:" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "Stun-server" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "NAT en Firewall" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "Mediaversleutelingstype" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "Mediaversleuteling is vereist" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "Netwerkinstellingen" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Aan" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Uit" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "Linphone - Authenticatie is vereist" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "Vul het domeinnaamwachtwoord in" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "" - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "SIP-account-instelwizard" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "Welkom!\nDeze instelwizard zal u begeleiden bij het gebruiken van een SIP-account voor oproepen." - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "Welkom bij de account-instelwizard" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "Creëer een account op linphone.org" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "Ik heb al een linphone.org-account en wil deze graag gebruiken" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "Ik heb al een SIP-account en wil deze graag gebruiken" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "Ik wil een externe URI-configuratie opgeven" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "Account-instelwizard" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "Gebruikersnaam*" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "Wachtwoord*" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "Domeinnaam*" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "Proxy" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "Uw account instellen (stap 1/1)" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "Vul uw linphone.org-gebruikersnaam in" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "Vul uw SIP-gebruikersnaam in (stap 1/1)" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "(*) Verplichte velden" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "E-mailadres: (*)" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "Gebruikersnaam: (*)" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "Wachtwoord: (*)" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "Bevestig uw wachtwoord: (*)" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "Houdt me op de hoogte van linphone-updates" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "Vul uw accountinformatie in (stap 1/2)" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "Valideer uw account door te klikken op de link die we zojuist naar uw e-mailadres hebben verstuurd.\nKom dan terug naar dit venster en klik op de knop Volgende." - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "Geldigheid (stap 2/2)" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "Er is een fout opgetreden: uw account is niet gevalideerd, de gebruikersnaam wordt al door iemand anders gebruikt of de server is onbereikbaar.\nGa terug en probeer het opnieuw." - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "Fout" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Bedankt. Uw account is nu ingesteld en klaar voor gebruik." - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "Linphone - Een SIP-account instellen" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "Uw SIP-identiteit:" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "Lijkt op:@" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "sip:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "SIP-proxyadres:" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "Lijkt op sip:" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "Registratieduur (sec):" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "Contactparameters (optioneel):" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "AVPF regulier RTCP-tussenpose (sec):" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "Route (optioneel):" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "Overdracht" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "Registreren" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "Aanwezigheidsinformatie publiceren" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "AVPF inschakelen" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "Een SIP-account instellen" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "Gereed." - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "Verbinden" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "" - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr "" - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "" - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "Verbonden." - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "" - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "STUN adres wordt opgezocht..." - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "" - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "Aanwezig" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "Bezet" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "Afwezig" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "Niet storen" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "" - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "Zoekt de lokatie van het telefoonnummer..." - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "Kon dit nummer niet vinden." - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "" - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "" - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "" - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "" - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "" - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "" - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "" - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "" - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "" - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "" - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "Oproep beeindigd." - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "Gebruiker is bezet." - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "Gebruiker is tijdelijk niet beschikbaar." - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "De gebruiker wenst niet gestoord te worden." - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "Oproep geweigerd." - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "" - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "" - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "Registratie op %s gelukt." - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "" - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "" - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "" - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "" -msgstr[1] "" - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "" - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" diff --git a/po/pl.po b/po/pl.po deleted file mode 100644 index 00d4e22cd..000000000 --- a/po/pl.po +++ /dev/null @@ -1,2093 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: Polish (http://www.transifex.com/belledonne-communications/linphone-gtk/language/pl/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: pl\n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "Nie można znaleźć pixmapy: %s" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "" - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "" - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "" - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "" - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "" - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "" - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "" - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "" - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "Nazwa" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "Jakość (Hz)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "Status" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "Parametr" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "Włączone" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "Wyłączone" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "" - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "" - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "" - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "" - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "" - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "" - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "" - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "" - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "" - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "" - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "" - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "" - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "" - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "" - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "SIP" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "" - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Włączony" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Wyłącz" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "" - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "" - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "sip:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "" - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "" - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr "" - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "" - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "Połączony" - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "" - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "" - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "" - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "Zajęty" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "Nie przeszkadzać" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "" - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "" - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "" - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "" - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "" - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "" - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "" - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "" - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "" - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "" - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "" - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "" - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "" - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "" - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "Osoba jest zajęta." - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "Osoba jest tymczasowo niedostępna." - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "Osoba nie chce, aby jej przeszkadzać." - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "Rozmowa odrzucona." - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "" - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "" - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "" - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "" - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "" - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "" - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "" - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" diff --git a/po/pt_BR.po b/po/pt_BR.po deleted file mode 100644 index 2fa82eac4..000000000 --- a/po/pt_BR.po +++ /dev/null @@ -1,2089 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: Portuguese (Brazil) (http://www.transifex.com/belledonne-communications/linphone-gtk/language/pt_BR/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: pt_BR\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "" -msgstr[1] "" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "" -msgstr[1] "" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "Não é possível achar arquivo pixmap: %s" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "" - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "" - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "" - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "" - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "" - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "" - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "" - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "Camadas recebidas" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "" - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "Nome" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "Taxa (Hz)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "Parâmetros" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "Ativado" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "Desativado" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "" - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "Nenhum" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "" - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "" - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "" - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "" - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "" -msgstr[1] "" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "" - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "" - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "" - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "" - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "" - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "" - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "" - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "" - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "" - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "Editar" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "Remover" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "" - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Ativado" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Desativar" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "" - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "" - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "Rota (opcional):" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "" - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "" - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr "" - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "" - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "Conectado." - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "" - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "" - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "" - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "Ocupado" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "Não perturbe" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "" - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "Procurando por telefone de destino..." - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "Não foi possível encontrar este número." - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "" - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "" - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "" - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "" - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "" - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "" - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "" - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "" - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "" - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "" - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "" - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "Usuário está ocupado." - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "Usuário está temporáriamente indisponível." - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "" - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "" - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "" - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "" - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "" - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "" - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "" - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "" - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "" -msgstr[1] "" - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "" - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" diff --git a/po/quot.sed b/po/quot.sed deleted file mode 100644 index 0122c4631..000000000 --- a/po/quot.sed +++ /dev/null @@ -1,6 +0,0 @@ -s/"\([^"]*\)"/“\1”/g -s/`\([^`']*\)'/‘\1’/g -s/ '\([^`']*\)' / ‘\1’ /g -s/ '\([^`']*\)'$/ ‘\1’/g -s/^'\([^`']*\)' /‘\1’ /g -s/“”/""/g diff --git a/po/remove-potcdate.sin b/po/remove-potcdate.sin deleted file mode 100644 index 2436c49e7..000000000 --- a/po/remove-potcdate.sin +++ /dev/null @@ -1,19 +0,0 @@ -# Sed script that remove the POT-Creation-Date line in the header entry -# from a POT file. -# -# The distinction between the first and the following occurrences of the -# pattern is achieved by looking at the hold space. -/^"POT-Creation-Date: .*"$/{ -x -# Test if the hold space is empty. -s/P/P/ -ta -# Yes it was empty. First occurrence. Remove the line. -g -d -bb -:a -# The hold space was nonempty. Following occurrences. Do nothing. -x -:b -} diff --git a/po/ru.po b/po/ru.po deleted file mode 100644 index 294f2f35a..000000000 --- a/po/ru.po +++ /dev/null @@ -1,2102 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -# AlexL , 2014 -# AlexL , 2014-2016 -# AlexL , 2014 -# Maxim Prokopyev , 2010 -# Simon Morlat , 2001 -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 12:36+0000\n" -"Last-Translator: AlexL \n" -"Language-Team: Russian (http://www.transifex.com/belledonne-communications/linphone-gtk/language/ru/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ru\n" -"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "Звонок %s" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "Послать текст для %s" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "Добавить %s в мой список контактов" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "Последние звонки" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "Последние вызовы (%i)" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "—" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "Прервано" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "Пропущено" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "Отклонено" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "%i минута" -msgstr[1] "%i минуты" -msgstr[2] "%i минут" -msgstr[3] "%i минут" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "%i секунда" -msgstr[1] "%i секунды" -msgstr[2] "%i секунд" -msgstr[3] "%i секунд" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "%s\tКачество: %s\n%s\t%s\t" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "%s\t%s" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "Конференция" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "Мне" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "Невозможно найти графический файл: %s" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "Отправка..." - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "Сообщение не отправилось" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "Копировать" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "Вывод некоторой отладочной информации на устройство стандартного вывода во время работы." - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "показать версию и выйти." - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "Путь к файлу для записи логов." - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "Запуск linphone с видео отключен." - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "Показывать только в системном лотке, не запуская главное окно." - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "Адрес для звонка прямо сейчас." - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "Определить рабочий каталог (относительно каталога установки, например: c:\\Program Files\\Linphone)" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "Файл конфигурации" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "Запустить помощника аудио" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "Запустить самотест и выйти при успехе со статусом 0" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "%s хочет добавить Вас в его/её список контактов.\nВы бы добавили его/её в свой список контактов и позволили ему/ей видеть ваш статус присутствия?\nЕсли вы ответите нет, то этот человек будет временно занесён в чёрный список." - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "Пожалуйста, введите пароль для пользователя %s\n для реалм (рилм) %s:" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "Ошибка звонка" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "Звонок окончен" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "Входящий звонок" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "Ответ" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "Отклонить" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "Звонок приостановлен" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "%s" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "%s предложил запустить видео. Вы принимаете?" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "Домашняя страница" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "Видео интернет телефон" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "%s (по умолчанию)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "Мы передали в %s" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "Звуковые карты не были обнаружены на этом компьютере.\nВы не сможете отправлять или получать аудио звонки." - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "Свободный SIP видео-телефон" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "Привет\n" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "Добавить в адресную книгу" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "Поиск в директории %s" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "Неверный sip контакт!" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "Добавить новый контакт" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "Редактировать контакт '%s'" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "Удалить контакт '%s'" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "Удалить историю чата для '%s'" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "Добавить новый контакт из директории '%s'" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "Имя" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "Частота (Гц)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "Статус" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "IP битрейт (КБит/сек)" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "Параметры" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "Разрешён" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "Не разрешён" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "Учётная запись" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "Английский" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "Французский" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "Шведский" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "Итальянский" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "Испанский" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "Бразильский португальский" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "Польский" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "Немецкий" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "Русский" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "Японский" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "Датский" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "Венгерский" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "Чешский" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "Китайский" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "Традиционный китайский" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "Норвежский" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "Иврит" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "Сербский" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "Арабский" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "Турецкий" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "Вы должны перезагрузить linphone для того, чтобы языковые настройки вступили в силу." - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "Нет" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "SRTP" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "DTLS" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "ZRTP" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "Доступна новая версия с %s.\nОткрыть браузер для загрузки?" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "Вы работаете с последней версией." - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "Имя, Фамилия" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "Ошибка связи с сервером" - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "Подключение..." - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "Соединено" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "Получение данных..." - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "Найден %i контакт" -msgstr[1] "Найдено %i контакта" -msgstr[2] "Найдено %i контактов" -msgstr[3] "Найдено %i контактов" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "Имя пользователя уже используется!" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "Не удалось проверить наличие имени пользователя. Пожалуйста, повторите попытку позднее." - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "Звонок #%i" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "Передача позвонить #%i с %s" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "Не используется" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "ICE не активировано" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "Неудача ICE" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "ICE в прогрессе" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "Пройти через один или несколько NAT" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "Напрямую" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "Через сервер ретрансляции" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "uPnP не активировано" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "uPnP в прогрессе" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "uPnp недоступен" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "uPnP выполняется" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "Неудача uPnP" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "Напрямую или через сервер" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "загрузка: %f\nотдача: %f (КБит/сек)" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "%ix%i @ %f кадр/сек" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "%.3f секунд" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "Повесить трубку" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "Звоним..." - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "00:00:00" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "Входящий звонок" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "хороший" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "средний" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "плохой" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "очень плохой" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "совсем плохой" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "недоступен" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "Защищённые с помощью SRTP" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "Защищённые с помощью DTLS" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "Защищённые с помощью ZRTP - [знак аутентификации: %s]" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "Установить непроверенный" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "Установить проверенный" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "В конференции" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "Звоним" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "Звонок приостановлен" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "Звонок закончен." - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "Передача в прогрессе" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "Передача завершена." - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "Передача неудачна." - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "Продолжить" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "Пауза" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "Записывается в\n%s %s" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "(Пауза)" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "Пожалуйста, введите информацию для входа %s:" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "получение от %s" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "Загрузка удалённой конфигурации из %s неудачна." - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "Голос не обнаружен" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "Слишком тихо" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "Хорошо" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "Слишком громко" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "Вы слышали 3 сигнала?" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "Настройки звука не найдены" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "Не удаётся запустить системное управление звуком" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "Добро пожаловать!\nЭтот ассистент поможет вам настроить настройки аудио для Linphone." - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "Устройство захвата" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "Уровень записи" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "Нет голоса" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "Системные настройки звука" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "Устройство воспроизведения" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "Проиграть три сигнала" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "Нажмите кнопку записи и скажите несколько слов" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "Прослушайте ваш записанный голос" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "Запись" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "Воспроизведение" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "Давайте сейчас запустим linphone" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "Помощник аудио" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "Помощник аудио" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "Калибровка усиления микрофона" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "Калибровка громкости динамика" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "Записать и проиграть" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "Прерывание" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "О Linphone" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "(C) Belledonne Communications, 2010\n" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "Интернет видео телефон, использующий стандарт протокола SIP (rfc3261)." - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "fr: Simon Morlat\nen: Simon Morlat and Delphine Perreau\nit: Alberto Zanoni \nde: Jean-Jacques Sarton \nsv: Daniel Nylander \nes: Jesus Benitez \nja: YAMAGUCHI YOSHIYA \npt_BR: Rafael Caesar Lenzi \npl: Robert Nasiadek \ncs: Petr Pisar \nhu: anonymous\nhe: Eli Zaretskii \n" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "Поиск контактов в директории" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "Добавить в мой список" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "Поиск кого-нибудь" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "Имя вызываемого" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "История звонков" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "Очистить всё" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "Позвонить повторно" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "Вызов статистики" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "Аудио кодек" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "Видео кодек" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "Использование пропускной способности аудио IP" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "Подключение медиа-аудио" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "Использование пропускной способности видео IP" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "Подключение медиа-видео" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "Округлять время в действии" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "Получено разрешение видео" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "Разрешение видео отправлено" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "Профиль RTP" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "Вызов статистики и информации" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "Отправить" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "Конец конференции" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "Указание удалённой конфигурации URI" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "Этот диалог позволяет установить HTTP или HTTPS адрес, когда конфигурация будет получена при запуске.\nПожалуйста, введите или измените настройки URI ниже. После нажатия OK linphone автоматически перезагрузится чтобы получить и учесть новую конфигурацию в учётной записи." - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "SIP адрес" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "Показывать этому контакту статус присутствия" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "Разрешить этому контакту видеть мой статус присутствия" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "Контактная информация" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "Настройки DSCP" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "SIP" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "Аудио поток RTP" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "Видео поток RTP" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "Установить значения DSCP (в шестнадцатеричном формате)" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "Щёлкните здесь чтобы установить громкость динамиков" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "Записать этот вызов в аудио файл" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "Видео" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "Без звука" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "Передача" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "Входящий звонок" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "Продолжительность" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "Вызвать рейтинг качества" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "Настройки LDAP" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "Адрес сервера:" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "Метод аутентификации:" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "Имя пользователя:" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "Пароль:" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "Использовать соединение TLS" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "Ещё недоступно" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "Соединение" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "Привязать DN" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "Имя для аутентификации" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "Реалм (рилм)" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "Базовый объект:" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "Фильтр (%s для имени):" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "Атрибут имени:" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "Атрибут SIP-адреса:" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "Атрибуты для запроса:" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "Поиск" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "Таймаут для поиска:" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "Максимум результатов:" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "Следовать алиасам" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "Разное" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "АНОНИМ" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "ПРОСТОЙ" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "ДАЙДЖЕСТ-MD5" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "NTLM" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Имя пользователя" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Пароль" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "Интернет-соединение:" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "Входить автоматически" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "Идентификатор пользователя" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "Информация для входа" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "Добро пожаловать!" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "Оптоволоконный канал" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "Окно отладки linphone" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "Прокрутка в конец" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "По умолчанию" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "Удалить" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "_Опции" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "Установить конфигурацию URI" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "Всегда запускать видео" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "Показать окно видео" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "Показать клавиатуру" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "Импорт контактов из vCards" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "Экспорт контактов как vCards" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "_Помощь" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "Показать окно отладки" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "_Домашняя страница" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "Проверить _обновления" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "Помощник учётной записи" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "SIP-адрес или номер телефона:" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "Начать новый звонок" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "Контакты" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "Поиск" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "Добавить контакты из директории" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "Добавить контакт" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "Очистить историю звонков" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "Мой текущий идентификатор:" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "Автоответ включен" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "аноним" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "GSSAPI" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "звуковая карта по умолчанию" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "звуковая карта" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "камера по умолчанию" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "CIF" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "Аудио кодеки" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "Видео кодеки" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "C" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "SIP (UDP)" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "SIP (TCP)" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "SIP (TLS)" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "Настройки" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "Эта секция определяет ваш SIP адрес, когда вы не используете учётную запись SIP" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "Отображаемое имя (например: Иван Сидоров):" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "Ваше имя пользователя:" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "Ваш результирующий SIP адрес:" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "Идентификатор по умолчанию" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "Мастер" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "Добавить" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "Редактировать" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "Удалить" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "Учётные записи" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "Стереть все пароли" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "Секретность" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "Автоматический ответ при получении звонка" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "Задержка перед ответом (мс)" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "Автоответ" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "Управление учётными записями SIP" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Мелодия звонка:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "Специальное устройство ALSA (опционально)" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Устройство захвата:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Устройство звонка:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Устройство воспроизведения:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Разрешить подавление эха" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Аудио" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Устройство для вывода видео:" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "Предпочтительное разрешение видео:" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "Метод вывода видео:" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "Показать предпросмотр с камеры" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "Предустановки видео:" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "Предпочтительная частота кадров:" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "0 означает \"безлимитный\"" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "Видео" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "Ограничение исходящего потока КБит/сек:" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "Ограничение скорости входящего потока КБит/сек:" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "Разрешить адаптивное управление скоростью" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "Адаптивное управление скоростью - это технология динамического угадывания доступной пропускной способности во время звонка." - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "Пропускная способность" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "Настройки мультимедиа" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "Установить MTU (максимально передаваемый блок):" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "Отправлять DTFM как SIP-информацию" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "Разрешить IPv6" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "Транспорт" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "Порт SIP/UDP" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "Случайно" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "Порт SIP/TCP" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "Аудио RTP/UDP:" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "Фиксированный" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "Видео RTP/UDP:" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "Тунель" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "Поля DSCP" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "Сетевые протоколы и порты" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "Прямое подключение к интернет" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "За NAT / брандмауэром (указать IP шлюза)" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "За NAT / брандмауэром (использовать STUN)" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "За NAT / брандмауэром (использовать ICE)" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "За NAT / брандмауэром (использовать uPnP)" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "Выделенный (публичный) IP-адрес:" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "STUN сервер:" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "NAT и брандмауэр" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "Тип медиа-шифрования" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "Использовать лайм для исходящих сообщений чата" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "Медиа-шифрование обязательно" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "Обязательный" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "Предпочтительный" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "Шифрование" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "Настройки сети" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Разрешить" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Выключить" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "Аудио кодеки" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "Видео кодеки" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "Кодеки" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "Язык" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "Показать дополнительные настройки" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "Уровень" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "Пользовательский интерфейс" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "Установка учётной записи LDAP" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "LDAP" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "Готово" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "Linphone - необходима регистрация" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "Введите пароль для домена" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "Конфигурирование..." - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "Пожалуйста, подождите пока получается конфигурация с сервера..." - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "Помощник настройки учётной записи SIP" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "Добро пожаловать!\nЭтот ассистент поможет вам использовать SIP аккаунт для ваших звонков." - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "Добро пожаловать в помощник настройки учётной записи" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "Создать учётную запись на linphone.org" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "Я уже имею учётную запись на linphone.org и только хочу использовать её" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "Я уже имею учётную запись sip и только хочу использовать её" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "Я хочу указать удалённую конфигурацию URI" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "Помощник настройки учётной записи" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "Введите вашу информацию об учётной записи" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "Имя пользователя*" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "Пароль*" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "Домен*" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "Прокси" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "Настроить вашу учётную запись (шаг 1/1)" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "Введите ваше имя пользователя для linphone.org" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "Введите ваше sip имя пользователя (шаг 1/1)" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "(*) Обязательные поля" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "Электронная почта: (*)" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "Имя пользователя: (*)" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "Пароль: (*)" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "Подтвердите ваш пароль: (*)" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "Информировать об обновлениях linphone" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "Введите информацию об учётной записи (шаг 1/2)" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "Ваша учётная запись создаётся, пожалуйста, подождите." - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "Создание учётной записи в прогрессе" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "Пожалуйста, подтвердите вашу учётную запись, щёлкнув на ссылку, которую вы только\nчто получили по электронной почте. Затем вернитесь сюда и нажмите кнопку Далее." - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "Подтверждение (шаг 2/2)" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "Проверяется действительность вашей учётной записи, пожалуйста, подождите." - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "Проверка действительности учётной записи в прогрессе" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "Ошибка, учётная запись не подтверждена, имя пользователя уже используется или\nсервер недоступен. Пожалуйста, зайдите снова и попробуйте ещё раз." - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "Ошибка" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Спасибо! Учётная запись успешно настроена и готова к использованию." - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "Linphone - настроить учётную запись SIP" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "Ваш идентификатор SIP:" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "Выглядит как sip:<имя_пользователя>@<домен>" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "sip:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "Адрес SIP прокси:" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "Выглядит как sip:<прокси имя_хоста>" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "Продолжительность регистрации (сек):" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "Параметры контакта (опционально):" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "AVPF постоянный интервал RTCP (сек):" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "Маршрут (опционально):" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "Транспорт" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "Регистрация" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "Опубликовать статус присутствия" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "Разрешить AVPF" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "Настроить учётную запись SIP" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "Настроить тунель VoIP" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "Хост" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "Порт" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "Конфигурировать тунель" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "Конфигурировать http прокси (опционально)" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "Пожалуйста, подождите" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "Готов" - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "Конфигурирование" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "Соединение" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "Невозможно позвонить" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "К сожалению, мы достигли максимального количества одновременных звонков" - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "контактирует с вами" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr "и спросил автоматический ответ." - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "Изменение параметров звонка..." - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "Соединён." - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "Звонок отменён" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "Невозможно приостановить звонок" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "Приостановка текущего звонка..." - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "Идет поиск STUN..." - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "Сбор локальных кандидатов ICE в прогрессе..." - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "В сети" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "Занят" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "Скоро вернусь" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "Нет на месте" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "На телефоне" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "На обеде" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "Не беспокоить" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "Отошёл" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "Разговариваю" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "Не в сети" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "В ожидании" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "Отдых" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "Неизвестный статус" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "Введённый SIP-адрес прокси является недействительным, он должен начинаться с \"sip:имя_хоста\"" - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "Неверные параметры для sip идентификации\nДолжно выглядеть как sip:имя_пользователя@домен_прокси, как например, sip:alice@example.net" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "Поиск назначения для телефонного номера.." - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "Не получилось принять решение по этому номеру." - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "Невозможно зайти как: %s" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "Обновление %s..." - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "Дистанционный звонок." - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "Дистанционный звонок..." - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "Предответное проключение." - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "На звонок ответил %s" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "Звонок возобновлён." - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "Несовместимость, проверьте кодеки или параметры безопасности..." - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "Несовместимость медиа-параметров." - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "Мы возобновили." - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "Мы приостановлены другой стороной." - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "Звонок был дистанционно обновлён." - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "Звонок прерван." - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "Пользователь занят." - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "Пользователь временно недоступен." - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "Пользователь не хочет чтобы его беспокоили." - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "Звонок отклонён." - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "Таймаут запроса." - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "Переадресован" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "Звонок не удался." - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "Регистрация на %s прошла успешно." - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "Отмена регистрации на %s завершена." - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "время ожидания истекло" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "Регистрация на %s не удалась: %s" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "Сервис недоступен, повтор" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "Маркер проверки подлинности: %s" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "Параметры звонка не были изменены: %s." - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "Параметры звонка были успешно изменены." - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "У вас %i пропущенный вызов." -msgstr[1] "У вас %i пропущенных вызова." -msgstr[2] "У вас %i пропущенных вызов." -msgstr[3] "У вас %i пропущенных вызов." - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "прервано" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "завершено" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "пропущено" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "неизвестно" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "%s в %s\nОт: %s\nДо: %s\nСтатус: %s\nПродолжительность: %i мин %i сек\n" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "Исходящий вызов" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "Невозможно воспроизвести %s." - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "Сделать скриншот" diff --git a/po/sr.po b/po/sr.po deleted file mode 100644 index eb96493a2..000000000 --- a/po/sr.po +++ /dev/null @@ -1,2094 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -# Мирослав Николић , 2014 -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: Serbian (http://www.transifex.com/belledonne-communications/linphone-gtk/language/sr/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: sr\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "Позови „%s“" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "Пошаљи текст за %s" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "Додајте „%s“ на списак контаката" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "Скорашњи позиви" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "Недавни позиви (%i)" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "н/д" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "Прекинут" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "Пропуштен" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "Одбијен" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "%i минут" -msgstr[1] "%i минута" -msgstr[2] "%i минута" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "%i секунда" -msgstr[1] "%i секунде" -msgstr[2] "%i секунди" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "%s\tКвалитет: %s\n%s\t%s\t" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "%s\t%s" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "Конференција" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "Ја" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "Не могу да пронађем датотеку сличице: %s" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "Шаљем..." - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "Порука није послата" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "Умножи" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "бележи на стандардни излаз неке податке прочишћавања док ради." - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "приказује издање и излази." - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "путања до датотеке за уписивање дневника." - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "Покреће линфон са искљученим видеом." - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "Покреће се само у системској фиоци, не приказује главно сучеље." - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "адреса за позивање управо сада" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "Наводи радни директоријум (треба да буде основа инсталације, нпр: „c:\\Program Files\\Linphone“)" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "Датотека подешавања" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "Покреће помоћника звука" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "Покреће самоиспробавање и излази 0 ако је успешно" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "%s жели да вас дода на свој списак контакта.\nДа ли желите да га/је додате на ваш списак контакта и да му/јој омогућите да види ваше стање присуства?\nАко одговорите негативно, ова особа ће тренутно бити стављена на списак забрањених." - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "Унесите вашу лозинку за корисничко име %s\n на подручју %s:" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "Грешка позива" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "Позив је завршен" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "Долазни позив" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "Јави се" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "Одбиј" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "Позив је заустављен" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "од %s" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "%s предлаже да започнете видео. Да ли прихватате ?" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "Веза веб сајта" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Линфон" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "Интернетски видео телефон" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "%s (основно)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "Преселили смо се на %s" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "Ниједна звучна картица није откривена на овом рачунару.\nНећете бити у могућности да шаљете или да примате звучне позиве." - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "Слободан СИП телефон са снимком" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "Здраво\n" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "Додајте у адресар" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "Тражи у директоријуму „%s“" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "Неисправан сип контакт !" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "Додај нови контакт" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "Уредите контакт „%s“" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "Обришите контакт „%s“" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "Обришите историјат ћаскања за „%s“" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "Додајте нови контакт из директоријума „%s“" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "Име" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "Проток (Hz)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "Стање" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "Проток бита ИП-а (kbit/s)" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "Параметри" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "Укључено" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "Искључено" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "Налог" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "Енглески" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "Француски" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "Шведски" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "Италијански" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "Шпански" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "Бразилски португалски" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "Пољски" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "Немачки" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "Руски" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "Јапански" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "Холандски" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "Мађарски" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "Чешки" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "Кинески" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "Традиционални кинески" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "Норвешки" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "Јеврејски" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "Српски" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "Арапски" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "Турски" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "Треба поново да покренете линфон да би нови изабрани језик ступио у дејство." - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "Ништа" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "СРТП" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "ДТЛС" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "ЗРТП" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "Новије издање је доступно са „%s“.\nДа ли желите да отворите прегледник и да га преузмете ?" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "Радите на најновијем издању." - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "Име и презиме" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "Грешка у коминикацији са сервером." - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "Повезујем се..." - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "Повезан сам" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "Примам податке..." - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "Нашао сам %i контакт" -msgstr[1] "Нашао сам %i контакта" -msgstr[2] "Нашао сам %i контаката" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "Корисничко име је већ у употреби!" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "Нисам успео да проверим доступност корисничког имена. Касније покушајте опет." - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "Позив бр. %i" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "Пребаци позив #%i са %s" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "Не користи се" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "ИЦЕ није покренут" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "ИЦЕ није успео" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "ИЦЕ је у току" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "Пролазим кроз један или више НАТ-са" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "Непосредно" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "Преко преносног сервера" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "уПнП није покренут" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "уПнП је у току" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "уПнП није доступан" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "уПнП ради" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "уПнП није успео" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "Непосредно или кроз сервер" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "преузимање: %f\nотпремање: %f (kbit/s)" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "%ix%i @ %f к/с" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "%.3f секунде" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "Прекини" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "Позивам..." - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "00:00:00" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "Долазни позив" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "добро" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "просечно" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "оскудно" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "јадно" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "много лоше" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "недоступно" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "Осигурано СРТП-ом" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "Осигурано ДТЛС-ом" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "Осигурано ЗРТП-ом [потврђивање идентитета: %s]" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "Непроверено подешавање" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "Проверено подешавање" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "На конференцији" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "У позиву" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "Заустављен позив" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "Позив је завршен." - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "Пренос је у току" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "Пренос је обављен." - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "Пренос није успео." - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "Настави" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "Застани" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "Снимам у\n%s %s" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "(Паузирано)" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "Унесите податке пријављивања за %s" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "довлачим са „%s“" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "Преузимање удаљеног подешавања са „%s“ није успело." - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "Глас није откривен" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "Сувише низак" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "Добар" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "Сувише гласан" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "Да ли сте чули три писка ?" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "Нисам пронашао поставке звука " - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "Не могу да покренем управљање звуком система " - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "Добро дошли!\nОвај помоћник ће вам помоћи да подесите поставке звука за Линфон" - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "Уређај за снимање" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "Снимљени волумен" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "Нема гласа" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "Поставке звука система" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "Уређај за пуштање" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "Пусти три писка" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "Притисните дугме за снимање и реците нешто" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "Слушајте ваш снимљени глас" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "Сними" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "Пусти" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "Хајде сада да покренемо Линфон" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "Помоћник звука" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "Помоћник звука" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "Дотеривање појачања микрофона" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "Дотеривање јачине звука звучника" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "Снимите и пустите" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "Завршавам" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "О Линфону" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "(C) Беледоне комуникације, 2010\n" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "Интернет телефон са снимком који користи уобичајени СИП протокол (rfc3261)." - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "fr: Simon Morlat\nen: Simon Morlat and Delphine Perreau\nit: Alberto Zanoni \nde: Jean-Jacques Sarton \nsv: Daniel Nylander \nes: Jesus Benitez \nja: YAMAGUCHI YOSHIYA \npt_BR: Rafael Caesar Lenzi \npl: Robert Nasiadek \ncs: Petr Pisar \nhu: anonymous\nhe: Eli Zaretskii \nsr: Мирослав Николић \n" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "Потражите пријатеље у директоријуму" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "Додај на мој списак" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "Потражите неког" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "Име позивника" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "Историјат позива" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "Очистите све" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "Повратни позив" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "Статистика позива" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "Звучни кодек" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "Видео кодек" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "Искоришћеност ИП пропусног опсега звука" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "Повезивост медија звука" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "Искоришћеност ИП пропусног опсега снимка" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "Повезивост медија снимка" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "Време повратног путовања" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "Примљена резолуција снимка" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "Послата резолуција снимка" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "РТП профил" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "Статистика позива и подаци" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "Пошаљи" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "Заврши конференцију" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "Наводим удаљену путању подешавања" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "Ово прозорче омогућава подешавање хттп или хттпс адресе када се подешавање добавља на покретању.\nУнесите или измените путању подешавања. Након што притиснете „У реду“, Линфон ће се сам поново покренути како би довукао и унео у налог нова подешавања. " - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "СИП адреса" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "Прикажи стање присуства овог пријатеља" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "Дозволи овом пријатељу да види стање мог присуства" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "Подаци о пријатељу" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "ДСЦП подешавања" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "СИП" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "РТП ток звука" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "РТП ток снимка" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "Подесите ДСЦП вредности (хексадецимално)" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "Притисните овде да подесите јачину звучника" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "Сними овај позив у звучну датотеку" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "Видео" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "Утишај" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "Пренос" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "Долазни позив" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "Трајање" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "Оцена квалитета позива" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "ЛДАП подешавања" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "Адреса сервера:" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "Начин потврђивања идентитета:" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "Корисничко име:" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "Лозинка:" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "Користи ТЛС везу" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "Још није доступно" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "Веза" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "Свежи назив домена" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "Назив потврђивања" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "Подручје" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "САСЛ" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "Предмет основе:" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "Пропусник (%s за име):" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "Особине имена:" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "Особине СИП адресе:" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "Особине за пропитивање:" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "Потражите" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "Време за претрагу:" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "Највише резултата:" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "Прати надимке" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "Разно" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "БЕЗИМЕНО" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "ЈЕДНОСТАВНО" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "ДИГЕСТ-МД5" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "НТЛМ" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Корисник" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Лозинка" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "Интернет веза:" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "Сам ме пријави" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "ИБ корисника" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "Подаци пријављивања" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "Добро дошли!" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "АДСЛ" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "Оптички канал" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "Линфоново прозорче прочишћавања" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "Премакни на крај" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "Основно" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "Обриши" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "_Могућности" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "Постави путању подешавања" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "Увек покрени видео" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "Укључи самовиђење" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "Прикажи тастатуру" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "Увези контакте из вКарти" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "Извези контакте у вКарте" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "По_моћ" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "Прикажи прозорче прочишћавања" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "_Матична страница" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "Провери _ажурирања" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "Помоћник налога" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "СИП адреса или број телефона:" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "Започните нови позив" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "Пријатељи" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "Тражи" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "Додај пријатеље из директоријума" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "Додај пријатеља" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "Очисти историјат озива" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "Мој тренутни идентитет:" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "Самојављање је укључено" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "безимено" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "ГССАПИ" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "САСЛ" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "основна звучна картица" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "звучна картица" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "основна камерица" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "ЦИФ" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "Кодеци звука" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "Кодеци снимка" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "В" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "СИП (УДП)" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "СИП (ТЦП)" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "СИП (ТЛС)" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "Подешавања" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "Овај одељак одређује вашу СИП адресу када не користите СИП налог" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "Ваше приказано име (нпр: Пера Перић):" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "Ваше корисничко име:" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "Ваша резултирајућа СИП адреса:" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "Основни идентитет" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "Чаробњак" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "Додај" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "Уреди" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "Уклони" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "Посреднички налози" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "Обриши све лозинке" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "Приватност" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "Сам одговори када се прими позив" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "Сачекај пре него што одговориш (ms)" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "Самостални-одговор" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "СИП налози" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Звук звона:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "АЛСА-ин посебни уређај (изборно):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Уређај за снимање:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Уређај за звоно:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Уређај за пуштање:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Укључи поништавање одјека" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Звук" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Улазни уређај снимка:" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "Жељена резолуција снимка:" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "Начин излаза снимка:" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "Прикажи претпреглед камерице" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "Претподешавање снимка:" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "Жељени проток кадрова снимка:" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "0 значи „неограничено“" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "Снимак" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "Ограничи брзину слања на (Kb/s):" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "Ограничи брзину преузимања на (Kb/s):" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "Укључи прилагодљиво управљање протоком" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "Прилагодљиво управљање протоком је техника за променљиво погађање доступног пропусног опсега за време позива." - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "Управљање пропусним опсегом" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "Мултимедија" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "Подеси јединицу највећег преноса:" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "Пошаљи ДТМФ као СИП податке" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "Омогући ИПв6" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "Пренос" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "СИП/УДП прикључник" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "Насумично" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "СИП/ТЦП прикључник" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "РТП/УДП звука:" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "Неизмењиво" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "РТП/УДП снимка:" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "Тунел" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "ДСЦП поља" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "Мрежни протокол и прикључници" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "Непосредна веза на Интернет" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "Иза НАТ-а / мрежне баријере (наведите ИП мрежног пролаза)" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "Иза НАТ-а / мрежне баријере (користите СТУН за решавање)" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "Иза НАТ-а / мрежне баријере (користите ИЦЕ)" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "Иза НАТ-а / мрежне баријере (користите уПнП)" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "Јавна ИП адреса:" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "Стун сервер:" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "НАТ и мрежна баријера" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "Врста шифровања медија" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "Користи Лиме за одлазне поруке ћаскања" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "Шифровање медија је обавезно" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "Обавезно" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "Жељено" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "Шифровање" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "Мрежа" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Укључи" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Искључи" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "Кодеци звука" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "Кодеци снимка" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "Kодеци" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "Језик" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "Прикажи напредна подешавања" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "Ниво" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "Корисничко сучеље" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "Подешавања ЛДАП налога" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "ЛДАП" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "Готово" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "Линфон — Потребно је потврђивање идентитета" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "Унесите лозинку домена" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "Подешавам..." - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "Сачекајте док довучем подешавања са сервера..." - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "Помоћник подешавања СИП налога" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "Добро дошли!\nОвај помоћник ће вам помоћи да користите СИП налог за ваше позиве." - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "Добро дошли у помоћника подешавања налога" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "Направи налог на линфон.орг-у" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "Већ имам налог линфон.орг-а и желим да га користим" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "Већ имам сип налог и желим да га користим" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "Желим да наведем удаљену путању подешавања" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "Помоћник подешавања налога" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "Унесите податке вашег налога" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "Корисник*" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "Лозинка*" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "Домен*" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "Посредник" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "Подесите ваш налог (корак 1/1)" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "Унесите ваше корисничко име линфон.орг-а" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "Унесите ваше корисничко име сип-а (корак 1/1)" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "(*) Обавезна поља" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "Ел. пошта: (*)" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "Корисник: (*)" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "Лозинка: (*)" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "Потврдите вашу лозинку: (*)" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "Обавештавај ме о ажурирањима линфона" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "Унесите податке налога (корак 1/2)" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "Ваш налог је направљен, сачекајте тренутак." - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "Прављење налога је у току" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "Потврдите ваш налог притиском на везу коју смо вам управо послали ел. поштом.\nЗатим се вратите овде и притисните дугме „Напред“." - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "Потврђивање (корак 2/2)" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "Проверавам да ли је ваш налог потврђен, сачекајте тренутак." - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "Провера налога је у току" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "Грешка, налог није потврђен, корисничко име је већ у употреби или је сервер недоступан.\nВратите се назад и покушајте опет." - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "Грешка" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Хвала вам. Ваш налог је сада подешен и спреман за употребу." - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "Линфон — Подесите СИП налог" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "Ваш СИП идентитет:" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "Изгледа као „sip:<корисничко-име>@<домен>“" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "сип:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "Адреса СИП посредника:" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "Изгледа као „sip:<назив посредника>“" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "Трајање уписа (сек):" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "Параметри пријатеља (изборно):" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "АВПФ редован РТЦП интервал (сек):" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "Рута (изборно):" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "Пренос" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "Упиши се" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "Објави податке о присуству" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "Укључи АВПФ" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "Подесите СИП налог" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "Подесите ВоИП тунел" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "Домаћин" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "Прикључник" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "Подесите тунел" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "Подесите хттп посредника (изборно)" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "Сачекајте мало" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "Спреман" - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "Подешавам" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "Ступам у везу" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "Не могу да позовем" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "Извините, достигли смо највећи број истовремених позива" - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "вам се обраћа" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr " и затражени само-одговор." - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "Мењам параметре позива..." - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "Повезан сам." - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "Позив је прекинут" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "Не могу да зауставим позив" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "Заустављам тренутни позив..." - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "У току је тражење стуна..." - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "Прикупљање месних ИЦЕ кандидата је у току..." - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "На вези" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "Заузет" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "Одмах се враћам" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "Одсутан" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "На телефону" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "На ручку сам" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "Не узнемиравај" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "Премештен" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "Користим другу услугу дописивања" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "Неповезан" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "На чекању" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "На одмору" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "Непознато стање" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "Адреса сип посредника коју сте унели је неисправна, мора почети на „sip:“ за којим следи назив домаћина." - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "Сип идентитет који сте унели није исправан.\nТреба да буде у облику „sip:корисник@домен-посредника“, као што је „sip:alice@example.net“" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "Тражим одредиште телефонског броја..." - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "Не могу да решим овај број." - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "Не могу да се пријавим као %s" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "Освежавам на %s..." - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "Удаљено звоњење." - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "Удаљено звоњење..." - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "Ранији медиј." - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "На позив је одговорио/ла %s" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "Позив је настављен." - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "Несагласно, проверите кодеке или безбедносна подешавања..." - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "Медијски параметри су несагласни." - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "Наставили смо." - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "Друга страна нас је паузирала." - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "Позив је освежен удаљеним." - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "Позив је завршен." - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "Корисник је заузет." - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "Корисник је привремено недоступан." - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "Корисник не жели да буде узнемираван." - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "Позив је одбијен." - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "Истекло је време захтева." - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "Преусмерен" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "Позив није успео." - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "Уписивање на „%s“ је успело." - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "Исписивање са „%s“ је обављено." - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "нема ограничења одговора" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "Уписивање на „%s“ није успело: %s" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "Услуга није доступна, поново покушавам" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "Симбол потврђивања идентитета је „%s“" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "Параметри позива не могу бити измењени: %s." - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "Параметри позива су успешно измењени." - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "Пропустили сте %i позив." -msgstr[1] "Пропустили сте %i позива." -msgstr[2] "Пропустили сте %i позива." - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "прекинут" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "завршен" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "пропуштен" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "непознато" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "%s на %s\nПозивач: %s\nПозивник: %s\nСтање: %s\nТрајање: %i мин. %i сек.\n" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "Одлазни позив" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "Не могу да пустим „%s“." - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" diff --git a/po/sv.po b/po/sv.po deleted file mode 100644 index 983966d5a..000000000 --- a/po/sv.po +++ /dev/null @@ -1,2091 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -# Henrik Mattsson-Mårn , 2016 -# Magnus Johansson , 2016 -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: Swedish (http://www.transifex.com/belledonne-communications/linphone-gtk/language/sv/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: sv\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "Ringer %s" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "Skicka text till %s" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "Lägg till %s till din kontaktlista" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "Senaste samtal" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "Senaste samtal (%i)" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "n/a" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "Avbrutna" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "Missade" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "Avvisade" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "%i minut" -msgstr[1] "%i minuter" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "%i sekund" -msgstr[1] "%i sekunder" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "%s\tKvalitet: %s\n%s\t%s\t" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "%s\t%s" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "Konferens" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "Jag" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "Kunde inte hitta pixmap filen: %s" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "Skickar..." - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "Meddelande ej skickat" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "Kopiera" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "skriv loggning information under körning" - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "visa version och avsluta." - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "sökväg till en fil att skriva loggar i." - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "Starta linphone med video inaktiverat." - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "Starta ikonifierat, visa inte huvudfönstret" - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "Samtalsmottagare" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "Välj en arbetskatalog som ska vara basen för installationen, såsom C:\\Program\\Linphone" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "Konfigurationsfil" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "Kör ljudassistenten" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "Kör självtest och avsluta 0 om möjligt" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "%s skulle vilja lägga dig till sin kontaktlista.\nVill du lägga denna person till din kontaktlista och tillåta den att se din närvarostatus?\nOm du svarar nej kommer personen att bli tillfälligt svartlistad." - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "Var vänlig och ange ditt lösenord för användarnam %s\n i område %s:" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "Samtalsfel" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "Samtalet slut" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "Inkommande samtal" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "Svara" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "Avböj" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "Samtal pausat" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "av %s" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "%s föreslår att starta video. Godtar du det?" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "Webbsajt" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "En internetvideotelefon" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "%s (Default)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "Vi är överförda till %s" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "Inget ljudkort har upptäckts på denna dator.\nDu kommer inte att kunna skicka och ta emot samtal." - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "En gratis SIP video-telefon" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "Hej\n" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "Lägg till i adressbok" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "Sök i %s katalogen" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "ogiltig SIP kontakt!" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "Lägg till en ny kontakt" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "Ändra kontakt '%s'" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "Ta bort kontakt '%s'" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "Ta bort chatthistorik för '%s'" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "Lägg till kontakt ifrån %s katalogen" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "Namn" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "Frekvens (Hz)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "Status" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "Datahastighet (kbit/s)" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "Parametrar" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "På" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "Av" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "Konto" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "Engelska" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "Franska" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "Svenska" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "Italienska" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "Spanska" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "Portugisiska (Brasilien)" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "Polska" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "Tyska" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "Ryska" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "Japanska" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "Nederländksa" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "Ungerska" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "Tjekiska" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "Kinesiska" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "Kinesiska (traditionell)" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "Norska" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "Hebreiska" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "Serbiska" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "Arabiska" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "Turkiska" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "Du behöver starta om Linphone för att det nya språket ska synas." - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "Ingen" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "SRTP" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "DTLS" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "ZRTP" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "En nyare version är tillgänglig på %s.\nVill du öppna en webbläsare för att ladda ner den?" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "Du kör den sensaste versionen." - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "Förnamn, Efternamn" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "Kommunikationsfel med servern." - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "Kontaktar ..." - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "Kopplad" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "Tar emot data..." - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "Hittat kontakt %i" -msgstr[1] "Hittat kontakt %i" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "Användarnamnet är upptaget!" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "Misslyckades att kontrollera tillgänglighet. Var vänlig och försök senare." - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "Ring #%i" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "Övergår till att ringa #%i med %s" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "Används ej" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "ICE inte aktiverat" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "ICE misslyckades" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "ICE pågår" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "Går igenom en eller flera NAT:s" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "Direkt" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "Genom en reläserver" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "uPnP inte aktiverat" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "uPnP pågår" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "uPnP ej tillgängligt" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "uPnP körs" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "uPnP misslyckades" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "Direkt eller genom server" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "nedladdning: %f\nuppladdning: %f (kbit/s)" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "%ix%i @ %f fps" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "%.3f sekunder" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "Lägg på" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "Ringer..." - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "00:00:00" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "Inkommande samtal" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "bra" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "medelmåttig" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "dålig" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "mycket dålig" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "för dålig" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "ej tillgänglig" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "Säkrad av SRTP" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "Säkrad av DTLS" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "Säkrad av ZRTP - [auth token: %s]" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "Ange som obekräftad" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "Ange som bekräftad" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "I konferens" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "I samtal" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "Pausat samtal" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "Samtalet slut." - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "Överföring pågår" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "Överföring klar." - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "Överföring misslyckades." - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "Fortsätt" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "Pausa" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "Spelar in i\n%s %s" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "(Pauserad)" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "Ange inloggningsuppgifter för %s" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "hämtar från %s" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "Hämtning av fjärrkonfiguration från %s misslyckades." - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "Ingen röst upptäckt" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "För svag" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "Bra" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "För stark" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "Hörde du tre pip?" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "Ljudinställningar ej funna" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "Kan inte starta systemljudkontroll" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "Välkommen\nDenna assistent kommer att hjälpa dig ställa in ljudet för Linphone" - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "Inspelningsenhet" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "Inspelad volym" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "Ingen röst" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "Systemljudsinställningar" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "Uppspelningsenhet" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "Spela tre pip" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "Klicka på inspelningsknappen och säg några ord" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "Lyssna på din inspelade röst" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "Spela in" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "Spela" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "Låt oss starta Linphone nu" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "Ljudassistent" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "Ljudassistent" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "Mikrofonkalibrering" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "Högtalarvolymkalibrering" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "Spela in och upp" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "Avslutar" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "Om Linphone" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "(C) Belledonne Communications, 2010\n" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "En internetvideotelefon som använder SIP (rfc3261)." - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "fr: Simon Morlat\nen: Simon Morlat och Delphine Perreau\nit: Alberto Zanoni \nde: Jean-Jacques Sarton \nsv: Daniel Nylander \nes: Jesus Benitez \nja: Yoshiya Yamaguchi \npt_BR: Rafael Caesar Lenzi \npl: Robert Nasiadek \ncs: Petr Pisar \nhu: anonym\nhe: Eli Zaretskii \n" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "Sök kontakter i katalogen" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "Lägg till min lista" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "Sök någon" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "Den uppringdas namn" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "Samtalshistorik" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "Rensa alla" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "Ring tillbaka" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "Samtalsstatistik" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "Ljudkodek" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "Videokodek" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "Bandbreddsanvändning för ljud" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "Ljudanslutningsbarhet" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "Bandbreddsanvändning för bild" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "Videoanslutningsbarhet" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "Rundturstid" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "Videoupplösning mottagen" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "Videoupplösning skickad" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "RTP-profil" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "Samtalsstatistik och information" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "Skicka" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "Avsluta konferens" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "Anger en fjärrkonfigurations-URI" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "Detta dialogfönster tillåter angivandet av en http- eller https-adress när konfigurationen hämtas vid starten.\nVar vänlig och ange eller modifiera konfigurations-URI:n nedan. Sedan du klickat på OK kommer Linphone att starta om automatiskt för att kunna hämta och använda den nya konfigurationen." - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "SIP Adress" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "Visa kontaktens närvarostatus" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "Tillåt den här kontakten att se min närvarostatus" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "Kontakt information" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "DSCP-inställningar" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "SIP" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "Ljud-RTP-ström" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "Video-RTP-ström" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "Ange DSCP-värden (med hexadecimal)" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "Klicka här för att ställa in högtalarvolymen" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "Spela in detta samtal till en ljudfil" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "Video" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "Tysta" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "Överför" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "I samtal" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "Längd" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "Samtalskvalitetsbetyg" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "LDAP-inställningar" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "Serveradress:" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "Autentiseringsmetod:" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "Användarnamn:" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "Lösenord:" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "Använd TLS-anslutning" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "Inte tillgänglig än" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "Anslutning" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "Bind DN" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "Autentiseringsnamn" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "Område" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "Basobjekt:" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "Filter (%s för namn):" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "Namnattribut:" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "SIP-adressattribut:" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "Attribut för fråga:" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "Sök" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "Tidsgräns för sökning:" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "Max resultat:" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "Följ alias" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "Diverse" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "ANONYMOUS" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "SIMPLE" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "DIGEST-MD5" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "NTLM" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Användarnamn" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Lösenord" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "Internetförbindelse:" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "Logga in mig automatiskt" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "AnvändarID" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "Inloggningsuppgifter" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "Välkommen!" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "Fiberkanal" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "Linphones felrättningsfönster" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "Rulla till slutet" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "Standard" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "Ta bort" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "_Alternativ" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "Ange konfigurations-URI" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "Starta alltid video" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "Självbild" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "Visa knappsats" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "_Hjälp" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "Visa felrättningsfönster" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "_Hemsida" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "Sök efter _uppdateringar" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "Kontoassistent" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "SIP-adress eller telefonnummer:" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "Påbörja ett nytt samtal" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "Kontakter" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "Sök" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "Lägg till kontakt ifrån katalogen" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "Lägg till kontakt" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "Rensa samtalshistorik" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "Min nuvarande identitet" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "Autosvar är aktiverat" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "anonym" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "GSSAPI" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "standardljudkort" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "ett ljudkort" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "standardkamera" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "CIF" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "Ljudkodekar" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "Videokodekar" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "C" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "SIP (UDP)" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "SIP (TCP)" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "SIP (TLS)" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "Inställningar" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "Denna sektion specificerar din SIP-adress när du inte använder ett SIP-konto" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "Ditt synliga namn (t.ex. Kalle Karlsson):" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "Ditt användarnamn:" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "Din SIP-adress:" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "Standardidentitet" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "Guide" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "Lägg till" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "Editera" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "Ta bort" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "Proxykonton" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "Radera alla lösenord" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "Integritet" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "Svara automatiskt när ett samtal tas emot" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "Fördröjning före svar (ms)" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "Autosvar" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "Hantera SIP-konton" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Ringsignal:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "Speciell enhet för ALSA (tillval):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Inspelningsenhet:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Ringningsenhet:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Uppspelningsenhet:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Tillåt ekoborttagning" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Ljud" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Videoinmatningsenhet:" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "Föredragen videoupplösning:" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "Videoutmatningsmetod:" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "Visa kameraförhandsgranskning" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "Videoförval:" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "Föredragen videobildfrekvens:" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "0 står för \"utan begränsning\"" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "Video" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "Max uppladdningshastighet i Kbit/sek:" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "Max nedladdningshastighet i Kbit/sek:" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "Aktivera anpassningsbar hastighetskontroll" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "Anpassningsbar hastighetskontroll är en teknik för att dynamiskt gissa tillgänglig bandbredd under ett samtal." - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "Bandbreddskontroll" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "Multimediainställningar" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "Välj MTU (Maximum Transmission Unit):" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "Skicka DTMF-koder som SIP-information" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "Tillåt IPv6" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "Transport" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "SIP/UDP-port" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "Slumpmässig" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "SIP/TCP-port" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "Ljud-RTP/UDP:" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "Låst" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "Video-RTP/UDP:" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "Tunnel" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "DSCP-fält" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "Nätverksprotokoll och portar" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "Direkt förbindelse till internet" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "Bakom NAT / brandvägg (specificera IP)" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "Bakom en NAT / brandvägg (använd STUN för att avgöra adressen)" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "Bakom NAT / brandvägg (använd ICE)" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "Bakom NAT / brandvägg (använd uPnP)" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "Publik IP-adress:" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "STUN-server:" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "NAT och Brandvägg" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "Mediakrypteringstyp" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "Använd Lime för utgående chattmeddelanden" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "Mediakryptering är obligatorisk" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "Kryptering" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "Nätverksinställningar" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Aktivera" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Inaktivera" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "Ljudkodekar" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "Videokodekar" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "Kodekar" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "Språk" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "Visa avancerade inställningar" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "Nivå" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "Användargränssnitt" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "LDAP-kontoinställning" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "LDAP" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "Klar" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "Linphone - Autentisering krävs" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "Ange lösenordet för domänen" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "Konfigurerar ..." - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "Var vänlig och vänta medan konfiguration hämtas från server ..." - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "Inställningsassistent för SIP-konto" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "Välkommen!\nDenna assistent kommer att hjälpa dig använda ett SIP-konto för dina samtal." - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "Välkommen till kontoinstallationsassistenten" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "Skapa ett konto på linphone.org" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "Jag har redan ett linphone.org-konto och jag vill bara använda det" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "Jag har redan ett sip-konto och jag vill bara använda det" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "Jag vill ange ett fjärrkonfigurations-URI" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "Kontoinstallationsassistenten" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "Ange din konto-information" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "Användarnamn*" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "Lösenord*" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "Domän*" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "Proxy" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "Konfigurera ditt konto (steg 1/1)" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "Ange ditt linphone.org-användarnamn" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "Ange ditt sip-användarnamn (steg 1/1)" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "(*) Obligatoriska fält" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "E-post: (*)" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "Användarnamn: (*)" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "Lösenord: (*)" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "Bekräfta ditt lösenord: (*)" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "Håll mig informerad om Linphone-uppdateringar" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "Ange kontoinformation (steg 1/2)" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "Ditt konto skapas. Var vänlig vänta." - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "Kontoskapande pågår" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "Var vänlig och bekräfta ditt konto genom att klicka på länken vi nyss skickade dig via e-post.\nKom sedan tillbaka hit och klicka på knappen Nästa." - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "Bekräftelse (steg 2/2)" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "Kontrollerar om ditt konto bekräftas. Var vänlig, vänta." - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "Kontobekräftelsekontroll pågår" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "Fel. Konto ej bekräftat, användarnamn upptaget eller server onåbar.\nVar vänlig, gå tillbaka och försök igen." - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "Fel" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Tack. Ditt konto är nu konfigurerat och färdigt att användas." - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "Linphone - Konfigurera ett SIP-konto" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "Din SIP-identitet:" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "Ser ut som sip:@" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "sip:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "SIP-proxyadress:" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "Ser ut som sip:" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "Registreringstid (sek.):" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "Kontaktparametrar (tillval):" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "AVPF regular RTCP intervall (sek):" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "Route (tillval):" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "Transport" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "Registrera" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "Publicera närvaroinformation" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "Aktivera AVPF" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "Konfigurera ett SIP-konto" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "Konfigurera VoIP-tunnel" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "Värd" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "Port" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "Konfigurera tunnel" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "Konfigurera http-proxy (valfritt)" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "Vänta" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "Redo" - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "Konfigurerar" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "Kontaktar" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "Kunde inte ringa" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "Beklagar. Vi har nått det maximala antalet samtidiga samtal." - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "kontaktar dig" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr "och frågade autosvar." - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "Modifierar samtalsparametrar ..." - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "Kopplad" - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "Samtal avbrutet" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "Kunde inte pausa samtalet" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "Pausar nuvarande samtal..." - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "STUN-uppslagning pågår ..." - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "Samlande av ICE-lokalkandidater pågår ..." - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "Online" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "Upptagen" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "Kommer strax tillbaka" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "Borta" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "I telefon" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "På lunch" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "Stör ej" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "Flyttat" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "Använder en annan meddelandetjänst" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "Frånkopplad" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "Pågående" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "Ledighet" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "Okänd status" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "SIP-proxyadressen du angav är inte rätt. Adressen måste starta med \"sip:\" följt av ett värdnamn." - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "SIP-adressen du angav är inte rätt.\nAdressen bör se ut som sip:användarnamn@domän, såsom sip:alice@exempel.net" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "Leta efter telefonnummerdestinationen ..." - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "Kan inte nå detta nummer." - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "Kunde inte logga in som %s" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "Förnyar på %s ..." - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "Ringer hos motparten." - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "Ringer hos motparten ..." - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "Tidig media" - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "Samtal besvarat av %s" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "Samtal återupptaget." - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "Inkompatibel. Kontrollera kodekar eller säkerhetsinställningar ..." - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "Inkompatibla mediaparametrar." - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "Vi har återupptagits." - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "Vi har pauserats av annan part." - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "Samtalet är uppdaterat av motpart." - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "Samtalet slut." - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "Användare är upptagen." - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "Användaren är tillfälligt otillgänglig." - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "Användaren vill inte bli störd." - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "Samtalet avböjdes." - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "Förfråganstid" - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "Omdirigerad" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "Samtal misslyckades." - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "Registrering hos %s lyckades." - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "Avregistrering hos %s lyckades." - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "Inget svar inom angiven tid" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "Registrering hos %s mislyckades: %s" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "Tjänst ej tillgänglig, försöker igen" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "Autentiseringstecken är %s" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "Samtalsparametrar kunde inte ändras: %s" - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "Samtalsparametrar ändrades framgångsrikt." - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "Du har %i missat samtal" -msgstr[1] "Du har %i missade samtal" - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "avbruten" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "slutförd" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "missad" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "okänd" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "%s vid %s\nFrån: %s\nTill: %s\nStatus: %s\nLängd: %i min %i sek\n" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "Utgående samtal" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "Kan inte spela %s." - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" diff --git a/po/tr.po b/po/tr.po deleted file mode 100644 index 4b27eecfa..000000000 --- a/po/tr.po +++ /dev/null @@ -1,2091 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -# Emin Tufan , 2016 -# faradundamarti , 2015-2016 -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: Turkish (http://www.transifex.com/belledonne-communications/linphone-gtk/language/tr/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: tr\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "Son çağrılar" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "Son çağrılar (%i)" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "yok" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "İptal edildi" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "Yanıtsız" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "Reddedildi" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "%i dakika" -msgstr[1] "%i dakika" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "%i saniye" -msgstr[1] "%i saniye" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "%s\tKalite: %s\n%s\t%s\t" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "%s\t%s" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "Grup görüşme" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "Bana" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "Gönderiliyor..." - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "İleti gitmedi" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "Kopya" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "" - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "sürümü görüntüle ve çık." - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "Günlükleri içine yazmak için bir dosya yolu" - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "Linphonu görüntü olmadan başlat" - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "Sadece sistem tepsisinde başlat, ana arayüzü gösterme." - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "adres ara" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "Bir çalışma dizini belirtin (kurulum temelinde olmalı,örneğin: c:\\Program Files\\Linphone)" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "Yapılandırma dosyası" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "Ses yardımcısını çalıştır" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "" - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "Çağrı yanlış" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "Çağrı sonlandırıldı" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "Gelen çağrı" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "Yanıt" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "Reddet" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "Çağrı duraklatıldı" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "%s tarafından" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "%s görüntü başlatmayı önerdi.Kabul ediyor musun?" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "İnternet " - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "Görüntülü internet telefonu" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "%s (Öntanımlı)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "%s ye aktardık" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "Bu bilgisayarda bir ses kartı bulunamadı.\nSesli görüşme yapamazsınız." - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "Özgür bir SİP görüntülü-telefon" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "Merhaba\n" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "Adres defterine ekle" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "%s dizininde ara" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "Geçersiz sip bağlantısı !" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "Yeni bir bağlantı ekle" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "'%s' bağlantısını düzenle" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "'%s' bağlantısını sil" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "'%s' sohbet geçmişini sil" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "%s dizininden yeni bağlantı ekle" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "Ad" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "Hız (Hz)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "Durum" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "İP Bit hızı (kbit/s)" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "Değişkenler" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "Etkin" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "Devre dışı" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "Hesap" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "İngilizce" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "Fransızca" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "İsveççe" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "İtalyanca" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "İspanyolca" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "Brezilya Portekizcesi" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "Lehçe" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "Almanca" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "Rusca" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "Japonca" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "Flemenkçe" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "Macarca" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "Çekce" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "Çince" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "Geleneksel Çince" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "Norveççe" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "İbranice" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "Sırpça" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "Arapça" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "Türkçe" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "Yeni dil seçiminizin etkili olabilmesi için linfonu yeniden başlatmalısınız." - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "Hiçbiri" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "SRTP (Güvenli Gerçek Zamanlı Aktarım Protokolü)" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "DTLS" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "ZRTP" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "%s den indirilebilir daha yeni bir sürüm var.\nOnu indirmek için internet tarayıcınızı açmak istiyor musunuz?" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "En son sürümü çalıştırıyorsunuz" - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "İlk ad, Son ad" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "Sunucuya bağlanma hatası" - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "Bağlanıyor..." - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "Bağlandı" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "Veri alınıyor..." - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "" -msgstr[1] "" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "Kullanıcı adınız zaten kullanılıyor!" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "Kullanıcı adınızın geçerlilik denetimi başarısız.Daha sonra tekrar deneyin." - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "Kullanılmıyor" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "ICE etkin değil" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "ICE başarısız" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "ICE sürüyor" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "Doğrudan" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "Bir röle sunucu aracılığı ile" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "Evrensel Tak-Çalıştır etkin değil" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "Evrensel Tak-Çalıştır ilerliyor" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "Evrensel Tak-Çalıştır kullanılamaz" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "Evrensel Tak-Çalıştır çalışıyor" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "Evrensel Tak-Çalıştır başarısız" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "Doğrudan veya sunucu aracılığıyla" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "İndime: %f\nkarşıya yükleme: %f (kbit/s)" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "Telefonu kapatma" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "Arıyor..." - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "00:00:00" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "Gelen çağrı" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "iyi" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "orta" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "zayıf" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "çok zayıf" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "çok kötü" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "kullanılamaz" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "SRTP güvencesi altında" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "DLTS güvencesi altında" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "Doğrulanmamış ayar" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "Doğrulanmış ayar" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "Grup görüşmede" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "Duraklatılmış çağrı" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "Çağrı sonlandı." - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "Aktarım sürüyor" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "Aktarım tamam" - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "Aktarım başarısız" - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "Devam et" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "Duraklat" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "(Duraklatıldı)" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "%s için giriş bilgisini girin " - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "" - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "Ses olmadığı algılandı" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "Çok düşük" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "İyi" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "Çok yüksek" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "Üç bip sesi duydun mu?" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "Ses tercihleri bulunamadı" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "Ses kontrol sistemi başlatılamıyor" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "Hoşgeldiniz!\nBu yardımcı,Linphone'un ses ayarlarını yapılandırmanıza yardım edecek" - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "Görüntü yakalama aygıtı" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "Ses yok" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "Sistem ses tercihleri" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "Oynatma aygıtı" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "Üç bip sesi çal" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "Kayıt tuşuna bas ve bazı kelimeler söyle" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "Kaydettiğin sesi dinle" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "Kayıt" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "Çalma" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "Haydi şimdi Linphona başlayalım" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "Ses Yardımcısı" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "Ses yardımcısı" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "Hoparlör ses yüksekliği ayarı" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "Kaydet ve Oynat" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "Sonlandırma" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "Linphone Hakkında" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "(C) Belledonne Communications, 2010\n\n" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "Standart SİP (rfc3261) protokolü kullanan görüntülü internet telefonu." - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "fr: Simon Morlat\nen: Simon Morlat and Delphine Perreau\nit: Alberto Zanoni \nde: Jean-Jacques Sarton \nsv: Daniel Nylander \nes: Jesus Benitez \nja: YAMAGUCHI YOSHIYA \npt_BR: Rafael Caesar Lenzi \npl: Robert Nasiadek \ncs: Petr Pisar \nhu: anonymous\nhe: Eli Zaretskii \n" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "Dizinde bağlantılar ara" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "Listeme ekle" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "Çağrı geçmişi" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "Hepsini temizle" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "Geri arama" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "Çağrı istatistikleri" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "Ses çözücü" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "Görüntü çözücü" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "Ses Ortamı bağlanırlığı" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "Görüntü Ortamı bağlanırlığı" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "Sinyal gidiş-dönüş süresi" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "Alınan görüntü çözünürlüğü" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "Giden görüntü çözünürlüğü" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "RTP profili" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "Çağrı istatistikleri ve bilgisi" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "Gönder" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "Grup görüşme son" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "" - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "SİP Adresi" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "Bu bağlantının varolan durumunu göster" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "Bağlantı bilgisi" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "DSCP ayarları" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "SİP" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "Hoparlör ses miktarı ayarı için buraya tıkla" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "Bu aramayı bir ses dosyasına kaydet" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "Görüntü" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "Sessiz" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "Aktarım" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "arıyor" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "Süre" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "Çağrı kalitesi düzeyi" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "LDAP Ayarları" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "Sunucu adresi:" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "Kimlik doğrulama yöntemi:" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "Kullanıcı adı:" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "Parola:" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "TLS Bağlantısı Kullan" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "Henüz kullanılabilir değil" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "Bağlantı" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "Yazar Adı" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "Ülke" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "Temel nesne:" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "Öznitelik Adı:" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "SIP adresi özniteliği" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "Ara" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "Arama zamanaşımına uğradı:" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "En çok sonuç:" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "Takma Adları İzle" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "Çeşitli" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Kallanıcı adı" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Parola" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "İnternet bağlantısı:" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "Kullanıcı kimliği" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "Giriş bilgisi" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "Hoşgeldiniz!" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "Fiber Kanal" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "Linphone hata giderme penceresi" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "Sonuna kadar ilerleyin" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "Öntanımlı" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "Sil" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "_Seçenekler" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "URl yapılandırma ayarları" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "Her zaman görüntüyü başlat" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "Özgörüntü etkin" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "Tuştakımını göster" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "_Yardım" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "Hata düzeltme penceresini göster" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "_Anasayfa" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "Güncellemeleri _Denetle" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "Hesap yardımcısı" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "SİP adresi veya telefon numarası:" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "Yeni bir arama başlat" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "Bağlantılar" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "Arama" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "Rehberden bağlantılar ekle" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "Bağlantı ekle" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "Çağrı geçmişini temizle" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "Güncel kimliğim:" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "Otomatik yanıtlama etkin" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "kimliği belirsiz" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "GSSAPI" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "SASL" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "öntanımlı ses kartı" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "Ses kartı" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "öntanımlı kamera" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "CIF" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "Ses çözücüleri" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "Görüntü çözücüleri" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "C" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "SIP (UDP)" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "SIP (TCP)" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "SIP (TLS)" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "Ayarlar" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "Bu bölüm bir SİP hesabı kullanmadığınız zaman sizin SİP adresinizi tanımlar" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "Görünecek adınız (örneğin: Faradunda Marti)" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "Kullanıcı adınız:" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "Öntanımlı kimlik" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "Yardımcı" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "Ekle" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "Düzenle" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "Kaldır" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "Vekil sunucu hesapları" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "Bütün parolaları sil" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "Gizlilik" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "Bir çağrı alındığında otomatik olarak yanıtla" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "Yanıtlamadan önceki gecikme (ms)" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "Otomatik yanıt" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "SİP Hesaplarını Yönet" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Zil sesi:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "ALSA özel aygıt (seçmeli)" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Görüntü yakalama aygıtı" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Ses çalma aygıtı:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Oynatma aygıtı:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "yankı giderme etkin" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Ses" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Görüntü aygıtı:" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "Tercih edilen görüntü çözünürlüğü:" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "Görüntü çıkış yöntemi:" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "Kamera önizlemesi göster" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "Görüntü ön ayarları:" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "Tercih edilen görüntü kare sayısı:" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "Görüntü" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "Gönderim hız sınırı Kbit/saniye:" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "İndirme hız sınırı Kbit/saniye:" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "Uyarlanabilir hız denetimi etkin" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "" - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "Bantgenişliği denetimi" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "Çokluortam ayarları" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "Maksimum İletim Birimi Ayarları" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "IPv6'ya izin ver" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "Taşıma" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "SIP/UDP bağlantı noktası" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "Rastgele" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "SIP/TCP bağlantı noktası" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "Sabitlenmiş" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "Tünel" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "DSCP alanları" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "Ağ protokol ve bağlanma yerleri" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "İnternete doğrudan bağlantı" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "NAT Arkasından / Güvenlik Duvarı (IP ağ geçidi belirleme)" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "NAT Arkasından / Güvenlik Duvarı (ICE kullan)" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "NAT arkasından / Güvenlik Duvarı (evrensel tak-çalıştır kullan)" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "Ortak İP adresi:" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "Stun sunucusu:" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "NAT ve Güvenlik Duvarı" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "Ortam şifreleme türü" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "Giden sohbet iletileri için Lime kullan" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "Ortam şifrelemesi zorunludur" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "Şifreleme" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "Ağ ayarları" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Etkinleştirme" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Devre dışı" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "Ses çözücüleri" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "Görüntü çözücüleri" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "Çözücüler" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "Dil" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "Gelişmiş ayarları göster" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "Aşama" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "Kullanıcı arayüzü" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "LDAP Hesap ayarı" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "LDAP" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "Tamam" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "Linphone - Kimlik doğrulaması gerekli" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "Lütfen alan adı parolası girin" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "Yapılandırılıyor..." - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "Sunucudan yapılandırma ayarlarınız getirilirken bekleyin..." - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "SİP hesabı yapılandırma yardımcısı" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "Hoşgeldiniz!\nBu yardımcı,çağrılarınız için bir SIP hesabı kullanmanıza yardım edecek." - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "Hesap açma yardımcısına hoşgeldiniz" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "linphone.org'da bir hesap oluştur" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "Önceden bir linphone.org hesabım var ve onu kullanmak istiyorum" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "Önceden bir sip hesabım var ve onu kullanmak istiyorum" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "Bir uzaktan URl yapılandırma belirlemek istiyorum" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "Hesap açma yardımcısı" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "Hesap bilgilerinizi girin" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "Kallanıcı adı*" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "Parola*" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "Alan adı*" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "Vekil sunucu" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "Hesabınızı yapılandırın (adım 1/1)" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "linphone.org kullanıcı adınızı girin" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "sip kullanıcı adınızı girin (adım 1/1)" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "(*) Zorunlu alanlar" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "E-posta: (*)" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "Kullanıcı adı: (*)" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "Parola: (*)" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "Parolanızı onaylayın: (*)" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "linphone güncellemeleri hakkında beni bilgilendir" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "Hesap bilgilerini girin (adım 1/2)" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "Hebabınız oluşturulmaya başlandı,lütfen bekleyin." - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "Hesap oluşturma sürüyor" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "Lütfen size e-posta yoluyla gönderdiğimiz bağlantıyı tıklayarak hesabınızı doğrulayın.\nSonra buraya geri dönün ve İleri düğmesine basın." - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "Doğrulama (adım 2/2)" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "Hesabınızın geçerli olup olmadığı denetleniyor,lütfen bekleyin." - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "Hesap geçerlilik sınaması sürüyor" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "Hata,hesap geçersiz,kullanıcı adı kullanılıyor veya sunucuya erişilemiyor.\nLütfen geri dönün ve tekrar deneyin." - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "Hata" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Teşekkürler. Hesabınız yapılandırıldı ve kullanıma hazır." - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "Linphone - Bir SİP hesabı yapılandır" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "SİP kimliğiniz:" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "sip:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "SİP Vekil sunucu adresi:" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "Kayıt süresi (saniye)" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "Güzergah (isteğe bağlı)" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "Taşıma" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "Kayıt" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "Yayınlama ön bilgisi" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "AVPF'yi etkinleştir" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "Bir SİP hesabı yapılandır" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "VoIP tüneli yapılandır" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "Barındırıcı" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "Bağlantı noktası" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "Tünel yapılandır" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "http vekil yapılandır (isteğe bağlı)" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "Lütfen bekleyin" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "Hazır" - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "Yapılandırılıyor" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "Bağlanıyor" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "Aranamıyor" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "" - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr "" - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "Çağrı değiştirgeleri değiştiriliyor..." - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "Bağlandı." - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "Çağrı iptal edildi" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "Çağrı duraklatılamadı" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "Geçerli çağrı duraklatılıyor..." - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "" - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "" - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "Çevrimiçi" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "Meşgul" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "Hemen döneceğim" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "Uzakta" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "Telefondayım" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "Yemekteyim" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "Rahatsız etmeyin" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "Taşındı" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "Diğer mesaj servisi kullanılıyor" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "Çevrimdışı" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "Bekliyor" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "Tatil" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "Bilinmeyen durum" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "" - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "" - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "" - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "" - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "" - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "" - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "" - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "Arama yeniden başlatıldı." - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "" - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "" - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "" - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "" - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "" - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "Çağrı sonlandırıldı" - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "Kullanıcı meşgul" - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "K" - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "Kullanıcı rahatsız edilmek istemiyor." - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "Çağrı reddedildi." - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "İstek zamanaşımına uğradı." - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "Yeniden yönlendirildi" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "Arama başarısız" - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "" - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "" - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "Servis kullanımdışı, tekrar deneyin" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "" - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "" - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "" -msgstr[1] "" - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "iptal edildi" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "tamamlandı" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "Yanıtsız" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "bilinmeyen" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "Giden arama" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "" - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" diff --git a/po/zh_CN.po b/po/zh_CN.po deleted file mode 100644 index 3ae8176a3..000000000 --- a/po/zh_CN.po +++ /dev/null @@ -1,2085 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: Chinese (China) (http://www.transifex.com/belledonne-communications/linphone-gtk/language/zh_CN/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: zh_CN\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "呼叫 %s" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "发送消息给 %s" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "无法打开位图文件:%s" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "" - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "运行时向标准输出记录调试信息。" - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "" - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "" - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "" - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "启动到系统托盘,不显示主界面。" - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "现在呼叫的地址" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "指定工作目录(应为安装目录例如 C:\\Program Files\\Linphone)" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "" - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "呼叫结束" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "呼入" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "拒绝" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "网站" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "%s (默认)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "未在此计算机上检测到声卡。\n您无法发送或接收音频呼叫。" - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "免费的 SIP 视频电话" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "在 %s 目录中查找 " - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "无效的 SIP 联系人!" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "编辑联系人 %s" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "删除联系人 %s" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "从 %s 目录增加联系人 " - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "名称" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "采样率(Hz)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "状态" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "参数" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "启用" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "禁用" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "帐户" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "英语" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "法语" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "瑞典语" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "意大利语" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "西班牙语" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "巴西葡萄牙语" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "波兰语" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "德语" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "俄语" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "日语" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "荷兰语" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "匈牙利语" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "捷克语" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "中文" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "您需要重启 linphone 以使语言选择生效。" - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "%s 有新版本。\n您是否要打开浏览器下载它?" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "您正在运行最新版。" - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "姓名" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "与服务器通讯失败" - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "正在连接..." - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "已连接" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "正在接收数据..." - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "找到 %i 联系方式" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "" - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "正在呼叫..." - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "通话结束。" - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "" - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "" - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "请输入 %s 的登录信息" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "" - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "" - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "一个采用标准 SIP (rfc3261) 协议的互联网视频电话" - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "查找联系人" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "添加为联系人" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "找人" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "呼叫历史" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "发送" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "" - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "SIP 地址" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "显示该联系人的在线状态" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "允许此人看到我的在线状态" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "联系人信息" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "呼入" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "通话时间" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "用户名:" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "密码:" - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "用户名" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "密码" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "网络连接:" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "自动登录" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "用户 ID" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "登录信息" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "Linphone 调试窗口" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "默认" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "启用自视" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "SIP 地址或电话号码:" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "联系人" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "搜索" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "从目录增加联系人" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "当前地址:" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "默认声卡" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "默认摄像头" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "CIF" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "C" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "设置" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "该段在您不使用SIP帐户时的SIP地址" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "您的显示名:" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "您的用户名:" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "您的 SIP 地址结果:" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "默认帐户" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "添加" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "编辑" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "移除" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "代理帐户" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "清除所有密码" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "隐私" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "SIP 帐户管理" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "铃声文件:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "ALSA 特殊设备(可选):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "录音设备:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "响铃设备:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "回放设备:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "启用回声抑制" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "音频" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "视频输入设备:" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "0 表示 “没有限制”" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "视频" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "上传速率限制 kbit/s:" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "下载速率限制 kbit/s:" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "" - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "带宽控制" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "音视频设置" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "设置最大传输单元(MTU):" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "以 SIP 消息发送 DTMF" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "传输协议" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "音频 RTP/UDP:" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "视频 RTP/UDP:" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "直接连接到互联网" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "在 NAT 或防火墙后(使用 STUN 解决)" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "公网 IP 地址:" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "Stun 服务器:" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "NAT 及防火墙" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "网络设置" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "启用" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "禁用" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "编解码器" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "语言" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "显示高级设置" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "级别" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "用户界面" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "完成" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "请输入密码" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "" - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "欢迎使用帐户设置向导" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "帐户设置向导" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "谢谢,您的帐户已经配置完毕,可以使用。" - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "Linphone - 配置 SIP 帐户" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "您的 SIP 地址:" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "类似于 sip:<用户名>@<域>" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "sip:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "SIP 代理地址:" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "类似于 sip:<代理主机名>" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "注册间隔(秒):" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "路由(可选):" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "发布在线状态" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "配置 SIP 帐户" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "请稍候" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "就绪" - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "联系中" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "" - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "正在联系您" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr " 并询问了自动回答。" - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "" - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "已连接。" - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "" - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "正在进行 Stun 查找..." - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "" - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "在线" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "忙碌" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "很快回来" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "离开" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "正在通话" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "外出吃饭" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "请勿打扰" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "已转到其他服务" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "正在使用其他消息服务" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "离线" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "挂起" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "您输入的 SIP 代理地址无效,它必须是以“sip:”开头,并紧随一个主机名。" - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "您输入的地址无效。\n它应具有“sip:用户名@代理域”的形式,例如 sip:alice@example.net" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "查询电话号码目的地..." - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "该号码无法解析。" - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "无法登录为 %s" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "" - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "响铃。" - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "" - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "" - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "" - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "" - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "" - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "" - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "" - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "" - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "通话结束。" - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "被叫正忙。" - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "您呼叫的用户暂时无法接通。" - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "用户已开启免打扰功能。" - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "呼叫被拒绝。" - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "" - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "已重定向" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "呼叫失败。" - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "成功注册到 %s" - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "已在 %s 解除注册。" - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "没有响应,超时" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "注册到 %s 失败: %s" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "" - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "" - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "您错过了 %i 个呼叫。" - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "" - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" diff --git a/po/zh_TW.po b/po/zh_TW.po deleted file mode 100644 index 581911162..000000000 --- a/po/zh_TW.po +++ /dev/null @@ -1,2085 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: linphone-gtk\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 14:01+0200\n" -"PO-Revision-Date: 2016-05-10 09:58+0000\n" -"Last-Translator: Belledonne Communications \n" -"Language-Team: Chinese (Taiwan) (http://www.transifex.com/belledonne-communications/linphone-gtk/language/zh_TW/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: zh_TW\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -#: ../gtk/calllogs.c:178 -#, c-format -msgid "Call %s" -msgstr "播打給 %s" - -#: ../gtk/calllogs.c:179 -#, c-format -msgid "Send text to %s" -msgstr "傳送文字給 %s" - -#: ../gtk/calllogs.c:181 -#, c-format -msgid "Add %s to your contact list" -msgstr "" - -#: ../gtk/calllogs.c:245 ../gtk/main.ui.h:23 -msgid "Recent calls" -msgstr "" - -#: ../gtk/calllogs.c:260 -#, c-format -msgid "Recent calls (%i)" -msgstr "" - -#: ../gtk/calllogs.c:334 -msgid "n/a" -msgstr "" - -#: ../gtk/calllogs.c:337 -msgid "Aborted" -msgstr "" - -#: ../gtk/calllogs.c:340 -msgid "Missed" -msgstr "" - -#: ../gtk/calllogs.c:343 -msgid "Declined" -msgstr "" - -#: ../gtk/calllogs.c:349 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "" - -#: ../gtk/calllogs.c:352 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "" - -#: ../gtk/calllogs.c:357 -#, c-format -msgid "" -"%s\tQuality: %s\n" -"%s\t%s\t" -msgstr "" - -#: ../gtk/calllogs.c:361 -#, c-format -msgid "%s\t%s" -msgstr "" - -#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 -msgid "Conference" -msgstr "" - -#: ../gtk/conference.c:46 -msgid "Me" -msgstr "" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "找不到 pixmap 檔:%s" - -#: ../gtk/chat.c:207 ../gtk/chat.c:265 -msgid "Sending..." -msgstr "" - -#: ../gtk/chat.c:224 ../gtk/chat.c:274 -msgid "Message not sent" -msgstr "" - -#: ../gtk/chat.c:498 -msgid "Copy" -msgstr "" - -#: ../gtk/main.c:134 -msgid "log to stdout some debug information while running." -msgstr "執行時將一些除錯資訊記錄到標準輸出。" - -#: ../gtk/main.c:135 -msgid "display version and exit." -msgstr "" - -#: ../gtk/main.c:136 -msgid "path to a file to write logs into." -msgstr "" - -#: ../gtk/main.c:137 -msgid "Start linphone with video disabled." -msgstr "" - -#: ../gtk/main.c:138 -msgid "Start only in the system tray, do not show the main interface." -msgstr "只在系統匣啟動,不要顯示主要介面。" - -#: ../gtk/main.c:139 -msgid "address to call right now" -msgstr "現在要打電話的位址" - -#: ../gtk/main.c:140 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: " -"c:\\Program Files\\Linphone)" -msgstr "指定一個工作目錄(應該為安裝的根目錄,例如:c:\\Program Files\\Linphone)" - -#: ../gtk/main.c:141 -msgid "Configuration file" -msgstr "" - -#: ../gtk/main.c:142 -msgid "Run the audio assistant" -msgstr "" - -#: ../gtk/main.c:143 -msgid "Run self test and exit 0 if succeed" -msgstr "" - -#: ../gtk/main.c:1058 -#, c-format -msgid "" -"%s would like to add you to his/her contact list.\n" -"Would you add him/her to your contact list and allow him/her to see your presence status?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "" - -#: ../gtk/main.c:1135 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at realm %s:" -msgstr "" - -#: ../gtk/main.c:1244 -msgid "Call error" -msgstr "" - -#: ../gtk/main.c:1247 ../coreapi/linphonecore.c:3942 -msgid "Call ended" -msgstr "通話已結束" - -#: ../gtk/main.c:1250 ../coreapi/call_log.c:235 -msgid "Incoming call" -msgstr "來電" - -#: ../gtk/main.c:1253 ../gtk/incall_view.c:579 ../gtk/in_call_frame.ui.h:2 -msgid "Answer" -msgstr "接聽" - -#: ../gtk/main.c:1255 ../gtk/in_call_frame.ui.h:3 -msgid "Decline" -msgstr "拒接" - -#: ../gtk/main.c:1262 -msgid "Call paused" -msgstr "" - -#: ../gtk/main.c:1262 -#, c-format -msgid "by %s" -msgstr "" - -#: ../gtk/main.c:1336 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "" - -#: ../gtk/main.c:1502 -msgid "Website link" -msgstr "網站連結" - -#: ../gtk/main.c:1561 ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - -#: ../gtk/main.c:1562 -msgid "A video internet phone" -msgstr "" - -#: ../gtk/main.c:1624 -#, c-format -msgid "%s (Default)" -msgstr "%s (預設值)" - -#: ../gtk/main.c:1997 ../coreapi/callbacks.c:1080 -#, c-format -msgid "We are transferred to %s" -msgstr "我們被轉接到 %s" - -#: ../gtk/main.c:2008 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "在這臺電腦中偵測不到音效卡。\n您將無法傳送或接收語音電話。" - -#: ../gtk/main.c:2173 -msgid "A free SIP video-phone" -msgstr "自由的 SIP 視訊電話" - -#: ../gtk/main.c:2292 -#, c-format -msgid "Hello\n" -msgstr "" - -#: ../gtk/friendlist.c:460 -msgid "Add to addressbook" -msgstr "" - -#: ../gtk/friendlist.c:626 -#, c-format -msgid "Search in %s directory" -msgstr "在 %s 目錄中搜尋" - -#: ../gtk/friendlist.c:773 -msgid "Invalid sip contact !" -msgstr "無效的 sip 連絡人!" - -#: ../gtk/friendlist.c:820 -#, c-format -msgid "Add a new contact" -msgstr "" - -#: ../gtk/friendlist.c:823 -#, c-format -msgid "Edit contact '%s'" -msgstr "編輯連絡人「%s」" - -#: ../gtk/friendlist.c:824 -#, c-format -msgid "Delete contact '%s'" -msgstr "刪除連絡人「%s」" - -#: ../gtk/friendlist.c:825 -#, c-format -msgid "Delete chat history of '%s'" -msgstr "" - -#: ../gtk/friendlist.c:862 -#, c-format -msgid "Add new contact from %s directory" -msgstr "從 %s 目錄加入新的連絡人" - -#: ../gtk/propertybox.c:592 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "名稱" - -#: ../gtk/propertybox.c:598 -msgid "Rate (Hz)" -msgstr "頻率 (Hz)" - -#: ../gtk/propertybox.c:604 -msgid "Status" -msgstr "狀態" - -#: ../gtk/propertybox.c:617 -msgid "IP Bitrate (kbit/s)" -msgstr "" - -#: ../gtk/propertybox.c:628 -msgid "Parameters" -msgstr "參數" - -#: ../gtk/propertybox.c:670 ../gtk/propertybox.c:824 -msgid "Enabled" -msgstr "已啟用" - -#: ../gtk/propertybox.c:672 ../gtk/propertybox.c:824 ../gtk/parameters.ui.h:57 -msgid "Disabled" -msgstr "已停用" - -#: ../gtk/propertybox.c:902 -msgid "Account" -msgstr "帳號" - -#: ../gtk/propertybox.c:1170 -msgid "English" -msgstr "英語" - -#: ../gtk/propertybox.c:1171 -msgid "French" -msgstr "法語" - -#: ../gtk/propertybox.c:1172 -msgid "Swedish" -msgstr "瑞典語" - -#: ../gtk/propertybox.c:1173 -msgid "Italian" -msgstr "義大利語" - -#: ../gtk/propertybox.c:1174 -msgid "Spanish" -msgstr "西班牙語" - -#: ../gtk/propertybox.c:1175 -msgid "Brazilian Portugese" -msgstr "巴西葡萄牙語" - -#: ../gtk/propertybox.c:1176 -msgid "Polish" -msgstr "波蘭語" - -#: ../gtk/propertybox.c:1177 -msgid "German" -msgstr "德語" - -#: ../gtk/propertybox.c:1178 -msgid "Russian" -msgstr "俄語" - -#: ../gtk/propertybox.c:1179 -msgid "Japanese" -msgstr "日語" - -#: ../gtk/propertybox.c:1180 -msgid "Dutch" -msgstr "荷蘭語" - -#: ../gtk/propertybox.c:1181 -msgid "Hungarian" -msgstr "匈牙利語" - -#: ../gtk/propertybox.c:1182 -msgid "Czech" -msgstr "捷克語" - -#: ../gtk/propertybox.c:1183 -msgid "Chinese" -msgstr "中文" - -#: ../gtk/propertybox.c:1184 -msgid "Traditional Chinese" -msgstr "" - -#: ../gtk/propertybox.c:1185 -msgid "Norwegian" -msgstr "" - -#: ../gtk/propertybox.c:1186 -msgid "Hebrew" -msgstr "" - -#: ../gtk/propertybox.c:1187 -msgid "Serbian" -msgstr "" - -#: ../gtk/propertybox.c:1188 -msgid "Arabic" -msgstr "" - -#: ../gtk/propertybox.c:1189 -msgid "Turkish" -msgstr "" - -#: ../gtk/propertybox.c:1246 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "您需要重新啟動 linphone 才能讓新選擇的語言生效。" - -#: ../gtk/propertybox.c:1332 -msgid "None" -msgstr "" - -#: ../gtk/propertybox.c:1336 -msgid "SRTP" -msgstr "" - -#: ../gtk/propertybox.c:1342 -msgid "DTLS" -msgstr "" - -#: ../gtk/propertybox.c:1349 -msgid "ZRTP" -msgstr "" - -#: ../gtk/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "在 %s 有最新的版本。\n您想要開啟瀏覽器下載它嗎?" - -#: ../gtk/update.c:91 -msgid "You are running the lastest version." -msgstr "您執行的是最新版本。" - -#: ../gtk/buddylookup.c:85 -msgid "Firstname, Lastname" -msgstr "名字, 姓氏" - -#: ../gtk/buddylookup.c:160 -msgid "Error communicating with server." -msgstr "與伺服器連線時發生錯誤。" - -#: ../gtk/buddylookup.c:164 -msgid "Connecting..." -msgstr "連線中..." - -#: ../gtk/buddylookup.c:168 -msgid "Connected" -msgstr "已連線" - -#: ../gtk/buddylookup.c:172 -msgid "Receiving data..." -msgstr "接收資料..." - -#: ../gtk/buddylookup.c:180 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "找不到 %i 個連絡人" - -#: ../gtk/setupwizard.c:219 -msgid "Username is already in use!" -msgstr "" - -#: ../gtk/setupwizard.c:223 -msgid "Failed to check username availability. Please try again later." -msgstr "" - -#: ../gtk/incall_view.c:67 ../gtk/incall_view.c:87 -#, c-format -msgid "Call #%i" -msgstr "" - -#: ../gtk/incall_view.c:145 -#, c-format -msgid "Transfer to call #%i with %s" -msgstr "" - -#: ../gtk/incall_view.c:202 ../gtk/incall_view.c:205 -msgid "Not used" -msgstr "" - -#: ../gtk/incall_view.c:212 -msgid "ICE not activated" -msgstr "" - -#: ../gtk/incall_view.c:214 -msgid "ICE failed" -msgstr "" - -#: ../gtk/incall_view.c:216 -msgid "ICE in progress" -msgstr "" - -#: ../gtk/incall_view.c:218 -msgid "Going through one or more NATs" -msgstr "" - -#: ../gtk/incall_view.c:220 -msgid "Direct" -msgstr "" - -#: ../gtk/incall_view.c:222 -msgid "Through a relay server" -msgstr "" - -#: ../gtk/incall_view.c:230 -msgid "uPnP not activated" -msgstr "" - -#: ../gtk/incall_view.c:232 -msgid "uPnP in progress" -msgstr "" - -#: ../gtk/incall_view.c:234 -msgid "uPnp not available" -msgstr "" - -#: ../gtk/incall_view.c:236 -msgid "uPnP is running" -msgstr "" - -#: ../gtk/incall_view.c:238 -msgid "uPnP failed" -msgstr "" - -#: ../gtk/incall_view.c:248 ../gtk/incall_view.c:249 -msgid "Direct or through server" -msgstr "" - -#: ../gtk/incall_view.c:258 ../gtk/incall_view.c:270 -#, c-format -msgid "" -"download: %f\n" -"upload: %f (kbit/s)" -msgstr "" - -#: ../gtk/incall_view.c:263 ../gtk/incall_view.c:265 -#, c-format -msgid "%ix%i @ %f fps" -msgstr "" - -#: ../gtk/incall_view.c:295 -#, c-format -msgid "%.3f seconds" -msgstr "" - -#: ../gtk/incall_view.c:453 ../gtk/in_call_frame.ui.h:10 -#: ../gtk/videowindow.c:248 -msgid "Hang up" -msgstr "" - -#: ../gtk/incall_view.c:558 -msgid "Calling..." -msgstr "播打..." - -#: ../gtk/incall_view.c:561 ../gtk/incall_view.c:793 -msgid "00:00:00" -msgstr "" - -#: ../gtk/incall_view.c:572 -msgid "Incoming call" -msgstr "來電" - -#: ../gtk/incall_view.c:609 -msgid "good" -msgstr "" - -#: ../gtk/incall_view.c:611 -msgid "average" -msgstr "" - -#: ../gtk/incall_view.c:613 -msgid "poor" -msgstr "" - -#: ../gtk/incall_view.c:615 -msgid "very poor" -msgstr "" - -#: ../gtk/incall_view.c:617 -msgid "too bad" -msgstr "" - -#: ../gtk/incall_view.c:618 ../gtk/incall_view.c:634 -msgid "unavailable" -msgstr "" - -#: ../gtk/incall_view.c:732 -msgid "Secured by SRTP" -msgstr "" - -#: ../gtk/incall_view.c:738 -msgid "Secured by DTLS" -msgstr "" - -#: ../gtk/incall_view.c:744 -#, c-format -msgid "Secured by ZRTP - [auth token: %s]" -msgstr "" - -#: ../gtk/incall_view.c:748 -msgid "Set unverified" -msgstr "" - -#: ../gtk/incall_view.c:748 -msgid "Set verified" -msgstr "" - -#: ../gtk/incall_view.c:788 -msgid "In conference" -msgstr "" - -#: ../gtk/incall_view.c:788 -msgid "In call" -msgstr "通話中" - -#: ../gtk/incall_view.c:825 -msgid "Paused call" -msgstr "暫停通話" - -#: ../gtk/incall_view.c:862 -msgid "Call ended." -msgstr "通話結束。" - -#: ../gtk/incall_view.c:893 -msgid "Transfer in progress" -msgstr "" - -#: ../gtk/incall_view.c:896 -msgid "Transfer done." -msgstr "" - -#: ../gtk/incall_view.c:899 -msgid "Transfer failed." -msgstr "" - -#: ../gtk/incall_view.c:930 -msgid "Resume" -msgstr "繼續" - -#: ../gtk/incall_view.c:930 ../gtk/in_call_frame.ui.h:7 -msgid "Pause" -msgstr "暫停" - -#: ../gtk/incall_view.c:996 -#, c-format -msgid "" -"Recording into\n" -"%s %s" -msgstr "" - -#: ../gtk/incall_view.c:996 -msgid "(Paused)" -msgstr "" - -#: ../gtk/loginframe.c:75 -#, c-format -msgid "Please enter login information for %s" -msgstr "請輸入 %s 的 登入資訊" - -#: ../gtk/config-fetching.c:57 -#, c-format -msgid "fetching from %s" -msgstr "" - -#: ../gtk/config-fetching.c:73 -#, c-format -msgid "Downloading of remote configuration from %s failed." -msgstr "" - -#: ../gtk/audio_assistant.c:103 -msgid "No voice detected" -msgstr "" - -#: ../gtk/audio_assistant.c:104 -msgid "Too low" -msgstr "" - -#: ../gtk/audio_assistant.c:105 -msgid "Good" -msgstr "" - -#: ../gtk/audio_assistant.c:106 -msgid "Too loud" -msgstr "" - -#: ../gtk/audio_assistant.c:188 -msgid "Did you hear three beeps ?" -msgstr "" - -#: ../gtk/audio_assistant.c:301 ../gtk/audio_assistant.c:306 -msgid "Sound preferences not found " -msgstr "" - -#: ../gtk/audio_assistant.c:315 -msgid "Cannot launch system sound control " -msgstr "" - -#: ../gtk/audio_assistant.c:327 -msgid "" -"Welcome!\n" -"This assistant will help you to configure audio settings for Linphone" -msgstr "" - -#: ../gtk/audio_assistant.c:337 -msgid "Capture device" -msgstr "" - -#: ../gtk/audio_assistant.c:338 -msgid "Recorded volume" -msgstr "" - -#: ../gtk/audio_assistant.c:342 -msgid "No voice" -msgstr "" - -#: ../gtk/audio_assistant.c:343 ../gtk/audio_assistant.c:382 -msgid "System sound preferences" -msgstr "" - -#: ../gtk/audio_assistant.c:378 -msgid "Playback device" -msgstr "" - -#: ../gtk/audio_assistant.c:379 -msgid "Play three beeps" -msgstr "" - -#: ../gtk/audio_assistant.c:412 -msgid "Press the record button and say some words" -msgstr "" - -#: ../gtk/audio_assistant.c:413 -msgid "Listen to your record voice" -msgstr "" - -#: ../gtk/audio_assistant.c:414 ../gtk/conf_frame.ui.h:2 -#: ../gtk/in_call_frame.ui.h:4 -msgid "Record" -msgstr "" - -#: ../gtk/audio_assistant.c:415 -msgid "Play" -msgstr "" - -#: ../gtk/audio_assistant.c:442 -msgid "Let's start Linphone now" -msgstr "" - -#: ../gtk/audio_assistant.c:513 -msgid "Audio Assistant" -msgstr "" - -#: ../gtk/audio_assistant.c:523 ../gtk/main.ui.h:15 -msgid "Audio assistant" -msgstr "" - -#: ../gtk/audio_assistant.c:528 -msgid "Mic Gain calibration" -msgstr "" - -#: ../gtk/audio_assistant.c:534 -msgid "Speaker volume calibration" -msgstr "" - -#: ../gtk/audio_assistant.c:539 -msgid "Record and Play" -msgstr "" - -#: ../gtk/audio_assistant.c:544 ../gtk/setup_wizard.ui.h:38 -msgid "Terminating" -msgstr "" - -#: ../gtk/about.ui.h:1 -msgid "About Linphone" -msgstr "" - -#: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications, 2010\n" -msgstr "" - -#: ../gtk/about.ui.h:4 -msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "使用標準 SIP (rfc3261) 通訊協定的網路視訊電話。" - -#: ../gtk/about.ui.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"he: Eli Zaretskii \n" -msgstr "" - -#: ../gtk/buddylookup.ui.h:1 -msgid "Search contacts in directory" -msgstr "在目錄中搜尋" - -#: ../gtk/buddylookup.ui.h:2 -msgid "Add to my list" -msgstr "加入我的清單" - -#: ../gtk/buddylookup.ui.h:3 -msgid "Search somebody" -msgstr "搜尋某人" - -#: ../gtk/callee_frame.ui.h:1 -msgid "Callee name" -msgstr "" - -#: ../gtk/call_logs.ui.h:1 -msgid "Call history" -msgstr "通話紀錄" - -#: ../gtk/call_logs.ui.h:2 -msgid "Clear all" -msgstr "全部清除" - -#: ../gtk/call_logs.ui.h:3 -msgid "Call back" -msgstr "回電" - -#: ../gtk/call_statistics.ui.h:1 -msgid "Call statistics" -msgstr "" - -#: ../gtk/call_statistics.ui.h:2 -msgid "Audio codec" -msgstr "" - -#: ../gtk/call_statistics.ui.h:3 -msgid "Video codec" -msgstr "" - -#: ../gtk/call_statistics.ui.h:4 -msgid "Audio IP bandwidth usage" -msgstr "" - -#: ../gtk/call_statistics.ui.h:5 -msgid "Audio Media connectivity" -msgstr "" - -#: ../gtk/call_statistics.ui.h:6 -msgid "Video IP bandwidth usage" -msgstr "" - -#: ../gtk/call_statistics.ui.h:7 -msgid "Video Media connectivity" -msgstr "" - -#: ../gtk/call_statistics.ui.h:8 -msgid "Round trip time" -msgstr "" - -#: ../gtk/call_statistics.ui.h:9 -msgid "Video resolution received" -msgstr "" - -#: ../gtk/call_statistics.ui.h:10 -msgid "Video resolution sent" -msgstr "" - -#: ../gtk/call_statistics.ui.h:11 -msgid "RTP profile" -msgstr "" - -#: ../gtk/call_statistics.ui.h:12 -msgid "Call statistics and information" -msgstr "" - -#: ../gtk/chatroom_frame.ui.h:1 -msgid "Send" -msgstr "傳送" - -#: ../gtk/conf_frame.ui.h:1 -msgid "End conference" -msgstr "" - -#: ../gtk/config-uri.ui.h:1 -msgid "Specifying a remote configuration URI" -msgstr "" - -#: ../gtk/config-uri.ui.h:2 -msgid "" -"This dialog allows to set an http or https address when configuration is to be fetched at startup.\n" -"Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. " -msgstr "" - -#: ../gtk/contact.ui.h:2 -msgid "SIP Address" -msgstr "SIP 位址" - -#: ../gtk/contact.ui.h:3 -msgid "Show this contact presence status" -msgstr "顯示這個連絡人的上線狀態" - -#: ../gtk/contact.ui.h:4 -msgid "Allow this contact to see my presence status" -msgstr "允許這個連絡人看到我的上線狀態" - -#: ../gtk/contact.ui.h:5 -msgid "Contact information" -msgstr "連絡人資訊" - -#: ../gtk/dscp_settings.ui.h:1 -msgid "DSCP settings" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:2 -msgid "SIP" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:3 -msgid "Audio RTP stream" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:4 -msgid "Video RTP stream" -msgstr "" - -#: ../gtk/dscp_settings.ui.h:5 -msgid "Set DSCP values (in hexadecimal)" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:1 -msgid "Click here to set the speakers volume" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:5 -msgid "Record this call to an audio file" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:6 -msgid "Video" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:8 -msgid "Mute" -msgstr "" - -#: ../gtk/in_call_frame.ui.h:9 -msgid "Transfer" -msgstr "轉接" - -#: ../gtk/in_call_frame.ui.h:12 -msgid "In call" -msgstr "通話中" - -#: ../gtk/in_call_frame.ui.h:13 -msgid "Duration" -msgstr "時間長度" - -#: ../gtk/in_call_frame.ui.h:14 -msgid "Call quality rating" -msgstr "" - -#: ../gtk/ldap.ui.h:1 -msgid "LDAP Settings" -msgstr "" - -#: ../gtk/ldap.ui.h:2 ../gtk/parameters.ui.h:90 -msgid "Server address:" -msgstr "" - -#: ../gtk/ldap.ui.h:3 ../gtk/parameters.ui.h:91 -msgid "Authentication method:" -msgstr "" - -#: ../gtk/ldap.ui.h:4 ../gtk/parameters.ui.h:92 ../gtk/setup_wizard.ui.h:17 -msgid "Username:" -msgstr "使用者名稱:" - -#: ../gtk/ldap.ui.h:5 ../gtk/password.ui.h:4 ../gtk/setup_wizard.ui.h:18 -msgid "Password:" -msgstr "密碼: " - -#: ../gtk/ldap.ui.h:6 -msgid "Use TLS Connection" -msgstr "" - -#: ../gtk/ldap.ui.h:7 -msgid "Not yet available" -msgstr "" - -#: ../gtk/ldap.ui.h:8 -msgid "Connection" -msgstr "" - -#: ../gtk/ldap.ui.h:9 -msgid "Bind DN" -msgstr "" - -#: ../gtk/ldap.ui.h:10 -msgid "Authname" -msgstr "" - -#: ../gtk/ldap.ui.h:11 -msgid "Realm" -msgstr "" - -#: ../gtk/ldap.ui.h:12 -msgid "SASL" -msgstr "" - -#: ../gtk/ldap.ui.h:13 -msgid "Base object:" -msgstr "" - -#: ../gtk/ldap.ui.h:15 -#, no-c-format -msgid "Filter (%s for name):" -msgstr "" - -#: ../gtk/ldap.ui.h:16 -msgid "Name Attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:17 -msgid "SIP address attribute:" -msgstr "" - -#: ../gtk/ldap.ui.h:18 -msgid "Attributes to query:" -msgstr "" - -#: ../gtk/ldap.ui.h:19 -msgid "Search" -msgstr "" - -#: ../gtk/ldap.ui.h:20 -msgid "Timeout for search:" -msgstr "" - -#: ../gtk/ldap.ui.h:21 -msgid "Max results:" -msgstr "" - -#: ../gtk/ldap.ui.h:22 -msgid "Follow Aliases" -msgstr "" - -#: ../gtk/ldap.ui.h:23 -msgid "Miscellaneous" -msgstr "" - -#: ../gtk/ldap.ui.h:24 -msgid "ANONYMOUS" -msgstr "" - -#: ../gtk/ldap.ui.h:25 -msgid "SIMPLE" -msgstr "" - -#: ../gtk/ldap.ui.h:26 -msgid "DIGEST-MD5" -msgstr "" - -#: ../gtk/ldap.ui.h:27 -msgid "NTLM" -msgstr "" - -#: ../gtk/login_frame.ui.h:1 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "使用者名稱" - -#: ../gtk/login_frame.ui.h:2 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "密碼" - -#: ../gtk/login_frame.ui.h:3 -msgid "Internet connection:" -msgstr "網路連線:" - -#: ../gtk/login_frame.ui.h:4 -msgid "Automatically log me in" -msgstr "將我自動登入" - -#: ../gtk/login_frame.ui.h:5 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "使用者ID" - -#: ../gtk/login_frame.ui.h:6 -msgid "Login information" -msgstr "登入資訊" - -#: ../gtk/login_frame.ui.h:7 -msgid "Welcome!" -msgstr "" - -#: ../gtk/login_frame.ui.h:8 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/login_frame.ui.h:9 -msgid "Fiber Channel" -msgstr "光纖通道" - -#: ../gtk/log.ui.h:1 -msgid "Linphone debug window" -msgstr "Linphone 除錯視窗" - -#: ../gtk/log.ui.h:2 -msgid "Scroll to end" -msgstr "" - -#: ../gtk/main.ui.h:1 -msgid "Default" -msgstr "預設值" - -#: ../gtk/main.ui.h:2 -msgid "Delete" -msgstr "" - -#: ../gtk/main.ui.h:3 -msgid "_Options" -msgstr "選項(_O)" - -#: ../gtk/main.ui.h:4 -msgid "Set configuration URI" -msgstr "" - -#: ../gtk/main.ui.h:5 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:6 -msgid "Enable self-view" -msgstr "啟用自拍檢視" - -#: ../gtk/main.ui.h:7 -msgid "Show keypad" -msgstr "" - -#: ../gtk/main.ui.h:8 -msgid "Import contacts from vCards" -msgstr "" - -#: ../gtk/main.ui.h:9 -msgid "Export contacts as vCards" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "_Help" -msgstr "求助(_H)" - -#: ../gtk/main.ui.h:11 -msgid "Show debug window" -msgstr "顯示除錯視窗" - -#: ../gtk/main.ui.h:12 -msgid "_Homepage" -msgstr "官方網頁(_H)" - -#: ../gtk/main.ui.h:13 -msgid "Check _Updates" -msgstr "檢查更新(_U)" - -#: ../gtk/main.ui.h:14 -msgid "Account assistant" -msgstr "" - -#: ../gtk/main.ui.h:16 -msgid "SIP address or phone number:" -msgstr "SIP 位址或電話號碼:" - -#: ../gtk/main.ui.h:17 -msgid "Initiate a new call" -msgstr "打出新電話" - -#: ../gtk/main.ui.h:18 -msgid "Contacts" -msgstr "連絡人" - -#: ../gtk/main.ui.h:19 -msgid "Search" -msgstr "搜尋" - -#: ../gtk/main.ui.h:20 -msgid "Add contacts from directory" -msgstr "從目錄加入連絡人" - -#: ../gtk/main.ui.h:21 -msgid "Add contact" -msgstr "加入聯絡人" - -#: ../gtk/main.ui.h:22 -msgid "Clear call history" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "My current identity:" -msgstr "我目前的使用者識別:" - -#: ../gtk/main.ui.h:25 -msgid "Autoanswer is enabled" -msgstr "" - -#: ../gtk/parameters.ui.h:1 -msgid "anonymous" -msgstr "" - -#: ../gtk/parameters.ui.h:2 -msgid "GSSAPI" -msgstr "" - -#: ../gtk/parameters.ui.h:3 -msgid "SASL" -msgstr "" - -#: ../gtk/parameters.ui.h:4 -msgid "default soundcard" -msgstr "預設的音效卡" - -#: ../gtk/parameters.ui.h:5 -msgid "a sound card" -msgstr "音效卡" - -#: ../gtk/parameters.ui.h:6 -msgid "default camera" -msgstr "預設的攝影機" - -#: ../gtk/parameters.ui.h:7 -msgid "CIF" -msgstr "CIF" - -#: ../gtk/parameters.ui.h:8 -msgid "Audio codecs" -msgstr "音訊編碼解碼器" - -#: ../gtk/parameters.ui.h:9 -msgid "Video codecs" -msgstr "視訊編碼解碼器" - -#: ../gtk/parameters.ui.h:10 -msgid "C" -msgstr "C" - -#: ../gtk/parameters.ui.h:11 -msgid "SIP (UDP)" -msgstr "" - -#: ../gtk/parameters.ui.h:12 -msgid "SIP (TCP)" -msgstr "" - -#: ../gtk/parameters.ui.h:13 -msgid "SIP (TLS)" -msgstr "" - -#: ../gtk/parameters.ui.h:14 -msgid "Settings" -msgstr "設定值" - -#: ../gtk/parameters.ui.h:15 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "這一區在不使用 SIP 帳號時定義您的 SIP 位址" - -#: ../gtk/parameters.ui.h:16 -msgid "Your display name (eg: John Doe):" -msgstr "您的顯示名稱 (例如: John Doe):" - -#: ../gtk/parameters.ui.h:17 -msgid "Your username:" -msgstr "您的使用者名稱:" - -#: ../gtk/parameters.ui.h:18 -msgid "Your resulting SIP address:" -msgstr "您組成的 SIP 位址:" - -#: ../gtk/parameters.ui.h:19 -msgid "Default identity" -msgstr "預設身分識別" - -#: ../gtk/parameters.ui.h:20 -msgid "Wizard" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Add" -msgstr "加入" - -#: ../gtk/parameters.ui.h:22 -msgid "Edit" -msgstr "編輯" - -#: ../gtk/parameters.ui.h:23 -msgid "Remove" -msgstr "移除" - -#: ../gtk/parameters.ui.h:24 -msgid "Proxy accounts" -msgstr "代理伺服器帳號" - -#: ../gtk/parameters.ui.h:25 -msgid "Erase all passwords" -msgstr "消除所有的密碼" - -#: ../gtk/parameters.ui.h:26 -msgid "Privacy" -msgstr "隱私" - -#: ../gtk/parameters.ui.h:27 -msgid "Automatically answer when a call is received" -msgstr "" - -#: ../gtk/parameters.ui.h:28 -msgid "Delay before answering (ms)" -msgstr "" - -#: ../gtk/parameters.ui.h:29 -msgid "Auto-answer" -msgstr "" - -#: ../gtk/parameters.ui.h:30 -msgid "Manage SIP Accounts" -msgstr "管理 SIP 帳號" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "鈴聲音效:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "ALSA 特殊裝置 (選擇性):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "捕捉裝置:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "響鈴裝置:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "播放裝置" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "啟用回音消除" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "音效" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "視訊輸入裝置:" - -#: ../gtk/parameters.ui.h:39 -msgid "Preferred video resolution:" -msgstr "" - -#: ../gtk/parameters.ui.h:40 -msgid "Video output method:" -msgstr "" - -#: ../gtk/parameters.ui.h:41 -msgid "Show camera preview" -msgstr "" - -#: ../gtk/parameters.ui.h:42 -msgid "Video preset:" -msgstr "" - -#: ../gtk/parameters.ui.h:43 -msgid "Preferred video framerate:" -msgstr "" - -#: ../gtk/parameters.ui.h:44 -msgid "0 stands for \"unlimited\"" -msgstr "0 表示「不限制」" - -#: ../gtk/parameters.ui.h:45 -msgid "Video" -msgstr "視訊" - -#: ../gtk/parameters.ui.h:46 -msgid "Upload speed limit in Kbit/sec:" -msgstr "上傳速度限制於 Kbit/sec:" - -#: ../gtk/parameters.ui.h:47 -msgid "Download speed limit in Kbit/sec:" -msgstr "下載速度限制於 Kbit/sec:" - -#: ../gtk/parameters.ui.h:48 -msgid "Enable adaptive rate control" -msgstr "" - -#: ../gtk/parameters.ui.h:49 -msgid "" -"Adaptive rate control is a technique to dynamically guess the available " -"bandwidth during a call." -msgstr "" - -#: ../gtk/parameters.ui.h:50 -msgid "Bandwidth control" -msgstr "頻寬控制" - -#: ../gtk/parameters.ui.h:51 -msgid "Multimedia settings" -msgstr "多媒體設定值" - -#: ../gtk/parameters.ui.h:52 -msgid "Set Maximum Transmission Unit:" -msgstr "設定最大傳輸單位:" - -#: ../gtk/parameters.ui.h:53 -msgid "Send DTMFs as SIP info" -msgstr "傳送 DTMFs 為 SIP 資訊" - -#: ../gtk/parameters.ui.h:54 -msgid "Allow IPv6" -msgstr "" - -#: ../gtk/parameters.ui.h:55 -msgid "Transport" -msgstr "傳輸" - -#: ../gtk/parameters.ui.h:56 -msgid "SIP/UDP port" -msgstr "" - -#: ../gtk/parameters.ui.h:58 -msgid "Random" -msgstr "" - -#: ../gtk/parameters.ui.h:59 -msgid "SIP/TCP port" -msgstr "" - -#: ../gtk/parameters.ui.h:60 -msgid "Audio RTP/UDP:" -msgstr "音效 RTP/UDP:" - -#: ../gtk/parameters.ui.h:61 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:62 -msgid "Video RTP/UDP:" -msgstr "視訊 RTP/UDP:" - -#: ../gtk/parameters.ui.h:63 -msgid "Tunnel" -msgstr "" - -#: ../gtk/parameters.ui.h:64 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:65 -msgid "Network protocol and ports" -msgstr "" - -#: ../gtk/parameters.ui.h:66 -msgid "Direct connection to the Internet" -msgstr "直接連線到網際網路" - -#: ../gtk/parameters.ui.h:67 -msgid "Behind NAT / Firewall (specify gateway IP )" -msgstr "" - -#: ../gtk/parameters.ui.h:68 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "在 NAT / 防火牆之後 (使用 STUN 解析)" - -#: ../gtk/parameters.ui.h:69 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "" - -#: ../gtk/parameters.ui.h:70 -msgid "Behind NAT / Firewall (use uPnP)" -msgstr "" - -#: ../gtk/parameters.ui.h:71 -msgid "Public IP address:" -msgstr "公共 IP 地址:" - -#: ../gtk/parameters.ui.h:72 -msgid "Stun server:" -msgstr "Stun 伺服器:" - -#: ../gtk/parameters.ui.h:73 -msgid "NAT and Firewall" -msgstr "NAT 與防火牆" - -#: ../gtk/parameters.ui.h:74 -msgid "Media encryption type" -msgstr "" - -#: ../gtk/parameters.ui.h:75 -msgid "Use Lime for outgoing chat messages" -msgstr "" - -#: ../gtk/parameters.ui.h:76 -msgid "Media encryption is mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:77 -msgid "Mandatory" -msgstr "" - -#: ../gtk/parameters.ui.h:78 -msgid "Preferred" -msgstr "" - -#: ../gtk/parameters.ui.h:79 -msgid "Encryption" -msgstr "" - -#: ../gtk/parameters.ui.h:80 -msgid "Network settings" -msgstr "網路設定值" - -#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "啟用" - -#: ../gtk/parameters.ui.h:82 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "停用" - -#: ../gtk/parameters.ui.h:83 -msgid "Audio codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:84 -msgid "Video codecs" -msgstr "" - -#: ../gtk/parameters.ui.h:85 -msgid "Codecs" -msgstr "編碼解碼器" - -#: ../gtk/parameters.ui.h:86 -msgid "Language" -msgstr "語言" - -#: ../gtk/parameters.ui.h:87 -msgid "Show advanced settings" -msgstr "顯示進階設定值" - -#: ../gtk/parameters.ui.h:88 -msgid "Level" -msgstr "級數" - -#: ../gtk/parameters.ui.h:89 -msgid "User interface" -msgstr "使用者介面" - -#: ../gtk/parameters.ui.h:93 -msgid "LDAP Account setup" -msgstr "" - -#: ../gtk/parameters.ui.h:94 -msgid "LDAP" -msgstr "" - -#: ../gtk/parameters.ui.h:95 -msgid "Done" -msgstr "完成" - -#: ../gtk/password.ui.h:1 -msgid "Linphone - Authentication required" -msgstr "Linphone - 需要驗證" - -#: ../gtk/password.ui.h:2 -msgid "Please enter the domain password" -msgstr "請輸入這個網域的密碼" - -#: ../gtk/provisioning-fetch.ui.h:1 -msgid "Configuring..." -msgstr "" - -#: ../gtk/provisioning-fetch.ui.h:2 -msgid "Please wait while fetching configuration from server..." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:1 -msgid "SIP account configuration assistant" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:2 -msgid "" -"Welcome!\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:4 -msgid "Welcome to the account setup assistant" -msgstr "歡迎使用帳號設定助理" - -#: ../gtk/setup_wizard.ui.h:5 -msgid "Create an account on linphone.org" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:6 -msgid "I have already a linphone.org account and I just want to use it" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:7 -msgid "I have already a sip account and I just want to use it" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:8 -msgid "I want to specify a remote configuration URI" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:9 -msgid "Account setup assistant" -msgstr "帳號設定助理" - -#: ../gtk/setup_wizard.ui.h:10 -msgid "Enter your account information" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:11 -msgid "Username*" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:12 -msgid "Password*" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:13 -msgid "Domain*" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:14 -msgid "Proxy" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:15 -msgid "Configure your account (step 1/1)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:16 -msgid "Enter your linphone.org username" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:19 -msgid "Enter your sip username (step 1/1)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:20 -msgid "(*) Required fields" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:21 -msgid "Email: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:22 -msgid "Username: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:23 -msgid "Password: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:24 -msgid "Confirm your password: (*)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:25 -msgid "Keep me informed with linphone updates" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:26 -msgid "Enter account information (step 1/2)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:27 -msgid "Your account is being created, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:28 -msgid "Account creation in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:29 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:31 -msgid "Validation (step 2/2)" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:32 -msgid "Checking if your account is been validated, please wait." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:33 -msgid "Account validation check in progress" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:34 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "" - -#: ../gtk/setup_wizard.ui.h:36 -msgid "Error" -msgstr "" - -#: ../gtk/setup_wizard.ui.h:37 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "謝謝您。您的帳號已設定完成並且可以使用。" - -#: ../gtk/sip_account.ui.h:1 -msgid "Linphone - Configure a SIP account" -msgstr "Linphone - 設定 SIP 帳號" - -#: ../gtk/sip_account.ui.h:2 -msgid "Your SIP identity:" -msgstr "您的 SIP 使用者識別:" - -#: ../gtk/sip_account.ui.h:3 -msgid "Looks like sip:@" -msgstr "看起來像 sip:@" - -#: ../gtk/sip_account.ui.h:4 -msgid "sip:" -msgstr "sip:" - -#: ../gtk/sip_account.ui.h:5 -msgid "SIP Proxy address:" -msgstr "SIP 代理位址:" - -#: ../gtk/sip_account.ui.h:6 -msgid "Looks like sip:" -msgstr "看起來像 sip:" - -#: ../gtk/sip_account.ui.h:7 -msgid "Registration duration (sec):" -msgstr "註冊時間 (秒):" - -#: ../gtk/sip_account.ui.h:8 -msgid "Contact params (optional):" -msgstr "" - -#: ../gtk/sip_account.ui.h:9 -msgid "AVPF regular RTCP interval (sec):" -msgstr "" - -#: ../gtk/sip_account.ui.h:10 -msgid "Route (optional):" -msgstr "路由 (選擇性):" - -#: ../gtk/sip_account.ui.h:11 -msgid "Transport" -msgstr "" - -#: ../gtk/sip_account.ui.h:12 -msgid "Register" -msgstr "" - -#: ../gtk/sip_account.ui.h:13 -msgid "Publish presence information" -msgstr "發布上線資訊" - -#: ../gtk/sip_account.ui.h:14 -msgid "Enable AVPF" -msgstr "" - -#: ../gtk/sip_account.ui.h:15 -msgid "Configure a SIP account" -msgstr "設定 SIP 帳號" - -#: ../gtk/tunnel_config.ui.h:1 -msgid "Configure VoIP tunnel" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:2 -msgid "Host" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:3 -msgid "Port" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:6 -msgid "Configure tunnel" -msgstr "" - -#: ../gtk/tunnel_config.ui.h:9 -msgid "Configure http proxy (optional)" -msgstr "" - -#: ../gtk/waiting.ui.h:2 -msgid "Please wait" -msgstr "請稍候" - -#: ../coreapi/linphonecore.c:1594 -msgid "Ready" -msgstr "準備就緒" - -#: ../coreapi/linphonecore.c:2685 -msgid "Configuring" -msgstr "" - -#. must be known at that time -#: ../coreapi/linphonecore.c:3084 -msgid "Contacting" -msgstr "正在連絡" - -#: ../coreapi/linphonecore.c:3089 -msgid "Could not call" -msgstr "無法通話" - -#: ../coreapi/linphonecore.c:3228 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "抱歉,我們已達瀏同步通話的最大數目" - -#: ../coreapi/linphonecore.c:3388 -msgid "is contacting you" -msgstr "正在連絡您" - -#: ../coreapi/linphonecore.c:3389 -msgid " and asked autoanswer." -msgstr "並要求自動接聽。" - -#: ../coreapi/linphonecore.c:3506 -msgid "Modifying call parameters..." -msgstr "修改通話參數..." - -#: ../coreapi/linphonecore.c:3898 -msgid "Connected." -msgstr "已連線。" - -#: ../coreapi/linphonecore.c:3923 -msgid "Call aborted" -msgstr "通話已放棄" - -#: ../coreapi/linphonecore.c:4125 -msgid "Could not pause the call" -msgstr "無法暫停通話" - -#: ../coreapi/linphonecore.c:4128 -msgid "Pausing the current call..." -msgstr "暫停目前的通話..." - -#: ../coreapi/misc.c:441 -msgid "Stun lookup in progress..." -msgstr "正在進行 Stun 搜尋..." - -#: ../coreapi/misc.c:657 -msgid "ICE local candidates gathering in progress..." -msgstr "" - -#: ../coreapi/friend.c:48 -msgid "Online" -msgstr "上線" - -#: ../coreapi/friend.c:51 -msgid "Busy" -msgstr "忙碌" - -#: ../coreapi/friend.c:54 -msgid "Be right back" -msgstr "馬上回來" - -#: ../coreapi/friend.c:57 -msgid "Away" -msgstr "離開" - -#: ../coreapi/friend.c:60 -msgid "On the phone" -msgstr "電話中" - -#: ../coreapi/friend.c:63 -msgid "Out to lunch" -msgstr "外出午餐" - -#: ../coreapi/friend.c:66 -msgid "Do not disturb" -msgstr "請勿打擾" - -#: ../coreapi/friend.c:69 -msgid "Moved" -msgstr "移動中" - -#: ../coreapi/friend.c:72 -msgid "Using another messaging service" -msgstr "使用另一個訊息服務" - -#: ../coreapi/friend.c:75 -msgid "Offline" -msgstr "離線" - -#: ../coreapi/friend.c:78 -msgid "Pending" -msgstr "等待中" - -#: ../coreapi/friend.c:81 -msgid "Vacation" -msgstr "" - -#: ../coreapi/friend.c:83 -msgid "Unknown status" -msgstr "" - -#: ../coreapi/proxy.c:339 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "您輸入的 sip 代理位址是無效的,它必須要以「sip:」開頭,後面接主機名稱。" - -#: ../coreapi/proxy.c:345 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "您輸入的 sip 身分是無效的。\n它應該看起來像 sip:使用者名稱@代理網域,像是 sip:alice@example.net" - -#: ../coreapi/proxy.c:979 -msgid "Looking for telephone number destination..." -msgstr "尋找電話號碼目的端..." - -#: ../coreapi/proxy.c:983 -msgid "Could not resolve this number." -msgstr "無法解析這個號碼。" - -#: ../coreapi/proxy.c:1437 -#, c-format -msgid "Could not login as %s" -msgstr "無法以 %s 登入" - -#: ../coreapi/proxy.c:1522 -#, c-format -msgid "Refreshing on %s..." -msgstr "" - -#: ../coreapi/callbacks.c:415 -msgid "Remote ringing." -msgstr "遠端響鈴。" - -#: ../coreapi/callbacks.c:427 -msgid "Remote ringing..." -msgstr "遠端響鈴..." - -#: ../coreapi/callbacks.c:450 -msgid "Early media." -msgstr "早期媒體。" - -#: ../coreapi/callbacks.c:480 -#, c-format -msgid "Call answered by %s" -msgstr "" - -#: ../coreapi/callbacks.c:522 -msgid "Call resumed." -msgstr "通話已繼續。" - -#: ../coreapi/callbacks.c:577 -msgid "Incompatible, check codecs or security settings..." -msgstr "" - -#: ../coreapi/callbacks.c:582 ../coreapi/callbacks.c:918 -msgid "Incompatible media parameters." -msgstr "" - -#: ../coreapi/callbacks.c:607 -msgid "We have been resumed." -msgstr "" - -#. we are being paused -#: ../coreapi/callbacks.c:615 -msgid "We are paused by other party." -msgstr "" - -#: ../coreapi/callbacks.c:625 -msgid "Call is updated by remote." -msgstr "" - -#: ../coreapi/callbacks.c:794 -msgid "Call terminated." -msgstr "通話已終止。" - -#: ../coreapi/callbacks.c:822 -msgid "User is busy." -msgstr "使用者現正忙碌。" - -#: ../coreapi/callbacks.c:823 -msgid "User is temporarily unavailable." -msgstr "使用者暫時無法聯繫。" - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:825 -msgid "User does not want to be disturbed." -msgstr "使用者不想要被打擾。" - -#: ../coreapi/callbacks.c:826 -msgid "Call declined." -msgstr "通話被拒接。" - -#: ../coreapi/callbacks.c:841 -msgid "Request timeout." -msgstr "" - -#: ../coreapi/callbacks.c:872 -msgid "Redirected" -msgstr "已重新導向" - -#: ../coreapi/callbacks.c:922 -msgid "Call failed." -msgstr "通話失敗。" - -#: ../coreapi/callbacks.c:1000 -#, c-format -msgid "Registration on %s successful." -msgstr "在 %s 註冊成功。" - -#: ../coreapi/callbacks.c:1001 -#, c-format -msgid "Unregistration on %s done." -msgstr "在 %s 取消註冊完成。" - -#: ../coreapi/callbacks.c:1019 -msgid "no response timeout" -msgstr "沒有回應逾時" - -#: ../coreapi/callbacks.c:1022 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "在 %s 註冊失敗:%s" - -#: ../coreapi/callbacks.c:1029 -msgid "Service unavailable, retrying" -msgstr "" - -#. if encryption is DTLS, no status to be displayed -#: ../coreapi/linphonecall.c:204 -#, c-format -msgid "Authentication token is %s" -msgstr "" - -#: ../coreapi/linphonecall.c:1663 -#, c-format -msgid "Call parameters could not be modified: %s." -msgstr "" - -#: ../coreapi/linphonecall.c:1665 -msgid "Call parameters were successfully modified." -msgstr "" - -#: ../coreapi/linphonecall.c:4636 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "您有 %i 通未接來電。" - -#: ../coreapi/call_log.c:223 -msgid "aborted" -msgstr "" - -#: ../coreapi/call_log.c:226 -msgid "completed" -msgstr "" - -#: ../coreapi/call_log.c:229 -msgid "missed" -msgstr "" - -#: ../coreapi/call_log.c:232 -msgid "unknown" -msgstr "" - -#: ../coreapi/call_log.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "" - -#: ../coreapi/call_log.c:235 -msgid "Outgoing call" -msgstr "" - -#: ../gtk/videowindow.c:72 -#, c-format -msgid "Cannot play %s." -msgstr "" - -#: ../gtk/videowindow.c:252 -msgid "Take screenshot" -msgstr "" From 53627f92e0bd8bfc178a72cd2413ff02a6d9aa18 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 21 Sep 2017 18:30:08 +0200 Subject: [PATCH 0127/2215] No longer depend on gettext + remove core callbacks that were deprecated since a very long time. --- CMakeLists.txt | 5 - README.md | 1 - cmake/FindIntl.cmake | 56 - config.h.cmake | 2 - console/linphonec.c | 47 - coreapi/call_log.c | 16 +- coreapi/callbacks.c | 26 +- coreapi/friend.c | 26 +- coreapi/linphonecore.c | 30 +- coreapi/linphonecore_jni.cc | 26 - coreapi/payload_type.c | 4 - coreapi/private.h | 31 - coreapi/proxy.c | 35 +- coreapi/vtables.c | 34 - include/linphone/core.h | 33 - intl/ChangeLog | 4 - intl/Makefile.in | 337 ----- intl/VERSION | 1 - intl/bindtextdom.c | 369 ----- intl/cat-compat.c | 262 ---- intl/dcgettext.c | 59 - intl/dgettext.c | 59 - intl/explodename.c | 192 --- intl/finddomain.c | 198 --- intl/gettext.c | 64 - intl/gettext.h | 102 -- intl/gettextP.h | 242 --- intl/hash-string.h | 59 - intl/intl-compat.c | 131 -- intl/l10nflist.c | 453 ------ intl/libgettext.h | 49 - intl/linux-msg.sed | 100 -- intl/loadinfo.h | 156 -- intl/loadmsgcat.c | 1316 ----------------- intl/localealias.c | 419 ------ intl/po2tbl.sed.in | 102 -- intl/textdomain.c | 142 -- intl/xopen-msg.sed | 104 -- src/c-wrapper/api/c-call.cpp | 1 - .../local-conference-event-handler.cpp | 4 +- .../remote-conference-event-handler.cpp | 4 +- src/conference/session/call-session.cpp | 80 +- src/conference/session/media-session.cpp | 30 +- src/nat/ice-agent.cpp | 1 - src/nat/stun-client.cpp | 1 - 45 files changed, 39 insertions(+), 5374 deletions(-) delete mode 100644 cmake/FindIntl.cmake delete mode 100644 intl/ChangeLog delete mode 100644 intl/Makefile.in delete mode 100644 intl/VERSION delete mode 100644 intl/bindtextdom.c delete mode 100644 intl/cat-compat.c delete mode 100644 intl/dcgettext.c delete mode 100644 intl/dgettext.c delete mode 100644 intl/explodename.c delete mode 100644 intl/finddomain.c delete mode 100644 intl/gettext.c delete mode 100644 intl/gettext.h delete mode 100644 intl/gettextP.h delete mode 100644 intl/hash-string.h delete mode 100644 intl/intl-compat.c delete mode 100644 intl/l10nflist.c delete mode 100644 intl/libgettext.h delete mode 100644 intl/linux-msg.sed delete mode 100644 intl/loadinfo.h delete mode 100644 intl/loadmsgcat.c delete mode 100644 intl/localealias.c delete mode 100644 intl/po2tbl.sed.in delete mode 100644 intl/textdomain.c delete mode 100644 intl/xopen-msg.sed diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b8f861b6..0d01fc3f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,7 +48,6 @@ option(ENABLE_DEBUG_LOGS "Turn on or off debug level logs." NO) option(ENABLE_DOC "Enable documentation generation with Doxygen." YES) option(ENABLE_JAVADOC "Add a target to generate documentation for Java API" NO) option(ENABLE_LDAP "Enable LDAP support." NO) -option(ENABLE_NLS "Build with internationalisation support" YES) option(ENABLE_RELATIVE_PREFIX "Find resources relatively to the installation directory." NO) option(ENABLE_ROOTCA_DOWNLOAD "Download rootca.pem at build time." YES) option(ENABLE_SOCI_STORAGE "Turn on compilation soci storage, for messages, contacts, history" YES) @@ -162,10 +161,6 @@ endif() if(ENABLE_ASSISTANT) set(BUILD_WIZARD 1) endif() -if(ENABLE_NLS) - find_package(Gettext REQUIRED) - find_package(Intl REQUIRED) -endif() if(ENABLE_LIME) #bzrtp is only required for LIME if(LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS) diff --git a/README.md b/README.md index 911bc58c1..f9eb8a190 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,6 @@ Building liblinphone * `ENABLE_VCARD=NO` : disable VCard support * `ENABLE_SQLITE_STORAGE=NO` : disable SQlite user data storage (message, history, contacts list) * `ENABLE_TOOLS=NO` : do not build tool binaries -* `ENABLE_NLS=NO` : disable internationalization * `ENABLE_LIME=YES` : disable Linphone Instant Messaging Encryption ### Note for packagers diff --git a/cmake/FindIntl.cmake b/cmake/FindIntl.cmake deleted file mode 100644 index 97dfea8e0..000000000 --- a/cmake/FindIntl.cmake +++ /dev/null @@ -1,56 +0,0 @@ -############################################################################ -# FindIntl.cmake -# Copyright (C) 2014 Belledonne Communications, Grenoble France -# -############################################################################ -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -############################################################################ -# -# - Find the libintl include file and library -# -# INTL_FOUND - system has libintl -# INTL_INCLUDE_DIRS - the libintl include directory -# INTL_LIBRARIES - The libraries needed to use libintl - -set(_INTL_ROOT_PATHS - ${CMAKE_INSTALL_PREFIX} -) - -find_path(INTL_INCLUDE_DIRS - NAMES libintl.h - HINTS _INTL_ROOT_PATHS - PATH_SUFFIXES include -) - -if(INTL_INCLUDE_DIRS) - set(HAVE_LIBINTL_H 1) -endif() - -set(INTL_ARGS INTL_INCLUDE_DIRS HAVE_LIBINTL_H) -if(NOT UNIX OR APPLE) - find_library(INTL_LIBRARIES - NAMES intl - HINTS ${_INTL_ROOT_PATHS} - PATH_SUFFIXES bin lib - ) - list(APPEND INTL_ARGS INTL_LIBRARIES) -endif() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Intl DEFAULT_MSG ${INTL_ARGS}) - -mark_as_advanced(${INTL_ARGS}) diff --git a/config.h.cmake b/config.h.cmake index 5de3f36a3..bfa18d6fe 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -39,12 +39,10 @@ #define PACKAGE_RING_DIR "${PACKAGE_RING_DIR}" #cmakedefine BUILD_WIZARD -#cmakedefine HAVE_GTK_OSX 1 #cmakedefine HAVE_NOTIFY4 #cmakedefine HAVE_ZLIB 1 #cmakedefine HAVE_CU_GET_SUITE 1 #cmakedefine HAVE_CU_CURSES 1 #cmakedefine HAVE_LIBUDEV_H 0 #cmakedefine HAVE_LIME -#cmakedefine ENABLE_NLS 1 #cmakedefine ENABLE_UPDATE_CHECK 1 diff --git a/console/linphonec.c b/console/linphonec.c index 28124a53f..edcd128a8 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -111,9 +111,6 @@ static char **linephonec_readline_completion(const char *text, /* These are callback for linphone core */ static void linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *username, const char *domain); static void linphonec_display_refer (LinphoneCore * lc, const char *refer_to); -static void linphonec_display_something (LinphoneCore * lc, const char *something); -static void linphonec_display_url (LinphoneCore * lc, const char *something, const char *url); -static void linphonec_display_warning (LinphoneCore * lc, const char *something); static void linphonec_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState new_call_state); static void linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid); @@ -122,7 +119,6 @@ static void linphonec_new_unknown_subscriber(LinphoneCore *lc, static void linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, const LinphoneAddress *from, const char *msg); -static void linphonec_display_status (LinphoneCore * lc, const char *something); static void linphonec_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf); static void print_prompt(LinphoneCore *opm); void linphonec_out(const char *fmt,...); @@ -206,45 +202,6 @@ linphonec_display_refer (LinphoneCore * lc, const char *refer_to) linphonec_out("Receiving out of call refer to %s\n", refer_to); } -/* - * Linphone core callback - */ -static void -linphonec_display_something (LinphoneCore * lc, const char *something) -{ - fprintf (stdout, "%s\n%s", something,prompt); - fflush(stdout); -} - -/* - * Linphone core callback - */ -static void -linphonec_display_status (LinphoneCore * lc, const char *something) -{ - fprintf (stdout, "%s\n%s", something,prompt); - fflush(stdout); -} - -/* - * Linphone core callback - */ -static void -linphonec_display_warning (LinphoneCore * lc, const char *something) -{ - fprintf (stdout, "Warning: %s\n%s", something,prompt); - fflush(stdout); -} - -/* - * Linphone core callback - */ -static void -linphonec_display_url (LinphoneCore * lc, const char *something, const char *url) -{ - fprintf (stdout, "%s : %s\n", something, url); -} - /* * Linphone core callback */ @@ -637,10 +594,6 @@ main (int argc, char *argv[]) { linphonec_vtable.notify_presence_received = linphonec_notify_presence_received; linphonec_vtable.new_subscription_requested = linphonec_new_unknown_subscriber; linphonec_vtable.auth_info_requested = linphonec_prompt_for_auth; - linphonec_vtable.display_status = linphonec_display_status; - linphonec_vtable.display_message=linphonec_display_something; - linphonec_vtable.display_warning=linphonec_display_warning; - linphonec_vtable.display_url=linphonec_display_url; linphonec_vtable.text_received=linphonec_text_received; linphonec_vtable.dtmf_received=linphonec_dtmf_received; linphonec_vtable.refer_received=linphonec_display_refer; diff --git a/coreapi/call_log.c b/coreapi/call_log.c index 479c0a5d6..b4ec345b4 100644 --- a/coreapi/call_log.c +++ b/coreapi/call_log.c @@ -230,25 +230,25 @@ char * linphone_call_log_to_str(const LinphoneCallLog *cl){ char *to=linphone_address_as_string (cl->to); switch(cl->status){ case LinphoneCallAborted: - status=_("aborted"); + status="aborted"; break; case LinphoneCallSuccess: - status=_("completed"); + status="completed"; break; case LinphoneCallMissed: - status=_("missed"); + status="missed"; break; case LinphoneCallAcceptedElsewhere: - status=_("answered elsewhere"); + status="answered elsewhere"; break; case LinphoneCallDeclinedElsewhere: - status=_("declined elsewhere"); + status="declined elsewhere"; break; default: - status=_("unknown"); + status="unknown"; } - tmp=ms_strdup_printf(_("%s at %s\nFrom: %s\nTo: %s\nStatus: %s\nDuration: %i mn %i sec\n"), - (cl->dir==LinphoneCallIncoming) ? _("Incoming call") : _("Outgoing call"), + tmp=ms_strdup_printf("%s at %s\nFrom: %s\nTo: %s\nStatus: %s\nDuration: %i mn %i sec\n", + (cl->dir==LinphoneCallIncoming) ? "Incoming call" : "Outgoing call", cl->start_date, from, to, diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 6e1e27880..63fdaaf94 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -324,27 +324,16 @@ static void auth_failure(SalOp *op, SalAuthInfo* info) { } static void register_success(SalOp *op, bool_t registered){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op); - char *msg; - if (!cfg){ ms_message("Registration success for deleted proxy config, ignored"); return; } linphone_proxy_config_set_state(cfg, registered ? LinphoneRegistrationOk : LinphoneRegistrationCleared , registered ? "Registration successful" : "Unregistration done"); - { - if (registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op)); - else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op)); - linphone_core_notify_display_status(lc,msg); - ms_free(msg); - } - } static void register_failure(SalOp *op){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op); const SalErrorInfo *ei=sal_op_get_error_info(op); const char *details=ei->full_string; @@ -354,17 +343,11 @@ static void register_failure(SalOp *op){ return ; } if (details==NULL) - details=_("no response timeout"); - - { - char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op), details); - linphone_core_notify_display_status(lc,msg); - ms_free(msg); - } + details="no response timeout"; if ((ei->reason == SalReasonServiceUnavailable || ei->reason == SalReasonIOError) && linphone_proxy_config_get_state(cfg) == LinphoneRegistrationOk) { - linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress,_("Service unavailable, retrying")); + linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress,"Service unavailable, retrying"); } else { linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,details); } @@ -415,11 +398,6 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){ call->refer_to=ms_strdup(referto); call->refer_pending=TRUE; linphone_call_set_state(call,LinphoneCallRefered,"Refered"); - { - char *msg=ms_strdup_printf(_("We are transferred to %s"),referto); - linphone_core_notify_display_status(lc,msg); - ms_free(msg); - } if (call->refer_pending) linphone_core_start_refered_call(lc,call,NULL); }else { linphone_core_notify_refer_received(lc,referto); diff --git a/coreapi/friend.c b/coreapi/friend.c index 914f44d66..523e0dc39 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -45,43 +45,43 @@ const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){ const char *str=NULL; switch(ss){ case LinphoneStatusOnline: - str=_("Online"); + str="Online"; break; case LinphoneStatusBusy: - str=_("Busy"); + str="Busy"; break; case LinphoneStatusBeRightBack: - str=_("Be right back"); + str="Be right back"; break; case LinphoneStatusAway: - str=_("Away"); + str="Away"; break; case LinphoneStatusOnThePhone: - str=_("On the phone"); + str="On the phone"; break; case LinphoneStatusOutToLunch: - str=_("Out to lunch"); + str="Out to lunch"; break; case LinphoneStatusDoNotDisturb: - str=_("Do not disturb"); + str="Do not disturb"; break; case LinphoneStatusMoved: - str=_("Moved"); + str="Moved"; break; case LinphoneStatusAltService: - str=_("Using another messaging service"); + str="Using another messaging service"; break; case LinphoneStatusOffline: - str=_("Offline"); + str="Offline"; break; case LinphoneStatusPending: - str=_("Pending"); + str="Pending"; break; case LinphoneStatusVacation: - str=_("Vacation"); + str="Vacation"; break; default: - str=_("Unknown status"); + str="Unknown status"; } return str; } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 43c4520c4..d4fc6cb4d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1997,8 +1997,6 @@ static void linphone_core_start(LinphoneCore * lc) { } #endif - - linphone_core_notify_display_status(lc,_("Ready")); lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon; linphone_core_set_state(lc,LinphoneGlobalOn,"Ready"); } @@ -2753,13 +2751,6 @@ const char *linphone_core_get_user_agent_version(void){ return _ua_version; } -static void transport_error(LinphoneCore *lc, const char* transport, int port){ - char *msg=ortp_strdup_printf("Could not start %s transport on port %i, maybe this port is already used.",transport,port); - ms_warning("%s",msg); - linphone_core_notify_display_warning(lc,msg); - ms_free(msg); -} - static bool_t transports_unchanged(const LinphoneSipTransports * tr1, const LinphoneSipTransports * tr2){ return tr2->udp_port==tr1->udp_port && @@ -2800,26 +2791,17 @@ int _linphone_core_apply_transports(LinphoneCore *lc){ sal_set_http_proxy_port(sal,linphone_core_get_http_proxy_port(lc)); } if (lc->tunnel && linphone_tunnel_sip_enabled(lc->tunnel) && linphone_tunnel_get_activated(lc->tunnel)){ - if (sal_listen_port(sal,anyaddr,tr->udp_port,SalTransportUDP,TRUE)!=0){ - transport_error(lc,"udp+tunnel",tr->udp_port); - } + sal_listen_port(sal,anyaddr,tr->udp_port,SalTransportUDP,TRUE); }else{ if (tr->udp_port!=0){ - if (sal_listen_port(sal,listening_address,tr->udp_port,SalTransportUDP,FALSE)!=0){ - transport_error(lc,"udp",tr->udp_port); - } + sal_listen_port(sal,listening_address,tr->udp_port,SalTransportUDP,FALSE); } if (tr->tcp_port!=0){ - if (sal_listen_port (sal,listening_address,tr->tcp_port,SalTransportTCP,FALSE)!=0){ - transport_error(lc,"tcp",tr->tcp_port); - } + sal_listen_port (sal,listening_address,tr->tcp_port,SalTransportTCP,FALSE); } if (linphone_core_sip_transport_supported(lc,LinphoneTransportTls)){ - if (tr->tls_port!=0){ - if (sal_listen_port (sal,listening_address,tr->tls_port,SalTransportTLS,FALSE)!=0){ - transport_error(lc,"tls",tr->tls_port); - } - } + if (tr->tls_port!=0) + sal_listen_port (sal,listening_address,tr->tls_port,SalTransportTLS,FALSE); } } return 0; @@ -3147,7 +3129,6 @@ void linphone_core_iterate(LinphoneCore *lc){ belle_http_provider_set_tls_crypto_config(lc->http_provider, lc->http_crypto_config); } - linphone_core_notify_display_status(lc, _("Configuring")); linphone_core_set_state(lc, LinphoneGlobalConfiguring, "Configuring"); remote_provisioning_uri = linphone_core_get_provisioning_uri(lc); @@ -3514,7 +3495,6 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const } if(!linphone_core_can_we_add_call(lc)){ - linphone_core_notify_display_warning(lc,_("Sorry, we have reached the maximum number of simultaneous calls")); return NULL; } diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index c6f063c54..54a2e42ed 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -262,9 +262,6 @@ public: authMethodClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$AuthMethod")); authMethodFromIntId = env->GetStaticMethodID(authMethodClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$AuthMethod;"); - /*displayStatus(LinphoneCore lc,String message);*/ - displayStatusId = env->GetMethodID(listenerClass,"displayStatus","(Lorg/linphone/core/LinphoneCore;Ljava/lang/String;)V"); - /*void generalState(LinphoneCore lc,int state); */ globalStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$GlobalState")); globalStateFromIntId = env->GetStaticMethodID(globalStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$GlobalState;"); @@ -454,7 +451,6 @@ public: jobject core; jclass listenerClass; - jmethodID displayStatusId; jmethodID newSubscriptionRequestId; jmethodID notifyPresenceReceivedId; jmethodID messageReceivedId; @@ -835,10 +831,6 @@ public: memset(vTable, 0, sizeof(LinphoneCoreVTable)); - if (ljb->displayStatusId) { - vTable->display_status = displayStatusCb; - } - if (ljb->globalStateId) { vTable->global_state_changed = globalStateChange; } @@ -958,24 +950,6 @@ public: LinphoneCoreVTable vTable; - static void displayStatusCb(LinphoneCore *lc, const char *message) { - JNIEnv *env = 0; - jint result = jvm->AttachCurrentThread(&env,NULL); - if (result != 0) { - ms_error("cannot attach VM"); - return; - } - - LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc); - LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); - LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); - jstring msg = message ? env->NewStringUTF(message) : NULL; - env->CallVoidMethod(lcData->listener,ljb->displayStatusId,lcData->core,msg); - handle_possible_java_exception(env, lcData->listener); - if (msg) { - env->DeleteLocalRef(msg); - } - } static void authInfoRequested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); diff --git a/coreapi/payload_type.c b/coreapi/payload_type.c index fba57120e..a0d1ec800 100644 --- a/coreapi/payload_type.c +++ b/coreapi/payload_type.c @@ -106,11 +106,7 @@ char *linphone_payload_type_get_description(const LinphonePayloadType *pt) { static const char *_linphone_core_get_payload_type_codec_description(const LinphoneCore *lc, const OrtpPayloadType *pt) { if (ms_factory_codec_supported(lc->factory, pt->mime_type)){ MSFilterDesc *desc=ms_factory_get_encoder(lc->factory, pt->mime_type); -#ifdef ENABLE_NLS - return dgettext("mediastreamer",desc->text); -#else return desc->text; -#endif } return NULL; } diff --git a/coreapi/private.h b/coreapi/private.h index 914685918..193d5d8ff 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -60,32 +60,6 @@ #define LIBLINPHONE_VERSION LINPHONE_VERSION #endif -#ifdef ENABLE_NLS - -#ifdef _MSC_VER -// prevent libintl.h from re-defining fprintf and vfprintf -#ifndef fprintf -#define fprintf fprintf -#endif -#ifndef vfprintf -#define vfprintf vfprintf -#endif -#define _GL_STDIO_H -#endif - -#include - -#ifndef _ -#define _(String) dgettext(GETTEXT_PACKAGE,String) -#endif -#else -#ifndef _ -#define _(something) (something) -#endif -#ifndef ngettext -#define ngettext(singular, plural, number) (((number)==1)?(singular):(plural)) -#endif -#endif #ifdef __ANDROID__ #include #endif @@ -1702,11 +1676,6 @@ void linphone_core_notify_global_state_changed(LinphoneCore *lc, LinphoneGlobalS void linphone_core_notify_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message); void linphone_core_notify_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token); void linphone_core_notify_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message); -void linphone_core_notify_show_interface(LinphoneCore *lc); -void linphone_core_notify_display_status(LinphoneCore *lc, const char *message); -void linphone_core_notify_display_message(LinphoneCore *lc, const char *message); -void linphone_core_notify_display_warning(LinphoneCore *lc, const char *message); -void linphone_core_notify_display_url(LinphoneCore *lc, const char *message, const char *url); void linphone_core_notify_new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url); void linphone_core_notify_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain); void linphone_core_notify_authentication_requested(LinphoneCore *lc, LinphoneAuthInfo *auth_info, LinphoneAuthMethod method); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index c56877c2f..e8cd9d6b7 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -362,18 +362,10 @@ LinphoneStatus linphone_proxy_config_set_route(LinphoneProxyConfig *cfg, const c } bool_t linphone_proxy_config_check(LinphoneCore *lc, LinphoneProxyConfig *cfg){ - if (cfg->reg_proxy==NULL){ - if (lc) - linphone_core_notify_display_warning(lc,_("The sip proxy address you entered is invalid, it must start with \"sip:\"" - " followed by a hostname.")); + if (cfg->reg_proxy==NULL) return FALSE; - } - if (cfg->identity_address==NULL){ - if (lc) - linphone_core_notify_display_warning(lc,_("The sip identity you entered is invalid.\nIt should look like " - "sip:username@proxydomain, such as sip:alice@example.net")); + if (cfg->identity_address==NULL) return FALSE; - } return TRUE; } @@ -741,13 +733,7 @@ LinphoneAddress* linphone_proxy_config_normalize_sip_uri(LinphoneProxyConfig *pr if (!username || *username=='\0') return NULL; if (is_enum(username,&enum_domain)){ - if (proxy) { - linphone_core_notify_display_status(proxy->lc,_("Looking for telephone number destination...")); - } if (enum_lookup(enum_domain,&enumres)<0){ - if (proxy) { - linphone_core_notify_display_status(proxy->lc,_("Could not resolve this number.")); - } ms_free(enum_domain); return NULL; } @@ -1226,7 +1212,6 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore* lc static void linphone_proxy_config_activate_sip_setup(LinphoneProxyConfig *cfg){ SipSetupContext *ssc; SipSetup *ss=sip_setup_lookup(cfg->type); - LinphoneCore *lc=linphone_proxy_config_get_core(cfg); unsigned int caps; if (!ss) return ; ssc=sip_setup_context_new(ss,cfg); @@ -1237,14 +1222,8 @@ static void linphone_proxy_config_activate_sip_setup(LinphoneProxyConfig *cfg){ } caps=(unsigned int)sip_setup_context_get_capabilities(ssc); if (caps & SIP_SETUP_CAP_ACCOUNT_MANAGER){ - if (sip_setup_context_login_account(ssc,cfg->reg_identity,NULL,NULL)!=0){ - { - char *tmp=ms_strdup_printf(_("Could not login as %s"),cfg->reg_identity); - linphone_core_notify_display_warning(lc,tmp); - ms_free(tmp); - } + if (sip_setup_context_login_account(ssc,cfg->reg_identity,NULL,NULL)!=0) return; - } } if (caps & SIP_SETUP_CAP_PROXY_PROVIDER){ char proxy[256]; @@ -1314,14 +1293,6 @@ void * linphone_proxy_config_get_user_data(const LinphoneProxyConfig *cfg) { void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const char *message){ LinphoneCore *lc=cfg->lc; - - if (state==LinphoneRegistrationProgress) { - char *msg=ortp_strdup_printf(_("Refreshing on %s..."), linphone_proxy_config_get_identity(cfg)); - linphone_core_notify_display_status(lc,msg); - ms_free(msg); - - } - if (cfg->state!=state || state==LinphoneRegistrationOk) { /*allow multiple notification of LinphoneRegistrationOk for refreshing*/ ms_message("Proxy config [%p] for identity [%s] moving from state [%s] to [%s] on core [%p]" , cfg, diff --git a/coreapi/vtables.c b/coreapi/vtables.c index ada08a8e7..7b0fb82c8 100644 --- a/coreapi/vtables.c +++ b/coreapi/vtables.c @@ -102,41 +102,7 @@ void linphone_core_notify_registration_state_changed(LinphoneCore *lc, LinphoneP NOTIFY_IF_EXIST(registration_state_changed, lc,cfg,cstate,message); cleanup_dead_vtable_refs(lc); } -#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) -#pragma GCC diagnostic push -#endif -#ifdef _MSC_VER -#pragma warning(disable : 4996) -#else -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif -void linphone_core_notify_show_interface(LinphoneCore *lc){ - NOTIFY_IF_EXIST(show, lc); - cleanup_dead_vtable_refs(lc); -} -void linphone_core_notify_display_status(LinphoneCore *lc, const char *message) { - NOTIFY_IF_EXIST(display_status, lc,message); - cleanup_dead_vtable_refs(lc); -} - -void linphone_core_notify_display_message(LinphoneCore *lc, const char *message){ - NOTIFY_IF_EXIST(display_message, lc,message); - cleanup_dead_vtable_refs(lc); -} - -void linphone_core_notify_display_warning(LinphoneCore *lc, const char *message){ - NOTIFY_IF_EXIST(display_warning, lc,message); - cleanup_dead_vtable_refs(lc); -} - -void linphone_core_notify_display_url(LinphoneCore *lc, const char *message, const char *url){ - NOTIFY_IF_EXIST(display_url, lc,message,url); - cleanup_dead_vtable_refs(lc); -} -#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) -#pragma GCC diagnostic pop -#endif void linphone_core_notify_notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { NOTIFY_IF_EXIST(notify_presence_received, lc, lf); cleanup_dead_vtable_refs(lc); diff --git a/include/linphone/core.h b/include/linphone/core.h index f3fa25583..e738629af 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -140,34 +140,6 @@ LINPHONE_PUBLIC const LinphoneAddress * linphone_core_get_current_call_remote_ad * @{ **/ -/** - * Callback prototype - * @deprecated - * @donotwrap - */ -typedef void (*ShowInterfaceCb)(LinphoneCore *lc); - -/** - * Callback prototype - * @deprecated - * @donotwrap - */ -typedef void (*DisplayStatusCb)(LinphoneCore *lc, const char *message); - -/** - * Callback prototype - * @deprecated - * @donotwrap - */ -typedef void (*DisplayMessageCb)(LinphoneCore *lc, const char *message); - -/** - * Callback prototype - * @deprecated - * @donotwrap - */ -typedef void (*DisplayUrlCb)(LinphoneCore *lc, const char *message, const char *url); - /** * Callback prototype */ @@ -202,11 +174,6 @@ typedef struct _LinphoneCoreVTable{ LinphoneCoreNotifyReceivedCb notify_received; /**< Notifies a an event notification, see linphone_core_subscribe() */ LinphoneCorePublishStateChangedCb publish_state_changed;/**Notifies publish state change (only from #LinphoneEvent api)*/ LinphoneCoreConfiguringStatusCb configuring_status; /** Notifies configuring status changes */ - LINPHONE_DEPRECATED DisplayStatusCb display_status; /**< @deprecated Callback that notifies various events with human readable text.*/ - LINPHONE_DEPRECATED DisplayMessageCb display_message;/**< @deprecated Callback to display a message to the user */ - LINPHONE_DEPRECATED DisplayMessageCb display_warning;/**< @deprecated Callback to display a warning to the user */ - LINPHONE_DEPRECATED DisplayUrlCb display_url; /**< @deprecated */ - LINPHONE_DEPRECATED ShowInterfaceCb show; /**< vNotifies the application that it should show up*/ LINPHONE_DEPRECATED LinphoneCoreTextMessageReceivedCb text_received; /**< @deprecated, use #message_received instead
    A text message has been received */ LINPHONE_DEPRECATED LinphoneCoreFileTransferRecvCb file_transfer_recv; /**< @deprecated Callback to store file received attached to a #LinphoneChatMessage */ LINPHONE_DEPRECATED LinphoneCoreFileTransferSendCb file_transfer_send; /**< @deprecated Callback to collect file chunk to be sent for a #LinphoneChatMessage */ diff --git a/intl/ChangeLog b/intl/ChangeLog deleted file mode 100644 index 65ec50f78..000000000 --- a/intl/ChangeLog +++ /dev/null @@ -1,4 +0,0 @@ -2002-08-06 GNU - - * Version 0.11.5 released. - diff --git a/intl/Makefile.in b/intl/Makefile.in deleted file mode 100644 index 0486dc93a..000000000 --- a/intl/Makefile.in +++ /dev/null @@ -1,337 +0,0 @@ -# Makefile for directory with message catalog handling in GNU NLS Utilities. -# Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Library General Public License as published -# by the Free Software Foundation; either version 2, 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 -# Library General Public License for more details. -# -# You should have received a copy of the GNU Library General Public -# License along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -# USA. - -PACKAGE = @PACKAGE@ -VERSION = @VERSION@ - -SHELL = /bin/sh - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -top_builddir = .. -VPATH = @srcdir@ - -prefix = @prefix@ -exec_prefix = @exec_prefix@ -transform = @program_transform_name@ -libdir = @libdir@ -includedir = @includedir@ -datadir = @datadir@ -localedir = $(datadir)/locale -gettextsrcdir = $(datadir)/gettext/intl -aliaspath = $(localedir) -subdir = intl - -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -MKINSTALLDIRS = @MKINSTALLDIRS@ -mkinstalldirs = $(SHELL) `case "$(MKINSTALLDIRS)" in /*) echo "$(MKINSTALLDIRS)" ;; *) echo "$(top_builddir)/$(MKINSTALLDIRS)" ;; esac` - -l = @INTL_LIBTOOL_SUFFIX_PREFIX@ - -AR = ar -CC = @CC@ -LIBTOOL = @LIBTOOL@ -RANLIB = @RANLIB@ -YACC = @INTLBISON@ -y -d -YFLAGS = --name-prefix=__gettext - -DEFS = -DLOCALEDIR=\"$(localedir)\" -DLOCALE_ALIAS_PATH=\"$(aliaspath)\" \ --DLIBDIR=\"$(libdir)\" -DIN_LIBINTL @DEFS@ -CPPFLAGS = @CPPFLAGS@ -CFLAGS = @CFLAGS@ -LDFLAGS = @LDFLAGS@ - -COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) - -HEADERS = $(COMHDRS) libgnuintl.h loadinfo.h -COMHDRS = gmo.h gettextP.h hash-string.h plural-exp.h eval-plural.h os2compat.h -SOURCES = $(COMSRCS) intl-compat.c -COMSRCS = bindtextdom.c dcgettext.c dgettext.c gettext.c \ -finddomain.c loadmsgcat.c localealias.c textdomain.c l10nflist.c \ -explodename.c dcigettext.c dcngettext.c dngettext.c ngettext.c plural.y \ -plural-exp.c localcharset.c localename.c osdep.c os2compat.c -OBJECTS = @INTLOBJS@ bindtextdom.$lo dcgettext.$lo dgettext.$lo gettext.$lo \ -finddomain.$lo loadmsgcat.$lo localealias.$lo textdomain.$lo l10nflist.$lo \ -explodename.$lo dcigettext.$lo dcngettext.$lo dngettext.$lo ngettext.$lo \ -plural.$lo plural-exp.$lo localcharset.$lo localename.$lo osdep.$lo -GETTOBJS = intl-compat.$lo -DISTFILES.common = Makefile.in \ -config.charset locale.alias ref-add.sin ref-del.sin $(HEADERS) $(SOURCES) -DISTFILES.generated = plural.c -DISTFILES.normal = VERSION -DISTFILES.gettext = COPYING.LIB-2.0 COPYING.LIB-2.1 libintl.glibc -DISTFILES.obsolete = xopen-msg.sed linux-msg.sed po2tbl.sed.in cat-compat.c \ -COPYING.LIB-2 gettext.h libgettext.h plural-eval.c - -# Libtool's library version information for libintl. -# Before making a gettext release, the gettext maintainer must change this -# according to the libtool documentation, section "Library interface versions". -# Maintainers of other packages that include the intl directory must *not* -# change these values. -LTV_CURRENT=4 -LTV_REVISION=0 -LTV_AGE=2 - -.SUFFIXES: -.SUFFIXES: .c .y .o .lo .sin .sed -.c.o: - $(COMPILE) $< -.c.lo: - $(LIBTOOL) --mode=compile $(COMPILE) $< - -.y.c: - $(YACC) $(YFLAGS) --output $@ $< - rm -f $*.h - -.sin.sed: - sed -e '/^#/d' -e 's/@''PACKAGE''@/@PACKAGE@/g' $< > t-$@ - mv t-$@ $@ - -INCLUDES = -I.. -I. -I$(top_srcdir)/intl - -all: all-@USE_INCLUDED_LIBINTL@ -all-yes: libintl.$la libintl.h charset.alias ref-add.sed ref-del.sed -all-no: all-no-@BUILD_INCLUDED_LIBINTL@ -all-no-yes: libgnuintl.$la -all-no-no: - -libintl.a libgnuintl.a: $(OBJECTS) - rm -f $@ - $(AR) cru $@ $(OBJECTS) - $(RANLIB) $@ - -libintl.la libgnuintl.la: $(OBJECTS) - $(LIBTOOL) --mode=link \ - $(CC) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ \ - $(OBJECTS) @LTLIBICONV@ -lc \ - -version-info $(LTV_CURRENT):$(LTV_REVISION):$(LTV_AGE) \ - -rpath $(libdir) \ - -no-undefined - -libintl.h: libgnuintl.h - cp $(srcdir)/libgnuintl.h libintl.h - -charset.alias: config.charset - $(SHELL) $(srcdir)/config.charset '@host@' > t-$@ - mv t-$@ $@ - -check: all - -# This installation goal is only used in GNU gettext. Packages which -# only use the library should use install instead. - -# We must not install the libintl.h/libintl.a files if we are on a -# system which has the GNU gettext() function in its C library or in a -# separate library. -# If you want to use the one which comes with this version of the -# package, you have to use `configure --with-included-gettext'. -install: install-exec install-data -install-exec: all - if test "$(PACKAGE)" = "gettext" \ - && test '@INTLOBJS@' = '$(GETTOBJS)'; then \ - $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \ - $(INSTALL_DATA) libintl.h $(DESTDIR)$(includedir)/libintl.h; \ - $(LIBTOOL) --mode=install \ - $(INSTALL_DATA) libintl.$la $(DESTDIR)$(libdir)/libintl.$la; \ - else \ - : ; \ - fi - if test '@USE_INCLUDED_LIBINTL@' = yes; then \ - test @GLIBC21@ != no || $(mkinstalldirs) $(DESTDIR)$(libdir); \ - temp=$(DESTDIR)$(libdir)/t-charset.alias; \ - dest=$(DESTDIR)$(libdir)/charset.alias; \ - if test -f $(DESTDIR)$(libdir)/charset.alias; then \ - orig=$(DESTDIR)$(libdir)/charset.alias; \ - sed -f ref-add.sed $$orig > $$temp; \ - $(INSTALL_DATA) $$temp $$dest; \ - rm -f $$temp; \ - else \ - if test @GLIBC21@ = no; then \ - orig=charset.alias; \ - sed -f ref-add.sed $$orig > $$temp; \ - $(INSTALL_DATA) $$temp $$dest; \ - rm -f $$temp; \ - fi; \ - fi; \ - $(mkinstalldirs) $(DESTDIR)$(localedir); \ - test -f $(DESTDIR)$(localedir)/locale.alias \ - && orig=$(DESTDIR)$(localedir)/locale.alias \ - || orig=$(srcdir)/locale.alias; \ - temp=$(DESTDIR)$(localedir)/t-locale.alias; \ - dest=$(DESTDIR)$(localedir)/locale.alias; \ - sed -f ref-add.sed $$orig > $$temp; \ - $(INSTALL_DATA) $$temp $$dest; \ - rm -f $$temp; \ - else \ - : ; \ - fi -install-data: all - if test "$(PACKAGE)" = "gettext"; then \ - $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ - $(INSTALL_DATA) VERSION $(DESTDIR)$(gettextsrcdir)/VERSION; \ - $(INSTALL_DATA) ChangeLog.inst $(DESTDIR)$(gettextsrcdir)/ChangeLog; \ - dists="COPYING.LIB-2.0 COPYING.LIB-2.1 $(DISTFILES.common)"; \ - for file in $$dists; do \ - $(INSTALL_DATA) $(srcdir)/$$file \ - $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - chmod a+x $(DESTDIR)$(gettextsrcdir)/config.charset; \ - dists="$(DISTFILES.generated)"; \ - for file in $$dists; do \ - if test -f $$file; then dir=.; else dir=$(srcdir); fi; \ - $(INSTALL_DATA) $$dir/$$file \ - $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - dists="$(DISTFILES.obsolete)"; \ - for file in $$dists; do \ - rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - else \ - : ; \ - fi - -install-strip: install - -installdirs: - if test "$(PACKAGE)" = "gettext" \ - && test '@INTLOBJS@' = '$(GETTOBJS)'; then \ - $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \ - else \ - : ; \ - fi - if test '@USE_INCLUDED_LIBINTL@' = yes; then \ - test @GLIBC21@ != no || $(mkinstalldirs) $(DESTDIR)$(libdir); \ - $(mkinstalldirs) $(DESTDIR)$(localedir); \ - else \ - : ; \ - fi - if test "$(PACKAGE)" = "gettext"; then \ - $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ - else \ - : ; \ - fi - -# Define this as empty until I found a useful application. -installcheck: - -uninstall: - if test "$(PACKAGE)" = "gettext" \ - && test '@INTLOBJS@' = '$(GETTOBJS)'; then \ - rm -f $(DESTDIR)$(includedir)/libintl.h; \ - $(LIBTOOL) --mode=uninstall \ - rm -f $(DESTDIR)$(libdir)/libintl.$la; \ - else \ - : ; \ - fi - if test '@USE_INCLUDED_LIBINTL@' = yes; then \ - if test -f $(DESTDIR)$(libdir)/charset.alias; then \ - temp=$(DESTDIR)$(libdir)/t-charset.alias; \ - dest=$(DESTDIR)$(libdir)/charset.alias; \ - sed -f ref-del.sed $$dest > $$temp; \ - if grep '^# Packages using this file: $$' $$temp > /dev/null; then \ - rm -f $$dest; \ - else \ - $(INSTALL_DATA) $$temp $$dest; \ - fi; \ - rm -f $$temp; \ - fi; \ - if test -f $(DESTDIR)$(localedir)/locale.alias; then \ - temp=$(DESTDIR)$(localedir)/t-locale.alias; \ - dest=$(DESTDIR)$(localedir)/locale.alias; \ - sed -f ref-del.sed $$dest > $$temp; \ - if grep '^# Packages using this file: $$' $$temp > /dev/null; then \ - rm -f $$dest; \ - else \ - $(INSTALL_DATA) $$temp $$dest; \ - fi; \ - rm -f $$temp; \ - fi; \ - else \ - : ; \ - fi - if test "$(PACKAGE)" = "gettext"; then \ - for file in VERSION ChangeLog COPYING.LIB-2.0 COPYING.LIB-2.1 $(DISTFILES.common) $(DISTFILES.generated); do \ - rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - else \ - : ; \ - fi - -info dvi: - -$(OBJECTS): ../config.h libgnuintl.h -bindtextdom.$lo dcgettext.$lo dcigettext.$lo dcngettext.$lo dgettext.$lo dngettext.$lo finddomain.$lo gettext.$lo intl-compat.$lo loadmsgcat.$lo localealias.$lo ngettext.$lo textdomain.$lo: gettextP.h gmo.h loadinfo.h -dcigettext.$lo: hash-string.h -explodename.$lo l10nflist.$lo: loadinfo.h -dcigettext.$lo loadmsgcat.$lo plural.$lo plural-exp.$lo: plural-exp.h -dcigettext.$lo: eval-plural.h - -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) - here=`pwd`; cd $(srcdir) && etags -o $$here/TAGS $(HEADERS) $(SOURCES) - -id: ID - -ID: $(HEADERS) $(SOURCES) - here=`pwd`; cd $(srcdir) && mkid -f$$here/ID $(HEADERS) $(SOURCES) - - -mostlyclean: - rm -f *.a *.la *.o *.lo core core.* - rm -f libintl.h charset.alias ref-add.sed ref-del.sed - rm -f -r .libs _libs - -clean: mostlyclean - -distclean: clean - rm -f Makefile ID TAGS - if test "$(PACKAGE)" = gettext; then \ - rm -f ChangeLog.inst $(DISTFILES.normal); \ - else \ - : ; \ - fi - -maintainer-clean: distclean - @echo "This command is intended for maintainers to use;" - @echo "it deletes files that may require special tools to rebuild." - - -# GNU gettext needs not contain the file `VERSION' but contains some -# other files which should not be distributed in other packages. -distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) -dist distdir: Makefile - if test "$(PACKAGE)" = gettext; then \ - additional="$(DISTFILES.gettext)"; \ - else \ - additional="$(DISTFILES.normal)"; \ - fi; \ - $(MAKE) $(DISTFILES.common) $(DISTFILES.generated) $$additional; \ - for file in ChangeLog $(DISTFILES.common) $(DISTFILES.generated) $$additional; do \ - if test -f $$file; then dir=.; else dir=$(srcdir); fi; \ - cp -p $$dir/$$file $(distdir); \ - done - -Makefile: Makefile.in ../config.status - cd .. \ - && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status - -# Tell versions [3.59,3.63) of GNU make not to export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/intl/VERSION b/intl/VERSION deleted file mode 100644 index acc8052f3..000000000 --- a/intl/VERSION +++ /dev/null @@ -1 +0,0 @@ -GNU gettext library from gettext-0.11.5 diff --git a/intl/bindtextdom.c b/intl/bindtextdom.c deleted file mode 100644 index d582ce11d..000000000 --- a/intl/bindtextdom.c +++ /dev/null @@ -1,369 +0,0 @@ -/* Implementation of the bindtextdomain(3) function - Copyright (C) 1995-1998, 2000, 2001, 2002 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include - -#ifdef _LIBC -# include -#else -# include "libgnuintl.h" -#endif -#include "gettextP.h" - -#ifdef _LIBC -/* We have to handle multi-threaded applications. */ -# include -#else -/* Provide dummy implementation if this is outside glibc. */ -# define __libc_rwlock_define(CLASS, NAME) -# define __libc_rwlock_wrlock(NAME) -# define __libc_rwlock_unlock(NAME) -#endif - -/* The internal variables in the standalone libintl.a must have different - names than the internal variables in GNU libc, otherwise programs - using libintl.a cannot be linked statically. */ -#if !defined _LIBC -# define _nl_default_dirname libintl_nl_default_dirname -# define _nl_domain_bindings libintl_nl_domain_bindings -#endif - -/* Some compilers, like SunOS4 cc, don't have offsetof in . */ -#ifndef offsetof -# define offsetof(type,ident) ((size_t)&(((type*)0)->ident)) -#endif - -/* @@ end of prolog @@ */ - -/* Contains the default location of the message catalogs. */ -extern const char _nl_default_dirname[]; - -/* List with bindings of specific domains. */ -extern struct binding *_nl_domain_bindings; - -/* Lock variable to protect the global data in the gettext implementation. */ -__libc_rwlock_define (extern, _nl_state_lock attribute_hidden) - - -/* Names for the libintl functions are a problem. They must not clash - with existing names and they should follow ANSI C. But this source - code is also used in GNU C Library where the names have a __ - prefix. So we have to make a difference here. */ -#ifdef _LIBC -# define BINDTEXTDOMAIN __bindtextdomain -# define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset -# ifndef strdup -# define strdup(str) __strdup (str) -# endif -#else -# define BINDTEXTDOMAIN libintl_bindtextdomain -# define BIND_TEXTDOMAIN_CODESET libintl_bind_textdomain_codeset -#endif - -/* Prototypes for local functions. */ -static void set_binding_values PARAMS ((const char *domainname, - const char **dirnamep, - const char **codesetp)); - -/* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP - to be used for the DOMAINNAME message catalog. - If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not - modified, only the current value is returned. - If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither - modified nor returned. */ -static void -set_binding_values (domainname, dirnamep, codesetp) - const char *domainname; - const char **dirnamep; - const char **codesetp; -{ - struct binding *binding; - int modified; - - /* Some sanity checks. */ - if (domainname == NULL || domainname[0] == '\0') - { - if (dirnamep) - *dirnamep = NULL; - if (codesetp) - *codesetp = NULL; - return; - } - - __libc_rwlock_wrlock (_nl_state_lock); - - modified = 0; - - for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next) - { - int compare = strcmp (domainname, binding->domainname); - if (compare == 0) - /* We found it! */ - break; - if (compare < 0) - { - /* It is not in the list. */ - binding = NULL; - break; - } - } - - if (binding != NULL) - { - if (dirnamep) - { - const char *dirname = *dirnamep; - - if (dirname == NULL) - /* The current binding has be to returned. */ - *dirnamep = binding->dirname; - else - { - /* The domain is already bound. If the new value and the old - one are equal we simply do nothing. Otherwise replace the - old binding. */ - char *result = binding->dirname; - if (strcmp (dirname, result) != 0) - { - if (strcmp (dirname, _nl_default_dirname) == 0) - result = (char *) _nl_default_dirname; - else - { -#if defined _LIBC || defined HAVE_STRDUP - result = strdup (dirname); -#else - size_t len = strlen (dirname) + 1; - result = (char *) malloc (len); - if (__builtin_expect (result != NULL, 1)) - memcpy (result, dirname, len); -#endif - } - - if (__builtin_expect (result != NULL, 1)) - { - if (binding->dirname != _nl_default_dirname) - free (binding->dirname); - - binding->dirname = result; - modified = 1; - } - } - *dirnamep = result; - } - } - - if (codesetp) - { - const char *codeset = *codesetp; - - if (codeset == NULL) - /* The current binding has be to returned. */ - *codesetp = binding->codeset; - else - { - /* The domain is already bound. If the new value and the old - one are equal we simply do nothing. Otherwise replace the - old binding. */ - char *result = binding->codeset; - if (result == NULL || strcmp (codeset, result) != 0) - { -#if defined _LIBC || defined HAVE_STRDUP - result = strdup (codeset); -#else - size_t len = strlen (codeset) + 1; - result = (char *) malloc (len); - if (__builtin_expect (result != NULL, 1)) - memcpy (result, codeset, len); -#endif - - if (__builtin_expect (result != NULL, 1)) - { - if (binding->codeset != NULL) - free (binding->codeset); - - binding->codeset = result; - binding->codeset_cntr++; - modified = 1; - } - } - *codesetp = result; - } - } - } - else if ((dirnamep == NULL || *dirnamep == NULL) - && (codesetp == NULL || *codesetp == NULL)) - { - /* Simply return the default values. */ - if (dirnamep) - *dirnamep = _nl_default_dirname; - if (codesetp) - *codesetp = NULL; - } - else - { - /* We have to create a new binding. */ - size_t len = strlen (domainname) + 1; - struct binding *new_binding = - (struct binding *) malloc (offsetof (struct binding, domainname) + len); - - if (__builtin_expect (new_binding == NULL, 0)) - goto failed; - - memcpy (new_binding->domainname, domainname, len); - - if (dirnamep) - { - const char *dirname = *dirnamep; - - if (dirname == NULL) - /* The default value. */ - dirname = _nl_default_dirname; - else - { - if (strcmp (dirname, _nl_default_dirname) == 0) - dirname = _nl_default_dirname; - else - { - char *result; -#if defined _LIBC || defined HAVE_STRDUP - result = strdup (dirname); - if (__builtin_expect (result == NULL, 0)) - goto failed_dirname; -#else - size_t len = strlen (dirname) + 1; - result = (char *) malloc (len); - if (__builtin_expect (result == NULL, 0)) - goto failed_dirname; - memcpy (result, dirname, len); -#endif - dirname = result; - } - } - *dirnamep = dirname; - new_binding->dirname = (char *) dirname; - } - else - /* The default value. */ - new_binding->dirname = (char *) _nl_default_dirname; - - new_binding->codeset_cntr = 0; - - if (codesetp) - { - const char *codeset = *codesetp; - - if (codeset != NULL) - { - char *result; - -#if defined _LIBC || defined HAVE_STRDUP - result = strdup (codeset); - if (__builtin_expect (result == NULL, 0)) - goto failed_codeset; -#else - size_t len = strlen (codeset) + 1; - result = (char *) malloc (len); - if (__builtin_expect (result == NULL, 0)) - goto failed_codeset; - memcpy (result, codeset, len); -#endif - codeset = result; - new_binding->codeset_cntr++; - } - *codesetp = codeset; - new_binding->codeset = (char *) codeset; - } - else - new_binding->codeset = NULL; - - /* Now enqueue it. */ - if (_nl_domain_bindings == NULL - || strcmp (domainname, _nl_domain_bindings->domainname) < 0) - { - new_binding->next = _nl_domain_bindings; - _nl_domain_bindings = new_binding; - } - else - { - binding = _nl_domain_bindings; - while (binding->next != NULL - && strcmp (domainname, binding->next->domainname) > 0) - binding = binding->next; - - new_binding->next = binding->next; - binding->next = new_binding; - } - - modified = 1; - - /* Here we deal with memory allocation failures. */ - if (0) - { - failed_codeset: - if (new_binding->dirname != _nl_default_dirname) - free (new_binding->dirname); - failed_dirname: - free (new_binding); - failed: - if (dirnamep) - *dirnamep = NULL; - if (codesetp) - *codesetp = NULL; - } - } - - /* If we modified any binding, we flush the caches. */ - if (modified) - ++_nl_msg_cat_cntr; - - __libc_rwlock_unlock (_nl_state_lock); -} - -/* Specify that the DOMAINNAME message catalog will be found - in DIRNAME rather than in the system locale data base. */ -char * -BINDTEXTDOMAIN (domainname, dirname) - const char *domainname; - const char *dirname; -{ - set_binding_values (domainname, &dirname, NULL); - return (char *) dirname; -} - -/* Specify the character encoding in which the messages from the - DOMAINNAME message catalog will be returned. */ -char * -BIND_TEXTDOMAIN_CODESET (domainname, codeset) - const char *domainname; - const char *codeset; -{ - set_binding_values (domainname, NULL, &codeset); - return (char *) codeset; -} - -#ifdef _LIBC -/* Aliases for function names in GNU C Library. */ -weak_alias (__bindtextdomain, bindtextdomain); -weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset); -#endif diff --git a/intl/cat-compat.c b/intl/cat-compat.c deleted file mode 100644 index 867d901b8..000000000 --- a/intl/cat-compat.c +++ /dev/null @@ -1,262 +0,0 @@ -/* Compatibility code for gettext-using-catgets interface. - Copyright (C) 1995, 1997 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#ifdef STDC_HEADERS -# include -# include -#else -char *getenv (); -# ifdef HAVE_MALLOC_H -# include -# endif -#endif - -#ifdef HAVE_NL_TYPES_H -# include -#endif - -#include "libgettext.h" - -/* @@ end of prolog @@ */ - -/* XPG3 defines the result of `setlocale (category, NULL)' as: - ``Directs `setlocale()' to query `category' and return the current - setting of `local'.'' - However it does not specify the exact format. And even worse: POSIX - defines this not at all. So we can use this feature only on selected - system (e.g. those using GNU C Library). */ -#ifdef _LIBC -# define HAVE_LOCALE_NULL -#endif - -/* The catalog descriptor. */ -static nl_catd catalog = (nl_catd) -1; - -/* Name of the default catalog. */ -static const char default_catalog_name[] = "messages"; - -/* Name of currently used catalog. */ -static const char *catalog_name = default_catalog_name; - -/* Get ID for given string. If not found return -1. */ -static int msg_to_cat_id PARAMS ((const char *msg)); - -/* Substitution for systems lacking this function in their C library. */ -#if !_LIBC && !HAVE_STPCPY -static char *stpcpy PARAMS ((char *dest, const char *src)); -#endif - - -/* Set currently used domain/catalog. */ -char * -textdomain (domainname) - const char *domainname; -{ - nl_catd new_catalog; - char *new_name; - size_t new_name_len; - char *lang; - -#if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES \ - && defined HAVE_LOCALE_NULL - lang = setlocale (LC_MESSAGES, NULL); -#else - lang = getenv ("LC_ALL"); - if (lang == NULL || lang[0] == '\0') - { - lang = getenv ("LC_MESSAGES"); - if (lang == NULL || lang[0] == '\0') - lang = getenv ("LANG"); - } -#endif - if (lang == NULL || lang[0] == '\0') - lang = "C"; - - /* See whether name of currently used domain is asked. */ - if (domainname == NULL) - return (char *) catalog_name; - - if (domainname[0] == '\0') - domainname = default_catalog_name; - - /* Compute length of added path element. */ - new_name_len = sizeof (LOCALEDIR) - 1 + 1 + strlen (lang) - + sizeof ("/LC_MESSAGES/") - 1 + sizeof (PACKAGE) - 1 - + sizeof (".cat"); - - new_name = (char *) malloc (new_name_len); - if (new_name == NULL) - return NULL; - - strcpy (new_name, PACKAGE); - new_catalog = catopen (new_name, 0); - - if (new_catalog == (nl_catd) -1) - { - /* NLSPATH search didn't work, try absolute path */ - sprintf (new_name, "%s/%s/LC_MESSAGES/%s.cat", LOCALEDIR, lang, - PACKAGE); - new_catalog = catopen (new_name, 0); - - if (new_catalog == (nl_catd) -1) - { - free (new_name); - return (char *) catalog_name; - } - } - - /* Close old catalog. */ - if (catalog != (nl_catd) -1) - catclose (catalog); - if (catalog_name != default_catalog_name) - free ((char *) catalog_name); - - catalog = new_catalog; - catalog_name = new_name; - - return (char *) catalog_name; -} - -char * -bindtextdomain (domainname, dirname) - const char *domainname; - const char *dirname; -{ -#if HAVE_SETENV || HAVE_PUTENV - char *old_val, *new_val, *cp; - size_t new_val_len; - - /* This does not make much sense here but to be compatible do it. */ - if (domainname == NULL) - return NULL; - - /* Compute length of added path element. If we use setenv we don't need - the first byts for NLSPATH=, but why complicate the code for this - peanuts. */ - new_val_len = sizeof ("NLSPATH=") - 1 + strlen (dirname) - + sizeof ("/%L/LC_MESSAGES/%N.cat"); - - old_val = getenv ("NLSPATH"); - if (old_val == NULL || old_val[0] == '\0') - { - old_val = NULL; - new_val_len += 1 + sizeof (LOCALEDIR) - 1 - + sizeof ("/%L/LC_MESSAGES/%N.cat"); - } - else - new_val_len += strlen (old_val); - - new_val = (char *) malloc (new_val_len); - if (new_val == NULL) - return NULL; - -# if HAVE_SETENV - cp = new_val; -# else - cp = stpcpy (new_val, "NLSPATH="); -# endif - - cp = stpcpy (cp, dirname); - cp = stpcpy (cp, "/%L/LC_MESSAGES/%N.cat:"); - - if (old_val == NULL) - { -# if __STDC__ - stpcpy (cp, LOCALEDIR "/%L/LC_MESSAGES/%N.cat"); -# else - - cp = stpcpy (cp, LOCALEDIR); - stpcpy (cp, "/%L/LC_MESSAGES/%N.cat"); -# endif - } - else - stpcpy (cp, old_val); - -# if HAVE_SETENV - setenv ("NLSPATH", new_val, 1); - free (new_val); -# else - putenv (new_val); - /* Do *not* free the environment entry we just entered. It is used - from now on. */ -# endif - -#endif - - return (char *) domainname; -} - -#undef gettext -char * -gettext (msg) - const char *msg; -{ - int msgid; - - if (msg == NULL || catalog == (nl_catd) -1) - return (char *) msg; - - /* Get the message from the catalog. We always use set number 1. - The message ID is computed by the function `msg_to_cat_id' - which works on the table generated by `po-to-tbl'. */ - msgid = msg_to_cat_id (msg); - if (msgid == -1) - return (char *) msg; - - return catgets (catalog, 1, msgid, (char *) msg); -} - -/* Look through the table `_msg_tbl' which has `_msg_tbl_length' entries - for the one equal to msg. If it is found return the ID. In case when - the string is not found return -1. */ -static int -msg_to_cat_id (msg) - const char *msg; -{ - int cnt; - - for (cnt = 0; cnt < _msg_tbl_length; ++cnt) - if (strcmp (msg, _msg_tbl[cnt]._msg) == 0) - return _msg_tbl[cnt]._msg_number; - - return -1; -} - - -/* @@ begin of epilog @@ */ - -/* We don't want libintl.a to depend on any other library. So we - avoid the non-standard function stpcpy. In GNU C Library this - function is available, though. Also allow the symbol HAVE_STPCPY - to be defined. */ -#if !_LIBC && !HAVE_STPCPY -static char * -stpcpy (dest, src) - char *dest; - const char *src; -{ - while ((*dest++ = *src++) != '\0') - /* Do nothing. */ ; - return dest - 1; -} -#endif diff --git a/intl/dcgettext.c b/intl/dcgettext.c deleted file mode 100644 index ca6a1c82d..000000000 --- a/intl/dcgettext.c +++ /dev/null @@ -1,59 +0,0 @@ -/* Implementation of the dcgettext(3) function. - Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "gettextP.h" -#ifdef _LIBC -# include -#else -# include "libgnuintl.h" -#endif - -/* @@ end of prolog @@ */ - -/* Names for the libintl functions are a problem. They must not clash - with existing names and they should follow ANSI C. But this source - code is also used in GNU C Library where the names have a __ - prefix. So we have to make a difference here. */ -#ifdef _LIBC -# define DCGETTEXT __dcgettext -# define DCIGETTEXT __dcigettext -#else -# define DCGETTEXT libintl_dcgettext -# define DCIGETTEXT libintl_dcigettext -#endif - -/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY - locale. */ -char * -DCGETTEXT (domainname, msgid, category) - const char *domainname; - const char *msgid; - int category; -{ - return DCIGETTEXT (domainname, msgid, NULL, 0, 0, category); -} - -#ifdef _LIBC -/* Alias for function name in GNU C Library. */ -INTDEF(__dcgettext) -weak_alias (__dcgettext, dcgettext); -#endif diff --git a/intl/dgettext.c b/intl/dgettext.c deleted file mode 100644 index cf5b4037f..000000000 --- a/intl/dgettext.c +++ /dev/null @@ -1,59 +0,0 @@ -/* Implementation of the dgettext(3) function. - Copyright (C) 1995-1997, 2000, 2001, 2002 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include "gettextP.h" -#ifdef _LIBC -# include -#else -# include "libgnuintl.h" -#endif - -/* @@ end of prolog @@ */ - -/* Names for the libintl functions are a problem. They must not clash - with existing names and they should follow ANSI C. But this source - code is also used in GNU C Library where the names have a __ - prefix. So we have to make a difference here. */ -#ifdef _LIBC -# define DGETTEXT __dgettext -# define DCGETTEXT INTUSE(__dcgettext) -#else -# define DGETTEXT libintl_dgettext -# define DCGETTEXT libintl_dcgettext -#endif - -/* Look up MSGID in the DOMAINNAME message catalog of the current - LC_MESSAGES locale. */ -char * -DGETTEXT (domainname, msgid) - const char *domainname; - const char *msgid; -{ - return DCGETTEXT (domainname, msgid, LC_MESSAGES); -} - -#ifdef _LIBC -/* Alias for function name in GNU C Library. */ -weak_alias (__dgettext, dgettext); -#endif diff --git a/intl/explodename.c b/intl/explodename.c deleted file mode 100644 index 2985064c9..000000000 --- a/intl/explodename.c +++ /dev/null @@ -1,192 +0,0 @@ -/* Copyright (C) 1995-1998, 2000, 2001 Free Software Foundation, Inc. - Contributed by Ulrich Drepper , 1995. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include - -#include "loadinfo.h" - -/* On some strange systems still no definition of NULL is found. Sigh! */ -#ifndef NULL -# if defined __STDC__ && __STDC__ -# define NULL ((void *) 0) -# else -# define NULL 0 -# endif -#endif - -/* @@ end of prolog @@ */ - -char * -_nl_find_language (name) - const char *name; -{ - while (name[0] != '\0' && name[0] != '_' && name[0] != '@' - && name[0] != '+' && name[0] != ',') - ++name; - - return (char *) name; -} - - -int -_nl_explode_name (name, language, modifier, territory, codeset, - normalized_codeset, special, sponsor, revision) - char *name; - const char **language; - const char **modifier; - const char **territory; - const char **codeset; - const char **normalized_codeset; - const char **special; - const char **sponsor; - const char **revision; -{ - enum { undecided, xpg, cen } syntax; - char *cp; - int mask; - - *modifier = NULL; - *territory = NULL; - *codeset = NULL; - *normalized_codeset = NULL; - *special = NULL; - *sponsor = NULL; - *revision = NULL; - - /* Now we determine the single parts of the locale name. First - look for the language. Termination symbols are `_' and `@' if - we use XPG4 style, and `_', `+', and `,' if we use CEN syntax. */ - mask = 0; - syntax = undecided; - *language = cp = name; - cp = _nl_find_language (*language); - - if (*language == cp) - /* This does not make sense: language has to be specified. Use - this entry as it is without exploding. Perhaps it is an alias. */ - cp = strchr (*language, '\0'); - else if (cp[0] == '_') - { - /* Next is the territory. */ - cp[0] = '\0'; - *territory = ++cp; - - while (cp[0] != '\0' && cp[0] != '.' && cp[0] != '@' - && cp[0] != '+' && cp[0] != ',' && cp[0] != '_') - ++cp; - - mask |= TERRITORY; - - if (cp[0] == '.') - { - /* Next is the codeset. */ - syntax = xpg; - cp[0] = '\0'; - *codeset = ++cp; - - while (cp[0] != '\0' && cp[0] != '@') - ++cp; - - mask |= XPG_CODESET; - - if (*codeset != cp && (*codeset)[0] != '\0') - { - *normalized_codeset = _nl_normalize_codeset (*codeset, - cp - *codeset); - if (strcmp (*codeset, *normalized_codeset) == 0) - free ((char *) *normalized_codeset); - else - mask |= XPG_NORM_CODESET; - } - } - } - - if (cp[0] == '@' || (syntax != xpg && cp[0] == '+')) - { - /* Next is the modifier. */ - syntax = cp[0] == '@' ? xpg : cen; - cp[0] = '\0'; - *modifier = ++cp; - - while (syntax == cen && cp[0] != '\0' && cp[0] != '+' - && cp[0] != ',' && cp[0] != '_') - ++cp; - - mask |= XPG_MODIFIER | CEN_AUDIENCE; - } - - if (syntax != xpg && (cp[0] == '+' || cp[0] == ',' || cp[0] == '_')) - { - syntax = cen; - - if (cp[0] == '+') - { - /* Next is special application (CEN syntax). */ - cp[0] = '\0'; - *special = ++cp; - - while (cp[0] != '\0' && cp[0] != ',' && cp[0] != '_') - ++cp; - - mask |= CEN_SPECIAL; - } - - if (cp[0] == ',') - { - /* Next is sponsor (CEN syntax). */ - cp[0] = '\0'; - *sponsor = ++cp; - - while (cp[0] != '\0' && cp[0] != '_') - ++cp; - - mask |= CEN_SPONSOR; - } - - if (cp[0] == '_') - { - /* Next is revision (CEN syntax). */ - cp[0] = '\0'; - *revision = ++cp; - - mask |= CEN_REVISION; - } - } - - /* For CEN syntax values it might be important to have the - separator character in the file name, not for XPG syntax. */ - if (syntax == xpg) - { - if (*territory != NULL && (*territory)[0] == '\0') - mask &= ~TERRITORY; - - if (*codeset != NULL && (*codeset)[0] == '\0') - mask &= ~XPG_CODESET; - - if (*modifier != NULL && (*modifier)[0] == '\0') - mask &= ~XPG_MODIFIER; - } - - return mask; -} diff --git a/intl/finddomain.c b/intl/finddomain.c deleted file mode 100644 index 2f103d556..000000000 --- a/intl/finddomain.c +++ /dev/null @@ -1,198 +0,0 @@ -/* Handle list of needed message catalogs - Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc. - Written by Ulrich Drepper , 1995. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include - -#if defined HAVE_UNISTD_H || defined _LIBC -# include -#endif - -#include "gettextP.h" -#ifdef _LIBC -# include -#else -# include "libgnuintl.h" -#endif - -/* @@ end of prolog @@ */ -/* List of already loaded domains. */ -static struct loaded_l10nfile *_nl_loaded_domains; - - -/* Return a data structure describing the message catalog described by - the DOMAINNAME and CATEGORY parameters with respect to the currently - established bindings. */ -struct loaded_l10nfile * -internal_function -_nl_find_domain (dirname, locale, domainname, domainbinding) - const char *dirname; - char *locale; - const char *domainname; - struct binding *domainbinding; -{ - struct loaded_l10nfile *retval; - const char *language; - const char *modifier; - const char *territory; - const char *codeset; - const char *normalized_codeset; - const char *special; - const char *sponsor; - const char *revision; - const char *alias_value; - int mask; - - /* LOCALE can consist of up to four recognized parts for the XPG syntax: - - language[_territory[.codeset]][@modifier] - - and six parts for the CEN syntax: - - language[_territory][+audience][+special][,[sponsor][_revision]] - - Beside the first part all of them are allowed to be missing. If - the full specified locale is not found, the less specific one are - looked for. The various parts will be stripped off according to - the following order: - (1) revision - (2) sponsor - (3) special - (4) codeset - (5) normalized codeset - (6) territory - (7) audience/modifier - */ - - /* If we have already tested for this locale entry there has to - be one data set in the list of loaded domains. */ - retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname, - strlen (dirname) + 1, 0, locale, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, domainname, 0); - if (retval != NULL) - { - /* We know something about this locale. */ - int cnt; - - if (retval->decided == 0) - _nl_load_domain (retval, domainbinding); - - if (retval->data != NULL) - return retval; - - for (cnt = 0; retval->successor[cnt] != NULL; ++cnt) - { - if (retval->successor[cnt]->decided == 0) - _nl_load_domain (retval->successor[cnt], domainbinding); - - if (retval->successor[cnt]->data != NULL) - break; - } - return cnt >= 0 ? retval : NULL; - /* NOTREACHED */ - } - - /* See whether the locale value is an alias. If yes its value - *overwrites* the alias name. No test for the original value is - done. */ - alias_value = _nl_expand_alias (locale); - if (alias_value != NULL) - { -#if defined _LIBC || defined HAVE_STRDUP - locale = strdup (alias_value); - if (locale == NULL) - return NULL; -#else - size_t len = strlen (alias_value) + 1; - locale = (char *) malloc (len); - if (locale == NULL) - return NULL; - - memcpy (locale, alias_value, len); -#endif - } - - /* Now we determine the single parts of the locale name. First - look for the language. Termination symbols are `_' and `@' if - we use XPG4 style, and `_', `+', and `,' if we use CEN syntax. */ - mask = _nl_explode_name (locale, &language, &modifier, &territory, - &codeset, &normalized_codeset, &special, - &sponsor, &revision); - - /* Create all possible locale entries which might be interested in - generalization. */ - retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname, - strlen (dirname) + 1, mask, language, territory, - codeset, normalized_codeset, modifier, special, - sponsor, revision, domainname, 1); - if (retval == NULL) - /* This means we are out of core. */ - return NULL; - - if (retval->decided == 0) - _nl_load_domain (retval, domainbinding); - if (retval->data == NULL) - { - int cnt; - for (cnt = 0; retval->successor[cnt] != NULL; ++cnt) - { - if (retval->successor[cnt]->decided == 0) - _nl_load_domain (retval->successor[cnt], domainbinding); - if (retval->successor[cnt]->data != NULL) - break; - } - } - - /* The room for an alias was dynamically allocated. Free it now. */ - if (alias_value != NULL) - free (locale); - - /* The space for normalized_codeset is dynamically allocated. Free it. */ - if (mask & XPG_NORM_CODESET) - free ((void *) normalized_codeset); - - return retval; -} - - -#ifdef _LIBC -static void __attribute__ ((unused)) -free_mem (void) -{ - struct loaded_l10nfile *runp = _nl_loaded_domains; - - while (runp != NULL) - { - struct loaded_l10nfile *here = runp; - if (runp->data != NULL) - _nl_unload_domain ((struct loaded_domain *) runp->data); - runp = runp->next; - free ((char *) here->filename); - free (here); - } -} - -text_set_element (__libc_subfreeres, free_mem); -#endif diff --git a/intl/gettext.c b/intl/gettext.c deleted file mode 100644 index 43d689f55..000000000 --- a/intl/gettext.c +++ /dev/null @@ -1,64 +0,0 @@ -/* Implementation of gettext(3) function. - Copyright (C) 1995, 1997, 2000, 2001, 2002 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#ifdef _LIBC -# define __need_NULL -# include -#else -# include /* Just for NULL. */ -#endif - -#include "gettextP.h" -#ifdef _LIBC -# include -#else -# include "libgnuintl.h" -#endif - -/* @@ end of prolog @@ */ - -/* Names for the libintl functions are a problem. They must not clash - with existing names and they should follow ANSI C. But this source - code is also used in GNU C Library where the names have a __ - prefix. So we have to make a difference here. */ -#ifdef _LIBC -# define GETTEXT __gettext -# define DCGETTEXT INTUSE(__dcgettext) -#else -# define GETTEXT libintl_gettext -# define DCGETTEXT libintl_dcgettext -#endif - -/* Look up MSGID in the current default message catalog for the current - LC_MESSAGES locale. If not found, returns MSGID itself (the default - text). */ -char * -GETTEXT (msgid) - const char *msgid; -{ - return DCGETTEXT (NULL, msgid, LC_MESSAGES); -} - -#ifdef _LIBC -/* Alias for function name in GNU C Library. */ -weak_alias (__gettext, gettext); -#endif diff --git a/intl/gettext.h b/intl/gettext.h deleted file mode 100644 index 6f5d76055..000000000 --- a/intl/gettext.h +++ /dev/null @@ -1,102 +0,0 @@ -/* Description of GNU message catalog format: general file layout. - Copyright (C) 1995, 1997, 2000, 2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ - -#ifndef _GETTEXT_H -#define _GETTEXT_H 1 - -#if HAVE_LIMITS_H || _LIBC -# include -#endif - -/* @@ end of prolog @@ */ - -/* The magic number of the GNU message catalog format. */ -#define _MAGIC 0x950412de -#define _MAGIC_SWAPPED 0xde120495 - -/* Revision number of the currently used .mo (binary) file format. */ -#define MO_REVISION_NUMBER 0 - -/* The following contortions are an attempt to use the C preprocessor - to determine an unsigned integral type that is 32 bits wide. An - alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but - as of version autoconf-2.13, the AC_CHECK_SIZEOF macro doesn't work - when cross-compiling. */ - -#if __STDC__ -# define UINT_MAX_32_BITS 4294967295U -#else -# define UINT_MAX_32_BITS 0xFFFFFFFF -#endif - -/* If UINT_MAX isn't defined, assume it's a 32-bit type. - This should be valid for all systems GNU cares about because - that doesn't include 16-bit systems, and only modern systems - (that certainly have ) have 64+-bit integral types. */ - -#ifndef UINT_MAX -# define UINT_MAX UINT_MAX_32_BITS -#endif - -#if UINT_MAX == UINT_MAX_32_BITS -typedef unsigned nls_uint32; -#else -# if USHRT_MAX == UINT_MAX_32_BITS -typedef unsigned short nls_uint32; -# else -# if ULONG_MAX == UINT_MAX_32_BITS -typedef unsigned long nls_uint32; -# else - /* The following line is intended to throw an error. Using #error is - not portable enough. */ - "Cannot determine unsigned 32-bit data type." -# endif -# endif -#endif - - -/* Header for binary .mo file format. */ -struct mo_file_header -{ - /* The magic number. */ - nls_uint32 magic; - /* The revision number of the file format. */ - nls_uint32 revision; - /* The number of strings pairs. */ - nls_uint32 nstrings; - /* Offset of table with start offsets of original strings. */ - nls_uint32 orig_tab_offset; - /* Offset of table with start offsets of translation strings. */ - nls_uint32 trans_tab_offset; - /* Size of hashing table. */ - nls_uint32 hash_tab_size; - /* Offset of first hashing entry. */ - nls_uint32 hash_tab_offset; -}; - -struct string_desc -{ - /* Length of addressed string. */ - nls_uint32 length; - /* Offset of string in file. */ - nls_uint32 offset; -}; - -/* @@ begin of epilog @@ */ - -#endif /* gettext.h */ diff --git a/intl/gettextP.h b/intl/gettextP.h deleted file mode 100644 index f085c59bb..000000000 --- a/intl/gettextP.h +++ /dev/null @@ -1,242 +0,0 @@ -/* Header describing internals of libintl library. - Copyright (C) 1995-1999, 2000-2002 Free Software Foundation, Inc. - Written by Ulrich Drepper , 1995. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ - -#ifndef _GETTEXTP_H -#define _GETTEXTP_H - -#include /* Get size_t. */ - -#ifdef _LIBC -# include "../iconv/gconv_int.h" -#else -# if HAVE_ICONV -# include -# endif -#endif - -#include "loadinfo.h" - -#include "gmo.h" /* Get nls_uint32. */ - -/* @@ end of prolog @@ */ - -#ifndef PARAMS -# if __STDC__ || defined __GNUC__ || defined __SUNPRO_C || defined __cplusplus || __PROTOTYPES -# define PARAMS(args) args -# else -# define PARAMS(args) () -# endif -#endif - -#ifndef internal_function -# define internal_function -#endif - -#ifndef attribute_hidden -# define attribute_hidden -#endif - -/* Tell the compiler when a conditional or integer expression is - almost always true or almost always false. */ -#ifndef HAVE_BUILTIN_EXPECT -# define __builtin_expect(expr, val) (expr) -#endif - -#ifndef W -# define W(flag, data) ((flag) ? SWAP (data) : (data)) -#endif - - -#ifdef _LIBC -# include -# define SWAP(i) bswap_32 (i) -#else -static inline nls_uint32 -SWAP (i) - nls_uint32 i; -{ - return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24); -} -#endif - - -/* In-memory representation of system dependent string. */ -struct sysdep_string_desc -{ - /* Length of addressed string, including the trailing NUL. */ - size_t length; - /* Pointer to addressed string. */ - const char *pointer; -}; - -/* The representation of an opened message catalog. */ -struct loaded_domain -{ - /* Pointer to memory containing the .mo file. */ - const char *data; - /* 1 if the memory is mmap()ed, 0 if the memory is malloc()ed. */ - int use_mmap; - /* Size of mmap()ed memory. */ - size_t mmap_size; - /* 1 if the .mo file uses a different endianness than this machine. */ - int must_swap; - /* Pointer to additional malloc()ed memory. */ - void *malloced; - - /* Number of static strings pairs. */ - nls_uint32 nstrings; - /* Pointer to descriptors of original strings in the file. */ - const struct string_desc *orig_tab; - /* Pointer to descriptors of translated strings in the file. */ - const struct string_desc *trans_tab; - - /* Number of system dependent strings pairs. */ - nls_uint32 n_sysdep_strings; - /* Pointer to descriptors of original sysdep strings. */ - const struct sysdep_string_desc *orig_sysdep_tab; - /* Pointer to descriptors of translated sysdep strings. */ - const struct sysdep_string_desc *trans_sysdep_tab; - - /* Size of hash table. */ - nls_uint32 hash_size; - /* Pointer to hash table. */ - const nls_uint32 *hash_tab; - /* 1 if the hash table uses a different endianness than this machine. */ - int must_swap_hash_tab; - - int codeset_cntr; -#ifdef _LIBC - __gconv_t conv; -#else -# if HAVE_ICONV - iconv_t conv; -# endif -#endif - char **conv_tab; - - struct expression *plural; - unsigned long int nplurals; -}; - -/* We want to allocate a string at the end of the struct. But ISO C - doesn't allow zero sized arrays. */ -#ifdef __GNUC__ -# define ZERO 0 -#else -# define ZERO 1 -#endif - -/* A set of settings bound to a message domain. Used to store settings - from bindtextdomain() and bind_textdomain_codeset(). */ -struct binding -{ - struct binding *next; - char *dirname; - int codeset_cntr; /* Incremented each time codeset changes. */ - char *codeset; - char domainname[ZERO]; -}; - -/* A counter which is incremented each time some previous translations - become invalid. - This variable is part of the external ABI of the GNU libintl. */ -extern int _nl_msg_cat_cntr; - -#ifndef _LIBC -const char *_nl_locale_name PARAMS ((int category, const char *categoryname)); -#endif - -struct loaded_l10nfile *_nl_find_domain PARAMS ((const char *__dirname, - char *__locale, - const char *__domainname, - struct binding *__domainbinding)) - internal_function; -void _nl_load_domain PARAMS ((struct loaded_l10nfile *__domain, - struct binding *__domainbinding)) - internal_function; -void _nl_unload_domain PARAMS ((struct loaded_domain *__domain)) - internal_function; -const char *_nl_init_domain_conv PARAMS ((struct loaded_l10nfile *__domain_file, - struct loaded_domain *__domain, - struct binding *__domainbinding)) - internal_function; -void _nl_free_domain_conv PARAMS ((struct loaded_domain *__domain)) - internal_function; - -char *_nl_find_msg PARAMS ((struct loaded_l10nfile *domain_file, - struct binding *domainbinding, - const char *msgid, size_t *lengthp)) - internal_function; - -#ifdef _LIBC -extern char *__gettext PARAMS ((const char *__msgid)); -extern char *__dgettext PARAMS ((const char *__domainname, - const char *__msgid)); -extern char *__dcgettext PARAMS ((const char *__domainname, - const char *__msgid, int __category)); -extern char *__ngettext PARAMS ((const char *__msgid1, const char *__msgid2, - unsigned long int __n)); -extern char *__dngettext PARAMS ((const char *__domainname, - const char *__msgid1, const char *__msgid2, - unsigned long int n)); -extern char *__dcngettext PARAMS ((const char *__domainname, - const char *__msgid1, const char *__msgid2, - unsigned long int __n, int __category)); -extern char *__dcigettext PARAMS ((const char *__domainname, - const char *__msgid1, const char *__msgid2, - int __plural, unsigned long int __n, - int __category)); -extern char *__textdomain PARAMS ((const char *__domainname)); -extern char *__bindtextdomain PARAMS ((const char *__domainname, - const char *__dirname)); -extern char *__bind_textdomain_codeset PARAMS ((const char *__domainname, - const char *__codeset)); -#else -extern char *libintl_gettext PARAMS ((const char *__msgid)); -extern char *libintl_dgettext PARAMS ((const char *__domainname, - const char *__msgid)); -extern char *libintl_dcgettext PARAMS ((const char *__domainname, - const char *__msgid, int __category)); -extern char *libintl_ngettext PARAMS ((const char *__msgid1, - const char *__msgid2, - unsigned long int __n)); -extern char *libintl_dngettext PARAMS ((const char *__domainname, - const char *__msgid1, - const char *__msgid2, - unsigned long int __n)); -extern char *libintl_dcngettext PARAMS ((const char *__domainname, - const char *__msgid1, - const char *__msgid2, - unsigned long int __n, - int __category)); -extern char *libintl_dcigettext PARAMS ((const char *__domainname, - const char *__msgid1, - const char *__msgid2, - int __plural, unsigned long int __n, - int __category)); -extern char *libintl_textdomain PARAMS ((const char *__domainname)); -extern char *libintl_bindtextdomain PARAMS ((const char *__domainname, - const char *__dirname)); -extern char *libintl_bind_textdomain_codeset PARAMS ((const char *__domainname, - const char *__codeset)); -#endif - -/* @@ begin of epilog @@ */ - -#endif /* gettextP.h */ diff --git a/intl/hash-string.h b/intl/hash-string.h deleted file mode 100644 index b267a8778..000000000 --- a/intl/hash-string.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Description of GNU message catalog format: string hashing function. - Copyright (C) 1995, 1997, 1998, 2000, 2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ - -/* @@ end of prolog @@ */ - -#ifndef PARAMS -# if __STDC__ || defined __GNUC__ || defined __SUNPRO_C || defined __cplusplus || __PROTOTYPES -# define PARAMS(Args) Args -# else -# define PARAMS(Args) () -# endif -#endif - -/* We assume to have `unsigned long int' value with at least 32 bits. */ -#define HASHWORDBITS 32 - - -/* Defines the so called `hashpjw' function by P.J. Weinberger - [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, - 1986, 1987 Bell Telephone Laboratories, Inc.] */ -static unsigned long int hash_string PARAMS ((const char *__str_param)); - -static inline unsigned long int -hash_string (str_param) - const char *str_param; -{ - unsigned long int hval, g; - const char *str = str_param; - - /* Compute the hash value for the given string. */ - hval = 0; - while (*str != '\0') - { - hval <<= 4; - hval += (unsigned long int) *str++; - g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4)); - if (g != 0) - { - hval ^= g >> (HASHWORDBITS - 8); - hval ^= g; - } - } - return hval; -} diff --git a/intl/intl-compat.c b/intl/intl-compat.c deleted file mode 100644 index da890159f..000000000 --- a/intl/intl-compat.c +++ /dev/null @@ -1,131 +0,0 @@ -/* intl-compat.c - Stub functions to call gettext functions from GNU gettext - Library. - Copyright (C) 1995, 2000-2002 Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#define _INTL_REDIRECT_MACROS -#include "libgnuintl.h" -#include "gettextP.h" - -/* @@ end of prolog @@ */ - -/* This file redirects the gettext functions (without prefix) to those - defined in the included GNU libintl library (with "libintl_" prefix). - It is compiled into libintl in order to make the AM_GNU_GETTEXT test - of gettext <= 0.11.2 work with the libintl library >= 0.11.3 which - has the redirections primarily in the include file. */ - - -#undef gettext -#undef dgettext -#undef dcgettext -#undef ngettext -#undef dngettext -#undef dcngettext -#undef textdomain -#undef bindtextdomain -#undef bind_textdomain_codeset - - -char * -gettext (msgid) - const char *msgid; -{ - return libintl_gettext (msgid); -} - - -char * -dgettext (domainname, msgid) - const char *domainname; - const char *msgid; -{ - return libintl_dgettext (domainname, msgid); -} - - -char * -dcgettext (domainname, msgid, category) - const char *domainname; - const char *msgid; - int category; -{ - return libintl_dcgettext (domainname, msgid, category); -} - - -char * -ngettext (msgid1, msgid2, n) - const char *msgid1; - const char *msgid2; - unsigned long int n; -{ - return libintl_ngettext (msgid1, msgid2, n); -} - - -char * -dngettext (domainname, msgid1, msgid2, n) - const char *domainname; - const char *msgid1; - const char *msgid2; - unsigned long int n; -{ - return libintl_dngettext (domainname, msgid1, msgid2, n); -} - - -char * -dcngettext (domainname, msgid1, msgid2, n, category) - const char *domainname; - const char *msgid1; - const char *msgid2; - unsigned long int n; - int category; -{ - return libintl_dcngettext (domainname, msgid1, msgid2, n, category); -} - - -char * -textdomain (domainname) - const char *domainname; -{ - return libintl_textdomain (domainname); -} - - -char * -bindtextdomain (domainname, dirname) - const char *domainname; - const char *dirname; -{ - return libintl_bindtextdomain (domainname, dirname); -} - - -char * -bind_textdomain_codeset (domainname, codeset) - const char *domainname; - const char *codeset; -{ - return libintl_bind_textdomain_codeset (domainname, codeset); -} diff --git a/intl/l10nflist.c b/intl/l10nflist.c deleted file mode 100644 index ec8713f8e..000000000 --- a/intl/l10nflist.c +++ /dev/null @@ -1,453 +0,0 @@ -/* Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc. - Contributed by Ulrich Drepper , 1995. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ - -/* Tell glibc's to provide a prototype for stpcpy(). - This must come before because may include - , and once has been included, it's too late. */ -#ifndef _GNU_SOURCE -# define _GNU_SOURCE 1 -#endif - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#if defined _LIBC || defined HAVE_ARGZ_H -# include -#endif -#include -#include -#include - -#include "loadinfo.h" - -/* On some strange systems still no definition of NULL is found. Sigh! */ -#ifndef NULL -# if defined __STDC__ && __STDC__ -# define NULL ((void *) 0) -# else -# define NULL 0 -# endif -#endif - -/* @@ end of prolog @@ */ - -#ifdef _LIBC -/* Rename the non ANSI C functions. This is required by the standard - because some ANSI C functions will require linking with this object - file and the name space must not be polluted. */ -# ifndef stpcpy -# define stpcpy(dest, src) __stpcpy(dest, src) -# endif -#else -# ifndef HAVE_STPCPY -static char *stpcpy PARAMS ((char *dest, const char *src)); -# endif -#endif - -/* Pathname support. - ISSLASH(C) tests whether C is a directory separator character. - IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not, - it may be concatenated to a directory pathname. - */ -#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__ - /* Win32, OS/2, DOS */ -# define ISSLASH(C) ((C) == '/' || (C) == '\\') -# define HAS_DEVICE(P) \ - ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \ - && (P)[1] == ':') -# define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P)) -#else - /* Unix */ -# define ISSLASH(C) ((C) == '/') -# define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0]) -#endif - -/* Define function which are usually not available. */ - -#if !defined _LIBC && !defined HAVE___ARGZ_COUNT -/* Returns the number of strings in ARGZ. */ -static size_t argz_count__ PARAMS ((const char *argz, size_t len)); - -static size_t -argz_count__ (argz, len) - const char *argz; - size_t len; -{ - size_t count = 0; - while (len > 0) - { - size_t part_len = strlen (argz); - argz += part_len + 1; - len -= part_len + 1; - count++; - } - return count; -} -# undef __argz_count -# define __argz_count(argz, len) argz_count__ (argz, len) -#else -# ifdef _LIBC -# define __argz_count(argz, len) INTUSE(__argz_count) (argz, len) -# endif -#endif /* !_LIBC && !HAVE___ARGZ_COUNT */ - -#if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY -/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's - except the last into the character SEP. */ -static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep)); - -static void -argz_stringify__ (argz, len, sep) - char *argz; - size_t len; - int sep; -{ - while (len > 0) - { - size_t part_len = strlen (argz); - argz += part_len; - len -= part_len + 1; - if (len > 0) - *argz++ = sep; - } -} -# undef __argz_stringify -# define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep) -#else -# ifdef _LIBC -# define __argz_stringify(argz, len, sep) \ - INTUSE(__argz_stringify) (argz, len, sep) -# endif -#endif /* !_LIBC && !HAVE___ARGZ_STRINGIFY */ - -#if !defined _LIBC && !defined HAVE___ARGZ_NEXT -static char *argz_next__ PARAMS ((char *argz, size_t argz_len, - const char *entry)); - -static char * -argz_next__ (argz, argz_len, entry) - char *argz; - size_t argz_len; - const char *entry; -{ - if (entry) - { - if (entry < argz + argz_len) - entry = strchr (entry, '\0') + 1; - - return entry >= argz + argz_len ? NULL : (char *) entry; - } - else - if (argz_len > 0) - return argz; - else - return 0; -} -# undef __argz_next -# define __argz_next(argz, len, entry) argz_next__ (argz, len, entry) -#endif /* !_LIBC && !HAVE___ARGZ_NEXT */ - - -/* Return number of bits set in X. */ -static int pop PARAMS ((int x)); - -static inline int -pop (x) - int x; -{ - /* We assume that no more than 16 bits are used. */ - x = ((x & ~0x5555) >> 1) + (x & 0x5555); - x = ((x & ~0x3333) >> 2) + (x & 0x3333); - x = ((x >> 4) + x) & 0x0f0f; - x = ((x >> 8) + x) & 0xff; - - return x; -} - - -struct loaded_l10nfile * -_nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language, - territory, codeset, normalized_codeset, modifier, special, - sponsor, revision, filename, do_allocate) - struct loaded_l10nfile **l10nfile_list; - const char *dirlist; - size_t dirlist_len; - int mask; - const char *language; - const char *territory; - const char *codeset; - const char *normalized_codeset; - const char *modifier; - const char *special; - const char *sponsor; - const char *revision; - const char *filename; - int do_allocate; -{ - char *abs_filename; - struct loaded_l10nfile **lastp; - struct loaded_l10nfile *retval; - char *cp; - size_t dirlist_count; - size_t entries; - int cnt; - - /* If LANGUAGE contains an absolute directory specification, we ignore - DIRLIST. */ - if (IS_ABSOLUTE_PATH (language)) - dirlist_len = 0; - - /* Allocate room for the full file name. */ - abs_filename = (char *) malloc (dirlist_len - + strlen (language) - + ((mask & TERRITORY) != 0 - ? strlen (territory) + 1 : 0) - + ((mask & XPG_CODESET) != 0 - ? strlen (codeset) + 1 : 0) - + ((mask & XPG_NORM_CODESET) != 0 - ? strlen (normalized_codeset) + 1 : 0) - + (((mask & XPG_MODIFIER) != 0 - || (mask & CEN_AUDIENCE) != 0) - ? strlen (modifier) + 1 : 0) - + ((mask & CEN_SPECIAL) != 0 - ? strlen (special) + 1 : 0) - + (((mask & CEN_SPONSOR) != 0 - || (mask & CEN_REVISION) != 0) - ? (1 + ((mask & CEN_SPONSOR) != 0 - ? strlen (sponsor) : 0) - + ((mask & CEN_REVISION) != 0 - ? strlen (revision) + 1 : 0)) : 0) - + 1 + strlen (filename) + 1); - - if (abs_filename == NULL) - return NULL; - - /* Construct file name. */ - cp = abs_filename; - if (dirlist_len > 0) - { - memcpy (cp, dirlist, dirlist_len); - __argz_stringify (cp, dirlist_len, PATH_SEPARATOR); - cp += dirlist_len; - cp[-1] = '/'; - } - - cp = stpcpy (cp, language); - - if ((mask & TERRITORY) != 0) - { - *cp++ = '_'; - cp = stpcpy (cp, territory); - } - if ((mask & XPG_CODESET) != 0) - { - *cp++ = '.'; - cp = stpcpy (cp, codeset); - } - if ((mask & XPG_NORM_CODESET) != 0) - { - *cp++ = '.'; - cp = stpcpy (cp, normalized_codeset); - } - if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0) - { - /* This component can be part of both syntaces but has different - leading characters. For CEN we use `+', else `@'. */ - *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@'; - cp = stpcpy (cp, modifier); - } - if ((mask & CEN_SPECIAL) != 0) - { - *cp++ = '+'; - cp = stpcpy (cp, special); - } - if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0) - { - *cp++ = ','; - if ((mask & CEN_SPONSOR) != 0) - cp = stpcpy (cp, sponsor); - if ((mask & CEN_REVISION) != 0) - { - *cp++ = '_'; - cp = stpcpy (cp, revision); - } - } - - *cp++ = '/'; - stpcpy (cp, filename); - - /* Look in list of already loaded domains whether it is already - available. */ - lastp = l10nfile_list; - for (retval = *l10nfile_list; retval != NULL; retval = retval->next) - if (retval->filename != NULL) - { - int compare = strcmp (retval->filename, abs_filename); - if (compare == 0) - /* We found it! */ - break; - if (compare < 0) - { - /* It's not in the list. */ - retval = NULL; - break; - } - - lastp = &retval->next; - } - - if (retval != NULL || do_allocate == 0) - { - free (abs_filename); - return retval; - } - - dirlist_count = (dirlist_len > 0 ? __argz_count (dirlist, dirlist_len) : 1); - - /* Allocate a new loaded_l10nfile. */ - retval = - (struct loaded_l10nfile *) - malloc (sizeof (*retval) - + (((dirlist_count << pop (mask)) + (dirlist_count > 1 ? 1 : 0)) - * sizeof (struct loaded_l10nfile *))); - if (retval == NULL) - return NULL; - - retval->filename = abs_filename; - - /* We set retval->data to NULL here; it is filled in later. - Setting retval->decided to 1 here means that retval does not - correspond to a real file (dirlist_count > 1) or is not worth - looking up (if an unnormalized codeset was specified). */ - retval->decided = (dirlist_count > 1 - || ((mask & XPG_CODESET) != 0 - && (mask & XPG_NORM_CODESET) != 0)); - retval->data = NULL; - - retval->next = *lastp; - *lastp = retval; - - entries = 0; - /* Recurse to fill the inheritance list of RETVAL. - If the DIRLIST is a real list (i.e. DIRLIST_COUNT > 1), the RETVAL - entry does not correspond to a real file; retval->filename contains - colons. In this case we loop across all elements of DIRLIST and - across all bit patterns dominated by MASK. - If the DIRLIST is a single directory or entirely redundant (i.e. - DIRLIST_COUNT == 1), we loop across all bit patterns dominated by - MASK, excluding MASK itself. - In either case, we loop down from MASK to 0. This has the effect - that the extra bits in the locale name are dropped in this order: - first the modifier, then the territory, then the codeset, then the - normalized_codeset. */ - for (cnt = dirlist_count > 1 ? mask : mask - 1; cnt >= 0; --cnt) - if ((cnt & ~mask) == 0 - && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0) - && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0)) - { - if (dirlist_count > 1) - { - /* Iterate over all elements of the DIRLIST. */ - char *dir = NULL; - - while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir)) - != NULL) - retval->successor[entries++] - = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, - cnt, language, territory, codeset, - normalized_codeset, modifier, special, - sponsor, revision, filename, 1); - } - else - retval->successor[entries++] - = _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, - cnt, language, territory, codeset, - normalized_codeset, modifier, special, - sponsor, revision, filename, 1); - } - retval->successor[entries] = NULL; - - return retval; -} - -/* Normalize codeset name. There is no standard for the codeset - names. Normalization allows the user to use any of the common - names. The return value is dynamically allocated and has to be - freed by the caller. */ -const char * -_nl_normalize_codeset (codeset, name_len) - const char *codeset; - size_t name_len; -{ - int len = 0; - int only_digit = 1; - char *retval; - char *wp; - size_t cnt; - - for (cnt = 0; cnt < name_len; ++cnt) - if (isalnum ((unsigned char) codeset[cnt])) - { - ++len; - - if (isalpha ((unsigned char) codeset[cnt])) - only_digit = 0; - } - - retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1); - - if (retval != NULL) - { - if (only_digit) - wp = stpcpy (retval, "iso"); - else - wp = retval; - - for (cnt = 0; cnt < name_len; ++cnt) - if (isalpha ((unsigned char) codeset[cnt])) - *wp++ = tolower ((unsigned char) codeset[cnt]); - else if (isdigit ((unsigned char) codeset[cnt])) - *wp++ = codeset[cnt]; - - *wp = '\0'; - } - - return (const char *) retval; -} - - -/* @@ begin of epilog @@ */ - -/* We don't want libintl.a to depend on any other library. So we - avoid the non-standard function stpcpy. In GNU C Library this - function is available, though. Also allow the symbol HAVE_STPCPY - to be defined. */ -#if !_LIBC && !HAVE_STPCPY -static char * -stpcpy (dest, src) - char *dest; - const char *src; -{ - while ((*dest++ = *src++) != '\0') - /* Do nothing. */ ; - return dest - 1; -} -#endif diff --git a/intl/libgettext.h b/intl/libgettext.h deleted file mode 100644 index c5be54a80..000000000 --- a/intl/libgettext.h +++ /dev/null @@ -1,49 +0,0 @@ -/* Convenience header for conditional use of GNU . - Copyright (C) 1995-1998, 2000, 2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ - -#ifndef _LIBGETTEXT_H -#define _LIBGETTEXT_H 1 - -/* NLS can be disabled through the configure --disable-nls option. */ -#if ENABLE_NLS - -/* Get declarations of GNU message catalog functions. */ -# include - -#else - -# define gettext(Msgid) (Msgid) -# define dgettext(Domainname, Msgid) (Msgid) -# define dcgettext(Domainname, Msgid, Category) (Msgid) -# define ngettext(Msgid1, Msgid2, N) \ - ((N) == 1 ? (char *) (Msgid1) : (char *) (Msgid2)) -# define dngettext(Domainname, Msgid1, Msgid2, N) \ - ((N) == 1 ? (char *) (Msgid1) : (char *) (Msgid2)) -# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ - ((N) == 1 ? (char *) (Msgid1) : (char *) (Msgid2)) -# define textdomain(Domainname) ((char *) (Domainname)) -# define bindtextdomain(Domainname, Dirname) ((char *) (Dirname)) -# define bind_textdomain_codeset(Domainname, Codeset) ((char *) (Codeset)) - -#endif - -/* For automatical extraction of messages sometimes no real - translation is needed. Instead the string itself is the result. */ -#define gettext_noop(Str) (Str) - -#endif /* _LIBGETTEXT_H */ diff --git a/intl/linux-msg.sed b/intl/linux-msg.sed deleted file mode 100644 index 5918e720a..000000000 --- a/intl/linux-msg.sed +++ /dev/null @@ -1,100 +0,0 @@ -# po2msg.sed - Convert Uniforum style .po file to Linux style .msg file -# Copyright (C) 1995 Free Software Foundation, Inc. -# Ulrich Drepper , 1995. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# -# The first directive in the .msg should be the definition of the -# message set number. We use always set number 1. -# -1 { - i\ -$set 1 # Automatically created by po2msg.sed - h - s/.*/0/ - x -} -# -# Mitch's old catalog format does not allow comments. -# -# We copy the original message as a comment into the .msg file. -# -/^msgid/ { - s/msgid[ ]*"// -# -# This does not work now with the new format. -# /"$/! { -# s/\\$// -# s/$/ ... (more lines following)"/ -# } - x -# The following nice solution is by -# Bruno - td -# Increment a decimal number in pattern space. -# First hide trailing `9' digits. - :d - s/9\(_*\)$/_\1/ - td -# Assure at least one digit is available. - s/^\(_*\)$/0\1/ -# Increment the last digit. - s/8\(_*\)$/9\1/ - s/7\(_*\)$/8\1/ - s/6\(_*\)$/7\1/ - s/5\(_*\)$/6\1/ - s/4\(_*\)$/5\1/ - s/3\(_*\)$/4\1/ - s/2\(_*\)$/3\1/ - s/1\(_*\)$/2\1/ - s/0\(_*\)$/1\1/ -# Convert the hidden `9' digits to `0's. - s/_/0/g - x - G - s/\(.*\)"\n\([0-9]*\)/$ #\2 Original Message:(\1)/p -} -# -# The .msg file contains, other then the .po file, only the translations -# but each given a unique ID. Starting from 1 and incrementing by 1 for -# each message we assign them to the messages. -# It is important that the .po file used to generate the cat-id-tbl.c file -# (with po-to-tbl) is the same as the one used here. (At least the order -# of declarations must not be changed.) -# -/^msgstr/ { - s/msgstr[ ]*"\(.*\)"/# \1/ -# Clear substitution flag. - tb -# Append the next line. - :b - N -# Look whether second part is continuation line. - s/\(.*\n\)"\(.*\)"/\1\2/ -# Yes, then branch. - ta - P - D -# Note that D includes a jump to the start!! -# We found a continuation line. But before printing insert '\'. - :a - s/\(.*\)\(\n.*\)/\1\\\2/ - P -# We cannot use D here. - s/.*\n\(.*\)/\1/ - tb -} -d diff --git a/intl/loadinfo.h b/intl/loadinfo.h deleted file mode 100644 index 1d3ba6162..000000000 --- a/intl/loadinfo.h +++ /dev/null @@ -1,156 +0,0 @@ -/* Copyright (C) 1996-1999, 2000-2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1996. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ - -#ifndef _LOADINFO_H -#define _LOADINFO_H 1 - -/* Declarations of locale dependent catalog lookup functions. - Implemented in - - localealias.c Possibly replace a locale name by another. - explodename.c Split a locale name into its various fields. - l10nflist.c Generate a list of filenames of possible message catalogs. - finddomain.c Find and open the relevant message catalogs. - - The main function _nl_find_domain() in finddomain.c is declared - in gettextP.h. - */ - -#ifndef PARAMS -# if __STDC__ || defined __GNUC__ || defined __SUNPRO_C || defined __cplusplus || __PROTOTYPES -# define PARAMS(args) args -# else -# define PARAMS(args) () -# endif -#endif - -#ifndef internal_function -# define internal_function -#endif - -/* Tell the compiler when a conditional or integer expression is - almost always true or almost always false. */ -#ifndef HAVE_BUILTIN_EXPECT -# define __builtin_expect(expr, val) (expr) -#endif - -/* Separator in PATH like lists of pathnames. */ -#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__ - /* Win32, OS/2, DOS */ -# define PATH_SEPARATOR ';' -#else - /* Unix */ -# define PATH_SEPARATOR ':' -#endif - -/* Encoding of locale name parts. */ -#define CEN_REVISION 1 -#define CEN_SPONSOR 2 -#define CEN_SPECIAL 4 -#define XPG_NORM_CODESET 8 -#define XPG_CODESET 16 -#define TERRITORY 32 -#define CEN_AUDIENCE 64 -#define XPG_MODIFIER 128 - -#define CEN_SPECIFIC (CEN_REVISION|CEN_SPONSOR|CEN_SPECIAL|CEN_AUDIENCE) -#define XPG_SPECIFIC (XPG_CODESET|XPG_NORM_CODESET|XPG_MODIFIER) - - -struct loaded_l10nfile -{ - const char *filename; - int decided; - - const void *data; - - struct loaded_l10nfile *next; - struct loaded_l10nfile *successor[1]; -}; - - -/* Normalize codeset name. There is no standard for the codeset - names. Normalization allows the user to use any of the common - names. The return value is dynamically allocated and has to be - freed by the caller. */ -extern const char *_nl_normalize_codeset PARAMS ((const char *codeset, - size_t name_len)); - -/* Lookup a locale dependent file. - *L10NFILE_LIST denotes a pool of lookup results of locale dependent - files of the same kind, sorted in decreasing order of ->filename. - DIRLIST and DIRLIST_LEN are an argz list of directories in which to - look, containing at least one directory (i.e. DIRLIST_LEN > 0). - MASK, LANGUAGE, TERRITORY, CODESET, NORMALIZED_CODESET, MODIFIER, - SPECIAL, SPONSOR, REVISION are the pieces of the locale name, as - produced by _nl_explode_name(). FILENAME is the filename suffix. - The return value is the lookup result, either found in *L10NFILE_LIST, - or - if DO_ALLOCATE is nonzero - freshly allocated, or possibly NULL. - If the return value is non-NULL, it is added to *L10NFILE_LIST, and - its ->next field denotes the chaining inside *L10NFILE_LIST, and - furthermore its ->successor[] field contains a list of other lookup - results from which this lookup result inherits. */ -extern struct loaded_l10nfile * -_nl_make_l10nflist PARAMS ((struct loaded_l10nfile **l10nfile_list, - const char *dirlist, size_t dirlist_len, int mask, - const char *language, const char *territory, - const char *codeset, - const char *normalized_codeset, - const char *modifier, const char *special, - const char *sponsor, const char *revision, - const char *filename, int do_allocate)); - -/* Lookup the real locale name for a locale alias NAME, or NULL if - NAME is not a locale alias (but possibly a real locale name). - The return value is statically allocated and must not be freed. */ -extern const char *_nl_expand_alias PARAMS ((const char *name)); - -/* Split a locale name NAME into its pieces: language, modifier, - territory, codeset, special, sponsor, revision. - NAME gets destructively modified: NUL bytes are inserted here and - there. *LANGUAGE gets assigned NAME. Each of *MODIFIER, *TERRITORY, - *CODESET, *SPECIAL, *SPONSOR, *REVISION gets assigned either a - pointer into the old NAME string, or NULL. *NORMALIZED_CODESET - gets assigned the expanded *CODESET, if it is different from *CODESET; - this one is dynamically allocated and has to be freed by the caller. - The return value is a bitmask, where each bit corresponds to one - filled-in value: - XPG_MODIFIER, CEN_AUDIENCE for *MODIFIER, - TERRITORY for *TERRITORY, - XPG_CODESET for *CODESET, - XPG_NORM_CODESET for *NORMALIZED_CODESET, - CEN_SPECIAL for *SPECIAL, - CEN_SPONSOR for *SPONSOR, - CEN_REVISION for *REVISION. - */ -extern int _nl_explode_name PARAMS ((char *name, const char **language, - const char **modifier, - const char **territory, - const char **codeset, - const char **normalized_codeset, - const char **special, - const char **sponsor, - const char **revision)); - -/* Split a locale name NAME into a leading language part and all the - rest. Return a pointer to the first character after the language, - i.e. to the first byte of the rest. */ -extern char *_nl_find_language PARAMS ((const char *name)); - -#endif /* loadinfo.h */ diff --git a/intl/loadmsgcat.c b/intl/loadmsgcat.c deleted file mode 100644 index 516f5211b..000000000 --- a/intl/loadmsgcat.c +++ /dev/null @@ -1,1316 +0,0 @@ -/* Load needed message catalogs. - Copyright (C) 1995-1999, 2000-2002 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ - -/* Tell glibc's to provide a prototype for mempcpy(). - This must come before because may include - , and once has been included, it's too late. */ -#ifndef _GNU_SOURCE -# define _GNU_SOURCE 1 -#endif - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include -#include - -#ifdef __GNUC__ -# define alloca __builtin_alloca -# define HAVE_ALLOCA 1 -#else -# if defined HAVE_ALLOCA_H || defined _LIBC -# include -# else -# ifdef _AIX - #pragma alloca -# else -# ifndef alloca -char *alloca (); -# endif -# endif -# endif -#endif - -#include -#include - -#if defined HAVE_UNISTD_H || defined _LIBC -# include -#endif - -#ifdef _LIBC -# include -# include -#endif - -#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \ - || (defined _LIBC && defined _POSIX_MAPPED_FILES) -# include -# undef HAVE_MMAP -# define HAVE_MMAP 1 -#else -# undef HAVE_MMAP -#endif - -#if defined HAVE_STDINT_H_WITH_UINTMAX || defined _LIBC -# include -#endif -#if defined HAVE_INTTYPES_H || defined _LIBC -# include -#endif - -#include "gmo.h" -#include "gettextP.h" -#include "hash-string.h" -#include "plural-exp.h" - -#ifdef _LIBC -# include "../locale/localeinfo.h" -#endif - -/* Provide fallback values for macros that ought to be defined in . - Note that our fallback values need not be literal strings, because we don't - use them with preprocessor string concatenation. */ -#if !defined PRId8 || PRI_MACROS_BROKEN -# undef PRId8 -# define PRId8 "d" -#endif -#if !defined PRIi8 || PRI_MACROS_BROKEN -# undef PRIi8 -# define PRIi8 "i" -#endif -#if !defined PRIo8 || PRI_MACROS_BROKEN -# undef PRIo8 -# define PRIo8 "o" -#endif -#if !defined PRIu8 || PRI_MACROS_BROKEN -# undef PRIu8 -# define PRIu8 "u" -#endif -#if !defined PRIx8 || PRI_MACROS_BROKEN -# undef PRIx8 -# define PRIx8 "x" -#endif -#if !defined PRIX8 || PRI_MACROS_BROKEN -# undef PRIX8 -# define PRIX8 "X" -#endif -#if !defined PRId16 || PRI_MACROS_BROKEN -# undef PRId16 -# define PRId16 "d" -#endif -#if !defined PRIi16 || PRI_MACROS_BROKEN -# undef PRIi16 -# define PRIi16 "i" -#endif -#if !defined PRIo16 || PRI_MACROS_BROKEN -# undef PRIo16 -# define PRIo16 "o" -#endif -#if !defined PRIu16 || PRI_MACROS_BROKEN -# undef PRIu16 -# define PRIu16 "u" -#endif -#if !defined PRIx16 || PRI_MACROS_BROKEN -# undef PRIx16 -# define PRIx16 "x" -#endif -#if !defined PRIX16 || PRI_MACROS_BROKEN -# undef PRIX16 -# define PRIX16 "X" -#endif -#if !defined PRId32 || PRI_MACROS_BROKEN -# undef PRId32 -# define PRId32 "d" -#endif -#if !defined PRIi32 || PRI_MACROS_BROKEN -# undef PRIi32 -# define PRIi32 "i" -#endif -#if !defined PRIo32 || PRI_MACROS_BROKEN -# undef PRIo32 -# define PRIo32 "o" -#endif -#if !defined PRIu32 || PRI_MACROS_BROKEN -# undef PRIu32 -# define PRIu32 "u" -#endif -#if !defined PRIx32 || PRI_MACROS_BROKEN -# undef PRIx32 -# define PRIx32 "x" -#endif -#if !defined PRIX32 || PRI_MACROS_BROKEN -# undef PRIX32 -# define PRIX32 "X" -#endif -#if !defined PRId64 || PRI_MACROS_BROKEN -# undef PRId64 -# define PRId64 (sizeof (long) == 8 ? "ld" : "lld") -#endif -#if !defined PRIi64 || PRI_MACROS_BROKEN -# undef PRIi64 -# define PRIi64 (sizeof (long) == 8 ? "li" : "lli") -#endif -#if !defined PRIo64 || PRI_MACROS_BROKEN -# undef PRIo64 -# define PRIo64 (sizeof (long) == 8 ? "lo" : "llo") -#endif -#if !defined PRIu64 || PRI_MACROS_BROKEN -# undef PRIu64 -# define PRIu64 (sizeof (long) == 8 ? "lu" : "llu") -#endif -#if !defined PRIx64 || PRI_MACROS_BROKEN -# undef PRIx64 -# define PRIx64 (sizeof (long) == 8 ? "lx" : "llx") -#endif -#if !defined PRIX64 || PRI_MACROS_BROKEN -# undef PRIX64 -# define PRIX64 (sizeof (long) == 8 ? "lX" : "llX") -#endif -#if !defined PRIdLEAST8 || PRI_MACROS_BROKEN -# undef PRIdLEAST8 -# define PRIdLEAST8 "d" -#endif -#if !defined PRIiLEAST8 || PRI_MACROS_BROKEN -# undef PRIiLEAST8 -# define PRIiLEAST8 "i" -#endif -#if !defined PRIoLEAST8 || PRI_MACROS_BROKEN -# undef PRIoLEAST8 -# define PRIoLEAST8 "o" -#endif -#if !defined PRIuLEAST8 || PRI_MACROS_BROKEN -# undef PRIuLEAST8 -# define PRIuLEAST8 "u" -#endif -#if !defined PRIxLEAST8 || PRI_MACROS_BROKEN -# undef PRIxLEAST8 -# define PRIxLEAST8 "x" -#endif -#if !defined PRIXLEAST8 || PRI_MACROS_BROKEN -# undef PRIXLEAST8 -# define PRIXLEAST8 "X" -#endif -#if !defined PRIdLEAST16 || PRI_MACROS_BROKEN -# undef PRIdLEAST16 -# define PRIdLEAST16 "d" -#endif -#if !defined PRIiLEAST16 || PRI_MACROS_BROKEN -# undef PRIiLEAST16 -# define PRIiLEAST16 "i" -#endif -#if !defined PRIoLEAST16 || PRI_MACROS_BROKEN -# undef PRIoLEAST16 -# define PRIoLEAST16 "o" -#endif -#if !defined PRIuLEAST16 || PRI_MACROS_BROKEN -# undef PRIuLEAST16 -# define PRIuLEAST16 "u" -#endif -#if !defined PRIxLEAST16 || PRI_MACROS_BROKEN -# undef PRIxLEAST16 -# define PRIxLEAST16 "x" -#endif -#if !defined PRIXLEAST16 || PRI_MACROS_BROKEN -# undef PRIXLEAST16 -# define PRIXLEAST16 "X" -#endif -#if !defined PRIdLEAST32 || PRI_MACROS_BROKEN -# undef PRIdLEAST32 -# define PRIdLEAST32 "d" -#endif -#if !defined PRIiLEAST32 || PRI_MACROS_BROKEN -# undef PRIiLEAST32 -# define PRIiLEAST32 "i" -#endif -#if !defined PRIoLEAST32 || PRI_MACROS_BROKEN -# undef PRIoLEAST32 -# define PRIoLEAST32 "o" -#endif -#if !defined PRIuLEAST32 || PRI_MACROS_BROKEN -# undef PRIuLEAST32 -# define PRIuLEAST32 "u" -#endif -#if !defined PRIxLEAST32 || PRI_MACROS_BROKEN -# undef PRIxLEAST32 -# define PRIxLEAST32 "x" -#endif -#if !defined PRIXLEAST32 || PRI_MACROS_BROKEN -# undef PRIXLEAST32 -# define PRIXLEAST32 "X" -#endif -#if !defined PRIdLEAST64 || PRI_MACROS_BROKEN -# undef PRIdLEAST64 -# define PRIdLEAST64 PRId64 -#endif -#if !defined PRIiLEAST64 || PRI_MACROS_BROKEN -# undef PRIiLEAST64 -# define PRIiLEAST64 PRIi64 -#endif -#if !defined PRIoLEAST64 || PRI_MACROS_BROKEN -# undef PRIoLEAST64 -# define PRIoLEAST64 PRIo64 -#endif -#if !defined PRIuLEAST64 || PRI_MACROS_BROKEN -# undef PRIuLEAST64 -# define PRIuLEAST64 PRIu64 -#endif -#if !defined PRIxLEAST64 || PRI_MACROS_BROKEN -# undef PRIxLEAST64 -# define PRIxLEAST64 PRIx64 -#endif -#if !defined PRIXLEAST64 || PRI_MACROS_BROKEN -# undef PRIXLEAST64 -# define PRIXLEAST64 PRIX64 -#endif -#if !defined PRIdFAST8 || PRI_MACROS_BROKEN -# undef PRIdFAST8 -# define PRIdFAST8 "d" -#endif -#if !defined PRIiFAST8 || PRI_MACROS_BROKEN -# undef PRIiFAST8 -# define PRIiFAST8 "i" -#endif -#if !defined PRIoFAST8 || PRI_MACROS_BROKEN -# undef PRIoFAST8 -# define PRIoFAST8 "o" -#endif -#if !defined PRIuFAST8 || PRI_MACROS_BROKEN -# undef PRIuFAST8 -# define PRIuFAST8 "u" -#endif -#if !defined PRIxFAST8 || PRI_MACROS_BROKEN -# undef PRIxFAST8 -# define PRIxFAST8 "x" -#endif -#if !defined PRIXFAST8 || PRI_MACROS_BROKEN -# undef PRIXFAST8 -# define PRIXFAST8 "X" -#endif -#if !defined PRIdFAST16 || PRI_MACROS_BROKEN -# undef PRIdFAST16 -# define PRIdFAST16 "d" -#endif -#if !defined PRIiFAST16 || PRI_MACROS_BROKEN -# undef PRIiFAST16 -# define PRIiFAST16 "i" -#endif -#if !defined PRIoFAST16 || PRI_MACROS_BROKEN -# undef PRIoFAST16 -# define PRIoFAST16 "o" -#endif -#if !defined PRIuFAST16 || PRI_MACROS_BROKEN -# undef PRIuFAST16 -# define PRIuFAST16 "u" -#endif -#if !defined PRIxFAST16 || PRI_MACROS_BROKEN -# undef PRIxFAST16 -# define PRIxFAST16 "x" -#endif -#if !defined PRIXFAST16 || PRI_MACROS_BROKEN -# undef PRIXFAST16 -# define PRIXFAST16 "X" -#endif -#if !defined PRIdFAST32 || PRI_MACROS_BROKEN -# undef PRIdFAST32 -# define PRIdFAST32 "d" -#endif -#if !defined PRIiFAST32 || PRI_MACROS_BROKEN -# undef PRIiFAST32 -# define PRIiFAST32 "i" -#endif -#if !defined PRIoFAST32 || PRI_MACROS_BROKEN -# undef PRIoFAST32 -# define PRIoFAST32 "o" -#endif -#if !defined PRIuFAST32 || PRI_MACROS_BROKEN -# undef PRIuFAST32 -# define PRIuFAST32 "u" -#endif -#if !defined PRIxFAST32 || PRI_MACROS_BROKEN -# undef PRIxFAST32 -# define PRIxFAST32 "x" -#endif -#if !defined PRIXFAST32 || PRI_MACROS_BROKEN -# undef PRIXFAST32 -# define PRIXFAST32 "X" -#endif -#if !defined PRIdFAST64 || PRI_MACROS_BROKEN -# undef PRIdFAST64 -# define PRIdFAST64 PRId64 -#endif -#if !defined PRIiFAST64 || PRI_MACROS_BROKEN -# undef PRIiFAST64 -# define PRIiFAST64 PRIi64 -#endif -#if !defined PRIoFAST64 || PRI_MACROS_BROKEN -# undef PRIoFAST64 -# define PRIoFAST64 PRIo64 -#endif -#if !defined PRIuFAST64 || PRI_MACROS_BROKEN -# undef PRIuFAST64 -# define PRIuFAST64 PRIu64 -#endif -#if !defined PRIxFAST64 || PRI_MACROS_BROKEN -# undef PRIxFAST64 -# define PRIxFAST64 PRIx64 -#endif -#if !defined PRIXFAST64 || PRI_MACROS_BROKEN -# undef PRIXFAST64 -# define PRIXFAST64 PRIX64 -#endif -#if !defined PRIdMAX || PRI_MACROS_BROKEN -# undef PRIdMAX -# define PRIdMAX (sizeof (uintmax_t) == sizeof (long) ? "ld" : "lld") -#endif -#if !defined PRIiMAX || PRI_MACROS_BROKEN -# undef PRIiMAX -# define PRIiMAX (sizeof (uintmax_t) == sizeof (long) ? "li" : "lli") -#endif -#if !defined PRIoMAX || PRI_MACROS_BROKEN -# undef PRIoMAX -# define PRIoMAX (sizeof (uintmax_t) == sizeof (long) ? "lo" : "llo") -#endif -#if !defined PRIuMAX || PRI_MACROS_BROKEN -# undef PRIuMAX -# define PRIuMAX (sizeof (uintmax_t) == sizeof (long) ? "lu" : "llu") -#endif -#if !defined PRIxMAX || PRI_MACROS_BROKEN -# undef PRIxMAX -# define PRIxMAX (sizeof (uintmax_t) == sizeof (long) ? "lx" : "llx") -#endif -#if !defined PRIXMAX || PRI_MACROS_BROKEN -# undef PRIXMAX -# define PRIXMAX (sizeof (uintmax_t) == sizeof (long) ? "lX" : "llX") -#endif -#if !defined PRIdPTR || PRI_MACROS_BROKEN -# undef PRIdPTR -# define PRIdPTR \ - (sizeof (void *) == sizeof (long) ? "ld" : \ - sizeof (void *) == sizeof (int) ? "d" : \ - "lld") -#endif -#if !defined PRIiPTR || PRI_MACROS_BROKEN -# undef PRIiPTR -# define PRIiPTR \ - (sizeof (void *) == sizeof (long) ? "li" : \ - sizeof (void *) == sizeof (int) ? "i" : \ - "lli") -#endif -#if !defined PRIoPTR || PRI_MACROS_BROKEN -# undef PRIoPTR -# define PRIoPTR \ - (sizeof (void *) == sizeof (long) ? "lo" : \ - sizeof (void *) == sizeof (int) ? "o" : \ - "llo") -#endif -#if !defined PRIuPTR || PRI_MACROS_BROKEN -# undef PRIuPTR -# define PRIuPTR \ - (sizeof (void *) == sizeof (long) ? "lu" : \ - sizeof (void *) == sizeof (int) ? "u" : \ - "llu") -#endif -#if !defined PRIxPTR || PRI_MACROS_BROKEN -# undef PRIxPTR -# define PRIxPTR \ - (sizeof (void *) == sizeof (long) ? "lx" : \ - sizeof (void *) == sizeof (int) ? "x" : \ - "llx") -#endif -#if !defined PRIXPTR || PRI_MACROS_BROKEN -# undef PRIXPTR -# define PRIXPTR \ - (sizeof (void *) == sizeof (long) ? "lX" : \ - sizeof (void *) == sizeof (int) ? "X" : \ - "llX") -#endif - -/* @@ end of prolog @@ */ - -#ifdef _LIBC -/* Rename the non ISO C functions. This is required by the standard - because some ISO C functions will require linking with this object - file and the name space must not be polluted. */ -# define open __open -# define close __close -# define read __read -# define mmap __mmap -# define munmap __munmap -#endif - -/* For those losing systems which don't have `alloca' we have to add - some additional code emulating it. */ -#ifdef HAVE_ALLOCA -# define freea(p) /* nothing */ -#else -# define alloca(n) malloc (n) -# define freea(p) free (p) -#endif - -/* For systems that distinguish between text and binary I/O. - O_BINARY is usually declared in . */ -#if !defined O_BINARY && defined _O_BINARY - /* For MSC-compatible compilers. */ -# define O_BINARY _O_BINARY -# define O_TEXT _O_TEXT -#endif -#ifdef __BEOS__ - /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect. */ -# undef O_BINARY -# undef O_TEXT -#endif -/* On reasonable systems, binary I/O is the default. */ -#ifndef O_BINARY -# define O_BINARY 0 -#endif - - -/* Prototypes for local functions. Needed to ensure compiler checking of - function argument counts despite of K&R C function definition syntax. */ -static const char *get_sysdep_segment_value PARAMS ((const char *name)); - - -/* We need a sign, whether a new catalog was loaded, which can be associated - with all translations. This is important if the translations are - cached by one of GCC's features. */ -int _nl_msg_cat_cntr; - - -/* Expand a system dependent string segment. Return NULL if unsupported. */ -static const char * -get_sysdep_segment_value (name) - const char *name; -{ - /* Test for an ISO C 99 section 7.8.1 format string directive. - Syntax: - P R I { d | i | o | u | x | X } - { { | LEAST | FAST } { 8 | 16 | 32 | 64 } | MAX | PTR } */ - /* We don't use a table of 14 times 6 'const char *' strings here, because - data relocations cost startup time. */ - if (name[0] == 'P' && name[1] == 'R' && name[2] == 'I') - { - if (name[3] == 'd' || name[3] == 'i' || name[3] == 'o' || name[3] == 'u' - || name[3] == 'x' || name[3] == 'X') - { - if (name[4] == '8' && name[5] == '\0') - { - if (name[3] == 'd') - return PRId8; - if (name[3] == 'i') - return PRIi8; - if (name[3] == 'o') - return PRIo8; - if (name[3] == 'u') - return PRIu8; - if (name[3] == 'x') - return PRIx8; - if (name[3] == 'X') - return PRIX8; - abort (); - } - if (name[4] == '1' && name[5] == '6' && name[6] == '\0') - { - if (name[3] == 'd') - return PRId16; - if (name[3] == 'i') - return PRIi16; - if (name[3] == 'o') - return PRIo16; - if (name[3] == 'u') - return PRIu16; - if (name[3] == 'x') - return PRIx16; - if (name[3] == 'X') - return PRIX16; - abort (); - } - if (name[4] == '3' && name[5] == '2' && name[6] == '\0') - { - if (name[3] == 'd') - return PRId32; - if (name[3] == 'i') - return PRIi32; - if (name[3] == 'o') - return PRIo32; - if (name[3] == 'u') - return PRIu32; - if (name[3] == 'x') - return PRIx32; - if (name[3] == 'X') - return PRIX32; - abort (); - } - if (name[4] == '6' && name[5] == '4' && name[6] == '\0') - { - if (name[3] == 'd') - return PRId64; - if (name[3] == 'i') - return PRIi64; - if (name[3] == 'o') - return PRIo64; - if (name[3] == 'u') - return PRIu64; - if (name[3] == 'x') - return PRIx64; - if (name[3] == 'X') - return PRIX64; - abort (); - } - if (name[4] == 'L' && name[5] == 'E' && name[6] == 'A' - && name[7] == 'S' && name[8] == 'T') - { - if (name[9] == '8' && name[10] == '\0') - { - if (name[3] == 'd') - return PRIdLEAST8; - if (name[3] == 'i') - return PRIiLEAST8; - if (name[3] == 'o') - return PRIoLEAST8; - if (name[3] == 'u') - return PRIuLEAST8; - if (name[3] == 'x') - return PRIxLEAST8; - if (name[3] == 'X') - return PRIXLEAST8; - abort (); - } - if (name[9] == '1' && name[10] == '6' && name[11] == '\0') - { - if (name[3] == 'd') - return PRIdLEAST16; - if (name[3] == 'i') - return PRIiLEAST16; - if (name[3] == 'o') - return PRIoLEAST16; - if (name[3] == 'u') - return PRIuLEAST16; - if (name[3] == 'x') - return PRIxLEAST16; - if (name[3] == 'X') - return PRIXLEAST16; - abort (); - } - if (name[9] == '3' && name[10] == '2' && name[11] == '\0') - { - if (name[3] == 'd') - return PRIdLEAST32; - if (name[3] == 'i') - return PRIiLEAST32; - if (name[3] == 'o') - return PRIoLEAST32; - if (name[3] == 'u') - return PRIuLEAST32; - if (name[3] == 'x') - return PRIxLEAST32; - if (name[3] == 'X') - return PRIXLEAST32; - abort (); - } - if (name[9] == '6' && name[10] == '4' && name[11] == '\0') - { - if (name[3] == 'd') - return PRIdLEAST64; - if (name[3] == 'i') - return PRIiLEAST64; - if (name[3] == 'o') - return PRIoLEAST64; - if (name[3] == 'u') - return PRIuLEAST64; - if (name[3] == 'x') - return PRIxLEAST64; - if (name[3] == 'X') - return PRIXLEAST64; - abort (); - } - } - if (name[4] == 'F' && name[5] == 'A' && name[6] == 'S' - && name[7] == 'T') - { - if (name[8] == '8' && name[9] == '\0') - { - if (name[3] == 'd') - return PRIdFAST8; - if (name[3] == 'i') - return PRIiFAST8; - if (name[3] == 'o') - return PRIoFAST8; - if (name[3] == 'u') - return PRIuFAST8; - if (name[3] == 'x') - return PRIxFAST8; - if (name[3] == 'X') - return PRIXFAST8; - abort (); - } - if (name[8] == '1' && name[9] == '6' && name[10] == '\0') - { - if (name[3] == 'd') - return PRIdFAST16; - if (name[3] == 'i') - return PRIiFAST16; - if (name[3] == 'o') - return PRIoFAST16; - if (name[3] == 'u') - return PRIuFAST16; - if (name[3] == 'x') - return PRIxFAST16; - if (name[3] == 'X') - return PRIXFAST16; - abort (); - } - if (name[8] == '3' && name[9] == '2' && name[10] == '\0') - { - if (name[3] == 'd') - return PRIdFAST32; - if (name[3] == 'i') - return PRIiFAST32; - if (name[3] == 'o') - return PRIoFAST32; - if (name[3] == 'u') - return PRIuFAST32; - if (name[3] == 'x') - return PRIxFAST32; - if (name[3] == 'X') - return PRIXFAST32; - abort (); - } - if (name[8] == '6' && name[9] == '4' && name[10] == '\0') - { - if (name[3] == 'd') - return PRIdFAST64; - if (name[3] == 'i') - return PRIiFAST64; - if (name[3] == 'o') - return PRIoFAST64; - if (name[3] == 'u') - return PRIuFAST64; - if (name[3] == 'x') - return PRIxFAST64; - if (name[3] == 'X') - return PRIXFAST64; - abort (); - } - } - if (name[4] == 'M' && name[5] == 'A' && name[6] == 'X' - && name[7] == '\0') - { - if (name[3] == 'd') - return PRIdMAX; - if (name[3] == 'i') - return PRIiMAX; - if (name[3] == 'o') - return PRIoMAX; - if (name[3] == 'u') - return PRIuMAX; - if (name[3] == 'x') - return PRIxMAX; - if (name[3] == 'X') - return PRIXMAX; - abort (); - } - if (name[4] == 'P' && name[5] == 'T' && name[6] == 'R' - && name[7] == '\0') - { - if (name[3] == 'd') - return PRIdPTR; - if (name[3] == 'i') - return PRIiPTR; - if (name[3] == 'o') - return PRIoPTR; - if (name[3] == 'u') - return PRIuPTR; - if (name[3] == 'x') - return PRIxPTR; - if (name[3] == 'X') - return PRIXPTR; - abort (); - } - } - } - /* Other system dependent strings are not valid. */ - return NULL; -} - -/* Initialize the codeset dependent parts of an opened message catalog. - Return the header entry. */ -const char * -internal_function -_nl_init_domain_conv (domain_file, domain, domainbinding) - struct loaded_l10nfile *domain_file; - struct loaded_domain *domain; - struct binding *domainbinding; -{ - /* Find out about the character set the file is encoded with. - This can be found (in textual form) in the entry "". If this - entry does not exist or if this does not contain the `charset=' - information, we will assume the charset matches the one the - current locale and we don't have to perform any conversion. */ - char *nullentry; - size_t nullentrylen; - - /* Preinitialize fields, to avoid recursion during _nl_find_msg. */ - domain->codeset_cntr = - (domainbinding != NULL ? domainbinding->codeset_cntr : 0); -#ifdef _LIBC - domain->conv = (__gconv_t) -1; -#else -# if HAVE_ICONV - domain->conv = (iconv_t) -1; -# endif -#endif - domain->conv_tab = NULL; - - /* Get the header entry. */ - nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen); - - if (nullentry != NULL) - { -#if defined _LIBC || HAVE_ICONV - const char *charsetstr; - - charsetstr = strstr (nullentry, "charset="); - if (charsetstr != NULL) - { - size_t len; - char *charset; - const char *outcharset; - - charsetstr += strlen ("charset="); - len = strcspn (charsetstr, " \t\n"); - - charset = (char *) alloca (len + 1); -# if defined _LIBC || HAVE_MEMPCPY - *((char *) mempcpy (charset, charsetstr, len)) = '\0'; -# else - memcpy (charset, charsetstr, len); - charset[len] = '\0'; -# endif - - /* The output charset should normally be determined by the - locale. But sometimes the locale is not used or not correctly - set up, so we provide a possibility for the user to override - this. Moreover, the value specified through - bind_textdomain_codeset overrides both. */ - if (domainbinding != NULL && domainbinding->codeset != NULL) - outcharset = domainbinding->codeset; - else - { - outcharset = getenv ("OUTPUT_CHARSET"); - if (outcharset == NULL || outcharset[0] == '\0') - { -# ifdef _LIBC - outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string; -# else -# if HAVE_ICONV - extern const char *locale_charset PARAMS ((void)); - outcharset = locale_charset (); -# endif -# endif - } - } - -# ifdef _LIBC - /* We always want to use transliteration. */ - outcharset = norm_add_slashes (outcharset, "TRANSLIT"); - charset = norm_add_slashes (charset, NULL); - if (__gconv_open (outcharset, charset, &domain->conv, - GCONV_AVOID_NOCONV) - != __GCONV_OK) - domain->conv = (__gconv_t) -1; -# else -# if HAVE_ICONV - /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5, - we want to use transliteration. */ -# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \ - || _LIBICONV_VERSION >= 0x0105 - if (strchr (outcharset, '/') == NULL) - { - char *tmp; - - len = strlen (outcharset); - tmp = (char *) alloca (len + 10 + 1); - memcpy (tmp, outcharset, len); - memcpy (tmp + len, "//TRANSLIT", 10 + 1); - outcharset = tmp; - - domain->conv = iconv_open (outcharset, charset); - - freea (outcharset); - } - else -# endif - domain->conv = iconv_open (outcharset, charset); -# endif -# endif - - freea (charset); - } -#endif /* _LIBC || HAVE_ICONV */ - } - - return nullentry; -} - -/* Frees the codeset dependent parts of an opened message catalog. */ -void -internal_function -_nl_free_domain_conv (domain) - struct loaded_domain *domain; -{ - if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1) - free (domain->conv_tab); - -#ifdef _LIBC - if (domain->conv != (__gconv_t) -1) - __gconv_close (domain->conv); -#else -# if HAVE_ICONV - if (domain->conv != (iconv_t) -1) - iconv_close (domain->conv); -# endif -#endif -} - -/* Load the message catalogs specified by FILENAME. If it is no valid - message catalog do nothing. */ -void -internal_function -_nl_load_domain (domain_file, domainbinding) - struct loaded_l10nfile *domain_file; - struct binding *domainbinding; -{ - int fd; - size_t size; -#ifdef _LIBC - struct stat64 st; -#else - struct stat st; -#endif - struct mo_file_header *data = (struct mo_file_header *) -1; - int use_mmap = 0; - struct loaded_domain *domain; - int revision; - const char *nullentry; - - domain_file->decided = 1; - domain_file->data = NULL; - - /* Note that it would be useless to store domainbinding in domain_file - because domainbinding might be == NULL now but != NULL later (after - a call to bind_textdomain_codeset). */ - - /* If the record does not represent a valid locale the FILENAME - might be NULL. This can happen when according to the given - specification the locale file name is different for XPG and CEN - syntax. */ - if (domain_file->filename == NULL) - return; - - /* Try to open the addressed file. */ - fd = open (domain_file->filename, O_RDONLY | O_BINARY); - if (fd == -1) - return; - - /* We must know about the size of the file. */ - if ( -#ifdef _LIBC - __builtin_expect (fstat64 (fd, &st) != 0, 0) -#else - __builtin_expect (fstat (fd, &st) != 0, 0) -#endif - || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0) - || __builtin_expect (size < sizeof (struct mo_file_header), 0)) - { - /* Something went wrong. */ - close (fd); - return; - } - -#ifdef HAVE_MMAP - /* Now we are ready to load the file. If mmap() is available we try - this first. If not available or it failed we try to load it. */ - data = (struct mo_file_header *) mmap (NULL, size, PROT_READ, - MAP_PRIVATE, fd, 0); - - if (__builtin_expect (data != (struct mo_file_header *) -1, 1)) - { - /* mmap() call was successful. */ - close (fd); - use_mmap = 1; - } -#endif - - /* If the data is not yet available (i.e. mmap'ed) we try to load - it manually. */ - if (data == (struct mo_file_header *) -1) - { - size_t to_read; - char *read_ptr; - - data = (struct mo_file_header *) malloc (size); - if (data == NULL) - return; - - to_read = size; - read_ptr = (char *) data; - do - { - long int nb = (long int) read (fd, read_ptr, to_read); - if (nb <= 0) - { -#ifdef EINTR - if (nb == -1 && errno == EINTR) - continue; -#endif - close (fd); - return; - } - read_ptr += nb; - to_read -= nb; - } - while (to_read > 0); - - close (fd); - } - - /* Using the magic number we can test whether it really is a message - catalog file. */ - if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED, - 0)) - { - /* The magic number is wrong: not a message catalog file. */ -#ifdef HAVE_MMAP - if (use_mmap) - munmap ((caddr_t) data, size); - else -#endif - free (data); - return; - } - - domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain)); - if (domain == NULL) - return; - domain_file->data = domain; - - domain->data = (char *) data; - domain->use_mmap = use_mmap; - domain->mmap_size = size; - domain->must_swap = data->magic != _MAGIC; - domain->malloced = NULL; - - /* Fill in the information about the available tables. */ - revision = W (domain->must_swap, data->revision); - /* We support only the major revision 0. */ - switch (revision >> 16) - { - case 0: - domain->nstrings = W (domain->must_swap, data->nstrings); - domain->orig_tab = (const struct string_desc *) - ((char *) data + W (domain->must_swap, data->orig_tab_offset)); - domain->trans_tab = (const struct string_desc *) - ((char *) data + W (domain->must_swap, data->trans_tab_offset)); - domain->hash_size = W (domain->must_swap, data->hash_tab_size); - domain->hash_tab = - (domain->hash_size > 2 - ? (const nls_uint32 *) - ((char *) data + W (domain->must_swap, data->hash_tab_offset)) - : NULL); - domain->must_swap_hash_tab = domain->must_swap; - - /* Now dispatch on the minor revision. */ - switch (revision & 0xffff) - { - case 0: - domain->n_sysdep_strings = 0; - domain->orig_sysdep_tab = NULL; - domain->trans_sysdep_tab = NULL; - break; - case 1: - default: - { - nls_uint32 n_sysdep_strings; - - if (domain->hash_tab == NULL) - /* This is invalid. These minor revisions need a hash table. */ - goto invalid; - - n_sysdep_strings = - W (domain->must_swap, data->n_sysdep_strings); - if (n_sysdep_strings > 0) - { - nls_uint32 n_sysdep_segments; - const struct sysdep_segment *sysdep_segments; - const char **sysdep_segment_values; - const nls_uint32 *orig_sysdep_tab; - const nls_uint32 *trans_sysdep_tab; - size_t memneed; - char *mem; - struct sysdep_string_desc *inmem_orig_sysdep_tab; - struct sysdep_string_desc *inmem_trans_sysdep_tab; - nls_uint32 *inmem_hash_tab; - unsigned int i; - - /* Get the values of the system dependent segments. */ - n_sysdep_segments = - W (domain->must_swap, data->n_sysdep_segments); - sysdep_segments = (const struct sysdep_segment *) - ((char *) data - + W (domain->must_swap, data->sysdep_segments_offset)); - sysdep_segment_values = - alloca (n_sysdep_segments * sizeof (const char *)); - for (i = 0; i < n_sysdep_segments; i++) - { - const char *name = - (char *) data - + W (domain->must_swap, sysdep_segments[i].offset); - nls_uint32 namelen = - W (domain->must_swap, sysdep_segments[i].length); - - if (!(namelen > 0 && name[namelen - 1] == '\0')) - { - freea (sysdep_segment_values); - goto invalid; - } - - sysdep_segment_values[i] = get_sysdep_segment_value (name); - } - - orig_sysdep_tab = (const nls_uint32 *) - ((char *) data - + W (domain->must_swap, data->orig_sysdep_tab_offset)); - trans_sysdep_tab = (const nls_uint32 *) - ((char *) data - + W (domain->must_swap, data->trans_sysdep_tab_offset)); - - /* Compute the amount of additional memory needed for the - system dependent strings and the augmented hash table. */ - memneed = 2 * n_sysdep_strings - * sizeof (struct sysdep_string_desc) - + domain->hash_size * sizeof (nls_uint32); - for (i = 0; i < 2 * n_sysdep_strings; i++) - { - const struct sysdep_string *sysdep_string = - (const struct sysdep_string *) - ((char *) data - + W (domain->must_swap, - i < n_sysdep_strings - ? orig_sysdep_tab[i] - : trans_sysdep_tab[i - n_sysdep_strings])); - size_t need = 0; - const struct segment_pair *p = sysdep_string->segments; - - if (W (domain->must_swap, p->sysdepref) != SEGMENTS_END) - for (p = sysdep_string->segments;; p++) - { - nls_uint32 sysdepref; - - need += W (domain->must_swap, p->segsize); - - sysdepref = W (domain->must_swap, p->sysdepref); - if (sysdepref == SEGMENTS_END) - break; - - if (sysdepref >= n_sysdep_segments) - { - /* Invalid. */ - freea (sysdep_segment_values); - goto invalid; - } - - need += strlen (sysdep_segment_values[sysdepref]); - } - - memneed += need; - } - - /* Allocate additional memory. */ - mem = (char *) malloc (memneed); - if (mem == NULL) - goto invalid; - - domain->malloced = mem; - inmem_orig_sysdep_tab = (struct sysdep_string_desc *) mem; - mem += n_sysdep_strings * sizeof (struct sysdep_string_desc); - inmem_trans_sysdep_tab = (struct sysdep_string_desc *) mem; - mem += n_sysdep_strings * sizeof (struct sysdep_string_desc); - inmem_hash_tab = (nls_uint32 *) mem; - mem += domain->hash_size * sizeof (nls_uint32); - - /* Compute the system dependent strings. */ - for (i = 0; i < 2 * n_sysdep_strings; i++) - { - const struct sysdep_string *sysdep_string = - (const struct sysdep_string *) - ((char *) data - + W (domain->must_swap, - i < n_sysdep_strings - ? orig_sysdep_tab[i] - : trans_sysdep_tab[i - n_sysdep_strings])); - const char *static_segments = - (char *) data - + W (domain->must_swap, sysdep_string->offset); - const struct segment_pair *p = sysdep_string->segments; - - /* Concatenate the segments, and fill - inmem_orig_sysdep_tab[i] (for i < n_sysdep_strings) and - inmem_trans_sysdep_tab[i-n_sysdep_strings] (for - i >= n_sysdep_strings). */ - - if (W (domain->must_swap, p->sysdepref) == SEGMENTS_END) - { - /* Only one static segment. */ - inmem_orig_sysdep_tab[i].length = - W (domain->must_swap, p->segsize); - inmem_orig_sysdep_tab[i].pointer = static_segments; - } - else - { - inmem_orig_sysdep_tab[i].pointer = mem; - - for (p = sysdep_string->segments;; p++) - { - nls_uint32 segsize = - W (domain->must_swap, p->segsize); - nls_uint32 sysdepref = - W (domain->must_swap, p->sysdepref); - size_t n; - - if (segsize > 0) - { - memcpy (mem, static_segments, segsize); - mem += segsize; - static_segments += segsize; - } - - if (sysdepref == SEGMENTS_END) - break; - - n = strlen (sysdep_segment_values[sysdepref]); - memcpy (mem, sysdep_segment_values[sysdepref], n); - mem += n; - } - - inmem_orig_sysdep_tab[i].length = - mem - inmem_orig_sysdep_tab[i].pointer; - } - } - - /* Compute the augmented hash table. */ - for (i = 0; i < domain->hash_size; i++) - inmem_hash_tab[i] = - W (domain->must_swap_hash_tab, domain->hash_tab[i]); - for (i = 0; i < n_sysdep_strings; i++) - { - const char *msgid = inmem_orig_sysdep_tab[i].pointer; - nls_uint32 hash_val = hash_string (msgid); - nls_uint32 idx = hash_val % domain->hash_size; - nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2)); - - for (;;) - { - if (inmem_hash_tab[idx] == 0) - { - /* Hash table entry is empty. Use it. */ - inmem_hash_tab[idx] = 1 + domain->nstrings + i; - break; - } - - if (idx >= domain->hash_size - incr) - idx -= domain->hash_size - incr; - else - idx += incr; - } - } - - freea (sysdep_segment_values); - - domain->n_sysdep_strings = n_sysdep_strings; - domain->orig_sysdep_tab = inmem_orig_sysdep_tab; - domain->trans_sysdep_tab = inmem_trans_sysdep_tab; - - domain->hash_tab = inmem_hash_tab; - domain->must_swap_hash_tab = 0; - } - else - { - domain->n_sysdep_strings = 0; - domain->orig_sysdep_tab = NULL; - domain->trans_sysdep_tab = NULL; - } - } - break; - } - break; - default: - /* This is an invalid revision. */ - invalid: - /* This is an invalid .mo file. */ - if (domain->malloced) - free (domain->malloced); -#ifdef HAVE_MMAP - if (use_mmap) - munmap ((caddr_t) data, size); - else -#endif - free (data); - free (domain); - domain_file->data = NULL; - return; - } - - /* Now initialize the character set converter from the character set - the file is encoded with (found in the header entry) to the domain's - specified character set or the locale's character set. */ - nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding); - - /* Also look for a plural specification. */ - EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals); -} - - -#ifdef _LIBC -void -internal_function -_nl_unload_domain (domain) - struct loaded_domain *domain; -{ - if (domain->plural != &__gettext_germanic_plural) - __gettext_free_exp (domain->plural); - - _nl_free_domain_conv (domain); - - if (domain->malloced) - free (domain->malloced); - -# ifdef _POSIX_MAPPED_FILES - if (domain->use_mmap) - munmap ((caddr_t) domain->data, domain->mmap_size); - else -# endif /* _POSIX_MAPPED_FILES */ - free ((void *) domain->data); - - free (domain); -} -#endif diff --git a/intl/localealias.c b/intl/localealias.c deleted file mode 100644 index 456e41e37..000000000 --- a/intl/localealias.c +++ /dev/null @@ -1,419 +0,0 @@ -/* Handle aliases for locale names. - Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ - -/* Tell glibc's to provide a prototype for mempcpy(). - This must come before because may include - , and once has been included, it's too late. */ -#ifndef _GNU_SOURCE -# define _GNU_SOURCE 1 -#endif - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#if defined _LIBC || defined HAVE___FSETLOCKING -# include -#endif -#include - -#ifdef __GNUC__ -# define alloca __builtin_alloca -# define HAVE_ALLOCA 1 -#else -# if defined HAVE_ALLOCA_H || defined _LIBC -# include -# else -# ifdef _AIX - #pragma alloca -# else -# ifndef alloca -char *alloca (); -# endif -# endif -# endif -#endif - -#include -#include - -#include "gettextP.h" - -/* @@ end of prolog @@ */ - -#ifdef _LIBC -/* Rename the non ANSI C functions. This is required by the standard - because some ANSI C functions will require linking with this object - file and the name space must not be polluted. */ -# define strcasecmp __strcasecmp - -# ifndef mempcpy -# define mempcpy __mempcpy -# endif -# define HAVE_MEMPCPY 1 -# define HAVE___FSETLOCKING 1 - -/* We need locking here since we can be called from different places. */ -# include - -__libc_lock_define_initialized (static, lock); -#endif - -#ifndef internal_function -# define internal_function -#endif - -/* Some optimizations for glibc. */ -#ifdef _LIBC -# define FEOF(fp) feof_unlocked (fp) -# define FGETS(buf, n, fp) fgets_unlocked (buf, n, fp) -#else -# define FEOF(fp) feof (fp) -# define FGETS(buf, n, fp) fgets (buf, n, fp) -#endif - -/* For those losing systems which don't have `alloca' we have to add - some additional code emulating it. */ -#ifdef HAVE_ALLOCA -# define freea(p) /* nothing */ -#else -# define alloca(n) malloc (n) -# define freea(p) free (p) -#endif - -#if defined _LIBC_REENTRANT || defined HAVE_FGETS_UNLOCKED -# undef fgets -# define fgets(buf, len, s) fgets_unlocked (buf, len, s) -#endif -#if defined _LIBC_REENTRANT || defined HAVE_FEOF_UNLOCKED -# undef feof -# define feof(s) feof_unlocked (s) -#endif - - -struct alias_map -{ - const char *alias; - const char *value; -}; - - -static char *string_space; -static size_t string_space_act; -static size_t string_space_max; -static struct alias_map *map; -static size_t nmap; -static size_t maxmap; - - -/* Prototypes for local functions. */ -static size_t read_alias_file PARAMS ((const char *fname, int fname_len)) - internal_function; -static int extend_alias_table PARAMS ((void)); -static int alias_compare PARAMS ((const struct alias_map *map1, - const struct alias_map *map2)); - - -const char * -_nl_expand_alias (name) - const char *name; -{ - static const char *locale_alias_path; - struct alias_map *retval; - const char *result = NULL; - size_t added; - -#ifdef _LIBC - __libc_lock_lock (lock); -#endif - - if (locale_alias_path == NULL) - locale_alias_path = LOCALE_ALIAS_PATH; - - do - { - struct alias_map item; - - item.alias = name; - - if (nmap > 0) - retval = (struct alias_map *) bsearch (&item, map, nmap, - sizeof (struct alias_map), - (int (*) PARAMS ((const void *, - const void *)) - ) alias_compare); - else - retval = NULL; - - /* We really found an alias. Return the value. */ - if (retval != NULL) - { - result = retval->value; - break; - } - - /* Perhaps we can find another alias file. */ - added = 0; - while (added == 0 && locale_alias_path[0] != '\0') - { - const char *start; - - while (locale_alias_path[0] == PATH_SEPARATOR) - ++locale_alias_path; - start = locale_alias_path; - - while (locale_alias_path[0] != '\0' - && locale_alias_path[0] != PATH_SEPARATOR) - ++locale_alias_path; - - if (start < locale_alias_path) - added = read_alias_file (start, locale_alias_path - start); - } - } - while (added != 0); - -#ifdef _LIBC - __libc_lock_unlock (lock); -#endif - - return result; -} - - -static size_t -internal_function -read_alias_file (fname, fname_len) - const char *fname; - int fname_len; -{ - FILE *fp; - char *full_fname; - size_t added; - static const char aliasfile[] = "/locale.alias"; - - full_fname = (char *) alloca (fname_len + sizeof aliasfile); -#ifdef HAVE_MEMPCPY - mempcpy (mempcpy (full_fname, fname, fname_len), - aliasfile, sizeof aliasfile); -#else - memcpy (full_fname, fname, fname_len); - memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile); -#endif - - fp = fopen (full_fname, "r"); - freea (full_fname); - if (fp == NULL) - return 0; - -#ifdef HAVE___FSETLOCKING - /* No threads present. */ - __fsetlocking (fp, FSETLOCKING_BYCALLER); -#endif - - added = 0; - while (!FEOF (fp)) - { - /* It is a reasonable approach to use a fix buffer here because - a) we are only interested in the first two fields - b) these fields must be usable as file names and so must not - be that long - */ - char buf[BUFSIZ]; - char *alias; - char *value; - char *cp; - - if (FGETS (buf, sizeof buf, fp) == NULL) - /* EOF reached. */ - break; - - /* Possibly not the whole line fits into the buffer. Ignore - the rest of the line. */ - if (strchr (buf, '\n') == NULL) - { - char altbuf[BUFSIZ]; - do - if (FGETS (altbuf, sizeof altbuf, fp) == NULL) - /* Make sure the inner loop will be left. The outer loop - will exit at the `feof' test. */ - break; - while (strchr (altbuf, '\n') == NULL); - } - - cp = buf; - /* Ignore leading white space. */ - while (isspace ((unsigned char) cp[0])) - ++cp; - - /* A leading '#' signals a comment line. */ - if (cp[0] != '\0' && cp[0] != '#') - { - alias = cp++; - while (cp[0] != '\0' && !isspace ((unsigned char) cp[0])) - ++cp; - /* Terminate alias name. */ - if (cp[0] != '\0') - *cp++ = '\0'; - - /* Now look for the beginning of the value. */ - while (isspace ((unsigned char) cp[0])) - ++cp; - - if (cp[0] != '\0') - { - size_t alias_len; - size_t value_len; - - value = cp++; - while (cp[0] != '\0' && !isspace ((unsigned char) cp[0])) - ++cp; - /* Terminate value. */ - if (cp[0] == '\n') - { - /* This has to be done to make the following test - for the end of line possible. We are looking for - the terminating '\n' which do not overwrite here. */ - *cp++ = '\0'; - *cp = '\n'; - } - else if (cp[0] != '\0') - *cp++ = '\0'; - - if (nmap >= maxmap) - if (__builtin_expect (extend_alias_table (), 0)) - return added; - - alias_len = strlen (alias) + 1; - value_len = strlen (value) + 1; - - if (string_space_act + alias_len + value_len > string_space_max) - { - /* Increase size of memory pool. */ - size_t new_size = (string_space_max - + (alias_len + value_len > 1024 - ? alias_len + value_len : 1024)); - char *new_pool = (char *) realloc (string_space, new_size); - if (new_pool == NULL) - return added; - - if (__builtin_expect (string_space != new_pool, 0)) - { - size_t i; - - for (i = 0; i < nmap; i++) - { - map[i].alias += new_pool - string_space; - map[i].value += new_pool - string_space; - } - } - - string_space = new_pool; - string_space_max = new_size; - } - - map[nmap].alias = memcpy (&string_space[string_space_act], - alias, alias_len); - string_space_act += alias_len; - - map[nmap].value = memcpy (&string_space[string_space_act], - value, value_len); - string_space_act += value_len; - - ++nmap; - ++added; - } - } - } - - /* Should we test for ferror()? I think we have to silently ignore - errors. --drepper */ - fclose (fp); - - if (added > 0) - qsort (map, nmap, sizeof (struct alias_map), - (int (*) PARAMS ((const void *, const void *))) alias_compare); - - return added; -} - - -static int -extend_alias_table () -{ - size_t new_size; - struct alias_map *new_map; - - new_size = maxmap == 0 ? 100 : 2 * maxmap; - new_map = (struct alias_map *) realloc (map, (new_size - * sizeof (struct alias_map))); - if (new_map == NULL) - /* Simply don't extend: we don't have any more core. */ - return -1; - - map = new_map; - maxmap = new_size; - return 0; -} - - -#ifdef _LIBC -static void __attribute__ ((unused)) -free_mem (void) -{ - if (string_space != NULL) - free (string_space); - if (map != NULL) - free (map); -} -text_set_element (__libc_subfreeres, free_mem); -#endif - - -static int -alias_compare (map1, map2) - const struct alias_map *map1; - const struct alias_map *map2; -{ -#if defined _LIBC || defined HAVE_STRCASECMP - return strcasecmp (map1->alias, map2->alias); -#else - const unsigned char *p1 = (const unsigned char *) map1->alias; - const unsigned char *p2 = (const unsigned char *) map2->alias; - unsigned char c1, c2; - - if (p1 == p2) - return 0; - - do - { - /* I know this seems to be odd but the tolower() function in - some systems libc cannot handle nonalpha characters. */ - c1 = isupper (*p1) ? tolower (*p1) : *p1; - c2 = isupper (*p2) ? tolower (*p2) : *p2; - if (c1 == '\0') - break; - ++p1; - ++p2; - } - while (c1 == c2); - - return c1 - c2; -#endif -} diff --git a/intl/po2tbl.sed.in b/intl/po2tbl.sed.in deleted file mode 100644 index b3bcca4d7..000000000 --- a/intl/po2tbl.sed.in +++ /dev/null @@ -1,102 +0,0 @@ -# po2tbl.sed - Convert Uniforum style .po file to lookup table for catgets -# Copyright (C) 1995 Free Software Foundation, Inc. -# Ulrich Drepper , 1995. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -1 { - i\ -/* Automatically generated by po2tbl.sed from @PACKAGE NAME@.pot. */\ -\ -#if HAVE_CONFIG_H\ -# include \ -#endif\ -\ -#include "libgettext.h"\ -\ -const struct _msg_ent _msg_tbl[] = { - h - s/.*/0/ - x -} -# -# Write msgid entries in C array form. -# -/^msgid/ { - s/msgid[ ]*\(".*"\)/ {\1/ - tb -# Append the next line - :b - N -# Look whether second part is continuation line. - s/\(.*\)"\(\n\)"\(.*"\)/\1\2\3/ -# Yes, then branch. - ta -# Because we assume that the input file correctly formed the line -# just read cannot be again be a msgid line. So it's safe to ignore -# it. - s/\(.*\)\n.*/\1/ - bc -# We found a continuation line. But before printing insert '\'. - :a - s/\(.*\)\(\n.*\)/\1\\\2/ - P -# We cannot use D here. - s/.*\n\(.*\)/\1/ -# Some buggy seds do not clear the `successful substitution since last ``t''' -# flag on `N', so we do a `t' here to clear it. - tb -# Not reached - :c - x -# The following nice solution is by -# Bruno - td -# Increment a decimal number in pattern space. -# First hide trailing `9' digits. - :d - s/9\(_*\)$/_\1/ - td -# Assure at least one digit is available. - s/^\(_*\)$/0\1/ -# Increment the last digit. - s/8\(_*\)$/9\1/ - s/7\(_*\)$/8\1/ - s/6\(_*\)$/7\1/ - s/5\(_*\)$/6\1/ - s/4\(_*\)$/5\1/ - s/3\(_*\)$/4\1/ - s/2\(_*\)$/3\1/ - s/1\(_*\)$/2\1/ - s/0\(_*\)$/1\1/ -# Convert the hidden `9' digits to `0's. - s/_/0/g - x - G - s/\(.*\)\n\([0-9]*\)/\1, \2},/ - s/\(.*\)"$/\1/ - p -} -# -# Last line. -# -$ { - i\ -};\ - - g - s/0*\(.*\)/int _msg_tbl_length = \1;/p -} -d diff --git a/intl/textdomain.c b/intl/textdomain.c deleted file mode 100644 index f259c696d..000000000 --- a/intl/textdomain.c +++ /dev/null @@ -1,142 +0,0 @@ -/* Implementation of the textdomain(3) function. - Copyright (C) 1995-1998, 2000, 2001, 2002 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include - -#ifdef _LIBC -# include -#else -# include "libgnuintl.h" -#endif -#include "gettextP.h" - -#ifdef _LIBC -/* We have to handle multi-threaded applications. */ -# include -#else -/* Provide dummy implementation if this is outside glibc. */ -# define __libc_rwlock_define(CLASS, NAME) -# define __libc_rwlock_wrlock(NAME) -# define __libc_rwlock_unlock(NAME) -#endif - -/* The internal variables in the standalone libintl.a must have different - names than the internal variables in GNU libc, otherwise programs - using libintl.a cannot be linked statically. */ -#if !defined _LIBC -# define _nl_default_default_domain libintl_nl_default_default_domain -# define _nl_current_default_domain libintl_nl_current_default_domain -#endif - -/* @@ end of prolog @@ */ - -/* Name of the default text domain. */ -extern const char _nl_default_default_domain[] attribute_hidden; - -/* Default text domain in which entries for gettext(3) are to be found. */ -extern const char *_nl_current_default_domain attribute_hidden; - - -/* Names for the libintl functions are a problem. They must not clash - with existing names and they should follow ANSI C. But this source - code is also used in GNU C Library where the names have a __ - prefix. So we have to make a difference here. */ -#ifdef _LIBC -# define TEXTDOMAIN __textdomain -# ifndef strdup -# define strdup(str) __strdup (str) -# endif -#else -# define TEXTDOMAIN libintl_textdomain -#endif - -/* Lock variable to protect the global data in the gettext implementation. */ -__libc_rwlock_define (extern, _nl_state_lock attribute_hidden) - -/* Set the current default message catalog to DOMAINNAME. - If DOMAINNAME is null, return the current default. - If DOMAINNAME is "", reset to the default of "messages". */ -char * -TEXTDOMAIN (domainname) - const char *domainname; -{ - char *new_domain; - char *old_domain; - - /* A NULL pointer requests the current setting. */ - if (domainname == NULL) - return (char *) _nl_current_default_domain; - - __libc_rwlock_wrlock (_nl_state_lock); - - old_domain = (char *) _nl_current_default_domain; - - /* If domain name is the null string set to default domain "messages". */ - if (domainname[0] == '\0' - || strcmp (domainname, _nl_default_default_domain) == 0) - { - _nl_current_default_domain = _nl_default_default_domain; - new_domain = (char *) _nl_current_default_domain; - } - else if (strcmp (domainname, old_domain) == 0) - /* This can happen and people will use it to signal that some - environment variable changed. */ - new_domain = old_domain; - else - { - /* If the following malloc fails `_nl_current_default_domain' - will be NULL. This value will be returned and so signals we - are out of core. */ -#if defined _LIBC || defined HAVE_STRDUP - new_domain = strdup (domainname); -#else - size_t len = strlen (domainname) + 1; - new_domain = (char *) malloc (len); - if (new_domain != NULL) - memcpy (new_domain, domainname, len); -#endif - - if (new_domain != NULL) - _nl_current_default_domain = new_domain; - } - - /* We use this possibility to signal a change of the loaded catalogs - since this is most likely the case and there is no other easy we - to do it. Do it only when the call was successful. */ - if (new_domain != NULL) - { - ++_nl_msg_cat_cntr; - - if (old_domain != new_domain && old_domain != _nl_default_default_domain) - free (old_domain); - } - - __libc_rwlock_unlock (_nl_state_lock); - - return new_domain; -} - -#ifdef _LIBC -/* Alias for function name in GNU C Library. */ -weak_alias (__textdomain, textdomain); -#endif diff --git a/intl/xopen-msg.sed b/intl/xopen-msg.sed deleted file mode 100644 index b19c0bbd0..000000000 --- a/intl/xopen-msg.sed +++ /dev/null @@ -1,104 +0,0 @@ -# po2msg.sed - Convert Uniforum style .po file to X/Open style .msg file -# Copyright (C) 1995 Free Software Foundation, Inc. -# Ulrich Drepper , 1995. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# -# The first directive in the .msg should be the definition of the -# message set number. We use always set number 1. -# -1 { - i\ -$set 1 # Automatically created by po2msg.sed - h - s/.*/0/ - x -} -# -# We copy all comments into the .msg file. Perhaps they can help. -# -/^#/ s/^#[ ]*/$ /p -# -# We copy the original message as a comment into the .msg file. -# -/^msgid/ { -# Does not work now -# /"$/! { -# s/\\$// -# s/$/ ... (more lines following)"/ -# } - s/^msgid[ ]*"\(.*\)"$/$ Original Message: \1/ - p -} -# -# The .msg file contains, other then the .po file, only the translations -# but each given a unique ID. Starting from 1 and incrementing by 1 for -# each message we assign them to the messages. -# It is important that the .po file used to generate the cat-id-tbl.c file -# (with po-to-tbl) is the same as the one used here. (At least the order -# of declarations must not be changed.) -# -/^msgstr/ { - s/msgstr[ ]*"\(.*\)"/\1/ - x -# The following nice solution is by -# Bruno - td -# Increment a decimal number in pattern space. -# First hide trailing `9' digits. - :d - s/9\(_*\)$/_\1/ - td -# Assure at least one digit is available. - s/^\(_*\)$/0\1/ -# Increment the last digit. - s/8\(_*\)$/9\1/ - s/7\(_*\)$/8\1/ - s/6\(_*\)$/7\1/ - s/5\(_*\)$/6\1/ - s/4\(_*\)$/5\1/ - s/3\(_*\)$/4\1/ - s/2\(_*\)$/3\1/ - s/1\(_*\)$/2\1/ - s/0\(_*\)$/1\1/ -# Convert the hidden `9' digits to `0's. - s/_/0/g - x -# Bring the line in the format ` ' - G - s/^[^\n]*$/& / - s/\(.*\)\n\([0-9]*\)/\2 \1/ -# Clear flag from last substitution. - tb -# Append the next line. - :b - N -# Look whether second part is a continuation line. - s/\(.*\n\)"\(.*\)"/\1\2/ -# Yes, then branch. - ta - P - D -# Note that `D' includes a jump to the start!! -# We found a continuation line. But before printing insert '\'. - :a - s/\(.*\)\(\n.*\)/\1\\\2/ - P -# We cannot use the sed command `D' here - s/.*\n\(.*\)/\1/ - tb -} -d diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 717dd83e0..e257e1dbb 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -246,7 +246,6 @@ static void linphone_call_lost (LinphoneCall *call) { temp = ms_strdup_printf("Media connectivity with %s is lost, call is going to be closed.", from ? from : "?"); if (from) ms_free(from); ms_message("LinphoneCall [%p]: %s", call, temp); - linphone_core_notify_display_warning(lc, temp); call->non_op_error = TRUE; linphone_error_info_set(call->ei,nullptr, LinphoneReasonIOError, 503, "Media lost", nullptr); linphone_call_terminate(call); diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 2dbd1e306..f9a6d143a 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -20,11 +20,11 @@ #include "conference/participant.h" #include "local-conference-event-handler.h" #include "object/object-p.h" -#include "xml/conference-info.h" -/* Needs to be included after xml/conference-info.h because of _() macro definition that breaks everything */ #include "private.h" +#include "xml/conference-info.h" + // ============================================================================= using namespace std; diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 03668dba0..38b39e7bd 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -18,11 +18,11 @@ #include "remote-conference-event-handler.h" #include "object/object-p.h" -#include "xml/conference-info.h" -/* Needs to be included after xml/conference-info.h because of _() macro definition that breaks everything */ #include "private.h" +#include "xml/conference-info.h" + // ============================================================================= using namespace std; diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 481db6bd2..4e0bf9085 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -157,19 +157,6 @@ void CallSessionPrivate::setState(LinphoneCallState newState, const string &mess linphone_core_multicast_lock_release(core); #endif break; - case LinphoneCallStreamsRunning: - if ((prevState == LinphoneCallUpdating) || (prevState == LinphoneCallUpdatedByRemote)) { - LinphoneReason reason = linphone_error_info_get_reason(ei); - char *msg; - if (reason != LinphoneReasonNone) { - msg = ms_strdup_printf(_("Call parameters could not be modified: %s."), linphone_reason_to_string(reason)); - } else { - msg = ms_strdup(_("Call parameters were successfully modified.")); - } - linphone_core_notify_display_status(core, msg); - ms_free(msg); - } - break; default: break; } @@ -223,13 +210,10 @@ bool CallSessionPrivate::startPing () { void CallSessionPrivate::abort (const string &errorMsg) { sal_call_terminate(op); - linphone_core_notify_display_status(core, "Call aborted"); setState(LinphoneCallError, errorMsg); } void CallSessionPrivate::accepted () { - L_Q(CallSession); - char *msg = nullptr; /* Immediately notify the connected state, even if errors occur after */ switch (state) { case LinphoneCallOutgoingProgress: @@ -237,9 +221,6 @@ void CallSessionPrivate::accepted () { case LinphoneCallOutgoingEarlyMedia: /* Immediately notify the connected state */ setState(LinphoneCallConnected, "Connected"); - msg = ms_strdup_printf(_("Call answered by %s"), q->getRemoteAddressAsString().c_str()); - linphone_core_notify_display_status(core, msg); - ms_free(msg); break; default: break; @@ -261,26 +242,8 @@ void CallSessionPrivate::ackReceived (LinphoneHeaders *headers) { bool CallSessionPrivate::failure () { L_Q(CallSession); - linphone_core_notify_show_interface(core); - const char *msg = ei->full_string; - const char *msg486 = "User is busy."; - const char *msg480 = "User is temporarily unavailable."; - const char *msg600 = "User does not want to be disturbed."; - const char *msg603 = "Call declined."; const SalErrorInfo *ei = sal_op_get_error_info(op); switch (ei->reason) { - case SalReasonNone: - break; - case SalReasonRequestTimeout: - msg = "Request timeout."; - linphone_core_notify_display_status(core, msg); - break; - case SalReasonDeclined: - linphone_core_notify_display_status(core, msg603); - break; - case SalReasonBusy: - linphone_core_notify_display_status(core, msg486); - break; case SalReasonRedirect: if ((state == LinphoneCallOutgoingInit) || (state == LinphoneCallOutgoingProgress) || (state == LinphoneCallOutgoingRinging) /* Push notification case */ || (state == LinphoneCallOutgoingEarlyMedia)) { @@ -297,24 +260,9 @@ bool CallSessionPrivate::failure () { #endif return true; } - msg = "Redirected"; - linphone_core_notify_display_status(core, msg); } break; - case SalReasonTemporarilyUnavailable: - linphone_core_notify_display_status(core, msg480); - break; - case SalReasonNotFound: - linphone_core_notify_display_status(core, msg); - break; - case SalReasonDoNotDisturb: - linphone_core_notify_display_status(core, msg600); - break; - case SalReasonUnsupportedContent: /* This is for compatibility: linphone sent 415 because of SDP offer answer failure */ - case SalReasonNotAcceptable: - break; default: - linphone_core_notify_display_status(core, "Call failed."); break; } @@ -371,12 +319,10 @@ void CallSessionPrivate::remoteRinging () { L_Q(CallSession); /* Set privacy */ q->getCurrentParams()->setPrivacy((LinphonePrivacyMask)sal_op_get_privacy(op)); - linphone_core_notify_display_status(core, _("Remote ringing.")); #if 0 if (lc->ringstream == NULL) start_remote_ring(lc, call); #endif lInfo() << "Remote ringing..."; - linphone_core_notify_display_status(core, _("Remote ringing...")); setState(LinphoneCallOutgoingRinging, "Remote ringing"); } @@ -404,8 +350,6 @@ void CallSessionPrivate::terminated () { linphone_core_stop_ringing(lc); } #endif - linphone_core_notify_show_interface(core); - linphone_core_notify_display_status(core, _("Call terminated.")); setState(LinphoneCallEnd, "Call ended"); } @@ -458,7 +402,6 @@ void CallSessionPrivate::updated (bool isUpdate) { void CallSessionPrivate::updatedByRemote () { L_Q(CallSession); - linphone_core_notify_display_status(core, "Call is updated by remote"); setState(LinphoneCallUpdatedByRemote,"Call updated by remote"); if (deferUpdate) { if (state == LinphoneCallUpdatedByRemote) @@ -489,7 +432,6 @@ void CallSessionPrivate::accept (const CallSessionParams *params) { } sal_call_accept(op); - linphone_core_notify_display_status(core, _("Connected.")); if (listener) listener->onSetCurrentSession(*q); setState(LinphoneCallConnected, "Connected"); @@ -650,7 +592,6 @@ LinphoneStatus CallSessionPrivate::startUpdate () { subject = "Refreshing"; else subject = "Media change"; - linphone_core_notify_display_status(core, "Modifying call parameters..."); if (destProxy && destProxy->op) { /* Give a chance to update the contact address if connectivity has changed */ sal_op_set_contact_address(op, sal_op_get_contact_address(destProxy->op)); @@ -664,7 +605,6 @@ void CallSessionPrivate::terminate () { linphone_error_info_set_reason(ei, LinphoneReasonDeclined); nonOpError = true; } - linphone_core_notify_display_status(core, _("Call ended")); setState(LinphoneCallEnd, "Call terminated"); } @@ -688,12 +628,8 @@ void CallSessionPrivate::setContactOp () { void CallSessionPrivate::completeLog () { log->duration = computeDuration(); /* Store duration since connected */ log->error_info = linphone_error_info_ref(ei); - if (log->status == LinphoneCallMissed) { + if (log->status == LinphoneCallMissed) core->missed_calls++; - char *info = bctbx_strdup_printf(ngettext("You have missed %i call.", "You have missed %i calls.", core->missed_calls), core->missed_calls); - linphone_core_notify_display_status(core, info); - bctbx_free(info); - } linphone_core_report_call_log(core, log); } @@ -890,16 +826,6 @@ void CallSession::startIncomingNotification () { return; } - LinphoneAddress *fromParsed = linphone_address_new(sal_op_get_from(d->op)); - linphone_address_clean(fromParsed); - char *tmp = linphone_address_as_string(fromParsed); - linphone_address_unref(fromParsed); - char *msg = ms_strdup_printf("%s %s%s", tmp, _("is contacting you"), (sal_call_autoanswer_asked(d->op)) ? _(" and asked autoanswer") : ""); - ms_free(tmp); - linphone_core_notify_show_interface(d->core); - linphone_core_notify_display_status(d->core, msg); - ms_free(msg); - if (d->listener) d->listener->onIncomingCallSessionStarted(*this); @@ -932,9 +858,6 @@ int CallSession::startInvite (const Address *destination) { destinationStr = realUrl; ms_free(realUrl); } - ostringstream os; - os << "Contacting " << destinationStr; - linphone_core_notify_display_status(d->core, os.str().c_str()); char *from = linphone_address_as_string(d->log->from); /* Take a ref because sal_call() may destroy the CallSession if no SIP transport is available */ shared_ptr ref = static_pointer_cast(shared_from_this()); @@ -944,7 +867,6 @@ int CallSession::startInvite (const Address *destination) { if ((d->state != LinphoneCallError) && (d->state != LinphoneCallReleased)) { /* sal_call() may invoke call_failure() and call_released() SAL callbacks synchronously, in which case there is no need to perform a state change here. */ - linphone_core_notify_display_status(d->core, _("Could not call")); d->setState(LinphoneCallError, "Call failed"); } } else { diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index a3f967873..75eaddcc2 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -150,8 +150,6 @@ void MediaSessionPrivate::accepted () { string nextStateMsg; switch (state) { case LinphoneCallResuming: - linphone_core_notify_display_status(core, _("Call resumed.")); - BCTBX_NO_BREAK; /* Intentional no break */ case LinphoneCallConnected: #if 0 if (call->referer) @@ -221,7 +219,7 @@ void MediaSessionPrivate::accepted () { break; default: lInfo() << "Incompatible SDP answer received, restoring previous state [" << linphone_call_state_to_string(prevState) << "]"; - setState(prevState, _("Incompatible media parameters.")); + setState(prevState, "Incompatible media parameters."); break; } break; @@ -249,7 +247,6 @@ void MediaSessionPrivate::ackReceived (LinphoneHeaders *headers) { bool MediaSessionPrivate::failure () { L_Q(MediaSession); const SalErrorInfo *ei = sal_op_get_error_info(op); - const char *msg = ei->full_string; switch (ei->reason) { case SalReasonRedirect: stopStreams(); @@ -292,8 +289,6 @@ bool MediaSessionPrivate::failure () { } } } - msg = "Incompatible media parameters."; - linphone_core_notify_display_status(core, msg); break; default: break; @@ -324,7 +319,6 @@ bool MediaSessionPrivate::failure () { } void MediaSessionPrivate::pausedByRemote () { - linphone_core_notify_display_status(core, "We are paused by other party"); MediaSessionParams *newParams = new MediaSessionParams(*params); if (lp_config_get_int(linphone_core_get_config(core), "sip", "inactive_video_on_pause", 0)) newParams->setVideoDirection(LinphoneMediaDirectionInactive); @@ -335,7 +329,6 @@ void MediaSessionPrivate::remoteRinging () { L_Q(MediaSession); /* Set privacy */ q->getCurrentParams()->setPrivacy((LinphonePrivacyMask)sal_op_get_privacy(op)); - linphone_core_notify_display_status(core, _("Remote ringing.")); SalMediaDescription *md = sal_call_get_final_media_description(op); if (md) { /* Initialize the remote call params by invoking linphone_call_get_remote_params(). This is useful as the SDP may not be present in the 200Ok */ @@ -352,11 +345,9 @@ void MediaSessionPrivate::remoteRinging () { if (videoStream) video_stream_send_vfu(videoStream); /* Request for iframe */ #endif - return; + return; } - linphone_core_notify_show_interface(core); - linphone_core_notify_display_status(core, _("Early media.")); setState(LinphoneCallOutgoingEarlyMedia, "Early media"); #if 0 linphone_core_stop_ringing(lc); @@ -379,13 +370,11 @@ void MediaSessionPrivate::remoteRinging () { if (lc->ringstream == NULL) start_remote_ring(lc, call); #endif lInfo() << "Remote ringing..."; - linphone_core_notify_display_status(core, _("Remote ringing...")); setState(LinphoneCallOutgoingRinging, "Remote ringing"); } } void MediaSessionPrivate::resumed () { - linphone_core_notify_display_status(core, "We have been resumed"); acceptUpdate(nullptr, LinphoneCallStreamsRunning, "Connected (streams running)"); } @@ -3294,14 +3283,6 @@ void MediaSessionPrivate::audioStreamAuthTokenReady (const string &authToken, bo void MediaSessionPrivate::audioStreamEncryptionChanged (bool encrypted) { L_Q(MediaSession); - if (encrypted && (params->getMediaEncryption() == LinphoneMediaEncryptionZRTP)) { - /* If encryption is DTLS, no status to be displayed */ - char status[255]; - memset(status, 0, sizeof(status)); - snprintf(status, sizeof(status) - 1, _("Authentication token is %s"), authToken.c_str()); - linphone_core_notify_display_status(core, status); - } - propagateEncryptionChanged(); #ifdef VIDEO_ENABLED @@ -3694,11 +3675,9 @@ LinphoneStatus MediaSessionPrivate::pause () { setState(LinphoneCallPausing, "Pausing call"); makeLocalMediaDescription(); sal_call_set_local_media_description(op, localDesc); - if (sal_call_update(op, subject.c_str(), false) != 0) - linphone_core_notify_display_warning(core, "Could not pause the call"); + sal_call_update(op, subject.c_str(), false); if (listener) listener->onResetCurrentSession(*q); - linphone_core_notify_display_status(core, "Pausing the current call..."); if (audioStream || videoStream || textStream) stopStreams(); pausedByApp = false; @@ -4222,9 +4201,6 @@ LinphoneStatus MediaSession::resume () { d->setState(LinphoneCallResuming,"Resuming"); if (!d->params->getPrivate()->getInConference() && d->listener) d->listener->onSetCurrentSession(*this); - ostringstream os; - os << "Resuming the call with " << getRemoteAddressAsString(); - linphone_core_notify_display_status(d->core, os.str().c_str()); if (d->core->sip_conf.sdp_200_ack) { /* We are NOT offering, set local media description after sending the call so that we are ready to * process the remote offer when it will arrive. */ diff --git a/src/nat/ice-agent.cpp b/src/nat/ice-agent.cpp index 46c686f31..50ef1c1f9 100644 --- a/src/nat/ice-agent.cpp +++ b/src/nat/ice-agent.cpp @@ -557,7 +557,6 @@ int IceAgent::gatherIceCandidates () { } else lWarning() << "ICE is used without STUN server"; LinphoneCore *core = mediaSession.getPrivate()->getCore(); - linphone_core_notify_display_status(core, _("ICE local candidates gathering in progress...")); ice_session_enable_forced_relay(iceSession, core->forced_ice_relay); ice_session_enable_short_turn_refresh(iceSession, core->short_turn_refresh); diff --git a/src/nat/stun-client.cpp b/src/nat/stun-client.cpp index b9dc162af..554bd9eb4 100644 --- a/src/nat/stun-client.cpp +++ b/src/nat/stun-client.cpp @@ -42,7 +42,6 @@ int StunClient::run (int audioPort, int videoPort, int textPort) { lError() << "Could not obtain STUN server addrinfo"; return -1; } - linphone_core_notify_display_status(core, "Stun lookup in progress..."); /* Create the RTP sockets and send STUN messages to the STUN server */ ortp_socket_t sockAudio = createStunSocket(audioPort); From c7994eee8cdc56a1137efcee4221cf8a4de16a5f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 21 Sep 2017 18:32:13 +0200 Subject: [PATCH 0128/2215] Remove useless files. --- gen-gtkfilelist.sh | 28 ------ gtk+-2.16.2.filelist | 165 ------------------------------- gtk+-2.16.6.filelist | 146 ---------------------------- gtk+-2.18.5.filelist | 130 ------------------------- gtk+-2.22.1.filelist | 152 ----------------------------- gtk+-2.24.8.filelist | 213 ----------------------------------------- linphone-deps.filelist | 19 ---- 7 files changed, 853 deletions(-) delete mode 100755 gen-gtkfilelist.sh delete mode 100755 gtk+-2.16.2.filelist delete mode 100644 gtk+-2.16.6.filelist delete mode 100644 gtk+-2.18.5.filelist delete mode 100644 gtk+-2.22.1.filelist delete mode 100644 gtk+-2.24.8.filelist delete mode 100755 linphone-deps.filelist diff --git a/gen-gtkfilelist.sh b/gen-gtkfilelist.sh deleted file mode 100755 index 095c4979c..000000000 --- a/gen-gtkfilelist.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# this script is used to generate a file list of gtk+ files necessary for -# execution. This is useful for generating linphone packages. -# It must be run within a gtk+ binary bundle tree, such as in the zip bundle -# downloadable from www.gtk.org -echo bin -find bin -name *.dll -find lib/gtk-2.0 -find etc -find share/locale/cs -find share/locale/de -find share/locale/es -find share/locale/fr -find share/locale/he -find share/locale/hu -find share/locale/it -find share/locale/ja -find share/locale/nb -find share/locale/nl -find share/locale/pl -find share/locale/pt -find share/locale/pt_BR -find share/locale/ru -find share/locale/sr -find share/locale/sv -find share/locale/zh_CN -find share/locale/zh_TW -find share/themes diff --git a/gtk+-2.16.2.filelist b/gtk+-2.16.2.filelist deleted file mode 100755 index 10e10a515..000000000 --- a/gtk+-2.16.2.filelist +++ /dev/null @@ -1,165 +0,0 @@ -bin -bin/libglade-2.0-0.dll -bin/intl.dll -bin/jpeg62.dll -bin/libasprintf-0.dll -bin/libatk-1.0-0.dll -bin/libcairo-2.dll -bin/libgailutil-18.dll -bin/libgdk-win32-2.0-0.dll -bin/libgdk_pixbuf-2.0-0.dll -bin/libgettextlib-0-17.dll -bin/libgettextpo-0.dll -bin/libgettextsrc-0-17.dll -bin/libgio-2.0-0.dll -bin/libglib-2.0-0.dll -bin/libgmodule-2.0-0.dll -bin/libgobject-2.0-0.dll -bin/libgthread-2.0-0.dll -bin/libgtk-win32-2.0-0.dll -bin/libpango-1.0-0.dll -bin/libpangocairo-1.0-0.dll -bin/libpangoft2-1.0-0.dll -bin/libpangowin32-1.0-0.dll -bin/libpng12-0.dll -bin/libtiff3.dll -bin/zlib1.dll -lib/gtk-2.0 -lib/gtk-2.0/2.10.0 -lib/gtk-2.0/2.10.0/engines -lib/gtk-2.0/2.10.0/engines/libpixmap.dll -lib/gtk-2.0/2.10.0/engines/libwimp.dll -lib/gtk-2.0/2.10.0/loaders -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-ani.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-bmp.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-gif.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-icns.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-ico.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-jpeg.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-pcx.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-png.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-pnm.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-ras.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-tga.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-tiff.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-wbmp.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-xbm.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-xpm.dll -lib/gtk-2.0/include -lib/gtk-2.0/include/gdkconfig.h -lib/gtk-2.0/modules -lib/gtk-2.0/modules/libgail.dll -etc -etc/gtk-2.0 -etc/gtk-2.0/gdk-pixbuf.loaders -etc/gtk-2.0/gtk.immodules -etc/gtk-2.0/im-multipress.conf -etc/pango -etc/pango/pango.modules -share/locale/fr -share/locale/fr/LC_MESSAGES -share/locale/fr/LC_MESSAGES/atk10.mo -share/locale/fr/LC_MESSAGES/gettext-runtime.mo -share/locale/fr/LC_MESSAGES/gettext-tools.mo -share/locale/fr/LC_MESSAGES/glib20.mo -share/locale/fr/LC_MESSAGES/gtk20-properties.mo -share/locale/fr/LC_MESSAGES/gtk20.mo -share/locale/de -share/locale/de/LC_MESSAGES -share/locale/de/LC_MESSAGES/atk10.mo -share/locale/de/LC_MESSAGES/gettext-runtime.mo -share/locale/de/LC_MESSAGES/gettext-tools.mo -share/locale/de/LC_MESSAGES/glib20.mo -share/locale/de/LC_MESSAGES/gtk20-properties.mo -share/locale/de/LC_MESSAGES/gtk20.mo -share/locale/sv -share/locale/sv/LC_MESSAGES -share/locale/sv/LC_MESSAGES/atk10.mo -share/locale/sv/LC_MESSAGES/gettext-runtime.mo -share/locale/sv/LC_MESSAGES/gettext-tools.mo -share/locale/sv/LC_MESSAGES/glib20.mo -share/locale/sv/LC_MESSAGES/gtk20-properties.mo -share/locale/sv/LC_MESSAGES/gtk20.mo -share/locale/cs -share/locale/cs/LC_MESSAGES -share/locale/cs/LC_MESSAGES/atk10.mo -share/locale/cs/LC_MESSAGES/gettext-runtime.mo -share/locale/cs/LC_MESSAGES/gettext-tools.mo -share/locale/cs/LC_MESSAGES/glib20.mo -share/locale/cs/LC_MESSAGES/gtk20-properties.mo -share/locale/cs/LC_MESSAGES/gtk20.mo -share/locale/es -share/locale/es/LC_MESSAGES -share/locale/es/LC_MESSAGES/atk10.mo -share/locale/es/LC_MESSAGES/gettext-runtime.mo -share/locale/es/LC_MESSAGES/gettext-tools.mo -share/locale/es/LC_MESSAGES/glib20.mo -share/locale/es/LC_MESSAGES/gtk20-properties.mo -share/locale/es/LC_MESSAGES/gtk20.mo -share/locale/hu -share/locale/hu/LC_MESSAGES -share/locale/hu/LC_MESSAGES/atk10.mo -share/locale/hu/LC_MESSAGES/glib20.mo -share/locale/hu/LC_MESSAGES/gtk20-properties.mo -share/locale/hu/LC_MESSAGES/gtk20.mo -share/locale/it -share/locale/it/LC_MESSAGES -share/locale/it/LC_MESSAGES/atk10.mo -share/locale/it/LC_MESSAGES/gettext-runtime.mo -share/locale/it/LC_MESSAGES/gettext-tools.mo -share/locale/it/LC_MESSAGES/glib20.mo -share/locale/it/LC_MESSAGES/gtk20-properties.mo -share/locale/it/LC_MESSAGES/gtk20.mo -share/locale/ja -share/locale/ja/LC_MESSAGES -share/locale/ja/LC_MESSAGES/atk10.mo -share/locale/ja/LC_MESSAGES/gettext-runtime.mo -share/locale/ja/LC_MESSAGES/gettext-tools.mo -share/locale/ja/LC_MESSAGES/glib20.mo -share/locale/ja/LC_MESSAGES/gtk20-properties.mo -share/locale/ja/LC_MESSAGES/gtk20.mo -share/locale/nl -share/locale/nl/LC_MESSAGES -share/locale/nl/LC_MESSAGES/atk10.mo -share/locale/nl/LC_MESSAGES/gettext-runtime.mo -share/locale/nl/LC_MESSAGES/gettext-tools.mo -share/locale/nl/LC_MESSAGES/glib20.mo -share/locale/nl/LC_MESSAGES/gtk20-properties.mo -share/locale/nl/LC_MESSAGES/gtk20.mo -share/locale/pl -share/locale/pl/LC_MESSAGES -share/locale/pl/LC_MESSAGES/atk10.mo -share/locale/pl/LC_MESSAGES/gettext-runtime.mo -share/locale/pl/LC_MESSAGES/gettext-tools.mo -share/locale/pl/LC_MESSAGES/glib20.mo -share/locale/pl/LC_MESSAGES/gtk20-properties.mo -share/locale/pl/LC_MESSAGES/gtk20.mo -share/locale/ru -share/locale/ru/LC_MESSAGES -share/locale/ru/LC_MESSAGES/atk10.mo -share/locale/ru/LC_MESSAGES/gettext-runtime.mo -share/locale/ru/LC_MESSAGES/gettext-tools.mo -share/locale/ru/LC_MESSAGES/glib20.mo -share/locale/ru/LC_MESSAGES/gtk20-properties.mo -share/locale/ru/LC_MESSAGES/gtk20.mo -share/locale/pt_BR -share/locale/pt_BR/LC_MESSAGES -share/locale/pt_BR/LC_MESSAGES/atk10.mo -share/locale/pt_BR/LC_MESSAGES/gettext-runtime.mo -share/locale/pt_BR/LC_MESSAGES/gettext-tools.mo -share/locale/pt_BR/LC_MESSAGES/glib20.mo -share/locale/pt_BR/LC_MESSAGES/gtk20-properties.mo -share/locale/pt_BR/LC_MESSAGES/gtk20.mo -share/themes -share/themes/Default -share/themes/Default/gtk-2.0-key -share/themes/Default/gtk-2.0-key/gtkrc -share/themes/Emacs -share/themes/Emacs/gtk-2.0-key -share/themes/Emacs/gtk-2.0-key/gtkrc -share/themes/MS-Windows -share/themes/MS-Windows/gtk-2.0 -share/themes/MS-Windows/gtk-2.0/gtkrc -share/themes/Raleigh -share/themes/Raleigh/gtk-2.0 -share/themes/Raleigh/gtk-2.0/gtkrc diff --git a/gtk+-2.16.6.filelist b/gtk+-2.16.6.filelist deleted file mode 100644 index 2b9b82f19..000000000 --- a/gtk+-2.16.6.filelist +++ /dev/null @@ -1,146 +0,0 @@ -bin -bin/libglade-2.0-0.dll -bin/freetype6.dll -bin/intl.dll -bin/libatk-1.0-0.dll -bin/libcairo-2.dll -bin/libexpat-1.dll -bin/libfontconfig-1.dll -bin/libgailutil-18.dll -bin/libgdk-win32-2.0-0.dll -bin/libgdk_pixbuf-2.0-0.dll -bin/libgio-2.0-0.dll -bin/libglib-2.0-0.dll -bin/libgmodule-2.0-0.dll -bin/libgobject-2.0-0.dll -bin/libgthread-2.0-0.dll -bin/libgtk-win32-2.0-0.dll -bin/libjpeg-7.dll -bin/libpango-1.0-0.dll -bin/libpangocairo-1.0-0.dll -bin/libpangoft2-1.0-0.dll -bin/libpangowin32-1.0-0.dll -bin/libpng12-0.dll -bin/libtiff-3.dll -bin/libtiffxx-3.dll -bin/zlib1.dll -lib/gtk-2.0 -lib/gtk-2.0/2.10.0 -lib/gtk-2.0/2.10.0/engines -lib/gtk-2.0/2.10.0/engines/libpixmap.dll -lib/gtk-2.0/2.10.0/engines/libwimp.dll -lib/gtk-2.0/2.10.0/loaders -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-ani.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-bmp.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-gif.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-icns.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-ico.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-jpeg.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-pcx.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-png.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-pnm.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-ras.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-tga.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-tiff.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-wbmp.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-xbm.dll -lib/gtk-2.0/2.10.0/loaders/libpixbufloader-xpm.dll -lib/gtk-2.0/include -lib/gtk-2.0/include/gdkconfig.h -lib/gtk-2.0/modules -lib/gtk-2.0/modules/libgail.dll -etc -etc/fonts -etc/fonts/fonts.conf -etc/fonts/fonts.dtd -etc/gtk-2.0 -etc/gtk-2.0/gdk-pixbuf.loaders -etc/gtk-2.0/gtk.immodules -etc/gtk-2.0/im-multipress.conf -etc/pango -etc/pango/pango.modules -share/locale/fr -share/locale/fr/LC_MESSAGES -share/locale/fr/LC_MESSAGES/atk10.mo -share/locale/fr/LC_MESSAGES/glib20.mo -share/locale/fr/LC_MESSAGES/gtk20-properties.mo -share/locale/fr/LC_MESSAGES/gtk20.mo -share/locale/de -share/locale/de/LC_MESSAGES -share/locale/de/LC_MESSAGES/atk10.mo -share/locale/de/LC_MESSAGES/glib20.mo -share/locale/de/LC_MESSAGES/gtk20-properties.mo -share/locale/de/LC_MESSAGES/gtk20.mo -share/locale/sv -share/locale/sv/LC_MESSAGES -share/locale/sv/LC_MESSAGES/atk10.mo -share/locale/sv/LC_MESSAGES/glib20.mo -share/locale/sv/LC_MESSAGES/gtk20-properties.mo -share/locale/sv/LC_MESSAGES/gtk20.mo -share/locale/cs -share/locale/cs/LC_MESSAGES -share/locale/cs/LC_MESSAGES/atk10.mo -share/locale/cs/LC_MESSAGES/glib20.mo -share/locale/cs/LC_MESSAGES/gtk20-properties.mo -share/locale/cs/LC_MESSAGES/gtk20.mo -share/locale/es -share/locale/es/LC_MESSAGES -share/locale/es/LC_MESSAGES/atk10.mo -share/locale/es/LC_MESSAGES/glib20.mo -share/locale/es/LC_MESSAGES/gtk20-properties.mo -share/locale/es/LC_MESSAGES/gtk20.mo -share/locale/hu -share/locale/hu/LC_MESSAGES -share/locale/hu/LC_MESSAGES/atk10.mo -share/locale/hu/LC_MESSAGES/glib20.mo -share/locale/hu/LC_MESSAGES/gtk20-properties.mo -share/locale/hu/LC_MESSAGES/gtk20.mo -share/locale/it -share/locale/it/LC_MESSAGES -share/locale/it/LC_MESSAGES/atk10.mo -share/locale/it/LC_MESSAGES/glib20.mo -share/locale/it/LC_MESSAGES/gtk20-properties.mo -share/locale/it/LC_MESSAGES/gtk20.mo -share/locale/ja -share/locale/ja/LC_MESSAGES -share/locale/ja/LC_MESSAGES/atk10.mo -share/locale/ja/LC_MESSAGES/glib20.mo -share/locale/ja/LC_MESSAGES/gtk20-properties.mo -share/locale/ja/LC_MESSAGES/gtk20.mo -share/locale/nl -share/locale/nl/LC_MESSAGES -share/locale/nl/LC_MESSAGES/atk10.mo -share/locale/nl/LC_MESSAGES/glib20.mo -share/locale/nl/LC_MESSAGES/gtk20-properties.mo -share/locale/nl/LC_MESSAGES/gtk20.mo -share/locale/pl -share/locale/pl/LC_MESSAGES -share/locale/pl/LC_MESSAGES/atk10.mo -share/locale/pl/LC_MESSAGES/glib20.mo -share/locale/pl/LC_MESSAGES/gtk20-properties.mo -share/locale/pl/LC_MESSAGES/gtk20.mo -share/locale/ru -share/locale/ru/LC_MESSAGES -share/locale/ru/LC_MESSAGES/atk10.mo -share/locale/ru/LC_MESSAGES/glib20.mo -share/locale/ru/LC_MESSAGES/gtk20-properties.mo -share/locale/ru/LC_MESSAGES/gtk20.mo -share/locale/pt_BR -share/locale/pt_BR/LC_MESSAGES -share/locale/pt_BR/LC_MESSAGES/atk10.mo -share/locale/pt_BR/LC_MESSAGES/glib20.mo -share/locale/pt_BR/LC_MESSAGES/gtk20-properties.mo -share/locale/pt_BR/LC_MESSAGES/gtk20.mo -share/themes -share/themes/Default -share/themes/Default/gtk-2.0-key -share/themes/Default/gtk-2.0-key/gtkrc -share/themes/Emacs -share/themes/Emacs/gtk-2.0-key -share/themes/Emacs/gtk-2.0-key/gtkrc -share/themes/MS-Windows -share/themes/MS-Windows/gtk-2.0 -share/themes/MS-Windows/gtk-2.0/gtkrc -share/themes/Raleigh -share/themes/Raleigh/gtk-2.0 -share/themes/Raleigh/gtk-2.0/gtkrc diff --git a/gtk+-2.18.5.filelist b/gtk+-2.18.5.filelist deleted file mode 100644 index cb2f3bef4..000000000 --- a/gtk+-2.18.5.filelist +++ /dev/null @@ -1,130 +0,0 @@ -bin -bin/libglade-2.0-0.dll -bin/freetype6.dll -bin/intl.dll -bin/libatk-1.0-0.dll -bin/libcairo-2.dll -bin/libexpat-1.dll -bin/libfontconfig-1.dll -bin/libgailutil-18.dll -bin/libgdk-win32-2.0-0.dll -bin/libgdk_pixbuf-2.0-0.dll -bin/libgio-2.0-0.dll -bin/libglib-2.0-0.dll -bin/libgmodule-2.0-0.dll -bin/libgobject-2.0-0.dll -bin/libgthread-2.0-0.dll -bin/libgtk-win32-2.0-0.dll -bin/libjpeg-7.dll -bin/libpango-1.0-0.dll -bin/libpangocairo-1.0-0.dll -bin/libpangoft2-1.0-0.dll -bin/libpangowin32-1.0-0.dll -bin/libpng12-0.dll -bin/libtiff-3.dll -bin/libtiffxx-3.dll -bin/zlib1.dll -lib/gtk-2.0 -lib/gtk-2.0/2.10.0 -lib/gtk-2.0/2.10.0/engines -lib/gtk-2.0/2.10.0/engines/libpixmap.dll -lib/gtk-2.0/2.10.0/engines/libwimp.dll -lib/gtk-2.0/include -lib/gtk-2.0/include/gdkconfig.h -lib/gtk-2.0/modules -lib/gtk-2.0/modules/libgail.dll -etc -etc/fonts -etc/fonts/fonts.conf -etc/fonts/fonts.dtd -etc/gtk-2.0 -etc/gtk-2.0/gdk-pixbuf.loaders -etc/gtk-2.0/gtk.immodules -etc/gtk-2.0/im-multipress.conf -etc/pango -etc/pango/pango.modules -share/locale/fr -share/locale/fr/LC_MESSAGES -share/locale/fr/LC_MESSAGES/atk10.mo -share/locale/fr/LC_MESSAGES/glib20.mo -share/locale/fr/LC_MESSAGES/gtk20-properties.mo -share/locale/fr/LC_MESSAGES/gtk20.mo -share/locale/de -share/locale/de/LC_MESSAGES -share/locale/de/LC_MESSAGES/atk10.mo -share/locale/de/LC_MESSAGES/glib20.mo -share/locale/de/LC_MESSAGES/gtk20-properties.mo -share/locale/de/LC_MESSAGES/gtk20.mo -share/locale/sv -share/locale/sv/LC_MESSAGES -share/locale/sv/LC_MESSAGES/atk10.mo -share/locale/sv/LC_MESSAGES/glib20.mo -share/locale/sv/LC_MESSAGES/gtk20-properties.mo -share/locale/sv/LC_MESSAGES/gtk20.mo -share/locale/cs -share/locale/cs/LC_MESSAGES -share/locale/cs/LC_MESSAGES/atk10.mo -share/locale/cs/LC_MESSAGES/glib20.mo -share/locale/cs/LC_MESSAGES/gtk20-properties.mo -share/locale/cs/LC_MESSAGES/gtk20.mo -share/locale/es -share/locale/es/LC_MESSAGES -share/locale/es/LC_MESSAGES/atk10.mo -share/locale/es/LC_MESSAGES/glib20.mo -share/locale/es/LC_MESSAGES/gtk20-properties.mo -share/locale/es/LC_MESSAGES/gtk20.mo -share/locale/hu -share/locale/hu/LC_MESSAGES -share/locale/hu/LC_MESSAGES/atk10.mo -share/locale/hu/LC_MESSAGES/glib20.mo -share/locale/hu/LC_MESSAGES/gtk20-properties.mo -share/locale/hu/LC_MESSAGES/gtk20.mo -share/locale/it -share/locale/it/LC_MESSAGES -share/locale/it/LC_MESSAGES/atk10.mo -share/locale/it/LC_MESSAGES/glib20.mo -share/locale/it/LC_MESSAGES/gtk20-properties.mo -share/locale/it/LC_MESSAGES/gtk20.mo -share/locale/ja -share/locale/ja/LC_MESSAGES -share/locale/ja/LC_MESSAGES/atk10.mo -share/locale/ja/LC_MESSAGES/glib20.mo -share/locale/ja/LC_MESSAGES/gtk20-properties.mo -share/locale/ja/LC_MESSAGES/gtk20.mo -share/locale/nl -share/locale/nl/LC_MESSAGES -share/locale/nl/LC_MESSAGES/atk10.mo -share/locale/nl/LC_MESSAGES/glib20.mo -share/locale/nl/LC_MESSAGES/gtk20-properties.mo -share/locale/nl/LC_MESSAGES/gtk20.mo -share/locale/pl -share/locale/pl/LC_MESSAGES -share/locale/pl/LC_MESSAGES/atk10.mo -share/locale/pl/LC_MESSAGES/glib20.mo -share/locale/pl/LC_MESSAGES/gtk20-properties.mo -share/locale/pl/LC_MESSAGES/gtk20.mo -share/locale/ru -share/locale/ru/LC_MESSAGES -share/locale/ru/LC_MESSAGES/atk10.mo -share/locale/ru/LC_MESSAGES/glib20.mo -share/locale/ru/LC_MESSAGES/gtk20-properties.mo -share/locale/ru/LC_MESSAGES/gtk20.mo -share/locale/pt_BR -share/locale/pt_BR/LC_MESSAGES -share/locale/pt_BR/LC_MESSAGES/atk10.mo -share/locale/pt_BR/LC_MESSAGES/glib20.mo -share/locale/pt_BR/LC_MESSAGES/gtk20-properties.mo -share/locale/pt_BR/LC_MESSAGES/gtk20.mo -share/themes -share/themes/Default -share/themes/Default/gtk-2.0-key -share/themes/Default/gtk-2.0-key/gtkrc -share/themes/Emacs -share/themes/Emacs/gtk-2.0-key -share/themes/Emacs/gtk-2.0-key/gtkrc -share/themes/MS-Windows -share/themes/MS-Windows/gtk-2.0 -share/themes/MS-Windows/gtk-2.0/gtkrc -share/themes/Raleigh -share/themes/Raleigh/gtk-2.0 -share/themes/Raleigh/gtk-2.0/gtkrc diff --git a/gtk+-2.22.1.filelist b/gtk+-2.22.1.filelist deleted file mode 100644 index 792aeeb06..000000000 --- a/gtk+-2.22.1.filelist +++ /dev/null @@ -1,152 +0,0 @@ -bin -bin/freetype6.dll -bin/intl.dll -bin/libasprintf-0.dll -bin/libatk-1.0-0.dll -bin/libcairo-2.dll -bin/libcairo-gobject-2.dll -bin/libcairo-script-interpreter-2.dll -bin/libexpat-1.dll -bin/libfontconfig-1.dll -bin/libgailutil-18.dll -bin/libgcc_s_dw2-1.dll -bin/libgdk-win32-2.0-0.dll -bin/libgdk_pixbuf-2.0-0.dll -bin/libgio-2.0-0.dll -bin/libglib-2.0-0.dll -bin/libgmodule-2.0-0.dll -bin/libgobject-2.0-0.dll -bin/libgthread-2.0-0.dll -bin/libgtk-win32-2.0-0.dll -bin/libpango-1.0-0.dll -bin/libpangocairo-1.0-0.dll -bin/libpangoft2-1.0-0.dll -bin/libpangowin32-1.0-0.dll -bin/libpng14-14.dll -bin/zlib1.dll -lib/gtk-2.0 -lib/gtk-2.0/2.10.0 -lib/gtk-2.0/2.10.0/engines -lib/gtk-2.0/2.10.0/engines/libpixmap.dll -lib/gtk-2.0/2.10.0/engines/libwimp.dll -lib/gtk-2.0/include -lib/gtk-2.0/include/gdkconfig.h -lib/gtk-2.0/modules -lib/gtk-2.0/modules/libgail.dll -etc -etc/fonts -etc/fonts/fonts.conf -etc/fonts/fonts.dtd -etc/gtk-2.0 -etc/gtk-2.0/gtk.immodules -etc/gtk-2.0/im-multipress.conf -etc/pango -etc/pango/pango.modules -share/locale/fr -share/locale/fr/LC_MESSAGES -share/locale/fr/LC_MESSAGES/atk10.mo -share/locale/fr/LC_MESSAGES/gdk-pixbuf.mo -share/locale/fr/LC_MESSAGES/gettext-runtime.mo -share/locale/fr/LC_MESSAGES/glib20.mo -share/locale/fr/LC_MESSAGES/gtk20-properties.mo -share/locale/fr/LC_MESSAGES/gtk20.mo -share/locale/de -share/locale/de/LC_MESSAGES -share/locale/de/LC_MESSAGES/atk10.mo -share/locale/de/LC_MESSAGES/gdk-pixbuf.mo -share/locale/de/LC_MESSAGES/gettext-runtime.mo -share/locale/de/LC_MESSAGES/glib20.mo -share/locale/de/LC_MESSAGES/gtk20-properties.mo -share/locale/de/LC_MESSAGES/gtk20.mo -share/locale/sv -share/locale/sv/LC_MESSAGES -share/locale/sv/LC_MESSAGES/atk10.mo -share/locale/sv/LC_MESSAGES/gdk-pixbuf.mo -share/locale/sv/LC_MESSAGES/gettext-runtime.mo -share/locale/sv/LC_MESSAGES/glib20.mo -share/locale/sv/LC_MESSAGES/gtk20-properties.mo -share/locale/sv/LC_MESSAGES/gtk20.mo -share/locale/cs -share/locale/cs/LC_MESSAGES -share/locale/cs/LC_MESSAGES/atk10.mo -share/locale/cs/LC_MESSAGES/gdk-pixbuf.mo -share/locale/cs/LC_MESSAGES/gettext-runtime.mo -share/locale/cs/LC_MESSAGES/glib20.mo -share/locale/cs/LC_MESSAGES/gtk20-properties.mo -share/locale/cs/LC_MESSAGES/gtk20.mo -share/locale/es -share/locale/es/LC_MESSAGES -share/locale/es/LC_MESSAGES/atk10.mo -share/locale/es/LC_MESSAGES/gdk-pixbuf.mo -share/locale/es/LC_MESSAGES/gettext-runtime.mo -share/locale/es/LC_MESSAGES/glib20.mo -share/locale/es/LC_MESSAGES/gtk20-properties.mo -share/locale/es/LC_MESSAGES/gtk20.mo -share/locale/hu -share/locale/hu/LC_MESSAGES -share/locale/hu/LC_MESSAGES/atk10.mo -share/locale/hu/LC_MESSAGES/gdk-pixbuf.mo -share/locale/hu/LC_MESSAGES/glib20.mo -share/locale/hu/LC_MESSAGES/gtk20-properties.mo -share/locale/hu/LC_MESSAGES/gtk20.mo -share/locale/it -share/locale/it/LC_MESSAGES -share/locale/it/LC_MESSAGES/atk10.mo -share/locale/it/LC_MESSAGES/gdk-pixbuf.mo -share/locale/it/LC_MESSAGES/gettext-runtime.mo -share/locale/it/LC_MESSAGES/glib20.mo -share/locale/it/LC_MESSAGES/gtk20-properties.mo -share/locale/it/LC_MESSAGES/gtk20.mo -share/locale/ja -share/locale/ja/LC_MESSAGES -share/locale/ja/LC_MESSAGES/atk10.mo -share/locale/ja/LC_MESSAGES/gdk-pixbuf.mo -share/locale/ja/LC_MESSAGES/gettext-runtime.mo -share/locale/ja/LC_MESSAGES/glib20.mo -share/locale/ja/LC_MESSAGES/gtk20-properties.mo -share/locale/ja/LC_MESSAGES/gtk20.mo -share/locale/nl -share/locale/nl/LC_MESSAGES -share/locale/nl/LC_MESSAGES/atk10.mo -share/locale/nl/LC_MESSAGES/gdk-pixbuf.mo -share/locale/nl/LC_MESSAGES/gettext-runtime.mo -share/locale/nl/LC_MESSAGES/glib20.mo -share/locale/nl/LC_MESSAGES/gtk20-properties.mo -share/locale/nl/LC_MESSAGES/gtk20.mo -share/locale/pl -share/locale/pl/LC_MESSAGES -share/locale/pl/LC_MESSAGES/atk10.mo -share/locale/pl/LC_MESSAGES/gdk-pixbuf.mo -share/locale/pl/LC_MESSAGES/gettext-runtime.mo -share/locale/pl/LC_MESSAGES/glib20.mo -share/locale/pl/LC_MESSAGES/gtk20-properties.mo -share/locale/pl/LC_MESSAGES/gtk20.mo -share/locale/ru -share/locale/ru/LC_MESSAGES -share/locale/ru/LC_MESSAGES/atk10.mo -share/locale/ru/LC_MESSAGES/gdk-pixbuf.mo -share/locale/ru/LC_MESSAGES/gettext-runtime.mo -share/locale/ru/LC_MESSAGES/glib20.mo -share/locale/ru/LC_MESSAGES/gtk20-properties.mo -share/locale/ru/LC_MESSAGES/gtk20.mo -share/locale/pt_BR -share/locale/pt_BR/LC_MESSAGES -share/locale/pt_BR/LC_MESSAGES/atk10.mo -share/locale/pt_BR/LC_MESSAGES/gdk-pixbuf.mo -share/locale/pt_BR/LC_MESSAGES/gettext-runtime.mo -share/locale/pt_BR/LC_MESSAGES/glib20.mo -share/locale/pt_BR/LC_MESSAGES/gtk20-properties.mo -share/locale/pt_BR/LC_MESSAGES/gtk20.mo -share/themes -share/themes/Default -share/themes/Default/gtk-2.0-key -share/themes/Default/gtk-2.0-key/gtkrc -share/themes/Emacs -share/themes/Emacs/gtk-2.0-key -share/themes/Emacs/gtk-2.0-key/gtkrc -share/themes/MS-Windows -share/themes/MS-Windows/gtk-2.0 -share/themes/MS-Windows/gtk-2.0/gtkrc -share/themes/Raleigh -share/themes/Raleigh/gtk-2.0 -share/themes/Raleigh/gtk-2.0/gtkrc diff --git a/gtk+-2.24.8.filelist b/gtk+-2.24.8.filelist deleted file mode 100644 index f893fafa0..000000000 --- a/gtk+-2.24.8.filelist +++ /dev/null @@ -1,213 +0,0 @@ -bin -bin/freetype6.dll -bin/intl.dll -bin/libasprintf-0.dll -bin/libatk-1.0-0.dll -bin/libcairo-2.dll -bin/libcairo-gobject-2.dll -bin/libcairo-script-interpreter-2.dll -bin/libexpat-1.dll -bin/libfontconfig-1.dll -bin/libgailutil-18.dll -bin/libgcc_s_dw2-1.dll -bin/libgdk-win32-2.0-0.dll -bin/libgdk_pixbuf-2.0-0.dll -bin/libgio-2.0-0.dll -bin/libglib-2.0-0.dll -bin/libgmodule-2.0-0.dll -bin/libgobject-2.0-0.dll -bin/libgthread-2.0-0.dll -bin/libgtk-win32-2.0-0.dll -bin/libpango-1.0-0.dll -bin/libpangocairo-1.0-0.dll -bin/libpangoft2-1.0-0.dll -bin/libpangowin32-1.0-0.dll -bin/libpng14-14.dll -bin/zlib1.dll -lib/gtk-2.0 -lib/gtk-2.0/2.10.0 -lib/gtk-2.0/2.10.0/engines -lib/gtk-2.0/2.10.0/engines/libpixmap.dll -lib/gtk-2.0/2.10.0/engines/libwimp.dll -lib/gtk-2.0/include -lib/gtk-2.0/include/gdkconfig.h -lib/gtk-2.0/modules -lib/gtk-2.0/modules/libgail.dll -etc -etc/bash_completion.d -etc/bash_completion.d/gdbus-bash-completion.sh -etc/bash_completion.d/gsettings-bash-completion.sh -etc/fonts -etc/fonts/fonts.conf -etc/fonts/fonts.dtd -etc/gtk-2.0 -etc/gtk-2.0/gtk.immodules -etc/gtk-2.0/im-multipress.conf -etc/pango -etc/pango/pango.modules -share/locale/ar/LC_MESSAGES/atk10.mo -share/locale/ar/LC_MESSAGES/gdk-pixbuf.mo -share/locale/ar/LC_MESSAGES/glib20.mo -share/locale/ar/LC_MESSAGES/gtk20-properties.mo -share/locale/ar/LC_MESSAGES/gtk20.mo -share/locale/cs -share/locale/cs/LC_MESSAGES -share/locale/cs/LC_MESSAGES/atk10.mo -share/locale/cs/LC_MESSAGES/gdk-pixbuf.mo -share/locale/cs/LC_MESSAGES/gettext-runtime.mo -share/locale/cs/LC_MESSAGES/glib20.mo -share/locale/cs/LC_MESSAGES/gtk20-properties.mo -share/locale/cs/LC_MESSAGES/gtk20.mo -share/locale/de -share/locale/de/LC_MESSAGES -share/locale/de/LC_MESSAGES/atk10.mo -share/locale/de/LC_MESSAGES/gdk-pixbuf.mo -share/locale/de/LC_MESSAGES/gettext-runtime.mo -share/locale/de/LC_MESSAGES/glib20.mo -share/locale/de/LC_MESSAGES/gtk20-properties.mo -share/locale/de/LC_MESSAGES/gtk20.mo -share/locale/es -share/locale/es/LC_MESSAGES -share/locale/es/LC_MESSAGES/atk10.mo -share/locale/es/LC_MESSAGES/gdk-pixbuf.mo -share/locale/es/LC_MESSAGES/gettext-runtime.mo -share/locale/es/LC_MESSAGES/glib20.mo -share/locale/es/LC_MESSAGES/gtk20-properties.mo -share/locale/es/LC_MESSAGES/gtk20.mo -share/locale/fr -share/locale/fr/LC_MESSAGES -share/locale/fr/LC_MESSAGES/atk10.mo -share/locale/fr/LC_MESSAGES/gdk-pixbuf.mo -share/locale/fr/LC_MESSAGES/gettext-runtime.mo -share/locale/fr/LC_MESSAGES/glib20.mo -share/locale/fr/LC_MESSAGES/gtk20-properties.mo -share/locale/fr/LC_MESSAGES/gtk20.mo -share/locale/he -share/locale/he/LC_MESSAGES -share/locale/he/LC_MESSAGES/atk10.mo -share/locale/he/LC_MESSAGES/gdk-pixbuf.mo -share/locale/he/LC_MESSAGES/glib20.mo -share/locale/he/LC_MESSAGES/gtk20-properties.mo -share/locale/he/LC_MESSAGES/gtk20.mo -share/locale/hu -share/locale/hu/LC_MESSAGES -share/locale/hu/LC_MESSAGES/atk10.mo -share/locale/hu/LC_MESSAGES/gdk-pixbuf.mo -share/locale/hu/LC_MESSAGES/glib20.mo -share/locale/hu/LC_MESSAGES/gtk20-properties.mo -share/locale/hu/LC_MESSAGES/gtk20.mo -share/locale/it -share/locale/it/LC_MESSAGES -share/locale/it/LC_MESSAGES/atk10.mo -share/locale/it/LC_MESSAGES/gdk-pixbuf.mo -share/locale/it/LC_MESSAGES/gettext-runtime.mo -share/locale/it/LC_MESSAGES/glib20.mo -share/locale/it/LC_MESSAGES/gtk20-properties.mo -share/locale/it/LC_MESSAGES/gtk20.mo -share/locale/ja -share/locale/ja/LC_MESSAGES -share/locale/ja/LC_MESSAGES/atk10.mo -share/locale/ja/LC_MESSAGES/gdk-pixbuf.mo -share/locale/ja/LC_MESSAGES/gettext-runtime.mo -share/locale/ja/LC_MESSAGES/glib20.mo -share/locale/ja/LC_MESSAGES/gtk20-properties.mo -share/locale/ja/LC_MESSAGES/gtk20.mo -share/locale/nb -share/locale/nb/LC_MESSAGES -share/locale/nb/LC_MESSAGES/atk10.mo -share/locale/nb/LC_MESSAGES/gdk-pixbuf.mo -share/locale/nb/LC_MESSAGES/gettext-runtime.mo -share/locale/nb/LC_MESSAGES/glib20.mo -share/locale/nb/LC_MESSAGES/gtk20-properties.mo -share/locale/nb/LC_MESSAGES/gtk20.mo -share/locale/nl -share/locale/nl/LC_MESSAGES -share/locale/nl/LC_MESSAGES/atk10.mo -share/locale/nl/LC_MESSAGES/gdk-pixbuf.mo -share/locale/nl/LC_MESSAGES/gettext-runtime.mo -share/locale/nl/LC_MESSAGES/glib20.mo -share/locale/nl/LC_MESSAGES/gtk20-properties.mo -share/locale/nl/LC_MESSAGES/gtk20.mo -share/locale/pl -share/locale/pl/LC_MESSAGES -share/locale/pl/LC_MESSAGES/atk10.mo -share/locale/pl/LC_MESSAGES/gdk-pixbuf.mo -share/locale/pl/LC_MESSAGES/gettext-runtime.mo -share/locale/pl/LC_MESSAGES/glib20.mo -share/locale/pl/LC_MESSAGES/gtk20-properties.mo -share/locale/pl/LC_MESSAGES/gtk20.mo -share/locale/pt -share/locale/pt/LC_MESSAGES -share/locale/pt/LC_MESSAGES/atk10.mo -share/locale/pt/LC_MESSAGES/gdk-pixbuf.mo -share/locale/pt/LC_MESSAGES/gettext-runtime.mo -share/locale/pt/LC_MESSAGES/glib20.mo -share/locale/pt/LC_MESSAGES/gtk20-properties.mo -share/locale/pt/LC_MESSAGES/gtk20.mo -share/locale/pt_BR -share/locale/pt_BR/LC_MESSAGES -share/locale/pt_BR/LC_MESSAGES/atk10.mo -share/locale/pt_BR/LC_MESSAGES/gdk-pixbuf.mo -share/locale/pt_BR/LC_MESSAGES/gettext-runtime.mo -share/locale/pt_BR/LC_MESSAGES/glib20.mo -share/locale/pt_BR/LC_MESSAGES/gtk20-properties.mo -share/locale/pt_BR/LC_MESSAGES/gtk20.mo -share/locale/ru -share/locale/ru/LC_MESSAGES -share/locale/ru/LC_MESSAGES/atk10.mo -share/locale/ru/LC_MESSAGES/gdk-pixbuf.mo -share/locale/ru/LC_MESSAGES/gettext-runtime.mo -share/locale/ru/LC_MESSAGES/glib20.mo -share/locale/ru/LC_MESSAGES/gtk20-properties.mo -share/locale/ru/LC_MESSAGES/gtk20.mo -share/locale/sr -share/locale/sr/LC_MESSAGES -share/locale/sr/LC_MESSAGES/atk10.mo -share/locale/sr/LC_MESSAGES/gdk-pixbuf.mo -share/locale/sr/LC_MESSAGES/gettext-runtime.mo -share/locale/sr/LC_MESSAGES/glib20.mo -share/locale/sr/LC_MESSAGES/gtk20-properties.mo -share/locale/sr/LC_MESSAGES/gtk20.mo -share/locale/sv -share/locale/sv/LC_MESSAGES -share/locale/sv/LC_MESSAGES/atk10.mo -share/locale/sv/LC_MESSAGES/gdk-pixbuf.mo -share/locale/sv/LC_MESSAGES/gettext-runtime.mo -share/locale/sv/LC_MESSAGES/glib20.mo -share/locale/sv/LC_MESSAGES/gtk20-properties.mo -share/locale/sv/LC_MESSAGES/gtk20.mo -share/locale/tr/LC_MESSAGES/atk10.mo -share/locale/tr/LC_MESSAGES/gdk-pixbuf.mo -share/locale/tr/LC_MESSAGES/gettext-runtime.mo -share/locale/tr/LC_MESSAGES/glib20.mo -share/locale/tr/LC_MESSAGES/gtk20-properties.mo -share/locale/tr/LC_MESSAGES/gtk20.mo -share/locale/zh_CN -share/locale/zh_CN/LC_MESSAGES -share/locale/zh_CN/LC_MESSAGES/atk10.mo -share/locale/zh_CN/LC_MESSAGES/gdk-pixbuf.mo -share/locale/zh_CN/LC_MESSAGES/gettext-runtime.mo -share/locale/zh_CN/LC_MESSAGES/glib20.mo -share/locale/zh_CN/LC_MESSAGES/gtk20-properties.mo -share/locale/zh_CN/LC_MESSAGES/gtk20.mo -share/locale/zh_TW -share/locale/zh_TW/LC_MESSAGES -share/locale/zh_TW/LC_MESSAGES/atk10.mo -share/locale/zh_TW/LC_MESSAGES/gdk-pixbuf.mo -share/locale/zh_TW/LC_MESSAGES/gettext-runtime.mo -share/locale/zh_TW/LC_MESSAGES/glib20.mo -share/locale/zh_TW/LC_MESSAGES/gtk20-properties.mo -share/locale/zh_TW/LC_MESSAGES/gtk20.mo -share/themes -share/themes/Default -share/themes/Default/gtk-2.0-key -share/themes/Default/gtk-2.0-key/gtkrc -share/themes/Emacs -share/themes/Emacs/gtk-2.0-key -share/themes/Emacs/gtk-2.0-key/gtkrc -share/themes/MS-Windows -share/themes/MS-Windows/gtk-2.0 -share/themes/MS-Windows/gtk-2.0/gtkrc -share/themes/Raleigh -share/themes/Raleigh/gtk-2.0 -share/themes/Raleigh/gtk-2.0/gtkrc diff --git a/linphone-deps.filelist b/linphone-deps.filelist deleted file mode 100755 index 8a77ad29b..000000000 --- a/linphone-deps.filelist +++ /dev/null @@ -1,19 +0,0 @@ -./bin/avcodec-53.dll -./bin/libspeex-1.dll -./bin/libspeexdsp-1.dll -./bin/avutil-51.dll -./bin/libpolarssl-0.dll -./bin/libbellesip-0.dll -./bin/libantlr3c.dll -./bin/libogg-0.dll -./bin/libtheora-0.dll -./bin/libxml2-2.dll -./bin/swscale-2.dll -./bin/libsoup-2.4-1.dll -./bin/libgcrypt-11.dll -./bin/libgpg-error-0.dll -./bin/libgnutls-26.dll -./bin/libtasn1-3.dll -./bin/libsqlite3-0.dll -./bin/libopus-0.dll -./bin/libbzrtp-0.dll From bc113345dba5495453f3a5fd092e579bc15c976f Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 22 Sep 2017 09:14:19 +0200 Subject: [PATCH 0129/2215] feat(c-wrapper): remove CPP_CLASS parameter of L_DECLARE_C_CLONABLE_STRUCT_IMPL --- src/c-wrapper/api/c-address.cpp | 2 +- src/c-wrapper/api/c-call-params.cpp | 2 +- src/c-wrapper/api/c-event-log.cpp | 10 +++--- src/c-wrapper/c-wrapper.h | 30 ++++------------ src/c-wrapper/internal/c-tools.h | 54 ++++++++++++++++++++++++----- 5 files changed, 60 insertions(+), 38 deletions(-) diff --git a/src/c-wrapper/api/c-address.cpp b/src/c-wrapper/api/c-address.cpp index 703876a33..640ef6f03 100644 --- a/src/c-wrapper/api/c-address.cpp +++ b/src/c-wrapper/api/c-address.cpp @@ -21,7 +21,7 @@ // ============================================================================= -L_DECLARE_C_CLONABLE_STRUCT_IMPL(Address, Address); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(Address); using namespace std; diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index 9db253605..5a8fbc5d7 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -25,7 +25,7 @@ #define GET_MEDIA_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, MediaSessionParams) #define GET_MEDIA_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, MediaSessionParams) -L_DECLARE_C_CLONABLE_STRUCT_IMPL(MediaSessionParams, CallParams) +L_DECLARE_C_CLONABLE_STRUCT_IMPL(CallParams) using namespace std; diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 77e0c53d2..94b259618 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -28,11 +28,11 @@ // ============================================================================= -L_DECLARE_C_CLONABLE_STRUCT_IMPL(EventLog, EventLog); -L_DECLARE_C_CLONABLE_STRUCT_IMPL(CallEvent, CallEvent); -L_DECLARE_C_CLONABLE_STRUCT_IMPL(ConferenceEvent, ConferenceEvent); -L_DECLARE_C_CLONABLE_STRUCT_IMPL(ConferenceParticipantEvent, ConferenceParticipantEvent); -L_DECLARE_C_CLONABLE_STRUCT_IMPL(ChatMessageEvent, ChatMessageEvent); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(EventLog); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(CallEvent); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(ConferenceEvent); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(ConferenceParticipantEvent); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(ChatMessageEvent); using namespace std; diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index bc9e24bff..74fa5d92e 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -25,32 +25,16 @@ // ============================================================================= -LINPHONE_BEGIN_NAMESPACE - -template -struct CppTypeToCType { - enum { Defined = false }; -}; - -LINPHONE_END_NAMESPACE - -#define L_REGISTER_TYPE(CPP_TYPE, C_TYPE) \ - extern Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init (); \ - namespace LINPHONE_NAMESPACE { \ - class CPP_TYPE; \ - }; \ - template<> \ - struct LINPHONE_NAMESPACE::CppTypeToCType { \ - enum { Defined = true }; \ - typedef C_TYPE cType; \ - typedef LINPHONE_NAMESPACE::CPP_TYPE cppType; \ - }; - -// ============================================================================= - +L_REGISTER_TYPE(Address, Address); L_REGISTER_TYPE(Call, Call); +L_REGISTER_TYPE(CallEvent, CallEvent); L_REGISTER_TYPE(ChatMessage, ChatMessage); +L_REGISTER_TYPE(ChatMessageEvent, ChatMessageEvent); L_REGISTER_TYPE(ChatRoom, ChatRoom); +L_REGISTER_TYPE(ConferenceEvent, ConferenceEvent); +L_REGISTER_TYPE(ConferenceParticipantEvent, ConferenceParticipantEvent); +L_REGISTER_TYPE(EventLog, EventLog); +L_REGISTER_TYPE(MediaSessionParams, CallParams); L_REGISTER_TYPE(Participant, Participant); #endif // ifndef _C_WRAPPER_H_ diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 2af90255f..e05eebd79 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -33,6 +33,16 @@ LINPHONE_BEGIN_NAMESPACE +template +struct CppTypeToCType { + enum { defined = false }; +}; + +template +struct CTypeToCppType { + enum { defined = false }; +}; + class Wrapper { private: template @@ -287,6 +297,32 @@ LINPHONE_END_NAMESPACE // Public Wrapper API. // ============================================================================= +// ----------------------------------------------------------------------------- +// Register type. +// ----------------------------------------------------------------------------- + +#define L_REGISTER_TYPE(CPP_TYPE, C_TYPE) \ + extern Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init (); \ + namespace LINPHONE_NAMESPACE { \ + class CPP_TYPE; \ + }; \ + template<> \ + struct LINPHONE_NAMESPACE::CppTypeToCType { \ + enum { defined = true }; \ + typedef Linphone ## C_TYPE type; \ + }; \ + template<> \ + struct LINPHONE_NAMESPACE::CTypeToCppType { \ + enum { defined = true }; \ + typedef LINPHONE_NAMESPACE::CPP_TYPE type; \ + }; + +#define L_ASSERT_C_TYPE(C_TYPE) \ + static_assert(LINPHONE_NAMESPACE::CTypeToCppType::defined, "Type is not defined."); \ + +#define L_CPP_TYPE_OF_C_TYPE(C_TYPE) \ + LINPHONE_NAMESPACE::CTypeToCppType::type + // ----------------------------------------------------------------------------- // C object declaration. // ----------------------------------------------------------------------------- @@ -310,10 +346,11 @@ LINPHONE_END_NAMESPACE L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(CPP_CLASS, C_TYPE, L_INTERNAL_C_STRUCT_NO_XTOR, L_INTERNAL_C_STRUCT_NO_XTOR) // Declare clonable wrapped C object. -#define L_DECLARE_C_CLONABLE_STRUCT_IMPL(CPP_CLASS, C_TYPE, ...) \ +#define L_DECLARE_C_CLONABLE_STRUCT_IMPL(C_TYPE, ...) \ + L_ASSERT_C_TYPE(C_TYPE) \ struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ - LINPHONE_NAMESPACE::CPP_CLASS *cppPtr; \ + L_CPP_TYPE_OF_C_TYPE(C_TYPE) *cppPtr; \ __VA_ARGS__ \ }; \ BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_TYPE); \ @@ -325,14 +362,15 @@ LINPHONE_END_NAMESPACE } \ static void _linphone_ ## C_TYPE ## _clone(Linphone ## C_TYPE * dest, const Linphone ## C_TYPE * src) { \ L_ASSERT(src->cppPtr); \ - dest->cppPtr = new LINPHONE_NAMESPACE::CPP_CLASS(*src->cppPtr); \ + dest->cppPtr = new L_CPP_TYPE_OF_C_TYPE(C_TYPE)(*src->cppPtr); \ } \ BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## C_TYPE); \ - BELLE_SIP_INSTANCIATE_VPTR(Linphone ## C_TYPE, belle_sip_object_t, \ - _linphone_ ## C_TYPE ## _uninit, \ - _linphone_ ## C_TYPE ## _clone, \ - NULL, \ - FALSE \ + BELLE_SIP_INSTANCIATE_VPTR( \ + Linphone ## C_TYPE, belle_sip_object_t, \ + _linphone_ ## C_TYPE ## _uninit, \ + _linphone_ ## C_TYPE ## _clone, \ + NULL, \ + FALSE \ ); #define L_DECLARE_C_STRUCT_NEW_DEFAULT(C_TYPE, C_NAME) \ From 1b2e103da9ce1fe5e2455741700b62307634a94e Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 22 Sep 2017 09:21:23 +0200 Subject: [PATCH 0130/2215] feat(c-wrapper): remove CPP_CLASS parameter of L_DECLARE_C_STRUCT_IMPL --- src/c-wrapper/api/c-call.cpp | 2 +- src/c-wrapper/api/c-chat-message.cpp | 2 +- src/c-wrapper/api/c-chat-room.cpp | 2 +- src/c-wrapper/api/c-participant.cpp | 2 +- src/c-wrapper/internal/c-tools.h | 16 ++++++++-------- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index e257e1dbb..02fb800a7 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -36,7 +36,7 @@ using namespace std; static void _linphone_call_constructor (LinphoneCall *call); static void _linphone_call_destructor (LinphoneCall *call); -L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(Call, Call, +L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(Call, _linphone_call_constructor, _linphone_call_destructor, bctbx_list_t *callbacks; /* A list of LinphoneCallCbs object */ LinphoneCallCbs *currentCbs; /* The current LinphoneCallCbs object used to call a callback */ diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index afb079ff4..c1b157220 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -38,7 +38,7 @@ using namespace std; static void _linphone_chat_message_constructor (LinphoneChatMessage *msg); static void _linphone_chat_message_destructor (LinphoneChatMessage *msg); -L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(ChatMessage, ChatMessage, +L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(ChatMessage, _linphone_chat_message_constructor, _linphone_chat_message_destructor, LinphoneChatMessageCbs *cbs; LinphoneChatRoom* chat_room; diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index f2662f08c..ca7316fa5 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -38,7 +38,7 @@ static void _linphone_chat_room_constructor (LinphoneChatRoom *cr); static void _linphone_chat_room_destructor (LinphoneChatRoom *cr); L_DECLARE_C_STRUCT_IMPL_WITH_XTORS( - ChatRoom, ChatRoom, + ChatRoom, _linphone_chat_room_constructor, _linphone_chat_room_destructor, LinphoneChatRoomCbs *cbs; LinphoneAddress *peerAddressCache; diff --git a/src/c-wrapper/api/c-participant.cpp b/src/c-wrapper/api/c-participant.cpp index 05e0169ff..d79ee04d2 100644 --- a/src/c-wrapper/api/c-participant.cpp +++ b/src/c-wrapper/api/c-participant.cpp @@ -25,7 +25,7 @@ using namespace std; -L_DECLARE_C_STRUCT_IMPL(Participant, Participant, +L_DECLARE_C_STRUCT_IMPL(Participant, mutable LinphoneAddress *addressCache; ); diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index e05eebd79..051048316 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -271,11 +271,11 @@ LINPHONE_END_NAMESPACE #define L_INTERNAL_C_STRUCT_NO_XTOR(OBJECT) -#define L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(CPP_CLASS, C_TYPE, CONSTRUCTOR, DESTRUCTOR) \ +#define L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(C_TYPE, CONSTRUCTOR, DESTRUCTOR) \ BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_TYPE); \ Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init() { \ Linphone ## C_TYPE * object = belle_sip_object_new(Linphone ## C_TYPE); \ - new(&object->cppPtr) std::shared_ptr(); \ + new(&object->cppPtr) std::shared_ptr(); \ CONSTRUCTOR(object); \ return object; \ } \ @@ -328,22 +328,22 @@ LINPHONE_END_NAMESPACE // ----------------------------------------------------------------------------- // Declare wrapped C object with constructor/destructor. -#define L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(CPP_CLASS, C_TYPE, CONSTRUCTOR, DESTRUCTOR, ...) \ +#define L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(C_TYPE, CONSTRUCTOR, DESTRUCTOR, ...) \ struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ - std::shared_ptr cppPtr; \ + std::shared_ptr cppPtr; \ __VA_ARGS__ \ }; \ - L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(CPP_CLASS, C_TYPE, CONSTRUCTOR, DESTRUCTOR) + L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(C_TYPE, CONSTRUCTOR, DESTRUCTOR) // Declare wrapped C object. -#define L_DECLARE_C_STRUCT_IMPL(CPP_CLASS, C_TYPE, ...) \ +#define L_DECLARE_C_STRUCT_IMPL(C_TYPE, ...) \ struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ - std::shared_ptr cppPtr; \ + std::shared_ptr cppPtr; \ __VA_ARGS__ \ }; \ - L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(CPP_CLASS, C_TYPE, L_INTERNAL_C_STRUCT_NO_XTOR, L_INTERNAL_C_STRUCT_NO_XTOR) + L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(C_TYPE, L_INTERNAL_C_STRUCT_NO_XTOR, L_INTERNAL_C_STRUCT_NO_XTOR) // Declare clonable wrapped C object. #define L_DECLARE_C_CLONABLE_STRUCT_IMPL(C_TYPE, ...) \ From c33a8f2d78b8102ca57f6f3ac0a481fd13c239d0 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 22 Sep 2017 10:12:02 +0200 Subject: [PATCH 0131/2215] Fixed compilation due to namespace issue --- src/c-wrapper/internal/c-tools.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 051048316..6af4adde1 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -303,19 +303,19 @@ LINPHONE_END_NAMESPACE #define L_REGISTER_TYPE(CPP_TYPE, C_TYPE) \ extern Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init (); \ - namespace LINPHONE_NAMESPACE { \ - class CPP_TYPE; \ - }; \ + LINPHONE_BEGIN_NAMESPACE \ + class CPP_TYPE; \ template<> \ - struct LINPHONE_NAMESPACE::CppTypeToCType { \ + struct CppTypeToCType { \ enum { defined = true }; \ typedef Linphone ## C_TYPE type; \ }; \ template<> \ - struct LINPHONE_NAMESPACE::CTypeToCppType { \ + struct CTypeToCppType { \ enum { defined = true }; \ - typedef LINPHONE_NAMESPACE::CPP_TYPE type; \ - }; + typedef CPP_TYPE type; \ + }; \ + LINPHONE_END_NAMESPACE #define L_ASSERT_C_TYPE(C_TYPE) \ static_assert(LINPHONE_NAMESPACE::CTypeToCppType::defined, "Type is not defined."); \ From 3b08856dc0e85a36f2a31019c96350572ac74b22 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 22 Sep 2017 10:16:26 +0200 Subject: [PATCH 0132/2215] feat(c-wrapper): remove CPP_TYPE parameter of L_GET_CPP_PTR_FROM_C_STRUCT --- coreapi/chat.c | 6 +++--- coreapi/chat_file_transfer.c | 2 +- coreapi/linphonecore.c | 2 +- src/c-wrapper/api/c-call-params.cpp | 2 +- src/c-wrapper/api/c-call.cpp | 16 ++++++++-------- src/c-wrapper/api/c-chat-message.cpp | 8 ++++---- src/c-wrapper/api/c-chat-room.cpp | 12 ++++++------ src/c-wrapper/api/c-event-log.cpp | 15 +++++---------- src/c-wrapper/api/c-participant.cpp | 6 +++--- src/c-wrapper/internal/c-tools.h | 13 ++++++++----- src/chat/chat-room.cpp | 2 +- src/conference/session/call-session.cpp | 3 +-- src/conference/session/media-session.cpp | 2 +- 13 files changed, 43 insertions(+), 46 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 6d69e0788..4ea5462fb 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -80,7 +80,7 @@ static LinphoneChatRoom *_linphone_core_create_chat_room_from_url(LinphoneCore * } static bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from) { - LinphoneAddress *addr = linphone_address_new(L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom)->getPeerAddress().asString().c_str()); + LinphoneAddress *addr = linphone_address_new(L_GET_CPP_PTR_FROM_C_STRUCT(cr)->getPeerAddress().asString().c_str()); bool_t result = linphone_address_weak_equal(addr, from); linphone_address_unref(addr); return result; @@ -235,8 +235,8 @@ int linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, uint32_t character, LinphoneCall *call) { if (linphone_core_realtime_text_enabled(lc)) { std::shared_ptr rttcr = - std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom)); + std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr)); L_GET_PRIVATE(rttcr)->realtimeTextReceived(character, call); - //L_GET_PRIVATE(std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom, ChatRoom)))->realtimeTextReceived(character, call); + //L_GET_PRIVATE(std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr)))->realtimeTextReceived(character, call); } } diff --git a/coreapi/chat_file_transfer.c b/coreapi/chat_file_transfer.c index 8f8e86a01..49e1670cf 100644 --- a/coreapi/chat_file_transfer.c +++ b/coreapi/chat_file_transfer.c @@ -29,5 +29,5 @@ #include "chat/chat-room.h" LinphoneChatMessage *linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent *initial_content) { - return L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom)->createFileTransferMessage(initial_content); + return L_GET_CPP_PTR_FROM_C_STRUCT(cr)->createFileTransferMessage(initial_content); } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index d4fc6cb4d..14dfb26e3 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -6653,7 +6653,7 @@ void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m) { } void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params) { - L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams)->initDefault(lc); + L_GET_CPP_PTR_FROM_C_STRUCT(params)->initDefault(lc); } void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) { diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index 5a8fbc5d7..804055dcc 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -22,7 +22,7 @@ // ============================================================================= -#define GET_MEDIA_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, MediaSessionParams) +#define GET_MEDIA_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj) #define GET_MEDIA_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, MediaSessionParams) L_DECLARE_C_CLONABLE_STRUCT_IMPL(CallParams) diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 02fb800a7..6b0edacbd 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -28,7 +28,7 @@ // ============================================================================= -#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, Call) +#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj) #define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, Call) using namespace std; @@ -936,7 +936,7 @@ LinphoneStatus linphone_call_accept (LinphoneCall *call) { } LinphoneStatus linphone_call_accept_with_params (LinphoneCall *call, const LinphoneCallParams *params) { - return GET_CPP_PTR(call)->accept(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams) : nullptr); + return GET_CPP_PTR(call)->accept(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params) : nullptr); } LinphoneStatus linphone_call_accept_early_media (LinphoneCall* call) { @@ -944,11 +944,11 @@ LinphoneStatus linphone_call_accept_early_media (LinphoneCall* call) { } LinphoneStatus linphone_call_accept_early_media_with_params (LinphoneCall *call, const LinphoneCallParams *params) { - return GET_CPP_PTR(call)->acceptEarlyMedia(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams) : nullptr); + return GET_CPP_PTR(call)->acceptEarlyMedia(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params) : nullptr); } LinphoneStatus linphone_call_update (LinphoneCall *call, const LinphoneCallParams *params) { - return GET_CPP_PTR(call)->update(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams) : nullptr); + return GET_CPP_PTR(call)->update(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params) : nullptr); } LinphoneStatus linphone_call_defer_update (LinphoneCall *call) { @@ -971,7 +971,7 @@ LinphoneStatus linphone_call_defer_update (LinphoneCall *call) { } LinphoneStatus linphone_call_accept_update (LinphoneCall *call, const LinphoneCallParams *params) { - return GET_CPP_PTR(call)->acceptUpdate(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams) : nullptr); + return GET_CPP_PTR(call)->acceptUpdate(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params) : nullptr); } LinphoneStatus linphone_call_transfer (LinphoneCall *call, const char *refer_to) { @@ -1188,8 +1188,8 @@ void linphone_call_set_user_data (LinphoneCall *call, void *ud) { LinphoneCall *linphone_call_new_outgoing (LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg) { LinphoneCall *call = L_INIT(Call); L_SET_CPP_PTR_FROM_C_STRUCT(call, std::make_shared(call, lc, LinphoneCallOutgoing, - *L_GET_CPP_PTR_FROM_C_STRUCT(from, Address), *L_GET_CPP_PTR_FROM_C_STRUCT(to, Address), - cfg, nullptr, L_GET_CPP_PTR_FROM_C_STRUCT(params, MediaSessionParams))); + *L_GET_CPP_PTR_FROM_C_STRUCT(from), *L_GET_CPP_PTR_FROM_C_STRUCT(to), + cfg, nullptr, L_GET_CPP_PTR_FROM_C_STRUCT(params))); call->currentParamsCache = linphone_call_params_new_for_wrapper(); call->paramsCache = linphone_call_params_new_for_wrapper(); call->remoteParamsCache = linphone_call_params_new_for_wrapper(); @@ -1200,7 +1200,7 @@ LinphoneCall *linphone_call_new_outgoing (LinphoneCore *lc, const LinphoneAddres LinphoneCall *linphone_call_new_incoming (LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, SalOp *op) { LinphoneCall *call = L_INIT(Call); L_SET_CPP_PTR_FROM_C_STRUCT(call, std::make_shared(call, lc, LinphoneCallIncoming, - *L_GET_CPP_PTR_FROM_C_STRUCT(from, Address), *L_GET_CPP_PTR_FROM_C_STRUCT(to, Address), + *L_GET_CPP_PTR_FROM_C_STRUCT(from), *L_GET_CPP_PTR_FROM_C_STRUCT(to), nullptr, op, nullptr)); call->currentParamsCache = linphone_call_params_new_for_wrapper(); call->paramsCache = linphone_call_params_new_for_wrapper(); diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index c1b157220..022696139 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -30,7 +30,7 @@ // ============================================================================= -#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, ChatMessage, ChatMessage) +#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj) #define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, ChatMessage, ChatMessage) using namespace std; @@ -324,7 +324,7 @@ void _linphone_chat_message_resend(LinphoneChatMessage *msg, bool_t ref_msg) { cr = linphone_chat_message_get_chat_room(msg); if (ref_msg) linphone_chat_message_ref(msg); - L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom)->sendMessage(msg); + L_GET_CPP_PTR_FROM_C_STRUCT(cr)->sendMessage(msg); } void linphone_chat_message_resend(LinphoneChatMessage *msg) { @@ -465,7 +465,7 @@ void linphone_chat_message_send_display_notification(LinphoneChatMessage *cm) { LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) { std::shared_ptr rttcr = - std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr, ChatRoom)); + std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr)); LinphoneCall *call = rttcr->getCall(); LinphoneCore *lc = rttcr->getCore(); const uint32_t new_line = 0x2028; @@ -936,7 +936,7 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co linphone_chat_message_ref(msg); linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone); _release_http_request(msg); - L_GET_CPP_PTR_FROM_C_STRUCT(msg->chat_room, ChatRoom)->sendMessage(msg); + L_GET_CPP_PTR_FROM_C_STRUCT(msg->chat_room)->sendMessage(msg); file_upload_end_background_task(msg); linphone_chat_message_unref(msg); } else { diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index ca7316fa5..e923279a6 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -29,7 +29,7 @@ // ============================================================================= -#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj, ChatRoom) +#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj) #define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, ChatRoom) using namespace std; @@ -211,7 +211,7 @@ LinphoneChatRoomState linphone_chat_room_get_state (const LinphoneChatRoom *cr) LinphoneParticipant *linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr) { return L_GET_C_BACK_PTR(GET_CPP_PTR(cr)->addParticipant( - *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address), nullptr, false), + *L_GET_CPP_PTR_FROM_C_STRUCT(addr), nullptr, false), Participant); } @@ -237,7 +237,7 @@ bctbx_list_t *linphone_chat_room_get_participants (const LinphoneChatRoom *cr) { } void linphone_chat_room_remove_participant (LinphoneChatRoom *cr, LinphoneParticipant *participant) { - GET_CPP_PTR(cr)->removeParticipant(L_GET_CPP_PTR_FROM_C_STRUCT(participant, Participant)); + GET_CPP_PTR(cr)->removeParticipant(L_GET_CPP_PTR_FROM_C_STRUCT(participant)); } void linphone_chat_room_remove_participants (LinphoneChatRoom *cr, const bctbx_list_t *participants) { @@ -272,9 +272,9 @@ void linphone_chat_room_set_user_data (LinphoneChatRoom *cr, void *ud) { LinphoneChatRoom *linphone_chat_room_new (LinphoneCore *core, const LinphoneAddress *addr) { LinphoneChatRoom *cr = _linphone_ChatRoom_init(); if (linphone_core_realtime_text_enabled(core)) - L_SET_CPP_PTR_FROM_C_STRUCT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address))); + L_SET_CPP_PTR_FROM_C_STRUCT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_STRUCT(addr))); else - L_SET_CPP_PTR_FROM_C_STRUCT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address))); + L_SET_CPP_PTR_FROM_C_STRUCT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_STRUCT(addr))); linphone_core_notify_chat_room_instantiated(core, cr); L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Instantiated); L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Created); @@ -290,7 +290,7 @@ LinphoneChatRoom *linphone_client_group_chat_room_new (LinphoneCore *core, const linphone_address_unref(factoryAddr); std::string from; if (proxy) - from = L_GET_CPP_PTR_FROM_C_STRUCT(linphone_proxy_config_get_identity_address(proxy), Address)->asString(); + from = L_GET_CPP_PTR_FROM_C_STRUCT(linphone_proxy_config_get_identity_address(proxy))->asString(); if (from.empty()) from = linphone_core_get_primary_contact(core); LinphonePrivate::Address me(from); diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 94b259618..086487144 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -53,7 +53,7 @@ LinphoneEventLog *linphone_event_log_ref (LinphoneEventLog *event_log) { LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *event_log) { return static_cast( - L_GET_CPP_PTR_FROM_C_STRUCT(event_log, EventLog)->getType() + L_GET_CPP_PTR_FROM_C_STRUCT(event_log)->getType() ); } @@ -67,7 +67,7 @@ LinphoneCallEvent *linphone_call_event_new (LinphoneEventLogType type, LinphoneC call_event, new LINPHONE_NAMESPACE::CallEvent( static_cast(type), - L_GET_CPP_PTR_FROM_C_STRUCT(call, Call) + L_GET_CPP_PTR_FROM_C_STRUCT(call) ) ); return call_event; @@ -75,10 +75,7 @@ LinphoneCallEvent *linphone_call_event_new (LinphoneEventLogType type, LinphoneC LinphoneCall *linphone_call_event_get_call (const LinphoneCallEvent *call_event) { return L_GET_C_BACK_PTR( - L_GET_CPP_PTR_FROM_C_STRUCT( - call_event, CallEvent - )->getCall(), - Call + L_GET_CPP_PTR_FROM_C_STRUCT(call_event)->getCall(), Call ); } @@ -128,7 +125,7 @@ LinphoneChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage * L_SET_CPP_PTR_FROM_C_STRUCT( chat_message_event, new LINPHONE_NAMESPACE::ChatMessageEvent( - L_GET_CPP_PTR_FROM_C_STRUCT(chat_message, ChatMessage) + L_GET_CPP_PTR_FROM_C_STRUCT(chat_message) ) ); return chat_message_event; @@ -136,9 +133,7 @@ LinphoneChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage * LinphoneChatMessage *linphone_chat_message_event_get_chat_message (const LinphoneChatMessageEvent *chat_message_event) { return L_GET_C_BACK_PTR( - L_GET_CPP_PTR_FROM_C_STRUCT( - chat_message_event, ChatMessageEvent - )->getChatMessage(), + L_GET_CPP_PTR_FROM_C_STRUCT(chat_message_event)->getChatMessage(), ChatMessage ); } diff --git a/src/c-wrapper/api/c-participant.cpp b/src/c-wrapper/api/c-participant.cpp index d79ee04d2..69d07deaf 100644 --- a/src/c-wrapper/api/c-participant.cpp +++ b/src/c-wrapper/api/c-participant.cpp @@ -47,7 +47,7 @@ void linphone_participant_set_user_data(LinphoneParticipant *participant, void * } const LinphoneAddress *linphone_participant_get_address (const LinphoneParticipant *participant) { - LinphonePrivate::Address addr = L_GET_CPP_PTR_FROM_C_STRUCT(participant, Participant)->getAddress(); + LinphonePrivate::Address addr = L_GET_CPP_PTR_FROM_C_STRUCT(participant)->getAddress(); if (participant->addressCache) linphone_address_unref(participant->addressCache); participant->addressCache = linphone_address_new(addr.asString().c_str()); @@ -55,9 +55,9 @@ const LinphoneAddress *linphone_participant_get_address (const LinphoneParticipa } bool_t linphone_participant_is_admin (const LinphoneParticipant *participant) { - return L_GET_CPP_PTR_FROM_C_STRUCT(participant, Participant)->isAdmin(); + return L_GET_CPP_PTR_FROM_C_STRUCT(participant)->isAdmin(); } void linphone_participant_set_admin (LinphoneParticipant *participant, bool_t value) { - L_GET_CPP_PTR_FROM_C_STRUCT(participant, Participant)->setAdmin(value); + L_GET_CPP_PTR_FROM_C_STRUCT(participant)->setAdmin(value); } diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 6af4adde1..6062b71fc 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -323,6 +323,9 @@ LINPHONE_END_NAMESPACE #define L_CPP_TYPE_OF_C_TYPE(C_TYPE) \ LINPHONE_NAMESPACE::CTypeToCppType::type +#define L_CPP_TYPE_OF_C_OBJECT(C_OBJECT) \ + LINPHONE_NAMESPACE::CTypeToCppType::type>::type>::type + // ----------------------------------------------------------------------------- // C object declaration. // ----------------------------------------------------------------------------- @@ -392,9 +395,9 @@ LINPHONE_END_NAMESPACE #define L_INIT(C_TYPE) _linphone_ ## C_TYPE ## _init () // Get the cpp-ptr of a wrapped C object. -#define L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE) \ +#define L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT) \ LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC< \ - LINPHONE_NAMESPACE::CPP_TYPE, \ + L_CPP_TYPE_OF_C_OBJECT(OBJECT), \ std::remove_pointer::type \ >(OBJECT) @@ -409,7 +412,7 @@ LINPHONE_END_NAMESPACE // Get the private data of a shared or simple cpp-ptr of a wrapped C object. #define L_GET_PRIVATE_FROM_C_STRUCT(OBJECT, CPP_TYPE) \ L_GET_PRIVATE(LINPHONE_NAMESPACE::Wrapper::getCppPtr( \ - L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE) \ + L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT) \ )) // Get the wrapped C object of a C++ object. @@ -421,11 +424,11 @@ LINPHONE_END_NAMESPACE // Get/set user data on a wrapped C object. #define L_GET_USER_DATA_FROM_C_STRUCT(OBJECT, CPP_TYPE) \ LINPHONE_NAMESPACE::Wrapper::getUserData( \ - L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE) \ + L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT) \ ) #define L_SET_USER_DATA_FROM_C_STRUCT(OBJECT, VALUE, CPP_TYPE) \ LINPHONE_NAMESPACE::Wrapper::setUserData( \ - L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_TYPE), \ + L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT), \ VALUE \ ) diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index b34123947..52b19cdfc 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -828,7 +828,7 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { if (identity.empty()) { LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(d->core, peer); if (proxy) { - identity = L_GET_CPP_PTR_FROM_C_STRUCT(linphone_proxy_config_get_identity_address(proxy), Address)->asString(); + identity = L_GET_CPP_PTR_FROM_C_STRUCT(linphone_proxy_config_get_identity_address(proxy))->asString(); } else { identity = linphone_core_get_primary_contact(d->core); } diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 4e0bf9085..9d44061a6 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -963,8 +963,7 @@ LinphoneReason CallSession::getReason () const { const Address& CallSession::getRemoteAddress () const { L_D(const CallSession); return *L_GET_CPP_PTR_FROM_C_STRUCT((d->direction == LinphoneCallIncoming) - ? linphone_call_log_get_from(d->log) : linphone_call_log_get_to(d->log), - Address); + ? linphone_call_log_get_from(d->log) : linphone_call_log_get_to(d->log)); } string CallSession::getRemoteAddressAsString () const { diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 75eaddcc2..2d837f700 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -1221,7 +1221,7 @@ void MediaSessionPrivate::makeLocalMediaDescription () { /* Re-check local ip address each time we make a new offer, because it may change in case of network reconnection */ { LinphoneAddress *address = (direction == LinphoneCallOutgoing ? log->to : log->from); - getLocalIp(*L_GET_CPP_PTR_FROM_C_STRUCT(address, Address)); + getLocalIp(*L_GET_CPP_PTR_FROM_C_STRUCT(address)); } strncpy(md->addr, mediaLocalIp.c_str(), sizeof(md->addr)); From c73614b852c3c583a3b95d0ebf5f4022ff25e273 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 22 Sep 2017 10:25:32 +0200 Subject: [PATCH 0133/2215] Fix some memory leaks. --- src/conference/remote-conference.cpp | 4 ++++ src/conference/remote-conference.h | 2 +- src/conference/session/media-session.cpp | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index 0136a29cd..49ab55fac 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -30,6 +30,10 @@ RemoteConference::RemoteConference (LinphoneCore *core, const Address &myAddress eventHandler = new RemoteConferenceEventHandler(core, this); } +RemoteConference::~RemoteConference () { + delete eventHandler; +} + // ----------------------------------------------------------------------------- shared_ptr RemoteConference::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index ddafca6f1..3a33bb98f 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -29,7 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class RemoteConference : public Conference, public ConferenceListener { public: RemoteConference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); - virtual ~RemoteConference() = default; + virtual ~RemoteConference(); protected: std::shared_ptr focus = nullptr; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 2d837f700..0d7ccaab4 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -72,11 +72,11 @@ MediaSessionPrivate::MediaSessionPrivate (const Conference &conference, const Ca params = new MediaSessionParams(*(reinterpret_cast(csp))); currentParams = new MediaSessionParams(); - audioStats = linphone_call_stats_ref(_linphone_call_stats_new()); + audioStats = _linphone_call_stats_new(); initStats(audioStats, LinphoneStreamTypeAudio); - videoStats = linphone_call_stats_ref(_linphone_call_stats_new()); + videoStats = _linphone_call_stats_new(); initStats(videoStats, LinphoneStreamTypeVideo); - textStats = linphone_call_stats_ref(_linphone_call_stats_new()); + textStats = _linphone_call_stats_new(); initStats(textStats, LinphoneStreamTypeText); int minPort, maxPort; From 78646be7bc28c0ac9c10c02760c8b5d177ad1885 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 22 Sep 2017 10:27:50 +0200 Subject: [PATCH 0134/2215] feat(c-wrapper): rename C_STRUCT to C_OBJECT --- coreapi/callbacks.c | 2 +- coreapi/chat.c | 8 +++--- coreapi/chat_file_transfer.c | 2 +- coreapi/linphonecore.c | 10 +++---- coreapi/proxy.c | 6 ++-- coreapi/quality_reporting.c | 2 +- src/c-wrapper/api/c-call-params.cpp | 10 +++---- src/c-wrapper/api/c-call.cpp | 36 ++++++++++++------------ src/c-wrapper/api/c-chat-message.cpp | 20 ++++++------- src/c-wrapper/api/c-chat-room.cpp | 30 ++++++++++---------- src/c-wrapper/api/c-event-log.cpp | 16 +++++------ src/c-wrapper/api/c-participant.cpp | 12 ++++---- src/c-wrapper/internal/c-tools.h | 30 ++++++++++---------- src/chat/chat-room.cpp | 2 +- src/conference/session/call-session.cpp | 6 ++-- src/conference/session/media-session.cpp | 8 +++--- 16 files changed, 100 insertions(+), 100 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 63fdaaf94..775ed81d0 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -169,7 +169,7 @@ static void call_received(SalOp *h) { LinphoneCall *call = linphone_call_new_incoming(lc, fromAddr, toAddr, h); linphone_address_unref(fromAddr); linphone_address_unref(toAddr); - L_GET_PRIVATE_FROM_C_STRUCT(call, Call)->startIncomingNotification(); + L_GET_PRIVATE_FROM_C_OBJECT(call, Call)->startIncomingNotification(); } static void call_rejected(SalOp *h){ diff --git a/coreapi/chat.c b/coreapi/chat.c index 4ea5462fb..d3155a01f 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -80,7 +80,7 @@ static LinphoneChatRoom *_linphone_core_create_chat_room_from_url(LinphoneCore * } static bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from) { - LinphoneAddress *addr = linphone_address_new(L_GET_CPP_PTR_FROM_C_STRUCT(cr)->getPeerAddress().asString().c_str()); + LinphoneAddress *addr = linphone_address_new(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getPeerAddress().asString().c_str()); bool_t result = linphone_address_weak_equal(addr, from); linphone_address_unref(addr); return result; @@ -225,7 +225,7 @@ int linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage LinphoneAddress *addr = linphone_address_new(sal_msg->from); linphone_address_clean(addr); LinphoneChatRoom *cr = linphone_core_get_chat_room(lc, addr); - LinphoneReason reason = L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom)->messageReceived(op, sal_msg); + LinphoneReason reason = L_GET_PRIVATE_FROM_C_OBJECT(cr, ChatRoom)->messageReceived(op, sal_msg); linphone_address_unref(addr); return reason; } @@ -235,8 +235,8 @@ int linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, uint32_t character, LinphoneCall *call) { if (linphone_core_realtime_text_enabled(lc)) { std::shared_ptr rttcr = - std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr)); + std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); L_GET_PRIVATE(rttcr)->realtimeTextReceived(character, call); - //L_GET_PRIVATE(std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr)))->realtimeTextReceived(character, call); + //L_GET_PRIVATE(std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr)))->realtimeTextReceived(character, call); } } diff --git a/coreapi/chat_file_transfer.c b/coreapi/chat_file_transfer.c index 49e1670cf..79f22ce47 100644 --- a/coreapi/chat_file_transfer.c +++ b/coreapi/chat_file_transfer.c @@ -29,5 +29,5 @@ #include "chat/chat-room.h" LinphoneChatMessage *linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent *initial_content) { - return L_GET_CPP_PTR_FROM_C_STRUCT(cr)->createFileTransferMessage(initial_content); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createFileTransferMessage(initial_content); } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 14dfb26e3..a1ccd0735 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3205,7 +3205,7 @@ void linphone_core_iterate(LinphoneCore *lc){ /* Get immediately a reference to next one in case the one we are going to examine is destroyed * and removed during linphone_call_start_invite() */ calls = bctbx_list_next(calls); - L_GET_PRIVATE_FROM_C_STRUCT(call, Call)->iterate(current_real_time, one_second_elapsed); + L_GET_PRIVATE_FROM_C_OBJECT(call, Call)->iterate(current_real_time, one_second_elapsed); } if (linphone_core_video_preview_enabled(lc)){ @@ -3341,7 +3341,7 @@ static bctbx_list_t *make_routes_for_proxy(LinphoneProxyConfig *proxy, const Lin ret=bctbx_list_append(ret,sal_address_new(local_route)); } if (srv_route){ - ret=bctbx_list_append(ret,sal_address_clone(L_GET_PRIVATE_FROM_C_STRUCT(srv_route, Address)->getInternalAddress())); + ret=bctbx_list_append(ret,sal_address_clone(L_GET_PRIVATE_FROM_C_OBJECT(srv_route, Address)->getInternalAddress())); } if (ret==NULL){ /*if the proxy address matches the domain part of the destination, then use the same transport @@ -3530,9 +3530,9 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const if (linphone_call_params_get_local_conference_mode(params) == FALSE) #endif lc->current_call=call; - bool defer = L_GET_PRIVATE_FROM_C_STRUCT(call, Call)->initiateOutgoing(); + bool defer = L_GET_PRIVATE_FROM_C_OBJECT(call, Call)->initiateOutgoing(); if (!defer) { - if (L_GET_PRIVATE_FROM_C_STRUCT(call, Call)->startInvite(nullptr) != 0) { + if (L_GET_PRIVATE_FROM_C_OBJECT(call, Call)->startInvite(nullptr) != 0) { /* The call has already gone to error and released state, so do not return it */ call = nullptr; } @@ -6653,7 +6653,7 @@ void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m) { } void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params) { - L_GET_CPP_PTR_FROM_C_STRUCT(params)->initDefault(lc); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->initDefault(lc); } void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) { diff --git a/coreapi/proxy.c b/coreapi/proxy.c index e8cd9d6b7..41af4af34 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -492,7 +492,7 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *cfg){ linphone_configure_op(cfg->lc, cfg->op, cfg->identity_address, cfg->sent_headers, FALSE); if ((contact=guess_contact_for_register(cfg))) { - sal_op_set_contact_address(cfg->op, L_GET_PRIVATE_FROM_C_STRUCT(contact, Address)->getInternalAddress()); + sal_op_set_contact_address(cfg->op, L_GET_PRIVATE_FROM_C_OBJECT(contact, Address)->getInternalAddress()); linphone_address_unref(contact); } @@ -503,7 +503,7 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *cfg){ proxy_string, cfg->reg_identity, cfg->expires, - cfg->pending_contact ? L_GET_PRIVATE_FROM_C_STRUCT(cfg->pending_contact, Address)->getInternalAddress() : NULL + cfg->pending_contact ? L_GET_PRIVATE_FROM_C_OBJECT(cfg->pending_contact, Address)->getInternalAddress() : NULL )==0) { if (cfg->pending_contact) { linphone_address_unref(cfg->pending_contact); @@ -1364,7 +1364,7 @@ const char* linphone_proxy_config_get_transport(const LinphoneProxyConfig *cfg) bool_t destroy_route_addr = FALSE; if (linphone_proxy_config_get_service_route(cfg)) { - route_addr = L_GET_PRIVATE_FROM_C_STRUCT(linphone_proxy_config_get_service_route(cfg), Address)->getInternalAddress(); + route_addr = L_GET_PRIVATE_FROM_C_OBJECT(linphone_proxy_config_get_service_route(cfg), Address)->getInternalAddress(); } else if (linphone_proxy_config_get_route(cfg)) { addr=linphone_proxy_config_get_route(cfg); } else if(linphone_proxy_config_get_addr(cfg)) { diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 44e0b1d2d..5ef13eed3 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -380,7 +380,7 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report, * (port, transport, maddr), then it is sent directly. * Otherwise it is routed as any LinphoneEvent publish, following proxy config policy. **/ - salAddress = L_GET_PRIVATE_FROM_C_STRUCT(request_uri, Address)->getInternalAddress(); + salAddress = L_GET_PRIVATE_FROM_C_OBJECT(request_uri, Address)->getInternalAddress(); if (sal_address_has_uri_param(salAddress, "transport") || sal_address_has_uri_param(salAddress, "maddr") || linphone_address_get_port(request_uri) != 0) { diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index 804055dcc..bca549c5f 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -22,8 +22,8 @@ // ============================================================================= -#define GET_MEDIA_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj) -#define GET_MEDIA_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, MediaSessionParams) +#define GET_MEDIA_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_OBJECT(obj) +#define GET_MEDIA_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_OBJECT(obj, MediaSessionParams) L_DECLARE_C_CLONABLE_STRUCT_IMPL(CallParams) @@ -485,11 +485,11 @@ void linphone_call_params_set_no_user_consent (LinphoneCallParams *params, bool_ // ============================================================================= void *linphone_call_params_get_user_data (const LinphoneCallParams *cp) { - return L_GET_USER_DATA_FROM_C_STRUCT(cp, MediaSessionParams); + return L_GET_USER_DATA_FROM_C_OBJECT(cp, MediaSessionParams); } void linphone_call_params_set_user_data (LinphoneCallParams *cp, void *ud) { - L_SET_USER_DATA_FROM_C_STRUCT(cp, ud, MediaSessionParams); + L_SET_USER_DATA_FROM_C_OBJECT(cp, ud, MediaSessionParams); } LinphoneCallParams *linphone_call_params_ref (LinphoneCallParams *cp) { @@ -507,7 +507,7 @@ void linphone_call_params_unref (LinphoneCallParams *cp) { LinphoneCallParams *linphone_call_params_new (LinphoneCore *core) { LinphoneCallParams *params = _linphone_CallParams_init(); - L_SET_CPP_PTR_FROM_C_STRUCT(params, new LinphonePrivate::MediaSessionParams()); + L_SET_CPP_PTR_FROM_C_OBJECT(params, new LinphonePrivate::MediaSessionParams()); GET_MEDIA_CPP_PTR(params)->initDefault(core); return params; } diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 6b0edacbd..bfeae22d7 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -28,15 +28,15 @@ // ============================================================================= -#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj) -#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, Call) +#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_OBJECT(obj) +#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_OBJECT(obj, Call) using namespace std; static void _linphone_call_constructor (LinphoneCall *call); static void _linphone_call_destructor (LinphoneCall *call); -L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(Call, +L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(Call, _linphone_call_constructor, _linphone_call_destructor, bctbx_list_t *callbacks; /* A list of LinphoneCallCbs object */ LinphoneCallCbs *currentCbs; /* The current LinphoneCallCbs object used to call a callback */ @@ -601,7 +601,7 @@ bool_t linphone_call_asked_to_autoanswer (LinphoneCall *call) { } const LinphoneAddress *linphone_call_get_remote_address (const LinphoneCall *call) { - L_SET_CPP_PTR_FROM_C_STRUCT(call->remoteAddressCache, &GET_CPP_PTR(call)->getRemoteAddress()); + L_SET_CPP_PTR_FROM_C_OBJECT(call->remoteAddressCache, &GET_CPP_PTR(call)->getRemoteAddress()); return call->remoteAddressCache; } @@ -690,7 +690,7 @@ int linphone_call_get_duration (const LinphoneCall *call) { } const LinphoneCallParams *linphone_call_get_current_params(LinphoneCall *call) { - L_SET_CPP_PTR_FROM_C_STRUCT(call->currentParamsCache, GET_CPP_PTR(call)->getCurrentParams()); + L_SET_CPP_PTR_FROM_C_OBJECT(call->currentParamsCache, GET_CPP_PTR(call)->getCurrentParams()); return call->currentParamsCache; } @@ -698,7 +698,7 @@ const LinphoneCallParams *linphone_call_get_remote_params(LinphoneCall *call) { const LinphonePrivate::MediaSessionParams *remoteParams = GET_CPP_PTR(call)->getRemoteParams(); if (!remoteParams) return nullptr; - L_SET_CPP_PTR_FROM_C_STRUCT(call->remoteParamsCache, remoteParams); + L_SET_CPP_PTR_FROM_C_OBJECT(call->remoteParamsCache, remoteParams); return call->remoteParamsCache; } @@ -936,7 +936,7 @@ LinphoneStatus linphone_call_accept (LinphoneCall *call) { } LinphoneStatus linphone_call_accept_with_params (LinphoneCall *call, const LinphoneCallParams *params) { - return GET_CPP_PTR(call)->accept(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params) : nullptr); + return GET_CPP_PTR(call)->accept(params ? L_GET_CPP_PTR_FROM_C_OBJECT(params) : nullptr); } LinphoneStatus linphone_call_accept_early_media (LinphoneCall* call) { @@ -944,11 +944,11 @@ LinphoneStatus linphone_call_accept_early_media (LinphoneCall* call) { } LinphoneStatus linphone_call_accept_early_media_with_params (LinphoneCall *call, const LinphoneCallParams *params) { - return GET_CPP_PTR(call)->acceptEarlyMedia(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params) : nullptr); + return GET_CPP_PTR(call)->acceptEarlyMedia(params ? L_GET_CPP_PTR_FROM_C_OBJECT(params) : nullptr); } LinphoneStatus linphone_call_update (LinphoneCall *call, const LinphoneCallParams *params) { - return GET_CPP_PTR(call)->update(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params) : nullptr); + return GET_CPP_PTR(call)->update(params ? L_GET_CPP_PTR_FROM_C_OBJECT(params) : nullptr); } LinphoneStatus linphone_call_defer_update (LinphoneCall *call) { @@ -971,7 +971,7 @@ LinphoneStatus linphone_call_defer_update (LinphoneCall *call) { } LinphoneStatus linphone_call_accept_update (LinphoneCall *call, const LinphoneCallParams *params) { - return GET_CPP_PTR(call)->acceptUpdate(params ? L_GET_CPP_PTR_FROM_C_STRUCT(params) : nullptr); + return GET_CPP_PTR(call)->acceptUpdate(params ? L_GET_CPP_PTR_FROM_C_OBJECT(params) : nullptr); } LinphoneStatus linphone_call_transfer (LinphoneCall *call, const char *refer_to) { @@ -1156,7 +1156,7 @@ void linphone_call_set_params (LinphoneCall *call, const LinphoneCallParams *par } const LinphoneCallParams *linphone_call_get_params (LinphoneCall *call) { - L_SET_CPP_PTR_FROM_C_STRUCT(call->paramsCache, GET_CPP_PTR(call)->getParams()); + L_SET_CPP_PTR_FROM_C_OBJECT(call->paramsCache, GET_CPP_PTR(call)->getParams()); return call->paramsCache; } @@ -1174,11 +1174,11 @@ void linphone_call_unref (LinphoneCall *call) { } void *linphone_call_get_user_data (const LinphoneCall *call) { - return L_GET_USER_DATA_FROM_C_STRUCT(call, Call); + return L_GET_USER_DATA_FROM_C_OBJECT(call, Call); } void linphone_call_set_user_data (LinphoneCall *call, void *ud) { - L_SET_USER_DATA_FROM_C_STRUCT(call, ud, Call); + L_SET_USER_DATA_FROM_C_OBJECT(call, ud, Call); } // ============================================================================= @@ -1187,9 +1187,9 @@ void linphone_call_set_user_data (LinphoneCall *call, void *ud) { LinphoneCall *linphone_call_new_outgoing (LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg) { LinphoneCall *call = L_INIT(Call); - L_SET_CPP_PTR_FROM_C_STRUCT(call, std::make_shared(call, lc, LinphoneCallOutgoing, - *L_GET_CPP_PTR_FROM_C_STRUCT(from), *L_GET_CPP_PTR_FROM_C_STRUCT(to), - cfg, nullptr, L_GET_CPP_PTR_FROM_C_STRUCT(params))); + L_SET_CPP_PTR_FROM_C_OBJECT(call, std::make_shared(call, lc, LinphoneCallOutgoing, + *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), + cfg, nullptr, L_GET_CPP_PTR_FROM_C_OBJECT(params))); call->currentParamsCache = linphone_call_params_new_for_wrapper(); call->paramsCache = linphone_call_params_new_for_wrapper(); call->remoteParamsCache = linphone_call_params_new_for_wrapper(); @@ -1199,8 +1199,8 @@ LinphoneCall *linphone_call_new_outgoing (LinphoneCore *lc, const LinphoneAddres LinphoneCall *linphone_call_new_incoming (LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, SalOp *op) { LinphoneCall *call = L_INIT(Call); - L_SET_CPP_PTR_FROM_C_STRUCT(call, std::make_shared(call, lc, LinphoneCallIncoming, - *L_GET_CPP_PTR_FROM_C_STRUCT(from), *L_GET_CPP_PTR_FROM_C_STRUCT(to), + L_SET_CPP_PTR_FROM_C_OBJECT(call, std::make_shared(call, lc, LinphoneCallIncoming, + *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), nullptr, op, nullptr)); call->currentParamsCache = linphone_call_params_new_for_wrapper(); call->paramsCache = linphone_call_params_new_for_wrapper(); diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 022696139..dd58ca4df 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -30,15 +30,15 @@ // ============================================================================= -#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj) -#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, ChatMessage, ChatMessage) +#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_OBJECT(obj) +#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_OBJECT(obj, ChatMessage, ChatMessage) using namespace std; static void _linphone_chat_message_constructor (LinphoneChatMessage *msg); static void _linphone_chat_message_destructor (LinphoneChatMessage *msg); -L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(ChatMessage, +L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(ChatMessage, _linphone_chat_message_constructor, _linphone_chat_message_destructor, LinphoneChatMessageCbs *cbs; LinphoneChatRoom* chat_room; @@ -92,11 +92,11 @@ void linphone_chat_message_unref (LinphoneChatMessage *msg) { } void * linphone_chat_message_get_user_data (const LinphoneChatMessage *msg) { - return L_GET_USER_DATA_FROM_C_STRUCT(msg, ChatMessage); + return L_GET_USER_DATA_FROM_C_OBJECT(msg, ChatMessage); } void linphone_chat_message_set_user_data (LinphoneChatMessage *msg, void *ud) { - L_SET_USER_DATA_FROM_C_STRUCT(msg, ud, ChatMessage); + L_SET_USER_DATA_FROM_C_OBJECT(msg, ud, ChatMessage); } @@ -309,7 +309,7 @@ void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMe linphone_chat_message_store_state(msg); if (msg->state == LinphoneChatMessageStateDelivered || msg->state == LinphoneChatMessageStateNotDelivered) { - L_GET_PRIVATE_FROM_C_STRUCT(msg->chat_room, ChatRoom)->moveTransientMessageToWeakMessages(msg); + L_GET_PRIVATE_FROM_C_OBJECT(msg->chat_room, ChatRoom)->moveTransientMessageToWeakMessages(msg); } } @@ -324,7 +324,7 @@ void _linphone_chat_message_resend(LinphoneChatMessage *msg, bool_t ref_msg) { cr = linphone_chat_message_get_chat_room(msg); if (ref_msg) linphone_chat_message_ref(msg); - L_GET_CPP_PTR_FROM_C_STRUCT(cr)->sendMessage(msg); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(msg); } void linphone_chat_message_resend(LinphoneChatMessage *msg) { @@ -440,7 +440,7 @@ static char *linphone_chat_message_create_imdn_xml(LinphoneChatMessage *cm, Imdn void linphone_chat_message_send_imdn(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason) { char *content = linphone_chat_message_create_imdn_xml(cm, imdn_type, reason); if (content) { - L_GET_PRIVATE_FROM_C_STRUCT(linphone_chat_message_get_chat_room(cm), ChatRoom)->sendImdn(content, reason); + L_GET_PRIVATE_FROM_C_OBJECT(linphone_chat_message_get_chat_room(cm), ChatRoom)->sendImdn(content, reason); ms_free(content); } } @@ -465,7 +465,7 @@ void linphone_chat_message_send_display_notification(LinphoneChatMessage *cm) { LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) { std::shared_ptr rttcr = - std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_STRUCT(cr)); + std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); LinphoneCall *call = rttcr->getCall(); LinphoneCore *lc = rttcr->getCore(); const uint32_t new_line = 0x2028; @@ -936,7 +936,7 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co linphone_chat_message_ref(msg); linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone); _release_http_request(msg); - L_GET_CPP_PTR_FROM_C_STRUCT(msg->chat_room)->sendMessage(msg); + L_GET_CPP_PTR_FROM_C_OBJECT(msg->chat_room)->sendMessage(msg); file_upload_end_background_task(msg); linphone_chat_message_unref(msg); } else { diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index e923279a6..1fbd85f18 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -29,15 +29,15 @@ // ============================================================================= -#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_STRUCT(obj) -#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_STRUCT(obj, ChatRoom) +#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_OBJECT(obj) +#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_OBJECT(obj, ChatRoom) using namespace std; static void _linphone_chat_room_constructor (LinphoneChatRoom *cr); static void _linphone_chat_room_destructor (LinphoneChatRoom *cr); -L_DECLARE_C_STRUCT_IMPL_WITH_XTORS( +L_DECLARE_C_OBJECT_IMPL_WITH_XTORS( ChatRoom, _linphone_chat_room_constructor, _linphone_chat_room_destructor, LinphoneChatRoomCbs *cbs; @@ -211,7 +211,7 @@ LinphoneChatRoomState linphone_chat_room_get_state (const LinphoneChatRoom *cr) LinphoneParticipant *linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr) { return L_GET_C_BACK_PTR(GET_CPP_PTR(cr)->addParticipant( - *L_GET_CPP_PTR_FROM_C_STRUCT(addr), nullptr, false), + *L_GET_CPP_PTR_FROM_C_OBJECT(addr), nullptr, false), Participant); } @@ -237,7 +237,7 @@ bctbx_list_t *linphone_chat_room_get_participants (const LinphoneChatRoom *cr) { } void linphone_chat_room_remove_participant (LinphoneChatRoom *cr, LinphoneParticipant *participant) { - GET_CPP_PTR(cr)->removeParticipant(L_GET_CPP_PTR_FROM_C_STRUCT(participant)); + GET_CPP_PTR(cr)->removeParticipant(L_GET_CPP_PTR_FROM_C_OBJECT(participant)); } void linphone_chat_room_remove_participants (LinphoneChatRoom *cr, const bctbx_list_t *participants) { @@ -258,11 +258,11 @@ void linphone_chat_room_unref (LinphoneChatRoom *cr) { } void *linphone_chat_room_get_user_data (const LinphoneChatRoom *cr) { - return L_GET_USER_DATA_FROM_C_STRUCT(cr, ChatRoom); + return L_GET_USER_DATA_FROM_C_OBJECT(cr, ChatRoom); } void linphone_chat_room_set_user_data (LinphoneChatRoom *cr, void *ud) { - L_SET_USER_DATA_FROM_C_STRUCT(cr, ud, ChatRoom); + L_SET_USER_DATA_FROM_C_OBJECT(cr, ud, ChatRoom); } // ============================================================================= @@ -272,12 +272,12 @@ void linphone_chat_room_set_user_data (LinphoneChatRoom *cr, void *ud) { LinphoneChatRoom *linphone_chat_room_new (LinphoneCore *core, const LinphoneAddress *addr) { LinphoneChatRoom *cr = _linphone_ChatRoom_init(); if (linphone_core_realtime_text_enabled(core)) - L_SET_CPP_PTR_FROM_C_STRUCT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_STRUCT(addr))); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_OBJECT(addr))); else - L_SET_CPP_PTR_FROM_C_STRUCT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_STRUCT(addr))); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_OBJECT(addr))); linphone_core_notify_chat_room_instantiated(core, cr); - L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Instantiated); - L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Created); + L_GET_PRIVATE_FROM_C_OBJECT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Instantiated); + L_GET_PRIVATE_FROM_C_OBJECT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Created); return cr; } @@ -290,16 +290,16 @@ LinphoneChatRoom *linphone_client_group_chat_room_new (LinphoneCore *core, const linphone_address_unref(factoryAddr); std::string from; if (proxy) - from = L_GET_CPP_PTR_FROM_C_STRUCT(linphone_proxy_config_get_identity_address(proxy))->asString(); + from = L_GET_CPP_PTR_FROM_C_OBJECT(linphone_proxy_config_get_identity_address(proxy))->asString(); if (from.empty()) from = linphone_core_get_primary_contact(core); LinphonePrivate::Address me(from); std::list l = L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(addresses, Address, Address); LinphoneChatRoom *cr = _linphone_ChatRoom_init(); - L_SET_CPP_PTR_FROM_C_STRUCT(cr, make_shared(core, me, l)); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared(core, me, l)); linphone_core_notify_chat_room_instantiated(core, cr); - L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Instantiated); - L_GET_PRIVATE_FROM_C_STRUCT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::CreationPending); + L_GET_PRIVATE_FROM_C_OBJECT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Instantiated); + L_GET_PRIVATE_FROM_C_OBJECT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::CreationPending); return cr; } diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 086487144..753e3f43a 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -42,7 +42,7 @@ using namespace std; LinphoneEventLog *linphone_event_log_new () { LinphoneEventLog *event_log = _linphone_EventLog_init(); - L_SET_CPP_PTR_FROM_C_STRUCT(event_log, new LINPHONE_NAMESPACE::EventLog()); + L_SET_CPP_PTR_FROM_C_OBJECT(event_log, new LINPHONE_NAMESPACE::EventLog()); return event_log; } @@ -53,7 +53,7 @@ LinphoneEventLog *linphone_event_log_ref (LinphoneEventLog *event_log) { LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *event_log) { return static_cast( - L_GET_CPP_PTR_FROM_C_STRUCT(event_log)->getType() + L_GET_CPP_PTR_FROM_C_OBJECT(event_log)->getType() ); } @@ -63,11 +63,11 @@ LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *event_ LinphoneCallEvent *linphone_call_event_new (LinphoneEventLogType type, LinphoneCall *call) { LinphoneCallEvent *call_event = _linphone_CallEvent_init(); - L_SET_CPP_PTR_FROM_C_STRUCT( + L_SET_CPP_PTR_FROM_C_OBJECT( call_event, new LINPHONE_NAMESPACE::CallEvent( static_cast(type), - L_GET_CPP_PTR_FROM_C_STRUCT(call) + L_GET_CPP_PTR_FROM_C_OBJECT(call) ) ); return call_event; @@ -75,7 +75,7 @@ LinphoneCallEvent *linphone_call_event_new (LinphoneEventLogType type, LinphoneC LinphoneCall *linphone_call_event_get_call (const LinphoneCallEvent *call_event) { return L_GET_C_BACK_PTR( - L_GET_CPP_PTR_FROM_C_STRUCT(call_event)->getCall(), Call + L_GET_CPP_PTR_FROM_C_OBJECT(call_event)->getCall(), Call ); } @@ -122,10 +122,10 @@ const LinphoneAddress *linphone_conference_participant_event_get_participant_add LinphoneChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage *chat_message) { LinphoneChatMessageEvent *chat_message_event = _linphone_ChatMessageEvent_init(); - L_SET_CPP_PTR_FROM_C_STRUCT( + L_SET_CPP_PTR_FROM_C_OBJECT( chat_message_event, new LINPHONE_NAMESPACE::ChatMessageEvent( - L_GET_CPP_PTR_FROM_C_STRUCT(chat_message) + L_GET_CPP_PTR_FROM_C_OBJECT(chat_message) ) ); return chat_message_event; @@ -133,7 +133,7 @@ LinphoneChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage * LinphoneChatMessage *linphone_chat_message_event_get_chat_message (const LinphoneChatMessageEvent *chat_message_event) { return L_GET_C_BACK_PTR( - L_GET_CPP_PTR_FROM_C_STRUCT(chat_message_event)->getChatMessage(), + L_GET_CPP_PTR_FROM_C_OBJECT(chat_message_event)->getChatMessage(), ChatMessage ); } diff --git a/src/c-wrapper/api/c-participant.cpp b/src/c-wrapper/api/c-participant.cpp index 69d07deaf..241774097 100644 --- a/src/c-wrapper/api/c-participant.cpp +++ b/src/c-wrapper/api/c-participant.cpp @@ -25,7 +25,7 @@ using namespace std; -L_DECLARE_C_STRUCT_IMPL(Participant, +L_DECLARE_C_OBJECT_IMPL(Participant, mutable LinphoneAddress *addressCache; ); @@ -39,15 +39,15 @@ void linphone_participant_unref (LinphoneParticipant *participant) { } void *linphone_participant_get_user_data(const LinphoneParticipant *participant) { - return L_GET_USER_DATA_FROM_C_STRUCT(participant, Participant); + return L_GET_USER_DATA_FROM_C_OBJECT(participant, Participant); } void linphone_participant_set_user_data(LinphoneParticipant *participant, void *ud) { - L_SET_USER_DATA_FROM_C_STRUCT(participant, ud, Participant); + L_SET_USER_DATA_FROM_C_OBJECT(participant, ud, Participant); } const LinphoneAddress *linphone_participant_get_address (const LinphoneParticipant *participant) { - LinphonePrivate::Address addr = L_GET_CPP_PTR_FROM_C_STRUCT(participant)->getAddress(); + LinphonePrivate::Address addr = L_GET_CPP_PTR_FROM_C_OBJECT(participant)->getAddress(); if (participant->addressCache) linphone_address_unref(participant->addressCache); participant->addressCache = linphone_address_new(addr.asString().c_str()); @@ -55,9 +55,9 @@ const LinphoneAddress *linphone_participant_get_address (const LinphoneParticipa } bool_t linphone_participant_is_admin (const LinphoneParticipant *participant) { - return L_GET_CPP_PTR_FROM_C_STRUCT(participant)->isAdmin(); + return L_GET_CPP_PTR_FROM_C_OBJECT(participant)->isAdmin(); } void linphone_participant_set_admin (LinphoneParticipant *participant, bool_t value) { - L_GET_CPP_PTR_FROM_C_STRUCT(participant)->setAdmin(value); + L_GET_CPP_PTR_FROM_C_OBJECT(participant)->setAdmin(value); } diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 6062b71fc..7deaa4b31 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -269,9 +269,9 @@ private: LINPHONE_END_NAMESPACE -#define L_INTERNAL_C_STRUCT_NO_XTOR(OBJECT) +#define L_INTERNAL_C_OBJECT_NO_XTOR(C_OBJECT) -#define L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(C_TYPE, CONSTRUCTOR, DESTRUCTOR) \ +#define L_INTERNAL_DECLARE_C_OBJECT_FUNCTIONS(C_TYPE, CONSTRUCTOR, DESTRUCTOR) \ BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_TYPE); \ Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init() { \ Linphone ## C_TYPE * object = belle_sip_object_new(Linphone ## C_TYPE); \ @@ -331,22 +331,22 @@ LINPHONE_END_NAMESPACE // ----------------------------------------------------------------------------- // Declare wrapped C object with constructor/destructor. -#define L_DECLARE_C_STRUCT_IMPL_WITH_XTORS(C_TYPE, CONSTRUCTOR, DESTRUCTOR, ...) \ +#define L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(C_TYPE, CONSTRUCTOR, DESTRUCTOR, ...) \ struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ std::shared_ptr cppPtr; \ __VA_ARGS__ \ }; \ - L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(C_TYPE, CONSTRUCTOR, DESTRUCTOR) + L_INTERNAL_DECLARE_C_OBJECT_FUNCTIONS(C_TYPE, CONSTRUCTOR, DESTRUCTOR) // Declare wrapped C object. -#define L_DECLARE_C_STRUCT_IMPL(C_TYPE, ...) \ +#define L_DECLARE_C_OBJECT_IMPL(C_TYPE, ...) \ struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ std::shared_ptr cppPtr; \ __VA_ARGS__ \ }; \ - L_INTERNAL_DECLARE_C_STRUCT_FUNCTIONS(C_TYPE, L_INTERNAL_C_STRUCT_NO_XTOR, L_INTERNAL_C_STRUCT_NO_XTOR) + L_INTERNAL_DECLARE_C_OBJECT_FUNCTIONS(C_TYPE, L_INTERNAL_C_OBJECT_NO_XTOR, L_INTERNAL_C_OBJECT_NO_XTOR) // Declare clonable wrapped C object. #define L_DECLARE_C_CLONABLE_STRUCT_IMPL(C_TYPE, ...) \ @@ -376,7 +376,7 @@ LINPHONE_END_NAMESPACE FALSE \ ); -#define L_DECLARE_C_STRUCT_NEW_DEFAULT(C_TYPE, C_NAME) \ +#define L_DECLARE_C_OBJECT_NEW_DEFAULT(C_TYPE, C_NAME) \ Linphone ## C_TYPE * linphone_ ## C_NAME ## _new() { \ Linphone ## C_TYPE * object = _linphone_ ## C_TYPE ## _init(); \ object->cppPtr = std::make_shared(); \ @@ -395,14 +395,14 @@ LINPHONE_END_NAMESPACE #define L_INIT(C_TYPE) _linphone_ ## C_TYPE ## _init () // Get the cpp-ptr of a wrapped C object. -#define L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT) \ +#define L_GET_CPP_PTR_FROM_C_OBJECT(OBJECT) \ LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC< \ L_CPP_TYPE_OF_C_OBJECT(OBJECT), \ std::remove_pointer::type \ >(OBJECT) // Set the cpp-ptr of a wrapped C object. -#define L_SET_CPP_PTR_FROM_C_STRUCT(OBJECT, CPP_PTR) \ +#define L_SET_CPP_PTR_FROM_C_OBJECT(OBJECT, CPP_PTR) \ LINPHONE_NAMESPACE::Wrapper::setCppPtrFromC(OBJECT, CPP_PTR) // Get the private data of a shared or simple cpp-ptr. @@ -410,9 +410,9 @@ LINPHONE_END_NAMESPACE LINPHONE_NAMESPACE::Wrapper::getPrivate(OBJECT) // Get the private data of a shared or simple cpp-ptr of a wrapped C object. -#define L_GET_PRIVATE_FROM_C_STRUCT(OBJECT, CPP_TYPE) \ +#define L_GET_PRIVATE_FROM_C_OBJECT(OBJECT, CPP_TYPE) \ L_GET_PRIVATE(LINPHONE_NAMESPACE::Wrapper::getCppPtr( \ - L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT) \ + L_GET_CPP_PTR_FROM_C_OBJECT(OBJECT) \ )) // Get the wrapped C object of a C++ object. @@ -422,13 +422,13 @@ LINPHONE_END_NAMESPACE ) // Get/set user data on a wrapped C object. -#define L_GET_USER_DATA_FROM_C_STRUCT(OBJECT, CPP_TYPE) \ +#define L_GET_USER_DATA_FROM_C_OBJECT(OBJECT, CPP_TYPE) \ LINPHONE_NAMESPACE::Wrapper::getUserData( \ - L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT) \ + L_GET_CPP_PTR_FROM_C_OBJECT(OBJECT) \ ) -#define L_SET_USER_DATA_FROM_C_STRUCT(OBJECT, VALUE, CPP_TYPE) \ +#define L_SET_USER_DATA_FROM_C_OBJECT(OBJECT, VALUE, CPP_TYPE) \ LINPHONE_NAMESPACE::Wrapper::setUserData( \ - L_GET_CPP_PTR_FROM_C_STRUCT(OBJECT), \ + L_GET_CPP_PTR_FROM_C_OBJECT(OBJECT), \ VALUE \ ) diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 52b19cdfc..dd28bc88d 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -828,7 +828,7 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { if (identity.empty()) { LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(d->core, peer); if (proxy) { - identity = L_GET_CPP_PTR_FROM_C_STRUCT(linphone_proxy_config_get_identity_address(proxy))->asString(); + identity = L_GET_CPP_PTR_FROM_C_OBJECT(linphone_proxy_config_get_identity_address(proxy))->asString(); } else { identity = linphone_core_get_primary_contact(d->core); } diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 9d44061a6..e12a5d416 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -454,7 +454,7 @@ LinphoneStatus CallSessionPrivate::checkForAcceptation () const { bctbx_list_t *copy = bctbx_list_copy(linphone_core_get_calls(core)); for (bctbx_list_t *it = copy; it != nullptr; it = bctbx_list_next(it)) { LinphoneCall *call = reinterpret_cast(bctbx_list_get_data(it)); - shared_ptr session = L_GET_PRIVATE_FROM_C_STRUCT(call, Call)->getActiveSession(); + shared_ptr session = L_GET_PRIVATE_FROM_C_OBJECT(call, Call)->getActiveSession(); if (session.get() == q) continue; switch (session->getState()) { case LinphoneCallOutgoingInit: @@ -616,7 +616,7 @@ void CallSessionPrivate::setContactOp () { SalAddress *salAddress = nullptr; LinphoneAddress *contact = getFixedContact(); if (contact) { - salAddress = const_cast(L_GET_PRIVATE_FROM_C_STRUCT(contact, Address)->getInternalAddress()); + salAddress = const_cast(L_GET_PRIVATE_FROM_C_OBJECT(contact, Address)->getInternalAddress()); sal_address_ref(salAddress); linphone_address_unref(contact); } @@ -962,7 +962,7 @@ LinphoneReason CallSession::getReason () const { const Address& CallSession::getRemoteAddress () const { L_D(const CallSession); - return *L_GET_CPP_PTR_FROM_C_STRUCT((d->direction == LinphoneCallIncoming) + return *L_GET_CPP_PTR_FROM_C_OBJECT((d->direction == LinphoneCallIncoming) ? linphone_call_log_get_from(d->log) : linphone_call_log_get_to(d->log)); } diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 0d7ccaab4..1e9c71e85 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -913,7 +913,7 @@ int MediaSessionPrivate::selectFixedPort (int streamIndex, pair portRa bool alreadyUsed = false; for (const bctbx_list_t *elem = linphone_core_get_calls(core); elem != nullptr; elem = bctbx_list_next(elem)) { LinphoneCall *lcall = reinterpret_cast(bctbx_list_get_data(elem)); - MediaSession *session = dynamic_cast(L_GET_PRIVATE_FROM_C_STRUCT(lcall, Call)->getConference()->getActiveParticipant()->getPrivate()->getSession().get()); + MediaSession *session = dynamic_cast(L_GET_PRIVATE_FROM_C_OBJECT(lcall, Call)->getConference()->getActiveParticipant()->getPrivate()->getSession().get()); int existingPort = session->getPrivate()->mediaPorts[streamIndex].rtpPort; if (existingPort == triedPort) { alreadyUsed = true; @@ -935,7 +935,7 @@ int MediaSessionPrivate::selectRandomPort (int streamIndex, pair portR if (triedPort < portRange.first) triedPort = portRange.first + 2; for (const bctbx_list_t *elem = linphone_core_get_calls(core); elem != nullptr; elem = bctbx_list_next(elem)) { LinphoneCall *lcall = reinterpret_cast(bctbx_list_get_data(elem)); - MediaSession *session = dynamic_cast(L_GET_PRIVATE_FROM_C_STRUCT(lcall, Call)->getConference()->getActiveParticipant()->getPrivate()->getSession().get()); + MediaSession *session = dynamic_cast(L_GET_PRIVATE_FROM_C_OBJECT(lcall, Call)->getConference()->getActiveParticipant()->getPrivate()->getSession().get()); int existingPort = session->getPrivate()->mediaPorts[streamIndex].rtpPort; if (existingPort == triedPort) { alreadyUsed = true; @@ -1107,7 +1107,7 @@ void MediaSessionPrivate::selectOutgoingIpVersion () { } const LinphoneAddress *to = linphone_call_log_get_to_address(log); - if (sal_address_is_ipv6(L_GET_PRIVATE_FROM_C_STRUCT(to, Address)->getInternalAddress())) + if (sal_address_is_ipv6(L_GET_PRIVATE_FROM_C_OBJECT(to, Address)->getInternalAddress())) af = AF_INET6; else if (destProxy && destProxy->op) af = sal_op_get_address_family(destProxy->op); @@ -1221,7 +1221,7 @@ void MediaSessionPrivate::makeLocalMediaDescription () { /* Re-check local ip address each time we make a new offer, because it may change in case of network reconnection */ { LinphoneAddress *address = (direction == LinphoneCallOutgoing ? log->to : log->from); - getLocalIp(*L_GET_CPP_PTR_FROM_C_STRUCT(address)); + getLocalIp(*L_GET_CPP_PTR_FROM_C_OBJECT(address)); } strncpy(md->addr, mediaLocalIp.c_str(), sizeof(md->addr)); From 1431e1518d7b0c87199d6656968e46e3e475526d Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 22 Sep 2017 10:40:14 +0200 Subject: [PATCH 0135/2215] feat(c-wrapper): remove CPP_TYPE parameter of L_GET_PRIVATE_FROM_C_OBJECT --- coreapi/callbacks.c | 2 +- coreapi/chat.c | 2 +- coreapi/linphonecore.c | 8 ++++---- coreapi/proxy.c | 6 +++--- coreapi/quality_reporting.c | 2 +- src/c-wrapper/api/c-call-params.cpp | 2 +- src/c-wrapper/api/c-call.cpp | 2 +- src/c-wrapper/api/c-chat-message.cpp | 6 +++--- src/c-wrapper/api/c-chat-room.cpp | 10 +++++----- src/c-wrapper/internal/c-tools.h | 20 ++++++++++---------- src/conference/session/call-session.cpp | 4 ++-- src/conference/session/media-session.cpp | 6 +++--- 12 files changed, 35 insertions(+), 35 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 775ed81d0..0683b28e9 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -169,7 +169,7 @@ static void call_received(SalOp *h) { LinphoneCall *call = linphone_call_new_incoming(lc, fromAddr, toAddr, h); linphone_address_unref(fromAddr); linphone_address_unref(toAddr); - L_GET_PRIVATE_FROM_C_OBJECT(call, Call)->startIncomingNotification(); + L_GET_PRIVATE_FROM_C_OBJECT(call)->startIncomingNotification(); } static void call_rejected(SalOp *h){ diff --git a/coreapi/chat.c b/coreapi/chat.c index d3155a01f..5140df79a 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -225,7 +225,7 @@ int linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage LinphoneAddress *addr = linphone_address_new(sal_msg->from); linphone_address_clean(addr); LinphoneChatRoom *cr = linphone_core_get_chat_room(lc, addr); - LinphoneReason reason = L_GET_PRIVATE_FROM_C_OBJECT(cr, ChatRoom)->messageReceived(op, sal_msg); + LinphoneReason reason = L_GET_PRIVATE_FROM_C_OBJECT(cr)->messageReceived(op, sal_msg); linphone_address_unref(addr); return reason; } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index a1ccd0735..738c1912a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3205,7 +3205,7 @@ void linphone_core_iterate(LinphoneCore *lc){ /* Get immediately a reference to next one in case the one we are going to examine is destroyed * and removed during linphone_call_start_invite() */ calls = bctbx_list_next(calls); - L_GET_PRIVATE_FROM_C_OBJECT(call, Call)->iterate(current_real_time, one_second_elapsed); + L_GET_PRIVATE_FROM_C_OBJECT(call)->iterate(current_real_time, one_second_elapsed); } if (linphone_core_video_preview_enabled(lc)){ @@ -3341,7 +3341,7 @@ static bctbx_list_t *make_routes_for_proxy(LinphoneProxyConfig *proxy, const Lin ret=bctbx_list_append(ret,sal_address_new(local_route)); } if (srv_route){ - ret=bctbx_list_append(ret,sal_address_clone(L_GET_PRIVATE_FROM_C_OBJECT(srv_route, Address)->getInternalAddress())); + ret=bctbx_list_append(ret,sal_address_clone(L_GET_PRIVATE_FROM_C_OBJECT(srv_route)->getInternalAddress())); } if (ret==NULL){ /*if the proxy address matches the domain part of the destination, then use the same transport @@ -3530,9 +3530,9 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const if (linphone_call_params_get_local_conference_mode(params) == FALSE) #endif lc->current_call=call; - bool defer = L_GET_PRIVATE_FROM_C_OBJECT(call, Call)->initiateOutgoing(); + bool defer = L_GET_PRIVATE_FROM_C_OBJECT(call)->initiateOutgoing(); if (!defer) { - if (L_GET_PRIVATE_FROM_C_OBJECT(call, Call)->startInvite(nullptr) != 0) { + if (L_GET_PRIVATE_FROM_C_OBJECT(call)->startInvite(nullptr) != 0) { /* The call has already gone to error and released state, so do not return it */ call = nullptr; } diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 41af4af34..eddf9ee76 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -492,7 +492,7 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *cfg){ linphone_configure_op(cfg->lc, cfg->op, cfg->identity_address, cfg->sent_headers, FALSE); if ((contact=guess_contact_for_register(cfg))) { - sal_op_set_contact_address(cfg->op, L_GET_PRIVATE_FROM_C_OBJECT(contact, Address)->getInternalAddress()); + sal_op_set_contact_address(cfg->op, L_GET_PRIVATE_FROM_C_OBJECT(contact)->getInternalAddress()); linphone_address_unref(contact); } @@ -503,7 +503,7 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *cfg){ proxy_string, cfg->reg_identity, cfg->expires, - cfg->pending_contact ? L_GET_PRIVATE_FROM_C_OBJECT(cfg->pending_contact, Address)->getInternalAddress() : NULL + cfg->pending_contact ? L_GET_PRIVATE_FROM_C_OBJECT(cfg->pending_contact)->getInternalAddress() : NULL )==0) { if (cfg->pending_contact) { linphone_address_unref(cfg->pending_contact); @@ -1364,7 +1364,7 @@ const char* linphone_proxy_config_get_transport(const LinphoneProxyConfig *cfg) bool_t destroy_route_addr = FALSE; if (linphone_proxy_config_get_service_route(cfg)) { - route_addr = L_GET_PRIVATE_FROM_C_OBJECT(linphone_proxy_config_get_service_route(cfg), Address)->getInternalAddress(); + route_addr = L_GET_PRIVATE_FROM_C_OBJECT(linphone_proxy_config_get_service_route(cfg))->getInternalAddress(); } else if (linphone_proxy_config_get_route(cfg)) { addr=linphone_proxy_config_get_route(cfg); } else if(linphone_proxy_config_get_addr(cfg)) { diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 5ef13eed3..2175baa07 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -380,7 +380,7 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report, * (port, transport, maddr), then it is sent directly. * Otherwise it is routed as any LinphoneEvent publish, following proxy config policy. **/ - salAddress = L_GET_PRIVATE_FROM_C_OBJECT(request_uri, Address)->getInternalAddress(); + salAddress = L_GET_PRIVATE_FROM_C_OBJECT(request_uri)->getInternalAddress(); if (sal_address_has_uri_param(salAddress, "transport") || sal_address_has_uri_param(salAddress, "maddr") || linphone_address_get_port(request_uri) != 0) { diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index bca549c5f..3845dc66d 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -23,7 +23,7 @@ // ============================================================================= #define GET_MEDIA_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_OBJECT(obj) -#define GET_MEDIA_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_OBJECT(obj, MediaSessionParams) +#define GET_MEDIA_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_OBJECT(obj) L_DECLARE_C_CLONABLE_STRUCT_IMPL(CallParams) diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index bfeae22d7..8aa57a52a 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -29,7 +29,7 @@ // ============================================================================= #define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_OBJECT(obj) -#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_OBJECT(obj, Call) +#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_OBJECT(obj) using namespace std; diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index dd58ca4df..c5202a85d 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -31,7 +31,7 @@ // ============================================================================= #define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_OBJECT(obj) -#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_OBJECT(obj, ChatMessage, ChatMessage) +#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_OBJECT(obj) using namespace std; @@ -309,7 +309,7 @@ void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMe linphone_chat_message_store_state(msg); if (msg->state == LinphoneChatMessageStateDelivered || msg->state == LinphoneChatMessageStateNotDelivered) { - L_GET_PRIVATE_FROM_C_OBJECT(msg->chat_room, ChatRoom)->moveTransientMessageToWeakMessages(msg); + L_GET_PRIVATE_FROM_C_OBJECT(msg->chat_room)->moveTransientMessageToWeakMessages(msg); } } @@ -440,7 +440,7 @@ static char *linphone_chat_message_create_imdn_xml(LinphoneChatMessage *cm, Imdn void linphone_chat_message_send_imdn(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason) { char *content = linphone_chat_message_create_imdn_xml(cm, imdn_type, reason); if (content) { - L_GET_PRIVATE_FROM_C_OBJECT(linphone_chat_message_get_chat_room(cm), ChatRoom)->sendImdn(content, reason); + L_GET_PRIVATE_FROM_C_OBJECT(linphone_chat_message_get_chat_room(cm))->sendImdn(content, reason); ms_free(content); } } diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 1fbd85f18..7bfbdddf9 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -30,7 +30,7 @@ // ============================================================================= #define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_OBJECT(obj) -#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_OBJECT(obj, ChatRoom) +#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_OBJECT(obj) using namespace std; @@ -276,8 +276,8 @@ LinphoneChatRoom *linphone_chat_room_new (LinphoneCore *core, const LinphoneAddr else L_SET_CPP_PTR_FROM_C_OBJECT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_OBJECT(addr))); linphone_core_notify_chat_room_instantiated(core, cr); - L_GET_PRIVATE_FROM_C_OBJECT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Instantiated); - L_GET_PRIVATE_FROM_C_OBJECT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Created); + L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); + L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Created); return cr; } @@ -298,8 +298,8 @@ LinphoneChatRoom *linphone_client_group_chat_room_new (LinphoneCore *core, const LinphoneChatRoom *cr = _linphone_ChatRoom_init(); L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared(core, me, l)); linphone_core_notify_chat_room_instantiated(core, cr); - L_GET_PRIVATE_FROM_C_OBJECT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Instantiated); - L_GET_PRIVATE_FROM_C_OBJECT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::CreationPending); + L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); + L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::CreationPending); return cr; } diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 7deaa4b31..053cb81bb 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -395,24 +395,24 @@ LINPHONE_END_NAMESPACE #define L_INIT(C_TYPE) _linphone_ ## C_TYPE ## _init () // Get the cpp-ptr of a wrapped C object. -#define L_GET_CPP_PTR_FROM_C_OBJECT(OBJECT) \ +#define L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT) \ LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC< \ - L_CPP_TYPE_OF_C_OBJECT(OBJECT), \ - std::remove_pointer::type \ - >(OBJECT) + L_CPP_TYPE_OF_C_OBJECT(C_OBJECT), \ + std::remove_pointer::type \ + >(C_OBJECT) // Set the cpp-ptr of a wrapped C object. -#define L_SET_CPP_PTR_FROM_C_OBJECT(OBJECT, CPP_PTR) \ - LINPHONE_NAMESPACE::Wrapper::setCppPtrFromC(OBJECT, CPP_PTR) +#define L_SET_CPP_PTR_FROM_C_OBJECT(C_OBJECT, CPP_PTR) \ + LINPHONE_NAMESPACE::Wrapper::setCppPtrFromC(C_OBJECT, CPP_PTR) // Get the private data of a shared or simple cpp-ptr. -#define L_GET_PRIVATE(OBJECT) \ - LINPHONE_NAMESPACE::Wrapper::getPrivate(OBJECT) +#define L_GET_PRIVATE(CPP_OBJECT) \ + LINPHONE_NAMESPACE::Wrapper::getPrivate(CPP_OBJECT) // Get the private data of a shared or simple cpp-ptr of a wrapped C object. -#define L_GET_PRIVATE_FROM_C_OBJECT(OBJECT, CPP_TYPE) \ +#define L_GET_PRIVATE_FROM_C_OBJECT(C_OBJECT) \ L_GET_PRIVATE(LINPHONE_NAMESPACE::Wrapper::getCppPtr( \ - L_GET_CPP_PTR_FROM_C_OBJECT(OBJECT) \ + L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT) \ )) // Get the wrapped C object of a C++ object. diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index e12a5d416..91d1edb9b 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -454,7 +454,7 @@ LinphoneStatus CallSessionPrivate::checkForAcceptation () const { bctbx_list_t *copy = bctbx_list_copy(linphone_core_get_calls(core)); for (bctbx_list_t *it = copy; it != nullptr; it = bctbx_list_next(it)) { LinphoneCall *call = reinterpret_cast(bctbx_list_get_data(it)); - shared_ptr session = L_GET_PRIVATE_FROM_C_OBJECT(call, Call)->getActiveSession(); + shared_ptr session = L_GET_PRIVATE_FROM_C_OBJECT(call)->getActiveSession(); if (session.get() == q) continue; switch (session->getState()) { case LinphoneCallOutgoingInit: @@ -616,7 +616,7 @@ void CallSessionPrivate::setContactOp () { SalAddress *salAddress = nullptr; LinphoneAddress *contact = getFixedContact(); if (contact) { - salAddress = const_cast(L_GET_PRIVATE_FROM_C_OBJECT(contact, Address)->getInternalAddress()); + salAddress = const_cast(L_GET_PRIVATE_FROM_C_OBJECT(contact)->getInternalAddress()); sal_address_ref(salAddress); linphone_address_unref(contact); } diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 1e9c71e85..5f8703d42 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -913,7 +913,7 @@ int MediaSessionPrivate::selectFixedPort (int streamIndex, pair portRa bool alreadyUsed = false; for (const bctbx_list_t *elem = linphone_core_get_calls(core); elem != nullptr; elem = bctbx_list_next(elem)) { LinphoneCall *lcall = reinterpret_cast(bctbx_list_get_data(elem)); - MediaSession *session = dynamic_cast(L_GET_PRIVATE_FROM_C_OBJECT(lcall, Call)->getConference()->getActiveParticipant()->getPrivate()->getSession().get()); + MediaSession *session = dynamic_cast(L_GET_PRIVATE_FROM_C_OBJECT(lcall)->getConference()->getActiveParticipant()->getPrivate()->getSession().get()); int existingPort = session->getPrivate()->mediaPorts[streamIndex].rtpPort; if (existingPort == triedPort) { alreadyUsed = true; @@ -935,7 +935,7 @@ int MediaSessionPrivate::selectRandomPort (int streamIndex, pair portR if (triedPort < portRange.first) triedPort = portRange.first + 2; for (const bctbx_list_t *elem = linphone_core_get_calls(core); elem != nullptr; elem = bctbx_list_next(elem)) { LinphoneCall *lcall = reinterpret_cast(bctbx_list_get_data(elem)); - MediaSession *session = dynamic_cast(L_GET_PRIVATE_FROM_C_OBJECT(lcall, Call)->getConference()->getActiveParticipant()->getPrivate()->getSession().get()); + MediaSession *session = dynamic_cast(L_GET_PRIVATE_FROM_C_OBJECT(lcall)->getConference()->getActiveParticipant()->getPrivate()->getSession().get()); int existingPort = session->getPrivate()->mediaPorts[streamIndex].rtpPort; if (existingPort == triedPort) { alreadyUsed = true; @@ -1107,7 +1107,7 @@ void MediaSessionPrivate::selectOutgoingIpVersion () { } const LinphoneAddress *to = linphone_call_log_get_to_address(log); - if (sal_address_is_ipv6(L_GET_PRIVATE_FROM_C_OBJECT(to, Address)->getInternalAddress())) + if (sal_address_is_ipv6(L_GET_PRIVATE_FROM_C_OBJECT(to)->getInternalAddress())) af = AF_INET6; else if (destProxy && destProxy->op) af = sal_op_get_address_family(destProxy->op); From ccb1828d7d26f4796b7fe2c4e0baecc1db1e7b90 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 22 Sep 2017 10:48:51 +0200 Subject: [PATCH 0136/2215] feat(c-wrapper): remove CPP_TYPE parameter of L_GET_USER_DATA_FROM_C_OBJECT --- src/c-wrapper/api/c-call-params.cpp | 2 +- src/c-wrapper/api/c-call.cpp | 2 +- src/c-wrapper/api/c-chat-message.cpp | 2 +- src/c-wrapper/api/c-chat-room.cpp | 2 +- src/c-wrapper/api/c-participant.cpp | 2 +- src/c-wrapper/internal/c-tools.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index 3845dc66d..9d8fc7974 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -485,7 +485,7 @@ void linphone_call_params_set_no_user_consent (LinphoneCallParams *params, bool_ // ============================================================================= void *linphone_call_params_get_user_data (const LinphoneCallParams *cp) { - return L_GET_USER_DATA_FROM_C_OBJECT(cp, MediaSessionParams); + return L_GET_USER_DATA_FROM_C_OBJECT(cp); } void linphone_call_params_set_user_data (LinphoneCallParams *cp, void *ud) { diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 8aa57a52a..10e7cc5c0 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -1174,7 +1174,7 @@ void linphone_call_unref (LinphoneCall *call) { } void *linphone_call_get_user_data (const LinphoneCall *call) { - return L_GET_USER_DATA_FROM_C_OBJECT(call, Call); + return L_GET_USER_DATA_FROM_C_OBJECT(call); } void linphone_call_set_user_data (LinphoneCall *call, void *ud) { diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index c5202a85d..355a86c2b 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -92,7 +92,7 @@ void linphone_chat_message_unref (LinphoneChatMessage *msg) { } void * linphone_chat_message_get_user_data (const LinphoneChatMessage *msg) { - return L_GET_USER_DATA_FROM_C_OBJECT(msg, ChatMessage); + return L_GET_USER_DATA_FROM_C_OBJECT(msg); } void linphone_chat_message_set_user_data (LinphoneChatMessage *msg, void *ud) { diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 7bfbdddf9..9ed6d2beb 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -258,7 +258,7 @@ void linphone_chat_room_unref (LinphoneChatRoom *cr) { } void *linphone_chat_room_get_user_data (const LinphoneChatRoom *cr) { - return L_GET_USER_DATA_FROM_C_OBJECT(cr, ChatRoom); + return L_GET_USER_DATA_FROM_C_OBJECT(cr); } void linphone_chat_room_set_user_data (LinphoneChatRoom *cr, void *ud) { diff --git a/src/c-wrapper/api/c-participant.cpp b/src/c-wrapper/api/c-participant.cpp index 241774097..66d5f39b1 100644 --- a/src/c-wrapper/api/c-participant.cpp +++ b/src/c-wrapper/api/c-participant.cpp @@ -39,7 +39,7 @@ void linphone_participant_unref (LinphoneParticipant *participant) { } void *linphone_participant_get_user_data(const LinphoneParticipant *participant) { - return L_GET_USER_DATA_FROM_C_OBJECT(participant, Participant); + return L_GET_USER_DATA_FROM_C_OBJECT(participant); } void linphone_participant_set_user_data(LinphoneParticipant *participant, void *ud) { diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 053cb81bb..6da6bd2ab 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -422,7 +422,7 @@ LINPHONE_END_NAMESPACE ) // Get/set user data on a wrapped C object. -#define L_GET_USER_DATA_FROM_C_OBJECT(OBJECT, CPP_TYPE) \ +#define L_GET_USER_DATA_FROM_C_OBJECT(OBJECT) \ LINPHONE_NAMESPACE::Wrapper::getUserData( \ L_GET_CPP_PTR_FROM_C_OBJECT(OBJECT) \ ) From bd02b8968d26da86d53a7a1306974d34e1e5b1b6 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 22 Sep 2017 10:58:11 +0200 Subject: [PATCH 0137/2215] feat(c-wrapper): remove CPP_TYPE parameter of L_SET_USER_DATA_FROM_C_OBJECT --- src/c-wrapper/api/c-call-params.cpp | 2 +- src/c-wrapper/api/c-call.cpp | 2 +- src/c-wrapper/api/c-chat-message.cpp | 2 +- src/c-wrapper/api/c-chat-room.cpp | 2 +- src/c-wrapper/api/c-participant.cpp | 2 +- src/c-wrapper/internal/c-tools.h | 14 +++++++------- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index 9d8fc7974..e6573061e 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -489,7 +489,7 @@ void *linphone_call_params_get_user_data (const LinphoneCallParams *cp) { } void linphone_call_params_set_user_data (LinphoneCallParams *cp, void *ud) { - L_SET_USER_DATA_FROM_C_OBJECT(cp, ud, MediaSessionParams); + L_SET_USER_DATA_FROM_C_OBJECT(cp, ud); } LinphoneCallParams *linphone_call_params_ref (LinphoneCallParams *cp) { diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 10e7cc5c0..c31c45354 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -1178,7 +1178,7 @@ void *linphone_call_get_user_data (const LinphoneCall *call) { } void linphone_call_set_user_data (LinphoneCall *call, void *ud) { - L_SET_USER_DATA_FROM_C_OBJECT(call, ud, Call); + L_SET_USER_DATA_FROM_C_OBJECT(call, ud); } // ============================================================================= diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 355a86c2b..b2665f26a 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -96,7 +96,7 @@ void * linphone_chat_message_get_user_data (const LinphoneChatMessage *msg) { } void linphone_chat_message_set_user_data (LinphoneChatMessage *msg, void *ud) { - L_SET_USER_DATA_FROM_C_OBJECT(msg, ud, ChatMessage); + L_SET_USER_DATA_FROM_C_OBJECT(msg, ud); } diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 9ed6d2beb..48eaee264 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -262,7 +262,7 @@ void *linphone_chat_room_get_user_data (const LinphoneChatRoom *cr) { } void linphone_chat_room_set_user_data (LinphoneChatRoom *cr, void *ud) { - L_SET_USER_DATA_FROM_C_OBJECT(cr, ud, ChatRoom); + L_SET_USER_DATA_FROM_C_OBJECT(cr, ud); } // ============================================================================= diff --git a/src/c-wrapper/api/c-participant.cpp b/src/c-wrapper/api/c-participant.cpp index 66d5f39b1..89ff5ee1f 100644 --- a/src/c-wrapper/api/c-participant.cpp +++ b/src/c-wrapper/api/c-participant.cpp @@ -43,7 +43,7 @@ void *linphone_participant_get_user_data(const LinphoneParticipant *participant) } void linphone_participant_set_user_data(LinphoneParticipant *participant, void *ud) { - L_SET_USER_DATA_FROM_C_OBJECT(participant, ud, Participant); + L_SET_USER_DATA_FROM_C_OBJECT(participant, ud); } const LinphoneAddress *linphone_participant_get_address (const LinphoneParticipant *participant) { diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 6da6bd2ab..10821be11 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -394,7 +394,7 @@ LINPHONE_END_NAMESPACE // Call the init function of wrapped C object. #define L_INIT(C_TYPE) _linphone_ ## C_TYPE ## _init () -// Get the cpp-ptr of a wrapped C object. +// Get/set the cpp-ptr of a wrapped C object. #define L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT) \ LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC< \ L_CPP_TYPE_OF_C_OBJECT(C_OBJECT), \ @@ -416,19 +416,19 @@ LINPHONE_END_NAMESPACE )) // Get the wrapped C object of a C++ object. -#define L_GET_C_BACK_PTR(OBJECT, C_TYPE) \ +#define L_GET_C_BACK_PTR(C_OBJECT, C_TYPE) \ LINPHONE_NAMESPACE::Wrapper::getCBackPtr( \ - OBJECT, _linphone_ ## C_TYPE ## _init \ + C_OBJECT, _linphone_ ## C_TYPE ## _init \ ) // Get/set user data on a wrapped C object. -#define L_GET_USER_DATA_FROM_C_OBJECT(OBJECT) \ +#define L_GET_USER_DATA_FROM_C_OBJECT(C_OBJECT) \ LINPHONE_NAMESPACE::Wrapper::getUserData( \ - L_GET_CPP_PTR_FROM_C_OBJECT(OBJECT) \ + L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT) \ ) -#define L_SET_USER_DATA_FROM_C_OBJECT(OBJECT, VALUE, CPP_TYPE) \ +#define L_SET_USER_DATA_FROM_C_OBJECT(C_OBJECT, VALUE) \ LINPHONE_NAMESPACE::Wrapper::setUserData( \ - L_GET_CPP_PTR_FROM_C_OBJECT(OBJECT), \ + L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT), \ VALUE \ ) From bb9c6de6d66e4189e1b6fcdea1e938b87f45e60f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 22 Sep 2017 11:17:58 +0200 Subject: [PATCH 0138/2215] Started cpp ChatMessage --- src/chat/chat-message-p.h | 6 +++++- src/chat/chat-message.cpp | 22 +++++++++++++++++----- src/chat/chat-message.h | 12 ++++++++++-- src/chat/chat-room.cpp | 4 +++- 4 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 7b77764cd..8614e1e7a 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -31,8 +31,12 @@ class ChatMessagePrivate : public ObjectPrivate { friend class CpimChatMessageModifier; friend class MultipartChatMessageModifier; +public: + ChatMessagePrivate (const std::shared_ptr &room); + virtual ~ChatMessagePrivate (); + private: - std::weak_ptr chatRoom; + std::shared_ptr chatRoom; ChatMessage::Direction direction = ChatMessage::Incoming; // LinphoneAddress *from; // LinphoneAddress *to; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index ee56033da..a38ca9fd5 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -22,6 +22,7 @@ #include "linphone/types.h" #include "linphone/core.h" #include "linphone/lpconfig.h" +#include "c-wrapper/c-wrapper.h" #include "chat-message-p.h" #include "chat-message.h" @@ -30,6 +31,8 @@ #include "modifier/cpim-chat-message-modifier.h" #include "chat-room.h" +#define GET_BACK_PTR(object) L_GET_C_BACK_PTR(object->shared_from_this(), ChatMessage) + // ============================================================================= LINPHONE_BEGIN_NAMESPACE @@ -38,15 +41,24 @@ using namespace std; // ----------------------------------------------------------------------------- +ChatMessagePrivate::ChatMessagePrivate (const std::shared_ptr &room) +: chatRoom(room) {} + +ChatMessagePrivate::~ChatMessagePrivate () {} + +// ----------------------------------------------------------------------------- + +ChatMessage::ChatMessage (const std::shared_ptr &room) : Object(*new ChatMessagePrivate(room)) {} + ChatMessage::ChatMessage (ChatMessagePrivate &p) : Object(p) {} +LinphoneChatMessage * ChatMessage::getBackPtr() { + return GET_BACK_PTR(this); +} + shared_ptr ChatMessage::getChatRoom () const { L_D(const ChatMessage); - shared_ptr chatRoom = d->chatRoom.lock(); - if (!chatRoom) { - // TODO. - } - return chatRoom; + return d->chatRoom; } ChatMessage::Direction ChatMessage::getDirection () const { diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index b8b026c8e..a105d7487 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -22,6 +22,8 @@ #include #include +#include "linphone/api/c-chat-message.h" + #include "object/object.h" // ============================================================================= @@ -54,6 +56,11 @@ public: Displayed }; + ChatMessage (const std::shared_ptr &room); + virtual ~ChatMessage () = default; + + LinphoneChatMessage * getBackPtr(); + std::shared_ptr getChatRoom () const; Direction getDirection () const; @@ -89,9 +96,10 @@ public: void addCustomHeader (const std::string &headerName, const std::string &headerValue); void removeCustomHeader (const std::string &headerName); -private: - ChatMessage (ChatMessagePrivate &p); +protected: + explicit ChatMessage (ChatMessagePrivate &p); +private: L_DECLARE_PRIVATE(ChatMessage); L_DISABLE_COPY(ChatMessage); }; diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index dd28bc88d..97e78cef1 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -27,6 +27,7 @@ #include "imdn.h" #include "logger/logger.h" +#include "chat-message.h" #include "chat-room.h" #define GET_BACK_PTR(object) L_GET_C_BACK_PTR(object->shared_from_this(), ChatRoom) @@ -609,7 +610,8 @@ LinphoneChatMessage *ChatRoom::createFileTransferMessage (const LinphoneContent } LinphoneChatMessage *ChatRoom::createMessage (const string &message) { - LinphoneChatMessage *msg = createMessage(""); + ChatMessage chatMessage(static_pointer_cast(shared_from_this())); + LinphoneChatMessage *msg = chatMessage.getBackPtr(); linphone_chat_message_set_chat_room(msg, GET_BACK_PTR(this)); linphone_chat_message_set_state(msg, LinphoneChatMessageStateIdle); linphone_chat_message_set_text(msg, message.empty() ? nullptr : ms_strdup(message.c_str())); From a38e2220455414f571b93130d8e9f44dfa142373 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 22 Sep 2017 11:17:40 +0200 Subject: [PATCH 0139/2215] Separate client chat room instantiation and creation on the server when adding the first participants. --- coreapi/chat.c | 4 ++-- coreapi/private.h | 2 +- include/linphone/api/c-chat-message.h | 2 -- include/linphone/core.h | 9 +++++++++ src/c-wrapper/api/c-chat-room.cpp | 6 ++---- src/chat/client-group-chat-room.cpp | 20 ++++++++++++-------- src/chat/client-group-chat-room.h | 2 +- 7 files changed, 27 insertions(+), 18 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 5140df79a..61708382c 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -123,8 +123,8 @@ LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAd return ret; } -LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, const bctbx_list_t *addresses) { - return linphone_client_group_chat_room_new(lc, addresses); +LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc) { + return linphone_client_group_chat_room_new(lc); } void linphone_core_delete_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr) { diff --git a/coreapi/private.h b/coreapi/private.h index 193d5d8ff..ecd503718 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -460,7 +460,7 @@ void _linphone_proxy_config_release_ops(LinphoneProxyConfig *obj); /*chat*/ LinphoneChatRoom * linphone_chat_room_new(LinphoneCore *core, const LinphoneAddress *addr); -LinphoneChatRoom * linphone_client_group_chat_room_new(LinphoneCore *lc, const bctbx_list_t *addresses); +LinphoneChatRoom * linphone_client_group_chat_room_new(LinphoneCore *lc); void linphone_chat_room_release(LinphoneChatRoom *cr); void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call); bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr); diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index bf69e0df7..74f2753d1 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -294,8 +294,6 @@ LINPHONE_PUBLIC void linphone_chat_message_cancel_file_transfer(LinphoneChatMess */ LINPHONE_PUBLIC void linphone_chat_message_resend(LinphoneChatMessage *msg); -LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, const bctbx_list_t *addresses); - LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg); /** diff --git a/include/linphone/core.h b/include/linphone/core.h index e738629af..ebb981018 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -4822,6 +4822,15 @@ LINPHONE_PUBLIC void linphone_core_set_chat_database_path(LinphoneCore *lc, cons **/ LINPHONE_PUBLIC const char *linphone_core_get_chat_database_path(const LinphoneCore *lc); +/** + * Create a client-side group chat room. When calling this function the chat room is only created + * at the client-side and is empty. Pou need to call linphone_chat_room_add_participants() to + * create at the server side and add participants to it. + * @param[in] lc A #LinphoneCore object + * @return The newly created client-side group chat room. + */ +LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc); + /** * Get a chat room whose peer is the supplied address. If it does not exist yet, it will be created. * No reference is transfered to the application. The LinphoneCore keeps a reference on the chat room. diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 48eaee264..65f5c9b25 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -281,7 +281,7 @@ LinphoneChatRoom *linphone_chat_room_new (LinphoneCore *core, const LinphoneAddr return cr; } -LinphoneChatRoom *linphone_client_group_chat_room_new (LinphoneCore *core, const bctbx_list_t *addresses) { +LinphoneChatRoom *linphone_client_group_chat_room_new (LinphoneCore *core) { const char *factoryUri = linphone_core_get_chat_conference_factory_uri(core); if (!factoryUri) return nullptr; @@ -294,12 +294,10 @@ LinphoneChatRoom *linphone_client_group_chat_room_new (LinphoneCore *core, const if (from.empty()) from = linphone_core_get_primary_contact(core); LinphonePrivate::Address me(from); - std::list l = L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(addresses, Address, Address); LinphoneChatRoom *cr = _linphone_ChatRoom_init(); - L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared(core, me, l)); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared(core, me)); linphone_core_notify_chat_room_instantiated(core, cr); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); - L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::CreationPending); return cr; } diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 9cd3592e0..b413930d9 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -31,15 +31,13 @@ ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core) : Ch // ============================================================================= -ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, list

    &addresses) +ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me) : ChatRoom(*new ChatRoomPrivate(core)), RemoteConference(core, me, nullptr) { string factoryUri = linphone_core_get_chat_conference_factory_uri(core); focus = make_shared(factoryUri); CallSessionParams csp; shared_ptr session = focus->getPrivate()->createSession(*this, &csp, false, this); session->configure(LinphoneCallOutgoing, nullptr, nullptr, me, focus->getAddress()); - session->initiateOutgoing(); - session->startInvite(nullptr); // TODO } @@ -52,24 +50,30 @@ shared_ptr ClientGroupChatRoom::addParticipant (const Address &addr } void ClientGroupChatRoom::addParticipants (const list
    &addresses, const CallSessionParams *params, bool hasMedia) { + L_D(ClientGroupChatRoom); + if (d->state == ChatRoom::State::Instantiated) { + shared_ptr session = focus->getPrivate()->getSession(); + session->initiateOutgoing(); + session->startInvite(nullptr); + d->setState(ChatRoom::State::CreationPending); + } // TODO } bool ClientGroupChatRoom::canHandleParticipants () const { - return true; + return RemoteConference::canHandleParticipants(); } const string& ClientGroupChatRoom::getId () const { - return id; + return RemoteConference::getId(); } int ClientGroupChatRoom::getNbParticipants () const { - // TODO - return 1; + return RemoteConference::getNbParticipants(); } list> ClientGroupChatRoom::getParticipants () const { - return participants; + return RemoteConference::getParticipants(); } void ClientGroupChatRoom::removeParticipant (const shared_ptr &participant) { diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index 5dacb98f2..aa31265c4 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -35,7 +35,7 @@ class ClientGroupChatRoomPrivate; class ClientGroupChatRoom : public ChatRoom, public RemoteConference { public: - ClientGroupChatRoom (LinphoneCore *core, const Address &me, std::list
    &addresses); + ClientGroupChatRoom (LinphoneCore *core, const Address &me); virtual ~ClientGroupChatRoom () = default; public: From dd6db1933557001eb830a0605afb3253502a06f5 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 22 Sep 2017 11:35:21 +0200 Subject: [PATCH 0140/2215] feat(c-wrapper): remove TYPE parameter of L_GET_C_LIST_FROM_CPP_LIST --- src/c-wrapper/api/c-chat-room.cpp | 6 +++--- src/c-wrapper/internal/c-tools.h | 33 ++++++++++++++++++++----------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 65f5c9b25..a2041e866 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -166,7 +166,7 @@ void linphone_chat_room_set_call (LinphoneChatRoom *cr, LinphoneCall *call) { } bctbx_list_t *linphone_chat_room_get_transient_messages (const LinphoneChatRoom *cr) { - return L_GET_C_LIST_FROM_CPP_LIST(GET_CPP_PRIVATE_PTR(cr)->getTransientMessages(), LinphoneChatMessage); + return L_GET_C_LIST_FROM_CPP_LIST(GET_CPP_PRIVATE_PTR(cr)->getTransientMessages()); } void linphone_chat_room_mark_as_read (LinphoneChatRoom *cr) { @@ -190,11 +190,11 @@ void linphone_chat_room_delete_history (LinphoneChatRoom *cr) { } bctbx_list_t *linphone_chat_room_get_history_range (LinphoneChatRoom *cr, int startm, int endm) { - return L_GET_C_LIST_FROM_CPP_LIST(GET_CPP_PTR(cr)->getHistoryRange(startm, endm), LinphoneChatMessage); + return L_GET_C_LIST_FROM_CPP_LIST(GET_CPP_PTR(cr)->getHistoryRange(startm, endm)); } bctbx_list_t *linphone_chat_room_get_history (LinphoneChatRoom *cr, int nb_message) { - return L_GET_C_LIST_FROM_CPP_LIST(GET_CPP_PTR(cr)->getHistory(nb_message), LinphoneChatMessage); + return L_GET_C_LIST_FROM_CPP_LIST(GET_CPP_PTR(cr)->getHistory(nb_message)); } LinphoneChatMessage *linphone_chat_room_find_message (LinphoneChatRoom *cr, const char *message_id) { diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 10821be11..3c61e27de 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -155,6 +155,10 @@ public: return cppPtr; } + // --------------------------------------------------------------------------- + // Get c back ptr helpers. + // --------------------------------------------------------------------------- + template static inline CType *getCBackPtr (const std::shared_ptr &object, CType *(*cTypeAllocator)()) { Variant v = object->getProperty("LinphonePrivate::Wrapper::cBackPtr"); @@ -177,6 +181,8 @@ public: return reinterpret_cast(value); } + // --------------------------------------------------------------------------- + // Get/set user data. // --------------------------------------------------------------------------- template @@ -203,16 +209,26 @@ public: object->setProperty("LinphonePrivate::Wrapper::userData", value); } + // --------------------------------------------------------------------------- + // List helpers. // --------------------------------------------------------------------------- template - static inline bctbx_list_t *getCListFromCppList (const std::list cppList) { + static inline bctbx_list_t *getCListFromCppList (const std::list &cppList) { bctbx_list_t *result = nullptr; for (const auto &value : cppList) result = bctbx_list_append(result, value); return result; } + template + static inline std::list getCppListFromCList (const bctbx_list_t *cList) { + std::list result; + for (auto it = cList; it; it = bctbx_list_next(it)) + result.push_back(static_cast(bctbx_list_get_data(it))); + return result; + } + template static inline bctbx_list_t *getCListOfStructPtrFromCppListOfCppObj (const std::list> cppList, CType *(*cTypeAllocator)()) { bctbx_list_t *result = nullptr; @@ -229,14 +245,6 @@ public: return result; } - template - static inline std::list getCppListFromCList (const bctbx_list_t *cList) { - std::list result; - for (auto it = cList; it; it = bctbx_list_next(it)) - result.push_back(static_cast(bctbx_list_get_data(it))); - return result; - } - template< typename CppType, typename CType, @@ -432,10 +440,11 @@ LINPHONE_END_NAMESPACE VALUE \ ) -#define L_GET_C_LIST_FROM_CPP_LIST(LIST, TYPE) \ - LINPHONE_NAMESPACE::Wrapper::getCListFromCppList(LIST) +#define L_GET_C_LIST_FROM_CPP_LIST(LIST) \ + LINPHONE_NAMESPACE::Wrapper::getCListFromCppList(LIST) #define L_GET_CPP_LIST_FROM_C_LIST(LIST, TYPE) \ - LINPHONE_NAMESPACE::Wrapper::getCppListFromCList(LIST) + LINPHONE_NAMESPACE::Wrapper::getCppListFromCList(LIST) + #define L_GET_C_LIST_OF_STRUCT_PTR_FROM_CPP_LIST_OF_CPP_OBJ(LIST, CPP_TYPE, C_TYPE) \ LINPHONE_NAMESPACE::Wrapper::getCListOfStructPtrFromCppListOfCppObj(LIST, _linphone_ ## C_TYPE ## _init) #define L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(LIST, CPP_TYPE, C_TYPE) \ From 49979626248b72332f9c4badee97b581f0a79fc5 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 22 Sep 2017 14:38:00 +0200 Subject: [PATCH 0141/2215] feat(c-wrapper): remove C_TYPE parameter of L_GET_C_BACK_PTR --- src/c-wrapper/api/c-chat-room.cpp | 4 +- src/c-wrapper/api/c-event-log.cpp | 5 +- src/c-wrapper/internal/c-tools.h | 136 +++++++++++++++----------- src/chat/chat-message.cpp | 4 +- src/chat/chat-room.cpp | 2 +- src/chat/client-group-chat-room.cpp | 14 +-- src/chat/real-time-text-chat-room.cpp | 2 +- 7 files changed, 92 insertions(+), 75 deletions(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index a2041e866..af8c7090c 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -211,8 +211,8 @@ LinphoneChatRoomState linphone_chat_room_get_state (const LinphoneChatRoom *cr) LinphoneParticipant *linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr) { return L_GET_C_BACK_PTR(GET_CPP_PTR(cr)->addParticipant( - *L_GET_CPP_PTR_FROM_C_OBJECT(addr), nullptr, false), - Participant); + *L_GET_CPP_PTR_FROM_C_OBJECT(addr), nullptr, false) + ); } void linphone_chat_room_add_participants (LinphoneChatRoom *cr, const bctbx_list_t *addresses) { diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 753e3f43a..873988e0a 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -75,7 +75,7 @@ LinphoneCallEvent *linphone_call_event_new (LinphoneEventLogType type, LinphoneC LinphoneCall *linphone_call_event_get_call (const LinphoneCallEvent *call_event) { return L_GET_C_BACK_PTR( - L_GET_CPP_PTR_FROM_C_OBJECT(call_event)->getCall(), Call + L_GET_CPP_PTR_FROM_C_OBJECT(call_event)->getCall() ); } @@ -133,7 +133,6 @@ LinphoneChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage * LinphoneChatMessage *linphone_chat_message_event_get_chat_message (const LinphoneChatMessageEvent *chat_message_event) { return L_GET_C_BACK_PTR( - L_GET_CPP_PTR_FROM_C_OBJECT(chat_message_event)->getChatMessage(), - ChatMessage + L_GET_CPP_PTR_FROM_C_OBJECT(chat_message_event)->getChatMessage() ); } diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 3c61e27de..4ccea66b6 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -43,6 +43,9 @@ struct CTypeToCppType { enum { defined = false }; }; +template +struct CObjectInitializer {}; + class Wrapper { private: template @@ -58,18 +61,22 @@ private: }; public: + // --------------------------------------------------------------------------- + // Get private data of cpp Object. + // --------------------------------------------------------------------------- + template - static inline decltype (std::declval().getPrivate()) getPrivate (T *object) { - if (!object) + static inline decltype (std::declval().getPrivate()) getPrivate (T *cppObject) { + if (!cppObject) return nullptr; - return object->getPrivate(); + return cppObject->getPrivate(); } template - static inline decltype (std::declval().getPrivate()) getPrivate (const std::shared_ptr &object) { - if (!object) + static inline decltype (std::declval().getPrivate()) getPrivate (const std::shared_ptr &cppObject) { + if (!cppObject) return nullptr; - return object->getPrivate(); + return cppObject->getPrivate(); } // --------------------------------------------------------------------------- @@ -81,9 +88,9 @@ public: typename CType, typename = typename std::enable_if::value, CppType>::type > - static inline std::shared_ptr getCppPtrFromC (CType *object) { - L_ASSERT(object); - return reinterpret_cast *>(object)->cppPtr; + static inline std::shared_ptr getCppPtrFromC (CType *cObject) { + L_ASSERT(cObject); + return reinterpret_cast *>(cObject)->cppPtr; } template< @@ -91,9 +98,9 @@ public: typename CType, typename = typename std::enable_if::value, CppType>::type > - static inline std::shared_ptr getCppPtrFromC (const CType *object) { - L_ASSERT(object); - return reinterpret_cast *>(object)->cppPtr; + static inline std::shared_ptr getCppPtrFromC (const CType *cObject) { + L_ASSERT(cObject); + return reinterpret_cast *>(cObject)->cppPtr; } template< @@ -101,9 +108,9 @@ public: typename CType, typename = typename std::enable_if::value, CppType>::type > - static inline CppType *getCppPtrFromC (CType *object) { - L_ASSERT(object); - return reinterpret_cast *>(object)->cppPtr; + static inline CppType *getCppPtrFromC (CType *cObject) { + L_ASSERT(cObject); + return reinterpret_cast *>(cObject)->cppPtr; } template< @@ -111,74 +118,80 @@ public: typename CType, typename = typename std::enable_if::value, CppType>::type > - static inline const CppType *getCppPtrFromC (const CType *object) { - L_ASSERT(object); - return reinterpret_cast *>(object)->cppPtr; + static inline const CppType *getCppPtrFromC (const CType *cObject) { + L_ASSERT(cObject); + return reinterpret_cast *>(cObject)->cppPtr; } template - static inline void setCppPtrFromC (void *object, const std::shared_ptr &cppPtr) { - L_ASSERT(object); - static_cast *>(object)->cppPtr = cppPtr; - cppPtr->setProperty("LinphonePrivate::Wrapper::cBackPtr", object); + static inline void setCppPtrFromC (void *cObject, const std::shared_ptr &cppObject) { + L_ASSERT(cObject); + static_cast *>(cObject)->cppPtr = cppObject; + cppObject->setProperty("LinphonePrivate::Wrapper::cBackPtr", cObject); } template - static inline void setCppPtrFromC (void *object, const T *cppPtr) { - L_ASSERT(object); - T *oldPtr = reinterpret_cast(static_cast *>(object)->cppPtr); - if (oldPtr != cppPtr) { + static inline void setCppPtrFromC (void *cObject, const T *cppObject) { + L_ASSERT(cObject); + T *oldPtr = reinterpret_cast(static_cast *>(cObject)->cppPtr); + if (oldPtr != cppObject) { delete oldPtr; - T **cppObject = &static_cast *>(object)->cppPtr; - *cppObject = new T(*cppPtr); - (*cppObject)->setProperty("LinphonePrivate::Wrapper::cBackPtr", object); + T **cppPtr = &static_cast *>(cObject)->cppPtr; + *cppPtr = new T(*cppObject); + (*cppPtr)->setProperty("LinphonePrivate::Wrapper::cBackPtr", cObject); } } template - static T *getCppPtr (const std::shared_ptr &cppPtr) { - return cppPtr.get(); + static T *getCppPtr (const std::shared_ptr &cppObject) { + return cppObject.get(); } template - static T *getCppPtr (T *cppPtr) { - return cppPtr; + static T *getCppPtr (T *cppObject) { + return cppObject; } template - static const T *getCppPtr (const std::shared_ptr &cppPtr) { - return cppPtr.get(); + static const T *getCppPtr (const std::shared_ptr &cppObject) { + return cppObject.get(); } template - static const T *getCppPtr (const T *cppPtr) { - return cppPtr; + static const T *getCppPtr (const T *cppObject) { + return cppObject; } // --------------------------------------------------------------------------- // Get c back ptr helpers. // --------------------------------------------------------------------------- - template - static inline CType *getCBackPtr (const std::shared_ptr &object, CType *(*cTypeAllocator)()) { - Variant v = object->getProperty("LinphonePrivate::Wrapper::cBackPtr"); + template + static inline typename CppTypeToCType::type *getCBackPtr (const std::shared_ptr &cppObject) { + typedef typename CppTypeToCType::type RetType; + + Variant v = cppObject->getProperty("LinphonePrivate::Wrapper::cBackPtr"); void *value = v.getValue(); if (!value) { - CType *cObject = cTypeAllocator(); - setCppPtrFromC(cObject, object); + RetType *cObject = CObjectInitializer::init(); + setCppPtrFromC(cObject, cppObject); } - return reinterpret_cast(value); + + return reinterpret_cast(value); } - template - static inline CType *getCBackPtr (const CppType *object, CType *(*cTypeAllocator)()) { - Variant v = object->getProperty("LinphonePrivate::Wrapper::cBackPtr"); + template + static inline typename CppTypeToCType::type *getCBackPtr (const CppType *cppObject) { + typedef typename CppTypeToCType::type RetType; + + Variant v = cppObject->getProperty("LinphonePrivate::Wrapper::cBackPtr"); void *value = v.getValue(); if (!value) { - CType *cObject = cTypeAllocator(); - setCppPtrFromC(cObject, object); + RetType *cObject = CObjectInitializer::init(); + setCppPtrFromC(cObject, cppObject); } - return reinterpret_cast(value); + + return reinterpret_cast(value); } // --------------------------------------------------------------------------- @@ -233,7 +246,7 @@ public: static inline bctbx_list_t *getCListOfStructPtrFromCppListOfCppObj (const std::list> cppList, CType *(*cTypeAllocator)()) { bctbx_list_t *result = nullptr; for (const auto &value : cppList) - result = bctbx_list_append(result, getCBackPtr(value, cTypeAllocator)); + result = bctbx_list_append(result, getCBackPtr(value)); return result; } @@ -241,7 +254,7 @@ public: static inline bctbx_list_t *getCListOfStructPtrFromCppListOfCppObj (const std::list cppList, CType *(*cTypeAllocator)()) { bctbx_list_t *result = nullptr; for (const auto &value : cppList) - result = bctbx_list_append(result, getCBackPtr(value, cTypeAllocator)); + result = bctbx_list_append(result, getCBackPtr(value)); return result; } @@ -323,6 +336,12 @@ LINPHONE_END_NAMESPACE enum { defined = true }; \ typedef CPP_TYPE type; \ }; \ + template<> \ + struct CObjectInitializer { \ + static Linphone ## C_TYPE *init () { \ + return _linphone_ ## C_TYPE ## _init(); \ + } \ + }; \ LINPHONE_END_NAMESPACE #define L_ASSERT_C_TYPE(C_TYPE) \ @@ -424,10 +443,8 @@ LINPHONE_END_NAMESPACE )) // Get the wrapped C object of a C++ object. -#define L_GET_C_BACK_PTR(C_OBJECT, C_TYPE) \ - LINPHONE_NAMESPACE::Wrapper::getCBackPtr( \ - C_OBJECT, _linphone_ ## C_TYPE ## _init \ - ) +#define L_GET_C_BACK_PTR(C_OBJECT) \ + LINPHONE_NAMESPACE::Wrapper::getCBackPtr(C_OBJECT) // Get/set user data on a wrapped C object. #define L_GET_USER_DATA_FROM_C_OBJECT(C_OBJECT) \ @@ -440,10 +457,11 @@ LINPHONE_END_NAMESPACE VALUE \ ) -#define L_GET_C_LIST_FROM_CPP_LIST(LIST) \ - LINPHONE_NAMESPACE::Wrapper::getCListFromCppList(LIST) -#define L_GET_CPP_LIST_FROM_C_LIST(LIST, TYPE) \ - LINPHONE_NAMESPACE::Wrapper::getCppListFromCList(LIST) +// Transforms cpp list and c list. +#define L_GET_C_LIST_FROM_CPP_LIST(CPP_LIST) \ + LINPHONE_NAMESPACE::Wrapper::getCListFromCppList(CPP_LIST) +#define L_GET_CPP_LIST_FROM_C_LIST(C_LIST, TYPE) \ + LINPHONE_NAMESPACE::Wrapper::getCppListFromCList(C_LIST) #define L_GET_C_LIST_OF_STRUCT_PTR_FROM_CPP_LIST_OF_CPP_OBJ(LIST, CPP_TYPE, C_TYPE) \ LINPHONE_NAMESPACE::Wrapper::getCListOfStructPtrFromCppListOfCppObj(LIST, _linphone_ ## C_TYPE ## _init) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index a38ca9fd5..5d1a83f97 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -31,7 +31,7 @@ #include "modifier/cpim-chat-message-modifier.h" #include "chat-room.h" -#define GET_BACK_PTR(object) L_GET_C_BACK_PTR(object->shared_from_this(), ChatMessage) +#define GET_BACK_PTR(object) L_GET_C_BACK_PTR(static_pointer_cast(object->shared_from_this())) // ============================================================================= @@ -45,7 +45,7 @@ ChatMessagePrivate::ChatMessagePrivate (const std::shared_ptr &room) : chatRoom(room) {} ChatMessagePrivate::~ChatMessagePrivate () {} - + // ----------------------------------------------------------------------------- ChatMessage::ChatMessage (const std::shared_ptr &room) : Object(*new ChatMessagePrivate(room)) {} diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 97e78cef1..be08d9302 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -30,7 +30,7 @@ #include "chat-message.h" #include "chat-room.h" -#define GET_BACK_PTR(object) L_GET_C_BACK_PTR(object->shared_from_this(), ChatRoom) +#define GET_BACK_PTR(object) L_GET_C_BACK_PTR(static_pointer_cast(object->shared_from_this())) // ============================================================================= diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index b413930d9..85f2a8b80 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -56,7 +56,7 @@ void ClientGroupChatRoom::addParticipants (const list
    &addresses, const session->initiateOutgoing(); session->startInvite(nullptr); d->setState(ChatRoom::State::CreationPending); - } + } // TODO } @@ -102,11 +102,11 @@ void ClientGroupChatRoom::onParticipantAdded (const Address &addr) { } participant = make_shared(addr); participants.push_back(participant); - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this->shared_from_this(), ChatRoom); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(static_pointer_cast(this->shared_from_this())); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAddedCb cb = linphone_chat_room_cbs_get_participant_added(cbs); if (cb) - cb(cr, L_GET_C_BACK_PTR(participant, Participant)); + cb(cr, L_GET_C_BACK_PTR(participant)); } void ClientGroupChatRoom::onParticipantRemoved (const Address &addr) { @@ -115,11 +115,11 @@ void ClientGroupChatRoom::onParticipantRemoved (const Address &addr) { lWarning() << "Participant " << participant << " removed but not in the list of participants!"; return; } - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this->shared_from_this(), ChatRoom); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(static_pointer_cast(this->shared_from_this())); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantRemovedCb cb = linphone_chat_room_cbs_get_participant_removed(cbs); if (cb) - cb(cr, L_GET_C_BACK_PTR(participant, Participant)); + cb(cr, L_GET_C_BACK_PTR(participant)); participants.remove(participant); } @@ -130,11 +130,11 @@ void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdm return; } participant->setAdmin(isAdmin); - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this->shared_from_this(), ChatRoom); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(static_pointer_cast(this->shared_from_this())); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAdminStatusChangedCb cb = linphone_chat_room_cbs_get_participant_admin_status_changed(cbs); if (cb) - cb(cr, L_GET_C_BACK_PTR(participant, Participant), isAdmin); + cb(cr, L_GET_C_BACK_PTR(participant), isAdmin); } LINPHONE_END_NAMESPACE diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index b1d75d301..fe17f942d 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -24,7 +24,7 @@ #include "c-wrapper/c-wrapper.h" #include "logger/logger.h" -#define GET_BACK_PTR(object) L_GET_C_BACK_PTR(object->shared_from_this(), ChatRoom) +#define GET_BACK_PTR(object) L_GET_C_BACK_PTR(static_pointer_cast(object->shared_from_this())) // ============================================================================= From a1db41d2743116a630636c2b0516eaede4487e31 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 22 Sep 2017 14:47:15 +0200 Subject: [PATCH 0142/2215] feat(c-wrapper/api): remove useless define GET_xxx --- src/c-wrapper/api/c-call-params.cpp | 189 +++++++++++++-------------- src/c-wrapper/api/c-call.cpp | 137 ++++++++++--------- src/c-wrapper/api/c-chat-message.cpp | 3 - src/c-wrapper/api/c-chat-room.cpp | 67 +++++----- 4 files changed, 192 insertions(+), 204 deletions(-) diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index e6573061e..e4415fb73 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -22,9 +22,6 @@ // ============================================================================= -#define GET_MEDIA_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_OBJECT(obj) -#define GET_MEDIA_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_OBJECT(obj) - L_DECLARE_C_CLONABLE_STRUCT_IMPL(CallParams) using namespace std; @@ -34,7 +31,7 @@ using namespace std; // ============================================================================= SalMediaProto get_proto_from_call_params (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->getMediaProto(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getMediaProto(); } SalStreamDir sal_dir_from_call_params_dir (LinphoneMediaDirection cpdir) { @@ -77,15 +74,15 @@ SalStreamDir get_video_dir_from_call_params (const LinphoneCallParams *params) { } void linphone_call_params_set_custom_headers (LinphoneCallParams *params, const SalCustomHeader *ch) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setCustomHeaders(ch); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setCustomHeaders(ch); } void linphone_call_params_set_custom_sdp_attributes (LinphoneCallParams *params, const SalCustomSdpAttribute *csa) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setCustomSdpAttributes(csa); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setCustomSdpAttributes(csa); } void linphone_call_params_set_custom_sdp_media_attributes (LinphoneCallParams *params, LinphoneStreamType type, const SalCustomSdpAttribute *csa) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setCustomSdpMediaAttributes(type, csa); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setCustomSdpMediaAttributes(type, csa); } // ============================================================================= @@ -93,23 +90,23 @@ void linphone_call_params_set_custom_sdp_media_attributes (LinphoneCallParams *p // ============================================================================= void linphone_call_params_add_custom_header (LinphoneCallParams *params, const char *header_name, const char *header_value) { - GET_MEDIA_CPP_PTR(params)->addCustomHeader(header_name, header_value); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->addCustomHeader(header_name, header_value); } void linphone_call_params_add_custom_sdp_attribute (LinphoneCallParams *params, const char *attribute_name, const char *attribute_value) { - GET_MEDIA_CPP_PTR(params)->addCustomSdpAttribute(attribute_name, attribute_value); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->addCustomSdpAttribute(attribute_name, attribute_value); } void linphone_call_params_add_custom_sdp_media_attribute (LinphoneCallParams *params, LinphoneStreamType type, const char *attribute_name, const char *attribute_value) { - GET_MEDIA_CPP_PTR(params)->addCustomSdpMediaAttribute(type, attribute_name, attribute_value); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->addCustomSdpMediaAttribute(type, attribute_name, attribute_value); } void linphone_call_params_clear_custom_sdp_attributes (LinphoneCallParams *params) { - GET_MEDIA_CPP_PTR(params)->clearCustomSdpAttributes(); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->clearCustomSdpAttributes(); } void linphone_call_params_clear_custom_sdp_media_attributes (LinphoneCallParams *params, LinphoneStreamType type) { - GET_MEDIA_CPP_PTR(params)->clearCustomSdpMediaAttributes(type); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->clearCustomSdpMediaAttributes(type); } LinphoneCallParams *linphone_call_params_copy (const LinphoneCallParams *params) { @@ -117,42 +114,42 @@ LinphoneCallParams *linphone_call_params_copy (const LinphoneCallParams *params) } bool_t linphone_call_params_early_media_sending_enabled (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->earlyMediaSendingEnabled(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->earlyMediaSendingEnabled(); } void linphone_call_params_enable_early_media_sending (LinphoneCallParams *params, bool_t enabled) { - GET_MEDIA_CPP_PTR(params)->enableEarlyMediaSending(enabled); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableEarlyMediaSending(enabled); } void linphone_call_params_enable_low_bandwidth (LinphoneCallParams *params, bool_t enabled) { - GET_MEDIA_CPP_PTR(params)->enableLowBandwidth(enabled); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableLowBandwidth(enabled); } void linphone_call_params_enable_audio (LinphoneCallParams *params, bool_t enabled) { - GET_MEDIA_CPP_PTR(params)->enableAudio(enabled); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableAudio(enabled); } LinphoneStatus linphone_call_params_enable_realtime_text (LinphoneCallParams *params, bool_t yesno) { - GET_MEDIA_CPP_PTR(params)->enableRealtimeText(yesno); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableRealtimeText(yesno); return 0; } void linphone_call_params_enable_video (LinphoneCallParams *params, bool_t enabled) { - GET_MEDIA_CPP_PTR(params)->enableVideo(enabled); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableVideo(enabled); } const char *linphone_call_params_get_custom_header (const LinphoneCallParams *params, const char *header_name) { - string value = GET_MEDIA_CPP_PTR(params)->getCustomHeader(header_name); + string value = L_GET_CPP_PTR_FROM_C_OBJECT(params)->getCustomHeader(header_name); return value.empty() ? nullptr : value.c_str(); } const char *linphone_call_params_get_custom_sdp_attribute (const LinphoneCallParams *params, const char *attribute_name) { - string value = GET_MEDIA_CPP_PTR(params)->getCustomSdpAttribute(attribute_name); + string value = L_GET_CPP_PTR_FROM_C_OBJECT(params)->getCustomSdpAttribute(attribute_name); return value.empty() ? nullptr : value.c_str(); } const char *linphone_call_params_get_custom_sdp_media_attribute (const LinphoneCallParams *params, LinphoneStreamType type, const char *attribute_name) { - string value = GET_MEDIA_CPP_PTR(params)->getCustomSdpMediaAttribute(type, attribute_name); + string value = L_GET_CPP_PTR_FROM_C_OBJECT(params)->getCustomSdpMediaAttribute(type, attribute_name); return value.empty() ? nullptr : value.c_str(); } @@ -161,20 +158,20 @@ bool_t linphone_call_params_get_local_conference_mode (const LinphoneCallParams } LinphoneMediaEncryption linphone_call_params_get_media_encryption (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->getMediaEncryption(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getMediaEncryption(); } LinphonePrivacyMask linphone_call_params_get_privacy (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->getPrivacy(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getPrivacy(); } float linphone_call_params_get_received_framerate (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->getReceivedFps(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getReceivedFps(); } MSVideoSize linphone_call_params_get_received_video_size (const LinphoneCallParams *params) { MSVideoSize vsize; - LinphoneVideoDefinition *vdef = GET_MEDIA_CPP_PTR(params)->getReceivedVideoDefinition(); + LinphoneVideoDefinition *vdef = L_GET_CPP_PTR_FROM_C_OBJECT(params)->getReceivedVideoDefinition(); if (vdef) { vsize.width = static_cast(linphone_video_definition_get_width(vdef)); vsize.height = static_cast(linphone_video_definition_get_height(vdef)); @@ -186,25 +183,25 @@ MSVideoSize linphone_call_params_get_received_video_size (const LinphoneCallPara } const LinphoneVideoDefinition *linphone_call_params_get_received_video_definition (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->getReceivedVideoDefinition(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getReceivedVideoDefinition(); } const char *linphone_call_params_get_record_file (const LinphoneCallParams *params) { - const string &value = GET_MEDIA_CPP_PTR(params)->getRecordFilePath(); + const string &value = L_GET_CPP_PTR_FROM_C_OBJECT(params)->getRecordFilePath(); return value.empty() ? nullptr : value.c_str(); } const char *linphone_call_params_get_rtp_profile (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->getRtpProfile(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getRtpProfile(); } float linphone_call_params_get_sent_framerate (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->getSentFps(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getSentFps(); } MSVideoSize linphone_call_params_get_sent_video_size (const LinphoneCallParams *params) { MSVideoSize vsize; - LinphoneVideoDefinition *vdef = GET_MEDIA_CPP_PTR(params)->getSentVideoDefinition(); + LinphoneVideoDefinition *vdef = L_GET_CPP_PTR_FROM_C_OBJECT(params)->getSentVideoDefinition(); if (vdef) { vsize.width = static_cast(linphone_video_definition_get_width(vdef)); vsize.height = static_cast(linphone_video_definition_get_height(vdef)); @@ -216,156 +213,156 @@ MSVideoSize linphone_call_params_get_sent_video_size (const LinphoneCallParams * } const LinphoneVideoDefinition *linphone_call_params_get_sent_video_definition (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->getSentVideoDefinition(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getSentVideoDefinition(); } const char *linphone_call_params_get_session_name (const LinphoneCallParams *params) { - const string &value = GET_MEDIA_CPP_PTR(params)->getSessionName(); + const string &value = L_GET_CPP_PTR_FROM_C_OBJECT(params)->getSessionName(); return value.empty() ? nullptr : value.c_str(); } LinphonePayloadType *linphone_call_params_get_used_audio_payload_type (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->getUsedAudioPayloadType(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getUsedAudioPayloadType(); } LinphonePayloadType *linphone_call_params_get_used_video_payload_type (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->getUsedVideoPayloadType(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getUsedVideoPayloadType(); } LinphonePayloadType *linphone_call_params_get_used_text_payload_type (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->getUsedRealtimeTextPayloadType(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getUsedRealtimeTextPayloadType(); } const OrtpPayloadType *linphone_call_params_get_used_audio_codec (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->getUsedAudioCodec(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getUsedAudioCodec(); } void linphone_call_params_set_used_audio_codec (LinphoneCallParams *params, OrtpPayloadType *codec) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setUsedAudioCodec(codec); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setUsedAudioCodec(codec); } const OrtpPayloadType *linphone_call_params_get_used_video_codec (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->getUsedVideoCodec(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getUsedVideoCodec(); } void linphone_call_params_set_used_video_codec (LinphoneCallParams *params, OrtpPayloadType *codec) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setUsedVideoCodec(codec); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setUsedVideoCodec(codec); } const OrtpPayloadType *linphone_call_params_get_used_text_codec (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->getUsedRealtimeTextCodec(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getUsedRealtimeTextCodec(); } void linphone_call_params_set_used_text_codec (LinphoneCallParams *params, OrtpPayloadType *codec) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setUsedRealtimeTextCodec(codec); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setUsedRealtimeTextCodec(codec); } bool_t linphone_call_params_low_bandwidth_enabled (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->lowBandwidthEnabled(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->lowBandwidthEnabled(); } int linphone_call_params_get_audio_bandwidth_limit (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->getAudioBandwidthLimit(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getAudioBandwidthLimit(); } void linphone_call_params_set_audio_bandwidth_limit (LinphoneCallParams *params, int bandwidth) { - GET_MEDIA_CPP_PTR(params)->setAudioBandwidthLimit(bandwidth); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->setAudioBandwidthLimit(bandwidth); } void linphone_call_params_set_media_encryption (LinphoneCallParams *params, LinphoneMediaEncryption encryption) { - GET_MEDIA_CPP_PTR(params)->setMediaEncryption(encryption); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->setMediaEncryption(encryption); } void linphone_call_params_set_privacy (LinphoneCallParams *params, LinphonePrivacyMask privacy) { - GET_MEDIA_CPP_PTR(params)->setPrivacy(privacy); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->setPrivacy(privacy); } void linphone_call_params_set_record_file (LinphoneCallParams *params, const char *path) { - GET_MEDIA_CPP_PTR(params)->setRecordFilePath(path ? path : ""); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->setRecordFilePath(path ? path : ""); } void linphone_call_params_set_session_name (LinphoneCallParams *params, const char *name) { - GET_MEDIA_CPP_PTR(params)->setSessionName(name ? name : ""); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->setSessionName(name ? name : ""); } bool_t linphone_call_params_audio_enabled (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->audioEnabled(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->audioEnabled(); } bool_t linphone_call_params_realtime_text_enabled (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->realtimeTextEnabled(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->realtimeTextEnabled(); } bool_t linphone_call_params_video_enabled (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->videoEnabled(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->videoEnabled(); } LinphoneMediaDirection linphone_call_params_get_audio_direction (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->getAudioDirection(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getAudioDirection(); } LinphoneMediaDirection linphone_call_params_get_video_direction (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->getVideoDirection(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getVideoDirection(); } void linphone_call_params_set_audio_direction (LinphoneCallParams *params, LinphoneMediaDirection dir) { - GET_MEDIA_CPP_PTR(params)->setAudioDirection(dir); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->setAudioDirection(dir); } void linphone_call_params_set_video_direction (LinphoneCallParams *params, LinphoneMediaDirection dir) { - GET_MEDIA_CPP_PTR(params)->setVideoDirection(dir); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->setVideoDirection(dir); } void linphone_call_params_enable_audio_multicast (LinphoneCallParams *params, bool_t yesno) { - GET_MEDIA_CPP_PTR(params)->enableAudioMulticast(yesno); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableAudioMulticast(yesno); } bool_t linphone_call_params_audio_multicast_enabled (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->audioMulticastEnabled(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->audioMulticastEnabled(); } void linphone_call_params_enable_video_multicast (LinphoneCallParams *params, bool_t yesno) { - GET_MEDIA_CPP_PTR(params)->enableVideoMulticast(yesno); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableVideoMulticast(yesno); } bool_t linphone_call_params_video_multicast_enabled (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->videoMulticastEnabled(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->videoMulticastEnabled(); } bool_t linphone_call_params_real_early_media_enabled (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->earlyMediaSendingEnabled(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->earlyMediaSendingEnabled(); } bool_t linphone_call_params_avpf_enabled (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->avpfEnabled(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->avpfEnabled(); } void linphone_call_params_enable_avpf (LinphoneCallParams *params, bool_t enable) { - GET_MEDIA_CPP_PTR(params)->enableAvpf(enable); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableAvpf(enable); } bool_t linphone_call_params_mandatory_media_encryption_enabled (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->mandatoryMediaEncryptionEnabled(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->mandatoryMediaEncryptionEnabled(); } void linphone_call_params_enable_mandatory_media_encryption (LinphoneCallParams *params, bool_t value) { - GET_MEDIA_CPP_PTR(params)->enableMandatoryMediaEncryption(value); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableMandatoryMediaEncryption(value); } uint16_t linphone_call_params_get_avpf_rr_interval (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PTR(params)->getAvpfRrInterval(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getAvpfRrInterval(); } void linphone_call_params_set_avpf_rr_interval (LinphoneCallParams *params, uint16_t value) { - GET_MEDIA_CPP_PTR(params)->setAvpfRrInterval(value); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->setAvpfRrInterval(value); } void linphone_call_params_set_sent_fps (LinphoneCallParams *params, float value) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setSentFps(value); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setSentFps(value); } void linphone_call_params_set_received_fps (LinphoneCallParams *params, float value) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setReceivedFps(value); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setReceivedFps(value); } // ============================================================================= @@ -373,111 +370,111 @@ void linphone_call_params_set_received_fps (LinphoneCallParams *params, float va // ============================================================================= bool_t linphone_call_params_get_in_conference (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PRIVATE_PTR(params)->getInConference(); + return L_GET_PRIVATE_FROM_C_OBJECT(params)->getInConference(); } void linphone_call_params_set_in_conference (LinphoneCallParams *params, bool_t value) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setInConference(value); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setInConference(value); } bool_t linphone_call_params_get_internal_call_update (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PRIVATE_PTR(params)->getInternalCallUpdate(); + return L_GET_PRIVATE_FROM_C_OBJECT(params)->getInternalCallUpdate(); } void linphone_call_params_set_internal_call_update (LinphoneCallParams *params, bool_t value) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setInternalCallUpdate(value); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setInternalCallUpdate(value); } bool_t linphone_call_params_implicit_rtcp_fb_enabled (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PRIVATE_PTR(params)->implicitRtcpFbEnabled(); + return L_GET_PRIVATE_FROM_C_OBJECT(params)->implicitRtcpFbEnabled(); } void linphone_call_params_enable_implicit_rtcp_fb (LinphoneCallParams *params, bool_t value) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->enableImplicitRtcpFb(value); + L_GET_PRIVATE_FROM_C_OBJECT(params)->enableImplicitRtcpFb(value); } int linphone_call_params_get_down_bandwidth (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PRIVATE_PTR(params)->getDownBandwidth(); + return L_GET_PRIVATE_FROM_C_OBJECT(params)->getDownBandwidth(); } void linphone_call_params_set_down_bandwidth (LinphoneCallParams *params, int value) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setDownBandwidth(value); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setDownBandwidth(value); } int linphone_call_params_get_up_bandwidth (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PRIVATE_PTR(params)->getUpBandwidth(); + return L_GET_PRIVATE_FROM_C_OBJECT(params)->getUpBandwidth(); } void linphone_call_params_set_up_bandwidth (LinphoneCallParams *params, int value) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setUpBandwidth(value); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setUpBandwidth(value); } int linphone_call_params_get_down_ptime (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PRIVATE_PTR(params)->getDownPtime(); + return L_GET_PRIVATE_FROM_C_OBJECT(params)->getDownPtime(); } void linphone_call_params_set_down_ptime (LinphoneCallParams *params, int value) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setDownPtime(value); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setDownPtime(value); } int linphone_call_params_get_up_ptime (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PRIVATE_PTR(params)->getUpPtime(); + return L_GET_PRIVATE_FROM_C_OBJECT(params)->getUpPtime(); } void linphone_call_params_set_up_ptime (LinphoneCallParams *params, int value) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setUpPtime(value); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setUpPtime(value); } SalCustomHeader *linphone_call_params_get_custom_headers (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PRIVATE_PTR(params)->getCustomHeaders(); + return L_GET_PRIVATE_FROM_C_OBJECT(params)->getCustomHeaders(); } SalCustomSdpAttribute *linphone_call_params_get_custom_sdp_attributes (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PRIVATE_PTR(params)->getCustomSdpAttributes(); + return L_GET_PRIVATE_FROM_C_OBJECT(params)->getCustomSdpAttributes(); } SalCustomSdpAttribute *linphone_call_params_get_custom_sdp_media_attributes (const LinphoneCallParams *params, LinphoneStreamType type) { - return GET_MEDIA_CPP_PRIVATE_PTR(params)->getCustomSdpMediaAttributes(type); + return L_GET_PRIVATE_FROM_C_OBJECT(params)->getCustomSdpMediaAttributes(type); } LinphoneCall *linphone_call_params_get_referer (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PRIVATE_PTR(params)->getReferer(); + return L_GET_PRIVATE_FROM_C_OBJECT(params)->getReferer(); } void linphone_call_params_set_referer (LinphoneCallParams *params, LinphoneCall *referer) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setReferer(referer); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setReferer(referer); } bool_t linphone_call_params_get_update_call_when_ice_completed (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PRIVATE_PTR(params)->getUpdateCallWhenIceCompleted(); + return L_GET_PRIVATE_FROM_C_OBJECT(params)->getUpdateCallWhenIceCompleted(); } void linphone_call_params_set_update_call_when_ice_completed (LinphoneCallParams *params, bool_t value) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setUpdateCallWhenIceCompleted(value); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setUpdateCallWhenIceCompleted(value); } void linphone_call_params_set_sent_vsize (LinphoneCallParams *params, MSVideoSize vsize) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setSentVideoDefinition(linphone_video_definition_new(static_cast(vsize.width), static_cast(vsize.height), nullptr)); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setSentVideoDefinition(linphone_video_definition_new(static_cast(vsize.width), static_cast(vsize.height), nullptr)); } void linphone_call_params_set_recv_vsize (LinphoneCallParams *params, MSVideoSize vsize) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setReceivedVideoDefinition(linphone_video_definition_new(static_cast(vsize.width), static_cast(vsize.height), nullptr)); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setReceivedVideoDefinition(linphone_video_definition_new(static_cast(vsize.width), static_cast(vsize.height), nullptr)); } void linphone_call_params_set_sent_video_definition (LinphoneCallParams *params, LinphoneVideoDefinition *vdef) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setSentVideoDefinition(vdef); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setSentVideoDefinition(vdef); } void linphone_call_params_set_received_video_definition (LinphoneCallParams *params, LinphoneVideoDefinition *vdef) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setReceivedVideoDefinition(vdef); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setReceivedVideoDefinition(vdef); } bool_t linphone_call_params_get_no_user_consent (const LinphoneCallParams *params) { - return GET_MEDIA_CPP_PRIVATE_PTR(params)->getNoUserConsent(); + return L_GET_PRIVATE_FROM_C_OBJECT(params)->getNoUserConsent(); } void linphone_call_params_set_no_user_consent (LinphoneCallParams *params, bool_t value) { - GET_MEDIA_CPP_PRIVATE_PTR(params)->setNoUserConsent(value); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setNoUserConsent(value); } // ============================================================================= @@ -508,7 +505,7 @@ void linphone_call_params_unref (LinphoneCallParams *cp) { LinphoneCallParams *linphone_call_params_new (LinphoneCore *core) { LinphoneCallParams *params = _linphone_CallParams_init(); L_SET_CPP_PTR_FROM_C_OBJECT(params, new LinphonePrivate::MediaSessionParams()); - GET_MEDIA_CPP_PTR(params)->initDefault(core); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->initDefault(core); return params; } diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index c31c45354..5a22046c0 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -28,9 +28,6 @@ // ============================================================================= -#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_OBJECT(obj) -#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_OBJECT(obj) - using namespace std; static void _linphone_call_constructor (LinphoneCall *call); @@ -389,7 +386,7 @@ static void linphone_call_repair_by_invite_with_replaces (LinphoneCall *call) { #endif MediaStream *linphone_call_get_stream (LinphoneCall *call, LinphoneStreamType type) { - return GET_CPP_PRIVATE_PTR(call)->getMediaStream(type); + return L_GET_PRIVATE_FROM_C_OBJECT(call)->getMediaStream(type); } void linphone_call_set_broken (LinphoneCall *call) { @@ -511,11 +508,11 @@ void linphone_call_refresh_sockets (LinphoneCall *call) { } SalOp * linphone_call_get_op (const LinphoneCall *call) { - return GET_CPP_PRIVATE_PTR(call)->getOp(); + return L_GET_PRIVATE_FROM_C_OBJECT(call)->getOp(); } LinphoneProxyConfig * linphone_call_get_dest_proxy (const LinphoneCall *call) { - return GET_CPP_PRIVATE_PTR(call)->getDestProxy(); + return L_GET_PRIVATE_FROM_C_OBJECT(call)->getDestProxy(); } LinphoneCallLog * linphone_call_get_log (const LinphoneCall *call) { @@ -523,19 +520,19 @@ LinphoneCallLog * linphone_call_get_log (const LinphoneCall *call) { } IceSession * linphone_call_get_ice_session (const LinphoneCall *call) { - return GET_CPP_PRIVATE_PTR(call)->getIceSession(); + return L_GET_PRIVATE_FROM_C_OBJECT(call)->getIceSession(); } bool_t linphone_call_get_audio_muted (const LinphoneCall *call) { - return GET_CPP_PRIVATE_PTR(call)->getAudioMuted(); + return L_GET_PRIVATE_FROM_C_OBJECT(call)->getAudioMuted(); } void linphone_call_set_audio_muted (LinphoneCall *call, bool_t value) { - GET_CPP_PRIVATE_PTR(call)->setAudioMuted(value); + L_GET_PRIVATE_FROM_C_OBJECT(call)->setAudioMuted(value); } bool_t linphone_call_get_all_muted (const LinphoneCall *call) { - return GET_CPP_PTR(call)->getAllMuted(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getAllMuted(); } #define NOTIFY_IF_EXIST(cbName, functionName, ...) \ @@ -586,11 +583,11 @@ void linphone_call_notify_ack_processing (LinphoneCall *call, LinphoneHeaders *m // ============================================================================= LinphoneCore *linphone_call_get_core (const LinphoneCall *call) { - return GET_CPP_PTR(call)->getCore(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getCore(); } LinphoneCallState linphone_call_get_state (const LinphoneCall *call) { - return GET_CPP_PTR(call)->getState(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getState(); } bool_t linphone_call_asked_to_autoanswer (LinphoneCall *call) { @@ -601,7 +598,7 @@ bool_t linphone_call_asked_to_autoanswer (LinphoneCall *call) { } const LinphoneAddress *linphone_call_get_remote_address (const LinphoneCall *call) { - L_SET_CPP_PTR_FROM_C_OBJECT(call->remoteAddressCache, &GET_CPP_PTR(call)->getRemoteAddress()); + L_SET_CPP_PTR_FROM_C_OBJECT(call->remoteAddressCache, &L_GET_CPP_PTR_FROM_C_OBJECT(call)->getRemoteAddress()); return call->remoteAddressCache; } @@ -622,7 +619,7 @@ const char *linphone_call_get_to_header (const LinphoneCall *call, const char *n } char *linphone_call_get_remote_address_as_string (const LinphoneCall *call) { - return ms_strdup(GET_CPP_PTR(call)->getRemoteAddressAsString().c_str()); + return ms_strdup(L_GET_CPP_PTR_FROM_C_OBJECT(call)->getRemoteAddressAsString().c_str()); } const LinphoneAddress *linphone_call_get_diversion_address (const LinphoneCall *call) { @@ -638,7 +635,7 @@ LinphoneCallDir linphone_call_get_dir (const LinphoneCall *call) { } LinphoneCallLog *linphone_call_get_call_log (const LinphoneCall *call) { - return GET_CPP_PTR(call)->getLog(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getLog(); } const char *linphone_call_get_refer_to (const LinphoneCall *call) { @@ -686,16 +683,16 @@ LinphoneCall *linphone_call_get_replaced_call (LinphoneCall *call) { } int linphone_call_get_duration (const LinphoneCall *call) { - return GET_CPP_PTR(call)->getDuration(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getDuration(); } const LinphoneCallParams *linphone_call_get_current_params(LinphoneCall *call) { - L_SET_CPP_PTR_FROM_C_OBJECT(call->currentParamsCache, GET_CPP_PTR(call)->getCurrentParams()); + L_SET_CPP_PTR_FROM_C_OBJECT(call->currentParamsCache, L_GET_CPP_PTR_FROM_C_OBJECT(call)->getCurrentParams()); return call->currentParamsCache; } const LinphoneCallParams *linphone_call_get_remote_params(LinphoneCall *call) { - const LinphonePrivate::MediaSessionParams *remoteParams = GET_CPP_PTR(call)->getRemoteParams(); + const LinphonePrivate::MediaSessionParams *remoteParams = L_GET_CPP_PTR_FROM_C_OBJECT(call)->getRemoteParams(); if (!remoteParams) return nullptr; L_SET_CPP_PTR_FROM_C_OBJECT(call->remoteParamsCache, remoteParams); @@ -703,27 +700,27 @@ const LinphoneCallParams *linphone_call_get_remote_params(LinphoneCall *call) { } void linphone_call_enable_camera (LinphoneCall *call, bool_t enable) { - GET_CPP_PTR(call)->enableCamera(enable); + L_GET_CPP_PTR_FROM_C_OBJECT(call)->enableCamera(enable); } bool_t linphone_call_camera_enabled (const LinphoneCall *call) { - return GET_CPP_PTR(call)->cameraEnabled(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->cameraEnabled(); } LinphoneStatus linphone_call_take_video_snapshot (LinphoneCall *call, const char *file) { - return GET_CPP_PTR(call)->takeVideoSnapshot(file ? file : ""); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->takeVideoSnapshot(file ? file : ""); } LinphoneStatus linphone_call_take_preview_snapshot (LinphoneCall *call, const char *file) { - return GET_CPP_PTR(call)->takePreviewSnapshot(file ? file : ""); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->takePreviewSnapshot(file ? file : ""); } LinphoneReason linphone_call_get_reason (const LinphoneCall *call) { - return GET_CPP_PTR(call)->getReason(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getReason(); } const LinphoneErrorInfo *linphone_call_get_error_info (const LinphoneCall *call) { - return GET_CPP_PTR(call)->getErrorInfo(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getErrorInfo(); } const char *linphone_call_get_remote_user_agent (LinphoneCall *call) { @@ -738,7 +735,7 @@ const char *linphone_call_get_remote_user_agent (LinphoneCall *call) { } const char * linphone_call_get_remote_contact (LinphoneCall *call) { - std::string contact = GET_CPP_PTR(call)->getRemoteContact(); + std::string contact = L_GET_CPP_PTR_FROM_C_OBJECT(call)->getRemoteContact(); if (contact.empty()) return nullptr; if (call->remoteContactCache) @@ -748,24 +745,24 @@ const char * linphone_call_get_remote_contact (LinphoneCall *call) { } const char *linphone_call_get_authentication_token (LinphoneCall *call) { - std::string token = GET_CPP_PTR(call)->getAuthenticationToken(); + std::string token = L_GET_CPP_PTR_FROM_C_OBJECT(call)->getAuthenticationToken(); return token.empty() ? nullptr : token.c_str(); } bool_t linphone_call_get_authentication_token_verified (const LinphoneCall *call) { - return GET_CPP_PTR(call)->getAuthenticationTokenVerified(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getAuthenticationTokenVerified(); } void linphone_call_set_authentication_token_verified (LinphoneCall *call, bool_t verified) { - GET_CPP_PTR(call)->setAuthenticationTokenVerified(verified); + L_GET_CPP_PTR_FROM_C_OBJECT(call)->setAuthenticationTokenVerified(verified); } void linphone_call_send_vfu_request (LinphoneCall *call) { - GET_CPP_PTR(call)->sendVfuRequest(); + L_GET_CPP_PTR_FROM_C_OBJECT(call)->sendVfuRequest(); } void linphone_call_set_next_video_frame_decoded_callback (LinphoneCall *call, LinphoneCallCbFunc cb, void *ud) { - GET_CPP_PTR(call)->setNextVideoFrameDecodedCallback(cb, ud); + L_GET_CPP_PTR_FROM_C_OBJECT(call)->setNextVideoFrameDecodedCallback(cb, ud); } LinphoneCallState linphone_call_get_transfer_state (LinphoneCall *call) { @@ -777,7 +774,7 @@ LinphoneCallState linphone_call_get_transfer_state (LinphoneCall *call) { } void linphone_call_zoom_video (LinphoneCall* call, float zoom_factor, float* cx, float* cy) { - GET_CPP_PTR(call)->zoomVideo(zoom_factor, cx, cy); + L_GET_CPP_PTR_FROM_C_OBJECT(call)->zoomVideo(zoom_factor, cx, cy); } LinphoneStatus linphone_call_send_dtmf (LinphoneCall *call, char dtmf) { @@ -856,35 +853,35 @@ void linphone_call_set_audio_route (LinphoneCall *call, LinphoneAudioRoute route } int linphone_call_get_stream_count (const LinphoneCall *call) { - return GET_CPP_PTR(call)->getStreamCount(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getStreamCount(); } MSFormatType linphone_call_get_stream_type (const LinphoneCall *call, int stream_index) { - return GET_CPP_PTR(call)->getStreamType(stream_index); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getStreamType(stream_index); } RtpTransport *linphone_call_get_meta_rtp_transport (const LinphoneCall *call, int stream_index) { - return GET_CPP_PTR(call)->getMetaRtpTransport(stream_index); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getMetaRtpTransport(stream_index); } RtpTransport *linphone_call_get_meta_rtcp_transport (const LinphoneCall *call, int stream_index) { - return GET_CPP_PTR(call)->getMetaRtcpTransport(stream_index); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getMetaRtcpTransport(stream_index); } LinphoneStatus linphone_call_pause (LinphoneCall *call) { - return GET_CPP_PTR(call)->pause(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->pause(); } LinphoneStatus linphone_call_resume (LinphoneCall *call) { - return GET_CPP_PTR(call)->resume(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->resume(); } LinphoneStatus linphone_call_terminate (LinphoneCall *call) { - return GET_CPP_PTR(call)->terminate(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->terminate(); } LinphoneStatus linphone_call_terminate_with_error_info (LinphoneCall *call , const LinphoneErrorInfo *ei) { - return GET_CPP_PTR(call)->terminate(ei); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->terminate(ei); } LinphoneStatus linphone_call_redirect (LinphoneCall *call, const char *redirect_uri) { @@ -924,31 +921,31 @@ LinphoneStatus linphone_call_redirect (LinphoneCall *call, const char *redirect_ } LinphoneStatus linphone_call_decline (LinphoneCall *call, LinphoneReason reason) { - return GET_CPP_PTR(call)->decline(reason); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->decline(reason); } LinphoneStatus linphone_call_decline_with_error_info (LinphoneCall *call, const LinphoneErrorInfo *ei) { - return GET_CPP_PTR(call)->decline(ei); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->decline(ei); } LinphoneStatus linphone_call_accept (LinphoneCall *call) { - return GET_CPP_PTR(call)->accept(nullptr); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->accept(nullptr); } LinphoneStatus linphone_call_accept_with_params (LinphoneCall *call, const LinphoneCallParams *params) { - return GET_CPP_PTR(call)->accept(params ? L_GET_CPP_PTR_FROM_C_OBJECT(params) : nullptr); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->accept(params ? L_GET_CPP_PTR_FROM_C_OBJECT(params) : nullptr); } LinphoneStatus linphone_call_accept_early_media (LinphoneCall* call) { - return GET_CPP_PTR(call)->acceptEarlyMedia(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->acceptEarlyMedia(); } LinphoneStatus linphone_call_accept_early_media_with_params (LinphoneCall *call, const LinphoneCallParams *params) { - return GET_CPP_PTR(call)->acceptEarlyMedia(params ? L_GET_CPP_PTR_FROM_C_OBJECT(params) : nullptr); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->acceptEarlyMedia(params ? L_GET_CPP_PTR_FROM_C_OBJECT(params) : nullptr); } LinphoneStatus linphone_call_update (LinphoneCall *call, const LinphoneCallParams *params) { - return GET_CPP_PTR(call)->update(params ? L_GET_CPP_PTR_FROM_C_OBJECT(params) : nullptr); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->update(params ? L_GET_CPP_PTR_FROM_C_OBJECT(params) : nullptr); } LinphoneStatus linphone_call_defer_update (LinphoneCall *call) { @@ -971,7 +968,7 @@ LinphoneStatus linphone_call_defer_update (LinphoneCall *call) { } LinphoneStatus linphone_call_accept_update (LinphoneCall *call, const LinphoneCallParams *params) { - return GET_CPP_PTR(call)->acceptUpdate(params ? L_GET_CPP_PTR_FROM_C_OBJECT(params) : nullptr); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->acceptUpdate(params ? L_GET_CPP_PTR_FROM_C_OBJECT(params) : nullptr); } LinphoneStatus linphone_call_transfer (LinphoneCall *call, const char *refer_to) { @@ -1007,27 +1004,27 @@ LinphoneStatus linphone_call_transfer_to_another (LinphoneCall *call, LinphoneCa } void *linphone_call_get_native_video_window_id (const LinphoneCall *call) { - return GET_CPP_PTR(call)->getNativeVideoWindowId(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getNativeVideoWindowId(); } void linphone_call_set_native_video_window_id (LinphoneCall *call, void *id) { - GET_CPP_PTR(call)->setNativeVideoWindowId(id); + L_GET_CPP_PTR_FROM_C_OBJECT(call)->setNativeVideoWindowId(id); } void linphone_call_enable_echo_cancellation (LinphoneCall *call, bool_t enable) { - GET_CPP_PTR(call)->enableEchoCancellation(enable); + L_GET_CPP_PTR_FROM_C_OBJECT(call)->enableEchoCancellation(enable); } bool_t linphone_call_echo_cancellation_enabled (const LinphoneCall *call) { - return GET_CPP_PTR(call)->echoCancellationEnabled(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->echoCancellationEnabled(); } void linphone_call_enable_echo_limiter (LinphoneCall *call, bool_t val) { - GET_CPP_PTR(call)->enableEchoLimiter(val); + L_GET_CPP_PTR_FROM_C_OBJECT(call)->enableEchoLimiter(val); } bool_t linphone_call_echo_limiter_enabled (const LinphoneCall *call) { - return GET_CPP_PTR(call)->echoLimiterEnabled(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->echoLimiterEnabled(); } LinphoneChatRoom *linphone_call_get_chat_room (LinphoneCall *call) { @@ -1044,43 +1041,43 @@ LinphoneChatRoom *linphone_call_get_chat_room (LinphoneCall *call) { } float linphone_call_get_play_volume (const LinphoneCall *call) { - return GET_CPP_PTR(call)->getPlayVolume(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getPlayVolume(); } float linphone_call_get_record_volume (const LinphoneCall *call) { - return GET_CPP_PTR(call)->getRecordVolume(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getRecordVolume(); } float linphone_call_get_speaker_volume_gain (const LinphoneCall *call) { - return GET_CPP_PTR(call)->getSpeakerVolumeGain(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getSpeakerVolumeGain(); } void linphone_call_set_speaker_volume_gain( LinphoneCall *call, float volume) { - GET_CPP_PTR(call)->setSpeakerVolumeGain(volume); + L_GET_CPP_PTR_FROM_C_OBJECT(call)->setSpeakerVolumeGain(volume); } float linphone_call_get_microphone_volume_gain (const LinphoneCall *call) { - return GET_CPP_PTR(call)->getMicrophoneVolumeGain(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getMicrophoneVolumeGain(); } void linphone_call_set_microphone_volume_gain (LinphoneCall *call, float volume) { - GET_CPP_PTR(call)->setMicrophoneVolumeGain(volume); + L_GET_CPP_PTR_FROM_C_OBJECT(call)->setMicrophoneVolumeGain(volume); } float linphone_call_get_current_quality (const LinphoneCall *call) { - return GET_CPP_PTR(call)->getCurrentQuality(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getCurrentQuality(); } float linphone_call_get_average_quality (const LinphoneCall *call) { - return GET_CPP_PTR(call)->getAverageQuality(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getAverageQuality(); } void linphone_call_start_recording (LinphoneCall *call) { - GET_CPP_PTR(call)->startRecording(); + L_GET_CPP_PTR_FROM_C_OBJECT(call)->startRecording(); } void linphone_call_stop_recording (LinphoneCall *call) { - GET_CPP_PTR(call)->stopRecording(); + L_GET_CPP_PTR_FROM_C_OBJECT(call)->stopRecording(); } LinphonePlayer *linphone_call_get_player (LinphoneCall *call) { @@ -1094,7 +1091,7 @@ LinphonePlayer *linphone_call_get_player (LinphoneCall *call) { } bool_t linphone_call_media_in_progress (const LinphoneCall *call) { - return GET_CPP_PTR(call)->mediaInProgress(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->mediaInProgress(); } void linphone_call_ogl_render (const LinphoneCall *call) { @@ -1116,19 +1113,19 @@ LinphoneStatus linphone_call_send_info_message (LinphoneCall *call, const Linpho } LinphoneCallStats *linphone_call_get_stats (LinphoneCall *call, LinphoneStreamType type) { - return GET_CPP_PTR(call)->getStats(type); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getStats(type); } LinphoneCallStats *linphone_call_get_audio_stats (LinphoneCall *call) { - return GET_CPP_PTR(call)->getAudioStats(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getAudioStats(); } LinphoneCallStats *linphone_call_get_video_stats (LinphoneCall *call) { - return GET_CPP_PTR(call)->getVideoStats(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getVideoStats(); } LinphoneCallStats *linphone_call_get_text_stats (LinphoneCall *call) { - return GET_CPP_PTR(call)->getTextStats(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getTextStats(); } void linphone_call_add_callbacks (LinphoneCall *call, LinphoneCallCbs *cbs) { @@ -1156,7 +1153,7 @@ void linphone_call_set_params (LinphoneCall *call, const LinphoneCallParams *par } const LinphoneCallParams *linphone_call_get_params (LinphoneCall *call) { - L_SET_CPP_PTR_FROM_C_OBJECT(call->paramsCache, GET_CPP_PTR(call)->getParams()); + L_SET_CPP_PTR_FROM_C_OBJECT(call->paramsCache, L_GET_CPP_PTR_FROM_C_OBJECT(call)->getParams()); return call->paramsCache; } @@ -1206,6 +1203,6 @@ LinphoneCall *linphone_call_new_incoming (LinphoneCore *lc, const LinphoneAddres call->paramsCache = linphone_call_params_new_for_wrapper(); call->remoteParamsCache = linphone_call_params_new_for_wrapper(); call->remoteAddressCache = linphone_address_new(nullptr); - GET_CPP_PRIVATE_PTR(call)->initiateIncoming(); + L_GET_PRIVATE_FROM_C_OBJECT(call)->initiateIncoming(); return call; } diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index b2665f26a..5e324b42f 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -30,9 +30,6 @@ // ============================================================================= -#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_OBJECT(obj) -#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_OBJECT(obj) - using namespace std; static void _linphone_chat_message_constructor (LinphoneChatMessage *msg); diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index af8c7090c..e19ec6f9d 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -29,9 +29,6 @@ // ============================================================================= -#define GET_CPP_PTR(obj) L_GET_CPP_PTR_FROM_C_OBJECT(obj) -#define GET_CPP_PRIVATE_PTR(obj) L_GET_PRIVATE_FROM_C_OBJECT(obj) - using namespace std; static void _linphone_chat_room_constructor (LinphoneChatRoom *cr); @@ -62,19 +59,19 @@ static void _linphone_chat_room_destructor (LinphoneChatRoom *cr) { // ============================================================================= void linphone_chat_room_release (LinphoneChatRoom *cr) { - GET_CPP_PRIVATE_PTR(cr)->release(); + L_GET_PRIVATE_FROM_C_OBJECT(cr)->release(); } void linphone_chat_room_remove_transient_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) { - GET_CPP_PRIVATE_PTR(cr)->removeTransientMessage(msg); + L_GET_PRIVATE_FROM_C_OBJECT(cr)->removeTransientMessage(msg); } void linphone_chat_room_send_message (LinphoneChatRoom *cr, const char *msg) { - GET_CPP_PTR(cr)->sendMessage(GET_CPP_PTR(cr)->createMessage(msg)); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createMessage(msg)); } bool_t linphone_chat_room_is_remote_composing (const LinphoneChatRoom *cr) { - return GET_CPP_PTR(cr)->isRemoteComposing(); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->isRemoteComposing(); } LinphoneCore *linphone_chat_room_get_lc (const LinphoneChatRoom *cr) { @@ -82,19 +79,19 @@ LinphoneCore *linphone_chat_room_get_lc (const LinphoneChatRoom *cr) { } LinphoneCore *linphone_chat_room_get_core (const LinphoneChatRoom *cr) { - return GET_CPP_PTR(cr)->getCore(); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore(); } const LinphoneAddress *linphone_chat_room_get_peer_address (LinphoneChatRoom *cr) { if (cr->peerAddressCache) { linphone_address_unref(cr->peerAddressCache); } - cr->peerAddressCache = linphone_address_new(GET_CPP_PTR(cr)->getPeerAddress().asString().c_str()); + cr->peerAddressCache = linphone_address_new(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getPeerAddress().asString().c_str()); return cr->peerAddressCache; } LinphoneChatMessage *linphone_chat_room_create_message (LinphoneChatRoom *cr, const char *message) { - return GET_CPP_PTR(cr)->createMessage(message ? message : ""); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createMessage(message ? message : ""); } LinphoneChatMessage *linphone_chat_room_create_message_2 ( @@ -132,73 +129,73 @@ void linphone_chat_room_send_message2 ( ) { linphone_chat_message_set_message_state_changed_cb(msg, status_cb); linphone_chat_message_set_message_state_changed_cb_user_data(msg, ud); - GET_CPP_PTR(cr)->sendMessage(msg); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(msg); } void linphone_chat_room_send_chat_message_2 (LinphoneChatRoom *cr, LinphoneChatMessage *msg) { linphone_chat_message_ref(msg); - GET_CPP_PTR(cr)->sendMessage(msg); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(msg); } void linphone_chat_room_send_chat_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) { - GET_CPP_PTR(cr)->sendMessage(msg); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(msg); } uint32_t linphone_chat_room_get_char (const LinphoneChatRoom *cr) { if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) - return static_cast(GET_CPP_PTR(cr).get())->getChar(); + return static_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr).get())->getChar(); return 0; } void linphone_chat_room_compose (LinphoneChatRoom *cr) { - GET_CPP_PTR(cr)->compose(); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->compose(); } LinphoneCall *linphone_chat_room_get_call (const LinphoneChatRoom *cr) { if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) - return static_cast(GET_CPP_PTR(cr).get())->getCall(); + return static_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr).get())->getCall(); return nullptr; } void linphone_chat_room_set_call (LinphoneChatRoom *cr, LinphoneCall *call) { if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) - static_cast(GET_CPP_PRIVATE_PTR(cr))->setCall(call); + static_cast(L_GET_PRIVATE_FROM_C_OBJECT(cr))->setCall(call); } bctbx_list_t *linphone_chat_room_get_transient_messages (const LinphoneChatRoom *cr) { - return L_GET_C_LIST_FROM_CPP_LIST(GET_CPP_PRIVATE_PTR(cr)->getTransientMessages()); + return L_GET_C_LIST_FROM_CPP_LIST(L_GET_PRIVATE_FROM_C_OBJECT(cr)->getTransientMessages()); } void linphone_chat_room_mark_as_read (LinphoneChatRoom *cr) { - GET_CPP_PTR(cr)->markAsRead(); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->markAsRead(); } int linphone_chat_room_get_unread_messages_count (LinphoneChatRoom *cr) { - return GET_CPP_PTR(cr)->getUnreadMessagesCount(); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getUnreadMessagesCount(); } int linphone_chat_room_get_history_size (LinphoneChatRoom *cr) { - return GET_CPP_PTR(cr)->getHistorySize(); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistorySize(); } void linphone_chat_room_delete_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) { - GET_CPP_PTR(cr)->deleteMessage(msg); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->deleteMessage(msg); } void linphone_chat_room_delete_history (LinphoneChatRoom *cr) { - GET_CPP_PTR(cr)->deleteHistory(); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->deleteHistory(); } bctbx_list_t *linphone_chat_room_get_history_range (LinphoneChatRoom *cr, int startm, int endm) { - return L_GET_C_LIST_FROM_CPP_LIST(GET_CPP_PTR(cr)->getHistoryRange(startm, endm)); + return L_GET_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistoryRange(startm, endm)); } bctbx_list_t *linphone_chat_room_get_history (LinphoneChatRoom *cr, int nb_message) { - return L_GET_C_LIST_FROM_CPP_LIST(GET_CPP_PTR(cr)->getHistory(nb_message)); + return L_GET_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistory(nb_message)); } LinphoneChatMessage *linphone_chat_room_find_message (LinphoneChatRoom *cr, const char *message_id) { - return GET_CPP_PTR(cr)->findMessage(message_id); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findMessage(message_id); } LinphoneChatRoomCbs *linphone_chat_room_get_callbacks (const LinphoneChatRoom *cr) { @@ -206,42 +203,42 @@ LinphoneChatRoomCbs *linphone_chat_room_get_callbacks (const LinphoneChatRoom *c } LinphoneChatRoomState linphone_chat_room_get_state (const LinphoneChatRoom *cr) { - return (LinphoneChatRoomState)GET_CPP_PTR(cr)->getState(); + return (LinphoneChatRoomState)L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getState(); } LinphoneParticipant *linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr) { - return L_GET_C_BACK_PTR(GET_CPP_PTR(cr)->addParticipant( + return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->addParticipant( *L_GET_CPP_PTR_FROM_C_OBJECT(addr), nullptr, false) ); } void linphone_chat_room_add_participants (LinphoneChatRoom *cr, const bctbx_list_t *addresses) { - GET_CPP_PTR(cr)->addParticipants(L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(addresses, Address, Address), nullptr, false); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->addParticipants(L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(addresses, Address, Address), nullptr, false); } bool_t linphone_chat_room_can_handle_participants (const LinphoneChatRoom *cr) { - return GET_CPP_PTR(cr)->canHandleParticipants(); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->canHandleParticipants(); } const char *linphone_chat_room_get_id (const LinphoneChatRoom *cr) { - string id = GET_CPP_PTR(cr)->getId(); + string id = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getId(); return id.empty() ? nullptr : id.c_str(); } int linphone_chat_room_get_nb_participants (const LinphoneChatRoom *cr) { - return GET_CPP_PTR(cr)->getNbParticipants(); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getNbParticipants(); } bctbx_list_t *linphone_chat_room_get_participants (const LinphoneChatRoom *cr) { - return L_GET_C_LIST_OF_STRUCT_PTR_FROM_CPP_LIST_OF_CPP_OBJ(GET_CPP_PTR(cr)->getParticipants(), Participant, Participant); + return L_GET_C_LIST_OF_STRUCT_PTR_FROM_CPP_LIST_OF_CPP_OBJ(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getParticipants(), Participant, Participant); } void linphone_chat_room_remove_participant (LinphoneChatRoom *cr, LinphoneParticipant *participant) { - GET_CPP_PTR(cr)->removeParticipant(L_GET_CPP_PTR_FROM_C_OBJECT(participant)); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->removeParticipant(L_GET_CPP_PTR_FROM_C_OBJECT(participant)); } void linphone_chat_room_remove_participants (LinphoneChatRoom *cr, const bctbx_list_t *participants) { - GET_CPP_PTR(cr)->removeParticipants(L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(participants, Participant, Participant)); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->removeParticipants(L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(participants, Participant, Participant)); } // ============================================================================= From a568f332e59173ded93131e70ecd643f95b84559 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 22 Sep 2017 14:58:42 +0200 Subject: [PATCH 0143/2215] Fixed issue in C++ wrapper: forward declaration of class instead of importing header --- wrappers/cpp/genwrapper.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/wrappers/cpp/genwrapper.py b/wrappers/cpp/genwrapper.py index 45773addd..d5f0cb0ba 100755 --- a/wrappers/cpp/genwrapper.py +++ b/wrappers/cpp/genwrapper.py @@ -591,15 +591,12 @@ class ClassHeader(object): self.includes = {'internal': [], 'external': []} includes = self.needed_includes(_class) for include in includes['internal']: - if _class.name.to_camel_case(fullName=True) == 'LinphoneCore' or (isinstance(_class, AbsApi.Interface) and _class.listenedClass is not None and include == _class.listenedClass.name.to_snake_case()): - if include == 'enums': - self.includes['internal'].append({'name': include}) - else: - className = AbsApi.ClassName() - className.from_snake_case(include) - self.priorDeclarations.append({'name': className.to_camel_case()}) - else: + if include == 'enums': self.includes['internal'].append({'name': include}) + else: + className = AbsApi.ClassName() + className.from_snake_case(include) + self.priorDeclarations.append({'name': className.to_camel_case()}) for include in includes['external']: self.includes['external'].append({'name': include}) From 4bc82605b5880f0c032e187ebdaafac5b17ee2fe Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 22 Sep 2017 14:56:37 +0200 Subject: [PATCH 0144/2215] cast away --- coreapi/linphonecore.c | 4 ++-- coreapi/ringtoneplayer_ios.m | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 738c1912a..18db06759 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5518,11 +5518,11 @@ static MSFilter *get_audio_resource(LinphoneCore *lc, LinphoneAudioResourceType ringstream=lc->ringstream=ring_start(lc->factory, NULL,0,ringcard); ms_filter_call_method(lc->ringstream->gendtmf,MS_DTMF_GEN_SET_DEFAULT_AMPLITUDE,&); - lc->dmfs_playing_start_time = ms_get_cur_time_ms()/1000; + lc->dmfs_playing_start_time = (time_t)ms_get_cur_time_ms()/1000; }else{ ringstream=lc->ringstream; if (lc->dmfs_playing_start_time!=0) - lc->dmfs_playing_start_time = ms_get_cur_time_ms()/1000; + lc->dmfs_playing_start_time = (time_t)ms_get_cur_time_ms()/1000; } if (rtype==LinphoneToneGenerator) return ringstream->gendtmf; if (rtype==LinphoneLocalPlayer) return ringstream->source; diff --git a/coreapi/ringtoneplayer_ios.m b/coreapi/ringtoneplayer_ios.m index 61e73703b..2a7a51a4b 100644 --- a/coreapi/ringtoneplayer_ios.m +++ b/coreapi/ringtoneplayer_ios.m @@ -77,7 +77,7 @@ int linphone_ringtoneplayer_ios_start_with_cb(LinphoneRingtonePlayer* rp, const } bool_t linphone_ringtoneplayer_ios_is_started(LinphoneRingtonePlayer* rp) { - return [rp->player isPlaying]; + return (bool_t)[rp->player isPlaying]; } int linphone_ringtoneplayer_ios_stop(LinphoneRingtonePlayer* rp) { From dbb214f98892f0847001faaa62519d035be5eed3 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 22 Sep 2017 15:05:37 +0200 Subject: [PATCH 0145/2215] add method to create the resource-lists xml body for conference creation --- src/CMakeLists.txt | 2 ++ src/conference/remote-conference.cpp | 21 +++++++++++++++++++++ src/conference/remote-conference.h | 2 ++ 3 files changed, 25 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index edda58ab5..59d4bd5e3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -97,6 +97,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES utils/payload-type-handler.h variant/variant.h xml/conference-info.h + xml/resource-lists.h xml/xml.h ) @@ -162,6 +163,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES utils/utils.cpp variant/variant.cpp xml/conference-info.cpp + xml/resource-lists.cpp xml/xml.cpp ) diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index 49ab55fac..8218cf31c 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -18,8 +18,10 @@ #include "remote-conference.h" #include "participant-p.h" +#include "xml/resource-lists.h" using namespace std; +using namespace LinphonePrivate::Xsd::ResourceLists; LINPHONE_BEGIN_NAMESPACE @@ -57,6 +59,25 @@ void RemoteConference::removeParticipant (const shared_ptr &p } } + +string RemoteConference::getResourceLists(const list> &participants) { + ResourceLists rl = ResourceLists(); + ListType l = ListType(); + for(const auto &p : participants) { + EntryType entry = EntryType(p->getAddress().asStringUriOnly()); + if(p->getAddress().getDisplayName() != "") { + entry.setDisplayName(DisplayName(p->getAddress().getDisplayName())); + } + l.getEntry().push_back(entry); + } + rl.getList().push_back(l); + + Xsd::XmlSchema::NamespaceInfomap map; + stringstream xmlBody; + serializeResourceLists(xmlBody, rl, map); + return xmlBody.str(); +} + // ----------------------------------------------------------------------------- void RemoteConference::onConferenceCreated (const Address &addr) {} diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index 3a33bb98f..94100bb21 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -39,6 +39,8 @@ public: std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void removeParticipant (const std::shared_ptr &participant) override; + std::string getResourceLists(const std::list> &participants); + protected: /* ConferenceListener */ void onConferenceCreated (const Address &addr) override; From 8167360f47fb5284451f3b1cc30f5dd3018cc9e9 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 22 Sep 2017 15:09:14 +0200 Subject: [PATCH 0146/2215] feat(c-wrapper): setCppPtrFromC is now more secure --- src/c-wrapper/internal/c-tools.h | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 4ccea66b6..26694d757 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -123,21 +123,27 @@ public: return reinterpret_cast *>(cObject)->cppPtr; } - template - static inline void setCppPtrFromC (void *cObject, const std::shared_ptr &cppObject) { + template< + typename CppType, + typename = typename std::enable_if::value, CppType>::type + > + static inline void setCppPtrFromC (void *cObject, const std::shared_ptr &cppObject) { L_ASSERT(cObject); - static_cast *>(cObject)->cppPtr = cppObject; + static_cast *>(cObject)->cppPtr = cppObject; cppObject->setProperty("LinphonePrivate::Wrapper::cBackPtr", cObject); } - template - static inline void setCppPtrFromC (void *cObject, const T *cppObject) { + template< + typename CppType, + typename = typename std::enable_if::value, CppType>::type + > + static inline void setCppPtrFromC (void *cObject, const CppType *cppObject) { L_ASSERT(cObject); - T *oldPtr = reinterpret_cast(static_cast *>(cObject)->cppPtr); + CppType *oldPtr = reinterpret_cast(static_cast *>(cObject)->cppPtr); if (oldPtr != cppObject) { delete oldPtr; - T **cppPtr = &static_cast *>(cObject)->cppPtr; - *cppPtr = new T(*cppObject); + CppType **cppPtr = &static_cast *>(cObject)->cppPtr; + *cppPtr = new CppType(*cppObject); (*cppPtr)->setProperty("LinphonePrivate::Wrapper::cBackPtr", cObject); } } @@ -429,8 +435,8 @@ LINPHONE_END_NAMESPACE >(C_OBJECT) // Set the cpp-ptr of a wrapped C object. -#define L_SET_CPP_PTR_FROM_C_OBJECT(C_OBJECT, CPP_PTR) \ - LINPHONE_NAMESPACE::Wrapper::setCppPtrFromC(C_OBJECT, CPP_PTR) +#define L_SET_CPP_PTR_FROM_C_OBJECT(C_OBJECT, CPP_OBJECT) \ + LINPHONE_NAMESPACE::Wrapper::setCppPtrFromC(C_OBJECT, CPP_OBJECT) // Get the private data of a shared or simple cpp-ptr. #define L_GET_PRIVATE(CPP_OBJECT) \ From 3abfd2749df8d6746963af929dd14fa3e0debf05 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 22 Sep 2017 15:16:31 +0200 Subject: [PATCH 0147/2215] Create a shared_ptr of ChatMessage in ChatRoom createMessage --- src/chat/chat-room.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index be08d9302..7038f1bc3 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -610,8 +610,8 @@ LinphoneChatMessage *ChatRoom::createFileTransferMessage (const LinphoneContent } LinphoneChatMessage *ChatRoom::createMessage (const string &message) { - ChatMessage chatMessage(static_pointer_cast(shared_from_this())); - LinphoneChatMessage *msg = chatMessage.getBackPtr(); + shared_ptr chatMessage = make_shared(static_pointer_cast(shared_from_this())); + LinphoneChatMessage *msg = chatMessage->getBackPtr(); linphone_chat_message_set_chat_room(msg, GET_BACK_PTR(this)); linphone_chat_message_set_state(msg, LinphoneChatMessageStateIdle); linphone_chat_message_set_text(msg, message.empty() ? nullptr : ms_strdup(message.c_str())); From 22214117913c7bf35f05326f95f89ef7964002f6 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 22 Sep 2017 15:24:07 +0200 Subject: [PATCH 0148/2215] Change getResourceLists to use address --- src/conference/remote-conference.cpp | 10 +++++----- src/conference/remote-conference.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index 8218cf31c..269ed635e 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -60,13 +60,13 @@ void RemoteConference::removeParticipant (const shared_ptr &p } -string RemoteConference::getResourceLists(const list> &participants) { +string RemoteConference::getResourceLists(const list> &addresses) { ResourceLists rl = ResourceLists(); ListType l = ListType(); - for(const auto &p : participants) { - EntryType entry = EntryType(p->getAddress().asStringUriOnly()); - if(p->getAddress().getDisplayName() != "") { - entry.setDisplayName(DisplayName(p->getAddress().getDisplayName())); + for(const auto &addr : addresses) { + EntryType entry = EntryType(addr->asStringUriOnly()); + if(addr->getDisplayName() != "") { + entry.setDisplayName(DisplayName(addr->getDisplayName())); } l.getEntry().push_back(entry); } diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index 94100bb21..718bf6edb 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -39,7 +39,7 @@ public: std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void removeParticipant (const std::shared_ptr &participant) override; - std::string getResourceLists(const std::list> &participants); + std::string getResourceLists(const std::list> &addresses); protected: /* ConferenceListener */ From ce0f9d1c142dd003e5f1f727f5e9e18dff5ca263 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 22 Sep 2017 15:35:17 +0200 Subject: [PATCH 0149/2215] feat(c-wrapper): getCBackPtr is now more secure --- src/c-wrapper/internal/c-tools.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 26694d757..026080352 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -83,6 +83,7 @@ public: // Get c/cpp ptr helpers. // --------------------------------------------------------------------------- + // Get Object. template< typename CppType, typename CType, @@ -103,6 +104,7 @@ public: return reinterpret_cast *>(cObject)->cppPtr; } + // Get ClonableObject. template< typename CppType, typename CType, @@ -123,6 +125,7 @@ public: return reinterpret_cast *>(cObject)->cppPtr; } + // Set Object. template< typename CppType, typename = typename std::enable_if::value, CppType>::type @@ -133,6 +136,7 @@ public: cppObject->setProperty("LinphonePrivate::Wrapper::cBackPtr", cObject); } + // Set ClonableObject. template< typename CppType, typename = typename std::enable_if::value, CppType>::type @@ -148,6 +152,7 @@ public: } } + // Macro helpers. template static T *getCppPtr (const std::shared_ptr &cppObject) { return cppObject.get(); @@ -172,7 +177,10 @@ public: // Get c back ptr helpers. // --------------------------------------------------------------------------- - template + template< + typename CppType, + typename = typename std::enable_if::value, CppType>::type + > static inline typename CppTypeToCType::type *getCBackPtr (const std::shared_ptr &cppObject) { typedef typename CppTypeToCType::type RetType; @@ -186,7 +194,10 @@ public: return reinterpret_cast(value); } - template + template< + typename CppType, + typename = typename std::enable_if::value, CppType>::type + > static inline typename CppTypeToCType::type *getCBackPtr (const CppType *cppObject) { typedef typename CppTypeToCType::type RetType; From 8d075bbd27febc85f0b39991cb3cd2d542aaa220 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 22 Sep 2017 16:32:31 +0200 Subject: [PATCH 0150/2215] feat(c-wrapper): set/get UserData are simple functions now --- src/c-wrapper/internal/c-tools.h | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 026080352..9a6c4458f 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -25,7 +25,7 @@ // TODO: From coreapi. Remove me later. #include "private.h" -#include "variant/variant.h" +#include "object/property-container.h" // ============================================================================= // Internal. @@ -215,28 +215,24 @@ public: // Get/set user data. // --------------------------------------------------------------------------- - template - static void *getUserData (const std::shared_ptr &cppPtr) { - Variant v = cppPtr->getProperty("LinphonePrivate::Wrapper::userData"); - return v.getValue(); + static inline void *getUserData (const std::shared_ptr &propertyContainer) { + L_ASSERT(propertyContainer); + return propertyContainer->getProperty("LinphonePrivate::Wrapper::userData").getValue(); } - template - static void *getUserData (T *cppPtr) { - Variant v = cppPtr->getProperty("LinphonePrivate::Wrapper::userData"); - return v.getValue(); + static inline void *getUserData (const PropertyContainer *propertyContainer) { + L_ASSERT(propertyContainer); + return propertyContainer->getProperty("LinphonePrivate::Wrapper::userData").getValue(); } - template - static inline void setUserData (const std::shared_ptr &object, void *value) { - L_ASSERT(object); - object->setProperty("LinphonePrivate::Wrapper::userData", value); + static inline void setUserData (const std::shared_ptr &propertyContainer, void *value) { + L_ASSERT(propertyContainer); + propertyContainer->setProperty("LinphonePrivate::Wrapper::userData", value); } - template - static inline void setUserData (T *object, void *value) { - L_ASSERT(object); - object->setProperty("LinphonePrivate::Wrapper::userData", value); + static inline void setUserData (PropertyContainer *propertyContainer, void *value) { + L_ASSERT(propertyContainer); + propertyContainer->setProperty("LinphonePrivate::Wrapper::userData", value); } // --------------------------------------------------------------------------- From 3bcf6e3523175c93ebeb151286c941f4fbd695c9 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 22 Sep 2017 16:45:30 +0200 Subject: [PATCH 0151/2215] add parseResouceLists method to local conference --- src/conference/local-conference.cpp | 20 ++++++++++++++++++++ src/conference/local-conference.h | 2 ++ src/conference/remote-conference.cpp | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index 401022812..fa51cbdc9 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -18,8 +18,10 @@ #include "local-conference.h" #include "participant-p.h" +#include "xml/resource-lists.h" using namespace std; +using namespace LinphonePrivate::Xsd::ResourceLists; LINPHONE_BEGIN_NAMESPACE @@ -57,4 +59,22 @@ void LocalConference::removeParticipant (const shared_ptr &pa } } +list> LocalConference::parseResourceLists(string xmlBody) { + istringstream data(xmlBody); + unique_ptr rl = LinphonePrivate::Xsd::ResourceLists::parseResourceLists(data, Xsd::XmlSchema::Flags::dont_validate); + list> addresses = list>(); + for(const auto &l : rl->getList()) { + for(const auto &entry : l.getEntry()) { + shared_ptr
    addr = make_shared
    (Address(entry.getUri())); + // TODO : set display name when possible + /*if(!entry.getDisplayName()->present()) { + addr->setDisplayName(entry.getDisplayName()->get()); + }*/ + addresses.push_back(addr); + } + } + + return addresses; +} + LINPHONE_END_NAMESPACE diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h index eec26e1ef..1d20f9cb8 100644 --- a/src/conference/local-conference.h +++ b/src/conference/local-conference.h @@ -38,6 +38,8 @@ public: std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void removeParticipant (const std::shared_ptr &participant) override; + std::list> parseResourceLists(std::string xmlBody); + private: L_DISABLE_COPY(LocalConference); diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index 269ed635e..ade1aa1c4 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -65,7 +65,7 @@ string RemoteConference::getResourceLists(const list> ListType l = ListType(); for(const auto &addr : addresses) { EntryType entry = EntryType(addr->asStringUriOnly()); - if(addr->getDisplayName() != "") { + if(!addr->getDisplayName().empty()) { entry.setDisplayName(DisplayName(addr->getDisplayName())); } l.getEntry().push_back(entry); From bd11c0980fe1050891a25144efaf100a358c5f0d Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 22 Sep 2017 16:59:33 +0200 Subject: [PATCH 0152/2215] feat(c-wrapper): better code (reduce bin size) --- src/c-wrapper/internal/c-tools.h | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 9a6c4458f..3bb01844d 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -67,15 +67,13 @@ public: template static inline decltype (std::declval().getPrivate()) getPrivate (T *cppObject) { - if (!cppObject) - return nullptr; + L_ASSERT(cppObject); return cppObject->getPrivate(); } template static inline decltype (std::declval().getPrivate()) getPrivate (const std::shared_ptr &cppObject) { - if (!cppObject) - return nullptr; + L_ASSERT(cppObject); return cppObject->getPrivate(); } @@ -143,13 +141,14 @@ public: > static inline void setCppPtrFromC (void *cObject, const CppType *cppObject) { L_ASSERT(cObject); - CppType *oldPtr = reinterpret_cast(static_cast *>(cObject)->cppPtr); - if (oldPtr != cppObject) { - delete oldPtr; - CppType **cppPtr = &static_cast *>(cObject)->cppPtr; - *cppPtr = new CppType(*cppObject); - (*cppPtr)->setProperty("LinphonePrivate::Wrapper::cBackPtr", cObject); - } + + CppType **cppObjectAddr = &static_cast *>(cObject)->cppPtr; + if (*cppObjectAddr == cppObject) + return; + delete *cppObjectAddr; + + *cppObjectAddr = new CppType(*cppObject); + (*cppObjectAddr)->setProperty("LinphonePrivate::Wrapper::cBackPtr", cObject); } // Macro helpers. From d1dc5af4ea119f3864bc75bf13af6d74cf51a9a5 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 22 Sep 2017 17:13:33 +0200 Subject: [PATCH 0153/2215] fix(c-wrapper): return correctly cObject in getCBackPtr --- src/c-wrapper/internal/c-tools.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 3bb01844d..0e64a5c78 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -153,22 +153,22 @@ public: // Macro helpers. template - static T *getCppPtr (const std::shared_ptr &cppObject) { + static inline T *getCppPtr (const std::shared_ptr &cppObject) { return cppObject.get(); } template - static T *getCppPtr (T *cppObject) { + static inline T *getCppPtr (T *cppObject) { return cppObject; } template - static const T *getCppPtr (const std::shared_ptr &cppObject) { + static inline const T *getCppPtr (const std::shared_ptr &cppObject) { return cppObject.get(); } template - static const T *getCppPtr (const T *cppObject) { + static inline const T *getCppPtr (const T *cppObject) { return cppObject; } @@ -183,14 +183,14 @@ public: static inline typename CppTypeToCType::type *getCBackPtr (const std::shared_ptr &cppObject) { typedef typename CppTypeToCType::type RetType; - Variant v = cppObject->getProperty("LinphonePrivate::Wrapper::cBackPtr"); - void *value = v.getValue(); - if (!value) { - RetType *cObject = CObjectInitializer::init(); - setCppPtrFromC(cObject, cppObject); - } + Variant variant = cppObject->getProperty("LinphonePrivate::Wrapper::cBackPtr"); + void *value = variant.getValue(); + if (value) + return reinterpret_cast(value); - return reinterpret_cast(value); + RetType *cObject = CObjectInitializer::init(); + setCppPtrFromC(cObject, cppObject); + return cObject; } template< @@ -202,12 +202,12 @@ public: Variant v = cppObject->getProperty("LinphonePrivate::Wrapper::cBackPtr"); void *value = v.getValue(); - if (!value) { - RetType *cObject = CObjectInitializer::init(); - setCppPtrFromC(cObject, cppObject); - } + if (value) + return reinterpret_cast(value); - return reinterpret_cast(value); + RetType *cObject = CObjectInitializer::init(); + setCppPtrFromC(cObject, cppObject); + return cObject; } // --------------------------------------------------------------------------- From 25c138a64a42e6b4a3e0aae190edd82cb30443f0 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 22 Sep 2017 17:24:23 +0200 Subject: [PATCH 0154/2215] feat(c-wrapper): getPrivate is more secure --- src/c-wrapper/internal/c-tools.h | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 0e64a5c78..b7d7f7050 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -48,16 +48,21 @@ struct CObjectInitializer {}; class Wrapper { private: - template - struct WrappedObject { - belle_sip_object_t base; - std::shared_ptr cppPtr; + template + struct IsCppObject { + enum { value = std::is_base_of::value || std::is_base_of::value }; }; - template + template + struct WrappedObject { + belle_sip_object_t base; + std::shared_ptr cppPtr; + }; + + template struct WrappedClonableObject { belle_sip_object_t base; - T *cppPtr; + CType *cppPtr; }; public: @@ -65,14 +70,20 @@ public: // Get private data of cpp Object. // --------------------------------------------------------------------------- - template - static inline decltype (std::declval().getPrivate()) getPrivate (T *cppObject) { + template< + typename CppType, + typename = typename std::enable_if::value, CppType>::type + > + static inline decltype (std::declval().getPrivate()) getPrivate (CppType *cppObject) { L_ASSERT(cppObject); return cppObject->getPrivate(); } - template - static inline decltype (std::declval().getPrivate()) getPrivate (const std::shared_ptr &cppObject) { + template< + typename CppType, + typename = typename std::enable_if::value, CppType>::type + > + static inline decltype (std::declval().getPrivate()) getPrivate (const std::shared_ptr &cppObject) { L_ASSERT(cppObject); return cppObject->getPrivate(); } From 5f232e04f902efaeae261013d3a130d3650dd0f0 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 25 Sep 2017 09:29:00 +0200 Subject: [PATCH 0155/2215] feat(c-wrapper): clean code --- include/linphone/utils/utils.h | 21 ++++++++++++++++ src/c-wrapper/internal/c-tools.h | 42 ++++---------------------------- 2 files changed, 26 insertions(+), 37 deletions(-) diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h index eb2ae8336..3b11e25b8 100644 --- a/include/linphone/utils/utils.h +++ b/include/linphone/utils/utils.h @@ -19,6 +19,7 @@ #ifndef _UTILS_H_ #define _UTILS_H_ +#include #include #include @@ -29,6 +30,26 @@ LINPHONE_BEGIN_NAMESPACE namespace Utils { + template + static constexpr T *getPtr (const std::shared_ptr &object) { + return object.get(); + } + + template + static constexpr T *getPtr (T *object) { + return object; + } + + template + static constexpr const T *getPtr (const std::shared_ptr &object) { + return object.get(); + } + + template + static constexpr const T *getPtr (const T *object) { + return object; + } + LINPHONE_PUBLIC bool iequals (const std::string &a, const std::string &b); LINPHONE_PUBLIC std::vector split (const std::string &str, const std::string &delimiter); diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index b7d7f7050..059985775 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -20,7 +20,8 @@ #define _C_TOOLS_H_ #include -#include + +#include "linphone/utils/utils.h" // TODO: From coreapi. Remove me later. #include "private.h" @@ -74,17 +75,7 @@ public: typename CppType, typename = typename std::enable_if::value, CppType>::type > - static inline decltype (std::declval().getPrivate()) getPrivate (CppType *cppObject) { - L_ASSERT(cppObject); - return cppObject->getPrivate(); - } - - template< - typename CppType, - typename = typename std::enable_if::value, CppType>::type - > - static inline decltype (std::declval().getPrivate()) getPrivate (const std::shared_ptr &cppObject) { - L_ASSERT(cppObject); + static constexpr inline decltype (std::declval().getPrivate()) getPrivate (CppType *cppObject) { return cppObject->getPrivate(); } @@ -162,27 +153,6 @@ public: (*cppObjectAddr)->setProperty("LinphonePrivate::Wrapper::cBackPtr", cObject); } - // Macro helpers. - template - static inline T *getCppPtr (const std::shared_ptr &cppObject) { - return cppObject.get(); - } - - template - static inline T *getCppPtr (T *cppObject) { - return cppObject; - } - - template - static inline const T *getCppPtr (const std::shared_ptr &cppObject) { - return cppObject.get(); - } - - template - static inline const T *getCppPtr (const T *cppObject) { - return cppObject; - } - // --------------------------------------------------------------------------- // Get c back ptr helpers. // --------------------------------------------------------------------------- @@ -457,13 +427,11 @@ LINPHONE_END_NAMESPACE // Get the private data of a shared or simple cpp-ptr. #define L_GET_PRIVATE(CPP_OBJECT) \ - LINPHONE_NAMESPACE::Wrapper::getPrivate(CPP_OBJECT) + LINPHONE_NAMESPACE::Wrapper::getPrivate(LINPHONE_NAMESPACE::Utils::getPtr(CPP_OBJECT)) // Get the private data of a shared or simple cpp-ptr of a wrapped C object. #define L_GET_PRIVATE_FROM_C_OBJECT(C_OBJECT) \ - L_GET_PRIVATE(LINPHONE_NAMESPACE::Wrapper::getCppPtr( \ - L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT) \ - )) + L_GET_PRIVATE(LINPHONE_NAMESPACE::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT))) // Get the wrapped C object of a C++ object. #define L_GET_C_BACK_PTR(C_OBJECT) \ From 1ff43f92143c3cac0f6a900aa688178f4014defd Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 25 Sep 2017 09:59:24 +0200 Subject: [PATCH 0156/2215] feat(c-wrapper): reduce bin size --- src/c-wrapper/internal/c-tools.h | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 059985775..162266708 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -75,7 +75,7 @@ public: typename CppType, typename = typename std::enable_if::value, CppType>::type > - static constexpr inline decltype (std::declval().getPrivate()) getPrivate (CppType *cppObject) { + static constexpr decltype (std::declval().getPrivate()) getPrivate (CppType *cppObject) { return cppObject->getPrivate(); } @@ -89,8 +89,7 @@ public: typename CType, typename = typename std::enable_if::value, CppType>::type > - static inline std::shared_ptr getCppPtrFromC (CType *cObject) { - L_ASSERT(cObject); + static constexpr std::shared_ptr getCppPtrFromC (CType *cObject) { return reinterpret_cast *>(cObject)->cppPtr; } @@ -99,8 +98,7 @@ public: typename CType, typename = typename std::enable_if::value, CppType>::type > - static inline std::shared_ptr getCppPtrFromC (const CType *cObject) { - L_ASSERT(cObject); + static constexpr std::shared_ptr getCppPtrFromC (const CType *cObject) { return reinterpret_cast *>(cObject)->cppPtr; } @@ -110,8 +108,7 @@ public: typename CType, typename = typename std::enable_if::value, CppType>::type > - static inline CppType *getCppPtrFromC (CType *cObject) { - L_ASSERT(cObject); + static constexpr CppType *getCppPtrFromC (CType *cObject) { return reinterpret_cast *>(cObject)->cppPtr; } @@ -120,8 +117,7 @@ public: typename CType, typename = typename std::enable_if::value, CppType>::type > - static inline const CppType *getCppPtrFromC (const CType *cObject) { - L_ASSERT(cObject); + static constexpr const CppType *getCppPtrFromC (const CType *cObject) { return reinterpret_cast *>(cObject)->cppPtr; } @@ -195,21 +191,11 @@ public: // Get/set user data. // --------------------------------------------------------------------------- - static inline void *getUserData (const std::shared_ptr &propertyContainer) { - L_ASSERT(propertyContainer); - return propertyContainer->getProperty("LinphonePrivate::Wrapper::userData").getValue(); - } - static inline void *getUserData (const PropertyContainer *propertyContainer) { L_ASSERT(propertyContainer); return propertyContainer->getProperty("LinphonePrivate::Wrapper::userData").getValue(); } - static inline void setUserData (const std::shared_ptr &propertyContainer, void *value) { - L_ASSERT(propertyContainer); - propertyContainer->setProperty("LinphonePrivate::Wrapper::userData", value); - } - static inline void setUserData (PropertyContainer *propertyContainer, void *value) { L_ASSERT(propertyContainer); propertyContainer->setProperty("LinphonePrivate::Wrapper::userData", value); @@ -440,11 +426,11 @@ LINPHONE_END_NAMESPACE // Get/set user data on a wrapped C object. #define L_GET_USER_DATA_FROM_C_OBJECT(C_OBJECT) \ LINPHONE_NAMESPACE::Wrapper::getUserData( \ - L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT) \ + LINPHONE_NAMESPACE::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT)) \ ) #define L_SET_USER_DATA_FROM_C_OBJECT(C_OBJECT, VALUE) \ LINPHONE_NAMESPACE::Wrapper::setUserData( \ - L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT), \ + LINPHONE_NAMESPACE::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT)), \ VALUE \ ) From e313860c978a46a6192465e30d36c396c2e0724e Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 25 Sep 2017 10:10:16 +0200 Subject: [PATCH 0157/2215] feat(c-wrapper): better code for getCppPtrFromC --- src/c-wrapper/internal/c-tools.h | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 162266708..d93805c04 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -85,8 +85,8 @@ public: // Get Object. template< - typename CppType, typename CType, + typename CppType = typename CTypeToCppType::type, typename = typename std::enable_if::value, CppType>::type > static constexpr std::shared_ptr getCppPtrFromC (CType *cObject) { @@ -94,8 +94,8 @@ public: } template< - typename CppType, typename CType, + typename CppType = typename CTypeToCppType::type, typename = typename std::enable_if::value, CppType>::type > static constexpr std::shared_ptr getCppPtrFromC (const CType *cObject) { @@ -104,8 +104,8 @@ public: // Get ClonableObject. template< - typename CppType, typename CType, + typename CppType = typename CTypeToCppType::type, typename = typename std::enable_if::value, CppType>::type > static constexpr CppType *getCppPtrFromC (CType *cObject) { @@ -113,8 +113,8 @@ public: } template< - typename CppType, typename CType, + typename CppType = typename CTypeToCppType::type, typename = typename std::enable_if::value, CppType>::type > static constexpr const CppType *getCppPtrFromC (const CType *cObject) { @@ -245,7 +245,7 @@ public: static inline std::list> getCppListOfCppObjFromCListOfStructPtr (const bctbx_list_t *cList) { std::list> result; for (auto it = cList; it; it = bctbx_list_next(it)) - result.push_back(getCppPtrFromC(reinterpret_cast(bctbx_list_get_data(it)))); + result.push_back(getCppPtrFromC(reinterpret_cast(bctbx_list_get_data(it)))); return result; } @@ -257,7 +257,7 @@ public: static inline std::list getCppListOfCppObjFromCListOfStructPtr (const bctbx_list_t *cList) { std::list result; for (auto it = cList; it; it = bctbx_list_next(it)) - result.push_back(*getCppPtrFromC(reinterpret_cast(bctbx_list_get_data(it)))); + result.push_back(*getCppPtrFromC(reinterpret_cast(bctbx_list_get_data(it)))); return result; } @@ -402,10 +402,7 @@ LINPHONE_END_NAMESPACE // Get/set the cpp-ptr of a wrapped C object. #define L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT) \ - LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC< \ - L_CPP_TYPE_OF_C_OBJECT(C_OBJECT), \ - std::remove_pointer::type \ - >(C_OBJECT) + LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC(C_OBJECT) // Set the cpp-ptr of a wrapped C object. #define L_SET_CPP_PTR_FROM_C_OBJECT(C_OBJECT, CPP_OBJECT) \ From 416762da1d4f23b99ecff4330d8ce079870af04d Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 25 Sep 2017 10:13:43 +0200 Subject: [PATCH 0158/2215] fix(c-types): remove useless LinphoneStatus and bool_t --- include/linphone/api/c-types.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index b1d48dc13..7af89ac15 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -36,10 +36,6 @@ // Misc. // ============================================================================= -typedef int LinphoneStatus; - -typedef unsigned char bool_t; - #ifdef TRUE #undef TRUE #endif From 27bd89624ab2aeb315377b204a13b3fe5dfee911 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 25 Sep 2017 11:10:47 +0200 Subject: [PATCH 0159/2215] add display name management to resource list parsing --- src/conference/local-conference.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index fa51cbdc9..8e3b53a78 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -66,10 +66,9 @@ list> LocalConference::parseResourceLists(string xmlBody) { for(const auto &l : rl->getList()) { for(const auto &entry : l.getEntry()) { shared_ptr
    addr = make_shared
    (Address(entry.getUri())); - // TODO : set display name when possible - /*if(!entry.getDisplayName()->present()) { - addr->setDisplayName(entry.getDisplayName()->get()); - }*/ + if(!entry.getDisplayName().present()) { + addr->setDisplayName(entry.getDisplayName().get()); + } addresses.push_back(addr); } } From fd1385fdc0242a52f469f56cda4823019600a098 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 25 Sep 2017 12:14:25 +0200 Subject: [PATCH 0160/2215] feat(c-wrapper): provide a L_REGISTER_SUBTYPE macro to register derived cpp object --- include/linphone/utils/utils.h | 8 +++--- src/c-wrapper/c-wrapper.h | 2 ++ src/c-wrapper/internal/c-tools.h | 37 +++++++++++++++++++++------ src/chat/chat-message.cpp | 4 +-- src/chat/chat-room.cpp | 26 +++++++++---------- src/chat/client-group-chat-room.cpp | 6 ++--- src/chat/real-time-text-chat-room.cpp | 4 +-- 7 files changed, 52 insertions(+), 35 deletions(-) diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h index 3b11e25b8..c6ffd2855 100644 --- a/include/linphone/utils/utils.h +++ b/include/linphone/utils/utils.h @@ -31,22 +31,22 @@ LINPHONE_BEGIN_NAMESPACE namespace Utils { template - static constexpr T *getPtr (const std::shared_ptr &object) { + LINPHONE_PUBLIC constexpr T *getPtr (const std::shared_ptr &object) { return object.get(); } template - static constexpr T *getPtr (T *object) { + LINPHONE_PUBLIC constexpr T *getPtr (T *object) { return object; } template - static constexpr const T *getPtr (const std::shared_ptr &object) { + LINPHONE_PUBLIC constexpr const T *getPtr (const std::shared_ptr &object) { return object.get(); } template - static constexpr const T *getPtr (const T *object) { + LINPHONE_PUBLIC constexpr const T *getPtr (const T *object) { return object; } diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index 74fa5d92e..4deafac57 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -37,4 +37,6 @@ L_REGISTER_TYPE(EventLog, EventLog); L_REGISTER_TYPE(MediaSessionParams, CallParams); L_REGISTER_TYPE(Participant, Participant); +L_REGISTER_SUBTYPE(ChatRoom, ClientGroupChatRoom); + #endif // ifndef _C_WRAPPER_H_ diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index d93805c04..8e4da1d84 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -83,7 +83,6 @@ public: // Get c/cpp ptr helpers. // --------------------------------------------------------------------------- - // Get Object. template< typename CType, typename CppType = typename CTypeToCppType::type, @@ -102,7 +101,6 @@ public: return reinterpret_cast *>(cObject)->cppPtr; } - // Get ClonableObject. template< typename CType, typename CppType = typename CTypeToCppType::type, @@ -121,25 +119,24 @@ public: return reinterpret_cast *>(cObject)->cppPtr; } - // Set Object. + // --------------------------------------------------------------------------- + // Set c/cpp ptr helpers. + // --------------------------------------------------------------------------- + template< typename CppType, typename = typename std::enable_if::value, CppType>::type > static inline void setCppPtrFromC (void *cObject, const std::shared_ptr &cppObject) { - L_ASSERT(cObject); static_cast *>(cObject)->cppPtr = cppObject; cppObject->setProperty("LinphonePrivate::Wrapper::cBackPtr", cObject); } - // Set ClonableObject. template< typename CppType, typename = typename std::enable_if::value, CppType>::type > static inline void setCppPtrFromC (void *cObject, const CppType *cppObject) { - L_ASSERT(cObject); - CppType **cppObjectAddr = &static_cast *>(cObject)->cppPtr; if (*cppObjectAddr == cppObject) return; @@ -170,6 +167,14 @@ public: return cObject; } + template< + typename CppType, + typename = typename std::enable_if::value, CppType>::type + > + static inline typename CppTypeToCType::type *getCBackPtr (CppType *cppObject) { + return getCBackPtr(std::static_pointer_cast(cppObject->shared_from_this())); + } + template< typename CppType, typename = typename std::enable_if::value, CppType>::type @@ -317,12 +322,28 @@ LINPHONE_END_NAMESPACE }; \ template<> \ struct CObjectInitializer { \ - static Linphone ## C_TYPE *init () { \ + static inline Linphone ## C_TYPE *init () { \ return _linphone_ ## C_TYPE ## _init(); \ } \ }; \ LINPHONE_END_NAMESPACE +#define L_REGISTER_SUBTYPE(CPP_TYPE, CPP_SUBTYPE) \ + LINPHONE_BEGIN_NAMESPACE \ + class CPP_SUBTYPE; \ + template<> \ + struct CppTypeToCType { \ + enum { defined = true }; \ + typedef CppTypeToCType::type type; \ + }; \ + template<> \ + struct CObjectInitializer { \ + static inline typename CppTypeToCType::type *init () { \ + return CObjectInitializer::init(); \ + } \ + }; \ + LINPHONE_END_NAMESPACE + #define L_ASSERT_C_TYPE(C_TYPE) \ static_assert(LINPHONE_NAMESPACE::CTypeToCppType::defined, "Type is not defined."); \ diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 5d1a83f97..4360d0076 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -31,8 +31,6 @@ #include "modifier/cpim-chat-message-modifier.h" #include "chat-room.h" -#define GET_BACK_PTR(object) L_GET_C_BACK_PTR(static_pointer_cast(object->shared_from_this())) - // ============================================================================= LINPHONE_BEGIN_NAMESPACE @@ -53,7 +51,7 @@ ChatMessage::ChatMessage (const std::shared_ptr &room) : Object(*new C ChatMessage::ChatMessage (ChatMessagePrivate &p) : Object(p) {} LinphoneChatMessage * ChatMessage::getBackPtr() { - return GET_BACK_PTR(this); + return L_GET_C_BACK_PTR(this); } shared_ptr ChatMessage::getChatRoom () const { diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 7038f1bc3..239d28403 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -30,8 +30,6 @@ #include "chat-message.h" #include "chat-room.h" -#define GET_BACK_PTR(object) L_GET_C_BACK_PTR(static_pointer_cast(object->shared_from_this())) - // ============================================================================= using namespace std; @@ -105,7 +103,7 @@ void ChatRoomPrivate::release () { linphone_chat_message_deactivate(message); core = nullptr; - linphone_chat_room_unref(GET_BACK_PTR(q)); + linphone_chat_room_unref(L_GET_C_BACK_PTR(q)); } void ChatRoomPrivate::sendImdn (const string &content, LinphoneReason reason) { @@ -136,7 +134,7 @@ void ChatRoomPrivate::sendImdn (const string &content, LinphoneReason reason) { LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); if (cbProcessOutgoingMessage) { - retval = cbProcessOutgoingMessage(imee, GET_BACK_PTR(q), msg); + retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(q), msg); } } @@ -222,7 +220,7 @@ void ChatRoomPrivate::sendIsComposingNotification () { LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); if (cbProcessOutgoingMessage) { - retval = cbProcessOutgoingMessage(imee, GET_BACK_PTR(q), msg); + retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(q), msg); } } @@ -427,7 +425,7 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsIncomingMessageCb cbProcessIncomingMessage = linphone_im_encryption_engine_cbs_get_process_incoming_message(imeeCbs); if (cbProcessIncomingMessage) { - retval = cbProcessIncomingMessage(imee, GET_BACK_PTR(q), msg); + retval = cbProcessIncomingMessage(imee, L_GET_C_BACK_PTR(q), msg); if (retval == 0) { linphone_chat_message_set_is_secured(msg, TRUE); } else if (retval > 0) { @@ -506,7 +504,7 @@ void ChatRoomPrivate::chatMessageReceived (LinphoneChatMessage *msg) { if (!ContentType::isImdn(linphone_chat_message_get_content_type(msg)) && !ContentType::isImIsComposing(linphone_chat_message_get_content_type(msg))) { notifyChatMessageReceived(msg); remoteIsComposing = false; - linphone_core_notify_is_composing_received(core, GET_BACK_PTR(q)); + linphone_core_notify_is_composing_received(core, L_GET_C_BACK_PTR(q)); linphone_chat_message_send_delivery_notification(msg, LinphoneReasonNone); } } @@ -524,7 +522,7 @@ void ChatRoomPrivate::isComposingReceived (const string &text) { void ChatRoomPrivate::notifyChatMessageReceived (LinphoneChatMessage *msg) { L_Q(ChatRoom); - LinphoneChatRoom *cr = GET_BACK_PTR(q); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); if (linphone_chat_message_get_text(msg)) { /* Legacy API */ linphone_core_notify_text_message_received(core, cr, linphone_chat_message_get_from_address(msg), linphone_chat_message_get_text(msg)); @@ -538,7 +536,7 @@ void ChatRoomPrivate::notifyChatMessageReceived (LinphoneChatMessage *msg) { void ChatRoomPrivate::notifyStateChanged () { L_Q(ChatRoom); - LinphoneChatRoom *cr = GET_BACK_PTR(q); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsStateChangedCb cb = linphone_chat_room_cbs_get_state_changed(cbs); if (cb) @@ -547,7 +545,7 @@ void ChatRoomPrivate::notifyStateChanged () { void ChatRoomPrivate::notifyUndecryptableMessageReceived (LinphoneChatMessage *msg) { L_Q(ChatRoom); - LinphoneChatRoom *cr = GET_BACK_PTR(q); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsUndecryptableMessageReceivedCb cb = linphone_chat_room_cbs_get_undecryptable_message_received(cbs); if (cb) @@ -565,7 +563,7 @@ void ChatRoomPrivate::onIsComposingStateChanged (bool isComposing) { void ChatRoomPrivate::onIsRemoteComposingStateChanged (bool isComposing) { L_Q(ChatRoom); remoteIsComposing = isComposing; - linphone_core_notify_is_composing_received(core, GET_BACK_PTR(q)); + linphone_core_notify_is_composing_received(core, L_GET_C_BACK_PTR(q)); } void ChatRoomPrivate::onIsComposingRefreshNeeded () { @@ -593,7 +591,7 @@ void ChatRoom::compose () { LinphoneChatMessage *ChatRoom::createFileTransferMessage (const LinphoneContent *initialContent) { L_D(ChatRoom); LinphoneChatMessage *msg = createMessage(""); - linphone_chat_message_set_chat_room(msg, GET_BACK_PTR(this)); + linphone_chat_message_set_chat_room(msg, L_GET_C_BACK_PTR(this)); linphone_chat_message_set_text(msg, NULL); linphone_chat_message_set_file_transfer_information(msg, linphone_content_copy(initialContent)); linphone_chat_message_set_outgoing(msg); @@ -612,7 +610,7 @@ LinphoneChatMessage *ChatRoom::createFileTransferMessage (const LinphoneContent LinphoneChatMessage *ChatRoom::createMessage (const string &message) { shared_ptr chatMessage = make_shared(static_pointer_cast(shared_from_this())); LinphoneChatMessage *msg = chatMessage->getBackPtr(); - linphone_chat_message_set_chat_room(msg, GET_BACK_PTR(this)); + linphone_chat_message_set_chat_room(msg, L_GET_C_BACK_PTR(this)); linphone_chat_message_set_state(msg, LinphoneChatMessageStateIdle); linphone_chat_message_set_text(msg, message.empty() ? nullptr : ms_strdup(message.c_str())); linphone_chat_message_set_content_type(msg, ms_strdup("text/plain")); @@ -843,7 +841,7 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); if (cbProcessOutgoingMessage) { - retval = cbProcessOutgoingMessage(imee, GET_BACK_PTR(this), msg); + retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(this), msg); if (retval == 0) { linphone_chat_message_set_is_secured(msg, TRUE); } diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 85f2a8b80..bdf63dc9c 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -102,7 +102,7 @@ void ClientGroupChatRoom::onParticipantAdded (const Address &addr) { } participant = make_shared(addr); participants.push_back(participant); - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(static_pointer_cast(this->shared_from_this())); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAddedCb cb = linphone_chat_room_cbs_get_participant_added(cbs); if (cb) @@ -115,7 +115,7 @@ void ClientGroupChatRoom::onParticipantRemoved (const Address &addr) { lWarning() << "Participant " << participant << " removed but not in the list of participants!"; return; } - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(static_pointer_cast(this->shared_from_this())); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantRemovedCb cb = linphone_chat_room_cbs_get_participant_removed(cbs); if (cb) @@ -130,7 +130,7 @@ void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdm return; } participant->setAdmin(isAdmin); - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(static_pointer_cast(this->shared_from_this())); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAdminStatusChangedCb cb = linphone_chat_room_cbs_get_participant_admin_status_changed(cbs); if (cb) diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index fe17f942d..3898f8ec5 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -24,8 +24,6 @@ #include "c-wrapper/c-wrapper.h" #include "logger/logger.h" -#define GET_BACK_PTR(object) L_GET_C_BACK_PTR(static_pointer_cast(object->shared_from_this())) - // ============================================================================= using namespace std; @@ -65,7 +63,7 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp receivedRttCharacters.push_back(cmc); remoteIsComposing = true; - linphone_core_notify_is_composing_received(core, GET_BACK_PTR(q)); + linphone_core_notify_is_composing_received(core, L_GET_C_BACK_PTR(q)); if ((character == new_line) || (character == crlf) || (character == lf)) { /* End of message */ From ec1c1dbbe6da290478b342fe09df0fdb82966470 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 25 Sep 2017 13:43:32 +0200 Subject: [PATCH 0161/2215] feat(c-wrapper): provide better usage on list macros --- src/c-wrapper/api/c-chat-room.cpp | 6 +++--- src/c-wrapper/internal/c-tools.h | 34 +++++++++++++++++++------------ 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index e19ec6f9d..debae113a 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -213,7 +213,7 @@ LinphoneParticipant *linphone_chat_room_add_participant (LinphoneChatRoom *cr, c } void linphone_chat_room_add_participants (LinphoneChatRoom *cr, const bctbx_list_t *addresses) { - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->addParticipants(L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(addresses, Address, Address), nullptr, false); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->addParticipants(L_GET_RESOLVED_CPP_LIST_FROM_C_LIST(addresses, Address), nullptr, false); } bool_t linphone_chat_room_can_handle_participants (const LinphoneChatRoom *cr) { @@ -230,7 +230,7 @@ int linphone_chat_room_get_nb_participants (const LinphoneChatRoom *cr) { } bctbx_list_t *linphone_chat_room_get_participants (const LinphoneChatRoom *cr) { - return L_GET_C_LIST_OF_STRUCT_PTR_FROM_CPP_LIST_OF_CPP_OBJ(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getParticipants(), Participant, Participant); + return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getParticipants()); } void linphone_chat_room_remove_participant (LinphoneChatRoom *cr, LinphoneParticipant *participant) { @@ -238,7 +238,7 @@ void linphone_chat_room_remove_participant (LinphoneChatRoom *cr, LinphonePartic } void linphone_chat_room_remove_participants (LinphoneChatRoom *cr, const bctbx_list_t *participants) { - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->removeParticipants(L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(participants, Participant, Participant)); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->removeParticipants(L_GET_RESOLVED_CPP_LIST_FROM_C_LIST(participants, Participant)); } // ============================================================================= diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 8e4da1d84..5bb3ffd59 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -207,7 +207,7 @@ public: } // --------------------------------------------------------------------------- - // List helpers. + // List conversions. // --------------------------------------------------------------------------- template @@ -226,16 +226,23 @@ public: return result; } - template - static inline bctbx_list_t *getCListOfStructPtrFromCppListOfCppObj (const std::list> cppList, CType *(*cTypeAllocator)()) { + // --------------------------------------------------------------------------- + // Resolved list conversions. + // --------------------------------------------------------------------------- + + template< + typename CppType, + typename = typename std::enable_if::value, CppType>::type + > + static inline bctbx_list_t *getResolvedCListFromCppList (const std::list> &cppList) { bctbx_list_t *result = nullptr; for (const auto &value : cppList) result = bctbx_list_append(result, getCBackPtr(value)); return result; } - template - static inline bctbx_list_t *getCListOfStructPtrFromCppListOfCppObj (const std::list cppList, CType *(*cTypeAllocator)()) { + template + static inline bctbx_list_t *getResolvedCListFromCppList (const std::list &cppList) { bctbx_list_t *result = nullptr; for (const auto &value : cppList) result = bctbx_list_append(result, getCBackPtr(value)); @@ -243,11 +250,11 @@ public: } template< - typename CppType, typename CType, + typename CppType = typename CTypeToCppType::type, typename = typename std::enable_if::value, CppType>::type > - static inline std::list> getCppListOfCppObjFromCListOfStructPtr (const bctbx_list_t *cList) { + static inline std::list> getResolvedCppListFromCList (const bctbx_list_t *cList) { std::list> result; for (auto it = cList; it; it = bctbx_list_next(it)) result.push_back(getCppPtrFromC(reinterpret_cast(bctbx_list_get_data(it)))); @@ -255,11 +262,11 @@ public: } template< - typename CppType, typename CType, + typename CppType = typename CTypeToCppType::type, typename = typename std::enable_if::value, CppType>::type > - static inline std::list getCppListOfCppObjFromCListOfStructPtr (const bctbx_list_t *cList) { + static inline std::list getResolvedCppListFromCList (const bctbx_list_t *cList) { std::list result; for (auto it = cList; it; it = bctbx_list_next(it)) result.push_back(*getCppPtrFromC(reinterpret_cast(bctbx_list_get_data(it)))); @@ -458,9 +465,10 @@ LINPHONE_END_NAMESPACE #define L_GET_CPP_LIST_FROM_C_LIST(C_LIST, TYPE) \ LINPHONE_NAMESPACE::Wrapper::getCppListFromCList(C_LIST) -#define L_GET_C_LIST_OF_STRUCT_PTR_FROM_CPP_LIST_OF_CPP_OBJ(LIST, CPP_TYPE, C_TYPE) \ - LINPHONE_NAMESPACE::Wrapper::getCListOfStructPtrFromCppListOfCppObj(LIST, _linphone_ ## C_TYPE ## _init) -#define L_GET_CPP_LIST_OF_CPP_OBJ_FROM_C_LIST_OF_STRUCT_PTR(LIST, CPP_TYPE, C_TYPE) \ - LINPHONE_NAMESPACE::Wrapper::getCppListOfCppObjFromCListOfStructPtr(LIST) +// Transforms cpp list and c list and convert cpp object to c object. +#define L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(CPP_LIST) \ + LINPHONE_NAMESPACE::Wrapper::getResolvedCListFromCppList(CPP_LIST) +#define L_GET_RESOLVED_CPP_LIST_FROM_C_LIST(C_LIST, C_TYPE) \ + LINPHONE_NAMESPACE::Wrapper::getResolvedCppListFromCList(C_LIST) #endif // ifndef _C_TOOLS_H_ From 96f21ef1f21cc9be9df9667b29156fc61bac9eec Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 25 Sep 2017 14:02:02 +0200 Subject: [PATCH 0162/2215] add conference tester --- tester/CMakeLists.txt | 3 +- tester/conference-tester.cpp | 90 ++++++++++++++++++++++++++++++++++++ tester/liblinphone_tester.h | 1 + tester/tester.c | 1 + 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 tester/conference-tester.cpp diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index 32833ac16..ed7fa481d 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -198,6 +198,7 @@ set(SOURCE_FILES_C set(SOURCE_FILES_CXX clonable-object-tester.cpp conference-event-tester.cpp + conference-tester.cpp cpim-tester.cpp events-db-tester.cpp property-container-tester.cpp @@ -211,7 +212,7 @@ if(APPLE) endif() # TODO: Remove me later! -list(REMOVE_ITEM STRICT_OPTIONS_CPP "-Wconversion" "-Werror=conversion") +list(REMOVE_ITEM STRICT_OPTIONS_CPP "-Wconversion" "-Werror=conversion" "-Wcast-align" "-Werror=cast-align") bc_apply_compile_flags(SOURCE_FILES_C STRICT_OPTIONS_CPP STRICT_OPTIONS_C) bc_apply_compile_flags(SOURCE_FILES_CXX STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX) diff --git a/tester/conference-tester.cpp b/tester/conference-tester.cpp new file mode 100644 index 000000000..6a3261989 --- /dev/null +++ b/tester/conference-tester.cpp @@ -0,0 +1,90 @@ +/* + * conference-event-tester.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "linphone/core.h" +#include "private.h" +#include "liblinphone_tester.h" +#include "conference/conference-listener.h" +#include "conference/local-conference.h" +#include "conference/remote-conference.h" + +using namespace LinphonePrivate; +using namespace std; + +static string first_invite = "" +"" +"" +" " +" " +" " +" " +" " +"" +""; + +static string alice_addr = "sip:alice@sip.linphone.org"; +static string bob_addr = "sip:bob@sip.linphone.org"; +static string john_addr = "sip:john-doe@sip.linphone.org"; +static string anne_addr = "sip:anne-onyme@sip.linphone.org"; +static string sarah_addr = "sip:sarah-bache@sip.linphone.org"; + +static string bob_name = "Le Bricoleur"; +static string sarah_name = "Sarah"; + +void first_invite_parsing() { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + Address marie_identity(linphone_address_as_string_uri_only(marie->identity)); + LocalConference localConf(marie->lc, marie_identity); + list> addresses = localConf.parseResourceLists(first_invite); + BC_ASSERT_EQUAL(addresses.size(), 5, int, "%d"); + if(addresses.size() != 5) { + goto end; + } + BC_ASSERT_TRUE(addresses.front()->asStringUriOnly() == alice_addr); + addresses.pop_front(); + + BC_ASSERT_TRUE(addresses.front()->asStringUriOnly() == bob_addr); + BC_ASSERT_TRUE(addresses.front()->getDisplayName() == bob_name); + addresses.pop_front(); + + BC_ASSERT_TRUE(addresses.front()->asStringUriOnly() == john_addr); + addresses.pop_front(); + + BC_ASSERT_TRUE(addresses.front()->asStringUriOnly() == anne_addr); + addresses.pop_front(); + + BC_ASSERT_TRUE(addresses.front()->asStringUriOnly() == sarah_addr); + BC_ASSERT_TRUE(addresses.front()->getDisplayName() == sarah_name); + addresses.pop_front(); + +end: + linphone_core_manager_destroy(marie); +} + +test_t conference_tests[] = { + TEST_NO_TAG("First invite parsing", first_invite_parsing) +}; + +test_suite_t conference_test_suite = { + "Conference", + nullptr, + nullptr, + liblinphone_tester_before_each, + liblinphone_tester_after_each, + sizeof(conference_tests) / sizeof(conference_tests[0]), conference_tests +}; diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 047fae3ed..8de7b8b61 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -44,6 +44,7 @@ extern test_suite_t call_test_suite; extern test_suite_t call_video_test_suite; extern test_suite_t clonable_object_test_suite; extern test_suite_t conference_event_test_suite; +extern test_suite_t conference_test_suite; extern test_suite_t cpim_test_suite; extern test_suite_t dtmf_test_suite; extern test_suite_t event_test_suite; diff --git a/tester/tester.c b/tester/tester.c index 1f8f94288..7f2d684bc 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -565,6 +565,7 @@ void liblinphone_tester_add_suites() { bc_tester_add_suite(&stun_test_suite); bc_tester_add_suite(&event_test_suite); bc_tester_add_suite(&conference_event_test_suite); + bc_tester_add_suite(&conference_test_suite); bc_tester_add_suite(&flexisip_test_suite); bc_tester_add_suite(&remote_provisioning_test_suite); bc_tester_add_suite(&quality_reporting_test_suite); From 437f43665e1df73c7a478f82be6c88069fcbdb7b Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 25 Sep 2017 14:18:30 +0200 Subject: [PATCH 0163/2215] feat(c-wrapper): now belle-sip types are declared in this file --- coreapi/account_creator.c | 6 +- coreapi/account_creator_service.c | 3 +- coreapi/authentication.c | 3 +- coreapi/buffer.c | 3 +- coreapi/call_log.c | 23 +++---- coreapi/conference.cc | 16 +++-- coreapi/contact_providers_priv.h | 3 +- coreapi/contactprovider.c | 5 +- coreapi/content.c | 3 +- coreapi/error_info.c | 13 ++-- coreapi/event.c | 3 +- coreapi/factory.c | 9 +-- coreapi/friend.c | 27 ++++---- coreapi/friendlist.c | 29 ++++----- coreapi/im_encryption_engine.c | 3 +- coreapi/im_notif_policy.c | 3 +- coreapi/info.c | 4 +- coreapi/linphone_tunnel_config.c | 5 +- coreapi/lpconfig.c | 3 +- coreapi/misc.c | 3 +- coreapi/nat_policy.c | 6 +- coreapi/payload_type.c | 5 +- coreapi/player.c | 4 +- coreapi/presence.c | 5 +- coreapi/private.h | 70 --------------------- coreapi/vcard.cc | 13 ++-- coreapi/video_definition.c | 3 +- coreapi/xmlrpc.c | 6 +- src/c-wrapper/c-wrapper.h | 100 ++++++++++++++++++++++++++---- 29 files changed, 197 insertions(+), 182 deletions(-) diff --git a/coreapi/account_creator.c b/coreapi/account_creator.c index 791201466..46b947ff6 100644 --- a/coreapi/account_creator.c +++ b/coreapi/account_creator.c @@ -20,9 +20,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/account_creator.h" #include "linphone/core.h" #include "linphone/lpconfig.h" -#include "private.h" + +#include "c-wrapper/c-wrapper.h" + #if !_WIN32 -#include "regex.h" + #include "regex.h" #endif #include diff --git a/coreapi/account_creator_service.c b/coreapi/account_creator_service.c index cd090148f..3cf0bbff6 100644 --- a/coreapi/account_creator_service.c +++ b/coreapi/account_creator_service.c @@ -19,7 +19,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/account_creator_service.h" #include "linphone/core.h" -#include "private.h" + +#include "c-wrapper/c-wrapper.h" BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneAccountCreatorService); diff --git a/coreapi/authentication.c b/coreapi/authentication.c index a280de6bf..8fdf050c4 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -23,9 +23,10 @@ */ #include "linphone/core.h" -#include "private.h" #include "linphone/lpconfig.h" +#include "c-wrapper/c-wrapper.h" + static void _linphone_auth_info_uninit(LinphoneAuthInfo *obj); static void _linphone_auth_info_copy(LinphoneAuthInfo *dst, const LinphoneAuthInfo *src); diff --git a/coreapi/buffer.c b/coreapi/buffer.c index d895b1357..ce28b271a 100644 --- a/coreapi/buffer.c +++ b/coreapi/buffer.c @@ -18,9 +18,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/core.h" -#include "private.h" - +#include "c-wrapper/c-wrapper.h" static void linphone_buffer_destroy(LinphoneBuffer *buffer) { if (buffer->content) belle_sip_free(buffer->content); diff --git a/coreapi/call_log.c b/coreapi/call_log.c index b4ec345b4..499f3f582 100644 --- a/coreapi/call_log.c +++ b/coreapi/call_log.c @@ -20,23 +20,24 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define _XOPEN_SOURCE 700 /*required for strptime of GNU libc*/ #include -#include "private.h" #ifdef SQLITE_STORAGE_ENABLED -#ifndef _WIN32 -#if !defined(__ANDROID__) && !defined(__QNXNTO__) -# include -# include -# include -#endif + #ifndef _WIN32 + #if !defined(__ANDROID__) && !defined(__QNXNTO__) + #include + #include + #include + #endif #else -#include + #include #endif #define MAX_PATH_SIZE 1024 -#include "sqlite3.h" + #include "sqlite3.h" #endif +#include "c-wrapper/c-wrapper.h" + typedef struct _CallLogStorageResult { LinphoneCore *core; bctbx_list_t *result; @@ -316,7 +317,7 @@ LinphoneCallLog * linphone_call_log_new(LinphoneCallDir dir, LinphoneAddress *fr set_call_log_date(cl,cl->start_date_time); cl->from=from; - cl->to=to; + cl->to=to; cl->status=LinphoneCallAborted; /*default status*/ cl->quality=-1; @@ -561,7 +562,7 @@ const bctbx_list_t *linphone_core_get_call_history(LinphoneCore *lc) { CallLogStorageResult clsres; if (!lc || lc->logs_db == NULL) return NULL; - if (lc->call_logs != NULL) return lc->call_logs; + if (lc->call_logs != NULL) return lc->call_logs; if (lc->max_call_logs != LINPHONE_MAX_CALL_HISTORY_UNLIMITED){ buf = sqlite3_mprintf("SELECT * FROM call_history ORDER BY id DESC LIMIT %i", lc->max_call_logs); diff --git a/coreapi/conference.cc b/coreapi/conference.cc index 7934b3585..0acc08e8d 100644 --- a/coreapi/conference.cc +++ b/coreapi/conference.cc @@ -23,14 +23,18 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "linphone/core.h" -#include "private.h" -#include "conference_private.h" -#include -#include -#include #include +#include #include +#include + +#include + +#include "linphone/core.h" + +#include "conference_private.h" + +#include "c-wrapper/c-wrapper.h" using namespace std; diff --git a/coreapi/contact_providers_priv.h b/coreapi/contact_providers_priv.h index 6f24a18b0..5170ad7c9 100644 --- a/coreapi/contact_providers_priv.h +++ b/coreapi/contact_providers_priv.h @@ -17,9 +17,10 @@ #ifndef CONTACT_PROVIDERS_PRIV_H #define CONTACT_PROVIDERS_PRIV_H -#include "private.h" #include "linphone/core.h" +#include "c-wrapper/c-wrapper.h" + /* Base for contact search and contact provider */ struct _LinphoneContactSearch{ diff --git a/coreapi/contactprovider.c b/coreapi/contactprovider.c index 5c1a36b75..cad4875b8 100644 --- a/coreapi/contactprovider.c +++ b/coreapi/contactprovider.c @@ -14,9 +14,10 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "contact_providers_priv.h" #include "linphone/contactprovider.h" -#include +#include "linphone/core.h" + +#include "contact_providers_priv.h" /* ############################ * * LinphoneContactSearchRequest * diff --git a/coreapi/content.c b/coreapi/content.c index 7637b1c54..86d2cfbcc 100644 --- a/coreapi/content.c +++ b/coreapi/content.c @@ -18,9 +18,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/core.h" -#include "private.h" - +#include "c-wrapper/c-wrapper.h" static void linphone_content_set_sal_body_handler(LinphoneContent *content, SalBodyHandler *body_handler) { if (content->body_handler != NULL) { diff --git a/coreapi/error_info.c b/coreapi/error_info.c index ffe29fed7..b70f96837 100644 --- a/coreapi/error_info.c +++ b/coreapi/error_info.c @@ -18,12 +18,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/core.h" -#include "private.h" + +#include "c-wrapper/c-wrapper.h" BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneErrorInfo); - - static void linphone_error_info_reset(LinphoneErrorInfo *ei); static void error_info_destroy(LinphoneErrorInfo *ei){ @@ -182,7 +181,7 @@ void linphone_error_info_from_sal_reason_ei(LinphoneErrorInfo *ei, const SalErro linphone_error_info_from_sal(ei, reason_ei); return; } - + if (ei->sub_ei){ if (reason_ei->reason == SalReasonNone){ linphone_error_info_unref(ei->sub_ei); @@ -220,12 +219,12 @@ void linphone_error_info_fields_to_sal(const LinphoneErrorInfo* ei, SalErrorInfo sei->protocol_code = ei->protocol_code; sei->protocol = bctbx_strdup(ei->protocol); } - + void linphone_error_info_to_sal(const LinphoneErrorInfo* ei, SalErrorInfo* sei){ - + linphone_error_info_fields_to_sal(ei, sei); if (ei->sub_ei !=NULL) { - + linphone_error_info_to_sal(ei->sub_ei, sei->sub_sei); } } diff --git a/coreapi/event.c b/coreapi/event.c index fb43c4a3d..d7a170822 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -18,9 +18,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/event.h" -#include "private.h" #include "linphone/lpconfig.h" +#include "c-wrapper/c-wrapper.h" + const char * linphone_subscription_dir_to_string(LinphoneSubscriptionDir dir){ switch(dir){ case LinphoneSubscriptionIncoming: diff --git a/coreapi/factory.c b/coreapi/factory.c index 65bc944e2..ee7cbc761 100644 --- a/coreapi/factory.c +++ b/coreapi/factory.c @@ -18,17 +18,18 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/factory.h" -#include "private.h" + +#include "c-wrapper/c-wrapper.h" #ifndef PACKAGE_SOUND_DIR -#define PACKAGE_SOUND_DIR "." + #define PACKAGE_SOUND_DIR "." #endif #ifndef PACKAGE_RING_DIR -#define PACKAGE_RING_DIR "." + #define PACKAGE_RING_DIR "." #endif #ifndef PACKAGE_DATA_DIR -#define PACKAGE_DATA_DIR "." + #define PACKAGE_DATA_DIR "." #endif extern LinphoneCore *_linphone_core_new_with_config(LinphoneCoreCbs *cbs, struct _LpConfig *config, void *userdata); diff --git a/coreapi/friend.c b/coreapi/friend.c index 523e0dc39..45f640072 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -23,24 +23,25 @@ */ #include "linphone/core.h" -#include "private.h" #include "linphone/lpconfig.h" #ifdef SQLITE_STORAGE_ENABLED -#ifndef _WIN32 -#if !defined(__ANDROID__) && !defined(__QNXNTO__) -# include -# include -# include -#endif + #ifndef _WIN32 + #if !defined(__ANDROID__) && !defined(__QNXNTO__) + #include + #include + #include + #endif #else -#include + #include #endif #define MAX_PATH_SIZE 1024 -#include "sqlite3.h" + #include "sqlite3.h" #endif +#include "c-wrapper/c-wrapper.h" + const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){ const char *str=NULL; switch(ss){ @@ -1258,13 +1259,13 @@ static bool_t linphone_update_friends_table(sqlite3* db) { int database_user_version = -1; char *errmsg = NULL; - if (sqlite3_prepare_v2(db, "PRAGMA user_version;", -1, &stmt_version, NULL) == SQLITE_OK) { - while(sqlite3_step(stmt_version) == SQLITE_ROW) { - database_user_version = sqlite3_column_int(stmt_version, 0); + if (sqlite3_prepare_v2(db, "PRAGMA user_version;", -1, &stmt_version, NULL) == SQLITE_OK) { + while(sqlite3_step(stmt_version) == SQLITE_ROW) { + database_user_version = sqlite3_column_int(stmt_version, 0); ms_debug("friends database user version = %i", database_user_version); } } - sqlite3_finalize(stmt_version); + sqlite3_finalize(stmt_version); if (database_user_version != 3100) { // Linphone 3.10.0 int ret = sqlite3_exec(db, diff --git a/coreapi/friendlist.c b/coreapi/friendlist.c index f29b626ff..a03536994 100644 --- a/coreapi/friendlist.c +++ b/coreapi/friendlist.c @@ -17,11 +17,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "linphone/core.h" -#include "private.h" - #include +#include "linphone/core.h" + +#include "c-wrapper/c-wrapper.h" + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneFriendListCbs); BELLE_SIP_INSTANCIATE_VPTR(LinphoneFriendListCbs, belle_sip_object_t, @@ -461,14 +462,14 @@ const LinphoneAddress * _linphone_friend_list_get_rls_address(const LinphoneFrie const char* rls_uri = lp_config_get_string(list->lc->config, "sip", "rls_uri", NULL); if (list->lc->default_rls_addr) linphone_address_unref(list->lc->default_rls_addr); - + list->lc->default_rls_addr=NULL; - + if (rls_uri) { /*to make sure changes in config are used if any*/ list->lc->default_rls_addr = linphone_address_new(rls_uri); } - + return list->lc->default_rls_addr; } else @@ -476,7 +477,7 @@ const LinphoneAddress * _linphone_friend_list_get_rls_address(const LinphoneFrie } void linphone_friend_list_set_rls_address(LinphoneFriendList *list, const LinphoneAddress *rls_addr){ LinphoneAddress *new_rls_addr = rls_addr ? linphone_address_clone(rls_addr) : NULL; - + if (list->rls_addr){ linphone_address_unref(list->rls_addr); } @@ -874,14 +875,14 @@ void linphone_friend_list_update_subscriptions(LinphoneFriendList *list){ const LinphoneAddress *address = _linphone_friend_list_get_rls_address(list); bool_t only_when_registered = FALSE; bool_t should_send_list_subscribe = FALSE; - + if (list->lc){ if (address) cfg = linphone_core_lookup_known_proxy(list->lc, address); only_when_registered = linphone_core_should_subscribe_friends_only_when_registered(list->lc); should_send_list_subscribe = (!only_when_registered || !cfg || cfg->state == LinphoneRegistrationOk); } - + if (address != NULL) { if (list->enable_subscriptions) { if (should_send_list_subscribe){ @@ -1008,7 +1009,7 @@ LinphoneCore* linphone_friend_list_get_core(const LinphoneFriendList *list) { static LinphoneStatus linphone_friend_list_import_friends_from_vcard4(LinphoneFriendList *list, bctbx_list_t *vcards) { bctbx_list_t *vcards_iterator = NULL; int count = 0; - + if (!linphone_core_vcard_supported()) { ms_error("vCard support wasn't enabled at compilation time"); return -1; @@ -1017,9 +1018,9 @@ static LinphoneStatus linphone_friend_list_import_friends_from_vcard4(LinphoneFr ms_error("Can't import into a NULL list"); return -1; } - + vcards_iterator = vcards; - + while (vcards_iterator != NULL && bctbx_list_get_data(vcards_iterator) != NULL) { LinphoneVcard *vcard = (LinphoneVcard *)bctbx_list_get_data(vcards_iterator); LinphoneFriend *lf = linphone_friend_new_from_vcard(vcard); @@ -1036,7 +1037,7 @@ static LinphoneStatus linphone_friend_list_import_friends_from_vcard4(LinphoneFr bctbx_list_free(vcards); linphone_core_store_friends_list_in_db(list->lc, list); return count; - + } LinphoneStatus linphone_friend_list_import_friends_from_vcard4_file(LinphoneFriendList *list, const char *vcard_file) { bctbx_list_t *vcards = NULL; @@ -1115,7 +1116,7 @@ void linphone_friend_list_enable_subscriptions(LinphoneFriendList *list, bool_t } else { linphone_friend_list_close_subscriptions(list); } - + } } diff --git a/coreapi/im_encryption_engine.c b/coreapi/im_encryption_engine.c index 3363b1dfe..6e32f430e 100644 --- a/coreapi/im_encryption_engine.c +++ b/coreapi/im_encryption_engine.c @@ -18,9 +18,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/core.h" -#include "linphone/im_encryption_engine.h" #include "private.h" +#include "c-wrapper/c-wrapper.h" + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneImEncryptionEngineCbs); BELLE_SIP_INSTANCIATE_VPTR(LinphoneImEncryptionEngineCbs, belle_sip_object_t, diff --git a/coreapi/im_notif_policy.c b/coreapi/im_notif_policy.c index 3502aa963..9b628a46c 100644 --- a/coreapi/im_notif_policy.c +++ b/coreapi/im_notif_policy.c @@ -18,8 +18,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/core.h" -#include "private.h" +#include "c-wrapper/c-wrapper.h" BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneImNotifPolicy); @@ -30,7 +30,6 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneImNotifPolicy, belle_sip_object_t, FALSE ); - static void load_im_notif_policy_from_config(LinphoneImNotifPolicy *policy) { bctbx_list_t *default_list = bctbx_list_append(NULL, (void *)"all"); bctbx_list_t *values = lp_config_get_string_list(policy->lc->config, "sip", "im_notif_policy", default_list); diff --git a/coreapi/info.c b/coreapi/info.c index 364f5cfab..ad37a9a30 100644 --- a/coreapi/info.c +++ b/coreapi/info.c @@ -22,11 +22,11 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - + #include "linphone/core.h" -#include "private.h" #include "linphone/lpconfig.h" +#include "c-wrapper/c-wrapper.h" struct _LinphoneInfoMessage{ belle_sip_object_t base; diff --git a/coreapi/linphone_tunnel_config.c b/coreapi/linphone_tunnel_config.c index b95d153fe..f51d9c8e6 100644 --- a/coreapi/linphone_tunnel_config.c +++ b/coreapi/linphone_tunnel_config.c @@ -21,8 +21,8 @@ */ #include "linphone/tunnel.h" -#include "private.h" +#include "c-wrapper/c-wrapper.h" struct _LinphoneTunnelConfig { belle_sip_object_t base; @@ -139,6 +139,3 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneTunnelConfig, belle_sip_object_t, NULL, // marshal FALSE ); - - - diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index be86c9038..6e1b5cb60 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -24,7 +24,6 @@ #define MAX_LEN 16384 -#include "private.h" #include "bctoolbox/vfs.h" #include "belle-sip/object.h" #include "xml2lpc.h" @@ -61,6 +60,8 @@ #include "linphone/lpconfig.h" #include "lpc2xml.h" +#include "c-wrapper/c-wrapper.h" + typedef struct _LpItem{ char *key; char *value; diff --git a/coreapi/misc.c b/coreapi/misc.c index f7c0cb7bf..cf1bd497b 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -18,7 +18,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "private.h" #include "linphone/lpconfig.h" #include "linphone/wrapper_utils.h" #include "mediastreamer2/mediastream.h" @@ -59,6 +58,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "nat/stun-client.h" #include "utils/payload-type-handler.h" +#include "c-wrapper/c-wrapper.h" + void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc){ const bctbx_list_t *elem; int maxbw=LinphonePrivate::PayloadTypeHandler::getMinBandwidth(linphone_core_get_download_bandwidth(lc), diff --git a/coreapi/nat_policy.c b/coreapi/nat_policy.c index 3290011d8..4d96016df 100644 --- a/coreapi/nat_policy.c +++ b/coreapi/nat_policy.c @@ -18,8 +18,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/core.h" -#include "private.h" +#include "c-wrapper/c-wrapper.h" static LinphoneNatPolicy * _linphone_nat_policy_new_with_ref(LinphoneCore *lc, const char *ref) { LinphoneNatPolicy *policy = belle_sip_object_new(LinphoneNatPolicy); @@ -274,7 +274,7 @@ LinphoneNatPolicy * linphone_config_create_nat_policy_from_section(const Linphon policy = _linphone_nat_policy_new_with_ref(NULL, config_ref); else policy = linphone_nat_policy_new(NULL); - + if (server != NULL) linphone_nat_policy_set_stun_server(policy, server); if (username != NULL) linphone_nat_policy_set_stun_server_username(policy, username); if (l != NULL) { @@ -298,7 +298,7 @@ LinphoneNatPolicy * linphone_core_create_nat_policy_from_config(LinphoneCore *lc char *section; int index; bool_t finished = FALSE; - + for (index = 0; finished != TRUE; index++) { section = belle_sip_strdup_printf("nat_policy_%i", index); if (lp_config_has_section(config, section)) { diff --git a/coreapi/payload_type.c b/coreapi/payload_type.c index a0d1ec800..b2b042181 100644 --- a/coreapi/payload_type.c +++ b/coreapi/payload_type.c @@ -19,9 +19,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include -#include "linphone/payload_type.h" -#include "private.h" +#include "linphone/payload_type.h" + +#include "c-wrapper/c-wrapper.h" #include "utils/payload-type-handler.h" struct _LinphonePayloadType { diff --git a/coreapi/player.c b/coreapi/player.c index 1f3b21e67..1bf49fd7f 100644 --- a/coreapi/player.c +++ b/coreapi/player.c @@ -18,7 +18,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "private.h" +#include "c-wrapper/c-wrapper.h" BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphonePlayer); @@ -181,7 +181,7 @@ static void call_player_close(LinphonePlayer *player){ if (!call_player_check_state(player,TRUE)) return; AudioStream *astream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeAudio)); audio_stream_close_remote_play(astream); - + } static void on_call_destroy(void *obj, belle_sip_object_t *call_being_destroyed){ diff --git a/coreapi/presence.c b/coreapi/presence.c index e8e87f181..0ffa56d5d 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -18,16 +18,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/core.h" -#include "private.h" #include "linphone/lpconfig.h" #include "linphone/presence.h" - +#include "c-wrapper/c-wrapper.h" extern const char *__policy_enum_to_str(LinphoneSubscribePolicy pol); - - struct _LinphonePresenceNote { belle_sip_object_t base; void *user_data; diff --git a/coreapi/private.h b/coreapi/private.h index ecd503718..46a3d3813 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -1602,76 +1602,6 @@ BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneVideoActivationPolicy); LINPHONE_PUBLIC LinphoneVideoActivationPolicy *linphone_video_activation_policy_new(void); - -/** Belle Sip-based objects need unique ids - */ - -BELLE_SIP_DECLARE_TYPES_BEGIN(linphone, 10000) -BELLE_SIP_TYPE_ID(LinphoneAccountCreator), -BELLE_SIP_TYPE_ID(LinphoneAccountCreatorCbs), -BELLE_SIP_TYPE_ID(LinphoneAccountCreatorService), -BELLE_SIP_TYPE_ID(LinphoneAddress), -BELLE_SIP_TYPE_ID(LinphoneAuthInfo), -BELLE_SIP_TYPE_ID(LinphoneBuffer), -BELLE_SIP_TYPE_ID(LinphoneCall), -BELLE_SIP_TYPE_ID(LinphoneCallCbs), -BELLE_SIP_TYPE_ID(LinphoneCallEvent), -BELLE_SIP_TYPE_ID(LinphoneCallLog), -BELLE_SIP_TYPE_ID(LinphoneCallParams), -BELLE_SIP_TYPE_ID(LinphoneCallStats), -BELLE_SIP_TYPE_ID(LinphoneChatMessage), -BELLE_SIP_TYPE_ID(LinphoneChatMessageCbs), -BELLE_SIP_TYPE_ID(LinphoneChatMessageEvent), -BELLE_SIP_TYPE_ID(LinphoneChatRoom), -BELLE_SIP_TYPE_ID(LinphoneChatRoomCbs), -BELLE_SIP_TYPE_ID(LinphoneConference), -BELLE_SIP_TYPE_ID(LinphoneConferenceEvent), -BELLE_SIP_TYPE_ID(LinphoneConferenceParams), -BELLE_SIP_TYPE_ID(LinphoneConferenceParticipantEvent), -BELLE_SIP_TYPE_ID(LinphoneConfig), -BELLE_SIP_TYPE_ID(LinphoneContactProvider), -BELLE_SIP_TYPE_ID(LinphoneContactSearch), -BELLE_SIP_TYPE_ID(LinphoneContent), -BELLE_SIP_TYPE_ID(LinphoneCore), -BELLE_SIP_TYPE_ID(LinphoneCoreCbs), -BELLE_SIP_TYPE_ID(LinphoneErrorInfo), -BELLE_SIP_TYPE_ID(LinphoneEvent), -BELLE_SIP_TYPE_ID(LinphoneEventLog), -BELLE_SIP_TYPE_ID(LinphoneFactory), -BELLE_SIP_TYPE_ID(LinphoneFriend), -BELLE_SIP_TYPE_ID(LinphoneFriendList), -BELLE_SIP_TYPE_ID(LinphoneFriendListCbs), -BELLE_SIP_TYPE_ID(LinphoneImEncryptionEngine), -BELLE_SIP_TYPE_ID(LinphoneImEncryptionEngineCbs), -BELLE_SIP_TYPE_ID(LinphoneImNotifPolicy), -BELLE_SIP_TYPE_ID(LinphoneInfoMessage), -BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider), -BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch), -BELLE_SIP_TYPE_ID(LinphoneNatPolicy), -BELLE_SIP_TYPE_ID(LinphoneParticipant), -BELLE_SIP_TYPE_ID(LinphonePayloadType), -BELLE_SIP_TYPE_ID(LinphonePlayer), -BELLE_SIP_TYPE_ID(LinphonePlayerCbs), -BELLE_SIP_TYPE_ID(LinphonePresenceActivity), -BELLE_SIP_TYPE_ID(LinphonePresenceModel), -BELLE_SIP_TYPE_ID(LinphonePresenceNote), -BELLE_SIP_TYPE_ID(LinphonePresencePerson), -BELLE_SIP_TYPE_ID(LinphonePresenceService), -BELLE_SIP_TYPE_ID(LinphoneProxyConfig), -BELLE_SIP_TYPE_ID(LinphoneRange), -BELLE_SIP_TYPE_ID(LinphoneTransports), -BELLE_SIP_TYPE_ID(LinphoneTunnel), -BELLE_SIP_TYPE_ID(LinphoneTunnelConfig), -BELLE_SIP_TYPE_ID(LinphoneVcard), -BELLE_SIP_TYPE_ID(LinphoneVideoActivationPolicy), -BELLE_SIP_TYPE_ID(LinphoneVideoDefinition), -BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequest), -BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequestCbs), -BELLE_SIP_TYPE_ID(LinphoneXmlRpcSession) -BELLE_SIP_DECLARE_TYPES_END - - - void linphone_core_notify_global_state_changed(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); void linphone_core_notify_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message); void linphone_core_notify_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token); diff --git a/coreapi/vcard.cc b/coreapi/vcard.cc index d020c78dc..b002a28c6 100644 --- a/coreapi/vcard.cc +++ b/coreapi/vcard.cc @@ -17,15 +17,18 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "vcard_private.h" -#include "belcard/belcard.hpp" -#include "belcard/belcard_parser.hpp" -#include "sal/sal.h" #include -#include "private.h" + +#include +#include + #include "linphone/factory.h" #include "linphone/wrapper_utils.h" +#include "c-wrapper/c-wrapper.h" +#include "sal/sal.h" +#include "vcard_private.h" + #define VCARD_MD5_HASH_SIZE 16 using namespace std; diff --git a/coreapi/video_definition.c b/coreapi/video_definition.c index 717fdfd73..2a357824a 100644 --- a/coreapi/video_definition.c +++ b/coreapi/video_definition.c @@ -20,8 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/factory.h" #include "linphone/video_definition.h" -#include "private.h" - +#include "c-wrapper/c-wrapper.h" static void linphone_video_definition_destroy(LinphoneVideoDefinition *vdef) { if (vdef->name) bctbx_free(vdef->name); diff --git a/coreapi/xmlrpc.c b/coreapi/xmlrpc.c index 221876f15..9410ae309 100644 --- a/coreapi/xmlrpc.c +++ b/coreapi/xmlrpc.c @@ -17,14 +17,13 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "linphone/core.h" -#include "private.h" - #include #include #include +#include "linphone/core.h" +#include "c-wrapper/c-wrapper.h" BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneXmlRpcRequestCbs); @@ -423,4 +422,3 @@ void linphone_xml_rpc_session_release(LinphoneXmlRpcSession *session){ session->released = TRUE; belle_sip_object_unref(session); } - diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index 4deafac57..fde36fed1 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -23,20 +23,96 @@ #include "internal/c-tools.h" +// ============================================================================= +// Declare exported C types. // ============================================================================= -L_REGISTER_TYPE(Address, Address); -L_REGISTER_TYPE(Call, Call); -L_REGISTER_TYPE(CallEvent, CallEvent); -L_REGISTER_TYPE(ChatMessage, ChatMessage); -L_REGISTER_TYPE(ChatMessageEvent, ChatMessageEvent); -L_REGISTER_TYPE(ChatRoom, ChatRoom); -L_REGISTER_TYPE(ConferenceEvent, ConferenceEvent); -L_REGISTER_TYPE(ConferenceParticipantEvent, ConferenceParticipantEvent); -L_REGISTER_TYPE(EventLog, EventLog); -L_REGISTER_TYPE(MediaSessionParams, CallParams); -L_REGISTER_TYPE(Participant, Participant); +#define L_REGISTER_TYPES(F) \ + F(Address, Address) \ + F(Call, Call) \ + F(CallEvent, CallEvent) \ + F(ChatMessage, ChatMessage) \ + F(ChatMessageEvent, ChatMessageEvent) \ + F(ChatRoom, ChatRoom) \ + F(ConferenceEvent, ConferenceEvent) \ + F(ConferenceParticipantEvent, ConferenceParticipantEvent) \ + F(EventLog, EventLog) \ + F(MediaSessionParams, CallParams) \ + F(Participant, Participant) -L_REGISTER_SUBTYPE(ChatRoom, ClientGroupChatRoom); +#define L_REGISTER_SUBTYPES(F) \ + F(ChatRoom, ClientGroupChatRoom) + +// ============================================================================= +// Register belle-sip ID. +// ============================================================================= + +#define L_REGISTER_ID(CPP_TYPE, C_TYPE) BELLE_SIP_TYPE_ID(Linphone ## C_TYPE), + +BELLE_SIP_DECLARE_TYPES_BEGIN(linphone, 10000) +L_REGISTER_TYPES(L_REGISTER_ID) +BELLE_SIP_TYPE_ID(LinphoneAccountCreator), +BELLE_SIP_TYPE_ID(LinphoneAccountCreatorCbs), +BELLE_SIP_TYPE_ID(LinphoneAccountCreatorService), +BELLE_SIP_TYPE_ID(LinphoneAuthInfo), +BELLE_SIP_TYPE_ID(LinphoneBuffer), +BELLE_SIP_TYPE_ID(LinphoneCallCbs), +BELLE_SIP_TYPE_ID(LinphoneCallLog), +BELLE_SIP_TYPE_ID(LinphoneCallStats), +BELLE_SIP_TYPE_ID(LinphoneChatMessageCbs), +BELLE_SIP_TYPE_ID(LinphoneChatRoomCbs), +BELLE_SIP_TYPE_ID(LinphoneConference), +BELLE_SIP_TYPE_ID(LinphoneConferenceParams), +BELLE_SIP_TYPE_ID(LinphoneConfig), +BELLE_SIP_TYPE_ID(LinphoneContactProvider), +BELLE_SIP_TYPE_ID(LinphoneContactSearch), +BELLE_SIP_TYPE_ID(LinphoneContent), +BELLE_SIP_TYPE_ID(LinphoneCore), +BELLE_SIP_TYPE_ID(LinphoneCoreCbs), +BELLE_SIP_TYPE_ID(LinphoneErrorInfo), +BELLE_SIP_TYPE_ID(LinphoneEvent), +BELLE_SIP_TYPE_ID(LinphoneFactory), +BELLE_SIP_TYPE_ID(LinphoneFriend), +BELLE_SIP_TYPE_ID(LinphoneFriendList), +BELLE_SIP_TYPE_ID(LinphoneFriendListCbs), +BELLE_SIP_TYPE_ID(LinphoneImEncryptionEngine), +BELLE_SIP_TYPE_ID(LinphoneImEncryptionEngineCbs), +BELLE_SIP_TYPE_ID(LinphoneImNotifPolicy), +BELLE_SIP_TYPE_ID(LinphoneInfoMessage), +BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider), +BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch), +BELLE_SIP_TYPE_ID(LinphoneNatPolicy), +BELLE_SIP_TYPE_ID(LinphonePayloadType), +BELLE_SIP_TYPE_ID(LinphonePlayer), +BELLE_SIP_TYPE_ID(LinphonePlayerCbs), +BELLE_SIP_TYPE_ID(LinphonePresenceActivity), +BELLE_SIP_TYPE_ID(LinphonePresenceModel), +BELLE_SIP_TYPE_ID(LinphonePresenceNote), +BELLE_SIP_TYPE_ID(LinphonePresencePerson), +BELLE_SIP_TYPE_ID(LinphonePresenceService), +BELLE_SIP_TYPE_ID(LinphoneProxyConfig), +BELLE_SIP_TYPE_ID(LinphoneRange), +BELLE_SIP_TYPE_ID(LinphoneTransports), +BELLE_SIP_TYPE_ID(LinphoneTunnel), +BELLE_SIP_TYPE_ID(LinphoneTunnelConfig), +BELLE_SIP_TYPE_ID(LinphoneVcard), +BELLE_SIP_TYPE_ID(LinphoneVideoActivationPolicy), +BELLE_SIP_TYPE_ID(LinphoneVideoDefinition), +BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequest), +BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequestCbs), +BELLE_SIP_TYPE_ID(LinphoneXmlRpcSession) +BELLE_SIP_DECLARE_TYPES_END + +#undef L_REGISTER_ID + +// ============================================================================= +// Register C types. +// ============================================================================= + +L_REGISTER_TYPES(L_REGISTER_TYPE); +L_REGISTER_SUBTYPES(L_REGISTER_SUBTYPE); + +#undef L_REGISTER_SUBTYPES +#undef L_REGISTER_TYPES #endif // ifndef _C_WRAPPER_H_ From d0e48986338d8174f8f51c233a7e7f43b6341587 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 25 Sep 2017 14:04:43 +0200 Subject: [PATCH 0164/2215] Rename and document conference factory uri API. --- coreapi/chat.c | 4 +++- coreapi/linphonecore.c | 8 ++++---- coreapi/private.h | 2 +- include/linphone/core.h | 14 ++++++++++++-- src/c-wrapper/api/c-chat-room.cpp | 4 ++-- src/chat/client-group-chat-room.cpp | 2 +- 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 61708382c..b033d8f34 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -124,7 +124,9 @@ LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAd } LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc) { - return linphone_client_group_chat_room_new(lc); + LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc); + lc->chatrooms = bctbx_list_append(lc->chatrooms, cr); + return cr; } void linphone_core_delete_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr) { diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 18db06759..a168fcbae 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -7067,12 +7067,12 @@ LinphoneConference *linphone_core_get_conference(LinphoneCore *lc) { return lc->conf_ctx; } -void linphone_core_set_chat_conference_factory_uri(LinphoneCore *lc, const char *uri) { - lp_config_set_string(linphone_core_get_config(lc), "misc", "chat_conference_factory_uri", uri); +void linphone_core_set_conference_factory_uri(LinphoneCore *lc, const char *uri) { + lp_config_set_string(linphone_core_get_config(lc), "misc", "conference_factory_uri", uri); } -const char * linphone_core_get_chat_conference_factory_uri(const LinphoneCore *lc) { - return lp_config_get_string(linphone_core_get_config(lc), "misc", "chat_conference_factory_uri", nullptr); +const char * linphone_core_get_conference_factory_uri(const LinphoneCore *lc) { + return lp_config_get_string(linphone_core_get_config(lc), "misc", "conference_factory_uri", nullptr); } void linphone_core_set_tls_cert(LinphoneCore *lc, const char *tls_cert) { diff --git a/coreapi/private.h b/coreapi/private.h index 46a3d3813..3899a8509 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -460,7 +460,7 @@ void _linphone_proxy_config_release_ops(LinphoneProxyConfig *obj); /*chat*/ LinphoneChatRoom * linphone_chat_room_new(LinphoneCore *core, const LinphoneAddress *addr); -LinphoneChatRoom * linphone_client_group_chat_room_new(LinphoneCore *lc); +LinphoneChatRoom *_linphone_client_group_chat_room_new(LinphoneCore *core); void linphone_chat_room_release(LinphoneChatRoom *cr); void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call); bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr); diff --git a/include/linphone/core.h b/include/linphone/core.h index ebb981018..231557035 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -4169,9 +4169,19 @@ LINPHONE_PUBLIC LinphoneStatus linphone_core_stop_conference_recording(LinphoneC */ LINPHONE_PUBLIC LinphoneConference *linphone_core_get_conference(LinphoneCore *lc); -void linphone_core_set_chat_conference_factory_uri(LinphoneCore *lc, const char *uri); +/** + * Set the conference factory uri. + * @param[in] lc A #LinphoneCore object + * @param[in] uri The uri of the conference factory + */ +void linphone_core_set_conference_factory_uri(LinphoneCore *lc, const char *uri); -const char * linphone_core_get_chat_conference_factory_uri(const LinphoneCore *lc); +/** + * Get the conference factory uri. + * @param[in] lc A #LinphoneCore object + * @return The uri of the conference factory + */ +const char * linphone_core_get_conference_factory_uri(const LinphoneCore *lc); /** * @} diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index debae113a..6ae4f109f 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -278,8 +278,8 @@ LinphoneChatRoom *linphone_chat_room_new (LinphoneCore *core, const LinphoneAddr return cr; } -LinphoneChatRoom *linphone_client_group_chat_room_new (LinphoneCore *core) { - const char *factoryUri = linphone_core_get_chat_conference_factory_uri(core); +LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core) { + const char *factoryUri = linphone_core_get_conference_factory_uri(core); if (!factoryUri) return nullptr; LinphoneAddress *factoryAddr = linphone_address_new(factoryUri); diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index bdf63dc9c..9e03e37d2 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -33,7 +33,7 @@ ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core) : Ch ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me) : ChatRoom(*new ChatRoomPrivate(core)), RemoteConference(core, me, nullptr) { - string factoryUri = linphone_core_get_chat_conference_factory_uri(core); + string factoryUri = linphone_core_get_conference_factory_uri(core); focus = make_shared(factoryUri); CallSessionParams csp; shared_ptr session = focus->getPrivate()->createSession(*this, &csp, false, this); From 35f48398f4cea82b8be4381d073a5b28cf1d5948 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 25 Sep 2017 14:07:57 +0200 Subject: [PATCH 0165/2215] Improve check for acceptation handling when receiving an incoming INVITE. --- src/call/call-listener.h | 1 + src/call/call-p.h | 1 + src/call/call.cpp | 21 ++++++++++++++++ src/conference/conference.cpp | 5 ++++ src/conference/conference.h | 1 + .../session/call-session-listener.h | 1 + src/conference/session/call-session.cpp | 25 +++---------------- 7 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/call/call-listener.h b/src/call/call-listener.h index 02c9f05dd..82f837989 100644 --- a/src/call/call-listener.h +++ b/src/call/call-listener.h @@ -34,6 +34,7 @@ public: virtual void onCallSetReleased () = 0; virtual void onCallSetTerminated () = 0; virtual void onCallStateChanged (LinphoneCallState state, const std::string &message) = 0; + virtual void onCheckForAcceptation () = 0; virtual void onIncomingCallStarted () = 0; virtual void onIncomingCallToBeAdded () = 0; diff --git a/src/call/call-p.h b/src/call/call-p.h index 29b4236ba..9f2ebabdd 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -60,6 +60,7 @@ private: void onCallSetReleased () override; void onCallSetTerminated () override; void onCallStateChanged (LinphoneCallState state, const std::string &message) override; + void onCheckForAcceptation () override; void onIncomingCallStarted () override; void onIncomingCallToBeAdded () override; void onEncryptionChanged (bool activated, const std::string &authToken) override; diff --git a/src/call/call.cpp b/src/call/call.cpp index 994be2887..7aefd00c5 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -142,6 +142,27 @@ void CallPrivate::onCallStateChanged (LinphoneCallState state, const string &mes linphone_call_notify_state_changed(lcall, state, message.c_str()); } +void CallPrivate::onCheckForAcceptation () { + bctbx_list_t *copy = bctbx_list_copy(linphone_core_get_calls(core)); + for (bctbx_list_t *it = copy; it != nullptr; it = bctbx_list_next(it)) { + LinphoneCall *call = reinterpret_cast(bctbx_list_get_data(it)); + if (call == lcall) continue; + switch (linphone_call_get_state(call)) { + case LinphoneCallOutgoingInit: + case LinphoneCallOutgoingProgress: + case LinphoneCallOutgoingRinging: + case LinphoneCallOutgoingEarlyMedia: + lInfo() << "Already existing call [" << call << "] in state [" << linphone_call_state_to_string(linphone_call_get_state(call)) + << "], canceling it before accepting new call [" << lcall << "]"; + linphone_call_terminate(call); + break; + default: + break; /* Nothing to do */ + } + } + bctbx_list_free(copy); +} + void CallPrivate::onIncomingCallStarted () { if (lcall) linphone_core_notify_incoming_call(core, lcall); diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 4a40d509c..99463295a 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -107,6 +107,11 @@ void Conference::onCallSessionStateChanged (const CallSession &session, Linphone callListener->onCallStateChanged(state, message); } +void Conference::onCheckForAcceptation (const CallSession &session) { + if (callListener) + callListener->onCheckForAcceptation(); +} + void Conference::onIncomingCallSessionStarted (const CallSession &session) { if (callListener) callListener->onIncomingCallStarted(); diff --git a/src/conference/conference.h b/src/conference/conference.h index 583a770c2..b1a1f4fee 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -64,6 +64,7 @@ private: void onCallSessionSetReleased (const CallSession &session) override; void onCallSessionSetTerminated (const CallSession &session) override; void onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message) override; + void onCheckForAcceptation (const CallSession &session) override; void onIncomingCallSessionStarted (const CallSession &session) override; void onEncryptionChanged (const CallSession &session, bool activated, const std::string &authToken) override; void onStatsUpdated (const LinphoneCallStats *stats) override; diff --git a/src/conference/session/call-session-listener.h b/src/conference/session/call-session-listener.h index 228820a29..e5dd8d8ca 100644 --- a/src/conference/session/call-session-listener.h +++ b/src/conference/session/call-session-listener.h @@ -33,6 +33,7 @@ public: virtual void onCallSessionSetReleased (const CallSession &session) = 0; virtual void onCallSessionSetTerminated (const CallSession &session) = 0; virtual void onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message) = 0; + virtual void onCheckForAcceptation (const CallSession &session) = 0; virtual void onIncomingCallSessionStarted (const CallSession &session) = 0; virtual void onEncryptionChanged (const CallSession &session, bool activated, const std::string &authToken) = 0; diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 91d1edb9b..392c632ca 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -451,25 +451,8 @@ LinphoneStatus CallSessionPrivate::checkForAcceptation () const { lError() << "checkForAcceptation() CallSession [" << q << "] is in state [" << linphone_call_state_to_string(state) << "], operation not permitted"; return -1; } - bctbx_list_t *copy = bctbx_list_copy(linphone_core_get_calls(core)); - for (bctbx_list_t *it = copy; it != nullptr; it = bctbx_list_next(it)) { - LinphoneCall *call = reinterpret_cast(bctbx_list_get_data(it)); - shared_ptr session = L_GET_PRIVATE_FROM_C_OBJECT(call)->getActiveSession(); - if (session.get() == q) continue; - switch (session->getState()) { - case LinphoneCallOutgoingInit: - case LinphoneCallOutgoingProgress: - case LinphoneCallOutgoingRinging: - case LinphoneCallOutgoingEarlyMedia: - lInfo() << "Already existing CallSession [" << session << "] in state [" << linphone_call_state_to_string(session->getState()) - << "], canceling it before accepting new CallSession [" << q << "]"; - session->terminate(); - break; - default: - break; /* Nothing to do */ - } - } - bctbx_list_free(copy); + if (listener) + listener->onCheckForAcceptation(*q); /* Check if this call is supposed to replace an already running one */ SalOp *replaced = sal_call_get_replaces(op); @@ -822,14 +805,14 @@ void CallSession::startIncomingNotification () { call->bg_task_id=sal_begin_background_task("liblinphone call notification", NULL, NULL); #endif if (d->deferIncomingNotification) { - lInfo() << "Defer ringing"; + lInfo() << "Defer incoming notification"; return; } if (d->listener) d->listener->onIncomingCallSessionStarted(*this); - d->setState(LinphoneCallIncomingReceived, "Incoming call"); + d->setState(LinphoneCallIncomingReceived, "Incoming CallSession"); /* From now on, the application is aware of the call and supposed to take background task or already submitted notification to the user. * We can then drop our background task. */ From f9fc3e1a814a4d385f8a993e431ca953e8d66094 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 25 Sep 2017 14:11:31 +0200 Subject: [PATCH 0166/2215] Change the state of the client group chat room to "created" when it has been created remotely. --- src/chat/client-group-chat-room.cpp | 15 +++++++++++++-- src/chat/client-group-chat-room.h | 5 +++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 9e03e37d2..4ecf2ee45 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -87,11 +87,13 @@ void ClientGroupChatRoom::removeParticipants (const list // ----------------------------------------------------------------------------- void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { - // TODO + L_D(ClientGroupChatRoom); + d->setState(ChatRoom::State::Created); } void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { - // TODO + L_D(ClientGroupChatRoom); + d->setState(ChatRoom::State::Terminated); } void ClientGroupChatRoom::onParticipantAdded (const Address &addr) { @@ -137,4 +139,13 @@ void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdm cb(cr, L_GET_C_BACK_PTR(participant), isAdmin); } +// ----------------------------------------------------------------------------- + +void ClientGroupChatRoom::onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message) { + if (state == LinphoneCallConnected) { + // TODO: Get the conference ID instead of the remote address + onConferenceCreated(session.getRemoteAddress()); + } +} + LINPHONE_END_NAMESPACE diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index aa31265c4..8207b62dd 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -24,6 +24,7 @@ #include "chat/chat-room.h" #include "conference/remote-conference.h" +#include "conference/session/call-session.h" #include "linphone/types.h" @@ -57,6 +58,10 @@ private: void onParticipantRemoved (const Address &addr) override; void onParticipantSetAdmin (const Address &addr, bool isAdmin) override; +private: + /* CallSessionListener */ + void onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message) override; + private: L_DECLARE_PRIVATE(ClientGroupChatRoom); L_DISABLE_COPY(ClientGroupChatRoom); From 84df0776a61ea7d3297d2cded634a99f3dba411f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 25 Sep 2017 14:49:55 +0200 Subject: [PATCH 0167/2215] Fix conference participants resource-list parsing and generation. --- src/conference/local-conference.cpp | 16 +++++----- src/conference/local-conference.h | 2 +- src/conference/remote-conference.cpp | 11 ++++--- src/conference/remote-conference.h | 2 +- tester/conference-tester.cpp | 45 ++++++++++++++-------------- 5 files changed, 36 insertions(+), 40 deletions(-) diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index 8e3b53a78..1de626295 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -59,20 +59,18 @@ void LocalConference::removeParticipant (const shared_ptr &pa } } -list> LocalConference::parseResourceLists(string xmlBody) { +list
    LocalConference::parseResourceLists (string xmlBody) { istringstream data(xmlBody); unique_ptr rl = LinphonePrivate::Xsd::ResourceLists::parseResourceLists(data, Xsd::XmlSchema::Flags::dont_validate); - list> addresses = list>(); - for(const auto &l : rl->getList()) { - for(const auto &entry : l.getEntry()) { - shared_ptr
    addr = make_shared
    (Address(entry.getUri())); - if(!entry.getDisplayName().present()) { - addr->setDisplayName(entry.getDisplayName().get()); - } + list
    addresses = list
    (); + for (const auto &l : rl->getList()) { + for (const auto &entry : l.getEntry()) { + Address addr(entry.getUri()); + if (entry.getDisplayName().present()) + addr.setDisplayName(entry.getDisplayName().get()); addresses.push_back(addr); } } - return addresses; } diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h index 1d20f9cb8..41a032765 100644 --- a/src/conference/local-conference.h +++ b/src/conference/local-conference.h @@ -38,7 +38,7 @@ public: std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void removeParticipant (const std::shared_ptr &participant) override; - std::list> parseResourceLists(std::string xmlBody); + std::list
    parseResourceLists (std::string xmlBody); private: L_DISABLE_COPY(LocalConference); diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index ade1aa1c4..f0d30eb98 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -60,14 +60,13 @@ void RemoteConference::removeParticipant (const shared_ptr &p } -string RemoteConference::getResourceLists(const list> &addresses) { +string RemoteConference::getResourceLists (const list &addresses) { ResourceLists rl = ResourceLists(); ListType l = ListType(); - for(const auto &addr : addresses) { - EntryType entry = EntryType(addr->asStringUriOnly()); - if(!addr->getDisplayName().empty()) { - entry.setDisplayName(DisplayName(addr->getDisplayName())); - } + for (const auto &addr : addresses) { + EntryType entry = EntryType(addr.asStringUriOnly()); + if (!addr.getDisplayName().empty()) + entry.setDisplayName(DisplayName(addr.getDisplayName())); l.getEntry().push_back(entry); } rl.getList().push_back(l); diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index 718bf6edb..801dfff8c 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -39,7 +39,7 @@ public: std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void removeParticipant (const std::shared_ptr &participant) override; - std::string getResourceLists(const std::list> &addresses); + std::string getResourceLists (const std::list &addresses); protected: /* ConferenceListener */ diff --git a/tester/conference-tester.cpp b/tester/conference-tester.cpp index 6a3261989..111265d84 100644 --- a/tester/conference-tester.cpp +++ b/tester/conference-tester.cpp @@ -26,50 +26,49 @@ using namespace LinphonePrivate; using namespace std; -static string first_invite = "" +static const string firstInvite = "" "" "" " " -" " +" Le Bricoleur" " " " " -" " +" Sarah" "" ""; -static string alice_addr = "sip:alice@sip.linphone.org"; -static string bob_addr = "sip:bob@sip.linphone.org"; -static string john_addr = "sip:john-doe@sip.linphone.org"; -static string anne_addr = "sip:anne-onyme@sip.linphone.org"; -static string sarah_addr = "sip:sarah-bache@sip.linphone.org"; +static const string aliceAddr = "sip:alice@sip.linphone.org"; +static const string bobAddr = "sip:bob@sip.linphone.org"; +static const string johnAddr = "sip:john-doe@sip.linphone.org"; +static const string anneAddr = "sip:anne-onyme@sip.linphone.org"; +static const string sarahAddr = "sip:sarah-bache@sip.linphone.org"; -static string bob_name = "Le Bricoleur"; -static string sarah_name = "Sarah"; +static const string bobName = "Le Bricoleur"; +static const string sarahName = "Sarah"; -void first_invite_parsing() { +void first_invite_parsing () { LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); - Address marie_identity(linphone_address_as_string_uri_only(marie->identity)); - LocalConference localConf(marie->lc, marie_identity); - list> addresses = localConf.parseResourceLists(first_invite); + Address marieIdentity(linphone_address_as_string_uri_only(marie->identity)); + LocalConference localConf(marie->lc, marieIdentity); + list
    addresses = localConf.parseResourceLists(firstInvite); BC_ASSERT_EQUAL(addresses.size(), 5, int, "%d"); - if(addresses.size() != 5) { + if (addresses.size() != 5) goto end; - } - BC_ASSERT_TRUE(addresses.front()->asStringUriOnly() == alice_addr); + BC_ASSERT_TRUE(addresses.front().asStringUriOnly() == aliceAddr); addresses.pop_front(); - BC_ASSERT_TRUE(addresses.front()->asStringUriOnly() == bob_addr); - BC_ASSERT_TRUE(addresses.front()->getDisplayName() == bob_name); + BC_ASSERT_TRUE(addresses.front().asStringUriOnly() == bobAddr); + BC_ASSERT_TRUE(addresses.front().getDisplayName() == bobName); addresses.pop_front(); - BC_ASSERT_TRUE(addresses.front()->asStringUriOnly() == john_addr); + BC_ASSERT_TRUE(addresses.front().asStringUriOnly() == johnAddr); addresses.pop_front(); - BC_ASSERT_TRUE(addresses.front()->asStringUriOnly() == anne_addr); + BC_ASSERT_TRUE(addresses.front().asStringUriOnly() == anneAddr); addresses.pop_front(); - BC_ASSERT_TRUE(addresses.front()->asStringUriOnly() == sarah_addr); - BC_ASSERT_TRUE(addresses.front()->getDisplayName() == sarah_name); + BC_ASSERT_TRUE(addresses.front().asStringUriOnly() == sarahAddr); + BC_ASSERT_TRUE(addresses.front().getDisplayName() == sarahName); addresses.pop_front(); end: From fc861ade8a5f5c1c246b929d8781030fff15afc6 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 25 Sep 2017 15:22:10 +0200 Subject: [PATCH 0168/2215] feat(Variant): add getValueAsNumber impl --- include/linphone/utils/utils.h | 2 ++ src/utils/utils.cpp | 36 +++++++++++++++------------------- src/variant/variant.cpp | 33 ++++++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 21 deletions(-) diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h index c6ffd2855..8a160d63b 100644 --- a/include/linphone/utils/utils.h +++ b/include/linphone/utils/utils.h @@ -70,11 +70,13 @@ namespace Utils { LINPHONE_PUBLIC std::string toString (const void *val); LINPHONE_PUBLIC int stoi (const std::string &str, size_t *idx = 0, int base = 10); + LINPHONE_PUBLIC long long stoll (const std::string &str, size_t *idx = 0, int base = 10); LINPHONE_PUBLIC double stod (const std::string &str, size_t *idx = 0); LINPHONE_PUBLIC float stof (const std::string &str, size_t *idx = 0); LINPHONE_PUBLIC bool stob (const std::string &str); LINPHONE_PUBLIC int stoi (const char *str, size_t *idx = 0, int base = 10); + LINPHONE_PUBLIC long long stoll (const char *str, size_t *idx = 0, int base = 10); LINPHONE_PUBLIC double stod (const char *str, size_t *idx = 0); LINPHONE_PUBLIC float stof (const char *str, size_t *idx = 0); diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 877206952..e91583b34 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -85,33 +85,19 @@ string Utils::toString (const void *val) { } int Utils::stoi (const string &str, size_t *idx, int base) { - char *p; - int v = static_cast(strtol(str.c_str(), &p, base)); + return stoi(str.c_str(), idx, base); +} - if (idx) - *idx = static_cast(p - str.c_str()); - - return v; +long long Utils::stoll (const string &str, size_t *idx, int base) { + return stoll(str.c_str(), idx, base); } double Utils::stod (const string &str, size_t *idx) { - char *p; - double v = strtod(str.c_str(), &p); - - if (idx) - *idx = static_cast(p - str.c_str()); - - return v; + return stod(str.c_str(), idx); } float Utils::stof (const string &str, size_t *idx) { - char *p; - float v = strtof(str.c_str(), &p); - - if (idx) - *idx = static_cast(p - str.c_str()); - - return v; + return stof(str.c_str(), idx); } bool Utils::stob (const string &str) { @@ -129,6 +115,16 @@ int Utils::stoi (const char *str, size_t *idx, int base) { return v; } +long long Utils::stoll (const char *str, size_t *idx, int base) { + char *p; + long long v = static_cast(strtoll(str, &p, base)); + + if (idx) + *idx = static_cast(p - str); + + return v; +} + double Utils::stod (const char *str, size_t *idx) { char *p; double v = strtod(str, &p); diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index 96e5484d2..defd7b847 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -315,7 +315,38 @@ static inline unsigned long long getAssumedUnsignedNumber (const VariantPrivate // ----------------------------------------------------------------------------- static inline long long getValueAsNumber (const VariantPrivate &p, bool *soFarSoGood) { - // TODO. + const int type = p.getType(); + L_ASSERT(type > Variant::Invalid && type < Variant::MaxDefaultTypes); + + switch (static_cast(type)) { + case Variant::Int: + case Variant::Short: + case Variant::Long: + case Variant::LongLong: + case Variant::Char: + case Variant::Double: + case Variant::Float: + return getAssumedNumber(p); + + case Variant::UnsignedInt: + case Variant::UnsignedShort: + case Variant::UnsignedLong: + case Variant::UnsignedLongLong: + return static_cast(getAssumedUnsignedNumber(p)); + + case Variant::Bool: + return static_cast(p.value.b); + + case Variant::String: + return Utils::stoll(*p.value.str); + + case Variant::Generic: + return static_cast(!!p.value.g); + + default: + *soFarSoGood = false; + } + return 0; } From 352aa5568c38256a7247a0f4caadff35f3e62555 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 25 Sep 2017 15:28:36 +0200 Subject: [PATCH 0169/2215] feat(Variant): add getValueAsUnsignedNumber impl --- include/linphone/utils/utils.h | 2 ++ src/utils/utils.cpp | 14 ++++++++++++++ src/variant/variant.cpp | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h index 8a160d63b..cf384f01c 100644 --- a/include/linphone/utils/utils.h +++ b/include/linphone/utils/utils.h @@ -71,12 +71,14 @@ namespace Utils { LINPHONE_PUBLIC int stoi (const std::string &str, size_t *idx = 0, int base = 10); LINPHONE_PUBLIC long long stoll (const std::string &str, size_t *idx = 0, int base = 10); + LINPHONE_PUBLIC unsigned long long stoull (const std::string &str, size_t *idx = 0, int base = 10); LINPHONE_PUBLIC double stod (const std::string &str, size_t *idx = 0); LINPHONE_PUBLIC float stof (const std::string &str, size_t *idx = 0); LINPHONE_PUBLIC bool stob (const std::string &str); LINPHONE_PUBLIC int stoi (const char *str, size_t *idx = 0, int base = 10); LINPHONE_PUBLIC long long stoll (const char *str, size_t *idx = 0, int base = 10); + LINPHONE_PUBLIC unsigned long long stoull (const char *str, size_t *idx = 0, int base = 10); LINPHONE_PUBLIC double stod (const char *str, size_t *idx = 0); LINPHONE_PUBLIC float stof (const char *str, size_t *idx = 0); diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index e91583b34..66261305b 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -92,6 +92,10 @@ long long Utils::stoll (const string &str, size_t *idx, int base) { return stoll(str.c_str(), idx, base); } +unsigned long long Utils::stoull (const string &str, size_t *idx, int base) { + return stoull(str.c_str(), idx, base); +} + double Utils::stod (const string &str, size_t *idx) { return stod(str.c_str(), idx); } @@ -125,6 +129,16 @@ long long Utils::stoll (const char *str, size_t *idx, int base) { return v; } +unsigned long long Utils::stoull (const char *str, size_t *idx, int base) { + char *p; + unsigned long long v = static_cast(strtoull(str, &p, base)); + + if (idx) + *idx = static_cast(p - str); + + return v; +} + double Utils::stod (const char *str, size_t *idx) { char *p; double v = strtod(str, &p); diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index defd7b847..7590002dd 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -351,7 +351,38 @@ static inline long long getValueAsNumber (const VariantPrivate &p, bool *soFarSo } static inline unsigned long long getValueAsUnsignedNumber (const VariantPrivate &p, bool *soFarSoGood) { - // TODO. + const int type = p.getType(); + L_ASSERT(type > Variant::Invalid && type < Variant::MaxDefaultTypes); + + switch (static_cast(type)) { + case Variant::Int: + case Variant::Short: + case Variant::Long: + case Variant::LongLong: + case Variant::Char: + case Variant::Double: + case Variant::Float: + return static_cast(getAssumedNumber(p)); + + case Variant::UnsignedInt: + case Variant::UnsignedShort: + case Variant::UnsignedLong: + case Variant::UnsignedLongLong: + return getAssumedUnsignedNumber(p); + + case Variant::Bool: + return static_cast(p.value.b); + + case Variant::String: + return Utils::stoull(*p.value.str); + + case Variant::Generic: + return static_cast(!!p.value.g); + + default: + *soFarSoGood = false; + } + return 0; } From 2c7994a27bc6857da7d334da9d4de27cdb0d958e Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 25 Sep 2017 15:34:26 +0200 Subject: [PATCH 0170/2215] add first_invite_generating conference tester --- src/conference/remote-conference.cpp | 2 +- src/conference/remote-conference.h | 2 +- tester/conference-tester.cpp | 52 +++++++++++++++++++++++----- 3 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index f0d30eb98..2200d417d 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -60,7 +60,7 @@ void RemoteConference::removeParticipant (const shared_ptr &p } -string RemoteConference::getResourceLists (const list &addresses) { +string RemoteConference::getResourceLists (const list
    &addresses) { ResourceLists rl = ResourceLists(); ListType l = ListType(); for (const auto &addr : addresses) { diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index 801dfff8c..3277ba520 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -39,7 +39,7 @@ public: std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void removeParticipant (const std::shared_ptr &participant) override; - std::string getResourceLists (const std::list &addresses); + std::string getResourceLists (const std::list
    &addresses); protected: /* ConferenceListener */ diff --git a/tester/conference-tester.cpp b/tester/conference-tester.cpp index 111265d84..60939bd17 100644 --- a/tester/conference-tester.cpp +++ b/tester/conference-tester.cpp @@ -19,7 +19,6 @@ #include "linphone/core.h" #include "private.h" #include "liblinphone_tester.h" -#include "conference/conference-listener.h" #include "conference/local-conference.h" #include "conference/remote-conference.h" @@ -46,15 +45,14 @@ static const string sarahAddr = "sip:sarah-bache@sip.linphone.org"; static const string bobName = "Le Bricoleur"; static const string sarahName = "Sarah"; -void first_invite_parsing () { - LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); - Address marieIdentity(linphone_address_as_string_uri_only(marie->identity)); - LocalConference localConf(marie->lc, marieIdentity); - list
    addresses = localConf.parseResourceLists(firstInvite); +static void check_first_invite(LinphoneCore *core, const Address &address, string invite) { + LocalConference localConf(core, address); + list
    addresses = localConf.parseResourceLists(invite); BC_ASSERT_EQUAL(addresses.size(), 5, int, "%d"); if (addresses.size() != 5) - goto end; + return; BC_ASSERT_TRUE(addresses.front().asStringUriOnly() == aliceAddr); + BC_ASSERT_TRUE(addresses.front().getDisplayName().empty()); addresses.pop_front(); BC_ASSERT_TRUE(addresses.front().asStringUriOnly() == bobAddr); @@ -62,21 +60,57 @@ void first_invite_parsing () { addresses.pop_front(); BC_ASSERT_TRUE(addresses.front().asStringUriOnly() == johnAddr); + BC_ASSERT_TRUE(addresses.front().getDisplayName().empty()); addresses.pop_front(); BC_ASSERT_TRUE(addresses.front().asStringUriOnly() == anneAddr); + BC_ASSERT_TRUE(addresses.front().getDisplayName().empty()); addresses.pop_front(); BC_ASSERT_TRUE(addresses.front().asStringUriOnly() == sarahAddr); BC_ASSERT_TRUE(addresses.front().getDisplayName() == sarahName); addresses.pop_front(); - +} + +void first_invite_parsing () { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + const Address marieIdentity(linphone_address_as_string_uri_only(marie->identity)); + check_first_invite(marie->lc, marieIdentity, firstInvite); + linphone_core_manager_destroy(marie); +} + +void first_invite_serializing() { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + const Address marieIdentity(linphone_address_as_string_uri_only(marie->identity)); + RemoteConference remoteConf(marie->lc, marieIdentity); + list
    addresses = list
    (); + string xmlBody; + + Address aliceIdentity(aliceAddr); + Address bobIdentity(bobAddr); + Address johnIdentity(johnAddr); + Address anneIdentity(anneAddr); + Address sarahIdentity(sarahAddr); + + bobIdentity.setDisplayName(bobName); + sarahIdentity.setDisplayName(sarahName); + + addresses.push_back(aliceIdentity); + addresses.push_back(bobIdentity); + addresses.push_back(johnIdentity); + addresses.push_back(anneIdentity); + addresses.push_back(sarahIdentity); + + xmlBody = remoteConf.getResourceLists(addresses); + check_first_invite(marie->lc, marieIdentity, xmlBody); + end: linphone_core_manager_destroy(marie); } test_t conference_tests[] = { - TEST_NO_TAG("First invite parsing", first_invite_parsing) + TEST_NO_TAG("First invite parsing", first_invite_parsing), + TEST_NO_TAG("First invite serializing", first_invite_serializing) }; test_suite_t conference_test_suite = { From 37e25a736feaf41ac5d07d6bac16612144b01d59 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 25 Sep 2017 15:39:23 +0200 Subject: [PATCH 0171/2215] Fix build. --- tester/conference-tester.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/tester/conference-tester.cpp b/tester/conference-tester.cpp index 60939bd17..ca195fbfa 100644 --- a/tester/conference-tester.cpp +++ b/tester/conference-tester.cpp @@ -103,8 +103,6 @@ void first_invite_serializing() { xmlBody = remoteConf.getResourceLists(addresses); check_first_invite(marie->lc, marieIdentity, xmlBody); - -end: linphone_core_manager_destroy(marie); } From b44546279430f1d0a5de97d4d72eee98a047d829 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 25 Sep 2017 15:42:59 +0200 Subject: [PATCH 0172/2215] fix(utils): better code for strtoxxx --- src/utils/utils.cpp | 107 ++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 64 deletions(-) diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 66261305b..0ff383c5f 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -43,6 +43,8 @@ bool Utils::iequals (const string &a, const string &b) { return true; } +// ----------------------------------------------------------------------------- + vector Utils::split (const string &str, const string &delimiter) { vector out; @@ -54,6 +56,8 @@ vector Utils::split (const string &str, const string &delimiter) { return out; } +// ----------------------------------------------------------------------------- + #ifndef __ANDROID__ #define TO_STRING_IMPL(TYPE) \ string Utils::toString(TYPE val) { \ @@ -78,86 +82,59 @@ TO_STRING_IMPL(float) TO_STRING_IMPL(double) TO_STRING_IMPL(long double) +#undef TO_STRING_IMPL + string Utils::toString (const void *val) { ostringstream ss; ss << val; return ss.str(); } -int Utils::stoi (const string &str, size_t *idx, int base) { - return stoi(str.c_str(), idx, base); -} +// ----------------------------------------------------------------------------- -long long Utils::stoll (const string &str, size_t *idx, int base) { - return stoll(str.c_str(), idx, base); -} +#define STRING_TO_NUMBER_IMPL(TYPE, SUFFIX) \ + TYPE Utils::sto ## SUFFIX (const string &str, size_t *idx, int base) { \ + return sto ## SUFFIX(str.c_str(), idx, base); \ + } \ + TYPE Utils::sto ## SUFFIX (const char *str, size_t *idx, int base) { \ + char *p; \ + TYPE v = strto ## SUFFIX(str, &p, base); \ + if (idx) \ + *idx = static_cast(p - str); \ + return v; \ + } \ -unsigned long long Utils::stoull (const string &str, size_t *idx, int base) { - return stoull(str.c_str(), idx, base); -} +#define STRING_TO_NUMBER_IMPL_BASE_LESS(TYPE, SUFFIX) \ + TYPE Utils::sto ## SUFFIX (const string &str, size_t *idx) { \ + return sto ## SUFFIX(str.c_str(), idx); \ + } \ + TYPE Utils::sto ## SUFFIX (const char *str, size_t *idx) { \ + char *p; \ + TYPE v = strto ## SUFFIX(str, &p); \ + if (idx) \ + *idx = static_cast(p - str); \ + return v; \ + } \ -double Utils::stod (const string &str, size_t *idx) { - return stod(str.c_str(), idx); -} +#define strtoi(STR, IDX, BASE) static_cast(strtol(STR, IDX, BASE)) +STRING_TO_NUMBER_IMPL(int, i) +#undef strtoi -float Utils::stof (const string &str, size_t *idx) { - return stof(str.c_str(), idx); -} +STRING_TO_NUMBER_IMPL(long long, ll) +STRING_TO_NUMBER_IMPL(unsigned long long, ull) + +STRING_TO_NUMBER_IMPL_BASE_LESS(double, d) +STRING_TO_NUMBER_IMPL_BASE_LESS(float, f) + +#undef STRING_TO_NUMBER_IMPL +#undef STRING_TO_NUMBER_IMPL_BASE_LESS bool Utils::stob (const string &str) { const string lowerStr = stringToLower(str); return !lowerStr.empty() && (lowerStr == "true" || lowerStr == "1"); } -int Utils::stoi (const char *str, size_t *idx, int base) { - char *p; - int v = static_cast(strtol(str, &p, base)); - - if (idx) - *idx = static_cast(p - str); - - return v; -} - -long long Utils::stoll (const char *str, size_t *idx, int base) { - char *p; - long long v = static_cast(strtoll(str, &p, base)); - - if (idx) - *idx = static_cast(p - str); - - return v; -} - -unsigned long long Utils::stoull (const char *str, size_t *idx, int base) { - char *p; - unsigned long long v = static_cast(strtoull(str, &p, base)); - - if (idx) - *idx = static_cast(p - str); - - return v; -} - -double Utils::stod (const char *str, size_t *idx) { - char *p; - double v = strtod(str, &p); - - if (idx) - *idx = static_cast(p - str); - - return v; -} - -float Utils::stof (const char *str, size_t *idx) { - char *p; - float v = strtof(str, &p); - - if (idx) - *idx = static_cast(p - str); - - return v; -} +// ----------------------------------------------------------------------------- string Utils::stringToLower (const string &str) { string result(str.size(), ' '); @@ -165,6 +142,8 @@ string Utils::stringToLower (const string &str) { return result; } +// ----------------------------------------------------------------------------- + char *Utils::utf8ToChar (uint32_t ic) { char *result = new char[5]; int size = 0; From 0cee5a91a4b4d4ff23e41a743db86d48847ab66c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 25 Sep 2017 15:59:46 +0200 Subject: [PATCH 0173/2215] Started to move code from C to CPP for ChatMessage --- src/c-wrapper/api/c-chat-message.cpp | 142 ++++++++++------------ src/chat/chat-message-p.h | 13 +- src/chat/chat-message.cpp | 174 ++++++++++++++++++++++----- src/chat/chat-message.h | 50 ++++++-- src/content/content.cpp | 5 + src/content/content.h | 4 +- 6 files changed, 262 insertions(+), 126 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 5e324b42f..d8292eaf2 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -24,6 +24,7 @@ #include "c-wrapper/c-wrapper.h" #include "chat/chat-message-p.h" +#include "chat/chat-message.h" #include "chat/chat-room-p.h" #include "chat/real-time-text-chat-room-p.h" #include "content/content-type.h" @@ -102,44 +103,89 @@ void linphone_chat_message_set_user_data (LinphoneChatMessage *msg, void *ud) { // ============================================================================= const char *linphone_chat_message_get_external_body_url(const LinphoneChatMessage *msg) { - return msg->external_body_url; + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getExternalBodyUrl().c_str(); } void linphone_chat_message_set_external_body_url(LinphoneChatMessage *msg, const char *url) { - if (msg->external_body_url) { - ms_free(msg->external_body_url); - } - msg->external_body_url = url ? ms_strdup(url) : NULL; + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setExternalBodyUrl(string(url)); } time_t linphone_chat_message_get_time(const LinphoneChatMessage *msg) { - return msg->time; + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getTime(); } void linphone_chat_message_set_time(LinphoneChatMessage *msg, time_t time) { - msg->time = time; -} - -void linphone_chat_message_set_is_secured(LinphoneChatMessage *msg, bool_t secured) { - msg->is_secured = secured; + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setTime(time); } bool_t linphone_chat_message_is_secured(LinphoneChatMessage *msg) { - return msg->is_secured; + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->isSecured(); +} + +void linphone_chat_message_set_is_secured(LinphoneChatMessage *msg, bool_t secured) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setIsSecured(secured); } bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage *msg) { - return msg->dir == LinphoneChatMessageOutgoing; + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->isOutgoing(); } void linphone_chat_message_set_incoming(LinphoneChatMessage *msg) { - msg->dir = LinphoneChatMessageIncoming; + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setDirection(LinphonePrivate::ChatMessage::Direction::Incoming); } void linphone_chat_message_set_outgoing(LinphoneChatMessage *msg) { - msg->dir = LinphoneChatMessageOutgoing; + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setDirection(LinphonePrivate::ChatMessage::Direction::Outgoing); } +const char * linphone_chat_message_get_content_type(const LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getContentType().c_str(); +} + +const char *linphone_chat_message_get_text(const LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getText().c_str(); +} + +unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getStorageId(); +} + +LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage *msg) { + return ((LinphoneChatMessageState)L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getState()); +} + +void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessageState state) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setState((LinphonePrivate::ChatMessage::State)state); +} + +const char* linphone_chat_message_get_message_id(const LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getId().c_str(); +} + +void linphone_chat_message_set_message_id(LinphoneChatMessage *msg, char *id) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setId(id); +} + +void linphone_chat_message_set_storage_id(LinphoneChatMessage *msg, unsigned int id) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setStorageId(id); +} + +void linphone_chat_message_set_is_read(LinphoneChatMessage *msg, bool_t is_read) { + if (is_read) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->markAsRead(); + } +} + +const char *linphone_chat_message_get_appdata(const LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getAppdata().c_str(); +} + +void linphone_chat_message_set_appdata(LinphoneChatMessage *msg, const char *data) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setAppdata(data); +} + +// ============================================================================= + void linphone_chat_message_set_from_address(LinphoneChatMessage *msg, const LinphoneAddress *from) { if (msg->from) linphone_address_unref(msg->from); @@ -165,6 +211,8 @@ const LinphoneAddress *linphone_chat_message_get_to_address(const LinphoneChatMe return NULL; } +// ============================================================================= + void linphone_chat_message_set_message_state_changed_cb(LinphoneChatMessage* msg, LinphoneChatMessageStateChangedCb cb) { msg->message_state_changed_cb = cb; } @@ -177,10 +225,6 @@ void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChat return msg->message_state_changed_user_data; } -const char * linphone_chat_message_get_content_type(const LinphoneChatMessage *msg) { - return msg->content_type; -} - void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char *content_type) { if (msg->content_type) { ms_free(msg->content_type); @@ -188,10 +232,6 @@ void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char msg->content_type = content_type ? ms_strdup(content_type) : NULL; } -const char *linphone_chat_message_get_text(const LinphoneChatMessage *msg) { - return msg->message; -} - int linphone_chat_message_set_text(LinphoneChatMessage *msg, const char* text) { if (msg->message) ms_free(msg->message); @@ -203,58 +243,6 @@ int linphone_chat_message_set_text(LinphoneChatMessage *msg, const char* text) { return 0; } -unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage *msg) { - return msg->storage_id; -} - -void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessageState state) { - /* do not invoke callbacks on orphan messages */ - if (state != msg->state && msg->chat_room != NULL) { - if (((msg->state == LinphoneChatMessageStateDisplayed) || (msg->state == LinphoneChatMessageStateDeliveredToUser)) - && ((state == LinphoneChatMessageStateDeliveredToUser) || (state == LinphoneChatMessageStateDelivered) || (state == LinphoneChatMessageStateNotDelivered))) { - /* If the message has been displayed or delivered to user we must not go back to the delivered or not delivered state. */ - return; - } - ms_message("Chat message %p: moving from state %s to %s", msg, linphone_chat_message_state_to_string(msg->state), - linphone_chat_message_state_to_string(state)); - msg->state = state; - if (msg->message_state_changed_cb) { - msg->message_state_changed_cb(msg, msg->state, msg->message_state_changed_user_data); - } - if (linphone_chat_message_cbs_get_msg_state_changed(msg->cbs)) { - linphone_chat_message_cbs_get_msg_state_changed(msg->cbs)(msg, msg->state); - } - } -} - -const char* linphone_chat_message_get_message_id(const LinphoneChatMessage *msg) { - return msg->message_id; -} - -void linphone_chat_message_set_message_id(LinphoneChatMessage *msg, char *id) { - msg->message_id = id; -} - -void linphone_chat_message_set_is_read(LinphoneChatMessage *msg, bool_t is_read) { - msg->is_read = is_read; -} - -void linphone_chat_message_set_storage_id(LinphoneChatMessage *msg, unsigned int id) { - msg->storage_id = id; -} - -const char *linphone_chat_message_get_appdata(const LinphoneChatMessage *msg) { - return msg->appdata; -} - -void linphone_chat_message_set_appdata(LinphoneChatMessage *msg, const char *data) { - if (msg->appdata) { - ms_free(msg->appdata); - } - msg->appdata = data ? ms_strdup(data) : NULL; - linphone_chat_message_store_appdata(msg); -} - SalCustomHeader * linphone_chat_message_get_sal_custom_headers(const LinphoneChatMessage *msg) { return msg->sal_custom_headers; } @@ -544,10 +532,6 @@ LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessa return msg->dir == LinphoneChatMessageOutgoing ? msg->from : msg->to; } -LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage *msg) { - return msg->state; -} - void linphone_chat_message_add_custom_header(LinphoneChatMessage *msg, const char *header_name, const char *header_value) { msg->sal_custom_headers = sal_custom_header_append(msg->sal_custom_headers, header_name, header_value); diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 8614e1e7a..d39522ce7 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -37,22 +37,23 @@ public: private: std::shared_ptr chatRoom; + std::string externalBodyUrl; ChatMessage::Direction direction = ChatMessage::Incoming; + ChatMessage::State state = ChatMessage::Idle; + unsigned int storageId; // LinphoneAddress *from; // LinphoneAddress *to; - std::shared_ptr errorInfo; - std::string text; - bool isSecured = false; - bool isReadOnly = false; time_t time = 0; std::string id; std::string appData; + bool isRead = false; + bool isSecured = false; + bool isReadOnly = false; std::list > contents; std::shared_ptr internalContent; std::unordered_map customHeaders; - ChatMessage::State state = ChatMessage::Idle; std::shared_ptr eventsDb; - + std::shared_ptr errorInfo; L_DECLARE_PUBLIC(ChatMessage); }; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 4360d0076..3d2575047 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -26,6 +26,7 @@ #include "chat-message-p.h" #include "chat-message.h" +#include "content/content.h" #include "modifier/multipart-chat-message-modifier.h" #include "modifier/cpim-chat-message-modifier.h" @@ -59,11 +60,154 @@ shared_ptr ChatMessage::getChatRoom () const { return d->chatRoom; } +// ----------------------------------------------------------------------------- + +std::string ChatMessage::getExternalBodyUrl() const { + L_D(const ChatMessage); + return d->externalBodyUrl; +} + +void ChatMessage::setExternalBodyUrl(const string &url) { + L_D(ChatMessage); + d->externalBodyUrl = url; +} + +time_t ChatMessage::getTime () const { + L_D(const ChatMessage); + return d->time; +} +void ChatMessage::setTime(time_t time) { + L_D(ChatMessage); + d->time = time; +} + +bool ChatMessage::isSecured () const { + L_D(const ChatMessage); + return d->isSecured; +} + +void ChatMessage::setIsSecured(bool isSecured) { + L_D(ChatMessage); + d->isSecured = isSecured; +} + ChatMessage::Direction ChatMessage::getDirection () const { L_D(const ChatMessage); return d->direction; } +void ChatMessage::setDirection (ChatMessage::Direction dir) { + L_D(ChatMessage); + d->direction = dir; +} + +bool ChatMessage::isOutgoing () const { + L_D(const ChatMessage); + return d->direction == Outgoing; +} + +bool ChatMessage::isIncoming () const { + L_D(const ChatMessage); + return d->direction == Incoming; +} + +ChatMessage::State ChatMessage::getState() const { + L_D(const ChatMessage); + return d->state; +} + +void ChatMessage::setState(State state) { + L_D(ChatMessage); + if (state != d->state && d->chatRoom) { + if (((d->state == Displayed) || (d->state == DeliveredToUser)) + && ((state == DeliveredToUser) || (state == Delivered) || (state == NotDelivered))) { + return; + } + /* TODO + ms_message("Chat message %p: moving from state %s to %s", msg, linphone_chat_message_state_to_string(msg->state), linphone_chat_message_state_to_string(state)); + */ + d->state = state; + + LinphoneChatMessage *msg = L_GET_C_BACK_PTR(this); + /* TODO + if (msg->message_state_changed_cb) { + msg->message_state_changed_cb(msg, msg->state, msg->message_state_changed_user_data); + }*/ + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); + if (linphone_chat_message_cbs_get_msg_state_changed(cbs)) { + linphone_chat_message_cbs_get_msg_state_changed(cbs)(msg, linphone_chat_message_get_state(msg)); + } + } +} + +string ChatMessage::getId () const { + L_D(const ChatMessage); + return d->id; +} + +void ChatMessage::setId (string id) { + L_D(ChatMessage); + d->id = id; +} + +bool ChatMessage::isRead() const { + L_D(const ChatMessage); + return d->isRead; +} + +void ChatMessage::markAsRead() { + L_D(ChatMessage); + d->isRead = true; +} + +// ----------------------------------------------------------------------------- + +string ChatMessage::getContentType() const { + L_D(const ChatMessage); + if (d->internalContent) { + return d->internalContent->getContentType().asString(); + } + if (d->contents.size() > 0) { + return d->contents.front()->getContentType().asString(); + } + return ""; +} + +string ChatMessage::getText() const { + L_D(const ChatMessage); + if (d->internalContent) { + return d->internalContent->getBodyAsString(); + } + if (d->contents.size() > 0) { + return d->contents.front()->getBodyAsString(); + } + return ""; +} + +unsigned int ChatMessage::getStorageId() const { + L_D(const ChatMessage); + return d->storageId; +} + +void ChatMessage::setStorageId(unsigned int id) { + L_D(ChatMessage); + d->storageId = id; +} + +string ChatMessage::getAppdata () const { + L_D(const ChatMessage); + return d->appData; +} + +void ChatMessage::setAppdata (const string &appData) { + L_D(ChatMessage); + d->appData = appData; + // TODO: store app data in db ! + // linphone_chat_message_store_appdata(msg); +} + +// ----------------------------------------------------------------------------- + shared_ptr ChatMessage::getFromAddress () const { // TODO. return nullptr; @@ -84,11 +228,6 @@ shared_ptr ChatMessage::getRemoteAddress () const { return nullptr; } -ChatMessage::State ChatMessage::getState () const { - L_D(const ChatMessage); - return d->state; -} - shared_ptr ChatMessage::getErrorInfo () const { L_D(const ChatMessage); return d->errorInfo; @@ -119,36 +258,11 @@ bool ChatMessage::containsReadableText () const { return true; } -bool ChatMessage::isSecured () const { - L_D(const ChatMessage); - return d->isSecured; -} - bool ChatMessage::isReadOnly () const { L_D(const ChatMessage); return d->isReadOnly; } -time_t ChatMessage::getTime () const { - L_D(const ChatMessage); - return d->time; -} - -string ChatMessage::getId () const { - L_D(const ChatMessage); - return d->id; -} - -string ChatMessage::getAppdata () const { - L_D(const ChatMessage); - return d->appData; -} - -void ChatMessage::setAppdata (const string &appData) { - L_D(ChatMessage); - d->appData = appData; -} - list > ChatMessage::getContents () const { L_D(const ChatMessage); list > contents; diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index a105d7487..b2f903776 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -63,31 +63,61 @@ public: std::shared_ptr getChatRoom () const; + // ----------------------------------------------------------------------------- + Direction getDirection () const; + void setDirection (Direction dir); + bool isOutgoing () const; + bool isIncoming () const; + + std::string getExternalBodyUrl() const; + void setExternalBodyUrl(const std::string &url); + + time_t getTime () const; + + bool isSecured () const; + void setIsSecured(bool isSecured); + + State getState() const; + void setState(State state); + + std::string getId () const; + void setId (std::string); + + bool isRead() const; + void markAsRead(); + + std::string getAppdata () const; + void setAppdata (const std::string &appData); + + // ----------------------------------------------------------------------------- + // Deprecated methods, only used for C wrapper + // ----------------------------------------------------------------------------- + + std::string getContentType() const; + + std::string getText() const; + + unsigned int getStorageId() const; + void setStorageId(unsigned int id); + + void setTime(time_t time); + + // ----------------------------------------------------------------------------- std::shared_ptr getFromAddress () const; std::shared_ptr getToAddress () const; std::shared_ptr getLocalAddress () const; std::shared_ptr getRemoteAddress () const; - State getState () const; - std::shared_ptr getErrorInfo () const; void send (); bool containsReadableText () const; - bool isSecured () const; bool isReadOnly () const; - time_t getTime () const; - - std::string getId () const; - - std::string getAppdata () const; - void setAppdata (const std::string &appData); - std::list > getContents () const; void addContent (const std::shared_ptr &content); void removeContent (const std::shared_ptr &content); diff --git a/src/content/content.cpp b/src/content/content.cpp index a77f01eab..8a4aa7eef 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -81,6 +81,11 @@ const std::vector &Content::getBody () const { return d->body; } +string Content::getBodyAsString () const { + L_D(const Content); + return string(d->body.begin(), d->body.end()); +} + void Content::setBody (const std::vector &body) { L_D(Content); d->body = body; diff --git a/src/content/content.h b/src/content/content.h index 1a60e7fec..27c177711 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -22,6 +22,8 @@ #include #include +#include "content-type.h" + #include "object/clonable-object.h" // ============================================================================= @@ -29,7 +31,6 @@ LINPHONE_BEGIN_NAMESPACE class ContentPrivate; -class ContentType; class LINPHONE_PUBLIC Content : public ClonableObject { public: @@ -44,6 +45,7 @@ public: void setContentType (const ContentType &contentType); const std::vector &getBody () const; + std::string getBodyAsString () const; void setBody (const std::vector &body); void setBody (const std::string &body); void setBody (const void *buffer, size_t size); From 056f9435e9131474dfe497176c9fa9b5257546fb Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 25 Sep 2017 16:08:33 +0200 Subject: [PATCH 0174/2215] feat(BasicChatRoom): remove useless includes --- src/chat/basic-chat-room.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/chat/basic-chat-room.h b/src/chat/basic-chat-room.h index 01864f3a9..c464d9921 100644 --- a/src/chat/basic-chat-room.h +++ b/src/chat/basic-chat-room.h @@ -19,13 +19,7 @@ #ifndef _BASIC_CHAT_ROOM_H_ #define _BASIC_CHAT_ROOM_H_ -// From coreapi -#include "private.h" - #include "chat/chat-room.h" -#include "conference/conference-interface.h" - -#include "linphone/types.h" // ============================================================================= @@ -38,11 +32,11 @@ public: BasicChatRoom (LinphoneCore *core, const Address &peerAddress); virtual ~BasicChatRoom () = default; - /* ConferenceInterface */ + /* ConferenceInterface. */ std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; bool canHandleParticipants () const override; - const std::string& getId () const override; + const std::string &getId () const override; int getNbParticipants () const override; std::list> getParticipants () const override; void removeParticipant (const std::shared_ptr &participant) override; From 6ebe66ff5d36d9ff869e9c565547c02a543ee665 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 25 Sep 2017 16:44:22 +0200 Subject: [PATCH 0175/2215] L_DECLARE_PUBLIC should be private. --- src/conference/params/call-session-params-p.h | 1 - src/conference/params/media-session-params-p.h | 1 - src/conference/participant-p.h | 1 + src/conference/session/call-session-p.h | 1 + 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/conference/params/call-session-params-p.h b/src/conference/params/call-session-params-p.h index c410f5e37..88b1e9e02 100644 --- a/src/conference/params/call-session-params-p.h +++ b/src/conference/params/call-session-params-p.h @@ -58,7 +58,6 @@ private: SalCustomHeader *customHeaders = nullptr; LinphoneCall *referer = nullptr; /* In case call creation is consecutive to an incoming transfer, this points to the original call */ -public: L_DECLARE_PUBLIC(CallSessionParams); }; diff --git a/src/conference/params/media-session-params-p.h b/src/conference/params/media-session-params-p.h index ece0fb241..a32b88bd1 100644 --- a/src/conference/params/media-session-params-p.h +++ b/src/conference/params/media-session-params-p.h @@ -114,7 +114,6 @@ private: SalCustomSdpAttribute *customSdpAttributes = nullptr; SalCustomSdpAttribute *customSdpMediaAttributes[LinphoneStreamTypeUnknown]; -public: L_DECLARE_PUBLIC(MediaSessionParams); }; diff --git a/src/conference/participant-p.h b/src/conference/participant-p.h index 21f906a07..4abcb974a 100644 --- a/src/conference/participant-p.h +++ b/src/conference/participant-p.h @@ -41,6 +41,7 @@ public: std::shared_ptr createSession (const Conference &conference, const CallSessionParams *params, bool hasMedia, CallSessionListener *listener); std::shared_ptr getSession () const; +private: Address addr; bool isAdmin = false; std::shared_ptr session = nullptr; diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index 34de3ea3f..2e3913e71 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -104,6 +104,7 @@ protected: bool deferUpdate = false; bool nonOpError = false; /* Set when the LinphoneErrorInfo was set at higher level than sal */ +private: L_DECLARE_PUBLIC(CallSession); }; From ba9152a69d30e22256e6182125f8475622bfc313 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 25 Sep 2017 16:44:48 +0200 Subject: [PATCH 0176/2215] Use CPP_OBJECT name for argument of macro that expects a C++ object. --- src/c-wrapper/internal/c-tools.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 5bb3ffd59..6690f308e 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -445,8 +445,8 @@ LINPHONE_END_NAMESPACE L_GET_PRIVATE(LINPHONE_NAMESPACE::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT))) // Get the wrapped C object of a C++ object. -#define L_GET_C_BACK_PTR(C_OBJECT) \ - LINPHONE_NAMESPACE::Wrapper::getCBackPtr(C_OBJECT) +#define L_GET_C_BACK_PTR(CPP_OBJECT) \ + LINPHONE_NAMESPACE::Wrapper::getCBackPtr(CPP_OBJECT) // Get/set user data on a wrapped C object. #define L_GET_USER_DATA_FROM_C_OBJECT(C_OBJECT) \ From b10ab978b873775c179cc0aa3fc2823e37d842d6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 25 Sep 2017 16:46:20 +0200 Subject: [PATCH 0177/2215] Simplify the chat room instantiation notification. --- src/c-wrapper/api/c-chat-room.cpp | 6 ++---- src/chat/chat-room.cpp | 3 +++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 6ae4f109f..547f96705 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -267,12 +267,11 @@ void linphone_chat_room_set_user_data (LinphoneChatRoom *cr, void *ud) { // ============================================================================= LinphoneChatRoom *linphone_chat_room_new (LinphoneCore *core, const LinphoneAddress *addr) { - LinphoneChatRoom *cr = _linphone_ChatRoom_init(); + LinphoneChatRoom *cr = L_INIT(ChatRoom); if (linphone_core_realtime_text_enabled(core)) L_SET_CPP_PTR_FROM_C_OBJECT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_OBJECT(addr))); else L_SET_CPP_PTR_FROM_C_OBJECT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_OBJECT(addr))); - linphone_core_notify_chat_room_instantiated(core, cr); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Created); return cr; @@ -291,9 +290,8 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core) { if (from.empty()) from = linphone_core_get_primary_contact(core); LinphonePrivate::Address me(from); - LinphoneChatRoom *cr = _linphone_ChatRoom_init(); + LinphoneChatRoom *cr = L_INIT(ChatRoom); L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared(core, me)); - linphone_core_notify_chat_room_instantiated(core, cr); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); return cr; } diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 239d28403..19774db04 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -182,8 +182,11 @@ int ChatRoomPrivate::getMessagesCount (bool unreadOnly) { } void ChatRoomPrivate::setState (ChatRoom::State newState) { + L_Q(ChatRoom); if (newState != state) { state = newState; + if (state == ChatRoom::State::Instantiated) + linphone_core_notify_chat_room_instantiated(core, L_GET_C_BACK_PTR(q)); notifyStateChanged(); } } From 27f2dff83faa80f17d0e01dabcc666b4c38659d2 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 25 Sep 2017 17:04:42 +0200 Subject: [PATCH 0178/2215] fix(Utils): remove useless includes in payload-type-handler and clean code --- src/utils/payload-type-handler.cpp | 101 +++++++++++++++++------------ src/utils/payload-type-handler.h | 38 +++++------ 2 files changed, 76 insertions(+), 63 deletions(-) diff --git a/src/utils/payload-type-handler.cpp b/src/utils/payload-type-handler.cpp index fce4a60ec..25044f106 100644 --- a/src/utils/payload-type-handler.cpp +++ b/src/utils/payload-type-handler.cpp @@ -18,9 +18,13 @@ #include +#include "private.h" + +#include "logger/logger.h" + #include "payload-type-handler.h" -#include "private.h" +// ============================================================================= using namespace std; @@ -28,9 +32,11 @@ LINPHONE_BEGIN_NAMESPACE const int PayloadTypeHandler::udpHeaderSize = 8; const int PayloadTypeHandler::rtpHeaderSize = 12; -const int PayloadTypeHandler::ipv4HeaderSize = 20; /* 20 is the minimum, but there may be some options */ + +// 20 is the minimum, but there may be some options. +const int PayloadTypeHandler::ipv4HeaderSize = 20; + const VbrCodecBitrate PayloadTypeHandler::defaultVbrCodecBitrates[] = { - //{ 100, 44100, 100 }, { 64, 44100, 50 }, { 64, 16000, 40 }, { 32, 16000, 32 }, @@ -45,12 +51,18 @@ int PayloadTypeHandler::findPayloadTypeNumber (const bctbx_list_t *assigned, con const OrtpPayloadType *candidate = nullptr; for (const bctbx_list_t *elem = assigned; elem != nullptr; elem = bctbx_list_next(elem)) { const OrtpPayloadType *it = reinterpret_cast(bctbx_list_get_data(elem)); - if ((strcasecmp(pt->mime_type, payload_type_get_mime(it)) == 0) - && (it->clock_rate == pt->clock_rate) - && ((it->channels == pt->channels) || (pt->channels <= 0))) { + if ( + strcasecmp(pt->mime_type, payload_type_get_mime(it)) == 0 && + it->clock_rate == pt->clock_rate && + ((it->channels == pt->channels) || (pt->channels <= 0)) + ) { candidate = it; - if ((it->recv_fmtp && pt->recv_fmtp && (strcasecmp(it->recv_fmtp, pt->recv_fmtp) == 0)) || (!it->recv_fmtp && !pt->recv_fmtp)) - break; /* Exact match */ + if ( + (it->recv_fmtp && pt->recv_fmtp && (strcasecmp(it->recv_fmtp, pt->recv_fmtp) == 0)) || + (!it->recv_fmtp && !pt->recv_fmtp) + ) + // Exact match. + break; } } return candidate ? payload_type_get_number(candidate) : -1; @@ -74,7 +86,8 @@ bool PayloadTypeHandler::isPayloadTypeUsableForBandwidth (const OrtpPayloadType codecBand = getAudioPayloadTypeBandwidth(pt, bandwidthLimit); return bandwidthIsGreater(bandwidthLimit, (int)codecBand); case PAYLOAD_VIDEO: - if ((bandwidthLimit <= 0) || (bandwidthLimit >= videoEnablementLimit)) /* Infinite or greater than videoEnablementLimit */ + // Infinite or greater than videoEnablementLimit. + if (bandwidthLimit <= 0 || bandwidthLimit >= videoEnablementLimit) return true; break; case PAYLOAD_TEXT: @@ -104,11 +117,12 @@ void PayloadTypeHandler::assignPayloadTypeNumbers (const bctbx_list_t *codecs) { OrtpPayloadType *pt = reinterpret_cast(bctbx_list_get_data(elem)); int number = payload_type_get_number(pt); - /* Check if number is duplicated: it could be the case if the remote forced us to use a mapping with a previous offer */ + // Check if number is duplicated: it could be the case if the remote forced us to use a mapping with a previous offer. if ((number != -1) && !(pt->flags & PAYLOAD_TYPE_FROZEN_NUMBER)) { if (!isPayloadTypeNumberAvailable(codecs, number, pt)) { lInfo() << "Reassigning payload type " << number << " " << pt->mime_type << "/" << pt->clock_rate << " because already offered"; - number = -1; /* need to be re-assigned */ + // Need to be re-assigned. + number = -1; } } @@ -122,7 +136,7 @@ void PayloadTypeHandler::assignPayloadTypeNumbers (const bctbx_list_t *codecs) { } dynNumber++; } - if (dynNumber==127) { + if (dynNumber == 127) { lError() << "Too many payload types configured ! codec " << pt->mime_type << "/" << pt->clock_rate << " is disabled"; payload_type_set_enable(pt, false); } @@ -142,7 +156,7 @@ void PayloadTypeHandler::assignPayloadTypeNumbers (const bctbx_list_t *codecs) { } } -bctbx_list_t * PayloadTypeHandler::createSpecialPayloadTypes (const bctbx_list_t *codecs) { +bctbx_list_t *PayloadTypeHandler::createSpecialPayloadTypes (const bctbx_list_t *codecs) { bctbx_list_t *result = createTelephoneEventPayloadTypes(codecs); if (linphone_core_generic_comfort_noise_enabled(core)) { OrtpPayloadType *cn = payload_type_clone(&payload_type_cn); @@ -152,29 +166,32 @@ bctbx_list_t * PayloadTypeHandler::createSpecialPayloadTypes (const bctbx_list_t return result; } -bctbx_list_t * PayloadTypeHandler::createTelephoneEventPayloadTypes (const bctbx_list_t *codecs) { +bctbx_list_t *PayloadTypeHandler::createTelephoneEventPayloadTypes (const bctbx_list_t *codecs) { bctbx_list_t *result = nullptr; for (const bctbx_list_t *it = codecs; it != nullptr; it = bctbx_list_next(it)) { const OrtpPayloadType *pt = reinterpret_cast(bctbx_list_get_data(it)); - if (!hasTelephoneEventPayloadType(result, pt->clock_rate)) { - OrtpPayloadType *tev = payload_type_clone(&payload_type_telephone_event); - tev->clock_rate = pt->clock_rate; - /* Let it choose the number dynamically as for normal codecs */ - payload_type_set_number(tev, -1); - if (!result) { - /* But for first telephone-event, prefer the number that was configured in the core */ - if (isPayloadTypeNumberAvailable(codecs, core->codecs_conf.telephone_event_pt, nullptr)) - payload_type_set_number(tev, core->codecs_conf.telephone_event_pt); - } - result = bctbx_list_append(result, tev); - } + if (hasTelephoneEventPayloadType(result, pt->clock_rate)) + continue; + + OrtpPayloadType *tev = payload_type_clone(&payload_type_telephone_event); + tev->clock_rate = pt->clock_rate; + // Let it choose the number dynamically as for normal codecs. + payload_type_set_number(tev, -1); + // But for first telephone-event, prefer the number that was configured in the core. + if (!result && isPayloadTypeNumberAvailable(codecs, core->codecs_conf.telephone_event_pt, nullptr)) + payload_type_set_number(tev, core->codecs_conf.telephone_event_pt); + result = bctbx_list_append(result, tev); } return result; } bool PayloadTypeHandler::isPayloadTypeUsable (const OrtpPayloadType *pt) { - int maxBandwidth = getMinBandwidth(linphone_core_get_download_bandwidth(core), linphone_core_get_upload_bandwidth(core)); - return isPayloadTypeUsableForBandwidth(pt, maxBandwidth); + return isPayloadTypeUsableForBandwidth( + pt, getMinBandwidth( + linphone_core_get_download_bandwidth(core), + linphone_core_get_upload_bandwidth(core) + ) + ); } // ----------------------------------------------------------------------------- @@ -199,16 +216,16 @@ int PayloadTypeHandler::getAudioPayloadTypeBandwidth (const OrtpPayloadType *pt, /* *((codec-birate*ptime/8) + RTP header + UDP header + IP header)*8/ptime; - *ptime=1/npacket + * ptime=1/npacket */ double PayloadTypeHandler::getAudioPayloadTypeBandwidthFromCodecBitrate (const OrtpPayloadType *pt) { double npacket = 50; - if (strcmp(payload_type_get_mime(&payload_type_aaceld_44k), payload_type_get_mime(pt)) == 0) { - /* Special case of aac 44K because ptime=10ms */ + if (strcmp(payload_type_get_mime(&payload_type_aaceld_44k), payload_type_get_mime(pt)) == 0) + // Special case of aac 44K because ptime=10ms. npacket = 100; - } else if (strcmp(payload_type_get_mime(&payload_type_ilbc), payload_type_get_mime(pt)) == 0) { + else if (strcmp(payload_type_get_mime(&payload_type_ilbc), payload_type_get_mime(pt)) == 0) npacket = 1000 / 30.0; - } + int bitrate = pt->normal_bitrate; double packet_size = (((double)bitrate) / (npacket * 8)) + udpHeaderSize + rtpHeaderSize + ipv4HeaderSize; return packet_size * 8.0 * npacket; @@ -219,11 +236,12 @@ int PayloadTypeHandler::getMaxCodecSampleRate (const bctbx_list_t *codecs) { for (const bctbx_list_t *it = codecs; it != nullptr; it = bctbx_list_next(it)) { OrtpPayloadType *pt = reinterpret_cast(bctbx_list_get_data(it)); int sampleRate; - if (strcasecmp("G722", pt->mime_type) == 0) { - /* G722 spec says 8000 but the codec actually requires 16000 */ + if (strcasecmp("G722", pt->mime_type) == 0) + // G722 spec says 8000 but the codec actually requires 16000. sampleRate = 16000; - } else + else sampleRate = pt->clock_rate; + if (sampleRate > maxSampleRate) maxSampleRate = sampleRate; } @@ -252,7 +270,7 @@ bool PayloadTypeHandler::isPayloadTypeNumberAvailable (const bctbx_list_t *codec // ----------------------------------------------------------------------------- -bctbx_list_t * PayloadTypeHandler::makeCodecsList (SalStreamType type, int bandwidthLimit, int maxCodecs, const bctbx_list_t *previousList) { +bctbx_list_t *PayloadTypeHandler::makeCodecsList (SalStreamType type, int bandwidthLimit, int maxCodecs, const bctbx_list_t *previousList) { const bctbx_list_t *allCodecs = nullptr; switch (type) { default: @@ -273,13 +291,16 @@ bctbx_list_t * PayloadTypeHandler::makeCodecsList (SalStreamType type, int bandw OrtpPayloadType *pt = reinterpret_cast(bctbx_list_get_data(it)); if (!payload_type_enabled(pt)) continue; - if ((bandwidthLimit > 0) && !isPayloadTypeUsableForBandwidth(pt, bandwidthLimit)) { - lInfo() << "Codec " << pt->mime_type << "/" << pt->clock_rate << " eliminated because of audio bandwidth constraint of " - << bandwidthLimit << " kbit/s"; + + if (bandwidthLimit > 0 && !isPayloadTypeUsableForBandwidth(pt, bandwidthLimit)) { + lInfo() << "Codec " << pt->mime_type << "/" << pt->clock_rate << " eliminated because of audio bandwidth constraint of " << + bandwidthLimit << " kbit/s"; continue; } + if (!isPayloadTypeUsable(pt)) continue; + pt = payload_type_clone(pt); /* Look for a previously assigned number for this codec */ diff --git a/src/utils/payload-type-handler.h b/src/utils/payload-type-handler.h index 4aa09226c..892e175aa 100644 --- a/src/utils/payload-type-handler.h +++ b/src/utils/payload-type-handler.h @@ -19,25 +19,20 @@ #ifndef _PAYLOAD_TYPE_HANDLER_H_ #define _PAYLOAD_TYPE_HANDLER_H_ -#include "logger/logger.h" - #include "linphone/core.h" -#include "linphone/payload_type.h" #include "linphone/utils/general.h" -#include "sal/sal.h" + +#include "sal/sal.h" /* SalStreamType. */ // ============================================================================= -#define PAYLOAD_TYPE_ENABLED PAYLOAD_TYPE_USER_FLAG_0 +#define PAYLOAD_TYPE_ENABLED PAYLOAD_TYPE_USER_FLAG_0 #define PAYLOAD_TYPE_BITRATE_OVERRIDE PAYLOAD_TYPE_USER_FLAG_3 -#define PAYLOAD_TYPE_FROZEN_NUMBER PAYLOAD_TYPE_USER_FLAG_4 - -// ============================================================================= +#define PAYLOAD_TYPE_FROZEN_NUMBER PAYLOAD_TYPE_USER_FLAG_4 LINPHONE_BEGIN_NAMESPACE struct VbrCodecBitrate { -public: int maxAvailableBitrate; int minClockRate; int recommendedBitrate; @@ -46,20 +41,9 @@ public: class PayloadTypeHandler { public: PayloadTypeHandler (LinphoneCore *core) : core(core) {} - ~PayloadTypeHandler () = default; -private: - static int findPayloadTypeNumber (const bctbx_list_t *assigned, const OrtpPayloadType *pt); - static bool hasTelephoneEventPayloadType (const bctbx_list_t *tev, int rate); - static bool isPayloadTypeUsableForBandwidth (const OrtpPayloadType *pt, int bandwidthLimit); - static int lookupTypicalVbrBitrate (int maxBandwidth, int clockRate); + bctbx_list_t *makeCodecsList (SalStreamType type, int bandwidthLimit, int maxCodecs, const bctbx_list_t *previousList); - void assignPayloadTypeNumbers (const bctbx_list_t *codecs); - bctbx_list_t * createSpecialPayloadTypes (const bctbx_list_t *codecs); - bctbx_list_t * createTelephoneEventPayloadTypes (const bctbx_list_t *codecs); - bool isPayloadTypeUsable (const OrtpPayloadType *pt); - -public: static bool bandwidthIsGreater (int bandwidth1, int bandwidth2); static int getAudioPayloadTypeBandwidth (const OrtpPayloadType *pt, int maxBandwidth); static double getAudioPayloadTypeBandwidthFromCodecBitrate (const OrtpPayloadType *pt); @@ -68,9 +52,17 @@ public: static int getRemainingBandwidthForVideo (int total, int audio); static bool isPayloadTypeNumberAvailable (const bctbx_list_t *codecs, int number, const OrtpPayloadType *ignore); - bctbx_list_t * makeCodecsList (SalStreamType type, int bandwidthLimit, int maxCodecs, const bctbx_list_t *previousList); - private: + static int findPayloadTypeNumber (const bctbx_list_t *assigned, const OrtpPayloadType *pt); + static bool hasTelephoneEventPayloadType (const bctbx_list_t *tev, int rate); + static bool isPayloadTypeUsableForBandwidth (const OrtpPayloadType *pt, int bandwidthLimit); + static int lookupTypicalVbrBitrate (int maxBandwidth, int clockRate); + + void assignPayloadTypeNumbers (const bctbx_list_t *codecs); + bctbx_list_t *createSpecialPayloadTypes (const bctbx_list_t *codecs); + bctbx_list_t *createTelephoneEventPayloadTypes (const bctbx_list_t *codecs); + bool isPayloadTypeUsable (const OrtpPayloadType *pt); + static const int udpHeaderSize; static const int rtpHeaderSize; static const int ipv4HeaderSize; From 9a73bbc894547abeb69c03101431204623c090e1 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 25 Sep 2017 17:24:50 +0200 Subject: [PATCH 0179/2215] Handle content disposition and add helper to set the content type in a content. --- src/content/content.cpp | 16 ++++++++++++++++ src/content/content.h | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/src/content/content.cpp b/src/content/content.cpp index 8a4aa7eef..c2b1a425a 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -31,6 +31,7 @@ class ContentPrivate : public ClonableObjectPrivate { public: vector body; ContentType contentType; + string contentDisposition; }; // ----------------------------------------------------------------------------- @@ -76,6 +77,21 @@ void Content::setContentType (const ContentType &contentType) { d->contentType = contentType; } +void Content::setContentType (const string &contentType) { + L_D(Content); + d->contentType = ContentType(contentType); +} + +const string &Content::getContentDisposition () const { + L_D(const Content); + return d->contentDisposition; +} + +void Content::setContentDisposition (const string &contentDisposition) { + L_D(Content); + d->contentDisposition = contentDisposition; +} + const std::vector &Content::getBody () const { L_D(const Content); return d->body; diff --git a/src/content/content.h b/src/content/content.h index 27c177711..7037b124a 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -43,6 +43,10 @@ public: const ContentType &getContentType () const; void setContentType (const ContentType &contentType); + void setContentType (const std::string &contentType); + + const std::string &getContentDisposition () const; + void setContentDisposition (const std::string &contentDisposition); const std::vector &getBody () const; std::string getBodyAsString () const; From 0d0256698e33452efc87dbf7936a7aba778256a3 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 25 Sep 2017 17:29:41 +0200 Subject: [PATCH 0180/2215] More work on C to CPP ChatMessage --- coreapi/private.h | 1 - src/c-wrapper/api/c-chat-message.cpp | 141 ++++++++++++--------------- src/chat/chat-message-p.h | 1 - src/chat/chat-message.cpp | 13 ++- src/chat/chat-message.h | 1 - src/chat/chat-room.cpp | 1 - 6 files changed, 69 insertions(+), 89 deletions(-) diff --git a/coreapi/private.h b/coreapi/private.h index 3899a8509..0cd36ff8e 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -1090,7 +1090,6 @@ void linphone_chat_message_set_message_state_changed_cb_user_data(LinphoneChatMe void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChatMessage* msg); void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessageState state); void linphone_chat_message_set_message_id(LinphoneChatMessage *msg, char *id); -void linphone_chat_message_set_is_read(LinphoneChatMessage *msg, bool_t is_read); void linphone_chat_message_set_storage_id(LinphoneChatMessage *msg, unsigned int id); SalCustomHeader * linphone_chat_message_get_sal_custom_headers(const LinphoneChatMessage *msg); void linphone_chat_message_set_sal_custom_headers(LinphoneChatMessage *msg, SalCustomHeader *header); diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index d8292eaf2..3a8bc06d5 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -97,11 +97,18 @@ void linphone_chat_message_set_user_data (LinphoneChatMessage *msg, void *ud) { L_SET_USER_DATA_FROM_C_OBJECT(msg, ud); } +LinphoneChatMessageCbs *linphone_chat_message_get_callbacks(const LinphoneChatMessage *msg) { + return msg->cbs; +} // ============================================================================= // Getter and setters // ============================================================================= +LinphoneChatRoom *linphone_chat_message_get_chat_room(const LinphoneChatMessage *msg) { + return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getChatRoom()); +} + const char *linphone_chat_message_get_external_body_url(const LinphoneChatMessage *msg) { return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getExternalBodyUrl().c_str(); } @@ -130,6 +137,10 @@ bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage *msg) { return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->isOutgoing(); } +LinphoneChatMessageDir linphone_chat_message_get_direction(const LinphoneChatMessage *msg) { + return ((LinphoneChatMessageDir)L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getDirection()); +} + void linphone_chat_message_set_incoming(LinphoneChatMessage *msg) { L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setDirection(LinphonePrivate::ChatMessage::Direction::Incoming); } @@ -170,10 +181,8 @@ void linphone_chat_message_set_storage_id(LinphoneChatMessage *msg, unsigned int L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setStorageId(id); } -void linphone_chat_message_set_is_read(LinphoneChatMessage *msg, bool_t is_read) { - if (is_read) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->markAsRead(); - } +bool_t linphone_chat_message_is_read(LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->isRead(); } const char *linphone_chat_message_get_appdata(const LinphoneChatMessage *msg) { @@ -211,8 +220,6 @@ const LinphoneAddress *linphone_chat_message_get_to_address(const LinphoneChatMe return NULL; } -// ============================================================================= - void linphone_chat_message_set_message_state_changed_cb(LinphoneChatMessage* msg, LinphoneChatMessageStateChangedCb cb) { msg->message_state_changed_cb = cb; } @@ -243,6 +250,10 @@ int linphone_chat_message_set_text(LinphoneChatMessage *msg, const char* text) { return 0; } +LinphoneContent *linphone_chat_message_get_file_transfer_information(LinphoneChatMessage *msg) { + return msg->file_transfer_information; +} + SalCustomHeader * linphone_chat_message_get_sal_custom_headers(const LinphoneChatMessage *msg) { return msg->sal_custom_headers; } @@ -263,14 +274,6 @@ void linphone_chat_message_set_file_transfer_information(LinphoneChatMessage *ms msg->file_transfer_information = content; } -LinphoneChatMessageDir linphone_chat_message_get_direction(const LinphoneChatMessage *msg) { - return msg->dir; -} - -LinphoneChatRoom *linphone_chat_message_get_chat_room(const LinphoneChatMessage *msg) { - return msg->chat_room; -} - SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg) { return msg->op; } @@ -287,6 +290,52 @@ const char *linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage return msg->file_transfer_filepath; } +const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg) { + if (!msg->ei) ((LinphoneChatMessage*)msg)->ei = linphone_error_info_new(); /*let's do it mutable*/ + linphone_error_info_from_sal_op(msg->ei, msg->op); + return msg->ei; +} + +LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage *msg) { + return linphone_error_info_get_reason(linphone_chat_message_get_error_info(msg)); +}const LinphoneAddress *linphone_chat_message_get_peer_address(LinphoneChatMessage *msg) { + return linphone_chat_room_get_peer_address(msg->chat_room); +} + +bool_t linphone_chat_message_is_file_transfer(const LinphoneChatMessage *msg) { + return LinphonePrivate::ContentType::isFileTransfer(msg->content_type); +} + +bool_t linphone_chat_message_is_text(const LinphoneChatMessage *msg) { + return LinphonePrivate::ContentType::isText(msg->content_type); +} + +bool_t linphone_chat_message_get_to_be_stored(const LinphoneChatMessage *msg) { + return msg->to_be_stored; +} + +void linphone_chat_message_set_to_be_stored(LinphoneChatMessage *msg, bool_t to_be_stored) { + msg->to_be_stored = to_be_stored; +} + +LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessage *msg) { + return msg->dir == LinphoneChatMessageOutgoing ? msg->from : msg->to; +} + +void linphone_chat_message_add_custom_header(LinphoneChatMessage *msg, const char *header_name, + const char *header_value) { + msg->sal_custom_headers = sal_custom_header_append(msg->sal_custom_headers, header_name, header_value); +} + +const char *linphone_chat_message_get_custom_header(LinphoneChatMessage *msg, const char *header_name) { + return sal_custom_header_find(msg->sal_custom_headers, header_name); +} + +void linphone_chat_message_remove_custom_header(LinphoneChatMessage *msg, const char *header_name) { + msg->sal_custom_headers = sal_custom_header_remove(msg->sal_custom_headers, header_name); +} + +// ============================================================================= // ============================================================================= void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state) { @@ -508,52 +557,6 @@ const char *linphone_chat_message_state_to_string(const LinphoneChatMessageState return NULL; } -const LinphoneAddress *linphone_chat_message_get_peer_address(LinphoneChatMessage *msg) { - return linphone_chat_room_get_peer_address(msg->chat_room); -} - -bool_t linphone_chat_message_is_file_transfer(const LinphoneChatMessage *msg) { - return LinphonePrivate::ContentType::isFileTransfer(msg->content_type); -} - -bool_t linphone_chat_message_is_text(const LinphoneChatMessage *msg) { - return LinphonePrivate::ContentType::isText(msg->content_type); -} - -bool_t linphone_chat_message_get_to_be_stored(const LinphoneChatMessage *msg) { - return msg->to_be_stored; -} - -void linphone_chat_message_set_to_be_stored(LinphoneChatMessage *msg, bool_t to_be_stored) { - msg->to_be_stored = to_be_stored; -} - -LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessage *msg) { - return msg->dir == LinphoneChatMessageOutgoing ? msg->from : msg->to; -} - -void linphone_chat_message_add_custom_header(LinphoneChatMessage *msg, const char *header_name, - const char *header_value) { - msg->sal_custom_headers = sal_custom_header_append(msg->sal_custom_headers, header_name, header_value); -} - -const char *linphone_chat_message_get_custom_header(LinphoneChatMessage *msg, const char *header_name) { - return sal_custom_header_find(msg->sal_custom_headers, header_name); -} - -void linphone_chat_message_remove_custom_header(LinphoneChatMessage *msg, const char *header_name) { - msg->sal_custom_headers = sal_custom_header_remove(msg->sal_custom_headers, header_name); -} - -bool_t linphone_chat_message_is_read(LinphoneChatMessage *msg) { - LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); - LinphoneCore *lc = linphone_chat_room_get_core(cr); - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); - if ((linphone_im_notif_policy_get_recv_imdn_displayed(policy) == TRUE) && (msg->state == LinphoneChatMessageStateDisplayed)) return TRUE; - if ((linphone_im_notif_policy_get_recv_imdn_delivered(policy) == TRUE) && (msg->state == LinphoneChatMessageStateDeliveredToUser || msg->state == LinphoneChatMessageStateDisplayed)) return TRUE; - return (msg->state == LinphoneChatMessageStateDelivered || msg->state == LinphoneChatMessageStateDisplayed || msg->state == LinphoneChatMessageStateDeliveredToUser); -} - LinphoneChatMessage *linphone_chat_message_clone(const LinphoneChatMessage *msg) { LinphoneChatMessage *new_message = linphone_chat_room_create_message(msg->chat_room, msg->message); if (msg->external_body_url) @@ -588,20 +591,6 @@ void linphone_chat_message_release(LinphoneChatMessage *msg) { linphone_chat_message_unref(msg); } -const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg) { - if (!msg->ei) ((LinphoneChatMessage*)msg)->ei = linphone_error_info_new(); /*let's do it mutable*/ - linphone_error_info_from_sal_op(msg->ei, msg->op); - return msg->ei; -} - -LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage *msg) { - return linphone_error_info_get_reason(linphone_chat_message_get_error_info(msg)); -} - -LinphoneChatMessageCbs *linphone_chat_message_get_callbacks(const LinphoneChatMessage *msg) { - return msg->cbs; -} - static bool_t file_transfer_in_progress_and_valid(LinphoneChatMessage* msg) { return (linphone_chat_message_get_chat_room(msg) && linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)) && @@ -937,10 +926,6 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co } } -LinphoneContent *linphone_chat_message_get_file_transfer_information(LinphoneChatMessage *msg) { - return msg->file_transfer_information; -} - static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset, uint8_t *buffer, size_t size) { LinphoneChatMessage *msg = (LinphoneChatMessage *)data; LinphoneCore *lc = NULL; diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index d39522ce7..0145f1187 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -46,7 +46,6 @@ private: time_t time = 0; std::string id; std::string appData; - bool isRead = false; bool isSecured = false; bool isReadOnly = false; std::list > contents; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 3d2575047..de28edd49 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -151,13 +151,12 @@ void ChatMessage::setId (string id) { } bool ChatMessage::isRead() const { - L_D(const ChatMessage); - return d->isRead; -} - -void ChatMessage::markAsRead() { - L_D(ChatMessage); - d->isRead = true; + //L_D(const ChatMessage); + return false; + /*shared_ptr policy =d->chatRoom->core->getImNotifPolicy(); + if (policy->getRecvImdnDisplayed() && d->state == Displayed) return true; + if (policy->getRecvImdnDelivered() && (d->state == DeliveredToUser || d->state == Displayed)) return true; + return d->state == Delivered || d->state == Displayed || d->state == DeliveredToUser;*/ } // ----------------------------------------------------------------------------- diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index b2f903776..c14a4998e 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -85,7 +85,6 @@ public: void setId (std::string); bool isRead() const; - void markAsRead(); std::string getAppdata () const; void setAppdata (const std::string &appData); diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 19774db04..29102a8fb 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -286,7 +286,6 @@ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colN linphone_address_unref(peer); linphone_chat_message_set_time(newMessage, (time_t)atol(argv[9])); - linphone_chat_message_set_is_read(newMessage, !!atoi(argv[6])); linphone_chat_message_set_state(newMessage, static_cast(atoi(argv[7]))); linphone_chat_message_set_storage_id(newMessage, storageId); linphone_chat_message_set_external_body_url(newMessage, ms_strdup(argv[8])); From 113dee4b8d05572f5f704d6c09e24903855ae8b8 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 25 Sep 2017 17:37:56 +0200 Subject: [PATCH 0181/2215] fix(core): clean code, remove useless includes --- src/object/clonable-object.h | 4 ---- src/object/object-p.h | 2 -- src/object/object.h | 7 +++---- src/object/property-container.h | 4 ---- src/object/singleton.h | 2 +- src/utils/utils.cpp | 8 ++++---- src/variant/variant.h | 4 ++-- 7 files changed, 10 insertions(+), 21 deletions(-) diff --git a/src/object/clonable-object.h b/src/object/clonable-object.h index 89fe66b3f..b2162706e 100644 --- a/src/object/clonable-object.h +++ b/src/object/clonable-object.h @@ -19,10 +19,6 @@ #ifndef _CLONABLE_OBJECT_H_ #define _CLONABLE_OBJECT_H_ -#include - -#include "linphone/utils/general.h" - #include "property-container.h" // ============================================================================= diff --git a/src/object/object-p.h b/src/object/object-p.h index 74ac5b953..0b3cf57a2 100644 --- a/src/object/object-p.h +++ b/src/object/object-p.h @@ -21,8 +21,6 @@ #include -#include "linphone/utils/general.h" - #include "variant/variant.h" // ============================================================================= diff --git a/src/object/object.h b/src/object/object.h index a09cbc6e0..ede98e862 100644 --- a/src/object/object.h +++ b/src/object/object.h @@ -21,16 +21,15 @@ #include -#include "linphone/utils/general.h" - #include "property-container.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE -class LINPHONE_PUBLIC Object : public std::enable_shared_from_this, public PropertyContainer { - +class LINPHONE_PUBLIC Object : + public std::enable_shared_from_this, + public PropertyContainer { public: virtual ~Object (); diff --git a/src/object/property-container.h b/src/object/property-container.h index 67dab6034..5b8dbd540 100644 --- a/src/object/property-container.h +++ b/src/object/property-container.h @@ -19,10 +19,6 @@ #ifndef _PROPERTY_CONTAINER_H_ #define _PROPERTY_CONTAINER_H_ -#include - -#include "linphone/utils/general.h" - #include "variant/variant.h" // ============================================================================= diff --git a/src/object/singleton.h b/src/object/singleton.h index 667f71f9b..44b6715b0 100644 --- a/src/object/singleton.h +++ b/src/object/singleton.h @@ -26,7 +26,7 @@ LINPHONE_BEGIN_NAMESPACE template -class Singleton : public Object { +class LINPHONE_PUBLIC Singleton : public Object { public: virtual ~Singleton () = default; diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 0ff383c5f..471d0d1b4 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -93,10 +93,10 @@ string Utils::toString (const void *val) { // ----------------------------------------------------------------------------- #define STRING_TO_NUMBER_IMPL(TYPE, SUFFIX) \ - TYPE Utils::sto ## SUFFIX (const string &str, size_t *idx, int base) { \ + TYPE Utils::sto ## SUFFIX(const string &str, size_t * idx, int base) { \ return sto ## SUFFIX(str.c_str(), idx, base); \ } \ - TYPE Utils::sto ## SUFFIX (const char *str, size_t *idx, int base) { \ + TYPE Utils::sto ## SUFFIX(const char *str, size_t * idx, int base) { \ char *p; \ TYPE v = strto ## SUFFIX(str, &p, base); \ if (idx) \ @@ -105,10 +105,10 @@ string Utils::toString (const void *val) { } \ #define STRING_TO_NUMBER_IMPL_BASE_LESS(TYPE, SUFFIX) \ - TYPE Utils::sto ## SUFFIX (const string &str, size_t *idx) { \ + TYPE Utils::sto ## SUFFIX(const string &str, size_t * idx) { \ return sto ## SUFFIX(str.c_str(), idx); \ } \ - TYPE Utils::sto ## SUFFIX (const char *str, size_t *idx) { \ + TYPE Utils::sto ## SUFFIX(const char *str, size_t * idx) { \ char *p; \ TYPE v = strto ## SUFFIX(str, &p); \ if (idx) \ diff --git a/src/variant/variant.h b/src/variant/variant.h index ac15d2969..0506ef2c1 100644 --- a/src/variant/variant.h +++ b/src/variant/variant.h @@ -81,7 +81,7 @@ public: Variant (const std::string &value); // void* constructor. Must be explicitly called. - template::value> > + template::value>> Variant (T value) : Variant (Variant::createGeneric(value)) {} ~Variant (); @@ -98,7 +98,7 @@ public: template void setValue (const T &value) { // Yeah, I'm crazy but it's useful to avoid code duplication. - new (this) Variant(value); + new(this) Variant(value); } template From e75404cbd848c584c617d134726c577b7e5e68bb Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 26 Sep 2017 11:56:49 +0200 Subject: [PATCH 0182/2215] fix(core): fix coding style on many files, remove useless includes... --- include/linphone/utils/general.h | 7 + src/address/address-p.h | 2 +- src/address/address.cpp | 3 - src/address/address.h | 2 - src/call/call-p.h | 6 +- src/call/call.cpp | 13 +- src/call/call.h | 49 ++++--- src/conference/session/call-session-p.h | 2 - src/conference/session/media-session-p.h | 93 +++++++----- src/content/content-type.h | 2 - src/content/content.h | 2 - src/db/abstract/abstract-db.cpp | 2 - src/db/events-db.cpp | 50 +++++-- src/db/events-db.h | 14 +- src/db/provider/db-session-p.h | 2 - src/db/provider/db-session.cpp | 2 - src/event-log/call-event.cpp | 3 +- src/event-log/chat-message-event.cpp | 5 +- src/event-log/conference-event-p.h | 1 - src/event-log/conference-event.cpp | 2 - .../conference-participant-event.cpp | 1 - src/event-log/event-log.cpp | 4 - src/nat/ice-agent.cpp | 135 +++++++++++------- src/nat/ice-agent.h | 24 +++- src/nat/stun-client.cpp | 53 ++++--- src/nat/stun-client.h | 27 ++-- src/utils/payload-type-handler.cpp | 4 +- src/utils/payload-type-handler.h | 9 +- src/variant/variant.cpp | 2 +- 29 files changed, 311 insertions(+), 210 deletions(-) diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index 17978a996..4ba9d8dc9 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -136,6 +136,13 @@ inline const Object *getPublicHelper (const T *object, const ObjectPrivate *) { return *this; \ } +// ----------------------------------------------------------------------------- +// Wrapper public. +// ----------------------------------------------------------------------------- + +#define L_DECL_C_STRUCT(STRUCT) typedef struct _ ## STRUCT STRUCT; +#define L_DECL_C_STRUCT_PREFIX_LESS(STRUCT) typedef struct STRUCT STRUCT; + #endif LINPHONE_END_NAMESPACE diff --git a/src/address/address-p.h b/src/address/address-p.h index 15364bfc1..ba502726b 100644 --- a/src/address/address-p.h +++ b/src/address/address-p.h @@ -56,4 +56,4 @@ private: LINPHONE_END_NAMESPACE -#endif +#endif // ifndef _ADDRESS_P_H_ diff --git a/src/address/address.cpp b/src/address/address.cpp index 054bad63c..17b9ed9bf 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -17,14 +17,11 @@ */ #include "linphone/utils/utils.h" -#include "sal/sal.h" #include "address-p.h" #include "c-wrapper/c-wrapper.h" #include "logger/logger.h" -#include "address.h" - // ============================================================================= using namespace std; diff --git a/src/address/address.h b/src/address/address.h index e35688f0c..679ba572b 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -19,8 +19,6 @@ #ifndef _ADDRESS_H_ #define _ADDRESS_H_ -#include - #include "enums.h" #include "object/clonable-object.h" diff --git a/src/call/call-p.h b/src/call/call-p.h index 9f2ebabdd..4be0b488c 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -19,12 +19,9 @@ #ifndef _CALL_P_H_ #define _CALL_P_H_ -#include - -#include "object/object-p.h" - #include "call.h" #include "conference/conference.h" +#include "object/object-p.h" #include "private.h" @@ -70,7 +67,6 @@ private: void onFirstVideoFrameDecoded () override; void onResetFirstVideoFrameDecoded () override; -private: LinphoneCall *lcall = nullptr; LinphoneCore *core = nullptr; diff --git a/src/call/call.cpp b/src/call/call.cpp index 7aefd00c5..b4f726bf5 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -17,23 +17,20 @@ */ #include "call-p.h" -#include "conference/participant-p.h" -#include "conference/session/media-session-p.h" - -#include "call.h" #include "conference/local-conference.h" +#include "conference/participant-p.h" #include "conference/remote-conference.h" -#include "conference/session/media-session.h" +#include "conference/session/media-session-p.h" #include "logger/logger.h" -#include "private.h" +#include "call.h" + +// ============================================================================= using namespace std; LINPHONE_BEGIN_NAMESPACE -// ============================================================================= - CallPrivate::CallPrivate (LinphoneCall *call, LinphoneCore *core, LinphoneCallDir direction, const Address &from, const Address &to, LinphoneProxyConfig *cfg, SalOp *op, const MediaSessionParams *msp) : lcall(call), core(core) { nextVideoFrameDecoded._func = nullptr; diff --git a/src/call/call.h b/src/call/call.h index ad13c8b9c..cbf4b7aca 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -19,12 +19,9 @@ #ifndef _CALL_CALL_H_ #define _CALL_CALL_H_ -#include "linphone/types.h" - -#include "object/object.h" #include "address/address.h" -#include "call/call-listener.h" #include "conference/params/media-session-params.h" +#include "object/object.h" // ============================================================================= @@ -39,8 +36,16 @@ class Call : public Object { friend class MediaSessionPrivate; public: - Call (LinphoneCall *call, LinphoneCore *core, LinphoneCallDir direction, const Address &from, const Address &to, - LinphoneProxyConfig *cfg, SalOp *op, const MediaSessionParams *msp); + Call ( + LinphoneCall *call, + LinphoneCore *core, + LinphoneCallDir direction, + const Address &from, + const Address &to, + LinphoneProxyConfig *cfg, + SalOp *op, + const MediaSessionParams *msp + ); LinphoneStatus accept (const MediaSessionParams *msp = nullptr); LinphoneStatus acceptEarlyMedia (const MediaSessionParams *msp = nullptr); @@ -52,8 +57,8 @@ public: void sendVfuRequest (); void startRecording (); void stopRecording (); - LinphoneStatus takePreviewSnapshot (const std::string& file); - LinphoneStatus takeVideoSnapshot (const std::string& file); + LinphoneStatus takePreviewSnapshot (const std::string &file); + LinphoneStatus takeVideoSnapshot (const std::string &file); LinphoneStatus terminate (const LinphoneErrorInfo *ei = nullptr); LinphoneStatus update (const MediaSessionParams *msp = nullptr); void zoomVideo (float zoomFactor, float *cx, float *cy); @@ -65,36 +70,36 @@ public: void enableEchoCancellation (bool value); void enableEchoLimiter (bool value); bool getAllMuted () const; - LinphoneCallStats * getAudioStats () const; + LinphoneCallStats *getAudioStats () const; std::string getAuthenticationToken () const; bool getAuthenticationTokenVerified () const; float getAverageQuality () const; - LinphoneCore * getCore () const; - const MediaSessionParams * getCurrentParams () const; + LinphoneCore *getCore () const; + const MediaSessionParams *getCurrentParams () const; float getCurrentQuality () const; LinphoneCallDir getDirection () const; int getDuration () const; - const LinphoneErrorInfo * getErrorInfo () const; - LinphoneCallLog * getLog () const; - RtpTransport * getMetaRtcpTransport (int streamIndex) const; - RtpTransport * getMetaRtpTransport (int streamIndex) const; + const LinphoneErrorInfo *getErrorInfo () const; + LinphoneCallLog *getLog () const; + RtpTransport *getMetaRtcpTransport (int streamIndex) const; + RtpTransport *getMetaRtpTransport (int streamIndex) const; float getMicrophoneVolumeGain () const; - void * getNativeVideoWindowId () const; - const MediaSessionParams * getParams () const; + void *getNativeVideoWindowId () const; + const MediaSessionParams *getParams () const; float getPlayVolume () const; LinphoneReason getReason () const; float getRecordVolume () const; - const Address& getRemoteAddress () const; + const Address &getRemoteAddress () const; std::string getRemoteAddressAsString () const; std::string getRemoteContact () const; - const MediaSessionParams * getRemoteParams () const; + const MediaSessionParams *getRemoteParams () const; float getSpeakerVolumeGain () const; LinphoneCallState getState () const; - LinphoneCallStats * getStats (LinphoneStreamType type) const; + LinphoneCallStats *getStats (LinphoneStreamType type) const; int getStreamCount () const; MSFormatType getStreamType (int streamIndex) const; - LinphoneCallStats * getTextStats () const; - LinphoneCallStats * getVideoStats () const; + LinphoneCallStats *getTextStats () const; + LinphoneCallStats *getVideoStats () const; bool mediaInProgress () const; void setAuthenticationTokenVerified (bool value); void setMicrophoneVolumeGain (float value); diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index 2e3913e71..790776151 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -19,8 +19,6 @@ #ifndef _CALL_SESSION_P_H_ #define _CALL_SESSION_P_H_ -#include - #include "object/object-p.h" #include "call-session.h" diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index fa96cf675..7d9cfbe6d 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -29,9 +29,6 @@ #include "nat/stun-client.h" #include "linphone/call_stats.h" -#include "sal/sal.h" - -#include "private.h" // ============================================================================= @@ -63,30 +60,53 @@ public: void prepareStreamsForIceGathering (bool hasVideo); void stopStreamsForIceGathering (); - int getAf () const { return af; } - bool getAudioMuted () const { return audioMuted; } - LinphoneCore * getCore () const { return core; } - IceSession * getIceSession () const { return iceAgent->getIceSession(); } - SalMediaDescription * getLocalDesc () const { return localDesc; } - MediaStream * getMediaStream (LinphoneStreamType type) const; - LinphoneNatPolicy * getNatPolicy () const { return natPolicy; } + int getAf () const { + return af; + } + + bool getAudioMuted () const { + return audioMuted; + } + + LinphoneCore *getCore () const { + return core; + } + + IceSession *getIceSession () const { + return iceAgent->getIceSession(); + } + + SalMediaDescription *getLocalDesc () const { + return localDesc; + } + + MediaStream *getMediaStream (LinphoneStreamType type) const; + LinphoneNatPolicy *getNatPolicy () const { + return natPolicy; + } + int getRtcpPort (LinphoneStreamType type) const; int getRtpPort (LinphoneStreamType type) const; - LinphoneCallStats * getStats (LinphoneStreamType type) const; + LinphoneCallStats *getStats (LinphoneStreamType type) const; int getStreamIndex (LinphoneStreamType type) const; int getStreamIndex (MediaStream *ms) const; - SalOp * getOp () const { return op; } - void setAudioMuted (bool value) { audioMuted = value; } + SalOp *getOp () const { + return op; + } + + void setAudioMuted (bool value) { + audioMuted = value; + } private: static OrtpJitterBufferAlgorithm jitterBufferNameToAlgo (const std::string &name); -#ifdef VIDEO_ENABLED - static void videoStreamEventCb (void *userData, const MSFilter *f, const unsigned int eventId, const void *args); -#endif -#ifdef TEST_EXT_RENDERER - static void extRendererCb (void *userData, const MSPicture *local, const MSPicture *remote); -#endif + #ifdef VIDEO_ENABLED + static void videoStreamEventCb (void *userData, const MSFilter *f, const unsigned int eventId, const void *args); + #endif // ifdef VIDEO_ENABLED + #ifdef TEST_EXT_RENDERER + static void extRendererCb (void *userData, const MSPicture *local, const MSPicture *remote); + #endif // ifdef TEST_EXT_RENDERER static void realTimeTextCharacterReceived (void *userData, MSFilter *f, unsigned int id, void *arg); static float aggregateQualityRatings (float audioRating, float videoRating); @@ -103,9 +123,9 @@ private: void initStats (LinphoneCallStats *stats, LinphoneStreamType type); void notifyStatsUpdated (int streamIndex) const; - OrtpEvQueue * getEventQueue (int streamIndex) const; - MediaStream * getMediaStream (int streamIndex) const; - MSWebCam * getVideoDevice () const; + OrtpEvQueue *getEventQueue (int streamIndex) const; + MediaStream *getMediaStream (int streamIndex) const; + MSWebCam *getVideoDevice () const; void fillMulticastMediaAddresses (); int selectFixedPort (int streamIndex, std::pair portRange); @@ -149,7 +169,7 @@ private: int getIdealAudioBandwidth (const SalMediaDescription *md, const SalStreamDescription *desc); int getVideoBandwidth (const SalMediaDescription *md, const SalStreamDescription *desc); - RtpProfile * makeProfile (const SalMediaDescription *md, const SalStreamDescription *desc, int *usedPt); + RtpProfile *makeProfile (const SalMediaDescription *md, const SalStreamDescription *desc, int *usedPt); void unsetRtpProfile (int streamIndex); void updateAllocatedAudioBandwidth (const PayloadType *pt, int maxbw); @@ -159,8 +179,8 @@ private: void configureAdaptiveRateControl (MediaStream *ms, const OrtpPayloadType *pt, bool videoWillBeUsed); void configureRtpSessionForRtcpFb (const SalStreamDescription *stream); void configureRtpSessionForRtcpXr (SalStreamType type); - RtpSession * createAudioRtpIoSession (); - RtpSession * createVideoRtpIoSession (); + RtpSession *createAudioRtpIoSession (); + RtpSession *createVideoRtpIoSession (); void freeResources (); void handleIceEvents (OrtpEvent *ev); void handleStreamEvents (int streamIndex); @@ -224,9 +244,9 @@ private: void accept (const MediaSessionParams *params); LinphoneStatus acceptUpdate (const CallSessionParams *csp, LinphoneCallState nextState, const std::string &stateInfo) override; -#ifdef VIDEO_ENABLED - void videoStreamEventCb (const MSFilter *f, const unsigned int eventId, const void *args); -#endif + #ifdef VIDEO_ENABLED + void videoStreamEventCb (const MSFilter *f, const unsigned int eventId, const void *args); + #endif // ifdef VIDEO_ENABLED void realTimeTextCharacterReceived (MSFilter *f, unsigned int id, void *arg); void stunAuthRequestedCb (const char *realm, const char *nonce, const char **username, const char **password, const char **ha1); @@ -265,11 +285,16 @@ private: StunClient *stunClient = nullptr; IceAgent *iceAgent = nullptr; - int af; /* The address family to prefer for RTP path, guessed from signaling path */ + // The address family to prefer for RTP path, guessed from signaling path. + int af; + std::string mediaLocalIp; PortConfig mediaPorts[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; bool needMediaLocalIpRefresh = false; - MSMediaStreamSessions sessions[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; /* The rtp, srtp, zrtp contexts for each stream */ + + // The rtp, srtp, zrtp contexts for each stream. + MSMediaStreamSessions sessions[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; + SalMediaDescription *localDesc = nullptr; int localDescChanged = 0; SalMediaDescription *biggestDesc = nullptr; @@ -283,8 +308,12 @@ private: std::string dtlsCertificateFingerprint; unsigned int nbMediaStarts = 0; - int upBandwidth = 0; /* Upload bandwidth setting at the time the call is started. Used to detect if it changes during a call */ - int audioBandwidth = 0; /* Upload bandwidth used by audio */ + + // Upload bandwidth setting at the time the call is started. Used to detect if it changes during a call. + int upBandwidth = 0; + + // Upload bandwidth used by audio. + int audioBandwidth = 0; bool allMuted = false; bool audioMuted = false; diff --git a/src/content/content-type.h b/src/content/content-type.h index 9df428f9f..c78d75c33 100644 --- a/src/content/content-type.h +++ b/src/content/content-type.h @@ -19,8 +19,6 @@ #ifndef _CONTENT_TYPE_H_ #define _CONTENT_TYPE_H_ -#include - #include "object/clonable-object.h" // ============================================================================= diff --git a/src/content/content.h b/src/content/content.h index 7037b124a..f25b0d783 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -19,11 +19,9 @@ #ifndef _CONTENT_H_ #define _CONTENT_H_ -#include #include #include "content-type.h" - #include "object/clonable-object.h" // ============================================================================= diff --git a/src/db/abstract/abstract-db.cpp b/src/db/abstract/abstract-db.cpp index 9345ec688..bbb80d4dd 100644 --- a/src/db/abstract/abstract-db.cpp +++ b/src/db/abstract/abstract-db.cpp @@ -20,8 +20,6 @@ #include "db/provider/db-session-provider.h" #include "logger/logger.h" -#include "abstract-db.h" - // ============================================================================= using namespace std; diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 2c30994fd..8befd680f 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -42,12 +42,12 @@ class EventsDbPrivate : public AbstractDbPrivate {}; EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} +#ifdef SOCI_ENABLED + // ----------------------------------------------------------------------------- // Soci backend. // ----------------------------------------------------------------------------- -#ifdef SOCI_ENABLED - template struct EnumToSql { T first; @@ -169,10 +169,18 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS dialog (" " id" + primaryKeyAutoIncrementStr() + "," - " local_sip_address_id INT UNSIGNED NOT NULL," // Sip address used to communicate. - " remote_sip_address_id INT UNSIGNED NOT NULL," // Server (for conference) or user sip address. - " creation_timestamp TIMESTAMP NOT NULL," // Dialog creation date. - " last_update_timestamp TIMESTAMP NOT NULL," // Last event timestamp (call, message...). + + // Sip address used to communicate. + " local_sip_address_id INT UNSIGNED NOT NULL," + + // Server (for conference) or user sip address. + " remote_sip_address_id INT UNSIGNED NOT NULL," + + // Dialog creation date. + " creation_timestamp TIMESTAMP NOT NULL," + + // Last event timestamp (call, message...). + " last_update_timestamp TIMESTAMP NOT NULL," " FOREIGN KEY (local_sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE," @@ -189,11 +197,19 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " state_id TINYINT UNSIGNED NOT NULL," " direction_id TINYINT UNSIGNED NOT NULL," " sender_sip_address_id INT UNSIGNED NOT NULL," - " imdn_message_id VARCHAR(255) NOT NULL," // See: https://tools.ietf.org/html/rfc5438#section-6.3 + + // See: https://tools.ietf.org/html/rfc5438#section-6.3 + " imdn_message_id VARCHAR(255) NOT NULL," + " is_secured BOOLEAN NOT NULL," - " content_type VARCHAR(255) NOT NULL," // Content type of text. (Html or text for example.) + + // Content type of text. (Html or text for example.) + " content_type VARCHAR(255) NOT NULL," " text TEXT," - " app_data VARCHAR(2048)," // App user data. + + // App user data. + " app_data VARCHAR(2048)," + " FOREIGN KEY (event_id)" " REFERENCES event(id)" " ON DELETE CASCADE," @@ -215,10 +231,18 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} "CREATE TABLE IF NOT EXISTS message_file_info (" " id" + primaryKeyAutoIncrementStr() + "," " message_id INT UNSIGNED NOT NULL," - " content_type VARCHAR(255) NOT NULL," // File content type. - " name VARCHAR(255) NOT NULL," // File name. - " size INT UNSIGNED NOT NULL," // File size. - " url VARCHAR(255) NOT NULL," // File url. + + // File content type. + " content_type VARCHAR(255) NOT NULL," + + // File name. + " name VARCHAR(255) NOT NULL," + + // File size. + " size INT UNSIGNED NOT NULL," + + // File url. + " url VARCHAR(255) NOT NULL," " key VARCHAR(4096)," " key_size INT UNSIGNED," " FOREIGN KEY (message_id)" diff --git a/src/db/events-db.h b/src/db/events-db.h index 22e187abb..6ca7f2a91 100644 --- a/src/db/events-db.h +++ b/src/db/events-db.h @@ -20,7 +20,6 @@ #define _EVENTS_DB_H_ #include -#include #include "abstract/abstract-db.h" @@ -53,8 +52,17 @@ public: // Messages, calls and conferences. int getMessagesCount (const std::string &remoteAddress = "") const; int getUnreadMessagesCount (const std::string &remoteAddress = "") const; - std::list > getHistory (const std::string &remoteAddress, int nLast, FilterMask mask = NoFilter) const; - std::list > getHistory (const std::string &remoteAddress, int begin, int end, FilterMask mask = NoFilter) const; + std::list> getHistory ( + const std::string &remoteAddress, + int nLast, + FilterMask mask = NoFilter + ) const; + std::list> getHistory ( + const std::string &remoteAddress, + int begin, + int end, + FilterMask mask = NoFilter + ) const; void cleanHistory (const std::string &remoteAddress = ""); protected: diff --git a/src/db/provider/db-session-p.h b/src/db/provider/db-session-p.h index de9e9b5da..6ed9ec95e 100644 --- a/src/db/provider/db-session-p.h +++ b/src/db/provider/db-session-p.h @@ -28,8 +28,6 @@ LINPHONE_BEGIN_NAMESPACE -// ----------------------------------------------------------------------------- - class DbSessionPrivate : public ClonableObjectPrivate { friend class DbSessionProvider; diff --git a/src/db/provider/db-session.cpp b/src/db/provider/db-session.cpp index f074804b3..48969d2e9 100644 --- a/src/db/provider/db-session.cpp +++ b/src/db/provider/db-session.cpp @@ -18,8 +18,6 @@ #include "db-session-p.h" -#include "db-session.h" - // ============================================================================= using namespace std; diff --git a/src/event-log/call-event.cpp b/src/event-log/call-event.cpp index 65556f9c5..6e304e7e2 100644 --- a/src/event-log/call-event.cpp +++ b/src/event-log/call-event.cpp @@ -16,9 +16,8 @@ * along with this program. If not, see . */ -#include "event-log-p.h" - #include "call-event.h" +#include "event-log-p.h" // ============================================================================= diff --git a/src/event-log/chat-message-event.cpp b/src/event-log/chat-message-event.cpp index bae401244..3fab969d7 100644 --- a/src/event-log/chat-message-event.cpp +++ b/src/event-log/chat-message-event.cpp @@ -16,9 +16,8 @@ * along with this program. If not, see . */ -#include "event-log-p.h" - #include "chat-message-event.h" +#include "event-log-p.h" // ============================================================================= @@ -45,7 +44,7 @@ ChatMessageEvent::ChatMessageEvent (const ChatMessageEvent &src) : ChatMessageEv ChatMessageEvent &ChatMessageEvent::operator= (const ChatMessageEvent &src) { L_D(ChatMessageEvent); if (this != &src) { - EventLog::operator= (src); + EventLog::operator=(src); d->chatMessage = src.getPrivate()->chatMessage; } diff --git a/src/event-log/conference-event-p.h b/src/event-log/conference-event-p.h index bad6d92cd..87885c3d7 100644 --- a/src/event-log/conference-event-p.h +++ b/src/event-log/conference-event-p.h @@ -21,7 +21,6 @@ #include "address/address.h" #include "conference-event.h" - #include "event-log-p.h" // ============================================================================= diff --git a/src/event-log/conference-event.cpp b/src/event-log/conference-event.cpp index 57657d527..81d79b4d2 100644 --- a/src/event-log/conference-event.cpp +++ b/src/event-log/conference-event.cpp @@ -19,8 +19,6 @@ #include "address/address.h" #include "conference-event-p.h" -#include "conference-event.h" - // ============================================================================= using namespace std; diff --git a/src/event-log/conference-participant-event.cpp b/src/event-log/conference-participant-event.cpp index 145d03956..0d1bf0443 100644 --- a/src/event-log/conference-participant-event.cpp +++ b/src/event-log/conference-participant-event.cpp @@ -18,7 +18,6 @@ #include "address/address.h" #include "conference-event-p.h" - #include "conference-participant-event.h" // ============================================================================= diff --git a/src/event-log/event-log.cpp b/src/event-log/event-log.cpp index cacec4d0d..e90a0ef9c 100644 --- a/src/event-log/event-log.cpp +++ b/src/event-log/event-log.cpp @@ -18,14 +18,10 @@ #include "event-log-p.h" -#include "event-log.h" - // ============================================================================= LINPHONE_BEGIN_NAMESPACE -// ----------------------------------------------------------------------------- - EventLog::EventLog () : ClonableObject(*new EventLogPrivate) {} EventLog::EventLog (const EventLog &) : ClonableObject(*new EventLogPrivate) {} diff --git a/src/nat/ice-agent.cpp b/src/nat/ice-agent.cpp index 50ef1c1f9..64d5f5c4f 100644 --- a/src/nat/ice-agent.cpp +++ b/src/nat/ice-agent.cpp @@ -18,17 +18,19 @@ #include "linphone/core.h" +#include "private.h" + #include "conference/session/media-session-p.h" #include "logger/logger.h" #include "ice-agent.h" // ============================================================================= + using namespace std; LINPHONE_BEGIN_NAMESPACE - bool IceAgent::candidatesGathered () const { if (!iceSession) return false; @@ -36,14 +38,21 @@ bool IceAgent::candidatesGathered () const { } void IceAgent::checkSession (IceRole role, bool isReinvite) { + // Already created. if (iceSession) - return; /* Already created */ + return; + LinphoneConfig *config = linphone_core_get_config(mediaSession.getPrivate()->getCore()); if (isReinvite && (lp_config_get_int(config, "net", "allow_late_ice", 0) == 0)) return; + iceSession = ice_session_new(); - /* For backward compatibility purposes, shall be enabled by default in the future */ - ice_session_enable_message_integrity_check(iceSession, !!lp_config_get_int(config, "net", "ice_session_enable_message_integrity_check", 1)); + + // For backward compatibility purposes, shall be enabled by default in the future. + ice_session_enable_message_integrity_check( + iceSession, + !!lp_config_get_int(config, "net", "ice_session_enable_message_integrity_check", 1) + ); if (lp_config_get_int(config, "net", "dont_default_to_stun_candidates", 0)) { IceCandidateType types[ICT_CandidateTypeMax]; types[0] = ICT_HostCandidate; @@ -57,6 +66,7 @@ void IceAgent::checkSession (IceRole role, bool isReinvite) { void IceAgent::deleteSession () { if (!iceSession) return; + ice_session_destroy(iceSession); iceSession = nullptr; mediaSession.getPrivate()->deactivateIce(); @@ -68,11 +78,13 @@ void IceAgent::gatheringFinished () { clearUnusedIceCandidates(mediaSession.getPrivate()->getLocalDesc(), rmd); if (!iceSession) return; + ice_session_compute_candidates_foundations(iceSession); ice_session_eliminate_redundant_candidates(iceSession); ice_session_choose_default_candidates(iceSession); + int pingTime = ice_session_average_gathering_round_trip_time(iceSession); - if (pingTime >=0) { + if (pingTime >= 0) { mediaSession.getPrivate()->setPingTime(pingTime); } } @@ -86,7 +98,7 @@ int IceAgent::getNbLosingPairs () const { bool IceAgent::hasCompleted () const { if (!iceSession) return false; - return (ice_session_state(iceSession) == IS_Completed); + return ice_session_state(iceSession) == IS_Completed; } bool IceAgent::hasCompletedCheckList () const { @@ -104,7 +116,7 @@ bool IceAgent::hasCompletedCheckList () const { bool IceAgent::isControlling () const { if (!iceSession) return false; - return (ice_session_role(iceSession) == IR_Controlling); + return ice_session_role(iceSession) == IR_Controlling; } bool IceAgent::prepare (const SalMediaDescription *localDesc, bool incomingOffer) { @@ -115,7 +127,8 @@ bool IceAgent::prepare (const SalMediaDescription *localDesc, bool incomingOffer bool hasVideo = false; if (incomingOffer) { remoteDesc = sal_call_get_remote_media_description(mediaSession.getPrivate()->getOp()); - hasVideo = linphone_core_video_enabled(mediaSession.getPrivate()->getCore()) && linphone_core_media_description_contains_video_stream(remoteDesc); + hasVideo = linphone_core_video_enabled(mediaSession.getPrivate()->getCore()) && + linphone_core_media_description_contains_video_stream(remoteDesc); } else hasVideo = mediaSession.getMediaParams()->videoEnabled(); @@ -124,14 +137,16 @@ bool IceAgent::prepare (const SalMediaDescription *localDesc, bool incomingOffer prepareIceForStream(mediaSession.getPrivate()->getMediaStream(LinphoneStreamTypeVideo), true); if (mediaSession.getMediaParams()->realtimeTextEnabled()) prepareIceForStream(mediaSession.getPrivate()->getMediaStream(LinphoneStreamTypeText), true); - /* Start ICE gathering */ + + // Start ICE gathering. if (incomingOffer) - updateFromRemoteMediaDescription(localDesc, remoteDesc, true); /* This may delete the ice session */ + // This may delete the ice session. + updateFromRemoteMediaDescription(localDesc, remoteDesc, true); if (iceSession && !ice_session_candidates_gathered(iceSession)) { mediaSession.getPrivate()->prepareStreamsForIceGathering(hasVideo); int err = gatherIceCandidates(); if (err == 0) { - /* Ice candidates gathering wasn't started, but we can proceed with the call anyway. */ + // Ice candidates gathering wasn't started, but we can proceed with the call anyway. mediaSession.getPrivate()->stopStreamsForIceGathering(); return false; } else if (err == -1) { @@ -147,6 +162,7 @@ bool IceAgent::prepare (const SalMediaDescription *localDesc, bool incomingOffer void IceAgent::prepareIceForStream (MediaStream *ms, bool createChecklist) { if (!iceSession) return; + int streamIndex = mediaSession.getPrivate()->getStreamIndex(ms); rtp_session_set_pktinfo(ms->sessions.rtp_session, true); IceCheckList *cl = ice_session_check_list(iceSession, streamIndex); @@ -186,20 +202,25 @@ void IceAgent::stopIceForInactiveStreams (SalMediaDescription *desc) { updateIceStateInCallStats(); } -void IceAgent::updateFromRemoteMediaDescription (const SalMediaDescription *localDesc, const SalMediaDescription *remoteDesc, bool isOffer) { +void IceAgent::updateFromRemoteMediaDescription ( + const SalMediaDescription *localDesc, + const SalMediaDescription *remoteDesc, + bool isOffer +) { if (!iceSession) return; + if (!iceParamsFoundInRemoteMediaDescription(remoteDesc)) { - /* Response from remote does not contain mandatory ICE attributes, delete the session */ + // Response from remote does not contain mandatory ICE attributes, delete the session. deleteSession(); mediaSession.getPrivate()->enableSymmetricRtp(linphone_core_symmetric_rtp_enabled(mediaSession.getPrivate()->getCore())); return; } - /* Check for ICE restart and set remote credentials */ + // Check for ICE restart and set remote credentials. bool iceRestarted = checkForIceRestartAndSetRemoteCredentials(remoteDesc, isOffer); - /* Create ICE check lists if needed and parse ICE attributes */ + // Create ICE check lists if needed and parse ICE attributes. createIceCheckListsAndParseIceAttributes(remoteDesc, iceRestarted); for (int i = 0; i < remoteDesc->nb_streams; i++) { const SalStreamDescription *stream = &remoteDesc->streams[i]; @@ -259,9 +280,9 @@ void IceAgent::updateIceStateInCallStats () { if (textCheckList && mediaSession.getMediaParams()->realtimeTextEnabled()) _linphone_call_stats_set_ice_state(textStats, LinphoneIceStateFailed); } - lInfo() << "CallSession [" << &mediaSession << "] New ICE state: audio: [" << linphone_ice_state_to_string(linphone_call_stats_get_ice_state(audioStats)) - << "] video: [" << linphone_ice_state_to_string(linphone_call_stats_get_ice_state(videoStats)) - << "] text: [" << linphone_ice_state_to_string(linphone_call_stats_get_ice_state(textStats)) << "]"; + lInfo() << "CallSession [" << &mediaSession << "] New ICE state: audio: [" << linphone_ice_state_to_string(linphone_call_stats_get_ice_state(audioStats)) << + "] video: [" << linphone_ice_state_to_string(linphone_call_stats_get_ice_state(videoStats)) << + "] text: [" << linphone_ice_state_to_string(linphone_call_stats_get_ice_state(textStats)) << "]"; } void IceAgent::updateLocalMediaDescriptionFromIce (SalMediaDescription *desc) { @@ -297,9 +318,9 @@ void IceAgent::updateLocalMediaDescriptionFromIce (SalMediaDescription *desc) { if (!sal_stream_description_active(stream) || !cl) continue; if (ice_check_list_state(cl) == ICL_Completed) { - /* Set this to false once flexisip are updated everywhere, let's say in December 2016 */ LinphoneConfig *config = linphone_core_get_config(mediaSession.getPrivate()->getCore()); - bool useNoRtpProxy = lp_config_get_int(config, "sip", "ice_uses_nortpproxy", true); + // TODO: Remove `ice_uses_nortpproxy` option, let's say in December 2018. + bool useNoRtpProxy = lp_config_get_int(config, "sip", "ice_uses_nortpproxy", false); if (useNoRtpProxy) stream->set_nortpproxy = true; result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(iceSession, i), &rtpCandidate, &rtcpCandidate); @@ -343,9 +364,11 @@ void IceAgent::updateLocalMediaDescriptionFromIce (SalMediaDescription *desc) { continue; if (defaultAddr[0] == '\0') defaultAddr = desc->addr; - /* Only include the candidates matching the default destination for each component of the stream if the state is Completed as specified in RFC5245 section 9.1.2.2. */ - if ((ice_check_list_state(cl) == ICL_Completed) - && !((iceCandidate->taddr.port == defaultPort) && (strlen(iceCandidate->taddr.ip) == strlen(defaultAddr)) && (strcmp(iceCandidate->taddr.ip, defaultAddr) == 0))) + // Only include the candidates matching the default destination for each component of the stream if the state is Completed as specified in RFC5245 section 9.1.2.2. + if ( + ice_check_list_state(cl) == ICL_Completed && + !((iceCandidate->taddr.port == defaultPort) && (strlen(iceCandidate->taddr.ip) == strlen(defaultAddr)) && (strcmp(iceCandidate->taddr.ip, defaultAddr) == 0)) + ) continue; strncpy(salCandidate->foundation, iceCandidate->foundation, sizeof(salCandidate->foundation)); salCandidate->componentID = iceCandidate->componentID; @@ -441,7 +464,7 @@ bool IceAgent::checkForIceRestartAndSetRemoteCredentials (const SalMediaDescript if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) { if (ice_check_list_remote_credentials_changed(cl, stream->ice_ufrag, stream->ice_pwd)) { if (!iceRestarted && ice_check_list_get_remote_ufrag(cl) && ice_check_list_get_remote_pwd(cl)) { - /* Restart only if remote ufrag/paswd was already set */ + // Restart only if remote ufrag/paswd was already set. ice_session_restart(iceSession, isOffer ? IR_Controlled : IR_Controlling); iceRestarted = true; } @@ -515,8 +538,11 @@ void IceAgent::createIceCheckListsAndParseIceAttributes (const SalMediaDescripti int componentID = j + 1; if (remoteCandidate->addr[0] == '\0') break; getIceDefaultAddrAndPort(static_cast(componentID), md, stream, &addr, &port); - if (j == 0) /* If we receive a re-invite and we finished ICE processing on our side, use the candidates given by the remote. */ + + // If we receive a re-invite and we finished ICE processing on our side, use the candidates given by the remote. + if (j == 0) ice_check_list_unselect_valid_pairs(cl); + int remoteFamily = AF_INET; if (strchr(remoteCandidate->addr, ':')) remoteFamily = AF_INET6; @@ -560,7 +586,7 @@ int IceAgent::gatherIceCandidates () { ice_session_enable_forced_relay(iceSession, core->forced_ice_relay); ice_session_enable_short_turn_refresh(iceSession, core->short_turn_refresh); - /* Gather local host candidates. */ + // Gather local host candidates. char localAddr[64]; if (mediaSession.getPrivate()->getAf() == AF_INET6) { if (linphone_core_get_local_ip_for(AF_INET6, nullptr, localAddr) < 0) { @@ -579,7 +605,7 @@ int IceAgent::gatherIceCandidates () { if (ai && natPolicy && linphone_nat_policy_stun_server_activated(natPolicy)) { string server = linphone_nat_policy_get_stun_server(natPolicy); lInfo() << "ICE: gathering candidates from [" << server << "] using " << (linphone_nat_policy_turn_enabled(natPolicy) ? "TURN" : "STUN"); - /* Gather local srflx candidates */ + // Gather local srflx candidates. ice_session_enable_turn(iceSession, linphone_nat_policy_turn_enabled(natPolicy)); ice_session_set_stun_auth_requested_cb(iceSession, MediaSessionPrivate::stunAuthRequestedCb, &mediaSession); return ice_session_gather_candidates(iceSession, ai->ai_addr, (socklen_t)ai->ai_addrlen) ? 1 : 0; @@ -592,7 +618,13 @@ int IceAgent::gatherIceCandidates () { return 0; } -void IceAgent::getIceDefaultAddrAndPort (uint16_t componentID, const SalMediaDescription *md, const SalStreamDescription *stream, const char **addr, int *port) { +void IceAgent::getIceDefaultAddrAndPort ( + uint16_t componentID, + const SalMediaDescription *md, + const SalStreamDescription *stream, + const char **addr, + int *port +) { if (componentID == 1) { *addr = stream->rtp_addr; *port = stream->rtp_port; @@ -609,8 +641,8 @@ void IceAgent::getIceDefaultAddrAndPort (uint16_t componentID, const SalMediaDes * the DNS resolution returned. If a NAT64 address is present, use it, otherwise if an IPv4 address * is present, use it, otherwise use an IPv6 address if it is present. */ -const struct addrinfo * IceAgent::getIcePreferredStunServerAddrinfo (const struct addrinfo *ai) { - /* Search for NAT64 addrinfo */ +const struct addrinfo *IceAgent::getIcePreferredStunServerAddrinfo (const struct addrinfo *ai) { + // Search for NAT64 addrinfo. const struct addrinfo *it = ai; while (it) { if (it->ai_family == AF_INET6) { @@ -623,7 +655,7 @@ const struct addrinfo * IceAgent::getIcePreferredStunServerAddrinfo (const struc } const struct addrinfo *preferredAi = it; if (!preferredAi) { - /* Search for IPv4 addrinfo */ + // Search for IPv4 addrinfo. it = ai; while (it) { if (it->ai_family == AF_INET) @@ -635,7 +667,7 @@ const struct addrinfo * IceAgent::getIcePreferredStunServerAddrinfo (const struc preferredAi = it; } if (!preferredAi) { - /* Search for IPv6 addrinfo */ + // Search for IPv6 addrinfo. it = ai; while (it) { if (it->ai_family == AF_INET6) @@ -667,25 +699,28 @@ bool IceAgent::iceParamsFoundInRemoteMediaDescription (const SalMediaDescription } void IceAgent::updateIceStateInCallStatsForStream (LinphoneCallStats *stats, IceCheckList *cl) { - if (ice_check_list_state(cl) == ICL_Completed) { - switch (ice_check_list_selected_valid_candidate_type(cl)) { - case ICT_HostCandidate: - _linphone_call_stats_set_ice_state(stats, LinphoneIceStateHostConnection); - break; - case ICT_ServerReflexiveCandidate: - case ICT_PeerReflexiveCandidate: - _linphone_call_stats_set_ice_state(stats, LinphoneIceStateReflexiveConnection); - break; - case ICT_RelayedCandidate: - _linphone_call_stats_set_ice_state(stats, LinphoneIceStateRelayConnection); - break; - case ICT_CandidateInvalid: - case ICT_CandidateTypeMax: - /* Shall not happen */ - break; - } - } else + if (ice_check_list_state(cl) != ICL_Completed) { _linphone_call_stats_set_ice_state(stats, LinphoneIceStateFailed); + return; + } + + switch (ice_check_list_selected_valid_candidate_type(cl)) { + case ICT_HostCandidate: + _linphone_call_stats_set_ice_state(stats, LinphoneIceStateHostConnection); + break; + case ICT_ServerReflexiveCandidate: + case ICT_PeerReflexiveCandidate: + _linphone_call_stats_set_ice_state(stats, LinphoneIceStateReflexiveConnection); + break; + case ICT_RelayedCandidate: + _linphone_call_stats_set_ice_state(stats, LinphoneIceStateRelayConnection); + break; + case ICT_CandidateInvalid: + case ICT_CandidateTypeMax: + // Shall not happen. + L_ASSERT(false); + break; + } } LINPHONE_END_NAMESPACE diff --git a/src/nat/ice-agent.h b/src/nat/ice-agent.h index 0019ecd29..2aa13b05d 100644 --- a/src/nat/ice-agent.h +++ b/src/nat/ice-agent.h @@ -22,14 +22,18 @@ #include #include -#include "linphone/types.h" #include "linphone/utils/general.h" -#include "sal/sal.h" - -#include "conference/session/media-session.h" // ============================================================================= +L_DECL_C_STRUCT_PREFIX_LESS(SalMediaDescription); +L_DECL_C_STRUCT_PREFIX_LESS(SalStreamDescription); +L_DECL_C_STRUCT(LinphoneCallStats); +L_DECL_C_STRUCT(LinphoneCore); +L_DECL_C_STRUCT(MediaStream); + +class MediaSession; + LINPHONE_BEGIN_NAMESPACE class IceAgent { @@ -41,10 +45,16 @@ public: void deleteSession (); void gatheringFinished (); int getNbLosingPairs () const; - IceSession * getIceSession () const { return iceSession; } + IceSession *getIceSession () const { + return iceSession; + } + bool hasCompleted () const; bool hasCompletedCheckList () const; - bool hasSession () const { return iceSession; } + bool hasSession () const { + return iceSession; + } + bool isControlling () const; bool prepare (const SalMediaDescription *localDesc, bool incomingOffer); void prepareIceForStream (MediaStream *ms, bool createChecklist); @@ -62,7 +72,7 @@ private: void createIceCheckListsAndParseIceAttributes (const SalMediaDescription *md, bool iceRestarted); int gatherIceCandidates (); void getIceDefaultAddrAndPort (uint16_t componentID, const SalMediaDescription *md, const SalStreamDescription *stream, const char **addr, int *port); - const struct addrinfo * getIcePreferredStunServerAddrinfo (const struct addrinfo *ai); + const struct addrinfo *getIcePreferredStunServerAddrinfo (const struct addrinfo *ai); bool iceParamsFoundInRemoteMediaDescription (const SalMediaDescription *md); void updateIceStateInCallStatsForStream (LinphoneCallStats *stats, IceCheckList *cl); diff --git a/src/nat/stun-client.cpp b/src/nat/stun-client.cpp index 554bd9eb4..b2faacc8b 100644 --- a/src/nat/stun-client.cpp +++ b/src/nat/stun-client.cpp @@ -16,8 +16,6 @@ * along with this program. If not, see . */ -#include "linphone/core.h" - #include "private.h" #include "logger/logger.h" @@ -113,31 +111,28 @@ int StunClient::run (int audioPort, int videoPort, int textPort) { break; } loops++; - } while (!(gotAudio && (gotVideo || (sockVideo == -1)) && (gotText || (sockText == -1)))); + } while (!(gotAudio && (gotVideo || sockVideo == -1) && (gotText || sockText == -1))); if (ret == 0) ret = (int)elapsed; + if (!gotAudio) lError() << "No STUN server response for audio port"; - else { - if (!coneAudio) - lInfo() << "NAT is symmetric for audio port"; - } + else if (!coneAudio) + lInfo() << "NAT is symmetric for audio port"; + if (sockVideo != -1) { if (!gotVideo) lError() << "No STUN server response for video port"; - else { - if (!coneVideo) - lInfo() << "NAT is symmetric for video port"; - } + else if (!coneVideo) + lInfo() << "NAT is symmetric for video port"; } + if (sockText != -1) { if (!gotText) lError() << "No STUN server response for text port"; - else { - if (!coneText) - lInfo() << "NAT is symmetric for text port"; - } + else if (!coneText) + lInfo() << "NAT is symmetric for text port"; } close_socket(sockAudio); @@ -150,16 +145,22 @@ void StunClient::updateMediaDescription (SalMediaDescription *md) const { for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (!sal_stream_description_active(&md->streams[i])) continue; - if ((md->streams[i].type == SalAudio) && (audioCandidate.port != 0)) { + if (md->streams[i].type == SalAudio && audioCandidate.port != 0) { strncpy(md->streams[i].rtp_addr, audioCandidate.address.c_str(), sizeof(md->streams[i].rtp_addr)); md->streams[i].rtp_port = audioCandidate.port; - if ((!audioCandidate.address.empty() && !videoCandidate.address.empty() && (audioCandidate.address == videoCandidate.address)) - || (sal_media_description_get_nb_active_streams(md) == 1)) + if ( + ( + !audioCandidate.address.empty() && + !videoCandidate.address.empty() && + audioCandidate.address == videoCandidate.address + ) || + sal_media_description_get_nb_active_streams(md) == 1 + ) strncpy(md->addr, audioCandidate.address.c_str(), sizeof(md->addr)); - } else if ((md->streams[i].type == SalVideo) && (videoCandidate.port != 0)) { + } else if (md->streams[i].type == SalVideo && videoCandidate.port != 0) { strncpy(md->streams[i].rtp_addr, videoCandidate.address.c_str(), sizeof(md->streams[i].rtp_addr)); md->streams[i].rtp_port = videoCandidate.port; - } else if ((md->streams[i].type == SalText) && (textCandidate.port != 0)) { + } else if (md->streams[i].type == SalText && textCandidate.port != 0) { strncpy(md->streams[i].rtp_addr, textCandidate.address.c_str(), sizeof(md->streams[i].rtp_addr)); md->streams[i].rtp_port = textCandidate.port; } @@ -187,13 +188,13 @@ ortp_socket_t StunClient::createStunSocket (int localPort) { return -1; } int optval = 1; - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (SOCKET_OPTION_VALUE)&optval, sizeof (optval)) < 0) + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (SOCKET_OPTION_VALUE)&optval, sizeof(optval)) < 0) lWarning() << "Fail to set SO_REUSEADDR"; set_non_blocking_socket(sock); return sock; } -int StunClient::recvStunResponse(ortp_socket_t sock, Candidate &candidate, int &id) { +int StunClient::recvStunResponse (ortp_socket_t sock, Candidate &candidate, int &id) { char buf[MS_STUN_MAX_MESSAGE_SIZE]; int len = MS_STUN_MAX_MESSAGE_SIZE; @@ -223,7 +224,13 @@ int StunClient::recvStunResponse(ortp_socket_t sock, Candidate &candidate, int & return len; } -int StunClient::sendStunRequest(ortp_socket_t sock, const struct sockaddr *server, socklen_t addrlen, int id, bool changeAddr) { +int StunClient::sendStunRequest ( + ortp_socket_t sock, + const struct sockaddr *server, + socklen_t addrlen, + int id, + bool changeAddr +) { MSStunMessage *req = ms_stun_binding_request_create(); UInt96 trId = ms_stun_message_get_tr_id(req); trId.octet[0] = static_cast(id); diff --git a/src/nat/stun-client.h b/src/nat/stun-client.h index e4da561ce..6230fef7e 100644 --- a/src/nat/stun-client.h +++ b/src/nat/stun-client.h @@ -19,18 +19,20 @@ #ifndef _STUN_CLIENT_H_ #define _STUN_CLIENT_H_ +#include + #include -#include "linphone/types.h" #include "linphone/utils/general.h" -#include "sal/sal.h" // ============================================================================= +L_DECL_C_STRUCT_PREFIX_LESS(SalMediaDescription); +L_DECL_C_STRUCT(LinphoneCore); + LINPHONE_BEGIN_NAMESPACE class StunClient { - struct Candidate { std::string address; int port; @@ -42,14 +44,21 @@ public: int run (int audioPort, int videoPort, int textPort); void updateMediaDescription (SalMediaDescription *md) const; - const Candidate & getAudioCandidate () const { return audioCandidate; } - const Candidate & getVideoCandidate () const { return videoCandidate; } - const Candidate & getTextCandidate () const { return textCandidate; } + const Candidate &getAudioCandidate () const { + return audioCandidate; + } + + const Candidate &getVideoCandidate () const { + return videoCandidate; + } + + const Candidate &getTextCandidate () const { + return textCandidate; + } -private: ortp_socket_t createStunSocket (int localPort); - int recvStunResponse(ortp_socket_t sock, Candidate &candidate, int &id); - int sendStunRequest(ortp_socket_t sock, const struct sockaddr *server, socklen_t addrlen, int id, bool changeAddr); + int recvStunResponse (ortp_socket_t sock, Candidate &candidate, int &id); + int sendStunRequest (ortp_socket_t sock, const struct sockaddr *server, socklen_t addrlen, int id, bool changeAddr); private: LinphoneCore *core = nullptr; diff --git a/src/utils/payload-type-handler.cpp b/src/utils/payload-type-handler.cpp index 25044f106..7761aacfe 100644 --- a/src/utils/payload-type-handler.cpp +++ b/src/utils/payload-type-handler.cpp @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -#include +#include #include "private.h" @@ -294,7 +294,7 @@ bctbx_list_t *PayloadTypeHandler::makeCodecsList (SalStreamType type, int bandwi if (bandwidthLimit > 0 && !isPayloadTypeUsableForBandwidth(pt, bandwidthLimit)) { lInfo() << "Codec " << pt->mime_type << "/" << pt->clock_rate << " eliminated because of audio bandwidth constraint of " << - bandwidthLimit << " kbit/s"; + bandwidthLimit << " kbit/s"; continue; } diff --git a/src/utils/payload-type-handler.h b/src/utils/payload-type-handler.h index 892e175aa..fb339e255 100644 --- a/src/utils/payload-type-handler.h +++ b/src/utils/payload-type-handler.h @@ -19,17 +19,18 @@ #ifndef _PAYLOAD_TYPE_HANDLER_H_ #define _PAYLOAD_TYPE_HANDLER_H_ -#include "linphone/core.h" #include "linphone/utils/general.h" -#include "sal/sal.h" /* SalStreamType. */ - -// ============================================================================= +#include "sal/sal.h" #define PAYLOAD_TYPE_ENABLED PAYLOAD_TYPE_USER_FLAG_0 #define PAYLOAD_TYPE_BITRATE_OVERRIDE PAYLOAD_TYPE_USER_FLAG_3 #define PAYLOAD_TYPE_FROZEN_NUMBER PAYLOAD_TYPE_USER_FLAG_4 +// ============================================================================= + +L_DECL_C_STRUCT(LinphoneCore); + LINPHONE_BEGIN_NAMESPACE struct VbrCodecBitrate { diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index 7590002dd..2d5cf1a77 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -171,7 +171,7 @@ Variant::Variant (float value) : Variant(Float) { d->value.f = value; } -Variant::Variant (const std::string &value) : Variant(String) { +Variant::Variant (const string &value) : Variant(String) { L_D(Variant); *d->value.str = value; } From fc75fdef794a58dadaa6602bb6508a5c9d0d8773 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 26 Sep 2017 12:12:36 +0200 Subject: [PATCH 0183/2215] feat(c-wrapper): L_GET_CPP_PTR_FROM_C_OBJECT supports optional cpp type parameter --- src/c-wrapper/internal/c-tools.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 6690f308e..bbaed56d7 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -429,8 +429,16 @@ LINPHONE_END_NAMESPACE #define L_INIT(C_TYPE) _linphone_ ## C_TYPE ## _init () // Get/set the cpp-ptr of a wrapped C object. -#define L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT) \ - LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC(C_OBJECT) +#define L_GET_CPP_PTR_FROM_C_OBJECT_1_ARGS(C_OBJECT) \ + L_GET_CPP_PTR_FROM_C_OBJECT_2_ARGS(C_OBJECT, ) +#define L_GET_CPP_PTR_FROM_C_OBJECT_2_ARGS(C_OBJECT, CPP_TYPE) \ + LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC(C_OBJECT) + +#define L_GET_CPP_PTR_FROM_C_OBJECT_MACRO_CHOOSER(...) \ + L_GET_ARG_3(__VA_ARGS__, L_GET_CPP_PTR_FROM_C_OBJECT_2_ARGS, L_GET_CPP_PTR_FROM_C_OBJECT_1_ARGS) + +#define L_GET_CPP_PTR_FROM_C_OBJECT(...) \ + L_GET_CPP_PTR_FROM_C_OBJECT_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__) // Set the cpp-ptr of a wrapped C object. #define L_SET_CPP_PTR_FROM_C_OBJECT(C_OBJECT, CPP_OBJECT) \ From 6a3956494c4f8cf0cd50dfcdbeae9c1de7fbf81e Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 26 Sep 2017 13:46:01 +0200 Subject: [PATCH 0184/2215] fix(core): coding style --- coreapi/chat.c | 8 +- daemon/commands/call-transfer.cc | 6 +- daemon/commands/conference.cc | 4 +- daemon/commands/register-info.cc | 32 ++++---- daemon/commands/video.cc | 4 +- daemon/daemon.cc | 22 +++--- src/c-wrapper/api/c-call.cpp | 8 +- src/c-wrapper/api/c-chat-message.cpp | 4 +- src/c-wrapper/api/c-chat-room.cpp | 6 +- src/call/call-listener.h | 2 +- src/call/call-p.h | 32 +++++--- src/call/call.cpp | 98 ++++++++++++++---------- src/call/call.h | 2 +- src/chat/chat-message.cpp | 8 +- src/chat/client-group-chat-room.cpp | 2 +- src/chat/is-composing.cpp | 4 +- src/conference/conference.cpp | 2 +- src/conference/conference.h | 6 +- src/conference/participant-p.h | 2 +- src/conference/remote-conference.h | 2 +- src/conference/session/call-session.cpp | 2 +- src/conference/session/media-session.cpp | 4 +- src/content/content-type.cpp | 4 +- src/content/content.cpp | 6 +- src/object/property-container.cpp | 2 +- 25 files changed, 152 insertions(+), 120 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index b033d8f34..7059cb04b 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -42,6 +42,8 @@ #include "chat/real-time-text-chat-room-p.h" #include "content/content-type.h" +using namespace std; + void linphone_core_disable_chat(LinphoneCore *lc, LinphoneReason deny_reason) { lc->chat_deny_code = deny_reason; } @@ -236,9 +238,9 @@ int linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, uint32_t character, LinphoneCall *call) { if (linphone_core_realtime_text_enabled(lc)) { - std::shared_ptr rttcr = - std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); + shared_ptr rttcr = + static_pointer_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); L_GET_PRIVATE(rttcr)->realtimeTextReceived(character, call); - //L_GET_PRIVATE(std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr)))->realtimeTextReceived(character, call); + //L_GET_PRIVATE(static_pointer_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr)))->realtimeTextReceived(character, call); } } diff --git a/daemon/commands/call-transfer.cc b/daemon/commands/call-transfer.cc index fbb41042a..e7d3f9e24 100644 --- a/daemon/commands/call-transfer.cc +++ b/daemon/commands/call-transfer.cc @@ -1,6 +1,6 @@ /* call-transfer.cc -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -85,7 +85,7 @@ void CallTransferCommand::exec(Daemon* app, const string& args) return; } if (linphone_call_transfer_to_another(call_to_transfer, call_to_transfer_to) == 0) { - std::ostringstream ostr; + ostringstream ostr; ostr << "Call ID: " << call_to_transfer_id << "\n"; ostr << "Transfer to: " << call_to_transfer_to_id << "\n"; app->sendResponse(Response(ostr.str(), Response::Ok)); @@ -93,7 +93,7 @@ void CallTransferCommand::exec(Daemon* app, const string& args) } } else { if (linphone_call_transfer(call_to_transfer, sip_uri_to_transfer_to.c_str()) == 0) { - std::ostringstream ostr; + ostringstream ostr; ostr << "Call ID: " << call_to_transfer_id << "\n"; ostr << "Transfer to: " << sip_uri_to_transfer_to << "\n"; app->sendResponse(Response(ostr.str(), Response::Ok)); diff --git a/daemon/commands/conference.cc b/daemon/commands/conference.cc index a4929f72c..6d1c83c93 100644 --- a/daemon/commands/conference.cc +++ b/daemon/commands/conference.cc @@ -1,6 +1,6 @@ /* conference.cc -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -79,7 +79,7 @@ void ConferenceCommand::exec(Daemon* app, const string& args) { } if (ret == 0) { - std::ostringstream ostr; + ostringstream ostr; ostr << "Call ID: " << id << "\n"; ostr << "Conference: " << subcommand << " OK" << "\n"; app->sendResponse(Response(ostr.str(), Response::Ok)); diff --git a/daemon/commands/register-info.cc b/daemon/commands/register-info.cc index 681d894e3..5b39259e5 100644 --- a/daemon/commands/register-info.cc +++ b/daemon/commands/register-info.cc @@ -1,6 +1,6 @@ /* register-info.cc -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -21,6 +21,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include #include "register-info.h" +using namespace std; + class RegisterInfoResponse: public Response { public: RegisterInfoResponse(): Response() {} @@ -28,19 +30,19 @@ public: append(id, cfg); } void append(int id, const ::LinphoneProxyConfig *cfg) { - std::ostringstream ost; + ostringstream ost; ost << getBody(); - if (ost.tellp() > 0) ost << std::endl; - ost << "Id: " << id << std::endl; - ost << "Identity: " << linphone_proxy_config_get_identity(cfg) << std::endl; - ost << "Proxy: " << linphone_proxy_config_get_server_addr(cfg) << std::endl; - + if (ost.tellp() > 0) ost << endl; + ost << "Id: " << id << endl; + ost << "Identity: " << linphone_proxy_config_get_identity(cfg) << endl; + ost << "Proxy: " << linphone_proxy_config_get_server_addr(cfg) << endl; + const char *route = linphone_proxy_config_get_route(cfg); if (route != NULL) { - ost << "Route: " << route << std::endl; + ost << "Route: " << route << endl; } - - ost << "State: " << linphone_registration_state_to_string(linphone_proxy_config_get_state(cfg)) << std::endl; + + ost << "State: " << linphone_registration_state_to_string(linphone_proxy_config_get_state(cfg)) << endl; setBody(ost.str()); } }; @@ -72,9 +74,9 @@ RegisterInfoCommand::RegisterInfoCommand(): "Reason: No register with such id.")); } -void RegisterInfoCommand::exec(Daemon *app, const std::string& args) { - std::string param; - std::istringstream ist(args); +void RegisterInfoCommand::exec(Daemon *app, const string& args) { + string param; + istringstream ist(args); ist >> param; if (ist.fail()) { app->sendResponse(Response("Missing parameter.", Response::Error)); @@ -93,10 +95,10 @@ void RegisterInfoCommand::exec(Daemon *app, const std::string& args) { int id; try { id = atoi(param.c_str()); - } catch (std::invalid_argument) { + } catch (invalid_argument) { app->sendResponse(Response("Invalid ID.", Response::Error)); return; - } catch (std::out_of_range) { + } catch (out_of_range) { app->sendResponse(Response("Out of range ID.", Response::Error)); return; } diff --git a/daemon/commands/video.cc b/daemon/commands/video.cc index 2b92a8db8..99679f7a4 100644 --- a/daemon/commands/video.cc +++ b/daemon/commands/video.cc @@ -1,6 +1,6 @@ /* video.cc -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -162,7 +162,7 @@ AutoVideo::AutoVideo(): "Auto video OFF")); } -void AutoVideo::exec(Daemon* app, const std::string& args) +void AutoVideo::exec(Daemon* app, const string& args) { bool enable = (args.compare("on") == 0); diff --git a/daemon/daemon.cc b/daemon/daemon.cc index af2474cb8..d97650863 100644 --- a/daemon/daemon.cc +++ b/daemon/daemon.cc @@ -1,6 +1,6 @@ /* daemon.cc -Copyright (C) 2016 Belledonne Communications, Grenoble, France +Copyright (C) 2016 Belledonne Communications, Grenoble, France This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -331,11 +331,11 @@ Daemon::Daemon(const char *config_path, const char *factory_config_path, const c linphone_core_set_user_data(mLc, this); linphone_core_enable_video_capture(mLc,capture_video); linphone_core_enable_video_display(mLc,display_video); - + for(const bctbx_list_t *proxy = linphone_core_get_proxy_config_list(mLc); proxy != NULL; proxy = bctbx_list_next(proxy)) { updateProxyId((LinphoneProxyConfig *)bctbx_list_get_data(proxy)); } - + initCommands(); mUseStatsEvents=true; } @@ -403,7 +403,7 @@ LinphoneAuthInfo *Daemon::findAuthInfo(int id) { } int Daemon::updateAudioStreamId(AudioStream *audio_stream) { - for (std::map::iterator it = mAudioStreams.begin(); it != mAudioStreams.end(); ++it) { + for (map::iterator it = mAudioStreams.begin(); it != mAudioStreams.end(); ++it) { if (it->second->stream == audio_stream) return it->first; } @@ -414,21 +414,21 @@ int Daemon::updateAudioStreamId(AudioStream *audio_stream) { } AudioStreamAndOther *Daemon::findAudioStreamAndOther(int id) { - std::map::iterator it = mAudioStreams.find(id); + map::iterator it = mAudioStreams.find(id); if (it != mAudioStreams.end()) return it->second; return NULL; } AudioStream *Daemon::findAudioStream(int id) { - std::map::iterator it = mAudioStreams.find(id); + map::iterator it = mAudioStreams.find(id); if (it != mAudioStreams.end()) return it->second->stream; return NULL; } void Daemon::removeAudioStream(int id) { - std::map::iterator it = mAudioStreams.find(id); + map::iterator it = mAudioStreams.find(id); if (it != mAudioStreams.end()) { mAudioStreams.erase(it); delete(it->second); @@ -542,7 +542,7 @@ void Daemon::dtmfReceived(LinphoneCore *lc, LinphoneCall *call, int dtmf) { } void Daemon::iterateStreamStats() { - for (std::map::iterator it = mAudioStreams.begin(); it != mAudioStreams.end(); ++it) { + for (map::iterator it = mAudioStreams.begin(); it != mAudioStreams.end(); ++it) { OrtpEvent *ev; while (it->second->queue && (NULL != (ev=ortp_ev_queue_get(it->second->queue)))){ OrtpEventType evt=ortp_event_get_type(ev); @@ -730,7 +730,7 @@ void Daemon::dumpCommandsHelpHtml(){ cout<<"

    "<<"Description"<<"

    "<"<getDescription())<<"

    "<"<<"Examples"<<""< &examples=(*it)->getExamples(); + const list &examples=(*it)->getExamples(); cout<<"

    "; for(list::const_iterator ex_it=examples.begin();ex_it!=examples.end();++ex_it){ cout<<""<")<getCommand())<<"
    "<::max(), '\n'); + cin.ignore(numeric_limits::max(), '\n'); return outbuf.str(); #endif } @@ -851,7 +851,7 @@ void Daemon::enableLSD(bool enabled) { Daemon::~Daemon() { uninitCommands(); - for (std::map::iterator it = mAudioStreams.begin(); it != mAudioStreams.end(); ++it) { + for (map::iterator it = mAudioStreams.begin(); it != mAudioStreams.end(); ++it) { audio_stream_stop(it->second->stream); } diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 5a22046c0..3a398b8fb 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -735,7 +735,7 @@ const char *linphone_call_get_remote_user_agent (LinphoneCall *call) { } const char * linphone_call_get_remote_contact (LinphoneCall *call) { - std::string contact = L_GET_CPP_PTR_FROM_C_OBJECT(call)->getRemoteContact(); + string contact = L_GET_CPP_PTR_FROM_C_OBJECT(call)->getRemoteContact(); if (contact.empty()) return nullptr; if (call->remoteContactCache) @@ -745,7 +745,7 @@ const char * linphone_call_get_remote_contact (LinphoneCall *call) { } const char *linphone_call_get_authentication_token (LinphoneCall *call) { - std::string token = L_GET_CPP_PTR_FROM_C_OBJECT(call)->getAuthenticationToken(); + string token = L_GET_CPP_PTR_FROM_C_OBJECT(call)->getAuthenticationToken(); return token.empty() ? nullptr : token.c_str(); } @@ -1184,7 +1184,7 @@ void linphone_call_set_user_data (LinphoneCall *call, void *ud) { LinphoneCall *linphone_call_new_outgoing (LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg) { LinphoneCall *call = L_INIT(Call); - L_SET_CPP_PTR_FROM_C_OBJECT(call, std::make_shared(call, lc, LinphoneCallOutgoing, + L_SET_CPP_PTR_FROM_C_OBJECT(call, make_shared(call, lc, LinphoneCallOutgoing, *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), cfg, nullptr, L_GET_CPP_PTR_FROM_C_OBJECT(params))); call->currentParamsCache = linphone_call_params_new_for_wrapper(); @@ -1196,7 +1196,7 @@ LinphoneCall *linphone_call_new_outgoing (LinphoneCore *lc, const LinphoneAddres LinphoneCall *linphone_call_new_incoming (LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, SalOp *op) { LinphoneCall *call = L_INIT(Call); - L_SET_CPP_PTR_FROM_C_OBJECT(call, std::make_shared(call, lc, LinphoneCallIncoming, + L_SET_CPP_PTR_FROM_C_OBJECT(call, make_shared(call, lc, LinphoneCallIncoming, *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), nullptr, op, nullptr)); call->currentParamsCache = linphone_call_params_new_for_wrapper(); diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 3a8bc06d5..3b4b78881 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -498,8 +498,8 @@ void linphone_chat_message_send_display_notification(LinphoneChatMessage *cm) { }LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg, uint32_t character) { LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) { - std::shared_ptr rttcr = - std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); + shared_ptr rttcr = + static_pointer_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); LinphoneCall *call = rttcr->getCall(); LinphoneCore *lc = rttcr->getCore(); const uint32_t new_line = 0x2028; diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 547f96705..6da8b0c6e 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -269,9 +269,9 @@ void linphone_chat_room_set_user_data (LinphoneChatRoom *cr, void *ud) { LinphoneChatRoom *linphone_chat_room_new (LinphoneCore *core, const LinphoneAddress *addr) { LinphoneChatRoom *cr = L_INIT(ChatRoom); if (linphone_core_realtime_text_enabled(core)) - L_SET_CPP_PTR_FROM_C_OBJECT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_OBJECT(addr))); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared(core, *L_GET_CPP_PTR_FROM_C_OBJECT(addr))); else - L_SET_CPP_PTR_FROM_C_OBJECT(cr, std::make_shared(core, *L_GET_CPP_PTR_FROM_C_OBJECT(addr))); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared(core, *L_GET_CPP_PTR_FROM_C_OBJECT(addr))); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Created); return cr; @@ -284,7 +284,7 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core) { LinphoneAddress *factoryAddr = linphone_address_new(factoryUri); LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core, factoryAddr); linphone_address_unref(factoryAddr); - std::string from; + string from; if (proxy) from = L_GET_CPP_PTR_FROM_C_OBJECT(linphone_proxy_config_get_identity_address(proxy))->asString(); if (from.empty()) diff --git a/src/call/call-listener.h b/src/call/call-listener.h index 82f837989..11680c334 100644 --- a/src/call/call-listener.h +++ b/src/call/call-listener.h @@ -27,7 +27,7 @@ LINPHONE_BEGIN_NAMESPACE class CallListener { public: - virtual ~CallListener() = default; + virtual ~CallListener () = default; virtual void onAckBeingSent (LinphoneHeaders *headers) = 0; virtual void onAckReceived (LinphoneHeaders *headers) = 0; diff --git a/src/call/call-p.h b/src/call/call-p.h index 4be0b488c..c655c9052 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -29,25 +29,39 @@ LINPHONE_BEGIN_NAMESPACE -class CallPrivate : public ObjectPrivate, CallListener { +class CallPrivate : + public ObjectPrivate, + CallListener { public: - CallPrivate (LinphoneCall *call, LinphoneCore *core, LinphoneCallDir direction, const Address &from, const Address &to, - LinphoneProxyConfig *cfg, SalOp *op, const MediaSessionParams *msp); + CallPrivate ( + LinphoneCall *call, + LinphoneCore *core, + LinphoneCallDir direction, + const Address &from, + const Address &to, + LinphoneProxyConfig *cfg, + SalOp *op, + const MediaSessionParams *msp + ); virtual ~CallPrivate (); void initiateIncoming (); bool initiateOutgoing (); void iterate (time_t currentRealTime, bool oneSecondElapsed); void startIncomingNotification (); - int startInvite (const Address *destination); /* If destination is nullptr, it is taken from the call log */ + + int startInvite (const Address *destination); std::shared_ptr getActiveSession () const; bool getAudioMuted () const; - Conference * getConference () const { return conference; } - LinphoneProxyConfig * getDestProxy () const; - IceSession * getIceSession () const; - MediaStream * getMediaStream (LinphoneStreamType type) const; - SalOp * getOp () const; + Conference *getConference () const { + return conference; + } + + LinphoneProxyConfig *getDestProxy () const; + IceSession *getIceSession () const; + MediaStream *getMediaStream (LinphoneStreamType type) const; + SalOp *getOp () const; void setAudioMuted (bool value); private: diff --git a/src/call/call.cpp b/src/call/call.cpp index b4f726bf5..9c9e6f613 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -23,16 +23,22 @@ #include "conference/session/media-session-p.h" #include "logger/logger.h" -#include "call.h" - // ============================================================================= using namespace std; LINPHONE_BEGIN_NAMESPACE -CallPrivate::CallPrivate (LinphoneCall *call, LinphoneCore *core, LinphoneCallDir direction, const Address &from, const Address &to, - LinphoneProxyConfig *cfg, SalOp *op, const MediaSessionParams *msp) : lcall(call), core(core) { +CallPrivate::CallPrivate ( + LinphoneCall *call, + LinphoneCore *core, + LinphoneCallDir direction, + const Address &from, + const Address &to, + LinphoneProxyConfig *cfg, + SalOp *op, + const MediaSessionParams *msp +) : lcall(call), core(core) { nextVideoFrameDecoded._func = nullptr; nextVideoFrameDecoded._user_data = nullptr; } @@ -52,19 +58,19 @@ bool CallPrivate::getAudioMuted () const { return static_cast(getActiveSession().get())->getPrivate()->getAudioMuted(); } -LinphoneProxyConfig * CallPrivate::getDestProxy () const { +LinphoneProxyConfig *CallPrivate::getDestProxy () const { return getActiveSession()->getPrivate()->getDestProxy(); } -IceSession * CallPrivate::getIceSession () const { +IceSession *CallPrivate::getIceSession () const { return static_cast(getActiveSession().get())->getPrivate()->getIceSession(); } -MediaStream * CallPrivate::getMediaStream (LinphoneStreamType type) const { +MediaStream *CallPrivate::getMediaStream (LinphoneStreamType type) const { return static_cast(getActiveSession().get())->getPrivate()->getMediaStream(type); } -SalOp * CallPrivate::getOp () const { +SalOp *CallPrivate::getOp () const { return getActiveSession()->getPrivate()->getOp(); } @@ -119,16 +125,16 @@ void CallPrivate::onCallSetTerminated () { } if (linphone_core_del_call(core, lcall) != 0) lError() << "Could not remove the call from the list!!!"; -#if 0 - if (core->conf_ctx) - linphone_conference_on_call_terminating(core->conf_ctx, lcall); - if (lcall->ringing_beep){ - linphone_core_stop_dtmf(core); - lcall->ringing_beep = false; - } - if (lcall->chat_room) - linphone_chat_room_set_call(lcall->chat_room, nullptr); -#endif + #if 0 + if (core->conf_ctx) + linphone_conference_on_call_terminating(core->conf_ctx, lcall); + if (lcall->ringing_beep) { + linphone_core_stop_dtmf(core); + lcall->ringing_beep = false; + } + if (lcall->chat_room) + linphone_chat_room_set_call(lcall->chat_room, nullptr); + #endif // if 0 if (!core->calls) ms_bandwidth_controller_reset_state(core->bw_controller); } @@ -149,8 +155,8 @@ void CallPrivate::onCheckForAcceptation () { case LinphoneCallOutgoingProgress: case LinphoneCallOutgoingRinging: case LinphoneCallOutgoingEarlyMedia: - lInfo() << "Already existing call [" << call << "] in state [" << linphone_call_state_to_string(linphone_call_get_state(call)) - << "], canceling it before accepting new call [" << lcall << "]"; + lInfo() << "Already existing call [" << call << "] in state [" << linphone_call_state_to_string(linphone_call_get_state(call)) << + "], canceling it before accepting new call [" << lcall << "]"; linphone_call_terminate(call); break; default: @@ -198,16 +204,24 @@ void CallPrivate::onFirstVideoFrameDecoded () { } void CallPrivate::onResetFirstVideoFrameDecoded () { -#ifdef VIDEO_ENABLED - if (lcall && nextVideoFrameDecoded._func) - static_cast(getActiveSession().get())->resetFirstVideoFrameDecoded(); -#endif + #ifdef VIDEO_ENABLED + if (lcall && nextVideoFrameDecoded._func) + static_cast(getActiveSession().get())->resetFirstVideoFrameDecoded(); + #endif // ifdef VIDEO_ENABLED } // ============================================================================= -Call::Call (LinphoneCall *call, LinphoneCore *core, LinphoneCallDir direction, const Address &from, const Address &to, - LinphoneProxyConfig *cfg, SalOp *op, const MediaSessionParams *msp) : Object(*new CallPrivate(call, core, direction, from, to, cfg, op, msp)) { +Call::Call ( + LinphoneCall *call, + LinphoneCore *core, + LinphoneCallDir direction, + const Address &from, + const Address &to, + LinphoneProxyConfig *cfg, + SalOp *op, + const MediaSessionParams *msp +) : Object(*new CallPrivate(call, core, direction, from, to, cfg, op, msp)) { L_D(Call); const Address *myAddress = (direction == LinphoneCallIncoming) ? &to : &from; string confType = lp_config_get_string(linphone_core_get_config(core), "misc", "conference_type", "local"); @@ -273,12 +287,12 @@ void Call::stopRecording () { static_cast(d->getActiveSession().get())->stopRecording(); } -LinphoneStatus Call::takePreviewSnapshot (const string& file) { +LinphoneStatus Call::takePreviewSnapshot (const string &file) { L_D(Call); return static_cast(d->getActiveSession().get())->takePreviewSnapshot(file); } -LinphoneStatus Call::takeVideoSnapshot (const string& file) { +LinphoneStatus Call::takeVideoSnapshot (const string &file) { L_D(Call); return static_cast(d->getActiveSession().get())->takeVideoSnapshot(file); } @@ -335,7 +349,7 @@ bool Call::getAllMuted () const { return static_cast(d->getActiveSession().get())->getAllMuted(); } -LinphoneCallStats * Call::getAudioStats () const { +LinphoneCallStats *Call::getAudioStats () const { L_D(const Call); return static_cast(d->getActiveSession().get())->getAudioStats(); } @@ -355,12 +369,12 @@ float Call::getAverageQuality () const { return static_cast(d->getActiveSession().get())->getAverageQuality(); } -LinphoneCore * Call::getCore () const { +LinphoneCore *Call::getCore () const { L_D(const Call); return d->core; } -const MediaSessionParams * Call::getCurrentParams () const { +const MediaSessionParams *Call::getCurrentParams () const { L_D(const Call); return static_cast(d->getActiveSession().get())->getCurrentParams(); } @@ -380,22 +394,22 @@ int Call::getDuration () const { return d->getActiveSession()->getDuration(); } -const LinphoneErrorInfo * Call::getErrorInfo () const { +const LinphoneErrorInfo *Call::getErrorInfo () const { L_D(const Call); return d->getActiveSession()->getErrorInfo(); } -LinphoneCallLog * Call::getLog () const { +LinphoneCallLog *Call::getLog () const { L_D(const Call); return d->getActiveSession()->getLog(); } -RtpTransport * Call::getMetaRtcpTransport (int streamIndex) const { +RtpTransport *Call::getMetaRtcpTransport (int streamIndex) const { L_D(const Call); return static_cast(d->getActiveSession().get())->getMetaRtcpTransport(streamIndex); } -RtpTransport * Call::getMetaRtpTransport (int streamIndex) const { +RtpTransport *Call::getMetaRtpTransport (int streamIndex) const { L_D(const Call); return static_cast(d->getActiveSession().get())->getMetaRtpTransport(streamIndex); } @@ -405,12 +419,12 @@ float Call::getMicrophoneVolumeGain () const { return static_cast(d->getActiveSession().get())->getMicrophoneVolumeGain(); } -void * Call::getNativeVideoWindowId () const { +void *Call::getNativeVideoWindowId () const { L_D(const Call); return static_cast(d->getActiveSession().get())->getNativeVideoWindowId(); } -const MediaSessionParams * Call::getParams () const { +const MediaSessionParams *Call::getParams () const { L_D(const Call); return static_cast(d->getActiveSession().get())->getMediaParams(); } @@ -430,7 +444,7 @@ float Call::getRecordVolume () const { return static_cast(d->getActiveSession().get())->getRecordVolume(); } -const Address& Call::getRemoteAddress () const { +const Address &Call::getRemoteAddress () const { L_D(const Call); return d->getActiveSession()->getRemoteAddress(); } @@ -445,7 +459,7 @@ string Call::getRemoteContact () const { return d->getActiveSession()->getRemoteContact(); } -const MediaSessionParams * Call::getRemoteParams () const { +const MediaSessionParams *Call::getRemoteParams () const { L_D(const Call); return static_cast(d->getActiveSession().get())->getRemoteParams(); } @@ -460,7 +474,7 @@ LinphoneCallState Call::getState () const { return d->getActiveSession()->getState(); } -LinphoneCallStats * Call::getStats (LinphoneStreamType type) const { +LinphoneCallStats *Call::getStats (LinphoneStreamType type) const { L_D(const Call); return static_cast(d->getActiveSession().get())->getStats(type); } @@ -475,12 +489,12 @@ MSFormatType Call::getStreamType (int streamIndex) const { return static_cast(d->getActiveSession().get())->getStreamType(streamIndex); } -LinphoneCallStats * Call::getTextStats () const { +LinphoneCallStats *Call::getTextStats () const { L_D(const Call); return static_cast(d->getActiveSession().get())->getTextStats(); } -LinphoneCallStats * Call::getVideoStats () const { +LinphoneCallStats *Call::getVideoStats () const { L_D(const Call); return static_cast(d->getActiveSession().get())->getVideoStats(); } diff --git a/src/call/call.h b/src/call/call.h index cbf4b7aca..d809c3563 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -19,7 +19,6 @@ #ifndef _CALL_CALL_H_ #define _CALL_CALL_H_ -#include "address/address.h" #include "conference/params/media-session-params.h" #include "object/object.h" @@ -27,6 +26,7 @@ LINPHONE_BEGIN_NAMESPACE +class Address; class CallPrivate; class CallSessionPrivate; class MediaSessionPrivate; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index de28edd49..c73be1e5f 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -40,14 +40,14 @@ using namespace std; // ----------------------------------------------------------------------------- -ChatMessagePrivate::ChatMessagePrivate (const std::shared_ptr &room) +ChatMessagePrivate::ChatMessagePrivate (const shared_ptr &room) : chatRoom(room) {} ChatMessagePrivate::~ChatMessagePrivate () {} // ----------------------------------------------------------------------------- -ChatMessage::ChatMessage (const std::shared_ptr &room) : Object(*new ChatMessagePrivate(room)) {} +ChatMessage::ChatMessage (const shared_ptr &room) : Object(*new ChatMessagePrivate(room)) {} ChatMessage::ChatMessage (ChatMessagePrivate &p) : Object(p) {} @@ -62,7 +62,7 @@ shared_ptr ChatMessage::getChatRoom () const { // ----------------------------------------------------------------------------- -std::string ChatMessage::getExternalBodyUrl() const { +string ChatMessage::getExternalBodyUrl() const { L_D(const ChatMessage); return d->externalBodyUrl; } @@ -127,7 +127,7 @@ void ChatMessage::setState(State state) { ms_message("Chat message %p: moving from state %s to %s", msg, linphone_chat_message_state_to_string(msg->state), linphone_chat_message_state_to_string(state)); */ d->state = state; - + LinphoneChatMessage *msg = L_GET_C_BACK_PTR(this); /* TODO if (msg->message_state_changed_cb) { diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 4ecf2ee45..912383cf4 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -141,7 +141,7 @@ void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdm // ----------------------------------------------------------------------------- -void ClientGroupChatRoom::onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message) { +void ClientGroupChatRoom::onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const string &message) { if (state == LinphoneCallConnected) { // TODO: Get the conference ID instead of the remote address onConferenceCreated(session.getRemoteAddress()); diff --git a/src/chat/is-composing.cpp b/src/chat/is-composing.cpp index 7a4560aa5..e1ef360b1 100644 --- a/src/chat/is-composing.cpp +++ b/src/chat/is-composing.cpp @@ -42,7 +42,7 @@ IsComposing::~IsComposing () { // ----------------------------------------------------------------------------- -std::string IsComposing::marshal (bool isComposing) { +string IsComposing::marshal (bool isComposing) { string content; xmlBufferPtr buf = xmlBufferCreate(); @@ -192,7 +192,7 @@ unsigned int IsComposing::getRefreshTimerDuration () { unsigned int IsComposing::getRemoteRefreshTimerDuration () { int remoteRefreshTimerDuration = lp_config_get_int(core->config, "sip", "composing_remote_refresh_timeout", defaultRemoteRefreshTimeout); - return remoteRefreshTimerDuration < 0 ? 0 : static_cast(remoteRefreshTimerDuration); + return remoteRefreshTimerDuration < 0 ? 0 : static_cast(remoteRefreshTimerDuration); } void IsComposing::parse (xmlparsing_context_t *xmlCtx) { diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 99463295a..b26f83845 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -149,7 +149,7 @@ void Conference::onResetFirstVideoFrameDecoded (const CallSession &session) { // ----------------------------------------------------------------------------- -std::shared_ptr Conference::findParticipant (const Address &addr) { +shared_ptr Conference::findParticipant (const Address &addr) { for (const auto &participant : participants) { if (addr.equal(participant->getAddress())) return participant; diff --git a/src/conference/conference.h b/src/conference/conference.h index b1a1f4fee..d80c50298 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -82,10 +82,10 @@ protected: LinphoneCore *core = nullptr; CallListener *callListener = nullptr; - std::shared_ptr activeParticipant = nullptr; - std::string id; - std::shared_ptr me = nullptr; + std::shared_ptr activeParticipant; + std::shared_ptr me; std::list> participants; + std::string id; private: L_DISABLE_COPY(Conference); diff --git a/src/conference/participant-p.h b/src/conference/participant-p.h index 4abcb974a..8d863a9eb 100644 --- a/src/conference/participant-p.h +++ b/src/conference/participant-p.h @@ -44,7 +44,7 @@ public: private: Address addr; bool isAdmin = false; - std::shared_ptr session = nullptr; + std::shared_ptr session; L_DECLARE_PUBLIC(Participant); }; diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index 3277ba520..8e7593320 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -32,7 +32,7 @@ public: virtual ~RemoteConference(); protected: - std::shared_ptr focus = nullptr; + std::shared_ptr focus; public: /* ConferenceInterface */ diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 392c632ca..d38fa5e85 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -558,7 +558,7 @@ void CallSessionPrivate::setTerminated() { listener->onCallSessionSetTerminated(*q); } -LinphoneStatus CallSessionPrivate::startAcceptUpdate (LinphoneCallState nextState, const std::string &stateInfo) { +LinphoneStatus CallSessionPrivate::startAcceptUpdate (LinphoneCallState nextState, const string &stateInfo) { sal_call_accept(op); setState(nextState, stateInfo); return 0; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 5f8703d42..c1bce3c98 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -4348,7 +4348,7 @@ void MediaSession::resetFirstVideoFrameDecoded () { ms_filter_call_method_noarg(d->videoStream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION); } -LinphoneStatus MediaSession::takePreviewSnapshot (const std::string& file) { +LinphoneStatus MediaSession::takePreviewSnapshot (const string& file) { #ifdef VIDEO_ENABLED L_D(MediaSession); if (d->videoStream && d->videoStream->local_jpegwriter) { @@ -4360,7 +4360,7 @@ LinphoneStatus MediaSession::takePreviewSnapshot (const std::string& file) { return -1; } -LinphoneStatus MediaSession::takeVideoSnapshot (const std::string& file) { +LinphoneStatus MediaSession::takeVideoSnapshot (const string& file) { #ifdef VIDEO_ENABLED L_D(MediaSession); if (d->videoStream && d->videoStream->jpegwriter) { diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index 4fc11faf0..6d0815811 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -79,7 +79,7 @@ const string &ContentType::getType () const { return d->type; } -bool ContentType::setType (const std::string &type) { +bool ContentType::setType (const string &type) { L_D(ContentType); if (type.find('/') == string::npos) { d->type = type; @@ -93,7 +93,7 @@ const string &ContentType::getSubType () const { return d->subType; } -bool ContentType::setSubType (const std::string &subType) { +bool ContentType::setSubType (const string &subType) { L_D(ContentType); if (subType.find('/') == string::npos) { d->subType = subType; diff --git a/src/content/content.cpp b/src/content/content.cpp index c2b1a425a..efac402a1 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -92,7 +92,7 @@ void Content::setContentDisposition (const string &contentDisposition) { d->contentDisposition = contentDisposition; } -const std::vector &Content::getBody () const { +const vector &Content::getBody () const { L_D(const Content); return d->body; } @@ -102,12 +102,12 @@ string Content::getBodyAsString () const { return string(d->body.begin(), d->body.end()); } -void Content::setBody (const std::vector &body) { +void Content::setBody (const vector &body) { L_D(Content); d->body = body; } -void Content::setBody (const std::string &body) { +void Content::setBody (const string &body) { L_D(Content); d->body = vector(body.cbegin(), body.cend()); } diff --git a/src/object/property-container.cpp b/src/object/property-container.cpp index fadc32082..b0c472588 100644 --- a/src/object/property-container.cpp +++ b/src/object/property-container.cpp @@ -28,7 +28,7 @@ LINPHONE_BEGIN_NAMESPACE class PropertyContainerPrivate { public: - unordered_map properties; + unordered_map properties; }; // ----------------------------------------------------------------------------- From 325653641b7bea05eaa6785a4f7d6c596cec633e Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 26 Sep 2017 14:33:49 +0200 Subject: [PATCH 0185/2215] feat(c-wrapper): add an optional parameter CPP_TYPE on L_GET_PRIVATE_FROM_C_OBJECT --- src/c-wrapper/api/c-chat-room.cpp | 2 +- src/c-wrapper/internal/c-tools.h | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 6da8b0c6e..652ccb466 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -159,7 +159,7 @@ LinphoneCall *linphone_chat_room_get_call (const LinphoneChatRoom *cr) { void linphone_chat_room_set_call (LinphoneChatRoom *cr, LinphoneCall *call) { if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) - static_cast(L_GET_PRIVATE_FROM_C_OBJECT(cr))->setCall(call); + L_GET_PRIVATE_FROM_C_OBJECT(cr, RealTimeTextChatRoom)->setCall(call); } bctbx_list_t *linphone_chat_room_get_transient_messages (const LinphoneChatRoom *cr) { diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index bbaed56d7..3316a93fc 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -430,9 +430,12 @@ LINPHONE_END_NAMESPACE // Get/set the cpp-ptr of a wrapped C object. #define L_GET_CPP_PTR_FROM_C_OBJECT_1_ARGS(C_OBJECT) \ - L_GET_CPP_PTR_FROM_C_OBJECT_2_ARGS(C_OBJECT, ) + LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC(C_OBJECT) #define L_GET_CPP_PTR_FROM_C_OBJECT_2_ARGS(C_OBJECT, CPP_TYPE) \ - LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC(C_OBJECT) + LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC< \ + std::remove_pointer::type, \ + LINPHONE_NAMESPACE::CPP_TYPE \ + >(C_OBJECT) #define L_GET_CPP_PTR_FROM_C_OBJECT_MACRO_CHOOSER(...) \ L_GET_ARG_3(__VA_ARGS__, L_GET_CPP_PTR_FROM_C_OBJECT_2_ARGS, L_GET_CPP_PTR_FROM_C_OBJECT_1_ARGS) @@ -449,8 +452,16 @@ LINPHONE_END_NAMESPACE LINPHONE_NAMESPACE::Wrapper::getPrivate(LINPHONE_NAMESPACE::Utils::getPtr(CPP_OBJECT)) // Get the private data of a shared or simple cpp-ptr of a wrapped C object. -#define L_GET_PRIVATE_FROM_C_OBJECT(C_OBJECT) \ +#define L_GET_PRIVATE_FROM_C_OBJECT_1_ARGS(C_OBJECT) \ L_GET_PRIVATE(LINPHONE_NAMESPACE::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT))) +#define L_GET_PRIVATE_FROM_C_OBJECT_2_ARGS(C_OBJECT, CPP_TYPE) \ + L_GET_PRIVATE(LINPHONE_NAMESPACE::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT, CPP_TYPE))) + +#define L_GET_PRIVATE_FROM_C_OBJECT_MACRO_CHOOSER(...) \ + L_GET_ARG_3(__VA_ARGS__, L_GET_PRIVATE_FROM_C_OBJECT_2_ARGS, L_GET_PRIVATE_FROM_C_OBJECT_1_ARGS) + +#define L_GET_PRIVATE_FROM_C_OBJECT(...) \ + L_GET_PRIVATE_FROM_C_OBJECT_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__) // Get the wrapped C object of a C++ object. #define L_GET_C_BACK_PTR(CPP_OBJECT) \ From 20690528fbd608fbe8fb7bcdb36ec6983a67413a Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 26 Sep 2017 15:47:52 +0200 Subject: [PATCH 0186/2215] feat(c-wrapper): getCppPtrFromC is more secure, check types --- include/linphone/utils/general.h | 2 +- src/c-wrapper/c-wrapper.h | 3 ++- src/c-wrapper/internal/c-tools.h | 28 +++++++++++++++++++++++----- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index 4ba9d8dc9..aabcf1ab4 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -74,7 +74,7 @@ void l_assert (const char *condition, const char *file, int line); // Allows access to private internal data. // Gives a control to C Wrapper. #define L_DECLARE_PRIVATE(CLASS) \ - inline CLASS ## Private * getPrivate() { \ + inline CLASS ## Private *getPrivate() { \ return reinterpret_cast(mPrivate); \ } \ inline const CLASS ## Private *getPrivate() const { \ diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index fde36fed1..fed96f8df 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -41,7 +41,8 @@ F(Participant, Participant) #define L_REGISTER_SUBTYPES(F) \ - F(ChatRoom, ClientGroupChatRoom) + F(ChatRoom, ClientGroupChatRoom) \ + F(ChatRoom, RealTimeTextChatRoom) // ============================================================================= // Register belle-sip ID. diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 3316a93fc..788d090b3 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -37,11 +37,13 @@ LINPHONE_BEGIN_NAMESPACE template struct CppTypeToCType { enum { defined = false }; + typedef void type; }; template struct CTypeToCppType { enum { defined = false }; + typedef void type; }; template @@ -51,7 +53,23 @@ class Wrapper { private: template struct IsCppObject { - enum { value = std::is_base_of::value || std::is_base_of::value }; + enum { + value = std::is_base_of::value || std::is_base_of::value + }; + }; + + template + struct IsDefinedNotClonableCppObject { + enum { + value = CppTypeToCType::defined && std::is_base_of::value + }; + }; + + template + struct IsDefinedClonableCppObject { + enum { + value = CppTypeToCType::defined && std::is_base_of::value + }; }; template @@ -86,7 +104,7 @@ public: template< typename CType, typename CppType = typename CTypeToCppType::type, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static constexpr std::shared_ptr getCppPtrFromC (CType *cObject) { return reinterpret_cast *>(cObject)->cppPtr; @@ -95,7 +113,7 @@ public: template< typename CType, typename CppType = typename CTypeToCppType::type, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static constexpr std::shared_ptr getCppPtrFromC (const CType *cObject) { return reinterpret_cast *>(cObject)->cppPtr; @@ -104,7 +122,7 @@ public: template< typename CType, typename CppType = typename CTypeToCppType::type, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static constexpr CppType *getCppPtrFromC (CType *cObject) { return reinterpret_cast *>(cObject)->cppPtr; @@ -113,7 +131,7 @@ public: template< typename CType, typename CppType = typename CTypeToCppType::type, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static constexpr const CppType *getCppPtrFromC (const CType *cObject) { return reinterpret_cast *>(cObject)->cppPtr; From 78f4b39ab16e4b0a1406ad04b70941b1c1007cf9 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 26 Sep 2017 15:39:11 +0200 Subject: [PATCH 0187/2215] Finish cleaning of c-chat-message, still work to do in ChatMessage --- coreapi/private.h | 1 - include/linphone/api/c-chat-message.h | 6 +- src/c-wrapper/api/c-chat-message.cpp | 1130 ++++--------------------- src/chat/chat-message-p.h | 9 +- src/chat/chat-message.cpp | 938 +++++++++++++++++++- src/chat/chat-message.h | 54 +- src/chat/chat-room.cpp | 2 - tester/message_tester.c | 2 +- 8 files changed, 1139 insertions(+), 1003 deletions(-) diff --git a/coreapi/private.h b/coreapi/private.h index 0cd36ff8e..b3a9d0ce7 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -1099,7 +1099,6 @@ void linphone_chat_message_set_file_transfer_information(LinphoneChatMessage *ms LinphoneChatMessageDir linphone_chat_message_get_direction(const LinphoneChatMessage *msg); SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg); void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, SalOp *op); -void linphone_chat_message_set_chat_room(LinphoneChatMessage *msg, LinphoneChatRoom *room); void linphone_chat_message_destroy(LinphoneChatMessage* msg); void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state); void linphone_chat_message_set_is_secured(LinphoneChatMessage *msg, bool_t secured); diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index 74f2753d1..7b82dcccd 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -105,7 +105,7 @@ LINPHONE_PUBLIC void linphone_chat_message_set_from_address(LinphoneChatMessage* * @param[in] message #LinphoneChatMessage obj * @return #LinphoneAddress */ -LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_from_address(const LinphoneChatMessage* msg); +LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_from_address(LinphoneChatMessage* msg); /** * Set destination of the message @@ -119,7 +119,7 @@ LINPHONE_PUBLIC void linphone_chat_message_set_to_address(LinphoneChatMessage* m * @param[in] message #LinphoneChatMessage obj * @return #LinphoneAddress */ -LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_to_address(const LinphoneChatMessage* msg); +LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_to_address(LinphoneChatMessage* msg); /** * Get the content type of a chat message. @@ -301,7 +301,7 @@ LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_peer_address(Li *@param message #LinphoneChatMessage obj *@return #LinphoneAddress */ -LINPHONE_PUBLIC LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessage* message); +LINPHONE_PUBLIC const LinphoneAddress *linphone_chat_message_get_local_address(LinphoneChatMessage* message); /** * Add custom headers to the message. diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 3b4b78881..9fe96f8b4 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -23,11 +23,13 @@ #include "ortp/b64.h" #include "c-wrapper/c-wrapper.h" +#include "address/address.h" +#include "content/content.h" +#include "content/content-type.h" #include "chat/chat-message-p.h" #include "chat/chat-message.h" #include "chat/chat-room-p.h" #include "chat/real-time-text-chat-room-p.h" -#include "content/content-type.h" // ============================================================================= @@ -39,30 +41,9 @@ static void _linphone_chat_message_destructor (LinphoneChatMessage *msg); L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(ChatMessage, _linphone_chat_message_constructor, _linphone_chat_message_destructor, LinphoneChatMessageCbs *cbs; - LinphoneChatRoom* chat_room; + LinphoneAddress *from; // cache for shared_ptr

    + LinphoneAddress *to; // cache for shared_ptr
    LinphoneErrorInfo *ei; - LinphoneChatMessageDir dir; - char* message; - void* message_userdata; - char* appdata; - char* external_body_url; - LinphoneAddress *from; - LinphoneAddress *to; - time_t time; - SalCustomHeader *sal_custom_headers; - LinphoneChatMessageState state; - bool_t is_read; - unsigned int storage_id; - char *message_id; - SalOp *op; - LinphoneContent *file_transfer_information; //< used to store file transfer information when the message is of file transfer type - char *content_type; //< is used to specified the type of message to be sent, used only for file transfer message - bool_t to_be_stored; - belle_http_request_t *http_request; //< keep a reference to the http_request in case of file transfer in order to be able to cancel the transfer - belle_http_request_listener_t *http_listener; // our listener, only owned by us - char *file_transfer_filepath; - unsigned long bg_task_id; - bool_t is_secured; LinphoneChatMessageStateChangedCb message_state_changed_cb; void* message_state_changed_user_data; ) @@ -74,6 +55,10 @@ static void _linphone_chat_message_constructor (LinphoneChatMessage *msg) { static void _linphone_chat_message_destructor (LinphoneChatMessage *msg) { linphone_chat_message_cbs_unref(msg->cbs); msg->cbs = nullptr; + if (msg->from) + linphone_address_unref(msg->from); + if (msg->to) + linphone_address_unref(msg->to); } // ============================================================================= @@ -149,14 +134,6 @@ void linphone_chat_message_set_outgoing(LinphoneChatMessage *msg) { L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setDirection(LinphonePrivate::ChatMessage::Direction::Outgoing); } -const char * linphone_chat_message_get_content_type(const LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getContentType().c_str(); -} - -const char *linphone_chat_message_get_text(const LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getText().c_str(); -} - unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage *msg) { return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getStorageId(); } @@ -193,33 +170,136 @@ void linphone_chat_message_set_appdata(LinphoneChatMessage *msg, const char *dat L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setAppdata(data); } -// ============================================================================= - void linphone_chat_message_set_from_address(LinphoneChatMessage *msg, const LinphoneAddress *from) { - if (msg->from) - linphone_address_unref(msg->from); - msg->from = linphone_address_clone(from); + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFromAddress(make_shared(linphone_address_as_string(from))); } -const LinphoneAddress *linphone_chat_message_get_from_address(const LinphoneChatMessage *msg) { +const LinphoneAddress *linphone_chat_message_get_from_address(LinphoneChatMessage *msg) { + if (msg->from) + linphone_address_unref(msg->from); + msg->from = linphone_address_new(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFromAddress()->asString().c_str()); return msg->from; } void linphone_chat_message_set_to_address(LinphoneChatMessage *msg, const LinphoneAddress *to) { - if (msg->to) - linphone_address_unref(msg->to); - msg->to = linphone_address_clone(to); + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setToAddress(make_shared(linphone_address_as_string(to))); } -const LinphoneAddress *linphone_chat_message_get_to_address(const LinphoneChatMessage *msg) { +const LinphoneAddress *linphone_chat_message_get_to_address(LinphoneChatMessage *msg) { if (msg->to) - return msg->to; - if (msg->dir == LinphoneChatMessageOutgoing) { - return linphone_chat_room_get_peer_address(msg->chat_room); - } - return NULL; + linphone_address_unref(msg->to); + msg->to = linphone_address_new(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getToAddress()->asString().c_str()); + return msg->to; } +const char *linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFileTransferFilepath().c_str(); +} + +void linphone_chat_message_set_file_transfer_filepath(LinphoneChatMessage *msg, const char *filepath) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFileTransferFilepath(filepath); +} + +bool_t linphone_chat_message_get_to_be_stored(const LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->isToBeStored(); +} + +void linphone_chat_message_set_to_be_stored(LinphoneChatMessage *msg, bool_t to_be_stored) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setIsToBeStored(to_be_stored); +} + +belle_http_request_t * linphone_chat_message_get_http_request(LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getHttpRequest(); +} + +void linphone_chat_message_set_http_request(LinphoneChatMessage *msg, belle_http_request_t *request) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setHttpRequest(request); +} + +SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getSalOp(); +} + +void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, SalOp *op) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setSalOp(op); +} + +SalCustomHeader * linphone_chat_message_get_sal_custom_headers(const LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getSalCustomHeaders(); +} + +void linphone_chat_message_set_sal_custom_headers(LinphoneChatMessage *msg, SalCustomHeader *header) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setSalCustomHeaders(header); +} + +void linphone_chat_message_add_custom_header(LinphoneChatMessage *msg, const char *header_name, + const char *header_value) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->addSalCustomHeader(header_name, header_value); +} + +void linphone_chat_message_remove_custom_header(LinphoneChatMessage *msg, const char *header_name) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->removeSalCustomHeader(header_name); +} + +const char *linphone_chat_message_get_custom_header(LinphoneChatMessage *msg, const char *header_name) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getSalCustomHeaderValue(header_name).c_str(); +} + +// ============================================================================= +// Methods +// ============================================================================= + +int linphone_chat_room_upload_file(LinphoneChatMessage *msg) { + return ((LinphoneStatus)L_GET_CPP_PTR_FROM_C_OBJECT(msg)->uploadFile()); +} + +LinphoneStatus linphone_chat_message_download_file(LinphoneChatMessage *msg) { + return ((LinphoneStatus)L_GET_CPP_PTR_FROM_C_OBJECT(msg)->downloadFile()); +} + +void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->cancelFileTransfer(); +} + +void linphone_chat_message_resend(LinphoneChatMessage *msg) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->reSend(); +} + +void linphone_chat_message_resend_2(LinphoneChatMessage *msg) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->reSend(); +} + +void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->updateState((LinphonePrivate::ChatMessage::State) new_state); +} +void linphone_chat_message_send_imdn(LinphoneChatMessage *msg, ImdnType imdn_type, LinphoneReason reason) { + //TODO + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->sendImdn(); +} + +void linphone_chat_message_deactivate(LinphoneChatMessage *msg){ + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->cancelFileTransfer(); + // TODO ? + //msg->chat_room = NULL; +} + +void linphone_chat_message_send_delivery_notification(LinphoneChatMessage *msg, LinphoneReason reason) { + //TODO + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->sendDeliveryNotification(); +} + +void linphone_chat_message_send_display_notification(LinphoneChatMessage *msg) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->sendDisplayNotification(); +} + +LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg, uint32_t character) { + return ((LinphoneStatus)L_GET_CPP_PTR_FROM_C_OBJECT(msg)->putCharacter(character)); +} + +// ============================================================================= +// Old listener +// ============================================================================= + void linphone_chat_message_set_message_state_changed_cb(LinphoneChatMessage* msg, LinphoneChatMessageStateChangedCb cb) { msg->message_state_changed_cb = cb; } @@ -232,307 +312,69 @@ void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChat return msg->message_state_changed_user_data; } +// ============================================================================= +// Structure has changed, hard to keep the behavior +// ============================================================================= + +const char * linphone_chat_message_get_content_type(const LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getContentType().c_str(); +} + void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char *content_type) { - if (msg->content_type) { - ms_free(msg->content_type); - } - msg->content_type = content_type ? ms_strdup(content_type) : NULL; + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setContentType(content_type); +} + +const char *linphone_chat_message_get_text(const LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getText().c_str(); } int linphone_chat_message_set_text(LinphoneChatMessage *msg, const char* text) { - if (msg->message) - ms_free(msg->message); - if (text) - msg->message = ms_strdup(text); - else - msg->message = NULL; - + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setText(text); return 0; } LinphoneContent *linphone_chat_message_get_file_transfer_information(LinphoneChatMessage *msg) { - return msg->file_transfer_information; -} - -SalCustomHeader * linphone_chat_message_get_sal_custom_headers(const LinphoneChatMessage *msg) { - return msg->sal_custom_headers; -} - -void linphone_chat_message_set_sal_custom_headers(LinphoneChatMessage *msg, SalCustomHeader *header) { - msg->sal_custom_headers = header; -} - -belle_http_request_t * linphone_chat_message_get_http_request(LinphoneChatMessage *msg) { - return msg->http_request; -} - -void linphone_chat_message_set_http_request(LinphoneChatMessage *msg, belle_http_request_t *request) { - msg->http_request = request; + //return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFileTransferInformation(); + //TODO + return NULL; } void linphone_chat_message_set_file_transfer_information(LinphoneChatMessage *msg, LinphoneContent *content) { - msg->file_transfer_information = content; + //TODO + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFileTransferInformation(nullptr); } -SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg) { - return msg->op; +// ============================================================================= +// Nothing to do, they call other C API methods +// ============================================================================= + +const LinphoneAddress *linphone_chat_message_get_peer_address(LinphoneChatMessage *msg) { + return linphone_chat_room_get_peer_address(linphone_chat_message_get_chat_room(msg)); } -void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, SalOp *op) { - msg->op = op; -} - -void linphone_chat_message_set_chat_room(LinphoneChatMessage *msg, LinphoneChatRoom *room) { - msg->chat_room = room; -} - -const char *linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage *msg) { - return msg->file_transfer_filepath; +const LinphoneAddress *linphone_chat_message_get_local_address(LinphoneChatMessage *msg) { + if (L_GET_CPP_PTR_FROM_C_OBJECT(msg)->isOutgoing()) { + return linphone_chat_message_get_from_address(msg); + } + return linphone_chat_message_get_to_address(msg); } const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg) { if (!msg->ei) ((LinphoneChatMessage*)msg)->ei = linphone_error_info_new(); /*let's do it mutable*/ - linphone_error_info_from_sal_op(msg->ei, msg->op); + linphone_error_info_from_sal_op(msg->ei, linphone_chat_message_get_sal_op(msg)); return msg->ei; } LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage *msg) { return linphone_error_info_get_reason(linphone_chat_message_get_error_info(msg)); -}const LinphoneAddress *linphone_chat_message_get_peer_address(LinphoneChatMessage *msg) { - return linphone_chat_room_get_peer_address(msg->chat_room); } bool_t linphone_chat_message_is_file_transfer(const LinphoneChatMessage *msg) { - return LinphonePrivate::ContentType::isFileTransfer(msg->content_type); + return LinphonePrivate::ContentType::isFileTransfer(linphone_chat_message_get_content_type(msg)); } bool_t linphone_chat_message_is_text(const LinphoneChatMessage *msg) { - return LinphonePrivate::ContentType::isText(msg->content_type); -} - -bool_t linphone_chat_message_get_to_be_stored(const LinphoneChatMessage *msg) { - return msg->to_be_stored; -} - -void linphone_chat_message_set_to_be_stored(LinphoneChatMessage *msg, bool_t to_be_stored) { - msg->to_be_stored = to_be_stored; -} - -LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessage *msg) { - return msg->dir == LinphoneChatMessageOutgoing ? msg->from : msg->to; -} - -void linphone_chat_message_add_custom_header(LinphoneChatMessage *msg, const char *header_name, - const char *header_value) { - msg->sal_custom_headers = sal_custom_header_append(msg->sal_custom_headers, header_name, header_value); -} - -const char *linphone_chat_message_get_custom_header(LinphoneChatMessage *msg, const char *header_name) { - return sal_custom_header_find(msg->sal_custom_headers, header_name); -} - -void linphone_chat_message_remove_custom_header(LinphoneChatMessage *msg, const char *header_name) { - msg->sal_custom_headers = sal_custom_header_remove(msg->sal_custom_headers, header_name); -} - -// ============================================================================= -// ============================================================================= - -void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state) { - linphone_chat_message_set_state(msg, new_state); - linphone_chat_message_store_state(msg); - - if (msg->state == LinphoneChatMessageStateDelivered || msg->state == LinphoneChatMessageStateNotDelivered) { - L_GET_PRIVATE_FROM_C_OBJECT(msg->chat_room)->moveTransientMessageToWeakMessages(msg); - } -} - -void _linphone_chat_message_resend(LinphoneChatMessage *msg, bool_t ref_msg) { - LinphoneChatMessageState state = linphone_chat_message_get_state(msg); - LinphoneChatRoom *cr; - - if (state != LinphoneChatMessageStateNotDelivered) { - ms_warning("Cannot resend chat message in state %s", linphone_chat_message_state_to_string(state)); - return; - } - - cr = linphone_chat_message_get_chat_room(msg); - if (ref_msg) linphone_chat_message_ref(msg); - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(msg); -} - -void linphone_chat_message_resend(LinphoneChatMessage *msg) { - _linphone_chat_message_resend(msg, FALSE); -} - -void linphone_chat_message_resend_2(LinphoneChatMessage *msg) { - _linphone_chat_message_resend(msg, TRUE); -} - -static char *linphone_chat_message_create_imdn_xml(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason) { - xmlBufferPtr buf; - xmlTextWriterPtr writer; - int err; - char *content = NULL; - char *datetime = NULL; - const char *message_id; - - /* Check that the chat message has a message id */ - message_id = linphone_chat_message_get_message_id(cm); - if (message_id == NULL) return NULL; - - buf = xmlBufferCreate(); - if (buf == NULL) { - ms_error("Error creating the XML buffer"); - return content; - } - writer = xmlNewTextWriterMemory(buf, 0); - if (writer == NULL) { - ms_error("Error creating the XML writer"); - return content; - } - - datetime = linphone_timestamp_to_rfc3339_string(linphone_chat_message_get_time(cm)); - err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); - if (err >= 0) { - err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"imdn", - (const xmlChar *)"urn:ietf:params:xml:ns:imdn"); - } - if ((err >= 0) && (reason != LinphoneReasonNone)) { - err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"linphoneimdn", NULL, (const xmlChar *)"http://www.linphone.org/xsds/imdn.xsd"); - } - if (err >= 0) { - err = xmlTextWriterWriteElement(writer, (const xmlChar *)"message-id", (const xmlChar *)message_id); - } - if (err >= 0) { - err = xmlTextWriterWriteElement(writer, (const xmlChar *)"datetime", (const xmlChar *)datetime); - } - if (err >= 0) { - if (imdn_type == ImdnTypeDelivery) { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivery-notification"); - } else { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"display-notification"); - } - } - if (err >= 0) { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"status"); - } - if (err >= 0) { - if (reason == LinphoneReasonNone) { - if (imdn_type == ImdnTypeDelivery) { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivered"); - } else { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"displayed"); - } - } else { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"error"); - } - } - if (err >= 0) { - /* Close the "delivered", "displayed" or "error" element. */ - err = xmlTextWriterEndElement(writer); - } - if ((err >= 0) && (reason != LinphoneReasonNone)) { - err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"linphoneimdn", (const xmlChar *)"reason", NULL); - if (err >= 0) { - char codestr[16]; - snprintf(codestr, 16, "%d", linphone_reason_to_error_code(reason)); - err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"code", (const xmlChar *)codestr); - } - if (err >= 0) { - err = xmlTextWriterWriteString(writer, (const xmlChar *)linphone_reason_to_string(reason)); - } - if (err >= 0) { - err = xmlTextWriterEndElement(writer); - } - } - if (err >= 0) { - /* Close the "status" element. */ - err = xmlTextWriterEndElement(writer); - } - if (err >= 0) { - /* Close the "delivery-notification" or "display-notification" element. */ - err = xmlTextWriterEndElement(writer); - } - if (err >= 0) { - /* Close the "imdn" element. */ - err = xmlTextWriterEndElement(writer); - } - if (err >= 0) { - err = xmlTextWriterEndDocument(writer); - } - if (err > 0) { - /* xmlTextWriterEndDocument returns the size of the content. */ - content = ms_strdup((char *)buf->content); - } - xmlFreeTextWriter(writer); - xmlBufferFree(buf); - ms_free(datetime); - return content; -} - -void linphone_chat_message_send_imdn(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason) { - char *content = linphone_chat_message_create_imdn_xml(cm, imdn_type, reason); - if (content) { - L_GET_PRIVATE_FROM_C_OBJECT(linphone_chat_message_get_chat_room(cm))->sendImdn(content, reason); - ms_free(content); - } -} - -void linphone_chat_message_send_delivery_notification(LinphoneChatMessage *cm, LinphoneReason reason) { - LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(cm); - LinphoneCore *lc = linphone_chat_room_get_core(cr); - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); - if (linphone_im_notif_policy_get_send_imdn_delivered(policy) == TRUE) { - linphone_chat_message_send_imdn(cm, ImdnTypeDelivery, reason); - } -} - -void linphone_chat_message_send_display_notification(LinphoneChatMessage *cm) { - LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(cm); - LinphoneCore *lc = linphone_chat_room_get_core(cr); - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); - if (linphone_im_notif_policy_get_send_imdn_displayed(policy) == TRUE) { - linphone_chat_message_send_imdn(cm, ImdnTypeDisplay, LinphoneReasonNone); - } -}LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg, uint32_t character) { - LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); - if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) { - shared_ptr rttcr = - static_pointer_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); - LinphoneCall *call = rttcr->getCall(); - LinphoneCore *lc = rttcr->getCore(); - const uint32_t new_line = 0x2028; - const uint32_t crlf = 0x0D0A; - const uint32_t lf = 0x0A; - - if (!call || !linphone_call_get_stream(call, LinphoneStreamTypeText)) { - return -1; - } - - if (character == new_line || character == crlf || character == lf) { - if (lc && lp_config_get_int(lc->config, "misc", "store_rtt_messages", 1) == 1) { - ms_debug("New line sent, forge a message with content %s", msg->message); - msg->time = ms_time(0); - msg->state = LinphoneChatMessageStateDisplayed; - msg->dir = LinphoneChatMessageOutgoing; - if (msg->from) linphone_address_unref(msg->from); - msg->from = linphone_address_new(linphone_core_get_identity(lc)); - msg->storage_id = linphone_chat_message_store(msg); - ms_free(msg->message); - msg->message = NULL; - } - } else { - char *value = LinphonePrivate::Utils::utf8ToChar(character); - msg->message = ms_strcat_printf(msg->message, value); - ms_debug("Sent RTT character: %s (%lu), pending text is %s", value, (unsigned long)character, msg->message); - delete value; - } - - text_stream_putchar32(reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeText)), character); - return 0; - } - return -1; + return LinphonePrivate::ContentType::isText(linphone_chat_message_get_content_type(msg)); } const char *linphone_chat_message_state_to_string(const LinphoneChatMessageState state) { @@ -557,618 +399,6 @@ const char *linphone_chat_message_state_to_string(const LinphoneChatMessageState return NULL; } -LinphoneChatMessage *linphone_chat_message_clone(const LinphoneChatMessage *msg) { - LinphoneChatMessage *new_message = linphone_chat_room_create_message(msg->chat_room, msg->message); - if (msg->external_body_url) - new_message->external_body_url = ms_strdup(msg->external_body_url); - if (msg->appdata) - new_message->appdata = ms_strdup(msg->appdata); - new_message->message_state_changed_cb = msg->message_state_changed_cb; - new_message->message_state_changed_user_data = msg->message_state_changed_user_data; - new_message->message_userdata = msg->message_userdata; - new_message->time = msg->time; - new_message->state = msg->state; - new_message->storage_id = msg->storage_id; - if (msg->from) - new_message->from = linphone_address_clone(msg->from); - if (msg->file_transfer_filepath) - new_message->file_transfer_filepath = ms_strdup(msg->file_transfer_filepath); - if (msg->file_transfer_information) - new_message->file_transfer_information = linphone_content_copy(msg->file_transfer_information); - return new_message; -} - -void linphone_chat_message_deactivate(LinphoneChatMessage *msg){ - if (msg->file_transfer_information != NULL) { - _linphone_chat_message_cancel_file_transfer(msg, FALSE); - } - /*mark the chat msg as orphan (it has no chat room anymore)*/ - msg->chat_room = NULL; -} - -void linphone_chat_message_release(LinphoneChatMessage *msg) { - linphone_chat_message_deactivate(msg); - linphone_chat_message_unref(msg); -} - -static bool_t file_transfer_in_progress_and_valid(LinphoneChatMessage* msg) { - return (linphone_chat_message_get_chat_room(msg) && - linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)) && - linphone_chat_message_get_http_request(msg) && - !belle_http_request_is_cancelled(linphone_chat_message_get_http_request(msg))); -} - -static void _release_http_request(LinphoneChatMessage* msg) { - if (linphone_chat_message_get_http_request(msg)) { - belle_sip_object_unref(msg->http_request); - msg->http_request = NULL; - if (msg->http_listener){ - belle_sip_object_unref(msg->http_listener); - msg->http_listener = NULL; - // unhold the reference that the listener was holding on the message - linphone_chat_message_unref(msg); - } - } -} - -static void linphone_chat_message_process_io_error_upload(void *data, const belle_sip_io_error_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - ms_error("I/O Error during file upload of msg [%p]", msg); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); - _release_http_request(msg); - linphone_chat_room_remove_transient_message(msg->chat_room, msg); - linphone_chat_message_unref(msg); -} - -static void linphone_chat_message_process_auth_requested_upload(void *data, belle_sip_auth_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - ms_error("Error during file upload: auth requested for msg [%p]", msg); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); - _release_http_request(msg); - linphone_chat_room_remove_transient_message(msg->chat_room, msg); - linphone_chat_message_unref(msg); -} - -static void linphone_chat_message_process_io_error_download(void *data, const belle_sip_io_error_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - ms_error("I/O Error during file download msg [%p]", msg); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateFileTransferError); - _release_http_request(msg); -} - -static void linphone_chat_message_process_auth_requested_download(void *data, belle_sip_auth_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - ms_error("Error during file download : auth requested for msg [%p]", msg); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateFileTransferError); - _release_http_request(msg); -} - -static void linphone_chat_message_file_transfer_on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *m, - void *data, size_t offset, size_t total) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - if (!file_transfer_in_progress_and_valid(msg)) { - ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); - _release_http_request(msg); - return; - } - if (linphone_chat_message_cbs_get_file_transfer_progress_indication(msg->cbs)) { - linphone_chat_message_cbs_get_file_transfer_progress_indication(msg->cbs)( - msg, msg->file_transfer_information, offset, total); - } else { - /* Legacy: call back given by application level */ - linphone_core_notify_file_transfer_progress_indication(linphone_chat_room_get_core(msg->chat_room), msg, msg->file_transfer_information, - offset, total); - } -} - -static int on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, - void *data, size_t offset, uint8_t *buffer, size_t *size) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - LinphoneCore *lc = NULL; - LinphoneImEncryptionEngine *imee = NULL; - int retval = -1; - - if (!file_transfer_in_progress_and_valid(msg)) { - if (msg->http_request) { - ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); - _release_http_request(msg); - } - return BELLE_SIP_STOP; - } - - lc = linphone_chat_room_get_core(msg->chat_room); - /* if we've not reach the end of file yet, ask for more data */ - /* in case of file body handler, won't be called */ - if (msg->file_transfer_filepath == NULL && offset < linphone_content_get_size(msg->file_transfer_information)) { - /* get data from call back */ - LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = linphone_chat_message_cbs_get_file_transfer_send(msg->cbs); - if (file_transfer_send_cb) { - LinphoneBuffer *lb = file_transfer_send_cb(msg, msg->file_transfer_information, offset, *size); - if (lb == NULL) { - *size = 0; - } else { - *size = linphone_buffer_get_size(lb); - memcpy(buffer, linphone_buffer_get_content(lb), *size); - linphone_buffer_unref(lb); - } - } else { - /* Legacy */ - linphone_core_notify_file_transfer_send(lc, msg, msg->file_transfer_information, (char *)buffer, size); - } - } - - imee = linphone_core_get_im_encryption_engine(lc); - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); - if (cb_process_uploading_file) { - size_t max_size = *size; - uint8_t *encrypted_buffer = (uint8_t *)ms_malloc0(max_size); - retval = cb_process_uploading_file(imee, msg, offset, (const uint8_t *)buffer, size, encrypted_buffer); - if (retval == 0) { - if (*size > max_size) { - ms_error("IM encryption engine process upload file callback returned a size bigger than the size of the buffer, so it will be truncated !"); - *size = max_size; - } - memcpy(buffer, encrypted_buffer, *size); - } - ms_free(encrypted_buffer); - } - } - - return retval <= 0 ? BELLE_SIP_CONTINUE : BELLE_SIP_STOP; -} - -static void on_send_end(belle_sip_user_body_handler_t *bh, void *data) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room); - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); - - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); - if (cb_process_uploading_file) { - cb_process_uploading_file(imee, msg, 0, NULL, NULL, NULL); - } - } -} - -static void file_upload_end_background_task(LinphoneChatMessage *obj){ - if (obj->bg_task_id){ - ms_message("channel [%p]: ending file upload background task with id=[%lx].",obj,obj->bg_task_id); - sal_end_background_task(obj->bg_task_id); - obj->bg_task_id=0; - } -} - -static void file_upload_background_task_ended(LinphoneChatMessage *obj){ - ms_warning("channel [%p]: file upload background task has to be ended now, but work isn't finished.",obj); - file_upload_end_background_task(obj); -} - -static void file_upload_begin_background_task(LinphoneChatMessage *obj){ - if (obj->bg_task_id==0){ - obj->bg_task_id=sal_begin_background_task("file transfer upload",(void (*)(void*))file_upload_background_task_ended, obj); - if (obj->bg_task_id) ms_message("channel [%p]: starting file upload background task with id=[%lx].",obj,obj->bg_task_id); - } -} - -static void linphone_chat_message_process_response_from_post_file(void *data, const belle_http_response_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - - if (msg->http_request && !file_transfer_in_progress_and_valid(msg)) { - ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); - _release_http_request(msg); - return; - } - - /* check the answer code */ - if (event->response) { - int code = belle_http_response_get_status_code(event->response); - if (code == 204) { /* this is the reply to the first post to the server - an empty msg */ - /* start uploading the file */ - belle_sip_multipart_body_handler_t *bh; - char *first_part_header; - belle_sip_body_handler_t *first_part_bh; - - bool_t is_file_encryption_enabled = FALSE; - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(linphone_chat_room_get_core(msg->chat_room)); - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer_cb = - linphone_im_encryption_engine_cbs_get_is_encryption_enabled_for_file_transfer(imee_cbs); - if (is_encryption_enabled_for_file_transfer_cb) { - is_file_encryption_enabled = is_encryption_enabled_for_file_transfer_cb(imee, msg->chat_room); - } - } - /* shall we encrypt the file */ - if (is_file_encryption_enabled) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb generate_file_transfer_key_cb = - linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(imee_cbs); - if (generate_file_transfer_key_cb) { - generate_file_transfer_key_cb(imee, msg->chat_room, msg); - } - /* temporary storage for the Content-disposition header value : use a generic filename to not leak it - * Actual filename stored in msg->file_transfer_information->name will be set in encrypted msg - * sended to the */ - first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"filename.txt\""); - } else { - /* temporary storage for the Content-disposition header value */ - first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"%s\"", - linphone_content_get_name(msg->file_transfer_information)); - } - - /* create a user body handler to take care of the file and add the content disposition and content-type - * headers */ - first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new( - linphone_content_get_size(msg->file_transfer_information), - linphone_chat_message_file_transfer_on_progress, NULL, NULL, - on_send_body, on_send_end, msg); - if (msg->file_transfer_filepath != NULL) { - belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh; - first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(msg->file_transfer_filepath, - NULL, msg); // No need to add again the callback for progression, otherwise it will be called twice - linphone_content_set_size(msg->file_transfer_information, belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh)); - belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)first_part_bh, body_handler); - } else if (linphone_content_get_buffer(msg->file_transfer_information) != NULL) { - first_part_bh = (belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer( - linphone_content_get_buffer(msg->file_transfer_information), - linphone_content_get_size(msg->file_transfer_information), linphone_chat_message_file_transfer_on_progress, msg); - } - - belle_sip_body_handler_add_header(first_part_bh, - belle_sip_header_create("Content-disposition", first_part_header)); - belle_sip_free(first_part_header); - belle_sip_body_handler_add_header(first_part_bh, - (belle_sip_header_t *)belle_sip_header_content_type_create( - linphone_content_get_type(msg->file_transfer_information), - linphone_content_get_subtype(msg->file_transfer_information))); - - /* insert it in a multipart body handler which will manage the boundaries of multipart msg */ - bh = belle_sip_multipart_body_handler_new(linphone_chat_message_file_transfer_on_progress, msg, first_part_bh, NULL); - - linphone_chat_message_ref(msg); - _release_http_request(msg); - file_upload_begin_background_task(msg); - linphone_chat_room_upload_file(msg); - belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(msg->http_request), BELLE_SIP_BODY_HANDLER(bh)); - linphone_chat_message_unref(msg); - } else if (code == 200) { /* file has been uploaded correctly, get server reply and send it */ - const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); - if (body && strlen(body) > 0) { - /* if we have an encryption key for the file, we must insert it into the msg and restore the correct - * filename */ - const char *content_key = linphone_content_get_key(msg->file_transfer_information); - size_t content_key_size = linphone_content_get_key_size(msg->file_transfer_information); - if (content_key != NULL) { - /* parse the msg body */ - xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body); - - xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody); - if (cur != NULL) { - cur = cur->xmlChildrenNode; - while (cur != NULL) { - if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { /* we found a file info node, check - it has a type="file" attribute */ - xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); - if (!xmlStrcmp(typeAttribute, - (const xmlChar *)"file")) { /* this is the node we are looking for : add a - file-key children node */ - xmlNodePtr fileInfoNodeChildren = - cur - ->xmlChildrenNode; /* need to parse the children node to update the file-name - one */ - /* convert key to base64 */ - size_t b64Size = b64::b64_encode(NULL, content_key_size, NULL, 0); - char *keyb64 = (char *)ms_malloc0(b64Size + 1); - int xmlStringLength; - - b64Size = b64::b64_encode(content_key, content_key_size, keyb64, b64Size); - keyb64[b64Size] = '\0'; /* libxml need a null terminated string */ - - /* add the node containing the key to the file-info node */ - xmlNewTextChild(cur, NULL, (const xmlChar *)"file-key", (const xmlChar *)keyb64); - xmlFree(typeAttribute); - ms_free(keyb64); - - /* look for the file-name node and update its content */ - while (fileInfoNodeChildren != NULL) { - if (!xmlStrcmp( - fileInfoNodeChildren->name, - (const xmlChar *)"file-name")) { /* we found a the file-name node, update - its content with the real filename */ - /* update node content */ - xmlNodeSetContent(fileInfoNodeChildren, - (const xmlChar *)(linphone_content_get_name( - msg->file_transfer_information))); - break; - } - fileInfoNodeChildren = fileInfoNodeChildren->next; - } - - /* dump the xml into msg->message */ - xmlDocDumpFormatMemoryEnc(xmlMessageBody, (xmlChar **)&msg->message, &xmlStringLength, - "UTF-8", 0); - - break; - } - xmlFree(typeAttribute); - } - cur = cur->next; - } - } - xmlFreeDoc(xmlMessageBody); - } else { /* no encryption key, transfer in plain, just copy the msg sent by server */ - msg->message = ms_strdup(body); - } - linphone_chat_message_set_content_type(msg, "application/vnd.gsma.rcs-ft-http+xml"); - linphone_chat_message_ref(msg); - linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone); - _release_http_request(msg); - L_GET_CPP_PTR_FROM_C_OBJECT(msg->chat_room)->sendMessage(msg); - file_upload_end_background_task(msg); - linphone_chat_message_unref(msg); - } else { - ms_warning("Received empty response from server, file transfer failed"); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); - _release_http_request(msg); - file_upload_end_background_task(msg); - linphone_chat_message_unref(msg); - } - } else { - ms_warning("Unhandled HTTP code response %d for file transfer", code); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); - _release_http_request(msg); - file_upload_end_background_task(msg); - linphone_chat_message_unref(msg); - } - } -} - -static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset, uint8_t *buffer, size_t size) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - LinphoneCore *lc = NULL; - LinphoneImEncryptionEngine *imee = NULL; - int retval = -1; - uint8_t *decrypted_buffer = NULL; - - if (!msg->chat_room) { - linphone_chat_message_cancel_file_transfer(msg); - return; - } - lc = linphone_chat_room_get_core(msg->chat_room); - - if (lc == NULL){ - return; /*might happen during linphone_core_destroy()*/ - } - - if (!msg->http_request || belle_http_request_is_cancelled(msg->http_request)) { - ms_warning("Cancelled request for msg [%p], ignoring %s", msg, __FUNCTION__); - return; - } - - /* first call may be with a zero size, ignore it */ - if (size == 0) { - return; - } - - decrypted_buffer = (uint8_t *)ms_malloc0(size); - imee = linphone_core_get_im_encryption_engine(lc); - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); - if (cb_process_downloading_file) { - retval = cb_process_downloading_file(imee, msg, offset, (const uint8_t *)buffer, size, decrypted_buffer); - if (retval == 0) { - memcpy(buffer, decrypted_buffer, size); - } - } - } - ms_free(decrypted_buffer); - - if (retval <= 0) { - if (msg->file_transfer_filepath == NULL) { - if (linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)) { - LinphoneBuffer *lb = linphone_buffer_new_from_data(buffer, size); - linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)(msg, msg->file_transfer_information, lb); - linphone_buffer_unref(lb); - } else { - /* Legacy: call back given by application level */ - linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, (const char *)buffer, size); - } - } - } else { - ms_warning("File transfer decrypt failed with code %d", (int)retval); - linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferError); - } - - return; -} - -static void on_recv_end(belle_sip_user_body_handler_t *bh, void *data) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room); - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); - int retval = -1; - - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); - if (cb_process_downloading_file) { - retval = cb_process_downloading_file(imee, msg, 0, NULL, 0, NULL); - } - } - - if (retval <= 0) { - if (msg->file_transfer_filepath == NULL) { - if (linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)) { - LinphoneBuffer *lb = linphone_buffer_new(); - linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)(msg, msg->file_transfer_information, lb); - linphone_buffer_unref(lb); - } else { - /* Legacy: call back given by application level */ - linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, NULL, 0); - } - } - } - - if (retval <= 0 && linphone_chat_message_get_state(msg) != LinphoneChatMessageStateFileTransferError) { - linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone); - } -} - -static LinphoneContent *linphone_chat_create_file_transfer_information_from_headers(const belle_sip_message_t *m) { - LinphoneContent *content = linphone_content_new(); - - belle_sip_header_content_length_t *content_length_hdr = - BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(m, "Content-Length")); - belle_sip_header_content_type_t *content_type_hdr = - BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(m, "Content-Type")); - const char *type = NULL, *subtype = NULL; - - linphone_content_set_name(content, ""); - - if (content_type_hdr) { - type = belle_sip_header_content_type_get_type(content_type_hdr); - subtype = belle_sip_header_content_type_get_subtype(content_type_hdr); - ms_message("Extracted content type %s / %s from header", type ? type : "", subtype ? subtype : ""); - if (type) - linphone_content_set_type(content, type); - if (subtype) - linphone_content_set_subtype(content, subtype); - } - - if (content_length_hdr) { - linphone_content_set_size(content, belle_sip_header_content_length_get_content_length(content_length_hdr)); - ms_message("Extracted content length %i from header", (int)linphone_content_get_size(content)); - } - - return content; -} - -static void linphone_chat_process_response_headers_from_get_file(void *data, const belle_http_response_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - if (event->response) { - /*we are receiving a response, set a specific body handler to acquire the response. - * if not done, belle-sip will create a memory body handler, the default*/ - belle_sip_message_t *response = BELLE_SIP_MESSAGE(event->response); - belle_sip_body_handler_t *body_handler = NULL; - size_t body_size = 0; - - if (msg->file_transfer_information == NULL) { - ms_warning("No file transfer information for msg %p: creating...", msg); - msg->file_transfer_information = linphone_chat_create_file_transfer_information_from_headers(response); - } - - if (msg->file_transfer_information) { - body_size = linphone_content_get_size(msg->file_transfer_information); - } - - - body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, linphone_chat_message_file_transfer_on_progress, NULL, on_recv_body, NULL, on_recv_end, msg); - if (msg->file_transfer_filepath != NULL) { - belle_sip_user_body_handler_t *bh = (belle_sip_user_body_handler_t *)body_handler; - body_handler = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new( - msg->file_transfer_filepath, linphone_chat_message_file_transfer_on_progress, msg); - if (belle_sip_body_handler_get_size((belle_sip_body_handler_t *)body_handler) == 0) { - /* If the size of the body has not been initialized from the file stat, use the one from the - * file_transfer_information. */ - belle_sip_body_handler_set_size((belle_sip_body_handler_t *)body_handler, body_size); - } - belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)body_handler, bh); - } - belle_sip_message_set_body_handler((belle_sip_message_t *)event->response, body_handler); - } -} - -static void linphone_chat_process_response_from_get_file(void *data, const belle_http_response_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - /* check the answer code */ - if (event->response) { - int code = belle_http_response_get_status_code(event->response); - if (code >= 400 && code < 500) { - ms_warning("File transfer failed with code %d", code); - linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferError); - } else if (code != 200) { - ms_warning("Unhandled HTTP code response %d for file transfer", code); - } - _release_http_request(msg); - } -} - -int _linphone_chat_room_start_http_transfer(LinphoneChatMessage *msg, const char* url, const char* action, const belle_http_request_listener_callbacks_t *cbs) { - belle_generic_uri_t *uri = NULL; - const char* ua = linphone_core_get_user_agent(linphone_chat_room_get_core(msg->chat_room)); - - if (url == NULL) { - ms_warning("Cannot process file transfer msg: no file remote URI configured."); - goto error; - } - uri = belle_generic_uri_parse(url); - if (uri == NULL || belle_generic_uri_get_host(uri)==NULL) { - ms_warning("Cannot process file transfer msg: incorrect file remote URI configured '%s'.", url); - goto error; - } - - msg->http_request = belle_http_request_create(action, uri, belle_sip_header_create("User-Agent", ua), NULL); - - if (msg->http_request == NULL) { - ms_warning("Could not create http request for uri %s", url); - goto error; - } - /* keep a reference to the http request to be able to cancel it during upload */ - belle_sip_object_ref(msg->http_request); - - /* give msg to listener to be able to start the actual file upload when server answer a 204 No content */ - msg->http_listener = belle_http_request_listener_create_from_callbacks(cbs, linphone_chat_message_ref(msg)); - belle_http_provider_send_request(linphone_chat_room_get_core(msg->chat_room)->http_provider, msg->http_request, msg->http_listener); - return 0; -error: - if (uri) { - belle_sip_object_unref(uri); - } - return -1; -} - -int linphone_chat_room_upload_file(LinphoneChatMessage *msg) { - belle_http_request_listener_callbacks_t cbs = {0}; - int err; - - if (msg->http_request){ - ms_error("linphone_chat_room_upload_file(): there is already an upload in progress."); - return -1; - } - - cbs.process_response = linphone_chat_message_process_response_from_post_file; - cbs.process_io_error = linphone_chat_message_process_io_error_upload; - cbs.process_auth_requested = linphone_chat_message_process_auth_requested_upload; - err = _linphone_chat_room_start_http_transfer(msg, linphone_core_get_file_transfer_server(linphone_chat_room_get_core(msg->chat_room)), "POST", &cbs); - if (err == -1){ - linphone_chat_message_set_state(msg, LinphoneChatMessageStateNotDelivered); - } - return err; -} - -LinphoneStatus linphone_chat_message_download_file(LinphoneChatMessage *msg) { - belle_http_request_listener_callbacks_t cbs = {0}; - int err; - - if (msg->http_request){ - ms_error("linphone_chat_message_download_file(): there is already a download in progress"); - return -1; - } - cbs.process_response_headers = linphone_chat_process_response_headers_from_get_file; - cbs.process_response = linphone_chat_process_response_from_get_file; - cbs.process_io_error = linphone_chat_message_process_io_error_download; - cbs.process_auth_requested = linphone_chat_message_process_auth_requested_download; - err = _linphone_chat_room_start_http_transfer(msg, msg->external_body_url, "GET", &cbs); - if (err == -1) return -1; - /* start the download, status is In Progress */ - linphone_chat_message_set_state(msg, LinphoneChatMessageStateInProgress); - return 0; -} - void linphone_chat_message_start_file_download(LinphoneChatMessage *msg, LinphoneChatMessageStateChangedCb status_cb, void *ud) { msg->message_state_changed_cb = status_cb; @@ -1176,39 +406,7 @@ void linphone_chat_message_start_file_download(LinphoneChatMessage *msg, linphone_chat_message_download_file(msg); } -void _linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg, bool_t unref) { - if (msg->http_request) { - if (msg->state == LinphoneChatMessageStateInProgress) { - linphone_chat_message_set_state(msg, LinphoneChatMessageStateNotDelivered); - } - if (!belle_http_request_is_cancelled(msg->http_request)) { - if (msg->chat_room) { - ms_message("Canceling file transfer %s - msg [%p] chat room[%p]" - , (msg->external_body_url == NULL) ? linphone_core_get_file_transfer_server(linphone_chat_room_get_core(msg->chat_room)) : msg->external_body_url - , msg - , msg->chat_room); - belle_http_provider_cancel_request(linphone_chat_room_get_core(msg->chat_room)->http_provider, msg->http_request); - if ((msg->dir == LinphoneChatMessageOutgoing) && unref) { - // must release it - linphone_chat_message_unref(msg); - } - } else { - ms_message("Warning: http request still running for ORPHAN msg [%p]: this is a memory leak", msg); - } - } - _release_http_request(msg); - } else { - ms_message("No existing file transfer - nothing to cancel"); - } -} - -void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg) { - _linphone_chat_message_cancel_file_transfer(msg, TRUE); -} - -void linphone_chat_message_set_file_transfer_filepath(LinphoneChatMessage *msg, const char *filepath) { - if (msg->file_transfer_filepath != NULL) { - ms_free(msg->file_transfer_filepath); - } - msg->file_transfer_filepath = ms_strdup(filepath); -} +void linphone_chat_message_release(LinphoneChatMessage *msg) { + linphone_chat_message_deactivate(msg); + linphone_chat_message_unref(msg); +} \ No newline at end of file diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 0145f1187..2b756812f 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -41,18 +41,23 @@ private: ChatMessage::Direction direction = ChatMessage::Incoming; ChatMessage::State state = ChatMessage::Idle; unsigned int storageId; - // LinphoneAddress *from; - // LinphoneAddress *to; + std::shared_ptr
    from; + std::shared_ptr
    to; time_t time = 0; std::string id; std::string appData; + std::string fileTransferFilePath; bool isSecured = false; bool isReadOnly = false; + bool isToBeStored = false; std::list > contents; std::shared_ptr internalContent; std::unordered_map customHeaders; std::shared_ptr eventsDb; std::shared_ptr errorInfo; + belle_http_request_t *httpRequest; + SalOp *salOp; + SalCustomHeader *salCustomHeaders; L_DECLARE_PUBLIC(ChatMessage); }; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index c73be1e5f..2c5f07e50 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -19,7 +19,6 @@ #include "db/events-db.h" #include "object/object-p.h" -#include "linphone/types.h" #include "linphone/core.h" #include "linphone/lpconfig.h" #include "c-wrapper/c-wrapper.h" @@ -151,14 +150,67 @@ void ChatMessage::setId (string id) { } bool ChatMessage::isRead() const { - //L_D(const ChatMessage); return false; - /*shared_ptr policy =d->chatRoom->core->getImNotifPolicy(); + /* TODO + L_D(const ChatMessage); + shared_ptr policy =d->chatRoom->core->getImNotifPolicy(); if (policy->getRecvImdnDisplayed() && d->state == Displayed) return true; if (policy->getRecvImdnDelivered() && (d->state == DeliveredToUser || d->state == Displayed)) return true; return d->state == Delivered || d->state == Displayed || d->state == DeliveredToUser;*/ } +string ChatMessage::getAppdata () const { + L_D(const ChatMessage); + return d->appData; +} + +void ChatMessage::setAppdata (const string &appData) { + L_D(ChatMessage); + d->appData = appData; + // TODO: store app data in db ! + // linphone_chat_message_store_appdata(msg); +} + +shared_ptr
    ChatMessage::getFromAddress () const { + L_D(const ChatMessage); + return d->from; +} + +void ChatMessage::setFromAddress(shared_ptr
    from) { + L_D(ChatMessage); + d->from = from; +} + +shared_ptr
    ChatMessage::getToAddress () const { + L_D(const ChatMessage); + return d->to; +} + +void ChatMessage::setToAddress(shared_ptr
    to) { + L_D(ChatMessage); + d->to = to; +} + +string ChatMessage::getFileTransferFilepath() const { + L_D(const ChatMessage); + return d->fileTransferFilePath; +} + +void ChatMessage::setFileTransferFilepath(const string &path) { + L_D(ChatMessage); + d->fileTransferFilePath = path; +} + +bool ChatMessage::isToBeStored() const { + L_D(const ChatMessage); + return d->isToBeStored; +} + +void ChatMessage::setIsToBeStored(bool store) { + L_D(ChatMessage); + d->isToBeStored = store; +} + // ----------------------------------------------------------------------------- string ChatMessage::getContentType() const { @@ -172,6 +224,10 @@ string ChatMessage::getContentType() const { return ""; } +void ChatMessage::setContentType(string contentType) { + //TODO +} + string ChatMessage::getText() const { L_D(const ChatMessage); if (d->internalContent) { @@ -183,6 +239,19 @@ string ChatMessage::getText() const { return ""; } +void ChatMessage::setText(string text) { + //TODO +} + +shared_ptr ChatMessage::getFileTransferInformation() const { + //TODO + return nullptr; +} + +void ChatMessage::setFileTransferInformation(shared_ptr content) { + //TODO +} + unsigned int ChatMessage::getStorageId() const { L_D(const ChatMessage); return d->storageId; @@ -193,45 +262,868 @@ void ChatMessage::setStorageId(unsigned int id) { d->storageId = id; } -string ChatMessage::getAppdata () const { +belle_http_request_t *ChatMessage::getHttpRequest() const { L_D(const ChatMessage); - return d->appData; + return d->httpRequest; } -void ChatMessage::setAppdata (const string &appData) { +void ChatMessage::setHttpRequest(belle_http_request_t *request) { L_D(ChatMessage); - d->appData = appData; - // TODO: store app data in db ! - // linphone_chat_message_store_appdata(msg); + d->httpRequest = request; } -// ----------------------------------------------------------------------------- - -shared_ptr ChatMessage::getFromAddress () const { - // TODO. - return nullptr; +SalOp *ChatMessage::getSalOp() const { + L_D(const ChatMessage); + return d->salOp; } -shared_ptr ChatMessage::getToAddress () const { - // TODO. - return nullptr; +void ChatMessage::setSalOp(SalOp *op) { + L_D(ChatMessage); + d->salOp = op; } -shared_ptr ChatMessage::getLocalAddress () const { - // TODO. - return nullptr; +SalCustomHeader *ChatMessage::getSalCustomHeaders() const { + L_D(const ChatMessage); + return d->salCustomHeaders; } -shared_ptr ChatMessage::getRemoteAddress () const { - // TODO. - return nullptr; +void ChatMessage::setSalCustomHeaders(SalCustomHeader *headers) { + L_D(ChatMessage); + d->salCustomHeaders = headers; +} + +void ChatMessage::addSalCustomHeader(string name, string value) { + L_D(ChatMessage); + d->salCustomHeaders = sal_custom_header_append(d->salCustomHeaders, name.c_str(), value.c_str()); +} + +void ChatMessage::removeSalCustomHeader(string name) { + L_D(ChatMessage); + d->salCustomHeaders = sal_custom_header_remove(d->salCustomHeaders, name.c_str()); +} + +string ChatMessage::getSalCustomHeaderValue(string name) { + L_D(ChatMessage); + return sal_custom_header_find(d->salCustomHeaders, name.c_str()); } shared_ptr ChatMessage::getErrorInfo () const { L_D(const ChatMessage); + //TODO return d->errorInfo; } +// ----------------------------------------------------------------------------- + +void ChatMessage::updateState(State state) { + //TODO + /*linphone_chat_message_set_state(msg, new_state); + linphone_chat_message_store_state(msg); + + if (msg->state == LinphoneChatMessageStateDelivered || msg->state == LinphoneChatMessageStateNotDelivered) { + L_GET_PRIVATE_FROM_C_OBJECT(msg->chat_room)->moveTransientMessageToWeakMessages(msg); + }*/ +} + +void ChatMessage::reSend() { + //TODO + /*LinphoneChatMessageState state = linphone_chat_message_get_state(msg); + LinphoneChatRoom *cr; + + if (state != LinphoneChatMessageStateNotDelivered) { + ms_warning("Cannot resend chat message in state %s", linphone_chat_message_state_to_string(state)); + return; + } + + cr = linphone_chat_message_get_chat_room(msg); + if (ref_msg) linphone_chat_message_ref(msg); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(msg);*/ +} + +/*static void linphone_chat_message_process_io_error_upload(void *data, const belle_sip_io_error_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + ms_error("I/O Error during file upload of msg [%p]", msg); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); + _release_http_request(msg); + linphone_chat_room_remove_transient_message(msg->chat_room, msg); + linphone_chat_message_unref(msg); +} + +static void linphone_chat_message_process_auth_requested_upload(void *data, belle_sip_auth_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + ms_error("Error during file upload: auth requested for msg [%p]", msg); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); + _release_http_request(msg); + linphone_chat_room_remove_transient_message(msg->chat_room, msg); + linphone_chat_message_unref(msg); +} + +static void linphone_chat_message_process_io_error_download(void *data, const belle_sip_io_error_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + ms_error("I/O Error during file download msg [%p]", msg); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateFileTransferError); + _release_http_request(msg); +} + +static void linphone_chat_process_response_from_get_file(void *data, const belle_http_response_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + // check the answer code + if (event->response) { + int code = belle_http_response_get_status_code(event->response); + if (code >= 400 && code < 500) { + ms_warning("File transfer failed with code %d", code); + linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferError); + } else if (code != 200) { + ms_warning("Unhandled HTTP code response %d for file transfer", code); + } + _release_http_request(msg); + } +}*/ + +/*static char *linphone_chat_message_create_imdn_xml(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason) { + xmlBufferPtr buf; + xmlTextWriterPtr writer; + int err; + char *content = NULL; + char *datetime = NULL; + const char *message_id; + + // Check that the chat message has a message id + message_id = linphone_chat_message_get_message_id(cm); + if (message_id == NULL) return NULL; + + buf = xmlBufferCreate(); + if (buf == NULL) { + ms_error("Error creating the XML buffer"); + return content; + } + writer = xmlNewTextWriterMemory(buf, 0); + if (writer == NULL) { + ms_error("Error creating the XML writer"); + return content; + } + + datetime = linphone_timestamp_to_rfc3339_string(linphone_chat_message_get_time(cm)); + err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); + if (err >= 0) { + err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"imdn", + (const xmlChar *)"urn:ietf:params:xml:ns:imdn"); + } + if ((err >= 0) && (reason != LinphoneReasonNone)) { + err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"linphoneimdn", NULL, (const xmlChar *)"http://www.linphone.org/xsds/imdn.xsd"); + } + if (err >= 0) { + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"message-id", (const xmlChar *)message_id); + } + if (err >= 0) { + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"datetime", (const xmlChar *)datetime); + } + if (err >= 0) { + if (imdn_type == ImdnTypeDelivery) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivery-notification"); + } else { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"display-notification"); + } + } + if (err >= 0) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"status"); + } + if (err >= 0) { + if (reason == LinphoneReasonNone) { + if (imdn_type == ImdnTypeDelivery) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivered"); + } else { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"displayed"); + } + } else { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"error"); + } + } + if (err >= 0) { + // Close the "delivered", "displayed" or "error" element. + err = xmlTextWriterEndElement(writer); + } + if ((err >= 0) && (reason != LinphoneReasonNone)) { + err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"linphoneimdn", (const xmlChar *)"reason", NULL); + if (err >= 0) { + char codestr[16]; + snprintf(codestr, 16, "%d", linphone_reason_to_error_code(reason)); + err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"code", (const xmlChar *)codestr); + } + if (err >= 0) { + err = xmlTextWriterWriteString(writer, (const xmlChar *)linphone_reason_to_string(reason)); + } + if (err >= 0) { + err = xmlTextWriterEndElement(writer); + } + } + if (err >= 0) { + // Close the "status" element. + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + // Close the "delivery-notification" or "display-notification" element. + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + // Close the "imdn" element. + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + err = xmlTextWriterEndDocument(writer); + } + if (err > 0) { + // xmlTextWriterEndDocument returns the size of the content. + content = ms_strdup((char *)buf->content); + } + xmlFreeTextWriter(writer); + xmlBufferFree(buf); + ms_free(datetime); + return content; +}*/ + +void ChatMessage::sendImdn() { + //TODO + /*char *content = linphone_chat_message_create_imdn_xml(cm, imdn_type, reason); + if (content) { + L_GET_PRIVATE_FROM_C_OBJECT(linphone_chat_message_get_chat_room(cm))->sendImdn(content, reason); + ms_free(content); + }*/ +} + +void ChatMessage::sendDeliveryNotification() { + //TODO + /*LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(cm); + LinphoneCore *lc = linphone_chat_room_get_core(cr); + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); + if (linphone_im_notif_policy_get_send_imdn_delivered(policy) == TRUE) { + linphone_chat_message_send_imdn(cm, ImdnTypeDelivery, reason); + }*/ +} + +void ChatMessage::sendDisplayNotification() { + //TODO + /*LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(cm); + LinphoneCore *lc = linphone_chat_room_get_core(cr); + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); + if (linphone_im_notif_policy_get_send_imdn_displayed(policy) == TRUE) { + linphone_chat_message_send_imdn(cm, ImdnTypeDisplay, LinphoneReasonNone); + }*/ +} + +/* +static LinphoneContent *linphone_chat_create_file_transfer_information_from_headers(const belle_sip_message_t *m) { + LinphoneContent *content = linphone_content_new(); + + belle_sip_header_content_length_t *content_length_hdr = + BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(m, "Content-Length")); + belle_sip_header_content_type_t *content_type_hdr = + BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(m, "Content-Type")); + const char *type = NULL, *subtype = NULL; + + linphone_content_set_name(content, ""); + + if (content_type_hdr) { + type = belle_sip_header_content_type_get_type(content_type_hdr); + subtype = belle_sip_header_content_type_get_subtype(content_type_hdr); + ms_message("Extracted content type %s / %s from header", type ? type : "", subtype ? subtype : ""); + if (type) + linphone_content_set_type(content, type); + if (subtype) + linphone_content_set_subtype(content, subtype); + } + + if (content_length_hdr) { + linphone_content_set_size(content, belle_sip_header_content_length_get_content_length(content_length_hdr)); + ms_message("Extracted content length %i from header", (int)linphone_content_get_size(content)); + } + + return content; +} + +static void linphone_chat_process_response_headers_from_get_file(void *data, const belle_http_response_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + if (event->response) { + //we are receiving a response, set a specific body handler to acquire the response. + // if not done, belle-sip will create a memory body handler, the default + belle_sip_message_t *response = BELLE_SIP_MESSAGE(event->response); + belle_sip_body_handler_t *body_handler = NULL; + size_t body_size = 0; + + if (msg->file_transfer_information == NULL) { + ms_warning("No file transfer information for msg %p: creating...", msg); + msg->file_transfer_information = linphone_chat_create_file_transfer_information_from_headers(response); + } + + if (msg->file_transfer_information) { + body_size = linphone_content_get_size(msg->file_transfer_information); + } + + + body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, linphone_chat_message_file_transfer_on_progress, NULL, on_recv_body, NULL, on_recv_end, msg); + if (msg->file_transfer_filepath != NULL) { + belle_sip_user_body_handler_t *bh = (belle_sip_user_body_handler_t *)body_handler; + body_handler = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new( + msg->file_transfer_filepath, linphone_chat_message_file_transfer_on_progress, msg); + if (belle_sip_body_handler_get_size((belle_sip_body_handler_t *)body_handler) == 0) { + // If the size of the body has not been initialized from the file stat, use the one from the + // file_transfer_information. + belle_sip_body_handler_set_size((belle_sip_body_handler_t *)body_handler, body_size); + } + belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)body_handler, bh); + } + belle_sip_message_set_body_handler((belle_sip_message_t *)event->response, body_handler); + } + }*/ + +/*static bool_t file_transfer_in_progress_and_valid(LinphoneChatMessage* msg) { + return (linphone_chat_message_get_chat_room(msg) && + linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)) && + linphone_chat_message_get_http_request(msg) && + !belle_http_request_is_cancelled(linphone_chat_message_get_http_request(msg))); +} + +static void _release_http_request(LinphoneChatMessage* msg) { + if (linphone_chat_message_get_http_request(msg)) { + belle_sip_object_unref(msg->http_request); + msg->http_request = NULL; + if (msg->http_listener){ + belle_sip_object_unref(msg->http_listener); + msg->http_listener = NULL; + // unhold the reference that the listener was holding on the message + linphone_chat_message_unref(msg); + } + } +} + +static void linphone_chat_message_process_auth_requested_download(void *data, belle_sip_auth_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + ms_error("Error during file download : auth requested for msg [%p]", msg); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateFileTransferError); + _release_http_request(msg); +} + +static void linphone_chat_message_file_transfer_on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *m, + void *data, size_t offset, size_t total) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + if (!file_transfer_in_progress_and_valid(msg)) { + ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); + _release_http_request(msg); + return; + } + if (linphone_chat_message_cbs_get_file_transfer_progress_indication(msg->cbs)) { + linphone_chat_message_cbs_get_file_transfer_progress_indication(msg->cbs)( + msg, msg->file_transfer_information, offset, total); + } else { + // Legacy: call back given by application level + linphone_core_notify_file_transfer_progress_indication(linphone_chat_room_get_core(msg->chat_room), msg, msg->file_transfer_information, + offset, total); + } +} + +static int on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, + void *data, size_t offset, uint8_t *buffer, size_t *size) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + LinphoneCore *lc = NULL; + LinphoneImEncryptionEngine *imee = NULL; + int retval = -1; + + if (!file_transfer_in_progress_and_valid(msg)) { + if (msg->http_request) { + ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); + _release_http_request(msg); + } + return BELLE_SIP_STOP; + } + + lc = linphone_chat_room_get_core(msg->chat_room); + // if we've not reach the end of file yet, ask for more data + // in case of file body handler, won't be called + if (msg->file_transfer_filepath == NULL && offset < linphone_content_get_size(msg->file_transfer_information)) { + // get data from call back + LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = linphone_chat_message_cbs_get_file_transfer_send(msg->cbs); + if (file_transfer_send_cb) { + LinphoneBuffer *lb = file_transfer_send_cb(msg, msg->file_transfer_information, offset, *size); + if (lb == NULL) { + *size = 0; + } else { + *size = linphone_buffer_get_size(lb); + memcpy(buffer, linphone_buffer_get_content(lb), *size); + linphone_buffer_unref(lb); + } + } else { + // Legacy + linphone_core_notify_file_transfer_send(lc, msg, msg->file_transfer_information, (char *)buffer, size); + } + } + + imee = linphone_core_get_im_encryption_engine(lc); + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); + if (cb_process_uploading_file) { + size_t max_size = *size; + uint8_t *encrypted_buffer = (uint8_t *)ms_malloc0(max_size); + retval = cb_process_uploading_file(imee, msg, offset, (const uint8_t *)buffer, size, encrypted_buffer); + if (retval == 0) { + if (*size > max_size) { + ms_error("IM encryption engine process upload file callback returned a size bigger than the size of the buffer, so it will be truncated !"); + *size = max_size; + } + memcpy(buffer, encrypted_buffer, *size); + } + ms_free(encrypted_buffer); + } + } + + return retval <= 0 ? BELLE_SIP_CONTINUE : BELLE_SIP_STOP; +} + +static void on_send_end(belle_sip_user_body_handler_t *bh, void *data) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room); + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); + + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); + if (cb_process_uploading_file) { + cb_process_uploading_file(imee, msg, 0, NULL, NULL, NULL); + } + } +} + +static void file_upload_end_background_task(LinphoneChatMessage *obj){ + if (obj->bg_task_id){ + ms_message("channel [%p]: ending file upload background task with id=[%lx].",obj,obj->bg_task_id); + sal_end_background_task(obj->bg_task_id); + obj->bg_task_id=0; + } +} + +static void file_upload_background_task_ended(LinphoneChatMessage *obj){ + ms_warning("channel [%p]: file upload background task has to be ended now, but work isn't finished.",obj); + file_upload_end_background_task(obj); +} + +static void file_upload_begin_background_task(LinphoneChatMessage *obj){ + if (obj->bg_task_id==0){ + obj->bg_task_id=sal_begin_background_task("file transfer upload",(void (*)(void*))file_upload_background_task_ended, obj); + if (obj->bg_task_id) ms_message("channel [%p]: starting file upload background task with id=[%lx].",obj,obj->bg_task_id); + } +} + +static void linphone_chat_message_process_response_from_post_file(void *data, const belle_http_response_event_t *event) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + + if (msg->http_request && !file_transfer_in_progress_and_valid(msg)) { + ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); + _release_http_request(msg); + return; + } + + // check the answer code + if (event->response) { + int code = belle_http_response_get_status_code(event->response); + if (code == 204) { // this is the reply to the first post to the server - an empty msg + // start uploading the file + belle_sip_multipart_body_handler_t *bh; + char *first_part_header; + belle_sip_body_handler_t *first_part_bh; + + bool_t is_file_encryption_enabled = FALSE; + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(linphone_chat_room_get_core(msg->chat_room)); + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer_cb = + linphone_im_encryption_engine_cbs_get_is_encryption_enabled_for_file_transfer(imee_cbs); + if (is_encryption_enabled_for_file_transfer_cb) { + is_file_encryption_enabled = is_encryption_enabled_for_file_transfer_cb(imee, msg->chat_room); + } + } + // shall we encrypt the file + if (is_file_encryption_enabled) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb generate_file_transfer_key_cb = + linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(imee_cbs); + if (generate_file_transfer_key_cb) { + generate_file_transfer_key_cb(imee, msg->chat_room, msg); + } + // temporary storage for the Content-disposition header value : use a generic filename to not leak it + // Actual filename stored in msg->file_transfer_information->name will be set in encrypted msg + // sended to the + first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"filename.txt\""); + } else { + // temporary storage for the Content-disposition header value + first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"%s\"", + linphone_content_get_name(msg->file_transfer_information)); + } + + // create a user body handler to take care of the file and add the content disposition and content-type headers + first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new( + linphone_content_get_size(msg->file_transfer_information), + linphone_chat_message_file_transfer_on_progress, NULL, NULL, + on_send_body, on_send_end, msg); + if (msg->file_transfer_filepath != NULL) { + belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh; + first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(msg->file_transfer_filepath, + NULL, msg); // No need to add again the callback for progression, otherwise it will be called twice + linphone_content_set_size(msg->file_transfer_information, belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh)); + belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)first_part_bh, body_handler); + } else if (linphone_content_get_buffer(msg->file_transfer_information) != NULL) { + first_part_bh = (belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer( + linphone_content_get_buffer(msg->file_transfer_information), + linphone_content_get_size(msg->file_transfer_information), linphone_chat_message_file_transfer_on_progress, msg); + } + + belle_sip_body_handler_add_header(first_part_bh, + belle_sip_header_create("Content-disposition", first_part_header)); + belle_sip_free(first_part_header); + belle_sip_body_handler_add_header(first_part_bh, + (belle_sip_header_t *)belle_sip_header_content_type_create( + linphone_content_get_type(msg->file_transfer_information), + linphone_content_get_subtype(msg->file_transfer_information))); + + // insert it in a multipart body handler which will manage the boundaries of multipart msg + bh = belle_sip_multipart_body_handler_new(linphone_chat_message_file_transfer_on_progress, msg, first_part_bh, NULL); + + linphone_chat_message_ref(msg); + _release_http_request(msg); + file_upload_begin_background_task(msg); + linphone_chat_room_upload_file(msg); + belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(msg->http_request), BELLE_SIP_BODY_HANDLER(bh)); + linphone_chat_message_unref(msg); + } else if (code == 200) { // file has been uploaded correctly, get server reply and send it + const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); + if (body && strlen(body) > 0) { + // if we have an encryption key for the file, we must insert it into the msg and restore the correct filename + const char *content_key = linphone_content_get_key(msg->file_transfer_information); + size_t content_key_size = linphone_content_get_key_size(msg->file_transfer_information); + if (content_key != NULL) { + // parse the msg body + xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body); + + xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody); + if (cur != NULL) { + cur = cur->xmlChildrenNode; + while (cur != NULL) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { // we found a file info node, check + // it has a type="file" attribute + xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); + if (!xmlStrcmp(typeAttribute, + (const xmlChar *)"file")) { // this is the node we are looking for : add a + // file-key children node + xmlNodePtr fileInfoNodeChildren = + cur + ->xmlChildrenNode; // need to parse the children node to update the file-name one + // convert key to base64 + size_t b64Size = b64::b64_encode(NULL, content_key_size, NULL, 0); + char *keyb64 = (char *)ms_malloc0(b64Size + 1); + int xmlStringLength; + + b64Size = b64::b64_encode(content_key, content_key_size, keyb64, b64Size); + keyb64[b64Size] = '\0'; // libxml need a null terminated string + + // add the node containing the key to the file-info node + xmlNewTextChild(cur, NULL, (const xmlChar *)"file-key", (const xmlChar *)keyb64); + xmlFree(typeAttribute); + ms_free(keyb64); + + // look for the file-name node and update its content + while (fileInfoNodeChildren != NULL) { + if (!xmlStrcmp( + fileInfoNodeChildren->name, + (const xmlChar *)"file-name")) { // we found a the file-name node, update + // its content with the real filename + // update node content + xmlNodeSetContent(fileInfoNodeChildren, + (const xmlChar *)(linphone_content_get_name( + msg->file_transfer_information))); + break; + } + fileInfoNodeChildren = fileInfoNodeChildren->next; + } + + // dump the xml into msg->message + xmlDocDumpFormatMemoryEnc(xmlMessageBody, (xmlChar **)&msg->message, &xmlStringLength, + "UTF-8", 0); + + break; + } + xmlFree(typeAttribute); + } + cur = cur->next; + } + } + xmlFreeDoc(xmlMessageBody); + } else { // no encryption key, transfer in plain, just copy the msg sent by server + msg->message = ms_strdup(body); + } + linphone_chat_message_set_content_type(msg, "application/vnd.gsma.rcs-ft-http+xml"); + linphone_chat_message_ref(msg); + linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone); + _release_http_request(msg); + L_GET_CPP_PTR_FROM_C_OBJECT(msg->chat_room)->sendMessage(msg); + file_upload_end_background_task(msg); + linphone_chat_message_unref(msg); + } else { + ms_warning("Received empty response from server, file transfer failed"); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); + _release_http_request(msg); + file_upload_end_background_task(msg); + linphone_chat_message_unref(msg); + } + } else { + ms_warning("Unhandled HTTP code response %d for file transfer", code); + linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); + _release_http_request(msg); + file_upload_end_background_task(msg); + linphone_chat_message_unref(msg); + } + } +} + +static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset, uint8_t *buffer, size_t size) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + LinphoneCore *lc = NULL; + LinphoneImEncryptionEngine *imee = NULL; + int retval = -1; + uint8_t *decrypted_buffer = NULL; + + if (!msg->chat_room) { + linphone_chat_message_cancel_file_transfer(msg); + return; + } + lc = linphone_chat_room_get_core(msg->chat_room); + + if (lc == NULL){ + return; // might happen during linphone_core_destroy() + } + + if (!msg->http_request || belle_http_request_is_cancelled(msg->http_request)) { + ms_warning("Cancelled request for msg [%p], ignoring %s", msg, __FUNCTION__); + return; + } + + // first call may be with a zero size, ignore it + if (size == 0) { + return; + } + + decrypted_buffer = (uint8_t *)ms_malloc0(size); + imee = linphone_core_get_im_encryption_engine(lc); + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); + if (cb_process_downloading_file) { + retval = cb_process_downloading_file(imee, msg, offset, (const uint8_t *)buffer, size, decrypted_buffer); + if (retval == 0) { + memcpy(buffer, decrypted_buffer, size); + } + } + } + ms_free(decrypted_buffer); + + if (retval <= 0) { + if (msg->file_transfer_filepath == NULL) { + if (linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)) { + LinphoneBuffer *lb = linphone_buffer_new_from_data(buffer, size); + linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)(msg, msg->file_transfer_information, lb); + linphone_buffer_unref(lb); + } else { + // Legacy: call back given by application level + linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, (const char *)buffer, size); + } + } + } else { + ms_warning("File transfer decrypt failed with code %d", (int)retval); + linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferError); + } + + return; +} + +static void on_recv_end(belle_sip_user_body_handler_t *bh, void *data) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)data; + LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room); + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); + int retval = -1; + + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); + if (cb_process_downloading_file) { + retval = cb_process_downloading_file(imee, msg, 0, NULL, 0, NULL); + } + } + + if (retval <= 0) { + if (msg->file_transfer_filepath == NULL) { + if (linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)) { + LinphoneBuffer *lb = linphone_buffer_new(); + linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)(msg, msg->file_transfer_information, lb); + linphone_buffer_unref(lb); + } else { + // Legacy: call back given by application level + linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, NULL, 0); + } + } + } + + if (retval <= 0 && linphone_chat_message_get_state(msg) != LinphoneChatMessageStateFileTransferError) { + linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone); + } +}*/ + +/* + +static int _linphone_chat_room_start_http_transfer(LinphoneChatMessage *msg, const char* url, const char* action, const belle_http_request_listener_callbacks_t *cbs) { + belle_generic_uri_t *uri = NULL; + const char* ua = linphone_core_get_user_agent(linphone_chat_room_get_core(msg->chat_room)); + + if (url == NULL) { + ms_warning("Cannot process file transfer msg: no file remote URI configured."); + goto error; + } + uri = belle_generic_uri_parse(url); + if (uri == NULL || belle_generic_uri_get_host(uri)==NULL) { + ms_warning("Cannot process file transfer msg: incorrect file remote URI configured '%s'.", url); + goto error; + } + + msg->http_request = belle_http_request_create(action, uri, belle_sip_header_create("User-Agent", ua), NULL); + + if (msg->http_request == NULL) { + ms_warning("Could not create http request for uri %s", url); + goto error; + } + // keep a reference to the http request to be able to cancel it during upload + belle_sip_object_ref(msg->http_request); + + // give msg to listener to be able to start the actual file upload when server answer a 204 No content + msg->http_listener = belle_http_request_listener_create_from_callbacks(cbs, linphone_chat_message_ref(msg)); + belle_http_provider_send_request(linphone_chat_room_get_core(msg->chat_room)->http_provider, msg->http_request, msg->http_listener); + return 0; + error: + if (uri) { + belle_sip_object_unref(uri); + } + return -1; + } +*/ + +int ChatMessage::uploadFile() { + return -1; + //TODO + /*belle_http_request_listener_callbacks_t cbs = {0}; + int err; + + if (msg->http_request){ + ms_error("linphone_chat_room_upload_file(): there is already an upload in progress."); + return -1; + } + + cbs.process_response = linphone_chat_message_process_response_from_post_file; + cbs.process_io_error = linphone_chat_message_process_io_error_upload; + cbs.process_auth_requested = linphone_chat_message_process_auth_requested_upload; + err = _linphone_chat_room_start_http_transfer(msg, linphone_core_get_file_transfer_server(linphone_chat_room_get_core(msg->chat_room)), "POST", &cbs); + if (err == -1){ + linphone_chat_message_set_state(msg, LinphoneChatMessageStateNotDelivered); + } + return err;*/ +} + +int ChatMessage::downloadFile() { + return -1; + //TODO + /*belle_http_request_listener_callbacks_t cbs = {0}; + int err; + + if (msg->http_request){ + ms_error("linphone_chat_message_download_file(): there is already a download in progress"); + return -1; + } + cbs.process_response_headers = linphone_chat_process_response_headers_from_get_file; + cbs.process_response = linphone_chat_process_response_from_get_file; + cbs.process_io_error = linphone_chat_message_process_io_error_download; + cbs.process_auth_requested = linphone_chat_message_process_auth_requested_download; + err = _linphone_chat_room_start_http_transfer(msg, msg->external_body_url, "GET", &cbs); + if (err == -1) return -1; + // start the download, status is In Progress + linphone_chat_message_set_state(msg, LinphoneChatMessageStateInProgress); + return 0;*/ +} + +void ChatMessage::cancelFileTransfer() { + //TODO + /*if (msg->http_request) { + if (msg->state == LinphoneChatMessageStateInProgress) { + linphone_chat_message_set_state(msg, LinphoneChatMessageStateNotDelivered); + } + if (!belle_http_request_is_cancelled(msg->http_request)) { + if (msg->chat_room) { + ms_message("Canceling file transfer %s - msg [%p] chat room[%p]" + , (msg->external_body_url == NULL) ? linphone_core_get_file_transfer_server(linphone_chat_room_get_core(msg->chat_room)) : msg->external_body_url + , msg + , msg->chat_room); + belle_http_provider_cancel_request(linphone_chat_room_get_core(msg->chat_room)->http_provider, msg->http_request); + if ((msg->dir == LinphoneChatMessageOutgoing) && unref) { + // must release it + linphone_chat_message_unref(msg); + } + } else { + ms_message("Warning: http request still running for ORPHAN msg [%p]: this is a memory leak", msg); + } + } + _release_http_request(msg); + } else { + ms_message("No existing file transfer - nothing to cancel"); + }*/ +} + +int ChatMessage::putCharacter(uint32_t character) { + //TODO + /*LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); + if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) { + std::shared_ptr rttcr = + std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); + LinphoneCall *call = rttcr->getCall(); + LinphoneCore *lc = rttcr->getCore(); + const uint32_t new_line = 0x2028; + const uint32_t crlf = 0x0D0A; + const uint32_t lf = 0x0A; + + if (!call || !linphone_call_get_stream(call, LinphoneStreamTypeText)) { + return -1; + } + + if (character == new_line || character == crlf || character == lf) { + if (lc && lp_config_get_int(lc->config, "misc", "store_rtt_messages", 1) == 1) { + ms_debug("New line sent, forge a message with content %s", msg->message); + msg->time = ms_time(0); + msg->state = LinphoneChatMessageStateDisplayed; + msg->dir = LinphoneChatMessageOutgoing; + if (msg->from) linphone_address_unref(msg->from); + msg->from = linphone_address_new(linphone_core_get_identity(lc)); + msg->storage_id = linphone_chat_message_store(msg); + ms_free(msg->message); + msg->message = NULL; + } + } else { + char *value = LinphonePrivate::Utils::utf8ToChar(character); + msg->message = ms_strcat_printf(msg->message, value); + ms_debug("Sent RTT character: %s (%lu), pending text is %s", value, (unsigned long)character, msg->message); + delete value; + } + + text_stream_putchar32(reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeText)), character); + return 0; + }*/ + return -1; +} + +// ----------------------------------------------------------------------------- + void ChatMessage::send () { L_D(ChatMessage); diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index c14a4998e..7faa8be72 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -22,6 +22,8 @@ #include #include +#include "imdn.h" +#include "linphone/api/c-types.h" #include "linphone/api/c-chat-message.h" #include "object/object.h" @@ -62,7 +64,24 @@ public: LinphoneChatMessage * getBackPtr(); std::shared_ptr getChatRoom () const; + void setChatRoom (std::shared_ptr cr); + // ----------------------------------------------------------------------------- + // Methods + // ----------------------------------------------------------------------------- + + void updateState(State state); + void reSend(); + void sendImdn(); + void sendDeliveryNotification(); + void sendDisplayNotification(); + int uploadFile(); + int downloadFile(); + void cancelFileTransfer(); + int putCharacter(uint32_t character); + + // ----------------------------------------------------------------------------- + // Getters & setters // ----------------------------------------------------------------------------- Direction getDirection () const; @@ -89,25 +108,50 @@ public: std::string getAppdata () const; void setAppdata (const std::string &appData); + std::shared_ptr
    getFromAddress () const; + void setFromAddress(std::shared_ptr
    from); + + std::shared_ptr
    getToAddress () const; + void setToAddress(std::shared_ptr
    to); + + std::string getFileTransferFilepath() const; + void setFileTransferFilepath(const std::string &path); + + bool isToBeStored() const; + void setIsToBeStored(bool store); + // ----------------------------------------------------------------------------- // Deprecated methods, only used for C wrapper // ----------------------------------------------------------------------------- std::string getContentType() const; + void setContentType(std::string contentType); std::string getText() const; + void setText(std::string text); + + std::shared_ptr getFileTransferInformation() const; + void setFileTransferInformation(std::shared_ptr content); unsigned int getStorageId() const; void setStorageId(unsigned int id); void setTime(time_t time); - // ----------------------------------------------------------------------------- + belle_http_request_t *getHttpRequest() const; + void setHttpRequest(belle_http_request_t *request); - std::shared_ptr getFromAddress () const; - std::shared_ptr getToAddress () const; - std::shared_ptr getLocalAddress () const; - std::shared_ptr getRemoteAddress () const; + SalOp *getSalOp() const; + void setSalOp(SalOp *op); + + SalCustomHeader *getSalCustomHeaders() const; + void setSalCustomHeaders(SalCustomHeader *headers); + + void addSalCustomHeader(std::string name, std::string value); + void removeSalCustomHeader(std::string name); + std::string getSalCustomHeaderValue(std::string name); + + // ----------------------------------------------------------------------------- std::shared_ptr getErrorInfo () const; diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 29102a8fb..b04b14841 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -593,7 +593,6 @@ void ChatRoom::compose () { LinphoneChatMessage *ChatRoom::createFileTransferMessage (const LinphoneContent *initialContent) { L_D(ChatRoom); LinphoneChatMessage *msg = createMessage(""); - linphone_chat_message_set_chat_room(msg, L_GET_C_BACK_PTR(this)); linphone_chat_message_set_text(msg, NULL); linphone_chat_message_set_file_transfer_information(msg, linphone_content_copy(initialContent)); linphone_chat_message_set_outgoing(msg); @@ -612,7 +611,6 @@ LinphoneChatMessage *ChatRoom::createFileTransferMessage (const LinphoneContent LinphoneChatMessage *ChatRoom::createMessage (const string &message) { shared_ptr chatMessage = make_shared(static_pointer_cast(shared_from_this())); LinphoneChatMessage *msg = chatMessage->getBackPtr(); - linphone_chat_message_set_chat_room(msg, L_GET_C_BACK_PTR(this)); linphone_chat_message_set_state(msg, LinphoneChatMessageStateIdle); linphone_chat_message_set_text(msg, message.empty() ? nullptr : ms_strdup(message.c_str())); linphone_chat_message_set_content_type(msg, ms_strdup("text/plain")); diff --git a/tester/message_tester.c b/tester/message_tester.c index 444010ec3..3b661a342 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -741,7 +741,7 @@ static void file_transfer_2_messages_simultaneously(void) { linphone_chat_room_send_chat_message(pauline_room,msg); linphone_chat_room_send_chat_message(pauline_room,msg2); if (BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,1, 60000))) { - msg = linphone_chat_message_clone(marie->stat.last_received_chat_message); + msg = linphone_chat_message_ref(marie->stat.last_received_chat_message); BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,2, 60000)); msg2 = marie->stat.last_received_chat_message; BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_core_get_chat_rooms(marie->lc)), 1, unsigned int, "%u"); From 38a9ac162a585218d390491609b88528f5548a65 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 26 Sep 2017 15:52:12 +0200 Subject: [PATCH 0188/2215] Fix Ronan's changes lost in previous merge --- src/chat/chat-message.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 2c5f07e50..c9bc60bae 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -1085,8 +1085,8 @@ int ChatMessage::putCharacter(uint32_t character) { //TODO /*LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) { - std::shared_ptr rttcr = - std::static_pointer_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); + shared_ptr rttcr = + static_pointer_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); LinphoneCall *call = rttcr->getCall(); LinphoneCore *lc = rttcr->getCore(); const uint32_t new_line = 0x2028; From f3b3015dbc9e0f81ef750c7e10c95d2aaae8a65e Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 26 Sep 2017 15:55:21 +0200 Subject: [PATCH 0189/2215] feat(c-wrapper): setCppPtrFromC is more secure, check types --- src/c-wrapper/c-wrapper.h | 1 + src/c-wrapper/internal/c-tools.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index fed96f8df..531f03f0a 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -41,6 +41,7 @@ F(Participant, Participant) #define L_REGISTER_SUBTYPES(F) \ + F(ChatRoom, BasicChatRoom) \ F(ChatRoom, ClientGroupChatRoom) \ F(ChatRoom, RealTimeTextChatRoom) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 788d090b3..6f05c5759 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -143,7 +143,7 @@ public: template< typename CppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static inline void setCppPtrFromC (void *cObject, const std::shared_ptr &cppObject) { static_cast *>(cObject)->cppPtr = cppObject; @@ -152,7 +152,7 @@ public: template< typename CppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static inline void setCppPtrFromC (void *cObject, const CppType *cppObject) { CppType **cppObjectAddr = &static_cast *>(cObject)->cppPtr; From 57de771a2866fac05b5145d97efb268e8dc27438 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 26 Sep 2017 16:03:28 +0200 Subject: [PATCH 0190/2215] feat(c-wrappper): check types at compile time in all functions --- src/c-wrapper/internal/c-tools.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 6f05c5759..9cffcacff 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -170,7 +170,7 @@ public: template< typename CppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static inline typename CppTypeToCType::type *getCBackPtr (const std::shared_ptr &cppObject) { typedef typename CppTypeToCType::type RetType; @@ -187,7 +187,7 @@ public: template< typename CppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static inline typename CppTypeToCType::type *getCBackPtr (CppType *cppObject) { return getCBackPtr(std::static_pointer_cast(cppObject->shared_from_this())); @@ -195,7 +195,7 @@ public: template< typename CppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static inline typename CppTypeToCType::type *getCBackPtr (const CppType *cppObject) { typedef typename CppTypeToCType::type RetType; @@ -250,7 +250,7 @@ public: template< typename CppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static inline bctbx_list_t *getResolvedCListFromCppList (const std::list> &cppList) { bctbx_list_t *result = nullptr; @@ -259,7 +259,10 @@ public: return result; } - template + template< + typename CppType, + typename = typename std::enable_if::value, CppType>::type + > static inline bctbx_list_t *getResolvedCListFromCppList (const std::list &cppList) { bctbx_list_t *result = nullptr; for (const auto &value : cppList) @@ -270,7 +273,7 @@ public: template< typename CType, typename CppType = typename CTypeToCppType::type, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static inline std::list> getResolvedCppListFromCList (const bctbx_list_t *cList) { std::list> result; @@ -282,7 +285,7 @@ public: template< typename CType, typename CppType = typename CTypeToCppType::type, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static inline std::list getResolvedCppListFromCList (const bctbx_list_t *cList) { std::list result; From f97b6b9baeaad56db9e57afe0cc159e9ce1dbff4 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 26 Sep 2017 16:56:22 +0200 Subject: [PATCH 0191/2215] Add definition of operator= for call/media session params. --- src/conference/params/call-session-params-p.h | 4 + src/conference/params/call-session-params.cpp | 38 ++++++-- src/conference/params/call-session-params.h | 2 + .../params/media-session-params-p.h | 5 + .../params/media-session-params.cpp | 95 ++++++++++++------- src/conference/params/media-session-params.h | 2 + 6 files changed, 102 insertions(+), 44 deletions(-) diff --git a/src/conference/params/call-session-params-p.h b/src/conference/params/call-session-params-p.h index 88b1e9e02..3b5e4e701 100644 --- a/src/conference/params/call-session-params-p.h +++ b/src/conference/params/call-session-params-p.h @@ -33,6 +33,10 @@ public: CallSessionParamsPrivate (const CallSessionParamsPrivate &src); virtual ~CallSessionParamsPrivate (); + CallSessionParamsPrivate &operator= (const CallSessionParamsPrivate &src); + + static void clone (const CallSessionParamsPrivate &src, CallSessionParamsPrivate &dst); + bool getInConference () const { return inConference; } void setInConference (bool value) { inConference = value; } bool getInternalCallUpdate () const { return internalCallUpdate; } diff --git a/src/conference/params/call-session-params.cpp b/src/conference/params/call-session-params.cpp index 4cc8d7963..7730438d4 100644 --- a/src/conference/params/call-session-params.cpp +++ b/src/conference/params/call-session-params.cpp @@ -27,15 +27,7 @@ LINPHONE_BEGIN_NAMESPACE // ============================================================================= CallSessionParamsPrivate::CallSessionParamsPrivate (const CallSessionParamsPrivate &src) : ClonableObjectPrivate () { - sessionName = src.sessionName; - privacy = src.privacy; - inConference = src.inConference; - internalCallUpdate = src.internalCallUpdate; - noUserConsent = src.noUserConsent; - /* The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient. */ - if (src.customHeaders) - customHeaders = sal_custom_header_clone(src.customHeaders); - referer = src.referer; + clone(src, *this); } CallSessionParamsPrivate::~CallSessionParamsPrivate () { @@ -43,6 +35,27 @@ CallSessionParamsPrivate::~CallSessionParamsPrivate () { sal_custom_header_free(customHeaders); } +CallSessionParamsPrivate &CallSessionParamsPrivate::operator= (const CallSessionParamsPrivate &src) { + if (this != &src) { + if (customHeaders) + sal_custom_header_free(customHeaders); + clone(src, *this); + } + return *this; +} + +void CallSessionParamsPrivate::clone (const CallSessionParamsPrivate &src, CallSessionParamsPrivate &dst) { + dst.sessionName = src.sessionName; + dst.privacy = src.privacy; + dst.inConference = src.inConference; + dst.internalCallUpdate = src.internalCallUpdate; + dst.noUserConsent = src.noUserConsent; + /* The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient. */ + if (src.customHeaders) + dst.customHeaders = sal_custom_header_clone(src.customHeaders); + dst.referer = src.referer; +} + // ----------------------------------------------------------------------------- SalCustomHeader * CallSessionParamsPrivate::getCustomHeaders () const { @@ -67,6 +80,13 @@ CallSessionParams::CallSessionParams (CallSessionParamsPrivate &p) : ClonableObj CallSessionParams::CallSessionParams (const CallSessionParams &src) : ClonableObject(*new CallSessionParamsPrivate(*src.getPrivate())) {} +CallSessionParams &CallSessionParams::operator= (const CallSessionParams &src) { + L_D(CallSessionParams); + if (this != &src) + *d = *src.getPrivate(); + return *this; +} + // ----------------------------------------------------------------------------- void CallSessionParams::initDefault (LinphoneCore *core) { diff --git a/src/conference/params/call-session-params.h b/src/conference/params/call-session-params.h index adb6ed1eb..d666afac9 100644 --- a/src/conference/params/call-session-params.h +++ b/src/conference/params/call-session-params.h @@ -41,6 +41,8 @@ public: CallSessionParams (const CallSessionParams &src); virtual ~CallSessionParams () = default; + CallSessionParams &operator= (const CallSessionParams &src); + virtual void initDefault (LinphoneCore *core); const std::string& getSessionName () const; diff --git a/src/conference/params/media-session-params-p.h b/src/conference/params/media-session-params-p.h index a32b88bd1..5355ff2f9 100644 --- a/src/conference/params/media-session-params-p.h +++ b/src/conference/params/media-session-params-p.h @@ -39,6 +39,11 @@ public: MediaSessionParamsPrivate (const MediaSessionParamsPrivate &src); virtual ~MediaSessionParamsPrivate (); + MediaSessionParamsPrivate &operator= (const MediaSessionParamsPrivate &src); + + static void clone (const MediaSessionParamsPrivate &src, MediaSessionParamsPrivate &dst); + void clean (); + static SalStreamDir mediaDirectionToSalStreamDir (LinphoneMediaDirection direction); static LinphoneMediaDirection salStreamDirToMediaDirection (SalStreamDir dir); diff --git a/src/conference/params/media-session-params.cpp b/src/conference/params/media-session-params.cpp index fe65b7be3..03fb0c748 100644 --- a/src/conference/params/media-session-params.cpp +++ b/src/conference/params/media-session-params.cpp @@ -36,44 +36,60 @@ MediaSessionParamsPrivate::MediaSessionParamsPrivate () { } MediaSessionParamsPrivate::MediaSessionParamsPrivate (const MediaSessionParamsPrivate &src) : CallSessionParamsPrivate(src) { - audioEnabled = src.audioEnabled; - audioBandwidthLimit = src.audioBandwidthLimit; - audioDirection = src.audioDirection; - audioMulticastEnabled = src.audioMulticastEnabled; - usedAudioCodec = src.usedAudioCodec; - videoEnabled = src.videoEnabled; - videoDirection = src.videoDirection; - videoMulticastEnabled = src.videoMulticastEnabled; - usedVideoCodec = src.usedVideoCodec; - receivedFps = src.receivedFps; - receivedVideoDefinition = src.receivedVideoDefinition ? linphone_video_definition_ref(src.receivedVideoDefinition) : nullptr; - sentFps = src.sentFps; - sentVideoDefinition = src.sentVideoDefinition ? linphone_video_definition_ref(src.sentVideoDefinition) : nullptr; - realtimeTextEnabled = src.realtimeTextEnabled; - usedRealtimeTextCodec = src.usedRealtimeTextCodec; - avpfEnabled = src.avpfEnabled; - avpfRrInterval = src.avpfRrInterval; - lowBandwidthEnabled = src.lowBandwidthEnabled; - recordFilePath = src.recordFilePath; - earlyMediaSendingEnabled = src.earlyMediaSendingEnabled; - encryption = src.encryption; - mandatoryMediaEncryptionEnabled = src.mandatoryMediaEncryptionEnabled; - _implicitRtcpFbEnabled = src._implicitRtcpFbEnabled; - downBandwidth = src.downBandwidth; - upBandwidth = src.upBandwidth; - downPtime = src.downPtime; - upPtime = src.upPtime; - updateCallWhenIceCompleted = src.updateCallWhenIceCompleted; - if (src.customSdpAttributes) - customSdpAttributes = sal_custom_sdp_attribute_clone(src.customSdpAttributes); - memset(customSdpMediaAttributes, 0, sizeof(customSdpMediaAttributes)); - for (unsigned int i = 0; i < (unsigned int)LinphoneStreamTypeUnknown; i++) { - if (src.customSdpMediaAttributes[i]) - customSdpMediaAttributes[i] = sal_custom_sdp_attribute_clone(src.customSdpMediaAttributes[i]); - } + clone(src, *this); } MediaSessionParamsPrivate::~MediaSessionParamsPrivate () { + this->clean(); +} + +MediaSessionParamsPrivate &MediaSessionParamsPrivate::operator= (const MediaSessionParamsPrivate &src) { + if (this != &src) { + this->clean(); + clone(src, *this); + } + return *this; +} + +void MediaSessionParamsPrivate::clone (const MediaSessionParamsPrivate &src, MediaSessionParamsPrivate &dst) { + dst.audioEnabled = src.audioEnabled; + dst.audioBandwidthLimit = src.audioBandwidthLimit; + dst.audioDirection = src.audioDirection; + dst.audioMulticastEnabled = src.audioMulticastEnabled; + dst.usedAudioCodec = src.usedAudioCodec; + dst.videoEnabled = src.videoEnabled; + dst.videoDirection = src.videoDirection; + dst.videoMulticastEnabled = src.videoMulticastEnabled; + dst.usedVideoCodec = src.usedVideoCodec; + dst.receivedFps = src.receivedFps; + dst.receivedVideoDefinition = src.receivedVideoDefinition ? linphone_video_definition_ref(src.receivedVideoDefinition) : nullptr; + dst.sentFps = src.sentFps; + dst.sentVideoDefinition = src.sentVideoDefinition ? linphone_video_definition_ref(src.sentVideoDefinition) : nullptr; + dst.realtimeTextEnabled = src.realtimeTextEnabled; + dst.usedRealtimeTextCodec = src.usedRealtimeTextCodec; + dst.avpfEnabled = src.avpfEnabled; + dst.avpfRrInterval = src.avpfRrInterval; + dst.lowBandwidthEnabled = src.lowBandwidthEnabled; + dst.recordFilePath = src.recordFilePath; + dst.earlyMediaSendingEnabled = src.earlyMediaSendingEnabled; + dst.encryption = src.encryption; + dst.mandatoryMediaEncryptionEnabled = src.mandatoryMediaEncryptionEnabled; + dst._implicitRtcpFbEnabled = src._implicitRtcpFbEnabled; + dst.downBandwidth = src.downBandwidth; + dst.upBandwidth = src.upBandwidth; + dst.downPtime = src.downPtime; + dst.upPtime = src.upPtime; + dst.updateCallWhenIceCompleted = src.updateCallWhenIceCompleted; + if (src.customSdpAttributes) + dst.customSdpAttributes = sal_custom_sdp_attribute_clone(src.customSdpAttributes); + memset(dst.customSdpMediaAttributes, 0, sizeof(dst.customSdpMediaAttributes)); + for (unsigned int i = 0; i < (unsigned int)LinphoneStreamTypeUnknown; i++) { + if (src.customSdpMediaAttributes[i]) + dst.customSdpMediaAttributes[i] = sal_custom_sdp_attribute_clone(src.customSdpMediaAttributes[i]); + } +} + +void MediaSessionParamsPrivate::clean () { if (receivedVideoDefinition) linphone_video_definition_unref(receivedVideoDefinition); if (sentVideoDefinition) @@ -203,6 +219,15 @@ MediaSessionParams::MediaSessionParams () : CallSessionParams(*new MediaSessionP MediaSessionParams::MediaSessionParams (const MediaSessionParams &src) : CallSessionParams(*new MediaSessionParamsPrivate(*src.getPrivate())) {} +MediaSessionParams &MediaSessionParams::operator= (const MediaSessionParams &src) { + L_D(MediaSessionParams); + if (this != &src) { + CallSessionParams::operator=(src); + *d = *src.getPrivate(); + } + return *this; +} + // ----------------------------------------------------------------------------- void MediaSessionParams::initDefault (LinphoneCore *core) { diff --git a/src/conference/params/media-session-params.h b/src/conference/params/media-session-params.h index a8fdb1d7a..0a6aafe9b 100644 --- a/src/conference/params/media-session-params.h +++ b/src/conference/params/media-session-params.h @@ -40,6 +40,8 @@ public: MediaSessionParams (const MediaSessionParams &src); virtual ~MediaSessionParams () = default; + MediaSessionParams &operator= (const MediaSessionParams &src); + void initDefault (LinphoneCore *core) override; bool audioEnabled () const; From 076e744dcd3b3893674bb5bc4ddfe476a9d0e5f4 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 26 Sep 2017 16:58:13 +0200 Subject: [PATCH 0192/2215] Handle subject in INVITE + create body when creating the client group chat room. --- coreapi/bellesip_sal/sal_op_call.c | 6 +++-- coreapi/chat.c | 4 +-- coreapi/private.h | 2 +- coreapi/sal/sal.h | 2 +- include/linphone/core.h | 3 ++- src/address/address.cpp | 4 +++ src/address/address.h | 2 ++ src/c-wrapper/api/c-chat-room.cpp | 4 +-- src/call/call.cpp | 2 +- src/chat/client-group-chat-room-p.h | 4 ++- src/chat/client-group-chat-room.cpp | 31 +++++++++++++++++------- src/chat/client-group-chat-room.h | 2 +- src/conference/session/call-session.cpp | 8 +++--- src/conference/session/call-session.h | 2 +- src/conference/session/media-session.cpp | 6 ++--- src/conference/session/media-session.h | 2 +- 16 files changed, 54 insertions(+), 30 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 4f416f565..d1fff0d83 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -773,7 +773,7 @@ static void sal_op_fill_invite(SalOp *op, belle_sip_request_t* invite) { return; } -int sal_call(SalOp *op, const char *from, const char *to){ +int sal_call(SalOp *op, const char *from, const char *to, const char *subject){ belle_sip_request_t* invite; op->dir=SalOpDirOutgoing; @@ -789,6 +789,8 @@ int sal_call(SalOp *op, const char *from, const char *to){ } sal_op_fill_invite(op,invite); + if (subject) + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite), belle_sip_header_create("Subject", subject)); sal_op_call_fill_cbs(op); if (op->replaces){ @@ -1036,7 +1038,7 @@ int sal_call_update(SalOp *op, const char *subject, bool_t no_user_consent){ during a very early state of outgoing call initiation (the dialog has not been created yet). */ const char *from = sal_op_get_from(op); const char *to = sal_op_get_to(op); - return sal_call(op, from, to); + return sal_call(op, from, to, subject); } state = belle_sip_dialog_get_state(op->dialog); diff --git a/coreapi/chat.c b/coreapi/chat.c index 7059cb04b..a458facac 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -125,8 +125,8 @@ LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAd return ret; } -LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc) { - LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc); +LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, const char *subject) { + LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, subject); lc->chatrooms = bctbx_list_append(lc->chatrooms, cr); return cr; } diff --git a/coreapi/private.h b/coreapi/private.h index b3a9d0ce7..80cea1623 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -460,7 +460,7 @@ void _linphone_proxy_config_release_ops(LinphoneProxyConfig *obj); /*chat*/ LinphoneChatRoom * linphone_chat_room_new(LinphoneCore *core, const LinphoneAddress *addr); -LinphoneChatRoom *_linphone_client_group_chat_room_new(LinphoneCore *core); +LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, const char *subject); void linphone_chat_room_release(LinphoneChatRoom *cr); void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call); bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr); diff --git a/coreapi/sal/sal.h b/coreapi/sal/sal.h index bcda97dde..5e0188feb 100644 --- a/coreapi/sal/sal.h +++ b/coreapi/sal/sal.h @@ -742,7 +742,7 @@ void sal_op_set_event(SalOp *op, const char *event); /*Call API*/ int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc); -int sal_call(SalOp *h, const char *from, const char *to); +int sal_call(SalOp *h, const char *from, const char *to, const char *subject); int sal_call_notify_ringing(SalOp *h, bool_t early_media); /*accept an incoming call or, during a call accept a reINVITE*/ int sal_call_accept(SalOp*h); diff --git a/include/linphone/core.h b/include/linphone/core.h index 231557035..55b6fc282 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -4837,9 +4837,10 @@ LINPHONE_PUBLIC const char *linphone_core_get_chat_database_path(const LinphoneC * at the client-side and is empty. Pou need to call linphone_chat_room_add_participants() to * create at the server side and add participants to it. * @param[in] lc A #LinphoneCore object + * @param[in] subject The subject of the group chat room * @return The newly created client-side group chat room. */ -LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, const char *subject); /** * Get a chat room whose peer is the supplied address. If it does not exist yet, it will be created. diff --git a/src/address/address.cpp b/src/address/address.cpp index 17b9ed9bf..8de8d1f90 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -67,6 +67,10 @@ bool Address::operator== (const Address &address) const { return equal(address); } +bool Address::operator< (const Address &address) const { + return asString() < address.asString(); +} + bool Address::isValid () const { L_D(const Address); return static_cast(d->internalAddress); diff --git a/src/address/address.h b/src/address/address.h index 679ba572b..eb3d74ed0 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -38,6 +38,8 @@ public: bool operator== (const Address &address) const; + bool operator< (const Address &address) const; + bool isValid () const; const std::string &getScheme () const; diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 652ccb466..558b8e56c 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -277,7 +277,7 @@ LinphoneChatRoom *linphone_chat_room_new (LinphoneCore *core, const LinphoneAddr return cr; } -LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core) { +LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, const char *subject) { const char *factoryUri = linphone_core_get_conference_factory_uri(core); if (!factoryUri) return nullptr; @@ -291,7 +291,7 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core) { from = linphone_core_get_primary_contact(core); LinphonePrivate::Address me(from); LinphoneChatRoom *cr = L_INIT(ChatRoom); - L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared(core, me)); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared(core, me, subject ? subject : "")); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); return cr; } diff --git a/src/call/call.cpp b/src/call/call.cpp index 9c9e6f613..929bfceca 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -97,7 +97,7 @@ void CallPrivate::startIncomingNotification () { } int CallPrivate::startInvite (const Address *destination) { - return getActiveSession()->startInvite(destination); + return getActiveSession()->startInvite(destination, ""); } // ----------------------------------------------------------------------------- diff --git a/src/chat/client-group-chat-room-p.h b/src/chat/client-group-chat-room-p.h index 346faf869..ef642bc6c 100644 --- a/src/chat/client-group-chat-room-p.h +++ b/src/chat/client-group-chat-room-p.h @@ -31,10 +31,12 @@ LINPHONE_BEGIN_NAMESPACE class ClientGroupChatRoomPrivate : public ChatRoomPrivate { public: - ClientGroupChatRoomPrivate (LinphoneCore *core); + ClientGroupChatRoomPrivate (LinphoneCore *core, const std::string &subject); virtual ~ClientGroupChatRoomPrivate () = default; private: + std::string subject; + L_DECLARE_PUBLIC(ClientGroupChatRoom); }; diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 912383cf4..bfd078e57 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -19,6 +19,7 @@ #include "client-group-chat-room-p.h" #include "c-wrapper/c-wrapper.h" #include "conference/participant-p.h" +#include "content/content.h" #include "logger/logger.h" // ============================================================================= @@ -27,18 +28,15 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core) : ChatRoomPrivate(core) {} +ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core, const string &subject) + : ChatRoomPrivate(core), subject(subject) {} // ============================================================================= -ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me) - : ChatRoom(*new ChatRoomPrivate(core)), RemoteConference(core, me, nullptr) { +ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, const string &subject) + : ChatRoom(*new ClientGroupChatRoomPrivate(core, subject)), RemoteConference(core, me, nullptr) { string factoryUri = linphone_core_get_conference_factory_uri(core); focus = make_shared(factoryUri); - CallSessionParams csp; - shared_ptr session = focus->getPrivate()->createSession(*this, &csp, false, this); - session->configure(LinphoneCallOutgoing, nullptr, nullptr, me, focus->getAddress()); - // TODO } // ----------------------------------------------------------------------------- @@ -51,10 +49,25 @@ shared_ptr ClientGroupChatRoom::addParticipant (const Address &addr void ClientGroupChatRoom::addParticipants (const list
    &addresses, const CallSessionParams *params, bool hasMedia) { L_D(ClientGroupChatRoom); + if (addresses.empty()) + return; + list
    sortedAddresses(addresses); + sortedAddresses.sort(); + sortedAddresses.unique(); if (d->state == ChatRoom::State::Instantiated) { - shared_ptr session = focus->getPrivate()->getSession(); + Content content; + content.setBody(getResourceLists(sortedAddresses)); + content.setContentType("application/resource-lists+xml"); + content.setContentDisposition("recipient-list"); + lInfo() << "Body size: " << content.getSize() << endl << "Body:" << endl << content.getBodyAsString(); + CallSessionParams csp; + if (params) + csp = *params; + csp.addCustomHeader("Require", "recipient-list-invite"); + shared_ptr session = focus->getPrivate()->createSession(*this, &csp, false, this); + session->configure(LinphoneCallOutgoing, nullptr, nullptr, me->getAddress(), focus->getAddress()); session->initiateOutgoing(); - session->startInvite(nullptr); + session->startInvite(nullptr, d->subject); d->setState(ChatRoom::State::CreationPending); } // TODO diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index 8207b62dd..eab0f5a28 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -36,7 +36,7 @@ class ClientGroupChatRoomPrivate; class ClientGroupChatRoom : public ChatRoom, public RemoteConference { public: - ClientGroupChatRoom (LinphoneCore *core, const Address &me); + ClientGroupChatRoom (LinphoneCore *core, const Address &me, const std::string &subject); virtual ~ClientGroupChatRoom () = default; public: diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index d38fa5e85..64af9041d 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -311,7 +311,7 @@ void CallSessionPrivate::pingReply () { if (state == LinphoneCallOutgoingInit) { pingReplied = true; if (isReadyForInvite()) - q->startInvite(nullptr); + q->startInvite(nullptr, ""); } } @@ -770,7 +770,7 @@ void CallSession::iterate (time_t currentRealTime, bool oneSecondElapsed) { int elapsed = (int)(currentRealTime - d->log->start_date_time); if ((d->state == LinphoneCallOutgoingInit) && (elapsed >= d->core->sip_conf.delayed_timeout)) { /* Start the call even if the OPTIONS reply did not arrive */ - startInvite(nullptr); + startInvite(nullptr, ""); } if ((d->state == LinphoneCallIncomingReceived) || (d->state == LinphoneCallIncomingEarlyMedia)) { if (oneSecondElapsed) @@ -828,7 +828,7 @@ void CallSession::startIncomingNotification () { } } -int CallSession::startInvite (const Address *destination) { +int CallSession::startInvite (const Address *destination, const string &subject) { L_D(CallSession); /* Try to be best-effort in giving real local or routable contact address */ d->setContactOp(); @@ -844,7 +844,7 @@ int CallSession::startInvite (const Address *destination) { char *from = linphone_address_as_string(d->log->from); /* Take a ref because sal_call() may destroy the CallSession if no SIP transport is available */ shared_ptr ref = static_pointer_cast(shared_from_this()); - int result = sal_call(d->op, from, destinationStr.c_str()); + int result = sal_call(d->op, from, destinationStr.c_str(), subject.empty() ? nullptr : subject.c_str()); ms_free(from); if (result < 0) { if ((d->state != LinphoneCallError) && (d->state != LinphoneCallReleased)) { diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index 96dcbf2bf..07f8ab262 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -47,7 +47,7 @@ public: virtual bool initiateOutgoing (); virtual void iterate (time_t currentRealTime, bool oneSecondElapsed); virtual void startIncomingNotification (); - virtual int startInvite (const Address *destination); + virtual int startInvite (const Address *destination, const std::string &subject); LinphoneStatus terminate (const LinphoneErrorInfo *ei = nullptr); LinphoneStatus update (const CallSessionParams *csp); diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index c1bce3c98..c19d8d9ce 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -2090,7 +2090,7 @@ void MediaSessionPrivate::handleIceEvents (OrtpEvent *ev) { case LinphoneCallOutgoingInit: stopStreamsForIceGathering(); if (isReadyForInvite()) - q->startInvite(nullptr); + q->startInvite(nullptr, ""); break; case LinphoneCallIdle: stopStreamsForIceGathering(); @@ -4249,7 +4249,7 @@ void MediaSession::startIncomingNotification () { CallSession::startIncomingNotification(); } -int MediaSession::startInvite (const Address *destination) { +int MediaSession::startInvite (const Address *destination, const string &subject) { L_D(MediaSession); linphone_core_stop_dtmf_stream(d->core); d->makeLocalMediaDescription(); @@ -4265,7 +4265,7 @@ int MediaSession::startInvite (const Address *destination) { sal_call_set_local_media_description(d->op, d->localDesc); } - int result = CallSession::startInvite(destination); + int result = CallSession::startInvite(destination, subject); if (result < 0) { if (d->state == LinphoneCallError) d->stopStreams(); diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index e27c1c7e2..27770ebb1 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -48,7 +48,7 @@ public: LinphoneStatus resume (); void sendVfuRequest (); void startIncomingNotification () override; - int startInvite (const Address *destination) override; + int startInvite (const Address *destination, const std::string &subject) override; void startRecording (); void stopRecording (); LinphoneStatus update (const MediaSessionParams *msp); From 9ce0960e320b5d611d8d6ae504962214c2eeedfa Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 26 Sep 2017 17:11:42 +0200 Subject: [PATCH 0193/2215] Remove declaration of function that is no longer defined. --- include/linphone/api/c-chat-message.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index 7b82dcccd..b62cde920 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -200,11 +200,6 @@ LINPHONE_PUBLIC unsigned int linphone_chat_message_store(LinphoneChatMessage *ms */ LINPHONE_PUBLIC LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage* message); -/** - * Duplicate a LinphoneChatMessage -**/ -LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* message); - /** * Get if the message was encrypted when transfered * @param[in] message #LinphoneChatMessage obj @@ -371,4 +366,4 @@ LINPHONE_PUBLIC LinphoneChatMessageCbs * linphone_chat_message_get_callbacks(con } #endif // ifdef __cplusplus -#endif // ifndef _C_CHAT_MESSAGE_H_ \ No newline at end of file +#endif // ifndef _C_CHAT_MESSAGE_H_ From a67a7fbcc311dc44eff27d3ef552e74237f2543b Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 26 Sep 2017 17:43:18 +0200 Subject: [PATCH 0194/2215] feat(c-wrapper): IsDefinedCppObject check inheritance and consistency between cpp and c objects \o/ --- src/c-wrapper/internal/c-tools.h | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 9cffcacff..9d6e90999 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -36,7 +36,10 @@ LINPHONE_BEGIN_NAMESPACE template struct CppTypeToCType { - enum { defined = false }; + enum { + defined = false, + isSubtype = false + }; typedef void type; }; @@ -58,17 +61,27 @@ private: }; }; + template + struct IsDefinedCppObject { + enum { + value = CppTypeToCType::defined && ( + !CppTypeToCType::isSubtype || + std::is_base_of::type>::type, CppType>::value + ) + }; + }; + template struct IsDefinedNotClonableCppObject { enum { - value = CppTypeToCType::defined && std::is_base_of::value + value = IsDefinedCppObject::value && std::is_base_of::value }; }; template struct IsDefinedClonableCppObject { enum { - value = CppTypeToCType::defined && std::is_base_of::value + value = IsDefinedCppObject::value && std::is_base_of::value }; }; @@ -340,7 +353,10 @@ LINPHONE_END_NAMESPACE class CPP_TYPE; \ template<> \ struct CppTypeToCType { \ - enum { defined = true }; \ + enum { \ + defined = true, \ + isSubtype = false \ + }; \ typedef Linphone ## C_TYPE type; \ }; \ template<> \ @@ -359,9 +375,13 @@ LINPHONE_END_NAMESPACE #define L_REGISTER_SUBTYPE(CPP_TYPE, CPP_SUBTYPE) \ LINPHONE_BEGIN_NAMESPACE \ class CPP_SUBTYPE; \ + static_assert(CppTypeToCType::defined, "Type base is not defined"); \ template<> \ struct CppTypeToCType { \ - enum { defined = true }; \ + enum { \ + defined = true, \ + isSubtype = true \ + }; \ typedef CppTypeToCType::type type; \ }; \ template<> \ From 7a54c7fe29b28250893adfa5d491dee1014937e7 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 27 Sep 2017 09:33:56 +0200 Subject: [PATCH 0195/2215] feat(c-wrapper): better names --- src/c-wrapper/internal/c-tools.h | 82 ++++++++++++++------------------ 1 file changed, 35 insertions(+), 47 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 9d6e90999..6f886310e 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -35,23 +35,20 @@ LINPHONE_BEGIN_NAMESPACE template -struct CppTypeToCType { +struct CppTypeMetaInfo { enum { defined = false, isSubtype = false }; - typedef void type; + typedef void cType; }; template -struct CTypeToCppType { +struct CTypeMetaInfo { enum { defined = false }; - typedef void type; + typedef void cppType; }; -template -struct CObjectInitializer {}; - class Wrapper { private: template @@ -64,9 +61,9 @@ private: template struct IsDefinedCppObject { enum { - value = CppTypeToCType::defined && ( - !CppTypeToCType::isSubtype || - std::is_base_of::type>::type, CppType>::value + value = CppTypeMetaInfo::defined && ( + !CppTypeMetaInfo::isSubtype || + std::is_base_of::cType>::cppType, CppType>::value ) }; }; @@ -116,7 +113,7 @@ public: template< typename CType, - typename CppType = typename CTypeToCppType::type, + typename CppType = typename CTypeMetaInfo::cppType, typename = typename std::enable_if::value, CppType>::type > static constexpr std::shared_ptr getCppPtrFromC (CType *cObject) { @@ -125,7 +122,7 @@ public: template< typename CType, - typename CppType = typename CTypeToCppType::type, + typename CppType = typename CTypeMetaInfo::cppType, typename = typename std::enable_if::value, CppType>::type > static constexpr std::shared_ptr getCppPtrFromC (const CType *cObject) { @@ -134,7 +131,7 @@ public: template< typename CType, - typename CppType = typename CTypeToCppType::type, + typename CppType = typename CTypeMetaInfo::cppType, typename = typename std::enable_if::value, CppType>::type > static constexpr CppType *getCppPtrFromC (CType *cObject) { @@ -143,7 +140,7 @@ public: template< typename CType, - typename CppType = typename CTypeToCppType::type, + typename CppType = typename CTypeMetaInfo::cppType, typename = typename std::enable_if::value, CppType>::type > static constexpr const CppType *getCppPtrFromC (const CType *cObject) { @@ -185,15 +182,15 @@ public: typename CppType, typename = typename std::enable_if::value, CppType>::type > - static inline typename CppTypeToCType::type *getCBackPtr (const std::shared_ptr &cppObject) { - typedef typename CppTypeToCType::type RetType; + static inline typename CppTypeMetaInfo::cType *getCBackPtr (const std::shared_ptr &cppObject) { + typedef typename CppTypeMetaInfo::cType RetType; Variant variant = cppObject->getProperty("LinphonePrivate::Wrapper::cBackPtr"); void *value = variant.getValue(); if (value) return reinterpret_cast(value); - RetType *cObject = CObjectInitializer::init(); + RetType *cObject = CppTypeMetaInfo::init(); setCppPtrFromC(cObject, cppObject); return cObject; } @@ -202,7 +199,7 @@ public: typename CppType, typename = typename std::enable_if::value, CppType>::type > - static inline typename CppTypeToCType::type *getCBackPtr (CppType *cppObject) { + static inline typename CppTypeMetaInfo::cType *getCBackPtr (CppType *cppObject) { return getCBackPtr(std::static_pointer_cast(cppObject->shared_from_this())); } @@ -210,15 +207,15 @@ public: typename CppType, typename = typename std::enable_if::value, CppType>::type > - static inline typename CppTypeToCType::type *getCBackPtr (const CppType *cppObject) { - typedef typename CppTypeToCType::type RetType; + static inline typename CppTypeMetaInfo::cType *getCBackPtr (const CppType *cppObject) { + typedef typename CppTypeMetaInfo::cType RetType; Variant v = cppObject->getProperty("LinphonePrivate::Wrapper::cBackPtr"); void *value = v.getValue(); if (value) return reinterpret_cast(value); - RetType *cObject = CObjectInitializer::init(); + RetType *cObject = CppTypeMetaInfo::init(); setCppPtrFromC(cObject, cppObject); return cObject; } @@ -285,7 +282,7 @@ public: template< typename CType, - typename CppType = typename CTypeToCppType::type, + typename CppType = typename CTypeMetaInfo::cppType, typename = typename std::enable_if::value, CppType>::type > static inline std::list> getResolvedCppListFromCList (const bctbx_list_t *cList) { @@ -297,7 +294,7 @@ public: template< typename CType, - typename CppType = typename CTypeToCppType::type, + typename CppType = typename CTypeMetaInfo::cppType, typename = typename std::enable_if::value, CppType>::type > static inline std::list getResolvedCppListFromCList (const bctbx_list_t *cList) { @@ -352,54 +349,45 @@ LINPHONE_END_NAMESPACE LINPHONE_BEGIN_NAMESPACE \ class CPP_TYPE; \ template<> \ - struct CppTypeToCType { \ + struct CppTypeMetaInfo { \ enum { \ defined = true, \ isSubtype = false \ }; \ - typedef Linphone ## C_TYPE type; \ - }; \ - template<> \ - struct CTypeToCppType { \ - enum { defined = true }; \ - typedef CPP_TYPE type; \ - }; \ - template<> \ - struct CObjectInitializer { \ + typedef Linphone ## C_TYPE cType; \ static inline Linphone ## C_TYPE *init () { \ return _linphone_ ## C_TYPE ## _init(); \ } \ }; \ + template<> \ + struct CTypeMetaInfo { \ + enum { defined = true }; \ + typedef CPP_TYPE cppType; \ + }; \ LINPHONE_END_NAMESPACE #define L_REGISTER_SUBTYPE(CPP_TYPE, CPP_SUBTYPE) \ LINPHONE_BEGIN_NAMESPACE \ class CPP_SUBTYPE; \ - static_assert(CppTypeToCType::defined, "Type base is not defined"); \ + static_assert(CppTypeMetaInfo::defined, "Base type is not defined"); \ template<> \ - struct CppTypeToCType { \ + struct CppTypeMetaInfo { \ enum { \ defined = true, \ isSubtype = true \ }; \ - typedef CppTypeToCType::type type; \ - }; \ - template<> \ - struct CObjectInitializer { \ - static inline typename CppTypeToCType::type *init () { \ - return CObjectInitializer::init(); \ + typedef CppTypeMetaInfo::cType cType; \ + static inline typename CppTypeMetaInfo::cType *init () { \ + return CppTypeMetaInfo::init(); \ } \ }; \ LINPHONE_END_NAMESPACE -#define L_ASSERT_C_TYPE(C_TYPE) \ - static_assert(LINPHONE_NAMESPACE::CTypeToCppType::defined, "Type is not defined."); \ - #define L_CPP_TYPE_OF_C_TYPE(C_TYPE) \ - LINPHONE_NAMESPACE::CTypeToCppType::type + LINPHONE_NAMESPACE::CTypeMetaInfo::cppType #define L_CPP_TYPE_OF_C_OBJECT(C_OBJECT) \ - LINPHONE_NAMESPACE::CTypeToCppType::type>::type>::type + LINPHONE_NAMESPACE::CTypeMetaInfo::type>::type>::cppType // ----------------------------------------------------------------------------- // C object declaration. @@ -425,7 +413,7 @@ LINPHONE_END_NAMESPACE // Declare clonable wrapped C object. #define L_DECLARE_C_CLONABLE_STRUCT_IMPL(C_TYPE, ...) \ - L_ASSERT_C_TYPE(C_TYPE) \ + static_assert(LINPHONE_NAMESPACE::CTypeMetaInfo::defined, "Type is not defined."); \ struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ L_CPP_TYPE_OF_C_TYPE(C_TYPE) *cppPtr; \ From f8f9c93e3ba19053d61292bd517da5d691dd3807 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 27 Sep 2017 10:36:36 +0200 Subject: [PATCH 0196/2215] fix(api/c-address): use wrapper macros --- src/c-wrapper/api/c-address.cpp | 72 ++++++++++++++++----------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/src/c-wrapper/api/c-address.cpp b/src/c-wrapper/api/c-address.cpp index 640ef6f03..e258d888a 100644 --- a/src/c-wrapper/api/c-address.cpp +++ b/src/c-wrapper/api/c-address.cpp @@ -34,8 +34,8 @@ LinphoneAddress *linphone_address_new (const char *address) { return nullptr; } - LinphoneAddress *object = _linphone_Address_init(); - object->cppPtr = cppPtr; + LinphoneAddress *object = L_INIT(Address); + L_SET_CPP_PTR_FROM_C_OBJECT(object, cppPtr); return object; } @@ -53,135 +53,135 @@ void linphone_address_unref (LinphoneAddress *address) { } const char *linphone_address_get_scheme (const LinphoneAddress *address) { - return L_STRING_TO_C(address->cppPtr->getScheme()); + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getScheme()); } const char *linphone_address_get_display_name (const LinphoneAddress *address) { - return L_STRING_TO_C(address->cppPtr->getDisplayName()); + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getDisplayName()); } LinphoneStatus linphone_address_set_display_name (LinphoneAddress *address, const char *display_name) { - return !address->cppPtr->setDisplayName(L_C_TO_STRING(display_name)); + return !L_GET_CPP_PTR_FROM_C_OBJECT(address)->setDisplayName(L_C_TO_STRING(display_name)); } const char *linphone_address_get_username (const LinphoneAddress *address) { - return L_STRING_TO_C(address->cppPtr->getUsername()); + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getUsername()); } LinphoneStatus linphone_address_set_username (LinphoneAddress *address, const char *username) { - return !address->cppPtr->setUsername(L_C_TO_STRING(username)); + return !L_GET_CPP_PTR_FROM_C_OBJECT(address)->setUsername(L_C_TO_STRING(username)); } const char *linphone_address_get_domain (const LinphoneAddress *address) { - return L_STRING_TO_C(address->cppPtr->getDomain()); + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getDomain()); } LinphoneStatus linphone_address_set_domain (LinphoneAddress *address, const char *domain) { - return !address->cppPtr->setDomain(L_C_TO_STRING(domain)); + return !L_GET_CPP_PTR_FROM_C_OBJECT(address)->setDomain(L_C_TO_STRING(domain)); } int linphone_address_get_port (const LinphoneAddress *address) { - return address->cppPtr->getPort(); + return L_GET_CPP_PTR_FROM_C_OBJECT(address)->getPort(); } LinphoneStatus linphone_address_set_port (LinphoneAddress *address, int port) { - return !address->cppPtr->setPort(port); + return !L_GET_CPP_PTR_FROM_C_OBJECT(address)->setPort(port); } LinphoneTransportType linphone_address_get_transport (const LinphoneAddress *address) { - return static_cast(address->cppPtr->getTransport()); + return static_cast(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getTransport()); } LinphoneStatus linphone_address_set_transport (LinphoneAddress *address, LinphoneTransportType transport) { - return !address->cppPtr->setTransport(static_cast(transport)); + return !L_GET_CPP_PTR_FROM_C_OBJECT(address)->setTransport(static_cast(transport)); } bool_t linphone_address_get_secure (const LinphoneAddress *address) { - return address->cppPtr->getSecure(); + return L_GET_CPP_PTR_FROM_C_OBJECT(address)->getSecure(); } void linphone_address_set_secure (LinphoneAddress *address, bool_t enabled) { - address->cppPtr->setSecure(enabled); + L_GET_CPP_PTR_FROM_C_OBJECT(address)->setSecure(enabled); } bool_t linphone_address_is_sip (const LinphoneAddress *address) { - return address->cppPtr->isSip(); + return L_GET_CPP_PTR_FROM_C_OBJECT(address)->isSip(); } const char *linphone_address_get_method_param (const LinphoneAddress *address) { - return L_STRING_TO_C(address->cppPtr->getMethodParam()); + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getMethodParam()); } void linphone_address_set_method_param (LinphoneAddress *address, const char *method_param) { - address->cppPtr->setMethodParam(L_C_TO_STRING(method_param)); + L_GET_CPP_PTR_FROM_C_OBJECT(address)->setMethodParam(L_C_TO_STRING(method_param)); } const char *linphone_address_get_password (const LinphoneAddress *address) { - return L_STRING_TO_C(address->cppPtr->getPassword()); + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getPassword()); } void linphone_address_set_password (LinphoneAddress *address, const char *password) { - address->cppPtr->setPassword(L_C_TO_STRING(password)); + L_GET_CPP_PTR_FROM_C_OBJECT(address)->setPassword(L_C_TO_STRING(password)); } void linphone_address_clean (LinphoneAddress *address) { - address->cppPtr->clean(); + L_GET_CPP_PTR_FROM_C_OBJECT(address)->clean(); } char *linphone_address_as_string (const LinphoneAddress *address) { - return ms_strdup(address->cppPtr->asString().c_str()); + return ms_strdup(L_GET_CPP_PTR_FROM_C_OBJECT(address)->asString().c_str()); } char *linphone_address_as_string_uri_only (const LinphoneAddress *address) { - return ms_strdup(address->cppPtr->asStringUriOnly().c_str()); + return ms_strdup(L_GET_CPP_PTR_FROM_C_OBJECT(address)->asStringUriOnly().c_str()); } bool_t linphone_address_weak_equal (const LinphoneAddress *address1, const LinphoneAddress *address2) { - return address1->cppPtr->weakEqual(*address2->cppPtr); + return L_GET_CPP_PTR_FROM_C_OBJECT(address1)->weakEqual(*L_GET_CPP_PTR_FROM_C_OBJECT(address2)); } bool_t linphone_address_equal (const LinphoneAddress *address1, const LinphoneAddress *address2) { - return *address1->cppPtr == *address2->cppPtr; + return *L_GET_CPP_PTR_FROM_C_OBJECT(address1) == *L_GET_CPP_PTR_FROM_C_OBJECT(address2); } const char *linphone_address_get_header (const LinphoneAddress *address, const char *header_name) { - return L_STRING_TO_C(address->cppPtr->getHeaderValue(L_C_TO_STRING(header_name))); + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getHeaderValue(L_C_TO_STRING(header_name))); } void linphone_address_set_header (LinphoneAddress *address, const char *header_name, const char *header_value) { - address->cppPtr->setHeader(L_C_TO_STRING(header_name), L_C_TO_STRING(header_value)); + L_GET_CPP_PTR_FROM_C_OBJECT(address)->setHeader(L_C_TO_STRING(header_name), L_C_TO_STRING(header_value)); } bool_t linphone_address_has_param (const LinphoneAddress *address, const char *param_name) { - return address->cppPtr->hasParam(L_C_TO_STRING(param_name)); + return L_GET_CPP_PTR_FROM_C_OBJECT(address)->hasParam(L_C_TO_STRING(param_name)); } const char *linphone_address_get_param (const LinphoneAddress *address, const char *param_name) { - return L_STRING_TO_C(address->cppPtr->getParamValue(L_C_TO_STRING(param_name))); + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getParamValue(L_C_TO_STRING(param_name))); } void linphone_address_set_param (LinphoneAddress *address, const char *param_name, const char *param_value) { - address->cppPtr->setParam(L_C_TO_STRING(param_name), L_C_TO_STRING(param_value)); + L_GET_CPP_PTR_FROM_C_OBJECT(address)->setParam(L_C_TO_STRING(param_name), L_C_TO_STRING(param_value)); } void linphone_address_set_params (LinphoneAddress *address, const char *params) { - address->cppPtr->setParams(L_C_TO_STRING(params)); + L_GET_CPP_PTR_FROM_C_OBJECT(address)->setParams(L_C_TO_STRING(params)); } bool_t linphone_address_has_uri_param (const LinphoneAddress *address, const char *uri_param_name) { - return address->cppPtr->hasUriParam(L_C_TO_STRING(uri_param_name)); + return L_GET_CPP_PTR_FROM_C_OBJECT(address)->hasUriParam(L_C_TO_STRING(uri_param_name)); } const char *linphone_address_get_uri_param (const LinphoneAddress *address, const char *uri_param_name) { - return L_STRING_TO_C(address->cppPtr->getUriParamValue(L_C_TO_STRING(uri_param_name))); + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(address)->getUriParamValue(L_C_TO_STRING(uri_param_name))); } void linphone_address_set_uri_param (LinphoneAddress *address, const char *uri_param_name, const char *uri_param_value) { - address->cppPtr->setUriParam(L_C_TO_STRING(uri_param_name), L_C_TO_STRING(uri_param_value)); + L_GET_CPP_PTR_FROM_C_OBJECT(address)->setUriParam(L_C_TO_STRING(uri_param_name), L_C_TO_STRING(uri_param_value)); } void linphone_address_set_uri_params (LinphoneAddress *address, const char *params) { - address->cppPtr->setUriParams(L_C_TO_STRING(params)); + L_GET_CPP_PTR_FROM_C_OBJECT(address)->setUriParams(L_C_TO_STRING(params)); } void linphone_address_destroy (LinphoneAddress *address) { @@ -189,5 +189,5 @@ void linphone_address_destroy (LinphoneAddress *address) { } bool_t linphone_address_is_secure (const LinphoneAddress *address) { - return address->cppPtr->getSecure(); + return L_GET_CPP_PTR_FROM_C_OBJECT(address)->getSecure(); } From 1cff67c57ac07fe954128ff2dbf8189b970ccf27 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 27 Sep 2017 10:56:57 +0200 Subject: [PATCH 0197/2215] feat(c-wrapper): setCppPtrFromC is more secure, check types --- src/c-wrapper/internal/c-tools.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 6f886310e..736187980 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -152,20 +152,22 @@ public: // --------------------------------------------------------------------------- template< - typename CppType, + typename CType, + typename CppType = typename CTypeMetaInfo::cppType, typename = typename std::enable_if::value, CppType>::type > - static inline void setCppPtrFromC (void *cObject, const std::shared_ptr &cppObject) { - static_cast *>(cObject)->cppPtr = cppObject; + static inline void setCppPtrFromC (CType *cObject, const std::shared_ptr &cppObject) { + reinterpret_cast *>(cObject)->cppPtr = cppObject; cppObject->setProperty("LinphonePrivate::Wrapper::cBackPtr", cObject); } template< - typename CppType, + typename CType, + typename CppType = typename CTypeMetaInfo::cppType, typename = typename std::enable_if::value, CppType>::type > - static inline void setCppPtrFromC (void *cObject, const CppType *cppObject) { - CppType **cppObjectAddr = &static_cast *>(cObject)->cppPtr; + static inline void setCppPtrFromC (CType *cObject, const CppType *cppObject) { + CppType **cppObjectAddr = &reinterpret_cast *>(cObject)->cppPtr; if (*cppObjectAddr == cppObject) return; delete *cppObjectAddr; From 950def6133bbd93c826e1fc4b7ff3626fc257a60 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 27 Sep 2017 11:36:46 +0200 Subject: [PATCH 0198/2215] Removed TODOs from c-chat-message --- src/c-wrapper/api/c-chat-message.cpp | 27 ++-- src/chat/chat-message-p.h | 6 +- src/chat/chat-message.cpp | 206 +++++++++++++-------------- src/chat/chat-message.h | 42 +++--- 4 files changed, 133 insertions(+), 148 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 9fe96f8b4..0b0ead9b3 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -43,7 +43,6 @@ L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(ChatMessage, LinphoneChatMessageCbs *cbs; LinphoneAddress *from; // cache for shared_ptr
    LinphoneAddress *to; // cache for shared_ptr
    - LinphoneErrorInfo *ei; LinphoneChatMessageStateChangedCb message_state_changed_cb; void* message_state_changed_user_data; ) @@ -245,6 +244,10 @@ const char *linphone_chat_message_get_custom_header(LinphoneChatMessage *msg, co return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getSalCustomHeaderValue(header_name).c_str(); } +const LinphoneErrorInfo *linphone_chat_message_get_error_info(LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getErrorInfo(); +} + // ============================================================================= // Methods // ============================================================================= @@ -273,19 +276,16 @@ void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMe L_GET_CPP_PTR_FROM_C_OBJECT(msg)->updateState((LinphonePrivate::ChatMessage::State) new_state); } void linphone_chat_message_send_imdn(LinphoneChatMessage *msg, ImdnType imdn_type, LinphoneReason reason) { - //TODO - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->sendImdn(); + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->sendImdn(imdn_type, reason); } void linphone_chat_message_deactivate(LinphoneChatMessage *msg){ L_GET_CPP_PTR_FROM_C_OBJECT(msg)->cancelFileTransfer(); - // TODO ? - //msg->chat_room = NULL; + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setChatRoom(nullptr); } void linphone_chat_message_send_delivery_notification(LinphoneChatMessage *msg, LinphoneReason reason) { - //TODO - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->sendDeliveryNotification(); + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->sendDeliveryNotification(reason); } void linphone_chat_message_send_display_notification(LinphoneChatMessage *msg) { @@ -334,14 +334,11 @@ int linphone_chat_message_set_text(LinphoneChatMessage *msg, const char* text) { } LinphoneContent *linphone_chat_message_get_file_transfer_information(LinphoneChatMessage *msg) { - //return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFileTransferInformation(); - //TODO - return NULL; + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFileTransferInformation(); } void linphone_chat_message_set_file_transfer_information(LinphoneChatMessage *msg, LinphoneContent *content) { - //TODO - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFileTransferInformation(nullptr); + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFileTransferInformation(content); } // ============================================================================= @@ -359,12 +356,6 @@ const LinphoneAddress *linphone_chat_message_get_local_address(LinphoneChatMessa return linphone_chat_message_get_to_address(msg); } -const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg) { - if (!msg->ei) ((LinphoneChatMessage*)msg)->ei = linphone_error_info_new(); /*let's do it mutable*/ - linphone_error_info_from_sal_op(msg->ei, linphone_chat_message_get_sal_op(msg)); - return msg->ei; -} - LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage *msg) { return linphone_error_info_get_reason(linphone_chat_message_get_error_info(msg)); } diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 2b756812f..17da7bb79 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -54,10 +54,14 @@ private: std::shared_ptr internalContent; std::unordered_map customHeaders; std::shared_ptr eventsDb; - std::shared_ptr errorInfo; + LinphoneErrorInfo * errorInfo; belle_http_request_t *httpRequest; SalOp *salOp; SalCustomHeader *salCustomHeaders; + // Used for compatibility with previous C API + std::string cContentType; + std::string cText; + LinphoneContent *cFileTransferInformation; L_DECLARE_PUBLIC(ChatMessage); }; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index c9bc60bae..325fcce97 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -37,14 +37,18 @@ LINPHONE_BEGIN_NAMESPACE using namespace std; -// ----------------------------------------------------------------------------- +// ============================================================================= +// ChatMessagePrivate +// ============================================================================= ChatMessagePrivate::ChatMessagePrivate (const shared_ptr &room) : chatRoom(room) {} ChatMessagePrivate::~ChatMessagePrivate () {} -// ----------------------------------------------------------------------------- +// ============================================================================= +// ChatMessage +// ============================================================================= ChatMessage::ChatMessage (const shared_ptr &room) : Object(*new ChatMessagePrivate(room)) {} @@ -59,6 +63,11 @@ shared_ptr ChatMessage::getChatRoom () const { return d->chatRoom; } +void ChatMessage::setChatRoom (shared_ptr chatRoom) { + L_D(ChatMessage); + d->chatRoom = chatRoom; +} + // ----------------------------------------------------------------------------- string ChatMessage::getExternalBodyUrl() const { @@ -215,41 +224,32 @@ void ChatMessage::setIsToBeStored(bool store) { string ChatMessage::getContentType() const { L_D(const ChatMessage); - if (d->internalContent) { - return d->internalContent->getContentType().asString(); - } - if (d->contents.size() > 0) { - return d->contents.front()->getContentType().asString(); - } - return ""; + return d->cContentType; } void ChatMessage::setContentType(string contentType) { - //TODO + L_D(ChatMessage); + d->cContentType = contentType; } string ChatMessage::getText() const { L_D(const ChatMessage); - if (d->internalContent) { - return d->internalContent->getBodyAsString(); - } - if (d->contents.size() > 0) { - return d->contents.front()->getBodyAsString(); - } - return ""; + return d->cText; } void ChatMessage::setText(string text) { - //TODO + L_D(ChatMessage); + d->cText = text; } -shared_ptr ChatMessage::getFileTransferInformation() const { - //TODO - return nullptr; +LinphoneContent * ChatMessage::getFileTransferInformation() const { + L_D(const ChatMessage); + return d->cFileTransferInformation; } -void ChatMessage::setFileTransferInformation(shared_ptr content) { - //TODO +void ChatMessage::setFileTransferInformation(LinphoneContent *content) { + L_D(ChatMessage); + d->cFileTransferInformation = content; } unsigned int ChatMessage::getStorageId() const { @@ -307,12 +307,64 @@ string ChatMessage::getSalCustomHeaderValue(string name) { return sal_custom_header_find(d->salCustomHeaders, name.c_str()); } -shared_ptr ChatMessage::getErrorInfo () const { - L_D(const ChatMessage); - //TODO +const LinphoneErrorInfo * ChatMessage::getErrorInfo() { + L_D(ChatMessage); + if (!d->errorInfo) d->errorInfo = linphone_error_info_new(); //let's do it mutable + linphone_error_info_from_sal_op(d->errorInfo, d->salOp); return d->errorInfo; } +bool ChatMessage::isReadOnly () const { + L_D(const ChatMessage); + return d->isReadOnly; +} + +list > ChatMessage::getContents () const { + L_D(const ChatMessage); + list > contents; + for (const auto &content : d->contents) + contents.push_back(content); + return contents; +} + +void ChatMessage::addContent (const shared_ptr &content) { + L_D(ChatMessage); + if (d->isReadOnly) return; + + d->contents.push_back(content); +} + +void ChatMessage::removeContent (const shared_ptr &content) { + L_D(ChatMessage); + if (d->isReadOnly) return; + + d->contents.remove(const_pointer_cast(content)); +} + +string ChatMessage::getCustomHeaderValue (const string &headerName) const { + L_D(const ChatMessage); + try { + return d->customHeaders.at(headerName); + } catch (const exception &) { + // Key doesn't exist. + } + return ""; +} + +void ChatMessage::addCustomHeader (const string &headerName, const string &headerValue) { + L_D(ChatMessage); + if (d->isReadOnly) return; + + d->customHeaders[headerName] = headerValue; +} + +void ChatMessage::removeCustomHeader (const string &headerName) { + L_D(ChatMessage); + if (d->isReadOnly) return; + + d->customHeaders.erase(headerName); +} + // ----------------------------------------------------------------------------- void ChatMessage::updateState(State state) { @@ -325,6 +377,26 @@ void ChatMessage::updateState(State state) { }*/ } +void ChatMessage::send () { + L_D(ChatMessage); + + if (d->contents.size() > 1) { + MultipartChatMessageModifier mcmm; + mcmm.encode(d); + } + + LinphoneCore *lc = getChatRoom()->getCore(); + LpConfig *lpc = linphone_core_get_config(lc); + if (lp_config_get_int(lpc, "sip", "use_cpim", 0) == 1) { + CpimChatMessageModifier ccmm; + ccmm.encode(d); + } + + // TODO. + + d->isReadOnly = true; +} + void ChatMessage::reSend() { //TODO /*LinphoneChatMessageState state = linphone_chat_message_get_state(msg); @@ -482,7 +554,7 @@ static void linphone_chat_process_response_from_get_file(void *data, const belle return content; }*/ -void ChatMessage::sendImdn() { +void ChatMessage::sendImdn(ImdnType imdnType, LinphoneReason reason) { //TODO /*char *content = linphone_chat_message_create_imdn_xml(cm, imdn_type, reason); if (content) { @@ -491,7 +563,7 @@ void ChatMessage::sendImdn() { }*/ } -void ChatMessage::sendDeliveryNotification() { +void ChatMessage::sendDeliveryNotification(LinphoneReason reason) { //TODO /*LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(cm); LinphoneCore *lc = linphone_chat_room_get_core(cr); @@ -1122,82 +1194,4 @@ int ChatMessage::putCharacter(uint32_t character) { return -1; } -// ----------------------------------------------------------------------------- - -void ChatMessage::send () { - L_D(ChatMessage); - - if (d->contents.size() > 1) { - MultipartChatMessageModifier mcmm; - mcmm.encode(d); - } - - LinphoneCore *lc = getChatRoom()->getCore(); - LpConfig *lpc = linphone_core_get_config(lc); - if (lp_config_get_int(lpc, "sip", "use_cpim", 0) == 1) { - CpimChatMessageModifier ccmm; - ccmm.encode(d); - } - - // TODO. - - d->isReadOnly = true; -} - -bool ChatMessage::containsReadableText () const { - // TODO: Check content type. - return true; -} - -bool ChatMessage::isReadOnly () const { - L_D(const ChatMessage); - return d->isReadOnly; -} - -list > ChatMessage::getContents () const { - L_D(const ChatMessage); - list > contents; - for (const auto &content : d->contents) - contents.push_back(content); - return contents; -} - -void ChatMessage::addContent (const shared_ptr &content) { - L_D(ChatMessage); - if (d->isReadOnly) return; - - d->contents.push_back(content); -} - -void ChatMessage::removeContent (const shared_ptr &content) { - L_D(ChatMessage); - if (d->isReadOnly) return; - - d->contents.remove(const_pointer_cast(content)); -} - -string ChatMessage::getCustomHeaderValue (const string &headerName) const { - L_D(const ChatMessage); - try { - return d->customHeaders.at(headerName); - } catch (const exception &) { - // Key doesn't exist. - } - return ""; -} - -void ChatMessage::addCustomHeader (const string &headerName, const string &headerValue) { - L_D(ChatMessage); - if (d->isReadOnly) return; - - d->customHeaders[headerName] = headerValue; -} - -void ChatMessage::removeCustomHeader (const string &headerName) { - L_D(ChatMessage); - if (d->isReadOnly) return; - - d->customHeaders.erase(headerName); -} - LINPHONE_END_NAMESPACE diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index 7faa8be72..1c4ccc43f 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -64,16 +64,16 @@ public: LinphoneChatMessage * getBackPtr(); std::shared_ptr getChatRoom () const; - void setChatRoom (std::shared_ptr cr); // ----------------------------------------------------------------------------- // Methods // ----------------------------------------------------------------------------- void updateState(State state); + void send(); void reSend(); - void sendImdn(); - void sendDeliveryNotification(); + void sendImdn(ImdnType imdnType, LinphoneReason reason); + void sendDeliveryNotification(LinphoneReason reason); void sendDisplayNotification(); int uploadFile(); int downloadFile(); @@ -119,10 +119,24 @@ public: bool isToBeStored() const; void setIsToBeStored(bool store); + + const LinphoneErrorInfo * getErrorInfo (); + + bool isReadOnly () const; + + std::list > getContents () const; + void addContent (const std::shared_ptr &content); + void removeContent (const std::shared_ptr &content); + + std::string getCustomHeaderValue (const std::string &headerName) const; + void addCustomHeader (const std::string &headerName, const std::string &headerValue); + void removeCustomHeader (const std::string &headerName); // ----------------------------------------------------------------------------- // Deprecated methods, only used for C wrapper // ----------------------------------------------------------------------------- + + void setChatRoom (std::shared_ptr chatRoom); std::string getContentType() const; void setContentType(std::string contentType); @@ -130,8 +144,8 @@ public: std::string getText() const; void setText(std::string text); - std::shared_ptr getFileTransferInformation() const; - void setFileTransferInformation(std::shared_ptr content); + LinphoneContent * getFileTransferInformation() const; + void setFileTransferInformation(LinphoneContent *content); unsigned int getStorageId() const; void setStorageId(unsigned int id); @@ -150,24 +164,6 @@ public: void addSalCustomHeader(std::string name, std::string value); void removeSalCustomHeader(std::string name); std::string getSalCustomHeaderValue(std::string name); - - // ----------------------------------------------------------------------------- - - std::shared_ptr getErrorInfo () const; - - void send (); - - bool containsReadableText () const; - - bool isReadOnly () const; - - std::list > getContents () const; - void addContent (const std::shared_ptr &content); - void removeContent (const std::shared_ptr &content); - - std::string getCustomHeaderValue (const std::string &headerName) const; - void addCustomHeader (const std::string &headerName, const std::string &headerValue); - void removeCustomHeader (const std::string &headerName); protected: explicit ChatMessage (ChatMessagePrivate &p); From e46b4630dae53cae4d8db6b668c4753350178eed Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 27 Sep 2017 12:14:35 +0200 Subject: [PATCH 0199/2215] feat(c-wrapper): deal with shared from this --- src/c-wrapper/internal/c-tools.h | 52 +++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 736187980..23aed93d0 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -32,6 +32,12 @@ // Internal. // ============================================================================= +#ifdef DEBUG + #define CHECK_CPP_OBJECT_AT_RUNTIME(CPP_OBJECT) checkCppObjectAtRuntime(CPP_OBJECT) +#else + #define CHECK_CPP_OBJECT_AT_RUNTIME(CPP_OBJECT) +#endif + LINPHONE_BEGIN_NAMESPACE template @@ -45,7 +51,9 @@ struct CppTypeMetaInfo { template struct CTypeMetaInfo { - enum { defined = false }; + enum { + defined = false + }; typedef void cppType; }; @@ -94,6 +102,15 @@ private: CType *cppPtr; }; + // --------------------------------------------------------------------------- + // Runtime checker. + // --------------------------------------------------------------------------- + + static inline void fatal (const char *message) { + std::cout << "[FATAL C-WRAPPER]" << message << std::endl; + exit(1); + } + public: // --------------------------------------------------------------------------- // Get private data of cpp Object. @@ -103,7 +120,7 @@ public: typename CppType, typename = typename std::enable_if::value, CppType>::type > - static constexpr decltype (std::declval().getPrivate()) getPrivate (CppType *cppObject) { + static constexpr decltype(std::declval().getPrivate()) getPrivate (CppType *cppObject) { return cppObject->getPrivate(); } @@ -190,7 +207,7 @@ public: Variant variant = cppObject->getProperty("LinphonePrivate::Wrapper::cBackPtr"); void *value = variant.getValue(); if (value) - return reinterpret_cast(value); + return static_cast(value); RetType *cObject = CppTypeMetaInfo::init(); setCppPtrFromC(cObject, cppObject); @@ -202,7 +219,14 @@ public: typename = typename std::enable_if::value, CppType>::type > static inline typename CppTypeMetaInfo::cType *getCBackPtr (CppType *cppObject) { - return getCBackPtr(std::static_pointer_cast(cppObject->shared_from_this())); + try { + return getCBackPtr(std::static_pointer_cast(cppObject->shared_from_this())); + } catch (const std::bad_weak_ptr &e) { + fatal(e.what()); + } + + L_ASSERT(false); + return nullptr; } template< @@ -212,10 +236,10 @@ public: static inline typename CppTypeMetaInfo::cType *getCBackPtr (const CppType *cppObject) { typedef typename CppTypeMetaInfo::cType RetType; - Variant v = cppObject->getProperty("LinphonePrivate::Wrapper::cBackPtr"); - void *value = v.getValue(); + Variant variant = cppObject->getProperty("LinphonePrivate::Wrapper::cBackPtr"); + void *value = variant.getValue(); if (value) - return reinterpret_cast(value); + return static_cast(value); RetType *cObject = CppTypeMetaInfo::init(); setCppPtrFromC(cObject, cppObject); @@ -241,7 +265,7 @@ public: // --------------------------------------------------------------------------- template - static inline bctbx_list_t *getCListFromCppList (const std::list &cppList) { + static inline bctbx_list_t *getCListFromCppList (const std::list &cppList) { bctbx_list_t *result = nullptr; for (const auto &value : cppList) result = bctbx_list_append(result, value); @@ -249,7 +273,7 @@ public: } template - static inline std::list getCppListFromCList (const bctbx_list_t *cList) { + static inline std::list getCppListFromCList (const bctbx_list_t *cList) { std::list result; for (auto it = cList; it; it = bctbx_list_next(it)) result.push_back(static_cast(bctbx_list_get_data(it))); @@ -290,7 +314,7 @@ public: static inline std::list> getResolvedCppListFromCList (const bctbx_list_t *cList) { std::list> result; for (auto it = cList; it; it = bctbx_list_next(it)) - result.push_back(getCppPtrFromC(reinterpret_cast(bctbx_list_get_data(it)))); + result.push_back(getCppPtrFromC(static_cast(bctbx_list_get_data(it)))); return result; } @@ -302,7 +326,7 @@ public: static inline std::list getResolvedCppListFromCList (const bctbx_list_t *cList) { std::list result; for (auto it = cList; it; it = bctbx_list_next(it)) - result.push_back(*getCppPtrFromC(reinterpret_cast(bctbx_list_get_data(it)))); + result.push_back(*getCppPtrFromC(static_cast(bctbx_list_get_data(it)))); return result; } @@ -318,7 +342,7 @@ LINPHONE_END_NAMESPACE #define L_INTERNAL_DECLARE_C_OBJECT_FUNCTIONS(C_TYPE, CONSTRUCTOR, DESTRUCTOR) \ BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_TYPE); \ - Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init() { \ + Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init () { \ Linphone ## C_TYPE * object = belle_sip_object_new(Linphone ## C_TYPE); \ new(&object->cppPtr) std::shared_ptr(); \ CONSTRUCTOR(object); \ @@ -443,7 +467,7 @@ LINPHONE_END_NAMESPACE #define L_DECLARE_C_OBJECT_NEW_DEFAULT(C_TYPE, C_NAME) \ Linphone ## C_TYPE * linphone_ ## C_NAME ## _new() { \ - Linphone ## C_TYPE * object = _linphone_ ## C_TYPE ## _init(); \ + Linphone ## C_TYPE *object = _linphone_ ## C_TYPE ## _init(); \ object->cppPtr = std::make_shared(); \ return object; \ } @@ -457,7 +481,7 @@ LINPHONE_END_NAMESPACE #define L_C_TO_STRING(STR) ((STR) == NULL ? std::string() : (STR)) // Call the init function of wrapped C object. -#define L_INIT(C_TYPE) _linphone_ ## C_TYPE ## _init () +#define L_INIT(C_TYPE) _linphone_ ## C_TYPE ## _init() // Get/set the cpp-ptr of a wrapped C object. #define L_GET_CPP_PTR_FROM_C_OBJECT_1_ARGS(C_OBJECT) \ From 68b9c2f4259a2dfca5b6684f4636c66ead88f367 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 27 Sep 2017 14:29:02 +0200 Subject: [PATCH 0200/2215] feat(c-wrapper): add runtime checks on getCppPtrFromC in debug mode --- src/c-wrapper/internal/c-tools.h | 68 +++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 23aed93d0..5a71264ec 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -32,12 +32,6 @@ // Internal. // ============================================================================= -#ifdef DEBUG - #define CHECK_CPP_OBJECT_AT_RUNTIME(CPP_OBJECT) checkCppObjectAtRuntime(CPP_OBJECT) -#else - #define CHECK_CPP_OBJECT_AT_RUNTIME(CPP_OBJECT) -#endif - LINPHONE_BEGIN_NAMESPACE template @@ -128,13 +122,34 @@ public: // Get c/cpp ptr helpers. // --------------------------------------------------------------------------- + #ifdef DEBUG + #define L_INTERNAL_WRAPPER_CONSTEXPR + #else + #define L_INTERNAL_WRAPPER_CONSTEXPR constexpr + #endif + template< typename CType, typename CppType = typename CTypeMetaInfo::cppType, typename = typename std::enable_if::value, CppType>::type > - static constexpr std::shared_ptr getCppPtrFromC (CType *cObject) { - return reinterpret_cast *>(cObject)->cppPtr; + static L_INTERNAL_WRAPPER_CONSTEXPR std::shared_ptr getCppPtrFromC (CType *cObject) { + #ifdef DEBUG + typedef typename CTypeMetaInfo::cppType BaseType; + typedef CppType DerivedType; + + std::shared_ptr cppObject = reinterpret_cast *>(cObject)->cppPtr; + if (!cppObject) + fatal("Cpp Object is null."); + + std::shared_ptr derivedCppObject = std::static_pointer_cast(cppObject); + if (!derivedCppObject) + fatal("Invalid derived cpp object."); + + return derivedCppObject; + #else + return reinterpret_cast *>(cObject)->cppPtr; + #endif } template< @@ -142,8 +157,12 @@ public: typename CppType = typename CTypeMetaInfo::cppType, typename = typename std::enable_if::value, CppType>::type > - static constexpr std::shared_ptr getCppPtrFromC (const CType *cObject) { - return reinterpret_cast *>(cObject)->cppPtr; + static L_INTERNAL_WRAPPER_CONSTEXPR std::shared_ptr getCppPtrFromC (const CType *cObject) { + #ifdef DEBUG + return getCppPtrFromC(const_cast(cObject)); + #else + return reinterpret_cast *>(cObject)->cppPtr; + #endif } template< @@ -151,8 +170,23 @@ public: typename CppType = typename CTypeMetaInfo::cppType, typename = typename std::enable_if::value, CppType>::type > - static constexpr CppType *getCppPtrFromC (CType *cObject) { - return reinterpret_cast *>(cObject)->cppPtr; + static L_INTERNAL_WRAPPER_CONSTEXPR CppType *getCppPtrFromC (CType *cObject) { + #ifdef DEBUG + typedef typename CTypeMetaInfo::cppType BaseType; + typedef CppType DerivedType; + + BaseType *cppObject = reinterpret_cast *>(cObject)->cppPtr; + if (!cppObject) + fatal("Cpp Object is null."); + + DerivedType *derivedCppObject = dynamic_cast(cppObject); + if (!derivedCppObject) + fatal("Invalid derived cpp object."); + + return derivedCppObject; + #else + return reinterpret_cast *>(cObject)->cppPtr; + #endif } template< @@ -160,10 +194,16 @@ public: typename CppType = typename CTypeMetaInfo::cppType, typename = typename std::enable_if::value, CppType>::type > - static constexpr const CppType *getCppPtrFromC (const CType *cObject) { - return reinterpret_cast *>(cObject)->cppPtr; + static L_INTERNAL_WRAPPER_CONSTEXPR const CppType *getCppPtrFromC (const CType *cObject) { + #ifdef DEBUG + return getCppPtrFromC(const_cast(cObject)); + #else + return reinterpret_cast *>(cObject)->cppPtr; + #endif } + #undef L_INTERNAL_WRAPPER_CONSTEXPR + // --------------------------------------------------------------------------- // Set c/cpp ptr helpers. // --------------------------------------------------------------------------- From b5c4007d59c7149e2eaca4d426d11b154b8b0aa8 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 27 Sep 2017 14:59:37 +0200 Subject: [PATCH 0201/2215] Change getId() to getConferenceAddress() in the conference interface. --- include/linphone/api/c-chat-room.h | 6 +++--- src/c-wrapper/api/c-chat-room.cpp | 18 +++++++++++++++--- src/chat/basic-chat-room-p.h | 2 -- src/chat/basic-chat-room.cpp | 7 +++---- src/chat/basic-chat-room.h | 2 +- src/chat/client-group-chat-room.cpp | 9 +++++---- src/chat/client-group-chat-room.h | 2 +- src/chat/real-time-text-chat-room-p.h | 2 -- src/chat/real-time-text-chat-room.cpp | 7 +++---- src/chat/real-time-text-chat-room.h | 2 +- src/conference/conference-interface.h | 2 +- src/conference/conference.cpp | 4 ++-- src/conference/conference.h | 4 ++-- 13 files changed, 37 insertions(+), 30 deletions(-) diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index b6071d0da..0b82cdb43 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -262,11 +262,11 @@ LINPHONE_PUBLIC void linphone_chat_room_add_participants (LinphoneChatRoom *cr, LINPHONE_PUBLIC bool_t linphone_chat_room_can_handle_participants (const LinphoneChatRoom *cr); /** - * Get the conference ID of the chat room. + * Get the conference address of the chat room. * @param[in] cr A LinphoneChatRoom object - * @return The conference ID of the chat room or NULL if this type of chat room is not conference based + * @return The conference address of the chat room or NULL if this type of chat room is not conference based */ -LINPHONE_PUBLIC const char * linphone_chat_room_get_id (const LinphoneChatRoom *cr); +LINPHONE_PUBLIC const LinphoneAddress *linphone_chat_room_get_conference_address (const LinphoneChatRoom *cr); /** * Get the number of participants in the chat room (that is without ourselves). diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 558b8e56c..02fd19102 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -38,6 +38,7 @@ L_DECLARE_C_OBJECT_IMPL_WITH_XTORS( ChatRoom, _linphone_chat_room_constructor, _linphone_chat_room_destructor, LinphoneChatRoomCbs *cbs; + mutable LinphoneAddress *conferenceAddressCache; LinphoneAddress *peerAddressCache; ) @@ -48,6 +49,10 @@ static void _linphone_chat_room_constructor (LinphoneChatRoom *cr) { static void _linphone_chat_room_destructor (LinphoneChatRoom *cr) { linphone_chat_room_cbs_unref(cr->cbs); cr->cbs = nullptr; + if (cr->conferenceAddressCache) { + linphone_address_unref(cr->conferenceAddressCache); + cr->conferenceAddressCache = nullptr; + } if (cr->peerAddressCache) { linphone_address_unref(cr->peerAddressCache); cr->peerAddressCache = nullptr; @@ -220,9 +225,16 @@ bool_t linphone_chat_room_can_handle_participants (const LinphoneChatRoom *cr) { return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->canHandleParticipants(); } -const char *linphone_chat_room_get_id (const LinphoneChatRoom *cr) { - string id = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getId(); - return id.empty() ? nullptr : id.c_str(); +const LinphoneAddress *linphone_chat_room_get_conference_address (const LinphoneChatRoom *cr) { + if (cr->conferenceAddressCache) { + linphone_address_unref(cr->conferenceAddressCache); + } + auto addr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getConferenceAddress(); + if (addr) + cr->conferenceAddressCache = linphone_address_new(addr->asString().c_str()); + else + cr->conferenceAddressCache = nullptr; + return cr->conferenceAddressCache; } int linphone_chat_room_get_nb_participants (const LinphoneChatRoom *cr) { diff --git a/src/chat/basic-chat-room-p.h b/src/chat/basic-chat-room-p.h index 54cd99f16..54d3d9fe5 100644 --- a/src/chat/basic-chat-room-p.h +++ b/src/chat/basic-chat-room-p.h @@ -35,8 +35,6 @@ public: virtual ~BasicChatRoomPrivate () = default; private: - std::string dummyConferenceId; - L_DECLARE_PUBLIC(BasicChatRoom); }; diff --git a/src/chat/basic-chat-room.cpp b/src/chat/basic-chat-room.cpp index c7eec4b58..1c1fba3b7 100644 --- a/src/chat/basic-chat-room.cpp +++ b/src/chat/basic-chat-room.cpp @@ -48,10 +48,9 @@ bool BasicChatRoom::canHandleParticipants () const { return false; } -const string& BasicChatRoom::getId () const { - L_D(const BasicChatRoom); - lError() << "a BasicChatRoom does not have a conference id"; - return d->dummyConferenceId; +const Address *BasicChatRoom::getConferenceAddress () const { + lError() << "a BasicChatRoom does not have a conference address"; + return nullptr; } int BasicChatRoom::getNbParticipants () const { diff --git a/src/chat/basic-chat-room.h b/src/chat/basic-chat-room.h index c464d9921..3bc723387 100644 --- a/src/chat/basic-chat-room.h +++ b/src/chat/basic-chat-room.h @@ -36,7 +36,7 @@ public: std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; bool canHandleParticipants () const override; - const std::string &getId () const override; + const Address *getConferenceAddress () const override; int getNbParticipants () const override; std::list> getParticipants () const override; void removeParticipant (const std::shared_ptr &participant) override; diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index bfd078e57..47ade072f 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -77,8 +77,8 @@ bool ClientGroupChatRoom::canHandleParticipants () const { return RemoteConference::canHandleParticipants(); } -const string& ClientGroupChatRoom::getId () const { - return RemoteConference::getId(); +const Address *ClientGroupChatRoom::getConferenceAddress () const { + return RemoteConference::getConferenceAddress(); } int ClientGroupChatRoom::getNbParticipants () const { @@ -101,6 +101,7 @@ void ClientGroupChatRoom::removeParticipants (const list void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { L_D(ClientGroupChatRoom); + conferenceAddress = addr; d->setState(ChatRoom::State::Created); } @@ -156,8 +157,8 @@ void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdm void ClientGroupChatRoom::onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const string &message) { if (state == LinphoneCallConnected) { - // TODO: Get the conference ID instead of the remote address - onConferenceCreated(session.getRemoteAddress()); + Address addr(session.getRemoteContact()); + onConferenceCreated(addr); } } diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index eab0f5a28..c795991d5 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -44,7 +44,7 @@ public: std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; bool canHandleParticipants () const override; - const std::string& getId () const override; + const Address *getConferenceAddress () const override; int getNbParticipants () const override; std::list> getParticipants () const override; void removeParticipant (const std::shared_ptr &participant) override; diff --git a/src/chat/real-time-text-chat-room-p.h b/src/chat/real-time-text-chat-room-p.h index 50ca2db1c..41a94f6af 100644 --- a/src/chat/real-time-text-chat-room-p.h +++ b/src/chat/real-time-text-chat-room-p.h @@ -46,8 +46,6 @@ public: LinphoneChatMessage *pendingMessage = nullptr; private: - std::string dummyConferenceId; - L_DECLARE_PUBLIC(RealTimeTextChatRoom); }; diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 3898f8ec5..851ec9451 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -152,10 +152,9 @@ bool RealTimeTextChatRoom::canHandleParticipants () const { return false; } -const string& RealTimeTextChatRoom::getId () const { - L_D(const RealTimeTextChatRoom); - lError() << "a RealTimeTextChatRoom does not have a conference id"; - return d->dummyConferenceId; +const Address *RealTimeTextChatRoom::getConferenceAddress () const { + lError() << "a RealTimeTextChatRoom does not have a conference address"; + return nullptr; } int RealTimeTextChatRoom::getNbParticipants () const { diff --git a/src/chat/real-time-text-chat-room.h b/src/chat/real-time-text-chat-room.h index 1be0f549b..117f36dd5 100644 --- a/src/chat/real-time-text-chat-room.h +++ b/src/chat/real-time-text-chat-room.h @@ -46,7 +46,7 @@ public: std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; bool canHandleParticipants () const override; - const std::string& getId () const override; + const Address *getConferenceAddress () const override; int getNbParticipants () const override; std::list> getParticipants () const override; void removeParticipant (const std::shared_ptr &participant) override; diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index a32040846..b4241d34c 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -37,7 +37,7 @@ public: virtual std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) = 0; virtual void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) = 0; virtual bool canHandleParticipants () const = 0; - virtual const std::string& getId () const = 0; + virtual const Address *getConferenceAddress () const = 0; virtual int getNbParticipants () const = 0; virtual std::list> getParticipants () const = 0; virtual void removeParticipant (const std::shared_ptr &participant) = 0; diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index b26f83845..8e4214989 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -54,8 +54,8 @@ bool Conference::canHandleParticipants () const { return true; } -const string& Conference::getId () const { - return id; +const Address *Conference::getConferenceAddress () const { + return &conferenceAddress; } int Conference::getNbParticipants () const { diff --git a/src/conference/conference.h b/src/conference/conference.h index d80c50298..955688757 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -50,7 +50,7 @@ public: std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; bool canHandleParticipants () const override; - const std::string& getId () const override; + const Address *getConferenceAddress () const override; int getNbParticipants () const override; std::list> getParticipants () const override; void removeParticipant (const std::shared_ptr &participant) override; @@ -85,7 +85,7 @@ protected: std::shared_ptr activeParticipant; std::shared_ptr me; std::list> participants; - std::string id; + Address conferenceAddress; private: L_DISABLE_COPY(Conference); From b0b2309038c81ac207a7082497e48ba1b0351cf2 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 27 Sep 2017 15:01:33 +0200 Subject: [PATCH 0202/2215] Prevent the params of the contact address from being erased. --- coreapi/linphonecore.c | 9 ++-- coreapi/private.h | 7 ++- coreapi/proxy.c | 68 ++++++++++--------------- coreapi/sal/sal.c | 13 ----- coreapi/sal/sal.h | 1 - src/conference/session/call-session.cpp | 8 ++- 6 files changed, 39 insertions(+), 67 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index a168fcbae..9e9dd8e86 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3467,10 +3467,11 @@ void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const Linphon sal_op_set_sent_custom_header(op,headers); sal_op_set_realm(op,linphone_proxy_config_get_realm(proxy)); if (with_contact && proxy && proxy->op){ - const SalAddress *contact; - contact=sal_op_get_contact_address(proxy->op); - SalAddress *new_contact = contact ? sal_address_clone(contact) : NULL; - sal_op_set_and_clean_contact_address(proxy->op, new_contact); + const LinphoneAddress *contact = linphone_proxy_config_get_contact(proxy); + SalAddress *salAddress = nullptr; + if (contact) + salAddress = sal_address_clone(const_cast(L_GET_PRIVATE_FROM_C_OBJECT(contact)->getInternalAddress())); + sal_op_set_contact_address(op, salAddress); } sal_op_cnx_ip_to_0000_if_sendonly_enable(op, !!lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0)); /*also set in linphone_call_new_incoming*/ } diff --git a/coreapi/private.h b/coreapi/private.h index 80cea1623..dc6ff89b8 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -296,6 +296,7 @@ LinphoneEvent *linphone_proxy_config_create_publish(LinphoneProxyConfig *cfg, co * Can be NULL * */ const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg); +const LinphoneAddress *_linphone_proxy_config_get_contact_without_params (const LinphoneProxyConfig *cfg); void linphone_friend_list_invalidate_subscriptions(LinphoneFriendList *list); void linphone_friend_list_notify_presence_received(LinphoneFriendList *list, LinphoneEvent *lev, const LinphoneContent *body); @@ -476,6 +477,8 @@ struct _LinphoneProxyConfig char *reg_proxy; char *reg_identity; LinphoneAddress* identity_address; + LinphoneAddress *contact_address; + LinphoneAddress *contact_address_without_params; char *reg_route; char *quality_reporting_collector; char *realm; @@ -517,10 +520,6 @@ struct _LinphoneProxyConfig char *refkey; char *sip_etag; /*publish context*/ - - // For migration purpose. (Do not use directly!) - // Cache. - LinphoneAddress *contact_address; }; BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneProxyConfig); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index eddf9ee76..e51322498 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -438,35 +438,30 @@ void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig * cfg){ } } -LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *cfg){ - LinphoneAddress *ret=NULL; - LinphoneAddress *proxy=linphone_address_new(cfg->reg_proxy); - const char *host; - - if (proxy==NULL) return NULL; - host=linphone_address_get_domain(proxy); - if (host!=NULL){ - int localport = -1; - const char *localip = NULL; - LinphoneAddress *contact=linphone_address_clone(cfg->identity_address); - - linphone_address_clean(contact); - +static void guess_contact_for_register (LinphoneProxyConfig *cfg) { + linphone_address_unref(cfg->contact_address); + cfg->contact_address = nullptr; + linphone_address_unref(cfg->contact_address_without_params); + cfg->contact_address_without_params = nullptr; + LinphoneAddress *proxy = linphone_address_new(cfg->reg_proxy); + if (!proxy) + return; + const char *host = linphone_address_get_domain(proxy); + if (host) { + cfg->contact_address_without_params = linphone_address_clone(cfg->identity_address); + linphone_address_clean(cfg->contact_address_without_params); + linphone_address_set_port(cfg->contact_address_without_params, -1); + linphone_address_set_domain(cfg->contact_address_without_params, nullptr); + linphone_address_set_display_name(cfg->contact_address_without_params, nullptr); + cfg->contact_address = linphone_address_clone(cfg->contact_address_without_params); if (cfg->contact_params) { // We want to add a list of contacts params to the linphone address - linphone_address_set_params(contact,cfg->contact_params); + linphone_address_set_params(cfg->contact_address, cfg->contact_params); } - if (cfg->contact_uri_params){ - linphone_address_set_uri_params(contact,cfg->contact_uri_params); - } - linphone_address_set_port(contact,localport); - linphone_address_set_domain(contact,localip); - linphone_address_set_display_name(contact,NULL); - - ret=contact; + if (cfg->contact_uri_params) + linphone_address_set_uri_params(cfg->contact_address, cfg->contact_uri_params); } linphone_address_unref(proxy); - return ret; } void _linphone_proxy_config_unregister(LinphoneProxyConfig *obj) { @@ -481,7 +476,6 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *cfg){ LinphoneAddress* proxy=linphone_address_new(cfg->reg_proxy); char* proxy_string; char * from = linphone_address_as_string(cfg->identity_address); - LinphoneAddress *contact; ms_message("LinphoneProxyConfig [%p] about to register (LinphoneCore version: %s)",cfg,linphone_core_get_version()); proxy_string=linphone_address_as_string_uri_only(proxy); linphone_address_unref(proxy); @@ -491,12 +485,10 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *cfg){ linphone_configure_op(cfg->lc, cfg->op, cfg->identity_address, cfg->sent_headers, FALSE); - if ((contact=guess_contact_for_register(cfg))) { - sal_op_set_contact_address(cfg->op, L_GET_PRIVATE_FROM_C_OBJECT(contact)->getInternalAddress()); - linphone_address_unref(contact); - } - - sal_op_set_user_pointer(cfg->op,cfg); + guess_contact_for_register(cfg); + if (cfg->contact_address) + sal_op_set_contact_address(cfg->op, L_GET_PRIVATE_FROM_C_OBJECT(cfg->contact_address)->getInternalAddress()); + sal_op_set_user_pointer(cfg->op, cfg); if (sal_register( cfg->op, @@ -1431,18 +1423,14 @@ uint8_t linphone_proxy_config_get_avpf_rr_interval(const LinphoneProxyConfig *cf return cfg->avpf_rr_interval; } -const LinphoneAddress* linphone_proxy_config_get_contact(const LinphoneProxyConfig *cfg) { - // Workaround for wrapping. - if (cfg->contact_address) - linphone_address_unref(cfg->contact_address); - - char *buf = sal_address_as_string(sal_op_get_contact_address(cfg->op)); - const_cast(cfg)->contact_address = linphone_address_new(buf); - ms_free(buf); - +const LinphoneAddress *linphone_proxy_config_get_contact (const LinphoneProxyConfig *cfg) { return cfg->contact_address; } +const LinphoneAddress *_linphone_proxy_config_get_contact_without_params (const LinphoneProxyConfig *cfg) { + return cfg->contact_address_without_params; +} + const struct _LinphoneAuthInfo* linphone_proxy_config_find_auth_info(const LinphoneProxyConfig *cfg) { const char* username = cfg->identity_address ? linphone_address_get_username(cfg->identity_address) : NULL; const char* domain = cfg->identity_address ? linphone_address_get_domain(cfg->identity_address) : NULL; diff --git a/coreapi/sal/sal.c b/coreapi/sal/sal.c index 28cc29f5f..e61232fc9 100644 --- a/coreapi/sal/sal.c +++ b/coreapi/sal/sal.c @@ -518,19 +518,6 @@ void sal_op_set_contact_address(SalOp *op, const SalAddress *address){ ((SalOpBase*)op)->contact_address=address?sal_address_clone(address):NULL; } -void sal_op_set_and_clean_contact_address(SalOp *op, SalAddress *contact) { - if (contact){ - SalTransport tport = sal_address_get_transport((SalAddress*)contact); - const char* gruu = bctbx_strdup(sal_address_get_uri_param(contact, "gr")); - sal_address_clean((SalAddress*)contact); /* clean out contact_params that come from proxy config*/ - sal_address_set_transport((SalAddress*)contact,tport); - if(gruu) - sal_address_set_uri_param(contact, "gr", gruu); - sal_op_set_contact_address(op, contact); - sal_address_unref(contact); - } -} - const SalAddress* sal_op_get_contact_address(const SalOp *op) { return ((SalOpBase*)op)->contact_address; } diff --git a/coreapi/sal/sal.h b/coreapi/sal/sal.h index 5e0188feb..1fda7a38a 100644 --- a/coreapi/sal/sal.h +++ b/coreapi/sal/sal.h @@ -674,7 +674,6 @@ SalOp * sal_op_new(Sal *sal); /*generic SalOp API, working for all operations */ Sal *sal_op_get_sal(const SalOp *op); void sal_op_set_contact_address(SalOp *op, const SalAddress* address); -void sal_op_set_and_clean_contact_address(SalOp *op, SalAddress* address); void sal_op_set_route(SalOp *op, const char *route); void sal_op_set_route_address(SalOp *op, const SalAddress* address); void sal_op_add_route_address(SalOp *op, const SalAddress* address); diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 64af9041d..66c1fc487 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -602,8 +602,8 @@ void CallSessionPrivate::setContactOp () { salAddress = const_cast(L_GET_PRIVATE_FROM_C_OBJECT(contact)->getInternalAddress()); sal_address_ref(salAddress); linphone_address_unref(contact); + sal_op_set_contact_address(op, salAddress); } - sal_op_set_and_clean_contact_address(op, salAddress); } // ----------------------------------------------------------------------------- @@ -645,12 +645,10 @@ LinphoneAddress * CallSessionPrivate::getFixedContact () const { char *addr = sal_address_as_string(sal_op_get_contact_address(pingOp)); result = linphone_address_new(addr); ms_free(addr); - } else if (destProxy && destProxy->op && sal_op_get_contact_address(destProxy->op)) { + } else if (destProxy && destProxy->op && _linphone_proxy_config_get_contact_without_params(destProxy)) { /* If using a proxy, use the contact address as guessed with the REGISTERs */ lInfo() << "Contact has been fixed using proxy"; - char *addr = sal_address_as_string(sal_op_get_contact_address(destProxy->op)); - result = linphone_address_new(addr); - ms_free(addr); + result = linphone_address_clone(_linphone_proxy_config_get_contact_without_params(destProxy)); } else { result = linphone_core_get_primary_contact_parsed(core); if (result) { From f049a10da8d6fc51b158d89d35ab0c2d90bca4f1 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 27 Sep 2017 15:02:09 +0200 Subject: [PATCH 0203/2215] Add the "text" feature tag in the Contact header of the group chat room creation INVITE. --- src/address/address.h | 2 ++ src/chat/client-group-chat-room.cpp | 5 +++++ src/conference/session/call-session.h | 1 + 3 files changed, 8 insertions(+) diff --git a/src/address/address.h b/src/address/address.h index eb3d74ed0..5a57c2f72 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -29,6 +29,8 @@ LINPHONE_BEGIN_NAMESPACE class AddressPrivate; class LINPHONE_PUBLIC Address : public ClonableObject { + friend class ClientGroupChatRoom; + public: Address (const std::string &address = ""); Address (const Address &src); diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 47ade072f..147616bf8 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -16,8 +16,10 @@ * along with this program. If not, see . */ +#include "address/address-p.h" #include "client-group-chat-room-p.h" #include "c-wrapper/c-wrapper.h" +#include "conference/session/call-session-p.h" #include "conference/participant-p.h" #include "content/content.h" #include "logger/logger.h" @@ -67,6 +69,9 @@ void ClientGroupChatRoom::addParticipants (const list
    &addresses, const shared_ptr session = focus->getPrivate()->createSession(*this, &csp, false, this); session->configure(LinphoneCallOutgoing, nullptr, nullptr, me->getAddress(), focus->getAddress()); session->initiateOutgoing(); + Address addr = me->getAddress(); + addr.setParam("text", ""); + sal_op_set_contact_address(session->getPrivate()->getOp(), addr.getPrivate()->getInternalAddress()); session->startInvite(nullptr, d->subject); d->setState(ChatRoom::State::CreationPending); } diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index 07f8ab262..cd5484cc2 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -34,6 +34,7 @@ class CallSessionPrivate; class CallSession : public Object { friend class CallPrivate; + friend class ClientGroupChatRoom; public: CallSession (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener); From f3aa06edc72e3ffd12fe5ff76ffd1a917bb1fee6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 27 Sep 2017 15:18:35 +0200 Subject: [PATCH 0204/2215] Fix build. --- src/c-wrapper/api/c-chat-message.cpp | 4 ++-- src/chat/chat-message-p.h | 2 +- src/chat/chat-message.cpp | 4 ++-- src/chat/chat-message.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 0b0ead9b3..70a92d8ec 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -244,7 +244,7 @@ const char *linphone_chat_message_get_custom_header(LinphoneChatMessage *msg, co return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getSalCustomHeaderValue(header_name).c_str(); } -const LinphoneErrorInfo *linphone_chat_message_get_error_info(LinphoneChatMessage *msg) { +const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg) { return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getErrorInfo(); } @@ -400,4 +400,4 @@ void linphone_chat_message_start_file_download(LinphoneChatMessage *msg, void linphone_chat_message_release(LinphoneChatMessage *msg) { linphone_chat_message_deactivate(msg); linphone_chat_message_unref(msg); -} \ No newline at end of file +} diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 17da7bb79..754701f0e 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -54,7 +54,7 @@ private: std::shared_ptr internalContent; std::unordered_map customHeaders; std::shared_ptr eventsDb; - LinphoneErrorInfo * errorInfo; + mutable LinphoneErrorInfo * errorInfo; belle_http_request_t *httpRequest; SalOp *salOp; SalCustomHeader *salCustomHeaders; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 325fcce97..2deb16b91 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -307,8 +307,8 @@ string ChatMessage::getSalCustomHeaderValue(string name) { return sal_custom_header_find(d->salCustomHeaders, name.c_str()); } -const LinphoneErrorInfo * ChatMessage::getErrorInfo() { - L_D(ChatMessage); +const LinphoneErrorInfo * ChatMessage::getErrorInfo() const { + L_D(const ChatMessage); if (!d->errorInfo) d->errorInfo = linphone_error_info_new(); //let's do it mutable linphone_error_info_from_sal_op(d->errorInfo, d->salOp); return d->errorInfo; diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index 1c4ccc43f..1762ca5bb 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -120,7 +120,7 @@ public: bool isToBeStored() const; void setIsToBeStored(bool store); - const LinphoneErrorInfo * getErrorInfo (); + const LinphoneErrorInfo * getErrorInfo () const; bool isReadOnly () const; From 21ddaf03d61a7552fb03b46bee3df9626f8eca09 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 27 Sep 2017 16:11:25 +0200 Subject: [PATCH 0205/2215] More work on chat_message.cpp --- coreapi/private.h | 1 + src/c-wrapper/api/c-chat-message.cpp | 4 ++++ src/chat/chat-message.cpp | 19 ++++++++++--------- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/coreapi/private.h b/coreapi/private.h index dc6ff89b8..b28d7bb86 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -1084,6 +1084,7 @@ void linphone_core_message_storage_set_debug(LinphoneCore *lc, bool_t debug); void linphone_chat_message_set_time(LinphoneChatMessage* msg, time_t time); void linphone_chat_message_set_incoming(LinphoneChatMessage *msg); void linphone_chat_message_set_outgoing(LinphoneChatMessage *msg); +LinphoneChatMessageStateChangedCb linphone_chat_message_get_message_state_changed_cb(LinphoneChatMessage* msg); void linphone_chat_message_set_message_state_changed_cb(LinphoneChatMessage* msg, LinphoneChatMessageStateChangedCb cb); void linphone_chat_message_set_message_state_changed_cb_user_data(LinphoneChatMessage* msg, void *user_data); void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChatMessage* msg); diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 70a92d8ec..fb0237698 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -300,6 +300,10 @@ LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg, uint32_t // Old listener // ============================================================================= +LinphoneChatMessageStateChangedCb linphone_chat_message_get_message_state_changed_cb(LinphoneChatMessage* msg) { + return msg->message_state_changed_cb; +} + void linphone_chat_message_set_message_state_changed_cb(LinphoneChatMessage* msg, LinphoneChatMessageStateChangedCb cb) { msg->message_state_changed_cb = cb; } diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 2deb16b91..5e9e22645 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -46,6 +46,8 @@ ChatMessagePrivate::ChatMessagePrivate (const shared_ptr &room) ChatMessagePrivate::~ChatMessagePrivate () {} +// ----------------------------------------------------------------------------- + // ============================================================================= // ChatMessage // ============================================================================= @@ -137,10 +139,9 @@ void ChatMessage::setState(State state) { d->state = state; LinphoneChatMessage *msg = L_GET_C_BACK_PTR(this); - /* TODO - if (msg->message_state_changed_cb) { - msg->message_state_changed_cb(msg, msg->state, msg->message_state_changed_user_data); - }*/ + if (linphone_chat_message_get_message_state_changed_cb(msg)) { + linphone_chat_message_get_message_state_changed_cb(msg)(msg, (LinphoneChatMessageState)state, linphone_chat_message_get_message_state_changed_cb_user_data(msg)); + } LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); if (linphone_chat_message_cbs_get_msg_state_changed(cbs)) { linphone_chat_message_cbs_get_msg_state_changed(cbs)(msg, linphone_chat_message_get_state(msg)); @@ -160,12 +161,12 @@ void ChatMessage::setId (string id) { bool ChatMessage::isRead() const { return false; - /* TODO L_D(const ChatMessage); - shared_ptr policy =d->chatRoom->core->getImNotifPolicy(); - if (policy->getRecvImdnDisplayed() && d->state == Displayed) return true; - if (policy->getRecvImdnDelivered() && (d->state == DeliveredToUser || d->state == Displayed)) return true; - return d->state == Delivered || d->state == Displayed || d->state == DeliveredToUser;*/ + LinphoneCore *lc = d->chatRoom->getCore(); + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); + if (linphone_im_notif_policy_get_recv_imdn_displayed(policy) && d->state == Displayed) return true; + if (linphone_im_notif_policy_get_recv_imdn_delivered(policy) && (d->state == DeliveredToUser || d->state == Displayed)) return true; + return d->state == Delivered || d->state == Displayed || d->state == DeliveredToUser; } string ChatMessage::getAppdata () const { From c156730daaa8ff694f14e74295cd4f8a70171503 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 27 Sep 2017 16:12:17 +0200 Subject: [PATCH 0206/2215] feat(general): remove class parameter of L_D and L_Q --- include/linphone/utils/general.h | 4 +- src/address/address.cpp | 72 ++++---- src/call/call.cpp | 118 ++++++------ src/chat/basic-chat-room.cpp | 2 +- src/chat/chat-message.cpp | 116 ++++++------ src/chat/chat-room.cpp | 54 +++--- src/chat/client-group-chat-room.cpp | 6 +- src/chat/cpim/header/cpim-core-headers.cpp | 8 +- src/chat/cpim/header/cpim-generic-header.cpp | 16 +- src/chat/cpim/header/cpim-header.cpp | 6 +- src/chat/cpim/message/cpim-message.cpp | 26 +-- src/chat/cpim/parser/cpim-parser.cpp | 26 +-- src/chat/real-time-text-chat-room.cpp | 10 +- .../local-conference-event-handler.cpp | 10 +- src/conference/params/call-session-params.cpp | 18 +- .../params/media-session-params.cpp | 102 +++++------ src/conference/participant.cpp | 8 +- .../remote-conference-event-handler.cpp | 14 +- src/conference/session/call-session.cpp | 70 ++++---- src/conference/session/media-session.cpp | 168 +++++++++--------- src/content/content-type.cpp | 16 +- src/content/content.cpp | 30 ++-- src/db/abstract/abstract-db.cpp | 8 +- src/db/events-db.cpp | 8 +- src/db/provider/db-session-provider.cpp | 2 +- src/db/provider/db-session.cpp | 8 +- src/event-log/call-event.cpp | 6 +- src/event-log/chat-message-event.cpp | 6 +- src/event-log/conference-event.cpp | 8 +- .../conference-participant-event.cpp | 6 +- src/event-log/event-log.cpp | 6 +- src/logger/logger.cpp | 6 +- src/object/property-container.cpp | 6 +- src/variant/variant.cpp | 40 ++--- 34 files changed, 505 insertions(+), 505 deletions(-) diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index aabcf1ab4..cfba622c7 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -125,8 +125,8 @@ inline const Object *getPublicHelper (const T *object, const ObjectPrivate *) { CLASS(const CLASS &) = delete; \ CLASS &operator= (const CLASS &) = delete; -#define L_D(CLASS) CLASS ## Private * const d = getPrivate(); -#define L_Q(CLASS) CLASS * const q = getPublic(); +#define L_D() decltype(std::declval().getPrivate()) const d = getPrivate(); +#define L_Q() decltype(std::declval().getPublic()) const q = getPublic(); #define L_USE_DEFAULT_SHARE_IMPL(CLASS, PARENT_CLASS) \ CLASS::CLASS (const CLASS &src) : PARENT_CLASS(*src.getPrivate()) {} \ diff --git a/src/address/address.cpp b/src/address/address.cpp index 8de8d1f90..a173c63c0 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -31,7 +31,7 @@ LINPHONE_BEGIN_NAMESPACE // ----------------------------------------------------------------------------- Address::Address (const string &address) : ClonableObject(*new AddressPrivate) { - L_D(Address); + L_D(); if (!(d->internalAddress = sal_address_new(L_STRING_TO_C(address)))) { lWarning() << "Cannot create address, bad uri [" << address << "]."; return; @@ -39,20 +39,20 @@ Address::Address (const string &address) : ClonableObject(*new AddressPrivate) { } Address::Address (const Address &src) : ClonableObject(*new AddressPrivate) { - L_D(Address); + L_D(); SalAddress *salAddress = src.getPrivate()->internalAddress; if (salAddress) d->internalAddress = sal_address_clone(salAddress); } Address::~Address () { - L_D(Address); + L_D(); if (d->internalAddress) sal_address_destroy(d->internalAddress); } Address &Address::operator= (const Address &src) { - L_D(Address); + L_D(); if (this != &src) { if (d->internalAddress) sal_address_destroy(d->internalAddress); @@ -72,24 +72,24 @@ bool Address::operator< (const Address &address) const { } bool Address::isValid () const { - L_D(const Address); + L_D(); return static_cast(d->internalAddress); } const string &Address::getScheme () const { - L_D(const Address); + L_D(); d->cache.scheme = L_C_TO_STRING(sal_address_get_scheme(d->internalAddress)); return d->cache.scheme; } const string &Address::getDisplayName () const { - L_D(const Address); + L_D(); d->cache.displayName = L_C_TO_STRING(sal_address_get_display_name(d->internalAddress)); return d->cache.displayName; } bool Address::setDisplayName (const string &displayName) { - L_D(Address); + L_D(); if (!d->internalAddress) return false; @@ -99,13 +99,13 @@ bool Address::setDisplayName (const string &displayName) { } const string &Address::getUsername () const { - L_D(const Address); + L_D(); d->cache.username = L_C_TO_STRING(sal_address_get_username(d->internalAddress)); return d->cache.username; } bool Address::setUsername (const string &username) { - L_D(Address); + L_D(); if (!d->internalAddress) return false; @@ -115,13 +115,13 @@ bool Address::setUsername (const string &username) { } const string &Address::getDomain () const { - L_D(const Address); + L_D(); d->cache.domain = L_C_TO_STRING(sal_address_get_domain(d->internalAddress)); return d->cache.domain; } bool Address::setDomain (const string &domain) { - L_D(Address); + L_D(); if (!d->internalAddress) return false; @@ -131,12 +131,12 @@ bool Address::setDomain (const string &domain) { } int Address::getPort () const { - L_D(const Address); + L_D(); return d->internalAddress ? sal_address_get_port(d->internalAddress) : 0; } bool Address::setPort (int port) { - L_D(const Address); + L_D(); if (!d->internalAddress) return false; @@ -146,12 +146,12 @@ bool Address::setPort (int port) { } Transport Address::getTransport () const { - L_D(const Address); + L_D(); return d->internalAddress ? static_cast(sal_address_get_transport(d->internalAddress)) : Transport::Udp; } bool Address::setTransport (Transport transport) { - L_D(const Address); + L_D(); if (!d->internalAddress) return false; @@ -161,12 +161,12 @@ bool Address::setTransport (Transport transport) { } bool Address::getSecure () const { - L_D(const Address); + L_D(); return d->internalAddress ? sal_address_is_secure(d->internalAddress) : false; } bool Address::setSecure (bool enabled) { - L_D(const Address); + L_D(); if (!d->internalAddress) return false; @@ -176,18 +176,18 @@ bool Address::setSecure (bool enabled) { } bool Address::isSip () const { - L_D(const Address); + L_D(); return d->internalAddress ? sal_address_is_sip(d->internalAddress) : false; } const string &Address::getMethodParam () const { - L_D(const Address); + L_D(); d->cache.methodParam = L_C_TO_STRING(sal_address_get_method_param(d->internalAddress)); return d->cache.methodParam; } bool Address::setMethodParam (const string &methodParam) { - L_D(Address); + L_D(); if (!d->internalAddress) return false; @@ -197,13 +197,13 @@ bool Address::setMethodParam (const string &methodParam) { } const string &Address::getPassword () const { - L_D(const Address); + L_D(); d->cache.password = L_C_TO_STRING(sal_address_get_password(d->internalAddress)); return d->cache.password; } bool Address::setPassword (const string &password) { - L_D(Address); + L_D(); if (!d->internalAddress) return false; @@ -213,7 +213,7 @@ bool Address::setPassword (const string &password) { } bool Address::clean () { - L_D(const Address); + L_D(); if (!d->internalAddress) return false; @@ -223,7 +223,7 @@ bool Address::clean () { } string Address::asString () const { - L_D(const Address); + L_D(); if (!d->internalAddress) return ""; @@ -235,7 +235,7 @@ string Address::asString () const { } string Address::asStringUriOnly () const { - L_D(const Address); + L_D(); if (!d->internalAddress) return ""; @@ -257,7 +257,7 @@ bool Address::weakEqual (const Address &address) const { } const string &Address::getHeaderValue (const string &headerName) const { - L_D(const Address); + L_D(); const char *value = sal_address_get_header(d->internalAddress, L_STRING_TO_C(headerName)); if (value) { @@ -269,7 +269,7 @@ const string &Address::getHeaderValue (const string &headerName) const { } bool Address::setHeader (const string &headerName, const string &headerValue) { - L_D(Address); + L_D(); if (!d->internalAddress) return false; @@ -279,12 +279,12 @@ bool Address::setHeader (const string &headerName, const string &headerValue) { } bool Address::hasParam (const string ¶mName) const { - L_D(const Address); + L_D(); return sal_address_has_param(d->internalAddress, L_STRING_TO_C(paramName)); } const string &Address::getParamValue (const string ¶mName) const { - L_D(const Address); + L_D(); const char *value = sal_address_get_param(d->internalAddress, L_STRING_TO_C(paramName)); if (value) { @@ -296,7 +296,7 @@ const string &Address::getParamValue (const string ¶mName) const { } bool Address::setParam (const string ¶mName, const string ¶mValue) { - L_D(Address); + L_D(); if (!d->internalAddress) return false; @@ -306,7 +306,7 @@ bool Address::setParam (const string ¶mName, const string ¶mValue) { } bool Address::setParams (const string ¶ms) { - L_D(Address); + L_D(); if (!d->internalAddress) return false; @@ -316,12 +316,12 @@ bool Address::setParams (const string ¶ms) { } bool Address::hasUriParam (const string &uriParamName) const { - L_D(const Address); + L_D(); return sal_address_has_uri_param(d->internalAddress, L_STRING_TO_C(uriParamName)); } const string &Address::getUriParamValue (const string &uriParamName) const { - L_D(const Address); + L_D(); const char *value = sal_address_get_uri_param(d->internalAddress, L_STRING_TO_C(uriParamName)); if (value) { @@ -333,7 +333,7 @@ const string &Address::getUriParamValue (const string &uriParamName) const { } bool Address::setUriParam (const string &uriParamName, const string &uriParamValue) { - L_D(Address); + L_D(); if (!d->internalAddress) return false; @@ -343,7 +343,7 @@ bool Address::setUriParam (const string &uriParamName, const string &uriParamVal } bool Address::setUriParams (const string &uriParams) { - L_D(Address); + L_D(); if (!d->internalAddress) return false; diff --git a/src/call/call.cpp b/src/call/call.cpp index 929bfceca..a9f22730e 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -222,7 +222,7 @@ Call::Call ( SalOp *op, const MediaSessionParams *msp ) : Object(*new CallPrivate(call, core, direction, from, to, cfg, op, msp)) { - L_D(Call); + L_D(); const Address *myAddress = (direction == LinphoneCallIncoming) ? &to : &from; string confType = lp_config_get_string(linphone_core_get_config(core), "misc", "conference_type", "local"); if (confType == "remote") { @@ -238,296 +238,296 @@ Call::Call ( // ----------------------------------------------------------------------------- LinphoneStatus Call::accept (const MediaSessionParams *msp) { - L_D(Call); + L_D(); return static_cast(d->getActiveSession().get())->accept(msp); } LinphoneStatus Call::acceptEarlyMedia (const MediaSessionParams *msp) { - L_D(Call); + L_D(); return static_cast(d->getActiveSession().get())->acceptEarlyMedia(msp); } LinphoneStatus Call::acceptUpdate (const MediaSessionParams *msp) { - L_D(Call); + L_D(); return static_cast(d->getActiveSession().get())->acceptUpdate(msp); } LinphoneStatus Call::decline (LinphoneReason reason) { - L_D(Call); + L_D(); return d->getActiveSession()->decline(reason); } LinphoneStatus Call::decline (const LinphoneErrorInfo *ei) { - L_D(Call); + L_D(); return d->getActiveSession()->decline(ei); } LinphoneStatus Call::pause () { - L_D(Call); + L_D(); return static_cast(d->getActiveSession().get())->pause(); } LinphoneStatus Call::resume () { - L_D(Call); + L_D(); return static_cast(d->getActiveSession().get())->resume(); } void Call::sendVfuRequest () { - L_D(Call); + L_D(); static_cast(d->getActiveSession().get())->sendVfuRequest(); } void Call::startRecording () { - L_D(Call); + L_D(); static_cast(d->getActiveSession().get())->startRecording(); } void Call::stopRecording () { - L_D(Call); + L_D(); static_cast(d->getActiveSession().get())->stopRecording(); } LinphoneStatus Call::takePreviewSnapshot (const string &file) { - L_D(Call); + L_D(); return static_cast(d->getActiveSession().get())->takePreviewSnapshot(file); } LinphoneStatus Call::takeVideoSnapshot (const string &file) { - L_D(Call); + L_D(); return static_cast(d->getActiveSession().get())->takeVideoSnapshot(file); } LinphoneStatus Call::terminate (const LinphoneErrorInfo *ei) { - L_D(Call); + L_D(); return d->getActiveSession()->terminate(ei); } LinphoneStatus Call::update (const MediaSessionParams *msp) { - L_D(Call); + L_D(); return static_cast(d->getActiveSession().get())->update(msp); } void Call::zoomVideo (float zoomFactor, float *cx, float *cy) { - L_D(Call); + L_D(); static_cast(d->getActiveSession().get())->zoomVideo(zoomFactor, cx, cy); } // ----------------------------------------------------------------------------- bool Call::cameraEnabled () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->cameraEnabled(); } bool Call::echoCancellationEnabled () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->echoCancellationEnabled(); } bool Call::echoLimiterEnabled () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->echoLimiterEnabled(); } void Call::enableCamera (bool value) { - L_D(Call); + L_D(); static_cast(d->getActiveSession().get())->enableCamera(value); } void Call::enableEchoCancellation (bool value) { - L_D(Call); + L_D(); static_cast(d->getActiveSession().get())->enableEchoCancellation(value); } void Call::enableEchoLimiter (bool value) { - L_D(Call); + L_D(); static_cast(d->getActiveSession().get())->enableEchoLimiter(value); } bool Call::getAllMuted () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getAllMuted(); } LinphoneCallStats *Call::getAudioStats () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getAudioStats(); } string Call::getAuthenticationToken () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getAuthenticationToken(); } bool Call::getAuthenticationTokenVerified () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getAuthenticationTokenVerified(); } float Call::getAverageQuality () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getAverageQuality(); } LinphoneCore *Call::getCore () const { - L_D(const Call); + L_D(); return d->core; } const MediaSessionParams *Call::getCurrentParams () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getCurrentParams(); } float Call::getCurrentQuality () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getCurrentQuality(); } LinphoneCallDir Call::getDirection () const { - L_D(const Call); + L_D(); return d->getActiveSession()->getDirection(); } int Call::getDuration () const { - L_D(const Call); + L_D(); return d->getActiveSession()->getDuration(); } const LinphoneErrorInfo *Call::getErrorInfo () const { - L_D(const Call); + L_D(); return d->getActiveSession()->getErrorInfo(); } LinphoneCallLog *Call::getLog () const { - L_D(const Call); + L_D(); return d->getActiveSession()->getLog(); } RtpTransport *Call::getMetaRtcpTransport (int streamIndex) const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getMetaRtcpTransport(streamIndex); } RtpTransport *Call::getMetaRtpTransport (int streamIndex) const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getMetaRtpTransport(streamIndex); } float Call::getMicrophoneVolumeGain () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getMicrophoneVolumeGain(); } void *Call::getNativeVideoWindowId () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getNativeVideoWindowId(); } const MediaSessionParams *Call::getParams () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getMediaParams(); } float Call::getPlayVolume () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getPlayVolume(); } LinphoneReason Call::getReason () const { - L_D(const Call); + L_D(); return d->getActiveSession()->getReason(); } float Call::getRecordVolume () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getRecordVolume(); } const Address &Call::getRemoteAddress () const { - L_D(const Call); + L_D(); return d->getActiveSession()->getRemoteAddress(); } string Call::getRemoteAddressAsString () const { - L_D(const Call); + L_D(); return d->getActiveSession()->getRemoteAddressAsString(); } string Call::getRemoteContact () const { - L_D(const Call); + L_D(); return d->getActiveSession()->getRemoteContact(); } const MediaSessionParams *Call::getRemoteParams () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getRemoteParams(); } float Call::getSpeakerVolumeGain () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getSpeakerVolumeGain(); } LinphoneCallState Call::getState () const { - L_D(const Call); + L_D(); return d->getActiveSession()->getState(); } LinphoneCallStats *Call::getStats (LinphoneStreamType type) const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getStats(type); } int Call::getStreamCount () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getStreamCount(); } MSFormatType Call::getStreamType (int streamIndex) const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getStreamType(streamIndex); } LinphoneCallStats *Call::getTextStats () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getTextStats(); } LinphoneCallStats *Call::getVideoStats () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->getVideoStats(); } bool Call::mediaInProgress () const { - L_D(const Call); + L_D(); return static_cast(d->getActiveSession().get())->mediaInProgress(); } void Call::setAuthenticationTokenVerified (bool value) { - L_D(Call); + L_D(); static_cast(d->getActiveSession().get())->setAuthenticationTokenVerified(value); } void Call::setMicrophoneVolumeGain (float value) { - L_D(Call); + L_D(); static_cast(d->getActiveSession().get())->setMicrophoneVolumeGain(value); } void Call::setNativeVideoWindowId (void *id) { - L_D(Call); + L_D(); static_cast(d->getActiveSession().get())->setNativeVideoWindowId(id); } void Call::setNextVideoFrameDecodedCallback (LinphoneCallCbFunc cb, void *user_data) { - L_D(Call); + L_D(); d->nextVideoFrameDecoded._func = cb; d->nextVideoFrameDecoded._user_data = user_data; d->onResetFirstVideoFrameDecoded(); } void Call::setSpeakerVolumeGain (float value) { - L_D(Call); + L_D(); static_cast(d->getActiveSession().get())->setSpeakerVolumeGain(value); } diff --git a/src/chat/basic-chat-room.cpp b/src/chat/basic-chat-room.cpp index 1c1fba3b7..820ffc6cd 100644 --- a/src/chat/basic-chat-room.cpp +++ b/src/chat/basic-chat-room.cpp @@ -58,7 +58,7 @@ int BasicChatRoom::getNbParticipants () const { } list> BasicChatRoom::getParticipants () const { - L_D(const BasicChatRoom); + L_D(); list> l; l.push_back(make_shared(d->peerAddress)); return l; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 5e9e22645..6f8c01563 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -61,73 +61,73 @@ LinphoneChatMessage * ChatMessage::getBackPtr() { } shared_ptr ChatMessage::getChatRoom () const { - L_D(const ChatMessage); + L_D(); return d->chatRoom; } void ChatMessage::setChatRoom (shared_ptr chatRoom) { - L_D(ChatMessage); + L_D(); d->chatRoom = chatRoom; } // ----------------------------------------------------------------------------- string ChatMessage::getExternalBodyUrl() const { - L_D(const ChatMessage); + L_D(); return d->externalBodyUrl; } void ChatMessage::setExternalBodyUrl(const string &url) { - L_D(ChatMessage); + L_D(); d->externalBodyUrl = url; } time_t ChatMessage::getTime () const { - L_D(const ChatMessage); + L_D(); return d->time; } void ChatMessage::setTime(time_t time) { - L_D(ChatMessage); + L_D(); d->time = time; } bool ChatMessage::isSecured () const { - L_D(const ChatMessage); + L_D(); return d->isSecured; } void ChatMessage::setIsSecured(bool isSecured) { - L_D(ChatMessage); + L_D(); d->isSecured = isSecured; } ChatMessage::Direction ChatMessage::getDirection () const { - L_D(const ChatMessage); + L_D(); return d->direction; } void ChatMessage::setDirection (ChatMessage::Direction dir) { - L_D(ChatMessage); + L_D(); d->direction = dir; } bool ChatMessage::isOutgoing () const { - L_D(const ChatMessage); + L_D(); return d->direction == Outgoing; } bool ChatMessage::isIncoming () const { - L_D(const ChatMessage); + L_D(); return d->direction == Incoming; } ChatMessage::State ChatMessage::getState() const { - L_D(const ChatMessage); + L_D(); return d->state; } void ChatMessage::setState(State state) { - L_D(ChatMessage); + L_D(); if (state != d->state && d->chatRoom) { if (((d->state == Displayed) || (d->state == DeliveredToUser)) && ((state == DeliveredToUser) || (state == Delivered) || (state == NotDelivered))) { @@ -150,18 +150,18 @@ void ChatMessage::setState(State state) { } string ChatMessage::getId () const { - L_D(const ChatMessage); + L_D(); return d->id; } void ChatMessage::setId (string id) { - L_D(ChatMessage); + L_D(); d->id = id; } bool ChatMessage::isRead() const { return false; - L_D(const ChatMessage); + L_D(); LinphoneCore *lc = d->chatRoom->getCore(); LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); if (linphone_im_notif_policy_get_recv_imdn_displayed(policy) && d->state == Displayed) return true; @@ -170,158 +170,158 @@ bool ChatMessage::isRead() const { } string ChatMessage::getAppdata () const { - L_D(const ChatMessage); + L_D(); return d->appData; } void ChatMessage::setAppdata (const string &appData) { - L_D(ChatMessage); + L_D(); d->appData = appData; // TODO: store app data in db ! // linphone_chat_message_store_appdata(msg); } shared_ptr
    ChatMessage::getFromAddress () const { - L_D(const ChatMessage); + L_D(); return d->from; } void ChatMessage::setFromAddress(shared_ptr
    from) { - L_D(ChatMessage); + L_D(); d->from = from; } shared_ptr
    ChatMessage::getToAddress () const { - L_D(const ChatMessage); + L_D(); return d->to; } void ChatMessage::setToAddress(shared_ptr
    to) { - L_D(ChatMessage); + L_D(); d->to = to; } string ChatMessage::getFileTransferFilepath() const { - L_D(const ChatMessage); + L_D(); return d->fileTransferFilePath; } void ChatMessage::setFileTransferFilepath(const string &path) { - L_D(ChatMessage); + L_D(); d->fileTransferFilePath = path; } bool ChatMessage::isToBeStored() const { - L_D(const ChatMessage); + L_D(); return d->isToBeStored; } void ChatMessage::setIsToBeStored(bool store) { - L_D(ChatMessage); + L_D(); d->isToBeStored = store; } // ----------------------------------------------------------------------------- string ChatMessage::getContentType() const { - L_D(const ChatMessage); + L_D(); return d->cContentType; } void ChatMessage::setContentType(string contentType) { - L_D(ChatMessage); + L_D(); d->cContentType = contentType; } string ChatMessage::getText() const { - L_D(const ChatMessage); + L_D(); return d->cText; } void ChatMessage::setText(string text) { - L_D(ChatMessage); + L_D(); d->cText = text; } LinphoneContent * ChatMessage::getFileTransferInformation() const { - L_D(const ChatMessage); + L_D(); return d->cFileTransferInformation; } void ChatMessage::setFileTransferInformation(LinphoneContent *content) { - L_D(ChatMessage); + L_D(); d->cFileTransferInformation = content; } unsigned int ChatMessage::getStorageId() const { - L_D(const ChatMessage); + L_D(); return d->storageId; } void ChatMessage::setStorageId(unsigned int id) { - L_D(ChatMessage); + L_D(); d->storageId = id; } belle_http_request_t *ChatMessage::getHttpRequest() const { - L_D(const ChatMessage); + L_D(); return d->httpRequest; } void ChatMessage::setHttpRequest(belle_http_request_t *request) { - L_D(ChatMessage); + L_D(); d->httpRequest = request; } SalOp *ChatMessage::getSalOp() const { - L_D(const ChatMessage); + L_D(); return d->salOp; } void ChatMessage::setSalOp(SalOp *op) { - L_D(ChatMessage); + L_D(); d->salOp = op; } SalCustomHeader *ChatMessage::getSalCustomHeaders() const { - L_D(const ChatMessage); + L_D(); return d->salCustomHeaders; } void ChatMessage::setSalCustomHeaders(SalCustomHeader *headers) { - L_D(ChatMessage); + L_D(); d->salCustomHeaders = headers; } void ChatMessage::addSalCustomHeader(string name, string value) { - L_D(ChatMessage); + L_D(); d->salCustomHeaders = sal_custom_header_append(d->salCustomHeaders, name.c_str(), value.c_str()); } void ChatMessage::removeSalCustomHeader(string name) { - L_D(ChatMessage); + L_D(); d->salCustomHeaders = sal_custom_header_remove(d->salCustomHeaders, name.c_str()); } string ChatMessage::getSalCustomHeaderValue(string name) { - L_D(ChatMessage); + L_D(); return sal_custom_header_find(d->salCustomHeaders, name.c_str()); } const LinphoneErrorInfo * ChatMessage::getErrorInfo() const { - L_D(const ChatMessage); + L_D(); if (!d->errorInfo) d->errorInfo = linphone_error_info_new(); //let's do it mutable linphone_error_info_from_sal_op(d->errorInfo, d->salOp); return d->errorInfo; } bool ChatMessage::isReadOnly () const { - L_D(const ChatMessage); + L_D(); return d->isReadOnly; } list > ChatMessage::getContents () const { - L_D(const ChatMessage); + L_D(); list > contents; for (const auto &content : d->contents) contents.push_back(content); @@ -329,21 +329,21 @@ list > ChatMessage::getContents () const { } void ChatMessage::addContent (const shared_ptr &content) { - L_D(ChatMessage); + L_D(); if (d->isReadOnly) return; d->contents.push_back(content); } void ChatMessage::removeContent (const shared_ptr &content) { - L_D(ChatMessage); + L_D(); if (d->isReadOnly) return; d->contents.remove(const_pointer_cast(content)); } string ChatMessage::getCustomHeaderValue (const string &headerName) const { - L_D(const ChatMessage); + L_D(); try { return d->customHeaders.at(headerName); } catch (const exception &) { @@ -353,14 +353,14 @@ string ChatMessage::getCustomHeaderValue (const string &headerName) const { } void ChatMessage::addCustomHeader (const string &headerName, const string &headerValue) { - L_D(ChatMessage); + L_D(); if (d->isReadOnly) return; d->customHeaders[headerName] = headerValue; } void ChatMessage::removeCustomHeader (const string &headerName) { - L_D(ChatMessage); + L_D(); if (d->isReadOnly) return; d->customHeaders.erase(headerName); @@ -379,7 +379,7 @@ void ChatMessage::updateState(State state) { } void ChatMessage::send () { - L_D(ChatMessage); + L_D(); if (d->contents.size() > 1) { MultipartChatMessageModifier mcmm; @@ -622,17 +622,17 @@ static void linphone_chat_process_response_headers_from_get_file(void *data, con belle_sip_message_t *response = BELLE_SIP_MESSAGE(event->response); belle_sip_body_handler_t *body_handler = NULL; size_t body_size = 0; - + if (msg->file_transfer_information == NULL) { ms_warning("No file transfer information for msg %p: creating...", msg); msg->file_transfer_information = linphone_chat_create_file_transfer_information_from_headers(response); } - + if (msg->file_transfer_information) { body_size = linphone_content_get_size(msg->file_transfer_information); } - - + + body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, linphone_chat_message_file_transfer_on_progress, NULL, on_recv_body, NULL, on_recv_end, msg); if (msg->file_transfer_filepath != NULL) { belle_sip_user_body_handler_t *bh = (belle_sip_user_body_handler_t *)body_handler; @@ -1072,7 +1072,7 @@ static int _linphone_chat_room_start_http_transfer(LinphoneChatMessage *msg, con } // keep a reference to the http request to be able to cancel it during upload belle_sip_object_ref(msg->http_request); - + // give msg to listener to be able to start the actual file upload when server answer a 204 No content msg->http_listener = belle_http_request_listener_create_from_callbacks(cbs, linphone_chat_message_ref(msg)); belle_http_provider_send_request(linphone_chat_room_get_core(msg->chat_room)->http_provider, msg->http_request, msg->http_listener); diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index b04b14841..2cd001716 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -94,7 +94,7 @@ void ChatRoomPrivate::removeTransientMessage (LinphoneChatMessage *msg) { // ----------------------------------------------------------------------------- void ChatRoomPrivate::release () { - L_Q(ChatRoom); + L_Q(); isComposingHandler.stopTimers(); for (auto &message : weakMessages) @@ -107,7 +107,7 @@ void ChatRoomPrivate::release () { } void ChatRoomPrivate::sendImdn (const string &content, LinphoneReason reason) { - L_Q(ChatRoom); + L_Q(); const char *identity = nullptr; LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str()); @@ -182,7 +182,7 @@ int ChatRoomPrivate::getMessagesCount (bool unreadOnly) { } void ChatRoomPrivate::setState (ChatRoom::State newState) { - L_Q(ChatRoom); + L_Q(); if (newState != state) { state = newState; if (state == ChatRoom::State::Instantiated) @@ -194,7 +194,7 @@ void ChatRoomPrivate::setState (ChatRoom::State newState) { // ----------------------------------------------------------------------------- void ChatRoomPrivate::sendIsComposingNotification () { - L_Q(ChatRoom); + L_Q(); LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(core); if (linphone_im_notif_policy_get_send_is_composing(policy)) { LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str()); @@ -261,7 +261,7 @@ void ChatRoomPrivate::sendIsComposingNotification () { * | 14 | secured flag */ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colName) { - L_Q(ChatRoom); + L_Q(); unsigned int storageId = (unsigned int)atoi(argv[0]); /* Check if the message exists in the weak messages list, in which case we should return that one. */ @@ -388,7 +388,7 @@ void ChatRoomPrivate::storeOrUpdateMessage (LinphoneChatMessage *msg) { // ----------------------------------------------------------------------------- LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *salMsg) { - L_Q(ChatRoom); + L_Q(); bool increaseMsgCount = true; LinphoneReason reason = LinphoneReasonNone; @@ -502,7 +502,7 @@ end: // ----------------------------------------------------------------------------- void ChatRoomPrivate::chatMessageReceived (LinphoneChatMessage *msg) { - L_Q(ChatRoom); + L_Q(); if (!ContentType::isImdn(linphone_chat_message_get_content_type(msg)) && !ContentType::isImIsComposing(linphone_chat_message_get_content_type(msg))) { notifyChatMessageReceived(msg); remoteIsComposing = false; @@ -512,7 +512,7 @@ void ChatRoomPrivate::chatMessageReceived (LinphoneChatMessage *msg) { } void ChatRoomPrivate::imdnReceived (const string &text) { - L_Q(ChatRoom); + L_Q(); Imdn::parse(*q, text); } @@ -523,7 +523,7 @@ void ChatRoomPrivate::isComposingReceived (const string &text) { // ----------------------------------------------------------------------------- void ChatRoomPrivate::notifyChatMessageReceived (LinphoneChatMessage *msg) { - L_Q(ChatRoom); + L_Q(); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); if (linphone_chat_message_get_text(msg)) { /* Legacy API */ @@ -537,7 +537,7 @@ void ChatRoomPrivate::notifyChatMessageReceived (LinphoneChatMessage *msg) { } void ChatRoomPrivate::notifyStateChanged () { - L_Q(ChatRoom); + L_Q(); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsStateChangedCb cb = linphone_chat_room_cbs_get_state_changed(cbs); @@ -546,7 +546,7 @@ void ChatRoomPrivate::notifyStateChanged () { } void ChatRoomPrivate::notifyUndecryptableMessageReceived (LinphoneChatMessage *msg) { - L_Q(ChatRoom); + L_Q(); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsUndecryptableMessageReceivedCb cb = linphone_chat_room_cbs_get_undecryptable_message_received(cbs); @@ -563,7 +563,7 @@ void ChatRoomPrivate::onIsComposingStateChanged (bool isComposing) { } void ChatRoomPrivate::onIsRemoteComposingStateChanged (bool isComposing) { - L_Q(ChatRoom); + L_Q(); remoteIsComposing = isComposing; linphone_core_notify_is_composing_received(core, L_GET_C_BACK_PTR(q)); } @@ -581,7 +581,7 @@ ChatRoom::ChatRoom (ChatRoomPrivate &p) : Object(p) {} // ----------------------------------------------------------------------------- void ChatRoom::compose () { - L_D(ChatRoom); + L_D(); if (!d->isComposing) { d->isComposing = true; d->sendIsComposingNotification(); @@ -591,7 +591,7 @@ void ChatRoom::compose () { } LinphoneChatMessage *ChatRoom::createFileTransferMessage (const LinphoneContent *initialContent) { - L_D(ChatRoom); + L_D(); LinphoneChatMessage *msg = createMessage(""); linphone_chat_message_set_text(msg, NULL); linphone_chat_message_set_file_transfer_information(msg, linphone_content_copy(initialContent)); @@ -621,7 +621,7 @@ LinphoneChatMessage *ChatRoom::createMessage (const string &message) { } void ChatRoom::deleteHistory () { - L_D(ChatRoom); + L_D(); if (!d->core->db) return; string peer = d->peerAddress.asStringUriOnly(); char *buf = sqlite3_mprintf("DELETE FROM history WHERE remoteContact = %Q;", peer.c_str()); @@ -631,7 +631,7 @@ void ChatRoom::deleteHistory () { } void ChatRoom::deleteMessage (LinphoneChatMessage *msg) { - L_D(ChatRoom); + L_D(); if (!d->core->db) return; char *buf = sqlite3_mprintf("DELETE FROM history WHERE id = %u;", linphone_chat_message_get_storage_id(msg)); d->sqlRequest(d->core->db, buf); @@ -643,7 +643,7 @@ void ChatRoom::deleteMessage (LinphoneChatMessage *msg) { } LinphoneChatMessage *ChatRoom::findMessage (const string &messageId) { - L_D(ChatRoom); + L_D(); LinphoneChatMessage *cm = nullptr; list l = d->findMessages(messageId); if (!l.empty()) { @@ -656,7 +656,7 @@ LinphoneChatMessage *ChatRoom::findMessage (const string &messageId) { } LinphoneChatMessage * ChatRoom::findMessageWithDirection (const string &messageId, LinphoneChatMessageDir direction) { - L_D(ChatRoom); + L_D(); LinphoneChatMessage *ret = nullptr; list l = d->findMessages(messageId); for (auto &message : l) { @@ -678,12 +678,12 @@ list ChatRoom::getHistory (int nbMessages) { } int ChatRoom::getHistorySize () { - L_D(ChatRoom); + L_D(); return d->getMessagesCount(false); } list ChatRoom::getHistoryRange (int startm, int endm) { - L_D(ChatRoom); + L_D(); if (!d->core->db) return list(); string peer = d->peerAddress.asStringUriOnly(); d->messages.clear(); @@ -739,17 +739,17 @@ list ChatRoom::getHistoryRange (int startm, int endm) { } int ChatRoom::getUnreadMessagesCount () { - L_D(ChatRoom); + L_D(); return d->getMessagesCount(true); } bool ChatRoom::isRemoteComposing () const { - L_D(const ChatRoom); + L_D(); return d->remoteIsComposing; } void ChatRoom::markAsRead () { - L_D(ChatRoom); + L_D(); if (!d->core->db) return; @@ -778,7 +778,7 @@ void ChatRoom::markAsRead () { } void ChatRoom::sendMessage (LinphoneChatMessage *msg) { - L_D(ChatRoom); + L_D(); linphone_chat_message_set_outgoing(msg); @@ -921,19 +921,19 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { // ----------------------------------------------------------------------------- LinphoneCore *ChatRoom::getCore () const { - L_D(const ChatRoom); + L_D(); return d->core; } // ----------------------------------------------------------------------------- const Address& ChatRoom::getPeerAddress () const { - L_D(const ChatRoom); + L_D(); return d->peerAddress; } ChatRoom::State ChatRoom::getState () const { - L_D(const ChatRoom); + L_D(); return d->state; } diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 147616bf8..bbfdcad87 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -50,7 +50,7 @@ shared_ptr ClientGroupChatRoom::addParticipant (const Address &addr } void ClientGroupChatRoom::addParticipants (const list
    &addresses, const CallSessionParams *params, bool hasMedia) { - L_D(ClientGroupChatRoom); + L_D(); if (addresses.empty()) return; list
    sortedAddresses(addresses); @@ -105,13 +105,13 @@ void ClientGroupChatRoom::removeParticipants (const list // ----------------------------------------------------------------------------- void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { - L_D(ClientGroupChatRoom); + L_D(); conferenceAddress = addr; d->setState(ChatRoom::State::Created); } void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { - L_D(ClientGroupChatRoom); + L_D(); d->setState(ChatRoom::State::Terminated); } diff --git a/src/chat/cpim/header/cpim-core-headers.cpp b/src/chat/cpim/header/cpim-core-headers.cpp index 4643d6e5c..866a3791c 100644 --- a/src/chat/cpim/header/cpim-core-headers.cpp +++ b/src/chat/cpim/header/cpim-core-headers.cpp @@ -74,7 +74,7 @@ bool Cpim::SubjectHeader::setValue (const string &value) { } string Cpim::SubjectHeader::getLanguage () const { - L_D(const SubjectHeader); + L_D(); return d->language; } @@ -82,14 +82,14 @@ bool Cpim::SubjectHeader::setLanguage (const string &language) { if (!language.empty() && !Parser::getInstance()->subjectHeaderLanguageIsValid(language)) return false; - L_D(SubjectHeader); + L_D(); d->language = language; return true; } string Cpim::SubjectHeader::asString () const { - L_D(const SubjectHeader); + L_D(); string languageParam; if (!d->language.empty()) @@ -99,7 +99,7 @@ string Cpim::SubjectHeader::asString () const { } void Cpim::SubjectHeader::force (const string &value, const string &language) { - L_D(SubjectHeader); + L_D(); CoreHeader::force(value); d->language = language; } diff --git a/src/chat/cpim/header/cpim-generic-header.cpp b/src/chat/cpim/header/cpim-generic-header.cpp index d2a55cbea..15ea98173 100644 --- a/src/chat/cpim/header/cpim-generic-header.cpp +++ b/src/chat/cpim/header/cpim-generic-header.cpp @@ -42,12 +42,12 @@ public: Cpim::GenericHeader::GenericHeader () : Header(*new GenericHeaderPrivate) {} string Cpim::GenericHeader::getName () const { - L_D(const GenericHeader); + L_D(); return d->name; } bool Cpim::GenericHeader::setName (const string &name) { - L_D(GenericHeader); + L_D(); static const set reserved = { "From", "To", "cc", "DateTime", "Subject", "NS", "Require" @@ -68,12 +68,12 @@ bool Cpim::GenericHeader::setValue (const string &value) { } Cpim::GenericHeader::ParameterList Cpim::GenericHeader::getParameters () const { - L_D(const GenericHeader); + L_D(); return d->parameters; } bool Cpim::GenericHeader::addParameter (const string &key, const string &value) { - L_D(GenericHeader); + L_D(); if (!Parser::getInstance()->headerParameterIsValid(key + "=" + value)) return false; @@ -83,17 +83,17 @@ bool Cpim::GenericHeader::addParameter (const string &key, const string &value) } void Cpim::GenericHeader::removeParameter (const string &key, const string &value) { - L_D(GenericHeader); + L_D(); d->parameters->remove(make_pair(key, value)); } bool Cpim::GenericHeader::isValid () const { - L_D(const GenericHeader); + L_D(); return !d->name.empty() && !getValue().empty(); } string Cpim::GenericHeader::asString () const { - L_D(const GenericHeader); + L_D(); string parameters; for (const auto ¶meter : *d->parameters) @@ -105,7 +105,7 @@ string Cpim::GenericHeader::asString () const { // ----------------------------------------------------------------------------- void Cpim::GenericHeader::force (const string &name, const string &value, const string ¶meters) { - L_D(GenericHeader); + L_D(); // Set name/value. d->name = name; diff --git a/src/chat/cpim/header/cpim-header.cpp b/src/chat/cpim/header/cpim-header.cpp index 0db1585a6..8bc6e9fb3 100644 --- a/src/chat/cpim/header/cpim-header.cpp +++ b/src/chat/cpim/header/cpim-header.cpp @@ -29,18 +29,18 @@ LINPHONE_BEGIN_NAMESPACE Cpim::Header::Header (HeaderPrivate &p) : Object(p) {} string Cpim::Header::getValue () const { - L_D(const Header); + L_D(); return d->value; } bool Cpim::Header::setValue (const string &value) { - L_D(Header); + L_D(); d->value = value; return true; } string Cpim::Header::asString () const { - L_D(const Header); + L_D(); return getName() + ": " + d->value + "\r\n"; } diff --git a/src/chat/cpim/message/cpim-message.cpp b/src/chat/cpim/message/cpim-message.cpp index 2dc33f4c3..64d63a9f2 100644 --- a/src/chat/cpim/message/cpim-message.cpp +++ b/src/chat/cpim/message/cpim-message.cpp @@ -47,12 +47,12 @@ Cpim::Message::Message () : Object(*new MessagePrivate) {} // ----------------------------------------------------------------------------- Cpim::Message::HeaderList Cpim::Message::getCpimHeaders () const { - L_D(const Message); + L_D(); return d->cpimHeaders; } bool Cpim::Message::addCpimHeader (const Header &cpimHeader) { - L_D(Message); + L_D(); if (!cpimHeader.isValid()) return false; @@ -62,7 +62,7 @@ bool Cpim::Message::addCpimHeader (const Header &cpimHeader) { } void Cpim::Message::removeCpimHeader (const Header &cpimHeader) { - L_D(Message); + L_D(); d->cpimHeaders->remove_if([&cpimHeader](const shared_ptr &header) { return cpimHeader.getName() == header->getName() && cpimHeader.getValue() == header->getValue(); }); @@ -71,12 +71,12 @@ void Cpim::Message::removeCpimHeader (const Header &cpimHeader) { // ----------------------------------------------------------------------------- Cpim::Message::HeaderList Cpim::Message::getMessageHeaders () const { - L_D(const Message); + L_D(); return d->messageHeaders; } bool Cpim::Message::addMessageHeader (const Header &messageHeader) { - L_D(Message); + L_D(); if (!messageHeader.isValid()) return false; @@ -86,7 +86,7 @@ bool Cpim::Message::addMessageHeader (const Header &messageHeader) { } void Cpim::Message::removeMessageHeader (const Header &messageHeader) { - L_D(Message); + L_D(); d->messageHeaders->remove_if([&messageHeader](const shared_ptr &header) { return messageHeader.getName() == header->getName() && messageHeader.getValue() == header->getValue(); }); @@ -95,12 +95,12 @@ void Cpim::Message::removeMessageHeader (const Header &messageHeader) { // ----------------------------------------------------------------------------- Cpim::Message::HeaderList Cpim::Message::getContentHeaders () const { - L_D(const Message); + L_D(); return d->contentHeaders; } bool Cpim::Message::addContentHeader (const Header &contentHeader) { - L_D(Message); + L_D(); if (!contentHeader.isValid()) return false; @@ -110,7 +110,7 @@ bool Cpim::Message::addContentHeader (const Header &contentHeader) { } void Cpim::Message::removeContentHeader (const Header &contentHeader) { - L_D(Message); + L_D(); d->contentHeaders->remove_if([&contentHeader](const shared_ptr &header) { return contentHeader.getName() == header->getName() && contentHeader.getValue() == header->getValue(); }); @@ -119,12 +119,12 @@ void Cpim::Message::removeContentHeader (const Header &contentHeader) { // ----------------------------------------------------------------------------- string Cpim::Message::getContent () const { - L_D(const Message); + L_D(); return d->content; } bool Cpim::Message::setContent (const string &content) { - L_D(Message); + L_D(); d->content = content; return true; } @@ -132,7 +132,7 @@ bool Cpim::Message::setContent (const string &content) { // ----------------------------------------------------------------------------- bool Cpim::Message::isValid () const { - L_D(const Message); + L_D(); return find_if(d->cpimHeaders->cbegin(), d->cpimHeaders->cend(), [](const shared_ptr &header) { @@ -143,7 +143,7 @@ bool Cpim::Message::isValid () const { // ----------------------------------------------------------------------------- string Cpim::Message::asString () const { - L_D(const Message); + L_D(); string output; for (const auto &cpimHeader : *d->cpimHeaders) diff --git a/src/chat/cpim/parser/cpim-parser.cpp b/src/chat/cpim/parser/cpim-parser.cpp index e6207d82c..48f6b7524 100644 --- a/src/chat/cpim/parser/cpim-parser.cpp +++ b/src/chat/cpim/parser/cpim-parser.cpp @@ -219,7 +219,7 @@ public: }; Cpim::Parser::Parser () : Singleton(*new ParserPrivate) { - L_D(Parser); + L_D(); belr::ABNFGrammarBuilder builder; @@ -231,7 +231,7 @@ Cpim::Parser::Parser () : Singleton(*new ParserPrivate) { // ----------------------------------------------------------------------------- shared_ptr Cpim::Parser::parseMessage (const string &input) { - L_D(Parser); + L_D(); typedef void (list >::*pushPtr)(const shared_ptr &value); @@ -300,17 +300,17 @@ static bool headerIsValid (const shared_ptr &grammar, const strin } bool Cpim::Parser::headerNameIsValid (const string &headerName) const { - L_D(const Parser); + L_D(); return headerIsValid(d->grammar, headerName + ": value\r\n"); } bool Cpim::Parser::headerValueIsValid (const string &headerValue) const { - L_D(const Parser); + L_D(); return headerIsValid(d->grammar, "key: " + headerValue + "\r\n"); } bool Cpim::Parser::headerParameterIsValid (const string &headerParameter) const { - L_D(const Parser); + L_D(); return headerIsValid(d->grammar, "key:;" + headerParameter + " value\r\n"); } @@ -338,19 +338,19 @@ static bool coreHeaderIsValid ( template<> bool Cpim::Parser::coreHeaderIsValid(const string &headerValue) const { - L_D(const Parser); + L_D(); return LINPHONE_NAMESPACE::coreHeaderIsValid(d->grammar, "From", headerValue); } template<> bool Cpim::Parser::coreHeaderIsValid(const string &headerValue) const { - L_D(const Parser); + L_D(); return LINPHONE_NAMESPACE::coreHeaderIsValid(d->grammar, "To", headerValue); } template<> bool Cpim::Parser::coreHeaderIsValid(const string &headerValue) const { - L_D(const Parser); + L_D(); return LINPHONE_NAMESPACE::coreHeaderIsValid(d->grammar, "cc", headerValue); } @@ -358,7 +358,7 @@ template<> bool Cpim::Parser::coreHeaderIsValid(const string &headerValue) const { static const int daysInMonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - L_D(const Parser); + L_D(); if (!LINPHONE_NAMESPACE::coreHeaderIsValid(d->grammar, "DateTime", headerValue)) return false; @@ -397,26 +397,26 @@ bool Cpim::Parser::coreHeaderIsValid(const string &headerV template<> bool Cpim::Parser::coreHeaderIsValid(const string &headerValue) const { - L_D(const Parser); + L_D(); return LINPHONE_NAMESPACE::coreHeaderIsValid(d->grammar, "Subject", headerValue); } template<> bool Cpim::Parser::coreHeaderIsValid(const string &headerValue) const { - L_D(const Parser); + L_D(); return LINPHONE_NAMESPACE::coreHeaderIsValid(d->grammar, "NS", headerValue); } template<> bool Cpim::Parser::coreHeaderIsValid(const string &headerValue) const { - L_D(const Parser); + L_D(); return LINPHONE_NAMESPACE::coreHeaderIsValid(d->grammar, "Require", headerValue); } // ----------------------------------------------------------------------------- bool Cpim::Parser::subjectHeaderLanguageIsValid (const string &language) const { - L_D(const Parser); + L_D(); return LINPHONE_NAMESPACE::coreHeaderIsValid(d->grammar, "Subject", "SubjectValue", ";lang=" + language); } diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 851ec9451..21b2656ba 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -47,7 +47,7 @@ RealTimeTextChatRoomPrivate::~RealTimeTextChatRoomPrivate () { // ----------------------------------------------------------------------------- void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, LinphoneCall *call) { - L_Q(ChatRoom); + L_Q(); const uint32_t new_line = 0x2028; const uint32_t crlf = 0x0D0A; const uint32_t lf = 0x0A; @@ -107,7 +107,7 @@ RealTimeTextChatRoom::RealTimeTextChatRoom (LinphoneCore *core, const Address &p // ----------------------------------------------------------------------------- void RealTimeTextChatRoom::sendMessage (LinphoneChatMessage *msg) { - L_D(ChatRoom); + L_D(); if (d->call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(d->call))) { uint32_t new_line = 0x2028; linphone_chat_message_put_char(msg, new_line); @@ -118,7 +118,7 @@ void RealTimeTextChatRoom::sendMessage (LinphoneChatMessage *msg) { // ----------------------------------------------------------------------------- uint32_t RealTimeTextChatRoom::getChar () const { - L_D(const ChatRoom); + L_D(); if (!d->receivedRttCharacters.empty()) { for (auto &cmc : d->receivedRttCharacters) { if (!cmc->has_been_read) { @@ -133,7 +133,7 @@ uint32_t RealTimeTextChatRoom::getChar () const { // ----------------------------------------------------------------------------- LinphoneCall *RealTimeTextChatRoom::getCall () const { - L_D(const ChatRoom); + L_D(); return d->call; } @@ -162,7 +162,7 @@ int RealTimeTextChatRoom::getNbParticipants () const { } list> RealTimeTextChatRoom::getParticipants () const { - L_D(const RealTimeTextChatRoom); + L_D(); list> l; l.push_back(make_shared(d->peerAddress)); return l; diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index f9a6d143a..4065dd089 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -70,7 +70,7 @@ void LocalConferenceEventHandlerPrivate::notifyAllExcept(string notify, const Ad // ============================================================================= LocalConferenceEventHandler::LocalConferenceEventHandler(LinphoneCore *core, LocalConference *localConf) : Object(*new LocalConferenceEventHandlerPrivate) { - L_D(LocalConferenceEventHandler); + L_D(); xercesc::XMLPlatformUtils::Initialize(); d->conf = localConf; d->core = core; // conf->getCore() ? @@ -83,7 +83,7 @@ LocalConferenceEventHandler::~LocalConferenceEventHandler() { // ----------------------------------------------------------------------------- string LocalConferenceEventHandler::subscribeReceived(LinphoneEvent *lev) { - L_D(LocalConferenceEventHandler); + L_D(); string entity = d->conf->getMe()->getAddress().asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; @@ -108,7 +108,7 @@ string LocalConferenceEventHandler::subscribeReceived(LinphoneEvent *lev) { } string LocalConferenceEventHandler::notifyParticipantAdded(const Address &addr) { - L_D(LocalConferenceEventHandler); + L_D(); string entity = d->conf->getMe()->getAddress().asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; @@ -130,7 +130,7 @@ string LocalConferenceEventHandler::notifyParticipantAdded(const Address &addr) } string LocalConferenceEventHandler::notifyParticipantRemoved(const Address &addr) { - L_D(LocalConferenceEventHandler); + L_D(); string entity = d->conf->getMe()->getAddress().asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; @@ -149,7 +149,7 @@ string LocalConferenceEventHandler::notifyParticipantRemoved(const Address &addr } string LocalConferenceEventHandler::notifyParticipantSetAdmin(const Address &addr, bool isAdmin) { - L_D(LocalConferenceEventHandler); + L_D(); string entity = d->conf->getMe()->getAddress().asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; diff --git a/src/conference/params/call-session-params.cpp b/src/conference/params/call-session-params.cpp index 7730438d4..c0030cc28 100644 --- a/src/conference/params/call-session-params.cpp +++ b/src/conference/params/call-session-params.cpp @@ -81,7 +81,7 @@ CallSessionParams::CallSessionParams (const CallSessionParams &src) : ClonableObject(*new CallSessionParamsPrivate(*src.getPrivate())) {} CallSessionParams &CallSessionParams::operator= (const CallSessionParams &src) { - L_D(CallSessionParams); + L_D(); if (this != &src) *d = *src.getPrivate(); return *this; @@ -90,7 +90,7 @@ CallSessionParams &CallSessionParams::operator= (const CallSessionParams &src) { // ----------------------------------------------------------------------------- void CallSessionParams::initDefault (LinphoneCore *core) { - L_D(CallSessionParams); + L_D(); d->inConference = false; d->privacy = LinphonePrivacyDefault; } @@ -98,41 +98,41 @@ void CallSessionParams::initDefault (LinphoneCore *core) { // ----------------------------------------------------------------------------- const string& CallSessionParams::getSessionName () const { - L_D(const CallSessionParams); + L_D(); return d->sessionName; } void CallSessionParams::setSessionName (const string &sessionName) { - L_D(CallSessionParams); + L_D(); d->sessionName = sessionName; } // ----------------------------------------------------------------------------- LinphonePrivacyMask CallSessionParams::getPrivacy () const { - L_D(const CallSessionParams); + L_D(); return d->privacy; } void CallSessionParams::setPrivacy (LinphonePrivacyMask privacy) { - L_D(CallSessionParams); + L_D(); d->privacy = privacy; } // ----------------------------------------------------------------------------- void CallSessionParams::addCustomHeader (const string &headerName, const string &headerValue) { - L_D(CallSessionParams); + L_D(); d->customHeaders = sal_custom_header_append(d->customHeaders, headerName.c_str(), headerValue.c_str()); } void CallSessionParams::clearCustomHeaders () { - L_D(CallSessionParams); + L_D(); d->setCustomHeaders(nullptr); } const char * CallSessionParams::getCustomHeader (const string &headerName) const { - L_D(const CallSessionParams); + L_D(); return sal_custom_header_find(d->customHeaders, headerName.c_str()); } diff --git a/src/conference/params/media-session-params.cpp b/src/conference/params/media-session-params.cpp index 03fb0c748..d04201c4c 100644 --- a/src/conference/params/media-session-params.cpp +++ b/src/conference/params/media-session-params.cpp @@ -138,7 +138,7 @@ LinphoneMediaDirection MediaSessionParamsPrivate::salStreamDirToMediaDirection ( // ----------------------------------------------------------------------------- void MediaSessionParamsPrivate::adaptToNetwork (LinphoneCore *core, int pingTimeMs) { - L_Q(MediaSessionParams); + L_Q(); if ((pingTimeMs > 0) && lp_config_get_int(linphone_core_get_config(core), "net", "activate_edge_workarounds", 0)) { lInfo() << "STUN server ping time is " << pingTimeMs << " ms"; int threshold = lp_config_get_int(linphone_core_get_config(core), "net", "edge_ping_time", 500); @@ -159,12 +159,12 @@ void MediaSessionParamsPrivate::adaptToNetwork (LinphoneCore *core, int pingTime // ----------------------------------------------------------------------------- SalStreamDir MediaSessionParamsPrivate::getSalAudioDirection () const { - L_Q(const MediaSessionParams); + L_Q(); return mediaDirectionToSalStreamDir(q->getAudioDirection()); } SalStreamDir MediaSessionParamsPrivate::getSalVideoDirection () const { - L_Q(const MediaSessionParams); + L_Q(); return mediaDirectionToSalStreamDir(q->getVideoDirection()); } @@ -220,7 +220,7 @@ MediaSessionParams::MediaSessionParams (const MediaSessionParams &src) : CallSessionParams(*new MediaSessionParamsPrivate(*src.getPrivate())) {} MediaSessionParams &MediaSessionParams::operator= (const MediaSessionParams &src) { - L_D(MediaSessionParams); + L_D(); if (this != &src) { CallSessionParams::operator=(src); *d = *src.getPrivate(); @@ -231,7 +231,7 @@ MediaSessionParams &MediaSessionParams::operator= (const MediaSessionParams &src // ----------------------------------------------------------------------------- void MediaSessionParams::initDefault (LinphoneCore *core) { - L_D(MediaSessionParams); + L_D(); CallSessionParams::initDefault(core); d->audioEnabled = true; d->videoEnabled = linphone_core_video_enabled(core) && core->video_policy.automatically_initiate; @@ -256,220 +256,220 @@ void MediaSessionParams::initDefault (LinphoneCore *core) { // ----------------------------------------------------------------------------- bool MediaSessionParams::audioEnabled () const { - L_D(const MediaSessionParams); + L_D(); return d->audioEnabled; } bool MediaSessionParams::audioMulticastEnabled () const { - L_D(const MediaSessionParams); + L_D(); return d->audioMulticastEnabled; } void MediaSessionParams::enableAudio (bool value) { - L_D(MediaSessionParams); + L_D(); d->audioEnabled = value; if (d->audioEnabled && (getAudioDirection() == LinphoneMediaDirectionInactive)) setAudioDirection(LinphoneMediaDirectionSendRecv); } void MediaSessionParams::enableAudioMulticast (bool value) { - L_D(MediaSessionParams); + L_D(); d->audioMulticastEnabled = value; } int MediaSessionParams::getAudioBandwidthLimit () const { - L_D(const MediaSessionParams); + L_D(); return d->audioBandwidthLimit; } LinphoneMediaDirection MediaSessionParams::getAudioDirection () const { - L_D(const MediaSessionParams); + L_D(); return d->audioDirection; } const OrtpPayloadType * MediaSessionParams::getUsedAudioCodec () const { - L_D(const MediaSessionParams); + L_D(); return d->usedAudioCodec; } LinphonePayloadType * MediaSessionParams::getUsedAudioPayloadType () const { - L_D(const MediaSessionParams); + L_D(); return d->usedAudioCodec ? linphone_payload_type_new(nullptr, d->usedAudioCodec) : nullptr; } void MediaSessionParams::setAudioBandwidthLimit (int value) { - L_D(MediaSessionParams); + L_D(); d->audioBandwidthLimit = value; } void MediaSessionParams::setAudioDirection (LinphoneMediaDirection direction) { - L_D(MediaSessionParams); + L_D(); d->audioDirection = direction; } // ----------------------------------------------------------------------------- void MediaSessionParams::enableVideo (bool value) { - L_D(MediaSessionParams); + L_D(); d->videoEnabled = value; if (d->videoEnabled && (getVideoDirection() == LinphoneMediaDirectionInactive)) setVideoDirection(LinphoneMediaDirectionSendRecv); } void MediaSessionParams::enableVideoMulticast (bool value) { - L_D(MediaSessionParams); + L_D(); d->videoMulticastEnabled = value; } float MediaSessionParams::getReceivedFps () const { - L_D(const MediaSessionParams); + L_D(); return d->receivedFps; } LinphoneVideoDefinition * MediaSessionParams::getReceivedVideoDefinition () const { - L_D(const MediaSessionParams); + L_D(); return d->receivedVideoDefinition; } float MediaSessionParams::getSentFps () const { - L_D(const MediaSessionParams); + L_D(); return d->sentFps; } LinphoneVideoDefinition * MediaSessionParams::getSentVideoDefinition () const { - L_D(const MediaSessionParams); + L_D(); return d->sentVideoDefinition; } const OrtpPayloadType * MediaSessionParams::getUsedVideoCodec () const { - L_D(const MediaSessionParams); + L_D(); return d->usedVideoCodec; } LinphonePayloadType * MediaSessionParams::getUsedVideoPayloadType () const { - L_D(const MediaSessionParams); + L_D(); return d->usedVideoCodec ? linphone_payload_type_new(nullptr, d->usedVideoCodec) : nullptr; } LinphoneMediaDirection MediaSessionParams::getVideoDirection () const { - L_D(const MediaSessionParams); + L_D(); return d->videoDirection; } void MediaSessionParams::setVideoDirection (LinphoneMediaDirection direction) { - L_D(MediaSessionParams); + L_D(); d->videoDirection = direction; } bool MediaSessionParams::videoEnabled () const { - L_D(const MediaSessionParams); + L_D(); return d->videoEnabled; } bool MediaSessionParams::videoMulticastEnabled () const { - L_D(const MediaSessionParams); + L_D(); return d->videoMulticastEnabled; } // ----------------------------------------------------------------------------- void MediaSessionParams::enableRealtimeText (bool value) { - L_D(MediaSessionParams); + L_D(); d->realtimeTextEnabled = value; } const OrtpPayloadType * MediaSessionParams::getUsedRealtimeTextCodec () const { - L_D(const MediaSessionParams); + L_D(); return d->usedRealtimeTextCodec; } LinphonePayloadType * MediaSessionParams::getUsedRealtimeTextPayloadType () const { - L_D(const MediaSessionParams); + L_D(); return d->usedRealtimeTextCodec ? linphone_payload_type_new(nullptr, d->usedRealtimeTextCodec) : nullptr; } bool MediaSessionParams::realtimeTextEnabled () const { - L_D(const MediaSessionParams); + L_D(); return d->realtimeTextEnabled; } // ----------------------------------------------------------------------------- bool MediaSessionParams::avpfEnabled () const { - L_D(const MediaSessionParams); + L_D(); return d->avpfEnabled; } void MediaSessionParams::enableAvpf (bool value) { - L_D(MediaSessionParams); + L_D(); d->avpfEnabled = value; } uint16_t MediaSessionParams::getAvpfRrInterval () const { - L_D(const MediaSessionParams); + L_D(); return d->avpfRrInterval; } void MediaSessionParams::setAvpfRrInterval (uint16_t value) { - L_D(MediaSessionParams); + L_D(); d->avpfRrInterval = value; } // ----------------------------------------------------------------------------- bool MediaSessionParams::lowBandwidthEnabled () const { - L_D(const MediaSessionParams); + L_D(); return d->lowBandwidthEnabled; } void MediaSessionParams::enableLowBandwidth (bool value) { - L_D(MediaSessionParams); + L_D(); d->lowBandwidthEnabled = value; } // ----------------------------------------------------------------------------- const string& MediaSessionParams::getRecordFilePath () const { - L_D(const MediaSessionParams); + L_D(); return d->recordFilePath; } void MediaSessionParams::setRecordFilePath (const string &path) { - L_D(MediaSessionParams); + L_D(); d->recordFilePath = path; } // ----------------------------------------------------------------------------- bool MediaSessionParams::earlyMediaSendingEnabled () const { - L_D(const MediaSessionParams); + L_D(); return d->earlyMediaSendingEnabled; } void MediaSessionParams::enableEarlyMediaSending (bool value) { - L_D(MediaSessionParams); + L_D(); d->earlyMediaSendingEnabled = value; } // ----------------------------------------------------------------------------- void MediaSessionParams::enableMandatoryMediaEncryption (bool value) { - L_D(MediaSessionParams); + L_D(); d->mandatoryMediaEncryptionEnabled = value; } LinphoneMediaEncryption MediaSessionParams::getMediaEncryption () const { - L_D(const MediaSessionParams); + L_D(); return d->encryption; } bool MediaSessionParams::mandatoryMediaEncryptionEnabled () const { - L_D(const MediaSessionParams); + L_D(); return d->mandatoryMediaEncryptionEnabled; } void MediaSessionParams::setMediaEncryption (LinphoneMediaEncryption encryption) { - L_D(MediaSessionParams); + L_D(); d->encryption = encryption; } @@ -491,34 +491,34 @@ const char * MediaSessionParams::getRtpProfile () const { // ----------------------------------------------------------------------------- void MediaSessionParams::addCustomSdpAttribute (const string &attributeName, const string &attributeValue) { - L_D(MediaSessionParams); + L_D(); d->customSdpAttributes = sal_custom_sdp_attribute_append(d->customSdpAttributes, attributeName.c_str(), attributeValue.c_str()); } void MediaSessionParams::clearCustomSdpAttributes () { - L_D(MediaSessionParams); + L_D(); d->setCustomSdpAttributes(nullptr); } const char * MediaSessionParams::getCustomSdpAttribute (const string &attributeName) const { - L_D(const MediaSessionParams); + L_D(); return sal_custom_sdp_attribute_find(d->customSdpAttributes, attributeName.c_str()); } // ----------------------------------------------------------------------------- void MediaSessionParams::addCustomSdpMediaAttribute (LinphoneStreamType lst, const string &attributeName, const string &attributeValue) { - L_D(MediaSessionParams); + L_D(); d->customSdpMediaAttributes[lst] = sal_custom_sdp_attribute_append(d->customSdpMediaAttributes[lst], attributeName.c_str(), attributeValue.c_str()); } void MediaSessionParams::clearCustomSdpMediaAttributes (LinphoneStreamType lst) { - L_D(MediaSessionParams); + L_D(); d->setCustomSdpMediaAttributes(lst, nullptr); } const char * MediaSessionParams::getCustomSdpMediaAttribute (LinphoneStreamType lst, const string &attributeName) const { - L_D(const MediaSessionParams); + L_D(); return sal_custom_sdp_attribute_find(d->customSdpMediaAttributes[lst], attributeName.c_str()); } diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index a7642b855..128660977 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -45,26 +45,26 @@ shared_ptr ParticipantPrivate::getSession () const { // ============================================================================= Participant::Participant (const Address &addr) : Object(*new ParticipantPrivate) { - L_D(Participant); + L_D(); d->addr = addr; } // ----------------------------------------------------------------------------- const Address& Participant::getAddress () const { - L_D(const Participant); + L_D(); return d->addr; } // ----------------------------------------------------------------------------- bool Participant::isAdmin () const { - L_D(const Participant); + L_D(); return d->isAdmin; } void Participant::setAdmin (bool isAdmin) { - L_D(Participant); + L_D(); d->isAdmin = isAdmin; } diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 38b39e7bd..6365707dc 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -44,14 +44,14 @@ public: RemoteConferenceEventHandler::RemoteConferenceEventHandler(LinphoneCore *core, ConferenceListener *listener) : Object(*new RemoteConferenceEventHandlerPrivate) { - L_D(RemoteConferenceEventHandler); + L_D(); xercesc::XMLPlatformUtils::Initialize(); d->core = core; d->listener = listener; } RemoteConferenceEventHandler::~RemoteConferenceEventHandler() { - L_D(RemoteConferenceEventHandler); + L_D(); xercesc::XMLPlatformUtils::Terminate(); if (d->lev) linphone_event_unref(d->lev); @@ -60,7 +60,7 @@ RemoteConferenceEventHandler::~RemoteConferenceEventHandler() { // ----------------------------------------------------------------------------- void RemoteConferenceEventHandler::subscribe(string confId) { - L_D(RemoteConferenceEventHandler); + L_D(); d->confId = confId; LinphoneAddress *addr = linphone_address_new(d->confAddr.asString().c_str()); d->lev = linphone_core_create_subscribe(d->core, addr, "Conference", 600); @@ -73,12 +73,12 @@ void RemoteConferenceEventHandler::subscribe(string confId) { } void RemoteConferenceEventHandler::unsubscribe() { - L_D(RemoteConferenceEventHandler); + L_D(); linphone_event_terminate(d->lev); } void RemoteConferenceEventHandler::notifyReceived(string xmlBody) { - L_D(RemoteConferenceEventHandler); + L_D(); istringstream data(xmlBody); unique_ptr confInfo = parseConferenceInfo(data, Xsd::XmlSchema::Flags::dont_validate); if (confInfo->getEntity() == d->confAddr.asString()) { @@ -109,12 +109,12 @@ void RemoteConferenceEventHandler::notifyReceived(string xmlBody) { // ----------------------------------------------------------------------------- string RemoteConferenceEventHandler::getConfId() { - L_D(RemoteConferenceEventHandler); + L_D(); return d->confId; } void RemoteConferenceEventHandler::setConferenceAddress (const Address &addr) { - L_D(RemoteConferenceEventHandler); + L_D(); d->confAddr = addr; } diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 66c1fc487..44ad05cbf 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -80,7 +80,7 @@ void CallSessionPrivate::initializeParamsAccordingToIncomingCallParams () { } void CallSessionPrivate::setState(LinphoneCallState newState, const string &message) { - L_Q(CallSession); + L_Q(); if (state != newState){ prevState = state; @@ -229,19 +229,19 @@ void CallSessionPrivate::accepted () { } void CallSessionPrivate::ackBeingSent (LinphoneHeaders *headers) { - L_Q(CallSession); + L_Q(); if (listener) listener->onAckBeingSent(*q, headers); } void CallSessionPrivate::ackReceived (LinphoneHeaders *headers) { - L_Q(CallSession); + L_Q(); if (listener) listener->onAckReceived(*q, headers); } bool CallSessionPrivate::failure () { - L_Q(CallSession); + L_Q(); const SalErrorInfo *ei = sal_op_get_error_info(op); switch (ei->reason) { case SalReasonRedirect: @@ -307,7 +307,7 @@ bool CallSessionPrivate::failure () { } void CallSessionPrivate::pingReply () { - L_Q(CallSession); + L_Q(); if (state == LinphoneCallOutgoingInit) { pingReplied = true; if (isReadyForInvite()) @@ -316,7 +316,7 @@ void CallSessionPrivate::pingReply () { } void CallSessionPrivate::remoteRinging () { - L_Q(CallSession); + L_Q(); /* Set privacy */ q->getCurrentParams()->setPrivacy((LinphonePrivacyMask)sal_op_get_privacy(op)); #if 0 @@ -401,7 +401,7 @@ void CallSessionPrivate::updated (bool isUpdate) { } void CallSessionPrivate::updatedByRemote () { - L_Q(CallSession); + L_Q(); setState(LinphoneCallUpdatedByRemote,"Call updated by remote"); if (deferUpdate) { if (state == LinphoneCallUpdatedByRemote) @@ -423,7 +423,7 @@ void CallSessionPrivate::updating (bool isUpdate) { // ----------------------------------------------------------------------------- void CallSessionPrivate::accept (const CallSessionParams *params) { - L_Q(CallSession); + L_Q(); /* Try to be best-effort in giving real local or routable contact address */ setContactOp(); if (params) { @@ -442,7 +442,7 @@ LinphoneStatus CallSessionPrivate::acceptUpdate (const CallSessionParams *csp, L } LinphoneStatus CallSessionPrivate::checkForAcceptation () const { - L_Q(const CallSession); + L_Q(); switch (state) { case LinphoneCallIncomingReceived: case LinphoneCallIncomingEarlyMedia: @@ -467,7 +467,7 @@ LinphoneStatus CallSessionPrivate::checkForAcceptation () const { } void CallSessionPrivate::handleIncomingReceivedStateInIncomingNotification () { - L_Q(CallSession); + L_Q(); /* Try to be best-effort in giving real local or routable contact address for 100Rel case */ setContactOp(); sal_call_notify_ringing(op, false); @@ -518,7 +518,7 @@ bool CallSessionPrivate::isUpdateAllowed (LinphoneCallState &nextState) const { * Called internally when reaching the Released state, to perform cleanups to break circular references. **/ void CallSessionPrivate::setReleased () { - L_Q(CallSession); + L_Q(); if (op) { /* Transfer the last error so that it can be obtained even in Released state */ if (!nonOpError) @@ -552,7 +552,7 @@ void CallSessionPrivate::setReleased () { * - update the call logs accordingly */ void CallSessionPrivate::setTerminated() { - L_Q(CallSession); + L_Q(); completeLog(); if (listener) listener->onCallSessionSetTerminated(*q); @@ -565,7 +565,7 @@ LinphoneStatus CallSessionPrivate::startAcceptUpdate (LinphoneCallState nextStat } LinphoneStatus CallSessionPrivate::startUpdate () { - L_Q(CallSession); + L_Q(); string subject; if (q->getParams()->getPrivate()->getInConference()) subject = "Conference"; @@ -617,7 +617,7 @@ void CallSessionPrivate::completeLog () { } void CallSessionPrivate::createOpTo (const LinphoneAddress *to) { - L_Q(CallSession); + L_Q(); if (op) sal_op_release(op); op = sal_op_new(core->sal); @@ -673,7 +673,7 @@ CallSession::CallSession (CallSessionPrivate &p) : Object(p) {} // ----------------------------------------------------------------------------- LinphoneStatus CallSession::accept (const CallSessionParams *csp) { - L_D(CallSession); + L_D(); LinphoneStatus result = d->checkForAcceptation(); if (result < 0) return result; d->accept(csp); @@ -681,7 +681,7 @@ LinphoneStatus CallSession::accept (const CallSessionParams *csp) { } LinphoneStatus CallSession::acceptUpdate (const CallSessionParams *csp) { - L_D(CallSession); + L_D(); if (d->state != LinphoneCallUpdatedByRemote) { lError() << "CallSession::acceptUpdate(): invalid state " << linphone_call_state_to_string(d->state) << " to call this method"; return -1; @@ -690,7 +690,7 @@ LinphoneStatus CallSession::acceptUpdate (const CallSessionParams *csp) { } void CallSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalOp *op, const Address &from, const Address &to) { - L_D(CallSession); + L_D(); d->direction = direction; d->destProxy = cfg; LinphoneAddress *fromAddr = linphone_address_new(from.asString().c_str()); @@ -727,7 +727,7 @@ LinphoneStatus CallSession::decline (LinphoneReason reason) { } LinphoneStatus CallSession::decline (const LinphoneErrorInfo *ei) { - L_D(CallSession); + L_D(); SalErrorInfo sei; SalErrorInfo sub_sei; memset(&sei, 0, sizeof(sei)); @@ -751,7 +751,7 @@ LinphoneStatus CallSession::decline (const LinphoneErrorInfo *ei) { void CallSession::initiateIncoming () {} bool CallSession::initiateOutgoing () { - L_D(CallSession); + L_D(); bool defer = false; d->setState(LinphoneCallOutgoingInit, "Starting outgoing call"); d->log->start_date_time = ms_time(nullptr); @@ -764,7 +764,7 @@ bool CallSession::initiateOutgoing () { } void CallSession::iterate (time_t currentRealTime, bool oneSecondElapsed) { - L_D(CallSession); + L_D(); int elapsed = (int)(currentRealTime - d->log->start_date_time); if ((d->state == LinphoneCallOutgoingInit) && (elapsed >= d->core->sip_conf.delayed_timeout)) { /* Start the call even if the OPTIONS reply did not arrive */ @@ -794,7 +794,7 @@ void CallSession::iterate (time_t currentRealTime, bool oneSecondElapsed) { } void CallSession::startIncomingNotification () { - L_D(CallSession); + L_D(); if (d->listener) d->listener->onCallSessionAccepted(*this); /* Prevent the CallSession from being destroyed while we are notifying, if the user declines within the state callback */ @@ -827,7 +827,7 @@ void CallSession::startIncomingNotification () { } int CallSession::startInvite (const Address *destination, const string &subject) { - L_D(CallSession); + L_D(); /* Try to be best-effort in giving real local or routable contact address */ d->setContactOp(); string destinationStr; @@ -858,7 +858,7 @@ int CallSession::startInvite (const Address *destination, const string &subject) } LinphoneStatus CallSession::terminate (const LinphoneErrorInfo *ei) { - L_D(CallSession); + L_D(); lInfo() << "Terminate CallSession [" << this << "] which is currently in state [" << linphone_call_state_to_string(d->state) << "]"; SalErrorInfo sei; memset(&sei, 0, sizeof(sei)); @@ -891,7 +891,7 @@ LinphoneStatus CallSession::terminate (const LinphoneErrorInfo *ei) { } LinphoneStatus CallSession::update (const CallSessionParams *csp) { - L_D(CallSession); + L_D(); LinphoneCallState nextState; LinphoneCallState initialState = d->state; if (!d->isUpdateAllowed(nextState)) @@ -909,12 +909,12 @@ LinphoneStatus CallSession::update (const CallSessionParams *csp) { // ----------------------------------------------------------------------------- LinphoneCallDir CallSession::getDirection () const { - L_D(const CallSession); + L_D(); return d->direction; } int CallSession::getDuration () const { - L_D(const CallSession); + L_D(); switch (d->state) { case LinphoneCallEnd: case LinphoneCallError: @@ -926,14 +926,14 @@ int CallSession::getDuration () const { } const LinphoneErrorInfo * CallSession::getErrorInfo () const { - L_D(const CallSession); + L_D(); if (!d->nonOpError) linphone_error_info_from_sal_op(d->ei, d->op); return d->ei; } LinphoneCallLog * CallSession::getLog () const { - L_D(const CallSession); + L_D(); return d->log; } @@ -942,7 +942,7 @@ LinphoneReason CallSession::getReason () const { } const Address& CallSession::getRemoteAddress () const { - L_D(const CallSession); + L_D(); return *L_GET_CPP_PTR_FROM_C_OBJECT((d->direction == LinphoneCallIncoming) ? linphone_call_log_get_from(d->log) : linphone_call_log_get_to(d->log)); } @@ -952,7 +952,7 @@ string CallSession::getRemoteAddressAsString () const { } string CallSession::getRemoteContact () const { - L_D(const CallSession); + L_D(); if (d->op) { /* sal_op_get_remote_contact preserves header params */ return sal_op_get_remote_contact(d->op); @@ -961,7 +961,7 @@ string CallSession::getRemoteContact () const { } const CallSessionParams * CallSession::getRemoteParams () { - L_D(CallSession); + L_D(); if (d->op){ const SalCustomHeader *ch = sal_op_get_recv_custom_header(d->op); if (ch) { @@ -976,21 +976,21 @@ const CallSessionParams * CallSession::getRemoteParams () { } LinphoneCallState CallSession::getState () const { - L_D(const CallSession); + L_D(); return d->state; } // ----------------------------------------------------------------------------- string CallSession::getRemoteUserAgent () const { - L_D(const CallSession); + L_D(); if (d->op) return sal_op_get_remote_ua(d->op); return string(); } CallSessionParams * CallSession::getCurrentParams () const { - L_D(const CallSession); + L_D(); d->updateCurrentParams(); return d->currentParams; } @@ -998,7 +998,7 @@ CallSessionParams * CallSession::getCurrentParams () const { // ----------------------------------------------------------------------------- const CallSessionParams * CallSession::getParams () const { - L_D(const CallSession); + L_D(); return d->params; } diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index c19d8d9ce..08e362a92 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -126,7 +126,7 @@ void MediaSessionPrivate::stunAuthRequestedCb (void *userData, const char *realm // ----------------------------------------------------------------------------- void MediaSessionPrivate::accepted () { - L_Q(MediaSession); + L_Q(); CallSessionPrivate::accepted(); LinphoneTaskList tl; linphone_task_list_init(&tl); @@ -245,7 +245,7 @@ void MediaSessionPrivate::ackReceived (LinphoneHeaders *headers) { } bool MediaSessionPrivate::failure () { - L_Q(MediaSession); + L_Q(); const SalErrorInfo *ei = sal_op_get_error_info(op); switch (ei->reason) { case SalReasonRedirect: @@ -326,7 +326,7 @@ void MediaSessionPrivate::pausedByRemote () { } void MediaSessionPrivate::remoteRinging () { - L_Q(MediaSession); + L_Q(); /* Set privacy */ q->getCurrentParams()->setPrivacy((LinphonePrivacyMask)sal_op_get_privacy(op)); SalMediaDescription *md = sal_call_get_final_media_description(op); @@ -409,7 +409,7 @@ void MediaSessionPrivate::updated (bool isUpdate) { } void MediaSessionPrivate::updating (bool isUpdate) { - L_Q(MediaSession); + L_Q(); SalMediaDescription *rmd = sal_call_get_remote_media_description(op); fixCallParams(rmd); if (state != LinphoneCallPaused) { @@ -613,7 +613,7 @@ float MediaSessionPrivate::aggregateQualityRatings (float audioRating, float vid // ----------------------------------------------------------------------------- void MediaSessionPrivate::setState (LinphoneCallState newState, const string &message) { - L_Q(MediaSession); + L_Q(); /* Take a ref on the session otherwise it might get destroyed during the call to setState */ shared_ptr session = static_pointer_cast(q->shared_from_this()); CallSessionPrivate::setState(newState, message); @@ -731,7 +731,7 @@ void MediaSessionPrivate::computeStreamsIndexes (const SalMediaDescription *md) * Fixing the params to proper values avoid request video by accident during internal call updates, pauses and resumes */ void MediaSessionPrivate::fixCallParams (SalMediaDescription *rmd) { - L_Q(MediaSession); + L_Q(); if (rmd) { computeStreamsIndexes(rmd); updateBiggestDesc(rmd); @@ -1138,7 +1138,7 @@ void MediaSessionPrivate::selectOutgoingIpVersion () { // ----------------------------------------------------------------------------- void MediaSessionPrivate::forceStreamsDirAccordingToState (SalMediaDescription *md) { - L_Q(MediaSession); + L_Q(); for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { SalStreamDescription *sd = &md->streams[i]; switch (state) { @@ -1191,7 +1191,7 @@ bool MediaSessionPrivate::generateB64CryptoKey (size_t keyLength, char *keyOut, } void MediaSessionPrivate::makeLocalMediaDescription () { - L_Q(MediaSession); + L_Q(); int maxIndex = 0; bool rtcpMux = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_mux", 0); SalMediaDescription *md = sal_media_description_new(); @@ -1527,7 +1527,7 @@ void MediaSessionPrivate::updateLocalMediaDescriptionFromIce () { // ----------------------------------------------------------------------------- SalMulticastRole MediaSessionPrivate::getMulticastRole (SalStreamType type) { - L_Q(MediaSession); + L_Q(); SalMulticastRole multicastRole = SalMulticastInactive; if (op) { SalStreamDescription *streamDesc = nullptr; @@ -1552,7 +1552,7 @@ SalMulticastRole MediaSessionPrivate::getMulticastRole (SalStreamType type) { } void MediaSessionPrivate::joinMulticastGroup (int streamIndex, MediaStream *ms) { - L_Q(MediaSession); + L_Q(); if (!mediaPorts[streamIndex].multicastIp.empty()) media_stream_join_multicast_group(ms, mediaPorts[streamIndex].multicastIp.c_str()); else @@ -1844,7 +1844,7 @@ void MediaSessionPrivate::unsetRtpProfile (int streamIndex) { } void MediaSessionPrivate::updateAllocatedAudioBandwidth (const PayloadType *pt, int maxbw) { - L_Q(MediaSession); + L_Q(); audioBandwidth = PayloadTypeHandler::getAudioPayloadTypeBandwidth(pt, maxbw); lInfo() << "Audio bandwidth for CallSession [" << q << "] is " << audioBandwidth; } @@ -1905,7 +1905,7 @@ void MediaSessionPrivate::clearEarlyMediaDestinations () { } void MediaSessionPrivate::configureAdaptiveRateControl (MediaStream *ms, const OrtpPayloadType *pt, bool videoWillBeUsed) { - L_Q(MediaSession); + L_Q(); bool enabled = linphone_core_adaptive_rate_control_enabled(core); if (!enabled) { media_stream_enable_adaptive_bitrate_control(ms, false); @@ -2062,7 +2062,7 @@ void MediaSessionPrivate::freeResources () { } void MediaSessionPrivate::handleIceEvents (OrtpEvent *ev) { - L_Q(MediaSession); + L_Q(); OrtpEventType evt = ortp_event_get_type(ev); OrtpEventData *evd = ortp_event_get_data(ev); if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { @@ -2186,7 +2186,7 @@ void MediaSessionPrivate::handleStreamEvents (int streamIndex) { } void MediaSessionPrivate::initializeAudioStream () { - L_Q(MediaSession); + L_Q(); if (audioStream) return; if (!sessions[mainAudioStreamIndex].rtp_session) { @@ -2339,7 +2339,7 @@ void MediaSessionPrivate::initializeTextStream () { void MediaSessionPrivate::initializeVideoStream () { #ifdef VIDEO_ENABLED - L_Q(MediaSession); + L_Q(); if (videoStream) return; if (!sessions[mainVideoStreamIndex].rtp_session) { @@ -2509,7 +2509,7 @@ void MediaSessionPrivate::postConfigureAudioStream (AudioStream *stream, bool mu } void MediaSessionPrivate::postConfigureAudioStreams (bool muted) { - L_Q(MediaSession); + L_Q(); postConfigureAudioStream(audioStream, muted); if (linphone_core_dtmf_received_has_listener(core)) audio_stream_play_received_dtmfs(audioStream, false); @@ -2694,7 +2694,7 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool } void MediaSessionPrivate::startStreams (LinphoneCallState targetState) { - L_Q(MediaSession); + L_Q(); switch (targetState) { case LinphoneCallIncomingEarlyMedia: if (linphone_core_get_remote_ringback_tone(core)) { @@ -2774,7 +2774,7 @@ void MediaSessionPrivate::startStreams (LinphoneCallState targetState) { } void MediaSessionPrivate::startTextStream () { - L_Q(MediaSession); + L_Q(); const SalStreamDescription *tstream = sal_media_description_find_best_stream(resultDesc, SalText); if (tstream && (tstream->dir != SalStreamInactive) && (tstream->rtp_port != 0)) { const char *rtpAddr = tstream->rtp_addr[0] != '\0' ? tstream->rtp_addr : resultDesc->addr; @@ -2811,7 +2811,7 @@ void MediaSessionPrivate::startTextStream () { void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { #ifdef VIDEO_ENABLED - L_Q(MediaSession); + L_Q(); bool reusedPreview = false; /* Shutdown preview */ MSFilter *source = nullptr; @@ -2955,7 +2955,7 @@ void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { } void MediaSessionPrivate::stopAudioStream () { - L_Q(MediaSession); + L_Q(); if (audioStream) { updateReportingMediaInfo(LINPHONE_CALL_STATS_AUDIO); media_stream_reclaim_sessions(&audioStream->ms, &sessions[mainAudioStreamIndex]); @@ -3027,7 +3027,7 @@ void MediaSessionPrivate::stopStreams () { } void MediaSessionPrivate::stopTextStream () { - L_Q(MediaSession); + L_Q(); if (textStream) { updateReportingMediaInfo(LINPHONE_CALL_STATS_TEXT); media_stream_reclaim_sessions(&textStream->ms, &sessions[mainTextStreamIndex]); @@ -3046,7 +3046,7 @@ void MediaSessionPrivate::stopTextStream () { void MediaSessionPrivate::stopVideoStream () { #ifdef VIDEO_ENABLED - L_Q(MediaSession); + L_Q(); if (videoStream) { updateReportingMediaInfo(LINPHONE_CALL_STATS_VIDEO); media_stream_reclaim_sessions(&videoStream->ms, &sessions[mainVideoStreamIndex]); @@ -3066,7 +3066,7 @@ void MediaSessionPrivate::stopVideoStream () { } void MediaSessionPrivate::tryEarlyMediaForking (SalMediaDescription *md) { - L_Q(MediaSession); + L_Q(); lInfo() << "Early media response received from another branch, checking if media can be forked to this new destination"; for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (!sal_stream_description_active(&resultDesc->streams[i])) @@ -3098,7 +3098,7 @@ void MediaSessionPrivate::tryEarlyMediaForking (SalMediaDescription *md) { } void MediaSessionPrivate::updateFrozenPayloads (SalMediaDescription *result) { - L_Q(MediaSession); + L_Q(); for (int i = 0; i < result->nb_streams; i++) { for (bctbx_list_t *elem = result->streams[i].payloads; elem != nullptr; elem = bctbx_list_next(elem)) { OrtpPayloadType *pt = reinterpret_cast(bctbx_list_get_data(elem)); @@ -3113,7 +3113,7 @@ void MediaSessionPrivate::updateFrozenPayloads (SalMediaDescription *result) { } void MediaSessionPrivate::updateStreams (SalMediaDescription *newMd, LinphoneCallState targetState) { - L_Q(MediaSession); + L_Q(); if (!((state == LinphoneCallIncomingEarlyMedia) && linphone_core_get_ring_during_incoming_early_media(core))) linphone_core_stop_ringing(core); if (!newMd) { @@ -3282,7 +3282,7 @@ void MediaSessionPrivate::audioStreamAuthTokenReady (const string &authToken, bo } void MediaSessionPrivate::audioStreamEncryptionChanged (bool encrypted) { - L_Q(MediaSession); + L_Q(); propagateEncryptionChanged(); #ifdef VIDEO_ENABLED @@ -3317,7 +3317,7 @@ unsigned int MediaSessionPrivate::getNbActiveStreams () const { } bool MediaSessionPrivate::isEncryptionMandatory () const { - L_Q(const MediaSession); + L_Q(); if (params->getMediaEncryption() == LinphoneMediaEncryptionDTLS) { lInfo() << "Forced encryption mandatory on CallSession [" << q << "] due to SRTP-DTLS"; return true; @@ -3345,7 +3345,7 @@ int MediaSessionPrivate::mediaParametersChanged (SalMediaDescription *oldMd, Sal } void MediaSessionPrivate::propagateEncryptionChanged () { - L_Q(MediaSession); + L_Q(); if (!allStreamsEncrypted()) { lInfo() << "Some streams are not encrypted"; q->getCurrentParams()->setMediaEncryption(LinphoneMediaEncryptionNone); @@ -3396,7 +3396,7 @@ void MediaSessionPrivate::updateRtpStats (LinphoneCallStats *stats, int streamIn // ----------------------------------------------------------------------------- bool MediaSessionPrivate::mediaReportEnabled (int statsType) { - L_Q(MediaSession); + L_Q(); if (!qualityReportingEnabled()) return false; if ((statsType == LINPHONE_CALL_STATS_VIDEO) && !q->getCurrentParams()->videoEnabled()) @@ -3445,7 +3445,7 @@ void MediaSessionPrivate::updateReportingCallState () { } void MediaSessionPrivate::updateReportingMediaInfo (int statsType) { - L_Q(MediaSession); + L_Q(); /* op might be already released if hanging up in state LinphoneCallOutgoingInit */ if (!op || !mediaReportEnabled(statsType)) return; @@ -3577,7 +3577,7 @@ void MediaSessionPrivate::executeBackgroundTasks (bool oneSecondElapsed) { } void MediaSessionPrivate::reportBandwidth () { - L_Q(MediaSession); + L_Q(); reportBandwidthForStream(&audioStream->ms, LinphoneStreamTypeAudio); reportBandwidthForStream(&videoStream->ms, LinphoneStreamTypeVideo); reportBandwidthForStream(&textStream->ms, LinphoneStreamTypeText); @@ -3631,7 +3631,7 @@ void MediaSessionPrivate::abort (const string &errorMsg) { } void MediaSessionPrivate::handleIncomingReceivedStateInIncomingNotification () { - L_Q(MediaSession); + L_Q(); /* Try to be best-effort in giving real local or routable contact address for 100Rel case */ setContactOp(); bool proposeEarlyMedia = lp_config_get_int(linphone_core_get_config(core), "sip", "incoming_calls_early_media", false); @@ -3655,7 +3655,7 @@ bool MediaSessionPrivate::isReadyForInvite () const { } LinphoneStatus MediaSessionPrivate::pause () { - L_Q(MediaSession); + L_Q(); if ((state != LinphoneCallStreamsRunning) && (state != LinphoneCallPausedByRemote)) { lWarning() << "Cannot pause this MediaSession, it is not active"; return -1; @@ -3874,7 +3874,7 @@ void MediaSessionPrivate::accept (const MediaSessionParams *csp) { } LinphoneStatus MediaSessionPrivate::acceptUpdate (const CallSessionParams *csp, LinphoneCallState nextState, const string &stateInfo) { - L_Q(MediaSession); + L_Q(); SalMediaDescription *desc = sal_call_get_remote_media_description(op); bool keepSdpVersion = lp_config_get_int(linphone_core_get_config(core), "sip", "keep_sdp_version", 0); if (keepSdpVersion && (desc->session_id == remoteSessionId) && (desc->session_ver == remoteSessionVer)) { @@ -3915,7 +3915,7 @@ LinphoneStatus MediaSessionPrivate::acceptUpdate (const CallSessionParams *csp, #ifdef VIDEO_ENABLED void MediaSessionPrivate::videoStreamEventCb (const MSFilter *f, const unsigned int eventId, const void *args) { - L_Q(MediaSession); + L_Q(); switch (eventId) { case MS_VIDEO_DECODER_DECODING_ERRORS: lWarning() << "MS_VIDEO_DECODER_DECODING_ERRORS"; @@ -4000,14 +4000,14 @@ void MediaSessionPrivate::stunAuthRequestedCb (const char *realm, const char *no MediaSession::MediaSession (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener) : CallSession(*new MediaSessionPrivate(conference, params, listener)) { - L_D(MediaSession); + L_D(); d->iceAgent = new IceAgent(*this); } // ----------------------------------------------------------------------------- LinphoneStatus MediaSession::accept (const MediaSessionParams *msp) { - L_D(MediaSession); + L_D(); LinphoneStatus result = d->checkForAcceptation(); if (result < 0) return result; @@ -4036,7 +4036,7 @@ LinphoneStatus MediaSession::accept (const MediaSessionParams *msp) { } LinphoneStatus MediaSession::acceptEarlyMedia (const MediaSessionParams *msp) { - L_D(MediaSession); + L_D(); if (d->state != LinphoneCallIncomingReceived) { lError() << "Bad state " << linphone_call_state_to_string(d->state) << " for MediaSession::acceptEarlyMedia()"; return -1; @@ -4059,7 +4059,7 @@ LinphoneStatus MediaSession::acceptEarlyMedia (const MediaSessionParams *msp) { } LinphoneStatus MediaSession::acceptUpdate (const MediaSessionParams *msp) { - L_D(MediaSession); + L_D(); if (d->expectMediaInAck) { lError() << "MediaSession::acceptUpdate() is not possible during a late offer incoming reINVITE (INVITE without SDP)"; return -1; @@ -4070,7 +4070,7 @@ LinphoneStatus MediaSession::acceptUpdate (const MediaSessionParams *msp) { // ----------------------------------------------------------------------------- void MediaSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalOp *op, const Address &from, const Address &to) { - L_D(MediaSession); + L_D(); CallSession::configure (direction, cfg, op, from, to); if (d->destProxy) @@ -4120,7 +4120,7 @@ void MediaSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cf } void MediaSession::initiateIncoming () { - L_D(MediaSession); + L_D(); CallSession::initiateIncoming(); d->initializeStreams(); if (d->natPolicy) { @@ -4130,7 +4130,7 @@ void MediaSession::initiateIncoming () { } bool MediaSession::initiateOutgoing () { - L_D(MediaSession); + L_D(); bool defer = CallSession::initiateOutgoing(); d->initializeStreams(); if (linphone_nat_policy_ice_enabled(d->natPolicy)) { @@ -4145,7 +4145,7 @@ bool MediaSession::initiateOutgoing () { } void MediaSession::iterate (time_t currentRealTime, bool oneSecondElapsed) { - L_D(MediaSession); + L_D(); int elapsed = (int)(currentRealTime - d->log->start_date_time); d->executeBackgroundTasks(oneSecondElapsed); if ((d->state == LinphoneCallOutgoingInit) && (elapsed >= d->core->sip_conf.delayed_timeout)) { @@ -4158,7 +4158,7 @@ void MediaSession::iterate (time_t currentRealTime, bool oneSecondElapsed) { } LinphoneStatus MediaSession::pause () { - L_D(MediaSession); + L_D(); LinphoneStatus result = d->pause(); if (result == 0) d->pausedByApp = true; @@ -4166,7 +4166,7 @@ LinphoneStatus MediaSession::pause () { } LinphoneStatus MediaSession::resume () { - L_D(MediaSession); + L_D(); if (d->state != LinphoneCallPaused) { lWarning() << "we cannot resume a call that has not been established and paused before"; return -1; @@ -4211,7 +4211,7 @@ LinphoneStatus MediaSession::resume () { void MediaSession::sendVfuRequest () { #ifdef VIDEO_ENABLED - L_D(MediaSession); + L_D(); MediaSessionParams *currentParams = getCurrentParams(); if ((currentParams->avpfEnabled() || currentParams->getPrivate()->implicitRtcpFbEnabled()) && d->videoStream && media_stream_get_state(&d->videoStream->ms) == MSStreamStarted) { // || sal_media_description_has_implicit_avpf((const SalMediaDescription *)call->resultdesc) @@ -4227,7 +4227,7 @@ void MediaSession::sendVfuRequest () { } void MediaSession::startIncomingNotification () { - L_D(MediaSession); + L_D(); d->makeLocalMediaDescription(); sal_call_set_local_media_description(d->op, d->localDesc); SalMediaDescription *md = sal_call_get_final_media_description(d->op); @@ -4250,7 +4250,7 @@ void MediaSession::startIncomingNotification () { } int MediaSession::startInvite (const Address *destination, const string &subject) { - L_D(MediaSession); + L_D(); linphone_core_stop_dtmf_stream(d->core); d->makeLocalMediaDescription(); if (d->core->ringstream && d->core->sound_conf.play_sndcard && d->core->sound_conf.capt_sndcard) { @@ -4280,7 +4280,7 @@ int MediaSession::startInvite (const Address *destination, const string &subject } void MediaSession::startRecording () { - L_D(MediaSession); + L_D(); if (d->params->getRecordFilePath().empty()) { lError() << "MediaSession::startRecording(): no output file specified. Use linphone_call_params_set_record_file()"; return; @@ -4291,14 +4291,14 @@ void MediaSession::startRecording () { } void MediaSession::stopRecording () { - L_D(MediaSession); + L_D(); if (d->audioStream && !d->params->getPrivate()->getInConference()) audio_stream_mixed_record_stop(d->audioStream); d->recordActive = false; } LinphoneStatus MediaSession::update (const MediaSessionParams *msp) { - L_D(MediaSession); + L_D(); LinphoneCallState nextState; LinphoneCallState initialState = d->state; if (!d->isUpdateAllowed(nextState)) @@ -4343,14 +4343,14 @@ LinphoneStatus MediaSession::update (const MediaSessionParams *msp) { // ----------------------------------------------------------------------------- void MediaSession::resetFirstVideoFrameDecoded () { - L_D(MediaSession); + L_D(); if (d->videoStream && d->videoStream->ms.decoder) ms_filter_call_method_noarg(d->videoStream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION); } LinphoneStatus MediaSession::takePreviewSnapshot (const string& file) { #ifdef VIDEO_ENABLED - L_D(MediaSession); + L_D(); if (d->videoStream && d->videoStream->local_jpegwriter) { const char *filepath = file.empty() ? nullptr : file.c_str(); return ms_filter_call_method(d->videoStream->local_jpegwriter, MS_JPEG_WRITER_TAKE_SNAPSHOT, (void *)filepath); @@ -4362,7 +4362,7 @@ LinphoneStatus MediaSession::takePreviewSnapshot (const string& file) { LinphoneStatus MediaSession::takeVideoSnapshot (const string& file) { #ifdef VIDEO_ENABLED - L_D(MediaSession); + L_D(); if (d->videoStream && d->videoStream->jpegwriter) { const char *filepath = file.empty() ? nullptr : file.c_str(); return ms_filter_call_method(d->videoStream->jpegwriter, MS_JPEG_WRITER_TAKE_SNAPSHOT, (void *)filepath); @@ -4373,7 +4373,7 @@ LinphoneStatus MediaSession::takeVideoSnapshot (const string& file) { } void MediaSession::zoomVideo (float zoomFactor, float *cx, float *cy) { - L_D(MediaSession); + L_D(); if (d->videoStream && d->videoStream->output) { if (zoomFactor < 1) zoomFactor = 1; @@ -4395,12 +4395,12 @@ void MediaSession::zoomVideo (float zoomFactor, float *cx, float *cy) { // ----------------------------------------------------------------------------- bool MediaSession::cameraEnabled () const { - L_D(const MediaSession); + L_D(); return d->cameraEnabled; } bool MediaSession::echoCancellationEnabled () const { - L_D(const MediaSession); + L_D(); if (d->audioStream && d->audioStream->ec) { bool val; ms_filter_call_method(d->audioStream->ec, MS_ECHO_CANCELLER_GET_BYPASS_MODE, &val); @@ -4410,7 +4410,7 @@ bool MediaSession::echoCancellationEnabled () const { } bool MediaSession::echoLimiterEnabled () const { - L_D(const MediaSession); + L_D(); if (d->audioStream) return d->audioStream->el_type !=ELInactive; else @@ -4418,7 +4418,7 @@ bool MediaSession::echoLimiterEnabled () const { } void MediaSession::enableCamera (bool value) { - L_D(MediaSession); + L_D(); #ifdef VIDEO_ENABLED d->cameraEnabled = value; switch (d->state) { @@ -4440,7 +4440,7 @@ void MediaSession::enableCamera (bool value) { } void MediaSession::enableEchoCancellation (bool value) { - L_D(MediaSession); + L_D(); if (d->audioStream && d->audioStream->ec) { bool bypassMode = !value; ms_filter_call_method(d->audioStream->ec, MS_ECHO_CANCELLER_SET_BYPASS_MODE, &bypassMode); @@ -4448,7 +4448,7 @@ void MediaSession::enableEchoCancellation (bool value) { } void MediaSession::enableEchoLimiter (bool value) { - L_D(MediaSession); + L_D(); if (d->audioStream) { if (value) { string type = lp_config_get_string(linphone_core_get_config(d->core), "sound", "el_type", "mic"); @@ -4462,7 +4462,7 @@ void MediaSession::enableEchoLimiter (bool value) { } bool MediaSession::getAllMuted () const { - L_D(const MediaSession); + L_D(); return d->allMuted; } @@ -4471,17 +4471,17 @@ LinphoneCallStats * MediaSession::getAudioStats () const { } string MediaSession::getAuthenticationToken () const { - L_D(const MediaSession); + L_D(); return d->authToken; } bool MediaSession::getAuthenticationTokenVerified () const { - L_D(const MediaSession); + L_D(); return d->authTokenVerified; } float MediaSession::getAverageQuality () const { - L_D(const MediaSession); + L_D(); float audioRating = -1.f; float videoRating = -1.f; if (d->audioStream) @@ -4492,13 +4492,13 @@ float MediaSession::getAverageQuality () const { } MediaSessionParams * MediaSession::getCurrentParams () const { - L_D(const MediaSession); + L_D(); d->updateCurrentParams(); return d->currentParams; } float MediaSession::getCurrentQuality () const { - L_D(const MediaSession); + L_D(); float audioRating = -1.f; float videoRating = -1.f; if (d->audioStream) @@ -4509,12 +4509,12 @@ float MediaSession::getCurrentQuality () const { } const MediaSessionParams * MediaSession::getMediaParams () const { - L_D(const MediaSession); + L_D(); return d->params; } RtpTransport * MediaSession::getMetaRtcpTransport (int streamIndex) const { - L_D(const MediaSession); + L_D(); if ((streamIndex < 0) || (streamIndex >= getStreamCount())) return nullptr; RtpTransport *metaRtp; @@ -4524,7 +4524,7 @@ RtpTransport * MediaSession::getMetaRtcpTransport (int streamIndex) const { } RtpTransport * MediaSession::getMetaRtpTransport (int streamIndex) const { - L_D(const MediaSession); + L_D(); if ((streamIndex < 0) || (streamIndex >= getStreamCount())) return nullptr; RtpTransport *metaRtp; @@ -4534,7 +4534,7 @@ RtpTransport * MediaSession::getMetaRtpTransport (int streamIndex) const { } float MediaSession::getMicrophoneVolumeGain () const { - L_D(const MediaSession); + L_D(); if (d->audioStream) return audio_stream_get_sound_card_input_gain(d->audioStream); else { @@ -4544,7 +4544,7 @@ float MediaSession::getMicrophoneVolumeGain () const { } void * MediaSession::getNativeVideoWindowId () const { - L_D(const MediaSession); + L_D(); if (d->videoWindowId) { /* The video id was previously set by the app */ return d->videoWindowId; @@ -4559,12 +4559,12 @@ void * MediaSession::getNativeVideoWindowId () const { } const CallSessionParams * MediaSession::getParams () const { - L_D(const MediaSession); + L_D(); return d->params; } float MediaSession::getPlayVolume () const { - L_D(const MediaSession); + L_D(); if (d->audioStream && d->audioStream->volrecv) { float vol = 0; ms_filter_call_method(d->audioStream->volrecv, MS_VOLUME_GET, &vol); @@ -4574,7 +4574,7 @@ float MediaSession::getPlayVolume () const { } float MediaSession::getRecordVolume () const { - L_D(const MediaSession); + L_D(); if (d->audioStream && d->audioStream->volsend && !d->audioMuted && (d->state == LinphoneCallStreamsRunning)) { float vol = 0; ms_filter_call_method(d->audioStream->volsend, MS_VOLUME_GET, &vol); @@ -4584,7 +4584,7 @@ float MediaSession::getRecordVolume () const { } const MediaSessionParams * MediaSession::getRemoteParams () { - L_D(MediaSession); + L_D(); if (d->op){ SalMediaDescription *md = sal_call_get_remote_media_description(d->op); if (md) { @@ -4637,7 +4637,7 @@ const MediaSessionParams * MediaSession::getRemoteParams () { } float MediaSession::getSpeakerVolumeGain () const { - L_D(const MediaSession); + L_D(); if (d->audioStream) return audio_stream_get_sound_card_output_gain(d->audioStream); else { @@ -4647,7 +4647,7 @@ float MediaSession::getSpeakerVolumeGain () const { } LinphoneCallStats * MediaSession::getStats (LinphoneStreamType type) const { - L_D(const MediaSession); + L_D(); if (type == LinphoneStreamTypeUnknown) return nullptr; LinphoneCallStats *stats = nullptr; @@ -4679,7 +4679,7 @@ int MediaSession::getStreamCount () const { } MSFormatType MediaSession::getStreamType (int streamIndex) const { - L_D(const MediaSession); + L_D(); /* TODO: Revisit when multiple media streams will be implemented */ if (streamIndex == d->mainVideoStreamIndex) return MSVideo; @@ -4699,7 +4699,7 @@ LinphoneCallStats * MediaSession::getVideoStats () const { } bool MediaSession::mediaInProgress () const { - L_D(const MediaSession); + L_D(); if ((linphone_call_stats_get_ice_state(d->audioStats) == LinphoneIceStateInProgress) || (linphone_call_stats_get_ice_state(d->videoStats) == LinphoneIceStateInProgress) || (linphone_call_stats_get_ice_state(d->textStats) == LinphoneIceStateInProgress)) @@ -4709,7 +4709,7 @@ bool MediaSession::mediaInProgress () const { } void MediaSession::setAuthenticationTokenVerified (bool value) { - L_D(MediaSession); + L_D(); if (!d->audioStream || !media_stream_started(&d->audioStream->ms)) { lError() << "MediaSession::setAuthenticationTokenVerified(): No audio stream or not started"; return; @@ -4727,7 +4727,7 @@ void MediaSession::setAuthenticationTokenVerified (bool value) { } void MediaSession::setMicrophoneVolumeGain (float value) { - L_D(MediaSession); + L_D(); if(d->audioStream) audio_stream_set_sound_card_input_gain(d->audioStream, value); else @@ -4735,7 +4735,7 @@ void MediaSession::setMicrophoneVolumeGain (float value) { } void MediaSession::setNativeVideoWindowId (void *id) { - L_D(MediaSession); + L_D(); d->videoWindowId = id; #ifdef VIDEO_ENABLED if (d->videoStream) @@ -4744,7 +4744,7 @@ void MediaSession::setNativeVideoWindowId (void *id) { } void MediaSession::setSpeakerVolumeGain (float value) { - L_D(MediaSession); + L_D(); if (d->audioStream) audio_stream_set_sound_card_output_gain(d->audioStream, value); else diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index 6d0815811..1605d6eed 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -34,7 +34,7 @@ public: // ----------------------------------------------------------------------------- ContentType::ContentType (const string &contentType) : ClonableObject(*new ContentTypePrivate) { - L_D(ContentType); + L_D(); size_t pos = contentType.find('/'); if (pos == string::npos) @@ -47,7 +47,7 @@ ContentType::ContentType (const string &contentType) : ClonableObject(*new Conte } ContentType::ContentType (const string &type, const string &subType) : ClonableObject(*new ContentTypePrivate) { - L_D(ContentType); + L_D(); if (setType(type)) { if (!setSubType(subType)) @@ -75,12 +75,12 @@ bool ContentType::operator== (const string &contentType) { } const string &ContentType::getType () const { - L_D(const ContentType); + L_D(); return d->type; } bool ContentType::setType (const string &type) { - L_D(ContentType); + L_D(); if (type.find('/') == string::npos) { d->type = type; return true; @@ -89,12 +89,12 @@ bool ContentType::setType (const string &type) { } const string &ContentType::getSubType () const { - L_D(const ContentType); + L_D(); return d->subType; } bool ContentType::setSubType (const string &subType) { - L_D(ContentType); + L_D(); if (subType.find('/') == string::npos) { d->subType = subType; return true; @@ -103,12 +103,12 @@ bool ContentType::setSubType (const string &subType) { } bool ContentType::isValid () const { - L_D(const ContentType); + L_D(); return !d->type.empty() && !d->subType.empty(); } string ContentType::asString () const { - L_D(const ContentType); + L_D(); return isValid() ? d->type + "/" + d->subType : ""; } diff --git a/src/content/content.cpp b/src/content/content.cpp index efac402a1..8b055e6ba 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -39,19 +39,19 @@ public: Content::Content () : ClonableObject(*new ContentPrivate) {} Content::Content (const Content &src) : ClonableObject(*new ContentPrivate) { - L_D(Content); + L_D(); d->body = src.getBody(); d->contentType = src.getContentType(); } Content::Content (Content &&src) : ClonableObject(*new ContentPrivate) { - L_D(Content); + L_D(); d->body = move(src.getPrivate()->body); d->contentType = move(src.getPrivate()->contentType); } Content &Content::operator= (const Content &src) { - L_D(Content); + L_D(); if (this != &src) { d->body = src.getBody(); d->contentType = src.getContentType(); @@ -61,65 +61,65 @@ Content &Content::operator= (const Content &src) { } Content &Content::operator= (Content &&src) { - L_D(Content); + L_D(); d->body = move(src.getPrivate()->body); d->contentType = move(src.getPrivate()->contentType); return *this; } const ContentType &Content::getContentType () const { - L_D(const Content); + L_D(); return d->contentType; } void Content::setContentType (const ContentType &contentType) { - L_D(Content); + L_D(); d->contentType = contentType; } void Content::setContentType (const string &contentType) { - L_D(Content); + L_D(); d->contentType = ContentType(contentType); } const string &Content::getContentDisposition () const { - L_D(const Content); + L_D(); return d->contentDisposition; } void Content::setContentDisposition (const string &contentDisposition) { - L_D(Content); + L_D(); d->contentDisposition = contentDisposition; } const vector &Content::getBody () const { - L_D(const Content); + L_D(); return d->body; } string Content::getBodyAsString () const { - L_D(const Content); + L_D(); return string(d->body.begin(), d->body.end()); } void Content::setBody (const vector &body) { - L_D(Content); + L_D(); d->body = body; } void Content::setBody (const string &body) { - L_D(Content); + L_D(); d->body = vector(body.cbegin(), body.cend()); } void Content::setBody (const void *buffer, size_t size) { - L_D(Content); + L_D(); const char *start = static_cast(buffer); d->body = vector(start, start + size); } size_t Content::getSize () const { - L_D(const Content); + L_D(); return d->body.size(); } diff --git a/src/db/abstract/abstract-db.cpp b/src/db/abstract/abstract-db.cpp index bbb80d4dd..1aaee41e5 100644 --- a/src/db/abstract/abstract-db.cpp +++ b/src/db/abstract/abstract-db.cpp @@ -29,7 +29,7 @@ LINPHONE_BEGIN_NAMESPACE AbstractDb::AbstractDb (AbstractDbPrivate &p) : Object(*new AbstractDbPrivate) {} bool AbstractDb::connect (Backend backend, const string ¶meters) { - L_D(AbstractDb); + L_D(); d->backend = backend; d->dbSession = DbSessionProvider::getInstance()->getSession( @@ -51,12 +51,12 @@ bool AbstractDb::connect (Backend backend, const string ¶meters) { } bool AbstractDb::isConnected () const { - L_D(const AbstractDb); + L_D(); return d->dbSession; } AbstractDb::Backend AbstractDb::getBackend () const { - L_D(const AbstractDb); + L_D(); return d->backend; } @@ -69,7 +69,7 @@ void AbstractDb::init () { // ----------------------------------------------------------------------------- string AbstractDb::primaryKeyAutoIncrementStr (const string &type) const { - L_D(const AbstractDb); + L_D(); switch (d->backend) { case Mysql: diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 8befd680f..04bca024c 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -129,7 +129,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} // ----------------------------------------------------------------------------- void EventsDb::init () { - L_D(EventsDb); + L_D(); soci::session *session = d->dbSession.getBackendSession(); *session << @@ -344,7 +344,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} } int EventsDb::getEventsCount (FilterMask mask) const { - L_D(const EventsDb); + L_D(); if (!isConnected()) { lWarning() << "Unable to get events count. Not connected."; @@ -366,7 +366,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} } int EventsDb::getMessagesCount (const string &remoteAddress) const { - L_D(const EventsDb); + L_D(); if (!isConnected()) { lWarning() << "Unable to get messages count. Not connected."; @@ -393,7 +393,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} } int EventsDb::getUnreadMessagesCount (const string &remoteAddress) const { - L_D(const EventsDb); + L_D(); if (!isConnected()) { lWarning() << "Unable to get unread messages count. Not connected."; diff --git a/src/db/provider/db-session-provider.cpp b/src/db/provider/db-session-provider.cpp index 34edc9a5f..7094be668 100644 --- a/src/db/provider/db-session-provider.cpp +++ b/src/db/provider/db-session-provider.cpp @@ -43,7 +43,7 @@ public: DbSessionProvider::DbSessionProvider () : Singleton(*new DbSessionProviderPrivate) {} DbSession DbSessionProvider::getSession (const string &uri) { - L_D(DbSessionProvider); + L_D(); #ifdef SOCI_ENABLED DbSession session(DbSession::Soci); diff --git a/src/db/provider/db-session.cpp b/src/db/provider/db-session.cpp index 48969d2e9..8abb52039 100644 --- a/src/db/provider/db-session.cpp +++ b/src/db/provider/db-session.cpp @@ -25,24 +25,24 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE DbSession::DbSession (Type type) : ClonableObject(*new DbSessionPrivate) { - L_D(DbSession); + L_D(); d->type = type; } L_USE_DEFAULT_SHARE_IMPL(DbSession, ClonableObject); DbSession::operator bool () const { - L_D(const DbSession); + L_D(); return d->isValid; } DbSession::Type DbSession::getBackendType () const { - L_D(const DbSession); + L_D(); return d->type; } void *DbSession::getBackendSession () const { - L_D(const DbSession); + L_D(); return d->backendSession.get(); } diff --git a/src/event-log/call-event.cpp b/src/event-log/call-event.cpp index 6e304e7e2..e1b1f9f86 100644 --- a/src/event-log/call-event.cpp +++ b/src/event-log/call-event.cpp @@ -33,7 +33,7 @@ public: // ----------------------------------------------------------------------------- CallEvent::CallEvent (Type type, const shared_ptr &call) : EventLog(*new CallEventPrivate, type) { - L_D(CallEvent); + L_D(); L_ASSERT(call); L_ASSERT(type == Type::CallStart || type == Type::CallEnd); d->call = call; @@ -42,7 +42,7 @@ CallEvent::CallEvent (Type type, const shared_ptr &call) : EventLog(*new C CallEvent::CallEvent (const CallEvent &src) : CallEvent(src.getType(), src.getCall()) {} CallEvent &CallEvent::operator= (const CallEvent &src) { - L_D(CallEvent); + L_D(); if (this != &src) { EventLog::operator=(src); d->call = src.getPrivate()->call; @@ -52,7 +52,7 @@ CallEvent &CallEvent::operator= (const CallEvent &src) { } shared_ptr CallEvent::getCall () const { - L_D(const CallEvent); + L_D(); return d->call; } diff --git a/src/event-log/chat-message-event.cpp b/src/event-log/chat-message-event.cpp index 3fab969d7..ed2119772 100644 --- a/src/event-log/chat-message-event.cpp +++ b/src/event-log/chat-message-event.cpp @@ -34,7 +34,7 @@ public: ChatMessageEvent::ChatMessageEvent (const shared_ptr &chatMessage) : EventLog(*new ChatMessageEventPrivate, EventLog::Type::ChatMessage) { - L_D(ChatMessageEvent); + L_D(); L_ASSERT(chatMessage); d->chatMessage = chatMessage; } @@ -42,7 +42,7 @@ ChatMessageEvent::ChatMessageEvent (const shared_ptr &chatMessage) ChatMessageEvent::ChatMessageEvent (const ChatMessageEvent &src) : ChatMessageEvent(src.getChatMessage()) {} ChatMessageEvent &ChatMessageEvent::operator= (const ChatMessageEvent &src) { - L_D(ChatMessageEvent); + L_D(); if (this != &src) { EventLog::operator=(src); d->chatMessage = src.getPrivate()->chatMessage; @@ -52,7 +52,7 @@ ChatMessageEvent &ChatMessageEvent::operator= (const ChatMessageEvent &src) { } shared_ptr ChatMessageEvent::getChatMessage () const { - L_D(const ChatMessageEvent); + L_D(); return d->chatMessage; } diff --git a/src/event-log/conference-event.cpp b/src/event-log/conference-event.cpp index 81d79b4d2..7d8bb1ba9 100644 --- a/src/event-log/conference-event.cpp +++ b/src/event-log/conference-event.cpp @@ -27,7 +27,7 @@ LINPHONE_BEGIN_NAMESPACE ConferenceEvent::ConferenceEvent (Type type, const Address &address) : EventLog(*new ConferenceEventPrivate, type) { - L_D(ConferenceEvent); + L_D(); L_ASSERT(type == Type::ConferenceCreated || type == Type::ConferenceDestroyed); d->address = address; } @@ -36,12 +36,12 @@ ConferenceEvent::ConferenceEvent (const ConferenceEvent &src) : ConferenceEvent( ConferenceEvent::ConferenceEvent (ConferenceEventPrivate &p, Type type, const Address &address) : EventLog(p, type) { - L_D(ConferenceEvent); + L_D(); d->address = address; } ConferenceEvent &ConferenceEvent::operator= (const ConferenceEvent &src) { - L_D(ConferenceEvent); + L_D(); if (this != &src) { EventLog::operator=(src); d->address = src.getPrivate()->address; @@ -51,7 +51,7 @@ ConferenceEvent &ConferenceEvent::operator= (const ConferenceEvent &src) { } const Address &ConferenceEvent::getAddress () const { - L_D(const ConferenceEvent); + L_D(); return d->address; } diff --git a/src/event-log/conference-participant-event.cpp b/src/event-log/conference-participant-event.cpp index 0d1bf0443..82a98b81f 100644 --- a/src/event-log/conference-participant-event.cpp +++ b/src/event-log/conference-participant-event.cpp @@ -38,7 +38,7 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( const Address &conferenceAddress, const Address &participantAddress ) : ConferenceEvent(*new ConferenceParticipantEventPrivate, type, conferenceAddress) { - L_D(ConferenceParticipantEvent); + L_D(); L_ASSERT( type == Type::ConferenceParticipantAdded || type == Type::ConferenceParticipantRemoved || @@ -52,7 +52,7 @@ ConferenceParticipantEvent::ConferenceParticipantEvent (const ConferenceParticip ConferenceParticipantEvent(src.getType(), src.getAddress(), src.getParticipantAddress()) {} ConferenceParticipantEvent &ConferenceParticipantEvent::operator= (const ConferenceParticipantEvent &src) { - L_D(ConferenceParticipantEvent); + L_D(); if (this != &src) { ConferenceEvent::operator=(src); d->participantAddress = src.getPrivate()->participantAddress; @@ -62,7 +62,7 @@ ConferenceParticipantEvent &ConferenceParticipantEvent::operator= (const Confere } const Address &ConferenceParticipantEvent::getParticipantAddress () const { - L_D(const ConferenceParticipantEvent); + L_D(); return d->participantAddress; } diff --git a/src/event-log/event-log.cpp b/src/event-log/event-log.cpp index e90a0ef9c..f37e802de 100644 --- a/src/event-log/event-log.cpp +++ b/src/event-log/event-log.cpp @@ -27,19 +27,19 @@ EventLog::EventLog () : ClonableObject(*new EventLogPrivate) {} EventLog::EventLog (const EventLog &) : ClonableObject(*new EventLogPrivate) {} EventLog::EventLog (EventLogPrivate &p, Type type) : ClonableObject(*new EventLogPrivate) { - L_D(EventLog); + L_D(); d->type = type; } EventLog &EventLog::operator= (const EventLog &src) { - L_D(EventLog); + L_D(); if (this != &src) d->type = src.getPrivate()->type; return *this; } EventLog::Type EventLog::getType () const { - L_D(const EventLog); + L_D(); return d->type; } diff --git a/src/logger/logger.cpp b/src/logger/logger.cpp index ede21b596..8689230a2 100644 --- a/src/logger/logger.cpp +++ b/src/logger/logger.cpp @@ -37,12 +37,12 @@ public: // ----------------------------------------------------------------------------- Logger::Logger (Level level) : Object(*new LoggerPrivate) { - L_D(Logger); + L_D(); d->level = level; } Logger::~Logger () { - L_D(Logger); + L_D(); const string str = d->os.str(); @@ -68,7 +68,7 @@ Logger::~Logger () { } ostringstream &Logger::getOutput () { - L_D(Logger); + L_D(); return d->os; } diff --git a/src/object/property-container.cpp b/src/object/property-container.cpp index b0c472588..5b4bc5db9 100644 --- a/src/object/property-container.cpp +++ b/src/object/property-container.cpp @@ -49,18 +49,18 @@ PropertyContainer &PropertyContainer::operator= (const PropertyContainer &) { } Variant PropertyContainer::getProperty (const string &name) const { - L_D(const PropertyContainer); + L_D(); auto it = d->properties.find(name); return it == d->properties.cend() ? Variant() : it->second; } void PropertyContainer::setProperty (const string &name, const Variant &value) { - L_D(PropertyContainer); + L_D(); d->properties[name] = value; } void PropertyContainer::setProperty (const string &name, Variant &&value) { - L_D(PropertyContainer); + L_D(); d->properties[name] = move(value); } diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index 2d5cf1a77..7ed8ac7d0 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -83,7 +83,7 @@ Variant::Variant () { } Variant::Variant (Type type) : Variant() { - L_D(Variant); + L_D(); d->setType(type); } @@ -92,7 +92,7 @@ Variant::Variant (const Variant &src) { L_ASSERT(!mPrivate); mPrivate = new VariantPrivate(); - L_D(Variant); + L_D(); int type = src.getPrivate()->getType(); d->setType(type); @@ -112,72 +112,72 @@ Variant::Variant (Variant &&src) { } Variant::Variant (int value) : Variant(Int) { - L_D(Variant); + L_D(); d->value.i = value; } Variant::Variant (unsigned int value) : Variant(UnsignedInt) { - L_D(Variant); + L_D(); d->value.ui = value; } Variant::Variant (short value) : Variant(Short) { - L_D(Variant); + L_D(); d->value.s = value; } Variant::Variant (unsigned short value) : Variant(UnsignedShort) { - L_D(Variant); + L_D(); d->value.us = value; } Variant::Variant (long value) : Variant(Long) { - L_D(Variant); + L_D(); d->value.l = value; } Variant::Variant (unsigned long value) : Variant(UnsignedLong) { - L_D(Variant); + L_D(); d->value.ul = value; } Variant::Variant (long long value) : Variant(LongLong) { - L_D(Variant); + L_D(); d->value.ll = value; } Variant::Variant (unsigned long long value) : Variant(UnsignedLongLong) { - L_D(Variant); + L_D(); d->value.ull = value; } Variant::Variant (char value) : Variant(Char) { - L_D(Variant); + L_D(); d->value.c = value; } Variant::Variant (bool value) : Variant(Bool) { - L_D(Variant); + L_D(); d->value.b = value; } Variant::Variant (double value) : Variant(Double) { - L_D(Variant); + L_D(); d->value.d = value; } Variant::Variant (float value) : Variant(Float) { - L_D(Variant); + L_D(); d->value.f = value; } Variant::Variant (const string &value) : Variant(String) { - L_D(Variant); + L_D(); *d->value.str = value; } Variant::~Variant () { - L_D(Variant); + L_D(); // Note: Private data can be stolen by copy operator (r-value). // It can be null, but it useless to test it. @@ -200,7 +200,7 @@ bool Variant::operator<= (const Variant &variant) const { } Variant &Variant::operator= (const Variant &variant) { - L_D(Variant); + L_D(); if (this != &variant) { // Update type. @@ -245,12 +245,12 @@ bool Variant::operator>= (const Variant &variant) const { } bool Variant::isValid () const { - L_D(const Variant); + L_D(); return d->getType() != Invalid; } void Variant::clear () { - L_D(Variant); + L_D(); d->setType(Invalid); } @@ -564,7 +564,7 @@ static inline void *getValueAsGeneric (const VariantPrivate &p, bool *soFarSoGoo void Variant::getValue (int type, void *value, bool *soFarSoGood) const { L_ASSERT(type > Invalid && type != MaxDefaultTypes); - L_D(const Variant); + L_D(); *soFarSoGood = true; From 6ca6fb6d89cd3cd1e921255389d5e558c078d458 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 27 Sep 2017 17:18:54 +0200 Subject: [PATCH 0207/2215] Move some code from ChatMessage to ChatMessagePrivate --- src/c-wrapper/api/c-chat-message.cpp | 40 +-- src/chat/chat-message-p.h | 42 +++ src/chat/chat-message.cpp | 417 +++++++++++++-------------- src/chat/chat-message.h | 34 --- src/chat/chat-room.h | 2 + 5 files changed, 266 insertions(+), 269 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index fb0237698..f4cb92dbc 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -106,7 +106,7 @@ time_t linphone_chat_message_get_time(const LinphoneChatMessage *msg) { } void linphone_chat_message_set_time(LinphoneChatMessage *msg, time_t time) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setTime(time); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setTime(time); } bool_t linphone_chat_message_is_secured(LinphoneChatMessage *msg) { @@ -134,7 +134,7 @@ void linphone_chat_message_set_outgoing(LinphoneChatMessage *msg) { } unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getStorageId(); + return L_GET_PRIVATE_FROM_C_OBJECT(msg)->getStorageId(); } LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage *msg) { @@ -154,7 +154,7 @@ void linphone_chat_message_set_message_id(LinphoneChatMessage *msg, char *id) { } void linphone_chat_message_set_storage_id(LinphoneChatMessage *msg, unsigned int id) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setStorageId(id); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setStorageId(id); } bool_t linphone_chat_message_is_read(LinphoneChatMessage *msg) { @@ -208,40 +208,40 @@ void linphone_chat_message_set_to_be_stored(LinphoneChatMessage *msg, bool_t to_ } belle_http_request_t * linphone_chat_message_get_http_request(LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getHttpRequest(); + return L_GET_PRIVATE_FROM_C_OBJECT(msg)->getHttpRequest(); } void linphone_chat_message_set_http_request(LinphoneChatMessage *msg, belle_http_request_t *request) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setHttpRequest(request); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setHttpRequest(request); } SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getSalOp(); + return L_GET_PRIVATE_FROM_C_OBJECT(msg)->getSalOp(); } void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, SalOp *op) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setSalOp(op); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setSalOp(op); } SalCustomHeader * linphone_chat_message_get_sal_custom_headers(const LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getSalCustomHeaders(); + return L_GET_PRIVATE_FROM_C_OBJECT(msg)->getSalCustomHeaders(); } void linphone_chat_message_set_sal_custom_headers(LinphoneChatMessage *msg, SalCustomHeader *header) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setSalCustomHeaders(header); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setSalCustomHeaders(header); } void linphone_chat_message_add_custom_header(LinphoneChatMessage *msg, const char *header_name, const char *header_value) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->addSalCustomHeader(header_name, header_value); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->addSalCustomHeader(header_name, header_value); } void linphone_chat_message_remove_custom_header(LinphoneChatMessage *msg, const char *header_name) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->removeSalCustomHeader(header_name); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->removeSalCustomHeader(header_name); } const char *linphone_chat_message_get_custom_header(LinphoneChatMessage *msg, const char *header_name) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getSalCustomHeaderValue(header_name).c_str(); + return L_GET_PRIVATE_FROM_C_OBJECT(msg)->getSalCustomHeaderValue(header_name).c_str(); } const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg) { @@ -276,12 +276,12 @@ void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMe L_GET_CPP_PTR_FROM_C_OBJECT(msg)->updateState((LinphonePrivate::ChatMessage::State) new_state); } void linphone_chat_message_send_imdn(LinphoneChatMessage *msg, ImdnType imdn_type, LinphoneReason reason) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->sendImdn(imdn_type, reason); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->sendImdn(imdn_type, reason); } void linphone_chat_message_deactivate(LinphoneChatMessage *msg){ L_GET_CPP_PTR_FROM_C_OBJECT(msg)->cancelFileTransfer(); - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setChatRoom(nullptr); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setChatRoom(nullptr); } void linphone_chat_message_send_delivery_notification(LinphoneChatMessage *msg, LinphoneReason reason) { @@ -321,28 +321,28 @@ void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChat // ============================================================================= const char * linphone_chat_message_get_content_type(const LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getContentType().c_str(); + return L_GET_PRIVATE_FROM_C_OBJECT(msg)->getContentType().c_str(); } void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char *content_type) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setContentType(content_type); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setContentType(content_type); } const char *linphone_chat_message_get_text(const LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getText().c_str(); + return L_GET_PRIVATE_FROM_C_OBJECT(msg)->getText().c_str(); } int linphone_chat_message_set_text(LinphoneChatMessage *msg, const char* text) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setText(text); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setText(text); return 0; } LinphoneContent *linphone_chat_message_get_file_transfer_information(LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFileTransferInformation(); + return L_GET_PRIVATE_FROM_C_OBJECT(msg)->getFileTransferInformation(); } void linphone_chat_message_set_file_transfer_information(LinphoneChatMessage *msg, LinphoneContent *content) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFileTransferInformation(content); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setFileTransferInformation(content); } // ============================================================================= diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 754701f0e..7479d2938 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -35,6 +35,45 @@ public: ChatMessagePrivate (const std::shared_ptr &room); virtual ~ChatMessagePrivate (); + void setChatRoom (std::shared_ptr chatRoom); + + // ----------------------------------------------------------------------------- + + void setTime(time_t time); + + unsigned int getStorageId() const; + void setStorageId(unsigned int id); + + belle_http_request_t *getHttpRequest() const; + void setHttpRequest(belle_http_request_t *request); + + SalOp *getSalOp() const; + void setSalOp(SalOp *op); + + SalCustomHeader *getSalCustomHeaders() const; + void setSalCustomHeaders(SalCustomHeader *headers); + + void addSalCustomHeader(std::string name, std::string value); + void removeSalCustomHeader(std::string name); + std::string getSalCustomHeaderValue(std::string name); + + // ----------------------------------------------------------------------------- + // Methods only used for C wrapper + // ----------------------------------------------------------------------------- + + std::string getContentType() const; + void setContentType(std::string contentType); + + std::string getText() const; + void setText(std::string text); + + LinphoneContent * getFileTransferInformation() const; + void setFileTransferInformation(LinphoneContent *content); + + // ----------------------------------------------------------------------------- + + void sendImdn(ImdnType imdnType, LinphoneReason reason); + private: std::shared_ptr chatRoom; std::string externalBodyUrl; @@ -62,6 +101,9 @@ private: std::string cContentType; std::string cText; LinphoneContent *cFileTransferInformation; + + std::string createImdnXml(ImdnType imdnType, LinphoneReason reason); + L_DECLARE_PUBLIC(ChatMessage); }; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 6f8c01563..8927fcf51 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -29,7 +29,7 @@ #include "modifier/multipart-chat-message-modifier.h" #include "modifier/cpim-chat-message-modifier.h" -#include "chat-room.h" +#include "chat-room-p.h" // ============================================================================= @@ -48,6 +48,196 @@ ChatMessagePrivate::~ChatMessagePrivate () {} // ----------------------------------------------------------------------------- +void ChatMessagePrivate::setChatRoom (shared_ptr cr) { + chatRoom = cr; +} + +void ChatMessagePrivate::setTime(time_t t) { + time = t; +} + +unsigned int ChatMessagePrivate::getStorageId() const { + return storageId; +} + +void ChatMessagePrivate::setStorageId(unsigned int id) { + storageId = id; +} + +belle_http_request_t *ChatMessagePrivate::getHttpRequest() const { + return httpRequest; +} + +void ChatMessagePrivate::setHttpRequest(belle_http_request_t *request) { + httpRequest = request; +} + +SalOp *ChatMessagePrivate::getSalOp() const { + return salOp; +} + +void ChatMessagePrivate::setSalOp(SalOp *op) { + salOp = op; +} + +SalCustomHeader *ChatMessagePrivate::getSalCustomHeaders() const { + return salCustomHeaders; +} + +void ChatMessagePrivate::setSalCustomHeaders(SalCustomHeader *headers) { + salCustomHeaders = headers; +} + +void ChatMessagePrivate::addSalCustomHeader(string name, string value) { + salCustomHeaders = sal_custom_header_append(salCustomHeaders, name.c_str(), value.c_str()); +} + +void ChatMessagePrivate::removeSalCustomHeader(string name) { + salCustomHeaders = sal_custom_header_remove(salCustomHeaders, name.c_str()); +} + +string ChatMessagePrivate::getSalCustomHeaderValue(string name) { + return sal_custom_header_find(salCustomHeaders, name.c_str()); +} + +// ----------------------------------------------------------------------------- + +string ChatMessagePrivate::getContentType() const { + return cContentType; +} + +void ChatMessagePrivate::setContentType(string contentType) { + cContentType = contentType; +} + +string ChatMessagePrivate::getText() const { + return cText; +} + +void ChatMessagePrivate::setText(string text) { + cText = text; +} + +LinphoneContent * ChatMessagePrivate::getFileTransferInformation() const { + return cFileTransferInformation; +} + +void ChatMessagePrivate::setFileTransferInformation(LinphoneContent *content) { + cFileTransferInformation = content; +} + +// ----------------------------------------------------------------------------- + +string ChatMessagePrivate::createImdnXml(ImdnType imdnType, LinphoneReason reason) { + /*xmlBufferPtr buf; + xmlTextWriterPtr writer; + int err; + char *content = NULL; + char *datetime = NULL; + const char *message_id; + + // Check that the chat message has a message id + message_id = linphone_chat_message_get_message_id(cm); + if (message_id == NULL) return NULL; + + buf = xmlBufferCreate(); + if (buf == NULL) { + ms_error("Error creating the XML buffer"); + return content; + } + writer = xmlNewTextWriterMemory(buf, 0); + if (writer == NULL) { + ms_error("Error creating the XML writer"); + return content; + } + + datetime = linphone_timestamp_to_rfc3339_string(linphone_chat_message_get_time(cm)); + err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); + if (err >= 0) { + err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"imdn", + (const xmlChar *)"urn:ietf:params:xml:ns:imdn"); + } + if ((err >= 0) && (reason != LinphoneReasonNone)) { + err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"linphoneimdn", NULL, (const xmlChar *)"http://www.linphone.org/xsds/imdn.xsd"); + } + if (err >= 0) { + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"message-id", (const xmlChar *)message_id); + } + if (err >= 0) { + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"datetime", (const xmlChar *)datetime); + } + if (err >= 0) { + if (imdn_type == ImdnTypeDelivery) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivery-notification"); + } else { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"display-notification"); + } + } + if (err >= 0) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"status"); + } + if (err >= 0) { + if (reason == LinphoneReasonNone) { + if (imdn_type == ImdnTypeDelivery) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivered"); + } else { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"displayed"); + } + } else { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"error"); + } + } + if (err >= 0) { + // Close the "delivered", "displayed" or "error" element. + err = xmlTextWriterEndElement(writer); + } + if ((err >= 0) && (reason != LinphoneReasonNone)) { + err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"linphoneimdn", (const xmlChar *)"reason", NULL); + if (err >= 0) { + char codestr[16]; + snprintf(codestr, 16, "%d", linphone_reason_to_error_code(reason)); + err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"code", (const xmlChar *)codestr); + } + if (err >= 0) { + err = xmlTextWriterWriteString(writer, (const xmlChar *)linphone_reason_to_string(reason)); + } + if (err >= 0) { + err = xmlTextWriterEndElement(writer); + } + } + if (err >= 0) { + // Close the "status" element. + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + // Close the "delivery-notification" or "display-notification" element. + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + // Close the "imdn" element. + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + err = xmlTextWriterEndDocument(writer); + } + if (err > 0) { + // xmlTextWriterEndDocument returns the size of the content. + content = ms_strdup((char *)buf->content); + } + xmlFreeTextWriter(writer); + xmlBufferFree(buf); + ms_free(datetime); + return content;*/ + return ""; +} + +void ChatMessagePrivate::sendImdn(ImdnType imdnType, LinphoneReason reason) { + string content = createImdnXml(imdnType, reason); + chatRoom->getPrivate()->sendImdn(content, reason); +} + +// ----------------------------------------------------------------------------- + // ============================================================================= // ChatMessage // ============================================================================= @@ -65,11 +255,6 @@ shared_ptr ChatMessage::getChatRoom () const { return d->chatRoom; } -void ChatMessage::setChatRoom (shared_ptr chatRoom) { - L_D(); - d->chatRoom = chatRoom; -} - // ----------------------------------------------------------------------------- string ChatMessage::getExternalBodyUrl() const { @@ -86,10 +271,6 @@ time_t ChatMessage::getTime () const { L_D(); return d->time; } -void ChatMessage::setTime(time_t time) { - L_D(); - d->time = time; -} bool ChatMessage::isSecured () const { L_D(); @@ -223,90 +404,9 @@ void ChatMessage::setIsToBeStored(bool store) { // ----------------------------------------------------------------------------- -string ChatMessage::getContentType() const { - L_D(); - return d->cContentType; -} -void ChatMessage::setContentType(string contentType) { - L_D(); - d->cContentType = contentType; -} -string ChatMessage::getText() const { - L_D(); - return d->cText; -} -void ChatMessage::setText(string text) { - L_D(); - d->cText = text; -} - -LinphoneContent * ChatMessage::getFileTransferInformation() const { - L_D(); - return d->cFileTransferInformation; -} - -void ChatMessage::setFileTransferInformation(LinphoneContent *content) { - L_D(); - d->cFileTransferInformation = content; -} - -unsigned int ChatMessage::getStorageId() const { - L_D(); - return d->storageId; -} - -void ChatMessage::setStorageId(unsigned int id) { - L_D(); - d->storageId = id; -} - -belle_http_request_t *ChatMessage::getHttpRequest() const { - L_D(); - return d->httpRequest; -} - -void ChatMessage::setHttpRequest(belle_http_request_t *request) { - L_D(); - d->httpRequest = request; -} - -SalOp *ChatMessage::getSalOp() const { - L_D(); - return d->salOp; -} - -void ChatMessage::setSalOp(SalOp *op) { - L_D(); - d->salOp = op; -} - -SalCustomHeader *ChatMessage::getSalCustomHeaders() const { - L_D(); - return d->salCustomHeaders; -} - -void ChatMessage::setSalCustomHeaders(SalCustomHeader *headers) { - L_D(); - d->salCustomHeaders = headers; -} - -void ChatMessage::addSalCustomHeader(string name, string value) { - L_D(); - d->salCustomHeaders = sal_custom_header_append(d->salCustomHeaders, name.c_str(), value.c_str()); -} - -void ChatMessage::removeSalCustomHeader(string name) { - L_D(); - d->salCustomHeaders = sal_custom_header_remove(d->salCustomHeaders, name.c_str()); -} - -string ChatMessage::getSalCustomHeaderValue(string name) { - L_D(); - return sal_custom_header_find(d->salCustomHeaders, name.c_str()); -} const LinphoneErrorInfo * ChatMessage::getErrorInfo() const { L_D(); @@ -399,18 +499,14 @@ void ChatMessage::send () { } void ChatMessage::reSend() { - //TODO - /*LinphoneChatMessageState state = linphone_chat_message_get_state(msg); - LinphoneChatRoom *cr; + L_D(); - if (state != LinphoneChatMessageStateNotDelivered) { - ms_warning("Cannot resend chat message in state %s", linphone_chat_message_state_to_string(state)); + if (d->state != NotDelivered) { + // ms_warning("Cannot resend chat message in state %s", linphone_chat_message_state_to_string(state)); return; } - cr = linphone_chat_message_get_chat_room(msg); - if (ref_msg) linphone_chat_message_ref(msg); - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(msg);*/ + d->chatRoom->sendMessage(L_GET_C_BACK_PTR(this)); } /*static void linphone_chat_message_process_io_error_upload(void *data, const belle_sip_io_error_event_t *event) { @@ -453,125 +549,16 @@ static void linphone_chat_process_response_from_get_file(void *data, const belle } }*/ -/*static char *linphone_chat_message_create_imdn_xml(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason) { - xmlBufferPtr buf; - xmlTextWriterPtr writer; - int err; - char *content = NULL; - char *datetime = NULL; - const char *message_id; - - // Check that the chat message has a message id - message_id = linphone_chat_message_get_message_id(cm); - if (message_id == NULL) return NULL; - - buf = xmlBufferCreate(); - if (buf == NULL) { - ms_error("Error creating the XML buffer"); - return content; - } - writer = xmlNewTextWriterMemory(buf, 0); - if (writer == NULL) { - ms_error("Error creating the XML writer"); - return content; - } - - datetime = linphone_timestamp_to_rfc3339_string(linphone_chat_message_get_time(cm)); - err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); - if (err >= 0) { - err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"imdn", - (const xmlChar *)"urn:ietf:params:xml:ns:imdn"); - } - if ((err >= 0) && (reason != LinphoneReasonNone)) { - err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"linphoneimdn", NULL, (const xmlChar *)"http://www.linphone.org/xsds/imdn.xsd"); - } - if (err >= 0) { - err = xmlTextWriterWriteElement(writer, (const xmlChar *)"message-id", (const xmlChar *)message_id); - } - if (err >= 0) { - err = xmlTextWriterWriteElement(writer, (const xmlChar *)"datetime", (const xmlChar *)datetime); - } - if (err >= 0) { - if (imdn_type == ImdnTypeDelivery) { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivery-notification"); - } else { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"display-notification"); - } - } - if (err >= 0) { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"status"); - } - if (err >= 0) { - if (reason == LinphoneReasonNone) { - if (imdn_type == ImdnTypeDelivery) { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivered"); - } else { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"displayed"); - } - } else { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"error"); - } - } - if (err >= 0) { - // Close the "delivered", "displayed" or "error" element. - err = xmlTextWriterEndElement(writer); - } - if ((err >= 0) && (reason != LinphoneReasonNone)) { - err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"linphoneimdn", (const xmlChar *)"reason", NULL); - if (err >= 0) { - char codestr[16]; - snprintf(codestr, 16, "%d", linphone_reason_to_error_code(reason)); - err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"code", (const xmlChar *)codestr); - } - if (err >= 0) { - err = xmlTextWriterWriteString(writer, (const xmlChar *)linphone_reason_to_string(reason)); - } - if (err >= 0) { - err = xmlTextWriterEndElement(writer); - } - } - if (err >= 0) { - // Close the "status" element. - err = xmlTextWriterEndElement(writer); - } - if (err >= 0) { - // Close the "delivery-notification" or "display-notification" element. - err = xmlTextWriterEndElement(writer); - } - if (err >= 0) { - // Close the "imdn" element. - err = xmlTextWriterEndElement(writer); - } - if (err >= 0) { - err = xmlTextWriterEndDocument(writer); - } - if (err > 0) { - // xmlTextWriterEndDocument returns the size of the content. - content = ms_strdup((char *)buf->content); - } - xmlFreeTextWriter(writer); - xmlBufferFree(buf); - ms_free(datetime); - return content; -}*/ - -void ChatMessage::sendImdn(ImdnType imdnType, LinphoneReason reason) { - //TODO - /*char *content = linphone_chat_message_create_imdn_xml(cm, imdn_type, reason); - if (content) { - L_GET_PRIVATE_FROM_C_OBJECT(linphone_chat_message_get_chat_room(cm))->sendImdn(content, reason); - ms_free(content); - }*/ -} - void ChatMessage::sendDeliveryNotification(LinphoneReason reason) { - //TODO + L_D(); + LinphoneCore *lc = d->chatRoom->getCore(); + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); + if (linphone_im_notif_policy_get_send_imdn_delivered(policy)) { + d->sendImdn(ImdnTypeDelivery, reason); + } /*LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(cm); LinphoneCore *lc = linphone_chat_room_get_core(cr); - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); - if (linphone_im_notif_policy_get_send_imdn_delivered(policy) == TRUE) { - linphone_chat_message_send_imdn(cm, ImdnTypeDelivery, reason); - }*/ + */ } void ChatMessage::sendDisplayNotification() { diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index 1762ca5bb..5b0485281 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -72,7 +72,6 @@ public: void updateState(State state); void send(); void reSend(); - void sendImdn(ImdnType imdnType, LinphoneReason reason); void sendDeliveryNotification(LinphoneReason reason); void sendDisplayNotification(); int uploadFile(); @@ -131,39 +130,6 @@ public: std::string getCustomHeaderValue (const std::string &headerName) const; void addCustomHeader (const std::string &headerName, const std::string &headerValue); void removeCustomHeader (const std::string &headerName); - - // ----------------------------------------------------------------------------- - // Deprecated methods, only used for C wrapper - // ----------------------------------------------------------------------------- - - void setChatRoom (std::shared_ptr chatRoom); - - std::string getContentType() const; - void setContentType(std::string contentType); - - std::string getText() const; - void setText(std::string text); - - LinphoneContent * getFileTransferInformation() const; - void setFileTransferInformation(LinphoneContent *content); - - unsigned int getStorageId() const; - void setStorageId(unsigned int id); - - void setTime(time_t time); - - belle_http_request_t *getHttpRequest() const; - void setHttpRequest(belle_http_request_t *request); - - SalOp *getSalOp() const; - void setSalOp(SalOp *op); - - SalCustomHeader *getSalCustomHeaders() const; - void setSalCustomHeaders(SalCustomHeader *headers); - - void addSalCustomHeader(std::string name, std::string value); - void removeSalCustomHeader(std::string name); - std::string getSalCustomHeaderValue(std::string name); protected: explicit ChatMessage (ChatMessagePrivate &p); diff --git a/src/chat/chat-room.h b/src/chat/chat-room.h index c71fc7880..d0e156635 100644 --- a/src/chat/chat-room.h +++ b/src/chat/chat-room.h @@ -37,6 +37,8 @@ LINPHONE_BEGIN_NAMESPACE class ChatRoomPrivate; class ChatRoom : public Object, public ConferenceInterface { + friend class ChatMessagePrivate; + public: L_DECLARE_ENUM(State, L_ENUM_VALUES_CHAT_ROOM_STATE); From 41233811c431162d097de62ac0fb6feea8cb59ea Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 27 Sep 2017 17:47:45 +0200 Subject: [PATCH 0208/2215] fix(windaube): magic-macros is now compatible with windows --- include/linphone/utils/magic-macros.h | 11 ++++++----- src/chat/basic-chat-room.h | 2 +- src/chat/chat-room.h | 9 ++++----- src/chat/client-group-chat-room.h | 2 +- src/chat/real-time-text-chat-room.h | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/linphone/utils/magic-macros.h b/include/linphone/utils/magic-macros.h index 439dcdf32..7a30256b5 100644 --- a/include/linphone/utils/magic-macros.h +++ b/include/linphone/utils/magic-macros.h @@ -36,13 +36,13 @@ LINPHONE_BEGIN_NAMESPACE A11, A12, A13, A14, A15, A16, N, ... \ ) N -#define L_GET_N_ARGS_HELPER(...) L_ARG_N(__VA_ARGS__) +#define L_EXPAND(X) X -#define L_GET_N_ARGS(...) L_GET_N_ARGS_HELPER( \ +#define L_GET_N_ARGS(...) L_EXPAND(L_ARG_N( \ __VA_ARGS__, \ 16, 15, 14, 13, 12, 11, 10, \ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 \ -) +)) // Get argument numbers - 1 from variadic. #define L_GET_N_ARGS_SUB(X, ...) L_GET_N_ARGS(__VA_ARGS__) @@ -83,8 +83,9 @@ LINPHONE_BEGIN_NAMESPACE #define L_GET_HEAP_15(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, ...) A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15 #define L_GET_HEAP_16(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, ...) A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16 -#define L_GET_HEAP(...) \ - L_CONCAT(L_GET_HEAP_, L_GET_N_ARGS_SUB(__VA_ARGS__)) (__VA_ARGS__) +#define L_GET_HEAP(...) L_EXPAND( \ + L_CONCAT(L_GET_HEAP_, L_GET_N_ARGS_SUB(__VA_ARGS__)) (__VA_ARGS__) \ +) // Call a macro on args. #define L_CALL(MACRO, ARGS) MACRO ARGS diff --git a/src/chat/basic-chat-room.h b/src/chat/basic-chat-room.h index 3bc723387..d7aae693a 100644 --- a/src/chat/basic-chat-room.h +++ b/src/chat/basic-chat-room.h @@ -27,7 +27,7 @@ LINPHONE_BEGIN_NAMESPACE class BasicChatRoomPrivate; -class BasicChatRoom : public ChatRoom { +class LINPHONE_PUBLIC BasicChatRoom : public ChatRoom { public: BasicChatRoom (LinphoneCore *core, const Address &peerAddress); virtual ~BasicChatRoom () = default; diff --git a/src/chat/chat-room.h b/src/chat/chat-room.h index d0e156635..b1c23c7ab 100644 --- a/src/chat/chat-room.h +++ b/src/chat/chat-room.h @@ -19,11 +19,11 @@ #ifndef _CHAT_ROOM_H_ #define _CHAT_ROOM_H_ +#include + // From coreapi #include "private.h" -#include - #include "address/address.h" #include "object/object.h" #include "conference/conference-interface.h" @@ -36,9 +36,9 @@ LINPHONE_BEGIN_NAMESPACE class ChatRoomPrivate; -class ChatRoom : public Object, public ConferenceInterface { +class LINPHONE_PUBLIC ChatRoom : public Object, public ConferenceInterface { friend class ChatMessagePrivate; - + public: L_DECLARE_ENUM(State, L_ENUM_VALUES_CHAT_ROOM_STATE); @@ -76,4 +76,3 @@ private: LINPHONE_END_NAMESPACE #endif // ifndef _CHAT_ROOM_H_ - diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index c795991d5..d5f1c5b1a 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -34,7 +34,7 @@ LINPHONE_BEGIN_NAMESPACE class ClientGroupChatRoomPrivate; -class ClientGroupChatRoom : public ChatRoom, public RemoteConference { +class LINPHONE_PUBLIC ClientGroupChatRoom : public ChatRoom, public RemoteConference { public: ClientGroupChatRoom (LinphoneCore *core, const Address &me, const std::string &subject); virtual ~ClientGroupChatRoom () = default; diff --git a/src/chat/real-time-text-chat-room.h b/src/chat/real-time-text-chat-room.h index 117f36dd5..2f3e3f40d 100644 --- a/src/chat/real-time-text-chat-room.h +++ b/src/chat/real-time-text-chat-room.h @@ -32,7 +32,7 @@ LINPHONE_BEGIN_NAMESPACE class RealTimeTextChatRoomPrivate; -class RealTimeTextChatRoom : public ChatRoom { +class LINPHONE_PUBLIC RealTimeTextChatRoom : public ChatRoom { public: RealTimeTextChatRoom (LinphoneCore *core, const Address &peerAddress); virtual ~RealTimeTextChatRoom () = default; From 0e387676be3481e7a97c3874d5c3fcbdd3b05549 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 28 Sep 2017 09:56:22 +0200 Subject: [PATCH 0209/2215] Moved some functions from ChatMessage to it's private part --- src/c-wrapper/api/c-chat-message.cpp | 6 +-- src/chat/chat-message-p.h | 4 ++ src/chat/chat-message.cpp | 70 +++++++++++++--------------- src/chat/chat-message.h | 2 - 4 files changed, 40 insertions(+), 42 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index f4cb92dbc..0695bb0f5 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -126,11 +126,11 @@ LinphoneChatMessageDir linphone_chat_message_get_direction(const LinphoneChatMes } void linphone_chat_message_set_incoming(LinphoneChatMessage *msg) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setDirection(LinphonePrivate::ChatMessage::Direction::Incoming); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setDirection(LinphonePrivate::ChatMessage::Direction::Incoming); } void linphone_chat_message_set_outgoing(LinphoneChatMessage *msg) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setDirection(LinphonePrivate::ChatMessage::Direction::Outgoing); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setDirection(LinphonePrivate::ChatMessage::Direction::Outgoing); } unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage *msg) { @@ -142,7 +142,7 @@ LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessa } void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessageState state) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setState((LinphonePrivate::ChatMessage::State)state); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setState((LinphonePrivate::ChatMessage::State)state); } const char* linphone_chat_message_get_message_id(const LinphoneChatMessage *msg) { diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 7479d2938..87892c120 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -38,6 +38,10 @@ public: void setChatRoom (std::shared_ptr chatRoom); // ----------------------------------------------------------------------------- + + void setDirection (ChatMessage::Direction dir); + + void setState(ChatMessage::State state); void setTime(time_t time); diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 8927fcf51..e20a29f19 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -52,10 +52,38 @@ void ChatMessagePrivate::setChatRoom (shared_ptr cr) { chatRoom = cr; } +void ChatMessagePrivate::setDirection (ChatMessage::Direction dir) { + direction = dir; +} + void ChatMessagePrivate::setTime(time_t t) { time = t; } +void ChatMessagePrivate::setState(ChatMessage::State s) { + L_Q(); + + if (s != state && chatRoom) { + if (((state == ChatMessage::State::Displayed) || (state == ChatMessage::State::DeliveredToUser)) + && ((s == ChatMessage::State::DeliveredToUser) || (s == ChatMessage::State::Delivered) || (s == ChatMessage::State::NotDelivered))) { + return; + } + /* TODO + ms_message("Chat message %p: moving from state %s to %s", msg, linphone_chat_message_state_to_string(msg->state), linphone_chat_message_state_to_string(state)); + */ + state = s; + + LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); + if (linphone_chat_message_get_message_state_changed_cb(msg)) { + linphone_chat_message_get_message_state_changed_cb(msg)(msg, (LinphoneChatMessageState)state, linphone_chat_message_get_message_state_changed_cb_user_data(msg)); + } + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); + if (linphone_chat_message_cbs_get_msg_state_changed(cbs)) { + linphone_chat_message_cbs_get_msg_state_changed(cbs)(msg, linphone_chat_message_get_state(msg)); + } + } +} + unsigned int ChatMessagePrivate::getStorageId() const { return storageId; } @@ -287,11 +315,6 @@ ChatMessage::Direction ChatMessage::getDirection () const { return d->direction; } -void ChatMessage::setDirection (ChatMessage::Direction dir) { - L_D(); - d->direction = dir; -} - bool ChatMessage::isOutgoing () const { L_D(); return d->direction == Outgoing; @@ -307,29 +330,6 @@ ChatMessage::State ChatMessage::getState() const { return d->state; } -void ChatMessage::setState(State state) { - L_D(); - if (state != d->state && d->chatRoom) { - if (((d->state == Displayed) || (d->state == DeliveredToUser)) - && ((state == DeliveredToUser) || (state == Delivered) || (state == NotDelivered))) { - return; - } - /* TODO - ms_message("Chat message %p: moving from state %s to %s", msg, linphone_chat_message_state_to_string(msg->state), linphone_chat_message_state_to_string(state)); - */ - d->state = state; - - LinphoneChatMessage *msg = L_GET_C_BACK_PTR(this); - if (linphone_chat_message_get_message_state_changed_cb(msg)) { - linphone_chat_message_get_message_state_changed_cb(msg)(msg, (LinphoneChatMessageState)state, linphone_chat_message_get_message_state_changed_cb_user_data(msg)); - } - LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); - if (linphone_chat_message_cbs_get_msg_state_changed(cbs)) { - linphone_chat_message_cbs_get_msg_state_changed(cbs)(msg, linphone_chat_message_get_state(msg)); - } - } -} - string ChatMessage::getId () const { L_D(); return d->id; @@ -556,19 +556,15 @@ void ChatMessage::sendDeliveryNotification(LinphoneReason reason) { if (linphone_im_notif_policy_get_send_imdn_delivered(policy)) { d->sendImdn(ImdnTypeDelivery, reason); } - /*LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(cm); - LinphoneCore *lc = linphone_chat_room_get_core(cr); - */ } void ChatMessage::sendDisplayNotification() { - //TODO - /*LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(cm); - LinphoneCore *lc = linphone_chat_room_get_core(cr); + L_D(); + LinphoneCore *lc = d->chatRoom->getCore(); LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); - if (linphone_im_notif_policy_get_send_imdn_displayed(policy) == TRUE) { - linphone_chat_message_send_imdn(cm, ImdnTypeDisplay, LinphoneReasonNone); - }*/ + if (linphone_im_notif_policy_get_send_imdn_displayed(policy)) { + d->sendImdn(ImdnTypeDisplay, LinphoneReasonNone); + } } /* diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index 5b0485281..bf0ec5a29 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -84,7 +84,6 @@ public: // ----------------------------------------------------------------------------- Direction getDirection () const; - void setDirection (Direction dir); bool isOutgoing () const; bool isIncoming () const; @@ -97,7 +96,6 @@ public: void setIsSecured(bool isSecured); State getState() const; - void setState(State state); std::string getId () const; void setId (std::string); From 7d10862c7f1c47b2d7cf9c26a9cd279ee2b10f6f Mon Sep 17 00:00:00 2001 From: "Ronan Abhamon (Windaube)" Date: Thu, 28 Sep 2017 12:13:10 +0200 Subject: [PATCH 0210/2215] feat(windaube): fix L_GET_CPP_PTR_FROM_C and L_GET_PRIVATE with L_EXPAND for Windows --- src/c-wrapper/internal/c-tools.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 5a71264ec..7692cfbea 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -533,7 +533,7 @@ LINPHONE_END_NAMESPACE >(C_OBJECT) #define L_GET_CPP_PTR_FROM_C_OBJECT_MACRO_CHOOSER(...) \ - L_GET_ARG_3(__VA_ARGS__, L_GET_CPP_PTR_FROM_C_OBJECT_2_ARGS, L_GET_CPP_PTR_FROM_C_OBJECT_1_ARGS) + L_EXPAND(L_GET_ARG_3(__VA_ARGS__, L_GET_CPP_PTR_FROM_C_OBJECT_2_ARGS, L_GET_CPP_PTR_FROM_C_OBJECT_1_ARGS)) #define L_GET_CPP_PTR_FROM_C_OBJECT(...) \ L_GET_CPP_PTR_FROM_C_OBJECT_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__) @@ -548,12 +548,12 @@ LINPHONE_END_NAMESPACE // Get the private data of a shared or simple cpp-ptr of a wrapped C object. #define L_GET_PRIVATE_FROM_C_OBJECT_1_ARGS(C_OBJECT) \ - L_GET_PRIVATE(LINPHONE_NAMESPACE::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT))) + L_GET_PRIVATE(LINPHONE_NAMESPACE::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT_1_ARGS(C_OBJECT))) #define L_GET_PRIVATE_FROM_C_OBJECT_2_ARGS(C_OBJECT, CPP_TYPE) \ - L_GET_PRIVATE(LINPHONE_NAMESPACE::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT, CPP_TYPE))) + L_GET_PRIVATE(LINPHONE_NAMESPACE::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT_2_ARGS(C_OBJECT, CPP_TYPE))) #define L_GET_PRIVATE_FROM_C_OBJECT_MACRO_CHOOSER(...) \ - L_GET_ARG_3(__VA_ARGS__, L_GET_PRIVATE_FROM_C_OBJECT_2_ARGS, L_GET_PRIVATE_FROM_C_OBJECT_1_ARGS) + L_EXPAND(L_GET_ARG_3(__VA_ARGS__, L_GET_PRIVATE_FROM_C_OBJECT_2_ARGS, L_GET_PRIVATE_FROM_C_OBJECT_1_ARGS)) #define L_GET_PRIVATE_FROM_C_OBJECT(...) \ L_GET_PRIVATE_FROM_C_OBJECT_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__) From 0cd07d1f86b7d547282d60e0af82c13cdd04fce7 Mon Sep 17 00:00:00 2001 From: "Ronan Abhamon (Windaube)" Date: Thu, 28 Sep 2017 12:27:07 +0200 Subject: [PATCH 0211/2215] fix(windaube): do not include Windows.h (avoid redefinitions) --- coreapi/call_log.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/coreapi/call_log.c b/coreapi/call_log.c index 499f3f582..43b4d4c44 100644 --- a/coreapi/call_log.c +++ b/coreapi/call_log.c @@ -21,15 +21,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include -#ifdef SQLITE_STORAGE_ENABLED - #ifndef _WIN32 - #if !defined(__ANDROID__) && !defined(__QNXNTO__) - #include - #include - #include - #endif -#else - #include +#if defined(SQLITE_STORAGE_ENABLED) && !defined(_WIN32) && !defined(__ANDROID__) && !defined(__QNXNTO__) + #include + #include + #include #endif #define MAX_PATH_SIZE 1024 From 889e73614f3fbb2911ce47235eb0b3477adf31a6 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 28 Sep 2017 12:30:21 +0200 Subject: [PATCH 0212/2215] fix(CallLog): bad endif --- coreapi/call_log.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/coreapi/call_log.c b/coreapi/call_log.c index 43b4d4c44..0933612b3 100644 --- a/coreapi/call_log.c +++ b/coreapi/call_log.c @@ -21,14 +21,16 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include -#if defined(SQLITE_STORAGE_ENABLED) && !defined(_WIN32) && !defined(__ANDROID__) && !defined(__QNXNTO__) - #include - #include - #include -#endif +#ifdef SQLITE_STORAGE_ENABLED + #if defined(_WIN32) && !defined(__ANDROID__) && !defined(__QNXNTO__) + #include + #include + #include + #endif -#define MAX_PATH_SIZE 1024 #include "sqlite3.h" + + #define MAX_PATH_SIZE 1024 #endif #include "c-wrapper/c-wrapper.h" From fc77bbe9f1d5518c1ab7e2d52ed3df024a874cd2 Mon Sep 17 00:00:00 2001 From: "Ronan Abhamon (Windaube)" Date: Thu, 28 Sep 2017 13:09:16 +0200 Subject: [PATCH 0213/2215] fix(windaube): do not include langinfo --- coreapi/call_log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/call_log.c b/coreapi/call_log.c index 0933612b3..c1f24ea10 100644 --- a/coreapi/call_log.c +++ b/coreapi/call_log.c @@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #ifdef SQLITE_STORAGE_ENABLED - #if defined(_WIN32) && !defined(__ANDROID__) && !defined(__QNXNTO__) + #if !defined(_WIN32) && !defined(__ANDROID__) && !defined(__QNXNTO__) #include #include #include From dc9fc11965a8d9e8095c66c1ab58d4d681ed7226 Mon Sep 17 00:00:00 2001 From: "Ronan Abhamon (Windaube)" Date: Thu, 28 Sep 2017 13:17:37 +0200 Subject: [PATCH 0214/2215] fix(windaube): in linphonecore use liblinphone_user_log_func, not invalid symbol --- coreapi/linphonecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 9e9dd8e86..2494d478a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -589,7 +589,7 @@ static void linphone_core_log_collection_handler(const char *domain, OrtpLogLeve #else /* This works on 32 bits, luckily. */ /* TODO: va_copy is available in Visual Studio 2013. */ - liblinphone_log_func(domain, level, fmt, args); + liblinphone_user_log_func(domain, level, fmt, args); #endif } From 5ab35788a4ad00a0e566ee5f1e2360f6c46437df Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 28 Sep 2017 13:27:04 +0200 Subject: [PATCH 0215/2215] Finished migration from C chatmessage to CPP --- src/chat/chat-message-p.h | 35 +- src/chat/chat-message.cpp | 1291 +++++++++++++++++++------------------ src/chat/chat-room.h | 1 + 3 files changed, 698 insertions(+), 629 deletions(-) diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 87892c120..fab4e79d9 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -74,13 +74,30 @@ public: LinphoneContent * getFileTransferInformation() const; void setFileTransferInformation(LinphoneContent *content); + // ----------------------------------------------------------------------------- + // Need to be public to be called from static C callbacks + // ----------------------------------------------------------------------------- + + void fileTransferOnProgress(belle_sip_body_handler_t *bh, belle_sip_message_t *m, size_t offset, size_t total); + int onSendBody(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, size_t offset, uint8_t *buffer, size_t *size); + void onSendEnd(belle_sip_user_body_handler_t *bh); + void onRecvBody(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, size_t offset, uint8_t *buffer, size_t size); + void onRecvEnd(belle_sip_user_body_handler_t *bh); + void fileUploadBackgroundTaskEnded(); + void processResponseFromPostFile(const belle_http_response_event_t *event); + void processResponseHeadersFromGetFile(const belle_http_response_event_t *event); + void processAuthRequestedDownload(const belle_sip_auth_event *event); + void processIoErrorUpload(const belle_sip_io_error_event_t *event); + void processAuthRequestedUpload(const belle_sip_auth_event *event); + void processIoErrorDownload(const belle_sip_io_error_event_t *event); + void processResponseFromGetFile(const belle_http_response_event_t *event); + // ----------------------------------------------------------------------------- void sendImdn(ImdnType imdnType, LinphoneReason reason); private: std::shared_ptr chatRoom; - std::string externalBodyUrl; ChatMessage::Direction direction = ChatMessage::Incoming; ChatMessage::State state = ChatMessage::Idle; unsigned int storageId; @@ -90,6 +107,8 @@ private: std::string id; std::string appData; std::string fileTransferFilePath; + std::string externalBodyUrl; + std::string rttMessage; bool isSecured = false; bool isReadOnly = false; bool isToBeStored = false; @@ -99,15 +118,29 @@ private: std::shared_ptr eventsDb; mutable LinphoneErrorInfo * errorInfo; belle_http_request_t *httpRequest; + belle_http_request_listener_t *httpListener; SalOp *salOp; SalCustomHeader *salCustomHeaders; + unsigned long backgroundTaskId; // Used for compatibility with previous C API std::string cContentType; std::string cText; LinphoneContent *cFileTransferInformation; + + // ----------------------------------------------------------------------------- std::string createImdnXml(ImdnType imdnType, LinphoneReason reason); + void fileUploadEndBackgroundTask(); + void fileUploadBeginBackgroundTask(); + bool isFileTransferInProgressAndValid(); + + int startHttpTransfer(std::string url, std::string action, belle_http_request_listener_callbacks_t *cbs); + + void releaseHttpRequest(); + + // ----------------------------------------------------------------------------- + L_DECLARE_PUBLIC(ChatMessage); }; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index e20a29f19..6ad7fa3cc 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -30,11 +30,15 @@ #include "modifier/multipart-chat-message-modifier.h" #include "modifier/cpim-chat-message-modifier.h" #include "chat-room-p.h" +#include "real-time-text-chat-room.h" + +#include "ortp/b64.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE +using namespace B64_NAMESPACE; using namespace std; // ============================================================================= @@ -68,9 +72,7 @@ void ChatMessagePrivate::setState(ChatMessage::State s) { && ((s == ChatMessage::State::DeliveredToUser) || (s == ChatMessage::State::Delivered) || (s == ChatMessage::State::NotDelivered))) { return; } - /* TODO - ms_message("Chat message %p: moving from state %s to %s", msg, linphone_chat_message_state_to_string(msg->state), linphone_chat_message_state_to_string(state)); - */ + ms_message("Chat message %p: moving from state %s to %s", this, linphone_chat_message_state_to_string((LinphoneChatMessageState)s), linphone_chat_message_state_to_string((LinphoneChatMessageState)state)); state = s; LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); @@ -157,16 +159,14 @@ void ChatMessagePrivate::setFileTransferInformation(LinphoneContent *content) { // ----------------------------------------------------------------------------- string ChatMessagePrivate::createImdnXml(ImdnType imdnType, LinphoneReason reason) { - /*xmlBufferPtr buf; + xmlBufferPtr buf; xmlTextWriterPtr writer; int err; - char *content = NULL; + string content; char *datetime = NULL; - const char *message_id; // Check that the chat message has a message id - message_id = linphone_chat_message_get_message_id(cm); - if (message_id == NULL) return NULL; + if (id.empty()) return NULL; buf = xmlBufferCreate(); if (buf == NULL) { @@ -179,7 +179,7 @@ string ChatMessagePrivate::createImdnXml(ImdnType imdnType, LinphoneReason reaso return content; } - datetime = linphone_timestamp_to_rfc3339_string(linphone_chat_message_get_time(cm)); + datetime = linphone_timestamp_to_rfc3339_string(time); err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); if (err >= 0) { err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"imdn", @@ -189,13 +189,13 @@ string ChatMessagePrivate::createImdnXml(ImdnType imdnType, LinphoneReason reaso err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"linphoneimdn", NULL, (const xmlChar *)"http://www.linphone.org/xsds/imdn.xsd"); } if (err >= 0) { - err = xmlTextWriterWriteElement(writer, (const xmlChar *)"message-id", (const xmlChar *)message_id); + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"message-id", (const xmlChar *)id.c_str()); } if (err >= 0) { err = xmlTextWriterWriteElement(writer, (const xmlChar *)"datetime", (const xmlChar *)datetime); } if (err >= 0) { - if (imdn_type == ImdnTypeDelivery) { + if (imdnType == ImdnTypeDelivery) { err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivery-notification"); } else { err = xmlTextWriterStartElement(writer, (const xmlChar *)"display-notification"); @@ -206,7 +206,7 @@ string ChatMessagePrivate::createImdnXml(ImdnType imdnType, LinphoneReason reaso } if (err >= 0) { if (reason == LinphoneReasonNone) { - if (imdn_type == ImdnTypeDelivery) { + if (imdnType == ImdnTypeDelivery) { err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivered"); } else { err = xmlTextWriterStartElement(writer, (const xmlChar *)"displayed"); @@ -250,13 +250,12 @@ string ChatMessagePrivate::createImdnXml(ImdnType imdnType, LinphoneReason reaso } if (err > 0) { // xmlTextWriterEndDocument returns the size of the content. - content = ms_strdup((char *)buf->content); + content = string((char *)buf->content); } xmlFreeTextWriter(writer); xmlBufferFree(buf); ms_free(datetime); - return content;*/ - return ""; + return content; } void ChatMessagePrivate::sendImdn(ImdnType imdnType, LinphoneReason reason) { @@ -264,6 +263,598 @@ void ChatMessagePrivate::sendImdn(ImdnType imdnType, LinphoneReason reason) { chatRoom->getPrivate()->sendImdn(content, reason); } +static void _chat_message_file_transfer_on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *m, + void *data, size_t offset, size_t total) { + ChatMessagePrivate *d = (ChatMessagePrivate *)data; + d->fileTransferOnProgress(bh, m, offset, total); +} + +void ChatMessagePrivate::fileTransferOnProgress(belle_sip_body_handler_t *bh, belle_sip_message_t *m, + size_t offset, size_t total) { + L_Q(); + + if (!isFileTransferInProgressAndValid()) { + ms_warning("Cancelled request for %s msg [%p], ignoring %s", chatRoom ? "" : "ORPHAN", this, __FUNCTION__); + releaseHttpRequest(); + return; + } + + LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); + if (linphone_chat_message_cbs_get_file_transfer_progress_indication(cbs)) { + linphone_chat_message_cbs_get_file_transfer_progress_indication(cbs)(msg, cFileTransferInformation, offset, total); + } else { + // Legacy: call back given by application level + linphone_core_notify_file_transfer_progress_indication(chatRoom->getCore(), msg, cFileTransferInformation, offset, total); + } +} + +static int _chat_message_on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, + void *data, size_t offset, uint8_t *buffer, size_t *size) { + ChatMessagePrivate *d = (ChatMessagePrivate *)data; + return d->onSendBody(bh, m, offset, buffer, size); +} + +int ChatMessagePrivate::onSendBody(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, + size_t offset, uint8_t *buffer, size_t *size) { + L_Q(); + + LinphoneCore *lc = NULL; + LinphoneImEncryptionEngine *imee = NULL; + int retval = -1; + LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); + + if (!isFileTransferInProgressAndValid()) { + if (httpRequest) { + ms_warning("Cancelled request for %s msg [%p], ignoring %s", chatRoom ? "" : "ORPHAN", this, __FUNCTION__); + releaseHttpRequest(); + } + return BELLE_SIP_STOP; + } + + lc = chatRoom->getCore(); + // if we've not reach the end of file yet, ask for more data + // in case of file body handler, won't be called + if (fileTransferFilePath.empty() && offset < linphone_content_get_size(cFileTransferInformation)) { + // get data from call back + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); + LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = linphone_chat_message_cbs_get_file_transfer_send(cbs); + if (file_transfer_send_cb) { + LinphoneBuffer *lb = file_transfer_send_cb(msg, cFileTransferInformation, offset, *size); + if (lb == NULL) { + *size = 0; + } else { + *size = linphone_buffer_get_size(lb); + memcpy(buffer, linphone_buffer_get_content(lb), *size); + linphone_buffer_unref(lb); + } + } else { + // Legacy + linphone_core_notify_file_transfer_send(lc, msg, cFileTransferInformation, (char *)buffer, size); + } + } + + imee = linphone_core_get_im_encryption_engine(lc); + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); + if (cb_process_uploading_file) { + size_t max_size = *size; + uint8_t *encrypted_buffer = (uint8_t *)ms_malloc0(max_size); + retval = cb_process_uploading_file(imee, msg, offset, (const uint8_t *)buffer, size, encrypted_buffer); + if (retval == 0) { + if (*size > max_size) { + ms_error("IM encryption engine process upload file callback returned a size bigger than the size of the buffer, so it will be truncated !"); + *size = max_size; + } + memcpy(buffer, encrypted_buffer, *size); + } + ms_free(encrypted_buffer); + } + } + + return retval <= 0 ? BELLE_SIP_CONTINUE : BELLE_SIP_STOP; +} + +static void _chat_message_on_send_end(belle_sip_user_body_handler_t *bh, void *data) { + ChatMessagePrivate *d = (ChatMessagePrivate *)data; + d->onSendEnd(bh); +} + +void ChatMessagePrivate::onSendEnd(belle_sip_user_body_handler_t *bh) { + L_Q(); + + LinphoneCore *lc = chatRoom->getCore(); + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); + + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); + if (cb_process_uploading_file) { + cb_process_uploading_file(imee, L_GET_C_BACK_PTR(q), 0, NULL, NULL, NULL); + } + } +} + +void ChatMessagePrivate::fileUploadEndBackgroundTask() { + if (backgroundTaskId) { + ms_message("channel [%p]: ending file upload background task with id=[%lx].", this, backgroundTaskId); + sal_end_background_task(backgroundTaskId); + backgroundTaskId = 0; + } +} + +static void _chat_message_file_upload_background_task_ended(void *data) { + ChatMessagePrivate *d = (ChatMessagePrivate *)data; + d->fileUploadBackgroundTaskEnded(); +} + +void ChatMessagePrivate::fileUploadBackgroundTaskEnded() { + ms_warning("channel [%p]: file upload background task has to be ended now, but work isn't finished.", this); + fileUploadEndBackgroundTask(); +} + +void ChatMessagePrivate::fileUploadBeginBackgroundTask() { + if (backgroundTaskId == 0) { + backgroundTaskId = sal_begin_background_task("file transfer upload", _chat_message_file_upload_background_task_ended, this); + if (backgroundTaskId) ms_message("channel [%p]: starting file upload background task with id=[%lx].", this, backgroundTaskId); + } +} + +static void _chat_message_on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset, uint8_t *buffer, size_t size) { + ChatMessagePrivate *d = (ChatMessagePrivate *)data; + d->onRecvBody(bh, m, offset, buffer, size); +} + +void ChatMessagePrivate::onRecvBody(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, size_t offset, uint8_t *buffer, size_t size) { + L_Q(); + + LinphoneCore *lc = NULL; + LinphoneImEncryptionEngine *imee = NULL; + int retval = -1; + uint8_t *decrypted_buffer = NULL; + + if (!chatRoom) { + q->cancelFileTransfer(); + return; + } + lc = chatRoom->getCore(); + + if (lc == NULL) { + return; // might happen during linphone_core_destroy() + } + + if (!httpRequest || belle_http_request_is_cancelled(httpRequest)) { + ms_warning("Cancelled request for msg [%p], ignoring %s", this, __FUNCTION__); + return; + } + + // first call may be with a zero size, ignore it + if (size == 0) { + return; + } + + decrypted_buffer = (uint8_t *)ms_malloc0(size); + imee = linphone_core_get_im_encryption_engine(lc); + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); + if (cb_process_downloading_file) { + retval = cb_process_downloading_file(imee, L_GET_C_BACK_PTR(q), offset, (const uint8_t *)buffer, size, decrypted_buffer); + if (retval == 0) { + memcpy(buffer, decrypted_buffer, size); + } + } + } + ms_free(decrypted_buffer); + + if (retval <= 0) { + if (fileTransferFilePath.empty()) { + LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); + if (linphone_chat_message_cbs_get_file_transfer_recv(cbs)) { + LinphoneBuffer *lb = linphone_buffer_new_from_data(buffer, size); + linphone_chat_message_cbs_get_file_transfer_recv(cbs)(msg, cFileTransferInformation, lb); + linphone_buffer_unref(lb); + } else { + // Legacy: call back given by application level + linphone_core_notify_file_transfer_recv(lc, msg, cFileTransferInformation, (const char *)buffer, size); + } + } + } else { + ms_warning("File transfer decrypt failed with code %d", (int)retval); + setState(ChatMessage::FileTransferError); + } + + return; +} + +static void _chat_message_on_recv_end(belle_sip_user_body_handler_t *bh, void *data) { + ChatMessagePrivate *d = (ChatMessagePrivate *)data; + d->onRecvEnd(bh); +} + +void ChatMessagePrivate::onRecvEnd(belle_sip_user_body_handler_t *bh) { + L_Q(); + + LinphoneCore *lc = chatRoom->getCore(); + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); + int retval = -1; + + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); + if (cb_process_downloading_file) { + retval = cb_process_downloading_file(imee, L_GET_C_BACK_PTR(q), 0, NULL, 0, NULL); + } + } + + if (retval <= 0) { + if (fileTransferFilePath.empty()) { + LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); + if (linphone_chat_message_cbs_get_file_transfer_recv(cbs)) { + LinphoneBuffer *lb = linphone_buffer_new(); + linphone_chat_message_cbs_get_file_transfer_recv(cbs)(msg, cFileTransferInformation, lb); + linphone_buffer_unref(lb); + } else { + // Legacy: call back given by application level + linphone_core_notify_file_transfer_recv(lc, msg, cFileTransferInformation, NULL, 0); + } + } + } + + if (retval <= 0 && state != ChatMessage::State::FileTransferError) { + setState(ChatMessage::State::FileTransferDone); + } +} + +bool ChatMessagePrivate::isFileTransferInProgressAndValid() { + return (chatRoom && chatRoom->getCore() && httpRequest && !!belle_http_request_is_cancelled(httpRequest)); +} + +static void _chat_message_process_response_from_post_file(void *data, const belle_http_response_event_t *event) { + ChatMessagePrivate *d = (ChatMessagePrivate *)data; + d->processResponseFromPostFile(event); +} + +void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_event_t *event) { + L_Q(); + + if (httpRequest && !isFileTransferInProgressAndValid()) { + ms_warning("Cancelled request for %s msg [%p], ignoring %s", chatRoom ? "" : "ORPHAN", this, __FUNCTION__); + releaseHttpRequest(); + return; + } + + // check the answer code + if (event->response) { + int code = belle_http_response_get_status_code(event->response); + if (code == 204) { // this is the reply to the first post to the server - an empty msg + // start uploading the file + belle_sip_multipart_body_handler_t *bh; + string first_part_header; + belle_sip_body_handler_t *first_part_bh; + + bool_t is_file_encryption_enabled = FALSE; + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(chatRoom->getCore()); + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer_cb = + linphone_im_encryption_engine_cbs_get_is_encryption_enabled_for_file_transfer(imee_cbs); + if (is_encryption_enabled_for_file_transfer_cb) { + is_file_encryption_enabled = is_encryption_enabled_for_file_transfer_cb(imee, L_GET_C_BACK_PTR(chatRoom)); + } + } + // shall we encrypt the file + if (is_file_encryption_enabled) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb generate_file_transfer_key_cb = + linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(imee_cbs); + if (generate_file_transfer_key_cb) { + generate_file_transfer_key_cb(imee, L_GET_C_BACK_PTR(chatRoom), L_GET_C_BACK_PTR(q)); + } + // temporary storage for the Content-disposition header value : use a generic filename to not leak it + // Actual filename stored in msg->file_transfer_information->name will be set in encrypted msg + // sended to the + first_part_header = "form-data; name=\"File\"; filename=\"filename.txt\""; + } else { + // temporary storage for the Content-disposition header value + first_part_header = "form-data; name=\"File\"; filename=\"%s\""; + first_part_header = first_part_header + linphone_content_get_name(cFileTransferInformation); + } + + // create a user body handler to take care of the file and add the content disposition and content-type headers + first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new( + linphone_content_get_size(cFileTransferInformation), + _chat_message_file_transfer_on_progress, NULL, NULL, + _chat_message_on_send_body, _chat_message_on_send_end, this); + if (!fileTransferFilePath.empty()) { + belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh; + // No need to add again the callback for progression, otherwise it will be called twice + first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(fileTransferFilePath.c_str(), NULL, this); + linphone_content_set_size(cFileTransferInformation, belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh)); + belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)first_part_bh, body_handler); + } else if (linphone_content_get_buffer(cFileTransferInformation) != NULL) { + first_part_bh = (belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer( + linphone_content_get_buffer(cFileTransferInformation), + linphone_content_get_size(cFileTransferInformation), _chat_message_file_transfer_on_progress, this); + } + + belle_sip_body_handler_add_header(first_part_bh, + belle_sip_header_create("Content-disposition", first_part_header.c_str())); + belle_sip_body_handler_add_header(first_part_bh, + (belle_sip_header_t *)belle_sip_header_content_type_create( + linphone_content_get_type(cFileTransferInformation), + linphone_content_get_subtype(cFileTransferInformation))); + + // insert it in a multipart body handler which will manage the boundaries of multipart msg + bh = belle_sip_multipart_body_handler_new(_chat_message_file_transfer_on_progress, this, first_part_bh, NULL); + + releaseHttpRequest(); + fileUploadBeginBackgroundTask(); + q->uploadFile(); + belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(httpRequest), BELLE_SIP_BODY_HANDLER(bh)); + } else if (code == 200) { // file has been uploaded correctly, get server reply and send it + const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); + if (body && strlen(body) > 0) { + // if we have an encryption key for the file, we must insert it into the msg and restore the correct filename + const char *content_key = linphone_content_get_key(cFileTransferInformation); + size_t content_key_size = linphone_content_get_key_size(cFileTransferInformation); + if (content_key != NULL) { + // parse the msg body + xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body); + + xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody); + if (cur != NULL) { + cur = cur->xmlChildrenNode; + while (cur != NULL) { + // we found a file info node, check it has a type="file" attribute + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { + xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); + // this is the node we are looking for : add a file-key children node + if (!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { + // need to parse the children node to update the file-name one + xmlNodePtr fileInfoNodeChildren = cur->xmlChildrenNode; + // convert key to base64 + size_t b64Size = b64_encode(NULL, content_key_size, NULL, 0); + char *keyb64 = (char *)ms_malloc0(b64Size + 1); + int xmlStringLength; + + b64Size = b64_encode(content_key, content_key_size, keyb64, b64Size); + keyb64[b64Size] = '\0'; // libxml need a null terminated string + + // add the node containing the key to the file-info node + xmlNewTextChild(cur, NULL, (const xmlChar *)"file-key", (const xmlChar *)keyb64); + xmlFree(typeAttribute); + ms_free(keyb64); + + // look for the file-name node and update its content + while (fileInfoNodeChildren != NULL) { + // we found a the file-name node, update its content with the real filename + if (!xmlStrcmp(fileInfoNodeChildren->name, (const xmlChar *)"file-name")) { + // update node content + xmlNodeSetContent(fileInfoNodeChildren, (const xmlChar *)(linphone_content_get_name(cFileTransferInformation))); + break; + } + fileInfoNodeChildren = fileInfoNodeChildren->next; + } + + // dump the xml into msg->message + xmlDocDumpFormatMemoryEnc(xmlMessageBody, (xmlChar **)&cText, &xmlStringLength, "UTF-8", 0); + break; + } + xmlFree(typeAttribute); + } + cur = cur->next; + } + } + xmlFreeDoc(xmlMessageBody); + } else { // no encryption key, transfer in plain, just copy the msg sent by server + cText = ms_strdup(body); + } + cContentType = "application/vnd.gsma.rcs-ft-http+xml"; + q->updateState(ChatMessage::FileTransferDone); + releaseHttpRequest(); + chatRoom->sendMessage(L_GET_C_BACK_PTR(q)); + fileUploadEndBackgroundTask(); + } else { + ms_warning("Received empty response from server, file transfer failed"); + q->updateState(ChatMessage::NotDelivered); + releaseHttpRequest(); + fileUploadEndBackgroundTask(); + } + } else { + ms_warning("Unhandled HTTP code response %d for file transfer", code); + q->updateState(ChatMessage::NotDelivered); + releaseHttpRequest(); + fileUploadEndBackgroundTask(); + } + } +} + +static void _chat_process_response_headers_from_get_file(void *data, const belle_http_response_event_t *event) { + ChatMessagePrivate *d = (ChatMessagePrivate *)data; + d->processResponseHeadersFromGetFile(event); +} + +static LinphoneContent *createFileTransferInformationFromHeaders(const belle_sip_message_t *m) { + LinphoneContent *content = linphone_content_new(); + + belle_sip_header_content_length_t *content_length_hdr = + BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(m, "Content-Length")); + belle_sip_header_content_type_t *content_type_hdr = + BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(m, "Content-Type")); + const char *type = NULL, *subtype = NULL; + + linphone_content_set_name(content, ""); + + if (content_type_hdr) { + type = belle_sip_header_content_type_get_type(content_type_hdr); + subtype = belle_sip_header_content_type_get_subtype(content_type_hdr); + ms_message("Extracted content type %s / %s from header", type ? type : "", subtype ? subtype : ""); + if (type) { + linphone_content_set_type(content, type); + } + if (subtype) { + linphone_content_set_subtype(content, subtype); + } + } + + if (content_length_hdr) { + linphone_content_set_size(content, belle_sip_header_content_length_get_content_length(content_length_hdr)); + ms_message("Extracted content length %i from header", (int)linphone_content_get_size(content)); + } + + return content; +} + +void ChatMessagePrivate::processResponseHeadersFromGetFile(const belle_http_response_event_t *event) { + if (event->response) { + //we are receiving a response, set a specific body handler to acquire the response. + // if not done, belle-sip will create a memory body handler, the default + belle_sip_message_t *response = BELLE_SIP_MESSAGE(event->response); + belle_sip_body_handler_t *body_handler = NULL; + size_t body_size = 0; + + if (cFileTransferInformation == NULL) { + ms_warning("No file transfer information for msg [%p]: creating...", this); + cFileTransferInformation = createFileTransferInformationFromHeaders(response); + } + + if (cFileTransferInformation) { + body_size = linphone_content_get_size(cFileTransferInformation); + } + + body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, _chat_message_file_transfer_on_progress, + NULL, _chat_message_on_recv_body, + NULL, _chat_message_on_recv_end, this); + if (!fileTransferFilePath.empty()) { + belle_sip_user_body_handler_t *bh = (belle_sip_user_body_handler_t *)body_handler; + body_handler = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(fileTransferFilePath.c_str(), _chat_message_file_transfer_on_progress, this); + if (belle_sip_body_handler_get_size((belle_sip_body_handler_t *)body_handler) == 0) { + // If the size of the body has not been initialized from the file stat, use the one from the + // file_transfer_information. + belle_sip_body_handler_set_size((belle_sip_body_handler_t *)body_handler, body_size); + } + belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)body_handler, bh); + } + belle_sip_message_set_body_handler((belle_sip_message_t *)event->response, body_handler); + } +} + +static void _chat_message_process_auth_requested_download(void *data, belle_sip_auth_event *event) { + ChatMessagePrivate *d = (ChatMessagePrivate *)data; + d->processAuthRequestedDownload(event); +} + +void ChatMessagePrivate::processAuthRequestedDownload(const belle_sip_auth_event *event) { + ms_error("Error during file download : auth requested for msg [%p]", this); + setState(ChatMessage::FileTransferError); + releaseHttpRequest(); +} + +static void _chat_message_process_io_error_upload(void *data, const belle_sip_io_error_event_t *event) { + ChatMessagePrivate *d = (ChatMessagePrivate *)data; + d->processIoErrorUpload(event); +} + +void ChatMessagePrivate::processIoErrorUpload(const belle_sip_io_error_event_t *event) { + L_Q(); + ms_error("I/O Error during file upload of msg [%p]", this); + setState(ChatMessage::NotDelivered); + releaseHttpRequest(); + chatRoom->getPrivate()->removeTransientMessage(L_GET_C_BACK_PTR(q)); +} + +static void _chat_message_process_auth_requested_upload(void *data, belle_sip_auth_event *event) { + ChatMessagePrivate *d = (ChatMessagePrivate *)data; + d->processAuthRequestedUpload(event); +} + +void ChatMessagePrivate::processAuthRequestedUpload(const belle_sip_auth_event *event) { + L_Q(); + ms_error("Error during file upload: auth requested for msg [%p]", this); + setState(ChatMessage::NotDelivered); + releaseHttpRequest(); + chatRoom->getPrivate()->removeTransientMessage(L_GET_C_BACK_PTR(q)); +} + +static void _chat_message_process_io_error_download(void *data, const belle_sip_io_error_event_t *event) { + ChatMessagePrivate *d = (ChatMessagePrivate *)data; + d->processIoErrorDownload(event); +} + +void ChatMessagePrivate::processIoErrorDownload(const belle_sip_io_error_event_t *event) { + ms_error("I/O Error during file download msg [%p]", this); + setState(ChatMessage::FileTransferError); + releaseHttpRequest(); +} + +static void _chat_message_process_response_from_get_file(void *data, const belle_http_response_event_t *event) { + ChatMessagePrivate *d = (ChatMessagePrivate *)data; + d->processResponseFromGetFile(event); +} + +void ChatMessagePrivate::processResponseFromGetFile(const belle_http_response_event_t *event) { + // check the answer code + if (event->response) { + int code = belle_http_response_get_status_code(event->response); + if (code >= 400 && code < 500) { + ms_warning("File transfer failed with code %d", code); + setState(ChatMessage::FileTransferError); + } else if (code != 200) { + ms_warning("Unhandled HTTP code response %d for file transfer", code); + } + releaseHttpRequest(); + } +} + +int ChatMessagePrivate::startHttpTransfer(std::string url, std::string action, belle_http_request_listener_callbacks_t *cbs) { + belle_generic_uri_t *uri = NULL; + const char* ua = linphone_core_get_user_agent(chatRoom->getCore()); + + if (url.empty()) { + ms_warning("Cannot process file transfer msg [%p]: no file remote URI configured.", this); + goto error; + } + uri = belle_generic_uri_parse(url.c_str()); + if (uri == NULL || belle_generic_uri_get_host(uri) == NULL) { + ms_warning("Cannot process file transfer msg [%p]: incorrect file remote URI configured '%s'.", this, url.c_str()); + goto error; + } + + httpRequest = belle_http_request_create(action.c_str(), uri, belle_sip_header_create("User-Agent", ua), NULL); + + if (httpRequest == NULL) { + ms_warning("Could not create http request for uri %s", url.c_str()); + goto error; + } + // keep a reference to the http request to be able to cancel it during upload + belle_sip_object_ref(httpRequest); + + // give msg to listener to be able to start the actual file upload when server answer a 204 No content + httpListener = belle_http_request_listener_create_from_callbacks(cbs, NULL); + belle_http_provider_send_request(chatRoom->getCore()->http_provider, httpRequest, httpListener); + return 0; +error: + if (uri) { + belle_sip_object_unref(uri); + } + return -1; +} + +void ChatMessagePrivate::releaseHttpRequest() { + if (httpRequest) { + belle_sip_object_unref(httpRequest); + httpRequest = NULL; + if (httpListener){ + belle_sip_object_unref(httpListener); + httpListener = NULL; + } + } +} + // ----------------------------------------------------------------------------- // ============================================================================= @@ -358,8 +949,7 @@ string ChatMessage::getAppdata () const { void ChatMessage::setAppdata (const string &appData) { L_D(); d->appData = appData; - // TODO: store app data in db ! - // linphone_chat_message_store_appdata(msg); + linphone_chat_message_store_appdata(L_GET_C_BACK_PTR(this)); } shared_ptr
    ChatMessage::getFromAddress () const { @@ -404,10 +994,6 @@ void ChatMessage::setIsToBeStored(bool store) { // ----------------------------------------------------------------------------- - - - - const LinphoneErrorInfo * ChatMessage::getErrorInfo() const { L_D(); if (!d->errorInfo) d->errorInfo = linphone_error_info_new(); //let's do it mutable @@ -469,13 +1055,14 @@ void ChatMessage::removeCustomHeader (const string &headerName) { // ----------------------------------------------------------------------------- void ChatMessage::updateState(State state) { - //TODO - /*linphone_chat_message_set_state(msg, new_state); - linphone_chat_message_store_state(msg); + L_D(); - if (msg->state == LinphoneChatMessageStateDelivered || msg->state == LinphoneChatMessageStateNotDelivered) { - L_GET_PRIVATE_FROM_C_OBJECT(msg->chat_room)->moveTransientMessageToWeakMessages(msg); - }*/ + d->setState(state); + linphone_chat_message_store_state(L_GET_C_BACK_PTR(this)); + + if (state == Delivered || state == NotDelivered) { + d->chatRoom->getPrivate()->moveTransientMessageToWeakMessages(L_GET_C_BACK_PTR(this)); + } } void ChatMessage::send () { @@ -502,53 +1089,13 @@ void ChatMessage::reSend() { L_D(); if (d->state != NotDelivered) { - // ms_warning("Cannot resend chat message in state %s", linphone_chat_message_state_to_string(state)); + ms_warning("Cannot resend chat message in state %s", linphone_chat_message_state_to_string((LinphoneChatMessageState)d->state)); return; } d->chatRoom->sendMessage(L_GET_C_BACK_PTR(this)); } -/*static void linphone_chat_message_process_io_error_upload(void *data, const belle_sip_io_error_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - ms_error("I/O Error during file upload of msg [%p]", msg); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); - _release_http_request(msg); - linphone_chat_room_remove_transient_message(msg->chat_room, msg); - linphone_chat_message_unref(msg); -} - -static void linphone_chat_message_process_auth_requested_upload(void *data, belle_sip_auth_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - ms_error("Error during file upload: auth requested for msg [%p]", msg); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); - _release_http_request(msg); - linphone_chat_room_remove_transient_message(msg->chat_room, msg); - linphone_chat_message_unref(msg); -} - -static void linphone_chat_message_process_io_error_download(void *data, const belle_sip_io_error_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - ms_error("I/O Error during file download msg [%p]", msg); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateFileTransferError); - _release_http_request(msg); -} - -static void linphone_chat_process_response_from_get_file(void *data, const belle_http_response_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - // check the answer code - if (event->response) { - int code = belle_http_response_get_status_code(event->response); - if (code >= 400 && code < 500) { - ms_warning("File transfer failed with code %d", code); - linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferError); - } else if (code != 200) { - ms_warning("Unhandled HTTP code response %d for file transfer", code); - } - _release_http_request(msg); - } -}*/ - void ChatMessage::sendDeliveryNotification(LinphoneReason reason) { L_D(); LinphoneCore *lc = d->chatRoom->getCore(); @@ -567,584 +1114,74 @@ void ChatMessage::sendDisplayNotification() { } } -/* -static LinphoneContent *linphone_chat_create_file_transfer_information_from_headers(const belle_sip_message_t *m) { - LinphoneContent *content = linphone_content_new(); - - belle_sip_header_content_length_t *content_length_hdr = - BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(m, "Content-Length")); - belle_sip_header_content_type_t *content_type_hdr = - BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(m, "Content-Type")); - const char *type = NULL, *subtype = NULL; - - linphone_content_set_name(content, ""); - - if (content_type_hdr) { - type = belle_sip_header_content_type_get_type(content_type_hdr); - subtype = belle_sip_header_content_type_get_subtype(content_type_hdr); - ms_message("Extracted content type %s / %s from header", type ? type : "", subtype ? subtype : ""); - if (type) - linphone_content_set_type(content, type); - if (subtype) - linphone_content_set_subtype(content, subtype); - } - - if (content_length_hdr) { - linphone_content_set_size(content, belle_sip_header_content_length_get_content_length(content_length_hdr)); - ms_message("Extracted content length %i from header", (int)linphone_content_get_size(content)); - } - - return content; -} - -static void linphone_chat_process_response_headers_from_get_file(void *data, const belle_http_response_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - if (event->response) { - //we are receiving a response, set a specific body handler to acquire the response. - // if not done, belle-sip will create a memory body handler, the default - belle_sip_message_t *response = BELLE_SIP_MESSAGE(event->response); - belle_sip_body_handler_t *body_handler = NULL; - size_t body_size = 0; - - if (msg->file_transfer_information == NULL) { - ms_warning("No file transfer information for msg %p: creating...", msg); - msg->file_transfer_information = linphone_chat_create_file_transfer_information_from_headers(response); - } - - if (msg->file_transfer_information) { - body_size = linphone_content_get_size(msg->file_transfer_information); - } - - - body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, linphone_chat_message_file_transfer_on_progress, NULL, on_recv_body, NULL, on_recv_end, msg); - if (msg->file_transfer_filepath != NULL) { - belle_sip_user_body_handler_t *bh = (belle_sip_user_body_handler_t *)body_handler; - body_handler = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new( - msg->file_transfer_filepath, linphone_chat_message_file_transfer_on_progress, msg); - if (belle_sip_body_handler_get_size((belle_sip_body_handler_t *)body_handler) == 0) { - // If the size of the body has not been initialized from the file stat, use the one from the - // file_transfer_information. - belle_sip_body_handler_set_size((belle_sip_body_handler_t *)body_handler, body_size); - } - belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)body_handler, bh); - } - belle_sip_message_set_body_handler((belle_sip_message_t *)event->response, body_handler); - } - }*/ - -/*static bool_t file_transfer_in_progress_and_valid(LinphoneChatMessage* msg) { - return (linphone_chat_message_get_chat_room(msg) && - linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)) && - linphone_chat_message_get_http_request(msg) && - !belle_http_request_is_cancelled(linphone_chat_message_get_http_request(msg))); -} - -static void _release_http_request(LinphoneChatMessage* msg) { - if (linphone_chat_message_get_http_request(msg)) { - belle_sip_object_unref(msg->http_request); - msg->http_request = NULL; - if (msg->http_listener){ - belle_sip_object_unref(msg->http_listener); - msg->http_listener = NULL; - // unhold the reference that the listener was holding on the message - linphone_chat_message_unref(msg); - } - } -} - -static void linphone_chat_message_process_auth_requested_download(void *data, belle_sip_auth_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - ms_error("Error during file download : auth requested for msg [%p]", msg); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateFileTransferError); - _release_http_request(msg); -} - -static void linphone_chat_message_file_transfer_on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *m, - void *data, size_t offset, size_t total) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - if (!file_transfer_in_progress_and_valid(msg)) { - ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); - _release_http_request(msg); - return; - } - if (linphone_chat_message_cbs_get_file_transfer_progress_indication(msg->cbs)) { - linphone_chat_message_cbs_get_file_transfer_progress_indication(msg->cbs)( - msg, msg->file_transfer_information, offset, total); - } else { - // Legacy: call back given by application level - linphone_core_notify_file_transfer_progress_indication(linphone_chat_room_get_core(msg->chat_room), msg, msg->file_transfer_information, - offset, total); - } -} - -static int on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, - void *data, size_t offset, uint8_t *buffer, size_t *size) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - LinphoneCore *lc = NULL; - LinphoneImEncryptionEngine *imee = NULL; - int retval = -1; - - if (!file_transfer_in_progress_and_valid(msg)) { - if (msg->http_request) { - ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); - _release_http_request(msg); - } - return BELLE_SIP_STOP; - } - - lc = linphone_chat_room_get_core(msg->chat_room); - // if we've not reach the end of file yet, ask for more data - // in case of file body handler, won't be called - if (msg->file_transfer_filepath == NULL && offset < linphone_content_get_size(msg->file_transfer_information)) { - // get data from call back - LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = linphone_chat_message_cbs_get_file_transfer_send(msg->cbs); - if (file_transfer_send_cb) { - LinphoneBuffer *lb = file_transfer_send_cb(msg, msg->file_transfer_information, offset, *size); - if (lb == NULL) { - *size = 0; - } else { - *size = linphone_buffer_get_size(lb); - memcpy(buffer, linphone_buffer_get_content(lb), *size); - linphone_buffer_unref(lb); - } - } else { - // Legacy - linphone_core_notify_file_transfer_send(lc, msg, msg->file_transfer_information, (char *)buffer, size); - } - } - - imee = linphone_core_get_im_encryption_engine(lc); - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); - if (cb_process_uploading_file) { - size_t max_size = *size; - uint8_t *encrypted_buffer = (uint8_t *)ms_malloc0(max_size); - retval = cb_process_uploading_file(imee, msg, offset, (const uint8_t *)buffer, size, encrypted_buffer); - if (retval == 0) { - if (*size > max_size) { - ms_error("IM encryption engine process upload file callback returned a size bigger than the size of the buffer, so it will be truncated !"); - *size = max_size; - } - memcpy(buffer, encrypted_buffer, *size); - } - ms_free(encrypted_buffer); - } - } - - return retval <= 0 ? BELLE_SIP_CONTINUE : BELLE_SIP_STOP; -} - -static void on_send_end(belle_sip_user_body_handler_t *bh, void *data) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room); - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); - - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); - if (cb_process_uploading_file) { - cb_process_uploading_file(imee, msg, 0, NULL, NULL, NULL); - } - } -} - -static void file_upload_end_background_task(LinphoneChatMessage *obj){ - if (obj->bg_task_id){ - ms_message("channel [%p]: ending file upload background task with id=[%lx].",obj,obj->bg_task_id); - sal_end_background_task(obj->bg_task_id); - obj->bg_task_id=0; - } -} - -static void file_upload_background_task_ended(LinphoneChatMessage *obj){ - ms_warning("channel [%p]: file upload background task has to be ended now, but work isn't finished.",obj); - file_upload_end_background_task(obj); -} - -static void file_upload_begin_background_task(LinphoneChatMessage *obj){ - if (obj->bg_task_id==0){ - obj->bg_task_id=sal_begin_background_task("file transfer upload",(void (*)(void*))file_upload_background_task_ended, obj); - if (obj->bg_task_id) ms_message("channel [%p]: starting file upload background task with id=[%lx].",obj,obj->bg_task_id); - } -} - -static void linphone_chat_message_process_response_from_post_file(void *data, const belle_http_response_event_t *event) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - - if (msg->http_request && !file_transfer_in_progress_and_valid(msg)) { - ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__); - _release_http_request(msg); - return; - } - - // check the answer code - if (event->response) { - int code = belle_http_response_get_status_code(event->response); - if (code == 204) { // this is the reply to the first post to the server - an empty msg - // start uploading the file - belle_sip_multipart_body_handler_t *bh; - char *first_part_header; - belle_sip_body_handler_t *first_part_bh; - - bool_t is_file_encryption_enabled = FALSE; - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(linphone_chat_room_get_core(msg->chat_room)); - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer_cb = - linphone_im_encryption_engine_cbs_get_is_encryption_enabled_for_file_transfer(imee_cbs); - if (is_encryption_enabled_for_file_transfer_cb) { - is_file_encryption_enabled = is_encryption_enabled_for_file_transfer_cb(imee, msg->chat_room); - } - } - // shall we encrypt the file - if (is_file_encryption_enabled) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb generate_file_transfer_key_cb = - linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(imee_cbs); - if (generate_file_transfer_key_cb) { - generate_file_transfer_key_cb(imee, msg->chat_room, msg); - } - // temporary storage for the Content-disposition header value : use a generic filename to not leak it - // Actual filename stored in msg->file_transfer_information->name will be set in encrypted msg - // sended to the - first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"filename.txt\""); - } else { - // temporary storage for the Content-disposition header value - first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"%s\"", - linphone_content_get_name(msg->file_transfer_information)); - } - - // create a user body handler to take care of the file and add the content disposition and content-type headers - first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new( - linphone_content_get_size(msg->file_transfer_information), - linphone_chat_message_file_transfer_on_progress, NULL, NULL, - on_send_body, on_send_end, msg); - if (msg->file_transfer_filepath != NULL) { - belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh; - first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(msg->file_transfer_filepath, - NULL, msg); // No need to add again the callback for progression, otherwise it will be called twice - linphone_content_set_size(msg->file_transfer_information, belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh)); - belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)first_part_bh, body_handler); - } else if (linphone_content_get_buffer(msg->file_transfer_information) != NULL) { - first_part_bh = (belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer( - linphone_content_get_buffer(msg->file_transfer_information), - linphone_content_get_size(msg->file_transfer_information), linphone_chat_message_file_transfer_on_progress, msg); - } - - belle_sip_body_handler_add_header(first_part_bh, - belle_sip_header_create("Content-disposition", first_part_header)); - belle_sip_free(first_part_header); - belle_sip_body_handler_add_header(first_part_bh, - (belle_sip_header_t *)belle_sip_header_content_type_create( - linphone_content_get_type(msg->file_transfer_information), - linphone_content_get_subtype(msg->file_transfer_information))); - - // insert it in a multipart body handler which will manage the boundaries of multipart msg - bh = belle_sip_multipart_body_handler_new(linphone_chat_message_file_transfer_on_progress, msg, first_part_bh, NULL); - - linphone_chat_message_ref(msg); - _release_http_request(msg); - file_upload_begin_background_task(msg); - linphone_chat_room_upload_file(msg); - belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(msg->http_request), BELLE_SIP_BODY_HANDLER(bh)); - linphone_chat_message_unref(msg); - } else if (code == 200) { // file has been uploaded correctly, get server reply and send it - const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); - if (body && strlen(body) > 0) { - // if we have an encryption key for the file, we must insert it into the msg and restore the correct filename - const char *content_key = linphone_content_get_key(msg->file_transfer_information); - size_t content_key_size = linphone_content_get_key_size(msg->file_transfer_information); - if (content_key != NULL) { - // parse the msg body - xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body); - - xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody); - if (cur != NULL) { - cur = cur->xmlChildrenNode; - while (cur != NULL) { - if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { // we found a file info node, check - // it has a type="file" attribute - xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); - if (!xmlStrcmp(typeAttribute, - (const xmlChar *)"file")) { // this is the node we are looking for : add a - // file-key children node - xmlNodePtr fileInfoNodeChildren = - cur - ->xmlChildrenNode; // need to parse the children node to update the file-name one - // convert key to base64 - size_t b64Size = b64::b64_encode(NULL, content_key_size, NULL, 0); - char *keyb64 = (char *)ms_malloc0(b64Size + 1); - int xmlStringLength; - - b64Size = b64::b64_encode(content_key, content_key_size, keyb64, b64Size); - keyb64[b64Size] = '\0'; // libxml need a null terminated string - - // add the node containing the key to the file-info node - xmlNewTextChild(cur, NULL, (const xmlChar *)"file-key", (const xmlChar *)keyb64); - xmlFree(typeAttribute); - ms_free(keyb64); - - // look for the file-name node and update its content - while (fileInfoNodeChildren != NULL) { - if (!xmlStrcmp( - fileInfoNodeChildren->name, - (const xmlChar *)"file-name")) { // we found a the file-name node, update - // its content with the real filename - // update node content - xmlNodeSetContent(fileInfoNodeChildren, - (const xmlChar *)(linphone_content_get_name( - msg->file_transfer_information))); - break; - } - fileInfoNodeChildren = fileInfoNodeChildren->next; - } - - // dump the xml into msg->message - xmlDocDumpFormatMemoryEnc(xmlMessageBody, (xmlChar **)&msg->message, &xmlStringLength, - "UTF-8", 0); - - break; - } - xmlFree(typeAttribute); - } - cur = cur->next; - } - } - xmlFreeDoc(xmlMessageBody); - } else { // no encryption key, transfer in plain, just copy the msg sent by server - msg->message = ms_strdup(body); - } - linphone_chat_message_set_content_type(msg, "application/vnd.gsma.rcs-ft-http+xml"); - linphone_chat_message_ref(msg); - linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone); - _release_http_request(msg); - L_GET_CPP_PTR_FROM_C_OBJECT(msg->chat_room)->sendMessage(msg); - file_upload_end_background_task(msg); - linphone_chat_message_unref(msg); - } else { - ms_warning("Received empty response from server, file transfer failed"); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); - _release_http_request(msg); - file_upload_end_background_task(msg); - linphone_chat_message_unref(msg); - } - } else { - ms_warning("Unhandled HTTP code response %d for file transfer", code); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); - _release_http_request(msg); - file_upload_end_background_task(msg); - linphone_chat_message_unref(msg); - } - } -} - -static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset, uint8_t *buffer, size_t size) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - LinphoneCore *lc = NULL; - LinphoneImEncryptionEngine *imee = NULL; - int retval = -1; - uint8_t *decrypted_buffer = NULL; - - if (!msg->chat_room) { - linphone_chat_message_cancel_file_transfer(msg); - return; - } - lc = linphone_chat_room_get_core(msg->chat_room); - - if (lc == NULL){ - return; // might happen during linphone_core_destroy() - } - - if (!msg->http_request || belle_http_request_is_cancelled(msg->http_request)) { - ms_warning("Cancelled request for msg [%p], ignoring %s", msg, __FUNCTION__); - return; - } - - // first call may be with a zero size, ignore it - if (size == 0) { - return; - } - - decrypted_buffer = (uint8_t *)ms_malloc0(size); - imee = linphone_core_get_im_encryption_engine(lc); - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); - if (cb_process_downloading_file) { - retval = cb_process_downloading_file(imee, msg, offset, (const uint8_t *)buffer, size, decrypted_buffer); - if (retval == 0) { - memcpy(buffer, decrypted_buffer, size); - } - } - } - ms_free(decrypted_buffer); - - if (retval <= 0) { - if (msg->file_transfer_filepath == NULL) { - if (linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)) { - LinphoneBuffer *lb = linphone_buffer_new_from_data(buffer, size); - linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)(msg, msg->file_transfer_information, lb); - linphone_buffer_unref(lb); - } else { - // Legacy: call back given by application level - linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, (const char *)buffer, size); - } - } - } else { - ms_warning("File transfer decrypt failed with code %d", (int)retval); - linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferError); - } - - return; -} - -static void on_recv_end(belle_sip_user_body_handler_t *bh, void *data) { - LinphoneChatMessage *msg = (LinphoneChatMessage *)data; - LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room); - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); - int retval = -1; - - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); - if (cb_process_downloading_file) { - retval = cb_process_downloading_file(imee, msg, 0, NULL, 0, NULL); - } - } - - if (retval <= 0) { - if (msg->file_transfer_filepath == NULL) { - if (linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)) { - LinphoneBuffer *lb = linphone_buffer_new(); - linphone_chat_message_cbs_get_file_transfer_recv(msg->cbs)(msg, msg->file_transfer_information, lb); - linphone_buffer_unref(lb); - } else { - // Legacy: call back given by application level - linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, NULL, 0); - } - } - } - - if (retval <= 0 && linphone_chat_message_get_state(msg) != LinphoneChatMessageStateFileTransferError) { - linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone); - } -}*/ - -/* - -static int _linphone_chat_room_start_http_transfer(LinphoneChatMessage *msg, const char* url, const char* action, const belle_http_request_listener_callbacks_t *cbs) { - belle_generic_uri_t *uri = NULL; - const char* ua = linphone_core_get_user_agent(linphone_chat_room_get_core(msg->chat_room)); - - if (url == NULL) { - ms_warning("Cannot process file transfer msg: no file remote URI configured."); - goto error; - } - uri = belle_generic_uri_parse(url); - if (uri == NULL || belle_generic_uri_get_host(uri)==NULL) { - ms_warning("Cannot process file transfer msg: incorrect file remote URI configured '%s'.", url); - goto error; - } - - msg->http_request = belle_http_request_create(action, uri, belle_sip_header_create("User-Agent", ua), NULL); - - if (msg->http_request == NULL) { - ms_warning("Could not create http request for uri %s", url); - goto error; - } - // keep a reference to the http request to be able to cancel it during upload - belle_sip_object_ref(msg->http_request); - - // give msg to listener to be able to start the actual file upload when server answer a 204 No content - msg->http_listener = belle_http_request_listener_create_from_callbacks(cbs, linphone_chat_message_ref(msg)); - belle_http_provider_send_request(linphone_chat_room_get_core(msg->chat_room)->http_provider, msg->http_request, msg->http_listener); - return 0; - error: - if (uri) { - belle_sip_object_unref(uri); - } - return -1; - } -*/ - int ChatMessage::uploadFile() { - return -1; - //TODO - /*belle_http_request_listener_callbacks_t cbs = {0}; - int err; + L_D(); - if (msg->http_request){ + if (d->httpRequest){ ms_error("linphone_chat_room_upload_file(): there is already an upload in progress."); return -1; } - cbs.process_response = linphone_chat_message_process_response_from_post_file; - cbs.process_io_error = linphone_chat_message_process_io_error_upload; - cbs.process_auth_requested = linphone_chat_message_process_auth_requested_upload; - err = _linphone_chat_room_start_http_transfer(msg, linphone_core_get_file_transfer_server(linphone_chat_room_get_core(msg->chat_room)), "POST", &cbs); - if (err == -1){ - linphone_chat_message_set_state(msg, LinphoneChatMessageStateNotDelivered); + belle_http_request_listener_callbacks_t cbs = {0}; + cbs.process_response = _chat_message_process_response_from_post_file; + cbs.process_io_error = _chat_message_process_io_error_upload; + cbs.process_auth_requested = _chat_message_process_auth_requested_upload; + int err = d->startHttpTransfer(linphone_core_get_file_transfer_server(d->chatRoom->getCore()), "POST", &cbs); + + if (err == -1) { + d->setState(NotDelivered); } - return err;*/ + return err; } int ChatMessage::downloadFile() { - return -1; - //TODO - /*belle_http_request_listener_callbacks_t cbs = {0}; - int err; + L_D(); - if (msg->http_request){ + if (d->httpRequest) { ms_error("linphone_chat_message_download_file(): there is already a download in progress"); return -1; } - cbs.process_response_headers = linphone_chat_process_response_headers_from_get_file; - cbs.process_response = linphone_chat_process_response_from_get_file; - cbs.process_io_error = linphone_chat_message_process_io_error_download; - cbs.process_auth_requested = linphone_chat_message_process_auth_requested_download; - err = _linphone_chat_room_start_http_transfer(msg, msg->external_body_url, "GET", &cbs); + + belle_http_request_listener_callbacks_t cbs = {0}; + cbs.process_response_headers = _chat_process_response_headers_from_get_file; + cbs.process_response = _chat_message_process_response_from_get_file; + cbs.process_io_error = _chat_message_process_io_error_download; + cbs.process_auth_requested = _chat_message_process_auth_requested_download; + int err = d->startHttpTransfer(d->externalBodyUrl, "GET", &cbs); + if (err == -1) return -1; // start the download, status is In Progress - linphone_chat_message_set_state(msg, LinphoneChatMessageStateInProgress); - return 0;*/ + d->setState(InProgress); + return 0; } void ChatMessage::cancelFileTransfer() { - //TODO - /*if (msg->http_request) { - if (msg->state == LinphoneChatMessageStateInProgress) { - linphone_chat_message_set_state(msg, LinphoneChatMessageStateNotDelivered); + L_D(); + if (d->httpRequest) { + if (d->state == InProgress) { + d->setState(NotDelivered); } - if (!belle_http_request_is_cancelled(msg->http_request)) { - if (msg->chat_room) { - ms_message("Canceling file transfer %s - msg [%p] chat room[%p]" - , (msg->external_body_url == NULL) ? linphone_core_get_file_transfer_server(linphone_chat_room_get_core(msg->chat_room)) : msg->external_body_url - , msg - , msg->chat_room); - belle_http_provider_cancel_request(linphone_chat_room_get_core(msg->chat_room)->http_provider, msg->http_request); - if ((msg->dir == LinphoneChatMessageOutgoing) && unref) { - // must release it - linphone_chat_message_unref(msg); - } + if (!belle_http_request_is_cancelled(d->httpRequest)) { + if (d->chatRoom) { + ms_message("Canceling file transfer %s", (d->externalBodyUrl.empty()) ? linphone_core_get_file_transfer_server(d->chatRoom->getCore()) : d->externalBodyUrl.c_str()); + belle_http_provider_cancel_request(d->chatRoom->getCore()->http_provider, d->httpRequest); } else { - ms_message("Warning: http request still running for ORPHAN msg [%p]: this is a memory leak", msg); + ms_message("Warning: http request still running for ORPHAN msg: this is a memory leak"); } } - _release_http_request(msg); + d->releaseHttpRequest(); } else { ms_message("No existing file transfer - nothing to cancel"); - }*/ + } } int ChatMessage::putCharacter(uint32_t character) { - //TODO - /*LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); - if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) { + L_D(); + LinphoneCore *lc = d->chatRoom->getCore(); + if (linphone_core_realtime_text_enabled(lc)) { shared_ptr rttcr = - static_pointer_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); + static_pointer_cast(d->chatRoom); LinphoneCall *call = rttcr->getCall(); - LinphoneCore *lc = rttcr->getCore(); const uint32_t new_line = 0x2028; const uint32_t crlf = 0x0D0A; const uint32_t lf = 0x0A; @@ -1155,26 +1192,24 @@ int ChatMessage::putCharacter(uint32_t character) { if (character == new_line || character == crlf || character == lf) { if (lc && lp_config_get_int(lc->config, "misc", "store_rtt_messages", 1) == 1) { - ms_debug("New line sent, forge a message with content %s", msg->message); - msg->time = ms_time(0); - msg->state = LinphoneChatMessageStateDisplayed; - msg->dir = LinphoneChatMessageOutgoing; - if (msg->from) linphone_address_unref(msg->from); - msg->from = linphone_address_new(linphone_core_get_identity(lc)); - msg->storage_id = linphone_chat_message_store(msg); - ms_free(msg->message); - msg->message = NULL; + ms_debug("New line sent, forge a message with content %s", d->rttMessage.c_str()); + d->setTime(ms_time(0)); + d->state = Displayed; + d->direction = Outgoing; + setFromAddress(make_shared(linphone_address_as_string(linphone_address_new(linphone_core_get_identity(lc))))); + linphone_chat_message_store(L_GET_C_BACK_PTR(this)); + d->rttMessage = ""; } } else { char *value = LinphonePrivate::Utils::utf8ToChar(character); - msg->message = ms_strcat_printf(msg->message, value); - ms_debug("Sent RTT character: %s (%lu), pending text is %s", value, (unsigned long)character, msg->message); + d->rttMessage = d->rttMessage + string(value); + ms_debug("Sent RTT character: %s (%lu), pending text is %s", value, (unsigned long)character, d->rttMessage.c_str()); delete value; } text_stream_putchar32(reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeText)), character); return 0; - }*/ + } return -1; } diff --git a/src/chat/chat-room.h b/src/chat/chat-room.h index b1c23c7ab..debff026f 100644 --- a/src/chat/chat-room.h +++ b/src/chat/chat-room.h @@ -37,6 +37,7 @@ LINPHONE_BEGIN_NAMESPACE class ChatRoomPrivate; class LINPHONE_PUBLIC ChatRoom : public Object, public ConferenceInterface { + friend class ChatMessage; friend class ChatMessagePrivate; public: From 6add595c90217046ef544f8b3d4c1f709378dff0 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 28 Sep 2017 14:07:54 +0200 Subject: [PATCH 0216/2215] fix(Proxy): check contact address validity in guess_contact_for_register --- coreapi/proxy.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index e51322498..8268edff6 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -439,10 +439,14 @@ void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig * cfg){ } static void guess_contact_for_register (LinphoneProxyConfig *cfg) { - linphone_address_unref(cfg->contact_address); + if (cfg->contact_address) + linphone_address_unref(cfg->contact_address); cfg->contact_address = nullptr; - linphone_address_unref(cfg->contact_address_without_params); + + if (cfg->contact_address_without_params) + linphone_address_unref(cfg->contact_address_without_params); cfg->contact_address_without_params = nullptr; + LinphoneAddress *proxy = linphone_address_new(cfg->reg_proxy); if (!proxy) return; From 2b1f9ea105cccef98e595b1f9d4cae90b095fec5 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 28 Sep 2017 14:30:45 +0200 Subject: [PATCH 0217/2215] fix(c-wrapper): L_EXPAND is necessary for windows in the macro chooser case --- src/c-wrapper/internal/c-tools.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 7692cfbea..5e371372d 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -536,7 +536,7 @@ LINPHONE_END_NAMESPACE L_EXPAND(L_GET_ARG_3(__VA_ARGS__, L_GET_CPP_PTR_FROM_C_OBJECT_2_ARGS, L_GET_CPP_PTR_FROM_C_OBJECT_1_ARGS)) #define L_GET_CPP_PTR_FROM_C_OBJECT(...) \ - L_GET_CPP_PTR_FROM_C_OBJECT_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__) + L_EXPAND(L_GET_CPP_PTR_FROM_C_OBJECT_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)) // Set the cpp-ptr of a wrapped C object. #define L_SET_CPP_PTR_FROM_C_OBJECT(C_OBJECT, CPP_OBJECT) \ @@ -556,7 +556,7 @@ LINPHONE_END_NAMESPACE L_EXPAND(L_GET_ARG_3(__VA_ARGS__, L_GET_PRIVATE_FROM_C_OBJECT_2_ARGS, L_GET_PRIVATE_FROM_C_OBJECT_1_ARGS)) #define L_GET_PRIVATE_FROM_C_OBJECT(...) \ - L_GET_PRIVATE_FROM_C_OBJECT_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__) + L_EXPAND(L_GET_PRIVATE_FROM_C_OBJECT_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)) // Get the wrapped C object of a C++ object. #define L_GET_C_BACK_PTR(CPP_OBJECT) \ From b499578df6fa7ba193ea49c80e1ab429829e651b Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 28 Sep 2017 14:31:42 +0200 Subject: [PATCH 0218/2215] fix cast && better char* management --- daemon/commands/netsim.cc | 2 +- daemon/daemon.cc | 2 +- tester/conference-event-tester.cpp | 84 +++++++++++++++++++++--------- 3 files changed, 62 insertions(+), 26 deletions(-) diff --git a/daemon/commands/netsim.cc b/daemon/commands/netsim.cc index d2678d188..21d543c5a 100644 --- a/daemon/commands/netsim.cc +++ b/daemon/commands/netsim.cc @@ -96,7 +96,7 @@ void NetsimCommand::exec(Daemon* app, const string& args) { params.loss_rate = (float)atoi(value); } if (fmtp_get_value(parameters.c_str(), "latency", value, sizeof(value))) { - params.latency = atoi(value); + params.latency = (uint32_t)atoi(value); } if (fmtp_get_value(parameters.c_str(), "consecutive_loss_probability", value, sizeof(value))) { params.consecutive_loss_probability = (float)atof(value); diff --git a/daemon/daemon.cc b/daemon/daemon.cc index d97650863..77b769f9d 100644 --- a/daemon/daemon.cc +++ b/daemon/daemon.cc @@ -635,7 +635,7 @@ string Daemon::readPipe() { pfd[1].fd = mChildFd; nfds++; } - int err = poll(pfd, nfds, 50); + int err = poll(pfd, (nfds_t)nfds, 50); if (err > 0) { if (mServerFd != (ortp_pipe_t)-1 && (pfd[0].revents & POLLIN)) { struct sockaddr_storage addr; diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index e70ba8843..5aedeb447 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -472,11 +472,14 @@ void first_notify_parsing() { ConferenceEventTester tester(marie->lc, addr); LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); - char notify[strlen(first_notify) + strlen(confUri)]; + size_t size = strlen(first_notify) + strlen(confUri); + char *notify = new char[size]; - snprintf(notify, sizeof(notify), first_notify, confUri); + snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); + delete[] notify; + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); @@ -498,11 +501,14 @@ void first_notify_parsing_wrong_conf() { ConferenceEventTester tester(marie->lc, addr); LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); - char notify[strlen(first_notify) + strlen(confUri)]; + size_t size = strlen(first_notify) + strlen(confUri); + char *notify = new char[size]; - snprintf(notify, sizeof(notify), first_notify, confUri); + snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); + delete[] notify; + BC_ASSERT_EQUAL(tester.participants.size(), 0, int, "%d"); BC_ASSERT_FALSE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); BC_ASSERT_FALSE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); @@ -523,21 +529,27 @@ void participant_added_parsing() { LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); LinphoneAddress *frankAddr = linphone_core_interpret_url(marie->lc, frankUri); - char notify[strlen(first_notify) + strlen(confUri)]; - char notify_added[strlen(participant_added_notify) + strlen(confUri)]; + size_t size = strlen(first_notify) + strlen(confUri); + char *notify = new char[size]; + size_t size2 = strlen(participant_added_notify) + strlen(confUri); + char *notify_added = new char[size2]; - snprintf(notify, sizeof(notify), first_notify, confUri); + snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); + delete[] notify; + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); BC_ASSERT_TRUE(!tester.participants.find(linphone_address_as_string(bobAddr))->second); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second); - snprintf(notify_added, sizeof(notify_added), participant_added_notify, confUri); + snprintf(notify_added, size2, participant_added_notify, confUri); tester.handler->notifyReceived(notify_added); + delete[] notify_added; + BC_ASSERT_EQUAL(tester.participants.size(), 3, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(frankAddr)) != tester.participants.end()); BC_ASSERT_TRUE(!tester.participants.find(linphone_address_as_string(frankAddr))->second); @@ -559,21 +571,27 @@ void participant_not_added_parsing() { LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); LinphoneAddress *frankAddr = linphone_core_interpret_url(marie->lc, frankUri); - char notify[strlen(first_notify) + strlen(confUri)]; - char notify_not_added[strlen(participant_not_added_notify) + strlen(confUri)]; + size_t size = strlen(first_notify) + strlen(confUri); + char *notify = new char[size]; + size_t size2 = strlen(participant_not_added_notify) + strlen(confUri); + char *notify_not_added = new char[size2]; - snprintf(notify, sizeof(notify), first_notify, confUri); + snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); + delete[] notify; + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); BC_ASSERT_TRUE(!tester.participants.find(linphone_address_as_string(bobAddr))->second); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second); - snprintf(notify_not_added, sizeof(notify_not_added), participant_not_added_notify, confUri); + snprintf(notify_not_added, size2, participant_not_added_notify, confUri); tester.handler->notifyReceived(notify_not_added); + delete[] notify_not_added; + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); BC_ASSERT_FALSE(tester.participants.find(linphone_address_as_string(frankAddr)) != tester.participants.end()); @@ -593,21 +611,27 @@ void participant_deleted_parsing() { ConferenceEventTester tester(marie->lc, addr); LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); - char notify[strlen(first_notify) + strlen(confUri)]; - char notify_deleted[strlen(participant_deleted_notify) + strlen(confUri)]; + size_t size = strlen(first_notify) + strlen(confUri); + char *notify = new char[size]; + size_t size2 = strlen(participant_deleted_notify) + strlen(confUri); + char *notify_deleted = new char[size2]; - snprintf(notify, sizeof(notify), first_notify, confUri); + snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); + delete[] notify; + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); BC_ASSERT_TRUE(!tester.participants.find(linphone_address_as_string(bobAddr))->second); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second); - snprintf(notify_deleted, sizeof(notify_deleted), participant_deleted_notify, confUri); + snprintf(notify_deleted, size2, participant_deleted_notify, confUri); tester.handler->notifyReceived(notify_deleted); + delete[] notify_deleted; + BC_ASSERT_EQUAL(tester.participants.size(), 1, int, "%d"); BC_ASSERT_FALSE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); @@ -626,21 +650,27 @@ void participant_admined_parsing() { ConferenceEventTester tester(marie->lc, addr); LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); - char notify[strlen(first_notify) + strlen(confUri)]; - char notify_admined[strlen(participant_admined_notify) + strlen(confUri)]; + size_t size = strlen(first_notify) + strlen(confUri); + char *notify = new char[size]; + size_t size2 = strlen(participant_admined_notify) + strlen(confUri); + char *notify_admined = new char[size2]; - snprintf(notify, sizeof(notify), first_notify, confUri); + snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); + delete[] notify; + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); BC_ASSERT_TRUE(!tester.participants.find(linphone_address_as_string(bobAddr))->second); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second); - snprintf(notify_admined, sizeof(notify_admined), participant_admined_notify, confUri); + snprintf(notify_admined, size2, participant_admined_notify, confUri); tester.handler->notifyReceived(notify_admined); + delete[] notify_admined; + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr))->second); @@ -660,21 +690,27 @@ void participant_unadmined_parsing() { ConferenceEventTester tester(marie->lc, addr); LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); - char notify[strlen(first_notify) + strlen(confUri)]; - char notify_unadmined[strlen(participant_unadmined_notify) + strlen(confUri)]; + size_t size = strlen(first_notify) + strlen(confUri); + char *notify = new char[size]; + size_t size2 = strlen(participant_unadmined_notify) + strlen(confUri); + char notify_unadmined[size2]; - snprintf(notify, sizeof(notify), first_notify, confUri); + snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); + delete[] notify; + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); BC_ASSERT_TRUE(!tester.participants.find(linphone_address_as_string(bobAddr))->second); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second); - snprintf(notify_unadmined, sizeof(notify_unadmined), participant_unadmined_notify, confUri); + snprintf(notify_unadmined, size2, participant_unadmined_notify, confUri); tester.handler->notifyReceived(notify_unadmined); + delete[] participant_unadmined_notify; + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); BC_ASSERT_TRUE(!tester.participants.find(linphone_address_as_string(aliceAddr))->second); From 15c417b86ce4934cdbbe1cc8931ef550b27dc3e7 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 28 Sep 2017 14:32:23 +0200 Subject: [PATCH 0219/2215] Add isMe() method to the conference. --- src/conference/conference.cpp | 8 +++++++- src/conference/conference.h | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 8e4214989..0bd79f1f8 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -149,7 +149,7 @@ void Conference::onResetFirstVideoFrameDecoded (const CallSession &session) { // ----------------------------------------------------------------------------- -shared_ptr Conference::findParticipant (const Address &addr) { +shared_ptr Conference::findParticipant (const Address &addr) const { for (const auto &participant : participants) { if (addr.equal(participant->getAddress())) return participant; @@ -157,4 +157,10 @@ shared_ptr Conference::findParticipant (const Address &addr) { return nullptr; } +bool Conference::isMe (const Address &addr) const { + Address cleanedAddress = me->getAddress(); + cleanedAddress.setPort(0); + return addr.equal(cleanedAddress); +} + LINPHONE_END_NAMESPACE diff --git a/src/conference/conference.h b/src/conference/conference.h index 955688757..403602459 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -76,7 +76,8 @@ private: protected: explicit Conference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); - std::shared_ptr findParticipant (const Address &addr); + std::shared_ptr findParticipant (const Address &addr) const; + bool isMe (const Address &addr) const ; protected: LinphoneCore *core = nullptr; From f44d76f30219f7f8b2def42da04c9d8fc3c0377d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 28 Sep 2017 14:32:49 +0200 Subject: [PATCH 0220/2215] When creating a conference package event, mark it as internal. --- coreapi/event.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/coreapi/event.c b/coreapi/event.c index d7a170822..00adff5ec 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -84,6 +84,8 @@ static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscri lev->dir=dir; lev->op=op; lev->name=ms_strdup(name); + if (strcmp(lev->name, "Conference") == 0) + lev->internal = TRUE; sal_op_set_user_pointer(lev->op,lev); return lev; } From 9178c1a57a9f66592d305e54698d0e2ad5d3f170 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 28 Sep 2017 14:33:39 +0200 Subject: [PATCH 0221/2215] Add a method to set the address of a participant. --- src/conference/participant-p.h | 3 ++- src/conference/participant.cpp | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/conference/participant-p.h b/src/conference/participant-p.h index 8d863a9eb..58d522a34 100644 --- a/src/conference/participant-p.h +++ b/src/conference/participant-p.h @@ -39,7 +39,8 @@ public: virtual ~ParticipantPrivate () = default; std::shared_ptr createSession (const Conference &conference, const CallSessionParams *params, bool hasMedia, CallSessionListener *listener); - std::shared_ptr getSession () const; + std::shared_ptr getSession () const { return session; } + void setAddress (const Address &newAddr) { addr = newAddr; } private: Address addr; diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index 128660977..31a25000d 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -38,10 +38,6 @@ shared_ptr ParticipantPrivate::createSession (const Conference &con return session; } -shared_ptr ParticipantPrivate::getSession () const { - return session; -} - // ============================================================================= Participant::Participant (const Address &addr) : Object(*new ParticipantPrivate) { From 7383a292518a946d831f2dbebde56206f5bb705a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 28 Sep 2017 14:34:49 +0200 Subject: [PATCH 0222/2215] Subscribe to the conference event package when a client group chat room enters the created state. --- coreapi/linphonecore.c | 6 ++-- src/chat/client-group-chat-room.cpp | 10 ++++++- .../local-conference-event-handler.cpp | 10 +++---- src/conference/local-conference.h | 5 ++-- .../remote-conference-event-handler.cpp | 30 +++++++++---------- .../remote-conference-event-handler.h | 5 ++-- src/conference/remote-conference.h | 5 ++-- tester/conference-event-tester.cpp | 1 - 8 files changed, 38 insertions(+), 34 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 2494d478a..01e1f72e1 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2115,10 +2115,8 @@ static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEve } else if (strcmp(notified_event, "Conference") == 0) { LinphonePrivate::RemoteConferenceEventHandler *handler = reinterpret_cast(linphone_event_get_user_data(lev)); - if (handler) { - ms_message("Notify event for conference %s", handler->getConfId().c_str()); - handler->notifyReceived((char *)linphone_content_get_buffer(body)); - } + if (handler) + handler->notifyReceived(reinterpret_cast(linphone_content_get_buffer(body))); } } diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index bbfdcad87..3357fc5f1 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -108,6 +108,7 @@ void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { L_D(); conferenceAddress = addr; d->setState(ChatRoom::State::Created); + eventHandler->subscribe(conferenceAddress); } void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { @@ -116,6 +117,8 @@ void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { } void ClientGroupChatRoom::onParticipantAdded (const Address &addr) { + if (isMe(addr)) + return; shared_ptr participant = findParticipant(addr); if (participant) { lWarning() << "Participant " << participant << " added but already in the list of participants!"; @@ -145,7 +148,11 @@ void ClientGroupChatRoom::onParticipantRemoved (const Address &addr) { } void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdmin) { - shared_ptr participant = findParticipant(addr); + shared_ptr participant = nullptr; + if (isMe(addr)) + participant = me; + else + participant = findParticipant(addr); if (!participant) { lWarning() << "Participant " << participant << " admin status has been changed but is not in the list of participants!"; return; @@ -163,6 +170,7 @@ void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdm void ClientGroupChatRoom::onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const string &message) { if (state == LinphoneCallConnected) { Address addr(session.getRemoteContact()); + addr.clean(); onConferenceCreated(addr); } } diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 4065dd089..7e94fc45c 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -84,7 +84,7 @@ LocalConferenceEventHandler::~LocalConferenceEventHandler() { string LocalConferenceEventHandler::subscribeReceived(LinphoneEvent *lev) { L_D(); - string entity = d->conf->getMe()->getAddress().asStringUriOnly(); + string entity = d->conf->getConferenceAddress()->asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -103,13 +103,13 @@ string LocalConferenceEventHandler::subscribeReceived(LinphoneEvent *lev) { stringstream notify; serializeConferenceInfo(notify, confInfo, map); - //d->notifyFullState(notify.str(), lev); + d->notifyFullState(notify.str(), lev); return notify.str(); } string LocalConferenceEventHandler::notifyParticipantAdded(const Address &addr) { L_D(); - string entity = d->conf->getMe()->getAddress().asStringUriOnly(); + string entity = d->conf->getConferenceAddress()->asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -131,7 +131,7 @@ string LocalConferenceEventHandler::notifyParticipantAdded(const Address &addr) string LocalConferenceEventHandler::notifyParticipantRemoved(const Address &addr) { L_D(); - string entity = d->conf->getMe()->getAddress().asStringUriOnly(); + string entity = d->conf->getConferenceAddress()->asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -150,7 +150,7 @@ string LocalConferenceEventHandler::notifyParticipantRemoved(const Address &addr string LocalConferenceEventHandler::notifyParticipantSetAdmin(const Address &addr, bool isAdmin) { L_D(); - string entity = d->conf->getMe()->getAddress().asStringUriOnly(); + string entity = d->conf->getConferenceAddress()->asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h index 41a032765..c36bf9064 100644 --- a/src/conference/local-conference.h +++ b/src/conference/local-conference.h @@ -40,10 +40,11 @@ public: std::list
    parseResourceLists (std::string xmlBody); +protected: + LocalConferenceEventHandler *eventHandler = nullptr; + private: L_DISABLE_COPY(LocalConference); - - LocalConferenceEventHandler *eventHandler = nullptr; }; LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 6365707dc..a24a5d947 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -17,6 +17,7 @@ */ #include "remote-conference-event-handler.h" +#include "logger/logger.h" #include "object/object-p.h" #include "private.h" @@ -35,8 +36,7 @@ class RemoteConferenceEventHandlerPrivate : public ObjectPrivate { public: LinphoneCore *core = nullptr; ConferenceListener *listener = nullptr; - Address confAddr; - string confId; + Address confAddress; LinphoneEvent *lev = nullptr; }; @@ -59,16 +59,16 @@ RemoteConferenceEventHandler::~RemoteConferenceEventHandler() { // ----------------------------------------------------------------------------- -void RemoteConferenceEventHandler::subscribe(string confId) { +void RemoteConferenceEventHandler::subscribe(const Address &addr) { L_D(); - d->confId = confId; - LinphoneAddress *addr = linphone_address_new(d->confAddr.asString().c_str()); - d->lev = linphone_core_create_subscribe(d->core, addr, "Conference", 600); - linphone_address_unref(addr); + d->confAddress = addr; + LinphoneAddress *lAddr = linphone_address_new(d->confAddress.asString().c_str()); + d->lev = linphone_core_create_subscribe(d->core, lAddr, "Conference", 600); + linphone_address_unref(lAddr); linphone_event_ref(d->lev); linphone_event_set_internal(d->lev, TRUE); linphone_event_set_user_data(d->lev, this); - linphone_event_add_custom_header(d->lev, "Conf-id", d->confId.c_str()); // TODO : ??? + linphone_event_add_custom_header(d->lev, "Conf-id", d->confAddress.getUsername().c_str()); // TODO : ??? linphone_event_send_subscribe(d->lev, nullptr); } @@ -79,9 +79,12 @@ void RemoteConferenceEventHandler::unsubscribe() { void RemoteConferenceEventHandler::notifyReceived(string xmlBody) { L_D(); + lInfo() << "NOTIFY received for conference " << d->confAddress.asString(); istringstream data(xmlBody); unique_ptr confInfo = parseConferenceInfo(data, Xsd::XmlSchema::Flags::dont_validate); - if (confInfo->getEntity() == d->confAddr.asString()) { + Address cleanedConfAddress = d->confAddress; + cleanedConfAddress.setPort(0); + if (confInfo->getEntity() == cleanedConfAddress.asString()) { for (const auto &user : confInfo->getUsers()->getUser()) { LinphoneAddress *cAddr = linphone_core_interpret_url(d->core, user.getEntity()->c_str()); Address addr(linphone_address_as_string(cAddr)); @@ -108,14 +111,9 @@ void RemoteConferenceEventHandler::notifyReceived(string xmlBody) { // ----------------------------------------------------------------------------- -string RemoteConferenceEventHandler::getConfId() { +const Address &RemoteConferenceEventHandler::getConfAddress() { L_D(); - return d->confId; -} - -void RemoteConferenceEventHandler::setConferenceAddress (const Address &addr) { - L_D(); - d->confAddr = addr; + return d->confAddress; } LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference-event-handler.h b/src/conference/remote-conference-event-handler.h index 6ea95adfd..73c16fd4f 100644 --- a/src/conference/remote-conference-event-handler.h +++ b/src/conference/remote-conference-event-handler.h @@ -35,12 +35,11 @@ class RemoteConferenceEventHandler : public Object { RemoteConferenceEventHandler(LinphoneCore *core, ConferenceListener *listener); ~RemoteConferenceEventHandler(); - void subscribe(std::string confId); + void subscribe(const Address &confAddress); void notifyReceived(std::string xmlBody); void unsubscribe(); - std::string getConfId(); - void setConferenceAddress (const Address &addr); + const Address &getConfAddress(); private: L_DECLARE_PRIVATE(RemoteConferenceEventHandler); diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index 8e7593320..c6eda721d 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -49,10 +49,11 @@ protected: void onParticipantRemoved (const Address &addr) override; void onParticipantSetAdmin (const Address &addr, bool isAdmin) override; +protected: + RemoteConferenceEventHandler *eventHandler = nullptr; + private: L_DISABLE_COPY(RemoteConference); - - RemoteConferenceEventHandler *eventHandler = nullptr; }; LINPHONE_END_NAMESPACE diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index 5aedeb447..5c428120c 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -438,7 +438,6 @@ public: ConferenceEventTester::ConferenceEventTester (LinphoneCore *core, const Address &confAddr) { handler = new RemoteConferenceEventHandler(core, this); - handler->setConferenceAddress(confAddr); } ConferenceEventTester::~ConferenceEventTester () { From 8ba35cf9dd6b0094153cb4dc35e9222fd9d1a74d Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 28 Sep 2017 14:41:52 +0200 Subject: [PATCH 0223/2215] fix(CMakeLists.txt): remove -g flag on Windows --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d01fc3f3..4b62ef95c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,7 +72,11 @@ if(NOT CMAKE_BUILD_TYPE) endif() set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG") -set(CMAKE_CXX_FLAGS_DEBUG "-g -DDEBUG") + +set(CMAKE_CXX_FLAGS_DEBUG "-DDEBUG") +if(NOT WIN32) + list(APPEND CMAKE_CXX_FLAGS_DEBUG "-g") +endif() if(ENABLE_STATIC) set(LINPHONE_LIBS_FOR_TOOLS linphone-static) From 85d930e540b8a25dbaf64087b85295463b13b566 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 28 Sep 2017 14:52:23 +0200 Subject: [PATCH 0224/2215] fix(CMakeLists.txt): add correctly DEBUG variable --- CMakeLists.txt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b62ef95c..febd61170 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,12 +70,8 @@ set(CMAKE_CXX_STANDARD 11) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release") endif() - -set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG") - -set(CMAKE_CXX_FLAGS_DEBUG "-DDEBUG") -if(NOT WIN32) - list(APPEND CMAKE_CXX_FLAGS_DEBUG "-g") +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + add_definitions("-DDEBUG") endif() if(ENABLE_STATIC) From 54d828c4d4dddf76d51323d1e646cc376f320c56 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 28 Sep 2017 14:52:52 +0200 Subject: [PATCH 0225/2215] fix(core): declare correctly get_nowebcam_device when video is not enabled --- coreapi/private.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/coreapi/private.h b/coreapi/private.h index b28d7bb86..67e886c52 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -1675,9 +1675,8 @@ void v_table_reference_destroy(VTableReference *ref); LINPHONE_PUBLIC void _linphone_core_add_callbacks(LinphoneCore *lc, LinphoneCoreCbs *vtable, bool_t internal); -#ifdef VIDEO_ENABLED MSWebCam *get_nowebcam_device(MSFactory *f); -#endif + LinphoneLimeState linphone_core_lime_for_file_sharing_enabled(const LinphoneCore *lc); BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneTunnelConfig); From 20703484ff3febfd72cee25aaa64ad7cdfbc9b97 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 28 Sep 2017 14:55:20 +0200 Subject: [PATCH 0226/2215] Fixes related to ChatRoom & ChatMessage --- src/c-wrapper/api/c-chat-message.cpp | 24 +++++++++++++----- src/c-wrapper/api/c-chat-room.cpp | 4 ++- src/chat/chat-message-p.h | 34 ++++++++++++------------- src/chat/chat-message.cpp | 25 +++++++++---------- src/chat/chat-message.h | 10 ++++---- src/chat/chat-room.cpp | 37 +++++++++++++--------------- 6 files changed, 72 insertions(+), 62 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 0695bb0f5..1b14f8829 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -94,7 +94,9 @@ LinphoneChatRoom *linphone_chat_message_get_chat_room(const LinphoneChatMessage } const char *linphone_chat_message_get_external_body_url(const LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getExternalBodyUrl().c_str(); + const string& external_body_url = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getExternalBodyUrl(); + if (external_body_url.empty()) return NULL; + return external_body_url.c_str(); } void linphone_chat_message_set_external_body_url(LinphoneChatMessage *msg, const char *url) { @@ -162,7 +164,9 @@ bool_t linphone_chat_message_is_read(LinphoneChatMessage *msg) { } const char *linphone_chat_message_get_appdata(const LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getAppdata().c_str(); + const string& appData = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getAppdata(); + if (appData.empty()) return NULL; + return appData.c_str(); } void linphone_chat_message_set_appdata(LinphoneChatMessage *msg, const char *data) { @@ -192,7 +196,9 @@ const LinphoneAddress *linphone_chat_message_get_to_address(LinphoneChatMessage } const char *linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFileTransferFilepath().c_str(); + const string& path = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFileTransferFilepath(); + if (path.empty()) return NULL; + return path.c_str(); } void linphone_chat_message_set_file_transfer_filepath(LinphoneChatMessage *msg, const char *filepath) { @@ -241,7 +247,9 @@ void linphone_chat_message_remove_custom_header(LinphoneChatMessage *msg, const } const char *linphone_chat_message_get_custom_header(LinphoneChatMessage *msg, const char *header_name) { - return L_GET_PRIVATE_FROM_C_OBJECT(msg)->getSalCustomHeaderValue(header_name).c_str(); + const string& header = L_GET_PRIVATE_FROM_C_OBJECT(msg)->getSalCustomHeaderValue(header_name); + if (header.empty()) return NULL; + return header.c_str(); } const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg) { @@ -321,7 +329,9 @@ void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChat // ============================================================================= const char * linphone_chat_message_get_content_type(const LinphoneChatMessage *msg) { - return L_GET_PRIVATE_FROM_C_OBJECT(msg)->getContentType().c_str(); + const string& contentType = L_GET_PRIVATE_FROM_C_OBJECT(msg)->getContentType(); + if (contentType.empty()) return NULL; + return contentType.c_str(); } void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char *content_type) { @@ -329,7 +339,9 @@ void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char } const char *linphone_chat_message_get_text(const LinphoneChatMessage *msg) { - return L_GET_PRIVATE_FROM_C_OBJECT(msg)->getText().c_str(); + const string& text = L_GET_PRIVATE_FROM_C_OBJECT(msg)->getText(); + if (text.empty()) return NULL; + return text.c_str(); } int linphone_chat_message_set_text(LinphoneChatMessage *msg, const char* text) { diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 02fd19102..8c3c6a8a5 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -72,7 +72,9 @@ void linphone_chat_room_remove_transient_message (LinphoneChatRoom *cr, Linphone } void linphone_chat_room_send_message (LinphoneChatRoom *cr, const char *msg) { - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createMessage(msg)); + LinphoneChatMessage *message = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createMessage(msg); + ms_error("%s / %s", linphone_chat_message_get_text(message), linphone_chat_message_get_content_type(message)); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(message); } bool_t linphone_chat_room_is_remote_composing (const LinphoneChatRoom *cr) { diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index fab4e79d9..f062be033 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -65,11 +65,11 @@ public: // Methods only used for C wrapper // ----------------------------------------------------------------------------- - std::string getContentType() const; - void setContentType(std::string contentType); + const std::string& getContentType() const; + void setContentType(const std::string& contentType); - std::string getText() const; - void setText(std::string text); + const std::string& getText() const; + void setText(const std::string& text); LinphoneContent * getFileTransferInformation() const; void setFileTransferInformation(LinphoneContent *content); @@ -104,11 +104,11 @@ private: std::shared_ptr
    from; std::shared_ptr
    to; time_t time = 0; - std::string id; - std::string appData; - std::string fileTransferFilePath; - std::string externalBodyUrl; - std::string rttMessage; + std::string id = ""; + std::string appData = ""; + std::string fileTransferFilePath = ""; + std::string externalBodyUrl = ""; + std::string rttMessage = ""; bool isSecured = false; bool isReadOnly = false; bool isToBeStored = false; @@ -116,16 +116,16 @@ private: std::shared_ptr internalContent; std::unordered_map customHeaders; std::shared_ptr eventsDb; - mutable LinphoneErrorInfo * errorInfo; - belle_http_request_t *httpRequest; - belle_http_request_listener_t *httpListener; - SalOp *salOp; - SalCustomHeader *salCustomHeaders; + mutable LinphoneErrorInfo * errorInfo = NULL; + belle_http_request_t *httpRequest = NULL; + belle_http_request_listener_t *httpListener = NULL; + SalOp *salOp = NULL; + SalCustomHeader *salCustomHeaders = NULL; unsigned long backgroundTaskId; // Used for compatibility with previous C API - std::string cContentType; - std::string cText; - LinphoneContent *cFileTransferInformation; + std::string cContentType = ""; + std::string cText = ""; + LinphoneContent *cFileTransferInformation = NULL; // ----------------------------------------------------------------------------- diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 6ad7fa3cc..65fb33b70 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -46,7 +46,8 @@ using namespace std; // ============================================================================= ChatMessagePrivate::ChatMessagePrivate (const shared_ptr &room) -: chatRoom(room) {} +: chatRoom(room) { +} ChatMessagePrivate::~ChatMessagePrivate () {} @@ -132,19 +133,19 @@ string ChatMessagePrivate::getSalCustomHeaderValue(string name) { // ----------------------------------------------------------------------------- -string ChatMessagePrivate::getContentType() const { +const string& ChatMessagePrivate::getContentType() const { return cContentType; } -void ChatMessagePrivate::setContentType(string contentType) { +void ChatMessagePrivate::setContentType(const string& contentType) { cContentType = contentType; } -string ChatMessagePrivate::getText() const { +const string& ChatMessagePrivate::getText() const { return cText; } -void ChatMessagePrivate::setText(string text) { +void ChatMessagePrivate::setText(const string& text) { cText = text; } @@ -876,7 +877,7 @@ shared_ptr ChatMessage::getChatRoom () const { // ----------------------------------------------------------------------------- -string ChatMessage::getExternalBodyUrl() const { +const string& ChatMessage::getExternalBodyUrl() const { L_D(); return d->externalBodyUrl; } @@ -921,12 +922,12 @@ ChatMessage::State ChatMessage::getState() const { return d->state; } -string ChatMessage::getId () const { +const string& ChatMessage::getId () const { L_D(); return d->id; } -void ChatMessage::setId (string id) { +void ChatMessage::setId (const string& id) { L_D(); d->id = id; } @@ -941,7 +942,7 @@ bool ChatMessage::isRead() const { return d->state == Delivered || d->state == Displayed || d->state == DeliveredToUser; } -string ChatMessage::getAppdata () const { +const string& ChatMessage::getAppdata () const { L_D(); return d->appData; } @@ -972,7 +973,7 @@ void ChatMessage::setToAddress(shared_ptr
    to) { d->to = to; } -string ChatMessage::getFileTransferFilepath() const { +const string& ChatMessage::getFileTransferFilepath() const { L_D(); return d->fileTransferFilePath; } @@ -1035,7 +1036,7 @@ string ChatMessage::getCustomHeaderValue (const string &headerName) const { } catch (const exception &) { // Key doesn't exist. } - return ""; + return nullptr; } void ChatMessage::addCustomHeader (const string &headerName, const string &headerValue) { @@ -1080,8 +1081,6 @@ void ChatMessage::send () { ccmm.encode(d); } - // TODO. - d->isReadOnly = true; } diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index bf0ec5a29..153bab0aa 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -87,7 +87,7 @@ public: bool isOutgoing () const; bool isIncoming () const; - std::string getExternalBodyUrl() const; + const std::string& getExternalBodyUrl() const; void setExternalBodyUrl(const std::string &url); time_t getTime () const; @@ -97,12 +97,12 @@ public: State getState() const; - std::string getId () const; - void setId (std::string); + const std::string& getId () const; + void setId (const std::string&); bool isRead() const; - std::string getAppdata () const; + const std::string& getAppdata () const; void setAppdata (const std::string &appData); std::shared_ptr
    getFromAddress () const; @@ -111,7 +111,7 @@ public: std::shared_ptr
    getToAddress () const; void setToAddress(std::shared_ptr
    to); - std::string getFileTransferFilepath() const; + const std::string& getFileTransferFilepath() const; void setFileTransferFilepath(const std::string &path); bool isToBeStored() const; diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 2cd001716..8557d2fb1 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -27,7 +27,7 @@ #include "imdn.h" #include "logger/logger.h" -#include "chat-message.h" +#include "chat-message-p.h" #include "chat-room.h" // ============================================================================= @@ -592,31 +592,28 @@ void ChatRoom::compose () { LinphoneChatMessage *ChatRoom::createFileTransferMessage (const LinphoneContent *initialContent) { L_D(); - LinphoneChatMessage *msg = createMessage(""); - linphone_chat_message_set_text(msg, NULL); - linphone_chat_message_set_file_transfer_information(msg, linphone_content_copy(initialContent)); - linphone_chat_message_set_outgoing(msg); - LinphoneAddress *peer = linphone_address_new(d->peerAddress.asString().c_str()); - linphone_chat_message_set_to_address(msg, peer); - linphone_address_unref(peer); - linphone_chat_message_set_from_address(msg, linphone_address_new(linphone_core_get_identity(d->core))); - /* This will be set to application/vnd.gsma.rcs-ft-http+xml when we will transfer the xml reply from server to the peers */ - linphone_chat_message_set_content_type(msg, NULL); - /* This will store the http request during file upload to the server */ - linphone_chat_message_set_http_request(msg, NULL); - linphone_chat_message_set_time(msg, ms_time(0)); + + shared_ptr chatMessage = make_shared(static_pointer_cast(shared_from_this())); + + chatMessage->getPrivate()->setTime(ms_time(0)); + chatMessage->getPrivate()->setContentType("text/plain"); + chatMessage->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); + chatMessage->getPrivate()->setFileTransferInformation(linphone_content_copy(initialContent)); + chatMessage->setToAddress(make_shared
    (d->peerAddress.asString().c_str())); + chatMessage->setFromAddress(make_shared
    (linphone_core_get_identity(d->core))); + + LinphoneChatMessage *msg = chatMessage->getBackPtr(); return msg; } LinphoneChatMessage *ChatRoom::createMessage (const string &message) { shared_ptr chatMessage = make_shared(static_pointer_cast(shared_from_this())); + + chatMessage->getPrivate()->setTime(ms_time(0)); + chatMessage->getPrivate()->setContentType("text/plain"); + chatMessage->getPrivate()->setText(message); + LinphoneChatMessage *msg = chatMessage->getBackPtr(); - linphone_chat_message_set_state(msg, LinphoneChatMessageStateIdle); - linphone_chat_message_set_text(msg, message.empty() ? nullptr : ms_strdup(message.c_str())); - linphone_chat_message_set_content_type(msg, ms_strdup("text/plain")); - linphone_chat_message_set_file_transfer_information(msg, nullptr); - linphone_chat_message_set_http_request(msg, NULL); - linphone_chat_message_set_time(msg, ms_time(0)); return msg; } From 5605c66085c7c80f798cdd291badd6c5a1a5678d Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 28 Sep 2017 15:17:15 +0200 Subject: [PATCH 0227/2215] fix(ConferenceEventTester): fix test on Windows --- tester/conference-event-tester.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index 5c428120c..19e392046 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -692,7 +692,7 @@ void participant_unadmined_parsing() { size_t size = strlen(first_notify) + strlen(confUri); char *notify = new char[size]; size_t size2 = strlen(participant_unadmined_notify) + strlen(confUri); - char notify_unadmined[size2]; + char *notify_unadmined = new char[size2]; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -708,7 +708,7 @@ void participant_unadmined_parsing() { snprintf(notify_unadmined, size2, participant_unadmined_notify, confUri); tester.handler->notifyReceived(notify_unadmined); - delete[] participant_unadmined_notify; + delete[] notify_unadmined; BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); From 9750a40c34b8f82ac00b103e09d0994da02220df Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 28 Sep 2017 15:25:14 +0200 Subject: [PATCH 0228/2215] Use macro instead of checking if string is empty manually... --- src/c-wrapper/api/c-chat-message.cpp | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 1b14f8829..06546dd35 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -90,13 +90,13 @@ LinphoneChatMessageCbs *linphone_chat_message_get_callbacks(const LinphoneChatMe // ============================================================================= LinphoneChatRoom *linphone_chat_message_get_chat_room(const LinphoneChatMessage *msg) { - return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getChatRoom()); + shared_ptr message = L_GET_CPP_PTR_FROM_C_OBJECT(msg); + shared_ptr room = message->getChatRoom(); + return L_GET_C_BACK_PTR(room); } const char *linphone_chat_message_get_external_body_url(const LinphoneChatMessage *msg) { - const string& external_body_url = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getExternalBodyUrl(); - if (external_body_url.empty()) return NULL; - return external_body_url.c_str(); + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getExternalBodyUrl()); } void linphone_chat_message_set_external_body_url(LinphoneChatMessage *msg, const char *url) { @@ -164,9 +164,7 @@ bool_t linphone_chat_message_is_read(LinphoneChatMessage *msg) { } const char *linphone_chat_message_get_appdata(const LinphoneChatMessage *msg) { - const string& appData = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getAppdata(); - if (appData.empty()) return NULL; - return appData.c_str(); + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getAppdata()); } void linphone_chat_message_set_appdata(LinphoneChatMessage *msg, const char *data) { @@ -196,9 +194,7 @@ const LinphoneAddress *linphone_chat_message_get_to_address(LinphoneChatMessage } const char *linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage *msg) { - const string& path = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFileTransferFilepath(); - if (path.empty()) return NULL; - return path.c_str(); + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFileTransferFilepath()); } void linphone_chat_message_set_file_transfer_filepath(LinphoneChatMessage *msg, const char *filepath) { @@ -247,9 +243,7 @@ void linphone_chat_message_remove_custom_header(LinphoneChatMessage *msg, const } const char *linphone_chat_message_get_custom_header(LinphoneChatMessage *msg, const char *header_name) { - const string& header = L_GET_PRIVATE_FROM_C_OBJECT(msg)->getSalCustomHeaderValue(header_name); - if (header.empty()) return NULL; - return header.c_str(); + return L_STRING_TO_C(L_GET_PRIVATE_FROM_C_OBJECT(msg)->getSalCustomHeaderValue(header_name)); } const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg) { @@ -329,9 +323,7 @@ void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChat // ============================================================================= const char * linphone_chat_message_get_content_type(const LinphoneChatMessage *msg) { - const string& contentType = L_GET_PRIVATE_FROM_C_OBJECT(msg)->getContentType(); - if (contentType.empty()) return NULL; - return contentType.c_str(); + return L_STRING_TO_C(L_GET_PRIVATE_FROM_C_OBJECT(msg)->getContentType()); } void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char *content_type) { @@ -339,9 +331,7 @@ void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char } const char *linphone_chat_message_get_text(const LinphoneChatMessage *msg) { - const string& text = L_GET_PRIVATE_FROM_C_OBJECT(msg)->getText(); - if (text.empty()) return NULL; - return text.c_str(); + return L_STRING_TO_C(L_GET_PRIVATE_FROM_C_OBJECT(msg)->getText()); } int linphone_chat_message_set_text(LinphoneChatMessage *msg, const char* text) { From 7e55f79924f8d82d78c283fa81a6de95ded728ae Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 28 Sep 2017 15:28:20 +0200 Subject: [PATCH 0229/2215] Check if given shared_ptr is null in getCBackPtr --- src/c-wrapper/internal/c-tools.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 5e371372d..eb2348975 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -244,6 +244,8 @@ public: static inline typename CppTypeMetaInfo::cType *getCBackPtr (const std::shared_ptr &cppObject) { typedef typename CppTypeMetaInfo::cType RetType; + if (!cppObject) return nullptr; + Variant variant = cppObject->getProperty("LinphonePrivate::Wrapper::cBackPtr"); void *value = variant.getValue(); if (value) @@ -259,6 +261,7 @@ public: typename = typename std::enable_if::value, CppType>::type > static inline typename CppTypeMetaInfo::cType *getCBackPtr (CppType *cppObject) { + if (!cppObject) return nullptr; try { return getCBackPtr(std::static_pointer_cast(cppObject->shared_from_this())); } catch (const std::bad_weak_ptr &e) { @@ -275,6 +278,7 @@ public: > static inline typename CppTypeMetaInfo::cType *getCBackPtr (const CppType *cppObject) { typedef typename CppTypeMetaInfo::cType RetType; + if (!cppObject) return nullptr; Variant variant = cppObject->getProperty("LinphonePrivate::Wrapper::cBackPtr"); void *value = variant.getValue(); From 18643634a73ef518b6f71121d8b7014631039762 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 28 Sep 2017 15:31:02 +0200 Subject: [PATCH 0230/2215] Remove log commited by mistake --- src/c-wrapper/api/c-chat-room.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 8c3c6a8a5..f3ea4571d 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -73,7 +73,6 @@ void linphone_chat_room_remove_transient_message (LinphoneChatRoom *cr, Linphone void linphone_chat_room_send_message (LinphoneChatRoom *cr, const char *msg) { LinphoneChatMessage *message = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createMessage(msg); - ms_error("%s / %s", linphone_chat_message_get_text(message), linphone_chat_message_get_content_type(message)); L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(message); } From 5e80df36faf652c6e8d4c21dae224e91ff117c4e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 28 Sep 2017 15:31:29 +0200 Subject: [PATCH 0231/2215] Fix memory leaks. --- coreapi/proxy.c | 2 ++ src/c-wrapper/api/c-address.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 8268edff6..a74eefa0b 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -248,6 +248,8 @@ void _linphone_proxy_config_destroy(LinphoneProxyConfig *cfg){ } if (cfg->contact_address) linphone_address_unref(cfg->contact_address); + if (cfg->contact_address_without_params) + linphone_address_unref(cfg->contact_address_without_params); _linphone_proxy_config_release_ops(cfg); } diff --git a/src/c-wrapper/api/c-address.cpp b/src/c-wrapper/api/c-address.cpp index e258d888a..f4a38b414 100644 --- a/src/c-wrapper/api/c-address.cpp +++ b/src/c-wrapper/api/c-address.cpp @@ -36,6 +36,7 @@ LinphoneAddress *linphone_address_new (const char *address) { LinphoneAddress *object = L_INIT(Address); L_SET_CPP_PTR_FROM_C_OBJECT(object, cppPtr); + delete cppPtr; return object; } From e783a88a3121a671b298ad70fae1576ed4e92974 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 28 Sep 2017 15:33:46 +0200 Subject: [PATCH 0232/2215] feat(c-wrapper): little optimization on getCBackPtr --- src/c-wrapper/internal/c-tools.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index eb2348975..0a5c0eff9 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -244,7 +244,8 @@ public: static inline typename CppTypeMetaInfo::cType *getCBackPtr (const std::shared_ptr &cppObject) { typedef typename CppTypeMetaInfo::cType RetType; - if (!cppObject) return nullptr; + if (L_UNLIKELY(!cppObject)) + return nullptr; Variant variant = cppObject->getProperty("LinphonePrivate::Wrapper::cBackPtr"); void *value = variant.getValue(); @@ -261,7 +262,9 @@ public: typename = typename std::enable_if::value, CppType>::type > static inline typename CppTypeMetaInfo::cType *getCBackPtr (CppType *cppObject) { - if (!cppObject) return nullptr; + if (L_UNLIKELY(!cppObject)) + return nullptr; + try { return getCBackPtr(std::static_pointer_cast(cppObject->shared_from_this())); } catch (const std::bad_weak_ptr &e) { @@ -277,8 +280,10 @@ public: typename = typename std::enable_if::value, CppType>::type > static inline typename CppTypeMetaInfo::cType *getCBackPtr (const CppType *cppObject) { + if (L_UNLIKELY(!cppObject)) + return nullptr; + typedef typename CppTypeMetaInfo::cType RetType; - if (!cppObject) return nullptr; Variant variant = cppObject->getProperty("LinphonePrivate::Wrapper::cBackPtr"); void *value = variant.getValue(); From 4029e83de77b5c82a8ca6512a43b5f8be48e619f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 28 Sep 2017 15:52:31 +0200 Subject: [PATCH 0233/2215] Use string conversion macros. --- src/c-wrapper/api/c-call-params.cpp | 25 ++++++++++-------------- src/c-wrapper/api/c-call.cpp | 7 +++---- src/c-wrapper/api/c-chat-room.cpp | 4 ++-- src/conference/session/media-session.cpp | 6 +++--- 4 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index e4415fb73..1750d14e4 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -90,15 +90,15 @@ void linphone_call_params_set_custom_sdp_media_attributes (LinphoneCallParams *p // ============================================================================= void linphone_call_params_add_custom_header (LinphoneCallParams *params, const char *header_name, const char *header_value) { - L_GET_CPP_PTR_FROM_C_OBJECT(params)->addCustomHeader(header_name, header_value); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->addCustomHeader(header_name, L_C_TO_STRING(header_value)); } void linphone_call_params_add_custom_sdp_attribute (LinphoneCallParams *params, const char *attribute_name, const char *attribute_value) { - L_GET_CPP_PTR_FROM_C_OBJECT(params)->addCustomSdpAttribute(attribute_name, attribute_value); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->addCustomSdpAttribute(attribute_name, L_C_TO_STRING(attribute_value)); } void linphone_call_params_add_custom_sdp_media_attribute (LinphoneCallParams *params, LinphoneStreamType type, const char *attribute_name, const char *attribute_value) { - L_GET_CPP_PTR_FROM_C_OBJECT(params)->addCustomSdpMediaAttribute(type, attribute_name, attribute_value); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->addCustomSdpMediaAttribute(type, attribute_name, L_C_TO_STRING(attribute_value)); } void linphone_call_params_clear_custom_sdp_attributes (LinphoneCallParams *params) { @@ -139,18 +139,15 @@ void linphone_call_params_enable_video (LinphoneCallParams *params, bool_t enabl } const char *linphone_call_params_get_custom_header (const LinphoneCallParams *params, const char *header_name) { - string value = L_GET_CPP_PTR_FROM_C_OBJECT(params)->getCustomHeader(header_name); - return value.empty() ? nullptr : value.c_str(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getCustomHeader(header_name); } const char *linphone_call_params_get_custom_sdp_attribute (const LinphoneCallParams *params, const char *attribute_name) { - string value = L_GET_CPP_PTR_FROM_C_OBJECT(params)->getCustomSdpAttribute(attribute_name); - return value.empty() ? nullptr : value.c_str(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getCustomSdpAttribute(attribute_name); } const char *linphone_call_params_get_custom_sdp_media_attribute (const LinphoneCallParams *params, LinphoneStreamType type, const char *attribute_name) { - string value = L_GET_CPP_PTR_FROM_C_OBJECT(params)->getCustomSdpMediaAttribute(type, attribute_name); - return value.empty() ? nullptr : value.c_str(); + return L_GET_CPP_PTR_FROM_C_OBJECT(params)->getCustomSdpMediaAttribute(type, attribute_name); } bool_t linphone_call_params_get_local_conference_mode (const LinphoneCallParams *params) { @@ -187,8 +184,7 @@ const LinphoneVideoDefinition *linphone_call_params_get_received_video_definitio } const char *linphone_call_params_get_record_file (const LinphoneCallParams *params) { - const string &value = L_GET_CPP_PTR_FROM_C_OBJECT(params)->getRecordFilePath(); - return value.empty() ? nullptr : value.c_str(); + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(params)->getRecordFilePath()); } const char *linphone_call_params_get_rtp_profile (const LinphoneCallParams *params) { @@ -217,8 +213,7 @@ const LinphoneVideoDefinition *linphone_call_params_get_sent_video_definition (c } const char *linphone_call_params_get_session_name (const LinphoneCallParams *params) { - const string &value = L_GET_CPP_PTR_FROM_C_OBJECT(params)->getSessionName(); - return value.empty() ? nullptr : value.c_str(); + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(params)->getSessionName()); } LinphonePayloadType *linphone_call_params_get_used_audio_payload_type (const LinphoneCallParams *params) { @@ -278,11 +273,11 @@ void linphone_call_params_set_privacy (LinphoneCallParams *params, LinphonePriva } void linphone_call_params_set_record_file (LinphoneCallParams *params, const char *path) { - L_GET_CPP_PTR_FROM_C_OBJECT(params)->setRecordFilePath(path ? path : ""); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->setRecordFilePath(L_C_TO_STRING(path)); } void linphone_call_params_set_session_name (LinphoneCallParams *params, const char *name) { - L_GET_CPP_PTR_FROM_C_OBJECT(params)->setSessionName(name ? name : ""); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->setSessionName(L_C_TO_STRING(name)); } bool_t linphone_call_params_audio_enabled (const LinphoneCallParams *params) { diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 3a398b8fb..3f49beeca 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -708,11 +708,11 @@ bool_t linphone_call_camera_enabled (const LinphoneCall *call) { } LinphoneStatus linphone_call_take_video_snapshot (LinphoneCall *call, const char *file) { - return L_GET_CPP_PTR_FROM_C_OBJECT(call)->takeVideoSnapshot(file ? file : ""); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->takeVideoSnapshot(L_C_TO_STRING(file)); } LinphoneStatus linphone_call_take_preview_snapshot (LinphoneCall *call, const char *file) { - return L_GET_CPP_PTR_FROM_C_OBJECT(call)->takePreviewSnapshot(file ? file : ""); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->takePreviewSnapshot(L_C_TO_STRING(file)); } LinphoneReason linphone_call_get_reason (const LinphoneCall *call) { @@ -745,8 +745,7 @@ const char * linphone_call_get_remote_contact (LinphoneCall *call) { } const char *linphone_call_get_authentication_token (LinphoneCall *call) { - string token = L_GET_CPP_PTR_FROM_C_OBJECT(call)->getAuthenticationToken(); - return token.empty() ? nullptr : token.c_str(); + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(call)->getAuthenticationToken()); } bool_t linphone_call_get_authentication_token_verified (const LinphoneCall *call) { diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index f3ea4571d..251e560d6 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -97,7 +97,7 @@ const LinphoneAddress *linphone_chat_room_get_peer_address (LinphoneChatRoom *cr } LinphoneChatMessage *linphone_chat_room_create_message (LinphoneChatRoom *cr, const char *message) { - return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createMessage(message ? message : ""); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createMessage(L_C_TO_STRING(message)); } LinphoneChatMessage *linphone_chat_room_create_message_2 ( @@ -304,7 +304,7 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, cons from = linphone_core_get_primary_contact(core); LinphonePrivate::Address me(from); LinphoneChatRoom *cr = L_INIT(ChatRoom); - L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared(core, me, subject ? subject : "")); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared(core, me, L_C_TO_STRING(subject))); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); return cr; } diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 08e362a92..3b2c377ae 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -2552,8 +2552,8 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool MSSndCard *captcard = core->sound_conf.capt_sndcard; if (!captcard) lWarning() << "No card defined for capture!"; - string playfile = core->play_file ? core->play_file : ""; - string recfile = core->rec_file ? core->rec_file : ""; + string playfile = L_C_TO_STRING(core->play_file); + string recfile = L_C_TO_STRING(core->rec_file); /* Don't use file or soundcard capture when placed in recv-only mode */ if ((stream->rtp_port == 0) || (stream->dir == SalStreamRecvOnly) || ((stream->multicast_role == SalMulticastReceiver) && isMulticast)) { captcard = nullptr; @@ -3106,7 +3106,7 @@ void MediaSessionPrivate::updateFrozenPayloads (SalMediaDescription *result) { /* New codec, needs to be added to the list */ localDesc->streams[i].already_assigned_payloads = bctbx_list_append(localDesc->streams[i].already_assigned_payloads, payload_type_clone(pt)); lInfo() << "CallSession[" << q << "] : payload type " << payload_type_get_number(pt) << " " << pt->mime_type << "/" << pt->clock_rate - << " fmtp=" << (pt->recv_fmtp ? pt->recv_fmtp : "") << " added to frozen list"; + << " fmtp=" << L_C_TO_STRING(pt->recv_fmtp) << " added to frozen list"; } } } From 99f2adb9409ea1991f03008e089df5bca0cf90c6 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 28 Sep 2017 15:59:08 +0200 Subject: [PATCH 0234/2215] feat(General): provide L_LIKELY and L_UNLIKELY macros (__builtin_expect) --- include/linphone/utils/general.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index cfba622c7..82bcf68b0 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -71,6 +71,9 @@ void l_assert (const char *condition, const char *file, int line); #define L_ASSERT(CONDITION) ((CONDITION) ? static_cast(0) : LINPHONE_NAMESPACE::l_assert(#CONDITION, __FILE__, __LINE__)) #endif +#define L_LIKELY(EXPRESSION) __builtin_expect(static_cast(EXPRESSION), true) +#define L_UNLIKELY(EXPRESSION) __builtin_expect(static_cast(EXPRESSION), false) + // Allows access to private internal data. // Gives a control to C Wrapper. #define L_DECLARE_PRIVATE(CLASS) \ From 723267630ee9bedd1011cfd65e034759240f6856 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 28 Sep 2017 16:00:46 +0200 Subject: [PATCH 0235/2215] Fix issue in log --- src/chat/chat-message.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 65fb33b70..612f983bf 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -73,7 +73,7 @@ void ChatMessagePrivate::setState(ChatMessage::State s) { && ((s == ChatMessage::State::DeliveredToUser) || (s == ChatMessage::State::Delivered) || (s == ChatMessage::State::NotDelivered))) { return; } - ms_message("Chat message %p: moving from state %s to %s", this, linphone_chat_message_state_to_string((LinphoneChatMessageState)s), linphone_chat_message_state_to_string((LinphoneChatMessageState)state)); + ms_message("Chat message %p: moving from state %s to %s", this, linphone_chat_message_state_to_string((LinphoneChatMessageState)state), linphone_chat_message_state_to_string((LinphoneChatMessageState)s)); state = s; LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); From b9f9dc1c5b78e5f67be74e197071ee83d103388c Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 28 Sep 2017 16:09:11 +0200 Subject: [PATCH 0236/2215] fix(core): clean a lot of C4800 errors on Windows --- coreapi/callbacks.c | 2 +- src/address/address.cpp | 10 ++-- src/c-wrapper/api/c-address.cpp | 2 +- src/c-wrapper/api/c-call-params.cpp | 28 +++++----- src/c-wrapper/api/c-call.cpp | 10 ++-- src/c-wrapper/api/c-chat-message.cpp | 4 +- src/c-wrapper/api/c-participant.cpp | 2 +- .../params/media-session-params.cpp | 14 ++--- src/conference/session/call-session.cpp | 2 +- src/conference/session/media-session.cpp | 55 +++++++++---------- src/nat/ice-agent.cpp | 16 +++--- src/nat/ice-agent.h | 2 +- 12 files changed, 73 insertions(+), 74 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 0683b28e9..e52a3199e 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -227,7 +227,7 @@ static void call_updating(SalOp *op, bool_t is_update) { ms_warning("call_updating: CallSession no longer exists"); return; } - L_GET_PRIVATE(session)->updating(is_update); + L_GET_PRIVATE(session)->updating(!!is_update); } diff --git a/src/address/address.cpp b/src/address/address.cpp index a173c63c0..e6c52dc0d 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -73,7 +73,7 @@ bool Address::operator< (const Address &address) const { bool Address::isValid () const { L_D(); - return static_cast(d->internalAddress); + d->internalAddress; } const string &Address::getScheme () const { @@ -162,7 +162,7 @@ bool Address::setTransport (Transport transport) { bool Address::getSecure () const { L_D(); - return d->internalAddress ? sal_address_is_secure(d->internalAddress) : false; + return d->internalAddress && sal_address_is_secure(d->internalAddress); } bool Address::setSecure (bool enabled) { @@ -177,7 +177,7 @@ bool Address::setSecure (bool enabled) { bool Address::isSip () const { L_D(); - return d->internalAddress ? sal_address_is_sip(d->internalAddress) : false; + return d->internalAddress && sal_address_is_sip(d->internalAddress); } const string &Address::getMethodParam () const { @@ -280,7 +280,7 @@ bool Address::setHeader (const string &headerName, const string &headerValue) { bool Address::hasParam (const string ¶mName) const { L_D(); - return sal_address_has_param(d->internalAddress, L_STRING_TO_C(paramName)); + return !!sal_address_has_param(d->internalAddress, L_STRING_TO_C(paramName)); } const string &Address::getParamValue (const string ¶mName) const { @@ -317,7 +317,7 @@ bool Address::setParams (const string ¶ms) { bool Address::hasUriParam (const string &uriParamName) const { L_D(); - return sal_address_has_uri_param(d->internalAddress, L_STRING_TO_C(uriParamName)); + return !!sal_address_has_uri_param(d->internalAddress, L_STRING_TO_C(uriParamName)); } const string &Address::getUriParamValue (const string &uriParamName) const { diff --git a/src/c-wrapper/api/c-address.cpp b/src/c-wrapper/api/c-address.cpp index f4a38b414..c144d0da8 100644 --- a/src/c-wrapper/api/c-address.cpp +++ b/src/c-wrapper/api/c-address.cpp @@ -102,7 +102,7 @@ bool_t linphone_address_get_secure (const LinphoneAddress *address) { } void linphone_address_set_secure (LinphoneAddress *address, bool_t enabled) { - L_GET_CPP_PTR_FROM_C_OBJECT(address)->setSecure(enabled); + L_GET_CPP_PTR_FROM_C_OBJECT(address)->setSecure(!!enabled); } bool_t linphone_address_is_sip (const LinphoneAddress *address) { diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index 1750d14e4..cec561f98 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -118,24 +118,24 @@ bool_t linphone_call_params_early_media_sending_enabled (const LinphoneCallParam } void linphone_call_params_enable_early_media_sending (LinphoneCallParams *params, bool_t enabled) { - L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableEarlyMediaSending(enabled); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableEarlyMediaSending(!!enabled); } void linphone_call_params_enable_low_bandwidth (LinphoneCallParams *params, bool_t enabled) { - L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableLowBandwidth(enabled); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableLowBandwidth(!!enabled); } void linphone_call_params_enable_audio (LinphoneCallParams *params, bool_t enabled) { - L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableAudio(enabled); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableAudio(!!enabled); } LinphoneStatus linphone_call_params_enable_realtime_text (LinphoneCallParams *params, bool_t yesno) { - L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableRealtimeText(yesno); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableRealtimeText(!!yesno); return 0; } void linphone_call_params_enable_video (LinphoneCallParams *params, bool_t enabled) { - L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableVideo(enabled); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableVideo(!!enabled); } const char *linphone_call_params_get_custom_header (const LinphoneCallParams *params, const char *header_name) { @@ -309,7 +309,7 @@ void linphone_call_params_set_video_direction (LinphoneCallParams *params, Linph } void linphone_call_params_enable_audio_multicast (LinphoneCallParams *params, bool_t yesno) { - L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableAudioMulticast(yesno); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableAudioMulticast(!!yesno); } bool_t linphone_call_params_audio_multicast_enabled (const LinphoneCallParams *params) { @@ -317,7 +317,7 @@ bool_t linphone_call_params_audio_multicast_enabled (const LinphoneCallParams *p } void linphone_call_params_enable_video_multicast (LinphoneCallParams *params, bool_t yesno) { - L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableVideoMulticast(yesno); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableVideoMulticast(!!yesno); } bool_t linphone_call_params_video_multicast_enabled (const LinphoneCallParams *params) { @@ -333,7 +333,7 @@ bool_t linphone_call_params_avpf_enabled (const LinphoneCallParams *params) { } void linphone_call_params_enable_avpf (LinphoneCallParams *params, bool_t enable) { - L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableAvpf(enable); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableAvpf(!!enable); } bool_t linphone_call_params_mandatory_media_encryption_enabled (const LinphoneCallParams *params) { @@ -341,7 +341,7 @@ bool_t linphone_call_params_mandatory_media_encryption_enabled (const LinphoneCa } void linphone_call_params_enable_mandatory_media_encryption (LinphoneCallParams *params, bool_t value) { - L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableMandatoryMediaEncryption(value); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->enableMandatoryMediaEncryption(!!value); } uint16_t linphone_call_params_get_avpf_rr_interval (const LinphoneCallParams *params) { @@ -369,7 +369,7 @@ bool_t linphone_call_params_get_in_conference (const LinphoneCallParams *params) } void linphone_call_params_set_in_conference (LinphoneCallParams *params, bool_t value) { - L_GET_PRIVATE_FROM_C_OBJECT(params)->setInConference(value); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setInConference(!!value); } bool_t linphone_call_params_get_internal_call_update (const LinphoneCallParams *params) { @@ -377,7 +377,7 @@ bool_t linphone_call_params_get_internal_call_update (const LinphoneCallParams * } void linphone_call_params_set_internal_call_update (LinphoneCallParams *params, bool_t value) { - L_GET_PRIVATE_FROM_C_OBJECT(params)->setInternalCallUpdate(value); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setInternalCallUpdate(!!value); } bool_t linphone_call_params_implicit_rtcp_fb_enabled (const LinphoneCallParams *params) { @@ -385,7 +385,7 @@ bool_t linphone_call_params_implicit_rtcp_fb_enabled (const LinphoneCallParams * } void linphone_call_params_enable_implicit_rtcp_fb (LinphoneCallParams *params, bool_t value) { - L_GET_PRIVATE_FROM_C_OBJECT(params)->enableImplicitRtcpFb(value); + L_GET_PRIVATE_FROM_C_OBJECT(params)->enableImplicitRtcpFb(!!value); } int linphone_call_params_get_down_bandwidth (const LinphoneCallParams *params) { @@ -445,7 +445,7 @@ bool_t linphone_call_params_get_update_call_when_ice_completed (const LinphoneCa } void linphone_call_params_set_update_call_when_ice_completed (LinphoneCallParams *params, bool_t value) { - L_GET_PRIVATE_FROM_C_OBJECT(params)->setUpdateCallWhenIceCompleted(value); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setUpdateCallWhenIceCompleted(!!value); } void linphone_call_params_set_sent_vsize (LinphoneCallParams *params, MSVideoSize vsize) { @@ -469,7 +469,7 @@ bool_t linphone_call_params_get_no_user_consent (const LinphoneCallParams *param } void linphone_call_params_set_no_user_consent (LinphoneCallParams *params, bool_t value) { - L_GET_PRIVATE_FROM_C_OBJECT(params)->setNoUserConsent(value); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setNoUserConsent(!!value); } // ============================================================================= diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 3f49beeca..a14f73f65 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -528,7 +528,7 @@ bool_t linphone_call_get_audio_muted (const LinphoneCall *call) { } void linphone_call_set_audio_muted (LinphoneCall *call, bool_t value) { - L_GET_PRIVATE_FROM_C_OBJECT(call)->setAudioMuted(value); + L_GET_PRIVATE_FROM_C_OBJECT(call)->setAudioMuted(!!value); } bool_t linphone_call_get_all_muted (const LinphoneCall *call) { @@ -700,7 +700,7 @@ const LinphoneCallParams *linphone_call_get_remote_params(LinphoneCall *call) { } void linphone_call_enable_camera (LinphoneCall *call, bool_t enable) { - L_GET_CPP_PTR_FROM_C_OBJECT(call)->enableCamera(enable); + L_GET_CPP_PTR_FROM_C_OBJECT(call)->enableCamera(!!enable); } bool_t linphone_call_camera_enabled (const LinphoneCall *call) { @@ -753,7 +753,7 @@ bool_t linphone_call_get_authentication_token_verified (const LinphoneCall *call } void linphone_call_set_authentication_token_verified (LinphoneCall *call, bool_t verified) { - L_GET_CPP_PTR_FROM_C_OBJECT(call)->setAuthenticationTokenVerified(verified); + L_GET_CPP_PTR_FROM_C_OBJECT(call)->setAuthenticationTokenVerified(!!verified); } void linphone_call_send_vfu_request (LinphoneCall *call) { @@ -1011,7 +1011,7 @@ void linphone_call_set_native_video_window_id (LinphoneCall *call, void *id) { } void linphone_call_enable_echo_cancellation (LinphoneCall *call, bool_t enable) { - L_GET_CPP_PTR_FROM_C_OBJECT(call)->enableEchoCancellation(enable); + L_GET_CPP_PTR_FROM_C_OBJECT(call)->enableEchoCancellation(!!enable); } bool_t linphone_call_echo_cancellation_enabled (const LinphoneCall *call) { @@ -1019,7 +1019,7 @@ bool_t linphone_call_echo_cancellation_enabled (const LinphoneCall *call) { } void linphone_call_enable_echo_limiter (LinphoneCall *call, bool_t val) { - L_GET_CPP_PTR_FROM_C_OBJECT(call)->enableEchoLimiter(val); + L_GET_CPP_PTR_FROM_C_OBJECT(call)->enableEchoLimiter(!!val); } bool_t linphone_call_echo_limiter_enabled (const LinphoneCall *call) { diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 06546dd35..f01208942 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -116,7 +116,7 @@ bool_t linphone_chat_message_is_secured(LinphoneChatMessage *msg) { } void linphone_chat_message_set_is_secured(LinphoneChatMessage *msg, bool_t secured) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setIsSecured(secured); + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setIsSecured(!!secured); } bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage *msg) { @@ -206,7 +206,7 @@ bool_t linphone_chat_message_get_to_be_stored(const LinphoneChatMessage *msg) { } void linphone_chat_message_set_to_be_stored(LinphoneChatMessage *msg, bool_t to_be_stored) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setIsToBeStored(to_be_stored); + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setIsToBeStored(!!to_be_stored); } belle_http_request_t * linphone_chat_message_get_http_request(LinphoneChatMessage *msg) { diff --git a/src/c-wrapper/api/c-participant.cpp b/src/c-wrapper/api/c-participant.cpp index 89ff5ee1f..1c1a00516 100644 --- a/src/c-wrapper/api/c-participant.cpp +++ b/src/c-wrapper/api/c-participant.cpp @@ -59,5 +59,5 @@ bool_t linphone_participant_is_admin (const LinphoneParticipant *participant) { } void linphone_participant_set_admin (LinphoneParticipant *participant, bool_t value) { - L_GET_CPP_PTR_FROM_C_OBJECT(participant)->setAdmin(value); + L_GET_CPP_PTR_FROM_C_OBJECT(participant)->setAdmin(!!value); } diff --git a/src/conference/params/media-session-params.cpp b/src/conference/params/media-session-params.cpp index d04201c4c..bfb473659 100644 --- a/src/conference/params/media-session-params.cpp +++ b/src/conference/params/media-session-params.cpp @@ -239,18 +239,18 @@ void MediaSessionParams::initDefault (LinphoneCore *core) { lError() << "LinphoneCore has video disabled for both capture and display, but video policy is to start the call with video. " "This is a possible mis-use of the API. In this case, video is disabled in default LinphoneCallParams"; } - d->realtimeTextEnabled = linphone_core_realtime_text_enabled(core); + d->realtimeTextEnabled = !!linphone_core_realtime_text_enabled(core); d->encryption = linphone_core_get_media_encryption(core); d->avpfEnabled = (linphone_core_get_avpf_mode(core) == LinphoneAVPFEnabled); - d->_implicitRtcpFbEnabled = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_fb_implicit_rtcp_fb", true); + d->_implicitRtcpFbEnabled = !!lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_fb_implicit_rtcp_fb", true); d->avpfRrInterval = static_cast(linphone_core_get_avpf_rr_interval(core)); d->audioDirection = LinphoneMediaDirectionSendRecv; d->videoDirection = LinphoneMediaDirectionSendRecv; - d->earlyMediaSendingEnabled = lp_config_get_int(linphone_core_get_config(core), "misc", "real_early_media", false); - d->audioMulticastEnabled = linphone_core_audio_multicast_enabled(core); - d->videoMulticastEnabled = linphone_core_video_multicast_enabled(core); - d->updateCallWhenIceCompleted = lp_config_get_int(linphone_core_get_config(core), "sip", "update_call_when_ice_completed", true); - d->mandatoryMediaEncryptionEnabled = linphone_core_is_media_encryption_mandatory(core); + d->earlyMediaSendingEnabled = !!lp_config_get_int(linphone_core_get_config(core), "misc", "real_early_media", false); + d->audioMulticastEnabled = !!linphone_core_audio_multicast_enabled(core); + d->videoMulticastEnabled = !!linphone_core_video_multicast_enabled(core); + d->updateCallWhenIceCompleted = !!lp_config_get_int(linphone_core_get_config(core), "sip", "update_call_when_ice_completed", true); + d->mandatoryMediaEncryptionEnabled = !!linphone_core_is_media_encryption_mandatory(core); } // ----------------------------------------------------------------------------- diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 44ad05cbf..01bac32d6 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -354,7 +354,7 @@ void CallSessionPrivate::terminated () { } void CallSessionPrivate::updated (bool isUpdate) { - deferUpdate = lp_config_get_int(linphone_core_get_config(core), "sip", "defer_update_default", FALSE); + deferUpdate = !!lp_config_get_int(linphone_core_get_config(core), "sip", "defer_update_default", FALSE); SalErrorInfo sei; memset(&sei, 0, sizeof(sei)); switch (state) { diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 3b2c377ae..5a2ce5942 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -790,7 +790,7 @@ void MediaSessionPrivate::initializeParamsAccordingToIncomingCallParams () { */ void MediaSessionPrivate::setCompatibleIncomingCallParams (SalMediaDescription *md) { /* Handle AVPF, SRTP and DTLS */ - params->enableAvpf(sal_media_description_has_avpf(md)); + params->enableAvpf(!!sal_media_description_has_avpf(md)); if (destProxy) params->setAvpfRrInterval(static_cast(linphone_proxy_config_get_avpf_rr_interval(destProxy) * 1000)); else @@ -1193,7 +1193,7 @@ bool MediaSessionPrivate::generateB64CryptoKey (size_t keyLength, char *keyOut, void MediaSessionPrivate::makeLocalMediaDescription () { L_Q(); int maxIndex = 0; - bool rtcpMux = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_mux", 0); + bool rtcpMux = !!lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_mux", 0); SalMediaDescription *md = sal_media_description_new(); SalMediaDescription *oldMd = localDesc; @@ -1492,7 +1492,7 @@ void MediaSessionPrivate::setupZrtpHash (SalMediaDescription *md) { void MediaSessionPrivate::setupEncryptionKeys (SalMediaDescription *md) { SalMediaDescription *oldMd = localDesc; - bool keepSrtpKeys = lp_config_get_int(linphone_core_get_config(core), "sip", "keep_srtp_keys", 1); + bool keepSrtpKeys = !!lp_config_get_int(linphone_core_get_config(core), "sip", "keep_srtp_keys", 1); for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (!sal_stream_description_active(&md->streams[i])) continue; @@ -1906,7 +1906,7 @@ void MediaSessionPrivate::clearEarlyMediaDestinations () { void MediaSessionPrivate::configureAdaptiveRateControl (MediaStream *ms, const OrtpPayloadType *pt, bool videoWillBeUsed) { L_Q(); - bool enabled = linphone_core_adaptive_rate_control_enabled(core); + bool enabled = !!linphone_core_adaptive_rate_control_enabled(core); if (!enabled) { media_stream_enable_adaptive_bitrate_control(ms, false); return; @@ -2010,7 +2010,7 @@ RtpSession * MediaSessionPrivate::createAudioRtpIoSession () { int jittcomp = lp_config_get_int(config, "sound", "rtp_jittcomp", 0); /* 0 means no jitter buffer */ rtp_session_set_jitter_compensation(rtpSession, jittcomp); rtp_session_enable_jitter_buffer(rtpSession, (jittcomp > 0)); - bool symmetric = lp_config_get_int(config, "sound", "rtp_symmetric", 0); + bool symmetric = !!lp_config_get_int(config, "sound", "rtp_symmetric", 0); rtp_session_set_symmetric_rtp(rtpSession, symmetric); return rtpSession; } @@ -2158,15 +2158,15 @@ void MediaSessionPrivate::handleStreamEvents (int streamIndex) { OrtpEventData *evd = ortp_event_get_data(ev); if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED) { if (streamIndex == mainAudioStreamIndex) - audioStreamEncryptionChanged(evd->info.zrtp_stream_encrypted); + audioStreamEncryptionChanged(!!evd->info.zrtp_stream_encrypted); else if (streamIndex == mainVideoStreamIndex) propagateEncryptionChanged(); } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) { if (streamIndex == mainAudioStreamIndex) - audioStreamAuthTokenReady(evd->info.zrtp_info.sas, evd->info.zrtp_info.verified); + audioStreamAuthTokenReady(evd->info.zrtp_info.sas, !!evd->info.zrtp_info.verified); } else if (evt == ORTP_EVENT_DTLS_ENCRYPTION_CHANGED) { if (streamIndex == mainAudioStreamIndex) - audioStreamEncryptionChanged(evd->info.dtls_stream_encrypted); + audioStreamEncryptionChanged(!!evd->info.dtls_stream_encrypted); else if (streamIndex == mainVideoStreamIndex) propagateEncryptionChanged(); } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) @@ -2420,7 +2420,7 @@ void MediaSessionPrivate::parameterizeEqualizer (AudioStream *stream) { lWarning() << "'eq_gains' linphonerc parameter has no effect anymore. Please use 'mic_eq_gains' or 'spk_eq_gains' instead"; if (stream->mic_equalizer) { MSFilter *f = stream->mic_equalizer; - bool enabled = lp_config_get_int(config, "sound", "mic_eq_active", 0); + bool enabled = !!lp_config_get_int(config, "sound", "mic_eq_active", 0); ms_filter_call_method(f, MS_EQUALIZER_SET_ACTIVE, &enabled); const char *gains = lp_config_get_string(config, "sound", "mic_eq_gains", nullptr); if (enabled && gains) { @@ -2436,7 +2436,7 @@ void MediaSessionPrivate::parameterizeEqualizer (AudioStream *stream) { } if (stream->spk_equalizer) { MSFilter *f = stream->spk_equalizer; - bool enabled = lp_config_get_int(config, "sound", "spk_eq_active", 0); + bool enabled = !!lp_config_get_int(config, "sound", "spk_eq_active", 0); ms_filter_call_method(f, MS_EQUALIZER_SET_ACTIVE, &enabled); const char *gains = lp_config_get_string(config, "sound", "spk_eq_gains", nullptr); if (enabled && gains) { @@ -2542,7 +2542,7 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool lWarning() << "No audio stream accepted?"; else { const char *rtpAddr = (stream->rtp_addr[0] != '\0') ? stream->rtp_addr : resultDesc->addr; - bool isMulticast = ms_is_multicast(rtpAddr); + bool isMulticast = !!ms_is_multicast(rtpAddr); bool ok = true; currentParams->getPrivate()->setUsedAudioCodec(rtp_profile_get_payload(audioProfile, usedPt)); currentParams->enableAudio(true); @@ -2574,8 +2574,8 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool } } /* If playfile are supplied don't use soundcards */ - bool useRtpIo = lp_config_get_int(linphone_core_get_config(core), "sound", "rtp_io", false); - bool useRtpIoEnableLocalOutput = lp_config_get_int(linphone_core_get_config(core), "sound", "rtp_io_enable_local_output", false); + bool useRtpIo = !!lp_config_get_int(linphone_core_get_config(core), "sound", "rtp_io", false); + bool useRtpIoEnableLocalOutput = !!lp_config_get_int(linphone_core_get_config(core), "sound", "rtp_io_enable_local_output", false); if (core->use_files || (useRtpIo && !useRtpIoEnableLocalOutput)) { captcard = playcard = nullptr; } @@ -2589,7 +2589,7 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool captcard = playcard = nullptr; } #endif - bool useEc = (captcard == nullptr) ? false : linphone_core_echo_cancellation_enabled(core); + bool useEc = captcard && linphone_core_echo_cancellation_enabled(core); audio_stream_enable_echo_canceller(audioStream, useEc); if (playcard && (stream->max_rate > 0)) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate); @@ -3634,12 +3634,12 @@ void MediaSessionPrivate::handleIncomingReceivedStateInIncomingNotification () { L_Q(); /* Try to be best-effort in giving real local or routable contact address for 100Rel case */ setContactOp(); - bool proposeEarlyMedia = lp_config_get_int(linphone_core_get_config(core), "sip", "incoming_calls_early_media", false); + bool proposeEarlyMedia = !!lp_config_get_int(linphone_core_get_config(core), "sip", "incoming_calls_early_media", false); if (proposeEarlyMedia) q->acceptEarlyMedia(); else sal_call_notify_ringing(op, false); - if (sal_call_get_replaces(op) && lp_config_get_int(linphone_core_get_config(core), "sip", "auto_answer_replacing_calls", 1)) + if (sal_call_get_replaces(op) && !!lp_config_get_int(linphone_core_get_config(core), "sip", "auto_answer_replacing_calls", 1)) q->accept(); } @@ -3821,15 +3821,15 @@ void MediaSessionPrivate::updateCurrentParams () const { currentParams->setAudioDirection(sd ? MediaSessionParamsPrivate::salStreamDirToMediaDirection(sd->dir) : LinphoneMediaDirectionInactive); if (currentParams->getAudioDirection() != LinphoneMediaDirectionInactive) { const char *rtpAddr = (sd->rtp_addr[0] != '\0') ? sd->rtp_addr : md->addr; - currentParams->enableAudioMulticast(ms_is_multicast(rtpAddr)); + currentParams->enableAudioMulticast(!!ms_is_multicast(rtpAddr)); } else currentParams->enableAudioMulticast(false); sd = sal_media_description_find_best_stream(md, SalVideo); - currentParams->getPrivate()->enableImplicitRtcpFb(sd ? sal_stream_description_has_implicit_avpf(sd): false); + currentParams->getPrivate()->enableImplicitRtcpFb(sd && sal_stream_description_has_implicit_avpf(sd)); currentParams->setVideoDirection(sd ? MediaSessionParamsPrivate::salStreamDirToMediaDirection(sd->dir) : LinphoneMediaDirectionInactive); if (currentParams->getVideoDirection() != LinphoneMediaDirectionInactive) { const char *rtpAddr = (sd->rtp_addr[0] != '\0') ? sd->rtp_addr : md->addr; - currentParams->enableVideoMulticast(ms_is_multicast(rtpAddr)); + currentParams->enableVideoMulticast(!!ms_is_multicast(rtpAddr)); } else currentParams->enableVideoMulticast(false); } @@ -3876,7 +3876,7 @@ void MediaSessionPrivate::accept (const MediaSessionParams *csp) { LinphoneStatus MediaSessionPrivate::acceptUpdate (const CallSessionParams *csp, LinphoneCallState nextState, const string &stateInfo) { L_Q(); SalMediaDescription *desc = sal_call_get_remote_media_description(op); - bool keepSdpVersion = lp_config_get_int(linphone_core_get_config(core), "sip", "keep_sdp_version", 0); + bool keepSdpVersion = !!lp_config_get_int(linphone_core_get_config(core), "sip", "keep_sdp_version", 0); if (keepSdpVersion && (desc->session_id == remoteSessionId) && (desc->session_ver == remoteSessionVer)) { /* Remote has sent an INVITE with the same SDP as before, so send a 200 OK with the same SDP as before. */ lWarning() << "SDP version has not changed, send same SDP as before"; @@ -4401,20 +4401,19 @@ bool MediaSession::cameraEnabled () const { bool MediaSession::echoCancellationEnabled () const { L_D(); - if (d->audioStream && d->audioStream->ec) { - bool val; - ms_filter_call_method(d->audioStream->ec, MS_ECHO_CANCELLER_GET_BYPASS_MODE, &val); - return !val; - } else - return linphone_core_echo_cancellation_enabled(d->core); + if (!d->audioStream || !d->audioStream->ec) + return !!linphone_core_echo_cancellation_enabled(d->core); + + bool val; + ms_filter_call_method(d->audioStream->ec, MS_ECHO_CANCELLER_GET_BYPASS_MODE, &val); + return !val; } bool MediaSession::echoLimiterEnabled () const { L_D(); if (d->audioStream) return d->audioStream->el_type !=ELInactive; - else - return linphone_core_echo_limiter_enabled(d->core); + return !!linphone_core_echo_limiter_enabled(d->core); } void MediaSession::enableCamera (bool value) { diff --git a/src/nat/ice-agent.cpp b/src/nat/ice-agent.cpp index 64d5f5c4f..0a8e19c10 100644 --- a/src/nat/ice-agent.cpp +++ b/src/nat/ice-agent.cpp @@ -34,7 +34,7 @@ LINPHONE_BEGIN_NAMESPACE bool IceAgent::candidatesGathered () const { if (!iceSession) return false; - return ice_session_candidates_gathered(iceSession); + return !!ice_session_candidates_gathered(iceSession); } void IceAgent::checkSession (IceRole role, bool isReinvite) { @@ -107,7 +107,7 @@ bool IceAgent::hasCompletedCheckList () const { switch (ice_session_state(iceSession)) { case IS_Completed: case IS_Failed: - return ice_session_has_completed_check_list(iceSession); + return !!ice_session_has_completed_check_list(iceSession); default: return false; } @@ -213,7 +213,7 @@ void IceAgent::updateFromRemoteMediaDescription ( if (!iceParamsFoundInRemoteMediaDescription(remoteDesc)) { // Response from remote does not contain mandatory ICE attributes, delete the session. deleteSession(); - mediaSession.getPrivate()->enableSymmetricRtp(linphone_core_symmetric_rtp_enabled(mediaSession.getPrivate()->getCore())); + mediaSession.getPrivate()->enableSymmetricRtp(!!linphone_core_symmetric_rtp_enabled(mediaSession.getPrivate()->getCore())); return; } @@ -236,7 +236,7 @@ void IceAgent::updateFromRemoteMediaDescription ( if (ice_session_nb_check_lists(iceSession) == 0) { deleteSession(); - mediaSession.getPrivate()->enableSymmetricRtp(linphone_core_symmetric_rtp_enabled(mediaSession.getPrivate()->getCore())); + mediaSession.getPrivate()->enableSymmetricRtp(!!linphone_core_symmetric_rtp_enabled(mediaSession.getPrivate()->getCore())); } } @@ -302,7 +302,7 @@ void IceAgent::updateLocalMediaDescriptionFromIce (SalMediaDescription *desc) { } } if (firstCl) - result = ice_check_list_selected_valid_local_candidate(firstCl, &rtpCandidate, nullptr); + result = !!ice_check_list_selected_valid_local_candidate(firstCl, &rtpCandidate, nullptr); if (result) strncpy(desc->addr, rtpCandidate->taddr.ip, sizeof(desc->addr)); else @@ -320,13 +320,13 @@ void IceAgent::updateLocalMediaDescriptionFromIce (SalMediaDescription *desc) { if (ice_check_list_state(cl) == ICL_Completed) { LinphoneConfig *config = linphone_core_get_config(mediaSession.getPrivate()->getCore()); // TODO: Remove `ice_uses_nortpproxy` option, let's say in December 2018. - bool useNoRtpProxy = lp_config_get_int(config, "sip", "ice_uses_nortpproxy", false); + bool useNoRtpProxy = !!lp_config_get_int(config, "sip", "ice_uses_nortpproxy", false); if (useNoRtpProxy) stream->set_nortpproxy = true; - result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(iceSession, i), &rtpCandidate, &rtcpCandidate); + result = !!ice_check_list_selected_valid_local_candidate(ice_session_check_list(iceSession, i), &rtpCandidate, &rtcpCandidate); } else { stream->set_nortpproxy = false; - result = ice_check_list_default_local_candidate(ice_session_check_list(iceSession, i), &rtpCandidate, &rtcpCandidate); + result = !!ice_check_list_default_local_candidate(ice_session_check_list(iceSession, i), &rtpCandidate, &rtcpCandidate); } if (result) { strncpy(stream->rtp_addr, rtpCandidate->taddr.ip, sizeof(stream->rtp_addr)); diff --git a/src/nat/ice-agent.h b/src/nat/ice-agent.h index 2aa13b05d..369d579da 100644 --- a/src/nat/ice-agent.h +++ b/src/nat/ice-agent.h @@ -52,7 +52,7 @@ public: bool hasCompleted () const; bool hasCompletedCheckList () const; bool hasSession () const { - return iceSession; + return !!iceSession; } bool isControlling () const; From 77dbc1b9ba5a7723561aab0d835c9bb9bb437176 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 28 Sep 2017 16:10:21 +0200 Subject: [PATCH 0237/2215] fix(Address): return correctly boolean in isValid --- include/linphone/utils/general.h | 2 +- src/address/address.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index 82bcf68b0..bccb155bf 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -55,7 +55,7 @@ LINPHONE_BEGIN_NAMESPACE #if defined(_MSC_VER) #define LINPHONE_DEPRECATED __declspec(deprecated) #else - #define LINPHONE_DEPRECATED __attribute__ ((deprecated)) + #define LINPHONE_DEPRECATED __attribute__((deprecated)) #endif #endif diff --git a/src/address/address.cpp b/src/address/address.cpp index e6c52dc0d..b89631211 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -73,7 +73,7 @@ bool Address::operator< (const Address &address) const { bool Address::isValid () const { L_D(); - d->internalAddress; + return !!d->internalAddress; } const string &Address::getScheme () const { From 5bf3920571fd625fd3db0553ea3b639876dc142f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 28 Sep 2017 16:20:37 +0200 Subject: [PATCH 0238/2215] Fixed issues related to chat file transfer --- src/chat/chat-message.cpp | 4 ++-- src/chat/chat-room.cpp | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 612f983bf..0d4ebe6fe 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -511,7 +511,7 @@ void ChatMessagePrivate::onRecvEnd(belle_sip_user_body_handler_t *bh) { } bool ChatMessagePrivate::isFileTransferInProgressAndValid() { - return (chatRoom && chatRoom->getCore() && httpRequest && !!belle_http_request_is_cancelled(httpRequest)); + return (chatRoom && chatRoom->getCore() && httpRequest && !belle_http_request_is_cancelled(httpRequest)); } static void _chat_message_process_response_from_post_file(void *data, const belle_http_response_event_t *event) { @@ -835,7 +835,7 @@ int ChatMessagePrivate::startHttpTransfer(std::string url, std::string action, b belle_sip_object_ref(httpRequest); // give msg to listener to be able to start the actual file upload when server answer a 204 No content - httpListener = belle_http_request_listener_create_from_callbacks(cbs, NULL); + httpListener = belle_http_request_listener_create_from_callbacks(cbs, this); belle_http_provider_send_request(chatRoom->getCore()->http_provider, httpRequest, httpListener); return 0; error: diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 8557d2fb1..ae5a8dc5f 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -596,7 +596,6 @@ LinphoneChatMessage *ChatRoom::createFileTransferMessage (const LinphoneContent shared_ptr chatMessage = make_shared(static_pointer_cast(shared_from_this())); chatMessage->getPrivate()->setTime(ms_time(0)); - chatMessage->getPrivate()->setContentType("text/plain"); chatMessage->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); chatMessage->getPrivate()->setFileTransferInformation(linphone_content_copy(initialContent)); chatMessage->setToAddress(make_shared
    (d->peerAddress.asString().c_str())); From eee82ef1ab676f52cca969065db26540f0ff6923 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 28 Sep 2017 16:32:34 +0200 Subject: [PATCH 0239/2215] More fixes related to ChatMessage --- src/c-wrapper/api/c-chat-message.cpp | 8 +++++--- src/chat/chat-room.cpp | 2 -- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index f01208942..2a9992842 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -168,11 +168,12 @@ const char *linphone_chat_message_get_appdata(const LinphoneChatMessage *msg) { } void linphone_chat_message_set_appdata(LinphoneChatMessage *msg, const char *data) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setAppdata(data); + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setAppdata(L_C_TO_STRING(data)); } void linphone_chat_message_set_from_address(LinphoneChatMessage *msg, const LinphoneAddress *from) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFromAddress(make_shared(linphone_address_as_string(from))); + if (!from) L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFromAddress(nullptr); + else L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFromAddress(make_shared(linphone_address_as_string(from))); } const LinphoneAddress *linphone_chat_message_get_from_address(LinphoneChatMessage *msg) { @@ -183,7 +184,8 @@ const LinphoneAddress *linphone_chat_message_get_from_address(LinphoneChatMessag } void linphone_chat_message_set_to_address(LinphoneChatMessage *msg, const LinphoneAddress *to) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setToAddress(make_shared(linphone_address_as_string(to))); + if (!to) L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setToAddress(nullptr); + else L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setToAddress(make_shared(linphone_address_as_string(to))); } const LinphoneAddress *linphone_chat_message_get_to_address(LinphoneChatMessage *msg) { diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index ae5a8dc5f..2ea8fb67f 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -277,10 +277,8 @@ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colN if (atoi(argv[3]) == LinphoneChatMessageIncoming) { linphone_chat_message_set_incoming(newMessage); linphone_chat_message_set_from_address(newMessage, peer); - linphone_chat_message_set_to_address(newMessage, NULL); } else { linphone_chat_message_set_outgoing(newMessage); - linphone_chat_message_set_from_address(newMessage, NULL); linphone_chat_message_set_to_address(newMessage, peer); } linphone_address_unref(peer); From 613d1e61d344151c5e84dabd9bd64bf6f58aabbe Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 28 Sep 2017 17:29:30 +0200 Subject: [PATCH 0240/2215] fix(General): define L_LIKELY/L_UNLIKELY for Windows --- include/linphone/utils/general.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index bccb155bf..b9e36ade1 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -71,8 +71,13 @@ void l_assert (const char *condition, const char *file, int line); #define L_ASSERT(CONDITION) ((CONDITION) ? static_cast(0) : LINPHONE_NAMESPACE::l_assert(#CONDITION, __FILE__, __LINE__)) #endif -#define L_LIKELY(EXPRESSION) __builtin_expect(static_cast(EXPRESSION), true) -#define L_UNLIKELY(EXPRESSION) __builtin_expect(static_cast(EXPRESSION), false) +#ifndef _MSC_VER + #define L_LIKELY(EXPRESSION) __builtin_expect(static_cast(EXPRESSION), true) + #define L_UNLIKELY(EXPRESSION) __builtin_expect(static_cast(EXPRESSION), false) +#else + #define L_LIKELY(EXPRESSION) EXPRESSION + #define L_UNLIKELY(EXPRESSION) EXPRESSION +#endif // Allows access to private internal data. // Gives a control to C Wrapper. From 6c3bc0c06ee6643880cea00cbf75fcaccaa00c01 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 28 Sep 2017 17:34:01 +0200 Subject: [PATCH 0241/2215] Fixed more issues with c-chat-message wrapper --- src/c-wrapper/api/c-chat-message.cpp | 16 ++++++++-------- src/chat/chat-message-p.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 2a9992842..9ddc5c0e7 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -100,7 +100,7 @@ const char *linphone_chat_message_get_external_body_url(const LinphoneChatMessag } void linphone_chat_message_set_external_body_url(LinphoneChatMessage *msg, const char *url) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setExternalBodyUrl(string(url)); + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setExternalBodyUrl(L_C_TO_STRING(url)); } time_t linphone_chat_message_get_time(const LinphoneChatMessage *msg) { @@ -152,7 +152,7 @@ const char* linphone_chat_message_get_message_id(const LinphoneChatMessage *msg) } void linphone_chat_message_set_message_id(LinphoneChatMessage *msg, char *id) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setId(id); + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setId(L_C_TO_STRING(id)); } void linphone_chat_message_set_storage_id(LinphoneChatMessage *msg, unsigned int id) { @@ -200,7 +200,7 @@ const char *linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage } void linphone_chat_message_set_file_transfer_filepath(LinphoneChatMessage *msg, const char *filepath) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFileTransferFilepath(filepath); + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFileTransferFilepath(L_C_TO_STRING(filepath)); } bool_t linphone_chat_message_get_to_be_stored(const LinphoneChatMessage *msg) { @@ -237,15 +237,15 @@ void linphone_chat_message_set_sal_custom_headers(LinphoneChatMessage *msg, SalC void linphone_chat_message_add_custom_header(LinphoneChatMessage *msg, const char *header_name, const char *header_value) { - L_GET_PRIVATE_FROM_C_OBJECT(msg)->addSalCustomHeader(header_name, header_value); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->addSalCustomHeader(L_C_TO_STRING(header_name), L_C_TO_STRING(header_value)); } void linphone_chat_message_remove_custom_header(LinphoneChatMessage *msg, const char *header_name) { - L_GET_PRIVATE_FROM_C_OBJECT(msg)->removeSalCustomHeader(header_name); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->removeSalCustomHeader(L_C_TO_STRING(header_name)); } const char *linphone_chat_message_get_custom_header(LinphoneChatMessage *msg, const char *header_name) { - return L_STRING_TO_C(L_GET_PRIVATE_FROM_C_OBJECT(msg)->getSalCustomHeaderValue(header_name)); + return L_STRING_TO_C(L_GET_PRIVATE_FROM_C_OBJECT(msg)->getSalCustomHeaderValue(L_C_TO_STRING(header_name))); } const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg) { @@ -329,7 +329,7 @@ const char * linphone_chat_message_get_content_type(const LinphoneChatMessage *m } void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char *content_type) { - L_GET_PRIVATE_FROM_C_OBJECT(msg)->setContentType(content_type); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setContentType(L_C_TO_STRING(content_type)); } const char *linphone_chat_message_get_text(const LinphoneChatMessage *msg) { @@ -337,7 +337,7 @@ const char *linphone_chat_message_get_text(const LinphoneChatMessage *msg) { } int linphone_chat_message_set_text(LinphoneChatMessage *msg, const char* text) { - L_GET_PRIVATE_FROM_C_OBJECT(msg)->setText(text); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setText(L_C_TO_STRING(text)); return 0; } diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index f062be033..2e5b2500c 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -100,7 +100,7 @@ private: std::shared_ptr chatRoom; ChatMessage::Direction direction = ChatMessage::Incoming; ChatMessage::State state = ChatMessage::Idle; - unsigned int storageId; + unsigned int storageId = 0; std::shared_ptr
    from; std::shared_ptr
    to; time_t time = 0; From 7e1335282481d038fff72531aae823809ab3fae6 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 28 Sep 2017 17:39:12 +0200 Subject: [PATCH 0242/2215] feat(General): L_DECLARE_PRIVATE can declare a LINPHONE_NAMESPACE::Tester friend --- include/linphone/utils/general.h | 22 +++++++++++++++------- tester/CMakeLists.txt | 2 ++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index b9e36ade1..060c85df1 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -79,9 +79,12 @@ void l_assert (const char *condition, const char *file, int line); #define L_UNLIKELY(EXPRESSION) EXPRESSION #endif -// Allows access to private internal data. -// Gives a control to C Wrapper. -#define L_DECLARE_PRIVATE(CLASS) \ +class ClonableObject; +class ClonableObjectPrivate; +class Object; +class ObjectPrivate; + +#define L_INTERNAL_DECLARE_PRIVATE(CLASS) \ inline CLASS ## Private *getPrivate() { \ return reinterpret_cast(mPrivate); \ } \ @@ -91,10 +94,15 @@ void l_assert (const char *condition, const char *file, int line); friend class CLASS ## Private; \ friend class Wrapper; -class ClonableObject; -class ClonableObjectPrivate; -class Object; -class ObjectPrivate; +// Allows access to private internal data. +// Gives a control to C Wrapper. +#ifndef LINPHONE_TESTER + #define L_DECLARE_PRIVATE(CLASS) L_INTERNAL_DECLARE_PRIVATE(CLASS) +#else + #define L_DECLARE_PRIVATE(CLASS) \ + L_INTERNAL_DECLARE_PRIVATE(CLASS) \ + friend class Tester; +#endif template inline ClonableObject *getPublicHelper (T *object, ClonableObjectPrivate *context) { diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index ed7fa481d..cc9952668 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -218,6 +218,8 @@ bc_apply_compile_flags(SOURCE_FILES_C STRICT_OPTIONS_CPP STRICT_OPTIONS_C) bc_apply_compile_flags(SOURCE_FILES_CXX STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX) bc_apply_compile_flags(SOURCE_FILES_OBJC STRICT_OPTIONS_CPP STRICT_OPTIONS_OBJC) +add_definitions("-DLINPHONE_TESTER") + if(MSVC) get_source_file_property(MESSAGE_TESTER_C_COMPILE_FLAGS message_tester.c COMPILE_FLAGS) set(MESSAGE_TESTER_C_COMPILE_FLAGS "${MESSAGE_TESTER_C_COMPILE_FLAGS} /wd4996") # Disable "was declared deprecated" warnings From 46dbc8a4cbf8ae4a61c80854190641550baa5b68 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 28 Sep 2017 17:45:59 +0200 Subject: [PATCH 0243/2215] Fixed chat message state update when file transfer not saved in db --- src/chat/chat-message.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 0d4ebe6fe..28c464fe3 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -750,8 +750,10 @@ static void _chat_message_process_auth_requested_download(void *data, belle_sip_ } void ChatMessagePrivate::processAuthRequestedDownload(const belle_sip_auth_event *event) { + L_Q(); + ms_error("Error during file download : auth requested for msg [%p]", this); - setState(ChatMessage::FileTransferError); + q->updateState(ChatMessage::FileTransferError); releaseHttpRequest(); } @@ -763,7 +765,7 @@ static void _chat_message_process_io_error_upload(void *data, const belle_sip_io void ChatMessagePrivate::processIoErrorUpload(const belle_sip_io_error_event_t *event) { L_Q(); ms_error("I/O Error during file upload of msg [%p]", this); - setState(ChatMessage::NotDelivered); + q->updateState(ChatMessage::NotDelivered); releaseHttpRequest(); chatRoom->getPrivate()->removeTransientMessage(L_GET_C_BACK_PTR(q)); } @@ -776,7 +778,7 @@ static void _chat_message_process_auth_requested_upload(void *data, belle_sip_au void ChatMessagePrivate::processAuthRequestedUpload(const belle_sip_auth_event *event) { L_Q(); ms_error("Error during file upload: auth requested for msg [%p]", this); - setState(ChatMessage::NotDelivered); + q->updateState(ChatMessage::NotDelivered); releaseHttpRequest(); chatRoom->getPrivate()->removeTransientMessage(L_GET_C_BACK_PTR(q)); } @@ -787,8 +789,10 @@ static void _chat_message_process_io_error_download(void *data, const belle_sip_ } void ChatMessagePrivate::processIoErrorDownload(const belle_sip_io_error_event_t *event) { + L_Q(); + ms_error("I/O Error during file download msg [%p]", this); - setState(ChatMessage::FileTransferError); + q->updateState(ChatMessage::FileTransferError); releaseHttpRequest(); } From 6bcf9311cc1573589024af318f9e4c2372879f19 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 28 Sep 2017 19:19:29 +0200 Subject: [PATCH 0244/2215] Fixed issue with lime file transfer --- src/chat/chat-message.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 28c464fe3..c0bec7680 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -642,7 +642,9 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e } // dump the xml into msg->message - xmlDocDumpFormatMemoryEnc(xmlMessageBody, (xmlChar **)&cText, &xmlStringLength, "UTF-8", 0); + char *buffer; + xmlDocDumpFormatMemoryEnc(xmlMessageBody, (xmlChar **)&buffer, &xmlStringLength, "UTF-8", 0); + setText(buffer); break; } xmlFree(typeAttribute); From 6024a8fd4e85faeb18e3ee6ec91c9276f2ee4293 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 28 Sep 2017 20:25:07 +0200 Subject: [PATCH 0245/2215] Yet another fix for ChatMessage --- src/chat/chat-message-p.h | 6 +++--- src/chat/chat-message.cpp | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 2e5b2500c..eb9a3d74c 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -57,9 +57,9 @@ public: SalCustomHeader *getSalCustomHeaders() const; void setSalCustomHeaders(SalCustomHeader *headers); - void addSalCustomHeader(std::string name, std::string value); - void removeSalCustomHeader(std::string name); - std::string getSalCustomHeaderValue(std::string name); + void addSalCustomHeader(const std::string& name, const std::string& value); + void removeSalCustomHeader(const std::string& name); + std::string getSalCustomHeaderValue(const std::string& name); // ----------------------------------------------------------------------------- // Methods only used for C wrapper diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index c0bec7680..9235b0e7b 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -119,16 +119,16 @@ void ChatMessagePrivate::setSalCustomHeaders(SalCustomHeader *headers) { salCustomHeaders = headers; } -void ChatMessagePrivate::addSalCustomHeader(string name, string value) { +void ChatMessagePrivate::addSalCustomHeader(const string& name, const string& value) { salCustomHeaders = sal_custom_header_append(salCustomHeaders, name.c_str(), value.c_str()); } -void ChatMessagePrivate::removeSalCustomHeader(string name) { +void ChatMessagePrivate::removeSalCustomHeader(const string& name) { salCustomHeaders = sal_custom_header_remove(salCustomHeaders, name.c_str()); } -string ChatMessagePrivate::getSalCustomHeaderValue(string name) { - return sal_custom_header_find(salCustomHeaders, name.c_str()); +string ChatMessagePrivate::getSalCustomHeaderValue(const string& name) { + return L_C_TO_STRING(sal_custom_header_find(salCustomHeaders, name.c_str())); } // ----------------------------------------------------------------------------- From 4e798d8b32f77c4e4b09c8aec15a43e60137d706 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 29 Sep 2017 10:51:47 +0200 Subject: [PATCH 0246/2215] feat(c-wrapper): L_GET_PRIVATE supports CPP_TYPE parameter --- src/c-wrapper/api/c-chat-room.cpp | 4 +- src/c-wrapper/internal/c-tools.h | 62 +++++++++++++++++++++++++------ src/call/call.cpp | 11 +++--- 3 files changed, 58 insertions(+), 19 deletions(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 251e560d6..dc4bd45d1 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -149,7 +149,7 @@ void linphone_chat_room_send_chat_message (LinphoneChatRoom *cr, LinphoneChatMes uint32_t linphone_chat_room_get_char (const LinphoneChatRoom *cr) { if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) - return static_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr).get())->getChar(); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr, RealTimeTextChatRoom)->getChar(); return 0; } @@ -159,7 +159,7 @@ void linphone_chat_room_compose (LinphoneChatRoom *cr) { LinphoneCall *linphone_chat_room_get_call (const LinphoneChatRoom *cr) { if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) - return static_cast(L_GET_CPP_PTR_FROM_C_OBJECT(cr).get())->getCall(); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr, RealTimeTextChatRoom)->getCall(); return nullptr; } diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 0a5c0eff9..2aeb69ac4 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -32,6 +32,12 @@ // Internal. // ============================================================================= +#ifdef DEBUG + #define L_INTERNAL_WRAPPER_CONSTEXPR +#else + #define L_INTERNAL_WRAPPER_CONSTEXPR constexpr +#endif + LINPHONE_BEGIN_NAMESPACE template @@ -60,6 +66,13 @@ private: }; }; + template + struct IsPrivateCppObject { + enum { + value = std::is_base_of::value || std::is_base_of::value + }; + }; + template struct IsDefinedCppObject { enum { @@ -106,6 +119,29 @@ private: } public: + // --------------------------------------------------------------------------- + // Casts. + // --------------------------------------------------------------------------- + + template< + typename CppDerivedPrivateType, + typename CppBasePrivateType, + typename = typename std::enable_if::value, CppDerivedPrivateType>::type + > + static L_INTERNAL_WRAPPER_CONSTEXPR CppDerivedPrivateType *cast (CppBasePrivateType *base) { + #ifdef DEBUG + if (!base) + return static_cast(base); + + CppDerivedPrivateType *derived = dynamic_cast(base); + if (!derived) + fatal("Invalid cast."); + return derived; + #else + return static_cast(base); + #endif + } + // --------------------------------------------------------------------------- // Get private data of cpp Object. // --------------------------------------------------------------------------- @@ -122,12 +158,6 @@ public: // Get c/cpp ptr helpers. // --------------------------------------------------------------------------- - #ifdef DEBUG - #define L_INTERNAL_WRAPPER_CONSTEXPR - #else - #define L_INTERNAL_WRAPPER_CONSTEXPR constexpr - #endif - template< typename CType, typename CppType = typename CTypeMetaInfo::cppType, @@ -159,7 +189,7 @@ public: > static L_INTERNAL_WRAPPER_CONSTEXPR std::shared_ptr getCppPtrFromC (const CType *cObject) { #ifdef DEBUG - return getCppPtrFromC(const_cast(cObject)); + return getCppPtrFromC(const_cast(cObject)); #else return reinterpret_cast *>(cObject)->cppPtr; #endif @@ -202,8 +232,6 @@ public: #endif } - #undef L_INTERNAL_WRAPPER_CONSTEXPR - // --------------------------------------------------------------------------- // Set c/cpp ptr helpers. // --------------------------------------------------------------------------- @@ -387,6 +415,8 @@ private: LINPHONE_END_NAMESPACE +#undef L_INTERNAL_WRAPPER_CONSTEXPR + #define L_INTERNAL_C_OBJECT_NO_XTOR(C_OBJECT) #define L_INTERNAL_DECLARE_C_OBJECT_FUNCTIONS(C_TYPE, CONSTRUCTOR, DESTRUCTOR) \ @@ -552,14 +582,22 @@ LINPHONE_END_NAMESPACE LINPHONE_NAMESPACE::Wrapper::setCppPtrFromC(C_OBJECT, CPP_OBJECT) // Get the private data of a shared or simple cpp-ptr. -#define L_GET_PRIVATE(CPP_OBJECT) \ +#define L_GET_PRIVATE_1_ARGS(CPP_OBJECT) \ LINPHONE_NAMESPACE::Wrapper::getPrivate(LINPHONE_NAMESPACE::Utils::getPtr(CPP_OBJECT)) +#define L_GET_PRIVATE_2_ARGS(CPP_OBJECT, CPP_TYPE) \ + LINPHONE_NAMESPACE::Wrapper::cast(L_GET_PRIVATE_1_ARGS(CPP_OBJECT)) + +#define L_GET_PRIVATE_MACRO_CHOOSER(...) \ + L_EXPAND(L_GET_ARG_3(__VA_ARGS__, L_GET_PRIVATE_2_ARGS, L_GET_PRIVATE_1_ARGS)) + +#define L_GET_PRIVATE(...) \ + L_EXPAND(L_GET_PRIVATE_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)) // Get the private data of a shared or simple cpp-ptr of a wrapped C object. #define L_GET_PRIVATE_FROM_C_OBJECT_1_ARGS(C_OBJECT) \ - L_GET_PRIVATE(LINPHONE_NAMESPACE::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT_1_ARGS(C_OBJECT))) + L_GET_PRIVATE_1_ARGS(LINPHONE_NAMESPACE::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT_1_ARGS(C_OBJECT))) #define L_GET_PRIVATE_FROM_C_OBJECT_2_ARGS(C_OBJECT, CPP_TYPE) \ - L_GET_PRIVATE(LINPHONE_NAMESPACE::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT_2_ARGS(C_OBJECT, CPP_TYPE))) + L_GET_PRIVATE_1_ARGS(LINPHONE_NAMESPACE::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT_2_ARGS(C_OBJECT, CPP_TYPE))) #define L_GET_PRIVATE_FROM_C_OBJECT_MACRO_CHOOSER(...) \ L_EXPAND(L_GET_ARG_3(__VA_ARGS__, L_GET_PRIVATE_FROM_C_OBJECT_2_ARGS, L_GET_PRIVATE_FROM_C_OBJECT_1_ARGS)) diff --git a/src/call/call.cpp b/src/call/call.cpp index a9f22730e..68adb2b62 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +#include "c-wrapper/c-wrapper.h" #include "call-p.h" #include "conference/local-conference.h" #include "conference/participant-p.h" @@ -51,11 +52,11 @@ CallPrivate::~CallPrivate () { // ----------------------------------------------------------------------------- shared_ptr CallPrivate::getActiveSession () const { - return conference->getActiveParticipant()->getPrivate()->getSession(); + return L_GET_PRIVATE(conference->getActiveParticipant())->getSession(); } bool CallPrivate::getAudioMuted () const { - return static_cast(getActiveSession().get())->getPrivate()->getAudioMuted(); + return L_GET_PRIVATE(getActiveSession(), MediaSession)->getAudioMuted(); } LinphoneProxyConfig *CallPrivate::getDestProxy () const { @@ -63,11 +64,11 @@ LinphoneProxyConfig *CallPrivate::getDestProxy () const { } IceSession *CallPrivate::getIceSession () const { - return static_cast(getActiveSession().get())->getPrivate()->getIceSession(); + return L_GET_PRIVATE(getActiveSession(), MediaSession)->getIceSession(); } MediaStream *CallPrivate::getMediaStream (LinphoneStreamType type) const { - return static_cast(getActiveSession().get())->getPrivate()->getMediaStream(type); + return L_GET_PRIVATE(getActiveSession(), MediaSession)->getMediaStream(type); } SalOp *CallPrivate::getOp () const { @@ -75,7 +76,7 @@ SalOp *CallPrivate::getOp () const { } void CallPrivate::setAudioMuted (bool value) { - static_cast(getActiveSession().get())->getPrivate()->setAudioMuted(value); + L_GET_PRIVATE(getActiveSession(), MediaSession)->setAudioMuted(value); } // ----------------------------------------------------------------------------- From 384f99be8ab4897929eb7cc9c3d5c1810446bc14 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 29 Sep 2017 10:56:10 +0200 Subject: [PATCH 0247/2215] Fix some memory leaks. --- src/conference/local-conference-event-handler.cpp | 2 +- src/conference/remote-conference-event-handler.cpp | 14 +++++++------- src/conference/remote-conference.cpp | 5 ++++- src/conference/session/call-session.cpp | 3 +-- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 7e94fc45c..daaaba05b 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -49,7 +49,7 @@ void LocalConferenceEventHandlerPrivate::notifyFullState(string notify, Linphone linphone_content_set_buffer(content, notify.c_str(), strlen(notify.c_str())); linphone_event_notify(lev, content); linphone_content_unref(content); - // linphone_event_unref(lev); ?? + linphone_event_unref(lev); } void LocalConferenceEventHandlerPrivate::notifyAllExcept(string notify, const Address &addr) { diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index a24a5d947..94aa0abd4 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -51,10 +51,7 @@ RemoteConferenceEventHandler::RemoteConferenceEventHandler(LinphoneCore *core, C } RemoteConferenceEventHandler::~RemoteConferenceEventHandler() { - L_D(); xercesc::XMLPlatformUtils::Terminate(); - if (d->lev) - linphone_event_unref(d->lev); } // ----------------------------------------------------------------------------- @@ -65,16 +62,17 @@ void RemoteConferenceEventHandler::subscribe(const Address &addr) { LinphoneAddress *lAddr = linphone_address_new(d->confAddress.asString().c_str()); d->lev = linphone_core_create_subscribe(d->core, lAddr, "Conference", 600); linphone_address_unref(lAddr); - linphone_event_ref(d->lev); linphone_event_set_internal(d->lev, TRUE); linphone_event_set_user_data(d->lev, this); - linphone_event_add_custom_header(d->lev, "Conf-id", d->confAddress.getUsername().c_str()); // TODO : ??? linphone_event_send_subscribe(d->lev, nullptr); } void RemoteConferenceEventHandler::unsubscribe() { L_D(); - linphone_event_terminate(d->lev); + if (d->lev) { + linphone_event_terminate(d->lev); + d->lev = nullptr; + } } void RemoteConferenceEventHandler::notifyReceived(string xmlBody) { @@ -87,7 +85,9 @@ void RemoteConferenceEventHandler::notifyReceived(string xmlBody) { if (confInfo->getEntity() == cleanedConfAddress.asString()) { for (const auto &user : confInfo->getUsers()->getUser()) { LinphoneAddress *cAddr = linphone_core_interpret_url(d->core, user.getEntity()->c_str()); - Address addr(linphone_address_as_string(cAddr)); + char *cAddrStr = linphone_address_as_string(cAddr); + Address addr(cAddrStr); + bctbx_free(cAddrStr); if (user.getState() == "deleted") d->listener->onParticipantRemoved(addr); else { diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index 2200d417d..f83f10e67 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -33,6 +33,7 @@ RemoteConference::RemoteConference (LinphoneCore *core, const Address &myAddress } RemoteConference::~RemoteConference () { + eventHandler->unsubscribe(); delete eventHandler; } @@ -81,7 +82,9 @@ string RemoteConference::getResourceLists (const list
    &addresses) { void RemoteConference::onConferenceCreated (const Address &addr) {} -void RemoteConference::onConferenceTerminated (const Address &addr) {} +void RemoteConference::onConferenceTerminated (const Address &addr) { + eventHandler->unsubscribe(); +} void RemoteConference::onParticipantAdded (const Address &addr) {} diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 01bac32d6..5dd173e5d 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -600,9 +600,8 @@ void CallSessionPrivate::setContactOp () { LinphoneAddress *contact = getFixedContact(); if (contact) { salAddress = const_cast(L_GET_PRIVATE_FROM_C_OBJECT(contact)->getInternalAddress()); - sal_address_ref(salAddress); - linphone_address_unref(contact); sal_op_set_contact_address(op, salAddress); + linphone_address_unref(contact); } } From 53d7a7d639fb89183a5103340bcb56ebf6244a09 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 29 Sep 2017 15:06:11 +0200 Subject: [PATCH 0248/2215] fix(Address): use a mutable only once --- src/address/address-p.h | 20 ++++++++++---------- src/call/call.cpp | 1 - 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/address/address-p.h b/src/address/address-p.h index ba502726b..b48a58c7f 100644 --- a/src/address/address-p.h +++ b/src/address/address-p.h @@ -36,20 +36,20 @@ public: private: struct AddressCache { - mutable std::string scheme; - mutable std::string displayName; - mutable std::string username; - mutable std::string domain; - mutable std::string methodParam; - mutable std::string password; + std::string scheme; + std::string displayName; + std::string username; + std::string domain; + std::string methodParam; + std::string password; - mutable std::unordered_map headers; - mutable std::unordered_map params; - mutable std::unordered_map uriParams; + std::unordered_map headers; + std::unordered_map params; + std::unordered_map uriParams; }; SalAddress *internalAddress = nullptr; - AddressCache cache; + mutable AddressCache cache; L_DECLARE_PUBLIC(Address); }; diff --git a/src/call/call.cpp b/src/call/call.cpp index 68adb2b62..1571d9e2e 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -16,7 +16,6 @@ * along with this program. If not, see . */ -#include "c-wrapper/c-wrapper.h" #include "call-p.h" #include "conference/local-conference.h" #include "conference/participant-p.h" From 2230acf7b48711e47f02a81d256ec734a99e89f4 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 29 Sep 2017 15:06:34 +0200 Subject: [PATCH 0249/2215] fix(Call): avoid usage of L_GET_PRIVATE --- src/call/call.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/call/call.cpp b/src/call/call.cpp index 1571d9e2e..d1d4495b3 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -51,11 +51,11 @@ CallPrivate::~CallPrivate () { // ----------------------------------------------------------------------------- shared_ptr CallPrivate::getActiveSession () const { - return L_GET_PRIVATE(conference->getActiveParticipant())->getSession(); + return conference->getActiveParticipant()->getPrivate()->getSession(); } bool CallPrivate::getAudioMuted () const { - return L_GET_PRIVATE(getActiveSession(), MediaSession)->getAudioMuted(); + return static_pointer_cast(getActiveSession())->getAudioMuted(); } LinphoneProxyConfig *CallPrivate::getDestProxy () const { @@ -63,7 +63,7 @@ LinphoneProxyConfig *CallPrivate::getDestProxy () const { } IceSession *CallPrivate::getIceSession () const { - return L_GET_PRIVATE(getActiveSession(), MediaSession)->getIceSession(); + return static_pointer_cast(getActiveSession())->getIceSession(); } MediaStream *CallPrivate::getMediaStream (LinphoneStreamType type) const { From 19b8a88dda9a6b962207d2374f3aa4c0c3c0939c Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 29 Sep 2017 15:23:36 +0200 Subject: [PATCH 0250/2215] add operator!= to Address && refactor local-conference-event-handler --- src/address/address.cpp | 4 + src/address/address.h | 1 + .../local-conference-event-handler.cpp | 149 +++++++++++------- .../local-conference-event-handler.h | 8 +- 4 files changed, 97 insertions(+), 65 deletions(-) diff --git a/src/address/address.cpp b/src/address/address.cpp index b89631211..3956b61bb 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -67,6 +67,10 @@ bool Address::operator== (const Address &address) const { return equal(address); } +bool Address::operator!= (const Address &address) const { + return !(*this == address); +} + bool Address::operator< (const Address &address) const { return asString() < address.asString(); } diff --git a/src/address/address.h b/src/address/address.h index 5a57c2f72..9e5d90cc6 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -39,6 +39,7 @@ public: Address &operator= (const Address &src); bool operator== (const Address &address) const; + bool operator!= (const Address &address) const; bool operator< (const Address &address) const; diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index daaaba05b..d7176f80c 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -37,14 +37,22 @@ class LocalConferenceEventHandlerPrivate : public ObjectPrivate { public: void notifyFullState(string notify, LinphoneEvent *lev); void notifyAllExcept(string notify, const Address &addr); + void notifyAll(string notify); + string createNotifyFullState(); + string createNotifyParticipantAdded(const Address &addr); + string createNotifyParticipantRemoved(const Address &addr); + string createNotifyParticipantAdmined(const Address &addr, bool isAdmin); LinphoneCore *core = nullptr; LocalConference *conf = nullptr; + +private: + void sendNotify(string notify, const Address &addr); }; // ----------------------------------------------------------------------------- -void LocalConferenceEventHandlerPrivate::notifyFullState(string notify, LinphoneEvent *lev) { +static void doNotify(string notify, LinphoneEvent *lev) { LinphoneContent *content = linphone_core_create_content(lev->lc); linphone_content_set_buffer(content, notify.c_str(), strlen(notify.c_str())); linphone_event_notify(lev, content); @@ -52,46 +60,41 @@ void LocalConferenceEventHandlerPrivate::notifyFullState(string notify, Linphone linphone_event_unref(lev); } -void LocalConferenceEventHandlerPrivate::notifyAllExcept(string notify, const Address &addr) { - for (const auto &participant : conf->getParticipants()) { - if (!addr.equal(participant->getAddress())) { - LinphoneAddress *cAddr = linphone_address_new(participant->getAddress().asString().c_str()); - LinphoneEvent *lev = linphone_core_create_notify(core, cAddr, "Conference"); - linphone_address_unref(cAddr); - LinphoneContent *content = linphone_core_create_content(lev->lc); - linphone_content_set_buffer(content, notify.c_str(), strlen(notify.c_str())); - linphone_event_notify(lev, content); - linphone_content_unref(content); - linphone_event_unref(lev); - } - } -} - -// ============================================================================= - -LocalConferenceEventHandler::LocalConferenceEventHandler(LinphoneCore *core, LocalConference *localConf) : Object(*new LocalConferenceEventHandlerPrivate) { - L_D(); - xercesc::XMLPlatformUtils::Initialize(); - d->conf = localConf; - d->core = core; // conf->getCore() ? -} - -LocalConferenceEventHandler::~LocalConferenceEventHandler() { - xercesc::XMLPlatformUtils::Terminate(); +static string createNotify(ConferenceType confInfo) { + stringstream notify; + Xsd::XmlSchema::NamespaceInfomap map; + map[""].name = "urn:ietf:params:xml:ns:conference-info"; + serializeConferenceInfo(notify, confInfo, map); + return notify.str(); } // ----------------------------------------------------------------------------- -string LocalConferenceEventHandler::subscribeReceived(LinphoneEvent *lev) { - L_D(); - string entity = d->conf->getConferenceAddress()->asStringUriOnly(); +void LocalConferenceEventHandlerPrivate::notifyFullState(string notify, LinphoneEvent *lev) { + doNotify(notify, lev); +} + +void LocalConferenceEventHandlerPrivate::notifyAllExcept(string notify, const Address &addr) { + for (const auto &participant : conf->getParticipants()) { + if (addr != participant->getAddress()) { + this->sendNotify(notify, addr); + } + } +} + +void LocalConferenceEventHandlerPrivate::notifyAll(string notify) { + for (const auto &participant : conf->getParticipants()) { + this->sendNotify(notify, participant->getAddress()); + } +} + +string LocalConferenceEventHandlerPrivate::createNotifyFullState() { + string entity = this->conf->getConferenceAddress()->asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); - Xsd::XmlSchema::NamespaceInfomap map; - map[""].name = "urn:ietf:params:xml:ns:conference-info"; - for (const auto &participant : d->conf->getParticipants()) { + for (const auto &participant : this->conf->getParticipants()) { UserType user = UserType(); UserRolesType roles; user.setRoles(roles); @@ -101,15 +104,11 @@ string LocalConferenceEventHandler::subscribeReceived(LinphoneEvent *lev) { confInfo.getUsers()->getUser().push_back(user); } - stringstream notify; - serializeConferenceInfo(notify, confInfo, map); - d->notifyFullState(notify.str(), lev); - return notify.str(); + return(createNotify(confInfo)); } -string LocalConferenceEventHandler::notifyParticipantAdded(const Address &addr) { - L_D(); - string entity = d->conf->getConferenceAddress()->asStringUriOnly(); +string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded(const Address &addr) { + string entity = this->conf->getConferenceAddress()->asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -122,16 +121,11 @@ string LocalConferenceEventHandler::notifyParticipantAdded(const Address &addr) user.setState("full"); confInfo.getUsers()->getUser().push_back(user); - Xsd::XmlSchema::NamespaceInfomap map; - stringstream notify; - serializeConferenceInfo(notify, confInfo, map); - //d->notifyAllExcept(notify.str(), addr); - return notify.str(); + return(createNotify(confInfo)); } -string LocalConferenceEventHandler::notifyParticipantRemoved(const Address &addr) { - L_D(); - string entity = d->conf->getConferenceAddress()->asStringUriOnly(); +string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved(const Address &addr) { + string entity = this->conf->getConferenceAddress()->asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -141,16 +135,11 @@ string LocalConferenceEventHandler::notifyParticipantRemoved(const Address &addr user.setState("deleted"); confInfo.getUsers()->getUser().push_back(user); - Xsd::XmlSchema::NamespaceInfomap map; - stringstream notify; - serializeConferenceInfo(notify, confInfo, map); - //d->notifyAllExcept(notify.str(), addr); - return notify.str(); + return(createNotify(confInfo)); } -string LocalConferenceEventHandler::notifyParticipantSetAdmin(const Address &addr, bool isAdmin) { - L_D(); - string entity = d->conf->getConferenceAddress()->asStringUriOnly(); +string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined(const Address &addr, bool isAdmin) { + string entity = this->conf->getConferenceAddress()->asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -163,11 +152,49 @@ string LocalConferenceEventHandler::notifyParticipantSetAdmin(const Address &add user.setState("partial"); confInfo.getUsers()->getUser().push_back(user); - Xsd::XmlSchema::NamespaceInfomap map; - stringstream notify; - serializeConferenceInfo(notify, confInfo, map); - //d->notifyAllExcept(notify.str(), addr); - return notify.str(); + return(createNotify(confInfo)); +} + +void LocalConferenceEventHandlerPrivate::sendNotify(string notify, const Address &addr) { + LinphoneAddress *cAddr = linphone_address_new(addr.asString().c_str()); + LinphoneEvent *lev = linphone_core_create_notify(core, cAddr, "Conference"); + linphone_address_unref(cAddr); + doNotify(notify, lev); +} + +// ============================================================================= + +LocalConferenceEventHandler::LocalConferenceEventHandler(LinphoneCore *core, LocalConference *localConf) : Object(*new LocalConferenceEventHandlerPrivate) { + L_D(); + xercesc::XMLPlatformUtils::Initialize(); + d->conf = localConf; + d->core = core; +} + +LocalConferenceEventHandler::~LocalConferenceEventHandler() { + xercesc::XMLPlatformUtils::Terminate(); +} + +// ----------------------------------------------------------------------------- + +void LocalConferenceEventHandler::subscribeReceived(LinphoneEvent *lev) { + L_D(); + d->notifyFullState(d->createNotifyFullState(), lev); +} + +void LocalConferenceEventHandler::notifyParticipantAdded(const Address &addr) { + L_D(); + d->notifyAllExcept(d->createNotifyParticipantAdded(addr), addr); +} + +void LocalConferenceEventHandler::notifyParticipantRemoved(const Address &addr) { + L_D(); + d->notifyAllExcept(d->createNotifyParticipantRemoved(addr), addr); +} + +void LocalConferenceEventHandler::notifyParticipantSetAdmin(const Address &addr, bool isAdmin) { + L_D(); + d->notifyAll(d->createNotifyParticipantAdmined(addr, isAdmin)); } LINPHONE_END_NAMESPACE diff --git a/src/conference/local-conference-event-handler.h b/src/conference/local-conference-event-handler.h index c1d379701..f210f8251 100644 --- a/src/conference/local-conference-event-handler.h +++ b/src/conference/local-conference-event-handler.h @@ -36,10 +36,10 @@ class LocalConferenceEventHandler : public Object { LocalConferenceEventHandler(LinphoneCore *core, LocalConference *localConf); ~LocalConferenceEventHandler(); - std::string subscribeReceived(LinphoneEvent *lev); - std::string notifyParticipantAdded(const Address &addr); - std::string notifyParticipantRemoved(const Address &addr); - std::string notifyParticipantSetAdmin(const Address &addr, bool isAdmin); + void subscribeReceived(LinphoneEvent *lev); + void notifyParticipantAdded(const Address &addr); + void notifyParticipantRemoved(const Address &addr); + void notifyParticipantSetAdmin(const Address &addr, bool isAdmin); private: L_DECLARE_PRIVATE(LocalConferenceEventHandler); From 127d5aa728a421151c7cd497701181859b271978 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 29 Sep 2017 15:29:07 +0200 Subject: [PATCH 0251/2215] fix(Call): use getPrivate correctly --- src/call/call.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/call/call.cpp b/src/call/call.cpp index d1d4495b3..b474f60ee 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -55,7 +55,7 @@ shared_ptr CallPrivate::getActiveSession () const { } bool CallPrivate::getAudioMuted () const { - return static_pointer_cast(getActiveSession())->getAudioMuted(); + return static_pointer_cast(getActiveSession())->getPrivate()->getAudioMuted(); } LinphoneProxyConfig *CallPrivate::getDestProxy () const { @@ -63,11 +63,11 @@ LinphoneProxyConfig *CallPrivate::getDestProxy () const { } IceSession *CallPrivate::getIceSession () const { - return static_pointer_cast(getActiveSession())->getIceSession(); + return static_pointer_cast(getActiveSession())->getPrivate()->getIceSession(); } MediaStream *CallPrivate::getMediaStream (LinphoneStreamType type) const { - return L_GET_PRIVATE(getActiveSession(), MediaSession)->getMediaStream(type); + return static_pointer_cast(getActiveSession())->getPrivate()->getMediaStream(type); } SalOp *CallPrivate::getOp () const { @@ -75,7 +75,7 @@ SalOp *CallPrivate::getOp () const { } void CallPrivate::setAudioMuted (bool value) { - L_GET_PRIVATE(getActiveSession(), MediaSession)->setAudioMuted(value); + static_pointer_cast(getActiveSession())->getPrivate()->setAudioMuted(value); } // ----------------------------------------------------------------------------- From 96bd4b35e0bd3897b554a5f03fe93701eec624e0 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 29 Sep 2017 15:42:27 +0200 Subject: [PATCH 0252/2215] Use the correct name for the conference event package. --- coreapi/event.c | 2 +- coreapi/linphonecore.c | 2 +- src/conference/local-conference-event-handler.cpp | 2 +- src/conference/remote-conference-event-handler.cpp | 2 +- tester/conference-event-tester.cpp | 10 +++++----- tester/eventapi_tester.c | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/coreapi/event.c b/coreapi/event.c index 00adff5ec..100fa2e5c 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -84,7 +84,7 @@ static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscri lev->dir=dir; lev->op=op; lev->name=ms_strdup(name); - if (strcmp(lev->name, "Conference") == 0) + if (strcmp(lev->name, "conference") == 0) lev->internal = TRUE; sal_op_set_user_pointer(lev->op,lev); return lev; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 01e1f72e1..f80b56b43 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2123,7 +2123,7 @@ static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEve static void linphone_core_internal_subscription_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state) { if (strcasecmp(linphone_event_get_name(lev), "Presence") == 0) { linphone_friend_list_subscription_state_changed(lc, lev, state); - } else if (strcmp(linphone_event_get_name(lev), "Conference") == 0) { + } else if (strcmp(linphone_event_get_name(lev), "conference") == 0) { } } diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index d7176f80c..dd7734a47 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -157,7 +157,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined(const void LocalConferenceEventHandlerPrivate::sendNotify(string notify, const Address &addr) { LinphoneAddress *cAddr = linphone_address_new(addr.asString().c_str()); - LinphoneEvent *lev = linphone_core_create_notify(core, cAddr, "Conference"); + LinphoneEvent *lev = linphone_core_create_notify(core, cAddr, "conference"); linphone_address_unref(cAddr); doNotify(notify, lev); } diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 94aa0abd4..2acc7bbee 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -60,7 +60,7 @@ void RemoteConferenceEventHandler::subscribe(const Address &addr) { L_D(); d->confAddress = addr; LinphoneAddress *lAddr = linphone_address_new(d->confAddress.asString().c_str()); - d->lev = linphone_core_create_subscribe(d->core, lAddr, "Conference", 600); + d->lev = linphone_core_create_subscribe(d->core, lAddr, "conference", 600); linphone_address_unref(lAddr); linphone_event_set_internal(d->lev, TRUE); linphone_event_set_user_data(d->lev, this); diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index 19e392046..8dabe55a8 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -742,7 +742,7 @@ void send_first_notify() { localConf.addParticipant(bobAddr, ¶ms, false); shared_ptr alice = localConf.addParticipant(aliceAddr, ¶ms, false); alice->setAdmin(true); - LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "Conference"); + LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "conference"); string notify = localConf.getEventHandler()->subscribeReceived(lev); tester.handler->notifyReceived(notify); linphone_event_unref(lev); @@ -780,7 +780,7 @@ void send_added_notify() { Address frankAddr(frankAddrStr); bctbx_free(frankAddrStr); linphone_address_unref(cFrankAddr); - LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "Conference"); + LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "conference"); CallSessionParams params; localConf.addParticipant(bobAddr, ¶ms, false); @@ -834,7 +834,7 @@ void send_removed_notify() { localConf.addParticipant(bobAddr, ¶ms, false); shared_ptr alice = localConf.addParticipant(aliceAddr, ¶ms, false); alice->setAdmin(true); - LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "Conference"); + LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "conference"); string notify = localConf.getEventHandler()->subscribeReceived(lev); tester.handler->notifyReceived(notify); linphone_event_unref(lev); @@ -880,7 +880,7 @@ void send_admined_notify() { localConf.addParticipant(bobAddr, ¶ms, false); shared_ptr alice = localConf.addParticipant(aliceAddr, ¶ms, false); alice->setAdmin(true); - LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "Conference"); + LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "conference"); string notify = localConf.getEventHandler()->subscribeReceived(lev); tester.handler->notifyReceived(notify); linphone_event_unref(lev); @@ -927,7 +927,7 @@ void send_unadmined_notify() { localConf.addParticipant(bobAddr, ¶ms, false); shared_ptr alice = localConf.addParticipant(aliceAddr, ¶ms, false); alice->setAdmin(true); - LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "Conference"); + LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "conference"); string notify = localConf.getEventHandler()->subscribeReceived(lev); tester.handler->notifyReceived(notify); linphone_event_unref(lev); diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index 24614827f..205aa3935 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -82,7 +82,7 @@ void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, Li counters->number_of_LinphoneSubscriptionActive++; if (linphone_event_get_subscription_dir(lev)==LinphoneSubscriptionIncoming){ mgr->lev=lev; - if(strcmp(linphone_event_get_name(lev), "Conference") == 0) { + if(strcmp(linphone_event_get_name(lev), "conference") == 0) { // TODO : Get LocalConfEventHandler and call handler->subscribeReceived(lev) } else { linphone_event_notify(lev,content); From 5961e5a6aad3d454d048cc55d1e330d22e64d544 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 29 Sep 2017 15:43:14 +0200 Subject: [PATCH 0253/2215] Add the Hacks class. --- src/CMakeLists.txt | 2 ++ src/hacks/hacks.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/hacks/hacks.h | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 src/hacks/hacks.cpp create mode 100644 src/hacks/hacks.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 59d4bd5e3..0a73468af 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -85,6 +85,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES event-log/conference-participant-event.h event-log/event-log-p.h event-log/event-log.h + hacks/hacks.h logger/logger.h nat/ice-agent.h nat/stun-client.h @@ -152,6 +153,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES event-log/conference-event.cpp event-log/conference-participant-event.cpp event-log/event-log.cpp + hacks/hacks.cpp logger/logger.cpp nat/ice-agent.cpp nat/stun-client.cpp diff --git a/src/hacks/hacks.cpp b/src/hacks/hacks.cpp new file mode 100644 index 000000000..b5caeadc7 --- /dev/null +++ b/src/hacks/hacks.cpp @@ -0,0 +1,45 @@ +/* + * hacks.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include + +#include + +#include "hacks.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +// ----------------------------------------------------------------------------- + +bool Hacks::contactHasParam(const string &contact, const string ¶mName) { + // This is very ugly!!! The handling of Contact headers and addresses is a real + // crap that really needs to be reworked. Meanwhile, we cannot get the params on the + // remote contact address and need to forge and parse a contact header. + ostringstream os; + os << "Contact: " << contact; + belle_sip_header_contact_t *contactHeader = belle_sip_header_contact_parse(os.str().c_str()); + bool result = belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(contactHeader), paramName.c_str()); + belle_sip_object_unref(contactHeader); + return result; +} + +LINPHONE_END_NAMESPACE diff --git a/src/hacks/hacks.h b/src/hacks/hacks.h new file mode 100644 index 000000000..dfef46ba9 --- /dev/null +++ b/src/hacks/hacks.h @@ -0,0 +1,39 @@ +/* + * hacks.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _HACKS_H_ +#define _HACKS_H_ + +#include + +#include "linphone/utils/general.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +// This class has the purpose to centralize the temporary hacks so that they +// can be located more easily. +class Hacks { +public: + static bool contactHasParam(const std::string &contact, const std::string ¶mName); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _HACKS_H_ From 70219e4c7775cdb42fc36f6d37691d8c8343fede Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 29 Sep 2017 15:43:31 +0200 Subject: [PATCH 0254/2215] Subscribe to the conference event package only when the contact returned by the conference factory contains the "isfocus" feature tag. --- src/chat/client-group-chat-room.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 3357fc5f1..961adb590 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -22,6 +22,7 @@ #include "conference/session/call-session-p.h" #include "conference/participant-p.h" #include "content/content.h" +#include "hacks/hacks.h" #include "logger/logger.h" // ============================================================================= @@ -108,7 +109,6 @@ void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { L_D(); conferenceAddress = addr; d->setState(ChatRoom::State::Created); - eventHandler->subscribe(conferenceAddress); } void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { @@ -172,6 +172,8 @@ void ClientGroupChatRoom::onCallSessionStateChanged (const CallSession &session, Address addr(session.getRemoteContact()); addr.clean(); onConferenceCreated(addr); + if (Hacks::contactHasParam(session.getRemoteContact(), "isfocus")) + eventHandler->subscribe(conferenceAddress); } } From 86b626d3fe78e8bbc095817be36ea030c9a3c7ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Fri, 29 Sep 2017 17:19:52 +0200 Subject: [PATCH 0255/2215] Migration of Sal and SalOp into C++ classes --- console/linphonec.c | 3 +- coreapi/CMakeLists.txt | 16 +- coreapi/account_creator_private.h | 201 +++ coreapi/authentication.c | 11 +- coreapi/bellesip_sal/sal_impl.c | 1089 ------------ coreapi/bellesip_sal/sal_impl.h | 149 +- coreapi/bellesip_sal/sal_op_call.c | 1240 -------------- coreapi/bellesip_sal/sal_op_call_transfer.c | 273 --- coreapi/bellesip_sal/sal_op_events.c | 385 ----- coreapi/bellesip_sal/sal_op_impl.c | 762 +-------- coreapi/bellesip_sal/sal_op_info.c | 34 - coreapi/bellesip_sal/sal_op_message.c | 216 --- coreapi/bellesip_sal/sal_op_publish.c | 112 -- coreapi/call_log.c | 2 +- coreapi/callbacks.c | 121 +- coreapi/carddav.c | 4 +- coreapi/chat.c | 1 + coreapi/conference.cc | 2 +- coreapi/error_info.c | 6 +- coreapi/event.c | 75 +- coreapi/friend.c | 37 +- coreapi/friendlist.c | 4 +- coreapi/info.c | 6 +- coreapi/linphonecall.c | 2 +- coreapi/linphonecore.c | 185 ++- coreapi/misc.c | 2 +- coreapi/nat_policy.c | 4 +- coreapi/offeranswer.c | 1 + coreapi/presence.c | 28 +- coreapi/private.h | 248 +-- coreapi/proxy.c | 33 +- coreapi/quality_reporting.c | 1 + coreapi/sal.c | 942 ----------- coreapi/sal/call_op.cpp | 1475 +++++++++++++++++ coreapi/sal/call_op.h | 108 ++ coreapi/sal/event_op.cpp | 425 +++++ coreapi/sal/event_op.h | 74 + coreapi/sal/message_op.cpp | 88 + coreapi/sal/message_op.h | 47 + coreapi/sal/message_op_interface.h | 38 + .../sal_op_presence.c => sal/presence_op.cpp} | 324 ++-- coreapi/sal/presence_op.h | 58 + .../register_op.cpp} | 149 +- coreapi/sal/register_op.h | 43 + coreapi/sal/sal.c | 106 ++ coreapi/sal/sal.cpp | 976 +++++++++++ coreapi/sal/sal.h | 477 ++---- coreapi/sal/sal.hpp | 319 ++++ coreapi/sal/sal_op.cpp | 1025 ++++++++++++ coreapi/sal/sal_op.h | 258 +++ coreapi/tester_utils.cpp | 101 ++ coreapi/tester_utils.h | 154 ++ coreapi/vcard.cc | 3 +- src/c-wrapper/api/c-call.cpp | 20 +- src/c-wrapper/api/c-chat-message.cpp | 1 + src/call/call-p.h | 2 +- src/call/call.cpp | 4 +- src/call/call.h | 2 +- src/chat/chat-room.cpp | 37 +- src/chat/client-group-chat-room.cpp | 2 +- src/chat/is-composing.cpp | 12 +- src/conference/params/call-session-params.h | 1 + src/conference/session/call-session-p.h | 5 +- src/conference/session/call-session.cpp | 104 +- src/conference/session/call-session.h | 3 +- src/conference/session/media-session-p.h | 9 +- src/conference/session/media-session.cpp | 138 +- src/conference/session/media-session.h | 2 +- src/nat/ice-agent.cpp | 4 +- tester/account_creator_tester.c | 16 +- tester/accountmanager.c | 9 +- tester/audio_bypass_tester.c | 7 +- tester/call_multi_tester.c | 7 +- tester/call_single_tester.c | 145 +- tester/call_video_tester.c | 29 +- tester/certificates/client/cert.pem | 40 +- tester/complex_sip_case_tester.c | 1 - tester/dtmf_tester.c | 5 +- tester/eventapi_tester.c | 11 +- tester/flexisip_tester.c | 15 +- tester/liblinphone_tester.c | 1 - tester/liblinphone_tester.h | 1 + tester/log_collection_tester.c | 1 - tester/message_tester.c | 69 +- tester/offeranswer_tester.c | 1 - tester/presence_server_tester.c | 72 +- tester/presence_tester.c | 11 +- tester/quality_reporting_tester.c | 17 +- tester/register_tester.c | 71 +- tester/remote_provisioning_tester.c | 13 +- tester/setup_tester.c | 3 +- tester/stun_tester.c | 1 - tester/tester.c | 13 +- tester/tunnel_tester.c | 1 - tester/vcard_tester.c | 76 +- tester/video_tester.c | 1 - 96 files changed, 6659 insertions(+), 6767 deletions(-) create mode 100644 coreapi/account_creator_private.h delete mode 100644 coreapi/bellesip_sal/sal_op_call.c delete mode 100644 coreapi/bellesip_sal/sal_op_call_transfer.c delete mode 100644 coreapi/bellesip_sal/sal_op_events.c delete mode 100644 coreapi/bellesip_sal/sal_op_info.c delete mode 100644 coreapi/bellesip_sal/sal_op_message.c delete mode 100644 coreapi/bellesip_sal/sal_op_publish.c delete mode 100644 coreapi/sal.c create mode 100644 coreapi/sal/call_op.cpp create mode 100644 coreapi/sal/call_op.h create mode 100644 coreapi/sal/event_op.cpp create mode 100644 coreapi/sal/event_op.h create mode 100644 coreapi/sal/message_op.cpp create mode 100644 coreapi/sal/message_op.h create mode 100644 coreapi/sal/message_op_interface.h rename coreapi/{bellesip_sal/sal_op_presence.c => sal/presence_op.cpp} (59%) create mode 100644 coreapi/sal/presence_op.h rename coreapi/{bellesip_sal/sal_op_registration.c => sal/register_op.cpp} (51%) create mode 100644 coreapi/sal/register_op.h create mode 100644 coreapi/sal/sal.cpp create mode 100644 coreapi/sal/sal.hpp create mode 100644 coreapi/sal/sal_op.cpp create mode 100644 coreapi/sal/sal_op.h create mode 100644 coreapi/tester_utils.cpp create mode 100644 coreapi/tester_utils.h diff --git a/console/linphonec.c b/console/linphonec.c index edcd128a8..ca556536b 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -28,7 +28,6 @@ #include #include #include -#include "private.h" /*coreapi/private.h, needed for LINPHONE_VERSION */ #endif /*_WIN32_WCE*/ #include #include @@ -790,7 +789,7 @@ linphonec_prompt_for_auth_final(LinphoneCore *lc) pending_auth=auth_stack.elem[auth_stack.nitems-1]; snprintf(auth_prompt, 256, "Password for %s on %s: ", - pending_auth->username, pending_auth->realm); + linphone_auth_info_get_username(pending_auth), linphone_auth_info_get_realm(pending_auth)); printf("\n"); #ifdef HAVE_READLINE diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index b1f95067c..b6b473113 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -56,15 +56,7 @@ set(LINPHONE_SOURCE_FILES_C authentication.c bellesip_sal/sal_address_impl.c bellesip_sal/sal_impl.c - bellesip_sal/sal_op_call.c - bellesip_sal/sal_op_call_transfer.c - bellesip_sal/sal_op_events.c bellesip_sal/sal_op_impl.c - bellesip_sal/sal_op_info.c - bellesip_sal/sal_op_message.c - bellesip_sal/sal_op_presence.c - bellesip_sal/sal_op_publish.c - bellesip_sal/sal_op_registration.c bellesip_sal/sal_sdp.c buffer.c callbacks.c @@ -119,6 +111,14 @@ set(LINPHONE_SOURCE_FILES_C ) set(LINPHONE_SOURCE_FILES_CXX conference.cc + sal/call_op.cpp + sal/event_op.cpp + sal/message_op.cpp + sal/presence_op.cpp + sal/register_op.cpp + sal/sal.cpp + sal/sal_op.cpp + tester_utils.cpp ) set(LINPHONE_INCLUDE_DIRS ${LINPHONE_INCLUDE_DIRS}) if(ANDROID) diff --git a/coreapi/account_creator_private.h b/coreapi/account_creator_private.h new file mode 100644 index 000000000..a848d7ccb --- /dev/null +++ b/coreapi/account_creator_private.h @@ -0,0 +1,201 @@ +/* +account_creator.h +Copyright (C) 2017 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _ACCOUNT_CREATOR_PRIVATE_H_ +#define _ACCOUNT_CREATOR_PRIVATE_H_ + +#include "linphone/defs.h" +#include +#include "linphone/account_creator_service.h" +#include "linphone/account_creator.h" + +struct _LinphoneAccountCreatorService { + belle_sip_object_t base; + void *user_data; + + LinphoneAccountCreatorRequestFunc account_creator_service_constructor_cb; /**< Constructor */ + LinphoneAccountCreatorRequestFunc account_creator_service_destructor_cb; /**< Destructor */ + + LinphoneAccountCreatorRequestFunc create_account_request_cb; /**< Request to create account */ + LinphoneAccountCreatorRequestFunc is_account_exist_request_cb; /**< Request to know if account exist */ + + LinphoneAccountCreatorRequestFunc activate_account_request_cb; /**< Request to activate account */ + LinphoneAccountCreatorRequestFunc is_account_activated_request_cb; /**< Request to know if account is activated */ + + LinphoneAccountCreatorRequestFunc link_account_request_cb; /**< Request to link account with an alias */ + LinphoneAccountCreatorRequestFunc activate_alias_request_cb; /**< Request to activate the link of alias */ + LinphoneAccountCreatorRequestFunc is_alias_used_request_cb; /**< Request to know if alias is used */ + LinphoneAccountCreatorRequestFunc is_account_linked_request_cb; /**< Request to know if account is linked with an alias */ + + LinphoneAccountCreatorRequestFunc recover_account_request_cb; /**< Request to recover account */ + LinphoneAccountCreatorRequestFunc update_account_request_cb; /**< Request to update account */ +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneAccountCreatorService); + +struct _LinphoneAccountCreatorCbs { + belle_sip_object_t base; + void *user_data; + + LinphoneAccountCreatorCbsStatusCb create_account_response_cb; /**< Response of create_account request */ + LinphoneAccountCreatorCbsStatusCb is_account_exist_response_cb; /**< Response of is_account_exist request */ + + LinphoneAccountCreatorCbsStatusCb activate_account_response_cb; /**< Response of activate_account request */ + LinphoneAccountCreatorCbsStatusCb is_account_activated_response_cb; /**< Response of is_account_activated request */ + + LinphoneAccountCreatorCbsStatusCb link_account_response_cb; /**< Response of link_account request */ + LinphoneAccountCreatorCbsStatusCb activate_alias_response_cb; /**< Response of activation alias */ + LinphoneAccountCreatorCbsStatusCb is_alias_used_response_cb; /**< Response of is_alias_used request */ + LinphoneAccountCreatorCbsStatusCb is_account_linked_response_cb; /**< Response of is_account_linked request */ + + LinphoneAccountCreatorCbsStatusCb recover_account_response_cb; /**< Response of recover_account request */ + LinphoneAccountCreatorCbsStatusCb update_account_response_cb; /**< Response of update_account request */ +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneAccountCreatorCbs); + +struct _LinphoneAccountCreator { + belle_sip_object_t base; + void *user_data; + LinphoneCore *core; + + /* AccountCreator */ + LinphoneAccountCreatorService *service; /**< Account creator service */ + LinphoneAccountCreatorCbs *cbs; /**< Account creator cbs */ + LinphoneXmlRpcSession *xmlrpc_session; /**< XML-RPC session */ + LinphoneProxyConfig *proxy_cfg; /**< Default proxy config */ + + /* User */ + char *username; /**< Username */ + char *display_name; /**< Display name */ + /* Password */ + char *password; /**< Plain text password */ + char *ha1; /**< Hash password */ + /* Phone Number(Alias) */ + char *phone_number; /**< User phone number*/ + char *phone_country_code; /**< User phone number country code */ + /* Email(Alias) */ + char *email; /**< User email */ + /* Misc */ + char *language; /**< User language */ + char *activation_code; /**< Account validation code */ + char *domain; /**< Domain */ + LinphoneTransportType transport; /**< Transport used */ + + /* Deprecated */ + char *route; +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneAccountCreator); + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Account creator custom to set Linphone default values + * @param[in] creator LinphoneAccountCreator object + * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_constructor_linphone(LinphoneAccountCreator *creator); + +/** + * Send an XML-RPC request to test the existence of a Linphone account. + * @param[in] creator LinphoneAccountCreator object + * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_is_account_exist_linphone(LinphoneAccountCreator *creator); + +/** + * Send an XML-RPC request to create a Linphone account. + * @param[in] creator LinphoneAccountCreator object + * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_create_account_linphone(LinphoneAccountCreator *creator); + +/** + * Send an XML-RPC request to activate a Linphone account with phone number. + * @param[in] creator LinphoneAccountCreator object + * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_activate_account_linphone(LinphoneAccountCreator *creator); + +/** + * Send an XML-RPC request to activate a Linphone account with email. + * @param[in] creator LinphoneAccountCreator object + * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_activate_email_account_linphone(LinphoneAccountCreator *creator); + +/** + * Send an XML-RPC request to test the validation of a Linphone account. + * @param[in] creator LinphoneAccountCreator object + * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_is_account_activated_linphone(LinphoneAccountCreator *creator); + +/** + * Send an XML-RPC request to test the existence a phone number with a Linphone account. + * @param[in] creator LinphoneAccountCreator object + * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_is_phone_number_used_linphone(LinphoneAccountCreator *creator); + +/** + * Send an XML-RPC request to link a phone number with a Linphone account. + * @param[in] creator LinphoneAccountCreator object + * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_link_phone_number_with_account_linphone(LinphoneAccountCreator *creator); + +/** + * Send an XML-RPC request to activate the link of a phone number with a Linphone account. + * @param[in] creator LinphoneAccountCreator object + * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_activate_phone_number_link_linphone(LinphoneAccountCreator *creator); + +/** + * Send an XML-RPC request to a Linphone account with the phone number. + * @param[in] creator LinphoneAccountCreator object + * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_recover_phone_account_linphone(LinphoneAccountCreator *creator); + +/** + * Send an XML-RPC request to ask if an account is linked with a phone number + * @param[in] creator LinphoneAccountCreator object + * @return if this account is linked with a phone number +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_is_account_linked_linphone(LinphoneAccountCreator *creator); + +/** + * Send an XML-RPC request to ask if an account is linked with a phone number + * @param[in] creator LinphoneAccountCreator object + * @param[in] new_pwd const char * : new password for the account creator + * @return LinphoneAccountCreatorStatusRequestOk if everything is OK, or a specific error otherwise. +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_update_password_linphone(LinphoneAccountCreator *creator); + +#ifdef __cplusplus +} +#endif + +#endif // _ACCOUNT_CREATOR_PRIVATE_H_ diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 8fdf050c4..c79769527 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -24,9 +24,12 @@ #include "linphone/core.h" #include "linphone/lpconfig.h" +#include "sal/sal.hpp" #include "c-wrapper/c-wrapper.h" +using namespace LINPHONE_NAMESPACE; + static void _linphone_auth_info_uninit(LinphoneAuthInfo *obj); static void _linphone_auth_info_copy(LinphoneAuthInfo *dst, const LinphoneAuthInfo *src); @@ -434,10 +437,10 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) lc->auth_info=bctbx_list_append(lc->auth_info,linphone_auth_info_clone(info)); /* retry pending authentication operations */ - for(l=elem=sal_get_pending_auths(lc->sal);elem!=NULL;elem=elem->next){ + for(l=elem=lc->sal->get_pending_auths();elem!=NULL;elem=elem->next){ SalOp *op=(SalOp*)elem->data; LinphoneAuthInfo *ai; - const SalAuthInfo *req_sai=sal_op_get_auth_requested(op); + const SalAuthInfo *req_sai=op->get_auth_requested(); ai=(LinphoneAuthInfo*)_linphone_core_find_auth_info(lc,req_sai->realm,req_sai->username,req_sai->domain, FALSE); if (ai){ SalAuthInfo sai; @@ -456,12 +459,12 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) } /*proxy case*/ for (proxy=(bctbx_list_t*)linphone_core_get_proxy_config_list(lc);proxy!=NULL;proxy=proxy->next) { - if (proxy->data == sal_op_get_user_pointer(op)) { + if (proxy->data == op->get_user_pointer()) { linphone_proxy_config_set_state((LinphoneProxyConfig*)(proxy->data),LinphoneRegistrationProgress,"Authentication..."); break; } } - sal_op_authenticate(op,&sai); + op->authenticate(&sai); restarted_op_count++; } } diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index da8ce0f7d..7803b92a5 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -23,41 +23,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "config.h" #endif -/* -rfc3323 -4.2 Expressing Privacy Preferences -When a Privacy header is constructed, it MUST consist of either the - value 'none', or one or more of the values 'user', 'header' and - 'session' (each of which MUST appear at most once) which MAY in turn - be followed by the 'critical' indicator. - */ -void sal_op_set_privacy_from_message(SalOp* op,belle_sip_message_t* msg) { - belle_sip_header_privacy_t* privacy = belle_sip_message_get_header_by_type(msg,belle_sip_header_privacy_t); - if (!privacy) { - sal_op_set_privacy(op,SalPrivacyNone); - } else { - belle_sip_list_t* privacy_list=belle_sip_header_privacy_get_privacy(privacy); - sal_op_set_privacy(op,0); - for (;privacy_list!=NULL;privacy_list=privacy_list->next) { - char* privacy_value=(char*)privacy_list->data; - if(strcmp(sal_privacy_to_string(SalPrivacyCritical),privacy_value) == 0) - sal_op_set_privacy(op,sal_op_get_privacy(op)|SalPrivacyCritical); - if(strcmp(sal_privacy_to_string(SalPrivacyHeader),privacy_value) == 0) - sal_op_set_privacy(op,sal_op_get_privacy(op)|SalPrivacyHeader); - if(strcmp(sal_privacy_to_string(SalPrivacyId),privacy_value) == 0) - sal_op_set_privacy(op,sal_op_get_privacy(op)|SalPrivacyId); - if(strcmp(sal_privacy_to_string(SalPrivacyNone),privacy_value) == 0) { - sal_op_set_privacy(op,SalPrivacyNone); - break; - } - if(strcmp(sal_privacy_to_string(SalPrivacySession),privacy_value) == 0) - sal_op_set_privacy(op,sal_op_get_privacy(op)|SalPrivacySession); - if(strcmp(sal_privacy_to_string(SalPrivacyUser),privacy_value) == 0) - sal_op_set_privacy(op,sal_op_get_privacy(op)|SalPrivacyUser); - } - } -} -static void set_tls_properties(Sal *ctx); void sal_enable_log(){ sal_set_log_level(ORTP_MESSAGE); @@ -93,817 +58,6 @@ void sal_set_log_handler(BctbxLogFunc log_handler) { _belle_sip_log_handler = log_handler; belle_sip_set_log_handler(log_handler); } -void sal_add_pending_auth(Sal *sal, SalOp *op){ - if (bctbx_list_find(sal->pending_auths,op)==NULL){ - sal->pending_auths=bctbx_list_append(sal->pending_auths,op); - op->has_auth_pending=TRUE; - } -} - -void sal_remove_pending_auth(Sal *sal, SalOp *op){ - if (op->has_auth_pending){ - op->has_auth_pending=FALSE; - if (bctbx_list_find(sal->pending_auths,op)){ - sal->pending_auths=bctbx_list_remove(sal->pending_auths,op); - } - } -} - -void sal_process_authentication(SalOp *op) { - belle_sip_request_t* initial_request=belle_sip_transaction_get_request((belle_sip_transaction_t*)op->pending_auth_transaction); - belle_sip_request_t* new_request; - bool_t is_within_dialog=FALSE; - belle_sip_list_t* auth_list=NULL; - belle_sip_auth_event_t* auth_event; - belle_sip_response_t *response=belle_sip_transaction_get_response((belle_sip_transaction_t*)op->pending_auth_transaction); - belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(initial_request,belle_sip_header_from_t); - belle_sip_uri_t *from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)from); - - if (strcasecmp(belle_sip_uri_get_host(from_uri),"anonymous.invalid")==0){ - /*prefer using the from from the SalOp*/ - from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)sal_op_get_from_address(op)); - } - - if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) { - new_request = belle_sip_dialog_create_request_from(op->dialog,initial_request); - if (!new_request) - new_request = belle_sip_dialog_create_queued_request_from(op->dialog,initial_request); - is_within_dialog=TRUE; - } else { - new_request=initial_request; - belle_sip_message_remove_header(BELLE_SIP_MESSAGE(new_request),BELLE_SIP_AUTHORIZATION); - belle_sip_message_remove_header(BELLE_SIP_MESSAGE(new_request),BELLE_SIP_PROXY_AUTHORIZATION); - } - if (new_request==NULL) { - ms_error("sal_process_authentication() op=[%p] cannot obtain new request from dialog.",op); - return; - } - - if (belle_sip_provider_add_authorization(op->base.root->prov,new_request,response,from_uri,&auth_list,op->base.realm)) { - if (is_within_dialog) { - sal_op_send_request(op,new_request); - } else { - sal_op_resend_request(op,new_request); - } - sal_remove_pending_auth(op->base.root,op); - }else { - belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(response,belle_sip_header_from_t); - char *tmp=belle_sip_object_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from))); - ms_message("No auth info found for [%s]",tmp); - belle_sip_free(tmp); - sal_add_pending_auth(op->base.root,op); - - if (is_within_dialog) { - belle_sip_object_unref(new_request); - } - } - /*always store auth info, for case of wrong credential*/ - if (op->auth_info) { - sal_auth_info_delete(op->auth_info); - op->auth_info=NULL; - } - if (auth_list){ - auth_event=(belle_sip_auth_event_t*)(auth_list->data); - op->auth_info=sal_auth_info_create(auth_event); - belle_sip_list_free_with_data(auth_list,(void (*)(void*))belle_sip_auth_event_destroy); - } -} - -static void process_dialog_terminated(void *sal, const belle_sip_dialog_terminated_event_t *event){ - belle_sip_dialog_t* dialog = belle_sip_dialog_terminated_event_get_dialog(event); - SalOp* op = reinterpret_cast(belle_sip_dialog_get_application_data(dialog)); - if (op && op->callbacks && op->callbacks->process_dialog_terminated) { - op->callbacks->process_dialog_terminated(op,event); - } else { - ms_error("sal process_dialog_terminated no op found for this dialog [%p], ignoring",dialog); - } -} - -static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ - belle_sip_client_transaction_t*client_transaction; - SalOp* op; - if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(belle_sip_io_error_event_get_source(event),belle_sip_client_transaction_t)) { - client_transaction=BELLE_SIP_CLIENT_TRANSACTION(belle_sip_io_error_event_get_source(event)); - op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); - /*also reset auth count on IO error*/ - op->auth_requests=0; - if (op->callbacks && op->callbacks->process_io_error) { - op->callbacks->process_io_error(op,event); - } - } else { - /*ms_error("sal process_io_error not implemented yet for non transaction");*/ - /*nop, because already handle at transaction layer*/ - } -} - -static void process_request_event(void *ud, const belle_sip_request_event_t *event) { - Sal *sal=(Sal*)ud; - SalOp* op=NULL; - belle_sip_request_t* req = belle_sip_request_event_get_request(event); - belle_sip_dialog_t* dialog=belle_sip_request_event_get_dialog(event); - belle_sip_header_address_t* origin_address; - belle_sip_header_address_t* address=NULL; - belle_sip_header_from_t* from_header; - belle_sip_header_to_t* to; - belle_sip_header_diversion_t* diversion; - belle_sip_response_t* resp; - belle_sip_header_t *evh; - const char *method=belle_sip_request_get_method(req); - belle_sip_header_contact_t* remote_contact = belle_sip_message_get_header_by_type(req, belle_sip_header_contact_t); - - from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); - - if (dialog) { - op=(SalOp*)belle_sip_dialog_get_application_data(dialog); - - if (op == NULL && strcmp("NOTIFY",method) == 0) { - /*special case for Dialog created by notify mathing subscribe*/ - belle_sip_transaction_t * sub_trans = belle_sip_dialog_get_last_transaction(dialog); - op = (SalOp*)belle_sip_transaction_get_application_data(sub_trans); - } - if (op==NULL || op->state==SalOpStateTerminated){ - ms_warning("Receiving request for null or terminated op [%p], ignored",op); - return; - } - }else{ - /*handle the case where we are receiving a request with to tag but it is not belonging to any dialog*/ - belle_sip_header_to_t *to = belle_sip_message_get_header_by_type(req, belle_sip_header_to_t); - if ((strcmp("INVITE",method)==0 || strcmp("NOTIFY",method)==0) && (belle_sip_header_to_get_tag(to) != NULL)) { - ms_warning("Receiving %s with to-tag but no know dialog here. Rejecting.", method); - resp=belle_sip_response_create_from_request(req,481); - belle_sip_provider_send_response(sal->prov,resp); - return; - /* by default (eg. when a to-tag is present), out of dialog ACK are automatically - handled in lower layers (belle-sip) but in case it misses, it will be forwarded to us */ - } else if (strcmp("ACK",method)==0 && (belle_sip_header_to_get_tag(to) == NULL)) { - ms_warning("Receiving ACK without to-tag but no know dialog here. Ignoring"); - return; - } - - if (strcmp("INVITE",method)==0) { - op=sal_op_new(sal); - op->dir=SalOpDirIncoming; - sal_op_call_fill_cbs(op); - }else if ((strcmp("SUBSCRIBE",method)==0 || strcmp("NOTIFY",method)==0) && (evh=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Event"))!=NULL) { - op=sal_op_new(sal); - op->dir=SalOpDirIncoming; - if (strncmp(belle_sip_header_get_unparsed_value(evh),"presence",strlen("presence"))==0){ - sal_op_presence_fill_cbs(op); - }else - sal_op_subscribe_fill_cbs(op); - }else if (strcmp("MESSAGE",method)==0) { - op=sal_op_new(sal); - op->dir=SalOpDirIncoming; - sal_op_message_fill_cbs(op); - }else if (strcmp("OPTIONS",method)==0) { - resp=belle_sip_response_create_from_request(req,200); - belle_sip_provider_send_response(sal->prov,resp); - return; - }else if (strcmp("INFO",method)==0) { - resp=belle_sip_response_create_from_request(req,481);/*INFO out of call dialogs are not allowed*/ - belle_sip_provider_send_response(sal->prov,resp); - return; - }else if (strcmp("BYE",method)==0) { - resp=belle_sip_response_create_from_request(req,481);/*out of dialog BYE */ - belle_sip_provider_send_response(sal->prov,resp); - return; - }else if (strcmp("CANCEL",method)==0) { - resp=belle_sip_response_create_from_request(req,481);/*out of dialog CANCEL */ - belle_sip_provider_send_response(sal->prov,resp); - return; - }else if (sal->enable_test_features && strcmp("PUBLISH",method)==0) { - resp=belle_sip_response_create_from_request(req,200);/*out of dialog PUBLISH */ - belle_sip_message_add_header((belle_sip_message_t*)resp,belle_sip_header_create("SIP-Etag","4441929FFFZQOA")); - belle_sip_provider_send_response(sal->prov,resp); - return; - }else { - ms_error("sal process_request_event not implemented yet for method [%s]",belle_sip_request_get_method(req)); - resp=belle_sip_response_create_from_request(req,405); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp) - ,BELLE_SIP_HEADER(belle_sip_header_allow_create("INVITE, CANCEL, ACK, BYE, SUBSCRIBE, NOTIFY, MESSAGE, OPTIONS, INFO"))); - belle_sip_provider_send_response(sal->prov,resp); - return; - } - } - - if (!op->base.from_address) { - if (belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))) - address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) - ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); - else if ((belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(from_header)))) - address=belle_sip_header_address_create2(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) - ,belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); - else - ms_error("Cannot not find from uri from request [%p]",req); - sal_op_set_from_address(op,(SalAddress*)address); - belle_sip_object_unref(address); - } - - if( remote_contact ){ - __sal_op_set_remote_contact(op, belle_sip_header_get_unparsed_value(BELLE_SIP_HEADER(remote_contact))); - } - - if (!op->base.to_address) { - to=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_to_t); - if (belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to))) - address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(to)) - ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to))); - else if ((belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(to)))) - address=belle_sip_header_address_create2(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(to)) - ,belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(to))); - else - ms_error("Cannot not find to uri from request [%p]",req); - - sal_op_set_to_address(op,(SalAddress*)address); - belle_sip_object_unref(address); - } - - if(!op->base.diversion_address){ - diversion=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_diversion_t); - if (diversion) { - if (belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(diversion))) - address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(diversion)) - ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(diversion))); - else if ((belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(diversion)))) - address=belle_sip_header_address_create2(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(diversion)) - ,belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(diversion))); - else - ms_warning("Cannot not find diversion header from request [%p]",req); - if (address) { - sal_op_set_diversion_address(op,(SalAddress*)address); - belle_sip_object_unref(address); - } - } - } - - if (!op->base.origin) { - /*set origin uri*/ - origin_address=belle_sip_header_address_create(NULL,belle_sip_request_extract_origin(req)); - __sal_op_set_network_origin_address(op,(SalAddress*)origin_address); - belle_sip_object_unref(origin_address); - } - if (!op->base.remote_ua) { - sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(req)); - } - - if (!op->base.call_id) { - op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_call_id_t)))); - } - /*It is worth noting that proxies can (and - will) remove this header field*/ - sal_op_set_privacy_from_message(op,(belle_sip_message_t*)req); - - sal_op_assign_recv_headers(op,(belle_sip_message_t*)req); - if (op->callbacks && op->callbacks->process_request_event) { - op->callbacks->process_request_event(op,event); - } else { - ms_error("sal process_request_event not implemented yet"); - } - -} - -static void process_response_event(void *user_ctx, const belle_sip_response_event_t *event){ - belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); - belle_sip_response_t* response = belle_sip_response_event_get_response(event); - int response_code = belle_sip_response_get_status_code(response); - - if (!client_transaction) { - ms_warning("Discarding stateless response [%i]",response_code); - return; - } else { - SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); - belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); - belle_sip_header_contact_t* remote_contact = belle_sip_message_get_header_by_type(response, belle_sip_header_contact_t); - - if (op->state == SalOpStateTerminated) { - belle_sip_message("Op [%p] is terminated, nothing to do with this [%i]", op, response_code); - return; - } - /*do it all the time, since we can receive provisional responses from a different instance than the final one*/ - sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response)); - - if(remote_contact) { - __sal_op_set_remote_contact(op, belle_sip_header_get_unparsed_value(BELLE_SIP_HEADER(remote_contact))); - } - - if (!op->base.call_id) { - op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(response), belle_sip_header_call_id_t)))); - } - - sal_op_assign_recv_headers(op,(belle_sip_message_t*)response); - - if (op->callbacks && op->callbacks->process_response_event) { - /*handle authorization*/ - switch (response_code) { - case 200: - break; - case 401: - case 407: - if (op->state == SalOpStateTerminating && strcmp("BYE",belle_sip_request_get_method(request))!=0) { - /*only bye are completed*/ - belle_sip_message("Op is in state terminating, nothing else to do "); - } else { - if (op->pending_auth_transaction){ - belle_sip_object_unref(op->pending_auth_transaction); - op->pending_auth_transaction=NULL; - } - if (++op->auth_requests > 2) { - ms_warning("Auth info cannot be found for op [%s/%s] after 2 attempts, giving up",sal_op_get_from(op) - ,sal_op_get_to(op)); - op->base.root->callbacks.auth_failure(op,op->auth_info); - sal_remove_pending_auth(op->base.root,op); - } else { - op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction); - sal_process_authentication(op); - return; - } - } - break; - case 403: - if (op->auth_info) op->base.root->callbacks.auth_failure(op,op->auth_info); - break; - } - if (response_code >= 180 && response_code !=401 && response_code !=407 && response_code !=403) { - /*not an auth request*/ - op->auth_requests=0; - } - op->callbacks->process_response_event(op,event); - } else { - ms_error("Unhandled event response [%p]",event); - } - } -} - -static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { - belle_sip_client_transaction_t* client_transaction = belle_sip_timeout_event_get_client_transaction(event); - SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); - if (op && op->callbacks && op->callbacks->process_timeout) { - op->callbacks->process_timeout(op,event); - } else { - ms_error("Unhandled event timeout [%p]",event); - } -} - -static void process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { - belle_sip_client_transaction_t* client_transaction = belle_sip_transaction_terminated_event_get_client_transaction(event); - belle_sip_server_transaction_t* server_transaction = belle_sip_transaction_terminated_event_get_server_transaction(event); - belle_sip_transaction_t* trans; - SalOp* op; - - if(client_transaction) - trans=BELLE_SIP_TRANSACTION(client_transaction); - else - trans=BELLE_SIP_TRANSACTION(server_transaction); - - op = (SalOp*)belle_sip_transaction_get_application_data(trans); - if (op && op->callbacks && op->callbacks->process_transaction_terminated) { - op->callbacks->process_transaction_terminated(op,event); - } else { - ms_message("Unhandled transaction terminated [%p]",trans); - } - if (op) { - sal_op_unref(op); /*because every transaction ref op*/ - belle_sip_transaction_set_application_data(trans,NULL); /*no longuer reference something we do not ref to avoid futur access of a released op*/ - } -} - - -static void process_auth_requested(void *sal, belle_sip_auth_event_t *event) { - SalAuthInfo* auth_info = sal_auth_info_create(event); - ((Sal*)sal)->callbacks.auth_requested(reinterpret_cast(sal),auth_info); - belle_sip_auth_event_set_passwd(event,(const char*)auth_info->password); - belle_sip_auth_event_set_ha1(event,(const char*)auth_info->ha1); - belle_sip_auth_event_set_userid(event,(const char*)auth_info->userid); - belle_sip_auth_event_set_signing_key(event,(belle_sip_signing_key_t *)auth_info->key); - belle_sip_auth_event_set_client_certificates_chain(event,(belle_sip_certificates_chain_t* )auth_info->certificates); - sal_auth_info_delete(auth_info); -} - -Sal * sal_init(MSFactory *factory){ - belle_sip_listener_callbacks_t listener_callbacks; - Sal * sal=ms_new0(Sal,1); - - /*belle_sip_object_enable_marshal_check(TRUE);*/ - sal->auto_contacts=TRUE; - sal->factory = factory; - /*first create the stack, which initializes the belle-sip object's pool for this thread*/ - sal->stack = belle_sip_stack_new(NULL); - - sal->user_agent=belle_sip_header_user_agent_new(); -#if defined(PACKAGE_NAME) && defined(LIBLINPHONE_VERSION) - belle_sip_header_user_agent_add_product(sal->user_agent, PACKAGE_NAME "/" LIBLINPHONE_VERSION); -#else - belle_sip_header_user_agent_add_product(sal->user_agent, "Unknown"); -#endif - sal_append_stack_string_to_user_agent(sal); - belle_sip_object_ref(sal->user_agent); - - sal->prov = belle_sip_stack_create_provider(sal->stack,NULL); - sal_nat_helper_enable(sal,TRUE); - memset(&listener_callbacks,0,sizeof(listener_callbacks)); - listener_callbacks.process_dialog_terminated=process_dialog_terminated; - listener_callbacks.process_io_error=process_io_error; - listener_callbacks.process_request_event=process_request_event; - listener_callbacks.process_response_event=process_response_event; - listener_callbacks.process_timeout=process_timeout; - listener_callbacks.process_transaction_terminated=process_transaction_terminated; - listener_callbacks.process_auth_requested=process_auth_requested; - sal->listener=belle_sip_listener_create_from_callbacks(&listener_callbacks,sal); - belle_sip_provider_add_sip_listener(sal->prov,sal->listener); - sal->tls_verify=TRUE; - sal->tls_verify_cn=TRUE; - sal->refresher_retry_after=60000; /*default value in ms*/ - sal->enable_sip_update=TRUE; - sal->pending_trans_checking=TRUE; - sal->ssl_config = NULL; - return sal; -} - -void sal_set_user_pointer(Sal *sal, void *user_data){ - sal->up=user_data; -} - -void *sal_get_user_pointer(const Sal *sal){ - return sal->up; -} - -static void unimplemented_stub(void){ - ms_warning("Unimplemented SAL callback"); -} - -void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ - memcpy(&ctx->callbacks,cbs,sizeof(*cbs)); - if (ctx->callbacks.call_received==NULL) - ctx->callbacks.call_received=(SalOnCallReceived)unimplemented_stub; - if (ctx->callbacks.call_ringing==NULL) - ctx->callbacks.call_ringing=(SalOnCallRinging)unimplemented_stub; - if (ctx->callbacks.call_accepted==NULL) - ctx->callbacks.call_accepted=(SalOnCallAccepted)unimplemented_stub; - if (ctx->callbacks.call_failure==NULL) - ctx->callbacks.call_failure=(SalOnCallFailure)unimplemented_stub; - if (ctx->callbacks.call_terminated==NULL) - ctx->callbacks.call_terminated=(SalOnCallTerminated)unimplemented_stub; - if (ctx->callbacks.call_released==NULL) - ctx->callbacks.call_released=(SalOnCallReleased)unimplemented_stub; - if (ctx->callbacks.call_updating==NULL) - ctx->callbacks.call_updating=(SalOnCallUpdating)unimplemented_stub; - if (ctx->callbacks.auth_failure==NULL) - ctx->callbacks.auth_failure=(SalOnAuthFailure)unimplemented_stub; - if (ctx->callbacks.register_success==NULL) - ctx->callbacks.register_success=(SalOnRegisterSuccess)unimplemented_stub; - if (ctx->callbacks.register_failure==NULL) - ctx->callbacks.register_failure=(SalOnRegisterFailure)unimplemented_stub; - if (ctx->callbacks.dtmf_received==NULL) - ctx->callbacks.dtmf_received=(SalOnDtmfReceived)unimplemented_stub; - if (ctx->callbacks.notify==NULL) - ctx->callbacks.notify=(SalOnNotify)unimplemented_stub; - if (ctx->callbacks.subscribe_received==NULL) - ctx->callbacks.subscribe_received=(SalOnSubscribeReceived)unimplemented_stub; - if (ctx->callbacks.incoming_subscribe_closed==NULL) - ctx->callbacks.incoming_subscribe_closed=(SalOnIncomingSubscribeClosed)unimplemented_stub; - if (ctx->callbacks.parse_presence_requested==NULL) - ctx->callbacks.parse_presence_requested=(SalOnParsePresenceRequested)unimplemented_stub; - if (ctx->callbacks.convert_presence_to_xml_requested==NULL) - ctx->callbacks.convert_presence_to_xml_requested=(SalOnConvertPresenceToXMLRequested)unimplemented_stub; - if (ctx->callbacks.notify_presence==NULL) - ctx->callbacks.notify_presence=(SalOnNotifyPresence)unimplemented_stub; - if (ctx->callbacks.subscribe_presence_received==NULL) - ctx->callbacks.subscribe_presence_received=(SalOnSubscribePresenceReceived)unimplemented_stub; - if (ctx->callbacks.message_received==NULL) - ctx->callbacks.message_received=(SalOnMessageReceived)unimplemented_stub; - if (ctx->callbacks.ping_reply==NULL) - ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub; - if (ctx->callbacks.auth_requested==NULL) - ctx->callbacks.auth_requested=(SalOnAuthRequested)unimplemented_stub; - if (ctx->callbacks.info_received==NULL) - ctx->callbacks.info_received=(SalOnInfoReceived)unimplemented_stub; - if (ctx->callbacks.on_publish_response==NULL) - ctx->callbacks.on_publish_response=(SalOnPublishResponse)unimplemented_stub; - if (ctx->callbacks.on_expire==NULL) - ctx->callbacks.on_expire=(SalOnExpire)unimplemented_stub; -} - - - -void sal_uninit(Sal* sal){ - belle_sip_object_unref(sal->user_agent); - belle_sip_object_unref(sal->prov); - belle_sip_object_unref(sal->stack); - belle_sip_object_unref(sal->listener); - if (sal->supported) belle_sip_object_unref(sal->supported); - bctbx_list_free_with_data(sal->supported_tags,ms_free); - bctbx_list_free_with_data(sal->supported_content_types, ms_free); - if (sal->uuid) ms_free(sal->uuid); - if (sal->root_ca) ms_free(sal->root_ca); - if (sal->root_ca_data) ms_free(sal->root_ca_data); - ms_free(sal); -}; - -int sal_transport_available(Sal *sal, SalTransport t){ - switch(t){ - case SalTransportUDP: - case SalTransportTCP: - return TRUE; - case SalTransportTLS: - return belle_sip_stack_tls_available(sal->stack); - case SalTransportDTLS: - return FALSE; - } - return FALSE; -} - -bool_t sal_content_encoding_available(Sal *sal, const char *content_encoding) { - return (bool_t)belle_sip_stack_content_encoding_available(sal->stack, content_encoding); -} - -static int sal_add_listen_port(Sal *ctx, SalAddress* addr, bool_t is_tunneled){ - int result; - belle_sip_listening_point_t* lp; - if (is_tunneled){ -#ifdef TUNNEL_ENABLED - if (sal_address_get_transport(addr)!=SalTransportUDP){ - ms_error("Tunneled mode is only available for UDP kind of transports."); - return -1; - } - lp = belle_sip_tunnel_listening_point_new(ctx->stack, ctx->tunnel_client); - if (!lp){ - ms_error("Could not create tunnel listening point."); - return -1; - } -#else - ms_error("No tunnel support in library."); - return -1; -#endif - }else{ - lp = belle_sip_stack_create_listening_point(ctx->stack, - sal_address_get_domain(addr), - sal_address_get_port(addr), - sal_transport_to_string(sal_address_get_transport(addr))); - } - if (lp) { - belle_sip_listening_point_set_keep_alive(lp,(int)ctx->keep_alive); - result = belle_sip_provider_add_listening_point(ctx->prov,lp); - if (sal_address_get_transport(addr)==SalTransportTLS) { - set_tls_properties(ctx); - } - } else { - return -1; - } - return result; -} - -int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_tunneled) { - SalAddress* sal_addr = sal_address_new(NULL); - int result; - sal_address_set_domain(sal_addr,addr); - sal_address_set_port(sal_addr,port); - sal_address_set_transport(sal_addr,tr); - result = sal_add_listen_port(ctx, sal_addr, !!is_tunneled); - sal_address_destroy(sal_addr); - return result; -} - -static void remove_listening_point(belle_sip_listening_point_t* lp,belle_sip_provider_t* prov) { - belle_sip_provider_remove_listening_point(prov,lp); -} - -int sal_get_listening_port(Sal *ctx, SalTransport tr){ - const char *tpn=sal_transport_to_string(tr); - belle_sip_listening_point_t *lp=belle_sip_provider_get_listening_point(ctx->prov, tpn); - if (lp){ - return belle_sip_listening_point_get_port(lp); - } - return 0; -} - -int sal_unlisten_ports(Sal *ctx){ - const belle_sip_list_t * lps = belle_sip_provider_get_listening_points(ctx->prov); - belle_sip_list_t * tmp_list = belle_sip_list_copy(lps); - belle_sip_list_for_each2 (tmp_list,(void (*)(void*,void*))remove_listening_point,ctx->prov); - belle_sip_list_free(tmp_list); - ms_message("sal_unlisten_ports done"); - return 0; -} - -ortp_socket_t sal_get_socket(Sal *ctx){ - ms_warning("sal_get_socket is deprecated"); - return -1; -} - -void sal_set_user_agent(Sal *ctx, const char *user_agent){ - belle_sip_header_user_agent_set_products(ctx->user_agent,NULL); - belle_sip_header_user_agent_add_product(ctx->user_agent,user_agent); - return ; -} - -const char* sal_get_user_agent(Sal *ctx){ - static char user_agent[255]; - belle_sip_header_user_agent_get_products_as_string(ctx->user_agent, user_agent, 254); - return user_agent; -} - -void sal_append_stack_string_to_user_agent(Sal *ctx) { - char stack_string[64]; - snprintf(stack_string, sizeof(stack_string) - 1, "(belle-sip/%s)", belle_sip_version_to_string()); - belle_sip_header_user_agent_add_product(ctx->user_agent, stack_string); -} - -/*keepalive period in ms*/ -void sal_set_keepalive_period(Sal *ctx,unsigned int value){ - const belle_sip_list_t* iterator; - belle_sip_listening_point_t* lp; - ctx->keep_alive=value; - for (iterator=belle_sip_provider_get_listening_points(ctx->prov);iterator!=NULL;iterator=iterator->next) { - lp=(belle_sip_listening_point_t*)iterator->data; - if (ctx->use_tcp_tls_keep_alive || strcasecmp(belle_sip_listening_point_get_transport(lp),"udp")==0) { - belle_sip_listening_point_set_keep_alive(lp,(int)ctx->keep_alive); - } - } -} -int sal_set_tunnel(Sal *ctx, void *tunnelclient) { -#ifdef TUNNEL_ENABLED - ctx->tunnel_client=tunnelclient; - return 0; -#else - return -1; -#endif -} - -/** - * returns keepalive period in ms - * 0 desactiaved - * */ -unsigned int sal_get_keepalive_period(Sal *ctx){ - return ctx->keep_alive; -} -void sal_use_session_timers(Sal *ctx, int expires){ - ctx->session_expires=expires; - return ; -} - -void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec){ - ctx->one_matching_codec=one_matching_codec; -} - -void sal_use_rport(Sal *ctx, bool_t use_rports){ - belle_sip_provider_enable_rport(ctx->prov,use_rports); - ms_message("Sal use rport [%s]",use_rports?"enabled":"disabled"); - return ; -} - -static void set_tls_properties(Sal *ctx){ - belle_sip_listening_point_t *lp=belle_sip_provider_get_listening_point(ctx->prov,"TLS"); - if (lp){ - belle_sip_tls_listening_point_t *tlp=BELLE_SIP_TLS_LISTENING_POINT(lp); - belle_tls_crypto_config_t *crypto_config = belle_tls_crypto_config_new(); - int verify_exceptions = BELLE_TLS_VERIFY_NONE; - if (!ctx->tls_verify) verify_exceptions = BELLE_TLS_VERIFY_ANY_REASON; - else if (!ctx->tls_verify_cn) verify_exceptions = BELLE_TLS_VERIFY_CN_MISMATCH; - belle_tls_crypto_config_set_verify_exceptions(crypto_config, verify_exceptions); - if (ctx->root_ca != NULL) belle_tls_crypto_config_set_root_ca(crypto_config, ctx->root_ca); - if (ctx->root_ca_data != NULL) belle_tls_crypto_config_set_root_ca_data(crypto_config, ctx->root_ca_data); - if (ctx->ssl_config != NULL) belle_tls_crypto_config_set_ssl_config(crypto_config, ctx->ssl_config); - belle_sip_tls_listening_point_set_crypto_config(tlp, crypto_config); - belle_sip_object_unref(crypto_config); - } -} - -void sal_set_root_ca(Sal* ctx, const char* rootCa) { - if (ctx->root_ca) { - ms_free(ctx->root_ca); - ctx->root_ca = NULL; - } - if (rootCa) - ctx->root_ca = ms_strdup(rootCa); - set_tls_properties(ctx); - return; -} - -void sal_set_root_ca_data(Sal* ctx, const char* data) { - if (ctx->root_ca_data) { - ms_free(ctx->root_ca_data); - ctx->root_ca_data = NULL; - } - if (data) - ctx->root_ca_data = ms_strdup(data); - set_tls_properties(ctx); - return; -} - -void sal_verify_server_certificates(Sal *ctx, bool_t verify){ - ctx->tls_verify=verify; - set_tls_properties(ctx); - return ; -} - -void sal_verify_server_cn(Sal *ctx, bool_t verify){ - ctx->tls_verify_cn=verify; - set_tls_properties(ctx); - return ; -} - -void sal_set_ssl_config(Sal *ctx, void *ssl_config) { - ctx->ssl_config = ssl_config; - set_tls_properties(ctx); - return ; -} - -void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled) { - ctx->use_tcp_tls_keep_alive=enabled; -} - -int sal_iterate(Sal *sal){ - belle_sip_stack_sleep(sal->stack,0); - return 0; -} -bctbx_list_t * sal_get_pending_auths(Sal *sal){ - return bctbx_list_copy(sal->pending_auths); -} - -/*misc*/ -void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t iplen){ - strncpy(ip,address_family==AF_INET6 ? "::1" : "127.0.0.1",iplen); - ms_error("sal_get_default_local_ip() is deprecated."); -} - -const char *sal_get_root_ca(Sal* ctx) { - return ctx->root_ca; -} - -int sal_reset_transports(Sal *ctx){ - ms_message("Reseting transports"); - belle_sip_provider_clean_channels(ctx->prov); - return 0; -} - -void sal_set_dscp(Sal *ctx, int dscp){ - belle_sip_stack_set_default_dscp(ctx->stack,dscp); -} - -void sal_set_send_error(Sal *sal,int value) { - belle_sip_stack_set_send_error(sal->stack,value); -} -void sal_set_recv_error(Sal *sal,int value) { - belle_sip_provider_set_recv_error(sal->prov,value); -} -void sal_nat_helper_enable(Sal *sal,bool_t enable) { - sal->nat_helper_enabled=enable; - belle_sip_provider_enable_nat_helper(sal->prov,enable); - ms_message("Sal nat helper [%s]",enable?"enabled":"disabled"); -} -bool_t sal_nat_helper_enabled(Sal *sal) { - return sal->nat_helper_enabled; -} -void sal_set_dns_timeout(Sal* sal,int timeout) { - belle_sip_stack_set_dns_timeout(sal->stack, timeout); -} - -int sal_get_dns_timeout(const Sal* sal) { - return belle_sip_stack_get_dns_timeout(sal->stack); -} - -void sal_set_transport_timeout(Sal* sal,int timeout) { - belle_sip_stack_set_transport_timeout(sal->stack, timeout); -} - -int sal_get_transport_timeout(const Sal* sal) { - return belle_sip_stack_get_transport_timeout(sal->stack); -} - -void sal_set_dns_servers(Sal *sal, const bctbx_list_t *servers){ - belle_sip_list_t *l = NULL; - - /*we have to convert the bctbx_list_t into a belle_sip_list_t first*/ - for (; servers != NULL; servers = servers->next){ - l = belle_sip_list_append(l, servers->data); - } - belle_sip_stack_set_dns_servers(sal->stack, l); - belle_sip_list_free(l); -} - -void sal_enable_dns_srv(Sal *sal, bool_t enable) { - belle_sip_stack_enable_dns_srv(sal->stack, (unsigned char)enable); -} - -bool_t sal_dns_srv_enabled(const Sal *sal) { - return (bool_t)belle_sip_stack_dns_srv_enabled(sal->stack); -} - -void sal_enable_dns_search(Sal *sal, bool_t enable) { - belle_sip_stack_enable_dns_search(sal->stack, (unsigned char)enable); -} - -bool_t sal_dns_search_enabled(const Sal *sal) { - return (bool_t)belle_sip_stack_dns_search_enabled(sal->stack); -} - -void sal_set_dns_user_hosts_file(Sal *sal, const char *hosts_file) { - belle_sip_stack_set_dns_user_hosts_file(sal->stack, hosts_file); -} - -const char * sal_get_dns_user_hosts_file(const Sal *sal) { - return belle_sip_stack_get_dns_user_hosts_file(sal->stack); -} SalAuthInfo* sal_auth_info_create(belle_sip_auth_event_t* event) { SalAuthInfo* auth_info = sal_auth_info_new(); @@ -925,21 +79,6 @@ void sal_signing_key_delete(belle_sip_signing_key_t *key) { belle_sip_object_unref((belle_sip_object_t *)key); } -const char* sal_op_type_to_string(const SalOpType type) { - switch(type) { - case SalOpRegister: return "SalOpRegister"; - case SalOpCall: return "SalOpCall"; - case SalOpMessage: return "SalOpMessage"; - case SalOpPresence: return "SalOpPresence"; - default: - return "SalOpUnknown"; - } -} - -void sal_use_dates(Sal *ctx, bool_t enabled){ - ctx->use_dates=enabled; -} - int sal_auth_compute_ha1(const char* userid,const char* realm,const char* password, char ha1[33]) { return belle_sip_auth_helper_compute_ha1(userid, realm, password, ha1); } @@ -1001,11 +140,6 @@ SalCustomHeader *sal_custom_header_clone(const SalCustomHeader *ch){ return (SalCustomHeader*)belle_sip_object_ref((belle_sip_message_t*)ch); } -const SalCustomHeader *sal_op_get_recv_custom_header(SalOp *op){ - SalOpBase *b=(SalOpBase *)op; - return b->recv_custom_headers; -} - SalCustomSdpAttribute * sal_custom_sdp_attribute_append(SalCustomSdpAttribute *csa, const char *name, const char *value) { belle_sdp_session_description_t *desc = (belle_sdp_session_description_t *)csa; belle_sdp_attribute_t *attr; @@ -1040,167 +174,6 @@ SalCustomSdpAttribute * sal_custom_sdp_attribute_clone(const SalCustomSdpAttribu return (SalCustomSdpAttribute *)belle_sip_object_ref((belle_sdp_session_description_t *)csa); } -void sal_set_uuid(Sal *sal, const char *uuid){ - if (sal->uuid){ - ms_free(sal->uuid); - sal->uuid=NULL; - } - if (uuid) - sal->uuid=ms_strdup(uuid); -} - -typedef struct { - unsigned int time_low; - unsigned short time_mid; - unsigned short time_hi_and_version; - unsigned char clock_seq_hi_and_reserved; - unsigned char clock_seq_low; - unsigned char node[6]; -} sal_uuid_t; - -int sal_generate_uuid(char *uuid, size_t len) { - sal_uuid_t uuid_struct; - int i; - int written; - - if (len==0) return -1; - /*create an UUID as described in RFC4122, 4.4 */ - belle_sip_random_bytes((unsigned char*)&uuid_struct, sizeof(sal_uuid_t)); - uuid_struct.clock_seq_hi_and_reserved&=(unsigned char)~(1<<6); - uuid_struct.clock_seq_hi_and_reserved|=1<<7; - uuid_struct.time_hi_and_version&=(short unsigned int)~(0xf<<12); - uuid_struct.time_hi_and_version|=4<<12; - - written=snprintf(uuid,len,"%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", uuid_struct.time_low, uuid_struct.time_mid, - uuid_struct.time_hi_and_version, uuid_struct.clock_seq_hi_and_reserved, - uuid_struct.clock_seq_low); - if ((written < 0) || ((size_t)written > (len +13))) { - ms_error("sal_create_uuid(): buffer is too short !"); - return -1; - } - for (i = 0; i < 6; i++) - written+=snprintf(uuid+written,len-(size_t)written,"%2.2x", uuid_struct.node[i]); - uuid[len-1]='\0'; - return 0; -} - -int sal_create_uuid(Sal*ctx, char *uuid, size_t len) { - if (sal_generate_uuid(uuid, len) == 0) { - sal_set_uuid(ctx, uuid); - return 0; - } - return -1; -} - -static void make_supported_header(Sal *sal){ - bctbx_list_t *it; - char *alltags=NULL; - size_t buflen=64; - size_t written=0; - - if (sal->supported){ - belle_sip_object_unref(sal->supported); - sal->supported=NULL; - } - for(it=sal->supported_tags;it!=NULL;it=it->next){ - const char *tag=(const char*)it->data; - size_t taglen=strlen(tag); - if (alltags==NULL || (written+taglen+1>=buflen)) alltags=reinterpret_cast(ms_realloc(alltags,(buflen=buflen*2))); - written+=(size_t)snprintf(alltags+written,buflen-written,it->next ? "%s, " : "%s",tag); - } - if (alltags){ - sal->supported=belle_sip_header_create("Supported",alltags); - if (sal->supported){ - belle_sip_object_ref(sal->supported); - } - ms_free(alltags); - } -} - -void sal_set_supported_tags(Sal *ctx, const char* tags){ - ctx->supported_tags=bctbx_list_free_with_data(ctx->supported_tags,ms_free); - if (tags){ - char *iter; - char *buffer=ms_strdup(tags); - char *tag; - char *context=NULL; - iter=buffer; - while((tag=strtok_r(iter,", ",&context))!=NULL){ - iter=NULL; - ctx->supported_tags=bctbx_list_append(ctx->supported_tags,ms_strdup(tag)); - } - ms_free(buffer); - } - make_supported_header(ctx); -} - -const char *sal_get_supported_tags(Sal *ctx){ - if (ctx->supported){ - return belle_sip_header_get_unparsed_value(ctx->supported); - } - return NULL; -} - -void sal_add_supported_tag(Sal *ctx, const char* tag){ - bctbx_list_t *elem=bctbx_list_find_custom(ctx->supported_tags,(bctbx_compare_func)strcasecmp,tag); - if (!elem){ - ctx->supported_tags=bctbx_list_append(ctx->supported_tags,ms_strdup(tag)); - make_supported_header(ctx); - } - -} - -void sal_remove_supported_tag(Sal *ctx, const char* tag){ - bctbx_list_t *elem=bctbx_list_find_custom(ctx->supported_tags,(bctbx_compare_func)strcasecmp,tag); - if (elem){ - ms_free(elem->data); - ctx->supported_tags=bctbx_list_erase_link(ctx->supported_tags,elem); - make_supported_header(ctx); - } -} - - - -belle_sip_response_t* sal_create_response_from_request ( Sal* sal, belle_sip_request_t* req, int code ) { - belle_sip_response_t *resp=belle_sip_response_create_from_request(req,code); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(sal->user_agent)); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),sal->supported); - return resp; -} - -void sal_set_refresher_retry_after(Sal *sal,int value) { - sal->refresher_retry_after=value; -} - -int sal_get_refresher_retry_after(const Sal *sal) { - return sal->refresher_retry_after; -} - -void sal_enable_auto_contacts(Sal *ctx, bool_t enabled){ - ctx->auto_contacts=enabled; -} - -void sal_enable_test_features(Sal*ctx, bool_t enabled){ - ctx->enable_test_features=enabled; -} - -void sal_use_no_initial_route(Sal *ctx, bool_t enabled){ - ctx->no_initial_route=enabled; -} - -belle_sip_resolver_context_t * sal_resolve_a(Sal* sal, const char *name, int port, int family, belle_sip_resolver_callback_t cb, void *data){ - return belle_sip_stack_resolve_a(sal->stack,name,port,family,cb,data); -} - -belle_sip_resolver_context_t * sal_resolve(Sal *sal, const char *service, const char *transport, const char *name, int port, int family, belle_sip_resolver_callback_t cb, void *data) { - return belle_sip_stack_resolve(sal->stack, service, transport, name, port, family, cb, data); -} - - -void sal_enable_unconditional_answer(Sal *sal,int value) { - belle_sip_provider_enable_unconditional_answer(sal->prov,value); -} - /** Parse a file containing either a certificate chain order in PEM format or a single DER cert * @param auth_info structure where to store the result of parsing * @param path path to certificate chain file @@ -1296,16 +269,6 @@ unsigned int sal_get_random(void){ return ret; } -belle_sip_source_t * sal_create_timer(Sal *sal, belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms, const char* timer_name) { - belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(sal->stack); - return belle_sip_main_loop_create_timeout(ml, func, data, timeout_value_ms, timer_name); -} - -void sal_cancel_timer(Sal *sal, belle_sip_source_t *timer) { - belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(sal->stack); - belle_sip_main_loop_remove_source(ml, timer); -} - unsigned long sal_begin_background_task(const char *name, void (*max_time_reached)(void *), void *data){ return belle_sip_begin_background_task(name, max_time_reached, data); } @@ -1314,39 +277,6 @@ void sal_end_background_task(unsigned long id){ belle_sip_end_background_task(id); } - -void sal_enable_sip_update_method(Sal *ctx,bool_t value) { - ctx->enable_sip_update=value; -} - -void sal_default_set_sdp_handling(Sal *sal, SalOpSDPHandling sdp_handling_method) { - if (sdp_handling_method != SalOpSDPNormal ) ms_message("Enabling special SDP handling for all new SalOp in Sal[%p]!", sal); - sal->default_sdp_handling = sdp_handling_method; -} - -bool_t sal_pending_trans_checking_enabled(const Sal *sal) { - return sal->pending_trans_checking; -} - -int sal_enable_pending_trans_checking(Sal *sal, bool_t value) { - sal->pending_trans_checking = value; - return 0; -} -void sal_set_http_proxy_host(Sal *sal, const char *host) { - belle_sip_stack_set_http_proxy_host(sal->stack, host); -} - -void sal_set_http_proxy_port(Sal *sal, int port) { - belle_sip_stack_set_http_proxy_port(sal->stack, port); -} -const char *sal_get_http_proxy_host(const Sal *sal) { - return belle_sip_stack_get_http_proxy_host(sal->stack); -} - -int sal_get_http_proxy_port(const Sal *sal) { - return belle_sip_stack_get_http_proxy_port(sal->stack); -} - static belle_sip_header_t * sal_body_handler_find_header(const SalBodyHandler *body_handler, const char *header_name) { belle_sip_body_handler_t *bsbh = BELLE_SIP_BODY_HANDLER(body_handler); const belle_sip_list_t *l = belle_sip_body_handler_get_headers(bsbh); @@ -1476,22 +406,3 @@ const char * sal_body_handler_get_header(const SalBodyHandler *body_handler, con } return NULL; } - -void *sal_get_stack_impl(Sal *sal) { - return sal->stack; -} - -bool_t sal_is_content_type_supported(const Sal *sal, const char *content_type) { - bctbx_list_t *item; - for (item = sal->supported_content_types; item != NULL; item = bctbx_list_next(item)) { - const char *item_content_type = (const char *)bctbx_list_get_data(item); - if (strcmp(item_content_type, content_type) == 0) return TRUE; - } - return FALSE; -} - -void sal_add_content_type_support(Sal *sal, const char *content_type) { - if ((content_type != NULL) && (sal_is_content_type_supported(sal, content_type) == FALSE)) { - sal->supported_content_types = bctbx_list_append(sal->supported_content_types, ms_strdup(content_type)); - } -} diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 6c290ff33..a30f22e5a 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -24,161 +24,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "belle-sip/belle-sip.h" #include "belle-sip/belle-sdp.h" -struct Sal{ - MSFactory *factory; - SalCallbacks callbacks; - MSList *pending_auths;/*MSList of SalOp */ - belle_sip_stack_t* stack; - belle_sip_provider_t *prov; - belle_sip_header_user_agent_t* user_agent; - belle_sip_listener_t *listener; - void *tunnel_client; - void *up; /*user pointer*/ - int session_expires; - unsigned int keep_alive; - char *root_ca; - char *root_ca_data; - char *uuid; - int refresher_retry_after; /*retry after value for refresher*/ - MSList *supported_tags;/*list of char * */ - belle_sip_header_t *supported; - bool_t one_matching_codec; - bool_t use_tcp_tls_keep_alive; - bool_t nat_helper_enabled; - bool_t tls_verify; - bool_t tls_verify_cn; - bool_t use_dates; - bool_t auto_contacts; - bool_t enable_test_features; - bool_t no_initial_route; - bool_t enable_sip_update; /*true by default*/ - SalOpSDPHandling default_sdp_handling; - bool_t pending_trans_checking; /*testing purpose*/ - void *ssl_config; - bctbx_list_t *supported_content_types; /* list of char* */ -}; -typedef enum SalOpState { - SalOpStateEarly=0 - ,SalOpStateActive - ,SalOpStateTerminating /*this state is used to wait until a proceeding state, so we can send the cancel*/ - ,SalOpStateTerminated -}SalOpState; - -const char* sal_op_state_to_string(SalOpState value); - -typedef enum SalOpDir { - SalOpDirIncoming=0 - ,SalOpDirOutgoing -}SalOpDir; -typedef enum SalOpType { - SalOpUnknown, - SalOpRegister, - SalOpCall, - SalOpMessage, - SalOpPresence, - SalOpPublish, - SalOpSubscribe -}SalOpType; - -const char* sal_op_type_to_string(SalOpType type); - -struct SalOp{ - SalOpBase base; - const belle_sip_listener_callbacks_t *callbacks; - SalErrorInfo error_info; - SalErrorInfo reason_error_info; - belle_sip_client_transaction_t *pending_auth_transaction; - belle_sip_server_transaction_t* pending_server_trans; - belle_sip_server_transaction_t* pending_update_server_trans; - belle_sip_client_transaction_t* pending_client_trans; - SalAuthInfo* auth_info; - belle_sip_dialog_t* dialog; - belle_sip_header_replaces_t *replaces; - belle_sip_header_referred_by_t *referred_by; - SalMediaDescription *result; - belle_sdp_session_description_t *sdp_answer; - SalOpState state; - SalOpDir dir; - belle_sip_refresher_t* refresher; - int ref; - SalOpType type; - SalPrivacyMask privacy; - belle_sip_header_event_t *event; /*used by SalOpSubscribe kinds*/ - SalOpSDPHandling sdp_handling; - int auth_requests; /*number of auth requested for this op*/ - bool_t cnx_ip_to_0000_if_sendonly_enabled; - bool_t auto_answer_asked; - bool_t sdp_offering; - bool_t call_released; - bool_t manual_refresher; - bool_t has_auth_pending; - bool_t supports_session_timers; - bool_t op_released; -}; - - -belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescription *sal); +belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescription *desc); int sdp_to_media_description(belle_sdp_session_description_t *sdp, SalMediaDescription *desc); -belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method); - - -void sal_op_call_fill_cbs(SalOp*op); -void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog); - -/*return reffed op*/ -SalOp* sal_op_ref(SalOp* op); -/*return null, destroy op if ref count =0*/ -void* sal_op_unref(SalOp* op); -void sal_op_release_impl(SalOp *op); - -void sal_op_set_replaces(SalOp* op,belle_sip_header_replaces_t* replaces); -void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message); -int sal_op_send_request(SalOp* op, belle_sip_request_t* request); -int sal_op_send_request_with_expires(SalOp* op, belle_sip_request_t* request,int expires); -void sal_op_resend_request(SalOp* op, belle_sip_request_t* request); -int sal_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int expires,belle_sip_refresher_listener_t listener ); -belle_sip_response_t *sal_op_create_response_from_request(SalOp *op, belle_sip_request_t *req, int code); - -/* - * return true if both from and to uri are sips - * */ -bool_t sal_op_is_secure(const SalOp* op); - -void sal_process_authentication(SalOp *op); -belle_sip_header_contact_t* sal_op_create_contact(SalOp *op) ; bool_t _sal_compute_sal_errors(belle_sip_response_t* response, SalReason* sal_reason, char* reason, size_t reason_size); SalReason _sal_reason_from_sip_code(int code); -void sal_op_set_reason_error_info(SalOp *op, belle_sip_message_t *msg); -void sal_op_set_error_info_from_response(SalOp *op, belle_sip_response_t *response); -/*presence*/ -void sal_op_presence_fill_cbs(SalOp*op); -/*messaging*/ -void sal_op_message_fill_cbs(SalOp*op); -void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *event); -void sal_op_subscribe_fill_cbs(SalOp*op); - -/*call transfer*/ -void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event, belle_sip_server_transaction_t *tr); -void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event, belle_sip_server_transaction_t *tr); /*create SalAuthInfo by copying username and realm from suth event*/ SalAuthInfo* sal_auth_info_create(belle_sip_auth_event_t* event) ; -void sal_add_pending_auth(Sal *sal, SalOp *op); -void sal_remove_pending_auth(Sal *sal, SalOp *op); -void sal_add_presence_info(SalOp *op, belle_sip_message_t *notify, SalPresenceModel *presence); - -belle_sip_response_t *sal_create_response_from_request(Sal *sal, belle_sip_request_t *req, int code); - -void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming); - -SalBodyHandler * sal_op_get_body_handler(SalOp *op, belle_sip_message_t *msg); - -int sal_reason_to_sip_code(SalReason r); - -void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg); - -SalSubscribeStatus belle_sip_message_get_subscription_state(const belle_sip_message_t *msg); #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c deleted file mode 100644 index d1fff0d83..000000000 --- a/coreapi/bellesip_sal/sal_op_call.c +++ /dev/null @@ -1,1240 +0,0 @@ -/* -linphone -Copyright (C) 2012 Belledonne Communications, Grenoble, France - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#include "sal_impl.h" -#include "offeranswer.h" - -#include - -static int extract_sdp(SalOp* op,belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error); - -/*used for calls terminated before creation of a dialog*/ -static void call_set_released(SalOp* op){ - if (!op->call_released){ - op->state=SalOpStateTerminated; - op->base.root->callbacks.call_released(op); - op->call_released=TRUE; - /*be aware that the following line may destroy the op*/ - set_or_update_dialog(op,NULL); - } -} - -static void call_set_error(SalOp* op,belle_sip_response_t* response, bool_t fatal){ - sal_op_set_error_info_from_response(op,response); - if (fatal) op->state = SalOpStateTerminating; - op->base.root->callbacks.call_failure(op); -} -static void set_addr_to_0000(char value[], size_t sz) { - if (ms_is_ipv6(value)) { - strncpy(value,"::0", sz); - } else { - strncpy(value,"0.0.0.0", sz); - } - return; -} -static void sdp_process(SalOp *h){ - ms_message("Doing SDP offer/answer process of type %s",h->sdp_offering ? "outgoing" : "incoming"); - if (h->result){ - sal_media_description_unref(h->result); - h->result = NULL; - } - - /* if SDP was invalid */ - if (h->base.remote_media == NULL) return; - - h->result=sal_media_description_new(); - if (h->sdp_offering){ - offer_answer_initiate_outgoing(h->base.root->factory, h->base.local_media,h->base.remote_media,h->result); - }else{ - int i; - if (h->sdp_answer){ - belle_sip_object_unref(h->sdp_answer); - } - offer_answer_initiate_incoming(h->base.root->factory, h->base.local_media,h->base.remote_media,h->result,h->base.root->one_matching_codec); - /*for backward compatibility purpose*/ - if(h->cnx_ip_to_0000_if_sendonly_enabled && sal_media_description_has_dir(h->result,SalStreamSendOnly)) { - set_addr_to_0000(h->result->addr, sizeof(h->result->addr)); - for(i=0;iresult->streams[i].dir == SalStreamSendOnly) { - set_addr_to_0000(h->result->streams[i].rtp_addr, sizeof(h->result->streams[i].rtp_addr)); - set_addr_to_0000(h->result->streams[i].rtcp_addr, sizeof(h->result->streams[i].rtcp_addr)); - } - } - } - h->sdp_answer=(belle_sdp_session_description_t *)belle_sip_object_ref(media_description_to_sdp(h->result)); - /*once we have generated the SDP answer, we modify the result description for processing by the upper layer. - It should contains media parameters constraint from the remote offer, not our response*/ - strcpy(h->result->addr,h->base.remote_media->addr); - h->result->bandwidth=h->base.remote_media->bandwidth; - - for(i=0;iresult->streams[i].rtp_port!=0){ /*if stream was accepted*/ - strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr); - h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime; - h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth; - h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port; - strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr); - h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port; - - if (sal_stream_description_has_srtp(&h->result->streams[i])) { - h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0]; - } - } - } - } -} - -static int set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* session_desc) { - belle_sip_header_content_type_t* content_type ; - belle_sip_header_content_length_t* content_length; - belle_sip_error_code error = BELLE_SIP_BUFFER_OVERFLOW; - size_t length = 0; - - if (session_desc) { - size_t bufLen = 2048; - size_t hardlimit = 16*1024; /* 16k SDP limit seems reasonable */ - char* buff = reinterpret_cast(belle_sip_malloc(bufLen)); - content_type = belle_sip_header_content_type_create("application","sdp"); - - /* try to marshal the description. This could go higher than 2k so we iterate */ - while( error != BELLE_SIP_OK && bufLen <= hardlimit && buff != NULL){ - error = belle_sip_object_marshal(BELLE_SIP_OBJECT(session_desc),buff,bufLen,&length); - if( error != BELLE_SIP_OK ){ - bufLen *= 2; - length = 0; - buff = reinterpret_cast(belle_sip_realloc(buff,bufLen)); - } - } - /* give up if hard limit reached */ - if (error != BELLE_SIP_OK || buff == NULL) { - ms_error("Buffer too small (%d) or not enough memory, giving up SDP", (int)bufLen); - return -1; - } - - content_length = belle_sip_header_content_length_create(length); - belle_sip_message_add_header(msg,BELLE_SIP_HEADER(content_type)); - belle_sip_message_add_header(msg,BELLE_SIP_HEADER(content_length)); - belle_sip_message_assign_body(msg,buff,length); - return 0; - } else { - return -1; - } -} -static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription *desc){ - int err; - belle_sdp_session_description_t *sdp=media_description_to_sdp(desc); - err=set_sdp(msg,sdp); - belle_sip_object_unref(sdp); - return err; - -} - -static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event) { - SalOp *op = (SalOp *)user_ctx; - - if (op->state == SalOpStateTerminated) return; - - if (op->pending_client_trans && (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(op->pending_client_trans)) == BELLE_SIP_TRANSACTION_INIT)) { - - sal_error_info_set(&op->error_info, SalReasonIOError, "SIP", 503, "IO error", NULL); - op->base.root->callbacks.call_failure(op); - - if (!op->dialog || belle_sip_dialog_get_state(op->dialog) != BELLE_SIP_DIALOG_CONFIRMED){ - /* Call terminated very very early, before INVITE is even sent, probably DNS resolution timeout. */ - op->state = SalOpStateTerminating; - call_set_released(op); - } - } else { - /* Nothing to be done. If the error comes from a connectivity loss, - * the call will be marked as broken, and an attempt to repair it will be done. */ - } -} - -static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) { - SalOp* op=(SalOp*)ctx; - - if (op->dialog && op->dialog==belle_sip_dialog_terminated_event_get_dialog(event)) { - /*belle_sip_transaction_t* trans=belle_sip_dialog_get_last_transaction(op->dialog);*/ - ms_message("Dialog [%p] terminated for op [%p]",belle_sip_dialog_terminated_event_get_dialog(event),op); - - switch(belle_sip_dialog_get_previous_state(op->dialog)) { - case BELLE_SIP_DIALOG_EARLY: - case BELLE_SIP_DIALOG_NULL: - if (op->state!=SalOpStateTerminated && op->state!=SalOpStateTerminating) { - /*this is an early termination due to incorrect response received*/ - op->base.root->callbacks.call_failure(op); - op->state=SalOpStateTerminating; - } - break; - case BELLE_SIP_DIALOG_CONFIRMED: - if (op->state!=SalOpStateTerminated && op->state!=SalOpStateTerminating) { - /*this is probably a normal termination from a BYE*/ - op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op)); - op->state=SalOpStateTerminating; - } - break; - default: - break; - } - belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(op->base.root->stack) - ,(belle_sip_callback_t) call_set_released - , op); - } else { - ms_error("dialog unknown for op "); - } -} - -static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) { - belle_sdp_session_description_t* sdp; - SalReason reason; - if (op->base.remote_media){ - sal_media_description_unref(op->base.remote_media); - op->base.remote_media=NULL; - } - if (extract_sdp(op,BELLE_SIP_MESSAGE(response),&sdp,&reason)==0) { - if (sdp){ - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - }/*if no sdp in response, what can we do ?*/ - } - /* process sdp in any case to reset result media description*/ - if (op->base.local_media) sdp_process(op); -} - -void sal_call_cancel_invite(SalOp *op) { - sal_call_cancel_invite_with_info(op,NULL); -} - -static void cancelling_invite(SalOp *op, const SalErrorInfo *info) { - sal_call_cancel_invite_with_info(op, info); - op->state=SalOpStateTerminating; -} - -static int vfu_retry (void *user_data, unsigned int events) { - SalOp *op=(SalOp *)user_data; - sal_call_send_vfu_request(op); - sal_op_unref(op); - return BELLE_SIP_STOP; -} - -static void call_process_response(void *op_base, const belle_sip_response_event_t *event){ - SalOp* op = (SalOp*)op_base; - belle_sip_request_t* ack; - belle_sip_dialog_state_t dialog_state; - belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); - belle_sip_request_t* req; - belle_sip_response_t* response=belle_sip_response_event_get_response(event); - int code = belle_sip_response_get_status_code(response); - belle_sip_header_content_type_t *header_content_type=NULL; - belle_sip_dialog_t *dialog=belle_sip_response_event_get_dialog(event); - const char *method; - - if (!client_transaction) { - ms_warning("Discarding stateless response [%i] on op [%p]",code,op); - return; - } - req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); - set_or_update_dialog(op,dialog); - dialog_state=dialog ? belle_sip_dialog_get_state(dialog) : BELLE_SIP_DIALOG_NULL; - method=belle_sip_request_get_method(req); - ms_message("Op [%p] receiving call response [%i], dialog is [%p] in state [%s]",op,code,dialog,belle_sip_dialog_state_to_string(dialog_state)); - /*to make sure no cb will destroy op*/ - sal_op_ref(op); - switch(dialog_state) { - case BELLE_SIP_DIALOG_NULL: - case BELLE_SIP_DIALOG_EARLY: { - if (strcmp("INVITE",method)==0 ) { - if (op->state == SalOpStateTerminating) { - /*check if CANCEL was sent before*/ - if (strcmp("CANCEL",belle_sip_request_get_method(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_client_trans))))!=0) { - /*it wasn't sent */ - if (code<200) { - cancelling_invite(op, NULL); - }else{ - /* no need to send the INVITE because the UAS rejected the INVITE*/ - if (op->dialog==NULL) call_set_released(op); - } - } else { - /*it was sent already, so just expect the 487 or any error response to send the call_released() notification*/ - if (code>=300){ - if (op->dialog==NULL) call_set_released(op); - } - } - } else if (code >= 180 && code<200) { - belle_sip_response_t *prev_response=reinterpret_cast(belle_sip_object_data_get(BELLE_SIP_OBJECT(dialog),"early_response")); - if (!prev_response || code>belle_sip_response_get_status_code(prev_response)){ - handle_sdp_from_response(op,response); - op->base.root->callbacks.call_ringing(op); - } - belle_sip_object_data_set(BELLE_SIP_OBJECT(dialog),"early_response",belle_sip_object_ref(response),belle_sip_object_unref); - } else if (code>=300){ - call_set_error(op, response, TRUE); - if (op->dialog==NULL) call_set_released(op); - } - } else if (code >=200 && code<300) { - if (strcmp("UPDATE",method)==0) { - handle_sdp_from_response(op,response); - op->base.root->callbacks.call_accepted(op); - } else if (strcmp("CANCEL", method) == 0) { - op->base.root->callbacks.call_cancel_done(op); - } - } - } - break; - case BELLE_SIP_DIALOG_CONFIRMED: { - switch (op->state) { - case SalOpStateEarly:/*invite case*/ - case SalOpStateActive: /*re-invite, INFO, UPDATE case*/ - if (strcmp("INVITE",method)==0){ - if (code >=200 && code<300) { - handle_sdp_from_response(op,response); - ack=belle_sip_dialog_create_ack(op->dialog,belle_sip_dialog_get_local_seq_number(op->dialog)); - if (ack == NULL) { - ms_error("This call has been already terminated."); - return ; - } - if (op->sdp_answer){ - set_sdp(BELLE_SIP_MESSAGE(ack),op->sdp_answer); - belle_sip_object_unref(op->sdp_answer); - op->sdp_answer=NULL; - } - belle_sip_message_add_header(BELLE_SIP_MESSAGE(ack),BELLE_SIP_HEADER(op->base.root->user_agent)); - op->base.root->callbacks.call_accepted(op); /*INVITE*/ - op->base.root->callbacks.call_ack_being_sent(op, (SalCustomHeader*)ack); - belle_sip_dialog_send_ack(op->dialog,ack); - op->state=SalOpStateActive; - }else if (code >= 300){ - call_set_error(op,response, FALSE); - } - }else if (strcmp("INFO",method)==0){ - if (code == 491 - && (header_content_type = belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t)) - && strcmp("application",belle_sip_header_content_type_get_type(header_content_type))==0 - && strcmp("media_control+xml",belle_sip_header_content_type_get_subtype(header_content_type))==0) { - unsigned int retry_in = (unsigned int)(1000*((float)rand()/(float)RAND_MAX)); - belle_sip_source_t *s=sal_create_timer(op->base.root,vfu_retry,sal_op_ref(op), retry_in, "vfu request retry"); - ms_message("Rejected vfu request on op [%p], just retry in [%ui] ms",op,retry_in); - belle_sip_object_unref(s); - }else { - /*ignoring*/ - } - }else if (strcmp("UPDATE",method)==0){ - op->base.root->callbacks.call_accepted(op); /*INVITE*/ - }else if (strcmp("CANCEL",method)==0){ - op->base.root->callbacks.call_cancel_done(op); - } - break; - case SalOpStateTerminating: - sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE")); - break; - case SalOpStateTerminated: - default: - ms_error("Call op [%p] receives unexpected answer [%i] while in state [%s].",op,code, sal_op_state_to_string(op->state)); - } - } - break; - case BELLE_SIP_DIALOG_TERMINATED: { - if (strcmp("INVITE",method)==0 && code >= 300){ - call_set_error(op,response, TRUE); - } - } - break; - default: { - ms_error("call op [%p] receive answer [%i] not implemented",op,code); - } - break; - } - sal_op_unref(op); -} - -static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { - SalOp* op=(SalOp*)user_ctx; - - if (op->state==SalOpStateTerminated) return; - - if (!op->dialog) { - /*call terminated very early*/ - sal_error_info_set(&op->error_info, SalReasonRequestTimeout, "SIP", 408, "Request timeout", NULL); - op->base.root->callbacks.call_failure(op); - op->state = SalOpStateTerminating; - call_set_released(op); - } else { - /*dialog will terminated shortly, nothing to do*/ - } -} - -static void call_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { - SalOp* op = (SalOp*)user_ctx; - belle_sip_client_transaction_t *client_transaction=belle_sip_transaction_terminated_event_get_client_transaction(event); - belle_sip_server_transaction_t *server_transaction=belle_sip_transaction_terminated_event_get_server_transaction(event); - belle_sip_request_t* req; - belle_sip_response_t* resp; - int code = 0; - bool_t release_call=FALSE; - - if (client_transaction) { - req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); - resp=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(client_transaction)); - } else { - req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction)); - resp=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(server_transaction)); - } - if (resp) code = belle_sip_response_get_status_code(resp); - - if (op->state == SalOpStateTerminating - && strcmp("BYE",belle_sip_request_get_method(req))==0 - && (!resp || (belle_sip_response_get_status_code(resp) != 401 - && belle_sip_response_get_status_code(resp) != 407)) - && op->dialog==NULL) { - release_call=TRUE; - }else if (op->state == SalOpStateEarly && code < 200){ - /*call terminated early*/ - sal_error_info_set(&op->error_info, SalReasonIOError, "SIP", 503, "I/O error", NULL); - op->state = SalOpStateTerminating; - op->base.root->callbacks.call_failure(op); - release_call=TRUE; - } - if (server_transaction){ - if (op->pending_server_trans==server_transaction){ - belle_sip_object_unref(op->pending_server_trans); - op->pending_server_trans=NULL; - } - if (op->pending_update_server_trans==server_transaction){ - belle_sip_object_unref(op->pending_update_server_trans); - op->pending_update_server_trans=NULL; - } - } - if (release_call) call_set_released(op); -} - -static void call_terminated(SalOp* op,belle_sip_server_transaction_t* server_transaction, int status_code, belle_sip_request_t* cancel_request) { - belle_sip_response_t* resp; - belle_sip_request_t* server_req = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction)); - op->state = SalOpStateTerminating; - sal_op_set_reason_error_info(op, BELLE_SIP_MESSAGE(cancel_request ? cancel_request : server_req)); - resp=sal_op_create_response_from_request(op,server_req,status_code); - belle_sip_server_transaction_send_response(server_transaction,resp); - op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op)); -} - -static void unsupported_method(belle_sip_server_transaction_t* server_transaction,belle_sip_request_t* request) { - belle_sip_response_t* resp; - resp=belle_sip_response_create_from_request(request,501); - belle_sip_server_transaction_send_response(server_transaction,resp); - return; -} - -/* - * Extract the sdp from a sip message. - * If there is no body in the message, the session_desc is set to null, 0 is returned. - * If body was present is not a SDP or parsing of SDP failed, -1 is returned and SalReason is set appropriately. - * -**/ -static int extract_sdp(SalOp *op, belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error) { - const char *body; - belle_sip_header_content_type_t* content_type; - - if (op&&op->sdp_handling == SalOpSDPSimulateError){ - ms_error("Simulating SDP parsing error for op %p", op); - *session_desc=NULL; - *error=SalReasonNotAcceptable; - return -1; - } else if( op && op->sdp_handling == SalOpSDPSimulateRemove){ - ms_error("Simulating no SDP for op %p", op); - *session_desc = NULL; - return 0; - } - - body = belle_sip_message_get_body(message); - if(body == NULL) { - *session_desc = NULL; - return 0; - } - - content_type = belle_sip_message_get_header_by_type(message,belle_sip_header_content_type_t); - if (content_type){ - if (strcmp("application",belle_sip_header_content_type_get_type(content_type))==0 - && strcmp("sdp",belle_sip_header_content_type_get_subtype(content_type))==0) { - *session_desc=belle_sdp_session_description_parse(body); - if (*session_desc==NULL) { - ms_error("Failed to parse SDP message."); - *error=SalReasonNotAcceptable; - return -1; - } - }else{ - *error=SalReasonUnsupportedContent; - return -1; - } - }else *session_desc=NULL; - return 0; -} - -static int is_media_description_acceptable(SalMediaDescription *md){ - if (md->nb_streams==0){ - ms_warning("Media description does not define any stream."); - return FALSE; - } - return TRUE; -} - -static SalReason process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) { - belle_sdp_session_description_t* sdp; - SalReason reason = SalReasonNone; - SalErrorInfo sei; - - memset(&sei, 0, sizeof(sei)); - if (extract_sdp(op,BELLE_SIP_MESSAGE(invite),&sdp,&reason)==0) { - if (sdp){ - op->sdp_offering=FALSE; - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - /*make some sanity check about the SDP received*/ - if (!is_media_description_acceptable(op->base.remote_media)){ - reason=SalReasonNotAcceptable; - } - belle_sip_object_unref(sdp); - }else op->sdp_offering=TRUE; /*INVITE without SDP*/ - } - - if (reason != SalReasonNone){ - sal_error_info_set(&sei, reason,"SIP", 0, NULL, NULL); - sal_call_decline_with_error_info(op, &sei,NULL); - sal_error_info_reset(&sei); - } - return reason; -} - -static void sal_op_reset_descriptions(SalOp *op) { - if (op->base.remote_media){ - sal_media_description_unref(op->base.remote_media); - op->base.remote_media=NULL; - } - if (op->result){ - sal_media_description_unref(op->result); - op->result=NULL; - } -} - -static bool_t is_a_pending_invite_incoming_transaction(belle_sip_transaction_t *tr){ - return BELLE_SIP_OBJECT_IS_INSTANCE_OF(tr, belle_sip_ist_t) && belle_sip_transaction_state_is_transient( - belle_sip_transaction_get_state(tr)); -} - -static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { - SalOp* op = (SalOp*)op_base; - SalReason reason; - belle_sip_server_transaction_t* server_transaction=NULL; - belle_sdp_session_description_t* sdp; - belle_sip_request_t* req = belle_sip_request_event_get_request(event); - belle_sip_dialog_state_t dialog_state; - belle_sip_response_t* resp; - belle_sip_header_t* call_info; - const char *method=belle_sip_request_get_method(req); - bool_t is_update=FALSE; - bool_t drop_op = FALSE; - - if (strcmp("ACK",method)!=0){ /*ACK doesn't create a server transaction*/ - server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); - belle_sip_object_ref(server_transaction); - belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),sal_op_ref(op)); - } - - if (strcmp("INVITE",method)==0) { - if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); - /*updating pending invite transaction*/ - op->pending_server_trans=server_transaction; - belle_sip_object_ref(op->pending_server_trans); - } - - if (strcmp("UPDATE",method)==0) { - if (op->pending_update_server_trans) belle_sip_object_unref(op->pending_update_server_trans); - /*updating pending update transaction*/ - op->pending_update_server_trans=server_transaction; - belle_sip_object_ref(op->pending_update_server_trans); - } - - if (!op->dialog) { - set_or_update_dialog(op,belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(op->pending_server_trans))); - ms_message("new incoming call from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op)); - } - dialog_state=belle_sip_dialog_get_state(op->dialog); - switch(dialog_state) { - case BELLE_SIP_DIALOG_NULL: { - if (strcmp("INVITE",method)==0) { - if (!op->replaces && (op->replaces=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_replaces_t))) { - belle_sip_object_ref(op->replaces); - } else if(op->replaces) { - ms_warning("replace header already set"); - } - - if ( (reason = process_sdp_for_invite(op,req)) == SalReasonNone) { - if ((call_info=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Call-Info"))) { - if( strstr(belle_sip_header_get_unparsed_value(call_info),"answer-after=") != NULL) { - op->auto_answer_asked=TRUE; - ms_message("The caller asked to automatically answer the call(Emergency?)\n"); - } - } - op->base.root->callbacks.call_received(op); - }else{ - sal_error_info_set(&op->error_info, reason, "SIP", 0, NULL, NULL); - op->base.root->callbacks.call_rejected(op); - /*the INVITE was declined by process_sdp_for_invite(). As we are not inside an established dialog, we can drop the op immediately*/ - drop_op = TRUE; - } - break; - }BCTBX_NO_BREAK; /* else same behavior as for EARLY state, thus NO BREAK*/ - } - case BELLE_SIP_DIALOG_EARLY: { - if (strcmp("CANCEL",method)==0) { - if(belle_sip_request_event_get_server_transaction(event)) { - /*first answer 200 ok to cancel*/ - belle_sip_server_transaction_send_response(server_transaction - ,sal_op_create_response_from_request(op,req,200)); - /*terminate invite transaction*/ - call_terminated(op,op->pending_server_trans,487,req); - } else { - /*call leg does not exist*/ - belle_sip_server_transaction_send_response(server_transaction - ,sal_op_create_response_from_request(op,req,481)); - } - } else if (strcmp("PRACK",method)==0) { - resp=sal_op_create_response_from_request(op,req,200); - belle_sip_server_transaction_send_response(server_transaction,resp); - } else if (strcmp("UPDATE",method)==0) { - sal_op_reset_descriptions(op); - if (process_sdp_for_invite(op,req)==SalReasonNone) - op->base.root->callbacks.call_updating(op,TRUE); - } else { - belle_sip_error("Unexpected method [%s] for dialog state BELLE_SIP_DIALOG_EARLY",belle_sip_request_get_method(req)); - unsupported_method(server_transaction,req); - } - break; - } - case BELLE_SIP_DIALOG_CONFIRMED: - /*great ACK received*/ - if (strcmp("ACK",method)==0) { - if (!op->pending_client_trans || - !belle_sip_transaction_state_is_transient(belle_sip_transaction_get_state((belle_sip_transaction_t*)op->pending_client_trans))){ - if (op->sdp_offering){ - SalReason reason; - if (extract_sdp(op,BELLE_SIP_MESSAGE(req),&sdp,&reason)==0){ - if (sdp){ - if (op->base.remote_media) - sal_media_description_unref(op->base.remote_media); - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - sdp_process(op); - belle_sip_object_unref(sdp); - }else{ - ms_warning("SDP expected in ACK but not found."); - } - } - } - op->base.root->callbacks.call_ack_received(op, (SalCustomHeader*)req); - }else{ - ms_message("Ignored received ack since a new client transaction has been started since."); - } - } else if(strcmp("BYE",method)==0) { - call_terminated(op,server_transaction,200,req); - /*call end not notified by dialog deletion because transaction can end before dialog*/ - } else if(strcmp("INVITE",method)==0 || (is_update=(strcmp("UPDATE",method)==0)) ) { - if (is_update && !belle_sip_message_get_body(BELLE_SIP_MESSAGE(req))) { - /*session timer case*/ - /*session expire should be handled. to be done when real session timer (rfc4028) will be implemented*/ - resp=sal_op_create_response_from_request(op,req,200); - belle_sip_server_transaction_send_response(server_transaction,resp); - belle_sip_object_unref(op->pending_update_server_trans); - op->pending_update_server_trans=NULL; - } else { - /*re-invite*/ - sal_op_reset_descriptions(op); - if (process_sdp_for_invite(op,req)==SalReasonNone) - op->base.root->callbacks.call_updating(op,is_update); - } - } else if (strcmp("INFO",method)==0){ - if (belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)) - && strstr(belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)),"picture_fast_update")) { - /*vfu request*/ - ms_message("Receiving VFU request on op [%p]",op); - if (op->base.root->callbacks.vfu_request){ - op->base.root->callbacks.vfu_request(op); - - } - }else{ - belle_sip_message_t *msg = BELLE_SIP_MESSAGE(req); - belle_sip_body_handler_t *body_handler = BELLE_SIP_BODY_HANDLER(sal_op_get_body_handler(op, msg)); - if (body_handler) { - belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(msg, belle_sip_header_content_type_t); - if (content_type - && (strcmp(belle_sip_header_content_type_get_type(content_type), "application") == 0) - && (strcmp(belle_sip_header_content_type_get_subtype(content_type), "dtmf-relay") == 0)) { - char tmp[10]; - if (sal_lines_get_value(belle_sip_message_get_body(msg), "Signal",tmp, sizeof(tmp))){ - op->base.root->callbacks.dtmf_received(op,tmp[0]); - } - }else - op->base.root->callbacks.info_received(op, (SalBodyHandler *)body_handler); - } else { - op->base.root->callbacks.info_received(op,NULL); - } - } - resp=sal_op_create_response_from_request(op,req,200); - belle_sip_server_transaction_send_response(server_transaction,resp); - }else if (strcmp("REFER",method)==0) { - sal_op_process_refer(op,event,server_transaction); - } else if (strcmp("NOTIFY",method)==0) { - sal_op_call_process_notify(op,event,server_transaction); - } else if (strcmp("OPTIONS",method)==0) { - resp=sal_op_create_response_from_request(op,req,200); - belle_sip_server_transaction_send_response(server_transaction,resp); - } else if (strcmp("CANCEL",method)==0) { - belle_sip_transaction_t *last_transaction = belle_sip_dialog_get_last_transaction(op->dialog); - if (last_transaction == NULL || !is_a_pending_invite_incoming_transaction(last_transaction) ) { - /*call leg does not exist because 200ok already sent*/ - belle_sip_server_transaction_send_response(server_transaction,sal_op_create_response_from_request(op,req,481)); - } else { - /* CANCEL on re-INVITE for which a 200ok has not been sent yet */ - belle_sip_server_transaction_send_response(server_transaction, sal_op_create_response_from_request(op, req, 200)); - belle_sip_server_transaction_send_response(BELLE_SIP_SERVER_TRANSACTION(last_transaction), - sal_op_create_response_from_request(op, belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_transaction)), 487)); - } - } else if (strcmp("MESSAGE",method)==0){ - sal_process_incoming_message(op,event); - }else{ - ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog); - unsupported_method(server_transaction,req); - } - break; - default: - ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); - break; - } - - if (server_transaction) belle_sip_object_unref(server_transaction); - if (drop_op) sal_op_release(op); -} - - -/*Call API*/ -int sal_call_set_local_media_description(SalOp *op, SalMediaDescription *desc){ - if (desc) - sal_media_description_ref(desc); - if (op->base.local_media) - sal_media_description_unref(op->base.local_media); - op->base.local_media=desc; - - if (op->base.remote_media){ - /*case of an incoming call where we modify the local capabilities between the time - * the call is ringing and it is accepted (for example if you want to accept without video*/ - /*reset the sdp answer so that it is computed again*/ - if (op->sdp_answer){ - belle_sip_object_unref(op->sdp_answer); - op->sdp_answer=NULL; - } - } - return 0; -} - -static belle_sip_header_allow_t *create_allow(bool_t enable_update){ - belle_sip_header_allow_t* header_allow; - char allow [256]; - snprintf(allow,sizeof(allow),"INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO%s",(enable_update?", UPDATE":"")); - header_allow = belle_sip_header_allow_create(allow); - return header_allow; -} - -static void sal_op_fill_invite(SalOp *op, belle_sip_request_t* invite) { - belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(create_allow(op->base.root->enable_sip_update))); - - if (op->base.root->session_expires!=0){ - belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Session-expires", "600;refresher=uas")); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Supported", "timer")); - } - if (op->base.local_media){ - op->sdp_offering=TRUE; - set_sdp_from_desc(BELLE_SIP_MESSAGE(invite),op->base.local_media); - }else op->sdp_offering=FALSE; - return; -} - -int sal_call(SalOp *op, const char *from, const char *to, const char *subject){ - belle_sip_request_t* invite; - op->dir=SalOpDirOutgoing; - - sal_op_set_from(op,from); - sal_op_set_to(op,to); - - ms_message("[%s] calling [%s] on op [%p]", from, to, op); - invite=sal_op_build_request(op,"INVITE"); - - if( invite == NULL ){ - /* can happen if the op has an invalid address */ - return -1; - } - - sal_op_fill_invite(op,invite); - if (subject) - belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite), belle_sip_header_create("Subject", subject)); - - sal_op_call_fill_cbs(op); - if (op->replaces){ - belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(op->replaces)); - } - if (op->referred_by) - belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(op->referred_by)); - - return sal_op_send_request(op,invite); -} - -static belle_sip_listener_callbacks_t call_op_callbacks={0}; - -void sal_op_call_fill_cbs(SalOp*op) { - if (call_op_callbacks.process_response_event==NULL){ - call_op_callbacks.process_io_error=call_process_io_error; - call_op_callbacks.process_response_event=call_process_response; - call_op_callbacks.process_timeout=call_process_timeout; - call_op_callbacks.process_transaction_terminated=call_process_transaction_terminated; - call_op_callbacks.process_request_event=process_request_event; - call_op_callbacks.process_dialog_terminated=process_dialog_terminated; - } - op->callbacks=&call_op_callbacks; - op->type=SalOpCall; -} - -static void handle_offer_answer_response(SalOp* op, belle_sip_response_t* response) { - if (op->base.local_media){ - /*this is the case where we received an invite without SDP*/ - if (op->sdp_offering) { - set_sdp_from_desc(BELLE_SIP_MESSAGE(response),op->base.local_media); - }else{ - - if ( op->sdp_answer==NULL ) - { - if( op->sdp_handling == SalOpSDPSimulateRemove ){ - ms_warning("Simulating SDP removal in answer for op %p", op); - } else { - sdp_process(op); - } - } - - if (op->sdp_answer){ - set_sdp(BELLE_SIP_MESSAGE(response),op->sdp_answer); - belle_sip_object_unref(op->sdp_answer); - op->sdp_answer=NULL; - } - } - }else{ - ms_error("You are accepting a call but not defined any media capabilities !"); - } -} - -int sal_call_notify_ringing(SalOp *op, bool_t early_media){ - int status_code =early_media?183:180; - belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)); - belle_sip_response_t* ringing_response = sal_op_create_response_from_request(op,req,status_code); - belle_sip_header_t *require; - const char *tags=NULL; - - if (early_media){ - handle_offer_answer_response(op,ringing_response); - } - require=belle_sip_message_get_header((belle_sip_message_t*)req,"Require"); - if (require) tags=belle_sip_header_get_unparsed_value(require); - /* if client requires 100rel, then add necessary stuff*/ - if (tags && strstr(tags,"100rel")!=0) { - belle_sip_message_add_header((belle_sip_message_t*)ringing_response,belle_sip_header_create("Require","100rel")); - belle_sip_message_add_header((belle_sip_message_t*)ringing_response,belle_sip_header_create("RSeq","1")); - } - -#ifndef SAL_OP_CALL_FORCE_CONTACT_IN_RINGING - if (tags && strstr(tags,"100rel")!=0) -#endif - { - belle_sip_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(op); - belle_sip_header_contact_t* contact_header; - if (contact && (contact_header=belle_sip_header_contact_create(contact))) { - belle_sip_message_add_header(BELLE_SIP_MESSAGE(ringing_response),BELLE_SIP_HEADER(contact_header)); - } - } - belle_sip_server_transaction_send_response(op->pending_server_trans,ringing_response); - return 0; -} - - -/*accept an incoming call or, during a call accept a reINVITE*/ -int sal_call_accept(SalOp*h){ - belle_sip_response_t *response; - belle_sip_header_contact_t* contact_header; - belle_sip_server_transaction_t* transaction; - - /*first check if an UPDATE transaction need to be accepted*/ - if (h->pending_update_server_trans) { - transaction=h->pending_update_server_trans; - } else if (h->pending_server_trans) { - /*so it must be an invite/re-invite*/ - transaction=h->pending_server_trans; - } else { - ms_error("No transaction to accept for op [%p]",h); - return -1; - } - ms_message("Accepting server transaction [%p] on op [%p]", transaction, h); - - /* sends a 200 OK */ - response = sal_op_create_response_from_request(h,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(transaction)),200); - if (response==NULL){ - ms_error("Fail to build answer for call"); - return -1; - } - belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(create_allow(h->base.root->enable_sip_update))); - if (h->base.root->session_expires!=0){ -/* if (h->supports_session_timers) {*/ - belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),belle_sip_header_create("Supported", "timer")); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),belle_sip_header_create( "Session-expires", "600;refresher=uac")); - /*}*/ - } - - if ((contact_header=sal_op_create_contact(h))) { - belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact_header)); - } - - _sal_op_add_custom_headers(h, BELLE_SIP_MESSAGE(response)); - - handle_offer_answer_response(h,response); - - belle_sip_server_transaction_send_response(transaction,response); - if (h->pending_update_server_trans) { - belle_sip_object_unref(h->pending_update_server_trans); - h->pending_update_server_trans=NULL; - } - if (h->state == SalOpStateEarly){ - h->state = SalOpStateActive; - } - return 0; -} - -static belle_sip_header_reason_t *sal_call_make_reason_header( const SalErrorInfo *info){ - if (info != NULL){ - belle_sip_header_reason_t* reason = BELLE_SIP_HEADER_REASON(belle_sip_header_reason_new()); - belle_sip_header_reason_set_text(reason, info->status_string); - belle_sip_header_reason_set_protocol(reason,info->protocol); - belle_sip_header_reason_set_cause(reason,info->protocol_code); - return reason; - } - return NULL; -} - -void sal_call_cancel_invite_with_info(SalOp* op, const SalErrorInfo *info) { - belle_sip_request_t* cancel; - ms_message("Cancelling INVITE request from [%s] to [%s] ",sal_op_get_from(op), sal_op_get_to(op)); - cancel = belle_sip_client_transaction_create_cancel(op->pending_client_trans); - if (cancel){ - if (info != NULL){ - belle_sip_header_reason_t* reason = sal_call_make_reason_header(info); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(cancel),BELLE_SIP_HEADER(reason)); - } - sal_op_send_request(op,cancel); - }else if (op->dialog){ - belle_sip_dialog_state_t state = belle_sip_dialog_get_state(op->dialog);; - /*case where the response received is invalid (could not establish a dialog), but the transaction is not cancellable - * because already terminated*/ - switch(state){ - case BELLE_SIP_DIALOG_EARLY: - case BELLE_SIP_DIALOG_NULL: - /*force kill the dialog*/ - ms_warning("op [%p]: force kill of dialog [%p]", op, op->dialog); - belle_sip_dialog_delete(op->dialog); - break; - default: - break; - } - } -} - -int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*optional*/){ - belle_sip_response_t* response; - belle_sip_header_contact_t* contact=NULL; - int status=sal_reason_to_sip_code(reason); - belle_sip_transaction_t *trans; - - if (reason==SalReasonRedirect){ - if (redirection!=NULL) { - if (strstr(redirection,"sip:")!=0) status=302; - else status=380; - contact= belle_sip_header_contact_new(); - belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact),belle_sip_uri_parse(redirection)); - } else { - ms_error("Cannot redirect to null"); - } - } - trans=(belle_sip_transaction_t*)op->pending_server_trans; - if (!trans) trans=(belle_sip_transaction_t*)op->pending_update_server_trans; - if (!trans){ - ms_error("sal_call_decline(): no pending transaction to decline."); - return -1; - } - response = sal_op_create_response_from_request(op,belle_sip_transaction_get_request(trans),status); - if (contact) belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact)); - belle_sip_server_transaction_send_response(BELLE_SIP_SERVER_TRANSACTION(trans),response); - return 0; -} - -int sal_call_decline_with_error_info(SalOp *op, const SalErrorInfo *info, const char *redirection /*optional*/){ - belle_sip_response_t* response; - belle_sip_header_contact_t* contact=NULL; - int status = info->protocol_code; - belle_sip_transaction_t *trans; - - if (info->reason==SalReasonRedirect){ - if (redirection!=NULL) { - if (strstr(redirection,"sip:")!=0) status=302; - else status=380; - contact= belle_sip_header_contact_new(); - belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact),belle_sip_uri_parse(redirection)); - } else { - ms_error("Cannot redirect to null"); - } - } - trans=(belle_sip_transaction_t*)op->pending_server_trans; - if (!trans) trans=(belle_sip_transaction_t*)op->pending_update_server_trans; - if (!trans){ - ms_error("sal_call_decline_with_error_info(): no pending transaction to decline."); - return -1; - } - response = sal_op_create_response_from_request(op,belle_sip_transaction_get_request(trans),status); - belle_sip_header_reason_t* reason_header = sal_call_make_reason_header(info->sub_sei); - if (reason_header) { - belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(reason_header)); - } - - if (contact) { - belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact)); - } - belle_sip_server_transaction_send_response(BELLE_SIP_SERVER_TRANSACTION(trans),response); - return 0; -} - -int sal_call_update(SalOp *op, const char *subject, bool_t no_user_consent){ - belle_sip_request_t *update; - belle_sip_dialog_state_t state; - - if (op->dialog == NULL) { - /* If the dialog does not exist, this is that we are trying to recover from a connection loss - during a very early state of outgoing call initiation (the dialog has not been created yet). */ - const char *from = sal_op_get_from(op); - const char *to = sal_op_get_to(op); - return sal_call(op, from, to, subject); - } - - state = belle_sip_dialog_get_state(op->dialog); - belle_sip_dialog_enable_pending_trans_checking(op->dialog,op->base.root->pending_trans_checking); - - /*check for dialog state*/ - if ( state == BELLE_SIP_DIALOG_CONFIRMED) { - if (no_user_consent) - update=belle_sip_dialog_create_request(op->dialog,"UPDATE"); - else - update=belle_sip_dialog_create_request(op->dialog,"INVITE"); - } else if (state == BELLE_SIP_DIALOG_EARLY) { - update=belle_sip_dialog_create_request(op->dialog,"UPDATE"); - } else { - ms_error("Cannot update op [%p] with dialog [%p] in state [%s]",op, op->dialog,belle_sip_dialog_state_to_string(state)); - return -1; - } - if (update){ - belle_sip_message_add_header(BELLE_SIP_MESSAGE(update),belle_sip_header_create( "Subject", subject)); - sal_op_fill_invite(op, update); - return sal_op_send_request(op,update); - } - /*it failed why ?*/ - if (belle_sip_dialog_request_pending(op->dialog)) - sal_error_info_set(&op->error_info,SalReasonRequestPending, "SIP", 491,NULL,NULL); - else - sal_error_info_set(&op->error_info,SalReasonUnknown, "SIP", 500,NULL,NULL); - return -1; -} - -SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){ - return h->base.remote_media; -} - -SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ - if (h->base.local_media && h->base.remote_media && !h->result){ - sdp_process(h); - } - return h->result; -} - -int sal_call_send_dtmf(SalOp *h, char dtmf){ - if (h->dialog && (belle_sip_dialog_get_state(h->dialog) == BELLE_SIP_DIALOG_CONFIRMED || belle_sip_dialog_get_state(h->dialog) == BELLE_SIP_DIALOG_EARLY)){ - belle_sip_request_t *req=belle_sip_dialog_create_queued_request(h->dialog,"INFO"); - if (req){ - size_t bodylen; - char dtmf_body[128]={0}; - - snprintf(dtmf_body, sizeof(dtmf_body)-1, "Signal=%c\r\nDuration=250\r\n", dtmf); - bodylen=strlen(dtmf_body); - belle_sip_message_set_body((belle_sip_message_t*)req,dtmf_body,bodylen); - belle_sip_message_add_header((belle_sip_message_t*)req,(belle_sip_header_t*)belle_sip_header_content_length_create(bodylen)); - belle_sip_message_add_header((belle_sip_message_t*)req,(belle_sip_header_t*)belle_sip_header_content_type_create("application", "dtmf-relay")); - sal_op_send_request(h,req); - }else ms_error("sal_call_send_dtmf(): could not build request"); - }else ms_error("sal_call_send_dtmf(): no dialog"); - return 0; -} - - -int sal_call_terminate_with_error(SalOp *op, const SalErrorInfo *info){ - SalErrorInfo sei; - const SalErrorInfo *p_sei; - belle_sip_dialog_state_t dialog_state = op->dialog ? belle_sip_dialog_get_state(op->dialog) : BELLE_SIP_DIALOG_NULL; - int ret = 0; - - memset(&sei, 0, sizeof(sei)); - if (info == NULL && dialog_state != BELLE_SIP_DIALOG_CONFIRMED && op->dir == SalOpDirIncoming){ - /*the purpose of this line is to set a default SalErrorInfo for declining an incoming call (not yet established of course) */ - sal_error_info_set(&sei,SalReasonDeclined, "SIP", 0, NULL, NULL); - p_sei = &sei; - } else{ - p_sei = info; - } - if (op->state==SalOpStateTerminating || op->state==SalOpStateTerminated) { - ms_error("Cannot terminate op [%p] in state [%s]",op,sal_op_state_to_string(op->state)); - ret = -1; - goto end; - } - switch(dialog_state) { - case BELLE_SIP_DIALOG_CONFIRMED: { - belle_sip_request_t * req = belle_sip_dialog_create_request(op->dialog,"BYE"); - if (info != NULL){ - belle_sip_header_reason_t* reason = sal_call_make_reason_header(info); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(reason)); - } - sal_op_send_request(op,req); - op->state=SalOpStateTerminating; - break; - } - - case BELLE_SIP_DIALOG_NULL: { - if (op->dir == SalOpDirIncoming) { - sal_call_decline_with_error_info(op, p_sei, NULL); - op->state=SalOpStateTerminated; - } else if (op->pending_client_trans){ - if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(op->pending_client_trans)) == BELLE_SIP_TRANSACTION_PROCEEDING){ - cancelling_invite(op, p_sei); - }else{ - /* Case where the CANCEL cannot be sent because no provisional response was received so far. - * The Op must be kept for the time of the transaction in case a response is received later. - * The state is passed to Terminating to remember to terminate later. - */ - op->state=SalOpStateTerminating; - /* However, even if the transaction is kept alive, we can stop sending retransmissions to avoid flowing the network with no longer - * necessary messages and avoid confusion in logs.*/ - belle_sip_client_transaction_stop_retransmissions(op->pending_client_trans); - } - } - break; - } - case BELLE_SIP_DIALOG_EARLY: { - if (op->dir == SalOpDirIncoming) { - sal_call_decline_with_error_info(op, p_sei,NULL); - op->state=SalOpStateTerminated; - } else { - cancelling_invite(op, p_sei); - } - break; - } - default: { - ms_error("sal_call_terminate not implemented yet for dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); - ret = -1; - goto end; - } - } -end: - sal_error_info_reset(&sei); - return ret; -} - - -int sal_call_terminate(SalOp *op){ - return sal_call_terminate_with_error(op, NULL); -} - - -bool_t sal_call_autoanswer_asked(SalOp *op){ - return op->auto_answer_asked; -} - -void sal_call_send_vfu_request(SalOp *op){ - char info_body[] = - "" - "" - " " - " " - " " - " " - " " - ""; - size_t content_lenth = sizeof(info_body) - 1; - belle_sip_dialog_state_t dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL; /*no dialog = dialog in NULL state*/ - if (dialog_state == BELLE_SIP_DIALOG_CONFIRMED) { - belle_sip_request_t* info = belle_sip_dialog_create_queued_request(op->dialog,"INFO"); - int error=TRUE; - if (info) { - belle_sip_message_add_header(BELLE_SIP_MESSAGE(info),BELLE_SIP_HEADER(belle_sip_header_content_type_create("application","media_control+xml"))); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(info),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_lenth))); - belle_sip_message_set_body(BELLE_SIP_MESSAGE(info),info_body,content_lenth); - error=sal_op_send_request(op,info); - } - if (error) - ms_warning("Cannot send vfu request to [%s] ", sal_op_get_to(op)); - - } else { - ms_warning("Cannot send vfu request to [%s] because dialog [%p] in wrong state [%s]",sal_op_get_to(op) - ,op->dialog - ,belle_sip_dialog_state_to_string(dialog_state)); - } - - return ; -} - -int sal_call_is_offerer(const SalOp *h){ - return h->sdp_offering; -} - -bool_t sal_call_compare_op(const SalOp *op1, const SalOp *op2) { - if (strcmp(op1->base.call_id, op2->base.call_id) == 0) return TRUE; - return FALSE; -} - -bool_t sal_call_dialog_request_pending(const SalOp *op) { - return belle_sip_dialog_request_pending(op->dialog) ? TRUE : FALSE; -} - -const char * sal_call_get_local_tag(SalOp *op) { - return belle_sip_dialog_get_local_tag(op->dialog); -} - -const char * sal_call_get_remote_tag(SalOp *op) { - return belle_sip_dialog_get_remote_tag(op->dialog); -} - -void sal_call_set_replaces(SalOp *op, const char *call_id, const char *from_tag, const char *to_tag) { - belle_sip_header_replaces_t *replaces = belle_sip_header_replaces_create(call_id, from_tag, to_tag); - sal_op_set_replaces(op, replaces); -} diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c deleted file mode 100644 index 8fe460314..000000000 --- a/coreapi/bellesip_sal/sal_op_call_transfer.c +++ /dev/null @@ -1,273 +0,0 @@ -/* -linphone -Copyright (C) 2012 Belledonne Communications, Grenoble, France - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#include "sal_impl.h" -#include "offeranswer.h" - - - -/*call transfer*/ -static void sal_op_set_referred_by(SalOp* op,belle_sip_header_referred_by_t* referred_by) { - if (op->referred_by){ - belle_sip_object_unref(op->referred_by); - } - op->referred_by=referred_by; - belle_sip_object_ref(op->referred_by); -} - - -int sal_call_refer_to(SalOp *op, belle_sip_header_refer_to_t* refer_to, belle_sip_header_referred_by_t* referred_by){ - char* tmp; - belle_sip_request_t* req=op->dialog?belle_sip_dialog_create_request(op->dialog,"REFER"):sal_op_build_request(op, "REFER"); - if (!req) { - tmp=belle_sip_uri_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to))); - ms_error("Cannot refer to [%s] for op [%p]",tmp,op); - belle_sip_free(tmp); - return -1; - } - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(refer_to)); - if (referred_by) belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(referred_by)); - return sal_op_send_request(op,req); -} - -int sal_call_refer(SalOp *op, const char *refer_to){ - belle_sip_header_address_t *referred_by; - belle_sip_header_refer_to_t* refer_to_header; - if (op->dialog) { - referred_by=(belle_sip_header_address_t*)belle_sip_object_clone(BELLE_SIP_OBJECT(belle_sip_dialog_get_local_party(op->dialog))); - }else{ - referred_by=BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op)); - } - refer_to_header=belle_sip_header_refer_to_create(belle_sip_header_address_parse(refer_to)); - - return sal_call_refer_to(op,refer_to_header,belle_sip_header_referred_by_create(referred_by)); -} - -int sal_call_refer_with_replaces(SalOp *op, SalOp *other_call_op){ - belle_sip_dialog_state_t other_call_dialog_state=other_call_op->dialog?belle_sip_dialog_get_state(other_call_op->dialog):BELLE_SIP_DIALOG_NULL; - belle_sip_dialog_state_t op_dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL; - belle_sip_header_replaces_t* replaces; - belle_sip_header_refer_to_t* refer_to; - belle_sip_header_referred_by_t* referred_by; - const char* from_tag; - const char* to_tag; - char* escaped_replaces; - /*first, build refer to*/ - if ((other_call_dialog_state!=BELLE_SIP_DIALOG_CONFIRMED) && (other_call_dialog_state!=BELLE_SIP_DIALOG_EARLY)) { - ms_error("wrong dialog state [%s] for op [%p], should be BELLE_SIP_DIALOG_CONFIRMED or BELE_SIP_DIALOG_EARLY", - belle_sip_dialog_state_to_string(other_call_dialog_state), - other_call_op); - return -1; - } - if (op_dialog_state!=BELLE_SIP_DIALOG_CONFIRMED) { - ms_error("wrong dialog state [%s] for op [%p], should be BELLE_SIP_DIALOG_CONFIRMED", - belle_sip_dialog_state_to_string(op_dialog_state), - op); - return -1; - } - - refer_to=belle_sip_header_refer_to_create(belle_sip_dialog_get_remote_party(other_call_op->dialog)); - belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(refer_to)); - /*rfc3891 - ... - 4. User Agent Client Behavior: Sending a Replaces Header - - A User Agent that wishes to replace a single existing early or - confirmed dialog with a new dialog of its own, MAY send the target - User Agent an INVITE request containing a Replaces header field. The - User Agent Client (UAC) places the Call-ID, to-tag, and from-tag - information for the target dialog in a single Replaces header field - and sends the new INVITE to the target.*/ - from_tag=belle_sip_dialog_get_local_tag(other_call_op->dialog); - to_tag=belle_sip_dialog_get_remote_tag(other_call_op->dialog); - - replaces=belle_sip_header_replaces_create(belle_sip_header_call_id_get_call_id(belle_sip_dialog_get_call_id(other_call_op->dialog)) - ,from_tag,to_tag); - escaped_replaces=belle_sip_header_replaces_value_to_escaped_string(replaces); - belle_sip_uri_set_header(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to)),"Replaces",escaped_replaces); - belle_sip_free(escaped_replaces); - referred_by=belle_sip_header_referred_by_create(belle_sip_dialog_get_local_party(op->dialog)); - belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(referred_by)); - return sal_call_refer_to(op,refer_to,referred_by); -} -/* -int sal_call_accept_refer(SalOp *h){ - ms_fatal("sal_call_accept_refer not implemented yet"); - return -1; -}*/ -/*informs this call is consecutive to an incoming refer */ -int sal_call_set_referer(SalOp *h, SalOp *refered_call){ - if (refered_call->replaces) - sal_op_set_replaces(h,refered_call->replaces); - if (refered_call->referred_by) - sal_op_set_referred_by(h,refered_call->referred_by); - return 0; -} -/* returns the SalOp of a call that should be replaced by h, if any */ -SalOp *sal_call_get_replaces(SalOp *op){ - if (op && op->replaces){ - /*rfc3891 - 3. User Agent Server Behavior: Receiving a Replaces Header - - The Replaces header contains information used to match an existing - SIP dialog (call-id, to-tag, and from-tag). Upon receiving an INVITE - with a Replaces header, the User Agent (UA) attempts to match this - information with a confirmed or early dialog. The User Agent Server - (UAS) matches the to-tag and from-tag parameters as if they were tags - present in an incoming request. In other words, the to-tag parameter - is compared to the local tag, and the from-tag parameter is compared - to the remote tag. - */ - belle_sip_dialog_t* dialog=belle_sip_provider_find_dialog(op->base.root->prov - ,belle_sip_header_replaces_get_call_id(op->replaces) - ,belle_sip_header_replaces_get_to_tag(op->replaces) - ,belle_sip_header_replaces_get_from_tag(op->replaces)); - - if (!dialog) { - /*for backward compatibility with liblinphone <= 3.10.2-243 */ - dialog=belle_sip_provider_find_dialog(op->base.root->prov - ,belle_sip_header_replaces_get_call_id(op->replaces) - ,belle_sip_header_replaces_get_from_tag(op->replaces) - ,belle_sip_header_replaces_get_to_tag(op->replaces)); - } - if (dialog) { - return (SalOp*)belle_sip_dialog_get_application_data(dialog); - } - } - return NULL; -} - -static int send_notify_for_refer(SalOp* op, int code, const char *reason){ - belle_sip_request_t* notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"); - char *sipfrag=belle_sip_strdup_printf("SIP/2.0 %i %s\r\n",code,reason); - size_t content_length=strlen(sipfrag); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) - ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,-1))); - - belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),belle_sip_header_create("Event","refer")); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(belle_sip_header_content_type_create("message","sipfrag"))); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length))); - belle_sip_message_assign_body(BELLE_SIP_MESSAGE(notify),sipfrag,content_length); - return sal_op_send_request(op,notify); -} - -static void notify_last_response(SalOp *op, SalOp *newcall){ - belle_sip_client_transaction_t *tr=newcall->pending_client_trans; - belle_sip_response_t *resp=NULL; - if (tr){ - resp=belle_sip_transaction_get_response((belle_sip_transaction_t*)tr); - } - if (resp==NULL){ - send_notify_for_refer(op, 100, "Trying"); - }else{ - send_notify_for_refer(op, belle_sip_response_get_status_code(resp), belle_sip_response_get_reason_phrase(resp)); - } -} - -int sal_call_notify_refer_state(SalOp *op, SalOp *newcall){ - belle_sip_dialog_state_t state; - if(belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_TERMINATED){ - return 0; - } - state = newcall->dialog?belle_sip_dialog_get_state(newcall->dialog):BELLE_SIP_DIALOG_NULL; - switch(state) { - case BELLE_SIP_DIALOG_EARLY: - send_notify_for_refer(op, 100, "Trying"); - break; - case BELLE_SIP_DIALOG_CONFIRMED: - send_notify_for_refer(op, 200, "Ok"); - break; - case BELLE_SIP_DIALOG_TERMINATED: - case BELLE_SIP_DIALOG_NULL: - notify_last_response(op,newcall); - break; - } - return 0; -} - - -void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event, belle_sip_server_transaction_t *server_transaction){ - belle_sip_request_t* req = belle_sip_request_event_get_request(event); - belle_sip_header_refer_to_t *refer_to= belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_refer_to_t); - belle_sip_header_referred_by_t *referred_by= belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_referred_by_t); - belle_sip_response_t* resp; - belle_sip_uri_t* refer_to_uri; - char* refer_to_uri_str; - - ms_message("Receiving REFER request on op [%p]",op); - if (refer_to) { - refer_to_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to)); - - if (refer_to_uri && belle_sip_uri_get_header(refer_to_uri,"Replaces")) { - sal_op_set_replaces(op,belle_sip_header_replaces_create2(belle_sip_uri_get_header(refer_to_uri,"Replaces"))); - belle_sip_uri_remove_header(refer_to_uri,"Replaces"); - } - if (referred_by){ - sal_op_set_referred_by(op,referred_by); - } - refer_to_uri_str=belle_sip_uri_to_string(refer_to_uri); - resp = sal_op_create_response_from_request(op,req,202); - belle_sip_server_transaction_send_response(server_transaction,resp); - op->base.root->callbacks.refer_received(op->base.root,op,refer_to_uri_str); - belle_sip_free(refer_to_uri_str); - } else { - ms_warning("cannot do anything with the refer without destination\n"); - resp = sal_op_create_response_from_request(op,req,400); - belle_sip_server_transaction_send_response(server_transaction,resp); - } - -} - -void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event, belle_sip_server_transaction_t* server_transaction){ - belle_sip_request_t* req = belle_sip_request_event_get_request(event); - const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); - belle_sip_header_t* header_event=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Event"); - belle_sip_header_content_type_t* content_type = belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t); - belle_sip_response_t* resp; - - ms_message("Receiving NOTIFY request on op [%p]",op); - if (header_event - && strncasecmp(belle_sip_header_get_unparsed_value(header_event),"refer",strlen("refer"))==0 - && content_type - && strcmp(belle_sip_header_content_type_get_type(content_type),"message")==0 - && strcmp(belle_sip_header_content_type_get_subtype(content_type),"sipfrag")==0 - && body){ - belle_sip_response_t* sipfrag=BELLE_SIP_RESPONSE(belle_sip_message_parse(body)); - - if (sipfrag){ - int code=belle_sip_response_get_status_code(sipfrag); - SalReferStatus status=SalReferFailed; - if (code<200){ - status=SalReferTrying; - }else if (code<300){ - status=SalReferSuccess; - }else if (code>=400){ - status=SalReferFailed; - } - belle_sip_object_unref(sipfrag); - resp = sal_op_create_response_from_request(op,req,200); - belle_sip_server_transaction_send_response(server_transaction,resp); - op->base.root->callbacks.notify_refer(op,status); - } - }else{ - ms_error("Notify without sipfrag, trashing"); - resp = sal_op_create_response_from_request(op,req,501); - belle_sip_server_transaction_send_response(server_transaction,resp); - } -} - diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c deleted file mode 100644 index ef0a2cb17..000000000 --- a/coreapi/bellesip_sal/sal_op_events.c +++ /dev/null @@ -1,385 +0,0 @@ -/* -linphone -Copyright (C) 2012 Belledonne Communications, Grenoble, France - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#include "sal_impl.h" - -SalSubscribeStatus belle_sip_message_get_subscription_state(const belle_sip_message_t *msg){ - belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(msg,belle_sip_header_subscription_state_t); - SalSubscribeStatus sss=SalSubscribeNone; - if (subscription_state_header){ - if (strcmp(belle_sip_header_subscription_state_get_state(subscription_state_header),BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED)==0) - sss=SalSubscribeTerminated; - else if (strcmp(belle_sip_header_subscription_state_get_state(subscription_state_header),BELLE_SIP_SUBSCRIPTION_STATE_PENDING)==0) - sss=SalSubscribePending; - else if (strcmp(belle_sip_header_subscription_state_get_state(subscription_state_header),BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE)==0) - sss=SalSubscribeActive; - } - return sss; -} - -static void subscribe_refresher_listener (belle_sip_refresher_t* refresher - ,void* user_pointer - ,unsigned int status_code - ,const char* reason_phrase, int will_retry) { - SalOp* op = (SalOp*)user_pointer; - belle_sip_transaction_t *tr=BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher)); - /*belle_sip_response_t* response=belle_sip_transaction_get_response(tr);*/ - SalSubscribeStatus sss=SalSubscribeTerminated; - - ms_message("Subscribe refresher [%i] reason [%s] ",status_code,reason_phrase?reason_phrase:"none"); - if (status_code>=200 && status_code<300){ - if (status_code==200) sss=SalSubscribeActive; - else if (status_code==202) sss=SalSubscribePending; - set_or_update_dialog(op,belle_sip_transaction_get_dialog(tr)); - op->base.root->callbacks.subscribe_response(op,sss, will_retry); - } else if (status_code >= 300) { - SalReason reason = SalReasonUnknown; - if (status_code == 503) { /*refresher returns 503 for IO error*/ - reason = SalReasonIOError; - } - sal_error_info_set(&op->error_info, reason, "SIP", (int)status_code,reason_phrase,NULL); - op->base.root->callbacks.subscribe_response(op,sss, will_retry); - }else if (status_code==0){ - op->base.root->callbacks.on_expire(op); - } - -} - -static void subscribe_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ - SalOp *op = (SalOp*)user_ctx; - belle_sip_object_t *src = belle_sip_io_error_event_get_source(event); - if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(src, belle_sip_client_transaction_t)){ - belle_sip_client_transaction_t *tr = BELLE_SIP_CLIENT_TRANSACTION(src); - belle_sip_request_t* req = belle_sip_transaction_get_request((belle_sip_transaction_t*)tr); - const char *method=belle_sip_request_get_method(req); - - if (!op->dialog) { - /*this is handling outgoing out-of-dialog notifies*/ - if (strcmp(method,"NOTIFY")==0){ - SalErrorInfo *ei=&op->error_info; - sal_error_info_set(ei,SalReasonIOError, "SIP", 0,NULL,NULL); - op->base.root->callbacks.on_notify_response(op); - } - } - } -} - -static void subscribe_process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) { - belle_sip_dialog_t *dialog = belle_sip_dialog_terminated_event_get_dialog(event); - SalOp* op= (SalOp*)ctx; - if (op->dialog) { - if (belle_sip_dialog_terminated_event_is_expired(event)){ - if (!belle_sip_dialog_is_server(dialog)){ - /*notify the app that our subscription is dead*/ - const char *eventname = NULL; - if (op->event){ - eventname = belle_sip_header_event_get_package_name(op->event); - } - op->base.root->callbacks.notify(op, SalSubscribeTerminated, eventname, NULL); - }else{ - op->base.root->callbacks.incoming_subscribe_closed(op); - } - } - set_or_update_dialog(op, NULL); - } -} - -static void subscribe_response_event(void *op_base, const belle_sip_response_event_t *event){ - SalOp *op = (SalOp*)op_base; - belle_sip_request_t * req; - const char *method; - belle_sip_client_transaction_t *tr = belle_sip_response_event_get_client_transaction(event); - - if (!tr) return; - req = belle_sip_transaction_get_request((belle_sip_transaction_t*)tr); - method = belle_sip_request_get_method(req); - - if (!op->dialog) { - if (strcmp(method,"NOTIFY")==0){ - sal_op_set_error_info_from_response(op,belle_sip_response_event_get_response(event)); - op->base.root->callbacks.on_notify_response(op); - } - } -} - -static void subscribe_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { - SalOp *op = (SalOp*)user_ctx; - belle_sip_request_t * req; - const char *method; - belle_sip_client_transaction_t *tr = belle_sip_timeout_event_get_client_transaction(event); - - if (!tr) return; - req = belle_sip_transaction_get_request((belle_sip_transaction_t*)tr); - method = belle_sip_request_get_method(req); - - if (!op->dialog) { - /*this is handling outgoing out-of-dialog notifies*/ - if (strcmp(method,"NOTIFY")==0){ - SalErrorInfo *ei=&op->error_info; - sal_error_info_set(ei,SalReasonRequestTimeout, "SIP", 0,NULL,NULL); - op->base.root->callbacks.on_notify_response(op); - } - } -} - -static void subscribe_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { -} - -static void handle_notify(SalOp *op, belle_sip_request_t *req, const char *eventname, SalBodyHandler* body_handler){ - SalSubscribeStatus sub_state; - belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t); - belle_sip_response_t* resp; - belle_sip_server_transaction_t* server_transaction = op->pending_server_trans; - - if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) { - sub_state=SalSubscribeTerminated; - ms_message("Outgoing subscription terminated by remote [%s]",sal_op_get_to(op)); - } else - sub_state=SalSubscribeActive; - sal_op_ref(op); - op->base.root->callbacks.notify(op,sub_state,eventname,body_handler); - resp=sal_op_create_response_from_request(op,req,200); - belle_sip_server_transaction_send_response(server_transaction,resp); - sal_op_unref(op); -} - -static void subscribe_process_request_event(void *op_base, const belle_sip_request_event_t *event) { - SalOp* op = (SalOp*)op_base; - belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); - belle_sip_request_t* req = belle_sip_request_event_get_request(event); - belle_sip_dialog_state_t dialog_state; - belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t); - belle_sip_header_event_t *event_header; - belle_sip_body_handler_t *body_handler; - belle_sip_response_t* resp; - const char *eventname=NULL; - const char *method=belle_sip_request_get_method(req); - belle_sip_dialog_t *dialog = NULL; - - belle_sip_object_ref(server_transaction); - if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); - op->pending_server_trans=server_transaction; - - event_header=belle_sip_message_get_header_by_type(req,belle_sip_header_event_t); - body_handler = BELLE_SIP_BODY_HANDLER(sal_op_get_body_handler(op, BELLE_SIP_MESSAGE(req))); - - if (event_header==NULL){ - ms_warning("No event header in incoming SUBSCRIBE."); - resp=sal_op_create_response_from_request(op,req,400); - belle_sip_server_transaction_send_response(server_transaction,resp); - if (!op->dialog) sal_op_release(op); - return; - } - if (op->event==NULL) { - op->event=event_header; - belle_sip_object_ref(op->event); - } - eventname=belle_sip_header_event_get_package_name(event_header); - - if (!op->dialog) { - if (strcmp(method,"SUBSCRIBE")==0){ - dialog = belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(server_transaction)); - if (!dialog){ - resp=sal_op_create_response_from_request(op,req,481); - belle_sip_server_transaction_send_response(server_transaction,resp); - sal_op_release(op); - return; - } - set_or_update_dialog(op, dialog); - ms_message("new incoming subscription from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op)); - }else{ /*this is a NOTIFY*/ - handle_notify(op, req, eventname, (SalBodyHandler *)body_handler); - return; - } - } - dialog_state=belle_sip_dialog_get_state(op->dialog); - switch(dialog_state) { - - case BELLE_SIP_DIALOG_NULL: { - const char *type = NULL; - belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_content_type_t); - if (content_type) type = belle_sip_header_content_type_get_type(content_type); - op->base.root->callbacks.subscribe_received(op, eventname, type ? (SalBodyHandler *)body_handler : NULL); - break; - } - case BELLE_SIP_DIALOG_EARLY: - ms_error("unexpected method [%s] for dialog [%p] in state BELLE_SIP_DIALOG_EARLY ",belle_sip_request_get_method(req),op->dialog); - break; - - case BELLE_SIP_DIALOG_CONFIRMED: - if (strcmp("NOTIFY",method)==0) { - handle_notify(op, req, eventname, (SalBodyHandler *)body_handler); - } else if (strcmp("SUBSCRIBE",method)==0) { - /*either a refresh of an unsubscribe*/ - if (expires && belle_sip_header_expires_get_expires(expires)>0) { - resp=sal_op_create_response_from_request(op,req,200); - belle_sip_server_transaction_send_response(server_transaction,resp); - } else if(expires) { - ms_message("Unsubscribe received from [%s]",sal_op_get_from(op)); - resp=sal_op_create_response_from_request(op,req,200); - belle_sip_server_transaction_send_response(server_transaction,resp); - op->base.root->callbacks.incoming_subscribe_closed(op); - } - } - break; - default: { - ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); - } - } -} - -static belle_sip_listener_callbacks_t op_subscribe_callbacks={ 0 }; - -/*Invoke when sal_op_release is called by upper layer*/ -static void sal_op_release_cb(struct SalOpBase* op_base) { - SalOp *op =(SalOp*)op_base; - if(op->refresher) { - belle_sip_refresher_stop(op->refresher); - belle_sip_object_unref(op->refresher); - op->refresher=NULL; - set_or_update_dialog(op,NULL); /*only if we have refresher. else dialog terminated event will remove association*/ - } - -} - -void sal_op_subscribe_fill_cbs(SalOp*op) { - if (op_subscribe_callbacks.process_io_error==NULL){ - op_subscribe_callbacks.process_io_error=subscribe_process_io_error; - op_subscribe_callbacks.process_response_event=subscribe_response_event; - op_subscribe_callbacks.process_timeout=subscribe_process_timeout; - op_subscribe_callbacks.process_transaction_terminated=subscribe_process_transaction_terminated; - op_subscribe_callbacks.process_request_event=subscribe_process_request_event; - op_subscribe_callbacks.process_dialog_terminated=subscribe_process_dialog_terminated; - } - op->callbacks=&op_subscribe_callbacks; - op->type=SalOpSubscribe; - op->base.release_cb=sal_op_release_cb; -} - - -int sal_subscribe(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBodyHandler *body_handler){ - belle_sip_request_t *req=NULL; - - if (from) - sal_op_set_from(op,from); - if (to) - sal_op_set_to(op,to); - - if (!op->dialog){ - sal_op_subscribe_fill_cbs(op); - req=sal_op_build_request(op,"SUBSCRIBE"); - if( req == NULL ) { - return -1; - } - sal_op_set_event(op, eventname); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(op->event)); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(expires))); - belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(body_handler)); - return sal_op_send_and_create_refresher(op,req,expires,subscribe_refresher_listener); - }else if (op->refresher){ - const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(op->refresher); - belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr); - /* modify last request to update body*/ - belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(last_req), BELLE_SIP_BODY_HANDLER(body_handler)); - return belle_sip_refresher_refresh(op->refresher,expires); - } - ms_warning("sal_subscribe(): no dialog and no refresher ?"); - return -1; -} - -int sal_unsubscribe(SalOp *op){ - if (op->refresher){ - const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(op->refresher); - belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr); - belle_sip_message_set_body(BELLE_SIP_MESSAGE(last_req), NULL, 0); - belle_sip_refresher_refresh(op->refresher,0); - return 0; - } - return -1; -} - -int sal_subscribe_accept(SalOp *op){ - belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)); - belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t); - belle_sip_response_t* resp = sal_op_create_response_from_request(op,req,200); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(expires)); - belle_sip_server_transaction_send_response(op->pending_server_trans,resp); - return 0; -} - -int sal_notify_pending_state(SalOp *op){ - - if (op->dialog != NULL && op->pending_server_trans) { - belle_sip_request_t* notify; - belle_sip_header_subscription_state_t* sub_state; - ms_message("Sending NOTIFY with subscription state pending for op [%p]",op); - if (!(notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"))) { - ms_error("Cannot create NOTIFY on op [%p]",op); - return -1; - } - if (op->event) belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(op->event)); - sub_state=belle_sip_header_subscription_state_new(); - belle_sip_header_subscription_state_set_state(sub_state,BELLE_SIP_SUBSCRIPTION_STATE_PENDING); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify), BELLE_SIP_HEADER(sub_state)); - return sal_op_send_request(op,notify); - } else { - ms_warning("NOTIFY with subscription state pending for op [%p] not implemented in this case (either dialog pending trans does not exist",op); - } - - return 0; -} - - -int sal_subscribe_decline(SalOp *op, SalReason reason){ - belle_sip_response_t* resp = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)), - sal_reason_to_sip_code(reason)); - belle_sip_server_transaction_send_response(op->pending_server_trans,resp); - return 0; -} - -int sal_notify(SalOp *op, const SalBodyHandler *body_handler){ - belle_sip_request_t* notify; - - if (op->dialog){ - if (!(notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"))) return -1; - }else{ - sal_op_subscribe_fill_cbs(op); - notify = sal_op_build_request(op, "NOTIFY"); - } - - if (op->event) belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(op->event)); - - belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) - ,op->dialog ? - BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,600)) : - BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,0)) - ); - belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(notify), BELLE_SIP_BODY_HANDLER(body_handler)); - return sal_op_send_request(op,notify); -} - -int sal_notify_close(SalOp *op){ - belle_sip_request_t* notify; - if (!op->dialog) return -1; - if (!(notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"))) return -1; - if (op->event) belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(op->event)); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) - ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1))); - return sal_op_send_request(op,notify); -} - diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index d99dbc274..7880fa4c6 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -17,483 +17,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sal_impl.h" +#include "sal/sal.hpp" -/*create an operation */ -SalOp * sal_op_new(Sal *sal){ - SalOp *op=ms_new0(SalOp,1); - __sal_op_init(op,sal); - op->type=SalOpUnknown; - op->privacy=SalPrivacyNone; - op->manual_refresher=FALSE;/*tells that requests with expiry (SUBSCRIBE, PUBLISH) will be automatically refreshed*/ - op->sdp_handling=sal->default_sdp_handling; - sal_op_ref(op); - return op; -} - -void sal_op_kill_dialog(SalOp *op) { - ms_warning("op [%p]: force kill of dialog [%p]", op, op->dialog); - belle_sip_dialog_delete(op->dialog); -} - -void sal_op_release(SalOp *op){ - /*if in terminating state, keep this state because it means we are waiting for a response to be able to terminate the operation.*/ - if (op->state!=SalOpStateTerminating) - op->state=SalOpStateTerminated; - sal_op_set_user_pointer(op,NULL);/*mandatory because releasing op doesn't not mean freeing op. Make sure back pointer will not be used later*/ - if (op->base.release_cb) - op->base.release_cb(&op->base); - if (op->refresher) { - belle_sip_refresher_stop(op->refresher); - } - op->op_released = TRUE; - sal_op_unref(op); -} - -void sal_op_release_impl(SalOp *op){ - ms_message("Destroying op [%p] of type [%s]",op,sal_op_type_to_string(op->type)); - if (op->pending_auth_transaction) belle_sip_object_unref(op->pending_auth_transaction); - sal_remove_pending_auth(op->base.root,op); - if (op->auth_info) { - sal_auth_info_delete(op->auth_info); - } - if (op->sdp_answer) belle_sip_object_unref(op->sdp_answer); - if (op->refresher) { - belle_sip_object_unref(op->refresher); - op->refresher=NULL; - } - if (op->result) - sal_media_description_unref(op->result); - if(op->replaces) belle_sip_object_unref(op->replaces); - if(op->referred_by) belle_sip_object_unref(op->referred_by); - - if (op->pending_client_trans) belle_sip_object_unref(op->pending_client_trans); - if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); - if (op->pending_update_server_trans) belle_sip_object_unref(op->pending_update_server_trans); - if (op->event) belle_sip_object_unref(op->event); - sal_error_info_reset(&op->error_info); - __sal_op_free(op); - return ; -} - -void sal_op_authenticate(SalOp *op, const SalAuthInfo *info){ - if (op->type == SalOpRegister) { - /*Registration authenticate is just about registering again*/ - sal_register_refresh(op,-1); - }else { - /*for sure auth info will be accessible from the provider*/ - sal_process_authentication(op); - } - return ; -} - -void sal_op_cancel_authentication(SalOp *h){ - ms_fatal("sal_op_cancel_authentication not implemented yet"); - return ; -} - -SalAuthInfo * sal_op_get_auth_requested(SalOp *op){ - return op->auth_info; -} - -belle_sip_header_contact_t* sal_op_create_contact(SalOp *op){ - belle_sip_header_contact_t* contact_header; - belle_sip_uri_t* contact_uri; - - if (sal_op_get_contact_address(op)) { - contact_header = belle_sip_header_contact_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_contact_address(op))); - } else { - contact_header= belle_sip_header_contact_new(); - } - - if (!(contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_header)))) { - /*no uri, just creating a new one*/ - contact_uri=belle_sip_uri_new(); - belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact_header),contact_uri); - } - - belle_sip_uri_set_user_password(contact_uri,NULL); - belle_sip_uri_set_secure(contact_uri,sal_op_is_secure(op)); - if (op->privacy!=SalPrivacyNone){ - belle_sip_uri_set_user(contact_uri,NULL); - } - belle_sip_header_contact_set_automatic(contact_header,op->base.root->auto_contacts); - if (op->base.root->uuid){ - if (belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance")==0){ - char *instance_id=belle_sip_strdup_printf("\"\"",op->base.root->uuid); - belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance",instance_id); - belle_sip_free(instance_id); - } - } - return contact_header; -} - - - -static void add_initial_route_set(belle_sip_request_t *request, const MSList *list){ - const MSList *elem; - for (elem=list;elem!=NULL;elem=elem->next){ - SalAddress *addr=(SalAddress*)elem->data; - belle_sip_header_route_t *route; - belle_sip_uri_t *uri; - /*Optimization: if the initial route set only contains one URI which is the same as the request URI, ommit it*/ - if (elem==list && list->next==NULL){ - belle_sip_uri_t *requri=belle_sip_request_get_uri(request); - /*skip the first route it is the same as the request uri*/ - if (strcmp(sal_address_get_domain(addr),belle_sip_uri_get_host(requri))==0 ){ - ms_message("Skipping top route of initial route-set because same as request-uri."); - continue; - } - } - - route=belle_sip_header_route_create((belle_sip_header_address_t*)addr); - uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)route); - belle_sip_uri_set_lr_param(uri,1); - belle_sip_message_add_header((belle_sip_message_t*)request,(belle_sip_header_t*)route); - } -} - -belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { - belle_sip_header_from_t* from_header; - belle_sip_header_to_t* to_header; - belle_sip_provider_t* prov=op->base.root->prov; - belle_sip_request_t *req; - belle_sip_uri_t* req_uri; - belle_sip_uri_t* to_uri; - belle_sip_header_call_id_t *call_id_header; - - const SalAddress* to_address; - const MSList *elem=sal_op_get_route_addresses(op); - char token[10]; - - /* check that the op has a correct to address */ - to_address = sal_op_get_to_address(op); - if( to_address == NULL ){ - ms_error("No To: address, cannot build request"); - return NULL; - } - - to_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to_address)); - if( to_uri == NULL ){ - ms_error("To: address is invalid, cannot build request"); - return NULL; - } - - if (strcmp("REGISTER",method)==0 || op->privacy==SalPrivacyNone) { - from_header = belle_sip_header_from_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op)) - ,belle_sip_random_token(token,sizeof(token))); - } else { - from_header=belle_sip_header_from_create2("Anonymous ",belle_sip_random_token(token,sizeof(token))); - } - /*make sure to preserve components like headers or port*/ - - req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)to_uri); - belle_sip_uri_set_secure(req_uri,sal_op_is_secure(op)); - - to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(to_address),NULL); - call_id_header = belle_sip_provider_create_call_id(prov); - if (sal_op_get_call_id(op)) { - belle_sip_header_call_id_set_call_id(call_id_header, sal_op_get_call_id(op)); - } - - req=belle_sip_request_create( - req_uri, - method, - call_id_header, - belle_sip_header_cseq_create(20,method), - from_header, - to_header, - belle_sip_header_via_new(), - 70); - - if (op->privacy & SalPrivacyId) { - belle_sip_header_p_preferred_identity_t* p_preferred_identity=belle_sip_header_p_preferred_identity_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op))); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(p_preferred_identity)); - } - - if (elem && strcmp(method,"REGISTER")!=0 && !op->base.root->no_initial_route){ - add_initial_route_set(req,elem); - } - - if (strcmp("REGISTER",method)!=0 && op->privacy!=SalPrivacyNone ){ - belle_sip_header_privacy_t* privacy_header=belle_sip_header_privacy_new(); - if (op->privacy&SalPrivacyCritical) - belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyCritical)); - if (op->privacy&SalPrivacyHeader) - belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyHeader)); - if (op->privacy&SalPrivacyId) - belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyId)); - if (op->privacy&SalPrivacyNone) - belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyNone)); - if (op->privacy&SalPrivacySession) - belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacySession)); - if (op->privacy&SalPrivacyUser) - belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyUser)); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(privacy_header)); - } - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),op->base.root->supported); - return req; -} - -belle_sip_response_t *sal_op_create_response_from_request(SalOp *op, belle_sip_request_t *req, int code){ - return sal_create_response_from_request(op->base.root,req,code); -} - -/*ping: main purpose is to obtain its own contact address behind firewalls*/ -int sal_ping(SalOp *op, const char *from, const char *to){ - sal_op_set_from(op,from); - sal_op_set_to(op,to); - return sal_op_send_request(op,sal_op_build_request(op,"OPTIONS")); -} - -void sal_op_set_replaces(SalOp* op,belle_sip_header_replaces_t* replaces) { - if (op->replaces){ - belle_sip_object_unref(op->replaces); - } - op->replaces=replaces; - belle_sip_object_ref(op->replaces); -} - -void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message) { - belle_sip_header_user_agent_t* user_agent=belle_sip_message_get_header_by_type(message,belle_sip_header_user_agent_t); - char user_agent_string[256]; - if (user_agent && belle_sip_header_user_agent_get_products_as_string(user_agent,user_agent_string,sizeof(user_agent_string))>0) { - if (op->base.remote_ua!=NULL){ - ms_free(op->base.remote_ua); - } - op->base.remote_ua=ms_strdup(user_agent_string); - } -} - -int sal_op_send_request_with_expires(SalOp* op, belle_sip_request_t* request,int expires) { - belle_sip_header_expires_t* expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_EXPIRES); - - if (!expires_header && expires>=0) { - belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header=belle_sip_header_expires_new())); - } - if (expires_header) belle_sip_header_expires_set_expires(expires_header,expires); - return sal_op_send_request(op,request); -} - -void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) { - belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_CSEQ); - belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); - sal_op_send_request(op,request); -} - -static void add_headers(SalOp *op, belle_sip_header_t *h, belle_sip_message_t *msg){ - - if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(h,belle_sip_header_contact_t)){ - belle_sip_header_contact_t* newct; - /*special case for contact, we want to keep everything from the custom contact but set automatic mode and add our own parameters as well*/ - sal_op_set_contact_address(op,(SalAddress*)BELLE_SIP_HEADER_ADDRESS(h)); - newct = sal_op_create_contact(op); - belle_sip_message_set_header(BELLE_SIP_MESSAGE(msg),BELLE_SIP_HEADER(newct)); - return; - } - /*if a header already exists in the message, replace it*/ - belle_sip_message_set_header(msg,h); - -} - -void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg){ - if (op->base.sent_custom_headers){ - belle_sip_message_t *ch=(belle_sip_message_t*)op->base.sent_custom_headers; - belle_sip_list_t *l=belle_sip_message_get_all_headers(ch); - belle_sip_list_t *elem; - for(elem=l;elem!=NULL;elem=elem->next){ - add_headers(op,(belle_sip_header_t*)elem->data,msg); - } - belle_sip_list_free(l); - } -} - -static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* request, bool_t add_contact) { - belle_sip_client_transaction_t* client_transaction; - belle_sip_provider_t* prov=op->base.root->prov; - belle_sip_uri_t* outbound_proxy=NULL; - belle_sip_header_contact_t* contact; - int result =-1; - belle_sip_uri_t *next_hop_uri=NULL; - - if (add_contact && !belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_contact_t)) { - contact = sal_op_create_contact(op); - belle_sip_message_set_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact)); - } /*keep existing*/ - - _sal_op_add_custom_headers(op, (belle_sip_message_t*)request); - - if (!op->dialog || belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_NULL) { - /*don't put route header if dialog is in confirmed state*/ - const MSList *elem=sal_op_get_route_addresses(op); - const char *transport; - const char *method=belle_sip_request_get_method(request); - belle_sip_listening_point_t *udplp=belle_sip_provider_get_listening_point(prov,"UDP"); - - if (elem) { - outbound_proxy=belle_sip_header_address_get_uri((belle_sip_header_address_t*)elem->data); - next_hop_uri=outbound_proxy; - }else{ - next_hop_uri=(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_request_get_uri(request)); - } - transport=belle_sip_uri_get_transport_param(next_hop_uri); - if (transport==NULL){ - /*compatibility mode: by default it should be udp as not explicitely set and if no udp listening point is available, then use - * the first available transport*/ - if (!belle_sip_uri_is_secure(next_hop_uri)){ - if (udplp==NULL){ - if (belle_sip_provider_get_listening_point(prov,"TCP")!=NULL){ - transport="tcp"; - }else if (belle_sip_provider_get_listening_point(prov,"TLS")!=NULL ){ - transport="tls"; - } - } - if (transport){ - belle_sip_message("Transport is not specified, using %s because UDP is not available.",transport); - belle_sip_uri_set_transport_param(next_hop_uri,transport); - } - } - }else{ -#ifdef TUNNEL_ENABLED - if (udplp && BELLE_SIP_OBJECT_IS_INSTANCE_OF(udplp,belle_sip_tunnel_listening_point_t)){ - /* our tunnel mode only supports UDP. Force transport to be set to UDP */ - belle_sip_uri_set_transport_param(next_hop_uri,"udp"); - } -#endif - } - /*because in case of tunnel, transport can be changed*/ - transport=belle_sip_uri_get_transport_param(next_hop_uri); - - if ((strcmp(method,"REGISTER")==0 || strcmp(method,"SUBSCRIBE")==0) && transport && - (strcasecmp(transport,"TCP")==0 || strcasecmp(transport,"TLS")==0)){ - /*RFC 5923: add 'alias' parameter to tell the server that we want it to keep the connection for future requests*/ - belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_via_t); - belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(via),"alias",NULL); - } - } - - client_transaction = belle_sip_provider_create_client_transaction(prov,request); - belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),sal_op_ref(op)); - if (op->pending_client_trans) belle_sip_object_unref(op->pending_client_trans); - op->pending_client_trans=client_transaction; /*update pending inv for being able to cancel*/ - belle_sip_object_ref(op->pending_client_trans); - - if (belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_user_agent_t)==NULL) - belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(op->base.root->user_agent)); - - if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION) - && !belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION)) { - /*hmm just in case we already have authentication param in cache*/ - belle_sip_provider_add_authorization(op->base.root->prov,request,NULL,NULL,NULL,op->base.realm); - } - result = belle_sip_client_transaction_send_request_to(client_transaction,next_hop_uri/*might be null*/); - - /*update call id if not set yet for this OP*/ - if (result == 0 && !op->base.call_id) { - op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request), belle_sip_header_call_id_t)))); - } - - return result; - -} - -int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { - bool_t need_contact=FALSE; - if (request==NULL) { - return -1; /*sanity check*/ - } - /* - Header field where proxy ACK BYE CAN INV OPT REG - ___________________________________________________________ - Contact R o - - m o o - */ - if (strcmp(belle_sip_request_get_method(request),"INVITE")==0 - ||strcmp(belle_sip_request_get_method(request),"REGISTER")==0 - ||strcmp(belle_sip_request_get_method(request),"SUBSCRIBE")==0 - ||strcmp(belle_sip_request_get_method(request),"OPTIONS")==0 - ||strcmp(belle_sip_request_get_method(request),"REFER")==0) /* Despite contact seems not mandatory, call flow example show a Contact in REFER requests*/ - need_contact=TRUE; - - return _sal_op_send_request_with_contact(op, request,need_contact); -} - -int sal_reason_to_sip_code(SalReason r){ - int ret=500; - switch(r){ - case SalReasonNone: - ret=200; - break; - case SalReasonIOError: - ret=503; - break; - case SalReasonUnknown: - ret=400; - break; - case SalReasonBusy: - ret=486; - break; - case SalReasonDeclined: - ret=603; - break; - case SalReasonDoNotDisturb: - ret=600; - break; - case SalReasonForbidden: - ret=403; - break; - case SalReasonUnsupportedContent: - ret=415; - break; - case SalReasonNotFound: - ret=404; - break; - case SalReasonRedirect: - ret=302; - break; - case SalReasonTemporarilyUnavailable: - ret=480; - break; - case SalReasonServiceUnavailable: - ret=503; - break; - case SalReasonRequestPending: - ret=491; - break; - case SalReasonUnauthorized: - ret=401; - break; - case SalReasonNotAcceptable: - ret=488; /*or maybe 606 Not Acceptable ?*/ - break; - case SalReasonNoMatch: - ret=481; - break; - case SalReasonRequestTimeout: - ret=408; - break; - case SalReasonMovedPermanently: - ret=301; - break; - case SalReasonGone: - ret=410; - break; - case SalReasonAddressIncomplete: - ret=484; - break; - case SalReasonNotImplemented: - ret=501; - break; - case SalReasonServerTimeout: - ret=504; - break; - case SalReasonBadGateway: - ret=502; - break; - case SalReasonInternalError: - ret=500; - break; - } - return ret; -} +using namespace LINPHONE_NAMESPACE; SalReason _sal_reason_from_sip_code(int code) { if (code>=100 && code<300) return SalReasonNone; @@ -596,7 +122,7 @@ void sal_error_info_set(SalErrorInfo *ei, SalReason reason, const char *protocol else{ ei->reason=reason; if (code == 0) { - code = sal_reason_to_sip_code(reason); + code = to_sip_code(reason); } } ei->protocol_code=code; @@ -610,286 +136,4 @@ void sal_error_info_set(SalErrorInfo *ei, SalReason reason, const char *protocol } } -void sal_op_set_reason_error_info(SalOp *op, belle_sip_message_t *msg){ - belle_sip_header_reason_t* reason_header = belle_sip_message_get_header_by_type(msg,belle_sip_header_reason_t); - if (reason_header){ - SalErrorInfo *ei=&op->reason_error_info; // ?// - const char *protocol = belle_sip_header_reason_get_protocol(reason_header); - int code = belle_sip_header_reason_get_cause(reason_header); - const char *text = belle_sip_header_reason_get_text(reason_header); - sal_error_info_set(ei, SalReasonUnknown, protocol, code, text, NULL); - } -} - -void sal_op_set_error_info_from_response(SalOp *op, belle_sip_response_t *response){ - int code = belle_sip_response_get_status_code(response); - const char *reason_phrase=belle_sip_response_get_reason_phrase(response); - belle_sip_header_t *warning=belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Warning"); - SalErrorInfo *ei=&op->error_info; - const char *warnings; - - warnings=warning ? belle_sip_header_get_unparsed_value(warning) : NULL; - sal_error_info_set(ei,SalReasonUnknown,"SIP", code,reason_phrase,warnings); - sal_op_set_reason_error_info(op, BELLE_SIP_MESSAGE(response)); -} - -const SalErrorInfo *sal_op_get_error_info(const SalOp *op){ - return &op->error_info; -} - -const SalErrorInfo * sal_op_get_reason_error_info(const SalOp *op){ - return &op->reason_error_info; -} - - - - -static void unlink_op_with_dialog(SalOp *op, belle_sip_dialog_t* dialog){ - belle_sip_dialog_set_application_data(dialog,NULL); - sal_op_unref(op); - belle_sip_object_unref(dialog); -} - -static belle_sip_dialog_t *link_op_with_dialog(SalOp *op, belle_sip_dialog_t* dialog){ - belle_sip_dialog_set_application_data(dialog,sal_op_ref(op)); - belle_sip_object_ref(dialog); - return dialog; -} - -void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog) { - ms_message("op [%p] : set_or_update_dialog() current=[%p] new=[%p]",op,op->dialog,dialog); - sal_op_ref(op); - if (op->dialog!=dialog){ - if (op->dialog){ - /*FIXME: shouldn't we delete unconfirmed dialogs ?*/ - unlink_op_with_dialog(op,op->dialog); - op->dialog=NULL; - } - if (dialog) { - op->dialog=link_op_with_dialog(op,dialog); - belle_sip_dialog_enable_pending_trans_checking(dialog,op->base.root->pending_trans_checking); - } - } - sal_op_unref(op); -} -/*return reffed op*/ -SalOp* sal_op_ref(SalOp* op) { - op->ref++; - return op; -} -/*return null, destroy op if ref count =0*/ -void* sal_op_unref(SalOp* op) { - op->ref--; - if (op->ref==0) { - sal_op_release_impl(op); - }else if (op->ref<0){ - ms_fatal("SalOp [%p]: too many unrefs.",op); - } - return NULL; -} - -int sal_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int expires,belle_sip_refresher_listener_t listener ) { - if (sal_op_send_request_with_expires(op,req,expires)==0) { - if (op->refresher) { - belle_sip_refresher_stop(op->refresher); - belle_sip_object_unref(op->refresher); - } - if ((op->refresher = belle_sip_client_transaction_create_refresher(op->pending_client_trans))) { - /*since refresher acquires the transaction, we should remove our context from the transaction, because we won't be notified - * that it is terminated anymore.*/ - sal_op_unref(op);/*loose the reference that was given to the transaction when creating it*/ - /* Note that the refresher will replace our data with belle_sip_transaction_set_application_data(). - Something in the design is not very good here, it makes things complicated to the belle-sip user. - Possible ideas to improve things: refresher shall not use belle_sip_transaction_set_application_data() internally, refresher should let the first transaction - notify the user as a normal transaction*/ - belle_sip_refresher_set_listener(op->refresher,listener,op); - belle_sip_refresher_set_retry_after(op->refresher,op->base.root->refresher_retry_after); - belle_sip_refresher_set_realm(op->refresher,op->base.realm); - belle_sip_refresher_enable_manual_mode(op->refresher,op->manual_refresher); - return 0; - } else { - return -1; - } - } - return -1; -} - -const char* sal_op_state_to_string(const SalOpState value) { - switch(value) { - case SalOpStateEarly: return"SalOpStateEarly"; - case SalOpStateActive: return "SalOpStateActive"; - case SalOpStateTerminating: return "SalOpStateTerminating"; - case SalOpStateTerminated: return "SalOpStateTerminated"; - default: - return "Unknown"; - } -} - -/* - * Warning: this function takes owneship of the custom headers - */ -void sal_op_set_sent_custom_header(SalOp *op, SalCustomHeader* ch){ - SalOpBase *b=(SalOpBase *)op; - if (b->sent_custom_headers){ - sal_custom_header_free(b->sent_custom_headers); - b->sent_custom_headers=NULL; - } - if (ch) belle_sip_object_ref((belle_sip_message_t*)ch); - b->sent_custom_headers=ch; -} - -void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming){ - if (incoming) belle_sip_object_ref(incoming); - if (op->base.recv_custom_headers){ - belle_sip_object_unref(op->base.recv_custom_headers); - op->base.recv_custom_headers=NULL; - } - if (incoming){ - op->base.recv_custom_headers=(SalCustomHeader*)incoming; - } -} - -const char *sal_op_get_remote_contact(const SalOp *op){ - /* - * remote contact is filled in process_response - */ - return op->base.remote_contact; -} - -SalBodyHandler * sal_op_get_body_handler(SalOp *op, belle_sip_message_t *msg) { - belle_sip_body_handler_t *body_handler = belle_sip_message_get_body_handler(msg); - if (body_handler != NULL) { - belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(msg, belle_sip_header_content_type_t); - belle_sip_header_content_length_t *content_length = belle_sip_message_get_header_by_type(msg, belle_sip_header_content_length_t); - belle_sip_header_t *content_encoding = belle_sip_message_get_header(msg, "Content-Encoding"); - if (content_type != NULL) belle_sip_body_handler_add_header(body_handler, BELLE_SIP_HEADER(content_type)); - if (content_length != NULL) belle_sip_body_handler_add_header(body_handler, BELLE_SIP_HEADER(content_length)); - if (content_encoding != NULL) belle_sip_body_handler_add_header(body_handler, content_encoding); - } - return (SalBodyHandler *)body_handler; -} - -void sal_op_set_privacy(SalOp* op,SalPrivacyMask privacy) { - op->privacy=privacy; -} -SalPrivacyMask sal_op_get_privacy(const SalOp* op) { - return op->privacy; -} - -bool_t sal_op_is_secure(const SalOp* op) { - const SalAddress* from = sal_op_get_from_address(op); - const SalAddress* to = sal_op_get_to_address(op); - - return from && to && strcasecmp("sips",sal_address_get_scheme(from))==0 && strcasecmp("sips",sal_address_get_scheme(to))==0; -} - -void sal_op_set_manual_refresher_mode(SalOp *op, bool_t enabled){ - op->manual_refresher=enabled; -} - -int sal_op_get_address_family(SalOp *op){ - belle_sip_transaction_t *tr=NULL; - belle_sip_header_address_t *contact; - - - if (op->refresher) - tr=(belle_sip_transaction_t *)belle_sip_refresher_get_transaction(op->refresher); - - if (tr==NULL) - tr=(belle_sip_transaction_t *)op->pending_client_trans; - if (tr==NULL) - tr=(belle_sip_transaction_t *)op->pending_server_trans; - - if (tr==NULL){ - ms_error("Unable to determine IP version from signaling operation."); - return AF_UNSPEC; - } - - - if (op->refresher) { - belle_sip_response_t *resp = belle_sip_transaction_get_response(tr); - belle_sip_header_via_t *via = resp ?belle_sip_message_get_header_by_type(resp,belle_sip_header_via_t):NULL; - if (!via){ - ms_error("Unable to determine IP version from signaling operation, no via header found."); - return AF_UNSPEC; - } - return (strchr(belle_sip_header_via_get_host(via),':') != NULL) ? AF_INET6 : AF_INET; - } else { - belle_sip_request_t *req = belle_sip_transaction_get_request(tr); - contact=(belle_sip_header_address_t*)belle_sip_message_get_header_by_type(req,belle_sip_header_contact_t); - if (!contact){ - ms_error("Unable to determine IP version from signaling operation, no contact header found."); - } - return sal_address_is_ipv6((SalAddress*)contact) ? AF_INET6 : AF_INET; - } -} - -bool_t sal_op_is_idle(SalOp *op){ - if (op->dialog){ - return !belle_sip_dialog_request_pending(op->dialog); - } - return TRUE; -} - -void sal_op_stop_refreshing(SalOp *op){ - if (op->refresher){ - belle_sip_refresher_stop(op->refresher); - } -} - -void sal_call_set_sdp_handling(SalOp *h, SalOpSDPHandling handling) { - if (handling != SalOpSDPNormal) ms_message("Enabling special SDP handling for SalOp[%p]!", h); - h->sdp_handling = handling; -} -void sal_op_cnx_ip_to_0000_if_sendonly_enable(SalOp *op,bool_t yesno) { - op->cnx_ip_to_0000_if_sendonly_enabled = yesno; -} - -bool_t sal_op_cnx_ip_to_0000_if_sendonly_enabled(SalOp *op) { - return op->cnx_ip_to_0000_if_sendonly_enabled; -} - -bool_t sal_op_is_forked_of(const SalOp *op1, const SalOp *op2){ - return op1->base.call_id && op2->base.call_id && strcmp(op1->base.call_id, op2->base.call_id) == 0; -} -int sal_op_refresh(SalOp *op) { - if (op->refresher) { - belle_sip_refresher_refresh(op->refresher,belle_sip_refresher_get_expires(op->refresher)); - return 0; - } - ms_warning("sal_refresh on op [%p] of type [%s] no refresher",op,sal_op_type_to_string(op->type)); - return -1; -} - -void sal_op_set_event(SalOp *op, const char *eventname){ - belle_sip_header_event_t *header = NULL; - if (op->event) belle_sip_object_unref(op->event); - if (eventname){ - header = belle_sip_header_event_create(eventname); - belle_sip_object_ref(header); - } - op->event = header; -} - -const char* sal_op_get_public_address(SalOp *op, int *port) { - if (op && op->refresher) { - return belle_sip_refresher_get_public_address(op->refresher, port); - } - return NULL; -} - -const char* sal_op_get_local_address(SalOp *op, int *port) { - if (op && op->refresher) { - return belle_sip_refresher_get_local_address(op->refresher, port); - } - return NULL; -} - -char* sal_op_get_dialog_id(const SalOp *op) { - if (op->dialog != NULL) { - return ms_strdup_printf("%s;to-tag=%s;from-tag=%s", ((SalOpBase*)op)->call_id, - belle_sip_dialog_get_remote_tag(op->dialog), belle_sip_dialog_get_local_tag(op->dialog)); - } - return NULL; -} diff --git a/coreapi/bellesip_sal/sal_op_info.c b/coreapi/bellesip_sal/sal_op_info.c deleted file mode 100644 index 7ecf8e68b..000000000 --- a/coreapi/bellesip_sal/sal_op_info.c +++ /dev/null @@ -1,34 +0,0 @@ -/* -linphone -Copyright (C) 2012 Belledonne Communications, Grenoble, France - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#include "sal_impl.h" - - -int sal_send_info(SalOp *op, const char *from, const char *to, const SalBodyHandler *body_handler){ - if (op->dialog && belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_CONFIRMED){ - belle_sip_request_t *req; - belle_sip_dialog_enable_pending_trans_checking(op->dialog,op->base.root->pending_trans_checking); - req=belle_sip_dialog_create_queued_request(op->dialog,"INFO"); - belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(body_handler)); - return sal_op_send_request(op,req); - }else{ - ms_error("Cannot send INFO message on op [%p] because dialog is not in confirmed state yet.", op); - } - return -1; -} - diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c deleted file mode 100644 index cfb73763a..000000000 --- a/coreapi/bellesip_sal/sal_op_message.c +++ /dev/null @@ -1,216 +0,0 @@ -/* -linphone -Copyright (C) 2012 Belledonne Communications, Grenoble, France - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#include "sal_impl.h" - -#include "linphone/core.h" -#include "private.h" -#include - -static void process_error( SalOp* op) { - if (op->dir == SalOpDirOutgoing) { - op->base.root->callbacks.message_delivery_update(op, SalMessageDeliveryFailed); - } else { - ms_warning("unexpected io error for incoming message on op [%p]",op); - } - op->state=SalOpStateTerminated; - -} - -static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ - SalOp* op = (SalOp*)user_ctx; - sal_error_info_set(&op->error_info,SalReasonIOError, "SIP", 503,"IO Error",NULL); - process_error(op); -} -static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { - SalOp* op=(SalOp*)user_ctx; - sal_error_info_set(&op->error_info,SalReasonRequestTimeout, "SIP", 408,"Request timeout",NULL); - process_error(op); - -} -static void process_response_event(void *op_base, const belle_sip_response_event_t *event){ - SalOp* op = (SalOp*)op_base; - int code = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)); - SalMessageDeliveryStatus status; - sal_op_set_error_info_from_response(op,belle_sip_response_event_get_response(event)); - - if (code>=100 && code <200) - status=SalMessageDeliveryInProgress; - else if (code>=200 && code <300) - status=SalMessageDeliveryDone; - else - status=SalMessageDeliveryFailed; - - op->base.root->callbacks.message_delivery_update(op,status); -} - -static bool_t is_external_body(belle_sip_header_content_type_t* content_type) { - return strcmp("message",belle_sip_header_content_type_get_type(content_type))==0 - && strcmp("external-body",belle_sip_header_content_type_get_subtype(content_type))==0; -} - -static void add_message_accept(SalOp *op, belle_sip_message_t *msg) { - bctbx_list_t *item; - const char *str; - char *old; - char *header = ms_strdup("xml/cipher, application/cipher.vnd.gsma.rcs-ft-http+xml"); - - for (item = op->base.root->supported_content_types; item != NULL; item = bctbx_list_next(item)) { - str = (const char *)bctbx_list_get_data(item); - old = header; - header = ms_strdup_printf("%s, %s", old, str); - ms_free(old); - } - - belle_sip_message_add_header(msg, belle_sip_header_create("Accept", header)); - ms_free(header); -} - -void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *event){ - belle_sip_request_t* req = belle_sip_request_event_get_request(event); - belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,req); - belle_sip_header_address_t* address; - belle_sip_header_from_t* from_header; - belle_sip_header_content_type_t* content_type; - belle_sip_response_t* resp; - int errcode = 500; - belle_sip_header_call_id_t* call_id = belle_sip_message_get_header_by_type(req,belle_sip_header_call_id_t); - belle_sip_header_cseq_t* cseq = belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); - belle_sip_header_date_t *date=belle_sip_message_get_header_by_type(req,belle_sip_header_date_t); - char* from; - bool_t external_body=FALSE; - - from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); - content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t); - - if (content_type) { - SalMessage salmsg; - char message_id[256]={0}; - - if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); - op->pending_server_trans=server_transaction; - belle_sip_object_ref(op->pending_server_trans); - - external_body=is_external_body(content_type); - address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) - ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); - from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address)); - snprintf(message_id,sizeof(message_id)-1,"%s%i" - ,belle_sip_header_call_id_get_call_id(call_id) - ,belle_sip_header_cseq_get_seq_number(cseq)); - salmsg.from=from; - /* if we just deciphered a message, use the deciphered part(which can be a rcs xml body pointing to the file to retreive from server)*/ - salmsg.text=(!external_body)?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL; - salmsg.url=NULL; - salmsg.content_type = ms_strdup_printf("%s/%s", belle_sip_header_content_type_get_type(content_type), belle_sip_header_content_type_get_subtype(content_type)); - if (external_body && belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")) { - size_t url_length=strlen(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")); - salmsg.url = ms_strdup(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")+1); /* skip first "*/ - ((char*)salmsg.url)[url_length-2]='\0'; /*remove trailing "*/ - } - salmsg.message_id=message_id; - salmsg.time=date ? belle_sip_header_date_get_time(date) : time(NULL); - op->base.root->callbacks.message_received(op,&salmsg); - - belle_sip_object_unref(address); - belle_sip_free(from); - if (salmsg.url) ms_free((char*)salmsg.url); - ms_free((char *)salmsg.content_type); - } else { - ms_error("Unsupported MESSAGE (no Content-Type)"); - resp = belle_sip_response_create_from_request(req, errcode); - add_message_accept(op, (belle_sip_message_t*)resp); - belle_sip_server_transaction_send_response(server_transaction,resp); - sal_op_release(op); - } -} - -static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { - SalOp* op = (SalOp*)op_base; - sal_process_incoming_message(op,event); -} - -int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri){ - belle_sip_request_t* req; - char content_type_raw[256]; - size_t content_length = msg?strlen(msg):0; - time_t curtime = ms_time(NULL); - const char *body; - int retval; - - if (op->dialog){ - /*for SIP MESSAGE that are sent in call's dialog*/ - req=belle_sip_dialog_create_queued_request(op->dialog,"MESSAGE"); - }else{ - sal_op_message_fill_cbs(op); - if (from) - sal_op_set_from(op,from); - if (to) - sal_op_set_to(op,to); - op->dir=SalOpDirOutgoing; - - req=sal_op_build_request(op,"MESSAGE"); - if (req == NULL ){ - return -1; - } - if (sal_op_get_contact_address(op)){ - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); - } - } - - snprintf(content_type_raw,sizeof(content_type_raw),BELLE_SIP_CONTENT_TYPE ": %s",content_type); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_type_parse(content_type_raw))); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length))); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime))); - body = msg; - if (body){ - /*don't call set_body() with null argument because it resets content type and content length*/ - belle_sip_message_set_body(BELLE_SIP_MESSAGE(req), body, content_length); - } - retval = sal_op_send_request(op,req); - - return retval; -} - -int sal_message_reply(SalOp *op, SalReason reason){ - if (op->pending_server_trans){ - int code=sal_reason_to_sip_code(reason); - belle_sip_response_t *resp = belle_sip_response_create_from_request( - belle_sip_transaction_get_request((belle_sip_transaction_t*)op->pending_server_trans),code); - belle_sip_server_transaction_send_response(op->pending_server_trans,resp); - return 0; - }else ms_error("sal_message_reply(): no server transaction"); - return -1; -} - -int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) { - return sal_message_send(op,from,to,"text/plain",msg, NULL); -} - -static belle_sip_listener_callbacks_t op_message_callbacks={0}; - -void sal_op_message_fill_cbs(SalOp*op) { - if (op_message_callbacks.process_io_error==NULL){ - op_message_callbacks.process_io_error=process_io_error; - op_message_callbacks.process_response_event=process_response_event; - op_message_callbacks.process_timeout=process_timeout; - op_message_callbacks.process_request_event=process_request_event; - } - op->callbacks=&op_message_callbacks; - op->type=SalOpMessage; -} diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c deleted file mode 100644 index 5907c2cd6..000000000 --- a/coreapi/bellesip_sal/sal_op_publish.c +++ /dev/null @@ -1,112 +0,0 @@ -/* -linphone -Copyright (C) 2012 Belledonne Communications, Grenoble, France - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#include "sal_impl.h" - - -static void publish_refresher_listener (belle_sip_refresher_t* refresher - ,void* user_pointer - ,unsigned int status_code - ,const char* reason_phrase, int will_retry) { - SalOp* op = (SalOp*)user_pointer; - const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); - belle_sip_response_t *response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(last_publish_trans)); - ms_message("Publish refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase?reason_phrase:"none",sal_op_get_proxy(op)); - if (status_code==0){ - op->base.root->callbacks.on_expire(op); - }else if (status_code>=200){ - belle_sip_header_t *sip_etag; - const char *sip_etag_string = NULL; - if (response && (sip_etag = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response), "SIP-ETag"))) { - sip_etag_string = belle_sip_header_get_unparsed_value(sip_etag); - } - sal_op_set_entity_tag(op, sip_etag_string); - sal_error_info_set(&op->error_info,SalReasonUnknown, "SIP", (int)status_code,reason_phrase,NULL); - sal_op_assign_recv_headers(op,(belle_sip_message_t*)response); - op->base.root->callbacks.on_publish_response(op); - } -} - -static void publish_response_event(void *userctx, const belle_sip_response_event_t *event){ - SalOp *op=(SalOp*)userctx; - sal_op_set_error_info_from_response(op,belle_sip_response_event_get_response(event)); - if (op->error_info.protocol_code>=200){ - op->base.root->callbacks.on_publish_response(op); - } -} - -static belle_sip_listener_callbacks_t op_publish_callbacks={0}; - -void sal_op_publish_fill_cbs(SalOp *op) { - if (op_publish_callbacks.process_response_event==NULL){ - op_publish_callbacks.process_response_event=publish_response_event; - } - op->callbacks=&op_publish_callbacks; - op->type=SalOpPublish; -} - -int sal_publish(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBodyHandler *body_handler){ - belle_sip_request_t *req=NULL; - if(!op->refresher || !belle_sip_refresher_get_transaction(op->refresher)) { - if (from) - sal_op_set_from(op,from); - if (to) - sal_op_set_to(op,to); - - sal_op_publish_fill_cbs(op); - req=sal_op_build_request(op,"PUBLISH"); - if( req == NULL ){ - return -1; - } - - if (sal_op_get_entity_tag(op)) { - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("SIP-If-Match", sal_op_get_entity_tag(op))); - } - - if (sal_op_get_contact_address(op)){ - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); - } - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event",eventname)); - belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(body_handler)); - if (expires!=-1) - return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener); - else return sal_op_send_request(op,req); - } else { - /*update status*/ - const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); - belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); - /*update body*/ - if (expires == 0) { - belle_sip_message_set_body(BELLE_SIP_MESSAGE(last_publish), NULL, 0); - } else { - belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(last_publish), BELLE_SIP_BODY_HANDLER(body_handler)); - } - return belle_sip_refresher_refresh(op->refresher,expires==-1 ? BELLE_SIP_REFRESHER_REUSE_EXPIRES : expires); - } -} - -int sal_op_unpublish(SalOp *op){ - if (op->refresher){ - const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(op->refresher); - belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr); - belle_sip_message_set_body(BELLE_SIP_MESSAGE(last_req), NULL, 0); - belle_sip_refresher_refresh(op->refresher,0); - return 0; - } - return -1; -} diff --git a/coreapi/call_log.c b/coreapi/call_log.c index c1f24ea10..abed37602 100644 --- a/coreapi/call_log.c +++ b/coreapi/call_log.c @@ -114,7 +114,7 @@ void call_logs_write_to_config_file(LinphoneCore *lc){ } } -bctbx_list_t * call_logs_read_from_config_file(LinphoneCore *lc){ +bctbx_list_t * linphone_core_read_call_logs_from_config_file(LinphoneCore *lc){ char logsection[32]; int i; const char *tmp; diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index e52a3199e..8a70e1718 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -19,6 +19,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "sal/sal.h" +#include "sal/call_op.h" +#include "sal/message_op.h" #include "linphone/core.h" #include "private.h" @@ -40,6 +42,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "conference/session/media-session.h" #include "conference/session/media-session-p.h" +using namespace LINPHONE_NAMESPACE; + static void register_failure(SalOp *op); static bool_t already_a_call_with_remote_address(const LinphoneCore *lc, const LinphoneAddress *remote) { @@ -58,7 +62,7 @@ static bool_t already_a_call_with_remote_address(const LinphoneCore *lc, const L } -static LinphoneCall * look_for_broken_call_to_replace(SalOp *h, LinphoneCore *lc) { +static LinphoneCall * look_for_broken_call_to_replace(LINPHONE_NAMESPACE::SalOp *h, LinphoneCore *lc) { const bctbx_list_t *calls = linphone_core_get_calls(lc); const bctbx_list_t *it = calls; while (it != NULL) { @@ -78,9 +82,9 @@ static LinphoneCall * look_for_broken_call_to_replace(SalOp *h, LinphoneCore *lc return NULL; } -static void call_received(SalOp *h) { +static void call_received(SalCallOp *h) { /* Look if this INVITE is for a call that has already been notified but broken because of network failure */ - LinphoneCore *lc = reinterpret_cast(sal_get_user_pointer(sal_op_get_sal(h))); + LinphoneCore *lc = reinterpret_cast(h->get_sal()->get_user_pointer()); LinphoneCall *replacedCall = look_for_broken_call_to_replace(h, lc); if (replacedCall) { linphone_call_replace_op(replacedCall, h); @@ -88,13 +92,13 @@ static void call_received(SalOp *h) { } LinphoneAddress *fromAddr = nullptr; - const char *pAssertedId = sal_custom_header_find(sal_op_get_recv_custom_header(h), "P-Asserted-Identity"); + const char *pAssertedId = sal_custom_header_find(h->get_recv_custom_header(), "P-Asserted-Identity"); /* In some situation, better to trust the network rather than the UAC */ if (lp_config_get_int(linphone_core_get_config(lc), "sip", "call_logs_use_asserted_id_instead_of_from", 0)) { if (pAssertedId) { LinphoneAddress *pAssertedIdAddr = linphone_address_new(pAssertedId); if (pAssertedIdAddr) { - ms_message("Using P-Asserted-Identity [%s] instead of from [%s] for op [%p]", pAssertedId, sal_op_get_from(h), h); + ms_message("Using P-Asserted-Identity [%s] instead of from [%s] for op [%p]", pAssertedId, h->get_from(), h); fromAddr = pAssertedIdAddr; } else ms_warning("Unsupported P-Asserted-Identity header for op [%p] ", h); @@ -103,8 +107,8 @@ static void call_received(SalOp *h) { } if (!fromAddr) - fromAddr = linphone_address_new(sal_op_get_from(h)); - LinphoneAddress *toAddr = linphone_address_new(sal_op_get_to(h)); + fromAddr = linphone_address_new(h->get_from()); + LinphoneAddress *toAddr = linphone_address_new(h->get_to()); /* First check if we can answer successfully to this invite */ LinphonePresenceActivity *activity = nullptr; @@ -118,12 +122,12 @@ static void call_received(SalOp *h) { SalErrorInfo sei; memset(&sei, 0, sizeof(sei)); sal_error_info_set(&sei, SalReasonRedirect, "SIP", 0, nullptr, nullptr); - sal_call_decline_with_error_info(h, &sei, altContact); + h->decline_with_error_info(&sei, altContact); ms_free(altContact); LinphoneErrorInfo *ei = linphone_error_info_new(); linphone_error_info_set(ei, nullptr, LinphoneReasonMovedPermanently, 302, "Moved permanently", nullptr); linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, fromAddr, toAddr, ei); - sal_op_release(h); + h->release(); sal_error_info_reset(&sei); return; } @@ -135,17 +139,17 @@ static void call_received(SalOp *h) { } if (!linphone_core_can_we_add_call(lc)) { /* Busy */ - sal_call_decline(h, SalReasonBusy, nullptr); + h->decline(SalReasonBusy, nullptr); LinphoneErrorInfo *ei = linphone_error_info_new(); linphone_error_info_set(ei, nullptr, LinphoneReasonBusy, 486, "Busy - too many calls", nullptr); linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, fromAddr, toAddr, ei); - sal_op_release(h); + h->release(); return; } /* Check if I'm the caller */ LinphoneAddress *fromAddressToSearchIfMe = nullptr; - if (sal_op_get_privacy(h) == SalPrivacyNone) + if (h->get_privacy() == SalPrivacyNone) fromAddressToSearchIfMe = linphone_address_clone(fromAddr); else if (pAssertedId) fromAddressToSearchIfMe = linphone_address_new(pAssertedId); @@ -154,11 +158,11 @@ static void call_received(SalOp *h) { if (fromAddressToSearchIfMe && already_a_call_with_remote_address(lc, fromAddressToSearchIfMe)) { char *addr = linphone_address_as_string(fromAddr); ms_warning("Receiving a call while one with same address [%s] is initiated, refusing this one with busy message", addr); - sal_call_decline(h, SalReasonBusy, nullptr); + h->decline(SalReasonBusy, nullptr); LinphoneErrorInfo *ei = linphone_error_info_new(); linphone_error_info_set(ei, nullptr, LinphoneReasonBusy, 486, "Busy - duplicated call", nullptr); linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, fromAddr, toAddr, ei); - sal_op_release(h); + h->release(); linphone_address_unref(fromAddressToSearchIfMe); ms_free(addr); return; @@ -172,11 +176,11 @@ static void call_received(SalOp *h) { L_GET_PRIVATE_FROM_C_OBJECT(call)->startIncomingNotification(); } -static void call_rejected(SalOp *h){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); +static void call_rejected(SalCallOp *h){ + LinphoneCore *lc=(LinphoneCore *)h->get_sal()->get_user_pointer(); LinphoneErrorInfo *ei = linphone_error_info_new(); linphone_error_info_from_sal_op(ei, h); - linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, linphone_address_new(sal_op_get_from(h)), linphone_address_new(sal_op_get_to(h)), ei); + linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, linphone_address_new(h->get_from()), linphone_address_new(h->get_to()), ei); } #if 0 @@ -195,7 +199,7 @@ static void start_remote_ring(LinphoneCore *lc, LinphoneCall *call) { #endif static void call_ringing(SalOp *h) { - LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(h)); + LinphonePrivate::CallSession *session = reinterpret_cast(h->get_user_pointer()); if (!session) return; L_GET_PRIVATE(session)->remoteRinging(); } @@ -212,7 +216,7 @@ static void start_pending_refer(LinphoneCall *call){ * - when a request is accepted (pause, resume) */ static void call_accepted(SalOp *op) { - LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); + LinphonePrivate::CallSession *session = reinterpret_cast(op->get_user_pointer()); if (!session) { ms_warning("call_accepted: CallSession no longer exists"); return; @@ -222,7 +226,7 @@ static void call_accepted(SalOp *op) { /* this callback is called when an incoming re-INVITE/ SIP UPDATE modifies the session*/ static void call_updating(SalOp *op, bool_t is_update) { - LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); + LinphonePrivate::CallSession *session = reinterpret_cast(op->get_user_pointer()); if (!session) { ms_warning("call_updating: CallSession no longer exists"); return; @@ -232,7 +236,7 @@ static void call_updating(SalOp *op, bool_t is_update) { static void call_ack_received(SalOp *op, SalCustomHeader *ack) { - LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); + LinphonePrivate::CallSession *session = reinterpret_cast(op->get_user_pointer()); if (!session) { ms_warning("call_ack_received(): no CallSession for which an ack is expected"); return; @@ -242,7 +246,7 @@ static void call_ack_received(SalOp *op, SalCustomHeader *ack) { static void call_ack_being_sent(SalOp *op, SalCustomHeader *ack) { - LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); + LinphonePrivate::CallSession *session = reinterpret_cast(op->get_user_pointer()); if (!session) { ms_warning("call_ack_being_sent(): no CallSession for which an ack is supposed to be sent"); return; @@ -251,7 +255,7 @@ static void call_ack_being_sent(SalOp *op, SalCustomHeader *ack) { } static void call_terminated(SalOp *op, const char *from) { - LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); + LinphonePrivate::CallSession *session = reinterpret_cast(op->get_user_pointer()); if (!session) return; L_GET_PRIVATE(session)->terminated(); @@ -276,7 +280,7 @@ static int resume_call_after_failed_transfer(LinphoneCall *call){ #endif static void call_failure(SalOp *op) { - LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); + LinphonePrivate::CallSession *session = reinterpret_cast(op->get_user_pointer()); if (!session) { ms_warning("Failure reported on already terminated CallSession"); return; @@ -285,7 +289,7 @@ static void call_failure(SalOp *op) { } static void call_released(SalOp *op) { - LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); + LinphonePrivate::CallSession *session = reinterpret_cast(op->get_user_pointer()); if (!session) { /* We can get here when the core manages call at Sal level without creating a Call object. Typicially, * when declining an incoming call with busy because maximum number of calls is reached. */ @@ -305,7 +309,7 @@ static void call_cancel_done(SalOp *op) { } static void auth_failure(SalOp *op, SalAuthInfo* info) { - LinphoneCore *lc = (LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + LinphoneCore *lc = reinterpret_cast(op->get_sal()->get_user_pointer()); LinphoneAuthInfo *ai = NULL; if (info != NULL) { @@ -324,7 +328,7 @@ static void auth_failure(SalOp *op, SalAuthInfo* info) { } static void register_success(SalOp *op, bool_t registered){ - LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op); + LinphoneProxyConfig *cfg=(LinphoneProxyConfig *)op->get_user_pointer(); if (!cfg){ ms_message("Registration success for deleted proxy config, ignored"); return; @@ -334,8 +338,8 @@ static void register_success(SalOp *op, bool_t registered){ } static void register_failure(SalOp *op){ - LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op); - const SalErrorInfo *ei=sal_op_get_error_info(op); + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)op->get_user_pointer(); + const SalErrorInfo *ei=op->get_error_info(); const char *details=ei->full_string; if (cfg==NULL){ @@ -360,7 +364,7 @@ static void register_failure(SalOp *op){ } static void vfu_request(SalOp *op) { - LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); + LinphonePrivate::CallSession *session = reinterpret_cast(op->get_user_pointer()); if (!session) return; LinphonePrivate::MediaSession *mediaSession = dynamic_cast(session); @@ -406,14 +410,15 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){ } static void message_received(SalOp *op, const SalMessage *msg){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); + LinphoneCore *lc=(LinphoneCore *)op->get_sal()->get_user_pointer(); + LinphoneCall *call=(LinphoneCall*)op->get_user_pointer(); LinphoneReason reason = lc->chat_deny_code; if (reason == LinphoneReasonNone) { linphone_core_message_received(lc, op, msg); } - sal_message_reply(op, linphone_reason_to_sal(reason)); - if (!call) sal_op_release(op); + auto messageOp = dynamic_cast(op); + messageOp->reply(linphone_reason_to_sal(reason)); + if (!call) op->release(); } static void parse_presence_requested(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result) { @@ -432,22 +437,22 @@ static void convert_presence_to_xml_requested(SalOp *op, SalPresenceModel *prese } static void notify_presence(SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model, const char *msg){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + LinphoneCore *lc=(LinphoneCore *)op->get_sal()->get_user_pointer(); linphone_notify_recv(lc,op,ss,model); } -static void subscribe_presence_received(SalOp *op, const char *from){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); +static void subscribe_presence_received(SalPresenceOp *op, const char *from){ + LinphoneCore *lc=(LinphoneCore *)op->get_sal()->get_user_pointer(); linphone_subscription_new(lc,op,from); } -static void subscribe_presence_closed(SalOp *op, const char *from){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); +static void subscribe_presence_closed(SalPresenceOp *op, const char *from){ + LinphoneCore *lc=(LinphoneCore *)op->get_sal()->get_user_pointer(); linphone_subscription_closed(lc,op); } static void ping_reply(SalOp *op) { - LinphonePrivate::CallSession *session = reinterpret_cast(sal_op_get_user_pointer(op)); + LinphonePrivate::CallSession *session = reinterpret_cast(op->get_user_pointer()); if (!session) { ms_warning("Ping reply without CallSession attached..."); return; @@ -519,7 +524,7 @@ static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) { } } static bool_t auth_requested(Sal* sal, SalAuthInfo* sai) { - LinphoneCore *lc = (LinphoneCore *)sal_get_user_pointer(sal); + LinphoneCore *lc = (LinphoneCore *)sal->get_user_pointer(); if (fill_auth_info(lc,sai)) { return TRUE; } else { @@ -537,7 +542,7 @@ static bool_t auth_requested(Sal* sal, SalAuthInfo* sai) { } static void notify_refer(SalOp *op, SalReferStatus status){ - LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op); + LinphoneCall *call=(LinphoneCall*) op->get_user_pointer(); LinphoneCallState cstate; if (call==NULL) { ms_warning("Receiving notify_refer for unknown call."); @@ -576,7 +581,7 @@ static LinphoneChatMessageState chatStatusSal2Linphone(SalMessageDeliveryStatus } static void message_delivery_update(SalOp *op, SalMessageDeliveryStatus status){ - LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )sal_op_get_user_pointer(op); + LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )op->get_user_pointer(); if (chat_msg == NULL) { // Do not handle delivery status for isComposing messages. @@ -592,12 +597,12 @@ static void message_delivery_update(SalOp *op, SalMessageDeliveryStatus status){ } static void info_received(SalOp *op, SalBodyHandler *body_handler){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + LinphoneCore *lc=(LinphoneCore *)op->get_sal()->get_user_pointer(); linphone_core_notify_info_message(lc,op,body_handler); } static void subscribe_response(SalOp *op, SalSubscribeStatus status, int will_retry){ - LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); + LinphoneEvent *lev=(LinphoneEvent*)op->get_user_pointer(); if (lev==NULL) return; @@ -613,9 +618,9 @@ static void subscribe_response(SalOp *op, SalSubscribeStatus status, int will_re } } -static void notify(SalOp *op, SalSubscribeStatus st, const char *eventname, SalBodyHandler *body_handler){ - LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); +static void notify(SalSubscribeOp *op, SalSubscribeStatus st, const char *eventname, SalBodyHandler *body_handler){ + LinphoneEvent *lev=(LinphoneEvent*)op->get_user_pointer(); + LinphoneCore *lc=(LinphoneCore *)op->get_sal()->get_user_pointer(); bool_t out_of_dialog = (lev==NULL); if (out_of_dialog) { /*out of dialog notify */ @@ -636,9 +641,9 @@ static void notify(SalOp *op, SalSubscribeStatus st, const char *eventname, SalB } } -static void subscribe_received(SalOp *op, const char *eventname, const SalBodyHandler *body_handler){ - LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); +static void subscribe_received(SalSubscribeOp *op, const char *eventname, const SalBodyHandler *body_handler){ + LinphoneEvent *lev=(LinphoneEvent*)op->get_user_pointer(); + LinphoneCore *lc=(LinphoneCore *)op->get_sal()->get_user_pointer(); if (lev==NULL) { lev=linphone_event_new_with_op(lc,op,LinphoneSubscriptionIncoming,eventname); @@ -650,14 +655,14 @@ static void subscribe_received(SalOp *op, const char *eventname, const SalBodyHa } static void incoming_subscribe_closed(SalOp *op){ - LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); + LinphoneEvent *lev=(LinphoneEvent*)op->get_user_pointer(); linphone_event_set_state(lev,LinphoneSubscriptionTerminated); } static void on_publish_response(SalOp* op){ - LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); - const SalErrorInfo *ei=sal_op_get_error_info(op); + LinphoneEvent *lev=(LinphoneEvent*)op->get_user_pointer(); + const SalErrorInfo *ei=op->get_error_info(); if (lev==NULL) return; if (ei->reason==SalReasonNone){ @@ -676,7 +681,7 @@ static void on_publish_response(SalOp* op){ static void on_expire(SalOp *op){ - LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); + LinphoneEvent *lev=(LinphoneEvent*)op->get_user_pointer(); if (lev==NULL) return; @@ -688,14 +693,14 @@ static void on_expire(SalOp *op){ } static void on_notify_response(SalOp *op){ - LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); + LinphoneEvent *lev=(LinphoneEvent*)op->get_user_pointer(); if (lev==NULL) return; /*this is actually handling out of dialogs notify - for the moment*/ if (!lev->is_out_of_dialog_op) return; switch (linphone_event_get_subscription_state(lev)){ case LinphoneSubscriptionIncomingReceived: - if (sal_op_get_error_info(op)->reason == SalReasonNone){ + if (op->get_error_info()->reason == SalReasonNone){ linphone_event_set_state(lev, LinphoneSubscriptionTerminated); }else{ linphone_event_set_state(lev, LinphoneSubscriptionError); @@ -706,7 +711,7 @@ static void on_notify_response(SalOp *op){ } } -SalCallbacks linphone_sal_callbacks={ +Sal::Callbacks linphone_sal_callbacks={ call_received, call_rejected, call_ringing, diff --git a/coreapi/carddav.c b/coreapi/carddav.c index 75dc7afd5..f874b325e 100644 --- a/coreapi/carddav.c +++ b/coreapi/carddav.c @@ -20,6 +20,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/core.h" #include "private.h" +using namespace LINPHONE_NAMESPACE; + LinphoneCardDavContext* linphone_carddav_context_new(LinphoneFriendList *lfl) { LinphoneCardDavContext *carddav_context = NULL; @@ -573,7 +575,7 @@ static char* generate_url_from_server_address_and_uid(const char *server_url) { char *result = NULL; if (server_url) { char *uuid = reinterpret_cast(ms_malloc(64)); - if (sal_generate_uuid(uuid, 64) == 0) { + if (Sal::generate_uuid(uuid, 64) == 0) { char *url = reinterpret_cast(ms_malloc(300)); snprintf(url, 300, "%s/linphone-%s.vcf", server_url, uuid); ms_debug("Generated url is %s", url); diff --git a/coreapi/chat.c b/coreapi/chat.c index a458facac..3797ce69a 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -43,6 +43,7 @@ #include "content/content-type.h" using namespace std; +using namespace LINPHONE_NAMESPACE; void linphone_core_disable_chat(LinphoneCore *lc, LinphoneReason deny_reason) { lc->chat_deny_code = deny_reason; diff --git a/coreapi/conference.cc b/coreapi/conference.cc index 0acc08e8d..eb88aa5a1 100644 --- a/coreapi/conference.cc +++ b/coreapi/conference.cc @@ -795,7 +795,7 @@ int RemoteConference::removeParticipant(const LinphoneAddress *uri) { linphone_address_set_method_param(refer_to_addr, "BYE"); refer_to = linphone_address_as_string(refer_to_addr); linphone_address_unref(refer_to_addr); - res = sal_call_refer(linphone_call_get_op(m_focusCall), refer_to); + res = linphone_call_get_op(m_focusCall)->refer(refer_to); ms_free(refer_to); if(res == 0) { diff --git a/coreapi/error_info.c b/coreapi/error_info.c index b70f96837..cbbaab7b0 100644 --- a/coreapi/error_info.c +++ b/coreapi/error_info.c @@ -197,16 +197,16 @@ void linphone_error_info_from_sal_reason_ei(LinphoneErrorInfo *ei, const SalErro } } -void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const SalOp *op){ +void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const LINPHONE_NAMESPACE::SalOp *op){ if (op==NULL) { /*leave previous values in LinphoneErrorInfo, the op may have been released already.*/ return; }else{ const SalErrorInfo *sei; linphone_error_info_reset(ei); - sei = sal_op_get_error_info(op); + sei = op->get_error_info(); linphone_error_info_from_sal(ei, sei); - sei = sal_op_get_reason_error_info(op); + sei = op->get_reason_error_info(); linphone_error_info_from_sal_reason_ei(ei, sei); } } diff --git a/coreapi/event.c b/coreapi/event.c index 100fa2e5c..1f7ebe2c5 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -19,9 +19,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/event.h" #include "linphone/lpconfig.h" +#include "sal/event_op.h" #include "c-wrapper/c-wrapper.h" +using namespace LINPHONE_NAMESPACE; + const char * linphone_subscription_dir_to_string(LinphoneSubscriptionDir dir){ switch(dir){ case LinphoneSubscriptionIncoming: @@ -73,12 +76,12 @@ LINPHONE_PUBLIC const char *linphone_publish_state_to_string(LinphonePublishStat static void linphone_event_release(LinphoneEvent *lev){ if (lev->op) { /*this will stop the refresher*/ - sal_op_stop_refreshing(lev->op); + lev->op->stop_refreshing(); } linphone_event_unref(lev); } -static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, SalOp *op){ +static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, LINPHONE_NAMESPACE::SalEventOp *op){ LinphoneEvent *lev=belle_sip_object_new(LinphoneEvent); lev->lc=lc; lev->dir=dir; @@ -86,27 +89,27 @@ static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscri lev->name=ms_strdup(name); if (strcmp(lev->name, "conference") == 0) lev->internal = TRUE; - sal_op_set_user_pointer(lev->op,lev); + lev->op->set_user_pointer(lev); return lev; } LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, int expires){ - LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, sal_op_new(lc->sal)); + LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, new SalSubscribeOp(lc->sal)); lev->expires=expires; return lev; } -static LinphoneEvent *linphone_event_new_with_op_base(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name, bool_t is_out_of_dialog){ +static LinphoneEvent *linphone_event_new_with_op_base(LinphoneCore *lc, SalEventOp *op, LinphoneSubscriptionDir dir, const char *name, bool_t is_out_of_dialog){ LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, op); lev->is_out_of_dialog_op=is_out_of_dialog; return lev; } -LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name) { +LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalEventOp *op, LinphoneSubscriptionDir dir, const char *name) { return linphone_event_new_with_op_base(lc,op,dir,name,FALSE); } -LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name) { +LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, SalEventOp *op, LinphoneSubscriptionDir dir, const char *name) { return linphone_event_new_with_op_base(lc,op,dir,name,TRUE); } @@ -174,7 +177,7 @@ LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev){ LinphoneEvent *linphone_core_create_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){ LinphoneEvent *lev=linphone_event_new(lc, LinphoneSubscriptionOutgoing, event, expires); linphone_configure_op(lc,lev->op,resource,NULL,TRUE); - sal_op_set_manual_refresher_mode(lev->op,!lp_config_get_int(lc->config,"sip","refresh_generic_subscribe",1)); + lev->op->set_manual_refresher_mode(!lp_config_get_int(lc->config,"sip","refresh_generic_subscribe",1)); return lev; } @@ -182,7 +185,7 @@ LinphoneEvent *linphone_core_create_notify(LinphoneCore *lc, const LinphoneAddre LinphoneEvent *lev=linphone_event_new(lc, LinphoneSubscriptionIncoming, event, -1); linphone_configure_op(lc,lev->op,resource,NULL,TRUE); lev->subscription_state = LinphoneSubscriptionIncomingReceived; - sal_op_set_event(lev->op, event); + lev->op->set_event(event); lev->is_out_of_dialog_op = TRUE; return lev; } @@ -218,13 +221,14 @@ LinphoneStatus linphone_event_send_subscribe(LinphoneEvent *lev, const LinphoneC } if (lev->send_custom_headers){ - sal_op_set_sent_custom_header(lev->op,lev->send_custom_headers); + lev->op->set_sent_custom_header(lev->send_custom_headers); sal_custom_header_free(lev->send_custom_headers); lev->send_custom_headers=NULL; - }else sal_op_set_sent_custom_header(lev->op,NULL); + }else lev->op->set_sent_custom_header(NULL); body_handler = sal_body_handler_from_content(body); - err=sal_subscribe(lev->op,NULL,NULL,lev->name,lev->expires,body_handler); + auto subscribeOp = dynamic_cast(lev->op); + err=subscribeOp->subscribe(NULL,NULL,lev->name,lev->expires,body_handler); if (err==0){ if (lev->subscription_state==LinphoneSubscriptionNone) linphone_event_set_state(lev,LinphoneSubscriptionOutgoingProgress); @@ -237,7 +241,7 @@ LinphoneStatus linphone_event_update_subscribe(LinphoneEvent *lev, const Linphon } LinphoneStatus linphone_event_refresh_subscribe(LinphoneEvent *lev) { - return sal_op_refresh(lev->op); + return lev->op->refresh(); } LinphoneStatus linphone_event_accept_subscription(LinphoneEvent *lev){ @@ -246,7 +250,8 @@ LinphoneStatus linphone_event_accept_subscription(LinphoneEvent *lev){ ms_error("linphone_event_accept_subscription(): cannot accept subscription if subscription wasn't just received."); return -1; } - err=sal_subscribe_accept(lev->op); + auto subscribeOp = dynamic_cast(lev->op); + err=subscribeOp->accept(); if (err==0){ linphone_event_set_state(lev,LinphoneSubscriptionActive); } @@ -259,7 +264,8 @@ LinphoneStatus linphone_event_deny_subscription(LinphoneEvent *lev, LinphoneReas ms_error("linphone_event_deny_subscription(): cannot deny subscription if subscription wasn't just received."); return -1; } - err=sal_subscribe_decline(lev->op,linphone_reason_to_sal(reason)); + auto subscribeOp = dynamic_cast(lev->op); + err=subscribeOp->decline(linphone_reason_to_sal(reason)); linphone_event_set_state(lev,LinphoneSubscriptionTerminated); return err; } @@ -275,7 +281,8 @@ LinphoneStatus linphone_event_notify(LinphoneEvent *lev, const LinphoneContent * return -1; } body_handler = sal_body_handler_from_content(body); - return sal_notify(lev->op, body_handler); + auto subscribeOp = dynamic_cast(lev->op); + return subscribeOp->notify(body_handler); } static LinphoneEvent *_linphone_core_create_publish(LinphoneCore *core, LinphoneProxyConfig *cfg, const LinphoneAddress *resource, const char *event, int expires){ @@ -295,7 +302,7 @@ static LinphoneEvent *_linphone_core_create_publish(LinphoneCore *core, Linphone lev = linphone_event_new(lc,LinphoneSubscriptionInvalidDir, event,expires); linphone_configure_op_with_proxy(lc,lev->op,resource,NULL, !!lp_config_get_int(lc->config,"sip","publish_msg_with_contact",0),cfg); - sal_op_set_manual_refresher_mode(lev->op,!lp_config_get_int(lc->config,"sip","refresh_generic_publish",1)); + lev->op->set_manual_refresher_mode(!lp_config_get_int(lc->config,"sip","refresh_generic_publish",1)); return lev; } LinphoneEvent *linphone_core_create_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){ @@ -322,12 +329,13 @@ static int _linphone_event_send_publish(LinphoneEvent *lev, const LinphoneConten return -1; } if (lev->send_custom_headers){ - sal_op_set_sent_custom_header(lev->op,lev->send_custom_headers); + lev->op->set_sent_custom_header(lev->send_custom_headers); sal_custom_header_free(lev->send_custom_headers); lev->send_custom_headers=NULL; - }else sal_op_set_sent_custom_header(lev->op,NULL); + }else lev->op->set_sent_custom_header(NULL); body_handler = sal_body_handler_from_content(body); - err=sal_publish(lev->op,NULL,NULL,lev->name,lev->expires,body_handler); + auto publishOp = dynamic_cast(lev->op); + err=publishOp->publish(NULL,NULL,lev->name,lev->expires,body_handler); if (err==0){ linphone_event_set_publish_state(lev,LinphonePublishProgress); }else if (notify_err){ @@ -357,14 +365,17 @@ LinphoneStatus linphone_event_update_publish(LinphoneEvent* lev, const LinphoneC } LinphoneStatus linphone_event_refresh_publish(LinphoneEvent *lev) { - return sal_op_refresh(lev->op); + return lev->op->refresh(); } void linphone_event_pause_publish(LinphoneEvent *lev) { - if (lev->op) sal_op_stop_refreshing(lev->op); + if (lev->op) lev->op->stop_refreshing(); } void linphone_event_unpublish(LinphoneEvent *lev) { lev->terminating = TRUE; /* needed to get clear event*/ - if (lev->op) sal_op_unpublish(lev->op); + if (lev->op) { + auto op = dynamic_cast(lev->op); + op->unpublish(); + } } void linphone_event_set_user_data(LinphoneEvent *ev, void *up){ ev->userdata=up; @@ -379,7 +390,7 @@ void linphone_event_add_custom_header(LinphoneEvent *ev, const char *name, const } const char* linphone_event_get_custom_header(LinphoneEvent* ev, const char* name){ - const SalCustomHeader *ch=sal_op_get_recv_custom_header(ev->op); + const SalCustomHeader *ch=ev->op->get_recv_custom_header(); return sal_custom_header_find(ch,name); } @@ -395,16 +406,18 @@ void linphone_event_terminate(LinphoneEvent *lev){ } lev->terminating=TRUE; - if (lev->dir==LinphoneSubscriptionIncoming){ - sal_notify_close(lev->op); + auto op = dynamic_cast(lev->op); + op->close_notify(); }else if (lev->dir==LinphoneSubscriptionOutgoing){ - sal_unsubscribe(lev->op); + auto op = dynamic_cast(lev->op); + op->unsubscribe(); } if (lev->publish_state!=LinphonePublishNone){ if (lev->publish_state==LinphonePublishOk && lev->expires!=-1){ - sal_op_unpublish(lev->op); + auto op = dynamic_cast(lev->op); + op->unpublish(); } linphone_event_set_publish_state(lev,LinphonePublishCleared); return; @@ -424,7 +437,7 @@ LinphoneEvent *linphone_event_ref(LinphoneEvent *lev){ static void linphone_event_destroy(LinphoneEvent *lev){ if (lev->ei) linphone_error_info_unref(lev->ei); - if (lev->op) sal_op_release(lev->op); + if (lev->op) lev->op->release(); if (lev->send_custom_headers) sal_custom_header_free(lev->send_custom_headers); if (lev->to_address) linphone_address_unref(lev->to_address); if (lev->from_address) linphone_address_unref(lev->from_address); @@ -451,7 +464,7 @@ const char *linphone_event_get_name(const LinphoneEvent *lev){ static const LinphoneAddress *_linphone_event_cache_to (const LinphoneEvent *lev) { if (lev->to_address) linphone_address_unref(lev->to_address); - char *buf = sal_address_as_string(sal_op_get_to_address(lev->op)); + char *buf = sal_address_as_string(lev->op->get_to_address()); ((LinphoneEvent *)lev)->to_address = linphone_address_new(buf); ms_free(buf); return lev->to_address; @@ -460,7 +473,7 @@ static const LinphoneAddress *_linphone_event_cache_to (const LinphoneEvent *lev static const LinphoneAddress *_linphone_event_cache_from (const LinphoneEvent *lev) { if (lev->from_address) linphone_address_unref(lev->from_address); - char *buf = sal_address_as_string(sal_op_get_from_address(lev->op)); + char *buf = sal_address_as_string(lev->op->get_from_address()); ((LinphoneEvent *)lev)->from_address = linphone_address_new(buf); ms_free(buf); return lev->from_address; diff --git a/coreapi/friend.c b/coreapi/friend.c index 45f640072..20e7a1f8e 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -42,6 +42,9 @@ #include "c-wrapper/c-wrapper.h" +using namespace std; +using namespace LINPHONE_NAMESPACE; + const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){ const char *str=NULL; switch(ss){ @@ -185,12 +188,12 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr); */ }else{ - sal_op_release(fr->outsub); + fr->outsub->release(); fr->outsub=NULL; } - fr->outsub=sal_op_new(lc->sal); + fr->outsub=new SalPresenceOp(lc->sal); linphone_configure_op(lc,fr->outsub,addr,NULL,TRUE); - sal_subscribe_presence(fr->outsub,NULL,NULL,lp_config_get_int(lc->config,"sip","subscribe_expires",600)); + fr->outsub->subscribe(NULL,NULL,lp_config_get_int(lc->config,"sip","subscribe_expires",600)); fr->subscribe_active=TRUE; } } @@ -468,8 +471,8 @@ void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence) } } for(elem=lf->insubs; elem!=NULL; elem=bctbx_list_next(elem)){ - SalOp *op = (SalOp*)bctbx_list_get_data(elem); - sal_notify_presence(op,(SalPresenceModel *)presence); + auto op = reinterpret_cast(bctbx_list_get_data(elem)); + op->notify_presence((SalPresenceModel *)presence); } } @@ -480,14 +483,14 @@ void linphone_friend_add_incoming_subscription(LinphoneFriend *lf, SalOp *op){ void linphone_friend_remove_incoming_subscription(LinphoneFriend *lf, SalOp *op){ if (bctbx_list_find(lf->insubs, op)){ - sal_op_release(op); + op->release(); lf->insubs = bctbx_list_remove(lf->insubs, op); } } static void linphone_friend_unsubscribe(LinphoneFriend *lf){ if (lf->outsub!=NULL) { - sal_unsubscribe(lf->outsub); + lf->outsub->unsubscribe(); } /* for friend list there is no necessary outsub*/ lf->subscribe_active=FALSE; @@ -498,7 +501,7 @@ void linphone_friend_invalidate_subscription(LinphoneFriend *lf){ LinphoneCore *lc=lf->lc; if (lf->outsub!=NULL) { - sal_op_release(lf->outsub); + lf->outsub->release(); lf->outsub=NULL; } @@ -521,9 +524,17 @@ void linphone_friend_invalidate_subscription(LinphoneFriend *lf){ lf->initial_subscribes_sent=FALSE; } +static void close_presence_notification(SalPresenceOp *op) { + op->notify_presence_close(); +} + +static void release_sal_op(SalOp *op) { + op->release(); +} + static void linphone_friend_close_incoming_subscriptions(LinphoneFriend *lf) { - bctbx_list_for_each(lf->insubs, (MSIterateFunc) sal_notify_presence_close); - lf->insubs = bctbx_list_free_with_data(lf->insubs, (MSIterateFunc)sal_op_release); + bctbx_list_for_each(lf->insubs, (MSIterateFunc) close_presence_notification); + lf->insubs = bctbx_list_free_with_data(lf->insubs, (MSIterateFunc)release_sal_op); } void linphone_friend_close_subscriptions(LinphoneFriend *lf){ @@ -532,9 +543,9 @@ void linphone_friend_close_subscriptions(LinphoneFriend *lf){ } static void _linphone_friend_release_ops(LinphoneFriend *lf){ - lf->insubs = bctbx_list_free_with_data(lf->insubs, (MSIterateFunc) sal_op_release); + lf->insubs = bctbx_list_free_with_data(lf->insubs, (MSIterateFunc) release_sal_op); if (lf->outsub){ - sal_op_release(lf->outsub); + lf->outsub->release(); lf->outsub=NULL; } } @@ -756,7 +767,7 @@ void linphone_friend_update_subscribes(LinphoneFriend *fr, bool_t only_when_regi linphone_friend_unsubscribe(fr); }else if (!can_subscribe && fr->outsub){ fr->subscribe_active=FALSE; - sal_op_stop_refreshing(fr->outsub); + fr->outsub->stop_refreshing(); } } diff --git a/coreapi/friendlist.c b/coreapi/friendlist.c index a03536994..113ca9ff4 100644 --- a/coreapi/friendlist.c +++ b/coreapi/friendlist.c @@ -23,6 +23,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" +using namespace LINPHONE_NAMESPACE; + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneFriendListCbs); BELLE_SIP_INSTANCIATE_VPTR(LinphoneFriendListCbs, belle_sip_object_t, @@ -807,7 +809,7 @@ LinphoneFriend * linphone_friend_list_find_friend_by_out_subscribe(const Linphon const bctbx_list_t *elem; for (elem = list->friends; elem != NULL; elem = bctbx_list_next(elem)) { LinphoneFriend *lf = (LinphoneFriend *)bctbx_list_get_data(elem); - if (lf->outsub && ((lf->outsub == op) || sal_op_is_forked_of(lf->outsub, op))) return lf; + if (lf->outsub && ((lf->outsub == op) || lf->outsub->is_forked_of(op))) return lf; } return NULL; } diff --git a/coreapi/info.c b/coreapi/info.c index ad37a9a30..d4bd92623 100644 --- a/coreapi/info.c +++ b/coreapi/info.c @@ -28,6 +28,8 @@ #include "c-wrapper/c-wrapper.h" +using namespace LINPHONE_NAMESPACE; + struct _LinphoneInfoMessage{ belle_sip_object_t base; LinphoneContent *content; @@ -97,10 +99,10 @@ SalCustomHeader *linphone_info_message_get_headers (const LinphoneInfoMessage *i } void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, SalBodyHandler *body_handler){ - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); + LinphoneCall *call=(LinphoneCall*)op->get_user_pointer(); if (call){ LinphoneInfoMessage *info=linphone_core_create_info_message(lc); - info->headers=sal_custom_header_clone(sal_op_get_recv_custom_header(op)); + info->headers=sal_custom_header_clone(op->get_recv_custom_header()); if (body_handler) info->content=linphone_content_from_sal_body_handler(body_handler); linphone_call_notify_info_message_received(call, info); linphone_info_message_unref(info); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 6afea2b22..9962d373a 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -125,4 +125,4 @@ void set_playback_gain_db(AudioStream *st, float gain){ if (st->volrecv){ ms_filter_call_method(st->volrecv,MS_VOLUME_SET_DB_GAIN,&gain); }else ms_warning("Could not apply playback gain: gain control wasn't activated."); -} \ No newline at end of file +} diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f80b56b43..069ec68fd 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -130,6 +130,9 @@ void linphone_core_zrtp_cache_db_init(LinphoneCore *lc, const char *fileName); #include "contact_providers_priv.h" +using namespace LINPHONE_NAMESPACE; + + const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc); static void toggle_video_preview(LinphoneCore *lc, bool_t val); @@ -143,7 +146,7 @@ static void toggle_video_preview(LinphoneCore *lc, bool_t val); #define HOLD_MUSIC_WAV "toy-mono.wav" #define HOLD_MUSIC_MKV "dont_wait_too_long.mkv" -extern SalCallbacks linphone_sal_callbacks; +extern Sal::Callbacks linphone_sal_callbacks; static void _linphone_core_cbs_uninit(LinphoneCoreCbs *cbs); @@ -1286,11 +1289,11 @@ static void sip_config_read(LinphoneCore *lc) { int ipv6_default = TRUE; if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){ - sal_use_session_timers(lc->sal,200); + lc->sal->use_session_timers(200); } - sal_use_no_initial_route(lc->sal, !!lp_config_get_int(lc->config,"sip","use_no_initial_route",0)); - sal_use_rport(lc->sal, !!lp_config_get_int(lc->config,"sip","use_rport",1)); + lc->sal->use_no_initial_route(!!lp_config_get_int(lc->config,"sip","use_no_initial_route",0)); + lc->sal->use_rport(!!lp_config_get_int(lc->config,"sip","use_rport",1)); if (!lp_config_get_int(lc->config,"sip","ipv6_migration_done",FALSE) && lp_config_has_entry(lc->config,"sip","use_ipv6")) { lp_config_clean_entry(lc->config,"sip","use_ipv6"); @@ -1309,7 +1312,7 @@ static void sip_config_read(LinphoneCore *lc) { certificates_config_read(lc); /*setting the dscp must be done before starting the transports, otherwise it is not taken into effect*/ - sal_set_dscp(lc->sal,linphone_core_get_sip_dscp(lc)); + lc->sal->set_dscp(linphone_core_get_sip_dscp(lc)); /*start listening on ports*/ linphone_core_set_sip_transports(lc,&tr); @@ -1385,12 +1388,12 @@ static void sip_config_read(LinphoneCore *lc) { lc->sip_conf.keepalive_period = (unsigned int)lp_config_get_int(lc->config,"sip","keepalive_period",10000); lc->sip_conf.tcp_tls_keepalive = !!lp_config_get_int(lc->config,"sip","tcp_tls_keepalive",0); linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0)); - sal_use_one_matching_codec_policy(lc->sal, !!lp_config_get_int(lc->config,"sip","only_one_codec",0)); - sal_use_dates(lc->sal, !!lp_config_get_int(lc->config,"sip","put_date",0)); - sal_enable_sip_update_method(lc->sal, !!lp_config_get_int(lc->config,"sip","sip_update",1)); + lc->sal->use_one_matching_codec_policy(!!lp_config_get_int(lc->config,"sip","only_one_codec",0)); + lc->sal->use_dates(!!lp_config_get_int(lc->config,"sip","put_date",0)); + lc->sal->enable_sip_update_method(!!lp_config_get_int(lc->config,"sip","sip_update",1)); lc->sip_conf.vfu_with_info = !!lp_config_get_int(lc->config,"sip","vfu_with_info",1); linphone_core_set_sip_transport_timeout(lc, lp_config_get_int(lc->config, "sip", "transport_timeout", 63000)); - sal_set_supported_tags(lc->sal,lp_config_get_string(lc->config,"sip","supported","replaces, outbound, gruu")); + lc->sal->set_supported_tags(lp_config_get_string(lc->config,"sip","supported","replaces, outbound, gruu")); lc->sip_conf.save_auth_info = !!lp_config_get_int(lc->config, "sip", "save_auth_info", 1); linphone_core_create_im_notif_policy(lc); } @@ -1769,7 +1772,7 @@ static void ui_config_read(LinphoneCore *lc) read_friends_from_rc(lc); } if (!lc->logs_db) { - lc->call_logs = call_logs_read_from_config_file(lc); + lc->call_logs = linphone_core_read_call_logs_from_config_file(lc); } #endif } @@ -1842,37 +1845,37 @@ void linphone_core_set_expected_bandwidth(LinphoneCore *lc, int bw){ } void linphone_core_set_sip_transport_timeout(LinphoneCore *lc, int timeout_ms) { - sal_set_transport_timeout(lc->sal, timeout_ms); + lc->sal->set_transport_timeout(timeout_ms); if (linphone_core_ready(lc)) lp_config_set_int(lc->config, "sip", "transport_timeout", timeout_ms); } int linphone_core_get_sip_transport_timeout(LinphoneCore *lc) { - return sal_get_transport_timeout(lc->sal); + return lc->sal->get_transport_timeout(); } void linphone_core_set_dns_servers(LinphoneCore *lc, const bctbx_list_t *servers){ - sal_set_dns_servers(lc->sal, servers); + lc->sal->set_dns_servers(servers); } void linphone_core_enable_dns_srv(LinphoneCore *lc, bool_t enable) { - sal_enable_dns_srv(lc->sal, enable); + lc->sal->enable_dns_srv(enable); if (linphone_core_ready(lc)) lp_config_set_int(lc->config, "net", "dns_srv_enabled", enable ? 1 : 0); } bool_t linphone_core_dns_srv_enabled(const LinphoneCore *lc) { - return sal_dns_srv_enabled(lc->sal); + return lc->sal->dns_srv_enabled(); } void linphone_core_enable_dns_search(LinphoneCore *lc, bool_t enable) { - sal_enable_dns_search(lc->sal, enable); + lc->sal->enable_dns_search(enable); if (linphone_core_ready(lc)) lp_config_set_int(lc->config, "net", "dns_search_enabled", enable ? 1 : 0); } bool_t linphone_core_dns_search_enabled(const LinphoneCore *lc) { - return sal_dns_search_enabled(lc->sal); + return lc->sal->dns_search_enabled(); } int linphone_core_get_download_bandwidth(const LinphoneCore *lc){ @@ -1958,10 +1961,10 @@ static void misc_config_read(LinphoneCore *lc) { uuid=lp_config_get_string(config,"misc","uuid",NULL); if (!uuid){ char tmp[64]; - sal_create_uuid(lc->sal,tmp,sizeof(tmp)); + lc->sal->create_uuid(tmp,sizeof(tmp)); lp_config_set_string(config,"misc","uuid",tmp); }else if (strcmp(uuid,"0")!=0) /*to allow to disable sip.instance*/ - sal_set_uuid(lc->sal, uuid); + lc->sal->set_uuid(uuid); lc->user_certificates_path=ms_strdup(lp_config_get_string(config,"misc","user_certificates_path",".")); lc->send_call_stats_periodical_updates = !!lp_config_get_int(config, "misc", "send_call_stats_periodical_updates", 0); @@ -2211,12 +2214,12 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig /* This allows to run event's callback in linphone_core_iterate() */ lc->msevq=ms_factory_create_event_queue(lc->factory); - lc->sal=sal_init(lc->factory); - sal_set_http_proxy_host(lc->sal, linphone_core_get_http_proxy_host(lc)); - sal_set_http_proxy_port(lc->sal, linphone_core_get_http_proxy_port(lc)); + lc->sal=new Sal(lc->factory); + lc->sal->set_http_proxy_host(linphone_core_get_http_proxy_host(lc)); + lc->sal->set_http_proxy_port(linphone_core_get_http_proxy_port(lc)); - sal_set_user_pointer(lc->sal,lc); - sal_set_callbacks(lc->sal,&linphone_sal_callbacks); + lc->sal->set_user_pointer(lc); + lc->sal->set_callbacks(&linphone_sal_callbacks); #ifdef TUNNEL_ENABLED lc->tunnel=linphone_core_tunnel_new(lc); @@ -2228,7 +2231,7 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig /* Create the http provider in dual stack mode (ipv4 and ipv6. * If this creates problem, we may need to implement parallel ipv6/ ipv4 http requests in belle-sip. */ - lc->http_provider = belle_sip_stack_create_http_provider(reinterpret_cast(sal_get_stack_impl(lc->sal)), "::0"); + lc->http_provider = belle_sip_stack_create_http_provider(reinterpret_cast(lc->sal->get_stack_impl()), "::0"); lc->http_crypto_config = belle_tls_crypto_config_new(); belle_http_provider_set_tls_crypto_config(lc->http_provider,lc->http_crypto_config); @@ -2733,12 +2736,12 @@ void linphone_core_set_user_agent(LinphoneCore *lc, const char *name, const char char ua_string[256]; snprintf(ua_string, sizeof(ua_string) - 1, "%s/%s", name?name:"", ver?ver:""); if (lc->sal) { - sal_set_user_agent(lc->sal, ua_string); - sal_append_stack_string_to_user_agent(lc->sal); + lc->sal->set_user_agent(ua_string); + lc->sal->append_stack_string_to_user_agent(); } } const char *linphone_core_get_user_agent(LinphoneCore *lc){ - return sal_get_user_agent(lc->sal); + return lc->sal->get_user_agent(); } const char *linphone_core_get_user_agent_name(void){ @@ -2781,32 +2784,32 @@ int _linphone_core_apply_transports(LinphoneCore *lc){ else anyaddr="0.0.0.0"; - sal_unlisten_ports(sal); + sal->unlisten_ports(); listening_address = lp_config_get_string(lc->config,"sip","bind_address",anyaddr); if (linphone_core_get_http_proxy_host(lc)) { - sal_set_http_proxy_host(sal, linphone_core_get_http_proxy_host(lc)); - sal_set_http_proxy_port(sal,linphone_core_get_http_proxy_port(lc)); + sal->set_http_proxy_host(linphone_core_get_http_proxy_host(lc)); + sal->set_http_proxy_port(linphone_core_get_http_proxy_port(lc)); } if (lc->tunnel && linphone_tunnel_sip_enabled(lc->tunnel) && linphone_tunnel_get_activated(lc->tunnel)){ - sal_listen_port(sal,anyaddr,tr->udp_port,SalTransportUDP,TRUE); + sal->set_listen_port(anyaddr,tr->udp_port,SalTransportUDP,TRUE); }else{ if (tr->udp_port!=0){ - sal_listen_port(sal,listening_address,tr->udp_port,SalTransportUDP,FALSE); + sal->set_listen_port(listening_address,tr->udp_port,SalTransportUDP,FALSE); } if (tr->tcp_port!=0){ - sal_listen_port (sal,listening_address,tr->tcp_port,SalTransportTCP,FALSE); + sal->set_listen_port (listening_address,tr->tcp_port,SalTransportTCP,FALSE); } if (linphone_core_sip_transport_supported(lc,LinphoneTransportTls)){ if (tr->tls_port!=0) - sal_listen_port (sal,listening_address,tr->tls_port,SalTransportTLS,FALSE); + sal->set_listen_port (listening_address,tr->tls_port,SalTransportTLS,FALSE); } } return 0; } bool_t linphone_core_sip_transport_supported(const LinphoneCore *lc, LinphoneTransportType tp){ - return !!sal_transport_available(lc->sal,(SalTransport)tp); + return !!lc->sal->transport_available((SalTransport)tp); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneTransports); @@ -2946,17 +2949,17 @@ LinphoneTransports *linphone_core_get_transports(LinphoneCore *lc){ } void linphone_core_get_sip_transports_used(LinphoneCore *lc, LinphoneSipTransports *tr){ - tr->udp_port=sal_get_listening_port(lc->sal,SalTransportUDP); - tr->tcp_port=sal_get_listening_port(lc->sal,SalTransportTCP); - tr->tls_port=sal_get_listening_port(lc->sal,SalTransportTLS); + tr->udp_port=lc->sal->get_listening_port(SalTransportUDP); + tr->tcp_port=lc->sal->get_listening_port(SalTransportTCP); + tr->tls_port=lc->sal->get_listening_port(SalTransportTLS); } LinphoneTransports *linphone_core_get_transports_used(LinphoneCore *lc){ LinphoneTransports *transports = linphone_transports_new(); - transports->udp_port = sal_get_listening_port(lc->sal, SalTransportUDP); - transports->tcp_port = sal_get_listening_port(lc->sal, SalTransportTCP); - transports->tls_port = sal_get_listening_port(lc->sal, SalTransportTLS); - transports->dtls_port = sal_get_listening_port(lc->sal, SalTransportDTLS); + transports->udp_port = lc->sal->get_listening_port(SalTransportUDP); + transports->tcp_port = lc->sal->get_listening_port(SalTransportTCP); + transports->tls_port = lc->sal->get_listening_port(SalTransportTLS); + transports->dtls_port = lc->sal->get_listening_port(SalTransportDTLS); return transports; } @@ -2988,7 +2991,7 @@ void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val){ bool_t linphone_core_content_encoding_supported(const LinphoneCore *lc, const char *content_encoding) { const char *handle_content_encoding = lp_config_get_string(lc->config, "sip", "handle_content_encoding", "deflate"); - return (strcmp(handle_content_encoding, content_encoding) == 0) && sal_content_encoding_available(lc->sal, content_encoding); + return (strcmp(handle_content_encoding, content_encoding) == 0) && lc->sal->content_encoding_available(content_encoding); } static void monitor_network_state(LinphoneCore *lc, time_t curtime){ @@ -3122,8 +3125,8 @@ void linphone_core_iterate(LinphoneCore *lc){ } } if (linphone_core_get_global_state(lc) == LinphoneGlobalStartup) { - if (sal_get_root_ca(lc->sal)) { - belle_tls_crypto_config_set_root_ca(lc->http_crypto_config, sal_get_root_ca(lc->sal)); + if (lc->sal->get_root_ca()) { + belle_tls_crypto_config_set_root_ca(lc->http_crypto_config, lc->sal->get_root_ca()); belle_http_provider_set_tls_crypto_config(lc->http_provider, lc->http_crypto_config); } @@ -3190,7 +3193,7 @@ void linphone_core_iterate(LinphoneCore *lc){ } } - sal_iterate(lc->sal); + lc->sal->iterate(); if (lc->msevq) ms_event_queue_pump(lc->msevq); if (lc->auto_net_state_mon) monitor_network_state(lc, current_real_time); @@ -3438,7 +3441,7 @@ static void linphone_transfer_routes_to_op(bctbx_list_t *routes, SalOp *op){ bctbx_list_t *it; for(it=routes;it!=NULL;it=it->next){ SalAddress *addr=(SalAddress*)it->data; - sal_op_add_route_address(op,addr); + op->add_route_address(addr); sal_address_destroy(addr); } bctbx_list_free(routes); @@ -3450,7 +3453,7 @@ void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const Linphon if (proxy){ identity=linphone_proxy_config_get_identity(proxy); if (linphone_proxy_config_get_privacy(proxy)!=LinphonePrivacyDefault) { - sal_op_set_privacy(op,linphone_proxy_config_get_privacy(proxy)); + op->set_privacy(linphone_proxy_config_get_privacy(proxy)); } }else identity=linphone_core_get_primary_contact(lc); /*sending out of calls*/ @@ -3459,19 +3462,19 @@ void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const Linphon linphone_transfer_routes_to_op(routes,op); } char *addr = linphone_address_as_string(dest); - sal_op_set_to(op,addr); + op->set_to(addr); ms_free(addr); - sal_op_set_from(op,identity); - sal_op_set_sent_custom_header(op,headers); - sal_op_set_realm(op,linphone_proxy_config_get_realm(proxy)); + op->set_from(identity); + op->set_sent_custom_header(headers); + op->set_realm(linphone_proxy_config_get_realm(proxy)); if (with_contact && proxy && proxy->op){ const LinphoneAddress *contact = linphone_proxy_config_get_contact(proxy); SalAddress *salAddress = nullptr; if (contact) salAddress = sal_address_clone(const_cast(L_GET_PRIVATE_FROM_C_OBJECT(contact)->getInternalAddress())); - sal_op_set_contact_address(op, salAddress); + op->set_contact_address(salAddress); } - sal_op_cnx_ip_to_0000_if_sendonly_enable(op, !!lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0)); /*also set in linphone_call_new_incoming*/ + op->enable_cnx_ip_to_0000_if_sendonly(!!lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0)); /*also set in linphone_call_new_incoming*/ } void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact) { linphone_configure_op_with_proxy(lc, op, dest, headers,with_contact,linphone_core_lookup_known_proxy(lc,dest)); @@ -4216,7 +4219,7 @@ const char *linphone_core_get_ring(const LinphoneCore *lc){ } void linphone_core_set_root_ca(LinphoneCore *lc, const char *path) { - sal_set_root_ca(lc->sal, path); + lc->sal->set_root_ca(path); if (lc->http_crypto_config) { belle_tls_crypto_config_set_root_ca(lc->http_crypto_config, path); } @@ -4224,8 +4227,8 @@ void linphone_core_set_root_ca(LinphoneCore *lc, const char *path) { } void linphone_core_set_root_ca_data(LinphoneCore *lc, const char *data) { - sal_set_root_ca(lc->sal, NULL); - sal_set_root_ca_data(lc->sal, data); + lc->sal->set_root_ca(NULL); + lc->sal->set_root_ca_data(data); if (lc->http_crypto_config) { belle_tls_crypto_config_set_root_ca_data(lc->http_crypto_config, data); } @@ -4236,7 +4239,7 @@ const char *linphone_core_get_root_ca(LinphoneCore *lc){ } void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno){ - sal_verify_server_certificates(lc->sal,yesno); + lc->sal->verify_server_certificates(yesno); if (lc->http_crypto_config){ belle_tls_crypto_config_set_verify_exceptions(lc->http_crypto_config, yesno ? 0 : BELLE_TLS_VERIFY_ANY_REASON); } @@ -4244,7 +4247,7 @@ void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno){ } void linphone_core_verify_server_cn(LinphoneCore *lc, bool_t yesno){ - sal_verify_server_cn(lc->sal,yesno); + lc->sal->verify_server_cn(yesno); if (lc->http_crypto_config){ belle_tls_crypto_config_set_verify_exceptions(lc->http_crypto_config, yesno ? 0 : BELLE_TLS_VERIFY_CN_MISMATCH); } @@ -4252,7 +4255,7 @@ void linphone_core_verify_server_cn(LinphoneCore *lc, bool_t yesno){ } void linphone_core_set_ssl_config(LinphoneCore *lc, void *ssl_config) { - sal_set_ssl_config(lc->sal, ssl_config); + lc->sal->set_ssl_config(ssl_config); if (lc->http_crypto_config) { belle_tls_crypto_config_set_ssl_config(lc->http_crypto_config, ssl_config); } @@ -4549,9 +4552,9 @@ void linphone_core_set_nat_policy(LinphoneCore *lc, LinphoneNatPolicy *policy) { linphone_nat_policy_save_to_config(lc->nat_policy); } - sal_nat_helper_enable(lc->sal, !!lp_config_get_int(lc->config, "net", "enable_nat_helper", 1)); - sal_enable_auto_contacts(lc->sal, TRUE); - sal_use_rport(lc->sal, !!lp_config_get_int(lc->config, "sip", "use_rport", 1)); + lc->sal->enable_nat_helper(!!lp_config_get_int(lc->config, "net", "enable_nat_helper", 1)); + lc->sal->enable_auto_contacts(TRUE); + lc->sal->use_rport(!!lp_config_get_int(lc->config, "sip", "use_rport", 1)); if (lc->sip_conf.contact) update_primary_contact(lc); } @@ -4653,7 +4656,7 @@ void linphone_core_migrate_logs_from_rc_to_db(LinphoneCore *lc) { return; } - logs_to_migrate = call_logs_read_from_config_file(lc); + logs_to_migrate = linphone_core_read_call_logs_from_config_file(lc); if (!logs_to_migrate) { ms_warning("nothing to migrate, skipping..."); return; @@ -5730,7 +5733,7 @@ void sip_config_uninit(LinphoneCore *lc) for (i=0;i<20&&still_registered;i++){ still_registered=FALSE; - sal_iterate(lc->sal); + lc->sal->iterate(); for(elem=config->proxies;elem!=NULL;elem=bctbx_list_next(elem)){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data); LinphoneRegistrationState state = linphone_proxy_config_get_state(cfg); @@ -5754,8 +5757,8 @@ void sip_config_uninit(LinphoneCore *lc) linphone_vcard_context_destroy(lc->vcard_context); } - sal_reset_transports(lc->sal); - sal_unlisten_ports(lc->sal); /*to make sure no new messages are received*/ + lc->sal->reset_transports(); + lc->sal->unlisten_ports(); /*to make sure no new messages are received*/ if (lc->http_provider) { belle_sip_object_unref(lc->http_provider); lc->http_provider=NULL; @@ -5774,8 +5777,8 @@ void sip_config_uninit(LinphoneCore *lc) } #endif - sal_iterate(lc->sal); /*make sure event are purged*/ - sal_uninit(lc->sal); + lc->sal->iterate(); /*make sure event are purged*/ + delete lc->sal; lc->sal=NULL; if (lc->sip_conf.guessed_contact) @@ -6054,7 +6057,7 @@ static void set_sip_network_reachable(LinphoneCore* lc,bool_t is_sip_reachable, if (!lc->sip_network_reachable){ linphone_core_invalidate_friend_subscriptions(lc); - sal_reset_transports(lc->sal); + lc->sal->reset_transports(); /*mark all calls as broken, so that they can be either dropped immediately or restaured when network will be back*/ bctbx_list_for_each(lc->calls, (MSIterateFunc) linphone_call_set_broken); } @@ -6133,7 +6136,7 @@ bool_t linphone_core_is_network_reachable(LinphoneCore* lc) { } ortp_socket_t linphone_core_get_sip_socket(LinphoneCore *lc){ - return sal_get_socket(lc->sal); + return lc->sal->get_socket(); } void linphone_core_destroy(LinphoneCore *lc){ @@ -6320,15 +6323,15 @@ const char *linphone_error_to_string(LinphoneReason err){ void linphone_core_enable_keep_alive(LinphoneCore* lc,bool_t enable) { if (enable > 0) { - sal_use_tcp_tls_keepalive(lc->sal,lc->sip_conf.tcp_tls_keepalive); - sal_set_keepalive_period(lc->sal,lc->sip_conf.keepalive_period); + lc->sal->use_tcp_tls_keepalive(lc->sip_conf.tcp_tls_keepalive); + lc->sal->set_keepalive_period(lc->sip_conf.keepalive_period); } else { - sal_set_keepalive_period(lc->sal,0); + lc->sal->set_keepalive_period(0); } } bool_t linphone_core_keep_alive_enabled(LinphoneCore* lc) { - return sal_get_keepalive_period(lc->sal) > 0; + return lc->sal->get_keepalive_period() > 0; } void linphone_core_start_dtmf_stream(LinphoneCore* lc) { @@ -6665,7 +6668,7 @@ const char* linphone_core_get_device_identifier(const LinphoneCore *lc) { } void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp){ - sal_set_dscp(lc->sal,dscp); + lc->sal->set_dscp(dscp); if (linphone_core_ready(lc)){ lp_config_set_int_hex(lc->config,"sip","dscp",dscp); _linphone_core_apply_transports(lc); @@ -6727,13 +6730,13 @@ const char * linphone_core_get_file_transfer_server(LinphoneCore *core) { } void linphone_core_add_supported_tag(LinphoneCore *lc, const char *tag){ - sal_add_supported_tag(lc->sal,tag); - lp_config_set_string(lc->config,"sip","supported",sal_get_supported_tags(lc->sal)); + lc->sal->add_supported_tag(tag); + lp_config_set_string(lc->config,"sip","supported",lc->sal->get_supported_tags()); } void linphone_core_remove_supported_tag(LinphoneCore *lc, const char *tag){ - sal_remove_supported_tag(lc->sal,tag); - lp_config_set_string(lc->config,"sip","supported",sal_get_supported_tags(lc->sal)); + lc->sal->remove_supported_tag(tag); + lp_config_set_string(lc->config,"sip","supported",lc->sal->get_supported_tags()); } void linphone_core_set_avpf_mode(LinphoneCore *lc, LinphoneAVPFMode mode){ @@ -6895,15 +6898,15 @@ void linphone_core_enable_realtime_text(LinphoneCore *lc, bool_t value) { void linphone_core_set_http_proxy_host(LinphoneCore *lc, const char *host) { lp_config_set_string(lc->config,"sip","http_proxy_host",host); if (lc->sal) { - sal_set_http_proxy_host(lc->sal,host); - sal_set_http_proxy_port(lc->sal,linphone_core_get_http_proxy_port(lc)); /*to make sure default value is set*/ + lc->sal->set_http_proxy_host(host); + lc->sal->set_http_proxy_port(linphone_core_get_http_proxy_port(lc)); /*to make sure default value is set*/ } } void linphone_core_set_http_proxy_port(LinphoneCore *lc, int port) { lp_config_set_int(lc->config,"sip","http_proxy_port",port); if (lc->sal) - sal_set_http_proxy_port(lc->sal,port); + lc->sal->set_http_proxy_port(port); } const char *linphone_core_get_http_proxy_host(const LinphoneCore *lc) { @@ -7132,19 +7135,19 @@ LinphoneImEncryptionEngine *linphone_core_get_im_encryption_engine(const Linphon } void linphone_core_initialize_supported_content_types(LinphoneCore *lc) { - sal_add_content_type_support(lc->sal, "text/plain"); - sal_add_content_type_support(lc->sal, "message/external-body"); - sal_add_content_type_support(lc->sal, "application/vnd.gsma.rcs-ft-http+xml"); - sal_add_content_type_support(lc->sal, "application/im-iscomposing+xml"); - sal_add_content_type_support(lc->sal, "message/imdn+xml"); + lc->sal->add_content_type_support("text/plain"); + lc->sal->add_content_type_support("message/external-body"); + lc->sal->add_content_type_support("application/vnd.gsma.rcs-ft-http+xml"); + lc->sal->add_content_type_support("application/im-iscomposing+xml"); + lc->sal->add_content_type_support("message/imdn+xml"); } bool_t linphone_core_is_content_type_supported(const LinphoneCore *lc, const char *content_type) { - return sal_is_content_type_supported(lc->sal, content_type); + return lc->sal->is_content_type_supported(content_type); } void linphone_core_add_content_type_support(LinphoneCore *lc, const char *content_type) { - sal_add_content_type_support(lc->sal, content_type); + lc->sal->add_content_type_support(content_type); } #ifdef ENABLE_UPDATE_CHECK diff --git a/coreapi/misc.c b/coreapi/misc.c index cf1bd497b..c14a8b4c8 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -508,7 +508,7 @@ const char * linphone_core_get_echo_canceller_filter_name(const LinphoneCore *lc * task_fun must return BELLE_SIP_STOP when job is finished. **/ void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description){ - belle_sip_source_t *s=sal_create_timer(lc->sal,task_fun,data, 20, task_description); + belle_sip_source_t *s=lc->sal->create_timer(task_fun,data, 20, task_description); belle_sip_object_unref(s); } diff --git a/coreapi/nat_policy.c b/coreapi/nat_policy.c index 4d96016df..86f676412 100644 --- a/coreapi/nat_policy.c +++ b/coreapi/nat_policy.c @@ -230,7 +230,7 @@ void linphone_nat_policy_resolve_stun_server(LinphoneNatPolicy *policy) { int family = AF_INET; if (linphone_core_ipv6_enabled(policy->lc) == TRUE) family = AF_INET6; ms_message("Starting stun server resolution [%s]", host); - policy->stun_resolver_context = sal_resolve(policy->lc->sal, service, "udp", host, port, family, stun_server_resolved, policy); + policy->stun_resolver_context = policy->lc->sal->resolve(service, "udp", host, port, family, stun_server_resolved, policy); if (policy->stun_resolver_context) belle_sip_object_ref(policy->stun_resolver_context); } } @@ -252,7 +252,7 @@ const struct addrinfo * linphone_nat_policy_get_stun_server_addrinfo(LinphoneNat int wait_limit = 1000; linphone_nat_policy_resolve_stun_server(policy); while ((policy->stun_addrinfo == NULL) && (policy->stun_resolver_context != NULL) && (wait_ms < wait_limit)) { - sal_iterate(policy->lc->sal); + policy->lc->sal->iterate(); ms_usleep(50000); wait_ms += 50; } diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 2e657b9a5..a24e9b418 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sal/sal.h" +#include "sal/sal.hpp" #include "offeranswer.h" #include "private.h" diff --git a/coreapi/presence.c b/coreapi/presence.c index 0ffa56d5d..7546b756d 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -23,6 +23,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" +using namespace LINPHONE_NAMESPACE; + extern const char *__policy_enum_to_str(LinphoneSubscribePolicy pol); struct _LinphonePresenceNote { @@ -1540,7 +1542,7 @@ void linphone_core_notify_all_friends(LinphoneCore *lc, LinphonePresenceModel *p } } -void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ +void linphone_subscription_new(LinphoneCore *lc, SalSubscribeOp *op, const char *from){ LinphoneFriend *lf=NULL; char *tmp; LinphoneAddress *uri; @@ -1557,12 +1559,12 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ linphone_friend_add_incoming_subscription(lf, op); lf->inc_subscribe_pending=TRUE; if (lp_config_get_int(lc->config,"sip","notify_pending_state",0)) { - sal_notify_pending_state(op); + op->notify_pending_state(); } - sal_subscribe_accept(op); + op->accept(); } else { ms_message("%s is not authorized to subscribe", from); - sal_subscribe_decline(op, SalReasonDeclined); + op->decline(SalReasonDeclined); } linphone_friend_done(lf); /*this will do all necessary actions */ }else{ @@ -1570,14 +1572,14 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ if (linphone_find_friend_by_address(lc->subscribers,uri,&lf)){ if (lf->pol==LinphoneSPDeny){ ms_message("Rejecting %s because we already rejected it once.",from); - sal_subscribe_decline(op,SalReasonDeclined); + op->decline(SalReasonDeclined); } else { /* else it is in wait for approval state, because otherwise it is in the friend list.*/ ms_message("New subscriber found in subscriber list, in %s state.",__policy_enum_to_str(lf->pol)); } }else { - sal_subscribe_accept(op); + op->accept(); linphone_core_add_subscriber(lc,tmp,op); } } @@ -1930,7 +1932,7 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa if (linphone_core_get_default_friend_list(lc) != NULL) lf=linphone_core_find_friend_by_out_subscribe(lc, op); if (lf==NULL && lp_config_get_int(lc->config,"sip","allow_out_of_subscribe_presence",0)){ - char *buf = sal_address_as_string_uri_only(sal_op_get_from_address(op)); + char *buf = sal_address_as_string_uri_only(op->get_from_address()); LinphoneAddress *addr = linphone_address_new(buf); lf = linphone_core_find_friend(lc, addr); ms_free(buf); @@ -1959,27 +1961,27 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa linphone_core_notify_notify_presence_received(lc,(LinphoneFriend*)lf); if (op != lf->outsub){ /*case of a NOTIFY received out of any dialog*/ - sal_op_release(op); + op->release(); return; } }else{ ms_message("But this person is not part of our friend list, so we don't care."); linphone_presence_model_unref(presence); - sal_op_release(op); + op->release(); return ; } if (ss==SalSubscribeTerminated){ if (lf){ if (lf->outsub != op){ - sal_op_release(op); + op->release(); } if (lf->outsub){ - sal_op_release(lf->outsub); + lf->outsub->release(); lf->outsub=NULL; } lf->subscribe_active=FALSE; }else{ - sal_op_release(op); + op->release(); } } } @@ -1994,7 +1996,7 @@ void linphone_subscription_closed(LinphoneCore *lc, SalOp *op){ linphone_friend_remove_incoming_subscription(lf, op); }else{ /*case of an op that we already released because the friend was destroyed*/ - ms_message("Receiving unsuscribe for unknown in-subscribtion from %s", sal_op_get_from(op)); + ms_message("Receiving unsuscribe for unknown in-subscribtion from %s", op->get_from()); } } diff --git a/coreapi/private.h b/coreapi/private.h index 67e886c52..ce5b184a4 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -32,12 +32,19 @@ #include "linphone/core_utils.h" #include "linphone/conference.h" #include "sal/sal.h" +#include "sal/call_op.h" +#include "sal/event_op.h" +#include "sal/message_op.h" +#include "sal/presence_op.h" +#include "sal/register_op.h" #include "linphone/sipsetup.h" #include "quality_reporting.h" #include "linphone/ringtoneplayer.h" #include "vcard_private.h" #include "carddav.h" #include "linphone/player.h" +#include "account_creator_private.h" +#include "tester_utils.h" #include "bctoolbox/port.h" #include "bctoolbox/map.h" @@ -164,7 +171,7 @@ typedef struct _CallCallbackObj bool_t is_read; unsigned int storage_id; char *message_id; - SalOp *op; + MessageOp *op; LinphoneContent *file_transfer_information; //< used to store file transfer information when the message is of file transfer type char *content_type; //< is used to specified the type of message to be sent, used only for file transfer message bool_t to_be_stored; @@ -214,7 +221,7 @@ void linphone_call_notify_info_message_received(LinphoneCall *call, const Linpho void linphone_call_notify_ack_processing(LinphoneCall *call, LinphoneHeaders *msg, bool_t is_received); LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg); -LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, SalOp *op); +LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, LINPHONE_NAMESPACE::SalCallOp *op); void _linphone_call_set_new_params(LinphoneCall *call, const LinphoneCallParams *params); void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message); /* private: */ @@ -222,12 +229,12 @@ LinphoneCallLog * linphone_call_log_new(LinphoneCallDir dir, LinphoneAddress *fr void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state); LinphonePlayer *linphone_call_build_player(LinphoneCall*call); void linphone_call_refresh_sockets(LinphoneCall *call); -void linphone_call_replace_op(LinphoneCall *call, SalOp *op); +void linphone_call_replace_op(LinphoneCall *call, LINPHONE_NAMESPACE::SalOp *op); void linphone_call_reinvite_to_recover_from_connection_loss(LinphoneCall *call); -SalOp * linphone_call_get_op(const LinphoneCall *call); +LINPHONE_NAMESPACE::SalCallOp *linphone_call_get_op(const LinphoneCall *call); LinphoneProxyConfig * linphone_call_get_dest_proxy(const LinphoneCall *call); -MediaStream * linphone_call_get_stream(LinphoneCall *call, LinphoneStreamType type); +LINPHONE_PUBLIC MediaStream * linphone_call_get_stream(LinphoneCall *call, LinphoneStreamType type); LinphoneCallLog * linphone_call_get_log(const LinphoneCall *call); IceSession * linphone_call_get_ice_session(const LinphoneCall *call); bool_t linphone_call_get_audio_muted(const LinphoneCall *call); @@ -311,15 +318,15 @@ void _linphone_friend_release(LinphoneFriend *lf); LINPHONE_PUBLIC void linphone_friend_update_subscribes(LinphoneFriend *fr, bool_t only_when_registered); void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence); void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc); -void linphone_friend_add_incoming_subscription(LinphoneFriend *lf, SalOp *op); -void linphone_friend_remove_incoming_subscription(LinphoneFriend *lf, SalOp *op); +void linphone_friend_add_incoming_subscription(LinphoneFriend *lf, LINPHONE_NAMESPACE::SalOp *op); +void linphone_friend_remove_incoming_subscription(LinphoneFriend *lf, LINPHONE_NAMESPACE::SalOp *op); const char * linphone_friend_phone_number_to_sip_uri(LinphoneFriend *lf, const char *phone_number); const char * linphone_friend_sip_uri_to_phone_number(LinphoneFriend *lf, const char *uri); void linphone_friend_clear_presence_models(LinphoneFriend *lf); -LinphoneFriend *linphone_friend_list_find_friend_by_inc_subscribe(const LinphoneFriendList *list, SalOp *op); -LinphoneFriend *linphone_friend_list_find_friend_by_out_subscribe(const LinphoneFriendList *list, SalOp *op); -LinphoneFriend *linphone_core_find_friend_by_out_subscribe(const LinphoneCore *lc, SalOp *op); -LinphoneFriend *linphone_core_find_friend_by_inc_subscribe(const LinphoneCore *lc, SalOp *op); +LinphoneFriend *linphone_friend_list_find_friend_by_inc_subscribe(const LinphoneFriendList *list, LINPHONE_NAMESPACE::SalOp *op); +LinphoneFriend *linphone_friend_list_find_friend_by_out_subscribe(const LinphoneFriendList *list, LINPHONE_NAMESPACE::SalOp *op); +LinphoneFriend *linphone_core_find_friend_by_out_subscribe(const LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op); +LinphoneFriend *linphone_core_find_friend_by_inc_subscribe(const LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op); MSList *linphone_find_friend_by_address(MSList *fl, const LinphoneAddress *addr, LinphoneFriend **lf); bool_t linphone_core_should_subscribe_friends_only_when_registered(const LinphoneCore *lc); void linphone_core_update_friends_subscriptions(LinphoneCore *lc); @@ -354,19 +361,19 @@ static MS2_INLINE void set_string(char **dest, const char *src, bool_t lowercase } } -void linphone_process_authentication(LinphoneCore* lc, SalOp *op); -void linphone_authentication_ok(LinphoneCore *lc, SalOp *op); -void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from); +void linphone_process_authentication(LinphoneCore* lc, LINPHONE_NAMESPACE::SalOp *op); +void linphone_authentication_ok(LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op); +void linphone_subscription_new(LinphoneCore *lc, LINPHONE_NAMESPACE::SalSubscribeOp *op, const char *from); void linphone_core_send_presence(LinphoneCore *lc, LinphonePresenceModel *presence); void linphone_notify_parse_presence(const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result); -void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presence, const char *contact, char **content); -void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model); -void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, SalOp *op); +void linphone_notify_convert_presence_to_xml(LINPHONE_NAMESPACE::SalOp *op, SalPresenceModel *presence, const char *contact, char **content); +void linphone_notify_recv(LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model); +void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op); void linphone_core_soundcard_hint_check(LinphoneCore* lc); -void linphone_subscription_answered(LinphoneCore *lc, SalOp *op); -void linphone_subscription_closed(LinphoneCore *lc, SalOp *op); +void linphone_subscription_answered(LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op); +void linphone_subscription_closed(LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op); void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc); @@ -415,7 +422,7 @@ LINPHONE_PUBLIC void linphone_core_get_local_ip(LinphoneCore *lc, int af, const LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore *lc, int index); void linphone_proxy_config_write_to_config_file(LinphoneConfig* config,LinphoneProxyConfig *obj, int index); -int linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *msg); +int linphone_core_message_received(LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op, const SalMessage *msg); void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, uint32_t character, LinphoneCall *call); void linphone_call_init_media_streams(LinphoneCall *call); @@ -439,17 +446,12 @@ int linphone_call_start_update(LinphoneCall *call); int linphone_call_start_accept_update(LinphoneCall *call, LinphoneCallState next_state, const char *state_info); void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call); bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md); -extern SalCallbacks linphone_sal_callbacks; +extern LINPHONE_NAMESPACE::Sal::Callbacks linphone_sal_callbacks; LINPHONE_PUBLIC bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); LINPHONE_PUBLIC bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc); void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description); -typedef enum _LinphoneProxyConfigAddressComparisonResult{ - LinphoneProxyConfigAddressDifferent, - LinphoneProxyConfigAddressEqual, - LinphoneProxyConfigAddressWeakEqual -} LinphoneProxyConfigAddressComparisonResult; LINPHONE_PUBLIC LinphoneProxyConfigAddressComparisonResult linphone_proxy_config_address_equal(const LinphoneAddress *a, const LinphoneAddress *b); LINPHONE_PUBLIC LinphoneProxyConfigAddressComparisonResult linphone_proxy_config_is_server_config_changed(const LinphoneProxyConfig* obj); @@ -486,7 +488,7 @@ struct _LinphoneProxyConfig char *contact_uri_params; int expires; int publish_expires; - SalOp *op; + LINPHONE_NAMESPACE::SalRegisterOp *op; SalCustomHeader *sent_headers; char *type; struct _SipSetupContext *ssctx; @@ -565,7 +567,7 @@ struct _LinphoneFriend{ void *user_data; LinphoneAddress *uri; MSList *insubs; /*list of SalOp. There can be multiple instances of a same Friend that subscribe to our presence*/ - SalOp *outsub; + LINPHONE_NAMESPACE::SalPresenceOp *outsub; LinphoneSubscribePolicy pol; MSList *presence_models; /* list of LinphoneFriendPresence. It associates SIP URIs and phone numbers with their respective presence models. */ MSList *phone_number_sip_uri_map; /* list of LinphoneFriendPhoneNumberSipUri. It associates phone numbers with their corresponding SIP URIs. */ @@ -803,7 +805,7 @@ struct _LinphoneCore MSFactory* factory; MSList* vtable_refs; int vtable_notify_recursion; - Sal *sal; + LINPHONE_NAMESPACE::Sal *sal; LinphoneGlobalState state; struct _LpConfig *config; MSList *default_audio_codecs; @@ -939,7 +941,7 @@ struct _LinphoneEvent{ LinphoneErrorInfo *ei; LinphoneSubscriptionDir dir; LinphoneCore *lc; - SalOp *op; + LINPHONE_NAMESPACE::SalEventOp *op; SalCustomHeader *send_custom_headers; LinphoneSubscriptionState subscription_state; LinphonePublishState publish_state; @@ -1053,7 +1055,7 @@ void _linphone_core_codec_config_write(LinphoneCore *lc); #endif #endif -LINPHONE_PUBLIC bctbx_list_t * call_logs_read_from_config_file(LinphoneCore *lc); +LINPHONE_PUBLIC bctbx_list_t * linphone_core_read_call_logs_from_config_file(LinphoneCore *lc); void call_logs_write_to_config_file(LinphoneCore *lc); void linphone_core_call_log_storage_init(LinphoneCore *lc); void linphone_core_call_log_storage_close(LinphoneCore *lc); @@ -1097,8 +1099,8 @@ belle_http_request_t * linphone_chat_message_get_http_request(const LinphoneChat void linphone_chat_message_set_http_request(LinphoneChatMessage *msg, belle_http_request_t *request); void linphone_chat_message_set_file_transfer_information(LinphoneChatMessage *msg, LinphoneContent *content); LinphoneChatMessageDir linphone_chat_message_get_direction(const LinphoneChatMessage *msg); -SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg); -void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, SalOp *op); +LINPHONE_NAMESPACE::SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg); +void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, LINPHONE_NAMESPACE::SalOp *op); void linphone_chat_message_destroy(LinphoneChatMessage* msg); void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state); void linphone_chat_message_set_is_secured(LinphoneChatMessage *msg, bool_t secured); @@ -1117,10 +1119,10 @@ void linphone_chat_message_send_imdn(LinphoneChatMessage *cm, ImdnType imdn_type void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID id); bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc); const char *linphone_core_create_uuid(LinphoneCore *lc); -void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact); -void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact, LinphoneProxyConfig *proxy); +void linphone_configure_op(LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact); +void linphone_configure_op_with_proxy(LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact, LinphoneProxyConfig *proxy); void linphone_call_create_op(LinphoneCall *call); -void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, SalBodyHandler *body); +void linphone_core_notify_info_message(LinphoneCore* lc,LINPHONE_NAMESPACE::SalOp *op, SalBodyHandler *body); LinphoneContent * linphone_content_new(void); LinphoneContent * linphone_content_copy(const LinphoneContent *ref); SalBodyHandler *sal_body_handler_from_content(const LinphoneContent *content); @@ -1128,12 +1130,12 @@ SalReason linphone_reason_to_sal(LinphoneReason reason); LinphoneReason linphone_reason_from_sal(SalReason reason); void linphone_error_info_to_sal(const LinphoneErrorInfo* ei, SalErrorInfo* sei); LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, int expires); -LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name); +LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, LINPHONE_NAMESPACE::SalEventOp *op, LinphoneSubscriptionDir dir, const char *name); void linphone_event_unpublish(LinphoneEvent *lev); /** * Useful for out of dialog notify * */ -LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name); +LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, LINPHONE_NAMESPACE::SalEventOp *op, LinphoneSubscriptionDir dir, const char *name); void linphone_event_set_internal(LinphoneEvent *lev, bool_t internal); bool_t linphone_event_is_internal(LinphoneEvent *lev); void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state); @@ -1247,174 +1249,6 @@ struct _LinphoneXmlRpcSession { BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneXmlRpcSession); -/***************************************************************************** - * Account creator interface * - ****************************************************************************/ - -struct _LinphoneAccountCreatorService { - belle_sip_object_t base; - void *user_data; - - LinphoneAccountCreatorRequestFunc account_creator_service_constructor_cb; /**< Constructor */ - LinphoneAccountCreatorRequestFunc account_creator_service_destructor_cb; /**< Destructor */ - - LinphoneAccountCreatorRequestFunc create_account_request_cb; /**< Request to create account */ - LinphoneAccountCreatorRequestFunc is_account_exist_request_cb; /**< Request to know if account exist */ - - LinphoneAccountCreatorRequestFunc activate_account_request_cb; /**< Request to activate account */ - LinphoneAccountCreatorRequestFunc is_account_activated_request_cb; /**< Request to know if account is activated */ - - LinphoneAccountCreatorRequestFunc link_account_request_cb; /**< Request to link account with an alias */ - LinphoneAccountCreatorRequestFunc activate_alias_request_cb; /**< Request to activate the link of alias */ - LinphoneAccountCreatorRequestFunc is_alias_used_request_cb; /**< Request to know if alias is used */ - LinphoneAccountCreatorRequestFunc is_account_linked_request_cb; /**< Request to know if account is linked with an alias */ - - LinphoneAccountCreatorRequestFunc recover_account_request_cb; /**< Request to recover account */ - LinphoneAccountCreatorRequestFunc update_account_request_cb; /**< Request to update account */ -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneAccountCreatorService); - -struct _LinphoneAccountCreatorCbs { - belle_sip_object_t base; - void *user_data; - - LinphoneAccountCreatorCbsStatusCb create_account_response_cb; /**< Response of create_account request */ - LinphoneAccountCreatorCbsStatusCb is_account_exist_response_cb; /**< Response of is_account_exist request */ - - LinphoneAccountCreatorCbsStatusCb activate_account_response_cb; /**< Response of activate_account request */ - LinphoneAccountCreatorCbsStatusCb is_account_activated_response_cb; /**< Response of is_account_activated request */ - - LinphoneAccountCreatorCbsStatusCb link_account_response_cb; /**< Response of link_account request */ - LinphoneAccountCreatorCbsStatusCb activate_alias_response_cb; /**< Response of activation alias */ - LinphoneAccountCreatorCbsStatusCb is_alias_used_response_cb; /**< Response of is_alias_used request */ - LinphoneAccountCreatorCbsStatusCb is_account_linked_response_cb; /**< Response of is_account_linked request */ - - LinphoneAccountCreatorCbsStatusCb recover_account_response_cb; /**< Response of recover_account request */ - LinphoneAccountCreatorCbsStatusCb update_account_response_cb; /**< Response of update_account request */ -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneAccountCreatorCbs); - -struct _LinphoneAccountCreator { - belle_sip_object_t base; - void *user_data; - LinphoneCore *core; - - /* AccountCreator */ - LinphoneAccountCreatorService *service; /**< Account creator service */ - LinphoneAccountCreatorCbs *cbs; /**< Account creator cbs */ - LinphoneXmlRpcSession *xmlrpc_session; /**< XML-RPC session */ - LinphoneProxyConfig *proxy_cfg; /**< Default proxy config */ - - /* User */ - char *username; /**< Username */ - char *display_name; /**< Display name */ - /* Password */ - char *password; /**< Plain text password */ - char *ha1; /**< Hash password */ - /* Phone Number(Alias) */ - char *phone_number; /**< User phone number*/ - char *phone_country_code; /**< User phone number country code */ - /* Email(Alias) */ - char *email; /**< User email */ - /* Misc */ - char *language; /**< User language */ - char *activation_code; /**< Account validation code */ - char *domain; /**< Domain */ - LinphoneTransportType transport; /**< Transport used */ - - /* Deprecated */ - char *route; -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneAccountCreator); - -/** - * Account creator custom to set Linphone default values - * @param[in] creator LinphoneAccountCreator object - * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise -**/ -LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_constructor_linphone(LinphoneAccountCreator *creator); - -/** - * Send an XML-RPC request to test the existence of a Linphone account. - * @param[in] creator LinphoneAccountCreator object - * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise -**/ -LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_is_account_exist_linphone(LinphoneAccountCreator *creator); - -/** - * Send an XML-RPC request to create a Linphone account. - * @param[in] creator LinphoneAccountCreator object - * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise -**/ -LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_create_account_linphone(LinphoneAccountCreator *creator); - -/** - * Send an XML-RPC request to activate a Linphone account with phone number. - * @param[in] creator LinphoneAccountCreator object - * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise -**/ -LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_activate_account_linphone(LinphoneAccountCreator *creator); - -/** - * Send an XML-RPC request to activate a Linphone account with email. - * @param[in] creator LinphoneAccountCreator object - * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise -**/ -LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_activate_email_account_linphone(LinphoneAccountCreator *creator); - -/** - * Send an XML-RPC request to test the validation of a Linphone account. - * @param[in] creator LinphoneAccountCreator object - * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise -**/ -LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_is_account_activated_linphone(LinphoneAccountCreator *creator); - -/** - * Send an XML-RPC request to test the existence a phone number with a Linphone account. - * @param[in] creator LinphoneAccountCreator object - * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise -**/ -LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_is_phone_number_used_linphone(LinphoneAccountCreator *creator); - -/** - * Send an XML-RPC request to link a phone number with a Linphone account. - * @param[in] creator LinphoneAccountCreator object - * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise -**/ -LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_link_phone_number_with_account_linphone(LinphoneAccountCreator *creator); - -/** - * Send an XML-RPC request to activate the link of a phone number with a Linphone account. - * @param[in] creator LinphoneAccountCreator object - * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise -**/ -LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_activate_phone_number_link_linphone(LinphoneAccountCreator *creator); - -/** - * Send an XML-RPC request to a Linphone account with the phone number. - * @param[in] creator LinphoneAccountCreator object - * @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise -**/ -LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_recover_phone_account_linphone(LinphoneAccountCreator *creator); - -/** - * Send an XML-RPC request to ask if an account is linked with a phone number - * @param[in] creator LinphoneAccountCreator object - * @return if this account is linked with a phone number -**/ -LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_is_account_linked_linphone(LinphoneAccountCreator *creator); - -/** - * Send an XML-RPC request to ask if an account is linked with a phone number - * @param[in] creator LinphoneAccountCreator object - * @param[in] new_pwd const char * : new password for the account creator - * @return LinphoneAccountCreatorStatusRequestOk if everything is OK, or a specific error otherwise. -**/ -LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_update_password_linphone(LinphoneAccountCreator *creator); - /***************************************************************************** * CardDAV interface * @@ -1524,7 +1358,7 @@ void linphone_xml_xpath_context_init_carddav_ns(xmlparsing_context_t *xml_ctx); char * linphone_timestamp_to_rfc3339_string(time_t timestamp); -void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const SalOp *op); +void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const LINPHONE_NAMESPACE::SalOp *op); void payload_type_set_enable(OrtpPayloadType *pt, bool_t value); bool_t payload_type_enabled(const OrtpPayloadType *pt); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index a74eefa0b..590b144e5 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -33,6 +33,8 @@ Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) #include "address/address-p.h" #include "c-wrapper/c-wrapper.h" +using namespace LINPHONE_NAMESPACE; + /*store current config related to server location*/ static void linphone_proxy_config_store_server_config(LinphoneProxyConfig* cfg) { if (cfg->saved_identity) linphone_address_unref(cfg->saved_identity); @@ -213,7 +215,7 @@ LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc) { void _linphone_proxy_config_release_ops(LinphoneProxyConfig *cfg){ if (cfg->op) { - sal_op_release(cfg->op); + cfg->op->release(); cfg->op=NULL; } if (cfg->presence_publish_event){ @@ -387,7 +389,7 @@ void linphone_proxy_config_enable_publish(LinphoneProxyConfig *cfg, bool_t val){ } void linphone_proxy_config_pause_register(LinphoneProxyConfig *cfg){ - if (cfg->op) sal_op_stop_refreshing(cfg->op); + if (cfg->op) cfg->op->stop_refreshing(); } void linphone_proxy_config_edit(LinphoneProxyConfig *cfg){ @@ -410,7 +412,7 @@ void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig * cfg){ LinphoneAddress *contact_addr = NULL; { const SalAddress *sal_addr = cfg->op && cfg->state == LinphoneRegistrationOk - ? sal_op_get_contact_address(cfg->op) + ? cfg->op->get_contact_address() : NULL; if (sal_addr) { char *buf = sal_address_as_string(sal_addr); @@ -435,7 +437,7 @@ void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig * cfg){ } if (cfg->op){ - sal_op_release(cfg->op); + cfg->op->release(); cfg->op=NULL; } } @@ -473,7 +475,7 @@ static void guess_contact_for_register (LinphoneProxyConfig *cfg) { void _linphone_proxy_config_unregister(LinphoneProxyConfig *obj) { if (obj->op && (obj->state == LinphoneRegistrationOk || (obj->state == LinphoneRegistrationProgress && obj->expires != 0))) { - sal_unregister(obj->op); + obj->op->unregister(); } } @@ -486,18 +488,17 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *cfg){ proxy_string=linphone_address_as_string_uri_only(proxy); linphone_address_unref(proxy); if (cfg->op) - sal_op_release(cfg->op); - cfg->op=sal_op_new(cfg->lc->sal); + cfg->op->release(); + cfg->op=new SalRegisterOp(cfg->lc->sal); linphone_configure_op(cfg->lc, cfg->op, cfg->identity_address, cfg->sent_headers, FALSE); guess_contact_for_register(cfg); if (cfg->contact_address) - sal_op_set_contact_address(cfg->op, L_GET_PRIVATE_FROM_C_OBJECT(cfg->contact_address)->getInternalAddress()); - sal_op_set_user_pointer(cfg->op, cfg); + cfg->op->set_contact_address(L_GET_PRIVATE_FROM_C_OBJECT(cfg->contact_address)->getInternalAddress()); + cfg->op->set_user_pointer(cfg); - if (sal_register( - cfg->op, + if (cfg->op->register_( proxy_string, cfg->reg_identity, cfg->expires, @@ -524,7 +525,7 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *cfg){ void linphone_proxy_config_refresh_register(LinphoneProxyConfig *cfg){ if (cfg->reg_sendregister && cfg->op && cfg->state!=LinphoneRegistrationProgress){ - if (sal_register_refresh(cfg->op,cfg->expires) == 0) { + if (cfg->op->register_refresh(cfg->expires) == 0) { linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress, "Refresh registration"); } } @@ -795,8 +796,8 @@ LinphoneStatus linphone_proxy_config_done(LinphoneProxyConfig *cfg) if (res == LinphoneProxyConfigAddressDifferent) { _linphone_proxy_config_unregister(cfg); } - sal_op_set_user_pointer(cfg->op,NULL); /*we don't want to receive status for this un register*/ - sal_op_unref(cfg->op); /*but we keep refresher to handle authentication if needed*/ + cfg->op->set_user_pointer(NULL); /*we don't want to receive status for this un register*/ + cfg->op->unref(); /*but we keep refresher to handle authentication if needed*/ cfg->op=NULL; } if (cfg->presence_publish_event) { @@ -989,7 +990,7 @@ struct _LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig const char *linphone_proxy_config_get_custom_header(LinphoneProxyConfig *cfg, const char *header_name){ const SalCustomHeader *ch; if (!cfg->op) return NULL; - ch = sal_op_get_recv_custom_header(cfg->op); + ch = cfg->op->get_recv_custom_header(); return sal_custom_header_find(ch, header_name); } @@ -1353,7 +1354,7 @@ const LinphoneErrorInfo *linphone_proxy_config_get_error_info(const LinphoneProx } const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg) { - return cfg->op?(const LinphoneAddress*) sal_op_get_service_route(cfg->op):NULL; + return cfg->op?(const LinphoneAddress*) cfg->op->get_service_route():NULL; } const char* linphone_proxy_config_get_transport(const LinphoneProxyConfig *cfg) { const char* addr=NULL; diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 2175baa07..fd2e393fd 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/core.h" #include "private.h" #include "sal/sal.h" +#include "sal/sal.hpp" #include "ortp/rtpsession.h" #include diff --git a/coreapi/sal.c b/coreapi/sal.c deleted file mode 100644 index 3870e59e3..000000000 --- a/coreapi/sal.c +++ /dev/null @@ -1,942 +0,0 @@ -/* -linphone -Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -/** -This file contains SAL API functions that do not depend on the underlying implementation (like belle-sip). -**/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "sal/sal.h" - - -#include - - -const char *sal_multicast_role_to_string(SalMulticastRole role){ - switch(role){ - case SalMulticastInactive: - return "inactive"; - case SalMulticastReceiver: - return "receiver"; - case SalMulticastSender: - return "sender"; - case SalMulticastSenderReceiver: - return "sender-receiver"; - } - return "INVALID"; -} - -const char* sal_transport_to_string(SalTransport transport) { - switch (transport) { - case SalTransportUDP:return "udp"; - case SalTransportTCP: return "tcp"; - case SalTransportTLS:return "tls"; - case SalTransportDTLS:return "dtls"; - default: { - ms_fatal("Unexpected transport [%i]",transport); - return NULL; - } - } -} - -SalTransport sal_transport_parse(const char* param) { - if (!param) return SalTransportUDP; - if (strcasecmp("udp",param)==0) return SalTransportUDP; - if (strcasecmp("tcp",param)==0) return SalTransportTCP; - if (strcasecmp("tls",param)==0) return SalTransportTLS; - if (strcasecmp("dtls",param)==0) return SalTransportDTLS; - ms_error("Unknown transport type[%s], returning UDP", param); - return SalTransportUDP; -} - -SalMediaDescription *sal_media_description_new(){ - SalMediaDescription *md=ms_new0(SalMediaDescription,1); - int i; - md->refcount=1; - for(i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { - md->streams[i].dir=SalStreamInactive; - md->streams[i].rtp_port = 0; - md->streams[i].rtcp_port = 0; - md->streams[i].haveZrtpHash = 0; - } - return md; -} - -static void sal_media_description_destroy(SalMediaDescription *md){ - int i; - for(i=0;istreams[i].payloads,(void (*)(void *))payload_type_destroy); - bctbx_list_free_with_data(md->streams[i].already_assigned_payloads,(void (*)(void *))payload_type_destroy); - md->streams[i].payloads=NULL; - md->streams[i].already_assigned_payloads=NULL; - sal_custom_sdp_attribute_free(md->streams[i].custom_sdp_attributes); - } - sal_custom_sdp_attribute_free(md->custom_sdp_attributes); - ms_free(md); -} - -SalMediaDescription * sal_media_description_ref(SalMediaDescription *md){ - md->refcount++; - return md; -} - -void sal_media_description_unref(SalMediaDescription *md){ - md->refcount--; - if (md->refcount==0){ - sal_media_description_destroy (md); - } -} - -SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, SalMediaProto proto, SalStreamType type){ - int i; - for(i=0;istreams[i]; - if (!sal_stream_description_active(ss)) continue; - if (ss->proto==proto && ss->type==type) return ss; - } - return NULL; -} - -unsigned int sal_media_description_nb_active_streams_of_type(SalMediaDescription *md, SalStreamType type) { - unsigned int i; - unsigned int nb = 0; - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i) { - if (!sal_stream_description_active(&md->streams[i])) continue; - if (md->streams[i].type == type) nb++; - } - return nb; -} - -SalStreamDescription * sal_media_description_get_active_stream_of_type(SalMediaDescription *md, SalStreamType type, unsigned int idx) { - unsigned int i; - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i) { - if (!sal_stream_description_active(&md->streams[i])) continue; - if (md->streams[i].type == type) { - if (idx-- == 0) return &md->streams[i]; - } - } - return NULL; -} - -SalStreamDescription * sal_media_description_find_secure_stream_of_type(SalMediaDescription *md, SalStreamType type) { - SalStreamDescription *desc = sal_media_description_find_stream(md, SalProtoRtpSavpf, type); - if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavp, type); - return desc; -} - -SalStreamDescription * sal_media_description_find_best_stream(SalMediaDescription *md, SalStreamType type) { - SalStreamDescription *desc = sal_media_description_find_stream(md, SalProtoUdpTlsRtpSavpf, type); - if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoUdpTlsRtpSavp, type); - if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavpf, type); - if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavp, type); - if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpAvpf, type); - if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpAvp, type); - return desc; -} - -bool_t sal_media_description_empty(const SalMediaDescription *md){ - if (sal_media_description_get_nb_active_streams(md) > 0) return FALSE; - return TRUE; -} - -void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir){ - int i; - for(i=0;istreams[i]; - if (!sal_stream_description_active(ss)) continue; - ss->dir=stream_dir; - } -} - -int sal_media_description_get_nb_active_streams(const SalMediaDescription *md) { - int i; - int nb = 0; - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { - if (sal_stream_description_active(&md->streams[i])) nb++; - } - return nb; -} - -static bool_t is_null_address(const char *addr){ - return strcmp(addr,"0.0.0.0")==0 || strcmp(addr,"::0")==0; -} - -/*check for the presence of at least one stream with requested direction */ -static bool_t has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){ - int i; - - /* we are looking for at least one stream with requested direction, inactive streams are ignored*/ - for(i=0;istreams[i]; - if (!sal_stream_description_active(ss)) continue; - if (ss->dir==stream_dir) { - return TRUE; - } - /*compatibility check for phones that only used the null address and no attributes */ - if (ss->dir==SalStreamSendRecv && stream_dir==SalStreamSendOnly && (is_null_address(md->addr) || is_null_address(ss->rtp_addr))){ - return TRUE; - } - } - return FALSE; -} - -bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){ - if (stream_dir==SalStreamRecvOnly){ - return has_dir(md, SalStreamRecvOnly) && !(has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv)); - }else if (stream_dir==SalStreamSendOnly){ - return has_dir(md, SalStreamSendOnly) && !(has_dir(md,SalStreamRecvOnly) || has_dir(md,SalStreamSendRecv)); - }else if (stream_dir==SalStreamSendRecv){ - return has_dir(md,SalStreamSendRecv); - }else{ - /*SalStreamInactive*/ - if (has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv) || has_dir(md,SalStreamRecvOnly)) - return FALSE; - else return TRUE; - } - return FALSE; -} - -bool_t sal_stream_description_active(const SalStreamDescription *sd) { - return (sd->rtp_port > 0); -} - -/*these are switch case, so that when a new proto is added we can't forget to modify this function*/ -bool_t sal_stream_description_has_avpf(const SalStreamDescription *sd) { - switch (sd->proto){ - case SalProtoRtpAvpf: - case SalProtoRtpSavpf: - case SalProtoUdpTlsRtpSavpf: - return TRUE; - case SalProtoRtpAvp: - case SalProtoRtpSavp: - case SalProtoUdpTlsRtpSavp: - case SalProtoOther: - return FALSE; - } - return FALSE; -} - -bool_t sal_stream_description_has_ipv6(const SalStreamDescription *sd){ - return strchr(sd->rtp_addr,':') != NULL; -} - -bool_t sal_stream_description_has_implicit_avpf(const SalStreamDescription *sd){ - return sd->implicit_rtcp_fb; -} -/*these are switch case, so that when a new proto is added we can't forget to modify this function*/ -bool_t sal_stream_description_has_srtp(const SalStreamDescription *sd) { - switch (sd->proto){ - case SalProtoRtpSavp: - case SalProtoRtpSavpf: - return TRUE; - case SalProtoRtpAvp: - case SalProtoRtpAvpf: - case SalProtoUdpTlsRtpSavpf: - case SalProtoUdpTlsRtpSavp: - case SalProtoOther: - return FALSE; - } - return FALSE; -} - -bool_t sal_stream_description_has_dtls(const SalStreamDescription *sd) { - switch (sd->proto){ - case SalProtoUdpTlsRtpSavpf: - case SalProtoUdpTlsRtpSavp: - return TRUE; - case SalProtoRtpSavp: - case SalProtoRtpSavpf: - case SalProtoRtpAvp: - case SalProtoRtpAvpf: - case SalProtoOther: - return FALSE; - } - return FALSE; -} - -bool_t sal_stream_description_has_zrtp(const SalStreamDescription *sd) { - if (sd->haveZrtpHash==1) return TRUE; - return FALSE; -} - -bool_t sal_media_description_has_avpf(const SalMediaDescription *md) { - int i; - if (md->nb_streams == 0) return FALSE; - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { - if (!sal_stream_description_active(&md->streams[i])) continue; - if (sal_stream_description_has_avpf(&md->streams[i]) != TRUE) return FALSE; - } - return TRUE; -} - -bool_t sal_media_description_has_implicit_avpf(const SalMediaDescription *md) { - int i; - if (md->nb_streams == 0) return FALSE; - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { - if (!sal_stream_description_active(&md->streams[i])) continue; - if (sal_stream_description_has_implicit_avpf(&md->streams[i]) != TRUE) return FALSE; - } - return TRUE; -} - -bool_t sal_media_description_has_srtp(const SalMediaDescription *md) { - int i; - if (md->nb_streams == 0) return FALSE; - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { - if (!sal_stream_description_active(&md->streams[i])) continue; - if (sal_stream_description_has_srtp(&md->streams[i]) != TRUE) return FALSE; - } - return TRUE; -} - -bool_t sal_media_description_has_dtls(const SalMediaDescription *md) { - int i; - if (md->nb_streams == 0) return FALSE; - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { - if (!sal_stream_description_active(&md->streams[i])) continue; - if (sal_stream_description_has_dtls(&md->streams[i]) != TRUE) return FALSE; - } - return TRUE; -} - -bool_t sal_media_description_has_zrtp(const SalMediaDescription *md) { - int i; - if (md->nb_streams == 0) return FALSE; - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { - if (!sal_stream_description_active(&md->streams[i])) continue; - if (sal_stream_description_has_zrtp(&md->streams[i]) != TRUE) return FALSE; - } - return TRUE; -} - -bool_t sal_media_description_has_ipv6(const SalMediaDescription *md){ - int i; - if (md->nb_streams == 0) return FALSE; - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { - if (!sal_stream_description_active(&md->streams[i])) continue; - if (md->streams[i].rtp_addr[0] != '\0'){ - if (!sal_stream_description_has_ipv6(&md->streams[i])) return FALSE; - }else{ - if (strchr(md->addr,':') == NULL) return FALSE; - } - } - return TRUE; -} - -/* -static bool_t fmtp_equals(const char *p1, const char *p2){ - if (p1 && p2 && strcmp(p1,p2)==0) return TRUE; - if (p1==NULL && p2==NULL) return TRUE; - return FALSE; -} -*/ - -static bool_t payload_type_equals(const PayloadType *p1, const PayloadType *p2){ - if (p1->type!=p2->type) return FALSE; - if (strcmp(p1->mime_type,p2->mime_type)!=0) return FALSE; - if (p1->clock_rate!=p2->clock_rate) return FALSE; - if (p1->channels!=p2->channels) return FALSE; - if (payload_type_get_number(p1) != payload_type_get_number(p2)) return FALSE; - /* - Do not compare fmtp right now: they are modified internally when the call is started - */ - /* - if (!fmtp_equals(p1->recv_fmtp,p2->recv_fmtp) || - !fmtp_equals(p1->send_fmtp,p2->send_fmtp)) - return FALSE; - */ - return TRUE; -} - -static bool_t is_recv_only(PayloadType *p){ - return (p->flags & PAYLOAD_TYPE_FLAG_CAN_RECV) && ! (p->flags & PAYLOAD_TYPE_FLAG_CAN_SEND); -} - -static bool_t payload_list_equals(const bctbx_list_t *l1, const bctbx_list_t *l2){ - const bctbx_list_t *e1,*e2; - for(e1=l1,e2=l2;e1!=NULL && e2!=NULL; e1=e1->next,e2=e2->next){ - PayloadType *p1=(PayloadType*)e1->data; - PayloadType *p2=(PayloadType*)e2->data; - if (!payload_type_equals(p1,p2)) - return FALSE; - } - if (e1!=NULL){ - /*skip possible recv-only payloads*/ - for(;e1!=NULL && is_recv_only((PayloadType*)e1->data);e1=e1->next){ - ms_message("Skipping recv-only payload type..."); - } - } - if (e1!=NULL || e2!=NULL){ - /*means one list is longer than the other*/ - return FALSE; - } - return TRUE; -} - -int sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2) { - int result = SAL_MEDIA_DESCRIPTION_UNCHANGED; - int i; - - /* A different proto should result in SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED but the encryption change - needs a stream restart for now, so use SAL_MEDIA_DESCRIPTION_CODEC_CHANGED */ - if (sd1->proto != sd2->proto) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; - for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) { - if ((sd1->crypto[i].tag != sd2->crypto[i].tag) - || (sd1->crypto[i].algo != sd2->crypto[i].algo)){ - result|=SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED; - } - if ((strncmp(sd1->crypto[i].master_key, sd2->crypto[i].master_key, sizeof(sd1->crypto[i].master_key) - 1))) { - result |= SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED; - } - } - - if (sd1->type != sd2->type) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; - if (strcmp(sd1->rtp_addr, sd2->rtp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; - if (sd1->rtp_addr[0]!='\0' && sd2->rtp_addr[0]!='\0' && ms_is_multicast(sd1->rtp_addr) != ms_is_multicast(sd2->rtp_addr)) - result |= SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED; - if (sd1->rtp_port != sd2->rtp_port) { - if ((sd1->rtp_port == 0) || (sd2->rtp_port == 0)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; - else result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; - } - if (strcmp(sd1->rtcp_addr, sd2->rtcp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; - if (sd1->rtcp_port != sd2->rtcp_port) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; - if (!payload_list_equals(sd1->payloads, sd2->payloads)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; - if (sd1->bandwidth != sd2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; - if (sd1->ptime != sd2->ptime) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; - if (sd1->dir != sd2->dir) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; - - /* ICE */ - if (strcmp(sd1->ice_ufrag, sd2->ice_ufrag) != 0) result |= SAL_MEDIA_DESCRIPTION_ICE_RESTART_DETECTED; - if (strcmp(sd1->ice_pwd, sd2->ice_pwd) != 0) result |= SAL_MEDIA_DESCRIPTION_ICE_RESTART_DETECTED; - - /*DTLS*/ - if (sd1->dtls_role != sd2->dtls_role) result |= SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED; - if (strcmp(sd1->dtls_fingerprint, sd2->dtls_fingerprint) != 0) result |= SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED; - - return result; -} - -char * sal_media_description_print_differences(int result){ - char *out = NULL; - if (result & SAL_MEDIA_DESCRIPTION_CODEC_CHANGED){ - out = ms_strcat_printf(out, "%s ", "CODEC_CHANGED"); - result &= ~SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; - } - if (result & SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED){ - out = ms_strcat_printf(out, "%s ", "NETWORK_CHANGED"); - result &= ~SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; - } - if (result & SAL_MEDIA_DESCRIPTION_ICE_RESTART_DETECTED){ - out = ms_strcat_printf(out, "%s ", "ICE_RESTART_DETECTED"); - result &= ~SAL_MEDIA_DESCRIPTION_ICE_RESTART_DETECTED; - } - if (result & SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED){ - out = ms_strcat_printf(out, "%s ", "CRYPTO_KEYS_CHANGED"); - result &= ~SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED; - } - if (result & SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED){ - out = ms_strcat_printf(out, "%s ", "NETWORK_XXXCAST_CHANGED"); - result &= ~SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED; - } - if (result & SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED){ - out = ms_strcat_printf(out, "%s ", "STREAMS_CHANGED"); - result &= ~SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED; - } - if (result & SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED){ - out = ms_strcat_printf(out, "%s ", "CRYPTO_POLICY_CHANGED"); - result &= ~SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED; - } - if (result & SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION){ - out = ms_strcat_printf(out, "%s ", "FORCE_STREAM_RECONSTRUCTION"); - result &= ~SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION; - } - if (result){ - ms_fatal("There are unhandled result bitmasks in sal_media_description_print_differences(), fix it"); - } - if (!out) out = ms_strdup("NONE"); - return out; -} - -int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2) { - int result = SAL_MEDIA_DESCRIPTION_UNCHANGED; - int i; - - if (strcmp(md1->addr, md2->addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; - if (md1->addr[0]!='\0' && md2->addr[0]!='\0' && ms_is_multicast(md1->addr) != ms_is_multicast(md2->addr)) - result |= SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED; - if (md1->nb_streams != md2->nb_streams) result |= SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED; - if (md1->bandwidth != md2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; - - /* ICE */ - if (strcmp(md1->ice_ufrag, md2->ice_ufrag) != 0) result |= SAL_MEDIA_DESCRIPTION_ICE_RESTART_DETECTED; - if (strcmp(md1->ice_pwd, md2->ice_pwd) != 0) result |= SAL_MEDIA_DESCRIPTION_ICE_RESTART_DETECTED; - - for(i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i){ - if (!sal_stream_description_active(&md1->streams[i]) && !sal_stream_description_active(&md2->streams[i])) continue; - result |= sal_stream_description_equals(&md1->streams[i], &md2->streams[i]); - } - return result; -} - -static void assign_address(SalAddress** address, const char *value){ - if (*address){ - sal_address_destroy(*address); - *address=NULL; - } - if (value) - *address=sal_address_new(value); -} - -static void assign_string(char **str, const char *arg){ - if (*str){ - ms_free(*str); - *str=NULL; - } - if (arg) - *str=ms_strdup(arg); -} - -void sal_op_set_contact_address(SalOp *op, const SalAddress *address){ - if (((SalOpBase*)op)->contact_address) sal_address_destroy(((SalOpBase*)op)->contact_address); - ((SalOpBase*)op)->contact_address=address?sal_address_clone(address):NULL; -} - -void sal_op_set_and_clean_contact_address(SalOp *op, SalAddress *contact) { - if (contact){ - SalTransport tport = sal_address_get_transport((SalAddress*)contact); - const char* gruu = bctbx_strdup(sal_address_get_uri_param(contact, "gr")); - sal_address_clean((SalAddress*)contact); /* clean out contact_params that come from proxy config*/ - sal_address_set_transport((SalAddress*)contact,tport); - if(gruu) - sal_address_set_uri_param(contact, "gr", gruu); - sal_op_set_contact_address(op, contact); - sal_address_unref(contact); - } -} - -const SalAddress* sal_op_get_contact_address(const SalOp *op) { - return ((SalOpBase*)op)->contact_address; -} - -const SalAddress*sal_op_get_remote_contact_address(const SalOp* op) -{ - return ((SalOpBase*)op)->remote_contact_address; -} - -#define SET_PARAM(op,name) \ - char* name##_string=NULL; \ - assign_address(&((SalOpBase*)op)->name##_address,name); \ - if (((SalOpBase*)op)->name##_address) { \ - name##_string=sal_address_as_string(((SalOpBase*)op)->name##_address); \ - }\ - assign_string(&((SalOpBase*)op)->name,name##_string); \ - if(name##_string) ms_free(name##_string); - - -void sal_op_set_route(SalOp *op, const char *route){ - char* route_string=NULL; - SalOpBase* op_base = (SalOpBase*)op; - if (op_base->route_addresses) { - bctbx_list_for_each(op_base->route_addresses,(void (*)(void *))sal_address_destroy); - op_base->route_addresses=bctbx_list_free(op_base->route_addresses); - } - if (route) { - op_base->route_addresses=bctbx_list_append(NULL,NULL); - assign_address((SalAddress**)&(op_base->route_addresses->data),route); - route_string=sal_address_as_string((SalAddress*)op_base->route_addresses->data); \ - } - assign_string(&op_base->route,route_string); \ - if(route_string) ms_free(route_string); -} -const bctbx_list_t* sal_op_get_route_addresses(const SalOp *op) { - return ((SalOpBase*)op)->route_addresses; -} -void sal_op_set_route_address(SalOp *op, const SalAddress *address){ - char* address_string=sal_address_as_string(address); /*can probably be optimized*/ - sal_op_set_route(op,address_string); - ms_free(address_string); -} -void sal_op_add_route_address(SalOp *op, const SalAddress *address){ - SalOpBase* op_base = (SalOpBase*)op; - if (op_base->route_addresses) { - op_base->route_addresses=bctbx_list_append(op_base->route_addresses,(void*)sal_address_clone(address)); - } else { - sal_op_set_route_address(op,address); - } -} -void sal_op_set_realm(SalOp *op, const char *realm){ - SalOpBase* op_base = (SalOpBase*)op; - if (op_base->realm != NULL){ - ms_free(op_base->realm); - } - op_base->realm = ms_strdup(realm); -} -void sal_op_set_from(SalOp *op, const char *from){ - SET_PARAM(op,from); -} -void sal_op_set_from_address(SalOp *op, const SalAddress *from){ - char* address_string=sal_address_as_string(from); /*can probably be optimized*/ - sal_op_set_from(op,address_string); - ms_free(address_string); -} -void sal_op_set_to(SalOp *op, const char *to){ - SET_PARAM(op,to); -} -void sal_op_set_to_address(SalOp *op, const SalAddress *to){ - char* address_string=sal_address_as_string(to); /*can probably be optimized*/ - sal_op_set_to(op,address_string); - ms_free(address_string); -} -void sal_op_set_diversion_address(SalOp *op, const SalAddress *diversion){ - if (((SalOpBase*)op)->diversion_address) sal_address_destroy(((SalOpBase*)op)->diversion_address); - ((SalOpBase*)op)->diversion_address=diversion?sal_address_clone(diversion):NULL; -} -void sal_op_set_user_pointer(SalOp *op, void *up){ - ((SalOpBase*)op)->user_pointer=up; -} - -Sal *sal_op_get_sal(const SalOp *op){ - return ((SalOpBase*)op)->root; -} - -const char *sal_op_get_from(const SalOp *op){ - return ((SalOpBase*)op)->from; -} -const SalAddress *sal_op_get_from_address(const SalOp *op){ - return ((SalOpBase*)op)->from_address; -} - -const char *sal_op_get_to(const SalOp *op){ - return ((SalOpBase*)op)->to; -} - -const SalAddress *sal_op_get_to_address(const SalOp *op){ - return ((SalOpBase*)op)->to_address; -} - -const SalAddress *sal_op_get_diversion_address(const SalOp *op){ - return ((SalOpBase*)op)->diversion_address; -} - -const char *sal_op_get_remote_ua(const SalOp *op){ - return ((SalOpBase*)op)->remote_ua; -} - -void *sal_op_get_user_pointer(const SalOp *op){ - return ((SalOpBase*)op)->user_pointer; -} - -const char *sal_op_get_proxy(const SalOp *op){ - return ((SalOpBase*)op)->route; -} - -const char *sal_op_get_network_origin(const SalOp *op){ - return ((SalOpBase*)op)->origin; -} -const char* sal_op_get_call_id(const SalOp *op) { - return ((SalOpBase*)op)->call_id; -} - -void __sal_op_init(SalOp *b, Sal *sal){ - memset(b,0,sizeof(SalOpBase)); - ((SalOpBase*)b)->root=sal; -} - -void __sal_op_set_network_origin(SalOp *op, const char *origin){ - SET_PARAM(op,origin); -} - -void __sal_op_set_remote_contact(SalOp *op, const char* remote_contact){ - assign_address(&((SalOpBase*)op)->remote_contact_address,remote_contact);\ - /*to preserve header params*/ - assign_string(&((SalOpBase*)op)->remote_contact,remote_contact); \ -} - -void __sal_op_set_network_origin_address(SalOp *op, SalAddress *origin){ - char* address_string=sal_address_as_string(origin); /*can probably be optimized*/ - __sal_op_set_network_origin(op,address_string); - ms_free(address_string); -} - -void __sal_op_free(SalOp *op){ - SalOpBase *b=(SalOpBase *)op; - if (b->from_address){ - sal_address_destroy(b->from_address); - b->from_address=NULL; - } - if (b->to_address){ - sal_address_destroy(b->to_address); - b->to_address=NULL; - } - - if (b->service_route){ - sal_address_destroy(b->service_route); - b->service_route=NULL; - } - - if (b->origin_address){ - sal_address_destroy(b->origin_address); - b->origin_address=NULL; - } - - if (b->from) { - ms_free(b->from); - b->from=NULL; - } - if (b->to) { - ms_free(b->to); - b->to=NULL; - } - if (b->route) { - ms_free(b->route); - b->route=NULL; - } - if (b->realm) { - ms_free(b->realm); - b->realm=NULL; - } - if (b->contact_address) { - sal_address_destroy(b->contact_address); - } - if (b->origin){ - ms_free(b->origin); - b->origin=NULL; - } - if (b->remote_ua){ - ms_free(b->remote_ua); - b->remote_ua=NULL; - } - if (b->remote_contact){ - ms_free(b->remote_contact); - b->remote_contact=NULL; - } - if (b->remote_contact_address){ - sal_address_destroy(b->remote_contact_address); - } - if (b->local_media) - sal_media_description_unref(b->local_media); - if (b->remote_media) - sal_media_description_unref(b->remote_media); - if (b->call_id) - ms_free((void*)b->call_id); - if (b->service_route) { - sal_address_destroy(b->service_route); - } - if (b->route_addresses){ - bctbx_list_for_each(b->route_addresses,(void (*)(void*)) sal_address_destroy); - b->route_addresses=bctbx_list_free(b->route_addresses); - } - if (b->recv_custom_headers) - sal_custom_header_free(b->recv_custom_headers); - if (b->sent_custom_headers) - sal_custom_header_free(b->sent_custom_headers); - - if (b->entity_tag != NULL){ - ms_free(b->entity_tag); - b->entity_tag = NULL; - } - ms_free(op); -} - -SalAuthInfo* sal_auth_info_new() { - return ms_new0(SalAuthInfo,1); -} - -SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info) { - SalAuthInfo* new_auth_info=sal_auth_info_new(); - new_auth_info->username=auth_info->username?ms_strdup(auth_info->username):NULL; - new_auth_info->userid=auth_info->userid?ms_strdup(auth_info->userid):NULL; - new_auth_info->realm=auth_info->realm?ms_strdup(auth_info->realm):NULL; - new_auth_info->domain=auth_info->realm?ms_strdup(auth_info->domain):NULL; - new_auth_info->password=auth_info->password?ms_strdup(auth_info->password):NULL; - return new_auth_info; -} - -void sal_auth_info_delete(SalAuthInfo* auth_info) { - if (auth_info->username) ms_free(auth_info->username); - if (auth_info->userid) ms_free(auth_info->userid); - if (auth_info->realm) ms_free(auth_info->realm); - if (auth_info->domain) ms_free(auth_info->domain); - if (auth_info->password) ms_free(auth_info->password); - if (auth_info->ha1) ms_free(auth_info->ha1); - if (auth_info->certificates) sal_certificates_chain_delete(auth_info->certificates); - if (auth_info->key) sal_signing_key_delete(auth_info->key); - ms_free(auth_info); -} - - - -const char* sal_stream_type_to_string(SalStreamType type) { - switch (type) { - case SalAudio: return "audio"; - case SalVideo: return "video"; - case SalText: return "text"; - default: return "other"; - } -} - -const char *sal_stream_description_get_type_as_string(const SalStreamDescription *desc){ - if (desc->type==SalOther) return desc->typeother; - else return sal_stream_type_to_string(desc->type); -} - -const char* sal_media_proto_to_string(SalMediaProto type) { - switch (type) { - case SalProtoRtpAvp:return "RTP/AVP"; - case SalProtoRtpSavp:return "RTP/SAVP"; - case SalProtoUdpTlsRtpSavp:return "UDP/TLS/RTP/SAVP"; - case SalProtoRtpAvpf:return "RTP/AVPF"; - case SalProtoRtpSavpf:return "RTP/SAVPF"; - case SalProtoUdpTlsRtpSavpf:return "UDP/TLS/RTP/SAVPF"; - default: return "unknown"; - } -} - -const char *sal_stream_description_get_proto_as_string(const SalStreamDescription *desc){ - if (desc->proto==SalProtoOther) return desc->proto_other; - else return sal_media_proto_to_string(desc->proto); -} - - -const char* sal_stream_dir_to_string(SalStreamDir type) { - switch (type) { - case SalStreamSendRecv:return "sendrecv"; - case SalStreamSendOnly:return "sendonly"; - case SalStreamRecvOnly:return "recvonly"; - case SalStreamInactive:return "inative"; - default: return "unknown"; - } - -} - -const char* sal_reason_to_string(const SalReason reason) { - switch (reason) { - case SalReasonDeclined : return "SalReasonDeclined"; - case SalReasonBusy: return "SalReasonBusy"; - case SalReasonRedirect: return "SalReasonRedirect"; - case SalReasonTemporarilyUnavailable: return "SalReasonTemporarilyUnavailable"; - case SalReasonNotFound: return "SalReasonNotFound"; - case SalReasonDoNotDisturb: return "SalReasonDoNotDisturb"; - case SalReasonUnsupportedContent: return "SalReasonUnsupportedContent"; - case SalReasonForbidden: return "SalReasonForbidden"; - case SalReasonUnknown: return "SalReasonUnknown"; - case SalReasonServiceUnavailable: return "SalReasonServiceUnavailable"; - case SalReasonNotAcceptable: return "SalReasonNotAcceptable"; - default: return "Unkown reason"; - } -} -const SalAddress* sal_op_get_service_route(const SalOp *op) { - return ((SalOpBase*)op)->service_route; -} -void sal_op_set_service_route(SalOp *op,const SalAddress* service_route) { - if (((SalOpBase*)op)->service_route) - sal_address_destroy(((SalOpBase*)op)->service_route); - - ((SalOpBase*)op)->service_route=service_route?sal_address_clone(service_route):NULL; -} - -const char* sal_presence_status_to_string(const SalPresenceStatus status) { - switch (status) { - case SalPresenceOffline: return "SalPresenceOffline"; - case SalPresenceOnline: return "SalPresenceOnline"; - case SalPresenceBusy: return "SalPresenceBusy"; - case SalPresenceBerightback: return "SalPresenceBerightback"; - case SalPresenceAway: return "SalPresenceAway"; - case SalPresenceOnthephone: return "SalPresenceOnthephone"; - case SalPresenceOuttolunch: return "SalPresenceOuttolunch"; - case SalPresenceDonotdisturb: return "SalPresenceDonotdisturb"; - case SalPresenceMoved: return "SalPresenceMoved"; - case SalPresenceAltService: return "SalPresenceAltService"; - default : return "unknown"; - } - -} -const char* sal_privacy_to_string(SalPrivacy privacy) { - switch(privacy) { - case SalPrivacyUser: return "user"; - case SalPrivacyHeader: return "header"; - case SalPrivacySession: return "session"; - case SalPrivacyId: return "id"; - case SalPrivacyNone: return "none"; - case SalPrivacyCritical: return "critical"; - default: return NULL; - } -} - -static void remove_trailing_spaces(char *line) { - size_t size = strlen(line); - char *end = line + size - 1; - while (end >= line && isspace(*end)) { - end--; - } - *(end + 1) = '\0'; -} - -static int line_get_value(const char *input, const char *key, char *value, size_t value_size, size_t *read){ - const char *end=strchr(input,'\n'); - char line[256]={0}; - char key_candidate[256]; - char *equal; - size_t len; - if (!end) len=strlen(input); - else len=end +1 -input; - *read=len; - strncpy(line,input,MIN(len,sizeof(line))); - equal=strchr(line,'='); - if (!equal) return FALSE; - *equal='\0'; - if (sscanf(line,"%s",key_candidate)!=1) return FALSE; - if (strcasecmp(key,key_candidate)==0){ - equal++; - remove_trailing_spaces(equal); - strncpy(value,equal,value_size-1); - value[value_size-1]='\0'; - return TRUE; - } - return FALSE; -} - -int sal_lines_get_value(const char *data, const char *key, char *value, size_t value_size){ - size_t read=0; - - do{ - if (line_get_value(data,key,value,value_size,&read)) - return TRUE; - data+=read; - }while(read!=0); - return FALSE; -} - -const char *sal_op_get_entity_tag(const SalOp* op) { - SalOpBase* op_base = (SalOpBase*)op; - return op_base->entity_tag; -} - - -void sal_op_set_entity_tag(SalOp *op, const char* entity_tag) { - SalOpBase* op_base = (SalOpBase*)op; - if (op_base->entity_tag != NULL){ - ms_free(op_base->entity_tag); - } - if (entity_tag) - op_base->entity_tag = ms_strdup(entity_tag); - else - op_base->entity_tag = NULL; -} diff --git a/coreapi/sal/call_op.cpp b/coreapi/sal/call_op.cpp new file mode 100644 index 000000000..aa7ecf193 --- /dev/null +++ b/coreapi/sal/call_op.cpp @@ -0,0 +1,1475 @@ +#include "call_op.h" +#include "bellesip_sal/sal_impl.h" +#include "offeranswer.h" +#include +#include + +using namespace std; + +#define SIP_MESSAGE_BODY_LIMIT 16*1024 // 16kB + +LINPHONE_BEGIN_NAMESPACE + +int SalCallOp::set_local_media_description(SalMediaDescription *desc) { + if (this->custom_body) { + bctbx_error("cannot set local media description on SalOp [%p] because a custom body is already set", this); + return -1; + } + + if (desc) sal_media_description_ref(desc); + if (this->local_media) sal_media_description_unref(this->local_media); + this->local_media=desc; + + if (this->remote_media){ + /*case of an incoming call where we modify the local capabilities between the time + * the call is ringing and it is accepted (for example if you want to accept without video*/ + /*reset the sdp answer so that it is computed again*/ + if (this->sdp_answer){ + belle_sip_object_unref(this->sdp_answer); + this->sdp_answer=NULL; + } + } + return 0; +} + +int SalCallOp::set_local_custom_body(SalCustomBody *body) { + if (this->local_media) { + bctbx_error("cannot set custom body on SalOp [%p] because a local media description is already set", this); + return -1; + } + if (this->custom_body) sal_custom_body_unref(this->custom_body); + this->custom_body = sal_custom_body_ref(body ? body : NULL); + return 0; +} + +belle_sip_header_allow_t *SalCallOp::create_allow(bool_t enable_update) { + belle_sip_header_allow_t* header_allow; + char allow [256]; + snprintf(allow,sizeof(allow),"INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO%s",(enable_update?", UPDATE":"")); + header_allow = belle_sip_header_allow_create(allow); + return header_allow; +} + +int SalCallOp::set_custom_body(belle_sip_message_t *msg, const SalCustomBody *body) { + if (body->data_length > SIP_MESSAGE_BODY_LIMIT) { + bctbx_error("trying to add a body greater than %dkB to message [%p]", SIP_MESSAGE_BODY_LIMIT/1024, msg); + return -1; + } + if (body->data_length == 0 || body->raw_data == NULL) { + bctbx_error("trying to add an empty custom body to message [%p]", msg); + return -1; + } + + belle_sip_header_content_type_t *content_type = belle_sip_header_content_type_create(body->type->type, body->type->subtype); + belle_sip_header_content_length_t *content_length = belle_sip_header_content_length_create(body->data_length); + belle_sip_message_add_header(msg, BELLE_SIP_HEADER(content_type)); + belle_sip_message_add_header(msg, BELLE_SIP_HEADER(content_length)); + + char *buffer = bctbx_new(char, body->data_length); + memcpy(buffer, body->raw_data, body->data_length); + belle_sip_message_assign_body(msg, buffer, body->data_length); + + return 0; +} + +int SalCallOp::set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* session_desc) { + belle_sip_error_code error = BELLE_SIP_BUFFER_OVERFLOW; + size_t length = 0; + + if (session_desc == NULL) return -1; + + size_t bufLen = 2048; + char *buff = reinterpret_cast(belle_sip_malloc(bufLen)); + + /* try to marshal the description. This could go higher than 2k so we iterate */ + while( error != BELLE_SIP_OK && bufLen <= SIP_MESSAGE_BODY_LIMIT && buff != NULL){ + error = belle_sip_object_marshal(BELLE_SIP_OBJECT(session_desc),buff,bufLen,&length); + if( error != BELLE_SIP_OK ){ + bufLen *= 2; + length = 0; + buff = reinterpret_cast(belle_sip_realloc(buff,bufLen)); + } + } + /* give up if hard limit reached */ + if (error != BELLE_SIP_OK || buff == NULL) { + ms_error("Buffer too small (%d) or not enough memory, giving up SDP", (int)bufLen); + return -1; + } + + SalMimeType *mimetype = sal_mime_type_new("application", "sdp"); + SalCustomBody *body = sal_custom_body_new_with_buffer_moving(mimetype, buff, length); + set_custom_body(msg, body); + sal_custom_body_unref(body); + + return 0; +} + +int SalCallOp::set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription *desc) { + int err; + belle_sdp_session_description_t *sdp=media_description_to_sdp(desc); + err=set_sdp(msg,sdp); + belle_sip_object_unref(sdp); + return err; + +} + +void SalCallOp::fill_invite(belle_sip_request_t* invite) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(create_allow(this->root->enable_sip_update))); + + if (this->root->session_expires!=0){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Session-expires", "600;refresher=uas")); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Supported", "timer")); + } + if (this->local_media){ + this->sdp_offering=TRUE; + set_sdp_from_desc(BELLE_SIP_MESSAGE(invite),this->local_media); + } else this->sdp_offering=FALSE; + if (this->custom_body) { + set_custom_body(BELLE_SIP_MESSAGE(invite), this->custom_body); + } +} + +void SalCallOp::set_released() { + if (!this->call_released){ + this->state=State::Terminated; + this->root->callbacks.call_released(this); + this->call_released=TRUE; + /*be aware that the following line may destroy the op*/ + set_or_update_dialog(NULL); + } +} + +void SalCallOp::process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event) { + SalCallOp *op = (SalCallOp *)user_ctx; + + if (op->state == State::Terminated) return; + + if (op->pending_client_trans && (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(op->pending_client_trans)) == BELLE_SIP_TRANSACTION_INIT)) { + + sal_error_info_set(&op->error_info, SalReasonIOError, "SIP", 503, "IO error", NULL); + op->root->callbacks.call_failure(op); + + if (!op->dialog || belle_sip_dialog_get_state(op->dialog) != BELLE_SIP_DIALOG_CONFIRMED){ + /* Call terminated very very early, before INVITE is even sent, probably DNS resolution timeout. */ + op->state = State::Terminating; + op->set_released(); + } + } else { + /* Nothing to be done. If the error comes from a connectivity loss, + * the call will be marked as broken, and an attempt to repair it will be done. */ + } +} + +void SalCallOp::cancelling_invite(const SalErrorInfo *info) { + cancel_invite_with_info(info); + this->state=State::Terminating; +} + +SalCustomBody *SalCallOp::extract_body(belle_sip_message_t *message) { + const char *body_str = belle_sip_message_get_body(message); + belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(message, belle_sip_header_content_type_t); + belle_sip_header_content_length_t *content_length = belle_sip_message_get_header_by_type(message, belle_sip_header_content_length_t); + if (!(body_str && content_type && content_length)) return NULL; + const char *type_str = belle_sip_header_content_type_get_type(content_type); + const char *subtype_str = belle_sip_header_content_type_get_subtype(content_type); + size_t length = belle_sip_header_content_length_get_content_length(content_length); + SalMimeType *mime_type = sal_mime_type_new(type_str, subtype_str); + SalCustomBody *body = sal_custom_body_new_with_buffer_copy(mime_type, body_str, length); + return body; +} + +int SalCallOp::extract_sdp(belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error) { + *session_desc = NULL; + *error = SalReasonNone; + + if (this->sdp_handling == SalOpSDPSimulateError) { + ms_error("Simulating SDP parsing error for op %p", this); + *error = SalReasonNotAcceptable; + return -1; + } + + if (this->sdp_handling == SalOpSDPSimulateRemove) { + ms_error("Simulating no SDP for op %p", this); + return 0; + } + + SalCustomBody *body = extract_body(message); + if (body == NULL) return 0; + + if (strcmp("application", body->type->type) != 0 || strcmp("sdp", body->type->subtype) != 0) { + sal_custom_body_unref(body); + *error = SalReasonUnsupportedContent; + return -1; + } + + *session_desc = belle_sdp_session_description_parse(string(body->raw_data, body->data_length).c_str()); + sal_custom_body_unref(body); + + if (*session_desc == NULL) { + ms_error("Failed to parse SDP message."); + *error = SalReasonNotAcceptable; + return -1; + } + + return 0; +} + +void SalCallOp::set_addr_to_0000(char value[], size_t sz) { + if (ms_is_ipv6(value)) { + strncpy(value,"::0", sz); + } else { + strncpy(value,"0.0.0.0", sz); + } + return; +} + +void SalCallOp::sdp_process(){ + ms_message("Doing SDP offer/answer process of type %s", this->sdp_offering ? "outgoing" : "incoming"); + if (this->result){ + sal_media_description_unref(this->result); + this->result = NULL; + } + + /* if SDP was invalid */ + if (this->remote_media == NULL) return; + + this->result=sal_media_description_new(); + if (this->sdp_offering){ + offer_answer_initiate_outgoing(this->root->factory, this->local_media,this->remote_media,this->result); + }else{ + int i; + if (this->sdp_answer){ + belle_sip_object_unref(this->sdp_answer); + } + offer_answer_initiate_incoming(this->root->factory, this->local_media,this->remote_media,this->result,this->root->one_matching_codec); + /*for backward compatibility purpose*/ + if(this->_cnx_ip_to_0000_if_sendonly_enabled && sal_media_description_has_dir(this->result,SalStreamSendOnly)) { + set_addr_to_0000(this->result->addr, sizeof(this->result->addr)); + for(i=0;iresult->streams[i].dir == SalStreamSendOnly) { + set_addr_to_0000(this->result->streams[i].rtp_addr, sizeof(this->result->streams[i].rtp_addr)); + set_addr_to_0000(this->result->streams[i].rtcp_addr, sizeof(this->result->streams[i].rtcp_addr)); + } + } + } + + this->sdp_answer=(belle_sdp_session_description_t *)belle_sip_object_ref(media_description_to_sdp(this->result)); + /*once we have generated the SDP answer, we modify the result description for processing by the upper layer. + It should contains media parameters constraint from the remote offer, not our response*/ + strcpy(this->result->addr,this->remote_media->addr); + this->result->bandwidth=this->remote_media->bandwidth; + + for(i=0;iresult->streams[i].rtp_port!=0){ /*if stream was accepted*/ + strcpy(this->result->streams[i].rtp_addr,this->remote_media->streams[i].rtp_addr); + this->result->streams[i].ptime=this->remote_media->streams[i].ptime; + this->result->streams[i].bandwidth=this->remote_media->streams[i].bandwidth; + this->result->streams[i].rtp_port=this->remote_media->streams[i].rtp_port; + strcpy(this->result->streams[i].rtcp_addr,this->remote_media->streams[i].rtcp_addr); + this->result->streams[i].rtcp_port=this->remote_media->streams[i].rtcp_port; + + if (sal_stream_description_has_srtp(&this->result->streams[i])) { + this->result->streams[i].crypto[0] = this->remote_media->streams[i].crypto[0]; + } + } + } + } +} + +void SalCallOp::handle_sdp_from_response(belle_sip_response_t* response) { + belle_sdp_session_description_t* sdp; + SalReason reason; + if (this->remote_media){ + sal_media_description_unref(this->remote_media); + this->remote_media=NULL; + } + if (extract_sdp(BELLE_SIP_MESSAGE(response),&sdp,&reason)==0) { + if (sdp){ + this->remote_media=sal_media_description_new(); + sdp_to_media_description(sdp,this->remote_media); + }/*if no sdp in response, what can we do ?*/ + } + /* process sdp in any case to reset result media description*/ + if (this->local_media) sdp_process(); +} + +void SalCallOp::set_error(belle_sip_response_t* response, bool_t fatal){ + set_error_info_from_response(response); + if (fatal) this->state = State::Terminating; + this->root->callbacks.call_failure(this); +} + +int SalCallOp::vfu_retry_cb (void *user_data, unsigned int events) { + SalCallOp *op=(SalCallOp *)user_data; + op->send_vfu_request(); + op->ref(); + return BELLE_SIP_STOP; +} + +void SalCallOp::process_response_cb(void *op_base, const belle_sip_response_event_t *event) { + SalCallOp * op = (SalCallOp *)op_base; + belle_sip_request_t* ack; + belle_sip_dialog_state_t dialog_state; + belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); + belle_sip_request_t* req; + belle_sip_response_t* response=belle_sip_response_event_get_response(event); + int code = belle_sip_response_get_status_code(response); + belle_sip_header_content_type_t *header_content_type=NULL; + belle_sip_dialog_t *dialog=belle_sip_response_event_get_dialog(event); + const char *method; + + if (!client_transaction) { + ms_warning("Discarding stateless response [%i] on op [%p]",code,op); + return; + } + req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); + op->set_or_update_dialog(dialog); + dialog_state=dialog ? belle_sip_dialog_get_state(dialog) : BELLE_SIP_DIALOG_NULL; + method=belle_sip_request_get_method(req); + ms_message("Op [%p] receiving call response [%i], dialog is [%p] in state [%s]",op,code,dialog,belle_sip_dialog_state_to_string(dialog_state)); + /*to make sure no cb will destroy op*/ + op->ref(); + switch(dialog_state) { + case BELLE_SIP_DIALOG_NULL: + case BELLE_SIP_DIALOG_EARLY: { + if (strcmp("INVITE",method)==0 ) { + if (op->state == State::Terminating) { + /*check if CANCEL was sent before*/ + if (strcmp("CANCEL",belle_sip_request_get_method(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_client_trans))))!=0) { + /*it wasn't sent */ + if (code<200) { + op->cancelling_invite(NULL); + }else{ + /* no need to send the INVITE because the UAS rejected the INVITE*/ + if (op->dialog==NULL) op->set_released(); + } + } else { + /*it was sent already, so just expect the 487 or any error response to send the call_released() notification*/ + if (code>=300){ + if (op->dialog==NULL) op->set_released(); + } + } + } else if (code >= 180 && code<200) { + belle_sip_response_t *prev_response=reinterpret_cast(belle_sip_object_data_get(BELLE_SIP_OBJECT(dialog),"early_response")); + if (!prev_response || code>belle_sip_response_get_status_code(prev_response)){ + op->handle_sdp_from_response(response); + op->root->callbacks.call_ringing(op); + } + belle_sip_object_data_set(BELLE_SIP_OBJECT(dialog),"early_response",belle_sip_object_ref(response),belle_sip_object_unref); + } else if (code>=300){ + op->set_error(response, TRUE); + if (op->dialog==NULL) op->set_released(); + } + } else if (code >=200 && code<300) { + if (strcmp("UPDATE",method)==0) { + op->handle_sdp_from_response(response); + op->root->callbacks.call_accepted(op); + } else if (strcmp("CANCEL", method) == 0) { + op->root->callbacks.call_cancel_done(op); + } + } + } + break; + case BELLE_SIP_DIALOG_CONFIRMED: { + switch (op->state) { + case State::Early:/*invite case*/ + case State::Active: /*re-invite, INFO, UPDATE case*/ + if (strcmp("INVITE",method)==0){ + if (code >=200 && code<300) { + op->handle_sdp_from_response(response); + ack=belle_sip_dialog_create_ack(op->dialog,belle_sip_dialog_get_local_seq_number(op->dialog)); + if (ack == NULL) { + ms_error("This call has been already terminated."); + return ; + } + if (op->sdp_answer){ + set_sdp(BELLE_SIP_MESSAGE(ack),op->sdp_answer); + belle_sip_object_unref(op->sdp_answer); + op->sdp_answer=NULL; + } + belle_sip_message_add_header(BELLE_SIP_MESSAGE(ack),BELLE_SIP_HEADER(op->root->user_agent)); + op->root->callbacks.call_accepted(op); /*INVITE*/ + op->root->callbacks.call_ack_being_sent(op, (SalCustomHeader*)ack); + belle_sip_dialog_send_ack(op->dialog,ack); + op->state=State::Active; + }else if (code >= 300){ + op->set_error(response, FALSE); + } + }else if (strcmp("INFO",method)==0){ + if (code == 491 + && (header_content_type = belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t)) + && strcmp("application",belle_sip_header_content_type_get_type(header_content_type))==0 + && strcmp("media_control+xml",belle_sip_header_content_type_get_subtype(header_content_type))==0) { + unsigned int retry_in = rand() % 1001; // [0;1000] + belle_sip_source_t *s=op->root->create_timer(vfu_retry_cb,op->ref(), retry_in, "vfu request retry"); + ms_message("Rejected vfu request on op [%p], just retry in [%ui] ms",op,retry_in); + belle_sip_object_unref(s); + }else { + /*ignoring*/ + } + }else if (strcmp("UPDATE",method)==0){ + op->root->callbacks.call_accepted(op); /*INVITE*/ + }else if (strcmp("CANCEL",method)==0){ + op->root->callbacks.call_cancel_done(op); + } + break; + case State::Terminating: + op->send_request(belle_sip_dialog_create_request(op->dialog,"BYE")); + break; + case State::Terminated: + default: + ms_error("Call op [%p] receives unexpected answer [%i] while in state [%s].",op,code, to_string(op->state)); + } + } + break; + case BELLE_SIP_DIALOG_TERMINATED: { + if (strcmp("INVITE",method)==0 && code >= 300){ + op->set_error(response, TRUE); + } + } + break; + default: { + ms_error("call op [%p] receive answer [%i] not implemented",op,code); + } + break; + } + op->unref(); +} + +void SalCallOp::process_timeout_cb(void *user_ctx, const belle_sip_timeout_event_t *event) { + SalCallOp * op=(SalCallOp *)user_ctx; + + if (op->state==State::Terminated) return; + + if (!op->dialog) { + /*call terminated very early*/ + sal_error_info_set(&op->error_info, SalReasonRequestTimeout, "SIP", 408, "Request timeout", NULL); + op->root->callbacks.call_failure(op); + op->state = State::Terminating; + op->set_released(); + } else { + /*dialog will terminated shortly, nothing to do*/ + } +} + +void SalCallOp::process_transaction_terminated_cb(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { + SalCallOp * op = (SalCallOp *)user_ctx; + belle_sip_client_transaction_t *client_transaction=belle_sip_transaction_terminated_event_get_client_transaction(event); + belle_sip_server_transaction_t *server_transaction=belle_sip_transaction_terminated_event_get_server_transaction(event); + belle_sip_request_t* req; + belle_sip_response_t* resp; + int code = 0; + bool_t release_call=FALSE; + + if (client_transaction) { + req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); + resp=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(client_transaction)); + } else { + req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction)); + resp=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(server_transaction)); + } + if (resp) code = belle_sip_response_get_status_code(resp); + + if (op->state == State::Terminating + && strcmp("BYE",belle_sip_request_get_method(req))==0 + && (!resp || (belle_sip_response_get_status_code(resp) != 401 + && belle_sip_response_get_status_code(resp) != 407)) + && op->dialog==NULL) { + release_call=TRUE; + }else if (op->state == State::Early && code < 200){ + /*call terminated early*/ + sal_error_info_set(&op->error_info, SalReasonIOError, "SIP", 503, "I/O error", NULL); + op->state = State::Terminating; + op->root->callbacks.call_failure(op); + release_call=TRUE; + } + if (server_transaction){ + if (op->pending_server_trans==server_transaction){ + belle_sip_object_unref(op->pending_server_trans); + op->pending_server_trans=NULL; + } + if (op->pending_update_server_trans==server_transaction){ + belle_sip_object_unref(op->pending_update_server_trans); + op->pending_update_server_trans=NULL; + } + } + if (release_call) op->set_released(); +} + +int SalCallOp::is_media_description_acceptable(SalMediaDescription *md) { + if (md->nb_streams==0){ + ms_warning("Media description does not define any stream."); + return FALSE; + } + return TRUE; +} + +SalReason SalCallOp::process_sdp_for_invite(belle_sip_request_t* invite) { + belle_sdp_session_description_t* sdp; + SalReason reason = SalReasonNone; + SalErrorInfo sei; + + memset(&sei, 0, sizeof(sei)); + if (extract_sdp(BELLE_SIP_MESSAGE(invite),&sdp,&reason)==0) { + if (sdp){ + this->sdp_offering=FALSE; + this->remote_media=sal_media_description_new(); + sdp_to_media_description(sdp,this->remote_media); + /*make some sanity check about the SDP received*/ + if (!is_media_description_acceptable(this->remote_media)){ + reason=SalReasonNotAcceptable; + } + belle_sip_object_unref(sdp); + }else this->sdp_offering=TRUE; /*INVITE without SDP*/ + } + + if (reason != SalReasonNone){ + sal_error_info_set(&sei, reason,"SIP", 0, NULL, NULL); + decline_with_error_info(&sei,NULL); + sal_error_info_reset(&sei); + } + return reason; +} + +void SalCallOp::call_terminated(belle_sip_server_transaction_t* server_transaction, int status_code, belle_sip_request_t* cancel_request) { + belle_sip_response_t* resp; + belle_sip_request_t* server_req = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction)); + this->state = State::Terminating; + set_reason_error_info(BELLE_SIP_MESSAGE(cancel_request ? cancel_request : server_req)); + resp=create_response_from_request(server_req,status_code); + belle_sip_server_transaction_send_response(server_transaction,resp); + this->root->callbacks.call_terminated(this,this->dir==Dir::Incoming?this->get_from():this->get_to()); +} + +void SalCallOp::reset_descriptions() { + if (this->remote_media){ + sal_media_description_unref(this->remote_media); + this->remote_media=NULL; + } + if (this->result){ + sal_media_description_unref(this->result); + this->result=NULL; + } +} + +void SalCallOp::unsupported_method(belle_sip_server_transaction_t* server_transaction,belle_sip_request_t* request) { + belle_sip_response_t* resp; + resp=belle_sip_response_create_from_request(request,501); + belle_sip_server_transaction_send_response(server_transaction,resp); +} + +bool_t SalCallOp::is_a_pending_invite_incoming_transaction(belle_sip_transaction_t *tr){ + return BELLE_SIP_OBJECT_IS_INSTANCE_OF(tr, belle_sip_ist_t) && belle_sip_transaction_state_is_transient( + belle_sip_transaction_get_state(tr)); +} + +void SalCallOp::process_request_event_cb(void *op_base, const belle_sip_request_event_t *event) { + SalCallOp * op = (SalCallOp *)op_base; + SalReason reason; + belle_sip_server_transaction_t* server_transaction=NULL; + belle_sdp_session_description_t* sdp; + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_dialog_state_t dialog_state; + belle_sip_response_t* resp; + belle_sip_header_t* call_info; + const char *method=belle_sip_request_get_method(req); + bool_t is_update=FALSE; + bool_t drop_op = FALSE; + + if (strcmp("ACK",method)!=0){ /*ACK doesn't create a server transaction*/ + server_transaction = belle_sip_provider_create_server_transaction(op->root->prov,belle_sip_request_event_get_request(event)); + belle_sip_object_ref(server_transaction); + belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),op->ref()); + } + + if (strcmp("INVITE",method)==0) { + if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); + /*updating pending invite transaction*/ + op->pending_server_trans=server_transaction; + belle_sip_object_ref(op->pending_server_trans); + } + + if (strcmp("UPDATE",method)==0) { + if (op->pending_update_server_trans) belle_sip_object_unref(op->pending_update_server_trans); + /*updating pending update transaction*/ + op->pending_update_server_trans=server_transaction; + belle_sip_object_ref(op->pending_update_server_trans); + } + + if (!op->dialog) { + op->set_or_update_dialog(belle_sip_provider_create_dialog(op->root->prov, BELLE_SIP_TRANSACTION(op->pending_server_trans))); + ms_message("new incoming call from [%s] to [%s]",op->get_from(),op->get_to()); + } + dialog_state=belle_sip_dialog_get_state(op->dialog); + switch(dialog_state) { + case BELLE_SIP_DIALOG_NULL: { + if (strcmp("INVITE",method)==0) { + if (!op->replaces && (op->replaces=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_replaces_t))) { + belle_sip_object_ref(op->replaces); + } else if(op->replaces) { + ms_warning("replace header already set"); + } + + if ( (reason = op->process_sdp_for_invite(req)) == SalReasonNone) { + if ((call_info=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Call-Info"))) { + if( strstr(belle_sip_header_get_unparsed_value(call_info),"answer-after=") != NULL) { + op->auto_answer_asked=TRUE; + ms_message("The caller asked to automatically answer the call(Emergency?)\n"); + } + } + op->root->callbacks.call_received(op); + }else{ + sal_error_info_set(&op->error_info, reason, "SIP", 0, NULL, NULL); + op->root->callbacks.call_rejected(op); + /*the INVITE was declined by process_sdp_for_invite(). As we are not inside an established dialog, we can drop the op immediately*/ + drop_op = TRUE; + } + break; + }BCTBX_NO_BREAK; /* else same behavior as for EARLY state, thus NO BREAK*/ + } + case BELLE_SIP_DIALOG_EARLY: { + if (strcmp("CANCEL",method)==0) { + if(belle_sip_request_event_get_server_transaction(event)) { + /*first answer 200 ok to cancel*/ + belle_sip_server_transaction_send_response(server_transaction + ,op->create_response_from_request(req,200)); + /*terminate invite transaction*/ + op->call_terminated(op->pending_server_trans,487,req); + } else { + /*call leg does not exist*/ + belle_sip_server_transaction_send_response(server_transaction + ,op->create_response_from_request(req,481)); + } + } else if (strcmp("PRACK",method)==0) { + resp=op->create_response_from_request(req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + } else if (strcmp("UPDATE",method)==0) { + op->reset_descriptions(); + if (op->process_sdp_for_invite(req)==SalReasonNone) + op->root->callbacks.call_updating(op,TRUE); + } else { + belle_sip_error("Unexpected method [%s] for dialog state BELLE_SIP_DIALOG_EARLY",belle_sip_request_get_method(req)); + unsupported_method(server_transaction,req); + } + break; + } + case BELLE_SIP_DIALOG_CONFIRMED: + /*great ACK received*/ + if (strcmp("ACK",method)==0) { + if (!op->pending_client_trans || + !belle_sip_transaction_state_is_transient(belle_sip_transaction_get_state((belle_sip_transaction_t*)op->pending_client_trans))){ + if (op->sdp_offering){ + SalReason reason; + if (op->extract_sdp(BELLE_SIP_MESSAGE(req),&sdp,&reason)==0) { + if (sdp){ + if (op->remote_media) + sal_media_description_unref(op->remote_media); + op->remote_media=sal_media_description_new(); + sdp_to_media_description(sdp,op->remote_media); + op->sdp_process(); + belle_sip_object_unref(sdp); + }else{ + ms_warning("SDP expected in ACK but not found."); + } + } + } + op->root->callbacks.call_ack_received(op, (SalCustomHeader*)req); + }else{ + ms_message("Ignored received ack since a new client transaction has been started since."); + } + } else if(strcmp("BYE",method)==0) { + op->call_terminated(server_transaction,200,req); + /*call end not notified by dialog deletion because transaction can end before dialog*/ + } else if(strcmp("INVITE",method)==0 || (is_update=(strcmp("UPDATE",method)==0)) ) { + if (is_update && !belle_sip_message_get_body(BELLE_SIP_MESSAGE(req))) { + /*session timer case*/ + /*session expire should be handled. to be done when real session timer (rfc4028) will be implemented*/ + resp=op->create_response_from_request(req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + belle_sip_object_unref(op->pending_update_server_trans); + op->pending_update_server_trans=NULL; + } else { + /*re-invite*/ + op->reset_descriptions(); + if (op->process_sdp_for_invite(req)==SalReasonNone) + op->root->callbacks.call_updating(op,is_update); + } + } else if (strcmp("INFO",method)==0){ + if (belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)) + && strstr(belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)),"picture_fast_update")) { + /*vfu request*/ + ms_message("Receiving VFU request on op [%p]",op); + if (op->root->callbacks.vfu_request){ + op->root->callbacks.vfu_request(op); + + } + }else{ + belle_sip_message_t *msg = BELLE_SIP_MESSAGE(req); + belle_sip_body_handler_t *body_handler = BELLE_SIP_BODY_HANDLER(op->get_body_handler(msg)); + if (body_handler) { + belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(msg, belle_sip_header_content_type_t); + if (content_type + && (strcmp(belle_sip_header_content_type_get_type(content_type), "application") == 0) + && (strcmp(belle_sip_header_content_type_get_subtype(content_type), "dtmf-relay") == 0)) { + char tmp[10]; + if (sal_lines_get_value(belle_sip_message_get_body(msg), "Signal",tmp, sizeof(tmp))){ + op->root->callbacks.dtmf_received(op,tmp[0]); + } + }else + op->root->callbacks.info_received(op, (SalBodyHandler *)body_handler); + } else { + op->root->callbacks.info_received(op,NULL); + } + } + resp=op->create_response_from_request(req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + }else if (strcmp("REFER",method)==0) { + op->process_refer(event,server_transaction); + } else if (strcmp("NOTIFY",method)==0) { + op->process_notify(event,server_transaction); + } else if (strcmp("OPTIONS",method)==0) { + resp=op->create_response_from_request(req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + } else if (strcmp("CANCEL",method)==0) { + belle_sip_transaction_t *last_transaction = belle_sip_dialog_get_last_transaction(op->dialog); + if (last_transaction == NULL || !is_a_pending_invite_incoming_transaction(last_transaction) ) { + /*call leg does not exist because 200ok already sent*/ + belle_sip_server_transaction_send_response(server_transaction,op->create_response_from_request(req,481)); + } else { + /* CANCEL on re-INVITE for which a 200ok has not been sent yet */ + belle_sip_server_transaction_send_response(server_transaction, op->create_response_from_request(req, 200)); + belle_sip_server_transaction_send_response(BELLE_SIP_SERVER_TRANSACTION(last_transaction), + op->create_response_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_transaction)), 487)); + } + } else if (strcmp("MESSAGE",method)==0){ + op->process_incoming_message(event); + }else{ + ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog); + unsupported_method(server_transaction,req); + } + break; + default: + ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); + break; + } + + if (server_transaction) belle_sip_object_unref(server_transaction); + if (drop_op) op->release(); +} + +void SalCallOp::set_call_as_released(SalCallOp *op) { + op->set_released(); +} + +void SalCallOp::process_dialog_terminated_cb(void *ctx, const belle_sip_dialog_terminated_event_t *event) { + SalCallOp * op=(SalCallOp *)ctx; + + if (op->dialog && op->dialog==belle_sip_dialog_terminated_event_get_dialog(event)) { + /*belle_sip_transaction_t* trans=belle_sip_dialog_get_last_transaction(op->dialog);*/ + ms_message("Dialog [%p] terminated for op [%p]",belle_sip_dialog_terminated_event_get_dialog(event),op); + + switch(belle_sip_dialog_get_previous_state(op->dialog)) { + case BELLE_SIP_DIALOG_EARLY: + case BELLE_SIP_DIALOG_NULL: + if (op->state!=State::Terminated && op->state!=State::Terminating) { + /*this is an early termination due to incorrect response received*/ + op->root->callbacks.call_failure(op); + op->state=State::Terminating; + } + break; + case BELLE_SIP_DIALOG_CONFIRMED: + if (op->state!=State::Terminated && op->state!=State::Terminating) { + /*this is probably a normal termination from a BYE*/ + op->root->callbacks.call_terminated(op,op->dir==Dir::Incoming?op->get_from():op->get_to()); + op->state=State::Terminating; + } + break; + default: + break; + } + belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(op->root->stack) + ,(belle_sip_callback_t) set_call_as_released + , op); + } else { + ms_error("dialog unknown for op "); + } +} + +void SalCallOp::fill_cbs() { + static belle_sip_listener_callbacks_t call_op_callbacks = {0}; + if (call_op_callbacks.process_response_event==NULL){ + call_op_callbacks.process_io_error=process_io_error_cb; + call_op_callbacks.process_response_event=process_response_cb; + call_op_callbacks.process_timeout=process_timeout_cb; + call_op_callbacks.process_transaction_terminated=process_transaction_terminated_cb; + call_op_callbacks.process_request_event=process_request_event_cb; + call_op_callbacks.process_dialog_terminated=process_dialog_terminated_cb; + } + this->callbacks=&call_op_callbacks; + this->type=Type::Call; +} + +int SalCallOp::call(const char *from, const char *to, const char *subject) { + belle_sip_request_t* invite; + this->dir=Dir::Outgoing; + + set_from(from); + set_to(to); + + ms_message("[%s] calling [%s] on op [%p]", from, to, this); + invite=build_request("INVITE"); + + if( invite == NULL ){ + /* can happen if the op has an invalid address */ + return -1; + } + + fill_invite(invite); + if (subject) belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite), belle_sip_header_create("Subject", subject)); + + fill_cbs(); + if (this->replaces){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(this->replaces)); + } + if (this->referred_by) + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(this->referred_by)); + + return send_request(invite); +} + +int SalCallOp::notify_ringing(bool_t early_media){ + int status_code =early_media?183:180; + belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(this->pending_server_trans)); + belle_sip_response_t* ringing_response = create_response_from_request(req,status_code); + belle_sip_header_t *require; + const char *tags=NULL; + + if (early_media){ + handle_offer_answer_response(ringing_response); + } + require=belle_sip_message_get_header((belle_sip_message_t*)req,"Require"); + if (require) tags=belle_sip_header_get_unparsed_value(require); + /* if client requires 100rel, then add necessary stuff*/ + if (tags && strstr(tags,"100rel")!=0) { + belle_sip_message_add_header((belle_sip_message_t*)ringing_response,belle_sip_header_create("Require","100rel")); + belle_sip_message_add_header((belle_sip_message_t*)ringing_response,belle_sip_header_create("RSeq","1")); + } + +#ifndef SAL_OP_CALL_FORCE_CONTACT_IN_RINGING + if (tags && strstr(tags,"100rel")!=0) +#endif + { + belle_sip_header_address_t* contact= (belle_sip_header_address_t*)get_contact_address(); + belle_sip_header_contact_t* contact_header; + if (contact && (contact_header=belle_sip_header_contact_create(contact))) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(ringing_response),BELLE_SIP_HEADER(contact_header)); + } + } + belle_sip_server_transaction_send_response(this->pending_server_trans,ringing_response); + return 0; +} + +int SalCallOp::accept() { + belle_sip_response_t *response; + belle_sip_header_contact_t* contact_header; + belle_sip_server_transaction_t* transaction; + + /*first check if an UPDATE transaction need to be accepted*/ + if (this->pending_update_server_trans) { + transaction= this->pending_update_server_trans; + } else if (this->pending_server_trans) { + /*so it must be an invite/re-invite*/ + transaction= this->pending_server_trans; + } else { + ms_error("No transaction to accept for op [%p]", this); + return -1; + } + ms_message("Accepting server transaction [%p] on op [%p]", transaction, this); + + /* sends a 200 OK */ + response = create_response_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(transaction)),200); + if (response==NULL){ + ms_error("Fail to build answer for call"); + return -1; + } + belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(create_allow(this->root->enable_sip_update))); + if (this->root->session_expires!=0){ +/* if (h->supports_session_timers) {*/ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),belle_sip_header_create("Supported", "timer")); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),belle_sip_header_create( "Session-expires", "600;refresher=uac")); + /*}*/ + } + + if ((contact_header=create_contact())) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact_header)); + } + + add_custom_headers(BELLE_SIP_MESSAGE(response)); + + handle_offer_answer_response(response); + + belle_sip_server_transaction_send_response(transaction,response); + if (this->pending_update_server_trans) { + belle_sip_object_unref(this->pending_update_server_trans); + this->pending_update_server_trans=NULL; + } + if (this->state == State::Early){ + this->state = State::Active; + } + return 0; +} + +int SalCallOp::decline(SalReason reason, const char *redirection /*optional*/){ + belle_sip_response_t* response; + belle_sip_header_contact_t* contact=NULL; + int status=to_sip_code(reason); + belle_sip_transaction_t *trans; + + if (reason==SalReasonRedirect){ + if (redirection!=NULL) { + if (strstr(redirection,"sip:")!=0) status=302; + else status=380; + contact= belle_sip_header_contact_new(); + belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact),belle_sip_uri_parse(redirection)); + } else { + ms_error("Cannot redirect to null"); + } + } + trans=(belle_sip_transaction_t*)this->pending_server_trans; + if (!trans) trans=(belle_sip_transaction_t*)this->pending_update_server_trans; + if (!trans){ + ms_error("sal_call_decline(): no pending transaction to decline."); + return -1; + } + response = create_response_from_request(belle_sip_transaction_get_request(trans),status); + if (contact) belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact)); + belle_sip_server_transaction_send_response(BELLE_SIP_SERVER_TRANSACTION(trans),response); + return 0; +} + +belle_sip_header_reason_t *SalCallOp::make_reason_header( const SalErrorInfo *info){ + if (info != NULL){ + belle_sip_header_reason_t* reason = BELLE_SIP_HEADER_REASON(belle_sip_header_reason_new()); + belle_sip_header_reason_set_text(reason, info->status_string); + belle_sip_header_reason_set_protocol(reason,info->protocol); + belle_sip_header_reason_set_cause(reason,info->protocol_code); + return reason; + } + return NULL; +} + +int SalCallOp::decline_with_error_info(const SalErrorInfo *info, const char *redirection /*optional*/){ + belle_sip_response_t* response; + belle_sip_header_contact_t* contact=NULL; + int status = info->protocol_code; + belle_sip_transaction_t *trans; + + if (info->reason==SalReasonRedirect){ + if (redirection!=NULL) { + if (strstr(redirection,"sip:")!=0) status=302; + else status=380; + contact= belle_sip_header_contact_new(); + belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact),belle_sip_uri_parse(redirection)); + } else { + ms_error("Cannot redirect to null"); + } + } + trans=(belle_sip_transaction_t*)this->pending_server_trans; + if (!trans) trans=(belle_sip_transaction_t*)this->pending_update_server_trans; + if (!trans){ + ms_error("sal_call_decline_with_error_info(): no pending transaction to decline."); + return -1; + } + response = create_response_from_request(belle_sip_transaction_get_request(trans),status); + belle_sip_header_reason_t* reason_header = make_reason_header(info->sub_sei); + if (reason_header) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(reason_header)); + } + + if (contact) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact)); + } + belle_sip_server_transaction_send_response(BELLE_SIP_SERVER_TRANSACTION(trans),response); + return 0; +} + +int SalCallOp::update(const char *subject, bool_t no_user_consent) { + belle_sip_request_t *update; + belle_sip_dialog_state_t state; + + if (this->dialog == NULL) { + /* If the dialog does not exist, this is that we are trying to recover from a connection loss + during a very early state of outgoing call initiation (the dialog has not been created yet). */ + const char *from = get_from(); + const char *to = get_to(); + return call(from, to, subject); + } + + state = belle_sip_dialog_get_state(this->dialog); + belle_sip_dialog_enable_pending_trans_checking(this->dialog,this->root->pending_trans_checking); + + /*check for dialog state*/ + if ( state == BELLE_SIP_DIALOG_CONFIRMED) { + if (no_user_consent) + update=belle_sip_dialog_create_request(this->dialog,"UPDATE"); + else + update=belle_sip_dialog_create_request(this->dialog,"INVITE"); + } else if (state == BELLE_SIP_DIALOG_EARLY) { + update=belle_sip_dialog_create_request(this->dialog,"UPDATE"); + } else { + ms_error("Cannot update op [%p] with dialog [%p] in state [%s]", this, this->dialog,belle_sip_dialog_state_to_string(state)); + return -1; + } + if (update){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(update),belle_sip_header_create( "Subject", subject)); + fill_invite(update); + return send_request(update); + } + /*it failed why ?*/ + if (belle_sip_dialog_request_pending(this->dialog)) + sal_error_info_set(&this->error_info,SalReasonRequestPending, "SIP", 491,NULL,NULL); + else + sal_error_info_set(&this->error_info,SalReasonUnknown, "SIP", 500,NULL,NULL); + return -1; +} + +void SalCallOp::cancel_invite_with_info(const SalErrorInfo *info) { + belle_sip_request_t* cancel; + ms_message("Cancelling INVITE request from [%s] to [%s] ",get_from(), get_to()); + cancel = belle_sip_client_transaction_create_cancel(this->pending_client_trans); + if (cancel){ + if (info != NULL){ + belle_sip_header_reason_t* reason = make_reason_header(info); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(cancel),BELLE_SIP_HEADER(reason)); + } + send_request(cancel); + }else if (this->dialog){ + belle_sip_dialog_state_t state = belle_sip_dialog_get_state(this->dialog);; + /*case where the response received is invalid (could not establish a dialog), but the transaction is not cancellable + * because already terminated*/ + switch(state){ + case BELLE_SIP_DIALOG_EARLY: + case BELLE_SIP_DIALOG_NULL: + /*force kill the dialog*/ + ms_warning("op [%p]: force kill of dialog [%p]", this, this->dialog); + belle_sip_dialog_delete(this->dialog); + break; + default: + break; + } + } +} + +SalMediaDescription *SalCallOp::get_final_media_description() { + if (this->local_media && this->remote_media && !this->result){ + sdp_process(); + } + return this->result; +} + +int SalCallOp::refer_to(belle_sip_header_refer_to_t* refer_to, belle_sip_header_referred_by_t* referred_by) { + char* tmp; + belle_sip_request_t* req=this->dialog?belle_sip_dialog_create_request(this->dialog,"REFER"):build_request("REFER"); + if (!req) { + tmp=belle_sip_uri_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to))); + ms_error("Cannot refer to [%s] for op [%p]",tmp, this); + belle_sip_free(tmp); + return -1; + } + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(refer_to)); + if (referred_by) belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(referred_by)); + return send_request(req); +} + +int SalCallOp::refer(const char *refer_to_){ + belle_sip_header_address_t *referred_by; + belle_sip_header_refer_to_t* refer_to_header; + if (this->dialog) { + referred_by=(belle_sip_header_address_t*)belle_sip_object_clone(BELLE_SIP_OBJECT(belle_sip_dialog_get_local_party(this->dialog))); + }else{ + referred_by=BELLE_SIP_HEADER_ADDRESS(get_from_address()); + } + refer_to_header=belle_sip_header_refer_to_create(belle_sip_header_address_parse(refer_to_)); + + return refer_to(refer_to_header,belle_sip_header_referred_by_create(referred_by)); +} + +int SalCallOp::refer_with_replaces(SalCallOp *other_call_op) { + belle_sip_dialog_state_t other_call_dialog_state=other_call_op->dialog?belle_sip_dialog_get_state(other_call_op->dialog):BELLE_SIP_DIALOG_NULL; + belle_sip_dialog_state_t op_dialog_state= this->dialog?belle_sip_dialog_get_state(this->dialog):BELLE_SIP_DIALOG_NULL; + belle_sip_header_replaces_t* replaces; + belle_sip_header_refer_to_t* refer_to_; + belle_sip_header_referred_by_t* referred_by; + const char* from_tag; + const char* to_tag; + char* escaped_replaces; + /*first, build refer to*/ + if ((other_call_dialog_state!=BELLE_SIP_DIALOG_CONFIRMED) && (other_call_dialog_state!=BELLE_SIP_DIALOG_EARLY)) { + ms_error("wrong dialog state [%s] for op [%p], should be BELLE_SIP_DIALOG_CONFIRMED or BELE_SIP_DIALOG_EARLY", + belle_sip_dialog_state_to_string(other_call_dialog_state), + other_call_op); + return -1; + } + if (op_dialog_state!=BELLE_SIP_DIALOG_CONFIRMED) { + ms_error("wrong dialog state [%s] for op [%p], should be BELLE_SIP_DIALOG_CONFIRMED", + belle_sip_dialog_state_to_string(op_dialog_state), + this); + return -1; + } + + refer_to_ =belle_sip_header_refer_to_create(belle_sip_dialog_get_remote_party(other_call_op->dialog)); + belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(refer_to_)); + /*rfc3891 + ... + 4. User Agent Client Behavior: Sending a Replaces Header + + A User Agent that wishes to replace a single existing early or + confirmed dialog with a new dialog of its own, MAY send the target + User Agent an INVITE request containing a Replaces header field. The + User Agent Client (UAC) places the Call-ID, to-tag, and from-tag + information for the target dialog in a single Replaces header field + and sends the new INVITE to the target.*/ + from_tag=belle_sip_dialog_get_local_tag(other_call_op->dialog); + to_tag=belle_sip_dialog_get_remote_tag(other_call_op->dialog); + + replaces=belle_sip_header_replaces_create(belle_sip_header_call_id_get_call_id(belle_sip_dialog_get_call_id(other_call_op->dialog)) + ,from_tag,to_tag); + escaped_replaces=belle_sip_header_replaces_value_to_escaped_string(replaces); + belle_sip_uri_set_header(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to_)),"Replaces",escaped_replaces); + belle_sip_free(escaped_replaces); + referred_by=belle_sip_header_referred_by_create(belle_sip_dialog_get_local_party(this->dialog)); + belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(referred_by)); + return refer_to(refer_to_,referred_by); +} + +int SalCallOp::set_referer(SalCallOp *refered_call){ + if (refered_call->replaces) + SalOp::set_replaces(refered_call->replaces); + if (refered_call->referred_by) + set_referred_by(refered_call->referred_by); + return 0; +} + +SalCallOp *SalCallOp::get_replaces() { + if (this->replaces){ + /*rfc3891 + 3. User Agent Server Behavior: Receiving a Replaces Header + + The Replaces header contains information used to match an existing + SIP dialog (call-id, to-tag, and from-tag). Upon receiving an INVITE + with a Replaces header, the User Agent (UA) attempts to match this + information with a confirmed or early dialog. The User Agent Server + (UAS) matches the to-tag and from-tag parameters as if they were tags + present in an incoming request. In other words, the to-tag parameter + is compared to the local tag, and the from-tag parameter is compared + to the remote tag. + */ + belle_sip_dialog_t* dialog=belle_sip_provider_find_dialog(this->root->prov + ,belle_sip_header_replaces_get_call_id(this->replaces) + ,belle_sip_header_replaces_get_to_tag(this->replaces) + ,belle_sip_header_replaces_get_from_tag(this->replaces)); + + if (!dialog) { + /*for backward compatibility with liblinphone <= 3.10.2-243 */ + dialog=belle_sip_provider_find_dialog(this->root->prov + ,belle_sip_header_replaces_get_call_id(this->replaces) + ,belle_sip_header_replaces_get_from_tag(this->replaces) + ,belle_sip_header_replaces_get_to_tag(this->replaces)); + } + if (dialog) { + return (SalCallOp*)belle_sip_dialog_get_application_data(dialog); + } + } + return NULL; +} + +int SalCallOp::send_dtmf(char dtmf){ + if (this->dialog && (belle_sip_dialog_get_state(this->dialog) == BELLE_SIP_DIALOG_CONFIRMED || belle_sip_dialog_get_state(this->dialog) == BELLE_SIP_DIALOG_EARLY)){ + belle_sip_request_t *req=belle_sip_dialog_create_queued_request(this->dialog,"INFO"); + if (req){ + size_t bodylen; + char dtmf_body[128]={0}; + + snprintf(dtmf_body, sizeof(dtmf_body)-1, "Signal=%c\r\nDuration=250\r\n", dtmf); + bodylen=strlen(dtmf_body); + belle_sip_message_set_body((belle_sip_message_t*)req,dtmf_body,bodylen); + belle_sip_message_add_header((belle_sip_message_t*)req,(belle_sip_header_t*)belle_sip_header_content_length_create(bodylen)); + belle_sip_message_add_header((belle_sip_message_t*)req,(belle_sip_header_t*)belle_sip_header_content_type_create("application", "dtmf-relay")); + send_request(req); + }else ms_error("sal_call_send_dtmf(): could not build request"); + }else ms_error("sal_call_send_dtmf(): no dialog"); + return 0; +} + +int SalCallOp::terminate_with_error(const SalErrorInfo *info) { + SalErrorInfo sei; + const SalErrorInfo *p_sei; + belle_sip_dialog_state_t dialog_state = this->dialog ? belle_sip_dialog_get_state(this->dialog) : BELLE_SIP_DIALOG_NULL; + int ret = 0; + + memset(&sei, 0, sizeof(sei)); + if (info == NULL && dialog_state != BELLE_SIP_DIALOG_CONFIRMED && this->dir == Dir::Incoming){ + /*the purpose of this line is to set a default SalErrorInfo for declining an incoming call (not yet established of course) */ + sal_error_info_set(&sei,SalReasonDeclined, "SIP", 0, NULL, NULL); + p_sei = &sei; + } else{ + p_sei = info; + } + if (this->state==State::Terminating || this->state==State::Terminated) { + ms_error("Cannot terminate op [%p] in state [%s]",this,to_string(this->state)); + ret = -1; + goto end; + } + switch(dialog_state) { + case BELLE_SIP_DIALOG_CONFIRMED: { + belle_sip_request_t * req = belle_sip_dialog_create_request(this->dialog,"BYE"); + if (info != NULL){ + belle_sip_header_reason_t* reason = make_reason_header(info); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(reason)); + } + send_request(req); + this->state=State::Terminating; + break; + } + + case BELLE_SIP_DIALOG_NULL: { + if (this->dir == Dir::Incoming) { + decline_with_error_info(p_sei, NULL); + this->state=State::Terminated; + } else if (this->pending_client_trans){ + if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(this->pending_client_trans)) == BELLE_SIP_TRANSACTION_PROCEEDING){ + cancelling_invite(p_sei); + }else{ + /* Case where the CANCEL cannot be sent because no provisional response was received so far. + * The Op must be kept for the time of the transaction in case a response is received later. + * The state is passed to Terminating to remember to terminate later. + */ + this->state=State::Terminating; + /* However, even if the transaction is kept alive, we can stop sending retransmissions to avoid flowing the network with no longer + * necessary messages and avoid confusion in logs.*/ + belle_sip_client_transaction_stop_retransmissions(this->pending_client_trans); + } + } + break; + } + case BELLE_SIP_DIALOG_EARLY: { + if (this->dir == Dir::Incoming) { + decline_with_error_info(p_sei,NULL); + this->state=State::Terminated; + } else { + cancelling_invite(p_sei); + } + break; + } + default: { + ms_error("sal_call_terminate not implemented yet for dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); + ret = -1; + goto end; + } + } +end: + sal_error_info_reset(&sei); + return ret; +} + +void SalCallOp::send_vfu_request() { + char info_body[] = + "" + "" + " " + " " + " " + " " + " " + ""; + size_t content_lenth = sizeof(info_body) - 1; + belle_sip_dialog_state_t dialog_state= this->dialog?belle_sip_dialog_get_state(this->dialog):BELLE_SIP_DIALOG_NULL; /*no dialog = dialog in NULL state*/ + if (dialog_state == BELLE_SIP_DIALOG_CONFIRMED) { + belle_sip_request_t* info = belle_sip_dialog_create_queued_request(this->dialog,"INFO"); + int error=TRUE; + if (info) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(info),BELLE_SIP_HEADER(belle_sip_header_content_type_create("application","media_control+xml"))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(info),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_lenth))); + belle_sip_message_set_body(BELLE_SIP_MESSAGE(info),info_body,content_lenth); + error=send_request(info); + } + if (error) + ms_warning("Cannot send vfu request to [%s] ", get_to()); + + } else { + ms_warning("Cannot send vfu request to [%s] because dialog [%p] in wrong state [%s]",get_to() + ,this->dialog + ,belle_sip_dialog_state_to_string(dialog_state)); + } + + return ; +} + +int SalCallOp::send_notify_for_refer(int code, const char *reason) { + belle_sip_request_t* notify=belle_sip_dialog_create_queued_request(this->dialog,"NOTIFY"); + char *sipfrag=belle_sip_strdup_printf("SIP/2.0 %i %s\r\n",code,reason); + size_t content_length=strlen(sipfrag); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) + ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,-1))); + + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),belle_sip_header_create("Event","refer")); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(belle_sip_header_content_type_create("message","sipfrag"))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length))); + belle_sip_message_assign_body(BELLE_SIP_MESSAGE(notify),sipfrag,content_length); + return send_request(notify); +} + +void SalCallOp::notify_last_response(SalCallOp *newcall) { + belle_sip_client_transaction_t *tr=newcall->pending_client_trans; + belle_sip_response_t *resp=NULL; + if (tr){ + resp=belle_sip_transaction_get_response((belle_sip_transaction_t*)tr); + } + if (resp==NULL){ + send_notify_for_refer(100, "Trying"); + }else{ + send_notify_for_refer(belle_sip_response_get_status_code(resp), belle_sip_response_get_reason_phrase(resp)); + } +} + +int SalCallOp::notify_refer_state(SalCallOp *newcall) { + belle_sip_dialog_state_t state; + if(belle_sip_dialog_get_state(this->dialog) == BELLE_SIP_DIALOG_TERMINATED){ + return 0; + } + state = this->dialog?belle_sip_dialog_get_state(this->dialog):BELLE_SIP_DIALOG_NULL; + switch(state) { + case BELLE_SIP_DIALOG_EARLY: + send_notify_for_refer(100, "Trying"); + break; + case BELLE_SIP_DIALOG_CONFIRMED: + send_notify_for_refer(200, "Ok"); + break; + case BELLE_SIP_DIALOG_TERMINATED: + case BELLE_SIP_DIALOG_NULL: + notify_last_response(newcall); + break; + } + return 0; +} + +void SalCallOp::set_replaces(const char *call_id, const char *from_tag, const char *to_tag) { + belle_sip_header_replaces_t *replaces = belle_sip_header_replaces_create(call_id, from_tag, to_tag); + SalOp::set_replaces(replaces); +} + +void SalCallOp::set_sdp_handling(SalOpSDPHandling handling) { + if (handling != SalOpSDPNormal) ms_message("Enabling special SDP handling for SalOp[%p]!", this); + this->sdp_handling = handling; +} + +void SalCallOp::process_refer(const belle_sip_request_event_t *event, belle_sip_server_transaction_t *server_transaction) { + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_header_refer_to_t *refer_to= belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_refer_to_t); + belle_sip_header_referred_by_t *referred_by= belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_referred_by_t); + belle_sip_response_t* resp; + belle_sip_uri_t* refer_to_uri; + char* refer_to_uri_str; + + ms_message("Receiving REFER request on op [%p]", this); + if (refer_to) { + refer_to_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to)); + + if (refer_to_uri && belle_sip_uri_get_header(refer_to_uri,"Replaces")) { + SalOp::set_replaces(belle_sip_header_replaces_create2(belle_sip_uri_get_header(refer_to_uri,"Replaces"))); + belle_sip_uri_remove_header(refer_to_uri,"Replaces"); + } + if (referred_by){ + set_referred_by(referred_by); + } + refer_to_uri_str=belle_sip_uri_to_string(refer_to_uri); + resp = create_response_from_request(req,202); + belle_sip_server_transaction_send_response(server_transaction,resp); + this->root->callbacks.refer_received(this->root,this,refer_to_uri_str); + belle_sip_free(refer_to_uri_str); + } else { + ms_warning("cannot do anything with the refer without destination\n"); + resp = create_response_from_request(req,400); + belle_sip_server_transaction_send_response(server_transaction,resp); + } + +} + +void SalCallOp::process_notify(const belle_sip_request_event_t *event, belle_sip_server_transaction_t* server_transaction) { + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); + belle_sip_header_t* header_event=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Event"); + belle_sip_header_content_type_t* content_type = belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t); + belle_sip_response_t* resp; + + ms_message("Receiving NOTIFY request on op [%p]", this); + if (header_event + && strncasecmp(belle_sip_header_get_unparsed_value(header_event),"refer",strlen("refer"))==0 + && content_type + && strcmp(belle_sip_header_content_type_get_type(content_type),"message")==0 + && strcmp(belle_sip_header_content_type_get_subtype(content_type),"sipfrag")==0 + && body){ + belle_sip_response_t* sipfrag=BELLE_SIP_RESPONSE(belle_sip_message_parse(body)); + + if (sipfrag){ + int code=belle_sip_response_get_status_code(sipfrag); + SalReferStatus status=SalReferFailed; + if (code<200){ + status=SalReferTrying; + }else if (code<300){ + status=SalReferSuccess; + }else if (code>=400){ + status=SalReferFailed; + } + belle_sip_object_unref(sipfrag); + resp = create_response_from_request(req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + this->root->callbacks.notify_refer(this,status); + } + }else{ + ms_error("Notify without sipfrag, trashing"); + resp = create_response_from_request(req,501); + belle_sip_server_transaction_send_response(server_transaction,resp); + } +} + +int SalCallOp::send_message(const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri) { + if (!this->dialog) return -1; + belle_sip_request_t* req=belle_sip_dialog_create_queued_request(this->dialog,"MESSAGE"); + prepare_message_request(req, content_type, msg, peer_uri); + return send_request(req); +} + +bool_t SalCallOp::compare_op(const SalCallOp *op2) const { + return (strcmp(this->call_id, op2->call_id) == 0); +} + +void SalCallOp::handle_offer_answer_response(belle_sip_response_t* response) { + if (this->local_media){ + /*this is the case where we received an invite without SDP*/ + if (this->sdp_offering) { + set_sdp_from_desc(BELLE_SIP_MESSAGE(response),this->local_media); + }else{ + + if ( this->sdp_answer==NULL ) + { + if( this->sdp_handling == SalOpSDPSimulateRemove ){ + ms_warning("Simulating SDP removal in answer for op %p", this); + } else { + sdp_process(); + } + } + + if (this->sdp_answer){ + set_sdp(BELLE_SIP_MESSAGE(response),this->sdp_answer); + belle_sip_object_unref(this->sdp_answer); + this->sdp_answer=NULL; + } + } + }else{ + ms_error("You are accepting a call but not defined any media capabilities !"); + } +} + +LINPHONE_END_NAMESPACE diff --git a/coreapi/sal/call_op.h b/coreapi/sal/call_op.h new file mode 100644 index 000000000..2f773ae83 --- /dev/null +++ b/coreapi/sal/call_op.h @@ -0,0 +1,108 @@ +/* +sal_op.h +Copyright (C) 2017 Belledonne Communications + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _SAL_CALL_OP_H_ +#define _SAL_CALL_OP_H_ + +#include "sal_op.h" +#include "message_op_interface.h" + +LINPHONE_BEGIN_NAMESPACE + +class SalCallOp: public SalOp, public SalMessageOpInterface { +public: + SalCallOp(Sal *sal): SalOp(sal) {} + + int set_local_media_description(SalMediaDescription *desc); + int set_local_custom_body(SalCustomBody *body); + + SalMediaDescription *get_remote_media_description() {return this->remote_media;} + SalMediaDescription *get_final_media_description(); + + int call(const char *from, const char *to, const char *subject); + int notify_ringing(bool_t early_media); + int accept(); + int decline(SalReason reason, const char *redirection /*optional*/); + int decline_with_error_info(const SalErrorInfo *info, const char *redirection /*optional*/); + int update(const char *subject, bool_t no_user_consent); + void cancel_invite() {cancel_invite_with_info(NULL);} + void cancel_invite_with_info(const SalErrorInfo *info); + int refer(const char *refer_to_); + int refer_with_replaces(SalCallOp *other_call_op); + int set_referer(SalCallOp *refered_call); + SalCallOp *get_replaces(); + int send_dtmf(char dtmf); + int terminate() {return terminate_with_error(NULL);} + int terminate_with_error(const SalErrorInfo *info); + bool_t autoanswer_asked() const {return this->auto_answer_asked;} + void send_vfu_request(); + int is_offerer() const {return this->sdp_offering;} + int notify_refer_state(SalCallOp *newcall); + bool_t compare_op(const SalCallOp *op2) const; + bool_t dialog_request_pending() const {return (belle_sip_dialog_request_pending(this->dialog) != 0);} + const char *get_local_tag() {return belle_sip_dialog_get_local_tag(this->dialog);} + const char *get_remote_tag() {return belle_sip_dialog_get_remote_tag(this->dialog);} + void set_replaces(const char *call_id, const char *from_tag, const char *to_tag); + void set_sdp_handling(SalOpSDPHandling handling); + +// int send_message(const char *from, const char *to, const char *msg) override {return MessageOpInterface::send_message(from, to, msg);} + int send_message(const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri) override; + int reply(SalReason reason) override {return SalOp::reply_message(reason);} + +private: + static belle_sip_header_allow_t *create_allow(bool_t enable_update); + static int set_custom_body(belle_sip_message_t *msg, const SalCustomBody *body); + static int set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* session_desc); + static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription *desc); + void set_released(); + static void process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event); + void cancelling_invite(const SalErrorInfo *info); + static SalCustomBody *extract_body(belle_sip_message_t *message); + int extract_sdp(belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error); + static void set_addr_to_0000(char value[], size_t sz); + void sdp_process(); + void handle_sdp_from_response(belle_sip_response_t* response); + void set_error(belle_sip_response_t* response, bool_t fatal); + static int vfu_retry_cb (void *user_data, unsigned int events); + static void process_response_cb(void *op_base, const belle_sip_response_event_t *event); + static void process_timeout_cb(void *user_ctx, const belle_sip_timeout_event_t *event); + static void process_transaction_terminated_cb(void *user_ctx, const belle_sip_transaction_terminated_event_t *event); + static int is_media_description_acceptable(SalMediaDescription *md); + SalReason process_sdp_for_invite(belle_sip_request_t* invite); + void call_terminated(belle_sip_server_transaction_t* server_transaction, int status_code, belle_sip_request_t* cancel_request); + void reset_descriptions(); + static void unsupported_method(belle_sip_server_transaction_t* server_transaction,belle_sip_request_t* request); + static bool_t is_a_pending_invite_incoming_transaction(belle_sip_transaction_t *tr); + static void process_request_event_cb(void *op_base, const belle_sip_request_event_t *event); + static void set_call_as_released(SalCallOp *op); + static void process_dialog_terminated_cb(void *ctx, const belle_sip_dialog_terminated_event_t *event); + virtual void fill_cbs() override; + void fill_invite(belle_sip_request_t* invite); + static belle_sip_header_reason_t *make_reason_header( const SalErrorInfo *info); + int refer_to(belle_sip_header_refer_to_t* refer_to, belle_sip_header_referred_by_t* referred_by); + void notify_last_response(SalCallOp *newcall); + int send_notify_for_refer(int code, const char *reason); + void process_refer(const belle_sip_request_event_t *event, belle_sip_server_transaction_t *server_transaction); + void process_notify(const belle_sip_request_event_t *event, belle_sip_server_transaction_t* server_transaction); + void handle_offer_answer_response(belle_sip_response_t* response); +}; + +LINPHONE_END_NAMESPACE + +#endif diff --git a/coreapi/sal/event_op.cpp b/coreapi/sal/event_op.cpp new file mode 100644 index 000000000..d3f3b8ca6 --- /dev/null +++ b/coreapi/sal/event_op.cpp @@ -0,0 +1,425 @@ +#include "event_op.h" + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +void SalSubscribeOp::subscribe_process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event) { + SalSubscribeOp *op = (SalSubscribeOp *)user_ctx; + belle_sip_object_t *src = belle_sip_io_error_event_get_source(event); + if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(src, belle_sip_client_transaction_t)){ + belle_sip_client_transaction_t *tr = BELLE_SIP_CLIENT_TRANSACTION(src); + belle_sip_request_t* req = belle_sip_transaction_get_request((belle_sip_transaction_t*)tr); + const char *method=belle_sip_request_get_method(req); + + if (!op->dialog) { + /*this is handling outgoing out-of-dialog notifies*/ + if (strcmp(method,"NOTIFY")==0){ + SalErrorInfo *ei=&op->error_info; + sal_error_info_set(ei,SalReasonIOError, "SIP", 0,NULL,NULL); + op->root->callbacks.on_notify_response(op); + } + } + } +} + +void SalSubscribeOp::subscribe_response_event_cb(void *op_base, const belle_sip_response_event_t *event){ + SalSubscribeOp *op = (SalSubscribeOp *)op_base; + belle_sip_request_t * req; + const char *method; + belle_sip_client_transaction_t *tr = belle_sip_response_event_get_client_transaction(event); + + if (!tr) return; + req = belle_sip_transaction_get_request((belle_sip_transaction_t*)tr); + method = belle_sip_request_get_method(req); + + if (!op->dialog) { + if (strcmp(method,"NOTIFY")==0){ + op->set_error_info_from_response(belle_sip_response_event_get_response(event)); + op->root->callbacks.on_notify_response(op); + } + } +} + +void SalSubscribeOp::subscribe_process_timeout_cb(void *user_ctx, const belle_sip_timeout_event_t *event) { + SalSubscribeOp *op = (SalSubscribeOp *)user_ctx; + belle_sip_request_t * req; + const char *method; + belle_sip_client_transaction_t *tr = belle_sip_timeout_event_get_client_transaction(event); + + if (!tr) return; + req = belle_sip_transaction_get_request((belle_sip_transaction_t*)tr); + method = belle_sip_request_get_method(req); + + if (!op->dialog) { + /*this is handling outgoing out-of-dialog notifies*/ + if (strcmp(method,"NOTIFY")==0){ + SalErrorInfo *ei=&op->error_info; + sal_error_info_set(ei,SalReasonRequestTimeout, "SIP", 0,NULL,NULL); + op->root->callbacks.on_notify_response(op); + } + } +} + +void SalSubscribeOp::handle_notify(belle_sip_request_t *req, const char *eventname, SalBodyHandler* body_handler){ + SalSubscribeStatus sub_state; + belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t); + belle_sip_response_t* resp; + belle_sip_server_transaction_t* server_transaction = this->pending_server_trans; + + if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) { + sub_state=SalSubscribeTerminated; + ms_message("Outgoing subscription terminated by remote [%s]",get_to()); + } else + sub_state=SalSubscribeActive; + ref(); + this->root->callbacks.notify(this,sub_state,eventname,body_handler); + resp=create_response_from_request(req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + unref(); +} + +void SalSubscribeOp::subscribe_process_request_event_cb(void *op_base, const belle_sip_request_event_t *event) { + SalSubscribeOp * op = (SalSubscribeOp *)op_base; + belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->root->prov,belle_sip_request_event_get_request(event)); + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_dialog_state_t dialog_state; + belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t); + belle_sip_header_event_t *event_header; + belle_sip_body_handler_t *body_handler; + belle_sip_response_t* resp; + const char *eventname=NULL; + const char *method=belle_sip_request_get_method(req); + belle_sip_dialog_t *dialog = NULL; + + belle_sip_object_ref(server_transaction); + if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); + op->pending_server_trans=server_transaction; + + event_header=belle_sip_message_get_header_by_type(req,belle_sip_header_event_t); + body_handler = BELLE_SIP_BODY_HANDLER(op->get_body_handler(BELLE_SIP_MESSAGE(req))); + + if (event_header==NULL){ + ms_warning("No event header in incoming SUBSCRIBE."); + resp=op->create_response_from_request(req,400); + belle_sip_server_transaction_send_response(server_transaction,resp); + if (!op->dialog) op->release(); + return; + } + if (op->event==NULL) { + op->event=event_header; + belle_sip_object_ref(op->event); + } + eventname=belle_sip_header_event_get_package_name(event_header); + + if (!op->dialog) { + if (strcmp(method,"SUBSCRIBE")==0){ + dialog = belle_sip_provider_create_dialog(op->root->prov,BELLE_SIP_TRANSACTION(server_transaction)); + if (!dialog){ + resp=op->create_response_from_request(req,481); + belle_sip_server_transaction_send_response(server_transaction,resp); + op->release(); + return; + } + op->set_or_update_dialog(dialog); + ms_message("new incoming subscription from [%s] to [%s]",op->get_from(),op->get_to()); + }else{ /*this is a NOTIFY*/ + op->handle_notify(req, eventname, (SalBodyHandler *)body_handler); + return; + } + } + dialog_state=belle_sip_dialog_get_state(op->dialog); + switch(dialog_state) { + + case BELLE_SIP_DIALOG_NULL: { + const char *type = NULL; + belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_content_type_t); + if (content_type) type = belle_sip_header_content_type_get_type(content_type); + op->root->callbacks.subscribe_received(op, eventname, type ? (SalBodyHandler *)body_handler : NULL); + break; + } + case BELLE_SIP_DIALOG_EARLY: + ms_error("unexpected method [%s] for dialog [%p] in state BELLE_SIP_DIALOG_EARLY ",belle_sip_request_get_method(req),op->dialog); + break; + + case BELLE_SIP_DIALOG_CONFIRMED: + if (strcmp("NOTIFY",method)==0) { + op->handle_notify(req, eventname, (SalBodyHandler *)body_handler); + } else if (strcmp("SUBSCRIBE",method)==0) { + /*either a refresh of an unsubscribe*/ + if (expires && belle_sip_header_expires_get_expires(expires)>0) { + resp=op->create_response_from_request(req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + } else if(expires) { + ms_message("Unsubscribe received from [%s]",op->get_from()); + resp=op->create_response_from_request(req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + op->root->callbacks.incoming_subscribe_closed(op); + } + } + break; + default: { + ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); + } + } +} + +void SalSubscribeOp::subscribe_process_dialog_terminated_cb(void *ctx, const belle_sip_dialog_terminated_event_t *event) { + belle_sip_dialog_t *dialog = belle_sip_dialog_terminated_event_get_dialog(event); + SalSubscribeOp * op= (SalSubscribeOp *)ctx; + if (op->dialog) { + if (belle_sip_dialog_terminated_event_is_expired(event)){ + if (!belle_sip_dialog_is_server(dialog)){ + /*notify the app that our subscription is dead*/ + const char *eventname = NULL; + if (op->event){ + eventname = belle_sip_header_event_get_package_name(op->event); + } + op->root->callbacks.notify(op, SalSubscribeTerminated, eventname, NULL); + }else{ + op->root->callbacks.incoming_subscribe_closed(op); + } + } + op->set_or_update_dialog(NULL); + } +} + +void SalSubscribeOp::_release_cb(SalOp *op_base) { + auto *op =reinterpret_cast(op_base); + if(op->refresher) { + belle_sip_refresher_stop(op->refresher); + belle_sip_object_unref(op->refresher); + op->refresher=NULL; + op->set_or_update_dialog(NULL); /*only if we have refresher. else dialog terminated event will remove association*/ + } +} + +void SalSubscribeOp::fill_cbs() { + static belle_sip_listener_callbacks_t op_subscribe_callbacks={0}; + if (op_subscribe_callbacks.process_io_error==NULL){ + op_subscribe_callbacks.process_io_error=subscribe_process_io_error_cb; + op_subscribe_callbacks.process_response_event=subscribe_response_event_cb; + op_subscribe_callbacks.process_timeout=subscribe_process_timeout_cb; + op_subscribe_callbacks.process_transaction_terminated=subscribe_process_transaction_terminated_cb; + op_subscribe_callbacks.process_request_event=subscribe_process_request_event_cb; + op_subscribe_callbacks.process_dialog_terminated=subscribe_process_dialog_terminated_cb; + } + this->callbacks=&op_subscribe_callbacks; + this->type=Type::Subscribe; + this->release_cb=release_cb; +} + +void SalSubscribeOp::subscribe_refresher_listener_cb (belle_sip_refresher_t* refresher,void* user_pointer,unsigned int status_code,const char* reason_phrase, int will_retry) { + SalSubscribeOp * op = (SalSubscribeOp *)user_pointer; + belle_sip_transaction_t *tr=BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher)); + /*belle_sip_response_t* response=belle_sip_transaction_get_response(tr);*/ + SalSubscribeStatus sss=SalSubscribeTerminated; + + ms_message("Subscribe refresher [%i] reason [%s] ",status_code,reason_phrase?reason_phrase:"none"); + if (status_code>=200 && status_code<300){ + if (status_code==200) sss=SalSubscribeActive; + else if (status_code==202) sss=SalSubscribePending; + op->set_or_update_dialog(belle_sip_transaction_get_dialog(tr)); + op->root->callbacks.subscribe_response(op,sss, will_retry); + } else if (status_code >= 300) { + SalReason reason = SalReasonUnknown; + if (status_code == 503) { /*refresher returns 503 for IO error*/ + reason = SalReasonIOError; + } + sal_error_info_set(&op->error_info, reason, "SIP", status_code,reason_phrase,NULL); + op->root->callbacks.subscribe_response(op,sss, will_retry); + }else if (status_code==0){ + op->root->callbacks.on_expire(op); + } + +} + +int SalSubscribeOp::subscribe(const char *from, const char *to, const char *eventname, int expires, const SalBodyHandler *body_handler) { + belle_sip_request_t *req=NULL; + + if (from) + set_from(from); + if (to) + set_to(to); + + if (!this->dialog){ + fill_cbs(); + req=build_request("SUBSCRIBE"); + if( req == NULL ) { + return -1; + } + set_event(eventname); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(this->event)); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(expires))); + belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(body_handler)); + return send_and_create_refresher(req,expires,subscribe_refresher_listener_cb); + }else if (this->refresher){ + const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(this->refresher); + belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr); + /* modify last request to update body*/ + belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(last_req), BELLE_SIP_BODY_HANDLER(body_handler)); + return belle_sip_refresher_refresh(this->refresher,expires); + } + ms_warning("sal_subscribe(): no dialog and no refresher ?"); + return -1; +} + +int SalSubscribeOp::accept() { + belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(this->pending_server_trans)); + belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t); + belle_sip_response_t* resp = create_response_from_request(req,200); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(expires)); + belle_sip_server_transaction_send_response(this->pending_server_trans,resp); + return 0; +} + +int SalSubscribeOp::decline(SalReason reason) { + belle_sip_response_t* resp = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(this->pending_server_trans)), + to_sip_code(reason)); + belle_sip_server_transaction_send_response(this->pending_server_trans,resp); + return 0; +} + +int SalSubscribeOp::notify_pending_state() { + + if (this->dialog != NULL && this->pending_server_trans) { + belle_sip_request_t* notify; + belle_sip_header_subscription_state_t* sub_state; + ms_message("Sending NOTIFY with subscription state pending for op [%p]", this); + if (!(notify=belle_sip_dialog_create_request(this->dialog,"NOTIFY"))) { + ms_error("Cannot create NOTIFY on op [%p]", this); + return -1; + } + if (this->event) belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(this->event)); + sub_state=belle_sip_header_subscription_state_new(); + belle_sip_header_subscription_state_set_state(sub_state,BELLE_SIP_SUBSCRIPTION_STATE_PENDING); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify), BELLE_SIP_HEADER(sub_state)); + return send_request(notify); + } else { + ms_warning("NOTIFY with subscription state pending for op [%p] not implemented in this case (either dialog pending trans does not exist", this); + } + + return 0; +} + +int SalSubscribeOp::notify(const SalBodyHandler *body_handler) { + belle_sip_request_t* notify; + + if (this->dialog){ + if (!(notify=belle_sip_dialog_create_queued_request(this->dialog,"NOTIFY"))) return -1; + }else{ + fill_cbs(); + notify = build_request("NOTIFY"); + } + + if (this->event) belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(this->event)); + + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) + , this->dialog ? + BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,600)) : + BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,0)) + ); + belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(notify), BELLE_SIP_BODY_HANDLER(body_handler)); + return send_request(notify); +} + +int SalSubscribeOp::close_notify() { + belle_sip_request_t* notify; + if (!this->dialog) return -1; + if (!(notify=belle_sip_dialog_create_queued_request(this->dialog,"NOTIFY"))) return -1; + if (this->event) belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(this->event)); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) + ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1))); + return send_request(notify); +} + +void SalPublishOp::publish_response_event_cb(void *userctx, const belle_sip_response_event_t *event) { + SalPublishOp *op=(SalPublishOp *)userctx; + op->set_error_info_from_response(belle_sip_response_event_get_response(event)); + if (op->error_info.protocol_code>=200){ + op->root->callbacks.on_publish_response(op); + } +} + +void SalPublishOp::fill_cbs() { + static belle_sip_listener_callbacks_t op_publish_callbacks={0}; + if (op_publish_callbacks.process_response_event==NULL){ + op_publish_callbacks.process_response_event=publish_response_event_cb; + } + + this->callbacks=&op_publish_callbacks; + this->type=Type::Publish; +} + +void SalPublishOp::publish_refresher_listener_cb (belle_sip_refresher_t* refresher,void* user_pointer,unsigned int status_code,const char* reason_phrase, int will_retry) { + SalPublishOp * op = (SalPublishOp *)user_pointer; + const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); + belle_sip_response_t *response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(last_publish_trans)); + ms_message("Publish refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase?reason_phrase:"none",op->get_proxy()); + if (status_code==0){ + op->root->callbacks.on_expire(op); + }else if (status_code>=200){ + belle_sip_header_t *sip_etag; + const char *sip_etag_string = NULL; + if (response && (sip_etag = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response), "SIP-ETag"))) { + sip_etag_string = belle_sip_header_get_unparsed_value(sip_etag); + } + op->set_entity_tag(sip_etag_string); + sal_error_info_set(&op->error_info,SalReasonUnknown, "SIP", status_code,reason_phrase,NULL); + op->assign_recv_headers((belle_sip_message_t*)response); + op->root->callbacks.on_publish_response(op); + } +} + +int SalPublishOp::publish(const char *from, const char *to, const char *eventname, int expires, const SalBodyHandler *body_handler) { + belle_sip_request_t *req=NULL; + if(!this->refresher || !belle_sip_refresher_get_transaction(this->refresher)) { + if (from) + set_from(from); + if (to) + set_to(to); + + fill_cbs(); + req=build_request("PUBLISH"); + if( req == NULL ){ + return -1; + } + + if (get_entity_tag()) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("SIP-If-Match", get_entity_tag())); + } + + if (get_contact_address()){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(create_contact())); + } + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event",eventname)); + belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(body_handler)); + if (expires!=-1) + return send_and_create_refresher(req,expires,publish_refresher_listener_cb); + else return send_request(req); + } else { + /*update status*/ + const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(this->refresher); + belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); + /*update body*/ + if (expires == 0) { + belle_sip_message_set_body(BELLE_SIP_MESSAGE(last_publish), NULL, 0); + } else { + belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(last_publish), BELLE_SIP_BODY_HANDLER(body_handler)); + } + return belle_sip_refresher_refresh(this->refresher,expires==-1 ? BELLE_SIP_REFRESHER_REUSE_EXPIRES : expires); + } +} + +int SalPublishOp::unpublish() { + if (this->refresher){ + const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(this->refresher); + belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr); + belle_sip_message_set_body(BELLE_SIP_MESSAGE(last_req), NULL, 0); + belle_sip_refresher_refresh(this->refresher,0); + return 0; + } + return -1; +} + +LINPHONE_END_NAMESPACE diff --git a/coreapi/sal/event_op.h b/coreapi/sal/event_op.h new file mode 100644 index 000000000..0084c508a --- /dev/null +++ b/coreapi/sal/event_op.h @@ -0,0 +1,74 @@ +/* +event_op.h +Copyright (C) 2017 Belledonne Communications + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _SAL_EVENT_OP_H_ +#define _SAL_EVENT_OP_H_ + +#include "sal_op.h" + +LINPHONE_BEGIN_NAMESPACE + +class SalEventOp: public SalOp { +public: + SalEventOp(Sal *sal): SalOp(sal) {} +}; + +class SalSubscribeOp: public SalEventOp { +public: + SalSubscribeOp(Sal *sal): SalEventOp(sal) {} + + int subscribe(const char *from, const char *to, const char *eventname, int expires, const SalBodyHandler *body_handler); + int unsubscribe() {return SalOp::unsubscribe();} + int accept(); + int decline(SalReason reason); + int notify_pending_state(); + int notify(const SalBodyHandler *body_handler); + int close_notify(); + +private: + virtual void fill_cbs() override; + void handle_notify(belle_sip_request_t *req, const char *eventname, SalBodyHandler* body_handler); + + static void subscribe_process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event); + static void subscribe_response_event_cb(void *op_base, const belle_sip_response_event_t *event); + static void subscribe_process_timeout_cb(void *user_ctx, const belle_sip_timeout_event_t *event); + static void subscribe_process_transaction_terminated_cb(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) {} + static void subscribe_process_request_event_cb(void *op_base, const belle_sip_request_event_t *event); + static void subscribe_process_dialog_terminated_cb(void *ctx, const belle_sip_dialog_terminated_event_t *event); + static void _release_cb(SalOp *op_base); + static void subscribe_refresher_listener_cb (belle_sip_refresher_t* refresher,void* user_pointer,unsigned int status_code,const char* reason_phrase, int will_retry); +}; + +class SalPublishOp: public SalEventOp { +public: + SalPublishOp(Sal *sal): SalEventOp(sal) {} + + int publish(const char *from, const char *to, const char *eventname, int expires, const SalBodyHandler *body_handler); + int unpublish(); + +private: + virtual void fill_cbs() override; + + static void publish_response_event_cb(void *userctx, const belle_sip_response_event_t *event); + static void publish_refresher_listener_cb (belle_sip_refresher_t* refresher,void* user_pointer,unsigned int status_code,const char* reason_phrase, int will_retry); +}; + +LINPHONE_END_NAMESPACE + +#endif diff --git a/coreapi/sal/message_op.cpp b/coreapi/sal/message_op.cpp new file mode 100644 index 000000000..a97a088e0 --- /dev/null +++ b/coreapi/sal/message_op.cpp @@ -0,0 +1,88 @@ +#include "message_op.h" + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +void SalMessageOp::process_error() { + if (this->dir == Dir::Outgoing) { + this->root->callbacks.message_delivery_update(this, SalMessageDeliveryFailed); + } else { + ms_warning("unexpected io error for incoming message on op [%p]", this); + } + this->state=State::Terminated; +} + +void SalMessageOp::process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event) { + SalMessageOp * op = (SalMessageOp *)user_ctx; + sal_error_info_set(&op->error_info,SalReasonIOError, "SIP", 503,"IO Error",NULL); + op->process_error(); +} + +void SalMessageOp::process_response_event_cb(void *op_base, const belle_sip_response_event_t *event) { + SalMessageOp * op = (SalMessageOp *)op_base; + int code = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)); + SalMessageDeliveryStatus status; + op->set_error_info_from_response(belle_sip_response_event_get_response(event)); + + if (code>=100 && code <200) + status=SalMessageDeliveryInProgress; + else if (code>=200 && code <300) + status=SalMessageDeliveryDone; + else + status=SalMessageDeliveryFailed; + + op->root->callbacks.message_delivery_update(op,status); +} + +void SalMessageOp::process_timeout_cb(void *user_ctx, const belle_sip_timeout_event_t *event) { + SalMessageOp * op=(SalMessageOp *)user_ctx; + sal_error_info_set(&op->error_info,SalReasonRequestTimeout, "SIP", 408,"Request timeout",NULL); + op->process_error(); +} + +void SalMessageOp::process_request_event_cb(void *op_base, const belle_sip_request_event_t *event) { + SalMessageOp * op = (SalMessageOp *)op_base; + op->process_incoming_message(event); +} + +void SalMessageOp::fill_cbs() { + static belle_sip_listener_callbacks_t op_message_callbacks = {0}; + if (op_message_callbacks.process_io_error==NULL) { + op_message_callbacks.process_io_error=process_io_error_cb; + op_message_callbacks.process_response_event=process_response_event_cb; + op_message_callbacks.process_timeout=process_timeout_cb; + op_message_callbacks.process_request_event=process_request_event_cb; + } + this->callbacks=&op_message_callbacks; + this->type=Type::Message; +} + +void SalMessageOpInterface::prepare_message_request(belle_sip_request_t *req, const char* content_type, const char *msg, const char *peer_uri) { + char content_type_raw[256]; + size_t content_length = msg?strlen(msg):0; + time_t curtime = ms_time(NULL); + snprintf(content_type_raw,sizeof(content_type_raw),BELLE_SIP_CONTENT_TYPE ": %s",content_type); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_type_parse(content_type_raw))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime))); + if (msg){ + /*don't call set_body() with null argument because it resets content type and content length*/ + belle_sip_message_set_body(BELLE_SIP_MESSAGE(req), msg, content_length); + } +} + +int SalMessageOp::send_message(const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri) { + fill_cbs(); + if (from) set_from(from); + if (to) set_to(to); + this->dir=Dir::Outgoing; + + belle_sip_request_t* req=build_request("MESSAGE"); + if (req == NULL ) return -1; + if (get_contact_address()) belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(create_contact())); + prepare_message_request(req, content_type, msg, peer_uri); + return send_request(req); +} + +LINPHONE_END_NAMESPACE diff --git a/coreapi/sal/message_op.h b/coreapi/sal/message_op.h new file mode 100644 index 000000000..22d7e3d7f --- /dev/null +++ b/coreapi/sal/message_op.h @@ -0,0 +1,47 @@ +/* +message_op.h +Copyright (C) 2017 Belledonne Communications + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _SAL_MASSAGE_OP_H_ +#define _SAL_MASSAGE_OP_H_ + +#include "sal_op.h" +#include "message_op_interface.h" + +LINPHONE_BEGIN_NAMESPACE + +class SalMessageOp: public SalOp, public SalMessageOpInterface { +public: + SalMessageOp(Sal *sal): SalOp(sal) {} + + int send_message(const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri) override; + int reply(SalReason reason) override {return SalOp::reply_message(reason);} + +private: + virtual void fill_cbs() override; + void process_error(); + + static void process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event); + static void process_response_event_cb(void *op_base, const belle_sip_response_event_t *event); + static void process_timeout_cb(void *user_ctx, const belle_sip_timeout_event_t *event); + static void process_request_event_cb(void *op_base, const belle_sip_request_event_t *event); +}; + +LINPHONE_END_NAMESPACE + +#endif diff --git a/coreapi/sal/message_op_interface.h b/coreapi/sal/message_op_interface.h new file mode 100644 index 000000000..1e5abee82 --- /dev/null +++ b/coreapi/sal/message_op_interface.h @@ -0,0 +1,38 @@ +/* +message_op_interface.h +Copyright (C) 2017 Belledonne Communications + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _SAL_MESSAGE_OP_INTERFACE_H_ +#define _SAL_MESSAGE_OP_INTERFACE_H_ + +LINPHONE_BEGIN_NAMESPACE + +class SalMessageOpInterface { +public: + virtual ~SalMessageOpInterface() = default; + int send_message(const char *from, const char *to, const char *msg) {return send_message(from,to,"text/plain",msg, nullptr);} + virtual int send_message(const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri) = 0; + virtual int reply(SalReason reason) = 0; + +protected: + void prepare_message_request(belle_sip_request_t *req, const char* content_type, const char *msg, const char *peer_uri); +}; + +LINPHONE_END_NAMESPACE + +#endif diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/sal/presence_op.cpp similarity index 59% rename from coreapi/bellesip_sal/sal_op_presence.c rename to coreapi/sal/presence_op.cpp index ba0624bfb..853017160 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/sal/presence_op.cpp @@ -1,53 +1,11 @@ -/* -linphone -Copyright (C) 2012 Belledonne Communications, Grenoble, France +#include "presence_op.h" -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. +using namespace std; -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. +LINPHONE_BEGIN_NAMESPACE -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 "sal_impl.h" - - -void sal_add_presence_info(SalOp *op, belle_sip_message_t *notify, SalPresenceModel *presence) { - char *contact_info; - char *content = NULL; - size_t content_length; - - if (presence){ - belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(notify,belle_sip_header_from_t); - contact_info=belle_sip_uri_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from))); - op->base.root->callbacks.convert_presence_to_xml_requested(op, presence, contact_info, &content); - belle_sip_free(contact_info); - if (content == NULL) return; - } - - belle_sip_message_remove_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_CONTENT_TYPE); - belle_sip_message_remove_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_CONTENT_LENGTH); - belle_sip_message_set_body(BELLE_SIP_MESSAGE(notify),NULL,0); - - if (content){ - belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) - ,BELLE_SIP_HEADER(belle_sip_header_content_type_create("application","pidf+xml"))); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) - ,BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length=strlen(content)))); - belle_sip_message_set_body(BELLE_SIP_MESSAGE(notify),content,content_length); - ms_free(content); - } -} - -static void presence_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ - SalOp* op = (SalOp*)user_ctx; +void SalPresenceOp::presence_process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event) { + SalPresenceOp * op = (SalPresenceOp *)user_ctx; belle_sip_request_t* request; belle_sip_client_transaction_t* client_transaction = NULL; @@ -65,55 +23,43 @@ static void presence_process_io_error(void *user_ctx, const belle_sip_io_error_e ms_warning("presence_process_io_error() refresher is present, should not happen"); return; } - ms_message("subscription to [%s] io error",sal_op_get_to(op)); + ms_message("subscription to [%s] io error",op->get_to()); if (!op->op_released){ - op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, NULL,NULL); /*NULL = offline*/ + op->root->callbacks.notify_presence(op,SalSubscribeTerminated, NULL,NULL); /*NULL = offline*/ } } } -static void presence_process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) { - SalOp* op= (SalOp*)ctx; - if (op->dialog && belle_sip_dialog_is_server(op->dialog)) { - ms_message("Incoming subscribtion from [%s] terminated",sal_op_get_from(op)); - if (!op->op_released){ - op->base.root->callbacks.subscribe_presence_closed(op, sal_op_get_from(op)); - } - set_or_update_dialog(op, NULL); - }/* else client dialog is managed by refresher*/ -} - -static void presence_refresher_listener(belle_sip_refresher_t* refresher, void* user_pointer, unsigned int status_code, const char* reason_phrase, int will_retry){ - SalOp* op = (SalOp*)user_pointer; +void SalPresenceOp::presence_refresher_listener_cb(belle_sip_refresher_t* refresher, void* user_pointer, unsigned int status_code, const char* reason_phrase, int will_retry) { + SalPresenceOp * op = (SalPresenceOp *)user_pointer; if (status_code >= 300) { ms_message("The SUBSCRIBE dialog no longer works. Let's restart a new one."); belle_sip_refresher_stop(op->refresher); if (op->dialog) { /*delete previous dialog if any*/ - set_or_update_dialog(op, NULL); + op->set_or_update_dialog(NULL); } - if (sal_op_get_contact_address(op)) { + if (op->get_contact_address()) { /*contact is also probably not good*/ - SalAddress* contact=sal_address_clone(sal_op_get_contact_address(op)); + SalAddress* contact=sal_address_clone(op->get_contact_address()); sal_address_set_port(contact,-1); sal_address_set_domain(contact,NULL); - sal_op_set_contact_address(op,contact); + op->set_contact_address(contact); sal_address_destroy(contact); } /*send a new SUBSCRIBE, that will attempt to establish a new dialog*/ - sal_subscribe_presence(op,NULL,NULL,-1); + op->subscribe(NULL,NULL,-1); } if (status_code == 0 || status_code == 503){ /*timeout or io error: the remote doesn't seem reachable.*/ if (!op->op_released){ - op->base.root->callbacks.notify_presence(op,SalSubscribeActive, NULL,NULL); /*NULL = offline*/ + op->root->callbacks.notify_presence(op,SalSubscribeActive, NULL,NULL); /*NULL = offline*/ } } } - -static void presence_response_event(void *op_base, const belle_sip_response_event_t *event){ - SalOp* op = (SalOp*)op_base; +void SalPresenceOp::presence_response_event_cb(void *op_base, const belle_sip_response_event_t *event) { + SalPresenceOp * op = (SalPresenceOp *)op_base; belle_sip_dialog_state_t dialog_state; belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); belle_sip_response_t* response=belle_sip_response_event_get_response(event); @@ -121,18 +67,18 @@ static void presence_response_event(void *op_base, const belle_sip_response_even int code = belle_sip_response_get_status_code(response); belle_sip_header_expires_t* expires; - sal_op_set_error_info_from_response(op,response); + op->set_error_info_from_response(response); if (code>=300) { if (strcmp("SUBSCRIBE",belle_sip_request_get_method(request))==0){ - ms_message("subscription to [%s] rejected",sal_op_get_to(op)); + ms_message("subscription to [%s] rejected",op->get_to()); if (!op->op_released){ - op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, NULL,NULL); /*NULL = offline*/ + op->root->callbacks.notify_presence(op,SalSubscribeTerminated, NULL,NULL); /*NULL = offline*/ } return; } } - set_or_update_dialog(reinterpret_cast(op_base),belle_sip_response_event_get_dialog(event)); + op->set_or_update_dialog(belle_sip_response_event_get_dialog(event)); if (!op->dialog) { ms_message("presence op [%p] receive out of dialog answer [%i]",op,code); return; @@ -155,8 +101,8 @@ static void presence_response_event(void *op_base, const belle_sip_response_even } if ((expires != NULL) && (belle_sip_header_expires_get_expires(expires) > 0)) { op->refresher=belle_sip_client_transaction_create_refresher(client_transaction); - belle_sip_refresher_set_listener(op->refresher,presence_refresher_listener,op); - belle_sip_refresher_set_realm(op->refresher,op->base.realm); + belle_sip_refresher_set_listener(op->refresher,presence_refresher_listener_cb,op); + belle_sip_refresher_set_realm(op->refresher,op->realm); } } break; @@ -168,8 +114,8 @@ static void presence_response_event(void *op_base, const belle_sip_response_even } } -static void presence_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { - SalOp* op = (SalOp*)user_ctx; +void SalPresenceOp::presence_process_timeout_cb(void *user_ctx, const belle_sip_timeout_event_t *event) { + SalPresenceOp * op = (SalPresenceOp *)user_ctx; belle_sip_client_transaction_t* client_transaction = belle_sip_timeout_event_get_client_transaction(event); belle_sip_request_t* request; @@ -178,18 +124,18 @@ static void presence_process_timeout(void *user_ctx, const belle_sip_timeout_eve request = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); if (strcmp("SUBSCRIBE",belle_sip_request_get_method(request))==0){ - ms_message("subscription to [%s] timeout",sal_op_get_to(op)); + ms_message("subscription to [%s] timeout",op->get_to()); if (!op->op_released){ - op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, NULL,NULL); /*NULL = offline*/ + op->root->callbacks.notify_presence(op,SalSubscribeTerminated, NULL,NULL); /*NULL = offline*/ } } } -static void presence_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { +void SalPresenceOp::presence_process_transaction_terminated_cb(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { ms_message("presence_process_transaction_terminated not implemented yet"); } -static SalPresenceModel * process_presence_notification(SalOp *op, belle_sip_request_t *req) { +SalPresenceModel *SalPresenceOp::process_presence_notification(belle_sip_request_t *req) { belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_content_type_t); belle_sip_header_content_length_t *content_length = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_content_length_t); const char *body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); @@ -201,8 +147,8 @@ static SalPresenceModel * process_presence_notification(SalOp *op, belle_sip_req return NULL; if (body==NULL) return NULL; - if (!op->op_released){ - op->base.root->callbacks.parse_presence_requested(op, + if (!this->op_released){ + this->root->callbacks.parse_presence_requested(this, belle_sip_header_content_type_get_type(content_type), belle_sip_header_content_type_get_subtype(content_type), body, @@ -212,9 +158,9 @@ static SalPresenceModel * process_presence_notification(SalOp *op, belle_sip_req return result; } -static void handle_notify(SalOp *op, belle_sip_request_t *req, belle_sip_dialog_t *dialog){ +void SalPresenceOp::handle_notify(belle_sip_request_t *req, belle_sip_dialog_t *dialog) { belle_sip_response_t* resp=NULL; - belle_sip_server_transaction_t* server_transaction=op->pending_server_trans; + belle_sip_server_transaction_t* server_transaction= this->pending_server_trans; belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t); SalSubscribeStatus sub_state; @@ -222,35 +168,35 @@ static void handle_notify(SalOp *op, belle_sip_request_t *req, belle_sip_dialog_ SalPresenceModel *presence_model = NULL; const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); - if (op->dialog !=NULL && dialog != op->dialog){ - ms_warning("Receiving a NOTIFY from a dialog we haven't stored (op->dialog=%p dialog=%p)", op->dialog, dialog); + if (this->dialog !=NULL && dialog != this->dialog){ + ms_warning("Receiving a NOTIFY from a dialog we haven't stored (op->dialog=%p dialog=%p)", this->dialog, dialog); } if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) { sub_state=SalSubscribeTerminated; - ms_message("Outgoing subscription terminated by remote [%s]",sal_op_get_to(op)); + ms_message("Outgoing subscription terminated by remote [%s]",get_to()); } else { sub_state=belle_sip_message_get_subscription_state(BELLE_SIP_MESSAGE(req)); } - presence_model = process_presence_notification(op, req); + presence_model = process_presence_notification(req); if (presence_model != NULL || body==NULL) { /* Presence notification body parsed successfully. */ - resp = sal_op_create_response_from_request(op, req, 200); /*create first because the op may be destroyed by notify_presence */ - if (!op->op_released){ - op->base.root->callbacks.notify_presence(op, sub_state, presence_model, NULL); + resp = create_response_from_request(req, 200); /*create first because the op may be destroyed by notify_presence */ + if (!this->op_released){ + this->root->callbacks.notify_presence(this, sub_state, presence_model, NULL); } } else if (body){ /* Formatting error in presence notification body. */ ms_warning("Wrongly formatted presence document."); - resp = sal_op_create_response_from_request(op, req, 488); + resp = create_response_from_request(req, 488); } if (resp) belle_sip_server_transaction_send_response(server_transaction,resp); } } -static void presence_process_request_event(void *op_base, const belle_sip_request_event_t *event) { - SalOp* op = (SalOp*)op_base; - belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); +void SalPresenceOp::presence_process_request_event_cb(void *op_base, const belle_sip_request_event_t *event) { + SalPresenceOp * op = (SalPresenceOp *)op_base; + belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->root->prov,belle_sip_request_event_get_request(event)); belle_sip_request_t* req = belle_sip_request_event_get_request(event); belle_sip_dialog_state_t dialog_state; belle_sip_response_t* resp; @@ -263,9 +209,9 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques if (event_header==NULL){ ms_warning("No event header in incoming SUBSCRIBE."); - resp=sal_op_create_response_from_request(op,req,400); + resp=op->create_response_from_request(req,400); belle_sip_server_transaction_send_response(server_transaction,resp); - if (!op->dialog) sal_op_release(op); + if (!op->dialog) op->release(); return; } if (op->event==NULL) { @@ -276,21 +222,21 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques if (!op->dialog) { if (strcmp(method,"SUBSCRIBE")==0){ - belle_sip_dialog_t *dialog = belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(server_transaction)); + belle_sip_dialog_t *dialog = belle_sip_provider_create_dialog(op->root->prov,BELLE_SIP_TRANSACTION(server_transaction)); if (!dialog){ - resp=sal_op_create_response_from_request(op,req,481); + resp=op->create_response_from_request(req,481); belle_sip_server_transaction_send_response(server_transaction,resp); - sal_op_release(op); + op->release(); return; } - set_or_update_dialog(op, dialog); - ms_message("new incoming subscription from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op)); + op->set_or_update_dialog(dialog); + ms_message("new incoming subscription from [%s] to [%s]",op->get_from(),op->get_to()); }else if (strcmp(method,"NOTIFY")==0 && belle_sip_request_event_get_dialog(event)) { /*special case of dialog created by notify matching subscribe*/ - set_or_update_dialog(op, belle_sip_request_event_get_dialog(event)); + op->set_or_update_dialog(belle_sip_request_event_get_dialog(event)); } else {/* this is a NOTIFY */ ms_message("Receiving out of dialog notify"); - handle_notify(op, req, belle_sip_request_event_get_dialog(event)); + op->handle_notify(req, belle_sip_request_event_get_dialog(event)); return; } } @@ -298,9 +244,9 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques switch(dialog_state) { case BELLE_SIP_DIALOG_NULL: { if (strcmp("NOTIFY",method)==0) { - handle_notify(op, req, belle_sip_request_event_get_dialog(event)); + op->handle_notify(req, belle_sip_request_event_get_dialog(event)); } else if (strcmp("SUBSCRIBE",method)==0) { - op->base.root->callbacks.subscribe_presence_received(op,sal_op_get_from(op)); + op->root->callbacks.subscribe_presence_received(op,op->get_from()); } break; } @@ -310,12 +256,12 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques case BELLE_SIP_DIALOG_CONFIRMED: if (strcmp("NOTIFY",method)==0) { - handle_notify(op, req, belle_sip_request_event_get_dialog(event)); + op->handle_notify(req, belle_sip_request_event_get_dialog(event)); } else if (strcmp("SUBSCRIBE",method)==0) { /*either a refresh or an unsubscribe. If it is a refresh there is nothing to notify to the app. If it is an unSUBSCRIBE, then the dialog will be terminated shortly, and this will be notified to the app through the dialog_terminated callback.*/ - resp=sal_op_create_response_from_request(op,req,200); + resp=op->create_response_from_request(req,200); belle_sip_server_transaction_send_response(server_transaction,resp); } break; @@ -325,117 +271,163 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques } } -static belle_sip_listener_callbacks_t op_presence_callbacks={0}; +void SalPresenceOp::presence_process_dialog_terminated_cb(void *ctx, const belle_sip_dialog_terminated_event_t *event) { + SalPresenceOp * op= (SalPresenceOp *)ctx; + if (op->dialog && belle_sip_dialog_is_server(op->dialog)) { + ms_message("Incoming subscribtion from [%s] terminated",op->get_from()); + if (!op->op_released){ + op->root->callbacks.subscribe_presence_closed(op, op->get_from()); + } + op->set_or_update_dialog(NULL); + }/* else client dialog is managed by refresher*/ +} -/*Invoke when sal_op_release is called by upper layer*/ -static void sal_op_release_cb(struct SalOpBase* op_base) { - SalOp *op =(SalOp*)op_base; +void SalPresenceOp::_release_cb(SalOp *op_base) { + SalPresenceOp *op =(SalPresenceOp *)op_base; if(op->refresher) { belle_sip_refresher_stop(op->refresher); belle_sip_object_unref(op->refresher); op->refresher=NULL; - set_or_update_dialog(op,NULL); /*only if we have refresher. else dialog terminated event will remove association*/ + op->set_or_update_dialog(NULL); /*only if we have refresher. else dialog terminated event will remove association*/ } - } -void sal_op_presence_fill_cbs(SalOp*op) { + +void SalPresenceOp::fill_cbs() { + static belle_sip_listener_callbacks_t op_presence_callbacks={0}; if (op_presence_callbacks.process_request_event==NULL){ - op_presence_callbacks.process_io_error=presence_process_io_error; - op_presence_callbacks.process_response_event=presence_response_event; - op_presence_callbacks.process_timeout=presence_process_timeout; - op_presence_callbacks.process_transaction_terminated=presence_process_transaction_terminated; - op_presence_callbacks.process_request_event=presence_process_request_event; - op_presence_callbacks.process_dialog_terminated=presence_process_dialog_terminated; + op_presence_callbacks.process_io_error=presence_process_io_error_cb; + op_presence_callbacks.process_response_event=presence_response_event_cb; + op_presence_callbacks.process_timeout= presence_process_timeout_cb; + op_presence_callbacks.process_transaction_terminated=presence_process_transaction_terminated_cb; + op_presence_callbacks.process_request_event=presence_process_request_event_cb; + op_presence_callbacks.process_dialog_terminated=presence_process_dialog_terminated_cb; } - op->callbacks=&op_presence_callbacks; - op->type=SalOpPresence; - op->base.release_cb=sal_op_release_cb; + this->callbacks=&op_presence_callbacks; + this->type=Type::Presence; + this->release_cb=_release_cb; } - -/*presence Subscribe/notify*/ -int sal_subscribe_presence(SalOp *op, const char *from, const char *to, int expires){ +int SalPresenceOp::subscribe(const char *from, const char *to, int expires) { belle_sip_request_t *req=NULL; if (from) - sal_op_set_from(op,from); + set_from(from); if (to) - sal_op_set_to(op,to); + set_to(to); - sal_op_presence_fill_cbs(op); + fill_cbs(); if (expires==-1){ - if (op->refresher){ - expires=belle_sip_refresher_get_expires(op->refresher); - belle_sip_object_unref(op->refresher); - op->refresher=NULL; + if (this->refresher){ + expires=belle_sip_refresher_get_expires(this->refresher); + belle_sip_object_unref(this->refresher); + this->refresher=NULL; }else{ ms_error("sal_subscribe_presence(): cannot guess expires from previous refresher."); return -1; } } - if (!op->event){ - op->event=belle_sip_header_event_create("presence"); - belle_sip_object_ref(op->event); + if (!this->event){ + this->event=belle_sip_header_event_create("presence"); + belle_sip_object_ref(this->event); } - belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(op->base.from_address),"tag"); - belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(op->base.to_address),"tag"); - req=sal_op_build_request(op,"SUBSCRIBE"); + belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(this->from_address),"tag"); + belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(this->to_address),"tag"); + req=build_request("SUBSCRIBE"); if( req ){ - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(op->event)); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(this->event)); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(expires))); } - return sal_op_send_request(op,req); + return send_request(req); } +int SalPresenceOp::check_dialog_state() { + belle_sip_dialog_state_t state= this->dialog?belle_sip_dialog_get_state(this->dialog): BELLE_SIP_DIALOG_NULL; + if (state != BELLE_SIP_DIALOG_CONFIRMED) { + ms_warning("Cannot notify presence for op [%p] because dialog in state [%s]", this, belle_sip_dialog_state_to_string(state)); + return -1; + } else + return 0; +} -static belle_sip_request_t *create_presence_notify(SalOp *op){ - belle_sip_request_t* notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"); +belle_sip_request_t *SalPresenceOp::create_presence_notify() { + belle_sip_request_t* notify=belle_sip_dialog_create_queued_request(this->dialog,"NOTIFY"); if (!notify) return NULL; belle_sip_message_add_header((belle_sip_message_t*)notify,belle_sip_header_create("Event","presence")); return notify; } -static int sal_op_check_dialog_state(SalOp *op) { - belle_sip_dialog_state_t state=op->dialog?belle_sip_dialog_get_state(op->dialog): BELLE_SIP_DIALOG_NULL; - if (state != BELLE_SIP_DIALOG_CONFIRMED) { - ms_warning("Cannot notify presence for op [%p] because dialog in state [%s]",op, belle_sip_dialog_state_to_string(state)); - return -1; - } else - return 0; +void SalPresenceOp::add_presence_info(belle_sip_message_t *notify, SalPresenceModel *presence) { + char *contact_info; + char *content = NULL; + size_t content_length; + + if (presence){ + belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(notify,belle_sip_header_from_t); + contact_info=belle_sip_uri_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from))); + this->root->callbacks.convert_presence_to_xml_requested(this, presence, contact_info, &content); + belle_sip_free(contact_info); + if (content == NULL) return; + } + + belle_sip_message_remove_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_CONTENT_TYPE); + belle_sip_message_remove_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_CONTENT_LENGTH); + belle_sip_message_set_body(BELLE_SIP_MESSAGE(notify),NULL,0); + + if (content){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) + ,BELLE_SIP_HEADER(belle_sip_header_content_type_create("application","pidf+xml"))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) + ,BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length=strlen(content)))); + belle_sip_message_set_body(BELLE_SIP_MESSAGE(notify),content,content_length); + ms_free(content); + } } -int sal_notify_presence(SalOp *op, SalPresenceModel *presence){ +int SalPresenceOp::notify_presence(SalPresenceModel *presence) { belle_sip_request_t* notify=NULL; - if (sal_op_check_dialog_state(op)) { + if (check_dialog_state()) { return -1; } - notify=create_presence_notify(op); + notify=create_presence_notify(); if (!notify) return-1; - sal_add_presence_info(op,BELLE_SIP_MESSAGE(notify),presence); /*FIXME, what about expires ??*/ + add_presence_info(BELLE_SIP_MESSAGE(notify),presence); /*FIXME, what about expires ??*/ belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,600))); - return sal_op_send_request(op,notify); + return send_request(notify); } -int sal_notify_presence_close(SalOp *op){ +int SalPresenceOp::notify_presence_close() { belle_sip_request_t* notify=NULL; int status; - if (sal_op_check_dialog_state(op)) { + if (check_dialog_state()) { return -1; } - notify=create_presence_notify(op); + notify=create_presence_notify(); if (!notify) return-1; - sal_add_presence_info(op,BELLE_SIP_MESSAGE(notify),NULL); /*FIXME, what about expires ??*/ + add_presence_info(BELLE_SIP_MESSAGE(notify),NULL); /*FIXME, what about expires ??*/ belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1))); - status = sal_op_send_request(op,notify); - set_or_update_dialog(op,NULL); /*because we may be chalanged for the notify, so we must release dialog right now*/ + status = send_request(notify); + set_or_update_dialog(NULL); /*because we may be chalanged for the notify, so we must release dialog right now*/ return status; } +SalSubscribeStatus SalPresenceOp::belle_sip_message_get_subscription_state(const belle_sip_message_t *msg) { + belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(msg,belle_sip_header_subscription_state_t); + SalSubscribeStatus sss=SalSubscribeNone; + if (subscription_state_header){ + if (strcmp(belle_sip_header_subscription_state_get_state(subscription_state_header),BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED)==0) + sss=SalSubscribeTerminated; + else if (strcmp(belle_sip_header_subscription_state_get_state(subscription_state_header),BELLE_SIP_SUBSCRIPTION_STATE_PENDING)==0) + sss=SalSubscribePending; + else if (strcmp(belle_sip_header_subscription_state_get_state(subscription_state_header),BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE)==0) + sss=SalSubscribeActive; + } + return sss; +} - +LINPHONE_END_NAMESPACE diff --git a/coreapi/sal/presence_op.h b/coreapi/sal/presence_op.h new file mode 100644 index 000000000..f8eebd9e7 --- /dev/null +++ b/coreapi/sal/presence_op.h @@ -0,0 +1,58 @@ +/* +presence_op.h +Copyright (C) 2017 Belledonne Communications + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _SAL_PRESENCE_OP_H_ +#define _SAL_PRESENCE_OP_H_ + +#include "event_op.h" + +LINPHONE_BEGIN_NAMESPACE + +class SalPresenceOp: public SalSubscribeOp { +public: + SalPresenceOp(Sal *sal): SalSubscribeOp(sal) {} + + int subscribe(const char *from, const char *to, int expires); + int unsubscribe() {return SalOp::unsubscribe();} + int notify_presence(SalPresenceModel *presence); + int notify_presence_close(); + +private: + virtual void fill_cbs() override; + void handle_notify(belle_sip_request_t *req, belle_sip_dialog_t *dialog); + SalPresenceModel * process_presence_notification(belle_sip_request_t *req); + int check_dialog_state(); + belle_sip_request_t *create_presence_notify(); + void add_presence_info(belle_sip_message_t *notify, SalPresenceModel *presence); + + static SalSubscribeStatus belle_sip_message_get_subscription_state(const belle_sip_message_t *msg); + + static void presence_process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event); + static void presence_response_event_cb(void *op_base, const belle_sip_response_event_t *event); + static void presence_refresher_listener_cb(belle_sip_refresher_t* refresher, void* user_pointer, unsigned int status_code, const char* reason_phrase, int will_retry); + static void presence_process_timeout_cb(void *user_ctx, const belle_sip_timeout_event_t *event); + static void presence_process_transaction_terminated_cb(void *user_ctx, const belle_sip_transaction_terminated_event_t *event); + static void presence_process_request_event_cb(void *op_base, const belle_sip_request_event_t *event); + static void presence_process_dialog_terminated_cb(void *ctx, const belle_sip_dialog_terminated_event_t *event); + static void _release_cb(SalOp *op_base); +}; + +LINPHONE_END_NAMESPACE + +#endif diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/sal/register_op.cpp similarity index 51% rename from coreapi/bellesip_sal/sal_op_registration.c rename to coreapi/sal/register_op.cpp index e21e88803..d06875a22 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/sal/register_op.cpp @@ -1,40 +1,64 @@ -/* -linphone -Copyright (C) 2012 Belledonne Communications, Grenoble, France +#include "register_op.h" +#include "bellesip_sal/sal_impl.h" -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. +using namespace std; -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. +LINPHONE_BEGIN_NAMESPACE -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 "sal_impl.h" +int SalRegisterOp::register_(const char *proxy, const char *from, int expires, const SalAddress* old_contact) { + belle_sip_request_t *req; + belle_sip_uri_t* req_uri; + belle_sip_header_t* accept_header; + if (this->refresher){ + belle_sip_refresher_stop(this->refresher); + belle_sip_object_unref(this->refresher); + this->refresher=NULL; + } -static void register_refresher_listener (belle_sip_refresher_t* refresher - ,void* user_pointer - ,unsigned int status_code - ,const char* reason_phrase, int will_retry) { - SalOp* op = (SalOp*)user_pointer; + this->type=Type::Register; + set_from(from); + set_to(from); + set_route(proxy); + req = build_request("REGISTER"); + req_uri = belle_sip_request_get_uri(req); + belle_sip_uri_set_user(req_uri,NULL); /*remove userinfo if any*/ + if (this->root->_use_dates) { + time_t curtime=time(NULL); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime))); + } + accept_header = belle_sip_header_create("Accept", "application/sdp, text/plain, application/vnd.gsma.rcs-ft-http+xml"); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req), accept_header); + belle_sip_message_set_header(BELLE_SIP_MESSAGE(req),(belle_sip_header_t*)create_contact()); + if (old_contact) { + belle_sip_header_contact_t *contact=belle_sip_header_contact_create((const belle_sip_header_address_t *)old_contact); + if (contact) { + char * tmp; + belle_sip_header_contact_set_expires(contact,0); /*remove old aor*/ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req), BELLE_SIP_HEADER(contact)); + tmp = belle_sip_object_to_string(contact); + ms_message("Clearing contact [%s] for op [%p]",tmp,this); + ms_free(tmp); + } else { + ms_error("Cannot add old contact header to op [%p]",this); + } + } + return send_and_create_refresher(req,expires,register_refresher_listener); +} + +void SalRegisterOp::register_refresher_listener(belle_sip_refresher_t* refresher, void* user_pointer, unsigned int status_code, const char* reason_phrase, int will_retry) { + SalRegisterOp * op = (SalRegisterOp *)user_pointer; belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher))); - ms_message("Register refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase,sal_op_get_proxy(op)); + ms_message("Register refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase,op->get_proxy()); if (belle_sip_refresher_get_auth_events(refresher)) { if (op->auth_info) sal_auth_info_delete(op->auth_info); /*only take first one for now*/ op->auth_info=sal_auth_info_create((belle_sip_auth_event_t*)(belle_sip_refresher_get_auth_events(refresher)->data)); } - sal_error_info_set(&op->error_info,SalReasonUnknown, "SIP", (int)status_code,reason_phrase,NULL); + sal_error_info_set(&op->error_info,SalReasonUnknown, "SIP", status_code,reason_phrase,NULL); if (status_code>=200){ - sal_op_assign_recv_headers(op,(belle_sip_message_t*)response); + op->assign_recv_headers((belle_sip_message_t*)response); } if(status_code == 200) { /*check service route rfc3608*/ @@ -44,23 +68,24 @@ static void register_refresher_listener (belle_sip_refresher_t* refresher if ((service_route=belle_sip_message_get_header_by_type(response,belle_sip_header_service_route_t))) { service_route_address=belle_sip_header_address_create(NULL,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(service_route))); } - sal_op_set_service_route(op,(const SalAddress*)service_route_address); + op->set_service_route((const SalAddress*)service_route_address); if (service_route_address) belle_sip_object_unref(service_route_address); - sal_remove_pending_auth(op->base.root,op); /*just in case*/ + op->root->remove_pending_auth(op); /*just in case*/ if (contact) { const char *gruu; belle_sip_parameters_t* p = (BELLE_SIP_PARAMETERS(contact)); if((gruu = belle_sip_parameters_get_parameter(p, "pub-gruu"))) { char *unquoted = belle_sip_unquote_strdup(gruu); - sal_op_set_contact_address(op, (SalAddress*)belle_sip_header_address_parse(unquoted)); + op->set_contact_address((SalAddress*)belle_sip_header_address_parse(unquoted)); + bctbx_free(unquoted); belle_sip_parameters_remove_parameter(p, "pub-gruu"); } else { - sal_op_set_contact_address(op, (SalAddress*)(BELLE_SIP_HEADER_ADDRESS(contact))); /*update contact with real value*/ + op->set_contact_address((SalAddress*)(BELLE_SIP_HEADER_ADDRESS(contact))); /*update contact with real value*/ } } - op->base.root->callbacks.register_success(op,belle_sip_refresher_get_expires(op->refresher)>0); + op->root->callbacks.register_success(op,belle_sip_refresher_get_expires(op->refresher)>0); } else if (status_code>=400) { /* from rfc3608, 6.1. If the UA refreshes the registration, the stored value of the Service- @@ -71,67 +96,17 @@ static void register_refresher_listener (belle_sip_refresher_t* refresher request is refused or if an existing registration expires and the UA chooses not to re-register, the UA SHOULD discard any stored service route for that address-of-record. */ - sal_op_set_service_route(op,NULL); - sal_op_ref(op); /*take a ref while invoking the callback to make sure the operations done after are valid*/ - op->base.root->callbacks.register_failure(op); - if (op->state!=SalOpStateTerminated && op->auth_info) { + op->set_service_route(NULL); + op->ref(); /*take a ref while invoking the callback to make sure the operations done after are valid*/ + op->root->callbacks.register_failure(op); + if (op->state!=State::Terminated && op->auth_info) { /*add pending auth*/ - sal_add_pending_auth(op->base.root,op); + op->root->add_pending_auth(op); if (status_code==403 || status_code==401 || status_code==407 ) - op->base.root->callbacks.auth_failure(op,op->auth_info); + op->root->callbacks.auth_failure(op,op->auth_info); } - sal_op_unref(op); + op->unref(); } } -int sal_register(SalOp *op, const char *proxy, const char *from, int expires, const SalAddress* old_contact){ - belle_sip_request_t *req; - belle_sip_uri_t* req_uri; - belle_sip_header_t* accept_header; - - if (op->refresher){ - belle_sip_refresher_stop(op->refresher); - belle_sip_object_unref(op->refresher); - op->refresher=NULL; - } - - op->type=SalOpRegister; - sal_op_set_from(op,from); - sal_op_set_to(op,from); - sal_op_set_route(op,proxy); - req = sal_op_build_request(op,"REGISTER"); - req_uri = belle_sip_request_get_uri(req); - belle_sip_uri_set_user(req_uri,NULL); /*remove userinfo if any*/ - if (op->base.root->use_dates){ - time_t curtime=time(NULL); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime))); - } - accept_header = belle_sip_header_create("Accept", "application/sdp, text/plain, application/vnd.gsma.rcs-ft-http+xml"); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req), accept_header); - belle_sip_message_set_header(BELLE_SIP_MESSAGE(req),(belle_sip_header_t*)sal_op_create_contact(op)); - if (old_contact) { - belle_sip_header_contact_t *contact=belle_sip_header_contact_create((const belle_sip_header_address_t *)old_contact); - if (contact) { - char * tmp; - belle_sip_header_contact_set_expires(contact,0); /*remove old aor*/ - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req), BELLE_SIP_HEADER(contact)); - tmp = belle_sip_object_to_string(contact); - ms_message("Clearing contact [%s] for op [%p]",tmp,op); - ms_free(tmp); - } else { - ms_error("Cannot add old contact header to op [%p]",op); - } - } - return sal_op_send_and_create_refresher(op,req,expires,register_refresher_listener); -} - -int sal_register_refresh(SalOp *op, int expires){ - if (op->refresher) - return belle_sip_refresher_refresh(op->refresher,expires); - else - return -1; -} - -int sal_unregister(SalOp *op){ - return sal_register_refresh(op,0); -} +LINPHONE_END_NAMESPACE diff --git a/coreapi/sal/register_op.h b/coreapi/sal/register_op.h new file mode 100644 index 000000000..a8f2c03c0 --- /dev/null +++ b/coreapi/sal/register_op.h @@ -0,0 +1,43 @@ +/* +register_op.h +Copyright (C) 2017 Belledonne Communications + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _SAL_REGISTER_OP_H_ +#define _SAL_REGISTER_OP_H_ + +#include "sal_op.h" + +LINPHONE_BEGIN_NAMESPACE + +class SalRegisterOp: public SalOp { +public: + SalRegisterOp(Sal *sal): SalOp(sal) {} + int register_(const char *proxy, const char *from, int expires, const SalAddress* old_contact); + int register_refresh(int expires) {return this->refresher ? belle_sip_refresher_refresh(this->refresher,expires) : -1;} + int unregister() {return register_refresh(0);} + + virtual void authenticate(const SalAuthInfo *info) override {register_refresh(-1);} + +private: + virtual void fill_cbs() override {}; + static void register_refresher_listener(belle_sip_refresher_t* refresher, void* user_pointer, unsigned int status_code, const char* reason_phrase, int will_retry); +}; + +LINPHONE_END_NAMESPACE + +#endif diff --git a/coreapi/sal/sal.c b/coreapi/sal/sal.c index e61232fc9..4dee10831 100644 --- a/coreapi/sal/sal.c +++ b/coreapi/sal/sal.c @@ -174,6 +174,98 @@ int sal_media_description_get_nb_active_streams(const SalMediaDescription *md) { return nb; } +SalMimeType *sal_mime_type_new(const char *type, const char *subtype) { + SalMimeType *mime_type = bctbx_new0(SalMimeType, 1); + if (type) mime_type->type = bctbx_strdup(type); + if (subtype) mime_type->subtype = bctbx_strdup(subtype); + return mime_type; +} + +SalMimeType *sal_mime_type_copy(const SalMimeType *mime_type) { + SalMimeType *new_mime_type = bctbx_new0(SalMimeType, 1); + if (mime_type->type) new_mime_type->type = bctbx_strdup(mime_type->type); + if (mime_type->subtype) new_mime_type->subtype = bctbx_strdup(mime_type->subtype); + return new_mime_type; +} + +SalMimeType *sal_mime_type_ref(SalMimeType *mime_type) { + if (!mime_type) return NULL; + mime_type->ref++; + return mime_type; +} + +void sal_mime_type_unref(SalMimeType *mime_type) { + mime_type->ref--; + if (mime_type->ref <= 0) { + if (mime_type->type) bctbx_free(mime_type->type); + if (mime_type->subtype) bctbx_free(mime_type->subtype); + } + bctbx_free(mime_type); +} + +SalCustomBody *sal_custom_body_new(SalMimeType *type) { + if (type == NULL) { + bctbx_error("creating a SalCustomBody from NULL SalMimeType"); + return NULL; + } + SalCustomBody *body = bctbx_new0(SalCustomBody, 1); + body->type = sal_mime_type_ref(type); + return body; +} + +SalCustomBody *sal_custom_body_new_with_buffer_copy(SalMimeType *type, const char *raw_data, size_t data_length) { + SalCustomBody *body = sal_custom_body_new(type); + if (body == NULL) return NULL; + body->data_length = data_length; + if (data_length > 0 && raw_data) { + body->raw_data = bctbx_new(char, data_length); + memcpy(body->raw_data, raw_data, data_length); + } + return body; +} + +SalCustomBody *sal_custom_body_new_with_buffer_moving(SalMimeType *type, char *raw_data, size_t data_length) { + SalCustomBody *body = sal_custom_body_new(type); + if (body == NULL) return NULL; + sal_custom_body_set_buffer_by_moving(body, raw_data, data_length); + return body; +} + +SalCustomBody *sal_custom_body_ref(SalCustomBody *body) { + if (!body) return NULL; + body->ref++; + return body; +} + +void sal_custom_body_unref(SalCustomBody *body) { + body->ref--; + if (body->ref <= 0) { + if (body->type) sal_mime_type_unref(body->type); + if (body->raw_data) bctbx_free(body->raw_data); + } + bctbx_free(body); +} + +void sal_custom_body_set_buffer_by_copy(SalCustomBody *body, const char *buffer, size_t length) { + char *buff_copy = NULL; + if (buffer && length > 0) { + buff_copy = bctbx_new(char, length); + memcpy(buff_copy, buffer, length); + } else length = 0; + sal_custom_body_set_buffer_by_moving(body, buff_copy, length); +} + +void sal_custom_body_set_buffer_by_moving(SalCustomBody *body, char *buffer, size_t length) { + if (body->raw_data) bctbx_free(body->raw_data); + if (length > 0 && buffer) { + body->raw_data = buffer; + body->data_length = length; + } else { + body->raw_data = NULL; + body->data_length = length; + } +} + static bool_t is_null_address(const char *addr){ return strcmp(addr,"0.0.0.0")==0 || strcmp(addr,"::0")==0; } @@ -495,6 +587,7 @@ int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaD return result; } +#if 0 static void assign_address(SalAddress** address, const char *value){ if (*address){ sal_address_destroy(*address); @@ -552,9 +645,11 @@ void sal_op_set_route(SalOp *op, const char *route){ assign_string(&op_base->route,route_string); \ if(route_string) ms_free(route_string); } + const bctbx_list_t* sal_op_get_route_addresses(const SalOp *op) { return ((SalOpBase*)op)->route_addresses; } + void sal_op_set_route_address(SalOp *op, const SalAddress *address){ char* address_string=sal_address_as_string(address); /*can probably be optimized*/ sal_op_set_route(op,address_string); @@ -606,6 +701,7 @@ Sal *sal_op_get_sal(const SalOp *op){ const char *sal_op_get_from(const SalOp *op){ return ((SalOpBase*)op)->from; } + const SalAddress *sal_op_get_from_address(const SalOp *op){ return ((SalOpBase*)op)->from_address; } @@ -637,6 +733,7 @@ const char *sal_op_get_proxy(const SalOp *op){ const char *sal_op_get_network_origin(const SalOp *op){ return ((SalOpBase*)op)->origin; } + const char* sal_op_get_call_id(const SalOp *op) { return ((SalOpBase*)op)->call_id; } @@ -721,6 +818,9 @@ void __sal_op_free(SalOp *op){ sal_media_description_unref(b->local_media); if (b->remote_media) sal_media_description_unref(b->remote_media); + if (b->custom_body) { + sal_custom_body_unref(b->custom_body); + } if (b->call_id) ms_free((void*)b->call_id); if (b->service_route) { @@ -741,6 +841,7 @@ void __sal_op_free(SalOp *op){ } ms_free(op); } +#endif SalAuthInfo* sal_auth_info_new() { return ms_new0(SalAuthInfo,1); @@ -829,15 +930,18 @@ const char* sal_reason_to_string(const SalReason reason) { default: return "Unkown reason"; } } +#if 0 const SalAddress* sal_op_get_service_route(const SalOp *op) { return ((SalOpBase*)op)->service_route; } + void sal_op_set_service_route(SalOp *op,const SalAddress* service_route) { if (((SalOpBase*)op)->service_route) sal_address_destroy(((SalOpBase*)op)->service_route); ((SalOpBase*)op)->service_route=service_route?sal_address_clone(service_route):NULL; } +#endif const char* sal_presence_status_to_string(const SalPresenceStatus status) { switch (status) { @@ -911,6 +1015,7 @@ int sal_lines_get_value(const char *data, const char *key, char *value, size_t v return FALSE; } +#if 0 const char *sal_op_get_entity_tag(const SalOp* op) { SalOpBase* op_base = (SalOpBase*)op; return op_base->entity_tag; @@ -927,3 +1032,4 @@ void sal_op_set_entity_tag(SalOp *op, const char* entity_tag) { else op_base->entity_tag = NULL; } +#endif diff --git a/coreapi/sal/sal.cpp b/coreapi/sal/sal.cpp new file mode 100644 index 000000000..200ca30ad --- /dev/null +++ b/coreapi/sal/sal.cpp @@ -0,0 +1,976 @@ +#include "sal.hpp" +#include "call_op.h" +#include "presence_op.h" +#include "event_op.h" +#include "message_op.h" +#include "bellesip_sal/sal_impl.h" +#include "tester_utils.h" +#include "private.h" + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +void Sal::process_dialog_terminated_cb(void *sal, const belle_sip_dialog_terminated_event_t *event) { + belle_sip_dialog_t* dialog = belle_sip_dialog_terminated_event_get_dialog(event); + SalOp* op = reinterpret_cast(belle_sip_dialog_get_application_data(dialog)); + if (op && op->callbacks && op->callbacks->process_dialog_terminated) { + op->callbacks->process_dialog_terminated(op,event); + } else { + ms_error("sal process_dialog_terminated no op found for this dialog [%p], ignoring",dialog); + } +} + +void Sal::process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event){ + belle_sip_client_transaction_t*client_transaction; + SalOp* op; + if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(belle_sip_io_error_event_get_source(event),belle_sip_client_transaction_t)) { + client_transaction=BELLE_SIP_CLIENT_TRANSACTION(belle_sip_io_error_event_get_source(event)); + op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); + /*also reset auth count on IO error*/ + op->auth_requests=0; + if (op->callbacks && op->callbacks->process_io_error) { + op->callbacks->process_io_error(op,event); + } + } else { + /*ms_error("sal process_io_error not implemented yet for non transaction");*/ + /*nop, because already handle at transaction layer*/ + } +} + +void Sal::process_request_event_cb(void *ud, const belle_sip_request_event_t *event) { + Sal *sal=(Sal*)ud; + SalOp* op=NULL; + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_dialog_t* dialog=belle_sip_request_event_get_dialog(event); + belle_sip_header_address_t* origin_address; + belle_sip_header_address_t* address=NULL; + belle_sip_header_from_t* from_header; + belle_sip_header_to_t* to; + belle_sip_header_diversion_t* diversion; + belle_sip_response_t* resp; + belle_sip_header_t *evh; + const char *method=belle_sip_request_get_method(req); + belle_sip_header_contact_t* remote_contact = belle_sip_message_get_header_by_type(req, belle_sip_header_contact_t); + + from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); + + if (dialog) { + op=(SalOp*)belle_sip_dialog_get_application_data(dialog); + + if (op == NULL && strcmp("NOTIFY",method) == 0) { + /*special case for Dialog created by notify mathing subscribe*/ + belle_sip_transaction_t * sub_trans = belle_sip_dialog_get_last_transaction(dialog); + op = (SalOp*)belle_sip_transaction_get_application_data(sub_trans); + } + if (op==NULL || op->state==SalOp::State::Terminated){ + ms_warning("Receiving request for null or terminated op [%p], ignored",op); + return; + } + }else{ + /*handle the case where we are receiving a request with to tag but it is not belonging to any dialog*/ + belle_sip_header_to_t *to = belle_sip_message_get_header_by_type(req, belle_sip_header_to_t); + if ((strcmp("INVITE",method)==0 || strcmp("NOTIFY",method)==0) && (belle_sip_header_to_get_tag(to) != NULL)) { + ms_warning("Receiving %s with to-tag but no know dialog here. Rejecting.", method); + resp=belle_sip_response_create_from_request(req,481); + belle_sip_provider_send_response(sal->prov,resp); + return; + /* by default (eg. when a to-tag is present), out of dialog ACK are automatically + handled in lower layers (belle-sip) but in case it misses, it will be forwarded to us */ + } else if (strcmp("ACK",method)==0 && (belle_sip_header_to_get_tag(to) == NULL)) { + ms_warning("Receiving ACK without to-tag but no know dialog here. Ignoring"); + return; + } + + if (strcmp("INVITE",method)==0) { + op=new SalCallOp(sal); + op->dir=SalOp::Dir::Incoming; + op->fill_cbs(); + }else if ((strcmp("SUBSCRIBE",method)==0 || strcmp("NOTIFY",method)==0) && (evh=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Event"))!=NULL) { + if (strncmp(belle_sip_header_get_unparsed_value(evh),"presence",strlen("presence"))==0){ + op=new SalPresenceOp(sal); + } else { + op=new SalSubscribeOp(sal); + } + op->dir=SalOp::Dir::Incoming; + op->fill_cbs(); + }else if (strcmp("MESSAGE",method)==0) { + op=new SalMessageOp(sal); + op->dir=SalOp::Dir::Incoming; + op->fill_cbs(); + }else if (strcmp("OPTIONS",method)==0) { + resp=belle_sip_response_create_from_request(req,200); + belle_sip_provider_send_response(sal->prov,resp); + return; + }else if (strcmp("INFO",method)==0) { + resp=belle_sip_response_create_from_request(req,481);/*INFO out of call dialogs are not allowed*/ + belle_sip_provider_send_response(sal->prov,resp); + return; + }else if (strcmp("BYE",method)==0) { + resp=belle_sip_response_create_from_request(req,481);/*out of dialog BYE */ + belle_sip_provider_send_response(sal->prov,resp); + return; + }else if (strcmp("CANCEL",method)==0) { + resp=belle_sip_response_create_from_request(req,481);/*out of dialog CANCEL */ + belle_sip_provider_send_response(sal->prov,resp); + return; + }else if (sal->_enable_test_features && strcmp("PUBLISH",method)==0) { + resp=belle_sip_response_create_from_request(req,200);/*out of dialog PUBLISH */ + belle_sip_message_add_header((belle_sip_message_t*)resp,belle_sip_header_create("SIP-Etag","4441929FFFZQOA")); + belle_sip_provider_send_response(sal->prov,resp); + return; + }else { + ms_error("sal process_request_event not implemented yet for method [%s]",belle_sip_request_get_method(req)); + resp=belle_sip_response_create_from_request(req,405); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp) + ,BELLE_SIP_HEADER(belle_sip_header_allow_create("INVITE, CANCEL, ACK, BYE, SUBSCRIBE, NOTIFY, MESSAGE, OPTIONS, INFO"))); + belle_sip_provider_send_response(sal->prov,resp); + return; + } + } + + if (!op->from_address) { + if (belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))) + address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) + ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); + else if ((belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(from_header)))) + address=belle_sip_header_address_create2(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) + ,belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); + else + ms_error("Cannot not find from uri from request [%p]",req); + op->set_from_address((SalAddress*)address); + belle_sip_object_unref(address); + } + + if( remote_contact ){ + op->set_remote_contact(belle_sip_header_get_unparsed_value(BELLE_SIP_HEADER(remote_contact))); + } + + if (!op->to_address) { + to=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_to_t); + if (belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to))) + address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(to)) + ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to))); + else if ((belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(to)))) + address=belle_sip_header_address_create2(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(to)) + ,belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(to))); + else + ms_error("Cannot not find to uri from request [%p]",req); + + op->set_to_address((SalAddress*)address); + belle_sip_object_unref(address); + } + + if(!op->diversion_address){ + diversion=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_diversion_t); + if (diversion) { + if (belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(diversion))) + address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(diversion)) + ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(diversion))); + else if ((belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(diversion)))) + address=belle_sip_header_address_create2(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(diversion)) + ,belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(diversion))); + else + ms_warning("Cannot not find diversion header from request [%p]",req); + if (address) { + op->set_diversion_address((SalAddress*)address); + belle_sip_object_unref(address); + } + } + } + + if (!op->origin) { + /*set origin uri*/ + origin_address=belle_sip_header_address_create(NULL,belle_sip_request_extract_origin(req)); + op->set_network_origin_address((SalAddress*)origin_address); + belle_sip_object_unref(origin_address); + } + if (!op->remote_ua) { + op->set_remote_ua(BELLE_SIP_MESSAGE(req)); + } + + if (!op->call_id) { + op->call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_call_id_t)))); + } + /*It is worth noting that proxies can (and + will) remove this header field*/ + op->set_privacy_from_message((belle_sip_message_t*)req); + + op->assign_recv_headers((belle_sip_message_t*)req); + if (op->callbacks && op->callbacks->process_request_event) { + op->callbacks->process_request_event(op,event); + } else { + ms_error("sal process_request_event not implemented yet"); + } + +} + +void Sal::process_response_event_cb(void *user_ctx, const belle_sip_response_event_t *event) { + belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); + belle_sip_response_t* response = belle_sip_response_event_get_response(event); + int response_code = belle_sip_response_get_status_code(response); + + if (!client_transaction) { + ms_warning("Discarding stateless response [%i]",response_code); + return; + } else { + SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); + belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); + belle_sip_header_contact_t* remote_contact = belle_sip_message_get_header_by_type(response, belle_sip_header_contact_t); + + if (op->state == SalOp::State::Terminated) { + belle_sip_message("Op [%p] is terminated, nothing to do with this [%i]", op, response_code); + return; + } + /*do it all the time, since we can receive provisional responses from a different instance than the final one*/ + op->set_remote_ua(BELLE_SIP_MESSAGE(response)); + + if(remote_contact) { + op->set_remote_contact(belle_sip_header_get_unparsed_value(BELLE_SIP_HEADER(remote_contact))); + } + + if (!op->call_id) { + op->call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(response), belle_sip_header_call_id_t)))); + } + + op->assign_recv_headers((belle_sip_message_t*)response); + + if (op->callbacks && op->callbacks->process_response_event) { + /*handle authorization*/ + switch (response_code) { + case 200: + break; + case 401: + case 407: + if (op->state == SalOp::State::Terminating && strcmp("BYE",belle_sip_request_get_method(request))!=0) { + /*only bye are completed*/ + belle_sip_message("Op is in state terminating, nothing else to do "); + } else { + if (op->pending_auth_transaction){ + belle_sip_object_unref(op->pending_auth_transaction); + op->pending_auth_transaction=NULL; + } + if (++op->auth_requests > 2) { + ms_warning("Auth info cannot be found for op [%s/%s] after 2 attempts, giving up",op->get_from() + ,op->get_to()); + op->root->callbacks.auth_failure(op,op->auth_info); + op->root->remove_pending_auth(op); + } else { + op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction); + op->process_authentication(); + return; + } + } + break; + case 403: + if (op->auth_info) op->root->callbacks.auth_failure(op,op->auth_info); + break; + } + if (response_code >= 180 && response_code !=401 && response_code !=407 && response_code !=403) { + /*not an auth request*/ + op->auth_requests=0; + } + op->callbacks->process_response_event(op,event); + } else { + ms_error("Unhandled event response [%p]",event); + } + } +} + +void Sal::process_timeout_cb(void *user_ctx, const belle_sip_timeout_event_t *event) { + belle_sip_client_transaction_t* client_transaction = belle_sip_timeout_event_get_client_transaction(event); + SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); + if (op && op->callbacks && op->callbacks->process_timeout) { + op->callbacks->process_timeout(op,event); + } else { + ms_error("Unhandled event timeout [%p]",event); + } +} + +void Sal::process_transaction_terminated_cb(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { + belle_sip_client_transaction_t* client_transaction = belle_sip_transaction_terminated_event_get_client_transaction(event); + belle_sip_server_transaction_t* server_transaction = belle_sip_transaction_terminated_event_get_server_transaction(event); + belle_sip_transaction_t* trans; + SalOp* op; + + if(client_transaction) + trans=BELLE_SIP_TRANSACTION(client_transaction); + else + trans=BELLE_SIP_TRANSACTION(server_transaction); + + op = (SalOp*)belle_sip_transaction_get_application_data(trans); + if (op && op->callbacks && op->callbacks->process_transaction_terminated) { + op->callbacks->process_transaction_terminated(op,event); + } else { + ms_message("Unhandled transaction terminated [%p]",trans); + } + if (op) { + op->unref(); /*because every transaction ref op*/ + belle_sip_transaction_set_application_data(trans,NULL); /*no longuer reference something we do not ref to avoid futur access of a released op*/ + } +} + +void Sal::process_auth_requested_cb(void *sal, belle_sip_auth_event_t *event) { + SalAuthInfo* auth_info = sal_auth_info_create(event); + ((Sal*)sal)->callbacks.auth_requested(reinterpret_cast(sal),auth_info); + belle_sip_auth_event_set_passwd(event,(const char*)auth_info->password); + belle_sip_auth_event_set_ha1(event,(const char*)auth_info->ha1); + belle_sip_auth_event_set_userid(event,(const char*)auth_info->userid); + belle_sip_auth_event_set_signing_key(event,(belle_sip_signing_key_t *)auth_info->key); + belle_sip_auth_event_set_client_certificates_chain(event,(belle_sip_certificates_chain_t* )auth_info->certificates); + sal_auth_info_delete(auth_info); +} + +Sal::Sal(MSFactory *factory){ + belle_sip_listener_callbacks_t listener_callbacks = {0}; + + /*belle_sip_object_enable_marshal_check(TRUE);*/ + this->factory = factory; + /*first create the stack, which initializes the belle-sip object's pool for this thread*/ + this->stack = belle_sip_stack_new(NULL); + + this->user_agent=belle_sip_header_user_agent_new(); +#if defined(PACKAGE_NAME) && defined(LIBLINPHONE_VERSION) + belle_sip_header_user_agent_add_product(this->user_agent, PACKAGE_NAME "/" LIBLINPHONE_VERSION); +#else + belle_sip_header_user_agent_add_product(this->user_agent, "Unknown"); +#endif + append_stack_string_to_user_agent(); + belle_sip_object_ref(this->user_agent); + + this->prov = belle_sip_stack_create_provider(this->stack,NULL); + enable_nat_helper(TRUE); + + listener_callbacks.process_dialog_terminated=process_dialog_terminated_cb; + listener_callbacks.process_io_error=process_io_error_cb; + listener_callbacks.process_request_event=process_request_event_cb; + listener_callbacks.process_response_event=process_response_event_cb; + listener_callbacks.process_timeout=process_timeout_cb; + listener_callbacks.process_transaction_terminated=process_transaction_terminated_cb; + listener_callbacks.process_auth_requested=process_auth_requested_cb; + this->listener=belle_sip_listener_create_from_callbacks(&listener_callbacks, this); + belle_sip_provider_add_sip_listener(this->prov, this->listener); +} + +Sal::~Sal() { + belle_sip_object_unref(this->user_agent); + belle_sip_object_unref(this->prov); + belle_sip_object_unref(this->stack); + belle_sip_object_unref(this->listener); + if (this->supported) belle_sip_object_unref(this->supported); + bctbx_list_free_with_data(this->supported_tags,ms_free); + bctbx_list_free_with_data(this->supported_content_types, ms_free); + if (this->uuid) ms_free(this->uuid); + if (this->root_ca) ms_free(this->root_ca); + if (this->root_ca_data) ms_free(this->root_ca_data); +} + +void Sal::set_callbacks(const Callbacks *cbs) { + memcpy(&this->callbacks,cbs,sizeof(*cbs)); + if (this->callbacks.call_received==NULL) + this->callbacks.call_received=(OnCallReceivedCb)unimplemented_stub; + if (this->callbacks.call_ringing==NULL) + this->callbacks.call_ringing=(OnCallRingingCb)unimplemented_stub; + if (this->callbacks.call_accepted==NULL) + this->callbacks.call_accepted=(OnCallAcceptedCb)unimplemented_stub; + if (this->callbacks.call_failure==NULL) + this->callbacks.call_failure=(OnCallFailureCb)unimplemented_stub; + if (this->callbacks.call_terminated==NULL) + this->callbacks.call_terminated=(OnCallTerminatedCb)unimplemented_stub; + if (this->callbacks.call_released==NULL) + this->callbacks.call_released=(OnCallReleasedCb)unimplemented_stub; + if (this->callbacks.call_updating==NULL) + this->callbacks.call_updating=(OnCallUpdatingCb)unimplemented_stub; + if (this->callbacks.auth_failure==NULL) + this->callbacks.auth_failure=(OnAuthFailureCb)unimplemented_stub; + if (this->callbacks.register_success==NULL) + this->callbacks.register_success=(OnRegisterSuccessCb)unimplemented_stub; + if (this->callbacks.register_failure==NULL) + this->callbacks.register_failure=(OnRegisterFailureCb)unimplemented_stub; + if (this->callbacks.dtmf_received==NULL) + this->callbacks.dtmf_received=(OnDtmfReceivedCb)unimplemented_stub; + if (this->callbacks.notify==NULL) + this->callbacks.notify=(OnNotifyCb)unimplemented_stub; + if (this->callbacks.subscribe_received==NULL) + this->callbacks.subscribe_received=(OnSubscribeReceivedCb)unimplemented_stub; + if (this->callbacks.incoming_subscribe_closed==NULL) + this->callbacks.incoming_subscribe_closed=(OnIncomingSubscribeClosedCb)unimplemented_stub; + if (this->callbacks.parse_presence_requested==NULL) + this->callbacks.parse_presence_requested=(OnParsePresenceRequestedCb)unimplemented_stub; + if (this->callbacks.convert_presence_to_xml_requested==NULL) + this->callbacks.convert_presence_to_xml_requested=(OnConvertPresenceToXMLRequestedCb)unimplemented_stub; + if (this->callbacks.notify_presence==NULL) + this->callbacks.notify_presence=(OnNotifyPresenceCb)unimplemented_stub; + if (this->callbacks.subscribe_presence_received==NULL) + this->callbacks.subscribe_presence_received=(OnSubscribePresenceReceivedCb)unimplemented_stub; + if (this->callbacks.message_received==NULL) + this->callbacks.message_received=(OnMessageReceivedCb)unimplemented_stub; + if (this->callbacks.ping_reply==NULL) + this->callbacks.ping_reply=(OnPingReplyCb)unimplemented_stub; + if (this->callbacks.auth_requested==NULL) + this->callbacks.auth_requested=(OnAuthRequestedCb)unimplemented_stub; + if (this->callbacks.info_received==NULL) + this->callbacks.info_received=(OnInfoReceivedCb)unimplemented_stub; + if (this->callbacks.on_publish_response==NULL) + this->callbacks.on_publish_response=(OnPublishResponseCb)unimplemented_stub; + if (this->callbacks.on_expire==NULL) + this->callbacks.on_expire=(OnExpireCb)unimplemented_stub; +} + +void Sal::set_tls_properties(){ + belle_sip_listening_point_t *lp=belle_sip_provider_get_listening_point(this->prov,"TLS"); + if (lp){ + belle_sip_tls_listening_point_t *tlp=BELLE_SIP_TLS_LISTENING_POINT(lp); + belle_tls_crypto_config_t *crypto_config = belle_tls_crypto_config_new(); + int verify_exceptions = BELLE_TLS_VERIFY_NONE; + if (!this->tls_verify) verify_exceptions = BELLE_TLS_VERIFY_ANY_REASON; + else if (!this->tls_verify_cn) verify_exceptions = BELLE_TLS_VERIFY_CN_MISMATCH; + belle_tls_crypto_config_set_verify_exceptions(crypto_config, verify_exceptions); + if (this->root_ca != NULL) belle_tls_crypto_config_set_root_ca(crypto_config, this->root_ca); + if (this->root_ca_data != NULL) belle_tls_crypto_config_set_root_ca_data(crypto_config, this->root_ca_data); + if (this->ssl_config != NULL) belle_tls_crypto_config_set_ssl_config(crypto_config, this->ssl_config); + belle_sip_tls_listening_point_set_crypto_config(tlp, crypto_config); + belle_sip_object_unref(crypto_config); + } +} + +int Sal::add_listen_port(SalAddress* addr, bool_t is_tunneled) { + int result; + belle_sip_listening_point_t* lp; + if (is_tunneled){ +#ifdef TUNNEL_ENABLED + if (sal_address_get_transport(addr)!=SalTransportUDP){ + ms_error("Tunneled mode is only available for UDP kind of transports."); + return -1; + } + lp = belle_sip_tunnel_listening_point_new(this->stack, this->tunnel_client); + if (!lp){ + ms_error("Could not create tunnel listening point."); + return -1; + } +#else + ms_error("No tunnel support in library."); + return -1; +#endif + }else{ + lp = belle_sip_stack_create_listening_point(this->stack, + sal_address_get_domain(addr), + sal_address_get_port(addr), + sal_transport_to_string(sal_address_get_transport(addr))); + } + if (lp) { + belle_sip_listening_point_set_keep_alive(lp,this->keep_alive); + result = belle_sip_provider_add_listening_point(this->prov,lp); + if (sal_address_get_transport(addr)==SalTransportTLS) { + set_tls_properties(); + } + } else { + return -1; + } + return result; +} + +int Sal::set_listen_port(const char *addr, int port, SalTransport tr, bool_t is_tunneled) { + SalAddress* sal_addr = sal_address_new(NULL); + int result; + sal_address_set_domain(sal_addr,addr); + sal_address_set_port(sal_addr,port); + sal_address_set_transport(sal_addr,tr); + result = add_listen_port(sal_addr, is_tunneled); + sal_address_destroy(sal_addr); + return result; +} + +int Sal::get_listening_port(SalTransport tr){ + const char *tpn=sal_transport_to_string(tr); + belle_sip_listening_point_t *lp=belle_sip_provider_get_listening_point(this->prov, tpn); + if (lp){ + return belle_sip_listening_point_get_port(lp); + } + return 0; +} + +int Sal::unlisten_ports(){ + const belle_sip_list_t * lps = belle_sip_provider_get_listening_points(this->prov); + belle_sip_list_t * tmp_list = belle_sip_list_copy(lps); + belle_sip_list_for_each2 (tmp_list,(void (*)(void*,void*))remove_listening_point,this->prov); + belle_sip_list_free(tmp_list); + ms_message("sal_unlisten_ports done"); + return 0; +} + +int Sal::transport_available(SalTransport t) { + switch(t){ + case SalTransportUDP: + case SalTransportTCP: + return TRUE; + case SalTransportTLS: + return belle_sip_stack_tls_available(this->stack); + case SalTransportDTLS: + return FALSE; + } + return FALSE; +} + +void Sal::make_supported_header(){ + bctbx_list_t *it; + char *alltags=NULL; + size_t buflen=64; + size_t written=0; + + if (this->supported){ + belle_sip_object_unref(this->supported); + this->supported=NULL; + } + for(it=this->supported_tags;it!=NULL;it=it->next){ + const char *tag=(const char*)it->data; + size_t taglen=strlen(tag); + if (alltags==NULL || (written+taglen+1>=buflen)) alltags=reinterpret_cast(ms_realloc(alltags,(buflen=buflen*2))); + written+=snprintf(alltags+written,buflen-written,it->next ? "%s, " : "%s",tag); + } + if (alltags){ + this->supported=belle_sip_header_create("Supported",alltags); + if (this->supported){ + belle_sip_object_ref(this->supported); + } + ms_free(alltags); + } +} + +void Sal::set_supported_tags(const char* tags){ + this->supported_tags=bctbx_list_free_with_data(this->supported_tags,ms_free); + if (tags){ + char *iter; + char *buffer=ms_strdup(tags); + char *tag; + char *context=NULL; + iter=buffer; + while((tag=strtok_r(iter,", ",&context))!=NULL){ + iter=NULL; + this->supported_tags=bctbx_list_append(this->supported_tags,ms_strdup(tag)); + } + ms_free(buffer); + } + make_supported_header(); +} + +void Sal::add_supported_tag(const char* tag){ + bctbx_list_t *elem=bctbx_list_find_custom(this->supported_tags,(bctbx_compare_func)strcasecmp,tag); + if (!elem){ + this->supported_tags=bctbx_list_append(this->supported_tags,ms_strdup(tag)); + make_supported_header(); + } +} + +void Sal::remove_supported_tag(const char* tag){ + bctbx_list_t *elem=bctbx_list_find_custom(this->supported_tags,(bctbx_compare_func)strcasecmp,tag); + if (elem){ + ms_free(elem->data); + this->supported_tags=bctbx_list_erase_link(this->supported_tags,elem); + make_supported_header(); + } +} + +int Sal::reset_transports() { + ms_message("Reseting transports"); + belle_sip_provider_clean_channels(this->prov); + return 0; +} + +ortp_socket_t Sal::get_socket() const { + ms_warning("sal_get_socket is deprecated"); + return -1; +} + +void Sal::set_user_agent(const char *user_agent) { + belle_sip_header_user_agent_set_products(this->user_agent,NULL); + belle_sip_header_user_agent_add_product(this->user_agent,user_agent); +} + +const char* Sal::get_user_agent() const { + static char user_agent[255]; + belle_sip_header_user_agent_get_products_as_string(this->user_agent, user_agent, 254); + return user_agent; +} + +void Sal::append_stack_string_to_user_agent() { + char stack_string[64]; + snprintf(stack_string, sizeof(stack_string) - 1, "(belle-sip/%s)", belle_sip_version_to_string()); + belle_sip_header_user_agent_add_product(this->user_agent, stack_string); +} + +void Sal::set_keepalive_period(unsigned int value) { + const belle_sip_list_t* iterator; + belle_sip_listening_point_t* lp; + this->keep_alive=value; + for (iterator=belle_sip_provider_get_listening_points(this->prov);iterator!=NULL;iterator=iterator->next) { + lp=(belle_sip_listening_point_t*)iterator->data; + if (this->use_tcp_tls_keep_alive || strcasecmp(belle_sip_listening_point_get_transport(lp),"udp")==0) { + belle_sip_listening_point_set_keep_alive(lp,this->keep_alive); + } + } +} + +int Sal::set_tunnel(void *tunnelclient) { +#ifdef TUNNEL_ENABLED + this->tunnel_client=tunnelclient; + return 0; +#else + return -1; +#endif +} + +bool_t Sal::is_content_type_supported(const char *content_type) const { + bctbx_list_t *item; + for (item = this->supported_content_types; item != NULL; item = bctbx_list_next(item)) { + const char *item_content_type = (const char *)bctbx_list_get_data(item); + if (strcmp(item_content_type, content_type) == 0) return TRUE; + } + return FALSE; +} + +void Sal::add_content_type_support(const char *content_type) { + if ((content_type != NULL) && (is_content_type_supported(content_type) == FALSE)) { + this->supported_content_types = bctbx_list_append(this->supported_content_types, ms_strdup(content_type)); + } +} + +void Sal::use_rport(bool_t use_rports) { + belle_sip_provider_enable_rport(this->prov,use_rports); + ms_message("Sal use rport [%s]", use_rports ? "enabled" : "disabled"); +} + +void Sal::set_root_ca(const char* rootCa) { + if (this->root_ca) { + ms_free(this->root_ca); + this->root_ca = NULL; + } + if (rootCa) + this->root_ca = ms_strdup(rootCa); + set_tls_properties(); +} + +void Sal::set_root_ca_data(const char* data) { + if (this->root_ca_data) { + ms_free(this->root_ca_data); + this->root_ca_data = NULL; + } + if (data) + this->root_ca_data = ms_strdup(data); + set_tls_properties(); +} + +void Sal::verify_server_certificates(bool_t verify) { + this->tls_verify=verify; + set_tls_properties(); +} + +void Sal::verify_server_cn(bool_t verify) { + this->tls_verify_cn = verify; + set_tls_properties(); +} + +void Sal::set_ssl_config(void *ssl_config) { + this->ssl_config = ssl_config; + set_tls_properties(); +} + +void Sal::set_uuid(const char *uuid){ + if (this->uuid){ + ms_free(this->uuid); + this->uuid=NULL; + } + if (uuid) + this->uuid=ms_strdup(uuid); +} + +int Sal::create_uuid(char *uuid, size_t len) { + if (generate_uuid(uuid, len) == 0) { + set_uuid(uuid); + return 0; + } + return -1; +} + +int Sal::generate_uuid(char *uuid, size_t len) { + sal_uuid_t uuid_struct; + int i; + int written; + + if (len==0) return -1; + /*create an UUID as described in RFC4122, 4.4 */ + belle_sip_random_bytes((unsigned char*)&uuid_struct, sizeof(sal_uuid_t)); + uuid_struct.clock_seq_hi_and_reserved&=(unsigned char)~(1<<6); + uuid_struct.clock_seq_hi_and_reserved|=(unsigned char)1<<7; + uuid_struct.time_hi_and_version&=(unsigned char)~(0xf<<12); + uuid_struct.time_hi_and_version|=(unsigned char)4<<12; + + written=snprintf(uuid,len,"%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", uuid_struct.time_low, uuid_struct.time_mid, + uuid_struct.time_hi_and_version, uuid_struct.clock_seq_hi_and_reserved, + uuid_struct.clock_seq_low); + if ((written < 0) || ((size_t)written > (len +13))) { + ms_error("sal_create_uuid(): buffer is too short !"); + return -1; + } + for (i = 0; i < 6; i++) + written+=snprintf(uuid+written,len-written,"%2.2x", uuid_struct.node[i]); + uuid[len-1]='\0'; + return 0; +} + +void Sal::add_pending_auth(SalOp *op){ + if (bctbx_list_find(this->pending_auths,op)==NULL){ + this->pending_auths=bctbx_list_append(this->pending_auths,op); + op->has_auth_pending=TRUE; + } +} + +void Sal::remove_pending_auth(SalOp *op){ + if (op->has_auth_pending){ + op->has_auth_pending=FALSE; + if (bctbx_list_find(this->pending_auths,op)){ + this->pending_auths=bctbx_list_remove(this->pending_auths,op); + } + } +} + +void Sal::set_default_sdp_handling(SalOpSDPHandling sdp_handling_method) { + if (sdp_handling_method != SalOpSDPNormal ) ms_message("Enabling special SDP handling for all new SalOp in Sal[%p]!", this); + this->default_sdp_handling = sdp_handling_method; +} + +void Sal::enable_nat_helper(bool_t enable) { + this->_nat_helper_enabled=enable; + belle_sip_provider_enable_nat_helper(this->prov,enable); + ms_message("Sal nat helper [%s]",enable?"enabled":"disabled"); +} + +void Sal::get_default_local_ip(int address_family, char *ip, size_t iplen) { + strncpy(ip,address_family==AF_INET6 ? "::1" : "127.0.0.1",iplen); + ms_error("sal_get_default_local_ip() is deprecated."); +} + +void Sal::set_dns_servers(const bctbx_list_t *servers){ + belle_sip_list_t *l = NULL; + + /*we have to convert the bctbx_list_t into a belle_sip_list_t first*/ + for (; servers != NULL; servers = servers->next){ + l = belle_sip_list_append(l, servers->data); + } + belle_sip_stack_set_dns_servers(this->stack, l); + belle_sip_list_free(l); +} + +belle_sip_source_t *Sal::create_timer(belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms, const char* timer_name) { + belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(this->stack); + return belle_sip_main_loop_create_timeout(ml, func, data, timeout_value_ms, timer_name); +} + +void Sal::cancel_timer(belle_sip_source_t *timer) { + belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(this->stack); + belle_sip_main_loop_remove_source(ml, timer); +} + +belle_sip_response_t* Sal::create_response_from_request (belle_sip_request_t* req, int code ) { + belle_sip_response_t *resp=belle_sip_response_create_from_request(req,code); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(this->user_agent)); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp), this->supported); + return resp; +} + + + + +/***********************************/ +/* Global functions implementation */ +/***********************************/ + +int to_sip_code(SalReason r) { + int ret=500; + switch(r){ + case SalReasonNone: + ret=200; + break; + case SalReasonIOError: + ret=503; + break; + case SalReasonUnknown: + ret=400; + break; + case SalReasonBusy: + ret=486; + break; + case SalReasonDeclined: + ret=603; + break; + case SalReasonDoNotDisturb: + ret=600; + break; + case SalReasonForbidden: + ret=403; + break; + case SalReasonUnsupportedContent: + ret=415; + break; + case SalReasonNotFound: + ret=404; + break; + case SalReasonRedirect: + ret=302; + break; + case SalReasonTemporarilyUnavailable: + ret=480; + break; + case SalReasonServiceUnavailable: + ret=503; + break; + case SalReasonRequestPending: + ret=491; + break; + case SalReasonUnauthorized: + ret=401; + break; + case SalReasonNotAcceptable: + ret=488; /*or maybe 606 Not Acceptable ?*/ + break; + case SalReasonNoMatch: + ret=481; + break; + case SalReasonRequestTimeout: + ret=408; + break; + case SalReasonMovedPermanently: + ret=301; + break; + case SalReasonGone: + ret=410; + break; + case SalReasonAddressIncomplete: + ret=484; + break; + case SalReasonNotImplemented: + ret=501; + break; + case SalReasonServerTimeout: + ret=504; + break; + case SalReasonBadGateway: + ret=502; + break; + case SalReasonInternalError: + ret=500; + break; + } + return ret; +} + +LINPHONE_END_NAMESPACE + +/*******************************/ +/* C++ to C wrapping functions */ +/*******************************/ + +using namespace LINPHONE_NAMESPACE; + +extern "C" { + +Sal *linphone_core_get_sal(const LinphoneCore *lc) { + return lc->sal; +} + +SalOp *linphone_proxy_config_get_sal_op(const LinphoneProxyConfig *cfg) { + return cfg->op; +} + +SalOp *linphone_call_get_op_as_sal_op(const LinphoneCall *call) { + return linphone_call_get_op(call); +} + +Sal *sal_init(MSFactory *factory) { + return new Sal(factory); +} + +void sal_uninit(Sal* sal) { + delete sal; +} + +int sal_create_uuid(Sal *ctx, char *uuid, size_t len) { + return ctx->create_uuid(uuid, len); +} + +void sal_set_uuid(Sal *ctx, const char *uuid) { + ctx->set_uuid(uuid); +} + +void sal_default_set_sdp_handling(Sal* h, SalOpSDPHandling handling_method) { + h->set_default_sdp_handling(handling_method); +} + +void sal_set_send_error(Sal *sal,int value) { + sal->set_send_error(value); +} + +void sal_set_recv_error(Sal *sal,int value) { + sal->set_recv_error(value); +} + +int sal_enable_pending_trans_checking(Sal *sal, bool_t value) { + return sal->enable_pending_trans_checking(value); +} + +void sal_enable_unconditional_answer(Sal *sal,int value) { + sal->enable_unconditional_answer(value); +} + +void sal_set_dns_timeout(Sal* sal,int timeout) { + sal->set_dns_timeout(timeout); +} + +void sal_set_dns_user_hosts_file(Sal *sal, const char *hosts_file) { + sal->set_dns_user_hosts_file(hosts_file); +} + +void *sal_get_stack_impl(Sal *sal) { + return sal->get_stack_impl(); +} + +void sal_set_refresher_retry_after(Sal *sal,int value) { + sal->set_refresher_retry_after(value); +} + +int sal_get_refresher_retry_after(const Sal *sal) { + return sal->get_refresher_retry_after(); +} + +void sal_set_transport_timeout(Sal* sal,int timeout) { + sal->set_transport_timeout(timeout); +} + +void sal_enable_test_features(Sal*ctx, bool_t enabled) { + ctx->enable_test_features(enabled); +} + +int sal_transport_available(Sal *ctx, SalTransport t) { + return ctx->transport_available(t); +} + +const SalErrorInfo *sal_op_get_error_info(const SalOp *op) { + return op->get_error_info(); +} + +bool_t sal_call_dialog_request_pending(const SalOp *op) { + auto callOp = dynamic_cast(op); + return callOp->dialog_request_pending(); +} + +void sal_call_set_sdp_handling(SalOp *h, SalOpSDPHandling handling) { + auto callOp = dynamic_cast(h); + callOp->set_sdp_handling(handling); +} + +SalMediaDescription * sal_call_get_final_media_description(SalOp *h) { + auto callOp = dynamic_cast(h); + return callOp->get_final_media_description(); +} + +} diff --git a/coreapi/sal/sal.h b/coreapi/sal/sal.h index 1fda7a38a..e45e170cf 100644 --- a/coreapi/sal/sal.h +++ b/coreapi/sal/sal.h @@ -46,22 +46,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #endif #endif -#ifdef __cplusplus -extern "C" { -#endif - /*Dirty hack, keep in sync with mediastreamer2/include/mediastream.h */ #ifndef PAYLOAD_TYPE_FLAG_CAN_RECV #define PAYLOAD_TYPE_FLAG_CAN_RECV PAYLOAD_TYPE_USER_FLAG_1 #define PAYLOAD_TYPE_FLAG_CAN_SEND PAYLOAD_TYPE_USER_FLAG_2 #endif -struct Sal; - -typedef struct Sal Sal; - -struct SalOp; - -typedef struct SalOp SalOp; struct SalAddress; @@ -98,7 +87,9 @@ typedef enum { #define SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION (1<<6) /* use force graph reconstruction*/ #define SAL_MEDIA_DESCRIPTION_ICE_RESTART_DETECTED (1<<7) - +#ifdef __cplusplus +extern "C" { +#endif const char* sal_transport_to_string(SalTransport transport); SalTransport sal_transport_parse(const char*); @@ -146,12 +137,12 @@ const char *sal_address_get_password(const SalAddress *addr); void sal_address_set_header(SalAddress *addr, const char *header_name, const char *header_value); const char *sal_address_get_header(const SalAddress *addr, const char *name); -LINPHONE_PUBLIC Sal * sal_init(MSFactory *factory); -LINPHONE_PUBLIC void sal_uninit(Sal* sal); void sal_set_log_handler(BctbxLogFunc log_handler); -void sal_set_user_pointer(Sal *sal, void *user_data); -void *sal_get_user_pointer(const Sal *sal); + +#ifdef __cplusplus +} +#endif typedef enum { @@ -160,7 +151,7 @@ typedef enum { SalText, SalOther } SalStreamType; -const char* sal_stream_type_to_string(SalStreamType type); + typedef enum{ SalProtoRtpAvp, @@ -171,7 +162,6 @@ typedef enum{ SalProtoUdpTlsRtpSavpf, SalProtoOther }SalMediaProto; -const char* sal_media_proto_to_string(SalMediaProto type); typedef enum{ SalStreamSendRecv, @@ -179,8 +169,18 @@ typedef enum{ SalStreamRecvOnly, SalStreamInactive }SalStreamDir; + +#ifdef __cplusplus +extern "C" { +#endif + +const char* sal_stream_type_to_string(SalStreamType type); +const char* sal_media_proto_to_string(SalMediaProto type); const char* sal_stream_dir_to_string(SalStreamDir type); +#ifdef __cplusplus +} +#endif #define SAL_ENDPOINT_CANDIDATE_MAX 2 @@ -254,8 +254,8 @@ typedef struct SalStreamDescription{ char rtcp_cname[256]; int rtp_port; int rtcp_port; - MSList *payloads; /*user_data=(void*)((intptr_t)n); #define payload_type_get_number(pt) ((int)(intptr_t)(pt)->user_data) -/*misc*/ -void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t iplen); +#ifdef __cplusplus +extern "C" { +#endif -LINPHONE_PUBLIC belle_sip_resolver_context_t * sal_resolve_a(Sal* sal, const char *name, int port, int family, belle_sip_resolver_callback_t cb, void *data); -LINPHONE_PUBLIC belle_sip_resolver_context_t * sal_resolve(Sal *sal, const char *service, const char *transport, const char *name, int port, int family, belle_sip_resolver_callback_t cb, void *data); - SalCustomHeader *sal_custom_header_ref(SalCustomHeader *ch); void sal_custom_header_unref(SalCustomHeader *ch); SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value); @@ -861,9 +638,6 @@ SalCustomHeader *sal_custom_header_remove(SalCustomHeader *ch, const char *name) void sal_custom_header_free(SalCustomHeader *ch); SalCustomHeader *sal_custom_header_clone(const SalCustomHeader *ch); -const SalCustomHeader *sal_op_get_recv_custom_header(SalOp *op); - -void sal_op_set_sent_custom_header(SalOp *op, SalCustomHeader* ch); SalCustomSdpAttribute * sal_custom_sdp_attribute_append(SalCustomSdpAttribute *csa, const char *name, const char *value); @@ -877,50 +651,13 @@ void sal_enable_log(void); void sal_disable_log(void); void sal_set_log_level(OrtpLogLevel level); -/*internal API */ -void __sal_op_init(SalOp *b, Sal *sal); -void __sal_op_set_network_origin(SalOp *op, const char *origin /*a sip uri*/); -void __sal_op_set_network_origin_address(SalOp *op, SalAddress *origin); -void __sal_op_set_remote_contact(SalOp *op, const char *ct); -void __sal_op_free(SalOp *b); - -/*test api*/ -/*0 for no error*/ -LINPHONE_PUBLIC void sal_set_send_error(Sal *sal,int value); -/*1 for no error*/ -LINPHONE_PUBLIC void sal_set_recv_error(Sal *sal,int value); - -/*always answer 480 if value=true*/ -LINPHONE_PUBLIC void sal_enable_unconditional_answer(Sal *sal,int value); - -LINPHONE_PUBLIC bool_t sal_pending_trans_checking_enabled(const Sal *sal) ; -LINPHONE_PUBLIC int sal_enable_pending_trans_checking(Sal *sal, bool_t value) ; - - - -/*refresher retry after value in ms*/ -LINPHONE_PUBLIC void sal_set_refresher_retry_after(Sal *sal,int value); -LINPHONE_PUBLIC int sal_get_refresher_retry_after(const Sal *sal); -/*enable contact fixing*/ -void sal_nat_helper_enable(Sal *sal,bool_t enable); -bool_t sal_nat_helper_enabled(Sal *sal); - -LINPHONE_PUBLIC void sal_set_dns_timeout(Sal* sal,int timeout); -LINPHONE_PUBLIC int sal_get_dns_timeout(const Sal* sal); -LINPHONE_PUBLIC void sal_set_transport_timeout(Sal* sal,int timeout); -LINPHONE_PUBLIC int sal_get_transport_timeout(const Sal* sal); -void sal_set_dns_servers(Sal *sal, const MSList *servers); -LINPHONE_PUBLIC void sal_enable_dns_srv(Sal *sal, bool_t enable); -LINPHONE_PUBLIC bool_t sal_dns_srv_enabled(const Sal *sal); -LINPHONE_PUBLIC void sal_enable_dns_search(Sal *sal, bool_t enable); -LINPHONE_PUBLIC bool_t sal_dns_search_enabled(const Sal *sal); -LINPHONE_PUBLIC void sal_set_dns_user_hosts_file(Sal *sal, const char *hosts_file); -LINPHONE_PUBLIC const char *sal_get_dns_user_hosts_file(const Sal *sal); unsigned int sal_get_random(void); LINPHONE_PUBLIC char *sal_get_random_token(int size); unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size); +#if 0 belle_sip_source_t * sal_create_timer(Sal *sal, belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms, const char* timer_name); void sal_cancel_timer(Sal *sal, belle_sip_source_t *timer); +#endif //SalBodyHandler * sal_body_handler_new(const char *type, const char *subtype, void *data, size_t size, const char *encoding); SalBodyHandler * sal_body_handler_new(void); @@ -944,21 +681,11 @@ const char * sal_body_handler_get_header(const SalBodyHandler *body_handler, con /*this function parses a document with key=value pairs separated by new lines, and extracts the value for a given key*/ int sal_lines_get_value(const char *data, const char *key, char *value, size_t value_size); -LINPHONE_PUBLIC void *sal_get_stack_impl(Sal *sal); -const char* sal_op_get_public_address(SalOp *sal, int *port); -const char* sal_op_get_local_address(SalOp *sal, int *port); unsigned long sal_begin_background_task(const char *name, void (*max_time_reached)(void *), void *data); void sal_end_background_task(unsigned long id); /*Some old equipment may not only rely on attribute sendonly/recvonly/sendrecv/inative*/ -void sal_op_cnx_ip_to_0000_if_sendonly_enable(SalOp *sal,bool_t yesno); -bool_t sal_op_cnx_ip_to_0000_if_sendonly_enabled(SalOp *sal); - -void sal_set_http_proxy_host(Sal *sal, const char *host) ; -void sal_set_http_proxy_port(Sal *sal, int port) ; -const char *sal_get_http_proxy_host(const Sal *sal); -int sal_get_http_proxy_port(const Sal *sal); #ifdef __cplusplus } diff --git a/coreapi/sal/sal.hpp b/coreapi/sal/sal.hpp new file mode 100644 index 000000000..4cc74563b --- /dev/null +++ b/coreapi/sal/sal.hpp @@ -0,0 +1,319 @@ +/* +sal.hpp +Copyright (C) 2017 Belledonne Communications + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _SAL_HPP_ +#define _SAL_HPP_ + +#include "sal/sal.h" +#include "linphone/utils/general.h" + +LINPHONE_BEGIN_NAMESPACE + +class SalOp; +class SalCallOp; +class SalMessageOp; +class SalSubscribeOp; +class SalPresenceOp; + +class Sal{ +public: + typedef void (*OnCallReceivedCb)(SalCallOp *op); + typedef void (*OnCallRingingCb)(SalOp *op); + typedef void (*OnCallAcceptedCb)(SalOp *op); + typedef void (*OnCallAckReceivedCb)(SalOp *op, SalCustomHeader *ack); + typedef void (*OnCallAckBeingSentCb)(SalOp *op, SalCustomHeader *ack); + typedef void (*OnCallUpdatingCb)(SalOp *op, bool_t is_update);/* Called when a reINVITE/UPDATE is received*/ + typedef void (*OnCallTerminatedCb)(SalOp *op, const char *from); + typedef void (*OnCallFailureCb)(SalOp *op); + typedef void (*OnCallReleasedCb)(SalOp *salop); + typedef void (*OnCallCancelDoneCb)(SalOp *salop); + typedef void (*OnAuthRequestedLegacyCb)(SalOp *op, const char *realm, const char *username); + typedef bool_t (*OnAuthRequestedCb)(Sal *sal,SalAuthInfo* info); + typedef void (*OnAuthFailureCb)(SalOp *op, SalAuthInfo* info); + typedef void (*OnRegisterSuccessCb)(SalOp *op, bool_t registered); + typedef void (*OnRegisterFailureCb)(SalOp *op); + typedef void (*OnVfuRequestCb)(SalOp *op); + typedef void (*OnDtmfReceivedCb)(SalOp *op, char dtmf); + typedef void (*OnReferCb)(Sal *sal, SalOp *op, const char *referto); + typedef void (*OnMessageReceivedCb)(SalOp *op, const SalMessage *msg); + typedef void (*OnMessageDeliveryUpdateCb)(SalOp *op, SalMessageDeliveryStatus); + typedef void (*OnNotifyReferCb)(SalOp *op, SalReferStatus state); + typedef void (*OnSubscribeResponseCb)(SalOp *op, SalSubscribeStatus status, int will_retry); + typedef void (*OnNotifyCb)(SalSubscribeOp *op, SalSubscribeStatus status, const char *event, SalBodyHandler *body); + typedef void (*OnSubscribeReceivedCb)(SalSubscribeOp *salop, const char *event, const SalBodyHandler *body); + typedef void (*OnIncomingSubscribeClosedCb)(SalOp *salop); + typedef void (*OnParsePresenceRequestedCb)(SalOp *salop, const char *content_type, const char *content_subtype, const char *content, SalPresenceModel **result); + typedef void (*OnConvertPresenceToXMLRequestedCb)(SalOp *salop, SalPresenceModel *presence, const char *contact, char **content); + typedef void (*OnNotifyPresenceCb)(SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model, const char *msg); + typedef void (*OnSubscribePresenceReceivedCb)(SalPresenceOp *salop, const char *from); + typedef void (*OnSubscribePresenceClosedCb)(SalPresenceOp *salop, const char *from); + typedef void (*OnPingReplyCb)(SalOp *salop); + typedef void (*OnInfoReceivedCb)(SalOp *salop, SalBodyHandler *body); + typedef void (*OnPublishResponseCb)(SalOp *salop); + typedef void (*OnNotifyResponseCb)(SalOp *salop); + typedef void (*OnExpireCb)(SalOp *salop); + + struct Callbacks { + OnCallReceivedCb call_received; + OnCallReceivedCb call_rejected; + OnCallRingingCb call_ringing; + OnCallAcceptedCb call_accepted; + OnCallAckReceivedCb call_ack_received; + OnCallAckBeingSentCb call_ack_being_sent; + OnCallUpdatingCb call_updating; + OnCallTerminatedCb call_terminated; + OnCallFailureCb call_failure; + OnCallReleasedCb call_released; + OnCallCancelDoneCb call_cancel_done; + OnAuthFailureCb auth_failure; + OnRegisterSuccessCb register_success; + OnRegisterFailureCb register_failure; + OnVfuRequestCb vfu_request; + OnDtmfReceivedCb dtmf_received; + OnReferCb refer_received; + OnMessageReceivedCb message_received; + OnMessageDeliveryUpdateCb message_delivery_update; + OnNotifyReferCb notify_refer; + OnSubscribeReceivedCb subscribe_received; + OnIncomingSubscribeClosedCb incoming_subscribe_closed; + OnSubscribeResponseCb subscribe_response; + OnNotifyCb notify; + OnSubscribePresenceReceivedCb subscribe_presence_received; + OnSubscribePresenceClosedCb subscribe_presence_closed; + OnParsePresenceRequestedCb parse_presence_requested; + OnConvertPresenceToXMLRequestedCb convert_presence_to_xml_requested; + OnNotifyPresenceCb notify_presence; + OnPingReplyCb ping_reply; + OnAuthRequestedCb auth_requested; + OnInfoReceivedCb info_received; + OnPublishResponseCb on_publish_response; + OnExpireCb on_expire; + OnNotifyResponseCb on_notify_response; + }; + + Sal(MSFactory *factory); + ~Sal(); + + void set_user_pointer(void *user_data) {this->up=user_data;} + void *get_user_pointer() const {return this->up;} + + void set_callbacks(const Callbacks *cbs); + + void *get_stack_impl() {return this->stack;} + + int iterate() {belle_sip_stack_sleep(this->stack,0); return 0;} + + void set_send_error(int value) {belle_sip_stack_set_send_error(this->stack,value);} + void set_recv_error(int value) {belle_sip_provider_set_recv_error(this->prov,value);} + + + /******************/ + /* SIP parameters */ + /******************/ + void set_supported_tags(const char* tags); + const char *get_supported_tags() const {return this->supported ? belle_sip_header_get_unparsed_value(this->supported) : NULL;} + void add_supported_tag(const char* tag); + void remove_supported_tag(const char* tag); + + void set_user_agent(const char *user_agent); + const char* get_user_agent() const; + void append_stack_string_to_user_agent(); + + bool_t content_encoding_available(const char *content_encoding) {return (bool_t)belle_sip_stack_content_encoding_available(this->stack, content_encoding);} + bool_t is_content_type_supported(const char *content_type) const; + void add_content_type_support(const char *content_type); + + void set_default_sdp_handling(SalOpSDPHandling sdp_handling_method); + + void set_uuid(const char *uuid); + int create_uuid(char *uuid, size_t len); + static int generate_uuid(char *uuid, size_t len); + + void enable_nat_helper(bool_t enable); + bool_t nat_helper_enabled() const {return this->_nat_helper_enabled;} + + bool_t pending_trans_checking_enabled() const {return this->pending_trans_checking;} + int enable_pending_trans_checking(bool_t value) {this->pending_trans_checking = value; return 0;} + + void set_refresher_retry_after(int value) {this->refresher_retry_after=value;} + int get_refresher_retry_after() const {return this->refresher_retry_after;} + + void enable_sip_update_method(bool_t value) {this->enable_sip_update=value;} + void use_session_timers(int expires) {this->session_expires=expires;} + void use_dates(bool_t enabled) {this->_use_dates=enabled;} + void use_one_matching_codec_policy(bool_t one_matching_codec) {this->one_matching_codec=one_matching_codec;} + void use_rport(bool_t use_rports); + void enable_auto_contacts(bool_t enabled) {this->auto_contacts=enabled;} + void enable_test_features(bool_t enabled) {this->_enable_test_features=enabled;} + void use_no_initial_route(bool_t enabled) {this->no_initial_route=enabled;} + void enable_unconditional_answer(int value) {belle_sip_provider_enable_unconditional_answer(this->prov,value);} + + bctbx_list_t *get_pending_auths() const {return bctbx_list_copy(this->pending_auths);} + + + /**********************/ + /* Network parameters */ + /**********************/ + int set_listen_port(const char *addr, int port, SalTransport tr, bool_t is_tunneled); + int get_listening_port(SalTransport tr); + int transport_available(SalTransport t); + + void get_default_local_ip(int address_family, char *ip, size_t iplen); + + void set_transport_timeout(int timeout) {belle_sip_stack_set_transport_timeout(this->stack, timeout);} + int get_transport_timeout() const {return belle_sip_stack_get_transport_timeout(this->stack);} + + void set_keepalive_period(unsigned int value); + unsigned int get_keepalive_period() const {return this->keep_alive;} + void use_tcp_tls_keepalive(bool_t enabled) {this->use_tcp_tls_keep_alive=enabled;} + + void set_dscp(int dscp) {belle_sip_stack_set_default_dscp(this->stack,dscp);} + + int set_tunnel(void *tunnelclient); + + void set_http_proxy_host(const char *host) {belle_sip_stack_set_http_proxy_host(this->stack, host);} + const char *get_http_proxy_host() const {return belle_sip_stack_get_http_proxy_host(this->stack);} + + void set_http_proxy_port(int port) {belle_sip_stack_set_http_proxy_port(this->stack, port);} + int get_http_proxy_port() const {return belle_sip_stack_get_http_proxy_port(this->stack);} + + ortp_socket_t get_socket() const; + + int unlisten_ports(); + int reset_transports(); + + + /******************/ + /* TLS parameters */ + /******************/ + void set_ssl_config(void *ssl_config); + void set_root_ca(const char* rootCa); + void set_root_ca_data(const char* data); + const char *get_root_ca() const {return this->root_ca;} + + void verify_server_certificates(bool_t verify); + void verify_server_cn(bool_t verify); + + + /******************/ + /* DNS resolution */ + /******************/ + void set_dns_timeout(int timeout) {belle_sip_stack_set_dns_timeout(this->stack, timeout);} + int get_dns_timeout() const {return belle_sip_stack_get_dns_timeout(this->stack);} + + void set_dns_servers(const bctbx_list_t *servers); + + void enable_dns_search(bool_t enable) {belle_sip_stack_enable_dns_search(this->stack, (unsigned char)enable);} + bool_t dns_search_enabled() const {return (bool_t)belle_sip_stack_dns_search_enabled(this->stack);} + + void enable_dns_srv(bool_t enable) {belle_sip_stack_enable_dns_srv(this->stack, (unsigned char)enable);} + bool_t dns_srv_enabled() const {return (bool_t)belle_sip_stack_dns_srv_enabled(this->stack);} + + void set_dns_user_hosts_file(const char *hosts_file) {belle_sip_stack_set_dns_user_hosts_file(this->stack, hosts_file);} + const char *get_dns_user_hosts_file() const {return belle_sip_stack_get_dns_user_hosts_file(this->stack);} + + belle_sip_resolver_context_t *resolve_a(const char *name, int port, int family, belle_sip_resolver_callback_t cb, void *data) + {return belle_sip_stack_resolve_a(this->stack,name,port,family,cb,data);} + belle_sip_resolver_context_t *resolve(const char *service, const char *transport, const char *name, int port, int family, belle_sip_resolver_callback_t cb, void *data) + {return belle_sip_stack_resolve(this->stack, service, transport, name, port, family, cb, data);} + + + /**********/ + /* Timers */ + /**********/ + belle_sip_source_t *create_timer(belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms, const char* timer_name); + void cancel_timer(belle_sip_source_t *timer); + + +private: + struct sal_uuid_t { + unsigned int time_low; + unsigned short time_mid; + unsigned short time_hi_and_version; + unsigned char clock_seq_hi_and_reserved; + unsigned char clock_seq_low; + unsigned char node[6]; + }; + + void set_tls_properties(); + int add_listen_port(SalAddress* addr, bool_t is_tunneled); + void make_supported_header(); + void add_pending_auth(SalOp *op); + void remove_pending_auth(SalOp *op); + belle_sip_response_t* create_response_from_request (belle_sip_request_t* req, int code ); + + static void unimplemented_stub() {ms_warning("Unimplemented SAL callback");} + static void remove_listening_point(belle_sip_listening_point_t* lp,belle_sip_provider_t* prov) {belle_sip_provider_remove_listening_point(prov,lp);} + + /* Internal callbacks */ + static void process_dialog_terminated_cb(void *sal, const belle_sip_dialog_terminated_event_t *event); + static void process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event); + static void process_request_event_cb(void *ud, const belle_sip_request_event_t *event); + static void process_response_event_cb(void *user_ctx, const belle_sip_response_event_t *event); + static void process_timeout_cb(void *user_ctx, const belle_sip_timeout_event_t *event); + static void process_transaction_terminated_cb(void *user_ctx, const belle_sip_transaction_terminated_event_t *event); + static void process_auth_requested_cb(void *sal, belle_sip_auth_event_t *event); + + MSFactory *factory = NULL; + Callbacks callbacks = {0}; + MSList *pending_auths = NULL;/*MSList of SalOp */ + belle_sip_stack_t* stack = NULL; + belle_sip_provider_t *prov = NULL; + belle_sip_header_user_agent_t* user_agent = NULL; + belle_sip_listener_t *listener = NULL; + void *tunnel_client = NULL; + void *up = NULL; /*user pointer*/ + int session_expires = 0; + unsigned int keep_alive = 0; + char *root_ca = NULL; + char *root_ca_data = NULL; + char *uuid = NULL; + int refresher_retry_after = 60000; /*retry after value for refresher*/ + MSList *supported_tags = NULL;/*list of char * */ + belle_sip_header_t *supported = NULL; + bool_t one_matching_codec = FALSE; + bool_t use_tcp_tls_keep_alive = FALSE; + bool_t _nat_helper_enabled = FALSE; + bool_t tls_verify = TRUE; + bool_t tls_verify_cn = TRUE; + bool_t _use_dates = FALSE; + bool_t auto_contacts = TRUE; + bool_t _enable_test_features = FALSE; + bool_t no_initial_route = FALSE; + bool_t enable_sip_update = TRUE; /*true by default*/ + SalOpSDPHandling default_sdp_handling = SalOpSDPNormal; + bool_t pending_trans_checking = TRUE; /*testing purpose*/ + void *ssl_config = NULL; + bctbx_list_t *supported_content_types = NULL; /* list of char* */ + + friend class SalOp; + friend class SalCallOp; + friend class SalRegisterOp; + friend class SalMessageOp; + friend class SalPresenceOp; + friend class SalSubscribeOp; + friend class SalPublishOp; +}; + +int to_sip_code(SalReason r); + +LINPHONE_END_NAMESPACE + + +#endif // _LINPHONE_SAL_HH diff --git a/coreapi/sal/sal_op.cpp b/coreapi/sal/sal_op.cpp new file mode 100644 index 000000000..e2fa78e09 --- /dev/null +++ b/coreapi/sal/sal_op.cpp @@ -0,0 +1,1025 @@ +#include +#include "sal_op.h" +#include "bellesip_sal/sal_impl.h" + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +SalOp::SalOp(Sal *sal) { + this->root = sal; + this->sdp_handling = sal->default_sdp_handling; + memset(&this->error_info, 0, sizeof(this->error_info)); + memset(&this->reason_error_info, 0, sizeof(this->reason_error_info)); + ref(); +} + +SalOp::~SalOp() { + ms_message("Destroying op [%p] of type [%s]",this,to_string(this->type)); + + if (this->pending_auth_transaction) belle_sip_object_unref(this->pending_auth_transaction); + this->root->remove_pending_auth(this); + if (this->auth_info) { + sal_auth_info_delete(this->auth_info); + } + if (this->sdp_answer) belle_sip_object_unref(this->sdp_answer); + if (this->refresher) { + belle_sip_object_unref(this->refresher); + this->refresher=NULL; + } + if (this->result) + sal_media_description_unref(this->result); + if(this->replaces) belle_sip_object_unref(this->replaces); + if(this->referred_by) belle_sip_object_unref(this->referred_by); + + if (this->pending_client_trans) belle_sip_object_unref(this->pending_client_trans); + if (this->pending_server_trans) belle_sip_object_unref(this->pending_server_trans); + if (this->pending_update_server_trans) belle_sip_object_unref(this->pending_update_server_trans); + if (this->event) belle_sip_object_unref(this->event); + + sal_error_info_reset(&this->error_info); + if (this->from_address){ + sal_address_destroy(this->from_address); + this->from_address=NULL; + } + if (this->to_address){ + sal_address_destroy(this->to_address); + this->to_address=NULL; + } + + if (this->service_route){ + sal_address_destroy(this->service_route); + this->service_route=NULL; + } + + if (this->origin_address){ + sal_address_destroy(this->origin_address); + this->origin_address=NULL; + } + + if (this->from) { + ms_free(this->from); + this->from=NULL; + } + if (this->to) { + ms_free(this->to); + this->to=NULL; + } + if (this->route) { + ms_free(this->route); + this->route=NULL; + } + if (this->realm) { + ms_free(this->realm); + this->realm=NULL; + } + if (this->contact_address) { + sal_address_destroy(this->contact_address); + } + if (this->origin){ + ms_free(this->origin); + this->origin=NULL; + } + if (this->remote_ua){ + ms_free(this->remote_ua); + this->remote_ua=NULL; + } + if (this->remote_contact){ + ms_free(this->remote_contact); + this->remote_contact=NULL; + } + if (this->remote_contact_address){ + sal_address_destroy(this->remote_contact_address); + } + if (this->local_media) + sal_media_description_unref(this->local_media); + if (this->remote_media) + sal_media_description_unref(this->remote_media); + if (this->custom_body) { + sal_custom_body_unref(this->custom_body); + } + if (this->call_id) + ms_free((void *)this->call_id); + if (this->service_route) { + sal_address_destroy(this->service_route); + } + if (this->route_addresses){ + bctbx_list_for_each(this->route_addresses,(void (*)(void*)) sal_address_destroy); + this->route_addresses=bctbx_list_free(this->route_addresses); + } + if (this->recv_custom_headers) + sal_custom_header_free(this->recv_custom_headers); + if (this->sent_custom_headers) + sal_custom_header_free(this->sent_custom_headers); + + if (this->entity_tag != NULL){ + ms_free(this->entity_tag); + this->entity_tag = NULL; + } +} + +SalOp *SalOp::ref() { + _ref++; + return this; +} + +void *SalOp::unref() { + _ref--; + if (_ref==0) { + delete this; + } else if (_ref<0) { + ms_fatal("SalOp [%p]: too many unrefs.",this); + } + return NULL; +} + +void SalOp::set_contact_address(const SalAddress *address) { + if (this->contact_address) sal_address_destroy(this->contact_address); + this->contact_address=address?sal_address_clone(address):NULL; +} + +void SalOp::assign_address(SalAddress** address, const char *value) { + if (*address){ + sal_address_destroy(*address); + *address=NULL; + } + if (value) + *address=sal_address_new(value); +} + +void SalOp::assign_string(char **str, const char *arg) { + if (*str){ + ms_free(*str); + *str=NULL; + } + if (arg) + *str=ms_strdup(arg); +} + +void SalOp::set_route(const char *route) { + char* route_string=NULL; + if (this->route_addresses) { + bctbx_list_for_each(this->route_addresses,(void (*)(void *))sal_address_destroy); + this->route_addresses=bctbx_list_free(this->route_addresses); + } + if (route) { + this->route_addresses=bctbx_list_append(NULL,NULL); + assign_address((SalAddress**)&(this->route_addresses->data),route); + route_string=sal_address_as_string((SalAddress*)this->route_addresses->data); + } + assign_string(&this->route,route_string); + if(route_string) ms_free(route_string); +} + +void SalOp::set_route_address(const SalAddress *address){ + char* address_string=sal_address_as_string(address); /*can probably be optimized*/ + set_route(address_string); + ms_free(address_string); +} + +void SalOp::add_route_address(const SalAddress *address) { + if (this->route_addresses) { + this->route_addresses=bctbx_list_append(this->route_addresses,(void*)sal_address_clone(address)); + } else { + set_route_address(address); + } +} + +void SalOp::set_realm(const char *realm) { + if (this->realm != NULL){ + ms_free(this->realm); + } + this->realm = ms_strdup(realm); +} + +#define SET_PARAM(name) \ + char* name##_string=NULL; \ + assign_address(&this->name##_address,name); \ + if (this->name##_address) { \ + name##_string=sal_address_as_string(this->name##_address); \ + }\ + assign_string(&this->name,name##_string); \ + if(name##_string) ms_free(name##_string); + +void SalOp::set_from(const char *from){ + SET_PARAM(from); +} + +void SalOp::set_from_address(const SalAddress *from) { + char* address_string=sal_address_as_string(from); /*can probably be optimized*/ + set_from(address_string); + ms_free(address_string); +} + +void SalOp::set_to(const char *to) { + SET_PARAM(to); +} + +void SalOp::set_to_address(const SalAddress *to) { + char* address_string=sal_address_as_string(to); /*can probably be optimized*/ + set_to(address_string); + ms_free(address_string); +} + +void SalOp::set_diversion_address(const SalAddress *diversion) { + if (this->diversion_address) sal_address_destroy(this->diversion_address); + this->diversion_address=diversion ? sal_address_clone(diversion) : NULL; +} + +int SalOp::refresh() { + if (this->refresher) { + belle_sip_refresher_refresh(this->refresher,belle_sip_refresher_get_expires(this->refresher)); + return 0; + } + ms_warning("sal_refresh on op [%p] of type [%s] no refresher",this,to_string(this->type)); + return -1; +} + +void SalOp::kill_dialog() { + ms_warning("op [%p]: force kill of dialog [%p]", this, this->dialog); + belle_sip_dialog_delete(this->dialog); +} + +void SalOp::release() { + /*if in terminating state, keep this state because it means we are waiting for a response to be able to terminate the operation.*/ + if (this->state!=State::Terminating) + this->state=State::Terminated; + set_user_pointer(NULL);/*mandatory because releasing op doesn't not mean freeing op. Make sure back pointer will not be used later*/ + if (this->release_cb) + this->release_cb(this); + if (this->refresher) { + belle_sip_refresher_stop(this->refresher); + } + this->op_released = TRUE; + unref(); +} + +int SalOp::send_request_with_contact(belle_sip_request_t* request, bool_t add_contact) { + belle_sip_client_transaction_t* client_transaction; + belle_sip_provider_t* prov=this->root->prov; + belle_sip_uri_t* outbound_proxy=NULL; + belle_sip_header_contact_t* contact; + int result =-1; + belle_sip_uri_t *next_hop_uri=NULL; + + if (add_contact && !belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_contact_t)) { + contact = create_contact(); + belle_sip_message_set_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact)); + } /*keep existing*/ + + add_custom_headers((belle_sip_message_t*)request); + + if (!this->dialog || belle_sip_dialog_get_state(this->dialog) == BELLE_SIP_DIALOG_NULL) { + /*don't put route header if dialog is in confirmed state*/ + const MSList *elem=get_route_addresses(); + const char *transport; + const char *method=belle_sip_request_get_method(request); + belle_sip_listening_point_t *udplp=belle_sip_provider_get_listening_point(prov,"UDP"); + + if (elem) { + outbound_proxy=belle_sip_header_address_get_uri((belle_sip_header_address_t*)elem->data); + next_hop_uri=outbound_proxy; + }else{ + next_hop_uri=(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_request_get_uri(request)); + } + transport=belle_sip_uri_get_transport_param(next_hop_uri); + if (transport==NULL){ + /*compatibility mode: by default it should be udp as not explicitely set and if no udp listening point is available, then use + * the first available transport*/ + if (!belle_sip_uri_is_secure(next_hop_uri)){ + if (udplp==NULL){ + if (belle_sip_provider_get_listening_point(prov,"TCP")!=NULL){ + transport="tcp"; + }else if (belle_sip_provider_get_listening_point(prov,"TLS")!=NULL ){ + transport="tls"; + } + } + if (transport){ + belle_sip_message("Transport is not specified, using %s because UDP is not available.",transport); + belle_sip_uri_set_transport_param(next_hop_uri,transport); + } + } + }else{ +#ifdef TUNNEL_ENABLED + if (udplp && BELLE_SIP_OBJECT_IS_INSTANCE_OF(udplp,belle_sip_tunnel_listening_point_t)){ + /* our tunnel mode only supports UDP. Force transport to be set to UDP */ + belle_sip_uri_set_transport_param(next_hop_uri,"udp"); + } +#endif + } + /*because in case of tunnel, transport can be changed*/ + transport=belle_sip_uri_get_transport_param(next_hop_uri); + + if ((strcmp(method,"REGISTER")==0 || strcmp(method,"SUBSCRIBE")==0) && transport && + (strcasecmp(transport,"TCP")==0 || strcasecmp(transport,"TLS")==0)){ + /*RFC 5923: add 'alias' parameter to tell the server that we want it to keep the connection for future requests*/ + belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_via_t); + belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(via),"alias",NULL); + } + } + + client_transaction = belle_sip_provider_create_client_transaction(prov,request); + belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),ref()); + if (this->pending_client_trans) belle_sip_object_unref(this->pending_client_trans); + + this->pending_client_trans=client_transaction; /*update pending inv for being able to cancel*/ + belle_sip_object_ref(this->pending_client_trans); + + if (belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_user_agent_t)==NULL) + belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(this->root->user_agent)); + + if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION) + && !belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION)) { + /*hmm just in case we already have authentication param in cache*/ + belle_sip_provider_add_authorization(this->root->prov,request,NULL,NULL,NULL,this->realm); + } + result = belle_sip_client_transaction_send_request_to(client_transaction,next_hop_uri/*might be null*/); + + /*update call id if not set yet for this OP*/ + if (result == 0 && !this->call_id) { + this->call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request), belle_sip_header_call_id_t)))); + } + + return result; + +} + +int SalOp::send_request(belle_sip_request_t* request) { + bool_t need_contact=FALSE; + if (request==NULL) { + return -1; /*sanity check*/ + } + /* + Header field where proxy ACK BYE CAN INV OPT REG + ___________________________________________________________ + Contact R o - - m o o + */ + if (strcmp(belle_sip_request_get_method(request),"INVITE")==0 + ||strcmp(belle_sip_request_get_method(request),"REGISTER")==0 + ||strcmp(belle_sip_request_get_method(request),"SUBSCRIBE")==0 + ||strcmp(belle_sip_request_get_method(request),"OPTIONS")==0 + ||strcmp(belle_sip_request_get_method(request),"REFER")==0) /* Despite contact seems not mandatory, call flow example show a Contact in REFER requests*/ + need_contact=TRUE; + + return send_request_with_contact(request,need_contact); +} + +void SalOp::resend_request(belle_sip_request_t* request) { + belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_CSEQ); + belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); + send_request(request); +} + +void SalOp::process_authentication() { + belle_sip_request_t* initial_request=belle_sip_transaction_get_request((belle_sip_transaction_t*)this->pending_auth_transaction); + belle_sip_request_t* new_request; + bool_t is_within_dialog=FALSE; + belle_sip_list_t* auth_list=NULL; + belle_sip_auth_event_t* auth_event; + belle_sip_response_t *response=belle_sip_transaction_get_response((belle_sip_transaction_t*)this->pending_auth_transaction); + belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(initial_request,belle_sip_header_from_t); + belle_sip_uri_t *from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)from); + + if (strcasecmp(belle_sip_uri_get_host(from_uri),"anonymous.invalid")==0){ + /*prefer using the from from the SalOp*/ + from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)get_from_address()); + } + + if (this->dialog && belle_sip_dialog_get_state(this->dialog)==BELLE_SIP_DIALOG_CONFIRMED) { + new_request = belle_sip_dialog_create_request_from(this->dialog,initial_request); + if (!new_request) + new_request = belle_sip_dialog_create_queued_request_from(this->dialog,initial_request); + is_within_dialog=TRUE; + } else { + new_request=initial_request; + belle_sip_message_remove_header(BELLE_SIP_MESSAGE(new_request),BELLE_SIP_AUTHORIZATION); + belle_sip_message_remove_header(BELLE_SIP_MESSAGE(new_request),BELLE_SIP_PROXY_AUTHORIZATION); + } + if (new_request==NULL) { + ms_error("sal_process_authentication() op=[%p] cannot obtain new request from dialog.",this); + return; + } + + if (belle_sip_provider_add_authorization(this->root->prov,new_request,response,from_uri,&auth_list,this->realm)) { + if (is_within_dialog) { + send_request(new_request); + } else { + resend_request(new_request); + } + this->root->remove_pending_auth(this); + }else { + belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(response,belle_sip_header_from_t); + char *tmp=belle_sip_object_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from))); + ms_message("No auth info found for [%s]",tmp); + belle_sip_free(tmp); + this->root->add_pending_auth(this); + + if (is_within_dialog) { + belle_sip_object_unref(new_request); + } + } + /*always store auth info, for case of wrong credential*/ + if (this->auth_info) { + sal_auth_info_delete(this->auth_info); + this->auth_info=NULL; + } + if (auth_list){ + auth_event=(belle_sip_auth_event_t*)(auth_list->data); + this->auth_info=sal_auth_info_create(auth_event); + belle_sip_list_free_with_data(auth_list,(void (*)(void*))belle_sip_auth_event_destroy); + } +} + +char *SalOp::get_dialog_id() const { + if (this->dialog != NULL) { + return ms_strdup_printf("%s;to-tag=%s;from-tag=%s", this->call_id, + belle_sip_dialog_get_remote_tag(this->dialog), belle_sip_dialog_get_local_tag(this->dialog)); + } + return NULL; +} + +int SalOp::get_address_family() const { + belle_sip_transaction_t *tr=NULL; + belle_sip_header_address_t *contact; + + + if (this->refresher) + tr=(belle_sip_transaction_t *)belle_sip_refresher_get_transaction(this->refresher); + + if (tr==NULL) + tr=(belle_sip_transaction_t *)this->pending_client_trans; + if (tr==NULL) + tr=(belle_sip_transaction_t *)this->pending_server_trans; + + if (tr==NULL){ + ms_error("Unable to determine IP version from signaling operation."); + return AF_UNSPEC; + } + + + if (this->refresher) { + belle_sip_response_t *resp = belle_sip_transaction_get_response(tr); + belle_sip_header_via_t *via = resp ?belle_sip_message_get_header_by_type(resp,belle_sip_header_via_t):NULL; + if (!via){ + ms_error("Unable to determine IP version from signaling operation, no via header found."); + return AF_UNSPEC; + } + return (strchr(belle_sip_header_via_get_host(via),':') != NULL) ? AF_INET6 : AF_INET; + } else { + belle_sip_request_t *req = belle_sip_transaction_get_request(tr); + contact=(belle_sip_header_address_t*)belle_sip_message_get_header_by_type(req,belle_sip_header_contact_t); + if (!contact){ + ms_error("Unable to determine IP version from signaling operation, no contact header found."); + } + return sal_address_is_ipv6((SalAddress*)contact) ? AF_INET6 : AF_INET; + } +} + +bool_t SalOp::is_idle() const { + if (this->dialog){ + return !belle_sip_dialog_request_pending(this->dialog); + } + return TRUE; +} + +void SalOp::set_entity_tag(const char* entity_tag) { + if (this->entity_tag != NULL) ms_free(this->entity_tag); + this->entity_tag = entity_tag ? ms_strdup(entity_tag) : NULL; +} + +void SalOp::set_event(const char *eventname) { + belle_sip_header_event_t *header = NULL; + if (this->event) belle_sip_object_unref(this->event); + if (eventname){ + header = belle_sip_header_event_create(eventname); + belle_sip_object_ref(header); + } + this->event = header; +} + +void SalOp::add_initial_route_set(belle_sip_request_t *request, const MSList *list) { + const MSList *elem; + for (elem=list;elem!=NULL;elem=elem->next){ + SalAddress *addr=(SalAddress*)elem->data; + belle_sip_header_route_t *route; + belle_sip_uri_t *uri; + /*Optimization: if the initial route set only contains one URI which is the same as the request URI, ommit it*/ + if (elem==list && list->next==NULL){ + belle_sip_uri_t *requri=belle_sip_request_get_uri(request); + /*skip the first route it is the same as the request uri*/ + if (strcmp(sal_address_get_domain(addr),belle_sip_uri_get_host(requri))==0 ){ + ms_message("Skipping top route of initial route-set because same as request-uri."); + continue; + } + } + + route=belle_sip_header_route_create((belle_sip_header_address_t*)addr); + uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)route); + belle_sip_uri_set_lr_param(uri,1); + belle_sip_message_add_header((belle_sip_message_t*)request,(belle_sip_header_t*)route); + } +} + +belle_sip_request_t* SalOp::build_request(const char* method) { + belle_sip_header_from_t* from_header; + belle_sip_header_to_t* to_header; + belle_sip_provider_t* prov=this->root->prov; + belle_sip_request_t *req; + belle_sip_uri_t* req_uri; + belle_sip_uri_t* to_uri; + belle_sip_header_call_id_t *call_id_header; + + const SalAddress* to_address; + const MSList *elem=get_route_addresses(); + char token[10]; + + /* check that the op has a correct to address */ + to_address = get_to_address(); + if( to_address == NULL ){ + ms_error("No To: address, cannot build request"); + return NULL; + } + + to_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to_address)); + if( to_uri == NULL ){ + ms_error("To: address is invalid, cannot build request"); + return NULL; + } + + if (strcmp("REGISTER",method)==0 || this->privacy==SalPrivacyNone) { + from_header = belle_sip_header_from_create(BELLE_SIP_HEADER_ADDRESS(get_from_address()) + ,belle_sip_random_token(token,sizeof(token))); + } else { + from_header=belle_sip_header_from_create2("Anonymous ",belle_sip_random_token(token,sizeof(token))); + } + /*make sure to preserve components like headers or port*/ + + req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)to_uri); + belle_sip_uri_set_secure(req_uri,is_secure()); + + to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(to_address),NULL); + call_id_header = belle_sip_provider_create_call_id(prov); + if (get_call_id()) { + belle_sip_header_call_id_set_call_id(call_id_header, get_call_id()); + } + + req=belle_sip_request_create( + req_uri, + method, + call_id_header, + belle_sip_header_cseq_create(20,method), + from_header, + to_header, + belle_sip_header_via_new(), + 70); + + if (this->privacy & SalPrivacyId) { + belle_sip_header_p_preferred_identity_t* p_preferred_identity=belle_sip_header_p_preferred_identity_create(BELLE_SIP_HEADER_ADDRESS(get_from_address())); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(p_preferred_identity)); + } + + if (elem && strcmp(method,"REGISTER")!=0 && !this->root->no_initial_route){ + add_initial_route_set(req,elem); + } + + if (strcmp("REGISTER",method)!=0 && this->privacy!=SalPrivacyNone ){ + belle_sip_header_privacy_t* privacy_header=belle_sip_header_privacy_new(); + if (this->privacy&SalPrivacyCritical) + belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyCritical)); + if (this->privacy&SalPrivacyHeader) + belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyHeader)); + if (this->privacy&SalPrivacyId) + belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyId)); + if (this->privacy&SalPrivacyNone) + belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyNone)); + if (this->privacy&SalPrivacySession) + belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacySession)); + if (this->privacy&SalPrivacyUser) + belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyUser)); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(privacy_header)); + } + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),this->root->supported); + return req; +} + +void SalOp::set_error_info_from_response(belle_sip_response_t *response) { + int code = belle_sip_response_get_status_code(response); + const char *reason_phrase=belle_sip_response_get_reason_phrase(response); + belle_sip_header_t *warning=belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Warning"); + SalErrorInfo *ei=&this->error_info; + const char *warnings; + + warnings=warning ? belle_sip_header_get_unparsed_value(warning) : NULL; + sal_error_info_set(ei,SalReasonUnknown,"SIP", code,reason_phrase,warnings); + set_reason_error_info(BELLE_SIP_MESSAGE(response)); +} + +const char* SalOp::to_string(const State value) { + switch(value) { + case State::Early: return"SalOpStateEarly"; + case State::Active: return "SalOpStateActive"; + case State::Terminating: return "SalOpStateTerminating"; + case State::Terminated: return "SalOpStateTerminated"; + default: + return "Unknown"; + } +} + +void SalOp::set_reason_error_info(belle_sip_message_t *msg) { + belle_sip_header_reason_t* reason_header = belle_sip_message_get_header_by_type(msg,belle_sip_header_reason_t); + if (reason_header){ + SalErrorInfo *ei=&this->reason_error_info; // ?// + const char *protocol = belle_sip_header_reason_get_protocol(reason_header); + int code = belle_sip_header_reason_get_cause(reason_header); + const char *text = belle_sip_header_reason_get_text(reason_header); + sal_error_info_set(ei, SalReasonUnknown, protocol, code, text, NULL); + } +} + +void SalOp::set_referred_by(belle_sip_header_referred_by_t* referred_by) { + if (this->referred_by){ + belle_sip_object_unref(this->referred_by); + } + + this->referred_by=referred_by; + belle_sip_object_ref(this->referred_by); +} + +void SalOp::set_replaces(belle_sip_header_replaces_t* replaces) { + if (this->replaces){ + belle_sip_object_unref(this->replaces); + } + + this->replaces=replaces; + belle_sip_object_ref(this->replaces); +} + +int SalOp::send_request_with_expires(belle_sip_request_t* request,int expires) { + belle_sip_header_expires_t* expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_EXPIRES); + + if (!expires_header && expires>=0) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header=belle_sip_header_expires_new())); + } + if (expires_header) belle_sip_header_expires_set_expires(expires_header,expires); + return send_request(request); +} + +int SalOp::send_and_create_refresher(belle_sip_request_t* req, int expires,belle_sip_refresher_listener_t listener) { + if (send_request_with_expires(req,expires)==0) { + if (this->refresher) { + belle_sip_refresher_stop(this->refresher); + belle_sip_object_unref(this->refresher); + } + if ((this->refresher = belle_sip_client_transaction_create_refresher(this->pending_client_trans))) { + /*since refresher acquires the transaction, we should remove our context from the transaction, because we won't be notified + * that it is terminated anymore.*/ + unref();/*loose the reference that was given to the transaction when creating it*/ + /* Note that the refresher will replace our data with belle_sip_transaction_set_application_data(). + Something in the design is not very good here, it makes things complicated to the belle-sip user. + Possible ideas to improve things: refresher shall not use belle_sip_transaction_set_application_data() internally, refresher should let the first transaction + notify the user as a normal transaction*/ + belle_sip_refresher_set_listener(this->refresher,listener, this); + belle_sip_refresher_set_retry_after(this->refresher,this->root->refresher_retry_after); + belle_sip_refresher_set_realm(this->refresher,this->realm); + belle_sip_refresher_enable_manual_mode(this->refresher, this->manual_refresher); + return 0; + } else { + return -1; + } + } + return -1; +} + +belle_sip_header_contact_t *SalOp::create_contact() { + belle_sip_header_contact_t* contact_header; + belle_sip_uri_t* contact_uri; + + if (get_contact_address()) { + contact_header = belle_sip_header_contact_create(BELLE_SIP_HEADER_ADDRESS(get_contact_address())); + } else { + contact_header= belle_sip_header_contact_new(); + } + + if (!(contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_header)))) { + /*no uri, just creating a new one*/ + contact_uri=belle_sip_uri_new(); + belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact_header),contact_uri); + } + + belle_sip_uri_set_user_password(contact_uri,NULL); + belle_sip_uri_set_secure(contact_uri,is_secure()); + if (this->privacy!=SalPrivacyNone){ + belle_sip_uri_set_user(contact_uri,NULL); + } + belle_sip_header_contact_set_automatic(contact_header,this->root->auto_contacts); + if (this->root->uuid){ + if (belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance")==0){ + char *instance_id=belle_sip_strdup_printf("\"\"",this->root->uuid); + belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance",instance_id); + belle_sip_free(instance_id); + } + } + return contact_header; +} + +void SalOp::unlink_op_with_dialog(belle_sip_dialog_t* dialog) { + belle_sip_dialog_set_application_data(dialog,NULL); + unref(); + belle_sip_object_unref(dialog); +} + +belle_sip_dialog_t *SalOp::link_op_with_dialog(belle_sip_dialog_t* dialog) { + belle_sip_dialog_set_application_data(dialog,ref()); + belle_sip_object_ref(dialog); + return dialog; +} + +void SalOp::set_or_update_dialog(belle_sip_dialog_t* dialog) { + ms_message("op [%p] : set_or_update_dialog() current=[%p] new=[%p]", this, this->dialog,dialog); + ref(); + if (this->dialog!=dialog){ + if (this->dialog){ + /*FIXME: shouldn't we delete unconfirmed dialogs ?*/ + unlink_op_with_dialog(this->dialog); + this->dialog=NULL; + } + if (dialog) { + this->dialog=link_op_with_dialog(dialog); + belle_sip_dialog_enable_pending_trans_checking(dialog,this->root->pending_trans_checking); + } + } + unref(); +} + +int SalOp::ping(const char *from, const char *to) { + set_from(from); + set_to(to); + return send_request(build_request("OPTIONS")); +} + +int SalOp::send_info(const char *from, const char *to, const SalBodyHandler *body_handler) { + if (this->dialog && belle_sip_dialog_get_state(this->dialog) == BELLE_SIP_DIALOG_CONFIRMED) { + belle_sip_request_t *req; + belle_sip_dialog_enable_pending_trans_checking(this->dialog,this->root->pending_trans_checking); + req=belle_sip_dialog_create_queued_request(this->dialog,"INFO"); + belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(body_handler)); + return send_request(req); + }else{ + ms_error("Cannot send INFO message on op [%p] because dialog is not in confirmed state yet.", this); + } + return -1; +} + +SalBodyHandler *SalOp::get_body_handler(belle_sip_message_t *msg) { + belle_sip_body_handler_t *body_handler = belle_sip_message_get_body_handler(msg); + if (body_handler != NULL) { + belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(msg, belle_sip_header_content_type_t); + belle_sip_header_content_length_t *content_length = belle_sip_message_get_header_by_type(msg, belle_sip_header_content_length_t); + belle_sip_header_t *content_encoding = belle_sip_message_get_header(msg, "Content-Encoding"); + if (content_type != NULL) belle_sip_body_handler_add_header(body_handler, BELLE_SIP_HEADER(content_type)); + if (content_length != NULL) belle_sip_body_handler_add_header(body_handler, BELLE_SIP_HEADER(content_length)); + if (content_encoding != NULL) belle_sip_body_handler_add_header(body_handler, content_encoding); + } + return (SalBodyHandler *)body_handler; +} + +void SalOp::assign_recv_headers(belle_sip_message_t *incoming) { + if (incoming) belle_sip_object_ref(incoming); + if (this->recv_custom_headers){ + belle_sip_object_unref(this->recv_custom_headers); + this->recv_custom_headers=NULL; + } + if (incoming){ + this->recv_custom_headers=(SalCustomHeader*)incoming; + } +} + +void SalOp::set_remote_contact(const char* remote_contact) { + assign_address(&this->remote_contact_address,remote_contact); + /*to preserve header params*/ + assign_string(&this->remote_contact,remote_contact); +} + +void SalOp::set_network_origin(const char *origin) { + SET_PARAM(origin); +} + +void SalOp::set_network_origin_address(SalAddress *origin){ + char* address_string=sal_address_as_string(origin); /*can probably be optimized*/ + set_network_origin(address_string); + ms_free(address_string); +} + +/* +rfc3323 +4.2 Expressing Privacy Preferences +When a Privacy header is constructed, it MUST consist of either the + value 'none', or one or more of the values 'user', 'header' and + 'session' (each of which MUST appear at most once) which MAY in turn + be followed by the 'critical' indicator. + */ +void SalOp::set_privacy_from_message(belle_sip_message_t* msg) { + belle_sip_header_privacy_t* privacy = belle_sip_message_get_header_by_type(msg,belle_sip_header_privacy_t); + if (!privacy) { + set_privacy(SalPrivacyNone); + } else { + belle_sip_list_t* privacy_list=belle_sip_header_privacy_get_privacy(privacy); + set_privacy(0); + for (;privacy_list!=NULL;privacy_list=privacy_list->next) { + char* privacy_value=(char*)privacy_list->data; + if(strcmp(sal_privacy_to_string(SalPrivacyCritical),privacy_value) == 0) + set_privacy(get_privacy()|SalPrivacyCritical); + if(strcmp(sal_privacy_to_string(SalPrivacyHeader),privacy_value) == 0) + set_privacy(get_privacy()|SalPrivacyHeader); + if(strcmp(sal_privacy_to_string(SalPrivacyId),privacy_value) == 0) + set_privacy(get_privacy()|SalPrivacyId); + if(strcmp(sal_privacy_to_string(SalPrivacyNone),privacy_value) == 0) { + set_privacy(SalPrivacyNone); + break; + } + if(strcmp(sal_privacy_to_string(SalPrivacySession),privacy_value) == 0) + set_privacy(get_privacy()|SalPrivacySession); + if(strcmp(sal_privacy_to_string(SalPrivacyUser),privacy_value) == 0) + set_privacy(get_privacy()|SalPrivacyUser); + } + } +} + +void SalOp::set_remote_ua(belle_sip_message_t* message) { + belle_sip_header_user_agent_t* user_agent=belle_sip_message_get_header_by_type(message,belle_sip_header_user_agent_t); + char user_agent_string[256]; + if (user_agent && belle_sip_header_user_agent_get_products_as_string(user_agent,user_agent_string,sizeof(user_agent_string))>0) { + if (this->remote_ua!=NULL){ + ms_free(this->remote_ua); + } + this->remote_ua=ms_strdup(user_agent_string); + } +} + +const char *SalOp::to_string(const Type type) { + switch(type) { + case Type::Register: return "SalOpRegister"; + case Type::Call: return "SalOpCall"; + case Type::Message: return "SalOpMessage"; + case Type::Presence: return "SalOpPresence"; + default: return "SalOpUnknown"; + } +} + +bool_t SalOp::is_secure() const { + const SalAddress* from = get_from_address(); + const SalAddress* to = get_to_address(); + return from && to && strcasecmp("sips",sal_address_get_scheme(from))==0 && strcasecmp("sips",sal_address_get_scheme(to))==0; +} + +/* + * Warning: this function takes owneship of the custom headers + */ +void SalOp::set_sent_custom_header(SalCustomHeader* ch){ + if (this->sent_custom_headers){ + sal_custom_header_free(this->sent_custom_headers); + this->sent_custom_headers=NULL; + } + if (ch) belle_sip_object_ref((belle_sip_message_t*)ch); + this->sent_custom_headers=ch; +} + +void SalOp::add_headers(belle_sip_header_t *h, belle_sip_message_t *msg){ + + if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(h,belle_sip_header_contact_t)){ + belle_sip_header_contact_t* newct; + /*special case for contact, we want to keep everything from the custom contact but set automatic mode and add our own parameters as well*/ + set_contact_address((SalAddress*)BELLE_SIP_HEADER_ADDRESS(h)); + newct = create_contact(); + belle_sip_message_set_header(BELLE_SIP_MESSAGE(msg),BELLE_SIP_HEADER(newct)); + return; + } + /*if a header already exists in the message, replace it*/ + belle_sip_message_set_header(msg,h); + +} + +void SalOp::add_custom_headers(belle_sip_message_t *msg){ + if (this->sent_custom_headers){ + belle_sip_message_t *ch=(belle_sip_message_t*)this->sent_custom_headers; + belle_sip_list_t *l=belle_sip_message_get_all_headers(ch); + belle_sip_list_t *elem; + for(elem=l;elem!=NULL;elem=elem->next){ + add_headers((belle_sip_header_t*)elem->data,msg); + } + belle_sip_list_free(l); + } +} + +int SalOp::unsubscribe(){ + if (this->refresher){ + const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(this->refresher); + belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr); + belle_sip_message_set_body(BELLE_SIP_MESSAGE(last_req), NULL, 0); + belle_sip_refresher_refresh(this->refresher,0); + return 0; + } + return -1; +} + +void SalOp::process_incoming_message(const belle_sip_request_event_t *event) { + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(this->root->prov,req); + belle_sip_header_address_t* address; + belle_sip_header_from_t* from_header; + belle_sip_header_content_type_t* content_type; + belle_sip_response_t* resp; + int errcode = 500; + belle_sip_header_call_id_t* call_id = belle_sip_message_get_header_by_type(req,belle_sip_header_call_id_t); + belle_sip_header_cseq_t* cseq = belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); + belle_sip_header_date_t *date=belle_sip_message_get_header_by_type(req,belle_sip_header_date_t); + char* from; + bool_t external_body=FALSE; + + from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); + content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t); + + if (content_type) { + SalMessage salmsg; + char message_id[256]={0}; + + if (this->pending_server_trans) belle_sip_object_unref(this->pending_server_trans); + + this->pending_server_trans=server_transaction; + belle_sip_object_ref(this->pending_server_trans); + + external_body=is_external_body(content_type); + address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) + ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); + from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address)); + snprintf(message_id,sizeof(message_id)-1,"%s%i" + ,belle_sip_header_call_id_get_call_id(call_id) + ,belle_sip_header_cseq_get_seq_number(cseq)); + salmsg.from=from; + /* if we just deciphered a message, use the deciphered part(which can be a rcs xml body pointing to the file to retreive from server)*/ + salmsg.text=(!external_body)?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL; + salmsg.url=NULL; + salmsg.content_type = ms_strdup_printf("%s/%s", belle_sip_header_content_type_get_type(content_type), belle_sip_header_content_type_get_subtype(content_type)); + if (external_body && belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")) { + size_t url_length=strlen(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")); + salmsg.url = ms_strdup(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")+1); /* skip first "*/ + ((char*)salmsg.url)[url_length-2]='\0'; /*remove trailing "*/ + } + salmsg.message_id=message_id; + salmsg.time=date ? belle_sip_header_date_get_time(date) : time(NULL); + this->root->callbacks.message_received(this,&salmsg); + + belle_sip_object_unref(address); + belle_sip_free(from); + if (salmsg.url) ms_free((char*)salmsg.url); + ms_free((char *)salmsg.content_type); + } else { + ms_error("Unsupported MESSAGE (no Content-Type)"); + resp = belle_sip_response_create_from_request(req, errcode); + add_message_accept((belle_sip_message_t*)resp); + belle_sip_server_transaction_send_response(server_transaction,resp); + release(); + } +} + +bool_t SalOp::is_external_body(belle_sip_header_content_type_t* content_type) { + return strcmp("message",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("external-body",belle_sip_header_content_type_get_subtype(content_type))==0; +} + +int SalOp::reply_message(SalReason reason) { + if (this->pending_server_trans){ + int code=to_sip_code(reason); + belle_sip_response_t *resp = belle_sip_response_create_from_request( + belle_sip_transaction_get_request((belle_sip_transaction_t*)this->pending_server_trans),code); + belle_sip_server_transaction_send_response(this->pending_server_trans,resp); + return 0; + }else ms_error("sal_message_reply(): no server transaction"); + return -1; +} + +void SalOp::add_message_accept(belle_sip_message_t *msg) { + bctbx_list_t *item; + const char *str; + char *old; + char *header = ms_strdup("xml/cipher, application/cipher.vnd.gsma.rcs-ft-http+xml"); + + for (item = this->root->supported_content_types; item != NULL; item = bctbx_list_next(item)) { + str = (const char *)bctbx_list_get_data(item); + old = header; + header = ms_strdup_printf("%s, %s", old, str); + ms_free(old); + } + + belle_sip_message_add_header(msg, belle_sip_header_create("Accept", header)); + ms_free(header); +} + +void SalOp::set_service_route(const SalAddress* service_route) { + if (this->service_route) + sal_address_destroy(this->service_route); + + this->service_route=service_route?sal_address_clone(service_route):NULL; +} + +LINPHONE_END_NAMESPACE diff --git a/coreapi/sal/sal_op.h b/coreapi/sal/sal_op.h new file mode 100644 index 000000000..1a58b2b43 --- /dev/null +++ b/coreapi/sal/sal_op.h @@ -0,0 +1,258 @@ +/* +sal_op.h +Copyright (C) 2017 Belledonne Communications + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _SAL_OP_H_ +#define _SAL_OP_H_ + +#include +#include +#include +#include "sal.h" +#include "sal.hpp" + +LINPHONE_BEGIN_NAMESPACE + +class SalOp { +public: + SalOp(Sal *sal); + virtual ~SalOp(); + + SalOp *ref(); + void *unref(); + + Sal *get_sal() const {return this->root;} + + void set_user_pointer(void *up) {this->user_pointer=up;} + void *get_user_pointer() const {return this->user_pointer;} + + + void set_from(const char *from); + void set_from_address(const SalAddress *from); + const char *get_from() const {return this->from;} + const SalAddress *get_from_address() const {return this->from_address;} + + void set_to(const char *to); + void set_to_address(const SalAddress *to); + const char *get_to() const {return this->to;} + const SalAddress *get_to_address() const {return this->to_address;} + + void set_contact_address(const SalAddress* address); + const SalAddress *get_contact_address() const {return this->contact_address;} + + void set_route(const char *route); + void set_route_address(const SalAddress* address); + const bctbx_list_t *get_route_addresses() const {return this->route_addresses;} + void add_route_address(const SalAddress* address); + + void set_diversion_address(const SalAddress *diversion); + const SalAddress *get_diversion_address() const {return this->diversion_address;} + + void set_service_route(const SalAddress* service_route); + const SalAddress *get_service_route() const {return this->service_route;} + + void set_manual_refresher_mode(bool_t enabled) {this->manual_refresher=enabled;} + + void set_entity_tag(const char* entity_tag); + const char *get_entity_tag() const {return this->entity_tag;} + + void set_event(const char *eventname); + + void set_privacy(SalPrivacyMask privacy) {this->privacy=privacy;} + SalPrivacyMask get_privacy() const {return this->privacy;} + + void set_realm(const char *realm); + + void set_sent_custom_header(SalCustomHeader* ch); + + void enable_cnx_ip_to_0000_if_sendonly(bool_t yesno) {this->_cnx_ip_to_0000_if_sendonly_enabled = yesno;} + bool_t cnx_ip_to_0000_if_sendonly_enabled() const {return this->_cnx_ip_to_0000_if_sendonly_enabled;} + + const char *get_proxy() const {return this->route;} + const char *get_network_origin() const {return this->origin;} + const char* get_call_id() const {return this->call_id;} + char* get_dialog_id() const; + int get_address_family() const; + const SalCustomHeader *get_recv_custom_header() const {return this->recv_custom_headers;} + const char *get_remote_contact() const {return this->remote_contact;} + const SalAddress *get_remote_contact_address() const {return this->remote_contact_address;} + const char *get_remote_ua() const {return this->remote_ua;} + + const char *get_public_address(int *port) {return this->refresher ? belle_sip_refresher_get_public_address(this->refresher, port) : NULL;} + const char *get_local_address(int *port) {return this->refresher ? belle_sip_refresher_get_local_address(this->refresher, port) : NULL;} + + const SalErrorInfo *get_error_info() const {return &this->error_info;} + const SalErrorInfo *get_reason_error_info() const {return &this->reason_error_info;} + + bool_t is_forked_of(const SalOp *op2) const {return this->call_id && op2->call_id && strcmp(this->call_id, op2->call_id) == 0;} + bool_t is_idle() const ; + + void stop_refreshing() {if (this->refresher) belle_sip_refresher_stop(this->refresher);} + int refresh(); + void kill_dialog(); + void release(); + + virtual void authenticate(const SalAuthInfo *info) {process_authentication();} + void cancel_authentication() {ms_fatal("sal_op_cancel_authentication not implemented yet");} + SalAuthInfo *get_auth_requested() {return this->auth_info;} + + int ping(const char *from, const char *to); + int send_info(const char *from, const char *to, const SalBodyHandler *body_handler); + +protected: + enum class State { + Early = 0, + Active, + Terminating, /*this state is used to wait until a proceeding state, so we can send the cancel*/ + Terminated + }; + + static const char* to_string(const State value); + + enum class Dir { + Incoming = 0, + Outgoing + }; + + enum class Type { + Unknown, + Register, + Call, + Message, + Presence, + Publish, + Subscribe + }; + + static const char *to_string(const SalOp::Type type); + + typedef void (*ReleaseCb)(SalOp *op); + + virtual void fill_cbs() {} + void release_impl(); + void process_authentication(); + + belle_sip_request_t* build_request(const char* method); + int send_request(belle_sip_request_t* request); + int send_request_with_contact(belle_sip_request_t* request, bool_t add_contact); + int send_request_with_expires(belle_sip_request_t* request,int expires); + void resend_request(belle_sip_request_t* request); + int send_and_create_refresher(belle_sip_request_t* req, int expires,belle_sip_refresher_listener_t listener); + + void set_reason_error_info(belle_sip_message_t *msg); + void set_error_info_from_response(belle_sip_response_t *response); + + void set_referred_by(belle_sip_header_referred_by_t* referred_by); + void set_replaces(belle_sip_header_replaces_t* replaces); + + void set_remote_contact(const char* remote_contact); + void set_network_origin(const char *origin); + void set_network_origin_address(SalAddress *origin); + void set_privacy_from_message(belle_sip_message_t* msg); + void set_remote_ua(belle_sip_message_t* message); + + belle_sip_response_t *create_response_from_request(belle_sip_request_t *req, int code) {return this->root->create_response_from_request(req,code);} + belle_sip_header_contact_t *create_contact(); + + void set_or_update_dialog(belle_sip_dialog_t* dialog); + belle_sip_dialog_t *link_op_with_dialog(belle_sip_dialog_t* dialog); + void unlink_op_with_dialog(belle_sip_dialog_t* dialog); + + SalBodyHandler *get_body_handler(belle_sip_message_t *msg); + + void assign_recv_headers(belle_sip_message_t *incoming); + + bool_t is_secure() const; + void add_headers(belle_sip_header_t *h, belle_sip_message_t *msg); + void add_custom_headers(belle_sip_message_t *msg); + int unsubscribe(); + + void process_incoming_message(const belle_sip_request_event_t *event); + int reply_message(SalReason reason); + void add_message_accept(belle_sip_message_t *msg); + static bool_t is_external_body(belle_sip_header_content_type_t* content_type); + + static void assign_address(SalAddress** address, const char *value); + static void assign_string(char **str, const char *arg); + static void add_initial_route_set(belle_sip_request_t *request, const MSList *list); + + // SalOpBase + Sal *root = NULL; + char *route = NULL; /*or request-uri for REGISTER*/ + MSList* route_addresses = NULL; /*list of SalAddress* */ + SalAddress* contact_address = NULL; + char *from = NULL; + SalAddress* from_address = NULL; + char *to = NULL; + SalAddress* to_address = NULL; + char *origin = NULL; + SalAddress* origin_address = NULL; + SalAddress* diversion_address = NULL; + char *remote_ua = NULL; + SalAddress* remote_contact_address = NULL; + char *remote_contact = NULL; + SalMediaDescription *local_media = NULL; + SalMediaDescription *remote_media = NULL; + SalCustomBody *custom_body = NULL; + void *user_pointer = NULL; + const char* call_id = NULL; + char* realm = NULL; + SalAddress* service_route = NULL; /*as defined by rfc3608, might be a list*/ + SalCustomHeader *sent_custom_headers = NULL; + SalCustomHeader *recv_custom_headers = NULL; + char* entity_tag = NULL; /*as defined by rfc3903 (I.E publih)*/ + ReleaseCb release_cb = NULL; + + // BelleSip implementation + const belle_sip_listener_callbacks_t *callbacks = NULL; + SalErrorInfo error_info; + SalErrorInfo reason_error_info; + belle_sip_client_transaction_t *pending_auth_transaction = NULL; + belle_sip_server_transaction_t* pending_server_trans = NULL; + belle_sip_server_transaction_t* pending_update_server_trans = NULL; + belle_sip_client_transaction_t* pending_client_trans = NULL; + SalAuthInfo* auth_info = NULL; + belle_sip_dialog_t* dialog = NULL; + belle_sip_header_replaces_t *replaces = NULL; + belle_sip_header_referred_by_t *referred_by = NULL; + SalMediaDescription *result = NULL; + belle_sdp_session_description_t *sdp_answer = NULL; + State state = State::Early; + Dir dir = Dir::Incoming; + belle_sip_refresher_t* refresher = NULL; + int _ref = 0; + Type type = Type::Unknown; + SalPrivacyMask privacy = SalPrivacyNone; + belle_sip_header_event_t *event = NULL; /*used by SalOpSubscribe kinds*/ + SalOpSDPHandling sdp_handling = SalOpSDPNormal; + int auth_requests = 0; /*number of auth requested for this op*/ + bool_t _cnx_ip_to_0000_if_sendonly_enabled = FALSE; + bool_t auto_answer_asked = FALSE; + bool_t sdp_offering = FALSE; + bool_t call_released = FALSE; + bool_t manual_refresher = FALSE; + bool_t has_auth_pending = FALSE; + bool_t supports_session_timers = FALSE; + bool_t op_released = FALSE; + + friend class Sal; +}; + +LINPHONE_END_NAMESPACE + +#endif diff --git a/coreapi/tester_utils.cpp b/coreapi/tester_utils.cpp new file mode 100644 index 000000000..77c30ad4c --- /dev/null +++ b/coreapi/tester_utils.cpp @@ -0,0 +1,101 @@ +/* +tester_utils.cpp +Copyright (C) 2017 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "tester_utils.h" +#include "private.h" + +LinphoneVcardContext *linphone_core_get_vcard_context(const LinphoneCore *lc) { + return lc->vcard_context; +} + +void linphone_core_set_zrtp_not_available_simulation(LinphoneCore *lc, bool_t enabled) { + lc->zrtp_not_available_simulation = enabled; +} + +belle_http_provider_t *linphone_core_get_http_provider(const LinphoneCore *lc) { + return lc->http_provider; +} + +void linphone_core_enable_send_call_stats_periodical_updates(LinphoneCore *lc, bool_t enabled) { + lc->send_call_stats_periodical_updates = enabled; +} + +sqlite3 *linphone_core_get_sqlite_database(const LinphoneCore *lc) { + return lc->db; +} + +void linphone_core_set_zrtp_cache_db(LinphoneCore *lc, sqlite3 *cache_db) { + lc->zrtp_cache_db = cache_db; +} + +LinphoneCoreCbs *linphone_core_get_first_callbacks(const LinphoneCore *lc) { + return ((VTableReference *)lc->vtable_refs->data)->cbs; +} + +bctbx_list_t **linphone_core_get_call_logs_attribute(LinphoneCore *lc) { + return &lc->call_logs; +} + +void linphone_core_cbs_set_auth_info_requested(LinphoneCoreCbs *cbs, LinphoneCoreAuthInfoRequestedCb cb) { + cbs->vtable->auth_info_requested = cb; +} + +LinphoneQualityReporting *linphone_call_log_get_quality_reporting(LinphoneCallLog *call_log) { + return &call_log->reporting; +} + +reporting_session_report_t **linphone_quality_reporting_get_reports(LinphoneQualityReporting *qreporting) { + return &qreporting->reports[0]; +} + +const bctbx_list_t *linphone_friend_get_insubs(const LinphoneFriend *fr) { + return fr->insubs; +} + +int linphone_friend_list_get_expected_notification_version(const LinphoneFriendList *list) { + return list->expected_notification_version; +} + +unsigned int linphone_friend_list_get_storage_id(const LinphoneFriendList *list) { + return list->storage_id; +} + +unsigned int linphone_friend_get_storage_id(const LinphoneFriend *lf) { + return lf->storage_id; +} + +void linphone_friend_set_core(LinphoneFriend *lf, LinphoneCore *lc) { + lf->lc = lc; +} + +LinphoneFriendList *linphone_friend_get_friend_list(const LinphoneFriend *lf) { + return lf->friend_list; +} + +bctbx_list_t **linphone_friend_list_get_friends_attribute(LinphoneFriendList *lfl) { + return &lfl->friends; +} + +const bctbx_list_t *linphone_friend_list_get_dirty_friends_to_update(const LinphoneFriendList *lfl) { + return lfl->dirty_friends_to_update; +} + +int linphone_friend_list_get_revision(const LinphoneFriendList *lfl) { + return lfl->revision; +} diff --git a/coreapi/tester_utils.h b/coreapi/tester_utils.h new file mode 100644 index 000000000..26ac68756 --- /dev/null +++ b/coreapi/tester_utils.h @@ -0,0 +1,154 @@ +/* +tester_utils.h +Copyright (C) 2017 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _TESTER_UTILS_H_ +#define _TESTER_UTILS_H_ + +#include "account_creator_private.h" +#include "linphone/core.h" +#include "linphone/tunnel.h" +#include "sal/sal.h" +#include +#include "quality_reporting.h" +#include "vcard_private.h" + +#ifndef __cplusplus +typedef struct _Sal Sal; +typedef struct _SalOp SalOp; +#endif + +typedef struct _LinphoneQualityReporting LinphoneQualityReporting; + +typedef enum _LinphoneProxyConfigAddressComparisonResult{ + LinphoneProxyConfigAddressDifferent, + LinphoneProxyConfigAddressEqual, + LinphoneProxyConfigAddressWeakEqual +} LinphoneProxyConfigAddressComparisonResult; + +#ifdef __cplusplus +extern "C" { +#endif + +LINPHONE_PUBLIC LinphoneVcardContext *linphone_core_get_vcard_context(const LinphoneCore *lc); +LINPHONE_PUBLIC bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_get_local_ip(LinphoneCore *lc, int af, const char *dest, char *result); +LINPHONE_PUBLIC void linphone_core_enable_forced_ice_relay(LinphoneCore *lc, bool_t enable); +LINPHONE_PUBLIC void linphone_core_set_zrtp_not_available_simulation(LinphoneCore *lc, bool_t enabled); +LINPHONE_PUBLIC belle_http_provider_t *linphone_core_get_http_provider(const LinphoneCore *lc); +LINPHONE_PUBLIC const char *linphone_core_get_tone_file(const LinphoneCore *lc, LinphoneToneID id); +LINPHONE_PUBLIC IceSession * linphone_call_get_ice_session(const LinphoneCall *call); +LINPHONE_PUBLIC const struct addrinfo *linphone_core_get_stun_server_addrinfo(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_enable_send_call_stats_periodical_updates(LinphoneCore *lc, bool_t enabled); + +LINPHONE_PUBLIC int linphone_run_stun_tests(LinphoneCore *lc, int audioPort, int videoPort, int textPort, + char *audioCandidateAddr, int *audioCandidatePort, char *videoCandidateAddr, int *videoCandidatePort, char *textCandidateAddr, int *textCandidatePort); +LINPHONE_PUBLIC void linphone_core_enable_short_turn_refresh(LinphoneCore *lc, bool_t enable); + +LINPHONE_PUBLIC sqlite3 *linphone_core_get_sqlite_database(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_zrtp_cache_db(LinphoneCore *lc, sqlite3 *cache_db); + +LINPHONE_PUBLIC LinphoneCoreCbs *linphone_core_get_first_callbacks(const LinphoneCore *lc); +LINPHONE_PUBLIC void _linphone_core_add_callbacks(LinphoneCore *lc, LinphoneCoreCbs *vtable, bool_t internal); + +LINPHONE_PUBLIC bctbx_list_t * linphone_core_read_call_logs_from_config_file(LinphoneCore *lc); +LINPHONE_PUBLIC bctbx_list_t **linphone_core_get_call_logs_attribute(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_delete_call_log(LinphoneCore *lc, LinphoneCallLog *log); + +LINPHONE_PUBLIC const MSList *linphone_core_get_call_history(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_delete_call_history(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_call_history_size(LinphoneCore *lc); + +LINPHONE_DEPRECATED LINPHONE_PUBLIC void linphone_core_cbs_set_auth_info_requested(LinphoneCoreCbs *cbs, LinphoneCoreAuthInfoRequestedCb cb); + +LINPHONE_PUBLIC LinphoneProxyConfigAddressComparisonResult linphone_proxy_config_is_server_config_changed(const LinphoneProxyConfig* obj); +LINPHONE_PUBLIC LinphoneProxyConfigAddressComparisonResult linphone_proxy_config_address_equal(const LinphoneAddress *a, const LinphoneAddress *b); + +LINPHONE_PUBLIC LinphoneCallLog *linphone_call_get_log(const LinphoneCall *call); +LINPHONE_PUBLIC MediaStream * linphone_call_get_stream(LinphoneCall *call, LinphoneStreamType type); +LINPHONE_PUBLIC bool_t linphone_call_get_all_muted(const LinphoneCall *call); +LINPHONE_PUBLIC LinphoneProxyConfig * linphone_call_get_dest_proxy(const LinphoneCall *call); + +LINPHONE_PUBLIC void linphone_call_params_set_no_user_consent(LinphoneCallParams *params, bool_t value); +LINPHONE_PUBLIC bool_t linphone_call_params_get_update_call_when_ice_completed(const LinphoneCallParams *params); + +LINPHONE_PUBLIC int _linphone_call_stats_get_updated(const LinphoneCallStats *stats); +LINPHONE_PUBLIC bool_t _linphone_call_stats_rtcp_received_via_mux(const LinphoneCallStats *stats); +LINPHONE_PUBLIC mblk_t *_linphone_call_stats_get_received_rtcp (const LinphoneCallStats *stats); + +LINPHONE_PUBLIC LinphoneQualityReporting *linphone_call_log_get_quality_reporting(LinphoneCallLog *call_log); +LINPHONE_PUBLIC reporting_session_report_t **linphone_quality_reporting_get_reports(LinphoneQualityReporting *qreporting); + +LINPHONE_PUBLIC bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr); + +LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_from_db(LinphoneCore *lc, LinphoneFriendList *list); +LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_lists_from_db(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_friend_invalidate_subscription(LinphoneFriend *lf); +LINPHONE_PUBLIC void linphone_friend_update_subscribes(LinphoneFriend *fr, bool_t only_when_registered); +LINPHONE_PUBLIC const bctbx_list_t *linphone_friend_get_insubs(const LinphoneFriend *fr); +LINPHONE_PUBLIC int linphone_friend_list_get_expected_notification_version(const LinphoneFriendList *list); +LINPHONE_PUBLIC unsigned int linphone_friend_list_get_storage_id(const LinphoneFriendList *list); +LINPHONE_PUBLIC unsigned int linphone_friend_get_storage_id(const LinphoneFriend *lf); +LINPHONE_PUBLIC void linphone_friend_set_core(LinphoneFriend *lf, LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneFriendList *linphone_friend_get_friend_list(const LinphoneFriend *lf); +LINPHONE_PUBLIC bctbx_list_t **linphone_friend_list_get_friends_attribute(LinphoneFriendList *lfl); +LINPHONE_PUBLIC const bctbx_list_t *linphone_friend_list_get_dirty_friends_to_update(const LinphoneFriendList *lfl); +LINPHONE_PUBLIC int linphone_friend_list_get_revision(const LinphoneFriendList *lfl); + +LINPHONE_PUBLIC int linphone_remote_provisioning_load_file( LinphoneCore* lc, const char* file_path); + + +#ifndef __cplusplus +LINPHONE_PUBLIC Sal *linphone_core_get_sal(const LinphoneCore *lc); +LINPHONE_PUBLIC SalOp *linphone_proxy_config_get_sal_op(const LinphoneProxyConfig *cfg); +LINPHONE_PUBLIC SalOp *linphone_call_get_op_as_sal_op(const LinphoneCall *call); + +LINPHONE_PUBLIC Sal * sal_init(MSFactory *factory); +LINPHONE_PUBLIC void sal_uninit(Sal* sal); + +LINPHONE_PUBLIC int sal_create_uuid(Sal *ctx, char *uuid, size_t len); +LINPHONE_PUBLIC char *sal_get_random_token(int size); +LINPHONE_PUBLIC void sal_set_uuid(Sal *ctx, const char *uuid); + +LINPHONE_PUBLIC void sal_default_set_sdp_handling(Sal* h, SalOpSDPHandling handling_method) ; +LINPHONE_PUBLIC void sal_set_send_error(Sal *sal,int value); +LINPHONE_PUBLIC void sal_set_recv_error(Sal *sal,int value); +LINPHONE_PUBLIC int sal_enable_pending_trans_checking(Sal *sal, bool_t value); +LINPHONE_PUBLIC void sal_enable_unconditional_answer(Sal *sal,int value); +LINPHONE_PUBLIC void sal_set_dns_timeout(Sal* sal,int timeout); +LINPHONE_PUBLIC void sal_set_dns_user_hosts_file(Sal *sal, const char *hosts_file); +LINPHONE_PUBLIC void *sal_get_stack_impl(Sal *sal); +LINPHONE_PUBLIC void sal_set_refresher_retry_after(Sal *sal,int value); +LINPHONE_PUBLIC int sal_get_refresher_retry_after(const Sal *sal); +LINPHONE_PUBLIC void sal_set_transport_timeout(Sal* sal,int timeout); +LINPHONE_PUBLIC void sal_enable_test_features(Sal*ctx, bool_t enabled); +LINPHONE_PUBLIC int sal_transport_available(Sal *ctx, SalTransport t); + +LINPHONE_PUBLIC const SalErrorInfo *sal_op_get_error_info(const SalOp *op); +LINPHONE_PUBLIC bool_t sal_call_dialog_request_pending(const SalOp *op); +LINPHONE_PUBLIC void sal_call_set_sdp_handling(SalOp *h, SalOpSDPHandling handling); +LINPHONE_PUBLIC SalMediaDescription * sal_call_get_final_media_description(SalOp *h); +#endif + +#ifdef __cplusplus +} +#endif + + + +#endif // _TESTER_UTILS_H_ diff --git a/coreapi/vcard.cc b/coreapi/vcard.cc index b002a28c6..0bd71534d 100644 --- a/coreapi/vcard.cc +++ b/coreapi/vcard.cc @@ -32,6 +32,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define VCARD_MD5_HASH_SIZE 16 using namespace std; +using namespace LINPHONE_NAMESPACE; struct _LinphoneVcardContext { shared_ptr parser; @@ -367,7 +368,7 @@ bool_t linphone_vcard_generate_unique_id(LinphoneVcard *vCard) { if (linphone_vcard_get_uid(vCard)) { return FALSE; } - if (sal_generate_uuid(uuid, sizeof(uuid)) == 0) { + if (Sal::generate_uuid(uuid, sizeof(uuid)) == 0) { char vcard_uuid[sizeof(uuid)+4]; snprintf(vcard_uuid, sizeof(vcard_uuid), "urn:%s", uuid); linphone_vcard_set_uid(vCard, vcard_uuid); diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index a14f73f65..0a83d27b9 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -48,8 +48,8 @@ L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(Call, SalMediaDescription *localdesc; SalMediaDescription *resultdesc; struct _LinphoneCallLog *log; - SalOp *op; - SalOp *ping_op; + LINPHONE_NAMESPACE::SalOp *op; + LINPHONE_NAMESPACE::SalOp *ping_op; LinphoneCallState transfer_state; /*idle if no transfer*/ struct _AudioStream *audiostream; /**/ struct _VideoStream *videostream; @@ -113,7 +113,7 @@ static void _linphone_call_destructor (LinphoneCall *call) { call->text_stats = nullptr; } if (call->op) { - sal_op_release(call->op); + call->op->release(); call->op=nullptr; } if (call->resultdesc) { @@ -125,7 +125,7 @@ static void _linphone_call_destructor (LinphoneCall *call) { call->localdesc=nullptr; } if (call->ping_op) { - sal_op_release(call->ping_op); + call->ping_op->release(); call->ping_op=nullptr; } if (call->refer_to){ @@ -325,7 +325,7 @@ int linphone_call_start_invite (LinphoneCall *call, const LinphoneAddress *desti return 0; } -void linphone_call_replace_op (LinphoneCall *call, SalOp *op) { +void linphone_call_replace_op (LinphoneCall *call, LINPHONE_NAMESPACE::SalOp *op) { #if 0 SalOp *oldop = call->op; LinphoneCallState oldstate = linphone_call_get_state(call); @@ -507,7 +507,7 @@ void linphone_call_refresh_sockets (LinphoneCall *call) { #endif } -SalOp * linphone_call_get_op (const LinphoneCall *call) { +LINPHONE_NAMESPACE::SalCallOp * linphone_call_get_op (const LinphoneCall *call) { return L_GET_PRIVATE_FROM_C_OBJECT(call)->getOp(); } @@ -593,7 +593,7 @@ LinphoneCallState linphone_call_get_state (const LinphoneCall *call) { bool_t linphone_call_asked_to_autoanswer (LinphoneCall *call) { //return TRUE if the unique(for the moment) incoming call asked to be autoanswered if (call) - return sal_call_autoanswer_asked(linphone_call_get_op(call)); + return linphone_call_get_op(call)->autoanswer_asked(); return FALSE; } @@ -1107,8 +1107,8 @@ void linphone_call_ogl_render (const LinphoneCall *call) { LinphoneStatus linphone_call_send_info_message (LinphoneCall *call, const LinphoneInfoMessage *info) { SalBodyHandler *body_handler = sal_body_handler_from_content(linphone_info_message_get_content(info)); - sal_op_set_sent_custom_header(linphone_call_get_op(call), linphone_info_message_get_headers(info)); - return sal_send_info(linphone_call_get_op(call), nullptr, nullptr, body_handler); + linphone_call_get_op(call)->set_sent_custom_header(linphone_info_message_get_headers(info)); + return linphone_call_get_op(call)->send_info(nullptr, nullptr, body_handler); } LinphoneCallStats *linphone_call_get_stats (LinphoneCall *call, LinphoneStreamType type) { @@ -1193,7 +1193,7 @@ LinphoneCall *linphone_call_new_outgoing (LinphoneCore *lc, const LinphoneAddres return call; } -LinphoneCall *linphone_call_new_incoming (LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, SalOp *op) { +LinphoneCall *linphone_call_new_incoming (LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, LINPHONE_NAMESPACE::SalCallOp *op) { LinphoneCall *call = L_INIT(Call); L_SET_CPP_PTR_FROM_C_OBJECT(call, make_shared(call, lc, LinphoneCallIncoming, *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 9ddc5c0e7..1f66d709a 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -34,6 +34,7 @@ // ============================================================================= using namespace std; +using namespace LINPHONE_NAMESPACE; static void _linphone_chat_message_constructor (LinphoneChatMessage *msg); static void _linphone_chat_message_destructor (LinphoneChatMessage *msg); diff --git a/src/call/call-p.h b/src/call/call-p.h index c655c9052..69586713c 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -61,7 +61,7 @@ public: LinphoneProxyConfig *getDestProxy () const; IceSession *getIceSession () const; MediaStream *getMediaStream (LinphoneStreamType type) const; - SalOp *getOp () const; + SalCallOp *getOp () const; void setAudioMuted (bool value); private: diff --git a/src/call/call.cpp b/src/call/call.cpp index b474f60ee..369f2bfd7 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -70,7 +70,7 @@ MediaStream *CallPrivate::getMediaStream (LinphoneStreamType type) const { return static_pointer_cast(getActiveSession())->getPrivate()->getMediaStream(type); } -SalOp *CallPrivate::getOp () const { +SalCallOp * CallPrivate::getOp () const { return getActiveSession()->getPrivate()->getOp(); } @@ -219,7 +219,7 @@ Call::Call ( const Address &from, const Address &to, LinphoneProxyConfig *cfg, - SalOp *op, + SalCallOp *op, const MediaSessionParams *msp ) : Object(*new CallPrivate(call, core, direction, from, to, cfg, op, msp)) { L_D(); diff --git a/src/call/call.h b/src/call/call.h index d809c3563..b42780fb1 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -43,7 +43,7 @@ public: const Address &from, const Address &to, LinphoneProxyConfig *cfg, - SalOp *op, + SalCallOp *op, const MediaSessionParams *msp ); diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 2ea8fb67f..b29f39575 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -29,6 +29,7 @@ #include "chat-message-p.h" #include "chat-room.h" +#include "sal/message_op.h" // ============================================================================= @@ -118,7 +119,7 @@ void ChatRoomPrivate::sendImdn (const string &content, LinphoneReason reason) { identity = linphone_core_get_primary_contact(core); /* Sending out of call */ - SalOp *op = sal_op_new(core->sal); + SalMessageOp *op = new SalMessageOp(core->sal); linphone_configure_op(core, op, peer, nullptr, !!lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0)); LinphoneChatMessage *msg = q->createMessage(content); LinphoneAddress *fromAddr = linphone_address_new(identity); @@ -139,14 +140,14 @@ void ChatRoomPrivate::sendImdn (const string &content, LinphoneReason reason) { } if (retval <= 0) { - sal_message_send(op, identity, peerAddress.asString().c_str(), linphone_chat_message_get_content_type(msg), linphone_chat_message_get_text(msg), nullptr); + op->send_message(identity, peerAddress.asString().c_str(), linphone_chat_message_get_content_type(msg), linphone_chat_message_get_text(msg), nullptr); } linphone_chat_message_unref(msg); linphone_address_unref(fromAddr); linphone_address_unref(toAddr); linphone_address_unref(peer); - sal_op_unref(op); + op->unref(); } // ----------------------------------------------------------------------------- @@ -207,7 +208,7 @@ void ChatRoomPrivate::sendIsComposingNotification () { identity = linphone_core_get_primary_contact(core); /* Sending out of call */ - SalOp *op = sal_op_new(core->sal); + SalMessageOp *op = new SalMessageOp(core->sal); linphone_configure_op(core, op, peer, nullptr, !!lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0)); string content = isComposingHandler.marshal(isComposing); if (!content.empty()) { @@ -228,12 +229,12 @@ void ChatRoomPrivate::sendIsComposingNotification () { } if (retval <= 0) { - sal_message_send(op, identity, peerAddress.asString().c_str(), linphone_chat_message_get_content_type(msg), linphone_chat_message_get_text(msg), nullptr); + op->send_message(identity, peerAddress.asString().c_str(), linphone_chat_message_get_content_type(msg), linphone_chat_message_get_text(msg), nullptr); } linphone_chat_message_unref(msg); linphone_address_unref(fromAddr); - sal_op_unref(op); + op->unref(); } linphone_address_unref(peer); } @@ -393,7 +394,7 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa LinphoneChatMessage *msg; /* Check if this is a duplicate message */ - if ((msg = q->findMessageWithDirection(sal_op_get_call_id(op), LinphoneChatMessageIncoming))) { + if ((msg = q->findMessageWithDirection(op->get_call_id(), LinphoneChatMessageIncoming))) { reason = core->chat_deny_code; if (msg) linphone_chat_message_unref(msg); @@ -406,14 +407,14 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa linphone_chat_message_set_from_address(msg, peer); linphone_address_unref(peer); - LinphoneAddress *to = sal_op_get_to(op) ? linphone_address_new(sal_op_get_to(op)) : linphone_address_new(linphone_core_get_identity(core)); + LinphoneAddress *to = op->get_to() ? linphone_address_new(op->get_to()) : linphone_address_new(linphone_core_get_identity(core)); linphone_chat_message_set_to_address(msg, to); linphone_chat_message_set_time(msg, salMsg->time); linphone_chat_message_set_state(msg, LinphoneChatMessageStateDelivered); linphone_chat_message_set_incoming(msg); - linphone_chat_message_set_message_id(msg, ms_strdup(sal_op_get_call_id(op))); + linphone_chat_message_set_message_id(msg, ms_strdup(op->get_call_id())); - const SalCustomHeader *ch = sal_op_get_recv_custom_header(op); + const SalCustomHeader *ch = op->get_recv_custom_header(); if (ch) linphone_chat_message_set_sal_custom_headers(msg, sal_custom_header_clone(ch)); if (salMsg->url) @@ -844,16 +845,16 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { if (!op) { /* Sending out of call */ - linphone_chat_message_set_sal_op(msg, op = sal_op_new(d->core->sal)); + linphone_chat_message_set_sal_op(msg, op = new SalMessageOp(d->core->sal)); linphone_configure_op( d->core, op, peer, linphone_chat_message_get_sal_custom_headers(msg), !!lp_config_get_int(d->core->config, "sip", "chat_msg_with_contact", 0) ); - sal_op_set_user_pointer(op, msg); /* If out of call, directly store msg */ + op->set_user_pointer(msg); /* If out of call, directly store msg */ } if (retval > 0) { - sal_error_info_set((SalErrorInfo *)sal_op_get_error_info(op), SalReasonNotAcceptable, "SIP", retval, "Unable to encrypt IM", nullptr); + sal_error_info_set((SalErrorInfo *)op->get_error_info(), SalReasonNotAcceptable, "SIP", retval, "Unable to encrypt IM", nullptr); d->storeOrUpdateMessage(msg); linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); linphone_chat_message_unref(msg); @@ -863,13 +864,15 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { if (linphone_chat_message_get_external_body_url(msg)) { char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", linphone_chat_message_get_external_body_url(msg)); - sal_message_send(op, identity.c_str(), d->peerAddress.asString().c_str(), content_type, nullptr, nullptr); + auto msgOp = dynamic_cast(op); + msgOp->send_message(identity.c_str(), d->peerAddress.asString().c_str(), content_type, nullptr, nullptr); ms_free(content_type); } else { + auto msgOp = dynamic_cast(op); if (linphone_chat_message_get_content_type(msg)) { - sal_message_send(op, identity.c_str(), d->peerAddress.asString().c_str(), linphone_chat_message_get_content_type(msg), linphone_chat_message_get_text(msg), d->peerAddress.asStringUriOnly().c_str()); + msgOp->send_message(identity.c_str(), d->peerAddress.asString().c_str(), linphone_chat_message_get_content_type(msg), linphone_chat_message_get_text(msg), d->peerAddress.asStringUriOnly().c_str()); } else { - sal_text_send(op, identity.c_str(), d->peerAddress.asString().c_str(), linphone_chat_message_get_text(msg)); + msgOp->send_message(identity.c_str(), d->peerAddress.asString().c_str(), linphone_chat_message_get_text(msg)); } } @@ -881,7 +884,7 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { /* We replace the encrypted content type by the original one */ linphone_chat_message_set_content_type(msg, ms_strdup(clearTextContentType)); } - linphone_chat_message_set_message_id(msg, ms_strdup(sal_op_get_call_id(op))); /* must be known at that time */ + linphone_chat_message_set_message_id(msg, ms_strdup(op->get_call_id())); /* must be known at that time */ d->storeOrUpdateMessage(msg); if (d->isComposing) diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 961adb590..57e65cdc1 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -72,7 +72,7 @@ void ClientGroupChatRoom::addParticipants (const list
    &addresses, const session->initiateOutgoing(); Address addr = me->getAddress(); addr.setParam("text", ""); - sal_op_set_contact_address(session->getPrivate()->getOp(), addr.getPrivate()->getInternalAddress()); + session->getPrivate()->getOp()->set_contact_address(addr.getPrivate()->getInternalAddress()); session->startInvite(nullptr, d->subject); d->setState(ChatRoom::State::CreationPending); } diff --git a/src/chat/is-composing.cpp b/src/chat/is-composing.cpp index e1ef360b1..7b13a214b 100644 --- a/src/chat/is-composing.cpp +++ b/src/chat/is-composing.cpp @@ -107,7 +107,7 @@ void IsComposing::parse (const string &text) { void IsComposing::startIdleTimer () { unsigned int duration = getIdleTimerDuration(); if (!idleTimer) { - idleTimer = sal_create_timer(core->sal, idleTimerExpired, this, + idleTimer = core->sal->create_timer(idleTimerExpired, this, duration * 1000, "composing idle timeout"); } else { belle_sip_source_set_timeout(idleTimer, duration * 1000); @@ -117,7 +117,7 @@ void IsComposing::startIdleTimer () { void IsComposing::startRefreshTimer () { unsigned int duration = getRefreshTimerDuration(); if (!refreshTimer) { - refreshTimer = sal_create_timer(core->sal, refreshTimerExpired, this, + refreshTimer = core->sal->create_timer(refreshTimerExpired, this, duration * 1000, "composing refresh timeout"); } else { belle_sip_source_set_timeout(refreshTimer, duration * 1000); @@ -129,7 +129,7 @@ void IsComposing::startRemoteRefreshTimer (const char *refreshStr) { if (refreshStr) duration = static_cast(stoi(refreshStr)); if (!remoteRefreshTimer) { - remoteRefreshTimer = sal_create_timer(core->sal, remoteRefreshTimerExpired, this, + remoteRefreshTimer = core->sal->create_timer(remoteRefreshTimerExpired, this, duration * 1000, "composing remote refresh timeout"); } else { belle_sip_source_set_timeout(remoteRefreshTimer, duration * 1000); @@ -154,7 +154,7 @@ void IsComposing::stopTimers () { void IsComposing::stopIdleTimer () { if (idleTimer) { if (core && core->sal) - sal_cancel_timer(core->sal, idleTimer); + core->sal->cancel_timer(idleTimer); belle_sip_object_unref(idleTimer); idleTimer = nullptr; } @@ -163,7 +163,7 @@ void IsComposing::stopIdleTimer () { void IsComposing::stopRefreshTimer () { if (refreshTimer) { if (core && core->sal) - sal_cancel_timer(core->sal, refreshTimer); + core->sal->cancel_timer(refreshTimer); belle_sip_object_unref(refreshTimer); refreshTimer = nullptr; } @@ -172,7 +172,7 @@ void IsComposing::stopRefreshTimer () { void IsComposing::stopRemoteRefreshTimer () { if (remoteRefreshTimer) { if (core && core->sal) - sal_cancel_timer(core->sal, remoteRefreshTimer); + core->sal->cancel_timer(remoteRefreshTimer); belle_sip_object_unref(remoteRefreshTimer); remoteRefreshTimer = nullptr; } diff --git a/src/conference/params/call-session-params.h b/src/conference/params/call-session-params.h index d666afac9..2b01dcfe8 100644 --- a/src/conference/params/call-session-params.h +++ b/src/conference/params/call-session-params.h @@ -23,6 +23,7 @@ #include "linphone/types.h" #include "sal/sal.h" +#include "sal/sal.hpp" // ============================================================================= diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index 790776151..c1b68870f 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -22,6 +22,7 @@ #include "object/object-p.h" #include "call-session.h" +#include "sal/call_op.h" // ============================================================================= @@ -39,7 +40,7 @@ public: void setPingTime (int value) { pingTime = value; } LinphoneProxyConfig * getDestProxy () const { return destProxy; } - SalOp * getOp () const { return op; } + SalCallOp * getOp () const { return op; } virtual void abort (const std::string &errorMsg); virtual void accepted (); @@ -92,7 +93,7 @@ protected: LinphoneErrorInfo *ei = nullptr; LinphoneCallLog *log = nullptr; - SalOp *op = nullptr; + SalCallOp *op = nullptr; SalOp *pingOp = nullptr; bool pingReplied = false; diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 5dd173e5d..eb1922516 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -60,7 +60,7 @@ CallSessionPrivate::~CallSessionPrivate () { if (log) linphone_call_log_unref(log); if (op) - sal_op_release(op); + op->release(); } // ----------------------------------------------------------------------------- @@ -76,7 +76,7 @@ int CallSessionPrivate::computeDuration () const { * end apparently does not support. This features are: privacy, video... */ void CallSessionPrivate::initializeParamsAccordingToIncomingCallParams () { - currentParams->setPrivacy((LinphonePrivacyMask)sal_op_get_privacy(op)); + currentParams->setPrivacy((LinphonePrivacyMask)op->get_privacy()); } void CallSessionPrivate::setState(LinphoneCallState newState, const string &message) { @@ -186,21 +186,21 @@ bool CallSessionPrivate::startPing () { * send an option request back to the caller so that we get a chance to discover our nat'd address * before answering for incoming call */ pingReplied = false; - pingOp = sal_op_new(core->sal); + pingOp = new SalOp(core->sal); if (direction == LinphoneCallIncoming) { - const char *from = sal_op_get_from(pingOp); - const char *to = sal_op_get_to(pingOp); + const char *from = pingOp->get_from(); + const char *to = pingOp->get_to(); linphone_configure_op(core, pingOp, log->from, nullptr, false); - sal_op_set_route(pingOp, sal_op_get_network_origin(op)); - sal_ping(pingOp, from, to); + pingOp->set_route(op->get_network_origin()); + pingOp->ping(from, to); } else if (direction == LinphoneCallOutgoing) { char *from = linphone_address_as_string(log->from); char *to = linphone_address_as_string(log->to); - sal_ping(pingOp, from, to); + pingOp->ping(from, to); ms_free(from); ms_free(to); } - sal_op_set_user_pointer(pingOp, this); + pingOp->set_user_pointer(this); return true; } return false; @@ -209,7 +209,7 @@ bool CallSessionPrivate::startPing () { // ----------------------------------------------------------------------------- void CallSessionPrivate::abort (const string &errorMsg) { - sal_call_terminate(op); + op->terminate(); setState(LinphoneCallError, errorMsg); } @@ -225,7 +225,7 @@ void CallSessionPrivate::accepted () { default: break; } - currentParams->setPrivacy((LinphonePrivacyMask)sal_op_get_privacy(op)); + currentParams->setPrivacy((LinphonePrivacyMask)op->get_privacy()); } void CallSessionPrivate::ackBeingSent (LinphoneHeaders *headers) { @@ -242,12 +242,12 @@ void CallSessionPrivate::ackReceived (LinphoneHeaders *headers) { bool CallSessionPrivate::failure () { L_Q(); - const SalErrorInfo *ei = sal_op_get_error_info(op); + const SalErrorInfo *ei = op->get_error_info(); switch (ei->reason) { case SalReasonRedirect: if ((state == LinphoneCallOutgoingInit) || (state == LinphoneCallOutgoingProgress) || (state == LinphoneCallOutgoingRinging) /* Push notification case */ || (state == LinphoneCallOutgoingEarlyMedia)) { - const SalAddress *redirectionTo = sal_op_get_remote_contact_address(op); + const SalAddress *redirectionTo = op->get_remote_contact_address(); if (redirectionTo) { char *url = sal_address_as_string(redirectionTo); lWarning() << "Redirecting CallSession [" << q << "] to " << url; @@ -285,9 +285,9 @@ bool CallSessionPrivate::failure () { setState(LinphoneCallEnd, "Call declined"); else { if (linphone_call_state_is_early(state)) - setState(LinphoneCallError, ei->full_string); + setState(LinphoneCallError, ei->full_string ? ei->full_string : ""); else - setState(LinphoneCallEnd, ei->full_string); + setState(LinphoneCallEnd, ei->full_string ? ei->full_string : ""); } #if 0 // TODO: handle in Call class if (ei->reason != SalReasonNone) @@ -318,7 +318,7 @@ void CallSessionPrivate::pingReply () { void CallSessionPrivate::remoteRinging () { L_Q(); /* Set privacy */ - q->getCurrentParams()->setPrivacy((LinphonePrivacyMask)sal_op_get_privacy(op)); + q->getCurrentParams()->setPrivacy((LinphonePrivacyMask)op->get_privacy()); #if 0 if (lc->ringstream == NULL) start_remote_ring(lc, call); #endif @@ -334,7 +334,7 @@ void CallSessionPrivate::terminated () { return; case LinphoneCallIncomingReceived: case LinphoneCallIncomingEarlyMedia: - if (!sal_op_get_reason_error_info(op)->protocol || strcmp(sal_op_get_reason_error_info(op)->protocol, "") == 0) { + if (!op->get_reason_error_info()->protocol || strcmp(op->get_reason_error_info()->protocol, "") == 0) { linphone_error_info_set(ei, nullptr, LinphoneReasonNotAnswered, 0, "Incoming call cancelled", nullptr); nonOpError = true; } @@ -383,7 +383,7 @@ void CallSessionPrivate::updated (bool isUpdate) { case LinphoneCallPausing: case LinphoneCallResuming: sal_error_info_set(&sei, SalReasonInternalError, "SIP", 0, nullptr, nullptr); - sal_call_decline_with_error_info(op, &sei, nullptr); + op->decline_with_error_info(&sei, nullptr); BCTBX_NO_BREAK; /* no break */ case LinphoneCallIdle: case LinphoneCallOutgoingInit: @@ -428,10 +428,10 @@ void CallSessionPrivate::accept (const CallSessionParams *params) { setContactOp(); if (params) { this->params = new CallSessionParams(*params); - sal_op_set_sent_custom_header(op, this->params->getPrivate()->getCustomHeaders()); + op->set_sent_custom_header(this->params->getPrivate()->getCustomHeaders()); } - sal_call_accept(op); + op->accept(); if (listener) listener->onSetCurrentSession(*q); setState(LinphoneCallConnected, "Connected"); @@ -455,9 +455,9 @@ LinphoneStatus CallSessionPrivate::checkForAcceptation () const { listener->onCheckForAcceptation(*q); /* Check if this call is supposed to replace an already running one */ - SalOp *replaced = sal_call_get_replaces(op); + SalOp *replaced = op->get_replaces(); if (replaced) { - CallSession *session = reinterpret_cast(sal_op_get_user_pointer(replaced)); + CallSession *session = reinterpret_cast(replaced->get_user_pointer()); if (session) { lInfo() << "CallSession " << q << " replaces CallSession " << session << ". This last one is going to be terminated automatically"; session->terminate(); @@ -470,8 +470,8 @@ void CallSessionPrivate::handleIncomingReceivedStateInIncomingNotification () { L_Q(); /* Try to be best-effort in giving real local or routable contact address for 100Rel case */ setContactOp(); - sal_call_notify_ringing(op, false); - if (sal_call_get_replaces(op) && lp_config_get_int(linphone_core_get_config(core), "sip", "auto_answer_replacing_calls", 1)) + op->notify_ringing(false); + if (op->get_replaces() && lp_config_get_int(linphone_core_get_config(core), "sip", "auto_answer_replacing_calls", 1)) q->accept(); } @@ -524,7 +524,7 @@ void CallSessionPrivate::setReleased () { if (!nonOpError) linphone_error_info_from_sal_op(ei, op); /* So that we cannot have anymore upcalls for SAL concerning this call */ - sal_op_release(op); + op->release(); op = nullptr; } #if 0 @@ -558,8 +558,8 @@ void CallSessionPrivate::setTerminated() { listener->onCallSessionSetTerminated(*q); } -LinphoneStatus CallSessionPrivate::startAcceptUpdate (LinphoneCallState nextState, const string &stateInfo) { - sal_call_accept(op); +LinphoneStatus CallSessionPrivate::startAcceptUpdate (LinphoneCallState nextState, const std::string &stateInfo) { + op->accept(); setState(nextState, stateInfo); return 0; } @@ -577,10 +577,10 @@ LinphoneStatus CallSessionPrivate::startUpdate () { subject = "Media change"; if (destProxy && destProxy->op) { /* Give a chance to update the contact address if connectivity has changed */ - sal_op_set_contact_address(op, sal_op_get_contact_address(destProxy->op)); + op->set_contact_address(destProxy->op->get_contact_address()); } else - sal_op_set_contact_address(op, nullptr); - return sal_call_update(op, subject.c_str(), q->getParams()->getPrivate()->getNoUserConsent()); + op->set_contact_address(nullptr); + return op->update(subject.c_str(), q->getParams()->getPrivate()->getNoUserConsent()); } void CallSessionPrivate::terminate () { @@ -600,7 +600,7 @@ void CallSessionPrivate::setContactOp () { LinphoneAddress *contact = getFixedContact(); if (contact) { salAddress = const_cast(L_GET_PRIVATE_FROM_C_OBJECT(contact)->getInternalAddress()); - sal_op_set_contact_address(op, salAddress); + op->set_contact_address(salAddress); linphone_address_unref(contact); } } @@ -618,16 +618,16 @@ void CallSessionPrivate::completeLog () { void CallSessionPrivate::createOpTo (const LinphoneAddress *to) { L_Q(); if (op) - sal_op_release(op); - op = sal_op_new(core->sal); - sal_op_set_user_pointer(op, q); + op->release(); + op = new SalCallOp(core->sal); + op->set_user_pointer(q); #if 0 if (linphone_call_params_get_referer(call->params)) sal_call_set_referer(call->op,linphone_call_params_get_referer(call->params)->op); #endif linphone_configure_op(core, op, to, q->getParams()->getPrivate()->getCustomHeaders(), false); if (q->getParams()->getPrivacy() != LinphonePrivacyDefault) - sal_op_set_privacy(op, (SalPrivacyMask)q->getParams()->getPrivacy()); + op->set_privacy((SalPrivacyMask)q->getParams()->getPrivacy()); /* else privacy might be set by proxy */ } @@ -635,13 +635,13 @@ void CallSessionPrivate::createOpTo (const LinphoneAddress *to) { LinphoneAddress * CallSessionPrivate::getFixedContact () const { LinphoneAddress *result = nullptr; - if (op && sal_op_get_contact_address(op)) { + if (op && op->get_contact_address()) { /* If already choosed, don't change it */ return nullptr; - } else if (pingOp && sal_op_get_contact_address(pingOp)) { + } else if (pingOp && pingOp->get_contact_address()) { /* If the ping OPTIONS request succeeded use the contact guessed from the received, rport */ lInfo() << "Contact has been fixed using OPTIONS"; - char *addr = sal_address_as_string(sal_op_get_contact_address(pingOp)); + char *addr = sal_address_as_string(pingOp->get_contact_address()); result = linphone_address_new(addr); ms_free(addr); } else if (destProxy && destProxy->op && _linphone_proxy_config_get_contact_without_params(destProxy)) { @@ -688,7 +688,7 @@ LinphoneStatus CallSession::acceptUpdate (const CallSessionParams *csp) { return d->acceptUpdate(csp, d->prevState, linphone_call_state_to_string(d->prevState)); } -void CallSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalOp *op, const Address &from, const Address &to) { +void CallSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalCallOp *op, const Address &from, const Address &to) { L_D(); d->direction = direction; d->destProxy = cfg; @@ -703,10 +703,10 @@ void CallSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg if (op) { /* We already have an op for incoming calls */ d->op = op; - sal_op_set_user_pointer(d->op, this); - sal_op_cnx_ip_to_0000_if_sendonly_enable(op, !!lp_config_get_default_int(linphone_core_get_config(d->core), + d->op->set_user_pointer(this); + op->enable_cnx_ip_to_0000_if_sendonly(!!lp_config_get_default_int(linphone_core_get_config(d->core), "sip", "cnx_ip_to_0000_if_sendonly_enabled", 0)); - d->log->call_id = ms_strdup(sal_op_get_call_id(op)); /* Must be known at that time */ + d->log->call_id = ms_strdup(op->get_call_id()); /* Must be known at that time */ } if (direction == LinphoneCallOutgoing) { @@ -738,9 +738,9 @@ LinphoneStatus CallSession::decline (const LinphoneErrorInfo *ei) { } if (ei) { linphone_error_info_to_sal(ei, &sei); - sal_call_decline_with_error_info(d->op, &sei , nullptr); + d->op->decline_with_error_info(&sei , nullptr); } else - sal_call_decline(d->op, SalReasonDeclined, nullptr); + d->op->decline(SalReasonDeclined, nullptr); sal_error_info_reset(&sei); sal_error_info_reset(&sub_sei); d->terminate(); @@ -841,7 +841,7 @@ int CallSession::startInvite (const Address *destination, const string &subject) char *from = linphone_address_as_string(d->log->from); /* Take a ref because sal_call() may destroy the CallSession if no SIP transport is available */ shared_ptr ref = static_pointer_cast(shared_from_this()); - int result = sal_call(d->op, from, destinationStr.c_str(), subject.empty() ? nullptr : subject.c_str()); + int result = d->op->call(from, destinationStr.c_str(), subject.empty() ? nullptr : subject.c_str()); ms_free(from); if (result < 0) { if ((d->state != LinphoneCallError) && (d->state != LinphoneCallReleased)) { @@ -850,7 +850,7 @@ int CallSession::startInvite (const Address *destination, const string &subject) d->setState(LinphoneCallError, "Call failed"); } } else { - d->log->call_id = ms_strdup(sal_op_get_call_id(d->op)); /* Must be known at that time */ + d->log->call_id = ms_strdup(d->op->get_call_id()); /* Must be known at that time */ d->setState(LinphoneCallOutgoingProgress, "Outgoing call in progress"); } return result; @@ -872,16 +872,16 @@ LinphoneStatus CallSession::terminate (const LinphoneErrorInfo *ei) { return decline(ei); case LinphoneCallOutgoingInit: /* In state OutgoingInit, op has to be destroyed */ - sal_op_release(d->op); + d->op->release(); d->op = nullptr; break; default: if (ei) { linphone_error_info_to_sal(ei, &sei); - sal_call_terminate_with_error(d->op, &sei); + d->op->terminate_with_error(&sei); sal_error_info_reset(&sei); } else - sal_call_terminate(d->op); + d->op->terminate(); break; } @@ -954,7 +954,7 @@ string CallSession::getRemoteContact () const { L_D(); if (d->op) { /* sal_op_get_remote_contact preserves header params */ - return sal_op_get_remote_contact(d->op); + return d->op->get_remote_contact(); } return string(); } @@ -962,7 +962,7 @@ string CallSession::getRemoteContact () const { const CallSessionParams * CallSession::getRemoteParams () { L_D(); if (d->op){ - const SalCustomHeader *ch = sal_op_get_recv_custom_header(d->op); + const SalCustomHeader *ch = d->op->get_recv_custom_header(); if (ch) { /* Instanciate a remote_params only if a SIP message was received before (custom headers indicates this) */ if (!d->remoteParams) @@ -984,7 +984,7 @@ LinphoneCallState CallSession::getState () const { string CallSession::getRemoteUserAgent () const { L_D(); if (d->op) - return sal_op_get_remote_ua(d->op); + return d->op->get_remote_ua(); return string(); } diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index cd5484cc2..74b95461b 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -24,6 +24,7 @@ #include "conference/conference.h" #include "conference/params/call-session-params.h" #include "conference/session/call-session-listener.h" +#include "sal/call_op.h" // ============================================================================= @@ -41,7 +42,7 @@ public: LinphoneStatus accept (const CallSessionParams *csp = nullptr); LinphoneStatus acceptUpdate (const CallSessionParams *csp); - virtual void configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalOp *op, const Address &from, const Address &to); + virtual void configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalCallOp *op, const Address &from, const Address &to); LinphoneStatus decline (LinphoneReason reason); LinphoneStatus decline (const LinphoneErrorInfo *ei); virtual void initiateIncoming (); diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index 7d9cfbe6d..b9e75b401 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -90,13 +90,8 @@ public: LinphoneCallStats *getStats (LinphoneStreamType type) const; int getStreamIndex (LinphoneStreamType type) const; int getStreamIndex (MediaStream *ms) const; - SalOp *getOp () const { - return op; - } - - void setAudioMuted (bool value) { - audioMuted = value; - } + SalCallOp * getOp () const { return op; } + void setAudioMuted (bool value) { audioMuted = value; } private: static OrtpJitterBufferAlgorithm jitterBufferNameToAlgo (const std::string &name); diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 5a2ce5942..9137f16dd 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -132,8 +132,8 @@ void MediaSessionPrivate::accepted () { linphone_task_list_init(&tl); /* Reset the internal call update flag, so it doesn't risk to be copied and used in further re-INVITEs */ params->getPrivate()->setInternalCallUpdate(false); - SalMediaDescription *rmd = sal_call_get_remote_media_description(op); - SalMediaDescription *md = sal_call_get_final_media_description(op); + SalMediaDescription *rmd = op->get_remote_media_description(); + SalMediaDescription *md = op->get_final_media_description(); if (!md && (prevState == LinphoneCallOutgoingEarlyMedia) && resultDesc) { lInfo() << "Using early media SDP since none was received with the 200 OK"; md = resultDesc; @@ -144,7 +144,7 @@ void MediaSessionPrivate::accepted () { /* There is a valid SDP in the response, either offer or answer, and we're able to start/update the streams */ if (rmd) { /* Handle remote ICE attributes if any. */ - iceAgent->updateFromRemoteMediaDescription(localDesc, rmd, !sal_call_is_offerer(op)); + iceAgent->updateFromRemoteMediaDescription(localDesc, rmd, !op->is_offerer()); } LinphoneCallState nextState = LinphoneCallIdle; string nextStateMsg; @@ -246,7 +246,7 @@ void MediaSessionPrivate::ackReceived (LinphoneHeaders *headers) { bool MediaSessionPrivate::failure () { L_Q(); - const SalErrorInfo *ei = sal_op_get_error_info(op); + const SalErrorInfo *ei = op->get_error_info(); switch (ei->reason) { case SalReasonRedirect: stopStreams(); @@ -328,8 +328,8 @@ void MediaSessionPrivate::pausedByRemote () { void MediaSessionPrivate::remoteRinging () { L_Q(); /* Set privacy */ - q->getCurrentParams()->setPrivacy((LinphonePrivacyMask)sal_op_get_privacy(op)); - SalMediaDescription *md = sal_call_get_final_media_description(op); + q->getCurrentParams()->setPrivacy((LinphonePrivacyMask)op->get_privacy()); + SalMediaDescription *md = op->get_final_media_description(); if (md) { /* Initialize the remote call params by invoking linphone_call_get_remote_params(). This is useful as the SDP may not be present in the 200Ok */ q->getRemoteParams(); @@ -385,7 +385,7 @@ void MediaSessionPrivate::terminated () { /* This callback is called when an incoming re-INVITE/ SIP UPDATE modifies the session */ void MediaSessionPrivate::updated (bool isUpdate) { - SalMediaDescription *rmd = sal_call_get_remote_media_description(op); + SalMediaDescription *rmd = op->get_remote_media_description(); switch (state) { case LinphoneCallPausedByRemote: if (sal_media_description_has_dir(rmd, SalStreamSendRecv) || sal_media_description_has_dir(rmd, SalStreamRecvOnly)) { @@ -410,7 +410,7 @@ void MediaSessionPrivate::updated (bool isUpdate) { void MediaSessionPrivate::updating (bool isUpdate) { L_Q(); - SalMediaDescription *rmd = sal_call_get_remote_media_description(op); + SalMediaDescription *rmd = op->get_remote_media_description(); fixCallParams(rmd); if (state != LinphoneCallPaused) { /* Refresh the local description, but in paused state, we don't change anything. */ @@ -420,16 +420,16 @@ void MediaSessionPrivate::updating (bool isUpdate) { params->initDefault(core); } makeLocalMediaDescription(); - sal_call_set_local_media_description(op, localDesc); + op->set_local_media_description(localDesc); } if (rmd) { SalErrorInfo sei; memset(&sei, 0, sizeof(sei)); expectMediaInAck = false; - SalMediaDescription *md = sal_call_get_final_media_description(op); + SalMediaDescription *md = op->get_final_media_description(); if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(core, md))) { sal_error_info_set(&sei, SalReasonNotAcceptable, "SIP", 0, nullptr, nullptr); - sal_call_decline_with_error_info(op, &sei, nullptr); + op->decline_with_error_info(&sei, nullptr); sal_error_info_reset(&sei); return; } @@ -439,7 +439,7 @@ void MediaSessionPrivate::updating (bool isUpdate) { if (diff & (SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED | SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED)) { lWarning() << "Cannot accept this update, it is changing parameters that require user approval"; sal_error_info_set(&sei, SalReasonUnknown, "SIP", 504, "Cannot change the session parameters without prompting the user", nullptr); - sal_call_decline_with_error_info(op, &sei, nullptr); + op->decline_with_error_info(&sei, nullptr); sal_error_info_reset(&sei); return; } @@ -448,7 +448,7 @@ void MediaSessionPrivate::updating (bool isUpdate) { } else { /* Case of a reINVITE or UPDATE without SDP */ expectMediaInAck = true; - sal_call_accept(op); /* Respond with an offer */ + op->accept(); /* Respond with an offer */ /* Don't do anything else in this case, wait for the ACK to receive to notify the app */ } } @@ -767,12 +767,12 @@ void MediaSessionPrivate::initializeParamsAccordingToIncomingCallParams () { CallSessionPrivate::initializeParamsAccordingToIncomingCallParams(); currentParams->getPrivate()->setUpdateCallWhenIceCompleted(params->getPrivate()->getUpdateCallWhenIceCompleted()); params->enableVideo(linphone_core_video_enabled(core) && core->video_policy.automatically_accept); - SalMediaDescription *md = sal_call_get_remote_media_description(op); + SalMediaDescription *md = op->get_remote_media_description(); if (md) { /* It is licit to receive an INVITE without SDP, in this case WE choose the media parameters according to policy */ setCompatibleIncomingCallParams(md); /* Set multicast role & address if any */ - if (!sal_call_is_offerer(op)) { + if (!op->is_offerer()) { for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (md->streams[i].dir == SalStreamInactive) continue; @@ -824,7 +824,7 @@ void MediaSessionPrivate::updateBiggestDesc (SalMediaDescription *md) { } void MediaSessionPrivate::updateRemoteSessionIdAndVer () { - SalMediaDescription *desc = sal_call_get_remote_media_description(op); + SalMediaDescription *desc = op->get_remote_media_description(); if (desc) { remoteSessionId = desc->session_id; remoteSessionVer = desc->session_ver; @@ -1026,7 +1026,7 @@ void MediaSessionPrivate::getLocalIp (const Address &remoteAddr) { /* If a known proxy was identified for this call, then we may have a chance to take the local ip address * from the socket that connects to this proxy */ if (destProxy && destProxy->op) { - ip = sal_op_get_local_address(destProxy->op, nullptr); + ip = destProxy->op->get_local_address(nullptr); if (ip) { lInfo() << "Found media local-ip from signaling."; mediaLocalIp = ip; @@ -1085,9 +1085,9 @@ void MediaSessionPrivate::runStunTestsIfNeeded () { void MediaSessionPrivate::selectIncomingIpVersion () { if (linphone_core_ipv6_enabled(core)) { if (destProxy && destProxy->op) - af = sal_op_get_address_family(destProxy->op); + af = destProxy->op->get_address_family(); else - af = sal_op_get_address_family(op); + af = op->get_address_family(); } else af = AF_INET; } @@ -1110,7 +1110,7 @@ void MediaSessionPrivate::selectOutgoingIpVersion () { if (sal_address_is_ipv6(L_GET_PRIVATE_FROM_C_OBJECT(to)->getInternalAddress())) af = AF_INET6; else if (destProxy && destProxy->op) - af = sal_op_get_address_family(destProxy->op); + af = destProxy->op->get_address_family(); else { char ipv4[LINPHONE_IPADDR_SIZE]; char ipv6[LINPHONE_IPADDR_SIZE]; @@ -1531,15 +1531,15 @@ SalMulticastRole MediaSessionPrivate::getMulticastRole (SalStreamType type) { SalMulticastRole multicastRole = SalMulticastInactive; if (op) { SalStreamDescription *streamDesc = nullptr; - SalMediaDescription *remoteDesc = sal_call_get_remote_media_description(op); + SalMediaDescription *remoteDesc = op->get_remote_media_description(); if (!localDesc && !remoteDesc && (direction == LinphoneCallOutgoing)) { /* Well using call dir */ if (((type == SalAudio) && params->audioMulticastEnabled()) || ((type == SalVideo) && params->videoMulticastEnabled())) multicastRole = SalMulticastSender; - } else if (localDesc && (!remoteDesc || sal_call_is_offerer(op))) { + } else if (localDesc && (!remoteDesc || op->is_offerer())) { streamDesc = sal_media_description_find_best_stream(localDesc, type); - } else if (!sal_call_is_offerer(op) && remoteDesc) { + } else if (!op->is_offerer() && remoteDesc) { streamDesc = sal_media_description_find_best_stream(remoteDesc, type); } @@ -1581,8 +1581,8 @@ void MediaSessionPrivate::setDtlsFingerprint (MSMediaStreamSessions *sessions, c } void MediaSessionPrivate::setDtlsFingerprintOnAllStreams () { - SalMediaDescription *remote = sal_call_get_remote_media_description(op); - SalMediaDescription *result = sal_call_get_final_media_description(op); + SalMediaDescription *remote = op->get_remote_media_description(); + SalMediaDescription *result = op->get_final_media_description(); if (!remote || !result) { /* This can happen in some tricky cases (early-media without SDP in the 200). In that case, simply skip DTLS code */ return; @@ -1692,8 +1692,8 @@ void MediaSessionPrivate::startDtls (MSMediaStreamSessions *sessions, const SalS } void MediaSessionPrivate::startDtlsOnAllStreams () { - SalMediaDescription *remote = sal_call_get_remote_media_description(op); - SalMediaDescription *result = sal_call_get_final_media_description(op); + SalMediaDescription *remote = op->get_remote_media_description(); + SalMediaDescription *result = op->get_final_media_description(); if (!remote || !result) { /* This can happen in some tricky cases (early-media without SDP in the 200). In that case, simply skip DTLS code */ return; @@ -1958,7 +1958,7 @@ void MediaSessionPrivate::configureRtpSessionForRtcpFb (const SalStreamDescripti } void MediaSessionPrivate::configureRtpSessionForRtcpXr (SalStreamType type) { - SalMediaDescription *remote = sal_call_get_remote_media_description(op); + SalMediaDescription *remote = op->get_remote_media_description(); if (!remote) return; const SalStreamDescription *localStream = sal_media_description_find_best_stream(localDesc, type); @@ -2095,7 +2095,7 @@ void MediaSessionPrivate::handleIceEvents (OrtpEvent *ev) { case LinphoneCallIdle: stopStreamsForIceGathering(); updateLocalMediaDescriptionFromIce(); - sal_call_set_local_media_description(op, localDesc); + op->set_local_media_description(localDesc); deferIncomingNotification = false; static_cast(q)->startIncomingNotification(); break; @@ -2194,7 +2194,7 @@ void MediaSessionPrivate::initializeAudioStream () { SalMediaDescription *remoteDesc = nullptr; SalStreamDescription *streamDesc = nullptr; if (op) - remoteDesc = sal_call_get_remote_media_description(op); + remoteDesc = op->get_remote_media_description(); if (remoteDesc) streamDesc = sal_media_description_find_best_stream(remoteDesc, SalAudio); @@ -2303,7 +2303,7 @@ void MediaSessionPrivate::initializeTextStream () { SalMediaDescription *remoteDesc = nullptr; SalStreamDescription *streamDesc = nullptr; if (op) - remoteDesc = sal_call_get_remote_media_description(op); + remoteDesc = op->get_remote_media_description(); if (remoteDesc) streamDesc = sal_media_description_find_best_stream(remoteDesc, SalText); @@ -2347,7 +2347,7 @@ void MediaSessionPrivate::initializeVideoStream () { SalMediaDescription *remoteDesc = nullptr; SalStreamDescription *streamDesc = nullptr; if (op) - remoteDesc = sal_call_get_remote_media_description(op); + remoteDesc = op->get_remote_media_description(); if (remoteDesc) streamDesc = sal_media_description_find_best_stream(remoteDesc, SalVideo); @@ -2678,7 +2678,7 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool currentParams->getPrivate()->setInConference(params->getPrivate()->getInConference()); currentParams->enableLowBandwidth(params->lowBandwidthEnabled()); /* Start ZRTP engine if needed : set here or remote have a zrtp-hash attribute */ - SalMediaDescription *remote = sal_call_get_remote_media_description(op); + SalMediaDescription *remote = op->get_remote_media_description(); const SalStreamDescription *remoteStream = sal_media_description_find_best_stream(remote, SalAudio); if (linphone_core_media_encryption_supported(core, LinphoneMediaEncryptionZRTP) && ((params->getMediaEncryption() == LinphoneMediaEncryptionZRTP) || (remoteStream->haveZrtpHash == 1))) { @@ -2929,7 +2929,7 @@ void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { if (listener) listener->onResetFirstVideoFrameDecoded(*q); /* Start ZRTP engine if needed : set here or remote have a zrtp-hash attribute */ - SalMediaDescription *remote = sal_call_get_remote_media_description(op); + SalMediaDescription *remote = op->get_remote_media_description(); const SalStreamDescription *remoteStream = sal_media_description_find_best_stream(remote, SalVideo); if ((params->getMediaEncryption() == LinphoneMediaEncryptionZRTP) || (remoteStream->haveZrtpHash == 1)) { /* Audio stream is already encrypted and video stream is active */ @@ -3310,7 +3310,7 @@ uint16_t MediaSessionPrivate::getAvpfRrInterval () const { unsigned int MediaSessionPrivate::getNbActiveStreams () const { SalMediaDescription *md = nullptr; if (op) - md = sal_call_get_remote_media_description(op); + md = op->get_remote_media_description(); if (!md) return 0; return sal_media_description_nb_active_streams_of_type(md, SalAudio) + sal_media_description_nb_active_streams_of_type(md, SalVideo) + sal_media_description_nb_active_streams_of_type(md, SalText); @@ -3450,7 +3450,7 @@ void MediaSessionPrivate::updateReportingMediaInfo (int statsType) { if (!op || !mediaReportEnabled(statsType)) return; - char *dialogId = sal_op_get_dialog_id(op); + char *dialogId = op->get_dialog_id(); reporting_session_report_t * report = log->reporting.reports[statsType]; STR_REASSIGN(report->info.call_id, ms_strdup(log->call_id)); @@ -3638,8 +3638,8 @@ void MediaSessionPrivate::handleIncomingReceivedStateInIncomingNotification () { if (proposeEarlyMedia) q->acceptEarlyMedia(); else - sal_call_notify_ringing(op, false); - if (sal_call_get_replaces(op) && !!lp_config_get_int(linphone_core_get_config(core), "sip", "auto_answer_replacing_calls", 1)) + op->notify_ringing(false); + if (op->get_replaces() && !!lp_config_get_int(linphone_core_get_config(core), "sip", "auto_answer_replacing_calls", 1)) q->accept(); } @@ -3674,8 +3674,8 @@ LinphoneStatus MediaSessionPrivate::pause () { #endif setState(LinphoneCallPausing, "Pausing call"); makeLocalMediaDescription(); - sal_call_set_local_media_description(op, localDesc); - sal_call_update(op, subject.c_str(), false); + op->set_local_media_description(localDesc); + op->update(subject.c_str(), false); if (listener) listener->onResetCurrentSession(*q); if (audioStream || videoStream || textStream) @@ -3696,9 +3696,9 @@ LinphoneStatus MediaSessionPrivate::startAcceptUpdate (LinphoneCallState nextSta } makeLocalMediaDescription(); updateRemoteSessionIdAndVer(); - sal_call_set_local_media_description(op, localDesc); - sal_call_accept(op); - SalMediaDescription *md = sal_call_get_final_media_description(op); + op->set_local_media_description(localDesc); + op->accept(); + SalMediaDescription *md = op->get_final_media_description(); iceAgent->stopIceForInactiveStreams(md); if (md && !sal_media_description_empty(md)) updateStreams(md, nextState); @@ -3711,14 +3711,14 @@ LinphoneStatus MediaSessionPrivate::startUpdate () { if (!params->getPrivate()->getNoUserConsent()) makeLocalMediaDescription(); if (!core->sip_conf.sdp_200_ack) - sal_call_set_local_media_description(op, localDesc); + op->set_local_media_description(localDesc); else - sal_call_set_local_media_description(op, nullptr); + op->set_local_media_description(nullptr); LinphoneStatus result = CallSessionPrivate::startUpdate(); if (core->sip_conf.sdp_200_ack) { /* We are NOT offering, set local media description after sending the call so that we are ready to * process the remote offer when it will arrive. */ - sal_call_set_local_media_description(op, localDesc); + op->set_local_media_description(localDesc); } return result; } @@ -3842,7 +3842,7 @@ void MediaSessionPrivate::accept (const MediaSessionParams *csp) { params = new MediaSessionParams(*csp); iceAgent->prepare(localDesc, true); makeLocalMediaDescription(); - sal_call_set_local_media_description(op, localDesc); + op->set_local_media_description(localDesc); } updateRemoteSessionIdAndVer(); @@ -3864,7 +3864,7 @@ void MediaSessionPrivate::accept (const MediaSessionParams *csp) { CallSessionPrivate::accept(params); - SalMediaDescription *newMd = sal_call_get_final_media_description(op); + SalMediaDescription *newMd = op->get_final_media_description(); iceAgent->stopIceForInactiveStreams(newMd); if (newMd) { updateStreams(newMd, LinphoneCallStreamsRunning); @@ -3875,19 +3875,19 @@ void MediaSessionPrivate::accept (const MediaSessionParams *csp) { LinphoneStatus MediaSessionPrivate::acceptUpdate (const CallSessionParams *csp, LinphoneCallState nextState, const string &stateInfo) { L_Q(); - SalMediaDescription *desc = sal_call_get_remote_media_description(op); + SalMediaDescription *desc = op->get_remote_media_description(); bool keepSdpVersion = !!lp_config_get_int(linphone_core_get_config(core), "sip", "keep_sdp_version", 0); if (keepSdpVersion && (desc->session_id == remoteSessionId) && (desc->session_ver == remoteSessionVer)) { /* Remote has sent an INVITE with the same SDP as before, so send a 200 OK with the same SDP as before. */ lWarning() << "SDP version has not changed, send same SDP as before"; - sal_call_accept(op); + op->accept(); setState(nextState, stateInfo); return 0; } if (csp) params = new MediaSessionParams(*static_cast(csp)); else { - if (!sal_call_is_offerer(op)) { + if (!op->is_offerer()) { /* Reset call params for multicast because this param is only relevant when offering */ params->enableAudioMulticast(false); params->enableVideoMulticast(false); @@ -4047,12 +4047,12 @@ LinphoneStatus MediaSession::acceptEarlyMedia (const MediaSessionParams *msp) { if (msp) { d->params = new MediaSessionParams(*msp); d->makeLocalMediaDescription(); - sal_call_set_local_media_description(d->op, d->localDesc); - sal_op_set_sent_custom_header(d->op, d->params->getPrivate()->getCustomHeaders()); + d->op->set_local_media_description(d->localDesc); + d->op->set_sent_custom_header(d->params->getPrivate()->getCustomHeaders()); } - sal_call_notify_ringing(d->op, true); + d->op->notify_ringing(true); d->setState(LinphoneCallIncomingEarlyMedia, "Incoming call early media"); - SalMediaDescription *md = sal_call_get_final_media_description(d->op); + SalMediaDescription *md = d->op->get_final_media_description(); if (md) d->updateStreams(md, d->state); return 0; @@ -4069,7 +4069,7 @@ LinphoneStatus MediaSession::acceptUpdate (const MediaSessionParams *msp) { // ----------------------------------------------------------------------------- -void MediaSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalOp *op, const Address &from, const Address &to) { +void MediaSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalCallOp *op, const Address &from, const Address &to) { L_D(); CallSession::configure (direction, cfg, op, from, to); @@ -4103,7 +4103,7 @@ void MediaSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cf d->params = new MediaSessionParams(); d->params->initDefault(d->core); d->initializeParamsAccordingToIncomingCallParams(); - SalMediaDescription *md = sal_call_get_remote_media_description(d->op); + SalMediaDescription *md = d->op->get_remote_media_description(); if (d->natPolicy && linphone_nat_policy_ice_enabled(d->natPolicy)) { if (md) { /* Create the ice session now if ICE is required */ @@ -4189,14 +4189,14 @@ LinphoneStatus MediaSession::resume () { audio_stream_play(d->audioStream, nullptr); d->makeLocalMediaDescription(); if (!d->core->sip_conf.sdp_200_ack) - sal_call_set_local_media_description(d->op, d->localDesc); + d->op->set_local_media_description(d->localDesc); else - sal_call_set_local_media_description(d->op, nullptr); + d->op->set_local_media_description(nullptr); sal_media_description_set_dir(d->localDesc, SalStreamSendRecv); string subject = "Call resuming"; if (d->params->getPrivate()->getInConference() && !getCurrentParams()->getPrivate()->getInConference()) subject = "Conference"; - if (sal_call_update(d->op, subject.c_str(), false) != 0) + if (d->op->update(subject.c_str(), false) != 0) return -1; d->setState(LinphoneCallResuming,"Resuming"); if (!d->params->getPrivate()->getInConference() && d->listener) @@ -4204,7 +4204,7 @@ LinphoneStatus MediaSession::resume () { if (d->core->sip_conf.sdp_200_ack) { /* We are NOT offering, set local media description after sending the call so that we are ready to * process the remote offer when it will arrive. */ - sal_call_set_local_media_description(d->op, d->localDesc); + d->op->set_local_media_description(d->localDesc); } return 0; } @@ -4220,7 +4220,7 @@ void MediaSession::sendVfuRequest () { } else if (d->core->sip_conf.vfu_with_info) { lInfo() << "Request SIP INFO FIR on CallSession [" << this << "]"; if (d->state == LinphoneCallStreamsRunning) - sal_call_send_vfu_request(d->op); + d->op->send_vfu_request(); } else lInfo() << "vfu request using sip disabled from config [sip,vfu_with_info]"; #endif @@ -4229,8 +4229,8 @@ void MediaSession::sendVfuRequest () { void MediaSession::startIncomingNotification () { L_D(); d->makeLocalMediaDescription(); - sal_call_set_local_media_description(d->op, d->localDesc); - SalMediaDescription *md = sal_call_get_final_media_description(d->op); + d->op->set_local_media_description(d->localDesc); + SalMediaDescription *md = d->op->get_final_media_description(); if (md) { if (sal_media_description_empty(md) || linphone_core_incompatible_security(d->core, md)) { LinphoneErrorInfo *ei = linphone_error_info_new(); @@ -4238,7 +4238,7 @@ void MediaSession::startIncomingNotification () { #if 0 linphone_core_report_early_failed_call(d->core, LinphoneCallIncoming, linphone_address_ref(from_addr), linphone_address_ref(to_addr), ei); #endif - sal_call_decline(d->op, SalReasonNotAcceptable, nullptr); + d->op->decline(SalReasonNotAcceptable, nullptr); #if 0 linphone_call_unref(call); #endif @@ -4262,7 +4262,7 @@ int MediaSession::startInvite (const Address *destination, const string &subject } if (!d->core->sip_conf.sdp_200_ack) { /* We are offering, set local media description before sending the call */ - sal_call_set_local_media_description(d->op, d->localDesc); + d->op->set_local_media_description(d->localDesc); } int result = CallSession::startInvite(destination, subject); @@ -4274,7 +4274,7 @@ int MediaSession::startInvite (const Address *destination, const string &subject if (d->core->sip_conf.sdp_200_ack) { /* We are NOT offering, set local media description after sending the call so that we are ready to process the remote offer when it will arrive. */ - sal_call_set_local_media_description(d->op, d->localDesc); + d->op->set_local_media_description(d->localDesc); } return result; } @@ -4585,7 +4585,7 @@ float MediaSession::getRecordVolume () const { const MediaSessionParams * MediaSession::getRemoteParams () { L_D(); if (d->op){ - SalMediaDescription *md = sal_call_get_remote_media_description(d->op); + SalMediaDescription *md = d->op->get_remote_media_description(); if (md) { if (d->remoteParams) delete d->remoteParams; @@ -4623,7 +4623,7 @@ const MediaSessionParams * MediaSession::getRemoteParams () { d->remoteParams->getPrivate()->setCustomSdpMediaAttributes(LinphoneStreamTypeVideo, md->streams[d->mainVideoStreamIndex].custom_sdp_attributes); d->remoteParams->getPrivate()->setCustomSdpMediaAttributes(LinphoneStreamTypeText, md->streams[d->mainTextStreamIndex].custom_sdp_attributes); } - const SalCustomHeader *ch = sal_op_get_recv_custom_header(d->op); + const SalCustomHeader *ch = d->op->get_recv_custom_header(); if (ch) { /* Instanciate a remote_params only if a SIP message was received before (custom headers indicates this) */ if (!d->remoteParams) diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index 27770ebb1..00aeebdfe 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -40,7 +40,7 @@ public: LinphoneStatus accept (const MediaSessionParams *msp = nullptr); LinphoneStatus acceptEarlyMedia (const MediaSessionParams *msp = nullptr); LinphoneStatus acceptUpdate (const MediaSessionParams *msp); - void configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalOp *op, const Address &from, const Address &to) override; + void configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalCallOp *op, const Address &from, const Address &to) override; void initiateIncoming () override; bool initiateOutgoing () override; void iterate (time_t currentRealTime, bool oneSecondElapsed) override; diff --git a/src/nat/ice-agent.cpp b/src/nat/ice-agent.cpp index 0a8e19c10..d002234c2 100644 --- a/src/nat/ice-agent.cpp +++ b/src/nat/ice-agent.cpp @@ -73,7 +73,7 @@ void IceAgent::deleteSession () { } void IceAgent::gatheringFinished () { - const SalMediaDescription *rmd = sal_call_get_remote_media_description(mediaSession.getPrivate()->getOp()); + const SalMediaDescription *rmd = mediaSession.getPrivate()->getOp()->get_remote_media_description(); if (rmd) clearUnusedIceCandidates(mediaSession.getPrivate()->getLocalDesc(), rmd); if (!iceSession) @@ -126,7 +126,7 @@ bool IceAgent::prepare (const SalMediaDescription *localDesc, bool incomingOffer SalMediaDescription *remoteDesc = nullptr; bool hasVideo = false; if (incomingOffer) { - remoteDesc = sal_call_get_remote_media_description(mediaSession.getPrivate()->getOp()); + remoteDesc = mediaSession.getPrivate()->getOp()->get_remote_media_description(); hasVideo = linphone_core_video_enabled(mediaSession.getPrivate()->getCore()) && linphone_core_media_description_contains_video_stream(remoteDesc); } else diff --git a/tester/account_creator_tester.c b/tester/account_creator_tester.c index dadf2c3ef..5588ae4c1 100644 --- a/tester/account_creator_tester.c +++ b/tester/account_creator_tester.c @@ -17,7 +17,7 @@ */ #include "liblinphone_tester.h" -#include "private.h" +#include static const char XMLRPC_URL[] = "https://sip2.linphone.org:446/xmlrpc.php"; @@ -338,6 +338,20 @@ static void account_creator_cb(LinphoneAccountCreator *creator, LinphoneAccountC account_creator_set_cb_done(cbs); } +static void set_string(char **dest, const char *src, bool_t lowercase) { + if (*dest) { + ms_free(*dest); + *dest = NULL; + } + if (src) { + *dest = ms_strdup(src); + if (lowercase) { + char *cur = *dest; + for (; *cur; cur++) *cur = tolower(*cur); + } + } +} + static void _get_activation_code_cb(LinphoneXmlRpcRequest *request) { LinphoneAccountCreator *creator = (LinphoneAccountCreator *)linphone_xml_rpc_request_get_user_data(request); LinphoneAccountCreatorStatus status = LinphoneAccountCreatorStatusRequestFailed; diff --git a/tester/accountmanager.c b/tester/accountmanager.c index 3fc4e265a..a26f3f94f 100644 --- a/tester/accountmanager.c +++ b/tester/accountmanager.c @@ -16,8 +16,9 @@ along with this program. If not, see . */ +#include #include "liblinphone_tester.h" -#include "private.h" +#include "tester_utils.h" struct _Account{ LinphoneAddress *identity; @@ -100,7 +101,7 @@ static void account_created_on_server_cb(LinphoneCore *lc, LinphoneProxyConfig * Account *account=(Account*)linphone_core_get_user_data(lc); switch(state){ case LinphoneRegistrationOk: { - char * phrase = sal_op_get_error_info((SalOp*)cfg->op)->full_string; + char * phrase = sal_op_get_error_info(linphone_proxy_config_get_sal_op(cfg))->full_string; if (phrase && strcasecmp("Test account created", phrase) == 0) { account->created=1; } else { @@ -236,10 +237,10 @@ static LinphoneAddress *account_manager_check_account(AccountManager *m, Linphon /* create and/or set uuid */ if (account->uuid == NULL) { char tmp[64]; - sal_create_uuid(cm->lc->sal, tmp, sizeof(tmp)); + sal_create_uuid(linphone_core_get_sal(cm->lc), tmp, sizeof(tmp)); account->uuid = bctbx_strdup(tmp); } - sal_set_uuid(cm->lc->sal, account->uuid); + sal_set_uuid(linphone_core_get_sal(cm->lc), account->uuid); } /*remove previous auth info to avoid mismatching*/ diff --git a/tester/audio_bypass_tester.c b/tester/audio_bypass_tester.c index 1d85bdbef..98809f1f3 100644 --- a/tester/audio_bypass_tester.c +++ b/tester/audio_bypass_tester.c @@ -17,7 +17,6 @@ */ #include "liblinphone_tester.h" -#include "private.h" #include "audio_bypass_wav_header.h" // This is a copy of mediastreamer2/src/audiofilters/wav_header.h /********************************************************************** @@ -436,7 +435,7 @@ static void only_enable_payload(LinphoneCore *lc, const char *mime, int rate, in * This is important so that the audio comparison is succesful*/ static void set_jitter_buffer_params(LinphoneCore *lc){ int jitter_buffer_ms = 300; - lp_config_set_int(lc->config, "rtp", "jitter_buffer_min_size", jitter_buffer_ms); + lp_config_set_int(linphone_core_get_config(lc), "rtp", "jitter_buffer_min_size", jitter_buffer_ms); linphone_core_set_audio_jittcomp(lc, jitter_buffer_ms); } @@ -457,8 +456,8 @@ static void audio_bypass(void) { double similar=1; const double threshold = 0.85; - lp_config_set_string(marie_lc->config, "sound", "features", "None"); - lp_config_set_string(pauline_lc->config, "sound", "features", "None"); + lp_config_set_string(linphone_core_get_config(marie_lc), "sound", "features", "None"); + lp_config_set_string(linphone_core_get_config(pauline_lc), "sound", "features", "None"); /*make sure the record file doesn't already exists, otherwise this test will append new samples to it*/ unlink(recordpath); diff --git a/tester/call_multi_tester.c b/tester/call_multi_tester.c index 11c0718a5..56581a1e8 100644 --- a/tester/call_multi_tester.c +++ b/tester/call_multi_tester.c @@ -21,7 +21,6 @@ #include #include "linphone/core.h" #include "linphone/lpconfig.h" -#include "private.h" #include "liblinphone_tester.h" #include "mediastreamer2/msutils.h" #include "belle-sip/sipstack.h" @@ -259,7 +258,7 @@ static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManag lcs=bctbx_list_append(lcs,laure->lc); if (focus) lcs=bctbx_list_append(lcs,focus->lc); - is_remote_conf = (strcmp(lp_config_get_string(marie->lc->config, "misc", "conference_type", "local"), "remote") == 0); + is_remote_conf = (strcmp(lp_config_get_string(linphone_core_get_config(marie->lc), "misc", "conference_type", "local"), "remote") == 0); if(is_remote_conf) BC_ASSERT_PTR_NOT_NULL(focus); if (!BC_ASSERT_TRUE(call(marie,pauline))) goto end; @@ -836,7 +835,7 @@ static void eject_from_3_participants_conference(LinphoneCoreManager *marie, Lin lcs=bctbx_list_append(lcs,laure->lc); if(focus) lcs=bctbx_list_append(lcs,focus->lc); - is_remote_conf = (strcmp(lp_config_get_string(marie->lc->config, "misc", "conference_type", "local"), "remote") == 0); + is_remote_conf = (strcmp(lp_config_get_string(linphone_core_get_config(marie->lc), "misc", "conference_type", "local"), "remote") == 0); if(is_remote_conf) BC_ASSERT_PTR_NOT_NULL(focus); BC_ASSERT_TRUE(call(marie,pauline)); @@ -1130,7 +1129,7 @@ void do_not_stop_ringing_when_declining_one_of_two_incoming_calls(void) { linphone_call_decline(pauline_called_by_laure, LinphoneReasonDeclined); BC_ASSERT_TRUE(wait_for(laure->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - BC_ASSERT_TRUE(linphone_ringtoneplayer_is_started(pauline->lc->ringtoneplayer)); + BC_ASSERT_TRUE(linphone_ringtoneplayer_is_started(linphone_core_get_ringtoneplayer(pauline->lc))); linphone_call_terminate(pauline_called_by_marie); BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallEnd,2)); diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index cf7f0969c..c658917d8 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -21,7 +21,6 @@ #include #include "linphone/core.h" #include "linphone/lpconfig.h" -#include "private.h" #include "liblinphone_tester.h" #include "mediastreamer2/msutils.h" #include "belle-sip/sipstack.h" @@ -45,10 +44,11 @@ extern void libmsopenh264_init(MSFactory *factory); void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg){ - char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to); - char* from=linphone_address_as_string(linphone_call_get_call_log(call)->from); + LinphoneCallLog *calllog = linphone_call_get_call_log(call); + char* to=linphone_address_as_string(linphone_call_log_get_to(calllog)); + char* from=linphone_address_as_string(linphone_call_log_get_from(calllog)); stats* counters; - ms_message(" %s call from [%s] to [%s], new state is [%s]" ,linphone_call_get_call_log(call)->dir==LinphoneCallIncoming?"Incoming":"Outgoing" + ms_message(" %s call from [%s] to [%s], new state is [%s]" ,linphone_call_log_get_dir(calllog)==LinphoneCallIncoming?"Incoming":"Outgoing" ,from ,to ,linphone_call_state_to_string(cstate)); @@ -131,10 +131,11 @@ void call_stats_updated(LinphoneCore *lc, LinphoneCall *call, const LinphoneCall } void linphone_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token) { - char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to); - char* from=linphone_address_as_string(linphone_call_get_call_log(call)->from); + LinphoneCallLog *calllog = linphone_call_get_call_log(call); + char* to=linphone_address_as_string(linphone_call_log_get_to(calllog)); + char* from=linphone_address_as_string(linphone_call_log_get_from(calllog)); stats* counters; - ms_message(" %s call from [%s] to [%s], is now [%s]",linphone_call_get_call_log(call)->dir==LinphoneCallIncoming?"Incoming":"Outgoing" + ms_message(" %s call from [%s] to [%s], is now [%s]",linphone_call_log_get_dir(calllog)==LinphoneCallIncoming?"Incoming":"Outgoing" ,from ,to ,(on?"encrypted":"unencrypted")); @@ -148,8 +149,9 @@ void linphone_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool } void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state) { - char* to=linphone_address_as_string(linphone_call_get_call_log(transfered)->to); - char* from=linphone_address_as_string(linphone_call_get_call_log(transfered)->from); + LinphoneCallLog *clog = linphone_call_get_call_log(transfered); + char* to=linphone_address_as_string(linphone_call_log_get_to(clog)); + char* from=linphone_address_as_string(linphone_call_log_get_to(clog)); stats* counters; ms_message("Transferred call from [%s] to [%s], new state is [%s]",from,to,linphone_call_state_to_string(new_call_state)); ms_free(to); @@ -171,8 +173,9 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, void linphone_call_iframe_decoded_cb(LinphoneCall *call,void * user_data) { - char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to); - char* from=linphone_address_as_string(linphone_call_get_call_log(call)->from); + LinphoneCallLog *calllog = linphone_call_get_call_log(call); + char* to=linphone_address_as_string(linphone_call_log_get_to(calllog)); + char* from=linphone_address_as_string(linphone_call_log_get_from(calllog)); stats* counters; LinphoneCore* lc=(LinphoneCore*)user_data; ms_message("call from [%s] to [%s] receive iFrame",from,to); @@ -265,9 +268,9 @@ void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreMana static void setup_sdp_handling(const LinphoneCallTestParams* params, LinphoneCoreManager* mgr ){ if( params->sdp_removal ){ - sal_default_set_sdp_handling(mgr->lc->sal, SalOpSDPSimulateRemove); + sal_default_set_sdp_handling(linphone_core_get_sal(mgr->lc), SalOpSDPSimulateRemove); } else if( params->sdp_simulate_error ){ - sal_default_set_sdp_handling(mgr->lc->sal, SalOpSDPSimulateError); + sal_default_set_sdp_handling(linphone_core_get_sal(mgr->lc), SalOpSDPSimulateError); } } @@ -318,8 +321,8 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr ,initial_callee.number_of_LinphoneCallIncomingReceived+1); BC_ASSERT_EQUAL(did_receive_call, !callee_test_params->sdp_simulate_error, int, "%d"); - sal_default_set_sdp_handling(caller_mgr->lc->sal, SalOpSDPNormal); - sal_default_set_sdp_handling(callee_mgr->lc->sal, SalOpSDPNormal); + sal_default_set_sdp_handling(linphone_core_get_sal(caller_mgr->lc), SalOpSDPNormal); + sal_default_set_sdp_handling(linphone_core_get_sal(caller_mgr->lc), SalOpSDPNormal); if (!did_receive_call) return 0; @@ -354,7 +357,7 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr if (linphone_call_params_get_privacy(linphone_call_get_current_params(linphone_core_get_current_call(caller_mgr->lc))) == LinphonePrivacyNone) { /*don't check in case of p asserted id*/ - if (!lp_config_get_int(callee_mgr->lc->config,"sip","call_logs_use_asserted_id_instead_of_from",0)) + if (!lp_config_get_int(linphone_core_get_config(callee_mgr->lc),"sip","call_logs_use_asserted_id_instead_of_from",0)) BC_ASSERT_TRUE(linphone_address_weak_equal(callee_from,linphone_call_get_remote_address(callee_call))); } else { BC_ASSERT_FALSE(linphone_address_weak_equal(callee_from,linphone_call_get_remote_address(linphone_core_get_current_call(callee_mgr->lc)))); @@ -416,8 +419,8 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr if (linphone_core_get_firewall_policy(caller_mgr->lc) == LinphonePolicyUseIce && linphone_core_get_firewall_policy(callee_mgr->lc) == LinphonePolicyUseIce && !linphone_core_sdp_200_ack_enabled(caller_mgr->lc) /*ice does not work with sdp less invite*/ - && lp_config_get_int(callee_mgr->lc->config, "sip", "update_call_when_ice_completed", TRUE) - && lp_config_get_int(caller_mgr->lc->config, "sip", "update_call_when_ice_completed", TRUE) + && lp_config_get_int(linphone_core_get_config(callee_mgr->lc), "sip", "update_call_when_ice_completed", TRUE) + && lp_config_get_int(linphone_core_get_config(callee_mgr->lc), "sip", "update_call_when_ice_completed", TRUE) && linphone_core_get_media_encryption(caller_mgr->lc) != LinphoneMediaEncryptionDTLS /*no ice-reinvite with DTLS*/) { BC_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_caller.number_of_LinphoneCallStreamsRunning+2)); BC_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_callee.number_of_LinphoneCallStreamsRunning+2)); @@ -655,19 +658,19 @@ static void call_with_timed_out_bye(void) { BC_ASSERT_TRUE(call(marie,pauline)); - sal_set_send_error(pauline->lc->sal,1500); /*to trash the message without generating error*/ + sal_set_send_error(linphone_core_get_sal(pauline->lc),1500); /*to trash the message without generating error*/ timer_config.T1=50; /*to have timer F = 3s*/ timer_config.T2=4000; timer_config.T3=0; timer_config.T4=5000; - belle_sip_stack_set_timer_config(sal_get_stack_impl(pauline->lc->sal),&timer_config); + belle_sip_stack_set_timer_config(sal_get_stack_impl(linphone_core_get_sal(pauline->lc)),&timer_config); linphone_core_terminate_all_calls(pauline->lc); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1,timer_config.T1*84)); - sal_set_send_error(pauline->lc->sal,0); + sal_set_send_error(linphone_core_get_sal(pauline->lc),0); linphone_core_terminate_all_calls(marie->lc); BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1,5000)); @@ -1269,7 +1272,7 @@ static void call_with_dns_time_out(void) { linphone_core_set_sip_transports(marie->lc,&transport); linphone_core_iterate(marie->lc); - sal_set_dns_timeout(marie->lc->sal,0); + sal_set_dns_timeout(linphone_core_get_sal(marie->lc),0); linphone_core_invite(marie->lc,"\"t\x8et\x8e\" "); /*just to use non ascii values*/ for(i=0;i<10;i++){ ms_usleep(200000); @@ -1503,7 +1506,7 @@ static void call_with_no_sdp_ack_without_sdp(void){ BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallIncomingReceived,1)); call=linphone_core_get_current_call(pauline->lc); if (call){ - sal_call_set_sdp_handling(linphone_call_get_op(call), SalOpSDPSimulateError); /*this will have the effect that the SDP received in the ACK will be ignored*/ + sal_call_set_sdp_handling(linphone_call_get_op_as_sal_op(call), SalOpSDPSimulateError); /*this will have the effect that the SDP received in the ACK will be ignored*/ linphone_call_accept(call); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1)); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); @@ -1954,8 +1957,8 @@ static void call_caller_with_custom_header_or_sdp_attributes(void) { linphone_call_params_unref(caller_params); - sal_default_set_sdp_handling(caller_mgr->lc->sal, SalOpSDPNormal); - sal_default_set_sdp_handling(callee_mgr->lc->sal, SalOpSDPNormal); + sal_default_set_sdp_handling(linphone_core_get_sal(caller_mgr->lc), SalOpSDPNormal); + sal_default_set_sdp_handling(linphone_core_get_sal(caller_mgr->lc), SalOpSDPNormal); // Wait for Outgoing Progress if (linphone_core_get_calls_nb(callee_mgr->lc)<=1) @@ -2074,8 +2077,8 @@ static void call_callee_with_custom_header_or_sdp_attributes(void) { - sal_default_set_sdp_handling(caller_mgr->lc->sal, SalOpSDPNormal); - sal_default_set_sdp_handling(callee_mgr->lc->sal, SalOpSDPNormal); + sal_default_set_sdp_handling(linphone_core_get_sal(caller_mgr->lc), SalOpSDPNormal); + sal_default_set_sdp_handling(linphone_core_get_sal(caller_mgr->lc), SalOpSDPNormal); // Wait for Outgoing Progress if (linphone_core_get_calls_nb(callee_mgr->lc)<=1) @@ -2140,14 +2143,14 @@ void call_paused_resumed_base(bool_t multicast, bool_t with_losses) { wait_for_until(pauline->lc, marie->lc, NULL, 5, 3000); if (with_losses) { - sal_set_send_error(marie->lc->sal,1500); /*to trash 200ok without generating error*/ + sal_set_send_error(linphone_core_get_sal(marie->lc),1500); /*to trash 200ok without generating error*/ } linphone_call_pause(call_pauline); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausing,1)); if (with_losses) { BC_ASSERT_FALSE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,1,1000)); - sal_set_send_error(marie->lc->sal,0); /*to trash 200ok without generating error*/ + sal_set_send_error(linphone_core_get_sal(marie->lc),0); /*to trash 200ok without generating error*/ } @@ -2175,12 +2178,12 @@ void call_paused_resumed_base(bool_t multicast, bool_t with_losses) { if (with_losses) { /* now we want to loose the ack*/ linphone_call_pause(call_pauline); - sal_set_send_error(pauline->lc->sal,1500); /*to trash ACK without generating error*/ + sal_set_send_error(linphone_core_get_sal(pauline->lc),1500); /*to trash ACK without generating error*/ BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausing,2)); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,2)); BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,2,1000)); /*now try to resume, it should be OK*/ - sal_set_send_error(pauline->lc->sal,0); + sal_set_send_error(linphone_core_get_sal(pauline->lc),0); linphone_call_resume(call_pauline); BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,3,2000)); BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,3,2000)); @@ -2820,7 +2823,7 @@ static void call_with_mkv_file_player(void) { linphone_player_cbs_set_user_data(cbs, marie); int res = linphone_player_open(player,hellomkv); //if(!ms_filter_codec_supported("opus")) { - if(!ms_factory_codec_supported(marie->lc->factory, "opus") && !ms_factory_codec_supported(pauline->lc->factory, "opus")){ + if(!ms_factory_codec_supported(linphone_core_get_ms_factory(marie->lc), "opus") && !ms_factory_codec_supported(linphone_core_get_ms_factory(pauline->lc), "opus")){ BC_ASSERT_EQUAL(res, -1, int, "%d"); end_call(marie, pauline); goto end; @@ -2911,13 +2914,13 @@ static void _call_base_with_configfile(LinphoneMediaEncryption mode, bool_t enab linphone_core_set_media_encryption(pauline->lc,mode); if (mode==LinphoneMediaEncryptionDTLS) { /* for DTLS we must access certificates or at least have a directory to store them */ char *path = bc_tester_file("certificates-marie"); - marie->lc->user_certificates_path = ms_strdup(path); + linphone_core_set_user_certificates_path(marie->lc, path); bc_free(path); path = bc_tester_file("certificates-pauline"); - pauline->lc->user_certificates_path = ms_strdup(path); + linphone_core_set_user_certificates_path(pauline->lc, path); bc_free(path); - belle_sip_mkdir(marie->lc->user_certificates_path); - belle_sip_mkdir(pauline->lc->user_certificates_path); + belle_sip_mkdir(linphone_core_get_user_certificates_path(marie->lc)); + belle_sip_mkdir(linphone_core_get_user_certificates_path(pauline->lc)); } linphone_core_set_firewall_policy(marie->lc,policy); @@ -3249,14 +3252,14 @@ static void call_established_with_rejected_info(void) { BC_ASSERT_TRUE((call_ok=call(pauline,marie))); if (call_ok){ - sal_enable_unconditional_answer(marie->lc->sal,TRUE); + sal_enable_unconditional_answer(linphone_core_get_sal(marie->lc),TRUE); im1 = linphone_core_create_info_message(pauline->lc); linphone_call_send_info_message(linphone_core_get_current_call(pauline->lc),im1); wait_for_until(marie->lc,pauline->lc,&dummy,1,1000); /*just to sleep while iterating 1s*/ linphone_info_message_unref(im1); - sal_enable_unconditional_answer(marie->lc->sal,FALSE); + sal_enable_unconditional_answer(linphone_core_get_sal(marie->lc),FALSE); im2 = linphone_core_create_info_message(pauline->lc); linphone_call_send_info_message(linphone_core_get_current_call(pauline->lc),im2); @@ -3319,7 +3322,7 @@ static void call_established_with_complex_rejected_operation(void) { linphone_info_message_unref(info); params=linphone_core_create_call_params(marie->lc,linphone_core_get_current_call(marie->lc)); - sal_enable_pending_trans_checking(marie->lc->sal,FALSE); /*to allow // transactions*/ + sal_enable_pending_trans_checking(linphone_core_get_sal(marie->lc),FALSE); /*to allow // transactions*/ linphone_core_enable_payload_type(marie->lc,linphone_core_find_payload_type(marie->lc,"PCMU",8000,1),TRUE); linphone_core_enable_payload_type(marie->lc,linphone_core_find_payload_type(marie->lc,"PCMA",8000,1),FALSE); @@ -3515,7 +3518,7 @@ static void call_established_with_rejected_reinvite_with_error_base(bool_t trans linphone_info_message_unref(info); } else - sal_enable_unconditional_answer(marie->lc->sal,TRUE); + sal_enable_unconditional_answer(linphone_core_get_sal(marie->lc),TRUE); result = linphone_call_update(linphone_core_get_current_call(pauline->lc),linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc))); @@ -3533,7 +3536,7 @@ static void call_established_with_rejected_reinvite_with_error_base(bool_t trans check_call_state(marie,LinphoneCallStreamsRunning); if (!trans_pending) - sal_enable_unconditional_answer(marie->lc->sal,FALSE); + sal_enable_unconditional_answer(linphone_core_get_sal(marie->lc),FALSE); end_call(pauline, marie); } @@ -3563,7 +3566,9 @@ static void call_rejected_because_wrong_credentials_with_params(const char* user linphone_core_set_user_agent(marie->lc,user_agent,NULL); } if (!enable_auth_req_cb) { - ((VTableReference*)(marie->lc->vtable_refs->data))->cbs->vtable->auth_info_requested=NULL; + // ((VTableReference*)(marie->lc->vtable_refs->data))->cbs->vtable->auth_info_requested=NULL; + LinphoneCoreCbs *cbs = linphone_core_get_first_callbacks(marie->lc); + linphone_core_cbs_set_auth_info_requested(cbs, NULL); linphone_core_add_auth_info(marie->lc,wrong_auth_info); } @@ -4080,7 +4085,7 @@ void early_media_without_sdp_in_200_base( bool_t use_video, bool_t use_ice ){ liblinphone_tester_check_rtcp(marie, pauline); /* will send the 200OK _without_ SDP. We expect the early-media SDP to be used instead */ - sal_call_set_sdp_handling(linphone_call_get_op(pauline_call), SalOpSDPSimulateRemove); + sal_call_set_sdp_handling(linphone_call_get_op_as_sal_op(pauline_call), SalOpSDPSimulateRemove); linphone_call_accept(pauline_call); BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallConnected, 1,1000)); @@ -4175,9 +4180,10 @@ static void call_state_changed_2(LinphoneCore *lc, LinphoneCall *call, LinphoneC static void call_state_changed_3(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg){ /*just to check multi listener in such situation*/ - char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to); - char* from=linphone_address_as_string(linphone_call_get_call_log(call)->from); - ms_message("Third call listener reports: %s call from [%s] to [%s], new state is [%s]" ,linphone_call_get_call_log(call)->dir==LinphoneCallIncoming?"Incoming":"Outgoing" + LinphoneCallLog *clog = linphone_call_get_call_log(call); + char* to=linphone_address_as_string(linphone_call_log_get_to(clog)); + char* from=linphone_address_as_string(linphone_call_log_get_from(clog)); + ms_message("Third call listener reports: %s call from [%s] to [%s], new state is [%s]" ,linphone_call_log_get_dir(clog)==LinphoneCallIncoming?"Incoming":"Outgoing" ,from ,to ,linphone_call_state_to_string(cstate)); @@ -4268,8 +4274,8 @@ static void simple_stereo_call(const char *codec_name, int clock_rate, int bitra linphone_core_set_record_file(pauline->lc, recordpath); /*stereo is supported only without volume control, echo canceller...*/ - lp_config_set_string(marie->lc->config,"sound","features","REMOTE_PLAYING"); - lp_config_set_string(pauline->lc->config,"sound","features","REMOTE_PLAYING"); + lp_config_set_string(linphone_core_get_config(marie->lc),"sound","features","REMOTE_PLAYING"); + lp_config_set_string(linphone_core_get_config(pauline->lc),"sound","features","REMOTE_PLAYING"); if (!BC_ASSERT_TRUE(call(pauline,marie))) goto end; wait_for_until(marie->lc, pauline->lc, NULL, 0, 6000); @@ -4486,12 +4492,12 @@ static void call_with_rtp_io_mode(void) { /* The callee uses the RTP IO mode with the PCMU codec to send back audio to the caller. */ disable_all_audio_codecs_except_one(pauline->lc, "pcmu", -1); - lp_config_set_int(pauline->lc->config, "sound", "rtp_io", 1); - lp_config_set_string(pauline->lc->config, "sound", "rtp_local_addr", linphone_core_ipv6_enabled(pauline->lc) ? "::1" : "127.0.0.1"); - lp_config_set_string(pauline->lc->config, "sound", "rtp_remote_addr", linphone_core_ipv6_enabled(pauline->lc) ? "::1" : "127.0.0.1"); - lp_config_set_int(pauline->lc->config, "sound", "rtp_local_port", 17076); - lp_config_set_int(pauline->lc->config, "sound", "rtp_remote_port", 17076); - lp_config_set_string(pauline->lc->config, "sound", "rtp_map", "pcmu/8000/1"); + lp_config_set_int(linphone_core_get_config(pauline->lc), "sound", "rtp_io", 1); + lp_config_set_string(linphone_core_get_config(pauline->lc), "sound", "rtp_local_addr", linphone_core_ipv6_enabled(pauline->lc) ? "::1" : "127.0.0.1"); + lp_config_set_string(linphone_core_get_config(pauline->lc), "sound", "rtp_remote_addr", linphone_core_ipv6_enabled(pauline->lc) ? "::1" : "127.0.0.1"); + lp_config_set_int(linphone_core_get_config(pauline->lc), "sound", "rtp_local_port", 17076); + lp_config_set_int(linphone_core_get_config(pauline->lc), "sound", "rtp_remote_port", 17076); + lp_config_set_string(linphone_core_get_config(pauline->lc), "sound", "rtp_map", "pcmu/8000/1"); BC_ASSERT_TRUE((call_ok = call(marie, pauline))); if (!call_ok) goto end; @@ -5020,9 +5026,9 @@ static void recovered_call_on_network_switch_in_early_state_4(void) { BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1)); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1)); - BC_ASSERT_TRUE(sal_call_dialog_request_pending(linphone_call_get_op(incoming_call))); + BC_ASSERT_TRUE(sal_call_dialog_request_pending(linphone_call_get_op_as_sal_op(incoming_call))); wait_for_until(marie->lc, pauline->lc, NULL, 1, 2000); - BC_ASSERT_FALSE(sal_call_dialog_request_pending(linphone_call_get_op(incoming_call))); + BC_ASSERT_FALSE(sal_call_dialog_request_pending(linphone_call_get_op_as_sal_op(incoming_call))); linphone_call_terminate(incoming_call); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1)); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallReleased, 1)); @@ -5075,7 +5081,7 @@ static void configure_video_policies_for_network_switch(LinphoneCore *marie, Lin linphone_core_enable_video_display(pauline, TRUE); linphone_core_set_video_policy(marie, &policy); linphone_core_set_video_policy(pauline, &policy); - lp_config_set_int(pauline->config, "sip", "defer_update_default", TRUE); + lp_config_set_int(linphone_core_get_config(pauline), "sip", "defer_update_default", TRUE); } static void recovered_call_on_network_switch_during_reinvite_2(void) { @@ -5479,13 +5485,13 @@ end: static void call_logs_if_no_db_set(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* laure = linphone_core_manager_new("laure_call_logs_rc"); - BC_ASSERT_TRUE(bctbx_list_size(laure->lc->call_logs) == 10); + BC_ASSERT_TRUE(bctbx_list_size(linphone_core_get_call_logs(laure->lc)) == 10); BC_ASSERT_TRUE(call(marie, laure)); wait_for_until(marie->lc, laure->lc, NULL, 5, 1000); end_call(marie, laure); - BC_ASSERT_TRUE(bctbx_list_size(laure->lc->call_logs) == 11); + BC_ASSERT_TRUE(bctbx_list_size(linphone_core_get_call_logs(laure->lc)) == 11); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(laure); } @@ -5495,15 +5501,16 @@ static void call_logs_migrate(void) { char *logs_db = bc_tester_file("call_logs.db"); size_t i = 0; int incoming_count = 0, outgoing_count = 0, missed_count = 0, aborted_count = 0, decline_count = 0, video_enabled_count = 0; + bctbx_list_t **call_logs_attr = NULL; unlink(logs_db); - BC_ASSERT_TRUE(bctbx_list_size(laure->lc->call_logs) == 10); + BC_ASSERT_TRUE(bctbx_list_size(linphone_core_get_call_logs(laure->lc)) == 10); linphone_core_set_call_logs_database_path(laure->lc, logs_db); BC_ASSERT_TRUE(linphone_core_get_call_history_size(laure->lc) == 10); - for (; i < bctbx_list_size(laure->lc->call_logs); i++) { - LinphoneCallLog *log = bctbx_list_nth_data(laure->lc->call_logs, (int)i); + for (; i < bctbx_list_size(linphone_core_get_call_logs(laure->lc)); i++) { + LinphoneCallLog *log = bctbx_list_nth_data(linphone_core_get_call_logs(laure->lc), (int)i); LinphoneCallStatus state = linphone_call_log_get_status(log); LinphoneCallDir direction = linphone_call_log_get_dir(log); @@ -5536,15 +5543,16 @@ static void call_logs_migrate(void) { LinphoneCallLog *log = linphone_core_get_last_outgoing_call_log(laure->lc); BC_ASSERT_PTR_NOT_NULL(log); if (log) { - BC_ASSERT_EQUAL((int)log->start_date_time, 1441738272, int, "%d"); + BC_ASSERT_EQUAL((int)linphone_call_log_get_start_date(log), 1441738272, int, "%d"); linphone_call_log_unref(log); log = NULL; } } - laure->lc->call_logs = bctbx_list_free_with_data(laure->lc->call_logs, (void (*)(void*))linphone_call_log_unref); - laure->lc->call_logs = call_logs_read_from_config_file(laure->lc); - BC_ASSERT_TRUE(bctbx_list_size(laure->lc->call_logs) == 0); + call_logs_attr = linphone_core_get_call_logs_attribute(laure->lc); + *call_logs_attr = bctbx_list_free_with_data(*call_logs_attr, (void (*)(void*))linphone_call_log_unref); + *call_logs_attr = linphone_core_read_call_logs_from_config_file(laure->lc); + BC_ASSERT_TRUE(bctbx_list_size(linphone_core_get_call_logs(laure->lc)) == 0); unlink(logs_db); ms_free(logs_db); @@ -5823,7 +5831,7 @@ static void call_with_ice_with_default_candidate_not_stun(void){ char localip[LINPHONE_IPADDR_SIZE]; bool_t call_ok; - lp_config_set_int(marie->lc->config, "net", "dont_default_to_stun_candidates", 1); + lp_config_set_int(linphone_core_get_config(marie->lc), "net", "dont_default_to_stun_candidates", 1); linphone_core_set_firewall_policy(marie->lc, LinphonePolicyUseIce); linphone_core_set_firewall_policy(pauline->lc, LinphonePolicyUseIce); linphone_core_get_local_ip(marie->lc, AF_INET, NULL, localip); @@ -5931,7 +5939,8 @@ static void call_with_encryption_mandatory(bool_t caller_has_encryption_mandator LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); LinphoneCallStats *marie_stats, *pauline_stats; /*marie doesn't support ZRTP at all*/ - marie->lc->zrtp_not_available_simulation=1; + // marie->lc->zrtp_not_available_simulation=1; + linphone_core_set_zrtp_not_available_simulation(marie->lc, TRUE); /*pauline requests encryption to be mandatory*/ linphone_core_set_media_encryption(pauline->lc, LinphoneMediaEncryptionZRTP); diff --git a/tester/call_video_tester.c b/tester/call_video_tester.c index 1588d5b76..1f3872d05 100644 --- a/tester/call_video_tester.c +++ b/tester/call_video_tester.c @@ -18,7 +18,6 @@ #include "linphone/core.h" #include "liblinphone_tester.h" -#include "private.h" #ifdef VIDEO_ENABLED static void call_paused_resumed_with_video_base_call_cb(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message) { @@ -235,7 +234,7 @@ bool_t request_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee, bo BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallStreamsRunning,initial_caller_stat.number_of_LinphoneCallStreamsRunning+1)); video_policy = linphone_core_get_video_activation_policy(caller->lc); - if (video_policy->automatically_accept || accept_with_params) { + if (linphone_video_activation_policy_get_automatically_accept(video_policy) || accept_with_params) { video_added = BC_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)))); video_added = BC_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)))) @@ -567,13 +566,13 @@ void video_call_base_2(LinphoneCoreManager* caller,LinphoneCoreManager* callee, if (mode==LinphoneMediaEncryptionDTLS) { /* for DTLS we must access certificates or at least have a directory to store them */ char *path = bc_tester_file("certificates-marie"); - callee->lc->user_certificates_path = ms_strdup(path); + linphone_core_set_user_certificates_path(callee->lc, path); bc_free(path); path = bc_tester_file("certificates-pauline"); - caller->lc->user_certificates_path = ms_strdup(path); + linphone_core_set_user_certificates_path(caller->lc, path); bc_free(path); - belle_sip_mkdir(callee->lc->user_certificates_path); - belle_sip_mkdir(caller->lc->user_certificates_path); + belle_sip_mkdir(linphone_core_get_user_certificates_path(callee->lc)); + belle_sip_mkdir(linphone_core_get_user_certificates_path(caller->lc)); } linphone_core_set_media_encryption(callee->lc,mode); @@ -682,13 +681,13 @@ void video_call_base_3(LinphoneCoreManager* caller,LinphoneCoreManager* callee, if (mode==LinphoneMediaEncryptionDTLS) { /* for DTLS we must access certificates or at least have a directory to store them */ char *path = bc_tester_file("certificates-marie"); - callee->lc->user_certificates_path = ms_strdup(path); + linphone_core_set_user_certificates_path(callee->lc, path); bc_free(path); path = bc_tester_file("certificates-pauline"); - caller->lc->user_certificates_path = ms_strdup(path); + linphone_core_set_user_certificates_path(caller->lc, path); bc_free(path); - belle_sip_mkdir(callee->lc->user_certificates_path); - belle_sip_mkdir(caller->lc->user_certificates_path); + belle_sip_mkdir(linphone_core_get_user_certificates_path(callee->lc)); + belle_sip_mkdir(linphone_core_get_user_certificates_path(caller->lc)); } linphone_core_set_media_encryption(callee->lc,mode); @@ -1331,7 +1330,7 @@ static void accept_call_in_send_only_base(LinphoneCoreManager* pauline, Linphone linphone_core_set_video_device(marie->lc,liblinphone_tester_mire_id); /*The send-only client shall set rtp symmetric in absence of media relay for this test.*/ - lp_config_set_int(marie->lc->config,"rtp","symmetric",1); + lp_config_set_int(linphone_core_get_config(marie->lc),"rtp","symmetric",1); linphone_call_set_next_video_frame_decoded_callback(linphone_core_invite_address(pauline->lc,marie->identity) ,linphone_call_iframe_decoded_cb @@ -1842,7 +1841,7 @@ static void incoming_reinvite_with_invalid_ack_sdp(void){ const LinphoneCallParams *caller_params; stats initial_caller_stat=caller->stat; stats initial_callee_stat=callee->stat; - sal_call_set_sdp_handling(linphone_call_get_op(inc_call), SalOpSDPSimulateError); /* will force a parse error for the ACK SDP*/ + sal_call_set_sdp_handling(linphone_call_get_op_as_sal_op(inc_call), SalOpSDPSimulateError); /* will force a parse error for the ACK SDP*/ BC_ASSERT_PTR_NOT_NULL(_request_video(caller, callee, TRUE)); BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallUpdating,initial_callee_stat.number_of_LinphoneCallUpdating+1)); BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallStreamsRunning,initial_callee_stat.number_of_LinphoneCallStreamsRunning+1)); @@ -1858,7 +1857,7 @@ static void incoming_reinvite_with_invalid_ack_sdp(void){ caller_params = linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)); // TODO [refactoring]: BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,(int*)&caller_params->has_video,FALSE)); (void)caller_params; - sal_call_set_sdp_handling(linphone_call_get_op(inc_call), SalOpSDPNormal); + sal_call_set_sdp_handling(linphone_call_get_op_as_sal_op(inc_call), SalOpSDPNormal); } end_call(caller, callee); @@ -1877,7 +1876,7 @@ static void outgoing_reinvite_with_invalid_ack_sdp(void) { if (out_call) { stats initial_caller_stat=caller->stat; stats initial_callee_stat=callee->stat; - sal_call_set_sdp_handling(linphone_call_get_op(out_call), SalOpSDPSimulateError); /* will force a parse error for the ACK SDP*/ + sal_call_set_sdp_handling(linphone_call_get_op_as_sal_op(out_call), SalOpSDPSimulateError); /* will force a parse error for the ACK SDP*/ BC_ASSERT_PTR_NOT_NULL(_request_video(caller, callee, TRUE)); BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallUpdating,initial_callee_stat.number_of_LinphoneCallUpdating+1)); BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallStreamsRunning,initial_callee_stat.number_of_LinphoneCallStreamsRunning+1)); @@ -1891,7 +1890,7 @@ static void outgoing_reinvite_with_invalid_ack_sdp(void) { BC_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)))); BC_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)))); - sal_call_set_sdp_handling(linphone_call_get_op(out_call), SalOpSDPNormal); + sal_call_set_sdp_handling(linphone_call_get_op_as_sal_op(out_call), SalOpSDPNormal); } end_call(caller, callee); diff --git a/tester/certificates/client/cert.pem b/tester/certificates/client/cert.pem index 0893135ad..3fd0cd0d8 100644 --- a/tester/certificates/client/cert.pem +++ b/tester/certificates/client/cert.pem @@ -2,16 +2,16 @@ Certificate: Data: Version: 3 (0x2) Serial Number: 14 (0xe) - Signature Algorithm: sha256WithRSAEncryption + Signature Algorithm: sha1WithRSAEncryption Issuer: C=FR, ST=Some-State, L=Grenoble, O=Belledonne Communications, OU=LAB, CN=Jehan Monnier/emailAddress=jehan.monnier@belledonne-communications.com Validity - Not Before: Sep 20 14:00:00 2016 GMT - Not After : Sep 20 14:00:00 2017 GMT + Not Before: Sep 25 08:36:50 2017 GMT + Not After : Sep 23 08:36:50 2027 GMT Subject: C=FR, ST=Rhone-Alpes Auvergne, L=Grenoble, O=Belledonne Communications, CN=sip:sip.example.org/emailAddress=info@belledonne-communications.com Subject Public Key Info: Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: + RSA Public Key: (2048 bit) + Modulus (2048 bit): 00:9e:31:b6:30:07:0e:de:8b:dd:41:66:ec:52:84: 37:2c:bf:98:bc:8f:d3:8e:0d:0f:97:de:b0:4a:c6: 26:c3:c5:29:4d:4e:ed:6c:0c:fe:06:61:49:16:67: @@ -41,22 +41,22 @@ Certificate: X509v3 Authority Key Identifier: keyid:06:5F:5D:C7:16:AF:62:F8:2D:6E:71:03:88:A0:D6:1D:2B:04:7F:BA - Signature Algorithm: sha256WithRSAEncryption - 3e:6c:d5:87:db:04:2b:1b:73:93:9e:ea:fe:10:4a:38:9b:3e: - 63:8f:f2:8d:8a:d0:bc:b2:4a:63:e0:3c:31:71:00:cf:81:4a: - ae:4c:51:fc:5d:51:b7:0a:86:48:5b:1f:a6:cc:ca:d2:c3:95: - da:4b:34:dc:8c:dd:1b:27:fb:d2:a8:e4:5e:5a:cc:01:f0:63: - 58:74:72:1b:5f:c9:51:87:49:dd:ff:13:77:4c:2f:59:38:7f: - 0a:48:94:17:67:b9:7e:6a:1f:c8:29:67:e0:d4:79:c9:8c:5b: - 25:09:1d:46:f2:3a:e4:29:85:73:32:c5:94:72:59:31:57:9c: - 65:d5 + Signature Algorithm: sha1WithRSAEncryption + 93:16:99:16:33:aa:1c:cd:44:b0:cd:05:fb:11:de:eb:15:ec: + b9:a3:f1:bc:93:71:5b:6d:86:5a:f8:a1:91:96:60:52:7e:5f: + 11:a8:aa:41:aa:d8:96:07:5a:b6:8d:a6:5f:e0:db:60:58:50: + a8:b2:53:5d:e1:14:db:b5:de:8c:00:9c:83:66:b9:88:12:67: + 50:79:70:06:03:5c:eb:5a:d8:98:b2:af:39:15:ad:b9:65:ad: + 45:ef:1c:30:b1:27:6d:88:2f:2f:c6:cb:d3:a6:41:4a:95:f2: + 52:7e:d2:7f:3e:99:7e:72:43:92:e2:3b:5a:e0:3f:28:30:db: + d3:c0 -----BEGIN CERTIFICATE----- -MIID5jCCA0+gAwIBAgIBDjANBgkqhkiG9w0BAQsFADCBuzELMAkGA1UEBhMCRlIx +MIID5jCCA0+gAwIBAgIBDjANBgkqhkiG9w0BAQUFADCBuzELMAkGA1UEBhMCRlIx EzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCEdyZW5vYmxlMSIwIAYDVQQK DBlCZWxsZWRvbm5lIENvbW11bmljYXRpb25zMQwwCgYDVQQLDANMQUIxFjAUBgNV BAMMDUplaGFuIE1vbm5pZXIxOjA4BgkqhkiG9w0BCQEWK2plaGFuLm1vbm5pZXJA -YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wHhcNMTYwOTIwMTQwMDAwWhcN -MTcwOTIwMTQwMDAwWjCBtDELMAkGA1UEBhMCRlIxHTAbBgNVBAgMFFJob25lLUFs +YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wHhcNMTcwOTI1MDgzNjUwWhcN +MjcwOTIzMDgzNjUwWjCBtDELMAkGA1UEBhMCRlIxHTAbBgNVBAgMFFJob25lLUFs cGVzIEF1dmVyZ25lMREwDwYDVQQHDAhHcmVub2JsZTEiMCAGA1UECgwZQmVsbGVk b25uZSBDb21tdW5pY2F0aW9uczEcMBoGA1UEAwwTc2lwOnNpcC5leGFtcGxlLm9y ZzExMC8GCSqGSIb3DQEJARYiaW5mb0BiZWxsZWRvbm5lLWNvbW11bmljYXRpb25z @@ -69,7 +69,7 @@ dA7hxP32w0HFTB75i5zHfoBZ+Vvnq3b9Wp3YvW/5WHjkcoJEhTJ9wif2Umlp6OZw AKpkRW8CAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNT TCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFMtXv4mv2dvM4Ph5ca1/ A2MgCkljMB8GA1UdIwQYMBaAFAZfXccWr2L4LW5xA4ig1h0rBH+6MA0GCSqGSIb3 -DQEBCwUAA4GBAD5s1YfbBCsbc5Oe6v4QSjibPmOP8o2K0LyySmPgPDFxAM+BSq5M -UfxdUbcKhkhbH6bMytLDldpLNNyM3Rsn+9Ko5F5azAHwY1h0chtfyVGHSd3/E3dM -L1k4fwpIlBdnuX5qH8gpZ+DUecmMWyUJHUbyOuQphXMyxZRyWTFXnGXV +DQEBBQUAA4GBAJMWmRYzqhzNRLDNBfsR3usV7Lmj8byTcVtthlr4oZGWYFJ+XxGo +qkGq2JYHWraNpl/g22BYUKiyU13hFNu13owAnINmuYgSZ1B5cAYDXOta2JiyrzkV +rbllrUXvHDCxJ22ILy/Gy9OmQUqV8lJ+0n8+mX5yQ5LiO1rgPygw29PA -----END CERTIFICATE----- diff --git a/tester/complex_sip_case_tester.c b/tester/complex_sip_case_tester.c index e9cbeb7df..2a572acdb 100644 --- a/tester/complex_sip_case_tester.c +++ b/tester/complex_sip_case_tester.c @@ -20,7 +20,6 @@ #include "linphone/core.h" #include "liblinphone_tester.h" #include "linphone/lpconfig.h" -#include "private.h" #if HAVE_SIPP diff --git a/tester/dtmf_tester.c b/tester/dtmf_tester.c index 3ac461e12..58723d9b9 100644 --- a/tester/dtmf_tester.c +++ b/tester/dtmf_tester.c @@ -17,7 +17,6 @@ */ #include "liblinphone_tester.h" -#include "private.h" void dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf) { stats* counters = get_stats(lc); @@ -37,7 +36,7 @@ void send_dtmf_base(LinphoneCoreManager **pmarie, LinphoneCoreManager **ppauline if (use_opus) { //if (!ms_filter_codec_supported("opus")) { - if(!ms_factory_codec_supported(marie->lc->factory, "opus") && !ms_factory_codec_supported(pauline->lc->factory, "opus")){ + if(!ms_factory_codec_supported(linphone_core_get_ms_factory(marie->lc), "opus") && !ms_factory_codec_supported(linphone_core_get_ms_factory(pauline->lc), "opus")){ ms_warning("Opus not supported, skipping test."); return; @@ -69,7 +68,7 @@ void send_dtmf_base(LinphoneCoreManager **pmarie, LinphoneCoreManager **ppauline } if (dtmf_seq != NULL) { - int dtmf_delay_ms = lp_config_get_int(linphone_call_get_core(marie_call)->config,"net","dtmf_delay_ms",200); + int dtmf_delay_ms = lp_config_get_int(linphone_core_get_config(linphone_call_get_core(marie_call)),"net","dtmf_delay_ms",200); dtmf_count_prev = pauline->stat.dtmf_count; linphone_call_send_dtmfs(marie_call, dtmf_seq); diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index 205aa3935..7bbdbf24e 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -19,7 +19,6 @@ #include "linphone/core.h" -#include "private.h" #include "linphone/lpconfig.h" #include #include "liblinphone_tester.h" @@ -181,7 +180,7 @@ static void subscribe_test_with_args(bool_t terminated_by_subscriber, RefreshTes lcs=bctbx_list_append(lcs,pauline->lc); if (refresh_type==ManualRefresh){ - lp_config_set_int(marie->lc->config,"sip","refresh_generic_subscribe",0); + lp_config_set_int(linphone_core_get_config(marie->lc),"sip","refresh_generic_subscribe",0); } content = linphone_core_create_content(marie->lc); @@ -239,7 +238,7 @@ static void subscribe_test_with_args2(bool_t terminated_by_subscriber, RefreshTe lcs=bctbx_list_append(lcs,pauline->lc); if (refresh_type==ManualRefresh){ - lp_config_set_int(marie->lc->config,"sip","refresh_generic_subscribe",0); + lp_config_set_int(linphone_core_get_config(marie->lc),"sip","refresh_generic_subscribe",0); } content = linphone_core_create_content(marie->lc); @@ -414,11 +413,11 @@ static void subscribe_with_io_error(void) { BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,1,5000)); /* now marie gets network errors when refreshing*/ - sal_set_send_error(marie->lc->sal, -1); + sal_set_send_error(linphone_core_get_sal(marie->lc), -1); /*marie will retry the subscription*/ BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingProgress,2,8000)); - sal_set_send_error(marie->lc->sal, 0); + sal_set_send_error(linphone_core_get_sal(marie->lc), 0); /*and get it accepted again*/ BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,2,10000)); @@ -498,7 +497,7 @@ static void publish_test_with_args(bool_t refresh, int expires){ linphone_content_set_subtype(content,"somexml"); linphone_content_set_buffer(content,subscribe_content,strlen(subscribe_content)); - lp_config_set_int(marie->lc->config,"sip","refresh_generic_publish",refresh); + lp_config_set_int(linphone_core_get_config(marie->lc),"sip","refresh_generic_publish",refresh); lev=linphone_core_create_publish(marie->lc,pauline->identity,"dodo",expires); linphone_event_add_custom_header(lev,"CustomHeader","someValue"); diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c index bc03161fa..07c9d14d8 100644 --- a/tester/flexisip_tester.c +++ b/tester/flexisip_tester.c @@ -19,7 +19,6 @@ #include "linphone/core.h" #include "linphone/lpconfig.h" -#include "private.h" #include "liblinphone_tester.h" static void setPublish(LinphoneProxyConfig * proxy_config, bool_t enable) { @@ -793,12 +792,12 @@ static void file_transfer_message_rcs_to_external_body_client(void) { linphone_core_set_network_reachable(marie->lc, FALSE); linphone_core_set_network_reachable(pauline->lc, FALSE); - linphone_proxy_config_set_custom_header(marie->lc->default_proxy, "Accept", "application/sdp"); + linphone_proxy_config_set_custom_header(linphone_core_get_default_proxy_config(marie->lc), "Accept", "application/sdp"); linphone_core_set_network_reachable(marie->lc, TRUE); linphone_core_manager_start(marie, TRUE); - linphone_proxy_config_set_custom_header(pauline->lc->default_proxy, "Accept", "application/sdp, text/plain, application/vnd.gsma.rcs-ft-http+xml"); + linphone_proxy_config_set_custom_header(linphone_core_get_default_proxy_config(pauline->lc), "Accept", "application/sdp, text/plain, application/vnd.gsma.rcs-ft-http+xml"); linphone_core_set_network_reachable(pauline->lc, TRUE); linphone_core_manager_start(pauline, TRUE); @@ -891,10 +890,10 @@ static void file_transfer_message_external_body_to_external_body_client(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - linphone_proxy_config_set_custom_header(marie->lc->default_proxy, "Accept", "application/sdp"); + linphone_proxy_config_set_custom_header(linphone_core_get_default_proxy_config(marie->lc), "Accept", "application/sdp"); linphone_core_manager_start(marie, TRUE); - linphone_proxy_config_set_custom_header(pauline->lc->default_proxy, "Accept", "application/sdp"); + linphone_proxy_config_set_custom_header(linphone_core_get_default_proxy_config(pauline->lc), "Accept", "application/sdp"); linphone_core_manager_start(pauline, TRUE); reset_counters(&marie->stat); @@ -915,10 +914,10 @@ static void file_transfer_message_external_body_to_rcs_client(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - linphone_proxy_config_set_custom_header(marie->lc->default_proxy, "Accept", "application/sdp"); + linphone_proxy_config_set_custom_header(linphone_core_get_default_proxy_config(marie->lc), "Accept", "application/sdp"); linphone_core_manager_start(marie, TRUE); - linphone_proxy_config_set_custom_header(pauline->lc->default_proxy, "Accept", "application/sdp, text/plain, application/vnd.gsma.rcs-ft-http+xml"); + linphone_proxy_config_set_custom_header(linphone_core_get_default_proxy_config(pauline->lc), "Accept", "application/sdp, text/plain, application/vnd.gsma.rcs-ft-http+xml"); linphone_core_manager_start(pauline, TRUE); reset_counters(&marie->stat); @@ -1368,7 +1367,7 @@ void test_removing_old_tport(void) { marie2 = ms_new0(LinphoneCoreManager, 1); linphone_core_manager_init(marie2, "marie_rc", NULL); - sal_set_uuid(marie2->lc->sal, linphone_config_get_string(linphone_core_get_config(marie1->lc),"misc", "uuid", "0")); + sal_set_uuid(linphone_core_get_sal(marie2->lc), linphone_config_get_string(linphone_core_get_config(marie1->lc),"misc", "uuid", "0")); linphone_core_manager_start(marie2, TRUE); lcs=bctbx_list_append(lcs, marie2->lc); linphone_core_refresh_registers(marie2->lc); diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 178a8347a..67c17d71f 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -18,7 +18,6 @@ #include "linphone/core.h" -#include "private.h" #include "liblinphone_tester.h" #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 8de7b8b61..de8174668 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -25,6 +25,7 @@ #include #include "linphone/core.h" #include +#include "tester_utils.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/tester/log_collection_tester.c b/tester/log_collection_tester.c index f4f59c82f..15c9f6256 100644 --- a/tester/log_collection_tester.c +++ b/tester/log_collection_tester.c @@ -21,7 +21,6 @@ #endif #include #include "linphone/core.h" -#include "private.h" #include "liblinphone_tester.h" #ifdef HAVE_ZLIB diff --git a/tester/message_tester.c b/tester/message_tester.c index 3b661a342..1e93ca046 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -19,10 +19,11 @@ #include "linphone/core.h" -#include "private.h" #include "liblinphone_tester.h" #include "lime.h" #include "bctoolbox/crypto.h" +#include +#include #ifdef SQLITE_STORAGE_ENABLED #include @@ -237,7 +238,7 @@ LinphoneChatMessage* create_message_from_sintel_trailer(LinphoneChatRoom *chat_r fseek(file_to_send, 0, SEEK_SET); content = linphone_core_create_content(linphone_chat_room_get_core(chat_room)); - belle_sip_object_set_name(&content->base, "sintel trailer content"); + belle_sip_object_set_name(BELLE_SIP_OBJECT(content), "sintel trailer content"); linphone_content_set_type(content,"video"); linphone_content_set_subtype(content,"mkv"); linphone_content_set_size(content,file_size); /*total size to be transfered*/ @@ -263,7 +264,7 @@ LinphoneChatMessage* create_file_transfer_message_from_sintel_trailer(LinphoneCh char *send_filepath = bc_tester_res("sounds/sintel_trailer_opus_h264.mkv"); content = linphone_core_create_content(linphone_chat_room_get_core(chat_room)); - belle_sip_object_set_name(&content->base, "sintel trailer content"); + belle_sip_object_set_name(BELLE_SIP_OBJECT(content), "sintel trailer content"); linphone_content_set_type(content,"video"); linphone_content_set_subtype(content,"mkv"); linphone_content_set_name(content,"sintel_trailer_opus_h264.mkv"); @@ -312,7 +313,7 @@ static void text_message(void) { static void text_message_within_call_dialog(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); - lp_config_set_int(pauline->lc->config,"sip","chat_use_call_dialogs",1); + lp_config_set_int(linphone_core_get_config(pauline->lc),"sip","chat_use_call_dialogs",1); BC_ASSERT_TRUE(call(marie,pauline)); linphone_chat_room_send_message(linphone_core_get_chat_room(pauline->lc, marie->identity),"Bla bla bla bla"); @@ -408,7 +409,7 @@ static void text_message_with_send_error(void) { LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); /*simulate a network error*/ - sal_set_send_error(marie->lc->sal, -1); + sal_set_send_error(linphone_core_get_sal(marie->lc), -1); linphone_chat_message_cbs_set_msg_state_changed(cbs,liblinphone_tester_chat_message_msg_state_changed); linphone_chat_room_send_chat_message(chat_room,msg); @@ -423,7 +424,7 @@ static void text_message_with_send_error(void) { /* the msg should have been discarded from transient list after an error */ BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_chat_room_get_transient_messages(chat_room)), 0, unsigned int, "%u"); - sal_set_send_error(marie->lc->sal, 0); + sal_set_send_error(linphone_core_get_sal(marie->lc), 0); /*give a chance to register again to allow linphone_core_manager_destroy to properly unregister*/ linphone_core_refresh_registers(marie->lc); @@ -503,14 +504,14 @@ void transfer_message_base2(LinphoneCoreManager* marie, LinphoneCoreManager* pau BC_ASSERT_EQUAL((int)linphone_chat_message_get_state(sent_msg), (int)LinphoneChatMessageStateInProgress, int, "%d"); bctbx_list_free_with_data(history, (bctbx_list_free_func)linphone_chat_message_unref); } - sal_set_send_error(pauline->lc->sal, -1); + sal_set_send_error(linphone_core_get_sal(pauline->lc), -1); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageNotDelivered,1)); BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageNotDelivered,1, int, "%d"); BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,0, int, "%d"); - sal_set_send_error(pauline->lc->sal, 0); + sal_set_send_error(linphone_core_get_sal(pauline->lc), 0); linphone_core_refresh_registers(pauline->lc); /*to make sure registration is back in registered and so it can be later unregistered*/ BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneRegistrationOk,pauline->stat.number_of_LinphoneRegistrationOk+1)); @@ -550,9 +551,9 @@ void transfer_message_base2(LinphoneCoreManager* marie, LinphoneCoreManager* pau /* wait for file to be 50% downloaded */ BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.progress_of_LinphoneFileTransfer, 50)); /* and simulate network error */ - belle_http_provider_set_recv_error(marie->lc->http_provider, -1); + belle_http_provider_set_recv_error(linphone_core_get_http_provider(marie->lc), -1); BC_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneMessageNotDelivered,1, 10000)); - belle_http_provider_set_recv_error(marie->lc->http_provider, 0); + belle_http_provider_set_recv_error(linphone_core_get_http_provider(marie->lc), 0); } else { /* wait for a long time in case the DNS SRV resolution takes times - it should be immediate though */ if (BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,1,55000))) { @@ -892,8 +893,8 @@ static int enable_lime_for_message_test(LinphoneCoreManager *marie, LinphoneCore linphone_core_enable_lime(pauline->lc, LinphoneLimeMandatory); /* make sure to not trigger the cache migration function */ - lp_config_set_int(marie->lc->config, "sip", "zrtp_cache_migration_done", TRUE); - lp_config_set_int(pauline->lc->config, "sip", "zrtp_cache_migration_done", TRUE); + lp_config_set_int(linphone_core_get_config(marie->lc), "sip", "zrtp_cache_migration_done", TRUE); + lp_config_set_int(linphone_core_get_config(pauline->lc), "sip", "zrtp_cache_migration_done", TRUE); /* create temporary cache files: setting the database_path will create and initialise the files */ tmp = bc_tester_file("tmpZIDCacheMarie.sqlite"); @@ -1157,8 +1158,8 @@ static void _im_error_delivery_notification(bool_t online) { BC_ASSERT_PTR_NOT_NULL(linphone_core_get_chat_room(marie->lc, pauline->identity)); /* Temporary disabling receiver cache and enable all IM notifications */ - zrtp_cache_db_holder = marie->lc->zrtp_cache_db; - marie->lc->zrtp_cache_db = NULL; + zrtp_cache_db_holder = linphone_core_get_zrtp_cache_db(marie->lc); + linphone_core_set_zrtp_cache_db(marie->lc, NULL); linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie->lc)); linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline->lc)); @@ -1179,7 +1180,7 @@ static void _im_error_delivery_notification(bool_t online) { BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneMessageNotDelivered, 1)); /* Restore the ZID cache of the receiver and resend the chat message */ - marie->lc->zrtp_cache_db = zrtp_cache_db_holder; + linphone_core_set_zrtp_cache_db(marie->lc, zrtp_cache_db_holder); linphone_chat_message_ref(msg); linphone_chat_message_resend(msg); BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageReceived, 2)); /* Check the new message is now received */ @@ -1249,8 +1250,8 @@ static void lime_text_message_to_non_lime(bool_t sender_policy_mandatory, bool_t /* enable lime for both parts */ if (enable_lime_for_message_test(marie, pauline) < 0) goto end; /* but then disable marie */ - sqlite3_close(marie->lc->zrtp_cache_db); - marie->lc->zrtp_cache_db = NULL; + sqlite3_close(linphone_core_get_zrtp_cache_db(marie->lc)); + linphone_core_set_zrtp_cache_db(marie->lc, NULL); } chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); @@ -1479,7 +1480,7 @@ static void lime_cache_migration(void) { linphone_core_enable_lime(marie->lc, LinphoneLimeMandatory); /* make sure to trigger the cache migration function */ - lp_config_set_int(marie->lc->config, "sip", "zrtp_cache_migration_done", FALSE); + lp_config_set_int(linphone_core_get_config(marie->lc), "sip", "zrtp_cache_migration_done", FALSE); /* set the cache path, it will trigger the migration function */ linphone_core_set_zrtp_secrets_file(marie->lc, xmlCache_filepath); @@ -1490,7 +1491,7 @@ static void lime_cache_migration(void) { linphone_address_unref(new_identity); bctbx_str_to_uint8(associatedKey.peerZID, (const uint8_t *)"0987654321fedcba5a5a5a5a", (uint16_t)strlen("0987654321fedcba5a5a5a5a")); /* 0987654321fedcba5a5a5a5a is the only one with pvs=1*/ - BC_ASSERT_FALSE(lime_getCachedRcvKeyByZid(marie->lc->zrtp_cache_db, &associatedKey, selfURI, "sip:bob@sip.linphone.org")); + BC_ASSERT_FALSE(lime_getCachedRcvKeyByZid(linphone_core_get_zrtp_cache_db(marie->lc), &associatedKey, selfURI, "sip:bob@sip.linphone.org")); ms_free(selfURI); /* perform checks on the new cache, simple check is ok as deeper ones are performed in the bzrtp migration tester */ /* TODO */ @@ -1588,14 +1589,14 @@ static void database_migration(void) { // the messages.db has 10000 dummy messages with the very first DB scheme. // This will test the migration procedure linphone_core_set_chat_database_path(marie->lc, tmp_db); - BC_ASSERT_PTR_NOT_NULL(marie->lc->db); - if (!marie->lc->db) goto end; + BC_ASSERT_PTR_NOT_NULL(linphone_core_get_sqlite_database(marie->lc)); + if (!linphone_core_get_sqlite_database(marie->lc)) goto end; chatrooms = linphone_core_get_chat_rooms(marie->lc); BC_ASSERT(bctbx_list_size(chatrooms) > 0); // check that all messages have been migrated to the UTC time storage - BC_ASSERT(sqlite3_exec(marie->lc->db, "SELECT COUNT(*) FROM history WHERE time != '-1';", check_no_strange_time, NULL, NULL) == SQLITE_OK); + BC_ASSERT(sqlite3_exec(linphone_core_get_sqlite_database(marie->lc), "SELECT COUNT(*) FROM history WHERE time != '-1';", check_no_strange_time, NULL, NULL) == SQLITE_OK); // check that the read messages (field read=1) has been migrated to the LinphoneChatMessageStateDisplayed state cr = linphone_core_get_chat_room_from_uri(marie->lc, "sip:Marielle@sip.linphone.org"); @@ -1618,8 +1619,8 @@ static void history_range(void){ BC_ASSERT_EQUAL(message_tester_copy_file(src_db, tmp_db), 0, int, "%d"); linphone_core_set_chat_database_path(marie->lc, tmp_db); - BC_ASSERT_PTR_NOT_NULL(marie->lc->db); - if (!marie->lc->db) goto end; + BC_ASSERT_PTR_NOT_NULL(linphone_core_get_sqlite_database(marie->lc)); + if (!linphone_core_get_sqlite_database(marie->lc)) goto end; chatroom = linphone_core_get_chat_room(marie->lc, jehan_addr); BC_ASSERT_PTR_NOT_NULL(chatroom); @@ -1663,8 +1664,8 @@ static void history_count(void) { BC_ASSERT_EQUAL(message_tester_copy_file(src_db, tmp_db), 0, int, "%d"); linphone_core_set_chat_database_path(marie->lc, tmp_db); - BC_ASSERT_PTR_NOT_NULL(marie->lc->db); - if (!marie->lc->db) goto end; + BC_ASSERT_PTR_NOT_NULL(linphone_core_get_sqlite_database(marie->lc)); + if (!linphone_core_get_sqlite_database(marie->lc)) goto end; chatroom = linphone_core_get_chat_room(marie->lc, jehan_addr); BC_ASSERT_PTR_NOT_NULL(chatroom); @@ -1846,19 +1847,19 @@ static void real_time_text(bool_t audio_stream_enabled, bool_t srtp_enabled, boo linphone_core_set_chat_database_path(marie->lc, marie_db); linphone_core_set_chat_database_path(pauline->lc, pauline_db); #ifdef SQLITE_STORAGE_ENABLED - BC_ASSERT_PTR_NOT_NULL(marie->lc->db); - BC_ASSERT_PTR_NOT_NULL(pauline->lc->db); + BC_ASSERT_PTR_NOT_NULL(linphone_core_get_sqlite_database(marie->lc)); + BC_ASSERT_PTR_NOT_NULL(linphone_core_get_sqlite_database(pauline->lc)); #endif if (do_not_store_rtt_messages_in_sql_storage) { - lp_config_set_int(marie->lc->config, "misc", "store_rtt_messages", 0); - lp_config_set_int(pauline->lc->config, "misc", "store_rtt_messages", 0); + lp_config_set_int(linphone_core_get_config(marie->lc), "misc", "store_rtt_messages", 0); + lp_config_set_int(linphone_core_get_config(pauline->lc), "misc", "store_rtt_messages", 0); } } if (mess_with_marie_payload_number) { - bctbx_list_t *elem; - for (elem = marie->lc->codecs_conf.text_codecs; elem != NULL; elem = elem->next) { + const bctbx_list_t *elem; + for (elem = linphone_core_get_text_codecs(marie->lc); elem != NULL; elem = elem->next) { PayloadType *pt = (PayloadType*)elem->data; if (strcasecmp(pt->mime_type, payload_type_t140.mime_type) == 0) { payload_type_set_number(pt, 99); @@ -1866,8 +1867,8 @@ static void real_time_text(bool_t audio_stream_enabled, bool_t srtp_enabled, boo } } } else if (mess_with_pauline_payload_number) { - bctbx_list_t *elem; - for (elem = pauline->lc->codecs_conf.text_codecs; elem != NULL; elem = elem->next) { + const bctbx_list_t *elem; + for (elem = linphone_core_get_text_codecs(pauline->lc); elem != NULL; elem = elem->next) { PayloadType *pt = (PayloadType*)elem->data; if (strcasecmp(pt->mime_type, payload_type_t140.mime_type) == 0) { payload_type_set_number(pt, 99); diff --git a/tester/offeranswer_tester.c b/tester/offeranswer_tester.c index fb043f576..4d1c9f720 100644 --- a/tester/offeranswer_tester.c +++ b/tester/offeranswer_tester.c @@ -20,7 +20,6 @@ #include #include "linphone/core.h" #include "linphone/lpconfig.h" -#include "private.h" #include "liblinphone_tester.h" static int get_codec_position(const MSList *l, const char *mime_type, int rate){ diff --git a/tester/presence_server_tester.c b/tester/presence_server_tester.c index 4e8753a55..7e8cac7f6 100644 --- a/tester/presence_server_tester.c +++ b/tester/presence_server_tester.c @@ -18,8 +18,8 @@ #include "linphone/core.h" -#include "private.h" #include "liblinphone_tester.h" +#include "linphone/core_utils.h" static void enable_publish(LinphoneCoreManager *mgr, bool_t enable) { LinphoneProxyConfig *cfg = linphone_core_get_default_proxy_config(mgr->lc); @@ -37,9 +37,9 @@ const char * get_identity(LinphoneCoreManager *mgr) { static void enable_deflate_content_encoding(LinphoneCoreManager *mgr, bool_t enable) { LinphoneCore *lc = mgr->lc; if (enable == TRUE) - lp_config_set_string(lc->config, "sip", "handle_content_encoding", "deflate"); + lp_config_set_string(linphone_core_get_config(lc), "sip", "handle_content_encoding", "deflate"); else - lp_config_set_string(lc->config, "sip", "handle_content_encoding", "none"); + lp_config_set_string(linphone_core_get_config(lc), "sip", "handle_content_encoding", "none"); } static void simple(void) { @@ -54,7 +54,7 @@ static void simple(void) { _linphone_core_add_callbacks(pauline->lc, callbacks, TRUE); linphone_core_cbs_unref(callbacks); - lp_config_set_int(marie->lc->config, "sip", "subscribe_expires", 40); + lp_config_set_int(linphone_core_get_config(marie->lc), "sip", "subscribe_expires", 40); linphone_core_set_user_agent(pauline->lc, "full-presence-support-bypass", NULL); linphone_core_set_user_agent(marie->lc, "full-presence-support-bypass", NULL); enable_publish(pauline, TRUE); @@ -153,7 +153,7 @@ static void subscriber_no_longer_reachable(void){ lcs = bctbx_list_append(lcs, marie->lc); lcs = bctbx_list_append(lcs, pauline1->lc); - lp_config_set_int(marie->lc->config, "sip", "subscribe_expires", 80); + lp_config_set_int(linphone_core_get_config(marie->lc), "sip", "subscribe_expires", 80); linphone_core_set_user_agent(marie->lc, "full-presence-support-bypass", NULL); linphone_core_set_user_agent(pauline1->lc, "full-presence-support-bypass", NULL); @@ -425,16 +425,16 @@ static void test_presence_list_base(bool_t enable_compression) { wait_for_list(lcs, &laure->stat.number_of_NotifyPresenceReceived, 2, 4000); BC_ASSERT_EQUAL(laure->stat.number_of_NotifyPresenceReceived, 2, int, "%d"); - BC_ASSERT_EQUAL(linphone_core_get_default_friend_list(laure->lc)->expected_notification_version, 1, int, "%d"); + BC_ASSERT_EQUAL(linphone_friend_list_get_expected_notification_version(linphone_core_get_default_friend_list(laure->lc)), 1, int, "%d"); lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(laure->lc), marie_identity); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusBusy, int, "%d"); - if (!BC_ASSERT_TRUE(lf->presence_received)) goto end; + if (!BC_ASSERT_TRUE(linphone_friend_is_presence_received(lf))) goto end; lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(laure->lc), pauline_identity); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusVacation, int, "%d"); - if (!BC_ASSERT_TRUE(lf->presence_received)) goto end; + if (!BC_ASSERT_TRUE(linphone_friend_is_presence_received(lf))) goto end; lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(laure->lc), "sip:michelle@sip.inexistentdomain.com"); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOffline, int, "%d"); - BC_ASSERT_FALSE(lf->presence_received); + BC_ASSERT_FALSE(linphone_friend_is_presence_received(lf)); lfl = linphone_core_create_friend_list(marie->lc); linphone_friend_list_set_rls_uri(lfl, rls_uri); @@ -448,10 +448,10 @@ static void test_presence_list_base(bool_t enable_compression) { wait_for_list(lcs, &marie->stat.number_of_NotifyPresenceReceived, 1, 4000); BC_ASSERT_EQUAL(marie->stat.number_of_NotifyPresenceReceived, 1, int, "%d"); - BC_ASSERT_EQUAL(linphone_core_get_default_friend_list(marie->lc)->expected_notification_version, 1, int, "%d"); + BC_ASSERT_EQUAL(linphone_friend_list_get_expected_notification_version(linphone_core_get_default_friend_list(marie->lc)), 1, int, "%d"); lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(marie->lc), laure_identity); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOnline, int, "%d"); - if (!BC_ASSERT_TRUE(lf->presence_received)) goto end; + if (!BC_ASSERT_TRUE(linphone_friend_is_presence_received(lf))) goto end; lfl = linphone_core_create_friend_list(pauline->lc); linphone_friend_list_set_rls_uri(lfl, rls_uri); @@ -465,10 +465,10 @@ static void test_presence_list_base(bool_t enable_compression) { wait_for_list(lcs, &pauline->stat.number_of_NotifyPresenceReceived, 1, 4000); BC_ASSERT_EQUAL(pauline->stat.number_of_NotifyPresenceReceived, 1, int, "%d"); - BC_ASSERT_EQUAL(linphone_core_get_default_friend_list(pauline->lc)->expected_notification_version, 1, int, "%d"); + BC_ASSERT_EQUAL(linphone_friend_list_get_expected_notification_version(linphone_core_get_default_friend_list(pauline->lc)), 1, int, "%d"); lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(pauline->lc), marie_identity); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusBusy, int, "%d"); - if (!BC_ASSERT_TRUE(lf->presence_received)) goto end; + if (!BC_ASSERT_TRUE(linphone_friend_is_presence_received(lf))) goto end; presence = linphone_core_create_presence_model_with_activity(marie->lc, LinphonePresenceActivityOnThePhone, NULL); linphone_core_set_presence_model(marie->lc, presence); @@ -478,13 +478,13 @@ static void test_presence_list_base(bool_t enable_compression) { /* The number of PresenceReceived events can be 3 or 4 here. TODO: ideally it should always be 3. */ BC_ASSERT_GREATER(laure->stat.number_of_NotifyPresenceReceived, 3, int, "%d"); BC_ASSERT_LOWER(laure->stat.number_of_NotifyPresenceReceived, 4, int, "%d"); - BC_ASSERT_EQUAL(linphone_core_get_default_friend_list(laure->lc)->expected_notification_version, 2, int, "%d"); + BC_ASSERT_EQUAL(linphone_friend_list_get_expected_notification_version(linphone_core_get_default_friend_list(laure->lc)), 2, int, "%d"); lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(laure->lc), marie_identity); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOnThePhone, int, "%d"); wait_for_list(lcs, &pauline->stat.number_of_NotifyPresenceReceived, 2, 4000); BC_ASSERT_EQUAL(pauline->stat.number_of_NotifyPresenceReceived, 2, int, "%d"); - BC_ASSERT_EQUAL(linphone_core_get_default_friend_list(pauline->lc)->expected_notification_version, 2, int, "%d"); + BC_ASSERT_EQUAL(linphone_friend_list_get_expected_notification_version(linphone_core_get_default_friend_list(pauline->lc)), 2, int, "%d"); lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(pauline->lc), marie_identity); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOnThePhone, int, "%d"); @@ -605,7 +605,7 @@ static void test_presence_list_subscription_expire_for_unknown(void) { const char *rls_uri = "sip:rls@sip.example.org"; LinphoneFriendList *lfl; LinphoneFriend *lf; - lp_config_set_int(laure->lc->config, "sip", "rls_presence_expires", 3); + lp_config_set_int(linphone_core_get_config(laure->lc), "sip", "rls_presence_expires", 3); lfl = linphone_core_create_friend_list(laure->lc); linphone_friend_list_set_rls_uri(lfl, rls_uri); @@ -636,7 +636,7 @@ static void test_presence_list_subscribe_with_error(bool_t io_error) { int dummy = 0; LinphonePresenceModel *presence; - lp_config_set_int(laure->lc->config, "sip", "rls_presence_expires", 5); + lp_config_set_int(linphone_core_get_config(laure->lc), "sip", "rls_presence_expires", 5); pauline_identity = get_identity(pauline); presence = linphone_core_create_presence_model_with_activity(pauline->lc, LinphonePresenceActivityVacation, NULL); @@ -667,28 +667,28 @@ static void test_presence_list_subscribe_with_error(bool_t io_error) { enable_publish(pauline, TRUE); BC_ASSERT_TRUE(wait_for_until(laure->lc, pauline->lc, &laure->stat.number_of_LinphonePresenceActivityVacation, 1, 6000)); BC_ASSERT_GREATER(laure->stat.number_of_NotifyPresenceReceived, 1, int, "%d"); - BC_ASSERT_GREATER(linphone_core_get_default_friend_list(laure->lc)->expected_notification_version, 1, int, "%d"); + BC_ASSERT_GREATER(linphone_friend_list_get_expected_notification_version(linphone_core_get_default_friend_list(laure->lc)), 1, int, "%d"); lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(laure->lc), pauline_identity); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusVacation, int, "%d"); - BC_ASSERT_TRUE(lf->presence_received); + BC_ASSERT_TRUE(linphone_friend_is_presence_received(lf)); lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(laure->lc), "sip:michelle@sip.inexistentdomain.com"); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOffline, int, "%d"); - BC_ASSERT_FALSE(lf->presence_received); + BC_ASSERT_FALSE(linphone_friend_is_presence_received(lf)); BC_ASSERT_TRUE(wait_for_until(laure->lc, pauline->lc, &laure->stat.number_of_LinphonePresenceActivityVacation, 2, 6000)); if (io_error) { ms_message("Simulating socket error"); - sal_set_recv_error(laure->lc->sal, -1); + sal_set_recv_error(linphone_core_get_sal(laure->lc), -1); wait_for_list(lcs, &dummy, 1, 500); /* just time for socket to be closed */ } else { ms_message("Simulating in/out packets losses"); - sal_set_send_error(laure->lc->sal,1500); /*make sure no refresh is sent, trash the message without generating error*/ - sal_set_recv_error(laure->lc->sal, 1500); /*make sure server notify to close the dialog is also ignored*/ + sal_set_send_error(linphone_core_get_sal(laure->lc),1500); /*make sure no refresh is sent, trash the message without generating error*/ + sal_set_recv_error(linphone_core_get_sal(laure->lc), 1500); /*make sure server notify to close the dialog is also ignored*/ wait_for_list(lcs, &dummy, 1, 32000); /* Wait a little bit for the subscribe transaction to timeout */ } /*restart normal behavior*/ - sal_set_send_error(laure->lc->sal,0); - sal_set_recv_error(laure->lc->sal, 1); + sal_set_send_error(linphone_core_get_sal(laure->lc),0); + sal_set_recv_error(linphone_core_get_sal(laure->lc), 1); /*a new subscribe should be sent */ BC_ASSERT_TRUE(wait_for_until(laure->lc, pauline->lc, &laure->stat.number_of_LinphonePresenceActivityVacation, 3, 9000)); /* give time for subscription to recover to avoid to receive 491 Request pending*/ @@ -726,7 +726,7 @@ static void presence_list_subscribe_network_changes(void) { int dummy = 0; LinphonePresenceModel *presence; - lp_config_set_int(laure->lc->config, "sip", "rls_presence_expires", 5); + lp_config_set_int(linphone_core_get_config(laure->lc), "sip", "rls_presence_expires", 5); pauline_identity = get_identity(pauline); presence = linphone_core_create_presence_model_with_activity(pauline->lc, LinphonePresenceActivityVacation, NULL); @@ -757,13 +757,13 @@ static void presence_list_subscribe_network_changes(void) { enable_publish(pauline, TRUE); BC_ASSERT_TRUE(wait_for_until(laure->lc, pauline->lc, &laure->stat.number_of_LinphonePresenceActivityVacation, 1, 6000)); BC_ASSERT_GREATER(laure->stat.number_of_NotifyPresenceReceived, 1, int, "%d"); - BC_ASSERT_GREATER(linphone_core_get_default_friend_list(laure->lc)->expected_notification_version, 1, int, "%d"); + BC_ASSERT_GREATER(linphone_friend_list_get_expected_notification_version(linphone_core_get_default_friend_list(laure->lc)), 1, int, "%d"); lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(laure->lc), pauline_identity); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusVacation, int, "%d"); - BC_ASSERT_TRUE(lf->presence_received); + BC_ASSERT_TRUE(linphone_friend_is_presence_received(lf)); lf = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(laure->lc), "sip:michelle@sip.inexistentdomain.com"); BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOffline, int, "%d"); - BC_ASSERT_FALSE(lf->presence_received); + BC_ASSERT_FALSE(linphone_friend_is_presence_received(lf)); BC_ASSERT_TRUE(wait_for_until(laure->lc, pauline->lc, &laure->stat.number_of_LinphonePresenceActivityVacation, 2, 6000)); @@ -897,7 +897,7 @@ static void long_term_presence_list(void) { if (BC_ASSERT_PTR_NOT_NULL(presence)) { BC_ASSERT_STRING_EQUAL(linphone_presence_model_get_contact(presence), "sip:liblinphone_tester@sip.example.org"); } - BC_ASSERT_TRUE(f1->presence_received); + BC_ASSERT_TRUE(linphone_friend_is_presence_received(f1)); /*now try with nationnal version of phone numer*/ pauline_proxy_config = linphone_core_get_default_proxy_config(pauline->lc); @@ -910,7 +910,7 @@ static void long_term_presence_list(void) { f2 = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(pauline->lc), "sip:random_unknown@sip.example.org"); BC_ASSERT_EQUAL(linphone_presence_model_get_basic_status(linphone_friend_get_presence_model(f2)), LinphonePresenceBasicStatusClosed, int, "%d"); - BC_ASSERT_FALSE(f2->presence_received); + BC_ASSERT_FALSE(linphone_friend_is_presence_received(f2)); linphone_core_manager_destroy(pauline); }else ms_warning("Test skipped, no vcard support"); @@ -1144,7 +1144,7 @@ static void multiple_publish_aggregation(void) { _linphone_core_add_callbacks(pauline2->lc, callbacks, TRUE); linphone_core_cbs_unref(callbacks); - lp_config_set_int(marie->lc->config, "sip", "subscribe_expires", 40); + lp_config_set_int(linphone_core_get_config(marie->lc), "sip", "subscribe_expires", 40); linphone_core_set_user_agent(pauline->lc, "full-presence-support", NULL); linphone_core_set_user_agent(pauline2->lc, "full-presence-support", NULL); linphone_core_set_user_agent(marie->lc, "full-presence-support", NULL); @@ -1229,7 +1229,7 @@ static void extended_notify_only_both_side_subscribed(void) { _linphone_core_add_callbacks(pauline->lc, callbacks, TRUE); linphone_core_cbs_unref(callbacks); - lp_config_set_int(marie->lc->config, "sip", "subscribe_expires", 40); + lp_config_set_int(linphone_core_get_config(marie->lc), "sip", "subscribe_expires", 40); linphone_core_set_user_agent(pauline->lc, "full-presence-support", NULL); linphone_core_set_user_agent(marie->lc, "full-presence-support", NULL); enable_publish(pauline, TRUE); @@ -1303,7 +1303,7 @@ static void extended_notify_only_both_side_subscribed2(void) { _linphone_core_add_callbacks(pauline->lc, callbacks, TRUE); linphone_core_cbs_unref(callbacks); - lp_config_set_int(marie->lc->config, "sip", "subscribe_expires", 40); + lp_config_set_int(linphone_core_get_config(marie->lc), "sip", "subscribe_expires", 40); linphone_core_set_user_agent(pauline->lc, "full-presence-support", NULL); linphone_core_set_user_agent(marie->lc, "full-presence-support", NULL); enable_publish(pauline, TRUE); @@ -1380,7 +1380,7 @@ static void extended_notify_sub_unsub_sub(void) { _linphone_core_add_callbacks(pauline->lc, callbacks, TRUE); linphone_core_cbs_unref(callbacks); - lp_config_set_int(marie->lc->config, "sip", "subscribe_expires", 40); + lp_config_set_int(linphone_core_get_config(marie->lc), "sip", "subscribe_expires", 40); linphone_core_set_user_agent(pauline->lc, "full-presence-support", NULL); linphone_core_set_user_agent(marie->lc, "full-presence-support", NULL); @@ -1471,7 +1471,7 @@ static void extended_notify_sub_unsub_sub2(void) { _linphone_core_add_callbacks(pauline2->lc, callbacks, TRUE); linphone_core_cbs_unref(callbacks); - lp_config_set_int(marie->lc->config, "sip", "subscribe_expires", 40); + lp_config_set_int(linphone_core_get_config(marie->lc), "sip", "subscribe_expires", 40); linphone_core_set_user_agent(pauline->lc, "full-presence-support", NULL); linphone_core_set_user_agent(pauline2->lc, "full-presence-support", NULL); linphone_core_set_user_agent(marie->lc, "full-presence-support", NULL); diff --git a/tester/presence_tester.c b/tester/presence_tester.c index 7de76b692..176bba7d5 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -18,7 +18,6 @@ #include "linphone/core.h" -#include "private.h" #include "liblinphone_tester.h" static LinphoneCoreManager* presence_linphone_core_manager_new_with_rc_name(char* username, char * rc_name) { @@ -282,11 +281,11 @@ static void subscribe_failure_handle_by_app(void) { BC_ASSERT_TRUE(subscribe_to_callee_presence(marie,pauline)); wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,1); /*just to wait for unsubscription even if not notified*/ - sal_set_recv_error(marie->lc->sal, 0); /*simulate an error*/ + sal_set_recv_error(linphone_core_get_sal(marie->lc), 0); /*simulate an error*/ BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneRegistrationProgress,2)); BC_ASSERT_EQUAL(linphone_proxy_config_get_error(config),LinphoneReasonIOError, int, "%d"); - sal_set_recv_error(marie->lc->sal, 1); + sal_set_recv_error(linphone_core_get_sal(marie->lc), 1); lf = linphone_core_get_friend_by_address(marie->lc,lf_identity); ms_free(lf_identity); @@ -578,7 +577,7 @@ static void subscribe_presence_expired(void){ lcs = bctbx_list_append(lcs, marie->lc); lcs = bctbx_list_append(lcs, pauline1->lc); - lp_config_set_int(marie->lc->config, "sip", "subscribe_expires", 10); + lp_config_set_int(linphone_core_get_config(marie->lc), "sip", "subscribe_expires", 10); lf = linphone_core_create_friend(marie->lc); linphone_friend_set_address(lf, pauline1->identity); @@ -592,13 +591,13 @@ static void subscribe_presence_expired(void){ lf = linphone_core_find_friend(pauline1->lc, marie->identity); BC_ASSERT_PTR_NOT_NULL(lf); if (lf) { - BC_ASSERT_PTR_NOT_NULL(lf->insubs); + BC_ASSERT_PTR_NOT_NULL(linphone_friend_get_insubs(lf)); /*marie comes offline suddenly*/ linphone_core_set_network_reachable(marie->lc, FALSE); /*after a certain time, pauline shall see the incoming SUBSCRIBE expired*/ wait_for_list(lcs,NULL, 0, 11000); - BC_ASSERT_PTR_NULL(lf->insubs); + BC_ASSERT_PTR_NULL(linphone_friend_get_insubs(lf)); /*just make network reachable so that marie can unregister properly*/ linphone_core_set_network_reachable(marie->lc, TRUE); diff --git a/tester/quality_reporting_tester.c b/tester/quality_reporting_tester.c index d60068418..590ab6694 100644 --- a/tester/quality_reporting_tester.c +++ b/tester/quality_reporting_tester.c @@ -18,8 +18,8 @@ #include #include "linphone/core.h" -#include "private.h" #include "liblinphone_tester.h" +#include "quality_reporting.h" /*avoid crash if x is NULL on libc versions <4.5.26 */ #define __strstr(x, y) ((x==NULL)?NULL:strstr(x,y)) @@ -81,14 +81,14 @@ char * on_report_send_verify_metrics(const reporting_content_metrics_t *metrics, void on_report_send_with_rtcp_xr_local(const LinphoneCall *call, SalStreamType stream_type, const LinphoneContent *content){ char * body = (char*)linphone_content_get_buffer(content); char * remote_metrics_start = __strstr(body, "RemoteMetrics:"); - reporting_session_report_t * report = linphone_call_get_log(call)->reporting.reports[stream_type]; + reporting_session_report_t * report = linphone_quality_reporting_get_reports(linphone_call_log_get_quality_reporting(linphone_call_get_log(call)))[stream_type]; on_report_send_mandatory(call,stream_type,content); BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "LocalMetrics:")); BC_ASSERT_TRUE(!remote_metrics_start || on_report_send_verify_metrics(&report->local_metrics,body) < remote_metrics_start); } void on_report_send_with_rtcp_xr_remote(const LinphoneCall *call, SalStreamType stream_type, const LinphoneContent *content){ char * body = (char*)linphone_content_get_buffer(content); - reporting_session_report_t * report = linphone_call_get_log(call)->reporting.reports[stream_type]; + reporting_session_report_t * report = linphone_quality_reporting_get_reports(linphone_call_log_get_quality_reporting(linphone_call_get_log(call)))[stream_type]; on_report_send_mandatory(call,stream_type,content); if (report->remote_metrics.rtcp_sr_count+report->remote_metrics.rtcp_xr_count>0){ @@ -132,6 +132,8 @@ static void quality_reporting_not_used_without_config(void) { LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); LinphoneCall* call_marie = NULL; LinphoneCall* call_pauline = NULL; + reporting_session_report_t **quality_reports = NULL; + if (create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline, NULL, NULL)) { // marie has stats collection enabled but pauline has not @@ -139,10 +141,11 @@ static void quality_reporting_not_used_without_config(void) { BC_ASSERT_FALSE(linphone_proxy_config_quality_reporting_enabled(linphone_call_get_dest_proxy(call_pauline))); // this field should be already filled - BC_ASSERT_PTR_NOT_NULL(linphone_call_get_log(call_marie)->reporting.reports[0]->info.local_addr.ip); + quality_reports = linphone_quality_reporting_get_reports(linphone_call_log_get_quality_reporting(linphone_call_get_log(call_marie))); + BC_ASSERT_PTR_NOT_NULL(quality_reports[0]->info.local_addr.ip); // but not this one since it is updated at the end of call - BC_ASSERT_PTR_NULL(linphone_call_get_log(call_marie)->reporting.reports[0]->dialog_id); + BC_ASSERT_PTR_NULL(quality_reports[0]->dialog_id); end_call(marie, pauline); } @@ -233,6 +236,7 @@ static void quality_reporting_at_call_termination(void) { LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_rtcp_xr"); LinphoneCall* call_marie = NULL; LinphoneCall* call_pauline = NULL; + reporting_session_report_t **quality_reports = NULL; if (create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline, NULL, NULL)) { linphone_reporting_set_on_report_send(call_marie, on_report_send_with_rtcp_xr_remote); @@ -240,7 +244,8 @@ static void quality_reporting_at_call_termination(void) { linphone_core_terminate_all_calls(marie->lc); // now dialog id should be filled - BC_ASSERT_PTR_NOT_NULL(linphone_call_get_log(call_marie)->reporting.reports[0]->dialog_id); + quality_reports = linphone_quality_reporting_get_reports(linphone_call_log_get_quality_reporting(linphone_call_get_log(call_marie))); + BC_ASSERT_PTR_NOT_NULL(quality_reports[0]->dialog_id); BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallReleased,1, 10000)); BC_ASSERT_TRUE(wait_for_until(pauline->lc,NULL,&pauline->stat.number_of_LinphoneCallReleased,1, 10000)); diff --git a/tester/register_tester.c b/tester/register_tester.c index aa9b1f52e..e3b750480 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -18,7 +18,6 @@ #include "linphone/core.h" -#include "private.h" #include "liblinphone_tester.h" @@ -145,7 +144,7 @@ static void register_with_refresh_base_2(LinphoneCore* lc register_with_refresh_base_3(lc, refresh, domain, route, late_auth_info, transport,LinphoneRegistrationOk ); } static void register_with_refresh_base(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { - LinphoneTransports *transport = linphone_transports_new(); + LinphoneTransports *transport = linphone_factory_create_transports(linphone_factory_get()); linphone_transports_set_udp_port(transport, 5070); linphone_transports_set_tcp_port(transport, 5070); linphone_transports_set_tls_port(transport, 5071); @@ -172,7 +171,7 @@ static void register_with_refresh_with_send_error(void) { linphone_auth_info_unref(info); register_with_refresh_base(lcm->lc,TRUE,auth_domain,route); /*simultate a network error*/ - sal_set_send_error(lcm->lc->sal, -1); + sal_set_send_error(linphone_core_get_sal(lcm->lc), -1); while (counters->number_of_LinphoneRegistrationProgress<2 && retry++ <200) { linphone_core_iterate(lcm->lc); ms_usleep(10000); @@ -289,7 +288,7 @@ static void simple_tcp_register_compatibility_mode(void){ LinphoneTransports *transport = NULL; sprintf(route,"sip:%s",test_route); lcm = create_lcm(); - transport = linphone_transports_new(); + transport = linphone_factory_create_transports(linphone_factory_get()); linphone_transports_set_tcp_port(transport, 5070); register_with_refresh_base_2(lcm->lc,FALSE,test_domain,route,FALSE,transport); linphone_transports_unref(transport); @@ -369,7 +368,7 @@ static void authenticated_register_with_late_credentials(void){ sprintf(route,"sip:%s",test_route); lcm = linphone_core_manager_new(NULL); - transport = linphone_transports_new(); + transport = linphone_factory_create_transports(linphone_factory_get()); linphone_transports_set_udp_port(transport, 5070); linphone_transports_set_tcp_port(transport, 5070); linphone_transports_set_dtls_port(transport, 5071); @@ -415,8 +414,8 @@ static void authenticated_register_with_provided_credentials(void){ BC_ASSERT_TRUE(wait_for(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationOk,1)); BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,0, int, "%d"); - BC_ASSERT_PTR_NULL(lp_config_get_string(lcm->lc->config, "auth_info_0", "passwd", NULL)); - BC_ASSERT_PTR_NOT_NULL(lp_config_get_string(lcm->lc->config, "auth_info_0", "ha1", NULL)); + BC_ASSERT_PTR_NULL(lp_config_get_string(linphone_core_get_config(lcm->lc), "auth_info_0", "passwd", NULL)); + BC_ASSERT_PTR_NOT_NULL(lp_config_get_string(linphone_core_get_config(lcm->lc), "auth_info_0", "ha1", NULL)); linphone_proxy_config_destroy(cfg); linphone_core_manager_destroy(lcm); @@ -435,7 +434,7 @@ static void authenticated_register_with_wrong_late_credentials(void){ sprintf(route,"sip:%s",test_route); lcm = linphone_core_manager_new(NULL); - transport = linphone_transports_new(); + transport = linphone_factory_create_transports(linphone_factory_get()); linphone_transports_set_udp_port(transport, 5070); linphone_transports_set_tcp_port(transport, 5070); linphone_transports_set_tls_port(transport, 5071); @@ -454,7 +453,7 @@ static void authenticated_register_with_wrong_late_credentials(void){ static void authenticated_register_with_wrong_credentials_with_params_base(const char* user_agent,LinphoneCoreManager *lcm) { stats* counters; - LinphoneTransports *transport = linphone_transports_new(); + LinphoneTransports *transport = linphone_factory_create_transports(linphone_factory_get()); LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,"wrong passwd",NULL,auth_domain,NULL); /*create authentication structure from identity*/ char route[256]; @@ -464,7 +463,7 @@ static void authenticated_register_with_wrong_credentials_with_params_base(const linphone_transports_set_tls_port(transport, 5071); linphone_transports_set_dtls_port(transport, 0); - sal_set_refresher_retry_after(lcm->lc->sal,500); + sal_set_refresher_retry_after(linphone_core_get_sal(lcm->lc),500); if (user_agent) { linphone_core_set_user_agent(lcm->lc,user_agent,NULL); } @@ -585,7 +584,7 @@ static void transport_change(void){ lcm=configure_lcm(); if (lcm) { lc=lcm->lc; - sip_tr = linphone_transports_new(); + sip_tr = linphone_factory_create_transports(linphone_factory_get()); counters = get_stats(lc); register_ok=counters->number_of_LinphoneRegistrationOk; @@ -593,7 +592,7 @@ static void transport_change(void){ total_number_of_proxies=(int)bctbx_list_size(linphone_core_get_proxy_config_list(lc)); sip_tr_orig = linphone_core_get_transports(lc); - sip_tr->udp_port = sip_tr_orig->udp_port; + linphone_transports_set_udp_port(sip_tr, linphone_transports_get_udp_port(sip_tr_orig)); /*keep only udp*/ linphone_core_set_transports(lc, sip_tr); @@ -610,7 +609,7 @@ static void transport_change(void){ static void transport_dont_bind(void){ LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_tcp_rc"); stats* counters = &pauline->stat; - LinphoneTransports *tr = linphone_transports_new(); + LinphoneTransports *tr = linphone_factory_create_transports(linphone_factory_get()); linphone_transports_set_tcp_port(tr, LC_SIP_TRANSPORT_DONTBIND); linphone_transports_set_tls_port(tr, LC_SIP_TRANSPORT_DONTBIND); @@ -618,9 +617,9 @@ static void transport_dont_bind(void){ BC_ASSERT_TRUE(wait_for_until(pauline->lc,pauline->lc,&counters->number_of_LinphoneRegistrationOk,2,15000)); linphone_transports_unref(tr); tr = linphone_core_get_transports_used(pauline->lc); - BC_ASSERT_EQUAL(tr->udp_port, 0, int, "%i"); - BC_ASSERT_EQUAL(tr->tcp_port, LC_SIP_TRANSPORT_DONTBIND, int, "%i"); - BC_ASSERT_EQUAL(tr->tls_port, LC_SIP_TRANSPORT_DONTBIND, int, "%i"); + BC_ASSERT_EQUAL(linphone_transports_get_udp_port(tr), 0, int, "%i"); + BC_ASSERT_EQUAL(linphone_transports_get_tcp_port(tr), LC_SIP_TRANSPORT_DONTBIND, int, "%i"); + BC_ASSERT_EQUAL(linphone_transports_get_tls_port(tr), LC_SIP_TRANSPORT_DONTBIND, int, "%i"); linphone_transports_unref(tr); linphone_core_manager_destroy(pauline); } @@ -696,7 +695,7 @@ static void proxy_transport_change_with_wrong_port(void) { LinphoneProxyConfig* proxy_config; LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ char route[256]; - LinphoneTransports *transport= linphone_transports_new(); + LinphoneTransports *transport= linphone_factory_create_transports(linphone_factory_get()); sprintf(route,"sip:%s",test_route); linphone_transports_set_udp_port(transport, LC_SIP_TRANSPORT_RANDOM); linphone_transports_set_tcp_port(transport, LC_SIP_TRANSPORT_RANDOM); @@ -732,7 +731,7 @@ static void proxy_transport_change_with_wrong_port_givin_up(void) { LinphoneProxyConfig* proxy_config; LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ char route[256]; - LinphoneTransports *transport = linphone_transports_new(); + LinphoneTransports *transport = linphone_factory_create_transports(linphone_factory_get()); sprintf(route,"sip:%s",test_route); linphone_transports_set_udp_port(transport, LC_SIP_TRANSPORT_RANDOM); linphone_transports_set_tcp_port(transport, LC_SIP_TRANSPORT_RANDOM); @@ -774,12 +773,12 @@ static void io_recv_error(void){ counters = get_stats(lc); register_ok=counters->number_of_LinphoneRegistrationOk; number_of_udp_proxy=get_number_of_udp_proxy(lc); - sal_set_recv_error(lc->sal, 0); + sal_set_recv_error(linphone_core_get_sal(lc), 0); BC_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationProgress,2*(register_ok-number_of_udp_proxy) /*because 1 udp*/)); BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0,int,"%d"); - sal_set_recv_error(lc->sal, 1); /*reset*/ + sal_set_recv_error(linphone_core_get_sal(lc), 1); /*reset*/ linphone_core_manager_destroy(lcm); } @@ -798,11 +797,11 @@ static void io_recv_error_retry_immediatly(void){ counters = get_stats(lc); register_ok=counters->number_of_LinphoneRegistrationOk; number_of_udp_proxy=get_number_of_udp_proxy(lc); - sal_set_recv_error(lc->sal, 0); + sal_set_recv_error(linphone_core_get_sal(lc), 0); BC_ASSERT_TRUE(wait_for(lc,NULL,&counters->number_of_LinphoneRegistrationProgress,(register_ok-number_of_udp_proxy)+register_ok /*because 1 udp*/)); BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0,int,"%d"); - sal_set_recv_error(lc->sal, 1); /*reset*/ + sal_set_recv_error(linphone_core_get_sal(lc), 1); /*reset*/ BC_ASSERT_TRUE(wait_for_until(lc,lc,&counters->number_of_LinphoneRegistrationOk,register_ok-number_of_udp_proxy+register_ok,30000)); @@ -820,7 +819,7 @@ static void io_recv_error_late_recovery(void){ bctbx_list_t* lcs; lcm=linphone_core_manager_new2( "multi_account_rc",FALSE); /*to make sure iterates are not call yet*/ lc=lcm->lc; - sal_set_refresher_retry_after(lc->sal,1000); + sal_set_refresher_retry_after(linphone_core_get_sal(lc),1000); counters=&lcm->stat; BC_ASSERT_TRUE(wait_for(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationOk,(int)bctbx_list_size(linphone_core_get_proxy_config_list(lcm->lc)))); @@ -829,18 +828,18 @@ static void io_recv_error_late_recovery(void){ register_ok=counters->number_of_LinphoneRegistrationOk; number_of_udp_proxy=get_number_of_udp_proxy(lc); /*simulate a general socket error*/ - sal_set_recv_error(lc->sal, 0); - sal_set_send_error(lc->sal, -1); + sal_set_recv_error(linphone_core_get_sal(lc), 0); + sal_set_send_error(linphone_core_get_sal(lc), -1); BC_ASSERT_TRUE(wait_for(lc,NULL,&counters->number_of_LinphoneRegistrationProgress,(register_ok-number_of_udp_proxy)+register_ok /*because 1 udp*/)); BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0,int,"%d"); - BC_ASSERT_TRUE(wait_for_list(lcs=bctbx_list_append(NULL,lc),&counters->number_of_LinphoneRegistrationFailed,(register_ok-number_of_udp_proxy),sal_get_refresher_retry_after(lc->sal)+3000)); + BC_ASSERT_TRUE(wait_for_list(lcs=bctbx_list_append(NULL,lc),&counters->number_of_LinphoneRegistrationFailed,(register_ok-number_of_udp_proxy),sal_get_refresher_retry_after(linphone_core_get_sal(lc))+3000)); - sal_set_recv_error(lc->sal, 1); /*reset*/ - sal_set_send_error(lc->sal, 0); + sal_set_recv_error(linphone_core_get_sal(lc), 1); /*reset*/ + sal_set_send_error(linphone_core_get_sal(lc), 0); - BC_ASSERT_TRUE(wait_for_list(lcs=bctbx_list_append(NULL,lc),&counters->number_of_LinphoneRegistrationOk,register_ok-number_of_udp_proxy +register_ok,sal_get_refresher_retry_after(lc->sal)+3000)); + BC_ASSERT_TRUE(wait_for_list(lcs=bctbx_list_append(NULL,lc),&counters->number_of_LinphoneRegistrationOk,register_ok-number_of_udp_proxy +register_ok,sal_get_refresher_retry_after(linphone_core_get_sal(lc))+3000)); linphone_core_manager_destroy(lcm); } } @@ -870,7 +869,7 @@ static void io_recv_error_without_active_register(void){ /*wait for unregistrations*/ BC_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationCleared,register_ok /*because 1 udp*/)); - sal_set_recv_error(lc->sal, 0); + sal_set_recv_error(linphone_core_get_sal(lc), 0); /*nothing should happen because no active registration*/ wait_for_until(lc,lc, &dummy, 1, 3000); @@ -878,7 +877,7 @@ static void io_recv_error_without_active_register(void){ BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0,int,"%d"); - sal_set_recv_error(lc->sal, 1); /*reset*/ + sal_set_recv_error(linphone_core_get_sal(lc), 1); /*reset*/ linphone_core_manager_destroy(lcm); } @@ -969,7 +968,7 @@ static void tls_with_non_tls_server(void){ lcm=linphone_core_manager_new2( "marie_rc", 0); lc=lcm->lc; - sal_set_transport_timeout(lc->sal,3000); + sal_set_transport_timeout(linphone_core_get_sal(lc),3000); proxy_cfg = linphone_core_get_default_proxy_config(lc); linphone_proxy_config_edit(proxy_cfg); addr=linphone_address_new(linphone_proxy_config_get_addr(proxy_cfg)); @@ -1024,7 +1023,7 @@ static void redirect(void){ sprintf(route,"sip:%s:5064",test_route); lcm = create_lcm(); if (lcm) { - transport = linphone_transports_new(); + transport = linphone_factory_create_transports(linphone_factory_get()); linphone_transports_set_udp_port(transport, -1); linphone_core_set_user_agent(lcm->lc,"redirect",NULL); register_with_refresh_base_2(lcm->lc,FALSE,test_domain,route,FALSE,transport); @@ -1040,7 +1039,7 @@ static void tls_auth_global_client_cert(void) { char *cert_path = bc_tester_res("certificates/client/cert.pem"); char *key_path = bc_tester_res("certificates/client/key.pem"); linphone_core_manager_init(manager, "pauline_tls_client_rc", NULL); - lpc = manager->lc->config; + lpc = linphone_core_get_config(manager->lc); lp_config_set_string(lpc, "sip", "client_cert_chain", cert_path); lp_config_set_string(lpc, "sip", "client_cert_key", key_path); linphone_core_manager_start(manager, TRUE); @@ -1092,7 +1091,7 @@ static void tls_auth_info_client_cert_api(void) { char *cert = read_file(cert_path); char *key = read_file(key_path); LinphoneCore *lc = pauline->lc; - LinphoneAuthInfo *authInfo = (LinphoneAuthInfo *)lc->auth_info->data; + LinphoneAuthInfo *authInfo = (LinphoneAuthInfo *)bctbx_list_get_data(linphone_core_get_auth_info_list(lc)); linphone_auth_info_set_tls_cert(authInfo, cert); linphone_auth_info_set_tls_key(authInfo, key); BC_ASSERT_TRUE(wait_for(lc, lc, &pauline->stat.number_of_LinphoneRegistrationOk, 1)); @@ -1110,7 +1109,7 @@ static void tls_auth_info_client_cert_api_path(void) { char *cert = bc_tester_res("certificates/client/cert.pem"); char *key = bc_tester_res("certificates/client/key.pem"); LinphoneCore *lc = pauline->lc; - LinphoneAuthInfo *authInfo = (LinphoneAuthInfo *)lc->auth_info->data; + LinphoneAuthInfo *authInfo = (LinphoneAuthInfo *)bctbx_list_get_data(linphone_core_get_auth_info_list(lc)); linphone_auth_info_set_tls_cert_path(authInfo, cert); linphone_auth_info_set_tls_key_path(authInfo, key); BC_ASSERT_TRUE(wait_for(lc, lc, &pauline->stat.number_of_LinphoneRegistrationOk, 1)); diff --git a/tester/remote_provisioning_tester.c b/tester/remote_provisioning_tester.c index 967533780..25fc22d17 100644 --- a/tester/remote_provisioning_tester.c +++ b/tester/remote_provisioning_tester.c @@ -18,7 +18,6 @@ #include "linphone/core.h" -#include "private.h" #include "liblinphone_tester.h" void linphone_configuration_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) { @@ -89,11 +88,11 @@ static void remote_provisioning_default_values(void) { LinphoneCoreManager* marie = linphone_core_manager_new2("marie_remote_default_values_rc", FALSE); BC_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSuccessful,1)); lpc = linphone_core_create_proxy_config(marie->lc); - BC_ASSERT_TRUE(lpc->reg_sendregister); - BC_ASSERT_EQUAL(lpc->expires, 604800, int, "%d"); - BC_ASSERT_STRING_EQUAL(lpc->reg_proxy, ""); - BC_ASSERT_STRING_EQUAL(lpc->reg_route, ""); - BC_ASSERT_STRING_EQUAL(lpc->reg_identity, "sip:?@sip.linphone.org"); + BC_ASSERT_TRUE(linphone_proxy_config_register_enabled(lpc)); + BC_ASSERT_EQUAL(linphone_proxy_config_get_expires(lpc), 604800, int, "%d"); + BC_ASSERT_STRING_EQUAL(linphone_proxy_config_get_server_addr(lpc), ""); + BC_ASSERT_STRING_EQUAL(linphone_proxy_config_get_route(lpc), ""); + BC_ASSERT_STRING_EQUAL(linphone_proxy_config_get_identity(lpc), "sip:?@sip.linphone.org"); { LpConfig* lp = linphone_core_get_config(marie->lc); BC_ASSERT_STRING_EQUAL(lp_config_get_string(lp,"app","toto","empty"),"titi"); @@ -119,7 +118,7 @@ static void remote_provisioning_file(void) { { char* path = bc_tester_res("rcfiles/marie_remote_localfile2_rc"); char* abspath = ms_strdup_printf("file://%s", path); - lp_config_set_string(marie->lc->config, "misc", "config-uri", abspath); + lp_config_set_string(linphone_core_get_config(marie->lc), "misc", "config-uri", abspath); linphone_core_manager_start(marie, 1); ms_free(path); ms_free(abspath); diff --git a/tester/setup_tester.c b/tester/setup_tester.c index 5f4e24890..3e37b6965 100644 --- a/tester/setup_tester.c +++ b/tester/setup_tester.c @@ -20,7 +20,6 @@ #include "linphone/core.h" #include "liblinphone_tester.h" #include "linphone/lpconfig.h" -#include "private.h" static void linphone_version_test(void){ const char *version=linphone_core_get_version(); @@ -187,7 +186,7 @@ static void linphone_lpconfig_from_xml_zerolen_value(void){ BC_ASSERT_EQUAL(linphone_remote_provisioning_load_file(mgr->lc, xml_path), 0, int, "%d"); - conf = mgr->lc->config; + conf = linphone_core_get_config(mgr->lc); BC_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"test","zero_len","LOL"),"LOL"); BC_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"test","non_zero_len",""),"test"); diff --git a/tester/stun_tester.c b/tester/stun_tester.c index 6cad11fe8..3c6768c86 100644 --- a/tester/stun_tester.c +++ b/tester/stun_tester.c @@ -17,7 +17,6 @@ */ #include "linphone/core.h" -#include "private.h" #include "liblinphone_tester.h" #include "mediastreamer2/stun.h" #include "ortp/port.h" diff --git a/tester/tester.c b/tester/tester.c index 7f2d684bc..7829cb540 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -19,7 +19,6 @@ #include #include #include "linphone/core.h" -#include "private.h" #include "liblinphone_tester.h" #include @@ -164,8 +163,8 @@ LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, c linphone_core_enable_ipv6(lc, liblinphonetester_ipv6); linphone_core_set_sip_transport_timeout(lc, liblinphonetester_transport_timeout); - sal_enable_test_features(lc->sal,TRUE); - sal_set_dns_user_hosts_file(lc->sal, dnsuserhostspath); + sal_enable_test_features(linphone_core_get_sal(lc),TRUE); + sal_set_dns_user_hosts_file(linphone_core_get_sal(lc), dnsuserhostspath); #ifdef VIDEO_ENABLED linphone_core_set_static_picture(lc,nowebcampath); #endif @@ -343,13 +342,13 @@ void linphone_core_manager_init(LinphoneCoreManager *mgr, const char* rc_file, c { MSWebCam *cam; - cam = ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(mgr->lc->factory), "Mire: Mire (synthetic moving picture)"); + cam = ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(linphone_core_get_ms_factory(mgr->lc)), "Mire: Mire (synthetic moving picture)"); if (cam == NULL) { MSWebCamDesc *desc = ms_mire_webcam_desc_get(); if (desc){ cam=ms_web_cam_new(desc); - ms_web_cam_manager_add_cam(ms_factory_get_web_cam_manager(mgr->lc->factory), cam); + ms_web_cam_manager_add_cam(ms_factory_get_web_cam_manager(linphone_core_get_ms_factory(mgr->lc)), cam); } } } @@ -369,7 +368,7 @@ void linphone_core_manager_init(LinphoneCoreManager *mgr, const char* rc_file, c linphone_core_set_user_certificates_path(mgr->lc,bc_tester_get_writable_dir_prefix()); /*for now, we need the periodical updates facility to compute bandwidth measurements correctly during tests*/ - mgr->lc->send_call_stats_periodical_updates = TRUE; + linphone_core_enable_send_call_stats_periodical_updates(mgr->lc, TRUE); if (rc_path) ms_free(rc_path); } @@ -713,7 +712,7 @@ static void check_ice_from_rtp(LinphoneCall *c1, LinphoneCall *c2, LinphoneStrea const LinphoneCallParams *cp2 = linphone_call_get_current_params(c2); if (linphone_call_params_get_update_call_when_ice_completed(cp1) && linphone_call_params_get_update_call_when_ice_completed(cp2)) { memset(&remaddr, 0, remaddrlen); - result_desc = sal_call_get_final_media_description(linphone_call_get_op(c2)); + result_desc = sal_call_get_final_media_description(linphone_call_get_op_as_sal_op(c2)); expected_addr = result_desc->streams[0].rtp_addr; if (expected_addr[0] == '\0') expected_addr = result_desc->addr; astream = (AudioStream *)linphone_call_get_stream(c1, LinphoneStreamTypeAudio); diff --git a/tester/tunnel_tester.c b/tester/tunnel_tester.c index 37889b847..5e3d41e86 100644 --- a/tester/tunnel_tester.c +++ b/tester/tunnel_tester.c @@ -20,7 +20,6 @@ #include #include "linphone/core.h" #include "linphone/lpconfig.h" -#include "private.h" #include "liblinphone_tester.h" /* Retrieve the public IP from a given hostname */ diff --git a/tester/vcard_tester.c b/tester/vcard_tester.c index d4031715a..abad43f2d 100644 --- a/tester/vcard_tester.c +++ b/tester/vcard_tester.c @@ -17,13 +17,13 @@ */ #include "linphone/core.h" -#include "private.h" #ifdef VCARD_ENABLED #include "liblinphone_tester.h" #include "carddav.h" +#include #include #define CARDDAV_SERVER "http://dav.linphone.org/card.php/addressbooks/tester/default" @@ -145,7 +145,7 @@ static void linphone_vcard_update_existing_friends_test(void) { static void linphone_vcard_phone_numbers_and_sip_addresses(void) { LinphoneCoreManager* manager = linphone_core_manager_new2("empty_rc", FALSE); - LinphoneVcard *lvc = linphone_vcard_context_get_vcard_from_buffer(manager->lc->vcard_context, "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Sylvain Berfini\r\nIMPP:sip:sberfini@sip.linphone.org\r\nIMPP;TYPE=home:sip:sylvain@sip.linphone.org\r\nTEL;TYPE=work:0952636505\r\nEND:VCARD\r\n"); + LinphoneVcard *lvc = linphone_vcard_context_get_vcard_from_buffer(linphone_core_get_vcard_context(manager->lc), "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Sylvain Berfini\r\nIMPP:sip:sberfini@sip.linphone.org\r\nIMPP;TYPE=home:sip:sylvain@sip.linphone.org\r\nTEL;TYPE=work:0952636505\r\nEND:VCARD\r\n"); LinphoneFriend *lf = linphone_friend_new_from_vcard(lvc); linphone_vcard_unref(lvc); const bctbx_list_t *sip_addresses = linphone_friend_get_addresses(lf); @@ -157,10 +157,10 @@ static void linphone_vcard_phone_numbers_and_sip_addresses(void) { if (phone_numbers) bctbx_list_free(phone_numbers); linphone_friend_unref(lf); - lvc = linphone_vcard_context_get_vcard_from_buffer(manager->lc->vcard_context, "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Sylvain Berfini\r\nTEL;TYPE=work:0952636505\r\nTEL:0476010203\r\nEND:VCARD\r\n"); + lvc = linphone_vcard_context_get_vcard_from_buffer(linphone_core_get_vcard_context(manager->lc), "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Sylvain Berfini\r\nTEL;TYPE=work:0952636505\r\nTEL:0476010203\r\nEND:VCARD\r\n"); lf = linphone_friend_new_from_vcard(lvc); linphone_vcard_unref(lvc); - lf->lc = manager->lc; + linphone_friend_set_core(lf, manager->lc); sip_addresses = linphone_friend_get_addresses(lf); phone_numbers = linphone_friend_get_phone_numbers(lf); @@ -314,19 +314,19 @@ static void friends_sqlite_storage(void) { linphone_friend_list_set_display_name(lfl, "Test"); BC_ASSERT_EQUAL(linphone_friend_list_add_friend(lfl, lf), LinphoneFriendListOK, int, "%i"); linphone_friend_unref(lf); - BC_ASSERT_EQUAL(lfl->storage_id, 1, unsigned int, "%u"); - BC_ASSERT_EQUAL(lf->storage_id, 1, unsigned int, "%u"); + BC_ASSERT_EQUAL(linphone_friend_list_get_storage_id(lfl), 1, unsigned int, "%u"); + BC_ASSERT_EQUAL(linphone_friend_get_storage_id(lf), 1, unsigned int, "%u"); friends = linphone_friend_list_get_friends(linphone_core_get_default_friend_list(lc)); BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(friends), 0, unsigned int, "%u"); friends_lists_from_db = linphone_core_fetch_friends_lists_from_db(lc); BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(friends_lists_from_db), 1, unsigned int, "%u"); - friends_from_db = ((LinphoneFriendList *)friends_lists_from_db->data)->friends; + friends_from_db = *linphone_friend_list_get_friends_attribute((LinphoneFriendList *)bctbx_list_get_data(friends_lists_from_db)); BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(friends_from_db), 1, unsigned int, "%u"); lf2 = (LinphoneFriend *)friends_from_db->data; - BC_ASSERT_PTR_NOT_NULL(lf2->lc); - BC_ASSERT_PTR_NOT_NULL(lf2->friend_list); + BC_ASSERT_PTR_NOT_NULL(linphone_friend_get_core(lf2)); + BC_ASSERT_PTR_NOT_NULL(linphone_friend_get_friend_list(lf2)); friends_lists_from_db = bctbx_list_free_with_data(friends_lists_from_db, (void (*)(void *))linphone_friend_list_unref); friends_from_db = linphone_core_fetch_friends_from_db(lc, lfl); @@ -336,7 +336,7 @@ static void friends_sqlite_storage(void) { } lf2 = (LinphoneFriend *)friends_from_db->data; BC_ASSERT_STRING_EQUAL(linphone_friend_get_name(lf2), linphone_friend_get_name(lf)); - BC_ASSERT_EQUAL(lf2->storage_id, lf->storage_id, unsigned int, "%u"); + BC_ASSERT_EQUAL(linphone_friend_get_storage_id(lf2), linphone_friend_get_storage_id(lf), unsigned int, "%u"); BC_ASSERT_STRING_EQUAL(linphone_vcard_get_etag(linphone_friend_get_vcard(lf2)), linphone_vcard_get_etag(linphone_friend_get_vcard(lf))); BC_ASSERT_STRING_EQUAL(linphone_vcard_get_url(linphone_friend_get_vcard(lf2)), linphone_vcard_get_url(linphone_friend_get_vcard(lf))); laddress = linphone_friend_get_address(lf); @@ -388,7 +388,7 @@ static void friends_sqlite_store_lot_of_friends(void) { int ret; char *buf; - ret = sqlite3_open(lc->friends_db_file, &db); + ret = sqlite3_open(linphone_core_get_friends_database_path(lc), &db); BC_ASSERT_TRUE(ret ==SQLITE_OK); ret = sqlite3_exec(db,"BEGIN",0,0,&errmsg); BC_ASSERT_TRUE(ret ==SQLITE_OK); @@ -456,7 +456,7 @@ static void friends_sqlite_find_friend_in_lot_of_friends(void) { bctoolboxTimeSpec t1; bctoolboxTimeSpec t2; - ret = sqlite3_open(lc->friends_db_file, &db); + ret = sqlite3_open(linphone_core_get_friends_database_path(lc), &db); BC_ASSERT_TRUE(ret ==SQLITE_OK); ret = sqlite3_exec(db,"BEGIN",0,0,&errmsg); BC_ASSERT_TRUE(ret ==SQLITE_OK); @@ -633,7 +633,7 @@ static void carddav_sync_2(void) { static void carddav_sync_3(void) { LinphoneCoreManager *manager = linphone_core_manager_new2("carddav_rc", FALSE); LinphoneCardDAVStats *stats = (LinphoneCardDAVStats *)ms_new0(LinphoneCardDAVStats, 1); - LinphoneVcard *lvc = linphone_vcard_context_get_vcard_from_buffer(manager->lc->vcard_context, "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:1f08dd48-29ac-4097-8e48-8596d7776283\r\nFN:Sylvain Berfini\r\nIMPP;TYPE=work:sip:sylvain@sip.linphone.org\r\nEND:VCARD\r\n"); + LinphoneVcard *lvc = linphone_vcard_context_get_vcard_from_buffer(linphone_core_get_vcard_context(manager->lc), "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:1f08dd48-29ac-4097-8e48-8596d7776283\r\nFN:Sylvain Berfini\r\nIMPP;TYPE=work:sip:sylvain@sip.linphone.org\r\nEND:VCARD\r\n"); LinphoneFriend *lf = linphone_friend_new_from_vcard(lvc); char *friends_db = bc_tester_file("friends.db"); LinphoneFriendList *lfl = linphone_core_create_friend_list(manager->lc); @@ -674,7 +674,7 @@ static void carddav_sync_3(void) { static void carddav_sync_4(void) { LinphoneCoreManager *manager = linphone_core_manager_new2("carddav_rc", FALSE); LinphoneCardDAVStats *stats = (LinphoneCardDAVStats *)ms_new0(LinphoneCardDAVStats, 1); - LinphoneVcard *lvc = linphone_vcard_context_get_vcard_from_buffer(manager->lc->vcard_context, "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Margaux Clerc\r\nIMPP;TYPE=work:sip:margaux@sip.linphone.org\r\nEND:VCARD\r\n"); + LinphoneVcard *lvc = linphone_vcard_context_get_vcard_from_buffer(linphone_core_get_vcard_context(manager->lc), "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Margaux Clerc\r\nIMPP;TYPE=work:sip:margaux@sip.linphone.org\r\nEND:VCARD\r\n"); LinphoneFriend *lf = linphone_friend_new_from_vcard(lvc); LinphoneFriendList *lfl = linphone_core_create_friend_list(manager->lc); LinphoneCardDavContext *c = NULL; @@ -709,23 +709,23 @@ static void carddav_sync_4(void) { } static void carddav_contact_created(LinphoneFriendList *list, LinphoneFriend *lf) { - LinphoneCardDAVStats *stats = (LinphoneCardDAVStats *)linphone_friend_list_cbs_get_user_data(list->cbs); + LinphoneCardDAVStats *stats = (LinphoneCardDAVStats *)linphone_friend_list_cbs_get_user_data(linphone_friend_list_get_callbacks(list)); stats->new_contact_count++; } static void carddav_contact_deleted(LinphoneFriendList *list, LinphoneFriend *lf) { - LinphoneCardDAVStats *stats = (LinphoneCardDAVStats *)linphone_friend_list_cbs_get_user_data(list->cbs); + LinphoneCardDAVStats *stats = (LinphoneCardDAVStats *)linphone_friend_list_cbs_get_user_data(linphone_friend_list_get_callbacks(list)); stats->removed_contact_count++; } static void carddav_contact_updated(LinphoneFriendList *list, LinphoneFriend *new_friend, LinphoneFriend *old_friend) { - LinphoneCardDAVStats *stats = (LinphoneCardDAVStats *)linphone_friend_list_cbs_get_user_data(list->cbs); + LinphoneCardDAVStats *stats = (LinphoneCardDAVStats *)linphone_friend_list_cbs_get_user_data(linphone_friend_list_get_callbacks(list)); BC_ASSERT_STRING_EQUAL(linphone_vcard_get_full_name(linphone_friend_get_vcard(new_friend)), linphone_vcard_get_full_name(linphone_friend_get_vcard(old_friend))); stats->updated_contact_count++; } static void carddav_sync_status_changed(LinphoneFriendList *list, LinphoneFriendListSyncStatus status, const char *msg) { - LinphoneCardDAVStats *stats = (LinphoneCardDAVStats *)linphone_friend_list_cbs_get_user_data(list->cbs); + LinphoneCardDAVStats *stats = (LinphoneCardDAVStats *)linphone_friend_list_cbs_get_user_data(linphone_friend_list_get_callbacks(list)); char *state = status == LinphoneFriendListSyncStarted ? "Sync started" : (status == LinphoneFriendListSyncFailure ? "Sync failure" : "Sync successful"); ms_message("[CardDAV] %s : %s", state, msg); if (status == LinphoneFriendListSyncFailure || status == LinphoneFriendListSyncSuccessful) { @@ -736,7 +736,7 @@ static void carddav_sync_status_changed(LinphoneFriendList *list, LinphoneFriend static void carddav_integration(void) { LinphoneCoreManager *manager = linphone_core_manager_new2("carddav_rc", FALSE); LinphoneFriendList *lfl = linphone_core_create_friend_list(manager->lc); - LinphoneVcard *lvc = linphone_vcard_context_get_vcard_from_buffer(manager->lc->vcard_context, "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Margaux Clerc\r\nIMPP;TYPE=work:sip:margaux@sip.linphone.org\r\nEND:VCARD\r\n"); + LinphoneVcard *lvc = linphone_vcard_context_get_vcard_from_buffer(linphone_core_get_vcard_context(manager->lc), "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Margaux Clerc\r\nIMPP;TYPE=work:sip:margaux@sip.linphone.org\r\nEND:VCARD\r\n"); LinphoneFriend *lf = linphone_friend_new_from_vcard(lvc); LinphoneVcard *lvc2 = NULL; LinphoneFriend *lf2 = NULL; @@ -757,34 +757,34 @@ static void carddav_integration(void) { linphone_core_add_friend_list(manager->lc, lfl); BC_ASSERT_PTR_NULL(linphone_vcard_get_uid(lvc)); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(lfl->dirty_friends_to_update), 0, unsigned int, "%u"); + BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_friend_list_get_dirty_friends_to_update(lfl)), 0, unsigned int, "%u"); BC_ASSERT_EQUAL(linphone_friend_list_add_friend(lfl, lf), LinphoneFriendListOK, int, "%d"); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(lfl->dirty_friends_to_update), 1, unsigned int, "%u"); + BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_friend_list_get_dirty_friends_to_update(lfl)), 1, unsigned int, "%u"); wait_for_until(manager->lc, NULL, &stats->sync_done_count, 1, CARDDAV_SYNC_TIMEOUT); BC_ASSERT_EQUAL(stats->sync_done_count, 1, int, "%i"); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(lfl->dirty_friends_to_update), 0, unsigned int, "%u"); + BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_friend_list_get_dirty_friends_to_update(lfl)), 0, unsigned int, "%u"); BC_ASSERT_PTR_NOT_NULL(linphone_vcard_get_uid(lvc)); linphone_friend_list_remove_friend(lfl, lf); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(lfl->friends), 0, unsigned int, "%u"); + BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_friend_list_get_friends(lfl)), 0, unsigned int, "%u"); wait_for_until(manager->lc, NULL, &stats->sync_done_count, 2, CARDDAV_SYNC_TIMEOUT); BC_ASSERT_EQUAL(stats->sync_done_count, 2, int, "%i"); linphone_friend_unref(lf); lf = NULL; - lvc = linphone_vcard_context_get_vcard_from_buffer(manager->lc->vcard_context, "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Ghislain Mary\r\nIMPP;TYPE=work:sip:ghislain@sip.linphone.org\r\nEND:VCARD\r\n"); + lvc = linphone_vcard_context_get_vcard_from_buffer(linphone_core_get_vcard_context(manager->lc), "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Ghislain Mary\r\nIMPP;TYPE=work:sip:ghislain@sip.linphone.org\r\nEND:VCARD\r\n"); lf = linphone_friend_new_from_vcard(lvc); linphone_vcard_unref(lvc); BC_ASSERT_EQUAL(linphone_friend_list_add_local_friend(lfl, lf), LinphoneFriendListOK, int, "%d"); linphone_friend_unref(lf); - lvc2 = linphone_vcard_context_get_vcard_from_buffer(manager->lc->vcard_context, "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Sylvain Berfini\r\nIMPP:sip:sberfini@sip.linphone.org\r\nUID:1f08dd48-29ac-4097-8e48-8596d7776283\r\nEND:VCARD\r\n"); + lvc2 = linphone_vcard_context_get_vcard_from_buffer(linphone_core_get_vcard_context(manager->lc), "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Sylvain Berfini\r\nIMPP:sip:sberfini@sip.linphone.org\r\nUID:1f08dd48-29ac-4097-8e48-8596d7776283\r\nEND:VCARD\r\n"); linphone_vcard_set_url(lvc2, "/card.php/addressbooks/tester/default/me.vcf"); lf2 = linphone_friend_new_from_vcard(lvc2); linphone_vcard_unref(lvc2); linphone_friend_set_ref_key(lf2, refkey); BC_ASSERT_EQUAL(linphone_friend_list_add_local_friend(lfl, lf2), LinphoneFriendListOK, int, "%d"); - BC_ASSERT_EQUAL(lfl->revision, 0, int, "%i"); + BC_ASSERT_EQUAL(linphone_friend_list_get_revision(lfl), 0, int, "%i"); linphone_friend_list_synchronize_friends_from_server(lfl); wait_for_until(manager->lc, NULL, &stats->new_contact_count, 0, CARDDAV_SYNC_TIMEOUT); BC_ASSERT_EQUAL(stats->new_contact_count, 0, int, "%i"); @@ -792,14 +792,14 @@ static void carddav_integration(void) { BC_ASSERT_EQUAL(stats->removed_contact_count, 1, int, "%i"); wait_for_until(manager->lc, NULL, &stats->updated_contact_count, 1, CARDDAV_SYNC_TIMEOUT); BC_ASSERT_EQUAL(stats->updated_contact_count, 1, int, "%i"); - BC_ASSERT_NOT_EQUAL(lfl->revision, 0, int, "%i"); + BC_ASSERT_NOT_EQUAL(linphone_friend_list_get_revision(lfl), 0, int, "%i"); wait_for_until(manager->lc, NULL, &stats->sync_done_count, 3, CARDDAV_SYNC_TIMEOUT); BC_ASSERT_EQUAL(stats->sync_done_count, 3, int, "%i"); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(lfl->friends), 1, unsigned int, "%u"); - lf = (LinphoneFriend *)lfl->friends->data; - BC_ASSERT_STRING_EQUAL(lf->refkey, refkey); - BC_ASSERT_EQUAL(lf->storage_id, lf2->storage_id, unsigned int, "%u"); + BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_friend_list_get_friends(lfl)), 1, unsigned int, "%u"); + lf = (LinphoneFriend *)bctbx_list_get_data((linphone_friend_list_get_friends(lfl))); + BC_ASSERT_STRING_EQUAL(linphone_friend_get_ref_key(lf), refkey); + BC_ASSERT_EQUAL(linphone_friend_get_storage_id(lf), linphone_friend_get_storage_id(lf2), unsigned int, "%u"); linphone_friend_unref(lf2); addr = linphone_friend_get_address(lf); BC_ASSERT_PTR_NOT_NULL(addr); @@ -810,13 +810,13 @@ static void carddav_integration(void) { linphone_friend_edit(lf); linphone_friend_done(lf); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(lf->friend_list->dirty_friends_to_update), 0, unsigned int, "%u"); + BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_friend_list_get_dirty_friends_to_update(linphone_friend_get_friend_list(lf))), 0, unsigned int, "%u"); linphone_core_set_network_reachable(manager->lc, FALSE); //To prevent the CardDAV update linphone_friend_edit(lf); linphone_friend_set_name(lf, "François Grisez"); linphone_friend_done(lf); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(lf->friend_list->dirty_friends_to_update), 1, unsigned int, "%u"); + BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_friend_list_get_dirty_friends_to_update(linphone_friend_get_friend_list(lf))), 1, unsigned int, "%u"); ms_free(stats); linphone_friend_list_unref(lfl); @@ -846,7 +846,7 @@ static void carddav_clean(void) { // This is to ensure the content of the test BC_ASSERT_EQUAL(stats->sync_done_count, 1, int, "%i"); stats->sync_done_count = 0; - friends = bctbx_list_copy(lfl->friends); + friends = bctbx_list_copy(linphone_friend_list_get_friends(lfl)); friends_iterator = friends; while (friends_iterator) { LinphoneFriend *lf = (LinphoneFriend *)friends_iterator->data; @@ -859,7 +859,7 @@ static void carddav_clean(void) { // This is to ensure the content of the test } bctbx_list_free(friends); - lvc = linphone_vcard_context_get_vcard_from_buffer(manager->lc->vcard_context, "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Sylvain Berfini\r\nIMPP:sip:sylvain@sip.linphone.org\r\nUID:1f08dd48-29ac-4097-8e48-8596d7776283\r\nEND:VCARD\r\n"); + lvc = linphone_vcard_context_get_vcard_from_buffer(linphone_core_get_vcard_context(manager->lc), "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Sylvain Berfini\r\nIMPP:sip:sylvain@sip.linphone.org\r\nUID:1f08dd48-29ac-4097-8e48-8596d7776283\r\nEND:VCARD\r\n"); linphone_vcard_set_url(lvc, "http://dav.linphone.org/card.php/addressbooks/tester/default/me.vcf"); lf = linphone_friend_new_from_vcard(lvc); linphone_vcard_unref(lvc); @@ -908,9 +908,9 @@ static void carddav_server_to_client_and_client_to_sever_sync(void) { LinphoneFriendList *lfl = linphone_core_create_friend_list(manager->lc); LinphoneFriendListCbs *cbs = linphone_friend_list_get_callbacks(lfl); LinphoneCardDAVStats *stats = (LinphoneCardDAVStats *)ms_new0(LinphoneCardDAVStats, 1); - LinphoneVcard *lvc1 = linphone_vcard_context_get_vcard_from_buffer(manager->lc->vcard_context, "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Margaux Clerc\r\nIMPP;TYPE=work:sip:margaux@sip.linphone.org\r\nEND:VCARD\r\n"); + LinphoneVcard *lvc1 = linphone_vcard_context_get_vcard_from_buffer(linphone_core_get_vcard_context(manager->lc), "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Margaux Clerc\r\nIMPP;TYPE=work:sip:margaux@sip.linphone.org\r\nEND:VCARD\r\n"); LinphoneFriend *lf1 = linphone_friend_new_from_vcard(lvc1); - LinphoneVcard *lvc2 = linphone_vcard_context_get_vcard_from_buffer(manager->lc->vcard_context, "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Ghislain Mary\r\nIMPP;TYPE=work:sip:ghislain@sip.linphone.org\r\nEND:VCARD\r\n"); + LinphoneVcard *lvc2 = linphone_vcard_context_get_vcard_from_buffer(linphone_core_get_vcard_context(manager->lc), "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:Ghislain Mary\r\nIMPP;TYPE=work:sip:ghislain@sip.linphone.org\r\nEND:VCARD\r\n"); LinphoneFriend *lf2 = linphone_friend_new_from_vcard(lvc2); bctbx_list_t *friends = NULL, *friends_iterator = NULL; @@ -933,7 +933,7 @@ static void carddav_server_to_client_and_client_to_sever_sync(void) { BC_ASSERT_EQUAL(stats->sync_done_count, 3, int, "%i"); stats->sync_done_count = 0; - friends = bctbx_list_copy(lfl->friends); + friends = bctbx_list_copy(linphone_friend_list_get_friends(lfl)); friends_iterator = friends; while (friends_iterator) { LinphoneFriend *lf = (LinphoneFriend *)friends_iterator->data; diff --git a/tester/video_tester.c b/tester/video_tester.c index 9bd720870..95cc03ef0 100644 --- a/tester/video_tester.c +++ b/tester/video_tester.c @@ -15,7 +15,6 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "private.h" #if defined(VIDEO_ENABLED) From a830806c16160f3c14713f437108b9e18394465b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Fri, 29 Sep 2017 15:31:22 +0200 Subject: [PATCH 0256/2215] Replace SalCustomBody by LinphonePrivate::Content --- coreapi/sal/call_op.cpp | 89 +++++++++++++++++++--------------- coreapi/sal/call_op.h | 7 +-- coreapi/sal/sal.c | 92 ------------------------------------ coreapi/sal/sal.h | 34 ------------- coreapi/sal/sal_op.cpp | 3 -- coreapi/sal/sal_op.h | 3 +- src/content/content-type.cpp | 12 ++++- src/content/content-type.h | 6 ++- src/content/content.cpp | 5 ++ src/content/content.h | 1 + 10 files changed, 77 insertions(+), 175 deletions(-) diff --git a/coreapi/sal/call_op.cpp b/coreapi/sal/call_op.cpp index aa7ecf193..83cc8e7a7 100644 --- a/coreapi/sal/call_op.cpp +++ b/coreapi/sal/call_op.cpp @@ -3,6 +3,7 @@ #include "offeranswer.h" #include #include +#include using namespace std; @@ -11,7 +12,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE int SalCallOp::set_local_media_description(SalMediaDescription *desc) { - if (this->custom_body) { + if (this->custom_body.getBody().size() > 0) { bctbx_error("cannot set local media description on SalOp [%p] because a custom body is already set", this); return -1; } @@ -32,13 +33,21 @@ int SalCallOp::set_local_media_description(SalMediaDescription *desc) { return 0; } -int SalCallOp::set_local_custom_body(SalCustomBody *body) { +int SalCallOp::set_local_custom_body(const Content &body) { if (this->local_media) { bctbx_error("cannot set custom body on SalOp [%p] because a local media description is already set", this); return -1; } - if (this->custom_body) sal_custom_body_unref(this->custom_body); - this->custom_body = sal_custom_body_ref(body ? body : NULL); + this->custom_body = body; + return 0; +} + +int SalCallOp::set_local_custom_body(const Content &&body) { + if (this->local_media) { + bctbx_error("cannot set custom body on SalOp [%p] because a local media description is already set", this); + return -1; + } + this->custom_body = body; return 0; } @@ -50,24 +59,31 @@ belle_sip_header_allow_t *SalCallOp::create_allow(bool_t enable_update) { return header_allow; } -int SalCallOp::set_custom_body(belle_sip_message_t *msg, const SalCustomBody *body) { - if (body->data_length > SIP_MESSAGE_BODY_LIMIT) { +int SalCallOp::set_custom_body(belle_sip_message_t *msg, const Content &body) { + ContentType contentType = body.getContentType(); + size_t bodySize = body.getBody().size(); + + if (bodySize > SIP_MESSAGE_BODY_LIMIT) { bctbx_error("trying to add a body greater than %dkB to message [%p]", SIP_MESSAGE_BODY_LIMIT/1024, msg); return -1; } - if (body->data_length == 0 || body->raw_data == NULL) { + if (bodySize == 0) { bctbx_error("trying to add an empty custom body to message [%p]", msg); return -1; } + if (!contentType.isValid()) { + bctbx_error("trying to add a custom body with an invalid content type to message [%p]", msg); + return -1; + } - belle_sip_header_content_type_t *content_type = belle_sip_header_content_type_create(body->type->type, body->type->subtype); - belle_sip_header_content_length_t *content_length = belle_sip_header_content_length_create(body->data_length); + belle_sip_header_content_type_t *content_type = belle_sip_header_content_type_create(contentType.getType().c_str(), contentType.getSubType().c_str()); + belle_sip_header_content_length_t *content_length = belle_sip_header_content_length_create(bodySize); belle_sip_message_add_header(msg, BELLE_SIP_HEADER(content_type)); belle_sip_message_add_header(msg, BELLE_SIP_HEADER(content_length)); - char *buffer = bctbx_new(char, body->data_length); - memcpy(buffer, body->raw_data, body->data_length); - belle_sip_message_assign_body(msg, buffer, body->data_length); + char *buffer = bctbx_new(char, bodySize); + memcpy(buffer, body.getBody().data(), bodySize); + belle_sip_message_assign_body(msg, buffer, bodySize); return 0; } @@ -75,31 +91,32 @@ int SalCallOp::set_custom_body(belle_sip_message_t *msg, const SalCustomBody *bo int SalCallOp::set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* session_desc) { belle_sip_error_code error = BELLE_SIP_BUFFER_OVERFLOW; size_t length = 0; + size_t bufLen = 2048; if (session_desc == NULL) return -1; - size_t bufLen = 2048; - char *buff = reinterpret_cast(belle_sip_malloc(bufLen)); + vector buff(bufLen); /* try to marshal the description. This could go higher than 2k so we iterate */ - while( error != BELLE_SIP_OK && bufLen <= SIP_MESSAGE_BODY_LIMIT && buff != NULL){ - error = belle_sip_object_marshal(BELLE_SIP_OBJECT(session_desc),buff,bufLen,&length); + while( error != BELLE_SIP_OK && bufLen <= SIP_MESSAGE_BODY_LIMIT) { + error = belle_sip_object_marshal(BELLE_SIP_OBJECT(session_desc),buff.data(),bufLen,&length); if( error != BELLE_SIP_OK ){ bufLen *= 2; length = 0; - buff = reinterpret_cast(belle_sip_realloc(buff,bufLen)); + buff.resize(bufLen); } } /* give up if hard limit reached */ - if (error != BELLE_SIP_OK || buff == NULL) { + if (error != BELLE_SIP_OK) { ms_error("Buffer too small (%d) or not enough memory, giving up SDP", (int)bufLen); return -1; } + buff.resize(length); - SalMimeType *mimetype = sal_mime_type_new("application", "sdp"); - SalCustomBody *body = sal_custom_body_new_with_buffer_moving(mimetype, buff, length); + Content body; + body.setContentType("application/sdp"); + body.setBody(move(buff)); set_custom_body(msg, body); - sal_custom_body_unref(body); return 0; } @@ -124,7 +141,7 @@ void SalCallOp::fill_invite(belle_sip_request_t* invite) { this->sdp_offering=TRUE; set_sdp_from_desc(BELLE_SIP_MESSAGE(invite),this->local_media); } else this->sdp_offering=FALSE; - if (this->custom_body) { + if (this->custom_body.getBody().size() > 0) { set_custom_body(BELLE_SIP_MESSAGE(invite), this->custom_body); } } @@ -165,16 +182,17 @@ void SalCallOp::cancelling_invite(const SalErrorInfo *info) { this->state=State::Terminating; } -SalCustomBody *SalCallOp::extract_body(belle_sip_message_t *message) { - const char *body_str = belle_sip_message_get_body(message); +Content SalCallOp::extract_body(belle_sip_message_t *message) { + Content body; belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(message, belle_sip_header_content_type_t); belle_sip_header_content_length_t *content_length = belle_sip_message_get_header_by_type(message, belle_sip_header_content_length_t); - if (!(body_str && content_type && content_length)) return NULL; - const char *type_str = belle_sip_header_content_type_get_type(content_type); - const char *subtype_str = belle_sip_header_content_type_get_subtype(content_type); - size_t length = belle_sip_header_content_length_get_content_length(content_length); - SalMimeType *mime_type = sal_mime_type_new(type_str, subtype_str); - SalCustomBody *body = sal_custom_body_new_with_buffer_copy(mime_type, body_str, length); + const char *type_str = content_type ? belle_sip_header_content_type_get_type(content_type) : NULL; + const char *subtype_str = content_type ? belle_sip_header_content_type_get_subtype(content_type) : NULL; + size_t length = content_length ? belle_sip_header_content_length_get_content_length(content_length) : 0; + const char *body_str = belle_sip_message_get_body(message); + + if (type_str && subtype_str) body.setContentType(ContentType(type_str, subtype_str)); + if (length > 0 && body_str) body.setBody(body_str, length); return body; } @@ -193,18 +211,13 @@ int SalCallOp::extract_sdp(belle_sip_message_t* message,belle_sdp_session_descri return 0; } - SalCustomBody *body = extract_body(message); - if (body == NULL) return 0; - - if (strcmp("application", body->type->type) != 0 || strcmp("sdp", body->type->subtype) != 0) { - sal_custom_body_unref(body); + Content body = extract_body(message); + if (body.getContentType() != "application/sdp") { *error = SalReasonUnsupportedContent; return -1; } - *session_desc = belle_sdp_session_description_parse(string(body->raw_data, body->data_length).c_str()); - sal_custom_body_unref(body); - + *session_desc = belle_sdp_session_description_parse(body.getBodyAsString().c_str()); if (*session_desc == NULL) { ms_error("Failed to parse SDP message."); *error = SalReasonNotAcceptable; diff --git a/coreapi/sal/call_op.h b/coreapi/sal/call_op.h index 2f773ae83..a8a5616bf 100644 --- a/coreapi/sal/call_op.h +++ b/coreapi/sal/call_op.h @@ -30,7 +30,8 @@ public: SalCallOp(Sal *sal): SalOp(sal) {} int set_local_media_description(SalMediaDescription *desc); - int set_local_custom_body(SalCustomBody *body); + int set_local_custom_body(const Content &body); + int set_local_custom_body(const Content &&bdoy); SalMediaDescription *get_remote_media_description() {return this->remote_media;} SalMediaDescription *get_final_media_description(); @@ -67,13 +68,13 @@ public: private: static belle_sip_header_allow_t *create_allow(bool_t enable_update); - static int set_custom_body(belle_sip_message_t *msg, const SalCustomBody *body); + static int set_custom_body(belle_sip_message_t *msg, const Content &body); static int set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* session_desc); static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription *desc); void set_released(); static void process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event); void cancelling_invite(const SalErrorInfo *info); - static SalCustomBody *extract_body(belle_sip_message_t *message); + static Content extract_body(belle_sip_message_t *message); int extract_sdp(belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error); static void set_addr_to_0000(char value[], size_t sz); void sdp_process(); diff --git a/coreapi/sal/sal.c b/coreapi/sal/sal.c index 4dee10831..2ed838a4e 100644 --- a/coreapi/sal/sal.c +++ b/coreapi/sal/sal.c @@ -174,98 +174,6 @@ int sal_media_description_get_nb_active_streams(const SalMediaDescription *md) { return nb; } -SalMimeType *sal_mime_type_new(const char *type, const char *subtype) { - SalMimeType *mime_type = bctbx_new0(SalMimeType, 1); - if (type) mime_type->type = bctbx_strdup(type); - if (subtype) mime_type->subtype = bctbx_strdup(subtype); - return mime_type; -} - -SalMimeType *sal_mime_type_copy(const SalMimeType *mime_type) { - SalMimeType *new_mime_type = bctbx_new0(SalMimeType, 1); - if (mime_type->type) new_mime_type->type = bctbx_strdup(mime_type->type); - if (mime_type->subtype) new_mime_type->subtype = bctbx_strdup(mime_type->subtype); - return new_mime_type; -} - -SalMimeType *sal_mime_type_ref(SalMimeType *mime_type) { - if (!mime_type) return NULL; - mime_type->ref++; - return mime_type; -} - -void sal_mime_type_unref(SalMimeType *mime_type) { - mime_type->ref--; - if (mime_type->ref <= 0) { - if (mime_type->type) bctbx_free(mime_type->type); - if (mime_type->subtype) bctbx_free(mime_type->subtype); - } - bctbx_free(mime_type); -} - -SalCustomBody *sal_custom_body_new(SalMimeType *type) { - if (type == NULL) { - bctbx_error("creating a SalCustomBody from NULL SalMimeType"); - return NULL; - } - SalCustomBody *body = bctbx_new0(SalCustomBody, 1); - body->type = sal_mime_type_ref(type); - return body; -} - -SalCustomBody *sal_custom_body_new_with_buffer_copy(SalMimeType *type, const char *raw_data, size_t data_length) { - SalCustomBody *body = sal_custom_body_new(type); - if (body == NULL) return NULL; - body->data_length = data_length; - if (data_length > 0 && raw_data) { - body->raw_data = bctbx_new(char, data_length); - memcpy(body->raw_data, raw_data, data_length); - } - return body; -} - -SalCustomBody *sal_custom_body_new_with_buffer_moving(SalMimeType *type, char *raw_data, size_t data_length) { - SalCustomBody *body = sal_custom_body_new(type); - if (body == NULL) return NULL; - sal_custom_body_set_buffer_by_moving(body, raw_data, data_length); - return body; -} - -SalCustomBody *sal_custom_body_ref(SalCustomBody *body) { - if (!body) return NULL; - body->ref++; - return body; -} - -void sal_custom_body_unref(SalCustomBody *body) { - body->ref--; - if (body->ref <= 0) { - if (body->type) sal_mime_type_unref(body->type); - if (body->raw_data) bctbx_free(body->raw_data); - } - bctbx_free(body); -} - -void sal_custom_body_set_buffer_by_copy(SalCustomBody *body, const char *buffer, size_t length) { - char *buff_copy = NULL; - if (buffer && length > 0) { - buff_copy = bctbx_new(char, length); - memcpy(buff_copy, buffer, length); - } else length = 0; - sal_custom_body_set_buffer_by_moving(body, buff_copy, length); -} - -void sal_custom_body_set_buffer_by_moving(SalCustomBody *body, char *buffer, size_t length) { - if (body->raw_data) bctbx_free(body->raw_data); - if (length > 0 && buffer) { - body->raw_data = buffer; - body->data_length = length; - } else { - body->raw_data = NULL; - body->data_length = length; - } -} - static bool_t is_null_address(const char *addr){ return strcmp(addr,"0.0.0.0")==0 || strcmp(addr,"::0")==0; } diff --git a/coreapi/sal/sal.h b/coreapi/sal/sal.h index e45e170cf..37ca7f84e 100644 --- a/coreapi/sal/sal.h +++ b/coreapi/sal/sal.h @@ -362,40 +362,6 @@ int sal_media_description_get_nb_active_streams(const SalMediaDescription *md); } #endif -typedef struct _SalMimeType { - int ref; - char *type; - char *subtype; -} SalMimeType; - -typedef struct _SalCustomBody { - int ref; - SalMimeType *type; - size_t data_length; - char *raw_data; -} SalCustomBody; - -#ifdef __cplusplus -extern "C" { -#endif - -SalMimeType *sal_mime_type_new(const char *type, const char *subtype); -SalMimeType *sal_mime_type_copy(const SalMimeType *mime_type); -SalMimeType *sal_mime_type_ref(SalMimeType *mime_type); -void sal_mime_type_unref(SalMimeType *mime_type); - -SalCustomBody *sal_custom_body_new(SalMimeType *type); -SalCustomBody *sal_custom_body_new_with_buffer_copy(SalMimeType *type, const char *raw_data, size_t data_length); -SalCustomBody *sal_custom_body_new_with_buffer_moving(SalMimeType *type, char *raw_data, size_t data_length); -SalCustomBody *sal_custom_body_ref(SalCustomBody *body); -void sal_custom_body_unref(SalCustomBody *body); -void sal_custom_body_set_buffer_by_copy(SalCustomBody *body, const char *buffer, size_t length); -void sal_custom_body_set_buffer_by_moving(SalCustomBody *body, char *buffer, size_t length); - -#ifdef __cplusplus -} -#endif - typedef enum SalReason{ SalReasonNone, /*no error, please leave first so that it takes 0 value*/ diff --git a/coreapi/sal/sal_op.cpp b/coreapi/sal/sal_op.cpp index e2fa78e09..a72cae041 100644 --- a/coreapi/sal/sal_op.cpp +++ b/coreapi/sal/sal_op.cpp @@ -95,9 +95,6 @@ SalOp::~SalOp() { sal_media_description_unref(this->local_media); if (this->remote_media) sal_media_description_unref(this->remote_media); - if (this->custom_body) { - sal_custom_body_unref(this->custom_body); - } if (this->call_id) ms_free((void *)this->call_id); if (this->service_route) { diff --git a/coreapi/sal/sal_op.h b/coreapi/sal/sal_op.h index 1a58b2b43..d30b3b4d8 100644 --- a/coreapi/sal/sal_op.h +++ b/coreapi/sal/sal_op.h @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include "sal.h" #include "sal.hpp" +#include "content/content.h" LINPHONE_BEGIN_NAMESPACE @@ -208,7 +209,7 @@ protected: char *remote_contact = NULL; SalMediaDescription *local_media = NULL; SalMediaDescription *remote_media = NULL; - SalCustomBody *custom_body = NULL; + Content custom_body; void *user_pointer = NULL; const char* call_id = NULL; char* realm = NULL; diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index 1605d6eed..8df3a234b 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -66,14 +66,22 @@ ContentType &ContentType::operator= (const ContentType &src) { return *this; } -bool ContentType::operator== (const ContentType &contentType) { +bool ContentType::operator== (const ContentType &contentType) const { return getType() == contentType.getType() && getSubType() == contentType.getSubType(); } -bool ContentType::operator== (const string &contentType) { +bool ContentType::operator== (const string &contentType) const { return *this == ContentType(contentType); } +bool ContentType::operator!= (const ContentType &contentType) const { + return !(*this == contentType); +} + +bool ContentType::operator!= (const std::string &contentType) const { + return !(*this == contentType); +} + const string &ContentType::getType () const { L_D(); return d->type; diff --git a/src/content/content-type.h b/src/content/content-type.h index c78d75c33..8e3851cbf 100644 --- a/src/content/content-type.h +++ b/src/content/content-type.h @@ -35,8 +35,10 @@ public: ContentType &operator= (const ContentType &src); - bool operator== (const ContentType &contentType); - bool operator== (const std::string &contentType); + bool operator== (const ContentType &contentType) const; + bool operator== (const std::string &contentType) const; + bool operator!= (const ContentType &contentType) const; + bool operator!= (const std::string &contentType) const; bool isValid () const; diff --git a/src/content/content.cpp b/src/content/content.cpp index 8b055e6ba..23b56f3cb 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -107,6 +107,11 @@ void Content::setBody (const vector &body) { d->body = body; } +void Content::setBody (const std::vector &&body) { + L_D(); + d->body = body; +} + void Content::setBody (const string &body) { L_D(); d->body = vector(body.cbegin(), body.cend()); diff --git a/src/content/content.h b/src/content/content.h index f25b0d783..62b5cbe20 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -49,6 +49,7 @@ public: const std::vector &getBody () const; std::string getBodyAsString () const; void setBody (const std::vector &body); + void setBody (const std::vector &&body); void setBody (const std::string &body); void setBody (const void *buffer, size_t size); size_t getSize () const; From e7f7abd7ae8747310b442cbe018b7e80f38ca32d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Fri, 29 Sep 2017 18:03:58 +0200 Subject: [PATCH 0257/2215] Fix complation of complex_sip_case_tester.c --- coreapi/sal/sal.cpp | 4 ++++ coreapi/tester_utils.h | 2 ++ tester/complex_sip_case_tester.c | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/coreapi/sal/sal.cpp b/coreapi/sal/sal.cpp index 200ca30ad..20a859df1 100644 --- a/coreapi/sal/sal.cpp +++ b/coreapi/sal/sal.cpp @@ -973,4 +973,8 @@ SalMediaDescription * sal_call_get_final_media_description(SalOp *h) { return callOp->get_final_media_description(); } +belle_sip_resolver_context_t *sal_resolve_a(Sal *sal, const char *name, int port, int family, belle_sip_resolver_callback_t cb, void *data) { + return sal->resolve_a(name, port, family, cb, data); +} + } diff --git a/coreapi/tester_utils.h b/coreapi/tester_utils.h index 26ac68756..720e299d0 100644 --- a/coreapi/tester_utils.h +++ b/coreapi/tester_utils.h @@ -143,6 +143,8 @@ LINPHONE_PUBLIC const SalErrorInfo *sal_op_get_error_info(const SalOp *op); LINPHONE_PUBLIC bool_t sal_call_dialog_request_pending(const SalOp *op); LINPHONE_PUBLIC void sal_call_set_sdp_handling(SalOp *h, SalOpSDPHandling handling); LINPHONE_PUBLIC SalMediaDescription * sal_call_get_final_media_description(SalOp *h); + +LINPHONE_PUBLIC belle_sip_resolver_context_t *sal_resolve_a(Sal *sal, const char *name, int port, int family, belle_sip_resolver_callback_t cb, void *data); #endif #ifdef __cplusplus diff --git a/tester/complex_sip_case_tester.c b/tester/complex_sip_case_tester.c index 2a572acdb..a0a9fe1e5 100644 --- a/tester/complex_sip_case_tester.c +++ b/tester/complex_sip_case_tester.c @@ -100,7 +100,7 @@ LinphoneAddress * linphone_core_manager_resolve(LinphoneCoreManager *mgr, const int port = linphone_address_get_port(source); LinphoneAddress * dest; - sal_resolve_a( mgr->lc->sal + sal_resolve_a(linphone_core_get_sal(mgr->lc) ,linphone_address_get_domain(source) ,linphone_address_get_port(source) ,AF_INET From 72bc4fec53d885516358b0574c57e88f502112f7 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 29 Sep 2017 18:01:47 +0200 Subject: [PATCH 0258/2215] Moved most of exisiting code from LinphoneChatMessage* to shared_ptr --- coreapi/chat_file_transfer.c | 2 +- include/linphone/api/c-chat-message.h | 8 +- src/c-wrapper/api/c-chat-message.cpp | 22 +- src/c-wrapper/api/c-chat-room.cpp | 23 +- src/chat/chat-message-p.h | 15 +- src/chat/chat-message.cpp | 89 ++-- src/chat/chat-message.h | 20 +- src/chat/chat-room-p.h | 34 +- src/chat/chat-room.cpp | 427 +++++++++--------- src/chat/chat-room.h | 19 +- src/chat/imdn.cpp | 11 +- src/chat/imdn.h | 4 +- src/chat/modifier/chat-message-modifier.h | 2 + .../modifier/cpim-chat-message-modifier.cpp | 7 +- .../multipart-chat-message-modifier.cpp | 3 +- src/chat/real-time-text-chat-room-p.h | 2 +- src/chat/real-time-text-chat-room.cpp | 30 +- src/chat/real-time-text-chat-room.h | 2 +- 18 files changed, 370 insertions(+), 350 deletions(-) diff --git a/coreapi/chat_file_transfer.c b/coreapi/chat_file_transfer.c index 79f22ce47..7eab33106 100644 --- a/coreapi/chat_file_transfer.c +++ b/coreapi/chat_file_transfer.c @@ -29,5 +29,5 @@ #include "chat/chat-room.h" LinphoneChatMessage *linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent *initial_content) { - return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createFileTransferMessage(initial_content); + return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createFileTransferMessage(initial_content)); } diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index b62cde920..011427cd2 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -126,7 +126,7 @@ LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_to_address(Linp * @param[in] message LinphoneChatMessage object * @return The content type of the chat message */ -LINPHONE_PUBLIC const char * linphone_chat_message_get_content_type(const LinphoneChatMessage *msg); +LINPHONE_PUBLIC const char * linphone_chat_message_get_content_type(LinphoneChatMessage *msg); /** * Set the content type of a chat message. @@ -140,7 +140,7 @@ LINPHONE_PUBLIC void linphone_chat_message_set_content_type(LinphoneChatMessage * Get text part of this message * @return text or NULL if no text. */ -LINPHONE_PUBLIC const char* linphone_chat_message_get_text(const LinphoneChatMessage* msg); +LINPHONE_PUBLIC const char* linphone_chat_message_get_text(LinphoneChatMessage* msg); /** * Returns the id used to identify this message in the storage database @@ -235,14 +235,14 @@ LINPHONE_PUBLIC LinphoneContent* linphone_chat_message_get_file_transfer_informa * @param[in] message LinphoneChatMessage object * @return Whether or not the message is a file tranfer */ -LINPHONE_PUBLIC bool_t linphone_chat_message_is_file_transfer(const LinphoneChatMessage *message); +LINPHONE_PUBLIC bool_t linphone_chat_message_is_file_transfer(LinphoneChatMessage *message); /** * Return whether or not a chat message is a text. * @param[in] message LinphoneChatMessage object * @return Whether or not the message is a text */ -LINPHONE_PUBLIC bool_t linphone_chat_message_is_text(const LinphoneChatMessage *message); +LINPHONE_PUBLIC bool_t linphone_chat_message_is_text(LinphoneChatMessage *message); /** * Get if a chat message is to be stored. diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 1f66d709a..4206aefee 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -173,26 +173,28 @@ void linphone_chat_message_set_appdata(LinphoneChatMessage *msg, const char *dat } void linphone_chat_message_set_from_address(LinphoneChatMessage *msg, const LinphoneAddress *from) { - if (!from) L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFromAddress(nullptr); - else L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFromAddress(make_shared(linphone_address_as_string(from))); + LinphonePrivate::Address addr; + if (from) addr = LinphonePrivate::Address(linphone_address_as_string(from)); + else L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFromAddress(addr); } const LinphoneAddress *linphone_chat_message_get_from_address(LinphoneChatMessage *msg) { if (msg->from) linphone_address_unref(msg->from); - msg->from = linphone_address_new(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFromAddress()->asString().c_str()); + msg->from = linphone_address_new(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFromAddress().asString().c_str()); return msg->from; } void linphone_chat_message_set_to_address(LinphoneChatMessage *msg, const LinphoneAddress *to) { - if (!to) L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setToAddress(nullptr); - else L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setToAddress(make_shared(linphone_address_as_string(to))); + LinphonePrivate::Address addr; + if (to) addr = LinphonePrivate::Address(linphone_address_as_string(to)); + else L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setToAddress(addr); } const LinphoneAddress *linphone_chat_message_get_to_address(LinphoneChatMessage *msg) { if (msg->to) linphone_address_unref(msg->to); - msg->to = linphone_address_new(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getToAddress()->asString().c_str()); + msg->to = linphone_address_new(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getToAddress().asString().c_str()); return msg->to; } @@ -325,7 +327,7 @@ void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChat // Structure has changed, hard to keep the behavior // ============================================================================= -const char * linphone_chat_message_get_content_type(const LinphoneChatMessage *msg) { +const char * linphone_chat_message_get_content_type(LinphoneChatMessage *msg) { return L_STRING_TO_C(L_GET_PRIVATE_FROM_C_OBJECT(msg)->getContentType()); } @@ -333,7 +335,7 @@ void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char L_GET_PRIVATE_FROM_C_OBJECT(msg)->setContentType(L_C_TO_STRING(content_type)); } -const char *linphone_chat_message_get_text(const LinphoneChatMessage *msg) { +const char *linphone_chat_message_get_text(LinphoneChatMessage *msg) { return L_STRING_TO_C(L_GET_PRIVATE_FROM_C_OBJECT(msg)->getText()); } @@ -369,11 +371,11 @@ LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage *msg) { return linphone_error_info_get_reason(linphone_chat_message_get_error_info(msg)); } -bool_t linphone_chat_message_is_file_transfer(const LinphoneChatMessage *msg) { +bool_t linphone_chat_message_is_file_transfer(LinphoneChatMessage *msg) { return LinphonePrivate::ContentType::isFileTransfer(linphone_chat_message_get_content_type(msg)); } -bool_t linphone_chat_message_is_text(const LinphoneChatMessage *msg) { +bool_t linphone_chat_message_is_text(LinphoneChatMessage *msg) { return LinphonePrivate::ContentType::isText(linphone_chat_message_get_content_type(msg)); } diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index dc4bd45d1..1b78fd9e8 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -68,12 +68,11 @@ void linphone_chat_room_release (LinphoneChatRoom *cr) { } void linphone_chat_room_remove_transient_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) { - L_GET_PRIVATE_FROM_C_OBJECT(cr)->removeTransientMessage(msg); + L_GET_PRIVATE_FROM_C_OBJECT(cr)->removeTransientMessage(L_GET_CPP_PTR_FROM_C_OBJECT(msg)); } void linphone_chat_room_send_message (LinphoneChatRoom *cr, const char *msg) { - LinphoneChatMessage *message = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createMessage(msg); - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(message); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createMessage(msg)); } bool_t linphone_chat_room_is_remote_composing (const LinphoneChatRoom *cr) { @@ -97,7 +96,7 @@ const LinphoneAddress *linphone_chat_room_get_peer_address (LinphoneChatRoom *cr } LinphoneChatMessage *linphone_chat_room_create_message (LinphoneChatRoom *cr, const char *message) { - return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createMessage(L_C_TO_STRING(message)); + return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createMessage(L_C_TO_STRING(message))); } LinphoneChatMessage *linphone_chat_room_create_message_2 ( @@ -135,16 +134,16 @@ void linphone_chat_room_send_message2 ( ) { linphone_chat_message_set_message_state_changed_cb(msg, status_cb); linphone_chat_message_set_message_state_changed_cb_user_data(msg, ud); - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(msg); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(L_GET_CPP_PTR_FROM_C_OBJECT(msg)); } void linphone_chat_room_send_chat_message_2 (LinphoneChatRoom *cr, LinphoneChatMessage *msg) { linphone_chat_message_ref(msg); - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(msg); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(L_GET_CPP_PTR_FROM_C_OBJECT(msg)); } void linphone_chat_room_send_chat_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) { - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(msg); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(L_GET_CPP_PTR_FROM_C_OBJECT(msg)); } uint32_t linphone_chat_room_get_char (const LinphoneChatRoom *cr) { @@ -169,7 +168,7 @@ void linphone_chat_room_set_call (LinphoneChatRoom *cr, LinphoneCall *call) { } bctbx_list_t *linphone_chat_room_get_transient_messages (const LinphoneChatRoom *cr) { - return L_GET_C_LIST_FROM_CPP_LIST(L_GET_PRIVATE_FROM_C_OBJECT(cr)->getTransientMessages()); + return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_PRIVATE_FROM_C_OBJECT(cr)->getTransientMessages()); } void linphone_chat_room_mark_as_read (LinphoneChatRoom *cr) { @@ -185,7 +184,7 @@ int linphone_chat_room_get_history_size (LinphoneChatRoom *cr) { } void linphone_chat_room_delete_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) { - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->deleteMessage(msg); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->deleteMessage(L_GET_CPP_PTR_FROM_C_OBJECT(msg)); } void linphone_chat_room_delete_history (LinphoneChatRoom *cr) { @@ -193,15 +192,15 @@ void linphone_chat_room_delete_history (LinphoneChatRoom *cr) { } bctbx_list_t *linphone_chat_room_get_history_range (LinphoneChatRoom *cr, int startm, int endm) { - return L_GET_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistoryRange(startm, endm)); + return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistoryRange(startm, endm)); } bctbx_list_t *linphone_chat_room_get_history (LinphoneChatRoom *cr, int nb_message) { - return L_GET_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistory(nb_message)); + return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistory(nb_message)); } LinphoneChatMessage *linphone_chat_room_find_message (LinphoneChatRoom *cr, const char *message_id) { - return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findMessage(message_id); + return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findMessage(message_id)); } LinphoneChatRoomCbs *linphone_chat_room_get_callbacks (const LinphoneChatRoom *cr) { diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index eb9a3d74c..3988857ff 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -65,10 +65,10 @@ public: // Methods only used for C wrapper // ----------------------------------------------------------------------------- - const std::string& getContentType() const; + const std::string& getContentType(); void setContentType(const std::string& contentType); - const std::string& getText() const; + const std::string& getText(); void setText(const std::string& text); LinphoneContent * getFileTransferInformation() const; @@ -98,11 +98,11 @@ public: private: std::shared_ptr chatRoom; - ChatMessage::Direction direction = ChatMessage::Incoming; - ChatMessage::State state = ChatMessage::Idle; + ChatMessage::Direction direction = ChatMessage::Direction::Incoming; + ChatMessage::State state = ChatMessage::State::Idle; unsigned int storageId = 0; - std::shared_ptr
    from; - std::shared_ptr
    to; + Address from; + Address to; time_t time = 0; std::string id = ""; std::string appData = ""; @@ -122,9 +122,10 @@ private: SalOp *salOp = NULL; SalCustomHeader *salCustomHeaders = NULL; unsigned long backgroundTaskId; - // Used for compatibility with previous C API + // Cache for returned values, used for compatibility with previous C API std::string cContentType = ""; std::string cText = ""; + // Used for compatibility with previous C API LinphoneContent *cFileTransferInformation = NULL; // ----------------------------------------------------------------------------- diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 9235b0e7b..d3bc1b039 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -22,11 +22,11 @@ #include "linphone/core.h" #include "linphone/lpconfig.h" #include "c-wrapper/c-wrapper.h" +#include "address/address.h" #include "chat-message-p.h" -#include "chat-message.h" -#include "content/content.h" +#include "content/content.h" #include "modifier/multipart-chat-message-modifier.h" #include "modifier/cpim-chat-message-modifier.h" #include "chat-room-p.h" @@ -133,20 +133,33 @@ string ChatMessagePrivate::getSalCustomHeaderValue(const string& name) { // ----------------------------------------------------------------------------- -const string& ChatMessagePrivate::getContentType() const { +const string& ChatMessagePrivate::getContentType() { + if (internalContent) { + ContentType contentType = internalContent->getContentType(); + cContentType = contentType.asString(); + } return cContentType; } void ChatMessagePrivate::setContentType(const string& contentType) { - cContentType = contentType; + if (!internalContent) { + internalContent = make_shared(); + } + internalContent->setContentType(contentType); } -const string& ChatMessagePrivate::getText() const { +const string& ChatMessagePrivate::getText() { + if (internalContent) { + cText = internalContent->getBodyAsString(); + } return cText; } void ChatMessagePrivate::setText(const string& text) { - cText = text; + if (!internalContent) { + internalContent = make_shared(); + } + internalContent->setBody(text); } LinphoneContent * ChatMessagePrivate::getFileTransferInformation() const { @@ -464,7 +477,7 @@ void ChatMessagePrivate::onRecvBody(belle_sip_user_body_handler_t *bh, belle_sip } } else { ms_warning("File transfer decrypt failed with code %d", (int)retval); - setState(ChatMessage::FileTransferError); + setState(ChatMessage::State::FileTransferError); } return; @@ -654,22 +667,22 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e } xmlFreeDoc(xmlMessageBody); } else { // no encryption key, transfer in plain, just copy the msg sent by server - cText = ms_strdup(body); + setText(body); } - cContentType = "application/vnd.gsma.rcs-ft-http+xml"; - q->updateState(ChatMessage::FileTransferDone); + setContentType("application/vnd.gsma.rcs-ft-http+xml"); + q->updateState(ChatMessage::State::FileTransferDone); releaseHttpRequest(); - chatRoom->sendMessage(L_GET_C_BACK_PTR(q)); + //TODO chatRoom->sendMessage(q); fileUploadEndBackgroundTask(); } else { ms_warning("Received empty response from server, file transfer failed"); - q->updateState(ChatMessage::NotDelivered); + q->updateState(ChatMessage::State::NotDelivered); releaseHttpRequest(); fileUploadEndBackgroundTask(); } } else { ms_warning("Unhandled HTTP code response %d for file transfer", code); - q->updateState(ChatMessage::NotDelivered); + q->updateState(ChatMessage::State::NotDelivered); releaseHttpRequest(); fileUploadEndBackgroundTask(); } @@ -755,7 +768,7 @@ void ChatMessagePrivate::processAuthRequestedDownload(const belle_sip_auth_event L_Q(); ms_error("Error during file download : auth requested for msg [%p]", this); - q->updateState(ChatMessage::FileTransferError); + q->updateState(ChatMessage::State::FileTransferError); releaseHttpRequest(); } @@ -767,9 +780,9 @@ static void _chat_message_process_io_error_upload(void *data, const belle_sip_io void ChatMessagePrivate::processIoErrorUpload(const belle_sip_io_error_event_t *event) { L_Q(); ms_error("I/O Error during file upload of msg [%p]", this); - q->updateState(ChatMessage::NotDelivered); + q->updateState(ChatMessage::State::NotDelivered); releaseHttpRequest(); - chatRoom->getPrivate()->removeTransientMessage(L_GET_C_BACK_PTR(q)); + //TODO chatRoom->getPrivate()->removeTransientMessage(q); } static void _chat_message_process_auth_requested_upload(void *data, belle_sip_auth_event *event) { @@ -780,9 +793,9 @@ static void _chat_message_process_auth_requested_upload(void *data, belle_sip_au void ChatMessagePrivate::processAuthRequestedUpload(const belle_sip_auth_event *event) { L_Q(); ms_error("Error during file upload: auth requested for msg [%p]", this); - q->updateState(ChatMessage::NotDelivered); + q->updateState(ChatMessage::State::NotDelivered); releaseHttpRequest(); - chatRoom->getPrivate()->removeTransientMessage(L_GET_C_BACK_PTR(q)); + //TODO chatRoom->getPrivate()->removeTransientMessage(q); } static void _chat_message_process_io_error_download(void *data, const belle_sip_io_error_event_t *event) { @@ -794,7 +807,7 @@ void ChatMessagePrivate::processIoErrorDownload(const belle_sip_io_error_event_t L_Q(); ms_error("I/O Error during file download msg [%p]", this); - q->updateState(ChatMessage::FileTransferError); + q->updateState(ChatMessage::State::FileTransferError); releaseHttpRequest(); } @@ -809,7 +822,7 @@ void ChatMessagePrivate::processResponseFromGetFile(const belle_http_response_ev int code = belle_http_response_get_status_code(event->response); if (code >= 400 && code < 500) { ms_warning("File transfer failed with code %d", code); - setState(ChatMessage::FileTransferError); + setState(ChatMessage::State::FileTransferError); } else if (code != 200) { ms_warning("Unhandled HTTP code response %d for file transfer", code); } @@ -959,26 +972,36 @@ void ChatMessage::setAppdata (const string &appData) { linphone_chat_message_store_appdata(L_GET_C_BACK_PTR(this)); } -shared_ptr
    ChatMessage::getFromAddress () const { +const Address& ChatMessage::getFromAddress () const { L_D(); return d->from; } -void ChatMessage::setFromAddress(shared_ptr
    from) { +void ChatMessage::setFromAddress(Address from) { L_D(); d->from = from; } -shared_ptr
    ChatMessage::getToAddress () const { +void ChatMessage::setFromAddress(const string& from) { + L_D(); + d->from = Address(from); +} + +const Address& ChatMessage::getToAddress () const { L_D(); return d->to; } -void ChatMessage::setToAddress(shared_ptr
    to) { +void ChatMessage::setToAddress(Address to) { L_D(); d->to = to; } +void ChatMessage::setToAddress(const string& to) { + L_D(); + d->to = Address(to); +} + const string& ChatMessage::getFileTransferFilepath() const { L_D(); return d->fileTransferFilePath; @@ -1061,6 +1084,18 @@ void ChatMessage::removeCustomHeader (const string &headerName) { // ----------------------------------------------------------------------------- +void ChatMessage::store() { + L_D(); + + if (d->storageId != 0) { + /* The message has already been stored (probably because of file transfer), update it */ + linphone_chat_message_store_update(L_GET_C_BACK_PTR(this)); + } else { + /* Store the new message */ + linphone_chat_message_store(L_GET_C_BACK_PTR(this)); + } +} + void ChatMessage::updateState(State state) { L_D(); @@ -1068,7 +1103,7 @@ void ChatMessage::updateState(State state) { linphone_chat_message_store_state(L_GET_C_BACK_PTR(this)); if (state == Delivered || state == NotDelivered) { - d->chatRoom->getPrivate()->moveTransientMessageToWeakMessages(L_GET_C_BACK_PTR(this)); + d->chatRoom->getPrivate()->moveTransientMessageToWeakMessages(static_pointer_cast(shared_from_this())); } } @@ -1098,7 +1133,7 @@ void ChatMessage::reSend() { return; } - d->chatRoom->sendMessage(L_GET_C_BACK_PTR(this)); + d->chatRoom->sendMessage(static_pointer_cast(shared_from_this())); } void ChatMessage::sendDeliveryNotification(LinphoneReason reason) { @@ -1201,7 +1236,7 @@ int ChatMessage::putCharacter(uint32_t character) { d->setTime(ms_time(0)); d->state = Displayed; d->direction = Outgoing; - setFromAddress(make_shared(linphone_address_as_string(linphone_address_new(linphone_core_get_identity(lc))))); + setFromAddress(LinphonePrivate::Address(linphone_address_as_string(linphone_address_new(linphone_core_get_identity(lc))))); linphone_chat_message_store(L_GET_C_BACK_PTR(this)); d->rttMessage = ""; } diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index 153bab0aa..043e1fb1e 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -22,7 +22,7 @@ #include #include -#include "imdn.h" +#include "enums.h" #include "linphone/api/c-types.h" #include "linphone/api/c-chat-message.h" @@ -34,19 +34,22 @@ LINPHONE_BEGIN_NAMESPACE class Address; class ChatRoom; +class ChatRoomPrivate; class Content; class ErrorInfo; class ChatMessagePrivate; class LINPHONE_PUBLIC ChatMessage : public Object { friend class ChatRoom; + friend class ChatRoomPrivate; + friend class RealTimeTextChatRoomPrivate; -public: +public: enum Direction { Incoming, Outgoing }; - + enum State { Idle, InProgress, @@ -69,6 +72,7 @@ public: // Methods // ----------------------------------------------------------------------------- + void store(); void updateState(State state); void send(); void reSend(); @@ -105,11 +109,13 @@ public: const std::string& getAppdata () const; void setAppdata (const std::string &appData); - std::shared_ptr
    getFromAddress () const; - void setFromAddress(std::shared_ptr
    from); + const Address& getFromAddress () const; + void setFromAddress(Address from); + void setFromAddress(const std::string& from); - std::shared_ptr
    getToAddress () const; - void setToAddress(std::shared_ptr
    to); + const Address& getToAddress () const; + void setToAddress(Address to); + void setToAddress(const std::string& to); const std::string& getFileTransferFilepath() const; void setFileTransferFilepath(const std::string &path); diff --git a/src/chat/chat-room-p.h b/src/chat/chat-room-p.h index d40d69f5d..02d6e802c 100644 --- a/src/chat/chat-room-p.h +++ b/src/chat/chat-room-p.h @@ -41,16 +41,15 @@ public: private: static int createChatMessageFromDb (void *data, int argc, char **argv, char **colName); - static void onWeakMessageDestroyed (void *obj, belle_sip_object_t *messageBeingDestroyed); public: - void addTransientMessage (LinphoneChatMessage *msg); - void addWeakMessage (LinphoneChatMessage *msg); - std::list getTransientMessages () const { + void addTransientMessage (std::shared_ptr msg); + void addWeakMessage (std::shared_ptr msg); + std::list > getTransientMessages () const { return transientMessages; } - void moveTransientMessageToWeakMessages (LinphoneChatMessage *msg); - void removeTransientMessage (LinphoneChatMessage *msg); + void moveTransientMessageToWeakMessages (std::shared_ptr msg); + void removeTransientMessage (std::shared_ptr msg); void release (); void sendImdn (const std::string &content, LinphoneReason reason); @@ -62,27 +61,26 @@ protected: void sendIsComposingNotification (); int createChatMessageFromDb (int argc, char **argv, char **colName); - void onWeakMessageDestroyed (LinphoneChatMessage *messageBeingDestroyed); - LinphoneChatMessage *getTransientMessage (unsigned int storageId) const; - LinphoneChatMessage *getWeakMessage (unsigned int storageId) const; + std::shared_ptr getTransientMessage (unsigned int storageId) const; + std::shared_ptr getWeakMessage (unsigned int storageId) const; int sqlRequest (sqlite3 *db, const std::string &stmt); void sqlRequestMessage (sqlite3 *db, const std::string &stmt); - std::list findMessages (const std::string &messageId); - void storeOrUpdateMessage (LinphoneChatMessage *msg); + std::list > findMessages (const std::string &messageId); + void storeOrUpdateMessage (std::shared_ptr msg); public: LinphoneReason messageReceived (SalOp *op, const SalMessage *msg); void realtimeTextReceived (uint32_t character, LinphoneCall *call); protected: - void chatMessageReceived (LinphoneChatMessage *msg); + void chatMessageReceived (std::shared_ptr msg); void imdnReceived (const std::string &text); void isComposingReceived (const std::string &text); private: - void notifyChatMessageReceived (LinphoneChatMessage *msg); + void notifyChatMessageReceived (std::shared_ptr msg); void notifyStateChanged (); - void notifyUndecryptableMessageReceived (LinphoneChatMessage *msg); + void notifyUndecryptableMessageReceived (std::shared_ptr msg); private: /* IsComposingListener */ @@ -98,11 +96,11 @@ public: int unreadCount = -1; bool isComposing = false; bool remoteIsComposing = false; - std::list messages; - std::list transientMessages; - std::list weakMessages; + std::list > messages; + std::list > transientMessages; + std::list > weakMessages; std::list receivedRttCharacters; - LinphoneChatMessage *pendingMessage = nullptr; + std::shared_ptr pendingMessage = nullptr; IsComposing isComposingHandler; private: diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index b29f39575..8d48b34b1 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -23,13 +23,12 @@ #include "c-wrapper/c-wrapper.h" #include "chat-room-p.h" -#include "content/content-type.h" #include "imdn.h" -#include "logger/logger.h" - +#include "content/content.h" #include "chat-message-p.h" #include "chat-room.h" #include "sal/message_op.h" +#include "logger/logger.h" // ============================================================================= @@ -41,10 +40,10 @@ ChatRoomPrivate::ChatRoomPrivate (LinphoneCore *core) : core(core), isComposingHandler(core, this) {} ChatRoomPrivate::~ChatRoomPrivate () { - for (auto &message : transientMessages) + /*for (auto &message : transientMessages) linphone_chat_message_release(message); if (pendingMessage) - linphone_chat_message_unref(pendingMessage); + linphone_chat_message_unref(pendingMessage);*/ } // ----------------------------------------------------------------------------- @@ -54,26 +53,20 @@ int ChatRoomPrivate::createChatMessageFromDb (void *data, int argc, char **argv, return d->createChatMessageFromDb(argc, argv, colName); } -void ChatRoomPrivate::onWeakMessageDestroyed (void *obj, belle_sip_object_t *messageBeingDestroyed) { - ChatRoomPrivate *d = reinterpret_cast(obj); - d->onWeakMessageDestroyed(reinterpret_cast(messageBeingDestroyed)); -} - // ----------------------------------------------------------------------------- -void ChatRoomPrivate::addTransientMessage (LinphoneChatMessage *msg) { +void ChatRoomPrivate::addTransientMessage (shared_ptr msg) { auto iter = find(transientMessages.begin(), transientMessages.end(), msg); if (iter == transientMessages.end()) - transientMessages.push_back(linphone_chat_message_ref(msg)); + transientMessages.push_back(msg); } -void ChatRoomPrivate::addWeakMessage (LinphoneChatMessage *msg) { - auto iter = find(weakMessages.begin(), weakMessages.end(), msg); - if (iter == weakMessages.end()) - weakMessages.push_back(reinterpret_cast(belle_sip_object_weak_ref(msg, onWeakMessageDestroyed, this))); +void ChatRoomPrivate::addWeakMessage (shared_ptr msg) { + weak_ptr weakptr(msg); + weakMessages.push_back(weakptr); } -void ChatRoomPrivate::moveTransientMessageToWeakMessages (LinphoneChatMessage *msg) { +void ChatRoomPrivate::moveTransientMessageToWeakMessages (shared_ptr msg) { auto iter = find(transientMessages.begin(), transientMessages.end(), msg); if (iter != transientMessages.end()) { /* msg is not transient anymore, we can remove it from our transient list and unref it */ @@ -84,10 +77,9 @@ void ChatRoomPrivate::moveTransientMessageToWeakMessages (LinphoneChatMessage *m } } -void ChatRoomPrivate::removeTransientMessage (LinphoneChatMessage *msg) { +void ChatRoomPrivate::removeTransientMessage (shared_ptr msg) { auto iter = find(transientMessages.begin(), transientMessages.end(), msg); if (iter != transientMessages.end()) { - linphone_chat_message_unref(*iter); transientMessages.erase(iter); } } @@ -98,16 +90,16 @@ void ChatRoomPrivate::release () { L_Q(); isComposingHandler.stopTimers(); - for (auto &message : weakMessages) + /*for (auto &message : weakMessages) linphone_chat_message_deactivate(message); for (auto &message : transientMessages) - linphone_chat_message_deactivate(message); + linphone_chat_message_deactivate(message);*/ core = nullptr; linphone_chat_room_unref(L_GET_C_BACK_PTR(q)); } -void ChatRoomPrivate::sendImdn (const string &content, LinphoneReason reason) { +void ChatRoomPrivate::sendImdn (const string &payload, LinphoneReason reason) { L_Q(); const char *identity = nullptr; @@ -121,12 +113,15 @@ void ChatRoomPrivate::sendImdn (const string &content, LinphoneReason reason) { /* Sending out of call */ SalMessageOp *op = new SalMessageOp(core->sal); linphone_configure_op(core, op, peer, nullptr, !!lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0)); - LinphoneChatMessage *msg = q->createMessage(content); - LinphoneAddress *fromAddr = linphone_address_new(identity); - linphone_chat_message_set_from_address(msg, fromAddr); - LinphoneAddress *toAddr = linphone_address_new(peerAddress.asString().c_str()); - linphone_chat_message_set_to_address(msg, toAddr); - linphone_chat_message_set_content_type(msg, "message/imdn+xml"); + + shared_ptr msg = q->createMessage(); + msg->setFromAddress(identity); + msg->setToAddress(peerAddress.asString()); + + shared_ptr content = make_shared(); + content->setContentType("message/imdn+xml"); + content->setBody(payload); + msg->addContent(content); /* Do not try to encrypt the notification when it is reporting an error (maybe it should be bypassed only for some reasons). */ int retval = -1; @@ -135,17 +130,14 @@ void ChatRoomPrivate::sendImdn (const string &content, LinphoneReason reason) { LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); if (cbProcessOutgoingMessage) { - retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(q), msg); + retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(q), L_GET_C_BACK_PTR(msg)); } } if (retval <= 0) { - op->send_message(identity, peerAddress.asString().c_str(), linphone_chat_message_get_content_type(msg), linphone_chat_message_get_text(msg), nullptr); + op->send_message(identity, peerAddress.asString().c_str(), msg->getPrivate()->getContentType().c_str(), msg->getPrivate()->getText().c_str(), nullptr); } - linphone_chat_message_unref(msg); - linphone_address_unref(fromAddr); - linphone_address_unref(toAddr); linphone_address_unref(peer); op->unref(); } @@ -210,30 +202,31 @@ void ChatRoomPrivate::sendIsComposingNotification () { /* Sending out of call */ SalMessageOp *op = new SalMessageOp(core->sal); linphone_configure_op(core, op, peer, nullptr, !!lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0)); - string content = isComposingHandler.marshal(isComposing); - if (!content.empty()) { + string payload = isComposingHandler.marshal(isComposing); + if (!payload.empty()) { int retval = -1; - LinphoneAddress *fromAddr = linphone_address_new(identity); - LinphoneChatMessage *msg = q->createMessage(content); - linphone_chat_message_set_from_address(msg, fromAddr); - linphone_chat_message_set_to_address(msg, peer); - linphone_chat_message_set_content_type(msg, "application/im-iscomposing+xml"); + + shared_ptr msg = q->createMessage(); + msg->setFromAddress(identity); + msg->setToAddress(peerAddress.asString()); + + shared_ptr content = make_shared(); + content->setContentType("application/im-iscomposing+xml"); + content->setBody(payload); + msg->addContent(content); LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(core); if (imee) { LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); if (cbProcessOutgoingMessage) { - retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(q), msg); + retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(q), L_GET_C_BACK_PTR(msg)); } } if (retval <= 0) { - op->send_message(identity, peerAddress.asString().c_str(), linphone_chat_message_get_content_type(msg), linphone_chat_message_get_text(msg), nullptr); + op->send_message(identity, peerAddress.asString().c_str(), msg->getPrivate()->getContentType().c_str(), msg->getPrivate()->getText().c_str(), nullptr); } - - linphone_chat_message_unref(msg); - linphone_address_unref(fromAddr); op->unref(); } linphone_address_unref(peer); @@ -266,40 +259,53 @@ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colN unsigned int storageId = (unsigned int)atoi(argv[0]); /* Check if the message exists in the weak messages list, in which case we should return that one. */ - LinphoneChatMessage *newMessage = getWeakMessage(storageId); - if (!newMessage) { + shared_ptr message = getWeakMessage(storageId); + if (!message) { /* Check if the message exists in the transient list, in which case we should return that one. */ - newMessage = getTransientMessage(storageId); + message = getTransientMessage(storageId); } - if (!newMessage) { - newMessage = q->createMessage(argv[4] ? argv[4] : ""); + if (!message) { + message = q->createMessage(); - LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str()); - if (atoi(argv[3]) == LinphoneChatMessageIncoming) { - linphone_chat_message_set_incoming(newMessage); - linphone_chat_message_set_from_address(newMessage, peer); - } else { - linphone_chat_message_set_outgoing(newMessage); - linphone_chat_message_set_to_address(newMessage, peer); + shared_ptr content = make_shared(); + message->addContent(content); + + if (argv[4]) { + content->setBody(argv[4]); } - linphone_address_unref(peer); + if (argv[13]) { + content->setContentType(argv[13]); + } - linphone_chat_message_set_time(newMessage, (time_t)atol(argv[9])); - linphone_chat_message_set_state(newMessage, static_cast(atoi(argv[7]))); - linphone_chat_message_set_storage_id(newMessage, storageId); - linphone_chat_message_set_external_body_url(newMessage, ms_strdup(argv[8])); - linphone_chat_message_set_appdata(newMessage, ms_strdup(argv[10])); - linphone_chat_message_set_message_id(newMessage, ms_strdup(argv[12])); - linphone_chat_message_set_content_type(newMessage, argv[13]); - linphone_chat_message_set_is_secured(newMessage, (bool_t)atoi(argv[14])); + Address peer(peerAddress.asString()); + if (atoi(argv[3]) == ChatMessage::Direction::Incoming) { + message->getPrivate()->setDirection(ChatMessage::Direction::Incoming); + message->setFromAddress(peer); + } else { + message->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); + message->setToAddress(peer); + } + + message->getPrivate()->setTime((time_t)atol(argv[9])); + message->getPrivate()->setState((ChatMessage::State)atoi(argv[7])); + message->getPrivate()->setStorageId(storageId); + if (argv[8]) { + message->setExternalBodyUrl(argv[8]); + } + if (argv[10]) { + message->setAppdata(argv[10]); + } + message->setId(argv[12]); + message->setIsSecured((bool)atoi(argv[14])); if (argv[11]) { int id = atoi(argv[11]); if (id >= 0) - linphone_chat_message_fetch_content_from_database(core->db, newMessage, id); + linphone_chat_message_fetch_content_from_database(core->db, L_GET_C_BACK_PTR(message), id); } /* Fix content type for old messages that were stored without it */ + /* To keep ? if (!linphone_chat_message_get_content_type(newMessage)) { if (linphone_chat_message_get_file_transfer_information(newMessage)) { linphone_chat_message_set_content_type(newMessage, ms_strdup("application/vnd.gsma.rcs-ft-http+xml")); @@ -308,33 +314,28 @@ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colN } else { linphone_chat_message_set_content_type(newMessage, ms_strdup("text/plain")); } - } + }*/ /* Add the new message to the weak messages list. */ - addWeakMessage(newMessage); + addWeakMessage(message); } - messages.push_front(newMessage); + messages.push_front(message); return 0; } -void ChatRoomPrivate::onWeakMessageDestroyed (LinphoneChatMessage *messageBeingDestroyed) { - auto iter = find(weakMessages.begin(), weakMessages.end(), messageBeingDestroyed); - if (iter != transientMessages.end()) - weakMessages.erase(iter); -} - -LinphoneChatMessage *ChatRoomPrivate::getTransientMessage (unsigned int storageId) const { +shared_ptr ChatRoomPrivate::getTransientMessage (unsigned int storageId) const { for (auto &message : transientMessages) { - if (linphone_chat_message_get_storage_id(message) == storageId) - return linphone_chat_message_ref(message); + if (message->getPrivate()->getStorageId() == storageId) + return message; } return nullptr; } -LinphoneChatMessage *ChatRoomPrivate::getWeakMessage (unsigned int storageId) const { +std::shared_ptr ChatRoomPrivate::getWeakMessage (unsigned int storageId) const { for (auto &message : weakMessages) { - if (linphone_chat_message_get_storage_id(message) == storageId) - return linphone_chat_message_ref(message); + shared_ptr msg(message); + if (msg->getPrivate()->getStorageId() == storageId) + return msg; } return nullptr; } @@ -358,30 +359,21 @@ void ChatRoomPrivate::sqlRequestMessage (sqlite3 *db, const string &stmt) { } } -list ChatRoomPrivate::findMessages (const string &messageId) { +list > ChatRoomPrivate::findMessages (const string &messageId) { if (!core->db) - return list(); + return list >(); string peer = peerAddress.asStringUriOnly(); char *buf = sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q AND messageId = %Q", peer.c_str(), messageId.c_str()); messages.clear(); sqlRequestMessage(core->db, buf); sqlite3_free(buf); - list result = messages; + list > result = messages; messages.clear(); return result; } -/** - * TODO: Should be handled directly by the LinphoneChatMessage object! - */ -void ChatRoomPrivate::storeOrUpdateMessage (LinphoneChatMessage *msg) { - if (linphone_chat_message_get_storage_id(msg) != 0) { - /* The message has already been stored (probably because of file transfer), update it */ - linphone_chat_message_store_update(msg); - } else { - /* Store the new message */ - linphone_chat_message_store(msg); - } +void ChatRoomPrivate::storeOrUpdateMessage (shared_ptr msg) { + msg->store(); } // ----------------------------------------------------------------------------- @@ -391,34 +383,32 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa bool increaseMsgCount = true; LinphoneReason reason = LinphoneReasonNone; - LinphoneChatMessage *msg; + shared_ptr msg; /* Check if this is a duplicate message */ - if ((msg = q->findMessageWithDirection(op->get_call_id(), LinphoneChatMessageIncoming))) { + if ((msg = q->findMessageWithDirection(op->get_call_id(), ChatMessage::Direction::Incoming))) { reason = core->chat_deny_code; - if (msg) - linphone_chat_message_unref(msg); return reason; } - msg = q->createMessage(salMsg->text ? salMsg->text : ""); - linphone_chat_message_set_content_type(msg, salMsg->content_type); - LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str()); - linphone_chat_message_set_from_address(msg, peer); - linphone_address_unref(peer); + msg = q->createMessage(); - LinphoneAddress *to = op->get_to() ? linphone_address_new(op->get_to()) : linphone_address_new(linphone_core_get_identity(core)); - linphone_chat_message_set_to_address(msg, to); - linphone_chat_message_set_time(msg, salMsg->time); - linphone_chat_message_set_state(msg, LinphoneChatMessageStateDelivered); - linphone_chat_message_set_incoming(msg); - linphone_chat_message_set_message_id(msg, ms_strdup(op->get_call_id())); + shared_ptr content = make_shared(); + content->setContentType(salMsg->content_type); + content->setBody(salMsg->text ? salMsg->text : ""); + msg->addContent(content); + + msg->setToAddress( op->get_to() ? op->get_to() : linphone_core_get_identity(core)); + msg->getPrivate()->setTime(salMsg->time); + msg->getPrivate()->setState(ChatMessage::State::Delivered); + msg->getPrivate()->setDirection(ChatMessage::Direction::Incoming); + msg->setId(op->get_call_id()); const SalCustomHeader *ch = op->get_recv_custom_header(); if (ch) - linphone_chat_message_set_sal_custom_headers(msg, sal_custom_header_clone(ch)); + msg->getPrivate()->setSalCustomHeaders(sal_custom_header_clone(ch)); if (salMsg->url) - linphone_chat_message_set_external_body_url(msg, salMsg->url); + msg->setExternalBodyUrl(salMsg->url); int retval = -1; LinphoneImEncryptionEngine *imee = core->im_encryption_engine; @@ -426,14 +416,14 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsIncomingMessageCb cbProcessIncomingMessage = linphone_im_encryption_engine_cbs_get_process_incoming_message(imeeCbs); if (cbProcessIncomingMessage) { - retval = cbProcessIncomingMessage(imee, L_GET_C_BACK_PTR(q), msg); + retval = cbProcessIncomingMessage(imee, L_GET_C_BACK_PTR(q), L_GET_C_BACK_PTR(msg)); if (retval == 0) { - linphone_chat_message_set_is_secured(msg, TRUE); + msg->setIsSecured(true); } else if (retval > 0) { /* Unable to decrypt message */ notifyUndecryptableMessageReceived(msg); reason = linphone_error_code_to_reason(retval); - linphone_chat_message_send_delivery_notification(msg, reason); + msg->sendDeliveryNotification(reason); /* Return LinphoneReasonNone to avoid flexisip resending us a message we can't decrypt */ reason = LinphoneReasonNone; goto end; @@ -441,36 +431,36 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa } } - if ((retval <= 0) && (linphone_core_is_content_type_supported(core, linphone_chat_message_get_content_type(msg)) == FALSE)) { + if ((retval <= 0) && (linphone_core_is_content_type_supported(core, msg->getPrivate()->getContentType().c_str()) == FALSE)) { retval = 415; - lError() << "Unsupported MESSAGE (content-type " << linphone_chat_message_get_content_type(msg) << " not recognized)"; + lError() << "Unsupported MESSAGE (content-type " << msg->getPrivate()->getContentType() << " not recognized)"; } if (retval > 0) { reason = linphone_error_code_to_reason(retval); - linphone_chat_message_send_delivery_notification(msg, reason); + msg->sendDeliveryNotification(reason); goto end; } - if (ContentType::isFileTransfer(linphone_chat_message_get_content_type(msg))) { - create_file_transfer_information_from_vnd_gsma_rcs_ft_http_xml(msg); - linphone_chat_message_set_to_be_stored(msg, TRUE); - } else if (ContentType::isImIsComposing(linphone_chat_message_get_content_type(msg))) { - isComposingReceived(linphone_chat_message_get_text(msg)); - linphone_chat_message_set_to_be_stored(msg, FALSE); + if (ContentType::isFileTransfer(msg->getPrivate()->getContentType())) { + create_file_transfer_information_from_vnd_gsma_rcs_ft_http_xml(L_GET_C_BACK_PTR(msg)); + msg->setIsToBeStored(true); + } else if (ContentType::isImIsComposing(msg->getPrivate()->getContentType())) { + isComposingReceived(msg->getPrivate()->getText()); + msg->setIsToBeStored(false); increaseMsgCount = FALSE; if (lp_config_get_int(core->config, "sip", "deliver_imdn", 0) != 1) { goto end; } - } else if (ContentType::isImdn(linphone_chat_message_get_content_type(msg))) { - imdnReceived(linphone_chat_message_get_text(msg)); - linphone_chat_message_set_to_be_stored(msg, FALSE); + } else if (ContentType::isImdn(msg->getPrivate()->getContentType())) { + imdnReceived(msg->getPrivate()->getText()); + msg->setIsToBeStored(false); increaseMsgCount = FALSE; if (lp_config_get_int(core->config, "sip", "deliver_imdn", 0) != 1) { goto end; } - } else if (ContentType::isText(linphone_chat_message_get_content_type(msg))) { - linphone_chat_message_set_to_be_stored(msg, TRUE); + } else if (ContentType::isText(msg->getPrivate()->getContentType())) { + msg->setIsToBeStored(true); } if (increaseMsgCount) { @@ -486,27 +476,25 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa chatMessageReceived(msg); - if (linphone_chat_message_get_to_be_stored(msg)) { - linphone_chat_message_store(msg); + if (msg->isToBeStored()) { + msg->store(); } pendingMessage = nullptr; end: - if (msg) - linphone_chat_message_unref(msg); return reason; } // ----------------------------------------------------------------------------- -void ChatRoomPrivate::chatMessageReceived (LinphoneChatMessage *msg) { +void ChatRoomPrivate::chatMessageReceived (shared_ptr msg) { L_Q(); - if (!ContentType::isImdn(linphone_chat_message_get_content_type(msg)) && !ContentType::isImIsComposing(linphone_chat_message_get_content_type(msg))) { + if (!ContentType::isImdn(msg->getPrivate()->getContentType()) && !ContentType::isImIsComposing(msg->getPrivate()->getContentType())) { notifyChatMessageReceived(msg); remoteIsComposing = false; linphone_core_notify_is_composing_received(core, L_GET_C_BACK_PTR(q)); - linphone_chat_message_send_delivery_notification(msg, LinphoneReasonNone); + msg->sendDeliveryNotification(LinphoneReasonNone); } } @@ -521,18 +509,18 @@ void ChatRoomPrivate::isComposingReceived (const string &text) { // ----------------------------------------------------------------------------- -void ChatRoomPrivate::notifyChatMessageReceived (LinphoneChatMessage *msg) { +void ChatRoomPrivate::notifyChatMessageReceived (shared_ptr msg) { L_Q(); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); - if (linphone_chat_message_get_text(msg)) { + if (!msg->getPrivate()->getText().empty()) { /* Legacy API */ - linphone_core_notify_text_message_received(core, cr, linphone_chat_message_get_from_address(msg), linphone_chat_message_get_text(msg)); + linphone_core_notify_text_message_received(core, cr, L_GET_C_BACK_PTR(&msg->getFromAddress()), msg->getPrivate()->getText().c_str()); } LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsMessageReceivedCb cb = linphone_chat_room_cbs_get_message_received(cbs); if (cb) - cb(cr, msg); - linphone_core_notify_message_received(core, cr, msg); + cb(cr, L_GET_C_BACK_PTR(msg)); + linphone_core_notify_message_received(core, cr, L_GET_C_BACK_PTR(msg)); } void ChatRoomPrivate::notifyStateChanged () { @@ -544,14 +532,14 @@ void ChatRoomPrivate::notifyStateChanged () { cb(cr, (LinphoneChatRoomState)state); } -void ChatRoomPrivate::notifyUndecryptableMessageReceived (LinphoneChatMessage *msg) { +void ChatRoomPrivate::notifyUndecryptableMessageReceived (shared_ptr msg) { L_Q(); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsUndecryptableMessageReceivedCb cb = linphone_chat_room_cbs_get_undecryptable_message_received(cbs); if (cb) - cb(cr, msg); - linphone_core_notify_message_received_unable_decrypt(core, cr, msg); + cb(cr, L_GET_C_BACK_PTR(msg)); + linphone_core_notify_message_received_unable_decrypt(core, cr, L_GET_C_BACK_PTR(msg)); } // ----------------------------------------------------------------------------- @@ -589,30 +577,34 @@ void ChatRoom::compose () { d->isComposingHandler.startIdleTimer(); } -LinphoneChatMessage *ChatRoom::createFileTransferMessage (const LinphoneContent *initialContent) { +shared_ptr ChatRoom::createFileTransferMessage (const LinphoneContent *initialContent) { L_D(); - shared_ptr chatMessage = make_shared(static_pointer_cast(shared_from_this())); + shared_ptr chatMessage = createMessage(); - chatMessage->getPrivate()->setTime(ms_time(0)); chatMessage->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); chatMessage->getPrivate()->setFileTransferInformation(linphone_content_copy(initialContent)); - chatMessage->setToAddress(make_shared
    (d->peerAddress.asString().c_str())); - chatMessage->setFromAddress(make_shared
    (linphone_core_get_identity(d->core))); + chatMessage->setToAddress(d->peerAddress); + chatMessage->setFromAddress(linphone_core_get_identity(d->core)); - LinphoneChatMessage *msg = chatMessage->getBackPtr(); - return msg; + return chatMessage; } -LinphoneChatMessage *ChatRoom::createMessage (const string &message) { +shared_ptr ChatRoom::createMessage (const string &message) { + shared_ptr chatMessage = createMessage(); + + shared_ptr content = make_shared(); + content->setContentType("text/plain"); + content->setBody(message); + chatMessage->addContent(content); + + return chatMessage; +} + +shared_ptr ChatRoom::createMessage () { shared_ptr chatMessage = make_shared(static_pointer_cast(shared_from_this())); - chatMessage->getPrivate()->setTime(ms_time(0)); - chatMessage->getPrivate()->setContentType("text/plain"); - chatMessage->getPrivate()->setText(message); - - LinphoneChatMessage *msg = chatMessage->getBackPtr(); - return msg; + return chatMessage; } void ChatRoom::deleteHistory () { @@ -625,10 +617,10 @@ void ChatRoom::deleteHistory () { if (d->unreadCount > 0) d->unreadCount = 0; } -void ChatRoom::deleteMessage (LinphoneChatMessage *msg) { +void ChatRoom::deleteMessage (shared_ptr msg) { L_D(); if (!d->core->db) return; - char *buf = sqlite3_mprintf("DELETE FROM history WHERE id = %u;", linphone_chat_message_get_storage_id(msg)); + char *buf = sqlite3_mprintf("DELETE FROM history WHERE id = %u;", msg->getPrivate()->getStorageId()); d->sqlRequest(d->core->db, buf); sqlite3_free(buf); @@ -637,38 +629,30 @@ void ChatRoom::deleteMessage (LinphoneChatMessage *msg) { d->unreadCount = -1; } -LinphoneChatMessage *ChatRoom::findMessage (const string &messageId) { +shared_ptr ChatRoom::findMessage (const string &messageId) { L_D(); - LinphoneChatMessage *cm = nullptr; - list l = d->findMessages(messageId); + shared_ptr cm = nullptr; + list > l = d->findMessages(messageId); if (!l.empty()) { cm = l.front(); - linphone_chat_message_ref(cm); - for (auto &message : l) - linphone_chat_message_unref(message); } return cm; } -LinphoneChatMessage * ChatRoom::findMessageWithDirection (const string &messageId, LinphoneChatMessageDir direction) { +shared_ptr ChatRoom::findMessageWithDirection (const string &messageId, ChatMessage::Direction direction) { L_D(); - LinphoneChatMessage *ret = nullptr; - list l = d->findMessages(messageId); + shared_ptr ret = nullptr; + list > l = d->findMessages(messageId); for (auto &message : l) { - if (linphone_chat_message_get_direction(message) == direction) { - linphone_chat_message_ref(message); + if (message->getDirection() == direction) { ret = message; break; } } - if (!l.empty()) { - for (auto &message : l) - linphone_chat_message_unref(message); - } return ret; } -list ChatRoom::getHistory (int nbMessages) { +list > ChatRoom::getHistory (int nbMessages) { return getHistoryRange(0, nbMessages - 1); } @@ -677,9 +661,9 @@ int ChatRoom::getHistorySize () { return d->getMessagesCount(false); } -list ChatRoom::getHistoryRange (int startm, int endm) { +list > ChatRoom::getHistoryRange (int startm, int endm) { L_D(); - if (!d->core->db) return list(); + if (!d->core->db) return list >(); string peer = d->peerAddress.asStringUriOnly(); d->messages.clear(); @@ -717,18 +701,16 @@ list ChatRoom::getHistoryRange (int startm, int endm) { if (!d->messages.empty()) { /* Fill local addr with core identity instead of per message */ - LinphoneAddress *localAddr = linphone_address_new(linphone_core_get_identity(d->core)); for (auto &message : d->messages) { - if (linphone_chat_message_is_outgoing(message)) { - linphone_chat_message_set_from_address(message, linphone_address_ref(localAddr)); + if (message->isOutgoing()) { + message->setFromAddress(linphone_core_get_identity(d->core)); } else { - linphone_chat_message_set_to_address(message, linphone_address_ref(localAddr)); + message->setToAddress(linphone_core_get_identity(d->core)); } } - linphone_address_unref(localAddr); } - list result = d->messages; + list > result = d->messages; d->messages.clear(); return result; } @@ -752,61 +734,60 @@ void ChatRoom::markAsRead () { if (getUnreadMessagesCount() == 0) return; string peer = d->peerAddress.asStringUriOnly(); - char *buf = sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q AND direction = %i AND status != %i", peer.c_str(), LinphoneChatMessageIncoming, LinphoneChatMessageStateDisplayed); + char *buf = sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q AND direction = %i AND status != %i", peer.c_str(), ChatMessage::Direction::Incoming, ChatMessage::State::Displayed); d->sqlRequestMessage(d->core->db, buf); sqlite3_free(buf); for (auto &message : d->messages) { - linphone_chat_message_send_display_notification(message); - linphone_chat_message_unref(message); + message->sendDisplayNotification(); } d->messages.clear(); - buf = sqlite3_mprintf("UPDATE history SET status=%i WHERE remoteContact=%Q AND direction=%i;", LinphoneChatMessageStateDisplayed, peer.c_str(), LinphoneChatMessageIncoming); + buf = sqlite3_mprintf("UPDATE history SET status=%i WHERE remoteContact=%Q AND direction=%i;", ChatMessage::State::Displayed, peer.c_str(), ChatMessage::Direction::Incoming); d->sqlRequest(d->core->db, buf); sqlite3_free(buf); if (d->pendingMessage) { - linphone_chat_message_set_state(d->pendingMessage, LinphoneChatMessageStateDisplayed); - linphone_chat_message_send_display_notification(d->pendingMessage); + d->pendingMessage->getPrivate()->setState(ChatMessage::State::Displayed); + d->pendingMessage->sendDisplayNotification(); } d->unreadCount = 0; } -void ChatRoom::sendMessage (LinphoneChatMessage *msg) { +void ChatRoom::sendMessage (shared_ptr msg) { L_D(); - linphone_chat_message_set_outgoing(msg); + msg->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); /* Check if we shall upload a file to a server */ - if (linphone_chat_message_get_file_transfer_information(msg) && !linphone_chat_message_get_content_type(msg)) { + if (msg->getPrivate()->getFileTransferInformation() && msg->getPrivate()->getContentType().empty()) { /* Open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */ - if (linphone_chat_room_upload_file(msg) == 0) { + if (msg->uploadFile() == 0) { /* Add to transient list only if message is going out */ d->addTransientMessage(msg); /* Store the message so that even if the upload is stopped, it can be done again */ d->storeOrUpdateMessage(msg); } else { - linphone_chat_message_unref(msg); return; } } else { - SalOp *op = linphone_chat_message_get_sal_op(msg); + SalOp *op = msg->getPrivate()->getSalOp(); LinphoneCall *call = nullptr; string identity; char *clearTextMessage = nullptr; char *clearTextContentType = nullptr; LinphoneAddress *peer = linphone_address_new(d->peerAddress.asString().c_str()); - if (linphone_chat_message_get_text(msg)) { - clearTextMessage = ms_strdup(linphone_chat_message_get_text(msg)); + if (!msg->getPrivate()->getText().empty()) { + clearTextMessage = ms_strdup(msg->getPrivate()->getText().c_str()); } - if (linphone_chat_message_get_content_type(msg)) { - clearTextContentType = ms_strdup(linphone_chat_message_get_content_type(msg)); + if (!msg->getPrivate()->getContentType().empty()) { + clearTextContentType = ms_strdup(msg->getPrivate()->getContentType().c_str()); } /* Add to transient list */ d->addTransientMessage(msg); - linphone_chat_message_set_time(msg, ms_time(0)); + msg->getPrivate()->setTime(ms_time(0)); + if (lp_config_get_int(d->core->config, "sip", "chat_use_call_dialogs", 0) != 0) { call = linphone_core_get_call_by_remote_address(d->core, d->peerAddress.asString().c_str()); if (call) { @@ -828,7 +809,7 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { identity = linphone_core_get_primary_contact(d->core); } } - linphone_chat_message_set_from_address(msg, linphone_address_new(identity.c_str())); + msg->setFromAddress(identity); int retval = -1; LinphoneImEncryptionEngine *imee = d->core->im_encryption_engine; @@ -836,55 +817,54 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); if (cbProcessOutgoingMessage) { - retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(this), msg); + retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(this), L_GET_C_BACK_PTR(msg)); if (retval == 0) { - linphone_chat_message_set_is_secured(msg, TRUE); + msg->setIsSecured(true); } } } if (!op) { /* Sending out of call */ - linphone_chat_message_set_sal_op(msg, op = new SalMessageOp(d->core->sal)); + msg->getPrivate()->setSalOp(op = new SalMessageOp(d->core->sal)); linphone_configure_op( - d->core, op, peer, linphone_chat_message_get_sal_custom_headers(msg), + d->core, op, peer, msg->getPrivate()->getSalCustomHeaders(), !!lp_config_get_int(d->core->config, "sip", "chat_msg_with_contact", 0) ); - op->set_user_pointer(msg); /* If out of call, directly store msg */ + op->set_user_pointer(L_GET_C_BACK_PTR(msg)); /* If out of call, directly store msg */ } if (retval > 0) { sal_error_info_set((SalErrorInfo *)op->get_error_info(), SalReasonNotAcceptable, "SIP", retval, "Unable to encrypt IM", nullptr); d->storeOrUpdateMessage(msg); - linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); - linphone_chat_message_unref(msg); + msg->updateState(ChatMessage::State::NotDelivered); linphone_address_unref(peer); return; } - if (linphone_chat_message_get_external_body_url(msg)) { - char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", linphone_chat_message_get_external_body_url(msg)); + if (!msg->getExternalBodyUrl().empty()) { + char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"",msg->getExternalBodyUrl().empty()); auto msgOp = dynamic_cast(op); msgOp->send_message(identity.c_str(), d->peerAddress.asString().c_str(), content_type, nullptr, nullptr); ms_free(content_type); } else { auto msgOp = dynamic_cast(op); - if (linphone_chat_message_get_content_type(msg)) { - msgOp->send_message(identity.c_str(), d->peerAddress.asString().c_str(), linphone_chat_message_get_content_type(msg), linphone_chat_message_get_text(msg), d->peerAddress.asStringUriOnly().c_str()); + if (!msg->getPrivate()->getContentType().empty()) { + msgOp->send_message(identity.c_str(), d->peerAddress.asString().c_str(), msg->getPrivate()->getContentType().c_str(), msg->getPrivate()->getText().c_str(), d->peerAddress.asStringUriOnly().c_str()); } else { - msgOp->send_message(identity.c_str(), d->peerAddress.asString().c_str(), linphone_chat_message_get_text(msg)); + msgOp->send_message(identity.c_str(), d->peerAddress.asString().c_str(), msg->getPrivate()->getText().c_str()); } } - if (linphone_chat_message_get_text(msg) && clearTextMessage && strcmp(linphone_chat_message_get_text(msg), clearTextMessage) != 0) { + if (!msg->getPrivate()->getText().empty() && clearTextMessage && strcmp(msg->getPrivate()->getText().c_str(), clearTextMessage) != 0) { /* We replace the encrypted message by the original one so it can be correctly stored and displayed by the application */ - linphone_chat_message_set_text(msg, ms_strdup(clearTextMessage)); + msg->getPrivate()->setText(clearTextMessage); } - if (linphone_chat_message_get_content_type(msg) && clearTextContentType && (strcmp(linphone_chat_message_get_content_type(msg), clearTextContentType) != 0)) { + if (!msg->getPrivate()->getContentType().empty() && clearTextContentType && (strcmp(msg->getPrivate()->getContentType().c_str(), clearTextContentType) != 0)) { /* We replace the encrypted content type by the original one */ - linphone_chat_message_set_content_type(msg, ms_strdup(clearTextContentType)); + msg->getPrivate()->setContentType(clearTextContentType); } - linphone_chat_message_set_message_id(msg, ms_strdup(op->get_call_id())); /* must be known at that time */ + msg->setId(op->get_call_id()); /* must be known at that time */ d->storeOrUpdateMessage(msg); if (d->isComposing) @@ -903,15 +883,14 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) { if (call && linphone_call_get_op(call) == op) { /* In this case, chat delivery status is not notified, so unrefing chat message right now */ /* Might be better fixed by delivering status, but too costly for now */ - linphone_chat_room_remove_transient_message(linphone_chat_message_get_chat_room(msg), msg); - linphone_chat_message_unref(msg); + d->removeTransientMessage(msg); return; } } /* If operation failed, we should not change message state */ - if (linphone_chat_message_is_outgoing(msg)) { - linphone_chat_message_set_state(msg, LinphoneChatMessageStateInProgress); + if (msg->isOutgoing()) { + msg->getPrivate()->setState(ChatMessage::State::InProgress); } } diff --git a/src/chat/chat-room.h b/src/chat/chat-room.h index debff026f..e9d2ea018 100644 --- a/src/chat/chat-room.h +++ b/src/chat/chat-room.h @@ -28,6 +28,8 @@ #include "object/object.h" #include "conference/conference-interface.h" +#include "chat-message.h" + #include "linphone/types.h" // ============================================================================= @@ -47,19 +49,20 @@ public: virtual ~ChatRoom () = default; void compose (); - LinphoneChatMessage *createFileTransferMessage (const LinphoneContent *initialContent); - LinphoneChatMessage *createMessage (const std::string &msg); + std::shared_ptr createFileTransferMessage (const LinphoneContent *initialContent); + std::shared_ptr createMessage (const std::string &msg); + std::shared_ptr createMessage (); void deleteHistory (); - void deleteMessage (LinphoneChatMessage *msg); - LinphoneChatMessage * findMessage (const std::string& messageId); - LinphoneChatMessage * findMessageWithDirection (const std::string &messageId, LinphoneChatMessageDir direction); - std::list getHistory (int nbMessages); + void deleteMessage (std::shared_ptr msg); + std::shared_ptr findMessage (const std::string& messageId); + std::shared_ptr findMessageWithDirection (const std::string &messageId, ChatMessage::Direction direction); + std::list > getHistory (int nbMessages); int getHistorySize (); - std::list getHistoryRange (int startm, int endm); + std::list > getHistoryRange (int startm, int endm); int getUnreadMessagesCount (); bool isRemoteComposing () const; void markAsRead (); - virtual void sendMessage (LinphoneChatMessage *msg); + virtual void sendMessage (std::shared_ptr msg); LinphoneCore *getCore () const; diff --git a/src/chat/imdn.cpp b/src/chat/imdn.cpp index e0c0696ca..b63e7199d 100644 --- a/src/chat/imdn.cpp +++ b/src/chat/imdn.cpp @@ -19,6 +19,8 @@ #include "logger/logger.h" #include "imdn.h" +#include "chat/chat-room.h" +#include "chat/chat-message.h" // ============================================================================= @@ -59,7 +61,7 @@ void Imdn::parse (ChatRoom &cr, xmlparsing_context_t *xmlCtx) { } if (messageIdStr && datetimeStr) { - LinphoneChatMessage *cm = cr.findMessageWithDirection(messageIdStr, LinphoneChatMessageOutgoing); + shared_ptr cm = cr.findMessageWithDirection(messageIdStr, ChatMessage::Direction::Outgoing); if (!cm) { lWarning() << "Received IMDN for unknown message " << messageIdStr; } else { @@ -73,9 +75,9 @@ void Imdn::parse (ChatRoom &cr, xmlparsing_context_t *xmlCtx) { xmlNodePtr node = deliveryStatusObject->nodesetval->nodeTab[0]; if (node->children && node->children->name) { if (strcmp((const char *)node->children->name, "delivered") == 0) { - linphone_chat_message_update_state(cm, LinphoneChatMessageStateDeliveredToUser); + cm->updateState(ChatMessage::State::DeliveredToUser); } else if (strcmp((const char *)node->children->name, "error") == 0) { - linphone_chat_message_update_state(cm, LinphoneChatMessageStateNotDelivered); + cm->updateState(ChatMessage::State::NotDelivered); } } } @@ -86,13 +88,12 @@ void Imdn::parse (ChatRoom &cr, xmlparsing_context_t *xmlCtx) { xmlNodePtr node = displayStatusObject->nodesetval->nodeTab[0]; if (node->children && node->children->name) { if (strcmp((const char *)node->children->name, "displayed") == 0) { - linphone_chat_message_update_state(cm, LinphoneChatMessageStateDisplayed); + cm->updateState(ChatMessage::State::Displayed); } } } xmlXPathFreeObject(displayStatusObject); } - linphone_chat_message_unref(cm); } } if (messageIdStr) diff --git a/src/chat/imdn.h b/src/chat/imdn.h index c4bb6d1a5..3a1f332c4 100644 --- a/src/chat/imdn.h +++ b/src/chat/imdn.h @@ -21,14 +21,14 @@ #include "linphone/utils/general.h" -#include "chat-room.h" - #include "private.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE +class ChatRoom; + class Imdn { public: static void parse (ChatRoom &cr, const std::string &content); diff --git a/src/chat/modifier/chat-message-modifier.h b/src/chat/modifier/chat-message-modifier.h index 1bd6d5a88..0f4071df8 100644 --- a/src/chat/modifier/chat-message-modifier.h +++ b/src/chat/modifier/chat-message-modifier.h @@ -21,6 +21,8 @@ #include "linphone/utils/general.h" +#include "private.h" + // ============================================================================= LINPHONE_BEGIN_NAMESPACE diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index dec8d2046..33c2dba62 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -16,12 +16,13 @@ * along with this program. If not, see . */ -#include "chat/chat-message-p.h" +#include "cpim-chat-message-modifier.h" + #include "chat/cpim/cpim.h" #include "content/content-type.h" #include "content/content.h" - -#include "cpim-chat-message-modifier.h" +#include "address/address.h" +#include "chat/chat-message-p.h" // ============================================================================= diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index f0e073cbb..c3c8299ca 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -16,8 +16,9 @@ * along with this program. If not, see . */ -#include "chat/chat-message-p.h" #include "multipart-chat-message-modifier.h" +#include "address/address.h" +#include "chat/chat-message-p.h" // ============================================================================= diff --git a/src/chat/real-time-text-chat-room-p.h b/src/chat/real-time-text-chat-room-p.h index 41a94f6af..5aaf502c2 100644 --- a/src/chat/real-time-text-chat-room-p.h +++ b/src/chat/real-time-text-chat-room-p.h @@ -43,7 +43,7 @@ public: public: LinphoneCall *call = nullptr; std::list receivedRttCharacters; - LinphoneChatMessage *pendingMessage = nullptr; + std::shared_ptr pendingMessage = nullptr; private: L_DECLARE_PUBLIC(RealTimeTextChatRoom); diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 21b2656ba..0a4939735 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -21,6 +21,7 @@ #include "linphone/utils/utils.h" #include "real-time-text-chat-room-p.h" +#include "chat-message-p.h" #include "c-wrapper/c-wrapper.h" #include "logger/logger.h" @@ -40,8 +41,6 @@ RealTimeTextChatRoomPrivate::~RealTimeTextChatRoomPrivate () { for (auto &rttChars : receivedRttCharacters) bctbx_free(rttChars); } - if (pendingMessage) - linphone_chat_message_unref(pendingMessage); } // ----------------------------------------------------------------------------- @@ -67,16 +66,11 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp if ((character == new_line) || (character == crlf) || (character == lf)) { /* End of message */ - lDebug() << "New line received, forge a message with content " << linphone_chat_message_get_text(pendingMessage); - LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str()); - linphone_chat_message_set_from_address(pendingMessage, peer); - linphone_address_unref(peer); - linphone_chat_message_set_to_address(pendingMessage, linphone_call_get_dest_proxy(call) - ? linphone_address_clone(linphone_call_get_dest_proxy(call)->identity_address) - : linphone_address_new(linphone_core_get_identity(core))); - linphone_chat_message_set_time(pendingMessage, ms_time(0)); - linphone_chat_message_set_state(pendingMessage, LinphoneChatMessageStateDelivered); - linphone_chat_message_set_incoming(pendingMessage); + lDebug() << "New line received, forge a message with content " << pendingMessage->getPrivate()->getText().c_str(); + pendingMessage->setFromAddress(peerAddress); + pendingMessage->setToAddress(linphone_call_get_dest_proxy(call) ? linphone_address_as_string(linphone_call_get_dest_proxy(call)->identity_address) : linphone_core_get_identity(core)); + pendingMessage->getPrivate()->setState(ChatMessage::State::Delivered); + pendingMessage->getPrivate()->setDirection(ChatMessage::Direction::Incoming); if (lp_config_get_int(core->config, "misc", "store_rtt_messages", 1) == 1) storeOrUpdateMessage(pendingMessage); @@ -85,16 +79,15 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp else unreadCount++; chatMessageReceived(pendingMessage); - linphone_chat_message_unref(pendingMessage); pendingMessage = nullptr; for (auto &rttChars : receivedRttCharacters) ms_free(rttChars); receivedRttCharacters.clear(); } else { char *value = Utils::utf8ToChar(character); - char *text = (char *)linphone_chat_message_get_text(pendingMessage); - linphone_chat_message_set_text(pendingMessage, ms_strcat_printf(text, value)); - lDebug() << "Received RTT character: " << value << " (" << character << "), pending text is " << linphone_chat_message_get_text(pendingMessage); + char *text = (char *)pendingMessage->getPrivate()->getText().c_str(); + pendingMessage->getPrivate()->setText(ms_strcat_printf(text, value)); + lDebug() << "Received RTT character: " << value << " (" << character << "), pending text is " << pendingMessage->getPrivate()->getText(); delete value; } } @@ -106,12 +99,11 @@ RealTimeTextChatRoom::RealTimeTextChatRoom (LinphoneCore *core, const Address &p // ----------------------------------------------------------------------------- -void RealTimeTextChatRoom::sendMessage (LinphoneChatMessage *msg) { +void RealTimeTextChatRoom::sendMessage (std::shared_ptr msg) { L_D(); if (d->call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(d->call))) { uint32_t new_line = 0x2028; - linphone_chat_message_put_char(msg, new_line); - linphone_chat_message_unref(msg); + msg->putCharacter(new_line); } } diff --git a/src/chat/real-time-text-chat-room.h b/src/chat/real-time-text-chat-room.h index 2f3e3f40d..524296521 100644 --- a/src/chat/real-time-text-chat-room.h +++ b/src/chat/real-time-text-chat-room.h @@ -37,7 +37,7 @@ public: RealTimeTextChatRoom (LinphoneCore *core, const Address &peerAddress); virtual ~RealTimeTextChatRoom () = default; - void sendMessage (LinphoneChatMessage *msg) override; + void sendMessage (std::shared_ptr msg) override; uint32_t getChar () const; LinphoneCall *getCall () const; From 613a6ff76307053f5dda4bb14c4474caad1a9b6f Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 2 Oct 2017 10:14:43 +0200 Subject: [PATCH 0259/2215] feat(core): add a private-access file to access private data --- include/linphone/utils/private-access.h | 60 +++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 include/linphone/utils/private-access.h diff --git a/include/linphone/utils/private-access.h b/include/linphone/utils/private-access.h new file mode 100644 index 000000000..776fd8043 --- /dev/null +++ b/include/linphone/utils/private-access.h @@ -0,0 +1,60 @@ +/* + * private-access.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +// ============================================================================= +// Tools to get/set private data of Cpp objects. +// +// See: https://bloglitb.blogspot.fr/2011/12/access-to-private-members-safer.html +// See: http://en.cppreference.com/w/cpp/language/adl +// See: http://en.cppreference.com/w/cpp/language/friend +// ============================================================================= + +#ifndef _PRIVATE_ACCESS_H_ +#define _PRIVATE_ACCESS_H_ + +#include + +#define L_INTERNAL_STRUCT_L_ATTR_GET(CLASS, ATTR_NAME) AttrGet ## _ ## CLASS ## _ ## ATTR_NAME +#define L_INTERNAL_STRUCT_ATTR_SPY(ATTR_NAME) AttrSpy ## _ ## ATTR_NAME + +#define L_ENABLE_ATTR_ACCESS(CLASS, ATTR_TYPE, ATTR_NAME) \ + template \ + struct L_INTERNAL_STRUCT_L_ATTR_GET(CLASS, ATTR_NAME) { \ + friend constexpr ATTR_TYPE (CLASS::*get(AttrSpy *)) { \ + return Attr; \ + } \ + }; \ + template \ + struct L_INTERNAL_STRUCT_ATTR_SPY(ATTR_NAME); \ + template<> \ + struct L_INTERNAL_STRUCT_ATTR_SPY(ATTR_NAME) { \ + friend constexpr ATTR_TYPE (CLASS::*get(L_INTERNAL_STRUCT_ATTR_SPY(ATTR_NAME) *)); \ + }; \ + template struct L_INTERNAL_STRUCT_L_ATTR_GET(CLASS, ATTR_NAME)< \ + L_INTERNAL_STRUCT_ATTR_SPY(ATTR_NAME), \ + &CLASS::ATTR_NAME \ + >; + +// Warning: Allow to modify const data. +// Returns a ref to `ATTR_NAME`. +#define L_ATTR_GET(OBJECT, ATTR_NAME) \ + (const_cast::type &>(OBJECT)).*get( \ + static_cast::type> *>(nullptr) \ + ) + +#endif // ifndef _PRIVATE_ACCESS_H_ From fc12fb1e0e8af7e924d1e4a686f5e7b0f254fd4b Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 2 Oct 2017 10:16:08 +0200 Subject: [PATCH 0260/2215] fix(private-access): coding style --- include/linphone/utils/private-access.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linphone/utils/private-access.h b/include/linphone/utils/private-access.h index 776fd8043..8d907f2d0 100644 --- a/include/linphone/utils/private-access.h +++ b/include/linphone/utils/private-access.h @@ -35,7 +35,7 @@ #define L_ENABLE_ATTR_ACCESS(CLASS, ATTR_TYPE, ATTR_NAME) \ template \ struct L_INTERNAL_STRUCT_L_ATTR_GET(CLASS, ATTR_NAME) { \ - friend constexpr ATTR_TYPE (CLASS::*get(AttrSpy *)) { \ + friend constexpr ATTR_TYPE (CLASS::*get(AttrSpy *)) { \ return Attr; \ } \ }; \ From c67b913d0f8b567341ffea29453d40d5de23661c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 2 Oct 2017 10:32:59 +0200 Subject: [PATCH 0261/2215] Moved send code from ChatMessage to ChatRoom --- src/chat/chat-message-p.h | 2 ++ src/chat/chat-message.cpp | 24 +++-------------- src/chat/chat-message.h | 55 ++++++++++++++++++++++----------------- src/chat/chat-room.cpp | 25 ++++++++++++++++-- 4 files changed, 60 insertions(+), 46 deletions(-) diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 3988857ff..4f770eabc 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -45,6 +45,8 @@ public: void setTime(time_t time); + void setIsReadOnly(bool readOnly); + unsigned int getStorageId() const; void setStorageId(unsigned int id); diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index d3bc1b039..618468aa5 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -27,8 +27,6 @@ #include "chat-message-p.h" #include "content/content.h" -#include "modifier/multipart-chat-message-modifier.h" -#include "modifier/cpim-chat-message-modifier.h" #include "chat-room-p.h" #include "real-time-text-chat-room.h" @@ -65,6 +63,10 @@ void ChatMessagePrivate::setTime(time_t t) { time = t; } +void ChatMessagePrivate::setIsReadOnly(bool readOnly) { + isReadOnly = readOnly; +} + void ChatMessagePrivate::setState(ChatMessage::State s) { L_Q(); @@ -1107,24 +1109,6 @@ void ChatMessage::updateState(State state) { } } -void ChatMessage::send () { - L_D(); - - if (d->contents.size() > 1) { - MultipartChatMessageModifier mcmm; - mcmm.encode(d); - } - - LinphoneCore *lc = getChatRoom()->getCore(); - LpConfig *lpc = linphone_core_get_config(lc); - if (lp_config_get_int(lpc, "sip", "use_cpim", 0) == 1) { - CpimChatMessageModifier ccmm; - ccmm.encode(d); - } - - d->isReadOnly = true; -} - void ChatMessage::reSend() { L_D(); diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index 043e1fb1e..ba974e010 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -61,59 +61,66 @@ public: Displayed }; - ChatMessage (const std::shared_ptr &room); - virtual ~ChatMessage () = default; + ChatMessage(const std::shared_ptr &room); + virtual ~ChatMessage() = default; LinphoneChatMessage * getBackPtr(); - std::shared_ptr getChatRoom () const; + std::shared_ptr getChatRoom() const; // ----------------------------------------------------------------------------- // Methods // ----------------------------------------------------------------------------- void store(); + void updateState(State state); - void send(); + void reSend(); + void sendDeliveryNotification(LinphoneReason reason); + void sendDisplayNotification(); + int uploadFile(); + int downloadFile(); + void cancelFileTransfer(); + int putCharacter(uint32_t character); // ----------------------------------------------------------------------------- // Getters & setters // ----------------------------------------------------------------------------- - Direction getDirection () const; - bool isOutgoing () const; - bool isIncoming () const; + Direction getDirection() const; + bool isOutgoing() const; + bool isIncoming() const; const std::string& getExternalBodyUrl() const; void setExternalBodyUrl(const std::string &url); - time_t getTime () const; + time_t getTime() const; - bool isSecured () const; + bool isSecured() const; void setIsSecured(bool isSecured); State getState() const; - const std::string& getId () const; - void setId (const std::string&); + const std::string& getId() const; + void setId(const std::string&); bool isRead() const; - const std::string& getAppdata () const; - void setAppdata (const std::string &appData); + const std::string& getAppdata() const; + void setAppdata(const std::string &appData); - const Address& getFromAddress () const; + const Address& getFromAddress() const; void setFromAddress(Address from); void setFromAddress(const std::string& from); - const Address& getToAddress () const; + const Address& getToAddress() const; void setToAddress(Address to); void setToAddress(const std::string& to); @@ -123,20 +130,20 @@ public: bool isToBeStored() const; void setIsToBeStored(bool store); - const LinphoneErrorInfo * getErrorInfo () const; + const LinphoneErrorInfo * getErrorInfo() const; - bool isReadOnly () const; + bool isReadOnly() const; - std::list > getContents () const; - void addContent (const std::shared_ptr &content); - void removeContent (const std::shared_ptr &content); + std::list > getContents() const; + void addContent(const std::shared_ptr &content); + void removeContent(const std::shared_ptr &content); - std::string getCustomHeaderValue (const std::string &headerName) const; - void addCustomHeader (const std::string &headerName, const std::string &headerValue); - void removeCustomHeader (const std::string &headerName); + std::string getCustomHeaderValue(const std::string &headerName) const; + void addCustomHeader(const std::string &headerName, const std::string &headerValue); + void removeCustomHeader(const std::string &headerName); protected: - explicit ChatMessage (ChatMessagePrivate &p); + explicit ChatMessage(ChatMessagePrivate &p); private: L_DECLARE_PRIVATE(ChatMessage); diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 8d48b34b1..ef182ef6b 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -23,6 +23,8 @@ #include "c-wrapper/c-wrapper.h" #include "chat-room-p.h" +#include "modifier/multipart-chat-message-modifier.h" +#include "modifier/cpim-chat-message-modifier.h" #include "imdn.h" #include "content/content.h" #include "chat-message-p.h" @@ -810,6 +812,10 @@ void ChatRoom::sendMessage (shared_ptr msg) { } } msg->setFromAddress(identity); + + // --------------------------------------- + // Start of message modification + // --------------------------------------- int retval = -1; LinphoneImEncryptionEngine *imee = d->core->im_encryption_engine; @@ -824,6 +830,20 @@ void ChatRoom::sendMessage (shared_ptr msg) { } } + if (msg->getContents().size() > 1) { + MultipartChatMessageModifier mcmm; + mcmm.encode(msg->getPrivate()); + } + + if (lp_config_get_int(d->core->config, "sip", "use_cpim", 0) == 1) { + CpimChatMessageModifier ccmm; + ccmm.encode(msg->getPrivate()); + } + + // --------------------------------------- + // End of message modification + // --------------------------------------- + if (!op) { /* Sending out of call */ msg->getPrivate()->setSalOp(op = new SalMessageOp(d->core->sal)); @@ -843,7 +863,7 @@ void ChatRoom::sendMessage (shared_ptr msg) { } if (!msg->getExternalBodyUrl().empty()) { - char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"",msg->getExternalBodyUrl().empty()); + char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", msg->getExternalBodyUrl().c_str()); auto msgOp = dynamic_cast(op); msgOp->send_message(identity.c_str(), d->peerAddress.asString().c_str(), content_type, nullptr, nullptr); ms_free(content_type); @@ -864,7 +884,7 @@ void ChatRoom::sendMessage (shared_ptr msg) { /* We replace the encrypted content type by the original one */ msg->getPrivate()->setContentType(clearTextContentType); } - msg->setId(op->get_call_id()); /* must be known at that time */ + msg->setId(op->get_call_id()); /* must be known at that time */ d->storeOrUpdateMessage(msg); if (d->isComposing) @@ -890,6 +910,7 @@ void ChatRoom::sendMessage (shared_ptr msg) { /* If operation failed, we should not change message state */ if (msg->isOutgoing()) { + msg->getPrivate()->setIsReadOnly(true); msg->getPrivate()->setState(ChatMessage::State::InProgress); } } From 3544ad224f37e559df2668f0c2bac3846d4f913c Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 2 Oct 2017 10:41:20 +0200 Subject: [PATCH 0262/2215] feat(Content): add `isEmpty` method --- src/content/content.cpp | 4 ++++ src/content/content.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/content/content.cpp b/src/content/content.cpp index 23b56f3cb..0557e3955 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -128,4 +128,8 @@ size_t Content::getSize () const { return d->body.size(); } +bool Content::isEmpty () const { + return getSize() == 0; +} + LINPHONE_END_NAMESPACE diff --git a/src/content/content.h b/src/content/content.h index 62b5cbe20..b68e7a344 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -48,12 +48,16 @@ public: const std::vector &getBody () const; std::string getBodyAsString () const; + void setBody (const std::vector &body); void setBody (const std::vector &&body); void setBody (const std::string &body); void setBody (const void *buffer, size_t size); + size_t getSize () const; + bool isEmpty () const; + private: L_DECLARE_PRIVATE(Content); }; From 11f9f38d261f606fa3969b6d18b483c0bac7bce5 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 2 Oct 2017 11:08:12 +0200 Subject: [PATCH 0263/2215] fix(Content): use move operator correctly --- src/content/content.cpp | 4 ++-- src/content/content.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/content.cpp b/src/content/content.cpp index 0557e3955..fb2b64113 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -107,9 +107,9 @@ void Content::setBody (const vector &body) { d->body = body; } -void Content::setBody (const std::vector &&body) { +void Content::setBody (std::vector &&body) { L_D(); - d->body = body; + d->body = move(body); } void Content::setBody (const string &body) { diff --git a/src/content/content.h b/src/content/content.h index b68e7a344..5c7b00c3a 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -50,7 +50,7 @@ public: std::string getBodyAsString () const; void setBody (const std::vector &body); - void setBody (const std::vector &&body); + void setBody (std::vector &&body); void setBody (const std::string &body); void setBody (const void *buffer, size_t size); From 004d7741801e616a8ec2c6931bdd50dfb398f652 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 2 Oct 2017 11:09:39 +0200 Subject: [PATCH 0264/2215] fix(windows): add missing LINPHONE_PUBLIC on exported classes --- src/conference/conference-interface.h | 2 +- src/conference/conference.h | 2 +- src/conference/remote-conference.h | 2 +- src/conference/session/call-session-listener.h | 2 +- src/conference/session/call-session.h | 2 +- src/conference/session/media-session.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index b4241d34c..1cd62ec6d 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -30,7 +30,7 @@ LINPHONE_BEGIN_NAMESPACE -class ConferenceInterface { +class LINPHONE_PUBLIC ConferenceInterface { public: virtual ~ConferenceInterface() = default; diff --git a/src/conference/conference.h b/src/conference/conference.h index 403602459..b9a89cd31 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -34,7 +34,7 @@ LINPHONE_BEGIN_NAMESPACE class CallSessionPrivate; -class Conference : public ConferenceInterface, public CallSessionListener { +class LINPHONE_PUBLIC Conference : public ConferenceInterface, public CallSessionListener { friend class CallSessionPrivate; public: diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index c6eda721d..8ae6c2f1f 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -26,7 +26,7 @@ LINPHONE_BEGIN_NAMESPACE -class RemoteConference : public Conference, public ConferenceListener { +class LINPHONE_PUBLIC RemoteConference : public Conference, public ConferenceListener { public: RemoteConference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); virtual ~RemoteConference(); diff --git a/src/conference/session/call-session-listener.h b/src/conference/session/call-session-listener.h index e5dd8d8ca..cae85a71e 100644 --- a/src/conference/session/call-session-listener.h +++ b/src/conference/session/call-session-listener.h @@ -23,7 +23,7 @@ LINPHONE_BEGIN_NAMESPACE -class CallSessionListener { +class LINPHONE_PUBLIC CallSessionListener { public: virtual ~CallSessionListener() = default; diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index 74b95461b..a43331c2e 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -33,7 +33,7 @@ LINPHONE_BEGIN_NAMESPACE class CallPrivate; class CallSessionPrivate; -class CallSession : public Object { +class LINPHONE_PUBLIC CallSession : public Object { friend class CallPrivate; friend class ClientGroupChatRoom; diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index 00aeebdfe..4de168815 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -30,7 +30,7 @@ class CallPrivate; class IceAgent; class MediaSessionPrivate; -class MediaSession : public CallSession { +class LINPHONE_PUBLIC MediaSession : public CallSession { friend class CallPrivate; friend class IceAgent; From 4bbf7f1fb002f9fcdec187c8d9357345680f7dd9 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 2 Oct 2017 11:10:51 +0200 Subject: [PATCH 0265/2215] Fixed ChatMessage legacy getContentType and getText methods --- src/chat/chat-message.cpp | 13 +++++++++++-- src/chat/chat-room.cpp | 7 +++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 618468aa5..70558d927 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -137,8 +137,12 @@ string ChatMessagePrivate::getSalCustomHeaderValue(const string& name) { const string& ChatMessagePrivate::getContentType() { if (internalContent) { - ContentType contentType = internalContent->getContentType(); - cContentType = contentType.asString(); + cContentType = internalContent->getContentType().asString(); + } else { + if (contents.size() > 0) { + shared_ptr content = contents.front(); + cContentType = content->getContentType().asString(); + } } return cContentType; } @@ -153,6 +157,11 @@ void ChatMessagePrivate::setContentType(const string& contentType) { const string& ChatMessagePrivate::getText() { if (internalContent) { cText = internalContent->getBodyAsString(); + } else { + if (contents.size() > 0) { + shared_ptr content = contents.front(); + cText = content->getBodyAsString(); + } } return cText; } diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index ef182ef6b..6b244668d 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -580,14 +580,10 @@ void ChatRoom::compose () { } shared_ptr ChatRoom::createFileTransferMessage (const LinphoneContent *initialContent) { - L_D(); - shared_ptr chatMessage = createMessage(); chatMessage->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); chatMessage->getPrivate()->setFileTransferInformation(linphone_content_copy(initialContent)); - chatMessage->setToAddress(d->peerAddress); - chatMessage->setFromAddress(linphone_core_get_identity(d->core)); return chatMessage; } @@ -604,8 +600,11 @@ shared_ptr ChatRoom::createMessage (const string &message) { } shared_ptr ChatRoom::createMessage () { + L_D(); shared_ptr chatMessage = make_shared(static_pointer_cast(shared_from_this())); chatMessage->getPrivate()->setTime(ms_time(0)); + chatMessage->setToAddress(d->peerAddress); + chatMessage->setFromAddress(linphone_core_get_identity(d->core)); return chatMessage; } From 6984378aa921609e42ed2c8c4b201e628cbb2c00 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 28 Sep 2017 13:13:08 +0200 Subject: [PATCH 0266/2215] add linphone_core_cbs_set_message_received_unable_decrypt linphone_core_cbs_get_message_received_unable_decrypt --- include/linphone/core.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/linphone/core.h b/include/linphone/core.h index 55b6fc282..e78ba8e4c 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -378,6 +378,20 @@ LINPHONE_PUBLIC void linphone_core_cbs_set_message_received(LinphoneCoreCbs *cbs */ LINPHONE_PUBLIC LinphoneCoreCbsMessageReceivedCb linphone_core_cbs_get_message_received(LinphoneCoreCbs *cbs); +/** + * Set the #LinphoneCoreCbsMessageReceivedUnableDecryptCb callback. + * @param[in] cbs A #LinphoneCoreCbs. + * @param[in] cb The callback. + */ +LINPHONE_PUBLIC void linphone_core_cbs_set_message_received_unable_decrypt(LinphoneCoreCbs *cbs, LinphoneCoreCbsMessageReceivedUnableDecryptCb cb); + +/** + * Get the #LinphoneCoreCbsMessageReceivedUnableDecryptCb callback. + * @param[in] cbs A #LinphoneCoreCbs. + * @return The callback. + */ +LINPHONE_PUBLIC LinphoneCoreCbsMessageReceivedUnableDecryptCb linphone_core_cbs_get_message_received_unable_decrypt(LinphoneCoreCbs *cbs); + /** * Set the #LinphoneCoreCbsIsComposingReceivedCb callback. * @param[in] cbs A #LinphoneCoreCbs. From 38987363ea4124c16f99be0902d61089c3036bfe Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 2 Oct 2017 11:17:36 +0200 Subject: [PATCH 0267/2215] fix implicit cast warnings --- coreapi/sal/event_op.cpp | 4 ++-- coreapi/sal/register_op.cpp | 2 +- coreapi/sal/sal.cpp | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/coreapi/sal/event_op.cpp b/coreapi/sal/event_op.cpp index d3f3b8ca6..42882d5ae 100644 --- a/coreapi/sal/event_op.cpp +++ b/coreapi/sal/event_op.cpp @@ -226,7 +226,7 @@ void SalSubscribeOp::subscribe_refresher_listener_cb (belle_sip_refresher_t* ref if (status_code == 503) { /*refresher returns 503 for IO error*/ reason = SalReasonIOError; } - sal_error_info_set(&op->error_info, reason, "SIP", status_code,reason_phrase,NULL); + sal_error_info_set(&op->error_info, reason, "SIP", (int)status_code, reason_phrase, NULL); op->root->callbacks.subscribe_response(op,sss, will_retry); }else if (status_code==0){ op->root->callbacks.on_expire(op); @@ -365,7 +365,7 @@ void SalPublishOp::publish_refresher_listener_cb (belle_sip_refresher_t* refresh sip_etag_string = belle_sip_header_get_unparsed_value(sip_etag); } op->set_entity_tag(sip_etag_string); - sal_error_info_set(&op->error_info,SalReasonUnknown, "SIP", status_code,reason_phrase,NULL); + sal_error_info_set(&op->error_info,SalReasonUnknown, "SIP", (int)status_code, reason_phrase, NULL); op->assign_recv_headers((belle_sip_message_t*)response); op->root->callbacks.on_publish_response(op); } diff --git a/coreapi/sal/register_op.cpp b/coreapi/sal/register_op.cpp index d06875a22..437b3b843 100644 --- a/coreapi/sal/register_op.cpp +++ b/coreapi/sal/register_op.cpp @@ -56,7 +56,7 @@ void SalRegisterOp::register_refresher_listener(belle_sip_refresher_t* refresher /*only take first one for now*/ op->auth_info=sal_auth_info_create((belle_sip_auth_event_t*)(belle_sip_refresher_get_auth_events(refresher)->data)); } - sal_error_info_set(&op->error_info,SalReasonUnknown, "SIP", status_code,reason_phrase,NULL); + sal_error_info_set(&op->error_info,SalReasonUnknown, "SIP", (int)status_code, reason_phrase, NULL); if (status_code>=200){ op->assign_recv_headers((belle_sip_message_t*)response); } diff --git a/coreapi/sal/sal.cpp b/coreapi/sal/sal.cpp index 20a859df1..1222c757c 100644 --- a/coreapi/sal/sal.cpp +++ b/coreapi/sal/sal.cpp @@ -459,7 +459,7 @@ int Sal::add_listen_port(SalAddress* addr, bool_t is_tunneled) { sal_transport_to_string(sal_address_get_transport(addr))); } if (lp) { - belle_sip_listening_point_set_keep_alive(lp,this->keep_alive); + belle_sip_listening_point_set_keep_alive(lp,(int)this->keep_alive); result = belle_sip_provider_add_listening_point(this->prov,lp); if (sal_address_get_transport(addr)==SalTransportTLS) { set_tls_properties(); @@ -526,7 +526,7 @@ void Sal::make_supported_header(){ const char *tag=(const char*)it->data; size_t taglen=strlen(tag); if (alltags==NULL || (written+taglen+1>=buflen)) alltags=reinterpret_cast(ms_realloc(alltags,(buflen=buflen*2))); - written+=snprintf(alltags+written,buflen-written,it->next ? "%s, " : "%s",tag); + written+=(size_t)snprintf(alltags+written,buflen-written,it->next ? "%s, " : "%s",tag); } if (alltags){ this->supported=belle_sip_header_create("Supported",alltags); @@ -606,7 +606,7 @@ void Sal::set_keepalive_period(unsigned int value) { for (iterator=belle_sip_provider_get_listening_points(this->prov);iterator!=NULL;iterator=iterator->next) { lp=(belle_sip_listening_point_t*)iterator->data; if (this->use_tcp_tls_keep_alive || strcasecmp(belle_sip_listening_point_get_transport(lp),"udp")==0) { - belle_sip_listening_point_set_keep_alive(lp,this->keep_alive); + belle_sip_listening_point_set_keep_alive(lp,(int)this->keep_alive); } } } @@ -713,7 +713,7 @@ int Sal::generate_uuid(char *uuid, size_t len) { return -1; } for (i = 0; i < 6; i++) - written+=snprintf(uuid+written,len-written,"%2.2x", uuid_struct.node[i]); + written+=snprintf(uuid+written,len-(unsigned long)written,"%2.2x", uuid_struct.node[i]); uuid[len-1]='\0'; return 0; } From c8616f0eb37d27e43b8b0d085506ebf586f4d67f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 2 Oct 2017 11:56:56 +0200 Subject: [PATCH 0268/2215] Done ChatRoom::release --- src/chat/chat-room.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 6b244668d..e8fa7b045 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -41,12 +41,7 @@ LINPHONE_BEGIN_NAMESPACE ChatRoomPrivate::ChatRoomPrivate (LinphoneCore *core) : core(core), isComposingHandler(core, this) {} -ChatRoomPrivate::~ChatRoomPrivate () { - /*for (auto &message : transientMessages) - linphone_chat_message_release(message); - if (pendingMessage) - linphone_chat_message_unref(pendingMessage);*/ -} +ChatRoomPrivate::~ChatRoomPrivate () {} // ----------------------------------------------------------------------------- @@ -92,10 +87,15 @@ void ChatRoomPrivate::release () { L_Q(); isComposingHandler.stopTimers(); - /*for (auto &message : weakMessages) - linphone_chat_message_deactivate(message); - for (auto &message : transientMessages) - linphone_chat_message_deactivate(message);*/ + for (auto &message : weakMessages) { + shared_ptr msg(message); + msg->cancelFileTransfer(); + msg->getPrivate()->setChatRoom(nullptr); + } + for (auto &message : transientMessages) { + message->cancelFileTransfer(); + message->getPrivate()->setChatRoom(nullptr); + } core = nullptr; linphone_chat_room_unref(L_GET_C_BACK_PTR(q)); From 655ce511486557500f84450b21e1b5099d9c301d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 2 Oct 2017 12:14:50 +0200 Subject: [PATCH 0269/2215] Fixed message in call dialog --- coreapi/callbacks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 8a70e1718..45a0e1d87 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -416,7 +416,7 @@ static void message_received(SalOp *op, const SalMessage *msg){ if (reason == LinphoneReasonNone) { linphone_core_message_received(lc, op, msg); } - auto messageOp = dynamic_cast(op); + auto messageOp = dynamic_cast(op); messageOp->reply(linphone_reason_to_sal(reason)); if (!call) op->release(); } From d2c788a0c787fae480170e9ea81b8aa733fc93dd Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 2 Oct 2017 12:23:41 +0200 Subject: [PATCH 0270/2215] Fixed crash due to bad weak_ptr in ChatRoom --- src/chat/chat-room.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index e8fa7b045..f08d677bb 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -88,9 +88,12 @@ void ChatRoomPrivate::release () { isComposingHandler.stopTimers(); for (auto &message : weakMessages) { - shared_ptr msg(message); - msg->cancelFileTransfer(); - msg->getPrivate()->setChatRoom(nullptr); + try { + shared_ptr msg(message); + msg->cancelFileTransfer(); + msg->getPrivate()->setChatRoom(nullptr); + } catch(const std::bad_weak_ptr& e) {} + } for (auto &message : transientMessages) { message->cancelFileTransfer(); From 33d7a384afecf9a52b9c06bdf16f2a11fdb45dab Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 2 Oct 2017 12:31:36 +0200 Subject: [PATCH 0271/2215] feat(General): remove LINPHONE_NAMESPACE --- coreapi/authentication.c | 2 +- coreapi/bellesip_sal/sal_op_impl.c | 2 +- coreapi/callbacks.c | 4 +- coreapi/carddav.c | 2 +- coreapi/chat.c | 2 +- coreapi/error_info.c | 2 +- coreapi/event.c | 4 +- coreapi/friend.c | 2 +- coreapi/friendlist.c | 2 +- coreapi/info.c | 2 +- coreapi/linphonecore.c | 2 +- coreapi/presence.c | 2 +- coreapi/private.h | 62 ++++++++++++++-------------- coreapi/proxy.c | 2 +- coreapi/sal/sal.cpp | 2 +- coreapi/vcard.cc | 2 +- include/linphone/utils/general.h | 6 +-- src/c-wrapper/api/c-address.cpp | 4 +- src/c-wrapper/api/c-call.cpp | 10 ++--- src/c-wrapper/api/c-chat-message.cpp | 2 +- src/c-wrapper/api/c-event-log.cpp | 8 ++-- src/c-wrapper/internal/c-tools.h | 42 +++++++++---------- src/chat/cpim/parser/cpim-parser.cpp | 16 +++---- src/logger/logger.h | 10 ++--- tester/cpim-tester.cpp | 2 +- 25 files changed, 97 insertions(+), 99 deletions(-) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index c79769527..e884faf5a 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -28,7 +28,7 @@ #include "c-wrapper/c-wrapper.h" -using namespace LINPHONE_NAMESPACE; +using namespace LinphonePrivate; static void _linphone_auth_info_uninit(LinphoneAuthInfo *obj); static void _linphone_auth_info_copy(LinphoneAuthInfo *dst, const LinphoneAuthInfo *src); diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 7880fa4c6..5040f6d01 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -19,7 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "sal_impl.h" #include "sal/sal.hpp" -using namespace LINPHONE_NAMESPACE; +using namespace LinphonePrivate; SalReason _sal_reason_from_sip_code(int code) { if (code>=100 && code<300) return SalReasonNone; diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 45a0e1d87..a19d9924f 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -42,7 +42,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "conference/session/media-session.h" #include "conference/session/media-session-p.h" -using namespace LINPHONE_NAMESPACE; +using namespace LinphonePrivate; static void register_failure(SalOp *op); @@ -62,7 +62,7 @@ static bool_t already_a_call_with_remote_address(const LinphoneCore *lc, const L } -static LinphoneCall * look_for_broken_call_to_replace(LINPHONE_NAMESPACE::SalOp *h, LinphoneCore *lc) { +static LinphoneCall * look_for_broken_call_to_replace(LinphonePrivate::SalOp *h, LinphoneCore *lc) { const bctbx_list_t *calls = linphone_core_get_calls(lc); const bctbx_list_t *it = calls; while (it != NULL) { diff --git a/coreapi/carddav.c b/coreapi/carddav.c index f874b325e..91a742a4a 100644 --- a/coreapi/carddav.c +++ b/coreapi/carddav.c @@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/core.h" #include "private.h" -using namespace LINPHONE_NAMESPACE; +using namespace LinphonePrivate; LinphoneCardDavContext* linphone_carddav_context_new(LinphoneFriendList *lfl) { LinphoneCardDavContext *carddav_context = NULL; diff --git a/coreapi/chat.c b/coreapi/chat.c index 3797ce69a..d17b6cef7 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -43,7 +43,7 @@ #include "content/content-type.h" using namespace std; -using namespace LINPHONE_NAMESPACE; +using namespace LinphonePrivate; void linphone_core_disable_chat(LinphoneCore *lc, LinphoneReason deny_reason) { lc->chat_deny_code = deny_reason; diff --git a/coreapi/error_info.c b/coreapi/error_info.c index cbbaab7b0..556cb35f1 100644 --- a/coreapi/error_info.c +++ b/coreapi/error_info.c @@ -197,7 +197,7 @@ void linphone_error_info_from_sal_reason_ei(LinphoneErrorInfo *ei, const SalErro } } -void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const LINPHONE_NAMESPACE::SalOp *op){ +void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const LinphonePrivate::SalOp *op){ if (op==NULL) { /*leave previous values in LinphoneErrorInfo, the op may have been released already.*/ return; diff --git a/coreapi/event.c b/coreapi/event.c index 1f7ebe2c5..5b9b0a989 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" -using namespace LINPHONE_NAMESPACE; +using namespace LinphonePrivate; const char * linphone_subscription_dir_to_string(LinphoneSubscriptionDir dir){ switch(dir){ @@ -81,7 +81,7 @@ static void linphone_event_release(LinphoneEvent *lev){ linphone_event_unref(lev); } -static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, LINPHONE_NAMESPACE::SalEventOp *op){ +static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, LinphonePrivate::SalEventOp *op){ LinphoneEvent *lev=belle_sip_object_new(LinphoneEvent); lev->lc=lc; lev->dir=dir; diff --git a/coreapi/friend.c b/coreapi/friend.c index 20e7a1f8e..15df1680c 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -43,7 +43,7 @@ #include "c-wrapper/c-wrapper.h" using namespace std; -using namespace LINPHONE_NAMESPACE; +using namespace LinphonePrivate; const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){ const char *str=NULL; diff --git a/coreapi/friendlist.c b/coreapi/friendlist.c index 113ca9ff4..2589c4f1d 100644 --- a/coreapi/friendlist.c +++ b/coreapi/friendlist.c @@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" -using namespace LINPHONE_NAMESPACE; +using namespace LinphonePrivate; BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneFriendListCbs); diff --git a/coreapi/info.c b/coreapi/info.c index d4bd92623..3259c94ca 100644 --- a/coreapi/info.c +++ b/coreapi/info.c @@ -28,7 +28,7 @@ #include "c-wrapper/c-wrapper.h" -using namespace LINPHONE_NAMESPACE; +using namespace LinphonePrivate; struct _LinphoneInfoMessage{ belle_sip_object_t base; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 069ec68fd..4948d1d5f 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -130,7 +130,7 @@ void linphone_core_zrtp_cache_db_init(LinphoneCore *lc, const char *fileName); #include "contact_providers_priv.h" -using namespace LINPHONE_NAMESPACE; +using namespace LinphonePrivate; const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc); diff --git a/coreapi/presence.c b/coreapi/presence.c index 7546b756d..071981d59 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" -using namespace LINPHONE_NAMESPACE; +using namespace LinphonePrivate; extern const char *__policy_enum_to_str(LinphoneSubscribePolicy pol); diff --git a/coreapi/private.h b/coreapi/private.h index ce5b184a4..fe4ae5c48 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -221,7 +221,7 @@ void linphone_call_notify_info_message_received(LinphoneCall *call, const Linpho void linphone_call_notify_ack_processing(LinphoneCall *call, LinphoneHeaders *msg, bool_t is_received); LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg); -LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, LINPHONE_NAMESPACE::SalCallOp *op); +LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, LinphonePrivate::SalCallOp *op); void _linphone_call_set_new_params(LinphoneCall *call, const LinphoneCallParams *params); void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message); /* private: */ @@ -229,10 +229,10 @@ LinphoneCallLog * linphone_call_log_new(LinphoneCallDir dir, LinphoneAddress *fr void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state); LinphonePlayer *linphone_call_build_player(LinphoneCall*call); void linphone_call_refresh_sockets(LinphoneCall *call); -void linphone_call_replace_op(LinphoneCall *call, LINPHONE_NAMESPACE::SalOp *op); +void linphone_call_replace_op(LinphoneCall *call, LinphonePrivate::SalOp *op); void linphone_call_reinvite_to_recover_from_connection_loss(LinphoneCall *call); -LINPHONE_NAMESPACE::SalCallOp *linphone_call_get_op(const LinphoneCall *call); +LinphonePrivate::SalCallOp *linphone_call_get_op(const LinphoneCall *call); LinphoneProxyConfig * linphone_call_get_dest_proxy(const LinphoneCall *call); LINPHONE_PUBLIC MediaStream * linphone_call_get_stream(LinphoneCall *call, LinphoneStreamType type); LinphoneCallLog * linphone_call_get_log(const LinphoneCall *call); @@ -318,15 +318,15 @@ void _linphone_friend_release(LinphoneFriend *lf); LINPHONE_PUBLIC void linphone_friend_update_subscribes(LinphoneFriend *fr, bool_t only_when_registered); void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence); void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc); -void linphone_friend_add_incoming_subscription(LinphoneFriend *lf, LINPHONE_NAMESPACE::SalOp *op); -void linphone_friend_remove_incoming_subscription(LinphoneFriend *lf, LINPHONE_NAMESPACE::SalOp *op); +void linphone_friend_add_incoming_subscription(LinphoneFriend *lf, LinphonePrivate::SalOp *op); +void linphone_friend_remove_incoming_subscription(LinphoneFriend *lf, LinphonePrivate::SalOp *op); const char * linphone_friend_phone_number_to_sip_uri(LinphoneFriend *lf, const char *phone_number); const char * linphone_friend_sip_uri_to_phone_number(LinphoneFriend *lf, const char *uri); void linphone_friend_clear_presence_models(LinphoneFriend *lf); -LinphoneFriend *linphone_friend_list_find_friend_by_inc_subscribe(const LinphoneFriendList *list, LINPHONE_NAMESPACE::SalOp *op); -LinphoneFriend *linphone_friend_list_find_friend_by_out_subscribe(const LinphoneFriendList *list, LINPHONE_NAMESPACE::SalOp *op); -LinphoneFriend *linphone_core_find_friend_by_out_subscribe(const LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op); -LinphoneFriend *linphone_core_find_friend_by_inc_subscribe(const LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op); +LinphoneFriend *linphone_friend_list_find_friend_by_inc_subscribe(const LinphoneFriendList *list, LinphonePrivate::SalOp *op); +LinphoneFriend *linphone_friend_list_find_friend_by_out_subscribe(const LinphoneFriendList *list, LinphonePrivate::SalOp *op); +LinphoneFriend *linphone_core_find_friend_by_out_subscribe(const LinphoneCore *lc, LinphonePrivate::SalOp *op); +LinphoneFriend *linphone_core_find_friend_by_inc_subscribe(const LinphoneCore *lc, LinphonePrivate::SalOp *op); MSList *linphone_find_friend_by_address(MSList *fl, const LinphoneAddress *addr, LinphoneFriend **lf); bool_t linphone_core_should_subscribe_friends_only_when_registered(const LinphoneCore *lc); void linphone_core_update_friends_subscriptions(LinphoneCore *lc); @@ -361,19 +361,19 @@ static MS2_INLINE void set_string(char **dest, const char *src, bool_t lowercase } } -void linphone_process_authentication(LinphoneCore* lc, LINPHONE_NAMESPACE::SalOp *op); -void linphone_authentication_ok(LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op); -void linphone_subscription_new(LinphoneCore *lc, LINPHONE_NAMESPACE::SalSubscribeOp *op, const char *from); +void linphone_process_authentication(LinphoneCore* lc, LinphonePrivate::SalOp *op); +void linphone_authentication_ok(LinphoneCore *lc, LinphonePrivate::SalOp *op); +void linphone_subscription_new(LinphoneCore *lc, LinphonePrivate::SalSubscribeOp *op, const char *from); void linphone_core_send_presence(LinphoneCore *lc, LinphonePresenceModel *presence); void linphone_notify_parse_presence(const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result); -void linphone_notify_convert_presence_to_xml(LINPHONE_NAMESPACE::SalOp *op, SalPresenceModel *presence, const char *contact, char **content); -void linphone_notify_recv(LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model); -void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op); +void linphone_notify_convert_presence_to_xml(LinphonePrivate::SalOp *op, SalPresenceModel *presence, const char *contact, char **content); +void linphone_notify_recv(LinphoneCore *lc, LinphonePrivate::SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model); +void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, LinphonePrivate::SalOp *op); void linphone_core_soundcard_hint_check(LinphoneCore* lc); -void linphone_subscription_answered(LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op); -void linphone_subscription_closed(LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op); +void linphone_subscription_answered(LinphoneCore *lc, LinphonePrivate::SalOp *op); +void linphone_subscription_closed(LinphoneCore *lc, LinphonePrivate::SalOp *op); void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc); @@ -422,7 +422,7 @@ LINPHONE_PUBLIC void linphone_core_get_local_ip(LinphoneCore *lc, int af, const LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore *lc, int index); void linphone_proxy_config_write_to_config_file(LinphoneConfig* config,LinphoneProxyConfig *obj, int index); -int linphone_core_message_received(LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op, const SalMessage *msg); +int linphone_core_message_received(LinphoneCore *lc, LinphonePrivate::SalOp *op, const SalMessage *msg); void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, uint32_t character, LinphoneCall *call); void linphone_call_init_media_streams(LinphoneCall *call); @@ -446,7 +446,7 @@ int linphone_call_start_update(LinphoneCall *call); int linphone_call_start_accept_update(LinphoneCall *call, LinphoneCallState next_state, const char *state_info); void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call); bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md); -extern LINPHONE_NAMESPACE::Sal::Callbacks linphone_sal_callbacks; +extern LinphonePrivate::Sal::Callbacks linphone_sal_callbacks; LINPHONE_PUBLIC bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); LINPHONE_PUBLIC bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc); @@ -488,7 +488,7 @@ struct _LinphoneProxyConfig char *contact_uri_params; int expires; int publish_expires; - LINPHONE_NAMESPACE::SalRegisterOp *op; + LinphonePrivate::SalRegisterOp *op; SalCustomHeader *sent_headers; char *type; struct _SipSetupContext *ssctx; @@ -567,7 +567,7 @@ struct _LinphoneFriend{ void *user_data; LinphoneAddress *uri; MSList *insubs; /*list of SalOp. There can be multiple instances of a same Friend that subscribe to our presence*/ - LINPHONE_NAMESPACE::SalPresenceOp *outsub; + LinphonePrivate::SalPresenceOp *outsub; LinphoneSubscribePolicy pol; MSList *presence_models; /* list of LinphoneFriendPresence. It associates SIP URIs and phone numbers with their respective presence models. */ MSList *phone_number_sip_uri_map; /* list of LinphoneFriendPhoneNumberSipUri. It associates phone numbers with their corresponding SIP URIs. */ @@ -805,7 +805,7 @@ struct _LinphoneCore MSFactory* factory; MSList* vtable_refs; int vtable_notify_recursion; - LINPHONE_NAMESPACE::Sal *sal; + LinphonePrivate::Sal *sal; LinphoneGlobalState state; struct _LpConfig *config; MSList *default_audio_codecs; @@ -941,7 +941,7 @@ struct _LinphoneEvent{ LinphoneErrorInfo *ei; LinphoneSubscriptionDir dir; LinphoneCore *lc; - LINPHONE_NAMESPACE::SalEventOp *op; + LinphonePrivate::SalEventOp *op; SalCustomHeader *send_custom_headers; LinphoneSubscriptionState subscription_state; LinphonePublishState publish_state; @@ -1099,8 +1099,8 @@ belle_http_request_t * linphone_chat_message_get_http_request(const LinphoneChat void linphone_chat_message_set_http_request(LinphoneChatMessage *msg, belle_http_request_t *request); void linphone_chat_message_set_file_transfer_information(LinphoneChatMessage *msg, LinphoneContent *content); LinphoneChatMessageDir linphone_chat_message_get_direction(const LinphoneChatMessage *msg); -LINPHONE_NAMESPACE::SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg); -void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, LINPHONE_NAMESPACE::SalOp *op); +LinphonePrivate::SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg); +void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, LinphonePrivate::SalOp *op); void linphone_chat_message_destroy(LinphoneChatMessage* msg); void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state); void linphone_chat_message_set_is_secured(LinphoneChatMessage *msg, bool_t secured); @@ -1119,10 +1119,10 @@ void linphone_chat_message_send_imdn(LinphoneChatMessage *cm, ImdnType imdn_type void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID id); bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc); const char *linphone_core_create_uuid(LinphoneCore *lc); -void linphone_configure_op(LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact); -void linphone_configure_op_with_proxy(LinphoneCore *lc, LINPHONE_NAMESPACE::SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact, LinphoneProxyConfig *proxy); +void linphone_configure_op(LinphoneCore *lc, LinphonePrivate::SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact); +void linphone_configure_op_with_proxy(LinphoneCore *lc, LinphonePrivate::SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact, LinphoneProxyConfig *proxy); void linphone_call_create_op(LinphoneCall *call); -void linphone_core_notify_info_message(LinphoneCore* lc,LINPHONE_NAMESPACE::SalOp *op, SalBodyHandler *body); +void linphone_core_notify_info_message(LinphoneCore* lc,LinphonePrivate::SalOp *op, SalBodyHandler *body); LinphoneContent * linphone_content_new(void); LinphoneContent * linphone_content_copy(const LinphoneContent *ref); SalBodyHandler *sal_body_handler_from_content(const LinphoneContent *content); @@ -1130,12 +1130,12 @@ SalReason linphone_reason_to_sal(LinphoneReason reason); LinphoneReason linphone_reason_from_sal(SalReason reason); void linphone_error_info_to_sal(const LinphoneErrorInfo* ei, SalErrorInfo* sei); LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, int expires); -LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, LINPHONE_NAMESPACE::SalEventOp *op, LinphoneSubscriptionDir dir, const char *name); +LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, LinphonePrivate::SalEventOp *op, LinphoneSubscriptionDir dir, const char *name); void linphone_event_unpublish(LinphoneEvent *lev); /** * Useful for out of dialog notify * */ -LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, LINPHONE_NAMESPACE::SalEventOp *op, LinphoneSubscriptionDir dir, const char *name); +LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, LinphonePrivate::SalEventOp *op, LinphoneSubscriptionDir dir, const char *name); void linphone_event_set_internal(LinphoneEvent *lev, bool_t internal); bool_t linphone_event_is_internal(LinphoneEvent *lev); void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state); @@ -1358,7 +1358,7 @@ void linphone_xml_xpath_context_init_carddav_ns(xmlparsing_context_t *xml_ctx); char * linphone_timestamp_to_rfc3339_string(time_t timestamp); -void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const LINPHONE_NAMESPACE::SalOp *op); +void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const LinphonePrivate::SalOp *op); void payload_type_set_enable(OrtpPayloadType *pt, bool_t value); bool_t payload_type_enabled(const OrtpPayloadType *pt); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 590b144e5..da1d83afd 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -33,7 +33,7 @@ Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) #include "address/address-p.h" #include "c-wrapper/c-wrapper.h" -using namespace LINPHONE_NAMESPACE; +using namespace LinphonePrivate; /*store current config related to server location*/ static void linphone_proxy_config_store_server_config(LinphoneProxyConfig* cfg) { diff --git a/coreapi/sal/sal.cpp b/coreapi/sal/sal.cpp index 1222c757c..fb5d91dd0 100644 --- a/coreapi/sal/sal.cpp +++ b/coreapi/sal/sal.cpp @@ -870,7 +870,7 @@ LINPHONE_END_NAMESPACE /* C++ to C wrapping functions */ /*******************************/ -using namespace LINPHONE_NAMESPACE; +using namespace LinphonePrivate; extern "C" { diff --git a/coreapi/vcard.cc b/coreapi/vcard.cc index 0bd71534d..62d907082 100644 --- a/coreapi/vcard.cc +++ b/coreapi/vcard.cc @@ -32,7 +32,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define VCARD_MD5_HASH_SIZE 16 using namespace std; -using namespace LINPHONE_NAMESPACE; +using namespace LinphonePrivate; struct _LinphoneVcardContext { shared_ptr parser; diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index 060c85df1..515767649 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -21,10 +21,8 @@ // ============================================================================= -#define LINPHONE_NAMESPACE LinphonePrivate - #ifdef __cplusplus - #define LINPHONE_BEGIN_NAMESPACE namespace LINPHONE_NAMESPACE { + #define LINPHONE_BEGIN_NAMESPACE namespace LinphonePrivate { #define LINPHONE_END_NAMESPACE } #else #define LINPHONE_BEGIN_NAMESPACE @@ -68,7 +66,7 @@ void l_assert (const char *condition, const char *file, int line); #ifndef DEBUG #define L_ASSERT(CONDITION) static_cast(false && (CONDITION)) #else - #define L_ASSERT(CONDITION) ((CONDITION) ? static_cast(0) : LINPHONE_NAMESPACE::l_assert(#CONDITION, __FILE__, __LINE__)) + #define L_ASSERT(CONDITION) ((CONDITION) ? static_cast(0) : LinphonePrivate::l_assert(#CONDITION, __FILE__, __LINE__)) #endif #ifndef _MSC_VER diff --git a/src/c-wrapper/api/c-address.cpp b/src/c-wrapper/api/c-address.cpp index c144d0da8..b1f603a65 100644 --- a/src/c-wrapper/api/c-address.cpp +++ b/src/c-wrapper/api/c-address.cpp @@ -28,7 +28,7 @@ using namespace std; // ============================================================================= LinphoneAddress *linphone_address_new (const char *address) { - LINPHONE_NAMESPACE::Address *cppPtr = new LINPHONE_NAMESPACE::Address(L_C_TO_STRING(address)); + LinphonePrivate::Address *cppPtr = new LinphonePrivate::Address(L_C_TO_STRING(address)); if (!cppPtr->isValid()) { delete cppPtr; return nullptr; @@ -94,7 +94,7 @@ LinphoneTransportType linphone_address_get_transport (const LinphoneAddress *add } LinphoneStatus linphone_address_set_transport (LinphoneAddress *address, LinphoneTransportType transport) { - return !L_GET_CPP_PTR_FROM_C_OBJECT(address)->setTransport(static_cast(transport)); + return !L_GET_CPP_PTR_FROM_C_OBJECT(address)->setTransport(static_cast(transport)); } bool_t linphone_address_get_secure (const LinphoneAddress *address) { diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 0a83d27b9..4d0278ed4 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -48,8 +48,8 @@ L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(Call, SalMediaDescription *localdesc; SalMediaDescription *resultdesc; struct _LinphoneCallLog *log; - LINPHONE_NAMESPACE::SalOp *op; - LINPHONE_NAMESPACE::SalOp *ping_op; + LinphonePrivate::SalOp *op; + LinphonePrivate::SalOp *ping_op; LinphoneCallState transfer_state; /*idle if no transfer*/ struct _AudioStream *audiostream; /**/ struct _VideoStream *videostream; @@ -325,7 +325,7 @@ int linphone_call_start_invite (LinphoneCall *call, const LinphoneAddress *desti return 0; } -void linphone_call_replace_op (LinphoneCall *call, LINPHONE_NAMESPACE::SalOp *op) { +void linphone_call_replace_op (LinphoneCall *call, LinphonePrivate::SalOp *op) { #if 0 SalOp *oldop = call->op; LinphoneCallState oldstate = linphone_call_get_state(call); @@ -507,7 +507,7 @@ void linphone_call_refresh_sockets (LinphoneCall *call) { #endif } -LINPHONE_NAMESPACE::SalCallOp * linphone_call_get_op (const LinphoneCall *call) { +LinphonePrivate::SalCallOp * linphone_call_get_op (const LinphoneCall *call) { return L_GET_PRIVATE_FROM_C_OBJECT(call)->getOp(); } @@ -1193,7 +1193,7 @@ LinphoneCall *linphone_call_new_outgoing (LinphoneCore *lc, const LinphoneAddres return call; } -LinphoneCall *linphone_call_new_incoming (LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, LINPHONE_NAMESPACE::SalCallOp *op) { +LinphoneCall *linphone_call_new_incoming (LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, LinphonePrivate::SalCallOp *op) { LinphoneCall *call = L_INIT(Call); L_SET_CPP_PTR_FROM_C_OBJECT(call, make_shared(call, lc, LinphoneCallIncoming, *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 4206aefee..b4d9009ae 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -34,7 +34,7 @@ // ============================================================================= using namespace std; -using namespace LINPHONE_NAMESPACE; +using namespace LinphonePrivate; static void _linphone_chat_message_constructor (LinphoneChatMessage *msg); static void _linphone_chat_message_destructor (LinphoneChatMessage *msg); diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 873988e0a..c1f54e3d0 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -42,7 +42,7 @@ using namespace std; LinphoneEventLog *linphone_event_log_new () { LinphoneEventLog *event_log = _linphone_EventLog_init(); - L_SET_CPP_PTR_FROM_C_OBJECT(event_log, new LINPHONE_NAMESPACE::EventLog()); + L_SET_CPP_PTR_FROM_C_OBJECT(event_log, new LinphonePrivate::EventLog()); return event_log; } @@ -65,8 +65,8 @@ LinphoneCallEvent *linphone_call_event_new (LinphoneEventLogType type, LinphoneC LinphoneCallEvent *call_event = _linphone_CallEvent_init(); L_SET_CPP_PTR_FROM_C_OBJECT( call_event, - new LINPHONE_NAMESPACE::CallEvent( - static_cast(type), + new LinphonePrivate::CallEvent( + static_cast(type), L_GET_CPP_PTR_FROM_C_OBJECT(call) ) ); @@ -124,7 +124,7 @@ LinphoneChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage * LinphoneChatMessageEvent *chat_message_event = _linphone_ChatMessageEvent_init(); L_SET_CPP_PTR_FROM_C_OBJECT( chat_message_event, - new LINPHONE_NAMESPACE::ChatMessageEvent( + new LinphonePrivate::ChatMessageEvent( L_GET_CPP_PTR_FROM_C_OBJECT(chat_message) ) ); diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 2aeb69ac4..8bdb93998 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -489,10 +489,10 @@ LINPHONE_END_NAMESPACE LINPHONE_END_NAMESPACE #define L_CPP_TYPE_OF_C_TYPE(C_TYPE) \ - LINPHONE_NAMESPACE::CTypeMetaInfo::cppType + LinphonePrivate::CTypeMetaInfo::cppType #define L_CPP_TYPE_OF_C_OBJECT(C_OBJECT) \ - LINPHONE_NAMESPACE::CTypeMetaInfo::type>::type>::cppType + LinphonePrivate::CTypeMetaInfo::type>::type>::cppType // ----------------------------------------------------------------------------- // C object declaration. @@ -518,7 +518,7 @@ LINPHONE_END_NAMESPACE // Declare clonable wrapped C object. #define L_DECLARE_C_CLONABLE_STRUCT_IMPL(C_TYPE, ...) \ - static_assert(LINPHONE_NAMESPACE::CTypeMetaInfo::defined, "Type is not defined."); \ + static_assert(LinphonePrivate::CTypeMetaInfo::defined, "Type is not defined."); \ struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ L_CPP_TYPE_OF_C_TYPE(C_TYPE) *cppPtr; \ @@ -547,7 +547,7 @@ LINPHONE_END_NAMESPACE #define L_DECLARE_C_OBJECT_NEW_DEFAULT(C_TYPE, C_NAME) \ Linphone ## C_TYPE * linphone_ ## C_NAME ## _new() { \ Linphone ## C_TYPE *object = _linphone_ ## C_TYPE ## _init(); \ - object->cppPtr = std::make_shared(); \ + object->cppPtr = std::make_shared(); \ return object; \ } @@ -564,11 +564,11 @@ LINPHONE_END_NAMESPACE // Get/set the cpp-ptr of a wrapped C object. #define L_GET_CPP_PTR_FROM_C_OBJECT_1_ARGS(C_OBJECT) \ - LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC(C_OBJECT) + LinphonePrivate::Wrapper::getCppPtrFromC(C_OBJECT) #define L_GET_CPP_PTR_FROM_C_OBJECT_2_ARGS(C_OBJECT, CPP_TYPE) \ - LINPHONE_NAMESPACE::Wrapper::getCppPtrFromC< \ + LinphonePrivate::Wrapper::getCppPtrFromC< \ std::remove_pointer::type, \ - LINPHONE_NAMESPACE::CPP_TYPE \ + LinphonePrivate::CPP_TYPE \ >(C_OBJECT) #define L_GET_CPP_PTR_FROM_C_OBJECT_MACRO_CHOOSER(...) \ @@ -579,13 +579,13 @@ LINPHONE_END_NAMESPACE // Set the cpp-ptr of a wrapped C object. #define L_SET_CPP_PTR_FROM_C_OBJECT(C_OBJECT, CPP_OBJECT) \ - LINPHONE_NAMESPACE::Wrapper::setCppPtrFromC(C_OBJECT, CPP_OBJECT) + LinphonePrivate::Wrapper::setCppPtrFromC(C_OBJECT, CPP_OBJECT) // Get the private data of a shared or simple cpp-ptr. #define L_GET_PRIVATE_1_ARGS(CPP_OBJECT) \ - LINPHONE_NAMESPACE::Wrapper::getPrivate(LINPHONE_NAMESPACE::Utils::getPtr(CPP_OBJECT)) + LinphonePrivate::Wrapper::getPrivate(LinphonePrivate::Utils::getPtr(CPP_OBJECT)) #define L_GET_PRIVATE_2_ARGS(CPP_OBJECT, CPP_TYPE) \ - LINPHONE_NAMESPACE::Wrapper::cast(L_GET_PRIVATE_1_ARGS(CPP_OBJECT)) + LinphonePrivate::Wrapper::cast(L_GET_PRIVATE_1_ARGS(CPP_OBJECT)) #define L_GET_PRIVATE_MACRO_CHOOSER(...) \ L_EXPAND(L_GET_ARG_3(__VA_ARGS__, L_GET_PRIVATE_2_ARGS, L_GET_PRIVATE_1_ARGS)) @@ -595,9 +595,9 @@ LINPHONE_END_NAMESPACE // Get the private data of a shared or simple cpp-ptr of a wrapped C object. #define L_GET_PRIVATE_FROM_C_OBJECT_1_ARGS(C_OBJECT) \ - L_GET_PRIVATE_1_ARGS(LINPHONE_NAMESPACE::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT_1_ARGS(C_OBJECT))) + L_GET_PRIVATE_1_ARGS(LinphonePrivate::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT_1_ARGS(C_OBJECT))) #define L_GET_PRIVATE_FROM_C_OBJECT_2_ARGS(C_OBJECT, CPP_TYPE) \ - L_GET_PRIVATE_1_ARGS(LINPHONE_NAMESPACE::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT_2_ARGS(C_OBJECT, CPP_TYPE))) + L_GET_PRIVATE_1_ARGS(LinphonePrivate::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT_2_ARGS(C_OBJECT, CPP_TYPE))) #define L_GET_PRIVATE_FROM_C_OBJECT_MACRO_CHOOSER(...) \ L_EXPAND(L_GET_ARG_3(__VA_ARGS__, L_GET_PRIVATE_FROM_C_OBJECT_2_ARGS, L_GET_PRIVATE_FROM_C_OBJECT_1_ARGS)) @@ -607,29 +607,29 @@ LINPHONE_END_NAMESPACE // Get the wrapped C object of a C++ object. #define L_GET_C_BACK_PTR(CPP_OBJECT) \ - LINPHONE_NAMESPACE::Wrapper::getCBackPtr(CPP_OBJECT) + LinphonePrivate::Wrapper::getCBackPtr(CPP_OBJECT) // Get/set user data on a wrapped C object. #define L_GET_USER_DATA_FROM_C_OBJECT(C_OBJECT) \ - LINPHONE_NAMESPACE::Wrapper::getUserData( \ - LINPHONE_NAMESPACE::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT)) \ + LinphonePrivate::Wrapper::getUserData( \ + LinphonePrivate::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT)) \ ) #define L_SET_USER_DATA_FROM_C_OBJECT(C_OBJECT, VALUE) \ - LINPHONE_NAMESPACE::Wrapper::setUserData( \ - LINPHONE_NAMESPACE::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT)), \ + LinphonePrivate::Wrapper::setUserData( \ + LinphonePrivate::Utils::getPtr(L_GET_CPP_PTR_FROM_C_OBJECT(C_OBJECT)), \ VALUE \ ) // Transforms cpp list and c list. #define L_GET_C_LIST_FROM_CPP_LIST(CPP_LIST) \ - LINPHONE_NAMESPACE::Wrapper::getCListFromCppList(CPP_LIST) + LinphonePrivate::Wrapper::getCListFromCppList(CPP_LIST) #define L_GET_CPP_LIST_FROM_C_LIST(C_LIST, TYPE) \ - LINPHONE_NAMESPACE::Wrapper::getCppListFromCList(C_LIST) + LinphonePrivate::Wrapper::getCppListFromCList(C_LIST) // Transforms cpp list and c list and convert cpp object to c object. #define L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(CPP_LIST) \ - LINPHONE_NAMESPACE::Wrapper::getResolvedCListFromCppList(CPP_LIST) + LinphonePrivate::Wrapper::getResolvedCListFromCppList(CPP_LIST) #define L_GET_RESOLVED_CPP_LIST_FROM_C_LIST(C_LIST, C_TYPE) \ - LINPHONE_NAMESPACE::Wrapper::getResolvedCppListFromCList(C_LIST) + LinphonePrivate::Wrapper::getResolvedCppListFromCList(C_LIST) #endif // ifndef _C_TOOLS_H_ diff --git a/src/chat/cpim/parser/cpim-parser.cpp b/src/chat/cpim/parser/cpim-parser.cpp index 48f6b7524..19b6018ae 100644 --- a/src/chat/cpim/parser/cpim-parser.cpp +++ b/src/chat/cpim/parser/cpim-parser.cpp @@ -339,19 +339,19 @@ static bool coreHeaderIsValid ( template<> bool Cpim::Parser::coreHeaderIsValid(const string &headerValue) const { L_D(); - return LINPHONE_NAMESPACE::coreHeaderIsValid(d->grammar, "From", headerValue); + return LinphonePrivate::coreHeaderIsValid(d->grammar, "From", headerValue); } template<> bool Cpim::Parser::coreHeaderIsValid(const string &headerValue) const { L_D(); - return LINPHONE_NAMESPACE::coreHeaderIsValid(d->grammar, "To", headerValue); + return LinphonePrivate::coreHeaderIsValid(d->grammar, "To", headerValue); } template<> bool Cpim::Parser::coreHeaderIsValid(const string &headerValue) const { L_D(); - return LINPHONE_NAMESPACE::coreHeaderIsValid(d->grammar, "cc", headerValue); + return LinphonePrivate::coreHeaderIsValid(d->grammar, "cc", headerValue); } template<> @@ -359,7 +359,7 @@ bool Cpim::Parser::coreHeaderIsValid(const string &headerV static const int daysInMonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; L_D(); - if (!LINPHONE_NAMESPACE::coreHeaderIsValid(d->grammar, "DateTime", headerValue)) + if (!LinphonePrivate::coreHeaderIsValid(d->grammar, "DateTime", headerValue)) return false; // Check date. @@ -398,26 +398,26 @@ bool Cpim::Parser::coreHeaderIsValid(const string &headerV template<> bool Cpim::Parser::coreHeaderIsValid(const string &headerValue) const { L_D(); - return LINPHONE_NAMESPACE::coreHeaderIsValid(d->grammar, "Subject", headerValue); + return LinphonePrivate::coreHeaderIsValid(d->grammar, "Subject", headerValue); } template<> bool Cpim::Parser::coreHeaderIsValid(const string &headerValue) const { L_D(); - return LINPHONE_NAMESPACE::coreHeaderIsValid(d->grammar, "NS", headerValue); + return LinphonePrivate::coreHeaderIsValid(d->grammar, "NS", headerValue); } template<> bool Cpim::Parser::coreHeaderIsValid(const string &headerValue) const { L_D(); - return LINPHONE_NAMESPACE::coreHeaderIsValid(d->grammar, "Require", headerValue); + return LinphonePrivate::coreHeaderIsValid(d->grammar, "Require", headerValue); } // ----------------------------------------------------------------------------- bool Cpim::Parser::subjectHeaderLanguageIsValid (const string &language) const { L_D(); - return LINPHONE_NAMESPACE::coreHeaderIsValid(d->grammar, "Subject", "SubjectValue", ";lang=" + language); + return LinphonePrivate::coreHeaderIsValid(d->grammar, "Subject", "SubjectValue", ";lang=" + language); } LINPHONE_END_NAMESPACE diff --git a/src/logger/logger.h b/src/logger/logger.h index daaa0b6a9..785dfc4ab 100644 --- a/src/logger/logger.h +++ b/src/logger/logger.h @@ -51,11 +51,11 @@ private: LINPHONE_END_NAMESPACE -#define lDebug() LINPHONE_NAMESPACE::Logger(LINPHONE_NAMESPACE::Logger::Debug).getOutput() -#define lInfo() LINPHONE_NAMESPACE::Logger(LINPHONE_NAMESPACE::Logger::Info).getOutput() -#define lWarning() LINPHONE_NAMESPACE::Logger(LINPHONE_NAMESPACE::Logger::Warning).getOutput() -#define lError() LINPHONE_NAMESPACE::Logger(LINPHONE_NAMESPACE::Logger::Error).getOutput() -#define lFatal() LINPHONE_NAMESPACE::Logger(LINPHONE_NAMESPACE::Logger::Fatal).getOutput() +#define lDebug() LinphonePrivate::Logger(LinphonePrivate::Logger::Debug).getOutput() +#define lInfo() LinphonePrivate::Logger(LinphonePrivate::Logger::Info).getOutput() +#define lWarning() LinphonePrivate::Logger(LinphonePrivate::Logger::Warning).getOutput() +#define lError() LinphonePrivate::Logger(LinphonePrivate::Logger::Error).getOutput() +#define lFatal() LinphonePrivate::Logger(LinphonePrivate::Logger::Fatal).getOutput() #define L_BEGIN_LOG_EXCEPTION try { #define L_END_LOG_EXCEPTION \ diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index ea83c2f65..09e8bb4d9 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -24,7 +24,7 @@ using namespace std; -using namespace LINPHONE_NAMESPACE; +using namespace LinphonePrivate; static void parse_minimal_message () { const string str = "Content-type: Message/CPIM\r\n" From 8d39bbe9b11ce5e0b04b7675c5f4d57478b52965 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 2 Oct 2017 14:31:52 +0200 Subject: [PATCH 0272/2215] Moved send code from ChatRoom to ChatMessage --- src/c-wrapper/api/c-chat-message.cpp | 4 +- src/chat/chat-message-p.h | 2 + src/chat/chat-message.cpp | 145 +++++++++++++++++++++++++-- src/chat/chat-message.h | 1 + src/chat/chat-room.cpp | 136 +------------------------ 5 files changed, 146 insertions(+), 142 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index b4d9009ae..dae659457 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -91,9 +91,7 @@ LinphoneChatMessageCbs *linphone_chat_message_get_callbacks(const LinphoneChatMe // ============================================================================= LinphoneChatRoom *linphone_chat_message_get_chat_room(const LinphoneChatMessage *msg) { - shared_ptr message = L_GET_CPP_PTR_FROM_C_OBJECT(msg); - shared_ptr room = message->getChatRoom(); - return L_GET_C_BACK_PTR(room); + return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getChatRoom()); } const char *linphone_chat_message_get_external_body_url(const LinphoneChatMessage *msg) { diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 4f770eabc..f461d5c26 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -97,6 +97,8 @@ public: // ----------------------------------------------------------------------------- void sendImdn(ImdnType imdnType, LinphoneReason reason); + + void send(); private: std::shared_ptr chatRoom; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 70558d927..59caf669c 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -29,6 +29,8 @@ #include "content/content.h" #include "chat-room-p.h" #include "real-time-text-chat-room.h" +#include "modifier/multipart-chat-message-modifier.h" +#include "modifier/cpim-chat-message-modifier.h" #include "ortp/b64.h" @@ -83,7 +85,7 @@ void ChatMessagePrivate::setState(ChatMessage::State s) { linphone_chat_message_get_message_state_changed_cb(msg)(msg, (LinphoneChatMessageState)state, linphone_chat_message_get_message_state_changed_cb_user_data(msg)); } LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); - if (linphone_chat_message_cbs_get_msg_state_changed(cbs)) { + if (cbs && linphone_chat_message_cbs_get_msg_state_changed(cbs)) { linphone_chat_message_cbs_get_msg_state_changed(cbs)(msg, linphone_chat_message_get_state(msg)); } } @@ -585,8 +587,7 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e first_part_header = "form-data; name=\"File\"; filename=\"filename.txt\""; } else { // temporary storage for the Content-disposition header value - first_part_header = "form-data; name=\"File\"; filename=\"%s\""; - first_part_header = first_part_header + linphone_content_get_name(cFileTransferInformation); + first_part_header = "form-data; name=\"File\"; filename=\"" +string(linphone_content_get_name(cFileTransferInformation)) + "\""; } // create a user body handler to take care of the file and add the content disposition and content-type headers @@ -683,7 +684,7 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e setContentType("application/vnd.gsma.rcs-ft-http+xml"); q->updateState(ChatMessage::State::FileTransferDone); releaseHttpRequest(); - //TODO chatRoom->sendMessage(q); + send(); fileUploadEndBackgroundTask(); } else { ms_warning("Received empty response from server, file transfer failed"); @@ -793,7 +794,7 @@ void ChatMessagePrivate::processIoErrorUpload(const belle_sip_io_error_event_t * ms_error("I/O Error during file upload of msg [%p]", this); q->updateState(ChatMessage::State::NotDelivered); releaseHttpRequest(); - //TODO chatRoom->getPrivate()->removeTransientMessage(q); + chatRoom->getPrivate()->removeTransientMessage(q->getSharedPtr()); } static void _chat_message_process_auth_requested_upload(void *data, belle_sip_auth_event *event) { @@ -806,7 +807,7 @@ void ChatMessagePrivate::processAuthRequestedUpload(const belle_sip_auth_event * ms_error("Error during file upload: auth requested for msg [%p]", this); q->updateState(ChatMessage::State::NotDelivered); releaseHttpRequest(); - //TODO chatRoom->getPrivate()->removeTransientMessage(q); + chatRoom->getPrivate()->removeTransientMessage(q->getSharedPtr()); } static void _chat_message_process_io_error_download(void *data, const belle_sip_io_error_event_t *event) { @@ -886,6 +887,132 @@ void ChatMessagePrivate::releaseHttpRequest() { } } +void ChatMessagePrivate::send() { + L_Q(); + SalOp *op = salOp; + LinphoneCall *call = NULL; + + if (lp_config_get_int(chatRoom->getCore()->config, "sip", "chat_use_call_dialogs", 0) != 0) { + call = linphone_core_get_call_by_remote_address(chatRoom->getCore(), chatRoom->getPeerAddress().asString().c_str()); + if (call) { + if (linphone_call_get_state(call) == LinphoneCallConnected || linphone_call_get_state(call) == LinphoneCallStreamsRunning || + linphone_call_get_state(call) == LinphoneCallPaused || linphone_call_get_state(call) == LinphoneCallPausing || + linphone_call_get_state(call) == LinphoneCallPausedByRemote) { + ms_message("send SIP msg through the existing call."); + op = linphone_call_get_op(call); + string identity = linphone_core_find_best_identity(chatRoom->getCore(), linphone_call_get_remote_address(call)); + if (identity.empty()) { + LinphoneAddress *addr = linphone_address_new(chatRoom->getPeerAddress().asString().c_str()); + LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(chatRoom->getCore(), addr); + if (proxy) { + identity = L_GET_CPP_PTR_FROM_C_OBJECT(linphone_proxy_config_get_identity_address(proxy))->asString(); + } else { + identity = linphone_core_get_primary_contact(chatRoom->getCore()); + } + linphone_address_unref(addr); + } + q->setFromAddress(identity); + } + } + } + + if (!op) { + LinphoneAddress *peer = linphone_address_new(chatRoom->getPeerAddress().asString().c_str()); + /* Sending out of call */ + salOp = op = new SalMessageOp(chatRoom->getCore()->sal); + linphone_configure_op( + chatRoom->getCore(), op, peer, getSalCustomHeaders(), + !!lp_config_get_int(chatRoom->getCore()->config, "sip", "chat_msg_with_contact", 0) + ); + op->set_user_pointer(L_GET_C_BACK_PTR(q)); /* If out of call, directly store msg */ + linphone_address_unref(peer); + } + + // --------------------------------------- + // Start of message modification + // --------------------------------------- + + string clearTextMessage; + string clearTextContentType; + + if (!getText().empty()) { + clearTextMessage = getText().c_str(); + } + if (!getContentType().empty()) { + clearTextContentType = getContentType(); + } + + int retval = -1; + LinphoneImEncryptionEngine *imee = chatRoom->getCore()->im_encryption_engine; + if (imee) { + LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); + if (cbProcessOutgoingMessage) { + //TODO retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(chatRoom), L_GET_C_BACK_PTR(this)); + if (retval == 0) { + isSecured = true; + } + } + } + + if (retval > 0) { + sal_error_info_set((SalErrorInfo *)op->get_error_info(), SalReasonNotAcceptable, "SIP", retval, "Unable to encrypt IM", nullptr); + q->updateState(ChatMessage::State::NotDelivered); + q->store(); + return; + } + + if (contents.size() > 1) { + MultipartChatMessageModifier mcmm; + mcmm.encode(this); + } + + if (lp_config_get_int(chatRoom->getCore()->config, "sip", "use_cpim", 0) == 1) { + CpimChatMessageModifier ccmm; + ccmm.encode(this); + } + + // --------------------------------------- + // End of message modification + // --------------------------------------- + + if (!externalBodyUrl.empty()) { + char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", externalBodyUrl.c_str()); + auto msgOp = dynamic_cast(op); + msgOp->send_message(from.asString().c_str(), chatRoom->getPeerAddress().asString().c_str(), content_type, nullptr, nullptr); + ms_free(content_type); + } else { + auto msgOp = dynamic_cast(op); + if (!getContentType().empty()) { + msgOp->send_message(from.asString().c_str(), chatRoom->getPeerAddress().asString().c_str(), getContentType().c_str(), getText().c_str(), chatRoom->getPeerAddress().asStringUriOnly().c_str()); + } else { + msgOp->send_message(from.asString().c_str(), chatRoom->getPeerAddress().asString().c_str(), getText().c_str()); + } + } + + if (!getText().empty() && getText() == clearTextMessage) { + /* We replace the encrypted message by the original one so it can be correctly stored and displayed by the application */ + setText(clearTextMessage); + } + if (!getContentType().empty() && getContentType() == clearTextContentType) { + /* We replace the encrypted content type by the original one */ + setContentType(clearTextContentType); + } + q->setId(op->get_call_id()); /* must be known at that time */ + + if (call && linphone_call_get_op(call) == op) { + /* In this case, chat delivery status is not notified, so unrefing chat message right now */ + /* Might be better fixed by delivering status, but too costly for now */ + return; + } + + /* If operation failed, we should not change message state */ + if (q->isOutgoing()) { + setIsReadOnly(true); + setState(ChatMessage::State::InProgress); + } +} + // ----------------------------------------------------------------------------- // ============================================================================= @@ -1150,7 +1277,7 @@ void ChatMessage::sendDisplayNotification() { int ChatMessage::uploadFile() { L_D(); - if (d->httpRequest){ + if (d->httpRequest) { ms_error("linphone_chat_room_upload_file(): there is already an upload in progress."); return -1; } @@ -1246,4 +1373,8 @@ int ChatMessage::putCharacter(uint32_t character) { return -1; } +shared_ptr ChatMessage::getSharedPtr() { + return static_pointer_cast(shared_from_this()); +} + LINPHONE_END_NAMESPACE diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index ba974e010..9c1c709d3 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -143,6 +143,7 @@ public: void removeCustomHeader(const std::string &headerName); protected: + std::shared_ptr getSharedPtr(); explicit ChatMessage(ChatMessagePrivate &p); private: diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index f08d677bb..a861e0843 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -23,8 +23,6 @@ #include "c-wrapper/c-wrapper.h" #include "chat-room-p.h" -#include "modifier/multipart-chat-message-modifier.h" -#include "modifier/cpim-chat-message-modifier.h" #include "imdn.h" #include "content/content.h" #include "chat-message-p.h" @@ -770,150 +768,24 @@ void ChatRoom::sendMessage (shared_ptr msg) { d->addTransientMessage(msg); /* Store the message so that even if the upload is stopped, it can be done again */ d->storeOrUpdateMessage(msg); + + msg->getPrivate()->setState(ChatMessage::State::InProgress); } else { return; } } else { - SalOp *op = msg->getPrivate()->getSalOp(); - LinphoneCall *call = nullptr; - string identity; - char *clearTextMessage = nullptr; - char *clearTextContentType = nullptr; - LinphoneAddress *peer = linphone_address_new(d->peerAddress.asString().c_str()); - - if (!msg->getPrivate()->getText().empty()) { - clearTextMessage = ms_strdup(msg->getPrivate()->getText().c_str()); - } - if (!msg->getPrivate()->getContentType().empty()) { - clearTextContentType = ms_strdup(msg->getPrivate()->getContentType().c_str()); - } - /* Add to transient list */ d->addTransientMessage(msg); + msg->getPrivate()->setTime(ms_time(0)); + msg->getPrivate()->send(); - if (lp_config_get_int(d->core->config, "sip", "chat_use_call_dialogs", 0) != 0) { - call = linphone_core_get_call_by_remote_address(d->core, d->peerAddress.asString().c_str()); - if (call) { - if (linphone_call_get_state(call) == LinphoneCallConnected || linphone_call_get_state(call) == LinphoneCallStreamsRunning || - linphone_call_get_state(call) == LinphoneCallPaused || linphone_call_get_state(call) == LinphoneCallPausing || - linphone_call_get_state(call) == LinphoneCallPausedByRemote) { - ms_message("send SIP msg through the existing call."); - op = linphone_call_get_op(call); - identity = linphone_core_find_best_identity(d->core, linphone_call_get_remote_address(call)); - } - } - } - - if (identity.empty()) { - LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(d->core, peer); - if (proxy) { - identity = L_GET_CPP_PTR_FROM_C_OBJECT(linphone_proxy_config_get_identity_address(proxy))->asString(); - } else { - identity = linphone_core_get_primary_contact(d->core); - } - } - msg->setFromAddress(identity); - - // --------------------------------------- - // Start of message modification - // --------------------------------------- - - int retval = -1; - LinphoneImEncryptionEngine *imee = d->core->im_encryption_engine; - if (imee) { - LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); - if (cbProcessOutgoingMessage) { - retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(this), L_GET_C_BACK_PTR(msg)); - if (retval == 0) { - msg->setIsSecured(true); - } - } - } - - if (msg->getContents().size() > 1) { - MultipartChatMessageModifier mcmm; - mcmm.encode(msg->getPrivate()); - } - - if (lp_config_get_int(d->core->config, "sip", "use_cpim", 0) == 1) { - CpimChatMessageModifier ccmm; - ccmm.encode(msg->getPrivate()); - } - - // --------------------------------------- - // End of message modification - // --------------------------------------- - - if (!op) { - /* Sending out of call */ - msg->getPrivate()->setSalOp(op = new SalMessageOp(d->core->sal)); - linphone_configure_op( - d->core, op, peer, msg->getPrivate()->getSalCustomHeaders(), - !!lp_config_get_int(d->core->config, "sip", "chat_msg_with_contact", 0) - ); - op->set_user_pointer(L_GET_C_BACK_PTR(msg)); /* If out of call, directly store msg */ - } - - if (retval > 0) { - sal_error_info_set((SalErrorInfo *)op->get_error_info(), SalReasonNotAcceptable, "SIP", retval, "Unable to encrypt IM", nullptr); - d->storeOrUpdateMessage(msg); - msg->updateState(ChatMessage::State::NotDelivered); - linphone_address_unref(peer); - return; - } - - if (!msg->getExternalBodyUrl().empty()) { - char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", msg->getExternalBodyUrl().c_str()); - auto msgOp = dynamic_cast(op); - msgOp->send_message(identity.c_str(), d->peerAddress.asString().c_str(), content_type, nullptr, nullptr); - ms_free(content_type); - } else { - auto msgOp = dynamic_cast(op); - if (!msg->getPrivate()->getContentType().empty()) { - msgOp->send_message(identity.c_str(), d->peerAddress.asString().c_str(), msg->getPrivate()->getContentType().c_str(), msg->getPrivate()->getText().c_str(), d->peerAddress.asStringUriOnly().c_str()); - } else { - msgOp->send_message(identity.c_str(), d->peerAddress.asString().c_str(), msg->getPrivate()->getText().c_str()); - } - } - - if (!msg->getPrivate()->getText().empty() && clearTextMessage && strcmp(msg->getPrivate()->getText().c_str(), clearTextMessage) != 0) { - /* We replace the encrypted message by the original one so it can be correctly stored and displayed by the application */ - msg->getPrivate()->setText(clearTextMessage); - } - if (!msg->getPrivate()->getContentType().empty() && clearTextContentType && (strcmp(msg->getPrivate()->getContentType().c_str(), clearTextContentType) != 0)) { - /* We replace the encrypted content type by the original one */ - msg->getPrivate()->setContentType(clearTextContentType); - } - msg->setId(op->get_call_id()); /* must be known at that time */ d->storeOrUpdateMessage(msg); if (d->isComposing) d->isComposing = false; d->isComposingHandler.stopIdleTimer(); d->isComposingHandler.stopRefreshTimer(); - - if (clearTextMessage) { - ms_free(clearTextMessage); - } - if (clearTextContentType) { - ms_free(clearTextContentType); - } - linphone_address_unref(peer); - - if (call && linphone_call_get_op(call) == op) { - /* In this case, chat delivery status is not notified, so unrefing chat message right now */ - /* Might be better fixed by delivering status, but too costly for now */ - d->removeTransientMessage(msg); - return; - } - } - - /* If operation failed, we should not change message state */ - if (msg->isOutgoing()) { - msg->getPrivate()->setIsReadOnly(true); - msg->getPrivate()->setState(ChatMessage::State::InProgress); } } From c58a24190140e9241b77aedcc31e4196ad38b75f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 2 Oct 2017 14:32:14 +0200 Subject: [PATCH 0273/2215] Do not exit on fatal, otherwise we don't get a backtrace --- src/c-wrapper/internal/c-tools.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 8bdb93998..25aecf70d 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -115,7 +115,7 @@ private: static inline void fatal (const char *message) { std::cout << "[FATAL C-WRAPPER]" << message << std::endl; - exit(1); + //exit(1); } public: From ebbb838a5e7d36483ec7ab5378895853ac3b8b62 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 2 Oct 2017 15:31:33 +0200 Subject: [PATCH 0274/2215] Fixed call to IMEE callback --- src/chat/chat-message.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 59caf669c..d854e9b48 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -948,7 +948,7 @@ void ChatMessagePrivate::send() { LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); if (cbProcessOutgoingMessage) { - //TODO retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(chatRoom), L_GET_C_BACK_PTR(this)); + retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(chatRoom), L_GET_C_BACK_PTR(q->getSharedPtr())); if (retval == 0) { isSecured = true; } From bb5d418afd2e571f9302c9b7455ed9fb31536e0f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 2 Oct 2017 16:24:52 +0200 Subject: [PATCH 0275/2215] Add accessors for the conference subject in the conference interface. --- coreapi/sal/sal.cpp | 6 +++++ coreapi/sal/sal_op.cpp | 8 +++++++ coreapi/sal/sal_op.h | 8 +++++-- include/linphone/api/c-chat-room.h | 14 ++++++++++++ src/c-wrapper/api/c-chat-room.cpp | 8 +++++++ src/chat/basic-chat-room-p.h | 2 ++ src/chat/basic-chat-room.cpp | 10 ++++++++ src/chat/basic-chat-room.h | 2 ++ src/chat/client-group-chat-room-p.h | 4 +--- src/chat/client-group-chat-room.cpp | 27 ++++++++++++++++++---- src/chat/client-group-chat-room.h | 2 ++ src/chat/real-time-text-chat-room-p.h | 2 ++ src/chat/real-time-text-chat-room.cpp | 10 ++++++++ src/chat/real-time-text-chat-room.h | 2 ++ src/conference/conference-interface.h | 2 ++ src/conference/conference.cpp | 8 +++++++ src/conference/conference.h | 3 +++ src/conference/session/call-session-p.h | 3 ++- src/conference/session/call-session.cpp | 29 +++++++++++++----------- src/conference/session/call-session.h | 4 ++-- src/conference/session/media-session-p.h | 2 +- src/conference/session/media-session.cpp | 8 +++---- src/conference/session/media-session.h | 4 ++-- 23 files changed, 136 insertions(+), 32 deletions(-) diff --git a/coreapi/sal/sal.cpp b/coreapi/sal/sal.cpp index fb5d91dd0..520c2d6d8 100644 --- a/coreapi/sal/sal.cpp +++ b/coreapi/sal/sal.cpp @@ -52,6 +52,7 @@ void Sal::process_request_event_cb(void *ud, const belle_sip_request_event_t *ev belle_sip_header_t *evh; const char *method=belle_sip_request_get_method(req); belle_sip_header_contact_t* remote_contact = belle_sip_message_get_header_by_type(req, belle_sip_header_contact_t); + belle_sip_header_t *subjectHeader = belle_sip_message_get_header(BELLE_SIP_MESSAGE(req), "Subject"); from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); @@ -161,6 +162,11 @@ void Sal::process_request_event_cb(void *ud, const belle_sip_request_event_t *ev belle_sip_object_unref(address); } + if (subjectHeader) { + const char *subject = belle_sip_header_get_unparsed_value(subjectHeader); + op->set_subject(subject); + } + if(!op->diversion_address){ diversion=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_diversion_t); if (diversion) { diff --git a/coreapi/sal/sal_op.cpp b/coreapi/sal/sal_op.cpp index a72cae041..a73d018ce 100644 --- a/coreapi/sal/sal_op.cpp +++ b/coreapi/sal/sal_op.cpp @@ -65,6 +65,10 @@ SalOp::~SalOp() { ms_free(this->to); this->to=NULL; } + if (this->subject) { + ms_free(this->subject); + this->subject = NULL; + } if (this->route) { ms_free(this->route); this->route=NULL; @@ -198,6 +202,10 @@ void SalOp::set_realm(const char *realm) { assign_string(&this->name,name##_string); \ if(name##_string) ms_free(name##_string); +void SalOp::set_subject (const char *subject) { + assign_string(&this->subject, subject); +} + void SalOp::set_from(const char *from){ SET_PARAM(from); } diff --git a/coreapi/sal/sal_op.h b/coreapi/sal/sal_op.h index d30b3b4d8..118784620 100644 --- a/coreapi/sal/sal_op.h +++ b/coreapi/sal/sal_op.h @@ -41,8 +41,11 @@ public: void set_user_pointer(void *up) {this->user_pointer=up;} void *get_user_pointer() const {return this->user_pointer;} - - + + + void set_subject (const char *subject); + const char *get_subject () const { return this->subject; } + void set_from(const char *from); void set_from_address(const SalAddress *from); const char *get_from() const {return this->from;} @@ -197,6 +200,7 @@ protected: char *route = NULL; /*or request-uri for REGISTER*/ MSList* route_addresses = NULL; /*list of SalAddress* */ SalAddress* contact_address = NULL; + char *subject = NULL; char *from = NULL; SalAddress* from_address = NULL; char *to = NULL; diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index 0b82cdb43..d98c05de9 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -282,6 +282,13 @@ LINPHONE_PUBLIC int linphone_chat_room_get_nb_participants (const LinphoneChatRo */ LINPHONE_PUBLIC bctbx_list_t * linphone_chat_room_get_participants (const LinphoneChatRoom *cr); +/** + * Get the subject of a chat room. + * @param[in] cr A LinphoneChatRoom object + * @return The subject of the chat room + */ +LINPHONE_PUBLIC const char * linphone_chat_room_get_subject (const LinphoneChatRoom *cr); + /** * Remove a participant of a chat room. * @param[in] cr A LinphoneChatRoom object @@ -296,6 +303,13 @@ LINPHONE_PUBLIC void linphone_chat_room_remove_participant (LinphoneChatRoom *cr */ LINPHONE_PUBLIC void linphone_chat_room_remove_participants (LinphoneChatRoom *cr, const bctbx_list_t *participants); +/** + * Set the subject of a chat room. + * @param[in] cr A LinphoneChatRoom object + * @param[in] subject The new subject to set for the chat room + */ +LINPHONE_PUBLIC void linphone_chat_room_set_subject (LinphoneChatRoom *cr, const char *subject); + /** * Returns back pointer to #LinphoneCore object. * @deprecated use linphone_chat_room_get_core() diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 1b78fd9e8..3bc39f348 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -245,6 +245,10 @@ bctbx_list_t *linphone_chat_room_get_participants (const LinphoneChatRoom *cr) { return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getParticipants()); } +const char * linphone_chat_room_get_subject (const LinphoneChatRoom *cr) { + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getSubject()); +} + void linphone_chat_room_remove_participant (LinphoneChatRoom *cr, LinphoneParticipant *participant) { L_GET_CPP_PTR_FROM_C_OBJECT(cr)->removeParticipant(L_GET_CPP_PTR_FROM_C_OBJECT(participant)); } @@ -253,6 +257,10 @@ void linphone_chat_room_remove_participants (LinphoneChatRoom *cr, const bctbx_l L_GET_CPP_PTR_FROM_C_OBJECT(cr)->removeParticipants(L_GET_RESOLVED_CPP_LIST_FROM_C_LIST(participants, Participant)); } +void linphone_chat_room_set_subject (LinphoneChatRoom *cr, const char *subject) { + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->setSubject(L_C_TO_STRING(subject)); +} + // ============================================================================= // Reference and user data handling functions. // ============================================================================= diff --git a/src/chat/basic-chat-room-p.h b/src/chat/basic-chat-room-p.h index 54d3d9fe5..056ba79f1 100644 --- a/src/chat/basic-chat-room-p.h +++ b/src/chat/basic-chat-room-p.h @@ -35,6 +35,8 @@ public: virtual ~BasicChatRoomPrivate () = default; private: + std::string subject; + L_DECLARE_PUBLIC(BasicChatRoom); }; diff --git a/src/chat/basic-chat-room.cpp b/src/chat/basic-chat-room.cpp index 820ffc6cd..2d41a5657 100644 --- a/src/chat/basic-chat-room.cpp +++ b/src/chat/basic-chat-room.cpp @@ -64,6 +64,11 @@ list> BasicChatRoom::getParticipants () const { return l; } +const string &BasicChatRoom::getSubject () const { + L_D(); + return d->subject; +} + void BasicChatRoom::removeParticipant (const shared_ptr &participant) { lError() << "removeParticipant() is not allowed on a BasicChatRoom"; } @@ -72,4 +77,9 @@ void BasicChatRoom::removeParticipants (const list> &par lError() << "removeParticipants() is not allowed on a BasicChatRoom"; } +void BasicChatRoom::setSubject (const string &subject) { + L_D(); + d->subject = subject; +} + LINPHONE_END_NAMESPACE diff --git a/src/chat/basic-chat-room.h b/src/chat/basic-chat-room.h index d7aae693a..b80a771de 100644 --- a/src/chat/basic-chat-room.h +++ b/src/chat/basic-chat-room.h @@ -39,8 +39,10 @@ public: const Address *getConferenceAddress () const override; int getNbParticipants () const override; std::list> getParticipants () const override; + const std::string &getSubject () const override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; + void setSubject (const std::string &subject) override; private: L_DECLARE_PRIVATE(BasicChatRoom); diff --git a/src/chat/client-group-chat-room-p.h b/src/chat/client-group-chat-room-p.h index ef642bc6c..346faf869 100644 --- a/src/chat/client-group-chat-room-p.h +++ b/src/chat/client-group-chat-room-p.h @@ -31,12 +31,10 @@ LINPHONE_BEGIN_NAMESPACE class ClientGroupChatRoomPrivate : public ChatRoomPrivate { public: - ClientGroupChatRoomPrivate (LinphoneCore *core, const std::string &subject); + ClientGroupChatRoomPrivate (LinphoneCore *core); virtual ~ClientGroupChatRoomPrivate () = default; private: - std::string subject; - L_DECLARE_PUBLIC(ClientGroupChatRoom); }; diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 57e65cdc1..fb21ca9cc 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -31,15 +31,16 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core, const string &subject) - : ChatRoomPrivate(core), subject(subject) {} +ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core) + : ChatRoomPrivate(core) {} // ============================================================================= ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, const string &subject) - : ChatRoom(*new ClientGroupChatRoomPrivate(core, subject)), RemoteConference(core, me, nullptr) { + : ChatRoom(*new ClientGroupChatRoomPrivate(core)), RemoteConference(core, me, nullptr) { string factoryUri = linphone_core_get_conference_factory_uri(core); focus = make_shared(factoryUri); + this->subject = subject; } // ----------------------------------------------------------------------------- @@ -73,7 +74,7 @@ void ClientGroupChatRoom::addParticipants (const list
    &addresses, const Address addr = me->getAddress(); addr.setParam("text", ""); session->getPrivate()->getOp()->set_contact_address(addr.getPrivate()->getInternalAddress()); - session->startInvite(nullptr, d->subject); + session->startInvite(nullptr, subject); d->setState(ChatRoom::State::CreationPending); } // TODO @@ -95,6 +96,10 @@ list> ClientGroupChatRoom::getParticipants () const { return RemoteConference::getParticipants(); } +const string &ClientGroupChatRoom::getSubject () const { + return RemoteConference::getSubject(); +} + void ClientGroupChatRoom::removeParticipant (const shared_ptr &participant) { // TODO } @@ -103,6 +108,20 @@ void ClientGroupChatRoom::removeParticipants (const list // TODO } +void ClientGroupChatRoom::setSubject (const string &subject) { + L_D(); + if (d->state != ChatRoom::State::Created) { + lError() << "Cannot change the ClientGroupChatRoom subject in a state other than Created"; + return; + } + if (!me->isAdmin()) { + lError() << "Cannot change the ClientGroupChatRoom subject because I am not admin"; + return; + } + shared_ptr session = focus->getPrivate()->getSession(); + session->update(nullptr, subject); +} + // ----------------------------------------------------------------------------- void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index d5f1c5b1a..05ba772f7 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -47,8 +47,10 @@ public: const Address *getConferenceAddress () const override; int getNbParticipants () const override; std::list> getParticipants () const override; + const std::string &getSubject () const override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; + void setSubject (const std::string &subject) override; private: /* ConferenceListener */ diff --git a/src/chat/real-time-text-chat-room-p.h b/src/chat/real-time-text-chat-room-p.h index 5aaf502c2..88e4e7df4 100644 --- a/src/chat/real-time-text-chat-room-p.h +++ b/src/chat/real-time-text-chat-room-p.h @@ -46,6 +46,8 @@ public: std::shared_ptr pendingMessage = nullptr; private: + std::string subject; + L_DECLARE_PUBLIC(RealTimeTextChatRoom); }; diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 0a4939735..885b98e33 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -160,6 +160,11 @@ list> RealTimeTextChatRoom::getParticipants () const { return l; } +const string &RealTimeTextChatRoom::getSubject () const { + L_D(); + return d->subject; +} + void RealTimeTextChatRoom::removeParticipant (const shared_ptr &participant) { lError() << "removeParticipant() is not allowed on a RealTimeTextChatRoom"; } @@ -168,4 +173,9 @@ void RealTimeTextChatRoom::removeParticipants (const listsubject = subject; +} + LINPHONE_END_NAMESPACE diff --git a/src/chat/real-time-text-chat-room.h b/src/chat/real-time-text-chat-room.h index 524296521..f9a7c077c 100644 --- a/src/chat/real-time-text-chat-room.h +++ b/src/chat/real-time-text-chat-room.h @@ -49,8 +49,10 @@ public: const Address *getConferenceAddress () const override; int getNbParticipants () const override; std::list> getParticipants () const override; + const std::string &getSubject () const override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; + void setSubject (const std::string &subject) override; private: L_DECLARE_PRIVATE(RealTimeTextChatRoom); diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index 1cd62ec6d..1058ff8e6 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -40,8 +40,10 @@ public: virtual const Address *getConferenceAddress () const = 0; virtual int getNbParticipants () const = 0; virtual std::list> getParticipants () const = 0; + virtual const std::string &getSubject () const = 0; virtual void removeParticipant (const std::shared_ptr &participant) = 0; virtual void removeParticipants (const std::list> &participants) = 0; + virtual void setSubject (const std::string &subject) = 0; }; LINPHONE_END_NAMESPACE diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 0bd79f1f8..818273165 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -66,6 +66,10 @@ list> Conference::getParticipants () const { return participants; } +const string &Conference::getSubject () const { + return subject; +} + void Conference::removeParticipant (const shared_ptr &participant) { lError() << "Conference class does not handle removeParticipant() generically"; } @@ -75,6 +79,10 @@ void Conference::removeParticipants (const list> &partic removeParticipant(p); } +void Conference::setSubject (const string &subject) { + this->subject = subject; +} + // ----------------------------------------------------------------------------- void Conference::onAckBeingSent (const CallSession &session, LinphoneHeaders *headers) { diff --git a/src/conference/conference.h b/src/conference/conference.h index b9a89cd31..e83debbbe 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -53,8 +53,10 @@ public: const Address *getConferenceAddress () const override; int getNbParticipants () const override; std::list> getParticipants () const override; + const std::string &getSubject () const override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; + void setSubject (const std::string &subject) override; private: /* CallSessionListener */ @@ -87,6 +89,7 @@ protected: std::shared_ptr me; std::list> participants; Address conferenceAddress; + std::string subject; private: L_DISABLE_COPY(Conference); diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index c1b68870f..924aed37a 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -64,7 +64,7 @@ protected: virtual void setReleased (); virtual void setTerminated (); virtual LinphoneStatus startAcceptUpdate (LinphoneCallState nextState, const std::string &stateInfo); - virtual LinphoneStatus startUpdate (); + virtual LinphoneStatus startUpdate (const std::string &subject); virtual void terminate (); virtual void updateCurrentParams () const; @@ -85,6 +85,7 @@ protected: mutable CallSessionParams *currentParams = nullptr; CallSessionParams *remoteParams = nullptr; + std::string subject; LinphoneCallDir direction = LinphoneCallOutgoing; LinphoneCallState state = LinphoneCallIdle; LinphoneCallState prevState = LinphoneCallIdle; diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index eb1922516..3bb20e55e 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -564,23 +564,25 @@ LinphoneStatus CallSessionPrivate::startAcceptUpdate (LinphoneCallState nextStat return 0; } -LinphoneStatus CallSessionPrivate::startUpdate () { +LinphoneStatus CallSessionPrivate::startUpdate (const string &subject) { L_Q(); - string subject; - if (q->getParams()->getPrivate()->getInConference()) - subject = "Conference"; - else if (q->getParams()->getPrivate()->getInternalCallUpdate()) - subject = "ICE processing concluded"; - else if (q->getParams()->getPrivate()->getNoUserConsent()) - subject = "Refreshing"; - else - subject = "Media change"; + string newSubject(subject); + if (newSubject.empty()) { + if (q->getParams()->getPrivate()->getInConference()) + newSubject = "Conference"; + else if (q->getParams()->getPrivate()->getInternalCallUpdate()) + newSubject = "ICE processing concluded"; + else if (q->getParams()->getPrivate()->getNoUserConsent()) + newSubject = "Refreshing"; + else + newSubject = "Media change"; + } if (destProxy && destProxy->op) { /* Give a chance to update the contact address if connectivity has changed */ op->set_contact_address(destProxy->op->get_contact_address()); } else op->set_contact_address(nullptr); - return op->update(subject.c_str(), q->getParams()->getPrivate()->getNoUserConsent()); + return op->update(newSubject.c_str(), q->getParams()->getPrivate()->getNoUserConsent()); } void CallSessionPrivate::terminate () { @@ -827,6 +829,7 @@ void CallSession::startIncomingNotification () { int CallSession::startInvite (const Address *destination, const string &subject) { L_D(); + d->subject = subject; /* Try to be best-effort in giving real local or routable contact address */ d->setContactOp(); string destinationStr; @@ -889,7 +892,7 @@ LinphoneStatus CallSession::terminate (const LinphoneErrorInfo *ei) { return 0; } -LinphoneStatus CallSession::update (const CallSessionParams *csp) { +LinphoneStatus CallSession::update (const CallSessionParams *csp, const string &subject) { L_D(); LinphoneCallState nextState; LinphoneCallState initialState = d->state; @@ -897,7 +900,7 @@ LinphoneStatus CallSession::update (const CallSessionParams *csp) { return -1; if (d->currentParams == csp) lWarning() << "CallSession::update() is given the current params, this is probably not what you intend to do!"; - LinphoneStatus result = d->startUpdate(); + LinphoneStatus result = d->startUpdate(subject); if (result && (d->state != initialState)) { /* Restore initial state */ d->setState(initialState, "Restore initial state"); diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index a43331c2e..7f68e4fb7 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -49,9 +49,9 @@ public: virtual bool initiateOutgoing (); virtual void iterate (time_t currentRealTime, bool oneSecondElapsed); virtual void startIncomingNotification (); - virtual int startInvite (const Address *destination, const std::string &subject); + virtual int startInvite (const Address *destination, const std::string &subject = ""); LinphoneStatus terminate (const LinphoneErrorInfo *ei = nullptr); - LinphoneStatus update (const CallSessionParams *csp); + LinphoneStatus update (const CallSessionParams *csp, const std::string &subject = ""); CallSessionParams *getCurrentParams () const; LinphoneCallDir getDirection () const; diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index b9e75b401..18ff22f56 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -232,7 +232,7 @@ private: LinphoneStatus pause (); void setTerminated () override; LinphoneStatus startAcceptUpdate (LinphoneCallState nextState, const std::string &stateInfo) override; - LinphoneStatus startUpdate () override; + LinphoneStatus startUpdate (const std::string &subject = "") override; void terminate () override; void updateCurrentParams () const override; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 9137f16dd..d159a4dca 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -3706,7 +3706,7 @@ LinphoneStatus MediaSessionPrivate::startAcceptUpdate (LinphoneCallState nextSta return 0; } -LinphoneStatus MediaSessionPrivate::startUpdate () { +LinphoneStatus MediaSessionPrivate::startUpdate (const string &subject) { fillMulticastMediaAddresses(); if (!params->getPrivate()->getNoUserConsent()) makeLocalMediaDescription(); @@ -3714,7 +3714,7 @@ LinphoneStatus MediaSessionPrivate::startUpdate () { op->set_local_media_description(localDesc); else op->set_local_media_description(nullptr); - LinphoneStatus result = CallSessionPrivate::startUpdate(); + LinphoneStatus result = CallSessionPrivate::startUpdate(subject); if (core->sip_conf.sdp_200_ack) { /* We are NOT offering, set local media description after sending the call so that we are ready to * process the remote offer when it will arrive. */ @@ -4297,7 +4297,7 @@ void MediaSession::stopRecording () { d->recordActive = false; } -LinphoneStatus MediaSession::update (const MediaSessionParams *msp) { +LinphoneStatus MediaSession::update (const MediaSessionParams *msp, const string &subject) { L_D(); LinphoneCallState nextState; LinphoneCallState initialState = d->state; @@ -4316,7 +4316,7 @@ LinphoneStatus MediaSession::update (const MediaSessionParams *msp) { lInfo() << "Defer CallSession update to gather ICE candidates"; return 0; } - LinphoneStatus result = d->startUpdate(); + LinphoneStatus result = d->startUpdate(subject); if (result && (d->state != initialState)) { /* Restore initial state */ d->setState(initialState, "Restore initial state"); diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index 4de168815..60e2163e2 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -48,10 +48,10 @@ public: LinphoneStatus resume (); void sendVfuRequest (); void startIncomingNotification () override; - int startInvite (const Address *destination, const std::string &subject) override; + int startInvite (const Address *destination, const std::string &subject = "") override; void startRecording (); void stopRecording (); - LinphoneStatus update (const MediaSessionParams *msp); + LinphoneStatus update (const MediaSessionParams *msp, const std::string &subject = ""); void resetFirstVideoFrameDecoded (); LinphoneStatus takePreviewSnapshot (const std::string& file); From 2e94f78c5a735fc74cb8b036af4a8c23dfe9fc23 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 2 Oct 2017 16:26:44 +0200 Subject: [PATCH 0276/2215] SalCallOp::decline_with_error_info() is now taking a SalAddress as parameter instead of an uri. --- coreapi/callbacks.c | 4 +++- coreapi/sal/call_op.cpp | 10 ++++------ coreapi/sal/call_op.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index a19d9924f..cb6dcb199 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -122,8 +122,10 @@ static void call_received(SalCallOp *h) { SalErrorInfo sei; memset(&sei, 0, sizeof(sei)); sal_error_info_set(&sei, SalReasonRedirect, "SIP", 0, nullptr, nullptr); - h->decline_with_error_info(&sei, altContact); + SalAddress *altAddr = sal_address_new(altContact); + h->decline_with_error_info(&sei, altAddr); ms_free(altContact); + sal_address_unref(altAddr); LinphoneErrorInfo *ei = linphone_error_info_new(); linphone_error_info_set(ei, nullptr, LinphoneReasonMovedPermanently, 302, "Moved permanently", nullptr); linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, fromAddr, toAddr, ei); diff --git a/coreapi/sal/call_op.cpp b/coreapi/sal/call_op.cpp index 83cc8e7a7..7ee12ad0d 100644 --- a/coreapi/sal/call_op.cpp +++ b/coreapi/sal/call_op.cpp @@ -972,18 +972,16 @@ belle_sip_header_reason_t *SalCallOp::make_reason_header( const SalErrorInfo *in return NULL; } -int SalCallOp::decline_with_error_info(const SalErrorInfo *info, const char *redirection /*optional*/){ +int SalCallOp::decline_with_error_info(const SalErrorInfo *info, const SalAddress *redirectionAddr /*optional*/){ belle_sip_response_t* response; belle_sip_header_contact_t* contact=NULL; int status = info->protocol_code; belle_sip_transaction_t *trans; if (info->reason==SalReasonRedirect){ - if (redirection!=NULL) { - if (strstr(redirection,"sip:")!=0) status=302; - else status=380; - contact= belle_sip_header_contact_new(); - belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact),belle_sip_uri_parse(redirection)); + if (redirectionAddr) { + status = 302; + contact = belle_sip_header_contact_create(BELLE_SIP_HEADER_ADDRESS(redirectionAddr)); } else { ms_error("Cannot redirect to null"); } diff --git a/coreapi/sal/call_op.h b/coreapi/sal/call_op.h index a8a5616bf..8ac3605bb 100644 --- a/coreapi/sal/call_op.h +++ b/coreapi/sal/call_op.h @@ -40,7 +40,7 @@ public: int notify_ringing(bool_t early_media); int accept(); int decline(SalReason reason, const char *redirection /*optional*/); - int decline_with_error_info(const SalErrorInfo *info, const char *redirection /*optional*/); + int decline_with_error_info(const SalErrorInfo *info, const SalAddress *redirectionAddr /*optional*/); int update(const char *subject, bool_t no_user_consent); void cancel_invite() {cancel_invite_with_info(NULL);} void cancel_invite_with_info(const SalErrorInfo *info); From 7969616d435d156cc4f40f28fa20817c07e8eb01 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 2 Oct 2017 16:28:27 +0200 Subject: [PATCH 0277/2215] Handle redirection in the CallSession class. --- coreapi/private.h | 1 - src/address/address.h | 1 + src/c-wrapper/api/c-call.cpp | 48 +----------------------- src/call/call.cpp | 5 +++ src/call/call.h | 1 + src/conference/session/call-session-p.h | 2 + src/conference/session/call-session.cpp | 46 +++++++++++++++++++++-- src/conference/session/call-session.h | 2 + src/conference/session/media-session-p.h | 1 + src/conference/session/media-session.cpp | 18 ++++----- 10 files changed, 66 insertions(+), 59 deletions(-) diff --git a/coreapi/private.h b/coreapi/private.h index fe4ae5c48..228339482 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -438,7 +438,6 @@ void linphone_core_stop_waiting(LinphoneCore *lc); int linphone_call_proceed_with_invite_if_ready(LinphoneCall *call, LinphoneProxyConfig *dest_proxy); int linphone_call_start_invite(LinphoneCall *call, const LinphoneAddress *destination/* = NULL if to be taken from the call log */); -int linphone_call_restart_invite(LinphoneCall *call); /* * param automatic_offering aims is to take into account previous answer for video in case of automatic re-invite. * Purpose is to avoid to re-ask video previously declined */ diff --git a/src/address/address.h b/src/address/address.h index 9e5d90cc6..94c2e4ea2 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -29,6 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class AddressPrivate; class LINPHONE_PUBLIC Address : public ClonableObject { + friend class CallSession; friend class ClientGroupChatRoom; public: diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 4d0278ed4..f7d51ac93 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -179,19 +179,7 @@ void linphone_call_update_local_media_description_from_ice_or_upnp (LinphoneCall void linphone_call_make_local_media_description (LinphoneCall *call) {} -void linphone_call_create_op (LinphoneCall *call) { -#if 0 - if (call->op) sal_op_release(call->op); - call->op=sal_op_new(call->core->sal); - sal_op_set_user_pointer(call->op,call); - if (linphone_call_params_get_referer(call->params)) - sal_call_set_referer(call->op,linphone_call_params_get_referer(call->params)->op); - linphone_configure_op(call->core,call->op,call->log->to,linphone_call_params_get_custom_headers(call->params),FALSE); - if (linphone_call_params_get_privacy(call->params) != LinphonePrivacyDefault) - sal_op_set_privacy(call->op,(SalPrivacyMask)linphone_call_params_get_privacy(call->params)); - /*else privacy might be set by proxy */ -#endif -} +void linphone_call_create_op (LinphoneCall *call) {} void linphone_call_set_state (LinphoneCall *call, LinphoneCallState cstate, const char *message) {} @@ -884,39 +872,7 @@ LinphoneStatus linphone_call_terminate_with_error_info (LinphoneCall *call , con } LinphoneStatus linphone_call_redirect (LinphoneCall *call, const char *redirect_uri) { -#if 0 - char *real_url = nullptr; - LinphoneCore *lc; - LinphoneAddress *real_parsed_url; - SalErrorInfo sei; - - if (call->state != LinphoneCallIncomingReceived) { - ms_error("Bad state for call redirection."); - return -1; - } - - lc = linphone_call_get_core(call); - real_parsed_url = linphone_core_interpret_url(lc, redirect_uri); - if (!real_parsed_url) { - /* Bad url */ - ms_error("Bad redirect URI: %s", redirect_uri ? redirect_uri : "NULL"); - return -1; - } - - memset(&sei, 0, sizeof(sei)); - real_url = linphone_address_as_string(real_parsed_url); - sal_error_info_set(&sei,SalReasonRedirect, "SIP", 0, nullptr, nullptr); - sal_call_decline_with_error_info(call->op, &sei, real_url); - ms_free(real_url); - linphone_error_info_set(call->ei, nullptr, LinphoneReasonMovedPermanently, 302, "Call redirected", nullptr); - call->non_op_error = TRUE; - terminate_call(call); - linphone_address_unref(real_parsed_url); - sal_error_info_reset(&sei); - return 0; -#else - return 0; -#endif + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->redirect(redirect_uri); } LinphoneStatus linphone_call_decline (LinphoneCall *call, LinphoneReason reason) { diff --git a/src/call/call.cpp b/src/call/call.cpp index 369f2bfd7..ba0f12951 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -267,6 +267,11 @@ LinphoneStatus Call::pause () { return static_cast(d->getActiveSession().get())->pause(); } +LinphoneStatus Call::redirect (const std::string &redirectUri) { + L_D(); + return d->getActiveSession()->redirect(redirectUri); +} + LinphoneStatus Call::resume () { L_D(); return static_cast(d->getActiveSession().get())->resume(); diff --git a/src/call/call.h b/src/call/call.h index b42780fb1..2cf6a08da 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -53,6 +53,7 @@ public: LinphoneStatus decline (LinphoneReason reason); LinphoneStatus decline (const LinphoneErrorInfo *ei); LinphoneStatus pause (); + LinphoneStatus redirect (const std::string &redirectUri); LinphoneStatus resume (); void sendVfuRequest (); void startRecording (); diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index 924aed37a..18f1fdf83 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -61,6 +61,7 @@ protected: virtual void handleIncomingReceivedStateInIncomingNotification (); virtual bool isReadyForInvite () const; bool isUpdateAllowed (LinphoneCallState &nextState) const; + virtual int restartInvite (); virtual void setReleased (); virtual void setTerminated (); virtual LinphoneStatus startAcceptUpdate (LinphoneCallState nextState, const std::string &stateInfo); @@ -72,6 +73,7 @@ protected: private: void completeLog (); + void createOp (); void createOpTo (const LinphoneAddress *to); LinphoneAddress * getFixedContact () const; diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 3bb20e55e..2397cbe6b 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -255,9 +255,7 @@ bool CallSessionPrivate::failure () { linphone_address_unref(log->to); log->to = linphone_address_new(url); ms_free(url); -#if 0 - linphone_call_restart_invite(call); -#endif + restartInvite(); return true; } } @@ -514,6 +512,12 @@ bool CallSessionPrivate::isUpdateAllowed (LinphoneCallState &nextState) const { return true; } +int CallSessionPrivate::restartInvite () { + L_Q(); + createOp(); + return q->startInvite(nullptr, subject); +} + /* * Called internally when reaching the Released state, to perform cleanups to break circular references. **/ @@ -617,6 +621,10 @@ void CallSessionPrivate::completeLog () { linphone_core_report_call_log(core, log); } +void CallSessionPrivate::createOp () { + createOpTo(log->to); +} + void CallSessionPrivate::createOpTo (const LinphoneAddress *to) { L_Q(); if (op) @@ -794,6 +802,38 @@ void CallSession::iterate (time_t currentRealTime, bool oneSecondElapsed) { } } +LinphoneStatus CallSession::redirect (const string &redirectUri) { + L_D(); + LinphoneAddress *realParsedAddr = linphone_core_interpret_url(d->core, redirectUri.c_str()); + if (!realParsedAddr) { + /* Bad url */ + lError() << "Bad redirect URI: " << redirectUri; + return -1; + } + char *realParsedUri = linphone_address_as_string(realParsedAddr); + Address redirectAddr(realParsedUri); + bctbx_free(realParsedUri); + linphone_address_unref(realParsedAddr); + return redirect(redirectAddr); +} + +LinphoneStatus CallSession::redirect (const Address &redirectAddr) { + L_D(); + if (d->state != LinphoneCallIncomingReceived) { + lError() << "Bad state for CallSession redirection"; + return -1; + } + SalErrorInfo sei; + memset(&sei, 0, sizeof(sei)); + sal_error_info_set(&sei, SalReasonRedirect, "SIP", 0, nullptr, nullptr); + d->op->decline_with_error_info(&sei, redirectAddr.getPrivate()->getInternalAddress()); + linphone_error_info_set(d->ei, nullptr, LinphoneReasonMovedPermanently, 302, "Call redirected", nullptr); + d->nonOpError = true; + d->terminate(); + sal_error_info_reset(&sei); + return 0; +} + void CallSession::startIncomingNotification () { L_D(); if (d->listener) diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index 7f68e4fb7..52ae7e1d3 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -48,6 +48,8 @@ public: virtual void initiateIncoming (); virtual bool initiateOutgoing (); virtual void iterate (time_t currentRealTime, bool oneSecondElapsed); + LinphoneStatus redirect (const std::string &redirectUri); + LinphoneStatus redirect (const Address &redirectAddr); virtual void startIncomingNotification (); virtual int startInvite (const Address *destination, const std::string &subject = ""); LinphoneStatus terminate (const LinphoneErrorInfo *ei = nullptr); diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index 18ff22f56..31f8da816 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -230,6 +230,7 @@ private: void handleIncomingReceivedStateInIncomingNotification () override; bool isReadyForInvite () const override; LinphoneStatus pause (); + int restartInvite () override; void setTerminated () override; LinphoneStatus startAcceptUpdate (LinphoneCallState nextState, const std::string &stateInfo) override; LinphoneStatus startUpdate (const std::string &subject = "") override; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index d159a4dca..505821151 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -264,27 +264,21 @@ bool MediaSessionPrivate::failure () { if (i == 0) lInfo() << "Retrying CallSession [" << q << "] with SAVP"; params->enableAvpf(false); -#if 0 - linphone_call_restart_invite(call); -#endif + restartInvite(); return true; } else if (!linphone_core_is_media_encryption_mandatory(core)) { if (i == 0) lInfo() << "Retrying CallSession [" << q << "] with AVP"; params->setMediaEncryption(LinphoneMediaEncryptionNone); memset(localDesc->streams[i].crypto, 0, sizeof(localDesc->streams[i].crypto)); -#if 0 - linphone_call_restart_invite(call); -#endif + restartInvite(); return true; } } else if (params->avpfEnabled()) { if (i == 0) lInfo() << "Retrying CallSession [" << q << "] with AVP"; params->enableAvpf(false); -#if 0 - linphone_call_restart_invite(call); -#endif + restartInvite(); return true; } } @@ -3684,6 +3678,12 @@ LinphoneStatus MediaSessionPrivate::pause () { return 0; } +int MediaSessionPrivate::restartInvite () { + stopStreams(); + initializeStreams(); + return CallSessionPrivate::restartInvite(); +} + void MediaSessionPrivate::setTerminated () { freeResources(); CallSessionPrivate::setTerminated(); From 18f0782b469cd92b0f439bb3e5b417595256bd1f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 2 Oct 2017 16:58:02 +0200 Subject: [PATCH 0278/2215] Take a ref when creating a bctbx_list of C pointers from a std::list of shared_ptr --- src/c-wrapper/internal/c-tools.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 25aecf70d..b200979da 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -367,8 +367,9 @@ public: > static inline bctbx_list_t *getResolvedCListFromCppList (const std::list> &cppList) { bctbx_list_t *result = nullptr; - for (const auto &value : cppList) - result = bctbx_list_append(result, getCBackPtr(value)); + for (const auto &value : cppList) { + result = bctbx_list_append(result, belle_sip_object_ref(getCBackPtr(value))); + } return result; } @@ -379,7 +380,7 @@ public: static inline bctbx_list_t *getResolvedCListFromCppList (const std::list &cppList) { bctbx_list_t *result = nullptr; for (const auto &value : cppList) - result = bctbx_list_append(result, getCBackPtr(value)); + result = bctbx_list_append(result, belle_sip_object_ref(getCBackPtr(value))); return result; } From 429a231cb022e1db63c32d92e48d60f36b556cfe Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 2 Oct 2017 17:08:40 +0200 Subject: [PATCH 0279/2215] fix(c-wrapper): use abort instead of fatal --- src/c-wrapper/internal/c-tools.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index b200979da..df944e22d 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -113,9 +113,9 @@ private: // Runtime checker. // --------------------------------------------------------------------------- - static inline void fatal (const char *message) { - std::cout << "[FATAL C-WRAPPER]" << message << std::endl; - //exit(1); + static inline void abort (const char *message) { + std::cerr << "[FATAL C-WRAPPER]" << message << std::endl; + std::abort(); } public: @@ -135,7 +135,7 @@ public: CppDerivedPrivateType *derived = dynamic_cast(base); if (!derived) - fatal("Invalid cast."); + abort("Invalid cast."); return derived; #else return static_cast(base); @@ -170,11 +170,11 @@ public: std::shared_ptr cppObject = reinterpret_cast *>(cObject)->cppPtr; if (!cppObject) - fatal("Cpp Object is null."); + abort("Cpp Object is null."); std::shared_ptr derivedCppObject = std::static_pointer_cast(cppObject); if (!derivedCppObject) - fatal("Invalid derived cpp object."); + abort("Invalid derived cpp object."); return derivedCppObject; #else @@ -207,11 +207,11 @@ public: BaseType *cppObject = reinterpret_cast *>(cObject)->cppPtr; if (!cppObject) - fatal("Cpp Object is null."); + abort("Cpp Object is null."); DerivedType *derivedCppObject = dynamic_cast(cppObject); if (!derivedCppObject) - fatal("Invalid derived cpp object."); + abort("Invalid derived cpp object."); return derivedCppObject; #else @@ -294,9 +294,9 @@ public: return nullptr; try { - return getCBackPtr(std::static_pointer_cast(cppObject->shared_from_this())); + return getCBackPtr(std::static_pointer_cast(cppObject->sharedFromThis())); } catch (const std::bad_weak_ptr &e) { - fatal(e.what()); + abort(e.what()); } L_ASSERT(false); From c699446974e800e623eb1f93c83da990975a38a9 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 2 Oct 2017 17:12:06 +0200 Subject: [PATCH 0280/2215] fix(c-wrapper): use shared_from_this --- src/c-wrapper/internal/c-tools.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index df944e22d..8f4c2749c 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -294,7 +294,7 @@ public: return nullptr; try { - return getCBackPtr(std::static_pointer_cast(cppObject->sharedFromThis())); + return getCBackPtr(std::static_pointer_cast(cppObject->shared_from_this())); } catch (const std::bad_weak_ptr &e) { abort(e.what()); } From 83e8d95af521a759e3ec7b2738b43121cdf413a9 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 2 Oct 2017 17:12:45 +0200 Subject: [PATCH 0281/2215] Catch another bad_weak_ptr exception --- src/chat/chat-room.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index a861e0843..5a6abe170 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -91,7 +91,6 @@ void ChatRoomPrivate::release () { msg->cancelFileTransfer(); msg->getPrivate()->setChatRoom(nullptr); } catch(const std::bad_weak_ptr& e) {} - } for (auto &message : transientMessages) { message->cancelFileTransfer(); @@ -336,9 +335,11 @@ shared_ptr ChatRoomPrivate::getTransientMessage (unsigned int stora std::shared_ptr ChatRoomPrivate::getWeakMessage (unsigned int storageId) const { for (auto &message : weakMessages) { - shared_ptr msg(message); - if (msg->getPrivate()->getStorageId() == storageId) - return msg; + try { + shared_ptr msg(message); + if (msg->getPrivate()->getStorageId() == storageId) + return msg; + } catch(const std::bad_weak_ptr& e) {} } return nullptr; } From 1e285da9593343225a30870aeb2b590513c3972f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 2 Oct 2017 17:41:46 +0200 Subject: [PATCH 0282/2215] Fix creation of ChatMessage from history if id is null --- src/chat/chat-room.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 5a6abe170..4a99b6a79 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -297,7 +297,9 @@ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colN if (argv[10]) { message->setAppdata(argv[10]); } - message->setId(argv[12]); + if (argv[12]) { + message->setId(argv[12]); + } message->setIsSecured((bool)atoi(argv[14])); if (argv[11]) { From b5e0165503501a7a4eb7e8f405734db2b7b1d0c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Fri, 29 Sep 2017 17:52:38 +0200 Subject: [PATCH 0283/2215] Reworks Sal in order to be able to send and accept INVITEs with not-SDP body --- coreapi/sal/call_op.cpp | 237 ++++++++++++++++------------ coreapi/sal/call_op.h | 75 +++++---- coreapi/sal/sal_op.cpp | 4 - coreapi/sal/sal_op.h | 3 - src/c-wrapper/api/c-call-params.cpp | 4 +- src/content/content.cpp | 5 + src/content/content.h | 2 + tester/call_single_tester.c | 15 +- 8 files changed, 204 insertions(+), 141 deletions(-) diff --git a/coreapi/sal/call_op.cpp b/coreapi/sal/call_op.cpp index 7ee12ad0d..68daf9355 100644 --- a/coreapi/sal/call_op.cpp +++ b/coreapi/sal/call_op.cpp @@ -3,21 +3,27 @@ #include "offeranswer.h" #include #include -#include using namespace std; -#define SIP_MESSAGE_BODY_LIMIT 16*1024 // 16kB - LINPHONE_BEGIN_NAMESPACE +SalCallOp::~SalCallOp() { + if (this->local_media) sal_media_description_unref(this->local_media); + if (this->remote_media) sal_media_description_unref(this->remote_media); +} + int SalCallOp::set_local_media_description(SalMediaDescription *desc) { - if (this->custom_body.getBody().size() > 0) { - bctbx_error("cannot set local media description on SalOp [%p] because a custom body is already set", this); - return -1; - } - if (desc) sal_media_description_ref(desc); + + belle_sip_error_code error; + belle_sdp_session_description_t *sdp = media_description_to_sdp(desc); + vector buffer = marshal_media_description(sdp, error); + if (error != BELLE_SIP_OK) return -1; + + this->local_body.setContentType("application/sdp"); + this->local_body.setBody(move(buffer)); + if (this->local_media) sal_media_description_unref(this->local_media); this->local_media=desc; @@ -33,21 +39,30 @@ int SalCallOp::set_local_media_description(SalMediaDescription *desc) { return 0; } -int SalCallOp::set_local_custom_body(const Content &body) { - if (this->local_media) { - bctbx_error("cannot set custom body on SalOp [%p] because a local media description is already set", this); - return -1; - } - this->custom_body = body; - return 0; +int SalCallOp::set_local_body(const Content &body) { + Content bodyCopy = body; + return set_local_body(move(bodyCopy)); } -int SalCallOp::set_local_custom_body(const Content &&body) { - if (this->local_media) { - bctbx_error("cannot set custom body on SalOp [%p] because a local media description is already set", this); - return -1; +int SalCallOp::set_local_body(const Content &&body) { + if (!body.isValid()) return -1; + + if (body.getContentType() == "application/sdp") { + SalMediaDescription *desc = NULL; + if (body.getSize() > 0) { + belle_sdp_session_description_t *sdp = belle_sdp_session_description_parse(body.getBodyAsString().c_str()); + if (sdp == NULL) return -1; + desc = sal_media_description_new(); + if (sdp_to_media_description(sdp, desc) != 0) { + sal_media_description_unref(desc); + return -1; + } + } + if (this->local_media) sal_media_description_unref(this->local_media); + this->local_media = desc; } - this->custom_body = body; + + this->local_body = body; return 0; } @@ -64,38 +79,31 @@ int SalCallOp::set_custom_body(belle_sip_message_t *msg, const Content &body) { size_t bodySize = body.getBody().size(); if (bodySize > SIP_MESSAGE_BODY_LIMIT) { - bctbx_error("trying to add a body greater than %dkB to message [%p]", SIP_MESSAGE_BODY_LIMIT/1024, msg); - return -1; - } - if (bodySize == 0) { - bctbx_error("trying to add an empty custom body to message [%p]", msg); - return -1; - } - if (!contentType.isValid()) { - bctbx_error("trying to add a custom body with an invalid content type to message [%p]", msg); + bctbx_error("trying to add a body greater than %lukB to message [%p]", (unsigned long)SIP_MESSAGE_BODY_LIMIT/1024, msg); return -1; } - belle_sip_header_content_type_t *content_type = belle_sip_header_content_type_create(contentType.getType().c_str(), contentType.getSubType().c_str()); + if (contentType.isValid()) { + belle_sip_header_content_type_t *content_type = belle_sip_header_content_type_create(contentType.getType().c_str(), contentType.getSubType().c_str()); + belle_sip_message_add_header(msg, BELLE_SIP_HEADER(content_type)); + } belle_sip_header_content_length_t *content_length = belle_sip_header_content_length_create(bodySize); - belle_sip_message_add_header(msg, BELLE_SIP_HEADER(content_type)); belle_sip_message_add_header(msg, BELLE_SIP_HEADER(content_length)); - char *buffer = bctbx_new(char, bodySize); - memcpy(buffer, body.getBody().data(), bodySize); - belle_sip_message_assign_body(msg, buffer, bodySize); + if (bodySize > 0) { + char *buffer = bctbx_new(char, bodySize); + memcpy(buffer, body.getBody().data(), bodySize); + belle_sip_message_assign_body(msg, buffer, bodySize); + } return 0; } -int SalCallOp::set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* session_desc) { - belle_sip_error_code error = BELLE_SIP_BUFFER_OVERFLOW; +std::vector SalCallOp::marshal_media_description(belle_sdp_session_description_t *session_desc, belle_sip_error_code &error) { size_t length = 0; size_t bufLen = 2048; - - if (session_desc == NULL) return -1; - vector buff(bufLen); + error = BELLE_SIP_BUFFER_OVERFLOW; /* try to marshal the description. This could go higher than 2k so we iterate */ while( error != BELLE_SIP_OK && bufLen <= SIP_MESSAGE_BODY_LIMIT) { @@ -106,12 +114,24 @@ int SalCallOp::set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* buff.resize(bufLen); } } + /* give up if hard limit reached */ if (error != BELLE_SIP_OK) { ms_error("Buffer too small (%d) or not enough memory, giving up SDP", (int)bufLen); - return -1; + return std::vector(); // return a new vector in order to free the buffer held by 'buff' vector } + buff.resize(length); + return buff; +} + +int SalCallOp::set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* session_desc) { + belle_sip_error_code error; + + if (session_desc == NULL) return -1; + + vector buff = marshal_media_description(session_desc, error); + if (error != BELLE_SIP_OK) return -1; Content body; body.setContentType("application/sdp"); @@ -132,18 +152,12 @@ int SalCallOp::set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescrip void SalCallOp::fill_invite(belle_sip_request_t* invite) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(create_allow(this->root->enable_sip_update))); - if (this->root->session_expires!=0){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Session-expires", "600;refresher=uas")); belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Supported", "timer")); } - if (this->local_media){ - this->sdp_offering=TRUE; - set_sdp_from_desc(BELLE_SIP_MESSAGE(invite),this->local_media); - } else this->sdp_offering=FALSE; - if (this->custom_body.getBody().size() > 0) { - set_custom_body(BELLE_SIP_MESSAGE(invite), this->custom_body); - } + this->sdp_offering = (this->local_body.getContentType() == "application/sdp"); + set_custom_body(BELLE_SIP_MESSAGE(invite), this->local_body); } void SalCallOp::set_released() { @@ -196,7 +210,7 @@ Content SalCallOp::extract_body(belle_sip_message_t *message) { return body; } -int SalCallOp::extract_sdp(belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error) { +int SalCallOp::parse_sdp_body(const Content &body,belle_sdp_session_description_t** session_desc, SalReason *error) { *session_desc = NULL; *error = SalReasonNone; @@ -210,12 +224,6 @@ int SalCallOp::extract_sdp(belle_sip_message_t* message,belle_sdp_session_descri ms_error("Simulating no SDP for op %p", this); return 0; } - - Content body = extract_body(message); - if (body.getContentType() != "application/sdp") { - *error = SalReasonUnsupportedContent; - return -1; - } *session_desc = belle_sdp_session_description_parse(body.getBodyAsString().c_str()); if (*session_desc == NULL) { @@ -290,21 +298,27 @@ void SalCallOp::sdp_process(){ } } -void SalCallOp::handle_sdp_from_response(belle_sip_response_t* response) { - belle_sdp_session_description_t* sdp; +void SalCallOp::handle_body_from_response(belle_sip_response_t* response) { SalReason reason; + belle_sdp_session_description_t* sdp; + Content body = extract_body(BELLE_SIP_MESSAGE(response)); if (this->remote_media){ sal_media_description_unref(this->remote_media); this->remote_media=NULL; } - if (extract_sdp(BELLE_SIP_MESSAGE(response),&sdp,&reason)==0) { - if (sdp){ - this->remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,this->remote_media); - }/*if no sdp in response, what can we do ?*/ + if (body.getContentType() == "application/sdp") { + if (parse_sdp_body(body, &sdp, &reason) == 0) { + if (sdp) { + this->remote_media = sal_media_description_new(); + sdp_to_media_description(sdp, this->remote_media); + this->remote_body = move(body); + }/*if no sdp in response, what can we do ?*/ + } + /* process sdp in any case to reset result media description*/ + if (this->local_media) sdp_process(); + } else { + this->remote_body = move(body); } - /* process sdp in any case to reset result media description*/ - if (this->local_media) sdp_process(); } void SalCallOp::set_error(belle_sip_response_t* response, bool_t fatal){ @@ -366,7 +380,7 @@ void SalCallOp::process_response_cb(void *op_base, const belle_sip_response_even } else if (code >= 180 && code<200) { belle_sip_response_t *prev_response=reinterpret_cast(belle_sip_object_data_get(BELLE_SIP_OBJECT(dialog),"early_response")); if (!prev_response || code>belle_sip_response_get_status_code(prev_response)){ - op->handle_sdp_from_response(response); + op->handle_body_from_response(response); op->root->callbacks.call_ringing(op); } belle_sip_object_data_set(BELLE_SIP_OBJECT(dialog),"early_response",belle_sip_object_ref(response),belle_sip_object_unref); @@ -376,7 +390,7 @@ void SalCallOp::process_response_cb(void *op_base, const belle_sip_response_even } } else if (code >=200 && code<300) { if (strcmp("UPDATE",method)==0) { - op->handle_sdp_from_response(response); + op->handle_body_from_response(response); op->root->callbacks.call_accepted(op); } else if (strcmp("CANCEL", method) == 0) { op->root->callbacks.call_cancel_done(op); @@ -390,7 +404,7 @@ void SalCallOp::process_response_cb(void *op_base, const belle_sip_response_even case State::Active: /*re-invite, INFO, UPDATE case*/ if (strcmp("INVITE",method)==0){ if (code >=200 && code<300) { - op->handle_sdp_from_response(response); + op->handle_body_from_response(response); ack=belle_sip_dialog_create_ack(op->dialog,belle_sip_dialog_get_local_seq_number(op->dialog)); if (ack == NULL) { ms_error("This call has been already terminated."); @@ -518,30 +532,58 @@ int SalCallOp::is_media_description_acceptable(SalMediaDescription *md) { return TRUE; } -SalReason SalCallOp::process_sdp_for_invite(belle_sip_request_t* invite) { - belle_sdp_session_description_t* sdp; +SalReason SalCallOp::process_body_for_invite(belle_sip_request_t* invite) { SalReason reason = SalReasonNone; - SalErrorInfo sei; + + Content body = extract_body(BELLE_SIP_MESSAGE(invite)); + if (!body.isValid()) return SalReasonUnsupportedContent; + + if (body.getContentType() == "application/sdp") { + belle_sdp_session_description_t* sdp; + if (parse_sdp_body(body, &sdp, &reason) == 0) { + if (sdp) { + this->sdp_offering = FALSE; + if (this->remote_media) sal_media_description_unref(this->remote_media); + this->remote_media = sal_media_description_new(); + sdp_to_media_description(sdp, this->remote_media); + /*make some sanity check about the SDP received*/ + if (!is_media_description_acceptable(this->remote_media)) { + reason = SalReasonNotAcceptable; + } + belle_sip_object_unref(sdp); + } else this->sdp_offering = TRUE; /*INVITE without SDP*/ + } + if (reason != SalReasonNone) { + SalErrorInfo sei; + memset(&sei, 0, sizeof(sei)); + sal_error_info_set(&sei, reason, "SIP", 0, NULL, NULL); + decline_with_error_info(&sei, NULL); + sal_error_info_reset(&sei); + } + } + this->remote_body = move(body); + return reason; +} - memset(&sei, 0, sizeof(sei)); - if (extract_sdp(BELLE_SIP_MESSAGE(invite),&sdp,&reason)==0) { - if (sdp){ - this->sdp_offering=FALSE; - this->remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,this->remote_media); - /*make some sanity check about the SDP received*/ - if (!is_media_description_acceptable(this->remote_media)){ - reason=SalReasonNotAcceptable; +SalReason SalCallOp::process_body_for_ack(belle_sip_request_t *ack) { + SalReason reason = SalReasonNone; + Content body = extract_body(BELLE_SIP_MESSAGE(ack)); + if (!body.isValid()) return SalReasonUnsupportedContent; + if (body.getContentType() == "application/sdp") { + belle_sdp_session_description_t *sdp; + if (parse_sdp_body(body, &sdp, &reason) == 0) { + if (sdp) { + if (this->remote_media) sal_media_description_unref(this->remote_media); + this->remote_media = sal_media_description_new(); + sdp_to_media_description(sdp, this->remote_media); + this->sdp_process(); + belle_sip_object_unref(sdp); + } else { + ms_warning("SDP expected in ACK but not found."); } - belle_sip_object_unref(sdp); - }else this->sdp_offering=TRUE; /*INVITE without SDP*/ - } - - if (reason != SalReasonNone){ - sal_error_info_set(&sei, reason,"SIP", 0, NULL, NULL); - decline_with_error_info(&sei,NULL); - sal_error_info_reset(&sei); + } } + this->remote_body = move(body); return reason; } @@ -581,7 +623,6 @@ void SalCallOp::process_request_event_cb(void *op_base, const belle_sip_request_ SalCallOp * op = (SalCallOp *)op_base; SalReason reason; belle_sip_server_transaction_t* server_transaction=NULL; - belle_sdp_session_description_t* sdp; belle_sip_request_t* req = belle_sip_request_event_get_request(event); belle_sip_dialog_state_t dialog_state; belle_sip_response_t* resp; @@ -624,7 +665,7 @@ void SalCallOp::process_request_event_cb(void *op_base, const belle_sip_request_ ms_warning("replace header already set"); } - if ( (reason = op->process_sdp_for_invite(req)) == SalReasonNone) { + if ( (reason = op->process_body_for_invite(req)) == SalReasonNone) { if ((call_info=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Call-Info"))) { if( strstr(belle_sip_header_get_unparsed_value(call_info),"answer-after=") != NULL) { op->auto_answer_asked=TRUE; @@ -659,7 +700,7 @@ void SalCallOp::process_request_event_cb(void *op_base, const belle_sip_request_ belle_sip_server_transaction_send_response(server_transaction,resp); } else if (strcmp("UPDATE",method)==0) { op->reset_descriptions(); - if (op->process_sdp_for_invite(req)==SalReasonNone) + if (op->process_body_for_invite(req)==SalReasonNone) op->root->callbacks.call_updating(op,TRUE); } else { belle_sip_error("Unexpected method [%s] for dialog state BELLE_SIP_DIALOG_EARLY",belle_sip_request_get_method(req)); @@ -673,19 +714,7 @@ void SalCallOp::process_request_event_cb(void *op_base, const belle_sip_request_ if (!op->pending_client_trans || !belle_sip_transaction_state_is_transient(belle_sip_transaction_get_state((belle_sip_transaction_t*)op->pending_client_trans))){ if (op->sdp_offering){ - SalReason reason; - if (op->extract_sdp(BELLE_SIP_MESSAGE(req),&sdp,&reason)==0) { - if (sdp){ - if (op->remote_media) - sal_media_description_unref(op->remote_media); - op->remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->remote_media); - op->sdp_process(); - belle_sip_object_unref(sdp); - }else{ - ms_warning("SDP expected in ACK but not found."); - } - } + op->process_body_for_ack(req); } op->root->callbacks.call_ack_received(op, (SalCustomHeader*)req); }else{ @@ -705,7 +734,7 @@ void SalCallOp::process_request_event_cb(void *op_base, const belle_sip_request_ } else { /*re-invite*/ op->reset_descriptions(); - if (op->process_sdp_for_invite(req)==SalReasonNone) + if (op->process_body_for_invite(req)==SalReasonNone) op->root->callbacks.call_updating(op,is_update); } } else if (strcmp("INFO",method)==0){ diff --git a/coreapi/sal/call_op.h b/coreapi/sal/call_op.h index 8ac3605bb..1b4757d37 100644 --- a/coreapi/sal/call_op.h +++ b/coreapi/sal/call_op.h @@ -28,12 +28,14 @@ LINPHONE_BEGIN_NAMESPACE class SalCallOp: public SalOp, public SalMessageOpInterface { public: SalCallOp(Sal *sal): SalOp(sal) {} + ~SalCallOp() override; int set_local_media_description(SalMediaDescription *desc); - int set_local_custom_body(const Content &body); - int set_local_custom_body(const Content &&bdoy); + int set_local_body(const Content &body); + int set_local_body(const Content &&body); SalMediaDescription *get_remote_media_description() {return this->remote_media;} + const Content &get_remote_body() const {return this->remote_body;} SalMediaDescription *get_final_media_description(); int call(const char *from, const char *to, const char *subject); @@ -47,7 +49,7 @@ public: int refer(const char *refer_to_); int refer_with_replaces(SalCallOp *other_call_op); int set_referer(SalCallOp *refered_call); - SalCallOp *get_replaces(); + SalCallOp *get_replaces(); int send_dtmf(char dtmf); int terminate() {return terminate_with_error(NULL);} int terminate_with_error(const SalErrorInfo *info); @@ -62,46 +64,65 @@ public: void set_replaces(const char *call_id, const char *from_tag, const char *to_tag); void set_sdp_handling(SalOpSDPHandling handling); -// int send_message(const char *from, const char *to, const char *msg) override {return MessageOpInterface::send_message(from, to, msg);} + // Implementation of SalMessageOpInterface int send_message(const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri) override; int reply(SalReason reason) override {return SalOp::reply_message(reason);} private: + virtual void fill_cbs() override; + void set_released(); + + void set_error(belle_sip_response_t* response, bool_t fatal); + void call_terminated(belle_sip_server_transaction_t* server_transaction, int status_code, belle_sip_request_t* cancel_request); + void reset_descriptions(); + + int parse_sdp_body(const Content &body,belle_sdp_session_description_t** session_desc, SalReason *error); + void sdp_process(); + void handle_body_from_response(belle_sip_response_t* response); + SalReason process_body_for_invite(belle_sip_request_t* invite); + SalReason process_body_for_ack(belle_sip_request_t *ack); + void handle_offer_answer_response(belle_sip_response_t* response); + + void fill_invite(belle_sip_request_t* invite); + void cancelling_invite(const SalErrorInfo *info); + int refer_to(belle_sip_header_refer_to_t* refer_to, belle_sip_header_referred_by_t* referred_by); + int send_notify_for_refer(int code, const char *reason); + void notify_last_response(SalCallOp *newcall); + void process_refer(const belle_sip_request_event_t *event, belle_sip_server_transaction_t *server_transaction); + void process_notify(const belle_sip_request_event_t *event, belle_sip_server_transaction_t* server_transaction); + + static void set_addr_to_0000(char value[], size_t sz); + static int is_media_description_acceptable(SalMediaDescription *md); + static bool_t is_a_pending_invite_incoming_transaction(belle_sip_transaction_t *tr); + static void set_call_as_released(SalCallOp *op); + static void unsupported_method(belle_sip_server_transaction_t* server_transaction,belle_sip_request_t* request); + static belle_sip_header_reason_t *make_reason_header( const SalErrorInfo *info); static belle_sip_header_allow_t *create_allow(bool_t enable_update); + static std::vector marshal_media_description(belle_sdp_session_description_t *session_desc, belle_sip_error_code &error); + + // belle_sip_message handlers static int set_custom_body(belle_sip_message_t *msg, const Content &body); static int set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* session_desc); static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription *desc); - void set_released(); static void process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event); - void cancelling_invite(const SalErrorInfo *info); static Content extract_body(belle_sip_message_t *message); - int extract_sdp(belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error); - static void set_addr_to_0000(char value[], size_t sz); - void sdp_process(); - void handle_sdp_from_response(belle_sip_response_t* response); - void set_error(belle_sip_response_t* response, bool_t fatal); + + // Callbacks static int vfu_retry_cb (void *user_data, unsigned int events); static void process_response_cb(void *op_base, const belle_sip_response_event_t *event); static void process_timeout_cb(void *user_ctx, const belle_sip_timeout_event_t *event); static void process_transaction_terminated_cb(void *user_ctx, const belle_sip_transaction_terminated_event_t *event); - static int is_media_description_acceptable(SalMediaDescription *md); - SalReason process_sdp_for_invite(belle_sip_request_t* invite); - void call_terminated(belle_sip_server_transaction_t* server_transaction, int status_code, belle_sip_request_t* cancel_request); - void reset_descriptions(); - static void unsupported_method(belle_sip_server_transaction_t* server_transaction,belle_sip_request_t* request); - static bool_t is_a_pending_invite_incoming_transaction(belle_sip_transaction_t *tr); static void process_request_event_cb(void *op_base, const belle_sip_request_event_t *event); - static void set_call_as_released(SalCallOp *op); static void process_dialog_terminated_cb(void *ctx, const belle_sip_dialog_terminated_event_t *event); - virtual void fill_cbs() override; - void fill_invite(belle_sip_request_t* invite); - static belle_sip_header_reason_t *make_reason_header( const SalErrorInfo *info); - int refer_to(belle_sip_header_refer_to_t* refer_to, belle_sip_header_referred_by_t* referred_by); - void notify_last_response(SalCallOp *newcall); - int send_notify_for_refer(int code, const char *reason); - void process_refer(const belle_sip_request_event_t *event, belle_sip_server_transaction_t *server_transaction); - void process_notify(const belle_sip_request_event_t *event, belle_sip_server_transaction_t* server_transaction); - void handle_offer_answer_response(belle_sip_response_t* response); + + // Private constants + static const size_t SIP_MESSAGE_BODY_LIMIT = 16*1024; // 16kB + + // Attributes + SalMediaDescription *local_media = NULL; + SalMediaDescription *remote_media = NULL; + Content local_body; + Content remote_body; }; LINPHONE_END_NAMESPACE diff --git a/coreapi/sal/sal_op.cpp b/coreapi/sal/sal_op.cpp index a73d018ce..d3c26b8fd 100644 --- a/coreapi/sal/sal_op.cpp +++ b/coreapi/sal/sal_op.cpp @@ -95,10 +95,6 @@ SalOp::~SalOp() { if (this->remote_contact_address){ sal_address_destroy(this->remote_contact_address); } - if (this->local_media) - sal_media_description_unref(this->local_media); - if (this->remote_media) - sal_media_description_unref(this->remote_media); if (this->call_id) ms_free((void *)this->call_id); if (this->service_route) { diff --git a/coreapi/sal/sal_op.h b/coreapi/sal/sal_op.h index 118784620..8ae42afe8 100644 --- a/coreapi/sal/sal_op.h +++ b/coreapi/sal/sal_op.h @@ -211,9 +211,6 @@ protected: char *remote_ua = NULL; SalAddress* remote_contact_address = NULL; char *remote_contact = NULL; - SalMediaDescription *local_media = NULL; - SalMediaDescription *remote_media = NULL; - Content custom_body; void *user_pointer = NULL; const char* call_id = NULL; char* realm = NULL; diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index cec561f98..a6c55f39a 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -499,8 +499,10 @@ void linphone_call_params_unref (LinphoneCallParams *cp) { LinphoneCallParams *linphone_call_params_new (LinphoneCore *core) { LinphoneCallParams *params = _linphone_CallParams_init(); - L_SET_CPP_PTR_FROM_C_OBJECT(params, new LinphonePrivate::MediaSessionParams()); + auto mediaSessionParams = new LinphonePrivate::MediaSessionParams(); + L_SET_CPP_PTR_FROM_C_OBJECT(params, mediaSessionParams); L_GET_CPP_PTR_FROM_C_OBJECT(params)->initDefault(core); + delete mediaSessionParams; return params; } diff --git a/src/content/content.cpp b/src/content/content.cpp index fb2b64113..9c12562dc 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -132,4 +132,9 @@ bool Content::isEmpty () const { return getSize() == 0; } +bool Content::isValid() const { + L_D(); + return d->contentType.isValid() || d->body.empty(); +} + LINPHONE_END_NAMESPACE diff --git a/src/content/content.h b/src/content/content.h index 5c7b00c3a..352bcfcf0 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -55,6 +55,8 @@ public: void setBody (const void *buffer, size_t size); size_t getSize () const; + + bool isValid() const; bool isEmpty () const; diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index c658917d8..890a897a2 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -217,12 +217,17 @@ void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreMana break; } - linphone_call_stats_unref(audio_stats1); - linphone_call_stats_unref(audio_stats2); + if (audio_stats1) linphone_call_stats_unref(audio_stats1); + if (audio_stats2) linphone_call_stats_unref(audio_stats2); if (video_stats1) linphone_call_stats_unref(video_stats1); if (video_stats2) linphone_call_stats_unref(video_stats2); wait_for_until(caller->lc,callee->lc,NULL,0,20); /*just to sleep while iterating*/ }while (!liblinphone_tester_clock_elapsed(&ts,max_time_to_wait)); + + if (audio_stats1) linphone_call_stats_unref(audio_stats1); + if (audio_stats2) linphone_call_stats_unref(audio_stats2); + if (video_stats1) linphone_call_stats_unref(video_stats1); + if (video_stats2) linphone_call_stats_unref(video_stats2); audio_stats1 = linphone_call_get_audio_stats(c1); video_stats1 = linphone_call_get_video_stats(c1); @@ -262,6 +267,12 @@ void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreMana } } + + if (audio_stats1) linphone_call_stats_unref(audio_stats1); + if (audio_stats2) linphone_call_stats_unref(audio_stats2); + if (video_stats1) linphone_call_stats_unref(video_stats1); + if (video_stats2) linphone_call_stats_unref(video_stats2); + linphone_call_unref(c1); linphone_call_unref(c2); } From 231f0e3983f209476b7678030c16ad1fa00c212c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 3 Oct 2017 09:23:59 +0200 Subject: [PATCH 0284/2215] Add callback on chat room subject change. --- include/linphone/api/c-callbacks.h | 7 +++++++ include/linphone/api/c-chat-room-cbs.h | 14 ++++++++++++++ src/c-wrapper/api/c-chat-room-cbs.cpp | 9 +++++++++ src/chat/client-group-chat-room.cpp | 9 +++++++++ src/chat/client-group-chat-room.h | 1 + src/conference/conference-listener.h | 1 + src/conference/remote-conference.cpp | 2 ++ src/conference/remote-conference.h | 1 + 8 files changed, 44 insertions(+) diff --git a/include/linphone/api/c-callbacks.h b/include/linphone/api/c-callbacks.h index 347f03552..a6f6f0084 100644 --- a/include/linphone/api/c-callbacks.h +++ b/include/linphone/api/c-callbacks.h @@ -183,6 +183,13 @@ typedef void (*LinphoneChatRoomCbsParticipantAdminStatusChangedCb) (LinphoneChat */ typedef void (*LinphoneChatRoomCbsStateChangedCb) (LinphoneChatRoom *cr, LinphoneChatRoomState newState); +/** + * Callback used to notify that the subject of a chat room has changed. + * @param[in] cr #LinphoneChatRoom object + * @param[in] subject The new subject of the chat room + */ +typedef void (*LinphoneChatRoomCbsSubjectChangedCb) (LinphoneChatRoom *cr, const char *subject); + /** * Callback used to notify a chat room that a message has been received but we were unable to decrypt it * @param cr #LinphoneChatRoom involved in this conversation diff --git a/include/linphone/api/c-chat-room-cbs.h b/include/linphone/api/c-chat-room-cbs.h index aca42d1b2..62ffae9c7 100644 --- a/include/linphone/api/c-chat-room-cbs.h +++ b/include/linphone/api/c-chat-room-cbs.h @@ -144,6 +144,20 @@ LINPHONE_PUBLIC LinphoneChatRoomCbsStateChangedCb linphone_chat_room_cbs_get_sta */ LINPHONE_PUBLIC void linphone_chat_room_cbs_set_state_changed (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsStateChangedCb cb); +/** + * Get the subject changed callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @return The current subject changed callback. + */ +LINPHONE_PUBLIC LinphoneChatRoomCbsSubjectChangedCb linphone_chat_room_cbs_get_subject_changed (const LinphoneChatRoomCbs *cbs); + +/** + * Set the subject changed callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @param[in] cb The subject changed callback to be used. + */ +LINPHONE_PUBLIC void linphone_chat_room_cbs_set_subject_changed (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsSubjectChangedCb cb); + /** * Get the undecryptable message received callback. * @param[in] cbs LinphoneChatRoomCbs object. diff --git a/src/c-wrapper/api/c-chat-room-cbs.cpp b/src/c-wrapper/api/c-chat-room-cbs.cpp index 34b78e27e..760ce31dc 100644 --- a/src/c-wrapper/api/c-chat-room-cbs.cpp +++ b/src/c-wrapper/api/c-chat-room-cbs.cpp @@ -31,6 +31,7 @@ struct _LinphoneChatRoomCbs { LinphoneChatRoomCbsParticipantRemovedCb participantRemovedCb; LinphoneChatRoomCbsParticipantAdminStatusChangedCb participantAdminStatusChangedCb; LinphoneChatRoomCbsStateChangedCb stateChangedCb; + LinphoneChatRoomCbsSubjectChangedCb subjectChangedCb; LinphoneChatRoomCbsUndecryptableMessageReceivedCb undecryptableMessageReceivedCb; }; @@ -116,6 +117,14 @@ void linphone_chat_room_cbs_set_state_changed (LinphoneChatRoomCbs *cbs, Linphon cbs->stateChangedCb = cb; } +LinphoneChatRoomCbsSubjectChangedCb linphone_chat_room_cbs_get_subject_changed (const LinphoneChatRoomCbs *cbs) { + return cbs->subjectChangedCb; +} + +void linphone_chat_room_cbs_set_subject_changed (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsSubjectChangedCb cb) { + cbs->subjectChangedCb = cb; +} + LinphoneChatRoomCbsUndecryptableMessageReceivedCb linphone_chat_room_cbs_get_undecryptable_message_received (const LinphoneChatRoomCbs *cbs) { return cbs->undecryptableMessageReceivedCb; } diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index fb21ca9cc..3e9302005 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -184,6 +184,15 @@ void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdm cb(cr, L_GET_C_BACK_PTR(participant), isAdmin); } +void ClientGroupChatRoom::onSubjectChanged (const std::string &subject) { + this->subject = subject; + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); + LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); + LinphoneChatRoomCbsSubjectChangedCb cb = linphone_chat_room_cbs_get_subject_changed(cbs); + if (cb) + cb(cr, subject.c_str()); +} + // ----------------------------------------------------------------------------- void ClientGroupChatRoom::onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const string &message) { diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index 05ba772f7..064cc27de 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -59,6 +59,7 @@ private: void onParticipantAdded (const Address &addr) override; void onParticipantRemoved (const Address &addr) override; void onParticipantSetAdmin (const Address &addr, bool isAdmin) override; + void onSubjectChanged (const std::string &subject) override; private: /* CallSessionListener */ diff --git a/src/conference/conference-listener.h b/src/conference/conference-listener.h index 713b3456f..fc67cf34e 100644 --- a/src/conference/conference-listener.h +++ b/src/conference/conference-listener.h @@ -32,6 +32,7 @@ public: virtual void onParticipantAdded (const Address &addr) = 0; virtual void onParticipantRemoved (const Address &addr) = 0; virtual void onParticipantSetAdmin (const Address &addr, bool isAdmin) = 0; + virtual void onSubjectChanged (const std::string &subject) = 0; }; LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index f83f10e67..1f38c4d13 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -92,4 +92,6 @@ void RemoteConference::onParticipantRemoved (const Address &addr) {} void RemoteConference::onParticipantSetAdmin (const Address &addr, bool isAdmin) {} +void RemoteConference::onSubjectChanged (const std::string &subject) {} + LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index 8ae6c2f1f..cf2956fed 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -48,6 +48,7 @@ protected: void onParticipantAdded (const Address &addr) override; void onParticipantRemoved (const Address &addr) override; void onParticipantSetAdmin (const Address &addr, bool isAdmin) override; + void onSubjectChanged (const std::string &subject) override; protected: RemoteConferenceEventHandler *eventHandler = nullptr; From fc7a8e0eec158abcafd48def33ec51efae1c60be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Tue, 3 Oct 2017 10:25:47 +0200 Subject: [PATCH 0285/2215] Fix double frees in liblinphone_tester_check_rtcp() --- tester/call_single_tester.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index 890a897a2..514c524dc 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -185,11 +185,15 @@ void linphone_call_iframe_decoded_cb(LinphoneCall *call,void * user_data) { counters->number_of_IframeDecoded++; } +#define reset_call_stats(var, value) \ + if (var) linphone_call_stats_unref(var); \ + var = value + void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreManager* callee) { LinphoneCall *c1,*c2; MSTimeSpec ts; int max_time_to_wait; - LinphoneCallStats *audio_stats1, *video_stats1, *audio_stats2, *video_stats2; + LinphoneCallStats *audio_stats1 = NULL, *video_stats1 = NULL, *audio_stats2 = NULL, *video_stats2 = NULL; c1=linphone_core_get_current_call(caller->lc); c2=linphone_core_get_current_call(callee->lc); @@ -206,10 +210,10 @@ void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreMana max_time_to_wait = 5000; do { - audio_stats1 = linphone_call_get_audio_stats(c1); - video_stats1 = linphone_call_get_video_stats(c1); - audio_stats2 = linphone_call_get_audio_stats(c2); - video_stats2 = linphone_call_get_video_stats(c2); + reset_call_stats(audio_stats1, linphone_call_get_audio_stats(c1)); + reset_call_stats(video_stats1, linphone_call_get_video_stats(c1)); + reset_call_stats(audio_stats2, linphone_call_get_audio_stats(c2)); + reset_call_stats(video_stats2, linphone_call_get_video_stats(c2)); if (linphone_call_stats_get_round_trip_delay(audio_stats1) > 0.0 && linphone_call_stats_get_round_trip_delay(audio_stats2) > 0.0 && (!linphone_call_log_video_enabled(linphone_call_get_call_log(c1)) || linphone_call_stats_get_round_trip_delay(video_stats1)>0.0) @@ -217,22 +221,13 @@ void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreMana break; } - if (audio_stats1) linphone_call_stats_unref(audio_stats1); - if (audio_stats2) linphone_call_stats_unref(audio_stats2); - if (video_stats1) linphone_call_stats_unref(video_stats1); - if (video_stats2) linphone_call_stats_unref(video_stats2); wait_for_until(caller->lc,callee->lc,NULL,0,20); /*just to sleep while iterating*/ }while (!liblinphone_tester_clock_elapsed(&ts,max_time_to_wait)); - if (audio_stats1) linphone_call_stats_unref(audio_stats1); - if (audio_stats2) linphone_call_stats_unref(audio_stats2); - if (video_stats1) linphone_call_stats_unref(video_stats1); - if (video_stats2) linphone_call_stats_unref(video_stats2); - - audio_stats1 = linphone_call_get_audio_stats(c1); - video_stats1 = linphone_call_get_video_stats(c1); - audio_stats2 = linphone_call_get_audio_stats(c2); - video_stats2 = linphone_call_get_video_stats(c2); + reset_call_stats(audio_stats1, linphone_call_get_audio_stats(c1)); + reset_call_stats(video_stats1, linphone_call_get_video_stats(c1)); + reset_call_stats(audio_stats2, linphone_call_get_audio_stats(c2)); + reset_call_stats(video_stats2, linphone_call_get_video_stats(c2)); if (linphone_core_rtcp_enabled(caller->lc) && linphone_core_rtcp_enabled(callee->lc)) { BC_ASSERT_GREATER(caller->stat.number_of_rtcp_received, 1, int, "%i"); BC_ASSERT_GREATER(callee->stat.number_of_rtcp_received, 1, int, "%i"); From da23396b6e443fed7f72aa0185a141d45ea26870 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 3 Oct 2017 10:48:14 +0200 Subject: [PATCH 0286/2215] add subject handling to xml conference description --- .../local-conference-event-handler.cpp | 16 ++++++++++++++++ .../remote-conference-event-handler.cpp | 3 +++ 2 files changed, 19 insertions(+) diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index dd7734a47..7e99bf8c7 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -90,9 +90,13 @@ void LocalConferenceEventHandlerPrivate::notifyAll(string notify) { string LocalConferenceEventHandlerPrivate::createNotifyFullState() { string entity = this->conf->getConferenceAddress()->asStringUriOnly(); + string subject = this->conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); UsersType users; + ConferenceDescriptionType confDescr = ConferenceDescriptionType(); + confDescr.setSubject(subject); confInfo.setUsers(users); + confInfo.setConferenceDescription((const ConferenceDescriptionType) confDescr); for (const auto &participant : this->conf->getParticipants()) { UserType user = UserType(); @@ -109,9 +113,13 @@ string LocalConferenceEventHandlerPrivate::createNotifyFullState() { string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded(const Address &addr) { string entity = this->conf->getConferenceAddress()->asStringUriOnly(); + string subject = this->conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); UsersType users; + ConferenceDescriptionType confDescr = ConferenceDescriptionType(); + confDescr.setSubject(subject); confInfo.setUsers(users); + confInfo.setConferenceDescription((const ConferenceDescriptionType)confDescr); UserType user = UserType(); UserRolesType roles; @@ -126,9 +134,13 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded(const Ad string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved(const Address &addr) { string entity = this->conf->getConferenceAddress()->asStringUriOnly(); + string subject = this->conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); UsersType users; + ConferenceDescriptionType confDescr = ConferenceDescriptionType(); + confDescr.setSubject(subject); confInfo.setUsers(users); + confInfo.setConferenceDescription((const ConferenceDescriptionType)confDescr); UserType user = UserType(); user.setEntity(addr.asStringUriOnly()); @@ -140,9 +152,13 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved(const string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined(const Address &addr, bool isAdmin) { string entity = this->conf->getConferenceAddress()->asStringUriOnly(); + string subject = this->conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); UsersType users; + ConferenceDescriptionType confDescr = ConferenceDescriptionType(); + confDescr.setSubject(subject); confInfo.setUsers(users); + confInfo.setConferenceDescription((const ConferenceDescriptionType)confDescr); UserType user = UserType(); UserRolesType roles; diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 2acc7bbee..19d45c51e 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -83,6 +83,9 @@ void RemoteConferenceEventHandler::notifyReceived(string xmlBody) { Address cleanedConfAddress = d->confAddress; cleanedConfAddress.setPort(0); if (confInfo->getEntity() == cleanedConfAddress.asString()) { + if(confInfo->getConferenceDescription().present() && confInfo->getConferenceDescription().get().getSubject().present()) + d->listener->onSubjectChanged(confInfo->getConferenceDescription().get().getSubject().get()); + for (const auto &user : confInfo->getUsers()->getUser()) { LinphoneAddress *cAddr = linphone_core_interpret_url(d->core, user.getEntity()->c_str()); char *cAddrStr = linphone_address_as_string(cAddr); From 61d1cdd8b04469709d32e6fc0b0df00828560aa2 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 3 Oct 2017 11:07:46 +0200 Subject: [PATCH 0287/2215] Added EncryptionChatMessageModifier + moved some logic of ChatMessage reception from ChatRoom to the message itself --- src/CMakeLists.txt | 2 + src/chat/chat-message-p.h | 4 + src/chat/chat-message.cpp | 86 +++++++++++++++---- src/chat/chat-room-p.h | 1 + src/chat/chat-room.cpp | 47 +--------- src/chat/modifier/chat-message-modifier.h | 5 +- .../modifier/cpim-chat-message-modifier.cpp | 6 +- .../modifier/cpim-chat-message-modifier.h | 4 +- .../encryption-chat-message-modifier.cpp | 68 +++++++++++++++ .../encryption-chat-message-modifier.h | 38 ++++++++ .../multipart-chat-message-modifier.cpp | 6 +- .../multipart-chat-message-modifier.h | 4 +- 12 files changed, 198 insertions(+), 73 deletions(-) create mode 100644 src/chat/modifier/encryption-chat-message-modifier.cpp create mode 100644 src/chat/modifier/encryption-chat-message-modifier.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0a73468af..fad0f570e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -48,6 +48,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES chat/is-composing.h chat/modifier/chat-message-modifier.h chat/modifier/cpim-chat-message-modifier.h + chat/modifier/encryption-chat-message-modifier.h chat/modifier/multipart-chat-message-modifier.h chat/real-time-text-chat-room-p.h chat/real-time-text-chat-room.h @@ -129,6 +130,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES chat/imdn.cpp chat/is-composing.cpp chat/modifier/cpim-chat-message-modifier.cpp + chat/modifier/encryption-chat-message-modifier.cpp chat/modifier/multipart-chat-message-modifier.cpp chat/real-time-text-chat-room.cpp conference/conference.cpp diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index f461d5c26..7fc20f851 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -29,6 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class ChatMessagePrivate : public ObjectPrivate { friend class CpimChatMessageModifier; + friend class EncryptionChatMessageModifier; friend class MultipartChatMessageModifier; public: @@ -98,6 +99,7 @@ public: void sendImdn(ImdnType imdnType, LinphoneReason reason); + LinphoneReason receive(); void send(); private: @@ -143,6 +145,8 @@ private: int startHttpTransfer(std::string url, std::string action, belle_http_request_listener_callbacks_t *cbs); void releaseHttpRequest(); + + std::shared_ptr getPublicSharedPtr(); // ----------------------------------------------------------------------------- diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index d854e9b48..d06008c2f 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -29,9 +29,11 @@ #include "content/content.h" #include "chat-room-p.h" #include "real-time-text-chat-room.h" -#include "modifier/multipart-chat-message-modifier.h" #include "modifier/cpim-chat-message-modifier.h" +#include "modifier/encryption-chat-message-modifier.h" +#include "modifier/multipart-chat-message-modifier.h" +#include "logger/logger.h" #include "ortp/b64.h" // ============================================================================= @@ -53,6 +55,11 @@ ChatMessagePrivate::~ChatMessagePrivate () {} // ----------------------------------------------------------------------------- +shared_ptr ChatMessagePrivate::getPublicSharedPtr() { + L_Q(); + return q->getSharedPtr(); +} + void ChatMessagePrivate::setChatRoom (shared_ptr cr) { chatRoom = cr; } @@ -887,6 +894,59 @@ void ChatMessagePrivate::releaseHttpRequest() { } } +LinphoneReason ChatMessagePrivate::receive() { + L_Q(); + + LinphoneReason reason = LinphoneReasonNone; + bool store = false; + + // --------------------------------------- + // Start of message modification + // --------------------------------------- + + EncryptionChatMessageModifier ecmm; + int retval = 0; + retval = ecmm.decode(this); + if (retval > 0) { + /* Unable to decrypt message */ + chatRoom->getPrivate()->notifyUndecryptableMessageReceived(getPublicSharedPtr()); + reason = linphone_error_code_to_reason(retval); + q->sendDeliveryNotification(reason); + /* Return LinphoneReasonNone to avoid flexisip resending us a message we can't decrypt */ + reason = LinphoneReasonNone; + goto end; + } + + // --------------------------------------- + // End of message modification + // --------------------------------------- + + if ((retval <= 0) && (linphone_core_is_content_type_supported(chatRoom->getCore(), getContentType().c_str()) == FALSE)) { + retval = 415; + lError() << "Unsupported MESSAGE (content-type " << getContentType() << " not recognized)"; + } + + if (retval > 0) { + reason = linphone_error_code_to_reason(retval); + q->sendDeliveryNotification(reason); + goto end; + } + + if (ContentType::isFileTransfer(getContentType())) { + create_file_transfer_information_from_vnd_gsma_rcs_ft_http_xml(L_GET_C_BACK_PTR(getPublicSharedPtr())); + store = true; + } else if (ContentType::isText(getContentType())) { + store = true; + } + + if (store) { + q->store(); + } + +end: + return reason; +} + void ChatMessagePrivate::send() { L_Q(); SalOp *op = salOp; @@ -941,19 +1001,14 @@ void ChatMessagePrivate::send() { if (!getContentType().empty()) { clearTextContentType = getContentType(); } - - int retval = -1; - LinphoneImEncryptionEngine *imee = chatRoom->getCore()->im_encryption_engine; - if (imee) { - LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); - if (cbProcessOutgoingMessage) { - retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(chatRoom), L_GET_C_BACK_PTR(q->getSharedPtr())); - if (retval == 0) { - isSecured = true; - } - } + + if (contents.size() > 1) { + MultipartChatMessageModifier mcmm; + mcmm.encode(this); } + + EncryptionChatMessageModifier ecmm; + int retval = ecmm.encode(this); if (retval > 0) { sal_error_info_set((SalErrorInfo *)op->get_error_info(), SalReasonNotAcceptable, "SIP", retval, "Unable to encrypt IM", nullptr); @@ -962,11 +1017,6 @@ void ChatMessagePrivate::send() { return; } - if (contents.size() > 1) { - MultipartChatMessageModifier mcmm; - mcmm.encode(this); - } - if (lp_config_get_int(chatRoom->getCore()->config, "sip", "use_cpim", 0) == 1) { CpimChatMessageModifier ccmm; ccmm.encode(this); diff --git a/src/chat/chat-room-p.h b/src/chat/chat-room-p.h index 02d6e802c..4bcd6792a 100644 --- a/src/chat/chat-room-p.h +++ b/src/chat/chat-room-p.h @@ -35,6 +35,7 @@ LINPHONE_BEGIN_NAMESPACE class ChatRoomPrivate : public ObjectPrivate, public IsComposingListener { + friend class ChatMessagePrivate; public: ChatRoomPrivate (LinphoneCore *core); virtual ~ChatRoomPrivate (); diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 4a99b6a79..ad33f152c 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -416,57 +416,20 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa if (salMsg->url) msg->setExternalBodyUrl(salMsg->url); - int retval = -1; - LinphoneImEncryptionEngine *imee = core->im_encryption_engine; - if (imee) { - LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsIncomingMessageCb cbProcessIncomingMessage = linphone_im_encryption_engine_cbs_get_process_incoming_message(imeeCbs); - if (cbProcessIncomingMessage) { - retval = cbProcessIncomingMessage(imee, L_GET_C_BACK_PTR(q), L_GET_C_BACK_PTR(msg)); - if (retval == 0) { - msg->setIsSecured(true); - } else if (retval > 0) { - /* Unable to decrypt message */ - notifyUndecryptableMessageReceived(msg); - reason = linphone_error_code_to_reason(retval); - msg->sendDeliveryNotification(reason); - /* Return LinphoneReasonNone to avoid flexisip resending us a message we can't decrypt */ - reason = LinphoneReasonNone; - goto end; - } - } - } + reason = msg->getPrivate()->receive(); - if ((retval <= 0) && (linphone_core_is_content_type_supported(core, msg->getPrivate()->getContentType().c_str()) == FALSE)) { - retval = 415; - lError() << "Unsupported MESSAGE (content-type " << msg->getPrivate()->getContentType() << " not recognized)"; - } - - if (retval > 0) { - reason = linphone_error_code_to_reason(retval); - msg->sendDeliveryNotification(reason); - goto end; - } - - if (ContentType::isFileTransfer(msg->getPrivate()->getContentType())) { - create_file_transfer_information_from_vnd_gsma_rcs_ft_http_xml(L_GET_C_BACK_PTR(msg)); - msg->setIsToBeStored(true); - } else if (ContentType::isImIsComposing(msg->getPrivate()->getContentType())) { + if (ContentType::isImIsComposing(msg->getPrivate()->getContentType())) { isComposingReceived(msg->getPrivate()->getText()); - msg->setIsToBeStored(false); increaseMsgCount = FALSE; if (lp_config_get_int(core->config, "sip", "deliver_imdn", 0) != 1) { goto end; } } else if (ContentType::isImdn(msg->getPrivate()->getContentType())) { imdnReceived(msg->getPrivate()->getText()); - msg->setIsToBeStored(false); increaseMsgCount = FALSE; if (lp_config_get_int(core->config, "sip", "deliver_imdn", 0) != 1) { goto end; } - } else if (ContentType::isText(msg->getPrivate()->getContentType())) { - msg->setIsToBeStored(true); } if (increaseMsgCount) { @@ -482,10 +445,6 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa chatMessageReceived(msg); - if (msg->isToBeStored()) { - msg->store(); - } - pendingMessage = nullptr; end: @@ -751,7 +710,7 @@ void ChatRoom::markAsRead () { sqlite3_free(buf); if (d->pendingMessage) { - d->pendingMessage->getPrivate()->setState(ChatMessage::State::Displayed); + d->pendingMessage->updateState(ChatMessage::State::Displayed); d->pendingMessage->sendDisplayNotification(); } diff --git a/src/chat/modifier/chat-message-modifier.h b/src/chat/modifier/chat-message-modifier.h index 0f4071df8..ed4741de4 100644 --- a/src/chat/modifier/chat-message-modifier.h +++ b/src/chat/modifier/chat-message-modifier.h @@ -20,7 +20,6 @@ #define _CHAT_MESSAGE_MODIFIER_H_ #include "linphone/utils/general.h" - #include "private.h" // ============================================================================= @@ -33,8 +32,8 @@ class ChatMessageModifier { public: virtual ~ChatMessageModifier () = default; - virtual void encode (ChatMessagePrivate *messagePrivate) = 0; - virtual void decode (ChatMessagePrivate *messagePrivate) = 0; + virtual int encode (ChatMessagePrivate *messagePrivate) = 0; + virtual int decode (ChatMessagePrivate *messagePrivate) = 0; }; LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index 33c2dba62..65cb25e1e 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -30,7 +30,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -void CpimChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { +int CpimChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { Cpim::Message message; Cpim::GenericHeader cpimContentTypeHeader; cpimContentTypeHeader.setName("Content-Type"); @@ -68,9 +68,10 @@ void CpimChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { newContent->setBody(message.asString()); messagePrivate->internalContent = newContent; } + return 0; } -void CpimChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { +int CpimChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { shared_ptr content; if (messagePrivate->internalContent) { content = messagePrivate->internalContent; @@ -94,6 +95,7 @@ void CpimChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { } else { //TODO } + return 0; } LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/cpim-chat-message-modifier.h b/src/chat/modifier/cpim-chat-message-modifier.h index 9d5696bb0..550887808 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.h +++ b/src/chat/modifier/cpim-chat-message-modifier.h @@ -29,8 +29,8 @@ class CpimChatMessageModifier : public ChatMessageModifier { public: CpimChatMessageModifier () = default; - void encode (ChatMessagePrivate *messagePrivate) override; - void decode (ChatMessagePrivate *messagePrivate) override; + int encode (ChatMessagePrivate *messagePrivate) override; + int decode (ChatMessagePrivate *messagePrivate) override; }; LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/encryption-chat-message-modifier.cpp b/src/chat/modifier/encryption-chat-message-modifier.cpp new file mode 100644 index 000000000..0949724b4 --- /dev/null +++ b/src/chat/modifier/encryption-chat-message-modifier.cpp @@ -0,0 +1,68 @@ +/* + * encryption-chat-message-modifier.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "encryption-chat-message-modifier.h" + +#include "object/object-p.h" +#include "c-wrapper/c-wrapper.h" + +#include "content/content-type.h" +#include "content/content.h" +#include "address/address.h" +#include "chat/chat-room.h" +#include "chat/chat-message-p.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +int EncryptionChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { + int retval = -1; + LinphoneImEncryptionEngine *imee = messagePrivate->chatRoom->getCore()->im_encryption_engine; + if (imee) { + LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); + if (cbProcessOutgoingMessage) { + retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(messagePrivate->chatRoom), L_GET_C_BACK_PTR(messagePrivate->getPublicSharedPtr())); + if (retval == 0) { + messagePrivate->isSecured = true; + } + } + } + return retval; +} + +int EncryptionChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { + int retval = -1; + LinphoneImEncryptionEngine *imee = messagePrivate->chatRoom->getCore()->im_encryption_engine; + if (imee) { + LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsIncomingMessageCb cbProcessIncomingMessage = linphone_im_encryption_engine_cbs_get_process_incoming_message(imeeCbs); + if (cbProcessIncomingMessage) { + retval = cbProcessIncomingMessage(imee, L_GET_C_BACK_PTR(messagePrivate->chatRoom), L_GET_C_BACK_PTR(messagePrivate->getPublicSharedPtr())); + if (retval == 0) { + messagePrivate->isSecured = true; + } + } + } + return retval; +} + +LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/encryption-chat-message-modifier.h b/src/chat/modifier/encryption-chat-message-modifier.h new file mode 100644 index 000000000..8389236a0 --- /dev/null +++ b/src/chat/modifier/encryption-chat-message-modifier.h @@ -0,0 +1,38 @@ +/* + * encryption-chat-message-modifier.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _ENCRYPTION_CHAT_MESSAGE_MODIFIER_H_ +#define _ENCRYPTION_CHAT_MESSAGE_MODIFIER_H_ + +#include "chat-message-modifier.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class EncryptionChatMessageModifier : public ChatMessageModifier { +public: + EncryptionChatMessageModifier () = default; + + int encode (ChatMessagePrivate *messagePrivate) override; + int decode (ChatMessagePrivate *messagePrivate) override; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _ENCRYPTION_CHAT_MESSAGE_MODIFIER_H_ diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index c3c8299ca..cdad3fc02 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -26,14 +26,16 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -void MultipartChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { +int MultipartChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { if (messagePrivate->contents.size() > 1) { //TODO } + return 0; } -void MultipartChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { +int MultipartChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { //TODO + return 0; } LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/multipart-chat-message-modifier.h b/src/chat/modifier/multipart-chat-message-modifier.h index 17361d3d6..23b8dbe79 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.h +++ b/src/chat/modifier/multipart-chat-message-modifier.h @@ -29,8 +29,8 @@ class MultipartChatMessageModifier : public ChatMessageModifier { public: MultipartChatMessageModifier () = default; - void encode (ChatMessagePrivate *message) override; - void decode (ChatMessagePrivate *message) override; + int encode (ChatMessagePrivate *message) override; + int decode (ChatMessagePrivate *message) override; }; LINPHONE_END_NAMESPACE From 28e77ff2e65a2dc4427abee0be18658c450ad504 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 3 Oct 2017 11:13:35 +0200 Subject: [PATCH 0288/2215] Added ChatMessageModifiers chain in reception --- src/chat/chat-message.cpp | 13 ++++++++++--- src/content/content-type.cpp | 4 ++++ src/content/content-type.h | 1 + 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index d06008c2f..7e5716b30 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -904,6 +904,11 @@ LinphoneReason ChatMessagePrivate::receive() { // Start of message modification // --------------------------------------- + if (ContentType::isCPIM(getContentType())) { + CpimChatMessageModifier ccmm; + ccmm.decode(this); + } + EncryptionChatMessageModifier ecmm; int retval = 0; retval = ecmm.decode(this); @@ -914,8 +919,11 @@ LinphoneReason ChatMessagePrivate::receive() { q->sendDeliveryNotification(reason); /* Return LinphoneReasonNone to avoid flexisip resending us a message we can't decrypt */ reason = LinphoneReasonNone; - goto end; + return reason; } + + MultipartChatMessageModifier mcmm; + mcmm.decode(this); // --------------------------------------- // End of message modification @@ -929,7 +937,7 @@ LinphoneReason ChatMessagePrivate::receive() { if (retval > 0) { reason = linphone_error_code_to_reason(retval); q->sendDeliveryNotification(reason); - goto end; + return reason; } if (ContentType::isFileTransfer(getContentType())) { @@ -943,7 +951,6 @@ LinphoneReason ChatMessagePrivate::receive() { q->store(); } -end: return reason; } diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index 8df3a234b..eb558a1c1 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -152,4 +152,8 @@ bool ContentType::isText (const string &contentType) { return contentType == "text/plain"; } +bool ContentType::isCPIM(const string &contentType) { + return contentType == "Message/CPIM"; +} + LINPHONE_END_NAMESPACE diff --git a/src/content/content-type.h b/src/content/content-type.h index 8e3851cbf..1f16ed289 100644 --- a/src/content/content-type.h +++ b/src/content/content-type.h @@ -59,6 +59,7 @@ public: static bool isImIsComposing (const std::string &contentType); static bool isImdn (const std::string &contentType); static bool isText (const std::string &contentType); + static bool isCPIM (const std::string &contentType); private: L_DECLARE_PRIVATE(ContentType); From 64e0f9b8262ac67fc2d6d2c7b68c5bf00b351a3e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 3 Oct 2017 11:23:21 +0200 Subject: [PATCH 0289/2215] Fixed issue in From and To when receiving a message --- src/chat/chat-room.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index ad33f152c..de3f5915b 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -404,7 +404,8 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa content->setBody(salMsg->text ? salMsg->text : ""); msg->addContent(content); - msg->setToAddress( op->get_to() ? op->get_to() : linphone_core_get_identity(core)); + msg->setToAddress(op->get_to() ? op->get_to() : linphone_core_get_identity(core)); + msg->setFromAddress(peerAddress); msg->getPrivate()->setTime(salMsg->time); msg->getPrivate()->setState(ChatMessage::State::Delivered); msg->getPrivate()->setDirection(ChatMessage::Direction::Incoming); @@ -543,7 +544,11 @@ void ChatRoom::compose () { } shared_ptr ChatRoom::createFileTransferMessage (const LinphoneContent *initialContent) { + L_D(); shared_ptr chatMessage = createMessage(); + + chatMessage->setToAddress(d->peerAddress); + chatMessage->setFromAddress(linphone_core_get_identity(d->core)); chatMessage->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); chatMessage->getPrivate()->setFileTransferInformation(linphone_content_copy(initialContent)); @@ -552,6 +557,7 @@ shared_ptr ChatRoom::createFileTransferMessage (const LinphoneConte } shared_ptr ChatRoom::createMessage (const string &message) { + L_D(); shared_ptr chatMessage = createMessage(); shared_ptr content = make_shared(); @@ -559,15 +565,15 @@ shared_ptr ChatRoom::createMessage (const string &message) { content->setBody(message); chatMessage->addContent(content); + chatMessage->setToAddress(d->peerAddress); + chatMessage->setFromAddress(linphone_core_get_identity(d->core)); + return chatMessage; } shared_ptr ChatRoom::createMessage () { - L_D(); shared_ptr chatMessage = make_shared(static_pointer_cast(shared_from_this())); chatMessage->getPrivate()->setTime(ms_time(0)); - chatMessage->setToAddress(d->peerAddress); - chatMessage->setFromAddress(linphone_core_get_identity(d->core)); return chatMessage; } From 3c4a11dd4c7d1f9fbc2413cf94532dd105f1214c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 3 Oct 2017 11:53:40 +0200 Subject: [PATCH 0290/2215] Replaced ms_ log methods by logger --- src/chat/chat-message.cpp | 70 +++++++++++++++++++-------------------- src/chat/chat-room.cpp | 4 +-- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 7e5716b30..8ae8d0dcc 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -84,7 +84,7 @@ void ChatMessagePrivate::setState(ChatMessage::State s) { && ((s == ChatMessage::State::DeliveredToUser) || (s == ChatMessage::State::Delivered) || (s == ChatMessage::State::NotDelivered))) { return; } - ms_message("Chat message %p: moving from state %s to %s", this, linphone_chat_message_state_to_string((LinphoneChatMessageState)state), linphone_chat_message_state_to_string((LinphoneChatMessageState)s)); + lInfo() << "Chat message " << this << ": moving from state " << linphone_chat_message_state_to_string((LinphoneChatMessageState)state) << " to " << linphone_chat_message_state_to_string((LinphoneChatMessageState)s); state = s; LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); @@ -204,12 +204,12 @@ string ChatMessagePrivate::createImdnXml(ImdnType imdnType, LinphoneReason reaso buf = xmlBufferCreate(); if (buf == NULL) { - ms_error("Error creating the XML buffer"); + lError() << "Error creating the XML buffer"; return content; } writer = xmlNewTextWriterMemory(buf, 0); if (writer == NULL) { - ms_error("Error creating the XML writer"); + lError() << "Error creating the XML writer"; return content; } @@ -308,7 +308,7 @@ void ChatMessagePrivate::fileTransferOnProgress(belle_sip_body_handler_t *bh, be L_Q(); if (!isFileTransferInProgressAndValid()) { - ms_warning("Cancelled request for %s msg [%p], ignoring %s", chatRoom ? "" : "ORPHAN", this, __FUNCTION__); + lWarning() << "Cancelled request for " << (chatRoom ? "" : "ORPHAN") << " msg [" << this << "], ignoring " << __FUNCTION__; releaseHttpRequest(); return; } @@ -340,7 +340,7 @@ int ChatMessagePrivate::onSendBody(belle_sip_user_body_handler_t *bh, belle_sip_ if (!isFileTransferInProgressAndValid()) { if (httpRequest) { - ms_warning("Cancelled request for %s msg [%p], ignoring %s", chatRoom ? "" : "ORPHAN", this, __FUNCTION__); + lWarning() << "Cancelled request for " << (chatRoom ? "" : "ORPHAN") << " msg [" << this << "], ignoring " << __FUNCTION__; releaseHttpRequest(); } return BELLE_SIP_STOP; @@ -378,7 +378,7 @@ int ChatMessagePrivate::onSendBody(belle_sip_user_body_handler_t *bh, belle_sip_ retval = cb_process_uploading_file(imee, msg, offset, (const uint8_t *)buffer, size, encrypted_buffer); if (retval == 0) { if (*size > max_size) { - ms_error("IM encryption engine process upload file callback returned a size bigger than the size of the buffer, so it will be truncated !"); + lError() << "IM encryption engine process upload file callback returned a size bigger than the size of the buffer, so it will be truncated !"; *size = max_size; } memcpy(buffer, encrypted_buffer, *size); @@ -412,7 +412,7 @@ void ChatMessagePrivate::onSendEnd(belle_sip_user_body_handler_t *bh) { void ChatMessagePrivate::fileUploadEndBackgroundTask() { if (backgroundTaskId) { - ms_message("channel [%p]: ending file upload background task with id=[%lx].", this, backgroundTaskId); + lInfo() << "channel [" << this << "]: ending file upload background task with id=[" << backgroundTaskId << "]."; sal_end_background_task(backgroundTaskId); backgroundTaskId = 0; } @@ -424,14 +424,14 @@ static void _chat_message_file_upload_background_task_ended(void *data) { } void ChatMessagePrivate::fileUploadBackgroundTaskEnded() { - ms_warning("channel [%p]: file upload background task has to be ended now, but work isn't finished.", this); + lWarning() << "channel [" << this << "]: file upload background task has to be ended now, but work isn't finished."; fileUploadEndBackgroundTask(); } void ChatMessagePrivate::fileUploadBeginBackgroundTask() { if (backgroundTaskId == 0) { backgroundTaskId = sal_begin_background_task("file transfer upload", _chat_message_file_upload_background_task_ended, this); - if (backgroundTaskId) ms_message("channel [%p]: starting file upload background task with id=[%lx].", this, backgroundTaskId); + if (backgroundTaskId) lInfo() << "channel [" << this << "]: starting file upload background task with id=[" << backgroundTaskId << "]."; } } @@ -459,7 +459,7 @@ void ChatMessagePrivate::onRecvBody(belle_sip_user_body_handler_t *bh, belle_sip } if (!httpRequest || belle_http_request_is_cancelled(httpRequest)) { - ms_warning("Cancelled request for msg [%p], ignoring %s", this, __FUNCTION__); + lWarning() << "Cancelled request for msg [" << this << "], ignoring " << __FUNCTION__; return; } @@ -496,7 +496,7 @@ void ChatMessagePrivate::onRecvBody(belle_sip_user_body_handler_t *bh, belle_sip } } } else { - ms_warning("File transfer decrypt failed with code %d", (int)retval); + lWarning() << "File transfer decrypt failed with code " << (int)retval; setState(ChatMessage::State::FileTransferError); } @@ -556,7 +556,7 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e L_Q(); if (httpRequest && !isFileTransferInProgressAndValid()) { - ms_warning("Cancelled request for %s msg [%p], ignoring %s", chatRoom ? "" : "ORPHAN", this, __FUNCTION__); + lWarning() << "Cancelled request for " << (chatRoom ? "" : "ORPHAN") << " msg [" << this << "], ignoring " << __FUNCTION__; releaseHttpRequest(); return; } @@ -694,13 +694,13 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e send(); fileUploadEndBackgroundTask(); } else { - ms_warning("Received empty response from server, file transfer failed"); + lWarning() << "Received empty response from server, file transfer failed"; q->updateState(ChatMessage::State::NotDelivered); releaseHttpRequest(); fileUploadEndBackgroundTask(); } } else { - ms_warning("Unhandled HTTP code response %d for file transfer", code); + lWarning() << "Unhandled HTTP code response " << code << " for file transfer"; q->updateState(ChatMessage::State::NotDelivered); releaseHttpRequest(); fileUploadEndBackgroundTask(); @@ -727,7 +727,7 @@ static LinphoneContent *createFileTransferInformationFromHeaders(const belle_sip if (content_type_hdr) { type = belle_sip_header_content_type_get_type(content_type_hdr); subtype = belle_sip_header_content_type_get_subtype(content_type_hdr); - ms_message("Extracted content type %s / %s from header", type ? type : "", subtype ? subtype : ""); + lInfo() << "Extracted content type " << type << " / " << subtype << " from header"; if (type) { linphone_content_set_type(content, type); } @@ -738,7 +738,7 @@ static LinphoneContent *createFileTransferInformationFromHeaders(const belle_sip if (content_length_hdr) { linphone_content_set_size(content, belle_sip_header_content_length_get_content_length(content_length_hdr)); - ms_message("Extracted content length %i from header", (int)linphone_content_get_size(content)); + lInfo() << "Extracted content length " << linphone_content_get_size(content) << " from header"; } return content; @@ -753,7 +753,7 @@ void ChatMessagePrivate::processResponseHeadersFromGetFile(const belle_http_resp size_t body_size = 0; if (cFileTransferInformation == NULL) { - ms_warning("No file transfer information for msg [%p]: creating...", this); + lWarning() << "No file transfer information for msg [" << this << "]: creating..."; cFileTransferInformation = createFileTransferInformationFromHeaders(response); } @@ -786,7 +786,7 @@ static void _chat_message_process_auth_requested_download(void *data, belle_sip_ void ChatMessagePrivate::processAuthRequestedDownload(const belle_sip_auth_event *event) { L_Q(); - ms_error("Error during file download : auth requested for msg [%p]", this); + lError() << "Error during file download : auth requested for msg [" << this << "]"; q->updateState(ChatMessage::State::FileTransferError); releaseHttpRequest(); } @@ -798,7 +798,7 @@ static void _chat_message_process_io_error_upload(void *data, const belle_sip_io void ChatMessagePrivate::processIoErrorUpload(const belle_sip_io_error_event_t *event) { L_Q(); - ms_error("I/O Error during file upload of msg [%p]", this); + lError() << "I/O Error during file upload of msg [" << this << "]"; q->updateState(ChatMessage::State::NotDelivered); releaseHttpRequest(); chatRoom->getPrivate()->removeTransientMessage(q->getSharedPtr()); @@ -811,7 +811,7 @@ static void _chat_message_process_auth_requested_upload(void *data, belle_sip_au void ChatMessagePrivate::processAuthRequestedUpload(const belle_sip_auth_event *event) { L_Q(); - ms_error("Error during file upload: auth requested for msg [%p]", this); + lError() << "Error during file upload: auth requested for msg [" << this << "]"; q->updateState(ChatMessage::State::NotDelivered); releaseHttpRequest(); chatRoom->getPrivate()->removeTransientMessage(q->getSharedPtr()); @@ -825,7 +825,7 @@ static void _chat_message_process_io_error_download(void *data, const belle_sip_ void ChatMessagePrivate::processIoErrorDownload(const belle_sip_io_error_event_t *event) { L_Q(); - ms_error("I/O Error during file download msg [%p]", this); + lError() << "I/O Error during file download msg [" << this << "]"; q->updateState(ChatMessage::State::FileTransferError); releaseHttpRequest(); } @@ -840,10 +840,10 @@ void ChatMessagePrivate::processResponseFromGetFile(const belle_http_response_ev if (event->response) { int code = belle_http_response_get_status_code(event->response); if (code >= 400 && code < 500) { - ms_warning("File transfer failed with code %d", code); + lWarning() << "File transfer failed with code " << code; setState(ChatMessage::State::FileTransferError); } else if (code != 200) { - ms_warning("Unhandled HTTP code response %d for file transfer", code); + lWarning() << "Unhandled HTTP code response " << code << " for file transfer"; } releaseHttpRequest(); } @@ -854,19 +854,19 @@ int ChatMessagePrivate::startHttpTransfer(std::string url, std::string action, b const char* ua = linphone_core_get_user_agent(chatRoom->getCore()); if (url.empty()) { - ms_warning("Cannot process file transfer msg [%p]: no file remote URI configured.", this); + lWarning() << "Cannot process file transfer msg [" << this << "]: no file remote URI configured."; goto error; } uri = belle_generic_uri_parse(url.c_str()); if (uri == NULL || belle_generic_uri_get_host(uri) == NULL) { - ms_warning("Cannot process file transfer msg [%p]: incorrect file remote URI configured '%s'.", this, url.c_str()); + lWarning() << "Cannot process file transfer msg [" << this << "]: incorrect file remote URI configured '" << url << "'."; goto error; } httpRequest = belle_http_request_create(action.c_str(), uri, belle_sip_header_create("User-Agent", ua), NULL); if (httpRequest == NULL) { - ms_warning("Could not create http request for uri %s", url.c_str()); + lWarning() << "Could not create http request for uri " << url; goto error; } // keep a reference to the http request to be able to cancel it during upload @@ -965,7 +965,7 @@ void ChatMessagePrivate::send() { if (linphone_call_get_state(call) == LinphoneCallConnected || linphone_call_get_state(call) == LinphoneCallStreamsRunning || linphone_call_get_state(call) == LinphoneCallPaused || linphone_call_get_state(call) == LinphoneCallPausing || linphone_call_get_state(call) == LinphoneCallPausedByRemote) { - ms_message("send SIP msg through the existing call."); + lInfo() << "send SIP msg through the existing call."; op = linphone_call_get_op(call); string identity = linphone_core_find_best_identity(chatRoom->getCore(), linphone_call_get_remote_address(call)); if (identity.empty()) { @@ -1306,7 +1306,7 @@ void ChatMessage::reSend() { L_D(); if (d->state != NotDelivered) { - ms_warning("Cannot resend chat message in state %s", linphone_chat_message_state_to_string((LinphoneChatMessageState)d->state)); + lWarning() << "Cannot resend chat message in state " << linphone_chat_message_state_to_string((LinphoneChatMessageState)d->state); return; } @@ -1335,7 +1335,7 @@ int ChatMessage::uploadFile() { L_D(); if (d->httpRequest) { - ms_error("linphone_chat_room_upload_file(): there is already an upload in progress."); + lError() << "linphone_chat_room_upload_file(): there is already an upload in progress."; return -1; } @@ -1355,7 +1355,7 @@ int ChatMessage::downloadFile() { L_D(); if (d->httpRequest) { - ms_error("linphone_chat_message_download_file(): there is already a download in progress"); + lError() << "linphone_chat_message_download_file(): there is already a download in progress"; return -1; } @@ -1380,15 +1380,15 @@ void ChatMessage::cancelFileTransfer() { } if (!belle_http_request_is_cancelled(d->httpRequest)) { if (d->chatRoom) { - ms_message("Canceling file transfer %s", (d->externalBodyUrl.empty()) ? linphone_core_get_file_transfer_server(d->chatRoom->getCore()) : d->externalBodyUrl.c_str()); + lInfo() << "Canceling file transfer " << (d->externalBodyUrl.empty()) ? linphone_core_get_file_transfer_server(d->chatRoom->getCore()) : d->externalBodyUrl.c_str(); belle_http_provider_cancel_request(d->chatRoom->getCore()->http_provider, d->httpRequest); } else { - ms_message("Warning: http request still running for ORPHAN msg: this is a memory leak"); + lInfo() << "Warning: http request still running for ORPHAN msg: this is a memory leak"; } } d->releaseHttpRequest(); } else { - ms_message("No existing file transfer - nothing to cancel"); + lInfo() << "No existing file transfer - nothing to cancel"; } } @@ -1409,7 +1409,7 @@ int ChatMessage::putCharacter(uint32_t character) { if (character == new_line || character == crlf || character == lf) { if (lc && lp_config_get_int(lc->config, "misc", "store_rtt_messages", 1) == 1) { - ms_debug("New line sent, forge a message with content %s", d->rttMessage.c_str()); + lDebug() << "New line sent, forge a message with content " << d->rttMessage.c_str(); d->setTime(ms_time(0)); d->state = Displayed; d->direction = Outgoing; @@ -1420,7 +1420,7 @@ int ChatMessage::putCharacter(uint32_t character) { } else { char *value = LinphonePrivate::Utils::utf8ToChar(character); d->rttMessage = d->rttMessage + string(value); - ms_debug("Sent RTT character: %s (%lu), pending text is %s", value, (unsigned long)character, d->rttMessage.c_str()); + lDebug() << "Sent RTT character: " << value << "(" << (unsigned long)character << "), pending text is " << d->rttMessage.c_str(); delete value; } diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index de3f5915b..352f9b730 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -648,7 +648,7 @@ list > ChatRoom::getHistoryRange (int startm, int endm) ms_free(buf); buf = buf2; } else if (startm > 0) { - ms_message("%s(): end is lower than start (%d < %d). Assuming no end limit.", __FUNCTION__, endm, startm); + lInfo() << __FUNCTION__ << "(): end is lower than start (" << endm << " < " << startm << "). Assuming no end limit."; char *buf2 = ms_strdup_printf("%s LIMIT -1", buf); ms_free(buf); buf = buf2; @@ -665,7 +665,7 @@ list > ChatRoom::getHistoryRange (int startm, int endm) if ((endm + 1 - startm) > 1) { /* Display message only if at least 2 messages are loaded */ - ms_message("%s(): completed in %i ms", __FUNCTION__, (int)(end - begin)); + lInfo() << __FUNCTION__ << "(): completed in " << (int)(end - begin) << " ms"; } ms_free(buf); From 2ff88e790cff632481d91f0eb8e41c4fc97495ca Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 3 Oct 2017 12:59:46 +0200 Subject: [PATCH 0291/2215] Fixed some issues revealed by the Message tester --- coreapi/chat.c | 80 ----------------------------------- coreapi/private.h | 1 - src/chat/chat-message-p.h | 3 +- src/chat/chat-message.cpp | 88 +++++++++++++++++++++++++++++++++++++-- src/chat/chat-room.cpp | 6 +++ 5 files changed, 92 insertions(+), 86 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index d17b6cef7..eab5ed37e 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -146,86 +146,6 @@ LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const c return _linphone_core_get_or_create_chat_room(lc, to); } -void create_file_transfer_information_from_vnd_gsma_rcs_ft_http_xml(LinphoneChatMessage *msg) { - xmlChar *file_url = NULL; - xmlDocPtr xmlMessageBody; - xmlNodePtr cur; - /* parse the msg body to get all informations from it */ - xmlMessageBody = xmlParseDoc((const xmlChar *)linphone_chat_message_get_text(msg)); - LinphoneContent *content = linphone_content_new(); - linphone_chat_message_set_file_transfer_information(msg, content); - - cur = xmlDocGetRootElement(xmlMessageBody); - if (cur != NULL) { - cur = cur->xmlChildrenNode; - while (cur != NULL) { - if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { - /* we found a file info node, check if it has a type="file" attribute */ - xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); - if (!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for */ - cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */ - while (cur != NULL) { - if (!xmlStrcmp(cur->name, (const xmlChar *)"file-size")) { - xmlChar *fileSizeString = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - linphone_content_set_size(content, (size_t)strtol((const char *)fileSizeString, NULL, 10)); - xmlFree(fileSizeString); - } - - if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) { - xmlChar *filename = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - linphone_content_set_name(content, (char *)filename); - xmlFree(filename); - } - if (!xmlStrcmp(cur->name, (const xmlChar *)"content-type")) { - xmlChar *contentType = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - int contentTypeIndex = 0; - char *type; - char *subtype; - while (contentType[contentTypeIndex] != '/' && contentType[contentTypeIndex] != '\0') { - contentTypeIndex++; - } - type = ms_strndup((char *)contentType, contentTypeIndex); - subtype = ms_strdup(((char *)contentType + contentTypeIndex + 1)); - linphone_content_set_type(content, type); - linphone_content_set_subtype(content, subtype); - ms_free(subtype); - ms_free(type); - xmlFree(contentType); - } - if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) { - file_url = xmlGetProp(cur, (const xmlChar *)"url"); - } - - if (!xmlStrcmp(cur->name, (const xmlChar *)"file-key")) { - /* there is a key in the msg: file has been encrypted */ - /* convert the key from base 64 */ - xmlChar *keyb64 = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - size_t keyLength = b64::b64_decode((char *)keyb64, strlen((char *)keyb64), NULL, 0); - uint8_t *keyBuffer = (uint8_t *)malloc(keyLength); - /* decode the key into local key buffer */ - b64::b64_decode((char *)keyb64, strlen((char *)keyb64), keyBuffer, keyLength); - linphone_content_set_key(content, (char *)keyBuffer, keyLength); - /* duplicate key value into the linphone content private structure */ - xmlFree(keyb64); - free(keyBuffer); - } - - cur = cur->next; - } - xmlFree(typeAttribute); - break; - } - xmlFree(typeAttribute); - } - cur = cur->next; - } - } - xmlFreeDoc(xmlMessageBody); - - linphone_chat_message_set_external_body_url(msg, (const char *)file_url); - xmlFree(file_url); -} - int linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *sal_msg) { LinphoneAddress *addr = linphone_address_new(sal_msg->from); linphone_address_clean(addr); diff --git a/coreapi/private.h b/coreapi/private.h index 228339482..9e430c6cd 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -1111,7 +1111,6 @@ LinphoneChatRoom *_linphone_core_create_chat_room_from_call(LinphoneCall *call); void linphone_chat_room_remove_transient_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg); void linphone_chat_message_deactivate(LinphoneChatMessage *msg); void linphone_chat_message_release(LinphoneChatMessage *msg); -void create_file_transfer_information_from_vnd_gsma_rcs_ft_http_xml(LinphoneChatMessage *msg); void linphone_chat_message_fetch_content_from_database(sqlite3 *db, LinphoneChatMessage *message, int content_id); void linphone_chat_message_send_imdn(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason); diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 7fc20f851..199768d78 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -141,10 +141,9 @@ private: void fileUploadEndBackgroundTask(); void fileUploadBeginBackgroundTask(); bool isFileTransferInProgressAndValid(); - int startHttpTransfer(std::string url, std::string action, belle_http_request_listener_callbacks_t *cbs); - void releaseHttpRequest(); + void createFileTransferInformationsFromVndGsmaRcsFtHttpXml(); std::shared_ptr getPublicSharedPtr(); diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 8ae8d0dcc..47f174c33 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -187,6 +187,10 @@ LinphoneContent * ChatMessagePrivate::getFileTransferInformation() const { } void ChatMessagePrivate::setFileTransferInformation(LinphoneContent *content) { + if (cFileTransferInformation) { + linphone_content_unref(cFileTransferInformation); + cFileTransferInformation = NULL; + } cFileTransferInformation = content; } @@ -894,6 +898,86 @@ void ChatMessagePrivate::releaseHttpRequest() { } } +void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml() { + xmlChar *file_url = NULL; + xmlDocPtr xmlMessageBody; + xmlNodePtr cur; + /* parse the msg body to get all informations from it */ + xmlMessageBody = xmlParseDoc((const xmlChar *)getText().c_str()); + LinphoneContent *content = linphone_content_new(); + setFileTransferInformation(content); + + cur = xmlDocGetRootElement(xmlMessageBody); + if (cur != NULL) { + cur = cur->xmlChildrenNode; + while (cur != NULL) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { + /* we found a file info node, check if it has a type="file" attribute */ + xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); + if (!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for */ + cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */ + while (cur != NULL) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-size")) { + xmlChar *fileSizeString = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); + linphone_content_set_size(content, (size_t)strtol((const char *)fileSizeString, NULL, 10)); + xmlFree(fileSizeString); + } + + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) { + xmlChar *filename = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); + linphone_content_set_name(content, (char *)filename); + xmlFree(filename); + } + if (!xmlStrcmp(cur->name, (const xmlChar *)"content-type")) { + xmlChar *contentType = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); + int contentTypeIndex = 0; + char *type; + char *subtype; + while (contentType[contentTypeIndex] != '/' && contentType[contentTypeIndex] != '\0') { + contentTypeIndex++; + } + type = ms_strndup((char *)contentType, contentTypeIndex); + subtype = ms_strdup(((char *)contentType + contentTypeIndex + 1)); + linphone_content_set_type(content, type); + linphone_content_set_subtype(content, subtype); + ms_free(subtype); + ms_free(type); + xmlFree(contentType); + } + if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) { + file_url = xmlGetProp(cur, (const xmlChar *)"url"); + } + + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-key")) { + /* there is a key in the msg: file has been encrypted */ + /* convert the key from base 64 */ + xmlChar *keyb64 = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); + size_t keyLength = b64::b64_decode((char *)keyb64, strlen((char *)keyb64), NULL, 0); + uint8_t *keyBuffer = (uint8_t *)malloc(keyLength); + /* decode the key into local key buffer */ + b64::b64_decode((char *)keyb64, strlen((char *)keyb64), keyBuffer, keyLength); + linphone_content_set_key(content, (char *)keyBuffer, keyLength); + /* duplicate key value into the linphone content private structure */ + xmlFree(keyb64); + free(keyBuffer); + } + + cur = cur->next; + } + xmlFree(typeAttribute); + break; + } + xmlFree(typeAttribute); + } + cur = cur->next; + } + } + xmlFreeDoc(xmlMessageBody); + + externalBodyUrl = string((const char *)file_url); + xmlFree(file_url); +} + LinphoneReason ChatMessagePrivate::receive() { L_Q(); @@ -917,8 +1001,6 @@ LinphoneReason ChatMessagePrivate::receive() { chatRoom->getPrivate()->notifyUndecryptableMessageReceived(getPublicSharedPtr()); reason = linphone_error_code_to_reason(retval); q->sendDeliveryNotification(reason); - /* Return LinphoneReasonNone to avoid flexisip resending us a message we can't decrypt */ - reason = LinphoneReasonNone; return reason; } @@ -941,7 +1023,7 @@ LinphoneReason ChatMessagePrivate::receive() { } if (ContentType::isFileTransfer(getContentType())) { - create_file_transfer_information_from_vnd_gsma_rcs_ft_http_xml(L_GET_C_BACK_PTR(getPublicSharedPtr())); + createFileTransferInformationsFromVndGsmaRcsFtHttpXml(); store = true; } else if (ContentType::isText(getContentType())) { store = true; diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 352f9b730..c6b9e7c6e 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -419,6 +419,12 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa reason = msg->getPrivate()->receive(); + if (reason == LinphoneReasonNotAcceptable || reason == LinphoneReasonUnknown) { + /* Return LinphoneReasonNone to avoid flexisip resending us a message we can't decrypt */ + reason = LinphoneReasonNone; + goto end; + } + if (ContentType::isImIsComposing(msg->getPrivate()->getContentType())) { isComposingReceived(msg->getPrivate()->getText()); increaseMsgCount = FALSE; From ef62012c6e83ba4523a84d9d9047166188629222 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 3 Oct 2017 13:28:14 +0200 Subject: [PATCH 0292/2215] feat(Object): avoid usage of share_from_this --- include/linphone/utils/general.h | 14 ++++-- src/c-wrapper/api/c-call.cpp | 4 +- src/c-wrapper/api/c-chat-room.cpp | 6 +-- src/c-wrapper/internal/c-tools.h | 9 +--- src/chat/basic-chat-room.cpp | 2 +- src/chat/chat-message-p.h | 28 ++++++------ src/chat/chat-message.cpp | 43 +++++++------------ src/chat/chat-message.h | 19 ++++---- src/chat/chat-room.cpp | 9 ++-- src/chat/chat-room.h | 1 + .../encryption-chat-message-modifier.cpp | 4 +- src/chat/real-time-text-chat-room.cpp | 2 +- src/conference/conference.cpp | 2 +- src/conference/local-conference.cpp | 2 +- src/conference/participant.cpp | 8 ++-- src/conference/remote-conference.cpp | 2 +- src/conference/session/call-session.cpp | 4 +- src/conference/session/call-session.h | 2 + src/conference/session/media-session.cpp | 2 +- src/object/object-p.h | 6 ++- src/object/object.cpp | 17 +++++++- src/object/object.h | 27 ++++++++++-- 22 files changed, 121 insertions(+), 92 deletions(-) diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index 515767649..268c9b50a 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -103,7 +103,7 @@ class ObjectPrivate; #endif template -inline ClonableObject *getPublicHelper (T *object, ClonableObjectPrivate *context) { +inline ClonableObject *getPublicHelper (T *object, const ClonableObjectPrivate *context) { auto it = object->find(context); L_ASSERT(it != object->end()); return it->second; @@ -117,7 +117,7 @@ inline const ClonableObject *getPublicHelper (const T *object, const ClonableObj } template -inline Object *getPublicHelper (T *object, ObjectPrivate *) { +inline Object *getPublicHelper (T *object, const ObjectPrivate *) { return object; } @@ -127,7 +127,7 @@ inline const Object *getPublicHelper (const T *object, const ObjectPrivate *) { } #define L_DECLARE_PUBLIC(CLASS) \ - inline CLASS * getPublic () { \ + inline CLASS *getPublic () { \ return static_cast(getPublicHelper(mPublic, this)); \ } \ inline const CLASS *getPublic () const { \ @@ -142,6 +142,14 @@ inline const Object *getPublicHelper (const T *object, const ObjectPrivate *) { #define L_D() decltype(std::declval().getPrivate()) const d = getPrivate(); #define L_Q() decltype(std::declval().getPublic()) const q = getPublic(); +#define L_OVERRIDE_SHARED_FROM_THIS(CLASS) \ + inline std::shared_ptr getSharedFromThis () { \ + return std::static_pointer_cast(Object::getSharedFromThis()); \ + } \ + inline std::shared_ptr getSharedFromThis () const { \ + return std::static_pointer_cast(Object::getSharedFromThis()); \ + } + #define L_USE_DEFAULT_SHARE_IMPL(CLASS, PARENT_CLASS) \ CLASS::CLASS (const CLASS &src) : PARENT_CLASS(*src.getPrivate()) {} \ CLASS &CLASS::operator= (const CLASS &src) { \ diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index f7d51ac93..aef5da3ff 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -1139,7 +1139,7 @@ void linphone_call_set_user_data (LinphoneCall *call, void *ud) { LinphoneCall *linphone_call_new_outgoing (LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg) { LinphoneCall *call = L_INIT(Call); - L_SET_CPP_PTR_FROM_C_OBJECT(call, make_shared(call, lc, LinphoneCallOutgoing, + L_SET_CPP_PTR_FROM_C_OBJECT(call, LinphonePrivate::ObjectFactory::create(call, lc, LinphoneCallOutgoing, *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), cfg, nullptr, L_GET_CPP_PTR_FROM_C_OBJECT(params))); call->currentParamsCache = linphone_call_params_new_for_wrapper(); @@ -1151,7 +1151,7 @@ LinphoneCall *linphone_call_new_outgoing (LinphoneCore *lc, const LinphoneAddres LinphoneCall *linphone_call_new_incoming (LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, LinphonePrivate::SalCallOp *op) { LinphoneCall *call = L_INIT(Call); - L_SET_CPP_PTR_FROM_C_OBJECT(call, make_shared(call, lc, LinphoneCallIncoming, + L_SET_CPP_PTR_FROM_C_OBJECT(call, LinphonePrivate::ObjectFactory::create(call, lc, LinphoneCallIncoming, *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), nullptr, op, nullptr)); call->currentParamsCache = linphone_call_params_new_for_wrapper(); diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 3bc39f348..816fbd7c2 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -289,9 +289,9 @@ void linphone_chat_room_set_user_data (LinphoneChatRoom *cr, void *ud) { LinphoneChatRoom *linphone_chat_room_new (LinphoneCore *core, const LinphoneAddress *addr) { LinphoneChatRoom *cr = L_INIT(ChatRoom); if (linphone_core_realtime_text_enabled(core)) - L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared(core, *L_GET_CPP_PTR_FROM_C_OBJECT(addr))); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, LinphonePrivate::ObjectFactory::create(core, *L_GET_CPP_PTR_FROM_C_OBJECT(addr))); else - L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared(core, *L_GET_CPP_PTR_FROM_C_OBJECT(addr))); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, LinphonePrivate::ObjectFactory::create(core, *L_GET_CPP_PTR_FROM_C_OBJECT(addr))); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Created); return cr; @@ -311,7 +311,7 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, cons from = linphone_core_get_primary_contact(core); LinphonePrivate::Address me(from); LinphoneChatRoom *cr = L_INIT(ChatRoom); - L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared(core, me, L_C_TO_STRING(subject))); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, LinphonePrivate::ObjectFactory::create(core, me, L_C_TO_STRING(subject))); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); return cr; } diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 8f4c2749c..030eefe14 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -294,7 +294,7 @@ public: return nullptr; try { - return getCBackPtr(std::static_pointer_cast(cppObject->shared_from_this())); + return getCBackPtr(std::static_pointer_cast(cppObject->getSharedFromThis())); } catch (const std::bad_weak_ptr &e) { abort(e.what()); } @@ -545,13 +545,6 @@ LINPHONE_END_NAMESPACE FALSE \ ); -#define L_DECLARE_C_OBJECT_NEW_DEFAULT(C_TYPE, C_NAME) \ - Linphone ## C_TYPE * linphone_ ## C_NAME ## _new() { \ - Linphone ## C_TYPE *object = _linphone_ ## C_TYPE ## _init(); \ - object->cppPtr = std::make_shared(); \ - return object; \ - } - // ----------------------------------------------------------------------------- // Helpers. // ----------------------------------------------------------------------------- diff --git a/src/chat/basic-chat-room.cpp b/src/chat/basic-chat-room.cpp index 2d41a5657..949f02a39 100644 --- a/src/chat/basic-chat-room.cpp +++ b/src/chat/basic-chat-room.cpp @@ -60,7 +60,7 @@ int BasicChatRoom::getNbParticipants () const { list> BasicChatRoom::getParticipants () const { L_D(); list> l; - l.push_back(make_shared(d->peerAddress)); + l.push_back(ObjectFactory::create(d->peerAddress)); return l; } diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 199768d78..1bd7aeee7 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -37,20 +37,20 @@ public: virtual ~ChatMessagePrivate (); void setChatRoom (std::shared_ptr chatRoom); - + // ----------------------------------------------------------------------------- void setDirection (ChatMessage::Direction dir); void setState(ChatMessage::State state); - + void setTime(time_t time); - + void setIsReadOnly(bool readOnly); - + unsigned int getStorageId() const; void setStorageId(unsigned int id); - + belle_http_request_t *getHttpRequest() const; void setHttpRequest(belle_http_request_t *request); @@ -67,16 +67,16 @@ public: // ----------------------------------------------------------------------------- // Methods only used for C wrapper // ----------------------------------------------------------------------------- - + const std::string& getContentType(); void setContentType(const std::string& contentType); const std::string& getText(); void setText(const std::string& text); - + LinphoneContent * getFileTransferInformation() const; void setFileTransferInformation(LinphoneContent *content); - + // ----------------------------------------------------------------------------- // Need to be public to be called from static C callbacks // ----------------------------------------------------------------------------- @@ -94,11 +94,11 @@ public: void processAuthRequestedUpload(const belle_sip_auth_event *event); void processIoErrorDownload(const belle_sip_io_error_event_t *event); void processResponseFromGetFile(const belle_http_response_event_t *event); - + // ----------------------------------------------------------------------------- - + void sendImdn(ImdnType imdnType, LinphoneReason reason); - + LinphoneReason receive(); void send(); @@ -133,7 +133,7 @@ private: std::string cText = ""; // Used for compatibility with previous C API LinphoneContent *cFileTransferInformation = NULL; - + // ----------------------------------------------------------------------------- std::string createImdnXml(ImdnType imdnType, LinphoneReason reason); @@ -145,10 +145,6 @@ private: void releaseHttpRequest(); void createFileTransferInformationsFromVndGsmaRcsFtHttpXml(); - std::shared_ptr getPublicSharedPtr(); - - // ----------------------------------------------------------------------------- - L_DECLARE_PUBLIC(ChatMessage); }; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 47f174c33..bbd96d9d7 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -55,11 +55,6 @@ ChatMessagePrivate::~ChatMessagePrivate () {} // ----------------------------------------------------------------------------- -shared_ptr ChatMessagePrivate::getPublicSharedPtr() { - L_Q(); - return q->getSharedPtr(); -} - void ChatMessagePrivate::setChatRoom (shared_ptr cr) { chatRoom = cr; } @@ -607,7 +602,7 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e _chat_message_file_transfer_on_progress, NULL, NULL, _chat_message_on_send_body, _chat_message_on_send_end, this); if (!fileTransferFilePath.empty()) { - belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh; + belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh; // No need to add again the callback for progression, otherwise it will be called twice first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(fileTransferFilePath.c_str(), NULL, this); linphone_content_set_size(cFileTransferInformation, belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh)); @@ -765,8 +760,8 @@ void ChatMessagePrivate::processResponseHeadersFromGetFile(const belle_http_resp body_size = linphone_content_get_size(cFileTransferInformation); } - body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, _chat_message_file_transfer_on_progress, - NULL, _chat_message_on_recv_body, + body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, _chat_message_file_transfer_on_progress, + NULL, _chat_message_on_recv_body, NULL, _chat_message_on_recv_end, this); if (!fileTransferFilePath.empty()) { belle_sip_user_body_handler_t *bh = (belle_sip_user_body_handler_t *)body_handler; @@ -805,7 +800,7 @@ void ChatMessagePrivate::processIoErrorUpload(const belle_sip_io_error_event_t * lError() << "I/O Error during file upload of msg [" << this << "]"; q->updateState(ChatMessage::State::NotDelivered); releaseHttpRequest(); - chatRoom->getPrivate()->removeTransientMessage(q->getSharedPtr()); + chatRoom->getPrivate()->removeTransientMessage(q->getSharedFromThis()); } static void _chat_message_process_auth_requested_upload(void *data, belle_sip_auth_event *event) { @@ -818,7 +813,7 @@ void ChatMessagePrivate::processAuthRequestedUpload(const belle_sip_auth_event * lError() << "Error during file upload: auth requested for msg [" << this << "]"; q->updateState(ChatMessage::State::NotDelivered); releaseHttpRequest(); - chatRoom->getPrivate()->removeTransientMessage(q->getSharedPtr()); + chatRoom->getPrivate()->removeTransientMessage(q->getSharedFromThis()); } static void _chat_message_process_io_error_download(void *data, const belle_sip_io_error_event_t *event) { @@ -983,7 +978,7 @@ LinphoneReason ChatMessagePrivate::receive() { LinphoneReason reason = LinphoneReasonNone; bool store = false; - + // --------------------------------------- // Start of message modification // --------------------------------------- @@ -998,7 +993,7 @@ LinphoneReason ChatMessagePrivate::receive() { retval = ecmm.decode(this); if (retval > 0) { /* Unable to decrypt message */ - chatRoom->getPrivate()->notifyUndecryptableMessageReceived(getPublicSharedPtr()); + chatRoom->getPrivate()->notifyUndecryptableMessageReceived(q->getSharedFromThis()); reason = linphone_error_code_to_reason(retval); q->sendDeliveryNotification(reason); return reason; @@ -1006,7 +1001,7 @@ LinphoneReason ChatMessagePrivate::receive() { MultipartChatMessageModifier mcmm; mcmm.decode(this); - + // --------------------------------------- // End of message modification // --------------------------------------- @@ -1040,7 +1035,7 @@ void ChatMessagePrivate::send() { L_Q(); SalOp *op = salOp; LinphoneCall *call = NULL; - + if (lp_config_get_int(chatRoom->getCore()->config, "sip", "chat_use_call_dialogs", 0) != 0) { call = linphone_core_get_call_by_remote_address(chatRoom->getCore(), chatRoom->getPeerAddress().asString().c_str()); if (call) { @@ -1076,7 +1071,7 @@ void ChatMessagePrivate::send() { op->set_user_pointer(L_GET_C_BACK_PTR(q)); /* If out of call, directly store msg */ linphone_address_unref(peer); } - + // --------------------------------------- // Start of message modification // --------------------------------------- @@ -1090,7 +1085,7 @@ void ChatMessagePrivate::send() { if (!getContentType().empty()) { clearTextContentType = getContentType(); } - + if (contents.size() > 1) { MultipartChatMessageModifier mcmm; mcmm.encode(this); @@ -1098,7 +1093,6 @@ void ChatMessagePrivate::send() { EncryptionChatMessageModifier ecmm; int retval = ecmm.encode(this); - if (retval > 0) { sal_error_info_set((SalErrorInfo *)op->get_error_info(), SalReasonNotAcceptable, "SIP", retval, "Unable to encrypt IM", nullptr); q->updateState(ChatMessage::State::NotDelivered); @@ -1110,7 +1104,7 @@ void ChatMessagePrivate::send() { CpimChatMessageModifier ccmm; ccmm.encode(this); } - + // --------------------------------------- // End of message modification // --------------------------------------- @@ -1144,7 +1138,7 @@ void ChatMessagePrivate::send() { /* Might be better fixed by delivering status, but too costly for now */ return; } - + /* If operation failed, we should not change message state */ if (q->isOutgoing()) { setIsReadOnly(true); @@ -1379,9 +1373,8 @@ void ChatMessage::updateState(State state) { d->setState(state); linphone_chat_message_store_state(L_GET_C_BACK_PTR(this)); - if (state == Delivered || state == NotDelivered) { - d->chatRoom->getPrivate()->moveTransientMessageToWeakMessages(static_pointer_cast(shared_from_this())); - } + if (state == Delivered || state == NotDelivered) + d->chatRoom->getPrivate()->moveTransientMessageToWeakMessages(getSharedFromThis()); } void ChatMessage::reSend() { @@ -1392,7 +1385,7 @@ void ChatMessage::reSend() { return; } - d->chatRoom->sendMessage(static_pointer_cast(shared_from_this())); + d->chatRoom->sendMessage(getSharedFromThis()); } void ChatMessage::sendDeliveryNotification(LinphoneReason reason) { @@ -1512,8 +1505,4 @@ int ChatMessage::putCharacter(uint32_t character) { return -1; } -shared_ptr ChatMessage::getSharedPtr() { - return static_pointer_cast(shared_from_this()); -} - LINPHONE_END_NAMESPACE diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index 9c1c709d3..504549b3a 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -44,12 +44,14 @@ class LINPHONE_PUBLIC ChatMessage : public Object { friend class ChatRoomPrivate; friend class RealTimeTextChatRoomPrivate; -public: +public: + L_OVERRIDE_SHARED_FROM_THIS(ChatMessage); + enum Direction { Incoming, Outgoing }; - + enum State { Idle, InProgress, @@ -100,22 +102,22 @@ public: const std::string& getExternalBodyUrl() const; void setExternalBodyUrl(const std::string &url); - + time_t getTime() const; bool isSecured() const; void setIsSecured(bool isSecured); State getState() const; - + const std::string& getId() const; void setId(const std::string&); bool isRead() const; - + const std::string& getAppdata() const; void setAppdata(const std::string &appData); - + const Address& getFromAddress() const; void setFromAddress(Address from); void setFromAddress(const std::string& from); @@ -131,9 +133,9 @@ public: void setIsToBeStored(bool store); const LinphoneErrorInfo * getErrorInfo() const; - + bool isReadOnly() const; - + std::list > getContents() const; void addContent(const std::shared_ptr &content); void removeContent(const std::shared_ptr &content); @@ -143,7 +145,6 @@ public: void removeCustomHeader(const std::string &headerName); protected: - std::shared_ptr getSharedPtr(); explicit ChatMessage(ChatMessagePrivate &p); private: diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index c6b9e7c6e..ab5aa3116 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -211,7 +211,7 @@ void ChatRoomPrivate::sendIsComposingNotification () { shared_ptr msg = q->createMessage(); msg->setFromAddress(identity); msg->setToAddress(peerAddress.asString()); - + shared_ptr content = make_shared(); content->setContentType("application/im-iscomposing+xml"); content->setBody(payload); @@ -277,7 +277,7 @@ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colN } if (argv[13]) { content->setContentType(argv[13]); - } + } Address peer(peerAddress.asString()); if (atoi(argv[3]) == ChatMessage::Direction::Incoming) { @@ -555,7 +555,6 @@ shared_ptr ChatRoom::createFileTransferMessage (const LinphoneConte chatMessage->setToAddress(d->peerAddress); chatMessage->setFromAddress(linphone_core_get_identity(d->core)); - chatMessage->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); chatMessage->getPrivate()->setFileTransferInformation(linphone_content_copy(initialContent)); @@ -578,7 +577,7 @@ shared_ptr ChatRoom::createMessage (const string &message) { } shared_ptr ChatRoom::createMessage () { - shared_ptr chatMessage = make_shared(static_pointer_cast(shared_from_this())); + shared_ptr chatMessage = ObjectFactory::create(getSharedFromThis()); chatMessage->getPrivate()->setTime(ms_time(0)); return chatMessage; } @@ -742,7 +741,7 @@ void ChatRoom::sendMessage (shared_ptr msg) { d->addTransientMessage(msg); /* Store the message so that even if the upload is stopped, it can be done again */ d->storeOrUpdateMessage(msg); - + msg->getPrivate()->setState(ChatMessage::State::InProgress); } else { return; diff --git a/src/chat/chat-room.h b/src/chat/chat-room.h index e9d2ea018..781b3a303 100644 --- a/src/chat/chat-room.h +++ b/src/chat/chat-room.h @@ -44,6 +44,7 @@ class LINPHONE_PUBLIC ChatRoom : public Object, public ConferenceInterface { public: L_DECLARE_ENUM(State, L_ENUM_VALUES_CHAT_ROOM_STATE); + L_OVERRIDE_SHARED_FROM_THIS(ChatRoom); ChatRoom (LinphoneCore *core); virtual ~ChatRoom () = default; diff --git a/src/chat/modifier/encryption-chat-message-modifier.cpp b/src/chat/modifier/encryption-chat-message-modifier.cpp index 0949724b4..af5b24c91 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.cpp +++ b/src/chat/modifier/encryption-chat-message-modifier.cpp @@ -40,7 +40,7 @@ int EncryptionChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); if (cbProcessOutgoingMessage) { - retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(messagePrivate->chatRoom), L_GET_C_BACK_PTR(messagePrivate->getPublicSharedPtr())); + retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(messagePrivate->chatRoom), L_GET_C_BACK_PTR(messagePrivate->getPublic()->getSharedFromThis())); if (retval == 0) { messagePrivate->isSecured = true; } @@ -56,7 +56,7 @@ int EncryptionChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsIncomingMessageCb cbProcessIncomingMessage = linphone_im_encryption_engine_cbs_get_process_incoming_message(imeeCbs); if (cbProcessIncomingMessage) { - retval = cbProcessIncomingMessage(imee, L_GET_C_BACK_PTR(messagePrivate->chatRoom), L_GET_C_BACK_PTR(messagePrivate->getPublicSharedPtr())); + retval = cbProcessIncomingMessage(imee, L_GET_C_BACK_PTR(messagePrivate->chatRoom), L_GET_C_BACK_PTR(messagePrivate->getPublic()->getSharedFromThis())); if (retval == 0) { messagePrivate->isSecured = true; } diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 885b98e33..321a0fe56 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -156,7 +156,7 @@ int RealTimeTextChatRoom::getNbParticipants () const { list> RealTimeTextChatRoom::getParticipants () const { L_D(); list> l; - l.push_back(make_shared(d->peerAddress)); + l.push_back(ObjectFactory::create(d->peerAddress)); return l; } diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 818273165..2ae674663 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -29,7 +29,7 @@ LINPHONE_BEGIN_NAMESPACE Conference::Conference (LinphoneCore *core, const Address &myAddress, CallListener *listener) : core(core), callListener(listener) { - me = make_shared(myAddress); + me = ObjectFactory::create(myAddress); } // ----------------------------------------------------------------------------- diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index 1de626295..baad5dda5 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -42,7 +42,7 @@ shared_ptr LocalConference::addParticipant (const Address &addr, co shared_ptr participant = findParticipant(addr); if (participant) return participant; - participant = make_shared(addr); + participant = ObjectFactory::create(addr); participant->getPrivate()->createSession(*this, params, hasMedia, this); participants.push_back(participant); if (!activeParticipant) diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index 31a25000d..eea9b7f31 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -29,11 +29,13 @@ LINPHONE_BEGIN_NAMESPACE // ============================================================================= -shared_ptr ParticipantPrivate::createSession (const Conference &conference, const CallSessionParams *params, bool hasMedia, CallSessionListener *listener) { +shared_ptr ParticipantPrivate::createSession ( + const Conference &conference, const CallSessionParams *params, bool hasMedia, CallSessionListener *listener +) { if (hasMedia && (!params || dynamic_cast(params))) { - session = make_shared(conference, params, listener); + session = ObjectFactory::create(conference, params, listener); } else { - session = make_shared(conference, params, listener); + session = ObjectFactory::create(conference, params, listener); } return session; } diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index 1f38c4d13..d3e1b2f04 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -43,7 +43,7 @@ shared_ptr RemoteConference::addParticipant (const Address &addr, c shared_ptr participant = findParticipant(addr); if (participant) return participant; - participant = make_shared(addr); + participant = ObjectFactory::create(addr); participant->getPrivate()->createSession(*this, params, hasMedia, this); participants.push_back(participant); if (!activeParticipant) diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 2397cbe6b..40347a8f5 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -839,7 +839,7 @@ void CallSession::startIncomingNotification () { if (d->listener) d->listener->onCallSessionAccepted(*this); /* Prevent the CallSession from being destroyed while we are notifying, if the user declines within the state callback */ - shared_ptr ref = static_pointer_cast(shared_from_this()); + shared_ptr ref = getSharedFromThis(); #if 0 call->bg_task_id=sal_begin_background_task("liblinphone call notification", NULL, NULL); #endif @@ -883,7 +883,7 @@ int CallSession::startInvite (const Address *destination, const string &subject) } char *from = linphone_address_as_string(d->log->from); /* Take a ref because sal_call() may destroy the CallSession if no SIP transport is available */ - shared_ptr ref = static_pointer_cast(shared_from_this()); + shared_ptr ref = getSharedFromThis(); int result = d->op->call(from, destinationStr.c_str(), subject.empty() ? nullptr : subject.c_str()); ms_free(from); if (result < 0) { diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index 52ae7e1d3..2495dab34 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -38,6 +38,8 @@ class LINPHONE_PUBLIC CallSession : public Object { friend class ClientGroupChatRoom; public: + L_OVERRIDE_SHARED_FROM_THIS(CallSession); + CallSession (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener); LinphoneStatus accept (const CallSessionParams *csp = nullptr); diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 505821151..c19d55098 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -609,7 +609,7 @@ float MediaSessionPrivate::aggregateQualityRatings (float audioRating, float vid void MediaSessionPrivate::setState (LinphoneCallState newState, const string &message) { L_Q(); /* Take a ref on the session otherwise it might get destroyed during the call to setState */ - shared_ptr session = static_pointer_cast(q->shared_from_this()); + shared_ptr session = q->getSharedFromThis(); CallSessionPrivate::setState(newState, message); updateReportingCallState(); } diff --git a/src/object/object-p.h b/src/object/object-p.h index 0b3cf57a2..fe0d42c25 100644 --- a/src/object/object-p.h +++ b/src/object/object-p.h @@ -19,6 +19,7 @@ #ifndef _OBJECT_P_H_ #define _OBJECT_P_H_ +#include #include #include "variant/variant.h" @@ -28,14 +29,17 @@ LINPHONE_BEGIN_NAMESPACE class ObjectPrivate { + friend class ObjectFactory; + public: virtual ~ObjectPrivate () = default; protected: - Object *mPublic = nullptr; + Object *mPublic; private: std::unordered_map properties; + std::weak_ptr weak; L_DECLARE_PUBLIC(Object); }; diff --git a/src/object/object.cpp b/src/object/object.cpp index 01457e82d..4d83a7b54 100644 --- a/src/object/object.cpp +++ b/src/object/object.cpp @@ -30,8 +30,21 @@ Object::~Object () { delete mPrivate; } -Object::Object (ObjectPrivate &p) : mPrivate(&p) { - mPrivate->mPublic = this; +Object::Object (ObjectPrivate &p) : mPrivate(&p) {} + +shared_ptr Object::getSharedFromThis () { + return mPrivate->weak.lock(); +} + +shared_ptr Object::getSharedFromThis () const { + return mPrivate->weak.lock(); +} + +void ObjectFactory::setPublic (const shared_ptr &object) { + L_ASSERT(object); + ObjectPrivate *d = object->getPrivate(); + d->mPublic = object.get(); + d->weak = object; } LINPHONE_END_NAMESPACE diff --git a/src/object/object.h b/src/object/object.h index ede98e862..cf1afddea 100644 --- a/src/object/object.h +++ b/src/object/object.h @@ -27,15 +27,18 @@ LINPHONE_BEGIN_NAMESPACE -class LINPHONE_PUBLIC Object : - public std::enable_shared_from_this, - public PropertyContainer { +class LINPHONE_PUBLIC Object : public PropertyContainer { + friend class ObjectFactory; + public: virtual ~Object (); protected: explicit Object (ObjectPrivate &p); + std::shared_ptr getSharedFromThis (); + std::shared_ptr getSharedFromThis () const; + ObjectPrivate *mPrivate = nullptr; private: @@ -43,6 +46,24 @@ private: L_DISABLE_COPY(Object); }; +class ObjectFactory { +public: + template + static inline std::shared_ptr create (Args &&...args) { + static_assert(std::is_base_of::value, "Not an object."); + std::shared_ptr object = std::make_shared(args...); + setPublic(object); + return object; + } + +private: + ObjectFactory () = delete; + + static void setPublic (const std::shared_ptr &object); + + L_DISABLE_COPY(ObjectFactory); +}; + LINPHONE_END_NAMESPACE #endif // ifndef _OBJECT_H_ From f3206e9f79a32b411cf74a8a2b2d017d056df7e1 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 3 Oct 2017 13:40:17 +0200 Subject: [PATCH 0293/2215] fix(ClientGroupChatRoom): avoid usage of make_shared on Object! --- src/chat/client-group-chat-room.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 3e9302005..9e4bace9c 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -39,14 +39,14 @@ ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core) ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, const string &subject) : ChatRoom(*new ClientGroupChatRoomPrivate(core)), RemoteConference(core, me, nullptr) { string factoryUri = linphone_core_get_conference_factory_uri(core); - focus = make_shared(factoryUri); + focus = ObjectFactory::create(factoryUri); this->subject = subject; } // ----------------------------------------------------------------------------- shared_ptr ClientGroupChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { - activeParticipant = make_shared(addr); + activeParticipant = ObjectFactory::create(addr); activeParticipant->getPrivate()->createSession(*this, params, hasMedia, this); return activeParticipant; } @@ -143,7 +143,7 @@ void ClientGroupChatRoom::onParticipantAdded (const Address &addr) { lWarning() << "Participant " << participant << " added but already in the list of participants!"; return; } - participant = make_shared(addr); + participant = ObjectFactory::create(addr); participants.push_back(participant); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); From 4451f49d74e9dbec294307a518bc8916aad30478 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 3 Oct 2017 13:49:30 +0200 Subject: [PATCH 0294/2215] fix(Hacks): disable copy, Hacks is now uncreatable --- src/hacks/hacks.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/hacks/hacks.h b/src/hacks/hacks.h index dfef46ba9..bd8bd92f3 100644 --- a/src/hacks/hacks.h +++ b/src/hacks/hacks.h @@ -32,6 +32,11 @@ LINPHONE_BEGIN_NAMESPACE class Hacks { public: static bool contactHasParam(const std::string &contact, const std::string ¶mName); + +private: + Hacks () = default; + + L_DISABLE_COPY(Hacks); }; LINPHONE_END_NAMESPACE From cde7d0de156b452842577b0fec03a6f706e635c1 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 3 Oct 2017 13:54:29 +0200 Subject: [PATCH 0295/2215] fix(ContentType): use isCPIM instead of isCpim (camel case!) --- src/chat/chat-message.cpp | 2 +- src/content/content-type.cpp | 2 +- src/content/content-type.h | 2 +- src/content/content.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index bbd96d9d7..239b2e1ee 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -983,7 +983,7 @@ LinphoneReason ChatMessagePrivate::receive() { // Start of message modification // --------------------------------------- - if (ContentType::isCPIM(getContentType())) { + if (ContentType::isCpim(getContentType())) { CpimChatMessageModifier ccmm; ccmm.decode(this); } diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index eb558a1c1..95fb47280 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -152,7 +152,7 @@ bool ContentType::isText (const string &contentType) { return contentType == "text/plain"; } -bool ContentType::isCPIM(const string &contentType) { +bool ContentType::isCpim(const string &contentType) { return contentType == "Message/CPIM"; } diff --git a/src/content/content-type.h b/src/content/content-type.h index 1f16ed289..746166c66 100644 --- a/src/content/content-type.h +++ b/src/content/content-type.h @@ -59,7 +59,7 @@ public: static bool isImIsComposing (const std::string &contentType); static bool isImdn (const std::string &contentType); static bool isText (const std::string &contentType); - static bool isCPIM (const std::string &contentType); + static bool isCpim (const std::string &contentType); private: L_DECLARE_PRIVATE(ContentType); diff --git a/src/content/content.h b/src/content/content.h index 352bcfcf0..084f47fc8 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -55,7 +55,7 @@ public: void setBody (const void *buffer, size_t size); size_t getSize () const; - + bool isValid() const; bool isEmpty () const; From 5eca36e0713695100d29b003e010dda0107c30b4 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 3 Oct 2017 14:14:56 +0200 Subject: [PATCH 0296/2215] Removed unusued method on ChatMessage --- src/c-wrapper/api/c-chat-message.cpp | 8 -------- src/chat/chat-message-p.h | 1 - src/chat/chat-message.cpp | 10 ---------- src/chat/chat-message.h | 3 --- 4 files changed, 22 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index dae659457..d8393484a 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -204,14 +204,6 @@ void linphone_chat_message_set_file_transfer_filepath(LinphoneChatMessage *msg, L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFileTransferFilepath(L_C_TO_STRING(filepath)); } -bool_t linphone_chat_message_get_to_be_stored(const LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->isToBeStored(); -} - -void linphone_chat_message_set_to_be_stored(LinphoneChatMessage *msg, bool_t to_be_stored) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setIsToBeStored(!!to_be_stored); -} - belle_http_request_t * linphone_chat_message_get_http_request(LinphoneChatMessage *msg) { return L_GET_PRIVATE_FROM_C_OBJECT(msg)->getHttpRequest(); } diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 1bd7aeee7..efcd9bcf0 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -117,7 +117,6 @@ private: std::string rttMessage = ""; bool isSecured = false; bool isReadOnly = false; - bool isToBeStored = false; std::list > contents; std::shared_ptr internalContent; std::unordered_map customHeaders; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 239b2e1ee..27f6edca6 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -1283,16 +1283,6 @@ void ChatMessage::setFileTransferFilepath(const string &path) { d->fileTransferFilePath = path; } -bool ChatMessage::isToBeStored() const { - L_D(); - return d->isToBeStored; -} - -void ChatMessage::setIsToBeStored(bool store) { - L_D(); - d->isToBeStored = store; -} - // ----------------------------------------------------------------------------- const LinphoneErrorInfo * ChatMessage::getErrorInfo() const { diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index 504549b3a..3fb5d4a2d 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -129,9 +129,6 @@ public: const std::string& getFileTransferFilepath() const; void setFileTransferFilepath(const std::string &path); - bool isToBeStored() const; - void setIsToBeStored(bool store); - const LinphoneErrorInfo * getErrorInfo() const; bool isReadOnly() const; From 54de6bb650119f6bf8a12cd1f368a4c060009dca Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 3 Oct 2017 14:41:02 +0200 Subject: [PATCH 0297/2215] Moved from shared_ptr to Content in ChatMessage --- src/chat/chat-message-p.h | 4 +- src/chat/chat-message.cpp | 39 +++++++------------ src/chat/chat-message.h | 6 +-- src/chat/chat-room.cpp | 30 +++++++------- .../modifier/cpim-chat-message-modifier.cpp | 28 ++++++------- src/content/content.cpp | 5 +++ src/content/content.h | 1 + 7 files changed, 55 insertions(+), 58 deletions(-) diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index efcd9bcf0..f931f421a 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -117,8 +117,8 @@ private: std::string rttMessage = ""; bool isSecured = false; bool isReadOnly = false; - std::list > contents; - std::shared_ptr internalContent; + std::list contents; + Content internalContent; std::unordered_map customHeaders; std::shared_ptr eventsDb; mutable LinphoneErrorInfo * errorInfo = NULL; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 27f6edca6..e72f89d6f 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -140,41 +140,35 @@ string ChatMessagePrivate::getSalCustomHeaderValue(const string& name) { // ----------------------------------------------------------------------------- const string& ChatMessagePrivate::getContentType() { - if (internalContent) { - cContentType = internalContent->getContentType().asString(); + if (!internalContent.isEmpty()) { + cContentType = internalContent.getContentType().asString(); } else { if (contents.size() > 0) { - shared_ptr content = contents.front(); - cContentType = content->getContentType().asString(); + Content content = contents.front(); + cContentType = content.getContentType().asString(); } } return cContentType; } void ChatMessagePrivate::setContentType(const string& contentType) { - if (!internalContent) { - internalContent = make_shared(); - } - internalContent->setContentType(contentType); + internalContent.setContentType(contentType); } const string& ChatMessagePrivate::getText() { - if (internalContent) { - cText = internalContent->getBodyAsString(); + if (!internalContent.isEmpty()) { + cText = internalContent.getBodyAsString(); } else { if (contents.size() > 0) { - shared_ptr content = contents.front(); - cText = content->getBodyAsString(); + Content content = contents.front(); + cText = content.getBodyAsString(); } } return cText; } void ChatMessagePrivate::setText(const string& text) { - if (!internalContent) { - internalContent = make_shared(); - } - internalContent->setBody(text); + internalContent.setBody(text); } LinphoneContent * ChatMessagePrivate::getFileTransferInformation() const { @@ -1297,26 +1291,23 @@ bool ChatMessage::isReadOnly () const { return d->isReadOnly; } -list > ChatMessage::getContents () const { +const list& ChatMessage::getContents () const { L_D(); - list > contents; - for (const auto &content : d->contents) - contents.push_back(content); - return contents; + return d->contents; } -void ChatMessage::addContent (const shared_ptr &content) { +void ChatMessage::addContent (const Content &content) { L_D(); if (d->isReadOnly) return; d->contents.push_back(content); } -void ChatMessage::removeContent (const shared_ptr &content) { +void ChatMessage::removeContent (const Content& content) { L_D(); if (d->isReadOnly) return; - d->contents.remove(const_pointer_cast(content)); + d->contents.remove(content); } string ChatMessage::getCustomHeaderValue (const string &headerName) const { diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index 3fb5d4a2d..8344fe11e 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -133,9 +133,9 @@ public: bool isReadOnly() const; - std::list > getContents() const; - void addContent(const std::shared_ptr &content); - void removeContent(const std::shared_ptr &content); + const std::list& getContents() const; + void addContent(const Content& content); + void removeContent(const Content& content); std::string getCustomHeaderValue(const std::string &headerName) const; void addCustomHeader(const std::string &headerName, const std::string &headerValue); diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index ab5aa3116..dda6f4c7f 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -120,9 +120,9 @@ void ChatRoomPrivate::sendImdn (const string &payload, LinphoneReason reason) { msg->setFromAddress(identity); msg->setToAddress(peerAddress.asString()); - shared_ptr content = make_shared(); - content->setContentType("message/imdn+xml"); - content->setBody(payload); + Content content; + content.setContentType("message/imdn+xml"); + content.setBody(payload); msg->addContent(content); /* Do not try to encrypt the notification when it is reporting an error (maybe it should be bypassed only for some reasons). */ @@ -212,9 +212,9 @@ void ChatRoomPrivate::sendIsComposingNotification () { msg->setFromAddress(identity); msg->setToAddress(peerAddress.asString()); - shared_ptr content = make_shared(); - content->setContentType("application/im-iscomposing+xml"); - content->setBody(payload); + Content content; + content.setContentType("application/im-iscomposing+xml"); + content.setBody(payload); msg->addContent(content); LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(core); @@ -269,14 +269,14 @@ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colN if (!message) { message = q->createMessage(); - shared_ptr content = make_shared(); + Content content; message->addContent(content); if (argv[4]) { - content->setBody(argv[4]); + content.setBody(argv[4]); } if (argv[13]) { - content->setContentType(argv[13]); + content.setContentType(argv[13]); } Address peer(peerAddress.asString()); @@ -399,9 +399,9 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa msg = q->createMessage(); - shared_ptr content = make_shared(); - content->setContentType(salMsg->content_type); - content->setBody(salMsg->text ? salMsg->text : ""); + Content content; + content.setContentType(salMsg->content_type); + content.setBody(salMsg->text ? salMsg->text : ""); msg->addContent(content); msg->setToAddress(op->get_to() ? op->get_to() : linphone_core_get_identity(core)); @@ -565,9 +565,9 @@ shared_ptr ChatRoom::createMessage (const string &message) { L_D(); shared_ptr chatMessage = createMessage(); - shared_ptr content = make_shared(); - content->setContentType("text/plain"); - content->setBody(message); + Content content; + content.setContentType("text/plain"); + content.setBody(message); chatMessage->addContent(content); chatMessage->setToAddress(d->peerAddress); diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index 65cb25e1e..c46dd0223 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -37,8 +37,8 @@ int CpimChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { cpimContentTypeHeader.setValue("Message/CPIM"); message.addCpimHeader(cpimContentTypeHeader); - shared_ptr content; - if (messagePrivate->internalContent) { + Content content; + if (!messagePrivate->internalContent.isEmpty()) { // Another ChatMessageModifier was called before this one, we apply our changes on the private content content = messagePrivate->internalContent; } else { @@ -48,8 +48,8 @@ int CpimChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { content = messagePrivate->contents.front(); } - string contentType = content->getContentType().asString(); - const vector body = content->getBody(); + string contentType = content.getContentType().asString(); + const vector body = content.getBody(); string contentBody(body.begin(), body.end()); Cpim::GenericHeader contentTypeHeader; @@ -62,33 +62,33 @@ int CpimChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { if (!message.isValid()) { //TODO } else { - shared_ptr newContent = make_shared(); + Content newContent; ContentType newContentType("Message/CPIM"); - newContent->setContentType(newContentType); - newContent->setBody(message.asString()); + newContent.setContentType(newContentType); + newContent.setBody(message.asString()); messagePrivate->internalContent = newContent; } return 0; } int CpimChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { - shared_ptr content; - if (messagePrivate->internalContent) { + Content content; + if (!messagePrivate->internalContent.isEmpty()) { content = messagePrivate->internalContent; } else { content = messagePrivate->contents.front(); } - ContentType contentType = content->getContentType(); + ContentType contentType = content.getContentType(); if (contentType.asString() == "Message/CPIM") { - const vector body = content->getBody(); + const vector body = content.getBody(); string contentBody(body.begin(), body.end()); shared_ptr message = Cpim::Message::createFromString(contentBody); if (message && message->isValid()) { - shared_ptr newContent = make_shared(); + Content newContent; ContentType newContentType(message->getContentHeaders()->front()->getValue()); - newContent->setContentType(newContentType); - newContent->setBody(message->getContent()); + newContent.setContentType(newContentType); + newContent.setBody(message->getContent()); } else { //TODO } diff --git a/src/content/content.cpp b/src/content/content.cpp index 9c12562dc..2c3786ea5 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -67,6 +67,11 @@ Content &Content::operator= (Content &&src) { return *this; } +bool Content::operator==(const Content& content) { + // return true if the two are equal, and false otherwise. + return true; +} + const ContentType &Content::getContentType () const { L_D(); return d->contentType; diff --git a/src/content/content.h b/src/content/content.h index 084f47fc8..c7f419223 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -38,6 +38,7 @@ public: Content &operator= (const Content &src); Content &operator= (Content &&src); + bool operator==(const Content& content); const ContentType &getContentType () const; void setContentType (const ContentType &contentType); From fb312b1ae845cabc994aed868148c77646ca5680 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 3 Oct 2017 14:30:37 +0200 Subject: [PATCH 0298/2215] feat(core): add notes --- src/address/address.h | 1 + src/content/content-type.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/address/address.h b/src/address/address.h index 94c2e4ea2..d0075f3c1 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -29,6 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class AddressPrivate; class LINPHONE_PUBLIC Address : public ClonableObject { + // TODO: Remove me later. friend class CallSession; friend class ClientGroupChatRoom; diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index 95fb47280..b0609c72b 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -16,9 +16,10 @@ * along with this program. If not, see . */ -#include "content-type.h" #include "object/clonable-object-p.h" +#include "content-type.h" + // ============================================================================= using namespace std; From 2bac63219e0689ece3f61aeefb2f5e47b6014fd4 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 3 Oct 2017 15:10:57 +0200 Subject: [PATCH 0299/2215] feat(General): getPublicHelper => better code --- include/linphone/utils/general.h | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index 268c9b50a..d83dd0e37 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -102,36 +102,24 @@ class ObjectPrivate; friend class Tester; #endif -template -inline ClonableObject *getPublicHelper (T *object, const ClonableObjectPrivate *context) { - auto it = object->find(context); - L_ASSERT(it != object->end()); - return it->second; +template +inline T *getPublicHelper (U *map, const ClonableObjectPrivate *context) { + auto it = map->find(context); + L_ASSERT(it != map->end()); + return static_cast(it->second); } template -inline const ClonableObject *getPublicHelper (const T *object, const ClonableObjectPrivate *context) { - auto it = object->find(context); - L_ASSERT(it != object->cend()); - return it->second; -} - -template -inline Object *getPublicHelper (T *object, const ObjectPrivate *) { - return object; -} - -template -inline const Object *getPublicHelper (const T *object, const ObjectPrivate *) { - return object; +constexpr T *getPublicHelper (Object *object, const ObjectPrivate *) { + return static_cast(object); } #define L_DECLARE_PUBLIC(CLASS) \ inline CLASS *getPublic () { \ - return static_cast(getPublicHelper(mPublic, this)); \ + return getPublicHelper(mPublic, this); \ } \ inline const CLASS *getPublic () const { \ - return static_cast(getPublicHelper(mPublic, this)); \ + return getPublicHelper(mPublic, this); \ } \ friend class CLASS; From e7415078682231f0f4548dd93a8a2099e54c2e28 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 3 Oct 2017 15:22:45 +0200 Subject: [PATCH 0300/2215] fix(General): use const map instead of map on getPublicHelper --- include/linphone/utils/general.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index d83dd0e37..bfef0a83f 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -103,7 +103,7 @@ class ObjectPrivate; #endif template -inline T *getPublicHelper (U *map, const ClonableObjectPrivate *context) { +inline T *getPublicHelper (const U *map, const ClonableObjectPrivate *context) { auto it = map->find(context); L_ASSERT(it != map->end()); return static_cast(it->second); From c4121b438d12c549096253bdac888504721e97bc Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 3 Oct 2017 15:26:09 +0200 Subject: [PATCH 0301/2215] Fixed issue in ChatMessage contents when creating it from db --- src/chat/chat-room.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index dda6f4c7f..5e3e12100 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -270,14 +270,13 @@ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colN message = q->createMessage(); Content content; - message->addContent(content); - if (argv[4]) { content.setBody(argv[4]); } if (argv[13]) { content.setContentType(argv[13]); } + message->addContent(content); Address peer(peerAddress.asString()); if (atoi(argv[3]) == ChatMessage::Direction::Incoming) { @@ -310,13 +309,13 @@ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colN /* Fix content type for old messages that were stored without it */ /* To keep ? - if (!linphone_chat_message_get_content_type(newMessage)) { - if (linphone_chat_message_get_file_transfer_information(newMessage)) { - linphone_chat_message_set_content_type(newMessage, ms_strdup("application/vnd.gsma.rcs-ft-http+xml")); - } else if (linphone_chat_message_get_external_body_url(newMessage)) { - linphone_chat_message_set_content_type(newMessage, ms_strdup("message/external-body")); + if (message->getPrivate()->getContentType().empty()) { + if (message->getPrivate()->getFileTransferInformation()) { + message->getPrivate()->setContentType("application/vnd.gsma.rcs-ft-http+xml"); + } else if (!message->getExternalBodyUrl().empty()) { + message->getPrivate()->setContentType("message/external-body"); } else { - linphone_chat_message_set_content_type(newMessage, ms_strdup("text/plain")); + message->getPrivate()->setContentType("text/plain"); } }*/ From 779646a38bb8589e1fefaa7ea8d033df42a4a62f Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 3 Oct 2017 16:34:52 +0200 Subject: [PATCH 0302/2215] feat(ChatMessage): use L_DECLARE_ENUM for state --- include/CMakeLists.txt | 1 + include/linphone/enums/chat-message-enums.h | 34 +++++++++++++++++++++ src/chat/chat-message.cpp | 20 ++++++------ src/chat/chat-message.h | 15 ++------- 4 files changed, 47 insertions(+), 23 deletions(-) create mode 100644 include/linphone/enums/chat-message-enums.h diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 8877fd6a9..aaf4510a3 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -90,6 +90,7 @@ set(C_API_HEADER_FILES ) set(ENUMS_HEADER_FILES + chat-message-enums.h chat-room-enums.h event-log-enums.h ) diff --git a/include/linphone/enums/chat-message-enums.h b/include/linphone/enums/chat-message-enums.h new file mode 100644 index 000000000..a069b6989 --- /dev/null +++ b/include/linphone/enums/chat-message-enums.h @@ -0,0 +1,34 @@ +/* + * chat-room-enums.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _CHAT_MESSAGE_ENUMS_H_ +#define _CHAT_MESSAGE_ENUMS_H_ + +// ============================================================================= + +#define L_ENUM_VALUES_CHAT_MESSAGE_STATE(F) \ + F(Idle) \ + F(InProgress) \ + F(Delivered) \ + F(NotDelivered) \ + F(FileTransferError) \ + F(FileTransferDone) \ + F(DeliveredToUser) \ + F(Displayed) + +#endif // ifndef _CHAT_MESSAGE_ENUMS_H_ diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index e72f89d6f..89ef2534e 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -1221,9 +1221,9 @@ bool ChatMessage::isRead() const { L_D(); LinphoneCore *lc = d->chatRoom->getCore(); LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); - if (linphone_im_notif_policy_get_recv_imdn_displayed(policy) && d->state == Displayed) return true; - if (linphone_im_notif_policy_get_recv_imdn_delivered(policy) && (d->state == DeliveredToUser || d->state == Displayed)) return true; - return d->state == Delivered || d->state == Displayed || d->state == DeliveredToUser; + if (linphone_im_notif_policy_get_recv_imdn_displayed(policy) && d->state == State::Displayed) return true; + if (linphone_im_notif_policy_get_recv_imdn_delivered(policy) && (d->state == State::DeliveredToUser || d->state == State::Displayed)) return true; + return d->state == State::Delivered || d->state == State::Displayed || d->state == State::DeliveredToUser; } const string& ChatMessage::getAppdata () const { @@ -1354,14 +1354,14 @@ void ChatMessage::updateState(State state) { d->setState(state); linphone_chat_message_store_state(L_GET_C_BACK_PTR(this)); - if (state == Delivered || state == NotDelivered) + if (state == State::Delivered || state == State::NotDelivered) d->chatRoom->getPrivate()->moveTransientMessageToWeakMessages(getSharedFromThis()); } void ChatMessage::reSend() { L_D(); - if (d->state != NotDelivered) { + if (d->state != State::NotDelivered) { lWarning() << "Cannot resend chat message in state " << linphone_chat_message_state_to_string((LinphoneChatMessageState)d->state); return; } @@ -1402,7 +1402,7 @@ int ChatMessage::uploadFile() { int err = d->startHttpTransfer(linphone_core_get_file_transfer_server(d->chatRoom->getCore()), "POST", &cbs); if (err == -1) { - d->setState(NotDelivered); + d->setState(State::NotDelivered); } return err; } @@ -1424,15 +1424,15 @@ int ChatMessage::downloadFile() { if (err == -1) return -1; // start the download, status is In Progress - d->setState(InProgress); + d->setState(State::InProgress); return 0; } void ChatMessage::cancelFileTransfer() { L_D(); if (d->httpRequest) { - if (d->state == InProgress) { - d->setState(NotDelivered); + if (d->state == State::InProgress) { + d->setState(State::NotDelivered); } if (!belle_http_request_is_cancelled(d->httpRequest)) { if (d->chatRoom) { @@ -1467,7 +1467,7 @@ int ChatMessage::putCharacter(uint32_t character) { if (lc && lp_config_get_int(lc->config, "misc", "store_rtt_messages", 1) == 1) { lDebug() << "New line sent, forge a message with content " << d->rttMessage.c_str(); d->setTime(ms_time(0)); - d->state = Displayed; + d->state = State::Displayed; d->direction = Outgoing; setFromAddress(LinphonePrivate::Address(linphone_address_as_string(linphone_address_new(linphone_core_get_identity(lc))))); linphone_chat_message_store(L_GET_C_BACK_PTR(this)); diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index 8344fe11e..14af85871 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -20,11 +20,9 @@ #define _CHAT_MESSAGE_H_ #include -#include -#include "enums.h" #include "linphone/api/c-types.h" -#include "linphone/api/c-chat-message.h" +#include "linphone/enums/chat-message-enums.h" #include "object/object.h" @@ -52,16 +50,7 @@ public: Outgoing }; - enum State { - Idle, - InProgress, - Delivered, - NotDelivered, - FileTransferError, - FileTransferDone, - DeliveredToUser, - Displayed - }; + L_DECLARE_ENUM(State, L_ENUM_VALUES_CHAT_MESSAGE_STATE); ChatMessage(const std::shared_ptr &room); virtual ~ChatMessage() = default; From 3ccf8850db2e9557331d1dd4fcb36e73915f5337 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 3 Oct 2017 16:56:26 +0200 Subject: [PATCH 0303/2215] fix(EventsDb): use full name of ChatMessage state --- include/linphone/api/c-types.h | 9 ++++++++- include/linphone/types.h | 15 --------------- src/db/events-db.cpp | 19 ++++++++++--------- 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index 7af89ac15..3b7148b3f 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -22,9 +22,10 @@ // TODO: Remove me in the future. #include "linphone/types.h" -#include "linphone/utils/enum-generator.h" +#include "linphone/enums/chat-message-enums.h" #include "linphone/enums/chat-room-enums.h" #include "linphone/enums/event-log-enums.h" +#include "linphone/utils/enum-generator.h" // ============================================================================= @@ -129,6 +130,12 @@ typedef struct _LinphoneChatMessageEvent LinphoneChatMessageEvent; // C Enums. // ============================================================================= +/** + * LinphoneChatMessageState is used to notify if messages have been succesfully delivered or not. + * @ingroup chatroom + */ +L_DECLARE_C_ENUM(ChatMessageState, L_ENUM_VALUES_CHAT_MESSAGE_STATE); + L_DECLARE_C_ENUM(ChatRoomState, L_ENUM_VALUES_CHAT_ROOM_STATE); L_DECLARE_C_ENUM(EventLogType, L_ENUM_VALUES_EVENT_LOG_TYPE); diff --git a/include/linphone/types.h b/include/linphone/types.h index c8043e4f5..b314051af 100644 --- a/include/linphone/types.h +++ b/include/linphone/types.h @@ -318,21 +318,6 @@ typedef enum _LinphoneCallStatus { LinphoneCallDeclinedElsewhere /** messageStateToSql[] = { - { ChatMessage::Idle, "1" }, - { ChatMessage::InProgress, "2" }, - { ChatMessage::Delivered, "3" }, - { ChatMessage::NotDelivered, "4" }, - { ChatMessage::FileTransferError, "5" }, - { ChatMessage::FileTransferDone, "6" }, - { ChatMessage::DeliveredToUser, "7" }, - { ChatMessage::Displayed, "8" } + { ChatMessage::State::Idle, "1" }, + { ChatMessage::State::InProgress, "2" }, + { ChatMessage::State::Delivered, "3" }, + { ChatMessage::State::NotDelivered, "4" }, + { ChatMessage::State::FileTransferError, "5" }, + { ChatMessage::State::FileTransferDone, "6" }, + { ChatMessage::State::DeliveredToUser, "7" }, + { ChatMessage::State::Displayed, "8" } }; static constexpr const char *mapMessageStateToSql (ChatMessage::State state) { @@ -408,7 +409,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " )" " )" " AND direction_id = " + string(mapMessageDirectionToSql(ChatMessage::Incoming)) + - " AND state_id = " + string(mapMessageStateToSql(ChatMessage::Displayed)); + " AND state_id = " + string(mapMessageStateToSql(ChatMessage::State::Displayed)); int count = 0; L_BEGIN_LOG_EXCEPTION From aafd069305df78b26ee1ecedbce452b9622b345c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 3 Oct 2017 17:04:02 +0200 Subject: [PATCH 0304/2215] Removed from header methods deleted previously --- include/linphone/api/c-chat-message.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index 011427cd2..90ecd2ef4 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -244,21 +244,6 @@ LINPHONE_PUBLIC bool_t linphone_chat_message_is_file_transfer(LinphoneChatMessag */ LINPHONE_PUBLIC bool_t linphone_chat_message_is_text(LinphoneChatMessage *message); -/** - * Get if a chat message is to be stored. - * @param[in] message LinphoneChatMessage object - * @return Whether or not the message is to be stored - */ -LINPHONE_PUBLIC bool_t linphone_chat_message_get_to_be_stored(const LinphoneChatMessage *message); - -/** - * Set if a chat message is to be stored. - * This content type must match a content that is text representable, such as text/plain, text/html or image/svg+xml. - * @param[in] message LinphoneChatMessage object - * @param[in] to_be_stored Whether or not the chat message is to be stored - */ -LINPHONE_PUBLIC void linphone_chat_message_set_to_be_stored(LinphoneChatMessage *message, bool_t to_be_stored); - /** * Start the download of the file from remote server * From 097732c15f3d026322ec0c4943d5f7a5e63592ab Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 3 Oct 2017 17:10:43 +0200 Subject: [PATCH 0305/2215] The value param to the setParam() and setUriParam() of an Address is no optional. --- src/address/address.h | 4 ++-- src/chat/client-group-chat-room.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/address/address.h b/src/address/address.h index d0075f3c1..86549e8f9 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -88,12 +88,12 @@ public: bool hasParam (const std::string ¶mName) const; const std::string &getParamValue (const std::string ¶mName) const; - bool setParam (const std::string ¶mName, const std::string ¶mValue); + bool setParam (const std::string ¶mName, const std::string ¶mValue = ""); bool setParams (const std::string ¶ms); bool hasUriParam (const std::string &uriParamName) const; const std::string &getUriParamValue (const std::string &uriParamName) const; - bool setUriParam (const std::string &uriParamName, const std::string &uriParamValue); + bool setUriParam (const std::string &uriParamName, const std::string &uriParamValue = ""); bool setUriParams (const std::string &uriParams); private: diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 9e4bace9c..32819fcbd 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -72,7 +72,7 @@ void ClientGroupChatRoom::addParticipants (const list
    &addresses, const session->configure(LinphoneCallOutgoing, nullptr, nullptr, me->getAddress(), focus->getAddress()); session->initiateOutgoing(); Address addr = me->getAddress(); - addr.setParam("text", ""); + addr.setParam("text"); session->getPrivate()->getOp()->set_contact_address(addr.getPrivate()->getInternalAddress()); session->startInvite(nullptr, subject); d->setState(ChatRoom::State::CreationPending); From 9f9da0fda1e54b0df97c686661c6c5be95530d0a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 3 Oct 2017 17:23:27 +0200 Subject: [PATCH 0306/2215] Fixed ChatMessage getContentType() --- src/chat/chat-message.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 89ef2534e..5a9a678a8 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -140,7 +140,7 @@ string ChatMessagePrivate::getSalCustomHeaderValue(const string& name) { // ----------------------------------------------------------------------------- const string& ChatMessagePrivate::getContentType() { - if (!internalContent.isEmpty()) { + if (!internalContent.getContentType().asString().empty()) { cContentType = internalContent.getContentType().asString(); } else { if (contents.size() > 0) { From 14311c8786186effe490030c2e5625b6b6131e05 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 3 Oct 2017 17:30:37 +0200 Subject: [PATCH 0307/2215] Hacks::contactHasParam() can now be removed thanks to an update of belle-sip. --- src/chat/client-group-chat-room.cpp | 2 +- src/conference/session/call-session-p.h | 1 + src/conference/session/call-session.cpp | 11 +++++++++++ src/conference/session/call-session.h | 1 + src/hacks/hacks.cpp | 12 ------------ src/hacks/hacks.h | 1 - 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 32819fcbd..e5890910e 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -200,7 +200,7 @@ void ClientGroupChatRoom::onCallSessionStateChanged (const CallSession &session, Address addr(session.getRemoteContact()); addr.clean(); onConferenceCreated(addr); - if (Hacks::contactHasParam(session.getRemoteContact(), "isfocus")) + if (session.getRemoteContactAddress()->hasParam("isfocus")) eventHandler->subscribe(conferenceAddress); } } diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index 18f1fdf83..74c401c74 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -86,6 +86,7 @@ protected: CallSessionParams *params = nullptr; mutable CallSessionParams *currentParams = nullptr; CallSessionParams *remoteParams = nullptr; + mutable Address remoteContactAddress; std::string subject; LinphoneCallDir direction = LinphoneCallOutgoing; diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 40347a8f5..c28da3455 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -1002,6 +1002,17 @@ string CallSession::getRemoteContact () const { return string(); } +const Address *CallSession::getRemoteContactAddress () const { + L_D(); + if (!d->op) { + return nullptr; + } + char *addrStr = sal_address_as_string(d->op->get_remote_contact_address()); + d->remoteContactAddress = Address(addrStr); + bctbx_free(addrStr); + return &d->remoteContactAddress; +} + const CallSessionParams * CallSession::getRemoteParams () { L_D(); if (d->op){ diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index 2495dab34..6116895fb 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -67,6 +67,7 @@ public: const Address& getRemoteAddress () const; std::string getRemoteAddressAsString () const; std::string getRemoteContact () const; + const Address *getRemoteContactAddress () const; const CallSessionParams *getRemoteParams (); LinphoneCallState getState () const; diff --git a/src/hacks/hacks.cpp b/src/hacks/hacks.cpp index b5caeadc7..80ef02920 100644 --- a/src/hacks/hacks.cpp +++ b/src/hacks/hacks.cpp @@ -30,16 +30,4 @@ LINPHONE_BEGIN_NAMESPACE // ----------------------------------------------------------------------------- -bool Hacks::contactHasParam(const string &contact, const string ¶mName) { - // This is very ugly!!! The handling of Contact headers and addresses is a real - // crap that really needs to be reworked. Meanwhile, we cannot get the params on the - // remote contact address and need to forge and parse a contact header. - ostringstream os; - os << "Contact: " << contact; - belle_sip_header_contact_t *contactHeader = belle_sip_header_contact_parse(os.str().c_str()); - bool result = belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(contactHeader), paramName.c_str()); - belle_sip_object_unref(contactHeader); - return result; -} - LINPHONE_END_NAMESPACE diff --git a/src/hacks/hacks.h b/src/hacks/hacks.h index bd8bd92f3..f1eccc9c7 100644 --- a/src/hacks/hacks.h +++ b/src/hacks/hacks.h @@ -31,7 +31,6 @@ LINPHONE_BEGIN_NAMESPACE // can be located more easily. class Hacks { public: - static bool contactHasParam(const std::string &contact, const std::string ¶mName); private: Hacks () = default; From 3b10f8da340a089353817ee1b0989a7a5151a8ed Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 3 Oct 2017 18:03:50 +0200 Subject: [PATCH 0308/2215] Include the body containing the list of addresses to invite when sending the INVITE to create a client group chat room. --- coreapi/sal/call_op.cpp | 5 +++++ src/chat/client-group-chat-room.cpp | 3 +-- src/conference/session/call-session.cpp | 4 +++- src/conference/session/call-session.h | 3 ++- src/conference/session/media-session.cpp | 4 ++-- src/conference/session/media-session.h | 2 +- src/content/content.cpp | 4 ++++ 7 files changed, 18 insertions(+), 7 deletions(-) diff --git a/coreapi/sal/call_op.cpp b/coreapi/sal/call_op.cpp index 68daf9355..6c3b50ba6 100644 --- a/coreapi/sal/call_op.cpp +++ b/coreapi/sal/call_op.cpp @@ -76,6 +76,7 @@ belle_sip_header_allow_t *SalCallOp::create_allow(bool_t enable_update) { int SalCallOp::set_custom_body(belle_sip_message_t *msg, const Content &body) { ContentType contentType = body.getContentType(); + string contentDisposition = body.getContentDisposition(); size_t bodySize = body.getBody().size(); if (bodySize > SIP_MESSAGE_BODY_LIMIT) { @@ -87,6 +88,10 @@ int SalCallOp::set_custom_body(belle_sip_message_t *msg, const Content &body) { belle_sip_header_content_type_t *content_type = belle_sip_header_content_type_create(contentType.getType().c_str(), contentType.getSubType().c_str()); belle_sip_message_add_header(msg, BELLE_SIP_HEADER(content_type)); } + if (!contentDisposition.empty()) { + belle_sip_header_content_disposition_t *contentDispositionHeader = belle_sip_header_content_disposition_create(contentDisposition.c_str()); + belle_sip_message_add_header(msg, BELLE_SIP_HEADER(contentDispositionHeader)); + } belle_sip_header_content_length_t *content_length = belle_sip_header_content_length_create(bodySize); belle_sip_message_add_header(msg, BELLE_SIP_HEADER(content_length)); diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index e5890910e..5b2246a5d 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -63,7 +63,6 @@ void ClientGroupChatRoom::addParticipants (const list
    &addresses, const content.setBody(getResourceLists(sortedAddresses)); content.setContentType("application/resource-lists+xml"); content.setContentDisposition("recipient-list"); - lInfo() << "Body size: " << content.getSize() << endl << "Body:" << endl << content.getBodyAsString(); CallSessionParams csp; if (params) csp = *params; @@ -74,7 +73,7 @@ void ClientGroupChatRoom::addParticipants (const list
    &addresses, const Address addr = me->getAddress(); addr.setParam("text"); session->getPrivate()->getOp()->set_contact_address(addr.getPrivate()->getInternalAddress()); - session->startInvite(nullptr, subject); + session->startInvite(nullptr, subject, &content); d->setState(ChatRoom::State::CreationPending); } // TODO diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index c28da3455..bf8e903ec 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -867,7 +867,7 @@ void CallSession::startIncomingNotification () { } } -int CallSession::startInvite (const Address *destination, const string &subject) { +int CallSession::startInvite (const Address *destination, const string &subject, const Content *content) { L_D(); d->subject = subject; /* Try to be best-effort in giving real local or routable contact address */ @@ -884,6 +884,8 @@ int CallSession::startInvite (const Address *destination, const string &subject) char *from = linphone_address_as_string(d->log->from); /* Take a ref because sal_call() may destroy the CallSession if no SIP transport is available */ shared_ptr ref = getSharedFromThis(); + if (content) + d->op->set_local_body(*content); int result = d->op->call(from, destinationStr.c_str(), subject.empty() ? nullptr : subject.c_str()); ms_free(from); if (result < 0) { diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index 6116895fb..d53f8d26e 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -32,6 +32,7 @@ LINPHONE_BEGIN_NAMESPACE class CallPrivate; class CallSessionPrivate; +class Content; class LINPHONE_PUBLIC CallSession : public Object { friend class CallPrivate; @@ -53,7 +54,7 @@ public: LinphoneStatus redirect (const std::string &redirectUri); LinphoneStatus redirect (const Address &redirectAddr); virtual void startIncomingNotification (); - virtual int startInvite (const Address *destination, const std::string &subject = ""); + virtual int startInvite (const Address *destination, const std::string &subject = "", const Content *content = nullptr); LinphoneStatus terminate (const LinphoneErrorInfo *ei = nullptr); LinphoneStatus update (const CallSessionParams *csp, const std::string &subject = ""); diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index c19d55098..c56921792 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -4249,7 +4249,7 @@ void MediaSession::startIncomingNotification () { CallSession::startIncomingNotification(); } -int MediaSession::startInvite (const Address *destination, const string &subject) { +int MediaSession::startInvite (const Address *destination, const string &subject, const Content *content) { L_D(); linphone_core_stop_dtmf_stream(d->core); d->makeLocalMediaDescription(); @@ -4265,7 +4265,7 @@ int MediaSession::startInvite (const Address *destination, const string &subject d->op->set_local_media_description(d->localDesc); } - int result = CallSession::startInvite(destination, subject); + int result = CallSession::startInvite(destination, subject, content); if (result < 0) { if (d->state == LinphoneCallError) d->stopStreams(); diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index 60e2163e2..4318d70dd 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -48,7 +48,7 @@ public: LinphoneStatus resume (); void sendVfuRequest (); void startIncomingNotification () override; - int startInvite (const Address *destination, const std::string &subject = "") override; + int startInvite (const Address *destination, const std::string &subject = "", const Content *content = nullptr) override; void startRecording (); void stopRecording (); LinphoneStatus update (const MediaSessionParams *msp, const std::string &subject = ""); diff --git a/src/content/content.cpp b/src/content/content.cpp index 2c3786ea5..25cf8dd91 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -42,12 +42,14 @@ Content::Content (const Content &src) : ClonableObject(*new ContentPrivate) { L_D(); d->body = src.getBody(); d->contentType = src.getContentType(); + d->contentDisposition = src.getContentDisposition(); } Content::Content (Content &&src) : ClonableObject(*new ContentPrivate) { L_D(); d->body = move(src.getPrivate()->body); d->contentType = move(src.getPrivate()->contentType); + d->contentDisposition = move(src.getPrivate()->contentDisposition); } Content &Content::operator= (const Content &src) { @@ -55,6 +57,7 @@ Content &Content::operator= (const Content &src) { if (this != &src) { d->body = src.getBody(); d->contentType = src.getContentType(); + d->contentDisposition = src.getContentDisposition(); } return *this; @@ -64,6 +67,7 @@ Content &Content::operator= (Content &&src) { L_D(); d->body = move(src.getPrivate()->body); d->contentType = move(src.getPrivate()->contentType); + d->contentDisposition = move(src.getPrivate()->contentDisposition); return *this; } From e52a8e902b3d9cf5f71790f50a75f97ff21f1b88 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 4 Oct 2017 09:31:18 +0200 Subject: [PATCH 0309/2215] feat(EventsDb): update schema, supports chatroom subject --- src/db/events-db.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 794eb5e3f..70390fe2d 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -75,7 +75,6 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} ); } - static constexpr EnumToSql messageStateToSql[] = { { ChatMessage::State::Idle, "1" }, { ChatMessage::State::InProgress, "2" }, @@ -169,23 +168,19 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS dialog (" - " id" + primaryKeyAutoIncrementStr() + "," - - // Sip address used to communicate. - " local_sip_address_id INT UNSIGNED NOT NULL," - // Server (for conference) or user sip address. - " remote_sip_address_id INT UNSIGNED NOT NULL," + " peer_sip_address_id INT UNSIGNED PRIMARY KEY," // Dialog creation date. " creation_timestamp TIMESTAMP NOT NULL," + // Chatroom subject. + " subject VARCHAR(255)," + // Last event timestamp (call, message...). " last_update_timestamp TIMESTAMP NOT NULL," - " FOREIGN KEY (local_sip_address_id)" - " REFERENCES sip_address(id)" - " ON DELETE CASCADE," - " FOREIGN KEY (remote_sip_address_id)" + + " FOREIGN KEY (peer_sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" ")"; @@ -215,7 +210,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " REFERENCES event(id)" " ON DELETE CASCADE," " FOREIGN KEY (dialog_id)" - " REFERENCES dialog(id)" + " REFERENCES dialog(peer_sip_address_id)" " ON DELETE CASCADE," " FOREIGN KEY (state_id)" " REFERENCES message_state(id)" From 459d54c74656d7d5c74e879e6a988a4598420f08 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 4 Oct 2017 10:51:28 +0200 Subject: [PATCH 0310/2215] Fix automatic wrapper generation of enums with the L_DECLARE_C_ENUM macro. --- coreapi/help/doc/doxygen/Doxyfile.in | 3 ++- include/CMakeLists.txt | 1 + include/linphone/utils/enum-generator.h | 5 ++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/coreapi/help/doc/doxygen/Doxyfile.in b/coreapi/help/doc/doxygen/Doxyfile.in index 1e0ea6679..851af4c1a 100644 --- a/coreapi/help/doc/doxygen/Doxyfile.in +++ b/coreapi/help/doc/doxygen/Doxyfile.in @@ -2004,7 +2004,8 @@ SEARCH_INCLUDES = YES # preprocessor. # This tag requires that the tag SEARCH_INCLUDES is set to YES. -INCLUDE_PATH = . +INCLUDE_PATH = . \ + @LINPHONE_HEADER_ROOT_DIR@ # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index aaf4510a3..b0cd5236b 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -122,6 +122,7 @@ PREPEND(ENUMS_HEADER_FILES "${SRC_ROOT_DIRECTORY}/enums" ${ENUMS_HEADER_FILES}) PREPEND(UTILS_HEADER_FILES "${SRC_ROOT_DIRECTORY}/utils" ${UTILS_HEADER_FILES}) set(LINPHONE_HEADER_FILES ${ROOT_HEADER_FILES} ${C_API_HEADER_FILES} ${ENUMS_HEADER_FILES} ${UTILS_HEADER_FILES} PARENT_SCOPE) +set(LINPHONE_HEADER_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}" PARENT_SCOPE) # ------------------------------------------------------------------------------ diff --git a/include/linphone/utils/enum-generator.h b/include/linphone/utils/enum-generator.h index 333ff6d98..9629b5767 100644 --- a/include/linphone/utils/enum-generator.h +++ b/include/linphone/utils/enum-generator.h @@ -53,10 +53,9 @@ LINPHONE_BEGIN_NAMESPACE #define L_C_ENUM_PREFIX Linphone #define L_DECLARE_C_ENUM(NAME, VALUES) \ - enum L_CONCAT(L_C_ENUM_PREFIX, NAME) { \ + typedef enum L_CONCAT(_, L_CONCAT(L_C_ENUM_PREFIX, NAME)) { \ L_APPLY(L_CONCAT, L_CONCAT(L_C_ENUM_PREFIX, NAME), L_GET_HEAP(VALUES(L_DECLARE_ENUM_VALUE))) \ - }; \ - typedef enum L_CONCAT(L_C_ENUM_PREFIX, NAME) L_CONCAT(L_C_ENUM_PREFIX, NAME); + } L_CONCAT(L_C_ENUM_PREFIX, NAME) LINPHONE_END_NAMESPACE From 6caf117b9136ad2f5ae0d1df06e15838035867fb Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 4 Oct 2017 10:54:09 +0200 Subject: [PATCH 0311/2215] feat(Object): check weak ptr when `getSharedFromThis` is called --- src/object/object.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/object/object.cpp b/src/object/object.cpp index 4d83a7b54..c2f5967a2 100644 --- a/src/object/object.cpp +++ b/src/object/object.cpp @@ -16,12 +16,15 @@ * along with this program. If not, see . */ +#include "logger/logger.h" #include "object-p.h" #include "object.h" // ============================================================================= +#define GET_SHARED_FROM_THIS_FATAL_ERROR "Object was not created with `ObjectFactory::create`." + using namespace std; LINPHONE_BEGIN_NAMESPACE @@ -33,11 +36,21 @@ Object::~Object () { Object::Object (ObjectPrivate &p) : mPrivate(&p) {} shared_ptr Object::getSharedFromThis () { - return mPrivate->weak.lock(); + return const_pointer_cast(static_cast(this)->getSharedFromThis()); } shared_ptr Object::getSharedFromThis () const { - return mPrivate->weak.lock(); + shared_ptr object; + + try { + object = mPrivate->weak.lock(); + if (!object) + lFatal() << GET_SHARED_FROM_THIS_FATAL_ERROR; + } catch (const exception &) { + lFatal() << GET_SHARED_FROM_THIS_FATAL_ERROR; + } + + return object; } void ObjectFactory::setPublic (const shared_ptr &object) { From b7fdc47128c5b671127b5b01ba2b65813c44b715 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 4 Oct 2017 10:54:26 +0200 Subject: [PATCH 0312/2215] Added CPIM tester --- src/chat/chat-message.cpp | 5 +++ src/chat/chat-message.h | 1 + .../modifier/cpim-chat-message-modifier.cpp | 1 + tester/cpim-tester.cpp | 31 +++++++++++++++---- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 5a9a678a8..fa4c931a7 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -1310,6 +1310,11 @@ void ChatMessage::removeContent (const Content& content) { d->contents.remove(content); } +const Content& ChatMessage::getInternalContent() const { + L_D(); + return d->internalContent; +} + string ChatMessage::getCustomHeaderValue (const string &headerName) const { L_D(); try { diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index 14af85871..09bc267cf 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -125,6 +125,7 @@ public: const std::list& getContents() const; void addContent(const Content& content); void removeContent(const Content& content); + const Content& getInternalContent() const; std::string getCustomHeaderValue(const std::string &headerName) const; void addCustomHeader(const std::string &headerName, const std::string &headerValue); diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index c46dd0223..8cac39ada 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -89,6 +89,7 @@ int CpimChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { ContentType newContentType(message->getContentHeaders()->front()->getValue()); newContent.setContentType(newContentType); newContent.setBody(message->getContent()); + messagePrivate->internalContent = newContent; } else { //TODO } diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index 09e8bb4d9..8c0ac3f10 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -17,6 +17,9 @@ */ #include "chat/cpim/cpim.h" +#include "address/address.h" +#include "chat/basic-chat-room.h" +#include "chat/chat-message.h" #include "liblinphone_tester.h" @@ -379,12 +382,29 @@ static void build_message () { BC_ASSERT_STRING_EQUAL(strMessage.c_str(), expectedMessage.c_str()); } -static void cpim_chat_message_modifier_encoder(void) { - -} +static void cpim_chat_message_modifier(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LpConfig *config = linphone_core_get_config(marie->lc); + lp_config_set_int(config, "sip", "use_cpim", 1); -static void cpim_chat_message_modifier_decoder(void) { + Address paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); + shared_ptr marieRoom = ObjectFactory::create(marie->lc, paulineAddress); + + shared_ptr marieMessage = marieRoom->createMessage("Hello CPIM"); + marieRoom->sendMessage(marieMessage); + + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageReceived,1)); + BC_ASSERT_TRUE(ContentType::isCpim(marieMessage->getInternalContent().getContentType().asString())); + BC_ASSERT_PTR_NOT_NULL(pauline->stat.last_received_chat_message); + if (pauline->stat.last_received_chat_message != NULL) { + BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(pauline->stat.last_received_chat_message), "Hello CPIM"); + BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_content_type(pauline->stat.last_received_chat_message), "text/plain"); + } + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); } test_t cpim_tests[] = { @@ -397,8 +417,7 @@ test_t cpim_tests[] = { TEST_NO_TAG("Parse RFC example", parse_rfc_example), TEST_NO_TAG("Parse Message with generic header parameters", parse_message_with_generic_header_parameters), TEST_NO_TAG("Build Message", build_message), - TEST_NO_TAG("CPIM chat message modifier encoder", cpim_chat_message_modifier_encoder), - TEST_NO_TAG("CPIM chat message modifier decoder", cpim_chat_message_modifier_decoder) + TEST_NO_TAG("CPIM chat message modifier", cpim_chat_message_modifier) }; test_suite_t cpim_test_suite = { From f9e89679b3ad73071a74020079945f04f7201243 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 4 Oct 2017 11:39:32 +0200 Subject: [PATCH 0313/2215] Added implementation of == operator on Content object + added logs and return values in CPIM Chat Message Modifier --- src/chat/modifier/cpim-chat-message-modifier.cpp | 12 ++++++++---- src/content/content.cpp | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index 8cac39ada..14fe313ab 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -22,6 +22,7 @@ #include "content/content-type.h" #include "content/content.h" #include "address/address.h" +#include "logger/logger.h" #include "chat/chat-message-p.h" // ============================================================================= @@ -60,7 +61,8 @@ int CpimChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { message.setContent(contentBody); if (!message.isValid()) { - //TODO + lError() << "[CPIM] Message is invalid: " << contentBody; + return 500; } else { Content newContent; ContentType newContentType("Message/CPIM"); @@ -80,7 +82,7 @@ int CpimChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { } ContentType contentType = content.getContentType(); - if (contentType.asString() == "Message/CPIM") { + if (ContentType::isCpim(contentType.asString())) { const vector body = content.getBody(); string contentBody(body.begin(), body.end()); shared_ptr message = Cpim::Message::createFromString(contentBody); @@ -91,10 +93,12 @@ int CpimChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { newContent.setBody(message->getContent()); messagePrivate->internalContent = newContent; } else { - //TODO + lError() << "[CPIM] Message is invalid: " << contentBody; + return 500; } } else { - //TODO + lError() << "[CPIM] Message is not CPIM but " << contentType.asString(); + return -1; } return 0; } diff --git a/src/content/content.cpp b/src/content/content.cpp index 25cf8dd91..de2ebb9fb 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -72,8 +72,8 @@ Content &Content::operator= (Content &&src) { } bool Content::operator==(const Content& content) { - // return true if the two are equal, and false otherwise. - return true; + L_D(); + return d->contentType == content.getContentType() && d->body == content.getBody() && d->contentDisposition == content.getContentDisposition(); } const ContentType &Content::getContentType () const { From ab1e07c8b702a93a7fd7d654bc61ccccd7ccfdc4 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 4 Oct 2017 11:42:47 +0200 Subject: [PATCH 0314/2215] fix build issues --- src/chat/chat-message.cpp | 2 +- src/content/content.cpp | 3 ++- src/content/content.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index fa4c931a7..822493530 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -1441,7 +1441,7 @@ void ChatMessage::cancelFileTransfer() { } if (!belle_http_request_is_cancelled(d->httpRequest)) { if (d->chatRoom) { - lInfo() << "Canceling file transfer " << (d->externalBodyUrl.empty()) ? linphone_core_get_file_transfer_server(d->chatRoom->getCore()) : d->externalBodyUrl.c_str(); + lInfo() << "Canceling file transfer " << (d->externalBodyUrl.empty() ? linphone_core_get_file_transfer_server(d->chatRoom->getCore()) : d->externalBodyUrl.c_str()); belle_http_provider_cancel_request(d->chatRoom->getCore()->http_provider, d->httpRequest); } else { lInfo() << "Warning: http request still running for ORPHAN msg: this is a memory leak"; diff --git a/src/content/content.cpp b/src/content/content.cpp index de2ebb9fb..c6e3c148f 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -71,7 +71,8 @@ Content &Content::operator= (Content &&src) { return *this; } -bool Content::operator==(const Content& content) { +<<<<<<< HEAD +bool Content::operator==(const Content& content) const { L_D(); return d->contentType == content.getContentType() && d->body == content.getBody() && d->contentDisposition == content.getContentDisposition(); } diff --git a/src/content/content.h b/src/content/content.h index c7f419223..f923c33d4 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -38,7 +38,7 @@ public: Content &operator= (const Content &src); Content &operator= (Content &&src); - bool operator==(const Content& content); + bool operator==(const Content& content) const; const ContentType &getContentType () const; void setContentType (const ContentType &contentType); From bb41aeb4deab9ceab72a5fbfe09d31e350ef2573 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 4 Oct 2017 11:48:17 +0200 Subject: [PATCH 0315/2215] remove <<<<contentType == content.getContentType() && d->body == content.getBody() && d->contentDisposition == content.getContentDisposition(); From 181d14d7748e9b3bfa139af9ba8c3018a01b1569 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 4 Oct 2017 11:49:51 +0200 Subject: [PATCH 0316/2215] implement redirect at sal level. --- coreapi/sal/sal.cpp | 5 ++++ coreapi/sal/sal_op.cpp | 40 +++++++++++++++++++++++++++++- coreapi/sal/sal_op.h | 5 ++-- tester/CMakeLists.txt | 2 +- tester/conference-event-tester.cpp | 2 +- tester/tester.c | 2 +- 6 files changed, 50 insertions(+), 6 deletions(-) diff --git a/coreapi/sal/sal.cpp b/coreapi/sal/sal.cpp index 520c2d6d8..2a2b64fc7 100644 --- a/coreapi/sal/sal.cpp +++ b/coreapi/sal/sal.cpp @@ -271,6 +271,11 @@ void Sal::process_response_event_cb(void *user_ctx, const belle_sip_response_eve case 403: if (op->auth_info) op->root->callbacks.auth_failure(op,op->auth_info); break; + case 302: + case 301: + if (op->process_redirect() == 0) + return; + break; } if (response_code >= 180 && response_code !=401 && response_code !=407 && response_code !=403) { /*not an auth request*/ diff --git a/coreapi/sal/sal_op.cpp b/coreapi/sal/sal_op.cpp index d3c26b8fd..40b2cdf26 100644 --- a/coreapi/sal/sal_op.cpp +++ b/coreapi/sal/sal_op.cpp @@ -96,7 +96,7 @@ SalOp::~SalOp() { sal_address_destroy(this->remote_contact_address); } if (this->call_id) - ms_free((void *)this->call_id); + ms_free(this->call_id); if (this->service_route) { sal_address_destroy(this->service_route); } @@ -371,6 +371,44 @@ void SalOp::resend_request(belle_sip_request_t* request) { send_request(request); } +int SalOp::process_redirect(){ + belle_sip_request_t* request = belle_sip_transaction_get_request((belle_sip_transaction_t*)this->pending_client_trans); + belle_sip_response_t *response = belle_sip_transaction_get_response((belle_sip_transaction_t*)this->pending_client_trans); + belle_sip_header_contact_t *redirect_contact = belle_sip_message_get_header_by_type((belle_sip_message_t*)response, belle_sip_header_contact_t); + belle_sip_uri_t *redirect_uri; + belle_sip_header_call_id_t *callid = belle_sip_message_get_header_by_type((belle_sip_message_t*)request, belle_sip_header_call_id_t); + belle_sip_header_to_t *to = belle_sip_message_get_header_by_type((belle_sip_message_t*)request, belle_sip_header_to_t); + + if (!redirect_contact){ + ms_warning("Redirect not handled, there is no redirect contact header in response"); + return -1; + } + + redirect_uri = belle_sip_header_address_get_uri((belle_sip_header_address_t*) redirect_contact); + + if (!redirect_uri){ + ms_warning("Redirect not handled, there is no usable uri in contact."); + return -1; + } + + if (this->dialog && belle_sip_dialog_get_state(this->dialog)==BELLE_SIP_DIALOG_CONFIRMED){ + ms_warning("Redirect not handled within established dialogs. Does it make sense ?"); + return -1; + } + set_or_update_dialog(NULL); + belle_sip_message_remove_header_from_ptr((belle_sip_message_t*)request, (belle_sip_header_t*)callid); + belle_sip_message_add_header((belle_sip_message_t*)request, (belle_sip_header_t*)(callid = belle_sip_provider_create_call_id(this->get_sal()->prov))); + if (this->call_id){ + /*reset the call-id of op, it will be set when new request will be sent*/ + ms_free(this->call_id); + this->call_id = NULL; + } + belle_sip_request_set_uri(request, redirect_uri); + belle_sip_header_address_set_uri((belle_sip_header_address_t*)to, redirect_uri); + send_request(request); + return 0; +} + void SalOp::process_authentication() { belle_sip_request_t* initial_request=belle_sip_transaction_get_request((belle_sip_transaction_t*)this->pending_auth_transaction); belle_sip_request_t* new_request; diff --git a/coreapi/sal/sal_op.h b/coreapi/sal/sal_op.h index 8ae42afe8..0c2f0431a 100644 --- a/coreapi/sal/sal_op.h +++ b/coreapi/sal/sal_op.h @@ -150,6 +150,7 @@ protected: virtual void fill_cbs() {} void release_impl(); void process_authentication(); + int process_redirect(); belle_sip_request_t* build_request(const char* method); int send_request(belle_sip_request_t* request); @@ -184,7 +185,7 @@ protected: bool_t is_secure() const; void add_headers(belle_sip_header_t *h, belle_sip_message_t *msg); void add_custom_headers(belle_sip_message_t *msg); - int unsubscribe(); + int unsubscribe(); void process_incoming_message(const belle_sip_request_event_t *event); int reply_message(SalReason reason); @@ -212,7 +213,7 @@ protected: SalAddress* remote_contact_address = NULL; char *remote_contact = NULL; void *user_pointer = NULL; - const char* call_id = NULL; + char* call_id = NULL; char* realm = NULL; SalAddress* service_route = NULL; /*as defined by rfc3608, might be a list*/ SalCustomHeader *sent_custom_headers = NULL; diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index cc9952668..cd5bba8c7 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -197,7 +197,7 @@ set(SOURCE_FILES_C set(SOURCE_FILES_CXX clonable-object-tester.cpp - conference-event-tester.cpp +# conference-event-tester.cpp conference-tester.cpp cpim-tester.cpp events-db-tester.cpp diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index 8dabe55a8..b88c7cb03 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -430,7 +430,7 @@ private: void onParticipantAdded (const Address &addr) override; void onParticipantRemoved (const Address &addr) override; void onParticipantSetAdmin (const Address &addr, bool isAdmin) override; - + void onSubjectChanged(const std::string &subject) override; public: RemoteConferenceEventHandler *handler; map participants; diff --git a/tester/tester.c b/tester/tester.c index 7829cb540..c5e58e042 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -563,7 +563,7 @@ void liblinphone_tester_add_suites() { bc_tester_add_suite(&account_creator_test_suite); bc_tester_add_suite(&stun_test_suite); bc_tester_add_suite(&event_test_suite); - bc_tester_add_suite(&conference_event_test_suite); + //bc_tester_add_suite(&conference_event_test_suite); bc_tester_add_suite(&conference_test_suite); bc_tester_add_suite(&flexisip_test_suite); bc_tester_add_suite(&remote_provisioning_test_suite); From 4eb16ce346c2347809382c8046d77b391ffdfa7d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 4 Oct 2017 14:18:53 +0200 Subject: [PATCH 0317/2215] Do not return a Participant in the addParticipant() method of the conference interface because the addition can be done asynchronously. --- include/linphone/api/c-chat-room.h | 3 +-- src/c-wrapper/api/c-chat-room.cpp | 6 ++---- src/call/call.cpp | 3 ++- src/chat/basic-chat-room.cpp | 3 +-- src/chat/basic-chat-room.h | 2 +- src/chat/client-group-chat-room.cpp | 8 ++++---- src/chat/client-group-chat-room.h | 2 +- src/chat/real-time-text-chat-room.cpp | 3 +-- src/chat/real-time-text-chat-room.h | 2 +- src/conference/conference-interface.h | 2 +- src/conference/conference.cpp | 3 +-- src/conference/conference.h | 2 +- src/conference/local-conference.cpp | 5 ++--- src/conference/local-conference.h | 2 +- src/conference/remote-conference.cpp | 5 ++--- src/conference/remote-conference.h | 2 +- 16 files changed, 23 insertions(+), 30 deletions(-) diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index d98c05de9..af54a32cf 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -242,9 +242,8 @@ LINPHONE_PUBLIC LinphoneChatRoomState linphone_chat_room_get_state (const Linpho * Use linphone_chat_room_can_handle_participants() to know if this chat room handles participants. * @param[in] cr A LinphoneChatRoom object * @param[in] addr The address of the participant to add to the chat room - * @return The newly added participant or NULL in case of failure */ -LINPHONE_PUBLIC LinphoneParticipant * linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr); +LINPHONE_PUBLIC void linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr); /** * Add several participants to a chat room at once. This may fail if this type of chat room does not handle participants. diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 816fbd7c2..8d5ea33b5 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -211,10 +211,8 @@ LinphoneChatRoomState linphone_chat_room_get_state (const LinphoneChatRoom *cr) return (LinphoneChatRoomState)L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getState(); } -LinphoneParticipant *linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr) { - return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->addParticipant( - *L_GET_CPP_PTR_FROM_C_OBJECT(addr), nullptr, false) - ); +void linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr) { + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->addParticipant(*L_GET_CPP_PTR_FROM_C_OBJECT(addr), nullptr, false); } void linphone_chat_room_add_participants (LinphoneChatRoom *cr, const bctbx_list_t *addresses) { diff --git a/src/call/call.cpp b/src/call/call.cpp index ba0f12951..85e9e92ba 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -231,7 +231,8 @@ Call::Call ( d->conference = new LocalConference(core, *myAddress, d); } const Address *remoteAddress = (direction == LinphoneCallIncoming) ? &from : &to; - shared_ptr participant = d->conference->addParticipant(*remoteAddress, msp, true); + d->conference->addParticipant(*remoteAddress, msp, true); + shared_ptr participant = d->conference->getParticipants().front(); participant->getPrivate()->getSession()->configure(direction, cfg, op, from, to); } diff --git a/src/chat/basic-chat-room.cpp b/src/chat/basic-chat-room.cpp index 949f02a39..94a30f7ae 100644 --- a/src/chat/basic-chat-room.cpp +++ b/src/chat/basic-chat-room.cpp @@ -35,9 +35,8 @@ BasicChatRoom::BasicChatRoom (LinphoneCore *core, const Address &peerAddress) : // ----------------------------------------------------------------------------- -shared_ptr BasicChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { +void BasicChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { lError() << "addParticipant() is not allowed on a BasicChatRoom"; - return nullptr; } void BasicChatRoom::addParticipants (const list
    &addresses, const CallSessionParams *params, bool hasMedia) { diff --git a/src/chat/basic-chat-room.h b/src/chat/basic-chat-room.h index b80a771de..eac039d58 100644 --- a/src/chat/basic-chat-room.h +++ b/src/chat/basic-chat-room.h @@ -33,7 +33,7 @@ public: virtual ~BasicChatRoom () = default; /* ConferenceInterface. */ - std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; + void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; bool canHandleParticipants () const override; const Address *getConferenceAddress () const override; diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 5b2246a5d..30753dbed 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -45,10 +45,10 @@ ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, // ----------------------------------------------------------------------------- -shared_ptr ClientGroupChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { - activeParticipant = ObjectFactory::create(addr); - activeParticipant->getPrivate()->createSession(*this, params, hasMedia, this); - return activeParticipant; +void ClientGroupChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { + list
    addresses; + addresses.push_back(addr); + addParticipants(addresses, params, hasMedia); } void ClientGroupChatRoom::addParticipants (const list
    &addresses, const CallSessionParams *params, bool hasMedia) { diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index 064cc27de..ff060bf0f 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -41,7 +41,7 @@ public: public: /* ConferenceInterface */ - std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; + void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; bool canHandleParticipants () const override; const Address *getConferenceAddress () const override; diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 321a0fe56..063887017 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -131,9 +131,8 @@ LinphoneCall *RealTimeTextChatRoom::getCall () const { // ----------------------------------------------------------------------------- -shared_ptr RealTimeTextChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { +void RealTimeTextChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { lError() << "addParticipant() is not allowed on a RealTimeTextChatRoom"; - return nullptr; } void RealTimeTextChatRoom::addParticipants (const list
    &addresses, const CallSessionParams *params, bool hasMedia) { diff --git a/src/chat/real-time-text-chat-room.h b/src/chat/real-time-text-chat-room.h index f9a7c077c..3f2dd2edf 100644 --- a/src/chat/real-time-text-chat-room.h +++ b/src/chat/real-time-text-chat-room.h @@ -43,7 +43,7 @@ public: LinphoneCall *getCall () const; /* ConferenceInterface */ - std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; + void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; bool canHandleParticipants () const override; const Address *getConferenceAddress () const override; diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index 1058ff8e6..43e711d68 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -34,7 +34,7 @@ class LINPHONE_PUBLIC ConferenceInterface { public: virtual ~ConferenceInterface() = default; - virtual std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) = 0; + virtual void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) = 0; virtual void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) = 0; virtual bool canHandleParticipants () const = 0; virtual const Address *getConferenceAddress () const = 0; diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 2ae674663..1496fa327 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -40,9 +40,8 @@ shared_ptr Conference::getActiveParticipant () const { // ----------------------------------------------------------------------------- -shared_ptr Conference::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { +void Conference::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { lError() << "Conference class does not handle addParticipant() generically"; - return nullptr; } void Conference::addParticipants (const list
    &addresses, const CallSessionParams *params, bool hasMedia) { diff --git a/src/conference/conference.h b/src/conference/conference.h index e83debbbe..fe4b2f80d 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -47,7 +47,7 @@ public: public: /* ConferenceInterface */ - std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; + void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; bool canHandleParticipants () const override; const Address *getConferenceAddress () const override; diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index baad5dda5..f4de96ccd 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -38,16 +38,15 @@ LocalConference::~LocalConference () { // ----------------------------------------------------------------------------- -shared_ptr LocalConference::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { +void LocalConference::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { shared_ptr participant = findParticipant(addr); if (participant) - return participant; + return; participant = ObjectFactory::create(addr); participant->getPrivate()->createSession(*this, params, hasMedia, this); participants.push_back(participant); if (!activeParticipant) activeParticipant = participant; - return participant; } void LocalConference::removeParticipant (const shared_ptr &participant) { diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h index c36bf9064..7e74992be 100644 --- a/src/conference/local-conference.h +++ b/src/conference/local-conference.h @@ -35,7 +35,7 @@ public: public: /* ConferenceInterface */ - std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; + void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void removeParticipant (const std::shared_ptr &participant) override; std::list
    parseResourceLists (std::string xmlBody); diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index d3e1b2f04..e2cafec44 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -39,16 +39,15 @@ RemoteConference::~RemoteConference () { // ----------------------------------------------------------------------------- -shared_ptr RemoteConference::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { +void RemoteConference::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { shared_ptr participant = findParticipant(addr); if (participant) - return participant; + return; participant = ObjectFactory::create(addr); participant->getPrivate()->createSession(*this, params, hasMedia, this); participants.push_back(participant); if (!activeParticipant) activeParticipant = participant; - return participant; } void RemoteConference::removeParticipant (const shared_ptr &participant) { diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index cf2956fed..5a31c119f 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -36,7 +36,7 @@ protected: public: /* ConferenceInterface */ - std::shared_ptr addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; + void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void removeParticipant (const std::shared_ptr &participant) override; std::string getResourceLists (const std::list
    &addresses); From eb21b8abeccff6038f625349c7a1517797ab61de Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 4 Oct 2017 14:23:19 +0200 Subject: [PATCH 0318/2215] Add a content parameter to the update() method of the call session. --- src/conference/session/call-session.cpp | 4 +++- src/conference/session/call-session.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index bf8e903ec..0a3db26cc 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -934,7 +934,7 @@ LinphoneStatus CallSession::terminate (const LinphoneErrorInfo *ei) { return 0; } -LinphoneStatus CallSession::update (const CallSessionParams *csp, const string &subject) { +LinphoneStatus CallSession::update (const CallSessionParams *csp, const string &subject, const Content *content) { L_D(); LinphoneCallState nextState; LinphoneCallState initialState = d->state; @@ -942,6 +942,8 @@ LinphoneStatus CallSession::update (const CallSessionParams *csp, const string & return -1; if (d->currentParams == csp) lWarning() << "CallSession::update() is given the current params, this is probably not what you intend to do!"; + if (content) + d->op->set_local_body(*content); LinphoneStatus result = d->startUpdate(subject); if (result && (d->state != initialState)) { /* Restore initial state */ diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index d53f8d26e..dd8e27f2f 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -56,7 +56,7 @@ public: virtual void startIncomingNotification (); virtual int startInvite (const Address *destination, const std::string &subject = "", const Content *content = nullptr); LinphoneStatus terminate (const LinphoneErrorInfo *ei = nullptr); - LinphoneStatus update (const CallSessionParams *csp, const std::string &subject = ""); + LinphoneStatus update (const CallSessionParams *csp, const std::string &subject = "", const Content *content = nullptr); CallSessionParams *getCurrentParams () const; LinphoneCallDir getDirection () const; From 6d11f76cc4599aedde62691be4afa6eee0c67399 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 4 Oct 2017 14:23:52 +0200 Subject: [PATCH 0319/2215] Clean the new To uri when creating the new INVITE after a redirection. --- coreapi/sal/sal_op.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/coreapi/sal/sal_op.cpp b/coreapi/sal/sal_op.cpp index 40b2cdf26..fe656cf4f 100644 --- a/coreapi/sal/sal_op.cpp +++ b/coreapi/sal/sal_op.cpp @@ -404,6 +404,9 @@ int SalOp::process_redirect(){ this->call_id = NULL; } belle_sip_request_set_uri(request, redirect_uri); + redirect_uri = BELLE_SIP_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(redirect_uri))); + belle_sip_uri_set_port(redirect_uri, 0); + belle_sip_uri_set_transport_param(redirect_uri, nullptr); belle_sip_header_address_set_uri((belle_sip_header_address_t*)to, redirect_uri); send_request(request); return 0; From fda31ecc0ee1008ff7ceff3c300ddaa3b7436127 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 4 Oct 2017 14:24:55 +0200 Subject: [PATCH 0320/2215] Create a call session automatically when needed in the client group chat room. --- src/address/address.h | 1 + src/chat/client-group-chat-room-p.h | 4 ++ src/chat/client-group-chat-room.cpp | 55 ++++++++++++++++++--------- src/conference/participant.h | 1 + src/conference/session/call-session.h | 1 + 5 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/address/address.h b/src/address/address.h index 86549e8f9..134f7601b 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -32,6 +32,7 @@ class LINPHONE_PUBLIC Address : public ClonableObject { // TODO: Remove me later. friend class CallSession; friend class ClientGroupChatRoom; + friend class ClientGroupChatRoomPrivate; public: Address (const std::string &address = ""); diff --git a/src/chat/client-group-chat-room-p.h b/src/chat/client-group-chat-room-p.h index 346faf869..416dd29b0 100644 --- a/src/chat/client-group-chat-room-p.h +++ b/src/chat/client-group-chat-room-p.h @@ -29,11 +29,15 @@ LINPHONE_BEGIN_NAMESPACE +class CallSession; + class ClientGroupChatRoomPrivate : public ChatRoomPrivate { public: ClientGroupChatRoomPrivate (LinphoneCore *core); virtual ~ClientGroupChatRoomPrivate () = default; + std::shared_ptr createSession (); + private: L_DECLARE_PUBLIC(ClientGroupChatRoom); }; diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 30753dbed..7afe7c70e 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -34,6 +34,21 @@ LINPHONE_BEGIN_NAMESPACE ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core) : ChatRoomPrivate(core) {} +// ----------------------------------------------------------------------------- + +shared_ptr ClientGroupChatRoomPrivate::createSession () { + L_Q(); + CallSessionParams csp; + csp.addCustomHeader("Require", "recipient-list-invite"); + shared_ptr session = q->focus->getPrivate()->createSession(*q, &csp, false, q); + session->configure(LinphoneCallOutgoing, nullptr, nullptr, q->me->getAddress(), q->focus->getAddress()); + session->initiateOutgoing(); + Address addr = q->me->getAddress(); + addr.setParam("text"); + session->getPrivate()->getOp()->set_contact_address(addr.getPrivate()->getInternalAddress()); + return session; +} + // ============================================================================= ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, const string &subject) @@ -55,28 +70,27 @@ void ClientGroupChatRoom::addParticipants (const list
    &addresses, const L_D(); if (addresses.empty()) return; + if ((d->state != ChatRoom::State::Instantiated) && (d->state != ChatRoom::State::Created)) { + lError() << "Cannot add participants to the ClientGroupChatRoom in a state other than Instantiated or Created"; + return; + } list
    sortedAddresses(addresses); sortedAddresses.sort(); sortedAddresses.unique(); - if (d->state == ChatRoom::State::Instantiated) { - Content content; - content.setBody(getResourceLists(sortedAddresses)); - content.setContentType("application/resource-lists+xml"); - content.setContentDisposition("recipient-list"); - CallSessionParams csp; - if (params) - csp = *params; - csp.addCustomHeader("Require", "recipient-list-invite"); - shared_ptr session = focus->getPrivate()->createSession(*this, &csp, false, this); - session->configure(LinphoneCallOutgoing, nullptr, nullptr, me->getAddress(), focus->getAddress()); - session->initiateOutgoing(); - Address addr = me->getAddress(); - addr.setParam("text"); - session->getPrivate()->getOp()->set_contact_address(addr.getPrivate()->getInternalAddress()); + Content content; + content.setBody(getResourceLists(sortedAddresses)); + content.setContentType("application/resource-lists+xml"); + content.setContentDisposition("recipient-list"); + shared_ptr session = focus->getPrivate()->getSession(); + if (session) + session->update(nullptr, subject, &content); + else { + session = d->createSession(); session->startInvite(nullptr, subject, &content); - d->setState(ChatRoom::State::CreationPending); + if (d->state == ChatRoom::State::Instantiated) { + d->setState(ChatRoom::State::CreationPending); + } } - // TODO } bool ClientGroupChatRoom::canHandleParticipants () const { @@ -118,7 +132,12 @@ void ClientGroupChatRoom::setSubject (const string &subject) { return; } shared_ptr session = focus->getPrivate()->getSession(); - session->update(nullptr, subject); + if (session) + session->update(nullptr, subject); + else { + session = d->createSession(); + session->startInvite(nullptr, subject, nullptr); + } } // ----------------------------------------------------------------------------- diff --git a/src/conference/participant.h b/src/conference/participant.h index 0fbef9f00..37cbb24a1 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -35,6 +35,7 @@ class Participant : public Object { friend class Call; friend class CallPrivate; friend class ClientGroupChatRoom; + friend class ClientGroupChatRoomPrivate; friend class LocalConference; friend class MediaSessionPrivate; friend class RemoteConference; diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index dd8e27f2f..d09435a92 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -37,6 +37,7 @@ class Content; class LINPHONE_PUBLIC CallSession : public Object { friend class CallPrivate; friend class ClientGroupChatRoom; + friend class ClientGroupChatRoomPrivate; public: L_OVERRIDE_SHARED_FROM_THIS(CallSession); From 34318366b6d86767bc7b8dce06ee6304975bb3bf Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 4 Oct 2017 14:59:45 +0200 Subject: [PATCH 0321/2215] CallSession objects need to be handle by shared_ptr. --- src/chat/client-group-chat-room.cpp | 16 +++++++++--- src/chat/client-group-chat-room.h | 5 ++-- src/conference/conference.cpp | 26 +++++++++---------- src/conference/conference.h | 26 +++++++++---------- src/conference/participant-p.h | 1 + .../session/call-session-listener.h | 26 +++++++++---------- src/conference/session/call-session.cpp | 18 ++++++------- src/conference/session/media-session.cpp | 14 +++++----- 8 files changed, 72 insertions(+), 60 deletions(-) diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 7afe7c70e..6cb6e9b0a 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -58,6 +58,11 @@ ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, this->subject = subject; } +ClientGroupChatRoom::~ClientGroupChatRoom () { + shared_ptr session = focus->getPrivate()->getSession(); + session->terminate(); +} + // ----------------------------------------------------------------------------- void ClientGroupChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { @@ -213,12 +218,17 @@ void ClientGroupChatRoom::onSubjectChanged (const std::string &subject) { // ----------------------------------------------------------------------------- -void ClientGroupChatRoom::onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const string &message) { +void ClientGroupChatRoom::onCallSessionSetTerminated (const std::shared_ptr session) { + if (session == focus->getPrivate()->getSession()) + focus->getPrivate()->removeSession(); +} + +void ClientGroupChatRoom::onCallSessionStateChanged (const std::shared_ptr session, LinphoneCallState state, const string &message) { if (state == LinphoneCallConnected) { - Address addr(session.getRemoteContact()); + Address addr(session->getRemoteContact()); addr.clean(); onConferenceCreated(addr); - if (session.getRemoteContactAddress()->hasParam("isfocus")) + if (session->getRemoteContactAddress()->hasParam("isfocus")) eventHandler->subscribe(conferenceAddress); } } diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index ff060bf0f..7a12fd0f3 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -37,7 +37,7 @@ class ClientGroupChatRoomPrivate; class LINPHONE_PUBLIC ClientGroupChatRoom : public ChatRoom, public RemoteConference { public: ClientGroupChatRoom (LinphoneCore *core, const Address &me, const std::string &subject); - virtual ~ClientGroupChatRoom () = default; + virtual ~ClientGroupChatRoom (); public: /* ConferenceInterface */ @@ -63,7 +63,8 @@ private: private: /* CallSessionListener */ - void onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message) override; + void onCallSessionSetTerminated (const std::shared_ptr session) override; + void onCallSessionStateChanged (const std::shared_ptr session, LinphoneCallState state, const std::string &message) override; private: L_DECLARE_PRIVATE(ClientGroupChatRoom); diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 1496fa327..95ff53e24 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -84,47 +84,47 @@ void Conference::setSubject (const string &subject) { // ----------------------------------------------------------------------------- -void Conference::onAckBeingSent (const CallSession &session, LinphoneHeaders *headers) { +void Conference::onAckBeingSent (const std::shared_ptr session, LinphoneHeaders *headers) { if (callListener) callListener->onAckBeingSent(headers); } -void Conference::onAckReceived (const CallSession &session, LinphoneHeaders *headers) { +void Conference::onAckReceived (const std::shared_ptr session, LinphoneHeaders *headers) { if (callListener) callListener->onAckReceived(headers); } -void Conference::onCallSessionAccepted (const CallSession &session) { +void Conference::onCallSessionAccepted (const std::shared_ptr session) { if (callListener) callListener->onIncomingCallToBeAdded(); } -void Conference::onCallSessionSetReleased (const CallSession &session) { +void Conference::onCallSessionSetReleased (const std::shared_ptr session) { if (callListener) callListener->onCallSetReleased(); } -void Conference::onCallSessionSetTerminated (const CallSession &session) { +void Conference::onCallSessionSetTerminated (const std::shared_ptr session) { if (callListener) callListener->onCallSetTerminated(); } -void Conference::onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const string &message) { +void Conference::onCallSessionStateChanged (const std::shared_ptr session, LinphoneCallState state, const string &message) { if (callListener) callListener->onCallStateChanged(state, message); } -void Conference::onCheckForAcceptation (const CallSession &session) { +void Conference::onCheckForAcceptation (const std::shared_ptr session) { if (callListener) callListener->onCheckForAcceptation(); } -void Conference::onIncomingCallSessionStarted (const CallSession &session) { +void Conference::onIncomingCallSessionStarted (const std::shared_ptr session) { if (callListener) callListener->onIncomingCallStarted(); } -void Conference::onEncryptionChanged (const CallSession &session, bool activated, const string &authToken) { +void Conference::onEncryptionChanged (const std::shared_ptr session, bool activated, const string &authToken) { if (callListener) callListener->onEncryptionChanged(activated, authToken); } @@ -134,22 +134,22 @@ void Conference::onStatsUpdated (const LinphoneCallStats *stats) { callListener->onStatsUpdated(stats); } -void Conference::onResetCurrentSession (const CallSession &session) { +void Conference::onResetCurrentSession (const std::shared_ptr session) { if (callListener) callListener->onResetCurrentCall(); } -void Conference::onSetCurrentSession (const CallSession &session) { +void Conference::onSetCurrentSession (const std::shared_ptr session) { if (callListener) callListener->onSetCurrentCall(); } -void Conference::onFirstVideoFrameDecoded (const CallSession &session) { +void Conference::onFirstVideoFrameDecoded (const std::shared_ptr session) { if (callListener) callListener->onFirstVideoFrameDecoded(); } -void Conference::onResetFirstVideoFrameDecoded (const CallSession &session) { +void Conference::onResetFirstVideoFrameDecoded (const std::shared_ptr session) { if (callListener) callListener->onResetFirstVideoFrameDecoded(); } diff --git a/src/conference/conference.h b/src/conference/conference.h index fe4b2f80d..213b4ef3d 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -60,20 +60,20 @@ public: private: /* CallSessionListener */ - void onAckBeingSent (const CallSession &session, LinphoneHeaders *headers) override; - void onAckReceived (const CallSession &session, LinphoneHeaders *headers) override; - void onCallSessionAccepted (const CallSession &session) override; - void onCallSessionSetReleased (const CallSession &session) override; - void onCallSessionSetTerminated (const CallSession &session) override; - void onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message) override; - void onCheckForAcceptation (const CallSession &session) override; - void onIncomingCallSessionStarted (const CallSession &session) override; - void onEncryptionChanged (const CallSession &session, bool activated, const std::string &authToken) override; + void onAckBeingSent (const std::shared_ptr session, LinphoneHeaders *headers) override; + void onAckReceived (const std::shared_ptr session, LinphoneHeaders *headers) override; + void onCallSessionAccepted (const std::shared_ptr session) override; + void onCallSessionSetReleased (const std::shared_ptr session) override; + void onCallSessionSetTerminated (const std::shared_ptr session) override; + void onCallSessionStateChanged (const std::shared_ptr session, LinphoneCallState state, const std::string &message) override; + void onCheckForAcceptation (const std::shared_ptr session) override; + void onIncomingCallSessionStarted (const std::shared_ptr session) override; + void onEncryptionChanged (const std::shared_ptr session, bool activated, const std::string &authToken) override; void onStatsUpdated (const LinphoneCallStats *stats) override; - void onResetCurrentSession (const CallSession &session) override; - void onSetCurrentSession (const CallSession &session) override; - void onFirstVideoFrameDecoded (const CallSession &session) override; - void onResetFirstVideoFrameDecoded (const CallSession &session) override; + void onResetCurrentSession (const std::shared_ptr session) override; + void onSetCurrentSession (const std::shared_ptr session) override; + void onFirstVideoFrameDecoded (const std::shared_ptr session) override; + void onResetFirstVideoFrameDecoded (const std::shared_ptr session) override; protected: explicit Conference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); diff --git a/src/conference/participant-p.h b/src/conference/participant-p.h index 58d522a34..6c7cb5ea7 100644 --- a/src/conference/participant-p.h +++ b/src/conference/participant-p.h @@ -40,6 +40,7 @@ public: std::shared_ptr createSession (const Conference &conference, const CallSessionParams *params, bool hasMedia, CallSessionListener *listener); std::shared_ptr getSession () const { return session; } + void removeSession () { session = nullptr; } void setAddress (const Address &newAddr) { addr = newAddr; } private: diff --git a/src/conference/session/call-session-listener.h b/src/conference/session/call-session-listener.h index cae85a71e..60aa2c2ab 100644 --- a/src/conference/session/call-session-listener.h +++ b/src/conference/session/call-session-listener.h @@ -27,24 +27,24 @@ class LINPHONE_PUBLIC CallSessionListener { public: virtual ~CallSessionListener() = default; - virtual void onAckBeingSent (const CallSession &session, LinphoneHeaders *headers) = 0; - virtual void onAckReceived (const CallSession &session, LinphoneHeaders *headers) = 0; - virtual void onCallSessionAccepted (const CallSession &session) = 0; - virtual void onCallSessionSetReleased (const CallSession &session) = 0; - virtual void onCallSessionSetTerminated (const CallSession &session) = 0; - virtual void onCallSessionStateChanged (const CallSession &session, LinphoneCallState state, const std::string &message) = 0; - virtual void onCheckForAcceptation (const CallSession &session) = 0; - virtual void onIncomingCallSessionStarted (const CallSession &session) = 0; + virtual void onAckBeingSent (const std::shared_ptr session, LinphoneHeaders *headers) = 0; + virtual void onAckReceived (const std::shared_ptr session, LinphoneHeaders *headers) = 0; + virtual void onCallSessionAccepted (const std::shared_ptr session) = 0; + virtual void onCallSessionSetReleased (const std::shared_ptr session) = 0; + virtual void onCallSessionSetTerminated (const std::shared_ptr session) = 0; + virtual void onCallSessionStateChanged (const std::shared_ptr session, LinphoneCallState state, const std::string &message) = 0; + virtual void onCheckForAcceptation (const std::shared_ptr session) = 0; + virtual void onIncomingCallSessionStarted (const std::shared_ptr session) = 0; - virtual void onEncryptionChanged (const CallSession &session, bool activated, const std::string &authToken) = 0; + virtual void onEncryptionChanged (const std::shared_ptr session, bool activated, const std::string &authToken) = 0; virtual void onStatsUpdated (const LinphoneCallStats *stats) = 0; - virtual void onResetCurrentSession (const CallSession &session) = 0; - virtual void onSetCurrentSession (const CallSession &session) = 0; + virtual void onResetCurrentSession (const std::shared_ptr session) = 0; + virtual void onSetCurrentSession (const std::shared_ptr session) = 0; - virtual void onFirstVideoFrameDecoded (const CallSession &session) = 0; - virtual void onResetFirstVideoFrameDecoded (const CallSession &session) = 0; + virtual void onFirstVideoFrameDecoded (const std::shared_ptr session) = 0; + virtual void onResetFirstVideoFrameDecoded (const std::shared_ptr session) = 0; }; LINPHONE_END_NAMESPACE diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 0a3db26cc..562cb9420 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -174,7 +174,7 @@ void CallSessionPrivate::setState(LinphoneCallState newState, const string &mess linphone_call_state_to_string(prevState) << " to " << linphone_call_state_to_string(state) << ")"; } if (listener) - listener->onCallSessionStateChanged(*q, state, message); + listener->onCallSessionStateChanged(q->getSharedFromThis(), state, message); if (newState == LinphoneCallReleased) setReleased(); /* Shall be performed after app notification */ } @@ -231,13 +231,13 @@ void CallSessionPrivate::accepted () { void CallSessionPrivate::ackBeingSent (LinphoneHeaders *headers) { L_Q(); if (listener) - listener->onAckBeingSent(*q, headers); + listener->onAckBeingSent(q->getSharedFromThis(), headers); } void CallSessionPrivate::ackReceived (LinphoneHeaders *headers) { L_Q(); if (listener) - listener->onAckReceived(*q, headers); + listener->onAckReceived(q->getSharedFromThis(), headers); } bool CallSessionPrivate::failure () { @@ -431,7 +431,7 @@ void CallSessionPrivate::accept (const CallSessionParams *params) { op->accept(); if (listener) - listener->onSetCurrentSession(*q); + listener->onSetCurrentSession(q->getSharedFromThis()); setState(LinphoneCallConnected, "Connected"); } @@ -450,7 +450,7 @@ LinphoneStatus CallSessionPrivate::checkForAcceptation () const { return -1; } if (listener) - listener->onCheckForAcceptation(*q); + listener->onCheckForAcceptation(q->getSharedFromThis()); /* Check if this call is supposed to replace an already running one */ SalOp *replaced = op->get_replaces(); @@ -547,7 +547,7 @@ void CallSessionPrivate::setReleased () { } #endif if (listener) - listener->onCallSessionSetReleased(*q); + listener->onCallSessionSetReleased(q->getSharedFromThis()); } /* This method is called internally to get rid of a call that was notified to the application, @@ -559,7 +559,7 @@ void CallSessionPrivate::setTerminated() { L_Q(); completeLog(); if (listener) - listener->onCallSessionSetTerminated(*q); + listener->onCallSessionSetTerminated(q->getSharedFromThis()); } LinphoneStatus CallSessionPrivate::startAcceptUpdate (LinphoneCallState nextState, const std::string &stateInfo) { @@ -837,7 +837,7 @@ LinphoneStatus CallSession::redirect (const Address &redirectAddr) { void CallSession::startIncomingNotification () { L_D(); if (d->listener) - d->listener->onCallSessionAccepted(*this); + d->listener->onCallSessionAccepted(getSharedFromThis()); /* Prevent the CallSession from being destroyed while we are notifying, if the user declines within the state callback */ shared_ptr ref = getSharedFromThis(); #if 0 @@ -849,7 +849,7 @@ void CallSession::startIncomingNotification () { } if (d->listener) - d->listener->onIncomingCallSessionStarted(*this); + d->listener->onIncomingCallSessionStarted(getSharedFromThis()); d->setState(LinphoneCallIncomingReceived, "Incoming CallSession"); diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index c56921792..09c4b89cf 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -164,7 +164,7 @@ void MediaSessionPrivate::accepted () { nextStateMsg = "Call paused by remote"; } else { if (!params->getPrivate()->getInConference() && listener) - listener->onSetCurrentSession(*q); + listener->onSetCurrentSession(q->getSharedFromThis()); nextState = LinphoneCallStreamsRunning; nextStateMsg = "Streams running"; } @@ -2921,7 +2921,7 @@ void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { } ms_media_stream_sessions_set_encryption_mandatory(&videoStream->ms.sessions, isEncryptionMandatory()); if (listener) - listener->onResetFirstVideoFrameDecoded(*q); + listener->onResetFirstVideoFrameDecoded(q->getSharedFromThis()); /* Start ZRTP engine if needed : set here or remote have a zrtp-hash attribute */ SalMediaDescription *remote = op->get_remote_media_description(); const SalStreamDescription *remoteStream = sal_media_description_find_best_stream(remote, SalVideo); @@ -3344,7 +3344,7 @@ void MediaSessionPrivate::propagateEncryptionChanged () { lInfo() << "Some streams are not encrypted"; q->getCurrentParams()->setMediaEncryption(LinphoneMediaEncryptionNone); if (listener) - listener->onEncryptionChanged(*q, false, authToken); + listener->onEncryptionChanged(q->getSharedFromThis(), false, authToken); } else { if (!authToken.empty()) { /* ZRTP only is using auth_token */ @@ -3357,7 +3357,7 @@ void MediaSessionPrivate::propagateEncryptionChanged () { << ((q->getCurrentParams()->getMediaEncryption() == LinphoneMediaEncryptionZRTP) ? "ZRTP" : (q->getCurrentParams()->getMediaEncryption() == LinphoneMediaEncryptionDTLS) ? "DTLS" : "Unknown mechanism"); if (listener) - listener->onEncryptionChanged(*q, true, authToken); + listener->onEncryptionChanged(q->getSharedFromThis(), true, authToken); #ifdef VIDEO_ENABLED if (isEncryptionMandatory() && videoStream && media_stream_started(&videoStream->ms)) { /* Nothing could have been sent yet so generating key frame */ @@ -3671,7 +3671,7 @@ LinphoneStatus MediaSessionPrivate::pause () { op->set_local_media_description(localDesc); op->update(subject.c_str(), false); if (listener) - listener->onResetCurrentSession(*q); + listener->onResetCurrentSession(q->getSharedFromThis()); if (audioStream || videoStream || textStream) stopStreams(); pausedByApp = false; @@ -3932,7 +3932,7 @@ void MediaSessionPrivate::videoStreamEventCb (const MSFilter *f, const unsigned case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED: lInfo() << "First video frame decoded successfully"; if (listener) - listener->onFirstVideoFrameDecoded(*q); + listener->onFirstVideoFrameDecoded(q->getSharedFromThis()); break; case MS_VIDEO_DECODER_SEND_PLI: case MS_VIDEO_DECODER_SEND_SLI: @@ -4200,7 +4200,7 @@ LinphoneStatus MediaSession::resume () { return -1; d->setState(LinphoneCallResuming,"Resuming"); if (!d->params->getPrivate()->getInConference() && d->listener) - d->listener->onSetCurrentSession(*this); + d->listener->onSetCurrentSession(getSharedFromThis()); if (d->core->sip_conf.sdp_200_ack) { /* We are NOT offering, set local media description after sending the call so that we are ready to * process the remote offer when it will arrive. */ From e8e1e130f3a6cee6a78362df06da6414e6a0457c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 4 Oct 2017 17:11:58 +0200 Subject: [PATCH 0322/2215] Improve handling of content types. --- coreapi/sal/call_op.cpp | 17 ++--- src/c-wrapper/api/c-chat-message.cpp | 8 +-- src/chat/chat-message-p.h | 12 ++-- src/chat/chat-message.cpp | 32 +++++----- src/chat/chat-room.cpp | 12 ++-- .../modifier/cpim-chat-message-modifier.cpp | 5 +- src/content/content-type.cpp | 62 +++++-------------- src/content/content-type.h | 24 +++---- tester/cpim-tester.cpp | 2 +- 9 files changed, 72 insertions(+), 102 deletions(-) diff --git a/coreapi/sal/call_op.cpp b/coreapi/sal/call_op.cpp index 6c3b50ba6..c55139d5a 100644 --- a/coreapi/sal/call_op.cpp +++ b/coreapi/sal/call_op.cpp @@ -21,7 +21,7 @@ int SalCallOp::set_local_media_description(SalMediaDescription *desc) { vector buffer = marshal_media_description(sdp, error); if (error != BELLE_SIP_OK) return -1; - this->local_body.setContentType("application/sdp"); + this->local_body.setContentType(ContentType::Sdp); this->local_body.setBody(move(buffer)); if (this->local_media) sal_media_description_unref(this->local_media); @@ -47,7 +47,7 @@ int SalCallOp::set_local_body(const Content &body) { int SalCallOp::set_local_body(const Content &&body) { if (!body.isValid()) return -1; - if (body.getContentType() == "application/sdp") { + if (body.getContentType() == ContentType::Sdp) { SalMediaDescription *desc = NULL; if (body.getSize() > 0) { belle_sdp_session_description_t *sdp = belle_sdp_session_description_parse(body.getBodyAsString().c_str()); @@ -139,7 +139,7 @@ int SalCallOp::set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* if (error != BELLE_SIP_OK) return -1; Content body; - body.setContentType("application/sdp"); + body.setContentType(ContentType::Sdp); body.setBody(move(buff)); set_custom_body(msg, body); @@ -161,7 +161,7 @@ void SalCallOp::fill_invite(belle_sip_request_t* invite) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Session-expires", "600;refresher=uas")); belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Supported", "timer")); } - this->sdp_offering = (this->local_body.getContentType() == "application/sdp"); + this->sdp_offering = (this->local_body.getContentType() == ContentType::Sdp); set_custom_body(BELLE_SIP_MESSAGE(invite), this->local_body); } @@ -204,6 +204,7 @@ void SalCallOp::cancelling_invite(const SalErrorInfo *info) { Content SalCallOp::extract_body(belle_sip_message_t *message) { Content body; belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(message, belle_sip_header_content_type_t); + belle_sip_header_content_disposition_t *contentDisposition = belle_sip_message_get_header_by_type(message, belle_sip_header_content_disposition_t); belle_sip_header_content_length_t *content_length = belle_sip_message_get_header_by_type(message, belle_sip_header_content_length_t); const char *type_str = content_type ? belle_sip_header_content_type_get_type(content_type) : NULL; const char *subtype_str = content_type ? belle_sip_header_content_type_get_subtype(content_type) : NULL; @@ -211,6 +212,8 @@ Content SalCallOp::extract_body(belle_sip_message_t *message) { const char *body_str = belle_sip_message_get_body(message); if (type_str && subtype_str) body.setContentType(ContentType(type_str, subtype_str)); + if (contentDisposition) + body.setContentDisposition(belle_sip_header_content_disposition_get_content_disposition(contentDisposition)); if (length > 0 && body_str) body.setBody(body_str, length); return body; } @@ -311,7 +314,7 @@ void SalCallOp::handle_body_from_response(belle_sip_response_t* response) { sal_media_description_unref(this->remote_media); this->remote_media=NULL; } - if (body.getContentType() == "application/sdp") { + if (body.getContentType() == ContentType::Sdp) { if (parse_sdp_body(body, &sdp, &reason) == 0) { if (sdp) { this->remote_media = sal_media_description_new(); @@ -543,7 +546,7 @@ SalReason SalCallOp::process_body_for_invite(belle_sip_request_t* invite) { Content body = extract_body(BELLE_SIP_MESSAGE(invite)); if (!body.isValid()) return SalReasonUnsupportedContent; - if (body.getContentType() == "application/sdp") { + if (body.getContentType() == ContentType::Sdp) { belle_sdp_session_description_t* sdp; if (parse_sdp_body(body, &sdp, &reason) == 0) { if (sdp) { @@ -574,7 +577,7 @@ SalReason SalCallOp::process_body_for_ack(belle_sip_request_t *ack) { SalReason reason = SalReasonNone; Content body = extract_body(BELLE_SIP_MESSAGE(ack)); if (!body.isValid()) return SalReasonUnsupportedContent; - if (body.getContentType() == "application/sdp") { + if (body.getContentType() == ContentType::Sdp) { belle_sdp_session_description_t *sdp; if (parse_sdp_body(body, &sdp, &reason) == 0) { if (sdp) { diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index d8393484a..92d6cec9a 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -318,11 +318,11 @@ void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChat // ============================================================================= const char * linphone_chat_message_get_content_type(LinphoneChatMessage *msg) { - return L_STRING_TO_C(L_GET_PRIVATE_FROM_C_OBJECT(msg)->getContentType()); + return L_STRING_TO_C(L_GET_PRIVATE_FROM_C_OBJECT(msg)->getContentType().asString()); } void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char *content_type) { - L_GET_PRIVATE_FROM_C_OBJECT(msg)->setContentType(L_C_TO_STRING(content_type)); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setContentType(ContentType(L_C_TO_STRING(content_type))); } const char *linphone_chat_message_get_text(LinphoneChatMessage *msg) { @@ -362,11 +362,11 @@ LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage *msg) { } bool_t linphone_chat_message_is_file_transfer(LinphoneChatMessage *msg) { - return LinphonePrivate::ContentType::isFileTransfer(linphone_chat_message_get_content_type(msg)); + return LinphonePrivate::ContentType(linphone_chat_message_get_content_type(msg)) == LinphonePrivate::ContentType::FileTransfer; } bool_t linphone_chat_message_is_text(LinphoneChatMessage *msg) { - return LinphonePrivate::ContentType::isText(linphone_chat_message_get_content_type(msg)); + return LinphonePrivate::ContentType(linphone_chat_message_get_content_type(msg)) == LinphonePrivate::ContentType::PlainText; } const char *linphone_chat_message_state_to_string(const LinphoneChatMessageState state) { diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index f931f421a..bd5b5cbe7 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -68,13 +68,13 @@ public: // Methods only used for C wrapper // ----------------------------------------------------------------------------- - const std::string& getContentType(); - void setContentType(const std::string& contentType); + const ContentType &getContentType(); + void setContentType(const ContentType &contentType); - const std::string& getText(); - void setText(const std::string& text); + const std::string &getText(); + void setText(const std::string &text); - LinphoneContent * getFileTransferInformation() const; + LinphoneContent *getFileTransferInformation() const; void setFileTransferInformation(LinphoneContent *content); // ----------------------------------------------------------------------------- @@ -128,7 +128,7 @@ private: SalCustomHeader *salCustomHeaders = NULL; unsigned long backgroundTaskId; // Cache for returned values, used for compatibility with previous C API - std::string cContentType = ""; + ContentType cContentType; std::string cText = ""; // Used for compatibility with previous C API LinphoneContent *cFileTransferInformation = NULL; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 822493530..dc543a760 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -139,19 +139,19 @@ string ChatMessagePrivate::getSalCustomHeaderValue(const string& name) { // ----------------------------------------------------------------------------- -const string& ChatMessagePrivate::getContentType() { - if (!internalContent.getContentType().asString().empty()) { - cContentType = internalContent.getContentType().asString(); +const ContentType& ChatMessagePrivate::getContentType() { + if (internalContent.getContentType().isValid()) { + cContentType = internalContent.getContentType(); } else { if (contents.size() > 0) { Content content = contents.front(); - cContentType = content.getContentType().asString(); + cContentType = content.getContentType(); } } return cContentType; } -void ChatMessagePrivate::setContentType(const string& contentType) { +void ChatMessagePrivate::setContentType(const ContentType &contentType) { internalContent.setContentType(contentType); } @@ -681,7 +681,7 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e } else { // no encryption key, transfer in plain, just copy the msg sent by server setText(body); } - setContentType("application/vnd.gsma.rcs-ft-http+xml"); + setContentType(ContentType::FileTransfer); q->updateState(ChatMessage::State::FileTransferDone); releaseHttpRequest(); send(); @@ -977,7 +977,7 @@ LinphoneReason ChatMessagePrivate::receive() { // Start of message modification // --------------------------------------- - if (ContentType::isCpim(getContentType())) { + if (getContentType() == ContentType::Cpim) { CpimChatMessageModifier ccmm; ccmm.decode(this); } @@ -1000,9 +1000,9 @@ LinphoneReason ChatMessagePrivate::receive() { // End of message modification // --------------------------------------- - if ((retval <= 0) && (linphone_core_is_content_type_supported(chatRoom->getCore(), getContentType().c_str()) == FALSE)) { + if ((retval <= 0) && (linphone_core_is_content_type_supported(chatRoom->getCore(), getContentType().asString().c_str()) == FALSE)) { retval = 415; - lError() << "Unsupported MESSAGE (content-type " << getContentType() << " not recognized)"; + lError() << "Unsupported MESSAGE (content-type " << getContentType().asString() << " not recognized)"; } if (retval > 0) { @@ -1011,10 +1011,10 @@ LinphoneReason ChatMessagePrivate::receive() { return reason; } - if (ContentType::isFileTransfer(getContentType())) { + if (getContentType() == ContentType::FileTransfer) { createFileTransferInformationsFromVndGsmaRcsFtHttpXml(); store = true; - } else if (ContentType::isText(getContentType())) { + } else if (getContentType() == ContentType::PlainText) { store = true; } @@ -1071,12 +1071,12 @@ void ChatMessagePrivate::send() { // --------------------------------------- string clearTextMessage; - string clearTextContentType; + ContentType clearTextContentType; if (!getText().empty()) { clearTextMessage = getText().c_str(); } - if (!getContentType().empty()) { + if (getContentType().isValid()) { clearTextContentType = getContentType(); } @@ -1110,8 +1110,8 @@ void ChatMessagePrivate::send() { ms_free(content_type); } else { auto msgOp = dynamic_cast(op); - if (!getContentType().empty()) { - msgOp->send_message(from.asString().c_str(), chatRoom->getPeerAddress().asString().c_str(), getContentType().c_str(), getText().c_str(), chatRoom->getPeerAddress().asStringUriOnly().c_str()); + if (getContentType().isValid()) { + msgOp->send_message(from.asString().c_str(), chatRoom->getPeerAddress().asString().c_str(), getContentType().asString().c_str(), getText().c_str(), chatRoom->getPeerAddress().asStringUriOnly().c_str()); } else { msgOp->send_message(from.asString().c_str(), chatRoom->getPeerAddress().asString().c_str(), getText().c_str()); } @@ -1121,7 +1121,7 @@ void ChatMessagePrivate::send() { /* We replace the encrypted message by the original one so it can be correctly stored and displayed by the application */ setText(clearTextMessage); } - if (!getContentType().empty() && getContentType() == clearTextContentType) { + if (getContentType().isValid() && (getContentType() == clearTextContentType)) { /* We replace the encrypted content type by the original one */ setContentType(clearTextContentType); } diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 5e3e12100..4c47f02a4 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -137,7 +137,7 @@ void ChatRoomPrivate::sendImdn (const string &payload, LinphoneReason reason) { } if (retval <= 0) { - op->send_message(identity, peerAddress.asString().c_str(), msg->getPrivate()->getContentType().c_str(), msg->getPrivate()->getText().c_str(), nullptr); + op->send_message(identity, peerAddress.asString().c_str(), msg->getPrivate()->getContentType().asString().c_str(), msg->getPrivate()->getText().c_str(), nullptr); } linphone_address_unref(peer); @@ -227,7 +227,7 @@ void ChatRoomPrivate::sendIsComposingNotification () { } if (retval <= 0) { - op->send_message(identity, peerAddress.asString().c_str(), msg->getPrivate()->getContentType().c_str(), msg->getPrivate()->getText().c_str(), nullptr); + op->send_message(identity, peerAddress.asString().c_str(), msg->getPrivate()->getContentType().asString().c_str(), msg->getPrivate()->getText().c_str(), nullptr); } op->unref(); } @@ -424,13 +424,13 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa goto end; } - if (ContentType::isImIsComposing(msg->getPrivate()->getContentType())) { + if (msg->getPrivate()->getContentType() == ContentType::ImIsComposing) { isComposingReceived(msg->getPrivate()->getText()); increaseMsgCount = FALSE; if (lp_config_get_int(core->config, "sip", "deliver_imdn", 0) != 1) { goto end; } - } else if (ContentType::isImdn(msg->getPrivate()->getContentType())) { + } else if (msg->getPrivate()->getContentType() == ContentType::Imdn) { imdnReceived(msg->getPrivate()->getText()); increaseMsgCount = FALSE; if (lp_config_get_int(core->config, "sip", "deliver_imdn", 0) != 1) { @@ -461,7 +461,7 @@ end: void ChatRoomPrivate::chatMessageReceived (shared_ptr msg) { L_Q(); - if (!ContentType::isImdn(msg->getPrivate()->getContentType()) && !ContentType::isImIsComposing(msg->getPrivate()->getContentType())) { + if ((msg->getPrivate()->getContentType() != ContentType::Imdn) && (msg->getPrivate()->getContentType() != ContentType::ImIsComposing)) { notifyChatMessageReceived(msg); remoteIsComposing = false; linphone_core_notify_is_composing_received(core, L_GET_C_BACK_PTR(q)); @@ -733,7 +733,7 @@ void ChatRoom::sendMessage (shared_ptr msg) { msg->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); /* Check if we shall upload a file to a server */ - if (msg->getPrivate()->getFileTransferInformation() && msg->getPrivate()->getContentType().empty()) { + if (msg->getPrivate()->getFileTransferInformation() && !msg->getPrivate()->getContentType().isValid()) { /* Open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */ if (msg->uploadFile() == 0) { /* Add to transient list only if message is going out */ diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index 14fe313ab..189f2e4a2 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -81,8 +81,7 @@ int CpimChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { content = messagePrivate->contents.front(); } - ContentType contentType = content.getContentType(); - if (ContentType::isCpim(contentType.asString())) { + if (content.getContentType() == ContentType::Cpim) { const vector body = content.getBody(); string contentBody(body.begin(), body.end()); shared_ptr message = Cpim::Message::createFromString(contentBody); @@ -97,7 +96,7 @@ int CpimChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { return 500; } } else { - lError() << "[CPIM] Message is not CPIM but " << contentType.asString(); + lError() << "[CPIM] Message is not CPIM but " << content.getContentType().asString(); return -1; } return 0; diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index b0609c72b..e2972e478 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +#include "linphone/utils/utils.h" + #include "object/clonable-object-p.h" #include "content-type.h" @@ -34,6 +36,16 @@ public: // ----------------------------------------------------------------------------- +const ContentType ContentType::Cpim("message/cpim"); +const ContentType ContentType::FileTransfer("application/vnd.gsma.rcs-ft-http+xml"); +const ContentType ContentType::Imdn("message/imdn+xml"); +const ContentType ContentType::ImIsComposing("application/im-iscomposing+xml"); +const ContentType ContentType::PlainText("text/plain"); +const ContentType ContentType::ResourceLists("application/resource-lists+xml"); +const ContentType ContentType::Sdp("application/sdp"); + +// ----------------------------------------------------------------------------- + ContentType::ContentType (const string &contentType) : ClonableObject(*new ContentTypePrivate) { L_D(); @@ -71,16 +83,8 @@ bool ContentType::operator== (const ContentType &contentType) const { return getType() == contentType.getType() && getSubType() == contentType.getSubType(); } -bool ContentType::operator== (const string &contentType) const { - return *this == ContentType(contentType); -} - bool ContentType::operator!= (const ContentType &contentType) const { - return !(*this == contentType); -} - -bool ContentType::operator!= (const std::string &contentType) const { - return !(*this == contentType); + return !operator==(contentType); } const string &ContentType::getType () const { @@ -91,7 +95,7 @@ const string &ContentType::getType () const { bool ContentType::setType (const string &type) { L_D(); if (type.find('/') == string::npos) { - d->type = type; + d->type = Utils::stringToLower(type); return true; } return false; @@ -105,7 +109,7 @@ const string &ContentType::getSubType () const { bool ContentType::setSubType (const string &subType) { L_D(); if (subType.find('/') == string::npos) { - d->subType = subType; + d->subType = Utils::stringToLower(subType); return true; } return false; @@ -121,40 +125,4 @@ string ContentType::asString () const { return isValid() ? d->type + "/" + d->subType : ""; } -bool ContentType::isFileTransfer () const { - return isFileTransfer(asString()); -} - -bool ContentType::isImIsComposing () const { - return isFileTransfer(asString()); -} - -bool ContentType::isImdn () const { - return isImdn(asString()); -} - -bool ContentType::isText () const { - return isText(asString()); -} - -bool ContentType::isFileTransfer (const string &contentType) { - return contentType == "application/vnd.gsma.rcs-ft-http+xml"; -} - -bool ContentType::isImIsComposing (const string &contentType) { - return contentType == "application/im-iscomposing+xml"; -} - -bool ContentType::isImdn (const string &contentType) { - return contentType == "message/imdn+xml"; -} - -bool ContentType::isText (const string &contentType) { - return contentType == "text/plain"; -} - -bool ContentType::isCpim(const string &contentType) { - return contentType == "Message/CPIM"; -} - LINPHONE_END_NAMESPACE diff --git a/src/content/content-type.h b/src/content/content-type.h index 746166c66..9f05fef68 100644 --- a/src/content/content-type.h +++ b/src/content/content-type.h @@ -36,9 +36,12 @@ public: ContentType &operator= (const ContentType &src); bool operator== (const ContentType &contentType) const; - bool operator== (const std::string &contentType) const; bool operator!= (const ContentType &contentType) const; - bool operator!= (const std::string &contentType) const; + + // Delete these operators to prevent putting complicated content-type strings + // in the code. Instead define static const ContentType objects below. + bool operator== (const std::string &contentType) const = delete; + bool operator!= (const std::string &contentType) const = delete; bool isValid () const; @@ -50,16 +53,13 @@ public: std::string asString () const; - bool isFileTransfer () const; - bool isImIsComposing () const; - bool isImdn () const; - bool isText () const; - - static bool isFileTransfer (const std::string &contentType); - static bool isImIsComposing (const std::string &contentType); - static bool isImdn (const std::string &contentType); - static bool isText (const std::string &contentType); - static bool isCpim (const std::string &contentType); + static const ContentType Cpim; + static const ContentType FileTransfer; + static const ContentType Imdn; + static const ContentType ImIsComposing; + static const ContentType PlainText; + static const ContentType ResourceLists; + static const ContentType Sdp; private: L_DECLARE_PRIVATE(ContentType); diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index 8c0ac3f10..ce778ee6e 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -395,7 +395,7 @@ static void cpim_chat_message_modifier(void) { marieRoom->sendMessage(marieMessage); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageReceived,1)); - BC_ASSERT_TRUE(ContentType::isCpim(marieMessage->getInternalContent().getContentType().asString())); + BC_ASSERT_TRUE(marieMessage->getInternalContent().getContentType() == ContentType::Cpim); BC_ASSERT_PTR_NOT_NULL(pauline->stat.last_received_chat_message); if (pauline->stat.last_received_chat_message != NULL) { From 9b6d115836cd9aac358da87613675f5ad803d69c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 4 Oct 2017 17:47:29 +0200 Subject: [PATCH 0323/2215] Handle NOTIFY creation for conference subject change. --- .../local-conference-event-handler.cpp | 74 ++++++++++--------- .../local-conference-event-handler.h | 9 ++- 2 files changed, 46 insertions(+), 37 deletions(-) diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 7e99bf8c7..55dd61028 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -35,24 +35,25 @@ using namespace Xsd::ConferenceInfo; class LocalConferenceEventHandlerPrivate : public ObjectPrivate { public: - void notifyFullState(string notify, LinphoneEvent *lev); - void notifyAllExcept(string notify, const Address &addr); - void notifyAll(string notify); - string createNotifyFullState(); - string createNotifyParticipantAdded(const Address &addr); - string createNotifyParticipantRemoved(const Address &addr); - string createNotifyParticipantAdmined(const Address &addr, bool isAdmin); + void notifyFullState (string notify, LinphoneEvent *lev); + void notifyAllExcept (string notify, const Address &addr); + void notifyAll (string notify); + string createNotifyFullState (); + string createNotifyParticipantAdded (const Address &addr); + string createNotifyParticipantRemoved (const Address &addr); + string createNotifyParticipantAdmined (const Address &addr, bool isAdmin); + string createNotifySubjectChanged (); LinphoneCore *core = nullptr; LocalConference *conf = nullptr; private: - void sendNotify(string notify, const Address &addr); + void sendNotify (string notify, const Address &addr); }; // ----------------------------------------------------------------------------- -static void doNotify(string notify, LinphoneEvent *lev) { +static void doNotify (string notify, LinphoneEvent *lev) { LinphoneContent *content = linphone_core_create_content(lev->lc); linphone_content_set_buffer(content, notify.c_str(), strlen(notify.c_str())); linphone_event_notify(lev, content); @@ -60,7 +61,7 @@ static void doNotify(string notify, LinphoneEvent *lev) { linphone_event_unref(lev); } -static string createNotify(ConferenceType confInfo) { +static string createNotify (ConferenceType confInfo) { stringstream notify; Xsd::XmlSchema::NamespaceInfomap map; map[""].name = "urn:ietf:params:xml:ns:conference-info"; @@ -70,11 +71,11 @@ static string createNotify(ConferenceType confInfo) { // ----------------------------------------------------------------------------- -void LocalConferenceEventHandlerPrivate::notifyFullState(string notify, LinphoneEvent *lev) { +void LocalConferenceEventHandlerPrivate::notifyFullState (string notify, LinphoneEvent *lev) { doNotify(notify, lev); } -void LocalConferenceEventHandlerPrivate::notifyAllExcept(string notify, const Address &addr) { +void LocalConferenceEventHandlerPrivate::notifyAllExcept (string notify, const Address &addr) { for (const auto &participant : conf->getParticipants()) { if (addr != participant->getAddress()) { this->sendNotify(notify, addr); @@ -82,13 +83,13 @@ void LocalConferenceEventHandlerPrivate::notifyAllExcept(string notify, const Ad } } -void LocalConferenceEventHandlerPrivate::notifyAll(string notify) { +void LocalConferenceEventHandlerPrivate::notifyAll (string notify) { for (const auto &participant : conf->getParticipants()) { this->sendNotify(notify, participant->getAddress()); } } -string LocalConferenceEventHandlerPrivate::createNotifyFullState() { +string LocalConferenceEventHandlerPrivate::createNotifyFullState () { string entity = this->conf->getConferenceAddress()->asStringUriOnly(); string subject = this->conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); @@ -111,15 +112,12 @@ string LocalConferenceEventHandlerPrivate::createNotifyFullState() { return(createNotify(confInfo)); } -string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded(const Address &addr) { +string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const Address &addr) { string entity = this->conf->getConferenceAddress()->asStringUriOnly(); string subject = this->conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); UsersType users; - ConferenceDescriptionType confDescr = ConferenceDescriptionType(); - confDescr.setSubject(subject); confInfo.setUsers(users); - confInfo.setConferenceDescription((const ConferenceDescriptionType)confDescr); UserType user = UserType(); UserRolesType roles; @@ -132,15 +130,12 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded(const Ad return(createNotify(confInfo)); } -string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved(const Address &addr) { +string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved (const Address &addr) { string entity = this->conf->getConferenceAddress()->asStringUriOnly(); string subject = this->conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); UsersType users; - ConferenceDescriptionType confDescr = ConferenceDescriptionType(); - confDescr.setSubject(subject); confInfo.setUsers(users); - confInfo.setConferenceDescription((const ConferenceDescriptionType)confDescr); UserType user = UserType(); user.setEntity(addr.asStringUriOnly()); @@ -150,15 +145,12 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved(const return(createNotify(confInfo)); } -string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined(const Address &addr, bool isAdmin) { +string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined (const Address &addr, bool isAdmin) { string entity = this->conf->getConferenceAddress()->asStringUriOnly(); string subject = this->conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); UsersType users; - ConferenceDescriptionType confDescr = ConferenceDescriptionType(); - confDescr.setSubject(subject); confInfo.setUsers(users); - confInfo.setConferenceDescription((const ConferenceDescriptionType)confDescr); UserType user = UserType(); UserRolesType roles; @@ -171,7 +163,18 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined(const return(createNotify(confInfo)); } -void LocalConferenceEventHandlerPrivate::sendNotify(string notify, const Address &addr) { +string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged () { + string entity = this->conf->getConferenceAddress()->asStringUriOnly(); + string subject = this->conf->getSubject(); + ConferenceType confInfo = ConferenceType(entity); + ConferenceDescriptionType confDescr = ConferenceDescriptionType(); + confDescr.setSubject(subject); + confInfo.setConferenceDescription((const ConferenceDescriptionType)confDescr); + + return(createNotify(confInfo)); +} + +void LocalConferenceEventHandlerPrivate::sendNotify (string notify, const Address &addr) { LinphoneAddress *cAddr = linphone_address_new(addr.asString().c_str()); LinphoneEvent *lev = linphone_core_create_notify(core, cAddr, "conference"); linphone_address_unref(cAddr); @@ -180,37 +183,42 @@ void LocalConferenceEventHandlerPrivate::sendNotify(string notify, const Address // ============================================================================= -LocalConferenceEventHandler::LocalConferenceEventHandler(LinphoneCore *core, LocalConference *localConf) : Object(*new LocalConferenceEventHandlerPrivate) { +LocalConferenceEventHandler::LocalConferenceEventHandler (LinphoneCore *core, LocalConference *localConf) : Object(*new LocalConferenceEventHandlerPrivate) { L_D(); xercesc::XMLPlatformUtils::Initialize(); d->conf = localConf; d->core = core; } -LocalConferenceEventHandler::~LocalConferenceEventHandler() { +LocalConferenceEventHandler::~LocalConferenceEventHandler () { xercesc::XMLPlatformUtils::Terminate(); } // ----------------------------------------------------------------------------- -void LocalConferenceEventHandler::subscribeReceived(LinphoneEvent *lev) { +void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) { L_D(); d->notifyFullState(d->createNotifyFullState(), lev); } -void LocalConferenceEventHandler::notifyParticipantAdded(const Address &addr) { +void LocalConferenceEventHandler::notifyParticipantAdded (const Address &addr) { L_D(); d->notifyAllExcept(d->createNotifyParticipantAdded(addr), addr); } -void LocalConferenceEventHandler::notifyParticipantRemoved(const Address &addr) { +void LocalConferenceEventHandler::notifyParticipantRemoved (const Address &addr) { L_D(); d->notifyAllExcept(d->createNotifyParticipantRemoved(addr), addr); } -void LocalConferenceEventHandler::notifyParticipantSetAdmin(const Address &addr, bool isAdmin) { +void LocalConferenceEventHandler::notifyParticipantSetAdmin (const Address &addr, bool isAdmin) { L_D(); d->notifyAll(d->createNotifyParticipantAdmined(addr, isAdmin)); } +void LocalConferenceEventHandler::notifySubjectChanged () { + L_D(); + d->notifyAll(d->createNotifySubjectChanged()); +} + LINPHONE_END_NAMESPACE diff --git a/src/conference/local-conference-event-handler.h b/src/conference/local-conference-event-handler.h index f210f8251..93fe369c1 100644 --- a/src/conference/local-conference-event-handler.h +++ b/src/conference/local-conference-event-handler.h @@ -36,10 +36,11 @@ class LocalConferenceEventHandler : public Object { LocalConferenceEventHandler(LinphoneCore *core, LocalConference *localConf); ~LocalConferenceEventHandler(); - void subscribeReceived(LinphoneEvent *lev); - void notifyParticipantAdded(const Address &addr); - void notifyParticipantRemoved(const Address &addr); - void notifyParticipantSetAdmin(const Address &addr, bool isAdmin); + void subscribeReceived (LinphoneEvent *lev); + void notifyParticipantAdded (const Address &addr); + void notifyParticipantRemoved (const Address &addr); + void notifyParticipantSetAdmin (const Address &addr, bool isAdmin); + void notifySubjectChanged (); private: L_DECLARE_PRIVATE(LocalConferenceEventHandler); From 6beb962517eb061e027e38ad492a2224ba6945ff Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 5 Oct 2017 10:52:09 +0200 Subject: [PATCH 0324/2215] Move the new sal code in the src folder, respect the file naming conventions and add missing license headers. --- coreapi/CMakeLists.txt | 9 -- coreapi/authentication.c | 2 +- coreapi/bellesip_sal/sal_impl.h | 2 +- coreapi/bellesip_sal/sal_op_impl.c | 2 +- coreapi/callbacks.c | 6 +- coreapi/event.c | 2 +- coreapi/offeranswer.c | 2 +- coreapi/private.h | 12 +- coreapi/quality_reporting.c | 2 +- coreapi/quality_reporting.h | 2 +- coreapi/sal/message_op.h | 47 ------ coreapi/sal/message_op_interface.h | 38 ----- coreapi/sal/register_op.h | 43 ------ coreapi/tester_utils.h | 2 +- coreapi/vcard.cc | 2 +- src/CMakeLists.txt | 10 ++ .../sal.c => src/c-wrapper/internal/c-sal.cpp | 2 +- .../sal.h => src/c-wrapper/internal/c-sal.h | 0 src/chat/chat-room.cpp | 2 +- src/conference/params/call-session-params.h | 2 +- src/conference/session/call-session-p.h | 2 +- src/conference/session/call-session.h | 2 +- .../sal/call_op.cpp => src/sal/call-op.cpp | 21 ++- coreapi/sal/call_op.h => src/sal/call-op.h | 63 ++++---- .../sal/event_op.cpp => src/sal/event-op.cpp | 20 ++- coreapi/sal/event_op.h => src/sal/event-op.h | 49 +++---- src/sal/message-op-interface.h | 38 +++++ .../message_op.cpp => src/sal/message-op.cpp | 20 ++- src/sal/message-op.h | 46 ++++++ coreapi/sal/sal_op.cpp => src/sal/op.cpp | 21 ++- coreapi/sal/sal_op.h => src/sal/op.h | 124 ++++++++-------- .../sal/presence-op.cpp | 20 ++- .../presence_op.h => src/sal/presence-op.h | 47 +++--- .../sal/register-op.cpp | 20 ++- src/sal/register-op.h | 43 ++++++ {coreapi => src}/sal/sal.cpp | 28 +++- coreapi/sal/sal.hpp => src/sal/sal.h | 138 +++++++++--------- src/utils/payload-type-handler.h | 2 +- 38 files changed, 508 insertions(+), 385 deletions(-) delete mode 100644 coreapi/sal/message_op.h delete mode 100644 coreapi/sal/message_op_interface.h delete mode 100644 coreapi/sal/register_op.h rename coreapi/sal/sal.c => src/c-wrapper/internal/c-sal.cpp (99%) rename coreapi/sal/sal.h => src/c-wrapper/internal/c-sal.h (100%) rename coreapi/sal/call_op.cpp => src/sal/call-op.cpp (98%) rename coreapi/sal/call_op.h => src/sal/call-op.h (86%) rename coreapi/sal/event_op.cpp => src/sal/event-op.cpp (95%) rename coreapi/sal/event_op.h => src/sal/event-op.h (69%) create mode 100644 src/sal/message-op-interface.h rename coreapi/sal/message_op.cpp => src/sal/message-op.cpp (82%) create mode 100644 src/sal/message-op.h rename coreapi/sal/sal_op.cpp => src/sal/op.cpp (98%) rename coreapi/sal/sal_op.h => src/sal/op.h (90%) rename coreapi/sal/presence_op.cpp => src/sal/presence-op.cpp (95%) rename coreapi/sal/presence_op.h => src/sal/presence-op.h (63%) rename coreapi/sal/register_op.cpp => src/sal/register-op.cpp (86%) create mode 100644 src/sal/register-op.h rename {coreapi => src}/sal/sal.cpp (97%) rename coreapi/sal/sal.hpp => src/sal/sal.h (93%) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index b6b473113..4397e036a 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -44,7 +44,6 @@ list(APPEND LINPHONE_PRIVATE_HEADER_FILES offeranswer.h private.h quality_reporting.h - sal/sal.h sqlite3_bctbx_vfs.h vcard_private.h xml2lpc.h @@ -99,7 +98,6 @@ set(LINPHONE_SOURCE_FILES_C quality_reporting.c remote_provisioning.c ringtoneplayer.c - sal/sal.c siplogin.c sipsetup.c sqlite3_bctbx_vfs.c @@ -111,13 +109,6 @@ set(LINPHONE_SOURCE_FILES_C ) set(LINPHONE_SOURCE_FILES_CXX conference.cc - sal/call_op.cpp - sal/event_op.cpp - sal/message_op.cpp - sal/presence_op.cpp - sal/register_op.cpp - sal/sal.cpp - sal/sal_op.cpp tester_utils.cpp ) set(LINPHONE_INCLUDE_DIRS ${LINPHONE_INCLUDE_DIRS}) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index e884faf5a..070d308a5 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -24,7 +24,7 @@ #include "linphone/core.h" #include "linphone/lpconfig.h" -#include "sal/sal.hpp" +#include "sal/sal.h" #include "c-wrapper/c-wrapper.h" diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index a30f22e5a..7ce5a10b9 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef SAL_IMPL_H_ #define SAL_IMPL_H_ -#include "sal/sal.h" +#include "c-wrapper/internal/c-sal.h" #include "belle-sip/belle-sip.h" #include "belle-sip/belle-sdp.h" diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 5040f6d01..f3a9bce2e 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sal_impl.h" -#include "sal/sal.hpp" +#include "sal/sal.h" using namespace LinphonePrivate; diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index cb6dcb199..9e4cbf091 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -18,9 +18,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "sal/sal.h" -#include "sal/call_op.h" -#include "sal/message_op.h" +#include "c-wrapper/internal/c-sal.h" +#include "sal/call-op.h" +#include "sal/message-op.h" #include "linphone/core.h" #include "private.h" diff --git a/coreapi/event.c b/coreapi/event.c index 5b9b0a989..33f7919b2 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -19,7 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/event.h" #include "linphone/lpconfig.h" -#include "sal/event_op.h" +#include "sal/event-op.h" #include "c-wrapper/c-wrapper.h" diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index a24e9b418..3644d9bcc 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -17,8 +17,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "c-wrapper/internal/c-sal.h" #include "sal/sal.h" -#include "sal/sal.hpp" #include "offeranswer.h" #include "private.h" diff --git a/coreapi/private.h b/coreapi/private.h index 9e430c6cd..325be8645 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -31,12 +31,12 @@ #include "linphone/tunnel.h" #include "linphone/core_utils.h" #include "linphone/conference.h" -#include "sal/sal.h" -#include "sal/call_op.h" -#include "sal/event_op.h" -#include "sal/message_op.h" -#include "sal/presence_op.h" -#include "sal/register_op.h" +#include "c-wrapper/internal/c-sal.h" +#include "sal/call-op.h" +#include "sal/event-op.h" +#include "sal/message-op.h" +#include "sal/presence-op.h" +#include "sal/register-op.h" #include "linphone/sipsetup.h" #include "quality_reporting.h" #include "linphone/ringtoneplayer.h" diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index fd2e393fd..e6d84a4d4 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -23,8 +23,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/core.h" #include "private.h" +#include "c-wrapper/internal/c-sal.h" #include "sal/sal.h" -#include "sal/sal.hpp" #include "ortp/rtpsession.h" #include diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index 155dec2ee..1ee63335d 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -21,7 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define quality_reporting_h #include "linphone/core.h" -#include "sal/sal.h" +#include "c-wrapper/internal/c-sal.h" #ifdef __cplusplus extern "C"{ diff --git a/coreapi/sal/message_op.h b/coreapi/sal/message_op.h deleted file mode 100644 index 22d7e3d7f..000000000 --- a/coreapi/sal/message_op.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -message_op.h -Copyright (C) 2017 Belledonne Communications - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef _SAL_MASSAGE_OP_H_ -#define _SAL_MASSAGE_OP_H_ - -#include "sal_op.h" -#include "message_op_interface.h" - -LINPHONE_BEGIN_NAMESPACE - -class SalMessageOp: public SalOp, public SalMessageOpInterface { -public: - SalMessageOp(Sal *sal): SalOp(sal) {} - - int send_message(const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri) override; - int reply(SalReason reason) override {return SalOp::reply_message(reason);} - -private: - virtual void fill_cbs() override; - void process_error(); - - static void process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event); - static void process_response_event_cb(void *op_base, const belle_sip_response_event_t *event); - static void process_timeout_cb(void *user_ctx, const belle_sip_timeout_event_t *event); - static void process_request_event_cb(void *op_base, const belle_sip_request_event_t *event); -}; - -LINPHONE_END_NAMESPACE - -#endif diff --git a/coreapi/sal/message_op_interface.h b/coreapi/sal/message_op_interface.h deleted file mode 100644 index 1e5abee82..000000000 --- a/coreapi/sal/message_op_interface.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -message_op_interface.h -Copyright (C) 2017 Belledonne Communications - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef _SAL_MESSAGE_OP_INTERFACE_H_ -#define _SAL_MESSAGE_OP_INTERFACE_H_ - -LINPHONE_BEGIN_NAMESPACE - -class SalMessageOpInterface { -public: - virtual ~SalMessageOpInterface() = default; - int send_message(const char *from, const char *to, const char *msg) {return send_message(from,to,"text/plain",msg, nullptr);} - virtual int send_message(const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri) = 0; - virtual int reply(SalReason reason) = 0; - -protected: - void prepare_message_request(belle_sip_request_t *req, const char* content_type, const char *msg, const char *peer_uri); -}; - -LINPHONE_END_NAMESPACE - -#endif diff --git a/coreapi/sal/register_op.h b/coreapi/sal/register_op.h deleted file mode 100644 index a8f2c03c0..000000000 --- a/coreapi/sal/register_op.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -register_op.h -Copyright (C) 2017 Belledonne Communications - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef _SAL_REGISTER_OP_H_ -#define _SAL_REGISTER_OP_H_ - -#include "sal_op.h" - -LINPHONE_BEGIN_NAMESPACE - -class SalRegisterOp: public SalOp { -public: - SalRegisterOp(Sal *sal): SalOp(sal) {} - int register_(const char *proxy, const char *from, int expires, const SalAddress* old_contact); - int register_refresh(int expires) {return this->refresher ? belle_sip_refresher_refresh(this->refresher,expires) : -1;} - int unregister() {return register_refresh(0);} - - virtual void authenticate(const SalAuthInfo *info) override {register_refresh(-1);} - -private: - virtual void fill_cbs() override {}; - static void register_refresher_listener(belle_sip_refresher_t* refresher, void* user_pointer, unsigned int status_code, const char* reason_phrase, int will_retry); -}; - -LINPHONE_END_NAMESPACE - -#endif diff --git a/coreapi/tester_utils.h b/coreapi/tester_utils.h index 720e299d0..ccb993246 100644 --- a/coreapi/tester_utils.h +++ b/coreapi/tester_utils.h @@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "account_creator_private.h" #include "linphone/core.h" #include "linphone/tunnel.h" -#include "sal/sal.h" +#include "c-wrapper/internal/c-sal.h" #include #include "quality_reporting.h" #include "vcard_private.h" diff --git a/coreapi/vcard.cc b/coreapi/vcard.cc index 62d907082..8b6251be9 100644 --- a/coreapi/vcard.cc +++ b/coreapi/vcard.cc @@ -26,7 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/wrapper_utils.h" #include "c-wrapper/c-wrapper.h" -#include "sal/sal.h" +#include "c-wrapper/internal/c-sal.h" #include "vcard_private.h" #define VCARD_MD5_HASH_SIZE 16 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fad0f570e..037092329 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,6 +25,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES address/address.h c-wrapper/c-wrapper.h c-wrapper/internal/c-tools.h + c-wrapper/internal/c-sal.h call/call-listener.h call/call-p.h call/call.h @@ -96,6 +97,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES object/object.h object/property-container.h object/singleton.h + sal/sal.h utils/payload-type-handler.h variant/variant.h xml/conference-info.h @@ -116,6 +118,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES c-wrapper/api/c-chat-room-cbs.cpp c-wrapper/api/c-event-log.cpp c-wrapper/api/c-participant.cpp + c-wrapper/internal/c-sal.cpp call/call.cpp chat/basic-chat-room.cpp chat/chat-message.cpp @@ -162,6 +165,13 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES object/clonable-object.cpp object/object.cpp object/property-container.cpp + sal/call-op.cpp + sal/event-op.cpp + sal/message-op.cpp + sal/op.cpp + sal/presence-op.cpp + sal/register-op.cpp + sal/sal.cpp utils/general.cpp utils/payload-type-handler.cpp utils/utils.cpp diff --git a/coreapi/sal/sal.c b/src/c-wrapper/internal/c-sal.cpp similarity index 99% rename from coreapi/sal/sal.c rename to src/c-wrapper/internal/c-sal.cpp index 2ed838a4e..002dbe523 100644 --- a/coreapi/sal/sal.c +++ b/src/c-wrapper/internal/c-sal.cpp @@ -23,7 +23,7 @@ This file contains SAL API functions that do not depend on the underlying implem #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include "sal/sal.h" +#include "c-wrapper/internal/c-sal.h" #include diff --git a/coreapi/sal/sal.h b/src/c-wrapper/internal/c-sal.h similarity index 100% rename from coreapi/sal/sal.h rename to src/c-wrapper/internal/c-sal.h diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 4c47f02a4..3bc88a1d5 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -27,7 +27,7 @@ #include "content/content.h" #include "chat-message-p.h" #include "chat-room.h" -#include "sal/message_op.h" +#include "sal/message-op.h" #include "logger/logger.h" // ============================================================================= diff --git a/src/conference/params/call-session-params.h b/src/conference/params/call-session-params.h index 2b01dcfe8..f8498b980 100644 --- a/src/conference/params/call-session-params.h +++ b/src/conference/params/call-session-params.h @@ -22,8 +22,8 @@ #include "object/clonable-object.h" #include "linphone/types.h" +#include "c-wrapper/internal/c-sal.h" #include "sal/sal.h" -#include "sal/sal.hpp" // ============================================================================= diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index 74c401c74..f90938332 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -22,7 +22,7 @@ #include "object/object-p.h" #include "call-session.h" -#include "sal/call_op.h" +#include "sal/call-op.h" // ============================================================================= diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index d09435a92..1fd463d34 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -24,7 +24,7 @@ #include "conference/conference.h" #include "conference/params/call-session-params.h" #include "conference/session/call-session-listener.h" -#include "sal/call_op.h" +#include "sal/call-op.h" // ============================================================================= diff --git a/coreapi/sal/call_op.cpp b/src/sal/call-op.cpp similarity index 98% rename from coreapi/sal/call_op.cpp rename to src/sal/call-op.cpp index c55139d5a..40735c1a1 100644 --- a/coreapi/sal/call_op.cpp +++ b/src/sal/call-op.cpp @@ -1,6 +1,25 @@ -#include "call_op.h" +/* + * call-op.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + #include "bellesip_sal/sal_impl.h" #include "offeranswer.h" +#include "sal/call-op.h" + #include #include diff --git a/coreapi/sal/call_op.h b/src/sal/call-op.h similarity index 86% rename from coreapi/sal/call_op.h rename to src/sal/call-op.h index 1b4757d37..d46540ef3 100644 --- a/coreapi/sal/call_op.h +++ b/src/sal/call-op.h @@ -1,27 +1,26 @@ /* -sal_op.h -Copyright (C) 2017 Belledonne Communications - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ + * call-op.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ #ifndef _SAL_CALL_OP_H_ #define _SAL_CALL_OP_H_ -#include "sal_op.h" -#include "message_op_interface.h" +#include "sal/op.h" +#include "sal/message-op-interface.h" LINPHONE_BEGIN_NAMESPACE @@ -29,15 +28,15 @@ class SalCallOp: public SalOp, public SalMessageOpInterface { public: SalCallOp(Sal *sal): SalOp(sal) {} ~SalCallOp() override; - + int set_local_media_description(SalMediaDescription *desc); int set_local_body(const Content &body); int set_local_body(const Content &&body); - + SalMediaDescription *get_remote_media_description() {return this->remote_media;} const Content &get_remote_body() const {return this->remote_body;} SalMediaDescription *get_final_media_description(); - + int call(const char *from, const char *to, const char *subject); int notify_ringing(bool_t early_media); int accept(); @@ -63,7 +62,7 @@ public: const char *get_remote_tag() {return belle_sip_dialog_get_remote_tag(this->dialog);} void set_replaces(const char *call_id, const char *from_tag, const char *to_tag); void set_sdp_handling(SalOpSDPHandling handling); - + // Implementation of SalMessageOpInterface int send_message(const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri) override; int reply(SalReason reason) override {return SalOp::reply_message(reason);} @@ -71,18 +70,18 @@ public: private: virtual void fill_cbs() override; void set_released(); - + void set_error(belle_sip_response_t* response, bool_t fatal); void call_terminated(belle_sip_server_transaction_t* server_transaction, int status_code, belle_sip_request_t* cancel_request); void reset_descriptions(); - + int parse_sdp_body(const Content &body,belle_sdp_session_description_t** session_desc, SalReason *error); void sdp_process(); void handle_body_from_response(belle_sip_response_t* response); SalReason process_body_for_invite(belle_sip_request_t* invite); SalReason process_body_for_ack(belle_sip_request_t *ack); void handle_offer_answer_response(belle_sip_response_t* response); - + void fill_invite(belle_sip_request_t* invite); void cancelling_invite(const SalErrorInfo *info); int refer_to(belle_sip_header_refer_to_t* refer_to, belle_sip_header_referred_by_t* referred_by); @@ -90,7 +89,7 @@ private: void notify_last_response(SalCallOp *newcall); void process_refer(const belle_sip_request_event_t *event, belle_sip_server_transaction_t *server_transaction); void process_notify(const belle_sip_request_event_t *event, belle_sip_server_transaction_t* server_transaction); - + static void set_addr_to_0000(char value[], size_t sz); static int is_media_description_acceptable(SalMediaDescription *md); static bool_t is_a_pending_invite_incoming_transaction(belle_sip_transaction_t *tr); @@ -99,14 +98,14 @@ private: static belle_sip_header_reason_t *make_reason_header( const SalErrorInfo *info); static belle_sip_header_allow_t *create_allow(bool_t enable_update); static std::vector marshal_media_description(belle_sdp_session_description_t *session_desc, belle_sip_error_code &error); - + // belle_sip_message handlers static int set_custom_body(belle_sip_message_t *msg, const Content &body); static int set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* session_desc); static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription *desc); static void process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event); static Content extract_body(belle_sip_message_t *message); - + // Callbacks static int vfu_retry_cb (void *user_data, unsigned int events); static void process_response_cb(void *op_base, const belle_sip_response_event_t *event); @@ -114,10 +113,10 @@ private: static void process_transaction_terminated_cb(void *user_ctx, const belle_sip_transaction_terminated_event_t *event); static void process_request_event_cb(void *op_base, const belle_sip_request_event_t *event); static void process_dialog_terminated_cb(void *ctx, const belle_sip_dialog_terminated_event_t *event); - + // Private constants static const size_t SIP_MESSAGE_BODY_LIMIT = 16*1024; // 16kB - + // Attributes SalMediaDescription *local_media = NULL; SalMediaDescription *remote_media = NULL; @@ -127,4 +126,4 @@ private: LINPHONE_END_NAMESPACE -#endif +#endif // ifndef _SAL_CALL_OP_H_ diff --git a/coreapi/sal/event_op.cpp b/src/sal/event-op.cpp similarity index 95% rename from coreapi/sal/event_op.cpp rename to src/sal/event-op.cpp index 42882d5ae..01e748be5 100644 --- a/coreapi/sal/event_op.cpp +++ b/src/sal/event-op.cpp @@ -1,4 +1,22 @@ -#include "event_op.h" +/* + * event-op.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "sal/event-op.h" using namespace std; diff --git a/coreapi/sal/event_op.h b/src/sal/event-op.h similarity index 69% rename from coreapi/sal/event_op.h rename to src/sal/event-op.h index 0084c508a..94554fc69 100644 --- a/coreapi/sal/event_op.h +++ b/src/sal/event-op.h @@ -1,38 +1,37 @@ /* -event_op.h -Copyright (C) 2017 Belledonne Communications - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ + * event-op.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ #ifndef _SAL_EVENT_OP_H_ #define _SAL_EVENT_OP_H_ -#include "sal_op.h" +#include "sal/op.h" LINPHONE_BEGIN_NAMESPACE class SalEventOp: public SalOp { public: - SalEventOp(Sal *sal): SalOp(sal) {} + SalEventOp(Sal *sal): SalOp(sal) {} }; class SalSubscribeOp: public SalEventOp { public: SalSubscribeOp(Sal *sal): SalEventOp(sal) {} - + int subscribe(const char *from, const char *to, const char *eventname, int expires, const SalBodyHandler *body_handler); int unsubscribe() {return SalOp::unsubscribe();} int accept(); @@ -44,7 +43,7 @@ public: private: virtual void fill_cbs() override; void handle_notify(belle_sip_request_t *req, const char *eventname, SalBodyHandler* body_handler); - + static void subscribe_process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event); static void subscribe_response_event_cb(void *op_base, const belle_sip_response_event_t *event); static void subscribe_process_timeout_cb(void *user_ctx, const belle_sip_timeout_event_t *event); @@ -57,18 +56,18 @@ private: class SalPublishOp: public SalEventOp { public: - SalPublishOp(Sal *sal): SalEventOp(sal) {} - + SalPublishOp(Sal *sal): SalEventOp(sal) {} + int publish(const char *from, const char *to, const char *eventname, int expires, const SalBodyHandler *body_handler); int unpublish(); private: virtual void fill_cbs() override; - + static void publish_response_event_cb(void *userctx, const belle_sip_response_event_t *event); static void publish_refresher_listener_cb (belle_sip_refresher_t* refresher,void* user_pointer,unsigned int status_code,const char* reason_phrase, int will_retry); }; LINPHONE_END_NAMESPACE -#endif +#endif // ifndef _SAL_EVENT_OP_H_ diff --git a/src/sal/message-op-interface.h b/src/sal/message-op-interface.h new file mode 100644 index 000000000..abbea0852 --- /dev/null +++ b/src/sal/message-op-interface.h @@ -0,0 +1,38 @@ +/* + * message-op-interface.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _SAL_MESSAGE_OP_INTERFACE_H_ +#define _SAL_MESSAGE_OP_INTERFACE_H_ + +LINPHONE_BEGIN_NAMESPACE + +class SalMessageOpInterface { +public: + virtual ~SalMessageOpInterface() = default; + + int send_message(const char *from, const char *to, const char *msg) {return send_message(from,to,"text/plain",msg, nullptr);} + virtual int send_message(const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri) = 0; + virtual int reply(SalReason reason) = 0; + +protected: + void prepare_message_request(belle_sip_request_t *req, const char* content_type, const char *msg, const char *peer_uri); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _SAL_MESSAGE_OP_INTERFACE_H_ diff --git a/coreapi/sal/message_op.cpp b/src/sal/message-op.cpp similarity index 82% rename from coreapi/sal/message_op.cpp rename to src/sal/message-op.cpp index a97a088e0..f16efc010 100644 --- a/coreapi/sal/message_op.cpp +++ b/src/sal/message-op.cpp @@ -1,4 +1,22 @@ -#include "message_op.h" +/* + * message-op.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "sal/message-op.h" using namespace std; diff --git a/src/sal/message-op.h b/src/sal/message-op.h new file mode 100644 index 000000000..1a04d8334 --- /dev/null +++ b/src/sal/message-op.h @@ -0,0 +1,46 @@ +/* + * message-op.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _SAL_MESSAGE_OP_H_ +#define _SAL_MESSAGE_OP_H_ + +#include "sal/op.h" +#include "sal/message-op-interface.h" + +LINPHONE_BEGIN_NAMESPACE + +class SalMessageOp: public SalOp, public SalMessageOpInterface { +public: + SalMessageOp(Sal *sal): SalOp(sal) {} + + int send_message(const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri) override; + int reply(SalReason reason) override {return SalOp::reply_message(reason);} + +private: + virtual void fill_cbs() override; + void process_error(); + + static void process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event); + static void process_response_event_cb(void *op_base, const belle_sip_response_event_t *event); + static void process_timeout_cb(void *user_ctx, const belle_sip_timeout_event_t *event); + static void process_request_event_cb(void *op_base, const belle_sip_request_event_t *event); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _SAL_MESSAGE_OP_H_ diff --git a/coreapi/sal/sal_op.cpp b/src/sal/op.cpp similarity index 98% rename from coreapi/sal/sal_op.cpp rename to src/sal/op.cpp index fe656cf4f..aa4a66fd8 100644 --- a/coreapi/sal/sal_op.cpp +++ b/src/sal/op.cpp @@ -1,5 +1,24 @@ +/* + * op.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + #include -#include "sal_op.h" + +#include "sal/op.h" #include "bellesip_sal/sal_impl.h" using namespace std; diff --git a/coreapi/sal/sal_op.h b/src/sal/op.h similarity index 90% rename from coreapi/sal/sal_op.h rename to src/sal/op.h index 0c2f0431a..96fa910dd 100644 --- a/coreapi/sal/sal_op.h +++ b/src/sal/op.h @@ -1,21 +1,21 @@ /* -sal_op.h -Copyright (C) 2017 Belledonne Communications + * op.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ #ifndef _SAL_OP_H_ #define _SAL_OP_H_ @@ -23,9 +23,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include #include -#include "sal.h" -#include "sal.hpp" + +#include "c-wrapper/internal/c-sal.h" #include "content/content.h" +#include "sal/sal.h" LINPHONE_BEGIN_NAMESPACE @@ -33,16 +34,15 @@ class SalOp { public: SalOp(Sal *sal); virtual ~SalOp(); - + SalOp *ref(); void *unref(); - + Sal *get_sal() const {return this->root;} - + void set_user_pointer(void *up) {this->user_pointer=up;} void *get_user_pointer() const {return this->user_pointer;} - void set_subject (const char *subject); const char *get_subject () const { return this->subject; } @@ -50,43 +50,43 @@ public: void set_from_address(const SalAddress *from); const char *get_from() const {return this->from;} const SalAddress *get_from_address() const {return this->from_address;} - + void set_to(const char *to); void set_to_address(const SalAddress *to); const char *get_to() const {return this->to;} const SalAddress *get_to_address() const {return this->to_address;} - + void set_contact_address(const SalAddress* address); const SalAddress *get_contact_address() const {return this->contact_address;} - + void set_route(const char *route); void set_route_address(const SalAddress* address); const bctbx_list_t *get_route_addresses() const {return this->route_addresses;} void add_route_address(const SalAddress* address); - + void set_diversion_address(const SalAddress *diversion); const SalAddress *get_diversion_address() const {return this->diversion_address;} - + void set_service_route(const SalAddress* service_route); const SalAddress *get_service_route() const {return this->service_route;} - + void set_manual_refresher_mode(bool_t enabled) {this->manual_refresher=enabled;} - + void set_entity_tag(const char* entity_tag); const char *get_entity_tag() const {return this->entity_tag;} - + void set_event(const char *eventname); - + void set_privacy(SalPrivacyMask privacy) {this->privacy=privacy;} SalPrivacyMask get_privacy() const {return this->privacy;} - + void set_realm(const char *realm); - + void set_sent_custom_header(SalCustomHeader* ch); - + void enable_cnx_ip_to_0000_if_sendonly(bool_t yesno) {this->_cnx_ip_to_0000_if_sendonly_enabled = yesno;} bool_t cnx_ip_to_0000_if_sendonly_enabled() const {return this->_cnx_ip_to_0000_if_sendonly_enabled;} - + const char *get_proxy() const {return this->route;} const char *get_network_origin() const {return this->origin;} const char* get_call_id() const {return this->call_id;} @@ -96,28 +96,28 @@ public: const char *get_remote_contact() const {return this->remote_contact;} const SalAddress *get_remote_contact_address() const {return this->remote_contact_address;} const char *get_remote_ua() const {return this->remote_ua;} - + const char *get_public_address(int *port) {return this->refresher ? belle_sip_refresher_get_public_address(this->refresher, port) : NULL;} const char *get_local_address(int *port) {return this->refresher ? belle_sip_refresher_get_local_address(this->refresher, port) : NULL;} - + const SalErrorInfo *get_error_info() const {return &this->error_info;} const SalErrorInfo *get_reason_error_info() const {return &this->reason_error_info;} - + bool_t is_forked_of(const SalOp *op2) const {return this->call_id && op2->call_id && strcmp(this->call_id, op2->call_id) == 0;} bool_t is_idle() const ; - + void stop_refreshing() {if (this->refresher) belle_sip_refresher_stop(this->refresher);} int refresh(); void kill_dialog(); void release(); - + virtual void authenticate(const SalAuthInfo *info) {process_authentication();} void cancel_authentication() {ms_fatal("sal_op_cancel_authentication not implemented yet");} SalAuthInfo *get_auth_requested() {return this->auth_info;} - + int ping(const char *from, const char *to); int send_info(const char *from, const char *to, const SalBodyHandler *body_handler); - + protected: enum class State { Early = 0, @@ -125,14 +125,14 @@ protected: Terminating, /*this state is used to wait until a proceeding state, so we can send the cancel*/ Terminated }; - + static const char* to_string(const State value); enum class Dir { Incoming = 0, Outgoing }; - + enum class Type { Unknown, Register, @@ -142,60 +142,60 @@ protected: Publish, Subscribe }; - + static const char *to_string(const SalOp::Type type); - + typedef void (*ReleaseCb)(SalOp *op); - + virtual void fill_cbs() {} void release_impl(); void process_authentication(); int process_redirect(); - + belle_sip_request_t* build_request(const char* method); int send_request(belle_sip_request_t* request); int send_request_with_contact(belle_sip_request_t* request, bool_t add_contact); int send_request_with_expires(belle_sip_request_t* request,int expires); void resend_request(belle_sip_request_t* request); int send_and_create_refresher(belle_sip_request_t* req, int expires,belle_sip_refresher_listener_t listener); - + void set_reason_error_info(belle_sip_message_t *msg); void set_error_info_from_response(belle_sip_response_t *response); - + void set_referred_by(belle_sip_header_referred_by_t* referred_by); void set_replaces(belle_sip_header_replaces_t* replaces); - + void set_remote_contact(const char* remote_contact); void set_network_origin(const char *origin); void set_network_origin_address(SalAddress *origin); void set_privacy_from_message(belle_sip_message_t* msg); void set_remote_ua(belle_sip_message_t* message); - + belle_sip_response_t *create_response_from_request(belle_sip_request_t *req, int code) {return this->root->create_response_from_request(req,code);} belle_sip_header_contact_t *create_contact(); - + void set_or_update_dialog(belle_sip_dialog_t* dialog); belle_sip_dialog_t *link_op_with_dialog(belle_sip_dialog_t* dialog); void unlink_op_with_dialog(belle_sip_dialog_t* dialog); - + SalBodyHandler *get_body_handler(belle_sip_message_t *msg); - + void assign_recv_headers(belle_sip_message_t *incoming); - + bool_t is_secure() const; void add_headers(belle_sip_header_t *h, belle_sip_message_t *msg); void add_custom_headers(belle_sip_message_t *msg); int unsubscribe(); - + void process_incoming_message(const belle_sip_request_event_t *event); int reply_message(SalReason reason); void add_message_accept(belle_sip_message_t *msg); static bool_t is_external_body(belle_sip_header_content_type_t* content_type); - + static void assign_address(SalAddress** address, const char *value); static void assign_string(char **str, const char *arg); static void add_initial_route_set(belle_sip_request_t *request, const MSList *list); - + // SalOpBase Sal *root = NULL; char *route = NULL; /*or request-uri for REGISTER*/ @@ -220,7 +220,7 @@ protected: SalCustomHeader *recv_custom_headers = NULL; char* entity_tag = NULL; /*as defined by rfc3903 (I.E publih)*/ ReleaseCb release_cb = NULL; - + // BelleSip implementation const belle_sip_listener_callbacks_t *callbacks = NULL; SalErrorInfo error_info; @@ -252,10 +252,10 @@ protected: bool_t has_auth_pending = FALSE; bool_t supports_session_timers = FALSE; bool_t op_released = FALSE; - + friend class Sal; }; LINPHONE_END_NAMESPACE -#endif +#endif // ifndef _SAL_OP_H_ diff --git a/coreapi/sal/presence_op.cpp b/src/sal/presence-op.cpp similarity index 95% rename from coreapi/sal/presence_op.cpp rename to src/sal/presence-op.cpp index 853017160..6e61ecda7 100644 --- a/coreapi/sal/presence_op.cpp +++ b/src/sal/presence-op.cpp @@ -1,4 +1,22 @@ -#include "presence_op.h" +/* + * presence-op.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "sal/presence-op.h" using namespace std; diff --git a/coreapi/sal/presence_op.h b/src/sal/presence-op.h similarity index 63% rename from coreapi/sal/presence_op.h rename to src/sal/presence-op.h index f8eebd9e7..7cb2fa8fd 100644 --- a/coreapi/sal/presence_op.h +++ b/src/sal/presence-op.h @@ -1,35 +1,34 @@ /* -presence_op.h -Copyright (C) 2017 Belledonne Communications - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ + * presence-op.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ #ifndef _SAL_PRESENCE_OP_H_ #define _SAL_PRESENCE_OP_H_ -#include "event_op.h" +#include "sal/event-op.h" LINPHONE_BEGIN_NAMESPACE class SalPresenceOp: public SalSubscribeOp { public: - SalPresenceOp(Sal *sal): SalSubscribeOp(sal) {} - + SalPresenceOp(Sal *sal): SalSubscribeOp(sal) {} + int subscribe(const char *from, const char *to, int expires); - int unsubscribe() {return SalOp::unsubscribe();} + int unsubscribe() {return SalOp::unsubscribe();} int notify_presence(SalPresenceModel *presence); int notify_presence_close(); @@ -40,9 +39,9 @@ private: int check_dialog_state(); belle_sip_request_t *create_presence_notify(); void add_presence_info(belle_sip_message_t *notify, SalPresenceModel *presence); - + static SalSubscribeStatus belle_sip_message_get_subscription_state(const belle_sip_message_t *msg); - + static void presence_process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event); static void presence_response_event_cb(void *op_base, const belle_sip_response_event_t *event); static void presence_refresher_listener_cb(belle_sip_refresher_t* refresher, void* user_pointer, unsigned int status_code, const char* reason_phrase, int will_retry); @@ -55,4 +54,4 @@ private: LINPHONE_END_NAMESPACE -#endif +#endif // ifndef _SAL_PRESENCE_OP_H_ diff --git a/coreapi/sal/register_op.cpp b/src/sal/register-op.cpp similarity index 86% rename from coreapi/sal/register_op.cpp rename to src/sal/register-op.cpp index 437b3b843..47834e31b 100644 --- a/coreapi/sal/register_op.cpp +++ b/src/sal/register-op.cpp @@ -1,4 +1,22 @@ -#include "register_op.h" +/* + * register-op.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "sal/register-op.h" #include "bellesip_sal/sal_impl.h" using namespace std; diff --git a/src/sal/register-op.h b/src/sal/register-op.h new file mode 100644 index 000000000..4fe1b7f75 --- /dev/null +++ b/src/sal/register-op.h @@ -0,0 +1,43 @@ +/* + * register-op.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#ifndef _SAL_REGISTER_OP_H_ +#define _SAL_REGISTER_OP_H_ + +#include "sal/op.h" + +LINPHONE_BEGIN_NAMESPACE + +class SalRegisterOp: public SalOp { +public: + SalRegisterOp(Sal *sal): SalOp(sal) {} + + int register_(const char *proxy, const char *from, int expires, const SalAddress* old_contact); + int register_refresh(int expires) {return this->refresher ? belle_sip_refresher_refresh(this->refresher,expires) : -1;} + int unregister() {return register_refresh(0);} + + virtual void authenticate(const SalAuthInfo *info) override {register_refresh(-1);} + +private: + virtual void fill_cbs() override {}; + static void register_refresher_listener(belle_sip_refresher_t* refresher, void* user_pointer, unsigned int status_code, const char* reason_phrase, int will_retry); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _SAL_REGISTER_OP_H_ diff --git a/coreapi/sal/sal.cpp b/src/sal/sal.cpp similarity index 97% rename from coreapi/sal/sal.cpp rename to src/sal/sal.cpp index 2a2b64fc7..179e4ff29 100644 --- a/coreapi/sal/sal.cpp +++ b/src/sal/sal.cpp @@ -1,8 +1,26 @@ -#include "sal.hpp" -#include "call_op.h" -#include "presence_op.h" -#include "event_op.h" -#include "message_op.h" +/* + * sal.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "sal/sal.h" +#include "sal/call-op.h" +#include "sal/presence-op.h" +#include "sal/event-op.h" +#include "sal/message-op.h" #include "bellesip_sal/sal_impl.h" #include "tester_utils.h" #include "private.h" diff --git a/coreapi/sal/sal.hpp b/src/sal/sal.h similarity index 93% rename from coreapi/sal/sal.hpp rename to src/sal/sal.h index 4cc74563b..61d49c9f3 100644 --- a/coreapi/sal/sal.hpp +++ b/src/sal/sal.h @@ -1,26 +1,25 @@ /* -sal.hpp -Copyright (C) 2017 Belledonne Communications + * sal.h + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. +#ifndef _SAL_H_ +#define _SAL_H_ -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. -*/ - -#ifndef _SAL_HPP_ -#define _SAL_HPP_ - -#include "sal/sal.h" +#include "c-wrapper/internal/c-sal.h" #include "linphone/utils/general.h" LINPHONE_BEGIN_NAMESPACE @@ -68,7 +67,7 @@ public: typedef void (*OnPublishResponseCb)(SalOp *salop); typedef void (*OnNotifyResponseCb)(SalOp *salop); typedef void (*OnExpireCb)(SalOp *salop); - + struct Callbacks { OnCallReceivedCb call_received; OnCallReceivedCb call_rejected; @@ -106,23 +105,23 @@ public: OnExpireCb on_expire; OnNotifyResponseCb on_notify_response; }; - + Sal(MSFactory *factory); ~Sal(); - + void set_user_pointer(void *user_data) {this->up=user_data;} void *get_user_pointer() const {return this->up;} - + void set_callbacks(const Callbacks *cbs); - + void *get_stack_impl() {return this->stack;} - + int iterate() {belle_sip_stack_sleep(this->stack,0); return 0;} - + void set_send_error(int value) {belle_sip_stack_set_send_error(this->stack,value);} void set_recv_error(int value) {belle_sip_provider_set_recv_error(this->prov,value);} - - + + /******************/ /* SIP parameters */ /******************/ @@ -130,30 +129,30 @@ public: const char *get_supported_tags() const {return this->supported ? belle_sip_header_get_unparsed_value(this->supported) : NULL;} void add_supported_tag(const char* tag); void remove_supported_tag(const char* tag); - + void set_user_agent(const char *user_agent); const char* get_user_agent() const; void append_stack_string_to_user_agent(); - + bool_t content_encoding_available(const char *content_encoding) {return (bool_t)belle_sip_stack_content_encoding_available(this->stack, content_encoding);} bool_t is_content_type_supported(const char *content_type) const; void add_content_type_support(const char *content_type); - + void set_default_sdp_handling(SalOpSDPHandling sdp_handling_method); - + void set_uuid(const char *uuid); int create_uuid(char *uuid, size_t len); static int generate_uuid(char *uuid, size_t len); - + void enable_nat_helper(bool_t enable); bool_t nat_helper_enabled() const {return this->_nat_helper_enabled;} - + bool_t pending_trans_checking_enabled() const {return this->pending_trans_checking;} int enable_pending_trans_checking(bool_t value) {this->pending_trans_checking = value; return 0;} - + void set_refresher_retry_after(int value) {this->refresher_retry_after=value;} int get_refresher_retry_after() const {return this->refresher_retry_after;} - + void enable_sip_update_method(bool_t value) {this->enable_sip_update=value;} void use_session_timers(int expires) {this->session_expires=expires;} void use_dates(bool_t enabled) {this->_use_dates=enabled;} @@ -163,42 +162,42 @@ public: void enable_test_features(bool_t enabled) {this->_enable_test_features=enabled;} void use_no_initial_route(bool_t enabled) {this->no_initial_route=enabled;} void enable_unconditional_answer(int value) {belle_sip_provider_enable_unconditional_answer(this->prov,value);} - + bctbx_list_t *get_pending_auths() const {return bctbx_list_copy(this->pending_auths);} - - + + /**********************/ /* Network parameters */ /**********************/ int set_listen_port(const char *addr, int port, SalTransport tr, bool_t is_tunneled); int get_listening_port(SalTransport tr); int transport_available(SalTransport t); - + void get_default_local_ip(int address_family, char *ip, size_t iplen); - + void set_transport_timeout(int timeout) {belle_sip_stack_set_transport_timeout(this->stack, timeout);} int get_transport_timeout() const {return belle_sip_stack_get_transport_timeout(this->stack);} - + void set_keepalive_period(unsigned int value); unsigned int get_keepalive_period() const {return this->keep_alive;} void use_tcp_tls_keepalive(bool_t enabled) {this->use_tcp_tls_keep_alive=enabled;} - + void set_dscp(int dscp) {belle_sip_stack_set_default_dscp(this->stack,dscp);} - + int set_tunnel(void *tunnelclient); - + void set_http_proxy_host(const char *host) {belle_sip_stack_set_http_proxy_host(this->stack, host);} const char *get_http_proxy_host() const {return belle_sip_stack_get_http_proxy_host(this->stack);} - + void set_http_proxy_port(int port) {belle_sip_stack_set_http_proxy_port(this->stack, port);} int get_http_proxy_port() const {return belle_sip_stack_get_http_proxy_port(this->stack);} - + ortp_socket_t get_socket() const; - + int unlisten_ports(); int reset_transports(); - - + + /******************/ /* TLS parameters */ /******************/ @@ -206,41 +205,41 @@ public: void set_root_ca(const char* rootCa); void set_root_ca_data(const char* data); const char *get_root_ca() const {return this->root_ca;} - + void verify_server_certificates(bool_t verify); void verify_server_cn(bool_t verify); - - + + /******************/ /* DNS resolution */ /******************/ void set_dns_timeout(int timeout) {belle_sip_stack_set_dns_timeout(this->stack, timeout);} int get_dns_timeout() const {return belle_sip_stack_get_dns_timeout(this->stack);} - + void set_dns_servers(const bctbx_list_t *servers); - + void enable_dns_search(bool_t enable) {belle_sip_stack_enable_dns_search(this->stack, (unsigned char)enable);} bool_t dns_search_enabled() const {return (bool_t)belle_sip_stack_dns_search_enabled(this->stack);} - + void enable_dns_srv(bool_t enable) {belle_sip_stack_enable_dns_srv(this->stack, (unsigned char)enable);} bool_t dns_srv_enabled() const {return (bool_t)belle_sip_stack_dns_srv_enabled(this->stack);} - + void set_dns_user_hosts_file(const char *hosts_file) {belle_sip_stack_set_dns_user_hosts_file(this->stack, hosts_file);} const char *get_dns_user_hosts_file() const {return belle_sip_stack_get_dns_user_hosts_file(this->stack);} - + belle_sip_resolver_context_t *resolve_a(const char *name, int port, int family, belle_sip_resolver_callback_t cb, void *data) {return belle_sip_stack_resolve_a(this->stack,name,port,family,cb,data);} belle_sip_resolver_context_t *resolve(const char *service, const char *transport, const char *name, int port, int family, belle_sip_resolver_callback_t cb, void *data) {return belle_sip_stack_resolve(this->stack, service, transport, name, port, family, cb, data);} - - + + /**********/ /* Timers */ /**********/ belle_sip_source_t *create_timer(belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms, const char* timer_name); void cancel_timer(belle_sip_source_t *timer); - - + + private: struct sal_uuid_t { unsigned int time_low; @@ -250,17 +249,17 @@ private: unsigned char clock_seq_low; unsigned char node[6]; }; - + void set_tls_properties(); int add_listen_port(SalAddress* addr, bool_t is_tunneled); void make_supported_header(); void add_pending_auth(SalOp *op); void remove_pending_auth(SalOp *op); belle_sip_response_t* create_response_from_request (belle_sip_request_t* req, int code ); - + static void unimplemented_stub() {ms_warning("Unimplemented SAL callback");} static void remove_listening_point(belle_sip_listening_point_t* lp,belle_sip_provider_t* prov) {belle_sip_provider_remove_listening_point(prov,lp);} - + /* Internal callbacks */ static void process_dialog_terminated_cb(void *sal, const belle_sip_dialog_terminated_event_t *event); static void process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event); @@ -269,7 +268,7 @@ private: static void process_timeout_cb(void *user_ctx, const belle_sip_timeout_event_t *event); static void process_transaction_terminated_cb(void *user_ctx, const belle_sip_transaction_terminated_event_t *event); static void process_auth_requested_cb(void *sal, belle_sip_auth_event_t *event); - + MSFactory *factory = NULL; Callbacks callbacks = {0}; MSList *pending_auths = NULL;/*MSList of SalOp */ @@ -301,7 +300,7 @@ private: bool_t pending_trans_checking = TRUE; /*testing purpose*/ void *ssl_config = NULL; bctbx_list_t *supported_content_types = NULL; /* list of char* */ - + friend class SalOp; friend class SalCallOp; friend class SalRegisterOp; @@ -315,5 +314,4 @@ int to_sip_code(SalReason r); LINPHONE_END_NAMESPACE - -#endif // _LINPHONE_SAL_HH +#endif // ifndef _SAL_H_ diff --git a/src/utils/payload-type-handler.h b/src/utils/payload-type-handler.h index fb339e255..d62d0237c 100644 --- a/src/utils/payload-type-handler.h +++ b/src/utils/payload-type-handler.h @@ -21,7 +21,7 @@ #include "linphone/utils/general.h" -#include "sal/sal.h" +#include "c-wrapper/internal/c-sal.h" #define PAYLOAD_TYPE_ENABLED PAYLOAD_TYPE_USER_FLAG_0 #define PAYLOAD_TYPE_BITRATE_OVERRIDE PAYLOAD_TYPE_USER_FLAG_3 From 25371cbfef5525198605037bfc111798d745355a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 5 Oct 2017 12:43:41 +0200 Subject: [PATCH 0325/2215] Added a way to suspend the sending of a ChatMessage (now using this for file transfer) --- src/chat/chat-message-p.h | 9 +++ src/chat/chat-message.cpp | 63 ++++++++++++++----- src/chat/chat-room.cpp | 33 +++------- src/chat/modifier/chat-message-modifier.h | 17 +++++ .../encryption-chat-message-modifier.cpp | 2 +- .../multipart-chat-message-modifier.cpp | 6 ++ 6 files changed, 91 insertions(+), 39 deletions(-) diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index bd5b5cbe7..f31ffc0b9 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -33,6 +33,14 @@ class ChatMessagePrivate : public ObjectPrivate { friend class MultipartChatMessageModifier; public: + enum Step { + None = 1 << 0, + FileUpload = 1 << 1, + Multipart = 1 << 2, + Encryption = 1 << 3, + Cpim = 1 << 4 + }; + ChatMessagePrivate (const std::shared_ptr &room); virtual ~ChatMessagePrivate (); @@ -127,6 +135,7 @@ private: SalOp *salOp = NULL; SalCustomHeader *salCustomHeaders = NULL; unsigned long backgroundTaskId; + unsigned char currentSendStep = Step::None; // Cache for returned values, used for compatibility with previous C API ContentType cContentType; std::string cText = ""; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index dc543a760..99cb87839 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -1030,6 +1030,19 @@ void ChatMessagePrivate::send() { SalOp *op = salOp; LinphoneCall *call = NULL; + if ((currentSendStep & ChatMessagePrivate::Step::FileUpload) == ChatMessagePrivate::Step::FileUpload) { + lInfo() << "File upload step already done, skipping"; + } else { + if (getFileTransferInformation()) { + /* Open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */ + if (q->uploadFile() == 0) { + setState(ChatMessage::State::InProgress); + currentSendStep |= ChatMessagePrivate::Step::FileUpload; + } + return; + } + } + if (lp_config_get_int(chatRoom->getCore()->config, "sip", "chat_use_call_dialogs", 0) != 0) { call = linphone_core_get_call_by_remote_address(chatRoom->getCore(), chatRoom->getPeerAddress().asString().c_str()); if (call) { @@ -1070,33 +1083,52 @@ void ChatMessagePrivate::send() { // Start of message modification // --------------------------------------- + //TODO Remove : This won't be necessary once we store the contentsList string clearTextMessage; ContentType clearTextContentType; - + if (!getText().empty()) { clearTextMessage = getText().c_str(); } if (getContentType().isValid()) { clearTextContentType = getContentType(); } + //End of TODO Remove - if (contents.size() > 1) { - MultipartChatMessageModifier mcmm; - mcmm.encode(this); + if ((currentSendStep & ChatMessagePrivate::Step::Multipart) == ChatMessagePrivate::Step::Multipart) { + lInfo() << "Multipart step already done, skipping"; + } else { + if (contents.size() > 1) { + MultipartChatMessageModifier mcmm; + mcmm.encode(this); + } + currentSendStep |= ChatMessagePrivate::Step::Multipart; } - EncryptionChatMessageModifier ecmm; - int retval = ecmm.encode(this); - if (retval > 0) { - sal_error_info_set((SalErrorInfo *)op->get_error_info(), SalReasonNotAcceptable, "SIP", retval, "Unable to encrypt IM", nullptr); - q->updateState(ChatMessage::State::NotDelivered); - q->store(); - return; + if ((currentSendStep & ChatMessagePrivate::Step::Encryption) == ChatMessagePrivate::Step::Encryption) { + lInfo() << "Encryption step already done, skipping"; + } else { + EncryptionChatMessageModifier ecmm; + int retval = ecmm.encode(this); + if (retval > 0) { + if (retval > 1) { + sal_error_info_set((SalErrorInfo *)op->get_error_info(), SalReasonNotAcceptable, "SIP", retval, "Unable to encrypt IM", nullptr); + q->updateState(ChatMessage::State::NotDelivered); + q->store(); + } + return; + } + currentSendStep |= ChatMessagePrivate::Step::Encryption; } - if (lp_config_get_int(chatRoom->getCore()->config, "sip", "use_cpim", 0) == 1) { - CpimChatMessageModifier ccmm; - ccmm.encode(this); + if ((currentSendStep & ChatMessagePrivate::Step::Cpim) == ChatMessagePrivate::Step::Cpim) { + lInfo() << "Cpim step already done, skipping"; + } else { + if (lp_config_get_int(chatRoom->getCore()->config, "sip", "use_cpim", 0) == 1) { + CpimChatMessageModifier ccmm; + ccmm.encode(this); + } + currentSendStep |= ChatMessagePrivate::Step::Cpim; } // --------------------------------------- @@ -1117,6 +1149,7 @@ void ChatMessagePrivate::send() { } } + //TODO Remove : This won't be necessary once we store the contentsList if (!getText().empty() && getText() == clearTextMessage) { /* We replace the encrypted message by the original one so it can be correctly stored and displayed by the application */ setText(clearTextMessage); @@ -1125,6 +1158,8 @@ void ChatMessagePrivate::send() { /* We replace the encrypted content type by the original one */ setContentType(clearTextContentType); } + //End of TODO Remove + q->setId(op->get_call_id()); /* must be known at that time */ if (call && linphone_call_get_op(call) == op) { diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 3bc88a1d5..150e19bf2 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -732,33 +732,18 @@ void ChatRoom::sendMessage (shared_ptr msg) { msg->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); - /* Check if we shall upload a file to a server */ - if (msg->getPrivate()->getFileTransferInformation() && !msg->getPrivate()->getContentType().isValid()) { - /* Open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */ - if (msg->uploadFile() == 0) { - /* Add to transient list only if message is going out */ - d->addTransientMessage(msg); - /* Store the message so that even if the upload is stopped, it can be done again */ - d->storeOrUpdateMessage(msg); + /* Add to transient list */ + d->addTransientMessage(msg); - msg->getPrivate()->setState(ChatMessage::State::InProgress); - } else { - return; - } - } else { - /* Add to transient list */ - d->addTransientMessage(msg); + msg->getPrivate()->setTime(ms_time(0)); + msg->getPrivate()->send(); - msg->getPrivate()->setTime(ms_time(0)); - msg->getPrivate()->send(); + d->storeOrUpdateMessage(msg); - d->storeOrUpdateMessage(msg); - - if (d->isComposing) - d->isComposing = false; - d->isComposingHandler.stopIdleTimer(); - d->isComposingHandler.stopRefreshTimer(); - } + if (d->isComposing) + d->isComposing = false; + d->isComposingHandler.stopIdleTimer(); + d->isComposingHandler.stopRefreshTimer(); } // ----------------------------------------------------------------------------- diff --git a/src/chat/modifier/chat-message-modifier.h b/src/chat/modifier/chat-message-modifier.h index ed4741de4..3d98de617 100644 --- a/src/chat/modifier/chat-message-modifier.h +++ b/src/chat/modifier/chat-message-modifier.h @@ -32,7 +32,24 @@ class ChatMessageModifier { public: virtual ~ChatMessageModifier () = default; + /** + * This method will be called when the message is about to be sent. + * It should check first if the internalContent is filled. + * If so, it should apply it's changes to it, otherwise it should use the contentsList. + * If it returns 0, it means everything went well. + * If it returns -1, it means it didn't change anything. + * If it returns 1, it means to abort the sending process and it will be resumed later. + * If it returns any other value > 1, it's an error code. + */ virtual int encode (ChatMessagePrivate *messagePrivate) = 0; + + /** + * This method will be called when the message is about to be received. + * It should apply it's changes to the internal content, the last modifier will take care of filling the contentsList. + * If it returns 0, it means everything went well. + * If it returns -1, it means it didn't change anything. + * If it returns any other value > 0, it's an error code. + */ virtual int decode (ChatMessagePrivate *messagePrivate) = 0; }; diff --git a/src/chat/modifier/encryption-chat-message-modifier.cpp b/src/chat/modifier/encryption-chat-message-modifier.cpp index af5b24c91..45735553d 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.cpp +++ b/src/chat/modifier/encryption-chat-message-modifier.cpp @@ -41,7 +41,7 @@ int EncryptionChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); if (cbProcessOutgoingMessage) { retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(messagePrivate->chatRoom), L_GET_C_BACK_PTR(messagePrivate->getPublic()->getSharedFromThis())); - if (retval == 0) { + if (retval == 0 || retval == 1) { messagePrivate->isSecured = true; } } diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index cdad3fc02..cf2e7dad6 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -35,6 +35,12 @@ int MultipartChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { int MultipartChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { //TODO + if (false) { // Multipart required + + } else if (messagePrivate->contents.size() == 0) { + // All previous modifiers only altered the internal content, let's fill the content list because we're the last modifier to be called + messagePrivate->contents.push_back(messagePrivate->internalContent); + } return 0; } From fefbec929fd691292f5d393ceedda9131c267e9b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 5 Oct 2017 13:33:15 +0200 Subject: [PATCH 0326/2215] Added enum as returned value by ChatMessageModifiers + error code as return parameter --- src/chat/chat-message.cpp | 40 +++++++++---------- src/chat/modifier/chat-message-modifier.h | 18 ++++----- .../modifier/cpim-chat-message-modifier.cpp | 16 ++++---- .../modifier/cpim-chat-message-modifier.h | 4 +- .../encryption-chat-message-modifier.cpp | 19 +++++++-- .../encryption-chat-message-modifier.h | 4 +- .../multipart-chat-message-modifier.cpp | 10 +++-- .../multipart-chat-message-modifier.h | 4 +- 8 files changed, 65 insertions(+), 50 deletions(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 99cb87839..a500464d6 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -969,7 +969,7 @@ void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml() LinphoneReason ChatMessagePrivate::receive() { L_Q(); - + int errorCode = 0; LinphoneReason reason = LinphoneReasonNone; bool store = false; @@ -979,34 +979,33 @@ LinphoneReason ChatMessagePrivate::receive() { if (getContentType() == ContentType::Cpim) { CpimChatMessageModifier ccmm; - ccmm.decode(this); + ccmm.decode(this, &errorCode); } EncryptionChatMessageModifier ecmm; - int retval = 0; - retval = ecmm.decode(this); - if (retval > 0) { + ChatMessageModifier::Result result = ecmm.decode(this, &errorCode); + if (result == ChatMessageModifier::Result::Error) { /* Unable to decrypt message */ chatRoom->getPrivate()->notifyUndecryptableMessageReceived(q->getSharedFromThis()); - reason = linphone_error_code_to_reason(retval); + reason = linphone_error_code_to_reason(errorCode); q->sendDeliveryNotification(reason); return reason; } MultipartChatMessageModifier mcmm; - mcmm.decode(this); + mcmm.decode(this, &errorCode); // --------------------------------------- // End of message modification // --------------------------------------- - if ((retval <= 0) && (linphone_core_is_content_type_supported(chatRoom->getCore(), getContentType().asString().c_str()) == FALSE)) { - retval = 415; + if ((errorCode <= 0) && (linphone_core_is_content_type_supported(chatRoom->getCore(), getContentType().asString().c_str()) == FALSE)) { + errorCode = 415; lError() << "Unsupported MESSAGE (content-type " << getContentType().asString() << " not recognized)"; } - if (retval > 0) { - reason = linphone_error_code_to_reason(retval); + if (errorCode > 0) { + reason = linphone_error_code_to_reason(errorCode); q->sendDeliveryNotification(reason); return reason; } @@ -1029,6 +1028,7 @@ void ChatMessagePrivate::send() { L_Q(); SalOp *op = salOp; LinphoneCall *call = NULL; + int errorCode = 0; if ((currentSendStep & ChatMessagePrivate::Step::FileUpload) == ChatMessagePrivate::Step::FileUpload) { lInfo() << "File upload step already done, skipping"; @@ -1100,7 +1100,7 @@ void ChatMessagePrivate::send() { } else { if (contents.size() > 1) { MultipartChatMessageModifier mcmm; - mcmm.encode(this); + mcmm.encode(this, &errorCode); } currentSendStep |= ChatMessagePrivate::Step::Multipart; } @@ -1109,13 +1109,13 @@ void ChatMessagePrivate::send() { lInfo() << "Encryption step already done, skipping"; } else { EncryptionChatMessageModifier ecmm; - int retval = ecmm.encode(this); - if (retval > 0) { - if (retval > 1) { - sal_error_info_set((SalErrorInfo *)op->get_error_info(), SalReasonNotAcceptable, "SIP", retval, "Unable to encrypt IM", nullptr); - q->updateState(ChatMessage::State::NotDelivered); - q->store(); - } + ChatMessageModifier::Result result = ecmm.encode(this, &errorCode); + if (result == ChatMessageModifier::Result::Error) { + sal_error_info_set((SalErrorInfo *)op->get_error_info(), SalReasonNotAcceptable, "SIP", errorCode, "Unable to encrypt IM", nullptr); + q->updateState(ChatMessage::State::NotDelivered); + q->store(); + return; + } else if (result == ChatMessageModifier::Result::Suspended) { return; } currentSendStep |= ChatMessagePrivate::Step::Encryption; @@ -1126,7 +1126,7 @@ void ChatMessagePrivate::send() { } else { if (lp_config_get_int(chatRoom->getCore()->config, "sip", "use_cpim", 0) == 1) { CpimChatMessageModifier ccmm; - ccmm.encode(this); + ccmm.encode(this, &errorCode); } currentSendStep |= ChatMessagePrivate::Step::Cpim; } diff --git a/src/chat/modifier/chat-message-modifier.h b/src/chat/modifier/chat-message-modifier.h index 3d98de617..8be047ef2 100644 --- a/src/chat/modifier/chat-message-modifier.h +++ b/src/chat/modifier/chat-message-modifier.h @@ -30,27 +30,27 @@ class ChatMessagePrivate; class ChatMessageModifier { public: + enum Result { + Skipped = -1, + Done = 0, + Suspended = 1, + Error = 2 + }; + virtual ~ChatMessageModifier () = default; /** * This method will be called when the message is about to be sent. * It should check first if the internalContent is filled. * If so, it should apply it's changes to it, otherwise it should use the contentsList. - * If it returns 0, it means everything went well. - * If it returns -1, it means it didn't change anything. - * If it returns 1, it means to abort the sending process and it will be resumed later. - * If it returns any other value > 1, it's an error code. */ - virtual int encode (ChatMessagePrivate *messagePrivate) = 0; + virtual Result encode (ChatMessagePrivate *messagePrivate, int *errorCode) = 0; /** * This method will be called when the message is about to be received. * It should apply it's changes to the internal content, the last modifier will take care of filling the contentsList. - * If it returns 0, it means everything went well. - * If it returns -1, it means it didn't change anything. - * If it returns any other value > 0, it's an error code. */ - virtual int decode (ChatMessagePrivate *messagePrivate) = 0; + virtual Result decode (ChatMessagePrivate *messagePrivate, int *errorCode) = 0; }; LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index 189f2e4a2..456ca9566 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -31,7 +31,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -int CpimChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { +ChatMessageModifier::Result CpimChatMessageModifier::encode (ChatMessagePrivate *messagePrivate, int *errorCode) { Cpim::Message message; Cpim::GenericHeader cpimContentTypeHeader; cpimContentTypeHeader.setName("Content-Type"); @@ -62,7 +62,8 @@ int CpimChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { if (!message.isValid()) { lError() << "[CPIM] Message is invalid: " << contentBody; - return 500; + *errorCode = 500; + return ChatMessageModifier::Result::Error; } else { Content newContent; ContentType newContentType("Message/CPIM"); @@ -70,10 +71,10 @@ int CpimChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { newContent.setBody(message.asString()); messagePrivate->internalContent = newContent; } - return 0; + return ChatMessageModifier::Result::Done; } -int CpimChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { +ChatMessageModifier::Result CpimChatMessageModifier::decode (ChatMessagePrivate *messagePrivate, int *errorCode) { Content content; if (!messagePrivate->internalContent.isEmpty()) { content = messagePrivate->internalContent; @@ -93,13 +94,14 @@ int CpimChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { messagePrivate->internalContent = newContent; } else { lError() << "[CPIM] Message is invalid: " << contentBody; - return 500; + *errorCode = 500; + return ChatMessageModifier::Result::Error; } } else { lError() << "[CPIM] Message is not CPIM but " << content.getContentType().asString(); - return -1; + return ChatMessageModifier::Result::Skipped; } - return 0; + return ChatMessageModifier::Result::Done; } LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/cpim-chat-message-modifier.h b/src/chat/modifier/cpim-chat-message-modifier.h index 550887808..a42b4c9c6 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.h +++ b/src/chat/modifier/cpim-chat-message-modifier.h @@ -29,8 +29,8 @@ class CpimChatMessageModifier : public ChatMessageModifier { public: CpimChatMessageModifier () = default; - int encode (ChatMessagePrivate *messagePrivate) override; - int decode (ChatMessagePrivate *messagePrivate) override; + Result encode (ChatMessagePrivate *messagePrivate, int *errorCode) override; + Result decode (ChatMessagePrivate *messagePrivate, int *errorCode) override; }; LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/encryption-chat-message-modifier.cpp b/src/chat/modifier/encryption-chat-message-modifier.cpp index 45735553d..7a7b48c24 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.cpp +++ b/src/chat/modifier/encryption-chat-message-modifier.cpp @@ -33,7 +33,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -int EncryptionChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { +ChatMessageModifier::Result EncryptionChatMessageModifier::encode (ChatMessagePrivate *messagePrivate, int *errorCode) { int retval = -1; LinphoneImEncryptionEngine *imee = messagePrivate->chatRoom->getCore()->im_encryption_engine; if (imee) { @@ -43,13 +43,19 @@ int EncryptionChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(messagePrivate->chatRoom), L_GET_C_BACK_PTR(messagePrivate->getPublic()->getSharedFromThis())); if (retval == 0 || retval == 1) { messagePrivate->isSecured = true; + if (retval == 1) { + return ChatMessageModifier::Result::Suspended; + } + return ChatMessageModifier::Result::Done; } + *errorCode = retval; + return ChatMessageModifier::Result::Error; } } - return retval; + return ChatMessageModifier::Result::Skipped; } -int EncryptionChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { +ChatMessageModifier::Result EncryptionChatMessageModifier::decode (ChatMessagePrivate *messagePrivate, int *errorCode) { int retval = -1; LinphoneImEncryptionEngine *imee = messagePrivate->chatRoom->getCore()->im_encryption_engine; if (imee) { @@ -59,10 +65,15 @@ int EncryptionChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { retval = cbProcessIncomingMessage(imee, L_GET_C_BACK_PTR(messagePrivate->chatRoom), L_GET_C_BACK_PTR(messagePrivate->getPublic()->getSharedFromThis())); if (retval == 0) { messagePrivate->isSecured = true; + return ChatMessageModifier::Result::Done; + } else if (retval == -1) { + return ChatMessageModifier::Result::Skipped; } + *errorCode = retval; + return ChatMessageModifier::Result::Error; } } - return retval; + return ChatMessageModifier::Result::Skipped; } LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/encryption-chat-message-modifier.h b/src/chat/modifier/encryption-chat-message-modifier.h index 8389236a0..8edeb34db 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.h +++ b/src/chat/modifier/encryption-chat-message-modifier.h @@ -29,8 +29,8 @@ class EncryptionChatMessageModifier : public ChatMessageModifier { public: EncryptionChatMessageModifier () = default; - int encode (ChatMessagePrivate *messagePrivate) override; - int decode (ChatMessagePrivate *messagePrivate) override; + Result encode (ChatMessagePrivate *messagePrivate, int *errorCode) override; + Result decode (ChatMessagePrivate *messagePrivate, int *errorCode) override; }; LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index cf2e7dad6..89e9b9192 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -26,22 +26,24 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -int MultipartChatMessageModifier::encode (ChatMessagePrivate *messagePrivate) { +ChatMessageModifier::Result MultipartChatMessageModifier::encode (ChatMessagePrivate *messagePrivate, int *errorCode) { if (messagePrivate->contents.size() > 1) { //TODO + return ChatMessageModifier::Result::Done; } - return 0; + return ChatMessageModifier::Result::Skipped; } -int MultipartChatMessageModifier::decode (ChatMessagePrivate *messagePrivate) { +ChatMessageModifier::Result MultipartChatMessageModifier::decode (ChatMessagePrivate *messagePrivate, int *errorCode) { //TODO if (false) { // Multipart required + return ChatMessageModifier::Result::Done; } else if (messagePrivate->contents.size() == 0) { // All previous modifiers only altered the internal content, let's fill the content list because we're the last modifier to be called messagePrivate->contents.push_back(messagePrivate->internalContent); } - return 0; + return ChatMessageModifier::Result::Skipped; } LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/multipart-chat-message-modifier.h b/src/chat/modifier/multipart-chat-message-modifier.h index 23b8dbe79..13868bd5c 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.h +++ b/src/chat/modifier/multipart-chat-message-modifier.h @@ -29,8 +29,8 @@ class MultipartChatMessageModifier : public ChatMessageModifier { public: MultipartChatMessageModifier () = default; - int encode (ChatMessagePrivate *message) override; - int decode (ChatMessagePrivate *message) override; + Result encode (ChatMessagePrivate *message, int *errorCode) override; + Result decode (ChatMessagePrivate *message, int *errorCode) override; }; LINPHONE_END_NAMESPACE From 8ee8885d6ac61d93d229488e8e8a794429166603 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 5 Oct 2017 13:51:48 +0200 Subject: [PATCH 0327/2215] Fixed issue with string not being cached in C wrapper --- src/c-wrapper/api/c-chat-message.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 92d6cec9a..c5b4c45b4 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -46,6 +46,7 @@ L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(ChatMessage, LinphoneAddress *to; // cache for shared_ptr
    LinphoneChatMessageStateChangedCb message_state_changed_cb; void* message_state_changed_user_data; + mutable string contentTypeCache; ) static void _linphone_chat_message_constructor (LinphoneChatMessage *msg) { @@ -318,7 +319,8 @@ void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChat // ============================================================================= const char * linphone_chat_message_get_content_type(LinphoneChatMessage *msg) { - return L_STRING_TO_C(L_GET_PRIVATE_FROM_C_OBJECT(msg)->getContentType().asString()); + msg->contentTypeCache = L_GET_PRIVATE_FROM_C_OBJECT(msg)->getContentType().asString(); + return L_STRING_TO_C(msg->contentTypeCache); } void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char *content_type) { From 0b5defc743c3b192ecd19440ef09ab86e1846777 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 5 Oct 2017 14:15:35 +0200 Subject: [PATCH 0328/2215] Fixed cache string in c-chat-message --- src/c-wrapper/api/c-chat-message.cpp | 11 ++++++++--- src/chat/chat-room.cpp | 8 +++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index c5b4c45b4..4668066a6 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -46,7 +46,7 @@ L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(ChatMessage, LinphoneAddress *to; // cache for shared_ptr
    LinphoneChatMessageStateChangedCb message_state_changed_cb; void* message_state_changed_user_data; - mutable string contentTypeCache; + mutable char *contentTypeCache; ) static void _linphone_chat_message_constructor (LinphoneChatMessage *msg) { @@ -60,6 +60,8 @@ static void _linphone_chat_message_destructor (LinphoneChatMessage *msg) { linphone_address_unref(msg->from); if (msg->to) linphone_address_unref(msg->to); + if (msg->contentTypeCache) + ms_free(msg->contentTypeCache); } // ============================================================================= @@ -319,8 +321,11 @@ void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChat // ============================================================================= const char * linphone_chat_message_get_content_type(LinphoneChatMessage *msg) { - msg->contentTypeCache = L_GET_PRIVATE_FROM_C_OBJECT(msg)->getContentType().asString(); - return L_STRING_TO_C(msg->contentTypeCache); + if (msg->contentTypeCache) { + ms_free(msg->contentTypeCache); + } + msg->contentTypeCache = ms_strdup(L_STRING_TO_C(L_GET_PRIVATE_FROM_C_OBJECT(msg)->getContentType().asString())); + return msg->contentTypeCache; } void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char *content_type) { diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 150e19bf2..85a583f0f 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -551,6 +551,12 @@ void ChatRoom::compose () { shared_ptr ChatRoom::createFileTransferMessage (const LinphoneContent *initialContent) { L_D(); shared_ptr chatMessage = createMessage(); + + /* TODO + Content content; + content.setContentType(ContentType::FileTransfer); + content.setBody(linphone_content_get_string_buffer(initialContent)); + chatMessage->addContent(content);*/ chatMessage->setToAddress(d->peerAddress); chatMessage->setFromAddress(linphone_core_get_identity(d->core)); @@ -565,7 +571,7 @@ shared_ptr ChatRoom::createMessage (const string &message) { shared_ptr chatMessage = createMessage(); Content content; - content.setContentType("text/plain"); + content.setContentType(ContentType::PlainText); content.setBody(message); chatMessage->addContent(content); From 39291bef25063929926460c35f9af3ee8b5f3593 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 5 Oct 2017 14:26:16 +0200 Subject: [PATCH 0329/2215] Fixed EncryptionChatMessageModifier where Skipped result wasn't returned --- src/chat/modifier/encryption-chat-message-modifier.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/chat/modifier/encryption-chat-message-modifier.cpp b/src/chat/modifier/encryption-chat-message-modifier.cpp index 7a7b48c24..963be778c 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.cpp +++ b/src/chat/modifier/encryption-chat-message-modifier.cpp @@ -47,6 +47,8 @@ ChatMessageModifier::Result EncryptionChatMessageModifier::encode (ChatMessagePr return ChatMessageModifier::Result::Suspended; } return ChatMessageModifier::Result::Done; + } else if (retval == -1) { + return ChatMessageModifier::Result::Skipped; } *errorCode = retval; return ChatMessageModifier::Result::Error; From cc739ef55643aba271258a83187eb7dd20bf31fc Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 5 Oct 2017 14:41:21 +0200 Subject: [PATCH 0330/2215] Added test (from dev_async_im_encryption_engine branch) for asynchronous IMEE + fixed issue in EncryptionChatMessageModifier --- src/chat/chat-message.cpp | 1 + tester/message_tester.c | 39 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index a500464d6..8c673c9bb 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -1116,6 +1116,7 @@ void ChatMessagePrivate::send() { q->store(); return; } else if (result == ChatMessageModifier::Result::Suspended) { + currentSendStep |= ChatMessagePrivate::Step::Encryption; return; } currentSendStep |= ChatMessagePrivate::Step::Encryption; diff --git a/tester/message_tester.c b/tester/message_tester.c index 1e93ca046..6aa7cf4ed 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -23,6 +23,7 @@ #include "lime.h" #include "bctoolbox/crypto.h" #include +#include "linphone/core_utils.h" #include #ifdef SQLITE_STORAGE_ENABLED @@ -2394,7 +2395,26 @@ static int im_encryption_engine_process_outgoing_message_cb(LinphoneImEncryption return -1; } -void im_encryption_engine_b64(void) { +static bool_t im_encryption_engine_process_outgoing_message_async_impl(LinphoneChatMessage** msg) { + if (*msg) { + im_encryption_engine_process_outgoing_message_cb(NULL,NULL,*msg); + linphone_chat_room_send_chat_message(linphone_chat_message_get_chat_room(*msg), *msg); + linphone_chat_message_unref(*msg); + *msg=NULL; + } + return TRUE; +} + +static LinphoneChatMessage* pending_message=NULL; /*limited to one message at a time */ + +static int im_encryption_engine_process_outgoing_message_async(LinphoneImEncryptionEngine *engine, LinphoneChatRoom *room, LinphoneChatMessage *msg) { + pending_message=msg; + linphone_chat_message_ref(pending_message); + linphone_core_add_iterate_hook(linphone_chat_room_get_core(room), (LinphoneCoreIterateHook)im_encryption_engine_process_outgoing_message_async_impl,&pending_message); + return 1;/*temporaly code to defer message sending*/ +} + +void im_encryption_engine_b64_base(bool_t async) { LinphoneChatMessage *chat_msg = NULL; LinphoneChatRoom* chat_room = NULL; LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); @@ -2407,7 +2427,11 @@ void im_encryption_engine_b64(void) { linphone_im_encryption_engine_cbs_set_process_incoming_message(marie_cbs, im_encryption_engine_process_incoming_message_cb); linphone_im_encryption_engine_cbs_set_process_outgoing_message(marie_cbs, im_encryption_engine_process_outgoing_message_cb); linphone_im_encryption_engine_cbs_set_process_incoming_message(pauline_cbs, im_encryption_engine_process_incoming_message_cb); - linphone_im_encryption_engine_cbs_set_process_outgoing_message(pauline_cbs, im_encryption_engine_process_outgoing_message_cb); + if (async) { + linphone_im_encryption_engine_cbs_set_process_outgoing_message(pauline_cbs, im_encryption_engine_process_outgoing_message_async); + } else { + linphone_im_encryption_engine_cbs_set_process_outgoing_message(pauline_cbs, im_encryption_engine_process_outgoing_message_cb); + } linphone_core_set_im_encryption_engine(marie->lc, marie_imee); linphone_core_set_im_encryption_engine(pauline->lc, pauline_imee); @@ -2428,6 +2452,14 @@ void im_encryption_engine_b64(void) { linphone_core_manager_destroy(pauline); } +void im_encryption_engine_b64(void) { + im_encryption_engine_b64_base(FALSE); +} + +void im_encryption_engine_b64_async(void) { + im_encryption_engine_b64_base(TRUE); +} + test_t message_tests[] = { TEST_NO_TAG("Text message", text_message), TEST_NO_TAG("Text message within call dialog", text_message_within_call_dialog), @@ -2504,7 +2536,8 @@ test_t message_tests[] = { #ifdef SQLITE_STORAGE_ENABLED TEST_ONE_TAG("Text message with custom content-type and lime", text_message_with_custom_content_type_and_lime, "LIME"), #endif - TEST_NO_TAG("IM Encryption Engine b64", im_encryption_engine_b64) + TEST_NO_TAG("IM Encryption Engine b64", im_encryption_engine_b64), + TEST_NO_TAG("IM Encryption Engine b64 async", im_encryption_engine_b64_async) }; static int message_tester_before_suite(void) { From eab04534c8677c1bd3c42d44c0c28f5ac8fa2acc Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 5 Oct 2017 14:49:24 +0200 Subject: [PATCH 0331/2215] feat(EventsDb): import messages from old db --- include/linphone/utils/utils.h | 3 + src/db/abstract/abstract-db.cpp | 17 ++ src/db/abstract/abstract-db.h | 3 + src/db/events-db.cpp | 362 +++++++++++++++++++++----------- src/db/events-db.h | 2 + src/utils/utils.cpp | 7 + 6 files changed, 271 insertions(+), 123 deletions(-) diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h index cf384f01c..5ec2c4c38 100644 --- a/include/linphone/utils/utils.h +++ b/include/linphone/utils/utils.h @@ -19,6 +19,7 @@ #ifndef _UTILS_H_ #define _UTILS_H_ +#include #include #include #include @@ -92,6 +93,8 @@ namespace Utils { static const T object; return object; } + + LINPHONE_PUBLIC std::tm getLongAsTm (long time); } LINPHONE_END_NAMESPACE diff --git a/src/db/abstract/abstract-db.cpp b/src/db/abstract/abstract-db.cpp index 1aaee41e5..ce1397191 100644 --- a/src/db/abstract/abstract-db.cpp +++ b/src/db/abstract/abstract-db.cpp @@ -60,6 +60,10 @@ AbstractDb::Backend AbstractDb::getBackend () const { return d->backend; } +bool AbstractDb::import (Backend, const string &) { + return false; +} + // ----------------------------------------------------------------------------- void AbstractDb::init () { @@ -81,4 +85,17 @@ string AbstractDb::primaryKeyAutoIncrementStr (const string &type) const { return ""; } +string AbstractDb::insertOrIgnoreStr () const { + L_D(); + + switch (d->backend) { + case Mysql: + return "INSERT IGNORE INTO "; + case Sqlite3: + return "INSERT OR IGNORE INTO "; + } + + return ""; +} + LINPHONE_END_NAMESPACE diff --git a/src/db/abstract/abstract-db.h b/src/db/abstract/abstract-db.h index ac8922077..4b64695c5 100644 --- a/src/db/abstract/abstract-db.h +++ b/src/db/abstract/abstract-db.h @@ -43,12 +43,15 @@ public: Backend getBackend () const; + virtual bool import (Backend backend, const std::string ¶meters); + protected: explicit AbstractDb (AbstractDbPrivate &p); virtual void init (); std::string primaryKeyAutoIncrementStr (const std::string &type = "INT") const; + std::string insertOrIgnoreStr () const; private: L_DECLARE_PRIVATE(AbstractDb); diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 70390fe2d..b90bcf2a2 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -17,13 +17,17 @@ */ #include +#include #ifdef SOCI_ENABLED #include #endif // ifdef SOCI_ENABLED +#include "linphone/utils/utils.h" + #include "abstract/abstract-db-p.h" #include "chat/chat-message.h" +#include "db/provider/db-session-provider.h" #include "event-log/call-event.h" #include "event-log/chat-message-event.h" #include "logger/logger.h" @@ -61,8 +65,6 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} ); } -// ----------------------------------------------------------------------------- - static constexpr EnumToSql eventFilterToSql[] = { { EventsDb::MessageFilter, "1" }, { EventsDb::CallFilter, "2" }, @@ -75,27 +77,16 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} ); } - static constexpr EnumToSql messageStateToSql[] = { - { ChatMessage::State::Idle, "1" }, - { ChatMessage::State::InProgress, "2" }, - { ChatMessage::State::Delivered, "3" }, - { ChatMessage::State::NotDelivered, "4" }, - { ChatMessage::State::FileTransferError, "5" }, - { ChatMessage::State::FileTransferDone, "6" }, - { ChatMessage::State::DeliveredToUser, "7" }, - { ChatMessage::State::Displayed, "8" } +// ----------------------------------------------------------------------------- + + struct MessageEventReferences { + long eventId; + long localSipAddressId; + long remoteSipAddressId; + long chatRoomId; + long contentTypeId; }; - static constexpr const char *mapMessageStateToSql (ChatMessage::State state) { - return mapEnumToSql( - messageStateToSql, sizeof messageStateToSql / sizeof messageStateToSql[0], state - ); - } - - static constexpr const char *mapMessageDirectionToSql (ChatMessage::Direction direction) { - return direction == ChatMessage::Direction::Incoming ? "1" : "2"; - } - // ----------------------------------------------------------------------------- static string buildSqlEventFilter (const list &filters, EventsDb::FilterMask mask) { @@ -126,6 +117,77 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return sql; } +// ----------------------------------------------------------------------------- + + static inline long insertSipAddress (soci::session &session, const string &sipAddress) { + long id; + session << "SELECT id FROM sip_address WHERE value = :sipAddress", soci::use(sipAddress), soci::into(id); + if (session.got_data()) + return id; + + session << "INSERT INTO sip_address (value) VALUES (:sipAddress)", soci::use(sipAddress); + session.get_last_insert_id("sip_address", id); + return id; + } + + static inline long insertContentType (soci::session &session, const string &contentType) { + long id; + session << "SELECT id FROM content_type WHERE value = :contentType", soci::use(contentType), soci::into(id); + if (session.got_data()) + return id; + + session << "INSERT INTO content_type (value) VALUES (:contentType)", soci::use(contentType); + session.get_last_insert_id("content_type", id); + return id; + } + + static inline long insertEvent (soci::session &session, EventLog::Type type, const tm &date) { + session << "INSERT INTO event (event_type_id, date) VALUES (:eventTypeId, :date)", + soci::use(static_cast(type)), soci::use(date); + long id; + session.get_last_insert_id("event", id); + return id; + } + + static inline long insertChatRoom (soci::session &session, long sipAddressId, const tm &date) { + long id; + session << "SELECT peer_sip_address_id FROM chat_room WHERE peer_sip_address_id = :sipAddressId", + soci::use(sipAddressId), soci::into(id); + if (!session.got_data()) + session << "INSERT INTO chat_room (peer_sip_address_id, creation_date, last_update_date, subject) VALUES" + " (:sipAddressId, :creationDate, :lastUpdateDate, '')", soci::use(sipAddressId), soci::use(date), soci::use(date); + else + session << "UPDATE chat_room SET last_update_date = :lastUpdateDate WHERE peer_sip_address_id = :sipAddressId", + soci::use(date), soci::use(sipAddressId); + return sipAddressId; + } + + static inline long insertMessageEvent ( + soci::session &session, + const MessageEventReferences &references, + ChatMessage::State state, + ChatMessage::Direction direction, + const string &imdnMessageId, + bool isSecured, + const string *text = nullptr + ) { + soci::indicator textIndicator = text ? soci::i_ok : soci::i_null; + + session << "INSERT INTO message_event (" + " event_id, chat_room_id, local_sip_address_id, remote_sip_address_id, content_type_id," + " state, direction, imdn_message_id, is_secured, text" + ") VALUES (" + " :eventId, :chatRoomId, :localSipaddressId, :remoteSipaddressId, :contentTypeId," + " :state, :direction, :imdnMessageId, :isSecured, :text" + ")", soci::use(references.eventId), soci::use(references.chatRoomId), soci::use(references.localSipAddressId), + soci::use(references.remoteSipAddressId), soci::use(references.contentTypeId), + soci::use(static_cast(state)), soci::use(static_cast(direction)), soci::use(imdnMessageId), + soci::use(isSecured ? 1 : 0), soci::use(text ? *text : string(), textIndicator); + long id; + return session.get_last_insert_id("message_event", id); + return id; + } + // ----------------------------------------------------------------------------- void EventsDb::init () { @@ -139,8 +201,8 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} ")"; *session << - "CREATE TABLE IF NOT EXISTS event_type (" - " id TINYINT UNSIGNED," + "CREATE TABLE IF NOT EXISTS content_type (" + " id" + primaryKeyAutoIncrementStr() + "," " value VARCHAR(255) UNIQUE NOT NULL" ")"; @@ -148,38 +210,23 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} "CREATE TABLE IF NOT EXISTS event (" " id" + primaryKeyAutoIncrementStr() + "," " event_type_id TINYINT UNSIGNED NOT NULL," - " timestamp TIMESTAMP NOT NULL," - " FOREIGN KEY (event_type_id)" - " REFERENCES event_type(id)" - " ON DELETE CASCADE" + " date DATE NOT NULL" ")"; *session << - "CREATE TABLE IF NOT EXISTS message_state (" - " id TINYINT UNSIGNED," - " value VARCHAR(255) UNIQUE NOT NULL" - ")"; - - *session << - "CREATE TABLE IF NOT EXISTS message_direction (" - " id TINYINT UNSIGNED," - " value VARCHAR(255) UNIQUE NOT NULL" - ")"; - - *session << - "CREATE TABLE IF NOT EXISTS dialog (" + "CREATE TABLE IF NOT EXISTS chat_room (" // Server (for conference) or user sip address. " peer_sip_address_id INT UNSIGNED PRIMARY KEY," // Dialog creation date. - " creation_timestamp TIMESTAMP NOT NULL," + " creation_date DATE NOT NULL," + + // Last event date (call, message...). + " last_update_date DATE NOT NULL," // Chatroom subject. " subject VARCHAR(255)," - // Last event timestamp (call, message...). - " last_update_timestamp TIMESTAMP NOT NULL," - " FOREIGN KEY (peer_sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" @@ -189,37 +236,47 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} "CREATE TABLE IF NOT EXISTS message_event (" " id" + primaryKeyAutoIncrementStr() + "," " event_id INT UNSIGNED NOT NULL," - " dialog_id INT UNSIGNED NOT NULL," - " state_id TINYINT UNSIGNED NOT NULL," - " direction_id TINYINT UNSIGNED NOT NULL," - " sender_sip_address_id INT UNSIGNED NOT NULL," + " chat_room_id INT UNSIGNED NOT NULL," + + " local_sip_address_id INT UNSIGNED NOT NULL," + " remote_sip_address_id INT UNSIGNED NOT NULL," + + " content_type_id INT UNSIGNED NOT NULL," // See: https://tools.ietf.org/html/rfc5438#section-6.3 " imdn_message_id VARCHAR(255) NOT NULL," + " state TINYINT UNSIGNED NOT NULL," + " direction TINYINT UNSIGNED NOT NULL," " is_secured BOOLEAN NOT NULL," - // Content type of text. (Html or text for example.) - " content_type VARCHAR(255) NOT NULL," " text TEXT," - // App user data. - " app_data VARCHAR(2048)," - " FOREIGN KEY (event_id)" " REFERENCES event(id)" " ON DELETE CASCADE," - " FOREIGN KEY (dialog_id)" - " REFERENCES dialog(peer_sip_address_id)" + " FOREIGN KEY (chat_room_id)" + " REFERENCES chat_room(peer_sip_address_id)" " ON DELETE CASCADE," - " FOREIGN KEY (state_id)" - " REFERENCES message_state(id)" - " ON DELETE CASCADE," - " FOREIGN KEY (direction_id)" - " REFERENCES message_direction(id)" - " ON DELETE CASCADE," - " FOREIGN KEY (sender_sip_address_id)" + " FOREIGN KEY (local_sip_address_id)" " REFERENCES sip_address(id)" + " ON DELETE CASCADE," + " FOREIGN KEY (remote_sip_address_id)" + " REFERENCES sip_address(id)" + " ON DELETE CASCADE," + " FOREIGN KEY (content_type_id)" + " REFERENCES content_type(id)" + " ON DELETE CASCADE" + ")"; + + *session << + "CREATE TABLE IF NOT EXISTS message_crypto_data (" + " id" + primaryKeyAutoIncrementStr() + "," + " message_event_id INT UNSIGNED NOT NULL," + " data BLOB," + + " FOREIGN KEY (message_event_id)" + " REFERENCES message_event(id)" " ON DELETE CASCADE" ")"; @@ -227,70 +284,19 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} "CREATE TABLE IF NOT EXISTS message_file_info (" " id" + primaryKeyAutoIncrementStr() + "," " message_id INT UNSIGNED NOT NULL," + " content_type_id INT UNSIGNED NOT NULL," - // File content type. - " content_type VARCHAR(255) NOT NULL," - - // File name. " name VARCHAR(255) NOT NULL," - - // File size. " size INT UNSIGNED NOT NULL," - - // File url. " url VARCHAR(255) NOT NULL," - " key VARCHAR(4096)," - " key_size INT UNSIGNED," + " FOREIGN KEY (message_id)" " REFERENCES message(id)" " ON DELETE CASCADE" + " FOREIGN KEY (content_type_id)" + " REFERENCES content_type(id)" + " ON DELETE CASCADE" ")"; - - { - string query = getBackend() == Mysql - ? "INSERT INTO event_type (id, value)" - : "INSERT OR IGNORE INTO event_type (id, value)"; - query += "VALUES" - "(1, \"Message\")," - "(2, \"Call\")," - "(3, \"Conference\")"; - if (getBackend() == Mysql) - query += "ON DUPLICATE KEY UPDATE value = VALUES(value)"; - - *session << query; - } - - { - string query = getBackend() == Mysql - ? "INSERT INTO message_direction (id, value)" - : "INSERT OR IGNORE INTO message_direction (id, value)"; - query += "VALUES" - "(1, \"Incoming\")," - "(2, \"Outgoing\")"; - if (getBackend() == Mysql) - query += "ON DUPLICATE KEY UPDATE value = VALUES(value)"; - - *session << query; - } - - { - string query = getBackend() == Mysql - ? "INSERT INTO message_state (id, value)" - : "INSERT OR IGNORE INTO message_state (id, value)"; - query += "VALUES" - "(1, \"Idle\")," - "(2, \"InProgress\")," - "(3, \"Delivered\")," - "(4, \"NotDelivered\")," - "(5, \"FileTransferError\")," - "(6, \"FileTransferDone\")," - "(7, \"DeliveredToUser\")," - "(8, \"Displayed\")"; - if (getBackend() == Mysql) - query += "ON DUPLICATE KEY UPDATE value = VALUES(value)"; - - *session << query; - } } bool EventsDb::addEvent (const EventLog &eventLog) { @@ -371,7 +377,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} string query = "SELECT COUNT(*) FROM message_event"; if (!remoteAddress.empty()) - query += " WHERE dialog_id = (" + query += " WHERE chat_room_id = (" " SELECT id FROM dialog WHERE remote_sip_address_id =(" " SELECT id FROM sip_address WHERE value = :remote_address" " )" @@ -398,13 +404,13 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} string query = "SELECT COUNT(*) FROM message_event"; if (!remoteAddress.empty()) - query += " WHERE dialog_id = (" + query += " WHERE chat_room_id = (" " SELECT id FROM dialog WHERE remote_sip_address_id = (" " SELECT id FROM sip_address WHERE value = :remote_address" " )" " )" - " AND direction_id = " + string(mapMessageDirectionToSql(ChatMessage::Incoming)) + - " AND state_id = " + string(mapMessageStateToSql(ChatMessage::State::Displayed)); + " AND direction = " + Utils::toString(static_cast(ChatMessage::Direction::Incoming)) + + " AND state = " + Utils::toString(static_cast(ChatMessage::State::Displayed)); int count = 0; L_BEGIN_LOG_EXCEPTION @@ -430,7 +436,12 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return list>(); } - list> EventsDb::getHistory (const string &remoteAddress, int begin, int end, FilterMask mask) const { + list> EventsDb::getHistory ( + const string &remoteAddress, + int begin, + int end, + FilterMask mask + ) const { if (!isConnected()) { lWarning() << "Unable to get history. Not connected."; return list>(); @@ -454,6 +465,111 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} (void)remoteAddress; } +// ----------------------------------------------------------------------------- + + template + static T getValueFromLegacyMessage (const soci::row &message, int index, bool &isNull) { + isNull = false; + + try { + return message.get(index); + } catch (const exception &) { + isNull = true; + } + + return T(); + } + + static void importLegacyMessages ( + soci::session *session, + const string &insertOrIgnoreStr, + const soci::rowset &messages + ) { + soci::transaction tr(*session); + + for (const auto &message : messages) { + const int direction = message.get(3) + 1; + if (direction != 1 && direction != 2) { + lWarning() << "Unable to import legacy message with invalid direction."; + return; + } + + const int state = message.get(7, static_cast(ChatMessage::State::Displayed)); + + const tm date = Utils::getLongAsTm(message.get(9, 0)); + + const bool noUrl = false; + const string url = getValueFromLegacyMessage(message, 8, const_cast(noUrl)); + + const string contentType = message.get( + 13, + message.get(11, -1) != -1 + ? "application/vnd.gsma.rcs-ft-http+xml" + : (noUrl ? "text/plain" : "message/external-body") + ); + + const bool noText = false; + const string text = getValueFromLegacyMessage(message, 4, const_cast(noText)); + + struct MessageEventReferences references; + references.eventId = insertEvent(*session, EventLog::Type::ChatMessage, date); + references.localSipAddressId = insertSipAddress(*session, message.get(1)); + references.remoteSipAddressId = insertSipAddress(*session, message.get(2)); + references.chatRoomId = insertChatRoom(*session, references.remoteSipAddressId, date); + references.contentTypeId = insertContentType(*session, contentType); + + insertMessageEvent ( + *session, + references, + static_cast(state), + static_cast(direction), + message.get(12, ""), + !!message.get(14, 0), + noText ? nullptr : &text + ); + + const bool noAppData = false; + const string appData = getValueFromLegacyMessage(message, 10, const_cast(noAppData)); + (void)text; + (void)appData; + } + + tr.commit(); + } + + bool EventsDb::import (Backend, const string ¶meters) { + L_D(); + + // Backend is useless, it's sqlite3. (Only available legacy backend.) + const string uri = "sqlite3://" + parameters; + DbSession inDbSession = DbSessionProvider::getInstance()->getSession(uri); + + if (!inDbSession) { + lWarning() << "Unable to connect to: `" << uri << "`."; + return false; + } + + soci::session *outSession = d->dbSession.getBackendSession(); + soci::session *inSession = inDbSession.getBackendSession(); + + // Import messages. + try { + soci::rowset messages = (inSession->prepare << "SELECT * FROM history ORDER BY id DESC"); + try { + importLegacyMessages(outSession, insertOrIgnoreStr(), messages); + } catch (const exception &e) { + lInfo() << "Failed to import legacy messages from: `" << uri << "`. (" << e.what() << ")"; + return false; + } + lInfo() << "Successful import of legacy messages from: `" << uri << "`."; + } catch (const exception &) { + // Table doesn't exist. + return false; + } + + return true; + } + // ----------------------------------------------------------------------------- // No backend. // ----------------------------------------------------------------------------- diff --git a/src/db/events-db.h b/src/db/events-db.h index 6ca7f2a91..2c3819b78 100644 --- a/src/db/events-db.h +++ b/src/db/events-db.h @@ -65,6 +65,8 @@ public: ) const; void cleanHistory (const std::string &remoteAddress = ""); + bool import (Backend backend, const std::string ¶meters) override; + protected: void init () override; diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 471d0d1b4..1ed4f9fee 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -170,4 +170,11 @@ char *Utils::utf8ToChar (uint32_t ic) { return result; } +// ----------------------------------------------------------------------------- + +tm Utils::getLongAsTm (long time) { + tm result; + return *gmtime_r(&static_cast(time), &result); +} + LINPHONE_END_NAMESPACE From 18ed78a46e622608879c49662705e5c7e0c144c0 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 5 Oct 2017 15:08:41 +0200 Subject: [PATCH 0332/2215] Prevent duplicates when adding participants to a conference. --- src/conference/conference.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 95ff53e24..8773ea5e9 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -45,8 +45,14 @@ void Conference::addParticipant (const Address &addr, const CallSessionParams *p } void Conference::addParticipants (const list
    &addresses, const CallSessionParams *params, bool hasMedia) { - for (const auto &addr : addresses) - addParticipant(addr, params, hasMedia); + list
    sortedAddresses(addresses); + sortedAddresses.sort(); + sortedAddresses.unique(); + for (const auto &addr: sortedAddresses) { + shared_ptr participant = findParticipant(addr); + if (!participant) + addParticipant(addr, params, hasMedia); + } } bool Conference::canHandleParticipants () const { From 81340cfcb87af4510862bd20cb81039d95cd3f6a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 5 Oct 2017 15:08:55 +0200 Subject: [PATCH 0333/2215] Fix license headers. --- include/linphone/api/c-address.h | 21 ++++++------ include/linphone/api/c-api.h | 22 ++++++++---- include/linphone/api/c-call-cbs.h | 13 +++---- include/linphone/api/c-call-stats.h | 13 +++---- include/linphone/api/c-call.h | 13 +++---- include/linphone/api/c-callbacks.h | 13 +++---- include/linphone/api/c-chat-message-cbs.h | 13 +++---- include/linphone/api/c-chat-message.h | 13 +++---- include/linphone/api/c-chat-room-cbs.h | 13 +++---- include/linphone/api/c-chat-room.h | 13 +++---- include/linphone/api/c-event-log.h | 15 ++++---- include/linphone/api/c-participant.h | 13 +++---- include/linphone/api/c-types.h | 13 +++---- include/linphone/enums/chat-message-enums.h | 15 ++++---- include/linphone/enums/chat-room-enums.h | 13 +++---- include/linphone/enums/event-log-enums.h | 13 +++---- include/linphone/utils/enum-generator.h | 13 +++---- include/linphone/utils/general.h | 13 +++---- include/linphone/utils/magic-macros.h | 13 +++---- include/linphone/utils/private-access.h | 13 +++---- include/linphone/utils/utils.h | 13 +++---- src/address/address-p.h | 13 +++---- src/address/address.cpp | 15 ++++---- src/address/address.h | 13 +++---- src/c-wrapper/api/c-address.cpp | 15 ++++---- src/c-wrapper/api/c-call-cbs.cpp | 13 +++---- src/c-wrapper/api/c-call-params.cpp | 13 +++---- src/c-wrapper/api/c-call-stats.cpp | 13 +++---- src/c-wrapper/api/c-call.cpp | 13 +++---- src/c-wrapper/api/c-chat-message-cbs.cpp | 13 +++---- src/c-wrapper/api/c-chat-message.cpp | 13 +++---- src/c-wrapper/api/c-chat-room-cbs.cpp | 13 +++---- src/c-wrapper/api/c-chat-room.cpp | 13 +++---- src/c-wrapper/api/c-event-log.cpp | 13 +++---- src/c-wrapper/api/c-participant.cpp | 13 +++---- src/c-wrapper/c-wrapper.h | 13 +++---- src/c-wrapper/internal/c-sal.cpp | 34 +++++++++---------- src/c-wrapper/internal/c-sal.h | 34 +++++++++---------- src/c-wrapper/internal/c-tools.h | 15 ++++---- src/call/call-listener.h | 13 +++---- src/call/call-p.h | 13 +++---- src/call/call.cpp | 13 +++---- src/call/call.h | 13 +++---- src/chat/basic-chat-room-p.h | 13 +++---- src/chat/basic-chat-room.cpp | 13 +++---- src/chat/basic-chat-room.h | 13 +++---- src/chat/chat-message-p.h | 13 +++---- src/chat/chat-message.cpp | 13 +++---- src/chat/chat-message.h | 13 +++---- src/chat/chat-room-p.h | 13 +++---- src/chat/chat-room.cpp | 13 +++---- src/chat/chat-room.h | 13 +++---- src/chat/client-group-chat-room-p.h | 13 +++---- src/chat/client-group-chat-room.cpp | 13 +++---- src/chat/client-group-chat-room.h | 13 +++---- src/chat/cpim/cpim.h | 13 +++---- src/chat/cpim/header/cpim-core-headers.cpp | 13 +++---- src/chat/cpim/header/cpim-core-headers.h | 13 +++---- src/chat/cpim/header/cpim-generic-header.cpp | 13 +++---- src/chat/cpim/header/cpim-generic-header.h | 13 +++---- src/chat/cpim/header/cpim-header-p.h | 13 +++---- src/chat/cpim/header/cpim-header.cpp | 13 +++---- src/chat/cpim/header/cpim-header.h | 13 +++---- src/chat/cpim/message/cpim-message.cpp | 13 +++---- src/chat/cpim/message/cpim-message.h | 13 +++---- src/chat/cpim/parser/cpim-grammar.cpp | 13 +++---- src/chat/cpim/parser/cpim-grammar.h | 13 +++---- src/chat/cpim/parser/cpim-parser.cpp | 13 +++---- src/chat/cpim/parser/cpim-parser.h | 13 +++---- src/chat/imdn.cpp | 13 +++---- src/chat/imdn.h | 13 +++---- src/chat/is-composing-listener.h | 13 +++---- src/chat/is-composing.cpp | 13 +++---- src/chat/is-composing.h | 13 +++---- src/chat/modifier/chat-message-modifier.h | 13 +++---- .../modifier/cpim-chat-message-modifier.cpp | 13 +++---- .../modifier/cpim-chat-message-modifier.h | 13 +++---- .../encryption-chat-message-modifier.cpp | 13 +++---- .../encryption-chat-message-modifier.h | 13 +++---- .../multipart-chat-message-modifier.cpp | 13 +++---- .../multipart-chat-message-modifier.h | 13 +++---- src/chat/real-time-text-chat-room-p.h | 13 +++---- src/chat/real-time-text-chat-room.cpp | 15 ++++---- src/chat/real-time-text-chat-room.h | 13 +++---- src/conference/conference-interface.h | 13 +++---- src/conference/conference-listener.h | 15 ++++---- src/conference/conference.cpp | 13 +++---- src/conference/conference.h | 13 +++---- .../local-conference-event-handler.cpp | 13 +++---- .../local-conference-event-handler.h | 13 +++---- src/conference/local-conference.cpp | 13 +++---- src/conference/local-conference.h | 13 +++---- src/conference/params/call-session-params-p.h | 15 ++++---- src/conference/params/call-session-params.cpp | 13 +++---- src/conference/params/call-session-params.h | 13 +++---- .../params/media-session-params-p.h | 13 +++---- .../params/media-session-params.cpp | 13 +++---- src/conference/params/media-session-params.h | 13 +++---- src/conference/participant-p.h | 13 +++---- src/conference/participant.cpp | 13 +++---- src/conference/participant.h | 13 +++---- .../remote-conference-event-handler.cpp | 13 +++---- .../remote-conference-event-handler.h | 13 +++---- src/conference/remote-conference.cpp | 13 +++---- src/conference/remote-conference.h | 13 +++---- .../session/call-session-listener.h | 13 +++---- src/conference/session/call-session-p.h | 13 +++---- src/conference/session/call-session.cpp | 13 +++---- src/conference/session/call-session.h | 13 +++---- src/conference/session/media-session-p.h | 13 +++---- src/conference/session/media-session.cpp | 13 +++---- src/conference/session/media-session.h | 13 +++---- src/conference/session/port-config.h | 13 +++---- src/content/content-type.cpp | 13 +++---- src/content/content-type.h | 13 +++---- src/content/content.cpp | 13 +++---- src/content/content.h | 13 +++---- src/core/core.cpp | 13 +++---- src/core/core.h | 13 +++---- src/db/abstract/abstract-db-p.h | 13 +++---- src/db/abstract/abstract-db.cpp | 13 +++---- src/db/abstract/abstract-db.h | 13 +++---- src/db/events-db.cpp | 13 +++---- src/db/events-db.h | 13 +++---- src/db/provider/db-session-p.h | 13 +++---- src/db/provider/db-session-provider.cpp | 13 +++---- src/db/provider/db-session-provider.h | 13 +++---- src/db/provider/db-session.cpp | 13 +++---- src/db/provider/db-session.h | 13 +++---- src/enums.h | 13 +++---- src/event-log/call-event.cpp | 13 +++---- src/event-log/call-event.h | 13 +++---- src/event-log/chat-message-event.cpp | 13 +++---- src/event-log/chat-message-event.h | 13 +++---- src/event-log/conference-event-p.h | 13 +++---- src/event-log/conference-event.cpp | 13 +++---- src/event-log/conference-event.h | 13 +++---- .../conference-participant-event.cpp | 13 +++---- src/event-log/conference-participant-event.h | 13 +++---- src/event-log/event-log-p.h | 13 +++---- src/event-log/event-log.cpp | 13 +++---- src/event-log/event-log.h | 13 +++---- src/hacks/hacks.cpp | 15 ++++---- src/hacks/hacks.h | 13 +++---- src/logger/logger.cpp | 13 +++---- src/logger/logger.h | 13 +++---- src/nat/ice-agent.cpp | 13 +++---- src/nat/ice-agent.h | 13 +++---- src/nat/stun-client.cpp | 13 +++---- src/nat/stun-client.h | 13 +++---- src/object/clonable-object-p.h | 13 +++---- src/object/clonable-object.cpp | 13 +++---- src/object/clonable-object.h | 13 +++---- src/object/object-p.h | 13 +++---- src/object/object.cpp | 13 +++---- src/object/object.h | 13 +++---- src/object/property-container.cpp | 13 +++---- src/object/property-container.h | 13 +++---- src/object/singleton.h | 13 +++---- src/sal/call-op.cpp | 13 +++---- src/sal/call-op.h | 13 +++---- src/sal/event-op.cpp | 13 +++---- src/sal/event-op.h | 13 +++---- src/sal/message-op-interface.h | 13 +++---- src/sal/message-op.cpp | 13 +++---- src/sal/message-op.h | 13 +++---- src/sal/op.cpp | 13 +++---- src/sal/op.h | 14 ++++---- src/sal/presence-op.cpp | 13 +++---- src/sal/presence-op.h | 13 +++---- src/sal/register-op.cpp | 13 +++---- src/sal/register-op.h | 13 +++---- src/sal/sal.cpp | 13 +++---- src/sal/sal.h | 13 +++---- src/utils/general.cpp | 13 +++---- src/utils/payload-type-handler.cpp | 13 +++---- src/utils/payload-type-handler.h | 13 +++---- src/utils/utils.cpp | 13 +++---- src/variant/variant.cpp | 15 ++++---- src/variant/variant.h | 13 +++---- src/xml/generate.py | 2 +- 181 files changed, 1304 insertions(+), 1118 deletions(-) diff --git a/include/linphone/api/c-address.h b/include/linphone/api/c-address.h index 29312aa7f..4648be378 100644 --- a/include/linphone/api/c-address.h +++ b/include/linphone/api/c-address.h @@ -1,11 +1,11 @@ /* - * c-event-log.h - * Copyright (C) 2017 Belledonne Communications SARL + * c-address.h + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,11 +13,12 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef _C_EVENT_LOG_H_ -#define _C_EVENT_LOG_H_ +#ifndef _C_ADDRESS_H_ +#define _C_ADDRESS_H_ #include "linphone/api/c-types.h" @@ -239,4 +240,4 @@ LINPHONE_DEPRECATED LINPHONE_PUBLIC bool_t linphone_address_is_secure (const Lin } #endif // ifdef __cplusplus -#endif // ifndef _C_EVENT_LOG_H_ +#endif // ifndef _C_ADDRESS_H_ diff --git a/include/linphone/api/c-api.h b/include/linphone/api/c-api.h index 6f6433104..1224497e6 100644 --- a/include/linphone/api/c-api.h +++ b/include/linphone/api/c-api.h @@ -1,11 +1,11 @@ /* * c-api.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,16 +13,26 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _C_API_H_ #define _C_API_H_ +#include "linphone/utils/general.h" + #include "linphone/api/c-address.h" +#include "linphone/api/c-call.h" +#include "linphone/api/c-call-cbs.h" +#include "linphone/api/c-call-stats.h" +#include "linphone/api/c-callbacks.h" #include "linphone/api/c-chat-message.h" +#include "linphone/api/c-chat-message-cbs.h" #include "linphone/api/c-chat-room.h" +#include "linphone/api/c-chat-room-cbs.h" #include "linphone/api/c-event-log.h" #include "linphone/api/c-participant.h" +#include "linphone/api/c-types.h" #endif // ifndef _C_API_H_ diff --git a/include/linphone/api/c-call-cbs.h b/include/linphone/api/c-call-cbs.h index 25e37dbbe..b7bd9a1fb 100644 --- a/include/linphone/api/c-call-cbs.h +++ b/include/linphone/api/c-call-cbs.h @@ -1,11 +1,11 @@ /* * c-call-cbs.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _C_CALL_CBS_H_ diff --git a/include/linphone/api/c-call-stats.h b/include/linphone/api/c-call-stats.h index 0d631f652..ff3b95e30 100644 --- a/include/linphone/api/c-call-stats.h +++ b/include/linphone/api/c-call-stats.h @@ -1,11 +1,11 @@ /* * c-call-stats.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _C_CALL_STATS_H_ diff --git a/include/linphone/api/c-call.h b/include/linphone/api/c-call.h index 4087a6480..fe3c2c768 100644 --- a/include/linphone/api/c-call.h +++ b/include/linphone/api/c-call.h @@ -1,11 +1,11 @@ /* * c-call.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _C_CALL_H_ diff --git a/include/linphone/api/c-callbacks.h b/include/linphone/api/c-callbacks.h index a6f6f0084..359cfa9db 100644 --- a/include/linphone/api/c-callbacks.h +++ b/include/linphone/api/c-callbacks.h @@ -1,11 +1,11 @@ /* * c-callbacks.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _C_CALLBACKS_H_ diff --git a/include/linphone/api/c-chat-message-cbs.h b/include/linphone/api/c-chat-message-cbs.h index 3bfac6b14..a86cd5785 100644 --- a/include/linphone/api/c-chat-message-cbs.h +++ b/include/linphone/api/c-chat-message-cbs.h @@ -1,11 +1,11 @@ /* * c-chat-message-cbs.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _C_CHAT_MESSAGE_CBS_H_ diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index 90ecd2ef4..d3ef10486 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -1,11 +1,11 @@ /* * c-chat-message.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _C_CHAT_MESSAGE_H_ diff --git a/include/linphone/api/c-chat-room-cbs.h b/include/linphone/api/c-chat-room-cbs.h index 62ffae9c7..e3eeede9c 100644 --- a/include/linphone/api/c-chat-room-cbs.h +++ b/include/linphone/api/c-chat-room-cbs.h @@ -1,11 +1,11 @@ /* * c-chat-room-cbs.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _C_CHAT_ROOM_CBS_H_ diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index af54a32cf..fe8af1023 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -1,11 +1,11 @@ /* * c-chat-room.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _C_CHAT_ROOM_H_ diff --git a/include/linphone/api/c-event-log.h b/include/linphone/api/c-event-log.h index 2f4cd097f..f800373c5 100644 --- a/include/linphone/api/c-event-log.h +++ b/include/linphone/api/c-event-log.h @@ -1,11 +1,11 @@ /* * c-event-log.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _C_EVENT_LOG_H_ @@ -27,7 +28,7 @@ extern "C" { #endif // ifdef __cplusplus -LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_new (); +LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_new (void); LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_clone (const LinphoneEventLog *event_log); LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_ref (LinphoneEventLog *event_log); LINPHONE_PUBLIC LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *event_log); diff --git a/include/linphone/api/c-participant.h b/include/linphone/api/c-participant.h index f09789ce5..bdc3054c4 100644 --- a/include/linphone/api/c-participant.h +++ b/include/linphone/api/c-participant.h @@ -1,11 +1,11 @@ /* * c-participant.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _C_PARTICIPANT_H_ diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index 3b7148b3f..92ce261f3 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -1,11 +1,11 @@ /* * c-types.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _C_TYPES_H_ diff --git a/include/linphone/enums/chat-message-enums.h b/include/linphone/enums/chat-message-enums.h index a069b6989..f98f9fe7f 100644 --- a/include/linphone/enums/chat-message-enums.h +++ b/include/linphone/enums/chat-message-enums.h @@ -1,11 +1,11 @@ /* - * chat-room-enums.h - * Copyright (C) 2017 Belledonne Communications SARL + * chat-message-enums.h + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CHAT_MESSAGE_ENUMS_H_ diff --git a/include/linphone/enums/chat-room-enums.h b/include/linphone/enums/chat-room-enums.h index 7d67728cb..fd83868ae 100644 --- a/include/linphone/enums/chat-room-enums.h +++ b/include/linphone/enums/chat-room-enums.h @@ -1,11 +1,11 @@ /* * chat-room-enums.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CHAT_ROOM_ENUMS_H_ diff --git a/include/linphone/enums/event-log-enums.h b/include/linphone/enums/event-log-enums.h index b71606f6b..b854d5cbf 100644 --- a/include/linphone/enums/event-log-enums.h +++ b/include/linphone/enums/event-log-enums.h @@ -1,11 +1,11 @@ /* * event-log-enums.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _EVENT_LOG_ENUMS_H_ diff --git a/include/linphone/utils/enum-generator.h b/include/linphone/utils/enum-generator.h index 9629b5767..246834782 100644 --- a/include/linphone/utils/enum-generator.h +++ b/include/linphone/utils/enum-generator.h @@ -1,11 +1,11 @@ /* * enum-generator.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _ENUM_GENERATOR_H_ diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index bfef0a83f..71f444cd7 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -1,11 +1,11 @@ /* * general.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _GENERAL_H_ diff --git a/include/linphone/utils/magic-macros.h b/include/linphone/utils/magic-macros.h index 7a30256b5..0042925be 100644 --- a/include/linphone/utils/magic-macros.h +++ b/include/linphone/utils/magic-macros.h @@ -1,11 +1,11 @@ /* * magic-macros.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _MAGIC_MACROS_H_ diff --git a/include/linphone/utils/private-access.h b/include/linphone/utils/private-access.h index 8d907f2d0..1dd7dffa6 100644 --- a/include/linphone/utils/private-access.h +++ b/include/linphone/utils/private-access.h @@ -1,11 +1,11 @@ /* * private-access.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // ============================================================================= diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h index 5ec2c4c38..91d36cc53 100644 --- a/include/linphone/utils/utils.h +++ b/include/linphone/utils/utils.h @@ -1,11 +1,11 @@ /* * utils.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _UTILS_H_ diff --git a/src/address/address-p.h b/src/address/address-p.h index b48a58c7f..8dac81823 100644 --- a/src/address/address-p.h +++ b/src/address/address-p.h @@ -1,11 +1,11 @@ /* * address-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _ADDRESS_P_H_ diff --git a/src/address/address.cpp b/src/address/address.cpp index 3956b61bb..3220bbc58 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -1,19 +1,20 @@ /* * address.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY {} without even the implied warranty of + * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/utils/utils.h" diff --git a/src/address/address.h b/src/address/address.h index 134f7601b..e8ab35c8f 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -1,11 +1,11 @@ /* * address.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _ADDRESS_H_ diff --git a/src/c-wrapper/api/c-address.cpp b/src/c-wrapper/api/c-address.cpp index b1f603a65..be302f841 100644 --- a/src/c-wrapper/api/c-address.cpp +++ b/src/c-wrapper/api/c-address.cpp @@ -1,11 +1,11 @@ /* - * c-event-log.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * c-address.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "address/address.h" diff --git a/src/c-wrapper/api/c-call-cbs.cpp b/src/c-wrapper/api/c-call-cbs.cpp index 241be5ab7..a8dfd605b 100644 --- a/src/c-wrapper/api/c-call-cbs.cpp +++ b/src/c-wrapper/api/c-call-cbs.cpp @@ -1,11 +1,11 @@ /* * c-call-cbs.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/api/c-call-cbs.h" diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index a6c55f39a..a02639025 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -1,11 +1,11 @@ /* * c-call-params.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "c-wrapper/c-wrapper.h" diff --git a/src/c-wrapper/api/c-call-stats.cpp b/src/c-wrapper/api/c-call-stats.cpp index aa63cd2fd..50caec3f8 100644 --- a/src/c-wrapper/api/c-call-stats.cpp +++ b/src/c-wrapper/api/c-call-stats.cpp @@ -1,11 +1,11 @@ /* * c-call-stats.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/api/c-call-stats.h" diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index aef5da3ff..bc33b1ae5 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -1,11 +1,11 @@ /* * c-call.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/api/c-call.h" diff --git a/src/c-wrapper/api/c-chat-message-cbs.cpp b/src/c-wrapper/api/c-chat-message-cbs.cpp index cecd05c63..d8f1908b8 100644 --- a/src/c-wrapper/api/c-chat-message-cbs.cpp +++ b/src/c-wrapper/api/c-chat-message-cbs.cpp @@ -1,11 +1,11 @@ /* * c-chat-message-cbs.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/api/c-chat-message-cbs.h" diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 4668066a6..9e02fee9a 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -1,11 +1,11 @@ /* * c-chat-message.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/api/c-chat-message.h" diff --git a/src/c-wrapper/api/c-chat-room-cbs.cpp b/src/c-wrapper/api/c-chat-room-cbs.cpp index 760ce31dc..3dd1d4340 100644 --- a/src/c-wrapper/api/c-chat-room-cbs.cpp +++ b/src/c-wrapper/api/c-chat-room-cbs.cpp @@ -1,11 +1,11 @@ /* * c-chat-room-cbs.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/api/c-chat-room-cbs.h" diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 8d5ea33b5..9df110d4e 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -1,11 +1,11 @@ /* * c-chat-room.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // TODO: Remove me later. diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index c1f54e3d0..dbcde10a8 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -1,11 +1,11 @@ /* * c-event-log.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/api/c-chat-message.h" diff --git a/src/c-wrapper/api/c-participant.cpp b/src/c-wrapper/api/c-participant.cpp index 1c1a00516..eb6c18814 100644 --- a/src/c-wrapper/api/c-participant.cpp +++ b/src/c-wrapper/api/c-participant.cpp @@ -1,11 +1,11 @@ /* * c-participant.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/api/c-participant.h" diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index 531f03f0a..9a2ef349f 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -1,11 +1,11 @@ /* * c-wrapper.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _C_WRAPPER_H_ diff --git a/src/c-wrapper/internal/c-sal.cpp b/src/c-wrapper/internal/c-sal.cpp index 002dbe523..32a1633bb 100644 --- a/src/c-wrapper/internal/c-sal.cpp +++ b/src/c-wrapper/internal/c-sal.cpp @@ -1,21 +1,21 @@ /* -linphone -Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ + * c-sal.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ /** This file contains SAL API functions that do not depend on the underlying implementation (like belle-sip). diff --git a/src/c-wrapper/internal/c-sal.h b/src/c-wrapper/internal/c-sal.h index 37ca7f84e..7c4d5d1a5 100644 --- a/src/c-wrapper/internal/c-sal.h +++ b/src/c-wrapper/internal/c-sal.h @@ -1,21 +1,21 @@ /* -linphone -Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ + * c-sal.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ /** This header files defines the Signaling Abstraction Layer. diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 030eefe14..6f3a09687 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -1,11 +1,11 @@ /* - * c-wrapper.h - * Copyright (C) 2017 Belledonne Communications SARL + * c-tools.h + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _C_TOOLS_H_ diff --git a/src/call/call-listener.h b/src/call/call-listener.h index 11680c334..6a2feab41 100644 --- a/src/call/call-listener.h +++ b/src/call/call-listener.h @@ -1,11 +1,11 @@ /* * call-listener.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CALL_LISTENER_H_ diff --git a/src/call/call-p.h b/src/call/call-p.h index 69586713c..1bc0c420c 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -1,11 +1,11 @@ /* * call-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CALL_P_H_ diff --git a/src/call/call.cpp b/src/call/call.cpp index 85e9e92ba..1d3ded3e7 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -1,11 +1,11 @@ /* * call.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "call-p.h" diff --git a/src/call/call.h b/src/call/call.h index 2cf6a08da..ee10154f8 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -1,11 +1,11 @@ /* * call.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CALL_CALL_H_ diff --git a/src/chat/basic-chat-room-p.h b/src/chat/basic-chat-room-p.h index 056ba79f1..0d7a736cb 100644 --- a/src/chat/basic-chat-room-p.h +++ b/src/chat/basic-chat-room-p.h @@ -1,11 +1,11 @@ /* * basic-chat-room-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _BASIC_CHAT_ROOM_P_H_ diff --git a/src/chat/basic-chat-room.cpp b/src/chat/basic-chat-room.cpp index 94a30f7ae..0ceccf09e 100644 --- a/src/chat/basic-chat-room.cpp +++ b/src/chat/basic-chat-room.cpp @@ -1,11 +1,11 @@ /* * basic-chat-room.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "basic-chat-room-p.h" diff --git a/src/chat/basic-chat-room.h b/src/chat/basic-chat-room.h index eac039d58..361a972f6 100644 --- a/src/chat/basic-chat-room.h +++ b/src/chat/basic-chat-room.h @@ -1,11 +1,11 @@ /* * basic-chat-room.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _BASIC_CHAT_ROOM_H_ diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index f31ffc0b9..953e9b57d 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -1,11 +1,11 @@ /* * chat-message-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CHAT_MESSAGE_P_H_ diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 8c673c9bb..c434a0dcf 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -1,11 +1,11 @@ /* * chat-message.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "db/events-db.h" diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index 09bc267cf..9aca23808 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -1,11 +1,11 @@ /* * chat-message.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CHAT_MESSAGE_H_ diff --git a/src/chat/chat-room-p.h b/src/chat/chat-room-p.h index 4bcd6792a..592e5f5fd 100644 --- a/src/chat/chat-room-p.h +++ b/src/chat/chat-room-p.h @@ -1,11 +1,11 @@ /* * chat-room-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CHAT_ROOM_P_H_ diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 85a583f0f..c191040bd 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -1,11 +1,11 @@ /* * chat-room.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/src/chat/chat-room.h b/src/chat/chat-room.h index 781b3a303..09061e789 100644 --- a/src/chat/chat-room.h +++ b/src/chat/chat-room.h @@ -1,11 +1,11 @@ /* * chat-room.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CHAT_ROOM_H_ diff --git a/src/chat/client-group-chat-room-p.h b/src/chat/client-group-chat-room-p.h index 416dd29b0..7bc90bac5 100644 --- a/src/chat/client-group-chat-room-p.h +++ b/src/chat/client-group-chat-room-p.h @@ -1,11 +1,11 @@ /* * client-group-chat-room-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CLIENT_GROUP_CHAT_ROOM_P_H_ diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 6cb6e9b0a..c0cb30abe 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -1,11 +1,11 @@ /* * client-group-chat-room.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "address/address-p.h" diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index 7a12fd0f3..e5faf94d3 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -1,11 +1,11 @@ /* * client-group-chat-room.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CLIENT_GROUP_CHAT_ROOM_H_ diff --git a/src/chat/cpim/cpim.h b/src/chat/cpim/cpim.h index a2aa0a824..6cadc92ed 100644 --- a/src/chat/cpim/cpim.h +++ b/src/chat/cpim/cpim.h @@ -1,11 +1,11 @@ /* * cpim.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CPIM_H_ diff --git a/src/chat/cpim/header/cpim-core-headers.cpp b/src/chat/cpim/header/cpim-core-headers.cpp index 866a3791c..2673f3b6e 100644 --- a/src/chat/cpim/header/cpim-core-headers.cpp +++ b/src/chat/cpim/header/cpim-core-headers.cpp @@ -1,11 +1,11 @@ /* * cpim-core-headers.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "chat/cpim/parser/cpim-parser.h" diff --git a/src/chat/cpim/header/cpim-core-headers.h b/src/chat/cpim/header/cpim-core-headers.h index 15519e5b5..55bb51f0b 100644 --- a/src/chat/cpim/header/cpim-core-headers.h +++ b/src/chat/cpim/header/cpim-core-headers.h @@ -1,11 +1,11 @@ /* * cpim-core-headers.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CPIM_CORE_HEADERS_H_ diff --git a/src/chat/cpim/header/cpim-generic-header.cpp b/src/chat/cpim/header/cpim-generic-header.cpp index 15ea98173..dcce38199 100644 --- a/src/chat/cpim/header/cpim-generic-header.cpp +++ b/src/chat/cpim/header/cpim-generic-header.cpp @@ -1,11 +1,11 @@ /* * cpim-generic-header.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/src/chat/cpim/header/cpim-generic-header.h b/src/chat/cpim/header/cpim-generic-header.h index 259e60046..b2cdcaf6b 100644 --- a/src/chat/cpim/header/cpim-generic-header.h +++ b/src/chat/cpim/header/cpim-generic-header.h @@ -1,11 +1,11 @@ /* * cpim-generic-header.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CPIM_GENERIC_HEADER_H_ diff --git a/src/chat/cpim/header/cpim-header-p.h b/src/chat/cpim/header/cpim-header-p.h index af1606b12..b0bc61753 100644 --- a/src/chat/cpim/header/cpim-header-p.h +++ b/src/chat/cpim/header/cpim-header-p.h @@ -1,11 +1,11 @@ /* * cpim-header-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CPIM_HEADER_P_H_ diff --git a/src/chat/cpim/header/cpim-header.cpp b/src/chat/cpim/header/cpim-header.cpp index 8bc6e9fb3..558fabef1 100644 --- a/src/chat/cpim/header/cpim-header.cpp +++ b/src/chat/cpim/header/cpim-header.cpp @@ -1,11 +1,11 @@ /* * cpim-header.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "cpim-header-p.h" diff --git a/src/chat/cpim/header/cpim-header.h b/src/chat/cpim/header/cpim-header.h index 3a0d9d91c..192b9034a 100644 --- a/src/chat/cpim/header/cpim-header.h +++ b/src/chat/cpim/header/cpim-header.h @@ -1,11 +1,11 @@ /* * cpim-header.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CPIM_HEADER_H_ diff --git a/src/chat/cpim/message/cpim-message.cpp b/src/chat/cpim/message/cpim-message.cpp index 64d63a9f2..871dd83ba 100644 --- a/src/chat/cpim/message/cpim-message.cpp +++ b/src/chat/cpim/message/cpim-message.cpp @@ -1,11 +1,11 @@ /* * cpim-message.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/src/chat/cpim/message/cpim-message.h b/src/chat/cpim/message/cpim-message.h index 0ddf36d69..78a6ef501 100644 --- a/src/chat/cpim/message/cpim-message.h +++ b/src/chat/cpim/message/cpim-message.h @@ -1,11 +1,11 @@ /* * cpim-message.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CPIM_MESSAGE_H_ diff --git a/src/chat/cpim/parser/cpim-grammar.cpp b/src/chat/cpim/parser/cpim-grammar.cpp index b9b863f12..648c7e09b 100644 --- a/src/chat/cpim/parser/cpim-grammar.cpp +++ b/src/chat/cpim/parser/cpim-grammar.cpp @@ -1,11 +1,11 @@ /* * cpim-grammar.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "cpim-grammar.h" diff --git a/src/chat/cpim/parser/cpim-grammar.h b/src/chat/cpim/parser/cpim-grammar.h index da0c98088..3516a2dae 100644 --- a/src/chat/cpim/parser/cpim-grammar.h +++ b/src/chat/cpim/parser/cpim-grammar.h @@ -1,11 +1,11 @@ /* * cpim-grammar.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CPIM_GRAMMAR_H_ diff --git a/src/chat/cpim/parser/cpim-parser.cpp b/src/chat/cpim/parser/cpim-parser.cpp index 19b6018ae..df9bbbac5 100644 --- a/src/chat/cpim/parser/cpim-parser.cpp +++ b/src/chat/cpim/parser/cpim-parser.cpp @@ -1,11 +1,11 @@ /* * cpim-parser.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/src/chat/cpim/parser/cpim-parser.h b/src/chat/cpim/parser/cpim-parser.h index e6686eb2d..841b7e18c 100644 --- a/src/chat/cpim/parser/cpim-parser.h +++ b/src/chat/cpim/parser/cpim-parser.h @@ -1,11 +1,11 @@ /* * cpim-parser.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CPIM_PARSER_H_ diff --git a/src/chat/imdn.cpp b/src/chat/imdn.cpp index b63e7199d..28ec399a2 100644 --- a/src/chat/imdn.cpp +++ b/src/chat/imdn.cpp @@ -1,11 +1,11 @@ /* * imdn.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "logger/logger.h" diff --git a/src/chat/imdn.h b/src/chat/imdn.h index 3a1f332c4..933bae6e1 100644 --- a/src/chat/imdn.h +++ b/src/chat/imdn.h @@ -1,11 +1,11 @@ /* * imdn.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _IMDN_H_ diff --git a/src/chat/is-composing-listener.h b/src/chat/is-composing-listener.h index 66bd50c4d..cf6314ecb 100644 --- a/src/chat/is-composing-listener.h +++ b/src/chat/is-composing-listener.h @@ -1,11 +1,11 @@ /* * is-composing-listener.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _IS_COMPOSING_LISTENER_H_ diff --git a/src/chat/is-composing.cpp b/src/chat/is-composing.cpp index 7b13a214b..d19aa78ae 100644 --- a/src/chat/is-composing.cpp +++ b/src/chat/is-composing.cpp @@ -1,11 +1,11 @@ /* * is-composing.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/utils/utils.h" diff --git a/src/chat/is-composing.h b/src/chat/is-composing.h index d2ea49ded..15a2d4e9c 100644 --- a/src/chat/is-composing.h +++ b/src/chat/is-composing.h @@ -1,11 +1,11 @@ /* * is-composing.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _IS_COMPOSING_H_ diff --git a/src/chat/modifier/chat-message-modifier.h b/src/chat/modifier/chat-message-modifier.h index 8be047ef2..9d3950fe7 100644 --- a/src/chat/modifier/chat-message-modifier.h +++ b/src/chat/modifier/chat-message-modifier.h @@ -1,11 +1,11 @@ /* * chat-message-modifier.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CHAT_MESSAGE_MODIFIER_H_ diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index 456ca9566..5014e65d6 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -1,11 +1,11 @@ /* * cpim-chat-message-modifier.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "cpim-chat-message-modifier.h" diff --git a/src/chat/modifier/cpim-chat-message-modifier.h b/src/chat/modifier/cpim-chat-message-modifier.h index a42b4c9c6..d98016aa4 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.h +++ b/src/chat/modifier/cpim-chat-message-modifier.h @@ -1,11 +1,11 @@ /* * cpim-chat-message-modifier.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CPIM_CHAT_MESSAGE_MODIFIER_H_ diff --git a/src/chat/modifier/encryption-chat-message-modifier.cpp b/src/chat/modifier/encryption-chat-message-modifier.cpp index 963be778c..345549ca5 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.cpp +++ b/src/chat/modifier/encryption-chat-message-modifier.cpp @@ -1,11 +1,11 @@ /* * encryption-chat-message-modifier.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "encryption-chat-message-modifier.h" diff --git a/src/chat/modifier/encryption-chat-message-modifier.h b/src/chat/modifier/encryption-chat-message-modifier.h index 8edeb34db..fbee84efc 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.h +++ b/src/chat/modifier/encryption-chat-message-modifier.h @@ -1,11 +1,11 @@ /* * encryption-chat-message-modifier.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _ENCRYPTION_CHAT_MESSAGE_MODIFIER_H_ diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index 89e9b9192..c49e091f6 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -1,11 +1,11 @@ /* * multipart-chat-message-modifier.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "multipart-chat-message-modifier.h" diff --git a/src/chat/modifier/multipart-chat-message-modifier.h b/src/chat/modifier/multipart-chat-message-modifier.h index 13868bd5c..ca843fc71 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.h +++ b/src/chat/modifier/multipart-chat-message-modifier.h @@ -1,11 +1,11 @@ /* * multipart-chat-message-modifier.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _MULTIPART_CHAT_MESSAGE_MODIFIER_H_ diff --git a/src/chat/real-time-text-chat-room-p.h b/src/chat/real-time-text-chat-room-p.h index 88e4e7df4..78440181d 100644 --- a/src/chat/real-time-text-chat-room-p.h +++ b/src/chat/real-time-text-chat-room-p.h @@ -1,11 +1,11 @@ /* * real-time-text-chat-room-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _REAL_TIME_TEXT_CHAT_ROOM_P_H_ diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 063887017..3046a40f1 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -1,11 +1,11 @@ /* - * chat-room.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * real-time-text-chat-room.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/src/chat/real-time-text-chat-room.h b/src/chat/real-time-text-chat-room.h index 3f2dd2edf..511bb15cc 100644 --- a/src/chat/real-time-text-chat-room.h +++ b/src/chat/real-time-text-chat-room.h @@ -1,11 +1,11 @@ /* * real-time-text-chat-room.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _REAL_TIME_TEXT_CHAT_ROOM_H_ diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index 43e711d68..a897ae4b2 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -1,11 +1,11 @@ /* * conference-interface.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CONFERENCE_INTERFACE_H_ diff --git a/src/conference/conference-listener.h b/src/conference/conference-listener.h index fc67cf34e..aabe88a0c 100644 --- a/src/conference/conference-listener.h +++ b/src/conference/conference-listener.h @@ -1,11 +1,11 @@ /* - * conference-listener.h - * Copyright (C) 2017 Belledonne Communications SARL + * cenference-listener.h + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CONFERENCE_LISTENER_H_ diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 8773ea5e9..2d17c5010 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -1,11 +1,11 @@ /* * conference.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "participant-p.h" diff --git a/src/conference/conference.h b/src/conference/conference.h index 213b4ef3d..43da4651a 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -1,11 +1,11 @@ /* * conference.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CONFERENCE_H_ diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 55dd61028..8d5896229 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -1,11 +1,11 @@ /* * local-conference-event-handler.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "conference/local-conference.h" diff --git a/src/conference/local-conference-event-handler.h b/src/conference/local-conference-event-handler.h index 93fe369c1..5d5b6dcfe 100644 --- a/src/conference/local-conference-event-handler.h +++ b/src/conference/local-conference-event-handler.h @@ -1,11 +1,11 @@ /* * local-conference-event-handler.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _LOCAL_CONFERENCE_EVENT_HANDLER_H_ diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index f4de96ccd..07b026aa8 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -1,11 +1,11 @@ /* * local-conference.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "local-conference.h" diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h index 7e74992be..5fe1eabc7 100644 --- a/src/conference/local-conference.h +++ b/src/conference/local-conference.h @@ -1,11 +1,11 @@ /* * local-conference.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _LOCAL_CONFERENCE_H_ diff --git a/src/conference/params/call-session-params-p.h b/src/conference/params/call-session-params-p.h index 3b5e4e701..e56e0bb26 100644 --- a/src/conference/params/call-session-params-p.h +++ b/src/conference/params/call-session-params-p.h @@ -1,11 +1,11 @@ /* - * call-session-params-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * call-sessio-params-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CALL_SESSION_PARAMS_P_H_ diff --git a/src/conference/params/call-session-params.cpp b/src/conference/params/call-session-params.cpp index c0030cc28..463e490d2 100644 --- a/src/conference/params/call-session-params.cpp +++ b/src/conference/params/call-session-params.cpp @@ -1,11 +1,11 @@ /* * call-session-params.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "call-session-params-p.h" diff --git a/src/conference/params/call-session-params.h b/src/conference/params/call-session-params.h index f8498b980..5f9c8a7fc 100644 --- a/src/conference/params/call-session-params.h +++ b/src/conference/params/call-session-params.h @@ -1,11 +1,11 @@ /* * call-session-params.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CALL_SESSION_PARAMS_H_ diff --git a/src/conference/params/media-session-params-p.h b/src/conference/params/media-session-params-p.h index 5355ff2f9..f0955fa43 100644 --- a/src/conference/params/media-session-params-p.h +++ b/src/conference/params/media-session-params-p.h @@ -1,11 +1,11 @@ /* * media-session-params-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _MEDIA_SESSION_PARAMS_P_H_ diff --git a/src/conference/params/media-session-params.cpp b/src/conference/params/media-session-params.cpp index bfb473659..dd652d73e 100644 --- a/src/conference/params/media-session-params.cpp +++ b/src/conference/params/media-session-params.cpp @@ -1,11 +1,11 @@ /* * media-session-params.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "call-session-params-p.h" diff --git a/src/conference/params/media-session-params.h b/src/conference/params/media-session-params.h index 0a6aafe9b..e4603abc1 100644 --- a/src/conference/params/media-session-params.h +++ b/src/conference/params/media-session-params.h @@ -1,11 +1,11 @@ /* * media-session-params.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _MEDIA_SESSION_PARAMS_H_ diff --git a/src/conference/participant-p.h b/src/conference/participant-p.h index 6c7cb5ea7..363820f9b 100644 --- a/src/conference/participant-p.h +++ b/src/conference/participant-p.h @@ -1,11 +1,11 @@ /* * participant-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _PARTICIPANT_P_H_ diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index eea9b7f31..83544da5e 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -1,11 +1,11 @@ /* * participant.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "object/object-p.h" diff --git a/src/conference/participant.h b/src/conference/participant.h index 37cbb24a1..9d5c01ce1 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -1,11 +1,11 @@ /* * participant.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _PARTICIPANT_H_ diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 19d45c51e..5536bce0e 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -1,11 +1,11 @@ /* * remote-conference-event-handler.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "remote-conference-event-handler.h" diff --git a/src/conference/remote-conference-event-handler.h b/src/conference/remote-conference-event-handler.h index 73c16fd4f..fa30dd808 100644 --- a/src/conference/remote-conference-event-handler.h +++ b/src/conference/remote-conference-event-handler.h @@ -1,11 +1,11 @@ /* * remote-conference-event-handler.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _REMOTE_CONFERENCE_EVENT_HANDLER_H_ diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index e2cafec44..20c579f50 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -1,11 +1,11 @@ /* * remote-conference.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "remote-conference.h" diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index 5a31c119f..d9f93bc59 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -1,11 +1,11 @@ /* * remote-conference.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _REMOTE_CONFERENCE_H_ diff --git a/src/conference/session/call-session-listener.h b/src/conference/session/call-session-listener.h index 60aa2c2ab..5529e62fa 100644 --- a/src/conference/session/call-session-listener.h +++ b/src/conference/session/call-session-listener.h @@ -1,11 +1,11 @@ /* * call-session-listener.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CALL_SESSION_LISTENER_H_ diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index f90938332..c850459ea 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -1,11 +1,11 @@ /* * call-session-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CALL_SESSION_P_H_ diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 562cb9420..2b806c894 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -1,11 +1,11 @@ /* * call-session.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index 1fd463d34..3f32d5813 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -1,11 +1,11 @@ /* * call-session.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CALL_SESSION_H_ diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index 31f8da816..f47fb3a40 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -1,11 +1,11 @@ /* * media-session-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _MEDIA_SESSION_P_H_ diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 09c4b89cf..4850f2ab2 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -1,11 +1,11 @@ /* * media-session.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index 4318d70dd..af3a6c444 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -1,11 +1,11 @@ /* * media-session.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _MEDIA_SESSION_H_ diff --git a/src/conference/session/port-config.h b/src/conference/session/port-config.h index c4fdf6649..c7a055357 100644 --- a/src/conference/session/port-config.h +++ b/src/conference/session/port-config.h @@ -1,11 +1,11 @@ /* * port-config.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _PORT_CONFIG_H_ diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index e2972e478..06b1bb967 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -1,11 +1,11 @@ /* * content-type.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/utils/utils.h" diff --git a/src/content/content-type.h b/src/content/content-type.h index 9f05fef68..f944c99c2 100644 --- a/src/content/content-type.h +++ b/src/content/content-type.h @@ -1,11 +1,11 @@ /* * content-type.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CONTENT_TYPE_H_ diff --git a/src/content/content.cpp b/src/content/content.cpp index 6e3a94a69..3d18fbe59 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -1,11 +1,11 @@ /* * content.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "content-type.h" diff --git a/src/content/content.h b/src/content/content.h index f923c33d4..665293dbc 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -1,11 +1,11 @@ /* * content.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CONTENT_H_ diff --git a/src/core/core.cpp b/src/core/core.cpp index 2d4e9696e..ff9975e27 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -1,11 +1,11 @@ /* * core.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "object/object-p.h" diff --git a/src/core/core.h b/src/core/core.h index 1d4874c31..0a2cbf81f 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -1,11 +1,11 @@ /* * core.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CORE_H_ diff --git a/src/db/abstract/abstract-db-p.h b/src/db/abstract/abstract-db-p.h index 51dbd2ffe..852805d39 100644 --- a/src/db/abstract/abstract-db-p.h +++ b/src/db/abstract/abstract-db-p.h @@ -1,11 +1,11 @@ /* * abstract-db-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _ABSTRACT_DB_P_H_ diff --git a/src/db/abstract/abstract-db.cpp b/src/db/abstract/abstract-db.cpp index ce1397191..acc03fa84 100644 --- a/src/db/abstract/abstract-db.cpp +++ b/src/db/abstract/abstract-db.cpp @@ -1,11 +1,11 @@ /* * abstract-db.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "abstract-db-p.h" diff --git a/src/db/abstract/abstract-db.h b/src/db/abstract/abstract-db.h index 4b64695c5..153dfea79 100644 --- a/src/db/abstract/abstract-db.h +++ b/src/db/abstract/abstract-db.h @@ -1,11 +1,11 @@ /* * abstract-db.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _ABSTRACT_DB_H_ diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index b90bcf2a2..9ab9048ad 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -1,11 +1,11 @@ /* * events-db.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/src/db/events-db.h b/src/db/events-db.h index 2c3819b78..6e997ff0a 100644 --- a/src/db/events-db.h +++ b/src/db/events-db.h @@ -1,11 +1,11 @@ /* * events-db.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _EVENTS_DB_H_ diff --git a/src/db/provider/db-session-p.h b/src/db/provider/db-session-p.h index 6ed9ec95e..30751e0af 100644 --- a/src/db/provider/db-session-p.h +++ b/src/db/provider/db-session-p.h @@ -1,11 +1,11 @@ /* * db-session-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _DB_SESSION_P_H_ diff --git a/src/db/provider/db-session-provider.cpp b/src/db/provider/db-session-provider.cpp index 7094be668..e87e9d2e2 100644 --- a/src/db/provider/db-session-provider.cpp +++ b/src/db/provider/db-session-provider.cpp @@ -1,11 +1,11 @@ /* * db-session-provider.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef SOCI_ENABLED diff --git a/src/db/provider/db-session-provider.h b/src/db/provider/db-session-provider.h index 370aec943..82a41c739 100644 --- a/src/db/provider/db-session-provider.h +++ b/src/db/provider/db-session-provider.h @@ -1,11 +1,11 @@ /* * db-session-provider.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _DB_SESSION_PROVIDER_H_ diff --git a/src/db/provider/db-session.cpp b/src/db/provider/db-session.cpp index 8abb52039..1dd0610cc 100644 --- a/src/db/provider/db-session.cpp +++ b/src/db/provider/db-session.cpp @@ -1,11 +1,11 @@ /* * db-session.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "db-session-p.h" diff --git a/src/db/provider/db-session.h b/src/db/provider/db-session.h index 410c6b742..aed758c2a 100644 --- a/src/db/provider/db-session.h +++ b/src/db/provider/db-session.h @@ -1,11 +1,11 @@ /* * db-session.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _DB_SESSION_H_ diff --git a/src/enums.h b/src/enums.h index aab71c83d..993e5568a 100644 --- a/src/enums.h +++ b/src/enums.h @@ -1,11 +1,11 @@ /* * enums.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _ENUMS_H_ diff --git a/src/event-log/call-event.cpp b/src/event-log/call-event.cpp index e1b1f9f86..f98d7fad1 100644 --- a/src/event-log/call-event.cpp +++ b/src/event-log/call-event.cpp @@ -1,11 +1,11 @@ /* * call-event.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "call-event.h" diff --git a/src/event-log/call-event.h b/src/event-log/call-event.h index 423f71449..512d891c2 100644 --- a/src/event-log/call-event.h +++ b/src/event-log/call-event.h @@ -1,11 +1,11 @@ /* * call-event.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CALL_EVENT_H_ diff --git a/src/event-log/chat-message-event.cpp b/src/event-log/chat-message-event.cpp index ed2119772..6305413ea 100644 --- a/src/event-log/chat-message-event.cpp +++ b/src/event-log/chat-message-event.cpp @@ -1,11 +1,11 @@ /* * chat-message-event.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "chat-message-event.h" diff --git a/src/event-log/chat-message-event.h b/src/event-log/chat-message-event.h index 9acf3c745..91764665c 100644 --- a/src/event-log/chat-message-event.h +++ b/src/event-log/chat-message-event.h @@ -1,11 +1,11 @@ /* * chat-message-event.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CHAT_MESSAGE_EVENT_H_ diff --git a/src/event-log/conference-event-p.h b/src/event-log/conference-event-p.h index 87885c3d7..b3f403265 100644 --- a/src/event-log/conference-event-p.h +++ b/src/event-log/conference-event-p.h @@ -1,11 +1,11 @@ /* * conference-event-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CONFERENCE_EVENT_P_H_ diff --git a/src/event-log/conference-event.cpp b/src/event-log/conference-event.cpp index 7d8bb1ba9..795997a04 100644 --- a/src/event-log/conference-event.cpp +++ b/src/event-log/conference-event.cpp @@ -1,11 +1,11 @@ /* * conference-event.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "address/address.h" diff --git a/src/event-log/conference-event.h b/src/event-log/conference-event.h index cd1584cb7..d915ece90 100644 --- a/src/event-log/conference-event.h +++ b/src/event-log/conference-event.h @@ -1,11 +1,11 @@ /* * conference-event.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CONFERENCE_EVENT_H_ diff --git a/src/event-log/conference-participant-event.cpp b/src/event-log/conference-participant-event.cpp index 82a98b81f..b6ba46c17 100644 --- a/src/event-log/conference-participant-event.cpp +++ b/src/event-log/conference-participant-event.cpp @@ -1,11 +1,11 @@ /* * conference-participant-event.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "address/address.h" diff --git a/src/event-log/conference-participant-event.h b/src/event-log/conference-participant-event.h index 03d0d4b48..7732b75de 100644 --- a/src/event-log/conference-participant-event.h +++ b/src/event-log/conference-participant-event.h @@ -1,11 +1,11 @@ /* * conference-participant-event.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CONFERENCE_PARTICIPANT_EVENT_H_ diff --git a/src/event-log/event-log-p.h b/src/event-log/event-log-p.h index 1c50b09a5..2e1281a6d 100644 --- a/src/event-log/event-log-p.h +++ b/src/event-log/event-log-p.h @@ -1,11 +1,11 @@ /* * event-log-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _EVENT_LOG_P_H_ diff --git a/src/event-log/event-log.cpp b/src/event-log/event-log.cpp index f37e802de..25b73953c 100644 --- a/src/event-log/event-log.cpp +++ b/src/event-log/event-log.cpp @@ -1,11 +1,11 @@ /* * event-log.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "event-log-p.h" diff --git a/src/event-log/event-log.h b/src/event-log/event-log.h index 0527a140a..2524f91ee 100644 --- a/src/event-log/event-log.h +++ b/src/event-log/event-log.h @@ -1,11 +1,11 @@ /* * event-log.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _EVENT_LOG_H_ diff --git a/src/hacks/hacks.cpp b/src/hacks/hacks.cpp index 80ef02920..61ffc9b3d 100644 --- a/src/hacks/hacks.cpp +++ b/src/hacks/hacks.cpp @@ -1,19 +1,20 @@ /* * hacks.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY {} without even the implied warranty of + * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/src/hacks/hacks.h b/src/hacks/hacks.h index f1eccc9c7..363910fcb 100644 --- a/src/hacks/hacks.h +++ b/src/hacks/hacks.h @@ -1,11 +1,11 @@ /* * hacks.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _HACKS_H_ diff --git a/src/logger/logger.cpp b/src/logger/logger.cpp index 8689230a2..78ccc1ae6 100644 --- a/src/logger/logger.cpp +++ b/src/logger/logger.cpp @@ -1,11 +1,11 @@ /* * logger.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/core.h" diff --git a/src/logger/logger.h b/src/logger/logger.h index 785dfc4ab..2a904e85c 100644 --- a/src/logger/logger.h +++ b/src/logger/logger.h @@ -1,11 +1,11 @@ /* * logger.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _LOGGER_H_ diff --git a/src/nat/ice-agent.cpp b/src/nat/ice-agent.cpp index d002234c2..1c1937d36 100644 --- a/src/nat/ice-agent.cpp +++ b/src/nat/ice-agent.cpp @@ -1,11 +1,11 @@ /* * ice-agent.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/core.h" diff --git a/src/nat/ice-agent.h b/src/nat/ice-agent.h index 369d579da..98101488d 100644 --- a/src/nat/ice-agent.h +++ b/src/nat/ice-agent.h @@ -1,11 +1,11 @@ /* * ice-agent.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _ICE_AGENT_H_ diff --git a/src/nat/stun-client.cpp b/src/nat/stun-client.cpp index b2faacc8b..a6550f46f 100644 --- a/src/nat/stun-client.cpp +++ b/src/nat/stun-client.cpp @@ -1,11 +1,11 @@ /* * stun-client.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "private.h" diff --git a/src/nat/stun-client.h b/src/nat/stun-client.h index 6230fef7e..1de314d6e 100644 --- a/src/nat/stun-client.h +++ b/src/nat/stun-client.h @@ -1,11 +1,11 @@ /* * stun-client.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _STUN_CLIENT_H_ diff --git a/src/object/clonable-object-p.h b/src/object/clonable-object-p.h index 7d507599f..c1de00036 100644 --- a/src/object/clonable-object-p.h +++ b/src/object/clonable-object-p.h @@ -1,11 +1,11 @@ /* * clonable-object-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CLONABLE_OBJECT_P_H_ diff --git a/src/object/clonable-object.cpp b/src/object/clonable-object.cpp index 45412dc88..4851cd2d8 100644 --- a/src/object/clonable-object.cpp +++ b/src/object/clonable-object.cpp @@ -1,11 +1,11 @@ /* * clonable-object.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "clonable-object-p.h" diff --git a/src/object/clonable-object.h b/src/object/clonable-object.h index b2162706e..34c91ef69 100644 --- a/src/object/clonable-object.h +++ b/src/object/clonable-object.h @@ -1,11 +1,11 @@ /* * clonable-object.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CLONABLE_OBJECT_H_ diff --git a/src/object/object-p.h b/src/object/object-p.h index fe0d42c25..2623ea0f0 100644 --- a/src/object/object-p.h +++ b/src/object/object-p.h @@ -1,11 +1,11 @@ /* * object-p.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _OBJECT_P_H_ diff --git a/src/object/object.cpp b/src/object/object.cpp index c2f5967a2..3f127b04b 100644 --- a/src/object/object.cpp +++ b/src/object/object.cpp @@ -1,11 +1,11 @@ /* * object.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "logger/logger.h" diff --git a/src/object/object.h b/src/object/object.h index cf1afddea..843b48b9d 100644 --- a/src/object/object.h +++ b/src/object/object.h @@ -1,11 +1,11 @@ /* * object.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _OBJECT_H_ diff --git a/src/object/property-container.cpp b/src/object/property-container.cpp index 5b4bc5db9..44d2cb1de 100644 --- a/src/object/property-container.cpp +++ b/src/object/property-container.cpp @@ -1,11 +1,11 @@ /* * property-container.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/src/object/property-container.h b/src/object/property-container.h index 5b8dbd540..4362566df 100644 --- a/src/object/property-container.h +++ b/src/object/property-container.h @@ -1,11 +1,11 @@ /* * property-container.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _PROPERTY_CONTAINER_H_ diff --git a/src/object/singleton.h b/src/object/singleton.h index 44b6715b0..f58466a51 100644 --- a/src/object/singleton.h +++ b/src/object/singleton.h @@ -1,11 +1,11 @@ /* * singleton.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _SINGLETON_H_ diff --git a/src/sal/call-op.cpp b/src/sal/call-op.cpp index 40735c1a1..59c8a2e95 100644 --- a/src/sal/call-op.cpp +++ b/src/sal/call-op.cpp @@ -1,11 +1,11 @@ /* * call-op.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "bellesip_sal/sal_impl.h" diff --git a/src/sal/call-op.h b/src/sal/call-op.h index d46540ef3..82da673db 100644 --- a/src/sal/call-op.h +++ b/src/sal/call-op.h @@ -1,11 +1,11 @@ /* * call-op.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _SAL_CALL_OP_H_ diff --git a/src/sal/event-op.cpp b/src/sal/event-op.cpp index 01e748be5..e14a26f73 100644 --- a/src/sal/event-op.cpp +++ b/src/sal/event-op.cpp @@ -1,11 +1,11 @@ /* * event-op.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sal/event-op.h" diff --git a/src/sal/event-op.h b/src/sal/event-op.h index 94554fc69..0f18e5104 100644 --- a/src/sal/event-op.h +++ b/src/sal/event-op.h @@ -1,11 +1,11 @@ /* * event-op.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _SAL_EVENT_OP_H_ diff --git a/src/sal/message-op-interface.h b/src/sal/message-op-interface.h index abbea0852..3854d94a7 100644 --- a/src/sal/message-op-interface.h +++ b/src/sal/message-op-interface.h @@ -1,11 +1,11 @@ /* * message-op-interface.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _SAL_MESSAGE_OP_INTERFACE_H_ diff --git a/src/sal/message-op.cpp b/src/sal/message-op.cpp index f16efc010..697781979 100644 --- a/src/sal/message-op.cpp +++ b/src/sal/message-op.cpp @@ -1,11 +1,11 @@ /* * message-op.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sal/message-op.h" diff --git a/src/sal/message-op.h b/src/sal/message-op.h index 1a04d8334..5f8b8b32f 100644 --- a/src/sal/message-op.h +++ b/src/sal/message-op.h @@ -1,11 +1,11 @@ /* * message-op.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _SAL_MESSAGE_OP_H_ diff --git a/src/sal/op.cpp b/src/sal/op.cpp index aa4a66fd8..2b6912043 100644 --- a/src/sal/op.cpp +++ b/src/sal/op.cpp @@ -1,11 +1,11 @@ /* * op.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/src/sal/op.h b/src/sal/op.h index 96fa910dd..c183ade4c 100644 --- a/src/sal/op.h +++ b/src/sal/op.h @@ -1,11 +1,11 @@ /* * op.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,10 +13,10 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - #ifndef _SAL_OP_H_ #define _SAL_OP_H_ diff --git a/src/sal/presence-op.cpp b/src/sal/presence-op.cpp index 6e61ecda7..cf8b45a05 100644 --- a/src/sal/presence-op.cpp +++ b/src/sal/presence-op.cpp @@ -1,11 +1,11 @@ /* * presence-op.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sal/presence-op.h" diff --git a/src/sal/presence-op.h b/src/sal/presence-op.h index 7cb2fa8fd..749372dbe 100644 --- a/src/sal/presence-op.h +++ b/src/sal/presence-op.h @@ -1,11 +1,11 @@ /* * presence-op.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _SAL_PRESENCE_OP_H_ diff --git a/src/sal/register-op.cpp b/src/sal/register-op.cpp index 47834e31b..0a39e8c96 100644 --- a/src/sal/register-op.cpp +++ b/src/sal/register-op.cpp @@ -1,11 +1,11 @@ /* * register-op.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sal/register-op.h" diff --git a/src/sal/register-op.h b/src/sal/register-op.h index 4fe1b7f75..ab875e8ed 100644 --- a/src/sal/register-op.h +++ b/src/sal/register-op.h @@ -1,11 +1,11 @@ /* * register-op.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _SAL_REGISTER_OP_H_ diff --git a/src/sal/sal.cpp b/src/sal/sal.cpp index 179e4ff29..d29239442 100644 --- a/src/sal/sal.cpp +++ b/src/sal/sal.cpp @@ -1,11 +1,11 @@ /* * sal.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sal/sal.h" diff --git a/src/sal/sal.h b/src/sal/sal.h index 61d49c9f3..dda0b6e6d 100644 --- a/src/sal/sal.h +++ b/src/sal/sal.h @@ -1,11 +1,11 @@ /* * sal.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _SAL_H_ diff --git a/src/utils/general.cpp b/src/utils/general.cpp index 95379f996..abdb30aa2 100644 --- a/src/utils/general.cpp +++ b/src/utils/general.cpp @@ -1,11 +1,11 @@ /* * general.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/utils/general.h" diff --git a/src/utils/payload-type-handler.cpp b/src/utils/payload-type-handler.cpp index 7761aacfe..74ccb749e 100644 --- a/src/utils/payload-type-handler.cpp +++ b/src/utils/payload-type-handler.cpp @@ -1,11 +1,11 @@ /* * payload-type-handler.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/src/utils/payload-type-handler.h b/src/utils/payload-type-handler.h index d62d0237c..d52e849fa 100644 --- a/src/utils/payload-type-handler.h +++ b/src/utils/payload-type-handler.h @@ -1,11 +1,11 @@ /* * payload-type-handler.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _PAYLOAD_TYPE_HANDLER_H_ diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 1ed4f9fee..30e970df0 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -1,11 +1,11 @@ /* * utils.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index 7ed8ac7d0..8f9b4e9e6 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -1,19 +1,20 @@ /* * variant.cpp - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY {} without even the implied warranty of + * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/utils/utils.h" diff --git a/src/variant/variant.h b/src/variant/variant.h index 0506ef2c1..fcf7a26c8 100644 --- a/src/variant/variant.h +++ b/src/variant/variant.h @@ -1,11 +1,11 @@ /* * variant.h - * Copyright (C) 2017 Belledonne Communications SARL + * Copyright (C) 2010-2017 Belledonne Communications SARL * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +13,8 @@ * 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, see . + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _VARIANT_H_ diff --git a/src/xml/generate.py b/src/xml/generate.py index c5484eaf9..0046c4b05 100755 --- a/src/xml/generate.py +++ b/src/xml/generate.py @@ -1,6 +1,6 @@ #!/usr/bin/python -# Copyright (C) 2014 Belledonne Communications SARL +# Copyright (C) 2017 Belledonne Communications SARL # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License From 86161b9285d8fc9946a7d93bf111d9eb99bb00e5 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 5 Oct 2017 15:21:40 +0200 Subject: [PATCH 0334/2215] Fix build without soci. --- src/db/events-db.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 9ab9048ad..00d1d3304 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -611,6 +611,10 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} void EventsDb::cleanHistory (const string &) {} + bool EventsDb::import (Backend, const string &) { + return false; + } + #endif // ifdef SOCI_ENABLED LINPHONE_END_NAMESPACE From d20d39b232898919ec924bd98a3891514c6100fb Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 5 Oct 2017 17:36:56 +0200 Subject: [PATCH 0335/2215] add SAL api to send/recv out of dialogs refers. --- coreapi/callbacks.c | 16 +++++-- src/CMakeLists.txt | 1 + src/sal/call-op.cpp | 7 +-- src/sal/op.h | 3 +- src/sal/refer-op.cpp | 104 +++++++++++++++++++++++++++++++++++++++++++ src/sal/refer-op.h | 46 +++++++++++++++++++ src/sal/sal.cpp | 8 ++-- src/sal/sal.h | 9 +++- 8 files changed, 180 insertions(+), 14 deletions(-) create mode 100644 src/sal/refer-op.cpp create mode 100644 src/sal/refer-op.h diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 9e4cbf091..3e89c1b60 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/internal/c-sal.h" #include "sal/call-op.h" #include "sal/message-op.h" +#include "sal/refer-op.h" #include "linphone/core.h" #include "private.h" @@ -385,7 +386,7 @@ static void dtmf_received(SalOp *op, char dtmf){ #endif } -static void refer_received(Sal *sal, SalOp *op, const char *referto){ +static void call_refer_received(SalOp *op, const SalAddress *referto){ #if 0 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); @@ -713,6 +714,14 @@ static void on_notify_response(SalOp *op){ } } +static void refer_received(SalOp *op, const SalAddress *refer_to){ + /*if processing is ok*/ + dynamic_cast(op)->reply(SalReasonNone); + + /*otherwise*/ + //dynamic_cast(op)->reply(SalReasonDeclined); +} + Sal::Callbacks linphone_sal_callbacks={ call_received, call_rejected, @@ -725,12 +734,12 @@ Sal::Callbacks linphone_sal_callbacks={ call_failure, call_released, call_cancel_done, + call_refer_received, auth_failure, register_success, register_failure, vfu_request, dtmf_received, - refer_received, message_received, message_delivery_update, notify_refer, @@ -748,5 +757,6 @@ Sal::Callbacks linphone_sal_callbacks={ info_received, on_publish_response, on_expire, - on_notify_response + on_notify_response, + refer_received, }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 037092329..8928cc208 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -172,6 +172,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES sal/presence-op.cpp sal/register-op.cpp sal/sal.cpp + sal/refer-op.cpp utils/general.cpp utils/payload-type-handler.cpp utils/utils.cpp diff --git a/src/sal/call-op.cpp b/src/sal/call-op.cpp index 59c8a2e95..4929e6085 100644 --- a/src/sal/call-op.cpp +++ b/src/sal/call-op.cpp @@ -1438,7 +1438,6 @@ void SalCallOp::process_refer(const belle_sip_request_event_t *event, belle_sip_ belle_sip_header_referred_by_t *referred_by= belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_referred_by_t); belle_sip_response_t* resp; belle_sip_uri_t* refer_to_uri; - char* refer_to_uri_str; ms_message("Receiving REFER request on op [%p]", this); if (refer_to) { @@ -1451,13 +1450,11 @@ void SalCallOp::process_refer(const belle_sip_request_event_t *event, belle_sip_ if (referred_by){ set_referred_by(referred_by); } - refer_to_uri_str=belle_sip_uri_to_string(refer_to_uri); resp = create_response_from_request(req,202); belle_sip_server_transaction_send_response(server_transaction,resp); - this->root->callbacks.refer_received(this->root,this,refer_to_uri_str); - belle_sip_free(refer_to_uri_str); + this->root->callbacks.call_refer_received(this,(SalAddress*)BELLE_SIP_HEADER_ADDRESS(refer_to)); } else { - ms_warning("cannot do anything with the refer without destination\n"); + ms_warning("cannot do anything with the refer without destination"); resp = create_response_from_request(req,400); belle_sip_server_transaction_send_response(server_transaction,resp); } diff --git a/src/sal/op.h b/src/sal/op.h index c183ade4c..06c009909 100644 --- a/src/sal/op.h +++ b/src/sal/op.h @@ -140,7 +140,8 @@ protected: Message, Presence, Publish, - Subscribe + Subscribe, + Refer /*for out of dialog refer only*/ }; static const char *to_string(const SalOp::Type type); diff --git a/src/sal/refer-op.cpp b/src/sal/refer-op.cpp new file mode 100644 index 000000000..6a28b197e --- /dev/null +++ b/src/sal/refer-op.cpp @@ -0,0 +1,104 @@ +/* + Linphone library + Copyright (C) 2017 Belledonne Communications SARL + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "sal/refer-op.h" + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +void SalReferOp::process_error() { + this->state=State::Terminated; +} + +void SalReferOp::process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event) { + SalReferOp * op = (SalReferOp *)user_ctx; + sal_error_info_set(&op->error_info,SalReasonIOError, "SIP", 503,"IO Error",NULL); + op->process_error(); +} + +void SalReferOp::process_response_event_cb(void *op_base, const belle_sip_response_event_t *event) { + SalReferOp * op = (SalReferOp *)op_base; + op->set_error_info_from_response(belle_sip_response_event_get_response(event)); + /*the response is not notified to the app*/ + /*To be done when necessary*/ +} + +void SalReferOp::process_timeout_cb(void *user_ctx, const belle_sip_timeout_event_t *event) { + SalReferOp * op=(SalReferOp *)user_ctx; + sal_error_info_set(&op->error_info,SalReasonRequestTimeout, "SIP", 408,"Request timeout",NULL); + op->process_error(); +} + +void SalReferOp::process_request_event_cb(void *op_base, const belle_sip_request_event_t *event) { + SalReferOp * op = (SalReferOp *)op_base; + belle_sip_request_t *req = belle_sip_request_event_get_request(event); + belle_sip_header_refer_to_t *refer_to= belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_refer_to_t); + belle_sip_server_transaction_t *server_transaction = belle_sip_provider_create_server_transaction(op->root->prov,belle_sip_request_event_get_request(event)); + + belle_sip_object_ref(server_transaction); + belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),op->ref()); + op->pending_server_trans = server_transaction; + + if (!refer_to){ + ms_warning("cannot do anything with the refer without destination"); + op->reply(SalReasonUnknown);/*is mapped on bad request*/ + return; + } + op->root->callbacks.refer_received(op, (SalAddress*)refer_to); + /*the app is expected to reply in the callback*/ +} + +void SalReferOp::fill_cbs() { + static belle_sip_listener_callbacks_t op_refer_callbacks = {0}; + if (op_refer_callbacks.process_io_error==NULL) { + op_refer_callbacks.process_io_error=process_io_error_cb; + op_refer_callbacks.process_response_event=process_response_event_cb; + op_refer_callbacks.process_timeout=process_timeout_cb; + op_refer_callbacks.process_request_event=process_request_event_cb; + } + this->callbacks=&op_refer_callbacks; + this->type=Type::Refer; +} + +SalReferOp::SalReferOp(Sal *sal) : SalOp(sal){ + fill_cbs(); +} + +int SalReferOp::send_refer(const SalAddress *refer_to) { + this->dir=Dir::Outgoing; + + belle_sip_request_t* req=build_request("REFER"); + if (req == NULL ) return -1; + if (get_contact_address()) belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(create_contact())); + return send_request(req); +} + +int SalReferOp::reply(SalReason reason){ + if (this->pending_server_trans){ + int code=to_sip_code(reason); + belle_sip_response_t *resp = belle_sip_response_create_from_request( + belle_sip_transaction_get_request((belle_sip_transaction_t*)this->pending_server_trans),code); + belle_sip_server_transaction_send_response(this->pending_server_trans,resp); + return 0; + }else ms_error("SalReferOp::reply: no server transaction"); + return -1; +} + +LINPHONE_END_NAMESPACE diff --git a/src/sal/refer-op.h b/src/sal/refer-op.h new file mode 100644 index 000000000..a3197e7ca --- /dev/null +++ b/src/sal/refer-op.h @@ -0,0 +1,46 @@ +/* + Linphone library + Copyright (C) 2010-2017 Belledonne Communications SARL + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _SAL_REFER_OP_H_ +#define _SAL_REFER_OP_H_ + +#include "sal/op.h" + +LINPHONE_BEGIN_NAMESPACE + +class SalReferOp: public SalOp{ +public: + SalReferOp(Sal *sal); + + int send_refer(const SalAddress *refer_to); + int reply(SalReason reason); + +private: + virtual void fill_cbs() override; + void process_error(); + + static void process_io_error_cb(void *user_ctx, const belle_sip_io_error_event_t *event); + static void process_response_event_cb(void *op_base, const belle_sip_response_event_t *event); + static void process_timeout_cb(void *user_ctx, const belle_sip_timeout_event_t *event); + static void process_request_event_cb(void *op_base, const belle_sip_request_event_t *event); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _SAL_MESSAGE_OP_H_ diff --git a/src/sal/sal.cpp b/src/sal/sal.cpp index d29239442..2e2b8d86e 100644 --- a/src/sal/sal.cpp +++ b/src/sal/sal.cpp @@ -20,6 +20,7 @@ #include "sal/sal.h" #include "sal/call-op.h" #include "sal/presence-op.h" +#include "sal/refer-op.h" #include "sal/event-op.h" #include "sal/message-op.h" #include "bellesip_sal/sal_impl.h" @@ -104,7 +105,6 @@ void Sal::process_request_event_cb(void *ud, const belle_sip_request_event_t *ev if (strcmp("INVITE",method)==0) { op=new SalCallOp(sal); - op->dir=SalOp::Dir::Incoming; op->fill_cbs(); }else if ((strcmp("SUBSCRIBE",method)==0 || strcmp("NOTIFY",method)==0) && (evh=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Event"))!=NULL) { if (strncmp(belle_sip_header_get_unparsed_value(evh),"presence",strlen("presence"))==0){ @@ -112,11 +112,12 @@ void Sal::process_request_event_cb(void *ud, const belle_sip_request_event_t *ev } else { op=new SalSubscribeOp(sal); } - op->dir=SalOp::Dir::Incoming; op->fill_cbs(); }else if (strcmp("MESSAGE",method)==0) { op=new SalMessageOp(sal); - op->dir=SalOp::Dir::Incoming; + op->fill_cbs(); + }else if (strcmp("REFER",method)==0) { + op=new SalReferOp(sal); op->fill_cbs(); }else if (strcmp("OPTIONS",method)==0) { resp=belle_sip_response_create_from_request(req,200); @@ -147,6 +148,7 @@ void Sal::process_request_event_cb(void *ud, const belle_sip_request_event_t *ev belle_sip_provider_send_response(sal->prov,resp); return; } + op->dir=SalOp::Dir::Incoming; } if (!op->from_address) { diff --git a/src/sal/sal.h b/src/sal/sal.h index dda0b6e6d..eece42388 100644 --- a/src/sal/sal.h +++ b/src/sal/sal.h @@ -30,6 +30,7 @@ class SalCallOp; class SalMessageOp; class SalSubscribeOp; class SalPresenceOp; +class SalReferOp; class Sal{ public: @@ -50,7 +51,8 @@ public: typedef void (*OnRegisterFailureCb)(SalOp *op); typedef void (*OnVfuRequestCb)(SalOp *op); typedef void (*OnDtmfReceivedCb)(SalOp *op, char dtmf); - typedef void (*OnReferCb)(Sal *sal, SalOp *op, const char *referto); + typedef void (*OnCallReferCb)(SalOp *op, const SalAddress *referto); + typedef void (*OnReferCb)(SalOp *op, const SalAddress *referto); typedef void (*OnMessageReceivedCb)(SalOp *op, const SalMessage *msg); typedef void (*OnMessageDeliveryUpdateCb)(SalOp *op, SalMessageDeliveryStatus); typedef void (*OnNotifyReferCb)(SalOp *op, SalReferStatus state); @@ -81,12 +83,13 @@ public: OnCallFailureCb call_failure; OnCallReleasedCb call_released; OnCallCancelDoneCb call_cancel_done; + OnCallReferCb call_refer_received; OnAuthFailureCb auth_failure; OnRegisterSuccessCb register_success; OnRegisterFailureCb register_failure; OnVfuRequestCb vfu_request; OnDtmfReceivedCb dtmf_received; - OnReferCb refer_received; + OnMessageReceivedCb message_received; OnMessageDeliveryUpdateCb message_delivery_update; OnNotifyReferCb notify_refer; @@ -105,6 +108,7 @@ public: OnPublishResponseCb on_publish_response; OnExpireCb on_expire; OnNotifyResponseCb on_notify_response; + OnReferCb refer_received; /*for out of dialog refer*/ }; Sal(MSFactory *factory); @@ -309,6 +313,7 @@ private: friend class SalPresenceOp; friend class SalSubscribeOp; friend class SalPublishOp; + friend class SalReferOp; }; int to_sip_code(SalReason r); From df8aedecc32e39ba50cc787990bced3bded4d81a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 6 Oct 2017 10:30:37 +0200 Subject: [PATCH 0336/2215] Reworked ChatMessageModifiers to use a shared_ptr instead of ChatMessagePrivate* --- src/chat/chat-message.cpp | 17 +++++--- src/chat/chat-message.h | 2 + src/chat/modifier/chat-message-modifier.h | 7 ++-- .../modifier/cpim-chat-message-modifier.cpp | 40 +++++++++---------- .../modifier/cpim-chat-message-modifier.h | 4 +- .../encryption-chat-message-modifier.cpp | 18 +++++---- .../encryption-chat-message-modifier.h | 4 +- .../multipart-chat-message-modifier.cpp | 10 ++--- .../multipart-chat-message-modifier.h | 4 +- 9 files changed, 58 insertions(+), 48 deletions(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index c434a0dcf..eb7e5bf53 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -980,11 +980,11 @@ LinphoneReason ChatMessagePrivate::receive() { if (getContentType() == ContentType::Cpim) { CpimChatMessageModifier ccmm; - ccmm.decode(this, &errorCode); + ccmm.decode(q->getSharedFromThis(), &errorCode); } EncryptionChatMessageModifier ecmm; - ChatMessageModifier::Result result = ecmm.decode(this, &errorCode); + ChatMessageModifier::Result result = ecmm.decode(q->getSharedFromThis(), &errorCode); if (result == ChatMessageModifier::Result::Error) { /* Unable to decrypt message */ chatRoom->getPrivate()->notifyUndecryptableMessageReceived(q->getSharedFromThis()); @@ -994,7 +994,7 @@ LinphoneReason ChatMessagePrivate::receive() { } MultipartChatMessageModifier mcmm; - mcmm.decode(this, &errorCode); + mcmm.decode(q->getSharedFromThis(), &errorCode); // --------------------------------------- // End of message modification @@ -1101,7 +1101,7 @@ void ChatMessagePrivate::send() { } else { if (contents.size() > 1) { MultipartChatMessageModifier mcmm; - mcmm.encode(this, &errorCode); + mcmm.encode(q->getSharedFromThis(), &errorCode); } currentSendStep |= ChatMessagePrivate::Step::Multipart; } @@ -1110,7 +1110,7 @@ void ChatMessagePrivate::send() { lInfo() << "Encryption step already done, skipping"; } else { EncryptionChatMessageModifier ecmm; - ChatMessageModifier::Result result = ecmm.encode(this, &errorCode); + ChatMessageModifier::Result result = ecmm.encode(q->getSharedFromThis(), &errorCode); if (result == ChatMessageModifier::Result::Error) { sal_error_info_set((SalErrorInfo *)op->get_error_info(), SalReasonNotAcceptable, "SIP", errorCode, "Unable to encrypt IM", nullptr); q->updateState(ChatMessage::State::NotDelivered); @@ -1128,7 +1128,7 @@ void ChatMessagePrivate::send() { } else { if (lp_config_get_int(chatRoom->getCore()->config, "sip", "use_cpim", 0) == 1) { CpimChatMessageModifier ccmm; - ccmm.encode(this, &errorCode); + ccmm.encode(q->getSharedFromThis(), &errorCode); } currentSendStep |= ChatMessagePrivate::Step::Cpim; } @@ -1352,6 +1352,11 @@ const Content& ChatMessage::getInternalContent() const { return d->internalContent; } +void ChatMessage::setInternalContent(const Content& content) { + L_D(); + d->internalContent = content; +} + string ChatMessage::getCustomHeaderValue (const string &headerName) const { L_D(); try { diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index 9aca23808..d684f931a 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -126,7 +126,9 @@ public: const std::list& getContents() const; void addContent(const Content& content); void removeContent(const Content& content); + const Content& getInternalContent() const; + void setInternalContent(const Content& content); std::string getCustomHeaderValue(const std::string &headerName) const; void addCustomHeader(const std::string &headerName, const std::string &headerValue); diff --git a/src/chat/modifier/chat-message-modifier.h b/src/chat/modifier/chat-message-modifier.h index 9d3950fe7..02b671b7a 100644 --- a/src/chat/modifier/chat-message-modifier.h +++ b/src/chat/modifier/chat-message-modifier.h @@ -21,13 +21,14 @@ #define _CHAT_MESSAGE_MODIFIER_H_ #include "linphone/utils/general.h" +#include "object/object.h" #include "private.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE -class ChatMessagePrivate; +class ChatMessage; class ChatMessageModifier { public: @@ -45,13 +46,13 @@ public: * It should check first if the internalContent is filled. * If so, it should apply it's changes to it, otherwise it should use the contentsList. */ - virtual Result encode (ChatMessagePrivate *messagePrivate, int *errorCode) = 0; + virtual Result encode (std::shared_ptr message, int *errorCode) = 0; /** * This method will be called when the message is about to be received. * It should apply it's changes to the internal content, the last modifier will take care of filling the contentsList. */ - virtual Result decode (ChatMessagePrivate *messagePrivate, int *errorCode) = 0; + virtual Result decode (std::shared_ptr message, int *errorCode) = 0; }; LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index 5014e65d6..8d69fa301 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -32,22 +32,22 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ChatMessageModifier::Result CpimChatMessageModifier::encode (ChatMessagePrivate *messagePrivate, int *errorCode) { - Cpim::Message message; +ChatMessageModifier::Result CpimChatMessageModifier::encode (shared_ptr message, int *errorCode) { + Cpim::Message cpimMessage; Cpim::GenericHeader cpimContentTypeHeader; cpimContentTypeHeader.setName("Content-Type"); cpimContentTypeHeader.setValue("Message/CPIM"); - message.addCpimHeader(cpimContentTypeHeader); + cpimMessage.addCpimHeader(cpimContentTypeHeader); Content content; - if (!messagePrivate->internalContent.isEmpty()) { + if (!message->getInternalContent().isEmpty()) { // Another ChatMessageModifier was called before this one, we apply our changes on the private content - content = messagePrivate->internalContent; + content = message->getInternalContent(); } else { // We're the first ChatMessageModifier to be called, we'll create the private content from the public one // We take the first one because if there is more of them, the multipart modifier should have been called first // So we should not be in this block - content = messagePrivate->contents.front(); + content = message->getContents().front(); } string contentType = content.getContentType().asString(); @@ -57,11 +57,11 @@ ChatMessageModifier::Result CpimChatMessageModifier::encode (ChatMessagePrivate Cpim::GenericHeader contentTypeHeader; contentTypeHeader.setName("Content-Type"); contentTypeHeader.setValue(contentType); - message.addContentHeader(contentTypeHeader); + cpimMessage.addContentHeader(contentTypeHeader); - message.setContent(contentBody); + cpimMessage.setContent(contentBody); - if (!message.isValid()) { + if (!cpimMessage.isValid()) { lError() << "[CPIM] Message is invalid: " << contentBody; *errorCode = 500; return ChatMessageModifier::Result::Error; @@ -69,30 +69,30 @@ ChatMessageModifier::Result CpimChatMessageModifier::encode (ChatMessagePrivate Content newContent; ContentType newContentType("Message/CPIM"); newContent.setContentType(newContentType); - newContent.setBody(message.asString()); - messagePrivate->internalContent = newContent; + newContent.setBody(cpimMessage.asString()); + message->setInternalContent(newContent); } return ChatMessageModifier::Result::Done; } -ChatMessageModifier::Result CpimChatMessageModifier::decode (ChatMessagePrivate *messagePrivate, int *errorCode) { +ChatMessageModifier::Result CpimChatMessageModifier::decode (shared_ptr message, int *errorCode) { Content content; - if (!messagePrivate->internalContent.isEmpty()) { - content = messagePrivate->internalContent; + if (!message->getInternalContent().isEmpty()) { + content = message->getInternalContent(); } else { - content = messagePrivate->contents.front(); + content = message->getContents().front(); } if (content.getContentType() == ContentType::Cpim) { const vector body = content.getBody(); string contentBody(body.begin(), body.end()); - shared_ptr message = Cpim::Message::createFromString(contentBody); - if (message && message->isValid()) { + shared_ptr cpimMessage = Cpim::Message::createFromString(contentBody); + if (cpimMessage && cpimMessage->isValid()) { Content newContent; - ContentType newContentType(message->getContentHeaders()->front()->getValue()); + ContentType newContentType(cpimMessage->getContentHeaders()->front()->getValue()); newContent.setContentType(newContentType); - newContent.setBody(message->getContent()); - messagePrivate->internalContent = newContent; + newContent.setBody(cpimMessage->getContent()); + message->setInternalContent(newContent); } else { lError() << "[CPIM] Message is invalid: " << contentBody; *errorCode = 500; diff --git a/src/chat/modifier/cpim-chat-message-modifier.h b/src/chat/modifier/cpim-chat-message-modifier.h index d98016aa4..df6a4578c 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.h +++ b/src/chat/modifier/cpim-chat-message-modifier.h @@ -30,8 +30,8 @@ class CpimChatMessageModifier : public ChatMessageModifier { public: CpimChatMessageModifier () = default; - Result encode (ChatMessagePrivate *messagePrivate, int *errorCode) override; - Result decode (ChatMessagePrivate *messagePrivate, int *errorCode) override; + Result encode (std::shared_ptr message, int *errorCode) override; + Result decode (std::shared_ptr message, int *errorCode) override; }; LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/encryption-chat-message-modifier.cpp b/src/chat/modifier/encryption-chat-message-modifier.cpp index 345549ca5..e1798c57f 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.cpp +++ b/src/chat/modifier/encryption-chat-message-modifier.cpp @@ -34,16 +34,17 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ChatMessageModifier::Result EncryptionChatMessageModifier::encode (ChatMessagePrivate *messagePrivate, int *errorCode) { +ChatMessageModifier::Result EncryptionChatMessageModifier::encode (shared_ptr message, int *errorCode) { int retval = -1; - LinphoneImEncryptionEngine *imee = messagePrivate->chatRoom->getCore()->im_encryption_engine; + shared_ptr chatRoom = message->getChatRoom(); + LinphoneImEncryptionEngine *imee = chatRoom->getCore()->im_encryption_engine; if (imee) { LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); if (cbProcessOutgoingMessage) { - retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(messagePrivate->chatRoom), L_GET_C_BACK_PTR(messagePrivate->getPublic()->getSharedFromThis())); + retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(chatRoom), L_GET_C_BACK_PTR(message->getSharedFromThis())); if (retval == 0 || retval == 1) { - messagePrivate->isSecured = true; + message->setIsSecured(true); if (retval == 1) { return ChatMessageModifier::Result::Suspended; } @@ -58,16 +59,17 @@ ChatMessageModifier::Result EncryptionChatMessageModifier::encode (ChatMessagePr return ChatMessageModifier::Result::Skipped; } -ChatMessageModifier::Result EncryptionChatMessageModifier::decode (ChatMessagePrivate *messagePrivate, int *errorCode) { +ChatMessageModifier::Result EncryptionChatMessageModifier::decode (shared_ptr message, int *errorCode) { int retval = -1; - LinphoneImEncryptionEngine *imee = messagePrivate->chatRoom->getCore()->im_encryption_engine; + shared_ptr chatRoom = message->getChatRoom(); + LinphoneImEncryptionEngine *imee = chatRoom->getCore()->im_encryption_engine; if (imee) { LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsIncomingMessageCb cbProcessIncomingMessage = linphone_im_encryption_engine_cbs_get_process_incoming_message(imeeCbs); if (cbProcessIncomingMessage) { - retval = cbProcessIncomingMessage(imee, L_GET_C_BACK_PTR(messagePrivate->chatRoom), L_GET_C_BACK_PTR(messagePrivate->getPublic()->getSharedFromThis())); + retval = cbProcessIncomingMessage(imee, L_GET_C_BACK_PTR(chatRoom), L_GET_C_BACK_PTR(message->getSharedFromThis())); if (retval == 0) { - messagePrivate->isSecured = true; + message->setIsSecured(true); return ChatMessageModifier::Result::Done; } else if (retval == -1) { return ChatMessageModifier::Result::Skipped; diff --git a/src/chat/modifier/encryption-chat-message-modifier.h b/src/chat/modifier/encryption-chat-message-modifier.h index fbee84efc..8b9ce52dc 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.h +++ b/src/chat/modifier/encryption-chat-message-modifier.h @@ -30,8 +30,8 @@ class EncryptionChatMessageModifier : public ChatMessageModifier { public: EncryptionChatMessageModifier () = default; - Result encode (ChatMessagePrivate *messagePrivate, int *errorCode) override; - Result decode (ChatMessagePrivate *messagePrivate, int *errorCode) override; + Result encode (std::shared_ptr message, int *errorCode) override; + Result decode (std::shared_ptr message, int *errorCode) override; }; LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index c49e091f6..4390841ee 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -27,22 +27,22 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ChatMessageModifier::Result MultipartChatMessageModifier::encode (ChatMessagePrivate *messagePrivate, int *errorCode) { - if (messagePrivate->contents.size() > 1) { +ChatMessageModifier::Result MultipartChatMessageModifier::encode (shared_ptr message, int *errorCode) { + if (message->getContents().size() > 1) { //TODO return ChatMessageModifier::Result::Done; } return ChatMessageModifier::Result::Skipped; } -ChatMessageModifier::Result MultipartChatMessageModifier::decode (ChatMessagePrivate *messagePrivate, int *errorCode) { +ChatMessageModifier::Result MultipartChatMessageModifier::decode (shared_ptr message, int *errorCode) { //TODO if (false) { // Multipart required return ChatMessageModifier::Result::Done; - } else if (messagePrivate->contents.size() == 0) { + } else if (message->getContents().size() == 0) { // All previous modifiers only altered the internal content, let's fill the content list because we're the last modifier to be called - messagePrivate->contents.push_back(messagePrivate->internalContent); + message->addContent(message->getInternalContent()); } return ChatMessageModifier::Result::Skipped; } diff --git a/src/chat/modifier/multipart-chat-message-modifier.h b/src/chat/modifier/multipart-chat-message-modifier.h index ca843fc71..fd7b747ca 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.h +++ b/src/chat/modifier/multipart-chat-message-modifier.h @@ -30,8 +30,8 @@ class MultipartChatMessageModifier : public ChatMessageModifier { public: MultipartChatMessageModifier () = default; - Result encode (ChatMessagePrivate *message, int *errorCode) override; - Result decode (ChatMessagePrivate *message, int *errorCode) override; + Result encode (std::shared_ptr message, int *errorCode) override; + Result decode (std::shared_ptr message, int *errorCode) override; }; LINPHONE_END_NAMESPACE From 32e22abee2b377d5d525c463e68bdcf720b78b03 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 6 Oct 2017 10:33:19 +0200 Subject: [PATCH 0337/2215] Moved code that fill the contentsList of ChatMessage from MultipartChatModifier to ChatMessage itself --- src/chat/chat-message.cpp | 5 +++++ src/chat/modifier/multipart-chat-message-modifier.cpp | 3 --- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index eb7e5bf53..3723533b8 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -996,6 +996,11 @@ LinphoneReason ChatMessagePrivate::receive() { MultipartChatMessageModifier mcmm; mcmm.decode(q->getSharedFromThis(), &errorCode); + if (contents.size() == 0) { + // All previous modifiers only altered the internal content, let's fill the content list + contents.push_back(internalContent); + } + // --------------------------------------- // End of message modification // --------------------------------------- diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index 4390841ee..7d2f5f36b 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -40,9 +40,6 @@ ChatMessageModifier::Result MultipartChatMessageModifier::decode (shared_ptrgetContents().size() == 0) { - // All previous modifiers only altered the internal content, let's fill the content list because we're the last modifier to be called - message->addContent(message->getInternalContent()); } return ChatMessageModifier::Result::Skipped; } From d60b5fab06b3af88530238f09c74699e12d9ca3c Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 6 Oct 2017 11:00:09 +0200 Subject: [PATCH 0338/2215] feat(EventsDb): import correctly legacy messages --- include/linphone/utils/general.h | 2 + src/content/content.cpp | 6 +- src/content/content.h | 2 +- src/db/abstract/abstract-db.cpp | 26 ++- src/db/abstract/abstract-db.h | 3 +- src/db/events-db.cpp | 274 +++++++++++++++++-------------- src/object/object-p.h | 2 +- src/object/object.cpp | 6 +- 8 files changed, 185 insertions(+), 136 deletions(-) diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index 71f444cd7..fea6e3ff0 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -117,9 +117,11 @@ constexpr T *getPublicHelper (Object *object, const ObjectPrivate *) { #define L_DECLARE_PUBLIC(CLASS) \ inline CLASS *getPublic () { \ + L_ASSERT(mPublic); \ return getPublicHelper(mPublic, this); \ } \ inline const CLASS *getPublic () const { \ + L_ASSERT(mPublic); \ return getPublicHelper(mPublic, this); \ } \ friend class CLASS; diff --git a/src/content/content.cpp b/src/content/content.cpp index 3d18fbe59..b9581de73 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -72,9 +72,11 @@ Content &Content::operator= (Content &&src) { return *this; } -bool Content::operator==(const Content& content) const { +bool Content::operator== (const Content &content) const { L_D(); - return d->contentType == content.getContentType() && d->body == content.getBody() && d->contentDisposition == content.getContentDisposition(); + return d->contentType == content.getContentType() && + d->body == content.getBody() && + d->contentDisposition == content.getContentDisposition(); } const ContentType &Content::getContentType () const { diff --git a/src/content/content.h b/src/content/content.h index 665293dbc..57f78787f 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -39,7 +39,7 @@ public: Content &operator= (const Content &src); Content &operator= (Content &&src); - bool operator==(const Content& content) const; + bool operator== (const Content &content) const; const ContentType &getContentType () const; void setContentType (const ContentType &contentType); diff --git a/src/db/abstract/abstract-db.cpp b/src/db/abstract/abstract-db.cpp index acc03fa84..731f53bed 100644 --- a/src/db/abstract/abstract-db.cpp +++ b/src/db/abstract/abstract-db.cpp @@ -17,6 +17,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#ifdef SOCI_ENABLED + #include +#endif // ifdef SOCI_ENABLED + #include "abstract-db-p.h" #include "db/provider/db-session-provider.h" #include "logger/logger.h" @@ -86,17 +90,27 @@ string AbstractDb::primaryKeyAutoIncrementStr (const string &type) const { return ""; } -string AbstractDb::insertOrIgnoreStr () const { +long AbstractDb::getLastInsertId () const { L_D(); - switch (d->backend) { - case Mysql: - return "INSERT IGNORE INTO "; + string sql; + switch(d->backend) { case Sqlite3: - return "INSERT OR IGNORE INTO "; + sql = "SELECT last_insert_rowid()"; + break; + default: + lWarning() << "Unsupported backend."; + return -1; } - return ""; + long result = 0; + + #ifdef SOCI_ENABLED + soci::session *session = d->dbSession.getBackendSession(); + *session << sql, soci::into(result); + #endif // ifdef SOCI_ENABLED + + return result; } LINPHONE_END_NAMESPACE diff --git a/src/db/abstract/abstract-db.h b/src/db/abstract/abstract-db.h index 153dfea79..f8250f37b 100644 --- a/src/db/abstract/abstract-db.h +++ b/src/db/abstract/abstract-db.h @@ -52,7 +52,8 @@ protected: virtual void init (); std::string primaryKeyAutoIncrementStr (const std::string &type = "INT") const; - std::string insertOrIgnoreStr () const; + + long getLastInsertId () const; private: L_DECLARE_PRIVATE(AbstractDb); diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 00d1d3304..ae51560a1 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -41,7 +41,38 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -class EventsDbPrivate : public AbstractDbPrivate {}; +struct MessageEventReferences { +#ifdef SOCI_ENABLED + long eventId; + long localSipAddressId; + long remoteSipAddressId; + long chatRoomId; + long contentTypeId; +#endif +}; + +class EventsDbPrivate : public AbstractDbPrivate { +#ifdef SOCI_ENABLED +public: + long insertSipAddress (const string &sipAddress); + long insertContentType (const string &contentType); + long insertEvent (EventLog::Type type, const tm &date); + long insertChatRoom (long sipAddressId, const tm &date); + long insertMessageEvent ( + const MessageEventReferences &references, + ChatMessage::State state, + ChatMessage::Direction direction, + const string &imdnMessageId, + bool isSecured, + const string *text = nullptr + ); + + void importLegacyMessages (const soci::rowset &messages); +#endif + +private: + L_DECLARE_PUBLIC(EventsDb); +}; // ----------------------------------------------------------------------------- @@ -78,16 +109,6 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} ); } -// ----------------------------------------------------------------------------- - - struct MessageEventReferences { - long eventId; - long localSipAddressId; - long remoteSipAddressId; - long chatRoomId; - long contentTypeId; - }; - // ----------------------------------------------------------------------------- static string buildSqlEventFilter (const list &filters, EventsDb::FilterMask mask) { @@ -111,7 +132,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} sql += " WHERE "; } else sql += " OR "; - sql += " event_type_id = "; + sql += " type = "; sql += mapEventFilterToSql(filter); } @@ -120,73 +141,148 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} // ----------------------------------------------------------------------------- - static inline long insertSipAddress (soci::session &session, const string &sipAddress) { + long EventsDbPrivate::insertSipAddress (const string &sipAddress) { + L_Q(); + soci::session *session = dbSession.getBackendSession(); + long id; - session << "SELECT id FROM sip_address WHERE value = :sipAddress", soci::use(sipAddress), soci::into(id); - if (session.got_data()) + *session << "SELECT id FROM sip_address WHERE value = :sipAddress", soci::use(sipAddress), soci::into(id); + if (session->got_data()) return id; - session << "INSERT INTO sip_address (value) VALUES (:sipAddress)", soci::use(sipAddress); - session.get_last_insert_id("sip_address", id); - return id; + *session << "INSERT INTO sip_address (value) VALUES (:sipAddress)", soci::use(sipAddress); + return q->getLastInsertId(); } - static inline long insertContentType (soci::session &session, const string &contentType) { + long EventsDbPrivate::insertContentType (const string &contentType) { + L_Q(); + soci::session *session = dbSession.getBackendSession(); + long id; - session << "SELECT id FROM content_type WHERE value = :contentType", soci::use(contentType), soci::into(id); - if (session.got_data()) + *session << "SELECT id FROM content_type WHERE value = :contentType", soci::use(contentType), soci::into(id); + if (session->got_data()) return id; - session << "INSERT INTO content_type (value) VALUES (:contentType)", soci::use(contentType); - session.get_last_insert_id("content_type", id); - return id; + *session << "INSERT INTO content_type (value) VALUES (:contentType)", soci::use(contentType); + return q->getLastInsertId(); } - static inline long insertEvent (soci::session &session, EventLog::Type type, const tm &date) { - session << "INSERT INTO event (event_type_id, date) VALUES (:eventTypeId, :date)", + long EventsDbPrivate::insertEvent (EventLog::Type type, const tm &date) { + L_Q(); + soci::session *session = dbSession.getBackendSession(); + + *session << "INSERT INTO event (type, date) VALUES (:type, :date)", soci::use(static_cast(type)), soci::use(date); - long id; - session.get_last_insert_id("event", id); - return id; + return q->getLastInsertId(); } - static inline long insertChatRoom (soci::session &session, long sipAddressId, const tm &date) { + long EventsDbPrivate::insertChatRoom (long sipAddressId, const tm &date) { + soci::session *session = dbSession.getBackendSession(); + long id; - session << "SELECT peer_sip_address_id FROM chat_room WHERE peer_sip_address_id = :sipAddressId", + *session << "SELECT peer_sip_address_id FROM chat_room WHERE peer_sip_address_id = :sipAddressId", soci::use(sipAddressId), soci::into(id); - if (!session.got_data()) - session << "INSERT INTO chat_room (peer_sip_address_id, creation_date, last_update_date, subject) VALUES" + if (!session->got_data()) + *session << "INSERT INTO chat_room (peer_sip_address_id, creation_date, last_update_date, subject) VALUES" " (:sipAddressId, :creationDate, :lastUpdateDate, '')", soci::use(sipAddressId), soci::use(date), soci::use(date); else - session << "UPDATE chat_room SET last_update_date = :lastUpdateDate WHERE peer_sip_address_id = :sipAddressId", + *session << "UPDATE chat_room SET last_update_date = :lastUpdateDate WHERE peer_sip_address_id = :sipAddressId", soci::use(date), soci::use(sipAddressId); + return sipAddressId; } - static inline long insertMessageEvent ( - soci::session &session, + long EventsDbPrivate::insertMessageEvent ( const MessageEventReferences &references, ChatMessage::State state, ChatMessage::Direction direction, const string &imdnMessageId, bool isSecured, - const string *text = nullptr + const string *text ) { - soci::indicator textIndicator = text ? soci::i_ok : soci::i_null; + L_Q(); + soci::session *session = dbSession.getBackendSession(); - session << "INSERT INTO message_event (" - " event_id, chat_room_id, local_sip_address_id, remote_sip_address_id, content_type_id," + soci::indicator textIndicator = text ? soci::i_ok : soci::i_null; + *session << "INSERT INTO message_event (" + " event_id, chat_room_id, local_sip_address_id, remote_sip_address_id," " state, direction, imdn_message_id, is_secured, text" ") VALUES (" - " :eventId, :chatRoomId, :localSipaddressId, :remoteSipaddressId, :contentTypeId," + " :eventId, :chatRoomId, :localSipaddressId, :remoteSipaddressId," " :state, :direction, :imdnMessageId, :isSecured, :text" ")", soci::use(references.eventId), soci::use(references.chatRoomId), soci::use(references.localSipAddressId), - soci::use(references.remoteSipAddressId), soci::use(references.contentTypeId), - soci::use(static_cast(state)), soci::use(static_cast(direction)), soci::use(imdnMessageId), - soci::use(isSecured ? 1 : 0), soci::use(text ? *text : string(), textIndicator); - long id; - return session.get_last_insert_id("message_event", id); - return id; + soci::use(references.remoteSipAddressId), soci::use(static_cast(state)), + soci::use(static_cast(direction)), soci::use(imdnMessageId), soci::use(isSecured ? 1 : 0), + soci::use(text ? *text : string(), textIndicator); + return q->getLastInsertId(); + } + +// ----------------------------------------------------------------------------- + + template + static T getValueFromLegacyMessage (const soci::row &message, int index, bool &isNull) { + isNull = false; + + try { + return message.get(index); + } catch (const exception &) { + isNull = true; + } + + return T(); + } + + void EventsDbPrivate::importLegacyMessages (const soci::rowset &messages) { + soci::session *session = dbSession.getBackendSession(); + + soci::transaction tr(*session); + + for (const auto &message : messages) { + const int direction = message.get(3) + 1; + if (direction != 1 && direction != 2) { + lWarning() << "Unable to import legacy message with invalid direction."; + return; + } + + const int state = message.get(7, static_cast(ChatMessage::State::Displayed)); + + const tm date = Utils::getLongAsTm(message.get(9, 0)); + + const bool noUrl = false; + const string url = getValueFromLegacyMessage(message, 8, const_cast(noUrl)); + + const string contentType = message.get( + 13, + message.get(11, -1) != -1 + ? "application/vnd.gsma.rcs-ft-http+xml" + : (noUrl ? "text/plain" : "message/external-body") + ); + + const bool noText = false; + const string text = getValueFromLegacyMessage(message, 4, const_cast(noText)); + + struct MessageEventReferences references; + references.eventId = insertEvent(EventLog::Type::ChatMessage, date); + references.localSipAddressId = insertSipAddress(message.get(1)); + references.remoteSipAddressId = insertSipAddress(message.get(2)); + references.chatRoomId = insertChatRoom(references.remoteSipAddressId, date); + references.contentTypeId = insertContentType(contentType); + + insertMessageEvent ( + references, + static_cast(state), + static_cast(direction), + message.get(12, ""), + !!message.get(14, 0), + noText ? nullptr : &text + ); + + const bool noAppData = false; + const string appData = getValueFromLegacyMessage(message, 10, const_cast(noAppData)); + (void)appData; + } + + tr.commit(); } // ----------------------------------------------------------------------------- @@ -210,7 +306,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS event (" " id" + primaryKeyAutoIncrementStr() + "," - " event_type_id TINYINT UNSIGNED NOT NULL," + " type TINYINT UNSIGNED NOT NULL," " date DATE NOT NULL" ")"; @@ -238,10 +334,8 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " id" + primaryKeyAutoIncrementStr() + "," " event_id INT UNSIGNED NOT NULL," " chat_room_id INT UNSIGNED NOT NULL," - " local_sip_address_id INT UNSIGNED NOT NULL," " remote_sip_address_id INT UNSIGNED NOT NULL," - " content_type_id INT UNSIGNED NOT NULL," // See: https://tools.ietf.org/html/rfc5438#section-6.3 @@ -468,79 +562,14 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} // ----------------------------------------------------------------------------- - template - static T getValueFromLegacyMessage (const soci::row &message, int index, bool &isNull) { - isNull = false; - - try { - return message.get(index); - } catch (const exception &) { - isNull = true; - } - - return T(); - } - - static void importLegacyMessages ( - soci::session *session, - const string &insertOrIgnoreStr, - const soci::rowset &messages - ) { - soci::transaction tr(*session); - - for (const auto &message : messages) { - const int direction = message.get(3) + 1; - if (direction != 1 && direction != 2) { - lWarning() << "Unable to import legacy message with invalid direction."; - return; - } - - const int state = message.get(7, static_cast(ChatMessage::State::Displayed)); - - const tm date = Utils::getLongAsTm(message.get(9, 0)); - - const bool noUrl = false; - const string url = getValueFromLegacyMessage(message, 8, const_cast(noUrl)); - - const string contentType = message.get( - 13, - message.get(11, -1) != -1 - ? "application/vnd.gsma.rcs-ft-http+xml" - : (noUrl ? "text/plain" : "message/external-body") - ); - - const bool noText = false; - const string text = getValueFromLegacyMessage(message, 4, const_cast(noText)); - - struct MessageEventReferences references; - references.eventId = insertEvent(*session, EventLog::Type::ChatMessage, date); - references.localSipAddressId = insertSipAddress(*session, message.get(1)); - references.remoteSipAddressId = insertSipAddress(*session, message.get(2)); - references.chatRoomId = insertChatRoom(*session, references.remoteSipAddressId, date); - references.contentTypeId = insertContentType(*session, contentType); - - insertMessageEvent ( - *session, - references, - static_cast(state), - static_cast(direction), - message.get(12, ""), - !!message.get(14, 0), - noText ? nullptr : &text - ); - - const bool noAppData = false; - const string appData = getValueFromLegacyMessage(message, 10, const_cast(noAppData)); - (void)text; - (void)appData; - } - - tr.commit(); - } - bool EventsDb::import (Backend, const string ¶meters) { L_D(); + if (!isConnected()) { + lWarning() << "Unable to import data. Not connected."; + return 0; + } + // Backend is useless, it's sqlite3. (Only available legacy backend.) const string uri = "sqlite3://" + parameters; DbSession inDbSession = DbSessionProvider::getInstance()->getSession(uri); @@ -550,14 +579,13 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return false; } - soci::session *outSession = d->dbSession.getBackendSession(); soci::session *inSession = inDbSession.getBackendSession(); // Import messages. try { - soci::rowset messages = (inSession->prepare << "SELECT * FROM history ORDER BY id DESC"); + soci::rowset messages = (inSession->prepare << "SELECT * FROM history"); try { - importLegacyMessages(outSession, insertOrIgnoreStr(), messages); + d->importLegacyMessages(messages); } catch (const exception &e) { lInfo() << "Failed to import legacy messages from: `" << uri << "`. (" << e.what() << ")"; return false; diff --git a/src/object/object-p.h b/src/object/object-p.h index 2623ea0f0..c03afac98 100644 --- a/src/object/object-p.h +++ b/src/object/object-p.h @@ -36,7 +36,7 @@ public: virtual ~ObjectPrivate () = default; protected: - Object *mPublic; + Object *mPublic = nullptr; private: std::unordered_map properties; diff --git a/src/object/object.cpp b/src/object/object.cpp index 3f127b04b..7c62c0c42 100644 --- a/src/object/object.cpp +++ b/src/object/object.cpp @@ -30,12 +30,14 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +Object::Object (ObjectPrivate &p) : mPrivate(&p) { + mPrivate->mPublic = this; +} + Object::~Object () { delete mPrivate; } -Object::Object (ObjectPrivate &p) : mPrivate(&p) {} - shared_ptr Object::getSharedFromThis () { return const_pointer_cast(static_cast(this)->getSharedFromThis()); } From 7b59cd6ee63109d036ffe5d6c4777950a0a3b2f5 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 6 Oct 2017 11:09:36 +0200 Subject: [PATCH 0339/2215] Add API to leave a chat room. --- include/linphone/api/c-chat-room.h | 6 ++++ include/linphone/enums/chat-room-enums.h | 1 + src/c-wrapper/api/c-chat-room.cpp | 4 +++ src/chat/basic-chat-room.cpp | 2 ++ src/chat/basic-chat-room.h | 1 + src/chat/client-group-chat-room.cpp | 39 +++++++++++++++++------- src/chat/client-group-chat-room.h | 5 +-- src/chat/real-time-text-chat-room.cpp | 2 ++ src/chat/real-time-text-chat-room.h | 1 + src/conference/conference-interface.h | 1 + src/conference/conference.cpp | 10 ++++++ src/conference/conference.h | 2 ++ src/conference/participant.h | 1 + 13 files changed, 62 insertions(+), 13 deletions(-) diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index fe8af1023..ddadceb3e 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -289,6 +289,12 @@ LINPHONE_PUBLIC bctbx_list_t * linphone_chat_room_get_participants (const Linpho */ LINPHONE_PUBLIC const char * linphone_chat_room_get_subject (const LinphoneChatRoom *cr); +/** + * Leave a chat room. + * @param[in] cr A LinphoneChatRoom object + */ +LINPHONE_PUBLIC void linphone_chat_room_leave (LinphoneChatRoom *cr); + /** * Remove a participant of a chat room. * @param[in] cr A LinphoneChatRoom object diff --git a/include/linphone/enums/chat-room-enums.h b/include/linphone/enums/chat-room-enums.h index fd83868ae..8a4318aa8 100644 --- a/include/linphone/enums/chat-room-enums.h +++ b/include/linphone/enums/chat-room-enums.h @@ -27,6 +27,7 @@ F(Instantiated) \ F(CreationPending) \ F(Created) \ + F(TerminationPending) \ F(Terminated) \ F(CreationFailed) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 9df110d4e..26eb20ee9 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -248,6 +248,10 @@ const char * linphone_chat_room_get_subject (const LinphoneChatRoom *cr) { return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getSubject()); } +void linphone_chat_room_leave (LinphoneChatRoom *cr) { + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->leave(); +} + void linphone_chat_room_remove_participant (LinphoneChatRoom *cr, LinphoneParticipant *participant) { L_GET_CPP_PTR_FROM_C_OBJECT(cr)->removeParticipant(L_GET_CPP_PTR_FROM_C_OBJECT(participant)); } diff --git a/src/chat/basic-chat-room.cpp b/src/chat/basic-chat-room.cpp index 0ceccf09e..769abf5d9 100644 --- a/src/chat/basic-chat-room.cpp +++ b/src/chat/basic-chat-room.cpp @@ -69,6 +69,8 @@ const string &BasicChatRoom::getSubject () const { return d->subject; } +void BasicChatRoom::leave () {} + void BasicChatRoom::removeParticipant (const shared_ptr &participant) { lError() << "removeParticipant() is not allowed on a BasicChatRoom"; } diff --git a/src/chat/basic-chat-room.h b/src/chat/basic-chat-room.h index 361a972f6..62c15c849 100644 --- a/src/chat/basic-chat-room.h +++ b/src/chat/basic-chat-room.h @@ -41,6 +41,7 @@ public: int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; + void leave () override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; void setSubject (const std::string &subject) override; diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index c0cb30abe..5deeb9b26 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -59,11 +59,6 @@ ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, this->subject = subject; } -ClientGroupChatRoom::~ClientGroupChatRoom () { - shared_ptr session = focus->getPrivate()->getSession(); - session->terminate(); -} - // ----------------------------------------------------------------------------- void ClientGroupChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { @@ -119,6 +114,19 @@ const string &ClientGroupChatRoom::getSubject () const { return RemoteConference::getSubject(); } +void ClientGroupChatRoom::leave () { + L_D(); + eventHandler->unsubscribe(); + shared_ptr session = focus->getPrivate()->getSession(); + if (session) + session->terminate(); + else { + session = d->createSession(); + session->startInvite(nullptr, "", nullptr); + } + d->setState(ChatRoom::State::TerminationPending); +} + void ClientGroupChatRoom::removeParticipant (const shared_ptr &participant) { // TODO } @@ -219,18 +227,27 @@ void ClientGroupChatRoom::onSubjectChanged (const std::string &subject) { // ----------------------------------------------------------------------------- -void ClientGroupChatRoom::onCallSessionSetTerminated (const std::shared_ptr session) { +void ClientGroupChatRoom::onCallSessionSetReleased (const std::shared_ptr session) { if (session == focus->getPrivate()->getSession()) focus->getPrivate()->removeSession(); } void ClientGroupChatRoom::onCallSessionStateChanged (const std::shared_ptr session, LinphoneCallState state, const string &message) { + L_D(); if (state == LinphoneCallConnected) { - Address addr(session->getRemoteContact()); - addr.clean(); - onConferenceCreated(addr); - if (session->getRemoteContactAddress()->hasParam("isfocus")) - eventHandler->subscribe(conferenceAddress); + if (d->state == ChatRoom::State::CreationPending) { + Address addr(session->getRemoteContact()); + addr.clean(); + onConferenceCreated(addr); + if (session->getRemoteContactAddress()->hasParam("isfocus")) + eventHandler->subscribe(conferenceAddress); + } else if (d->state == ChatRoom::State::TerminationPending) { + focus->getPrivate()->getSession()->terminate(); + } + } else { + if ((state == LinphoneCallReleased) && (d->state == ChatRoom::State::TerminationPending)) { + onConferenceTerminated(conferenceAddress); + } } } diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index e5faf94d3..a535f751d 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -38,7 +38,7 @@ class ClientGroupChatRoomPrivate; class LINPHONE_PUBLIC ClientGroupChatRoom : public ChatRoom, public RemoteConference { public: ClientGroupChatRoom (LinphoneCore *core, const Address &me, const std::string &subject); - virtual ~ClientGroupChatRoom (); + virtual ~ClientGroupChatRoom () = default; public: /* ConferenceInterface */ @@ -49,6 +49,7 @@ public: int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; + void leave () override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; void setSubject (const std::string &subject) override; @@ -64,7 +65,7 @@ private: private: /* CallSessionListener */ - void onCallSessionSetTerminated (const std::shared_ptr session) override; + void onCallSessionSetReleased (const std::shared_ptr session) override; void onCallSessionStateChanged (const std::shared_ptr session, LinphoneCallState state, const std::string &message) override; private: diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 3046a40f1..f29a70fea 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -165,6 +165,8 @@ const string &RealTimeTextChatRoom::getSubject () const { return d->subject; } +void RealTimeTextChatRoom::leave () {} + void RealTimeTextChatRoom::removeParticipant (const shared_ptr &participant) { lError() << "removeParticipant() is not allowed on a RealTimeTextChatRoom"; } diff --git a/src/chat/real-time-text-chat-room.h b/src/chat/real-time-text-chat-room.h index 511bb15cc..9eacb9e3d 100644 --- a/src/chat/real-time-text-chat-room.h +++ b/src/chat/real-time-text-chat-room.h @@ -51,6 +51,7 @@ public: int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; + void leave () override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; void setSubject (const std::string &subject) override; diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index a897ae4b2..0829df832 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -42,6 +42,7 @@ public: virtual int getNbParticipants () const = 0; virtual std::list> getParticipants () const = 0; virtual const std::string &getSubject () const = 0; + virtual void leave () = 0; virtual void removeParticipant (const std::shared_ptr &participant) = 0; virtual void removeParticipants (const std::list> &participants) = 0; virtual void setSubject (const std::string &subject) = 0; diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 2d17c5010..eb274d158 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -76,6 +76,8 @@ const string &Conference::getSubject () const { return subject; } +void Conference::leave () {} + void Conference::removeParticipant (const shared_ptr &participant) { lError() << "Conference class does not handle removeParticipant() generically"; } @@ -171,6 +173,14 @@ shared_ptr Conference::findParticipant (const Address &addr) const return nullptr; } +shared_ptr Conference::findParticipant (const shared_ptr session) { + for (const auto &participant : participants) { + if (participant->getPrivate()->getSession() == session) + return participant; + } + return nullptr; +} + bool Conference::isMe (const Address &addr) const { Address cleanedAddress = me->getAddress(); cleanedAddress.setPort(0); diff --git a/src/conference/conference.h b/src/conference/conference.h index 43da4651a..5dafd55f2 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -55,6 +55,7 @@ public: int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; + void leave () override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; void setSubject (const std::string &subject) override; @@ -80,6 +81,7 @@ protected: explicit Conference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); std::shared_ptr findParticipant (const Address &addr) const; + std::shared_ptr findParticipant (const std::shared_ptr session); bool isMe (const Address &addr) const ; protected: diff --git a/src/conference/participant.h b/src/conference/participant.h index 9d5c01ce1..f0916fc1b 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -37,6 +37,7 @@ class Participant : public Object { friend class CallPrivate; friend class ClientGroupChatRoom; friend class ClientGroupChatRoomPrivate; + friend class Conference; friend class LocalConference; friend class MediaSessionPrivate; friend class RemoteConference; From 4f22ec0a6cc12569a04fd740764db82cd21c4244 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 6 Oct 2017 15:24:14 +0200 Subject: [PATCH 0340/2215] feat(EventsDb): import content text from legacy messages --- src/content/content-type.cpp | 1 + src/content/content-type.h | 1 + src/db/events-db.cpp | 146 +++++++++++++++++++++++++---------- 3 files changed, 106 insertions(+), 42 deletions(-) diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index 06b1bb967..76ff21ae3 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -38,6 +38,7 @@ public: // ----------------------------------------------------------------------------- const ContentType ContentType::Cpim("message/cpim"); +const ContentType ContentType::ExternalBody("message/external-body"); const ContentType ContentType::FileTransfer("application/vnd.gsma.rcs-ft-http+xml"); const ContentType ContentType::Imdn("message/imdn+xml"); const ContentType ContentType::ImIsComposing("application/im-iscomposing+xml"); diff --git a/src/content/content-type.h b/src/content/content-type.h index f944c99c2..dac4f5351 100644 --- a/src/content/content-type.h +++ b/src/content/content-type.h @@ -55,6 +55,7 @@ public: std::string asString () const; static const ContentType Cpim; + static const ContentType ExternalBody; static const ContentType FileTransfer; static const ContentType Imdn; static const ContentType ImIsComposing; diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index ae51560a1..de7a3fadd 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -28,6 +28,7 @@ #include "abstract/abstract-db-p.h" #include "chat/chat-message.h" +#include "content/content.h" #include "db/provider/db-session-provider.h" #include "event-log/call-event.h" #include "event-log/chat-message-event.h" @@ -35,6 +36,9 @@ #include "events-db.h" +#define MESSAGE_CONTENT_TYPE_TEXT 0 +#define MESSAGE_CONTENT_TYPE_FILE 1 + // ============================================================================= using namespace std; @@ -47,7 +51,6 @@ struct MessageEventReferences { long localSipAddressId; long remoteSipAddressId; long chatRoomId; - long contentTypeId; #endif }; @@ -55,6 +58,7 @@ class EventsDbPrivate : public AbstractDbPrivate { #ifdef SOCI_ENABLED public: long insertSipAddress (const string &sipAddress); + void insertContent (const Content &content, long messageEventId); long insertContentType (const string &contentType); long insertEvent (EventLog::Type type, const tm &date); long insertChatRoom (long sipAddressId, const tm &date); @@ -64,7 +68,7 @@ public: ChatMessage::Direction direction, const string &imdnMessageId, bool isSecured, - const string *text = nullptr + const list &contents ); void importLegacyMessages (const soci::rowset &messages); @@ -154,6 +158,34 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return q->getLastInsertId(); } + void EventsDbPrivate::insertContent (const Content &content, long messageEventId) { + L_Q(); + soci::session *session = dbSession.getBackendSession(); + + const ContentType &contentType = content.getContentType(); + int type; + if (contentType == ContentType::PlainText) + type = MESSAGE_CONTENT_TYPE_TEXT; + else if (contentType == ContentType::FileTransfer) + type = MESSAGE_CONTENT_TYPE_FILE; + else { + lWarning() << "Unable to insert in database unsupported content: `" << contentType.asString() << "`."; + return; + } + + long contentTypeId = insertContentType(contentType.asString()); + *session << "INSERT INTO message_content (message_event_id, content_type_id, type) VALUES" + " (:messageEventId, :contentTypeId, :type)", soci::use(messageEventId), soci::use(contentTypeId), soci::use(type); + + if (type == MESSAGE_CONTENT_TYPE_TEXT) { + *session << "INSERT INTO message_content_text (message_content_id, text) VALUES" + " (:messageContentId, :text)", soci::use(q->getLastInsertId()), soci::use(content.getBodyAsString()); + return; + } + + // TODO: MESSAGE_CONTENT_TYPE_FILE + } + long EventsDbPrivate::insertContentType (const string &contentType) { L_Q(); soci::session *session = dbSession.getBackendSession(); @@ -198,23 +230,27 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} ChatMessage::Direction direction, const string &imdnMessageId, bool isSecured, - const string *text + const list &contents ) { L_Q(); soci::session *session = dbSession.getBackendSession(); - soci::indicator textIndicator = text ? soci::i_ok : soci::i_null; *session << "INSERT INTO message_event (" " event_id, chat_room_id, local_sip_address_id, remote_sip_address_id," - " state, direction, imdn_message_id, is_secured, text" + " state, direction, imdn_message_id, is_secured" ") VALUES (" " :eventId, :chatRoomId, :localSipaddressId, :remoteSipaddressId," - " :state, :direction, :imdnMessageId, :isSecured, :text" + " :state, :direction, :imdnMessageId, :isSecured" ")", soci::use(references.eventId), soci::use(references.chatRoomId), soci::use(references.localSipAddressId), soci::use(references.remoteSipAddressId), soci::use(static_cast(state)), - soci::use(static_cast(direction)), soci::use(imdnMessageId), soci::use(isSecured ? 1 : 0), - soci::use(text ? *text : string(), textIndicator); - return q->getLastInsertId(); + soci::use(static_cast(direction)), soci::use(imdnMessageId), soci::use(isSecured ? 1 : 0); + + long messageEventId = q->getLastInsertId(); + + for (const auto &content : contents) + insertContent(content, messageEventId); + + return messageEventId; } // ----------------------------------------------------------------------------- @@ -248,25 +284,39 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} const tm date = Utils::getLongAsTm(message.get(9, 0)); - const bool noUrl = false; - const string url = getValueFromLegacyMessage(message, 8, const_cast(noUrl)); + bool isNull; + const string url = getValueFromLegacyMessage(message, 8, isNull); - const string contentType = message.get( - 13, - message.get(11, -1) != -1 - ? "application/vnd.gsma.rcs-ft-http+xml" - : (noUrl ? "text/plain" : "message/external-body") - ); + const int contentId = message.get(11, -1); + ContentType contentType(message.get(13, "")); + if (!contentType.isValid()) + contentType = contentId != -1 + ? ContentType::FileTransfer + : (isNull ? ContentType::PlainText : ContentType::ExternalBody); + if (contentType == ContentType::ExternalBody) { + lInfo() << "Import of external body content is skipped."; + continue; + } - const bool noText = false; - const string text = getValueFromLegacyMessage(message, 4, const_cast(noText)); + const string text = getValueFromLegacyMessage(message, 4, isNull); + + Content content; + content.setContentType(contentType); + if (contentType == ContentType::PlainText) { + if (isNull) { + lWarning() << "Unable to import legacy message with no text."; + continue; + } + content.setBody(text); + } else { + continue; + } struct MessageEventReferences references; references.eventId = insertEvent(EventLog::Type::ChatMessage, date); references.localSipAddressId = insertSipAddress(message.get(1)); references.remoteSipAddressId = insertSipAddress(message.get(2)); references.chatRoomId = insertChatRoom(references.remoteSipAddressId, date); - references.contentTypeId = insertContentType(contentType); insertMessageEvent ( references, @@ -274,7 +324,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} static_cast(direction), message.get(12, ""), !!message.get(14, 0), - noText ? nullptr : &text + { content } ); const bool noAppData = false; @@ -336,7 +386,6 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " chat_room_id INT UNSIGNED NOT NULL," " local_sip_address_id INT UNSIGNED NOT NULL," " remote_sip_address_id INT UNSIGNED NOT NULL," - " content_type_id INT UNSIGNED NOT NULL," // See: https://tools.ietf.org/html/rfc5438#section-6.3 " imdn_message_id VARCHAR(255) NOT NULL," @@ -345,8 +394,6 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " direction TINYINT UNSIGNED NOT NULL," " is_secured BOOLEAN NOT NULL," - " text TEXT," - " FOREIGN KEY (event_id)" " REFERENCES event(id)" " ON DELETE CASCADE," @@ -358,12 +405,45 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " ON DELETE CASCADE," " FOREIGN KEY (remote_sip_address_id)" " REFERENCES sip_address(id)" + " ON DELETE CASCADE" + ")"; + + *session << + "CREATE TABLE IF NOT EXISTS message_content (" + " id" + primaryKeyAutoIncrementStr() + "," + " message_event_id INT UNSIGNED NOT NULL," + " content_type_id INT UNSIGNED NOT NULL," + " type TINYINT UNSIGNED NOT NULL," + " FOREIGN KEY (message_event_id)" + " REFERENCES message_event(id)" " ON DELETE CASCADE," " FOREIGN KEY (content_type_id)" " REFERENCES content_type(id)" " ON DELETE CASCADE" ")"; + *session << + "CREATE TABLE IF NOT EXISTS message_content_text (" + " id" + primaryKeyAutoIncrementStr() + "," + " message_content_id INT UNSIGNED NOT NULL," + " text TEXT NOT NULL," + " FOREIGN KEY (message_content_id)" + " REFERENCES message_content(id)" + " ON DELETE CASCADE" + ")"; + + *session << + "CREATE TABLE IF NOT EXISTS message_content_file (" + " id" + primaryKeyAutoIncrementStr() + "," + " message_content_id INT UNSIGNED NOT NULL," + " name VARCHAR(255) NOT NULL," + " size INT UNSIGNED NOT NULL," + " url VARCHAR(255) NOT NULL," + " FOREIGN KEY (message_content_id)" + " REFERENCES message_content(id)" + " ON DELETE CASCADE" + ")"; + *session << "CREATE TABLE IF NOT EXISTS message_crypto_data (" " id" + primaryKeyAutoIncrementStr() + "," @@ -374,24 +454,6 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " REFERENCES message_event(id)" " ON DELETE CASCADE" ")"; - - *session << - "CREATE TABLE IF NOT EXISTS message_file_info (" - " id" + primaryKeyAutoIncrementStr() + "," - " message_id INT UNSIGNED NOT NULL," - " content_type_id INT UNSIGNED NOT NULL," - - " name VARCHAR(255) NOT NULL," - " size INT UNSIGNED NOT NULL," - " url VARCHAR(255) NOT NULL," - - " FOREIGN KEY (message_id)" - " REFERENCES message(id)" - " ON DELETE CASCADE" - " FOREIGN KEY (content_type_id)" - " REFERENCES content_type(id)" - " ON DELETE CASCADE" - ")"; } bool EventsDb::addEvent (const EventLog &eventLog) { From 5dc6b956df63e260d0bb535bbe05123962de35d3 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 6 Oct 2017 16:51:49 +0200 Subject: [PATCH 0341/2215] feat(EventsDb): deal with generic contents --- src/db/events-db.cpp | 57 +++++--------------------------------------- 1 file changed, 6 insertions(+), 51 deletions(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index de7a3fadd..e64babbff 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -36,9 +36,6 @@ #include "events-db.h" -#define MESSAGE_CONTENT_TYPE_TEXT 0 -#define MESSAGE_CONTENT_TYPE_FILE 1 - // ============================================================================= using namespace std; @@ -159,31 +156,12 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} } void EventsDbPrivate::insertContent (const Content &content, long messageEventId) { - L_Q(); soci::session *session = dbSession.getBackendSession(); - const ContentType &contentType = content.getContentType(); - int type; - if (contentType == ContentType::PlainText) - type = MESSAGE_CONTENT_TYPE_TEXT; - else if (contentType == ContentType::FileTransfer) - type = MESSAGE_CONTENT_TYPE_FILE; - else { - lWarning() << "Unable to insert in database unsupported content: `" << contentType.asString() << "`."; - return; - } - - long contentTypeId = insertContentType(contentType.asString()); - *session << "INSERT INTO message_content (message_event_id, content_type_id, type) VALUES" - " (:messageEventId, :contentTypeId, :type)", soci::use(messageEventId), soci::use(contentTypeId), soci::use(type); - - if (type == MESSAGE_CONTENT_TYPE_TEXT) { - *session << "INSERT INTO message_content_text (message_content_id, text) VALUES" - " (:messageContentId, :text)", soci::use(q->getLastInsertId()), soci::use(content.getBodyAsString()); - return; - } - - // TODO: MESSAGE_CONTENT_TYPE_FILE + long contentTypeId = insertContentType(content.getContentType().asString()); + *session << "INSERT INTO message_content (message_event_id, content_type_id, body) VALUES" + " (:messageEventId, :contentTypeId, :body)", soci::use(messageEventId), soci::use(contentTypeId), + soci::use(content.getBodyAsString()); } long EventsDbPrivate::insertContentType (const string &contentType) { @@ -381,8 +359,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS message_event (" - " id" + primaryKeyAutoIncrementStr() + "," - " event_id INT UNSIGNED NOT NULL," + " event_id INT UNSIGNED PRIMARY KEY," " chat_room_id INT UNSIGNED NOT NULL," " local_sip_address_id INT UNSIGNED NOT NULL," " remote_sip_address_id INT UNSIGNED NOT NULL," @@ -413,7 +390,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " id" + primaryKeyAutoIncrementStr() + "," " message_event_id INT UNSIGNED NOT NULL," " content_type_id INT UNSIGNED NOT NULL," - " type TINYINT UNSIGNED NOT NULL," + " body TEXT NOT NULL," " FOREIGN KEY (message_event_id)" " REFERENCES message_event(id)" " ON DELETE CASCADE," @@ -422,28 +399,6 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " ON DELETE CASCADE" ")"; - *session << - "CREATE TABLE IF NOT EXISTS message_content_text (" - " id" + primaryKeyAutoIncrementStr() + "," - " message_content_id INT UNSIGNED NOT NULL," - " text TEXT NOT NULL," - " FOREIGN KEY (message_content_id)" - " REFERENCES message_content(id)" - " ON DELETE CASCADE" - ")"; - - *session << - "CREATE TABLE IF NOT EXISTS message_content_file (" - " id" + primaryKeyAutoIncrementStr() + "," - " message_content_id INT UNSIGNED NOT NULL," - " name VARCHAR(255) NOT NULL," - " size INT UNSIGNED NOT NULL," - " url VARCHAR(255) NOT NULL," - " FOREIGN KEY (message_content_id)" - " REFERENCES message_content(id)" - " ON DELETE CASCADE" - ")"; - *session << "CREATE TABLE IF NOT EXISTS message_crypto_data (" " id" + primaryKeyAutoIncrementStr() + "," From 0db6249af53d492a02737dd412ff6e224b6c6433 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 6 Oct 2017 16:55:04 +0200 Subject: [PATCH 0342/2215] Simple ChatMessageMultipartModifier created + fixed a few things related to ChatMessages --- src/chat/chat-message-p.h | 2 +- src/chat/chat-message.cpp | 34 +++++--- src/chat/chat-room.cpp | 2 +- .../modifier/cpim-chat-message-modifier.cpp | 2 +- .../encryption-chat-message-modifier.cpp | 2 +- .../multipart-chat-message-modifier.cpp | 84 +++++++++++++++++-- src/content/content-type.cpp | 48 +++++++++-- src/content/content-type.h | 4 + tester/cpim-tester.cpp | 19 ++++- 9 files changed, 171 insertions(+), 26 deletions(-) diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 953e9b57d..569cd676c 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -152,7 +152,7 @@ private: bool isFileTransferInProgressAndValid(); int startHttpTransfer(std::string url, std::string action, belle_http_request_listener_callbacks_t *cbs); void releaseHttpRequest(); - void createFileTransferInformationsFromVndGsmaRcsFtHttpXml(); + void createFileTransferInformationsFromVndGsmaRcsFtHttpXml(std::string body); L_DECLARE_PUBLIC(ChatMessage); }; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 3723533b8..0c969fa4c 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -888,12 +888,12 @@ void ChatMessagePrivate::releaseHttpRequest() { } } -void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml() { +void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml(string body) { xmlChar *file_url = NULL; xmlDocPtr xmlMessageBody; xmlNodePtr cur; /* parse the msg body to get all informations from it */ - xmlMessageBody = xmlParseDoc((const xmlChar *)getText().c_str()); + xmlMessageBody = xmlParseDoc((const xmlChar *)body.c_str()); LinphoneContent *content = linphone_content_new(); setFileTransferInformation(content); @@ -1005,9 +1005,21 @@ LinphoneReason ChatMessagePrivate::receive() { // End of message modification // --------------------------------------- - if ((errorCode <= 0) && (linphone_core_is_content_type_supported(chatRoom->getCore(), getContentType().asString().c_str()) == FALSE)) { - errorCode = 415; - lError() << "Unsupported MESSAGE (content-type " << getContentType().asString() << " not recognized)"; + if (errorCode <= 0) { + bool foundSupportContentType = false; + for (auto it = contents.begin(); it != contents.end(); it++) { + if (linphone_core_is_content_type_supported(chatRoom->getCore(), it->getContentType().asString().c_str())) { + foundSupportContentType = true; + break; + } else { + lError() << "Unsupported content-type: " << it->getContentType().asString(); + } + } + + if (!foundSupportContentType) { + errorCode = 415; + lError() << "No content-type in the contents list is supported..."; + } } if (errorCode > 0) { @@ -1016,11 +1028,13 @@ LinphoneReason ChatMessagePrivate::receive() { return reason; } - if (getContentType() == ContentType::FileTransfer) { - createFileTransferInformationsFromVndGsmaRcsFtHttpXml(); - store = true; - } else if (getContentType() == ContentType::PlainText) { - store = true; + for (auto it = contents.begin(); it != contents.end(); it++) { + if (it->getContentType() == ContentType::FileTransfer) { + store = true; + createFileTransferInformationsFromVndGsmaRcsFtHttpXml(it->getBodyAsString()); + } else if (it->getContentType() == ContentType::PlainText) { + store = true; + } } if (store) { diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index c191040bd..eea1feab0 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -402,7 +402,7 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa Content content; content.setContentType(salMsg->content_type); content.setBody(salMsg->text ? salMsg->text : ""); - msg->addContent(content); + msg->setInternalContent(content); msg->setToAddress(op->get_to() ? op->get_to() : linphone_core_get_identity(core)); msg->setFromAddress(peerAddress); diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index 8d69fa301..c556c0d25 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -24,7 +24,7 @@ #include "content/content.h" #include "address/address.h" #include "logger/logger.h" -#include "chat/chat-message-p.h" +#include "chat/chat-message.h" // ============================================================================= diff --git a/src/chat/modifier/encryption-chat-message-modifier.cpp b/src/chat/modifier/encryption-chat-message-modifier.cpp index e1798c57f..cad20317a 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.cpp +++ b/src/chat/modifier/encryption-chat-message-modifier.cpp @@ -26,7 +26,7 @@ #include "content/content.h" #include "address/address.h" #include "chat/chat-room.h" -#include "chat/chat-message-p.h" +#include "chat/chat-message.h" // ============================================================================= diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index 7d2f5f36b..089173cd7 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -18,8 +18,11 @@ */ #include "multipart-chat-message-modifier.h" + #include "address/address.h" -#include "chat/chat-message-p.h" +#include "chat/chat-room.h" +#include "chat/chat-message.h" +#include "logger/logger.h" // ============================================================================= @@ -29,15 +32,86 @@ LINPHONE_BEGIN_NAMESPACE ChatMessageModifier::Result MultipartChatMessageModifier::encode (shared_ptr message, int *errorCode) { if (message->getContents().size() > 1) { - //TODO + LinphoneCore *lc = message->getChatRoom()->getCore(); + char tmp[64]; + lc->sal->create_uuid(tmp, sizeof(tmp)); + string boundary = tmp; + stringstream multipartMessage; + + multipartMessage << "--" << boundary; + for (auto it = message->getContents().begin(); it != message->getContents().end(); it++) { + multipartMessage << "\r\n"; + multipartMessage << "Content-Type: " << it->getContentType().asString() << "\r\n\r\n"; + multipartMessage << it->getBodyAsString() << "\r\n\r\n"; + multipartMessage << "--" << boundary; + } + multipartMessage << "--"; + + Content newContent; + ContentType newContentType("multipart/mixed"); + newContentType.setParameter("boundary=" + boundary); + newContent.setContentType(newContentType); + newContent.setBody(multipartMessage.str()); + message->setInternalContent(newContent); + return ChatMessageModifier::Result::Done; } return ChatMessageModifier::Result::Skipped; -} +} ChatMessageModifier::Result MultipartChatMessageModifier::decode (shared_ptr message, int *errorCode) { - //TODO - if (false) { // Multipart required + if (message->getInternalContent().getContentType().getType() == "multipart") { + string boundary = message->getInternalContent().getContentType().getParameter(); + if (boundary.empty()) { + lError() << "Boundary parameter of content-type not found !"; + return ChatMessageModifier::Result::Error; + } + + size_t pos = boundary.find("="); + if (pos == string::npos) { + lError() << "Parameter seems invalid: " << boundary; + return ChatMessageModifier::Result::Error; + } + boundary = "--" + boundary.substr(pos + 1); + lInfo() << "Multipart boundary is " << boundary; + + const vector body = message->getInternalContent().getBody(); + string contentsString(body.begin(), body.end()); + + pos = contentsString.find(boundary); + if (pos == string::npos) { + lError() << "Boundary not found in body !"; + return ChatMessageModifier::Result::Error; + } + + size_t start = pos + boundary.length() + 2; // 2 is the size of \r\n + size_t end; + do { + end = contentsString.find(boundary, start); + if (end != string::npos) { + string contentString = contentsString.substr(start, end-start); + + size_t contentTypePos = contentString.find(": ") + 2; // 2 is the size of : + size_t endOfLinePos = contentString.find("\r\n"); + if (contentTypePos >= endOfLinePos) { + lError() << "Content should start by a 'Content-Type: ' line !"; + continue; + } + string contentTypeString = contentString.substr(contentTypePos, endOfLinePos - contentTypePos); + ContentType contentType(contentTypeString); + + endOfLinePos += 4; // 4 is two time the size of \r\n + string contentBody = contentString.substr(endOfLinePos, contentString.length() - (endOfLinePos + 4)); // 4 is two time the size of \r\n + + Content content; + content.setContentType(contentType); + content.setBody(contentBody); + message->addContent(content); + + lInfo() << "Parsed and added content with type " << contentType.asString(); + } + start = end + boundary.length() + 2; // 2 is the size of \r\n + } while (end != string::npos); return ChatMessageModifier::Result::Done; } diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index 76ff21ae3..c6772c207 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -20,7 +20,7 @@ #include "linphone/utils/utils.h" #include "object/clonable-object-p.h" - +#include "logger/logger.h" #include "content-type.h" // ============================================================================= @@ -33,6 +33,7 @@ class ContentTypePrivate : public ClonableObjectPrivate { public: string type; string subType; + string parameter; }; // ----------------------------------------------------------------------------- @@ -52,13 +53,22 @@ ContentType::ContentType (const string &contentType) : ClonableObject(*new Conte L_D(); size_t pos = contentType.find('/'); + size_t posParam = contentType.find("; "); + size_t end = contentType.length(); if (pos == string::npos) return; if (setType(contentType.substr(0, pos))) { - if (!setSubType(contentType.substr(pos + 1))) + if (posParam != string::npos) { + end = posParam; + } + if (!setSubType(contentType.substr(pos + 1, end - (pos + 1)))) d->type.clear(); } + + if (posParam != string::npos) { + setParameter(contentType.substr(posParam + 2)); // We remove the blankspace after the ; + } } ContentType::ContentType (const string &type, const string &subType) : ClonableObject(*new ContentTypePrivate) { @@ -70,19 +80,30 @@ ContentType::ContentType (const string &type, const string &subType) : ClonableO } } -ContentType::ContentType (const ContentType &src) : ContentType(src.getType(), src.getSubType()) {} +ContentType::ContentType (const string &type, const string &subType, const string ¶meter) : ClonableObject(*new ContentTypePrivate) { + L_D(); + + if (setType(type)) { + if (!setSubType(subType)) + d->type.clear(); + } + setParameter(parameter); +} + +ContentType::ContentType (const ContentType &src) : ContentType(src.getType(), src.getSubType(), src.getParameter()) {} ContentType &ContentType::operator= (const ContentType &src) { if (this != &src) { setType(src.getType()); setSubType(src.getSubType()); + setParameter(src.getParameter()); } return *this; } bool ContentType::operator== (const ContentType &contentType) const { - return getType() == contentType.getType() && getSubType() == contentType.getSubType(); + return getType() == contentType.getType() && getSubType() == contentType.getSubType() && getParameter() == contentType.getParameter(); } bool ContentType::operator!= (const ContentType &contentType) const { @@ -117,6 +138,16 @@ bool ContentType::setSubType (const string &subType) { return false; } +const string &ContentType::getParameter () const { + L_D(); + return d->parameter; +} + +void ContentType::setParameter (const string ¶meter) { + L_D(); + d->parameter = parameter; +} + bool ContentType::isValid () const { L_D(); return !d->type.empty() && !d->subType.empty(); @@ -124,7 +155,14 @@ bool ContentType::isValid () const { string ContentType::asString () const { L_D(); - return isValid() ? d->type + "/" + d->subType : ""; + if (isValid()) { + string asString = d->type + "/" + d->subType; + if (!d->parameter.empty()) { + asString += "; " + d->parameter; + } + return asString; + } + return ""; } LINPHONE_END_NAMESPACE diff --git a/src/content/content-type.h b/src/content/content-type.h index dac4f5351..ebbbe9e19 100644 --- a/src/content/content-type.h +++ b/src/content/content-type.h @@ -32,6 +32,7 @@ class LINPHONE_PUBLIC ContentType : public ClonableObject { public: ContentType (const std::string &contentType = ""); ContentType (const std::string &type, const std::string &subType); + ContentType (const std::string &type, const std::string &subType, const std::string ¶meter); ContentType (const ContentType &src); ContentType &operator= (const ContentType &src); @@ -52,6 +53,9 @@ public: const std::string &getSubType () const; bool setSubType (const std::string &subType); + const std::string &getParameter () const; + void setParameter (const std::string ¶meter); + std::string asString () const; static const ContentType Cpim; diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index ce778ee6e..191792e57 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -382,7 +382,7 @@ static void build_message () { BC_ASSERT_STRING_EQUAL(strMessage.c_str(), expectedMessage.c_str()); } -static void cpim_chat_message_modifier(void) { +static void cpim_chat_message_modifier_base(bool_t use_multipart) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); LpConfig *config = linphone_core_get_config(marie->lc); @@ -392,6 +392,12 @@ static void cpim_chat_message_modifier(void) { shared_ptr marieRoom = ObjectFactory::create(marie->lc, paulineAddress); shared_ptr marieMessage = marieRoom->createMessage("Hello CPIM"); + if (use_multipart) { + Content content; + content.setContentType(ContentType::PlainText); + content.setBody("Hello Part 2"); + marieMessage->addContent(content); + } marieRoom->sendMessage(marieMessage); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageReceived,1)); @@ -407,6 +413,14 @@ static void cpim_chat_message_modifier(void) { linphone_core_manager_destroy(pauline); } +static void cpim_chat_message_modifier(void) { + cpim_chat_message_modifier_base(FALSE); +} + +static void cpim_chat_message_modifier_with_multipart_body(void) { + cpim_chat_message_modifier_base(TRUE); +} + test_t cpim_tests[] = { TEST_NO_TAG("Parse minimal CPIM message", parse_minimal_message), TEST_NO_TAG("Set generic header name", set_generic_header_name), @@ -417,7 +431,8 @@ test_t cpim_tests[] = { TEST_NO_TAG("Parse RFC example", parse_rfc_example), TEST_NO_TAG("Parse Message with generic header parameters", parse_message_with_generic_header_parameters), TEST_NO_TAG("Build Message", build_message), - TEST_NO_TAG("CPIM chat message modifier", cpim_chat_message_modifier) + TEST_NO_TAG("CPIM chat message modifier", cpim_chat_message_modifier), + TEST_NO_TAG("CPIM chat message modifier with multipart body", cpim_chat_message_modifier_with_multipart_body), }; test_suite_t cpim_test_suite = { From b1f48f57695101624ed785c58f14ca7eb3368ad5 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 6 Oct 2017 17:03:34 +0200 Subject: [PATCH 0343/2215] Fixed ChatMessage methods getContentType and getText when receiving a multipart --- src/chat/chat-message.cpp | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 0c969fa4c..6bc880351 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -141,12 +141,21 @@ string ChatMessagePrivate::getSalCustomHeaderValue(const string& name) { // ----------------------------------------------------------------------------- const ContentType& ChatMessagePrivate::getContentType() { - if (internalContent.getContentType().isValid()) { - cContentType = internalContent.getContentType(); - } else { + if (direction == ChatMessage::Direction::Incoming) { if (contents.size() > 0) { Content content = contents.front(); cContentType = content.getContentType(); + } else { + cContentType = internalContent.getContentType(); + } + } else { + if (internalContent.getContentType().isValid()) { + cContentType = internalContent.getContentType(); + } else { + if (contents.size() > 0) { + Content content = contents.front(); + cContentType = content.getContentType(); + } } } return cContentType; @@ -157,12 +166,21 @@ void ChatMessagePrivate::setContentType(const ContentType &contentType) { } const string& ChatMessagePrivate::getText() { - if (!internalContent.isEmpty()) { - cText = internalContent.getBodyAsString(); - } else { + if (direction == ChatMessage::Direction::Incoming) { if (contents.size() > 0) { Content content = contents.front(); cText = content.getBodyAsString(); + } else { + cText = internalContent.getBodyAsString(); + } + } else { + if (!internalContent.isEmpty()) { + cText = internalContent.getBodyAsString(); + } else { + if (contents.size() > 0) { + Content content = contents.front(); + cText = content.getBodyAsString(); + } } } return cText; From 4fc90808810c2b28a68cf45ba4b43ccee92d949d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 6 Oct 2017 17:06:07 +0200 Subject: [PATCH 0344/2215] Try not to use getContentType and getText methods --- src/chat/chat-message.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 6bc880351..39a6cd747 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -996,7 +996,7 @@ LinphoneReason ChatMessagePrivate::receive() { // Start of message modification // --------------------------------------- - if (getContentType() == ContentType::Cpim) { + if (internalContent.getContentType() == ContentType::Cpim) { CpimChatMessageModifier ccmm; ccmm.decode(q->getSharedFromThis(), &errorCode); } @@ -1174,6 +1174,10 @@ void ChatMessagePrivate::send() { // End of message modification // --------------------------------------- + if (internalContent.isEmpty()) { + internalContent = contents.front(); + } + if (!externalBodyUrl.empty()) { char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", externalBodyUrl.c_str()); auto msgOp = dynamic_cast(op); @@ -1181,10 +1185,10 @@ void ChatMessagePrivate::send() { ms_free(content_type); } else { auto msgOp = dynamic_cast(op); - if (getContentType().isValid()) { - msgOp->send_message(from.asString().c_str(), chatRoom->getPeerAddress().asString().c_str(), getContentType().asString().c_str(), getText().c_str(), chatRoom->getPeerAddress().asStringUriOnly().c_str()); + if (internalContent.getContentType().isValid()) { + msgOp->send_message(from.asString().c_str(), chatRoom->getPeerAddress().asString().c_str(), internalContent.getContentType().asString().c_str(), internalContent.getBodyAsString().c_str(), chatRoom->getPeerAddress().asStringUriOnly().c_str()); } else { - msgOp->send_message(from.asString().c_str(), chatRoom->getPeerAddress().asString().c_str(), getText().c_str()); + msgOp->send_message(from.asString().c_str(), chatRoom->getPeerAddress().asString().c_str(), internalContent.getBodyAsString().c_str()); } } From 4cb0e8028cc1be2b60785fa00d972a0f031f41c6 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 9 Oct 2017 10:32:42 +0200 Subject: [PATCH 0345/2215] feat(Tester): add tools to access private data --- .../utils => tester/tools}/private-access.h | 0 tester/tools/tester.h | 55 +++++++++++++++++++ 2 files changed, 55 insertions(+) rename {include/linphone/utils => tester/tools}/private-access.h (100%) create mode 100644 tester/tools/tester.h diff --git a/include/linphone/utils/private-access.h b/tester/tools/private-access.h similarity index 100% rename from include/linphone/utils/private-access.h rename to tester/tools/private-access.h diff --git a/tester/tools/tester.h b/tester/tools/tester.h new file mode 100644 index 000000000..9389c560d --- /dev/null +++ b/tester/tools/tester.h @@ -0,0 +1,55 @@ +/* + * tester.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _TESTER_H_ +#define _TESTER_H_ + +#include + +#include "utils/utils.h" + +// ============================================================================= + +// ----------------------------------------------------------------------------- +// Internal. +// ----------------------------------------------------------------------------- + +LINPHONE_BEGIN_NAMESPACE + +class Tester { +public: + template + static constexpr decltype(std::declval().getPrivate()) getPrivate (Object *cppObject) { + return cppObject->getPrivate(); + } + +private: + L_DISABLE_COPY(Tester); +}; + +LINPHONE_END_NAMESPACE + +// ----------------------------------------------------------------------------- +// Public. +// ----------------------------------------------------------------------------- + +#define L_GET_PRIVATE(OBJECT) \ + LinphonePrivate::Tester::getPrivate(LinphonePrivate::Utils::getPtr(OBJECT)) + +#endif // ifndef _TESTER_H_ From 94c9ad33a5ecd1eea2146d700ab8b1a975362547 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 9 Oct 2017 10:36:11 +0200 Subject: [PATCH 0346/2215] forbid Tester helper creation --- tester/tools/tester.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tester/tools/tester.h b/tester/tools/tester.h index 9389c560d..de2701d50 100644 --- a/tester/tools/tester.h +++ b/tester/tools/tester.h @@ -34,6 +34,8 @@ LINPHONE_BEGIN_NAMESPACE class Tester { public: + Tester () = delete; + template static constexpr decltype(std::declval().getPrivate()) getPrivate (Object *cppObject) { return cppObject->getPrivate(); From f8abe9ad07554aa22eb1762823339df40f0cba76 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 9 Oct 2017 10:53:55 +0200 Subject: [PATCH 0347/2215] Started multipart tester --- .../multipart-chat-message-modifier.cpp | 2 +- tester/CMakeLists.txt | 1 + tester/liblinphone_tester.h | 1 + tester/message_tester.c | 13 ++-- tester/multipart-tester.cpp | 77 +++++++++++++++++++ tester/tester.c | 1 + 6 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 tester/multipart-tester.cpp diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index 089173cd7..895a1a6d9 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -63,7 +63,7 @@ ChatMessageModifier::Result MultipartChatMessageModifier::decode (shared_ptrgetInternalContent().getContentType().getType() == "multipart") { string boundary = message->getInternalContent().getContentType().getParameter(); if (boundary.empty()) { - lError() << "Boundary parameter of content-type not found !"; + lError() << "Boundary parameter of content-type not found: " << message->getInternalContent().getContentType().asString(); return ChatMessageModifier::Result::Error; } diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index cd5bba8c7..947fb295d 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -200,6 +200,7 @@ set(SOURCE_FILES_CXX # conference-event-tester.cpp conference-tester.cpp cpim-tester.cpp + multipart-tester.cpp events-db-tester.cpp property-container-tester.cpp ) diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index de8174668..94c0cc7f0 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -55,6 +55,7 @@ extern test_suite_t log_collection_test_suite; extern test_suite_t message_test_suite; extern test_suite_t multi_call_test_suite; extern test_suite_t multicast_call_test_suite; +extern test_suite_t multipart_test_suite; extern test_suite_t offeranswer_test_suite; extern test_suite_t player_test_suite; extern test_suite_t presence_server_test_suite; diff --git a/tester/message_tester.c b/tester/message_tester.c index 6aa7cf4ed..0cd61f82a 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -2482,8 +2482,6 @@ test_t message_tests[] = { TEST_NO_TAG("Transfer message using external body url", file_transfer_using_external_body_url), TEST_NO_TAG("Transfer 2 messages simultaneously", file_transfer_2_messages_simultaneously), TEST_NO_TAG("Text message denied", text_message_denied), - TEST_NO_TAG("Info message", info_message), - TEST_NO_TAG("Info message with body", info_message_with_body), TEST_NO_TAG("IsComposing notification", is_composing_notification), TEST_NO_TAG("IMDN notifications", imdn_notifications), TEST_NO_TAG("IM notification policy", im_notification_policy), @@ -2511,13 +2509,10 @@ test_t message_tests[] = { TEST_NO_TAG("Database migration", database_migration), TEST_NO_TAG("History range", history_range), TEST_NO_TAG("History count", history_count), - TEST_NO_TAG("Crash during file transfer", crash_during_file_transfer), #endif - TEST_NO_TAG("Text status after destroying chat room", text_status_after_destroying_chat_room), TEST_NO_TAG("Transfer not sent if invalid url", file_transfer_not_sent_if_invalid_url), TEST_NO_TAG("Transfer not sent if host not found", file_transfer_not_sent_if_host_not_found), TEST_NO_TAG("Transfer not sent if url moved permanently", file_transfer_not_sent_if_url_moved_permanently), - TEST_ONE_TAG("Transfer io error after destroying chatroom", file_transfer_io_error_after_destroying_chatroom, "LeaksMemory"), TEST_ONE_TAG("Real Time Text message", real_time_text_message, "RTT"), TEST_ONE_TAG("Real Time Text SQL storage", real_time_text_sql_storage, "RTT"), TEST_ONE_TAG("Real Time Text SQL storage with RTT messages not stored", real_time_text_sql_storage_rtt_disabled, "RTT"), @@ -2537,7 +2532,13 @@ test_t message_tests[] = { TEST_ONE_TAG("Text message with custom content-type and lime", text_message_with_custom_content_type_and_lime, "LIME"), #endif TEST_NO_TAG("IM Encryption Engine b64", im_encryption_engine_b64), - TEST_NO_TAG("IM Encryption Engine b64 async", im_encryption_engine_b64_async) + TEST_NO_TAG("IM Encryption Engine b64 async", im_encryption_engine_b64_async), +// Crash currently + TEST_NO_TAG("Info message", info_message), + TEST_NO_TAG("Info message with body", info_message_with_body), + TEST_NO_TAG("Crash during file transfer", crash_during_file_transfer), + TEST_NO_TAG("Text status after destroying chat room", text_status_after_destroying_chat_room), + TEST_ONE_TAG("Transfer io error after destroying chatroom", file_transfer_io_error_after_destroying_chatroom, "LeaksMemory"), }; static int message_tester_before_suite(void) { diff --git a/tester/multipart-tester.cpp b/tester/multipart-tester.cpp new file mode 100644 index 000000000..470b05bd7 --- /dev/null +++ b/tester/multipart-tester.cpp @@ -0,0 +1,77 @@ +/* + * cpim-tester.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ + +#include "address/address.h" +#include "chat/basic-chat-room.h" +#include "chat/chat-message.h" + +#include "liblinphone_tester.h" + +// ============================================================================= + +using namespace std; + +using namespace LinphonePrivate; + +static void chat_message_multipart_modifier_base(bool first_file_transfer, bool second_file_transfer) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + + Address paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); + shared_ptr marieRoom = ObjectFactory::create(marie->lc, paulineAddress); + + shared_ptr marieMessage; + if (first_file_transfer) { + //TODO + marieMessage = marieRoom->createFileTransferMessage(NULL); + } else { + marieMessage = marieRoom->createMessage("Hello Part 1"); + } + + if (second_file_transfer) { + //TODO + } else { + Content content; + content.setContentType(ContentType::PlainText); + content.setBody("Hello Part 2"); + marieMessage->addContent(content); + } + marieRoom->sendMessage(marieMessage); + + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageReceived,1)); + BC_ASSERT_STRING_EQUAL(marieMessage->getInternalContent().getContentType().asString().c_str(), "multipart/mixed"); + + BC_ASSERT_PTR_NOT_NULL(pauline->stat.last_received_chat_message); + //TODO + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void multipart_two_text_content(void) { + chat_message_multipart_modifier_base(false, false); +} + +test_t multipart_tests[] = { + TEST_NO_TAG("Chat message multipart 2 text content", multipart_two_text_content), +}; + +test_suite_t multipart_test_suite = { + "Multipart", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each, + sizeof(multipart_tests) / sizeof(multipart_tests[0]), multipart_tests +}; diff --git a/tester/tester.c b/tester/tester.c index c5e58e042..50be44792 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -572,6 +572,7 @@ void liblinphone_tester_add_suites() { bc_tester_add_suite(&player_test_suite); bc_tester_add_suite(&dtmf_test_suite); bc_tester_add_suite(&cpim_test_suite); + bc_tester_add_suite(&multipart_test_suite); bc_tester_add_suite(&clonable_object_test_suite); bc_tester_add_suite(&events_db_test_suite); bc_tester_add_suite(&property_container_test_suite); From e5c3a5a96a958bbf45ff187a20287f9b9d5992f6 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 9 Oct 2017 11:04:59 +0200 Subject: [PATCH 0348/2215] feat(EventsDb): add new table => message_participant --- include/linphone/utils/general.h | 2 +- src/content/content-type.h | 2 +- src/db/events-db.cpp | 22 +++++++++++++++++++--- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index fea6e3ff0..b11044e92 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -127,7 +127,7 @@ constexpr T *getPublicHelper (Object *object, const ObjectPrivate *) { friend class CLASS; #define L_DISABLE_COPY(CLASS) \ - CLASS(const CLASS &) = delete; \ + CLASS (const CLASS &) = delete; \ CLASS &operator= (const CLASS &) = delete; #define L_D() decltype(std::declval().getPrivate()) const d = getPrivate(); diff --git a/src/content/content-type.h b/src/content/content-type.h index ebbbe9e19..c2a1d0ba1 100644 --- a/src/content/content-type.h +++ b/src/content/content-type.h @@ -30,7 +30,7 @@ class ContentTypePrivate; class LINPHONE_PUBLIC ContentType : public ClonableObject { public: - ContentType (const std::string &contentType = ""); + explicit ContentType (const std::string &contentType = ""); ContentType (const std::string &type, const std::string &subType); ContentType (const std::string &type, const std::string &subType, const std::string ¶meter); ContentType (const ContentType &src); diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index e64babbff..405b70552 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -305,9 +305,10 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} { content } ); - const bool noAppData = false; - const string appData = getValueFromLegacyMessage(message, 10, const_cast(noAppData)); - (void)appData; + bool noAppData = false; + const string appData = getValueFromLegacyMessage(message, 10, noAppData); + if (!noAppData) + return; } tr.commit(); @@ -385,6 +386,21 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " ON DELETE CASCADE" ")"; + *session << + "CREATE TABLE IF NOT EXISTS message_participant (" + " message_event_id INT UNSIGNED NOT NULL," + " sip_address_id INT UNSIGNED NOT NULL," + " state TINYINT UNSIGNED NOT NULL," + + " PRIMARY KEY (message_event_id, sip_address_id)," + " FOREIGN KEY (message_event_id)" + " REFERENCES message_event(id)" + " ON DELETE CASCADE," + " FOREIGN KEY (sip_address_id)" + " REFERENCES sip_address(id)" + " ON DELETE CASCADE," + ")"; + *session << "CREATE TABLE IF NOT EXISTS message_content (" " id" + primaryKeyAutoIncrementStr() + "," From 4577b09493584ec076aa6a13c071a7e5a8924cf1 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 9 Oct 2017 11:06:16 +0200 Subject: [PATCH 0349/2215] feat(Core): Address and Logger use explicit constructors --- src/address/address.h | 2 +- src/logger/logger.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/address/address.h b/src/address/address.h index e8ab35c8f..ffd32fc5e 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -36,7 +36,7 @@ class LINPHONE_PUBLIC Address : public ClonableObject { friend class ClientGroupChatRoomPrivate; public: - Address (const std::string &address = ""); + explicit Address (const std::string &address = ""); Address (const Address &src); ~Address (); diff --git a/src/logger/logger.h b/src/logger/logger.h index 2a904e85c..5c8a9ea19 100644 --- a/src/logger/logger.h +++ b/src/logger/logger.h @@ -40,7 +40,7 @@ public: Fatal }; - Logger (Level level); + explicit Logger (Level level); ~Logger (); std::ostringstream &getOutput (); From efb0bd5c7a310192f4a891ad4fe16a0a1be828ff Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 9 Oct 2017 11:22:51 +0200 Subject: [PATCH 0350/2215] feat(Conference): use shared_ptr ref sessions --- src/chat/client-group-chat-room.cpp | 7 ++--- src/chat/client-group-chat-room.h | 4 +-- src/conference/conference.cpp | 28 +++++++++---------- src/conference/conference.h | 28 +++++++++---------- src/conference/participant.cpp | 9 ++++-- src/conference/participant.h | 3 +- .../session/call-session-listener.h | 26 ++++++++--------- 7 files changed, 55 insertions(+), 50 deletions(-) diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 5deeb9b26..4966fcee0 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -54,8 +54,7 @@ shared_ptr ClientGroupChatRoomPrivate::createSession () { ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, const string &subject) : ChatRoom(*new ClientGroupChatRoomPrivate(core)), RemoteConference(core, me, nullptr) { - string factoryUri = linphone_core_get_conference_factory_uri(core); - focus = ObjectFactory::create(factoryUri); + focus = ObjectFactory::create(Address(linphone_core_get_conference_factory_uri(core))); this->subject = subject; } @@ -227,12 +226,12 @@ void ClientGroupChatRoom::onSubjectChanged (const std::string &subject) { // ----------------------------------------------------------------------------- -void ClientGroupChatRoom::onCallSessionSetReleased (const std::shared_ptr session) { +void ClientGroupChatRoom::onCallSessionSetReleased (const std::shared_ptr &session) { if (session == focus->getPrivate()->getSession()) focus->getPrivate()->removeSession(); } -void ClientGroupChatRoom::onCallSessionStateChanged (const std::shared_ptr session, LinphoneCallState state, const string &message) { +void ClientGroupChatRoom::onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const string &message) { L_D(); if (state == LinphoneCallConnected) { if (d->state == ChatRoom::State::CreationPending) { diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index a535f751d..eaf212f52 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -65,8 +65,8 @@ private: private: /* CallSessionListener */ - void onCallSessionSetReleased (const std::shared_ptr session) override; - void onCallSessionStateChanged (const std::shared_ptr session, LinphoneCallState state, const std::string &message) override; + void onCallSessionSetReleased (const std::shared_ptr &session) override; + void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) override; private: L_DECLARE_PRIVATE(ClientGroupChatRoom); diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index eb274d158..d6e626088 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -93,47 +93,47 @@ void Conference::setSubject (const string &subject) { // ----------------------------------------------------------------------------- -void Conference::onAckBeingSent (const std::shared_ptr session, LinphoneHeaders *headers) { +void Conference::onAckBeingSent (const std::shared_ptr &session, LinphoneHeaders *headers) { if (callListener) callListener->onAckBeingSent(headers); } -void Conference::onAckReceived (const std::shared_ptr session, LinphoneHeaders *headers) { +void Conference::onAckReceived (const std::shared_ptr &session, LinphoneHeaders *headers) { if (callListener) callListener->onAckReceived(headers); } -void Conference::onCallSessionAccepted (const std::shared_ptr session) { +void Conference::onCallSessionAccepted (const std::shared_ptr &session) { if (callListener) callListener->onIncomingCallToBeAdded(); } -void Conference::onCallSessionSetReleased (const std::shared_ptr session) { +void Conference::onCallSessionSetReleased (const std::shared_ptr &session) { if (callListener) callListener->onCallSetReleased(); } -void Conference::onCallSessionSetTerminated (const std::shared_ptr session) { +void Conference::onCallSessionSetTerminated (const std::shared_ptr &session) { if (callListener) callListener->onCallSetTerminated(); } -void Conference::onCallSessionStateChanged (const std::shared_ptr session, LinphoneCallState state, const string &message) { +void Conference::onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const string &message) { if (callListener) callListener->onCallStateChanged(state, message); } -void Conference::onCheckForAcceptation (const std::shared_ptr session) { +void Conference::onCheckForAcceptation (const std::shared_ptr &session) { if (callListener) callListener->onCheckForAcceptation(); } -void Conference::onIncomingCallSessionStarted (const std::shared_ptr session) { +void Conference::onIncomingCallSessionStarted (const std::shared_ptr &session) { if (callListener) callListener->onIncomingCallStarted(); } -void Conference::onEncryptionChanged (const std::shared_ptr session, bool activated, const string &authToken) { +void Conference::onEncryptionChanged (const std::shared_ptr &session, bool activated, const string &authToken) { if (callListener) callListener->onEncryptionChanged(activated, authToken); } @@ -143,22 +143,22 @@ void Conference::onStatsUpdated (const LinphoneCallStats *stats) { callListener->onStatsUpdated(stats); } -void Conference::onResetCurrentSession (const std::shared_ptr session) { +void Conference::onResetCurrentSession (const std::shared_ptr &session) { if (callListener) callListener->onResetCurrentCall(); } -void Conference::onSetCurrentSession (const std::shared_ptr session) { +void Conference::onSetCurrentSession (const std::shared_ptr &session) { if (callListener) callListener->onSetCurrentCall(); } -void Conference::onFirstVideoFrameDecoded (const std::shared_ptr session) { +void Conference::onFirstVideoFrameDecoded (const std::shared_ptr &session) { if (callListener) callListener->onFirstVideoFrameDecoded(); } -void Conference::onResetFirstVideoFrameDecoded (const std::shared_ptr session) { +void Conference::onResetFirstVideoFrameDecoded (const std::shared_ptr &session) { if (callListener) callListener->onResetFirstVideoFrameDecoded(); } @@ -173,7 +173,7 @@ shared_ptr Conference::findParticipant (const Address &addr) const return nullptr; } -shared_ptr Conference::findParticipant (const shared_ptr session) { +shared_ptr Conference::findParticipant (const shared_ptr &session) { for (const auto &participant : participants) { if (participant->getPrivate()->getSession() == session) return participant; diff --git a/src/conference/conference.h b/src/conference/conference.h index 5dafd55f2..2ee2c452d 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -62,26 +62,26 @@ public: private: /* CallSessionListener */ - void onAckBeingSent (const std::shared_ptr session, LinphoneHeaders *headers) override; - void onAckReceived (const std::shared_ptr session, LinphoneHeaders *headers) override; - void onCallSessionAccepted (const std::shared_ptr session) override; - void onCallSessionSetReleased (const std::shared_ptr session) override; - void onCallSessionSetTerminated (const std::shared_ptr session) override; - void onCallSessionStateChanged (const std::shared_ptr session, LinphoneCallState state, const std::string &message) override; - void onCheckForAcceptation (const std::shared_ptr session) override; - void onIncomingCallSessionStarted (const std::shared_ptr session) override; - void onEncryptionChanged (const std::shared_ptr session, bool activated, const std::string &authToken) override; + void onAckBeingSent (const std::shared_ptr &session, LinphoneHeaders *headers) override; + void onAckReceived (const std::shared_ptr &session, LinphoneHeaders *headers) override; + void onCallSessionAccepted (const std::shared_ptr &session) override; + void onCallSessionSetReleased (const std::shared_ptr &session) override; + void onCallSessionSetTerminated (const std::shared_ptr &session) override; + void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) override; + void onCheckForAcceptation (const std::shared_ptr &session) override; + void onIncomingCallSessionStarted (const std::shared_ptr &session) override; + void onEncryptionChanged (const std::shared_ptr &session, bool activated, const std::string &authToken) override; void onStatsUpdated (const LinphoneCallStats *stats) override; - void onResetCurrentSession (const std::shared_ptr session) override; - void onSetCurrentSession (const std::shared_ptr session) override; - void onFirstVideoFrameDecoded (const std::shared_ptr session) override; - void onResetFirstVideoFrameDecoded (const std::shared_ptr session) override; + void onResetCurrentSession (const std::shared_ptr &session) override; + void onSetCurrentSession (const std::shared_ptr &session) override; + void onFirstVideoFrameDecoded (const std::shared_ptr &session) override; + void onResetFirstVideoFrameDecoded (const std::shared_ptr &session) override; protected: explicit Conference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); std::shared_ptr findParticipant (const Address &addr) const; - std::shared_ptr findParticipant (const std::shared_ptr session); + std::shared_ptr findParticipant (const std::shared_ptr &session); bool isMe (const Address &addr) const ; protected: diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index 83544da5e..6cfe04a0f 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -43,9 +43,14 @@ shared_ptr ParticipantPrivate::createSession ( // ============================================================================= -Participant::Participant (const Address &addr) : Object(*new ParticipantPrivate) { +Participant::Participant (const Address &address) : Object(*new ParticipantPrivate) { L_D(); - d->addr = addr; + d->addr = address; +} + +Participant::Participant (Address &&address) : Object(*new ParticipantPrivate) { + L_D(); + d->addr = move(address); } // ----------------------------------------------------------------------------- diff --git a/src/conference/participant.h b/src/conference/participant.h index f0916fc1b..dd5de40ad 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -43,7 +43,8 @@ class Participant : public Object { friend class RemoteConference; public: - Participant (const Address &addr); + Participant (const Address &address); + Participant (Address &&address); const Address& getAddress () const; diff --git a/src/conference/session/call-session-listener.h b/src/conference/session/call-session-listener.h index 5529e62fa..8b6d72edf 100644 --- a/src/conference/session/call-session-listener.h +++ b/src/conference/session/call-session-listener.h @@ -28,24 +28,24 @@ class LINPHONE_PUBLIC CallSessionListener { public: virtual ~CallSessionListener() = default; - virtual void onAckBeingSent (const std::shared_ptr session, LinphoneHeaders *headers) = 0; - virtual void onAckReceived (const std::shared_ptr session, LinphoneHeaders *headers) = 0; - virtual void onCallSessionAccepted (const std::shared_ptr session) = 0; - virtual void onCallSessionSetReleased (const std::shared_ptr session) = 0; - virtual void onCallSessionSetTerminated (const std::shared_ptr session) = 0; - virtual void onCallSessionStateChanged (const std::shared_ptr session, LinphoneCallState state, const std::string &message) = 0; - virtual void onCheckForAcceptation (const std::shared_ptr session) = 0; - virtual void onIncomingCallSessionStarted (const std::shared_ptr session) = 0; + virtual void onAckBeingSent (const std::shared_ptr &session, LinphoneHeaders *headers) = 0; + virtual void onAckReceived (const std::shared_ptr &session, LinphoneHeaders *headers) = 0; + virtual void onCallSessionAccepted (const std::shared_ptr &session) = 0; + virtual void onCallSessionSetReleased (const std::shared_ptr &session) = 0; + virtual void onCallSessionSetTerminated (const std::shared_ptr &session) = 0; + virtual void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) = 0; + virtual void onCheckForAcceptation (const std::shared_ptr &session) = 0; + virtual void onIncomingCallSessionStarted (const std::shared_ptr &session) = 0; - virtual void onEncryptionChanged (const std::shared_ptr session, bool activated, const std::string &authToken) = 0; + virtual void onEncryptionChanged (const std::shared_ptr &session, bool activated, const std::string &authToken) = 0; virtual void onStatsUpdated (const LinphoneCallStats *stats) = 0; - virtual void onResetCurrentSession (const std::shared_ptr session) = 0; - virtual void onSetCurrentSession (const std::shared_ptr session) = 0; + virtual void onResetCurrentSession (const std::shared_ptr &session) = 0; + virtual void onSetCurrentSession (const std::shared_ptr &session) = 0; - virtual void onFirstVideoFrameDecoded (const std::shared_ptr session) = 0; - virtual void onResetFirstVideoFrameDecoded (const std::shared_ptr session) = 0; + virtual void onFirstVideoFrameDecoded (const std::shared_ptr &session) = 0; + virtual void onResetFirstVideoFrameDecoded (const std::shared_ptr &session) = 0; }; LINPHONE_END_NAMESPACE From 693bd2b78aa124f6b9029979536fb65c28905bda Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 9 Oct 2017 11:31:02 +0200 Subject: [PATCH 0351/2215] fix(Core): little performance fixes --- src/chat/cpim/parser/cpim-parser.cpp | 5 +---- src/core/core.h | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/chat/cpim/parser/cpim-parser.cpp b/src/chat/cpim/parser/cpim-parser.cpp index df9bbbac5..4fee76f9e 100644 --- a/src/chat/cpim/parser/cpim-parser.cpp +++ b/src/chat/cpim/parser/cpim-parser.cpp @@ -44,10 +44,7 @@ namespace Cpim { public: HeaderNode () = default; - explicit HeaderNode (const Header &header) { - mName = header.getName(); - mValue = header.getValue(); - + explicit HeaderNode (const Header &header) : mName(header.getName()), mValue(header.getValue()) { // Generic header. const GenericHeader *genericHeader = dynamic_cast(&header); if (genericHeader) { diff --git a/src/core/core.h b/src/core/core.h index 0a2cbf81f..025c60d22 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -33,7 +33,7 @@ public: // Nothing for the moment. private: - Core (CorePrivate &p); + explicit Core (CorePrivate &p); L_DECLARE_PRIVATE(Core); L_DISABLE_COPY(Core); From 0e671c0563938512563b2b06426e39ed4cd0c563 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 9 Oct 2017 12:14:51 +0200 Subject: [PATCH 0352/2215] Fix build. --- src/chat/cpim/parser/cpim-parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chat/cpim/parser/cpim-parser.cpp b/src/chat/cpim/parser/cpim-parser.cpp index 4fee76f9e..282b157f2 100644 --- a/src/chat/cpim/parser/cpim-parser.cpp +++ b/src/chat/cpim/parser/cpim-parser.cpp @@ -102,8 +102,8 @@ namespace Cpim { return header; } - string mValue; string mName; + string mValue; string mParameters; }; From 6394230a6c1be8af61f26092072da32bd1848b5a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 9 Oct 2017 12:05:39 +0200 Subject: [PATCH 0353/2215] Add missing Refer-To header when sending a REFER with the SalReferOp. --- src/sal/refer-op.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sal/refer-op.cpp b/src/sal/refer-op.cpp index 6a28b197e..bf666f43b 100644 --- a/src/sal/refer-op.cpp +++ b/src/sal/refer-op.cpp @@ -61,8 +61,10 @@ void SalReferOp::process_request_event_cb(void *op_base, const belle_sip_request op->reply(SalReasonUnknown);/*is mapped on bad request*/ return; } - op->root->callbacks.refer_received(op, (SalAddress*)refer_to); + SalAddress *referToAddr = sal_address_new(belle_sip_header_get_unparsed_value(BELLE_SIP_HEADER(refer_to))); + op->root->callbacks.refer_received(op, referToAddr); /*the app is expected to reply in the callback*/ + sal_address_unref(referToAddr); } void SalReferOp::fill_cbs() { @@ -87,6 +89,9 @@ int SalReferOp::send_refer(const SalAddress *refer_to) { belle_sip_request_t* req=build_request("REFER"); if (req == NULL ) return -1; if (get_contact_address()) belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(create_contact())); + belle_sip_header_refer_to_t *refer_to_header = belle_sip_header_refer_to_create(BELLE_SIP_HEADER_ADDRESS(refer_to)); + belle_sip_header_address_set_automatic(BELLE_SIP_HEADER_ADDRESS(refer_to_header), true); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req), BELLE_SIP_HEADER(refer_to_header)); return send_request(req); } From 24e4b233d9ca387eeeb79e49d8e0207826ce95a0 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 9 Oct 2017 12:06:22 +0200 Subject: [PATCH 0354/2215] Handle joining an existing group chat room when receiving a REFER inviting us to join. --- coreapi/callbacks.c | 17 ++++++++++++----- coreapi/chat.c | 12 +++++++++++- coreapi/private.h | 4 +++- src/c-wrapper/api/c-chat-room.cpp | 13 +++++-------- src/chat/basic-chat-room.cpp | 8 +++++++- src/chat/basic-chat-room.h | 1 + src/chat/client-group-chat-room.cpp | 14 ++++++++++++-- src/chat/client-group-chat-room.h | 3 ++- src/chat/real-time-text-chat-room.cpp | 8 +++++++- src/chat/real-time-text-chat-room.h | 1 + src/conference/conference-interface.h | 1 + src/conference/conference.cpp | 11 +++++++++-- src/conference/conference.h | 3 ++- src/conference/local-conference.cpp | 1 - src/conference/session/call-session.h | 1 + 15 files changed, 74 insertions(+), 24 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 3e89c1b60..f2d3aaa71 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -715,11 +715,18 @@ static void on_notify_response(SalOp *op){ } static void refer_received(SalOp *op, const SalAddress *refer_to){ - /*if processing is ok*/ - dynamic_cast(op)->reply(SalReasonNone); - - /*otherwise*/ - //dynamic_cast(op)->reply(SalReasonDeclined); + if (sal_address_has_param(refer_to, "text")) { + LinphonePrivate::Address addr(sal_address_as_string(refer_to)); + if (addr.isValid()) { + LinphoneCore *lc = reinterpret_cast(op->get_sal()->get_user_pointer()); + LinphoneChatRoom *cr = _linphone_core_join_client_group_chat_room(lc, addr); + if (cr) { + static_cast(op)->reply(SalReasonNone); + return; + } + } + } + static_cast(op)->reply(SalReasonDeclined); } Sal::Callbacks linphone_sal_callbacks={ diff --git a/coreapi/chat.c b/coreapi/chat.c index eab5ed37e..daf9b7bb6 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -127,7 +127,17 @@ LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAd } LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, const char *subject) { - LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, subject); + const char *factoryUri = linphone_core_get_conference_factory_uri(lc); + if (!factoryUri) + return nullptr; + LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, factoryUri, subject); + lc->chatrooms = bctbx_list_append(lc->chatrooms, cr); + return cr; +} + +LinphoneChatRoom *_linphone_core_join_client_group_chat_room (LinphoneCore *lc, const LinphonePrivate::Address &addr) { + LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); lc->chatrooms = bctbx_list_append(lc->chatrooms, cr); return cr; } diff --git a/coreapi/private.h b/coreapi/private.h index 325be8645..31bbda276 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -31,6 +31,7 @@ #include "linphone/tunnel.h" #include "linphone/core_utils.h" #include "linphone/conference.h" +#include "address/address.h" #include "c-wrapper/internal/c-sal.h" #include "sal/call-op.h" #include "sal/event-op.h" @@ -462,7 +463,8 @@ void _linphone_proxy_config_release_ops(LinphoneProxyConfig *obj); /*chat*/ LinphoneChatRoom * linphone_chat_room_new(LinphoneCore *core, const LinphoneAddress *addr); -LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, const char *subject); +LinphoneChatRoom *_linphone_core_join_client_group_chat_room (LinphoneCore *core, const LinphonePrivate::Address &addr); +LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, const char *uri, const char *subject); void linphone_chat_room_release(LinphoneChatRoom *cr); void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call); bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr); diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 26eb20ee9..163681be0 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -300,13 +300,10 @@ LinphoneChatRoom *linphone_chat_room_new (LinphoneCore *core, const LinphoneAddr return cr; } -LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, const char *subject) { - const char *factoryUri = linphone_core_get_conference_factory_uri(core); - if (!factoryUri) - return nullptr; - LinphoneAddress *factoryAddr = linphone_address_new(factoryUri); - LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core, factoryAddr); - linphone_address_unref(factoryAddr); +LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, const char *uri, const char *subject) { + LinphoneAddress *addr = linphone_address_new(uri); + LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core, addr); + linphone_address_unref(addr); string from; if (proxy) from = L_GET_CPP_PTR_FROM_C_OBJECT(linphone_proxy_config_get_identity_address(proxy))->asString(); @@ -314,7 +311,7 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, cons from = linphone_core_get_primary_contact(core); LinphonePrivate::Address me(from); LinphoneChatRoom *cr = L_INIT(ChatRoom); - L_SET_CPP_PTR_FROM_C_OBJECT(cr, LinphonePrivate::ObjectFactory::create(core, me, L_C_TO_STRING(subject))); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, LinphonePrivate::ObjectFactory::create(core, me, L_C_TO_STRING(uri), L_C_TO_STRING(subject))); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); return cr; } diff --git a/src/chat/basic-chat-room.cpp b/src/chat/basic-chat-room.cpp index 769abf5d9..f0eaacc66 100644 --- a/src/chat/basic-chat-room.cpp +++ b/src/chat/basic-chat-room.cpp @@ -69,7 +69,13 @@ const string &BasicChatRoom::getSubject () const { return d->subject; } -void BasicChatRoom::leave () {} +void BasicChatRoom::join () { + lError() << "join() is not allowed on a BasicChatRoom"; +} + +void BasicChatRoom::leave () { + lError() << "leave() is not allowed on a BasicChatRoom"; +} void BasicChatRoom::removeParticipant (const shared_ptr &participant) { lError() << "removeParticipant() is not allowed on a BasicChatRoom"; diff --git a/src/chat/basic-chat-room.h b/src/chat/basic-chat-room.h index 62c15c849..bd693e83b 100644 --- a/src/chat/basic-chat-room.h +++ b/src/chat/basic-chat-room.h @@ -41,6 +41,7 @@ public: int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; + void join () override; void leave () override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 4966fcee0..3b98f9448 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -52,9 +52,9 @@ shared_ptr ClientGroupChatRoomPrivate::createSession () { // ============================================================================= -ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, const string &subject) +ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, const string &uri, const string &subject) : ChatRoom(*new ClientGroupChatRoomPrivate(core)), RemoteConference(core, me, nullptr) { - focus = ObjectFactory::create(Address(linphone_core_get_conference_factory_uri(core))); + focus = ObjectFactory::create(Address(uri)); this->subject = subject; } @@ -113,6 +113,16 @@ const string &ClientGroupChatRoom::getSubject () const { return RemoteConference::getSubject(); } +void ClientGroupChatRoom::join () { + L_D(); + shared_ptr session = focus->getPrivate()->getSession(); + if (!session && (d->state == ChatRoom::State::Instantiated)) { + session = d->createSession(); + session->startInvite(nullptr, "", nullptr); + d->setState(ChatRoom::State::CreationPending); + } +} + void ClientGroupChatRoom::leave () { L_D(); eventHandler->unsubscribe(); diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index eaf212f52..1d28aa825 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -37,7 +37,7 @@ class ClientGroupChatRoomPrivate; class LINPHONE_PUBLIC ClientGroupChatRoom : public ChatRoom, public RemoteConference { public: - ClientGroupChatRoom (LinphoneCore *core, const Address &me, const std::string &subject); + ClientGroupChatRoom (LinphoneCore *core, const Address &me, const std::string &uri, const std::string &subject); virtual ~ClientGroupChatRoom () = default; public: @@ -49,6 +49,7 @@ public: int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; + void join () override; void leave () override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index f29a70fea..d89e6befe 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -165,7 +165,13 @@ const string &RealTimeTextChatRoom::getSubject () const { return d->subject; } -void RealTimeTextChatRoom::leave () {} +void RealTimeTextChatRoom::join () { + lError() << "join() is not allowed on a RealTimeTextChatRoom"; +} + +void RealTimeTextChatRoom::leave () { + lError() << "leave() is not allowed on a RealTimeTextChatRoom"; +} void RealTimeTextChatRoom::removeParticipant (const shared_ptr &participant) { lError() << "removeParticipant() is not allowed on a RealTimeTextChatRoom"; diff --git a/src/chat/real-time-text-chat-room.h b/src/chat/real-time-text-chat-room.h index 9eacb9e3d..ec7bdf929 100644 --- a/src/chat/real-time-text-chat-room.h +++ b/src/chat/real-time-text-chat-room.h @@ -51,6 +51,7 @@ public: int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; + void join () override; void leave () override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index 0829df832..a1d187991 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -42,6 +42,7 @@ public: virtual int getNbParticipants () const = 0; virtual std::list> getParticipants () const = 0; virtual const std::string &getSubject () const = 0; + virtual void join () = 0; virtual void leave () = 0; virtual void removeParticipant (const std::shared_ptr &participant) = 0; virtual void removeParticipants (const std::list> &participants) = 0; diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index d6e626088..9794b706c 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -20,6 +20,7 @@ #include "participant-p.h" #include "conference.h" +#include "conference/session/call-session-p.h" #include "logger/logger.h" using namespace std; @@ -76,6 +77,8 @@ const string &Conference::getSubject () const { return subject; } +void Conference::join () {} + void Conference::leave () {} void Conference::removeParticipant (const shared_ptr &participant) { @@ -166,14 +169,18 @@ void Conference::onResetFirstVideoFrameDecoded (const std::shared_ptr Conference::findParticipant (const Address &addr) const { + Address testedAddr = addr; + testedAddr.setPort(0); for (const auto &participant : participants) { - if (addr.equal(participant->getAddress())) + Address participantAddr = participant->getAddress(); + participantAddr.setPort(0); + if (testedAddr.equal(participantAddr)) return participant; } return nullptr; } -shared_ptr Conference::findParticipant (const shared_ptr &session) { +shared_ptr Conference::findParticipant (const shared_ptr &session) const { for (const auto &participant : participants) { if (participant->getPrivate()->getSession() == session) return participant; diff --git a/src/conference/conference.h b/src/conference/conference.h index 2ee2c452d..1d30d0b80 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -55,6 +55,7 @@ public: int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; + void join () override; void leave () override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; @@ -81,7 +82,7 @@ protected: explicit Conference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); std::shared_ptr findParticipant (const Address &addr) const; - std::shared_ptr findParticipant (const std::shared_ptr &session); + std::shared_ptr findParticipant (const std::shared_ptr &session) const; bool isMe (const Address &addr) const ; protected: diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index 07b026aa8..1a1dcc07b 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -44,7 +44,6 @@ void LocalConference::addParticipant (const Address &addr, const CallSessionPara if (participant) return; participant = ObjectFactory::create(addr); - participant->getPrivate()->createSession(*this, params, hasMedia, this); participants.push_back(participant); if (!activeParticipant) activeParticipant = participant; diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index 3f32d5813..c0eaccc8b 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -39,6 +39,7 @@ class LINPHONE_PUBLIC CallSession : public Object { friend class CallPrivate; friend class ClientGroupChatRoom; friend class ClientGroupChatRoomPrivate; + friend class Conference; public: L_OVERRIDE_SHARED_FROM_THIS(CallSession); From 20f2d66c519896dc98be040bd7cb114f2c1cecbf Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 9 Oct 2017 14:12:56 +0200 Subject: [PATCH 0355/2215] feat(Utils): getPtr can deal with references --- include/linphone/utils/utils.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h index 91d36cc53..c2f5d19df 100644 --- a/include/linphone/utils/utils.h +++ b/include/linphone/utils/utils.h @@ -32,6 +32,11 @@ LINPHONE_BEGIN_NAMESPACE namespace Utils { + template + LINPHONE_PUBLIC constexpr T *getPtr (std::shared_ptr &object) { + return object.get(); + } + template LINPHONE_PUBLIC constexpr T *getPtr (const std::shared_ptr &object) { return object.get(); @@ -43,13 +48,8 @@ namespace Utils { } template - LINPHONE_PUBLIC constexpr const T *getPtr (const std::shared_ptr &object) { - return object.get(); - } - - template - LINPHONE_PUBLIC constexpr const T *getPtr (const T *object) { - return object; + LINPHONE_PUBLIC constexpr T *getPtr (T &object) { + return &object; } LINPHONE_PUBLIC bool iequals (const std::string &a, const std::string &b); From c98ce07b4302b7a2b9bce3beda7c3bfa7b34ebd0 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 9 Oct 2017 15:09:15 +0200 Subject: [PATCH 0356/2215] fix(MediaSession): fix build when video mode is disabled --- src/conference/session/media-session.cpp | 31 +++++++++++++++--------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 4850f2ab2..524ecaab1 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -3200,14 +3200,21 @@ void MediaSessionPrivate::updateStreams (SalMediaDescription *newMd, LinphoneCal void MediaSessionPrivate::updateStreamsDestinations (SalMediaDescription *oldMd, SalMediaDescription *newMd) { SalStreamDescription *newAudioDesc = nullptr; - SalStreamDescription *newVideoDesc = nullptr; + + #ifdef VIDEO_ENABLED + SalStreamDescription *newVideoDesc = nullptr; + #endif + for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (!sal_stream_description_active(&newMd->streams[i])) continue; if (newMd->streams[i].type == SalAudio) newAudioDesc = &newMd->streams[i]; - else if (newMd->streams[i].type == SalVideo) - newVideoDesc = &newMd->streams[i]; + + #ifdef VIDEO_ENABLED + else if (newMd->streams[i].type == SalVideo) + newVideoDesc = &newMd->streams[i]; + #endif } if (audioStream && newAudioDesc) { const char *rtpAddr = (newAudioDesc->rtp_addr[0] != '\0') ? newAudioDesc->rtp_addr : newMd->addr; @@ -3277,16 +3284,16 @@ void MediaSessionPrivate::audioStreamAuthTokenReady (const string &authToken, bo } void MediaSessionPrivate::audioStreamEncryptionChanged (bool encrypted) { - L_Q(); propagateEncryptionChanged(); -#ifdef VIDEO_ENABLED - /* Enable video encryption */ - if ((params->getMediaEncryption() == LinphoneMediaEncryptionZRTP) && q->getCurrentParams()->videoEnabled()) { - lInfo() << "Trying to start ZRTP encryption on video stream"; - video_stream_start_zrtp(videoStream); - } -#endif + #ifdef VIDEO_ENABLED + L_Q(); + /* Enable video encryption */ + if ((params->getMediaEncryption() == LinphoneMediaEncryptionZRTP) && q->getCurrentParams()->videoEnabled()) { + lInfo() << "Trying to start ZRTP encryption on video stream"; + video_stream_start_zrtp(videoStream); + } + #endif } uint16_t MediaSessionPrivate::getAvpfRrInterval () const { @@ -4418,8 +4425,8 @@ bool MediaSession::echoLimiterEnabled () const { } void MediaSession::enableCamera (bool value) { - L_D(); #ifdef VIDEO_ENABLED + L_D(); d->cameraEnabled = value; switch (d->state) { case LinphoneCallStreamsRunning: From 69d52b3e7e8e21d921f31cded1ed1577a89c7ead Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 9 Oct 2017 15:10:51 +0200 Subject: [PATCH 0357/2215] fix private attribute access in tester --- tester/CMakeLists.txt | 15 ++++++++++----- tester/tools/private-access.h | 6 ++++-- tester/tools/tester.h | 4 ++-- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index 947fb295d..bb1a7eec7 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -176,7 +176,6 @@ set(SOURCE_FILES_C eventapi_tester.c flexisip_tester.c liblinphone_tester.c - liblinphone_tester.h log_collection_tester.c message_tester.c offeranswer_tester.c @@ -205,6 +204,12 @@ set(SOURCE_FILES_CXX property-container-tester.cpp ) +set(HEADER_FILES + liblinphone_tester.h + tools/private-access.h + tools/tester.h +) + set(SOURCE_FILES_OBJC ) if(APPLE) if (IOS) @@ -241,7 +246,7 @@ endif() # on mobile platforms, we compile the tester as a library so that we can link with it directly from native applications if(ANDROID OR IOS) - add_library(linphonetester SHARED ${SOURCE_FILES_C} ${SOURCE_FILES_CXX}) + add_library(linphonetester SHARED ${HEADER_FILES} ${SOURCE_FILES_C} ${SOURCE_FILES_CXX}) target_include_directories(linphonetester PUBLIC ${BCTOOLBOX_TESTER_INCLUDE_DIRS}) target_link_libraries(linphonetester ${LINPHONE_LIBS_FOR_TOOLS} ${OTHER_LIBS_FOR_TESTER}) if(IOS) @@ -262,7 +267,7 @@ if(ANDROID OR IOS) PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ ) elseif(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") - add_library(linphone_tester_static STATIC ${SOURCE_FILES_C} ${SOURCE_FILES_CXX}) + add_library(linphone_tester_static STATIC ${HEADER_FILES} ${SOURCE_FILES_C} ${SOURCE_FILES_CXX}) target_include_directories(linphone_tester_static PUBLIC ${BCTOOLBOX_TESTER_INCLUDE_DIRS}) target_link_libraries(linphone_tester_static ${LINPHONE_LIBS_FOR_TOOLS} ${OTHER_LIBS_FOR_TESTER}) @@ -296,9 +301,9 @@ endif() if (NOT ANDROID AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") if(IOS) set_source_files_properties(${IOS_RESOURCES_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) - add_executable(liblinphone_tester MACOSX_BUNDLE ${IOS_RESOURCES_FILES} ${SOURCE_FILES_C} ${SOURCE_FILES_CXX} ${SOURCE_FILES_OBJC}) + add_executable(liblinphone_tester MACOSX_BUNDLE ${IOS_RESOURCES_FILES} ${HEADER_FILES} ${SOURCE_FILES_C} ${SOURCE_FILES_CXX} ${SOURCE_FILES_OBJC}) else() - add_executable(liblinphone_tester ${SOURCE_FILES_C} ${SOURCE_FILES_CXX} ${SOURCE_FILES_OBJC}) + add_executable(liblinphone_tester ${HEADER_FILES} ${SOURCE_FILES_C} ${SOURCE_FILES_CXX} ${SOURCE_FILES_OBJC}) endif() set_target_properties(liblinphone_tester PROPERTIES LINK_FLAGS "${LINPHONE_LDFLAGS}") set_target_properties(liblinphone_tester PROPERTIES LINKER_LANGUAGE CXX) diff --git a/tester/tools/private-access.h b/tester/tools/private-access.h index 1dd7dffa6..0f1c20ec5 100644 --- a/tester/tools/private-access.h +++ b/tester/tools/private-access.h @@ -30,6 +30,8 @@ #include +#include "linphone/utils/utils.h" + #define L_INTERNAL_STRUCT_L_ATTR_GET(CLASS, ATTR_NAME) AttrGet ## _ ## CLASS ## _ ## ATTR_NAME #define L_INTERNAL_STRUCT_ATTR_SPY(ATTR_NAME) AttrSpy ## _ ## ATTR_NAME @@ -54,8 +56,8 @@ // Warning: Allow to modify const data. // Returns a ref to `ATTR_NAME`. #define L_ATTR_GET(OBJECT, ATTR_NAME) \ - (const_cast::type &>(OBJECT)).*get( \ - static_cast::type> *>(nullptr) \ + (const_cast::type>::type *>(LinphonePrivate::Utils::getPtr(OBJECT)))->*get( \ + static_cast::type>::type> *>(nullptr) \ ) #endif // ifndef _PRIVATE_ACCESS_H_ diff --git a/tester/tools/tester.h b/tester/tools/tester.h index de2701d50..650fefcd5 100644 --- a/tester/tools/tester.h +++ b/tester/tools/tester.h @@ -22,7 +22,7 @@ #include -#include "utils/utils.h" +#include "linphone/utils/utils.h" // ============================================================================= @@ -35,7 +35,7 @@ LINPHONE_BEGIN_NAMESPACE class Tester { public: Tester () = delete; - + template static constexpr decltype(std::declval().getPrivate()) getPrivate (Object *cppObject) { return cppObject->getPrivate(); From 7fcc7847f01710af7d684a9b91e501d8206aa25e Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 9 Oct 2017 15:17:52 +0200 Subject: [PATCH 0358/2215] fix cast issue --- src/db/events-db.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 405b70552..6618c7a24 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -238,7 +238,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} isNull = false; try { - return message.get(index); + return message.get((size_t)index); } catch (const exception &) { isNull = true; } From 160513f2fcdb474e722771437f31cefed550a946 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 9 Oct 2017 15:25:45 +0200 Subject: [PATCH 0359/2215] feat(EventsDb): add chat_room_participant table --- src/db/events-db.cpp | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 6618c7a24..df0ff6468 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -29,6 +29,7 @@ #include "abstract/abstract-db-p.h" #include "chat/chat-message.h" #include "content/content.h" +#include "conference/participant.h" #include "db/provider/db-session-provider.h" #include "event-log/call-event.h" #include "event-log/chat-message-event.h" @@ -55,10 +56,12 @@ class EventsDbPrivate : public AbstractDbPrivate { #ifdef SOCI_ENABLED public: long insertSipAddress (const string &sipAddress); - void insertContent (const Content &content, long messageEventId); + void insertContent (long messageEventId, const Content &content); long insertContentType (const string &contentType); long insertEvent (EventLog::Type type, const tm &date); long insertChatRoom (long sipAddressId, const tm &date); + void insertChatRoomParticipant (long chatRoomId, const shared_ptr &participant); + long insertMessageEvent ( const MessageEventReferences &references, ChatMessage::State state, @@ -155,7 +158,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return q->getLastInsertId(); } - void EventsDbPrivate::insertContent (const Content &content, long messageEventId) { + void EventsDbPrivate::insertContent (long messageEventId, const Content &content) { soci::session *session = dbSession.getBackendSession(); long contentTypeId = insertContentType(content.getContentType().asString()); @@ -202,6 +205,14 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return sipAddressId; } + void EventsDbPrivate::insertChatRoomParticipant (long chatRoomId, const shared_ptr &participant) { + soci::session *session = dbSession.getBackendSession(); + long participantId = insertSipAddress(participant->getAddress().asStringUriOnly()); + + *session << "UPDATE chat_room_participant SET is_admin = :isAdmin WHERE sip_address_id = sipAddressId", + soci::use(static_cast(participant->isAdmin())), soci::use(participantId); + } + long EventsDbPrivate::insertMessageEvent ( const MessageEventReferences &references, ChatMessage::State state, @@ -226,7 +237,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} long messageEventId = q->getLastInsertId(); for (const auto &content : contents) - insertContent(content, messageEventId); + insertContent(messageEventId, content); return messageEventId; } @@ -358,6 +369,21 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " ON DELETE CASCADE" ")"; + *session << + "CREATE TABLE IF NOT EXISTS chat_room_participant (" + " id" + primaryKeyAutoIncrementStr() + "," + " chat_room_id INT UNSIGNED NOT NULL," + " sip_address_id INT UNSIGNED NOT NULL," + " is_admin BOOLEAN NOT NULL," + + " FOREIGN KEY (chat_room_id)" + " REFERENCES chat_room(peer_sip_address_id)" + " ON DELETE CASCADE," + " FOREIGN KEY (sip_address_id)" + " REFERENCES sip_address(id)" + " ON DELETE CASCADE" + ")"; + *session << "CREATE TABLE IF NOT EXISTS message_event (" " event_id INT UNSIGNED PRIMARY KEY," @@ -398,7 +424,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " ON DELETE CASCADE," " FOREIGN KEY (sip_address_id)" " REFERENCES sip_address(id)" - " ON DELETE CASCADE," + " ON DELETE CASCADE" ")"; *session << From 4ec5f857ed642260fc039d39137dd5273f57184d Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 9 Oct 2017 15:57:15 +0200 Subject: [PATCH 0360/2215] feat(EventsDb): import Participants from legacy messages --- src/db/events-db.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index df0ff6468..32fe2c2db 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -60,7 +60,7 @@ public: long insertContentType (const string &contentType); long insertEvent (EventLog::Type type, const tm &date); long insertChatRoom (long sipAddressId, const tm &date); - void insertChatRoomParticipant (long chatRoomId, const shared_ptr &participant); + void insertChatRoomParticipant (long chatRoomId, long sipAddressId, bool isAdmin); long insertMessageEvent ( const MessageEventReferences &references, @@ -205,12 +205,18 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return sipAddressId; } - void EventsDbPrivate::insertChatRoomParticipant (long chatRoomId, const shared_ptr &participant) { + void EventsDbPrivate::insertChatRoomParticipant (long chatRoomId, long sipAddressId, bool isAdmin) { soci::session *session = dbSession.getBackendSession(); - long participantId = insertSipAddress(participant->getAddress().asStringUriOnly()); - - *session << "UPDATE chat_room_participant SET is_admin = :isAdmin WHERE sip_address_id = sipAddressId", - soci::use(static_cast(participant->isAdmin())), soci::use(participantId); + soci::statement statement = ( + session->prepare << "UPDATE chat_room_participant SET is_admin = :isAdmin" + " WHERE chat_room_id = :chatRoomId AND sip_address_id = :sipAddressId", + soci::use(static_cast(isAdmin)), soci::use(chatRoomId), soci::use(sipAddressId) + ); + statement.execute(true); + if (statement.get_affected_rows() == 0) + *session << "INSERT INTO chat_room_participant (chat_room_id, sip_address_id, is_admin)" + " VALUES (:chatRoomId, :sipAddressId, :isAdmin)", + soci::use(chatRoomId), soci::use(sipAddressId), soci::use(static_cast(isAdmin)); } long EventsDbPrivate::insertMessageEvent ( @@ -307,6 +313,8 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} references.remoteSipAddressId = insertSipAddress(message.get(2)); references.chatRoomId = insertChatRoom(references.remoteSipAddressId, date); + insertChatRoomParticipant(references.chatRoomId, references.remoteSipAddressId, false); + insertMessageEvent ( references, static_cast(state), From 9831f4dcc8d1c85e8c3d7984dc699a04962445f3 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 9 Oct 2017 15:59:50 +0200 Subject: [PATCH 0361/2215] fix(EventsDb): add static_cast instead of c cast --- src/db/events-db.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 32fe2c2db..0cc4e0062 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -255,7 +255,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} isNull = false; try { - return message.get((size_t)index); + return message.get(static_cast(index)); } catch (const exception &) { isNull = true; } From 47da8088e321c938a23f5f4bcfe4d4528a4b2c7a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 9 Oct 2017 16:40:17 +0200 Subject: [PATCH 0362/2215] Improve handling of conference event package subscription/notification. --- coreapi/chat.c | 1 + coreapi/linphonecore.c | 42 ++++++++++++++++--- coreapi/private.h | 3 ++ coreapi/tester_utils.h | 1 + src/chat/client-group-chat-room-p.h | 1 + src/chat/client-group-chat-room.cpp | 6 +++ src/conference/conference.cpp | 8 ++-- src/conference/conference.h | 5 ++- .../local-conference-event-handler.cpp | 22 +++++++--- src/conference/participant-p.h | 3 ++ src/conference/participant.h | 2 + 11 files changed, 78 insertions(+), 16 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index daf9b7bb6..b453892eb 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -138,6 +138,7 @@ LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, LinphoneChatRoom *_linphone_core_join_client_group_chat_room (LinphoneCore *lc, const LinphonePrivate::Address &addr) { LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); + _linphone_core_add_group_chat_room(lc, L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getConferenceAddress()->asStringUriOnly().c_str(), linphone_chat_room_ref(cr)); lc->chatrooms = bctbx_list_append(lc->chatrooms, cr); return cr; } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 4948d1d5f..7dedc0672 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -45,6 +45,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mediastreamer2/msjpegwriter.h" #include "mediastreamer2/msogl.h" #include "mediastreamer2/msvolume.h" +#include "chat/client-group-chat-room-p.h" #include "conference/remote-conference-event-handler.h" // For migration purpose. @@ -2115,11 +2116,13 @@ static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEve ms_message("Notify presence for list %p", list); linphone_friend_list_notify_presence_received(list, lev, body); } - } else if (strcmp(notified_event, "Conference") == 0) { - LinphonePrivate::RemoteConferenceEventHandler *handler = - reinterpret_cast(linphone_event_get_user_data(lev)); - if (handler) - handler->notifyReceived(reinterpret_cast(linphone_content_get_buffer(body))); + } else if (strcmp(notified_event, "conference") == 0) { + const LinphoneAddress *resource = linphone_event_get_resource(lev); + char *resourceUri = linphone_address_as_string_uri_only(resource); + LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, resourceUri); + bctbx_free(resourceUri); + if (cr) + L_GET_PRIVATE_FROM_C_OBJECT(cr, ClientGroupChatRoom)->notifyReceived(linphone_content_get_string_buffer(body)); } } @@ -2251,6 +2254,7 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig linphone_configuring_terminated(lc, LinphoneConfiguringSkipped, NULL); } // else linphone_core_start will be called after the remote provisioning (see linphone_core_iterate) lc->bw_controller = ms_bandwidth_controller_new(); + lc->group_chat_rooms = bctbx_mmap_cchar_new(); } LinphoneCore *_linphone_core_new_with_config(LinphoneCoreCbs *cbs, struct _LpConfig *config, void *userdata) { @@ -5946,6 +5950,8 @@ static void linphone_core_uninit(LinphoneCore *lc) } lc->chatrooms = bctbx_list_free_with_data(lc->chatrooms, (MSIterateFunc)linphone_chat_room_release); + if (lc->group_chat_rooms) + bctbx_mmap_cchar_delete_with_data(lc->group_chat_rooms, (void (*)(void *))linphone_chat_room_unref); linphone_core_set_state(lc,LinphoneGlobalShutdown,"Shutting down"); #ifdef VIDEO_ENABLED @@ -7077,6 +7083,32 @@ const char * linphone_core_get_conference_factory_uri(const LinphoneCore *lc) { return lp_config_get_string(linphone_core_get_config(lc), "misc", "conference_factory_uri", nullptr); } +bool_t _linphone_core_has_group_chat_room(const LinphoneCore *lc, const char *id) { + bool_t result; + bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, id); + bctbx_iterator_t *endit = bctbx_map_cchar_end(lc->group_chat_rooms); + result = !bctbx_iterator_cchar_equals(it, endit); + bctbx_iterator_cchar_delete(endit); + bctbx_iterator_cchar_delete(it); + return result; +} + +void _linphone_core_add_group_chat_room(LinphoneCore *lc, const char *id, LinphoneChatRoom *cr) { + bctbx_pair_t *pair = reinterpret_cast(bctbx_pair_cchar_new(id, linphone_chat_room_ref(cr))); + bctbx_map_cchar_insert_and_delete(lc->group_chat_rooms, pair); +} + +LinphoneChatRoom *_linphone_core_find_group_chat_room(const LinphoneCore *lc, const char *id) { + LinphoneChatRoom *result = nullptr; + bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, id); + bctbx_iterator_t *endit = bctbx_map_cchar_end(lc->group_chat_rooms); + if (!bctbx_iterator_cchar_equals(it, endit)) + result = reinterpret_cast(bctbx_pair_cchar_get_second(bctbx_iterator_cchar_get_pair(it))); + bctbx_iterator_cchar_delete(endit); + bctbx_iterator_cchar_delete(it); + return result; +} + void linphone_core_set_tls_cert(LinphoneCore *lc, const char *tls_cert) { if (lc->tls_cert) { ms_free(lc->tls_cert); diff --git a/coreapi/private.h b/coreapi/private.h index 31bbda276..74a551576 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -449,6 +449,8 @@ bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription extern LinphonePrivate::Sal::Callbacks linphone_sal_callbacks; LINPHONE_PUBLIC bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); LINPHONE_PUBLIC bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc); +bool_t _linphone_core_has_group_chat_room(const LinphoneCore *lc, const char *id); +void _linphone_core_add_group_chat_room(LinphoneCore *lc, const char *id, LinphoneChatRoom *cr); void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description); @@ -832,6 +834,7 @@ struct _LinphoneCore MSList *queued_calls; /* used by the autoreplier */ MSList *call_logs; MSList *chatrooms; + bctbx_map_t *group_chat_rooms; int max_call_logs; int missed_calls; VideoPreview *previewstream; diff --git a/coreapi/tester_utils.h b/coreapi/tester_utils.h index ccb993246..0431d80de 100644 --- a/coreapi/tester_utils.h +++ b/coreapi/tester_utils.h @@ -94,6 +94,7 @@ LINPHONE_PUBLIC mblk_t *_linphone_call_stats_get_received_rtcp (const LinphoneCa LINPHONE_PUBLIC LinphoneQualityReporting *linphone_call_log_get_quality_reporting(LinphoneCallLog *call_log); LINPHONE_PUBLIC reporting_session_report_t **linphone_quality_reporting_get_reports(LinphoneQualityReporting *qreporting); +LINPHONE_PUBLIC LinphoneChatRoom *_linphone_core_find_group_chat_room(const LinphoneCore *lc, const char *id); LINPHONE_PUBLIC bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr); LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_from_db(LinphoneCore *lc, LinphoneFriendList *list); diff --git a/src/chat/client-group-chat-room-p.h b/src/chat/client-group-chat-room-p.h index 7bc90bac5..54e8f9b60 100644 --- a/src/chat/client-group-chat-room-p.h +++ b/src/chat/client-group-chat-room-p.h @@ -38,6 +38,7 @@ public: virtual ~ClientGroupChatRoomPrivate () = default; std::shared_ptr createSession (); + void notifyReceived (std::string body); private: L_DECLARE_PUBLIC(ClientGroupChatRoom); diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 3b98f9448..b5637602b 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -50,6 +50,11 @@ shared_ptr ClientGroupChatRoomPrivate::createSession () { return session; } +void ClientGroupChatRoomPrivate::notifyReceived (string body) { + L_Q(); + q->eventHandler->notifyReceived(body); +} + // ============================================================================= ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, const string &uri, const string &subject) @@ -169,6 +174,7 @@ void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { L_D(); conferenceAddress = addr; d->setState(ChatRoom::State::Created); + _linphone_core_add_group_chat_room(d->core, addr.asStringUriOnly().c_str(), L_GET_C_BACK_PTR(this)); } void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 9794b706c..2b271e2d1 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -189,9 +189,11 @@ shared_ptr Conference::findParticipant (const shared_ptrgetAddress(); - cleanedAddress.setPort(0); - return addr.equal(cleanedAddress); + Address cleanedMe = me->getAddress(); + cleanedMe.setPort(0); + Address cleanedAddr = addr; + cleanedAddr.setPort(0); + return cleanedAddr.equal(cleanedMe); } LINPHONE_END_NAMESPACE diff --git a/src/conference/conference.h b/src/conference/conference.h index 1d30d0b80..57a4cdb44 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -46,6 +46,9 @@ public: LinphoneCore * getCore () const { return core; } + std::shared_ptr findParticipant (const Address &addr) const; + std::shared_ptr findParticipant (const std::shared_ptr &session) const; + public: /* ConferenceInterface */ void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; @@ -81,8 +84,6 @@ private: protected: explicit Conference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); - std::shared_ptr findParticipant (const Address &addr) const; - std::shared_ptr findParticipant (const std::shared_ptr &session) const; bool isMe (const Address &addr) const ; protected: diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 8d5896229..2e216e5c2 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -18,7 +18,7 @@ */ #include "conference/local-conference.h" -#include "conference/participant.h" +#include "conference/participant-p.h" #include "local-conference-event-handler.h" #include "object/object-p.h" @@ -78,15 +78,15 @@ void LocalConferenceEventHandlerPrivate::notifyFullState (string notify, Linphon void LocalConferenceEventHandlerPrivate::notifyAllExcept (string notify, const Address &addr) { for (const auto &participant : conf->getParticipants()) { - if (addr != participant->getAddress()) { - this->sendNotify(notify, addr); - } + if (participant->getPrivate()->isSubscribedToConferenceEventPackage() && (addr != participant->getAddress())) + sendNotify(notify, addr); } } void LocalConferenceEventHandlerPrivate::notifyAll (string notify) { for (const auto &participant : conf->getParticipants()) { - this->sendNotify(notify, participant->getAddress()); + if (participant->getPrivate()->isSubscribedToConferenceEventPackage()) + sendNotify(notify, participant->getAddress()); } } @@ -199,7 +199,17 @@ LocalConferenceEventHandler::~LocalConferenceEventHandler () { void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) { L_D(); - d->notifyFullState(d->createNotifyFullState(), lev); + const LinphoneAddress *lAddr = linphone_event_get_from(lev); + char *addrStr = linphone_address_as_string(lAddr); + shared_ptr participant = d->conf->findParticipant(Address(addrStr)); + bctbx_free(addrStr); + if (participant) { + if (linphone_event_get_subscription_state(lev) == LinphoneSubscriptionActive) { + participant->getPrivate()->subscribeToConferenceEventPackage(true); + d->notifyFullState(d->createNotifyFullState(), lev); + } else if (linphone_event_get_subscription_state(lev) == LinphoneSubscriptionTerminated) + participant->getPrivate()->subscribeToConferenceEventPackage(false); + } } void LocalConferenceEventHandler::notifyParticipantAdded (const Address &addr) { diff --git a/src/conference/participant-p.h b/src/conference/participant-p.h index 363820f9b..f862c54a4 100644 --- a/src/conference/participant-p.h +++ b/src/conference/participant-p.h @@ -41,12 +41,15 @@ public: std::shared_ptr createSession (const Conference &conference, const CallSessionParams *params, bool hasMedia, CallSessionListener *listener); std::shared_ptr getSession () const { return session; } + bool isSubscribedToConferenceEventPackage () const { return _isSubscribedToConferenceEventPackage; } + void subscribeToConferenceEventPackage (bool value) { _isSubscribedToConferenceEventPackage = value; } void removeSession () { session = nullptr; } void setAddress (const Address &newAddr) { addr = newAddr; } private: Address addr; bool isAdmin = false; + bool _isSubscribedToConferenceEventPackage = false; std::shared_ptr session; L_DECLARE_PUBLIC(Participant); diff --git a/src/conference/participant.h b/src/conference/participant.h index dd5de40ad..7b092bb7f 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -39,6 +39,8 @@ class Participant : public Object { friend class ClientGroupChatRoomPrivate; friend class Conference; friend class LocalConference; + friend class LocalConferenceEventHandler; + friend class LocalConferenceEventHandlerPrivate; friend class MediaSessionPrivate; friend class RemoteConference; From fe37c2892be1224eaffe68f1c095e59bb2946bc2 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 9 Oct 2017 16:49:38 +0200 Subject: [PATCH 0363/2215] Fix 'Conference event' tester --- src/CMakeLists.txt | 2 + .../local-conference-event-handler-p.h | 51 +++++++ .../local-conference-event-handler.cpp | 30 +--- .../local-conference-event-handler.h | 5 +- .../remote-conference-event-handler-p.h | 40 ++++++ .../remote-conference-event-handler.cpp | 15 +- tester/CMakeLists.txt | 2 +- tester/conference-event-tester.cpp | 133 +++++++++--------- tester/tester.c | 2 +- 9 files changed, 173 insertions(+), 107 deletions(-) create mode 100644 src/conference/local-conference-event-handler-p.h create mode 100644 src/conference/remote-conference-event-handler-p.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8928cc208..080df4c96 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -56,6 +56,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES conference/conference-listener.h conference/conference.h conference/local-conference.h + conference/local-conference-event-handler-p.h conference/local-conference-event-handler.h conference/params/call-session-params-p.h conference/params/call-session-params.h @@ -64,6 +65,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES conference/participant-p.h conference/participant.h conference/remote-conference.h + conference/remote-conference-event-handler-p.h conference/remote-conference-event-handler.h conference/session/call-session-listener.h conference/session/call-session-p.h diff --git a/src/conference/local-conference-event-handler-p.h b/src/conference/local-conference-event-handler-p.h new file mode 100644 index 000000000..264175c70 --- /dev/null +++ b/src/conference/local-conference-event-handler-p.h @@ -0,0 +1,51 @@ +/* + * local-conference-event-handler-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _LOCAL_CONFERENCE_EVENT_HANDLER_P_H_ +#define _LOCAL_CONFERENCE_EVENT_HANDLER_P_H_ + +#include + +#include "local-conference-event-handler.h" +#include "object/object-p.h" + +LINPHONE_BEGIN_NAMESPACE + +class LocalConferenceEventHandlerPrivate : public ObjectPrivate { +public: + void notifyFullState (const std::string ¬ify, LinphoneEvent *lev); + void notifyAllExcept (const std::string ¬ify, const Address &addr); + void notifyAll (const std::string ¬ify); + std::string createNotifyFullState (); + std::string createNotifyParticipantAdded (const Address &addr); + std::string createNotifyParticipantRemoved (const Address &addr); + std::string createNotifyParticipantAdmined (const Address &addr, bool isAdmin); + std::string createNotifySubjectChanged (); + +private: + LinphoneCore *core = nullptr; + LocalConference *conf = nullptr; + + void sendNotify (const std::string ¬ify, const Address &addr); + L_DECLARE_PUBLIC(LocalConferenceEventHandler); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _LOCAL_CONFERENCE_EVENT_HANDLER_P_H_ diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 2e216e5c2..8f46293ce 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -19,7 +19,7 @@ #include "conference/local-conference.h" #include "conference/participant-p.h" -#include "local-conference-event-handler.h" +#include "local-conference-event-handler-p.h" #include "object/object-p.h" #include "private.h" @@ -34,27 +34,9 @@ LINPHONE_BEGIN_NAMESPACE using namespace Xsd::ConferenceInfo; -class LocalConferenceEventHandlerPrivate : public ObjectPrivate { -public: - void notifyFullState (string notify, LinphoneEvent *lev); - void notifyAllExcept (string notify, const Address &addr); - void notifyAll (string notify); - string createNotifyFullState (); - string createNotifyParticipantAdded (const Address &addr); - string createNotifyParticipantRemoved (const Address &addr); - string createNotifyParticipantAdmined (const Address &addr, bool isAdmin); - string createNotifySubjectChanged (); - - LinphoneCore *core = nullptr; - LocalConference *conf = nullptr; - -private: - void sendNotify (string notify, const Address &addr); -}; - // ----------------------------------------------------------------------------- -static void doNotify (string notify, LinphoneEvent *lev) { +static void doNotify (const string ¬ify, LinphoneEvent *lev) { LinphoneContent *content = linphone_core_create_content(lev->lc); linphone_content_set_buffer(content, notify.c_str(), strlen(notify.c_str())); linphone_event_notify(lev, content); @@ -72,18 +54,18 @@ static string createNotify (ConferenceType confInfo) { // ----------------------------------------------------------------------------- -void LocalConferenceEventHandlerPrivate::notifyFullState (string notify, LinphoneEvent *lev) { +void LocalConferenceEventHandlerPrivate::notifyFullState (const string ¬ify, LinphoneEvent *lev) { doNotify(notify, lev); } -void LocalConferenceEventHandlerPrivate::notifyAllExcept (string notify, const Address &addr) { +void LocalConferenceEventHandlerPrivate::notifyAllExcept (const string ¬ify, const Address &addr) { for (const auto &participant : conf->getParticipants()) { if (participant->getPrivate()->isSubscribedToConferenceEventPackage() && (addr != participant->getAddress())) sendNotify(notify, addr); } } -void LocalConferenceEventHandlerPrivate::notifyAll (string notify) { +void LocalConferenceEventHandlerPrivate::notifyAll (const string ¬ify) { for (const auto &participant : conf->getParticipants()) { if (participant->getPrivate()->isSubscribedToConferenceEventPackage()) sendNotify(notify, participant->getAddress()); @@ -175,7 +157,7 @@ string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged () { return(createNotify(confInfo)); } -void LocalConferenceEventHandlerPrivate::sendNotify (string notify, const Address &addr) { +void LocalConferenceEventHandlerPrivate::sendNotify (const string ¬ify, const Address &addr) { LinphoneAddress *cAddr = linphone_address_new(addr.asString().c_str()); LinphoneEvent *lev = linphone_core_create_notify(core, cAddr, "conference"); linphone_address_unref(cAddr); diff --git a/src/conference/local-conference-event-handler.h b/src/conference/local-conference-event-handler.h index 5d5b6dcfe..5568ed171 100644 --- a/src/conference/local-conference-event-handler.h +++ b/src/conference/local-conference-event-handler.h @@ -20,11 +20,8 @@ #ifndef _LOCAL_CONFERENCE_EVENT_HANDLER_H_ #define _LOCAL_CONFERENCE_EVENT_HANDLER_H_ -#include - -#include "linphone/types.h" - #include "address/address.h" +#include "linphone/types.h" #include "object/object.h" LINPHONE_BEGIN_NAMESPACE diff --git a/src/conference/remote-conference-event-handler-p.h b/src/conference/remote-conference-event-handler-p.h new file mode 100644 index 000000000..71c342c42 --- /dev/null +++ b/src/conference/remote-conference-event-handler-p.h @@ -0,0 +1,40 @@ +/* + * remote-conference-event-handler-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _REMOTE_CONFERENCE_EVENT_HANDLER_P_H_ +#define _REMOTE_CONFERENCE_EVENT_HANDLER_P_H_ + +#include "object/object-p.h" +#include "remote-conference-event-handler.h" + +LINPHONE_BEGIN_NAMESPACE + +class RemoteConferenceEventHandlerPrivate : public ObjectPrivate { +private: + LinphoneCore *core = nullptr; + ConferenceListener *listener = nullptr; + Address confAddress; + LinphoneEvent *lev = nullptr; + + L_DECLARE_PUBLIC(RemoteConferenceEventHandler); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _REMOTE_CONFERENCE_EVENT_HANDLER_P_H_ \ No newline at end of file diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 5536bce0e..a409fe1d5 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -17,12 +17,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "remote-conference-event-handler.h" -#include "logger/logger.h" -#include "object/object-p.h" - #include "private.h" - +#include "logger/logger.h" +#include "remote-conference-event-handler-p.h" #include "xml/conference-info.h" // ============================================================================= @@ -33,14 +30,6 @@ LINPHONE_BEGIN_NAMESPACE using namespace Xsd::ConferenceInfo; -class RemoteConferenceEventHandlerPrivate : public ObjectPrivate { -public: - LinphoneCore *core = nullptr; - ConferenceListener *listener = nullptr; - Address confAddress; - LinphoneEvent *lev = nullptr; -}; - // ----------------------------------------------------------------------------- RemoteConferenceEventHandler::RemoteConferenceEventHandler(LinphoneCore *core, ConferenceListener *listener) diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index bb1a7eec7..e9263093e 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -196,7 +196,7 @@ set(SOURCE_FILES_C set(SOURCE_FILES_CXX clonable-object-tester.cpp -# conference-event-tester.cpp + conference-event-tester.cpp conference-tester.cpp cpim-tester.cpp multipart-tester.cpp diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index b88c7cb03..9cd2f8e09 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -24,9 +24,11 @@ #include "liblinphone_tester.h" #include "conference/conference-listener.h" #include "conference/local-conference.h" -#include "conference/local-conference-event-handler.h" +#include "conference/local-conference-event-handler-p.h" #include "conference/participant.h" -#include "conference/remote-conference-event-handler.h" +#include "conference/remote-conference-event-handler-p.h" +#include "tools/private-access.h" +#include "tools/tester.h" using namespace LinphonePrivate; using namespace std; @@ -417,7 +419,8 @@ static const char *aliceUri = "sip:alice@example.com"; static const char *frankUri = "sip:frank@example.com"; static const char *confUri = "sips:conf233@example.com"; - +L_ENABLE_ATTR_ACCESS(RemoteConferenceEventHandlerPrivate, Address, confAddress); +L_ENABLE_ATTR_ACCESS(Conference, Address, conferenceAddress); class ConferenceEventTester : public ConferenceListener { public: @@ -430,10 +433,11 @@ private: void onParticipantAdded (const Address &addr) override; void onParticipantRemoved (const Address &addr) override; void onParticipantSetAdmin (const Address &addr, bool isAdmin) override; - void onSubjectChanged(const std::string &subject) override; + void onSubjectChanged(const string &subject) override; public: RemoteConferenceEventHandler *handler; map participants; + string confSubject; }; ConferenceEventTester::ConferenceEventTester (LinphoneCore *core, const Address &confAddr) { @@ -461,6 +465,10 @@ void ConferenceEventTester::onParticipantSetAdmin (const Address &addr, bool isA it->second = isAdmin; } +void ConferenceEventTester::onSubjectChanged(const string &subject) { + confSubject = subject; +} + void first_notify_parsing() { LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri); @@ -474,6 +482,8 @@ void first_notify_parsing() { size_t size = strlen(first_notify) + strlen(confUri); char *notify = new char[size]; + RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); + L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -503,6 +513,8 @@ void first_notify_parsing_wrong_conf() { size_t size = strlen(first_notify) + strlen(confUri); char *notify = new char[size]; + RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); + L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -533,6 +545,8 @@ void participant_added_parsing() { size_t size2 = strlen(participant_added_notify) + strlen(confUri); char *notify_added = new char[size2]; + RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); + L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -575,6 +589,8 @@ void participant_not_added_parsing() { size_t size2 = strlen(participant_not_added_notify) + strlen(confUri); char *notify_not_added = new char[size2]; + RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); + L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -615,6 +631,8 @@ void participant_deleted_parsing() { size_t size2 = strlen(participant_deleted_notify) + strlen(confUri); char *notify_deleted = new char[size2]; + RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); + L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -654,6 +672,8 @@ void participant_admined_parsing() { size_t size2 = strlen(participant_admined_notify) + strlen(confUri); char *notify_admined = new char[size2]; + RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); + L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -694,6 +714,8 @@ void participant_unadmined_parsing() { size_t size2 = strlen(participant_unadmined_notify) + strlen(confUri); char *notify_unadmined = new char[size2]; + RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); + L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -740,12 +762,16 @@ void send_first_notify() { CallSessionParams params; localConf.addParticipant(bobAddr, ¶ms, false); - shared_ptr alice = localConf.addParticipant(aliceAddr, ¶ms, false); + localConf.addParticipant(aliceAddr, ¶ms, false); + shared_ptr alice = localConf.findParticipant(aliceAddr); alice->setAdmin(true); - LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "conference"); - string notify = localConf.getEventHandler()->subscribeReceived(lev); + LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); + L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; + string notify = localHandlerPrivate->createNotifyFullState(); + + RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); + L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; tester.handler->notifyReceived(notify); - linphone_event_unref(lev); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(bobAddr.asString()) != tester.participants.end()); @@ -780,15 +806,19 @@ void send_added_notify() { Address frankAddr(frankAddrStr); bctbx_free(frankAddrStr); linphone_address_unref(cFrankAddr); - LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "conference"); CallSessionParams params; localConf.addParticipant(bobAddr, ¶ms, false); - shared_ptr alice = localConf.addParticipant(aliceAddr, ¶ms, false); + localConf.addParticipant(aliceAddr, ¶ms, false); + shared_ptr alice = localConf.findParticipant(aliceAddr); alice->setAdmin(true); - string notify = localConf.getEventHandler()->subscribeReceived(lev); + LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); + L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; + string notify = localHandlerPrivate->createNotifyFullState(); + + RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); + L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; tester.handler->notifyReceived(notify); - linphone_event_unref(lev); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(bobAddr.asString()) != tester.participants.end()); @@ -796,7 +826,7 @@ void send_added_notify() { BC_ASSERT_TRUE(!tester.participants.find(bobAddr.asString())->second); BC_ASSERT_TRUE(tester.participants.find(aliceAddr.asString())->second); - notify = localConf.getEventHandler()->notifyParticipantAdded(frankAddr); + notify = localHandlerPrivate->createNotifyParticipantAdded(frankAddr); tester.handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester.participants.size(), 3, int, "%d"); @@ -832,12 +862,16 @@ void send_removed_notify() { CallSessionParams params; localConf.addParticipant(bobAddr, ¶ms, false); - shared_ptr alice = localConf.addParticipant(aliceAddr, ¶ms, false); + localConf.addParticipant(aliceAddr, ¶ms, false); + shared_ptr alice = localConf.findParticipant(aliceAddr); alice->setAdmin(true); - LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "conference"); - string notify = localConf.getEventHandler()->subscribeReceived(lev); + LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); + L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; + string notify = localHandlerPrivate->createNotifyFullState(); + + RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); + L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; tester.handler->notifyReceived(notify); - linphone_event_unref(lev); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(bobAddr.asString()) != tester.participants.end()); @@ -845,7 +879,7 @@ void send_removed_notify() { BC_ASSERT_TRUE(!tester.participants.find(bobAddr.asString())->second); BC_ASSERT_TRUE(tester.participants.find(aliceAddr.asString())->second); - notify = localConf.getEventHandler()->notifyParticipantRemoved(bobAddr); + notify = localHandlerPrivate->createNotifyParticipantRemoved(bobAddr); tester.handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester.participants.size(), 1, int, "%d"); @@ -878,12 +912,15 @@ void send_admined_notify() { CallSessionParams params; localConf.addParticipant(bobAddr, ¶ms, false); - shared_ptr alice = localConf.addParticipant(aliceAddr, ¶ms, false); + localConf.addParticipant(aliceAddr, ¶ms, false); + shared_ptr alice = localConf.findParticipant(aliceAddr); alice->setAdmin(true); - LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "conference"); - string notify = localConf.getEventHandler()->subscribeReceived(lev); + LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); + L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; + string notify = localHandlerPrivate->createNotifyFullState(); + RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); + L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; tester.handler->notifyReceived(notify); - linphone_event_unref(lev); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(bobAddr.asString()) != tester.participants.end()); @@ -891,7 +928,7 @@ void send_admined_notify() { BC_ASSERT_TRUE(!tester.participants.find(bobAddr.asString())->second); BC_ASSERT_TRUE(tester.participants.find(aliceAddr.asString())->second); - notify = localConf.getEventHandler()->notifyParticipantSetAdmin(bobAddr, true); + notify = localHandlerPrivate->createNotifyParticipantAdmined(bobAddr, true); tester.handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); @@ -925,12 +962,16 @@ void send_unadmined_notify() { CallSessionParams params; localConf.addParticipant(bobAddr, ¶ms, false); - shared_ptr alice = localConf.addParticipant(aliceAddr, ¶ms, false); + localConf.addParticipant(aliceAddr, ¶ms, false); + shared_ptr alice = localConf.findParticipant(aliceAddr); alice->setAdmin(true); - LinphoneEvent *lev = linphone_core_create_notify(pauline->lc, marie->identity, "conference"); - string notify = localConf.getEventHandler()->subscribeReceived(lev); + LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); + L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; + string notify = localHandlerPrivate->createNotifyFullState(); + RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); + L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; tester.handler->notifyReceived(notify); - linphone_event_unref(lev); + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(bobAddr.asString()) != tester.participants.end()); @@ -938,7 +979,7 @@ void send_unadmined_notify() { BC_ASSERT_TRUE(!tester.participants.find(bobAddr.asString())->second); BC_ASSERT_TRUE(tester.participants.find(aliceAddr.asString())->second); - notify = localConf.getEventHandler()->notifyParticipantSetAdmin(aliceAddr, false); + notify = localHandlerPrivate->createNotifyParticipantAdmined(aliceAddr, false); tester.handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); @@ -951,41 +992,6 @@ void send_unadmined_notify() { linphone_core_manager_destroy(pauline); } -#if 0 -void send_subscribe_receive_first_notify() { - LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); - LinphoneCoreManager *pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); - ConferenceEventTester tester(marie->lc, pauline->identity); - LinphoneAddress *bobAddr = linphone_core_interpret_url(marie->lc, bobUri); - LinphoneAddress *aliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); - string confId("conf233"); - - BC_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneRegistrationOk, 1, 1000)); - BC_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneRegistrationOk, 1, 1000)); - - tester.handler->subscribe(confId); - - BC_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneSubscriptionIncomingReceived, 1, 1000)); - BC_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneSubscriptionActive, 1, 3000)); - wait_for_until(marie->lc, pauline->lc, &marie->stat.number_of_NotifyReceived, 1, 3000); - - BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); - BC_ASSERT_TRUE(!tester.participants.find(linphone_address_as_string(bobAddr))->second); - BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second); - - tester.handler->unsubscribe(); - - BC_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneSubscriptionTerminated, 1, 1000)); - - linphone_address_unref(bobAddr); - linphone_address_unref(aliceAddr); - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); -} -#endif - test_t conference_event_tests[] = { TEST_NO_TAG("First notify parsing", first_notify_parsing), TEST_NO_TAG("First notify parsing wrong conf", first_notify_parsing_wrong_conf), @@ -999,7 +1005,6 @@ test_t conference_event_tests[] = { TEST_NO_TAG("Send participant removed notify", send_removed_notify), TEST_NO_TAG("Send participant admined notify", send_admined_notify), TEST_NO_TAG("Send participant unadmined notify", send_unadmined_notify) - //TEST_NO_TAG("Send subscribe receive first notify", send_subscribe_receive_first_notify) }; test_suite_t conference_event_test_suite = { diff --git a/tester/tester.c b/tester/tester.c index 50be44792..64e5551c7 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -563,7 +563,7 @@ void liblinphone_tester_add_suites() { bc_tester_add_suite(&account_creator_test_suite); bc_tester_add_suite(&stun_test_suite); bc_tester_add_suite(&event_test_suite); - //bc_tester_add_suite(&conference_event_test_suite); + bc_tester_add_suite(&conference_event_test_suite); bc_tester_add_suite(&conference_test_suite); bc_tester_add_suite(&flexisip_test_suite); bc_tester_add_suite(&remote_provisioning_test_suite); From 814d279f56586e911cda88e127a1e32a68b445f0 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 9 Oct 2017 16:50:25 +0200 Subject: [PATCH 0364/2215] fix(EventsDb): repare getMessagesCount --- src/db/events-db.cpp | 40 +++++++++++++++++++++------------------- src/db/events-db.h | 10 +++++----- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 0cc4e0062..fa2c2db65 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -529,34 +529,36 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return count; } - int EventsDb::getMessagesCount (const string &remoteAddress) const { + int EventsDb::getMessagesCount (const string &peerAddress) const { L_D(); if (!isConnected()) { lWarning() << "Unable to get messages count. Not connected."; return 0; } - - string query = "SELECT COUNT(*) FROM message_event"; - if (!remoteAddress.empty()) - query += " WHERE chat_room_id = (" - " SELECT id FROM dialog WHERE remote_sip_address_id =(" - " SELECT id FROM sip_address WHERE value = :remote_address" - " )" - " )"; int count = 0; L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); - *session << query, soci::use(remoteAddress), soci::into(count); + + string query = "SELECT COUNT(*) FROM message_event"; + if (peerAddress.empty()) + *session << query, soci::into(count); + else { + query += " WHERE chat_room_id = (" + " SELECT id FROM sip_address WHERE value = :peerSipAddress" + ")"; + + *session << query, soci::use(peerAddress), soci::into(count); + } L_END_LOG_EXCEPTION return count; } - int EventsDb::getUnreadMessagesCount (const string &remoteAddress) const { + int EventsDb::getUnreadMessagesCount (const string &peerAddress) const { L_D(); if (!isConnected()) { @@ -565,7 +567,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} } string query = "SELECT COUNT(*) FROM message_event"; - if (!remoteAddress.empty()) + if (!peerAddress.empty()) query += " WHERE chat_room_id = (" " SELECT id FROM dialog WHERE remote_sip_address_id = (" " SELECT id FROM sip_address WHERE value = :remote_address" @@ -578,28 +580,28 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); - *session << query, soci::use(remoteAddress), soci::into(count); + *session << query, soci::use(peerAddress), soci::into(count); L_END_LOG_EXCEPTION return count; } - list> EventsDb::getHistory (const string &remoteAddress, int nLast, FilterMask mask) const { + list> EventsDb::getHistory (const string &peerAddress, int nLast, FilterMask mask) const { if (!isConnected()) { lWarning() << "Unable to get history. Not connected."; return list>(); } // TODO. - (void)remoteAddress; + (void)peerAddress; (void)nLast; (void)mask; return list>(); } list> EventsDb::getHistory ( - const string &remoteAddress, + const string &peerAddress, int begin, int end, FilterMask mask @@ -610,21 +612,21 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} } // TODO. - (void)remoteAddress; + (void)peerAddress; (void)begin; (void)end; (void)mask; return list>(); } - void EventsDb::cleanHistory (const string &remoteAddress) { + void EventsDb::cleanHistory (const string &peerAddress) { if (!isConnected()) { lWarning() << "Unable to clean history. Not connected."; return; } // TODO. - (void)remoteAddress; + (void)peerAddress; } // ----------------------------------------------------------------------------- diff --git a/src/db/events-db.h b/src/db/events-db.h index 6e997ff0a..030ff7eeb 100644 --- a/src/db/events-db.h +++ b/src/db/events-db.h @@ -51,20 +51,20 @@ public: int getEventsCount (FilterMask mask = NoFilter) const; // Messages, calls and conferences. - int getMessagesCount (const std::string &remoteAddress = "") const; - int getUnreadMessagesCount (const std::string &remoteAddress = "") const; + int getMessagesCount (const std::string &peerAddress = "") const; + int getUnreadMessagesCount (const std::string &peerAddress = "") const; std::list> getHistory ( - const std::string &remoteAddress, + const std::string &peerAddress, int nLast, FilterMask mask = NoFilter ) const; std::list> getHistory ( - const std::string &remoteAddress, + const std::string &peerAddress, int begin, int end, FilterMask mask = NoFilter ) const; - void cleanHistory (const std::string &remoteAddress = ""); + void cleanHistory (const std::string &peerAddress = ""); bool import (Backend backend, const std::string ¶meters) override; From 429cba5d0a381e374e26a72f17f48ae4e9445013 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 9 Oct 2017 17:15:37 +0200 Subject: [PATCH 0365/2215] feat(EventsDb): add cleanEvents impl --- src/db/events-db.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index fa2c2db65..21e7975d7 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -498,13 +498,22 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} } void EventsDb::cleanEvents (FilterMask mask) { + L_D(); + if (!isConnected()) { lWarning() << "Unable to clean events. Not connected."; return; } - // TODO. - (void)mask; + string query = "DELETE FROM event" + + buildSqlEventFilter({ MessageFilter, CallFilter, ConferenceFilter }, mask); + + L_BEGIN_LOG_EXCEPTION + + soci::session *session = d->dbSession.getBackendSession(); + *session << query; + + L_END_LOG_EXCEPTION } int EventsDb::getEventsCount (FilterMask mask) const { From efe2cb6d20857573b58d3d3716fa7c8bc7925179 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 9 Oct 2017 17:18:15 +0200 Subject: [PATCH 0366/2215] add subject changed notify tests --- .../local-conference-event-handler.cpp | 3 - .../remote-conference-event-handler.cpp | 3 + tester/conference-event-tester.cpp | 61 ++++++++++++++++++- 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 8f46293ce..22b532b75 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -97,7 +97,6 @@ string LocalConferenceEventHandlerPrivate::createNotifyFullState () { string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const Address &addr) { string entity = this->conf->getConferenceAddress()->asStringUriOnly(); - string subject = this->conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -115,7 +114,6 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const A string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved (const Address &addr) { string entity = this->conf->getConferenceAddress()->asStringUriOnly(); - string subject = this->conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -130,7 +128,6 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved (const string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined (const Address &addr, bool isAdmin) { string entity = this->conf->getConferenceAddress()->asStringUriOnly(); - string subject = this->conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index a409fe1d5..216e8e568 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -76,6 +76,9 @@ void RemoteConferenceEventHandler::notifyReceived(string xmlBody) { if(confInfo->getConferenceDescription().present() && confInfo->getConferenceDescription().get().getSubject().present()) d->listener->onSubjectChanged(confInfo->getConferenceDescription().get().getSubject().get()); + if(!confInfo->getUsers().present()) + return; + for (const auto &user : confInfo->getUsers()->getUser()) { LinphoneAddress *cAddr = linphone_core_interpret_url(d->core, user.getEntity()->c_str()); char *cAddrStr = linphone_address_as_string(cAddr); diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index 9cd2f8e09..b578aa018 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -489,6 +489,7 @@ void first_notify_parsing() { delete[] notify; + BC_ASSERT_STRING_EQUAL(tester.confSubject.c_str(), "Agenda: This month's goals"); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); @@ -763,6 +764,7 @@ void send_first_notify() { CallSessionParams params; localConf.addParticipant(bobAddr, ¶ms, false); localConf.addParticipant(aliceAddr, ¶ms, false); + localConf.setSubject("A random test subject"); shared_ptr alice = localConf.findParticipant(aliceAddr); alice->setAdmin(true); LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); @@ -773,6 +775,7 @@ void send_first_notify() { L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; tester.handler->notifyReceived(notify); + BC_ASSERT_STRING_EQUAL(tester.confSubject.c_str(), "A random test subject"); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(bobAddr.asString()) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(aliceAddr.asString()) != tester.participants.end()); @@ -992,6 +995,61 @@ void send_unadmined_notify() { linphone_core_manager_destroy(pauline); } +void send_subject_changed_notify () { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager *pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + char *identityStr = linphone_address_as_string(pauline->identity); + Address addr(identityStr); + bctbx_free(identityStr); + ConferenceEventTester tester(marie->lc, addr); + LocalConference localConf(pauline->lc, addr); + LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); + char *bobAddrStr = linphone_address_as_string(cBobAddr); + Address bobAddr(bobAddrStr); + bctbx_free(bobAddrStr); + linphone_address_unref(cBobAddr); + LinphoneAddress *cAliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); + char *aliceAddrStr = linphone_address_as_string(cAliceAddr); + Address aliceAddr(aliceAddrStr); + bctbx_free(aliceAddrStr); + linphone_address_unref(cAliceAddr); + + CallSessionParams params; + localConf.addParticipant(bobAddr, ¶ms, false); + localConf.addParticipant(aliceAddr, ¶ms, false); + localConf.setSubject("A random test subject"); + shared_ptr alice = localConf.findParticipant(aliceAddr); + alice->setAdmin(true); + LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); + L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; + string notify = localHandlerPrivate->createNotifyFullState(); + + RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); + L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; + tester.handler->notifyReceived(notify); + + BC_ASSERT_STRING_EQUAL(tester.confSubject.c_str(), "A random test subject"); + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.participants.find(bobAddr.asString()) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(aliceAddr.asString()) != tester.participants.end()); + BC_ASSERT_TRUE(!tester.participants.find(bobAddr.asString())->second); + BC_ASSERT_TRUE(tester.participants.find(aliceAddr.asString())->second); + + localConf.setSubject("Another random test subject..."); + notify = localHandlerPrivate->createNotifySubjectChanged(); + tester.handler->notifyReceived(notify); + + BC_ASSERT_STRING_EQUAL(tester.confSubject.c_str(), "Another random test subject..."); + BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.participants.find(bobAddr.asString()) != tester.participants.end()); + BC_ASSERT_TRUE(tester.participants.find(aliceAddr.asString()) != tester.participants.end()); + BC_ASSERT_TRUE(!tester.participants.find(bobAddr.asString())->second); + BC_ASSERT_TRUE(tester.participants.find(aliceAddr.asString())->second); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + test_t conference_event_tests[] = { TEST_NO_TAG("First notify parsing", first_notify_parsing), TEST_NO_TAG("First notify parsing wrong conf", first_notify_parsing_wrong_conf), @@ -1004,7 +1062,8 @@ test_t conference_event_tests[] = { TEST_NO_TAG("Send participant added notify", send_added_notify), TEST_NO_TAG("Send participant removed notify", send_removed_notify), TEST_NO_TAG("Send participant admined notify", send_admined_notify), - TEST_NO_TAG("Send participant unadmined notify", send_unadmined_notify) + TEST_NO_TAG("Send participant unadmined notify", send_unadmined_notify), + TEST_NO_TAG("Send subject changed notify", send_subject_changed_notify) }; test_suite_t conference_event_test_suite = { From 2c67a76d6adace0744a1a2444f13f3d6aa0984d1 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 9 Oct 2017 17:33:57 +0200 Subject: [PATCH 0367/2215] feat(EventsDb): add getUnreadMessagesCount impl --- src/db/events-db.cpp | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 21e7975d7..000f41ac1 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -545,6 +545,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} lWarning() << "Unable to get messages count. Not connected."; return 0; } + int count = 0; L_BEGIN_LOG_EXCEPTION @@ -556,7 +557,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} *session << query, soci::into(count); else { query += " WHERE chat_room_id = (" - " SELECT id FROM sip_address WHERE value = :peerSipAddress" + " SELECT id FROM sip_address WHERE value = :peerAddress" ")"; *session << query, soci::use(peerAddress), soci::into(count); @@ -575,21 +576,25 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return 0; } - string query = "SELECT COUNT(*) FROM message_event"; - if (!peerAddress.empty()) - query += " WHERE chat_room_id = (" - " SELECT id FROM dialog WHERE remote_sip_address_id = (" - " SELECT id FROM sip_address WHERE value = :remote_address" - " )" - " )" - " AND direction = " + Utils::toString(static_cast(ChatMessage::Direction::Incoming)) + - " AND state = " + Utils::toString(static_cast(ChatMessage::State::Displayed)); int count = 0; + string query = "SELECT COUNT(*) FROM message_event WHERE"; + if (!peerAddress.empty()) + query += " chat_room_id = (" + " SELECT id FROM sip_address WHERE value = :peerAddress" + ") AND "; + + query += " direction = " + Utils::toString(static_cast(ChatMessage::Direction::Incoming)) + + + " AND state = " + Utils::toString(static_cast(ChatMessage::State::Displayed)); + L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); - *session << query, soci::use(peerAddress), soci::into(count); + + if (peerAddress.empty()) + *session << query, soci::into(count); + else + *session << query, soci::use(peerAddress), soci::into(count); L_END_LOG_EXCEPTION From fb8632903100150835a93d7c811fb50ca97c84b9 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 9 Oct 2017 17:50:45 +0200 Subject: [PATCH 0368/2215] Started JAVA wrapper --- tools/metadoc.py | 5 + wrappers/csharp/genwrapper.py | 2 +- wrappers/java/CMakeLists.txt | 38 ++ wrappers/java/genwrapper.py | 400 +++++++++++++++++++++ wrappers/java/java_class.mustache | 156 ++++++++ wrappers/java/java_enum.mustache | 60 ++++ wrappers/java/java_enum_old.mustache | 65 ++++ wrappers/java/java_interface.mustache | 46 +++ wrappers/java/java_interface_stub.mustache | 34 ++ wrappers/java/jni.mustache | 38 ++ 10 files changed, 843 insertions(+), 1 deletion(-) create mode 100644 wrappers/java/CMakeLists.txt create mode 100644 wrappers/java/genwrapper.py create mode 100644 wrappers/java/java_class.mustache create mode 100644 wrappers/java/java_enum.mustache create mode 100644 wrappers/java/java_enum_old.mustache create mode 100644 wrappers/java/java_interface.mustache create mode 100644 wrappers/java/java_interface_stub.mustache create mode 100644 wrappers/java/jni.mustache diff --git a/tools/metadoc.py b/tools/metadoc.py index 1cf932daf..fd985a11f 100644 --- a/tools/metadoc.py +++ b/tools/metadoc.py @@ -191,3 +191,8 @@ class SandcastleCSharpTranslator(Translator): if len(lines) > 0: lines.insert(0, '') lines.append('') + + +class SandcastleJavaTranslator(Translator): + def _tag_as_brief(self, lines): + pass diff --git a/wrappers/csharp/genwrapper.py b/wrappers/csharp/genwrapper.py index e5aad72a7..f83c68361 100644 --- a/wrappers/csharp/genwrapper.py +++ b/wrappers/csharp/genwrapper.py @@ -566,7 +566,7 @@ def render(renderer, item, path): os.unlink(tmppath) def main(): - argparser = argparse.ArgumentParser(description='Generate source files for the C++ wrapper') + argparser = argparse.ArgumentParser(description='Generate source files for the C# wrapper') argparser.add_argument('xmldir', type=str, help='Directory where the XML documentation of the Linphone\'s API generated by Doxygen is placed') argparser.add_argument('-o --output', type=str, help='the directory where to generate the source files', dest='outputdir', default='.') argparser.add_argument('-n --name', type=str, help='the name of the genarated source file', dest='outputfile', default='LinphoneWrapper.cs') diff --git a/wrappers/java/CMakeLists.txt b/wrappers/java/CMakeLists.txt new file mode 100644 index 000000000..66b01ea38 --- /dev/null +++ b/wrappers/java/CMakeLists.txt @@ -0,0 +1,38 @@ +############################################################################ +# CMakeLists.txt +# Copyright (C) 2017 Belledonne Communications, Grenoble France +# +############################################################################ +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +############################################################################ + +add_custom_command(OUTPUT linphone_jni.cc + COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/genwrapper.py" "${PROJECT_BINARY_DIR}/coreapi/help/doc/doxygen/xml" + DEPENDS ${PROJECT_SOURCE_DIR}/tools/genapixml.py + ${PROJECT_SOURCE_DIR}/tools/metadoc.py + ${PROJECT_SOURCE_DIR}/tools/abstractapi.py + genwrapper.py + wrapper_impl.mustache + linphone-doc + "${PROJECT_BINARY_DIR}/coreapi/help/doc/doxygen/xml/index.xml" +) + +add_custom_target(linphonej ALL DEPENDS linphone_jni.cc) + +#install(FILES ${CMAKE_CURRENT_BINARY_DIR}/linphone_jni.cc +# DESTINATION ${CMAKE_INSTALL_DATADIR}/linphonej +#) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py new file mode 100644 index 000000000..ca85ed3c0 --- /dev/null +++ b/wrappers/java/genwrapper.py @@ -0,0 +1,400 @@ +#!/usr/bin/python + +# Copyright (C) 2017 Belledonne Communications SARL +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +import argparse +import os +import sys +import pystache +import errno + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'tools')) +print(sys.path) +import genapixml as CApi +import abstractapi as AbsApi +import metadoc + +########################################################################## + +class JavaTranslator(object): + def __init__(self): + self.docTranslator = metadoc.SandcastleJavaTranslator() + + def throws_exception(self, _type): + if type(_type) is AbsApi.BaseType: + if _type.name == 'status': + return True + return False + + def translate_argument_name(self, _argName): + return _argName.to_snake_case() + + def translate_type(self, _type, native=False): + if type(_type) is AbsApi.ListType: + ptrtype = '' + if type(_type.containedTypeDesc) is AbsApi.ClassType: + ptrtype = self.translate_type(_type.containedTypeDesc, native) + elif type(_type.containedTypeDesc) is AbsApi.BaseType: + ptrtype = self.translate_type(_type.containedTypeDesc, native) + elif type(_type.containedTypeDesc) is AbsApi.EnumType: + ptrtype = self.translate_type(_type.containedTypeDesc, native) + else: + if _type.containedTypeDesc: + raise AbsApi.Error('translation of bctbx_list_t of ' + _type.containedTypeDesc.name) + else: + raise AbsApi.Error('translation of bctbx_list_t of unknow type !') + return ptrtype + '[]' + + elif type(_type) is AbsApi.ClassType: + if native: + return 'long' + return _type.desc.name.to_camel_case() + elif type(_type) is AbsApi.EnumType: + if native: + return 'int' + return _type.desc.name.to_camel_case() + elif type(_type) is AbsApi.BaseType: + if _type.name == 'string': + return 'String' + elif _type.name == 'integer': + return 'int' + elif _type.name == 'floatant': + return 'float' + elif _type.name == 'size': + return 'int' + return _type.name + + def translate_argument(self, _arg, native=False): + return '{0} {1}'.format(self.translate_type(_arg.type, native), self.translate_argument_name(_arg.name)) + + def translate_property(self, _property): + properties = [] + if _property.getter is not None: + properties.append(self.translate_method(_property.getter)) + if _property.setter is not None: + properties.append(self.translate_method(_property.setter)) + return properties + + def translate_method(self, _method): + methodDict = {} + + methodDict['return'] = self.translate_type(_method.returnType) + methodDict['return_native'] = self.translate_type(_method.returnType, True) + methodDict['return_keyword'] = '' if methodDict['return'] == 'void' else 'return ' + + methodDict['convertInputClassArrayToLongArray'] = False + methodDict['convertOutputClassArrayToLongArray'] = type(_method.returnType) is AbsApi.ListType and type(_method.returnType.containedTypeDesc) is AbsApi.ClassType + if methodDict['convertOutputClassArrayToLongArray']: + methodDict['native_params_impl_list_param_name'] = 'classArray' + methodDict['native_params_impl_list_param_type'] = self.translate_type(_method.returnType.containedTypeDesc) + + methodDict['name'] = _method.name.to_camel_case(lower=True) + methodDict['exception'] = self.throws_exception(_method.returnType) + + methodDict['params'] = '' + methodDict['native_params'] = 'long nativePtr' + methodDict['static_native_params'] = '' + methodDict['native_params_impl'] = '' + for arg in _method.args: + if arg is not _method.args[0]: + methodDict['params'] += ', ' + methodDict['native_params'] += ', ' + methodDict['native_params_impl'] += ', ' + + methodDict['params'] += self.translate_argument(arg) + methodDict['native_params'] += self.translate_argument(arg, True) + methodDict['static_native_params'] += self.translate_argument(arg, True) + if type(arg.type) is AbsApi.ClassType: + methodDict['native_params_impl'] += '((' + self.translate_type(arg.type) + ')' + self.translate_argument_name(arg.name) + ').nativePtr' + elif type(arg.type) is AbsApi.ListType: + if type(arg.type.containedTypeDesc) is AbsApi.ClassType: + methodDict['convertInputClassArrayToLongArray'] = True + methodDict['native_params_impl_list_param_name'] = self.translate_argument_name(arg.name) + methodDict['native_params_impl_list_param_type'] = self.translate_type(arg.type.containedTypeDesc) + 'Impl' + methodDict['native_params_impl'] += 'longArray' + else: + methodDict['native_params_impl'] += self.translate_argument_name(arg.name) + else: + methodDict['native_params_impl'] += self.translate_argument_name(arg.name) + + methodDict['classicMethod'] = not methodDict['convertInputClassArrayToLongArray'] and not methodDict['convertOutputClassArrayToLongArray'] + methodDict['deprecated'] = _method.deprecated + methodDict['doc'] = self.docTranslator.translate(_method.briefDescription) if _method.briefDescription is not None else None + + return methodDict + + def translate_class(self, _class): + classDict = { + 'methods' : [], + 'staticMethods' : [], + } + + classDict['isLinphoneFactory'] = _class.name.to_camel_case() == "Factory" + classDict['doc'] = self.docTranslator.translate(_class.briefDescription) if _class.briefDescription is not None else None + + for _property in _class.properties: + try: + classDict['methods'] += self.translate_property(_property) + except AbsApi.Error as e: + print('error while translating {0} property: {1}'.format(_property.name.to_snake_case(), e.args[0])) + + for method in _class.instanceMethods: + try: + methodDict = self.translate_method(method) + classDict['methods'].append(methodDict) + except AbsApi.Error as e: + print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0])) + + for method in _class.classMethods: + try: + methodDict = self.translate_method(method) + classDict['staticMethods'].append(methodDict) + except AbsApi.Error as e: + print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0])) + + return classDict + + def translate_interface(self, _class): + interfaceDict = { + 'methods' : [], + } + + interfaceDict['doc'] = self.docTranslator.translate(_class.briefDescription) + + for method in _class.methods: + interfaceDict['methods'].append(self.translate_method(method)) + + return interfaceDict + + def translate_enum(self, _class): + enumDict = {} + + enumDict['name'] = _class.name.to_camel_case() + enumDict['doc'] = self.docTranslator.translate(_class.briefDescription) + enumDict['values'] = [] + i = 0 + lastValue = None + + for enumValue in _class.values: + enumValDict = {} + enumValDict['name'] = enumValue.name.to_camel_case() + enumValDict['doc'] = self.docTranslator.translate(enumValue.briefDescription) + if type(enumValue.value) is int: + lastValue = enumValue.value + enumValDict['value'] = str(enumValue.value) + elif type(enumValue.value) is AbsApi.Flag: + enumValDict['value'] = '1<<' + str(enumValue.value.position) + else: + if lastValue is not None: + enumValDict['value'] = lastValue + 1 + lastValue += 1 + else: + enumValDict['value'] = i + i += 1 + enumValDict['commarorsemicolon'] = ';' if i == len(_class.values) else ',' + enumDict['values'].append(enumValDict) + + return enumDict + +########################################################################## + +class JavaEnum(object): + def __init__(self, _enum, translator): + self._class = translator.translate_enum(_enum) + self.packageName = "org.linphone" + self.className = _enum.name.to_camel_case() + self.filename = self.className + ".java" + self.values = self._class['values'] + self.doc = self._class['doc'] + self.jniMethods = [] + +class JavaInterface(object): + def __init__(self, _interface, translator): + self._class = translator.translate_interface(_interface) + self.packageName = "org.linphone" + self.className = _interface.name.to_camel_case() + self.filename = self.className + ".java" + self.imports = [] + self.methods = self._class['methods'] + self.doc = self._class['doc'] + self.jniMethods = [] + +class JavaInterfaceStub(object): + def __init__(self, _interface): + self.packageName = _interface.packageName + self.className = _interface.className + self.classNameStub = self.className + "Stub" + self.filename = self.className + "Stub.java" + self.methods = _interface.methods + +class JavaClass(object): + def __init__(self, _class, translator): + self._class = translator.translate_class(_class) + self.isLinphoneFactory = self._class['isLinphoneFactory'] + self.packageName = "org.linphone" + self.className = _class.name.to_camel_case() + self.classImplName = self.className + "Impl" + self.filename = self.className + ".java" + self.imports = [] + self.methods = self._class['methods'] + self.staticMethods = self._class['staticMethods'] + self.doc = self._class['doc'] + self.jniMethods = [] + self.enums = [] + + def add_enum(self, enum): + if enum.className.startswith(self.className): + enum.className = enum.className[len(self.className):] + self.enums.append(enum) + +class Jni(object): + def __init__(self): + self.methods = {} + + def add_methods(self, name, methods): + self.methods[name] = methods + +########################################################################## + +class GenWrapper(object): + def __init__(self, srcdir, javadir, xmldir): + self.srcdir = srcdir + self.javadir = javadir + + project = CApi.Project() + project.initFromDir(xmldir) + project.check() + + self.parser = AbsApi.CParser(project) + self.parser.parse_all() + self.translator = JavaTranslator() + self.renderer = pystache.Renderer() + self.jni = Jni() + + self.enums = {} + self.interfaces = {} + self.classes = {} + self.enums_list = { + 'CallState': 'Call', + 'ChatMessageState': 'ChatMessage', + 'ConfiguringState': 'Core', + 'CoreLogCollectionUploadState': 'Core', + 'GlobalState': 'Core', + 'RegistrationState': 'Core', + } + self.enums_to_remove = [] + + def render_all(self): + for _interface in self.parser.interfacesIndex.values(): + self.render_java_interface(_interface) + for _class in self.parser.classesIndex.values(): + self.render_java_class(_class) + for _enum in self.parser.enumsIndex.items(): + if _enum[1] is not None: + self.render_java_enum(_enum[1]) + + for name, value in self.enums.iteritems(): + if name in self.enums_list: + className = self.enums_list[name] + print 'Enum ' + name + ' belongs to class ' + className + self.classes[className].add_enum(value) + self.enums_to_remove.append(name) + + for enum in self.enums_to_remove: + self.enums.pop(enum, None) + + for name, value in self.enums.iteritems(): + self.render(value, self.javadir + '/' + value.filename) + for name, value in self.interfaces.iteritems(): + self.render(value, self.javadir + '/' + value.filename) + for name, value in self.classes.iteritems(): + self.render(value, self.javadir + '/' + value.filename) + + self.render(self.jni, self.srcdir + '/linphone_jni.cc') + + def render(self, item, path): + tmppath = path + '.tmp' + content = '' + with open(tmppath, mode='w') as f: + f.write(self.renderer.render(item)) + with open(tmppath, mode='rU') as f: + content = f.read() + with open(path, mode='w') as f: + f.write(content) + os.unlink(tmppath) + + def render_java_enum(self, _class): + if _class is not None: + try: + javaenum = JavaEnum(_class, self.translator) + self.enums[javaenum.className] = javaenum + except AbsApi.Error as e: + print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) + self.jni.add_methods(javaenum.className, javaenum.jniMethods) + + def render_java_interface(self, _class): + if _class is not None: + try: + javainterface = JavaInterface(_class, self.translator) + self.interfaces[javainterface.className] = javainterface + javaInterfaceStub = JavaInterfaceStub(javainterface) + self.interfaces[javaInterfaceStub.className] = javaInterfaceStub + except AbsApi.Error as e: + print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) + self.jni.add_methods(javainterface.className, javainterface.jniMethods) + + def render_java_class(self, _class): + if _class is not None: + try: + javaclass = JavaClass(_class, self.translator) + self.classes[javaclass.className] = javaclass + except AbsApi.Error as e: + print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) + self.jni.add_methods(javaclass.className, javaclass.jniMethods) + +########################################################################## + +def main(): + argparser = argparse.ArgumentParser(description='Generate source files for the Java wrapper') + argparser.add_argument('xmldir', type=str, help='Directory where the XML documentation of the Linphone\'s API generated by Doxygen is placed') + argparser.add_argument('-o --output', type=str, help='the directory where to generate the source files', dest='outputdir', default='.') + argparser.add_argument('-n --name', type=str, help='the name of the genarated source file', dest='outputfile', default='linphone_jni.cc') + args = argparser.parse_args() + + srcdir = args.outputdir + '/src' + javadir = args.outputdir + '/java' + + try: + os.makedirs(srcdir) + except OSError as e: + if e.errno != errno.EEXIST: + print("Cannot create '{0}' dircetory: {1}".format(srcdir, e.strerror)) + sys.exit(1) + + try: + os.makedirs(javadir) + except OSError as e: + if e.errno != errno.EEXIST: + print("Cannot create '{0}' dircetory: {1}".format(javadir, e.strerror)) + sys.exit(1) + + genwrapper = GenWrapper(srcdir, javadir, args.xmldir) + genwrapper.render_all() + +if __name__ == '__main__': + main() diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache new file mode 100644 index 000000000..cd8284ea9 --- /dev/null +++ b/wrappers/java/java_class.mustache @@ -0,0 +1,156 @@ +/* +{{className}}.java +Copyright (C) 2010 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +package {{packageName}} + +{{#imports}} +import {{import}} +{{/imports}} +{{#isLinphoneFactory}} +import org.linphone.mediastream.Version; +{{/isLinphoneFactory}} + +{{#doc}} +/** + {{#lines}} + * {{line}} + {{/lines}} + */ +{{/doc}} +public interface {{className}} { +{{#enums}} + enum {{className}} { + {{#values}} + {{#doc}} + /** + {{#lines}} + * {{line}} + {{/lines}} + */ + {{/doc}} + {{name}}({{value}}){{commarorsemicolon}} + + {{/values}} + protected final int mValue; + + private {{className}} (int value) { + mValue = value; + } + + static protected {{className}} fromInt(int value) throws CoreException { + switch(value) { + {{#values}} + case {{value}}: return {{name}}; + {{/values}} + default: + throw new CoreException("Unhandled enum value " + value + " for {{className}}"); + } + } + }; + +{{/enums}} +{{#isLinphoneFactory}} + +{{/isLinphoneFactory}} +{{#methods}} + {{#doc}} + /** + {{#lines}} + * {{line}} + {{/lines}} + */ + {{/doc}} + {{#deprecated}}@deprecated + {{/deprecated}}public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}}; + +{{/methods}} + +{{#staticMethods}} + {{#doc}} + /** + {{#lines}} + * {{line}} + {{/lines}} + */ + {{/doc}} + public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}}; + +{{/staticMethods}} +} + +class {{classImplName}} implements {{className}} { + + protected long nativePtr = 0; + +{{#isLinphoneFactory}} + private static boolean loadOptionalLibrary(String s) { + try { + System.loadLibrary(s); + return true; + } catch (Throwable e) { + android.util.Log.w("LinphoneCoreFactoryImpl", "Unable to load optional library " + s + ": " +e.getMessage()); + } + return false; + } + + static { + System.loadLibrary("gnustl_shared"); + loadOptionalLibrary("ffmpeg-linphone"); + System.loadLibrary("bctoolbox"); + System.loadLibrary("ortp"); + System.loadLibrary("mediastreamer_base"); + System.loadLibrary("mediastreamer_voip"); + System.loadLibrary("linphone"); + Version.dumpCapabilities(); + } +{{/isLinphoneFactory}} + +{{#methods}} + private native {{return_native}} {{name}}({{native_params}}); + public {{return}} {{name}}({{params}}) {{#exception}}throws CoreException{{/exception}} { + {{#convertInputClassArrayToLongArray}} + long[] longArray = new long[{{native_params_impl_list_param_name}}.length]; + for (int i=0; i < {{native_params_impl_list_param_name}}.length; i++) { + longArray[i] = (({{native_params_impl_list_param_type}}){{native_params_impl_list_param_name}}[i]).nativePtr; + } + {{name}}(nativePtr{{native_params_impl}}); + {{/convertInputClassArrayToLongArray}} + {{#convertOutputClassArrayToLongArray}} + long[] longArray = {{name}}(nativePtr{{native_params_impl}}); + if (longArray == null) return null; + + {{native_params_impl_list_param_type}}[] classArray = new {{native_params_impl_list_param_type}}[longArray.length]; + for (int i=0; i < longArray.length; i++) { + classArray[i] = new {{native_params_impl_list_param_type}}Impl(longArray[i]); + } + return classArray; + {{/convertOutputClassArrayToLongArray}} + {{#classicMethod}} + {{return_keyword}}{{name}}(nativePtr{{native_params_impl}}); + {{/classicMethod}} + } + +{{/methods}} + +{{#staticMethods}} + @Override + private native {{return_native}} {{name}}({{static_native_params}}); + +{{/staticMethods}} +} \ No newline at end of file diff --git a/wrappers/java/java_enum.mustache b/wrappers/java/java_enum.mustache new file mode 100644 index 000000000..a890ff72e --- /dev/null +++ b/wrappers/java/java_enum.mustache @@ -0,0 +1,60 @@ +/* +{{className}}.java +Copyright (C) 2010 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +package {{packageName}} + +{{#imports}} +import {{import}} +{{/imports}} + +{{#doc}} +/** + {{#lines}} + * {{line}} + {{/lines}} + */ +{{/doc}} +public enum {{className}} { +{{#values}} + {{#doc}} + /** + {{#lines}} + * {{line}} + {{/lines}} + */ + {{/doc}} + {{name}}({{value}}){{commarorsemicolon}} + +{{/values}} + protected final int mValue; + + private {{className}} (int value) { + mValue = value; + } + + static protected {{className}} fromInt(int value) throws CoreException { + switch(value) { + {{#values}} + case {{value}}: return {{name}}; + {{/values}} + default: + throw new CoreException("Unhandled enum value " + value + " for {{className}}"); + } + } +} \ No newline at end of file diff --git a/wrappers/java/java_enum_old.mustache b/wrappers/java/java_enum_old.mustache new file mode 100644 index 000000000..81f01e1bb --- /dev/null +++ b/wrappers/java/java_enum_old.mustache @@ -0,0 +1,65 @@ +/* +{{className}}.java +Copyright (C) 2010 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +package {{packageName}} + +{{#imports}} +import {{import}} +{{/imports}} + +{{#doc}} +/** + {{#lines}} + * {{line}} + {{/lines}} + */ +{{/doc}} +static public class {{className}} { + static private Vector<{{className}}> values = new Vector<{{className}}>(); +{{#values}} + + {{#doc}} + /** + {{#lines}} + * {{line}} + {{/lines}} + */ + {{/doc}} + static public {{className}} {{name}} = new {{className}}({{value}}, {{name}}); +{{/values}} + + protected final int mValue; + private final String mStringValue; + + private {{className}}(int value, String stringValue) { + mValue = value; + values.addElement(this); + mStringValue = stringValue; + } + public static {{className}} fromInt(int value) { + for (int i = 0; i < values.size(); i++) { + {{className}} mstate = ({{className}}) values.elementAt(i); + if (mstate.mValue == value) return mstate; + } + throw new RuntimeException("{{className}} not found [" + value + "]"); + } + public String toString() { + return mStringValue; + } +} \ No newline at end of file diff --git a/wrappers/java/java_interface.mustache b/wrappers/java/java_interface.mustache new file mode 100644 index 000000000..9832f7a8d --- /dev/null +++ b/wrappers/java/java_interface.mustache @@ -0,0 +1,46 @@ +/* +{{className}}.java +Copyright (C) 2010 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +package {{packageName}} + +{{#imports}} +import {{import}} +{{/imports}} + +{{#doc}} +/** + {{#lines}} + * {{line}} + {{/lines}} + */ +{{/doc}} +public interface {{className}} { +{{#methods}} + {{#doc}} + /** + {{#lines}} + * {{line}} + {{/lines}} + */ + {{/doc}} + {{#deprecated}}@deprecated + {{/deprecated}}public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}}; + +{{/methods}} +} \ No newline at end of file diff --git a/wrappers/java/java_interface_stub.mustache b/wrappers/java/java_interface_stub.mustache new file mode 100644 index 000000000..afb401674 --- /dev/null +++ b/wrappers/java/java_interface_stub.mustache @@ -0,0 +1,34 @@ +/* +{{classNameStub}}.java +Copyright (C) 2010 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +package {{packageName}} + +{{#imports}} +import {{import}} +{{/imports}} + +public class {{classNameStub}} implements {{className}} { +{{#methods}} + @Override + public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}} { + // Auto-generated method stub + } + +{{/methods}} +} \ No newline at end of file diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache new file mode 100644 index 000000000..7c5b17133 --- /dev/null +++ b/wrappers/java/jni.mustache @@ -0,0 +1,38 @@ +/* +linphone_jni.cc +Copyright (C) 2017 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *ajvm, void *reserved) { +#ifdef __ANDROID__ + ms_set_jvm(ajvm); +#endif /* __ANDROID__ */ + jvm=ajvm; + return JNI_VERSION_1_2; +} + +static const char* GetStringUTFChars(JNIEnv* env, jstring string) { + const char *cstring = string ? env->GetStringUTFChars(string, NULL) : NULL; + return cstring; +} + +static void ReleaseStringUTFChars(JNIEnv* env, jstring string, const char *cstring) { + if (string) env->ReleaseStringUTFChars(string, cstring); +} \ No newline at end of file From 353fcf2ed40353e5cfa461db3756704f546e440b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 10:28:28 +0200 Subject: [PATCH 0369/2215] Added more enum links to classes in Java wrapper --- wrappers/java/genwrapper.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index ca85ed3c0..82534e385 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -290,12 +290,25 @@ class GenWrapper(object): self.interfaces = {} self.classes = {} self.enums_list = { + 'AddressFamily': 'CallStats', + 'CallDir': 'Call', 'CallState': 'Call', + 'CallStatus': 'CallLog', 'ChatMessageState': 'ChatMessage', 'ConfiguringState': 'Core', 'CoreLogCollectionUploadState': 'Core', 'GlobalState': 'Core', + 'FriendListStatus': 'FriendList', + 'IceState': 'CallStats', + 'LimeState': 'Core', + 'MediaDirection': 'Core', + 'MediaEncryption': 'Core', + 'PlayerState': 'Player', 'RegistrationState': 'Core', + 'SubscribePolicy': 'Friend', + 'TransportType': 'Address', + 'XmlRpcArgType': 'XmlRpcRequest', + 'XmlRpcStatus': 'XmlRpcRequest', } self.enums_to_remove = [] From 210ae7c56c56cc8d2e0ef771912154862f95ef24 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 10:30:33 +0200 Subject: [PATCH 0370/2215] Fixed broken generation of listeners in Java wrapper --- wrappers/java/genwrapper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 82534e385..67d079870 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -366,7 +366,7 @@ class GenWrapper(object): javainterface = JavaInterface(_class, self.translator) self.interfaces[javainterface.className] = javainterface javaInterfaceStub = JavaInterfaceStub(javainterface) - self.interfaces[javaInterfaceStub.className] = javaInterfaceStub + self.interfaces[javaInterfaceStub.classNameStub] = javaInterfaceStub except AbsApi.Error as e: print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) self.jni.add_methods(javainterface.className, javainterface.jniMethods) From fc873d56151fa2846b07076b39f8d0c8970e5460 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 19 Sep 2017 14:37:48 +0200 Subject: [PATCH 0371/2215] disable gruu for tunnel testers --- tester/tunnel_tester.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tester/tunnel_tester.c b/tester/tunnel_tester.c index 5e3d41e86..03df655db 100644 --- a/tester/tunnel_tester.c +++ b/tester/tunnel_tester.c @@ -57,7 +57,9 @@ static void call_with_tunnel_base(LinphoneTunnelMode tunnel_mode, bool_t with_si char tunnel_ip[64]; char *public_ip, *public_ip2=NULL; BC_ASSERT_FALSE(get_ip_from_hostname("tunnel.linphone.org",tunnel_ip,sizeof(tunnel_ip))); - + linphone_core_remove_supported_tag(pauline->lc,"gruu"); /*with gruu, we have no access to the "public IP from contact*/ + linphone_core_remove_supported_tag(marie->lc,"gruu"); + BC_ASSERT_TRUE(wait_for(pauline->lc,NULL,&pauline->stat.number_of_LinphoneRegistrationOk,1)); public_ip = get_public_contact_ip(pauline->lc); BC_ASSERT_STRING_NOT_EQUAL(public_ip, tunnel_ip); From 46611dcf0f4c5776ce08f1c336335541a2c53b79 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 10 Oct 2017 10:50:33 +0200 Subject: [PATCH 0372/2215] feat(EventsDb): can clean messages history --- src/db/events-db.cpp | 33 +++++++++++++++++++++++++-------- src/db/events-db.h | 3 ++- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 000f41ac1..65da14503 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -379,11 +379,11 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS chat_room_participant (" - " id" + primaryKeyAutoIncrementStr() + "," " chat_room_id INT UNSIGNED NOT NULL," " sip_address_id INT UNSIGNED NOT NULL," " is_admin BOOLEAN NOT NULL," + " PRIMARY KEY (chat_room_id, sip_address_id)," " FOREIGN KEY (chat_room_id)" " REFERENCES chat_room(peer_sip_address_id)" " ON DELETE CASCADE," @@ -428,7 +428,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " PRIMARY KEY (message_event_id, sip_address_id)," " FOREIGN KEY (message_event_id)" - " REFERENCES message_event(id)" + " REFERENCES message_event(event_id)" " ON DELETE CASCADE," " FOREIGN KEY (sip_address_id)" " REFERENCES sip_address(id)" @@ -441,8 +441,9 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " message_event_id INT UNSIGNED NOT NULL," " content_type_id INT UNSIGNED NOT NULL," " body TEXT NOT NULL," + " FOREIGN KEY (message_event_id)" - " REFERENCES message_event(id)" + " REFERENCES message_event(event_id)" " ON DELETE CASCADE," " FOREIGN KEY (content_type_id)" " REFERENCES content_type(id)" @@ -451,12 +452,13 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS message_crypto_data (" - " id" + primaryKeyAutoIncrementStr() + "," " message_event_id INT UNSIGNED NOT NULL," + " key VARCHAR(255)," " data BLOB," + " PRIMARY KEY (message_event_id, key)," " FOREIGN KEY (message_event_id)" - " REFERENCES message_event(id)" + " REFERENCES message_event(event_id)" " ON DELETE CASCADE" ")"; } @@ -633,14 +635,29 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return list>(); } - void EventsDb::cleanHistory (const string &peerAddress) { + void EventsDb::cleanHistory (const string &peerAddress, FilterMask mask) { + L_D(); + + // TODO: Deal with mask. + (void)mask; + if (!isConnected()) { lWarning() << "Unable to clean history. Not connected."; return; } - // TODO. - (void)peerAddress; + L_BEGIN_LOG_EXCEPTION + + soci::session *session = d->dbSession.getBackendSession(); + *session << "DELETE FROM event WHERE id = (" + " SELECT event_id FROM message_event WHERE chat_room_id = (" + " SELECT peer_sip_address_id FROM chat_room WHERE peer_sip_address_id = (" + " SELECT id FROM sip_address WHERE value = :peerAddress" + " )" + " )" + ")"; + + L_END_LOG_EXCEPTION } // ----------------------------------------------------------------------------- diff --git a/src/db/events-db.h b/src/db/events-db.h index 030ff7eeb..d582f5149 100644 --- a/src/db/events-db.h +++ b/src/db/events-db.h @@ -64,8 +64,9 @@ public: int end, FilterMask mask = NoFilter ) const; - void cleanHistory (const std::string &peerAddress = ""); + void cleanHistory (const std::string &peerAddress = "", FilterMask mask = NoFilter); + // Import legacy messages from old db. bool import (Backend backend, const std::string ¶meters) override; protected: From a820e2add53cd6998616522e4d60a2a89503adf1 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 10 Oct 2017 10:55:07 +0200 Subject: [PATCH 0373/2215] feat(EventsDb): add message_content_app_data table --- src/db/events-db.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 65da14503..738a9e798 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -450,6 +450,18 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " ON DELETE CASCADE" ")"; + *session << + "CREATE TABLE IF NOT EXISTS message_content_app_data (" + " message_content_id INT UNSIGNED NOT NULL," + " key VARCHAR(255)," + " data BLOB," + + " PRIMARY KEY (message_content_id, key)," + " FOREIGN KEY (message_content_id)" + " REFERENCES message_content(id)" + " ON DELETE CASCADE" + ")"; + *session << "CREATE TABLE IF NOT EXISTS message_crypto_data (" " message_event_id INT UNSIGNED NOT NULL," @@ -649,7 +661,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); - *session << "DELETE FROM event WHERE id = (" + *session << "DELETE FROM event WHERE id IN (" " SELECT event_id FROM message_event WHERE chat_room_id = (" " SELECT peer_sip_address_id FROM chat_room WHERE peer_sip_address_id = (" " SELECT id FROM sip_address WHERE value = :peerAddress" From 85b9ab572df6f44f56ad5ad966b137361636b688 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 11:01:53 +0200 Subject: [PATCH 0374/2215] Generate java files for wrapper in package name directories --- wrappers/java/genwrapper.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 67d079870..09321a82b 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -214,9 +214,9 @@ class JavaTranslator(object): ########################################################################## class JavaEnum(object): - def __init__(self, _enum, translator): + def __init__(self, package, _enum, translator): self._class = translator.translate_enum(_enum) - self.packageName = "org.linphone" + self.packageName = package self.className = _enum.name.to_camel_case() self.filename = self.className + ".java" self.values = self._class['values'] @@ -224,9 +224,9 @@ class JavaEnum(object): self.jniMethods = [] class JavaInterface(object): - def __init__(self, _interface, translator): + def __init__(self, package, _interface, translator): self._class = translator.translate_interface(_interface) - self.packageName = "org.linphone" + self.packageName = package self.className = _interface.name.to_camel_case() self.filename = self.className + ".java" self.imports = [] @@ -243,10 +243,10 @@ class JavaInterfaceStub(object): self.methods = _interface.methods class JavaClass(object): - def __init__(self, _class, translator): + def __init__(self, package, _class, translator): self._class = translator.translate_class(_class) self.isLinphoneFactory = self._class['isLinphoneFactory'] - self.packageName = "org.linphone" + self.packageName = package self.className = _class.name.to_camel_case() self.classImplName = self.className + "Impl" self.filename = self.className + ".java" @@ -272,9 +272,10 @@ class Jni(object): ########################################################################## class GenWrapper(object): - def __init__(self, srcdir, javadir, xmldir): + def __init__(self, srcdir, javadir, package, xmldir): self.srcdir = srcdir self.javadir = javadir + self.package = package project = CApi.Project() project.initFromDir(xmldir) @@ -354,7 +355,7 @@ class GenWrapper(object): def render_java_enum(self, _class): if _class is not None: try: - javaenum = JavaEnum(_class, self.translator) + javaenum = JavaEnum(self.package, _class, self.translator) self.enums[javaenum.className] = javaenum except AbsApi.Error as e: print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) @@ -363,7 +364,7 @@ class GenWrapper(object): def render_java_interface(self, _class): if _class is not None: try: - javainterface = JavaInterface(_class, self.translator) + javainterface = JavaInterface(self.package, _class, self.translator) self.interfaces[javainterface.className] = javainterface javaInterfaceStub = JavaInterfaceStub(javainterface) self.interfaces[javaInterfaceStub.classNameStub] = javaInterfaceStub @@ -374,7 +375,7 @@ class GenWrapper(object): def render_java_class(self, _class): if _class is not None: try: - javaclass = JavaClass(_class, self.translator) + javaclass = JavaClass(self.package, _class, self.translator) self.classes[javaclass.className] = javaclass except AbsApi.Error as e: print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) @@ -386,11 +387,15 @@ def main(): argparser = argparse.ArgumentParser(description='Generate source files for the Java wrapper') argparser.add_argument('xmldir', type=str, help='Directory where the XML documentation of the Linphone\'s API generated by Doxygen is placed') argparser.add_argument('-o --output', type=str, help='the directory where to generate the source files', dest='outputdir', default='.') - argparser.add_argument('-n --name', type=str, help='the name of the genarated source file', dest='outputfile', default='linphone_jni.cc') + argparser.add_argument('-p --package', type=str, help='the package name for the wrapper', dest='package', default='org.linphone') + argparser.add_argument('-n --name', type=str, help='the name of the genarated source file', dest='name', default='linphone_jni.cc') args = argparser.parse_args() srcdir = args.outputdir + '/src' javadir = args.outputdir + '/java' + package_dirs = args.package.split('.') + for directory in package_dirs: + javadir += '/' + directory try: os.makedirs(srcdir) @@ -406,7 +411,7 @@ def main(): print("Cannot create '{0}' dircetory: {1}".format(javadir, e.strerror)) sys.exit(1) - genwrapper = GenWrapper(srcdir, javadir, args.xmldir) + genwrapper = GenWrapper(srcdir, javadir, args.package, args.xmldir) genwrapper.render_all() if __name__ == '__main__': From d22ca5c3b1f7935907860d720e5fa4755dc837b4 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 10 Oct 2017 11:07:49 +0200 Subject: [PATCH 0375/2215] feat(EventsDb): cleanHistory deal with mask parameter --- src/db/events-db.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 738a9e798..f2cf3f549 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -650,24 +650,26 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} void EventsDb::cleanHistory (const string &peerAddress, FilterMask mask) { L_D(); - // TODO: Deal with mask. - (void)mask; - if (!isConnected()) { lWarning() << "Unable to clean history. Not connected."; return; } + string query; + if (mask == EventsDb::NoFilter || mask & MessageFilter) + query += "SELECT event_id FROM message_event WHERE chat_room_id = (" + " SELECT peer_sip_address_id FROM chat_room WHERE peer_sip_address_id = (" + " SELECT id FROM sip_address WHERE value = :peerAddress" + " )" + ")"; + + if (query.empty()) + return; + L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); - *session << "DELETE FROM event WHERE id IN (" - " SELECT event_id FROM message_event WHERE chat_room_id = (" - " SELECT peer_sip_address_id FROM chat_room WHERE peer_sip_address_id = (" - " SELECT id FROM sip_address WHERE value = :peerAddress" - " )" - " )" - ")"; + *session << "DELETE FROM event WHERE id IN (" + query + ")", soci::use(peerAddress); L_END_LOG_EXCEPTION } From 49ae9548195de966bd31c9e8a796d7261ac8a54f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 11:11:35 +0200 Subject: [PATCH 0376/2215] Added all AccountCreator related enums to main class in java wrapper --- wrappers/java/genwrapper.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 09321a82b..872e78291 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -291,6 +291,15 @@ class GenWrapper(object): self.interfaces = {} self.classes = {} self.enums_list = { + 'AccountCreatorActivationCodeStatus': 'AccountCreator', + 'AccountCreatorDomainStatus': 'AccountCreator', + 'AccountCreatorEmailStatus': 'AccountCreator', + 'AccountCreatorLanguageStatus': 'AccountCreator', + 'AccountCreatorPasswordStatus': 'AccountCreator', + 'AccountCreatorPhoneNumberStatus': 'AccountCreator', + 'AccountCreatorStatus': 'AccountCreator', + 'AccountCreatorTransportStatus': 'AccountCreator', + 'AccountCreatorUsernameStatus': 'AccountCreator', 'AddressFamily': 'CallStats', 'CallDir': 'Call', 'CallState': 'Call', From 086a749511d517a87e6a7eec050a838a66bb9d8e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 11:17:34 +0200 Subject: [PATCH 0377/2215] Fixed enums names in Java wrapper --- wrappers/java/genwrapper.py | 74 ++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 872e78291..45e9d88c7 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -31,6 +31,39 @@ import metadoc ########################################################################## +ENUMS_LIST = { + 'AccountCreatorActivationCodeStatus': 'AccountCreator', + 'AccountCreatorDomainStatus': 'AccountCreator', + 'AccountCreatorEmailStatus': 'AccountCreator', + 'AccountCreatorLanguageStatus': 'AccountCreator', + 'AccountCreatorPasswordStatus': 'AccountCreator', + 'AccountCreatorPhoneNumberStatus': 'AccountCreator', + 'AccountCreatorStatus': 'AccountCreator', + 'AccountCreatorTransportStatus': 'AccountCreator', + 'AccountCreatorUsernameStatus': 'AccountCreator', + 'AddressFamily': 'CallStats', + 'CallDir': 'Call', + 'CallState': 'Call', + 'CallStatus': 'CallLog', + 'ChatMessageState': 'ChatMessage', + 'ConfiguringState': 'Core', + 'CoreLogCollectionUploadState': 'Core', + 'GlobalState': 'Core', + 'FriendListStatus': 'FriendList', + 'IceState': 'CallStats', + 'LimeState': 'Core', + 'MediaDirection': 'Core', + 'MediaEncryption': 'Core', + 'PlayerState': 'Player', + 'RegistrationState': 'Core', + 'SubscribePolicy': 'Friend', + 'TransportType': 'Address', + 'XmlRpcArgType': 'XmlRpcRequest', + 'XmlRpcStatus': 'XmlRpcRequest', +} + +########################################################################## + class JavaTranslator(object): def __init__(self): self.docTranslator = metadoc.SandcastleJavaTranslator() @@ -67,7 +100,12 @@ class JavaTranslator(object): elif type(_type) is AbsApi.EnumType: if native: return 'int' - return _type.desc.name.to_camel_case() + name = _type.desc.name.to_camel_case() + if name in ENUMS_LIST: + className = ENUMS_LIST[name] + if name.startswith(className): + name = className + '.' + name[len(className):] + return name elif type(_type) is AbsApi.BaseType: if _type.name == 'string': return 'String' @@ -290,36 +328,6 @@ class GenWrapper(object): self.enums = {} self.interfaces = {} self.classes = {} - self.enums_list = { - 'AccountCreatorActivationCodeStatus': 'AccountCreator', - 'AccountCreatorDomainStatus': 'AccountCreator', - 'AccountCreatorEmailStatus': 'AccountCreator', - 'AccountCreatorLanguageStatus': 'AccountCreator', - 'AccountCreatorPasswordStatus': 'AccountCreator', - 'AccountCreatorPhoneNumberStatus': 'AccountCreator', - 'AccountCreatorStatus': 'AccountCreator', - 'AccountCreatorTransportStatus': 'AccountCreator', - 'AccountCreatorUsernameStatus': 'AccountCreator', - 'AddressFamily': 'CallStats', - 'CallDir': 'Call', - 'CallState': 'Call', - 'CallStatus': 'CallLog', - 'ChatMessageState': 'ChatMessage', - 'ConfiguringState': 'Core', - 'CoreLogCollectionUploadState': 'Core', - 'GlobalState': 'Core', - 'FriendListStatus': 'FriendList', - 'IceState': 'CallStats', - 'LimeState': 'Core', - 'MediaDirection': 'Core', - 'MediaEncryption': 'Core', - 'PlayerState': 'Player', - 'RegistrationState': 'Core', - 'SubscribePolicy': 'Friend', - 'TransportType': 'Address', - 'XmlRpcArgType': 'XmlRpcRequest', - 'XmlRpcStatus': 'XmlRpcRequest', - } self.enums_to_remove = [] def render_all(self): @@ -332,8 +340,8 @@ class GenWrapper(object): self.render_java_enum(_enum[1]) for name, value in self.enums.iteritems(): - if name in self.enums_list: - className = self.enums_list[name] + if name in ENUMS_LIST: + className = ENUMS_LIST[name] print 'Enum ' + name + ' belongs to class ' + className self.classes[className].add_enum(value) self.enums_to_remove.append(name) From ec8327d1025aa39f1c8a04ec77d6693b5db09d84 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 10 Oct 2017 11:20:50 +0200 Subject: [PATCH 0378/2215] feat(EventsDb): add deleteEvent impl --- src/db/events-db.cpp | 21 +++++++++++++++++---- src/event-log/event-log-p.h | 3 +++ src/event-log/event-log.h | 2 ++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index f2cf3f549..0187d925d 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -28,11 +28,12 @@ #include "abstract/abstract-db-p.h" #include "chat/chat-message.h" -#include "content/content.h" #include "conference/participant.h" +#include "content/content.h" #include "db/provider/db-session-provider.h" #include "event-log/call-event.h" #include "event-log/chat-message-event.h" +#include "event-log/event-log-p.h" #include "logger/logger.h" #include "events-db.h" @@ -501,14 +502,26 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} } bool EventsDb::deleteEvent (const EventLog &eventLog) { + L_D(); + if (!isConnected()) { lWarning() << "Unable to delete event. Not connected."; return false; } - // TODO. - (void)eventLog; - return true; + int &id = const_cast(eventLog).getPrivate()->id; + if (id < 0) + return false; + + L_BEGIN_LOG_EXCEPTION + + soci::session *session = d->dbSession.getBackendSession(); + *session << "DELETE FROM event WHERE id = :id", soci::use(id); + id = -1; + + L_END_LOG_EXCEPTION + + return id == -1; } void EventsDb::cleanEvents (FilterMask mask) { diff --git a/src/event-log/event-log-p.h b/src/event-log/event-log-p.h index 2e1281a6d..17aa3ee1a 100644 --- a/src/event-log/event-log-p.h +++ b/src/event-log/event-log-p.h @@ -28,6 +28,9 @@ LINPHONE_BEGIN_NAMESPACE class EventLogPrivate : public ClonableObjectPrivate { +public: + int id = -1; + private: EventLog::Type type = EventLog::Type::None; diff --git a/src/event-log/event-log.h b/src/event-log/event-log.h index 2524f91ee..357e88f80 100644 --- a/src/event-log/event-log.h +++ b/src/event-log/event-log.h @@ -32,6 +32,8 @@ LINPHONE_BEGIN_NAMESPACE class EventLogPrivate; class LINPHONE_PUBLIC EventLog : public ClonableObject { + friend class EventsDb; + public: L_DECLARE_ENUM(Type, L_ENUM_VALUES_EVENT_LOG_TYPE); From 20cff19fe27b58fda0ce0481586c4d90b711b501 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 11:43:27 +0200 Subject: [PATCH 0379/2215] Improvements on enums and exceptions --- wrappers/java/genwrapper.py | 10 +++++++++- wrappers/java/java_class.mustache | 9 +++++++-- wrappers/java/java_enum.mustache | 6 +++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 45e9d88c7..376c15b25 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -104,7 +104,8 @@ class JavaTranslator(object): if name in ENUMS_LIST: className = ENUMS_LIST[name] if name.startswith(className): - name = className + '.' + name[len(className):] + name = name[len(className):] + name = className + '.' + name return name elif type(_type) is AbsApi.BaseType: if _type.name == 'string': @@ -115,6 +116,10 @@ class JavaTranslator(object): return 'float' elif _type.name == 'size': return 'int' + elif _type.name == 'status': + if native: + return 'int' + return 'void' return _type.name def translate_argument(self, _arg, native=False): @@ -144,6 +149,7 @@ class JavaTranslator(object): methodDict['name'] = _method.name.to_camel_case(lower=True) methodDict['exception'] = self.throws_exception(_method.returnType) + methodDict['enumCast'] = type(_method.returnType) is AbsApi.EnumType methodDict['params'] = '' methodDict['native_params'] = 'long nativePtr' methodDict['static_native_params'] = '' @@ -167,6 +173,8 @@ class JavaTranslator(object): methodDict['native_params_impl'] += 'longArray' else: methodDict['native_params_impl'] += self.translate_argument_name(arg.name) + elif type(arg.type) is AbsApi.EnumType: + methodDict['native_params_impl'] += self.translate_argument_name(arg.name) + '.toInt()' else: methodDict['native_params_impl'] += self.translate_argument_name(arg.name) diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index cd8284ea9..e1ff138d1 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -53,7 +53,7 @@ public interface {{className}} { mValue = value; } - static protected {{className}} fromInt(int value) throws CoreException { + static public {{className}} fromInt(int value) throws CoreException { switch(value) { {{#values}} case {{value}}: return {{name}}; @@ -62,6 +62,10 @@ public interface {{className}} { throw new CoreException("Unhandled enum value " + value + " for {{className}}"); } } + + public int toInt() { + return mValue; + } }; {{/enums}} @@ -142,7 +146,8 @@ class {{classImplName}} implements {{className}} { return classArray; {{/convertOutputClassArrayToLongArray}} {{#classicMethod}} - {{return_keyword}}{{name}}(nativePtr{{native_params_impl}}); + {{#exception}}int exceptionResult = {{/exception}}{{return_keyword}}{{#enumCast}}{{return}}.fromInt({{/enumCast}}{{name}}(nativePtr{{native_params_impl}}){{#enumCast}}){{/enumCast}}; + {{#exception}}if (exceptionResult != 0) throw new CoreException("{{name}} returned value " + exceptionResult){{/exception}} {{/classicMethod}} } diff --git a/wrappers/java/java_enum.mustache b/wrappers/java/java_enum.mustache index a890ff72e..0ea6a5853 100644 --- a/wrappers/java/java_enum.mustache +++ b/wrappers/java/java_enum.mustache @@ -48,7 +48,7 @@ public enum {{className}} { mValue = value; } - static protected {{className}} fromInt(int value) throws CoreException { + static public {{className}} fromInt(int value) throws CoreException { switch(value) { {{#values}} case {{value}}: return {{name}}; @@ -57,4 +57,8 @@ public enum {{className}} { throw new CoreException("Unhandled enum value " + value + " for {{className}}"); } } + + public int toInt() { + return mValue; + } } \ No newline at end of file From 7bee10282c0986bb242b4a34e174ffa4bb46c49c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 11:45:58 +0200 Subject: [PATCH 0380/2215] Fixed access to nativePtr in Java wrapper --- wrappers/java/genwrapper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 376c15b25..1743af6eb 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -164,7 +164,7 @@ class JavaTranslator(object): methodDict['native_params'] += self.translate_argument(arg, True) methodDict['static_native_params'] += self.translate_argument(arg, True) if type(arg.type) is AbsApi.ClassType: - methodDict['native_params_impl'] += '((' + self.translate_type(arg.type) + ')' + self.translate_argument_name(arg.name) + ').nativePtr' + methodDict['native_params_impl'] += '((' + self.translate_type(arg.type) + 'Impl)' + self.translate_argument_name(arg.name) + ').nativePtr' elif type(arg.type) is AbsApi.ListType: if type(arg.type.containedTypeDesc) is AbsApi.ClassType: methodDict['convertInputClassArrayToLongArray'] = True From b3775850884d2785d6d4b2ef6a65c6889f10fde7 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 11:47:32 +0200 Subject: [PATCH 0381/2215] Fixed package name declaration in java wrapper --- wrappers/java/java_class.mustache | 2 +- wrappers/java/java_enum.mustache | 2 +- wrappers/java/java_enum_old.mustache | 2 +- wrappers/java/java_interface.mustache | 2 +- wrappers/java/java_interface_stub.mustache | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index e1ff138d1..67061f96e 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package {{packageName}} +package {{packageName}}; {{#imports}} import {{import}} diff --git a/wrappers/java/java_enum.mustache b/wrappers/java/java_enum.mustache index 0ea6a5853..c2a38237d 100644 --- a/wrappers/java/java_enum.mustache +++ b/wrappers/java/java_enum.mustache @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package {{packageName}} +package {{packageName}}; {{#imports}} import {{import}} diff --git a/wrappers/java/java_enum_old.mustache b/wrappers/java/java_enum_old.mustache index 81f01e1bb..a31a421bf 100644 --- a/wrappers/java/java_enum_old.mustache +++ b/wrappers/java/java_enum_old.mustache @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package {{packageName}} +package {{packageName}}; {{#imports}} import {{import}} diff --git a/wrappers/java/java_interface.mustache b/wrappers/java/java_interface.mustache index 9832f7a8d..4937172f5 100644 --- a/wrappers/java/java_interface.mustache +++ b/wrappers/java/java_interface.mustache @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package {{packageName}} +package {{packageName}}; {{#imports}} import {{import}} diff --git a/wrappers/java/java_interface_stub.mustache b/wrappers/java/java_interface_stub.mustache index afb401674..8cb3384b4 100644 --- a/wrappers/java/java_interface_stub.mustache +++ b/wrappers/java/java_interface_stub.mustache @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package {{packageName}} +package {{packageName}}; {{#imports}} import {{import}} From 6e734e6b0bb4bca73dc1c3050904dfc64d633deb Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 25 Sep 2017 11:01:57 +0200 Subject: [PATCH 0382/2215] Add Gruu implementation completion from master in dev_refactor_cpp branch --- coreapi/bellesip_sal/sal_address_impl.c | 5 ++ coreapi/bellesip_sal/sal_op_impl.c | 4 +- coreapi/linphonecore.c | 19 +++++- src/c-wrapper/internal/c-sal.h | 1 + src/sal/op.cpp | 16 +++-- tester/call_single_tester.c | 84 ++++++++++++++++++------- tester/complex_sip_case_tester.c | 8 ++- tester/flexisip_tester.c | 11 ++++ tester/register_tester.c | 38 ++++++++++- 9 files changed, 146 insertions(+), 40 deletions(-) diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c index a78bf28e6..8ee6b0f8e 100644 --- a/coreapi/bellesip_sal/sal_address_impl.c +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -232,6 +232,11 @@ const char * sal_address_get_uri_param(const SalAddress *addr, const char *name) return belle_sip_parameters_get_parameter(parameters, name); } +void sal_address_remove_uri_param(const SalAddress *addr, const char *name) { + belle_sip_parameters_t* parameters = BELLE_SIP_PARAMETERS(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(addr))); + belle_sip_parameters_remove_parameter(parameters, name); +} + void sal_address_set_header(SalAddress *addr, const char *header_name, const char *header_value){ belle_sip_uri_set_header(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(addr)),header_name, header_value); } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index f3a9bce2e..80f661b54 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -134,6 +134,4 @@ void sal_error_info_set(SalErrorInfo *ei, SalReason reason, const char *protocol ei->full_string=ms_strdup_printf("%s %s",ei->status_string,ei->warnings); else ei->full_string=ms_strdup(ei->status_string); } -} - - +} \ No newline at end of file diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 7dedc0672..3401c9bec 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3454,6 +3454,7 @@ static void linphone_transfer_routes_to_op(bctbx_list_t *routes, SalOp *op){ void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact, LinphoneProxyConfig *proxy){ bctbx_list_t *routes=NULL; const char *identity; + if (proxy){ identity=linphone_proxy_config_get_identity(proxy); if (linphone_proxy_config_get_privacy(proxy)!=LinphonePrivacyDefault) { @@ -3465,12 +3466,24 @@ void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const Linphon routes=make_routes_for_proxy(proxy,dest); linphone_transfer_routes_to_op(routes,op); } - char *addr = linphone_address_as_string(dest); - op->set_to(addr); - ms_free(addr); + + const SalAddress *sal_dest = L_GET_PRIVATE_FROM_C_OBJECT(dest)->getInternalAddress(); + if (sal_address_has_uri_param(sal_dest,"gr")) { + /*in case of gruu destination remove gruu parram from to*/ + SalAddress *dest_copy = sal_address_clone(sal_dest); + sal_address_remove_uri_param(dest_copy,"gr"); + op->set_to_address(dest_copy); + sal_address_unref(dest_copy); + } else { + char *addr = linphone_address_as_string(dest); + op->set_to(addr); + ms_free(addr); + } + op->set_from(identity); op->set_sent_custom_header(headers); op->set_realm(linphone_proxy_config_get_realm(proxy)); + if (with_contact && proxy && proxy->op){ const LinphoneAddress *contact = linphone_proxy_config_get_contact(proxy); SalAddress *salAddress = nullptr; diff --git a/src/c-wrapper/internal/c-sal.h b/src/c-wrapper/internal/c-sal.h index 7c4d5d1a5..6b869f02b 100644 --- a/src/c-wrapper/internal/c-sal.h +++ b/src/c-wrapper/internal/c-sal.h @@ -130,6 +130,7 @@ void sal_address_set_uri_param(SalAddress *addr, const char *name, const char *v void sal_address_set_uri_params(SalAddress *addr, const char *params); bool_t sal_address_has_uri_param(const SalAddress *addr, const char *name); const char * sal_address_get_uri_param(const SalAddress *addr, const char *name); +void sal_address_remove_uri_param(const SalAddress *addr, const char *name); bool_t sal_address_is_ipv6(const SalAddress *addr); bool_t sal_address_is_sip(const SalAddress *addr); void sal_address_set_password(SalAddress *addr, const char *passwd); diff --git a/src/sal/op.cpp b/src/sal/op.cpp index 2b6912043..e9a07b34a 100644 --- a/src/sal/op.cpp +++ b/src/sal/op.cpp @@ -620,6 +620,7 @@ belle_sip_request_t* SalOp::build_request(const char* method) { belle_sip_uri_set_secure(req_uri,is_secure()); to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(to_address),NULL); + belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to_header))), "gr"); /*remove gruu in any case*/ call_id_header = belle_sip_provider_create_call_id(prov); if (get_call_id()) { belle_sip_header_call_id_set_call_id(call_id_header, get_call_id()); @@ -773,12 +774,15 @@ belle_sip_header_contact_t *SalOp::create_contact() { if (this->privacy!=SalPrivacyNone){ belle_sip_uri_set_user(contact_uri,NULL); } - belle_sip_header_contact_set_automatic(contact_header,this->root->auto_contacts); - if (this->root->uuid){ - if (belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance")==0){ - char *instance_id=belle_sip_strdup_printf("\"\"",this->root->uuid); - belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance",instance_id); - belle_sip_free(instance_id); + /*don't touch contact in case of gruu*/ + if (!belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_header))),"gr")) { + belle_sip_header_contact_set_automatic(contact_header,this->root->auto_contacts); + if (this->root->uuid) { + if (belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance")==0){ + char *instance_id=belle_sip_strdup_printf("\"\"",this->root->uuid); + belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance",instance_id); + belle_sip_free(instance_id); + } } } return contact_header; diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index 514c524dc..9d3d108c6 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -1414,7 +1414,7 @@ static void call_declined_with_error(void) { BC_ASSERT_PTR_NOT_NULL(in_call=linphone_core_get_current_call(callee_mgr->lc)); linphone_call_ref(out_call); - BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived,1)); + BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallOutgoingRinging,1)); BC_ASSERT_PTR_NOT_NULL(in_call=linphone_core_get_current_call(callee_mgr->lc)); if (in_call) { linphone_call_ref(in_call); @@ -6215,40 +6215,72 @@ static void recreate_zrtpdb_when_corrupted(void) { } static void simple_call_with_gruu(void) { - LinphoneCoreManager* marie; - LinphoneCoreManager* pauline; - const LinphoneAddress *addr; + const LinphoneAddress *pauline_addr, *marie_addr; LinphoneCall *marie_call = NULL; LinphoneCall *pauline_call = NULL; LinphoneProxyConfig* pauline_cfg; - - marie = linphone_core_manager_new( "marie_rc"); - pauline = linphone_core_manager_new("pauline_tcp_rc"); + LinphoneAddress *contact_addr; + LinphoneCoreManager *marie = ms_new0(LinphoneCoreManager, 1); + linphone_core_manager_init(marie, "marie_rc", NULL); + linphone_core_add_supported_tag(marie->lc,"gruu"); + linphone_core_manager_start(marie,TRUE); + LinphoneCoreManager *pauline = ms_new0(LinphoneCoreManager, 1); + linphone_core_manager_init(pauline, "pauline_tcp_rc", NULL); + linphone_core_add_supported_tag(pauline->lc,"gruu"); + linphone_core_manager_start(pauline,TRUE); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneRegistrationOk, 1)); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneRegistrationOk, 1)); pauline_cfg = linphone_core_get_default_proxy_config(pauline->lc); - addr = linphone_proxy_config_get_contact(pauline_cfg); - BC_ASSERT_PTR_NOT_NULL(addr); - BC_ASSERT_PTR_NOT_NULL(strstr(linphone_address_as_string_uri_only(addr), "gr")); - - marie_call = linphone_core_invite_address(marie->lc, addr); + pauline_addr = linphone_proxy_config_get_contact(pauline_cfg); + + BC_ASSERT_PTR_NOT_NULL(pauline_addr); + BC_ASSERT_TRUE(linphone_address_has_uri_param(pauline_addr,"gr")); + BC_ASSERT_STRING_EQUAL(linphone_address_get_domain(pauline_addr),"sip.example.org"); + + marie_call = linphone_core_invite_address(marie->lc, pauline_addr); BC_ASSERT_PTR_NOT_NULL(marie_call); if(!marie_call) goto end; BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallIncomingReceived, 1)); pauline_call = linphone_core_get_current_call(pauline->lc); BC_ASSERT_PTR_NOT_NULL(pauline_call); if(!pauline_call) goto end; + + marie_addr = linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(marie->lc)); + BC_ASSERT_TRUE(linphone_address_has_uri_param(marie_addr,"gr")); + BC_ASSERT_STRING_EQUAL(linphone_address_get_domain(marie_addr),"sip.example.org"); + contact_addr = linphone_address_new(linphone_call_get_remote_contact(pauline_call)); + if (!BC_ASSERT_TRUE(linphone_address_equal(contact_addr, marie_addr))) { + char* expected = linphone_address_as_string(marie_addr); + char* result = linphone_address_as_string(contact_addr); + ms_error("Expected contact is [%s], result is [%s]",expected,result); + ms_free(expected); + ms_free(result); + } + linphone_address_unref(contact_addr); + linphone_call_accept(pauline_call); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1)); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1)); - - linphone_call_terminate(pauline_call); - - BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1)); - BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); + + contact_addr = linphone_address_new(linphone_call_get_remote_contact(marie_call)); + if (!BC_ASSERT_TRUE(linphone_address_equal(contact_addr, pauline_addr))) { + char* expected = linphone_address_as_string(pauline_addr); + char* result = linphone_address_as_string(contact_addr); + ms_error("Expected contact is [%s], result is [%s]",expected,result); + ms_free(expected); + ms_free(result); + } + linphone_address_unref(contact_addr); + + liblinphone_tester_check_rtcp(marie,pauline); + end_call(marie,pauline); + + //BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1)); + //BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); end: linphone_core_manager_destroy(pauline); @@ -6256,9 +6288,6 @@ end: } static void simple_call_with_gruu_only_one_device_ring(void) { - LinphoneCoreManager* marie; - LinphoneCoreManager* pauline; - LinphoneCoreManager* pauline2; const LinphoneAddress *pauline_addr; const LinphoneAddress *pauline_addr2; LinphoneCall *marie_call = NULL; @@ -6266,9 +6295,18 @@ static void simple_call_with_gruu_only_one_device_ring(void) { LinphoneProxyConfig* pauline_cfg; LinphoneProxyConfig* pauline_cfg2; - marie = linphone_core_manager_new( "marie_rc"); - pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); - pauline2 = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCoreManager *marie = ms_new0(LinphoneCoreManager, 1); + linphone_core_manager_init(marie, "marie_rc", NULL); + linphone_core_add_supported_tag(marie->lc,"gruu"); + linphone_core_manager_start(marie,TRUE); + LinphoneCoreManager *pauline = ms_new0(LinphoneCoreManager, 1); + linphone_core_manager_init(pauline, transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc", NULL); + linphone_core_add_supported_tag(pauline->lc,"gruu"); + linphone_core_manager_start(pauline,TRUE); + LinphoneCoreManager *pauline2 = ms_new0(LinphoneCoreManager, 1); + linphone_core_manager_init(pauline2, transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc", NULL); + linphone_core_add_supported_tag(pauline2->lc,"gruu"); + linphone_core_manager_start(pauline2,TRUE); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneRegistrationOk, 1)); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneRegistrationOk, 1)); diff --git a/tester/complex_sip_case_tester.c b/tester/complex_sip_case_tester.c index a0a9fe1e5..eacf21aba 100644 --- a/tester/complex_sip_case_tester.c +++ b/tester/complex_sip_case_tester.c @@ -140,9 +140,11 @@ static void sip_update_within_icoming_reinvite_with_no_sdp(void) { if (sipp_out) { BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1)); - linphone_call_accept(linphone_core_get_current_call(mgr->lc)); - BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 2)); - BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1)); + if (linphone_core_get_current_call(mgr->lc)) { + linphone_call_accept(linphone_core_get_current_call(mgr->lc)); + BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 2)); + BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1)); + } pclose(sipp_out); } linphone_core_manager_destroy(mgr); diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c index 07c9d14d8..9c46c2942 100644 --- a/tester/flexisip_tester.c +++ b/tester/flexisip_tester.c @@ -1205,6 +1205,17 @@ static void redis_publish_subscribe(void) { marie2 = linphone_core_manager_new("marie2_rc"); BC_ASSERT_TRUE(wait_for_until(marie2->lc, NULL, &marie2->stat.number_of_LinphoneCallIncomingReceived, 1, 3000)); + linphone_call_accept(linphone_core_get_current_call(marie2->lc)); + BC_ASSERT_TRUE(wait_for_until(marie2->lc, pauline->lc, &marie2->stat.number_of_LinphoneCallStreamsRunning, 1, 3000)); + BC_ASSERT_TRUE(wait_for_until(marie2->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1, 3000)); + + liblinphone_tester_check_rtcp(marie2, pauline); + + linphone_call_terminate(linphone_core_get_current_call(marie2->lc)); + + BC_ASSERT_TRUE(wait_for_until(marie2->lc, pauline->lc, &marie2->stat.number_of_LinphoneCallEnd, 1, 3000)); + BC_ASSERT_TRUE(wait_for_until(marie2->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1, 3000)); + linphone_address_unref(marie_identity); linphone_core_manager_destroy(pauline); linphone_core_manager_destroy(marie2); diff --git a/tester/register_tester.c b/tester/register_tester.c index e3b750480..eeeec13ec 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -1186,7 +1186,10 @@ static void tls_auth_info_client_cert_cb_2(void) { } static void register_get_gruu(void) { - LinphoneCoreManager *marie=linphone_core_manager_new("marie_rc"); + LinphoneCoreManager *marie = ms_new0(LinphoneCoreManager, 1); + linphone_core_manager_init(marie, "marie_rc", NULL); + linphone_core_add_supported_tag(marie->lc,"gruu"); + linphone_core_manager_start(marie,TRUE); LinphoneProxyConfig *cfg=linphone_core_get_default_proxy_config(marie->lc); if(cfg) { const LinphoneAddress *addr = linphone_proxy_config_get_contact(cfg); @@ -1196,6 +1199,36 @@ static void register_get_gruu(void) { linphone_core_manager_destroy(marie); } +static void multi_devices_register_with_gruu(void) { + LinphoneCoreManager *marie = ms_new0(LinphoneCoreManager, 1); + linphone_core_manager_init(marie, "marie_rc", NULL); + linphone_core_add_supported_tag(marie->lc,"gruu"); + linphone_core_manager_start(marie,TRUE); + LinphoneProxyConfig *cfg=linphone_core_get_default_proxy_config(marie->lc); + + if(cfg) { + const LinphoneAddress *addr = linphone_proxy_config_get_contact(cfg); + BC_ASSERT_PTR_NOT_NULL(addr); + BC_ASSERT_STRING_EQUAL(linphone_address_get_domain(addr),linphone_proxy_config_get_domain(cfg)); + BC_ASSERT_TRUE(linphone_address_has_uri_param(addr,"gr")); + } + + linphone_core_set_network_reachable(marie->lc,FALSE); /*to make sure first instance is not unregistered*/ + linphone_core_manager_destroy(marie); + + marie=linphone_core_manager_new("marie_rc"); + cfg=linphone_core_get_default_proxy_config(marie->lc); + if(cfg) { + const LinphoneAddress *addr = linphone_proxy_config_get_contact(cfg); + BC_ASSERT_PTR_NOT_NULL(addr); + BC_ASSERT_STRING_EQUAL(linphone_address_get_domain(addr),linphone_proxy_config_get_domain(cfg)); + BC_ASSERT_TRUE(linphone_address_has_uri_param(addr,"gr")); + } + + linphone_core_manager_destroy(marie); +} + + test_t register_tests[] = { TEST_NO_TAG("Simple register", simple_register), TEST_NO_TAG("Simple register unregister", simple_unregister), @@ -1241,7 +1274,8 @@ test_t register_tests[] = { TEST_NO_TAG("AuthInfo TLS client certificate authentication using API 2", tls_auth_info_client_cert_api_path), TEST_NO_TAG("AuthInfo TLS client certificate authentication in callback", tls_auth_info_client_cert_cb), TEST_NO_TAG("AuthInfo TLS client certificate authentication in callback 2", tls_auth_info_client_cert_cb_2), - TEST_NO_TAG("Register get GRUU", register_get_gruu) + TEST_NO_TAG("Register get GRUU", register_get_gruu), + TEST_NO_TAG("Register get GRUU for multi device", multi_devices_register_with_gruu) }; test_suite_t register_test_suite = {"Register", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each, From 7099bab3ebe0face9558ceac4176516139448299 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 12:05:22 +0200 Subject: [PATCH 0383/2215] Fixed java wrapper time type --- wrappers/java/genwrapper.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 1743af6eb..1d9829d3b 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -116,6 +116,8 @@ class JavaTranslator(object): return 'float' elif _type.name == 'size': return 'int' + elif _type.name == 'time': + return 'long' elif _type.name == 'status': if native: return 'int' From f871550888579063ab2248b22ee0deede06aee90 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 10 Oct 2017 12:05:10 +0200 Subject: [PATCH 0384/2215] Fix some bugs in group chat handling. --- coreapi/chat.c | 1 - coreapi/linphonecore.c | 10 +++++++--- coreapi/private.h | 2 +- src/chat/client-group-chat-room.cpp | 3 ++- src/conference/conference.cpp | 2 +- src/conference/local-conference-event-handler.cpp | 10 ++++++++-- src/conference/params/call-session-params.h | 3 +-- src/conference/session/call-session-listener.h | 2 ++ src/conference/session/call-session.cpp | 6 ++++-- 9 files changed, 26 insertions(+), 13 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index b453892eb..daf9b7bb6 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -138,7 +138,6 @@ LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, LinphoneChatRoom *_linphone_core_join_client_group_chat_room (LinphoneCore *lc, const LinphonePrivate::Address &addr) { LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); - _linphone_core_add_group_chat_room(lc, L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getConferenceAddress()->asStringUriOnly().c_str(), linphone_chat_room_ref(cr)); lc->chatrooms = bctbx_list_append(lc->chatrooms, cr); return cr; } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 3401c9bec..d9b99e31d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -7106,14 +7106,18 @@ bool_t _linphone_core_has_group_chat_room(const LinphoneCore *lc, const char *id return result; } -void _linphone_core_add_group_chat_room(LinphoneCore *lc, const char *id, LinphoneChatRoom *cr) { - bctbx_pair_t *pair = reinterpret_cast(bctbx_pair_cchar_new(id, linphone_chat_room_ref(cr))); +void _linphone_core_add_group_chat_room(LinphoneCore *lc, const LinphonePrivate::Address &addr, LinphoneChatRoom *cr) { + Address cleanedAddr = addr; + cleanedAddr.setPort(0); + bctbx_pair_t *pair = reinterpret_cast(bctbx_pair_cchar_new(cleanedAddr.asStringUriOnly().c_str(), linphone_chat_room_ref(cr))); bctbx_map_cchar_insert_and_delete(lc->group_chat_rooms, pair); } LinphoneChatRoom *_linphone_core_find_group_chat_room(const LinphoneCore *lc, const char *id) { LinphoneChatRoom *result = nullptr; - bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, id); + Address cleanedAddr(id); + cleanedAddr.setPort(0); + bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, cleanedAddr.asStringUriOnly().c_str()); bctbx_iterator_t *endit = bctbx_map_cchar_end(lc->group_chat_rooms); if (!bctbx_iterator_cchar_equals(it, endit)) result = reinterpret_cast(bctbx_pair_cchar_get_second(bctbx_iterator_cchar_get_pair(it))); diff --git a/coreapi/private.h b/coreapi/private.h index 74a551576..ca1d8cf20 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -450,7 +450,7 @@ extern LinphonePrivate::Sal::Callbacks linphone_sal_callbacks; LINPHONE_PUBLIC bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); LINPHONE_PUBLIC bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc); bool_t _linphone_core_has_group_chat_room(const LinphoneCore *lc, const char *id); -void _linphone_core_add_group_chat_room(LinphoneCore *lc, const char *id, LinphoneChatRoom *cr); +void _linphone_core_add_group_chat_room(LinphoneCore *lc, const LinphonePrivate::Address &addr, LinphoneChatRoom *cr); void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description); diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index b5637602b..f261659bd 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -20,6 +20,7 @@ #include "address/address-p.h" #include "client-group-chat-room-p.h" #include "c-wrapper/c-wrapper.h" +#include "conference/params/call-session-params-p.h" #include "conference/session/call-session-p.h" #include "conference/participant-p.h" #include "content/content.h" @@ -174,7 +175,7 @@ void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { L_D(); conferenceAddress = addr; d->setState(ChatRoom::State::Created); - _linphone_core_add_group_chat_room(d->core, addr.asStringUriOnly().c_str(), L_GET_C_BACK_PTR(this)); + _linphone_core_add_group_chat_room(d->core, addr, L_GET_C_BACK_PTR(this)); } void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 2b271e2d1..9673f2658 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -174,7 +174,7 @@ shared_ptr Conference::findParticipant (const Address &addr) const for (const auto &participant : participants) { Address participantAddr = participant->getAddress(); participantAddr.setPort(0); - if (testedAddr.equal(participantAddr)) + if (testedAddr.weakEqual(participantAddr)) return participant; } return nullptr; diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 22b532b75..1476728ab 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -59,9 +59,13 @@ void LocalConferenceEventHandlerPrivate::notifyFullState (const string ¬ify, } void LocalConferenceEventHandlerPrivate::notifyAllExcept (const string ¬ify, const Address &addr) { + Address cleanedAddr(addr); + cleanedAddr.setPort(0); for (const auto &participant : conf->getParticipants()) { - if (participant->getPrivate()->isSubscribedToConferenceEventPackage() && (addr != participant->getAddress())) - sendNotify(notify, addr); + Address cleanedParticipantAddr(participant->getAddress()); + cleanedParticipantAddr.setPort(0); + if (participant->getPrivate()->isSubscribedToConferenceEventPackage() && !(cleanedAddr.weakEqual(cleanedParticipantAddr))) + sendNotify(notify, participant->getAddress()); } } @@ -157,6 +161,8 @@ string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged () { void LocalConferenceEventHandlerPrivate::sendNotify (const string ¬ify, const Address &addr) { LinphoneAddress *cAddr = linphone_address_new(addr.asString().c_str()); LinphoneEvent *lev = linphone_core_create_notify(core, cAddr, "conference"); + // Fix the From header to put the chat room URI + lev->op->set_from(this->conf->getConferenceAddress()->asString().c_str()); linphone_address_unref(cAddr); doNotify(notify, lev); } diff --git a/src/conference/params/call-session-params.h b/src/conference/params/call-session-params.h index 5f9c8a7fc..70ed155aa 100644 --- a/src/conference/params/call-session-params.h +++ b/src/conference/params/call-session-params.h @@ -30,13 +30,12 @@ LINPHONE_BEGIN_NAMESPACE -class CallSession; class CallSessionParamsPrivate; -class CallSessionPrivate; class CallSessionParams : public ClonableObject { friend class CallSession; friend class CallSessionPrivate; + friend class ClientGroupChatRoom; public: CallSessionParams (); diff --git a/src/conference/session/call-session-listener.h b/src/conference/session/call-session-listener.h index 8b6d72edf..a0d7e9520 100644 --- a/src/conference/session/call-session-listener.h +++ b/src/conference/session/call-session-listener.h @@ -24,6 +24,8 @@ LINPHONE_BEGIN_NAMESPACE +class CallSession; + class LINPHONE_PUBLIC CallSessionListener { public: virtual ~CallSessionListener() = default; diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 2b806c894..f56b7d84b 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -492,6 +492,7 @@ bool CallSessionPrivate::isUpdateAllowed (LinphoneCallState &nextState) const { case LinphoneCallOutgoingEarlyMedia: nextState = LinphoneCallEarlyUpdating; break; + case LinphoneCallConnected: case LinphoneCallStreamsRunning: case LinphoneCallPausedByRemote: case LinphoneCallUpdatedByRemote: @@ -943,8 +944,9 @@ LinphoneStatus CallSession::update (const CallSessionParams *csp, const string & return -1; if (d->currentParams == csp) lWarning() << "CallSession::update() is given the current params, this is probably not what you intend to do!"; - if (content) - d->op->set_local_body(*content); + if (csp) + d->params = new CallSessionParams(*csp); + d->op->set_local_body(content ? *content : Content()); LinphoneStatus result = d->startUpdate(subject); if (result && (d->state != initialState)) { /* Restore initial state */ From d954d98201681e6041b52ee14a61caf79e181c48 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 10 Oct 2017 12:09:07 +0200 Subject: [PATCH 0385/2215] Fix build when soci is not enabled. --- src/db/events-db.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 0187d925d..0f27f8e61 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -764,7 +764,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return list>(); } - void EventsDb::cleanHistory (const string &) {} + void EventsDb::cleanHistory (const string &, FilterMask) {} bool EventsDb::import (Backend, const string &) { return false; From 2b6753bdafd0cc54a0ec6c5cf2b65bf083fd6393 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 12:51:10 +0200 Subject: [PATCH 0386/2215] Started jni part of java wrapper --- wrappers/java/genwrapper.py | 45 ++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 1d9829d3b..e4cf66589 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -65,7 +65,12 @@ ENUMS_LIST = { ########################################################################## class JavaTranslator(object): - def __init__(self): + def __init__(self, packageName): + package_dirs = packageName.split('.') + self.jni_package = '' + for directory in package_dirs: + self.jni_package += directory + '_' + self.docTranslator = metadoc.SandcastleJavaTranslator() def throws_exception(self, _type): @@ -77,7 +82,7 @@ class JavaTranslator(object): def translate_argument_name(self, _argName): return _argName.to_snake_case() - def translate_type(self, _type, native=False): + def translate_type(self, _type, native=False, jni=False): if type(_type) is AbsApi.ListType: ptrtype = '' if type(_type.containedTypeDesc) is AbsApi.ClassType: @@ -124,8 +129,8 @@ class JavaTranslator(object): return 'void' return _type.name - def translate_argument(self, _arg, native=False): - return '{0} {1}'.format(self.translate_type(_arg.type, native), self.translate_argument_name(_arg.name)) + def translate_argument(self, _arg, native=False, jni=False): + return '{0} {1}'.format(self.translate_type(_arg.type, native, jni), self.translate_argument_name(_arg.name)) def translate_property(self, _property): properties = [] @@ -135,6 +140,14 @@ class JavaTranslator(object): properties.append(self.translate_method(_property.setter)) return properties + def translate_jni_property(self, _property): + properties = [] + if _property.getter is not None: + properties.append(self.translate_jni_method(_property.getter)) + if _property.setter is not None: + properties.append(self.translate_jni_method(_property.setter)) + return properties + def translate_method(self, _method): methodDict = {} @@ -186,10 +199,25 @@ class JavaTranslator(object): return methodDict + def translate_jni_method(self, _method): + methodDict = {} + + methodDict['return'] = self.translate_type(_method.returnType, jni=True) + methodDict['name'] = 'Java_' + self.jni_package + _method.parent.name.to_camel_case() + 'Impl_' + _method.name.to_camel_case(lower=True) + + methodDict['params'] = 'JNIEnv *env, jobject thiz' + for arg in _method.args: + if arg is not _method.args[0]: + methodDict['params'] += ', ' + methodDict['params'] += self.translate_argument(arg, jni=True) + + return methodDict + def translate_class(self, _class): classDict = { 'methods' : [], 'staticMethods' : [], + 'jniMethods' : [], } classDict['isLinphoneFactory'] = _class.name.to_camel_case() == "Factory" @@ -198,20 +226,25 @@ class JavaTranslator(object): for _property in _class.properties: try: classDict['methods'] += self.translate_property(_property) + classDict['jniMethods'] += self.translate_jni_property(_property) except AbsApi.Error as e: print('error while translating {0} property: {1}'.format(_property.name.to_snake_case(), e.args[0])) for method in _class.instanceMethods: try: methodDict = self.translate_method(method) + jniMethodDict = self.translate_jni_method(method) classDict['methods'].append(methodDict) + classDict['jniMethods'].append(jniMethodDict) except AbsApi.Error as e: print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0])) for method in _class.classMethods: try: methodDict = self.translate_method(method) + jniMethodDict = self.translate_jni_method(method) classDict['staticMethods'].append(methodDict) + classDict['jniMethods'].append(jniMethodDict) except AbsApi.Error as e: print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0])) @@ -301,8 +334,8 @@ class JavaClass(object): self.imports = [] self.methods = self._class['methods'] self.staticMethods = self._class['staticMethods'] + self.jniMethods = self._class['jniMethods'] self.doc = self._class['doc'] - self.jniMethods = [] self.enums = [] def add_enum(self, enum): @@ -331,7 +364,7 @@ class GenWrapper(object): self.parser = AbsApi.CParser(project) self.parser.parse_all() - self.translator = JavaTranslator() + self.translator = JavaTranslator(package) self.renderer = pystache.Renderer() self.jni = Jni() From 5a009ff9d53585556fe70792e1410bee72347e42 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 13:05:31 +0200 Subject: [PATCH 0387/2215] Java wrapper native will return objects, cast it --- wrappers/java/genwrapper.py | 19 ++++++++++++++++++- wrappers/java/java_class.mustache | 2 +- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index e4cf66589..ae3e028c9 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -100,11 +100,15 @@ class JavaTranslator(object): elif type(_type) is AbsApi.ClassType: if native: - return 'long' + return 'Object' + elif jni: + return 'jobject' return _type.desc.name.to_camel_case() elif type(_type) is AbsApi.EnumType: if native: return 'int' + elif jni: + return 'jint' name = _type.desc.name.to_camel_case() if name in ENUMS_LIST: className = ENUMS_LIST[name] @@ -114,16 +118,28 @@ class JavaTranslator(object): return name elif type(_type) is AbsApi.BaseType: if _type.name == 'string': + if jni: + return 'jstring' return 'String' elif _type.name == 'integer': + if jni: + return 'jint' return 'int' elif _type.name == 'floatant': + if jni: + return 'jfloat' return 'float' elif _type.name == 'size': + if jni: + return 'jint' return 'int' elif _type.name == 'time': + if jni: + return 'jlong' return 'long' elif _type.name == 'status': + if jni: + return 'jint' if native: return 'int' return 'void' @@ -165,6 +181,7 @@ class JavaTranslator(object): methodDict['exception'] = self.throws_exception(_method.returnType) methodDict['enumCast'] = type(_method.returnType) is AbsApi.EnumType + methodDict['classCast'] = type(_method.returnType) is AbsApi.ClassType methodDict['params'] = '' methodDict['native_params'] = 'long nativePtr' methodDict['static_native_params'] = '' diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 67061f96e..b386032b6 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -146,7 +146,7 @@ class {{classImplName}} implements {{className}} { return classArray; {{/convertOutputClassArrayToLongArray}} {{#classicMethod}} - {{#exception}}int exceptionResult = {{/exception}}{{return_keyword}}{{#enumCast}}{{return}}.fromInt({{/enumCast}}{{name}}(nativePtr{{native_params_impl}}){{#enumCast}}){{/enumCast}}; + {{#exception}}int exceptionResult = {{/exception}}{{return_keyword}}{{#enumCast}}{{return}}.fromInt({{/enumCast}}{{#classCast}}({{return}}){{/classCast}}{{name}}(nativePtr{{native_params_impl}}){{#enumCast}}){{/enumCast}}; {{#exception}}if (exceptionResult != 0) throw new CoreException("{{name}} returned value " + exceptionResult){{/exception}} {{/classicMethod}} } From fac07d9429899899bd03bf5cccbb13c76a70fb0a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 13:14:46 +0200 Subject: [PATCH 0388/2215] Improved way to get array of objects in java wrapper --- wrappers/java/genwrapper.py | 12 ++++-------- wrappers/java/java_class.mustache | 10 ---------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index ae3e028c9..73ea44653 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -84,6 +84,8 @@ class JavaTranslator(object): def translate_type(self, _type, native=False, jni=False): if type(_type) is AbsApi.ListType: + if jni: + return 'jobjectArray' ptrtype = '' if type(_type.containedTypeDesc) is AbsApi.ClassType: ptrtype = self.translate_type(_type.containedTypeDesc, native) @@ -99,9 +101,7 @@ class JavaTranslator(object): return ptrtype + '[]' elif type(_type) is AbsApi.ClassType: - if native: - return 'Object' - elif jni: + if jni: return 'jobject' return _type.desc.name.to_camel_case() elif type(_type) is AbsApi.EnumType: @@ -172,10 +172,6 @@ class JavaTranslator(object): methodDict['return_keyword'] = '' if methodDict['return'] == 'void' else 'return ' methodDict['convertInputClassArrayToLongArray'] = False - methodDict['convertOutputClassArrayToLongArray'] = type(_method.returnType) is AbsApi.ListType and type(_method.returnType.containedTypeDesc) is AbsApi.ClassType - if methodDict['convertOutputClassArrayToLongArray']: - methodDict['native_params_impl_list_param_name'] = 'classArray' - methodDict['native_params_impl_list_param_type'] = self.translate_type(_method.returnType.containedTypeDesc) methodDict['name'] = _method.name.to_camel_case(lower=True) methodDict['exception'] = self.throws_exception(_method.returnType) @@ -210,7 +206,7 @@ class JavaTranslator(object): else: methodDict['native_params_impl'] += self.translate_argument_name(arg.name) - methodDict['classicMethod'] = not methodDict['convertInputClassArrayToLongArray'] and not methodDict['convertOutputClassArrayToLongArray'] + methodDict['classicMethod'] = not methodDict['convertInputClassArrayToLongArray'] methodDict['deprecated'] = _method.deprecated methodDict['doc'] = self.docTranslator.translate(_method.briefDescription) if _method.briefDescription is not None else None diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index b386032b6..3eb9b7734 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -135,16 +135,6 @@ class {{classImplName}} implements {{className}} { } {{name}}(nativePtr{{native_params_impl}}); {{/convertInputClassArrayToLongArray}} - {{#convertOutputClassArrayToLongArray}} - long[] longArray = {{name}}(nativePtr{{native_params_impl}}); - if (longArray == null) return null; - - {{native_params_impl_list_param_type}}[] classArray = new {{native_params_impl_list_param_type}}[longArray.length]; - for (int i=0; i < longArray.length; i++) { - classArray[i] = new {{native_params_impl_list_param_type}}Impl(longArray[i]); - } - return classArray; - {{/convertOutputClassArrayToLongArray}} {{#classicMethod}} {{#exception}}int exceptionResult = {{/exception}}{{return_keyword}}{{#enumCast}}{{return}}.fromInt({{/enumCast}}{{#classCast}}({{return}}){{/classCast}}{{name}}(nativePtr{{native_params_impl}}){{#enumCast}}){{/enumCast}}; {{#exception}}if (exceptionResult != 0) throw new CoreException("{{name}} returned value " + exceptionResult){{/exception}} From 036cd8a5d81c71276726f8e4a928ebd568a22860 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 13:22:14 +0200 Subject: [PATCH 0389/2215] Always use objects in Java wrapper, JNI will take care of handling pointers --- wrappers/java/genwrapper.py | 4 +--- wrappers/java/jni.mustache | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 73ea44653..5614d5a01 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -191,9 +191,7 @@ class JavaTranslator(object): methodDict['params'] += self.translate_argument(arg) methodDict['native_params'] += self.translate_argument(arg, True) methodDict['static_native_params'] += self.translate_argument(arg, True) - if type(arg.type) is AbsApi.ClassType: - methodDict['native_params_impl'] += '((' + self.translate_type(arg.type) + 'Impl)' + self.translate_argument_name(arg.name) + ').nativePtr' - elif type(arg.type) is AbsApi.ListType: + if type(arg.type) is AbsApi.ListType: if type(arg.type.containedTypeDesc) is AbsApi.ClassType: methodDict['convertInputClassArrayToLongArray'] = True methodDict['native_params_impl_list_param_name'] = self.translate_argument_name(arg.name) diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index 7c5b17133..7427e5b78 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -35,4 +35,18 @@ static const char* GetStringUTFChars(JNIEnv* env, jstring string) { static void ReleaseStringUTFChars(JNIEnv* env, jstring string, const char *cstring) { if (string) env->ReleaseStringUTFChars(string, cstring); +} + +static jlong GetObjectNativePtr(JNIEnv *env, jobject object) { + jclass objClass = env->GetObjectClass(object); + jfieldID nativePtrId = env->GetFieldID(objClass, "nativePtr", "J"); + jlong nativePtr = env->GetLongField(object, nativePtrId); + return nativePtr; +} + +static jlong SetObjectNativePtr(JNIEnv *env, jobject object, jlong ptr) { + jclass objClass = env->GetObjectClass(object); + jfieldID nativePtrId = env->GetFieldID(objClass, "nativePtr", "J"); + env->SetLongField(object, nativePtrId, ptr); + return ptr; } \ No newline at end of file From 12df1381bcb4b3aec5b4e08198e7fbfd993ded1d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 13:24:46 +0200 Subject: [PATCH 0390/2215] Simplified java wrapper --- wrappers/java/genwrapper.py | 11 +---------- wrappers/java/java_class.mustache | 9 --------- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 5614d5a01..6e043820d 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -191,20 +191,11 @@ class JavaTranslator(object): methodDict['params'] += self.translate_argument(arg) methodDict['native_params'] += self.translate_argument(arg, True) methodDict['static_native_params'] += self.translate_argument(arg, True) - if type(arg.type) is AbsApi.ListType: - if type(arg.type.containedTypeDesc) is AbsApi.ClassType: - methodDict['convertInputClassArrayToLongArray'] = True - methodDict['native_params_impl_list_param_name'] = self.translate_argument_name(arg.name) - methodDict['native_params_impl_list_param_type'] = self.translate_type(arg.type.containedTypeDesc) + 'Impl' - methodDict['native_params_impl'] += 'longArray' - else: - methodDict['native_params_impl'] += self.translate_argument_name(arg.name) - elif type(arg.type) is AbsApi.EnumType: + if type(arg.type) is AbsApi.EnumType: methodDict['native_params_impl'] += self.translate_argument_name(arg.name) + '.toInt()' else: methodDict['native_params_impl'] += self.translate_argument_name(arg.name) - methodDict['classicMethod'] = not methodDict['convertInputClassArrayToLongArray'] methodDict['deprecated'] = _method.deprecated methodDict['doc'] = self.docTranslator.translate(_method.briefDescription) if _method.briefDescription is not None else None diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 3eb9b7734..7cd445cfa 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -128,17 +128,8 @@ class {{classImplName}} implements {{className}} { {{#methods}} private native {{return_native}} {{name}}({{native_params}}); public {{return}} {{name}}({{params}}) {{#exception}}throws CoreException{{/exception}} { - {{#convertInputClassArrayToLongArray}} - long[] longArray = new long[{{native_params_impl_list_param_name}}.length]; - for (int i=0; i < {{native_params_impl_list_param_name}}.length; i++) { - longArray[i] = (({{native_params_impl_list_param_type}}){{native_params_impl_list_param_name}}[i]).nativePtr; - } - {{name}}(nativePtr{{native_params_impl}}); - {{/convertInputClassArrayToLongArray}} - {{#classicMethod}} {{#exception}}int exceptionResult = {{/exception}}{{return_keyword}}{{#enumCast}}{{return}}.fromInt({{/enumCast}}{{#classCast}}({{return}}){{/classCast}}{{name}}(nativePtr{{native_params_impl}}){{#enumCast}}){{/enumCast}}; {{#exception}}if (exceptionResult != 0) throw new CoreException("{{name}} returned value " + exceptionResult){{/exception}} - {{/classicMethod}} } {{/methods}} From 13321b9d69a356d98f3ad71f2dea07970fed4898 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 13:26:30 +0200 Subject: [PATCH 0391/2215] Java wrapper deprecated annotation starts with a cap --- wrappers/java/java_class.mustache | 2 +- wrappers/java/java_interface.mustache | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 7cd445cfa..b86a8b06f 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -80,7 +80,7 @@ public interface {{className}} { {{/lines}} */ {{/doc}} - {{#deprecated}}@deprecated + {{#deprecated}}@Deprecated {{/deprecated}}public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}}; {{/methods}} diff --git a/wrappers/java/java_interface.mustache b/wrappers/java/java_interface.mustache index 4937172f5..22e964fba 100644 --- a/wrappers/java/java_interface.mustache +++ b/wrappers/java/java_interface.mustache @@ -39,7 +39,7 @@ public interface {{className}} { {{/lines}} */ {{/doc}} - {{#deprecated}}@deprecated + {{#deprecated}}@Deprecated {{/deprecated}}public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}}; {{/methods}} From ef4ad613b6e0404be2fde6f74d8f634c491befeb Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 10 Oct 2017 13:27:34 +0200 Subject: [PATCH 0392/2215] feat(Content): supports app data --- include/linphone/utils/general.h | 14 +++++++ src/CMakeLists.txt | 20 +++++---- src/content/content.cpp | 2 +- src/content/content.h | 5 ++- src/db/events-db.cpp | 2 +- src/event-log/event-log-p.h | 2 +- src/object/app-data-container.cpp | 68 +++++++++++++++++++++++++++++++ src/object/app-data-container.h | 53 ++++++++++++++++++++++++ 8 files changed, 152 insertions(+), 14 deletions(-) create mode 100644 src/object/app-data-container.cpp create mode 100644 src/object/app-data-container.h diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index b11044e92..495d72ee1 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -93,14 +93,28 @@ class ObjectPrivate; friend class CLASS ## Private; \ friend class Wrapper; +#define L_INTERNAL_DECLARE_PRIVATE_T(CLASS, PARENT_TYPE) \ + inline CLASS ## Private *getPrivate() { \ + return reinterpret_cast(PARENT_TYPE::mPrivate); \ + } \ + inline const CLASS ## Private *getPrivate() const { \ + return reinterpret_cast(PARENT_TYPE::mPrivate); \ + } \ + friend class CLASS ## Private; \ + friend class Wrapper; + // Allows access to private internal data. // Gives a control to C Wrapper. #ifndef LINPHONE_TESTER #define L_DECLARE_PRIVATE(CLASS) L_INTERNAL_DECLARE_PRIVATE(CLASS) + #define L_DECLARE_PRIVATE_T(CLASS, PARENT_TYPE) L_INTERNAL_DECLARE_PRIVATE_T(CLASS, PARENT_TYPE) #else #define L_DECLARE_PRIVATE(CLASS) \ L_INTERNAL_DECLARE_PRIVATE(CLASS) \ friend class Tester; + #define L_DECLARE_PRIVATE_T(CLASS, PARENT_TYPE) \ + L_INTERNAL_DECLARE_PRIVATE_T(CLASS, PARENT_TYPE) \ + friend class Tester; #endif template diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 080df4c96..8bf3bbf28 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,8 +24,8 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES address/address-p.h address/address.h c-wrapper/c-wrapper.h - c-wrapper/internal/c-tools.h c-wrapper/internal/c-sal.h + c-wrapper/internal/c-tools.h call/call-listener.h call/call-p.h call/call.h @@ -55,18 +55,18 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES chat/real-time-text-chat-room.h conference/conference-listener.h conference/conference.h - conference/local-conference.h conference/local-conference-event-handler-p.h conference/local-conference-event-handler.h + conference/local-conference.h conference/params/call-session-params-p.h conference/params/call-session-params.h conference/params/media-session-params-p.h conference/params/media-session-params.h conference/participant-p.h conference/participant.h - conference/remote-conference.h conference/remote-conference-event-handler-p.h conference/remote-conference-event-handler.h + conference/remote-conference.h conference/session/call-session-listener.h conference/session/call-session-p.h conference/session/call-session.h @@ -93,6 +93,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES logger/logger.h nat/ice-agent.h nat/stun-client.h + object/app-data-container.h object/clonable-object-p.h object/clonable-object.h object/object-p.h @@ -110,14 +111,14 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES set(LINPHONE_CXX_OBJECTS_SOURCE_FILES address/address.cpp c-wrapper/api/c-address.cpp - c-wrapper/api/c-call.cpp c-wrapper/api/c-call-cbs.cpp c-wrapper/api/c-call-params.cpp c-wrapper/api/c-call-stats.cpp - c-wrapper/api/c-chat-message.cpp + c-wrapper/api/c-call.cpp c-wrapper/api/c-chat-message-cbs.cpp - c-wrapper/api/c-chat-room.cpp + c-wrapper/api/c-chat-message.cpp c-wrapper/api/c-chat-room-cbs.cpp + c-wrapper/api/c-chat-room.cpp c-wrapper/api/c-event-log.cpp c-wrapper/api/c-participant.cpp c-wrapper/internal/c-sal.cpp @@ -139,13 +140,13 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES chat/modifier/multipart-chat-message-modifier.cpp chat/real-time-text-chat-room.cpp conference/conference.cpp - conference/local-conference.cpp conference/local-conference-event-handler.cpp + conference/local-conference.cpp conference/params/call-session-params.cpp conference/params/media-session-params.cpp conference/participant.cpp - conference/remote-conference.cpp conference/remote-conference-event-handler.cpp + conference/remote-conference.cpp conference/session/call-session.cpp conference/session/media-session.cpp content/content-type.cpp @@ -164,6 +165,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES logger/logger.cpp nat/ice-agent.cpp nat/stun-client.cpp + object/app-data-container.cpp object/clonable-object.cpp object/object.cpp object/property-container.cpp @@ -172,9 +174,9 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES sal/message-op.cpp sal/op.cpp sal/presence-op.cpp + sal/refer-op.cpp sal/register-op.cpp sal/sal.cpp - sal/refer-op.cpp utils/general.cpp utils/payload-type-handler.cpp utils/utils.cpp diff --git a/src/content/content.cpp b/src/content/content.cpp index b9581de73..e8d12d176 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -39,7 +39,7 @@ public: Content::Content () : ClonableObject(*new ContentPrivate) {} -Content::Content (const Content &src) : ClonableObject(*new ContentPrivate) { +Content::Content (const Content &src) : ClonableObject(*new ContentPrivate), AppDataContainer() { L_D(); d->body = src.getBody(); d->contentType = src.getContentType(); diff --git a/src/content/content.h b/src/content/content.h index 57f78787f..1e547ddf1 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -23,6 +23,7 @@ #include #include "content-type.h" +#include "object/app-data-container.h" #include "object/clonable-object.h" // ============================================================================= @@ -31,7 +32,7 @@ LINPHONE_BEGIN_NAMESPACE class ContentPrivate; -class LINPHONE_PUBLIC Content : public ClonableObject { +class LINPHONE_PUBLIC Content : public ClonableObject, public AppDataContainer { public: Content (); Content (const Content &src); @@ -63,7 +64,7 @@ public: bool isEmpty () const; private: - L_DECLARE_PRIVATE(Content); + L_DECLARE_PRIVATE_T(Content, ClonableObject); }; LINPHONE_END_NAMESPACE diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 0f27f8e61..16af86e41 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -509,7 +509,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return false; } - int &id = const_cast(eventLog).getPrivate()->id; + long &id = const_cast(eventLog).getPrivate()->id; if (id < 0) return false; diff --git a/src/event-log/event-log-p.h b/src/event-log/event-log-p.h index 17aa3ee1a..7e7a7788b 100644 --- a/src/event-log/event-log-p.h +++ b/src/event-log/event-log-p.h @@ -29,7 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class EventLogPrivate : public ClonableObjectPrivate { public: - int id = -1; + long id = -1; private: EventLog::Type type = EventLog::Type::None; diff --git a/src/object/app-data-container.cpp b/src/object/app-data-container.cpp new file mode 100644 index 000000000..37f33801b --- /dev/null +++ b/src/object/app-data-container.cpp @@ -0,0 +1,68 @@ +/* + * app-data-container.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include "app-data-container.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +class AppDataContainerPrivate { +public: + unordered_map appData; +}; + +// ----------------------------------------------------------------------------- + +AppDataContainer::AppDataContainer () : mPrivate(new AppDataContainerPrivate) {} + +// Empty copy constructor. Don't change this pattern. +// AppDataContainer is an Entity component, not a simple structure. +// An Entity is UNIQUE. +AppDataContainer::AppDataContainer (const AppDataContainer &) : mPrivate(new AppDataContainerPrivate) {} + +AppDataContainer::~AppDataContainer () { + delete mPrivate; +} + +AppDataContainer &AppDataContainer::operator= (const AppDataContainer &) { + return *this; +} + +string AppDataContainer::getAppData (const string &name) const { + L_D(); + auto it = d->appData.find(name); + return it == d->appData.cend() ? string() : it->second; +} + +void AppDataContainer::setAppData (const string &name, const string &appData) { + L_D(); + d->appData[name] = appData; +} + +void AppDataContainer::setAppData (const string &name, string &&appData) { + L_D(); + d->appData[name] = move(appData); +} + +LINPHONE_END_NAMESPACE diff --git a/src/object/app-data-container.h b/src/object/app-data-container.h new file mode 100644 index 000000000..274e5acbd --- /dev/null +++ b/src/object/app-data-container.h @@ -0,0 +1,53 @@ +/* + * app-data-container.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _APP_DATA_CONTAINER_H_ +#define _APP_DATA_CONTAINER_H_ + +#include + +#include "linphone/utils/general.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class AppDataContainerPrivate; + +class LINPHONE_PUBLIC AppDataContainer { +public: + AppDataContainer (); + AppDataContainer (const AppDataContainer &src); + virtual ~AppDataContainer (); + + AppDataContainer &operator= (const AppDataContainer &src); + + std::string getAppData (const std::string &name) const; + void setAppData (const std::string &name, const std::string &appData); + void setAppData (const std::string &name, std::string &&appData); + +private: + AppDataContainerPrivate *mPrivate = nullptr; + + L_DECLARE_PRIVATE(AppDataContainer); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _APP_DATA_CONTAINER_H_ From 3d1349d350e3bd24f61c25499bcc46277689fa4e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 13:28:47 +0200 Subject: [PATCH 0393/2215] Handle string_array type in java wrapper --- wrappers/java/genwrapper.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 6e043820d..cb65d1fe2 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -143,6 +143,10 @@ class JavaTranslator(object): if native: return 'int' return 'void' + elif _type.name == 'string_array': + if jni: + return 'jobjectArray' + return 'String[]' return _type.name def translate_argument(self, _arg, native=False, jni=False): From 36b10967ec29145f1ac633ca91742c6339678956 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 13:31:20 +0200 Subject: [PATCH 0394/2215] Handle character type in java wrapper --- wrappers/java/genwrapper.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index cb65d1fe2..3191e102e 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -147,6 +147,10 @@ class JavaTranslator(object): if jni: return 'jobjectArray' return 'String[]' + elif _type.name == 'character': + if jni: + return 'jchar' + return 'char' return _type.name def translate_argument(self, _arg, native=False, jni=False): From e4dd048ca0ca00c3f97f4387c3459a668990b91a Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 10 Oct 2017 13:35:11 +0200 Subject: [PATCH 0395/2215] fix(Address): remove equal method --- src/address/address.cpp | 6 +----- src/address/address.h | 1 - src/conference/conference.cpp | 2 +- src/conference/local-conference.cpp | 2 +- src/conference/remote-conference.cpp | 2 +- 5 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/address/address.cpp b/src/address/address.cpp index 3220bbc58..1be60feb0 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -65,7 +65,7 @@ Address &Address::operator= (const Address &src) { } bool Address::operator== (const Address &address) const { - return equal(address); + return asString() == address.asString(); } bool Address::operator!= (const Address &address) const { @@ -251,10 +251,6 @@ string Address::asStringUriOnly () const { return out; } -bool Address::equal (const Address &address) const { - return asString() == address.asString(); -} - bool Address::weakEqual (const Address &address) const { return getUsername() == address.getUsername() && getDomain() == address.getDomain() && diff --git a/src/address/address.h b/src/address/address.h index ffd32fc5e..b765067d3 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -82,7 +82,6 @@ public: std::string asString () const; std::string asStringUriOnly () const; - bool equal (const Address &address) const; bool weakEqual (const Address &address) const; const std::string &getHeaderValue (const std::string &headerName) const; diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 9673f2658..1ed57424e 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -193,7 +193,7 @@ bool Conference::isMe (const Address &addr) const { cleanedMe.setPort(0); Address cleanedAddr = addr; cleanedAddr.setPort(0); - return cleanedAddr.equal(cleanedMe); + return cleanedAddr == cleanedMe; } LINPHONE_END_NAMESPACE diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index 1a1dcc07b..a26a63832 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -51,7 +51,7 @@ void LocalConference::addParticipant (const Address &addr, const CallSessionPara void LocalConference::removeParticipant (const shared_ptr &participant) { for (const auto &p : participants) { - if (participant->getAddress().equal(p->getAddress())) { + if (participant->getAddress() == p->getAddress()) { participants.remove(p); return; } diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index 20c579f50..171908333 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -53,7 +53,7 @@ void RemoteConference::addParticipant (const Address &addr, const CallSessionPar void RemoteConference::removeParticipant (const shared_ptr &participant) { for (const auto &p : participants) { - if (participant->getAddress().equal(p->getAddress())) { + if (participant->getAddress() == p->getAddress()) { participants.remove(p); return; } From ce7f650f40e8166d1d1944c8d256946f91380b81 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 13:33:32 +0200 Subject: [PATCH 0396/2215] Fixed static native methods visibility --- wrappers/java/java_class.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index b86a8b06f..28f074c8f 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -136,7 +136,7 @@ class {{classImplName}} implements {{className}} { {{#staticMethods}} @Override - private native {{return_native}} {{name}}({{static_native_params}}); + public native {{return_native}} {{name}}({{static_native_params}}); {{/staticMethods}} } \ No newline at end of file From 03a625226b8ffd7c50a738af77e28602c9942628 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 13:37:27 +0200 Subject: [PATCH 0397/2215] Added throw CoreException to each method using Enum's fromInt function --- wrappers/java/genwrapper.py | 1 + wrappers/java/java_class.mustache | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 3191e102e..13a22f7a8 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -186,6 +186,7 @@ class JavaTranslator(object): methodDict['enumCast'] = type(_method.returnType) is AbsApi.EnumType methodDict['classCast'] = type(_method.returnType) is AbsApi.ClassType + methodDict['params'] = '' methodDict['native_params'] = 'long nativePtr' methodDict['static_native_params'] = '' diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 28f074c8f..51ab7f613 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -127,7 +127,7 @@ class {{classImplName}} implements {{className}} { {{#methods}} private native {{return_native}} {{name}}({{native_params}}); - public {{return}} {{name}}({{params}}) {{#exception}}throws CoreException{{/exception}} { + public {{return}} {{name}}({{params}}) {{#exception}}throws CoreException{{/exception}}{{#enumCast}}throws CoreException{{/enumCast}} { {{#exception}}int exceptionResult = {{/exception}}{{return_keyword}}{{#enumCast}}{{return}}.fromInt({{/enumCast}}{{#classCast}}({{return}}){{/classCast}}{{name}}(nativePtr{{native_params_impl}}){{#enumCast}}){{/enumCast}}; {{#exception}}if (exceptionResult != 0) throw new CoreException("{{name}} returned value " + exceptionResult){{/exception}} } From a208e415e55a941ac8b3a0d3f24cd9fa94bb30ba Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 13:38:36 +0200 Subject: [PATCH 0398/2215] Forgot to add throws CoreException to public interface in java wrapper --- wrappers/java/java_class.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 51ab7f613..89f1a38de 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -93,7 +93,7 @@ public interface {{className}} { {{/lines}} */ {{/doc}} - public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}}; + public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}}{{#enumCast}} throws CoreException{{/enumCast}}; {{/staticMethods}} } From ab2f1578217392fa0dc0da180f7dd2ae95bd439e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 13:39:55 +0200 Subject: [PATCH 0399/2215] Same fix as before --- wrappers/java/java_class.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 89f1a38de..3454ad9d9 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -81,7 +81,7 @@ public interface {{className}} { */ {{/doc}} {{#deprecated}}@Deprecated - {{/deprecated}}public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}}; + {{/deprecated}}public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}}{{#enumCast}} throws CoreException{{/enumCast}}; {{/methods}} From 27c271e46e432e2c75239abf8638a9a00b8134c3 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 13:51:51 +0200 Subject: [PATCH 0400/2215] Handle void* type in Java wrapper --- wrappers/java/genwrapper.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 13a22f7a8..bbed80662 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -151,6 +151,10 @@ class JavaTranslator(object): if jni: return 'jchar' return 'char' + elif _type.name == 'void': + if jni: + return 'jobject' + return 'Object' return _type.name def translate_argument(self, _arg, native=False, jni=False): @@ -186,7 +190,7 @@ class JavaTranslator(object): methodDict['enumCast'] = type(_method.returnType) is AbsApi.EnumType methodDict['classCast'] = type(_method.returnType) is AbsApi.ClassType - + methodDict['params'] = '' methodDict['native_params'] = 'long nativePtr' methodDict['static_native_params'] = '' From 6d04fdc1eb3917eeea15437c897224cb64d53795 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 13:57:37 +0200 Subject: [PATCH 0401/2215] Added constructor on each Java object implementation --- wrappers/java/genwrapper.py | 6 +++--- wrappers/java/java_class.mustache | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index bbed80662..27d86f585 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -214,13 +214,13 @@ class JavaTranslator(object): return methodDict - def translate_jni_method(self, _method): + def translate_jni_method(self, _method, static=False): methodDict = {} methodDict['return'] = self.translate_type(_method.returnType, jni=True) methodDict['name'] = 'Java_' + self.jni_package + _method.parent.name.to_camel_case() + 'Impl_' + _method.name.to_camel_case(lower=True) - methodDict['params'] = 'JNIEnv *env, jobject thiz' + methodDict['params'] = 'JNIEnv *env' if static else 'JNIEnv *env, jobject thiz' for arg in _method.args: if arg is not _method.args[0]: methodDict['params'] += ', ' @@ -257,7 +257,7 @@ class JavaTranslator(object): for method in _class.classMethods: try: methodDict = self.translate_method(method) - jniMethodDict = self.translate_jni_method(method) + jniMethodDict = self.translate_jni_method(method, True) classDict['staticMethods'].append(methodDict) classDict['jniMethods'].append(jniMethodDict) except AbsApi.Error as e: diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 3454ad9d9..8e5f006c2 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -102,6 +102,10 @@ class {{classImplName}} implements {{className}} { protected long nativePtr = 0; + protected {{classImplName}}(long ptr) { + nativePtr = ptr; + } + {{#isLinphoneFactory}} private static boolean loadOptionalLibrary(String s) { try { From 821b1204af5c3d318283f42d16ffd03d4fe74673 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 10 Oct 2017 13:56:54 +0200 Subject: [PATCH 0402/2215] feat(EventsDb): explicit columns on legacy import --- src/db/events-db.cpp | 55 ++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 16af86e41..dec49f760 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -251,6 +251,19 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} // ----------------------------------------------------------------------------- + #define LEGACY_MESSAGE_COL_LOCAL_ADDRESS 1 + #define LEGACY_MESSAGE_COL_REMOTE_ADDRESS 2 + #define LEGACY_MESSAGE_COL_DIRECTION 3 + #define LEGACY_MESSAGE_COL_TEXT 4 + #define LEGACY_MESSAGE_COL_STATE 7 + #define LEGACY_MESSAGE_COL_URL 8 + #define LEGACY_MESSAGE_COL_DATE 9 + #define LEGACY_MESSAGE_COL_APP_DATA 10 + #define LEGACY_MESSAGE_COL_CONTENT_ID 11 + #define LEGACY_MESSAGE_COL_IMDN_MESSAGE_ID 12 + #define LEGACY_MESSAGE_COL_CONTENT_TYPE 13 + #define LEGACY_MESSAGE_COL_IS_SECURED 14 + template static T getValueFromLegacyMessage (const soci::row &message, int index, bool &isNull) { isNull = false; @@ -270,21 +283,23 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} soci::transaction tr(*session); for (const auto &message : messages) { - const int direction = message.get(3) + 1; + const int direction = message.get(LEGACY_MESSAGE_COL_DIRECTION) + 1; if (direction != 1 && direction != 2) { lWarning() << "Unable to import legacy message with invalid direction."; return; } - const int state = message.get(7, static_cast(ChatMessage::State::Displayed)); + const int state = message.get( + LEGACY_MESSAGE_COL_STATE, static_cast(ChatMessage::State::Displayed) + ); - const tm date = Utils::getLongAsTm(message.get(9, 0)); + const tm date = Utils::getLongAsTm(message.get(LEGACY_MESSAGE_COL_DATE, 0)); bool isNull; - const string url = getValueFromLegacyMessage(message, 8, isNull); + const string url = getValueFromLegacyMessage(message, LEGACY_MESSAGE_COL_URL, isNull); - const int contentId = message.get(11, -1); - ContentType contentType(message.get(13, "")); + const int contentId = message.get(LEGACY_MESSAGE_COL_CONTENT_ID, -1); + ContentType contentType(message.get(LEGACY_MESSAGE_COL_CONTENT_TYPE, "")); if (!contentType.isValid()) contentType = contentId != -1 ? ContentType::FileTransfer @@ -294,7 +309,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} continue; } - const string text = getValueFromLegacyMessage(message, 4, isNull); + const string text = getValueFromLegacyMessage(message, LEGACY_MESSAGE_COL_TEXT, isNull); Content content; content.setContentType(contentType); @@ -305,13 +320,24 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} } content.setBody(text); } else { - continue; + if (contentType != ContentType::FileTransfer) { + lWarning() << "Unable to import unsupported legacy content."; + continue; + } + + const string appData = getValueFromLegacyMessage(message, LEGACY_MESSAGE_COL_APP_DATA, isNull); + if (isNull) { + lWarning() << "Unable to import legacy file message without app data."; + continue; + } + + content.setAppData("legacy", appData); } struct MessageEventReferences references; references.eventId = insertEvent(EventLog::Type::ChatMessage, date); - references.localSipAddressId = insertSipAddress(message.get(1)); - references.remoteSipAddressId = insertSipAddress(message.get(2)); + references.localSipAddressId = insertSipAddress(message.get(LEGACY_MESSAGE_COL_LOCAL_ADDRESS)); + references.remoteSipAddressId = insertSipAddress(message.get(LEGACY_MESSAGE_COL_REMOTE_ADDRESS)); references.chatRoomId = insertChatRoom(references.remoteSipAddressId, date); insertChatRoomParticipant(references.chatRoomId, references.remoteSipAddressId, false); @@ -320,15 +346,10 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} references, static_cast(state), static_cast(direction), - message.get(12, ""), - !!message.get(14, 0), + message.get(LEGACY_MESSAGE_COL_IMDN_MESSAGE_ID, ""), + !!message.get(LEGACY_MESSAGE_COL_IS_SECURED, 0), { content } ); - - bool noAppData = false; - const string appData = getValueFromLegacyMessage(message, 10, noAppData); - if (!noAppData) - return; } tr.commit(); From db8bfdff0751aa116748912c848804046f7161b3 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 10 Oct 2017 14:21:50 +0200 Subject: [PATCH 0403/2215] fix(Core): add explicit on some constructors --- src/conference/participant.h | 4 ++-- src/db/abstract/abstract-db-p.h | 2 ++ src/db/provider/db-session.h | 2 +- src/nat/ice-agent.h | 2 +- src/utils/payload-type-handler.h | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/conference/participant.h b/src/conference/participant.h index 7b092bb7f..dea93ed98 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -45,8 +45,8 @@ class Participant : public Object { friend class RemoteConference; public: - Participant (const Address &address); - Participant (Address &&address); + explicit Participant (const Address &address); + explicit Participant (Address &&address); const Address& getAddress () const; diff --git a/src/db/abstract/abstract-db-p.h b/src/db/abstract/abstract-db-p.h index 852805d39..2348ca74f 100644 --- a/src/db/abstract/abstract-db-p.h +++ b/src/db/abstract/abstract-db-p.h @@ -30,6 +30,8 @@ LINPHONE_BEGIN_NAMESPACE class AbstractDbPrivate : public ObjectPrivate { public: + AbstractDbPrivate () = default; + DbSession dbSession; private: diff --git a/src/db/provider/db-session.h b/src/db/provider/db-session.h index aed758c2a..5cfd61e05 100644 --- a/src/db/provider/db-session.h +++ b/src/db/provider/db-session.h @@ -43,7 +43,7 @@ public: Soci }; - DbSession (Type type = None); + explicit DbSession (Type type = None); DbSession (const DbSession &src); DbSession &operator= (const DbSession &src); diff --git a/src/nat/ice-agent.h b/src/nat/ice-agent.h index 98101488d..42c293312 100644 --- a/src/nat/ice-agent.h +++ b/src/nat/ice-agent.h @@ -39,7 +39,7 @@ LINPHONE_BEGIN_NAMESPACE class IceAgent { public: - IceAgent (MediaSession &mediaSession) : mediaSession(mediaSession) {} + explicit IceAgent (MediaSession &mediaSession) : mediaSession(mediaSession) {} bool candidatesGathered () const; void checkSession (IceRole role, bool isReinvite); diff --git a/src/utils/payload-type-handler.h b/src/utils/payload-type-handler.h index d52e849fa..f5e284fda 100644 --- a/src/utils/payload-type-handler.h +++ b/src/utils/payload-type-handler.h @@ -42,7 +42,7 @@ struct VbrCodecBitrate { class PayloadTypeHandler { public: - PayloadTypeHandler (LinphoneCore *core) : core(core) {} + explicit PayloadTypeHandler (LinphoneCore *core) : core(core) {} bctbx_list_t *makeCodecsList (SalStreamType type, int bandwidthLimit, int maxCodecs, const bctbx_list_t *previousList); From c04749eaab00d98b16c187771dc13f4002e8d21f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 14:28:05 +0200 Subject: [PATCH 0404/2215] Added userData & destructor in each object for Java wrapper --- wrappers/java/java_class.mustache | 32 ++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 8e5f006c2..2737241d3 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -84,6 +84,15 @@ public interface {{className}} { {{/deprecated}}public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}}{{#enumCast}} throws CoreException{{/enumCast}}; {{/methods}} + /** + * Sets the object to store in this object user's data + */ + public void setUserData(Object data); + + /** + * Gets the object stored in this object user's data + */ + public Object getUserData(); {{#staticMethods}} {{#doc}} @@ -101,6 +110,7 @@ public interface {{className}} { class {{classImplName}} implements {{className}} { protected long nativePtr = 0; + protected Object userData = null; protected {{classImplName}}(long ptr) { nativePtr = ptr; @@ -112,7 +122,7 @@ class {{classImplName}} implements {{className}} { System.loadLibrary(s); return true; } catch (Throwable e) { - android.util.Log.w("LinphoneCoreFactoryImpl", "Unable to load optional library " + s + ": " +e.getMessage()); + android.util.Log.w("LinphoneCoreFactoryImpl", "Unable to load optional library " + s + ": " + e.getMessage()); } return false; } @@ -132,11 +142,27 @@ class {{classImplName}} implements {{className}} { {{#methods}} private native {{return_native}} {{name}}({{native_params}}); public {{return}} {{name}}({{params}}) {{#exception}}throws CoreException{{/exception}}{{#enumCast}}throws CoreException{{/enumCast}} { - {{#exception}}int exceptionResult = {{/exception}}{{return_keyword}}{{#enumCast}}{{return}}.fromInt({{/enumCast}}{{#classCast}}({{return}}){{/classCast}}{{name}}(nativePtr{{native_params_impl}}){{#enumCast}}){{/enumCast}}; - {{#exception}}if (exceptionResult != 0) throw new CoreException("{{name}} returned value " + exceptionResult){{/exception}} + {{#exception}}int exceptionResult = {{/exception}}{{return_keyword}}{{#enumCast}}{{return}}.fromInt({{/enumCast}}{{#classCast}}({{return}}){{/classCast}}{{name}}(nativePtr{{native_params_impl}}){{#enumCast}}){{/enumCast}};{{#exception}} + if (exceptionResult != 0) throw new CoreException("{{name}} returned value " + exceptionResult){{/exception}} } {{/methods}} + private native void unref(long ptr); + protected void finalize() throws Throwable { + if (nativePtr != 0) { + unref(nativePtr); + nativePtr = 0; + } + super.finalize(); + } + + public void setUserData(Object data) { + userData = data; + } + + public Object getUserData() { + return userData; + } {{#staticMethods}} @Override From e1888dc13071fb73269d4d1f3bb42f535782e41a Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 10 Oct 2017 14:29:01 +0200 Subject: [PATCH 0405/2215] fix(Hacks): clean code --- src/hacks/hacks.cpp | 6 ------ src/hacks/hacks.h | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/hacks/hacks.cpp b/src/hacks/hacks.cpp index 61ffc9b3d..a4123a9ad 100644 --- a/src/hacks/hacks.cpp +++ b/src/hacks/hacks.cpp @@ -17,10 +17,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include - -#include - #include "hacks.h" // ============================================================================= @@ -29,6 +25,4 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -// ----------------------------------------------------------------------------- - LINPHONE_END_NAMESPACE diff --git a/src/hacks/hacks.h b/src/hacks/hacks.h index 363910fcb..5e58d07fa 100644 --- a/src/hacks/hacks.h +++ b/src/hacks/hacks.h @@ -32,9 +32,9 @@ LINPHONE_BEGIN_NAMESPACE // can be located more easily. class Hacks { public: + Hacks () = delete; private: - Hacks () = default; L_DISABLE_COPY(Hacks); }; From 5bbd468b55de8a0f27f3be47b6a2b8ea77a8bfa3 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 10 Oct 2017 15:48:10 +0200 Subject: [PATCH 0406/2215] feat(EventsDb): import app data from legacy messages --- src/content/content.cpp | 6 ++++-- src/db/events-db.cpp | 8 +++++++ src/object/app-data-container.cpp | 35 ++++++++++++++++++++----------- src/object/app-data-container.h | 3 +++ 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/content/content.cpp b/src/content/content.cpp index e8d12d176..c222ce388 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -39,14 +39,14 @@ public: Content::Content () : ClonableObject(*new ContentPrivate) {} -Content::Content (const Content &src) : ClonableObject(*new ContentPrivate), AppDataContainer() { +Content::Content (const Content &src) : ClonableObject(*new ContentPrivate), AppDataContainer(src) { L_D(); d->body = src.getBody(); d->contentType = src.getContentType(); d->contentDisposition = src.getContentDisposition(); } -Content::Content (Content &&src) : ClonableObject(*new ContentPrivate) { +Content::Content (Content &&src) : ClonableObject(*new ContentPrivate), AppDataContainer(src) { L_D(); d->body = move(src.getPrivate()->body); d->contentType = move(src.getPrivate()->contentType); @@ -59,6 +59,7 @@ Content &Content::operator= (const Content &src) { d->body = src.getBody(); d->contentType = src.getContentType(); d->contentDisposition = src.getContentDisposition(); + AppDataContainer::operator=(src); } return *this; @@ -69,6 +70,7 @@ Content &Content::operator= (Content &&src) { d->body = move(src.getPrivate()->body); d->contentType = move(src.getPrivate()->contentType); d->contentDisposition = move(src.getPrivate()->contentDisposition); + AppDataContainer::operator=(move(src)); return *this; } diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index dec49f760..d4a063db1 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -160,12 +160,20 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} } void EventsDbPrivate::insertContent (long messageEventId, const Content &content) { + L_Q(); + soci::session *session = dbSession.getBackendSession(); long contentTypeId = insertContentType(content.getContentType().asString()); *session << "INSERT INTO message_content (message_event_id, content_type_id, body) VALUES" " (:messageEventId, :contentTypeId, :body)", soci::use(messageEventId), soci::use(contentTypeId), soci::use(content.getBodyAsString()); + + long messageContentId = q->getLastInsertId(); + for (const auto &appData : content.getAppDataMap()) + *session << "INSERT INTO message_content_app_data (message_content_id, key, data) VALUES" + " (:messageContentId, :key, :data)", + soci::use(messageContentId), soci::use(appData.first), soci::use(appData.second); } long EventsDbPrivate::insertContentType (const string &contentType) { diff --git a/src/object/app-data-container.cpp b/src/object/app-data-container.cpp index 37f33801b..7d6117bd7 100644 --- a/src/object/app-data-container.cpp +++ b/src/object/app-data-container.cpp @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include +#include #include "app-data-container.h" @@ -29,40 +29,51 @@ LINPHONE_BEGIN_NAMESPACE class AppDataContainerPrivate { public: - unordered_map appData; + shared_ptr> appData; }; // ----------------------------------------------------------------------------- -AppDataContainer::AppDataContainer () : mPrivate(new AppDataContainerPrivate) {} +AppDataContainer::AppDataContainer () : mPrivate(new AppDataContainerPrivate) { + L_D(); + d->appData = make_shared>(); +} -// Empty copy constructor. Don't change this pattern. -// AppDataContainer is an Entity component, not a simple structure. -// An Entity is UNIQUE. -AppDataContainer::AppDataContainer (const AppDataContainer &) : mPrivate(new AppDataContainerPrivate) {} +AppDataContainer::AppDataContainer (const AppDataContainer &src) : mPrivate(new AppDataContainerPrivate) { + L_D(); + d->appData = src.getPrivate()->appData; +} AppDataContainer::~AppDataContainer () { delete mPrivate; } -AppDataContainer &AppDataContainer::operator= (const AppDataContainer &) { +AppDataContainer &AppDataContainer::operator= (const AppDataContainer &src) { + L_D(); + if (this != &src) + d->appData = src.getPrivate()->appData; return *this; } +const unordered_map &AppDataContainer::getAppDataMap () const { + L_D(); + return *d->appData.get(); +} + string AppDataContainer::getAppData (const string &name) const { L_D(); - auto it = d->appData.find(name); - return it == d->appData.cend() ? string() : it->second; + auto it = d->appData->find(name); + return it == d->appData->cend() ? string() : it->second; } void AppDataContainer::setAppData (const string &name, const string &appData) { L_D(); - d->appData[name] = appData; + (*d->appData)[name] = appData; } void AppDataContainer::setAppData (const string &name, string &&appData) { L_D(); - d->appData[name] = move(appData); + (*d->appData)[name] = move(appData); } LINPHONE_END_NAMESPACE diff --git a/src/object/app-data-container.h b/src/object/app-data-container.h index 274e5acbd..90e2e416e 100644 --- a/src/object/app-data-container.h +++ b/src/object/app-data-container.h @@ -21,6 +21,7 @@ #define _APP_DATA_CONTAINER_H_ #include +#include #include "linphone/utils/general.h" @@ -38,6 +39,8 @@ public: AppDataContainer &operator= (const AppDataContainer &src); + const std::unordered_map &getAppDataMap () const; + std::string getAppData (const std::string &name) const; void setAppData (const std::string &name, const std::string &appData); void setAppData (const std::string &name, std::string &&appData); From 360d4056dd640c596f4ac2125997ac38b27fe139 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 10 Oct 2017 15:51:32 +0200 Subject: [PATCH 0407/2215] fix(Content): add missed move --- src/content/content.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/content.cpp b/src/content/content.cpp index c222ce388..7a28ad53e 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -46,7 +46,7 @@ Content::Content (const Content &src) : ClonableObject(*new ContentPrivate), App d->contentDisposition = src.getContentDisposition(); } -Content::Content (Content &&src) : ClonableObject(*new ContentPrivate), AppDataContainer(src) { +Content::Content (Content &&src) : ClonableObject(*new ContentPrivate), AppDataContainer(move(src)) { L_D(); d->body = move(src.getPrivate()->body); d->contentType = move(src.getPrivate()->contentType); From c4bf870c43b675ce5e0d4bf1f8430f189fca2430 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 15:52:48 +0200 Subject: [PATCH 0408/2215] Started JNI generated layer --- wrappers/java/genwrapper.py | 113 +++++++++++++++++++++++++++--------- wrappers/java/jni.mustache | 87 +++++++++++++++++++++++++-- 2 files changed, 167 insertions(+), 33 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 27d86f585..9ce0a2429 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -82,10 +82,15 @@ class JavaTranslator(object): def translate_argument_name(self, _argName): return _argName.to_snake_case() - def translate_type(self, _type, native=False, jni=False): + def translate_type(self, _type, native=False, jni=False, isReturn=False): if type(_type) is AbsApi.ListType: if jni: - return 'jobjectArray' + if type(_type.containedTypeDesc) is AbsApi.ClassType: + return 'jobjectArray' + elif type(_type.containedTypeDesc) is AbsApi.BaseType: + return self.translate_type(_type.containedTypeDesc, jni=True) + 'Array' + elif type(_type.containedTypeDesc) is AbsApi.EnumType: + ptrtype = self.translate_type(_type.containedTypeDesc, native) ptrtype = '' if type(_type.containedTypeDesc) is AbsApi.ClassType: ptrtype = self.translate_type(_type.containedTypeDesc, native) @@ -125,6 +130,10 @@ class JavaTranslator(object): if jni: return 'jint' return 'int' + elif _type.name == 'boolean': + if jni: + return 'jboolean' + return 'boolean' elif _type.name == 'floatant': if jni: return 'jfloat' @@ -153,7 +162,10 @@ class JavaTranslator(object): return 'char' elif _type.name == 'void': if jni: - return 'jobject' + if isReturn: + return 'void' + else: + return 'jobject' return 'Object' return _type.name @@ -168,19 +180,19 @@ class JavaTranslator(object): properties.append(self.translate_method(_property.setter)) return properties - def translate_jni_property(self, _property): + def translate_jni_property(self, className, _property): properties = [] if _property.getter is not None: - properties.append(self.translate_jni_method(_property.getter)) + properties.append(self.translate_jni_method(className, _property.getter)) if _property.setter is not None: - properties.append(self.translate_jni_method(_property.setter)) + properties.append(self.translate_jni_method(className, _property.setter)) return properties def translate_method(self, _method): methodDict = {} - methodDict['return'] = self.translate_type(_method.returnType) - methodDict['return_native'] = self.translate_type(_method.returnType, True) + methodDict['return'] = self.translate_type(_method.returnType, isReturn=True) + methodDict['return_native'] = self.translate_type(_method.returnType, native=True, isReturn=True) methodDict['return_keyword'] = '' if methodDict['return'] == 'void' else 'return ' methodDict['convertInputClassArrayToLongArray'] = False @@ -214,25 +226,50 @@ class JavaTranslator(object): return methodDict - def translate_jni_method(self, _method, static=False): + def translate_jni_method(self, className, _method, static=False): methodDict = {} + methodDict['classCName'] = 'Linphone' + className.to_camel_case() + methodDict['className'] = className.to_camel_case() - methodDict['return'] = self.translate_type(_method.returnType, jni=True) - methodDict['name'] = 'Java_' + self.jni_package + _method.parent.name.to_camel_case() + 'Impl_' + _method.name.to_camel_case(lower=True) + methodDict['return'] = self.translate_type(_method.returnType, jni=True, isReturn=True) + methodDict['hasReturn'] = not methodDict['return'] == 'void' + methodDict['name'] = 'Java_' + self.jni_package + className.to_camel_case() + 'Impl_' + _method.name.to_camel_case(lower=True) + methodDict['notStatic'] = not static + methodDict['c_name'] = 'linphone_' + className.to_snake_case() + "_" + _method.name.to_snake_case() + methodDict['returnObject'] = methodDict['hasReturn'] and type(_method.returnType) is AbsApi.ClassType + methodDict['returnClassName'] = self.translate_type(_method.returnType) - methodDict['params'] = 'JNIEnv *env' if static else 'JNIEnv *env, jobject thiz' + methodDict['params'] = 'JNIEnv *env, jobject thiz' if static else 'JNIEnv *env, jobject thiz, jlong ptr' + methodDict['params_impl'] = '' + methodDict['strings'] = [] + methodDict['objects'] = [] + methodDict['returnedObjectGetter'] = '' for arg in _method.args: - if arg is not _method.args[0]: - methodDict['params'] += ', ' + methodDict['params'] += ', ' + methodDict['params_impl'] += ', ' methodDict['params'] += self.translate_argument(arg, jni=True) + argname = self.translate_argument_name(arg.name) + + if type(arg.type) is AbsApi.ClassType: + methodDict['objects'].append({'object': argname, 'objectClassCName': 'Linphone' + arg.type.desc.name.to_camel_case()}) + methodDict['params_impl'] += 'c_' + argname + + elif type(arg.type) is AbsApi.BaseType: + if arg.type.name == 'string': + methodDict['strings'].append({'string': argname}) + methodDict['params_impl'] += 'c_' + argname + else: + methodDict['params_impl'] += argname + else: + methodDict['params_impl'] += argname return methodDict def translate_class(self, _class): classDict = { - 'methods' : [], - 'staticMethods' : [], - 'jniMethods' : [], + 'methods': [], + 'staticMethods': [], + 'jniMethods': [], } classDict['isLinphoneFactory'] = _class.name.to_camel_case() == "Factory" @@ -241,14 +278,14 @@ class JavaTranslator(object): for _property in _class.properties: try: classDict['methods'] += self.translate_property(_property) - classDict['jniMethods'] += self.translate_jni_property(_property) + classDict['jniMethods'] += self.translate_jni_property(_class.name, _property) except AbsApi.Error as e: print('error while translating {0} property: {1}'.format(_property.name.to_snake_case(), e.args[0])) for method in _class.instanceMethods: try: methodDict = self.translate_method(method) - jniMethodDict = self.translate_jni_method(method) + jniMethodDict = self.translate_jni_method(_class.name, method) classDict['methods'].append(methodDict) classDict['jniMethods'].append(jniMethodDict) except AbsApi.Error as e: @@ -257,7 +294,7 @@ class JavaTranslator(object): for method in _class.classMethods: try: methodDict = self.translate_method(method) - jniMethodDict = self.translate_jni_method(method, True) + jniMethodDict = self.translate_jni_method(_class.name, method, True) classDict['staticMethods'].append(methodDict) classDict['jniMethods'].append(jniMethodDict) except AbsApi.Error as e: @@ -267,7 +304,7 @@ class JavaTranslator(object): def translate_interface(self, _class): interfaceDict = { - 'methods' : [], + 'methods': [], } interfaceDict['doc'] = self.docTranslator.translate(_class.briefDescription) @@ -342,6 +379,8 @@ class JavaClass(object): def __init__(self, package, _class, translator): self._class = translator.translate_class(_class) self.isLinphoneFactory = self._class['isLinphoneFactory'] + self.cName = 'Linphone' + _class.name.to_camel_case() + self.cPrefix = 'linphone_' + _class.name.to_snake_case() self.packageName = package self.className = _class.name.to_camel_case() self.classImplName = self.className + "Impl" @@ -359,11 +398,30 @@ class JavaClass(object): self.enums.append(enum) class Jni(object): - def __init__(self): - self.methods = {} + def __init__(self, package): + self.objects = [] + self.methods = [] + self.jni_package = '' + self.jni_path = '' + package_dirs = package.split('.') + for directory in package_dirs: + self.jni_package += directory + '_' + self.jni_path += directory + '/' + + def add_object(self, javaClass): + obj = { + 'jniPrefix': self.jni_package, + 'jniPath': self.jni_path, + 'cPrefix': javaClass.cPrefix, + 'className': javaClass.className, + 'classCName': javaClass.cName, + 'classImplName': javaClass.classImplName, + } + self.objects.append(obj) def add_methods(self, name, methods): - self.methods[name] = methods + for method in methods: + self.methods.append(method) ########################################################################## @@ -381,7 +439,7 @@ class GenWrapper(object): self.parser.parse_all() self.translator = JavaTranslator(package) self.renderer = pystache.Renderer() - self.jni = Jni() + self.jni = Jni(package) self.enums = {} self.interfaces = {} @@ -413,6 +471,7 @@ class GenWrapper(object): self.render(value, self.javadir + '/' + value.filename) for name, value in self.classes.iteritems(): self.render(value, self.javadir + '/' + value.filename) + self.jni.add_object(value) self.render(self.jni, self.srcdir + '/linphone_jni.cc') @@ -434,7 +493,7 @@ class GenWrapper(object): self.enums[javaenum.className] = javaenum except AbsApi.Error as e: print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) - self.jni.add_methods(javaenum.className, javaenum.jniMethods) + #self.jni.add_methods(javaenum.className, javaenum.jniMethods) def render_java_interface(self, _class): if _class is not None: @@ -445,7 +504,7 @@ class GenWrapper(object): self.interfaces[javaInterfaceStub.classNameStub] = javaInterfaceStub except AbsApi.Error as e: print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) - self.jni.add_methods(javainterface.className, javainterface.jniMethods) + #self.jni.add_methods(javainterface.className, javainterface.jniMethods) def render_java_class(self, _class): if _class is not None: diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index 7427e5b78..d0942cb6d 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -18,8 +18,31 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include +#ifdef USE_JAVAH +#include "linphonecore_jni.h" +#endif +#include "linphone/core_utils.h" #include +#include "mediastreamer2/mediastream.h" +#include "mediastreamer2/mscommon.h" +#include "mediastreamer2/msmediaplayer.h" +#include "mediastreamer2/msutils.h" +#include "mediastreamer2/devices.h" +#include "mediastreamer2/msjava.h" +#include "linphone/core.h" +#include "linphone/tunnel.h" +#include "linphone/account_creator.h" +#include "linphone/wrapper_utils.h" +#include "linphone/lpconfig.h" + +#ifdef __ANDROID__ +#include +#include +#endif /* __ANDROID__ */ + +static JavaVM *jvm=0; + JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *ajvm, void *reserved) { #ifdef __ANDROID__ ms_set_jvm(ajvm); @@ -44,9 +67,61 @@ static jlong GetObjectNativePtr(JNIEnv *env, jobject object) { return nativePtr; } -static jlong SetObjectNativePtr(JNIEnv *env, jobject object, jlong ptr) { - jclass objClass = env->GetObjectClass(object); - jfieldID nativePtrId = env->GetFieldID(objClass, "nativePtr", "J"); - env->SetLongField(object, nativePtrId, ptr); - return ptr; -} \ No newline at end of file +{{#objects}} +jobject get{{className}}(JNIEnv *env, {{classCName}} *ptr) { + jobject jobj = 0; + + if (ptr != NULL) { + void *up = {{cPrefix}}_get_user_data(ptr); + jclass {{cPrefix}}_class = env->FindClass("{{jniPath}}{{classImplName}}"); + jmethodID {{cPrefix}}_constructor = env->GetMethodID({{cPrefix}}_class, "", "(J)V"); + + if (up == NULL) { + jobj = env->NewObject({{cPrefix}}_class, {{cPrefix}}_constructor, (jlong)ptr); + {{cPrefix}}_set_user_data(ptr, (void*)env->NewWeakGlobalRef(jobj)); + {{cPrefix}}_ref(ptr); + } else { + jobj = env->NewLocalRef((jobject)up); + if (jobj == NULL) { + // Delete weak ref ? + env->DeleteWeakGlobalRef((jobject)up); + // takes implicit local ref + jobj = env->NewObject({{cPrefix}}_class, {{cPrefix}}_constructor, (jlong)ptr); + {{cPrefix}}_set_user_data(ptr, (void*)env->NewWeakGlobalRef(jobj)); + {{cPrefix}}_ref(ptr); + } + } + } + return jobj; +} + +void Java_{{jniPrefix}}{{classImplName}}_unref(JNIEnv* env, jobject thiz, jlong ptr) { + {{classCName}} *cptr = ({{classCName}}*)ptr; + jobject wref = (jobject){{cPrefix}}_get_user_data(cptr); + {{cPrefix}}_set_user_data(cptr, NULL); + if (wref) { + env->DeleteWeakGlobalRef(wref); + } + {{cPrefix}}_unref(cptr); +} + +{{/objects}} + +{{#methods}} +{{return}} {{name}}({{params}}) { + {{#notStatic}}{{classCName}} *cptr = ({{classCName}}*)ptr;{{/notStatic}} + {{#strings}} + const char* c_{{string}} = GetStringUTFChars(env, {{string}}); + {{/strings}} + {{#objects}} + {{objectClassCName}}* c_{{object}} = NULL; + if ({{object}}) c_{{object}} = ({{objectClassCName}}*)GetObjectNativePtr(env, {{object}}); + {{/objects}} + {{#hasReturn}}{{return}} jni_result = {{#returnObject}}get{{returnClassName}}({{/returnObject}}{{/hasReturn}}{{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}}){{#returnObject}}){{/returnObject}}; + {{#strings}} + ReleaseStringUTFChars(env, {{string}}, c_{{string}}); + {{/strings}} + {{#hasReturn}}return jni_result;{{/hasReturn}} +} + +{{/methods}} \ No newline at end of file From 3544b1b6a59de76bef565b6057d82dd2c93c1ac5 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 10 Oct 2017 16:48:15 +0200 Subject: [PATCH 0409/2215] fix(EventsDb): getUnreadMessages count returns the right count --- src/db/events-db.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index d4a063db1..adfad35db 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -291,8 +291,8 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} soci::transaction tr(*session); for (const auto &message : messages) { - const int direction = message.get(LEGACY_MESSAGE_COL_DIRECTION) + 1; - if (direction != 1 && direction != 2) { + const int direction = message.get(LEGACY_MESSAGE_COL_DIRECTION); + if (direction != 0 && direction != 1) { lWarning() << "Unable to import legacy message with invalid direction."; return; } @@ -356,7 +356,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} static_cast(direction), message.get(LEGACY_MESSAGE_COL_IMDN_MESSAGE_ID, ""), !!message.get(LEGACY_MESSAGE_COL_IS_SECURED, 0), - { content } + { move(content) } ); } @@ -641,7 +641,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} ") AND "; query += " direction = " + Utils::toString(static_cast(ChatMessage::Direction::Incoming)) + - + " AND state = " + Utils::toString(static_cast(ChatMessage::State::Displayed)); + + " AND state <> " + Utils::toString(static_cast(ChatMessage::State::Displayed)); L_BEGIN_LOG_EXCEPTION From 11325a908092ab0b9c50ebad18eb2b3402cfc92f Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 10 Oct 2017 17:11:08 +0200 Subject: [PATCH 0410/2215] feat(EventsDb): add data from legacy messages in message_participant table --- src/db/events-db.cpp | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index adfad35db..ae2f96949 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -72,6 +72,8 @@ public: const list &contents ); + void insertMessageParticipant (long messageEventId, long sipAddressId, ChatMessage::State state); + void importLegacyMessages (const soci::rowset &messages); #endif @@ -257,6 +259,20 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return messageEventId; } + void EventsDbPrivate::insertMessageParticipant (long messageEventId, long sipAddressId, ChatMessage::State state) { + soci::session *session = dbSession.getBackendSession(); + soci::statement statement = ( + session->prepare << "UPDATE message_participant SET state = :state" + " WHERE message_event_id = :messageEventId AND sip_address_id = :sipAddressId", + soci::use(static_cast(state)), soci::use(messageEventId), soci::use(sipAddressId) + ); + statement.execute(true); + if (statement.get_affected_rows() == 0) + *session << "INSERT INTO message_participant (message_event_id, sip_address_id, state)" + " VALUES (:messageEventId, :sipAddressId, :state)", + soci::use(messageEventId), soci::use(sipAddressId), soci::use(static_cast(state)); + } + // ----------------------------------------------------------------------------- #define LEGACY_MESSAGE_COL_LOCAL_ADDRESS 1 @@ -294,12 +310,16 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} const int direction = message.get(LEGACY_MESSAGE_COL_DIRECTION); if (direction != 0 && direction != 1) { lWarning() << "Unable to import legacy message with invalid direction."; - return; + continue; } const int state = message.get( LEGACY_MESSAGE_COL_STATE, static_cast(ChatMessage::State::Displayed) ); + if (state < 0 || state > static_cast(ChatMessage::State::Displayed)) { + lWarning() << "Unable to import legacy message with invalid state."; + continue; + } const tm date = Utils::getLongAsTm(message.get(LEGACY_MESSAGE_COL_DATE, 0)); @@ -350,7 +370,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} insertChatRoomParticipant(references.chatRoomId, references.remoteSipAddressId, false); - insertMessageEvent ( + long messageEventId = insertMessageEvent ( references, static_cast(state), static_cast(direction), @@ -358,6 +378,9 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} !!message.get(LEGACY_MESSAGE_COL_IS_SECURED, 0), { move(content) } ); + + if (state != static_cast(ChatMessage::State::Displayed)) + insertMessageParticipant(messageEventId, references.remoteSipAddressId, static_cast(state)); } tr.commit(); From 2fd4f54a45e3b7293e66c7f638aae1f78811e60d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 17:14:03 +0200 Subject: [PATCH 0411/2215] More work on the java wrapper --- wrappers/java/genwrapper.py | 29 +++++++++++++++++++++++- wrappers/java/jni.mustache | 44 ++++++++++++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 9ce0a2429..d1c2395d5 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -68,8 +68,10 @@ class JavaTranslator(object): def __init__(self, packageName): package_dirs = packageName.split('.') self.jni_package = '' + self.jni_path = '' for directory in package_dirs: self.jni_package += directory + '_' + self.jni_path += directory + '/' self.docTranslator = metadoc.SandcastleJavaTranslator() @@ -230,19 +232,38 @@ class JavaTranslator(object): methodDict = {} methodDict['classCName'] = 'Linphone' + className.to_camel_case() methodDict['className'] = className.to_camel_case() + methodDict['classImplName'] = className.to_camel_case() + 'Impl' + methodDict['jniPath'] = self.jni_path methodDict['return'] = self.translate_type(_method.returnType, jni=True, isReturn=True) - methodDict['hasReturn'] = not methodDict['return'] == 'void' + methodDict['hasListReturn'] = methodDict['return'] == 'jobjectArray' + methodDict['hasReturn'] = not methodDict['return'] == 'void' and not methodDict['hasListReturn'] + methodDict['hasNormalReturn'] = not methodDict['hasListReturn'] methodDict['name'] = 'Java_' + self.jni_package + className.to_camel_case() + 'Impl_' + _method.name.to_camel_case(lower=True) methodDict['notStatic'] = not static methodDict['c_name'] = 'linphone_' + className.to_snake_case() + "_" + _method.name.to_snake_case() methodDict['returnObject'] = methodDict['hasReturn'] and type(_method.returnType) is AbsApi.ClassType methodDict['returnClassName'] = self.translate_type(_method.returnType) + methodDict['isRealObjectArray'] = False + methodDict['isStringObjectArray'] = False + + if methodDict['hasListReturn']: + if _method.returnType.name == 'string_array': + methodDict['isStringObjectArray'] = True + elif type(_method.returnType.containedTypeDesc) is AbsApi.ClassType: + methodDict['isRealObjectArray'] = True + methodDict['objectClassCName'] = 'Linphone' + _method.returnType.containedTypeDesc.desc.name.to_camel_case() + methodDict['objectClassName'] = _method.returnType.containedTypeDesc.desc.name.to_camel_case() + methodDict['objectClassImplName'] = _method.returnType.containedTypeDesc.desc.name.to_camel_case() + 'Impl' + else: + print 'toto' methodDict['params'] = 'JNIEnv *env, jobject thiz' if static else 'JNIEnv *env, jobject thiz, jlong ptr' methodDict['params_impl'] = '' methodDict['strings'] = [] methodDict['objects'] = [] + methodDict['lists'] = [] + methodDict['array'] = [] methodDict['returnedObjectGetter'] = '' for arg in _method.args: methodDict['params'] += ', ' @@ -254,6 +275,12 @@ class JavaTranslator(object): methodDict['objects'].append({'object': argname, 'objectClassCName': 'Linphone' + arg.type.desc.name.to_camel_case()}) methodDict['params_impl'] += 'c_' + argname + elif type(arg.type) is AbsApi.ListType: + isStringList = type(arg.type.containedTypeDesc) is AbsApi.BaseType and arg.type.containedTypeDesc.name == 'string' + isObjList = type(arg.type.containedTypeDesc) is AbsApi.ClassType + methodDict['lists'].append({'list': argname, 'isStringList': isStringList, 'isObjList': isObjList}) + methodDict['params_impl'] += 'bctbx_list_' + argname + elif type(arg.type) is AbsApi.BaseType: if arg.type.name == 'string': methodDict['strings'].append({'string': argname}) diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index d0942cb6d..170181355 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -112,16 +112,48 @@ void Java_{{jniPrefix}}{{classImplName}}_unref(JNIEnv* env, jobject thiz, jlong {{#notStatic}}{{classCName}} *cptr = ({{classCName}}*)ptr;{{/notStatic}} {{#strings}} const char* c_{{string}} = GetStringUTFChars(env, {{string}}); - {{/strings}} - {{#objects}} + {{/strings}}{{#objects}} {{objectClassCName}}* c_{{object}} = NULL; if ({{object}}) c_{{object}} = ({{objectClassCName}}*)GetObjectNativePtr(env, {{object}}); - {{/objects}} + {{/objects}}{{#lists}} + bctbx_list_t *bctbx_list_{{list}} = NULL; + int count = env->GetArrayLength({{list}}); + for (int i=0; i < count; i++) { + {{#isStringList}} + jstring obj = (jstring) env->GetObjectArrayElement({{list}}, i); + const char *str = GetStringUTFChars(env, obj); + if (str) { + bctbx_list_{{list}} = bctbx_list_append(bctbx_list_{{list}}, ms_strdup(str)); + ReleaseStringUTFChars(env, obj, str); + } + {{/isStringList}} + {{#isObjList}} + jobject obj = env->GetObjectArrayElement({{list}}, i); + bctbx_list_{{list}} = bctbx_list_append(bctbx_list_{{list}}, GetObjectNativePtr(env, obj)); + {{/isObjList}} + } + {{/lists}}{{#hasListReturn}} + bctbx_list_t *list = {{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}}); + size_t count = bctbx_list_size(list); + {{#isRealObjectArray}}jobjectArray jni_list_result = env->NewObjectArray(count, env->FindClass("{{jniPath}}{{objectClassImplName}}"), NULL);{{/isRealObjectArray}} + {{#isStringObjectArray}}jobjectArray jni_list_result = env->NewObjectArray(count, env->FindClass("java/lang/String"), env->NewStringUTF(""));{{/isStringObjectArray}} + for (size_t i = 0; i < count; i++) { + {{#isRealObjectArray}} + {{objectClassCName}}* c_object = ({{objectClassCName}}*)list->data; + jobject object = get{{objectClassName}}(c_object); + {{/isRealObjectArray}} + {{#isStringObjectArray}}jstring object = list->data ? env->NewStringUTF(list->data) : 0;{{/isStringObjectArray}} + if (object != 0) { + env->SetObjectArrayElement(jni_list_result, i, object); + {{#isRealObjectArray}}env->DeleteLocalRef(object);{{/isRealObjectArray}} + } + list = bctbx_list_next(list); + } + {{/hasListReturn}}{{#hasNormalReturn}} {{#hasReturn}}{{return}} jni_result = {{#returnObject}}get{{returnClassName}}({{/returnObject}}{{/hasReturn}}{{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}}){{#returnObject}}){{/returnObject}}; - {{#strings}} + {{/hasNormalReturn}}{{#strings}} ReleaseStringUTFChars(env, {{string}}, c_{{string}}); - {{/strings}} - {{#hasReturn}}return jni_result;{{/hasReturn}} + {{/strings}}{{#hasReturn}}return jni_result;{{/hasReturn}}{{#hasListReturn}}return jni_list_result;{{/hasListReturn}} } {{/methods}} \ No newline at end of file From 3d10bbc99b2053d6803c10e0ef10e8a0ba8582dc Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 10 Oct 2017 17:11:49 +0200 Subject: [PATCH 0412/2215] Handle change of admin status of a participant in group chat. --- coreapi/callbacks.c | 23 ++++++++++++++++---- include/linphone/api/c-chat-room.h | 15 ++++++++++++++ include/linphone/api/c-participant.h | 7 ------- src/c-wrapper/api/c-chat-room.cpp | 10 +++++++++ src/c-wrapper/api/c-participant.cpp | 4 ---- src/chat/basic-chat-room.cpp | 9 ++++++++ src/chat/basic-chat-room.h | 2 ++ src/chat/client-group-chat-room.cpp | 30 ++++++++++++++++++++++++++- src/chat/client-group-chat-room.h | 2 ++ src/chat/real-time-text-chat-room.cpp | 9 ++++++++ src/chat/real-time-text-chat-room.h | 2 ++ src/conference/conference-interface.h | 2 ++ src/conference/conference.cpp | 4 ++++ src/conference/conference.h | 3 ++- src/conference/participant-p.h | 1 + src/conference/participant.cpp | 5 ----- src/conference/participant.h | 2 -- tester/conference-event-tester.cpp | 14 ++++++------- 18 files changed, 113 insertions(+), 31 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index f2d3aaa71..9b49492b4 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "sal/refer-op.h" #include "linphone/core.h" +#include "linphone/utils/utils.h" #include "private.h" #include "mediastreamer2/mediastream.h" #include "linphone/lpconfig.h" @@ -38,6 +39,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" #include "call/call-p.h" +#include "chat/chat-room.h" #include "conference/session/call-session.h" #include "conference/session/call-session-p.h" #include "conference/session/media-session.h" @@ -719,10 +721,23 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ LinphonePrivate::Address addr(sal_address_as_string(refer_to)); if (addr.isValid()) { LinphoneCore *lc = reinterpret_cast(op->get_sal()->get_user_pointer()); - LinphoneChatRoom *cr = _linphone_core_join_client_group_chat_room(lc, addr); - if (cr) { - static_cast(op)->reply(SalReasonNone); - return; + if (addr.hasParam("admin")) { + LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, op->get_to()); + if (cr) { + std::shared_ptr participant = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(addr); + if (participant) { + bool value = Utils::stob(addr.getParamValue("admin")); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->setParticipantAdminStatus(participant, value); + } + static_cast(op)->reply(SalReasonNone); + return; + } + } else { + LinphoneChatRoom *cr = _linphone_core_join_client_group_chat_room(lc, addr); + if (cr) { + static_cast(op)->reply(SalReasonNone); + return; + } } } } diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index ddadceb3e..e6e1d0d31 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -261,6 +261,13 @@ LINPHONE_PUBLIC void linphone_chat_room_add_participants (LinphoneChatRoom *cr, */ LINPHONE_PUBLIC bool_t linphone_chat_room_can_handle_participants (const LinphoneChatRoom *cr); +/** + * Find a participant of a chat room from its address. + * @param[in] cr A LinphoneChatRoom object + * @param[in] addr The address to search in the list of participants of the chat room + */ +LINPHONE_PUBLIC LinphoneParticipant *linphone_chat_room_find_participant (const LinphoneChatRoom *cr, const LinphoneAddress *addr); + /** * Get the conference address of the chat room. * @param[in] cr A LinphoneChatRoom object @@ -309,6 +316,14 @@ LINPHONE_PUBLIC void linphone_chat_room_remove_participant (LinphoneChatRoom *cr */ LINPHONE_PUBLIC void linphone_chat_room_remove_participants (LinphoneChatRoom *cr, const bctbx_list_t *participants); +/** + * Change the admin status of a participant of a chat room (you need to be an admin yourself to do this). + * @param[in] cr A LinphoneChatRoom object + * @param[in] participant The Participant for which to change the admin status + * @param[in] isAdmin A boolean value telling whether the participant should now be an admin or not + */ +LINPHONE_PUBLIC void linphone_chat_room_set_participant_admin_status (LinphoneChatRoom *cr, LinphoneParticipant *participant, bool_t isAdmin); + /** * Set the subject of a chat room. * @param[in] cr A LinphoneChatRoom object diff --git a/include/linphone/api/c-participant.h b/include/linphone/api/c-participant.h index bdc3054c4..21adf5f66 100644 --- a/include/linphone/api/c-participant.h +++ b/include/linphone/api/c-participant.h @@ -71,13 +71,6 @@ LINPHONE_PUBLIC const LinphoneAddress * linphone_participant_get_address (const */ LINPHONE_PUBLIC bool_t linphone_participant_is_admin (const LinphoneParticipant *participant); -/** - * Give the administrator rights or remove them to a conference participant. - * @param[in] participant A LinphoneParticipant object - * @param value A boolean value telling whether the participant should be an administrator or not - */ -LINPHONE_PUBLIC void linphone_participant_set_admin (LinphoneParticipant *participant, bool_t value); - /** * @} */ diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 163681be0..e56d447c0 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -27,6 +27,7 @@ #include "chat/basic-chat-room.h" #include "chat/client-group-chat-room.h" #include "chat/real-time-text-chat-room-p.h" +#include "conference/participant.h" // ============================================================================= @@ -224,6 +225,10 @@ bool_t linphone_chat_room_can_handle_participants (const LinphoneChatRoom *cr) { return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->canHandleParticipants(); } +LinphoneParticipant *linphone_chat_room_find_participant (const LinphoneChatRoom *cr, const LinphoneAddress *addr) { + return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(*L_GET_CPP_PTR_FROM_C_OBJECT(addr))); +} + const LinphoneAddress *linphone_chat_room_get_conference_address (const LinphoneChatRoom *cr) { if (cr->conferenceAddressCache) { linphone_address_unref(cr->conferenceAddressCache); @@ -260,6 +265,11 @@ void linphone_chat_room_remove_participants (LinphoneChatRoom *cr, const bctbx_l L_GET_CPP_PTR_FROM_C_OBJECT(cr)->removeParticipants(L_GET_RESOLVED_CPP_LIST_FROM_C_LIST(participants, Participant)); } +void linphone_chat_room_set_participant_admin_status (LinphoneChatRoom *cr, LinphoneParticipant *participant, bool_t isAdmin) { + shared_ptr p = L_GET_CPP_PTR_FROM_C_OBJECT(participant); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->setParticipantAdminStatus(p, !!isAdmin); +} + void linphone_chat_room_set_subject (LinphoneChatRoom *cr, const char *subject) { L_GET_CPP_PTR_FROM_C_OBJECT(cr)->setSubject(L_C_TO_STRING(subject)); } diff --git a/src/c-wrapper/api/c-participant.cpp b/src/c-wrapper/api/c-participant.cpp index eb6c18814..783c92ca3 100644 --- a/src/c-wrapper/api/c-participant.cpp +++ b/src/c-wrapper/api/c-participant.cpp @@ -58,7 +58,3 @@ const LinphoneAddress *linphone_participant_get_address (const LinphoneParticipa bool_t linphone_participant_is_admin (const LinphoneParticipant *participant) { return L_GET_CPP_PTR_FROM_C_OBJECT(participant)->isAdmin(); } - -void linphone_participant_set_admin (LinphoneParticipant *participant, bool_t value) { - L_GET_CPP_PTR_FROM_C_OBJECT(participant)->setAdmin(!!value); -} diff --git a/src/chat/basic-chat-room.cpp b/src/chat/basic-chat-room.cpp index f0eaacc66..ae59ffd01 100644 --- a/src/chat/basic-chat-room.cpp +++ b/src/chat/basic-chat-room.cpp @@ -48,6 +48,11 @@ bool BasicChatRoom::canHandleParticipants () const { return false; } +shared_ptr BasicChatRoom::findParticipant (const Address &addr) const { + lError() << "findParticipant() is not allowed on a BasicChatRoom"; + return nullptr; +} + const Address *BasicChatRoom::getConferenceAddress () const { lError() << "a BasicChatRoom does not have a conference address"; return nullptr; @@ -85,6 +90,10 @@ void BasicChatRoom::removeParticipants (const list> &par lError() << "removeParticipants() is not allowed on a BasicChatRoom"; } +void BasicChatRoom::setParticipantAdminStatus (shared_ptr &participant, bool isAdmin) { + lError() << "setParticipantAdminStatus() is not allowed on a BasicChatRoom"; +} + void BasicChatRoom::setSubject (const string &subject) { L_D(); d->subject = subject; diff --git a/src/chat/basic-chat-room.h b/src/chat/basic-chat-room.h index bd693e83b..73b7ed78a 100644 --- a/src/chat/basic-chat-room.h +++ b/src/chat/basic-chat-room.h @@ -37,6 +37,7 @@ public: void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; bool canHandleParticipants () const override; + std::shared_ptr findParticipant (const Address &addr) const override; const Address *getConferenceAddress () const override; int getNbParticipants () const override; std::list> getParticipants () const override; @@ -45,6 +46,7 @@ public: void leave () override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; + void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) override; void setSubject (const std::string &subject) override; private: diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index f261659bd..7abc13ad1 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -17,6 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "linphone/utils/utils.h" + #include "address/address-p.h" #include "client-group-chat-room-p.h" #include "c-wrapper/c-wrapper.h" @@ -26,6 +28,7 @@ #include "content/content.h" #include "hacks/hacks.h" #include "logger/logger.h" +#include "sal/refer-op.h" // ============================================================================= @@ -103,6 +106,10 @@ bool ClientGroupChatRoom::canHandleParticipants () const { return RemoteConference::canHandleParticipants(); } +shared_ptr ClientGroupChatRoom::findParticipant (const Address &addr) const { + return RemoteConference::findParticipant(addr); +} + const Address *ClientGroupChatRoom::getConferenceAddress () const { return RemoteConference::getConferenceAddress(); } @@ -150,6 +157,27 @@ void ClientGroupChatRoom::removeParticipants (const list // TODO } +void ClientGroupChatRoom::setParticipantAdminStatus (shared_ptr &participant, bool isAdmin) { + L_D(); + if (isAdmin == participant->isAdmin()) + return; + if (!me->isAdmin()) { + lError() << "Cannot change the participant admin status because I am not admin"; + return; + } + SalReferOp *referOp = new SalReferOp(d->core->sal); + LinphoneAddress *lAddr = linphone_address_new(conferenceAddress.asString().c_str()); + linphone_configure_op(d->core, referOp, lAddr, nullptr, false); + linphone_address_unref(lAddr); + Address referToAddr = participant->getAddress(); + referToAddr.setParam("text"); + referToAddr.setParam("admin", Utils::toString(isAdmin)); + referToAddr.setDomain(""); + referToAddr.setPort(-1); + referOp->send_refer(referToAddr.getPrivate()->getInternalAddress()); + referOp->unref(); +} + void ClientGroupChatRoom::setSubject (const string &subject) { L_D(); if (d->state != ChatRoom::State::Created) { @@ -224,7 +252,7 @@ void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdm lWarning() << "Participant " << participant << " admin status has been changed but is not in the list of participants!"; return; } - participant->setAdmin(isAdmin); + participant->getPrivate()->setAdmin(isAdmin); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAdminStatusChangedCb cb = linphone_chat_room_cbs_get_participant_admin_status_changed(cbs); diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index 1d28aa825..2d8692646 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -45,6 +45,7 @@ public: void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; bool canHandleParticipants () const override; + std::shared_ptr findParticipant (const Address &addr) const override; const Address *getConferenceAddress () const override; int getNbParticipants () const override; std::list> getParticipants () const override; @@ -53,6 +54,7 @@ public: void leave () override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; + void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) override; void setSubject (const std::string &subject) override; private: diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index d89e6befe..2c71170d5 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -144,6 +144,11 @@ bool RealTimeTextChatRoom::canHandleParticipants () const { return false; } +shared_ptr RealTimeTextChatRoom::findParticipant (const Address &addr) const { + lError() << "findParticipant() is not allowed on a RealTimeTextChatRoom"; + return nullptr; +} + const Address *RealTimeTextChatRoom::getConferenceAddress () const { lError() << "a RealTimeTextChatRoom does not have a conference address"; return nullptr; @@ -181,6 +186,10 @@ void RealTimeTextChatRoom::removeParticipants (const list &participant, bool isAdmin) { + lError() << "setParticipantAdminStatus() is not allowed on a RealTimeTextChatRoom"; +} + void RealTimeTextChatRoom::setSubject (const string &subject) { L_D(); d->subject = subject; diff --git a/src/chat/real-time-text-chat-room.h b/src/chat/real-time-text-chat-room.h index ec7bdf929..ad2f12d37 100644 --- a/src/chat/real-time-text-chat-room.h +++ b/src/chat/real-time-text-chat-room.h @@ -47,6 +47,7 @@ public: void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; bool canHandleParticipants () const override; + std::shared_ptr findParticipant (const Address &addr) const override; const Address *getConferenceAddress () const override; int getNbParticipants () const override; std::list> getParticipants () const override; @@ -55,6 +56,7 @@ public: void leave () override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; + void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) override; void setSubject (const std::string &subject) override; private: diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index a1d187991..443181f26 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -38,6 +38,7 @@ public: virtual void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) = 0; virtual void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) = 0; virtual bool canHandleParticipants () const = 0; + virtual std::shared_ptr findParticipant (const Address &addr) const = 0; virtual const Address *getConferenceAddress () const = 0; virtual int getNbParticipants () const = 0; virtual std::list> getParticipants () const = 0; @@ -46,6 +47,7 @@ public: virtual void leave () = 0; virtual void removeParticipant (const std::shared_ptr &participant) = 0; virtual void removeParticipants (const std::list> &participants) = 0; + virtual void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) = 0; virtual void setSubject (const std::string &subject) = 0; }; diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 1ed57424e..3ba9cf826 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -90,6 +90,10 @@ void Conference::removeParticipants (const list> &partic removeParticipant(p); } +void Conference::setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) { + lError() << "Conference class does not handle setParticipantAdminStatus() generically"; +} + void Conference::setSubject (const string &subject) { this->subject = subject; } diff --git a/src/conference/conference.h b/src/conference/conference.h index 57a4cdb44..cee450b11 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -46,7 +46,6 @@ public: LinphoneCore * getCore () const { return core; } - std::shared_ptr findParticipant (const Address &addr) const; std::shared_ptr findParticipant (const std::shared_ptr &session) const; public: @@ -54,6 +53,7 @@ public: void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; bool canHandleParticipants () const override; + std::shared_ptr findParticipant (const Address &addr) const override; const Address *getConferenceAddress () const override; int getNbParticipants () const override; std::list> getParticipants () const override; @@ -62,6 +62,7 @@ public: void leave () override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; + void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) override; void setSubject (const std::string &subject) override; private: diff --git a/src/conference/participant-p.h b/src/conference/participant-p.h index f862c54a4..fabce499c 100644 --- a/src/conference/participant-p.h +++ b/src/conference/participant-p.h @@ -45,6 +45,7 @@ public: void subscribeToConferenceEventPackage (bool value) { _isSubscribedToConferenceEventPackage = value; } void removeSession () { session = nullptr; } void setAddress (const Address &newAddr) { addr = newAddr; } + void setAdmin (bool isAdmin) { this->isAdmin = isAdmin; } private: Address addr; diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index 6cfe04a0f..0c9fc5003 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -67,11 +67,6 @@ bool Participant::isAdmin () const { return d->isAdmin; } -void Participant::setAdmin (bool isAdmin) { - L_D(); - d->isAdmin = isAdmin; -} - // ============================================================================= ostream & operator<< (ostream &strm, const shared_ptr &participant) { diff --git a/src/conference/participant.h b/src/conference/participant.h index dea93ed98..707227425 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -49,9 +49,7 @@ public: explicit Participant (Address &&address); const Address& getAddress () const; - bool isAdmin () const; - void setAdmin (bool isAdmin); private: L_DECLARE_PRIVATE(Participant); diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index b578aa018..96db4c8cb 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -25,7 +25,7 @@ #include "conference/conference-listener.h" #include "conference/local-conference.h" #include "conference/local-conference-event-handler-p.h" -#include "conference/participant.h" +#include "conference/participant-p.h" #include "conference/remote-conference-event-handler-p.h" #include "tools/private-access.h" #include "tools/tester.h" @@ -766,7 +766,7 @@ void send_first_notify() { localConf.addParticipant(aliceAddr, ¶ms, false); localConf.setSubject("A random test subject"); shared_ptr alice = localConf.findParticipant(aliceAddr); - alice->setAdmin(true); + L_GET_PRIVATE(alice)->setAdmin(true); LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; string notify = localHandlerPrivate->createNotifyFullState(); @@ -814,7 +814,7 @@ void send_added_notify() { localConf.addParticipant(bobAddr, ¶ms, false); localConf.addParticipant(aliceAddr, ¶ms, false); shared_ptr alice = localConf.findParticipant(aliceAddr); - alice->setAdmin(true); + L_GET_PRIVATE(alice)->setAdmin(true); LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; string notify = localHandlerPrivate->createNotifyFullState(); @@ -867,7 +867,7 @@ void send_removed_notify() { localConf.addParticipant(bobAddr, ¶ms, false); localConf.addParticipant(aliceAddr, ¶ms, false); shared_ptr alice = localConf.findParticipant(aliceAddr); - alice->setAdmin(true); + L_GET_PRIVATE(alice)->setAdmin(true); LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; string notify = localHandlerPrivate->createNotifyFullState(); @@ -917,7 +917,7 @@ void send_admined_notify() { localConf.addParticipant(bobAddr, ¶ms, false); localConf.addParticipant(aliceAddr, ¶ms, false); shared_ptr alice = localConf.findParticipant(aliceAddr); - alice->setAdmin(true); + L_GET_PRIVATE(alice)->setAdmin(true); LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; string notify = localHandlerPrivate->createNotifyFullState(); @@ -967,7 +967,7 @@ void send_unadmined_notify() { localConf.addParticipant(bobAddr, ¶ms, false); localConf.addParticipant(aliceAddr, ¶ms, false); shared_ptr alice = localConf.findParticipant(aliceAddr); - alice->setAdmin(true); + L_GET_PRIVATE(alice)->setAdmin(true); LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; string notify = localHandlerPrivate->createNotifyFullState(); @@ -1019,7 +1019,7 @@ void send_subject_changed_notify () { localConf.addParticipant(aliceAddr, ¶ms, false); localConf.setSubject("A random test subject"); shared_ptr alice = localConf.findParticipant(aliceAddr); - alice->setAdmin(true); + L_GET_PRIVATE(alice)->setAdmin(true); LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; string notify = localHandlerPrivate->createNotifyFullState(); From 8b8dcb3f72a1687e630e9969ce3e684b0a030e0c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Oct 2017 18:02:55 +0200 Subject: [PATCH 0413/2215] Few changes in java wrapper for factory + added LinphoneJavaBindings --- wrappers/java/genwrapper.py | 4 ++++ wrappers/java/java_class.mustache | 6 ++++++ wrappers/java/jni.mustache | 36 ++++++++++++++++++++++++++----- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index d1c2395d5..15c736045 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -233,6 +233,7 @@ class JavaTranslator(object): methodDict['classCName'] = 'Linphone' + className.to_camel_case() methodDict['className'] = className.to_camel_case() methodDict['classImplName'] = className.to_camel_case() + 'Impl' + methodDict['cPrefix'] = 'linphone_' + className.to_snake_case() methodDict['jniPath'] = self.jni_path methodDict['return'] = self.translate_type(_method.returnType, jni=True, isReturn=True) @@ -406,6 +407,7 @@ class JavaClass(object): def __init__(self, package, _class, translator): self._class = translator.translate_class(_class) self.isLinphoneFactory = self._class['isLinphoneFactory'] + self.isNotLinphoneFactory = not self.isLinphoneFactory self.cName = 'Linphone' + _class.name.to_camel_case() self.cPrefix = 'linphone_' + _class.name.to_snake_case() self.packageName = package @@ -436,6 +438,8 @@ class Jni(object): self.jni_path += directory + '/' def add_object(self, javaClass): + if javaClass.className == 'Factory': + return obj = { 'jniPrefix': self.jni_package, 'jniPath': self.jni_path, diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 2737241d3..873e3992a 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -94,6 +94,7 @@ public interface {{className}} { */ public Object getUserData(); +{{#isNotLinphoneFactory}} {{#staticMethods}} {{#doc}} /** @@ -105,6 +106,7 @@ public interface {{className}} { public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}}{{#enumCast}} throws CoreException{{/enumCast}}; {{/staticMethods}} +{{/isNotLinphoneFactory}} } class {{classImplName}} implements {{className}} { @@ -147,6 +149,7 @@ class {{classImplName}} implements {{className}} { } {{/methods}} +{{#isNotLinphoneFactory}} private native void unref(long ptr); protected void finalize() throws Throwable { if (nativePtr != 0) { @@ -155,6 +158,7 @@ class {{classImplName}} implements {{className}} { } super.finalize(); } +{{/isNotLinphoneFactory}} public void setUserData(Object data) { userData = data; @@ -164,9 +168,11 @@ class {{classImplName}} implements {{className}} { return userData; } +{{#isNotLinphoneFactory}} {{#staticMethods}} @Override public native {{return_native}} {{name}}({{static_native_params}}); {{/staticMethods}} +{{/isNotLinphoneFactory}} } \ No newline at end of file diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index 170181355..386ca6644 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -41,13 +41,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #endif /* __ANDROID__ */ -static JavaVM *jvm=0; +static JavaVM *jvm = NULL; JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *ajvm, void *reserved) { #ifdef __ANDROID__ ms_set_jvm(ajvm); #endif /* __ANDROID__ */ - jvm=ajvm; + jvm = ajvm; return JNI_VERSION_1_2; } @@ -67,14 +67,38 @@ static jlong GetObjectNativePtr(JNIEnv *env, jobject object) { return nativePtr; } +class LinphoneJavaBindings { +public: + LinphoneJavaBindings(JNIEnv *env) { + {{#objects}} + {{cPrefix}}_class = (jclass)env->NewGlobalRef(env->FindClass("{{jniPath}}{{classImplName}}")); + {{cPrefix}}_class_constructor = env->GetMethodID({{cPrefix}}_class, "", "(J)V"); + {{/objects}} + } + + ~LinphoneJavaBindings() { + JNIEnv *env = 0; + jvm->AttachCurrentThread(&env,NULL); + {{#objects}} + env->DeleteGlobalRef({{cPrefix}}_class); + {{/objects}} + } + + {{#objects}} + jclass {{cPrefix}}_class; + jmethodID {{cPrefix}}_class_constructor; + {{/objects}} +}; + {{#objects}} jobject get{{className}}(JNIEnv *env, {{classCName}} *ptr) { jobject jobj = 0; if (ptr != NULL) { void *up = {{cPrefix}}_get_user_data(ptr); - jclass {{cPrefix}}_class = env->FindClass("{{jniPath}}{{classImplName}}"); - jmethodID {{cPrefix}}_constructor = env->GetMethodID({{cPrefix}}_class, "", "(J)V"); + //TODO get ljb + jclass {{cPrefix}}_class = ljb->{{cPrefix}}_class; + jmethodID {{cPrefix}}_constructor = ljb->{{cPrefix}}_class_constructor; if (up == NULL) { jobj = env->NewObject({{cPrefix}}_class, {{cPrefix}}_constructor, (jlong)ptr); @@ -135,7 +159,9 @@ void Java_{{jniPrefix}}{{classImplName}}_unref(JNIEnv* env, jobject thiz, jlong {{/lists}}{{#hasListReturn}} bctbx_list_t *list = {{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}}); size_t count = bctbx_list_size(list); - {{#isRealObjectArray}}jobjectArray jni_list_result = env->NewObjectArray(count, env->FindClass("{{jniPath}}{{objectClassImplName}}"), NULL);{{/isRealObjectArray}} + {{#isRealObjectArray}} + //TODO get ljb + jobjectArray jni_list_result = env->NewObjectArray(count, ljb->{{cPrefix}}_class, NULL);{{/isRealObjectArray}} {{#isStringObjectArray}}jobjectArray jni_list_result = env->NewObjectArray(count, env->FindClass("java/lang/String"), env->NewStringUTF(""));{{/isStringObjectArray}} for (size_t i = 0; i < count; i++) { {{#isRealObjectArray}} From 5350cadf47eeb7e2c601abe902f1f46ecaebbc88 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 11 Oct 2017 09:57:55 +0200 Subject: [PATCH 0414/2215] Added set/get user_data in LinphoneFactory --- coreapi/factory.c | 10 ++++++++++ include/linphone/factory.h | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/coreapi/factory.c b/coreapi/factory.c index ee7cbc761..fadb6234f 100644 --- a/coreapi/factory.c +++ b/coreapi/factory.c @@ -57,6 +57,8 @@ struct _LinphoneFactory { char *cached_image_resources_dir; char *cached_msplugins_dir; LinphoneErrorInfo* ei; + + void *user_data; }; static void linphone_factory_uninit(LinphoneFactory *obj){ @@ -320,3 +322,11 @@ LinphoneTransports *linphone_factory_create_transports(LinphoneFactory *factory) LinphoneVideoActivationPolicy *linphone_factory_create_video_activation_policy(LinphoneFactory *factory) { return linphone_video_activation_policy_new(); } + +void *linphone_factory_get_user_data(const LinphoneFactory *factory) { + return factory->user_data; +} + +void linphone_factory_set_user_data(LinphoneFactory *factory, void *data) { + factory->user_data = data; +} diff --git a/include/linphone/factory.h b/include/linphone/factory.h index 33a509e7c..a3e49fc7b 100644 --- a/include/linphone/factory.h +++ b/include/linphone/factory.h @@ -261,6 +261,21 @@ LINPHONE_PUBLIC LinphoneTransports *linphone_factory_create_transports(LinphoneF * @return LinphoneVideoActivationPolicy object. */ LINPHONE_PUBLIC LinphoneVideoActivationPolicy *linphone_factory_create_video_activation_policy(LinphoneFactory *factory); + +/** + * Gets the user data in the LinphoneFactory object + * @param[in] factory the LinphoneFactory + * @return the user data +*/ +LINPHONE_PUBLIC void *linphone_factory_get_user_data(const LinphoneFactory *factory); + +/** + * Sets the user data in the LinphoneFactory object + * @param[in] factory the LinphoneFactory object + * @param[in] data the user data +*/ +LINPHONE_PUBLIC void linphone_factory_set_user_data(LinphoneFactory *factory, void *data); + /** * @} */ From 26cc84140d86273f48c5a49ea5c7ac05844b496a Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 11 Oct 2017 10:18:57 +0200 Subject: [PATCH 0415/2215] added participant's device added/removed listener --- src/CMakeLists.txt | 2 ++ src/chat/client-group-chat-room.cpp | 28 +++++++++++++++- src/chat/client-group-chat-room.h | 2 ++ src/conference/conference-listener.h | 2 ++ src/conference/participant-device.cpp | 36 ++++++++++++++++++++ src/conference/participant-device.h | 48 +++++++++++++++++++++++++++ src/conference/participant-p.h | 17 ++++++---- src/conference/participant.cpp | 25 ++++++++++++++ src/conference/participant.h | 4 ++- src/conference/remote-conference.cpp | 4 +++ src/conference/remote-conference.h | 2 ++ tester/conference-event-tester.cpp | 20 ++++++++++- 12 files changed, 181 insertions(+), 9 deletions(-) create mode 100644 src/conference/participant-device.cpp create mode 100644 src/conference/participant-device.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8bf3bbf28..701a1339c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -62,6 +62,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES conference/params/call-session-params.h conference/params/media-session-params-p.h conference/params/media-session-params.h + conference/participant-device.h conference/participant-p.h conference/participant.h conference/remote-conference-event-handler-p.h @@ -144,6 +145,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES conference/local-conference.cpp conference/params/call-session-params.cpp conference/params/media-session-params.cpp + conference/participant-device.cpp conference/participant.cpp conference/remote-conference-event-handler.cpp conference/remote-conference.cpp diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 7abc13ad1..907c93d74 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -231,7 +231,7 @@ void ClientGroupChatRoom::onParticipantAdded (const Address &addr) { void ClientGroupChatRoom::onParticipantRemoved (const Address &addr) { shared_ptr participant = findParticipant(addr); if (!participant) { - lWarning() << "Participant " << participant << " removed but not in the list of participants!"; + lWarning() << "Participant " << participant << " removed but is not in the list of participants!"; return; } LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); @@ -269,6 +269,32 @@ void ClientGroupChatRoom::onSubjectChanged (const std::string &subject) { cb(cr, subject.c_str()); } +void ClientGroupChatRoom::onParticipantDeviceAdded (const Address &addr, const Address &gruu) { + shared_ptr participant = nullptr; + if (isMe(addr)) + participant = me; + else + participant = findParticipant(addr); + if (!participant) { + lWarning() << "Participant " << participant << " added a device but is not in the list of participants!"; + return; + } + participant->getPrivate()->addDevice(gruu); +} + +void ClientGroupChatRoom::onParticipantDeviceRemoved (const Address &addr, const Address &gruu) { + shared_ptr participant = nullptr; + if (isMe(addr)) + participant = me; + else + participant = findParticipant(addr); + if (!participant) { + lWarning() << "Participant " << participant << " removed a device but is not in the list of participants!"; + return; + } + participant->getPrivate()->removeDevice(gruu); +} + // ----------------------------------------------------------------------------- void ClientGroupChatRoom::onCallSessionSetReleased (const std::shared_ptr &session) { diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index 2d8692646..200effef1 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -65,6 +65,8 @@ private: void onParticipantRemoved (const Address &addr) override; void onParticipantSetAdmin (const Address &addr, bool isAdmin) override; void onSubjectChanged (const std::string &subject) override; + void onParticipantDeviceAdded (const Address &addr, const Address &gruu) override; + void onParticipantDeviceRemoved (const Address &addr, const Address &gruu) override; private: /* CallSessionListener */ diff --git a/src/conference/conference-listener.h b/src/conference/conference-listener.h index aabe88a0c..34665bfbd 100644 --- a/src/conference/conference-listener.h +++ b/src/conference/conference-listener.h @@ -34,6 +34,8 @@ public: virtual void onParticipantRemoved (const Address &addr) = 0; virtual void onParticipantSetAdmin (const Address &addr, bool isAdmin) = 0; virtual void onSubjectChanged (const std::string &subject) = 0; + virtual void onParticipantDeviceAdded (const Address &addr, const Address &gruu) = 0; + virtual void onParticipantDeviceRemoved (const Address &addr, const Address &gruu) = 0; }; LINPHONE_END_NAMESPACE diff --git a/src/conference/participant-device.cpp b/src/conference/participant-device.cpp new file mode 100644 index 000000000..524ae7e2d --- /dev/null +++ b/src/conference/participant-device.cpp @@ -0,0 +1,36 @@ +/* + * participant-device.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "participant-device.h" + +using namespace std; + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +ParticipantDevice::ParticipantDevice (const Address &gruu) { + mGruu = gruu; +} + +bool ParticipantDevice::operator== (const ParticipantDevice &device) const { + return (mGruu == device.getGruu()); +} + +LINPHONE_END_NAMESPACE \ No newline at end of file diff --git a/src/conference/participant-device.h b/src/conference/participant-device.h new file mode 100644 index 000000000..38f495b21 --- /dev/null +++ b/src/conference/participant-device.h @@ -0,0 +1,48 @@ +/* + * participant-device.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _PARTICIPANT_DEVICE_H_ +#define _PARTICIPANT_DEVICE_H_ + +#include + +#include "address/address.h" +#include "linphone/utils/general.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ParticipantDevice { +public: + explicit ParticipantDevice (const Address &gruu); + + bool operator== (const ParticipantDevice &device) const; + + inline const Address &getGruu () const { + return mGruu; + }; + +private: + Address mGruu; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _PARTICIPANT_DEVICE_H_ \ No newline at end of file diff --git a/src/conference/participant-p.h b/src/conference/participant-p.h index fabce499c..258c65d7b 100644 --- a/src/conference/participant-p.h +++ b/src/conference/participant-p.h @@ -40,18 +40,23 @@ public: virtual ~ParticipantPrivate () = default; std::shared_ptr createSession (const Conference &conference, const CallSessionParams *params, bool hasMedia, CallSessionListener *listener); - std::shared_ptr getSession () const { return session; } - bool isSubscribedToConferenceEventPackage () const { return _isSubscribedToConferenceEventPackage; } - void subscribeToConferenceEventPackage (bool value) { _isSubscribedToConferenceEventPackage = value; } - void removeSession () { session = nullptr; } - void setAddress (const Address &newAddr) { addr = newAddr; } - void setAdmin (bool isAdmin) { this->isAdmin = isAdmin; } + inline std::shared_ptr getSession () const { return session; } + inline bool isSubscribedToConferenceEventPackage () const { return _isSubscribedToConferenceEventPackage; } + inline void subscribeToConferenceEventPackage (bool value) { _isSubscribedToConferenceEventPackage = value; } + inline void removeSession () { session.reset(); } + inline void setAddress (const Address &newAddr) { addr = newAddr; } + inline void setAdmin (bool isAdmin) { this->isAdmin = isAdmin; } + const std::list::const_iterator findDevice (const Address &gruu) const; + const std::list &getDevices () const; + void addDevice (const Address &gruu); + void removeDevice (const Address &gruu); private: Address addr; bool isAdmin = false; bool _isSubscribedToConferenceEventPackage = false; std::shared_ptr session; + std::list devices; L_DECLARE_PUBLIC(Participant); }; diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index 0c9fc5003..f4ef38269 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -17,6 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include + #include "object/object-p.h" #include "participant-p.h" @@ -41,6 +43,29 @@ shared_ptr ParticipantPrivate::createSession ( return session; } +// ----------------------------------------------------------------------------- + +const list::const_iterator ParticipantPrivate::findDevice (const Address &gruu) const { + ParticipantDevice device(gruu); + return find(devices.cbegin(), devices.cend(), device); +} + +const list &ParticipantPrivate::getDevices () const { + return devices; +} + +void ParticipantPrivate::addDevice (const Address &gruu) { + ParticipantDevice device(gruu); + if(findDevice(gruu) == devices.cend()) + devices.push_back(device); +} + +void ParticipantPrivate::removeDevice (const Address &gruu) { + ParticipantDevice device(gruu); + if(findDevice(gruu) != devices.cend()) + devices.remove(device); +} + // ============================================================================= Participant::Participant (const Address &address) : Object(*new ParticipantPrivate) { diff --git a/src/conference/participant.h b/src/conference/participant.h index 707227425..a1b2904c3 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -20,10 +20,12 @@ #ifndef _PARTICIPANT_H_ #define _PARTICIPANT_H_ -#include "address/address.h" +#include +#include "address/address.h" #include "object/object.h" #include "conference/params/call-session-params.h" +#include "conference/participant-device.h" // ============================================================================= diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index 171908333..aca20de9f 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -94,4 +94,8 @@ void RemoteConference::onParticipantSetAdmin (const Address &addr, bool isAdmin) void RemoteConference::onSubjectChanged (const std::string &subject) {} +void RemoteConference::onParticipantDeviceAdded (const Address &addr, const Address &gruu) {} + +void RemoteConference::onParticipantDeviceRemoved (const Address &addr, const Address &gruu) {} + LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index d9f93bc59..ea97a397f 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -50,6 +50,8 @@ protected: void onParticipantRemoved (const Address &addr) override; void onParticipantSetAdmin (const Address &addr, bool isAdmin) override; void onSubjectChanged (const std::string &subject) override; + void onParticipantDeviceAdded (const Address &addr, const Address &gruu) override; + void onParticipantDeviceRemoved (const Address &addr, const Address &gruu) override; protected: RemoteConferenceEventHandler *eventHandler = nullptr; diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index 96db4c8cb..f3d30e5b6 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -434,9 +434,12 @@ private: void onParticipantRemoved (const Address &addr) override; void onParticipantSetAdmin (const Address &addr, bool isAdmin) override; void onSubjectChanged(const string &subject) override; + void onParticipantDeviceAdded(const Address &addr, const Address &gruu) override; + void onParticipantDeviceRemoved(const Address &addr, const Address &gruu) override; public: RemoteConferenceEventHandler *handler; map participants; + map participantDevices; string confSubject; }; @@ -453,10 +456,12 @@ void ConferenceEventTester::onConferenceCreated (const Address &addr) {} void ConferenceEventTester::onConferenceTerminated (const Address &addr) {} void ConferenceEventTester::onParticipantAdded (const Address &addr) { - participants.insert(pair(addr.asString(), false)); + participants.insert(pair(addr.asString(), FALSE)); + participantDevices.insert(pair(addr.asString(), 0)); } void ConferenceEventTester::onParticipantRemoved (const Address &addr) { participants.erase(addr.asString()); + participantDevices.erase(addr.asString()); } void ConferenceEventTester::onParticipantSetAdmin (const Address &addr, bool isAdmin) { @@ -469,6 +474,19 @@ void ConferenceEventTester::onSubjectChanged(const string &subject) { confSubject = subject; } +void ConferenceEventTester::onParticipantDeviceAdded (const Address &addr, const Address &gruu) { + auto it = participantDevices.find(addr.asString()); + if (it != participantDevices.end()) + it->second++; + +} + +void ConferenceEventTester::onParticipantDeviceRemoved (const Address &addr, const Address &gruu) { + auto it = participantDevices.find(addr.asString()); + if (it != participantDevices.end() && it->second > 0) + it->second--; +} + void first_notify_parsing() { LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, confUri); From 2aa0652cc9eac74b9614eb2278cc20aec2e56294 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 11 Oct 2017 10:50:50 +0200 Subject: [PATCH 0416/2215] feat(EventsDb): add a trigger to delete message_participant entries --- src/db/events-db.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index ae2f96949..2ade6da98 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -267,10 +267,11 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} soci::use(static_cast(state)), soci::use(messageEventId), soci::use(sipAddressId) ); statement.execute(true); - if (statement.get_affected_rows() == 0) + if (statement.get_affected_rows() == 0 && state != ChatMessage::State::Displayed) { *session << "INSERT INTO message_participant (message_event_id, sip_address_id, state)" " VALUES (:messageEventId, :sipAddressId, :state)", soci::use(messageEventId), soci::use(sipAddressId), soci::use(static_cast(state)); + } } // ----------------------------------------------------------------------------- @@ -526,6 +527,26 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " REFERENCES message_event(event_id)" " ON DELETE CASCADE" ")"; + + // Trigger to delete participant_message cache entries. + string displayedId = Utils::toString(static_cast(ChatMessage::State::Displayed)); + string participantMessageDeleter = + "CREATE TRIGGER IF NOT EXISTS message_participant_deleter" + " AFTER UPDATE OF state ON message_participant FOR EACH ROW" + " WHEN NEW.state = "; + participantMessageDeleter += displayedId; + participantMessageDeleter += " AND (SELECT COUNT(*) FROM (" + " SELECT state FROM message_participant WHERE" + " NEW.message_event_id = message_participant.message_event_id" + " AND state <> "; + participantMessageDeleter += displayedId; + participantMessageDeleter += " LIMIT 1" + " )) = 0" + " BEGIN" + " DELETE FROM message_participant WHERE NEW.message_event_id = message_participant.message_event_id;" + " END"; + + *session << participantMessageDeleter; } bool EventsDb::addEvent (const EventLog &eventLog) { From 68706bb5eb966e85a8947bb83aea0e8ef189bffe Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 11 Oct 2017 10:52:39 +0200 Subject: [PATCH 0417/2215] Added enums to JNI layer of Java wrapper --- wrappers/java/genwrapper.py | 46 +++++++++++++++++++++++++++++++++---- wrappers/java/jni.mustache | 25 +++++++++++++++----- 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 15c736045..18422d5b3 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -233,7 +233,6 @@ class JavaTranslator(object): methodDict['classCName'] = 'Linphone' + className.to_camel_case() methodDict['className'] = className.to_camel_case() methodDict['classImplName'] = className.to_camel_case() + 'Impl' - methodDict['cPrefix'] = 'linphone_' + className.to_snake_case() methodDict['jniPath'] = self.jni_path methodDict['return'] = self.translate_type(_method.returnType, jni=True, isReturn=True) @@ -253,6 +252,7 @@ class JavaTranslator(object): methodDict['isStringObjectArray'] = True elif type(_method.returnType.containedTypeDesc) is AbsApi.ClassType: methodDict['isRealObjectArray'] = True + methodDict['objectCPrefix'] = 'linphone_' + _method.returnType.containedTypeDesc.desc.name.to_snake_case() methodDict['objectClassCName'] = 'Linphone' + _method.returnType.containedTypeDesc.desc.name.to_camel_case() methodDict['objectClassName'] = _method.returnType.containedTypeDesc.desc.name.to_camel_case() methodDict['objectClassImplName'] = _method.returnType.containedTypeDesc.desc.name.to_camel_case() + 'Impl' @@ -281,6 +281,10 @@ class JavaTranslator(object): isObjList = type(arg.type.containedTypeDesc) is AbsApi.ClassType methodDict['lists'].append({'list': argname, 'isStringList': isStringList, 'isObjList': isObjList}) methodDict['params_impl'] += 'bctbx_list_' + argname + + elif type(arg.type) is AbsApi.EnumType: + argCType = arg.type.name + methodDict['params_impl'] += '(' + argCType + ') ' + argname elif type(arg.type) is AbsApi.BaseType: if arg.type.name == 'string': @@ -333,6 +337,7 @@ class JavaTranslator(object): def translate_interface(self, _class): interfaceDict = { 'methods': [], + 'jniMethods': [], } interfaceDict['doc'] = self.docTranslator.translate(_class.briefDescription) @@ -343,7 +348,9 @@ class JavaTranslator(object): return interfaceDict def translate_enum(self, _class): - enumDict = {} + enumDict = { + 'jniMethods': [], + } enumDict['name'] = _class.name.to_camel_case() enumDict['doc'] = self.docTranslator.translate(_class.briefDescription) @@ -351,6 +358,8 @@ class JavaTranslator(object): i = 0 lastValue = None + enumDict['jniPath'] = self.jni_path + for enumValue in _class.values: enumValDict = {} enumValDict['name'] = enumValue.name.to_camel_case() @@ -379,10 +388,19 @@ class JavaEnum(object): self._class = translator.translate_enum(_enum) self.packageName = package self.className = _enum.name.to_camel_case() + self.cPrefix = 'linphone_' + _enum.name.to_snake_case() self.filename = self.className + ".java" self.values = self._class['values'] self.doc = self._class['doc'] - self.jniMethods = [] + self.jniMethods = self._class['jniMethods'] + + name = _enum.name.to_camel_case() + if name in ENUMS_LIST: + className = ENUMS_LIST[name] + if name.startswith(className): + name = name[len(className):] + name = className + '$' + name + self.jniName = name class JavaInterface(object): def __init__(self, package, _interface, translator): @@ -393,7 +411,7 @@ class JavaInterface(object): self.imports = [] self.methods = self._class['methods'] self.doc = self._class['doc'] - self.jniMethods = [] + self.jniMethods = self._class['jniMethods'] class JavaInterfaceStub(object): def __init__(self, _interface): @@ -429,6 +447,7 @@ class JavaClass(object): class Jni(object): def __init__(self, package): self.objects = [] + self.enums = [] self.methods = [] self.jni_package = '' self.jni_path = '' @@ -437,6 +456,16 @@ class Jni(object): self.jni_package += directory + '_' self.jni_path += directory + '/' + def add_enum(self, javaEnum): + obj = { + 'jniPrefix': self.jni_package, + 'jniPath': self.jni_path, + 'jniName': javaEnum.jniName, + 'cPrefix': javaEnum.cPrefix, + 'className': javaEnum.className, + } + self.enums.append(obj) + def add_object(self, javaClass): if javaClass.className == 'Factory': return @@ -467,6 +496,12 @@ class GenWrapper(object): project.check() self.parser = AbsApi.CParser(project) + self.parser.functionBl = \ + ['linphone_vcard_get_belcard',\ + 'linphone_core_get_current_vtable',\ + 'linphone_factory_get',\ + 'linphone_factory_clean'] + self.parser.classBl += 'LinphoneCoreVTable' self.parser.parse_all() self.translator = JavaTranslator(package) self.renderer = pystache.Renderer() @@ -487,6 +522,7 @@ class GenWrapper(object): self.render_java_enum(_enum[1]) for name, value in self.enums.iteritems(): + self.jni.add_enum(value) if name in ENUMS_LIST: className = ENUMS_LIST[name] print 'Enum ' + name + ' belongs to class ' + className @@ -552,7 +588,7 @@ def main(): argparser = argparse.ArgumentParser(description='Generate source files for the Java wrapper') argparser.add_argument('xmldir', type=str, help='Directory where the XML documentation of the Linphone\'s API generated by Doxygen is placed') argparser.add_argument('-o --output', type=str, help='the directory where to generate the source files', dest='outputdir', default='.') - argparser.add_argument('-p --package', type=str, help='the package name for the wrapper', dest='package', default='org.linphone') + argparser.add_argument('-p --package', type=str, help='the package name for the wrapper', dest='package', default='org.linphone.core') argparser.add_argument('-n --name', type=str, help='the name of the genarated source file', dest='name', default='linphone_jni.cc') args = argparser.parse_args() diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index 386ca6644..a43ccc4cc 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -18,9 +18,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include -#ifdef USE_JAVAH -#include "linphonecore_jni.h" -#endif #include "linphone/core_utils.h" #include @@ -47,6 +44,8 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *ajvm, void *reserved) { #ifdef __ANDROID__ ms_set_jvm(ajvm); #endif /* __ANDROID__ */ + LinphoneJavaBindings *ljb = new LinphoneJavaBindings(ms_get_jni_env()); + linphone_factory_set_user_data(linphone_factory_get(), ljb); jvm = ajvm; return JNI_VERSION_1_2; } @@ -74,6 +73,11 @@ public: {{cPrefix}}_class = (jclass)env->NewGlobalRef(env->FindClass("{{jniPath}}{{classImplName}}")); {{cPrefix}}_class_constructor = env->GetMethodID({{cPrefix}}_class, "", "(J)V"); {{/objects}} + + {{#enums}} + {{cPrefix}}_class = (jclass)env->NewGlobalRef(env->FindClass("{{jniPath}}{{jniName}}")); + {{cPrefix}}_class_constructor_from_int = env->GetStaticMethodID({{cPrefix}}_class, "fromInt", "(I)L{{jniPath}}{{jniName}};"); + {{/enums}} } ~LinphoneJavaBindings() { @@ -82,12 +86,21 @@ public: {{#objects}} env->DeleteGlobalRef({{cPrefix}}_class); {{/objects}} + + {{#enums}} + env->DeleteGlobalRef({{cPrefix}}_class); + {{/enums}} } {{#objects}} jclass {{cPrefix}}_class; jmethodID {{cPrefix}}_class_constructor; {{/objects}} + + {{#enums}} + jclass {{cPrefix}}_class; + jmethodID {{cPrefix}}_class_constructor_from_int; + {{/enums}} }; {{#objects}} @@ -96,7 +109,7 @@ jobject get{{className}}(JNIEnv *env, {{classCName}} *ptr) { if (ptr != NULL) { void *up = {{cPrefix}}_get_user_data(ptr); - //TODO get ljb + LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_factory_get_user_data(linphone_factory_get()); jclass {{cPrefix}}_class = ljb->{{cPrefix}}_class; jmethodID {{cPrefix}}_constructor = ljb->{{cPrefix}}_class_constructor; @@ -160,8 +173,8 @@ void Java_{{jniPrefix}}{{classImplName}}_unref(JNIEnv* env, jobject thiz, jlong bctbx_list_t *list = {{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}}); size_t count = bctbx_list_size(list); {{#isRealObjectArray}} - //TODO get ljb - jobjectArray jni_list_result = env->NewObjectArray(count, ljb->{{cPrefix}}_class, NULL);{{/isRealObjectArray}} + LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_factory_get_user_data(linphone_factory_get()); + jobjectArray jni_list_result = env->NewObjectArray(count, ljb->{{objectCPrefix}}_class, NULL);{{/isRealObjectArray}} {{#isStringObjectArray}}jobjectArray jni_list_result = env->NewObjectArray(count, env->FindClass("java/lang/String"), env->NewStringUTF(""));{{/isStringObjectArray}} for (size_t i = 0; i < count; i++) { {{#isRealObjectArray}} From 3a36854e2871223e42bc878c23575e3ce075b8d5 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 11 Oct 2017 11:10:14 +0200 Subject: [PATCH 0418/2215] feat(EventsDb): update message state when all message_participant are removed --- src/db/events-db.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index 2ade6da98..da472eeae 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -267,11 +267,10 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} soci::use(static_cast(state)), soci::use(messageEventId), soci::use(sipAddressId) ); statement.execute(true); - if (statement.get_affected_rows() == 0 && state != ChatMessage::State::Displayed) { + if (statement.get_affected_rows() == 0 && state != ChatMessage::State::Displayed) *session << "INSERT INTO message_participant (message_event_id, sip_address_id, state)" " VALUES (:messageEventId, :sipAddressId, :state)", soci::use(messageEventId), soci::use(sipAddressId), soci::use(static_cast(state)); - } } // ----------------------------------------------------------------------------- @@ -535,7 +534,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " AFTER UPDATE OF state ON message_participant FOR EACH ROW" " WHEN NEW.state = "; participantMessageDeleter += displayedId; - participantMessageDeleter += " AND (SELECT COUNT(*) FROM (" + participantMessageDeleter += " AND (SELECT COUNT(*) FROM (" " SELECT state FROM message_participant WHERE" " NEW.message_event_id = message_participant.message_event_id" " AND state <> "; @@ -544,6 +543,9 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} " )) = 0" " BEGIN" " DELETE FROM message_participant WHERE NEW.message_event_id = message_participant.message_event_id;" + " UPDATE message_event SET state = "; + participantMessageDeleter += displayedId; + participantMessageDeleter += " WHERE event_id = NEW.message_event_id;" " END"; *session << participantMessageDeleter; From 532020bb4c64f24d6055f91e58998819e5d2fc10 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 11 Oct 2017 11:26:59 +0200 Subject: [PATCH 0419/2215] handle add/remove of participant's device in conference event handlers --- src/chat/client-group-chat-room.cpp | 6 +- .../local-conference-event-handler-p.h | 3 + .../local-conference-event-handler.cpp | 99 ++++++++++++++++--- .../local-conference-event-handler.h | 6 +- .../remote-conference-event-handler.cpp | 27 +++-- .../remote-conference-event-handler.h | 12 +-- 6 files changed, 119 insertions(+), 34 deletions(-) diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 907c93d74..ce02a4563 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -243,7 +243,7 @@ void ClientGroupChatRoom::onParticipantRemoved (const Address &addr) { } void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdmin) { - shared_ptr participant = nullptr; + shared_ptr participant; if (isMe(addr)) participant = me; else @@ -270,7 +270,7 @@ void ClientGroupChatRoom::onSubjectChanged (const std::string &subject) { } void ClientGroupChatRoom::onParticipantDeviceAdded (const Address &addr, const Address &gruu) { - shared_ptr participant = nullptr; + shared_ptr participant; if (isMe(addr)) participant = me; else @@ -283,7 +283,7 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (const Address &addr, const A } void ClientGroupChatRoom::onParticipantDeviceRemoved (const Address &addr, const Address &gruu) { - shared_ptr participant = nullptr; + shared_ptr participant; if (isMe(addr)) participant = me; else diff --git a/src/conference/local-conference-event-handler-p.h b/src/conference/local-conference-event-handler-p.h index 264175c70..b50af3ed7 100644 --- a/src/conference/local-conference-event-handler-p.h +++ b/src/conference/local-conference-event-handler-p.h @@ -37,12 +37,15 @@ public: std::string createNotifyParticipantRemoved (const Address &addr); std::string createNotifyParticipantAdmined (const Address &addr, bool isAdmin); std::string createNotifySubjectChanged (); + std::string createNotifyParticipantDeviceAdded (const Address &addr, const Address &gruu); + std::string createNotifyParticipantDeviceRemoved (const Address &addr, const Address &gruu); private: LinphoneCore *core = nullptr; LocalConference *conf = nullptr; void sendNotify (const std::string ¬ify, const Address &addr); + L_DECLARE_PUBLIC(LocalConferenceEventHandler); }; diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 1476728ab..d58835022 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -64,7 +64,7 @@ void LocalConferenceEventHandlerPrivate::notifyAllExcept (const string ¬ify, for (const auto &participant : conf->getParticipants()) { Address cleanedParticipantAddr(participant->getAddress()); cleanedParticipantAddr.setPort(0); - if (participant->getPrivate()->isSubscribedToConferenceEventPackage() && !(cleanedAddr.weakEqual(cleanedParticipantAddr))) + if (participant->getPrivate()->isSubscribedToConferenceEventPackage() && !cleanedAddr.weakEqual(cleanedParticipantAddr)) sendNotify(notify, participant->getAddress()); } } @@ -77,8 +77,8 @@ void LocalConferenceEventHandlerPrivate::notifyAll (const string ¬ify) { } string LocalConferenceEventHandlerPrivate::createNotifyFullState () { - string entity = this->conf->getConferenceAddress()->asStringUriOnly(); - string subject = this->conf->getSubject(); + string entity = conf->getConferenceAddress()->asStringUriOnly(); + string subject = conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); UsersType users; ConferenceDescriptionType confDescr = ConferenceDescriptionType(); @@ -86,38 +86,51 @@ string LocalConferenceEventHandlerPrivate::createNotifyFullState () { confInfo.setUsers(users); confInfo.setConferenceDescription((const ConferenceDescriptionType) confDescr); - for (const auto &participant : this->conf->getParticipants()) { + for (const auto &participant : conf->getParticipants()) { UserType user = UserType(); UserRolesType roles; + UserType::EndpointSequence endpoints; user.setRoles(roles); + user.setEndpoint(endpoints); user.setEntity(participant->getAddress().asStringUriOnly()); user.getRoles()->getEntry().push_back(participant->isAdmin() ? "admin" : "participant"); user.setState("full"); + + for (const auto &device : participant->getPrivate()->getDevices()) { + const string &gruu = device.getGruu().asStringUriOnly(); + EndpointType endpoint = EndpointType(); + endpoint.setEntity(gruu); + endpoint.setState("full"); + user.getEndpoint().push_back(endpoint); + } + confInfo.getUsers()->getUser().push_back(user); } - return(createNotify(confInfo)); + return createNotify(confInfo); } string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const Address &addr) { - string entity = this->conf->getConferenceAddress()->asStringUriOnly(); + string entity = conf->getConferenceAddress()->asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); UserType user = UserType(); UserRolesType roles; + UserType::EndpointSequence endpoints; user.setRoles(roles); user.setEntity(addr.asStringUriOnly()); user.getRoles()->getEntry().push_back("participant"); user.setState("full"); + confInfo.getUsers()->getUser().push_back(user); - return(createNotify(confInfo)); + return createNotify(confInfo); } string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved (const Address &addr) { - string entity = this->conf->getConferenceAddress()->asStringUriOnly(); + string entity = conf->getConferenceAddress()->asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -127,11 +140,11 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved (const user.setState("deleted"); confInfo.getUsers()->getUser().push_back(user); - return(createNotify(confInfo)); + return createNotify(confInfo); } string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined (const Address &addr, bool isAdmin) { - string entity = this->conf->getConferenceAddress()->asStringUriOnly(); + string entity = conf->getConferenceAddress()->asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -144,25 +157,71 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined (const user.setState("partial"); confInfo.getUsers()->getUser().push_back(user); - return(createNotify(confInfo)); + return createNotify(confInfo); } string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged () { - string entity = this->conf->getConferenceAddress()->asStringUriOnly(); - string subject = this->conf->getSubject(); + string entity = conf->getConferenceAddress()->asStringUriOnly(); + string subject = conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); ConferenceDescriptionType confDescr = ConferenceDescriptionType(); confDescr.setSubject(subject); confInfo.setConferenceDescription((const ConferenceDescriptionType)confDescr); - return(createNotify(confInfo)); + return createNotify(confInfo); +} + +string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceAdded (const Address &addr, const Address &gruu) { + string entity = conf->getConferenceAddress()->asStringUriOnly(); + string subject = conf->getSubject(); + ConferenceType confInfo = ConferenceType(entity); + + UserType user = UserType(); + UserRolesType roles; + UserType::EndpointSequence endpoints; + user.setRoles(roles); + user.setEntity(addr.asStringUriOnly()); + user.getRoles()->getEntry().push_back("participant"); + user.setState("partial"); + + EndpointType endpoint = EndpointType(); + endpoint.setEntity(gruu.asStringUriOnly()); + endpoint.setState("full"); + user.getEndpoint().push_back(endpoint); + + confInfo.getUsers()->getUser().push_back(user); + + return createNotify(confInfo); +} + +string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceRemoved (const Address &addr, const Address &gruu) { + string entity = conf->getConferenceAddress()->asStringUriOnly(); + string subject = conf->getSubject(); + ConferenceType confInfo = ConferenceType(entity); + + UserType user = UserType(); + UserRolesType roles; + UserType::EndpointSequence endpoints; + user.setRoles(roles); + user.setEntity(addr.asStringUriOnly()); + user.getRoles()->getEntry().push_back("participant"); + user.setState("partial"); + + EndpointType endpoint = EndpointType(); + endpoint.setEntity(gruu.asStringUriOnly()); + endpoint.setState("deleted"); + user.getEndpoint().push_back(endpoint); + + confInfo.getUsers()->getUser().push_back(user); + + return createNotify(confInfo); } void LocalConferenceEventHandlerPrivate::sendNotify (const string ¬ify, const Address &addr) { LinphoneAddress *cAddr = linphone_address_new(addr.asString().c_str()); LinphoneEvent *lev = linphone_core_create_notify(core, cAddr, "conference"); // Fix the From header to put the chat room URI - lev->op->set_from(this->conf->getConferenceAddress()->asString().c_str()); + lev->op->set_from(conf->getConferenceAddress()->asString().c_str()); linphone_address_unref(cAddr); doNotify(notify, lev); } @@ -217,4 +276,14 @@ void LocalConferenceEventHandler::notifySubjectChanged () { d->notifyAll(d->createNotifySubjectChanged()); } +void LocalConferenceEventHandler::notifyParticipantDeviceAdded (const Address &addr, const Address &gruu) { + L_D(); + d->notifyAll(d->createNotifyParticipantDeviceAdded(addr, gruu)); +} + +void LocalConferenceEventHandler::notifyParticipantDeviceRemoved (const Address &addr, const Address &gruu) { + L_D(); + d->notifyAll(d->createNotifyParticipantDeviceRemoved(addr, gruu)); +} + LINPHONE_END_NAMESPACE diff --git a/src/conference/local-conference-event-handler.h b/src/conference/local-conference-event-handler.h index 5568ed171..f34eaee7d 100644 --- a/src/conference/local-conference-event-handler.h +++ b/src/conference/local-conference-event-handler.h @@ -31,14 +31,16 @@ class LocalConferenceEventHandlerPrivate; class LocalConferenceEventHandler : public Object { public: - LocalConferenceEventHandler(LinphoneCore *core, LocalConference *localConf); - ~LocalConferenceEventHandler(); + LocalConferenceEventHandler (LinphoneCore *core, LocalConference *localConf); + ~LocalConferenceEventHandler (); void subscribeReceived (LinphoneEvent *lev); void notifyParticipantAdded (const Address &addr); void notifyParticipantRemoved (const Address &addr); void notifyParticipantSetAdmin (const Address &addr, bool isAdmin); void notifySubjectChanged (); + void notifyParticipantDeviceAdded (const Address &addr, const Address &gruu); + void notifyParticipantDeviceRemoved (const Address &addr, const Address &gruu); private: L_DECLARE_PRIVATE(LocalConferenceEventHandler); diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 216e8e568..163f9961a 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -32,7 +32,7 @@ using namespace Xsd::ConferenceInfo; // ----------------------------------------------------------------------------- -RemoteConferenceEventHandler::RemoteConferenceEventHandler(LinphoneCore *core, ConferenceListener *listener) +RemoteConferenceEventHandler::RemoteConferenceEventHandler (LinphoneCore *core, ConferenceListener *listener) : Object(*new RemoteConferenceEventHandlerPrivate) { L_D(); xercesc::XMLPlatformUtils::Initialize(); @@ -40,13 +40,13 @@ RemoteConferenceEventHandler::RemoteConferenceEventHandler(LinphoneCore *core, C d->listener = listener; } -RemoteConferenceEventHandler::~RemoteConferenceEventHandler() { +RemoteConferenceEventHandler::~RemoteConferenceEventHandler () { xercesc::XMLPlatformUtils::Terminate(); } // ----------------------------------------------------------------------------- -void RemoteConferenceEventHandler::subscribe(const Address &addr) { +void RemoteConferenceEventHandler::subscribe (const Address &addr) { L_D(); d->confAddress = addr; LinphoneAddress *lAddr = linphone_address_new(d->confAddress.asString().c_str()); @@ -57,7 +57,7 @@ void RemoteConferenceEventHandler::subscribe(const Address &addr) { linphone_event_send_subscribe(d->lev, nullptr); } -void RemoteConferenceEventHandler::unsubscribe() { +void RemoteConferenceEventHandler::unsubscribe () { L_D(); if (d->lev) { linphone_event_terminate(d->lev); @@ -65,7 +65,7 @@ void RemoteConferenceEventHandler::unsubscribe() { } } -void RemoteConferenceEventHandler::notifyReceived(string xmlBody) { +void RemoteConferenceEventHandler::notifyReceived (string xmlBody) { L_D(); lInfo() << "NOTIFY received for conference " << d->confAddress.asString(); istringstream data(xmlBody); @@ -73,10 +73,10 @@ void RemoteConferenceEventHandler::notifyReceived(string xmlBody) { Address cleanedConfAddress = d->confAddress; cleanedConfAddress.setPort(0); if (confInfo->getEntity() == cleanedConfAddress.asString()) { - if(confInfo->getConferenceDescription().present() && confInfo->getConferenceDescription().get().getSubject().present()) + if (confInfo->getConferenceDescription().present() && confInfo->getConferenceDescription().get().getSubject().present()) d->listener->onSubjectChanged(confInfo->getConferenceDescription().get().getSubject().get()); - if(!confInfo->getUsers().present()) + if (!confInfo->getUsers().present()) return; for (const auto &user : confInfo->getUsers()->getUser()) { @@ -99,6 +99,17 @@ void RemoteConferenceEventHandler::notifyReceived(string xmlBody) { if (user.getState() == "full") d->listener->onParticipantAdded(addr); d->listener->onParticipantSetAdmin(addr, isAdmin); + for (const auto &endpoint : user.getEndpoint()) { + if (!endpoint.getEntity().present()) + break; + + Address gruu(endpoint.getEntity().get()); + if (endpoint.getState() == "deleted") + d->listener->onParticipantDeviceRemoved(addr, gruu); + else if (endpoint.getState() == "full") + d->listener->onParticipantDeviceAdded(addr, gruu); + + } } linphone_address_unref(cAddr); } @@ -107,7 +118,7 @@ void RemoteConferenceEventHandler::notifyReceived(string xmlBody) { // ----------------------------------------------------------------------------- -const Address &RemoteConferenceEventHandler::getConfAddress() { +const Address &RemoteConferenceEventHandler::getConfAddress () { L_D(); return d->confAddress; } diff --git a/src/conference/remote-conference-event-handler.h b/src/conference/remote-conference-event-handler.h index fa30dd808..7d25bd359 100644 --- a/src/conference/remote-conference-event-handler.h +++ b/src/conference/remote-conference-event-handler.h @@ -33,14 +33,14 @@ class RemoteConferenceEventHandlerPrivate; class RemoteConferenceEventHandler : public Object { public: - RemoteConferenceEventHandler(LinphoneCore *core, ConferenceListener *listener); - ~RemoteConferenceEventHandler(); + RemoteConferenceEventHandler (LinphoneCore *core, ConferenceListener *listener); + ~RemoteConferenceEventHandler (); - void subscribe(const Address &confAddress); - void notifyReceived(std::string xmlBody); - void unsubscribe(); + void subscribe (const Address &confAddress); + void notifyReceived (std::string xmlBody); + void unsubscribe (); - const Address &getConfAddress(); + const Address &getConfAddress (); private: L_DECLARE_PRIVATE(RemoteConferenceEventHandler); From 6cdd92ef8ad38f05b24f7d7f1daf8c31f65daf49 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 11 Oct 2017 11:38:43 +0200 Subject: [PATCH 0420/2215] add participant devices on participant added notifications --- src/conference/local-conference-event-handler.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index d58835022..3594c160a 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -115,10 +115,21 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const A ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); - UserType user = UserType(); UserRolesType roles; UserType::EndpointSequence endpoints; + + shared_ptr p = conf->findParticipant(addr); + if (p) { + for (const auto &device : p->getPrivate()->getDevices()) { + const string &gruu = device.getGruu().asStringUriOnly(); + EndpointType endpoint = EndpointType(); + endpoint.setEntity(gruu); + endpoint.setState("full"); + user.getEndpoint().push_back(endpoint); + } + } + user.setRoles(roles); user.setEntity(addr.asStringUriOnly()); user.getRoles()->getEntry().push_back("participant"); From 7f32ae8582e3e3f4b8a175128b538a5c1e34afed Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 11 Oct 2017 11:56:17 +0200 Subject: [PATCH 0421/2215] fix(ChatMessage): use L_DECLARE_ENUM to declare direction --- include/linphone/api/c-types.h | 6 ++ include/linphone/enums/chat-message-enums.h | 4 + src/chat/chat-message.cpp | 8 +- src/chat/chat-message.h | 99 ++++++++++----------- src/chat/chat-room.cpp | 4 +- 5 files changed, 63 insertions(+), 58 deletions(-) diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index 92ce261f3..16d86f3fb 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -137,6 +137,12 @@ typedef struct _LinphoneChatMessageEvent LinphoneChatMessageEvent; */ L_DECLARE_C_ENUM(ChatMessageState, L_ENUM_VALUES_CHAT_MESSAGE_STATE); +/** + * LinphoneChatMessageDirection is used to indicate if a message is outgoing or incoming. + * @ingroup chatroom + */ +L_DECLARE_C_ENUM(ChatMessageDirection, L_ENUM_VALUES_CHAT_MESSAGE_DIRECTION); + L_DECLARE_C_ENUM(ChatRoomState, L_ENUM_VALUES_CHAT_ROOM_STATE); L_DECLARE_C_ENUM(EventLogType, L_ENUM_VALUES_EVENT_LOG_TYPE); diff --git a/include/linphone/enums/chat-message-enums.h b/include/linphone/enums/chat-message-enums.h index f98f9fe7f..048a70213 100644 --- a/include/linphone/enums/chat-message-enums.h +++ b/include/linphone/enums/chat-message-enums.h @@ -32,4 +32,8 @@ F(DeliveredToUser) \ F(Displayed) +#define L_ENUM_VALUES_CHAT_MESSAGE_DIRECTION(F) \ + F(Incoming) \ + F(Outgoing) + #endif // ifndef _CHAT_MESSAGE_ENUMS_H_ diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 39a6cd747..3542edee6 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -1124,7 +1124,7 @@ void ChatMessagePrivate::send() { //TODO Remove : This won't be necessary once we store the contentsList string clearTextMessage; ContentType clearTextContentType; - + if (!getText().empty()) { clearTextMessage = getText().c_str(); } @@ -1271,12 +1271,12 @@ ChatMessage::Direction ChatMessage::getDirection () const { bool ChatMessage::isOutgoing () const { L_D(); - return d->direction == Outgoing; + return d->direction == Direction::Outgoing; } bool ChatMessage::isIncoming () const { L_D(); - return d->direction == Incoming; + return d->direction == Direction::Incoming; } ChatMessage::State ChatMessage::getState() const { @@ -1556,7 +1556,7 @@ int ChatMessage::putCharacter(uint32_t character) { lDebug() << "New line sent, forge a message with content " << d->rttMessage.c_str(); d->setTime(ms_time(0)); d->state = State::Displayed; - d->direction = Outgoing; + d->direction = Direction::Outgoing; setFromAddress(LinphonePrivate::Address(linphone_address_as_string(linphone_address_new(linphone_core_get_identity(lc))))); linphone_chat_message_store(L_GET_C_BACK_PTR(this)); d->rttMessage = ""; diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index d684f931a..90a6c6400 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -33,7 +33,6 @@ LINPHONE_BEGIN_NAMESPACE class Address; class ChatRoom; -class ChatRoomPrivate; class Content; class ErrorInfo; class ChatMessagePrivate; @@ -46,96 +45,92 @@ class LINPHONE_PUBLIC ChatMessage : public Object { public: L_OVERRIDE_SHARED_FROM_THIS(ChatMessage); - enum Direction { - Incoming, - Outgoing - }; - L_DECLARE_ENUM(State, L_ENUM_VALUES_CHAT_MESSAGE_STATE); + L_DECLARE_ENUM(Direction, L_ENUM_VALUES_CHAT_MESSAGE_DIRECTION); - ChatMessage(const std::shared_ptr &room); - virtual ~ChatMessage() = default; + ChatMessage (const std::shared_ptr &chatRoom); + virtual ~ChatMessage () = default; - LinphoneChatMessage * getBackPtr(); + LinphoneChatMessage *getBackPtr (); - std::shared_ptr getChatRoom() const; + std::shared_ptr getChatRoom () const; // ----------------------------------------------------------------------------- // Methods // ----------------------------------------------------------------------------- - void store(); + void store (); - void updateState(State state); + void updateState (State state); - void reSend(); + void reSend (); - void sendDeliveryNotification(LinphoneReason reason); + void sendDeliveryNotification (LinphoneReason reason); - void sendDisplayNotification(); + void sendDisplayNotification (); - int uploadFile(); + int uploadFile (); - int downloadFile(); + int downloadFile (); - void cancelFileTransfer(); + void cancelFileTransfer (); - int putCharacter(uint32_t character); + int putCharacter (uint32_t character); // ----------------------------------------------------------------------------- // Getters & setters // ----------------------------------------------------------------------------- - Direction getDirection() const; - bool isOutgoing() const; - bool isIncoming() const; + Direction getDirection () const; + bool isOutgoing () const; + bool isIncoming () const; - const std::string& getExternalBodyUrl() const; - void setExternalBodyUrl(const std::string &url); + const std::string &getExternalBodyUrl () const; + void setExternalBodyUrl (const std::string &url); - time_t getTime() const; + time_t getTime () const; - bool isSecured() const; - void setIsSecured(bool isSecured); + bool isSecured () const; + void setIsSecured (bool isSecured); - State getState() const; + State getState () const; - const std::string& getId() const; - void setId(const std::string&); + const std::string &getId () const; + void setId (const std::string &); - bool isRead() const; + bool isRead () const; - const std::string& getAppdata() const; - void setAppdata(const std::string &appData); + const std::string &getAppdata () const; + void setAppdata (const std::string &appData); - const Address& getFromAddress() const; - void setFromAddress(Address from); - void setFromAddress(const std::string& from); + const Address &getFromAddress () const; + void setFromAddress (Address from); + void setFromAddress (const std::string &from); - const Address& getToAddress() const; - void setToAddress(Address to); - void setToAddress(const std::string& to); + const Address &getToAddress () const; + void setToAddress (Address to); + void setToAddress (const std::string &to); - const std::string& getFileTransferFilepath() const; - void setFileTransferFilepath(const std::string &path); + const std::string &getFileTransferFilepath () const; + void setFileTransferFilepath (const std::string &path); - const LinphoneErrorInfo * getErrorInfo() const; + const LinphoneErrorInfo *getErrorInfo () const; - bool isReadOnly() const; + bool isReadOnly () const; - const std::list& getContents() const; - void addContent(const Content& content); - void removeContent(const Content& content); + const std::list &getContents () const; + void addContent (const Content &content); + void removeContent (const Content &content); - const Content& getInternalContent() const; - void setInternalContent(const Content& content); + const Content &getInternalContent () const; + void setInternalContent (const Content &content); - std::string getCustomHeaderValue(const std::string &headerName) const; - void addCustomHeader(const std::string &headerName, const std::string &headerValue); - void removeCustomHeader(const std::string &headerName); + std::string getCustomHeaderValue (const std::string &headerName) const; + void addCustomHeader (const std::string &headerName, const std::string &headerValue); + void removeCustomHeader (const std::string &headerName); protected: - explicit ChatMessage(ChatMessagePrivate &p); + explicit ChatMessage (ChatMessagePrivate &p); private: L_DECLARE_PRIVATE(ChatMessage); diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index eea1feab0..678a82d3c 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -280,7 +280,7 @@ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colN message->addContent(content); Address peer(peerAddress.asString()); - if (atoi(argv[3]) == ChatMessage::Direction::Incoming) { + if (atoi(argv[3]) == static_cast(ChatMessage::Direction::Incoming)) { message->getPrivate()->setDirection(ChatMessage::Direction::Incoming); message->setFromAddress(peer); } else { @@ -552,7 +552,7 @@ void ChatRoom::compose () { shared_ptr ChatRoom::createFileTransferMessage (const LinphoneContent *initialContent) { L_D(); shared_ptr chatMessage = createMessage(); - + /* TODO Content content; content.setContentType(ContentType::FileTransfer); From 6c8034768d3f75fd0e07a4cfc76123b3b6b71576 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 11 Oct 2017 12:53:04 +0200 Subject: [PATCH 0422/2215] More work on JNI layer for Java wrapper for listeners --- wrappers/java/genwrapper.py | 134 +++++++++++++++++++++++++++++++----- wrappers/java/jni.mustache | 67 +++++++++++++++++- 2 files changed, 184 insertions(+), 17 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 18422d5b3..d2cd01213 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -84,6 +84,61 @@ class JavaTranslator(object): def translate_argument_name(self, _argName): return _argName.to_snake_case() + def translate_java_jni_enum_name(self, _enum): + name = _enum.name.to_camel_case() + if name in ENUMS_LIST: + className = ENUMS_LIST[name] + if name.startswith(className): + name = name[len(className):] + name = className + '$' + name + return name + + def translate_java_jni_base_type_name(self, _type): + if _type == 'string': + return 'Ljava/lang/String;' + elif _type == 'integer': + return 'I' + elif _type == 'boolean': + return 'Z' + elif _type == 'floatant': + return 'F' + elif _type == 'size': + return 'I' + elif _type == 'time': + return 'I' + elif _type == 'status': + return 'I' + elif _type == 'string_array': + return '[Ljava/lang/String;' + elif _type == 'character': + return 'C' + elif _type == 'void': + return 'V' + return _type + + def translate_as_c_base_type(self, _type): + if _type == 'string': + return 'const char *' + elif _type == 'integer': + return 'int' + elif _type == 'boolean': + return 'bool_t' + elif _type == 'floatant': + return 'float' + elif _type == 'size': + return 'size_t' + elif _type == 'time': + return 'time_t' + elif _type == 'status': + return 'int' + elif _type == 'string_array': + return 'const char **' + elif _type == 'character': + return 'char' + elif _type == 'void': + return 'void *' + return _type + def translate_type(self, _type, native=False, jni=False, isReturn=False): if type(_type) is AbsApi.ListType: if jni: @@ -163,11 +218,10 @@ class JavaTranslator(object): return 'jchar' return 'char' elif _type.name == 'void': + if isReturn: + return 'void' if jni: - if isReturn: - return 'void' - else: - return 'jobject' + return 'jobject' return 'Object' return _type.name @@ -334,6 +388,57 @@ class JavaTranslator(object): return classDict + def translate_jni_interface(self, className, _method): + methodDict = {} + listenerName = 'Linphone' + className.to_camel_case() + methodDict['classCName'] = listenerName[:-8] #Remove Listener at the end + methodDict['className'] = className.to_camel_case() + methodDict['classImplName'] = className.to_camel_case() + 'Impl' + methodDict['jniPath'] = self.jni_path + methodDict['cPrefix'] = 'linphone_' + className.to_snake_case() + methodDict['callbackName'] = methodDict['cPrefix'] + '_' + _method.name.to_snake_case() + methodDict['jname'] = _method.name.to_camel_case(lower=True) + methodDict['return'] = self.translate_type(_method.returnType, jni=True, isReturn=True) + + methodDict['jobjects'] = [] + methodDict['jenums'] = [] + methodDict['jstrings'] = [] + methodDict['params'] = '' + methodDict['jparams'] = '(' + methodDict['params_impl'] = '' + for arg in _method.args: + argname = self.translate_argument_name(arg.name) + if arg is not _method.args[0]: + methodDict['params'] += ', ' + methodDict['params_impl'] += ', ' + + if type(arg.type) is AbsApi.ClassType: + methodDict['params'] += 'Linphone' + arg.type.desc.name.to_camel_case() + ' *' + (argname if arg is not _method.args[0] else 'cptr') + methodDict['jparams'] += 'L' + self.jni_path + arg.type.desc.name.to_camel_case() + ';' + methodDict['params_impl'] += 'j_' + argname + methodDict['jobjects'].append({'objectName': argname, 'className': arg.type.desc.name.to_camel_case(),}) + elif type(arg.type) is AbsApi.BaseType: + methodDict['params'] += self.translate_as_c_base_type(arg.type.name) + ' ' + argname + methodDict['jparams'] += self.translate_java_jni_base_type_name(arg.type.name) + if arg.type.name == 'string': + methodDict['params_impl'] += 'j_' + argname + methodDict['jstrings'].append({'stringName': argname,}) + else: + methodDict['params_impl'] += argname + elif type(arg.type) is AbsApi.EnumType: + methodDict['params'] += 'Linphone' + arg.type.desc.name.to_camel_case() + ' ' + argname + methodDict['jparams'] += 'L' + self.jni_path + self.translate_java_jni_enum_name(arg.type.desc) + ';' + methodDict['params_impl'] += 'j_' + argname + methodDict['jenums'].append({'enumName': argname, 'cEnumPrefix': 'linphone_' + arg.type.desc.name.to_snake_case()}) + + methodDict['jparams'] += ')' + if (methodDict['return'] == 'void'): + methodDict['jparams'] += 'V' + else: + pass #TODO + + return methodDict + def translate_interface(self, _class): interfaceDict = { 'methods': [], @@ -344,6 +449,7 @@ class JavaTranslator(object): for method in _class.methods: interfaceDict['methods'].append(self.translate_method(method)) + interfaceDict['jniMethods'].append(self.translate_jni_interface(_class.name, method)) return interfaceDict @@ -392,15 +498,7 @@ class JavaEnum(object): self.filename = self.className + ".java" self.values = self._class['values'] self.doc = self._class['doc'] - self.jniMethods = self._class['jniMethods'] - - name = _enum.name.to_camel_case() - if name in ENUMS_LIST: - className = ENUMS_LIST[name] - if name.startswith(className): - name = name[len(className):] - name = className + '$' + name - self.jniName = name + self.jniName = translator.translate_java_jni_enum_name(_enum) class JavaInterface(object): def __init__(self, package, _interface, translator): @@ -446,8 +544,9 @@ class JavaClass(object): class Jni(object): def __init__(self, package): - self.objects = [] self.enums = [] + self.interfaces = [] + self.objects = [] self.methods = [] self.jni_package = '' self.jni_path = '' @@ -479,6 +578,10 @@ class Jni(object): } self.objects.append(obj) + def add_interfaces(self, name, interfaces): + for interface in interfaces: + self.interfaces.append(interface) + def add_methods(self, name, methods): for method in methods: self.methods.append(method) @@ -560,7 +663,6 @@ class GenWrapper(object): self.enums[javaenum.className] = javaenum except AbsApi.Error as e: print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) - #self.jni.add_methods(javaenum.className, javaenum.jniMethods) def render_java_interface(self, _class): if _class is not None: @@ -571,7 +673,7 @@ class GenWrapper(object): self.interfaces[javaInterfaceStub.classNameStub] = javaInterfaceStub except AbsApi.Error as e: print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) - #self.jni.add_methods(javainterface.className, javainterface.jniMethods) + self.jni.add_interfaces(javainterface.className, javainterface.jniMethods) def render_java_class(self, _class): if _class is not None: diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index a43ccc4cc..00bcbf0ba 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -66,6 +66,8 @@ static jlong GetObjectNativePtr(JNIEnv *env, jobject object) { return nativePtr; } +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + class LinphoneJavaBindings { public: LinphoneJavaBindings(JNIEnv *env) { @@ -86,7 +88,7 @@ public: {{#objects}} env->DeleteGlobalRef({{cPrefix}}_class); {{/objects}} - + {{#enums}} env->DeleteGlobalRef({{cPrefix}}_class); {{/enums}} @@ -103,6 +105,8 @@ public: {{/enums}} }; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + {{#objects}} jobject get{{className}}(JNIEnv *env, {{classCName}} *ptr) { jobject jobj = 0; @@ -143,6 +147,67 @@ void Java_{{jniPrefix}}{{classImplName}}_unref(JNIEnv* env, jobject thiz, jlong } {{/objects}} +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static inline void handle_possible_java_exception(JNIEnv *env, jobject listener) +{ + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + ms_error("Listener %p raised an exception",listener); + } +} + +{{#interfaces}} +static {{return}} {{callbackName}}({{params}}) { + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_factory_get_user_data(linphone_factory_get()); + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + + {{classCName}}Cbs *cbs = {{cPrefix}}_get_callbacks(cptr); + jobject jlistener = (jobject) {{cPrefix}}_cbs_get_user_data(cbs); + + if (jlistener == NULL) { + ms_warning("{{name}}() notification without listener"); + return ; + } + + jclass jlistenerClass = (jclass) env->GetObjectClass(jlistener); + jmethodID jcallback = env->GetMethodID(jlistenerClass, "{{jname}}", "{{jparams}}"); + env->DeleteLocalRef(jlistenerClass); + + {{#jobjects}} + jobject j_{{objectName}} = get{{className}}(env, {{objectName}}); + {{/jobjects}} + {{#jenums}} + jobject j_{{enumName}} = env->CallStaticObjectMethod(ljb->{{cEnumPrefix}}_class, ljb->{{cEnumPrefix}}_class_constructor_from_int, (jint){{enumName}}); + {{/jenums}} + {{#jstrings}} + jstring j_{{stringName}} = {{stringName}} ? env->NewStringUTF({{stringName}}) : NULL; + {{/jstrings}} + + env->CallVoidMethod(jlistener, jcallback, {{params_impl}}); + + {{#jobjects}} + if (j_{{objectName}}) { + env->DeleteLocalRef(j_{{objectName}}); + } + {{/jobjects}} + {{#jstrings}} + if (j_{{stringName}}) { + env->DeleteLocalRef(j_{{stringName}}); + } + {{/jstrings}} + + handle_possible_java_exception(env, jlistener); +} + +{{/interfaces}} +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {{#methods}} {{return}} {{name}}({{params}}) { From da407f791d85abbd5c5e1d9906dee53b6196a89b Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 11 Oct 2017 13:36:51 +0200 Subject: [PATCH 0423/2215] add device addition/removal notification tester + lil fix --- .../local-conference-event-handler.cpp | 4 + tester/conference-event-tester.cpp | 157 +++++++++++++++++- 2 files changed, 160 insertions(+), 1 deletion(-) diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 3594c160a..4c01fb859 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -186,6 +186,8 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceAdded (c string entity = conf->getConferenceAddress()->asStringUriOnly(); string subject = conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); + UsersType users; + confInfo.setUsers(users); UserType user = UserType(); UserRolesType roles; @@ -209,6 +211,8 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceRemoved string entity = conf->getConferenceAddress()->asStringUriOnly(); string subject = conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); + UsersType users; + confInfo.setUsers(users); UserType user = UserType(); UserRolesType roles; diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index f3d30e5b6..f4554e5a6 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -117,6 +117,24 @@ static const char *first_notify = \ " sendrecv"\ " "\ " "\ +" "\ +" connected"\ +" dialed-out"\ +" "\ +" 2005-03-04T20:00:00Z"\ +" sip:mike@example.com"\ +" "\ +" "\ +" "\ +" main audio"\ +" audio"\ +" "\ +" 534232"\ +" sendrecv"\ +" "\ +" "\ " "\ " "\ " "; @@ -513,6 +531,11 @@ void first_notify_parsing() { BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); BC_ASSERT_TRUE(!tester.participants.find(linphone_address_as_string(bobAddr))->second); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr))->second); + BC_ASSERT_EQUAL(tester.participantDevices.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.participantDevices.find(linphone_address_as_string(bobAddr)) != tester.participantDevices.end()); + BC_ASSERT_TRUE(tester.participantDevices.find(linphone_address_as_string(aliceAddr)) != tester.participantDevices.end()); + BC_ASSERT_EQUAL(tester.participantDevices.find(linphone_address_as_string(bobAddr))->second, 1, int, "%d"); + BC_ASSERT_EQUAL(tester.participantDevices.find(linphone_address_as_string(aliceAddr))->second, 2, int, "%d"); linphone_address_unref(bobAddr); linphone_address_unref(aliceAddr); @@ -572,6 +595,7 @@ void participant_added_parsing() { delete[] notify; BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_EQUAL(tester.participantDevices.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); BC_ASSERT_TRUE(!tester.participants.find(linphone_address_as_string(bobAddr))->second); @@ -583,6 +607,7 @@ void participant_added_parsing() { delete[] notify_added; BC_ASSERT_EQUAL(tester.participants.size(), 3, int, "%d"); + BC_ASSERT_EQUAL(tester.participantDevices.size(), 3, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(frankAddr)) != tester.participants.end()); BC_ASSERT_TRUE(!tester.participants.find(linphone_address_as_string(frankAddr))->second); @@ -616,6 +641,7 @@ void participant_not_added_parsing() { delete[] notify; BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_EQUAL(tester.participantDevices.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); BC_ASSERT_TRUE(!tester.participants.find(linphone_address_as_string(bobAddr))->second); @@ -658,6 +684,7 @@ void participant_deleted_parsing() { delete[] notify; BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_EQUAL(tester.participantDevices.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(linphone_address_as_string(aliceAddr)) != tester.participants.end()); BC_ASSERT_TRUE(!tester.participants.find(linphone_address_as_string(bobAddr))->second); @@ -669,6 +696,7 @@ void participant_deleted_parsing() { delete[] notify_deleted; BC_ASSERT_EQUAL(tester.participants.size(), 1, int, "%d"); + BC_ASSERT_EQUAL(tester.participantDevices.size(), 1, int, "%d"); BC_ASSERT_FALSE(tester.participants.find(linphone_address_as_string(bobAddr)) != tester.participants.end()); linphone_address_unref(bobAddr); @@ -842,6 +870,7 @@ void send_added_notify() { tester.handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_EQUAL(tester.participantDevices.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(bobAddr.asString()) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(aliceAddr.asString()) != tester.participants.end()); BC_ASSERT_TRUE(!tester.participants.find(bobAddr.asString())->second); @@ -851,6 +880,7 @@ void send_added_notify() { tester.handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester.participants.size(), 3, int, "%d"); + BC_ASSERT_EQUAL(tester.participantDevices.size(), 3, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(bobAddr.asString()) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(aliceAddr.asString()) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(frankAddr.asString()) != tester.participants.end()); @@ -895,6 +925,7 @@ void send_removed_notify() { tester.handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_EQUAL(tester.participantDevices.size(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(bobAddr.asString()) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(aliceAddr.asString()) != tester.participants.end()); BC_ASSERT_TRUE(!tester.participants.find(bobAddr.asString())->second); @@ -904,6 +935,7 @@ void send_removed_notify() { tester.handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester.participants.size(), 1, int, "%d"); + BC_ASSERT_EQUAL(tester.participantDevices.size(), 1, int, "%d"); BC_ASSERT_FALSE(tester.participants.find(bobAddr.asString()) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(aliceAddr.asString()) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(aliceAddr.asString())->second); @@ -1068,6 +1100,127 @@ void send_subject_changed_notify () { linphone_core_manager_destroy(pauline); } +void send_device_added_notify() { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager *pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + char *identityStr = linphone_address_as_string(pauline->identity); + Address addr(identityStr); + bctbx_free(identityStr); + ConferenceEventTester tester(marie->lc, addr); + LocalConference localConf(pauline->lc, addr); + LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); + char *bobAddrStr = linphone_address_as_string(cBobAddr); + Address bobAddr(bobAddrStr); + bctbx_free(bobAddrStr); + linphone_address_unref(cBobAddr); + LinphoneAddress *cAliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); + char *aliceAddrStr = linphone_address_as_string(cAliceAddr); + Address aliceAddr(aliceAddrStr); + bctbx_free(aliceAddrStr); + linphone_address_unref(cAliceAddr); + + CallSessionParams params; + localConf.addParticipant(bobAddr, ¶ms, false); + localConf.addParticipant(aliceAddr, ¶ms, false); + shared_ptr alice = localConf.findParticipant(aliceAddr); + L_GET_PRIVATE(alice)->setAdmin(true); + LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); + L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; + string notify = localHandlerPrivate->createNotifyFullState(); + + RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); + L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; + tester.handler->notifyReceived(notify); + + BC_ASSERT_EQUAL(tester.participantDevices.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.participantDevices.find(bobAddr.asString()) != tester.participantDevices.end()); + BC_ASSERT_TRUE(tester.participantDevices.find(aliceAddr.asString()) != tester.participantDevices.end()); + BC_ASSERT_EQUAL(tester.participantDevices.find(bobAddr.asString())->second, 0, int, "%d"); + BC_ASSERT_EQUAL(tester.participantDevices.find(aliceAddr.asString())->second, 0, int, "%d"); + + notify = localHandlerPrivate->createNotifyParticipantDeviceAdded(aliceAddr, aliceAddr); + tester.handler->notifyReceived(notify); + + BC_ASSERT_EQUAL(tester.participantDevices.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.participantDevices.find(bobAddr.asString()) != tester.participantDevices.end()); + BC_ASSERT_TRUE(tester.participantDevices.find(aliceAddr.asString()) != tester.participantDevices.end()); + BC_ASSERT_EQUAL(tester.participantDevices.find(bobAddr.asString())->second, 0, int, "%d"); + BC_ASSERT_EQUAL(tester.participantDevices.find(aliceAddr.asString())->second, 1, int, "%d"); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +void send_device_removed_notify() { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager *pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + char *identityStr = linphone_address_as_string(pauline->identity); + Address addr(identityStr); + bctbx_free(identityStr); + ConferenceEventTester tester(marie->lc, addr); + LocalConference localConf(pauline->lc, addr); + LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); + char *bobAddrStr = linphone_address_as_string(cBobAddr); + Address bobAddr(bobAddrStr); + bctbx_free(bobAddrStr); + linphone_address_unref(cBobAddr); + LinphoneAddress *cAliceAddr = linphone_core_interpret_url(marie->lc, aliceUri); + char *aliceAddrStr = linphone_address_as_string(cAliceAddr); + Address aliceAddr(aliceAddrStr); + bctbx_free(aliceAddrStr); + linphone_address_unref(cAliceAddr); + + CallSessionParams params; + localConf.addParticipant(bobAddr, ¶ms, false); + localConf.addParticipant(aliceAddr, ¶ms, false); + localConf.setSubject("A random test subject"); + shared_ptr alice = localConf.findParticipant(aliceAddr); + L_GET_PRIVATE(alice)->setAdmin(true); + LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); + L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; + string notify = localHandlerPrivate->createNotifyFullState(); + + RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); + L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; + tester.handler->notifyReceived(notify); + + BC_ASSERT_EQUAL(tester.participantDevices.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.participantDevices.find(bobAddr.asString()) != tester.participantDevices.end()); + BC_ASSERT_TRUE(tester.participantDevices.find(aliceAddr.asString()) != tester.participantDevices.end()); + BC_ASSERT_EQUAL(tester.participantDevices.find(bobAddr.asString())->second, 0, int, "%d"); + BC_ASSERT_EQUAL(tester.participantDevices.find(aliceAddr.asString())->second, 0, int, "%d"); + + notify = localHandlerPrivate->createNotifyParticipantDeviceAdded(aliceAddr, aliceAddr); + tester.handler->notifyReceived(notify); + + BC_ASSERT_EQUAL(tester.participantDevices.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.participantDevices.find(bobAddr.asString()) != tester.participantDevices.end()); + BC_ASSERT_TRUE(tester.participantDevices.find(aliceAddr.asString()) != tester.participantDevices.end()); + BC_ASSERT_EQUAL(tester.participantDevices.find(bobAddr.asString())->second, 0, int, "%d"); + BC_ASSERT_EQUAL(tester.participantDevices.find(aliceAddr.asString())->second, 1, int, "%d"); + + notify = localHandlerPrivate->createNotifyParticipantDeviceRemoved(aliceAddr, aliceAddr); + tester.handler->notifyReceived(notify); + + BC_ASSERT_EQUAL(tester.participantDevices.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.participantDevices.find(bobAddr.asString()) != tester.participantDevices.end()); + BC_ASSERT_TRUE(tester.participantDevices.find(aliceAddr.asString()) != tester.participantDevices.end()); + BC_ASSERT_EQUAL(tester.participantDevices.find(bobAddr.asString())->second, 0, int, "%d"); + BC_ASSERT_EQUAL(tester.participantDevices.find(aliceAddr.asString())->second, 0, int, "%d"); + + notify = localHandlerPrivate->createNotifyParticipantDeviceRemoved(aliceAddr, aliceAddr); + tester.handler->notifyReceived(notify); + + BC_ASSERT_EQUAL(tester.participantDevices.size(), 2, int, "%d"); + BC_ASSERT_TRUE(tester.participantDevices.find(bobAddr.asString()) != tester.participantDevices.end()); + BC_ASSERT_TRUE(tester.participantDevices.find(aliceAddr.asString()) != tester.participantDevices.end()); + BC_ASSERT_EQUAL(tester.participantDevices.find(bobAddr.asString())->second, 0, int, "%d"); + BC_ASSERT_EQUAL(tester.participantDevices.find(aliceAddr.asString())->second, 0, int, "%d"); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + test_t conference_event_tests[] = { TEST_NO_TAG("First notify parsing", first_notify_parsing), TEST_NO_TAG("First notify parsing wrong conf", first_notify_parsing_wrong_conf), @@ -1081,7 +1234,9 @@ test_t conference_event_tests[] = { TEST_NO_TAG("Send participant removed notify", send_removed_notify), TEST_NO_TAG("Send participant admined notify", send_admined_notify), TEST_NO_TAG("Send participant unadmined notify", send_unadmined_notify), - TEST_NO_TAG("Send subject changed notify", send_subject_changed_notify) + TEST_NO_TAG("Send subject changed notify", send_subject_changed_notify), + TEST_NO_TAG("Send device added notify", send_device_added_notify), + TEST_NO_TAG("Send device removed notify", send_device_removed_notify) }; test_suite_t conference_event_test_suite = { From 935e429609b167880e21be94f7ae0bd67971c60d Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 11 Oct 2017 14:09:08 +0200 Subject: [PATCH 0424/2215] fix(Core): clean some dirty code... --- coreapi/authentication.c | 4 +- coreapi/bellesip_sal/sal_op_impl.c | 11 ++-- coreapi/carddav.c | 62 +++++++++++---------- coreapi/chat.c | 3 +- coreapi/friend.c | 1 + coreapi/friendlist.c | 12 +++-- coreapi/info.c | 8 +-- coreapi/linphonecore.c | 10 ++-- coreapi/vcard.cc | 3 +- include/linphone/api/c-chat-message.h | 28 +++++----- src/c-wrapper/api/c-chat-message.cpp | 38 +++++++------ src/chat/chat-message.cpp | 36 ++----------- src/chat/chat-message.h | 77 ++++++++------------------- src/chat/chat-room.cpp | 24 ++++----- src/chat/real-time-text-chat-room.cpp | 8 ++- src/sal/sal.cpp | 4 +- 16 files changed, 136 insertions(+), 193 deletions(-) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 070d308a5..17d84508b 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -28,8 +28,6 @@ #include "c-wrapper/c-wrapper.h" -using namespace LinphonePrivate; - static void _linphone_auth_info_uninit(LinphoneAuthInfo *obj); static void _linphone_auth_info_copy(LinphoneAuthInfo *dst, const LinphoneAuthInfo *src); @@ -438,7 +436,7 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) /* retry pending authentication operations */ for(l=elem=lc->sal->get_pending_auths();elem!=NULL;elem=elem->next){ - SalOp *op=(SalOp*)elem->data; + LinphonePrivate::SalOp *op= static_cast(elem->data); LinphoneAuthInfo *ai; const SalAuthInfo *req_sai=op->get_auth_requested(); ai=(LinphoneAuthInfo*)_linphone_core_find_auth_info(lc,req_sai->realm,req_sai->username,req_sai->domain, FALSE); diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 80f661b54..41190959f 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -19,8 +19,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "sal_impl.h" #include "sal/sal.h" -using namespace LinphonePrivate; - SalReason _sal_reason_from_sip_code(int code) { if (code>=100 && code<300) return SalReasonNone; @@ -82,13 +80,12 @@ SalReason _sal_reason_from_sip_code(int code) { } const SalErrorInfo *sal_error_info_none(void){ - static SalErrorInfo none={ + static const SalErrorInfo none = { SalReasonNone, (char *)"Ok", 200, NULL, - NULL, - + NULL }; return &none; } @@ -122,7 +119,7 @@ void sal_error_info_set(SalErrorInfo *ei, SalReason reason, const char *protocol else{ ei->reason=reason; if (code == 0) { - code = to_sip_code(reason); + code = LinphonePrivate::to_sip_code(reason); } } ei->protocol_code=code; @@ -134,4 +131,4 @@ void sal_error_info_set(SalErrorInfo *ei, SalReason reason, const char *protocol ei->full_string=ms_strdup_printf("%s %s",ei->status_string,ei->warnings); else ei->full_string=ms_strdup(ei->status_string); } -} \ No newline at end of file +} diff --git a/coreapi/carddav.c b/coreapi/carddav.c index 91a742a4a..880d778e2 100644 --- a/coreapi/carddav.c +++ b/coreapi/carddav.c @@ -20,8 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/core.h" #include "private.h" -using namespace LinphonePrivate; - LinphoneCardDavContext* linphone_carddav_context_new(LinphoneFriendList *lfl) { LinphoneCardDavContext *carddav_context = NULL; @@ -69,7 +67,7 @@ static void linphone_carddav_client_to_server_sync_done(LinphoneCardDavContext * if (!success) { ms_error("[carddav] CardDAV client to server sync failure: %s", msg); } - + if (cdc->sync_done_cb) { cdc->sync_done_cb(cdc, success, msg); } @@ -82,7 +80,7 @@ static void linphone_carddav_server_to_client_sync_done(LinphoneCardDavContext * } else { ms_error("[carddav] CardDAV server to client sync failure: %s", msg); } - + if (cdc->sync_done_cb) { cdc->sync_done_cb(cdc, success, msg); } @@ -120,7 +118,7 @@ static void linphone_carddav_vcards_pulled(LinphoneCardDavContext *cdc, bctbx_li LinphoneVcard *lvc = linphone_vcard_context_get_vcard_from_buffer(cdc->friend_list->lc->vcard_context, vCard->vcard); LinphoneFriend *lf = NULL; bctbx_list_t *local_friend = NULL; - + if (lvc) { // Compute downloaded vCards' URL and save it (+ eTag) char *vCard_name = strrchr(vCard->url, '/'); @@ -134,7 +132,7 @@ static void linphone_carddav_vcards_pulled(LinphoneCardDavContext *cdc, bctbx_li linphone_vcard_unref(lvc); /*ref is now owned by friend*/ if (lf) { local_friend = bctbx_list_find_custom(friends, (int (*)(const void*, const void*))find_matching_friend, lf); - + if (local_friend) { LinphoneFriend *lf2 = (LinphoneFriend *)local_friend->data; lf->storage_id = lf2->storage_id; @@ -144,7 +142,7 @@ static void linphone_carddav_vcards_pulled(LinphoneCardDavContext *cdc, bctbx_li lf->presence_received = lf2->presence_received; lf->lc = lf2->lc; lf->friend_list = lf2->friend_list; - + if (cdc->contact_updated_cb) { ms_debug("Contact updated: %s", linphone_friend_get_name(lf)); cdc->contact_updated_cb(cdc, lf, lf2); @@ -224,7 +222,7 @@ static void linphone_carddav_vcards_fetched(LinphoneCardDavContext *cdc, bctbx_l bctbx_list_t *friends = cdc->friend_list->friends; bctbx_list_t *friends_to_remove = NULL; bctbx_list_t *temp_list = NULL; - + while (friends) { LinphoneFriend *lf = (LinphoneFriend *)friends->data; if (lf) { @@ -260,7 +258,7 @@ static void linphone_carddav_vcards_fetched(LinphoneCardDavContext *cdc, bctbx_l friends_to_remove = bctbx_list_next(friends_to_remove); } temp_list = bctbx_list_free_with_data(temp_list, (void (*)(void *))linphone_friend_unref); - + linphone_carddav_pull_vcards(cdc, vCards); bctbx_list_free_with_data(vCards, (void (*)(void *))linphone_carddav_response_free); } @@ -340,22 +338,22 @@ static void linphone_carddav_query_free(LinphoneCardDavQuery *query) { if (!query) { return; } - + if (query->http_request_listener) { belle_sip_object_unref(query->http_request_listener); query->http_request_listener = NULL; } - + // Context will be freed later (in sync_done) query->context = NULL; - + if (query->url) { ms_free(query->url); } if (query->body) { ms_free(query->body); } - + ms_free(query); } @@ -380,7 +378,7 @@ static bool_t is_query_client_to_server_sync(LinphoneCardDavQuery *query) { static void process_response_from_carddav_request(void *data, const belle_http_response_event_t *event) { LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)data; - + if (event->response) { int code = belle_http_response_get_status_code(event->response); if (code == 207 || code == 200 || code == 201 || code == 204) { @@ -471,7 +469,7 @@ static void process_auth_requested_from_carddav_request(void *data, belle_sip_au const char *realm = belle_sip_auth_event_get_realm(event); belle_generic_uri_t *uri = belle_generic_uri_parse(query->url); const char *domain = belle_generic_uri_get_host(uri); - + if (cdc->auth_info) { belle_sip_auth_event_set_username(event, cdc->auth_info->username); belle_sip_auth_event_set_passwd(event, cdc->auth_info->passwd); @@ -479,7 +477,7 @@ static void process_auth_requested_from_carddav_request(void *data, belle_sip_au } else { LinphoneCore *lc = cdc->friend_list->lc; const bctbx_list_t *auth_infos = linphone_core_get_auth_info_list(lc); - + ms_debug("Looking for auth info for domain %s and realm %s", domain, realm); while (auth_infos) { LinphoneAuthInfo *auth_info = (LinphoneAuthInfo *)auth_infos->data; @@ -494,7 +492,7 @@ static void process_auth_requested_from_carddav_request(void *data, belle_sip_au } auth_infos = bctbx_list_next(auth_infos); } - + if (!auth_infos) { ms_error("[carddav] Authentication requested during CardDAV request sending, and username/password weren't provided"); if (is_query_client_to_server_sync(query)) { @@ -525,7 +523,7 @@ static void linphone_carddav_send_query(LinphoneCardDavQuery *query) { return; } req = belle_http_request_create(query->method, uri, belle_sip_header_content_type_create("application", "xml; charset=utf-8"), NULL); - + if (!req) { if (cdc && cdc->sync_done_cb) { cdc->sync_done_cb(cdc, FALSE, "Could not create belle_http_request_t"); @@ -535,7 +533,7 @@ static void linphone_carddav_send_query(LinphoneCardDavQuery *query) { linphone_carddav_query_free(query); return; } - + ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent(cdc->friend_list->lc), linphone_core_get_version()); belle_sip_message_add_header((belle_sip_message_t *)req, belle_sip_header_create("User-Agent", ua)); ms_free(ua); @@ -546,12 +544,12 @@ static void linphone_carddav_send_query(LinphoneCardDavQuery *query) { } else if (strcmp(query->method, "PUT")) { belle_sip_message_add_header((belle_sip_message_t *)req, belle_sip_header_create("If-None-Match", "*")); } - + if (query->body) { bh = belle_sip_memory_body_handler_new_copy_from_buffer(query->body, strlen(query->body), NULL, NULL); belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), bh ? BELLE_SIP_BODY_HANDLER(bh) : NULL); } - + cbs.process_response = process_response_from_carddav_request; cbs.process_io_error = process_io_error_from_carddav_request; cbs.process_auth_requested = process_auth_requested_from_carddav_request; @@ -575,7 +573,7 @@ static char* generate_url_from_server_address_and_uid(const char *server_url) { char *result = NULL; if (server_url) { char *uuid = reinterpret_cast(ms_malloc(64)); - if (Sal::generate_uuid(uuid, 64) == 0) { + if (LinphonePrivate::Sal::generate_uuid(uuid, 64) == 0) { char *url = reinterpret_cast(ms_malloc(300)); snprintf(url, 300, "%s/linphone-%s.vcf", server_url, uuid); ms_debug("Generated url is %s", url); @@ -594,7 +592,7 @@ void linphone_carddav_put_vcard(LinphoneCardDavContext *cdc, LinphoneFriend *lf) if (!linphone_vcard_get_uid(lvc)) { linphone_vcard_generate_unique_id(lvc); } - + if (!linphone_vcard_get_url(lvc)) { char *url = generate_url_from_server_address_and_uid(cdc->friend_list->uri); if (url) { @@ -609,7 +607,7 @@ void linphone_carddav_put_vcard(LinphoneCardDavContext *cdc, LinphoneFriend *lf) return; } } - + query = linphone_carddav_create_put_query(cdc, lvc); query->user_data = linphone_friend_ref(lf); linphone_carddav_send_query(query); @@ -620,11 +618,11 @@ void linphone_carddav_put_vcard(LinphoneCardDavContext *cdc, LinphoneFriend *lf) } else { msg = "Unknown error"; } - + if (msg) { ms_error("[carddav] %s", msg); } - + if (cdc && cdc->sync_done_cb) { cdc->sync_done_cb(cdc, FALSE, msg); } @@ -647,7 +645,7 @@ void linphone_carddav_delete_vcard(LinphoneCardDavContext *cdc, LinphoneFriend * LinphoneVcard *lvc = linphone_friend_get_vcard(lf); if (lvc && linphone_vcard_get_uid(lvc) && linphone_vcard_get_etag(lvc)) { LinphoneCardDavQuery *query = NULL; - + if (!linphone_vcard_get_url(lvc)) { char *url = generate_url_from_server_address_and_uid(cdc->friend_list->uri); if (url) { @@ -662,7 +660,7 @@ void linphone_carddav_delete_vcard(LinphoneCardDavContext *cdc, LinphoneFriend * return; } } - + query = linphone_carddav_create_delete_query(cdc, lvc); linphone_carddav_send_query(query); } else { @@ -674,11 +672,11 @@ void linphone_carddav_delete_vcard(LinphoneCardDavContext *cdc, LinphoneFriend * } else if (!linphone_vcard_get_etag(lvc)) { msg = "LinphoneVcard doesn't have an eTag"; } - + if (msg) { ms_error("[carddav] %s", msg); } - + if (cdc && cdc->sync_done_cb) { cdc->sync_done_cb(cdc, FALSE, msg); } @@ -739,7 +737,7 @@ static LinphoneCardDavQuery* linphone_carddav_create_addressbook_multiget_query( LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)ms_new0(LinphoneCardDavQuery, 1); char *body = (char *)ms_malloc((bctbx_list_size(vcards) + 1) * 300 * sizeof(char)); bctbx_list_t *iterator = vcards; - + query->context = cdc; query->depth = "1"; query->ifmatch = NULL; @@ -760,7 +758,7 @@ static LinphoneCardDavQuery* linphone_carddav_create_addressbook_multiget_query( strcat(body, ""); query->body = ms_strdup(body); ms_free(body); - + return query; } diff --git a/coreapi/chat.c b/coreapi/chat.c index daf9b7bb6..d90e76dbf 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -43,7 +43,6 @@ #include "content/content-type.h" using namespace std; -using namespace LinphonePrivate; void linphone_core_disable_chat(LinphoneCore *lc, LinphoneReason deny_reason) { lc->chat_deny_code = deny_reason; @@ -156,7 +155,7 @@ LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const c return _linphone_core_get_or_create_chat_room(lc, to); } -int linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *sal_msg) { +int linphone_core_message_received(LinphoneCore *lc, LinphonePrivate::SalOp *op, const SalMessage *sal_msg) { LinphoneAddress *addr = linphone_address_new(sal_msg->from); linphone_address_clean(addr); LinphoneChatRoom *cr = linphone_core_get_chat_room(lc, addr); diff --git a/coreapi/friend.c b/coreapi/friend.c index 15df1680c..1f3b1a378 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -43,6 +43,7 @@ #include "c-wrapper/c-wrapper.h" using namespace std; + using namespace LinphonePrivate; const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){ diff --git a/coreapi/friendlist.c b/coreapi/friendlist.c index 2589c4f1d..dd8f8af25 100644 --- a/coreapi/friendlist.c +++ b/coreapi/friendlist.c @@ -23,8 +23,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" -using namespace LinphonePrivate; - BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneFriendListCbs); BELLE_SIP_INSTANCIATE_VPTR(LinphoneFriendListCbs, belle_sip_object_t, @@ -796,7 +794,10 @@ LinphoneFriend * linphone_friend_list_find_friend_by_ref_key(const LinphoneFrien return NULL; } -LinphoneFriend * linphone_friend_list_find_friend_by_inc_subscribe(const LinphoneFriendList *list, SalOp *op) { +LinphoneFriend * linphone_friend_list_find_friend_by_inc_subscribe ( + const LinphoneFriendList *list, + LinphonePrivate::SalOp *op +) { const bctbx_list_t *elem; for (elem = list->friends; elem != NULL; elem = bctbx_list_next(elem)) { LinphoneFriend *lf = (LinphoneFriend *)bctbx_list_get_data(elem); @@ -805,7 +806,10 @@ LinphoneFriend * linphone_friend_list_find_friend_by_inc_subscribe(const Linphon return NULL; } -LinphoneFriend * linphone_friend_list_find_friend_by_out_subscribe(const LinphoneFriendList *list, SalOp *op) { +LinphoneFriend * linphone_friend_list_find_friend_by_out_subscribe ( + const LinphoneFriendList *list, + LinphonePrivate::SalOp *op +) { const bctbx_list_t *elem; for (elem = list->friends; elem != NULL; elem = bctbx_list_next(elem)) { LinphoneFriend *lf = (LinphoneFriend *)bctbx_list_get_data(elem); diff --git a/coreapi/info.c b/coreapi/info.c index 3259c94ca..fb1cd4a17 100644 --- a/coreapi/info.c +++ b/coreapi/info.c @@ -28,8 +28,6 @@ #include "c-wrapper/c-wrapper.h" -using namespace LinphonePrivate; - struct _LinphoneInfoMessage{ belle_sip_object_t base; LinphoneContent *content; @@ -98,7 +96,11 @@ SalCustomHeader *linphone_info_message_get_headers (const LinphoneInfoMessage *i return im->headers; } -void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, SalBodyHandler *body_handler){ +void linphone_core_notify_info_message ( + LinphoneCore* lc, + LinphonePrivate::SalOp *op, + SalBodyHandler *body_handler +) { LinphoneCall *call=(LinphoneCall*)op->get_user_pointer(); if (call){ LinphoneInfoMessage *info=linphone_core_create_info_message(lc); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index d9b99e31d..cfdb0e84e 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -130,10 +130,6 @@ void linphone_core_zrtp_cache_db_init(LinphoneCore *lc, const char *fileName); #include "enum.h" #include "contact_providers_priv.h" - -using namespace LinphonePrivate; - - const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc); static void toggle_video_preview(LinphoneCore *lc, bool_t val); @@ -147,6 +143,8 @@ static void toggle_video_preview(LinphoneCore *lc, bool_t val); #define HOLD_MUSIC_WAV "toy-mono.wav" #define HOLD_MUSIC_MKV "dont_wait_too_long.mkv" +using namespace LinphonePrivate; + extern Sal::Callbacks linphone_sal_callbacks; @@ -3454,7 +3452,7 @@ static void linphone_transfer_routes_to_op(bctbx_list_t *routes, SalOp *op){ void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact, LinphoneProxyConfig *proxy){ bctbx_list_t *routes=NULL; const char *identity; - + if (proxy){ identity=linphone_proxy_config_get_identity(proxy); if (linphone_proxy_config_get_privacy(proxy)!=LinphonePrivacyDefault) { @@ -3479,7 +3477,7 @@ void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const Linphon op->set_to(addr); ms_free(addr); } - + op->set_from(identity); op->set_sent_custom_header(headers); op->set_realm(linphone_proxy_config_get_realm(proxy)); diff --git a/coreapi/vcard.cc b/coreapi/vcard.cc index 8b6251be9..336ecf050 100644 --- a/coreapi/vcard.cc +++ b/coreapi/vcard.cc @@ -32,7 +32,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define VCARD_MD5_HASH_SIZE 16 using namespace std; -using namespace LinphonePrivate; struct _LinphoneVcardContext { shared_ptr parser; @@ -368,7 +367,7 @@ bool_t linphone_vcard_generate_unique_id(LinphoneVcard *vCard) { if (linphone_vcard_get_uid(vCard)) { return FALSE; } - if (Sal::generate_uuid(uuid, sizeof(uuid)) == 0) { + if (LinphonePrivate::Sal::generate_uuid(uuid, sizeof(uuid)) == 0) { char vcard_uuid[sizeof(uuid)+4]; snprintf(vcard_uuid, sizeof(vcard_uuid), "urn:%s", uuid); linphone_vcard_set_uid(vCard, vcard_uuid); diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index d3ef10486..d9f6ad404 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -19,7 +19,7 @@ #ifndef _C_CHAT_MESSAGE_H_ #define _C_CHAT_MESSAGE_H_ - + #include "linphone/api/c-types.h" #include "linphone/api/c-chat-message-cbs.h" @@ -38,13 +38,13 @@ typedef enum _LinphoneChatMessageDir{ LinphoneChatMessageIncoming, LinphoneChatMessageOutgoing } LinphoneChatMessageDir; - + // ============================================================================= - + #ifdef __cplusplus extern "C" { #endif // ifdef __cplusplus - + /** * @addtogroup chatmessage * @{ @@ -94,13 +94,6 @@ LINPHONE_PUBLIC time_t linphone_chat_message_get_time(const LinphoneChatMessage* **/ LINPHONE_PUBLIC bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage* msg); -/** - * Set origin of the message - * @param[in] message #LinphoneChatMessage obj - * @param[in] from #LinphoneAddress origin of this message (copied) - */ -LINPHONE_PUBLIC void linphone_chat_message_set_from_address(LinphoneChatMessage* msg, const LinphoneAddress* from); - /** * Get origin of the message * @param[in] message #LinphoneChatMessage obj @@ -109,11 +102,11 @@ LINPHONE_PUBLIC void linphone_chat_message_set_from_address(LinphoneChatMessage* LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_from_address(LinphoneChatMessage* msg); /** - * Set destination of the message + * Set origin of the message * @param[in] message #LinphoneChatMessage obj - * @param[in] addr #LinphoneAddress destination of this message (copied) + * @param[in] from #LinphoneAddress origin of this message (copied) */ -LINPHONE_PUBLIC void linphone_chat_message_set_to_address(LinphoneChatMessage* msg, const LinphoneAddress* addr); +LINPHONE_PUBLIC void linphone_chat_message_set_from_address(LinphoneChatMessage* msg, const LinphoneAddress* from); /** * Get destination of the message @@ -122,6 +115,13 @@ LINPHONE_PUBLIC void linphone_chat_message_set_to_address(LinphoneChatMessage* m */ LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_to_address(LinphoneChatMessage* msg); +/** + * Set destination of the message + * @param[in] message #LinphoneChatMessage obj + * @param[in] addr #LinphoneAddress destination of this message (copied) + */ +LINPHONE_PUBLIC void linphone_chat_message_set_to_address(LinphoneChatMessage* msg, const LinphoneAddress* addr); + /** * Get the content type of a chat message. * @param[in] message LinphoneChatMessage object diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 9e02fee9a..b60967110 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -35,7 +35,6 @@ // ============================================================================= using namespace std; -using namespace LinphonePrivate; static void _linphone_chat_message_constructor (LinphoneChatMessage *msg); static void _linphone_chat_message_destructor (LinphoneChatMessage *msg); @@ -57,9 +56,9 @@ static void _linphone_chat_message_constructor (LinphoneChatMessage *msg) { static void _linphone_chat_message_destructor (LinphoneChatMessage *msg) { linphone_chat_message_cbs_unref(msg->cbs); msg->cbs = nullptr; - if (msg->from) + if (msg->from) linphone_address_unref(msg->from); - if (msg->to) + if (msg->to) linphone_address_unref(msg->to); if (msg->contentTypeCache) ms_free(msg->contentTypeCache); @@ -123,7 +122,7 @@ void linphone_chat_message_set_is_secured(LinphoneChatMessage *msg, bool_t secur } bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->isOutgoing(); + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getDirection() == LinphonePrivate::ChatMessage::Direction::Outgoing; } LinphoneChatMessageDir linphone_chat_message_get_direction(const LinphoneChatMessage *msg) { @@ -151,11 +150,11 @@ void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessa } const char* linphone_chat_message_get_message_id(const LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getId().c_str(); + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getImdnMessageId().c_str(); } void linphone_chat_message_set_message_id(LinphoneChatMessage *msg, char *id) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setId(L_C_TO_STRING(id)); + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setImdnMessageId(L_C_TO_STRING(id)); } void linphone_chat_message_set_storage_id(LinphoneChatMessage *msg, unsigned int id) { @@ -174,12 +173,6 @@ void linphone_chat_message_set_appdata(LinphoneChatMessage *msg, const char *dat L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setAppdata(L_C_TO_STRING(data)); } -void linphone_chat_message_set_from_address(LinphoneChatMessage *msg, const LinphoneAddress *from) { - LinphonePrivate::Address addr; - if (from) addr = LinphonePrivate::Address(linphone_address_as_string(from)); - else L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFromAddress(addr); -} - const LinphoneAddress *linphone_chat_message_get_from_address(LinphoneChatMessage *msg) { if (msg->from) linphone_address_unref(msg->from); @@ -187,10 +180,10 @@ const LinphoneAddress *linphone_chat_message_get_from_address(LinphoneChatMessag return msg->from; } -void linphone_chat_message_set_to_address(LinphoneChatMessage *msg, const LinphoneAddress *to) { +void linphone_chat_message_set_from_address(LinphoneChatMessage *msg, const LinphoneAddress *from) { LinphonePrivate::Address addr; - if (to) addr = LinphonePrivate::Address(linphone_address_as_string(to)); - else L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setToAddress(addr); + if (from) addr = LinphonePrivate::Address(linphone_address_as_string(from)); + else L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFromAddress(addr); } const LinphoneAddress *linphone_chat_message_get_to_address(LinphoneChatMessage *msg) { @@ -200,6 +193,12 @@ const LinphoneAddress *linphone_chat_message_get_to_address(LinphoneChatMessage return msg->to; } +void linphone_chat_message_set_to_address(LinphoneChatMessage *msg, const LinphoneAddress *to) { + LinphonePrivate::Address addr; + if (to) addr = LinphonePrivate::Address(linphone_address_as_string(to)); + else L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setToAddress(addr); +} + const char *linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage *msg) { return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFileTransferFilepath()); } @@ -216,11 +215,11 @@ void linphone_chat_message_set_http_request(LinphoneChatMessage *msg, belle_http L_GET_PRIVATE_FROM_C_OBJECT(msg)->setHttpRequest(request); } -SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg) { +LinphonePrivate::SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg) { return L_GET_PRIVATE_FROM_C_OBJECT(msg)->getSalOp(); } -void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, SalOp *op) { +void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, LinphonePrivate::SalOp *op) { L_GET_PRIVATE_FROM_C_OBJECT(msg)->setSalOp(op); } @@ -330,7 +329,7 @@ const char * linphone_chat_message_get_content_type(LinphoneChatMessage *msg) { } void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char *content_type) { - L_GET_PRIVATE_FROM_C_OBJECT(msg)->setContentType(ContentType(L_C_TO_STRING(content_type))); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setContentType(LinphonePrivate::ContentType(L_C_TO_STRING(content_type))); } const char *linphone_chat_message_get_text(LinphoneChatMessage *msg) { @@ -359,9 +358,8 @@ const LinphoneAddress *linphone_chat_message_get_peer_address(LinphoneChatMessag } const LinphoneAddress *linphone_chat_message_get_local_address(LinphoneChatMessage *msg) { - if (L_GET_CPP_PTR_FROM_C_OBJECT(msg)->isOutgoing()) { + if (L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getDirection() == LinphonePrivate::ChatMessage::Direction::Outgoing) return linphone_chat_message_get_from_address(msg); - } return linphone_chat_message_get_to_address(msg); } diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 3542edee6..aff6d1048 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -1100,7 +1100,7 @@ void ChatMessagePrivate::send() { } linphone_address_unref(addr); } - q->setFromAddress(identity); + q->setFromAddress(Address(identity)); } } } @@ -1203,7 +1203,7 @@ void ChatMessagePrivate::send() { } //End of TODO Remove - q->setId(op->get_call_id()); /* must be known at that time */ + q->setImdnMessageId(op->get_call_id()); /* must be known at that time */ if (call && linphone_call_get_op(call) == op) { /* In this case, chat delivery status is not notified, so unrefing chat message right now */ @@ -1212,7 +1212,7 @@ void ChatMessagePrivate::send() { } /* If operation failed, we should not change message state */ - if (q->isOutgoing()) { + if (q->getDirection() == ChatMessage::Direction::Outgoing) { setIsReadOnly(true); setState(ChatMessage::State::InProgress); } @@ -1226,12 +1226,6 @@ void ChatMessagePrivate::send() { ChatMessage::ChatMessage (const shared_ptr &room) : Object(*new ChatMessagePrivate(room)) {} -ChatMessage::ChatMessage (ChatMessagePrivate &p) : Object(p) {} - -LinphoneChatMessage * ChatMessage::getBackPtr() { - return L_GET_C_BACK_PTR(this); -} - shared_ptr ChatMessage::getChatRoom () const { L_D(); return d->chatRoom; @@ -1269,27 +1263,17 @@ ChatMessage::Direction ChatMessage::getDirection () const { return d->direction; } -bool ChatMessage::isOutgoing () const { - L_D(); - return d->direction == Direction::Outgoing; -} - -bool ChatMessage::isIncoming () const { - L_D(); - return d->direction == Direction::Incoming; -} - ChatMessage::State ChatMessage::getState() const { L_D(); return d->state; } -const string& ChatMessage::getId () const { +const string& ChatMessage::getImdnMessageId () const { L_D(); return d->id; } -void ChatMessage::setId (const string& id) { +void ChatMessage::setImdnMessageId (const string& id) { L_D(); d->id = id; } @@ -1325,11 +1309,6 @@ void ChatMessage::setFromAddress(Address from) { d->from = from; } -void ChatMessage::setFromAddress(const string& from) { - L_D(); - d->from = Address(from); -} - const Address& ChatMessage::getToAddress () const { L_D(); return d->to; @@ -1340,11 +1319,6 @@ void ChatMessage::setToAddress(Address to) { d->to = to; } -void ChatMessage::setToAddress(const string& to) { - L_D(); - d->to = Address(to); -} - const string& ChatMessage::getFileTransferFilepath() const { L_D(); return d->fileTransferFilePath; diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index 90a6c6400..9900b4dbd 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -34,7 +34,6 @@ LINPHONE_BEGIN_NAMESPACE class Address; class ChatRoom; class Content; -class ErrorInfo; class ChatMessagePrivate; class LINPHONE_PUBLIC ChatMessage : public Object { @@ -49,73 +48,46 @@ public: L_DECLARE_ENUM(Direction, L_ENUM_VALUES_CHAT_MESSAGE_DIRECTION); ChatMessage (const std::shared_ptr &chatRoom); - virtual ~ChatMessage () = default; - LinphoneChatMessage *getBackPtr (); + // ----- TODO: Remove me. + const std::string &getFileTransferFilepath () const; + void setFileTransferFilepath (const std::string &path); + const std::string &getAppdata () const; + void setAppdata (const std::string &appData); + const std::string &getExternalBodyUrl () const; + void setExternalBodyUrl (const std::string &url); + int uploadFile (); + int downloadFile (); + void cancelFileTransfer (); + int putCharacter (uint32_t character); + void updateState (State state); + void reSend (); + void sendDeliveryNotification (LinphoneReason reason); + void sendDisplayNotification (); + void setImdnMessageId (const std::string &imdnMessageId); + void setIsSecured (bool isSecured); + void setFromAddress (Address from); + void setToAddress (Address to); + // ----- TODO: Remove me. std::shared_ptr getChatRoom () const; - // ----------------------------------------------------------------------------- - // Methods - // ----------------------------------------------------------------------------- - void store (); - void updateState (State state); - - void reSend (); - - void sendDeliveryNotification (LinphoneReason reason); - - void sendDisplayNotification (); - - int uploadFile (); - - int downloadFile (); - - void cancelFileTransfer (); - - int putCharacter (uint32_t character); - - // ----------------------------------------------------------------------------- - // Getters & setters - // ----------------------------------------------------------------------------- - - Direction getDirection () const; - bool isOutgoing () const; - bool isIncoming () const; - - const std::string &getExternalBodyUrl () const; - void setExternalBodyUrl (const std::string &url); - time_t getTime () const; bool isSecured () const; - void setIsSecured (bool isSecured); - State getState () const; + Direction getDirection () const; - const std::string &getId () const; - void setId (const std::string &); - - bool isRead () const; - - const std::string &getAppdata () const; - void setAppdata (const std::string &appData); + const std::string &getImdnMessageId () const; const Address &getFromAddress () const; - void setFromAddress (Address from); - void setFromAddress (const std::string &from); - const Address &getToAddress () const; - void setToAddress (Address to); - void setToAddress (const std::string &to); - - const std::string &getFileTransferFilepath () const; - void setFileTransferFilepath (const std::string &path); const LinphoneErrorInfo *getErrorInfo () const; + bool isRead () const; bool isReadOnly () const; const std::list &getContents () const; @@ -129,9 +101,6 @@ public: void addCustomHeader (const std::string &headerName, const std::string &headerValue); void removeCustomHeader (const std::string &headerName); -protected: - explicit ChatMessage (ChatMessagePrivate &p); - private: L_DECLARE_PRIVATE(ChatMessage); L_DISABLE_COPY(ChatMessage); diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index 678a82d3c..c8dabef24 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -118,8 +118,8 @@ void ChatRoomPrivate::sendImdn (const string &payload, LinphoneReason reason) { linphone_configure_op(core, op, peer, nullptr, !!lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0)); shared_ptr msg = q->createMessage(); - msg->setFromAddress(identity); - msg->setToAddress(peerAddress.asString()); + msg->setFromAddress(Address(identity)); + msg->setToAddress(peerAddress); Content content; content.setContentType("message/imdn+xml"); @@ -210,8 +210,8 @@ void ChatRoomPrivate::sendIsComposingNotification () { int retval = -1; shared_ptr msg = q->createMessage(); - msg->setFromAddress(identity); - msg->setToAddress(peerAddress.asString()); + msg->setFromAddress(Address(identity)); + msg->setToAddress(peerAddress); Content content; content.setContentType("application/im-iscomposing+xml"); @@ -298,7 +298,7 @@ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colN message->setAppdata(argv[10]); } if (argv[12]) { - message->setId(argv[12]); + message->setImdnMessageId(argv[12]); } message->setIsSecured((bool)atoi(argv[14])); @@ -404,12 +404,12 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa content.setBody(salMsg->text ? salMsg->text : ""); msg->setInternalContent(content); - msg->setToAddress(op->get_to() ? op->get_to() : linphone_core_get_identity(core)); + msg->setToAddress(Address(op->get_to() ? op->get_to() : linphone_core_get_identity(core))); msg->setFromAddress(peerAddress); msg->getPrivate()->setTime(salMsg->time); msg->getPrivate()->setState(ChatMessage::State::Delivered); msg->getPrivate()->setDirection(ChatMessage::Direction::Incoming); - msg->setId(op->get_call_id()); + msg->setImdnMessageId(op->get_call_id()); const SalCustomHeader *ch = op->get_recv_custom_header(); if (ch) @@ -560,7 +560,7 @@ shared_ptr ChatRoom::createFileTransferMessage (const LinphoneConte chatMessage->addContent(content);*/ chatMessage->setToAddress(d->peerAddress); - chatMessage->setFromAddress(linphone_core_get_identity(d->core)); + chatMessage->setFromAddress(Address(linphone_core_get_identity(d->core))); chatMessage->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); chatMessage->getPrivate()->setFileTransferInformation(linphone_content_copy(initialContent)); @@ -577,7 +577,7 @@ shared_ptr ChatRoom::createMessage (const string &message) { chatMessage->addContent(content); chatMessage->setToAddress(d->peerAddress); - chatMessage->setFromAddress(linphone_core_get_identity(d->core)); + chatMessage->setFromAddress(Address(linphone_core_get_identity(d->core))); return chatMessage; } @@ -683,10 +683,10 @@ list > ChatRoom::getHistoryRange (int startm, int endm) if (!d->messages.empty()) { /* Fill local addr with core identity instead of per message */ for (auto &message : d->messages) { - if (message->isOutgoing()) { - message->setFromAddress(linphone_core_get_identity(d->core)); + if (message->getDirection() == ChatMessage::Direction::Outgoing) { + message->setFromAddress(Address(linphone_core_get_identity(d->core))); } else { - message->setToAddress(linphone_core_get_identity(d->core)); + message->setToAddress(Address(linphone_core_get_identity(d->core))); } } } diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index 2c71170d5..fbff72412 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -69,7 +69,13 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp /* End of message */ lDebug() << "New line received, forge a message with content " << pendingMessage->getPrivate()->getText().c_str(); pendingMessage->setFromAddress(peerAddress); - pendingMessage->setToAddress(linphone_call_get_dest_proxy(call) ? linphone_address_as_string(linphone_call_get_dest_proxy(call)->identity_address) : linphone_core_get_identity(core)); + pendingMessage->setToAddress( + Address( + linphone_call_get_dest_proxy(call) + ? linphone_address_as_string(linphone_call_get_dest_proxy(call)->identity_address) + : linphone_core_get_identity(core) + ) + ); pendingMessage->getPrivate()->setState(ChatMessage::State::Delivered); pendingMessage->getPrivate()->setDirection(ChatMessage::Direction::Incoming); diff --git a/src/sal/sal.cpp b/src/sal/sal.cpp index 2e2b8d86e..974796253 100644 --- a/src/sal/sal.cpp +++ b/src/sal/sal.cpp @@ -78,7 +78,7 @@ void Sal::process_request_event_cb(void *ud, const belle_sip_request_event_t *ev if (dialog) { op=(SalOp*)belle_sip_dialog_get_application_data(dialog); - + if (op == NULL && strcmp("NOTIFY",method) == 0) { /*special case for Dialog created by notify mathing subscribe*/ belle_sip_transaction_t * sub_trans = belle_sip_dialog_get_last_transaction(dialog); @@ -372,7 +372,7 @@ Sal::Sal(MSFactory *factory){ this->prov = belle_sip_stack_create_provider(this->stack,NULL); enable_nat_helper(TRUE); - + listener_callbacks.process_dialog_terminated=process_dialog_terminated_cb; listener_callbacks.process_io_error=process_io_error_cb; listener_callbacks.process_request_event=process_request_event_cb; From 106de2c07376fe1043a03673b1426990f04008f6 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 11 Oct 2017 14:28:52 +0200 Subject: [PATCH 0425/2215] Added listeners to JNI layer of Java wrapper --- wrappers/java/genwrapper.py | 50 +++++++++++++++++++++++++++++++++---- wrappers/java/jni.mustache | 39 ++++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 6 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index d2cd01213..0be26af9c 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -388,7 +388,7 @@ class JavaTranslator(object): return classDict - def translate_jni_interface(self, className, _method): + def translate_jni_interface(self, _class, className, _method): methodDict = {} listenerName = 'Linphone' + className.to_camel_case() methodDict['classCName'] = listenerName[:-8] #Remove Listener at the end @@ -400,6 +400,9 @@ class JavaTranslator(object): methodDict['jname'] = _method.name.to_camel_case(lower=True) methodDict['return'] = self.translate_type(_method.returnType, jni=True, isReturn=True) + methodDict['isSingleListener'] = not _class.multilistener + methodDict['isMultiListener'] = _class.multilistener + methodDict['jobjects'] = [] methodDict['jenums'] = [] methodDict['jstrings'] = [] @@ -449,7 +452,7 @@ class JavaTranslator(object): for method in _class.methods: interfaceDict['methods'].append(self.translate_method(method)) - interfaceDict['jniMethods'].append(self.translate_jni_interface(_class.name, method)) + interfaceDict['jniMethods'].append(self.translate_jni_interface(_class.listenedClass, _class.name, method)) return interfaceDict @@ -500,12 +503,29 @@ class JavaEnum(object): self.doc = self._class['doc'] self.jniName = translator.translate_java_jni_enum_name(_enum) +class JniInterface(object): + def __init__(self, javaClass, apiClass): + self.isSingleListener = (not apiClass.multilistener) + self.isMultiListener = (apiClass.multilistener) + self.classCName = javaClass.cName + self.cPrefix = javaClass.cPrefix + self.callbacks = [] + listener = apiClass.listenerInterface + for method in listener.methods: + cb = 'linphone_' + listener.name.to_snake_case() + cbName = cb + '_' + method.name.to_snake_case() + self.callbacks.append({ + 'callbackName': cbName, + 'callback': method.name.to_snake_case()[3:], # Remove the on_ + }) + class JavaInterface(object): def __init__(self, package, _interface, translator): self._class = translator.translate_interface(_interface) self.packageName = package self.className = _interface.name.to_camel_case() self.filename = self.className + ".java" + self.cPrefix = 'linphone_' + _interface.name.to_snake_case() self.imports = [] self.methods = self._class['methods'] self.doc = self._class['doc'] @@ -529,6 +549,7 @@ class JavaClass(object): self.packageName = package self.className = _class.name.to_camel_case() self.classImplName = self.className + "Impl" + self.factoryName = _class.name.to_snake_case() self.filename = self.className + ".java" self.imports = [] self.methods = self._class['methods'] @@ -536,6 +557,9 @@ class JavaClass(object): self.jniMethods = self._class['jniMethods'] self.doc = self._class['doc'] self.enums = [] + self.jniInterface = None + if _class.listenerInterface is not None: + self.jniInterface = JniInterface(self, _class) def add_enum(self, enum): if enum.className.startswith(self.className): @@ -546,6 +570,7 @@ class Jni(object): def __init__(self, package): self.enums = [] self.interfaces = [] + self.callbacks = [] self.objects = [] self.methods = [] self.jni_package = '' @@ -578,10 +603,25 @@ class Jni(object): } self.objects.append(obj) - def add_interfaces(self, name, interfaces): - for interface in interfaces: + jniInterface = javaClass.jniInterface + if jniInterface is not None: + interface = { + 'isSingleListener': jniInterface.isSingleListener, + 'isMultiListener': jniInterface.isMultiListener, + 'classCName': jniInterface.classCName, + 'cPrefix': jniInterface.cPrefix, + 'jniPackage': self.jni_package, + 'factoryName': javaClass.factoryName, + 'callbacksList': [] + } + for callback in jniInterface.callbacks: + interface['callbacksList'].append(callback) self.interfaces.append(interface) + def add_callbacks(self, name, callbacks): + for callback in callbacks: + self.callbacks.append(callback) + def add_methods(self, name, methods): for method in methods: self.methods.append(method) @@ -673,7 +713,7 @@ class GenWrapper(object): self.interfaces[javaInterfaceStub.classNameStub] = javaInterfaceStub except AbsApi.Error as e: print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) - self.jni.add_interfaces(javainterface.className, javainterface.jniMethods) + self.jni.add_callbacks(javainterface.className, javainterface.jniMethods) def render_java_class(self, _class): if _class is not None: diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index 00bcbf0ba..083d42ec6 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -158,7 +158,7 @@ static inline void handle_possible_java_exception(JNIEnv *env, jobject listener) } } -{{#interfaces}} +{{#callbacks}} static {{return}} {{callbackName}}({{params}}) { JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); @@ -168,7 +168,12 @@ static {{return}} {{callbackName}}({{params}}) { return; } + {{#isSingleListener}} {{classCName}}Cbs *cbs = {{cPrefix}}_get_callbacks(cptr); + {{/isSingleListener}} + {{#isMultiListener}} + {{classCName}}Cbs *cbs = {{cPrefix}}_get_current_callbacks(cptr); + {{/isMultiListener}} jobject jlistener = (jobject) {{cPrefix}}_cbs_get_user_data(cbs); if (jlistener == NULL) { @@ -206,6 +211,38 @@ static {{return}} {{callbackName}}({{params}}) { handle_possible_java_exception(env, jlistener); } +{{/callbacks}} +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +{{#interfaces}} +{{#isSingleListener}} +void {{jniPackage}}{{classCName}}Impl_setListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { +{{/isSingleListener}} +{{#isMultiListener}} +void {{jniPackage}}{{classCName}}Impl_addListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { +{{/isMultiListener}} + {{classCName}} *cptr = ({{classCName}}*)ptr; + jobject listener = env->NewGlobalRef(jlistener); + {{#isSingleListener}} + {{classCName}}Cbs *cbs = {{cPrefix}}_get_callbacks(request); + {{/isSingleListener}} + {{#isMultiListener}} + {{classCName}}Cbs *cbs = linphone_factory_create_{{factoryName}}_cbs(NULL); + {{/isMultiListener}} + {{cPrefix}}_cbs_set_user_data(cbs, listener); + {{#callbacksList}} + {{cPrefix}}_cbs_set_{{callback}}(cbs, {{callbackName}}); + {{/callbacksList}} +} +{{#isMultiListener}} + +void {{jniPackage}}{{classCName}}Impl_removeListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { + {{classCName}} *cptr = ({{classCName}}*)ptr; + //TODO + {{cPrefix}}_remove_callbacks(ptr, ); +} +{{/isMultiListener}} + {{/interfaces}} ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// From b9c4d7dcdfaf52fa55cf1eacbf374f0193aab82c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 11 Oct 2017 14:23:51 +0200 Subject: [PATCH 0426/2215] Handle participant removal in client group chat room. --- coreapi/callbacks.c | 19 +++++++++++++++++-- coreapi/linphonecore.c | 19 ++++++++++++++++++- coreapi/private.h | 5 +++-- src/chat/client-group-chat-room.cpp | 20 +++++++++++++++----- 4 files changed, 53 insertions(+), 10 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 9b49492b4..78b2c35cc 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -721,10 +721,25 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ LinphonePrivate::Address addr(sal_address_as_string(refer_to)); if (addr.isValid()) { LinphoneCore *lc = reinterpret_cast(op->get_sal()->get_user_pointer()); - if (addr.hasParam("admin")) { + if (addr.hasUriParam("method") && (addr.getUriParamValue("method") == "BYE")) { + // The server asks a participant to leave a chat room + LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, addr.asStringUriOnly().c_str()); + if (cr) { + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->leave(); + static_cast(op)->reply(SalReasonNone); + return; + } + static_cast(op)->reply(SalReasonDeclined); + } else if (addr.hasParam("admin")) { LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, op->get_to()); if (cr) { - std::shared_ptr participant = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(addr); + Address fromAddr(op->get_from()); + std::shared_ptr participant = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(fromAddr); + if (!participant || !participant->isAdmin()) { + static_cast(op)->reply(SalReasonDeclined); + return; + } + participant = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(addr); if (participant) { bool value = Utils::stob(addr.getParamValue("admin")); L_GET_CPP_PTR_FROM_C_OBJECT(cr)->setParticipantAdminStatus(participant, value); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index cfdb0e84e..143dc746d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -7105,15 +7105,32 @@ bool_t _linphone_core_has_group_chat_room(const LinphoneCore *lc, const char *id } void _linphone_core_add_group_chat_room(LinphoneCore *lc, const LinphonePrivate::Address &addr, LinphoneChatRoom *cr) { - Address cleanedAddr = addr; + Address cleanedAddr(addr); + cleanedAddr.clean(); cleanedAddr.setPort(0); bctbx_pair_t *pair = reinterpret_cast(bctbx_pair_cchar_new(cleanedAddr.asStringUriOnly().c_str(), linphone_chat_room_ref(cr))); bctbx_map_cchar_insert_and_delete(lc->group_chat_rooms, pair); } +void _linphone_core_remove_group_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr) { + const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(cr); + Address cleanedAddr(*L_GET_CPP_PTR_FROM_C_OBJECT(confAddr)); + cleanedAddr.clean(); + cleanedAddr.setPort(0); + bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, cleanedAddr.asStringUriOnly().c_str()); + bctbx_iterator_t *endit = bctbx_map_cchar_end(lc->group_chat_rooms); + if (!bctbx_iterator_cchar_equals(it, endit)) { + bctbx_map_cchar_erase(lc->group_chat_rooms, it); + linphone_chat_room_unref(cr); + } + bctbx_iterator_cchar_delete(endit); + bctbx_iterator_cchar_delete(it); +} + LinphoneChatRoom *_linphone_core_find_group_chat_room(const LinphoneCore *lc, const char *id) { LinphoneChatRoom *result = nullptr; Address cleanedAddr(id); + cleanedAddr.clean(); cleanedAddr.setPort(0); bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, cleanedAddr.asStringUriOnly().c_str()); bctbx_iterator_t *endit = bctbx_map_cchar_end(lc->group_chat_rooms); diff --git a/coreapi/private.h b/coreapi/private.h index ca1d8cf20..9e8c32bb0 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -449,8 +449,9 @@ bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription extern LinphonePrivate::Sal::Callbacks linphone_sal_callbacks; LINPHONE_PUBLIC bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); LINPHONE_PUBLIC bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc); -bool_t _linphone_core_has_group_chat_room(const LinphoneCore *lc, const char *id); -void _linphone_core_add_group_chat_room(LinphoneCore *lc, const LinphonePrivate::Address &addr, LinphoneChatRoom *cr); +bool_t _linphone_core_has_group_chat_room (const LinphoneCore *lc, const char *id); +void _linphone_core_add_group_chat_room (LinphoneCore *lc, const LinphonePrivate::Address &addr, LinphoneChatRoom *cr); +void _linphone_core_remove_group_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr); void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description); diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index ce02a4563..fb7270231 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -150,11 +150,22 @@ void ClientGroupChatRoom::leave () { } void ClientGroupChatRoom::removeParticipant (const shared_ptr &participant) { - // TODO + L_D(); + SalReferOp *referOp = new SalReferOp(d->core->sal); + LinphoneAddress *lAddr = linphone_address_new(conferenceAddress.asString().c_str()); + linphone_configure_op(d->core, referOp, lAddr, nullptr, false); + linphone_address_unref(lAddr); + Address referToAddr = participant->getAddress(); + referToAddr.setParam("text"); + referToAddr.setUriParam("method", "BYE"); + referToAddr.setDomain(""); + referToAddr.setPort(-1); + referOp->send_refer(referToAddr.getPrivate()->getInternalAddress()); + referOp->unref(); } void ClientGroupChatRoom::removeParticipants (const list> &participants) { - // TODO + RemoteConference::removeParticipants(participants); } void ClientGroupChatRoom::setParticipantAdminStatus (shared_ptr &participant, bool isAdmin) { @@ -231,7 +242,7 @@ void ClientGroupChatRoom::onParticipantAdded (const Address &addr) { void ClientGroupChatRoom::onParticipantRemoved (const Address &addr) { shared_ptr participant = findParticipant(addr); if (!participant) { - lWarning() << "Participant " << participant << " removed but is not in the list of participants!"; + lWarning() << "Participant " << addr.asString() << " removed but not in the list of participants!"; return; } LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); @@ -315,9 +326,8 @@ void ClientGroupChatRoom::onCallSessionStateChanged (const std::shared_ptrgetPrivate()->getSession()->terminate(); } } else { - if ((state == LinphoneCallReleased) && (d->state == ChatRoom::State::TerminationPending)) { + if ((state == LinphoneCallReleased) && (d->state == ChatRoom::State::TerminationPending)) onConferenceTerminated(conferenceAddress); - } } } From 6310bfb10b828599afcb988a4f9c7f6d5fff9588 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 11 Oct 2017 14:59:11 +0200 Subject: [PATCH 0427/2215] fix(ChatMessage): remove ugly send method on chatroom!!! --- src/c-wrapper/api/c-chat-message.cpp | 4 +- src/c-wrapper/api/c-chat-room.cpp | 8 ++-- src/chat/chat-message.cpp | 4 +- src/chat/chat-message.h | 4 +- src/chat/chat-room-p.h | 18 +++++---- src/chat/chat-room.cpp | 54 +++++++++++++-------------- src/chat/chat-room.h | 3 +- src/chat/real-time-text-chat-room-p.h | 4 +- src/chat/real-time-text-chat-room.cpp | 15 +++----- src/chat/real-time-text-chat-room.h | 2 - tester/cpim-tester.cpp | 10 ++--- tester/multipart-tester.cpp | 4 +- 12 files changed, 62 insertions(+), 68 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index b60967110..7e28a33ef 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -265,11 +265,11 @@ void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg) { } void linphone_chat_message_resend(LinphoneChatMessage *msg) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->reSend(); + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->send(); } void linphone_chat_message_resend_2(LinphoneChatMessage *msg) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->reSend(); + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->send(); } void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state) { diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index e56d447c0..f447e0fd2 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -74,7 +74,7 @@ void linphone_chat_room_remove_transient_message (LinphoneChatRoom *cr, Linphone } void linphone_chat_room_send_message (LinphoneChatRoom *cr, const char *msg) { - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createMessage(msg)); + L_GET_PRIVATE_FROM_C_OBJECT(cr)->sendMessage(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createMessage(msg)); } bool_t linphone_chat_room_is_remote_composing (const LinphoneChatRoom *cr) { @@ -136,16 +136,16 @@ void linphone_chat_room_send_message2 ( ) { linphone_chat_message_set_message_state_changed_cb(msg, status_cb); linphone_chat_message_set_message_state_changed_cb_user_data(msg, ud); - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(L_GET_CPP_PTR_FROM_C_OBJECT(msg)); + L_GET_PRIVATE_FROM_C_OBJECT(cr)->sendMessage(L_GET_CPP_PTR_FROM_C_OBJECT(msg)); } void linphone_chat_room_send_chat_message_2 (LinphoneChatRoom *cr, LinphoneChatMessage *msg) { linphone_chat_message_ref(msg); - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(L_GET_CPP_PTR_FROM_C_OBJECT(msg)); + L_GET_PRIVATE_FROM_C_OBJECT(cr)->sendMessage(L_GET_CPP_PTR_FROM_C_OBJECT(msg)); } void linphone_chat_room_send_chat_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) { - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->sendMessage(L_GET_CPP_PTR_FROM_C_OBJECT(msg)); + L_GET_PRIVATE_FROM_C_OBJECT(cr)->sendMessage(L_GET_CPP_PTR_FROM_C_OBJECT(msg)); } uint32_t linphone_chat_room_get_char (const LinphoneChatRoom *cr) { diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index aff6d1048..50822b168 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -1420,7 +1420,7 @@ void ChatMessage::updateState(State state) { d->chatRoom->getPrivate()->moveTransientMessageToWeakMessages(getSharedFromThis()); } -void ChatMessage::reSend() { +void ChatMessage::send () { L_D(); if (d->state != State::NotDelivered) { @@ -1428,7 +1428,7 @@ void ChatMessage::reSend() { return; } - d->chatRoom->sendMessage(getSharedFromThis()); + d->chatRoom->getPrivate()->sendMessage(getSharedFromThis()); } void ChatMessage::sendDeliveryNotification(LinphoneReason reason) { diff --git a/src/chat/chat-message.h b/src/chat/chat-message.h index 9900b4dbd..7a5504860 100644 --- a/src/chat/chat-message.h +++ b/src/chat/chat-message.h @@ -61,18 +61,18 @@ public: void cancelFileTransfer (); int putCharacter (uint32_t character); void updateState (State state); - void reSend (); void sendDeliveryNotification (LinphoneReason reason); void sendDisplayNotification (); void setImdnMessageId (const std::string &imdnMessageId); void setIsSecured (bool isSecured); void setFromAddress (Address from); void setToAddress (Address to); + void store (); // ----- TODO: Remove me. std::shared_ptr getChatRoom () const; - void store (); + void send (); time_t getTime () const; diff --git a/src/chat/chat-room-p.h b/src/chat/chat-room-p.h index 592e5f5fd..fe8710a6a 100644 --- a/src/chat/chat-room-p.h +++ b/src/chat/chat-room-p.h @@ -45,13 +45,13 @@ private: static int createChatMessageFromDb (void *data, int argc, char **argv, char **colName); public: - void addTransientMessage (std::shared_ptr msg); - void addWeakMessage (std::shared_ptr msg); + void addTransientMessage (const std::shared_ptr &msg); + void addWeakMessage (const std::shared_ptr &msg); std::list > getTransientMessages () const { return transientMessages; } - void moveTransientMessageToWeakMessages (std::shared_ptr msg); - void removeTransientMessage (std::shared_ptr msg); + void moveTransientMessageToWeakMessages (const std::shared_ptr &msg); + void removeTransientMessage (const std::shared_ptr &msg); void release (); void sendImdn (const std::string &content, LinphoneReason reason); @@ -59,6 +59,8 @@ public: int getMessagesCount (bool unreadOnly); void setState (ChatRoom::State newState); + virtual void sendMessage (const std::shared_ptr &msg); + protected: void sendIsComposingNotification (); @@ -68,21 +70,21 @@ protected: int sqlRequest (sqlite3 *db, const std::string &stmt); void sqlRequestMessage (sqlite3 *db, const std::string &stmt); std::list > findMessages (const std::string &messageId); - void storeOrUpdateMessage (std::shared_ptr msg); + void storeOrUpdateMessage (const std::shared_ptr &msg); public: LinphoneReason messageReceived (SalOp *op, const SalMessage *msg); void realtimeTextReceived (uint32_t character, LinphoneCall *call); protected: - void chatMessageReceived (std::shared_ptr msg); + void chatMessageReceived (const std::shared_ptr &msg); void imdnReceived (const std::string &text); void isComposingReceived (const std::string &text); private: - void notifyChatMessageReceived (std::shared_ptr msg); + void notifyChatMessageReceived (const std::shared_ptr &msg); void notifyStateChanged (); - void notifyUndecryptableMessageReceived (std::shared_ptr msg); + void notifyUndecryptableMessageReceived (const std::shared_ptr &msg); private: /* IsComposingListener */ diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room.cpp index c8dabef24..d044fb4fd 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room.cpp @@ -51,18 +51,18 @@ int ChatRoomPrivate::createChatMessageFromDb (void *data, int argc, char **argv, // ----------------------------------------------------------------------------- -void ChatRoomPrivate::addTransientMessage (shared_ptr msg) { +void ChatRoomPrivate::addTransientMessage (const shared_ptr &msg) { auto iter = find(transientMessages.begin(), transientMessages.end(), msg); if (iter == transientMessages.end()) transientMessages.push_back(msg); } -void ChatRoomPrivate::addWeakMessage (shared_ptr msg) { +void ChatRoomPrivate::addWeakMessage (const shared_ptr &msg) { weak_ptr weakptr(msg); weakMessages.push_back(weakptr); } -void ChatRoomPrivate::moveTransientMessageToWeakMessages (shared_ptr msg) { +void ChatRoomPrivate::moveTransientMessageToWeakMessages (const shared_ptr &msg) { auto iter = find(transientMessages.begin(), transientMessages.end(), msg); if (iter != transientMessages.end()) { /* msg is not transient anymore, we can remove it from our transient list and unref it */ @@ -73,7 +73,7 @@ void ChatRoomPrivate::moveTransientMessageToWeakMessages (shared_ptr msg) { +void ChatRoomPrivate::removeTransientMessage (const shared_ptr &msg) { auto iter = find(transientMessages.begin(), transientMessages.end(), msg); if (iter != transientMessages.end()) { transientMessages.erase(iter); @@ -378,10 +378,27 @@ list > ChatRoomPrivate::findMessages (const string &mess return result; } -void ChatRoomPrivate::storeOrUpdateMessage (shared_ptr msg) { +void ChatRoomPrivate::storeOrUpdateMessage (const shared_ptr &msg) { msg->store(); } +void ChatRoomPrivate::sendMessage (const shared_ptr &msg) { + msg->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); + + /* Add to transient list */ + addTransientMessage(msg); + + msg->getPrivate()->setTime(ms_time(0)); + msg->getPrivate()->send(); + + storeOrUpdateMessage(msg); + + if (isComposing) + isComposing = false; + isComposingHandler.stopIdleTimer(); + isComposingHandler.stopRefreshTimer(); +} + // ----------------------------------------------------------------------------- LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *salMsg) { @@ -460,7 +477,7 @@ end: // ----------------------------------------------------------------------------- -void ChatRoomPrivate::chatMessageReceived (shared_ptr msg) { +void ChatRoomPrivate::chatMessageReceived (const shared_ptr &msg) { L_Q(); if ((msg->getPrivate()->getContentType() != ContentType::Imdn) && (msg->getPrivate()->getContentType() != ContentType::ImIsComposing)) { notifyChatMessageReceived(msg); @@ -481,7 +498,7 @@ void ChatRoomPrivate::isComposingReceived (const string &text) { // ----------------------------------------------------------------------------- -void ChatRoomPrivate::notifyChatMessageReceived (shared_ptr msg) { +void ChatRoomPrivate::notifyChatMessageReceived (const shared_ptr &msg) { L_Q(); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); if (!msg->getPrivate()->getText().empty()) { @@ -504,7 +521,7 @@ void ChatRoomPrivate::notifyStateChanged () { cb(cr, (LinphoneChatRoomState)state); } -void ChatRoomPrivate::notifyUndecryptableMessageReceived (shared_ptr msg) { +void ChatRoomPrivate::notifyUndecryptableMessageReceived (const shared_ptr &msg) { L_Q(); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); @@ -598,7 +615,7 @@ void ChatRoom::deleteHistory () { if (d->unreadCount > 0) d->unreadCount = 0; } -void ChatRoom::deleteMessage (shared_ptr msg) { +void ChatRoom::deleteMessage (const shared_ptr &msg) { L_D(); if (!d->core->db) return; char *buf = sqlite3_mprintf("DELETE FROM history WHERE id = %u;", msg->getPrivate()->getStorageId()); @@ -734,25 +751,6 @@ void ChatRoom::markAsRead () { d->unreadCount = 0; } -void ChatRoom::sendMessage (shared_ptr msg) { - L_D(); - - msg->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); - - /* Add to transient list */ - d->addTransientMessage(msg); - - msg->getPrivate()->setTime(ms_time(0)); - msg->getPrivate()->send(); - - d->storeOrUpdateMessage(msg); - - if (d->isComposing) - d->isComposing = false; - d->isComposingHandler.stopIdleTimer(); - d->isComposingHandler.stopRefreshTimer(); -} - // ----------------------------------------------------------------------------- LinphoneCore *ChatRoom::getCore () const { diff --git a/src/chat/chat-room.h b/src/chat/chat-room.h index 09061e789..50b087edb 100644 --- a/src/chat/chat-room.h +++ b/src/chat/chat-room.h @@ -55,7 +55,7 @@ public: std::shared_ptr createMessage (const std::string &msg); std::shared_ptr createMessage (); void deleteHistory (); - void deleteMessage (std::shared_ptr msg); + void deleteMessage (const std::shared_ptr &msg); std::shared_ptr findMessage (const std::string& messageId); std::shared_ptr findMessageWithDirection (const std::string &messageId, ChatMessage::Direction direction); std::list > getHistory (int nbMessages); @@ -64,7 +64,6 @@ public: int getUnreadMessagesCount (); bool isRemoteComposing () const; void markAsRead (); - virtual void sendMessage (std::shared_ptr msg); LinphoneCore *getCore () const; diff --git a/src/chat/real-time-text-chat-room-p.h b/src/chat/real-time-text-chat-room-p.h index 78440181d..8c02770a2 100644 --- a/src/chat/real-time-text-chat-room-p.h +++ b/src/chat/real-time-text-chat-room-p.h @@ -37,10 +37,10 @@ public: public: void setCall (LinphoneCall *call) { this->call = call; } - -public: void realtimeTextReceived (uint32_t character, LinphoneCall *call); + void sendMessage (const std::shared_ptr &msg) override; + public: LinphoneCall *call = nullptr; std::list receivedRttCharacters; diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/real-time-text-chat-room.cpp index fbff72412..d62eb31de 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/real-time-text-chat-room.cpp @@ -100,20 +100,17 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp } } -// ============================================================================= - -RealTimeTextChatRoom::RealTimeTextChatRoom (LinphoneCore *core, const Address &peerAddress) : ChatRoom(*new RealTimeTextChatRoomPrivate(core, peerAddress)) {} - -// ----------------------------------------------------------------------------- - -void RealTimeTextChatRoom::sendMessage (std::shared_ptr msg) { - L_D(); - if (d->call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(d->call))) { +void RealTimeTextChatRoomPrivate::sendMessage (const std::shared_ptr &msg) { + if (call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) { uint32_t new_line = 0x2028; msg->putCharacter(new_line); } } +// ============================================================================= + +RealTimeTextChatRoom::RealTimeTextChatRoom (LinphoneCore *core, const Address &peerAddress) : ChatRoom(*new RealTimeTextChatRoomPrivate(core, peerAddress)) {} + // ----------------------------------------------------------------------------- uint32_t RealTimeTextChatRoom::getChar () const { diff --git a/src/chat/real-time-text-chat-room.h b/src/chat/real-time-text-chat-room.h index ad2f12d37..52c0993ef 100644 --- a/src/chat/real-time-text-chat-room.h +++ b/src/chat/real-time-text-chat-room.h @@ -38,8 +38,6 @@ public: RealTimeTextChatRoom (LinphoneCore *core, const Address &peerAddress); virtual ~RealTimeTextChatRoom () = default; - void sendMessage (std::shared_ptr msg) override; - uint32_t getChar () const; LinphoneCall *getCall () const; diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index 191792e57..35af930bc 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -257,7 +257,7 @@ static void parse_rfc_example () { const string str2 = message->asString(); BC_ASSERT_STRING_EQUAL(str2.c_str(), str.c_str()); - + string content = message->getContent(); BC_ASSERT_STRING_EQUAL(content.c_str(), body.c_str()); } @@ -283,7 +283,7 @@ static void parse_message_with_generic_header_parameters () { const string str2 = message->asString(); BC_ASSERT_STRING_EQUAL(str2.c_str(), str.c_str()); - + string content = message->getContent(); BC_ASSERT_STRING_EQUAL(content.c_str(), body.c_str()); } @@ -346,7 +346,7 @@ static void build_message () { if (!BC_ASSERT_TRUE(contentTypeHeader.setName("Content-Type"))) return; if (!BC_ASSERT_TRUE( contentTypeHeader.setValue("text/xml; charset=utf-8"))) return; if (!BC_ASSERT_TRUE(message.addContentHeader(contentTypeHeader))) return; - + Cpim::GenericHeader contentIdHeader; if (!BC_ASSERT_TRUE(contentIdHeader.setName("Content-ID"))) return; if (!BC_ASSERT_TRUE( contentIdHeader.setValue("<1234567890@foo.com>"))) return; @@ -398,11 +398,11 @@ static void cpim_chat_message_modifier_base(bool_t use_multipart) { content.setBody("Hello Part 2"); marieMessage->addContent(content); } - marieRoom->sendMessage(marieMessage); + marieMessage->send(); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageReceived,1)); BC_ASSERT_TRUE(marieMessage->getInternalContent().getContentType() == ContentType::Cpim); - + BC_ASSERT_PTR_NOT_NULL(pauline->stat.last_received_chat_message); if (pauline->stat.last_received_chat_message != NULL) { BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(pauline->stat.last_received_chat_message), "Hello CPIM"); diff --git a/tester/multipart-tester.cpp b/tester/multipart-tester.cpp index 470b05bd7..b02ea3f4f 100644 --- a/tester/multipart-tester.cpp +++ b/tester/multipart-tester.cpp @@ -51,11 +51,11 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer, bool content.setBody("Hello Part 2"); marieMessage->addContent(content); } - marieRoom->sendMessage(marieMessage); + marieMessage->send(); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageReceived,1)); BC_ASSERT_STRING_EQUAL(marieMessage->getInternalContent().getContentType().asString().c_str(), "multipart/mixed"); - + BC_ASSERT_PTR_NOT_NULL(pauline->stat.last_received_chat_message); //TODO From ff688cd975818b34fce5230139a6405d8a56ac88 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 11 Oct 2017 15:03:50 +0200 Subject: [PATCH 0428/2215] Finished removeCallbacks in JNI layer for Java wrapper for multi listenable classes --- coreapi/vtables.c | 10 ++++++++++ include/linphone/api/c-call.h | 7 +++++++ include/linphone/core.h | 8 ++++++++ src/c-wrapper/api/c-call.cpp | 4 ++++ wrappers/java/jni.mustache | 16 +++++++++++++--- 5 files changed, 42 insertions(+), 3 deletions(-) diff --git a/coreapi/vtables.c b/coreapi/vtables.c index 7b0fb82c8..6a8691c02 100644 --- a/coreapi/vtables.c +++ b/coreapi/vtables.c @@ -332,6 +332,16 @@ void linphone_core_remove_listener(LinphoneCore *lc, const LinphoneCoreVTable *v } } +bctbx_list_t *linphone_core_get_callbacks(const LinphoneCore *lc) { + bctbx_list_t *result; + bctbx_list_t *it; + for(it=lc->vtable_refs; it!=NULL; it=it->next){ + VTableReference *ref=(VTableReference*)it->data; + result = bctbx_list_append(result, ref->cbs); + } + return result; +} + void linphone_core_remove_callbacks(LinphoneCore *lc, const LinphoneCoreCbs *cbs) { bctbx_list_t *it; ms_message("Callbacks [%p] unregistered on core [%p]",cbs,lc); diff --git a/include/linphone/api/c-call.h b/include/linphone/api/c-call.h index fe3c2c768..589056f19 100644 --- a/include/linphone/api/c-call.h +++ b/include/linphone/api/c-call.h @@ -756,6 +756,13 @@ LINPHONE_PUBLIC void linphone_call_add_callbacks(LinphoneCall *call, LinphoneCal */ LINPHONE_PUBLIC void linphone_call_remove_callbacks(LinphoneCall *call, LinphoneCallCbs *cbs); +/** + * Gets the list of listener in the call + * @param[in] call LinphoneCall object + * @return the list of LinphoneCallCbs + */ +LINPHONE_PUBLIC const bctbx_list_t *linphone_call_get_callbacks(const LinphoneCall *call); + /** * Gets the current LinphoneCallCbs. * This is meant only to be called from a callback to be able to get the user_data associated with the LinphoneCallCbs that is calling the callback. diff --git a/include/linphone/core.h b/include/linphone/core.h index e78ba8e4c..421e88e28 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -975,6 +975,14 @@ LINPHONE_DEPRECATED LINPHONE_PUBLIC void linphone_core_remove_listener(LinphoneC */ LINPHONE_PUBLIC void linphone_core_remove_callbacks(LinphoneCore *lc, const LinphoneCoreCbs *cbs); +/** + * @ingroup initializing + * Gets the list of listener in the core + * @param lc The #LinphoneCore + * @return the list of LinphoneCoreCbs + */ +LINPHONE_PUBLIC bctbx_list_t *linphone_core_get_callbacks(const LinphoneCore *lc); + /** * Sets the user agent string used in SIP messages, ideally called just after linphone_core_new() or linphone_core_init(). * @param[in] lc LinphoneCore object diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index bc33b1ae5..47a6492cc 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -1097,6 +1097,10 @@ LinphoneCallCbs *linphone_call_get_current_callbacks (const LinphoneCall *call) return call->currentCbs; } +const bctbx_list_t *linphone_call_get_callbacks(const LinphoneCall *call) { + return call->callbacks; +} + void linphone_call_set_params (LinphoneCall *call, const LinphoneCallParams *params) { #if 0 if ( call->state == LinphoneCallOutgoingInit || call->state == LinphoneCallIncomingReceived){ diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index 083d42ec6..f0040cc49 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -224,7 +224,7 @@ void {{jniPackage}}{{classCName}}Impl_addListener(JNIEnv* env, jobject thiz, jlo {{classCName}} *cptr = ({{classCName}}*)ptr; jobject listener = env->NewGlobalRef(jlistener); {{#isSingleListener}} - {{classCName}}Cbs *cbs = {{cPrefix}}_get_callbacks(request); + {{classCName}}Cbs *cbs = {{cPrefix}}_get_callbacks(cptr); {{/isSingleListener}} {{#isMultiListener}} {{classCName}}Cbs *cbs = linphone_factory_create_{{factoryName}}_cbs(NULL); @@ -233,13 +233,23 @@ void {{jniPackage}}{{classCName}}Impl_addListener(JNIEnv* env, jobject thiz, jlo {{#callbacksList}} {{cPrefix}}_cbs_set_{{callback}}(cbs, {{callbackName}}); {{/callbacksList}} + {{#isMultiListener}} + {{cPrefix}}_add_callbacks(cptr, cbs); + {{/isMultiListener}} } {{#isMultiListener}} void {{jniPackage}}{{classCName}}Impl_removeListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { {{classCName}} *cptr = ({{classCName}}*)ptr; - //TODO - {{cPrefix}}_remove_callbacks(ptr, ); + const bctbx_list_t *cbs_list = {{cPrefix}}_get_callbacks(cptr); + bctbx_list_t *it; + for (it = cbs_list; it != NULL; it = it->next) { + {{classCName}}Cbs *cbs = ({{classCName}}Cbs *)it->data; + if ({{cPrefix}}_cbs_get_user_data(cbs) == jlistener) { + {{cPrefix}}_remove_callbacks(cptr, cbs); + break; + } + } } {{/isMultiListener}} From 013be9e292a933bb79961dbd6fe4b9e7457a3863 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 11 Oct 2017 15:06:32 +0200 Subject: [PATCH 0429/2215] fix(ChatModifier): use `const std::shared_ptr &message` instead of `std::shared_ptr message` --- src/chat/modifier/chat-message-modifier.h | 4 ++-- src/chat/modifier/cpim-chat-message-modifier.cpp | 4 ++-- src/chat/modifier/cpim-chat-message-modifier.h | 4 ++-- src/chat/modifier/encryption-chat-message-modifier.cpp | 4 ++-- src/chat/modifier/encryption-chat-message-modifier.h | 4 ++-- src/chat/modifier/multipart-chat-message-modifier.cpp | 4 ++-- src/chat/modifier/multipart-chat-message-modifier.h | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/chat/modifier/chat-message-modifier.h b/src/chat/modifier/chat-message-modifier.h index 02b671b7a..8e448063c 100644 --- a/src/chat/modifier/chat-message-modifier.h +++ b/src/chat/modifier/chat-message-modifier.h @@ -46,13 +46,13 @@ public: * It should check first if the internalContent is filled. * If so, it should apply it's changes to it, otherwise it should use the contentsList. */ - virtual Result encode (std::shared_ptr message, int *errorCode) = 0; + virtual Result encode (const std::shared_ptr &message, int *errorCode) = 0; /** * This method will be called when the message is about to be received. * It should apply it's changes to the internal content, the last modifier will take care of filling the contentsList. */ - virtual Result decode (std::shared_ptr message, int *errorCode) = 0; + virtual Result decode (const std::shared_ptr &message, int *errorCode) = 0; }; LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index c556c0d25..04934aead 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -32,7 +32,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ChatMessageModifier::Result CpimChatMessageModifier::encode (shared_ptr message, int *errorCode) { +ChatMessageModifier::Result CpimChatMessageModifier::encode (const shared_ptr &message, int *errorCode) { Cpim::Message cpimMessage; Cpim::GenericHeader cpimContentTypeHeader; cpimContentTypeHeader.setName("Content-Type"); @@ -75,7 +75,7 @@ ChatMessageModifier::Result CpimChatMessageModifier::encode (shared_ptr message, int *errorCode) { +ChatMessageModifier::Result CpimChatMessageModifier::decode (const shared_ptr &message, int *errorCode) { Content content; if (!message->getInternalContent().isEmpty()) { content = message->getInternalContent(); diff --git a/src/chat/modifier/cpim-chat-message-modifier.h b/src/chat/modifier/cpim-chat-message-modifier.h index df6a4578c..4e26091b2 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.h +++ b/src/chat/modifier/cpim-chat-message-modifier.h @@ -30,8 +30,8 @@ class CpimChatMessageModifier : public ChatMessageModifier { public: CpimChatMessageModifier () = default; - Result encode (std::shared_ptr message, int *errorCode) override; - Result decode (std::shared_ptr message, int *errorCode) override; + Result encode (const std::shared_ptr &message, int *errorCode) override; + Result decode (const std::shared_ptr &message, int *errorCode) override; }; LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/encryption-chat-message-modifier.cpp b/src/chat/modifier/encryption-chat-message-modifier.cpp index cad20317a..156b7350e 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.cpp +++ b/src/chat/modifier/encryption-chat-message-modifier.cpp @@ -34,7 +34,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ChatMessageModifier::Result EncryptionChatMessageModifier::encode (shared_ptr message, int *errorCode) { +ChatMessageModifier::Result EncryptionChatMessageModifier::encode (const shared_ptr &message, int *errorCode) { int retval = -1; shared_ptr chatRoom = message->getChatRoom(); LinphoneImEncryptionEngine *imee = chatRoom->getCore()->im_encryption_engine; @@ -59,7 +59,7 @@ ChatMessageModifier::Result EncryptionChatMessageModifier::encode (shared_ptr message, int *errorCode) { +ChatMessageModifier::Result EncryptionChatMessageModifier::decode (const shared_ptr &message, int *errorCode) { int retval = -1; shared_ptr chatRoom = message->getChatRoom(); LinphoneImEncryptionEngine *imee = chatRoom->getCore()->im_encryption_engine; diff --git a/src/chat/modifier/encryption-chat-message-modifier.h b/src/chat/modifier/encryption-chat-message-modifier.h index 8b9ce52dc..6bd8833f2 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.h +++ b/src/chat/modifier/encryption-chat-message-modifier.h @@ -30,8 +30,8 @@ class EncryptionChatMessageModifier : public ChatMessageModifier { public: EncryptionChatMessageModifier () = default; - Result encode (std::shared_ptr message, int *errorCode) override; - Result decode (std::shared_ptr message, int *errorCode) override; + Result encode (const std::shared_ptr &message, int *errorCode) override; + Result decode (const std::shared_ptr &message, int *errorCode) override; }; LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index 895a1a6d9..72f1064ca 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -30,7 +30,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ChatMessageModifier::Result MultipartChatMessageModifier::encode (shared_ptr message, int *errorCode) { +ChatMessageModifier::Result MultipartChatMessageModifier::encode (const shared_ptr &message, int *errorCode) { if (message->getContents().size() > 1) { LinphoneCore *lc = message->getChatRoom()->getCore(); char tmp[64]; @@ -59,7 +59,7 @@ ChatMessageModifier::Result MultipartChatMessageModifier::encode (shared_ptr message, int *errorCode) { +ChatMessageModifier::Result MultipartChatMessageModifier::decode (const shared_ptr &message, int *errorCode) { if (message->getInternalContent().getContentType().getType() == "multipart") { string boundary = message->getInternalContent().getContentType().getParameter(); if (boundary.empty()) { diff --git a/src/chat/modifier/multipart-chat-message-modifier.h b/src/chat/modifier/multipart-chat-message-modifier.h index fd7b747ca..4336af26c 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.h +++ b/src/chat/modifier/multipart-chat-message-modifier.h @@ -30,8 +30,8 @@ class MultipartChatMessageModifier : public ChatMessageModifier { public: MultipartChatMessageModifier () = default; - Result encode (std::shared_ptr message, int *errorCode) override; - Result decode (std::shared_ptr message, int *errorCode) override; + Result encode (const std::shared_ptr &message, int *errorCode) override; + Result decode (const std::shared_ptr &message, int *errorCode) override; }; LINPHONE_END_NAMESPACE From faae5f44063458a23944a0579acf108fb5cf15eb Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 11 Oct 2017 15:24:43 +0200 Subject: [PATCH 0430/2215] Added set/add/remove listener to Java wrapper --- wrappers/java/genwrapper.py | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 0be26af9c..180aa4c9d 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -244,6 +244,36 @@ class JavaTranslator(object): properties.append(self.translate_jni_method(className, _property.setter)) return properties + def generate_listener(self, name, _class): + methodDict = {} + methodDict['return'] = 'void' + methodDict['return_native'] = 'void' + methodDict['return_keyword'] = '' + methodDict['convertInputClassArrayToLongArray'] = False + methodDict['name'] = name + methodDict['exception'] = False + methodDict['enumCast'] = False + methodDict['classCast'] = False + + methodDict['params'] = _class.name.to_camel_case() + 'Listener listener' + methodDict['native_params'] = 'long nativePtr, ' + _class.name.to_camel_case() + 'Listener listener' + methodDict['static_native_params'] = '' + methodDict['native_params_impl'] = ', listener' + + methodDict['deprecated'] = False + methodDict['doc'] = None + + return methodDict + + def generate_add_listener(self, _class): + return self.generate_listener('addListener', _class) + + def generate_remove_listener(self, _class): + return self.generate_listener('removeListener', _class) + + def generate_set_listener(self, _class): + return self.generate_listener('setListener', _class) + def translate_method(self, _method): methodDict = {} @@ -386,6 +416,15 @@ class JavaTranslator(object): except AbsApi.Error as e: print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0])) + islistenable = _class.listenerInterface is not None + if islistenable: + isMultiListener = (_class.multilistener) + if isMultiListener: + classDict['methods'].append(self.generate_add_listener(_class)) + classDict['methods'].append(self.generate_remove_listener(_class)) + else: + classDict['methods'].append(self.generate_set_listener(_class)) + return classDict def translate_jni_interface(self, _class, className, _method): From 8ec1430058f6763b0d9acccfb90b90f5da0cf0c4 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 11 Oct 2017 15:30:03 +0200 Subject: [PATCH 0431/2215] Added ENABLE_JAVA_WRAPPER to CMakeLists --- CMakeLists.txt | 6 +++++- coreapi/help/doc/doxygen/CMakeLists.txt | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index febd61170..a16203a69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,7 @@ option(ENABLE_STATIC "Build static library." YES) option(ENABLE_CONSOLE_UI "Turn on or off compilation of console interface." YES) option(ENABLE_CSHARP_WRAPPER "Build the C# wrapper for Liblinphone." OFF) +option(ENABLE_JAVA_WRAPPER "Build the Java wrapper for Liblinphone." OFF) option(ENABLE_CXX_WRAPPER "Build the C++ wrapper for Liblinphone." YES) option(ENABLE_DAEMON "Enable the linphone daemon interface." YES) option(ENABLE_DATE "Use build date in internal version number." NO) @@ -170,7 +171,7 @@ if(ENABLE_LIME) endif() set(HAVE_LIME 1) endif() -if(ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER) +if(ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRAPPER) find_package(PythonInterp REQUIRED) endif() @@ -355,6 +356,9 @@ endif() if(ENABLE_CSHARP_WRAPPER) add_subdirectory(wrappers/csharp) endif() +if(ENABLE_JAVA_WRAPPER) + add_subdirectory(wrappers/java) +endif() include(CMakePackageConfigHelpers) write_basic_package_version_file( diff --git a/coreapi/help/doc/doxygen/CMakeLists.txt b/coreapi/help/doc/doxygen/CMakeLists.txt index 2574eb772..95a5528ea 100644 --- a/coreapi/help/doc/doxygen/CMakeLists.txt +++ b/coreapi/help/doc/doxygen/CMakeLists.txt @@ -20,7 +20,7 @@ # ################################################################################ -if (ENABLE_DOC OR ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER) +if (ENABLE_DOC OR ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRAPPER) find_package(Doxygen) if (DOXYGEN_FOUND) if (DOXYGEN_DOT_FOUND) From 9e73b3402bcef27df12630f1a63f5a0ff5f2d666 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 11 Oct 2017 15:30:17 +0200 Subject: [PATCH 0432/2215] fix sync between op and proxy_config contact_address --- coreapi/proxy.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index da1d83afd..856a850d9 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1431,6 +1431,15 @@ uint8_t linphone_proxy_config_get_avpf_rr_interval(const LinphoneProxyConfig *cf } const LinphoneAddress *linphone_proxy_config_get_contact (const LinphoneProxyConfig *cfg) { + // Workaround for wrapping. + if (cfg->contact_address) + linphone_address_unref(cfg->contact_address); + + // Warning : Do not remove, the op can change its contact_address + char *buf = sal_address_as_string(cfg->op->get_contact_address()); + const_cast(cfg)->contact_address = linphone_address_new(buf); + ms_free(buf); + return cfg->contact_address; } From f54682374b9dfc829671bb1238a6aee03f26dcad Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 11 Oct 2017 16:01:47 +0200 Subject: [PATCH 0433/2215] fix(CharModifier): clean code (refactor, cppcheck and errorCode is now one reference --- src/chat/chat-message-p.h | 1 + src/chat/chat-message.cpp | 12 +-- src/chat/modifier/chat-message-modifier.h | 10 +- .../modifier/cpim-chat-message-modifier.cpp | 69 ++++++------ .../modifier/cpim-chat-message-modifier.h | 4 +- .../encryption-chat-message-modifier.cpp | 102 ++++++++++-------- .../encryption-chat-message-modifier.h | 4 +- .../multipart-chat-message-modifier.cpp | 70 ++++++------ .../multipart-chat-message-modifier.h | 4 +- src/content/content.h | 2 +- src/db/events-db.cpp | 1 + src/sal/call-op.cpp | 48 +++++---- tester/cpim-tester.cpp | 3 +- tester/multipart-tester.cpp | 1 + 14 files changed, 174 insertions(+), 157 deletions(-) diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message-p.h index 569cd676c..2d269865b 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message-p.h @@ -21,6 +21,7 @@ #define _CHAT_MESSAGE_P_H_ #include "chat-message.h" +#include "content/content-type.h" #include "db/events-db.h" #include "object/object-p.h" diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message.cpp index 50822b168..74ca2b62f 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message.cpp @@ -998,11 +998,11 @@ LinphoneReason ChatMessagePrivate::receive() { if (internalContent.getContentType() == ContentType::Cpim) { CpimChatMessageModifier ccmm; - ccmm.decode(q->getSharedFromThis(), &errorCode); + ccmm.decode(q->getSharedFromThis(), errorCode); } EncryptionChatMessageModifier ecmm; - ChatMessageModifier::Result result = ecmm.decode(q->getSharedFromThis(), &errorCode); + ChatMessageModifier::Result result = ecmm.decode(q->getSharedFromThis(), errorCode); if (result == ChatMessageModifier::Result::Error) { /* Unable to decrypt message */ chatRoom->getPrivate()->notifyUndecryptableMessageReceived(q->getSharedFromThis()); @@ -1012,7 +1012,7 @@ LinphoneReason ChatMessagePrivate::receive() { } MultipartChatMessageModifier mcmm; - mcmm.decode(q->getSharedFromThis(), &errorCode); + mcmm.decode(q->getSharedFromThis(), errorCode); if (contents.size() == 0) { // All previous modifiers only altered the internal content, let's fill the content list @@ -1138,7 +1138,7 @@ void ChatMessagePrivate::send() { } else { if (contents.size() > 1) { MultipartChatMessageModifier mcmm; - mcmm.encode(q->getSharedFromThis(), &errorCode); + mcmm.encode(q->getSharedFromThis(), errorCode); } currentSendStep |= ChatMessagePrivate::Step::Multipart; } @@ -1147,7 +1147,7 @@ void ChatMessagePrivate::send() { lInfo() << "Encryption step already done, skipping"; } else { EncryptionChatMessageModifier ecmm; - ChatMessageModifier::Result result = ecmm.encode(q->getSharedFromThis(), &errorCode); + ChatMessageModifier::Result result = ecmm.encode(q->getSharedFromThis(), errorCode); if (result == ChatMessageModifier::Result::Error) { sal_error_info_set((SalErrorInfo *)op->get_error_info(), SalReasonNotAcceptable, "SIP", errorCode, "Unable to encrypt IM", nullptr); q->updateState(ChatMessage::State::NotDelivered); @@ -1165,7 +1165,7 @@ void ChatMessagePrivate::send() { } else { if (lp_config_get_int(chatRoom->getCore()->config, "sip", "use_cpim", 0) == 1) { CpimChatMessageModifier ccmm; - ccmm.encode(q->getSharedFromThis(), &errorCode); + ccmm.encode(q->getSharedFromThis(), errorCode); } currentSendStep |= ChatMessagePrivate::Step::Cpim; } diff --git a/src/chat/modifier/chat-message-modifier.h b/src/chat/modifier/chat-message-modifier.h index 8e448063c..c853fd5ae 100644 --- a/src/chat/modifier/chat-message-modifier.h +++ b/src/chat/modifier/chat-message-modifier.h @@ -20,9 +20,7 @@ #ifndef _CHAT_MESSAGE_MODIFIER_H_ #define _CHAT_MESSAGE_MODIFIER_H_ -#include "linphone/utils/general.h" #include "object/object.h" -#include "private.h" // ============================================================================= @@ -32,7 +30,7 @@ class ChatMessage; class ChatMessageModifier { public: - enum Result { + enum class Result { Skipped = -1, Done = 0, Suspended = 1, @@ -43,16 +41,16 @@ public: /** * This method will be called when the message is about to be sent. - * It should check first if the internalContent is filled. + * It should check first if the internalContent is filled. * If so, it should apply it's changes to it, otherwise it should use the contentsList. */ - virtual Result encode (const std::shared_ptr &message, int *errorCode) = 0; + virtual Result encode (const std::shared_ptr &message, int &errorCode) = 0; /** * This method will be called when the message is about to be received. * It should apply it's changes to the internal content, the last modifier will take care of filling the contentsList. */ - virtual Result decode (const std::shared_ptr &message, int *errorCode) = 0; + virtual Result decode (const std::shared_ptr &message, int &errorCode) = 0; }; LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index 04934aead..5f224a950 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -17,14 +17,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "cpim-chat-message-modifier.h" - +#include "address/address.h" +#include "chat/chat-message.h" #include "chat/cpim/cpim.h" #include "content/content-type.h" #include "content/content.h" -#include "address/address.h" #include "logger/logger.h" -#include "chat/chat-message.h" + +#include "cpim-chat-message-modifier.h" // ============================================================================= @@ -32,7 +32,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ChatMessageModifier::Result CpimChatMessageModifier::encode (const shared_ptr &message, int *errorCode) { +ChatMessageModifier::Result CpimChatMessageModifier::encode (const shared_ptr &message, int &errorCode) { Cpim::Message cpimMessage; Cpim::GenericHeader cpimContentTypeHeader; cpimContentTypeHeader.setName("Content-Type"); @@ -50,58 +50,53 @@ ChatMessageModifier::Result CpimChatMessageModifier::encode (const shared_ptrgetContents().front(); } - string contentType = content.getContentType().asString(); - const vector body = content.getBody(); - string contentBody(body.begin(), body.end()); - Cpim::GenericHeader contentTypeHeader; contentTypeHeader.setName("Content-Type"); - contentTypeHeader.setValue(contentType); + contentTypeHeader.setValue(content.getContentType().asString()); cpimMessage.addContentHeader(contentTypeHeader); + const string contentBody = content.getBodyAsString(); cpimMessage.setContent(contentBody); if (!cpimMessage.isValid()) { lError() << "[CPIM] Message is invalid: " << contentBody; - *errorCode = 500; + errorCode = 500; return ChatMessageModifier::Result::Error; - } else { - Content newContent; - ContentType newContentType("Message/CPIM"); - newContent.setContentType(newContentType); - newContent.setBody(cpimMessage.asString()); - message->setInternalContent(newContent); } + + Content newContent; + newContent.setContentType(ContentType("Message/CPIM")); + newContent.setBody(cpimMessage.asString()); + message->setInternalContent(newContent); + return ChatMessageModifier::Result::Done; } -ChatMessageModifier::Result CpimChatMessageModifier::decode (const shared_ptr &message, int *errorCode) { +ChatMessageModifier::Result CpimChatMessageModifier::decode (const shared_ptr &message, int &errorCode) { Content content; - if (!message->getInternalContent().isEmpty()) { + if (!message->getInternalContent().isEmpty()) content = message->getInternalContent(); - } else { + else content = message->getContents().front(); - } - if (content.getContentType() == ContentType::Cpim) { - const vector body = content.getBody(); - string contentBody(body.begin(), body.end()); - shared_ptr cpimMessage = Cpim::Message::createFromString(contentBody); - if (cpimMessage && cpimMessage->isValid()) { - Content newContent; - ContentType newContentType(cpimMessage->getContentHeaders()->front()->getValue()); - newContent.setContentType(newContentType); - newContent.setBody(cpimMessage->getContent()); - message->setInternalContent(newContent); - } else { - lError() << "[CPIM] Message is invalid: " << contentBody; - *errorCode = 500; - return ChatMessageModifier::Result::Error; - } - } else { + if (content.getContentType() != ContentType::Cpim) { lError() << "[CPIM] Message is not CPIM but " << content.getContentType().asString(); return ChatMessageModifier::Result::Skipped; } + + const string contentBody = content.getBodyAsString(); + const shared_ptr cpimMessage = Cpim::Message::createFromString(contentBody); + if (!cpimMessage || !cpimMessage->isValid()) { + lError() << "[CPIM] Message is invalid: " << contentBody; + errorCode = 500; + return ChatMessageModifier::Result::Error; + } + + Content newContent; + newContent.setContentType(ContentType(cpimMessage->getContentHeaders()->front()->getValue())); + newContent.setBody(cpimMessage->getContent()); + message->setInternalContent(newContent); + return ChatMessageModifier::Result::Done; } diff --git a/src/chat/modifier/cpim-chat-message-modifier.h b/src/chat/modifier/cpim-chat-message-modifier.h index 4e26091b2..7cb94c705 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.h +++ b/src/chat/modifier/cpim-chat-message-modifier.h @@ -30,8 +30,8 @@ class CpimChatMessageModifier : public ChatMessageModifier { public: CpimChatMessageModifier () = default; - Result encode (const std::shared_ptr &message, int *errorCode) override; - Result decode (const std::shared_ptr &message, int *errorCode) override; + Result encode (const std::shared_ptr &message, int &errorCode) override; + Result decode (const std::shared_ptr &message, int &errorCode) override; }; LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/encryption-chat-message-modifier.cpp b/src/chat/modifier/encryption-chat-message-modifier.cpp index 156b7350e..cfda245d2 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.cpp +++ b/src/chat/modifier/encryption-chat-message-modifier.cpp @@ -17,16 +17,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "encryption-chat-message-modifier.h" - -#include "object/object-p.h" +#include "address/address.h" #include "c-wrapper/c-wrapper.h" - +#include "chat/chat-message.h" +#include "chat/chat-room.h" #include "content/content-type.h" #include "content/content.h" -#include "address/address.h" -#include "chat/chat-room.h" -#include "chat/chat-message.h" + +#include "encryption-chat-message-modifier.h" // ============================================================================= @@ -34,51 +32,67 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ChatMessageModifier::Result EncryptionChatMessageModifier::encode (const shared_ptr &message, int *errorCode) { - int retval = -1; +ChatMessageModifier::Result EncryptionChatMessageModifier::encode ( + const shared_ptr &message, + int &errorCode +) { shared_ptr chatRoom = message->getChatRoom(); LinphoneImEncryptionEngine *imee = chatRoom->getCore()->im_encryption_engine; - if (imee) { - LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); - if (cbProcessOutgoingMessage) { - retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(chatRoom), L_GET_C_BACK_PTR(message->getSharedFromThis())); - if (retval == 0 || retval == 1) { - message->setIsSecured(true); - if (retval == 1) { - return ChatMessageModifier::Result::Suspended; - } - return ChatMessageModifier::Result::Done; - } else if (retval == -1) { - return ChatMessageModifier::Result::Skipped; - } - *errorCode = retval; - return ChatMessageModifier::Result::Error; - } + if (!imee) + return ChatMessageModifier::Result::Skipped; + + LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = + linphone_im_encryption_engine_cbs_get_process_outgoing_message( + linphone_im_encryption_engine_get_callbacks(imee) + ); + + if (!cbProcessOutgoingMessage) + return ChatMessageModifier::Result::Skipped; + + int retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(chatRoom), L_GET_C_BACK_PTR(message)); + if (retval == -1) + return ChatMessageModifier::Result::Skipped; + + if (retval != 0 && retval != 1) { + errorCode = retval; + return ChatMessageModifier::Result::Error; } - return ChatMessageModifier::Result::Skipped; + + message->setIsSecured(true); + if (retval == 1) + return ChatMessageModifier::Result::Suspended; + + return ChatMessageModifier::Result::Done; } -ChatMessageModifier::Result EncryptionChatMessageModifier::decode (const shared_ptr &message, int *errorCode) { - int retval = -1; +ChatMessageModifier::Result EncryptionChatMessageModifier::decode ( + const shared_ptr &message, + int &errorCode +) { shared_ptr chatRoom = message->getChatRoom(); LinphoneImEncryptionEngine *imee = chatRoom->getCore()->im_encryption_engine; - if (imee) { - LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsIncomingMessageCb cbProcessIncomingMessage = linphone_im_encryption_engine_cbs_get_process_incoming_message(imeeCbs); - if (cbProcessIncomingMessage) { - retval = cbProcessIncomingMessage(imee, L_GET_C_BACK_PTR(chatRoom), L_GET_C_BACK_PTR(message->getSharedFromThis())); - if (retval == 0) { - message->setIsSecured(true); - return ChatMessageModifier::Result::Done; - } else if (retval == -1) { - return ChatMessageModifier::Result::Skipped; - } - *errorCode = retval; - return ChatMessageModifier::Result::Error; - } + if (!imee) + return ChatMessageModifier::Result::Skipped; + + LinphoneImEncryptionEngineCbsIncomingMessageCb cbProcessIncomingMessage = + linphone_im_encryption_engine_cbs_get_process_incoming_message( + linphone_im_encryption_engine_get_callbacks(imee) + ); + + if (!cbProcessIncomingMessage) + return ChatMessageModifier::Result::Skipped; + + int retval = cbProcessIncomingMessage(imee, L_GET_C_BACK_PTR(chatRoom), L_GET_C_BACK_PTR(message)); + if (retval != 0 && retval != -1) { + errorCode = retval; + return ChatMessageModifier::Result::Error; } - return ChatMessageModifier::Result::Skipped; + + if (retval == -1) + return ChatMessageModifier::Result::Skipped; + + message->setIsSecured(true); + return ChatMessageModifier::Result::Done; } LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/encryption-chat-message-modifier.h b/src/chat/modifier/encryption-chat-message-modifier.h index 6bd8833f2..6b17c9b5f 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.h +++ b/src/chat/modifier/encryption-chat-message-modifier.h @@ -30,8 +30,8 @@ class EncryptionChatMessageModifier : public ChatMessageModifier { public: EncryptionChatMessageModifier () = default; - Result encode (const std::shared_ptr &message, int *errorCode) override; - Result decode (const std::shared_ptr &message, int *errorCode) override; + Result encode (const std::shared_ptr &message, int &errorCode) override; + Result decode (const std::shared_ptr &message, int &errorCode) override; }; LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index 72f1064ca..89b7c008f 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -17,49 +17,53 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "multipart-chat-message-modifier.h" - #include "address/address.h" -#include "chat/chat-room.h" #include "chat/chat-message.h" +#include "chat/chat-room.h" +#include "content/content-type.h" #include "logger/logger.h" +#include "multipart-chat-message-modifier.h" + // ============================================================================= using namespace std; LINPHONE_BEGIN_NAMESPACE -ChatMessageModifier::Result MultipartChatMessageModifier::encode (const shared_ptr &message, int *errorCode) { - if (message->getContents().size() > 1) { - LinphoneCore *lc = message->getChatRoom()->getCore(); - char tmp[64]; - lc->sal->create_uuid(tmp, sizeof(tmp)); - string boundary = tmp; - stringstream multipartMessage; +ChatMessageModifier::Result MultipartChatMessageModifier::encode ( + const shared_ptr &message, + int &errorCode +) { + if (message->getContents().size() <= 1) + return ChatMessageModifier::Result::Skipped; + LinphoneCore *lc = message->getChatRoom()->getCore(); + char tmp[64]; + lc->sal->create_uuid(tmp, sizeof(tmp)); + string boundary = tmp; + stringstream multipartMessage; + + multipartMessage << "--" << boundary; + for (const auto &content : message->getContents()) { + multipartMessage << "\r\n"; + multipartMessage << "Content-Type: " << content.getContentType().asString() << "\r\n\r\n"; + multipartMessage << content.getBodyAsString() << "\r\n\r\n"; multipartMessage << "--" << boundary; - for (auto it = message->getContents().begin(); it != message->getContents().end(); it++) { - multipartMessage << "\r\n"; - multipartMessage << "Content-Type: " << it->getContentType().asString() << "\r\n\r\n"; - multipartMessage << it->getBodyAsString() << "\r\n\r\n"; - multipartMessage << "--" << boundary; - } - multipartMessage << "--"; - - Content newContent; - ContentType newContentType("multipart/mixed"); - newContentType.setParameter("boundary=" + boundary); - newContent.setContentType(newContentType); - newContent.setBody(multipartMessage.str()); - message->setInternalContent(newContent); - - return ChatMessageModifier::Result::Done; } - return ChatMessageModifier::Result::Skipped; -} + multipartMessage << "--"; -ChatMessageModifier::Result MultipartChatMessageModifier::decode (const shared_ptr &message, int *errorCode) { + Content newContent; + ContentType newContentType("multipart/mixed"); + newContentType.setParameter("boundary=" + boundary); + newContent.setContentType(newContentType); + newContent.setBody(multipartMessage.str()); + message->setInternalContent(newContent); + + return ChatMessageModifier::Result::Done; +} + +ChatMessageModifier::Result MultipartChatMessageModifier::decode (const shared_ptr &message, int &errorCode) { if (message->getInternalContent().getContentType().getType() == "multipart") { string boundary = message->getInternalContent().getContentType().getParameter(); if (boundary.empty()) { @@ -74,11 +78,11 @@ ChatMessageModifier::Result MultipartChatMessageModifier::decode (const shared_p } boundary = "--" + boundary.substr(pos + 1); lInfo() << "Multipart boundary is " << boundary; - + const vector body = message->getInternalContent().getBody(); string contentsString(body.begin(), body.end()); - pos = contentsString.find(boundary); + pos = contentsString.find(boundary); if (pos == string::npos) { lError() << "Boundary not found in body !"; return ChatMessageModifier::Result::Error; @@ -89,9 +93,9 @@ ChatMessageModifier::Result MultipartChatMessageModifier::decode (const shared_p do { end = contentsString.find(boundary, start); if (end != string::npos) { - string contentString = contentsString.substr(start, end-start); + string contentString = contentsString.substr(start, end - start); - size_t contentTypePos = contentString.find(": ") + 2; // 2 is the size of : + size_t contentTypePos = contentString.find(": ") + 2; // 2 is the size of : size_t endOfLinePos = contentString.find("\r\n"); if (contentTypePos >= endOfLinePos) { lError() << "Content should start by a 'Content-Type: ' line !"; diff --git a/src/chat/modifier/multipart-chat-message-modifier.h b/src/chat/modifier/multipart-chat-message-modifier.h index 4336af26c..dd6328a22 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.h +++ b/src/chat/modifier/multipart-chat-message-modifier.h @@ -30,8 +30,8 @@ class MultipartChatMessageModifier : public ChatMessageModifier { public: MultipartChatMessageModifier () = default; - Result encode (const std::shared_ptr &message, int *errorCode) override; - Result decode (const std::shared_ptr &message, int *errorCode) override; + Result encode (const std::shared_ptr &message, int &errorCode) override; + Result decode (const std::shared_ptr &message, int &errorCode) override; }; LINPHONE_END_NAMESPACE diff --git a/src/content/content.h b/src/content/content.h index 1e547ddf1..abf86c9d7 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -22,7 +22,6 @@ #include -#include "content-type.h" #include "object/app-data-container.h" #include "object/clonable-object.h" @@ -30,6 +29,7 @@ LINPHONE_BEGIN_NAMESPACE +class ContentType; class ContentPrivate; class LINPHONE_PUBLIC Content : public ClonableObject, public AppDataContainer { diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index da472eeae..f1f7b8844 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -29,6 +29,7 @@ #include "abstract/abstract-db-p.h" #include "chat/chat-message.h" #include "conference/participant.h" +#include "content/content-type.h" #include "content/content.h" #include "db/provider/db-session-provider.h" #include "event-log/call-event.h" diff --git a/src/sal/call-op.cpp b/src/sal/call-op.cpp index 4929e6085..8fac3f4e2 100644 --- a/src/sal/call-op.cpp +++ b/src/sal/call-op.cpp @@ -24,6 +24,8 @@ #include #include +#include "content/content-type.h" + using namespace std; LINPHONE_BEGIN_NAMESPACE @@ -35,15 +37,15 @@ SalCallOp::~SalCallOp() { int SalCallOp::set_local_media_description(SalMediaDescription *desc) { if (desc) sal_media_description_ref(desc); - + belle_sip_error_code error; belle_sdp_session_description_t *sdp = media_description_to_sdp(desc); vector buffer = marshal_media_description(sdp, error); if (error != BELLE_SIP_OK) return -1; - + this->local_body.setContentType(ContentType::Sdp); this->local_body.setBody(move(buffer)); - + if (this->local_media) sal_media_description_unref(this->local_media); this->local_media=desc; @@ -66,7 +68,7 @@ int SalCallOp::set_local_body(const Content &body) { int SalCallOp::set_local_body(const Content &&body) { if (!body.isValid()) return -1; - + if (body.getContentType() == ContentType::Sdp) { SalMediaDescription *desc = NULL; if (body.getSize() > 0) { @@ -81,7 +83,7 @@ int SalCallOp::set_local_body(const Content &&body) { if (this->local_media) sal_media_description_unref(this->local_media); this->local_media = desc; } - + this->local_body = body; return 0; } @@ -98,12 +100,12 @@ int SalCallOp::set_custom_body(belle_sip_message_t *msg, const Content &body) { ContentType contentType = body.getContentType(); string contentDisposition = body.getContentDisposition(); size_t bodySize = body.getBody().size(); - + if (bodySize > SIP_MESSAGE_BODY_LIMIT) { bctbx_error("trying to add a body greater than %lukB to message [%p]", (unsigned long)SIP_MESSAGE_BODY_LIMIT/1024, msg); return -1; } - + if (contentType.isValid()) { belle_sip_header_content_type_t *content_type = belle_sip_header_content_type_create(contentType.getType().c_str(), contentType.getSubType().c_str()); belle_sip_message_add_header(msg, BELLE_SIP_HEADER(content_type)); @@ -114,13 +116,13 @@ int SalCallOp::set_custom_body(belle_sip_message_t *msg, const Content &body) { } belle_sip_header_content_length_t *content_length = belle_sip_header_content_length_create(bodySize); belle_sip_message_add_header(msg, BELLE_SIP_HEADER(content_length)); - + if (bodySize > 0) { char *buffer = bctbx_new(char, bodySize); memcpy(buffer, body.getBody().data(), bodySize); belle_sip_message_assign_body(msg, buffer, bodySize); } - + return 0; } @@ -139,25 +141,25 @@ std::vector SalCallOp::marshal_media_description(belle_sdp_session_descrip buff.resize(bufLen); } } - + /* give up if hard limit reached */ if (error != BELLE_SIP_OK) { ms_error("Buffer too small (%d) or not enough memory, giving up SDP", (int)bufLen); return std::vector(); // return a new vector in order to free the buffer held by 'buff' vector } - + buff.resize(length); return buff; } int SalCallOp::set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* session_desc) { belle_sip_error_code error; - + if (session_desc == NULL) return -1; vector buff = marshal_media_description(session_desc, error); if (error != BELLE_SIP_OK) return -1; - + Content body; body.setContentType(ContentType::Sdp); body.setBody(move(buff)); @@ -230,7 +232,7 @@ Content SalCallOp::extract_body(belle_sip_message_t *message) { const char *subtype_str = content_type ? belle_sip_header_content_type_get_subtype(content_type) : NULL; size_t length = content_length ? belle_sip_header_content_length_get_content_length(content_length) : 0; const char *body_str = belle_sip_message_get_body(message); - + if (type_str && subtype_str) body.setContentType(ContentType(type_str, subtype_str)); if (contentDisposition) body.setContentDisposition(belle_sip_header_content_disposition_get_content_disposition(contentDisposition)); @@ -241,7 +243,7 @@ Content SalCallOp::extract_body(belle_sip_message_t *message) { int SalCallOp::parse_sdp_body(const Content &body,belle_sdp_session_description_t** session_desc, SalReason *error) { *session_desc = NULL; *error = SalReasonNone; - + if (this->sdp_handling == SalOpSDPSimulateError) { ms_error("Simulating SDP parsing error for op %p", this); *error = SalReasonNotAcceptable; @@ -252,7 +254,7 @@ int SalCallOp::parse_sdp_body(const Content &body,belle_sdp_session_description_ ms_error("Simulating no SDP for op %p", this); return 0; } - + *session_desc = belle_sdp_session_description_parse(body.getBodyAsString().c_str()); if (*session_desc == NULL) { ms_error("Failed to parse SDP message."); @@ -301,7 +303,7 @@ void SalCallOp::sdp_process(){ } } } - + this->sdp_answer=(belle_sdp_session_description_t *)belle_sip_object_ref(media_description_to_sdp(this->result)); /*once we have generated the SDP answer, we modify the result description for processing by the upper layer. It should contains media parameters constraint from the remote offer, not our response*/ @@ -562,10 +564,10 @@ int SalCallOp::is_media_description_acceptable(SalMediaDescription *md) { SalReason SalCallOp::process_body_for_invite(belle_sip_request_t* invite) { SalReason reason = SalReasonNone; - + Content body = extract_body(BELLE_SIP_MESSAGE(invite)); if (!body.isValid()) return SalReasonUnsupportedContent; - + if (body.getContentType() == ContentType::Sdp) { belle_sdp_session_description_t* sdp; if (parse_sdp_body(body, &sdp, &reason) == 0) { @@ -1191,7 +1193,7 @@ int SalCallOp::refer_with_replaces(SalCallOp *other_call_op) { /*rfc3891 ... 4. User Agent Client Behavior: Sending a Replaces Header - + A User Agent that wishes to replace a single existing early or confirmed dialog with a new dialog of its own, MAY send the target User Agent an INVITE request containing a Replaces header field. The @@ -1200,7 +1202,7 @@ int SalCallOp::refer_with_replaces(SalCallOp *other_call_op) { and sends the new INVITE to the target.*/ from_tag=belle_sip_dialog_get_local_tag(other_call_op->dialog); to_tag=belle_sip_dialog_get_remote_tag(other_call_op->dialog); - + replaces=belle_sip_header_replaces_create(belle_sip_header_call_id_get_call_id(belle_sip_dialog_get_call_id(other_call_op->dialog)) ,from_tag,to_tag); escaped_replaces=belle_sip_header_replaces_value_to_escaped_string(replaces); @@ -1223,7 +1225,7 @@ SalCallOp *SalCallOp::get_replaces() { if (this->replaces){ /*rfc3891 3. User Agent Server Behavior: Receiving a Replaces Header - + The Replaces header contains information used to match an existing SIP dialog (call-id, to-tag, and from-tag). Upon receiving an INVITE with a Replaces header, the User Agent (UA) attempts to match this @@ -1438,7 +1440,7 @@ void SalCallOp::process_refer(const belle_sip_request_event_t *event, belle_sip_ belle_sip_header_referred_by_t *referred_by= belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_referred_by_t); belle_sip_response_t* resp; belle_sip_uri_t* refer_to_uri; - + ms_message("Receiving REFER request on op [%p]", this); if (refer_to) { refer_to_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to)); diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index 35af930bc..fe86d493e 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -16,10 +16,11 @@ * along with this program. If not, see . */ -#include "chat/cpim/cpim.h" #include "address/address.h" #include "chat/basic-chat-room.h" #include "chat/chat-message.h" +#include "chat/cpim/cpim.h" +#include "content/content-type.h" #include "liblinphone_tester.h" diff --git a/tester/multipart-tester.cpp b/tester/multipart-tester.cpp index b02ea3f4f..ba0917de8 100644 --- a/tester/multipart-tester.cpp +++ b/tester/multipart-tester.cpp @@ -19,6 +19,7 @@ #include "address/address.h" #include "chat/basic-chat-room.h" #include "chat/chat-message.h" +#include "content/content-type.h" #include "liblinphone_tester.h" From e8d1503dfb73b8654b62fb12aee64ecf73ed09a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Wed, 11 Oct 2017 15:36:11 +0200 Subject: [PATCH 0434/2215] Fix crash while PUBLISH sending --- coreapi/event.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/event.c b/coreapi/event.c index 33f7919b2..a8fe6a043 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -300,7 +300,8 @@ static LinphoneEvent *_linphone_core_create_publish(LinphoneCore *core, Linphone if (!resource && cfg) resource = linphone_proxy_config_get_identity_address(cfg); - lev = linphone_event_new(lc,LinphoneSubscriptionInvalidDir, event,expires); + lev = linphone_event_new_with_op(lc, new SalPublishOp(lc->sal), LinphoneSubscriptionInvalidDir, event); + lev->expires = expires; linphone_configure_op_with_proxy(lc,lev->op,resource,NULL, !!lp_config_get_int(lc->config,"sip","publish_msg_with_contact",0),cfg); lev->op->set_manual_refresher_mode(!lp_config_get_int(lc->config,"sip","refresh_generic_publish",1)); return lev; From 73113495cb3e74565e429ca2bc4886d8b323149f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Tue, 3 Oct 2017 15:19:02 +0200 Subject: [PATCH 0435/2215] Make CMake to clean the old XML and HTML Doxygen documentations out before generating them again --- coreapi/help/doc/doxygen/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/coreapi/help/doc/doxygen/CMakeLists.txt b/coreapi/help/doc/doxygen/CMakeLists.txt index 95a5528ea..8d066161b 100644 --- a/coreapi/help/doc/doxygen/CMakeLists.txt +++ b/coreapi/help/doc/doxygen/CMakeLists.txt @@ -36,6 +36,7 @@ if (ENABLE_DOC OR ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRA string(CONCAT DOXYGEN_INPUT ${DOXYGEN_INPUT} " \"${PROJECT_SOURCE_DIR}/coreapi/help/examples/C\"") configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/html/index.html" "${CMAKE_CURRENT_BINARY_DIR}/xml/index.xml" + COMMAND ${CMAKE_COMMAND} -E remove -f html/* xml/* COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile DEPENDS ${DOC_INPUT_FILES} ) @@ -51,3 +52,4 @@ if (ENABLE_DOC OR ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRA endif () endif () endif () + From af625e5c8f83f0b2ba3ccf5252eb54c59934d9f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Wed, 11 Oct 2017 16:11:17 +0200 Subject: [PATCH 0436/2215] Fix wrappers generation --- coreapi/vtables.c | 2 +- include/linphone/api/c-call.h | 7 ------- include/linphone/core.h | 8 -------- include/linphone/wrapper_utils.h | 18 ++++++++++++++++++ src/c-wrapper/api/c-call.cpp | 2 +- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/coreapi/vtables.c b/coreapi/vtables.c index 6a8691c02..b14221950 100644 --- a/coreapi/vtables.c +++ b/coreapi/vtables.c @@ -332,7 +332,7 @@ void linphone_core_remove_listener(LinphoneCore *lc, const LinphoneCoreVTable *v } } -bctbx_list_t *linphone_core_get_callbacks(const LinphoneCore *lc) { +bctbx_list_t *linphone_core_get_callbacks_list(const LinphoneCore *lc) { bctbx_list_t *result; bctbx_list_t *it; for(it=lc->vtable_refs; it!=NULL; it=it->next){ diff --git a/include/linphone/api/c-call.h b/include/linphone/api/c-call.h index 589056f19..fe3c2c768 100644 --- a/include/linphone/api/c-call.h +++ b/include/linphone/api/c-call.h @@ -756,13 +756,6 @@ LINPHONE_PUBLIC void linphone_call_add_callbacks(LinphoneCall *call, LinphoneCal */ LINPHONE_PUBLIC void linphone_call_remove_callbacks(LinphoneCall *call, LinphoneCallCbs *cbs); -/** - * Gets the list of listener in the call - * @param[in] call LinphoneCall object - * @return the list of LinphoneCallCbs - */ -LINPHONE_PUBLIC const bctbx_list_t *linphone_call_get_callbacks(const LinphoneCall *call); - /** * Gets the current LinphoneCallCbs. * This is meant only to be called from a callback to be able to get the user_data associated with the LinphoneCallCbs that is calling the callback. diff --git a/include/linphone/core.h b/include/linphone/core.h index 421e88e28..e78ba8e4c 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -975,14 +975,6 @@ LINPHONE_DEPRECATED LINPHONE_PUBLIC void linphone_core_remove_listener(LinphoneC */ LINPHONE_PUBLIC void linphone_core_remove_callbacks(LinphoneCore *lc, const LinphoneCoreCbs *cbs); -/** - * @ingroup initializing - * Gets the list of listener in the core - * @param lc The #LinphoneCore - * @return the list of LinphoneCoreCbs - */ -LINPHONE_PUBLIC bctbx_list_t *linphone_core_get_callbacks(const LinphoneCore *lc); - /** * Sets the user agent string used in SIP messages, ideally called just after linphone_core_new() or linphone_core_init(). * @param[in] lc LinphoneCore object diff --git a/include/linphone/wrapper_utils.h b/include/linphone/wrapper_utils.h index d9990aa50..35c335595 100644 --- a/include/linphone/wrapper_utils.h +++ b/include/linphone/wrapper_utils.h @@ -25,6 +25,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef _WRAPPER_UTILS_H #define _WRAPPER_UTILS_H +#include +#include "linphone/defs.h" #include "linphone/types.h" #ifdef __cplusplus @@ -36,6 +38,22 @@ extern "C" { * @{ */ +/** + * @brief Gets the list of listener in the core. + * @param lc The #LinphoneCore. + * @return The list of #LinphoneCoreCbs. + * @donotwrap + */ +LINPHONE_PUBLIC bctbx_list_t *linphone_core_get_callbacks_list(const LinphoneCore *lc); + +/** + * @brief Gets the list of listener in the call. + * @param[in] call #LinphoneCall object. + * @return The list of #LinphoneCallCbs. + * @donotwrap + */ +LINPHONE_PUBLIC const bctbx_list_t *linphone_call_get_callbacks_list(const LinphoneCall *call); + /** * Send a message to peer member of this chat room. * diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 47a6492cc..c6d722fae 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -1097,7 +1097,7 @@ LinphoneCallCbs *linphone_call_get_current_callbacks (const LinphoneCall *call) return call->currentCbs; } -const bctbx_list_t *linphone_call_get_callbacks(const LinphoneCall *call) { +const bctbx_list_t *linphone_call_get_callbacks_list(const LinphoneCall *call) { return call->callbacks; } From 054a929f9b40f459d14e2440f4d8181fb7592fed Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 11 Oct 2017 16:15:17 +0200 Subject: [PATCH 0437/2215] Compilation fixes --- src/chat/is-composing.cpp | 2 +- wrappers/java/jni.mustache | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chat/is-composing.cpp b/src/chat/is-composing.cpp index d19aa78ae..9de87f525 100644 --- a/src/chat/is-composing.cpp +++ b/src/chat/is-composing.cpp @@ -128,7 +128,7 @@ void IsComposing::startRefreshTimer () { void IsComposing::startRemoteRefreshTimer (const char *refreshStr) { unsigned int duration = getRemoteRefreshTimerDuration(); if (refreshStr) - duration = static_cast(stoi(refreshStr)); + duration = static_cast(Utils::stoi(refreshStr)); if (!remoteRefreshTimer) { remoteRefreshTimer = core->sal->create_timer(remoteRefreshTimerExpired, this, duration * 1000, "composing remote refresh timeout"); diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index f0040cc49..499e30659 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -241,7 +241,7 @@ void {{jniPackage}}{{classCName}}Impl_addListener(JNIEnv* env, jobject thiz, jlo void {{jniPackage}}{{classCName}}Impl_removeListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { {{classCName}} *cptr = ({{classCName}}*)ptr; - const bctbx_list_t *cbs_list = {{cPrefix}}_get_callbacks(cptr); + const bctbx_list_t *cbs_list = {{cPrefix}}_get_callbacks_list(cptr); bctbx_list_t *it; for (it = cbs_list; it != NULL; it = it->next) { {{classCName}}Cbs *cbs = ({{classCName}}Cbs *)it->data; From aace7e68699c099d406716be2c639e408b476e1a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 11 Oct 2017 16:17:31 +0200 Subject: [PATCH 0438/2215] Another compilation fix --- src/c-wrapper/internal/c-tools.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 6f3a09687..f533caf50 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -116,7 +116,7 @@ private: static inline void abort (const char *message) { std::cerr << "[FATAL C-WRAPPER]" << message << std::endl; - std::abort(); + std::terminate(); } public: From 1922ce7e1e85c087e1dd829dca2118ca39f2bfc3 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 11 Oct 2017 16:23:33 +0200 Subject: [PATCH 0439/2215] Fix another Android build issue --- src/xml/conference-info.cpp | 2 ++ src/xml/conference-info.h | 2 ++ src/xml/prologue.txt | 2 ++ src/xml/resource-lists.cpp | 2 ++ src/xml/resource-lists.h | 2 ++ src/xml/xml.cpp | 2 ++ src/xml/xml.h | 2 ++ 7 files changed, 14 insertions(+) diff --git a/src/xml/conference-info.cpp b/src/xml/conference-info.cpp index 110ec162a..5378d95c5 100644 --- a/src/xml/conference-info.cpp +++ b/src/xml/conference-info.cpp @@ -35,8 +35,10 @@ // #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push +#ifndef __ANDROID__ #pragma GCC diagnostic ignored "-Wsuggest-override" #endif +#endif // // End prologue. diff --git a/src/xml/conference-info.h b/src/xml/conference-info.h index a8bef962a..6743d0d6f 100644 --- a/src/xml/conference-info.h +++ b/src/xml/conference-info.h @@ -50,8 +50,10 @@ // #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push +#ifndef __ANDROID__ #pragma GCC diagnostic ignored "-Wsuggest-override" #endif +#endif // // End prologue. diff --git a/src/xml/prologue.txt b/src/xml/prologue.txt index 1b3a4dc48..a9ad12572 100644 --- a/src/xml/prologue.txt +++ b/src/xml/prologue.txt @@ -1,4 +1,6 @@ #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push +#ifndef __ANDROID__ #pragma GCC diagnostic ignored "-Wsuggest-override" #endif +#endif diff --git a/src/xml/resource-lists.cpp b/src/xml/resource-lists.cpp index 848bcc6f1..01a3d9acf 100644 --- a/src/xml/resource-lists.cpp +++ b/src/xml/resource-lists.cpp @@ -35,8 +35,10 @@ // #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push +#ifndef __ANDROID__ #pragma GCC diagnostic ignored "-Wsuggest-override" #endif +#endif // // End prologue. diff --git a/src/xml/resource-lists.h b/src/xml/resource-lists.h index ce7f1a8ce..fa85b5adf 100644 --- a/src/xml/resource-lists.h +++ b/src/xml/resource-lists.h @@ -50,8 +50,10 @@ // #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push +#ifndef __ANDROID__ #pragma GCC diagnostic ignored "-Wsuggest-override" #endif +#endif // // End prologue. diff --git a/src/xml/xml.cpp b/src/xml/xml.cpp index b691c35cf..71588e366 100644 --- a/src/xml/xml.cpp +++ b/src/xml/xml.cpp @@ -35,8 +35,10 @@ // #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push +#ifndef __ANDROID__ #pragma GCC diagnostic ignored "-Wsuggest-override" #endif +#endif // // End prologue. diff --git a/src/xml/xml.h b/src/xml/xml.h index 0f1554543..04b3dc788 100644 --- a/src/xml/xml.h +++ b/src/xml/xml.h @@ -50,8 +50,10 @@ // #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push +#ifndef __ANDROID__ #pragma GCC diagnostic ignored "-Wsuggest-override" #endif +#endif // // End prologue. From b744a8e02516b3af583d6a3144e03e408228f0c8 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 11 Oct 2017 16:51:57 +0200 Subject: [PATCH 0440/2215] More Android compilation fixes --- coreapi/linphonecore.c | 2 +- coreapi/linphonecore_jni.cc | 120 ++++++++++++++++++------------------ 2 files changed, 61 insertions(+), 61 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 143dc746d..bab227b5b 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1159,7 +1159,7 @@ static void sound_config_read(LinphoneCore *lc) card=ms_alsa_card_new_custom(d+l,d+l); ms_snd_card_manager_add_card(ms_factory_get_snd_card_manager(lc->factory),card); *i=s; - l=i-d+1; + l=(size_t)(i-d)+1; } if(d[l]!='\0') { card=ms_alsa_card_new_custom(d+l,d+l); diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 54a2e42ed..77f1124fa 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -620,12 +620,12 @@ jobject getCall(JNIEnv *env, LinphoneCall *call){ LinphoneCore *lc = linphone_call_get_core(call); LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc); - void *up=linphone_call_get_user_pointer(call); + void *up=linphone_call_get_user_data(call); if (up==NULL){ jobj=env->NewObject(ljb->callClass, ljb->callCtrId, (jlong)call); jobj=env->NewGlobalRef(jobj); - linphone_call_set_user_pointer(call,(void*)jobj); + linphone_call_set_user_data(call,(void*)jobj); linphone_call_ref(call); }else{ jobj=(jobject)up; @@ -1086,7 +1086,7 @@ public: msg); handle_possible_java_exception(env, lcData->listener); if (state==LinphoneCallReleased) { - linphone_call_set_user_pointer(call,NULL); + linphone_call_set_user_data(call,NULL); env->DeleteGlobalRef(jcall); } if (msg) { @@ -1485,8 +1485,8 @@ public: LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); jobject jcontent = content ? create_java_linphone_content(env, content) : NULL; - jobject jbuffer = buff ? env->NewDirectByteBuffer(buff, asking) : NULL; - *size = env->CallIntMethod(lcData->listener, + jobject jbuffer = buff ? env->NewDirectByteBuffer(buff, (jlong)asking) : NULL; + *size = (size_t)env->CallIntMethod(lcData->listener, ljb->fileTransferSendId, lcData->core, (jmsg = getChatMessage(env, message)), @@ -1518,8 +1518,8 @@ public: LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); - jbyteArray jbytes = env->NewByteArray(size); - env->SetByteArrayRegion(jbytes, 0, size, (jbyte*)buff); + jbyteArray jbytes = env->NewByteArray((jint)size); + env->SetByteArrayRegion(jbytes, 0, (jint)size, (jbyte*)buff); jobject jcontent = content ? create_java_linphone_content(env, content) : NULL; env->CallVoidMethod(lcData->listener, @@ -1824,13 +1824,13 @@ extern "C" jobjectArray Java_org_linphone_core_LinphoneCoreImpl_getProxyConfigLi const bctbx_list_t* proxies = linphone_core_get_proxy_config_list((LinphoneCore*)lc); size_t proxyCount = bctbx_list_size(proxies); LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data((LinphoneCore *)lc); - jobjectArray jProxies = env->NewObjectArray(proxyCount,ljb->proxyClass,NULL); + jobjectArray jProxies = env->NewObjectArray((jint)proxyCount,ljb->proxyClass,NULL); for (size_t i = 0; i < proxyCount; i++ ) { LinphoneProxyConfig* proxy = (LinphoneProxyConfig*)proxies->data; jobject jproxy = getProxy(env,proxy,thiz); if(jproxy != NULL){ - env->SetObjectArrayElement(jProxies, i, jproxy); + env->SetObjectArrayElement(jProxies, (int)i, jproxy); } proxies = proxies->next; } @@ -1858,11 +1858,11 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_removeAuthInfo(JNIEnv* e extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_getAuthInfosList(JNIEnv* env, jobject thiz,jlong lc) { const bctbx_list_t* authInfos = linphone_core_get_auth_info_list((LinphoneCore*)lc); size_t listCount = bctbx_list_size(authInfos); - jlongArray jAuthInfos = env->NewLongArray(listCount); + jlongArray jAuthInfos = env->NewLongArray((jint)listCount); jlong *jInternalArray = env->GetLongArrayElements(jAuthInfos, NULL); for (size_t i = 0; i < listCount; i++ ) { - jInternalArray[i] = (unsigned long) (authInfos->data); + jInternalArray[i] = (jlong) (authInfos->data); authInfos = authInfos->next; } @@ -2111,14 +2111,14 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_sendDtmf( JNIEnv* env ,jobject thiz ,jlong lc ,jchar dtmf) { - linphone_core_send_dtmf((LinphoneCore*)lc,dtmf); + linphone_core_send_dtmf((LinphoneCore*)lc,(char)dtmf); } extern "C" void Java_org_linphone_core_LinphoneCoreImpl_playDtmf( JNIEnv* env ,jobject thiz ,jlong lc ,jchar dtmf ,jint duration) { - linphone_core_play_dtmf((LinphoneCore*)lc,dtmf,duration); + linphone_core_play_dtmf((LinphoneCore*)lc,(char)dtmf,duration); } extern "C" void Java_org_linphone_core_LinphoneCoreImpl_stopDtmf( JNIEnv* env ,jobject thiz @@ -2171,11 +2171,11 @@ extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_listVideoPayloadTy ,jlong lc) { const bctbx_list_t* codecs = linphone_core_get_video_codecs((LinphoneCore*)lc); size_t codecsCount = bctbx_list_size(codecs); - jlongArray jCodecs = env->NewLongArray(codecsCount); + jlongArray jCodecs = env->NewLongArray((jint)codecsCount); jlong *jInternalArray = env->GetLongArrayElements(jCodecs, NULL); for (size_t i = 0; i < codecsCount; i++ ) { - jInternalArray[i] = (unsigned long) (codecs->data); + jInternalArray[i] = (long) (codecs->data); codecs = codecs->next; } @@ -2201,11 +2201,11 @@ extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_listAudioPayloadTy ,jlong lc) { const bctbx_list_t* codecs = linphone_core_get_audio_codecs((LinphoneCore*)lc); size_t codecsCount = bctbx_list_size(codecs); - jlongArray jCodecs = env->NewLongArray(codecsCount); + jlongArray jCodecs = env->NewLongArray((int)codecsCount); jlong *jInternalArray = env->GetLongArrayElements(jCodecs, NULL); for (size_t i = 0; i < codecsCount; i++ ) { - jInternalArray[i] = (unsigned long) (codecs->data); + jInternalArray[i] = (long) (codecs->data); codecs = codecs->next; } @@ -2408,13 +2408,13 @@ extern "C" jobjectArray Java_org_linphone_core_LinphoneCoreImpl_getFriendList(JN const bctbx_list_t* friends = linphone_core_get_friend_list((LinphoneCore*)lc); size_t friendsSize = bctbx_list_size(friends); LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data((LinphoneCore *)lc); - jobjectArray jFriends = env->NewObjectArray(friendsSize,ljb->friendClass,NULL); + jobjectArray jFriends = env->NewObjectArray((int)friendsSize,ljb->friendClass,NULL); for (size_t i = 0; i < friendsSize; i++) { LinphoneFriend* lfriend = (LinphoneFriend*)friends->data; jobject jfriend = getFriend(env,lfriend); if(jfriend != NULL){ - env->SetObjectArrayElement(jFriends, i, jfriend); + env->SetObjectArrayElement(jFriends, (int)i, jfriend); env->DeleteLocalRef(jfriend); } friends = friends->next; @@ -2429,13 +2429,13 @@ extern "C" jobjectArray Java_org_linphone_core_LinphoneCoreImpl_getFriendLists(J const bctbx_list_t* friends = linphone_core_get_friends_lists((LinphoneCore*)lc); size_t friendsSize = bctbx_list_size(friends); LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data((LinphoneCore *)lc); - jobjectArray jFriends = env->NewObjectArray(friendsSize,ljb->friendListClass,NULL); + jobjectArray jFriends = env->NewObjectArray((int)friendsSize,ljb->friendListClass,NULL); for (size_t i = 0; i < friendsSize; i++) { LinphoneFriendList* lfriend = (LinphoneFriendList*)friends->data; jobject jfriend = getFriendList(env,lfriend); if(jfriend != NULL){ - env->SetObjectArrayElement(jFriends, i, jfriend); + env->SetObjectArrayElement(jFriends, (int)i, jfriend); } friends = friends->next; } @@ -2660,7 +2660,7 @@ extern "C" int Java_org_linphone_core_LinphoneCoreImpl_startEchoTester(JNIEnv* ,jobject thiz ,jlong lc ,jint rate) { - return linphone_core_start_echo_tester((LinphoneCore*)lc, rate); + return linphone_core_start_echo_tester((LinphoneCore*)lc, (unsigned int)rate); } extern "C" int Java_org_linphone_core_LinphoneCoreImpl_stopEchoTester(JNIEnv* env @@ -3627,11 +3627,11 @@ extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_getCallLogs(JNIEnv ,jlong lc) { const bctbx_list_t *logs = linphone_core_get_call_logs((LinphoneCore *) lc); size_t logsCount = bctbx_list_size(logs); - jlongArray jLogs = env->NewLongArray(logsCount); + jlongArray jLogs = env->NewLongArray((int)logsCount); jlong *jInternalArray = env->GetLongArrayElements(jLogs, NULL); for (size_t i = 0; i < logsCount; i++) { - jInternalArray[i] = (unsigned long) (logs->data); + jInternalArray[i] = (long) (logs->data); logs = logs->next; } @@ -4069,13 +4069,13 @@ extern "C" jobjectArray Java_org_linphone_core_LinphoneFriendListImpl_getFriendL size_t friendsSize = bctbx_list_size(friends); LinphoneCore *lc = linphone_friend_list_get_core((LinphoneFriendList *)list); LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc); - jobjectArray jFriends = env->NewObjectArray(friendsSize,ljb->friendClass,NULL); + jobjectArray jFriends = env->NewObjectArray((int)friendsSize,ljb->friendClass,NULL); for (size_t i = 0; i < friendsSize; i++) { LinphoneFriend* lfriend = (LinphoneFriend*)friends->data; jobject jfriend = getFriend(env,lfriend); if(jfriend != NULL){ - env->SetObjectArrayElement(jFriends, i, jfriend); + env->SetObjectArrayElement(jFriends, (int)i, jfriend); env->DeleteLocalRef(jfriend); } friends = friends->next; @@ -4095,10 +4095,10 @@ extern "C" jlongArray Java_org_linphone_core_LinphoneFriendImpl_getAddresses(JNI ,jlong ptr) { const bctbx_list_t *addresses = linphone_friend_get_addresses((LinphoneFriend*)ptr); size_t size = bctbx_list_size(addresses); - jlongArray jaddresses = env->NewLongArray(size); + jlongArray jaddresses = env->NewLongArray((int)size); jlong *jInternalArray = env->GetLongArrayElements(jaddresses, NULL); for (size_t i = 0; i < size; i++) { - jInternalArray[i] = (unsigned long) (addresses->data); + jInternalArray[i] = (long) (addresses->data); addresses = bctbx_list_next(addresses); } env->ReleaseLongArrayElements(jaddresses, jInternalArray, 0); @@ -4125,10 +4125,10 @@ extern "C" jobjectArray Java_org_linphone_core_LinphoneFriendImpl_getPhoneNumber bctbx_list_t *phone_numbers = linphone_friend_get_phone_numbers((LinphoneFriend*)ptr); bctbx_list_t *list = phone_numbers; size_t size = bctbx_list_size(phone_numbers); - jobjectArray jphonenumbers = env->NewObjectArray(size, env->FindClass("java/lang/String"), env->NewStringUTF("")); + jobjectArray jphonenumbers = env->NewObjectArray((int)size, env->FindClass("java/lang/String"), env->NewStringUTF("")); for (size_t i = 0; i < size; i++) { const char *phone = (const char *)phone_numbers->data; - env->SetObjectArrayElement(jphonenumbers, i, env->NewStringUTF(phone)); + env->SetObjectArrayElement(jphonenumbers, (int)i, env->NewStringUTF(phone)); phone_numbers = bctbx_list_next(phone_numbers); } bctbx_list_free(list); @@ -4407,13 +4407,13 @@ extern "C" jobjectArray _LinphoneChatRoomImpl_getHistory(JNIEnv* env, jobject th LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc); bctbx_list_t *list = history; size_t historySize = bctbx_list_size(history); - jobjectArray jHistory = env->NewObjectArray(historySize, ljb->chatMessageClass, NULL); + jobjectArray jHistory = env->NewObjectArray((int)historySize, ljb->chatMessageClass, NULL); for (size_t i = 0; i < historySize; i++) { LinphoneChatMessage *msg = (LinphoneChatMessage *)history->data; jobject jmsg = getChatMessage(env, msg); if (jmsg != NULL) { - env->SetObjectArrayElement(jHistory, i, jmsg); + env->SetObjectArrayElement(jHistory, (int)i, jmsg); env->DeleteLocalRef(jmsg); } @@ -4524,7 +4524,7 @@ extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_createFileTransferM linphone_content_set_name(content, tmp = GetStringUTFChars(env, jname)); ReleaseStringUTFChars(env, jname, tmp); - linphone_content_set_size(content, data_size); + linphone_content_set_size(content, (size_t)data_size); message = linphone_chat_room_create_file_transfer_message((LinphoneChatRoom *)ptr, content); @@ -4582,8 +4582,8 @@ extern "C" jbyteArray Java_org_linphone_core_LinphoneChatMessageImpl_getText(JNI const char *message = linphone_chat_message_get_text((LinphoneChatMessage*)ptr); if (message){ size_t length = strlen(message); - jbyteArray array = env->NewByteArray(length); - env->SetByteArrayRegion(array, 0, length, (const jbyte*)message); + jbyteArray array = env->NewByteArray((int)length); + env->SetByteArrayRegion(array, 0, (int)length, (const jbyte*)message); return array; } return NULL; @@ -4637,13 +4637,13 @@ extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_setExternalBodyUr extern "C" jlong Java_org_linphone_core_LinphoneChatMessageImpl_getFrom(JNIEnv* env ,jobject thiz ,jlong ptr) { - return (jlong) linphone_chat_message_get_from((LinphoneChatMessage*)ptr); + return (jlong) linphone_chat_message_get_from_address((LinphoneChatMessage*)ptr); } extern "C" jlong Java_org_linphone_core_LinphoneChatMessageImpl_getTo(JNIEnv* env ,jobject thiz ,jlong ptr) { - return (jlong) linphone_chat_message_get_to((LinphoneChatMessage*)ptr); + return (jlong) linphone_chat_message_get_to_address((LinphoneChatMessage*)ptr); } extern "C" jlong Java_org_linphone_core_LinphoneChatMessageImpl_getPeerAddress(JNIEnv* env @@ -4716,7 +4716,7 @@ static void message_state_changed(LinphoneChatMessage* msg, LinphoneChatMessageS return; } - jobject listener = (jobject) msg->message_state_changed_user_data; + jobject listener = (jobject) linphone_chat_message_get_message_state_changed_cb_user_data(msg); if (listener == NULL) { ms_error("message_state_changed() notification without listener"); @@ -4734,7 +4734,7 @@ static void message_state_changed(LinphoneChatMessage* msg, LinphoneChatMessageS if (state == LinphoneChatMessageStateDisplayed) { env->DeleteGlobalRef(listener); - msg->message_state_changed_user_data = NULL; + linphone_chat_message_set_message_state_changed_cb_user_data(msg, NULL); } if (jmessage) { env->DeleteLocalRef(jmessage); @@ -4749,7 +4749,7 @@ static void file_transfer_progress_indication(LinphoneChatMessage *msg, const Li return; } - jobject listener = (jobject) msg->message_state_changed_user_data; + jobject listener = (jobject) linphone_chat_message_get_message_state_changed_cb_user_data(msg); jclass clazz = (jclass) env->GetObjectClass(listener); jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageFileTransferProgressChanged", "(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;II)V"); env->DeleteLocalRef(clazz); @@ -4772,7 +4772,7 @@ static void file_transfer_recv(LinphoneChatMessage *msg, const LinphoneContent* return; } - jobject listener = (jobject) msg->message_state_changed_user_data; + jobject listener = (jobject) linphone_chat_message_get_message_state_changed_cb_user_data(msg); jclass clazz = (jclass) env->GetObjectClass(listener); jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageFileTransferReceived", "(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;Lorg/linphone/core/LinphoneBuffer;)V"); env->DeleteLocalRef(clazz); @@ -4801,7 +4801,7 @@ static LinphoneBuffer* file_transfer_send(LinphoneChatMessage *msg, const Linph return buffer; } - jobject listener = (jobject) msg->message_state_changed_user_data; + jobject listener = (jobject) linphone_chat_message_get_message_state_changed_cb_user_data(msg); jclass clazz = (jclass) env->GetObjectClass(listener); jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageFileTransferSent","(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;IILorg/linphone/core/LinphoneBuffer;)V"); env->DeleteLocalRef(clazz); @@ -4827,7 +4827,7 @@ extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_setListener(JNIEn LinphoneChatMessage *message = (LinphoneChatMessage *)ptr; LinphoneChatMessageCbs *cbs; - message->message_state_changed_user_data = listener; + linphone_chat_message_set_message_state_changed_cb_user_data(message, listener); cbs = linphone_chat_message_get_callbacks(message); linphone_chat_message_cbs_set_msg_state_changed(cbs, message_state_changed); linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication); @@ -4853,13 +4853,13 @@ extern "C" jobjectArray Java_org_linphone_core_LinphoneCoreImpl_getChatRooms(JNI const bctbx_list_t* chats = linphone_core_get_chat_rooms(lc); LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc); size_t chatsSize = bctbx_list_size(chats); - jobjectArray jChats = env->NewObjectArray(chatsSize, ljb->chatRoomClass, NULL); + jobjectArray jChats = env->NewObjectArray((int)chatsSize, ljb->chatRoomClass, NULL); for (size_t i = 0; i < chatsSize; i++) { LinphoneChatRoom *room = (LinphoneChatRoom *)chats->data; jobject jroom = getChatRoom(env, room); if (jroom != NULL) { - env->SetObjectArrayElement(jChats, i, jroom); + env->SetObjectArrayElement(jChats, (int)i, jroom); env->DeleteLocalRef(jroom); } chats = chats->next; @@ -5068,7 +5068,7 @@ extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_setPrivacy(JNIEnv* ,jobject thiz ,jlong cp ,jint privacy) { - linphone_call_params_set_privacy((LinphoneCallParams*)cp,privacy); + linphone_call_params_set_privacy((LinphoneCallParams*)cp,(unsigned int)privacy); } extern "C" jstring Java_org_linphone_core_LinphoneCallParamsImpl_getSessionName(JNIEnv* env @@ -5357,11 +5357,11 @@ extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_getExpires(JNIEnv } extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setPrivacy(JNIEnv* env,jobject thiz,jlong ptr,jint privacy) { - linphone_proxy_config_set_privacy((LinphoneProxyConfig *) ptr, (int) privacy); + linphone_proxy_config_set_privacy((LinphoneProxyConfig *) ptr, (unsigned int) privacy); } extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_getPrivacy(JNIEnv* env,jobject thiz,jlong ptr) { - return linphone_proxy_config_get_privacy((LinphoneProxyConfig *) ptr); + return (int) linphone_proxy_config_get_privacy((LinphoneProxyConfig *) ptr); } JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_enableAvpf(JNIEnv *env, jobject thiz, jlong ptr, jboolean enable) { @@ -5725,12 +5725,12 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_soundResourcesLocked // Needed by Galaxy S (can't switch to/from speaker while playing and still keep mic working) // Implemented directly in msandroid.cpp (sound filters for Android). extern "C" void Java_org_linphone_core_LinphoneCoreImpl_forceSpeakerState(JNIEnv *env, jobject thiz, jlong ptr, jboolean speakerOn) { - LinphoneCore *lc = (LinphoneCore *)ptr; + /*LinphoneCore *lc = (LinphoneCore *)ptr; LinphoneCall *call = linphone_core_get_current_call(lc); if (call && call->audiostream && call->audiostream->soundread) { bool_t on = speakerOn; ms_filter_call_method(call->audiostream->soundread, MS_AUDIO_CAPTURE_FORCE_SPEAKER_STATE, &on); - } + }*/ } // End Galaxy S hack functions @@ -5781,7 +5781,7 @@ extern "C" jobjectArray Java_org_linphone_core_LinphoneCoreImpl_tunnelGetServers const bctbx_list_t *it; int i; - tunnelConfigArray = env->NewObjectArray(bctbx_list_size(servers), tunnelConfigClass, NULL); + tunnelConfigArray = env->NewObjectArray((int)bctbx_list_size(servers), tunnelConfigClass, NULL); for(it = servers, i=0; it != NULL; it = it->next, i++) { LinphoneTunnelConfig *conf = (LinphoneTunnelConfig *)it->data; jobject elt = getTunnelConfig(env, conf); @@ -5907,7 +5907,7 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setStaticPicture(JNIEnv extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setCpuCountNative(JNIEnv *env, jobject thiz, jlong coreptr, jint count) { MSFactory *factory = linphone_core_get_ms_factory((LinphoneCore*)coreptr); - ms_factory_set_cpu_count(factory, count); + ms_factory_set_cpu_count(factory, (unsigned int)count); } extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setAudioJittcomp(JNIEnv *env, jobject thiz, jlong lc, jint value) { @@ -6059,7 +6059,7 @@ static LinphoneContent *create_content_from_java_args(JNIEnv *env, LinphoneCore ReleaseStringUTFChars(env, jencoding, tmp); } - linphone_content_set_buffer(content, data, env->GetArrayLength(jdata)); + linphone_content_set_buffer(content, data, (size_t)env->GetArrayLength(jdata)); env->ReleaseByteArrayElements(jdata,(jbyte*)data,JNI_ABORT); } return content; @@ -6273,8 +6273,8 @@ static jobject create_java_linphone_content(JNIEnv *env, const LinphoneContent * data = (!linphone_content_is_multipart(icontent) ? linphone_content_get_buffer(icontent) : NULL); if (data){ - jdata = env->NewByteArray(linphone_content_get_size(icontent)); - env->SetByteArrayRegion(jdata, 0, linphone_content_get_size(icontent), (jbyte*)data); + jdata = env->NewByteArray((int)linphone_content_get_size(icontent)); + env->SetByteArrayRegion(jdata, 0, (int)linphone_content_get_size(icontent), (jbyte*)data); } jobject jobj = env->NewObject(contentClass, ctor, jname, jtype, jsubtype, jdata, jencoding, jsize); @@ -6303,8 +6303,8 @@ static jobject create_java_linphone_buffer(JNIEnv *env, const LinphoneBuffer *bu jsize = buffer ? (jint) buffer->size : 0; if (buffer && buffer->content) { - jdata = env->NewByteArray(buffer->size); - env->SetByteArrayRegion(jdata, 0, buffer->size, (jbyte*)buffer->content); + jdata = env->NewByteArray((int)buffer->size); + env->SetByteArrayRegion(jdata, 0, (int)buffer->size, (jbyte*)buffer->content); } jobject jobj = env->NewObject(bufferClass, ctor, jdata, jsize); @@ -7788,7 +7788,7 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCallParamsImpl_realTimeTextEn } extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_putChar(JNIEnv* env ,jobject thiz, jlong ptr, jlong character) { - linphone_chat_message_put_char((LinphoneChatMessage *)ptr, character); + linphone_chat_message_put_char((LinphoneChatMessage *)ptr, (unsigned int)character); } extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_finalize(JNIEnv* env, jobject thiz, jlong ptr) { @@ -8140,11 +8140,11 @@ extern "C" jobjectArray Java_org_linphone_core_LinphoneConferenceImpl_getPartici int i; participants = linphone_conference_get_participants((LinphoneConference *)pconference); - jaddr_list = env->NewObjectArray(bctbx_list_size(participants), addr_class, NULL); + jaddr_list = env->NewObjectArray((int)bctbx_list_size(participants), addr_class, NULL); for(it=participants, i=0; it; it=bctbx_list_next(it), i++) { LinphoneAddress *addr = (LinphoneAddress *)it->data; jobject jaddr = env->NewObject(addr_class, addr_constructor, (jlong)addr); - env->SetObjectArrayElement(jaddr_list, i, jaddr); + env->SetObjectArrayElement(jaddr_list, (int)i, jaddr); } bctbx_list_free(participants); return jaddr_list; From 978f20f8cf636166c15435ec58a9a6fc9170857f Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 11 Oct 2017 18:01:36 +0200 Subject: [PATCH 0441/2215] feat(Chat): better architecture --- coreapi/callbacks.c | 2 +- coreapi/chat.c | 6 ++-- coreapi/chat_file_transfer.c | 2 +- coreapi/message_storage.c | 2 +- src/CMakeLists.txt | 30 +++++++++---------- src/c-wrapper/api/c-chat-message.cpp | 8 ++--- src/c-wrapper/api/c-chat-room.cpp | 6 ++-- src/c-wrapper/api/c-event-log.cpp | 2 +- src/chat/{ => chat-message}/chat-message-p.h | 12 ++++---- src/chat/{ => chat-message}/chat-message.cpp | 12 ++++---- src/chat/{ => chat-message}/chat-message.h | 0 src/chat/{ => chat-room}/basic-chat-room-p.h | 2 +- src/chat/{ => chat-room}/basic-chat-room.cpp | 0 src/chat/{ => chat-room}/basic-chat-room.h | 2 +- src/chat/{ => chat-room}/chat-room-p.h | 4 +-- src/chat/{ => chat-room}/chat-room.cpp | 6 ++-- src/chat/{ => chat-room}/chat-room.h | 2 +- .../client-group-chat-room-p.h | 2 +- .../client-group-chat-room.cpp | 0 .../{ => chat-room}/client-group-chat-room.h | 2 +- .../real-time-text-chat-room-p.h | 4 +-- .../real-time-text-chat-room.cpp | 2 +- .../real-time-text-chat-room.h | 2 +- src/chat/imdn.cpp | 6 ++-- src/chat/is-composing.cpp | 4 +-- src/chat/is-composing.h | 2 +- .../modifier/cpim-chat-message-modifier.cpp | 2 +- .../encryption-chat-message-modifier.cpp | 4 +-- .../multipart-chat-message-modifier.cpp | 4 +-- src/db/events-db.cpp | 2 +- tester/cpim-tester.cpp | 4 +-- tester/multipart-tester.cpp | 4 +-- 32 files changed, 71 insertions(+), 71 deletions(-) rename src/chat/{ => chat-message}/chat-message-p.h (96%) rename src/chat/{ => chat-message}/chat-message.cpp (99%) rename src/chat/{ => chat-message}/chat-message.h (100%) rename src/chat/{ => chat-room}/basic-chat-room-p.h (97%) rename src/chat/{ => chat-room}/basic-chat-room.cpp (100%) rename src/chat/{ => chat-room}/basic-chat-room.h (98%) rename src/chat/{ => chat-room}/chat-room-p.h (98%) rename src/chat/{ => chat-room}/chat-room.cpp (99%) rename src/chat/{ => chat-room}/chat-room.h (98%) rename src/chat/{ => chat-room}/client-group-chat-room-p.h (97%) rename src/chat/{ => chat-room}/client-group-chat-room.cpp (100%) rename src/chat/{ => chat-room}/client-group-chat-room.h (98%) rename src/chat/{ => chat-room}/real-time-text-chat-room-p.h (94%) rename src/chat/{ => chat-room}/real-time-text-chat-room.cpp (99%) rename src/chat/{ => chat-room}/real-time-text-chat-room.h (98%) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 78b2c35cc..e21544b49 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -39,7 +39,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" #include "call/call-p.h" -#include "chat/chat-room.h" +#include "chat/chat-room/chat-room.h" #include "conference/session/call-session.h" #include "conference/session/call-session-p.h" #include "conference/session/media-session.h" diff --git a/coreapi/chat.c b/coreapi/chat.c index d90e76dbf..90d51b3e0 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -36,10 +36,10 @@ #include "linphone/wrapper_utils.h" #include "c-wrapper/c-wrapper.h" -#include "chat/basic-chat-room.h" -#include "chat/client-group-chat-room.h" +#include "chat/chat-room/basic-chat-room.h" +#include "chat/chat-room/client-group-chat-room.h" #include "chat/real-time-text-chat-room.h" -#include "chat/real-time-text-chat-room-p.h" +#include "chat/chat-room/real-time-text-chat-room-p.h" #include "content/content-type.h" using namespace std; diff --git a/coreapi/chat_file_transfer.c b/coreapi/chat_file_transfer.c index 7eab33106..d3ded3de2 100644 --- a/coreapi/chat_file_transfer.c +++ b/coreapi/chat_file_transfer.c @@ -26,7 +26,7 @@ #include "private.h" #include "c-wrapper/c-wrapper.h" -#include "chat/chat-room.h" +#include "chat/chat-room/chat-room.h" LinphoneChatMessage *linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent *initial_content) { return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createFileTransferMessage(initial_content)); diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index ee3b9b2f8..803ab530b 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifdef SQLITE_STORAGE_ENABLED -#include "chat/chat-room.h" +#include "chat/chat-room/chat-room.h" #ifndef _WIN32 #if !defined(__QNXNTO__) && !defined(__ANDROID__) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 701a1339c..6a596c879 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,14 +29,16 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES call/call-listener.h call/call-p.h call/call.h - chat/basic-chat-room-p.h - chat/basic-chat-room.h - chat/chat-message-p.h - chat/chat-message.h - chat/chat-room-p.h - chat/chat-room.h - chat/client-group-chat-room-p.h - chat/client-group-chat-room.h + chat/chat-message/chat-message-p.h + chat/chat-message/chat-message.h + chat/chat-room/basic-chat-room-p.h + chat/chat-room/basic-chat-room.h + chat/chat-room/chat-room-p.h + chat/chat-room/chat-room.h + chat/chat-room/client-group-chat-room-p.h + chat/chat-room/client-group-chat-room.h + chat/chat-room/real-time-text-chat-room-p.h + chat/chat-room/real-time-text-chat-room.h chat/cpim/cpim.h chat/cpim/header/cpim-core-headers.h chat/cpim/header/cpim-generic-header.h @@ -51,8 +53,6 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES chat/modifier/cpim-chat-message-modifier.h chat/modifier/encryption-chat-message-modifier.h chat/modifier/multipart-chat-message-modifier.h - chat/real-time-text-chat-room-p.h - chat/real-time-text-chat-room.h conference/conference-listener.h conference/conference.h conference/local-conference-event-handler-p.h @@ -124,10 +124,11 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES c-wrapper/api/c-participant.cpp c-wrapper/internal/c-sal.cpp call/call.cpp - chat/basic-chat-room.cpp - chat/chat-message.cpp - chat/chat-room.cpp - chat/client-group-chat-room.cpp + chat/chat-message/chat-message.cpp + chat/chat-room/basic-chat-room.cpp + chat/chat-room/chat-room.cpp + chat/chat-room/client-group-chat-room.cpp + chat/chat-room/real-time-text-chat-room.cpp chat/cpim/header/cpim-core-headers.cpp chat/cpim/header/cpim-generic-header.cpp chat/cpim/header/cpim-header.cpp @@ -139,7 +140,6 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES chat/modifier/cpim-chat-message-modifier.cpp chat/modifier/encryption-chat-message-modifier.cpp chat/modifier/multipart-chat-message-modifier.cpp - chat/real-time-text-chat-room.cpp conference/conference.cpp conference/local-conference-event-handler.cpp conference/local-conference.cpp diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 7e28a33ef..0aed719e6 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -27,10 +27,10 @@ #include "address/address.h" #include "content/content.h" #include "content/content-type.h" -#include "chat/chat-message-p.h" -#include "chat/chat-message.h" -#include "chat/chat-room-p.h" -#include "chat/real-time-text-chat-room-p.h" +#include "chat/chat-message/chat-message-p.h" +#include "chat/chat-message/chat-message.h" +#include "chat/chat-room/chat-room-p.h" +#include "chat/chat-room/real-time-text-chat-room-p.h" // ============================================================================= diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index f447e0fd2..89e668ee5 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -24,9 +24,9 @@ #include "linphone/api/c-chat-room.h" #include "c-wrapper/c-wrapper.h" -#include "chat/basic-chat-room.h" -#include "chat/client-group-chat-room.h" -#include "chat/real-time-text-chat-room-p.h" +#include "chat/chat-room/basic-chat-room.h" +#include "chat/chat-room/client-group-chat-room.h" +#include "chat/chat-room/real-time-text-chat-room-p.h" #include "conference/participant.h" // ============================================================================= diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index dbcde10a8..4737af3f5 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -22,7 +22,7 @@ #include "c-wrapper/c-wrapper.h" #include "call/call.h" -#include "chat/chat-message.h" +#include "chat/chat-message/chat-message.h" #include "event-log/call-event.h" #include "event-log/chat-message-event.h" #include "event-log/conference-participant-event.h" diff --git a/src/chat/chat-message-p.h b/src/chat/chat-message/chat-message-p.h similarity index 96% rename from src/chat/chat-message-p.h rename to src/chat/chat-message/chat-message-p.h index 2d269865b..57355430f 100644 --- a/src/chat/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -120,11 +120,11 @@ private: Address from; Address to; time_t time = 0; - std::string id = ""; - std::string appData = ""; - std::string fileTransferFilePath = ""; - std::string externalBodyUrl = ""; - std::string rttMessage = ""; + std::string id; + std::string appData; + std::string fileTransferFilePath; + std::string externalBodyUrl; + std::string rttMessage; bool isSecured = false; bool isReadOnly = false; std::list contents; @@ -140,7 +140,7 @@ private: unsigned char currentSendStep = Step::None; // Cache for returned values, used for compatibility with previous C API ContentType cContentType; - std::string cText = ""; + std::string cText; // Used for compatibility with previous C API LinphoneContent *cFileTransferInformation = NULL; diff --git a/src/chat/chat-message.cpp b/src/chat/chat-message/chat-message.cpp similarity index 99% rename from src/chat/chat-message.cpp rename to src/chat/chat-message/chat-message.cpp index 74ca2b62f..3defac18f 100644 --- a/src/chat/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -25,14 +25,14 @@ #include "c-wrapper/c-wrapper.h" #include "address/address.h" -#include "chat-message-p.h" +#include "chat/chat-message/chat-message-p.h" #include "content/content.h" -#include "chat-room-p.h" -#include "real-time-text-chat-room.h" -#include "modifier/cpim-chat-message-modifier.h" -#include "modifier/encryption-chat-message-modifier.h" -#include "modifier/multipart-chat-message-modifier.h" +#include "chat/chat-room/chat-room-p.h" +#include "chat/chat-room/real-time-text-chat-room.h" +#include "chat/modifier/cpim-chat-message-modifier.h" +#include "chat/modifier/encryption-chat-message-modifier.h" +#include "chat/modifier/multipart-chat-message-modifier.h" #include "logger/logger.h" #include "ortp/b64.h" diff --git a/src/chat/chat-message.h b/src/chat/chat-message/chat-message.h similarity index 100% rename from src/chat/chat-message.h rename to src/chat/chat-message/chat-message.h diff --git a/src/chat/basic-chat-room-p.h b/src/chat/chat-room/basic-chat-room-p.h similarity index 97% rename from src/chat/basic-chat-room-p.h rename to src/chat/chat-room/basic-chat-room-p.h index 0d7a736cb..698996b18 100644 --- a/src/chat/basic-chat-room-p.h +++ b/src/chat/chat-room/basic-chat-room-p.h @@ -24,7 +24,7 @@ #include "private.h" #include "basic-chat-room.h" -#include "chat/chat-room-p.h" +#include "chat/chat-room/chat-room-p.h" // ============================================================================= diff --git a/src/chat/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp similarity index 100% rename from src/chat/basic-chat-room.cpp rename to src/chat/chat-room/basic-chat-room.cpp diff --git a/src/chat/basic-chat-room.h b/src/chat/chat-room/basic-chat-room.h similarity index 98% rename from src/chat/basic-chat-room.h rename to src/chat/chat-room/basic-chat-room.h index 73b7ed78a..11f6eed79 100644 --- a/src/chat/basic-chat-room.h +++ b/src/chat/chat-room/basic-chat-room.h @@ -20,7 +20,7 @@ #ifndef _BASIC_CHAT_ROOM_H_ #define _BASIC_CHAT_ROOM_H_ -#include "chat/chat-room.h" +#include "chat/chat-room/chat-room.h" // ============================================================================= diff --git a/src/chat/chat-room-p.h b/src/chat/chat-room/chat-room-p.h similarity index 98% rename from src/chat/chat-room-p.h rename to src/chat/chat-room/chat-room-p.h index fe8710a6a..e07889fe3 100644 --- a/src/chat/chat-room-p.h +++ b/src/chat/chat-room/chat-room-p.h @@ -27,8 +27,8 @@ #include "private.h" #include "chat-room.h" -#include "is-composing-listener.h" -#include "is-composing.h" +#include "chat/is-composing-listener.h" +#include "chat/is-composing.h" #include "object/object-p.h" // ============================================================================= diff --git a/src/chat/chat-room.cpp b/src/chat/chat-room/chat-room.cpp similarity index 99% rename from src/chat/chat-room.cpp rename to src/chat/chat-room/chat-room.cpp index d044fb4fd..2e759970d 100644 --- a/src/chat/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -23,10 +23,10 @@ #include "linphone/utils/utils.h" #include "c-wrapper/c-wrapper.h" -#include "chat-room-p.h" -#include "imdn.h" +#include "chat/chat-room/chat-room-p.h" +#include "chat/imdn.h" #include "content/content.h" -#include "chat-message-p.h" +#include "chat/chat-message/chat-message-p.h" #include "chat-room.h" #include "sal/message-op.h" #include "logger/logger.h" diff --git a/src/chat/chat-room.h b/src/chat/chat-room/chat-room.h similarity index 98% rename from src/chat/chat-room.h rename to src/chat/chat-room/chat-room.h index 50b087edb..2e4b6beac 100644 --- a/src/chat/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -29,7 +29,7 @@ #include "object/object.h" #include "conference/conference-interface.h" -#include "chat-message.h" +#include "chat/chat-message/chat-message.h" #include "linphone/types.h" diff --git a/src/chat/client-group-chat-room-p.h b/src/chat/chat-room/client-group-chat-room-p.h similarity index 97% rename from src/chat/client-group-chat-room-p.h rename to src/chat/chat-room/client-group-chat-room-p.h index 54e8f9b60..4b8885e85 100644 --- a/src/chat/client-group-chat-room-p.h +++ b/src/chat/chat-room/client-group-chat-room-p.h @@ -24,7 +24,7 @@ #include "private.h" #include "client-group-chat-room.h" -#include "chat/chat-room-p.h" +#include "chat/chat-room/chat-room-p.h" // ============================================================================= diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp similarity index 100% rename from src/chat/client-group-chat-room.cpp rename to src/chat/chat-room/client-group-chat-room.cpp diff --git a/src/chat/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h similarity index 98% rename from src/chat/client-group-chat-room.h rename to src/chat/chat-room/client-group-chat-room.h index 200effef1..77121c01d 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -23,7 +23,7 @@ // From coreapi #include "private.h" -#include "chat/chat-room.h" +#include "chat/chat-room/chat-room.h" #include "conference/remote-conference.h" #include "conference/session/call-session.h" diff --git a/src/chat/real-time-text-chat-room-p.h b/src/chat/chat-room/real-time-text-chat-room-p.h similarity index 94% rename from src/chat/real-time-text-chat-room-p.h rename to src/chat/chat-room/real-time-text-chat-room-p.h index 8c02770a2..f70a16f2d 100644 --- a/src/chat/real-time-text-chat-room-p.h +++ b/src/chat/chat-room/real-time-text-chat-room-p.h @@ -23,8 +23,8 @@ // From coreapi. #include "private.h" -#include "real-time-text-chat-room.h" -#include "chat/chat-room-p.h" +#include "chat/chat-room/real-time-text-chat-room.h" +#include "chat/chat-room/chat-room-p.h" // ============================================================================= diff --git a/src/chat/real-time-text-chat-room.cpp b/src/chat/chat-room/real-time-text-chat-room.cpp similarity index 99% rename from src/chat/real-time-text-chat-room.cpp rename to src/chat/chat-room/real-time-text-chat-room.cpp index d62eb31de..08da5812e 100644 --- a/src/chat/real-time-text-chat-room.cpp +++ b/src/chat/chat-room/real-time-text-chat-room.cpp @@ -22,7 +22,7 @@ #include "linphone/utils/utils.h" #include "real-time-text-chat-room-p.h" -#include "chat-message-p.h" +#include "chat/chat-message/chat-message-p.h" #include "c-wrapper/c-wrapper.h" #include "logger/logger.h" diff --git a/src/chat/real-time-text-chat-room.h b/src/chat/chat-room/real-time-text-chat-room.h similarity index 98% rename from src/chat/real-time-text-chat-room.h rename to src/chat/chat-room/real-time-text-chat-room.h index 52c0993ef..dcc06c7d7 100644 --- a/src/chat/real-time-text-chat-room.h +++ b/src/chat/chat-room/real-time-text-chat-room.h @@ -23,7 +23,7 @@ // From coreapi #include "private.h" -#include "chat/chat-room.h" +#include "chat/chat-room/chat-room.h" #include "linphone/types.h" diff --git a/src/chat/imdn.cpp b/src/chat/imdn.cpp index 28ec399a2..66900cb4c 100644 --- a/src/chat/imdn.cpp +++ b/src/chat/imdn.cpp @@ -19,9 +19,9 @@ #include "logger/logger.h" -#include "imdn.h" -#include "chat/chat-room.h" -#include "chat/chat-message.h" +#include "chat/imdn.h" +#include "chat/chat-room/chat-room.h" +#include "chat/chat-message/chat-message.h" // ============================================================================= diff --git a/src/chat/is-composing.cpp b/src/chat/is-composing.cpp index 9de87f525..93261385b 100644 --- a/src/chat/is-composing.cpp +++ b/src/chat/is-composing.cpp @@ -19,10 +19,10 @@ #include "linphone/utils/utils.h" -#include "chat-room-p.h" +#include "chat/chat-room/chat-room-p.h" #include "logger/logger.h" -#include "is-composing.h" +#include "chat/is-composing.h" // ============================================================================= diff --git a/src/chat/is-composing.h b/src/chat/is-composing.h index 15a2d4e9c..35d281fa3 100644 --- a/src/chat/is-composing.h +++ b/src/chat/is-composing.h @@ -22,7 +22,7 @@ #include "linphone/utils/general.h" -#include "is-composing-listener.h" +#include "chat/is-composing-listener.h" #include "private.h" diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index 5f224a950..af0b0568d 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -18,7 +18,7 @@ */ #include "address/address.h" -#include "chat/chat-message.h" +#include "chat/chat-message/chat-message.h" #include "chat/cpim/cpim.h" #include "content/content-type.h" #include "content/content.h" diff --git a/src/chat/modifier/encryption-chat-message-modifier.cpp b/src/chat/modifier/encryption-chat-message-modifier.cpp index cfda245d2..e6887b35d 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.cpp +++ b/src/chat/modifier/encryption-chat-message-modifier.cpp @@ -19,8 +19,8 @@ #include "address/address.h" #include "c-wrapper/c-wrapper.h" -#include "chat/chat-message.h" -#include "chat/chat-room.h" +#include "chat/chat-message/chat-message.h" +#include "chat/chat-room/chat-room.h" #include "content/content-type.h" #include "content/content.h" diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index 89b7c008f..e9c2cd2c3 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -18,8 +18,8 @@ */ #include "address/address.h" -#include "chat/chat-message.h" -#include "chat/chat-room.h" +#include "chat/chat-message/chat-message.h" +#include "chat/chat-room/chat-room.h" #include "content/content-type.h" #include "logger/logger.h" diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index f1f7b8844..c385aca21 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -27,7 +27,7 @@ #include "linphone/utils/utils.h" #include "abstract/abstract-db-p.h" -#include "chat/chat-message.h" +#include "chat/chat-message/chat-message.h" #include "conference/participant.h" #include "content/content-type.h" #include "content/content.h" diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index fe86d493e..26e9a5a4d 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -17,8 +17,8 @@ */ #include "address/address.h" -#include "chat/basic-chat-room.h" -#include "chat/chat-message.h" +#include "chat/chat-room/basic-chat-room.h" +#include "chat/chat-message/chat-message.h" #include "chat/cpim/cpim.h" #include "content/content-type.h" diff --git a/tester/multipart-tester.cpp b/tester/multipart-tester.cpp index ba0917de8..b40687c25 100644 --- a/tester/multipart-tester.cpp +++ b/tester/multipart-tester.cpp @@ -17,8 +17,8 @@ */ #include "address/address.h" -#include "chat/basic-chat-room.h" -#include "chat/chat-message.h" +#include "chat/chat-room/basic-chat-room.h" +#include "chat/chat-message/chat-message.h" #include "content/content-type.h" #include "liblinphone_tester.h" From 6c67cb237d9ed149a21081732df38c493e98c228 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 11 Oct 2017 18:05:34 +0200 Subject: [PATCH 0442/2215] feat(Chat): fix build --- coreapi/chat.c | 2 +- coreapi/linphonecore.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 90d51b3e0..b2fa26f1f 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -38,7 +38,7 @@ #include "c-wrapper/c-wrapper.h" #include "chat/chat-room/basic-chat-room.h" #include "chat/chat-room/client-group-chat-room.h" -#include "chat/real-time-text-chat-room.h" +#include "chat/chat-room/real-time-text-chat-room.h" #include "chat/chat-room/real-time-text-chat-room-p.h" #include "content/content-type.h" diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index bab227b5b..3ce577415 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -45,7 +45,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mediastreamer2/msjpegwriter.h" #include "mediastreamer2/msogl.h" #include "mediastreamer2/msvolume.h" -#include "chat/client-group-chat-room-p.h" +#include "chat/chat-room/client-group-chat-room-p.h" #include "conference/remote-conference-event-handler.h" // For migration purpose. From e7ed894fc958fa7406c864cbd34ed8b6a5b07f53 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 12 Oct 2017 09:30:40 +0200 Subject: [PATCH 0443/2215] Updated list of mustache files in CMakeLists --- wrappers/java/CMakeLists.txt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/wrappers/java/CMakeLists.txt b/wrappers/java/CMakeLists.txt index 66b01ea38..18712607a 100644 --- a/wrappers/java/CMakeLists.txt +++ b/wrappers/java/CMakeLists.txt @@ -26,13 +26,17 @@ add_custom_command(OUTPUT linphone_jni.cc ${PROJECT_SOURCE_DIR}/tools/metadoc.py ${PROJECT_SOURCE_DIR}/tools/abstractapi.py genwrapper.py - wrapper_impl.mustache + java_class.mustache + java_enum.mustache + java_interface_stub.mustache + java_interface.mustache + jni.mustache linphone-doc "${PROJECT_BINARY_DIR}/coreapi/help/doc/doxygen/xml/index.xml" ) add_custom_target(linphonej ALL DEPENDS linphone_jni.cc) -#install(FILES ${CMAKE_CURRENT_BINARY_DIR}/linphone_jni.cc -# DESTINATION ${CMAKE_INSTALL_DATADIR}/linphonej -#) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/linphone_jni.cc + DESTINATION ${CMAKE_INSTALL_DATADIR}/linphonej +) From 714a472e775b2e7d65e95051cd1862bde6791211 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 12 Oct 2017 10:20:29 +0200 Subject: [PATCH 0444/2215] Fixed compilation of JNI layer of Java wrapper --- CMakeLists.txt | 6 +++--- coreapi/CMakeLists.txt | 6 ++---- wrappers/java/CMakeLists.txt | 13 ++++++------- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a16203a69..c7d648143 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -335,6 +335,9 @@ endif() add_subdirectory(include) add_subdirectory(java) +if(ENABLE_JAVA_WRAPPER) + add_subdirectory(wrappers/java) +endif() add_subdirectory(src) add_subdirectory(coreapi) add_subdirectory(share) @@ -356,9 +359,6 @@ endif() if(ENABLE_CSHARP_WRAPPER) add_subdirectory(wrappers/csharp) endif() -if(ENABLE_JAVA_WRAPPER) - add_subdirectory(wrappers/java) -endif() include(CMakePackageConfigHelpers) write_basic_package_version_file( diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 4397e036a..d4faf04cc 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -112,9 +112,8 @@ set(LINPHONE_SOURCE_FILES_CXX tester_utils.cpp ) set(LINPHONE_INCLUDE_DIRS ${LINPHONE_INCLUDE_DIRS}) -if(ANDROID) - list(APPEND LINPHONE_SOURCE_FILES_CXX linphonecore_jni.cc) - set_source_files_properties(linphonecore_jni.cc PROPERTIES COMPILE_DEFINITIONS "USE_JAVAH") +if(ENABLE_JAVA_WRAPPER) + list(APPEND LINPHONE_SOURCE_FILES_CXX ${LINPHONE_JNI_SOURCES}) endif() set(LINPHONE_SOURCE_FILES_OBJC) @@ -255,7 +254,6 @@ if(ENABLE_SHARED) set_target_properties(linphone PROPERTIES PREFIX "lib") elseif(ANDROID) target_link_libraries(linphone PUBLIC "log" ${SUPPORT_LIBRARIES} ${CPUFEATURES_LIBRARIES}) - add_dependencies(linphone linphonecore-jni-header) endif() if(MSVC) if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") diff --git a/wrappers/java/CMakeLists.txt b/wrappers/java/CMakeLists.txt index 18712607a..78c6a1e1a 100644 --- a/wrappers/java/CMakeLists.txt +++ b/wrappers/java/CMakeLists.txt @@ -20,9 +20,9 @@ # ############################################################################ -add_custom_command(OUTPUT linphone_jni.cc - COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/genwrapper.py" "${PROJECT_BINARY_DIR}/coreapi/help/doc/doxygen/xml" - DEPENDS ${PROJECT_SOURCE_DIR}/tools/genapixml.py +add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/src/linphone_jni.cc" + COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/genwrapper.py" "${PROJECT_BINARY_DIR}/coreapi/help/doc/doxygen/xml" "-o" "${CMAKE_CURRENT_BINARY_DIR}" + DEPENDS ${PROJECT_SOURCE_DIR}/tools/genapixml.py ${LINPHONE_HEADER_FILES} ${PROJECT_SOURCE_DIR}/tools/metadoc.py ${PROJECT_SOURCE_DIR}/tools/abstractapi.py genwrapper.py @@ -33,10 +33,9 @@ add_custom_command(OUTPUT linphone_jni.cc jni.mustache linphone-doc "${PROJECT_BINARY_DIR}/coreapi/help/doc/doxygen/xml/index.xml" + COMMENT "Generating java wrapper" ) -add_custom_target(linphonej ALL DEPENDS linphone_jni.cc) +add_custom_target(linphonej ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/src/linphone_jni.cc") -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/linphone_jni.cc - DESTINATION ${CMAKE_INSTALL_DATADIR}/linphonej -) +set(LINPHONE_JNI_SOURCES "${CMAKE_CURRENT_BINARY_DIR}/src/linphone_jni.cc" PARENT_SCOPE) \ No newline at end of file From 783e9326d2770e0bb53f63b8dbd53e3b3d94561d Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 12 Oct 2017 10:21:56 +0200 Subject: [PATCH 0445/2215] mark const method as const --- src/conference/remote-conference-event-handler.cpp | 2 +- src/conference/remote-conference-event-handler.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 163f9961a..6f23d31f8 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -118,7 +118,7 @@ void RemoteConferenceEventHandler::notifyReceived (string xmlBody) { // ----------------------------------------------------------------------------- -const Address &RemoteConferenceEventHandler::getConfAddress () { +const Address &RemoteConferenceEventHandler::getConfAddress () const { L_D(); return d->confAddress; } diff --git a/src/conference/remote-conference-event-handler.h b/src/conference/remote-conference-event-handler.h index 7d25bd359..810feb49d 100644 --- a/src/conference/remote-conference-event-handler.h +++ b/src/conference/remote-conference-event-handler.h @@ -40,7 +40,7 @@ class RemoteConferenceEventHandler : public Object { void notifyReceived (std::string xmlBody); void unsubscribe (); - const Address &getConfAddress (); + const Address &getConfAddress () const; private: L_DECLARE_PRIVATE(RemoteConferenceEventHandler); From ff02fcd2744bf8f64ba3ced8981d14950a66f1eb Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 12 Oct 2017 10:34:20 +0200 Subject: [PATCH 0446/2215] mark const method as const --- src/conference/remote-conference.cpp | 2 +- src/conference/remote-conference.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index aca20de9f..ef6e4dd0f 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -61,7 +61,7 @@ void RemoteConference::removeParticipant (const shared_ptr &p } -string RemoteConference::getResourceLists (const list
    &addresses) { +string RemoteConference::getResourceLists (const list
    &addresses) const { ResourceLists rl = ResourceLists(); ListType l = ListType(); for (const auto &addr : addresses) { diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index ea97a397f..572873136 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -40,7 +40,7 @@ public: void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void removeParticipant (const std::shared_ptr &participant) override; - std::string getResourceLists (const std::list
    &addresses); + std::string getResourceLists (const std::list
    &addresses) const; protected: /* ConferenceListener */ From 531e3d1b8cd4ef2d156c29ec8f591f573b045ea7 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 12 Oct 2017 10:54:15 +0200 Subject: [PATCH 0447/2215] feat(ChatRoom): add a capabilities getter --- include/linphone/enums/chat-room-enums.h | 5 +++++ src/chat/chat-room/basic-chat-room.cpp | 4 ++++ src/chat/chat-room/basic-chat-room.h | 2 ++ src/chat/chat-room/chat-room.h | 6 +++++- src/chat/chat-room/client-group-chat-room.cpp | 4 +++- src/chat/chat-room/client-group-chat-room.h | 3 ++- .../chat-room/real-time-text-chat-room.cpp | 4 +++- src/chat/chat-room/real-time-text-chat-room.h | 2 ++ src/db/events-db.cpp | 21 +++++++++++++------ 9 files changed, 41 insertions(+), 10 deletions(-) diff --git a/include/linphone/enums/chat-room-enums.h b/include/linphone/enums/chat-room-enums.h index 8a4318aa8..11e1f8fa9 100644 --- a/include/linphone/enums/chat-room-enums.h +++ b/include/linphone/enums/chat-room-enums.h @@ -31,4 +31,9 @@ F(Terminated) \ F(CreationFailed) +#define L_ENUM_VALUES_CHAT_ROOM_CAPABILITIES(F) \ + F(Basic, 1 << 0) \ + F(RealTimeText, 1 << 1) \ + F(Conference, 1 << 2) + #endif // ifndef _CHAT_ROOM_ENUMS_H_ diff --git a/src/chat/chat-room/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp index ae59ffd01..2814a253d 100644 --- a/src/chat/chat-room/basic-chat-room.cpp +++ b/src/chat/chat-room/basic-chat-room.cpp @@ -36,6 +36,10 @@ BasicChatRoom::BasicChatRoom (LinphoneCore *core, const Address &peerAddress) : // ----------------------------------------------------------------------------- +int BasicChatRoom::getCapabilities () const { + return static_cast(Capabilities::Basic); +} + void BasicChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { lError() << "addParticipant() is not allowed on a BasicChatRoom"; } diff --git a/src/chat/chat-room/basic-chat-room.h b/src/chat/chat-room/basic-chat-room.h index 11f6eed79..d6b64d9a6 100644 --- a/src/chat/chat-room/basic-chat-room.h +++ b/src/chat/chat-room/basic-chat-room.h @@ -33,6 +33,8 @@ public: BasicChatRoom (LinphoneCore *core, const Address &peerAddress); virtual ~BasicChatRoom () = default; + int getCapabilities () const override; + /* ConferenceInterface. */ void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index 2e4b6beac..84c48911d 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -44,12 +44,16 @@ class LINPHONE_PUBLIC ChatRoom : public Object, public ConferenceInterface { friend class ChatMessagePrivate; public: - L_DECLARE_ENUM(State, L_ENUM_VALUES_CHAT_ROOM_STATE); L_OVERRIDE_SHARED_FROM_THIS(ChatRoom); + L_DECLARE_ENUM(Capabilities, L_ENUM_VALUES_CHAT_ROOM_CAPABILITIES); + L_DECLARE_ENUM(State, L_ENUM_VALUES_CHAT_ROOM_STATE); + ChatRoom (LinphoneCore *core); virtual ~ChatRoom () = default; + virtual int getCapabilities () const = 0; + void compose (); std::shared_ptr createFileTransferMessage (const LinphoneContent *initialContent); std::shared_ptr createMessage (const std::string &msg); diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index fb7270231..a32d9b094 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -67,7 +67,9 @@ ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, this->subject = subject; } -// ----------------------------------------------------------------------------- +int ClientGroupChatRoom::getCapabilities () const { + return static_cast(Capabilities::Conference); +} void ClientGroupChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { list
    addresses; diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 77121c01d..5801d3ffb 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -40,7 +40,8 @@ public: ClientGroupChatRoom (LinphoneCore *core, const Address &me, const std::string &uri, const std::string &subject); virtual ~ClientGroupChatRoom () = default; -public: + int getCapabilities () const override; + /* ConferenceInterface */ void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; diff --git a/src/chat/chat-room/real-time-text-chat-room.cpp b/src/chat/chat-room/real-time-text-chat-room.cpp index 08da5812e..212fc9d19 100644 --- a/src/chat/chat-room/real-time-text-chat-room.cpp +++ b/src/chat/chat-room/real-time-text-chat-room.cpp @@ -111,7 +111,9 @@ void RealTimeTextChatRoomPrivate::sendMessage (const std::shared_ptr(Capabilities::Basic) | static_cast(Capabilities::RealTimeText); +} uint32_t RealTimeTextChatRoom::getChar () const { L_D(); diff --git a/src/chat/chat-room/real-time-text-chat-room.h b/src/chat/chat-room/real-time-text-chat-room.h index dcc06c7d7..0dc3f6482 100644 --- a/src/chat/chat-room/real-time-text-chat-room.h +++ b/src/chat/chat-room/real-time-text-chat-room.h @@ -38,6 +38,8 @@ public: RealTimeTextChatRoom (LinphoneCore *core, const Address &peerAddress); virtual ~RealTimeTextChatRoom () = default; + int getCapabilities () const override; + uint32_t getChar () const; LinphoneCall *getCall () const; diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index c385aca21..b3c50d45c 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -28,6 +28,7 @@ #include "abstract/abstract-db-p.h" #include "chat/chat-message/chat-message.h" +#include "chat/chat-room/chat-room.h" #include "conference/participant.h" #include "content/content-type.h" #include "content/content.h" @@ -61,7 +62,7 @@ public: void insertContent (long messageEventId, const Content &content); long insertContentType (const string &contentType); long insertEvent (EventLog::Type type, const tm &date); - long insertChatRoom (long sipAddressId, const tm &date); + long insertChatRoom (long sipAddressId, int capabilities, const tm &date); void insertChatRoomParticipant (long chatRoomId, long sipAddressId, bool isAdmin); long insertMessageEvent ( @@ -201,15 +202,16 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return q->getLastInsertId(); } - long EventsDbPrivate::insertChatRoom (long sipAddressId, const tm &date) { + long EventsDbPrivate::insertChatRoom (long sipAddressId, int capabilities, const tm &date) { soci::session *session = dbSession.getBackendSession(); long id; *session << "SELECT peer_sip_address_id FROM chat_room WHERE peer_sip_address_id = :sipAddressId", soci::use(sipAddressId), soci::into(id); if (!session->got_data()) - *session << "INSERT INTO chat_room (peer_sip_address_id, creation_date, last_update_date, subject) VALUES" - " (:sipAddressId, :creationDate, :lastUpdateDate, '')", soci::use(sipAddressId), soci::use(date), soci::use(date); + *session << "INSERT INTO chat_room (peer_sip_address_id, creation_date, last_update_date, capabilities, subject) VALUES" + " (:sipAddressId, :creationDate, :lastUpdateDate, :capabilities, '')", + soci::use(sipAddressId), soci::use(date), soci::use(date), soci::use(capabilities); else *session << "UPDATE chat_room SET last_update_date = :lastUpdateDate WHERE peer_sip_address_id = :sipAddressId", soci::use(date), soci::use(sipAddressId); @@ -367,7 +369,11 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} references.eventId = insertEvent(EventLog::Type::ChatMessage, date); references.localSipAddressId = insertSipAddress(message.get(LEGACY_MESSAGE_COL_LOCAL_ADDRESS)); references.remoteSipAddressId = insertSipAddress(message.get(LEGACY_MESSAGE_COL_REMOTE_ADDRESS)); - references.chatRoomId = insertChatRoom(references.remoteSipAddressId, date); + references.chatRoomId = insertChatRoom( + references.remoteSipAddressId, + static_cast(ChatRoom::Capabilities::Basic), + date + ); insertChatRoomParticipant(references.chatRoomId, references.remoteSipAddressId, false); @@ -423,6 +429,9 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} // Last event date (call, message...). " last_update_date DATE NOT NULL," + // ConferenceChatRoom, BasicChatRoom, RTT... + "capabilities TINYINT UNSIGNED," + // Chatroom subject. " subject VARCHAR(255)," @@ -531,7 +540,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} // Trigger to delete participant_message cache entries. string displayedId = Utils::toString(static_cast(ChatMessage::State::Displayed)); string participantMessageDeleter = - "CREATE TRIGGER IF NOT EXISTS message_participant_deleter" + "CREATE TRIGGER IF NOT EXISTS message_participant_deleter" " AFTER UPDATE OF state ON message_participant FOR EACH ROW" " WHEN NEW.state = "; participantMessageDeleter += displayedId; From 1710cece1af1a675300e8483dca0ea2101806d33 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 12 Oct 2017 11:23:18 +0200 Subject: [PATCH 0448/2215] feat(AbstractDb): supports MySql backend for last insert id --- src/db/abstract/abstract-db.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/db/abstract/abstract-db.cpp b/src/db/abstract/abstract-db.cpp index 731f53bed..94baefbae 100644 --- a/src/db/abstract/abstract-db.cpp +++ b/src/db/abstract/abstract-db.cpp @@ -91,21 +91,24 @@ string AbstractDb::primaryKeyAutoIncrementStr (const string &type) const { } long AbstractDb::getLastInsertId () const { - L_D(); - - string sql; - switch(d->backend) { - case Sqlite3: - sql = "SELECT last_insert_rowid()"; - break; - default: - lWarning() << "Unsupported backend."; - return -1; - } - long result = 0; #ifdef SOCI_ENABLED + L_D(); + + string sql; + switch (d->backend) { + case Mysql: + sql = "SELECT LAST_INSERT_ID()"; + break; + case Sqlite3: + sql = "SELECT last_insert_rowid()"; + break; + default: + lWarning() << "Unsupported backend."; + return -1; + } + soci::session *session = d->dbSession.getBackendSession(); *session << sql, soci::into(result); #endif // ifdef SOCI_ENABLED From a780121af08c512bf7f4484edbaa8aed46523d91 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 12 Oct 2017 11:41:01 +0200 Subject: [PATCH 0449/2215] Add pragma to remove warnings when building the xsd generated source code. --- src/xml/conference-info.cpp | 1 + src/xml/conference-info.h | 1 + src/xml/prologue.txt | 1 + src/xml/resource-lists.cpp | 1 + src/xml/resource-lists.h | 1 + src/xml/xml.cpp | 1 + src/xml/xml.h | 1 + 7 files changed, 7 insertions(+) diff --git a/src/xml/conference-info.cpp b/src/xml/conference-info.cpp index 5378d95c5..934688d90 100644 --- a/src/xml/conference-info.cpp +++ b/src/xml/conference-info.cpp @@ -35,6 +35,7 @@ // #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" #ifndef __ANDROID__ #pragma GCC diagnostic ignored "-Wsuggest-override" #endif diff --git a/src/xml/conference-info.h b/src/xml/conference-info.h index 6743d0d6f..d748952de 100644 --- a/src/xml/conference-info.h +++ b/src/xml/conference-info.h @@ -50,6 +50,7 @@ // #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" #ifndef __ANDROID__ #pragma GCC diagnostic ignored "-Wsuggest-override" #endif diff --git a/src/xml/prologue.txt b/src/xml/prologue.txt index a9ad12572..f2a7bf6f0 100644 --- a/src/xml/prologue.txt +++ b/src/xml/prologue.txt @@ -1,5 +1,6 @@ #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" #ifndef __ANDROID__ #pragma GCC diagnostic ignored "-Wsuggest-override" #endif diff --git a/src/xml/resource-lists.cpp b/src/xml/resource-lists.cpp index 01a3d9acf..df290b542 100644 --- a/src/xml/resource-lists.cpp +++ b/src/xml/resource-lists.cpp @@ -35,6 +35,7 @@ // #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" #ifndef __ANDROID__ #pragma GCC diagnostic ignored "-Wsuggest-override" #endif diff --git a/src/xml/resource-lists.h b/src/xml/resource-lists.h index fa85b5adf..9ad3ebc70 100644 --- a/src/xml/resource-lists.h +++ b/src/xml/resource-lists.h @@ -50,6 +50,7 @@ // #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" #ifndef __ANDROID__ #pragma GCC diagnostic ignored "-Wsuggest-override" #endif diff --git a/src/xml/xml.cpp b/src/xml/xml.cpp index 71588e366..8025cbaec 100644 --- a/src/xml/xml.cpp +++ b/src/xml/xml.cpp @@ -35,6 +35,7 @@ // #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" #ifndef __ANDROID__ #pragma GCC diagnostic ignored "-Wsuggest-override" #endif diff --git a/src/xml/xml.h b/src/xml/xml.h index 04b3dc788..4bc12340b 100644 --- a/src/xml/xml.h +++ b/src/xml/xml.h @@ -50,6 +50,7 @@ // #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" #ifndef __ANDROID__ #pragma GCC diagnostic ignored "-Wsuggest-override" #endif From dc809316724b458a24483d41811a5dfb890b993e Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 12 Oct 2017 12:10:35 +0200 Subject: [PATCH 0450/2215] begin last conference event notify sent/received management --- .../local-conference-event-handler-p.h | 7 +++++- .../local-conference-event-handler.cpp | 24 ++++++++++--------- .../remote-conference-event-handler-p.h | 4 ++++ .../remote-conference-event-handler.cpp | 5 ++++ 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/conference/local-conference-event-handler-p.h b/src/conference/local-conference-event-handler-p.h index b50af3ed7..0fffe1c55 100644 --- a/src/conference/local-conference-event-handler-p.h +++ b/src/conference/local-conference-event-handler-p.h @@ -24,6 +24,7 @@ #include "local-conference-event-handler.h" #include "object/object-p.h" +#include "xml/conference-info.h" LINPHONE_BEGIN_NAMESPACE @@ -32,6 +33,7 @@ public: void notifyFullState (const std::string ¬ify, LinphoneEvent *lev); void notifyAllExcept (const std::string ¬ify, const Address &addr); void notifyAll (const std::string ¬ify); + std::string createNotify (Xsd::ConferenceInfo::ConferenceType confInfo); std::string createNotifyFullState (); std::string createNotifyParticipantAdded (const Address &addr); std::string createNotifyParticipantRemoved (const Address &addr); @@ -40,10 +42,13 @@ public: std::string createNotifyParticipantDeviceAdded (const Address &addr, const Address &gruu); std::string createNotifyParticipantDeviceRemoved (const Address &addr, const Address &gruu); + inline unsigned int getLastNotify () const { return lastNotify; }; + private: LinphoneCore *core = nullptr; LocalConference *conf = nullptr; - + unsigned int lastNotify = 0; + void sendNotify (const std::string ¬ify, const Address &addr); L_DECLARE_PUBLIC(LocalConferenceEventHandler); diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 4c01fb859..fef59f0ef 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -21,11 +21,8 @@ #include "conference/participant-p.h" #include "local-conference-event-handler-p.h" #include "object/object-p.h" - #include "private.h" -#include "xml/conference-info.h" - // ============================================================================= using namespace std; @@ -44,14 +41,6 @@ static void doNotify (const string ¬ify, LinphoneEvent *lev) { linphone_event_unref(lev); } -static string createNotify (ConferenceType confInfo) { - stringstream notify; - Xsd::XmlSchema::NamespaceInfomap map; - map[""].name = "urn:ietf:params:xml:ns:conference-info"; - serializeConferenceInfo(notify, confInfo, map); - return notify.str(); -} - // ----------------------------------------------------------------------------- void LocalConferenceEventHandlerPrivate::notifyFullState (const string ¬ify, LinphoneEvent *lev) { @@ -76,6 +65,18 @@ void LocalConferenceEventHandlerPrivate::notifyAll (const string ¬ify) { } } +string LocalConferenceEventHandlerPrivate::createNotify (ConferenceType confInfo) { + if (confInfo.getVersion().present()) { + lastNotify = confInfo.getVersion().get() + 1; + confInfo.setVersion(lastNotify); + } + stringstream notify; + Xsd::XmlSchema::NamespaceInfomap map; + map[""].name = "urn:ietf:params:xml:ns:conference-info"; + serializeConferenceInfo(notify, confInfo, map); + return notify.str(); +} + string LocalConferenceEventHandlerPrivate::createNotifyFullState () { string entity = conf->getConferenceAddress()->asStringUriOnly(); string subject = conf->getSubject(); @@ -248,6 +249,7 @@ LocalConferenceEventHandler::LocalConferenceEventHandler (LinphoneCore *core, Lo xercesc::XMLPlatformUtils::Initialize(); d->conf = localConf; d->core = core; + //init d->lastNotify = last notify } LocalConferenceEventHandler::~LocalConferenceEventHandler () { diff --git a/src/conference/remote-conference-event-handler-p.h b/src/conference/remote-conference-event-handler-p.h index 71c342c42..e89c454c1 100644 --- a/src/conference/remote-conference-event-handler-p.h +++ b/src/conference/remote-conference-event-handler-p.h @@ -26,11 +26,15 @@ LINPHONE_BEGIN_NAMESPACE class RemoteConferenceEventHandlerPrivate : public ObjectPrivate { +public: + inline unsigned int getLastNotify () const { return lastNotify; }; + private: LinphoneCore *core = nullptr; ConferenceListener *listener = nullptr; Address confAddress; LinphoneEvent *lev = nullptr; + unsigned int lastNotify = 0; L_DECLARE_PUBLIC(RemoteConferenceEventHandler); }; diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 6f23d31f8..749cd5bed 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -38,6 +38,7 @@ RemoteConferenceEventHandler::RemoteConferenceEventHandler (LinphoneCore *core, xercesc::XMLPlatformUtils::Initialize(); d->core = core; d->listener = listener; + // TODO : d->lastNotify = lastNotify } RemoteConferenceEventHandler::~RemoteConferenceEventHandler () { @@ -48,6 +49,7 @@ RemoteConferenceEventHandler::~RemoteConferenceEventHandler () { void RemoteConferenceEventHandler::subscribe (const Address &addr) { L_D(); + // TODO : add last notify d->confAddress = addr; LinphoneAddress *lAddr = linphone_address_new(d->confAddress.asString().c_str()); d->lev = linphone_core_create_subscribe(d->core, lAddr, "conference", 600); @@ -76,6 +78,9 @@ void RemoteConferenceEventHandler::notifyReceived (string xmlBody) { if (confInfo->getConferenceDescription().present() && confInfo->getConferenceDescription().get().getSubject().present()) d->listener->onSubjectChanged(confInfo->getConferenceDescription().get().getSubject().get()); + if (confInfo->getVersion().present()) + d->lastNotify = confInfo->getVersion().get(); + if (!confInfo->getUsers().present()) return; From 57626a7521e16019c5e377794ff88b3171c68c00 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 12 Oct 2017 12:14:48 +0200 Subject: [PATCH 0451/2215] put a method to private where it belongs --- src/conference/local-conference-event-handler-p.h | 2 +- src/conference/local-conference-event-handler.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/conference/local-conference-event-handler-p.h b/src/conference/local-conference-event-handler-p.h index 0fffe1c55..82b11f083 100644 --- a/src/conference/local-conference-event-handler-p.h +++ b/src/conference/local-conference-event-handler-p.h @@ -33,7 +33,6 @@ public: void notifyFullState (const std::string ¬ify, LinphoneEvent *lev); void notifyAllExcept (const std::string ¬ify, const Address &addr); void notifyAll (const std::string ¬ify); - std::string createNotify (Xsd::ConferenceInfo::ConferenceType confInfo); std::string createNotifyFullState (); std::string createNotifyParticipantAdded (const Address &addr); std::string createNotifyParticipantRemoved (const Address &addr); @@ -49,6 +48,7 @@ private: LocalConference *conf = nullptr; unsigned int lastNotify = 0; + std::string createNotify (Xsd::ConferenceInfo::ConferenceType confInfo); void sendNotify (const std::string ¬ify, const Address &addr); L_DECLARE_PUBLIC(LocalConferenceEventHandler); diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index fef59f0ef..59b67edaa 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -249,7 +249,7 @@ LocalConferenceEventHandler::LocalConferenceEventHandler (LinphoneCore *core, Lo xercesc::XMLPlatformUtils::Initialize(); d->conf = localConf; d->core = core; - //init d->lastNotify = last notify + // TODO : init d->lastNotify = last notify } LocalConferenceEventHandler::~LocalConferenceEventHandler () { From def3a31e09e2f9397a9a9c11ce366158df74e657 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 12 Oct 2017 13:05:38 +0200 Subject: [PATCH 0452/2215] Do not wrap IMEE + fix java wrapper compil when using -j + fixed classBl in abstractAPI tool + various fixes for jni layer of java wrapper --- coreapi/CMakeLists.txt | 4 +- include/linphone/api/c-chat-room.h | 1 + include/linphone/im_encryption_engine.h | 24 +++++++ tools/abstractapi.py | 4 +- wrappers/java/genwrapper.py | 79 ++++++++++++++++------- wrappers/java/jni.mustache | 84 ++++++++++++++----------- 6 files changed, 133 insertions(+), 63 deletions(-) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index d4faf04cc..6065c4a8f 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -206,9 +206,6 @@ if(ENABLE_STATIC) add_dependencies(linphone-static liblinphone-git-version) target_include_directories(linphone-static PUBLIC ${LINPHONE_INCLUDE_DIRS}) target_link_libraries(linphone-static INTERFACE ${LIBS}) - if(ANDROID) - add_dependencies(linphone-static linphonecore-jni-header) - endif() if(IOS) target_link_libraries(linphone-static INTERFACE "-framework Foundation" "-framework AVFoundation") endif() @@ -254,6 +251,7 @@ if(ENABLE_SHARED) set_target_properties(linphone PROPERTIES PREFIX "lib") elseif(ANDROID) target_link_libraries(linphone PUBLIC "log" ${SUPPORT_LIBRARIES} ${CPUFEATURES_LIBRARIES}) + add_dependencies(linphone linphonej) endif() if(MSVC) if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index e6e1d0d31..534c4265e 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -78,6 +78,7 @@ LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message(LinphoneC * @param is_read TRUE if the message should be flagged as read, FALSE otherwise. * @param is_incoming TRUE if the message has been received, FALSE otherwise. * @return a new #LinphoneChatMessage + * @donotwrap */ LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message_2(LinphoneChatRoom *cr, const char* message, const char* external_body_url, LinphoneChatMessageState state, time_t time, bool_t is_read, bool_t is_incoming); diff --git a/include/linphone/im_encryption_engine.h b/include/linphone/im_encryption_engine.h index d4c15dc3d..2a39661a9 100644 --- a/include/linphone/im_encryption_engine.h +++ b/include/linphone/im_encryption_engine.h @@ -35,12 +35,14 @@ extern "C" { * Acquire a reference to the LinphoneImEncryptionEngineCbs. * @param[in] cbs LinphoneImEncryptionEngineCbs object. * @return The same LinphoneImEncryptionEngineCbs object. + * @donotwrap **/ LinphoneImEncryptionEngineCbs * linphone_im_encryption_engine_cbs_ref(LinphoneImEncryptionEngineCbs *cbs); /** * Release reference to the LinphoneImEncryptionEngineCbs. * @param[in] cbs LinphoneImEncryptionEngineCbs object. + * @donotwrap **/ void linphone_im_encryption_engine_cbs_unref(LinphoneImEncryptionEngineCbs *cbs); @@ -48,6 +50,7 @@ void linphone_im_encryption_engine_cbs_unref(LinphoneImEncryptionEngineCbs *cbs) * Gets the user data in the LinphoneImEncryptionEngineCbs object * @param[in] cbs the LinphoneImEncryptionEngineCbs * @return the user data + * @donotwrap */ LINPHONE_PUBLIC void *linphone_im_encryption_engine_cbs_get_user_data(const LinphoneImEncryptionEngineCbs *cbs); @@ -55,6 +58,7 @@ LINPHONE_PUBLIC void *linphone_im_encryption_engine_cbs_get_user_data(const Linp * Sets the user data in the LinphoneImEncryptionEngineCbs object * @param[in] cbs the LinphoneImEncryptionEngineCbs object * @param[in] data the user data + * @donotwrap */ LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_user_data(LinphoneImEncryptionEngineCbs *cbs, void *data); @@ -62,12 +66,14 @@ LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_user_data(LinphoneImE * Acquire a reference to the LinphoneImEncryptionEngine. * @param[in] imee LinphoneImEncryptionEngine object. * @return The same LinphoneImEncryptionEngine object. + * @donotwrap **/ LINPHONE_PUBLIC LinphoneImEncryptionEngine * linphone_im_encryption_engine_ref(LinphoneImEncryptionEngine *imee); /** * Release reference to the LinphoneImEncryptionEngine. * @param[in] imee LinphoneImEncryptionEngine object. + * @donotwrap **/ LINPHONE_PUBLIC void linphone_im_encryption_engine_unref(LinphoneImEncryptionEngine *imee); @@ -75,6 +81,7 @@ LINPHONE_PUBLIC void linphone_im_encryption_engine_unref(LinphoneImEncryptionEng * Gets the user data in the LinphoneImEncryptionEngine object * @param[in] imee the LinphoneImEncryptionEngine * @return the user data + * @donotwrap */ LINPHONE_PUBLIC void *linphone_im_encryption_engine_get_user_data(const LinphoneImEncryptionEngine *imee); @@ -82,6 +89,7 @@ LINPHONE_PUBLIC void *linphone_im_encryption_engine_get_user_data(const Linphone * Sets the user data in the LinphoneImEncryptionEngine object * @param[in] imee the LinphoneImEncryptionEngine object * @param[in] data the user data + * @donotwrap */ LINPHONE_PUBLIC void linphone_im_encryption_engine_set_user_data(LinphoneImEncryptionEngine *imee, void *data); @@ -89,6 +97,7 @@ LINPHONE_PUBLIC void linphone_im_encryption_engine_set_user_data(LinphoneImEncry * Gets the LinphoneCore object that created the IM encryption engine * @param[in] imee LinphoneImEncryptionEngine object * @return The LinphoneCore object that created the IM encryption engine + * @donotwrap */ LINPHONE_PUBLIC LinphoneCore * linphone_im_encryption_engine_get_core(LinphoneImEncryptionEngine *imee); @@ -96,6 +105,7 @@ LINPHONE_PUBLIC LinphoneCore * linphone_im_encryption_engine_get_core(LinphoneIm * Gets the LinphoneImEncryptionEngineCbs object that holds the callbacks * @param[in] imee the LinphoneImEncryptionEngine object * @return the LinphoneImEncryptionEngineCbs object + * @donotwrap */ LINPHONE_PUBLIC LinphoneImEncryptionEngineCbs* linphone_im_encryption_engine_get_callbacks(const LinphoneImEncryptionEngine *imee); @@ -103,6 +113,7 @@ LINPHONE_PUBLIC LinphoneImEncryptionEngineCbs* linphone_im_encryption_engine_get * Gets the callback that will decrypt the chat messages upon reception * @param[in] cbs the LinphoneImEncryptionEngineCbs object * @return the callback + * @donotwrap */ LINPHONE_PUBLIC LinphoneImEncryptionEngineCbsIncomingMessageCb linphone_im_encryption_engine_cbs_get_process_incoming_message(LinphoneImEncryptionEngineCbs *cbs); @@ -110,6 +121,7 @@ LINPHONE_PUBLIC LinphoneImEncryptionEngineCbsIncomingMessageCb linphone_im_encry * Sets the callback that will decrypt the chat messages upon reception * @param[in] cbs the LinphoneImEncryptionEngineCbs object * @param[in] cb the callback to call + * @donotwrap */ LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_process_incoming_message(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineCbsIncomingMessageCb cb); @@ -117,6 +129,7 @@ LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_process_incoming_mess * Gets the callback that will encrypt the chat messages before sending them * @param[in] cbs the LinphoneImEncryptionEngineCbs object * @return the callback + * @donotwrap */ LINPHONE_PUBLIC LinphoneImEncryptionEngineCbsOutgoingMessageCb linphone_im_encryption_engine_cbs_get_process_outgoing_message(LinphoneImEncryptionEngineCbs *cbs); @@ -124,6 +137,7 @@ LINPHONE_PUBLIC LinphoneImEncryptionEngineCbsOutgoingMessageCb linphone_im_encry * Sets the callback that will encrypt the chat messages before sending them * @param[in] cbs the LinphoneImEncryptionEngineCbs object * @param[in] cb the callback to call + * @donotwrap */ LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_process_outgoing_message(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineCbsOutgoingMessageCb cb); @@ -131,6 +145,7 @@ LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_process_outgoing_mess * Gets the callback that will decrypt the files while downloading them * @param[in] cbs the LinphoneImEncryptionEngineCbs object * @return the callback + * @donotwrap */ LINPHONE_PUBLIC LinphoneImEncryptionEngineCbsDownloadingFileCb linphone_im_encryption_engine_cbs_get_process_downloading_file(LinphoneImEncryptionEngineCbs *cbs); @@ -138,6 +153,7 @@ LINPHONE_PUBLIC LinphoneImEncryptionEngineCbsDownloadingFileCb linphone_im_encry * Sets the callback that will decrypt the files while downloading them * @param[in] cbs the LinphoneImEncryptionEngineCbs object * @param[in] cb the callback to call + * @donotwrap */ LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_process_downloading_file(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineCbsDownloadingFileCb cb); @@ -145,6 +161,7 @@ LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_process_downloading_f * Gets the callback that will will encrypt the files while uploading them * @param[in] cbs the LinphoneImEncryptionEngineCbs object * @return the callback + * @donotwrap */ LINPHONE_PUBLIC LinphoneImEncryptionEngineCbsUploadingFileCb linphone_im_encryption_engine_cbs_get_process_uploading_file(LinphoneImEncryptionEngineCbs *cbs); @@ -152,6 +169,7 @@ LINPHONE_PUBLIC LinphoneImEncryptionEngineCbsUploadingFileCb linphone_im_encrypt * Sets the callback that will encrypt the files while uploading them * @param[in] cbs the LinphoneImEncryptionEngineCbs object * @param[in] cb the callback to call + * @donotwrap */ LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_process_uploading_file(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineCbsUploadingFileCb cb); @@ -159,6 +177,7 @@ LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_process_uploading_fil * Gets the callback telling wheter or not to encrypt the files * @param[in] cbs the LinphoneImEncryptionEngineCbs object * @return the callback + * @donotwrap */ LINPHONE_PUBLIC LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb linphone_im_encryption_engine_cbs_get_is_encryption_enabled_for_file_transfer(LinphoneImEncryptionEngineCbs *cbs); @@ -166,6 +185,7 @@ LINPHONE_PUBLIC LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferC * Sets the callback telling wheter or not to encrypt the files * @param[in] cbs the LinphoneImEncryptionEngineCbs object * @param[in] cb the callback to call + * @donotwrap */ LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_is_encryption_enabled_for_file_transfer(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb cb); @@ -173,6 +193,7 @@ LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_is_encryption_enabled * Gets the callback that will generate the key to encrypt the file before uploading it * @param[in] cbs the LinphoneImEncryptionEngineCbs object * @return the callback + * @donotwrap */ LINPHONE_PUBLIC LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(LinphoneImEncryptionEngineCbs *cbs); @@ -180,6 +201,7 @@ LINPHONE_PUBLIC LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb linphone_ * Sets the callback that will generate the key to encrypt the file before uploading it * @param[in] cbs the LinphoneImEncryptionEngineCbs object * @param[in] cb the callback to call + * @donotwrap */ LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_generate_file_transfer_key(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb cb); @@ -187,12 +209,14 @@ LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_generate_file_transfe * @param[in] msg LinphoneChatMessage * @param[in] text Const char * * @returns 0 if succeed. + * @donotwrap */ LINPHONE_PUBLIC int linphone_chat_message_set_text(LinphoneChatMessage *msg, const char* text); /** * Create the IM encryption engine * @return The created the IM encryption engine + * @donotwrap */ LINPHONE_PUBLIC LinphoneImEncryptionEngine *linphone_im_encryption_engine_new(void); diff --git a/tools/abstractapi.py b/tools/abstractapi.py index 00ab7d076..d7010dbb0 100644 --- a/tools/abstractapi.py +++ b/tools/abstractapi.py @@ -446,7 +446,7 @@ class Interface(DocumentableObject): class CParser(object): - def __init__(self, cProject): + def __init__(self, cProject, classBlAppend=[]): self.cBaseType = ['void', 'bool_t', 'char', 'short', 'int', 'long', 'size_t', 'time_t', 'float', 'double', 'LinphoneStatus'] self.cListType = 'bctbx_list_t' self.regexFixedSizeInteger = '^(u?)int(\d?\d)_t$' @@ -457,6 +457,8 @@ class CParser(object): 'linphone_vcard_get_belcard'] # manualy wrapped self.classBl = ['LpConfig'] # temporarly blacklisted + for bl in classBlAppend: + self.classBl.append(bl) # list of classes that must be concidered as refcountable even if # they are no ref()/unref() methods diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 180aa4c9d..749c4889e 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -116,11 +116,21 @@ class JavaTranslator(object): return 'V' return _type - def translate_as_c_base_type(self, _type): + def translate_as_c_base_type(self, t): + _type = t.name if _type == 'string': - return 'const char *' + return 'char *' elif _type == 'integer': - return 'int' + if t.size is None: + if t.isUnsigned: + return 'unsigned int' + return 'int' + inttype = 'int{0}_t'.format(t.size) + if t.isUnsigned: + inttype = 'u' + inttype + if t.isref: + inttype = inttype + ' *' + return inttype elif _type == 'boolean': return 'bool_t' elif _type == 'floatant': @@ -132,11 +142,13 @@ class JavaTranslator(object): elif _type == 'status': return 'int' elif _type == 'string_array': - return 'const char **' + return 'char **' elif _type == 'character': return 'char' elif _type == 'void': - return 'void *' + if t.isref: + return 'void *' + return 'void' return _type def translate_type(self, _type, native=False, jni=False, isReturn=False): @@ -145,6 +157,8 @@ class JavaTranslator(object): if type(_type.containedTypeDesc) is AbsApi.ClassType: return 'jobjectArray' elif type(_type.containedTypeDesc) is AbsApi.BaseType: + if _type.containedTypeDesc.name == 'string': + return 'jobjectArray' return self.translate_type(_type.containedTypeDesc, jni=True) + 'Array' elif type(_type.containedTypeDesc) is AbsApi.EnumType: ptrtype = self.translate_type(_type.containedTypeDesc, native) @@ -322,7 +336,8 @@ class JavaTranslator(object): methodDict['return'] = self.translate_type(_method.returnType, jni=True, isReturn=True) methodDict['hasListReturn'] = methodDict['return'] == 'jobjectArray' methodDict['hasReturn'] = not methodDict['return'] == 'void' and not methodDict['hasListReturn'] - methodDict['hasNormalReturn'] = not methodDict['hasListReturn'] + methodDict['hasStringReturn'] = methodDict['return'] == 'jstring' + methodDict['hasNormalReturn'] = not methodDict['hasListReturn'] and not methodDict['hasStringReturn'] methodDict['name'] = 'Java_' + self.jni_package + className.to_camel_case() + 'Impl_' + _method.name.to_camel_case(lower=True) methodDict['notStatic'] = not static methodDict['c_name'] = 'linphone_' + className.to_snake_case() + "_" + _method.name.to_snake_case() @@ -332,7 +347,9 @@ class JavaTranslator(object): methodDict['isStringObjectArray'] = False if methodDict['hasListReturn']: - if _method.returnType.name == 'string_array': + if type(_method.returnType) is AbsApi.BaseType and _method.returnType.name == 'string_array': + methodDict['isStringObjectArray'] = True + elif type(_method.returnType.containedTypeDesc) is AbsApi.BaseType: methodDict['isStringObjectArray'] = True elif type(_method.returnType.containedTypeDesc) is AbsApi.ClassType: methodDict['isRealObjectArray'] = True @@ -340,8 +357,6 @@ class JavaTranslator(object): methodDict['objectClassCName'] = 'Linphone' + _method.returnType.containedTypeDesc.desc.name.to_camel_case() methodDict['objectClassName'] = _method.returnType.containedTypeDesc.desc.name.to_camel_case() methodDict['objectClassImplName'] = _method.returnType.containedTypeDesc.desc.name.to_camel_case() + 'Impl' - else: - print 'toto' methodDict['params'] = 'JNIEnv *env, jobject thiz' if static else 'JNIEnv *env, jobject thiz, jlong ptr' methodDict['params_impl'] = '' @@ -352,18 +367,26 @@ class JavaTranslator(object): methodDict['returnedObjectGetter'] = '' for arg in _method.args: methodDict['params'] += ', ' - methodDict['params_impl'] += ', ' + if static: + if arg is not _method.args[0]: + methodDict['params_impl'] += ', ' + else: + methodDict['params_impl'] += ', ' + methodDict['params'] += self.translate_argument(arg, jni=True) argname = self.translate_argument_name(arg.name) if type(arg.type) is AbsApi.ClassType: - methodDict['objects'].append({'object': argname, 'objectClassCName': 'Linphone' + arg.type.desc.name.to_camel_case()}) + classCName = 'Linphone' + arg.type.desc.name.to_camel_case() + if classCName[-8:] == 'Listener': + classCName = 'Linphone' + arg.type.desc.name.to_camel_case()[:-8] + 'Cbs' + methodDict['objects'].append({'object': argname, 'objectClassCName': classCName}) methodDict['params_impl'] += 'c_' + argname elif type(arg.type) is AbsApi.ListType: isStringList = type(arg.type.containedTypeDesc) is AbsApi.BaseType and arg.type.containedTypeDesc.name == 'string' isObjList = type(arg.type.containedTypeDesc) is AbsApi.ClassType - methodDict['lists'].append({'list': argname, 'isStringList': isStringList, 'isObjList': isObjList}) + methodDict['lists'].append({'list': argname, 'isStringList': isStringList, 'isObjList': isObjList, 'objectClassCName': arg.type.containedTypeDesc.name}) methodDict['params_impl'] += 'bctbx_list_' + argname elif type(arg.type) is AbsApi.EnumType: @@ -375,7 +398,7 @@ class JavaTranslator(object): methodDict['strings'].append({'string': argname}) methodDict['params_impl'] += 'c_' + argname else: - methodDict['params_impl'] += argname + methodDict['params_impl'] += '(' + self.translate_as_c_base_type(arg.type) + ')' + argname else: methodDict['params_impl'] += argname @@ -434,14 +457,18 @@ class JavaTranslator(object): methodDict['className'] = className.to_camel_case() methodDict['classImplName'] = className.to_camel_case() + 'Impl' methodDict['jniPath'] = self.jni_path - methodDict['cPrefix'] = 'linphone_' + className.to_snake_case() + methodDict['cPrefix'] = 'linphone_' + className.to_snake_case()[:-9] # Remove _listener at the end methodDict['callbackName'] = methodDict['cPrefix'] + '_' + _method.name.to_snake_case() methodDict['jname'] = _method.name.to_camel_case(lower=True) - methodDict['return'] = self.translate_type(_method.returnType, jni=True, isReturn=True) - + methodDict['return'] = self.translate_as_c_base_type(_method.returnType) + if type(_method.returnType) is AbsApi.ClassType: + methodDict['return'] += '*' + methodDict['returnIfFail'] = '' if methodDict['return'] == 'void' else ' NULL' #TODO + methodDict['hasReturn'] = not methodDict['return'] == 'void' methodDict['isSingleListener'] = not _class.multilistener methodDict['isMultiListener'] = _class.multilistener + methodDict['firstParam'] = '' methodDict['jobjects'] = [] methodDict['jenums'] = [] methodDict['jstrings'] = [] @@ -453,14 +480,19 @@ class JavaTranslator(object): if arg is not _method.args[0]: methodDict['params'] += ', ' methodDict['params_impl'] += ', ' + else: + methodDict['firstParam'] = argname + + if (arg.type.isconst): + methodDict['params'] += 'const ' if type(arg.type) is AbsApi.ClassType: - methodDict['params'] += 'Linphone' + arg.type.desc.name.to_camel_case() + ' *' + (argname if arg is not _method.args[0] else 'cptr') + methodDict['params'] += 'Linphone' + arg.type.desc.name.to_camel_case() + ' *' + argname methodDict['jparams'] += 'L' + self.jni_path + arg.type.desc.name.to_camel_case() + ';' methodDict['params_impl'] += 'j_' + argname - methodDict['jobjects'].append({'objectName': argname, 'className': arg.type.desc.name.to_camel_case(),}) + methodDict['jobjects'].append({'objectName': argname, 'className': arg.type.desc.name.to_camel_case(), }) elif type(arg.type) is AbsApi.BaseType: - methodDict['params'] += self.translate_as_c_base_type(arg.type.name) + ' ' + argname + methodDict['params'] += self.translate_as_c_base_type(arg.type) + ' ' + argname methodDict['jparams'] += self.translate_java_jni_base_type_name(arg.type.name) if arg.type.name == 'string': methodDict['params_impl'] += 'j_' + argname @@ -551,7 +583,7 @@ class JniInterface(object): self.callbacks = [] listener = apiClass.listenerInterface for method in listener.methods: - cb = 'linphone_' + listener.name.to_snake_case() + cb = 'linphone_' + listener.name.to_snake_case()[:-9] # Remove _listener at the end cbName = cb + '_' + method.name.to_snake_case() self.callbacks.append({ 'callbackName': cbName, @@ -677,13 +709,14 @@ class GenWrapper(object): project.initFromDir(xmldir) project.check() - self.parser = AbsApi.CParser(project) + self.parser = AbsApi.CParser(project, ['LinphoneBuffer']) self.parser.functionBl = \ ['linphone_vcard_get_belcard',\ 'linphone_core_get_current_vtable',\ 'linphone_factory_get',\ - 'linphone_factory_clean'] - self.parser.classBl += 'LinphoneCoreVTable' + 'linphone_factory_clean',\ + 'linphone_call_zoom_video',\ + 'linphone_config_get_range'] self.parser.parse_all() self.translator = JavaTranslator(package) self.renderer = pystache.Renderer() diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index 499e30659..437c2f286 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -18,15 +18,16 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include -#include "linphone/core_utils.h" #include +#include "belle-sip/object.h" #include "mediastreamer2/mediastream.h" #include "mediastreamer2/mscommon.h" #include "mediastreamer2/msmediaplayer.h" #include "mediastreamer2/msutils.h" #include "mediastreamer2/devices.h" #include "mediastreamer2/msjava.h" +#include "linphone/core_utils.h" #include "linphone/core.h" #include "linphone/tunnel.h" #include "linphone/account_creator.h" @@ -44,12 +45,12 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *ajvm, void *reserved) { #ifdef __ANDROID__ ms_set_jvm(ajvm); #endif /* __ANDROID__ */ - LinphoneJavaBindings *ljb = new LinphoneJavaBindings(ms_get_jni_env()); - linphone_factory_set_user_data(linphone_factory_get(), ljb); jvm = ajvm; return JNI_VERSION_1_2; } +#define belle_sip_java_user_data_key "java_object" + static const char* GetStringUTFChars(JNIEnv* env, jstring string) { const char *cstring = string ? env->GetStringUTFChars(string, NULL) : NULL; return cstring; @@ -108,28 +109,33 @@ public: ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {{#objects}} -jobject get{{className}}(JNIEnv *env, {{classCName}} *ptr) { +jobject get{{className}}(JNIEnv *env, {{classCName}} *cptr) { jobject jobj = 0; - if (ptr != NULL) { - void *up = {{cPrefix}}_get_user_data(ptr); + if (cptr != NULL) { + void *up = belle_sip_object_data_get((belle_sip_object_t *)cptr, belle_sip_java_user_data_key); LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_factory_get_user_data(linphone_factory_get()); + if (!ljb) { + ljb = new LinphoneJavaBindings(env); + linphone_factory_set_user_data(linphone_factory_get(), ljb); + } + jclass {{cPrefix}}_class = ljb->{{cPrefix}}_class; jmethodID {{cPrefix}}_constructor = ljb->{{cPrefix}}_class_constructor; if (up == NULL) { - jobj = env->NewObject({{cPrefix}}_class, {{cPrefix}}_constructor, (jlong)ptr); - {{cPrefix}}_set_user_data(ptr, (void*)env->NewWeakGlobalRef(jobj)); - {{cPrefix}}_ref(ptr); + jobj = env->NewObject({{cPrefix}}_class, {{cPrefix}}_constructor, (jlong)cptr); + belle_sip_object_data_set((belle_sip_object_t *)cptr, belle_sip_java_user_data_key, (void*)env->NewWeakGlobalRef(jobj), NULL); + {{cPrefix}}_ref(cptr); } else { jobj = env->NewLocalRef((jobject)up); if (jobj == NULL) { // Delete weak ref ? env->DeleteWeakGlobalRef((jobject)up); // takes implicit local ref - jobj = env->NewObject({{cPrefix}}_class, {{cPrefix}}_constructor, (jlong)ptr); - {{cPrefix}}_set_user_data(ptr, (void*)env->NewWeakGlobalRef(jobj)); - {{cPrefix}}_ref(ptr); + jobj = env->NewObject({{cPrefix}}_class, {{cPrefix}}_constructor, (jlong)cptr); + belle_sip_object_data_set((belle_sip_object_t *)cptr, belle_sip_java_user_data_key, (void*)env->NewWeakGlobalRef(jobj), NULL); + {{cPrefix}}_ref(cptr); } } } @@ -138,8 +144,8 @@ jobject get{{className}}(JNIEnv *env, {{classCName}} *ptr) { void Java_{{jniPrefix}}{{classImplName}}_unref(JNIEnv* env, jobject thiz, jlong ptr) { {{classCName}} *cptr = ({{classCName}}*)ptr; - jobject wref = (jobject){{cPrefix}}_get_user_data(cptr); - {{cPrefix}}_set_user_data(cptr, NULL); + jobject wref = (jobject)belle_sip_object_data_get((belle_sip_object_t *)cptr, belle_sip_java_user_data_key); + belle_sip_object_data_set((belle_sip_object_t *)cptr, belle_sip_java_user_data_key, NULL, NULL); if (wref) { env->DeleteWeakGlobalRef(wref); } @@ -161,24 +167,23 @@ static inline void handle_possible_java_exception(JNIEnv *env, jobject listener) {{#callbacks}} static {{return}} {{callbackName}}({{params}}) { JNIEnv *env = 0; - jint result = jvm->AttachCurrentThread(&env,NULL); - LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_factory_get_user_data(linphone_factory_get()); - if (result != 0) { + jint jvmResult = jvm->AttachCurrentThread(&env,NULL); + if (jvmResult != 0) { ms_error("cannot attach VM"); - return; + return{{returnIfFail}}; } {{#isSingleListener}} - {{classCName}}Cbs *cbs = {{cPrefix}}_get_callbacks(cptr); + {{classCName}}Cbs *cbs = {{cPrefix}}_get_callbacks({{firstParam}}); {{/isSingleListener}} {{#isMultiListener}} - {{classCName}}Cbs *cbs = {{cPrefix}}_get_current_callbacks(cptr); + {{classCName}}Cbs *cbs = {{cPrefix}}_get_current_callbacks({{firstParam}}); {{/isMultiListener}} jobject jlistener = (jobject) {{cPrefix}}_cbs_get_user_data(cbs); if (jlistener == NULL) { ms_warning("{{name}}() notification without listener"); - return ; + return{{returnIfFail}}; } jclass jlistenerClass = (jclass) env->GetObjectClass(jlistener); @@ -186,9 +191,10 @@ static {{return}} {{callbackName}}({{params}}) { env->DeleteLocalRef(jlistenerClass); {{#jobjects}} - jobject j_{{objectName}} = get{{className}}(env, {{objectName}}); + jobject j_{{objectName}} = get{{className}}(env, (Linphone{{className}} *){{objectName}}); {{/jobjects}} {{#jenums}} + LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_factory_get_user_data(linphone_factory_get()); jobject j_{{enumName}} = env->CallStaticObjectMethod(ljb->{{cEnumPrefix}}_class, ljb->{{cEnumPrefix}}_class_constructor_from_int, (jint){{enumName}}); {{/jenums}} {{#jstrings}} @@ -209,6 +215,9 @@ static {{return}} {{callbackName}}({{params}}) { {{/jstrings}} handle_possible_java_exception(env, jlistener); + {{#hasReturn}} + return 0; + {{/hasReturn}} } {{/callbacks}} @@ -243,7 +252,7 @@ void {{jniPackage}}{{classCName}}Impl_removeListener(JNIEnv* env, jobject thiz, {{classCName}} *cptr = ({{classCName}}*)ptr; const bctbx_list_t *cbs_list = {{cPrefix}}_get_callbacks_list(cptr); bctbx_list_t *it; - for (it = cbs_list; it != NULL; it = it->next) { + for (it = (bctbx_list_t *)cbs_list; it != NULL; it = it->next) { {{classCName}}Cbs *cbs = ({{classCName}}Cbs *)it->data; if ({{cPrefix}}_cbs_get_user_data(cbs) == jlistener) { {{cPrefix}}_remove_callbacks(cptr, cbs); @@ -258,16 +267,15 @@ void {{jniPackage}}{{classCName}}Impl_removeListener(JNIEnv* env, jobject thiz, {{#methods}} {{return}} {{name}}({{params}}) { - {{#notStatic}}{{classCName}} *cptr = ({{classCName}}*)ptr;{{/notStatic}} - {{#strings}} + {{#notStatic}}{{classCName}} *cptr = ({{classCName}}*)ptr;{{/notStatic}}{{#strings}} const char* c_{{string}} = GetStringUTFChars(env, {{string}}); {{/strings}}{{#objects}} {{objectClassCName}}* c_{{object}} = NULL; if ({{object}}) c_{{object}} = ({{objectClassCName}}*)GetObjectNativePtr(env, {{object}}); {{/objects}}{{#lists}} bctbx_list_t *bctbx_list_{{list}} = NULL; - int count = env->GetArrayLength({{list}}); - for (int i=0; i < count; i++) { + int {{list}}_count = env->GetArrayLength({{list}}); + for (int i=0; i < {{list}}_count; i++) { {{#isStringList}} jstring obj = (jstring) env->GetObjectArrayElement({{list}}, i); const char *str = GetStringUTFChars(env, obj); @@ -278,30 +286,34 @@ void {{jniPackage}}{{classCName}}Impl_removeListener(JNIEnv* env, jobject thiz, {{/isStringList}} {{#isObjList}} jobject obj = env->GetObjectArrayElement({{list}}, i); - bctbx_list_{{list}} = bctbx_list_append(bctbx_list_{{list}}, GetObjectNativePtr(env, obj)); + bctbx_list_{{list}} = bctbx_list_append(bctbx_list_{{list}}, ({{objectClassCName}} *)GetObjectNativePtr(env, obj)); {{/isObjList}} } {{/lists}}{{#hasListReturn}} - bctbx_list_t *list = {{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}}); + const bctbx_list_t *list = {{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}}); size_t count = bctbx_list_size(list); {{#isRealObjectArray}} LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_factory_get_user_data(linphone_factory_get()); - jobjectArray jni_list_result = env->NewObjectArray(count, ljb->{{objectCPrefix}}_class, NULL);{{/isRealObjectArray}} - {{#isStringObjectArray}}jobjectArray jni_list_result = env->NewObjectArray(count, env->FindClass("java/lang/String"), env->NewStringUTF(""));{{/isStringObjectArray}} + jobjectArray jni_list_result = env->NewObjectArray((int)count, ljb->{{objectCPrefix}}_class, NULL);{{/isRealObjectArray}} + {{#isStringObjectArray}}jobjectArray jni_list_result = env->NewObjectArray((int)count, env->FindClass("java/lang/String"), env->NewStringUTF(""));{{/isStringObjectArray}} for (size_t i = 0; i < count; i++) { {{#isRealObjectArray}} {{objectClassCName}}* c_object = ({{objectClassCName}}*)list->data; - jobject object = get{{objectClassName}}(c_object); + jobject object = get{{objectClassName}}(env, c_object); {{/isRealObjectArray}} - {{#isStringObjectArray}}jstring object = list->data ? env->NewStringUTF(list->data) : 0;{{/isStringObjectArray}} + {{#isStringObjectArray}}const char *cstring = (const char *)list->data; + jstring object = cstring ? env->NewStringUTF(cstring) : 0;{{/isStringObjectArray}} if (object != 0) { - env->SetObjectArrayElement(jni_list_result, i, object); + env->SetObjectArrayElement(jni_list_result, (int)i, object); {{#isRealObjectArray}}env->DeleteLocalRef(object);{{/isRealObjectArray}} } list = bctbx_list_next(list); } - {{/hasListReturn}}{{#hasNormalReturn}} - {{#hasReturn}}{{return}} jni_result = {{#returnObject}}get{{returnClassName}}({{/returnObject}}{{/hasReturn}}{{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}}){{#returnObject}}){{/returnObject}}; + {{/hasListReturn}}{{#hasStringReturn}} + const char *c_string = {{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}}){{#returnObject}}){{/returnObject}}; + jstring jni_result = (c_string != NULL) ? env->NewStringUTF(c_string) : NULL; + {{/hasStringReturn}}{{#hasNormalReturn}} + {{#hasReturn}}{{return}} jni_result = ({{return}}){{#returnObject}}get{{returnClassName}}(env, (Linphone{{returnClassName}} *){{/returnObject}}{{/hasReturn}}{{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}}){{#returnObject}}){{/returnObject}}; {{/hasNormalReturn}}{{#strings}} ReleaseStringUTFChars(env, {{string}}, c_{{string}}); {{/strings}}{{#hasReturn}}return jni_result;{{/hasReturn}}{{#hasListReturn}}return jni_list_result;{{/hasListReturn}} From d63af8a7991556d1384b94b014d3d2093fddd45c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 12 Oct 2017 13:37:01 +0200 Subject: [PATCH 0453/2215] Created replacements for methods returning const char ** using bctbx_lists --- coreapi/linphonecore.c | 18 ++++++++++++++++++ coreapi/lpconfig.c | 13 +++++++++++++ coreapi/misc.c | 9 +++++++++ include/linphone/core.h | 30 ++++++++++++++++++++++++++++++ include/linphone/lpconfig.h | 9 +++++++++ include/linphone/types.h | 2 ++ 6 files changed, 81 insertions(+) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 3ce577415..ebd2253a0 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4142,6 +4142,24 @@ const char** linphone_core_get_video_devices(const LinphoneCore *lc){ return lc->video_conf.cams; } +const bctbx_list_t * linphone_core_get_sound_devices_list(LinphoneCore *lc){ + bctbx_list_t *cards_list = NULL; + const char** cards = lc->sound_conf.cards; + for (const char* c = *cards; c; c=*++cards) { + cards_list = bctbx_list_append(cards_list, (char *)c); + } + return cards_list; +} + +const bctbx_list_t * linphone_core_get_video_devices_list(const LinphoneCore *lc){ + bctbx_list_t *cards_list = NULL; + const char** cards = lc->video_conf.cams; + for (const char* c = *cards; c; c=*++cards) { + cards_list = bctbx_list_append(cards_list, (char *)c); + } + return cards_list; +} + void linphone_core_set_default_sound_devices(LinphoneCore *lc){ linphone_core_set_ringer_device(lc, NULL); linphone_core_set_playback_device(lc, NULL); diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index 6e1b5cb60..36c512234 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -1127,6 +1127,19 @@ const char** linphone_config_get_sections_names(LpConfig *lpconfig) { return sections_names; } +const bctbx_list_t * linphone_config_get_sections_names_list(LpConfig *lpconfig) { + const bctbx_list_t *sections = lpconfig->sections; + bctbx_list_t *sections_names = NULL; + int i; + + for (i = 0; sections != NULL; sections = sections->next, i++) { + LpSection *section = (LpSection *)sections->data; + sections_names = bctbx_list_append(sections_names, section->name); + } + + return sections_names; +} + char* linphone_config_dump_as_xml(const LpConfig *lpconfig) { char *buffer; diff --git a/coreapi/misc.c b/coreapi/misc.c index c14a8b4c8..c48265397 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -824,6 +824,15 @@ const char ** linphone_core_get_supported_file_formats(LinphoneCore *core){ return core->supported_formats; } +bctbx_list_t * linphone_core_get_supported_file_formats_list(LinphoneCore *core){ + bctbx_list_t *file_formats = NULL; + file_formats = bctbx_list_append(file_formats, ms_strdup("wav")); + if (ms_factory_lookup_filter_by_id(core->factory,MS_MKV_RECORDER_ID)){ + file_formats = bctbx_list_append(file_formats, ms_strdup("mkv")); + } + return file_formats; +} + bool_t linphone_core_file_format_supported(LinphoneCore *lc, const char *fmt){ const char **formats=linphone_core_get_supported_file_formats(lc); for(;*formats!=NULL;++formats){ diff --git a/include/linphone/core.h b/include/linphone/core.h index e78ba8e4c..fabcdab6c 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -2686,9 +2686,19 @@ LINPHONE_PUBLIC LinphoneNatPolicy * linphone_core_get_nat_policy(const LinphoneC * @param[in] lc LinphoneCore object * @return An unmodifiable array of strings contanining the names of the available sound devices that is NULL terminated * @ingroup media_parameters + * @donotwrap + * @deprecated use linphone_core_get_sound_devices_list instead **/ LINPHONE_PUBLIC const char** linphone_core_get_sound_devices(LinphoneCore *lc); +/** + * Gets the list of the available sound devices. + * @param[in] lc LinphoneCore object + * @return \bctbx_list{char *} An unmodifiable array of strings contanining the names of the available sound devices that is NULL terminated + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC const bctbx_list_t * linphone_core_get_sound_devices_list(LinphoneCore *lc); + /** * Use this function when you want to set the default sound devices **/ @@ -3592,9 +3602,19 @@ LINPHONE_PUBLIC void linphone_core_reload_video_devices(LinphoneCore *lc); * @param[in] lc LinphoneCore object * @return An unmodifiable array of strings contanining the names of the available video capture devices that is NULL terminated * @ingroup media_parameters + * @deprecated use linphone_core_get_video_devices_list instead + * @donotwrap **/ LINPHONE_PUBLIC const char** linphone_core_get_video_devices(const LinphoneCore *lc); +/** + * Gets the list of the available video capture devices. + * @param[in] lc LinphoneCore object + * @return \bctbx_list{char *} An unmodifiable array of strings contanining the names of the available video capture devices that is NULL terminated + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC const bctbx_list_t * linphone_core_get_video_devices_list(LinphoneCore *lc); + /** * Sets the active video device. * @param[in] lc LinphoneCore object @@ -4474,9 +4494,19 @@ LINPHONE_PUBLIC const char * linphone_core_get_file_transfer_server(LinphoneCore * @param core the core * @return the supported formats, typically 'wav' and 'mkv' * @ingroup media_parameters + * @deprecated use linphone_core_get_supported_file_formats_list instead + * @donotwrap **/ LINPHONE_PUBLIC const char ** linphone_core_get_supported_file_formats(LinphoneCore *core); +/** + * Returns a null terminated table of strings containing the file format extension supported for call recording. + * @param core the core + * @return \bctbx_list{char *} the supported formats, typically 'wav' and 'mkv' + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC bctbx_list_t * linphone_core_get_supported_file_formats_list(LinphoneCore *core); + /** * Returns whether a specific file format is supported. * @see linphone_core_get_supported_file_formats diff --git a/include/linphone/lpconfig.h b/include/linphone/lpconfig.h index a68292b87..1a9d17dbf 100644 --- a/include/linphone/lpconfig.h +++ b/include/linphone/lpconfig.h @@ -220,9 +220,18 @@ LINPHONE_PUBLIC void linphone_config_clean_entry(LinphoneConfig *lpconfig, const * Returns the list of sections' names in the LinphoneConfig. * @param[in] lpconfig The LinphoneConfig object * @return a null terminated static array of strings + * @deprecated use linphone_config_get_sections_names_list instead + * @donotwrap **/ LINPHONE_PUBLIC const char** linphone_config_get_sections_names(LinphoneConfig *lpconfig); +/** + * Returns the list of sections' names in the LinphoneConfig. + * @param[in] lpconfig The LinphoneConfig object + * @return \bctbx_list{char *} a null terminated static array of strings +**/ +LINPHONE_PUBLIC const bctbx_list_t * linphone_config_get_sections_names_list(LpConfig *lpconfig); + /** * Call a function for each section present in the configuration. **/ diff --git a/include/linphone/types.h b/include/linphone/types.h index b314051af..c1c46e835 100644 --- a/include/linphone/types.h +++ b/include/linphone/types.h @@ -537,12 +537,14 @@ typedef enum _LinphoneIceState { /** * IM encryption engine. * @ingroup misc + * @donotwrap */ typedef struct _LinphoneImEncryptionEngine LinphoneImEncryptionEngine; /** * An object to handle the callbacks for the handling a LinphoneImEncryptionEngine object. * @ingroup misc + * @donotwrap */ typedef struct _LinphoneImEncryptionEngineCbs LinphoneImEncryptionEngineCbs; From 5c52c4db7070d5b0c7234033229fb5ca38fc2a6a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 12 Oct 2017 14:07:23 +0200 Subject: [PATCH 0454/2215] Fixed some issues in generated Java code --- wrappers/java/classes/CoreException.java | 39 ++++++++++++++++++++++++ wrappers/java/genwrapper.py | 7 +++++ wrappers/java/java_class.mustache | 2 +- 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 wrappers/java/classes/CoreException.java diff --git a/wrappers/java/classes/CoreException.java b/wrappers/java/classes/CoreException.java new file mode 100644 index 000000000..3172687a1 --- /dev/null +++ b/wrappers/java/classes/CoreException.java @@ -0,0 +1,39 @@ +/* +CoreException.java +Copyright (C) 2010-2017 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +package org.linphone.core; + +@SuppressWarnings("serial") +public class CoreException extends Exception { + + public CoreException() { + } + + public CoreException(String detailMessage) { + super(detailMessage); + } + + public CoreException(Throwable e) { + super(e); + } + + public CoreException(String detailMessage, Throwable e) { + super(detailMessage,e); + } +} diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 749c4889e..256e17ef0 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -310,6 +310,7 @@ class JavaTranslator(object): for arg in _method.args: if arg is not _method.args[0]: methodDict['params'] += ', ' + methodDict['static_native_params'] += ', ' methodDict['native_params'] += ', ' methodDict['native_params_impl'] += ', ' @@ -799,6 +800,7 @@ class GenWrapper(object): ########################################################################## def main(): + import shutil argparser = argparse.ArgumentParser(description='Generate source files for the Java wrapper') argparser.add_argument('xmldir', type=str, help='Directory where the XML documentation of the Linphone\'s API generated by Doxygen is placed') argparser.add_argument('-o --output', type=str, help='the directory where to generate the source files', dest='outputdir', default='.') @@ -829,5 +831,10 @@ def main(): genwrapper = GenWrapper(srcdir, javadir, args.package, args.xmldir) genwrapper.render_all() + for f in os.listdir('./classes'): + src = os.path.join('./classes', f) + tgt = os.path.join(javadir, f) + shutil.copy(src, tgt) + if __name__ == '__main__': main() diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 873e3992a..77778af8d 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -145,7 +145,7 @@ class {{classImplName}} implements {{className}} { private native {{return_native}} {{name}}({{native_params}}); public {{return}} {{name}}({{params}}) {{#exception}}throws CoreException{{/exception}}{{#enumCast}}throws CoreException{{/enumCast}} { {{#exception}}int exceptionResult = {{/exception}}{{return_keyword}}{{#enumCast}}{{return}}.fromInt({{/enumCast}}{{#classCast}}({{return}}){{/classCast}}{{name}}(nativePtr{{native_params_impl}}){{#enumCast}}){{/enumCast}};{{#exception}} - if (exceptionResult != 0) throw new CoreException("{{name}} returned value " + exceptionResult){{/exception}} + if (exceptionResult != 0) throw new CoreException("{{name}} returned value " + exceptionResult);{{/exception}} } {{/methods}} From a342260c21895bdd79d437d5847fd2b0f8e9c938 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 12 Oct 2017 14:32:33 +0200 Subject: [PATCH 0455/2215] Fixed issue with linphone_jni.cc generation --- coreapi/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 6065c4a8f..f0a3bfdd6 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -114,6 +114,7 @@ set(LINPHONE_SOURCE_FILES_CXX set(LINPHONE_INCLUDE_DIRS ${LINPHONE_INCLUDE_DIRS}) if(ENABLE_JAVA_WRAPPER) list(APPEND LINPHONE_SOURCE_FILES_CXX ${LINPHONE_JNI_SOURCES}) + set_source_files_properties(${LINPHONE_JNI_SOURCES} PROPERTIES GENERATED TRUE) endif() set(LINPHONE_SOURCE_FILES_OBJC) From 8735c553eb8b200c0375e32c1be64ad8f9e88c08 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 12 Oct 2017 14:41:55 +0200 Subject: [PATCH 0456/2215] Added install step of generated java files --- wrappers/java/CMakeLists.txt | 5 ++++- wrappers/java/genwrapper.py | 6 ------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/wrappers/java/CMakeLists.txt b/wrappers/java/CMakeLists.txt index 78c6a1e1a..7dcb317fb 100644 --- a/wrappers/java/CMakeLists.txt +++ b/wrappers/java/CMakeLists.txt @@ -38,4 +38,7 @@ add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/src/linphone_jni.cc" add_custom_target(linphonej ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/src/linphone_jni.cc") -set(LINPHONE_JNI_SOURCES "${CMAKE_CURRENT_BINARY_DIR}/src/linphone_jni.cc" PARENT_SCOPE) \ No newline at end of file +set(LINPHONE_JNI_SOURCES "${CMAKE_CURRENT_BINARY_DIR}/src/linphone_jni.cc" PARENT_SCOPE) + +install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/java" DESTINATION "${CMAKE_INSTALL_DATADIR}/linphonej/") +install(DIRECTORY classes/ DESTINATION "${CMAKE_INSTALL_DATADIR}/linphonej/java/org/linphone/core/" FILES_MATCHING PATTERN "*.java") \ No newline at end of file diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 256e17ef0..7ad4279d1 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -800,7 +800,6 @@ class GenWrapper(object): ########################################################################## def main(): - import shutil argparser = argparse.ArgumentParser(description='Generate source files for the Java wrapper') argparser.add_argument('xmldir', type=str, help='Directory where the XML documentation of the Linphone\'s API generated by Doxygen is placed') argparser.add_argument('-o --output', type=str, help='the directory where to generate the source files', dest='outputdir', default='.') @@ -831,10 +830,5 @@ def main(): genwrapper = GenWrapper(srcdir, javadir, args.package, args.xmldir) genwrapper.render_all() - for f in os.listdir('./classes'): - src = os.path.join('./classes', f) - tgt = os.path.join(javadir, f) - shutil.copy(src, tgt) - if __name__ == '__main__': main() From d1c80c1ec9ded9b524527bbe055c5a07b8e33b7d Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 12 Oct 2017 12:00:45 +0200 Subject: [PATCH 0457/2215] fix(ChatRoom): remove useless includes --- src/chat/chat-room/basic-chat-room-p.h | 3 --- src/chat/chat-room/chat-room-p.h | 21 +++++++------------ src/chat/chat-room/chat-room.cpp | 8 +------ src/chat/chat-room/chat-room.h | 20 +++++------------- src/chat/chat-room/client-group-chat-room-p.h | 7 +------ src/chat/chat-room/client-group-chat-room.cpp | 6 +----- src/chat/chat-room/client-group-chat-room.h | 6 ------ .../chat-room/real-time-text-chat-room-p.h | 10 ++++----- .../chat-room/real-time-text-chat-room.cpp | 8 ++----- src/chat/chat-room/real-time-text-chat-room.h | 5 ----- .../multipart-chat-message-modifier.cpp | 3 +++ tester/cpim-tester.cpp | 3 ++- tester/multipart-tester.cpp | 3 ++- 13 files changed, 30 insertions(+), 73 deletions(-) diff --git a/src/chat/chat-room/basic-chat-room-p.h b/src/chat/chat-room/basic-chat-room-p.h index 698996b18..12b4b986b 100644 --- a/src/chat/chat-room/basic-chat-room-p.h +++ b/src/chat/chat-room/basic-chat-room-p.h @@ -20,9 +20,6 @@ #ifndef _BASIC_CHAT_ROOM_P_H_ #define _BASIC_CHAT_ROOM_P_H_ -// From coreapi. -#include "private.h" - #include "basic-chat-room.h" #include "chat/chat-room/chat-room-p.h" diff --git a/src/chat/chat-room/chat-room-p.h b/src/chat/chat-room/chat-room-p.h index e07889fe3..ee72788d5 100644 --- a/src/chat/chat-room/chat-room-p.h +++ b/src/chat/chat-room/chat-room-p.h @@ -20,15 +20,8 @@ #ifndef _CHAT_ROOM_P_H_ #define _CHAT_ROOM_P_H_ -#include "linphone/enums/chat-room-enums.h" -#include "linphone/utils/enum-generator.h" - -// From coreapi. -#include "private.h" - -#include "chat-room.h" -#include "chat/is-composing-listener.h" #include "chat/is-composing.h" +#include "chat-room.h" #include "object/object-p.h" // ============================================================================= @@ -37,6 +30,7 @@ LINPHONE_BEGIN_NAMESPACE class ChatRoomPrivate : public ObjectPrivate, public IsComposingListener { friend class ChatMessagePrivate; + public: ChatRoomPrivate (LinphoneCore *core); virtual ~ChatRoomPrivate (); @@ -47,9 +41,10 @@ private: public: void addTransientMessage (const std::shared_ptr &msg); void addWeakMessage (const std::shared_ptr &msg); - std::list > getTransientMessages () const { + std::list> getTransientMessages () const { return transientMessages; } + void moveTransientMessageToWeakMessages (const std::shared_ptr &msg); void removeTransientMessage (const std::shared_ptr &msg); @@ -69,7 +64,7 @@ protected: std::shared_ptr getWeakMessage (unsigned int storageId) const; int sqlRequest (sqlite3 *db, const std::string &stmt); void sqlRequestMessage (sqlite3 *db, const std::string &stmt); - std::list > findMessages (const std::string &messageId); + std::list> findMessages (const std::string &messageId); void storeOrUpdateMessage (const std::shared_ptr &msg); public: @@ -100,9 +95,9 @@ public: int unreadCount = -1; bool isComposing = false; bool remoteIsComposing = false; - std::list > messages; - std::list > transientMessages; - std::list > weakMessages; + std::list> messages; + std::list> transientMessages; + std::list> weakMessages; std::list receivedRttCharacters; std::shared_ptr pendingMessage = nullptr; IsComposing isComposingHandler; diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 2e759970d..f12b60850 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -19,16 +19,10 @@ #include -#include "linphone/api/c-chat-message.h" -#include "linphone/utils/utils.h" - #include "c-wrapper/c-wrapper.h" +#include "chat/chat-message/chat-message-p.h" #include "chat/chat-room/chat-room-p.h" #include "chat/imdn.h" -#include "content/content.h" -#include "chat/chat-message/chat-message-p.h" -#include "chat-room.h" -#include "sal/message-op.h" #include "logger/logger.h" // ============================================================================= diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index 84c48911d..d09203199 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -20,18 +20,8 @@ #ifndef _CHAT_ROOM_H_ #define _CHAT_ROOM_H_ -#include - -// From coreapi -#include "private.h" - -#include "address/address.h" -#include "object/object.h" -#include "conference/conference-interface.h" - #include "chat/chat-message/chat-message.h" - -#include "linphone/types.h" +#include "conference/conference-interface.h" // ============================================================================= @@ -60,18 +50,18 @@ public: std::shared_ptr createMessage (); void deleteHistory (); void deleteMessage (const std::shared_ptr &msg); - std::shared_ptr findMessage (const std::string& messageId); + std::shared_ptr findMessage (const std::string &messageId); std::shared_ptr findMessageWithDirection (const std::string &messageId, ChatMessage::Direction direction); - std::list > getHistory (int nbMessages); + std::list> getHistory (int nbMessages); int getHistorySize (); - std::list > getHistoryRange (int startm, int endm); + std::list> getHistoryRange (int startm, int endm); int getUnreadMessagesCount (); bool isRemoteComposing () const; void markAsRead (); LinphoneCore *getCore () const; - const Address& getPeerAddress () const; + const Address &getPeerAddress () const; State getState () const; protected: diff --git a/src/chat/chat-room/client-group-chat-room-p.h b/src/chat/chat-room/client-group-chat-room-p.h index 4b8885e85..ef874027d 100644 --- a/src/chat/chat-room/client-group-chat-room-p.h +++ b/src/chat/chat-room/client-group-chat-room-p.h @@ -20,18 +20,13 @@ #ifndef _CLIENT_GROUP_CHAT_ROOM_P_H_ #define _CLIENT_GROUP_CHAT_ROOM_P_H_ -// From coreapi. -#include "private.h" - -#include "client-group-chat-room.h" #include "chat/chat-room/chat-room-p.h" +#include "client-group-chat-room.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE -class CallSession; - class ClientGroupChatRoomPrivate : public ChatRoomPrivate { public: ClientGroupChatRoomPrivate (LinphoneCore *core); diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index a32d9b094..a1de405f0 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -22,11 +22,8 @@ #include "address/address-p.h" #include "client-group-chat-room-p.h" #include "c-wrapper/c-wrapper.h" -#include "conference/params/call-session-params-p.h" #include "conference/session/call-session-p.h" #include "conference/participant-p.h" -#include "content/content.h" -#include "hacks/hacks.h" #include "logger/logger.h" #include "sal/refer-op.h" @@ -36,8 +33,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core) - : ChatRoomPrivate(core) {} +ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core) : ChatRoomPrivate(core) {} // ----------------------------------------------------------------------------- diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 5801d3ffb..b97156cd2 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -20,14 +20,8 @@ #ifndef _CLIENT_GROUP_CHAT_ROOM_H_ #define _CLIENT_GROUP_CHAT_ROOM_H_ -// From coreapi -#include "private.h" - #include "chat/chat-room/chat-room.h" #include "conference/remote-conference.h" -#include "conference/session/call-session.h" - -#include "linphone/types.h" // ============================================================================= diff --git a/src/chat/chat-room/real-time-text-chat-room-p.h b/src/chat/chat-room/real-time-text-chat-room-p.h index f70a16f2d..e99f3b8ad 100644 --- a/src/chat/chat-room/real-time-text-chat-room-p.h +++ b/src/chat/chat-room/real-time-text-chat-room-p.h @@ -20,11 +20,8 @@ #ifndef _REAL_TIME_TEXT_CHAT_ROOM_P_H_ #define _REAL_TIME_TEXT_CHAT_ROOM_P_H_ -// From coreapi. -#include "private.h" - -#include "chat/chat-room/real-time-text-chat-room.h" #include "chat/chat-room/chat-room-p.h" +#include "chat/chat-room/real-time-text-chat-room.h" // ============================================================================= @@ -36,7 +33,10 @@ public: virtual ~RealTimeTextChatRoomPrivate (); public: - void setCall (LinphoneCall *call) { this->call = call; } + void setCall (LinphoneCall *call) { + this->call = call; + } + void realtimeTextReceived (uint32_t character, LinphoneCall *call); void sendMessage (const std::shared_ptr &msg) override; diff --git a/src/chat/chat-room/real-time-text-chat-room.cpp b/src/chat/chat-room/real-time-text-chat-room.cpp index 212fc9d19..1aa4a4693 100644 --- a/src/chat/chat-room/real-time-text-chat-room.cpp +++ b/src/chat/chat-room/real-time-text-chat-room.cpp @@ -17,14 +17,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include - -#include "linphone/utils/utils.h" - -#include "real-time-text-chat-room-p.h" -#include "chat/chat-message/chat-message-p.h" #include "c-wrapper/c-wrapper.h" +#include "chat/chat-message/chat-message-p.h" #include "logger/logger.h" +#include "real-time-text-chat-room-p.h" // ============================================================================= diff --git a/src/chat/chat-room/real-time-text-chat-room.h b/src/chat/chat-room/real-time-text-chat-room.h index 0dc3f6482..e8d7c919f 100644 --- a/src/chat/chat-room/real-time-text-chat-room.h +++ b/src/chat/chat-room/real-time-text-chat-room.h @@ -20,13 +20,8 @@ #ifndef _REAL_TIME_TEXT_CHAT_ROOM_H_ #define _REAL_TIME_TEXT_CHAT_ROOM_H_ -// From coreapi -#include "private.h" - #include "chat/chat-room/chat-room.h" -#include "linphone/types.h" - // ============================================================================= LINPHONE_BEGIN_NAMESPACE diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index e9c2cd2c3..10eb02133 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -17,6 +17,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +// TODO: Remove me later. +#include "private.h" + #include "address/address.h" #include "chat/chat-message/chat-message.h" #include "chat/chat-room/chat-room.h" diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index 26e9a5a4d..2b486a58f 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -17,10 +17,11 @@ */ #include "address/address.h" -#include "chat/chat-room/basic-chat-room.h" #include "chat/chat-message/chat-message.h" +#include "chat/chat-room/basic-chat-room.h" #include "chat/cpim/cpim.h" #include "content/content-type.h" +#include "content/content.h" #include "liblinphone_tester.h" diff --git a/tester/multipart-tester.cpp b/tester/multipart-tester.cpp index b40687c25..29a6544cb 100644 --- a/tester/multipart-tester.cpp +++ b/tester/multipart-tester.cpp @@ -17,9 +17,10 @@ */ #include "address/address.h" -#include "chat/chat-room/basic-chat-room.h" #include "chat/chat-message/chat-message.h" +#include "chat/chat-room/basic-chat-room.h" #include "content/content-type.h" +#include "content/content.h" #include "liblinphone_tester.h" From 006ecf4d76ee5e3e3fc820c7fa9f06e37dc42744 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 12 Oct 2017 16:54:47 +0200 Subject: [PATCH 0458/2215] feat(Conference): hide private attributes of Conference classes (feat Benjamin Reis aka Ben Rei Jeb) --- coreapi/callbacks.c | 5 +- include/linphone/utils/general.h | 7 + include/linphone/utils/utils.h | 10 ++ src/CMakeLists.txt | 3 + src/c-wrapper/api/c-chat-room.cpp | 10 +- src/call/call-p.h | 2 + src/chat/chat-room/basic-chat-room.cpp | 7 +- src/chat/chat-room/basic-chat-room.h | 2 +- src/chat/chat-room/client-group-chat-room.cpp | 108 +++++++----- src/chat/chat-room/client-group-chat-room.h | 4 +- .../chat-room/real-time-text-chat-room.cpp | 5 +- src/chat/chat-room/real-time-text-chat-room.h | 2 +- src/conference/conference-interface.h | 10 +- src/conference/conference-listener.h | 7 +- src/conference/conference-p.h | 59 +++++++ src/conference/conference.cpp | 162 +++++++++++------- src/conference/conference.h | 35 ++-- .../local-conference-event-handler.cpp | 16 +- src/conference/local-conference-p.h | 41 +++++ src/conference/local-conference.cpp | 34 ++-- src/conference/local-conference.h | 11 +- .../remote-conference-event-handler-p.h | 9 +- src/conference/remote-conference-p.h | 43 +++++ src/conference/remote-conference.cpp | 45 ++--- src/conference/remote-conference.h | 14 +- tester/conference-event-tester.cpp | 109 ++++++------ tester/tools/tester.h | 6 +- 27 files changed, 508 insertions(+), 258 deletions(-) create mode 100644 src/conference/conference-p.h create mode 100644 src/conference/local-conference-p.h create mode 100644 src/conference/remote-conference-p.h diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index e21544b49..b1dd16297 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -40,10 +40,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" #include "call/call-p.h" #include "chat/chat-room/chat-room.h" -#include "conference/session/call-session.h" +#include "conference/participant.h" #include "conference/session/call-session-p.h" -#include "conference/session/media-session.h" +#include "conference/session/call-session.h" #include "conference/session/media-session-p.h" +#include "conference/session/media-session.h" using namespace LinphonePrivate; diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index 495d72ee1..8e9e5d146 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -117,6 +117,13 @@ class ObjectPrivate; friend class Tester; #endif +// Generic public helper. (Neither ClonableObject nor Object.) +// `void *` is used to avoid downcasting. +template +constexpr T *getPublicHelper (void *object, const void *) { + return static_cast(object); +} + template inline T *getPublicHelper (const U *map, const ClonableObjectPrivate *context) { auto it = map->find(context); diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h index c2f5d19df..6f5569192 100644 --- a/include/linphone/utils/utils.h +++ b/include/linphone/utils/utils.h @@ -42,6 +42,16 @@ namespace Utils { return object.get(); } + template + LINPHONE_PUBLIC constexpr T *getPtr (std::unique_ptr &object) { + return object.get(); + } + + template + LINPHONE_PUBLIC constexpr T *getPtr (const std::unique_ptr &object) { + return object.get(); + } + template LINPHONE_PUBLIC constexpr T *getPtr (T *object) { return object; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6a596c879..692371a06 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,9 +54,11 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES chat/modifier/encryption-chat-message-modifier.h chat/modifier/multipart-chat-message-modifier.h conference/conference-listener.h + conference/conference-p.h conference/conference.h conference/local-conference-event-handler-p.h conference/local-conference-event-handler.h + conference/local-conference-p.h conference/local-conference.h conference/params/call-session-params-p.h conference/params/call-session-params.h @@ -67,6 +69,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES conference/participant.h conference/remote-conference-event-handler-p.h conference/remote-conference-event-handler.h + conference/remote-conference-p.h conference/remote-conference.h conference/session/call-session-listener.h conference/session/call-session-p.h diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 89e668ee5..f92827208 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -230,12 +230,12 @@ LinphoneParticipant *linphone_chat_room_find_participant (const LinphoneChatRoom } const LinphoneAddress *linphone_chat_room_get_conference_address (const LinphoneChatRoom *cr) { - if (cr->conferenceAddressCache) { + if (cr->conferenceAddressCache) linphone_address_unref(cr->conferenceAddressCache); - } - auto addr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getConferenceAddress(); - if (addr) - cr->conferenceAddressCache = linphone_address_new(addr->asString().c_str()); + + const LinphonePrivate::Address &address = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getConferenceAddress(); + if (address.isValid()) + cr->conferenceAddressCache = linphone_address_new(address.asString().c_str()); else cr->conferenceAddressCache = nullptr; return cr->conferenceAddressCache; diff --git a/src/call/call-p.h b/src/call/call-p.h index 1bc0c420c..5c75fa610 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -20,10 +20,12 @@ #ifndef _CALL_P_H_ #define _CALL_P_H_ +#include "call-listener.h" #include "call.h" #include "conference/conference.h" #include "object/object-p.h" +// TODO: Remove me later. #include "private.h" // ============================================================================= diff --git a/src/chat/chat-room/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp index 2814a253d..c439570fe 100644 --- a/src/chat/chat-room/basic-chat-room.cpp +++ b/src/chat/chat-room/basic-chat-room.cpp @@ -17,7 +17,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "linphone/utils/utils.h" + #include "basic-chat-room-p.h" +#include "conference/participant.h" #include "logger/logger.h" // ============================================================================= @@ -57,9 +60,9 @@ shared_ptr BasicChatRoom::findParticipant (const Address &addr) con return nullptr; } -const Address *BasicChatRoom::getConferenceAddress () const { +const Address &BasicChatRoom::getConferenceAddress () const { lError() << "a BasicChatRoom does not have a conference address"; - return nullptr; + return Utils::getEmptyConstRefObject
    (); } int BasicChatRoom::getNbParticipants () const { diff --git a/src/chat/chat-room/basic-chat-room.h b/src/chat/chat-room/basic-chat-room.h index d6b64d9a6..9e8bf1f72 100644 --- a/src/chat/chat-room/basic-chat-room.h +++ b/src/chat/chat-room/basic-chat-room.h @@ -40,7 +40,7 @@ public: void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; bool canHandleParticipants () const override; std::shared_ptr findParticipant (const Address &addr) const override; - const Address *getConferenceAddress () const override; + const Address &getConferenceAddress () const override; int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index a1de405f0..22ed84b38 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -20,10 +20,12 @@ #include "linphone/utils/utils.h" #include "address/address-p.h" -#include "client-group-chat-room-p.h" #include "c-wrapper/c-wrapper.h" -#include "conference/session/call-session-p.h" +#include "client-group-chat-room-p.h" #include "conference/participant-p.h" +#include "conference/remote-conference-event-handler.h" +#include "conference/remote-conference-p.h" +#include "conference/session/call-session-p.h" #include "logger/logger.h" #include "sal/refer-op.h" @@ -39,12 +41,17 @@ ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core) : Ch shared_ptr ClientGroupChatRoomPrivate::createSession () { L_Q(); + CallSessionParams csp; csp.addCustomHeader("Require", "recipient-list-invite"); - shared_ptr session = q->focus->getPrivate()->createSession(*q, &csp, false, q); - session->configure(LinphoneCallOutgoing, nullptr, nullptr, q->me->getAddress(), q->focus->getAddress()); + + shared_ptr focus = static_cast(q)->getPrivate()->focus; + shared_ptr session = focus->getPrivate()->createSession(*q, &csp, false, q); + const Address &myAddress = q->getMe()->getAddress(); + session->configure(LinphoneCallOutgoing, nullptr, nullptr, myAddress, focus->getAddress()); session->initiateOutgoing(); - Address addr = q->me->getAddress(); + + Address addr = myAddress; addr.setParam("text"); session->getPrivate()->getOp()->set_contact_address(addr.getPrivate()->getInternalAddress()); return session; @@ -52,15 +59,16 @@ shared_ptr ClientGroupChatRoomPrivate::createSession () { void ClientGroupChatRoomPrivate::notifyReceived (string body) { L_Q(); - q->eventHandler->notifyReceived(body); + static_cast(q)->getPrivate()->eventHandler->notifyReceived(body); } // ============================================================================= ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, const string &uri, const string &subject) : ChatRoom(*new ClientGroupChatRoomPrivate(core)), RemoteConference(core, me, nullptr) { - focus = ObjectFactory::create(Address(uri)); - this->subject = subject; + static_cast(Conference::mPrivate)->focus = + ObjectFactory::create(Address(uri)); + setSubject(subject); } int ClientGroupChatRoom::getCapabilities () const { @@ -75,28 +83,33 @@ void ClientGroupChatRoom::addParticipant (const Address &addr, const CallSession void ClientGroupChatRoom::addParticipants (const list
    &addresses, const CallSessionParams *params, bool hasMedia) { L_D(); + if (addresses.empty()) return; + if ((d->state != ChatRoom::State::Instantiated) && (d->state != ChatRoom::State::Created)) { lError() << "Cannot add participants to the ClientGroupChatRoom in a state other than Instantiated or Created"; return; } + list
    sortedAddresses(addresses); sortedAddresses.sort(); sortedAddresses.unique(); + Content content; content.setBody(getResourceLists(sortedAddresses)); content.setContentType("application/resource-lists+xml"); content.setContentDisposition("recipient-list"); - shared_ptr session = focus->getPrivate()->getSession(); + + shared_ptr session = + static_cast(Conference::mPrivate)->focus->getPrivate()->getSession(); if (session) - session->update(nullptr, subject, &content); + session->update(nullptr, getSubject(), &content); else { session = d->createSession(); - session->startInvite(nullptr, subject, &content); - if (d->state == ChatRoom::State::Instantiated) { + session->startInvite(nullptr, getSubject(), &content); + if (d->state == ChatRoom::State::Instantiated) d->setState(ChatRoom::State::CreationPending); - } } } @@ -108,7 +121,7 @@ shared_ptr ClientGroupChatRoom::findParticipant (const Address &add return RemoteConference::findParticipant(addr); } -const Address *ClientGroupChatRoom::getConferenceAddress () const { +const Address &ClientGroupChatRoom::getConferenceAddress () const { return RemoteConference::getConferenceAddress(); } @@ -126,7 +139,8 @@ const string &ClientGroupChatRoom::getSubject () const { void ClientGroupChatRoom::join () { L_D(); - shared_ptr session = focus->getPrivate()->getSession(); + shared_ptr session = + static_cast(Conference::mPrivate)->focus->getPrivate()->getSession(); if (!session && (d->state == ChatRoom::State::Instantiated)) { session = d->createSession(); session->startInvite(nullptr, "", nullptr); @@ -136,21 +150,26 @@ void ClientGroupChatRoom::join () { void ClientGroupChatRoom::leave () { L_D(); - eventHandler->unsubscribe(); - shared_ptr session = focus->getPrivate()->getSession(); + + RemoteConferencePrivate *conferencePrivate = + static_cast(Conference::mPrivate); + conferencePrivate->eventHandler->unsubscribe(); + + shared_ptr session = conferencePrivate->focus->getPrivate()->getSession(); if (session) session->terminate(); else { session = d->createSession(); session->startInvite(nullptr, "", nullptr); } + d->setState(ChatRoom::State::TerminationPending); } void ClientGroupChatRoom::removeParticipant (const shared_ptr &participant) { L_D(); SalReferOp *referOp = new SalReferOp(d->core->sal); - LinphoneAddress *lAddr = linphone_address_new(conferenceAddress.asString().c_str()); + LinphoneAddress *lAddr = linphone_address_new(getConferenceAddress().asString().c_str()); linphone_configure_op(d->core, referOp, lAddr, nullptr, false); linphone_address_unref(lAddr); Address referToAddr = participant->getAddress(); @@ -168,14 +187,17 @@ void ClientGroupChatRoom::removeParticipants (const list void ClientGroupChatRoom::setParticipantAdminStatus (shared_ptr &participant, bool isAdmin) { L_D(); + if (isAdmin == participant->isAdmin()) return; - if (!me->isAdmin()) { + + if (!getMe()->isAdmin()) { lError() << "Cannot change the participant admin status because I am not admin"; return; } + SalReferOp *referOp = new SalReferOp(d->core->sal); - LinphoneAddress *lAddr = linphone_address_new(conferenceAddress.asString().c_str()); + LinphoneAddress *lAddr = linphone_address_new(getConferenceAddress().asString().c_str()); linphone_configure_op(d->core, referOp, lAddr, nullptr, false); linphone_address_unref(lAddr); Address referToAddr = participant->getAddress(); @@ -189,15 +211,19 @@ void ClientGroupChatRoom::setParticipantAdminStatus (shared_ptr &pa void ClientGroupChatRoom::setSubject (const string &subject) { L_D(); + if (d->state != ChatRoom::State::Created) { lError() << "Cannot change the ClientGroupChatRoom subject in a state other than Created"; return; } - if (!me->isAdmin()) { + + if (!getMe()->isAdmin()) { lError() << "Cannot change the ClientGroupChatRoom subject because I am not admin"; return; } - shared_ptr session = focus->getPrivate()->getSession(); + + shared_ptr session = + static_cast(Conference::mPrivate)->focus->getPrivate()->getSession(); if (session) session->update(nullptr, subject); else { @@ -210,7 +236,7 @@ void ClientGroupChatRoom::setSubject (const string &subject) { void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { L_D(); - conferenceAddress = addr; + static_cast(Conference::mPrivate)->conferenceAddress = addr; d->setState(ChatRoom::State::Created); _linphone_core_add_group_chat_room(d->core, addr, L_GET_C_BACK_PTR(this)); } @@ -223,13 +249,15 @@ void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { void ClientGroupChatRoom::onParticipantAdded (const Address &addr) { if (isMe(addr)) return; + shared_ptr participant = findParticipant(addr); if (participant) { lWarning() << "Participant " << participant << " added but already in the list of participants!"; return; } + participant = ObjectFactory::create(addr); - participants.push_back(participant); + RemoteConference::mPrivate->participants.push_back(participant); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAddedCb cb = linphone_chat_room_cbs_get_participant_added(cbs); @@ -248,13 +276,13 @@ void ClientGroupChatRoom::onParticipantRemoved (const Address &addr) { LinphoneChatRoomCbsParticipantRemovedCb cb = linphone_chat_room_cbs_get_participant_removed(cbs); if (cb) cb(cr, L_GET_C_BACK_PTR(participant)); - participants.remove(participant); + RemoteConference::mPrivate->participants.remove(participant); } void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdmin) { shared_ptr participant; if (isMe(addr)) - participant = me; + participant = getMe(); else participant = findParticipant(addr); if (!participant) { @@ -270,7 +298,7 @@ void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdm } void ClientGroupChatRoom::onSubjectChanged (const std::string &subject) { - this->subject = subject; + setSubject(subject); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsSubjectChangedCb cb = linphone_chat_room_cbs_get_subject_changed(cbs); @@ -281,7 +309,7 @@ void ClientGroupChatRoom::onSubjectChanged (const std::string &subject) { void ClientGroupChatRoom::onParticipantDeviceAdded (const Address &addr, const Address &gruu) { shared_ptr participant; if (isMe(addr)) - participant = me; + participant = getMe(); else participant = findParticipant(addr); if (!participant) { @@ -294,7 +322,7 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (const Address &addr, const A void ClientGroupChatRoom::onParticipantDeviceRemoved (const Address &addr, const Address &gruu) { shared_ptr participant; if (isMe(addr)) - participant = me; + participant = getMe(); else participant = findParticipant(addr); if (!participant) { @@ -307,8 +335,11 @@ void ClientGroupChatRoom::onParticipantDeviceRemoved (const Address &addr, const // ----------------------------------------------------------------------------- void ClientGroupChatRoom::onCallSessionSetReleased (const std::shared_ptr &session) { - if (session == focus->getPrivate()->getSession()) - focus->getPrivate()->removeSession(); + ParticipantPrivate *participantPrivate = + static_cast(Conference::mPrivate)->focus->getPrivate(); + + if (session == participantPrivate->getSession()) + participantPrivate->removeSession(); } void ClientGroupChatRoom::onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const string &message) { @@ -319,14 +350,13 @@ void ClientGroupChatRoom::onCallSessionStateChanged (const std::shared_ptrgetRemoteContactAddress()->hasParam("isfocus")) - eventHandler->subscribe(conferenceAddress); - } else if (d->state == ChatRoom::State::TerminationPending) { - focus->getPrivate()->getSession()->terminate(); - } - } else { - if ((state == LinphoneCallReleased) && (d->state == ChatRoom::State::TerminationPending)) - onConferenceTerminated(conferenceAddress); - } + static_cast(Conference::mPrivate)->eventHandler->subscribe( + getConferenceAddress() + ); + } else if (d->state == ChatRoom::State::TerminationPending) + static_cast(Conference::mPrivate)->focus->getPrivate()->getSession()->terminate(); + } else if ((state == LinphoneCallReleased) && (d->state == ChatRoom::State::TerminationPending)) + onConferenceTerminated(getConferenceAddress()); } LINPHONE_END_NAMESPACE diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index b97156cd2..0d9432ccb 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -41,7 +41,7 @@ public: void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; bool canHandleParticipants () const override; std::shared_ptr findParticipant (const Address &addr) const override; - const Address *getConferenceAddress () const override; + const Address &getConferenceAddress () const override; int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; @@ -69,7 +69,7 @@ private: void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) override; private: - L_DECLARE_PRIVATE(ClientGroupChatRoom); + L_DECLARE_PRIVATE_T(ClientGroupChatRoom, ChatRoom); L_DISABLE_COPY(ClientGroupChatRoom); }; diff --git a/src/chat/chat-room/real-time-text-chat-room.cpp b/src/chat/chat-room/real-time-text-chat-room.cpp index 1aa4a4693..705fc0172 100644 --- a/src/chat/chat-room/real-time-text-chat-room.cpp +++ b/src/chat/chat-room/real-time-text-chat-room.cpp @@ -19,6 +19,7 @@ #include "c-wrapper/c-wrapper.h" #include "chat/chat-message/chat-message-p.h" +#include "conference/participant.h" #include "logger/logger.h" #include "real-time-text-chat-room-p.h" @@ -150,9 +151,9 @@ shared_ptr RealTimeTextChatRoom::findParticipant (const Address &ad return nullptr; } -const Address *RealTimeTextChatRoom::getConferenceAddress () const { +const Address &RealTimeTextChatRoom::getConferenceAddress () const { lError() << "a RealTimeTextChatRoom does not have a conference address"; - return nullptr; + return Utils::getEmptyConstRefObject
    (); } int RealTimeTextChatRoom::getNbParticipants () const { diff --git a/src/chat/chat-room/real-time-text-chat-room.h b/src/chat/chat-room/real-time-text-chat-room.h index e8d7c919f..01a84035d 100644 --- a/src/chat/chat-room/real-time-text-chat-room.h +++ b/src/chat/chat-room/real-time-text-chat-room.h @@ -43,7 +43,7 @@ public: void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; bool canHandleParticipants () const override; std::shared_ptr findParticipant (const Address &addr) const override; - const Address *getConferenceAddress () const override; + const Address &getConferenceAddress () const override; int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index 443181f26..42bdca4e2 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -23,14 +23,16 @@ #include #include -#include "address/address.h" -#include "conference/participant.h" -#include "conference/params/call-session-params.h" +#include "linphone/utils/general.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE +class Address; +class CallSessionParams; +class Participant; + class LINPHONE_PUBLIC ConferenceInterface { public: virtual ~ConferenceInterface() = default; @@ -39,7 +41,7 @@ public: virtual void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) = 0; virtual bool canHandleParticipants () const = 0; virtual std::shared_ptr findParticipant (const Address &addr) const = 0; - virtual const Address *getConferenceAddress () const = 0; + virtual const Address &getConferenceAddress () const = 0; virtual int getNbParticipants () const = 0; virtual std::list> getParticipants () const = 0; virtual const std::string &getSubject () const = 0; diff --git a/src/conference/conference-listener.h b/src/conference/conference-listener.h index 34665bfbd..96c30528e 100644 --- a/src/conference/conference-listener.h +++ b/src/conference/conference-listener.h @@ -20,12 +20,16 @@ #ifndef _CONFERENCE_LISTENER_H_ #define _CONFERENCE_LISTENER_H_ -#include "address/address.h" +#include + +#include "linphone/utils/general.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE +class Address; + class ConferenceListener { public: virtual void onConferenceCreated (const Address &addr) = 0; @@ -41,4 +45,3 @@ public: LINPHONE_END_NAMESPACE #endif // ifndef _CONFERENCE_LISTENER_H_ - diff --git a/src/conference/conference-p.h b/src/conference/conference-p.h new file mode 100644 index 000000000..1b0421da4 --- /dev/null +++ b/src/conference/conference-p.h @@ -0,0 +1,59 @@ +/* + * conference-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CONFERENCE_P_H_ +#define _CONFERENCE_P_H_ + +#include +#include + +#include "linphone/types.h" + +#include "address/address.h" +#include "conference.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class CallListener; +class Participant; + +class ConferencePrivate { +public: + Address conferenceAddress; + std::list> participants; + +protected: + LinphoneCore *core = nullptr; + CallListener *callListener = nullptr; + + std::shared_ptr activeParticipant; + std::shared_ptr me; + std::string subject; + + Conference *mPublic = nullptr; + +private: + L_DECLARE_PUBLIC(Conference); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CONFERENCE_P_H_ diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 3ba9cf826..0d97d880f 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -17,27 +17,45 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "participant-p.h" - -#include "conference.h" +#include "call/call-listener.h" +#include "conference-p.h" #include "conference/session/call-session-p.h" #include "logger/logger.h" +#include "participant-p.h" + +// ============================================================================= using namespace std; LINPHONE_BEGIN_NAMESPACE -// ============================================================================= +Conference::Conference (ConferencePrivate &p, LinphoneCore *core, const Address &myAddress, CallListener *listener) : mPrivate(&p) { + L_D(); + d->mPublic = this; + d->core = core; + d->callListener = listener; + d->me = ObjectFactory::create(myAddress); +} -Conference::Conference (LinphoneCore *core, const Address &myAddress, CallListener *listener) - : core(core), callListener(listener) { - me = ObjectFactory::create(myAddress); +Conference::~Conference () { + delete mPrivate; } // ----------------------------------------------------------------------------- shared_ptr Conference::getActiveParticipant () const { - return activeParticipant; + L_D(); + return d->activeParticipant; +} + +shared_ptr Conference::getMe () const { + L_D(); + return d->me; +} + +LinphoneCore *Conference::getCore () const { + L_D(); + return d->core; } // ----------------------------------------------------------------------------- @@ -61,20 +79,24 @@ bool Conference::canHandleParticipants () const { return true; } -const Address *Conference::getConferenceAddress () const { - return &conferenceAddress; +const Address &Conference::getConferenceAddress () const { + L_D(); + return d->conferenceAddress; } int Conference::getNbParticipants () const { - return static_cast(participants.size()); + L_D(); + return static_cast(d->participants.size()); } list> Conference::getParticipants () const { - return participants; + L_D(); + return d->participants; } const string &Conference::getSubject () const { - return subject; + L_D(); + return d->subject; } void Conference::join () {} @@ -90,110 +112,132 @@ void Conference::removeParticipants (const list> &partic removeParticipant(p); } -void Conference::setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) { +void Conference::setParticipantAdminStatus (shared_ptr &participant, bool isAdmin) { lError() << "Conference class does not handle setParticipantAdminStatus() generically"; } void Conference::setSubject (const string &subject) { - this->subject = subject; + L_D(); + d->subject = subject; } // ----------------------------------------------------------------------------- -void Conference::onAckBeingSent (const std::shared_ptr &session, LinphoneHeaders *headers) { - if (callListener) - callListener->onAckBeingSent(headers); +void Conference::onAckBeingSent (const shared_ptr &session, LinphoneHeaders *headers) { + L_D(); + if (d->callListener) + d->callListener->onAckBeingSent(headers); } -void Conference::onAckReceived (const std::shared_ptr &session, LinphoneHeaders *headers) { - if (callListener) - callListener->onAckReceived(headers); +void Conference::onAckReceived (const shared_ptr &session, LinphoneHeaders *headers) { + L_D(); + if (d->callListener) + d->callListener->onAckReceived(headers); } -void Conference::onCallSessionAccepted (const std::shared_ptr &session) { - if (callListener) - callListener->onIncomingCallToBeAdded(); +void Conference::onCallSessionAccepted (const shared_ptr &session) { + L_D(); + if (d->callListener) + d->callListener->onIncomingCallToBeAdded(); } -void Conference::onCallSessionSetReleased (const std::shared_ptr &session) { - if (callListener) - callListener->onCallSetReleased(); +void Conference::onCallSessionSetReleased (const shared_ptr &session) { + L_D(); + if (d->callListener) + d->callListener->onCallSetReleased(); } -void Conference::onCallSessionSetTerminated (const std::shared_ptr &session) { - if (callListener) - callListener->onCallSetTerminated(); +void Conference::onCallSessionSetTerminated (const shared_ptr &session) { + L_D(); + if (d->callListener) + d->callListener->onCallSetTerminated(); } -void Conference::onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const string &message) { - if (callListener) - callListener->onCallStateChanged(state, message); +void Conference::onCallSessionStateChanged (const shared_ptr &session, LinphoneCallState state, const string &message) { + L_D(); + if (d->callListener) + d->callListener->onCallStateChanged(state, message); } -void Conference::onCheckForAcceptation (const std::shared_ptr &session) { - if (callListener) - callListener->onCheckForAcceptation(); +void Conference::onCheckForAcceptation (const shared_ptr &session) { + L_D(); + if (d->callListener) + d->callListener->onCheckForAcceptation(); } -void Conference::onIncomingCallSessionStarted (const std::shared_ptr &session) { - if (callListener) - callListener->onIncomingCallStarted(); +void Conference::onIncomingCallSessionStarted (const shared_ptr &session) { + L_D(); + if (d->callListener) + d->callListener->onIncomingCallStarted(); } -void Conference::onEncryptionChanged (const std::shared_ptr &session, bool activated, const string &authToken) { - if (callListener) - callListener->onEncryptionChanged(activated, authToken); +void Conference::onEncryptionChanged (const shared_ptr &session, bool activated, const string &authToken) { + L_D(); + if (d->callListener) + d->callListener->onEncryptionChanged(activated, authToken); } void Conference::onStatsUpdated (const LinphoneCallStats *stats) { - if (callListener) - callListener->onStatsUpdated(stats); + L_D(); + if (d->callListener) + d->callListener->onStatsUpdated(stats); } -void Conference::onResetCurrentSession (const std::shared_ptr &session) { - if (callListener) - callListener->onResetCurrentCall(); +void Conference::onResetCurrentSession (const shared_ptr &session) { + L_D(); + if (d->callListener) + d->callListener->onResetCurrentCall(); } -void Conference::onSetCurrentSession (const std::shared_ptr &session) { - if (callListener) - callListener->onSetCurrentCall(); +void Conference::onSetCurrentSession (const shared_ptr &session) { + L_D(); + if (d->callListener) + d->callListener->onSetCurrentCall(); } -void Conference::onFirstVideoFrameDecoded (const std::shared_ptr &session) { - if (callListener) - callListener->onFirstVideoFrameDecoded(); +void Conference::onFirstVideoFrameDecoded (const shared_ptr &session) { + L_D(); + if (d->callListener) + d->callListener->onFirstVideoFrameDecoded(); } -void Conference::onResetFirstVideoFrameDecoded (const std::shared_ptr &session) { - if (callListener) - callListener->onResetFirstVideoFrameDecoded(); +void Conference::onResetFirstVideoFrameDecoded (const shared_ptr &session) { + L_D(); + if (d->callListener) + d->callListener->onResetFirstVideoFrameDecoded(); } // ----------------------------------------------------------------------------- shared_ptr Conference::findParticipant (const Address &addr) const { + L_D(); + Address testedAddr = addr; testedAddr.setPort(0); - for (const auto &participant : participants) { + for (const auto &participant : d->participants) { Address participantAddr = participant->getAddress(); participantAddr.setPort(0); if (testedAddr.weakEqual(participantAddr)) return participant; } + return nullptr; } shared_ptr Conference::findParticipant (const shared_ptr &session) const { - for (const auto &participant : participants) { + L_D(); + + for (const auto &participant : d->participants) { if (participant->getPrivate()->getSession() == session) return participant; } + return nullptr; } bool Conference::isMe (const Address &addr) const { - Address cleanedMe = me->getAddress(); + L_D(); + Address cleanedMe = d->me->getAddress(); cleanedMe.setPort(0); Address cleanedAddr = addr; cleanedAddr.setPort(0); diff --git a/src/conference/conference.h b/src/conference/conference.h index cee450b11..b89117c25 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -22,39 +22,36 @@ #include "linphone/types.h" -#include "address/address.h" -#include "call/call-listener.h" #include "conference/conference-interface.h" -#include "conference/params/call-session-params.h" -#include "conference/participant.h" #include "conference/session/call-session-listener.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE +class CallListener; class CallSessionPrivate; +class ConferencePrivate; class LINPHONE_PUBLIC Conference : public ConferenceInterface, public CallSessionListener { friend class CallSessionPrivate; public: - virtual ~Conference() = default; + virtual ~Conference(); std::shared_ptr getActiveParticipant () const; - std::shared_ptr getMe () const { return me; } + std::shared_ptr getMe () const; - LinphoneCore * getCore () const { return core; } + LinphoneCore * getCore () const; std::shared_ptr findParticipant (const std::shared_ptr &session) const; -public: /* ConferenceInterface */ void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
    &addresses, const CallSessionParams *params, bool hasMedia) override; bool canHandleParticipants () const override; std::shared_ptr findParticipant (const Address &addr) const override; - const Address *getConferenceAddress () const override; + const Address &getConferenceAddress () const override; int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; @@ -83,21 +80,19 @@ private: void onResetFirstVideoFrameDecoded (const std::shared_ptr &session) override; protected: - explicit Conference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); + explicit Conference ( + ConferencePrivate &p, + LinphoneCore *core, + const Address &myAddress, + CallListener *listener = nullptr + ); - bool isMe (const Address &addr) const ; + bool isMe (const Address &addr) const; -protected: - LinphoneCore *core = nullptr; - CallListener *callListener = nullptr; - - std::shared_ptr activeParticipant; - std::shared_ptr me; - std::list> participants; - Address conferenceAddress; - std::string subject; + ConferencePrivate *mPrivate = nullptr; private: + L_DECLARE_PRIVATE(Conference); L_DISABLE_COPY(Conference); }; diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 59b67edaa..ff9b33167 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -78,7 +78,7 @@ string LocalConferenceEventHandlerPrivate::createNotify (ConferenceType confInfo } string LocalConferenceEventHandlerPrivate::createNotifyFullState () { - string entity = conf->getConferenceAddress()->asStringUriOnly(); + string entity = conf->getConferenceAddress().asStringUriOnly(); string subject = conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); UsersType users; @@ -112,7 +112,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyFullState () { } string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const Address &addr) { - string entity = conf->getConferenceAddress()->asStringUriOnly(); + string entity = conf->getConferenceAddress().asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -142,7 +142,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const A } string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved (const Address &addr) { - string entity = conf->getConferenceAddress()->asStringUriOnly(); + string entity = conf->getConferenceAddress().asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -156,7 +156,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved (const } string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined (const Address &addr, bool isAdmin) { - string entity = conf->getConferenceAddress()->asStringUriOnly(); + string entity = conf->getConferenceAddress().asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -173,7 +173,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined (const } string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged () { - string entity = conf->getConferenceAddress()->asStringUriOnly(); + string entity = conf->getConferenceAddress().asStringUriOnly(); string subject = conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); ConferenceDescriptionType confDescr = ConferenceDescriptionType(); @@ -184,7 +184,7 @@ string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged () { } string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceAdded (const Address &addr, const Address &gruu) { - string entity = conf->getConferenceAddress()->asStringUriOnly(); + string entity = conf->getConferenceAddress().asStringUriOnly(); string subject = conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); UsersType users; @@ -209,7 +209,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceAdded (c } string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceRemoved (const Address &addr, const Address &gruu) { - string entity = conf->getConferenceAddress()->asStringUriOnly(); + string entity = conf->getConferenceAddress().asStringUriOnly(); string subject = conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); UsersType users; @@ -237,7 +237,7 @@ void LocalConferenceEventHandlerPrivate::sendNotify (const string ¬ify, const LinphoneAddress *cAddr = linphone_address_new(addr.asString().c_str()); LinphoneEvent *lev = linphone_core_create_notify(core, cAddr, "conference"); // Fix the From header to put the chat room URI - lev->op->set_from(conf->getConferenceAddress()->asString().c_str()); + lev->op->set_from(conf->getConferenceAddress().asString().c_str()); linphone_address_unref(cAddr); doNotify(notify, lev); } diff --git a/src/conference/local-conference-p.h b/src/conference/local-conference-p.h new file mode 100644 index 000000000..def1a9111 --- /dev/null +++ b/src/conference/local-conference-p.h @@ -0,0 +1,41 @@ +/* + * local-conference-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _LOCAL_CONFERENCE_P_H_ +#define _LOCAL_CONFERENCE_P_H_ + +#include "conference-p.h" +#include "local-conference.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class LocalConferenceEventHandler; + +class LocalConferencePrivate : public ConferencePrivate { +private: + std::unique_ptr eventHandler; + + L_DECLARE_PUBLIC(LocalConference); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _LOCAL_CONFERENCE_P_H_ diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index a26a63832..872e6da9e 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -17,42 +17,41 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "local-conference.h" +#include "local-conference-event-handler.h" +#include "local-conference-p.h" #include "participant-p.h" #include "xml/resource-lists.h" +// ============================================================================= + using namespace std; -using namespace LinphonePrivate::Xsd::ResourceLists; LINPHONE_BEGIN_NAMESPACE -// ============================================================================= - LocalConference::LocalConference (LinphoneCore *core, const Address &myAddress, CallListener *listener) - : Conference(core, myAddress, listener) { - eventHandler = new LocalConferenceEventHandler(core, this); -} - -LocalConference::~LocalConference () { - delete eventHandler; + : Conference(*new LocalConferencePrivate, core, myAddress, listener) { + L_D(); + d->eventHandler.reset(new LocalConferenceEventHandler(core, this)); } // ----------------------------------------------------------------------------- void LocalConference::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { + L_D(); shared_ptr participant = findParticipant(addr); if (participant) return; participant = ObjectFactory::create(addr); - participants.push_back(participant); - if (!activeParticipant) - activeParticipant = participant; + d->participants.push_back(participant); + if (!d->activeParticipant) + d->activeParticipant = participant; } void LocalConference::removeParticipant (const shared_ptr &participant) { - for (const auto &p : participants) { + L_D(); + for (const auto &p : d->participants) { if (participant->getAddress() == p->getAddress()) { - participants.remove(p); + d->participants.remove(p); return; } } @@ -60,7 +59,10 @@ void LocalConference::removeParticipant (const shared_ptr &pa list
    LocalConference::parseResourceLists (string xmlBody) { istringstream data(xmlBody); - unique_ptr rl = LinphonePrivate::Xsd::ResourceLists::parseResourceLists(data, Xsd::XmlSchema::Flags::dont_validate); + unique_ptr rl = LinphonePrivate::Xsd::ResourceLists::parseResourceLists( + data, + Xsd::XmlSchema::Flags::dont_validate + ); list
    addresses = list
    (); for (const auto &l : rl->getList()) { for (const auto &entry : l.getEntry()) { diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h index 5fe1eabc7..0c425447a 100644 --- a/src/conference/local-conference.h +++ b/src/conference/local-conference.h @@ -21,30 +21,25 @@ #define _LOCAL_CONFERENCE_H_ #include "conference.h" -#include "local-conference-event-handler.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE +class LocalConferencePrivate; + class LocalConference : public Conference { public: LocalConference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); - virtual ~LocalConference(); - LocalConferenceEventHandler * getEventHandler() const { return eventHandler; } - -public: /* ConferenceInterface */ void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void removeParticipant (const std::shared_ptr &participant) override; std::list
    parseResourceLists (std::string xmlBody); -protected: - LocalConferenceEventHandler *eventHandler = nullptr; - private: + L_DECLARE_PRIVATE(LocalConference); L_DISABLE_COPY(LocalConference); }; diff --git a/src/conference/remote-conference-event-handler-p.h b/src/conference/remote-conference-event-handler-p.h index e89c454c1..776435e08 100644 --- a/src/conference/remote-conference-event-handler-p.h +++ b/src/conference/remote-conference-event-handler-p.h @@ -20,14 +20,19 @@ #ifndef _REMOTE_CONFERENCE_EVENT_HANDLER_P_H_ #define _REMOTE_CONFERENCE_EVENT_HANDLER_P_H_ +#include "address/address.h" #include "object/object-p.h" #include "remote-conference-event-handler.h" +// ============================================================================= + LINPHONE_BEGIN_NAMESPACE class RemoteConferenceEventHandlerPrivate : public ObjectPrivate { public: - inline unsigned int getLastNotify () const { return lastNotify; }; + inline unsigned int getLastNotify () const { + return lastNotify; + }; private: LinphoneCore *core = nullptr; @@ -41,4 +46,4 @@ private: LINPHONE_END_NAMESPACE -#endif // ifndef _REMOTE_CONFERENCE_EVENT_HANDLER_P_H_ \ No newline at end of file +#endif // ifndef _REMOTE_CONFERENCE_EVENT_HANDLER_P_H_ diff --git a/src/conference/remote-conference-p.h b/src/conference/remote-conference-p.h new file mode 100644 index 000000000..54c3a1ad5 --- /dev/null +++ b/src/conference/remote-conference-p.h @@ -0,0 +1,43 @@ +/* + * remote-conference-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _REMOTE_CONFERENCE_P_H_ +#define _REMOTE_CONFERENCE_P_H_ + +#include "conference-p.h" +#include "remote-conference.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class RemoteConferenceEventHandler; + +class RemoteConferencePrivate : public ConferencePrivate { +public: + std::shared_ptr focus; + std::unique_ptr eventHandler; + +private: + L_DECLARE_PUBLIC(RemoteConference); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _REMOTE_CONFERENCE_P_H_ diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index ef6e4dd0f..9fa0df9d0 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -17,57 +17,59 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "remote-conference.h" #include "participant-p.h" +#include "remote-conference-event-handler.h" +#include "remote-conference-p.h" #include "xml/resource-lists.h" -using namespace std; -using namespace LinphonePrivate::Xsd::ResourceLists; - -LINPHONE_BEGIN_NAMESPACE - // ============================================================================= +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + RemoteConference::RemoteConference (LinphoneCore *core, const Address &myAddress, CallListener *listener) - : Conference(core, myAddress, listener) { - eventHandler = new RemoteConferenceEventHandler(core, this); + : Conference(*new RemoteConferencePrivate, core, myAddress, listener) { + L_D(); + d->eventHandler.reset(new RemoteConferenceEventHandler(core, this)); } RemoteConference::~RemoteConference () { - eventHandler->unsubscribe(); - delete eventHandler; + L_D(); + d->eventHandler->unsubscribe(); } // ----------------------------------------------------------------------------- void RemoteConference::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { + L_D(); shared_ptr participant = findParticipant(addr); if (participant) return; participant = ObjectFactory::create(addr); participant->getPrivate()->createSession(*this, params, hasMedia, this); - participants.push_back(participant); - if (!activeParticipant) - activeParticipant = participant; + d->participants.push_back(participant); + if (!d->activeParticipant) + d->activeParticipant = participant; } void RemoteConference::removeParticipant (const shared_ptr &participant) { - for (const auto &p : participants) { + L_D(); + for (const auto &p : d->participants) { if (participant->getAddress() == p->getAddress()) { - participants.remove(p); + d->participants.remove(p); return; } } } - string RemoteConference::getResourceLists (const list
    &addresses) const { - ResourceLists rl = ResourceLists(); - ListType l = ListType(); + Xsd::ResourceLists::ResourceLists rl = Xsd::ResourceLists::ResourceLists(); + Xsd::ResourceLists::ListType l = Xsd::ResourceLists::ListType(); for (const auto &addr : addresses) { - EntryType entry = EntryType(addr.asStringUriOnly()); + Xsd::ResourceLists::EntryType entry = Xsd::ResourceLists::EntryType(addr.asStringUriOnly()); if (!addr.getDisplayName().empty()) - entry.setDisplayName(DisplayName(addr.getDisplayName())); + entry.setDisplayName(Xsd::ResourceLists::DisplayName(addr.getDisplayName())); l.getEntry().push_back(entry); } rl.getList().push_back(l); @@ -83,7 +85,8 @@ string RemoteConference::getResourceLists (const list
    &addresses) const void RemoteConference::onConferenceCreated (const Address &addr) {} void RemoteConference::onConferenceTerminated (const Address &addr) { - eventHandler->unsubscribe(); + L_D(); + d->eventHandler->unsubscribe(); } void RemoteConference::onParticipantAdded (const Address &addr) {} diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index 572873136..fb8b80ee8 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -20,22 +20,22 @@ #ifndef _REMOTE_CONFERENCE_H_ #define _REMOTE_CONFERENCE_H_ +#include "conference-listener.h" #include "conference.h" -#include "remote-conference-event-handler.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE +class RemoteConferencePrivate; + class LINPHONE_PUBLIC RemoteConference : public Conference, public ConferenceListener { + friend class ClientGroupChatRoomPrivate; + public: RemoteConference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); virtual ~RemoteConference(); -protected: - std::shared_ptr focus; - -public: /* ConferenceInterface */ void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void removeParticipant (const std::shared_ptr &participant) override; @@ -53,10 +53,8 @@ protected: void onParticipantDeviceAdded (const Address &addr, const Address &gruu) override; void onParticipantDeviceRemoved (const Address &addr, const Address &gruu) override; -protected: - RemoteConferenceEventHandler *eventHandler = nullptr; - private: + L_DECLARE_PRIVATE(RemoteConference); L_DISABLE_COPY(RemoteConference); }; diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index f4554e5a6..3c4876e6c 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -19,14 +19,15 @@ #include #include -#include "linphone/core.h" -#include "private.h" -#include "liblinphone_tester.h" #include "conference/conference-listener.h" -#include "conference/local-conference.h" #include "conference/local-conference-event-handler-p.h" +#include "conference/local-conference-p.h" +#include "conference/local-conference.h" #include "conference/participant-p.h" #include "conference/remote-conference-event-handler-p.h" +#include "liblinphone_tester.h" +#include "linphone/core.h" +#include "private.h" #include "tools/private-access.h" #include "tools/tester.h" @@ -431,14 +432,12 @@ static const char *participant_unadmined_notify = \ " "\ " "; - static const char *bobUri = "sip:bob@example.com"; static const char *aliceUri = "sip:alice@example.com"; static const char *frankUri = "sip:frank@example.com"; static const char *confUri = "sips:conf233@example.com"; -L_ENABLE_ATTR_ACCESS(RemoteConferenceEventHandlerPrivate, Address, confAddress); -L_ENABLE_ATTR_ACCESS(Conference, Address, conferenceAddress); +L_ENABLE_ATTR_ACCESS(LocalConferencePrivate, unique_ptr, eventHandler); class ConferenceEventTester : public ConferenceListener { public: @@ -518,8 +517,8 @@ void first_notify_parsing() { size_t size = strlen(first_notify) + strlen(confUri); char *notify = new char[size]; - RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); - L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; + const_cast
    (tester.handler->getConfAddress()) = addr; + snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -555,8 +554,7 @@ void first_notify_parsing_wrong_conf() { size_t size = strlen(first_notify) + strlen(confUri); char *notify = new char[size]; - RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); - L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; + const_cast
    (tester.handler->getConfAddress()) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -587,8 +585,7 @@ void participant_added_parsing() { size_t size2 = strlen(participant_added_notify) + strlen(confUri); char *notify_added = new char[size2]; - RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); - L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; + const_cast
    (tester.handler->getConfAddress()) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -633,8 +630,7 @@ void participant_not_added_parsing() { size_t size2 = strlen(participant_not_added_notify) + strlen(confUri); char *notify_not_added = new char[size2]; - RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); - L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; + const_cast
    (tester.handler->getConfAddress()) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -676,8 +672,7 @@ void participant_deleted_parsing() { size_t size2 = strlen(participant_deleted_notify) + strlen(confUri); char *notify_deleted = new char[size2]; - RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); - L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; + const_cast
    (tester.handler->getConfAddress()) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -719,8 +714,7 @@ void participant_admined_parsing() { size_t size2 = strlen(participant_admined_notify) + strlen(confUri); char *notify_admined = new char[size2]; - RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); - L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; + const_cast
    (tester.handler->getConfAddress()) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -761,8 +755,7 @@ void participant_unadmined_parsing() { size_t size2 = strlen(participant_unadmined_notify) + strlen(confUri); char *notify_unadmined = new char[size2]; - RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); - L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; + const_cast
    (tester.handler->getConfAddress()) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -813,12 +806,13 @@ void send_first_notify() { localConf.setSubject("A random test subject"); shared_ptr alice = localConf.findParticipant(aliceAddr); L_GET_PRIVATE(alice)->setAdmin(true); - LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); - L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; + LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE( + L_ATTR_GET(L_GET_PRIVATE(localConf), eventHandler) + ); + const_cast
    (localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); - RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); - L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; + const_cast
    (tester.handler->getConfAddress()) = addr; tester.handler->notifyReceived(notify); BC_ASSERT_STRING_EQUAL(tester.confSubject.c_str(), "A random test subject"); @@ -861,12 +855,13 @@ void send_added_notify() { localConf.addParticipant(aliceAddr, ¶ms, false); shared_ptr alice = localConf.findParticipant(aliceAddr); L_GET_PRIVATE(alice)->setAdmin(true); - LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); - L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; + LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE( + L_ATTR_GET(L_GET_PRIVATE(localConf), eventHandler) + ); + const_cast
    (localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); - RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); - L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; + const_cast
    (tester.handler->getConfAddress()) = addr; tester.handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); @@ -916,12 +911,13 @@ void send_removed_notify() { localConf.addParticipant(aliceAddr, ¶ms, false); shared_ptr alice = localConf.findParticipant(aliceAddr); L_GET_PRIVATE(alice)->setAdmin(true); - LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); - L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; + LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE( + L_ATTR_GET(L_GET_PRIVATE(localConf), eventHandler) + ); + const_cast
    (localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); - RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); - L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; + const_cast
    (tester.handler->getConfAddress()) = addr; tester.handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); @@ -968,11 +964,13 @@ void send_admined_notify() { localConf.addParticipant(aliceAddr, ¶ms, false); shared_ptr alice = localConf.findParticipant(aliceAddr); L_GET_PRIVATE(alice)->setAdmin(true); - LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); - L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; + LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE( + L_ATTR_GET(L_GET_PRIVATE(localConf), eventHandler) + ); + const_cast
    (localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); - RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); - L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; + + const_cast
    (tester.handler->getConfAddress()) = addr; tester.handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); @@ -1018,11 +1016,13 @@ void send_unadmined_notify() { localConf.addParticipant(aliceAddr, ¶ms, false); shared_ptr alice = localConf.findParticipant(aliceAddr); L_GET_PRIVATE(alice)->setAdmin(true); - LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); - L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; + LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE( + L_ATTR_GET(L_GET_PRIVATE(localConf), eventHandler) + ); + const_cast
    (localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); - RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); - L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; + + const_cast
    (tester.handler->getConfAddress()) = addr; tester.handler->notifyReceived(notify); @@ -1070,12 +1070,13 @@ void send_subject_changed_notify () { localConf.setSubject("A random test subject"); shared_ptr alice = localConf.findParticipant(aliceAddr); L_GET_PRIVATE(alice)->setAdmin(true); - LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); - L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; + LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE( + L_ATTR_GET(L_GET_PRIVATE(localConf), eventHandler) + ); + const_cast
    (localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); - RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); - L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; + const_cast
    (tester.handler->getConfAddress()) = addr; tester.handler->notifyReceived(notify); BC_ASSERT_STRING_EQUAL(tester.confSubject.c_str(), "A random test subject"); @@ -1124,12 +1125,13 @@ void send_device_added_notify() { localConf.addParticipant(aliceAddr, ¶ms, false); shared_ptr alice = localConf.findParticipant(aliceAddr); L_GET_PRIVATE(alice)->setAdmin(true); - LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); - L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; + LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE( + L_ATTR_GET(L_GET_PRIVATE(localConf), eventHandler) + ); + const_cast
    (localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); - RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); - L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; + const_cast
    (tester.handler->getConfAddress()) = addr; tester.handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester.participantDevices.size(), 2, int, "%d"); @@ -1176,12 +1178,13 @@ void send_device_removed_notify() { localConf.setSubject("A random test subject"); shared_ptr alice = localConf.findParticipant(aliceAddr); L_GET_PRIVATE(alice)->setAdmin(true); - LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(localConf.getEventHandler()); - L_ATTR_GET(static_cast(localConf), conferenceAddress) = addr; + LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE( + L_ATTR_GET(L_GET_PRIVATE(localConf), eventHandler) + ); + const_cast
    (localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); - RemoteConferenceEventHandlerPrivate *remoteHandlerPrivate = L_GET_PRIVATE(tester.handler); - L_ATTR_GET(remoteHandlerPrivate, confAddress) = addr; + const_cast
    (tester.handler->getConfAddress()) = addr; tester.handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester.participantDevices.size(), 2, int, "%d"); diff --git a/tester/tools/tester.h b/tester/tools/tester.h index 650fefcd5..19e0c22ab 100644 --- a/tester/tools/tester.h +++ b/tester/tools/tester.h @@ -36,9 +36,9 @@ class Tester { public: Tester () = delete; - template - static constexpr decltype(std::declval().getPrivate()) getPrivate (Object *cppObject) { - return cppObject->getPrivate(); + template + static constexpr decltype(std::declval().getPrivate()) getPrivate (T *object) { + return object->getPrivate(); } private: From 82132c72c162e018db7f5a9793b79ca6750de917 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 12 Oct 2017 17:22:38 +0200 Subject: [PATCH 0459/2215] Added some enums to parent classes in Java wrapper + started migration script --- wrappers/java/genwrapper.py | 3 + wrappers/java/migration.sh | 212 ++++++++++++++++++++++++++++++++++++ 2 files changed, 215 insertions(+) create mode 100644 wrappers/java/migration.sh diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 7ad4279d1..de3366c07 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -42,12 +42,14 @@ ENUMS_LIST = { 'AccountCreatorTransportStatus': 'AccountCreator', 'AccountCreatorUsernameStatus': 'AccountCreator', 'AddressFamily': 'CallStats', + 'AuthMethod': 'Core', 'CallDir': 'Call', 'CallState': 'Call', 'CallStatus': 'CallLog', 'ChatMessageState': 'ChatMessage', 'ConfiguringState': 'Core', 'CoreLogCollectionUploadState': 'Core', + 'EcCalibratorStatus': 'Core', 'GlobalState': 'Core', 'FriendListStatus': 'FriendList', 'IceState': 'CallStats', @@ -58,6 +60,7 @@ ENUMS_LIST = { 'RegistrationState': 'Core', 'SubscribePolicy': 'Friend', 'TransportType': 'Address', + 'TunnelMode': 'Tunnel', 'XmlRpcArgType': 'XmlRpcRequest', 'XmlRpcStatus': 'XmlRpcRequest', } diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh new file mode 100644 index 000000000..d14eeb439 --- /dev/null +++ b/wrappers/java/migration.sh @@ -0,0 +1,212 @@ +#!/bin/sh + +SRC_DIR="src/android/org/linphone/*.java" + +# Listeners +sed -i 's/AccountCreator.AccountCreatorListener/AccountCreatorListener/g' $SRC_DIR +sed -i 's/LinphoneCoreListenerBase/CoreListenerStub/g' $SRC_DIR +sed -i 's/LinphoneCoreListener/CoreListener/g' $SRC_DIR +sed -i 's/LinphoneChatMessage.LinphoneChatMessageListener/ChatMessageListener/g' $SRC_DIR +sed -i 's/AccountCreator.AccountCreatorListener/AccountCreatorListener/g' $SRC_DIR + +# Enums +sed -i 's/Core.LinphoneLimeState/Core.LimeState/g' $SRC_DIR +sed -i 's/LinphoneLimeState/LimeState/g' $SRC_DIR + +sed -i 's/GlobalState.GlobalOn/Core.GlobalState.On/g' $SRC_DIR + +sed -i 's/RegistrationState.RegistrationOk/RegistrationState.Ok/g' $SRC_DIR +sed -i 's/RegistrationState.RegistrationFailed/RegistrationState.Failed/g' $SRC_DIR +sed -i 's/RegistrationState.RegistrationCleared/RegistrationState.Cleared/g' $SRC_DIR +sed -i 's/RegistrationState.RegistrationProgress/RegistrationState.Progress/g' $SRC_DIR + +sed -i 's/RemoteProvisioningState.ConfiguringSuccessful/ConfiguringState.Successful/g' $SRC_DIR +sed -i 's/LinphoneCore.RemoteProvisioningState/Core.ConfiguringState/g' $SRC_DIR +sed -i 's/RemoteProvisioningState/ConfiguringState/g' $SRC_DIR + +sed -i 's/CallDirection/Call.Dir/g' $SRC_DIR + +sed -i 's/State.CallReleased/State.Released/g' $SRC_DIR +sed -i 's/State.CallEnd/State.End/g' $SRC_DIR +sed -i 's/State.CallUpdatedByRemote/State.UpdatedByRemote/g' $SRC_DIR +sed -i 's/State.CallIncomingEarlyMedia/State.IncomingEarlyMedia/g' $SRC_DIR +sed -i 's/State.CallUpdating/State.Updating/g' $SRC_DIR + +sed -i 's/LogCollectionUploadState.LogCollectionUploadStateInProgress/LogCollectionUploadState.InProgress/g' $SRC_DIR +sed -i 's/LogCollectionUploadState.LogCollectionUploadStateDelivered/LogCollectionUploadState.Delivered/g' $SRC_DIR +sed -i 's/LogCollectionUploadState.LogCollectionUploadStateNotDelivered/LogCollectionUploadState.NotDelivered/g' $SRC_DIR + +sed -i 's/AccountCreator.RequestStatus/AccountCreator.Status/g' $SRC_DIR +sed -i 's/AccountCreator.Status.Ok/AccountCreator.Status.RequestOk/g' $SRC_DIR +sed -i 's/AccountCreator.PasswordCheck/AccountCreator.PasswordStatus/g' $SRC_DIR +sed -i 's/AccountCreator.PhoneNumberCheck/AccountCreator.PhoneNumberStatus/g' $SRC_DIR +sed -i 's/AccountCreator.EmailCheck/AccountCreator.EmailStatus/g' $SRC_DIR +sed -i 's/AccountCreator.UsernameCheck/AccountCreator.UsernameStatus/g' $SRC_DIR +sed -i 's/AccountCreator.Status.Failed/AccountCreator.Status.RequestFailed/g' $SRC_DIR +sed -i 's/AccountCreator.Status.ErrorServer/AccountCreator.Status.ServerError/g' $SRC_DIR + +sed -i 's/Reason.Media/Reason.NotAcceptable/g' $SRC_DIR +sed -i 's/Reason.BadCredentials/Reason.Forbidden/g' $SRC_DIR + +sed -i 's/TransportType.LinphoneTransportUdp/TransportType.Udp/g' $SRC_DIR +sed -i 's/TransportType.LinphoneTransportTcp/TransportType.Tcp/g' $SRC_DIR +sed -i 's/TransportType.LinphoneTransportTls/TransportType.Tls/g' $SRC_DIR +sed -i 's/TransportType.LinphoneTransportDtls/TransportType.Dtls/g' $SRC_DIR + +# Classes +sed -i 's/LpConfig/Config/g' $SRC_DIR +sed -i 's/LinphoneCoreException/CoreException/g' $SRC_DIR +sed -i 's/LinphoneCoreFactory/Factory/g' $SRC_DIR +sed -i 's/LinphoneAccountCreator/AccountCreator/g' $SRC_DIR +sed -i 's/LinphoneAddress/Address/g' $SRC_DIR +sed -i 's/LinphoneAuthInfo/AuthInfo/g' $SRC_DIR +sed -i 's/LinphoneCallLog/CallLog/g' $SRC_DIR +sed -i 's/LinphoneCallParams/CallParams/g' $SRC_DIR +sed -i 's/LinphoneCallStats/CallStats/g' $SRC_DIR +sed -i 's/LinphoneCall/Call/g' $SRC_DIR +sed -i 's/LinphoneChatMessage/ChatMessage/g' $SRC_DIR +sed -i 's/LinphoneChatRoom/ChatRoom/g' $SRC_DIR +sed -i 's/LinphoneConferenceParams/ConferenceParams/g' $SRC_DIR +sed -i 's/LinphoneConference/Conference/g' $SRC_DIR +sed -i 's/LinphoneConfig/Config/g' $SRC_DIR +sed -i 's/LinphoneContent/Content/g' $SRC_DIR +sed -i 's/LinphoneCore/Core/g' $SRC_DIR +sed -i 's/LinphoneEvent/Event/g' $SRC_DIR +sed -i 's/LinphoneFriendList/FriendList/g' $SRC_DIR +sed -i 's/LinphoneFriend/Friend/g' $SRC_DIR +sed -i 's/LinphoneHeaders/Headers/g' $SRC_DIR +sed -i 's/LinphoneImNotifyPolicy/ImNotifyPolicy/g' $SRC_DIR +sed -i 's/LinphoneInfoMessage/InfoMessage/g' $SRC_DIR +sed -i 's/LinphoneNatPolicy/NatPolicy/g' $SRC_DIR +sed -i 's/LinphonePayloadType/PayloadType/g' $SRC_DIR +sed -i 's/LinphonePlayer/Player/g' $SRC_DIR +sed -i 's/LinphonePresence/Presence/g' $SRC_DIR +sed -i 's/LinphonePrivacy/Privacy/g' $SRC_DIR +sed -i 's/LinphoneProxyConfig/ProxyConfig/g' $SRC_DIR +sed -i 's/LinphonePublishState/PublishState/g' $SRC_DIR +sed -i 's/LinphoneRange/Range/g' $SRC_DIR +sed -i 's/LinphoneStreamType/StreamType/g' $SRC_DIR +sed -i 's/LinphoneSubscription/Subscription/g' $SRC_DIR +sed -i 's/LinphoneTransports/Transports/g' $SRC_DIR +sed -i 's/LinphoneTunnel/Tunnel/g' $SRC_DIR +sed -i 's/LinphoneVcard/Vcard/g' $SRC_DIR +sed -i 's/LinphoneXmlRpc/XmlRpc/g' $SRC_DIR + +#Callbacks +sed -i 's/onChatMessageStateChanged/onMsgStateChanged/g' $SRC_DIR +sed -i 's/onChatMessageFileTransferProgressChanged/onFileTransferProgressIndication/g' $SRC_DIR + +#Methods +sed -i 's/getFriendList(/getFriendsLists(/g' $SRC_DIR +sed -i 's/getFriendLists()/getFriendsLists()/g' $SRC_DIR +sed -i 's/getIdentity(/getIdentityAddress(/g' $SRC_DIR +sed -i 's/isTunnelAvailable()/tunnelAvailable()/g' $SRC_DIR +sed -i 's/setZrtpSecretsCache(/setZrtpSecretsFile(/g' $SRC_DIR +sed -i 's/setRootCA(/setRootCa(/g' $SRC_DIR +sed -i 's/isInComingInvitePending()/isIncomingInvitePending()/g' $SRC_DIR +sed -i 's/getAudioCodecs()/getAudioPayloadTypes()/g' $SRC_DIR +sed -i 's/getVideoCodecs()/getVideoPayloadTypes()/g' $SRC_DIR +sed -i 's/getMime()/getMimeType()/g' $SRC_DIR +sed -i 's/getFrom()/getFromAddress()/g' $SRC_DIR +sed -i 's/getTo()/getToAddress()/g' $SRC_DIR +sed -i 's/getUserName()/getUsername()/g' $SRC_DIR +sed -i 's/getLimeEncryption()/limeEnabled()/g' $SRC_DIR +sed -i 's/getDirection/getDir/g' $SRC_DIR +sed -i 's/.getVideoEnabled()/.videoEnabled()/g' $SRC_DIR +sed -i 's/.getDataAsString()/.getStringBuffer()/g' $SRC_DIR +sed -i 's/getEventName()/getName()/g' $SRC_DIR +sed -i 's/setPlaybackGain(/setPlaybackGainDb(/g' $SRC_DIR +sed -i 's/isIncall()/inCall()/g' $SRC_DIR +sed -i 's/setVideoEnabled(/enableVideo(/g' $SRC_DIR +sed -i 's/setAudioBandwidth(/setAudioBandwidthLimit(/g' $SRC_DIR +sed -i 's/isAuthenticationTokenVerified()/getAuthenticationTokenVerified()/g' $SRC_DIR +sed -i 's/isMicMuted()/!micEnabled()/g' $SRC_DIR +sed -i 's/isLowBandwidthEnabled()/lowBandwidthEnabled()/g' $SRC_DIR +sed -i 's/muteMic(/enableMic(!/g' $SRC_DIR +sed -i 's/getRate()/getClockRate()/g' $SRC_DIR +sed -i 's/getSentVideoSize()/getSentVideoDefinition()/g' $SRC_DIR +sed -i 's/getReceivedVideoSize()/getReceivedVideoDefinition()/g' $SRC_DIR +sed -i 's/getUsedAudioCodec()/getUsedAudioPayloadType()/g' $SRC_DIR +sed -i 's/getUsedVideoCodec()/getUsedVideoPayloadType()/g' $SRC_DIR +sed -i 's/setVideoWindow(/setNativeVideoWindowId(/g' $SRC_DIR +sed -i 's/setPreviewWindow(/setNativePreviewWindowId(/g' $SRC_DIR +sed -i 's/islimeAvailable()/limeAvailable()/g' $SRC_DIR +sed -i 's/createChatMessage(/createMessage(/g' $SRC_DIR +#For messages only +sed -i 's/message.getStatus()/message.getState()/g' $SRC_DIR +# +sed -i 's/reSend()/resend()/g' $SRC_DIR +sed -i 's/setAppData(/setAppdata(/g' $SRC_DIR +sed -i 's/getAppData()/getAppdata()/g' $SRC_DIR +sed -i 's/getOrCreateChatRoom(/getChatRoomFromUri(/g' $SRC_DIR +sed -i 's/findFriendByAddress(/findFriend(/g' $SRC_DIR +sed -i 's/getTimestamp()/getStartDate()/g' $SRC_DIR +#For ProxyConfigs only +sed -i 's/lpc.getAddress()/lpc.getIdentityAddress()/g' $SRC_DIR +# +sed -i 's/getCallDuration()/getDuration()/g' $SRC_DIR +sed -i 's/isVCardSupported()/vcardSupported()/g' $SRC_DIR +sed -i 's/getPresenceModelForUri(/getPresenceModelForUriOrTel(/g' $SRC_DIR +sed -i 's/setAvpfRRInterval(/setAvpfRrInterval(/g' $SRC_DIR +sed -i 's/getProxy()/getServerAddr()/g' $SRC_DIR +sed -i 's/setProxy(/setServerAddr(/g' $SRC_DIR +sed -i 's/setIdentity(/setIdentityAddress(/g' $SRC_DIR +sed -i 's/setUserId(/setUserid(/g' $SRC_DIR +sed -i 's/getUserId(/getUserid/g' $SRC_DIR +sed -i 's/getAuthInfosList(/getAuthInfoList(/g' $SRC_DIR +sed -i 's/getPassword/getPasswd(/g' $SRC_DIR +sed -i 's/getSignalingTransportPorts()/getTransports()/g' $SRC_DIR +sed -i 's/setSignalingTransportPorts(/setTransports(/g' $SRC_DIR +sed -i 's/isIpv6Enabled()/ipv6Enabled()/g' $SRC_DIR +sed -i 's/isAdaptiveRateControlEnabled()/adaptiveRateControlEnabled()/g' $SRC_DIR +sed -i 's/setLimeEncryption(/enableLime(/g' $SRC_DIR +#For enums only +sed -i 's/.value()/.toInt()/g' $SRC_DIR +# +sed -i 's/clearAuthInfos()/clearAllAuthInfo()/g' $SRC_DIR +sed -i 's/clearProxyConfigs()/clearProxyConfig()/g' $SRC_DIR +sed -i 's/isVideoSupported()/videoSupported()/g' $SRC_DIR + +#Removed methods +sed -i 's/.isRegistered()/.getState() == RegistrationState.Ok/g' $SRC_DIR +sed -i 's/getBool(/getInt(/g' $SRC_DIR +sed -i 's/setBool(/setInt(/g' $SRC_DIR +sed -i 's/isInConference()/getConference() != null/g' $SRC_DIR +sed -i 's/getAudioStats()/getStats(StreamType.Audio)/g' $SRC_DIR +sed -i 's/getVideoStats()/getStats(StreamType.Audio)/g' $SRC_DIR +sed -i 's/getVcardToString()/getVcard().asVcard4String()/g' $SRC_DIR +sed -i 's/getVideoAutoInitiatePolicy()/getVideoActivationPolicy().getAutomaticallyInitiate()/g' $SRC_DIR +sed -i 's/setFamilyName(/getVcard().setFamilyName(/g' $SRC_DIR +sed -i 's/setGivenName(/getVcard().setGivenName(/g' $SRC_DIR +sed -i 's/setOrganization(/getVcard().setOrganization(/g' $SRC_DIR +sed -i 's/getFamilyName()/getVcard().getFamilyName()/g' $SRC_DIR +sed -i 's/getGivenName()/getVcard().getGivenName()/g' $SRC_DIR +sed -i 's/getOrganization()/getVcard().getOrganization()/g' $SRC_DIR +sed -i 's/enableAvpf(/setAvpfMode(AVPFMode.Enabled)/g' $SRC_DIR +sed -i 's/transports.udp = /transports.setUdpPort(/g' $SRC_DIR +sed -i 's/transports.tcp = /transports.setTcpPort(/g' $SRC_DIR +sed -i 's/transports.tls = /transports.setTlsPort(/g' $SRC_DIR +sed -i 's/transports.udp/transports.getUdpPort()/g' $SRC_DIR +sed -i 's/transports.tcp/transports.getTcpPort()/g' $SRC_DIR +sed -i 's/transports.tls/transports.getTlsPort()/g' $SRC_DIR +sed -i 's/getPrimaryContactUsername()/getPrimaryContactParsed().getUsername()/g' $SRC_DIR +sed -i 's/getPrimaryContactDisplayName()/getPrimaryContactParsed().getDisplayName()/g' $SRC_DIR + +#Have disapeared, to check +#OpenH264DownloadHelper +#Core.enablePayloadType() +#Core.isPayloadTypeEnabled() +#Core.payloadTypeIsVbr() +#Core.setPayloadTypeBitrate() +#DialPlan +#LinphoneBuffer +#CallParams.getJitterBufferSize() +#Core.getSupportedVideoSizes() +#Core.needsEchoCalibration() +#Core.removeFriend( +#Core.hasCrappyOpenGL() +#Core.enableSpeaker / isSpeakerEnabled() +#Core.getMSFactory() +#Core.enableVideo(true, true) => Core.enableVideoCapture(bool) & Core.enableVideoDisplay(bool) +#Core.setCpuCount() +#Call.zoomVideo() has been removed temporarily in the wrapper From 8f1ed031da08199f5bf44fcce43a54bffba4bae8 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 12 Oct 2017 17:55:23 +0200 Subject: [PATCH 0460/2215] feat(ChatRoom): call right `setSubject` method --- src/chat/chat-room/client-group-chat-room.cpp | 6 +++--- src/conference/local-conference-p.h | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 22ed84b38..3fdc1bb74 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -68,7 +68,7 @@ ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, : ChatRoom(*new ClientGroupChatRoomPrivate(core)), RemoteConference(core, me, nullptr) { static_cast(Conference::mPrivate)->focus = ObjectFactory::create(Address(uri)); - setSubject(subject); + RemoteConference::setSubject(subject); } int ClientGroupChatRoom::getCapabilities () const { @@ -152,7 +152,7 @@ void ClientGroupChatRoom::leave () { L_D(); RemoteConferencePrivate *conferencePrivate = - static_cast(Conference::mPrivate); + static_cast(Conference::mPrivate); conferencePrivate->eventHandler->unsubscribe(); shared_ptr session = conferencePrivate->focus->getPrivate()->getSession(); @@ -298,7 +298,7 @@ void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdm } void ClientGroupChatRoom::onSubjectChanged (const std::string &subject) { - setSubject(subject); + RemoteConference::setSubject(subject); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsSubjectChangedCb cb = linphone_chat_room_cbs_get_subject_changed(cbs); diff --git a/src/conference/local-conference-p.h b/src/conference/local-conference-p.h index def1a9111..3ae543efb 100644 --- a/src/conference/local-conference-p.h +++ b/src/conference/local-conference-p.h @@ -30,9 +30,10 @@ LINPHONE_BEGIN_NAMESPACE class LocalConferenceEventHandler; class LocalConferencePrivate : public ConferencePrivate { -private: +public: std::unique_ptr eventHandler; +private: L_DECLARE_PUBLIC(LocalConference); }; From 66a92bb88ab4d483ca998706c1ce10a1681ede67 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 13 Oct 2017 10:04:39 +0200 Subject: [PATCH 0461/2215] Some const fixes. --- coreapi/linphonecore.c | 4 ++-- include/linphone/core.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ebd2253a0..dbe706d4c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4142,7 +4142,7 @@ const char** linphone_core_get_video_devices(const LinphoneCore *lc){ return lc->video_conf.cams; } -const bctbx_list_t * linphone_core_get_sound_devices_list(LinphoneCore *lc){ +bctbx_list_t * linphone_core_get_sound_devices_list(const LinphoneCore *lc){ bctbx_list_t *cards_list = NULL; const char** cards = lc->sound_conf.cards; for (const char* c = *cards; c; c=*++cards) { @@ -4151,7 +4151,7 @@ const bctbx_list_t * linphone_core_get_sound_devices_list(LinphoneCore *lc){ return cards_list; } -const bctbx_list_t * linphone_core_get_video_devices_list(const LinphoneCore *lc){ +bctbx_list_t * linphone_core_get_video_devices_list(const LinphoneCore *lc){ bctbx_list_t *cards_list = NULL; const char** cards = lc->video_conf.cams; for (const char* c = *cards; c; c=*++cards) { diff --git a/include/linphone/core.h b/include/linphone/core.h index fabcdab6c..9add3df87 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -2697,7 +2697,7 @@ LINPHONE_PUBLIC const char** linphone_core_get_sound_devices(LinphoneCore *lc); * @return \bctbx_list{char *} An unmodifiable array of strings contanining the names of the available sound devices that is NULL terminated * @ingroup media_parameters **/ -LINPHONE_PUBLIC const bctbx_list_t * linphone_core_get_sound_devices_list(LinphoneCore *lc); +LINPHONE_PUBLIC bctbx_list_t * linphone_core_get_sound_devices_list(const LinphoneCore *lc); /** * Use this function when you want to set the default sound devices @@ -3613,7 +3613,7 @@ LINPHONE_PUBLIC const char** linphone_core_get_video_devices(const LinphoneCore * @return \bctbx_list{char *} An unmodifiable array of strings contanining the names of the available video capture devices that is NULL terminated * @ingroup media_parameters **/ -LINPHONE_PUBLIC const bctbx_list_t * linphone_core_get_video_devices_list(LinphoneCore *lc); +LINPHONE_PUBLIC bctbx_list_t * linphone_core_get_video_devices_list(const LinphoneCore *lc); /** * Sets the active video device. From a1fe2223f09605c891d5d0fbf6d5e723c8fe9fbb Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 13 Oct 2017 10:33:36 +0200 Subject: [PATCH 0462/2215] fix & test last notify id in conference event package --- src/conference/local-conference-event-handler.cpp | 7 +++---- tester/conference-event-tester.cpp | 4 ++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index ff9b33167..42d75d19d 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -66,10 +66,9 @@ void LocalConferenceEventHandlerPrivate::notifyAll (const string ¬ify) { } string LocalConferenceEventHandlerPrivate::createNotify (ConferenceType confInfo) { - if (confInfo.getVersion().present()) { - lastNotify = confInfo.getVersion().get() + 1; - confInfo.setVersion(lastNotify); - } + lastNotify = lastNotify + 1; + confInfo.setVersion(lastNotify); + stringstream notify; Xsd::XmlSchema::NamespaceInfomap map; map[""].name = "urn:ietf:params:xml:ns:conference-info"; diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index 3c4876e6c..72b78453b 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -1081,6 +1081,8 @@ void send_subject_changed_notify () { BC_ASSERT_STRING_EQUAL(tester.confSubject.c_str(), "A random test subject"); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_EQUAL(L_GET_PRIVATE(tester.handler)->getLastNotify(), 1, int, "%d"); + BC_ASSERT_EQUAL(localHandlerPrivate->getLastNotify(), 1, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(bobAddr.asString()) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(aliceAddr.asString()) != tester.participants.end()); BC_ASSERT_TRUE(!tester.participants.find(bobAddr.asString())->second); @@ -1092,6 +1094,8 @@ void send_subject_changed_notify () { BC_ASSERT_STRING_EQUAL(tester.confSubject.c_str(), "Another random test subject..."); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); + BC_ASSERT_EQUAL(L_GET_PRIVATE(tester.handler)->getLastNotify(), 2, int, "%d"); + BC_ASSERT_EQUAL(localHandlerPrivate->getLastNotify(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(bobAddr.asString()) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(aliceAddr.asString()) != tester.participants.end()); BC_ASSERT_TRUE(!tester.participants.find(bobAddr.asString())->second); From e12b123cf0daab6858fd29fd56e10f1c6850249d Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 13 Oct 2017 11:08:49 +0200 Subject: [PATCH 0463/2215] feat(General): provide a way to get private data in a a multiple inheritance case. --- include/linphone/utils/general.h | 30 +++++++++++++++++-- src/chat/chat-room/client-group-chat-room.cpp | 4 +-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index 8e9e5d146..1ccee3b72 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -20,6 +20,10 @@ #ifndef _GENERAL_H_ #define _GENERAL_H_ +#ifdef __cplusplus + #include +#endif + // ============================================================================= #ifdef __cplusplus @@ -151,8 +155,30 @@ constexpr T *getPublicHelper (Object *object, const ObjectPrivate *) { CLASS (const CLASS &) = delete; \ CLASS &operator= (const CLASS &) = delete; -#define L_D() decltype(std::declval().getPrivate()) const d = getPrivate(); -#define L_Q() decltype(std::declval().getPublic()) const q = getPublic(); +// Get Private data. +#define L_D() decltype(getPrivate()) const d = getPrivate(); + +// Get Public data. +#define L_Q() decltype(getPublic()) const q = getPublic(); + +template +struct AddConstMirror { + typedef U type; +}; + +template +struct AddConstMirror { + typedef typename std::add_const::type type; +}; + +// Get Private data of class in a multiple inheritance case. +#define L_D_T(CLASS, NAME) \ + auto const NAME = static_cast< \ + AddConstMirror< \ + std::remove_reference::type, \ + CLASS ## Private \ + >::type * \ + >(CLASS::mPrivate); #define L_OVERRIDE_SHARED_FROM_THIS(CLASS) \ inline std::shared_ptr getSharedFromThis () { \ diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 3fdc1bb74..9d0e85137 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -211,6 +211,7 @@ void ClientGroupChatRoom::setParticipantAdminStatus (shared_ptr &pa void ClientGroupChatRoom::setSubject (const string &subject) { L_D(); + L_D_T(RemoteConference, dConference); if (d->state != ChatRoom::State::Created) { lError() << "Cannot change the ClientGroupChatRoom subject in a state other than Created"; @@ -222,8 +223,7 @@ void ClientGroupChatRoom::setSubject (const string &subject) { return; } - shared_ptr session = - static_cast(Conference::mPrivate)->focus->getPrivate()->getSession(); + shared_ptr session = dConference->focus->getPrivate()->getSession(); if (session) session->update(nullptr, subject); else { From 2d9d5a571c40aff9b56bf3edf5ea0e301228dbaa Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 13 Oct 2017 11:15:10 +0200 Subject: [PATCH 0464/2215] feat(ClientGroupChatRoom): use L_D_T macro when possible --- src/chat/chat-room/client-group-chat-room.cpp | 60 ++++++++++++------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 9d0e85137..0f10d600f 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -64,10 +64,14 @@ void ClientGroupChatRoomPrivate::notifyReceived (string body) { // ============================================================================= -ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, const string &uri, const string &subject) - : ChatRoom(*new ClientGroupChatRoomPrivate(core)), RemoteConference(core, me, nullptr) { - static_cast(Conference::mPrivate)->focus = - ObjectFactory::create(Address(uri)); +ClientGroupChatRoom::ClientGroupChatRoom ( + LinphoneCore *core, + const Address &me, + const string &uri, + const string &subject +) : ChatRoom(*new ClientGroupChatRoomPrivate(core)), RemoteConference(core, me, nullptr) { + L_D_T(RemoteConference, dConference); + dConference->focus = ObjectFactory::create(Address(uri)); RemoteConference::setSubject(subject); } @@ -81,8 +85,13 @@ void ClientGroupChatRoom::addParticipant (const Address &addr, const CallSession addParticipants(addresses, params, hasMedia); } -void ClientGroupChatRoom::addParticipants (const list
    &addresses, const CallSessionParams *params, bool hasMedia) { +void ClientGroupChatRoom::addParticipants ( + const list
    &addresses, + const CallSessionParams *params, + bool hasMedia +) { L_D(); + L_D_T(RemoteConference, dConference); if (addresses.empty()) return; @@ -101,8 +110,7 @@ void ClientGroupChatRoom::addParticipants (const list
    &addresses, const content.setContentType("application/resource-lists+xml"); content.setContentDisposition("recipient-list"); - shared_ptr session = - static_cast(Conference::mPrivate)->focus->getPrivate()->getSession(); + shared_ptr session = dConference->focus->getPrivate()->getSession(); if (session) session->update(nullptr, getSubject(), &content); else { @@ -139,9 +147,10 @@ const string &ClientGroupChatRoom::getSubject () const { void ClientGroupChatRoom::join () { L_D(); - shared_ptr session = - static_cast(Conference::mPrivate)->focus->getPrivate()->getSession(); - if (!session && (d->state == ChatRoom::State::Instantiated)) { + L_D_T(RemoteConference, dConference); + + shared_ptr session = dConference->focus->getPrivate()->getSession(); + if (!session && d->state == ChatRoom::State::Instantiated) { session = d->createSession(); session->startInvite(nullptr, "", nullptr); d->setState(ChatRoom::State::CreationPending); @@ -150,12 +159,11 @@ void ClientGroupChatRoom::join () { void ClientGroupChatRoom::leave () { L_D(); + L_D_T(RemoteConference, dConference); - RemoteConferencePrivate *conferencePrivate = - static_cast(Conference::mPrivate); - conferencePrivate->eventHandler->unsubscribe(); + dConference->eventHandler->unsubscribe(); - shared_ptr session = conferencePrivate->focus->getPrivate()->getSession(); + shared_ptr session = dConference->focus->getPrivate()->getSession(); if (session) session->terminate(); else { @@ -236,7 +244,9 @@ void ClientGroupChatRoom::setSubject (const string &subject) { void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { L_D(); - static_cast(Conference::mPrivate)->conferenceAddress = addr; + L_D_T(RemoteConference, dConference); + + dConference->conferenceAddress = addr; d->setState(ChatRoom::State::Created); _linphone_core_add_group_chat_room(d->core, addr, L_GET_C_BACK_PTR(this)); } @@ -335,27 +345,31 @@ void ClientGroupChatRoom::onParticipantDeviceRemoved (const Address &addr, const // ----------------------------------------------------------------------------- void ClientGroupChatRoom::onCallSessionSetReleased (const std::shared_ptr &session) { - ParticipantPrivate *participantPrivate = - static_cast(Conference::mPrivate)->focus->getPrivate(); + L_D_T(RemoteConference, dConference); + ParticipantPrivate *participantPrivate = dConference->focus->getPrivate(); if (session == participantPrivate->getSession()) participantPrivate->removeSession(); } -void ClientGroupChatRoom::onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const string &message) { +void ClientGroupChatRoom::onCallSessionStateChanged ( + const std::shared_ptr &session, + LinphoneCallState state, + const string &message +) { L_D(); + L_D_T(RemoteConference, dConference); + if (state == LinphoneCallConnected) { if (d->state == ChatRoom::State::CreationPending) { Address addr(session->getRemoteContact()); addr.clean(); onConferenceCreated(addr); if (session->getRemoteContactAddress()->hasParam("isfocus")) - static_cast(Conference::mPrivate)->eventHandler->subscribe( - getConferenceAddress() - ); + dConference->eventHandler->subscribe(getConferenceAddress()); } else if (d->state == ChatRoom::State::TerminationPending) - static_cast(Conference::mPrivate)->focus->getPrivate()->getSession()->terminate(); - } else if ((state == LinphoneCallReleased) && (d->state == ChatRoom::State::TerminationPending)) + dConference->focus->getPrivate()->getSession()->terminate(); + } else if (state == LinphoneCallReleased && d->state == ChatRoom::State::TerminationPending) onConferenceTerminated(getConferenceAddress()); } From a9995e2fce4bd9dbcdd9e8b0b421d09fae189f27 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 13 Oct 2017 11:17:15 +0200 Subject: [PATCH 0465/2215] feat(ClientGroupChatRoom): use L_D_T in the case of simple `mPrivate` access --- src/chat/chat-room/client-group-chat-room.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 0f10d600f..b2b3c93e7 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -257,6 +257,8 @@ void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { } void ClientGroupChatRoom::onParticipantAdded (const Address &addr) { + L_D_T(RemoteConference, dConference); + if (isMe(addr)) return; @@ -267,7 +269,7 @@ void ClientGroupChatRoom::onParticipantAdded (const Address &addr) { } participant = ObjectFactory::create(addr); - RemoteConference::mPrivate->participants.push_back(participant); + dConference->participants.push_back(participant); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAddedCb cb = linphone_chat_room_cbs_get_participant_added(cbs); @@ -276,17 +278,22 @@ void ClientGroupChatRoom::onParticipantAdded (const Address &addr) { } void ClientGroupChatRoom::onParticipantRemoved (const Address &addr) { + L_D_T(RemoteConference, dConference); + shared_ptr participant = findParticipant(addr); if (!participant) { lWarning() << "Participant " << addr.asString() << " removed but not in the list of participants!"; return; } + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantRemovedCb cb = linphone_chat_room_cbs_get_participant_removed(cbs); + if (cb) cb(cr, L_GET_C_BACK_PTR(participant)); - RemoteConference::mPrivate->participants.remove(participant); + + dConference->participants.remove(participant); } void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdmin) { @@ -299,10 +306,12 @@ void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdm lWarning() << "Participant " << participant << " admin status has been changed but is not in the list of participants!"; return; } + participant->getPrivate()->setAdmin(isAdmin); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAdminStatusChangedCb cb = linphone_chat_room_cbs_get_participant_admin_status_changed(cbs); + if (cb) cb(cr, L_GET_C_BACK_PTR(participant), isAdmin); } @@ -312,6 +321,7 @@ void ClientGroupChatRoom::onSubjectChanged (const std::string &subject) { LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsSubjectChangedCb cb = linphone_chat_room_cbs_get_subject_changed(cbs); + if (cb) cb(cr, subject.c_str()); } From 5b139dc79b5e417dd869f159d342fce238072cb1 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 13 Oct 2017 11:12:12 +0200 Subject: [PATCH 0466/2215] Fix the URI grammar for CPIM. --- src/chat/cpim/parser/cpim-grammar.cpp | 109 +++++++++++--------------- 1 file changed, 44 insertions(+), 65 deletions(-) diff --git a/src/chat/cpim/parser/cpim-grammar.cpp b/src/chat/cpim/parser/cpim-grammar.cpp index 648c7e09b..245477855 100644 --- a/src/chat/cpim/parser/cpim-grammar.cpp +++ b/src/chat/cpim/parser/cpim-grammar.cpp @@ -89,89 +89,68 @@ UTF8-multi = %xC0-DF %x80-BF / %xF0-F7 %x80-BF %x80-BF %x80-BF / %xF8-FB %x80-BF %x80-BF %x80-BF %x80-BF / %xFC-FD %x80-BF %x80-BF %x80-BF %x80-BF %x80-BF + +URI = absoluteURI )==GRAMMAR==" -// See: https://tools.ietf.org/html/rfc2396 +// See: https://tools.ietf.org/html/rfc2396 & https://tools.ietf.org/html/rfc2732 R"==GRAMMAR==( -URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] +absoluteURI = scheme ":" ( hier-part / opaque-part ) +relativeURI = ( net-path / abs-path / rel-path ) [ "?" query ] -hier-part = "//" authority path-abempty - / path-absolute - / path-rootless - / path-empty +hier-part = ( net-path / abs-path ) [ "?" query ] +opaque-part = uric-no-slash *uric -URI-reference = URI / relative-ref +uric-no-slash = unreserved / escaped / ";" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / "," -absolute-URI = scheme ":" hier-part [ "?" query ] +net-path = "//" authority [ abs-path ] +abs-path = "/" path-segments +rel-path = rel-segment [ abs-path ] -relative-ref = relative-part [ "?" query ] [ "#" fragment ] - -relative-part = "//" authority path-abempty - / path-absolute - / path-noscheme - / path-empty +rel-segment = 1*( unreserved / escaped / ";" / "@" / "&" / "=" / "+" / "$" / "," ) scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) -authority = [ userinfo "@" ] host [ ":" port ] -userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) -host = IP-literal / IPv4address / reg-name +authority = server / reg-name + +reg-name = 1*( unreserved / escaped / "$" / "," / ";" / ":" / "@" / "&" / "=" / "+" ) + +server = [ [ userinfo "@" ] hostport ] +userinfo = *( unreserved / escaped / ";" / ":" / "&" / "=" / "+" / "$" / "," ) + +hostport = host [ ":" port ] +host = hostname / IPv4address / IPv6address +ipv6reference = "[" IPv6address "]" +hostname = *( domainlabel "." ) toplabel [ "." ] +domainlabel = alphanum / alphanum *( alphanum / "-" ) alphanum +toplabel = ALPHA / ALPHA *( alphanum / "-" ) alphanum +IPv6address = hexpart [ ":" IPv4address ] +IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT port = *DIGIT -IP-literal = "[" ( IPv6address / IPvFuture ) "]" +IPv6prefix = hexpart "/" 1*2DIGIT +hexpart = hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ] +hexseq = hex4 *( ":" hex4) +hex4 = 1*4HEXDIG -IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) +path = [ abs-path / opaque-part ] +path-segments = segment *( "/" segment ) +segment = *pchar *( ";" param ) +param = *pchar +pchar = unreserved / escaped / ":" / "@" / "&" / "=" / "+" / "$" / "," -IPv6address = 6( h16 ":" ) ls32 - / "::" 5( h16 ":" ) ls32 - / [ h16 ] "::" 4( h16 ":" ) ls32 - / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 - / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 - / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 - / [ *4( h16 ":" ) h16 ] "::" ls32 - / [ *5( h16 ":" ) h16 ] "::" h16 - / [ *6( h16 ":" ) h16 ] "::" +query = *uric -h16 = 1*4HEXDIG -ls32 = ( h16 ":" h16 ) / IPv4address -IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet -dec-octet = DIGIT - / %x31-39 DIGIT - / "1" 2DIGIT - / "2" %x30-34 DIGIT - / "25" %x30-35 +fragment = *uric -reg-name = *( unreserved / pct-encoded / sub-delims ) +uric = reserved / unreserved / escaped +reserved = ";" / "/" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / "," / "[" / "]" +unreserved = alphanum / mark +mark = "-" / "_" / "." / "!" / "~" / "*" / "'" / "(" / ")" -path = path-abempty - / path-absolute - / path-noscheme - / path-rootless - / path-empty +escaped = "%" HEXDIG HEXDIG -path-abempty = *( "/" segment ) -path-absolute = "/" [ segment-nz *( "/" segment ) ] -path-noscheme = segment-nz-nc *( "/" segment ) -path-rootless = segment-nz *( "/" segment ) -path-empty = [pchar] - -segment = *pchar -segment-nz = 1*pchar -segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) - -pchar = unreserved / pct-encoded / sub-delims / ":" / "@" / "\," - -query = *( pchar / "/" / "?" ) - -fragment = *( pchar / "/" / "?" ) - -pct-encoded = "%" HEXDIG HEXDIG - -unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" -reserved = gen-delims / sub-delims -gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" -sub-delims = "!" / "$" / "&" / "'" / "(" / ")" - / "*" / "+" / "," / ";" / "=" +alphanum = ALPHA / DIGIT )==GRAMMAR==" // See: https://tools.ietf.org/html/rfc3066 From 39437121317284bd8c1700b78c666c38b467b7b1 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 13 Oct 2017 11:18:29 +0200 Subject: [PATCH 0467/2215] Some cleaning in chat room and chat message. --- coreapi/private.h | 1 - include/linphone/api/c-chat-message.h | 5 -- src/c-wrapper/api/c-chat-message.cpp | 5 +- src/chat/chat-message/chat-message-p.h | 11 +++-- src/chat/chat-message/chat-message.cpp | 25 +++++----- src/chat/chat-room/chat-room.cpp | 46 ++----------------- src/chat/chat-room/client-group-chat-room.cpp | 2 +- src/chat/cpim/message/cpim-message.cpp | 3 +- src/chat/cpim/parser/cpim-parser.cpp | 3 +- src/chat/imdn.h | 5 ++ 10 files changed, 35 insertions(+), 71 deletions(-) diff --git a/coreapi/private.h b/coreapi/private.h index 9e8c32bb0..cd82d149a 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -1118,7 +1118,6 @@ void linphone_chat_room_remove_transient_message(LinphoneChatRoom *cr, LinphoneC void linphone_chat_message_deactivate(LinphoneChatMessage *msg); void linphone_chat_message_release(LinphoneChatMessage *msg); void linphone_chat_message_fetch_content_from_database(sqlite3 *db, LinphoneChatMessage *message, int content_id); -void linphone_chat_message_send_imdn(LinphoneChatMessage *cm, ImdnType imdn_type, LinphoneReason reason); void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID id); bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc); diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index d9f6ad404..20103291a 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -29,11 +29,6 @@ // ============================================================================= -typedef enum _ImdnType { - ImdnTypeDelivery, - ImdnTypeDisplay -} ImdnType; - typedef enum _LinphoneChatMessageDir{ LinphoneChatMessageIncoming, LinphoneChatMessageOutgoing diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 0aed719e6..e44853426 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -28,9 +28,9 @@ #include "content/content.h" #include "content/content-type.h" #include "chat/chat-message/chat-message-p.h" -#include "chat/chat-message/chat-message.h" #include "chat/chat-room/chat-room-p.h" #include "chat/chat-room/real-time-text-chat-room-p.h" +#include "chat/imdn.h" // ============================================================================= @@ -275,9 +275,6 @@ void linphone_chat_message_resend_2(LinphoneChatMessage *msg) { void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state) { L_GET_CPP_PTR_FROM_C_OBJECT(msg)->updateState((LinphonePrivate::ChatMessage::State) new_state); } -void linphone_chat_message_send_imdn(LinphoneChatMessage *msg, ImdnType imdn_type, LinphoneReason reason) { - L_GET_PRIVATE_FROM_C_OBJECT(msg)->sendImdn(imdn_type, reason); -} void linphone_chat_message_deactivate(LinphoneChatMessage *msg){ L_GET_CPP_PTR_FROM_C_OBJECT(msg)->cancelFileTransfer(); diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index 57355430f..e62bff099 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -20,10 +20,15 @@ #ifndef _CHAT_MESSAGE_P_H_ #define _CHAT_MESSAGE_P_H_ -#include "chat-message.h" +#include + +#include "chat/chat-message/chat-message.h" +#include "chat/imdn.h" +#include "content/content.h" #include "content/content-type.h" #include "db/events-db.h" #include "object/object-p.h" +#include "sal/sal.h" // ============================================================================= @@ -107,7 +112,7 @@ public: // ----------------------------------------------------------------------------- - void sendImdn(ImdnType imdnType, LinphoneReason reason); + void sendImdn(Imdn::Type imdnType, LinphoneReason reason); LinphoneReason receive(); void send(); @@ -146,7 +151,7 @@ private: // ----------------------------------------------------------------------------- - std::string createImdnXml(ImdnType imdnType, LinphoneReason reason); + std::string createImdnXml(Imdn::Type imdnType, LinphoneReason reason); void fileUploadEndBackgroundTask(); void fileUploadBeginBackgroundTask(); diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 3defac18f..a4b8678d6 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -74,7 +74,6 @@ void ChatMessagePrivate::setIsReadOnly(bool readOnly) { void ChatMessagePrivate::setState(ChatMessage::State s) { L_Q(); - if (s != state && chatRoom) { if (((state == ChatMessage::State::Displayed) || (state == ChatMessage::State::DeliveredToUser)) && ((s == ChatMessage::State::DeliveredToUser) || (s == ChatMessage::State::Delivered) || (s == ChatMessage::State::NotDelivered))) { @@ -204,7 +203,7 @@ void ChatMessagePrivate::setFileTransferInformation(LinphoneContent *content) { // ----------------------------------------------------------------------------- -string ChatMessagePrivate::createImdnXml(ImdnType imdnType, LinphoneReason reason) { +string ChatMessagePrivate::createImdnXml(Imdn::Type imdnType, LinphoneReason reason) { xmlBufferPtr buf; xmlTextWriterPtr writer; int err; @@ -241,7 +240,7 @@ string ChatMessagePrivate::createImdnXml(ImdnType imdnType, LinphoneReason reaso err = xmlTextWriterWriteElement(writer, (const xmlChar *)"datetime", (const xmlChar *)datetime); } if (err >= 0) { - if (imdnType == ImdnTypeDelivery) { + if (imdnType == Imdn::Type::Delivery) { err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivery-notification"); } else { err = xmlTextWriterStartElement(writer, (const xmlChar *)"display-notification"); @@ -252,7 +251,7 @@ string ChatMessagePrivate::createImdnXml(ImdnType imdnType, LinphoneReason reaso } if (err >= 0) { if (reason == LinphoneReasonNone) { - if (imdnType == ImdnTypeDelivery) { + if (imdnType == Imdn::Type::Delivery) { err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivered"); } else { err = xmlTextWriterStartElement(writer, (const xmlChar *)"displayed"); @@ -304,7 +303,7 @@ string ChatMessagePrivate::createImdnXml(ImdnType imdnType, LinphoneReason reaso return content; } -void ChatMessagePrivate::sendImdn(ImdnType imdnType, LinphoneReason reason) { +void ChatMessagePrivate::sendImdn(Imdn::Type imdnType, LinphoneReason reason) { string content = createImdnXml(imdnType, reason); chatRoom->getPrivate()->sendImdn(content, reason); } @@ -1082,7 +1081,7 @@ void ChatMessagePrivate::send() { } if (lp_config_get_int(chatRoom->getCore()->config, "sip", "chat_use_call_dialogs", 0) != 0) { - call = linphone_core_get_call_by_remote_address(chatRoom->getCore(), chatRoom->getPeerAddress().asString().c_str()); + call = linphone_core_get_call_by_remote_address(chatRoom->getCore(), to.asString().c_str()); if (call) { if (linphone_call_get_state(call) == LinphoneCallConnected || linphone_call_get_state(call) == LinphoneCallStreamsRunning || linphone_call_get_state(call) == LinphoneCallPaused || linphone_call_get_state(call) == LinphoneCallPausing || @@ -1091,7 +1090,7 @@ void ChatMessagePrivate::send() { op = linphone_call_get_op(call); string identity = linphone_core_find_best_identity(chatRoom->getCore(), linphone_call_get_remote_address(call)); if (identity.empty()) { - LinphoneAddress *addr = linphone_address_new(chatRoom->getPeerAddress().asString().c_str()); + LinphoneAddress *addr = linphone_address_new(to.asString().c_str()); LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(chatRoom->getCore(), addr); if (proxy) { identity = L_GET_CPP_PTR_FROM_C_OBJECT(linphone_proxy_config_get_identity_address(proxy))->asString(); @@ -1106,7 +1105,7 @@ void ChatMessagePrivate::send() { } if (!op) { - LinphoneAddress *peer = linphone_address_new(chatRoom->getPeerAddress().asString().c_str()); + LinphoneAddress *peer = linphone_address_new(to.asString().c_str()); /* Sending out of call */ salOp = op = new SalMessageOp(chatRoom->getCore()->sal); linphone_configure_op( @@ -1181,14 +1180,14 @@ void ChatMessagePrivate::send() { if (!externalBodyUrl.empty()) { char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", externalBodyUrl.c_str()); auto msgOp = dynamic_cast(op); - msgOp->send_message(from.asString().c_str(), chatRoom->getPeerAddress().asString().c_str(), content_type, nullptr, nullptr); + msgOp->send_message(from.asString().c_str(), to.asString().c_str(), content_type, nullptr, nullptr); ms_free(content_type); } else { auto msgOp = dynamic_cast(op); if (internalContent.getContentType().isValid()) { - msgOp->send_message(from.asString().c_str(), chatRoom->getPeerAddress().asString().c_str(), internalContent.getContentType().asString().c_str(), internalContent.getBodyAsString().c_str(), chatRoom->getPeerAddress().asStringUriOnly().c_str()); + msgOp->send_message(from.asString().c_str(), to.asString().c_str(), internalContent.getContentType().asString().c_str(), internalContent.getBodyAsString().c_str(), to.asStringUriOnly().c_str()); } else { - msgOp->send_message(from.asString().c_str(), chatRoom->getPeerAddress().asString().c_str(), internalContent.getBodyAsString().c_str()); + msgOp->send_message(from.asString().c_str(), to.asString().c_str(), internalContent.getBodyAsString().c_str()); } } @@ -1436,7 +1435,7 @@ void ChatMessage::sendDeliveryNotification(LinphoneReason reason) { LinphoneCore *lc = d->chatRoom->getCore(); LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); if (linphone_im_notif_policy_get_send_imdn_delivered(policy)) { - d->sendImdn(ImdnTypeDelivery, reason); + d->sendImdn(Imdn::Type::Delivery, reason); } } @@ -1445,7 +1444,7 @@ void ChatMessage::sendDisplayNotification() { LinphoneCore *lc = d->chatRoom->getCore(); LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); if (linphone_im_notif_policy_get_send_imdn_displayed(policy)) { - d->sendImdn(ImdnTypeDisplay, LinphoneReasonNone); + d->sendImdn(Imdn::Type::Display, LinphoneReasonNone); } } diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index f12b60850..c980b6566 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -187,46 +187,15 @@ void ChatRoomPrivate::sendIsComposingNotification () { L_Q(); LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(core); if (linphone_im_notif_policy_get_send_is_composing(policy)) { - LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str()); - LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core, peer); - const char *identity = nullptr; - - if (proxy) - identity = linphone_address_as_string(linphone_proxy_config_get_identity_address(proxy)); - else - identity = linphone_core_get_primary_contact(core); - - /* Sending out of call */ - SalMessageOp *op = new SalMessageOp(core->sal); - linphone_configure_op(core, op, peer, nullptr, !!lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0)); string payload = isComposingHandler.marshal(isComposing); if (!payload.empty()) { - int retval = -1; - shared_ptr msg = q->createMessage(); - msg->setFromAddress(Address(identity)); - msg->setToAddress(peerAddress); - Content content; content.setContentType("application/im-iscomposing+xml"); content.setBody(payload); msg->addContent(content); - - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(core); - if (imee) { - LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); - if (cbProcessOutgoingMessage) { - retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(q), L_GET_C_BACK_PTR(msg)); - } - } - - if (retval <= 0) { - op->send_message(identity, peerAddress.asString().c_str(), msg->getPrivate()->getContentType().asString().c_str(), msg->getPrivate()->getText().c_str(), nullptr); - } - op->unref(); + msg->getPrivate()->send(); } - linphone_address_unref(peer); } } @@ -561,7 +530,6 @@ void ChatRoom::compose () { } shared_ptr ChatRoom::createFileTransferMessage (const LinphoneContent *initialContent) { - L_D(); shared_ptr chatMessage = createMessage(); /* TODO @@ -570,31 +538,25 @@ shared_ptr ChatRoom::createFileTransferMessage (const LinphoneConte content.setBody(linphone_content_get_string_buffer(initialContent)); chatMessage->addContent(content);*/ - chatMessage->setToAddress(d->peerAddress); - chatMessage->setFromAddress(Address(linphone_core_get_identity(d->core))); chatMessage->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); chatMessage->getPrivate()->setFileTransferInformation(linphone_content_copy(initialContent)); - return chatMessage; } shared_ptr ChatRoom::createMessage (const string &message) { - L_D(); shared_ptr chatMessage = createMessage(); - Content content; content.setContentType(ContentType::PlainText); content.setBody(message); chatMessage->addContent(content); - - chatMessage->setToAddress(d->peerAddress); - chatMessage->setFromAddress(Address(linphone_core_get_identity(d->core))); - return chatMessage; } shared_ptr ChatRoom::createMessage () { + L_D(); shared_ptr chatMessage = ObjectFactory::create(getSharedFromThis()); + chatMessage->setToAddress(d->peerAddress); + chatMessage->setFromAddress(Address(linphone_core_get_identity(d->core))); chatMessage->getPrivate()->setTime(ms_time(0)); return chatMessage; } diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index b2b3c93e7..aee176244 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -245,8 +245,8 @@ void ClientGroupChatRoom::setSubject (const string &subject) { void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { L_D(); L_D_T(RemoteConference, dConference); - dConference->conferenceAddress = addr; + d->peerAddress = addr; d->setState(ChatRoom::State::Created); _linphone_core_add_group_chat_room(d->core, addr, L_GET_C_BACK_PTR(this)); } diff --git a/src/chat/cpim/message/cpim-message.cpp b/src/chat/cpim/message/cpim-message.cpp index 871dd83ba..54420470a 100644 --- a/src/chat/cpim/message/cpim-message.cpp +++ b/src/chat/cpim/message/cpim-message.cpp @@ -23,6 +23,7 @@ #include "logger/logger.h" #include "chat/cpim/parser/cpim-parser.h" +#include "content/content-type.h" #include "object/object-p.h" #include "cpim-message.h" @@ -137,7 +138,7 @@ bool Cpim::Message::isValid () const { return find_if(d->cpimHeaders->cbegin(), d->cpimHeaders->cend(), [](const shared_ptr &header) { - return Utils::iequals(header->getName(), "content-type") && header->getValue() == "Message/CPIM"; + return Utils::iequals(header->getName(), "content-type") && (ContentType(header->getValue()) == ContentType::Cpim); }) != d->cpimHeaders->cend(); } diff --git a/src/chat/cpim/parser/cpim-parser.cpp b/src/chat/cpim/parser/cpim-parser.cpp index 282b157f2..b54a9a45b 100644 --- a/src/chat/cpim/parser/cpim-parser.cpp +++ b/src/chat/cpim/parser/cpim-parser.cpp @@ -23,6 +23,7 @@ #include "linphone/utils/utils.h" #include "cpim-grammar.h" +#include "content/content-type.h" #include "logger/logger.h" #include "object/object-p.h" @@ -172,7 +173,7 @@ namespace Cpim { if (find_if(cpimHeaders->cbegin(), cpimHeaders->cend(), [](const shared_ptr &headerNode) { - return Utils::iequals(headerNode->getName(), "content-type") && headerNode->getValue() == "Message/CPIM"; + return Utils::iequals(headerNode->getName(), "content-type") && (ContentType(headerNode->getValue()) == ContentType::Cpim); }) == cpimHeaders->cend()) { lWarning() << "No MIME `Content-Type` found!"; return nullptr; diff --git a/src/chat/imdn.h b/src/chat/imdn.h index 933bae6e1..8bb57486a 100644 --- a/src/chat/imdn.h +++ b/src/chat/imdn.h @@ -32,6 +32,11 @@ class ChatRoom; class Imdn { public: + enum class Type { + Delivery, + Display + }; + static void parse (ChatRoom &cr, const std::string &content); private: From 505cceb22aa9dd66f227f7d7a0105dfa263b46d6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 13 Oct 2017 11:19:00 +0200 Subject: [PATCH 0468/2215] Allow overriding storeOrUpdateMessage() and messageReceived() methods of ChatRoomPrivate. --- src/chat/chat-room/chat-room-p.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chat/chat-room/chat-room-p.h b/src/chat/chat-room/chat-room-p.h index ee72788d5..4dd4663f6 100644 --- a/src/chat/chat-room/chat-room-p.h +++ b/src/chat/chat-room/chat-room-p.h @@ -65,10 +65,10 @@ protected: int sqlRequest (sqlite3 *db, const std::string &stmt); void sqlRequestMessage (sqlite3 *db, const std::string &stmt); std::list> findMessages (const std::string &messageId); - void storeOrUpdateMessage (const std::shared_ptr &msg); + virtual void storeOrUpdateMessage (const std::shared_ptr &msg); public: - LinphoneReason messageReceived (SalOp *op, const SalMessage *msg); + virtual LinphoneReason messageReceived (SalOp *op, const SalMessage *msg); void realtimeTextReceived (uint32_t character, LinphoneCall *call); protected: From 8ab95782bbf13a9dbc54721f557c23507370b9a1 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 13 Oct 2017 11:19:55 +0200 Subject: [PATCH 0469/2215] Fix state check in the send() method of ChatMessage. --- src/chat/chat-message/chat-message.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index a4b8678d6..d8f94593b 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -1422,8 +1422,10 @@ void ChatMessage::updateState(State state) { void ChatMessage::send () { L_D(); - if (d->state != State::NotDelivered) { - lWarning() << "Cannot resend chat message in state " << linphone_chat_message_state_to_string((LinphoneChatMessageState)d->state); + // Do not allow sending a message that is already being sent or that has been correctly delivered/displayed + if ((d->state == State::InProgress) || (d->state == State::Delivered) || (d->state == State::FileTransferDone) + || (d->state == State::DeliveredToUser) || (d->state == State::Displayed)) { + lWarning() << "Cannot send chat message in state " << linphone_chat_message_state_to_string((LinphoneChatMessageState)d->state); return; } From 3d50e6e9e2b53b5fcde3d952ea5a54997b6f9feb Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 13 Oct 2017 11:20:20 +0200 Subject: [PATCH 0470/2215] Handle From and To headers in CPIM messages. --- src/chat/chat-message/chat-message-p.h | 7 ++ src/chat/chat-message/chat-message.cpp | 65 ++++++++++--------- src/chat/chat-message/chat-message.h | 1 + src/chat/chat-room/chat-room.cpp | 1 + .../modifier/cpim-chat-message-modifier.cpp | 54 ++++++++++++++- .../modifier/cpim-chat-message-modifier.h | 3 + 6 files changed, 99 insertions(+), 32 deletions(-) diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index e62bff099..40f7ea492 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -55,6 +55,11 @@ public: // ----------------------------------------------------------------------------- + void setApplyModifiers (bool value) { applyModifiers = value; } + + const Address &getCpimFromAddress () const { return cpimFrom; } + void setCpimFromAddress (const Address &addr); + void setDirection (ChatMessage::Direction dir); void setState(ChatMessage::State state); @@ -124,6 +129,7 @@ private: unsigned int storageId = 0; Address from; Address to; + Address cpimFrom; time_t time = 0; std::string id; std::string appData; @@ -143,6 +149,7 @@ private: SalCustomHeader *salCustomHeaders = NULL; unsigned long backgroundTaskId; unsigned char currentSendStep = Step::None; + bool applyModifiers = true; // Cache for returned values, used for compatibility with previous C API ContentType cContentType; std::string cText; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index d8f94593b..bec65cd75 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -60,6 +60,11 @@ void ChatMessagePrivate::setChatRoom (shared_ptr cr) { chatRoom = cr; } +void ChatMessagePrivate::setCpimFromAddress (const Address &addr) { + cpimFrom = addr; + cpimFrom.clean(); +} + void ChatMessagePrivate::setDirection (ChatMessage::Direction dir) { direction = dir; } @@ -1132,41 +1137,43 @@ void ChatMessagePrivate::send() { } //End of TODO Remove - if ((currentSendStep & ChatMessagePrivate::Step::Multipart) == ChatMessagePrivate::Step::Multipart) { - lInfo() << "Multipart step already done, skipping"; - } else { - if (contents.size() > 1) { - MultipartChatMessageModifier mcmm; - mcmm.encode(q->getSharedFromThis(), errorCode); + if (applyModifiers) { + if ((currentSendStep & ChatMessagePrivate::Step::Multipart) == ChatMessagePrivate::Step::Multipart) { + lInfo() << "Multipart step already done, skipping"; + } else { + if (contents.size() > 1) { + MultipartChatMessageModifier mcmm; + mcmm.encode(q->getSharedFromThis(), errorCode); + } + currentSendStep |= ChatMessagePrivate::Step::Multipart; } - currentSendStep |= ChatMessagePrivate::Step::Multipart; - } - if ((currentSendStep & ChatMessagePrivate::Step::Encryption) == ChatMessagePrivate::Step::Encryption) { - lInfo() << "Encryption step already done, skipping"; - } else { - EncryptionChatMessageModifier ecmm; - ChatMessageModifier::Result result = ecmm.encode(q->getSharedFromThis(), errorCode); - if (result == ChatMessageModifier::Result::Error) { - sal_error_info_set((SalErrorInfo *)op->get_error_info(), SalReasonNotAcceptable, "SIP", errorCode, "Unable to encrypt IM", nullptr); - q->updateState(ChatMessage::State::NotDelivered); - q->store(); - return; - } else if (result == ChatMessageModifier::Result::Suspended) { + if ((currentSendStep & ChatMessagePrivate::Step::Encryption) == ChatMessagePrivate::Step::Encryption) { + lInfo() << "Encryption step already done, skipping"; + } else { + EncryptionChatMessageModifier ecmm; + ChatMessageModifier::Result result = ecmm.encode(q->getSharedFromThis(), errorCode); + if (result == ChatMessageModifier::Result::Error) { + sal_error_info_set((SalErrorInfo *)op->get_error_info(), SalReasonNotAcceptable, "SIP", errorCode, "Unable to encrypt IM", nullptr); + q->updateState(ChatMessage::State::NotDelivered); + q->store(); + return; + } else if (result == ChatMessageModifier::Result::Suspended) { + currentSendStep |= ChatMessagePrivate::Step::Encryption; + return; + } currentSendStep |= ChatMessagePrivate::Step::Encryption; - return; } - currentSendStep |= ChatMessagePrivate::Step::Encryption; - } - if ((currentSendStep & ChatMessagePrivate::Step::Cpim) == ChatMessagePrivate::Step::Cpim) { - lInfo() << "Cpim step already done, skipping"; - } else { - if (lp_config_get_int(chatRoom->getCore()->config, "sip", "use_cpim", 0) == 1) { - CpimChatMessageModifier ccmm; - ccmm.encode(q->getSharedFromThis(), errorCode); + if ((currentSendStep & ChatMessagePrivate::Step::Cpim) == ChatMessagePrivate::Step::Cpim) { + lInfo() << "Cpim step already done, skipping"; + } else { + if (lp_config_get_int(chatRoom->getCore()->config, "sip", "use_cpim", 0) == 1) { + CpimChatMessageModifier ccmm; + ccmm.encode(q->getSharedFromThis(), errorCode); + } + currentSendStep |= ChatMessagePrivate::Step::Cpim; } - currentSendStep |= ChatMessagePrivate::Step::Cpim; } // --------------------------------------- diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index 7a5504860..d4be49592 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -39,6 +39,7 @@ class ChatMessagePrivate; class LINPHONE_PUBLIC ChatMessage : public Object { friend class ChatRoom; friend class ChatRoomPrivate; + friend class CpimChatMessageModifier; friend class RealTimeTextChatRoomPrivate; public: diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index c980b6566..50dc7d370 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -557,6 +557,7 @@ shared_ptr ChatRoom::createMessage () { shared_ptr chatMessage = ObjectFactory::create(getSharedFromThis()); chatMessage->setToAddress(d->peerAddress); chatMessage->setFromAddress(Address(linphone_core_get_identity(d->core))); + chatMessage->getPrivate()->setCpimFromAddress(chatMessage->getFromAddress()); chatMessage->getPrivate()->setTime(ms_time(0)); return chatMessage; } diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index af0b0568d..e7e04d870 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -18,7 +18,7 @@ */ #include "address/address.h" -#include "chat/chat-message/chat-message.h" +#include "chat/chat-message/chat-message-p.h" #include "chat/cpim/cpim.h" #include "content/content-type.h" #include "content/content.h" @@ -36,9 +36,16 @@ ChatMessageModifier::Result CpimChatMessageModifier::encode (const shared_ptrgetPrivate()->getCpimFromAddress())); + cpimMessage.addMessageHeader(cpimFromHeader); + Cpim::ToHeader cpimToHeader; + cpimToHeader.setValue(cpimAddressAsString(message->getToAddress())); + cpimMessage.addMessageHeader(cpimToHeader); + Content content; if (!message->getInternalContent().isEmpty()) { // Another ChatMessageModifier was called before this one, we apply our changes on the private content @@ -93,11 +100,52 @@ ChatMessageModifier::Result CpimChatMessageModifier::decode (const shared_ptrgetContentHeaders()->front()->getValue())); + bool contentTypeFound = false; + Cpim::Message::HeaderList l = cpimMessage->getContentHeaders(); + if (l) { + for (const auto &header : *l.get()) { + if (header->getName() == "Content-Type") { + contentTypeFound = true; + newContent.setContentType(ContentType(header->getValue())); + break; + } + } + } + if (!contentTypeFound) { + lError() << "[CPIM] No Content-type for the content of the message"; + errorCode = 500; + return ChatMessageModifier::Result::Error; + } newContent.setBody(cpimMessage->getContent()); + + Address cpimFromAddress; + Address cpimToAddress; + l = cpimMessage->getMessageHeaders(); + if (l) { + for (const auto &header : *l.get()) { + if (header->getName() == "From") + cpimFromAddress = Address(header->getValue()); + else if (header->getName() == "To") + cpimToAddress = Address(header->getValue()); + } + } + + // Modify the initial message since there was no error message->setInternalContent(newContent); + if (cpimFromAddress.isValid()) + message->getPrivate()->setCpimFromAddress(cpimFromAddress); + if (cpimToAddress.isValid()) + message->setToAddress(cpimToAddress); return ChatMessageModifier::Result::Done; } +string CpimChatMessageModifier::cpimAddressAsString (const Address &addr) const { + ostringstream os; + if (!addr.getDisplayName().empty()) + os << addr.getDisplayName() << " "; + os << "<" << addr.asStringUriOnly() << ">"; + return os.str(); +} + LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/cpim-chat-message-modifier.h b/src/chat/modifier/cpim-chat-message-modifier.h index 7cb94c705..2b7488518 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.h +++ b/src/chat/modifier/cpim-chat-message-modifier.h @@ -32,6 +32,9 @@ public: Result encode (const std::shared_ptr &message, int &errorCode) override; Result decode (const std::shared_ptr &message, int &errorCode) override; + +private: + std::string cpimAddressAsString (const Address &addr) const; }; LINPHONE_END_NAMESPACE From 47824233aa3ceb18290fcb53f1a44171c3af42e9 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 13 Oct 2017 11:28:20 +0200 Subject: [PATCH 0471/2215] Handle receiving messages in a group chat room. --- coreapi/chat.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index b2fa26f1f..dad0c6940 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -156,11 +156,18 @@ LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const c } int linphone_core_message_received(LinphoneCore *lc, LinphonePrivate::SalOp *op, const SalMessage *sal_msg) { - LinphoneAddress *addr = linphone_address_new(sal_msg->from); - linphone_address_clean(addr); - LinphoneChatRoom *cr = linphone_core_get_chat_room(lc, addr); - LinphoneReason reason = L_GET_PRIVATE_FROM_C_OBJECT(cr)->messageReceived(op, sal_msg); - linphone_address_unref(addr); + LinphoneReason reason = LinphoneReasonNotAcceptable; + LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, op->get_from()); + if (cr) + reason = L_GET_PRIVATE_FROM_C_OBJECT(cr)->messageReceived(op, sal_msg); + else { + LinphoneAddress *addr = linphone_address_new(sal_msg->from); + linphone_address_clean(addr); + cr = linphone_core_get_chat_room(lc, addr); + if (cr) + reason = L_GET_PRIVATE_FROM_C_OBJECT(cr)->messageReceived(op, sal_msg); + linphone_address_unref(addr); + } return reason; } From 42b51aaaf3f7bab5664c1cc4dba93d48de252c7f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 13 Oct 2017 11:35:51 +0200 Subject: [PATCH 0472/2215] Uniformized set/get_passwd in set/get_password --- coreapi/authentication.c | 9 +- include/linphone/auth_info.h | 26 +++ wrappers/java/migration.sh | 375 ++++++++++++++++++----------------- 3 files changed, 230 insertions(+), 180 deletions(-) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 17d84508b..4d8603f63 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -83,6 +83,10 @@ const char *linphone_auth_info_get_username(const LinphoneAuthInfo *i) { } const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo *i) { + return linphone_auth_info_get_password(i); +} + +const char *linphone_auth_info_get_password(const LinphoneAuthInfo *i) { return i->passwd; } @@ -118,8 +122,11 @@ const char *linphone_auth_info_get_tls_key_path(const LinphoneAuthInfo *i) { return i->tls_key_path; } - void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd) { + linphone_auth_info_set_password(info, passwd); +} + +void linphone_auth_info_set_password(LinphoneAuthInfo *info, const char *passwd) { if (info->passwd) { ms_free(info->passwd); info->passwd = NULL; diff --git a/include/linphone/auth_info.h b/include/linphone/auth_info.h index 4a00e324d..1e780f3cf 100644 --- a/include/linphone/auth_info.h +++ b/include/linphone/auth_info.h @@ -78,6 +78,22 @@ LINPHONE_PUBLIC void linphone_auth_info_unref(LinphoneAuthInfo *info); **/ LINPHONE_PUBLIC void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd); +/** + * Sets the password. + * @param[in] info The #LinphoneAuthInfo object + * @param[in] passwd The password. + * @deprecated, use linphone_auth_info_set_password instead + * @donotwrap +**/ +LINPHONE_PUBLIC void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd); + +/** + * Sets the password. + * @param[in] info The #LinphoneAuthInfo object + * @param[in] passwd The password. +**/ +LINPHONE_PUBLIC void linphone_auth_info_set_password(LinphoneAuthInfo *info, const char *passwd); + /** * Sets the username. * @param[in] info The #LinphoneAuthInfo object @@ -154,9 +170,19 @@ LINPHONE_PUBLIC const char *linphone_auth_info_get_username(const LinphoneAuthIn * Gets the password. * @param[in] info The #LinphoneAuthInfo object * @return The password. + * @deprecated, use linphone_auth_info_get_password instead + * @donotwrap */ LINPHONE_PUBLIC const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo *info); +/** + * Gets the password. + * @param[in] info The #LinphoneAuthInfo object + * @return The password. + */ +LINPHONE_PUBLIC const char *linphone_auth_info_get_password(const LinphoneAuthInfo *info); + + /** * Gets the userid. * @param[in] info The #LinphoneAuthInfo object diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index d14eeb439..2c74ed8d6 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -1,212 +1,229 @@ #!/bin/sh -SRC_DIR="src/android/org/linphone/*.java" +SED_START='find ./src/android/org/linphone/ -type f -exec sed -i -e ' +SED_END='{} \;' # Listeners -sed -i 's/AccountCreator.AccountCreatorListener/AccountCreatorListener/g' $SRC_DIR -sed -i 's/LinphoneCoreListenerBase/CoreListenerStub/g' $SRC_DIR -sed -i 's/LinphoneCoreListener/CoreListener/g' $SRC_DIR -sed -i 's/LinphoneChatMessage.LinphoneChatMessageListener/ChatMessageListener/g' $SRC_DIR -sed -i 's/AccountCreator.AccountCreatorListener/AccountCreatorListener/g' $SRC_DIR +eval "$SED_START 's/AccountCreator.AccountCreatorListener/AccountCreatorListener/g' $SED_END" +eval "$SED_START 's/LinphoneCoreListenerBase/CoreListenerStub/g' $SED_END" +eval "$SED_START 's/LinphoneCoreListener/CoreListener/g' $SED_END" +eval "$SED_START 's/LinphoneChatMessage.LinphoneChatMessageListener/ChatMessageListener/g' $SED_END" # Enums -sed -i 's/Core.LinphoneLimeState/Core.LimeState/g' $SRC_DIR -sed -i 's/LinphoneLimeState/LimeState/g' $SRC_DIR +eval "$SED_START 's/Core.LinphoneLimeState/Core.LimeState/g' $SED_END" +eval "$SED_START 's/LinphoneLimeState/LimeState/g' $SED_END" -sed -i 's/GlobalState.GlobalOn/Core.GlobalState.On/g' $SRC_DIR +eval "$SED_START 's/GlobalState.GlobalOn/Core.GlobalState.On/g' $SED_END" -sed -i 's/RegistrationState.RegistrationOk/RegistrationState.Ok/g' $SRC_DIR -sed -i 's/RegistrationState.RegistrationFailed/RegistrationState.Failed/g' $SRC_DIR -sed -i 's/RegistrationState.RegistrationCleared/RegistrationState.Cleared/g' $SRC_DIR -sed -i 's/RegistrationState.RegistrationProgress/RegistrationState.Progress/g' $SRC_DIR +eval "$SED_START 's/RegistrationState.RegistrationOk/RegistrationState.Ok/g' $SED_END" +eval "$SED_START 's/RegistrationState.RegistrationFailed/RegistrationState.Failed/g' $SED_END" +eval "$SED_START 's/RegistrationState.RegistrationCleared/RegistrationState.Cleared/g' $SED_END" +eval "$SED_START 's/RegistrationState.RegistrationProgress/RegistrationState.Progress/g' $SED_END" -sed -i 's/RemoteProvisioningState.ConfiguringSuccessful/ConfiguringState.Successful/g' $SRC_DIR -sed -i 's/LinphoneCore.RemoteProvisioningState/Core.ConfiguringState/g' $SRC_DIR -sed -i 's/RemoteProvisioningState/ConfiguringState/g' $SRC_DIR +eval "$SED_START 's/RemoteProvisioningState.ConfiguringSuccessful/ConfiguringState.Successful/g' $SED_END" +eval "$SED_START 's/LinphoneCore.RemoteProvisioningState/Core.ConfiguringState/g' $SED_END" +eval "$SED_START 's/RemoteProvisioningState/ConfiguringState/g' $SED_END" +eval "$SED_START 's/ConfiguringFailed/Failed/g' $SED_END" -sed -i 's/CallDirection/Call.Dir/g' $SRC_DIR +eval "$SED_START 's/CallDirection/Call.Dir/g' $SED_END" -sed -i 's/State.CallReleased/State.Released/g' $SRC_DIR -sed -i 's/State.CallEnd/State.End/g' $SRC_DIR -sed -i 's/State.CallUpdatedByRemote/State.UpdatedByRemote/g' $SRC_DIR -sed -i 's/State.CallIncomingEarlyMedia/State.IncomingEarlyMedia/g' $SRC_DIR -sed -i 's/State.CallUpdating/State.Updating/g' $SRC_DIR +eval "$SED_START 's/State.CallReleased/State.Released/g' $SED_END" +eval "$SED_START 's/State.CallEnd/State.End/g' $SED_END" +eval "$SED_START 's/State.CallUpdatedByRemote/State.UpdatedByRemote/g' $SED_END" +eval "$SED_START 's/State.CallIncomingEarlyMedia/State.IncomingEarlyMedia/g' $SED_END" +eval "$SED_START 's/State.CallUpdating/State.Updating/g' $SED_END" -sed -i 's/LogCollectionUploadState.LogCollectionUploadStateInProgress/LogCollectionUploadState.InProgress/g' $SRC_DIR -sed -i 's/LogCollectionUploadState.LogCollectionUploadStateDelivered/LogCollectionUploadState.Delivered/g' $SRC_DIR -sed -i 's/LogCollectionUploadState.LogCollectionUploadStateNotDelivered/LogCollectionUploadState.NotDelivered/g' $SRC_DIR +eval "$SED_START 's/LogCollectionUploadState.LogCollectionUploadStateInProgress/LogCollectionUploadState.InProgress/g' $SED_END" +eval "$SED_START 's/LogCollectionUploadState.LogCollectionUploadStateDelivered/LogCollectionUploadState.Delivered/g' $SED_END" +eval "$SED_START 's/LogCollectionUploadState.LogCollectionUploadStateNotDelivered/LogCollectionUploadState.NotDelivered/g' $SED_END" -sed -i 's/AccountCreator.RequestStatus/AccountCreator.Status/g' $SRC_DIR -sed -i 's/AccountCreator.Status.Ok/AccountCreator.Status.RequestOk/g' $SRC_DIR -sed -i 's/AccountCreator.PasswordCheck/AccountCreator.PasswordStatus/g' $SRC_DIR -sed -i 's/AccountCreator.PhoneNumberCheck/AccountCreator.PhoneNumberStatus/g' $SRC_DIR -sed -i 's/AccountCreator.EmailCheck/AccountCreator.EmailStatus/g' $SRC_DIR -sed -i 's/AccountCreator.UsernameCheck/AccountCreator.UsernameStatus/g' $SRC_DIR -sed -i 's/AccountCreator.Status.Failed/AccountCreator.Status.RequestFailed/g' $SRC_DIR -sed -i 's/AccountCreator.Status.ErrorServer/AccountCreator.Status.ServerError/g' $SRC_DIR +eval "$SED_START 's/AccountCreator.RequestStatus/AccountCreator.Status/g' $SED_END" +eval "$SED_START 's/AccountCreator.Status.Ok/AccountCreator.Status.RequestOk/g' $SED_END" +eval "$SED_START 's/AccountCreator.PasswordCheck/AccountCreator.PasswordStatus/g' $SED_END" +eval "$SED_START 's/AccountCreator.PhoneNumberCheck/AccountCreator.PhoneNumberStatus/g' $SED_END" +eval "$SED_START 's/AccountCreator.EmailCheck/AccountCreator.EmailStatus/g' $SED_END" +eval "$SED_START 's/AccountCreator.UsernameCheck/AccountCreator.UsernameStatus/g' $SED_END" +eval "$SED_START 's/AccountCreator.Status.Failed/AccountCreator.Status.RequestFailed/g' $SED_END" +eval "$SED_START 's/AccountCreator.Status.ErrorServer/AccountCreator.Status.ServerError/g' $SED_END" -sed -i 's/Reason.Media/Reason.NotAcceptable/g' $SRC_DIR -sed -i 's/Reason.BadCredentials/Reason.Forbidden/g' $SRC_DIR +eval "$SED_START 's/Reason.Media/Reason.NotAcceptable/g' $SED_END" +eval "$SED_START 's/Reason.BadCredentials/Reason.Forbidden/g' $SED_END" -sed -i 's/TransportType.LinphoneTransportUdp/TransportType.Udp/g' $SRC_DIR -sed -i 's/TransportType.LinphoneTransportTcp/TransportType.Tcp/g' $SRC_DIR -sed -i 's/TransportType.LinphoneTransportTls/TransportType.Tls/g' $SRC_DIR -sed -i 's/TransportType.LinphoneTransportDtls/TransportType.Dtls/g' $SRC_DIR +eval "$SED_START 's/TransportType.LinphoneTransportUdp/TransportType.Udp/g' $SED_END" +eval "$SED_START 's/TransportType.LinphoneTransportTcp/TransportType.Tcp/g' $SED_END" +eval "$SED_START 's/TransportType.LinphoneTransportTls/TransportType.Tls/g' $SED_END" +eval "$SED_START 's/TransportType.LinphoneTransportDtls/TransportType.Dtls/g' $SED_END" + +eval "$SED_START 's/AddressFamily.INET_6.getInt()/AddressFamily.Inet6.toInt()/g' $SED_END" +eval "$SED_START 's/AddressFamily.INET.getInt()/AddressFamily.Inet.toInt()/g' $SED_END" # Classes -sed -i 's/LpConfig/Config/g' $SRC_DIR -sed -i 's/LinphoneCoreException/CoreException/g' $SRC_DIR -sed -i 's/LinphoneCoreFactory/Factory/g' $SRC_DIR -sed -i 's/LinphoneAccountCreator/AccountCreator/g' $SRC_DIR -sed -i 's/LinphoneAddress/Address/g' $SRC_DIR -sed -i 's/LinphoneAuthInfo/AuthInfo/g' $SRC_DIR -sed -i 's/LinphoneCallLog/CallLog/g' $SRC_DIR -sed -i 's/LinphoneCallParams/CallParams/g' $SRC_DIR -sed -i 's/LinphoneCallStats/CallStats/g' $SRC_DIR -sed -i 's/LinphoneCall/Call/g' $SRC_DIR -sed -i 's/LinphoneChatMessage/ChatMessage/g' $SRC_DIR -sed -i 's/LinphoneChatRoom/ChatRoom/g' $SRC_DIR -sed -i 's/LinphoneConferenceParams/ConferenceParams/g' $SRC_DIR -sed -i 's/LinphoneConference/Conference/g' $SRC_DIR -sed -i 's/LinphoneConfig/Config/g' $SRC_DIR -sed -i 's/LinphoneContent/Content/g' $SRC_DIR -sed -i 's/LinphoneCore/Core/g' $SRC_DIR -sed -i 's/LinphoneEvent/Event/g' $SRC_DIR -sed -i 's/LinphoneFriendList/FriendList/g' $SRC_DIR -sed -i 's/LinphoneFriend/Friend/g' $SRC_DIR -sed -i 's/LinphoneHeaders/Headers/g' $SRC_DIR -sed -i 's/LinphoneImNotifyPolicy/ImNotifyPolicy/g' $SRC_DIR -sed -i 's/LinphoneInfoMessage/InfoMessage/g' $SRC_DIR -sed -i 's/LinphoneNatPolicy/NatPolicy/g' $SRC_DIR -sed -i 's/LinphonePayloadType/PayloadType/g' $SRC_DIR -sed -i 's/LinphonePlayer/Player/g' $SRC_DIR -sed -i 's/LinphonePresence/Presence/g' $SRC_DIR -sed -i 's/LinphonePrivacy/Privacy/g' $SRC_DIR -sed -i 's/LinphoneProxyConfig/ProxyConfig/g' $SRC_DIR -sed -i 's/LinphonePublishState/PublishState/g' $SRC_DIR -sed -i 's/LinphoneRange/Range/g' $SRC_DIR -sed -i 's/LinphoneStreamType/StreamType/g' $SRC_DIR -sed -i 's/LinphoneSubscription/Subscription/g' $SRC_DIR -sed -i 's/LinphoneTransports/Transports/g' $SRC_DIR -sed -i 's/LinphoneTunnel/Tunnel/g' $SRC_DIR -sed -i 's/LinphoneVcard/Vcard/g' $SRC_DIR -sed -i 's/LinphoneXmlRpc/XmlRpc/g' $SRC_DIR +eval "$SED_START 's/LpConfig/Config/g' $SED_END" +eval "$SED_START 's/LinphoneCoreException/CoreException/g' $SED_END" +eval "$SED_START 's/LinphoneCoreFactory/Factory/g' $SED_END" +eval "$SED_START 's/LinphoneAccountCreator/AccountCreator/g' $SED_END" +eval "$SED_START 's/LinphoneAddress/Address/g' $SED_END" +eval "$SED_START 's/LinphoneAuthInfo/AuthInfo/g' $SED_END" +eval "$SED_START 's/LinphoneCallLog/CallLog/g' $SED_END" +eval "$SED_START 's/LinphoneCallParams/CallParams/g' $SED_END" +eval "$SED_START 's/LinphoneCallStats/CallStats/g' $SED_END" +eval "$SED_START 's/LinphoneCall/Call/g' $SED_END" +eval "$SED_START 's/LinphoneChatMessage/ChatMessage/g' $SED_END" +eval "$SED_START 's/LinphoneChatRoom/ChatRoom/g' $SED_END" +eval "$SED_START 's/LinphoneConferenceParams/ConferenceParams/g' $SED_END" +eval "$SED_START 's/LinphoneConference/Conference/g' $SED_END" +eval "$SED_START 's/LinphoneConfig/Config/g' $SED_END" +eval "$SED_START 's/LinphoneContent/Content/g' $SED_END" +eval "$SED_START 's/LinphoneCore/Core/g' $SED_END" +eval "$SED_START 's/LinphoneEvent/Event/g' $SED_END" +eval "$SED_START 's/LinphoneFriendList/FriendList/g' $SED_END" +eval "$SED_START 's/LinphoneFriend/Friend/g' $SED_END" +eval "$SED_START 's/LinphoneHeaders/Headers/g' $SED_END" +eval "$SED_START 's/LinphoneImNotifyPolicy/ImNotifyPolicy/g' $SED_END" +eval "$SED_START 's/LinphoneInfoMessage/InfoMessage/g' $SED_END" +eval "$SED_START 's/LinphoneNatPolicy/NatPolicy/g' $SED_END" +eval "$SED_START 's/LinphonePayloadType/PayloadType/g' $SED_END" +eval "$SED_START 's/LinphonePlayer/Player/g' $SED_END" +eval "$SED_START 's/LinphonePresence/Presence/g' $SED_END" +eval "$SED_START 's/LinphonePrivacy/Privacy/g' $SED_END" +eval "$SED_START 's/LinphoneProxyConfig/ProxyConfig/g' $SED_END" +eval "$SED_START 's/LinphonePublishState/PublishState/g' $SED_END" +eval "$SED_START 's/LinphoneRange/Range/g' $SED_END" +eval "$SED_START 's/LinphoneStreamType/StreamType/g' $SED_END" +eval "$SED_START 's/LinphoneSubscription/Subscription/g' $SED_END" +eval "$SED_START 's/LinphoneTransports/Transports/g' $SED_END" +eval "$SED_START 's/LinphoneTunnel/Tunnel/g' $SED_END" +eval "$SED_START 's/LinphoneVcard/Vcard/g' $SED_END" +eval "$SED_START 's/LinphoneXmlRpc/XmlRpc/g' $SED_END" -#Callbacks -sed -i 's/onChatMessageStateChanged/onMsgStateChanged/g' $SRC_DIR -sed -i 's/onChatMessageFileTransferProgressChanged/onFileTransferProgressIndication/g' $SRC_DIR +# Callbacks +eval "$SED_START 's/onChatMessageStateChanged/onMsgStateChanged/g' $SED_END" +eval "$SED_START 's/onChatMessageFileTransferProgressChanged/onFileTransferProgressIndication/g' $SED_END" +eval "$SED_START 's/registrationState/onRegistrationStateChanged/g' $SED_END" -#Methods -sed -i 's/getFriendList(/getFriendsLists(/g' $SRC_DIR -sed -i 's/getFriendLists()/getFriendsLists()/g' $SRC_DIR -sed -i 's/getIdentity(/getIdentityAddress(/g' $SRC_DIR -sed -i 's/isTunnelAvailable()/tunnelAvailable()/g' $SRC_DIR -sed -i 's/setZrtpSecretsCache(/setZrtpSecretsFile(/g' $SRC_DIR -sed -i 's/setRootCA(/setRootCa(/g' $SRC_DIR -sed -i 's/isInComingInvitePending()/isIncomingInvitePending()/g' $SRC_DIR -sed -i 's/getAudioCodecs()/getAudioPayloadTypes()/g' $SRC_DIR -sed -i 's/getVideoCodecs()/getVideoPayloadTypes()/g' $SRC_DIR -sed -i 's/getMime()/getMimeType()/g' $SRC_DIR -sed -i 's/getFrom()/getFromAddress()/g' $SRC_DIR -sed -i 's/getTo()/getToAddress()/g' $SRC_DIR -sed -i 's/getUserName()/getUsername()/g' $SRC_DIR -sed -i 's/getLimeEncryption()/limeEnabled()/g' $SRC_DIR -sed -i 's/getDirection/getDir/g' $SRC_DIR -sed -i 's/.getVideoEnabled()/.videoEnabled()/g' $SRC_DIR -sed -i 's/.getDataAsString()/.getStringBuffer()/g' $SRC_DIR -sed -i 's/getEventName()/getName()/g' $SRC_DIR -sed -i 's/setPlaybackGain(/setPlaybackGainDb(/g' $SRC_DIR -sed -i 's/isIncall()/inCall()/g' $SRC_DIR -sed -i 's/setVideoEnabled(/enableVideo(/g' $SRC_DIR -sed -i 's/setAudioBandwidth(/setAudioBandwidthLimit(/g' $SRC_DIR -sed -i 's/isAuthenticationTokenVerified()/getAuthenticationTokenVerified()/g' $SRC_DIR -sed -i 's/isMicMuted()/!micEnabled()/g' $SRC_DIR -sed -i 's/isLowBandwidthEnabled()/lowBandwidthEnabled()/g' $SRC_DIR -sed -i 's/muteMic(/enableMic(!/g' $SRC_DIR -sed -i 's/getRate()/getClockRate()/g' $SRC_DIR -sed -i 's/getSentVideoSize()/getSentVideoDefinition()/g' $SRC_DIR -sed -i 's/getReceivedVideoSize()/getReceivedVideoDefinition()/g' $SRC_DIR -sed -i 's/getUsedAudioCodec()/getUsedAudioPayloadType()/g' $SRC_DIR -sed -i 's/getUsedVideoCodec()/getUsedVideoPayloadType()/g' $SRC_DIR -sed -i 's/setVideoWindow(/setNativeVideoWindowId(/g' $SRC_DIR -sed -i 's/setPreviewWindow(/setNativePreviewWindowId(/g' $SRC_DIR -sed -i 's/islimeAvailable()/limeAvailable()/g' $SRC_DIR -sed -i 's/createChatMessage(/createMessage(/g' $SRC_DIR +# Methods +eval "$SED_START 's/getFriendList(/getFriendsLists(/g' $SED_END" +eval "$SED_START 's/getFriendLists()/getFriendsLists()/g' $SED_END" +eval "$SED_START 's/getIdentity(/getIdentityAddress(/g' $SED_END" +eval "$SED_START 's/isTunnelAvailable()/tunnelAvailable()/g' $SED_END" +eval "$SED_START 's/setZrtpSecretsCache(/setZrtpSecretsFile(/g' $SED_END" +eval "$SED_START 's/setRootCA(/setRootCa(/g' $SED_END" +eval "$SED_START 's/isInComingInvitePending()/isIncomingInvitePending()/g' $SED_END" +eval "$SED_START 's/getAudioCodecs()/getAudioPayloadTypes()/g' $SED_END" +eval "$SED_START 's/getVideoCodecs()/getVideoPayloadTypes()/g' $SED_END" +eval "$SED_START 's/getMime()/getMimeType()/g' $SED_END" +eval "$SED_START 's/getFrom()/getFromAddress()/g' $SED_END" +eval "$SED_START 's/getTo()/getToAddress()/g' $SED_END" +eval "$SED_START 's/getUserName()/getUsername()/g' $SED_END" +eval "$SED_START 's/getLimeEncryption()/limeEnabled()/g' $SED_END" +eval "$SED_START 's/getDirection/getDir/g' $SED_END" +eval "$SED_START 's/.getVideoEnabled()/.videoEnabled()/g' $SED_END" +eval "$SED_START 's/.getDataAsString()/.getStringBuffer()/g' $SED_END" +eval "$SED_START 's/getEventName()/getName()/g' $SED_END" +eval "$SED_START 's/setPlaybackGain(/setPlaybackGainDb(/g' $SED_END" +eval "$SED_START 's/isIncall()/inCall()/g' $SED_END" +eval "$SED_START 's/setVideoEnabled(/enableVideo(/g' $SED_END" +eval "$SED_START 's/setAudioBandwidth(/setAudioBandwidthLimit(/g' $SED_END" +eval "$SED_START 's/isAuthenticationTokenVerified()/getAuthenticationTokenVerified()/g' $SED_END" +eval "$SED_START 's/isMicMuted()/!micEnabled()/g' $SED_END" +eval "$SED_START 's/isLowBandwidthEnabled()/lowBandwidthEnabled()/g' $SED_END" +eval "$SED_START 's/muteMic(/enableMic(!/g' $SED_END" +eval "$SED_START 's/getRate()/getClockRate()/g' $SED_END" +eval "$SED_START 's/getSentVideoSize()/getSentVideoDefinition()/g' $SED_END" +eval "$SED_START 's/getReceivedVideoSize()/getReceivedVideoDefinition()/g' $SED_END" +eval "$SED_START 's/getUsedAudioCodec()/getUsedAudioPayloadType()/g' $SED_END" +eval "$SED_START 's/getUsedVideoCodec()/getUsedVideoPayloadType()/g' $SED_END" +eval "$SED_START 's/setVideoWindow(/setNativeVideoWindowId(/g' $SED_END" +eval "$SED_START 's/setPreviewWindow(/setNativePreviewWindowId(/g' $SED_END" +eval "$SED_START 's/islimeAvailable()/limeAvailable()/g' $SED_END" +eval "$SED_START 's/createChatMessage(/createMessage(/g' $SED_END" #For messages only -sed -i 's/message.getStatus()/message.getState()/g' $SRC_DIR +eval "$SED_START 's/message.getStatus()/message.getState()/g' $SED_END" # -sed -i 's/reSend()/resend()/g' $SRC_DIR -sed -i 's/setAppData(/setAppdata(/g' $SRC_DIR -sed -i 's/getAppData()/getAppdata()/g' $SRC_DIR -sed -i 's/getOrCreateChatRoom(/getChatRoomFromUri(/g' $SRC_DIR -sed -i 's/findFriendByAddress(/findFriend(/g' $SRC_DIR -sed -i 's/getTimestamp()/getStartDate()/g' $SRC_DIR +eval "$SED_START 's/reSend()/resend()/g' $SED_END" +eval "$SED_START 's/setAppData(/setAppdata(/g' $SED_END" +eval "$SED_START 's/getAppData()/getAppdata()/g' $SED_END" +eval "$SED_START 's/getOrCreateChatRoom(/getChatRoomFromUri(/g' $SED_END" +eval "$SED_START 's/findFriendByAddress(/findFriend(/g' $SED_END" +eval "$SED_START 's/getTimestamp()/getStartDate()/g' $SED_END" #For ProxyConfigs only -sed -i 's/lpc.getAddress()/lpc.getIdentityAddress()/g' $SRC_DIR +eval "$SED_START 's/lpc.getAddress()/lpc.getIdentityAddress()/g' $SED_END" +eval "$SED_START 's/cfg.getAddress()/lpc.getIdentityAddress()/g' $SED_END" # -sed -i 's/getCallDuration()/getDuration()/g' $SRC_DIR -sed -i 's/isVCardSupported()/vcardSupported()/g' $SRC_DIR -sed -i 's/getPresenceModelForUri(/getPresenceModelForUriOrTel(/g' $SRC_DIR -sed -i 's/setAvpfRRInterval(/setAvpfRrInterval(/g' $SRC_DIR -sed -i 's/getProxy()/getServerAddr()/g' $SRC_DIR -sed -i 's/setProxy(/setServerAddr(/g' $SRC_DIR -sed -i 's/setIdentity(/setIdentityAddress(/g' $SRC_DIR -sed -i 's/setUserId(/setUserid(/g' $SRC_DIR -sed -i 's/getUserId(/getUserid/g' $SRC_DIR -sed -i 's/getAuthInfosList(/getAuthInfoList(/g' $SRC_DIR -sed -i 's/getPassword/getPasswd(/g' $SRC_DIR -sed -i 's/getSignalingTransportPorts()/getTransports()/g' $SRC_DIR -sed -i 's/setSignalingTransportPorts(/setTransports(/g' $SRC_DIR -sed -i 's/isIpv6Enabled()/ipv6Enabled()/g' $SRC_DIR -sed -i 's/isAdaptiveRateControlEnabled()/adaptiveRateControlEnabled()/g' $SRC_DIR -sed -i 's/setLimeEncryption(/enableLime(/g' $SRC_DIR +eval "$SED_START 's/getCallDuration()/getDuration()/g' $SED_END" +eval "$SED_START 's/isVCardSupported()/vcardSupported()/g' $SED_END" +eval "$SED_START 's/getPresenceModelForUri(/getPresenceModelForUriOrTel(/g' $SED_END" +eval "$SED_START 's/setAvpfRRInterval(/setAvpfRrInterval(/g' $SED_END" +eval "$SED_START 's/getProxy()/getServerAddr()/g' $SED_END" +eval "$SED_START 's/setProxy(/setServerAddr(/g' $SED_END" +eval "$SED_START 's/setIdentity(/setIdentityAddress(/g' $SED_END" +eval "$SED_START 's/setUserId(/setUserid(/g' $SED_END" +eval "$SED_START 's/getUserId(/getUserid(/g' $SED_END" +eval "$SED_START 's/getAuthInfosList(/getAuthInfoList(/g' $SED_END" +eval "$SED_START 's/getSignalingTransportPorts()/getTransports()/g' $SED_END" +eval "$SED_START 's/setSignalingTransportPorts(/setTransports(/g' $SED_END" +eval "$SED_START 's/isIpv6Enabled()/ipv6Enabled()/g' $SED_END" +eval "$SED_START 's/isAdaptiveRateControlEnabled()/adaptiveRateControlEnabled()/g' $SED_END" +eval "$SED_START 's/setLimeEncryption(/enableLime(/g' $SED_END" #For enums only -sed -i 's/.value()/.toInt()/g' $SRC_DIR +eval "$SED_START 's/.value()/.toInt()/g' $SED_END" # -sed -i 's/clearAuthInfos()/clearAllAuthInfo()/g' $SRC_DIR -sed -i 's/clearProxyConfigs()/clearProxyConfig()/g' $SRC_DIR -sed -i 's/isVideoSupported()/videoSupported()/g' $SRC_DIR +eval "$SED_START 's/clearAuthInfos()/clearAllAuthInfo()/g' $SED_END" +eval "$SED_START 's/clearProxyConfigs()/clearProxyConfig()/g' $SED_END" +eval "$SED_START 's/isVideoSupported()/videoSupported()/g' $SED_END" +eval "$SED_START 's/VideoDefinition().toDisplayableString()/VideoDefinition().getName()/g' $SED_END" +eval "$SED_START 's/isAccountUsed/isAccountExist()/g' $SED_END" +eval "$SED_START 's/loadXmlFile(/loadFromXmlFile(/g' $SED_END" +eval "$SED_START 's/activatePhoneNumberLink()/activateAlias()/g' $SED_END" +eval "$SED_START 's//g' $SED_END" -#Removed methods -sed -i 's/.isRegistered()/.getState() == RegistrationState.Ok/g' $SRC_DIR -sed -i 's/getBool(/getInt(/g' $SRC_DIR -sed -i 's/setBool(/setInt(/g' $SRC_DIR -sed -i 's/isInConference()/getConference() != null/g' $SRC_DIR -sed -i 's/getAudioStats()/getStats(StreamType.Audio)/g' $SRC_DIR -sed -i 's/getVideoStats()/getStats(StreamType.Audio)/g' $SRC_DIR -sed -i 's/getVcardToString()/getVcard().asVcard4String()/g' $SRC_DIR -sed -i 's/getVideoAutoInitiatePolicy()/getVideoActivationPolicy().getAutomaticallyInitiate()/g' $SRC_DIR -sed -i 's/setFamilyName(/getVcard().setFamilyName(/g' $SRC_DIR -sed -i 's/setGivenName(/getVcard().setGivenName(/g' $SRC_DIR -sed -i 's/setOrganization(/getVcard().setOrganization(/g' $SRC_DIR -sed -i 's/getFamilyName()/getVcard().getFamilyName()/g' $SRC_DIR -sed -i 's/getGivenName()/getVcard().getGivenName()/g' $SRC_DIR -sed -i 's/getOrganization()/getVcard().getOrganization()/g' $SRC_DIR -sed -i 's/enableAvpf(/setAvpfMode(AVPFMode.Enabled)/g' $SRC_DIR -sed -i 's/transports.udp = /transports.setUdpPort(/g' $SRC_DIR -sed -i 's/transports.tcp = /transports.setTcpPort(/g' $SRC_DIR -sed -i 's/transports.tls = /transports.setTlsPort(/g' $SRC_DIR -sed -i 's/transports.udp/transports.getUdpPort()/g' $SRC_DIR -sed -i 's/transports.tcp/transports.getTcpPort()/g' $SRC_DIR -sed -i 's/transports.tls/transports.getTlsPort()/g' $SRC_DIR -sed -i 's/getPrimaryContactUsername()/getPrimaryContactParsed().getUsername()/g' $SRC_DIR -sed -i 's/getPrimaryContactDisplayName()/getPrimaryContactParsed().getDisplayName()/g' $SRC_DIR +# Removed methods +eval "$SED_START 's/.isRegistered()/.getState() == RegistrationState.Ok/g' $SED_END" +eval "$SED_START 's/getBool(/getInt(/g' $SED_END" +eval "$SED_START 's/setBool(/setInt(/g' $SED_END" +eval "$SED_START 's/isInConference()/getConference() != null/g' $SED_END" +eval "$SED_START 's/getAudioStats()/getStats(StreamType.Audio)/g' $SED_END" +eval "$SED_START 's/getVideoStats()/getStats(StreamType.Video)/g' $SED_END" +eval "$SED_START 's/getVcardToString()/getVcard().asVcard4String()/g' $SED_END" +eval "$SED_START 's/getVideoAutoInitiatePolicy()/getVideoActivationPolicy().getAutomaticallyInitiate()/g' $SED_END" +eval "$SED_START 's/setFamilyName(/getVcard().setFamilyName(/g' $SED_END" +eval "$SED_START 's/setGivenName(/getVcard().setGivenName(/g' $SED_END" +eval "$SED_START 's/setOrganization(/getVcard().setOrganization(/g' $SED_END" +eval "$SED_START 's/getFamilyName()/getVcard().getFamilyName()/g' $SED_END" +eval "$SED_START 's/getGivenName()/getVcard().getGivenName()/g' $SED_END" +eval "$SED_START 's/getOrganization()/getVcard().getOrganization()/g' $SED_END" +eval "$SED_START 's/enableAvpf(/setAvpfMode(AVPFMode.Enabled)/g' $SED_END" +eval "$SED_START 's/transports.udp = /transports.setUdpPort(/g' $SED_END" +eval "$SED_START 's/transports.tcp = /transports.setTcpPort(/g' $SED_END" +eval "$SED_START 's/transports.tls = /transports.setTlsPort(/g' $SED_END" +eval "$SED_START 's/transports.udp/transports.getUdpPort()/g' $SED_END" +eval "$SED_START 's/transports.tcp/transports.getTcpPort()/g' $SED_END" +eval "$SED_START 's/transports.tls/transports.getTlsPort()/g' $SED_END" +eval "$SED_START 's/getPrimaryContactUsername()/getPrimaryContactParsed().getUsername()/g' $SED_END" +eval "$SED_START 's/getPrimaryContactDisplayName()/getPrimaryContactParsed().getDisplayName()/g' $SED_END" -#Have disapeared, to check +#Changes in library required #OpenH264DownloadHelper +#DialPlan +#LinphoneBuffer +#Call.zoomVideo() + +#Android specifics not wrapped automatically +#Core.needsEchoCalibration() +#Core.hasCrappyOpenGL() +#Core.getMSFactory() + +# For the payloads, get the list from the Core, call the method on the object directly and set it back if required #Core.enablePayloadType() #Core.isPayloadTypeEnabled() #Core.payloadTypeIsVbr() #Core.setPayloadTypeBitrate() -#DialPlan -#LinphoneBuffer -#CallParams.getJitterBufferSize() -#Core.getSupportedVideoSizes() -#Core.needsEchoCalibration() -#Core.removeFriend( -#Core.hasCrappyOpenGL() -#Core.enableSpeaker / isSpeakerEnabled() -#Core.getMSFactory() + +#CallParams.getJitterBufferSize() => CallStatsImpl.getJitterBufferSizeMs() +#Core.getSupportedVideoSizes() => Factory.getSupportedVideoDefinitions() +#Core.removeFriend() => FriendList.removeFriend() +#Core.enableSpeaker / isSpeakerEnabled() => mAudioManager.setSpeakerphoneOn(speakerOn); #Core.enableVideo(true, true) => Core.enableVideoCapture(bool) & Core.enableVideoDisplay(bool) -#Core.setCpuCount() -#Call.zoomVideo() has been removed temporarily in the wrapper +#Core.setCpuCount() => Not needed anymore, can be removed +#AccountCreator.getPrefix => linphone_dial_plan_lookup_ccc_from_e164 +#ProxyConfig.lookupCCCFromIso=> linphone_dial_plan_lookup_ccc_from_iso From 0579b0db2b5d5e9c500f129d02951fd10c761727 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 13 Oct 2017 11:53:00 +0200 Subject: [PATCH 0473/2215] feat(General): provide a L_Q_T macro to access public data in a multiple inheritance case --- include/linphone/utils/general.h | 9 +++++++++ src/chat/chat-room/client-group-chat-room.cpp | 7 ++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index 1ccee3b72..7ade05a19 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -180,6 +180,15 @@ struct AddConstMirror { >::type * \ >(CLASS::mPrivate); +// Get Private data of class in a multiple inheritance case. +#define L_Q_T(CLASS, NAME) \ + auto const NAME = static_cast< \ + AddConstMirror< \ + std::remove_reference::type, \ + CLASS \ + >::type * \ + >(getPublic()); + #define L_OVERRIDE_SHARED_FROM_THIS(CLASS) \ inline std::shared_ptr getSharedFromThis () { \ return std::static_pointer_cast(Object::getSharedFromThis()); \ diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index aee176244..15d7d0251 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -41,11 +41,12 @@ ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core) : Ch shared_ptr ClientGroupChatRoomPrivate::createSession () { L_Q(); + L_Q_T(RemoteConference, qConference); CallSessionParams csp; csp.addCustomHeader("Require", "recipient-list-invite"); - shared_ptr focus = static_cast(q)->getPrivate()->focus; + shared_ptr focus = qConference->getPrivate()->focus; shared_ptr session = focus->getPrivate()->createSession(*q, &csp, false, q); const Address &myAddress = q->getMe()->getAddress(); session->configure(LinphoneCallOutgoing, nullptr, nullptr, myAddress, focus->getAddress()); @@ -58,8 +59,8 @@ shared_ptr ClientGroupChatRoomPrivate::createSession () { } void ClientGroupChatRoomPrivate::notifyReceived (string body) { - L_Q(); - static_cast(q)->getPrivate()->eventHandler->notifyReceived(body); + L_Q_T(RemoteConference, qConference); + qConference->getPrivate()->eventHandler->notifyReceived(body); } // ============================================================================= From a4427e4e0b18ae524ed82b66b279a63453899f73 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 13 Oct 2017 11:54:10 +0200 Subject: [PATCH 0474/2215] Workaround for XmlRpcArgType and XmlRpcStatus to be sub-enums of XmlRpcRequest --- wrappers/java/genwrapper.py | 12 ++++++++++-- wrappers/java/migration.sh | 5 ++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index de3366c07..b9de6e321 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -61,8 +61,8 @@ ENUMS_LIST = { 'SubscribePolicy': 'Friend', 'TransportType': 'Address', 'TunnelMode': 'Tunnel', - 'XmlRpcArgType': 'XmlRpcRequest', - 'XmlRpcStatus': 'XmlRpcRequest', + 'XmlRpcRequestArgType': 'XmlRpcRequest', + 'XmlRpcRequestStatus': 'XmlRpcRequest', } ########################################################################## @@ -572,11 +572,19 @@ class JavaEnum(object): self._class = translator.translate_enum(_enum) self.packageName = package self.className = _enum.name.to_camel_case() + if self.className == 'XmlRpcArgType': + self.className = 'XmlRpcRequestArgType' + elif self.className == 'XmlRpcStatus': + self.className = 'XmlRpcRequestStatus' self.cPrefix = 'linphone_' + _enum.name.to_snake_case() self.filename = self.className + ".java" self.values = self._class['values'] self.doc = self._class['doc'] self.jniName = translator.translate_java_jni_enum_name(_enum) + if self.className == 'XmlRpcRequestArgType': + self.jniName = 'XmlRpcRequest$ArgType' + elif self.className == 'XmlRpcRequestStatus': + self.jniName = 'XmlRpcRequest$Status' class JniInterface(object): def __init__(self, javaClass, apiClass): diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 2c74ed8d6..8ebac2c72 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -38,6 +38,7 @@ eval "$SED_START 's/LogCollectionUploadState.LogCollectionUploadStateDelivered/L eval "$SED_START 's/LogCollectionUploadState.LogCollectionUploadStateNotDelivered/LogCollectionUploadState.NotDelivered/g' $SED_END" eval "$SED_START 's/AccountCreator.RequestStatus/AccountCreator.Status/g' $SED_END" +eval "$SED_START 's/RequestStatus/Status/g' $SED_END" eval "$SED_START 's/AccountCreator.Status.Ok/AccountCreator.Status.RequestOk/g' $SED_END" eval "$SED_START 's/AccountCreator.PasswordCheck/AccountCreator.PasswordStatus/g' $SED_END" eval "$SED_START 's/AccountCreator.PhoneNumberCheck/AccountCreator.PhoneNumberStatus/g' $SED_END" @@ -45,6 +46,7 @@ eval "$SED_START 's/AccountCreator.EmailCheck/AccountCreator.EmailStatus/g' $SED eval "$SED_START 's/AccountCreator.UsernameCheck/AccountCreator.UsernameStatus/g' $SED_END" eval "$SED_START 's/AccountCreator.Status.Failed/AccountCreator.Status.RequestFailed/g' $SED_END" eval "$SED_START 's/AccountCreator.Status.ErrorServer/AccountCreator.Status.ServerError/g' $SED_END" +eval "$SED_START 's/PhoneNumberStatus.CountryCodeInvalid/PhoneNumberStatus.InvalidCountryCode/g' $SED_END" eval "$SED_START 's/Reason.Media/Reason.NotAcceptable/g' $SED_END" eval "$SED_START 's/Reason.BadCredentials/Reason.Forbidden/g' $SED_END" @@ -175,7 +177,8 @@ eval "$SED_START 's/VideoDefinition().toDisplayableString()/VideoDefinition().ge eval "$SED_START 's/isAccountUsed/isAccountExist()/g' $SED_END" eval "$SED_START 's/loadXmlFile(/loadFromXmlFile(/g' $SED_END" eval "$SED_START 's/activatePhoneNumberLink()/activateAlias()/g' $SED_END" -eval "$SED_START 's//g' $SED_END" +eval "$SED_START 's/isPhoneNumberUsed()/isAliasUsed()/g' $SED_END" +eval "$SED_START 's/recoverPhoneAccount()/recoverAccount()/g' $SED_END" # Removed methods eval "$SED_START 's/.isRegistered()/.getState() == RegistrationState.Ok/g' $SED_END" From 14edf879a12c3c5e3089bab8a67c803b1e00b73c Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 13 Oct 2017 12:02:50 +0200 Subject: [PATCH 0475/2215] feat(Db): rename provider folder to session --- src/CMakeLists.txt | 10 +++++----- src/db/abstract/abstract-db-p.h | 2 +- src/db/abstract/abstract-db.cpp | 2 +- src/db/events-db.cpp | 2 +- src/db/{provider => session}/db-session-p.h | 0 src/db/{provider => session}/db-session-provider.cpp | 0 src/db/{provider => session}/db-session-provider.h | 0 src/db/{provider => session}/db-session.cpp | 0 src/db/{provider => session}/db-session.h | 0 9 files changed, 8 insertions(+), 8 deletions(-) rename src/db/{provider => session}/db-session-p.h (100%) rename src/db/{provider => session}/db-session-provider.cpp (100%) rename src/db/{provider => session}/db-session-provider.h (100%) rename src/db/{provider => session}/db-session.cpp (100%) rename src/db/{provider => session}/db-session.h (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 692371a06..5e7299545 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -82,9 +82,9 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES db/abstract/abstract-db-p.h db/abstract/abstract-db.h db/events-db.h - db/provider/db-session-p.h - db/provider/db-session-provider.h - db/provider/db-session.h + db/session/db-session-p.h + db/session/db-session-provider.h + db/session/db-session.h enums.h event-log/call-event.h event-log/chat-message-event.h @@ -159,8 +159,8 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES core/core.cpp db/abstract/abstract-db.cpp db/events-db.cpp - db/provider/db-session-provider.cpp - db/provider/db-session.cpp + db/session/db-session-provider.cpp + db/session/db-session.cpp event-log/call-event.cpp event-log/chat-message-event.cpp event-log/conference-event.cpp diff --git a/src/db/abstract/abstract-db-p.h b/src/db/abstract/abstract-db-p.h index 2348ca74f..ce0887118 100644 --- a/src/db/abstract/abstract-db-p.h +++ b/src/db/abstract/abstract-db-p.h @@ -21,7 +21,7 @@ #define _ABSTRACT_DB_P_H_ #include "abstract-db.h" -#include "db/provider/db-session.h" +#include "db/session/db-session.h" #include "object/object-p.h" // ============================================================================= diff --git a/src/db/abstract/abstract-db.cpp b/src/db/abstract/abstract-db.cpp index 94baefbae..838a2e9a4 100644 --- a/src/db/abstract/abstract-db.cpp +++ b/src/db/abstract/abstract-db.cpp @@ -22,7 +22,7 @@ #endif // ifdef SOCI_ENABLED #include "abstract-db-p.h" -#include "db/provider/db-session-provider.h" +#include "db/session/db-session-provider.h" #include "logger/logger.h" // ============================================================================= diff --git a/src/db/events-db.cpp b/src/db/events-db.cpp index b3c50d45c..e827d244e 100644 --- a/src/db/events-db.cpp +++ b/src/db/events-db.cpp @@ -32,7 +32,7 @@ #include "conference/participant.h" #include "content/content-type.h" #include "content/content.h" -#include "db/provider/db-session-provider.h" +#include "db/session/db-session-provider.h" #include "event-log/call-event.h" #include "event-log/chat-message-event.h" #include "event-log/event-log-p.h" diff --git a/src/db/provider/db-session-p.h b/src/db/session/db-session-p.h similarity index 100% rename from src/db/provider/db-session-p.h rename to src/db/session/db-session-p.h diff --git a/src/db/provider/db-session-provider.cpp b/src/db/session/db-session-provider.cpp similarity index 100% rename from src/db/provider/db-session-provider.cpp rename to src/db/session/db-session-provider.cpp diff --git a/src/db/provider/db-session-provider.h b/src/db/session/db-session-provider.h similarity index 100% rename from src/db/provider/db-session-provider.h rename to src/db/session/db-session-provider.h diff --git a/src/db/provider/db-session.cpp b/src/db/session/db-session.cpp similarity index 100% rename from src/db/provider/db-session.cpp rename to src/db/session/db-session.cpp diff --git a/src/db/provider/db-session.h b/src/db/session/db-session.h similarity index 100% rename from src/db/provider/db-session.h rename to src/db/session/db-session.h From dbeba831a571dd45ba9622b5e4e742c0966f903f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 13 Oct 2017 13:53:47 +0200 Subject: [PATCH 0476/2215] Added instance() method in Factory object of generated Java wrapper --- wrappers/java/CMakeLists.txt | 2 +- wrappers/java/classes/tools/H264Helper.java | 79 ++++++ wrappers/java/classes/tools/Lpc2Xml.java | 68 +++++ .../classes/tools/OpenH264DownloadHelper.java | 240 ++++++++++++++++++ wrappers/java/classes/tools/Xml2Lpc.java | 73 ++++++ wrappers/java/java_class.mustache | 66 ++++- wrappers/java/migration.sh | 4 + 7 files changed, 523 insertions(+), 9 deletions(-) create mode 100644 wrappers/java/classes/tools/H264Helper.java create mode 100644 wrappers/java/classes/tools/Lpc2Xml.java create mode 100644 wrappers/java/classes/tools/OpenH264DownloadHelper.java create mode 100644 wrappers/java/classes/tools/Xml2Lpc.java diff --git a/wrappers/java/CMakeLists.txt b/wrappers/java/CMakeLists.txt index 7dcb317fb..c6d29d950 100644 --- a/wrappers/java/CMakeLists.txt +++ b/wrappers/java/CMakeLists.txt @@ -41,4 +41,4 @@ add_custom_target(linphonej ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/src/linphon set(LINPHONE_JNI_SOURCES "${CMAKE_CURRENT_BINARY_DIR}/src/linphone_jni.cc" PARENT_SCOPE) install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/java" DESTINATION "${CMAKE_INSTALL_DATADIR}/linphonej/") -install(DIRECTORY classes/ DESTINATION "${CMAKE_INSTALL_DATADIR}/linphonej/java/org/linphone/core/" FILES_MATCHING PATTERN "*.java") \ No newline at end of file +install(DIRECTORY classes/ DESTINATION "${CMAKE_INSTALL_DATADIR}/linphonej/java/org/linphone/core/") diff --git a/wrappers/java/classes/tools/H264Helper.java b/wrappers/java/classes/tools/H264Helper.java new file mode 100644 index 000000000..421d44f6f --- /dev/null +++ b/wrappers/java/classes/tools/H264Helper.java @@ -0,0 +1,79 @@ +package org.linphone.core.tools; + + +import android.os.Build; + +import org.linphone.core.LinphoneCore; +import org.linphone.mediastream.Log; + +/** + * Created by brieucviel on 09/12/2016. + */ + +public class H264Helper { + private static String FILTER_NAME_OPENH264_ENC = "MSOpenH264Enc" ; + private static String FILTER_NAME_OPENH264_DEC = "MSOpenH264Dec" ; + private static String FILTER_NAME_MEDIA_CODEC_ENC = "MSMediaCodecH264Enc" ; + private static String FILTER_NAME_MEDIA_CODEC_DEC = "MSMediaCodecH264Dec" ; + + public static String MODE_AUTO = "Auto" ; + public static String MODE_OPENH264 = "OpenH264" ; + public static String MODE_MEDIA_CODEC = "MediaCodec" ; + + + /** + * H264Helper + */ + public H264Helper() { + } + + + /** + * Define the Codec to use between MediaCodec and OpenH264 + * Possible mode are: + * - Auto to let the system choose in function of you OS version, + * - OpenH264 to enable OpenH264 Encoder and Decoder, + * - Mediacodec to enable Mediacodec only. + * @param mode String value between Auto, OpenH264 and MediaCodec + */ + public static void setH264Mode(String mode, LinphoneCore linphoneCore){ + if(mode.equals(MODE_OPENH264)){ + Log.i("H264Helper"," setH264Mode MODE_OPENH264 - Mode = "+mode); + linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_DEC , false); + linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_ENC , false); + linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_DEC , true); + linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_ENC , true); + }else if(mode.equals(MODE_MEDIA_CODEC)){ + Log.i("H264Helper"," setH264Mode MODE_MEDIA_CODEC - Mode = "+mode); + linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_DEC , false); + linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_ENC , false); + linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_DEC , true); + linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_ENC , true); + }else if(mode.equals(MODE_AUTO)){ + Log.i("H264Helper"," setH264Mode MODE_AUTO - Mode = "+mode); + // if android >= 5.0 use MediaCodec + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { + Log.i("H264Helper"," setH264Mode MODE_AUTO 1 - Mode = "+mode); + Log.i("H264Helper"," Openh264 disabled on the project, now using MediaCodec"); + linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_DEC , false); + linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_ENC , false); + linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_DEC , true); + linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_ENC , true); + } + //otherwise use OpenH264 + else{ + Log.i("H264Helper"," setH264Mode MODE_AUTO 2 - Mode = "+mode); + Log.i("H264Helper"," Openh264 enabled on the project"); + linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_DEC , false); + linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_ENC , false); + linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_DEC , true); + linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_ENC , true); + } + }else { + Log.i("H264Helper"," Error: Openh264 mode not reconized !"); + } + Log.i("H264Helper"," setH264Mode - Mode = "+mode); + } + +} + diff --git a/wrappers/java/classes/tools/Lpc2Xml.java b/wrappers/java/classes/tools/Lpc2Xml.java new file mode 100644 index 000000000..e61f4d2df --- /dev/null +++ b/wrappers/java/classes/tools/Lpc2Xml.java @@ -0,0 +1,68 @@ +package org.linphone.core.tools; + +import org.linphone.core.LpConfig; +import org.linphone.mediastream.Log; + +public class Lpc2Xml { + + private enum LogLevel { + DEBUG, + MESSAGE, + WARNING, + ERROR, + } + + private static boolean mAvailable; + + private long internalPtr = 0; + + private native void init(); + private native void destroy(); + + public Lpc2Xml() { + init(); + } + + public void finalize() { + destroy(); + } + + public native int setLpc(LpConfig lpc); + + public native int convertFile(String file); + public native int convertString(StringBuffer content); + + public void printLog(int level, String message) { + if(level > 0 && level < LogLevel.values().length) { + switch(LogLevel.values()[level]) { + case DEBUG: + Log.d(message); + break; + case MESSAGE: + Log.i(message); + break; + case WARNING: + Log.w(message); + break; + case ERROR: + Log.e(message); + break; + } + } + } + + static boolean isAvailable() { + return mAvailable; + } + + // Load library + static { + try { + System.loadLibrary("xml2"); + //System.loadLibrary("lpc2xml"); + mAvailable = true; + } catch (Throwable e) { + mAvailable = false; + } + } +} diff --git a/wrappers/java/classes/tools/OpenH264DownloadHelper.java b/wrappers/java/classes/tools/OpenH264DownloadHelper.java new file mode 100644 index 000000000..fc81245f4 --- /dev/null +++ b/wrappers/java/classes/tools/OpenH264DownloadHelper.java @@ -0,0 +1,240 @@ +package org.linphone.core.tools; +/* +CodecDownloader.java +Copyright (C) 2016 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import android.content.Context; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; + +import org.apache.commons.compress.compressors.bzip2.*; +import org.linphone.core.OpenH264DownloadHelperListener; +import org.linphone.mediastream.Log; + +/** + * @author Erwan Croze + */ +public class OpenH264DownloadHelper { + private OpenH264DownloadHelperListener openH264DownloadHelperListener; + private ArrayList userData; + private String fileDirection; + private String nameLib; + private String urlDownload; + private String nameFileDownload; + private String licenseMessage; + + /** + * Default values + * nameLib = "libopenh264-1.5.so" + * urlDownload = "http://ciscobinary.openh264.org/libopenh264-1.5.0-android19.so.bz2" + * nameFileDownload = "libopenh264-1.5.0-android19.so.bz2" + */ + public OpenH264DownloadHelper(Context context) { + userData = new ArrayList(); + licenseMessage = "OpenH264 Video Codec provided by Cisco Systems, Inc."; + nameLib = "libopenh264.so"; + urlDownload = "http://ciscobinary.openh264.org/libopenh264-1.5.0-android19.so.bz2"; + nameFileDownload = "libopenh264-1.5.0-android19.so.bz2"; + if(context.getFilesDir() != null) { + fileDirection = context.getFilesDir().toString(); + } + } + + /** + * Set OpenH264DownloadHelperListener + * @param h264Listener + */ + public void setOpenH264HelperListener(OpenH264DownloadHelperListener h264Listener) { + openH264DownloadHelperListener = h264Listener; + } + + /** + * @return OpenH264DownloadHelperListener + */ + public OpenH264DownloadHelperListener getOpenH264DownloadHelperListener() { + return openH264DownloadHelperListener; + } + + /** + * @param index of object in UserData list + * constraints (index superior or egal to 0 and index inferior to userData.size()) + * @return object if constraints are met + */ + public Object getUserData(int index) { + if (index < 0 || index >= userData.size()) return null; + return userData.get(index); + } + + /** + * Adding of object into UserData list + * @param object + * @return index of object in UserData list + */ + public int setUserData(Object object) { + this.userData.add(object); + return this.userData.indexOf(object); + } + + /** + * @param index + * @param object + * constraints (index superior or egal to 0 and index inferior to userData.size()) + */ + public void setUserData(int index, Object object) { + if (index < 0 || index > userData.size()) return; + this.userData.add(index,object); + } + + /** + * @return size of UserData list + */ + public int getUserDataSize() { + return this.userData.size(); + } + + /** + * @return OpenH264 license message + */ + public String getLicenseMessage() { + return licenseMessage; + } + + /** + * Set filename to storage for OpenH264 codec + * @param name + */ + public void setNameLib(String name) { + nameLib = name; + } + + /** + * @return filename of OpenH264 codec + */ + public String getNameLib() { + return nameLib; + } + + /** + * @return path of the lib + */ + public String getFullPathLib() { + return this.fileDirection + "/" + this.getNameLib(); + } + + /** + * Set name download file + * @param name : must be the same name relative to the url + */ + public void setNameFileDownload(String name) { + nameFileDownload = name; + } + + /** + * Set new url + * @param url : must be a Cisco Url to OpenH264 and .bzip2 file + */ + public void setUrlDownload(String url) { + urlDownload = url; + } + + /** + * Indicates whether the lib exists + * Requirements : fileDirection and nameLib init + * @return file exists ? + */ + public boolean isCodecFound() { + return new File(fileDirection+"/" + nameLib).exists(); + } + + /** + * Try to download and load codec + * Requirements : + * fileDirection + * nameFileDownload + * urlDownload + * nameLib + * codecDownListener + */ + public void downloadCodec() { + Thread thread = new Thread(new Runnable() + { + @Override + public void run() + { + try { + String path = fileDirection+"/" + nameLib; + URL url = new URL(urlDownload); + HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection(); + urlConnection.connect(); + Log.i("OpenH264Downloader"," "); + InputStream inputStream = urlConnection.getInputStream(); + FileOutputStream fileOutputStream = new FileOutputStream(fileDirection+"/"+nameFileDownload); + int totalSize = urlConnection.getContentLength(); + openH264DownloadHelperListener.OnProgress(0,totalSize); + + Log.i("OpenH264Downloader"," Download file:" + nameFileDownload); + + byte[] buffer = new byte[4096]; + int bufferLength; + int total = 0; + while((bufferLength = inputStream.read(buffer))>0 ){ + total += bufferLength; + fileOutputStream.write(buffer, 0, bufferLength); + openH264DownloadHelperListener.OnProgress(total, totalSize); + } + + fileOutputStream.close(); + inputStream.close(); + + Log.i("OpenH264Downloader"," Uncompress file:" + nameFileDownload); + + FileInputStream in = new FileInputStream(fileDirection+"/"+nameFileDownload); + FileOutputStream out = new FileOutputStream(path); + BZip2CompressorInputStream bzIn = new BZip2CompressorInputStream(in); + + while ((bufferLength = bzIn.read(buffer))>0) { + out.write(buffer, 0, bufferLength); + } + in.close(); + out.close(); + bzIn.close(); + + Log.i("OpenH264Downloader"," Remove file:" + nameFileDownload); + new File(fileDirection+"/"+nameFileDownload).delete(); + + Log.i("OpenH264Downloader"," Loading plugin:" + path); + System.load(path); + openH264DownloadHelperListener.OnProgress(2,1); + } catch (FileNotFoundException e) { + openH264DownloadHelperListener.OnError(e.getLocalizedMessage()); + } catch (IOException e) { + openH264DownloadHelperListener.OnError(e.getLocalizedMessage()); + } + } + }); + thread.start(); + } +} diff --git a/wrappers/java/classes/tools/Xml2Lpc.java b/wrappers/java/classes/tools/Xml2Lpc.java new file mode 100644 index 000000000..9b874152e --- /dev/null +++ b/wrappers/java/classes/tools/Xml2Lpc.java @@ -0,0 +1,73 @@ +package org.linphone.core.tools; + +import org.linphone.core.LpConfig; +import org.linphone.mediastream.Log; + +public class Xml2Lpc { + + private enum LogLevel { + DEBUG, + MESSAGE, + WARNING, + ERROR + } + + private static boolean mAvailable; + + private long internalPtr = 0; + + private native void init(); + private native void destroy(); + + public Xml2Lpc() { + init(); + } + + public void finalize() { + destroy(); + } + + public native int setXmlFile(String filename); + public native int setXmlString(String content); + + public native int setXsdFile(String filename); + public native int setXsdString(String content); + + public native int validate(); + public native int convert(LpConfig config); + + public void printLog(int level, String message) { + if(level > 0 && level < LogLevel.values().length) { + switch(LogLevel.values()[level]) { + case DEBUG: + Log.d(message); + break; + case MESSAGE: + Log.i(message); + break; + case WARNING: + Log.w(message); + break; + case ERROR: + Log.e(message); + break; + } + } + } + + public static boolean isAvailable() { + return mAvailable; + } + + // Load library + static { + try { + new Xml2Lpc(); + //System.loadLibrary("xml2"); + //System.loadLibrary("xml2lpc"); + mAvailable = true; + } catch (Throwable e) { + mAvailable = false; + } + } +} diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 77778af8d..0cc0252ec 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -23,7 +23,17 @@ package {{packageName}}; import {{import}} {{/imports}} {{#isLinphoneFactory}} +import android.content.Context; +import android.os.Build; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.linphone.mediastream.Log; import org.linphone.mediastream.Version; +import org.linphone.core.tools.OpenH264DownloadHelper; {{/isLinphoneFactory}} {{#doc}} @@ -33,7 +43,7 @@ import org.linphone.mediastream.Version; {{/lines}} */ {{/doc}} -public interface {{className}} { +public {{#isLinphoneFactory}}abstract class{{/isLinphoneFactory}}{{#isNotLinphoneFactory}}interface{{/isNotLinphoneFactory}} {{className}} { {{#enums}} enum {{className}} { {{#values}} @@ -70,7 +80,18 @@ public interface {{className}} { {{/enums}} {{#isLinphoneFactory}} - + static Factory _Factory; + + public static final synchronized Factory instance() { + try { + if (_Factory == null) { + _Factory = new FactoryImpl(0); + } + } catch (Exception e) { + System.err.println("Cannot instanciate factory"); + } + return _Factory; + } {{/isLinphoneFactory}} {{#methods}} {{#doc}} @@ -81,18 +102,18 @@ public interface {{className}} { */ {{/doc}} {{#deprecated}}@Deprecated - {{/deprecated}}public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}}{{#enumCast}} throws CoreException{{/enumCast}}; + {{/deprecated}}{{#isLinphoneFactory}}abstract {{/isLinphoneFactory}}public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}}{{#enumCast}} throws CoreException{{/enumCast}}; {{/methods}} /** * Sets the object to store in this object user's data */ - public void setUserData(Object data); + {{#isLinphoneFactory}}abstract {{/isLinphoneFactory}}public void setUserData(Object data); /** * Gets the object stored in this object user's data */ - public Object getUserData(); + {{#isLinphoneFactory}}abstract {{/isLinphoneFactory}}public Object getUserData(); {{#isNotLinphoneFactory}} {{#staticMethods}} @@ -109,7 +130,7 @@ public interface {{className}} { {{/isNotLinphoneFactory}} } -class {{classImplName}} implements {{className}} { +class {{classImplName}} {{#isLinphoneFactory}}extends{{/isLinphoneFactory}}{{#isNotLinphoneFactory}}implements{{/isNotLinphoneFactory}} {{className}} { protected long nativePtr = 0; protected Object userData = null; @@ -119,12 +140,12 @@ class {{classImplName}} implements {{className}} { } {{#isLinphoneFactory}} - private static boolean loadOptionalLibrary(String s) { + private static boolean loadOptionalLibrary(String s) { try { System.loadLibrary(s); return true; } catch (Throwable e) { - android.util.Log.w("LinphoneCoreFactoryImpl", "Unable to load optional library " + s + ": " + e.getMessage()); + android.util.Log.w("FactoryImpl", "Unable to load optional library " + s + ": " + e.getMessage()); } return false; } @@ -139,10 +160,37 @@ class {{classImplName}} implements {{className}} { System.loadLibrary("linphone"); Version.dumpCapabilities(); } + + private boolean loadingDownloadedOpenH264(Context context) { + File file = new File(context.getApplicationInfo().nativeLibraryDir + "/libmsopenh264.so"); + + if (!file.exists()) { + Log.i("FactoryImpl"," libmsopenh264 not found, we disable the download of Openh264"); + return false; + } + + OpenH264DownloadHelper downloadHelper = new OpenH264DownloadHelper(context); + if (downloadHelper.isCodecFound()) { + Log.i("FactoryImpl"," Loading OpenH264 downloaded plugin:" + downloadHelper.getFullPathLib()); + System.load(downloadHelper.getFullPathLib()); + } else { + Log.i("FactoryImpl"," Cannot load OpenH264 downloaded plugin"); + } + return true; + } + + public OpenH264DownloadHelper createOpenH264DownloadHelper() { + if (fcontext == null) { + new CoreException("Cannot create OpenH264DownloadHelper"); + return null;//exception + } + return new OpenH264DownloadHelper(fcontext); + } {{/isLinphoneFactory}} {{#methods}} private native {{return_native}} {{name}}({{native_params}}); + @Override public {{return}} {{name}}({{params}}) {{#exception}}throws CoreException{{/exception}}{{#enumCast}}throws CoreException{{/enumCast}} { {{#exception}}int exceptionResult = {{/exception}}{{return_keyword}}{{#enumCast}}{{return}}.fromInt({{/enumCast}}{{#classCast}}({{return}}){{/classCast}}{{name}}(nativePtr{{native_params_impl}}){{#enumCast}}){{/enumCast}};{{#exception}} if (exceptionResult != 0) throw new CoreException("{{name}} returned value " + exceptionResult);{{/exception}} @@ -160,10 +208,12 @@ class {{classImplName}} implements {{className}} { } {{/isNotLinphoneFactory}} + @Override public void setUserData(Object data) { userData = data; } + @Override public Object getUserData() { return userData; } diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 8ebac2c72..75c029679 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -3,6 +3,9 @@ SED_START='find ./src/android/org/linphone/ -type f -exec sed -i -e ' SED_END='{} \;' +# Imports +eval "$SED_START 's/import org.linphone.tools/import org.linphone.core.tools/g' $SED_END" + # Listeners eval "$SED_START 's/AccountCreator.AccountCreatorListener/AccountCreatorListener/g' $SED_END" eval "$SED_START 's/LinphoneCoreListenerBase/CoreListenerStub/g' $SED_END" @@ -204,6 +207,7 @@ eval "$SED_START 's/transports.tcp/transports.getTcpPort()/g' $SED_END" eval "$SED_START 's/transports.tls/transports.getTlsPort()/g' $SED_END" eval "$SED_START 's/getPrimaryContactUsername()/getPrimaryContactParsed().getUsername()/g' $SED_END" eval "$SED_START 's/getPrimaryContactDisplayName()/getPrimaryContactParsed().getDisplayName()/g' $SED_END" +eval "$SED_START 's/.sendDtmf(/.getCurrentCall().sendDtmf(/g' $SED_END" #Changes in library required #OpenH264DownloadHelper From 6369dbdd63ea672f73f48d0ec7b0f28487f5aaa3 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 13 Oct 2017 14:26:18 +0200 Subject: [PATCH 0477/2215] Remove @donotwrap tag for just deprecated functions. --- include/linphone/auth_info.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/include/linphone/auth_info.h b/include/linphone/auth_info.h index 1e780f3cf..c14433056 100644 --- a/include/linphone/auth_info.h +++ b/include/linphone/auth_info.h @@ -71,19 +71,11 @@ LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_ref(LinphoneAuthInfo *info) */ LINPHONE_PUBLIC void linphone_auth_info_unref(LinphoneAuthInfo *info); -/** - * Sets the password. - * @param[in] info The #LinphoneAuthInfo object - * @param[in] passwd The password. -**/ -LINPHONE_PUBLIC void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd); - /** * Sets the password. * @param[in] info The #LinphoneAuthInfo object * @param[in] passwd The password. * @deprecated, use linphone_auth_info_set_password instead - * @donotwrap **/ LINPHONE_PUBLIC void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd); @@ -171,7 +163,6 @@ LINPHONE_PUBLIC const char *linphone_auth_info_get_username(const LinphoneAuthIn * @param[in] info The #LinphoneAuthInfo object * @return The password. * @deprecated, use linphone_auth_info_get_password instead - * @donotwrap */ LINPHONE_PUBLIC const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo *info); From 591778510744bd47be920a8d61c7b3d46f258c5d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 13 Oct 2017 14:26:58 +0200 Subject: [PATCH 0478/2215] Add linphone_chat_message_send() API. --- include/linphone/api/c-chat-message.h | 9 ++++++++- include/linphone/api/c-chat-room.h | 7 ++++--- src/c-wrapper/api/c-chat-message.cpp | 4 ++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index 20103291a..4dabfcf8e 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -263,12 +263,19 @@ LINPHONE_PUBLIC LinphoneStatus linphone_chat_message_download_file(LinphoneChatM */ LINPHONE_PUBLIC void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage* msg); +/** + * Send a chat message. + * @param[in] msg LinphoneChatMessage object + */ +LINPHONE_PUBLIC void linphone_chat_message_send (LinphoneChatMessage *msg); + /** * Resend a chat message if it is in the 'not delivered' state for whatever reason. * @param[in] msg LinphoneChatMessage object + * @deprecated Use linphone_chat_message_send instead. * @donotwrap */ -LINPHONE_PUBLIC void linphone_chat_message_resend(LinphoneChatMessage *msg); +LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_chat_message_resend(LinphoneChatMessage *msg); LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg); diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index 534c4265e..33bedd0c4 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -100,7 +100,7 @@ LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_room_get_peer_address(Linph /** * Send a message to peer member of this chat room. - * @deprecated Use linphone_chat_room_send_chat_message() instead. + * @deprecated Use linphone_chat_message_send() instead. * @param cr #LinphoneChatRoom object * @param msg message to be sent * @donotwrap @@ -113,7 +113,7 @@ LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_chat_room_send_message(Linphon * @param msg #LinphoneChatMessage message to be sent * @param status_cb LinphoneChatMessageStateChangeCb status callback invoked when message is delivered or could not be delivered. May be NULL * @param ud user data for the status cb. - * @deprecated Use linphone_chat_room_send_chat_message() instead. + * @deprecated Use linphone_chat_message_send() instead. * @note The LinphoneChatMessage must not be destroyed until the the callback is called. * The LinphoneChatMessage reference is transfered to the function and thus doesn't need to be unref'd by the application. * @donotwrap @@ -127,9 +127,10 @@ LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_chat_room_send_message2(Linpho * The state of the message sending will be notified via the callbacks defined in the LinphoneChatMessageCbs object that can be obtained * by calling linphone_chat_message_get_callbacks(). * The LinphoneChatMessage reference is transfered to the function and thus doesn't need to be unref'd by the application. + * @deprecated Use linphone_chat_message_send() instead. * @donotwrap */ -LINPHONE_PUBLIC void linphone_chat_room_send_chat_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg); +LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_chat_room_send_chat_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg); /** * Mark all messages of the conversation as read diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index e44853426..95910a1d3 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -264,6 +264,10 @@ void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg) { L_GET_CPP_PTR_FROM_C_OBJECT(msg)->cancelFileTransfer(); } +void linphone_chat_message_send (LinphoneChatMessage *msg) { + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->send(); +} + void linphone_chat_message_resend(LinphoneChatMessage *msg) { L_GET_CPP_PTR_FROM_C_OBJECT(msg)->send(); } From 601a1a6564d3247f335e0e9ea55240440c675c79 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 13 Oct 2017 14:38:11 +0200 Subject: [PATCH 0479/2215] The cpimFrom address field in the ChatMessage is useless. --- src/chat/chat-message/chat-message-p.h | 4 ---- src/chat/chat-message/chat-message.cpp | 5 ----- src/chat/chat-room/chat-room.cpp | 1 - src/chat/modifier/cpim-chat-message-modifier.cpp | 4 ++-- 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index 40f7ea492..73c8a58f2 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -57,9 +57,6 @@ public: void setApplyModifiers (bool value) { applyModifiers = value; } - const Address &getCpimFromAddress () const { return cpimFrom; } - void setCpimFromAddress (const Address &addr); - void setDirection (ChatMessage::Direction dir); void setState(ChatMessage::State state); @@ -129,7 +126,6 @@ private: unsigned int storageId = 0; Address from; Address to; - Address cpimFrom; time_t time = 0; std::string id; std::string appData; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index bec65cd75..94bea15a8 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -60,11 +60,6 @@ void ChatMessagePrivate::setChatRoom (shared_ptr cr) { chatRoom = cr; } -void ChatMessagePrivate::setCpimFromAddress (const Address &addr) { - cpimFrom = addr; - cpimFrom.clean(); -} - void ChatMessagePrivate::setDirection (ChatMessage::Direction dir) { direction = dir; } diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 50dc7d370..c980b6566 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -557,7 +557,6 @@ shared_ptr ChatRoom::createMessage () { shared_ptr chatMessage = ObjectFactory::create(getSharedFromThis()); chatMessage->setToAddress(d->peerAddress); chatMessage->setFromAddress(Address(linphone_core_get_identity(d->core))); - chatMessage->getPrivate()->setCpimFromAddress(chatMessage->getFromAddress()); chatMessage->getPrivate()->setTime(ms_time(0)); return chatMessage; } diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index e7e04d870..c017ce9fb 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -40,7 +40,7 @@ ChatMessageModifier::Result CpimChatMessageModifier::encode (const shared_ptrgetPrivate()->getCpimFromAddress())); + cpimFromHeader.setValue(cpimAddressAsString(message->getFromAddress())); cpimMessage.addMessageHeader(cpimFromHeader); Cpim::ToHeader cpimToHeader; cpimToHeader.setValue(cpimAddressAsString(message->getToAddress())); @@ -133,7 +133,7 @@ ChatMessageModifier::Result CpimChatMessageModifier::decode (const shared_ptrsetInternalContent(newContent); if (cpimFromAddress.isValid()) - message->getPrivate()->setCpimFromAddress(cpimFromAddress); + message->setFromAddress(cpimFromAddress); if (cpimToAddress.isValid()) message->setToAddress(cpimToAddress); From e31b995bd35f3368cd3edf464b6d7912140e63bb Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 13 Oct 2017 14:38:57 +0200 Subject: [PATCH 0480/2215] Changes for Java's OpenH264's helper --- .../classes/tools/OpenH264DownloadHelper.java | 22 +++++++++++++-- wrappers/java/java_class.mustache | 28 ++++--------------- wrappers/java/migration.sh | 11 +++++++- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/wrappers/java/classes/tools/OpenH264DownloadHelper.java b/wrappers/java/classes/tools/OpenH264DownloadHelper.java index fc81245f4..6c0ce3744 100644 --- a/wrappers/java/classes/tools/OpenH264DownloadHelper.java +++ b/wrappers/java/classes/tools/OpenH264DownloadHelper.java @@ -31,7 +31,7 @@ import java.net.URL; import java.util.ArrayList; import org.apache.commons.compress.compressors.bzip2.*; -import org.linphone.core.OpenH264DownloadHelperListener; +import org.linphone.core.tools.OpenH264DownloadHelperListener; import org.linphone.mediastream.Log; /** @@ -58,11 +58,29 @@ public class OpenH264DownloadHelper { nameLib = "libopenh264.so"; urlDownload = "http://ciscobinary.openh264.org/libopenh264-1.5.0-android19.so.bz2"; nameFileDownload = "libopenh264-1.5.0-android19.so.bz2"; - if(context.getFilesDir() != null) { + if (context.getFilesDir() != null) { fileDirection = context.getFilesDir().toString(); } } + public static boolean isOpenH264DownloadEnabled(Context context) { + File file = new File(context.getApplicationInfo().nativeLibraryDir+"/libmsopenh264.so"); + + if (!file.exists()) { + Log.i("LinphoneCoreFactoryImpl"," libmsopenh264 not found, we disable the download of Openh264"); + return false; + } + + OpenH264DownloadHelper downloadHelper = new OpenH264DownloadHelper(context); + if (downloadHelper.isCodecFound()) { + Log.i("OpenH264DownloadHelper"," Loading OpenH264 downloaded plugin:" + downloadHelper.getFullPathLib()); + System.load(downloadHelper.getFullPathLib()); + } else { + Log.i("OpenH264DownloadHelper"," Cannot load OpenH264 downloaded plugin"); + } + return true; + } + /** * Set OpenH264DownloadHelperListener * @param h264Listener diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 0cc0252ec..6c838aa5b 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -92,6 +92,8 @@ public {{#isLinphoneFactory}}abstract class{{/isLinphoneFactory}}{{#isNotLinphon } return _Factory; } + + abstract public OpenH264DownloadHelper createOpenH264DownloadHelper(Context context); {{/isLinphoneFactory}} {{#methods}} {{#doc}} @@ -161,30 +163,12 @@ class {{classImplName}} {{#isLinphoneFactory}}extends{{/isLinphoneFactory}}{{#is Version.dumpCapabilities(); } - private boolean loadingDownloadedOpenH264(Context context) { - File file = new File(context.getApplicationInfo().nativeLibraryDir + "/libmsopenh264.so"); - - if (!file.exists()) { - Log.i("FactoryImpl"," libmsopenh264 not found, we disable the download of Openh264"); - return false; - } - - OpenH264DownloadHelper downloadHelper = new OpenH264DownloadHelper(context); - if (downloadHelper.isCodecFound()) { - Log.i("FactoryImpl"," Loading OpenH264 downloaded plugin:" + downloadHelper.getFullPathLib()); - System.load(downloadHelper.getFullPathLib()); - } else { - Log.i("FactoryImpl"," Cannot load OpenH264 downloaded plugin"); - } - return true; - } - - public OpenH264DownloadHelper createOpenH264DownloadHelper() { - if (fcontext == null) { + public OpenH264DownloadHelper createOpenH264DownloadHelper(Context context) { + if (context == null) { new CoreException("Cannot create OpenH264DownloadHelper"); - return null;//exception + return null; } - return new OpenH264DownloadHelper(fcontext); + return new OpenH264DownloadHelper(context); } {{/isLinphoneFactory}} diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 75c029679..452e783a8 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -5,6 +5,7 @@ SED_END='{} \;' # Imports eval "$SED_START 's/import org.linphone.tools/import org.linphone.core.tools/g' $SED_END" +eval "$SED_START 's/import org.linphone.core.OpenH264DownloadHelperListener/import org.linphone.core.tools.OpenH264DownloadHelperListener/g' $SED_END" # Listeners eval "$SED_START 's/AccountCreator.AccountCreatorListener/AccountCreatorListener/g' $SED_END" @@ -22,6 +23,7 @@ eval "$SED_START 's/RegistrationState.RegistrationOk/RegistrationState.Ok/g' $SE eval "$SED_START 's/RegistrationState.RegistrationFailed/RegistrationState.Failed/g' $SED_END" eval "$SED_START 's/RegistrationState.RegistrationCleared/RegistrationState.Cleared/g' $SED_END" eval "$SED_START 's/RegistrationState.RegistrationProgress/RegistrationState.Progress/g' $SED_END" +eval "$SED_START 's/RegistrationState.RegistrationNone/RegistrationState.None/g' $SED_END" eval "$SED_START 's/RemoteProvisioningState.ConfiguringSuccessful/ConfiguringState.Successful/g' $SED_END" eval "$SED_START 's/LinphoneCore.RemoteProvisioningState/Core.ConfiguringState/g' $SED_END" @@ -107,8 +109,9 @@ eval "$SED_START 's/onChatMessageFileTransferProgressChanged/onFileTransferProgr eval "$SED_START 's/registrationState/onRegistrationStateChanged/g' $SED_END" # Methods -eval "$SED_START 's/getFriendList(/getFriendsLists(/g' $SED_END" +eval "$SED_START 's/getFriendsLists()/getFriends()/g' $SED_END" eval "$SED_START 's/getFriendLists()/getFriendsLists()/g' $SED_END" +eval "$SED_START 's/getFriendList(/getFriendsLists(/g' $SED_END" eval "$SED_START 's/getIdentity(/getIdentityAddress(/g' $SED_END" eval "$SED_START 's/isTunnelAvailable()/tunnelAvailable()/g' $SED_END" eval "$SED_START 's/setZrtpSecretsCache(/setZrtpSecretsFile(/g' $SED_END" @@ -182,6 +185,7 @@ eval "$SED_START 's/loadXmlFile(/loadFromXmlFile(/g' $SED_END" eval "$SED_START 's/activatePhoneNumberLink()/activateAlias()/g' $SED_END" eval "$SED_START 's/isPhoneNumberUsed()/isAliasUsed()/g' $SED_END" eval "$SED_START 's/recoverPhoneAccount()/recoverAccount()/g' $SED_END" +eval "$SED_START 's/isLimeEncryptionAvailable()/limeAvailable()/g' $SED_END" # Removed methods eval "$SED_START 's/.isRegistered()/.getState() == RegistrationState.Ok/g' $SED_END" @@ -214,6 +218,11 @@ eval "$SED_START 's/.sendDtmf(/.getCurrentCall().sendDtmf(/g' $SED_END" #DialPlan #LinphoneBuffer #Call.zoomVideo() +#Factory.instance().setLogCollectionPath(getFilesDir().getAbsolutePath()); +#Factory.instance().enableLogCollection(isDebugEnabled); +#Factory.instance().setDebugMode(isDebugEnabled, getString(R.string.app_name)); +#Factory.instance().createConfig(String s); +#Core.enableDownloadOpenH264 #Android specifics not wrapped automatically #Core.needsEchoCalibration() From 33877398042e00a0839e7965e6af5377ad3cf55b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 13 Oct 2017 14:40:32 +0200 Subject: [PATCH 0481/2215] Forgot to commit the helper's listener --- .../tools/OpenH264DownloadHelperListener.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 wrappers/java/classes/tools/OpenH264DownloadHelperListener.java diff --git a/wrappers/java/classes/tools/OpenH264DownloadHelperListener.java b/wrappers/java/classes/tools/OpenH264DownloadHelperListener.java new file mode 100644 index 000000000..d3d6faa88 --- /dev/null +++ b/wrappers/java/classes/tools/OpenH264DownloadHelperListener.java @@ -0,0 +1,18 @@ +package org.linphone.core.tools; + +public interface OpenH264DownloadHelperListener { + /** + * Called at the beginning of download with current < max Called + * at each iteration of download Called at the ending of download + * with current > max + * @param current: Size of file already downloaded + * @param max: Size of file we want to download + */ + void OnProgress(int current, int max); + + /** + * Called when we failed to download codec + * @param error: Error message + */ + void OnError(String error); +} From eac08cf5197c5b5ec25c1403bae47db6717ca35b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 13 Oct 2017 14:46:28 +0200 Subject: [PATCH 0482/2215] Move chat notifications source files in their own directory. --- src/CMakeLists.txt | 9 +++++---- src/c-wrapper/api/c-chat-message.cpp | 2 +- src/chat/chat-message/chat-message-p.h | 2 +- src/chat/chat-room/chat-room-p.h | 2 +- src/chat/chat-room/chat-room.cpp | 2 +- src/chat/{ => notification}/imdn.cpp | 4 ++-- src/chat/{ => notification}/imdn.h | 0 src/chat/{ => notification}/is-composing-listener.h | 0 src/chat/{ => notification}/is-composing.cpp | 2 +- src/chat/{ => notification}/is-composing.h | 2 +- 10 files changed, 13 insertions(+), 12 deletions(-) rename src/chat/{ => notification}/imdn.cpp (99%) rename src/chat/{ => notification}/imdn.h (100%) rename src/chat/{ => notification}/is-composing-listener.h (100%) rename src/chat/{ => notification}/is-composing.cpp (99%) rename src/chat/{ => notification}/is-composing.h (97%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5e7299545..545159bc4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,12 +47,13 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES chat/cpim/message/cpim-message.h chat/cpim/parser/cpim-grammar.h chat/cpim/parser/cpim-parser.h - chat/imdn.h - chat/is-composing.h chat/modifier/chat-message-modifier.h chat/modifier/cpim-chat-message-modifier.h chat/modifier/encryption-chat-message-modifier.h chat/modifier/multipart-chat-message-modifier.h + chat/notification/imdn.h + chat/notification/is-composing.h + chat/notification/is-composing-listener.h conference/conference-listener.h conference/conference-p.h conference/conference.h @@ -138,11 +139,11 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES chat/cpim/message/cpim-message.cpp chat/cpim/parser/cpim-grammar.cpp chat/cpim/parser/cpim-parser.cpp - chat/imdn.cpp - chat/is-composing.cpp chat/modifier/cpim-chat-message-modifier.cpp chat/modifier/encryption-chat-message-modifier.cpp chat/modifier/multipart-chat-message-modifier.cpp + chat/notification/imdn.cpp + chat/notification/is-composing.cpp conference/conference.cpp conference/local-conference-event-handler.cpp conference/local-conference.cpp diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 95910a1d3..1c0db2089 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -30,7 +30,7 @@ #include "chat/chat-message/chat-message-p.h" #include "chat/chat-room/chat-room-p.h" #include "chat/chat-room/real-time-text-chat-room-p.h" -#include "chat/imdn.h" +#include "chat/notification/imdn.h" // ============================================================================= diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index 73c8a58f2..cf827e2f7 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -23,7 +23,7 @@ #include #include "chat/chat-message/chat-message.h" -#include "chat/imdn.h" +#include "chat/notification/imdn.h" #include "content/content.h" #include "content/content-type.h" #include "db/events-db.h" diff --git a/src/chat/chat-room/chat-room-p.h b/src/chat/chat-room/chat-room-p.h index 4dd4663f6..c1f3823ee 100644 --- a/src/chat/chat-room/chat-room-p.h +++ b/src/chat/chat-room/chat-room-p.h @@ -20,7 +20,7 @@ #ifndef _CHAT_ROOM_P_H_ #define _CHAT_ROOM_P_H_ -#include "chat/is-composing.h" +#include "chat/notification/is-composing.h" #include "chat-room.h" #include "object/object-p.h" diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index c980b6566..315682bdc 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -22,7 +22,7 @@ #include "c-wrapper/c-wrapper.h" #include "chat/chat-message/chat-message-p.h" #include "chat/chat-room/chat-room-p.h" -#include "chat/imdn.h" +#include "chat/notification/imdn.h" #include "logger/logger.h" // ============================================================================= diff --git a/src/chat/imdn.cpp b/src/chat/notification/imdn.cpp similarity index 99% rename from src/chat/imdn.cpp rename to src/chat/notification/imdn.cpp index 66900cb4c..8a63b1966 100644 --- a/src/chat/imdn.cpp +++ b/src/chat/notification/imdn.cpp @@ -19,9 +19,9 @@ #include "logger/logger.h" -#include "chat/imdn.h" -#include "chat/chat-room/chat-room.h" #include "chat/chat-message/chat-message.h" +#include "chat/chat-room/chat-room.h" +#include "chat/notification/imdn.h" // ============================================================================= diff --git a/src/chat/imdn.h b/src/chat/notification/imdn.h similarity index 100% rename from src/chat/imdn.h rename to src/chat/notification/imdn.h diff --git a/src/chat/is-composing-listener.h b/src/chat/notification/is-composing-listener.h similarity index 100% rename from src/chat/is-composing-listener.h rename to src/chat/notification/is-composing-listener.h diff --git a/src/chat/is-composing.cpp b/src/chat/notification/is-composing.cpp similarity index 99% rename from src/chat/is-composing.cpp rename to src/chat/notification/is-composing.cpp index 93261385b..a488fdb77 100644 --- a/src/chat/is-composing.cpp +++ b/src/chat/notification/is-composing.cpp @@ -20,9 +20,9 @@ #include "linphone/utils/utils.h" #include "chat/chat-room/chat-room-p.h" +#include "chat/notification/is-composing.h" #include "logger/logger.h" -#include "chat/is-composing.h" // ============================================================================= diff --git a/src/chat/is-composing.h b/src/chat/notification/is-composing.h similarity index 97% rename from src/chat/is-composing.h rename to src/chat/notification/is-composing.h index 35d281fa3..fda928ae1 100644 --- a/src/chat/is-composing.h +++ b/src/chat/notification/is-composing.h @@ -22,7 +22,7 @@ #include "linphone/utils/general.h" -#include "chat/is-composing-listener.h" +#include "chat/notification/is-composing-listener.h" #include "private.h" From 706cdd8eed6e5e81ff798f6fbef6e6d776c54a22 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 13 Oct 2017 15:16:59 +0200 Subject: [PATCH 0483/2215] Updated OpenH264DownloadHelper.java --- .../classes/tools/OpenH264DownloadHelper.java | 12 +++++++- wrappers/java/migration.sh | 30 ++++++++++++++++--- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/wrappers/java/classes/tools/OpenH264DownloadHelper.java b/wrappers/java/classes/tools/OpenH264DownloadHelper.java index 6c0ce3744..e987436a0 100644 --- a/wrappers/java/classes/tools/OpenH264DownloadHelper.java +++ b/wrappers/java/classes/tools/OpenH264DownloadHelper.java @@ -38,6 +38,8 @@ import org.linphone.mediastream.Log; * @author Erwan Croze */ public class OpenH264DownloadHelper { + private static boolean isDownloadEnabled; + private OpenH264DownloadHelperListener openH264DownloadHelperListener; private ArrayList userData; private String fileDirection; @@ -63,7 +65,15 @@ public class OpenH264DownloadHelper { } } - public static boolean isOpenH264DownloadEnabled(Context context) { + public static boolean isOpenH264DownloadEnabled() { + return isDownloadEnabled; + } + + public static void setOpenH264DownloadEnabled(boolean enabled) { + isDownloadEnabled = enabled; + } + + public static boolean checkIfOpenH264DownloadCanBeEnabled(Context context) { File file = new File(context.getApplicationInfo().nativeLibraryDir+"/libmsopenh264.so"); if (!file.exists()) { diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 452e783a8..ba773ad8f 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -156,7 +156,9 @@ eval "$SED_START 's/findFriendByAddress(/findFriend(/g' $SED_END" eval "$SED_START 's/getTimestamp()/getStartDate()/g' $SED_END" #For ProxyConfigs only eval "$SED_START 's/lpc.getAddress()/lpc.getIdentityAddress()/g' $SED_END" -eval "$SED_START 's/cfg.getAddress()/lpc.getIdentityAddress()/g' $SED_END" +eval "$SED_START 's/cfg.getAddress()/cfg.getIdentityAddress()/g' $SED_END" +eval "$SED_START 's/prxCfg.getAddress()/prxCfg.getIdentityAddress()/g' $SED_END" +eval "$SED_START 's/proxy.getAddress()/proxy.getIdentityAddress()/g' $SED_END" # eval "$SED_START 's/getCallDuration()/getDuration()/g' $SED_END" eval "$SED_START 's/isVCardSupported()/vcardSupported()/g' $SED_END" @@ -186,12 +188,20 @@ eval "$SED_START 's/activatePhoneNumberLink()/activateAlias()/g' $SED_END" eval "$SED_START 's/isPhoneNumberUsed()/isAliasUsed()/g' $SED_END" eval "$SED_START 's/recoverPhoneAccount()/recoverAccount()/g' $SED_END" eval "$SED_START 's/isLimeEncryptionAvailable()/limeAvailable()/g' $SED_END" +eval "$SED_START 's/getUseRfc2833ForDtmfs/getUseRfc2833ForDtmf/g' $SED_END" +eval "$SED_START 's/setUseRfc2833ForDtmfs/setUseRfc2833ForDtmf/g' $SED_END" +eval "$SED_START 's/getUseSipInfoForDtmfs/getUseInfoForDtmf/g' $SED_END" +eval "$SED_START 's/setUseSipInfoForDtmfs/setUseInfoForDtmf/g' $SED_END" +eval "$SED_START 's/getIncomingTimeout/getIncTimeout/g' $SED_END" +eval "$SED_START 's/setIncomingTimeout/setIncTimeout/g' $SED_END" +eval "$SED_START 's/migrateCallLogs()/migrateLogsFromRcToDb()/g' $SED_END" +eval "$SED_START 's/setRLSUri/setRlsUri/g' $SED_END" # Removed methods eval "$SED_START 's/.isRegistered()/.getState() == RegistrationState.Ok/g' $SED_END" eval "$SED_START 's/getBool(/getInt(/g' $SED_END" eval "$SED_START 's/setBool(/setInt(/g' $SED_END" -eval "$SED_START 's/isInConference()/getConference() != null/g' $SED_END" +eval "$SED_START 's/isInConference()/(getConference() != null)/g' $SED_END" eval "$SED_START 's/getAudioStats()/getStats(StreamType.Audio)/g' $SED_END" eval "$SED_START 's/getVideoStats()/getStats(StreamType.Video)/g' $SED_END" eval "$SED_START 's/getVcardToString()/getVcard().asVcard4String()/g' $SED_END" @@ -212,9 +222,12 @@ eval "$SED_START 's/transports.tls/transports.getTlsPort()/g' $SED_END" eval "$SED_START 's/getPrimaryContactUsername()/getPrimaryContactParsed().getUsername()/g' $SED_END" eval "$SED_START 's/getPrimaryContactDisplayName()/getPrimaryContactParsed().getDisplayName()/g' $SED_END" eval "$SED_START 's/.sendDtmf(/.getCurrentCall().sendDtmf(/g' $SED_END" +eval "$SED_START 's/content.getData() == null/content.getSize() == 0/'g $SED_END" +eval "$SED_START 's/lc.downloadOpenH264Enabled()/OpenH264DownloadHelper.isOpenH264DownloadEnabled()/g' $SED_END" +eval "$SED_START 's/enableDownloadOpenH264(/OpenH264DownloadHelper.enableDownloadOpenH264(/g' $SED_END" #Changes in library required -#OpenH264DownloadHelper +#Tunnel #DialPlan #LinphoneBuffer #Call.zoomVideo() @@ -222,12 +235,15 @@ eval "$SED_START 's/.sendDtmf(/.getCurrentCall().sendDtmf(/g' $SED_END" #Factory.instance().enableLogCollection(isDebugEnabled); #Factory.instance().setDebugMode(isDebugEnabled, getString(R.string.app_name)); #Factory.instance().createConfig(String s); -#Core.enableDownloadOpenH264 +#AccountCreator.updatePassword #Android specifics not wrapped automatically #Core.needsEchoCalibration() #Core.hasCrappyOpenGL() #Core.getMSFactory() +#COre.startEchoCalibration +#Core.startEchoTester +#Core.stopEchoTester # For the payloads, get the list from the Core, call the method on the object directly and set it back if required #Core.enablePayloadType() @@ -235,9 +251,15 @@ eval "$SED_START 's/.sendDtmf(/.getCurrentCall().sendDtmf(/g' $SED_END" #Core.payloadTypeIsVbr() #Core.setPayloadTypeBitrate() +#Factory.createLpConfigFromString => Config.newFromBuffer +#Factory.createLpConfig => Config.newWithFactory or Core.createConfig +#Core.getVideoDevice and Core.setVideoDevice now takes/returns String instead of int +#Factory.createAccountCreator() => Core.createAccountCreator() +#Factory.createPresenceModel() => Core.createPresenceModel() #CallParams.getJitterBufferSize() => CallStatsImpl.getJitterBufferSizeMs() #Core.getSupportedVideoSizes() => Factory.getSupportedVideoDefinitions() #Core.removeFriend() => FriendList.removeFriend() +#Core.getFriendsLists() => now returns a FriendList[] instead of a Friend[] #Core.enableSpeaker / isSpeakerEnabled() => mAudioManager.setSpeakerphoneOn(speakerOn); #Core.enableVideo(true, true) => Core.enableVideoCapture(bool) & Core.enableVideoDisplay(bool) #Core.setCpuCount() => Not needed anymore, can be removed From ec18035244c1e09301799cf6a1ea68445671957d Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 13 Oct 2017 15:20:19 +0200 Subject: [PATCH 0484/2215] add custom header telling last received notify to conf event subscribe --- src/conference/participant-device.cpp | 2 +- src/conference/remote-conference-event-handler.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/conference/participant-device.cpp b/src/conference/participant-device.cpp index 524ae7e2d..16a2130c3 100644 --- a/src/conference/participant-device.cpp +++ b/src/conference/participant-device.cpp @@ -33,4 +33,4 @@ bool ParticipantDevice::operator== (const ParticipantDevice &device) const { return (mGruu == device.getGruu()); } -LINPHONE_END_NAMESPACE \ No newline at end of file +LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 749cd5bed..53eeaf20a 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -20,6 +20,7 @@ #include "private.h" #include "logger/logger.h" #include "remote-conference-event-handler-p.h" +#include "linphone/utils/utils.h" #include "xml/conference-info.h" // ============================================================================= @@ -49,10 +50,10 @@ RemoteConferenceEventHandler::~RemoteConferenceEventHandler () { void RemoteConferenceEventHandler::subscribe (const Address &addr) { L_D(); - // TODO : add last notify d->confAddress = addr; LinphoneAddress *lAddr = linphone_address_new(d->confAddress.asString().c_str()); d->lev = linphone_core_create_subscribe(d->core, lAddr, "conference", 600); + linphone_event_add_custom_header(d->lev, "Last-Notify-Version", Utils::toString(d->lastNotify).c_str()); linphone_address_unref(lAddr); linphone_event_set_internal(d->lev, TRUE); linphone_event_set_user_data(d->lev, this); From 5cf6bc3b6b80e716adc1b5f84104b4220c87313f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 13 Oct 2017 15:32:47 +0200 Subject: [PATCH 0485/2215] Handle case where a received chat message is in fact an outgoing message sent by us from an other device. --- src/chat/chat-message/chat-message.cpp | 37 +++++++++++++++----------- src/chat/chat-room/chat-room-p.h | 1 - src/chat/chat-room/chat-room.cpp | 6 ----- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 94bea15a8..d163223e8 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -989,7 +989,6 @@ LinphoneReason ChatMessagePrivate::receive() { L_Q(); int errorCode = 0; LinphoneReason reason = LinphoneReasonNone; - bool store = false; // --------------------------------------- // Start of message modification @@ -1024,13 +1023,12 @@ LinphoneReason ChatMessagePrivate::receive() { if (errorCode <= 0) { bool foundSupportContentType = false; - for (auto it = contents.begin(); it != contents.end(); it++) { - if (linphone_core_is_content_type_supported(chatRoom->getCore(), it->getContentType().asString().c_str())) { + for (const auto &c : contents) { + if (linphone_core_is_content_type_supported(chatRoom->getCore(), c.getContentType().asString().c_str())) { foundSupportContentType = true; break; - } else { - lError() << "Unsupported content-type: " << it->getContentType().asString(); - } + } else + lError() << "Unsupported content-type: " << c.getContentType().asString(); } if (!foundSupportContentType) { @@ -1039,24 +1037,31 @@ LinphoneReason ChatMessagePrivate::receive() { } } + // Check if this is in fact an outgoing message (case where this is a message sent by us from an other device) + Address me(linphone_core_get_identity(chatRoom->getCore())); + if (me.weakEqual(from)) + setDirection(ChatMessage::Direction::Outgoing); + + /* Check if this is a duplicate message */ + if (chatRoom->findMessageWithDirection(q->getImdnMessageId(), q->getDirection())) + return chatRoom->getCore()->chat_deny_code; + if (errorCode > 0) { reason = linphone_error_code_to_reason(errorCode); q->sendDeliveryNotification(reason); return reason; } - for (auto it = contents.begin(); it != contents.end(); it++) { - if (it->getContentType() == ContentType::FileTransfer) { - store = true; - createFileTransferInformationsFromVndGsmaRcsFtHttpXml(it->getBodyAsString()); - } else if (it->getContentType() == ContentType::PlainText) { - store = true; - } + bool messageToBeStored = false; + for (const auto &c : contents) { + if (c.getContentType() == ContentType::FileTransfer) { + messageToBeStored = true; + createFileTransferInformationsFromVndGsmaRcsFtHttpXml(c.getBodyAsString()); + } else if (c.getContentType() == ContentType::PlainText) + messageToBeStored = true; } - - if (store) { + if (messageToBeStored) q->store(); - } return reason; } diff --git a/src/chat/chat-room/chat-room-p.h b/src/chat/chat-room/chat-room-p.h index c1f3823ee..0074c3767 100644 --- a/src/chat/chat-room/chat-room-p.h +++ b/src/chat/chat-room/chat-room-p.h @@ -98,7 +98,6 @@ public: std::list> messages; std::list> transientMessages; std::list> weakMessages; - std::list receivedRttCharacters; std::shared_ptr pendingMessage = nullptr; IsComposing isComposingHandler; diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 315682bdc..96eb6b1c8 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -371,12 +371,6 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa LinphoneReason reason = LinphoneReasonNone; shared_ptr msg; - /* Check if this is a duplicate message */ - if ((msg = q->findMessageWithDirection(op->get_call_id(), ChatMessage::Direction::Incoming))) { - reason = core->chat_deny_code; - return reason; - } - msg = q->createMessage(); Content content; From 91fc02dbccaa766da0c2e63169e6169103ec0087 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 13 Oct 2017 15:35:59 +0200 Subject: [PATCH 0486/2215] get last Notify received from the susbcribe --- src/conference/local-conference-event-handler.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 42d75d19d..272cde56a 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -19,6 +19,7 @@ #include "conference/local-conference.h" #include "conference/participant-p.h" +#include "linphone/utils/utils.h" #include "local-conference-event-handler-p.h" #include "object/object-p.h" #include "private.h" @@ -184,7 +185,6 @@ string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged () { string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceAdded (const Address &addr, const Address &gruu) { string entity = conf->getConferenceAddress().asStringUriOnly(); - string subject = conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -209,7 +209,6 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceAdded (c string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceRemoved (const Address &addr, const Address &gruu) { string entity = conf->getConferenceAddress().asStringUriOnly(); - string subject = conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -265,8 +264,13 @@ void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) { bctbx_free(addrStr); if (participant) { if (linphone_event_get_subscription_state(lev) == LinphoneSubscriptionActive) { - participant->getPrivate()->subscribeToConferenceEventPackage(true); - d->notifyFullState(d->createNotifyFullState(), lev); + int lastNotify = Utils::stoi(linphone_event_get_custom_header(lev, "Last-Notify-Version")); + if(lastNotify == 0) { + participant->getPrivate()->subscribeToConferenceEventPackage(true); + d->notifyFullState(d->createNotifyFullState(), lev); + } else { + // TODO : send all missed notify from lastNotify to d->lastNotify + } } else if (linphone_event_get_subscription_state(lev) == LinphoneSubscriptionTerminated) participant->getPrivate()->subscribeToConferenceEventPackage(false); } From 367243d2240faef58e13632677a9b95b26c14173 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 13 Oct 2017 15:46:45 +0200 Subject: [PATCH 0487/2215] feat(MainDb): chatroom fetch in progress --- src/CMakeLists.txt | 4 +- src/chat/chat-message/chat-message-p.h | 2 - src/chat/chat-message/chat-message.cpp | 1 - src/db/{events-db.cpp => main-db.cpp} | 131 ++++++++++++++++--------- src/db/{events-db.h => main-db.h} | 24 +++-- src/event-log/event-log.h | 2 +- tester/events-db-tester.cpp | 2 +- 7 files changed, 104 insertions(+), 62 deletions(-) rename src/db/{events-db.cpp => main-db.cpp} (86%) rename src/db/{events-db.h => main-db.h} (84%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 545159bc4..1d8c0c1c1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -82,7 +82,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/core.h db/abstract/abstract-db-p.h db/abstract/abstract-db.h - db/events-db.h + db/main-db.h db/session/db-session-p.h db/session/db-session-provider.h db/session/db-session.h @@ -159,7 +159,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES content/content.cpp core/core.cpp db/abstract/abstract-db.cpp - db/events-db.cpp + db/main-db.cpp db/session/db-session-provider.cpp db/session/db-session.cpp event-log/call-event.cpp diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index cf827e2f7..accd87b3c 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -26,7 +26,6 @@ #include "chat/notification/imdn.h" #include "content/content.h" #include "content/content-type.h" -#include "db/events-db.h" #include "object/object-p.h" #include "sal/sal.h" @@ -137,7 +136,6 @@ private: std::list contents; Content internalContent; std::unordered_map customHeaders; - std::shared_ptr eventsDb; mutable LinphoneErrorInfo * errorInfo = NULL; belle_http_request_t *httpRequest = NULL; belle_http_request_listener_t *httpListener = NULL; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index d163223e8..ebcf0e8c8 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -17,7 +17,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "db/events-db.h" #include "object/object-p.h" #include "linphone/core.h" diff --git a/src/db/events-db.cpp b/src/db/main-db.cpp similarity index 86% rename from src/db/events-db.cpp rename to src/db/main-db.cpp index e827d244e..5d7918755 100644 --- a/src/db/events-db.cpp +++ b/src/db/main-db.cpp @@ -1,5 +1,5 @@ /* - * events-db.cpp + * main-db.cpp * Copyright (C) 2010-2017 Belledonne Communications SARL * * This program is free software; you can redistribute it and/or @@ -38,7 +38,7 @@ #include "event-log/event-log-p.h" #include "logger/logger.h" -#include "events-db.h" +#include "main-db.h" // ============================================================================= @@ -55,7 +55,7 @@ struct MessageEventReferences { #endif }; -class EventsDbPrivate : public AbstractDbPrivate { +class MainDbPrivate : public AbstractDbPrivate { #ifdef SOCI_ENABLED public: long insertSipAddress (const string &sipAddress); @@ -80,12 +80,14 @@ public: #endif private: - L_DECLARE_PUBLIC(EventsDb); + unordered_map> chatRooms; + + L_DECLARE_PUBLIC(MainDb); }; // ----------------------------------------------------------------------------- -EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} +MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} #ifdef SOCI_ENABLED @@ -106,13 +108,13 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} ); } - static constexpr EnumToSql eventFilterToSql[] = { - { EventsDb::MessageFilter, "1" }, - { EventsDb::CallFilter, "2" }, - { EventsDb::ConferenceFilter, "3" } + static constexpr EnumToSql eventFilterToSql[] = { + { MainDb::MessageFilter, "1" }, + { MainDb::CallFilter, "2" }, + { MainDb::ConferenceFilter, "3" } }; - static constexpr const char *mapEventFilterToSql (EventsDb::Filter filter) { + static constexpr const char *mapEventFilterToSql (MainDb::Filter filter) { return mapEnumToSql( eventFilterToSql, sizeof eventFilterToSql / sizeof eventFilterToSql[0], filter ); @@ -120,14 +122,14 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} // ----------------------------------------------------------------------------- - static string buildSqlEventFilter (const list &filters, EventsDb::FilterMask mask) { + static string buildSqlEventFilter (const list &filters, MainDb::FilterMask mask) { L_ASSERT( - find_if(filters.cbegin(), filters.cend(), [](const EventsDb::Filter &filter) { - return filter == EventsDb::NoFilter; + find_if(filters.cbegin(), filters.cend(), [](const MainDb::Filter &filter) { + return filter == MainDb::NoFilter; }) == filters.cend() ); - if (mask == EventsDb::NoFilter) + if (mask == MainDb::NoFilter) return ""; bool isStart = true; @@ -150,7 +152,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} // ----------------------------------------------------------------------------- - long EventsDbPrivate::insertSipAddress (const string &sipAddress) { + long MainDbPrivate::insertSipAddress (const string &sipAddress) { L_Q(); soci::session *session = dbSession.getBackendSession(); @@ -163,7 +165,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return q->getLastInsertId(); } - void EventsDbPrivate::insertContent (long messageEventId, const Content &content) { + void MainDbPrivate::insertContent (long messageEventId, const Content &content) { L_Q(); soci::session *session = dbSession.getBackendSession(); @@ -180,7 +182,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} soci::use(messageContentId), soci::use(appData.first), soci::use(appData.second); } - long EventsDbPrivate::insertContentType (const string &contentType) { + long MainDbPrivate::insertContentType (const string &contentType) { L_Q(); soci::session *session = dbSession.getBackendSession(); @@ -193,7 +195,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return q->getLastInsertId(); } - long EventsDbPrivate::insertEvent (EventLog::Type type, const tm &date) { + long MainDbPrivate::insertEvent (EventLog::Type type, const tm &date) { L_Q(); soci::session *session = dbSession.getBackendSession(); @@ -202,7 +204,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return q->getLastInsertId(); } - long EventsDbPrivate::insertChatRoom (long sipAddressId, int capabilities, const tm &date) { + long MainDbPrivate::insertChatRoom (long sipAddressId, int capabilities, const tm &date) { soci::session *session = dbSession.getBackendSession(); long id; @@ -219,7 +221,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return sipAddressId; } - void EventsDbPrivate::insertChatRoomParticipant (long chatRoomId, long sipAddressId, bool isAdmin) { + void MainDbPrivate::insertChatRoomParticipant (long chatRoomId, long sipAddressId, bool isAdmin) { soci::session *session = dbSession.getBackendSession(); soci::statement statement = ( session->prepare << "UPDATE chat_room_participant SET is_admin = :isAdmin" @@ -233,7 +235,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} soci::use(chatRoomId), soci::use(sipAddressId), soci::use(static_cast(isAdmin)); } - long EventsDbPrivate::insertMessageEvent ( + long MainDbPrivate::insertMessageEvent ( const MessageEventReferences &references, ChatMessage::State state, ChatMessage::Direction direction, @@ -262,7 +264,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return messageEventId; } - void EventsDbPrivate::insertMessageParticipant (long messageEventId, long sipAddressId, ChatMessage::State state) { + void MainDbPrivate::insertMessageParticipant (long messageEventId, long sipAddressId, ChatMessage::State state) { soci::session *session = dbSession.getBackendSession(); soci::statement statement = ( session->prepare << "UPDATE message_participant SET state = :state" @@ -304,7 +306,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return T(); } - void EventsDbPrivate::importLegacyMessages (const soci::rowset &messages) { + void MainDbPrivate::importLegacyMessages (const soci::rowset &messages) { soci::session *session = dbSession.getBackendSession(); soci::transaction tr(*session); @@ -395,7 +397,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} // ----------------------------------------------------------------------------- - void EventsDb::init () { + void MainDb::init () { L_D(); soci::session *session = d->dbSession.getBackendSession(); @@ -561,7 +563,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} *session << participantMessageDeleter; } - bool EventsDb::addEvent (const EventLog &eventLog) { + bool MainDb::addEvent (const EventLog &eventLog) { if (!isConnected()) { lWarning() << "Unable to add event. Not connected."; return false; @@ -586,7 +588,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return true; } - bool EventsDb::deleteEvent (const EventLog &eventLog) { + bool MainDb::deleteEvent (const EventLog &eventLog) { L_D(); if (!isConnected()) { @@ -609,7 +611,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return id == -1; } - void EventsDb::cleanEvents (FilterMask mask) { + void MainDb::cleanEvents (FilterMask mask) { L_D(); if (!isConnected()) { @@ -628,7 +630,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} L_END_LOG_EXCEPTION } - int EventsDb::getEventsCount (FilterMask mask) const { + int MainDb::getEventsCount (FilterMask mask) const { L_D(); if (!isConnected()) { @@ -650,7 +652,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return count; } - int EventsDb::getMessagesCount (const string &peerAddress) const { + int MainDb::getMessagesCount (const string &peerAddress) const { L_D(); if (!isConnected()) { @@ -680,7 +682,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return count; } - int EventsDb::getUnreadMessagesCount (const string &peerAddress) const { + int MainDb::getUnreadMessagesCount (const string &peerAddress) const { L_D(); if (!isConnected()) { @@ -713,7 +715,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return count; } - list> EventsDb::getHistory (const string &peerAddress, int nLast, FilterMask mask) const { + list> MainDb::getHistory (const string &peerAddress, int nLast, FilterMask mask) const { if (!isConnected()) { lWarning() << "Unable to get history. Not connected."; return list>(); @@ -726,7 +728,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return list>(); } - list> EventsDb::getHistory ( + list> MainDb::getHistory ( const string &peerAddress, int begin, int end, @@ -745,7 +747,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} return list>(); } - void EventsDb::cleanHistory (const string &peerAddress, FilterMask mask) { + void MainDb::cleanHistory (const string &peerAddress, FilterMask mask) { L_D(); if (!isConnected()) { @@ -754,7 +756,7 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} } string query; - if (mask == EventsDb::NoFilter || mask & MessageFilter) + if (mask == MainDb::NoFilter || mask & MessageFilter) query += "SELECT event_id FROM message_event WHERE chat_room_id = (" " SELECT peer_sip_address_id FROM chat_room WHERE peer_sip_address_id = (" " SELECT id FROM sip_address WHERE value = :peerAddress" @@ -774,7 +776,42 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} // ----------------------------------------------------------------------------- - bool EventsDb::import (Backend, const string ¶meters) { +shared_ptr MainDb::findChatRoom (const string &peerAddress) const { + L_D(); + + const auto it = d->chatRooms.find(peerAddress); + if (it != d->chatRooms.cend()) { + try { + return it->second.lock(); + } catch (const exception &) { + lError() << "Cannot lock chat room: `" + peerAddress + "`"; + } + } else { + L_BEGIN_LOG_EXCEPTION + + soci::session *session = d->dbSession.getBackendSession(); + + tm creationDate; + tm lastUpdateDate; + int capabilities; + string subject; + + *session << "SELECT creation_date, last_update_date, capabilities, subject " + " FROM chat_room" + " WHERE peer_sip_address_id = (" + " SELECT id from sip_address WHERE value = :peerAddress" + " )", soci::use(peerAddress), soci::into(creationDate), soci::into(lastUpdateDate), + soci::use(capabilities), soci::use(subject); + + L_END_LOG_EXCEPTION + } + + return shared_ptr(); +} + +// ----------------------------------------------------------------------------- + + bool MainDb::import (Backend, const string ¶meters) { L_D(); if (!isConnected()) { @@ -817,41 +854,43 @@ EventsDb::EventsDb () : AbstractDb(*new EventsDbPrivate) {} #else - void EventsDb::init () {} + void MainDb::init () {} - bool EventsDb::addEvent (const EventLog &) { + bool MainDb::addEvent (const EventLog &) { return false; } - bool EventsDb::deleteEvent (const EventLog &) { + bool MainDb::deleteEvent (const EventLog &) { return false; } - void EventsDb::cleanEvents (FilterMask) {} + void MainDb::cleanEvents (FilterMask) {} - int EventsDb::getEventsCount (FilterMask) const { + int MainDb::getEventsCount (FilterMask) const { return 0; } - int EventsDb::getMessagesCount (const string &) const { + int MainDb::getMessagesCount (const string &) const { return 0; } - int EventsDb::getUnreadMessagesCount (const string &) const { + int MainDb::getUnreadMessagesCount (const string &) const { return 0; } - list> EventsDb::getHistory (const string &, int, FilterMask) const { + list> MainDb::getHistory (const string &, int, FilterMask) const { return list>(); } - list> EventsDb::getHistory (const string &, int, int, FilterMask) const { + list> MainDb::getHistory (const string &, int, int, FilterMask) const { return list>(); } - void EventsDb::cleanHistory (const string &, FilterMask) {} + void MainDb::cleanHistory (const string &, FilterMask) {} - bool EventsDb::import (Backend, const string &) { + shared_ptr MainDb::findChatRoom (const string &) const {} + + bool MainDb::import (Backend, const string &) { return false; } diff --git a/src/db/events-db.h b/src/db/main-db.h similarity index 84% rename from src/db/events-db.h rename to src/db/main-db.h index d582f5149..1cc262bc1 100644 --- a/src/db/events-db.h +++ b/src/db/main-db.h @@ -1,5 +1,5 @@ /* - * events-db.h + * main-db.h * Copyright (C) 2010-2017 Belledonne Communications SARL * * This program is free software; you can redistribute it and/or @@ -17,8 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef _EVENTS_DB_H_ -#define _EVENTS_DB_H_ +#ifndef _MAIN_DB_H_ +#define _MAIN_DB_H_ #include @@ -28,10 +28,13 @@ LINPHONE_BEGIN_NAMESPACE +class ChatRoom; class EventLog; -class EventsDbPrivate; +class MainDbPrivate; + +class LINPHONE_PUBLIC MainDb : public AbstractDb { + friend class ChatRoomProvider; -class LINPHONE_PUBLIC EventsDb : public AbstractDb { public: enum Filter { NoFilter = 0x0, @@ -42,7 +45,7 @@ public: typedef int FilterMask; - EventsDb (); + MainDb (); // Generic. bool addEvent (const EventLog &eventLog); @@ -66,6 +69,9 @@ public: ) const; void cleanHistory (const std::string &peerAddress = "", FilterMask mask = NoFilter); + // ChatRooms. + std::shared_ptr findChatRoom (const std::string &peerAddress) const; + // Import legacy messages from old db. bool import (Backend backend, const std::string ¶meters) override; @@ -73,10 +79,10 @@ protected: void init () override; private: - L_DECLARE_PRIVATE(EventsDb); - L_DISABLE_COPY(EventsDb); + L_DECLARE_PRIVATE(MainDb); + L_DISABLE_COPY(MainDb); }; LINPHONE_END_NAMESPACE -#endif // ifndef _EVENTS_DB_H_ +#endif // ifndef _MAIN_DB_H_ diff --git a/src/event-log/event-log.h b/src/event-log/event-log.h index 357e88f80..256fd2d53 100644 --- a/src/event-log/event-log.h +++ b/src/event-log/event-log.h @@ -32,7 +32,7 @@ LINPHONE_BEGIN_NAMESPACE class EventLogPrivate; class LINPHONE_PUBLIC EventLog : public ClonableObject { - friend class EventsDb; + friend class MainDb; public: L_DECLARE_ENUM(Type, L_ENUM_VALUES_EVENT_LOG_TYPE); diff --git a/tester/events-db-tester.cpp b/tester/events-db-tester.cpp index bf110400f..6c79d449c 100644 --- a/tester/events-db-tester.cpp +++ b/tester/events-db-tester.cpp @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -#include "db/events-db.h" +#include "db/main-db.h" #include "liblinphone_tester.h" From a7adfbdaf513c564e5417fd2312f642c8ea3ca0d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 13 Oct 2017 15:21:03 +0200 Subject: [PATCH 0488/2215] Improvements on OpenH264 Java helper --- .../classes/tools/OpenH264DownloadHelper.java | 31 ++++++++----------- wrappers/java/migration.sh | 1 - 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/wrappers/java/classes/tools/OpenH264DownloadHelper.java b/wrappers/java/classes/tools/OpenH264DownloadHelper.java index e987436a0..170bda78d 100644 --- a/wrappers/java/classes/tools/OpenH264DownloadHelper.java +++ b/wrappers/java/classes/tools/OpenH264DownloadHelper.java @@ -63,6 +63,19 @@ public class OpenH264DownloadHelper { if (context.getFilesDir() != null) { fileDirection = context.getFilesDir().toString(); } + + File file = new File(context.getApplicationInfo().nativeLibraryDir+"/libmsopenh264.so"); + if (!file.exists()) { + Log.i("LinphoneCoreFactoryImpl"," libmsopenh264 not found, we disable the download of Openh264"); + isDownloadEnabled = false; + } + if (isCodecFound()) { + Log.i("OpenH264DownloadHelper"," Loading OpenH264 downloaded plugin:" + downloadHelper.getFullPathLib()); + System.load(downloadHelper.getFullPathLib()); + } else { + Log.i("OpenH264DownloadHelper"," Cannot load OpenH264 downloaded plugin"); + } + isDownloadEnabled = true; } public static boolean isOpenH264DownloadEnabled() { @@ -73,24 +86,6 @@ public class OpenH264DownloadHelper { isDownloadEnabled = enabled; } - public static boolean checkIfOpenH264DownloadCanBeEnabled(Context context) { - File file = new File(context.getApplicationInfo().nativeLibraryDir+"/libmsopenh264.so"); - - if (!file.exists()) { - Log.i("LinphoneCoreFactoryImpl"," libmsopenh264 not found, we disable the download of Openh264"); - return false; - } - - OpenH264DownloadHelper downloadHelper = new OpenH264DownloadHelper(context); - if (downloadHelper.isCodecFound()) { - Log.i("OpenH264DownloadHelper"," Loading OpenH264 downloaded plugin:" + downloadHelper.getFullPathLib()); - System.load(downloadHelper.getFullPathLib()); - } else { - Log.i("OpenH264DownloadHelper"," Cannot load OpenH264 downloaded plugin"); - } - return true; - } - /** * Set OpenH264DownloadHelperListener * @param h264Listener diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index ba773ad8f..ef80e0005 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -234,7 +234,6 @@ eval "$SED_START 's/enableDownloadOpenH264(/OpenH264DownloadHelper.enableDownloa #Factory.instance().setLogCollectionPath(getFilesDir().getAbsolutePath()); #Factory.instance().enableLogCollection(isDebugEnabled); #Factory.instance().setDebugMode(isDebugEnabled, getString(R.string.app_name)); -#Factory.instance().createConfig(String s); #AccountCreator.updatePassword #Android specifics not wrapped automatically From 668dc9b6943718f8f5b1fbdb0321885981eb6bef Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 13 Oct 2017 18:01:42 +0200 Subject: [PATCH 0489/2215] Started new DialPlan object, still a few compilation issues --- coreapi/account_creator.c | 5 +- coreapi/dial_plan.c | 311 ---------------------- coreapi/proxy.c | 33 +-- include/CMakeLists.txt | 1 + include/linphone/api/c-dial-plan.h | 91 +++++++ include/linphone/api/c-types.h | 6 + include/linphone/core_utils.h | 45 ---- src/CMakeLists.txt | 4 + src/c-wrapper/api/c-dial-plan.cpp | 90 +++++++ src/c-wrapper/c-wrapper.h | 1 + src/db/main-db.cpp | 4 +- src/dial-plan/dial-plan-p.h | 44 ++++ src/dial-plan/dial-plan.cpp | 399 +++++++++++++++++++++++++++++ src/dial-plan/dial-plan.h | 63 +++++ wrappers/java/migration.sh | 6 +- 15 files changed, 725 insertions(+), 378 deletions(-) create mode 100644 include/linphone/api/c-dial-plan.h create mode 100644 src/c-wrapper/api/c-dial-plan.cpp create mode 100644 src/dial-plan/dial-plan-p.h create mode 100644 src/dial-plan/dial-plan.cpp create mode 100644 src/dial-plan/dial-plan.h diff --git a/coreapi/account_creator.c b/coreapi/account_creator.c index 46b947ff6..16d23a221 100644 --- a/coreapi/account_creator.c +++ b/coreapi/account_creator.c @@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/lpconfig.h" #include "c-wrapper/c-wrapper.h" +#include "linphone/api/c-dial-plan.h" #if !_WIN32 #include "regex.h" @@ -402,10 +403,10 @@ LinphoneAccountCreatorPhoneNumberStatusMask linphone_account_creator_set_phone_n if (linphone_dial_plan_is_generic(plan)) { return_status = LinphoneAccountCreatorPhoneNumberStatusInvalidCountryCode; } - if (size < plan->nnl - 1) { + if (size < linphone_dial_plan_get_national_number_length(plan) - 1) { return_status += LinphoneAccountCreatorPhoneNumberStatusTooShort; goto end; - } else if (size > plan->nnl + 1) { + } else if (size > linphone_dial_plan_get_national_number_length(plan) + 1) { return_status += LinphoneAccountCreatorPhoneNumberStatusTooLong; goto end; } else if (return_status & LinphoneAccountCreatorPhoneNumberStatusInvalidCountryCode) { diff --git a/coreapi/dial_plan.c b/coreapi/dial_plan.c index 327521377..1688fde3b 100644 --- a/coreapi/dial_plan.c +++ b/coreapi/dial_plan.c @@ -19,314 +19,3 @@ Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) */ #include "linphone/core_utils.h" - -/* - * http://en.wikipedia.org/wiki/Telephone_numbering_plan - * http://en.wikipedia.org/wiki/Telephone_numbers_in_Europe - * imported from https://en.wikipedia.org/wiki/List_of_mobile_phone_number_series_by_country - */ -static LinphoneDialPlan const dial_plans[]={ - //Country , iso country code, e164 country calling code, number length, international usual prefix - {"Afghanistan" ,"AF" , "93" , 9 , "00" }, - {"Albania" ,"AL" , "355" , 9 , "00" }, - {"Algeria" ,"DZ" , "213" , 9 , "00" }, - {"American Samoa" ,"AS" , "1" , 10 , "011" }, - {"Andorra" ,"AD" , "376" , 6 , "00" }, - {"Angola" ,"AO" , "244" , 9 , "00" }, - {"Anguilla" ,"AI" , "1" , 10 , "011" }, - {"Antigua and Barbuda" ,"AG" , "1" , 10 , "011" }, - {"Argentina" ,"AR" , "54" , 10 , "00" }, - {"Armenia" ,"AM" , "374" , 8 , "00" }, - {"Aruba" ,"AW" , "297" , 7 , "011" }, - {"Australia" ,"AU" , "61" , 9 , "0011"}, - {"Austria" ,"AT" , "43" , 10 , "00" }, - {"Azerbaijan" ,"AZ" , "994" , 9 , "00" }, - {"Bahamas" ,"BS" , "1" , 10 , "011" }, - {"Bahrain" ,"BH" , "973" , 8 , "00" }, - {"Bangladesh" ,"BD" , "880" , 10 , "00" }, - {"Barbados" ,"BB" , "1" , 10 , "011" }, - {"Belarus" ,"BY" , "375" , 9 , "00" }, - {"Belgium" ,"BE" , "32" , 9 , "00" }, - {"Belize" ,"BZ" , "501" , 7 , "00" }, - {"Benin" ,"BJ" , "229" , 8 , "00" }, - {"Bermuda" ,"BM" , "1" , 10 , "011" }, - {"Bhutan" ,"BT" , "975" , 8 , "00" }, - {"Bolivia" ,"BO" , "591" , 8 , "00" }, - {"Bosnia and Herzegovina" ,"BA" , "387" , 8 , "00" }, - {"Botswana" ,"BW" , "267" , 8 , "00" }, - {"Brazil" ,"BR" , "55" , 10 , "00" }, - {"Brunei Darussalam" ,"BN" , "673" , 7 , "00" }, - {"Bulgaria" ,"BG" , "359" , 9 , "00" }, - {"Burkina Faso" ,"BF" , "226" , 8 , "00" }, - {"Burundi" ,"BI" , "257" , 8 , "011" }, - {"Cambodia" ,"KH" , "855" , 9 , "00" }, - {"Cameroon" ,"CM" , "237" , 9 , "00" }, - {"Canada" ,"CA" , "1" , 10 , "011" }, - {"Cape Verde" ,"CV" , "238" , 7 , "00" }, - {"Cayman Islands" ,"KY" , "1" , 10 , "011" }, - {"Central African Republic" ,"CF" , "236" , 8 , "00" }, - {"Chad" ,"TD" , "235" , 8 , "00" }, - {"Chile" ,"CL" , "56" , 9 , "00" }, - {"China" ,"CN" , "86" , 11 , "00" }, - {"Colombia" ,"CO" , "57" , 10 , "00" }, - {"Comoros" ,"KM" , "269" , 7 , "00" }, - {"Congo" ,"CG" , "242" , 9 , "00" }, - {"Congo Democratic Republic" ,"CD" , "243" , 9 , "00" }, - {"Cook Islands" ,"CK" , "682" , 5 , "00" }, - {"Costa Rica" ,"CR" , "506" , 8 , "00" }, - {"Cote d'Ivoire" ,"AD" , "225" , 8 , "00" }, - {"Croatia" ,"HR" , "385" , 9 , "00" }, - {"Cuba" ,"CU" , "53" , 8 , "119" }, - {"Cyprus" ,"CY" , "357" , 8 , "00" }, - {"Czech Republic" ,"CZ" , "420" , 9 , "00" }, - {"Denmark" ,"DK" , "45" , 8 , "00" }, - {"Djibouti" ,"DJ" , "253" , 8 , "00" }, - {"Dominica" ,"DM" , "1" , 10 , "011" }, - {"Dominican Republic" ,"DO" , "1" , 10 , "011" }, - {"Ecuador" ,"EC" , "593" , 9 , "00" }, - {"Egypt" ,"EG" , "20" , 10 , "00" }, - {"El Salvador" ,"SV" , "503" , 8 , "00" }, - {"Equatorial Guinea" ,"GQ" , "240" , 9 , "00" }, - {"Eritrea" ,"ER" , "291" , 7 , "00" }, - {"Estonia" ,"EE" , "372" , 8 , "00" }, - {"Ethiopia" ,"ET" , "251" , 9 , "00" }, - {"Falkland Islands" ,"FK" , "500" , 5 , "00" }, - {"Faroe Islands" ,"FO" , "298" , 6 , "00" }, - {"Fiji" ,"FJ" , "679" , 7 , "00" }, - {"Finland" ,"FI" , "358" , 9 , "00" }, - {"France" ,"FR" , "33" , 9 , "00" }, - {"French Guiana" ,"GF" , "594" , 9 , "00" }, - {"French Polynesia" ,"PF" , "689" , 6 , "00" }, - {"Gabon" ,"GA" , "241" , 8 , "00" }, - {"Gambia" ,"GM" , "220" , 7 , "00" }, - {"Georgia" ,"GE" , "995" , 9 , "00" }, - {"Germany" ,"DE" , "49" , 11 , "00" }, - {"Ghana" ,"GH" , "233" , 9 , "00" }, - {"Gibraltar" ,"GI" , "350" , 8 , "00" }, - {"Greece" ,"GR" , "30" ,10 , "00" }, - {"Greenland" ,"GL" , "299" , 6 , "00" }, - {"Grenada" ,"GD" , "1" , 10 , "011" }, - {"Guadeloupe" ,"GP" , "590" , 9 , "00" }, - {"Guam" ,"GU" , "1" , 10 , "011" }, - {"Guatemala" ,"GT" , "502" , 8 , "00" }, - {"Guinea" ,"GN" , "224" , 8 , "00" }, - {"Guinea-Bissau" ,"GW" , "245" , 7 , "00" }, - {"Guyana" ,"GY" , "592" , 7 , "001" }, - {"Haiti" ,"HT" , "509" , 8 , "00" }, - {"Honduras" ,"HN" , "504" , 8 , "00" }, - {"Hong Kong" ,"HK" , "852" , 8 , "001" }, - {"Hungary" ,"HU" , "36" , 9 , "00" }, - {"Iceland" ,"IS" , "354" , 9 , "00" }, - {"India" ,"IN" , "91" , 10 , "00" }, - {"Indonesia" ,"ID" , "62" , 10 , "001" }, - {"Iran" ,"IR" , "98" , 10 , "00" }, - {"Iraq" ,"IQ" , "964" , 10 , "00" }, - {"Ireland" ,"IE" , "353" , 9 , "00" }, - {"Israel" ,"IL" , "972" , 9 , "00" }, - {"Italy" ,"IT" , "39" , 10 , "00" }, -/* {"Jersey" ,"JE" , "44" , 10 , "00" },*/ - {"Jamaica" ,"JM" , "1" , 10 , "011" }, - {"Japan" ,"JP" , "81" , 10 , "010" }, - {"Jordan" ,"JO" , "962" , 9 , "00" }, - {"Kazakhstan" ,"KZ" , "7" , 10 , "00" }, - {"Kenya" ,"KE" , "254" , 9 , "000" }, - {"Kiribati" ,"KI" , "686" , 5 , "00" }, - {"Korea, North" ,"KP" , "850" , 12 , "99" }, - {"Korea, South" ,"KR" , "82" , 12 , "001" }, - {"Kuwait" ,"KW" , "965" , 8 , "00" }, - {"Kyrgyzstan" ,"KG" , "996" , 9 , "00" }, - {"Laos" ,"LA" , "856" , 10 , "00" }, - {"Latvia" ,"LV" , "371" , 8 , "00" }, - {"Lebanon" ,"LB" , "961" , 7 , "00" }, - {"Lesotho" ,"LS" , "266" , 8 , "00" }, - {"Liberia" ,"LR" , "231" , 8 , "00" }, - {"Libya" ,"LY" , "218" , 8 , "00" }, - {"Liechtenstein" ,"LI" , "423" , 7 , "00" }, - {"Lithuania" ,"LT" , "370" , 8 , "00" }, - {"Luxembourg" ,"LU" , "352" , 9 , "00" }, - {"Macau" ,"MO" , "853" , 8 , "00" }, - {"Macedonia" ,"MK" , "389" , 8 , "00" }, - {"Madagascar" ,"MG" , "261" , 9 , "00" }, - {"Malawi" ,"MW" , "265" , 9 , "00" }, - {"Malaysia" ,"MY" , "60" , 9 , "00" }, - {"Maldives" ,"MV" , "960" , 7 , "00" }, - {"Mali" ,"ML" , "223" , 8 , "00" }, - {"Malta" ,"MT" , "356" , 8 , "00" }, - {"Marshall Islands" ,"MH" , "692" , 7 , "011" }, - {"Martinique" ,"MQ" , "596" , 9 , "00" }, - {"Mauritania" ,"MR" , "222" , 8 , "00" }, - {"Mauritius" ,"MU" , "230" , 7 , "00" }, - {"Mayotte Island" ,"YT" , "262" , 9 , "00" }, - {"Mexico" ,"MX" , "52" , 10 , "00" }, - /*The following is a pseudo dial plan for Mexican mobile phones. See https://en.wikipedia.org/wiki/Telephone_numbers_in_Mexico*/ - {"Mexico" ,"MX" , "521" , 10 , "00" }, - {"Micronesia" ,"FM" , "691" , 7 , "011" }, - {"Moldova" ,"MD" , "373" , 8 , "00" }, - {"Monaco" ,"MC" , "377" , 8 , "00" }, - {"Mongolia" ,"MN" , "976" , 8 , "001" }, - {"Montenegro" ,"ME" , "382" , 8 , "00" }, - {"Montserrat" ,"MS" , "664" , 10 , "011" }, - {"Morocco" ,"MA" , "212" , 9 , "00" }, - {"Mozambique" ,"MZ" , "258" , 9 , "00" }, - {"Myanmar" ,"MM" , "95" , 10 , "00" }, - {"Namibia" ,"NA" , "264" , 9 , "00" }, - {"Nauru" ,"NR" , "674" , 7 , "00" }, - {"Nepal" ,"NP" , "43" , 10 , "00" }, - {"Netherlands" ,"NL" , "31" , 9 , "00" }, - {"New Caledonia" ,"NC" , "687" , 6 , "00" }, - {"New Zealand" ,"NZ" , "64" , 8 , "00" }, - {"Nicaragua" ,"NI" , "505" , 8 , "00" }, - {"Niger" ,"NE" , "227" , 8 , "00" }, - {"Nigeria" ,"NG" , "234" , 10 , "009" }, - {"Niue" ,"NU" , "683" , 4 , "00" }, - {"Norfolk Island" ,"NF" , "672" , 5 , "00" }, - {"Northern Mariana Islands" ,"MP" , "1" , 10 , "011" }, - {"Norway" ,"NO" , "47" , 8 , "00" }, - {"Oman" ,"OM" , "968" , 8 , "00" }, - {"Pakistan" ,"PK" , "92" , 10 , "00" }, - {"Palau" ,"PW" , "680" , 7 , "011" }, - {"Palestine" ,"PS" , "970" , 9 , "00" }, - {"Panama" ,"PA" , "507" , 8 , "00" }, - {"Papua New Guinea" ,"PG" , "675" , 8 , "00" }, - {"Paraguay" ,"PY" , "595" , 9 , "00" }, - {"Peru" ,"PE" , "51" , 9 , "00" }, - {"Philippines" ,"PH" , "63" , 10 , "00" }, - {"Poland" ,"PL" , "48" , 9 , "00" }, - {"Portugal" ,"PT" , "351" , 9 , "00" }, - {"Puerto Rico" ,"PR" , "1" , 10 , "011" }, - {"Qatar" ,"QA" , "974" , 8 , "00" }, - {"R�union Island" ,"RE" , "262" , 9 , "011" }, - {"Romania" ,"RO" , "40" , 9 , "00" }, - {"Russian Federation" ,"RU" , "7" , 10 , "8" }, - {"Rwanda" ,"RW" , "250" , 9 , "00" }, - {"Saint Helena" ,"SH" , "290" , 4 , "00" }, - {"Saint Kitts and Nevis" ,"KN" , "1" , 10 , "011" }, - {"Saint Lucia" ,"LC" , "1" , 10 , "011" }, - {"Saint Pierre and Miquelon" ,"PM" , "508" , 6 , "00" }, - {"Saint Vincent and the Grenadines","VC" , "1" , 10 , "011" }, - {"Samoa" ,"WS" , "685" , 7 , "0" }, - {"San Marino" ,"SM" , "378" , 10 , "00" }, - {"Sao Tome and Principe" ,"ST" , "239" , 7 , "00" }, - {"Saudi Arabia" ,"SA" , "966" , 9 , "00" }, - {"Senegal" ,"SN" , "221" , 9 , "00" }, - {"Serbia" ,"RS" , "381" , 9 , "00" }, - {"Seychelles" ,"SC" , "248" , 7 , "00" }, - {"Sierra Leone" ,"SL" , "232" , 8 , "00" }, - {"Singapore" ,"SG" , "65" , 8 , "001" }, - {"Slovakia" ,"SK" , "421" , 9 , "00" }, - {"Slovenia" ,"SI" , "386" , 8 , "00" }, - {"Solomon Islands" ,"SB" , "677" , 7 , "00" }, - {"Somalia" ,"SO" , "252" , 8 , "00" }, - {"South Africa" ,"ZA" , "27" , 9 , "00" }, - {"Spain" ,"ES" , "34" , 9 , "00" }, - {"Sri Lanka" ,"LK" , "94" , 9 , "00" }, - {"Sudan" ,"SD" , "249" , 9 , "00" }, - {"Suriname" ,"SR" , "597" , 7 , "00" }, - {"Swaziland" ,"SZ" , "268" , 8 , "00" }, - {"Sweden" ,"SE" , "46" , 9 , "00" }, - {"Switzerland" ,"XK" , "41" , 9 , "00" }, - {"Syria" ,"SY" , "963" , 9 , "00" }, - {"Taiwan" ,"TW" , "886" , 9 , "810" }, - {"Tajikistan" ,"TJ" , "992" , 9 , "002" }, - {"Tanzania" ,"TZ" , "255" , 9 , "000" }, - {"Thailand" ,"TH" , "66" , 9 , "001" }, - {"Togo" ,"TG" , "228" , 8 , "00" }, - {"Tokelau" ,"TK" , "690" , 4 , "00" }, - {"Tonga" ,"TO" , "676" , 5 , "00" }, - {"Trinidad and Tobago" ,"TT" , "1" , 10 , "011" }, - {"Tunisia" ,"TN" , "216" , 8 , "00" }, - {"Turkey" ,"TR" , "90" , 10 , "00" }, - {"Turkmenistan" ,"TM" , "993" , 8 , "00" }, - {"Turks and Caicos Islands" ,"TC" , "1" , 7 , "0" }, - {"Tuvalu" ,"TV" , "688" , 5 , "00" }, - {"Uganda" ,"UG" , "256" , 9 , "000" }, - {"Ukraine" ,"UA" , "380" , 9 , "00" }, - {"United Arab Emirates" ,"AE" , "971" , 9 , "00" }, - {"United Kingdom" ,"GB" , "44" , 10 , "00" }, -/* {"United Kingdom" ,"UK" , "44" , 10 , "00" },*/ - {"United States" ,"US" , "1" , 10 , "011" }, - {"Uruguay" ,"UY" , "598" , 8 , "00" }, - {"Uzbekistan" ,"UZ" , "998" , 9 , "8" }, - {"Vanuatu" ,"VU" , "678" , 7 , "00" }, - {"Venezuela" ,"VE" , "58" , 10 , "00" }, - {"Vietnam" ,"VN" , "84" , 9 , "00" }, - {"Wallis and Futuna" ,"WF" , "681" , 5 , "00" }, - {"Yemen" ,"YE" , "967" , 9 , "00" }, - {"Zambia" ,"ZM" , "260" , 9 , "00" }, - {"Zimbabwe" ,"ZW" , "263" , 9 , "00" }, - {NULL ,NULL , "" , 0 , NULL } -}; -static LinphoneDialPlan most_common_dialplan={ "generic" ,"", "", 10, "00"}; - -int linphone_dial_plan_lookup_ccc_from_e164(const char* e164) { - LinphoneDialPlan* dial_plan; - LinphoneDialPlan* elected_dial_plan=NULL; - unsigned int found; - unsigned int i=0; - - if (e164[0]!='+') { - return -1;/*not an e164 number*/ - } - if (e164[1]=='1') { - /*USA case*/ - return 1; - } - do { - found=0; - i++; - for (dial_plan=(LinphoneDialPlan*)dial_plans; dial_plan->country!=NULL; dial_plan++) { - if (strncmp(dial_plan->ccc,&e164[1],i) == 0) { - elected_dial_plan=dial_plan; - found++; - } - } - } while ((found>1 || found==0) && i < sizeof(dial_plan->ccc)); - if (found==1) { - return atoi(elected_dial_plan->ccc); - } else { - return -1; /*not found */ - } - -} -int linphone_dial_plan_lookup_ccc_from_iso(const char* iso) { - LinphoneDialPlan* dial_plan; - for (dial_plan=(LinphoneDialPlan*)dial_plans; dial_plan->country!=NULL; dial_plan++) { - if (strcmp(iso, dial_plan->iso_country_code)==0) { - return atoi(dial_plan->ccc); - } - } - return -1; -} - -const LinphoneDialPlan* linphone_dial_plan_by_ccc_as_int(int ccc) { - int i; - char ccc_as_char[16] = {0}; - snprintf(ccc_as_char,sizeof(ccc_as_char)-1,"%i",ccc); - - for(i=0;dial_plans[i].country!=NULL;++i){ - if (strcmp(ccc_as_char,dial_plans[i].ccc)==0){ - return &dial_plans[i]; - } - } - /*else return a generic "most common" dial plan*/ - return &most_common_dialplan; -} - - -const LinphoneDialPlan* linphone_dial_plan_by_ccc(const char *ccc) { - if (!ccc) { - return &most_common_dialplan; - } - - return linphone_dial_plan_by_ccc_as_int((int)strtol(ccc,NULL,10)); -} - -const LinphoneDialPlan* linphone_dial_plan_get_all() { - return dial_plans; -} - -bool_t linphone_dial_plan_is_generic(const LinphoneDialPlan *ccc) { - if (strcmp(ccc->country, most_common_dialplan.country) == 0) - return TRUE; - return FALSE; -} diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 856a850d9..db2af889e 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -32,6 +32,7 @@ Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) // For migration purpose. #include "address/address-p.h" #include "c-wrapper/c-wrapper.h" +#include "linphone/api/c-dial-plan.h" using namespace LinphonePrivate; @@ -646,7 +647,7 @@ bool_t linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const char* linphone_proxy_config_normalize_phone_number(LinphoneProxyConfig *proxy, const char *username) { LinphoneProxyConfig *tmpproxy = proxy ? proxy : linphone_proxy_config_new(); char* result = NULL; - LinphoneDialPlan dialplan = {0}; + const LinphoneDialPlan *dialplan; char * nationnal_significant_number = NULL; int ccc = -1; @@ -656,24 +657,24 @@ char* linphone_proxy_config_normalize_phone_number(LinphoneProxyConfig *proxy, c ccc = linphone_dial_plan_lookup_ccc_from_e164(flatten); if (ccc>-1) { /*e164 like phone number*/ - dialplan = *linphone_dial_plan_by_ccc_as_int(ccc); - nationnal_significant_number = strstr(flatten, dialplan.ccc); + dialplan = linphone_dial_plan_by_ccc_as_int(ccc); + nationnal_significant_number = strstr(flatten, linphone_dial_plan_get_country_calling_code(dialplan)); if (nationnal_significant_number) { - nationnal_significant_number +=strlen(dialplan.ccc); + nationnal_significant_number +=strlen(linphone_dial_plan_get_country_calling_code(dialplan)); } } else if (flatten[0] =='+') { ms_message ("Unknown ccc for e164 like number [%s]", flatten); goto end; } else { - dialplan = *linphone_dial_plan_by_ccc(tmpproxy->dial_prefix); //copy dial plan; + dialplan = linphone_dial_plan_by_ccc(tmpproxy->dial_prefix); //copy dial plan; if (tmpproxy->dial_prefix){ - if (strcmp(tmpproxy->dial_prefix,dialplan.ccc) != 0){ + /*if (strcmp(tmpproxy->dial_prefix,linphone_dial_plan_get_country_calling_code(dialplan)) != 0){ //probably generic dialplan, preserving proxy dial prefix - strncpy(dialplan.ccc,tmpproxy->dial_prefix,sizeof(dialplan.ccc)); - } + strncpy(linphone_dial_plan_get_country_calling_code(dialplan),tmpproxy->dial_prefix,sizeof(linphone_dial_plan_get_country_calling_code(dialplan))); + }*/ /*it does not make sens to try replace icp with + if we are not sure from the country we are (I.E tmpproxy->dial_prefix==NULL)*/ - if (strstr(flatten,dialplan.icp)==flatten) { - char *e164 = replace_icp_with_plus(flatten,dialplan.icp); + if (strstr(flatten,linphone_dial_plan_get_international_call_prefix(dialplan))==flatten) { + char *e164 = replace_icp_with_plus(flatten,linphone_dial_plan_get_iso_country_code(dialplan)); result = linphone_proxy_config_normalize_phone_number(tmpproxy,e164); ms_free(e164); goto end; @@ -682,23 +683,23 @@ char* linphone_proxy_config_normalize_phone_number(LinphoneProxyConfig *proxy, c } nationnal_significant_number=flatten; } - ms_debug("Using dial plan '%s'",dialplan.country); + ms_debug("Using dial plan '%s'",linphone_dial_plan_get_country(dialplan)); /*if proxy has a dial prefix, modify phonenumber accordingly*/ - if (dialplan.ccc[0]!='\0') { + if (linphone_dial_plan_get_country_calling_code(dialplan)[0]!='\0') { /* the number already starts with + or international prefix*/ /*0. keep at most national number significant digits */ char* nationnal_significant_number_start = nationnal_significant_number + MAX(0, (int)strlen(nationnal_significant_number) - - (int)dialplan.nnl); - ms_debug("Prefix not present. Keeping at most %d digits: %s", dialplan.nnl, nationnal_significant_number_start); + - (int)linphone_dial_plan_get_national_number_length(dialplan)); + ms_debug("Prefix not present. Keeping at most %d digits: %s", linphone_dial_plan_get_national_number_length(dialplan), nationnal_significant_number_start); /*1. First prepend international calling prefix or +*/ /*2. Second add prefix*/ /*3. Finally add user digits */ result = ms_strdup_printf("%s%s%s" - , tmpproxy->dial_escape_plus ? dialplan.icp : "+" - , dialplan.ccc + , tmpproxy->dial_escape_plus ? linphone_dial_plan_get_international_call_prefix(dialplan) : "+" + , linphone_dial_plan_get_country_calling_code(dialplan) , nationnal_significant_number_start); ms_debug("Prepended prefix resulted in %s", result); } diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index b0cd5236b..31f1c52d6 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -84,6 +84,7 @@ set(C_API_HEADER_FILES c-chat-message-cbs.h c-chat-room.h c-chat-room-cbs.h + c-dial-plan.h c-event-log.h c-participant.h c-types.h diff --git a/include/linphone/api/c-dial-plan.h b/include/linphone/api/c-dial-plan.h new file mode 100644 index 000000000..00339ae1b --- /dev/null +++ b/include/linphone/api/c-dial-plan.h @@ -0,0 +1,91 @@ +/* + * c-dial-plan.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _C_DIAL_PLAN_H_ +#define _C_DIAL_PLAN_H_ + +#include "linphone/api/c-types.h" + +// ============================================================================= + +#ifdef __cplusplus + extern "C" { +#endif // ifdef __cplusplus + +/** + * @addtogroup misc + * @{ + */ + + LINPHONE_PUBLIC const char * linphone_dial_plan_get_country(const LinphoneDialPlan *dp); + LINPHONE_PUBLIC const char * linphone_dial_plan_get_iso_country_code(const LinphoneDialPlan *dp); + LINPHONE_PUBLIC const char * linphone_dial_plan_get_country_calling_code(const LinphoneDialPlan *dp); + LINPHONE_PUBLIC int linphone_dial_plan_get_national_number_length(const LinphoneDialPlan *dp); + LINPHONE_PUBLIC const char * linphone_dial_plan_get_international_call_prefix(const LinphoneDialPlan *dp); + + /** + *Function to get call country code from ISO 3166-1 alpha-2 code, ex: FR returns 33 + *@param iso country code alpha2 + *@return call country code or -1 if not found + */ +LINPHONE_PUBLIC int linphone_dial_plan_lookup_ccc_from_iso(const char* iso); + +/** + *Function to get call country code from an e164 number, ex: +33952650121 will return 33 + *@param e164 phone number + *@return call country code or -1 if not found + */ +LINPHONE_PUBLIC int linphone_dial_plan_lookup_ccc_from_e164(const char* e164); + +/** + * Return NULL-terminated array of all known dial plans + * @deprecated use linphone_dial_plan_get_all_list instead +**/ +LINPHONE_PUBLIC const LinphoneDialPlan* linphone_dial_plan_get_all(void); + +/** + * @return {\bctbx_list const LinphoneDialPlan*} of all known dial plans +**/ +LINPHONE_PUBLIC const bctbx_list_t * linphone_dial_plan_get_all_list(); + +/** + * Find best match for given CCC + * @return Return matching dial plan, or a generic one if none found +**/ +LINPHONE_PUBLIC const LinphoneDialPlan* linphone_dial_plan_by_ccc(const char *ccc); +/** + * Find best match for given CCC + * @return Return matching dial plan, or a generic one if none found + **/ +LINPHONE_PUBLIC const LinphoneDialPlan* linphone_dial_plan_by_ccc_as_int(int ccc); + +/** + * Return if given plan is generic +**/ +LINPHONE_PUBLIC bool_t linphone_dial_plan_is_generic(const LinphoneDialPlan *ccc); + +/** + * @} + */ + +#ifdef __cplusplus + } +#endif // ifdef __cplusplus + +#endif // ifndef _C_DIAL_PLAN_H_ diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index 16d86f3fb..980e40eec 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -117,6 +117,12 @@ typedef struct _LinphoneChatMessageCbs LinphoneChatMessageCbs; **/ typedef struct _LinphoneParticipant LinphoneParticipant; +/** +* Represents a dial plan +* @ingroup misc +**/ +typedef struct _LinphoneDialPlan LinphoneDialPlan; + // ----------------------------------------------------------------------------- // EventLog. // ----------------------------------------------------------------------------- diff --git a/include/linphone/core_utils.h b/include/linphone/core_utils.h index 5f7a97bab..52cd791bd 100644 --- a/include/linphone/core_utils.h +++ b/include/linphone/core_utils.h @@ -87,51 +87,6 @@ void linphone_core_add_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook ho void linphone_core_remove_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data); -typedef struct _LinphoneDialPlan { - const char *country; - const char* iso_country_code; /* ISO 3166-1 alpha-2 code, ex: FR for France*/ - char ccc[8]; /*country calling code*/ - int nnl; /*maximum national number length*/ - const char * icp; /*international call prefix, ex: 00 in europe*/ -} LinphoneDialPlan; - -/** - * @ingroup misc - *Function to get call country code from ISO 3166-1 alpha-2 code, ex: FR returns 33 - *@param iso country code alpha2 - *@return call country code or -1 if not found - */ -LINPHONE_PUBLIC int linphone_dial_plan_lookup_ccc_from_iso(const char* iso); - -/** - * @ingroup misc - *Function to get call country code from an e164 number, ex: +33952650121 will return 33 - *@param e164 phone number - *@return call country code or -1 if not found - */ -LINPHONE_PUBLIC int linphone_dial_plan_lookup_ccc_from_e164(const char* e164); - -/** - * Return NULL-terminated array of all known dial plans -**/ -LINPHONE_PUBLIC const LinphoneDialPlan* linphone_dial_plan_get_all(void); - -/** - * Find best match for given CCC - * @return Return matching dial plan, or a generic one if none found -**/ -LINPHONE_PUBLIC const LinphoneDialPlan* linphone_dial_plan_by_ccc(const char *ccc); -/** - * Find best match for given CCC - * @return Return matching dial plan, or a generic one if none found - **/ -LINPHONE_PUBLIC const LinphoneDialPlan* linphone_dial_plan_by_ccc_as_int(int ccc); - -/** - * Return if given plan is generic -**/ -LINPHONE_PUBLIC bool_t linphone_dial_plan_is_generic(const LinphoneDialPlan *ccc); - #ifdef __cplusplus } #endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1d8c0c1c1..b134e0b81 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -86,6 +86,8 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES db/session/db-session-p.h db/session/db-session-provider.h db/session/db-session.h + dial-plan/dial-plan-p.h + dial-plan/dial-plan.h enums.h event-log/call-event.h event-log/chat-message-event.h @@ -124,6 +126,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES c-wrapper/api/c-chat-message.cpp c-wrapper/api/c-chat-room-cbs.cpp c-wrapper/api/c-chat-room.cpp + c-wrapper/api/c-dial-plan.cpp c-wrapper/api/c-event-log.cpp c-wrapper/api/c-participant.cpp c-wrapper/internal/c-sal.cpp @@ -162,6 +165,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES db/main-db.cpp db/session/db-session-provider.cpp db/session/db-session.cpp + dial-plan/dial-plan.cpp event-log/call-event.cpp event-log/chat-message-event.cpp event-log/conference-event.cpp diff --git a/src/c-wrapper/api/c-dial-plan.cpp b/src/c-wrapper/api/c-dial-plan.cpp new file mode 100644 index 000000000..2ec2f2f58 --- /dev/null +++ b/src/c-wrapper/api/c-dial-plan.cpp @@ -0,0 +1,90 @@ +/* + * c-dial-plan.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "linphone/api/c-dial-plan.h" + +#include "linphone/wrapper_utils.h" +#include "c-wrapper/c-wrapper.h" +#include "dial-plan/dial-plan.h" + +// ============================================================================= + +using namespace std; + +L_DECLARE_C_OBJECT_IMPL(DialPlan); + +const char * linphone_dial_plan_get_country(const LinphoneDialPlan *dp) { + //return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(dp).getCountry()); + return NULL; +} + +const char * linphone_dial_plan_get_iso_country_code(const LinphoneDialPlan *dp) { + //return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(dp).getIsoCountryCode()); + return NULL; +} + +const char * linphone_dial_plan_get_country_calling_code(const LinphoneDialPlan *dp) { + //return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(dp).getCountryCallingCode()); + return NULL; +} + +int linphone_dial_plan_get_national_number_length(const LinphoneDialPlan *dp) { + //return L_GET_CPP_PTR_FROM_C_OBJECT(dp).getNationalNumberLength(); + return -1; +} + +const char * linphone_dial_plan_get_international_call_prefix(const LinphoneDialPlan *dp) { + //return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(dp).getInternationalCallPrefix()); + return NULL; +} + +int linphone_dial_plan_lookup_ccc_from_e164(const char* e164) { + return LinphonePrivate::DialPlan::lookupCccFromE164(L_C_TO_STRING(e164)); +} + +int linphone_dial_plan_lookup_ccc_from_iso(const char* iso) { + return LinphonePrivate::DialPlan::lookupCccFromIso(L_C_TO_STRING(iso)); +} + +const LinphoneDialPlan* linphone_dial_plan_by_ccc_as_int(int ccc) { + //LinphonePrivate::DialPlan dp = LinphonePrivate::DialPlan::findByCccAsInt(ccc); + //return L_GET_C_BACK_PTR(); + return NULL; //TODO +} + +const LinphoneDialPlan* linphone_dial_plan_by_ccc(const char *ccc) { + //LinphonePrivate::DialPlan dp = LinphonePrivate::DialPlan::findByCcc(L_C_TO_STRING(ccc)); + //return L_GET_C_BACK_PTR(); + return NULL; //TODO +} + +const LinphoneDialPlan* linphone_dial_plan_get_all() { + return NULL; //TODO +} + +const bctbx_list_t * linphone_dial_plan_get_all_list() { + //const list dps = LinphonePrivate::DialPlan::getAllDialPlans(); + //return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(); + return NULL; //TODO +} + +bool_t linphone_dial_plan_is_generic(const LinphoneDialPlan *ccc) { + //return L_GET_CPP_PTR_FROM_C_OBJECT(ccc).isGeneric(); + return FALSE; +} \ No newline at end of file diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index 9a2ef349f..c7322f97e 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -72,6 +72,7 @@ BELLE_SIP_TYPE_ID(LinphoneContactSearch), BELLE_SIP_TYPE_ID(LinphoneContent), BELLE_SIP_TYPE_ID(LinphoneCore), BELLE_SIP_TYPE_ID(LinphoneCoreCbs), +BELLE_SIP_TYPE_ID(LinphoneDialPlan), BELLE_SIP_TYPE_ID(LinphoneErrorInfo), BELLE_SIP_TYPE_ID(LinphoneEvent), BELLE_SIP_TYPE_ID(LinphoneFactory), diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 5d7918755..103f61a40 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -888,7 +888,9 @@ shared_ptr MainDb::findChatRoom (const string &peerAddress) const { void MainDb::cleanHistory (const string &, FilterMask) {} - shared_ptr MainDb::findChatRoom (const string &) const {} + shared_ptr MainDb::findChatRoom (const string &) const { + return nullptr; + } bool MainDb::import (Backend, const string &) { return false; diff --git a/src/dial-plan/dial-plan-p.h b/src/dial-plan/dial-plan-p.h new file mode 100644 index 000000000..c6a48bdca --- /dev/null +++ b/src/dial-plan/dial-plan-p.h @@ -0,0 +1,44 @@ +/* + * dial-plan-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _DIAL_PLAN_P_H_ +#define _DIAL_PLAN_P_H_ + +#include "dial-plan.h" +#include "object/clonable-object-p.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class DialPlanPrivate : public ClonableObjectPrivate { + +public: + std::string country; + std::string isoCountryCode; /* ISO 3166-1 alpha-2 code, ex: FR for France*/ + std::string countryCallingCode; /*country calling code*/ + int nationalNumberLength = 0; /*maximum national number length*/ + std::string internationalCallPrefix; /*international call prefix, ex: 00 in europe*/ + + L_DECLARE_PUBLIC(DialPlan); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _DIAL_PLAN_P_H_ diff --git a/src/dial-plan/dial-plan.cpp b/src/dial-plan/dial-plan.cpp new file mode 100644 index 000000000..8b66c1bce --- /dev/null +++ b/src/dial-plan/dial-plan.cpp @@ -0,0 +1,399 @@ +/* + * dial-plan.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "linphone/utils/utils.h" + +#include "dial-plan-p.h" +#include "c-wrapper/c-wrapper.h" +#include "logger/logger.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +/* + * http://en.wikipedia.org/wiki/Telephone_numbering_plan + * http://en.wikipedia.org/wiki/Telephone_numbers_in_Europe + * imported from https://en.wikipedia.org/wiki/List_of_mobile_phone_number_series_by_country + */ +static list const DialPlans = { + //Country , iso country code, e164 country calling code, number length, international usual prefix + {"Afghanistan" ,"AF" , "93" , 9 , "00" }, + {"Albania" ,"AL" , "355" , 9 , "00" }, + {"Algeria" ,"DZ" , "213" , 9 , "00" }, + {"American Samoa" ,"AS" , "1" , 10 , "011" }, + {"Andorra" ,"AD" , "376" , 6 , "00" }, + {"Angola" ,"AO" , "244" , 9 , "00" }, + {"Anguilla" ,"AI" , "1" , 10 , "011" }, + {"Antigua and Barbuda" ,"AG" , "1" , 10 , "011" }, + {"Argentina" ,"AR" , "54" , 10 , "00" }, + {"Armenia" ,"AM" , "374" , 8 , "00" }, + {"Aruba" ,"AW" , "297" , 7 , "011" }, + {"Australia" ,"AU" , "61" , 9 , "0011"}, + {"Austria" ,"AT" , "43" , 10 , "00" }, + {"Azerbaijan" ,"AZ" , "994" , 9 , "00" }, + {"Bahamas" ,"BS" , "1" , 10 , "011" }, + {"Bahrain" ,"BH" , "973" , 8 , "00" }, + {"Bangladesh" ,"BD" , "880" , 10 , "00" }, + {"Barbados" ,"BB" , "1" , 10 , "011" }, + {"Belarus" ,"BY" , "375" , 9 , "00" }, + {"Belgium" ,"BE" , "32" , 9 , "00" }, + {"Belize" ,"BZ" , "501" , 7 , "00" }, + {"Benin" ,"BJ" , "229" , 8 , "00" }, + {"Bermuda" ,"BM" , "1" , 10 , "011" }, + {"Bhutan" ,"BT" , "975" , 8 , "00" }, + {"Bolivia" ,"BO" , "591" , 8 , "00" }, + {"Bosnia and Herzegovina" ,"BA" , "387" , 8 , "00" }, + {"Botswana" ,"BW" , "267" , 8 , "00" }, + {"Brazil" ,"BR" , "55" , 10 , "00" }, + {"Brunei Darussalam" ,"BN" , "673" , 7 , "00" }, + {"Bulgaria" ,"BG" , "359" , 9 , "00" }, + {"Burkina Faso" ,"BF" , "226" , 8 , "00" }, + {"Burundi" ,"BI" , "257" , 8 , "011" }, + {"Cambodia" ,"KH" , "855" , 9 , "00" }, + {"Cameroon" ,"CM" , "237" , 9 , "00" }, + {"Canada" ,"CA" , "1" , 10 , "011" }, + {"Cape Verde" ,"CV" , "238" , 7 , "00" }, + {"Cayman Islands" ,"KY" , "1" , 10 , "011" }, + {"Central African Republic" ,"CF" , "236" , 8 , "00" }, + {"Chad" ,"TD" , "235" , 8 , "00" }, + {"Chile" ,"CL" , "56" , 9 , "00" }, + {"China" ,"CN" , "86" , 11 , "00" }, + {"Colombia" ,"CO" , "57" , 10 , "00" }, + {"Comoros" ,"KM" , "269" , 7 , "00" }, + {"Congo" ,"CG" , "242" , 9 , "00" }, + {"Congo Democratic Republic" ,"CD" , "243" , 9 , "00" }, + {"Cook Islands" ,"CK" , "682" , 5 , "00" }, + {"Costa Rica" ,"CR" , "506" , 8 , "00" }, + {"Cote d'Ivoire" ,"AD" , "225" , 8 , "00" }, + {"Croatia" ,"HR" , "385" , 9 , "00" }, + {"Cuba" ,"CU" , "53" , 8 , "119" }, + {"Cyprus" ,"CY" , "357" , 8 , "00" }, + {"Czech Republic" ,"CZ" , "420" , 9 , "00" }, + {"Denmark" ,"DK" , "45" , 8 , "00" }, + {"Djibouti" ,"DJ" , "253" , 8 , "00" }, + {"Dominica" ,"DM" , "1" , 10 , "011" }, + {"Dominican Republic" ,"DO" , "1" , 10 , "011" }, + {"Ecuador" ,"EC" , "593" , 9 , "00" }, + {"Egypt" ,"EG" , "20" , 10 , "00" }, + {"El Salvador" ,"SV" , "503" , 8 , "00" }, + {"Equatorial Guinea" ,"GQ" , "240" , 9 , "00" }, + {"Eritrea" ,"ER" , "291" , 7 , "00" }, + {"Estonia" ,"EE" , "372" , 8 , "00" }, + {"Ethiopia" ,"ET" , "251" , 9 , "00" }, + {"Falkland Islands" ,"FK" , "500" , 5 , "00" }, + {"Faroe Islands" ,"FO" , "298" , 6 , "00" }, + {"Fiji" ,"FJ" , "679" , 7 , "00" }, + {"Finland" ,"FI" , "358" , 9 , "00" }, + {"France" ,"FR" , "33" , 9 , "00" }, + {"French Guiana" ,"GF" , "594" , 9 , "00" }, + {"French Polynesia" ,"PF" , "689" , 6 , "00" }, + {"Gabon" ,"GA" , "241" , 8 , "00" }, + {"Gambia" ,"GM" , "220" , 7 , "00" }, + {"Georgia" ,"GE" , "995" , 9 , "00" }, + {"Germany" ,"DE" , "49" , 11 , "00" }, + {"Ghana" ,"GH" , "233" , 9 , "00" }, + {"Gibraltar" ,"GI" , "350" , 8 , "00" }, + {"Greece" ,"GR" , "30" ,10 , "00" }, + {"Greenland" ,"GL" , "299" , 6 , "00" }, + {"Grenada" ,"GD" , "1" , 10 , "011" }, + {"Guadeloupe" ,"GP" , "590" , 9 , "00" }, + {"Guam" ,"GU" , "1" , 10 , "011" }, + {"Guatemala" ,"GT" , "502" , 8 , "00" }, + {"Guinea" ,"GN" , "224" , 8 , "00" }, + {"Guinea-Bissau" ,"GW" , "245" , 7 , "00" }, + {"Guyana" ,"GY" , "592" , 7 , "001" }, + {"Haiti" ,"HT" , "509" , 8 , "00" }, + {"Honduras" ,"HN" , "504" , 8 , "00" }, + {"Hong Kong" ,"HK" , "852" , 8 , "001" }, + {"Hungary" ,"HU" , "36" , 9 , "00" }, + {"Iceland" ,"IS" , "354" , 9 , "00" }, + {"India" ,"IN" , "91" , 10 , "00" }, + {"Indonesia" ,"ID" , "62" , 10 , "001" }, + {"Iran" ,"IR" , "98" , 10 , "00" }, + {"Iraq" ,"IQ" , "964" , 10 , "00" }, + {"Ireland" ,"IE" , "353" , 9 , "00" }, + {"Israel" ,"IL" , "972" , 9 , "00" }, + {"Italy" ,"IT" , "39" , 10 , "00" }, +/* {"Jersey" ,"JE" , "44" , 10 , "00" },*/ + {"Jamaica" ,"JM" , "1" , 10 , "011" }, + {"Japan" ,"JP" , "81" , 10 , "010" }, + {"Jordan" ,"JO" , "962" , 9 , "00" }, + {"Kazakhstan" ,"KZ" , "7" , 10 , "00" }, + {"Kenya" ,"KE" , "254" , 9 , "000" }, + {"Kiribati" ,"KI" , "686" , 5 , "00" }, + {"Korea, North" ,"KP" , "850" , 12 , "99" }, + {"Korea, South" ,"KR" , "82" , 12 , "001" }, + {"Kuwait" ,"KW" , "965" , 8 , "00" }, + {"Kyrgyzstan" ,"KG" , "996" , 9 , "00" }, + {"Laos" ,"LA" , "856" , 10 , "00" }, + {"Latvia" ,"LV" , "371" , 8 , "00" }, + {"Lebanon" ,"LB" , "961" , 7 , "00" }, + {"Lesotho" ,"LS" , "266" , 8 , "00" }, + {"Liberia" ,"LR" , "231" , 8 , "00" }, + {"Libya" ,"LY" , "218" , 8 , "00" }, + {"Liechtenstein" ,"LI" , "423" , 7 , "00" }, + {"Lithuania" ,"LT" , "370" , 8 , "00" }, + {"Luxembourg" ,"LU" , "352" , 9 , "00" }, + {"Macau" ,"MO" , "853" , 8 , "00" }, + {"Macedonia" ,"MK" , "389" , 8 , "00" }, + {"Madagascar" ,"MG" , "261" , 9 , "00" }, + {"Malawi" ,"MW" , "265" , 9 , "00" }, + {"Malaysia" ,"MY" , "60" , 9 , "00" }, + {"Maldives" ,"MV" , "960" , 7 , "00" }, + {"Mali" ,"ML" , "223" , 8 , "00" }, + {"Malta" ,"MT" , "356" , 8 , "00" }, + {"Marshall Islands" ,"MH" , "692" , 7 , "011" }, + {"Martinique" ,"MQ" , "596" , 9 , "00" }, + {"Mauritania" ,"MR" , "222" , 8 , "00" }, + {"Mauritius" ,"MU" , "230" , 7 , "00" }, + {"Mayotte Island" ,"YT" , "262" , 9 , "00" }, + {"Mexico" ,"MX" , "52" , 10 , "00" }, + /*The following is a pseudo dial plan for Mexican mobile phones. See https://en.wikipedia.org/wiki/Telephone_numbers_in_Mexico*/ + {"Mexico" ,"MX" , "521" , 10 , "00" }, + {"Micronesia" ,"FM" , "691" , 7 , "011" }, + {"Moldova" ,"MD" , "373" , 8 , "00" }, + {"Monaco" ,"MC" , "377" , 8 , "00" }, + {"Mongolia" ,"MN" , "976" , 8 , "001" }, + {"Montenegro" ,"ME" , "382" , 8 , "00" }, + {"Montserrat" ,"MS" , "664" , 10 , "011" }, + {"Morocco" ,"MA" , "212" , 9 , "00" }, + {"Mozambique" ,"MZ" , "258" , 9 , "00" }, + {"Myanmar" ,"MM" , "95" , 10 , "00" }, + {"Namibia" ,"NA" , "264" , 9 , "00" }, + {"Nauru" ,"NR" , "674" , 7 , "00" }, + {"Nepal" ,"NP" , "43" , 10 , "00" }, + {"Netherlands" ,"NL" , "31" , 9 , "00" }, + {"New Caledonia" ,"NC" , "687" , 6 , "00" }, + {"New Zealand" ,"NZ" , "64" , 8 , "00" }, + {"Nicaragua" ,"NI" , "505" , 8 , "00" }, + {"Niger" ,"NE" , "227" , 8 , "00" }, + {"Nigeria" ,"NG" , "234" , 10 , "009" }, + {"Niue" ,"NU" , "683" , 4 , "00" }, + {"Norfolk Island" ,"NF" , "672" , 5 , "00" }, + {"Northern Mariana Islands" ,"MP" , "1" , 10 , "011" }, + {"Norway" ,"NO" , "47" , 8 , "00" }, + {"Oman" ,"OM" , "968" , 8 , "00" }, + {"Pakistan" ,"PK" , "92" , 10 , "00" }, + {"Palau" ,"PW" , "680" , 7 , "011" }, + {"Palestine" ,"PS" , "970" , 9 , "00" }, + {"Panama" ,"PA" , "507" , 8 , "00" }, + {"Papua New Guinea" ,"PG" , "675" , 8 , "00" }, + {"Paraguay" ,"PY" , "595" , 9 , "00" }, + {"Peru" ,"PE" , "51" , 9 , "00" }, + {"Philippines" ,"PH" , "63" , 10 , "00" }, + {"Poland" ,"PL" , "48" , 9 , "00" }, + {"Portugal" ,"PT" , "351" , 9 , "00" }, + {"Puerto Rico" ,"PR" , "1" , 10 , "011" }, + {"Qatar" ,"QA" , "974" , 8 , "00" }, + {"R�union Island" ,"RE" , "262" , 9 , "011" }, + {"Romania" ,"RO" , "40" , 9 , "00" }, + {"Russian Federation" ,"RU" , "7" , 10 , "8" }, + {"Rwanda" ,"RW" , "250" , 9 , "00" }, + {"Saint Helena" ,"SH" , "290" , 4 , "00" }, + {"Saint Kitts and Nevis" ,"KN" , "1" , 10 , "011" }, + {"Saint Lucia" ,"LC" , "1" , 10 , "011" }, + {"Saint Pierre and Miquelon" ,"PM" , "508" , 6 , "00" }, + {"Saint Vincent and the Grenadines","VC" , "1" , 10 , "011" }, + {"Samoa" ,"WS" , "685" , 7 , "0" }, + {"San Marino" ,"SM" , "378" , 10 , "00" }, + {"Sao Tome and Principe" ,"ST" , "239" , 7 , "00" }, + {"Saudi Arabia" ,"SA" , "966" , 9 , "00" }, + {"Senegal" ,"SN" , "221" , 9 , "00" }, + {"Serbia" ,"RS" , "381" , 9 , "00" }, + {"Seychelles" ,"SC" , "248" , 7 , "00" }, + {"Sierra Leone" ,"SL" , "232" , 8 , "00" }, + {"Singapore" ,"SG" , "65" , 8 , "001" }, + {"Slovakia" ,"SK" , "421" , 9 , "00" }, + {"Slovenia" ,"SI" , "386" , 8 , "00" }, + {"Solomon Islands" ,"SB" , "677" , 7 , "00" }, + {"Somalia" ,"SO" , "252" , 8 , "00" }, + {"South Africa" ,"ZA" , "27" , 9 , "00" }, + {"Spain" ,"ES" , "34" , 9 , "00" }, + {"Sri Lanka" ,"LK" , "94" , 9 , "00" }, + {"Sudan" ,"SD" , "249" , 9 , "00" }, + {"Suriname" ,"SR" , "597" , 7 , "00" }, + {"Swaziland" ,"SZ" , "268" , 8 , "00" }, + {"Sweden" ,"SE" , "46" , 9 , "00" }, + {"Switzerland" ,"XK" , "41" , 9 , "00" }, + {"Syria" ,"SY" , "963" , 9 , "00" }, + {"Taiwan" ,"TW" , "886" , 9 , "810" }, + {"Tajikistan" ,"TJ" , "992" , 9 , "002" }, + {"Tanzania" ,"TZ" , "255" , 9 , "000" }, + {"Thailand" ,"TH" , "66" , 9 , "001" }, + {"Togo" ,"TG" , "228" , 8 , "00" }, + {"Tokelau" ,"TK" , "690" , 4 , "00" }, + {"Tonga" ,"TO" , "676" , 5 , "00" }, + {"Trinidad and Tobago" ,"TT" , "1" , 10 , "011" }, + {"Tunisia" ,"TN" , "216" , 8 , "00" }, + {"Turkey" ,"TR" , "90" , 10 , "00" }, + {"Turkmenistan" ,"TM" , "993" , 8 , "00" }, + {"Turks and Caicos Islands" ,"TC" , "1" , 7 , "0" }, + {"Tuvalu" ,"TV" , "688" , 5 , "00" }, + {"Uganda" ,"UG" , "256" , 9 , "000" }, + {"Ukraine" ,"UA" , "380" , 9 , "00" }, + {"United Arab Emirates" ,"AE" , "971" , 9 , "00" }, + {"United Kingdom" ,"GB" , "44" , 10 , "00" }, +/* {"United Kingdom" ,"UK" , "44" , 10 , "00" },*/ + {"United States" ,"US" , "1" , 10 , "011" }, + {"Uruguay" ,"UY" , "598" , 8 , "00" }, + {"Uzbekistan" ,"UZ" , "998" , 9 , "8" }, + {"Vanuatu" ,"VU" , "678" , 7 , "00" }, + {"Venezuela" ,"VE" , "58" , 10 , "00" }, + {"Vietnam" ,"VN" , "84" , 9 , "00" }, + {"Wallis and Futuna" ,"WF" , "681" , 5 , "00" }, + {"Yemen" ,"YE" , "967" , 9 , "00" }, + {"Zambia" ,"ZM" , "260" , 9 , "00" }, + {"Zimbabwe" ,"ZW" , "263" , 9 , "00" }, + {NULL ,NULL , "" , 0 , NULL } +}; + +const DialPlan DialPlan::MostCommon("generic", "", "", 10, "00"); + +DialPlan::DialPlan (const string &country, const string &isoCountryCode, const string &ccc, int nnl, const string &icp) : ClonableObject(*new DialPlanPrivate) { + L_D(); + d->country = country; + d->isoCountryCode = isoCountryCode; + d->countryCallingCode = ccc; + d->nationalNumberLength = nnl; + d->internationalCallPrefix = icp; +} + +DialPlan::DialPlan (const DialPlan &src) : ClonableObject(*new DialPlanPrivate) { + L_D(); + d->country = src.getCountry(); + d->isoCountryCode = src.getIsoCountryCode(); + d->countryCallingCode = src.getCountryCallingCode(); + d->nationalNumberLength = src.getNationalNumberLength(); + d->internationalCallPrefix = src.getInternationalCallPrefix(); +} + +DialPlan::~DialPlan () { + +} + +DialPlan &DialPlan::operator= (const DialPlan &src) { + L_D(); + + if (this != &src) { + d->country = src.getCountry(); + d->isoCountryCode = src.getIsoCountryCode(); + d->countryCallingCode = src.getCountryCallingCode(); + d->nationalNumberLength = src.getNationalNumberLength(); + d->internationalCallPrefix = src.getInternationalCallPrefix(); + } + + return *this; +} + +const string& DialPlan::getCountry() const { + L_D(); + return d->country; +} + +const string& DialPlan::getIsoCountryCode() const { + L_D(); + return d->isoCountryCode; +} + +const string& DialPlan::getCountryCallingCode() const { + L_D(); + return d->countryCallingCode; +} + +int DialPlan::getNationalNumberLength() const { + L_D(); + return d->nationalNumberLength; +} + +const string& DialPlan::getInternationalCallPrefix() const { + L_D(); + return d->internationalCallPrefix; +} + +bool DialPlan::isGeneric() const { + L_D(); + return d->country == MostCommon.getCountry(); +} + +int DialPlan::lookupCccFromE164(string e164) { + if (e164[0] != '+') { + return -1; /*not an e164 number*/ + } + if (e164[1]=='1') { /*USA case*/ + return 1; + } + + DialPlan electedDialPlan; + unsigned int found; + unsigned int i = 0; + + do { + found = 0; + i++; + for (const auto &dp : DialPlans) { + if (strncmp(dp.getCountryCallingCode().c_str(), &e164[1], i) == 0) { + electedDialPlan = dp; + found++; + } + } + } while ((found > 1 || found == 0) && i < e164.length() - 1); + + if (found == 1) { + return atoi(electedDialPlan.getCountryCallingCode().c_str()); + } else { + return -1; /*not found */ + } +} + +int DialPlan::lookupCccFromIso(string iso) { + for (const auto &dp : DialPlans) { + if (dp.getIsoCountryCode() == iso) { + return atoi(dp.getCountryCallingCode().c_str()); + } + } + return -1; +} + +const DialPlan& DialPlan::findByCccAsInt(int ccc) { + string cccString = to_string(ccc); + return DialPlan::findByCcc(cccString); +} + +const DialPlan& DialPlan::findByCcc(const string& ccc) { + if (ccc.empty()) { + return MostCommon; + } + + for (const auto &dp : DialPlans) { + if (dp.getCountryCallingCode() == ccc) { + return dp; + } + } + /*else return a generic "most common" dial plan*/ + return MostCommon; +} + +const std::list& DialPlan::getAllDialPlans() { + return DialPlans; +} + +LINPHONE_END_NAMESPACE \ No newline at end of file diff --git a/src/dial-plan/dial-plan.h b/src/dial-plan/dial-plan.h new file mode 100644 index 000000000..b25a8853e --- /dev/null +++ b/src/dial-plan/dial-plan.h @@ -0,0 +1,63 @@ +/* + * dial-plan.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _DIAL_PLAN_H_ +#define _DIAL_PLAN_H_ + +#include +#include "object/clonable-object.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class DialPlanPrivate; + +class LINPHONE_PUBLIC DialPlan : public ClonableObject { +public: + DialPlan (const std::string &country = "", const std::string &isoCountryCode = "", const std::string &ccc = "", int nnl = 0, const std::string &icp = ""); + DialPlan (const DialPlan &src); + ~DialPlan (); + + DialPlan &operator= (const DialPlan &src); + + const std::string& getCountry() const; + const std::string& getIsoCountryCode() const; + const std::string& getCountryCallingCode() const; + int getNationalNumberLength() const; + const std::string& getInternationalCallPrefix() const; + bool isGeneric() const; + + static const DialPlan MostCommon; + + static int lookupCccFromE164(std::string e164); + static int lookupCccFromIso(std::string iso); + static const DialPlan& findByCccAsInt(int ccc); + static const DialPlan& findByCcc(const std::string& ccc); + static const std::list& getAllDialPlans(); + +private: + static std::list const DialPlans; + + L_DECLARE_PRIVATE(DialPlan); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _DIAL_PLAN_H_ diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index ef80e0005..7626a7745 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -231,9 +231,6 @@ eval "$SED_START 's/enableDownloadOpenH264(/OpenH264DownloadHelper.enableDownloa #DialPlan #LinphoneBuffer #Call.zoomVideo() -#Factory.instance().setLogCollectionPath(getFilesDir().getAbsolutePath()); -#Factory.instance().enableLogCollection(isDebugEnabled); -#Factory.instance().setDebugMode(isDebugEnabled, getString(R.string.app_name)); #AccountCreator.updatePassword #Android specifics not wrapped automatically @@ -264,3 +261,6 @@ eval "$SED_START 's/enableDownloadOpenH264(/OpenH264DownloadHelper.enableDownloa #Core.setCpuCount() => Not needed anymore, can be removed #AccountCreator.getPrefix => linphone_dial_plan_lookup_ccc_from_e164 #ProxyConfig.lookupCCCFromIso=> linphone_dial_plan_lookup_ccc_from_iso +#Factory.instance().setLogCollectionPath(getFilesDir().getAbsolutePath()); => Core.setLogCollectionPath +#Factory.instance().enableLogCollection(isDebugEnabled); => COre.enableLogCollection +#Factory.instance().setDebugMode(isDebugEnabled, getString(R.string.app_name)); => Core.setLogLevelMask From dc0da30d7547833c13d3e6eab8e67064d0fdd59a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 16 Oct 2017 10:13:07 +0200 Subject: [PATCH 0490/2215] More work on the DialPlan object --- include/linphone/api/c-dial-plan.h | 24 +++++++++++++++++++++ src/c-wrapper/api/c-dial-plan.cpp | 34 +++++++++++------------------- src/c-wrapper/c-wrapper.h | 2 +- src/c-wrapper/internal/c-tools.h | 2 +- src/dial-plan/dial-plan.cpp | 2 +- 5 files changed, 39 insertions(+), 25 deletions(-) diff --git a/include/linphone/api/c-dial-plan.h b/include/linphone/api/c-dial-plan.h index 00339ae1b..3a11b24f1 100644 --- a/include/linphone/api/c-dial-plan.h +++ b/include/linphone/api/c-dial-plan.h @@ -33,10 +33,34 @@ * @{ */ + /** + * Returns the country name of the dialplan + * @return the country name + */ LINPHONE_PUBLIC const char * linphone_dial_plan_get_country(const LinphoneDialPlan *dp); + + /** + * Returns the iso country code of the dialplan + * @return the iso country code + */ LINPHONE_PUBLIC const char * linphone_dial_plan_get_iso_country_code(const LinphoneDialPlan *dp); + + /** + * Returns the country calling code of the dialplan + * @return the country calling code + */ LINPHONE_PUBLIC const char * linphone_dial_plan_get_country_calling_code(const LinphoneDialPlan *dp); + + /** + * Returns the national number length of the dialplan + * @return the national number length + */ LINPHONE_PUBLIC int linphone_dial_plan_get_national_number_length(const LinphoneDialPlan *dp); + + /** + * Returns the international call prefix of the dialplan + * @return the international call prefix + */ LINPHONE_PUBLIC const char * linphone_dial_plan_get_international_call_prefix(const LinphoneDialPlan *dp); /** diff --git a/src/c-wrapper/api/c-dial-plan.cpp b/src/c-wrapper/api/c-dial-plan.cpp index 2ec2f2f58..faf706a6c 100644 --- a/src/c-wrapper/api/c-dial-plan.cpp +++ b/src/c-wrapper/api/c-dial-plan.cpp @@ -19,7 +19,6 @@ #include "linphone/api/c-dial-plan.h" -#include "linphone/wrapper_utils.h" #include "c-wrapper/c-wrapper.h" #include "dial-plan/dial-plan.h" @@ -30,28 +29,23 @@ using namespace std; L_DECLARE_C_OBJECT_IMPL(DialPlan); const char * linphone_dial_plan_get_country(const LinphoneDialPlan *dp) { - //return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(dp).getCountry()); - return NULL; + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(dp)->getCountry()); } const char * linphone_dial_plan_get_iso_country_code(const LinphoneDialPlan *dp) { - //return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(dp).getIsoCountryCode()); - return NULL; + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(dp)->getIsoCountryCode()); } const char * linphone_dial_plan_get_country_calling_code(const LinphoneDialPlan *dp) { - //return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(dp).getCountryCallingCode()); - return NULL; + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(dp)->getCountryCallingCode()); } int linphone_dial_plan_get_national_number_length(const LinphoneDialPlan *dp) { - //return L_GET_CPP_PTR_FROM_C_OBJECT(dp).getNationalNumberLength(); - return -1; + return L_GET_CPP_PTR_FROM_C_OBJECT(dp)->getNationalNumberLength(); } const char * linphone_dial_plan_get_international_call_prefix(const LinphoneDialPlan *dp) { - //return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(dp).getInternationalCallPrefix()); - return NULL; + return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(dp)->getInternationalCallPrefix()); } int linphone_dial_plan_lookup_ccc_from_e164(const char* e164) { @@ -63,15 +57,13 @@ int linphone_dial_plan_lookup_ccc_from_iso(const char* iso) { } const LinphoneDialPlan* linphone_dial_plan_by_ccc_as_int(int ccc) { - //LinphonePrivate::DialPlan dp = LinphonePrivate::DialPlan::findByCccAsInt(ccc); - //return L_GET_C_BACK_PTR(); - return NULL; //TODO + const LinphonePrivate::DialPlan& dp = LinphonePrivate::DialPlan::findByCccAsInt(ccc); + return L_GET_C_BACK_PTR(&dp); } const LinphoneDialPlan* linphone_dial_plan_by_ccc(const char *ccc) { - //LinphonePrivate::DialPlan dp = LinphonePrivate::DialPlan::findByCcc(L_C_TO_STRING(ccc)); - //return L_GET_C_BACK_PTR(); - return NULL; //TODO + const LinphonePrivate::DialPlan& dp = LinphonePrivate::DialPlan::findByCcc(L_C_TO_STRING(ccc)); + return L_GET_C_BACK_PTR(&dp); } const LinphoneDialPlan* linphone_dial_plan_get_all() { @@ -79,12 +71,10 @@ const LinphoneDialPlan* linphone_dial_plan_get_all() { } const bctbx_list_t * linphone_dial_plan_get_all_list() { - //const list dps = LinphonePrivate::DialPlan::getAllDialPlans(); - //return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(); - return NULL; //TODO + const list& dps = LinphonePrivate::DialPlan::getAllDialPlans(); + return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(dps); } bool_t linphone_dial_plan_is_generic(const LinphoneDialPlan *ccc) { - //return L_GET_CPP_PTR_FROM_C_OBJECT(ccc).isGeneric(); - return FALSE; + return L_GET_CPP_PTR_FROM_C_OBJECT(ccc)->isGeneric(); } \ No newline at end of file diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index c7322f97e..6b932c0c5 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -37,6 +37,7 @@ F(ChatRoom, ChatRoom) \ F(ConferenceEvent, ConferenceEvent) \ F(ConferenceParticipantEvent, ConferenceParticipantEvent) \ + F(DialPlan, DialPlan) \ F(EventLog, EventLog) \ F(MediaSessionParams, CallParams) \ F(Participant, Participant) @@ -72,7 +73,6 @@ BELLE_SIP_TYPE_ID(LinphoneContactSearch), BELLE_SIP_TYPE_ID(LinphoneContent), BELLE_SIP_TYPE_ID(LinphoneCore), BELLE_SIP_TYPE_ID(LinphoneCoreCbs), -BELLE_SIP_TYPE_ID(LinphoneDialPlan), BELLE_SIP_TYPE_ID(LinphoneErrorInfo), BELLE_SIP_TYPE_ID(LinphoneEvent), BELLE_SIP_TYPE_ID(LinphoneFactory), diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index f533caf50..e36e288f4 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -381,7 +381,7 @@ public: static inline bctbx_list_t *getResolvedCListFromCppList (const std::list &cppList) { bctbx_list_t *result = nullptr; for (const auto &value : cppList) - result = bctbx_list_append(result, belle_sip_object_ref(getCBackPtr(value))); + result = bctbx_list_append(result, belle_sip_object_ref(getCBackPtr(&value))); return result; } diff --git a/src/dial-plan/dial-plan.cpp b/src/dial-plan/dial-plan.cpp index 8b66c1bce..af6146b0e 100644 --- a/src/dial-plan/dial-plan.cpp +++ b/src/dial-plan/dial-plan.cpp @@ -34,7 +34,7 @@ LINPHONE_BEGIN_NAMESPACE * http://en.wikipedia.org/wiki/Telephone_numbers_in_Europe * imported from https://en.wikipedia.org/wiki/List_of_mobile_phone_number_series_by_country */ -static list const DialPlans = { +list const DialPlan::DialPlans = { //Country , iso country code, e164 country calling code, number length, international usual prefix {"Afghanistan" ,"AF" , "93" , 9 , "00" }, {"Albania" ,"AL" , "355" , 9 , "00" }, From 6110b30f89f61db600c9ae48c9073419286a976a Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 16 Oct 2017 10:27:23 +0200 Subject: [PATCH 0491/2215] feat(MainDb): add a private header --- src/CMakeLists.txt | 1 + src/db/main-db-p.h | 71 +++++++++++++ src/db/main-db.cpp | 259 +++++++++++++++++++-------------------------- 3 files changed, 180 insertions(+), 151 deletions(-) create mode 100644 src/db/main-db-p.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b134e0b81..8b9d33bae 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -82,6 +82,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/core.h db/abstract/abstract-db-p.h db/abstract/abstract-db.h + db/main-db-p.h db/main-db.h db/session/db-session-p.h db/session/db-session-provider.h diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h new file mode 100644 index 000000000..cec8344a1 --- /dev/null +++ b/src/db/main-db-p.h @@ -0,0 +1,71 @@ +/* + * main-db-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _MAIN_DB_P_H_ +#define _MAIN_DB_P_H_ + +#include "abstract/abstract-db-p.h" +#include "chat/chat-message/chat-message.h" +#include "event-log/event-log.h" +#include "main-db.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ChatRoom; +class Content; + +struct MessageEventReferences { + long eventId; + long localSipAddressId; + long remoteSipAddressId; + long chatRoomId; +}; + +class MainDbPrivate : public AbstractDbPrivate { +public: + +private: + long insertSipAddress (const std::string &sipAddress); + void insertContent (long messageEventId, const Content &content); + long insertContentType (const std::string &contentType); + long insertEvent (EventLog::Type type, const tm &date); + long insertChatRoom (long sipAddressId, int capabilities, const tm &date); + void insertChatRoomParticipant (long chatRoomId, long sipAddressId, bool isAdmin); + + long insertMessageEvent ( + const MessageEventReferences &references, + ChatMessage::State state, + ChatMessage::Direction direction, + const std::string &imdnMessageId, + bool isSecured, + const std::list &contents + ); + + void insertMessageParticipant (long messageEventId, long sipAddressId, ChatMessage::State state); + + std::unordered_map> chatRooms; + + L_DECLARE_PUBLIC(MainDb); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _MAIN_DB_P_H_ diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 103f61a40..3395f30b2 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -26,8 +26,6 @@ #include "linphone/utils/utils.h" -#include "abstract/abstract-db-p.h" -#include "chat/chat-message/chat-message.h" #include "chat/chat-room/chat-room.h" #include "conference/participant.h" #include "content/content-type.h" @@ -37,8 +35,7 @@ #include "event-log/chat-message-event.h" #include "event-log/event-log-p.h" #include "logger/logger.h" - -#include "main-db.h" +#include "main-db-p.h" // ============================================================================= @@ -46,45 +43,6 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -struct MessageEventReferences { -#ifdef SOCI_ENABLED - long eventId; - long localSipAddressId; - long remoteSipAddressId; - long chatRoomId; -#endif -}; - -class MainDbPrivate : public AbstractDbPrivate { -#ifdef SOCI_ENABLED -public: - long insertSipAddress (const string &sipAddress); - void insertContent (long messageEventId, const Content &content); - long insertContentType (const string &contentType); - long insertEvent (EventLog::Type type, const tm &date); - long insertChatRoom (long sipAddressId, int capabilities, const tm &date); - void insertChatRoomParticipant (long chatRoomId, long sipAddressId, bool isAdmin); - - long insertMessageEvent ( - const MessageEventReferences &references, - ChatMessage::State state, - ChatMessage::Direction direction, - const string &imdnMessageId, - bool isSecured, - const list &contents - ); - - void insertMessageParticipant (long messageEventId, long sipAddressId, ChatMessage::State state); - - void importLegacyMessages (const soci::rowset &messages); -#endif - -private: - unordered_map> chatRooms; - - L_DECLARE_PUBLIC(MainDb); -}; - // ----------------------------------------------------------------------------- MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} @@ -306,95 +264,6 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return T(); } - void MainDbPrivate::importLegacyMessages (const soci::rowset &messages) { - soci::session *session = dbSession.getBackendSession(); - - soci::transaction tr(*session); - - for (const auto &message : messages) { - const int direction = message.get(LEGACY_MESSAGE_COL_DIRECTION); - if (direction != 0 && direction != 1) { - lWarning() << "Unable to import legacy message with invalid direction."; - continue; - } - - const int state = message.get( - LEGACY_MESSAGE_COL_STATE, static_cast(ChatMessage::State::Displayed) - ); - if (state < 0 || state > static_cast(ChatMessage::State::Displayed)) { - lWarning() << "Unable to import legacy message with invalid state."; - continue; - } - - const tm date = Utils::getLongAsTm(message.get(LEGACY_MESSAGE_COL_DATE, 0)); - - bool isNull; - const string url = getValueFromLegacyMessage(message, LEGACY_MESSAGE_COL_URL, isNull); - - const int contentId = message.get(LEGACY_MESSAGE_COL_CONTENT_ID, -1); - ContentType contentType(message.get(LEGACY_MESSAGE_COL_CONTENT_TYPE, "")); - if (!contentType.isValid()) - contentType = contentId != -1 - ? ContentType::FileTransfer - : (isNull ? ContentType::PlainText : ContentType::ExternalBody); - if (contentType == ContentType::ExternalBody) { - lInfo() << "Import of external body content is skipped."; - continue; - } - - const string text = getValueFromLegacyMessage(message, LEGACY_MESSAGE_COL_TEXT, isNull); - - Content content; - content.setContentType(contentType); - if (contentType == ContentType::PlainText) { - if (isNull) { - lWarning() << "Unable to import legacy message with no text."; - continue; - } - content.setBody(text); - } else { - if (contentType != ContentType::FileTransfer) { - lWarning() << "Unable to import unsupported legacy content."; - continue; - } - - const string appData = getValueFromLegacyMessage(message, LEGACY_MESSAGE_COL_APP_DATA, isNull); - if (isNull) { - lWarning() << "Unable to import legacy file message without app data."; - continue; - } - - content.setAppData("legacy", appData); - } - - struct MessageEventReferences references; - references.eventId = insertEvent(EventLog::Type::ChatMessage, date); - references.localSipAddressId = insertSipAddress(message.get(LEGACY_MESSAGE_COL_LOCAL_ADDRESS)); - references.remoteSipAddressId = insertSipAddress(message.get(LEGACY_MESSAGE_COL_REMOTE_ADDRESS)); - references.chatRoomId = insertChatRoom( - references.remoteSipAddressId, - static_cast(ChatRoom::Capabilities::Basic), - date - ); - - insertChatRoomParticipant(references.chatRoomId, references.remoteSipAddressId, false); - - long messageEventId = insertMessageEvent ( - references, - static_cast(state), - static_cast(direction), - message.get(LEGACY_MESSAGE_COL_IMDN_MESSAGE_ID, ""), - !!message.get(LEGACY_MESSAGE_COL_IS_SECURED, 0), - { move(content) } - ); - - if (state != static_cast(ChatMessage::State::Displayed)) - insertMessageParticipant(messageEventId, references.remoteSipAddressId, static_cast(state)); - } - - tr.commit(); - } - // ----------------------------------------------------------------------------- void MainDb::init () { @@ -786,26 +655,27 @@ shared_ptr MainDb::findChatRoom (const string &peerAddress) const { } catch (const exception &) { lError() << "Cannot lock chat room: `" + peerAddress + "`"; } - } else { - L_BEGIN_LOG_EXCEPTION - - soci::session *session = d->dbSession.getBackendSession(); - - tm creationDate; - tm lastUpdateDate; - int capabilities; - string subject; - - *session << "SELECT creation_date, last_update_date, capabilities, subject " - " FROM chat_room" - " WHERE peer_sip_address_id = (" - " SELECT id from sip_address WHERE value = :peerAddress" - " )", soci::use(peerAddress), soci::into(creationDate), soci::into(lastUpdateDate), - soci::use(capabilities), soci::use(subject); - - L_END_LOG_EXCEPTION + return shared_ptr(); } + L_BEGIN_LOG_EXCEPTION + + soci::session *session = d->dbSession.getBackendSession(); + + tm creationDate; + tm lastUpdateDate; + int capabilities; + string subject; + + *session << "SELECT creation_date, last_update_date, capabilities, subject " + " FROM chat_room" + " WHERE peer_sip_address_id = (" + " SELECT id from sip_address WHERE value = :peerAddress" + " )", soci::use(peerAddress), soci::into(creationDate), soci::into(lastUpdateDate), + soci::use(capabilities), soci::use(subject); + + L_END_LOG_EXCEPTION + return shared_ptr(); } @@ -834,7 +704,94 @@ shared_ptr MainDb::findChatRoom (const string &peerAddress) const { try { soci::rowset messages = (inSession->prepare << "SELECT * FROM history"); try { - d->importLegacyMessages(messages); + soci::transaction tr(*d->dbSession.getBackendSession()); + + for (const auto &message : messages) { + const int direction = message.get(LEGACY_MESSAGE_COL_DIRECTION); + if (direction != 0 && direction != 1) { + lWarning() << "Unable to import legacy message with invalid direction."; + continue; + } + + const int state = message.get( + LEGACY_MESSAGE_COL_STATE, static_cast(ChatMessage::State::Displayed) + ); + if (state < 0 || state > static_cast(ChatMessage::State::Displayed)) { + lWarning() << "Unable to import legacy message with invalid state."; + continue; + } + + const tm date = Utils::getLongAsTm(message.get(LEGACY_MESSAGE_COL_DATE, 0)); + + bool isNull; + const string url = getValueFromLegacyMessage(message, LEGACY_MESSAGE_COL_URL, isNull); + + const int contentId = message.get(LEGACY_MESSAGE_COL_CONTENT_ID, -1); + ContentType contentType(message.get(LEGACY_MESSAGE_COL_CONTENT_TYPE, "")); + if (!contentType.isValid()) + contentType = contentId != -1 + ? ContentType::FileTransfer + : (isNull ? ContentType::PlainText : ContentType::ExternalBody); + if (contentType == ContentType::ExternalBody) { + lInfo() << "Import of external body content is skipped."; + continue; + } + + const string text = getValueFromLegacyMessage(message, LEGACY_MESSAGE_COL_TEXT, isNull); + + Content content; + content.setContentType(contentType); + if (contentType == ContentType::PlainText) { + if (isNull) { + lWarning() << "Unable to import legacy message with no text."; + continue; + } + content.setBody(text); + } else { + if (contentType != ContentType::FileTransfer) { + lWarning() << "Unable to import unsupported legacy content."; + continue; + } + + const string appData = getValueFromLegacyMessage(message, LEGACY_MESSAGE_COL_APP_DATA, isNull); + if (isNull) { + lWarning() << "Unable to import legacy file message without app data."; + continue; + } + + content.setAppData("legacy", appData); + } + + struct MessageEventReferences references; + references.eventId = d->insertEvent(EventLog::Type::ChatMessage, date); + references.localSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_LOCAL_ADDRESS)); + references.remoteSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_REMOTE_ADDRESS)); + references.chatRoomId = d->insertChatRoom( + references.remoteSipAddressId, + static_cast(ChatRoom::Capabilities::Basic), + date + ); + + d->insertChatRoomParticipant(references.chatRoomId, references.remoteSipAddressId, false); + + long messageEventId = d->insertMessageEvent ( + references, + static_cast(state), + static_cast(direction), + message.get(LEGACY_MESSAGE_COL_IMDN_MESSAGE_ID, ""), + !!message.get(LEGACY_MESSAGE_COL_IS_SECURED, 0), + { move(content) } + ); + + if (state != static_cast(ChatMessage::State::Displayed)) + d->insertMessageParticipant( + messageEventId, + references.remoteSipAddressId, + static_cast(state) + ); + } + + tr.commit(); } catch (const exception &e) { lInfo() << "Failed to import legacy messages from: `" << uri << "`. (" << e.what() << ")"; return false; From 8924272d7214eb371d8a6303f5d45f79c0e6f45b Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 16 Oct 2017 10:30:15 +0200 Subject: [PATCH 0492/2215] feat(MainDb): add a `last_notify` column --- src/db/main-db.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 3395f30b2..4e2ef9570 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -306,6 +306,8 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} // Chatroom subject. " subject VARCHAR(255)," + " last_notify INT UNSIGNED," + " FOREIGN KEY (peer_sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" From 0bab59418d125a11ab05eef6250d1703a4444bc3 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 16 Oct 2017 10:40:11 +0200 Subject: [PATCH 0493/2215] Handle is-composing notification coming from several participants. --- include/linphone/api/c-callbacks.h | 5 +- src/chat/chat-room/chat-room-p.h | 9 +- src/chat/chat-room/chat-room.cpp | 38 +++++-- .../chat-room/real-time-text-chat-room.cpp | 2 +- src/chat/notification/is-composing-listener.h | 4 +- src/chat/notification/is-composing.cpp | 105 +++++++++++------- src/chat/notification/is-composing.h | 21 ++-- 7 files changed, 115 insertions(+), 69 deletions(-) diff --git a/include/linphone/api/c-callbacks.h b/include/linphone/api/c-callbacks.h index 359cfa9db..60ba99bc7 100644 --- a/include/linphone/api/c-callbacks.h +++ b/include/linphone/api/c-callbacks.h @@ -144,9 +144,10 @@ typedef void (*LinphoneChatMessageCbsFileTransferProgressIndicationCb)(LinphoneC /** * Is composing notification callback prototype. * @param[in] cr #LinphoneChatRoom involved in the conversation - * @param[in] participant The #LinphoneParticipant that has sent the is-composing notification + * @param[in] remoteAddr The address that has sent the is-composing notification + * @param[in] isComposing A boolean value telling whether the remote is composing or not */ -typedef void (*LinphoneChatRoomCbsIsComposingReceivedCb) (LinphoneChatRoom *cr, const LinphoneParticipant *participant); +typedef void (*LinphoneChatRoomCbsIsComposingReceivedCb) (LinphoneChatRoom *cr, const LinphoneAddress *remoteAddr, bool_t isComposing); /** * Callback used to notify a chat room that a message has been received. diff --git a/src/chat/chat-room/chat-room-p.h b/src/chat/chat-room/chat-room-p.h index 0074c3767..c434b0bcc 100644 --- a/src/chat/chat-room/chat-room-p.h +++ b/src/chat/chat-room/chat-room-p.h @@ -20,6 +20,8 @@ #ifndef _CHAT_ROOM_P_H_ #define _CHAT_ROOM_P_H_ +#include + #include "chat/notification/is-composing.h" #include "chat-room.h" #include "object/object-p.h" @@ -74,17 +76,18 @@ public: protected: void chatMessageReceived (const std::shared_ptr &msg); void imdnReceived (const std::string &text); - void isComposingReceived (const std::string &text); + void isComposingReceived (const Address &remoteAddr, const std::string &text); private: void notifyChatMessageReceived (const std::shared_ptr &msg); + void notifyIsComposingReceived (const Address &remoteAddr, bool isComposing); void notifyStateChanged (); void notifyUndecryptableMessageReceived (const std::shared_ptr &msg); private: /* IsComposingListener */ void onIsComposingStateChanged (bool isComposing) override; - void onIsRemoteComposingStateChanged (bool isComposing) override; + void onIsRemoteComposingStateChanged (const Address &remoteAddr, bool isComposing) override; void onIsComposingRefreshNeeded () override; public: @@ -94,7 +97,7 @@ public: Address peerAddress; int unreadCount = -1; bool isComposing = false; - bool remoteIsComposing = false; + std::unordered_set remoteIsComposing; std::list> messages; std::list> transientMessages; std::list> weakMessages; diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 96eb6b1c8..238e2fcb2 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -400,7 +400,7 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa } if (msg->getPrivate()->getContentType() == ContentType::ImIsComposing) { - isComposingReceived(msg->getPrivate()->getText()); + isComposingReceived(msg->getFromAddress(), msg->getPrivate()->getText()); increaseMsgCount = FALSE; if (lp_config_get_int(core->config, "sip", "deliver_imdn", 0) != 1) { goto end; @@ -435,11 +435,11 @@ end: // ----------------------------------------------------------------------------- void ChatRoomPrivate::chatMessageReceived (const shared_ptr &msg) { - L_Q(); if ((msg->getPrivate()->getContentType() != ContentType::Imdn) && (msg->getPrivate()->getContentType() != ContentType::ImIsComposing)) { notifyChatMessageReceived(msg); - remoteIsComposing = false; - linphone_core_notify_is_composing_received(core, L_GET_C_BACK_PTR(q)); + remoteIsComposing.erase(msg->getFromAddress().asStringUriOnly()); + isComposingHandler.stopRemoteRefreshTimer(msg->getFromAddress().asStringUriOnly()); + notifyIsComposingReceived(msg->getFromAddress(), false); msg->sendDeliveryNotification(LinphoneReasonNone); } } @@ -449,8 +449,8 @@ void ChatRoomPrivate::imdnReceived (const string &text) { Imdn::parse(*q, text); } -void ChatRoomPrivate::isComposingReceived (const string &text) { - isComposingHandler.parse(text); +void ChatRoomPrivate::isComposingReceived (const Address &remoteAddr, const string &text) { + isComposingHandler.parse(remoteAddr, text); } // ----------------------------------------------------------------------------- @@ -469,6 +469,20 @@ void ChatRoomPrivate::notifyChatMessageReceived (const shared_ptr & linphone_core_notify_message_received(core, cr, L_GET_C_BACK_PTR(msg)); } +void ChatRoomPrivate::notifyIsComposingReceived (const Address &remoteAddr, bool isComposing) { + L_Q(); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); + LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); + LinphoneChatRoomCbsIsComposingReceivedCb cb = linphone_chat_room_cbs_get_is_composing_received(cbs); + if (cb) { + LinphoneAddress *lAddr = linphone_address_new(remoteAddr.asString().c_str()); + cb(cr, lAddr, !!isComposing); + linphone_address_unref(lAddr); + } + // Legacy notification + linphone_core_notify_is_composing_received(core, cr); +} + void ChatRoomPrivate::notifyStateChanged () { L_Q(); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); @@ -495,10 +509,12 @@ void ChatRoomPrivate::onIsComposingStateChanged (bool isComposing) { sendIsComposingNotification(); } -void ChatRoomPrivate::onIsRemoteComposingStateChanged (bool isComposing) { - L_Q(); - remoteIsComposing = isComposing; - linphone_core_notify_is_composing_received(core, L_GET_C_BACK_PTR(q)); +void ChatRoomPrivate::onIsRemoteComposingStateChanged (const Address &remoteAddr, bool isComposing) { + if (isComposing) + remoteIsComposing.insert(remoteAddr.asStringUriOnly()); + else + remoteIsComposing.erase(remoteAddr.asStringUriOnly()); + notifyIsComposingReceived(remoteAddr, isComposing); } void ChatRoomPrivate::onIsComposingRefreshNeeded () { @@ -670,7 +686,7 @@ int ChatRoom::getUnreadMessagesCount () { bool ChatRoom::isRemoteComposing () const { L_D(); - return d->remoteIsComposing; + return d->remoteIsComposing.size() > 0; } void ChatRoom::markAsRead () { diff --git a/src/chat/chat-room/real-time-text-chat-room.cpp b/src/chat/chat-room/real-time-text-chat-room.cpp index 705fc0172..1c47fd0c1 100644 --- a/src/chat/chat-room/real-time-text-chat-room.cpp +++ b/src/chat/chat-room/real-time-text-chat-room.cpp @@ -59,7 +59,7 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp cmc->has_been_read = FALSE; receivedRttCharacters.push_back(cmc); - remoteIsComposing = true; + remoteIsComposing.insert(peerAddress.asStringUriOnly()); linphone_core_notify_is_composing_received(core, L_GET_C_BACK_PTR(q)); if ((character == new_line) || (character == crlf) || (character == lf)) { diff --git a/src/chat/notification/is-composing-listener.h b/src/chat/notification/is-composing-listener.h index cf6314ecb..0097bc29f 100644 --- a/src/chat/notification/is-composing-listener.h +++ b/src/chat/notification/is-composing-listener.h @@ -26,12 +26,14 @@ LINPHONE_BEGIN_NAMESPACE +class Address; + class IsComposingListener { public: virtual ~IsComposingListener() = default; virtual void onIsComposingStateChanged (bool isComposing) = 0; - virtual void onIsRemoteComposingStateChanged (bool isComposing) = 0; + virtual void onIsRemoteComposingStateChanged (const Address &remoteAddr, bool isComposing) = 0; virtual void onIsComposingRefreshNeeded () = 0; }; diff --git a/src/chat/notification/is-composing.cpp b/src/chat/notification/is-composing.cpp index a488fdb77..dd2a935a7 100644 --- a/src/chat/notification/is-composing.cpp +++ b/src/chat/notification/is-composing.cpp @@ -17,6 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include + #include "linphone/utils/utils.h" #include "chat/chat-room/chat-room-p.h" @@ -30,6 +32,16 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +struct IsRemoteComposingData { + IsRemoteComposingData (IsComposing *isComposingHandler, string uri) + : isComposingHandler(isComposingHandler), uri(uri) {} + + IsComposing *isComposingHandler; + string uri; +}; + +// ----------------------------------------------------------------------------- + const string IsComposing::isComposingPrefix = "/xsi:isComposing"; // ----------------------------------------------------------------------------- @@ -94,12 +106,12 @@ string IsComposing::marshal (bool isComposing) { return content; } -void IsComposing::parse (const string &text) { +void IsComposing::parse (const Address &remoteAddr, const string &text) { xmlparsing_context_t *xmlCtx = linphone_xmlparsing_context_new(); xmlSetGenericErrorFunc(xmlCtx, linphone_xmlparsing_genericxml_error); xmlCtx->doc = xmlReadDoc((const unsigned char *)text.c_str(), 0, nullptr, 0); if (xmlCtx->doc) - parse(xmlCtx); + parse(xmlCtx, remoteAddr); else lWarning() << "Wrongly formatted presence XML: " << xmlCtx->errorBuffer; linphone_xmlparsing_context_destroy(xmlCtx); @@ -125,29 +137,10 @@ void IsComposing::startRefreshTimer () { } } -void IsComposing::startRemoteRefreshTimer (const char *refreshStr) { - unsigned int duration = getRemoteRefreshTimerDuration(); - if (refreshStr) - duration = static_cast(Utils::stoi(refreshStr)); - if (!remoteRefreshTimer) { - remoteRefreshTimer = core->sal->create_timer(remoteRefreshTimerExpired, this, - duration * 1000, "composing remote refresh timeout"); - } else { - belle_sip_source_set_timeout(remoteRefreshTimer, duration * 1000); - } -} - -#if 0 -void IsComposing::idleTimerExpired () { - stopRefreshTimer(); - stopIdleTimer(); -} -#endif - void IsComposing::stopTimers () { stopIdleTimer(); stopRefreshTimer(); - stopRemoteRefreshTimer(); + stopAllRemoteRefreshTimers(); } // ----------------------------------------------------------------------------- @@ -170,13 +163,10 @@ void IsComposing::stopRefreshTimer () { } } -void IsComposing::stopRemoteRefreshTimer () { - if (remoteRefreshTimer) { - if (core && core->sal) - core->sal->cancel_timer(remoteRefreshTimer); - belle_sip_object_unref(remoteRefreshTimer); - remoteRefreshTimer = nullptr; - } +void IsComposing::stopRemoteRefreshTimer (const string &uri) { + auto it = remoteRefreshTimers.find(uri); + if (it != remoteRefreshTimers.end()) + stopRemoteRefreshTimer(it); } // ----------------------------------------------------------------------------- @@ -196,7 +186,7 @@ unsigned int IsComposing::getRemoteRefreshTimerDuration () { return remoteRefreshTimerDuration < 0 ? 0 : static_cast(remoteRefreshTimerDuration); } -void IsComposing::parse (xmlparsing_context_t *xmlCtx) { +void IsComposing::parse (xmlparsing_context_t *xmlCtx, const Address &remoteAddr) { char xpathStr[MAX_XPATH_LENGTH]; char *stateStr = nullptr; char *refreshStr = nullptr; @@ -225,47 +215,78 @@ void IsComposing::parse (xmlparsing_context_t *xmlCtx) { if (stateStr) { if (strcmp(stateStr, "active") == 0) { state = true; - startRemoteRefreshTimer(refreshStr); + startRemoteRefreshTimer(remoteAddr.asStringUriOnly(), refreshStr); } else { - stopRemoteRefreshTimer(); + stopRemoteRefreshTimer(remoteAddr.asStringUriOnly()); } - listener->onIsRemoteComposingStateChanged(state); + listener->onIsRemoteComposingStateChanged(remoteAddr, state); linphone_free_xml_text_content(stateStr); } if (refreshStr) linphone_free_xml_text_content(refreshStr); } -int IsComposing::idleTimerExpired (unsigned int revents) { +int IsComposing::idleTimerExpired () { + stopRefreshTimer(); + stopIdleTimer(); listener->onIsComposingStateChanged(false); return BELLE_SIP_STOP; } -int IsComposing::refreshTimerExpired (unsigned int revents) { +int IsComposing::refreshTimerExpired () { listener->onIsComposingRefreshNeeded(); return BELLE_SIP_CONTINUE; } -int IsComposing::remoteRefreshTimerExpired (unsigned int revents) { - stopRemoteRefreshTimer(); - listener->onIsRemoteComposingStateChanged(false); +int IsComposing::remoteRefreshTimerExpired (const string &uri) { + stopRemoteRefreshTimer(uri); + listener->onIsRemoteComposingStateChanged(Address(uri), false); return BELLE_SIP_STOP; } +void IsComposing::startRemoteRefreshTimer (const string &uri, const char *refreshStr) { + unsigned int duration = getRemoteRefreshTimerDuration(); + if (refreshStr) + duration = static_cast(Utils::stoi(refreshStr)); + auto it = remoteRefreshTimers.find(uri); + if (it == remoteRefreshTimers.end()) { + IsRemoteComposingData *data = new IsRemoteComposingData(this, uri); + belle_sip_source_t *timer = core->sal->create_timer(remoteRefreshTimerExpired, data, + duration * 1000, "composing remote refresh timeout"); + pair p(uri, timer); + remoteRefreshTimers.insert(p); + } else + belle_sip_source_set_timeout(it->second, duration * 1000); +} + +void IsComposing::stopAllRemoteRefreshTimers () { + for (auto it = remoteRefreshTimers.begin(); it != remoteRefreshTimers.end();) + it = stopRemoteRefreshTimer(it); +} + +unordered_map::iterator IsComposing::stopRemoteRefreshTimer (const unordered_map::const_iterator it) { + if (core && core->sal) + core->sal->cancel_timer(it->second); + belle_sip_object_unref(it->second); + return remoteRefreshTimers.erase(it); +} + int IsComposing::idleTimerExpired (void *data, unsigned int revents) { IsComposing *d = reinterpret_cast(data); - return d->idleTimerExpired(revents); + return d->idleTimerExpired(); } int IsComposing::refreshTimerExpired (void *data, unsigned int revents) { IsComposing *d = reinterpret_cast(data); - return d->refreshTimerExpired(revents); + return d->refreshTimerExpired(); } int IsComposing::remoteRefreshTimerExpired (void *data, unsigned int revents) { - IsComposing *d = reinterpret_cast(data); - return d->remoteRefreshTimerExpired(revents); + IsRemoteComposingData *d = reinterpret_cast(data); + int result = d->isComposingHandler->remoteRefreshTimerExpired(d->uri); + delete d; + return result; } LINPHONE_END_NAMESPACE diff --git a/src/chat/notification/is-composing.h b/src/chat/notification/is-composing.h index fda928ae1..729b015bf 100644 --- a/src/chat/notification/is-composing.h +++ b/src/chat/notification/is-composing.h @@ -20,6 +20,8 @@ #ifndef _IS_COMPOSING_H_ #define _IS_COMPOSING_H_ +#include + #include "linphone/utils/general.h" #include "chat/notification/is-composing-listener.h" @@ -36,24 +38,25 @@ public: ~IsComposing (); std::string marshal (bool isComposing); - void parse (const std::string &content); + void parse (const Address &remoteAddr, const std::string &content); void startIdleTimer (); void startRefreshTimer (); - void startRemoteRefreshTimer (const char *refreshStr); - void stopComposing (); void stopIdleTimer (); void stopRefreshTimer (); - void stopRemoteRefreshTimer (); + void stopRemoteRefreshTimer (const std::string &uri); void stopTimers (); private: unsigned int getIdleTimerDuration (); unsigned int getRefreshTimerDuration (); unsigned int getRemoteRefreshTimerDuration (); - void parse (xmlparsing_context_t *xmlCtx); - int idleTimerExpired (unsigned int revents); - int refreshTimerExpired (unsigned int revents); - int remoteRefreshTimerExpired (unsigned int revents); + void parse (xmlparsing_context_t *xmlCtx, const Address &remoteAddr); + int idleTimerExpired (); + int refreshTimerExpired (); + int remoteRefreshTimerExpired (const std::string &uri); + void startRemoteRefreshTimer (const std::string &uri, const char *refreshStr); + void stopAllRemoteRefreshTimers (); + std::unordered_map::iterator stopRemoteRefreshTimer (const std::unordered_map::const_iterator it); static int idleTimerExpired (void *data, unsigned int revents); static int refreshTimerExpired (void *data, unsigned int revents); @@ -67,7 +70,7 @@ private: LinphoneCore *core = nullptr; IsComposingListener *listener = nullptr; - belle_sip_source_t *remoteRefreshTimer = nullptr; + std::unordered_mapremoteRefreshTimers; belle_sip_source_t *idleTimer = nullptr; belle_sip_source_t *refreshTimer = nullptr; }; From 243c9212ba5d985f3c5218e8340b1a071a30edbb Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 16 Oct 2017 10:54:58 +0200 Subject: [PATCH 0494/2215] Fix build issues linked to DialPlan. --- include/linphone/api/c-api.h | 1 + include/linphone/api/c-dial-plan.h | 2 +- tester/presence_server_tester.c | 10 +++++----- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/include/linphone/api/c-api.h b/include/linphone/api/c-api.h index 1224497e6..a5926cb71 100644 --- a/include/linphone/api/c-api.h +++ b/include/linphone/api/c-api.h @@ -31,6 +31,7 @@ #include "linphone/api/c-chat-message-cbs.h" #include "linphone/api/c-chat-room.h" #include "linphone/api/c-chat-room-cbs.h" +#include "linphone/api/c-dial-plan.h" #include "linphone/api/c-event-log.h" #include "linphone/api/c-participant.h" #include "linphone/api/c-types.h" diff --git a/include/linphone/api/c-dial-plan.h b/include/linphone/api/c-dial-plan.h index 3a11b24f1..8bb8631b1 100644 --- a/include/linphone/api/c-dial-plan.h +++ b/include/linphone/api/c-dial-plan.h @@ -86,7 +86,7 @@ LINPHONE_PUBLIC const LinphoneDialPlan* linphone_dial_plan_get_all(void); /** * @return {\bctbx_list const LinphoneDialPlan*} of all known dial plans **/ -LINPHONE_PUBLIC const bctbx_list_t * linphone_dial_plan_get_all_list(); +LINPHONE_PUBLIC const bctbx_list_t * linphone_dial_plan_get_all_list(void); /** * Find best match for given CCC diff --git a/tester/presence_server_tester.c b/tester/presence_server_tester.c index 7e8cac7f6..50e0955c7 100644 --- a/tester/presence_server_tester.c +++ b/tester/presence_server_tester.c @@ -971,12 +971,12 @@ static void long_term_presence_with_phone_without_sip(void) { while ((dialPlan = linphone_dial_plan_by_ccc_as_int(bctbx_random()%900)) == linphone_dial_plan_by_ccc(NULL)); /*now with have a dialplan*/ - for (i = 0; i < MIN((size_t)dialPlan->nnl,sizeof(phone)-1); i++) { + for (i = 0; i < MIN((size_t)linphone_dial_plan_get_national_number_length(dialPlan),sizeof(phone)-1); i++) { phone[i] = '0' + rand() % 10; } phone[i]='\0'; - e164=ms_strdup_printf("+%s%s",dialPlan->ccc,phone); + e164=ms_strdup_printf("+%s%s",linphone_dial_plan_get_country_calling_code(dialPlan),phone); ms_message("Phone number is %s, e164 is %s", phone, e164); @@ -1001,7 +1001,7 @@ static void long_term_presence_with_phone_without_sip(void) { /*know adding ccc to proxy config*/ proxy_config = linphone_core_get_default_proxy_config(pauline->lc); linphone_proxy_config_edit(proxy_config); - linphone_proxy_config_set_dial_prefix(proxy_config, dialPlan->ccc); + linphone_proxy_config_set_dial_prefix(proxy_config, linphone_dial_plan_get_country_calling_code(dialPlan)); linphone_proxy_config_done(proxy_config); /*re-create sub list*/ linphone_friend_list_enable_subscriptions(linphone_core_get_default_friend_list(pauline->lc), FALSE); @@ -1032,12 +1032,12 @@ static char * generate_random_e164_phone_from_dial_plan(const LinphoneDialPlan * char phone[64]; size_t i; /*now with have a dialplan*/ - for (i = 0; i < MIN((size_t)dialPlan->nnl,sizeof(phone)-1); i++) { + for (i = 0; i < MIN((size_t)linphone_dial_plan_get_national_number_length(dialPlan),sizeof(phone)-1); i++) { phone[i] = '0' + rand() % 10; } phone[i]='\0'; - return ms_strdup_printf("+%s%s",dialPlan->ccc,phone); + return ms_strdup_printf("+%s%s",linphone_dial_plan_get_country_calling_code(dialPlan),phone); } /* use case: I have a friend, I invite him to use Linphone for the first time. From ce3c1ca1ff6aadd985ec4fc7da8dd394aa89a5bd Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 16 Oct 2017 10:57:54 +0200 Subject: [PATCH 0495/2215] Some fixes regarding dialplan --- coreapi/dial_plan.c | 2 +- src/c-wrapper/api/c-dial-plan.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/dial_plan.c b/coreapi/dial_plan.c index 1688fde3b..2f77faead 100644 --- a/coreapi/dial_plan.c +++ b/coreapi/dial_plan.c @@ -18,4 +18,4 @@ Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "linphone/core_utils.h" +#include "linphone/core_utils.h" \ No newline at end of file diff --git a/src/c-wrapper/api/c-dial-plan.cpp b/src/c-wrapper/api/c-dial-plan.cpp index faf706a6c..8c4745b0f 100644 --- a/src/c-wrapper/api/c-dial-plan.cpp +++ b/src/c-wrapper/api/c-dial-plan.cpp @@ -18,6 +18,7 @@ */ #include "linphone/api/c-dial-plan.h" +#include "linphone/wrapper_utils.h" #include "c-wrapper/c-wrapper.h" #include "dial-plan/dial-plan.h" From 9c440ebf509a39dc9e6cdb30a10c57182b9ea925 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 16 Oct 2017 10:58:19 +0200 Subject: [PATCH 0496/2215] feat(EventsDbTester): add some tests --- tester/events-db-tester.cpp | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/tester/events-db-tester.cpp b/tester/events-db-tester.cpp index 6c79d449c..159244c28 100644 --- a/tester/events-db-tester.cpp +++ b/tester/events-db-tester.cpp @@ -36,12 +36,39 @@ static const string getDatabasePath () { // ----------------------------------------------------------------------------- static void open_database () { - EventsDb eventsDb; - BC_ASSERT_TRUE(eventsDb.connect(EventsDb::Sqlite3, getDatabasePath())); + MainDb eventsDb; + BC_ASSERT_TRUE(eventsDb.connect(MainDb::Sqlite3, getDatabasePath())); +} + +static void get_events_count () { + MainDb eventsDb; + BC_ASSERT_TRUE(eventsDb.connect(MainDb::Sqlite3, getDatabasePath())); + BC_ASSERT_EQUAL(eventsDb.getEventsCount(), 4976, int, "%d"); + BC_ASSERT_EQUAL(eventsDb.getEventsCount(MainDb::CallFilter), 0, int, "%d"); + BC_ASSERT_EQUAL(eventsDb.getEventsCount(MainDb::ConferenceFilter), 0, int, "%d"); + BC_ASSERT_EQUAL(eventsDb.getEventsCount(MainDb::MessageFilter), 4976, int, "%d"); + BC_ASSERT_EQUAL(eventsDb.getEventsCount(MainDb::NoFilter), 4976, int, "%d"); +} + +static void get_messages_count () { + MainDb eventsDb; + BC_ASSERT_TRUE(eventsDb.connect(MainDb::Sqlite3, getDatabasePath())); + BC_ASSERT_EQUAL(eventsDb.getMessagesCount(), 4976, int, "%d"); + BC_ASSERT_EQUAL(eventsDb.getMessagesCount("sip:test-7@sip.linphone.org"), 3, int, "%d"); +} + +static void get_unread_messages_count () { + MainDb eventsDb; + BC_ASSERT_TRUE(eventsDb.connect(MainDb::Sqlite3, getDatabasePath())); + BC_ASSERT_EQUAL(eventsDb.getUnreadMessagesCount(), 2, int, "%d"); + BC_ASSERT_EQUAL(eventsDb.getUnreadMessagesCount("sip:test-7@sip.linphone.org"), 0, int, "%d"); } test_t events_db_tests[] = { - TEST_NO_TAG("Open database", open_database) + TEST_NO_TAG("Open database", open_database), + TEST_NO_TAG("Get events count", get_events_count), + TEST_NO_TAG("Get messages count", get_messages_count), + TEST_NO_TAG("Get unread messages count", get_unread_messages_count) }; test_suite_t events_db_test_suite = { From 93d57e992639d193e86447806902935b18b66f8b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 16 Oct 2017 11:21:47 +0200 Subject: [PATCH 0497/2215] Added methods in core required for Android --- coreapi/ec-calibrator.c | 19 +++++++++++++++++++ coreapi/linphonecore.c | 9 +++++++++ include/linphone/core_utils.h | 26 ++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/coreapi/ec-calibrator.c b/coreapi/ec-calibrator.c index 4a8ee1282..0c1ce7212 100644 --- a/coreapi/ec-calibrator.c +++ b/coreapi/ec-calibrator.c @@ -324,3 +324,22 @@ int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibration ec_calibrator_start(lc->ecc); return 0; } + +bool_t linphone_core_has_builtin_echo_canceller(LinphoneCore *lc) { + MSFactory * factory = linphone_core_get_ms_factory(lc); + MSDevicesInfo *devices = ms_factory_get_devices_info(factory); + SoundDeviceDescription *sound_description = ms_devices_info_get_sound_device_description(devices); + if (sound_description == NULL) return FALSE; + if (sound_description->flags & DEVICE_HAS_BUILTIN_AEC) return TRUE; + return FALSE; +} + +bool_t linphone_core_is_echo_canceller_calibration_required(LinphoneCore *lc) { + MSFactory * factory = linphone_core_get_ms_factory(lc); + MSDevicesInfo *devices = ms_factory_get_devices_info(factory); + SoundDeviceDescription *sound_description = ms_devices_info_get_sound_device_description(devices); + if (sound_description == NULL) return TRUE; + if (sound_description->flags & DEVICE_HAS_BUILTIN_AEC) return FALSE; + if (sound_description->delay != 0) return FALSE; + return TRUE; +} diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index dbe706d4c..ea0417a84 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -7371,3 +7371,12 @@ void linphone_core_check_for_update(LinphoneCore *lc, const char *current_versio } #endif } + +bool_t linphone_core_has_crappy_opengl(LinphoneCore *lc) { + MSFactory * factory = linphone_core_get_ms_factory(lc); + MSDevicesInfo *devices = ms_factory_get_devices_info(factory); + SoundDeviceDescription *sound_description = ms_devices_info_get_sound_device_description(devices); + if (sound_description == NULL) return FALSE; + if (sound_description->flags & DEVICE_HAS_CRAPPY_OPENGL) return TRUE; + return FALSE; +} \ No newline at end of file diff --git a/include/linphone/core_utils.h b/include/linphone/core_utils.h index 52cd791bd..d72f41ded 100644 --- a/include/linphone/core_utils.h +++ b/include/linphone/core_utils.h @@ -59,16 +59,42 @@ typedef void (*LinphoneEcCalibrationAudioUninit)(void *data); **/ LINPHONE_PUBLIC int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibrationCallback cb, LinphoneEcCalibrationAudioInit audio_init_cb, LinphoneEcCalibrationAudioUninit audio_uninit_cb, void *cb_data); + /** * Start the simulation of call to test the latency with an external device * @param lc The core. * @param rate Sound sample rate. + * @ingroup misc **/ LINPHONE_PUBLIC LinphoneStatus linphone_core_start_echo_tester(LinphoneCore *lc, unsigned int rate); + /** * Stop the simulation of call + * @ingroup misc **/ LINPHONE_PUBLIC LinphoneStatus linphone_core_stop_echo_tester(LinphoneCore *lc); + +/** + * Check whether the device is flagged has crappy opengl + * @returns TRUE if crappy opengl flag is set, FALSE otherwise + * @ingroup misc +**/ +LINPHONE_PUBLIC bool_t linphone_core_has_crappy_opengl(LinphoneCore *lc); + +/** + * Check whether the device has a hardware echo canceller + * @returns TRUE if it does, FALSE otherwise + * @ingroup misc +**/ +LINPHONE_PUBLIC bool_t linphone_core_has_builtin_echo_canceller(LinphoneCore *lc); + +/** + * Check whether the device is echo canceller calibration is required + * @returns TRUE if it is required, FALSE otherwise + * @ingroup misc +**/ +LINPHONE_PUBLIC bool_t linphone_core_is_echo_canceller_calibration_required(LinphoneCore *lc); + /** * @ingroup IOS * Special function to warm up dtmf feeback stream. #linphone_core_stop_dtmf_stream must() be called before entering FG mode From d8e2c6c687fe799b2c36306d7fa836931053f577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Mon, 16 Oct 2017 11:39:48 +0200 Subject: [PATCH 0498/2215] [C++ wrapper] Fix generation of linphone::DialPlan class --- include/linphone/wrapper_utils.h | 12 ++++++++++++ src/c-wrapper/api/c-dial-plan.cpp | 10 +++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/include/linphone/wrapper_utils.h b/include/linphone/wrapper_utils.h index 35c335595..2905f7b5e 100644 --- a/include/linphone/wrapper_utils.h +++ b/include/linphone/wrapper_utils.h @@ -83,6 +83,18 @@ LINPHONE_PUBLIC void linphone_chat_message_resend_2(LinphoneChatMessage *msg); */ LINPHONE_PUBLIC void *linphone_vcard_get_belcard(LinphoneVcard *vcard); + +/** + * @brief Increases the reference counter of #LinphoneDialPlan objects. + */ +LINPHONE_PUBLIC LinphoneDialPlan *linphone_dial_plan_ref(LinphoneDialPlan *dp); + +/** + * @brief Decreases the reference counter of #LinphoneDialPaln objects. + */ +LINPHONE_PUBLIC void linphone_dial_plan_unref(LinphoneDialPlan *dp); + + /** * @} */ diff --git a/src/c-wrapper/api/c-dial-plan.cpp b/src/c-wrapper/api/c-dial-plan.cpp index 8c4745b0f..45626f2d9 100644 --- a/src/c-wrapper/api/c-dial-plan.cpp +++ b/src/c-wrapper/api/c-dial-plan.cpp @@ -29,6 +29,14 @@ using namespace std; L_DECLARE_C_OBJECT_IMPL(DialPlan); +LinphoneDialPlan *linphone_dial_plan_ref(LinphoneDialPlan *dp) { + return (LinphoneDialPlan *)belle_sip_object_ref(dp); +} + +void linphone_dial_plan_unref(LinphoneDialPlan *dp) { + belle_sip_object_unref(dp); +} + const char * linphone_dial_plan_get_country(const LinphoneDialPlan *dp) { return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(dp)->getCountry()); } @@ -78,4 +86,4 @@ const bctbx_list_t * linphone_dial_plan_get_all_list() { bool_t linphone_dial_plan_is_generic(const LinphoneDialPlan *ccc) { return L_GET_CPP_PTR_FROM_C_OBJECT(ccc)->isGeneric(); -} \ No newline at end of file +} From 454e14d794f45178400131cf3b592db691e4c8f9 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 16 Oct 2017 12:08:42 +0200 Subject: [PATCH 0499/2215] Fixed issue with dialplan at runtime --- src/dial-plan/dial-plan.cpp | 3 +-- wrappers/java/migration.sh | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dial-plan/dial-plan.cpp b/src/dial-plan/dial-plan.cpp index af6146b0e..d72d48086 100644 --- a/src/dial-plan/dial-plan.cpp +++ b/src/dial-plan/dial-plan.cpp @@ -262,8 +262,7 @@ list const DialPlan::DialPlans = { {"Wallis and Futuna" ,"WF" , "681" , 5 , "00" }, {"Yemen" ,"YE" , "967" , 9 , "00" }, {"Zambia" ,"ZM" , "260" , 9 , "00" }, - {"Zimbabwe" ,"ZW" , "263" , 9 , "00" }, - {NULL ,NULL , "" , 0 , NULL } + {"Zimbabwe" ,"ZW" , "263" , 9 , "00" } }; const DialPlan DialPlan::MostCommon("generic", "", "", 10, "00"); diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 7626a7745..afd282371 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -225,6 +225,7 @@ eval "$SED_START 's/.sendDtmf(/.getCurrentCall().sendDtmf(/g' $SED_END" eval "$SED_START 's/content.getData() == null/content.getSize() == 0/'g $SED_END" eval "$SED_START 's/lc.downloadOpenH264Enabled()/OpenH264DownloadHelper.isOpenH264DownloadEnabled()/g' $SED_END" eval "$SED_START 's/enableDownloadOpenH264(/OpenH264DownloadHelper.enableDownloadOpenH264(/g' $SED_END" +eval "$SED_START 's/mLc.destroy()/mLc = null/g' $SED_END" #Changes in library required #Tunnel From 30b04f5eb85d92ae171296f89235ed99c17ffd24 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 16 Oct 2017 13:20:06 +0200 Subject: [PATCH 0500/2215] Replaced linphone_dial_plan_get_all in linphonecore_jni.cc by linphone_dial_plan_get_all_list --- coreapi/linphonecore_jni.cc | 24 +++++++++++++----------- include/linphone/api/c-dial-plan.h | 3 ++- src/c-wrapper/api/c-dial-plan.cpp | 2 +- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 77f1124fa..27002061b 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -226,28 +226,30 @@ extern "C" jobjectArray Java_org_linphone_core_LinphoneCoreFactoryImpl_getAllDia jclass addr_class = env->FindClass("org/linphone/core/DialPlanImpl"); jmethodID addr_constructor = env->GetMethodID(addr_class, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;)V"); jobjectArray jaddr_array; - int i, size = 0; - countries = (LinphoneDialPlan *)linphone_dial_plan_get_all(); + size_t i; + const bctbx_list_t *countries = linphone_dial_plan_get_all_list(); + size_t size = bctbx_list_size(countries); - while (countries[size].country != NULL) size++; + jaddr_array = env->NewObjectArray((int)size, addr_class, NULL); - jaddr_array = env->NewObjectArray(size, addr_class, NULL); + for (i = 0; i < size; i++) { + LinphoneDialPlan* dp = (LinphoneDialPlan*)countries->data; - for (i=0; i < size ; i++) { - jstring jcountry = env->NewStringUTF(countries[i].country); - jstring jiso = env->NewStringUTF(countries[i].iso_country_code); - jstring jccc = env->NewStringUTF(countries[i].ccc); - jint jnnl = (jint)countries[i].nnl; - jstring jicp = env->NewStringUTF(countries[i].icp); + jstring jcountry = env->NewStringUTF(linphone_dial_plan_get_country(dp)); + jstring jiso = env->NewStringUTF(linphone_dial_plan_get_iso_country_code(dp)); + jstring jccc = env->NewStringUTF(linphone_dial_plan_get_country_calling_code(dp)); + jint jnnl = (jint)linphone_dial_plan_get_national_number_length(dp); + jstring jicp = env->NewStringUTF(linphone_dial_plan_get_international_call_prefix(dp)); jobject jaddr = env->NewObject(addr_class, addr_constructor, jcountry, jiso, jccc, jnnl, jicp); - env->SetObjectArrayElement(jaddr_array, i, jaddr); + env->SetObjectArrayElement(jaddr_array, (int)i, jaddr); env->DeleteLocalRef(jcountry); env->DeleteLocalRef(jiso); env->DeleteLocalRef(jccc); env->DeleteLocalRef(jicp); + countries = countries->next; } return jaddr_array; } diff --git a/include/linphone/api/c-dial-plan.h b/include/linphone/api/c-dial-plan.h index 8bb8631b1..6a2f85110 100644 --- a/include/linphone/api/c-dial-plan.h +++ b/include/linphone/api/c-dial-plan.h @@ -79,7 +79,8 @@ LINPHONE_PUBLIC int linphone_dial_plan_lookup_ccc_from_e164(const char* e164); /** * Return NULL-terminated array of all known dial plans - * @deprecated use linphone_dial_plan_get_all_list instead + * @deprecated use linphone_dial_plan_get_all_list instead, this method will always return NULL + * @donotwrap **/ LINPHONE_PUBLIC const LinphoneDialPlan* linphone_dial_plan_get_all(void); diff --git a/src/c-wrapper/api/c-dial-plan.cpp b/src/c-wrapper/api/c-dial-plan.cpp index 45626f2d9..beafd3ecd 100644 --- a/src/c-wrapper/api/c-dial-plan.cpp +++ b/src/c-wrapper/api/c-dial-plan.cpp @@ -76,7 +76,7 @@ const LinphoneDialPlan* linphone_dial_plan_by_ccc(const char *ccc) { } const LinphoneDialPlan* linphone_dial_plan_get_all() { - return NULL; //TODO + return NULL; } const bctbx_list_t * linphone_dial_plan_get_all_list() { From bf1d1d4e75223b46246460363389857042909950 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 16 Oct 2017 15:18:22 +0200 Subject: [PATCH 0501/2215] Fixes for wrapper and Android compil --- coreapi/factory.c | 4 ++++ include/linphone/api/c-dial-plan.h | 2 +- include/linphone/factory.h | 7 +++++++ src/dial-plan/dial-plan.cpp | 2 +- wrappers/java/migration.sh | 2 +- 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/coreapi/factory.c b/coreapi/factory.c index fadb6234f..5dab6b014 100644 --- a/coreapi/factory.c +++ b/coreapi/factory.c @@ -330,3 +330,7 @@ void *linphone_factory_get_user_data(const LinphoneFactory *factory) { void linphone_factory_set_user_data(LinphoneFactory *factory, void *data) { factory->user_data = data; } + +const bctbx_list_t * linphone_factory_get_dial_plans(LinphoneFactory *factory) { + return linphone_dial_plan_get_all_list(); +} diff --git a/include/linphone/api/c-dial-plan.h b/include/linphone/api/c-dial-plan.h index 6a2f85110..6cfd4fa78 100644 --- a/include/linphone/api/c-dial-plan.h +++ b/include/linphone/api/c-dial-plan.h @@ -85,7 +85,7 @@ LINPHONE_PUBLIC int linphone_dial_plan_lookup_ccc_from_e164(const char* e164); LINPHONE_PUBLIC const LinphoneDialPlan* linphone_dial_plan_get_all(void); /** - * @return {\bctbx_list const LinphoneDialPlan*} of all known dial plans + * @return \bctbx_list{LinphoneDialPlan} of all known dial plans **/ LINPHONE_PUBLIC const bctbx_list_t * linphone_dial_plan_get_all_list(void); diff --git a/include/linphone/factory.h b/include/linphone/factory.h index a3e49fc7b..6020db46a 100644 --- a/include/linphone/factory.h +++ b/include/linphone/factory.h @@ -276,6 +276,13 @@ LINPHONE_PUBLIC void *linphone_factory_get_user_data(const LinphoneFactory *fact */ LINPHONE_PUBLIC void linphone_factory_set_user_data(LinphoneFactory *factory, void *data); +/*** + * Returns a bctbx_list_t of all DialPlans + * @param[in] factory the LinphoneFactory object + * @return \bctbx_list{DialPlan} a list of DialPlan + */ +LINPHONE_PUBLIC const bctbx_list_t * linphone_factory_get_dial_plans(LinphoneFactory *factory); + /** * @} */ diff --git a/src/dial-plan/dial-plan.cpp b/src/dial-plan/dial-plan.cpp index d72d48086..4f9fb94f5 100644 --- a/src/dial-plan/dial-plan.cpp +++ b/src/dial-plan/dial-plan.cpp @@ -373,7 +373,7 @@ int DialPlan::lookupCccFromIso(string iso) { } const DialPlan& DialPlan::findByCccAsInt(int ccc) { - string cccString = to_string(ccc); + string cccString = Utils::toString(ccc); return DialPlan::findByCcc(cccString); } diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index afd282371..c2e889a81 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -238,7 +238,7 @@ eval "$SED_START 's/mLc.destroy()/mLc = null/g' $SED_END" #Core.needsEchoCalibration() #Core.hasCrappyOpenGL() #Core.getMSFactory() -#COre.startEchoCalibration +#Core.startEchoCalibration #Core.startEchoTester #Core.stopEchoTester From 4ee2312949eba161ffdcc262f53e9d967db13d73 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 16 Oct 2017 15:25:01 +0200 Subject: [PATCH 0502/2215] feat(EventLog): add new ConferenceParticipantDevice event --- include/linphone/enums/event-log-enums.h | 4 +- src/CMakeLists.txt | 3 + src/chat/chat-room/chat-room-p.h | 2 +- src/db/main-db.cpp | 2 + .../conference-participant-device-event.cpp | 80 +++++++++++++++++++ .../conference-participant-device-event.h | 51 ++++++++++++ .../conference-participant-event-p.h | 39 +++++++++ .../conference-participant-event.cpp | 19 +++-- src/event-log/conference-participant-event.h | 8 ++ 9 files changed, 198 insertions(+), 10 deletions(-) create mode 100644 src/event-log/conference-participant-device-event.cpp create mode 100644 src/event-log/conference-participant-device-event.h create mode 100644 src/event-log/conference-participant-event-p.h diff --git a/include/linphone/enums/event-log-enums.h b/include/linphone/enums/event-log-enums.h index b854d5cbf..22c3d3d34 100644 --- a/include/linphone/enums/event-log-enums.h +++ b/include/linphone/enums/event-log-enums.h @@ -32,6 +32,8 @@ F(ConferenceParticipantAdded) \ F(ConferenceParticipantRemoved) \ F(ConferenceParticipantSetAdmin) \ - F(ConferenceParticipantUnsetAdmin) + F(ConferenceParticipantUnsetAdmin) \ + F(ConferenceParticipantDeviceAdded) \ + F(ConferenceParticipantDeviceRemoved) #endif // ifndef _EVENT_LOG_ENUMS_H_ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8b9d33bae..4711b9625 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -94,6 +94,8 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES event-log/chat-message-event.h event-log/conference-event-p.h event-log/conference-event.h + event-log/conference-participant-device-event.h + event-log/conference-participant-event-p.h event-log/conference-participant-event.h event-log/event-log-p.h event-log/event-log.h @@ -170,6 +172,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES event-log/call-event.cpp event-log/chat-message-event.cpp event-log/conference-event.cpp + event-log/conference-participant-device-event.cpp event-log/conference-participant-event.cpp event-log/event-log.cpp hacks/hacks.cpp diff --git a/src/chat/chat-room/chat-room-p.h b/src/chat/chat-room/chat-room-p.h index c434b0bcc..069814e53 100644 --- a/src/chat/chat-room/chat-room-p.h +++ b/src/chat/chat-room/chat-room-p.h @@ -101,7 +101,7 @@ public: std::list> messages; std::list> transientMessages; std::list> weakMessages; - std::shared_ptr pendingMessage = nullptr; + std::shared_ptr pendingMessage; IsComposing isComposingHandler; private: diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 4e2ef9570..c5f9bb523 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -453,6 +453,8 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} case EventLog::Type::ConferenceParticipantRemoved: case EventLog::Type::ConferenceParticipantSetAdmin: case EventLog::Type::ConferenceParticipantUnsetAdmin: + case EventLog::Type::ConferenceParticipantDeviceAdded: + case EventLog::Type::ConferenceParticipantDeviceRemoved: break; } diff --git a/src/event-log/conference-participant-device-event.cpp b/src/event-log/conference-participant-device-event.cpp new file mode 100644 index 000000000..716a08131 --- /dev/null +++ b/src/event-log/conference-participant-device-event.cpp @@ -0,0 +1,80 @@ +/* + * conference-participant-device-event.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "conference-participant-device-event.h" +#include "conference-participant-event-p.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +class ConferenceParticipantDeviceEventPrivate : public ConferenceParticipantEventPrivate { +public: + Address gruuAddress; +}; + +// ----------------------------------------------------------------------------- + +ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent ( + Type type, + const Address &conferenceAddress, + const Address &participantAddress, + const Address &gruuAddress +) : ConferenceParticipantEvent( + *new ConferenceParticipantDeviceEventPrivate, + type, + conferenceAddress, + participantAddress +) { + L_D(); + L_ASSERT( + type == Type::ConferenceParticipantDeviceAdded || + type == Type::ConferenceParticipantDeviceRemoved + ); + d->gruuAddress = gruuAddress; +} + +ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent (const ConferenceParticipantDeviceEvent &src) : + ConferenceParticipantDeviceEvent( + src.getType(), + src.getAddress(), + src.getParticipantAddress(), + src.getGruuAddress() + ) {} + +ConferenceParticipantDeviceEvent &ConferenceParticipantDeviceEvent::operator= ( + const ConferenceParticipantDeviceEvent &src +) { + L_D(); + if (this != &src) { + ConferenceParticipantEvent::operator=(src); + d->gruuAddress = src.getPrivate()->gruuAddress; + } + + return *this; +} + +const Address &ConferenceParticipantDeviceEvent::getGruuAddress () const { + L_D(); + return d->gruuAddress; +} + +LINPHONE_END_NAMESPACE diff --git a/src/event-log/conference-participant-device-event.h b/src/event-log/conference-participant-device-event.h new file mode 100644 index 000000000..b30f86903 --- /dev/null +++ b/src/event-log/conference-participant-device-event.h @@ -0,0 +1,51 @@ +/* + * conference-participant-device-event.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CONFERENCE_PARTICIPANT_DEVICE_EVENT_H_ +#define _CONFERENCE_PARTICIPANT_DEVICE_EVENT_H_ + +#include "conference-participant-event.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ConferenceParticipantDeviceEventPrivate; + +class LINPHONE_PUBLIC ConferenceParticipantDeviceEvent : public ConferenceParticipantEvent { +public: + ConferenceParticipantDeviceEvent ( + Type type, + const Address &conferenceAddress, + const Address &participantAddress, + const Address &gruuAddress + ); + ConferenceParticipantDeviceEvent (const ConferenceParticipantDeviceEvent &src); + + ConferenceParticipantDeviceEvent &operator= (const ConferenceParticipantDeviceEvent &src); + + const Address &getGruuAddress () const; + +private: + L_DECLARE_PRIVATE(ConferenceParticipantDeviceEvent); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CONFERENCE_PARTICIPANT_DEVICE_EVENT_H_ diff --git a/src/event-log/conference-participant-event-p.h b/src/event-log/conference-participant-event-p.h new file mode 100644 index 000000000..6aab2eb72 --- /dev/null +++ b/src/event-log/conference-participant-event-p.h @@ -0,0 +1,39 @@ +/* + * conference-participant-event-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CONFERENCE_PARTICIPANT_EVENT_P_H_ +#define _CONFERENCE_PARTICIPANT_EVENT_P_H_ + +#include "conference-event-p.h" +#include "conference-participant-event.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ConferenceParticipantEventPrivate : public ConferenceEventPrivate { +private: + Address participantAddress; + + L_DECLARE_PUBLIC(ConferenceParticipantEvent); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CONFERENCE_PARTICIPANT_EVENT_P_H_ diff --git a/src/event-log/conference-participant-event.cpp b/src/event-log/conference-participant-event.cpp index b6ba46c17..71ff78c82 100644 --- a/src/event-log/conference-participant-event.cpp +++ b/src/event-log/conference-participant-event.cpp @@ -17,9 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "address/address.h" -#include "conference-event-p.h" -#include "conference-participant-event.h" +#include "conference-participant-event-p.h" // ============================================================================= @@ -27,11 +25,6 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -class ConferenceParticipantEventPrivate : public ConferenceEventPrivate { -public: - Address participantAddress; -}; - // ----------------------------------------------------------------------------- ConferenceParticipantEvent::ConferenceParticipantEvent ( @@ -52,6 +45,16 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( ConferenceParticipantEvent::ConferenceParticipantEvent (const ConferenceParticipantEvent &src) : ConferenceParticipantEvent(src.getType(), src.getAddress(), src.getParticipantAddress()) {} +ConferenceParticipantEvent::ConferenceParticipantEvent ( + ConferenceParticipantEventPrivate &p, + Type type, + const Address &conferenceAddress, + const Address &participantAddress +) : ConferenceEvent(p, type, conferenceAddress) { + L_D(); + d->participantAddress = participantAddress; +} + ConferenceParticipantEvent &ConferenceParticipantEvent::operator= (const ConferenceParticipantEvent &src) { L_D(); if (this != &src) { diff --git a/src/event-log/conference-participant-event.h b/src/event-log/conference-participant-event.h index 7732b75de..97f7e2eb0 100644 --- a/src/event-log/conference-participant-event.h +++ b/src/event-log/conference-participant-event.h @@ -41,6 +41,14 @@ public: const Address &getParticipantAddress () const; +protected: + ConferenceParticipantEvent ( + ConferenceParticipantEventPrivate &p, + Type type, + const Address &conferenceAddress, + const Address &participantAddress + ); + private: L_DECLARE_PRIVATE(ConferenceParticipantEvent); }; From cc86f4c3f6919de60363b5ec46dd4136c5d38d8b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 16 Oct 2017 15:32:39 +0200 Subject: [PATCH 0503/2215] Fixed factory getDialPlans() --- coreapi/factory.c | 10 +++++----- include/linphone/factory.h | 14 +++++++------- wrappers/java/migration.sh | 2 ++ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/coreapi/factory.c b/coreapi/factory.c index 5dab6b014..089dfca9e 100644 --- a/coreapi/factory.c +++ b/coreapi/factory.c @@ -323,14 +323,14 @@ LinphoneVideoActivationPolicy *linphone_factory_create_video_activation_policy(L return linphone_video_activation_policy_new(); } +const bctbx_list_t * linphone_factory_get_dial_plans(const LinphoneFactory *factory) { + return linphone_dial_plan_get_all_list(); +} + void *linphone_factory_get_user_data(const LinphoneFactory *factory) { return factory->user_data; } void linphone_factory_set_user_data(LinphoneFactory *factory, void *data) { factory->user_data = data; -} - -const bctbx_list_t * linphone_factory_get_dial_plans(LinphoneFactory *factory) { - return linphone_dial_plan_get_all_list(); -} +} \ No newline at end of file diff --git a/include/linphone/factory.h b/include/linphone/factory.h index 6020db46a..351567478 100644 --- a/include/linphone/factory.h +++ b/include/linphone/factory.h @@ -262,6 +262,13 @@ LINPHONE_PUBLIC LinphoneTransports *linphone_factory_create_transports(LinphoneF */ LINPHONE_PUBLIC LinphoneVideoActivationPolicy *linphone_factory_create_video_activation_policy(LinphoneFactory *factory); +/** + * Returns a bctbx_list_t of all DialPlans + * @param[in] factory the LinphoneFactory object + * @return \bctbx_list{LinphoneDialPlan} a list of DialPlan + */ +LINPHONE_PUBLIC const bctbx_list_t * linphone_factory_get_dial_plans(const LinphoneFactory *factory); + /** * Gets the user data in the LinphoneFactory object * @param[in] factory the LinphoneFactory @@ -276,13 +283,6 @@ LINPHONE_PUBLIC void *linphone_factory_get_user_data(const LinphoneFactory *fact */ LINPHONE_PUBLIC void linphone_factory_set_user_data(LinphoneFactory *factory, void *data); -/*** - * Returns a bctbx_list_t of all DialPlans - * @param[in] factory the LinphoneFactory object - * @return \bctbx_list{DialPlan} a list of DialPlan - */ -LINPHONE_PUBLIC const bctbx_list_t * linphone_factory_get_dial_plans(LinphoneFactory *factory); - /** * @} */ diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index c2e889a81..b046e46c3 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -226,6 +226,8 @@ eval "$SED_START 's/content.getData() == null/content.getSize() == 0/'g $SED_END eval "$SED_START 's/lc.downloadOpenH264Enabled()/OpenH264DownloadHelper.isOpenH264DownloadEnabled()/g' $SED_END" eval "$SED_START 's/enableDownloadOpenH264(/OpenH264DownloadHelper.enableDownloadOpenH264(/g' $SED_END" eval "$SED_START 's/mLc.destroy()/mLc = null/g' $SED_END" +eval "$SED_START 's/getAllDialPlan()/getDialPlans()/g' $SED_END" +eval "$SED_START 's/getCountryName()/getCountry()/g' $SED_END" #Changes in library required #Tunnel From 471c5b3d970f9267fe8b65fa533316ecee3f4c07 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 16 Oct 2017 15:51:52 +0200 Subject: [PATCH 0504/2215] Fixes for listeners in Java wrapper + added manually wrapped Core.getMediastreamerFactory --- wrappers/java/genwrapper.py | 4 +++- wrappers/java/java_class.mustache | 13 +++++++++++++ wrappers/java/jni.mustache | 17 +++++++++++++++++ wrappers/java/migration.sh | 3 +-- 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index b9de6e321..d1b3b52ef 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -416,6 +416,7 @@ class JavaTranslator(object): } classDict['isLinphoneFactory'] = _class.name.to_camel_case() == "Factory" + classDict['isLinphoneCore'] = _class.name.to_camel_case() == "Core" classDict['doc'] = self.docTranslator.translate(_class.briefDescription) if _class.briefDescription is not None else None for _property in _class.properties: @@ -590,7 +591,7 @@ class JniInterface(object): def __init__(self, javaClass, apiClass): self.isSingleListener = (not apiClass.multilistener) self.isMultiListener = (apiClass.multilistener) - self.classCName = javaClass.cName + self.classCName = javaClass.className self.cPrefix = javaClass.cPrefix self.callbacks = [] listener = apiClass.listenerInterface @@ -626,6 +627,7 @@ class JavaClass(object): def __init__(self, package, _class, translator): self._class = translator.translate_class(_class) self.isLinphoneFactory = self._class['isLinphoneFactory'] + self.isLinphoneCore = self._class['isLinphoneCore'] self.isNotLinphoneFactory = not self.isLinphoneFactory self.cName = 'Linphone' + _class.name.to_camel_case() self.cPrefix = 'linphone_' + _class.name.to_snake_case() diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 6c838aa5b..b5c75362e 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -95,6 +95,12 @@ public {{#isLinphoneFactory}}abstract class{{/isLinphoneFactory}}{{#isNotLinphon abstract public OpenH264DownloadHelper createOpenH264DownloadHelper(Context context); {{/isLinphoneFactory}} +{{#isLinphoneCore}} + /** + * Gets the mediastreamer's factory + */ + public org.linphone.mediastream.Factory getMediastreamerFactory(); +{{/isLinphoneCore}} {{#methods}} {{#doc}} /** @@ -181,6 +187,13 @@ class {{classImplName}} {{#isLinphoneFactory}}extends{{/isLinphoneFactory}}{{#is } {{/methods}} +{{#isLinphoneCore}} + private native org.linphone.mediastream.Factory getMediastreamerFactory(long nativePtr); + public org.linphone.mediastream.Factory getMediastreamerFactory() { + return getMediastreamerFactory(nativePtr); + } + +{{/isLinphoneCore}} {{#isNotLinphoneFactory}} private native void unref(long ptr); protected void finalize() throws Throwable { diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index 437c2f286..3bf1bf85d 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -72,6 +72,9 @@ static jlong GetObjectNativePtr(JNIEnv *env, jobject object) { class LinphoneJavaBindings { public: LinphoneJavaBindings(JNIEnv *env) { + ms_factory_class = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/mediastream/Factory")); + ms_factory_class_constructor = env->GetMethodID(ms_factory_class, "", "(J)V"); + {{#objects}} {{cPrefix}}_class = (jclass)env->NewGlobalRef(env->FindClass("{{jniPath}}{{classImplName}}")); {{cPrefix}}_class_constructor = env->GetMethodID({{cPrefix}}_class, "", "(J)V"); @@ -86,6 +89,9 @@ public: ~LinphoneJavaBindings() { JNIEnv *env = 0; jvm->AttachCurrentThread(&env,NULL); + + env->DeleteGlobalRef(ms_factory_class); + {{#objects}} env->DeleteGlobalRef({{cPrefix}}_class); {{/objects}} @@ -95,6 +101,9 @@ public: {{/enums}} } + jclass ms_factory_class; + jmethodID ms_factory_class_constructor; + {{#objects}} jclass {{cPrefix}}_class; jmethodID {{cPrefix}}_class_constructor; @@ -265,6 +274,14 @@ void {{jniPackage}}{{classCName}}Impl_removeListener(JNIEnv* env, jobject thiz, {{/interfaces}} ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +jobject {{jni_package}}CoreImpl_getMediastreamerFactory(JNIEnv *env, jobject thiz, jlong ptr) { + LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_factory_get_user_data(linphone_factory_get()); + MSFactory *factory = linphone_core_get_ms_factory((LinphoneCore*)ptr); + return env->NewObject(ljb->ms_factory_class, ljb->ms_factory_class_constructor, (jlong)factory); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + {{#methods}} {{return}} {{name}}({{params}}) { {{#notStatic}}{{classCName}} *cptr = ({{classCName}}*)ptr;{{/notStatic}}{{#strings}} diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index b046e46c3..00324baa8 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -228,10 +228,10 @@ eval "$SED_START 's/enableDownloadOpenH264(/OpenH264DownloadHelper.enableDownloa eval "$SED_START 's/mLc.destroy()/mLc = null/g' $SED_END" eval "$SED_START 's/getAllDialPlan()/getDialPlans()/g' $SED_END" eval "$SED_START 's/getCountryName()/getCountry()/g' $SED_END" +eval "$SED_START 's/getMSFactory()/getMediastreamerFactory()/g' $SED_END" #Changes in library required #Tunnel -#DialPlan #LinphoneBuffer #Call.zoomVideo() #AccountCreator.updatePassword @@ -239,7 +239,6 @@ eval "$SED_START 's/getCountryName()/getCountry()/g' $SED_END" #Android specifics not wrapped automatically #Core.needsEchoCalibration() #Core.hasCrappyOpenGL() -#Core.getMSFactory() #Core.startEchoCalibration #Core.startEchoTester #Core.stopEchoTester From 0b95c162d35a743145dc945a535afb808245e07d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 16 Oct 2017 15:56:17 +0200 Subject: [PATCH 0505/2215] Real fix for Java wrapper's listeners --- wrappers/java/genwrapper.py | 4 +++- wrappers/java/jni.mustache | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index d1b3b52ef..1a295e4d9 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -591,7 +591,8 @@ class JniInterface(object): def __init__(self, javaClass, apiClass): self.isSingleListener = (not apiClass.multilistener) self.isMultiListener = (apiClass.multilistener) - self.classCName = javaClass.className + self.className = javaClass.className + self.classCName = javaClass.cName self.cPrefix = javaClass.cPrefix self.callbacks = [] listener = apiClass.listenerInterface @@ -694,6 +695,7 @@ class Jni(object): 'isSingleListener': jniInterface.isSingleListener, 'isMultiListener': jniInterface.isMultiListener, 'classCName': jniInterface.classCName, + 'className': jniInterface.className, 'cPrefix': jniInterface.cPrefix, 'jniPackage': self.jni_package, 'factoryName': javaClass.factoryName, diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index 3bf1bf85d..ba7172de0 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -234,10 +234,10 @@ static {{return}} {{callbackName}}({{params}}) { {{#interfaces}} {{#isSingleListener}} -void {{jniPackage}}{{classCName}}Impl_setListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { +void {{jniPackage}}{{className}}Impl_setListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { {{/isSingleListener}} {{#isMultiListener}} -void {{jniPackage}}{{classCName}}Impl_addListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { +void {{jniPackage}}{{className}}Impl_addListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { {{/isMultiListener}} {{classCName}} *cptr = ({{classCName}}*)ptr; jobject listener = env->NewGlobalRef(jlistener); @@ -257,7 +257,7 @@ void {{jniPackage}}{{classCName}}Impl_addListener(JNIEnv* env, jobject thiz, jlo } {{#isMultiListener}} -void {{jniPackage}}{{classCName}}Impl_removeListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { +void {{jniPackage}}{{className}}Impl_removeListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { {{classCName}} *cptr = ({{classCName}}*)ptr; const bctbx_list_t *cbs_list = {{cPrefix}}_get_callbacks_list(cptr); bctbx_list_t *it; From 3bfbbae101a010761adc857a80345564b605d00d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 16 Oct 2017 16:11:22 +0200 Subject: [PATCH 0506/2215] Fixed migration for dialplan lookups --- wrappers/java/classes/LinphoneUtils.java | 34 ++++++++++++++++++++++++ wrappers/java/migration.sh | 4 +-- 2 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 wrappers/java/classes/LinphoneUtils.java diff --git a/wrappers/java/classes/LinphoneUtils.java b/wrappers/java/classes/LinphoneUtils.java new file mode 100644 index 000000000..c60ebb440 --- /dev/null +++ b/wrappers/java/classes/LinphoneUtils.java @@ -0,0 +1,34 @@ +/* +LinphoneUtils.java +Copyright (C) 2010-2017 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +package org.linphone.core; + +public class LinphoneUtils { + public static int getPrefixFromE164(String e164) { + DialPlan[] dialPlans = Factory.instance().getDialPlans(); + DialPlan dialPlan = dialPlans[0]; + return dialPlan.lookupCccFromE164(e164); + } + + public static int getCccFromIso(String countryIso) { + DialPlan[] dialPlans = Factory.instance().getDialPlans(); + DialPlan dialPlan = dialPlans[0]; + return dialPlan.lookupCccFromIso(countryIso); + } +} diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 00324baa8..2cef09ff8 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -229,6 +229,8 @@ eval "$SED_START 's/mLc.destroy()/mLc = null/g' $SED_END" eval "$SED_START 's/getAllDialPlan()/getDialPlans()/g' $SED_END" eval "$SED_START 's/getCountryName()/getCountry()/g' $SED_END" eval "$SED_START 's/getMSFactory()/getMediastreamerFactory()/g' $SED_END" +eval "$SED_START 's/accountCreator.getPrefix(/LinphoneUtils::getPrefixFromE164(/g' $SED_END" +eval "$SED_START 's/proxyConfig.lookupCCCFromIso(/LinphoneUtils::getCccFromIso(/g' $SED_END" #Changes in library required #Tunnel @@ -261,8 +263,6 @@ eval "$SED_START 's/getMSFactory()/getMediastreamerFactory()/g' $SED_END" #Core.enableSpeaker / isSpeakerEnabled() => mAudioManager.setSpeakerphoneOn(speakerOn); #Core.enableVideo(true, true) => Core.enableVideoCapture(bool) & Core.enableVideoDisplay(bool) #Core.setCpuCount() => Not needed anymore, can be removed -#AccountCreator.getPrefix => linphone_dial_plan_lookup_ccc_from_e164 -#ProxyConfig.lookupCCCFromIso=> linphone_dial_plan_lookup_ccc_from_iso #Factory.instance().setLogCollectionPath(getFilesDir().getAbsolutePath()); => Core.setLogCollectionPath #Factory.instance().enableLogCollection(isDebugEnabled); => COre.enableLogCollection #Factory.instance().setDebugMode(isDebugEnabled, getString(R.string.app_name)); => Core.setLogLevelMask From 22c6e1c482606c058ade769db9d68bcdd3b93f9e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 16 Oct 2017 16:14:47 +0200 Subject: [PATCH 0507/2215] Renamed LinphoneUtils into Utils --- wrappers/java/classes/{LinphoneUtils.java => Utils.java} | 4 ++-- wrappers/java/migration.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename wrappers/java/classes/{LinphoneUtils.java => Utils.java} (96%) diff --git a/wrappers/java/classes/LinphoneUtils.java b/wrappers/java/classes/Utils.java similarity index 96% rename from wrappers/java/classes/LinphoneUtils.java rename to wrappers/java/classes/Utils.java index c60ebb440..19eeb9718 100644 --- a/wrappers/java/classes/LinphoneUtils.java +++ b/wrappers/java/classes/Utils.java @@ -1,5 +1,5 @@ /* -LinphoneUtils.java +Utils.java Copyright (C) 2010-2017 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or @@ -19,7 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. package org.linphone.core; -public class LinphoneUtils { +public class Utils { public static int getPrefixFromE164(String e164) { DialPlan[] dialPlans = Factory.instance().getDialPlans(); DialPlan dialPlan = dialPlans[0]; diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 2cef09ff8..2e83169b7 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -229,8 +229,8 @@ eval "$SED_START 's/mLc.destroy()/mLc = null/g' $SED_END" eval "$SED_START 's/getAllDialPlan()/getDialPlans()/g' $SED_END" eval "$SED_START 's/getCountryName()/getCountry()/g' $SED_END" eval "$SED_START 's/getMSFactory()/getMediastreamerFactory()/g' $SED_END" -eval "$SED_START 's/accountCreator.getPrefix(/LinphoneUtils::getPrefixFromE164(/g' $SED_END" -eval "$SED_START 's/proxyConfig.lookupCCCFromIso(/LinphoneUtils::getCccFromIso(/g' $SED_END" +eval "$SED_START 's/accountCreator.getPrefix(/org.linphone.core.Utils::getPrefixFromE164(/g' $SED_END" +eval "$SED_START 's/proxyConfig.lookupCCCFromIso(/org.linphone.core.Utils::getCccFromIso(/g' $SED_END" #Changes in library required #Tunnel From 894391c13b676093b126ccf47a4965c0fe00b720 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 16 Oct 2017 16:15:21 +0200 Subject: [PATCH 0508/2215] feat(Events): add a ConferenceSubjectEvent --- include/linphone/enums/event-log-enums.h | 3 +- src/CMakeLists.txt | 2 + src/db/main-db.cpp | 1 + src/event-log/conference-event-p.h | 2 +- src/event-log/conference-event.cpp | 21 +++---- src/event-log/conference-event.h | 7 +-- .../conference-participant-device-event.cpp | 2 +- .../conference-participant-event.cpp | 2 +- src/event-log/conference-subject-event.cpp | 60 +++++++++++++++++++ src/event-log/conference-subject-event.h | 46 ++++++++++++++ src/event-log/event-log.h | 1 - 11 files changed, 128 insertions(+), 19 deletions(-) create mode 100644 src/event-log/conference-subject-event.cpp create mode 100644 src/event-log/conference-subject-event.h diff --git a/include/linphone/enums/event-log-enums.h b/include/linphone/enums/event-log-enums.h index 22c3d3d34..b209427bb 100644 --- a/include/linphone/enums/event-log-enums.h +++ b/include/linphone/enums/event-log-enums.h @@ -34,6 +34,7 @@ F(ConferenceParticipantSetAdmin) \ F(ConferenceParticipantUnsetAdmin) \ F(ConferenceParticipantDeviceAdded) \ - F(ConferenceParticipantDeviceRemoved) + F(ConferenceParticipantDeviceRemoved) \ + F(ConferenceSubjectChanged) #endif // ifndef _EVENT_LOG_ENUMS_H_ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4711b9625..3548dda9f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -97,6 +97,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES event-log/conference-participant-device-event.h event-log/conference-participant-event-p.h event-log/conference-participant-event.h + event-log/conference-subject-event.h event-log/event-log-p.h event-log/event-log.h hacks/hacks.h @@ -174,6 +175,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES event-log/conference-event.cpp event-log/conference-participant-device-event.cpp event-log/conference-participant-event.cpp + event-log/conference-subject-event.cpp event-log/event-log.cpp hacks/hacks.cpp logger/logger.cpp diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index c5f9bb523..ead9d7c04 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -455,6 +455,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} case EventLog::Type::ConferenceParticipantUnsetAdmin: case EventLog::Type::ConferenceParticipantDeviceAdded: case EventLog::Type::ConferenceParticipantDeviceRemoved: + case EventLog::Type::ConferenceSubjectChanged: break; } diff --git a/src/event-log/conference-event-p.h b/src/event-log/conference-event-p.h index b3f403265..f88f80752 100644 --- a/src/event-log/conference-event-p.h +++ b/src/event-log/conference-event-p.h @@ -30,7 +30,7 @@ LINPHONE_BEGIN_NAMESPACE class ConferenceEventPrivate : public EventLogPrivate { private: - Address address; + Address conferenceAddress; L_DECLARE_PUBLIC(ConferenceEvent); }; diff --git a/src/event-log/conference-event.cpp b/src/event-log/conference-event.cpp index 795997a04..b6f4e67e3 100644 --- a/src/event-log/conference-event.cpp +++ b/src/event-log/conference-event.cpp @@ -26,34 +26,35 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ConferenceEvent::ConferenceEvent (Type type, const Address &address) : +ConferenceEvent::ConferenceEvent (Type type, const Address &conferenceAddress) : EventLog(*new ConferenceEventPrivate, type) { L_D(); L_ASSERT(type == Type::ConferenceCreated || type == Type::ConferenceDestroyed); - d->address = address; + d->conferenceAddress = conferenceAddress; } -ConferenceEvent::ConferenceEvent (const ConferenceEvent &src) : ConferenceEvent(src.getType(), src.getAddress()) {} +ConferenceEvent::ConferenceEvent (const ConferenceEvent &src) : + ConferenceEvent(src.getType(), src.getConferenceAddress()) {} -ConferenceEvent::ConferenceEvent (ConferenceEventPrivate &p, Type type, const Address &address) : +ConferenceEvent::ConferenceEvent (ConferenceEventPrivate &p, Type type, const Address &conferenceAddress) : EventLog(p, type) { - L_D(); - d->address = address; -} + L_D(); + d->conferenceAddress = conferenceAddress; + } ConferenceEvent &ConferenceEvent::operator= (const ConferenceEvent &src) { L_D(); if (this != &src) { EventLog::operator=(src); - d->address = src.getPrivate()->address; + d->conferenceAddress = src.getPrivate()->conferenceAddress; } return *this; } -const Address &ConferenceEvent::getAddress () const { +const Address &ConferenceEvent::getConferenceAddress () const { L_D(); - return d->address; + return d->conferenceAddress; } LINPHONE_END_NAMESPACE diff --git a/src/event-log/conference-event.h b/src/event-log/conference-event.h index d915ece90..ff1e93439 100644 --- a/src/event-log/conference-event.h +++ b/src/event-log/conference-event.h @@ -31,16 +31,15 @@ class ConferenceEventPrivate; class LINPHONE_PUBLIC ConferenceEvent : public EventLog { public: - ConferenceEvent (Type type, const Address &address); + ConferenceEvent (Type type, const Address &conferenceAddress); ConferenceEvent (const ConferenceEvent &src); - virtual ~ConferenceEvent () = default; ConferenceEvent &operator= (const ConferenceEvent &src); - const Address &getAddress () const; + const Address &getConferenceAddress () const; protected: - ConferenceEvent (ConferenceEventPrivate &p, Type type, const Address &address); + ConferenceEvent (ConferenceEventPrivate &p, Type type, const Address &conferenceAddress); private: L_DECLARE_PRIVATE(ConferenceEvent); diff --git a/src/event-log/conference-participant-device-event.cpp b/src/event-log/conference-participant-device-event.cpp index 716a08131..ce1ffbe9a 100644 --- a/src/event-log/conference-participant-device-event.cpp +++ b/src/event-log/conference-participant-device-event.cpp @@ -55,7 +55,7 @@ ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent ( ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent (const ConferenceParticipantDeviceEvent &src) : ConferenceParticipantDeviceEvent( src.getType(), - src.getAddress(), + src.getConferenceAddress(), src.getParticipantAddress(), src.getGruuAddress() ) {} diff --git a/src/event-log/conference-participant-event.cpp b/src/event-log/conference-participant-event.cpp index 71ff78c82..00f591b4e 100644 --- a/src/event-log/conference-participant-event.cpp +++ b/src/event-log/conference-participant-event.cpp @@ -43,7 +43,7 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( } ConferenceParticipantEvent::ConferenceParticipantEvent (const ConferenceParticipantEvent &src) : - ConferenceParticipantEvent(src.getType(), src.getAddress(), src.getParticipantAddress()) {} + ConferenceParticipantEvent(src.getType(), src.getConferenceAddress(), src.getParticipantAddress()) {} ConferenceParticipantEvent::ConferenceParticipantEvent ( ConferenceParticipantEventPrivate &p, diff --git a/src/event-log/conference-subject-event.cpp b/src/event-log/conference-subject-event.cpp new file mode 100644 index 000000000..2cb6c9889 --- /dev/null +++ b/src/event-log/conference-subject-event.cpp @@ -0,0 +1,60 @@ +/* + * conference-subject-event.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "conference-event-p.h" +#include "conference-subject-event.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +class ConferenceSubjectEventPrivate : public ConferenceEventPrivate { +public: + string subject; +}; + +// ----------------------------------------------------------------------------- + +ConferenceSubjectEvent::ConferenceSubjectEvent (const Address &address, const string &subject) : + ConferenceEvent(*new ConferenceSubjectEventPrivate, Type::ConferenceSubjectChanged, address) { + L_D(); + d->subject = subject; +} + +ConferenceSubjectEvent::ConferenceSubjectEvent (const ConferenceSubjectEvent &src) : + ConferenceSubjectEvent(src.getConferenceAddress(), src.getSubject()) {} + +ConferenceSubjectEvent &ConferenceSubjectEvent::operator= (const ConferenceSubjectEvent &src) { + L_D(); + if (this != &src) { + ConferenceEvent::operator=(src); + d->subject = src.getPrivate()->subject; + } + + return *this; +} + +const string &ConferenceSubjectEvent::getSubject () const { + L_D(); + return d->subject; +} + +LINPHONE_END_NAMESPACE diff --git a/src/event-log/conference-subject-event.h b/src/event-log/conference-subject-event.h new file mode 100644 index 000000000..efb4e49f4 --- /dev/null +++ b/src/event-log/conference-subject-event.h @@ -0,0 +1,46 @@ +/* + * conference-subject-event.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CONFERENCE_SUBJECT_EVENT_H_ +#define _CONFERENCE_SUBJECT_EVENT_H_ + +#include "conference-event.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ConferenceSubjectEventPrivate; + +class LINPHONE_PUBLIC ConferenceSubjectEvent : public ConferenceEvent { +public: + ConferenceSubjectEvent (const Address &conferenceAddress, const std::string &subject); + ConferenceSubjectEvent (const ConferenceSubjectEvent &src); + + ConferenceSubjectEvent &operator= (const ConferenceSubjectEvent &src); + + const std::string &getSubject () const; + +private: + L_DECLARE_PRIVATE(ConferenceSubjectEvent); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CONFERENCE_SUBJECT_EVENT_H_ diff --git a/src/event-log/event-log.h b/src/event-log/event-log.h index 256fd2d53..057c141e6 100644 --- a/src/event-log/event-log.h +++ b/src/event-log/event-log.h @@ -39,7 +39,6 @@ public: EventLog (); EventLog (const EventLog &src); - virtual ~EventLog () = default; EventLog &operator= (const EventLog &src); From 15fcc6950da80f82a3ae7247e768cfce8166ae68 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 16 Oct 2017 17:04:20 +0200 Subject: [PATCH 0509/2215] Fix some memory leaks. --- src/chat/chat-message/chat-message-p.h | 12 ++++++------ src/chat/chat-message/chat-message.cpp | 5 ++++- src/chat/notification/is-composing.cpp | 9 ++++++--- src/conference/local-conference-event-handler.cpp | 1 - 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index accd87b3c..1618639fe 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -136,11 +136,11 @@ private: std::list contents; Content internalContent; std::unordered_map customHeaders; - mutable LinphoneErrorInfo * errorInfo = NULL; - belle_http_request_t *httpRequest = NULL; - belle_http_request_listener_t *httpListener = NULL; - SalOp *salOp = NULL; - SalCustomHeader *salCustomHeaders = NULL; + mutable LinphoneErrorInfo * errorInfo = nullptr; + belle_http_request_t *httpRequest = nullptr; + belle_http_request_listener_t *httpListener = nullptr; + SalOp *salOp = nullptr; + SalCustomHeader *salCustomHeaders = nullptr; unsigned long backgroundTaskId; unsigned char currentSendStep = Step::None; bool applyModifiers = true; @@ -148,7 +148,7 @@ private: ContentType cContentType; std::string cText; // Used for compatibility with previous C API - LinphoneContent *cFileTransferInformation = NULL; + LinphoneContent *cFileTransferInformation = nullptr; // ----------------------------------------------------------------------------- diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index ebcf0e8c8..ed813723d 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -51,7 +51,10 @@ ChatMessagePrivate::ChatMessagePrivate (const shared_ptr &room) : chatRoom(room) { } -ChatMessagePrivate::~ChatMessagePrivate () {} +ChatMessagePrivate::~ChatMessagePrivate () { + if (salOp) + salOp->release(); +} // ----------------------------------------------------------------------------- diff --git a/src/chat/notification/is-composing.cpp b/src/chat/notification/is-composing.cpp index dd2a935a7..ed2424b3e 100644 --- a/src/chat/notification/is-composing.cpp +++ b/src/chat/notification/is-composing.cpp @@ -266,9 +266,12 @@ void IsComposing::stopAllRemoteRefreshTimers () { } unordered_map::iterator IsComposing::stopRemoteRefreshTimer (const unordered_map::const_iterator it) { - if (core && core->sal) - core->sal->cancel_timer(it->second); - belle_sip_object_unref(it->second); + belle_sip_source_t *timer = it->second; + if (core && core->sal) { + core->sal->cancel_timer(timer); + delete reinterpret_cast(belle_sip_source_get_user_data(timer)); + } + belle_sip_object_unref(timer); return remoteRefreshTimers.erase(it); } diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 272cde56a..ec6a0cd0c 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -39,7 +39,6 @@ static void doNotify (const string ¬ify, LinphoneEvent *lev) { linphone_content_set_buffer(content, notify.c_str(), strlen(notify.c_str())); linphone_event_notify(lev, content); linphone_content_unref(content); - linphone_event_unref(lev); } // ----------------------------------------------------------------------------- From db683ee68043b223c7fdb81f9c5a6aa8c4da03de Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 16 Oct 2017 17:34:48 +0200 Subject: [PATCH 0510/2215] feat(MainDb): create events table for subject, participant... --- src/db/main-db.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index ead9d7c04..5aa1bd04e 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -328,6 +328,55 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} " ON DELETE CASCADE" ")"; + *session << + "CREATE TABLE IF NOT EXISTS conference_event (" + " event_id INT UNSIGNED PRIMARY KEY," + " chat_room_id INT UNSIGNED NOT NULL," + + " FOREIGN KEY (event_id)" + " REFERENCES event(id)" + " ON DELETE CASCADE," + " FOREIGN KEY (chat_room_id)" + " REFERENCES chat_room(peer_sip_address_id)" + " ON DELETE CASCADE" + ")"; + + *session << + "CREATE TABLE IF NOT EXISTS conference_participant_event (" + " conference_event_id INT UNSIGNED PRIMARY KEY," + " participant_address_id INT UNSIGNED NOT NULL," + + " FOREIGN KEY (conference_event_id)" + " REFERENCES event(event_id)" + " ON DELETE CASCADE," + " FOREIGN KEY (participant_address_id)" + " REFERENCES sip_address(id)" + " ON DELETE CASCADE" + ")"; + + *session << + "CREATE TABLE IF NOT EXISTS conference_participant_device_event (" + " conference_participant_event_id INT UNSIGNED PRIMARY KEY," + " gruu_address_id INT UNSIGNED NOT NULL," + + " FOREIGN KEY (conference_participant_event_id)" + " REFERENCES conference_participant_event(conference_event_id)" + " ON DELETE CASCADE," + " FOREIGN KEY (gruu_address_id)" + " REFERENCES sip_address(id)" + " ON DELETE CASCADE" + ")"; + + *session << + "CREATE TABLE IF NOT EXISTS conference_subject_event (" + " conference_event_id INT UNSIGNED PRIMARY KEY," + " subject VARCHAR(255)," + + " FOREIGN KEY (conference_event_id)" + " REFERENCES event(event_id)" + " ON DELETE CASCADE" + ")"; + *session << "CREATE TABLE IF NOT EXISTS message_event (" " event_id INT UNSIGNED PRIMARY KEY," From e10297ba6df500b3154f539b11e4c44ded4a227a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 16 Oct 2017 17:44:03 +0200 Subject: [PATCH 0511/2215] Added new zoom method on call which doesn't use reference to floats --- include/linphone/api/c-call.h | 12 +++++++++++- src/c-wrapper/api/c-call.cpp | 4 ++++ src/call/call.cpp | 4 ++++ src/call/call.h | 1 + src/conference/session/media-session.cpp | 22 +++++++++++++--------- src/conference/session/media-session.h | 1 + wrappers/java/migration.sh | 3 ++- 7 files changed, 36 insertions(+), 11 deletions(-) diff --git a/include/linphone/api/c-call.h b/include/linphone/api/c-call.h index fe3c2c768..da3dbaaa5 100644 --- a/include/linphone/api/c-call.h +++ b/include/linphone/api/c-call.h @@ -272,11 +272,21 @@ LINPHONE_PUBLIC LinphoneCallState linphone_call_get_transfer_state (LinphoneCall * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied. * @param cx a floating point number pointing the horizontal center of the zoom to be applied. This value should be between 0.0 and 1.0. * @param cy a floating point number pointing the vertical center of the zoom to be applied. This value should be between 0.0 and 1.0. - * + * @deprecated use linphone_call_zoom instead * cx and cy are updated in return in case their coordinates were too excentrated for the requested zoom factor. The zoom ensures that all the screen is fullfilled with the video. **/ LINPHONE_PUBLIC void linphone_call_zoom_video (LinphoneCall *call, float zoom_factor, float *cx, float *cy); +/** + * Perform a zoom of the video displayed during a call. + * The zoom ensures that all the screen is fullfilled with the video. + * @param call the call. + * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied. + * @param cx a floating point number pointing the horizontal center of the zoom to be applied. This value should be between 0.0 and 1.0. + * @param cy a floating point number pointing the vertical center of the zoom to be applied. This value should be between 0.0 and 1.0. +**/ +LINPHONE_PUBLIC void linphone_call_zoom (LinphoneCall *call, float zoom_factor, float cx, float cy); + /** * Send the specified dtmf. * diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index c6d722fae..3f1d13002 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -765,6 +765,10 @@ void linphone_call_zoom_video (LinphoneCall* call, float zoom_factor, float* cx, L_GET_CPP_PTR_FROM_C_OBJECT(call)->zoomVideo(zoom_factor, cx, cy); } +void linphone_call_zoom (LinphoneCall *call, float zoom_factor, float cx, float cy) { + L_GET_CPP_PTR_FROM_C_OBJECT(call)->zoomVideo(zoom_factor, cx, cy); +} + LinphoneStatus linphone_call_send_dtmf (LinphoneCall *call, char dtmf) { #if 0 if (!call){ diff --git a/src/call/call.cpp b/src/call/call.cpp index 1d3ded3e7..ea85c024d 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -315,6 +315,10 @@ LinphoneStatus Call::update (const MediaSessionParams *msp) { } void Call::zoomVideo (float zoomFactor, float *cx, float *cy) { + zoomVideo(zoomFactor, *cx, *cy); +} + +void Call::zoomVideo (float zoomFactor, float cx, float cy) { L_D(); static_cast(d->getActiveSession().get())->zoomVideo(zoomFactor, cx, cy); } diff --git a/src/call/call.h b/src/call/call.h index ee10154f8..a3d840c87 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -64,6 +64,7 @@ public: LinphoneStatus terminate (const LinphoneErrorInfo *ei = nullptr); LinphoneStatus update (const MediaSessionParams *msp = nullptr); void zoomVideo (float zoomFactor, float *cx, float *cy); + void zoomVideo (float zoomFactor, float cx, float cy); bool cameraEnabled () const; bool echoCancellationEnabled () const; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 524ecaab1..e51fc7069 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -4381,20 +4381,24 @@ LinphoneStatus MediaSession::takeVideoSnapshot (const string& file) { } void MediaSession::zoomVideo (float zoomFactor, float *cx, float *cy) { + zoomVideo(zoomFactor, *cx, *cy); +} + +void MediaSession::zoomVideo (float zoomFactor, float cx, float cy) { L_D(); if (d->videoStream && d->videoStream->output) { if (zoomFactor < 1) zoomFactor = 1; float halfsize = 0.5f * 1.0f / zoomFactor; - if ((*cx - halfsize) < 0) - *cx = 0 + halfsize; - if ((*cx + halfsize) > 1) - *cx = 1 - halfsize; - if ((*cy - halfsize) < 0) - *cy = 0 + halfsize; - if ((*cy + halfsize) > 1) - *cy = 1 - halfsize; - float zoom[3] = { zoomFactor, *cx, *cy }; + if ((cx - halfsize) < 0) + cx = 0 + halfsize; + if ((cx + halfsize) > 1) + cx = 1 - halfsize; + if ((cy - halfsize) < 0) + cy = 0 + halfsize; + if ((cy + halfsize) > 1) + cy = 1 - halfsize; + float zoom[3] = { zoomFactor, cx, cy }; ms_filter_call_method(d->videoStream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom); } else lWarning() << "Could not apply zoom: video output wasn't activated"; diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index af3a6c444..2ef160ab5 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -58,6 +58,7 @@ public: LinphoneStatus takePreviewSnapshot (const std::string& file); LinphoneStatus takeVideoSnapshot (const std::string& file); void zoomVideo (float zoomFactor, float *cx, float *cy); + void zoomVideo (float zoomFactor, float cx, float cy); bool cameraEnabled () const; bool echoCancellationEnabled () const; diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 2e83169b7..532e04f04 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -231,11 +231,12 @@ eval "$SED_START 's/getCountryName()/getCountry()/g' $SED_END" eval "$SED_START 's/getMSFactory()/getMediastreamerFactory()/g' $SED_END" eval "$SED_START 's/accountCreator.getPrefix(/org.linphone.core.Utils::getPrefixFromE164(/g' $SED_END" eval "$SED_START 's/proxyConfig.lookupCCCFromIso(/org.linphone.core.Utils::getCccFromIso(/g' $SED_END" +eval "$SED_START 's/linkPhoneNumberWithAccount()/linkAccount()/g' $SED_END" +eval "$SED_START 's/zoomVideo(/zoom(/g' $SED_END" #Changes in library required #Tunnel #LinphoneBuffer -#Call.zoomVideo() #AccountCreator.updatePassword #Android specifics not wrapped automatically From d64b2adf77a03450004adb491fc4c9fc47e19afc Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 17 Oct 2017 10:07:29 +0200 Subject: [PATCH 0512/2215] feat(EventLog): supports time --- include/linphone/api/c-event-log.h | 13 ++++++++++-- src/c-wrapper/api/c-event-log.cpp | 8 ++++++-- src/db/main-db.cpp | 10 +++++----- src/event-log/call-event.cpp | 5 +++-- src/event-log/call-event.h | 2 +- src/event-log/chat-message-event.cpp | 10 +++++++--- src/event-log/chat-message-event.h | 2 +- src/event-log/conference-event.cpp | 20 +++++++++++-------- src/event-log/conference-event.h | 4 ++-- .../conference-participant-device-event.cpp | 3 +++ .../conference-participant-device-event.h | 1 + .../conference-participant-event.cpp | 16 +++++++++++---- src/event-log/conference-participant-event.h | 2 ++ src/event-log/conference-subject-event.cpp | 9 ++++++--- src/event-log/conference-subject-event.h | 2 +- src/event-log/event-log-p.h | 3 ++- src/event-log/event-log.cpp | 3 ++- src/event-log/event-log.h | 5 ++++- 18 files changed, 81 insertions(+), 37 deletions(-) diff --git a/include/linphone/api/c-event-log.h b/include/linphone/api/c-event-log.h index f800373c5..9d71a30e5 100644 --- a/include/linphone/api/c-event-log.h +++ b/include/linphone/api/c-event-log.h @@ -33,12 +33,17 @@ LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_clone (const LinphoneEventL LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_ref (LinphoneEventLog *event_log); LINPHONE_PUBLIC LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *event_log); -LINPHONE_PUBLIC LinphoneCallEvent *linphone_call_event_new (LinphoneEventLogType type, LinphoneCall *call); +LINPHONE_PUBLIC LinphoneCallEvent *linphone_call_event_new ( + LinphoneEventLogType type, + time_t time, + LinphoneCall *call +); LINPHONE_PUBLIC LinphoneCallEvent *linphone_call_event_clone (const LinphoneCallEvent *call_event); LINPHONE_PUBLIC LinphoneCall *linphone_call_event_get_call (const LinphoneCallEvent *call_event); LINPHONE_PUBLIC LinphoneConferenceEvent *linphone_conference_event_new ( LinphoneEventLogType type, + time_t time, const LinphoneAddress *address ); LINPHONE_PUBLIC LinphoneConferenceEvent *linphone_conference_event_clone (const LinphoneConferenceEvent *conference_event); @@ -46,6 +51,7 @@ LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_event_get_address (co LINPHONE_PUBLIC LinphoneConferenceParticipantEvent *linphone_conference_participant_event_new ( LinphoneEventLogType type, + time_t time, const LinphoneAddress *conferenceAddress, const LinphoneAddress *participantAddress ); @@ -56,7 +62,10 @@ LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_participant_event_get const LinphoneConferenceParticipantEvent *conference_participant_event ); -LINPHONE_PUBLIC LinphoneChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage *chat_message); +LINPHONE_PUBLIC LinphoneChatMessageEvent *linphone_chat_message_event_new ( + LinphoneChatMessage *chat_message, + time_t time +); LINPHONE_PUBLIC LinphoneChatMessageEvent *linphone_chat_message_event_clone ( const LinphoneChatMessageEvent *chat_message_event ); diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 4737af3f5..77dd75244 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -62,12 +62,13 @@ LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *event_ // Call event. // ----------------------------------------------------------------------------- -LinphoneCallEvent *linphone_call_event_new (LinphoneEventLogType type, LinphoneCall *call) { +LinphoneCallEvent *linphone_call_event_new (LinphoneEventLogType type, time_t time, LinphoneCall *call) { LinphoneCallEvent *call_event = _linphone_CallEvent_init(); L_SET_CPP_PTR_FROM_C_OBJECT( call_event, new LinphonePrivate::CallEvent( static_cast(type), + time, L_GET_CPP_PTR_FROM_C_OBJECT(call) ) ); @@ -86,6 +87,7 @@ LinphoneCall *linphone_call_event_get_call (const LinphoneCallEvent *call_event) LinphoneConferenceEvent *linphone_conference_event_new ( LinphoneEventLogType type, + time_t time, const LinphoneAddress *address ) { // TODO. @@ -103,6 +105,7 @@ const LinphoneAddress *linphone_conference_event_get_address (const LinphoneConf LinphoneConferenceParticipantEvent *linphone_conference_participant_event_new ( LinphoneEventLogType type, + time_t time, const LinphoneAddress *conferenceAddress, const LinphoneAddress *participantAddress ) { @@ -121,11 +124,12 @@ const LinphoneAddress *linphone_conference_participant_event_get_participant_add // Message event. // ----------------------------------------------------------------------------- -LinphoneChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage *chat_message) { +LinphoneChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage *chat_message, time_t time) { LinphoneChatMessageEvent *chat_message_event = _linphone_ChatMessageEvent_init(); L_SET_CPP_PTR_FROM_C_OBJECT( chat_message_event, new LinphonePrivate::ChatMessageEvent( + time, L_GET_CPP_PTR_FROM_C_OBJECT(chat_message) ) ); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 5aa1bd04e..db0d2360c 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -519,19 +519,19 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return false; } - long &id = const_cast(eventLog).getPrivate()->id; - if (id < 0) + long &storageId = const_cast(eventLog).getPrivate()->storageId; + if (storageId < 0) return false; L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); - *session << "DELETE FROM event WHERE id = :id", soci::use(id); - id = -1; + *session << "DELETE FROM event WHERE id = :id", soci::use(storageId); + storageId = -1; L_END_LOG_EXCEPTION - return id == -1; + return storageId == -1; } void MainDb::cleanEvents (FilterMask mask) { diff --git a/src/event-log/call-event.cpp b/src/event-log/call-event.cpp index f98d7fad1..b434bbff2 100644 --- a/src/event-log/call-event.cpp +++ b/src/event-log/call-event.cpp @@ -33,14 +33,15 @@ public: // ----------------------------------------------------------------------------- -CallEvent::CallEvent (Type type, const shared_ptr &call) : EventLog(*new CallEventPrivate, type) { +CallEvent::CallEvent (Type type, const time_t &time, const shared_ptr &call) : + EventLog(*new CallEventPrivate, type, time) { L_D(); L_ASSERT(call); L_ASSERT(type == Type::CallStart || type == Type::CallEnd); d->call = call; } -CallEvent::CallEvent (const CallEvent &src) : CallEvent(src.getType(), src.getCall()) {} +CallEvent::CallEvent (const CallEvent &src) : CallEvent(src.getType(), src.getTime(), src.getCall()) {} CallEvent &CallEvent::operator= (const CallEvent &src) { L_D(); diff --git a/src/event-log/call-event.h b/src/event-log/call-event.h index 512d891c2..5bc348f47 100644 --- a/src/event-log/call-event.h +++ b/src/event-log/call-event.h @@ -33,7 +33,7 @@ class CallEventPrivate; class LINPHONE_PUBLIC CallEvent : public EventLog { public: - CallEvent (Type type, const std::shared_ptr &message); + CallEvent (Type type, const std::time_t &time, const std::shared_ptr &message); CallEvent (const CallEvent &src); CallEvent &operator= (const CallEvent &src); diff --git a/src/event-log/chat-message-event.cpp b/src/event-log/chat-message-event.cpp index 6305413ea..e6a796d93 100644 --- a/src/event-log/chat-message-event.cpp +++ b/src/event-log/chat-message-event.cpp @@ -33,14 +33,18 @@ public: // ----------------------------------------------------------------------------- -ChatMessageEvent::ChatMessageEvent (const shared_ptr &chatMessage) : - EventLog(*new ChatMessageEventPrivate, EventLog::Type::ChatMessage) { +ChatMessageEvent::ChatMessageEvent ( + const time_t &time, + const shared_ptr &chatMessage +) : EventLog(*new ChatMessageEventPrivate, EventLog::Type::ChatMessage, time) { L_D(); L_ASSERT(chatMessage); d->chatMessage = chatMessage; } -ChatMessageEvent::ChatMessageEvent (const ChatMessageEvent &src) : ChatMessageEvent(src.getChatMessage()) {} +ChatMessageEvent::ChatMessageEvent ( + const ChatMessageEvent &src +) : ChatMessageEvent(src.getTime(), src.getChatMessage()) {} ChatMessageEvent &ChatMessageEvent::operator= (const ChatMessageEvent &src) { L_D(); diff --git a/src/event-log/chat-message-event.h b/src/event-log/chat-message-event.h index 91764665c..a9a3c7e76 100644 --- a/src/event-log/chat-message-event.h +++ b/src/event-log/chat-message-event.h @@ -33,7 +33,7 @@ class ChatMessageEventPrivate; class LINPHONE_PUBLIC ChatMessageEvent : public EventLog { public: - ChatMessageEvent (const std::shared_ptr &chatMessage); + ChatMessageEvent (const std::time_t &time, const std::shared_ptr &chatMessage); ChatMessageEvent (const ChatMessageEvent &src); ChatMessageEvent &operator= (const ChatMessageEvent &src); diff --git a/src/event-log/conference-event.cpp b/src/event-log/conference-event.cpp index b6f4e67e3..50311782b 100644 --- a/src/event-log/conference-event.cpp +++ b/src/event-log/conference-event.cpp @@ -26,21 +26,25 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ConferenceEvent::ConferenceEvent (Type type, const Address &conferenceAddress) : - EventLog(*new ConferenceEventPrivate, type) { +ConferenceEvent::ConferenceEvent (Type type, const time_t &time, const Address &conferenceAddress) : + EventLog(*new ConferenceEventPrivate, type, time) { L_D(); L_ASSERT(type == Type::ConferenceCreated || type == Type::ConferenceDestroyed); d->conferenceAddress = conferenceAddress; } ConferenceEvent::ConferenceEvent (const ConferenceEvent &src) : - ConferenceEvent(src.getType(), src.getConferenceAddress()) {} + ConferenceEvent(src.getType(), src.getTime(), src.getConferenceAddress()) {} -ConferenceEvent::ConferenceEvent (ConferenceEventPrivate &p, Type type, const Address &conferenceAddress) : - EventLog(p, type) { - L_D(); - d->conferenceAddress = conferenceAddress; - } +ConferenceEvent::ConferenceEvent ( + ConferenceEventPrivate &p, + Type type, + const time_t &time, + const Address &conferenceAddress +) : EventLog(p, type, time) { + L_D(); + d->conferenceAddress = conferenceAddress; +} ConferenceEvent &ConferenceEvent::operator= (const ConferenceEvent &src) { L_D(); diff --git a/src/event-log/conference-event.h b/src/event-log/conference-event.h index ff1e93439..dbd2391ab 100644 --- a/src/event-log/conference-event.h +++ b/src/event-log/conference-event.h @@ -31,7 +31,7 @@ class ConferenceEventPrivate; class LINPHONE_PUBLIC ConferenceEvent : public EventLog { public: - ConferenceEvent (Type type, const Address &conferenceAddress); + ConferenceEvent (Type type, const std::time_t &time, const Address &conferenceAddress); ConferenceEvent (const ConferenceEvent &src); ConferenceEvent &operator= (const ConferenceEvent &src); @@ -39,7 +39,7 @@ public: const Address &getConferenceAddress () const; protected: - ConferenceEvent (ConferenceEventPrivate &p, Type type, const Address &conferenceAddress); + ConferenceEvent (ConferenceEventPrivate &p, Type type, const std::time_t &time, const Address &conferenceAddress); private: L_DECLARE_PRIVATE(ConferenceEvent); diff --git a/src/event-log/conference-participant-device-event.cpp b/src/event-log/conference-participant-device-event.cpp index ce1ffbe9a..fa0334f89 100644 --- a/src/event-log/conference-participant-device-event.cpp +++ b/src/event-log/conference-participant-device-event.cpp @@ -35,12 +35,14 @@ public: ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent ( Type type, + const time_t &time, const Address &conferenceAddress, const Address &participantAddress, const Address &gruuAddress ) : ConferenceParticipantEvent( *new ConferenceParticipantDeviceEventPrivate, type, + time, conferenceAddress, participantAddress ) { @@ -55,6 +57,7 @@ ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent ( ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent (const ConferenceParticipantDeviceEvent &src) : ConferenceParticipantDeviceEvent( src.getType(), + src.getTime(), src.getConferenceAddress(), src.getParticipantAddress(), src.getGruuAddress() diff --git a/src/event-log/conference-participant-device-event.h b/src/event-log/conference-participant-device-event.h index b30f86903..4fcf4fa8d 100644 --- a/src/event-log/conference-participant-device-event.h +++ b/src/event-log/conference-participant-device-event.h @@ -32,6 +32,7 @@ class LINPHONE_PUBLIC ConferenceParticipantDeviceEvent : public ConferencePartic public: ConferenceParticipantDeviceEvent ( Type type, + const std::time_t &time, const Address &conferenceAddress, const Address &participantAddress, const Address &gruuAddress diff --git a/src/event-log/conference-participant-event.cpp b/src/event-log/conference-participant-event.cpp index 00f591b4e..e58b668a2 100644 --- a/src/event-log/conference-participant-event.cpp +++ b/src/event-log/conference-participant-event.cpp @@ -29,9 +29,10 @@ LINPHONE_BEGIN_NAMESPACE ConferenceParticipantEvent::ConferenceParticipantEvent ( Type type, + const time_t &time, const Address &conferenceAddress, const Address &participantAddress -) : ConferenceEvent(*new ConferenceParticipantEventPrivate, type, conferenceAddress) { +) : ConferenceEvent(*new ConferenceParticipantEventPrivate, type, time, conferenceAddress) { L_D(); L_ASSERT( type == Type::ConferenceParticipantAdded || @@ -42,15 +43,22 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( d->participantAddress = participantAddress; } -ConferenceParticipantEvent::ConferenceParticipantEvent (const ConferenceParticipantEvent &src) : - ConferenceParticipantEvent(src.getType(), src.getConferenceAddress(), src.getParticipantAddress()) {} +ConferenceParticipantEvent::ConferenceParticipantEvent ( + const ConferenceParticipantEvent &src +) : ConferenceParticipantEvent( + src.getType(), + src.getTime(), + src.getConferenceAddress(), + src.getParticipantAddress() +) {} ConferenceParticipantEvent::ConferenceParticipantEvent ( ConferenceParticipantEventPrivate &p, Type type, + const time_t &time, const Address &conferenceAddress, const Address &participantAddress -) : ConferenceEvent(p, type, conferenceAddress) { +) : ConferenceEvent(p, type, time, conferenceAddress) { L_D(); d->participantAddress = participantAddress; } diff --git a/src/event-log/conference-participant-event.h b/src/event-log/conference-participant-event.h index 97f7e2eb0..69b5416db 100644 --- a/src/event-log/conference-participant-event.h +++ b/src/event-log/conference-participant-event.h @@ -32,6 +32,7 @@ class LINPHONE_PUBLIC ConferenceParticipantEvent : public ConferenceEvent { public: ConferenceParticipantEvent ( Type type, + const std::time_t &time, const Address &conferenceAddress, const Address &participantAddress ); @@ -45,6 +46,7 @@ protected: ConferenceParticipantEvent ( ConferenceParticipantEventPrivate &p, Type type, + const std::time_t &time, const Address &conferenceAddress, const Address &participantAddress ); diff --git a/src/event-log/conference-subject-event.cpp b/src/event-log/conference-subject-event.cpp index 2cb6c9889..492f6bcf4 100644 --- a/src/event-log/conference-subject-event.cpp +++ b/src/event-log/conference-subject-event.cpp @@ -33,14 +33,17 @@ public: // ----------------------------------------------------------------------------- -ConferenceSubjectEvent::ConferenceSubjectEvent (const Address &address, const string &subject) : - ConferenceEvent(*new ConferenceSubjectEventPrivate, Type::ConferenceSubjectChanged, address) { +ConferenceSubjectEvent::ConferenceSubjectEvent ( + const time_t &time, + const Address &address, + const string &subject +) : ConferenceEvent(*new ConferenceSubjectEventPrivate, Type::ConferenceSubjectChanged, time, address) { L_D(); d->subject = subject; } ConferenceSubjectEvent::ConferenceSubjectEvent (const ConferenceSubjectEvent &src) : - ConferenceSubjectEvent(src.getConferenceAddress(), src.getSubject()) {} + ConferenceSubjectEvent(src.getTime(), src.getConferenceAddress(), src.getSubject()) {} ConferenceSubjectEvent &ConferenceSubjectEvent::operator= (const ConferenceSubjectEvent &src) { L_D(); diff --git a/src/event-log/conference-subject-event.h b/src/event-log/conference-subject-event.h index efb4e49f4..a145b3fbd 100644 --- a/src/event-log/conference-subject-event.h +++ b/src/event-log/conference-subject-event.h @@ -30,7 +30,7 @@ class ConferenceSubjectEventPrivate; class LINPHONE_PUBLIC ConferenceSubjectEvent : public ConferenceEvent { public: - ConferenceSubjectEvent (const Address &conferenceAddress, const std::string &subject); + ConferenceSubjectEvent (const std::time_t &time, const Address &conferenceAddress, const std::string &subject); ConferenceSubjectEvent (const ConferenceSubjectEvent &src); ConferenceSubjectEvent &operator= (const ConferenceSubjectEvent &src); diff --git a/src/event-log/event-log-p.h b/src/event-log/event-log-p.h index 7e7a7788b..5732a56cc 100644 --- a/src/event-log/event-log-p.h +++ b/src/event-log/event-log-p.h @@ -29,10 +29,11 @@ LINPHONE_BEGIN_NAMESPACE class EventLogPrivate : public ClonableObjectPrivate { public: - long id = -1; + long storageId = -1; private: EventLog::Type type = EventLog::Type::None; + std::time_t time = -1; L_DECLARE_PUBLIC(EventLog); }; diff --git a/src/event-log/event-log.cpp b/src/event-log/event-log.cpp index 25b73953c..490334426 100644 --- a/src/event-log/event-log.cpp +++ b/src/event-log/event-log.cpp @@ -27,9 +27,10 @@ EventLog::EventLog () : ClonableObject(*new EventLogPrivate) {} EventLog::EventLog (const EventLog &) : ClonableObject(*new EventLogPrivate) {} -EventLog::EventLog (EventLogPrivate &p, Type type) : ClonableObject(*new EventLogPrivate) { +EventLog::EventLog (EventLogPrivate &p, Type type, const time_t &time) : ClonableObject(*new EventLogPrivate) { L_D(); d->type = type; + d->time = time; } EventLog &EventLog::operator= (const EventLog &src) { diff --git a/src/event-log/event-log.h b/src/event-log/event-log.h index 057c141e6..4d3cba931 100644 --- a/src/event-log/event-log.h +++ b/src/event-log/event-log.h @@ -20,6 +20,8 @@ #ifndef _EVENT_LOG_H_ #define _EVENT_LOG_H_ +#include + #include "linphone/enums/event-log-enums.h" #include "linphone/utils/enum-generator.h" @@ -43,9 +45,10 @@ public: EventLog &operator= (const EventLog &src); Type getType () const; + std::time_t getTime () const; protected: - EventLog (EventLogPrivate &p, Type type); + EventLog (EventLogPrivate &p, Type type, const std::time_t &time); private: L_DECLARE_PRIVATE(EventLog); From a0b59e43cdc35884603fe0331136a522b32bedf6 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 17 Oct 2017 10:16:00 +0200 Subject: [PATCH 0513/2215] feat(MainDbPrivate): add one insertConferenceEvent method --- src/db/main-db-p.h | 6 ++++++ src/db/main-db.cpp | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index cec8344a1..6e33241b3 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -43,6 +43,10 @@ class MainDbPrivate : public AbstractDbPrivate { public: private: + // --------------------------------------------------------------------------- + // Low level API. + // --------------------------------------------------------------------------- + long insertSipAddress (const std::string &sipAddress); void insertContent (long messageEventId, const Content &content); long insertContentType (const std::string &contentType); @@ -61,6 +65,8 @@ private: void insertMessageParticipant (long messageEventId, long sipAddressId, ChatMessage::State state); + void insertConferenceEvent (long eventId, long chatRoomId); + std::unordered_map> chatRooms; L_DECLARE_PUBLIC(MainDb); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index db0d2360c..4a085a0a2 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -236,6 +236,12 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} soci::use(messageEventId), soci::use(sipAddressId), soci::use(static_cast(state)); } + void MainDbPrivate::insertConferenceEvent (long eventId, long chatRoomId) { + soci::session *session = dbSession.getBackendSession(); + *session << "INSERT INTO conference_event (event_id, chat_room_id) VALUES (:eventId, :chatRoomId)", + soci::use(eventId), soci::use(chatRoomId); + } + // ----------------------------------------------------------------------------- #define LEGACY_MESSAGE_COL_LOCAL_ADDRESS 1 From 82f3d21b3f443c5c6c1658551f06b0193d964f0e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 17 Oct 2017 10:18:56 +0200 Subject: [PATCH 0514/2215] Added an option on Java wrapper for exceptions, default to false temporarily --- wrappers/java/genwrapper.py | 13 +++++++++---- wrappers/java/java_class.mustache | 4 ++-- wrappers/java/java_enum.mustache | 4 ++-- wrappers/java/migration.sh | 6 ++---- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 1a295e4d9..3e8810a34 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -68,7 +68,8 @@ ENUMS_LIST = { ########################################################################## class JavaTranslator(object): - def __init__(self, packageName): + def __init__(self, packageName, exceptions): + self.exceptions = exceptions package_dirs = packageName.split('.') self.jni_package = '' self.jni_path = '' @@ -79,6 +80,8 @@ class JavaTranslator(object): self.docTranslator = metadoc.SandcastleJavaTranslator() def throws_exception(self, _type): + if not self.exceptions: + return False if type(_type) is AbsApi.BaseType: if _type.name == 'status': return True @@ -716,10 +719,11 @@ class Jni(object): ########################################################################## class GenWrapper(object): - def __init__(self, srcdir, javadir, package, xmldir): + def __init__(self, srcdir, javadir, package, xmldir, exceptions): self.srcdir = srcdir self.javadir = javadir self.package = package + self.exceptions = exceptions project = CApi.Project() project.initFromDir(xmldir) @@ -734,7 +738,7 @@ class GenWrapper(object): 'linphone_call_zoom_video',\ 'linphone_config_get_range'] self.parser.parse_all() - self.translator = JavaTranslator(package) + self.translator = JavaTranslator(package, exceptions) self.renderer = pystache.Renderer() self.jni = Jni(package) @@ -820,6 +824,7 @@ def main(): argparser.add_argument('-o --output', type=str, help='the directory where to generate the source files', dest='outputdir', default='.') argparser.add_argument('-p --package', type=str, help='the package name for the wrapper', dest='package', default='org.linphone.core') argparser.add_argument('-n --name', type=str, help='the name of the genarated source file', dest='name', default='linphone_jni.cc') + argparser.add_argument('-e --exceptions', type=bool, help='enable the wrapping of LinphoneStatus into CoreException', dest='exceptions', default=False) args = argparser.parse_args() srcdir = args.outputdir + '/src' @@ -842,7 +847,7 @@ def main(): print("Cannot create '{0}' dircetory: {1}".format(javadir, e.strerror)) sys.exit(1) - genwrapper = GenWrapper(srcdir, javadir, args.package, args.xmldir) + genwrapper = GenWrapper(srcdir, javadir, args.package, args.xmldir, args.exceptions) genwrapper.render_all() if __name__ == '__main__': diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index b5c75362e..66e337f9e 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -63,13 +63,13 @@ public {{#isLinphoneFactory}}abstract class{{/isLinphoneFactory}}{{#isNotLinphon mValue = value; } - static public {{className}} fromInt(int value) throws CoreException { + static public {{className}} fromInt(int value) throws RuntimeException { switch(value) { {{#values}} case {{value}}: return {{name}}; {{/values}} default: - throw new CoreException("Unhandled enum value " + value + " for {{className}}"); + throw new RuntimeException("Unhandled enum value " + value + " for {{className}}"); } } diff --git a/wrappers/java/java_enum.mustache b/wrappers/java/java_enum.mustache index c2a38237d..6276d6dc0 100644 --- a/wrappers/java/java_enum.mustache +++ b/wrappers/java/java_enum.mustache @@ -48,13 +48,13 @@ public enum {{className}} { mValue = value; } - static public {{className}} fromInt(int value) throws CoreException { + static public {{className}} fromInt(int value) throws RuntimeException { switch(value) { {{#values}} case {{value}}: return {{name}}; {{/values}} default: - throw new CoreException("Unhandled enum value " + value + " for {{className}}"); + throw new RuntimeException("Unhandled enum value " + value + " for {{className}}"); } } diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 532e04f04..201445415 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -196,6 +196,8 @@ eval "$SED_START 's/getIncomingTimeout/getIncTimeout/g' $SED_END" eval "$SED_START 's/setIncomingTimeout/setIncTimeout/g' $SED_END" eval "$SED_START 's/migrateCallLogs()/migrateLogsFromRcToDb()/g' $SED_END" eval "$SED_START 's/setRLSUri/setRlsUri/g' $SED_END" +eval "$SED_START 's/hasCrappyOpenGL(/hasCrappyOpenGl(/g' $SED_END" +eval "$SED_START 's/needsEchoCalibration(/isEchoCancellerCalibrationRequired(/g' $SED_END" # Removed methods eval "$SED_START 's/.isRegistered()/.getState() == RegistrationState.Ok/g' $SED_END" @@ -240,11 +242,7 @@ eval "$SED_START 's/zoomVideo(/zoom(/g' $SED_END" #AccountCreator.updatePassword #Android specifics not wrapped automatically -#Core.needsEchoCalibration() -#Core.hasCrappyOpenGL() #Core.startEchoCalibration -#Core.startEchoTester -#Core.stopEchoTester # For the payloads, get the list from the Core, call the method on the object directly and set it back if required #Core.enablePayloadType() From 035ccdf0786eb2c95767b5fc266d12b2f77f2522 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 17 Oct 2017 10:23:55 +0200 Subject: [PATCH 0515/2215] Fixed issue with use of Utils class in java migration script --- wrappers/java/migration.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 201445415..70b7ae3c0 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -8,6 +8,7 @@ eval "$SED_START 's/import org.linphone.tools/import org.linphone.core.tools/g' eval "$SED_START 's/import org.linphone.core.OpenH264DownloadHelperListener/import org.linphone.core.tools.OpenH264DownloadHelperListener/g' $SED_END" # Listeners +eval "$SED_START 's/LinphoneAccountCreator.AccountCreatorListener/AccountCreatorListener/g' $SED_END" eval "$SED_START 's/AccountCreator.AccountCreatorListener/AccountCreatorListener/g' $SED_END" eval "$SED_START 's/LinphoneCoreListenerBase/CoreListenerStub/g' $SED_END" eval "$SED_START 's/LinphoneCoreListener/CoreListener/g' $SED_END" @@ -231,8 +232,8 @@ eval "$SED_START 's/mLc.destroy()/mLc = null/g' $SED_END" eval "$SED_START 's/getAllDialPlan()/getDialPlans()/g' $SED_END" eval "$SED_START 's/getCountryName()/getCountry()/g' $SED_END" eval "$SED_START 's/getMSFactory()/getMediastreamerFactory()/g' $SED_END" -eval "$SED_START 's/accountCreator.getPrefix(/org.linphone.core.Utils::getPrefixFromE164(/g' $SED_END" -eval "$SED_START 's/proxyConfig.lookupCCCFromIso(/org.linphone.core.Utils::getCccFromIso(/g' $SED_END" +eval "$SED_START 's/accountCreator.getPrefix(/org.linphone.core.Utils.getPrefixFromE164(/g' $SED_END" +eval "$SED_START 's/proxyConfig.lookupCCCFromIso(/org.linphone.core.Utils.getCccFromIso(/g' $SED_END" eval "$SED_START 's/linkPhoneNumberWithAccount()/linkAccount()/g' $SED_END" eval "$SED_START 's/zoomVideo(/zoom(/g' $SED_END" From b5176b5125671157c0d98c46a142c5bed9fcc9ee Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 17 Oct 2017 10:31:45 +0200 Subject: [PATCH 0516/2215] Removed throws Exception in java wrapper when returning an enum --- wrappers/java/java_class.mustache | 6 +++--- wrappers/java/migration.sh | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 66e337f9e..afe0d173c 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -110,7 +110,7 @@ public {{#isLinphoneFactory}}abstract class{{/isLinphoneFactory}}{{#isNotLinphon */ {{/doc}} {{#deprecated}}@Deprecated - {{/deprecated}}{{#isLinphoneFactory}}abstract {{/isLinphoneFactory}}public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}}{{#enumCast}} throws CoreException{{/enumCast}}; + {{/deprecated}}{{#isLinphoneFactory}}abstract {{/isLinphoneFactory}}public {{return}} {{name}}({{params}}); {{/methods}} /** @@ -132,7 +132,7 @@ public {{#isLinphoneFactory}}abstract class{{/isLinphoneFactory}}{{#isNotLinphon {{/lines}} */ {{/doc}} - public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}}{{#enumCast}} throws CoreException{{/enumCast}}; + public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}}; {{/staticMethods}} {{/isNotLinphoneFactory}} @@ -181,7 +181,7 @@ class {{classImplName}} {{#isLinphoneFactory}}extends{{/isLinphoneFactory}}{{#is {{#methods}} private native {{return_native}} {{name}}({{native_params}}); @Override - public {{return}} {{name}}({{params}}) {{#exception}}throws CoreException{{/exception}}{{#enumCast}}throws CoreException{{/enumCast}} { + public {{return}} {{name}}({{params}}) {{#exception}}throws CoreException{{/exception}} { {{#exception}}int exceptionResult = {{/exception}}{{return_keyword}}{{#enumCast}}{{return}}.fromInt({{/enumCast}}{{#classCast}}({{return}}){{/classCast}}{{name}}(nativePtr{{native_params_impl}}){{#enumCast}}){{/enumCast}};{{#exception}} if (exceptionResult != 0) throw new CoreException("{{name}} returned value " + exceptionResult);{{/exception}} } diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 70b7ae3c0..49febcfa8 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -8,8 +8,8 @@ eval "$SED_START 's/import org.linphone.tools/import org.linphone.core.tools/g' eval "$SED_START 's/import org.linphone.core.OpenH264DownloadHelperListener/import org.linphone.core.tools.OpenH264DownloadHelperListener/g' $SED_END" # Listeners -eval "$SED_START 's/LinphoneAccountCreator.AccountCreatorListener/AccountCreatorListener/g' $SED_END" -eval "$SED_START 's/AccountCreator.AccountCreatorListener/AccountCreatorListener/g' $SED_END" +eval "$SED_START 's/LinphoneAccountCreator.LinphoneAccountCreatorListener/AccountCreatorListener/g' $SED_END" +eval "$SED_START 's/AccountCreator.LinphoneAccountCreatorListener/AccountCreatorListener/g' $SED_END" eval "$SED_START 's/LinphoneCoreListenerBase/CoreListenerStub/g' $SED_END" eval "$SED_START 's/LinphoneCoreListener/CoreListener/g' $SED_END" eval "$SED_START 's/LinphoneChatMessage.LinphoneChatMessageListener/ChatMessageListener/g' $SED_END" From e0687317146ccf147709c3070794db11ac784e45 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 17 Oct 2017 11:18:31 +0200 Subject: [PATCH 0517/2215] More work on migration script for Java wrapper --- wrappers/java/migration.sh | 61 +++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 49febcfa8..6a8eaa29e 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -105,9 +105,67 @@ eval "$SED_START 's/LinphoneVcard/Vcard/g' $SED_END" eval "$SED_START 's/LinphoneXmlRpc/XmlRpc/g' $SED_END" # Callbacks +# # Account creator +eval "$SED_START 's/onAccountCreatorIsAccountUsed/onIsAccountExist/g' $SED_END" +eval "$SED_START 's/onAccountCreatorAccountCreated/onCreateAccount/g' $SED_END" +eval "$SED_START 's/onAccountCreatorAccountActivated/onActivateAccount/g' $SED_END" +eval "$SED_START 's/onAccountCreatorAccountLinkedWithPhoneNumber/onLinkAccount/g' $SED_END" +eval "$SED_START 's/onAccountCreatorPhoneNumberLinkActivated/onActivateAlias/g' $SED_END" +eval "$SED_START 's/onAccountCreatorIsAccountActivated/onIsAccountActivated/g' $SED_END" +eval "$SED_START 's/onAccountCreatorPhoneAccountRecovered/onRecoverAccount/g' $SED_END" +eval "$SED_START 's/onAccountCreatorIsAccountLinked/onIsAccountLinked/g' $SED_END" +eval "$SED_START 's/onAccountCreatorIsPhoneNumberUsed/onIsAliasUsed/g' $SED_END" +eval "$SED_START 's/onAccountCreatorPasswordUpdated/onUpdateAccount/g' $SED_END" + +# # Chat message eval "$SED_START 's/onChatMessageStateChanged/onMsgStateChanged/g' $SED_END" eval "$SED_START 's/onChatMessageFileTransferProgressChanged/onFileTransferProgressIndication/g' $SED_END" +#eval "$SED_START 's/onChatMessageFileTransferSent//g' $SED_END" +#eval "$SED_START 's/onChatMessageFileTransferReceived//g' $SED_END" + +# # Core +eval "$SED_START 's/authInfoRequested/removed/g' $SED_END" # Removed +eval "$SED_START 's/show(Core/removed/g' $SED_END" # Removed +eval "$SED_START 's/displayStatus/removed/g' $SED_END" # Removed +eval "$SED_START 's/displayMessage/removed/g' $SED_END" # Removed +eval "$SED_START 's/displayWarning/removed/g' $SED_END" # Removed +eval "$SED_START 's/fileTransferProgressIndication/removed/g' $SED_END" # Removed +eval "$SED_START 's/fileTransferRecv/removed/g' $SED_END" # Removed +eval "$SED_START 's/fileTransferSend/removed/g' $SED_END" # Removed +eval "$SED_START 's/notifyReceived(Core lc, Event/onNotifyReceived(Core lc, Event/g' $SED_END" +eval "$SED_START 's/notifyReceived/removed/g' $SED_END" # Removed +#eval "$SED_START 's/ecCalibrationStatus//g' $SED_END" +eval "$SED_START 's/publishStateChanged/onPublishStateChanged/g' $SED_END" # Removed +eval "$SED_START 's/callStatsUpdated/onCallStatsUpdated/g' $SED_END" +eval "$SED_START 's/authenticationRequested/onAuthenticationRequested/g' $SED_END" +eval "$SED_START 's/newSubscriptionRequest/onNewSubscriptionRequested/g' $SED_END" +eval "$SED_START 's/notifyPresenceReceived/onNotifyPresenceReceived/g' $SED_END" +eval "$SED_START 's/dtmfReceived/onDtmfReceived/g' $SED_END" +eval "$SED_START 's/transferState/onTransferStateChanged/g' $SED_END" +eval "$SED_START 's/infoReceived/onInfoReceived/g' $SED_END" +eval "$SED_START 's/subscriptionStateChanged/onSubscriptionStateChanged/g' $SED_END" +eval "$SED_START 's/globalState/onGlobalStateChanged/g' $SED_END" eval "$SED_START 's/registrationState/onRegistrationStateChanged/g' $SED_END" +eval "$SED_START 's/configuringStatus/onConfiguringStatus/g' $SED_END" +eval "$SED_START 's/messageReceived/onMessageReceived/g' $SED_END" +eval "$SED_START 's/messageReceivedUnableToDecrypted//g' $SED_END" +eval "$SED_START 's/callState/onCallStateChanged/g' $SED_END" +eval "$SED_START 's/callEncryptionChanged/onCallEncryptionChanged/g' $SED_END" +eval "$SED_START 's/isComposingReceived/onIsComposingReceived/g' $SED_END" +eval "$SED_START 's/uploadProgressIndication/onLogCollectionUploadProgressIndication/g' $SED_END" +eval "$SED_START 's/uploadStateChanged/onLogCollectionUploadStateChanged/g' $SED_END" +eval "$SED_START 's/friendListCreated/onFriendListCreated/g' $SED_END" +eval "$SED_START 's/friendListRemoved/onFriendListRemoved/g' $SED_END" +eval "$SED_START 's/networkReachableChanged/onNetworkReachable/g' $SED_END" + +# # Friend list +eval "$SED_START 's/onFriendCreated/onContactCreated/g' $SED_END" +eval "$SED_START 's/onFriendUpdated/onContactUpdated/g' $SED_END" +eval "$SED_START 's/onFriendDeleted/onContactDeleted/g' $SED_END" +eval "$SED_START 's/onFriendSyncStatusChanged/onSyncStatusChanged/g' $SED_END" + +# # XmlRpc request +eval "$SED_START 's/onXmlRpcRequestResponse/onResponse/g' $SED_END" # Methods eval "$SED_START 's/getFriendsLists()/getFriends()/g' $SED_END" @@ -183,7 +241,7 @@ eval "$SED_START 's/clearAuthInfos()/clearAllAuthInfo()/g' $SED_END" eval "$SED_START 's/clearProxyConfigs()/clearProxyConfig()/g' $SED_END" eval "$SED_START 's/isVideoSupported()/videoSupported()/g' $SED_END" eval "$SED_START 's/VideoDefinition().toDisplayableString()/VideoDefinition().getName()/g' $SED_END" -eval "$SED_START 's/isAccountUsed/isAccountExist()/g' $SED_END" +eval "$SED_START 's/isAccountUsed()/isAccountExist()/g' $SED_END" eval "$SED_START 's/loadXmlFile(/loadFromXmlFile(/g' $SED_END" eval "$SED_START 's/activatePhoneNumberLink()/activateAlias()/g' $SED_END" eval "$SED_START 's/isPhoneNumberUsed()/isAliasUsed()/g' $SED_END" @@ -199,6 +257,7 @@ eval "$SED_START 's/migrateCallLogs()/migrateLogsFromRcToDb()/g' $SED_END" eval "$SED_START 's/setRLSUri/setRlsUri/g' $SED_END" eval "$SED_START 's/hasCrappyOpenGL(/hasCrappyOpenGl(/g' $SED_END" eval "$SED_START 's/needsEchoCalibration(/isEchoCancellerCalibrationRequired(/g' $SED_END" +eval "$SED_START 's//getCountryCode()/getCountryCallingCode()/g' $SED_END" # Removed methods eval "$SED_START 's/.isRegistered()/.getState() == RegistrationState.Ok/g' $SED_END" From 03691826734dec33c3487a31ccdf7d451c13844a Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 17 Oct 2017 12:04:45 +0200 Subject: [PATCH 0518/2215] feat(MainDb): register conference participant event --- src/db/main-db-p.h | 19 ++++++---- src/db/main-db.cpp | 92 +++++++++++++++++++++++++++++++++------------ src/utils/utils.cpp | 8 ++-- 3 files changed, 85 insertions(+), 34 deletions(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 6e33241b3..882ac9dff 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -21,7 +21,6 @@ #define _MAIN_DB_P_H_ #include "abstract/abstract-db-p.h" -#include "chat/chat-message/chat-message.h" #include "event-log/event-log.h" #include "main-db.h" @@ -29,7 +28,6 @@ LINPHONE_BEGIN_NAMESPACE -class ChatRoom; class Content; struct MessageEventReferences { @@ -56,18 +54,25 @@ private: long insertMessageEvent ( const MessageEventReferences &references, - ChatMessage::State state, - ChatMessage::Direction direction, + int state, + int direction, const std::string &imdnMessageId, bool isSecured, const std::list &contents ); - void insertMessageParticipant (long messageEventId, long sipAddressId, ChatMessage::State state); + void insertMessageParticipant (long messageEventId, long sipAddressId, int state); - void insertConferenceEvent (long eventId, long chatRoomId); + // --------------------------------------------------------------------------- + // Events API. + // --------------------------------------------------------------------------- - std::unordered_map> chatRooms; + long insertEvent (const EventLog &eventLog); + long insertMessageEvent (const EventLog &eventLog); + long insertConferenceEvent (const EventLog &eventLog); + long insertConferenceParticipantEvent (const EventLog &eventLog); + long insertConferenceParticipantDeviceEvent (const EventLog &eventLog); + long insertConferenceSubjectEvent (const EventLog &eventLog); L_DECLARE_PUBLIC(MainDb); }; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 4a085a0a2..e639465f1 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -33,6 +33,8 @@ #include "db/session/db-session-provider.h" #include "event-log/call-event.h" #include "event-log/chat-message-event.h" +#include "event-log/conference-participant-device-event.h" +#include "event-log/conference-subject-event.h" #include "event-log/event-log-p.h" #include "logger/logger.h" #include "main-db-p.h" @@ -195,8 +197,8 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} long MainDbPrivate::insertMessageEvent ( const MessageEventReferences &references, - ChatMessage::State state, - ChatMessage::Direction direction, + int state, + int direction, const string &imdnMessageId, bool isSecured, const list &contents @@ -211,8 +213,8 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} " :eventId, :chatRoomId, :localSipaddressId, :remoteSipaddressId," " :state, :direction, :imdnMessageId, :isSecured" ")", soci::use(references.eventId), soci::use(references.chatRoomId), soci::use(references.localSipAddressId), - soci::use(references.remoteSipAddressId), soci::use(static_cast(state)), - soci::use(static_cast(direction)), soci::use(imdnMessageId), soci::use(isSecured ? 1 : 0); + soci::use(references.remoteSipAddressId), soci::use(state), soci::use(direction), + soci::use(imdnMessageId), soci::use(isSecured ? 1 : 0); long messageEventId = q->getLastInsertId(); @@ -222,24 +224,58 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return messageEventId; } - void MainDbPrivate::insertMessageParticipant (long messageEventId, long sipAddressId, ChatMessage::State state) { + void MainDbPrivate::insertMessageParticipant (long messageEventId, long sipAddressId, int state) { soci::session *session = dbSession.getBackendSession(); soci::statement statement = ( session->prepare << "UPDATE message_participant SET state = :state" " WHERE message_event_id = :messageEventId AND sip_address_id = :sipAddressId", - soci::use(static_cast(state)), soci::use(messageEventId), soci::use(sipAddressId) + soci::use(state), soci::use(messageEventId), soci::use(sipAddressId) ); statement.execute(true); - if (statement.get_affected_rows() == 0 && state != ChatMessage::State::Displayed) + if (statement.get_affected_rows() == 0 && state != static_cast(ChatMessage::State::Displayed)) *session << "INSERT INTO message_participant (message_event_id, sip_address_id, state)" " VALUES (:messageEventId, :sipAddressId, :state)", - soci::use(messageEventId), soci::use(sipAddressId), soci::use(static_cast(state)); + soci::use(messageEventId), soci::use(sipAddressId), soci::use(state); } - void MainDbPrivate::insertConferenceEvent (long eventId, long chatRoomId) { +// ----------------------------------------------------------------------------- + + long MainDbPrivate::insertEvent (const EventLog &eventLog) { + return insertEvent(eventLog.getType(), Utils::getLongAsTm(eventLog.getTime())); + } + + long MainDbPrivate::insertMessageEvent (const EventLog &eventLog) { + // TODO. + return 0; + } + + long MainDbPrivate::insertConferenceEvent (const EventLog &eventLog) { + long eventId = insertEvent(eventLog); soci::session *session = dbSession.getBackendSession(); - *session << "INSERT INTO conference_event (event_id, chat_room_id) VALUES (:eventId, :chatRoomId)", - soci::use(eventId), soci::use(chatRoomId); + *session << "INSERT INTO conference_event (event_id, chat_room_id)" + " VALUES (:eventId, (SELECT id FROM sip_address WHERE value = :conferenceAddress))", + soci::use(eventId), soci::use(static_cast(eventLog).getConferenceAddress().asString()); + return eventId; + } + + long MainDbPrivate::insertConferenceParticipantEvent (const EventLog &eventLog) { + long eventId = insertConferenceEvent(eventLog); + soci::session *session = dbSession.getBackendSession(); + *session << "INSERT INTO conference_participant_event (conference_event_id, chat_room_id)" + " VALUES (:eventId, (SELECT id FROM sip_address WHERE value = :participantAddress))", + soci::use(eventId), + soci::use(static_cast(eventLog).getParticipantAddress().asStringUriOnly()); + return eventId; + } + + long MainDbPrivate::insertConferenceParticipantDeviceEvent (const EventLog &eventLog) { + // TODO. + return 0; + } + + long MainDbPrivate::insertConferenceSubjectEvent (const EventLog &eventLog) { + // TODO. + return 0; } // ----------------------------------------------------------------------------- @@ -490,6 +526,8 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} } bool MainDb::addEvent (const EventLog &eventLog) { + L_D(); + if (!isConnected()) { lWarning() << "Unable to add event. Not connected."; return false; @@ -499,18 +537,34 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} switch (eventLog.getType()) { case EventLog::Type::None: return false; + case EventLog::Type::ChatMessage: + d->insertMessageEvent(eventLog); + break; + case EventLog::Type::CallStart: case EventLog::Type::CallEnd: + return false; // TODO. + case EventLog::Type::ConferenceCreated: case EventLog::Type::ConferenceDestroyed: + d->insertConferenceEvent(eventLog); + break; + case EventLog::Type::ConferenceParticipantAdded: case EventLog::Type::ConferenceParticipantRemoved: case EventLog::Type::ConferenceParticipantSetAdmin: case EventLog::Type::ConferenceParticipantUnsetAdmin: + d->insertConferenceParticipantEvent(eventLog); + break; + case EventLog::Type::ConferenceParticipantDeviceAdded: case EventLog::Type::ConferenceParticipantDeviceRemoved: + d->insertConferenceParticipantDeviceEvent(eventLog); + break; + case EventLog::Type::ConferenceSubjectChanged: + d->insertConferenceSubjectEvent(eventLog); break; } @@ -708,15 +762,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} shared_ptr MainDb::findChatRoom (const string &peerAddress) const { L_D(); - const auto it = d->chatRooms.find(peerAddress); - if (it != d->chatRooms.cend()) { - try { - return it->second.lock(); - } catch (const exception &) { - lError() << "Cannot lock chat room: `" + peerAddress + "`"; - } - return shared_ptr(); - } + // TODO: Use core cache. L_BEGIN_LOG_EXCEPTION @@ -836,8 +882,8 @@ shared_ptr MainDb::findChatRoom (const string &peerAddress) const { long messageEventId = d->insertMessageEvent ( references, - static_cast(state), - static_cast(direction), + state, + direction, message.get(LEGACY_MESSAGE_COL_IMDN_MESSAGE_ID, ""), !!message.get(LEGACY_MESSAGE_COL_IS_SECURED, 0), { move(content) } @@ -847,7 +893,7 @@ shared_ptr MainDb::findChatRoom (const string &peerAddress) const { d->insertMessageParticipant( messageEventId, references.remoteSipAddressId, - static_cast(state) + state ); } diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 30e970df0..5a106897a 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -61,12 +61,12 @@ vector Utils::split (const string &str, const string &delimiter) { #ifndef __ANDROID__ #define TO_STRING_IMPL(TYPE) \ - string Utils::toString(TYPE val) { \ + string Utils::toString (TYPE val) { \ return to_string(val); \ } #else #define TO_STRING_IMPL(TYPE) \ - string Utils::toString(TYPE val) { \ + string Utils::toString (TYPE val) { \ ostringstream os; \ os << val; \ return os.str(); \ @@ -94,10 +94,10 @@ string Utils::toString (const void *val) { // ----------------------------------------------------------------------------- #define STRING_TO_NUMBER_IMPL(TYPE, SUFFIX) \ - TYPE Utils::sto ## SUFFIX(const string &str, size_t * idx, int base) { \ + TYPE Utils::sto ## SUFFIX(const string &str, size_t *idx, int base) { \ return sto ## SUFFIX(str.c_str(), idx, base); \ } \ - TYPE Utils::sto ## SUFFIX(const char *str, size_t * idx, int base) { \ + TYPE Utils::sto ## SUFFIX(const char *str, size_t *idx, int base) { \ char *p; \ TYPE v = strto ## SUFFIX(str, &p, base); \ if (idx) \ From e4e40d183f93dc7c341f1c42914963d58eae7bd7 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 17 Oct 2017 14:13:34 +0200 Subject: [PATCH 0519/2215] feat(MainDb): supports conference events insertion --- src/db/main-db-p.h | 1 + src/db/main-db.cpp | 61 +++++++++++++++---- src/event-log/call-event.cpp | 2 +- src/event-log/call-event.h | 2 +- src/event-log/chat-message-event.cpp | 2 +- src/event-log/chat-message-event.h | 2 +- src/event-log/conference-event.cpp | 4 +- src/event-log/conference-event.h | 4 +- .../conference-participant-device-event.cpp | 2 +- .../conference-participant-device-event.h | 2 +- .../conference-participant-event.cpp | 4 +- src/event-log/conference-participant-event.h | 4 +- src/event-log/conference-subject-event.cpp | 2 +- src/event-log/conference-subject-event.h | 2 +- src/event-log/event-log.cpp | 7 ++- src/event-log/event-log.h | 2 +- 16 files changed, 72 insertions(+), 31 deletions(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 882ac9dff..464cfa0c7 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -68,6 +68,7 @@ private: // --------------------------------------------------------------------------- long insertEvent (const EventLog &eventLog); + long insertCallEvent (const EventLog &eventLog); long insertMessageEvent (const EventLog &eventLog); long insertConferenceEvent (const EventLog &eventLog); long insertConferenceParticipantEvent (const EventLog &eventLog); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index e639465f1..6ad867efe 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -244,6 +244,11 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return insertEvent(eventLog.getType(), Utils::getLongAsTm(eventLog.getTime())); } + long MainDbPrivate::insertCallEvent (const EventLog &eventLog) { + // TODO. + return 0; + } + long MainDbPrivate::insertMessageEvent (const EventLog &eventLog) { // TODO. return 0; @@ -251,31 +256,49 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} long MainDbPrivate::insertConferenceEvent (const EventLog &eventLog) { long eventId = insertEvent(eventLog); + long chatRoomId = insertSipAddress( + static_cast(eventLog).getConferenceAddress().asString() + ); + soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_event (event_id, chat_room_id)" - " VALUES (:eventId, (SELECT id FROM sip_address WHERE value = :conferenceAddress))", - soci::use(eventId), soci::use(static_cast(eventLog).getConferenceAddress().asString()); + " VALUES (:eventId, :chatRoomId)", soci::use(eventId), soci::use(chatRoomId); return eventId; } long MainDbPrivate::insertConferenceParticipantEvent (const EventLog &eventLog) { long eventId = insertConferenceEvent(eventLog); + long participantAddressId = insertSipAddress( + static_cast(eventLog).getParticipantAddress().asString() + ); + soci::session *session = dbSession.getBackendSession(); - *session << "INSERT INTO conference_participant_event (conference_event_id, chat_room_id)" - " VALUES (:eventId, (SELECT id FROM sip_address WHERE value = :participantAddress))", - soci::use(eventId), - soci::use(static_cast(eventLog).getParticipantAddress().asStringUriOnly()); + *session << "INSERT INTO conference_participant_event (conference_event_id, participant_address_id)" + " VALUES (:eventId, :participantAddressId)", soci::use(eventId), soci::use(participantAddressId); return eventId; } long MainDbPrivate::insertConferenceParticipantDeviceEvent (const EventLog &eventLog) { - // TODO. - return 0; + long eventId = insertConferenceParticipantEvent(eventLog); + long gruuAddressId = insertSipAddress( + static_cast(eventLog).getGruuAddress().asString() + ); + + soci::session *session = dbSession.getBackendSession(); + *session << "INSERT INTO conference_participant_device_event (conference_participant_event_id, gruu_address_id)" + " VALUES (:eventId, :gruuAddressId)", soci::use(eventId), soci::use(gruuAddressId); + return eventId; } long MainDbPrivate::insertConferenceSubjectEvent (const EventLog &eventLog) { - // TODO. - return 0; + long eventId = insertConferenceEvent(eventLog); + + soci::session *session = dbSession.getBackendSession(); + *session << "INSERT INTO conference_subject_event (conference_event_id, subject)" + " VALUES (:eventId, :subject)", soci::use(eventId), soci::use( + static_cast(eventLog).getSubject() + ); + return eventId; } // ----------------------------------------------------------------------------- @@ -533,7 +556,12 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return false; } - // TODO. + bool soFarSoGood = false; + + L_BEGIN_LOG_EXCEPTION + + soci::transaction tr(*d->dbSession.getBackendSession()); + switch (eventLog.getType()) { case EventLog::Type::None: return false; @@ -544,7 +572,8 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} case EventLog::Type::CallStart: case EventLog::Type::CallEnd: - return false; // TODO. + d->insertCallEvent(eventLog); + break; case EventLog::Type::ConferenceCreated: case EventLog::Type::ConferenceDestroyed: @@ -568,7 +597,13 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} break; } - return true; + tr.commit(); + + soFarSoGood = true; + + L_END_LOG_EXCEPTION + + return soFarSoGood; } bool MainDb::deleteEvent (const EventLog &eventLog) { diff --git a/src/event-log/call-event.cpp b/src/event-log/call-event.cpp index b434bbff2..6f7a50173 100644 --- a/src/event-log/call-event.cpp +++ b/src/event-log/call-event.cpp @@ -33,7 +33,7 @@ public: // ----------------------------------------------------------------------------- -CallEvent::CallEvent (Type type, const time_t &time, const shared_ptr &call) : +CallEvent::CallEvent (Type type, time_t time, const shared_ptr &call) : EventLog(*new CallEventPrivate, type, time) { L_D(); L_ASSERT(call); diff --git a/src/event-log/call-event.h b/src/event-log/call-event.h index 5bc348f47..532da7805 100644 --- a/src/event-log/call-event.h +++ b/src/event-log/call-event.h @@ -33,7 +33,7 @@ class CallEventPrivate; class LINPHONE_PUBLIC CallEvent : public EventLog { public: - CallEvent (Type type, const std::time_t &time, const std::shared_ptr &message); + CallEvent (Type type, std::time_t time, const std::shared_ptr &message); CallEvent (const CallEvent &src); CallEvent &operator= (const CallEvent &src); diff --git a/src/event-log/chat-message-event.cpp b/src/event-log/chat-message-event.cpp index e6a796d93..6c1e57419 100644 --- a/src/event-log/chat-message-event.cpp +++ b/src/event-log/chat-message-event.cpp @@ -34,7 +34,7 @@ public: // ----------------------------------------------------------------------------- ChatMessageEvent::ChatMessageEvent ( - const time_t &time, + time_t time, const shared_ptr &chatMessage ) : EventLog(*new ChatMessageEventPrivate, EventLog::Type::ChatMessage, time) { L_D(); diff --git a/src/event-log/chat-message-event.h b/src/event-log/chat-message-event.h index a9a3c7e76..bbe95baf8 100644 --- a/src/event-log/chat-message-event.h +++ b/src/event-log/chat-message-event.h @@ -33,7 +33,7 @@ class ChatMessageEventPrivate; class LINPHONE_PUBLIC ChatMessageEvent : public EventLog { public: - ChatMessageEvent (const std::time_t &time, const std::shared_ptr &chatMessage); + ChatMessageEvent (std::time_t time, const std::shared_ptr &chatMessage); ChatMessageEvent (const ChatMessageEvent &src); ChatMessageEvent &operator= (const ChatMessageEvent &src); diff --git a/src/event-log/conference-event.cpp b/src/event-log/conference-event.cpp index 50311782b..c11c94428 100644 --- a/src/event-log/conference-event.cpp +++ b/src/event-log/conference-event.cpp @@ -26,7 +26,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ConferenceEvent::ConferenceEvent (Type type, const time_t &time, const Address &conferenceAddress) : +ConferenceEvent::ConferenceEvent (Type type, time_t time, const Address &conferenceAddress) : EventLog(*new ConferenceEventPrivate, type, time) { L_D(); L_ASSERT(type == Type::ConferenceCreated || type == Type::ConferenceDestroyed); @@ -39,7 +39,7 @@ ConferenceEvent::ConferenceEvent (const ConferenceEvent &src) : ConferenceEvent::ConferenceEvent ( ConferenceEventPrivate &p, Type type, - const time_t &time, + time_t time, const Address &conferenceAddress ) : EventLog(p, type, time) { L_D(); diff --git a/src/event-log/conference-event.h b/src/event-log/conference-event.h index dbd2391ab..b2d791f2b 100644 --- a/src/event-log/conference-event.h +++ b/src/event-log/conference-event.h @@ -31,7 +31,7 @@ class ConferenceEventPrivate; class LINPHONE_PUBLIC ConferenceEvent : public EventLog { public: - ConferenceEvent (Type type, const std::time_t &time, const Address &conferenceAddress); + ConferenceEvent (Type type, std::time_t time, const Address &conferenceAddress); ConferenceEvent (const ConferenceEvent &src); ConferenceEvent &operator= (const ConferenceEvent &src); @@ -39,7 +39,7 @@ public: const Address &getConferenceAddress () const; protected: - ConferenceEvent (ConferenceEventPrivate &p, Type type, const std::time_t &time, const Address &conferenceAddress); + ConferenceEvent (ConferenceEventPrivate &p, Type type, std::time_t time, const Address &conferenceAddress); private: L_DECLARE_PRIVATE(ConferenceEvent); diff --git a/src/event-log/conference-participant-device-event.cpp b/src/event-log/conference-participant-device-event.cpp index fa0334f89..fd090f1df 100644 --- a/src/event-log/conference-participant-device-event.cpp +++ b/src/event-log/conference-participant-device-event.cpp @@ -35,7 +35,7 @@ public: ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent ( Type type, - const time_t &time, + time_t time, const Address &conferenceAddress, const Address &participantAddress, const Address &gruuAddress diff --git a/src/event-log/conference-participant-device-event.h b/src/event-log/conference-participant-device-event.h index 4fcf4fa8d..d70d08549 100644 --- a/src/event-log/conference-participant-device-event.h +++ b/src/event-log/conference-participant-device-event.h @@ -32,7 +32,7 @@ class LINPHONE_PUBLIC ConferenceParticipantDeviceEvent : public ConferencePartic public: ConferenceParticipantDeviceEvent ( Type type, - const std::time_t &time, + std::time_t time, const Address &conferenceAddress, const Address &participantAddress, const Address &gruuAddress diff --git a/src/event-log/conference-participant-event.cpp b/src/event-log/conference-participant-event.cpp index e58b668a2..3f6e560fd 100644 --- a/src/event-log/conference-participant-event.cpp +++ b/src/event-log/conference-participant-event.cpp @@ -29,7 +29,7 @@ LINPHONE_BEGIN_NAMESPACE ConferenceParticipantEvent::ConferenceParticipantEvent ( Type type, - const time_t &time, + time_t time, const Address &conferenceAddress, const Address &participantAddress ) : ConferenceEvent(*new ConferenceParticipantEventPrivate, type, time, conferenceAddress) { @@ -55,7 +55,7 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( ConferenceParticipantEvent::ConferenceParticipantEvent ( ConferenceParticipantEventPrivate &p, Type type, - const time_t &time, + time_t time, const Address &conferenceAddress, const Address &participantAddress ) : ConferenceEvent(p, type, time, conferenceAddress) { diff --git a/src/event-log/conference-participant-event.h b/src/event-log/conference-participant-event.h index 69b5416db..5b69d84cb 100644 --- a/src/event-log/conference-participant-event.h +++ b/src/event-log/conference-participant-event.h @@ -32,7 +32,7 @@ class LINPHONE_PUBLIC ConferenceParticipantEvent : public ConferenceEvent { public: ConferenceParticipantEvent ( Type type, - const std::time_t &time, + std::time_t time, const Address &conferenceAddress, const Address &participantAddress ); @@ -46,7 +46,7 @@ protected: ConferenceParticipantEvent ( ConferenceParticipantEventPrivate &p, Type type, - const std::time_t &time, + std::time_t time, const Address &conferenceAddress, const Address &participantAddress ); diff --git a/src/event-log/conference-subject-event.cpp b/src/event-log/conference-subject-event.cpp index 492f6bcf4..dc1073506 100644 --- a/src/event-log/conference-subject-event.cpp +++ b/src/event-log/conference-subject-event.cpp @@ -34,7 +34,7 @@ public: // ----------------------------------------------------------------------------- ConferenceSubjectEvent::ConferenceSubjectEvent ( - const time_t &time, + time_t time, const Address &address, const string &subject ) : ConferenceEvent(*new ConferenceSubjectEventPrivate, Type::ConferenceSubjectChanged, time, address) { diff --git a/src/event-log/conference-subject-event.h b/src/event-log/conference-subject-event.h index a145b3fbd..144fb8e48 100644 --- a/src/event-log/conference-subject-event.h +++ b/src/event-log/conference-subject-event.h @@ -30,7 +30,7 @@ class ConferenceSubjectEventPrivate; class LINPHONE_PUBLIC ConferenceSubjectEvent : public ConferenceEvent { public: - ConferenceSubjectEvent (const std::time_t &time, const Address &conferenceAddress, const std::string &subject); + ConferenceSubjectEvent (std::time_t time, const Address &conferenceAddress, const std::string &subject); ConferenceSubjectEvent (const ConferenceSubjectEvent &src); ConferenceSubjectEvent &operator= (const ConferenceSubjectEvent &src); diff --git a/src/event-log/event-log.cpp b/src/event-log/event-log.cpp index 490334426..cdb2281bb 100644 --- a/src/event-log/event-log.cpp +++ b/src/event-log/event-log.cpp @@ -27,7 +27,7 @@ EventLog::EventLog () : ClonableObject(*new EventLogPrivate) {} EventLog::EventLog (const EventLog &) : ClonableObject(*new EventLogPrivate) {} -EventLog::EventLog (EventLogPrivate &p, Type type, const time_t &time) : ClonableObject(*new EventLogPrivate) { +EventLog::EventLog (EventLogPrivate &p, Type type, time_t time) : ClonableObject(*new EventLogPrivate) { L_D(); d->type = type; d->time = time; @@ -45,4 +45,9 @@ EventLog::Type EventLog::getType () const { return d->type; } +std::time_t EventLog::getTime () const { + L_D(); + return d->time; +} + LINPHONE_END_NAMESPACE diff --git a/src/event-log/event-log.h b/src/event-log/event-log.h index 4d3cba931..e5f0d682a 100644 --- a/src/event-log/event-log.h +++ b/src/event-log/event-log.h @@ -48,7 +48,7 @@ public: std::time_t getTime () const; protected: - EventLog (EventLogPrivate &p, Type type, const std::time_t &time); + EventLog (EventLogPrivate &p, Type type, std::time_t time); private: L_DECLARE_PRIVATE(EventLog); From a949778e70aa9c7ed6b02d3972a853fe2e6f8b97 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 17 Oct 2017 14:41:59 +0200 Subject: [PATCH 0520/2215] feat(EventLog): better architecture --- src/CMakeLists.txt | 31 ++++++------ src/c-wrapper/api/c-event-log.cpp | 6 +-- src/db/main-db.cpp | 8 +-- src/dial-plan/dial-plan.h | 5 +- src/event-log/{ => call}/call-event.cpp | 2 +- src/event-log/{ => call}/call-event.h | 2 +- .../{ => chat}/chat-message-event.cpp | 2 +- src/event-log/{ => chat}/chat-message-event.h | 2 +- .../{ => conference}/conference-event-p.h | 2 +- .../{ => conference}/conference-event.cpp | 0 .../{ => conference}/conference-event.h | 2 +- .../conference/conference-notified-event-p.h | 0 .../conference/conference-notified-event.cpp | 0 .../conference/conference-notified-event.h | 50 +++++++++++++++++++ .../conference-participant-device-event.cpp | 0 .../conference-participant-device-event.h | 0 .../conference-participant-event-p.h | 0 .../conference-participant-event.cpp | 0 .../conference-participant-event.h | 0 .../conference-subject-event.cpp | 0 .../conference-subject-event.h | 0 21 files changed, 83 insertions(+), 29 deletions(-) rename src/event-log/{ => call}/call-event.cpp (98%) rename src/event-log/{ => call}/call-event.h (97%) rename src/event-log/{ => chat}/chat-message-event.cpp (98%) rename src/event-log/{ => chat}/chat-message-event.h (97%) rename src/event-log/{ => conference}/conference-event-p.h (97%) rename src/event-log/{ => conference}/conference-event.cpp (100%) rename src/event-log/{ => conference}/conference-event.h (97%) create mode 100644 src/event-log/conference/conference-notified-event-p.h create mode 100644 src/event-log/conference/conference-notified-event.cpp create mode 100644 src/event-log/conference/conference-notified-event.h rename src/event-log/{ => conference}/conference-participant-device-event.cpp (100%) rename src/event-log/{ => conference}/conference-participant-device-event.h (100%) rename src/event-log/{ => conference}/conference-participant-event-p.h (100%) rename src/event-log/{ => conference}/conference-participant-event.cpp (100%) rename src/event-log/{ => conference}/conference-participant-event.h (100%) rename src/event-log/{ => conference}/conference-subject-event.cpp (100%) rename src/event-log/{ => conference}/conference-subject-event.h (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3548dda9f..89f5eda14 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -90,14 +90,16 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES dial-plan/dial-plan-p.h dial-plan/dial-plan.h enums.h - event-log/call-event.h - event-log/chat-message-event.h - event-log/conference-event-p.h - event-log/conference-event.h - event-log/conference-participant-device-event.h - event-log/conference-participant-event-p.h - event-log/conference-participant-event.h - event-log/conference-subject-event.h + event-log/call/call-event.h + event-log/chat/chat-message-event.h + event-log/conference/conference-event-p.h + event-log/conference/conference-event.h + event-log/conference/conference-notified-event-p.h + event-log/conference/conference-notified-event.h + event-log/conference/conference-participant-device-event.h + event-log/conference/conference-participant-event-p.h + event-log/conference/conference-participant-event.h + event-log/conference/conference-subject-event.h event-log/event-log-p.h event-log/event-log.h hacks/hacks.h @@ -170,12 +172,13 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES db/session/db-session-provider.cpp db/session/db-session.cpp dial-plan/dial-plan.cpp - event-log/call-event.cpp - event-log/chat-message-event.cpp - event-log/conference-event.cpp - event-log/conference-participant-device-event.cpp - event-log/conference-participant-event.cpp - event-log/conference-subject-event.cpp + event-log/call/call-event.cpp + event-log/chat/chat-message-event.cpp + event-log/conference/conference-event.cpp + event-log/conference/conference-notified-event.cpp + event-log/conference/conference-participant-device-event.cpp + event-log/conference/conference-participant-event.cpp + event-log/conference/conference-subject-event.cpp event-log/event-log.cpp hacks/hacks.cpp logger/logger.cpp diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 77dd75244..e3e8cd467 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -23,9 +23,9 @@ #include "c-wrapper/c-wrapper.h" #include "call/call.h" #include "chat/chat-message/chat-message.h" -#include "event-log/call-event.h" -#include "event-log/chat-message-event.h" -#include "event-log/conference-participant-event.h" +#include "event-log/call/call-event.h" +#include "event-log/chat/chat-message-event.h" +#include "event-log/conference/conference-participant-event.h" // ============================================================================= diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 6ad867efe..4576ebb32 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -31,10 +31,10 @@ #include "content/content-type.h" #include "content/content.h" #include "db/session/db-session-provider.h" -#include "event-log/call-event.h" -#include "event-log/chat-message-event.h" -#include "event-log/conference-participant-device-event.h" -#include "event-log/conference-subject-event.h" +#include "event-log/call/call-event.h" +#include "event-log/chat/chat-message-event.h" +#include "event-log/conference/conference-participant-device-event.h" +#include "event-log/conference/conference-subject-event.h" #include "event-log/event-log-p.h" #include "logger/logger.h" #include "main-db-p.h" diff --git a/src/dial-plan/dial-plan.h b/src/dial-plan/dial-plan.h index b25a8853e..f7f51ec8d 100644 --- a/src/dial-plan/dial-plan.h +++ b/src/dial-plan/dial-plan.h @@ -21,6 +21,7 @@ #define _DIAL_PLAN_H_ #include + #include "object/clonable-object.h" // ============================================================================= @@ -34,7 +35,7 @@ public: DialPlan (const std::string &country = "", const std::string &isoCountryCode = "", const std::string &ccc = "", int nnl = 0, const std::string &icp = ""); DialPlan (const DialPlan &src); ~DialPlan (); - + DialPlan &operator= (const DialPlan &src); const std::string& getCountry() const; @@ -54,7 +55,7 @@ public: private: static std::list const DialPlans; - + L_DECLARE_PRIVATE(DialPlan); }; diff --git a/src/event-log/call-event.cpp b/src/event-log/call/call-event.cpp similarity index 98% rename from src/event-log/call-event.cpp rename to src/event-log/call/call-event.cpp index 6f7a50173..b4d6be335 100644 --- a/src/event-log/call-event.cpp +++ b/src/event-log/call/call-event.cpp @@ -18,7 +18,7 @@ */ #include "call-event.h" -#include "event-log-p.h" +#include "event-log/event-log-p.h" // ============================================================================= diff --git a/src/event-log/call-event.h b/src/event-log/call/call-event.h similarity index 97% rename from src/event-log/call-event.h rename to src/event-log/call/call-event.h index 532da7805..85ae6c28d 100644 --- a/src/event-log/call-event.h +++ b/src/event-log/call/call-event.h @@ -22,7 +22,7 @@ #include -#include "event-log.h" +#include "event-log/event-log.h" // ============================================================================= diff --git a/src/event-log/chat-message-event.cpp b/src/event-log/chat/chat-message-event.cpp similarity index 98% rename from src/event-log/chat-message-event.cpp rename to src/event-log/chat/chat-message-event.cpp index 6c1e57419..6e26e48e3 100644 --- a/src/event-log/chat-message-event.cpp +++ b/src/event-log/chat/chat-message-event.cpp @@ -18,7 +18,7 @@ */ #include "chat-message-event.h" -#include "event-log-p.h" +#include "event-log/event-log-p.h" // ============================================================================= diff --git a/src/event-log/chat-message-event.h b/src/event-log/chat/chat-message-event.h similarity index 97% rename from src/event-log/chat-message-event.h rename to src/event-log/chat/chat-message-event.h index bbe95baf8..becbdadd8 100644 --- a/src/event-log/chat-message-event.h +++ b/src/event-log/chat/chat-message-event.h @@ -22,7 +22,7 @@ #include -#include "event-log.h" +#include "event-log/event-log.h" // ============================================================================= diff --git a/src/event-log/conference-event-p.h b/src/event-log/conference/conference-event-p.h similarity index 97% rename from src/event-log/conference-event-p.h rename to src/event-log/conference/conference-event-p.h index f88f80752..85e7ae92e 100644 --- a/src/event-log/conference-event-p.h +++ b/src/event-log/conference/conference-event-p.h @@ -22,7 +22,7 @@ #include "address/address.h" #include "conference-event.h" -#include "event-log-p.h" +#include "event-log/event-log-p.h" // ============================================================================= diff --git a/src/event-log/conference-event.cpp b/src/event-log/conference/conference-event.cpp similarity index 100% rename from src/event-log/conference-event.cpp rename to src/event-log/conference/conference-event.cpp diff --git a/src/event-log/conference-event.h b/src/event-log/conference/conference-event.h similarity index 97% rename from src/event-log/conference-event.h rename to src/event-log/conference/conference-event.h index b2d791f2b..05fb34dc4 100644 --- a/src/event-log/conference-event.h +++ b/src/event-log/conference/conference-event.h @@ -20,7 +20,7 @@ #ifndef _CONFERENCE_EVENT_H_ #define _CONFERENCE_EVENT_H_ -#include "event-log.h" +#include "event-log/event-log.h" // ============================================================================= diff --git a/src/event-log/conference/conference-notified-event-p.h b/src/event-log/conference/conference-notified-event-p.h new file mode 100644 index 000000000..e69de29bb diff --git a/src/event-log/conference/conference-notified-event.cpp b/src/event-log/conference/conference-notified-event.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/src/event-log/conference/conference-notified-event.h b/src/event-log/conference/conference-notified-event.h new file mode 100644 index 000000000..5e87cf8bb --- /dev/null +++ b/src/event-log/conference/conference-notified-event.h @@ -0,0 +1,50 @@ +/* + * conference-notified-event.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CONFERENCE_NOTIFIED_EVENT_H_ +#define _CONFERENCE_NOTIFIED_EVENT_H_ + +#include "conference-event.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class Address; +class ConferenceNotifiedEventPrivate; + +class LINPHONE_PUBLIC ConferenceNotifiedEvent : public EventLog { +public: + ConferenceNotifiedEvent (Type type, std::time_t time, const Address &conferenceAddress); + ConferenceNotifiedEvent (const ConferenceNotifiedEvent &src); + + ConferenceNotifiedEvent &operator= (const ConferenceNotifiedEvent &src); + + const Address &getConferenceAddress () const; + +protected: + ConferenceNotifiedEvent (ConferenceNotifiedEventPrivate &p, Type type, std::time_t time, const Address &conferenceAddress); + +private: + L_DECLARE_PRIVATE(ConferenceNotifiedEvent); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CONFERENCE_NOTIFIED_EVENT_H_ diff --git a/src/event-log/conference-participant-device-event.cpp b/src/event-log/conference/conference-participant-device-event.cpp similarity index 100% rename from src/event-log/conference-participant-device-event.cpp rename to src/event-log/conference/conference-participant-device-event.cpp diff --git a/src/event-log/conference-participant-device-event.h b/src/event-log/conference/conference-participant-device-event.h similarity index 100% rename from src/event-log/conference-participant-device-event.h rename to src/event-log/conference/conference-participant-device-event.h diff --git a/src/event-log/conference-participant-event-p.h b/src/event-log/conference/conference-participant-event-p.h similarity index 100% rename from src/event-log/conference-participant-event-p.h rename to src/event-log/conference/conference-participant-event-p.h diff --git a/src/event-log/conference-participant-event.cpp b/src/event-log/conference/conference-participant-event.cpp similarity index 100% rename from src/event-log/conference-participant-event.cpp rename to src/event-log/conference/conference-participant-event.cpp diff --git a/src/event-log/conference-participant-event.h b/src/event-log/conference/conference-participant-event.h similarity index 100% rename from src/event-log/conference-participant-event.h rename to src/event-log/conference/conference-participant-event.h diff --git a/src/event-log/conference-subject-event.cpp b/src/event-log/conference/conference-subject-event.cpp similarity index 100% rename from src/event-log/conference-subject-event.cpp rename to src/event-log/conference/conference-subject-event.cpp diff --git a/src/event-log/conference-subject-event.h b/src/event-log/conference/conference-subject-event.h similarity index 100% rename from src/event-log/conference-subject-event.h rename to src/event-log/conference/conference-subject-event.h From bf9fba42938e69e1b8df59d854779f0d77257f45 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 17 Oct 2017 14:42:58 +0200 Subject: [PATCH 0521/2215] fix(DialPlan): indent code correctly, avoid usage of deprecated atoi function, use string refs... --- src/dial-plan/dial-plan-p.h | 13 +- src/dial-plan/dial-plan.cpp | 634 ++++++++++++++++++------------------ src/dial-plan/dial-plan.h | 33 +- 3 files changed, 342 insertions(+), 338 deletions(-) diff --git a/src/dial-plan/dial-plan-p.h b/src/dial-plan/dial-plan-p.h index c6a48bdca..22b8aef6e 100644 --- a/src/dial-plan/dial-plan-p.h +++ b/src/dial-plan/dial-plan-p.h @@ -28,13 +28,14 @@ LINPHONE_BEGIN_NAMESPACE class DialPlanPrivate : public ClonableObjectPrivate { - -public: +private: std::string country; - std::string isoCountryCode; /* ISO 3166-1 alpha-2 code, ex: FR for France*/ - std::string countryCallingCode; /*country calling code*/ - int nationalNumberLength = 0; /*maximum national number length*/ - std::string internationalCallPrefix; /*international call prefix, ex: 00 in europe*/ + std::string isoCountryCode; // ISO 3166-1 alpha-2 code, ex: FR for France. + std::string countryCallingCode; // Country calling code. + int nationalNumberLength = 0; // Maximum national number length. + std::string internationalCallPrefix; // International call prefix, ex: 00 in europe. + + static const std::list DialPlans; L_DECLARE_PUBLIC(DialPlan); }; diff --git a/src/dial-plan/dial-plan.cpp b/src/dial-plan/dial-plan.cpp index 4f9fb94f5..a2da2c667 100644 --- a/src/dial-plan/dial-plan.cpp +++ b/src/dial-plan/dial-plan.cpp @@ -17,10 +17,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include + #include "linphone/utils/utils.h" #include "dial-plan-p.h" -#include "c-wrapper/c-wrapper.h" #include "logger/logger.h" // ============================================================================= @@ -34,365 +35,364 @@ LINPHONE_BEGIN_NAMESPACE * http://en.wikipedia.org/wiki/Telephone_numbers_in_Europe * imported from https://en.wikipedia.org/wiki/List_of_mobile_phone_number_series_by_country */ -list const DialPlan::DialPlans = { - //Country , iso country code, e164 country calling code, number length, international usual prefix - {"Afghanistan" ,"AF" , "93" , 9 , "00" }, - {"Albania" ,"AL" , "355" , 9 , "00" }, - {"Algeria" ,"DZ" , "213" , 9 , "00" }, - {"American Samoa" ,"AS" , "1" , 10 , "011" }, - {"Andorra" ,"AD" , "376" , 6 , "00" }, - {"Angola" ,"AO" , "244" , 9 , "00" }, - {"Anguilla" ,"AI" , "1" , 10 , "011" }, - {"Antigua and Barbuda" ,"AG" , "1" , 10 , "011" }, - {"Argentina" ,"AR" , "54" , 10 , "00" }, - {"Armenia" ,"AM" , "374" , 8 , "00" }, - {"Aruba" ,"AW" , "297" , 7 , "011" }, - {"Australia" ,"AU" , "61" , 9 , "0011"}, - {"Austria" ,"AT" , "43" , 10 , "00" }, - {"Azerbaijan" ,"AZ" , "994" , 9 , "00" }, - {"Bahamas" ,"BS" , "1" , 10 , "011" }, - {"Bahrain" ,"BH" , "973" , 8 , "00" }, - {"Bangladesh" ,"BD" , "880" , 10 , "00" }, - {"Barbados" ,"BB" , "1" , 10 , "011" }, - {"Belarus" ,"BY" , "375" , 9 , "00" }, - {"Belgium" ,"BE" , "32" , 9 , "00" }, - {"Belize" ,"BZ" , "501" , 7 , "00" }, - {"Benin" ,"BJ" , "229" , 8 , "00" }, - {"Bermuda" ,"BM" , "1" , 10 , "011" }, - {"Bhutan" ,"BT" , "975" , 8 , "00" }, - {"Bolivia" ,"BO" , "591" , 8 , "00" }, - {"Bosnia and Herzegovina" ,"BA" , "387" , 8 , "00" }, - {"Botswana" ,"BW" , "267" , 8 , "00" }, - {"Brazil" ,"BR" , "55" , 10 , "00" }, - {"Brunei Darussalam" ,"BN" , "673" , 7 , "00" }, - {"Bulgaria" ,"BG" , "359" , 9 , "00" }, - {"Burkina Faso" ,"BF" , "226" , 8 , "00" }, - {"Burundi" ,"BI" , "257" , 8 , "011" }, - {"Cambodia" ,"KH" , "855" , 9 , "00" }, - {"Cameroon" ,"CM" , "237" , 9 , "00" }, - {"Canada" ,"CA" , "1" , 10 , "011" }, - {"Cape Verde" ,"CV" , "238" , 7 , "00" }, - {"Cayman Islands" ,"KY" , "1" , 10 , "011" }, - {"Central African Republic" ,"CF" , "236" , 8 , "00" }, - {"Chad" ,"TD" , "235" , 8 , "00" }, - {"Chile" ,"CL" , "56" , 9 , "00" }, - {"China" ,"CN" , "86" , 11 , "00" }, - {"Colombia" ,"CO" , "57" , 10 , "00" }, - {"Comoros" ,"KM" , "269" , 7 , "00" }, - {"Congo" ,"CG" , "242" , 9 , "00" }, - {"Congo Democratic Republic" ,"CD" , "243" , 9 , "00" }, - {"Cook Islands" ,"CK" , "682" , 5 , "00" }, - {"Costa Rica" ,"CR" , "506" , 8 , "00" }, - {"Cote d'Ivoire" ,"AD" , "225" , 8 , "00" }, - {"Croatia" ,"HR" , "385" , 9 , "00" }, - {"Cuba" ,"CU" , "53" , 8 , "119" }, - {"Cyprus" ,"CY" , "357" , 8 , "00" }, - {"Czech Republic" ,"CZ" , "420" , 9 , "00" }, - {"Denmark" ,"DK" , "45" , 8 , "00" }, - {"Djibouti" ,"DJ" , "253" , 8 , "00" }, - {"Dominica" ,"DM" , "1" , 10 , "011" }, - {"Dominican Republic" ,"DO" , "1" , 10 , "011" }, - {"Ecuador" ,"EC" , "593" , 9 , "00" }, - {"Egypt" ,"EG" , "20" , 10 , "00" }, - {"El Salvador" ,"SV" , "503" , 8 , "00" }, - {"Equatorial Guinea" ,"GQ" , "240" , 9 , "00" }, - {"Eritrea" ,"ER" , "291" , 7 , "00" }, - {"Estonia" ,"EE" , "372" , 8 , "00" }, - {"Ethiopia" ,"ET" , "251" , 9 , "00" }, - {"Falkland Islands" ,"FK" , "500" , 5 , "00" }, - {"Faroe Islands" ,"FO" , "298" , 6 , "00" }, - {"Fiji" ,"FJ" , "679" , 7 , "00" }, - {"Finland" ,"FI" , "358" , 9 , "00" }, - {"France" ,"FR" , "33" , 9 , "00" }, - {"French Guiana" ,"GF" , "594" , 9 , "00" }, - {"French Polynesia" ,"PF" , "689" , 6 , "00" }, - {"Gabon" ,"GA" , "241" , 8 , "00" }, - {"Gambia" ,"GM" , "220" , 7 , "00" }, - {"Georgia" ,"GE" , "995" , 9 , "00" }, - {"Germany" ,"DE" , "49" , 11 , "00" }, - {"Ghana" ,"GH" , "233" , 9 , "00" }, - {"Gibraltar" ,"GI" , "350" , 8 , "00" }, - {"Greece" ,"GR" , "30" ,10 , "00" }, - {"Greenland" ,"GL" , "299" , 6 , "00" }, - {"Grenada" ,"GD" , "1" , 10 , "011" }, - {"Guadeloupe" ,"GP" , "590" , 9 , "00" }, - {"Guam" ,"GU" , "1" , 10 , "011" }, - {"Guatemala" ,"GT" , "502" , 8 , "00" }, - {"Guinea" ,"GN" , "224" , 8 , "00" }, - {"Guinea-Bissau" ,"GW" , "245" , 7 , "00" }, - {"Guyana" ,"GY" , "592" , 7 , "001" }, - {"Haiti" ,"HT" , "509" , 8 , "00" }, - {"Honduras" ,"HN" , "504" , 8 , "00" }, - {"Hong Kong" ,"HK" , "852" , 8 , "001" }, - {"Hungary" ,"HU" , "36" , 9 , "00" }, - {"Iceland" ,"IS" , "354" , 9 , "00" }, - {"India" ,"IN" , "91" , 10 , "00" }, - {"Indonesia" ,"ID" , "62" , 10 , "001" }, - {"Iran" ,"IR" , "98" , 10 , "00" }, - {"Iraq" ,"IQ" , "964" , 10 , "00" }, - {"Ireland" ,"IE" , "353" , 9 , "00" }, - {"Israel" ,"IL" , "972" , 9 , "00" }, - {"Italy" ,"IT" , "39" , 10 , "00" }, -/* {"Jersey" ,"JE" , "44" , 10 , "00" },*/ - {"Jamaica" ,"JM" , "1" , 10 , "011" }, - {"Japan" ,"JP" , "81" , 10 , "010" }, - {"Jordan" ,"JO" , "962" , 9 , "00" }, - {"Kazakhstan" ,"KZ" , "7" , 10 , "00" }, - {"Kenya" ,"KE" , "254" , 9 , "000" }, - {"Kiribati" ,"KI" , "686" , 5 , "00" }, - {"Korea, North" ,"KP" , "850" , 12 , "99" }, - {"Korea, South" ,"KR" , "82" , 12 , "001" }, - {"Kuwait" ,"KW" , "965" , 8 , "00" }, - {"Kyrgyzstan" ,"KG" , "996" , 9 , "00" }, - {"Laos" ,"LA" , "856" , 10 , "00" }, - {"Latvia" ,"LV" , "371" , 8 , "00" }, - {"Lebanon" ,"LB" , "961" , 7 , "00" }, - {"Lesotho" ,"LS" , "266" , 8 , "00" }, - {"Liberia" ,"LR" , "231" , 8 , "00" }, - {"Libya" ,"LY" , "218" , 8 , "00" }, - {"Liechtenstein" ,"LI" , "423" , 7 , "00" }, - {"Lithuania" ,"LT" , "370" , 8 , "00" }, - {"Luxembourg" ,"LU" , "352" , 9 , "00" }, - {"Macau" ,"MO" , "853" , 8 , "00" }, - {"Macedonia" ,"MK" , "389" , 8 , "00" }, - {"Madagascar" ,"MG" , "261" , 9 , "00" }, - {"Malawi" ,"MW" , "265" , 9 , "00" }, - {"Malaysia" ,"MY" , "60" , 9 , "00" }, - {"Maldives" ,"MV" , "960" , 7 , "00" }, - {"Mali" ,"ML" , "223" , 8 , "00" }, - {"Malta" ,"MT" , "356" , 8 , "00" }, - {"Marshall Islands" ,"MH" , "692" , 7 , "011" }, - {"Martinique" ,"MQ" , "596" , 9 , "00" }, - {"Mauritania" ,"MR" , "222" , 8 , "00" }, - {"Mauritius" ,"MU" , "230" , 7 , "00" }, - {"Mayotte Island" ,"YT" , "262" , 9 , "00" }, - {"Mexico" ,"MX" , "52" , 10 , "00" }, +const list DialPlanPrivate::DialPlans = { + // Country, iso country code, e164 country calling code, number length, international usual prefix + { "Afghanistan", "AF", "93", 9, "00" }, + { "Albania", "AL", "355", 9, "00" }, + { "Algeria", "DZ", "213", 9, "00" }, + { "American Samoa", "AS", "1", 10, "011" }, + { "Andorra", "AD", "376", 6, "00" }, + { "Angola", "AO", "244", 9, "00" }, + { "Anguilla", "AI", "1", 10, "011" }, + { "Antigua and Barbuda", "AG", "1", 10, "011" }, + { "Argentina", "AR", "54", 10, "00" }, + { "Armenia", "AM", "374", 8, "00" }, + { "Aruba", "AW", "297", 7, "011" }, + { "Australia", "AU", "61", 9, "0011" }, + { "Austria", "AT", "43", 10, "00" }, + { "Azerbaijan", "AZ", "994", 9, "00" }, + { "Bahamas", "BS", "1", 10, "011" }, + { "Bahrain", "BH", "973", 8, "00" }, + { "Bangladesh", "BD", "880", 10, "00" }, + { "Barbados", "BB", "1", 10, "011" }, + { "Belarus", "BY", "375", 9, "00" }, + { "Belgium", "BE", "32", 9, "00" }, + { "Belize", "BZ", "501", 7, "00" }, + { "Benin", "BJ", "229", 8, "00" }, + { "Bermuda", "BM", "1", 10, "011" }, + { "Bhutan", "BT", "975", 8, "00" }, + { "Bolivia", "BO", "591", 8, "00" }, + { "Bosnia and Herzegovina", "BA", "387", 8, "00" }, + { "Botswana", "BW", "267", 8, "00" }, + { "Brazil", "BR", "55", 10, "00" }, + { "Brunei Darussalam", "BN", "673", 7, "00" }, + { "Bulgaria", "BG", "359", 9, "00" }, + { "Burkina Faso", "BF", "226", 8, "00" }, + { "Burundi", "BI", "257", 8, "011" }, + { "Cambodia", "KH", "855", 9, "00" }, + { "Cameroon", "CM", "237", 9, "00" }, + { "Canada", "CA", "1", 10, "011" }, + { "Cape Verde", "CV", "238", 7, "00" }, + { "Cayman Islands", "KY", "1", 10, "011" }, + { "Central African Republic", "CF", "236", 8, "00" }, + { "Chad", "TD", "235", 8, "00" }, + { "Chile", "CL", "56", 9, "00" }, + { "China", "CN", "86", 11, "00" }, + { "Colombia", "CO", "57", 10, "00" }, + { "Comoros", "KM", "269", 7, "00" }, + { "Congo", "CG", "242", 9, "00" }, + { "Congo Democratic Republic", "CD", "243", 9, "00" }, + { "Cook Islands", "CK", "682", 5, "00" }, + { "Costa Rica", "CR", "506", 8, "00" }, + { "Cote d'Ivoire", "AD", "225", 8, "00" }, + { "Croatia", "HR", "385", 9, "00" }, + { "Cuba", "CU", "53", 8, "119" }, + { "Cyprus", "CY", "357", 8, "00" }, + { "Czech Republic", "CZ", "420", 9, "00" }, + { "Denmark", "DK", "45", 8, "00" }, + { "Djibouti", "DJ", "253", 8, "00" }, + { "Dominica", "DM", "1", 10, "011" }, + { "Dominican Republic", "DO", "1", 10, "011" }, + { "Ecuador", "EC", "593", 9, "00" }, + { "Egypt", "EG", "20", 10, "00" }, + { "El Salvador", "SV", "503", 8, "00" }, + { "Equatorial Guinea", "GQ", "240", 9, "00" }, + { "Eritrea", "ER", "291", 7, "00" }, + { "Estonia", "EE", "372", 8, "00" }, + { "Ethiopia", "ET", "251", 9, "00" }, + { "Falkland Islands", "FK", "500", 5, "00" }, + { "Faroe Islands", "FO", "298", 6, "00" }, + { "Fiji", "FJ", "679", 7, "00" }, + { "Finland", "FI", "358", 9, "00" }, + { "France", "FR", "33", 9, "00" }, + { "French Guiana", "GF", "594", 9, "00" }, + { "French Polynesia", "PF", "689", 6, "00" }, + { "Gabon", "GA", "241", 8, "00" }, + { "Gambia", "GM", "220", 7, "00" }, + { "Georgia", "GE", "995", 9, "00" }, + { "Germany", "DE", "49", 11, "00" }, + { "Ghana", "GH", "233", 9, "00" }, + { "Gibraltar", "GI", "350", 8, "00" }, + { "Greece", "GR", "30", 10, "00" }, + { "Greenland", "GL", "299", 6, "00" }, + { "Grenada", "GD", "1", 10, "011" }, + { "Guadeloupe", "GP", "590", 9, "00" }, + { "Guam", "GU", "1", 10, "011" }, + { "Guatemala", "GT", "502", 8, "00" }, + { "Guinea", "GN", "224", 8, "00" }, + { "Guinea-Bissau", "GW", "245", 7, "00" }, + { "Guyana", "GY", "592", 7, "001" }, + { "Haiti", "HT", "509", 8, "00" }, + { "Honduras", "HN", "504", 8, "00" }, + { "Hong Kong", "HK", "852", 8, "001" }, + { "Hungary", "HU", "36", 9, "00" }, + { "Iceland", "IS", "354", 9, "00" }, + { "India", "IN", "91", 10, "00" }, + { "Indonesia", "ID", "62", 10, "001" }, + { "Iran", "IR", "98", 10, "00" }, + { "Iraq", "IQ", "964", 10, "00" }, + { "Ireland", "IE", "353", 9, "00" }, + { "Israel", "IL", "972", 9, "00" }, + { "Italy", "IT", "39", 10, "00" }, + /* {"Jersey" ,"JE" , "44" , 10 , "00" },*/ + { "Jamaica", "JM", "1", 10, "011" }, + { "Japan", "JP", "81", 10, "010" }, + { "Jordan", "JO", "962", 9, "00" }, + { "Kazakhstan", "KZ", "7", 10, "00" }, + { "Kenya", "KE", "254", 9, "000" }, + { "Kiribati", "KI", "686", 5, "00" }, + { "Korea, North", "KP", "850", 12, "99" }, + { "Korea, South", "KR", "82", 12, "001" }, + { "Kuwait", "KW", "965", 8, "00" }, + { "Kyrgyzstan", "KG", "996", 9, "00" }, + { "Laos", "LA", "856", 10, "00" }, + { "Latvia", "LV", "371", 8, "00" }, + { "Lebanon", "LB", "961", 7, "00" }, + { "Lesotho", "LS", "266", 8, "00" }, + { "Liberia", "LR", "231", 8, "00" }, + { "Libya", "LY", "218", 8, "00" }, + { "Liechtenstein", "LI", "423", 7, "00" }, + { "Lithuania", "LT", "370", 8, "00" }, + { "Luxembourg", "LU", "352", 9, "00" }, + { "Macau", "MO", "853", 8, "00" }, + { "Macedonia", "MK", "389", 8, "00" }, + { "Madagascar", "MG", "261", 9, "00" }, + { "Malawi", "MW", "265", 9, "00" }, + { "Malaysia", "MY", "60", 9, "00" }, + { "Maldives", "MV", "960", 7, "00" }, + { "Mali", "ML", "223", 8, "00" }, + { "Malta", "MT", "356", 8, "00" }, + { "Marshall Islands", "MH", "692", 7, "011" }, + { "Martinique", "MQ", "596", 9, "00" }, + { "Mauritania", "MR", "222", 8, "00" }, + { "Mauritius", "MU", "230", 7, "00" }, + { "Mayotte Island", "YT", "262", 9, "00" }, + { "Mexico", "MX", "52", 10, "00" }, /*The following is a pseudo dial plan for Mexican mobile phones. See https://en.wikipedia.org/wiki/Telephone_numbers_in_Mexico*/ - {"Mexico" ,"MX" , "521" , 10 , "00" }, - {"Micronesia" ,"FM" , "691" , 7 , "011" }, - {"Moldova" ,"MD" , "373" , 8 , "00" }, - {"Monaco" ,"MC" , "377" , 8 , "00" }, - {"Mongolia" ,"MN" , "976" , 8 , "001" }, - {"Montenegro" ,"ME" , "382" , 8 , "00" }, - {"Montserrat" ,"MS" , "664" , 10 , "011" }, - {"Morocco" ,"MA" , "212" , 9 , "00" }, - {"Mozambique" ,"MZ" , "258" , 9 , "00" }, - {"Myanmar" ,"MM" , "95" , 10 , "00" }, - {"Namibia" ,"NA" , "264" , 9 , "00" }, - {"Nauru" ,"NR" , "674" , 7 , "00" }, - {"Nepal" ,"NP" , "43" , 10 , "00" }, - {"Netherlands" ,"NL" , "31" , 9 , "00" }, - {"New Caledonia" ,"NC" , "687" , 6 , "00" }, - {"New Zealand" ,"NZ" , "64" , 8 , "00" }, - {"Nicaragua" ,"NI" , "505" , 8 , "00" }, - {"Niger" ,"NE" , "227" , 8 , "00" }, - {"Nigeria" ,"NG" , "234" , 10 , "009" }, - {"Niue" ,"NU" , "683" , 4 , "00" }, - {"Norfolk Island" ,"NF" , "672" , 5 , "00" }, - {"Northern Mariana Islands" ,"MP" , "1" , 10 , "011" }, - {"Norway" ,"NO" , "47" , 8 , "00" }, - {"Oman" ,"OM" , "968" , 8 , "00" }, - {"Pakistan" ,"PK" , "92" , 10 , "00" }, - {"Palau" ,"PW" , "680" , 7 , "011" }, - {"Palestine" ,"PS" , "970" , 9 , "00" }, - {"Panama" ,"PA" , "507" , 8 , "00" }, - {"Papua New Guinea" ,"PG" , "675" , 8 , "00" }, - {"Paraguay" ,"PY" , "595" , 9 , "00" }, - {"Peru" ,"PE" , "51" , 9 , "00" }, - {"Philippines" ,"PH" , "63" , 10 , "00" }, - {"Poland" ,"PL" , "48" , 9 , "00" }, - {"Portugal" ,"PT" , "351" , 9 , "00" }, - {"Puerto Rico" ,"PR" , "1" , 10 , "011" }, - {"Qatar" ,"QA" , "974" , 8 , "00" }, - {"R�union Island" ,"RE" , "262" , 9 , "011" }, - {"Romania" ,"RO" , "40" , 9 , "00" }, - {"Russian Federation" ,"RU" , "7" , 10 , "8" }, - {"Rwanda" ,"RW" , "250" , 9 , "00" }, - {"Saint Helena" ,"SH" , "290" , 4 , "00" }, - {"Saint Kitts and Nevis" ,"KN" , "1" , 10 , "011" }, - {"Saint Lucia" ,"LC" , "1" , 10 , "011" }, - {"Saint Pierre and Miquelon" ,"PM" , "508" , 6 , "00" }, - {"Saint Vincent and the Grenadines","VC" , "1" , 10 , "011" }, - {"Samoa" ,"WS" , "685" , 7 , "0" }, - {"San Marino" ,"SM" , "378" , 10 , "00" }, - {"Sao Tome and Principe" ,"ST" , "239" , 7 , "00" }, - {"Saudi Arabia" ,"SA" , "966" , 9 , "00" }, - {"Senegal" ,"SN" , "221" , 9 , "00" }, - {"Serbia" ,"RS" , "381" , 9 , "00" }, - {"Seychelles" ,"SC" , "248" , 7 , "00" }, - {"Sierra Leone" ,"SL" , "232" , 8 , "00" }, - {"Singapore" ,"SG" , "65" , 8 , "001" }, - {"Slovakia" ,"SK" , "421" , 9 , "00" }, - {"Slovenia" ,"SI" , "386" , 8 , "00" }, - {"Solomon Islands" ,"SB" , "677" , 7 , "00" }, - {"Somalia" ,"SO" , "252" , 8 , "00" }, - {"South Africa" ,"ZA" , "27" , 9 , "00" }, - {"Spain" ,"ES" , "34" , 9 , "00" }, - {"Sri Lanka" ,"LK" , "94" , 9 , "00" }, - {"Sudan" ,"SD" , "249" , 9 , "00" }, - {"Suriname" ,"SR" , "597" , 7 , "00" }, - {"Swaziland" ,"SZ" , "268" , 8 , "00" }, - {"Sweden" ,"SE" , "46" , 9 , "00" }, - {"Switzerland" ,"XK" , "41" , 9 , "00" }, - {"Syria" ,"SY" , "963" , 9 , "00" }, - {"Taiwan" ,"TW" , "886" , 9 , "810" }, - {"Tajikistan" ,"TJ" , "992" , 9 , "002" }, - {"Tanzania" ,"TZ" , "255" , 9 , "000" }, - {"Thailand" ,"TH" , "66" , 9 , "001" }, - {"Togo" ,"TG" , "228" , 8 , "00" }, - {"Tokelau" ,"TK" , "690" , 4 , "00" }, - {"Tonga" ,"TO" , "676" , 5 , "00" }, - {"Trinidad and Tobago" ,"TT" , "1" , 10 , "011" }, - {"Tunisia" ,"TN" , "216" , 8 , "00" }, - {"Turkey" ,"TR" , "90" , 10 , "00" }, - {"Turkmenistan" ,"TM" , "993" , 8 , "00" }, - {"Turks and Caicos Islands" ,"TC" , "1" , 7 , "0" }, - {"Tuvalu" ,"TV" , "688" , 5 , "00" }, - {"Uganda" ,"UG" , "256" , 9 , "000" }, - {"Ukraine" ,"UA" , "380" , 9 , "00" }, - {"United Arab Emirates" ,"AE" , "971" , 9 , "00" }, - {"United Kingdom" ,"GB" , "44" , 10 , "00" }, -/* {"United Kingdom" ,"UK" , "44" , 10 , "00" },*/ - {"United States" ,"US" , "1" , 10 , "011" }, - {"Uruguay" ,"UY" , "598" , 8 , "00" }, - {"Uzbekistan" ,"UZ" , "998" , 9 , "8" }, - {"Vanuatu" ,"VU" , "678" , 7 , "00" }, - {"Venezuela" ,"VE" , "58" , 10 , "00" }, - {"Vietnam" ,"VN" , "84" , 9 , "00" }, - {"Wallis and Futuna" ,"WF" , "681" , 5 , "00" }, - {"Yemen" ,"YE" , "967" , 9 , "00" }, - {"Zambia" ,"ZM" , "260" , 9 , "00" }, - {"Zimbabwe" ,"ZW" , "263" , 9 , "00" } + { "Mexico", "MX", "521", 10, "00" }, + { "Micronesia", "FM", "691", 7, "011" }, + { "Moldova", "MD", "373", 8, "00" }, + { "Monaco", "MC", "377", 8, "00" }, + { "Mongolia", "MN", "976", 8, "001" }, + { "Montenegro", "ME", "382", 8, "00" }, + { "Montserrat", "MS", "664", 10, "011" }, + { "Morocco", "MA", "212", 9, "00" }, + { "Mozambique", "MZ", "258", 9, "00" }, + { "Myanmar", "MM", "95", 10, "00" }, + { "Namibia", "NA", "264", 9, "00" }, + { "Nauru", "NR", "674", 7, "00" }, + { "Nepal", "NP", "43", 10, "00" }, + { "Netherlands", "NL", "31", 9, "00" }, + { "New Caledonia", "NC", "687", 6, "00" }, + { "New Zealand", "NZ", "64", 8, "00" }, + { "Nicaragua", "NI", "505", 8, "00" }, + { "Niger", "NE", "227", 8, "00" }, + { "Nigeria", "NG", "234", 10, "009" }, + { "Niue", "NU", "683", 4, "00" }, + { "Norfolk Island", "NF", "672", 5, "00" }, + { "Northern Mariana Islands", "MP", "1", 10, "011" }, + { "Norway", "NO", "47", 8, "00" }, + { "Oman", "OM", "968", 8, "00" }, + { "Pakistan", "PK", "92", 10, "00" }, + { "Palau", "PW", "680", 7, "011" }, + { "Palestine", "PS", "970", 9, "00" }, + { "Panama", "PA", "507", 8, "00" }, + { "Papua New Guinea", "PG", "675", 8, "00" }, + { "Paraguay", "PY", "595", 9, "00" }, + { "Peru", "PE", "51", 9, "00" }, + { "Philippines", "PH", "63", 10, "00" }, + { "Poland", "PL", "48", 9, "00" }, + { "Portugal", "PT", "351", 9, "00" }, + { "Puerto Rico", "PR", "1", 10, "011" }, + { "Qatar", "QA", "974", 8, "00" }, + { "R�union Island", "RE", "262", 9, "011" }, + { "Romania", "RO", "40", 9, "00" }, + { "Russian Federation", "RU", "7", 10, "8" }, + { "Rwanda", "RW", "250", 9, "00" }, + { "Saint Helena", "SH", "290", 4, "00" }, + { "Saint Kitts and Nevis", "KN", "1", 10, "011" }, + { "Saint Lucia", "LC", "1", 10, "011" }, + { "Saint Pierre and Miquelon", "PM", "508", 6, "00" }, + { "Saint Vincent and the Grenadines", "VC", "1", 10, "011" }, + { "Samoa", "WS", "685", 7, "0" }, + { "San Marino", "SM", "378", 10, "00" }, + { "Sao Tome and Principe", "ST", "239", 7, "00" }, + { "Saudi Arabia", "SA", "966", 9, "00" }, + { "Senegal", "SN", "221", 9, "00" }, + { "Serbia", "RS", "381", 9, "00" }, + { "Seychelles", "SC", "248", 7, "00" }, + { "Sierra Leone", "SL", "232", 8, "00" }, + { "Singapore", "SG", "65", 8, "001" }, + { "Slovakia", "SK", "421", 9, "00" }, + { "Slovenia", "SI", "386", 8, "00" }, + { "Solomon Islands", "SB", "677", 7, "00" }, + { "Somalia", "SO", "252", 8, "00" }, + { "South Africa", "ZA", "27", 9, "00" }, + { "Spain", "ES", "34", 9, "00" }, + { "Sri Lanka", "LK", "94", 9, "00" }, + { "Sudan", "SD", "249", 9, "00" }, + { "Suriname", "SR", "597", 7, "00" }, + { "Swaziland", "SZ", "268", 8, "00" }, + { "Sweden", "SE", "46", 9, "00" }, + { "Switzerland", "XK", "41", 9, "00" }, + { "Syria", "SY", "963", 9, "00" }, + { "Taiwan", "TW", "886", 9, "810" }, + { "Tajikistan", "TJ", "992", 9, "002" }, + { "Tanzania", "TZ", "255", 9, "000" }, + { "Thailand", "TH", "66", 9, "001" }, + { "Togo", "TG", "228", 8, "00" }, + { "Tokelau", "TK", "690", 4, "00" }, + { "Tonga", "TO", "676", 5, "00" }, + { "Trinidad and Tobago", "TT", "1", 10, "011" }, + { "Tunisia", "TN", "216", 8, "00" }, + { "Turkey", "TR", "90", 10, "00" }, + { "Turkmenistan", "TM", "993", 8, "00" }, + { "Turks and Caicos Islands", "TC", "1", 7, "0" }, + { "Tuvalu", "TV", "688", 5, "00" }, + { "Uganda", "UG", "256", 9, "000" }, + { "Ukraine", "UA", "380", 9, "00" }, + { "United Arab Emirates", "AE", "971", 9, "00" }, + { "United Kingdom", "GB", "44", 10, "00" }, + /* {"United Kingdom" ,"UK" , "44" , 10 , "00" },*/ + { "United States", "US", "1", 10, "011" }, + { "Uruguay", "UY", "598", 8, "00" }, + { "Uzbekistan", "UZ", "998", 9, "8" }, + { "Vanuatu", "VU", "678", 7, "00" }, + { "Venezuela", "VE", "58", 10, "00" }, + { "Vietnam", "VN", "84", 9, "00" }, + { "Wallis and Futuna", "WF", "681", 5, "00" }, + { "Yemen", "YE", "967", 9, "00" }, + { "Zambia", "ZM", "260", 9, "00" }, + { "Zimbabwe", "ZW", "263", 9, "00" } }; const DialPlan DialPlan::MostCommon("generic", "", "", 10, "00"); -DialPlan::DialPlan (const string &country, const string &isoCountryCode, const string &ccc, int nnl, const string &icp) : ClonableObject(*new DialPlanPrivate) { +DialPlan::DialPlan ( + const string &country, + const string &isoCountryCode, + const string &ccc, + int nnl, + const string &icp +) : ClonableObject(*new DialPlanPrivate) { L_D(); - d->country = country; - d->isoCountryCode = isoCountryCode; - d->countryCallingCode = ccc; - d->nationalNumberLength = nnl; - d->internationalCallPrefix = icp; + d->country = country; + d->isoCountryCode = isoCountryCode; + d->countryCallingCode = ccc; + d->nationalNumberLength = nnl; + d->internationalCallPrefix = icp; } DialPlan::DialPlan (const DialPlan &src) : ClonableObject(*new DialPlanPrivate) { L_D(); d->country = src.getCountry(); - d->isoCountryCode = src.getIsoCountryCode(); - d->countryCallingCode = src.getCountryCallingCode(); - d->nationalNumberLength = src.getNationalNumberLength(); - d->internationalCallPrefix = src.getInternationalCallPrefix(); -} - -DialPlan::~DialPlan () { - + d->isoCountryCode = src.getIsoCountryCode(); + d->countryCallingCode = src.getCountryCallingCode(); + d->nationalNumberLength = src.getNationalNumberLength(); + d->internationalCallPrefix = src.getInternationalCallPrefix(); } DialPlan &DialPlan::operator= (const DialPlan &src) { - L_D(); - + L_D(); + if (this != &src) { d->country = src.getCountry(); - d->isoCountryCode = src.getIsoCountryCode(); - d->countryCallingCode = src.getCountryCallingCode(); - d->nationalNumberLength = src.getNationalNumberLength(); - d->internationalCallPrefix = src.getInternationalCallPrefix(); + d->isoCountryCode = src.getIsoCountryCode(); + d->countryCallingCode = src.getCountryCallingCode(); + d->nationalNumberLength = src.getNationalNumberLength(); + d->internationalCallPrefix = src.getInternationalCallPrefix(); } return *this; } -const string& DialPlan::getCountry() const { - L_D(); - return d->country; +const string &DialPlan::getCountry () const { + L_D(); + return d->country; } -const string& DialPlan::getIsoCountryCode() const { - L_D(); - return d->isoCountryCode; -} - -const string& DialPlan::getCountryCallingCode() const { - L_D(); - return d->countryCallingCode; -} - -int DialPlan::getNationalNumberLength() const { - L_D(); - return d->nationalNumberLength; -} - -const string& DialPlan::getInternationalCallPrefix() const { - L_D(); - return d->internationalCallPrefix; +const string &DialPlan::getIsoCountryCode () const { + L_D(); + return d->isoCountryCode; } -bool DialPlan::isGeneric() const { - L_D(); - return d->country == MostCommon.getCountry(); +const string &DialPlan::getCountryCallingCode () const { + L_D(); + return d->countryCallingCode; } -int DialPlan::lookupCccFromE164(string e164) { - if (e164[0] != '+') { - return -1; /*not an e164 number*/ - } - if (e164[1]=='1') { /*USA case*/ +int DialPlan::getNationalNumberLength () const { + L_D(); + return d->nationalNumberLength; +} + +const string &DialPlan::getInternationalCallPrefix () const { + L_D(); + return d->internationalCallPrefix; +} + +bool DialPlan::isGeneric () const { + L_D(); + return d->country == MostCommon.getCountry(); +} + +int DialPlan::lookupCccFromE164 (const string &e164) { + if (e164[0] != '+') + return -1; // Not an e164 number. + + // USA case. + if (e164[1] == '1') return 1; - } - DialPlan electedDialPlan; + DialPlan electedDialPlan; unsigned int found; unsigned int i = 0; do { found = 0; - i++; - for (const auto &dp : DialPlans) { - if (strncmp(dp.getCountryCallingCode().c_str(), &e164[1], i) == 0) { - electedDialPlan = dp; - found++; - } - } - } while ((found > 1 || found == 0) && i < e164.length() - 1); - - if (found == 1) { - return atoi(electedDialPlan.getCountryCallingCode().c_str()); - } else { - return -1; /*not found */ - } -} + i++; + for (const auto &dp : DialPlanPrivate::DialPlans) { + if (strncmp(dp.getCountryCallingCode().c_str(), &e164[1], i) == 0) { + electedDialPlan = dp; + found++; + } + } + } while ((found > 1 || found == 0) && i < e164.length() - 1); + + if (found == 1) + return Utils::stoi(electedDialPlan.getCountryCallingCode()); -int DialPlan::lookupCccFromIso(string iso) { - for (const auto &dp : DialPlans) { - if (dp.getIsoCountryCode() == iso) { - return atoi(dp.getCountryCallingCode().c_str()); - } - } return -1; } -const DialPlan& DialPlan::findByCccAsInt(int ccc) { - string cccString = Utils::toString(ccc); - return DialPlan::findByCcc(cccString); +int DialPlan::lookupCccFromIso (const string &iso) { + for (const auto &dp : DialPlanPrivate::DialPlans) { + if (dp.getIsoCountryCode() == iso) + return Utils::stoi(dp.getCountryCallingCode()); + } + + return -1; } -const DialPlan& DialPlan::findByCcc(const string& ccc) { - if (ccc.empty()) { - return MostCommon; - } +const DialPlan &DialPlan::findByCccAsInt (int ccc) { + return DialPlan::findByCcc(Utils::toString(ccc)); +} - for (const auto &dp : DialPlans) { - if (dp.getCountryCallingCode() == ccc) { - return dp; - } - } - /*else return a generic "most common" dial plan*/ +const DialPlan &DialPlan::findByCcc (const string &ccc) { + if (ccc.empty()) + return MostCommon; + + for (const auto &dp : DialPlanPrivate::DialPlans) { + if (dp.getCountryCallingCode() == ccc) + return dp; + } + + // Return a generic "most common" dial plan. return MostCommon; } -const std::list& DialPlan::getAllDialPlans() { - return DialPlans; +const list &DialPlan::getAllDialPlans () { + return DialPlanPrivate::DialPlans; } -LINPHONE_END_NAMESPACE \ No newline at end of file +LINPHONE_END_NAMESPACE diff --git a/src/dial-plan/dial-plan.h b/src/dial-plan/dial-plan.h index f7f51ec8d..62edde4a3 100644 --- a/src/dial-plan/dial-plan.h +++ b/src/dial-plan/dial-plan.h @@ -32,30 +32,33 @@ class DialPlanPrivate; class LINPHONE_PUBLIC DialPlan : public ClonableObject { public: - DialPlan (const std::string &country = "", const std::string &isoCountryCode = "", const std::string &ccc = "", int nnl = 0, const std::string &icp = ""); + DialPlan ( + const std::string &country = "", + const std::string &isoCountryCode = "", + const std::string &ccc = "", + int nnl = 0, + const std::string &icp = "" + ); DialPlan (const DialPlan &src); - ~DialPlan (); DialPlan &operator= (const DialPlan &src); - const std::string& getCountry() const; - const std::string& getIsoCountryCode() const; - const std::string& getCountryCallingCode() const; - int getNationalNumberLength() const; - const std::string& getInternationalCallPrefix() const; - bool isGeneric() const; + const std::string &getCountry () const; + const std::string &getIsoCountryCode () const; + const std::string &getCountryCallingCode () const; + int getNationalNumberLength () const; + const std::string &getInternationalCallPrefix () const; + bool isGeneric () const; static const DialPlan MostCommon; - static int lookupCccFromE164(std::string e164); - static int lookupCccFromIso(std::string iso); - static const DialPlan& findByCccAsInt(int ccc); - static const DialPlan& findByCcc(const std::string& ccc); - static const std::list& getAllDialPlans(); + static int lookupCccFromE164 (const std::string &e164); + static int lookupCccFromIso (const std::string &iso); + static const DialPlan &findByCccAsInt (int ccc); + static const DialPlan &findByCcc (const std::string &ccc); + static const std::list &getAllDialPlans (); private: - static std::list const DialPlans; - L_DECLARE_PRIVATE(DialPlan); }; From ebe1a5f12fe8569ca4df9db3395ce45f664e31aa Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 17 Oct 2017 14:51:45 +0200 Subject: [PATCH 0522/2215] add time managment to confernce event notification --- src/chat/chat-room/client-group-chat-room.cpp | 12 ++++----- src/chat/chat-room/client-group-chat-room.h | 12 ++++----- src/conference/conference-listener.h | 13 +++++----- .../local-conference-event-handler.cpp | 9 +++++++ .../remote-conference-event-handler.cpp | 16 +++++++----- src/conference/remote-conference.cpp | 12 ++++----- src/conference/remote-conference.h | 12 ++++----- tester/conference-event-tester.cpp | 25 ++++++++++--------- 8 files changed, 63 insertions(+), 48 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 15d7d0251..af63cc759 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -257,7 +257,7 @@ void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { d->setState(ChatRoom::State::Terminated); } -void ClientGroupChatRoom::onParticipantAdded (const Address &addr) { +void ClientGroupChatRoom::onParticipantAdded (time_t tm, const Address &addr) { L_D_T(RemoteConference, dConference); if (isMe(addr)) @@ -278,7 +278,7 @@ void ClientGroupChatRoom::onParticipantAdded (const Address &addr) { cb(cr, L_GET_C_BACK_PTR(participant)); } -void ClientGroupChatRoom::onParticipantRemoved (const Address &addr) { +void ClientGroupChatRoom::onParticipantRemoved (time_t tm, const Address &addr) { L_D_T(RemoteConference, dConference); shared_ptr participant = findParticipant(addr); @@ -297,7 +297,7 @@ void ClientGroupChatRoom::onParticipantRemoved (const Address &addr) { dConference->participants.remove(participant); } -void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdmin) { +void ClientGroupChatRoom::onParticipantSetAdmin (time_t tm, const Address &addr, bool isAdmin) { shared_ptr participant; if (isMe(addr)) participant = getMe(); @@ -317,7 +317,7 @@ void ClientGroupChatRoom::onParticipantSetAdmin (const Address &addr, bool isAdm cb(cr, L_GET_C_BACK_PTR(participant), isAdmin); } -void ClientGroupChatRoom::onSubjectChanged (const std::string &subject) { +void ClientGroupChatRoom::onSubjectChanged (time_t tm, const std::string &subject) { RemoteConference::setSubject(subject); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); @@ -327,7 +327,7 @@ void ClientGroupChatRoom::onSubjectChanged (const std::string &subject) { cb(cr, subject.c_str()); } -void ClientGroupChatRoom::onParticipantDeviceAdded (const Address &addr, const Address &gruu) { +void ClientGroupChatRoom::onParticipantDeviceAdded (time_t tm, const Address &addr, const Address &gruu) { shared_ptr participant; if (isMe(addr)) participant = getMe(); @@ -340,7 +340,7 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (const Address &addr, const A participant->getPrivate()->addDevice(gruu); } -void ClientGroupChatRoom::onParticipantDeviceRemoved (const Address &addr, const Address &gruu) { +void ClientGroupChatRoom::onParticipantDeviceRemoved (time_t tm, const Address &addr, const Address &gruu) { shared_ptr participant; if (isMe(addr)) participant = getMe(); diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 0d9432ccb..52f176d00 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -56,12 +56,12 @@ private: /* ConferenceListener */ void onConferenceCreated (const Address &addr) override; void onConferenceTerminated (const Address &addr) override; - void onParticipantAdded (const Address &addr) override; - void onParticipantRemoved (const Address &addr) override; - void onParticipantSetAdmin (const Address &addr, bool isAdmin) override; - void onSubjectChanged (const std::string &subject) override; - void onParticipantDeviceAdded (const Address &addr, const Address &gruu) override; - void onParticipantDeviceRemoved (const Address &addr, const Address &gruu) override; + void onParticipantAdded (time_t tm, const Address &addr) override; + void onParticipantRemoved (time_t tm, const Address &addr) override; + void onParticipantSetAdmin (time_t tm, const Address &addr, bool isAdmin) override; + void onSubjectChanged (time_t tm, const std::string &subject) override; + void onParticipantDeviceAdded (time_t tm, const Address &addr, const Address &gruu) override; + void onParticipantDeviceRemoved (time_t tm, const Address &addr, const Address &gruu) override; private: /* CallSessionListener */ diff --git a/src/conference/conference-listener.h b/src/conference/conference-listener.h index 96c30528e..248052fb6 100644 --- a/src/conference/conference-listener.h +++ b/src/conference/conference-listener.h @@ -20,6 +20,7 @@ #ifndef _CONFERENCE_LISTENER_H_ #define _CONFERENCE_LISTENER_H_ +#include #include #include "linphone/utils/general.h" @@ -34,12 +35,12 @@ class ConferenceListener { public: virtual void onConferenceCreated (const Address &addr) = 0; virtual void onConferenceTerminated (const Address &addr) = 0; - virtual void onParticipantAdded (const Address &addr) = 0; - virtual void onParticipantRemoved (const Address &addr) = 0; - virtual void onParticipantSetAdmin (const Address &addr, bool isAdmin) = 0; - virtual void onSubjectChanged (const std::string &subject) = 0; - virtual void onParticipantDeviceAdded (const Address &addr, const Address &gruu) = 0; - virtual void onParticipantDeviceRemoved (const Address &addr, const Address &gruu) = 0; + virtual void onParticipantAdded (time_t tm, const Address &addr) = 0; + virtual void onParticipantRemoved (time_t tm, const Address &addr) = 0; + virtual void onParticipantSetAdmin (time_t tm, const Address &addr, bool isAdmin) = 0; + virtual void onSubjectChanged (time_t tm, const std::string &subject) = 0; + virtual void onParticipantDeviceAdded (time_t tm, const Address &addr, const Address &gruu) = 0; + virtual void onParticipantDeviceRemoved (time_t tm, const Address &addr, const Address &gruu) = 0; }; LINPHONE_END_NAMESPACE diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index ec6a0cd0c..92c6149e2 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -17,6 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include + #include "conference/local-conference.h" #include "conference/participant-p.h" #include "linphone/utils/utils.h" @@ -68,6 +70,13 @@ void LocalConferenceEventHandlerPrivate::notifyAll (const string ¬ify) { string LocalConferenceEventHandlerPrivate::createNotify (ConferenceType confInfo) { lastNotify = lastNotify + 1; confInfo.setVersion(lastNotify); + if (!confInfo.getConferenceDescription()) { + ConferenceDescriptionType description = ConferenceDescriptionType(); + confInfo.setConferenceDescription(description); + } + + time_t result = time(nullptr); + confInfo.getConferenceDescription()->setFreeText(Utils::toString(static_cast(result))); stringstream notify; Xsd::XmlSchema::NamespaceInfomap map; diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 53eeaf20a..685f2ef7d 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -73,11 +73,15 @@ void RemoteConferenceEventHandler::notifyReceived (string xmlBody) { lInfo() << "NOTIFY received for conference " << d->confAddress.asString(); istringstream data(xmlBody); unique_ptr confInfo = parseConferenceInfo(data, Xsd::XmlSchema::Flags::dont_validate); + time_t tm = time(nullptr); + if (confInfo->getConferenceDescription()->getFreeText().present()) + tm = static_cast(Utils::stoll(confInfo->getConferenceDescription()->getFreeText().get())); + Address cleanedConfAddress = d->confAddress; cleanedConfAddress.setPort(0); if (confInfo->getEntity() == cleanedConfAddress.asString()) { if (confInfo->getConferenceDescription().present() && confInfo->getConferenceDescription().get().getSubject().present()) - d->listener->onSubjectChanged(confInfo->getConferenceDescription().get().getSubject().get()); + d->listener->onSubjectChanged(tm, confInfo->getConferenceDescription().get().getSubject().get()); if (confInfo->getVersion().present()) d->lastNotify = confInfo->getVersion().get(); @@ -91,7 +95,7 @@ void RemoteConferenceEventHandler::notifyReceived (string xmlBody) { Address addr(cAddrStr); bctbx_free(cAddrStr); if (user.getState() == "deleted") - d->listener->onParticipantRemoved(addr); + d->listener->onParticipantRemoved(tm, addr); else { bool isAdmin = false; if (user.getRoles()) { @@ -103,17 +107,17 @@ void RemoteConferenceEventHandler::notifyReceived (string xmlBody) { } } if (user.getState() == "full") - d->listener->onParticipantAdded(addr); - d->listener->onParticipantSetAdmin(addr, isAdmin); + d->listener->onParticipantAdded(tm, addr); + d->listener->onParticipantSetAdmin(tm, addr, isAdmin); for (const auto &endpoint : user.getEndpoint()) { if (!endpoint.getEntity().present()) break; Address gruu(endpoint.getEntity().get()); if (endpoint.getState() == "deleted") - d->listener->onParticipantDeviceRemoved(addr, gruu); + d->listener->onParticipantDeviceRemoved(tm, addr, gruu); else if (endpoint.getState() == "full") - d->listener->onParticipantDeviceAdded(addr, gruu); + d->listener->onParticipantDeviceAdded(tm, addr, gruu); } } diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index 9fa0df9d0..3b317a10e 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -89,16 +89,16 @@ void RemoteConference::onConferenceTerminated (const Address &addr) { d->eventHandler->unsubscribe(); } -void RemoteConference::onParticipantAdded (const Address &addr) {} +void RemoteConference::onParticipantAdded (time_t tm, const Address &addr) {} -void RemoteConference::onParticipantRemoved (const Address &addr) {} +void RemoteConference::onParticipantRemoved (time_t tm, const Address &addr) {} -void RemoteConference::onParticipantSetAdmin (const Address &addr, bool isAdmin) {} +void RemoteConference::onParticipantSetAdmin (time_t tm, const Address &addr, bool isAdmin) {} -void RemoteConference::onSubjectChanged (const std::string &subject) {} +void RemoteConference::onSubjectChanged (time_t tm, const std::string &subject) {} -void RemoteConference::onParticipantDeviceAdded (const Address &addr, const Address &gruu) {} +void RemoteConference::onParticipantDeviceAdded (time_t tm, const Address &addr, const Address &gruu) {} -void RemoteConference::onParticipantDeviceRemoved (const Address &addr, const Address &gruu) {} +void RemoteConference::onParticipantDeviceRemoved (time_t tm, const Address &addr, const Address &gruu) {} LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index fb8b80ee8..f1898f10c 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -46,12 +46,12 @@ protected: /* ConferenceListener */ void onConferenceCreated (const Address &addr) override; void onConferenceTerminated (const Address &addr) override; - void onParticipantAdded (const Address &addr) override; - void onParticipantRemoved (const Address &addr) override; - void onParticipantSetAdmin (const Address &addr, bool isAdmin) override; - void onSubjectChanged (const std::string &subject) override; - void onParticipantDeviceAdded (const Address &addr, const Address &gruu) override; - void onParticipantDeviceRemoved (const Address &addr, const Address &gruu) override; + void onParticipantAdded (time_t tm, const Address &addr) override; + void onParticipantRemoved (time_t tm, const Address &addr) override; + void onParticipantSetAdmin (time_t tm, const Address &addr, bool isAdmin) override; + void onSubjectChanged (time_t tm, const std::string &subject) override; + void onParticipantDeviceAdded (time_t tm, const Address &addr, const Address &gruu) override; + void onParticipantDeviceRemoved (time_t tm, const Address &addr, const Address &gruu) override; private: L_DECLARE_PRIVATE(RemoteConference); diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index 72b78453b..c12317ac7 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -447,12 +447,13 @@ public: private: void onConferenceCreated (const Address &addr) override; void onConferenceTerminated (const Address &addr) override; - void onParticipantAdded (const Address &addr) override; - void onParticipantRemoved (const Address &addr) override; - void onParticipantSetAdmin (const Address &addr, bool isAdmin) override; - void onSubjectChanged(const string &subject) override; - void onParticipantDeviceAdded(const Address &addr, const Address &gruu) override; - void onParticipantDeviceRemoved(const Address &addr, const Address &gruu) override; + void onParticipantAdded (time_t tm, const Address &addr) override; + void onParticipantRemoved (time_t tm, const Address &addr) override; + void onParticipantSetAdmin (time_t tm, const Address &addr, bool isAdmin) override; + void onSubjectChanged (time_t tm, const string &subject) override; + void onParticipantDeviceAdded (time_t tm, const Address &addr, const Address &gruu) override; + void onParticipantDeviceRemoved (time_t tm, const Address &addr, const Address &gruu) override; + public: RemoteConferenceEventHandler *handler; map participants; @@ -472,33 +473,33 @@ void ConferenceEventTester::onConferenceCreated (const Address &addr) {} void ConferenceEventTester::onConferenceTerminated (const Address &addr) {} -void ConferenceEventTester::onParticipantAdded (const Address &addr) { +void ConferenceEventTester::onParticipantAdded (time_t tm, const Address &addr) { participants.insert(pair(addr.asString(), FALSE)); participantDevices.insert(pair(addr.asString(), 0)); } -void ConferenceEventTester::onParticipantRemoved (const Address &addr) { +void ConferenceEventTester::onParticipantRemoved (time_t tm, const Address &addr) { participants.erase(addr.asString()); participantDevices.erase(addr.asString()); } -void ConferenceEventTester::onParticipantSetAdmin (const Address &addr, bool isAdmin) { +void ConferenceEventTester::onParticipantSetAdmin (time_t tm, const Address &addr, bool isAdmin) { auto it = participants.find(addr.asString()); if (it != participants.end()) it->second = isAdmin; } -void ConferenceEventTester::onSubjectChanged(const string &subject) { +void ConferenceEventTester::onSubjectChanged(time_t tm, const string &subject) { confSubject = subject; } -void ConferenceEventTester::onParticipantDeviceAdded (const Address &addr, const Address &gruu) { +void ConferenceEventTester::onParticipantDeviceAdded (time_t tm, const Address &addr, const Address &gruu) { auto it = participantDevices.find(addr.asString()); if (it != participantDevices.end()) it->second++; } -void ConferenceEventTester::onParticipantDeviceRemoved (const Address &addr, const Address &gruu) { +void ConferenceEventTester::onParticipantDeviceRemoved (time_t tm, const Address &addr, const Address &gruu) { auto it = participantDevices.find(addr.asString()); if (it != participantDevices.end() && it->second > 0) it->second--; From 5fed24efc8cbacce6f436b2ed109bc3bb2c23fa3 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 17 Oct 2017 15:48:07 +0200 Subject: [PATCH 0523/2215] Added linphone_config_get_bool and linphone_config_set_bool for Java wrapper + fixes for some Java classes --- coreapi/lpconfig.c | 19 ++++- include/linphone/lpconfig.h | 12 +++ wrappers/java/classes/Utils.java | 4 +- wrappers/java/classes/tools/H264Helper.java | 36 ++++----- wrappers/java/classes/tools/Lpc2Xml.java | 4 +- wrappers/java/classes/tools/Xml2Lpc.java | 4 +- wrappers/java/migration.sh | 81 ++++++++++++++++----- 7 files changed, 116 insertions(+), 44 deletions(-) diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index 36c512234..66c8c6e67 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -648,7 +648,6 @@ bool_t linphone_config_get_range(const LpConfig *lpconfig, const char *section, } } - int linphone_config_get_int(const LpConfig *lpconfig,const char *section, const char *key, int default_value){ const char *str=linphone_config_get_string(lpconfig,section,key,NULL); if (str!=NULL) { @@ -663,6 +662,16 @@ int linphone_config_get_int(const LpConfig *lpconfig,const char *section, const else return default_value; } +bool_t linphone_config_get_bool(const LpConfig *lpconfig, const char *section, const char *key, bool_t default_value) { + const char *str = linphone_config_get_string(lpconfig, section, key, NULL); + if (str != NULL) { + int ret = 0; + sscanf(str, "%i", &ret); + return ret != 0; + } + return default_value; +} + int64_t linphone_config_get_int64(const LpConfig *lpconfig,const char *section, const char *key, int64_t default_value){ const char *str=linphone_config_get_string(lpconfig,section,key,NULL); if (str!=NULL) { @@ -775,6 +784,14 @@ void linphone_config_set_int(LpConfig *lpconfig,const char *section, const char linphone_config_set_string(lpconfig,section,key,tmp); } +void linphone_config_set_bool(LpConfig *lpconfig, const char *section, const char *key, bool_t value) { + if (value) { + linphone_config_set_int(lpconfig, section, key, 1); + } else { + linphone_config_set_int(lpconfig, section, key, 0); + } +} + void linphone_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *key, int value){ char tmp[30]; snprintf(tmp,sizeof(tmp),"0x%x",value); diff --git a/include/linphone/lpconfig.h b/include/linphone/lpconfig.h index 1a9d17dbf..eadab533b 100644 --- a/include/linphone/lpconfig.h +++ b/include/linphone/lpconfig.h @@ -132,6 +132,13 @@ LINPHONE_PUBLIC bool_t linphone_config_get_range(const LinphoneConfig *lpconfig, **/ LINPHONE_PUBLIC int linphone_config_get_int(const LinphoneConfig *lpconfig,const char *section, const char *key, int default_value); +/** + * Retrieves a configuration item as a boolean, given its section, key, and default value. + * + * The default boolean value is returned if the config item isn't found. +**/ +LINPHONE_PUBLIC bool_t linphone_config_get_bool(const LpConfig *lpconfig, const char *section, const char *key, bool_t default_value); + /** * Retrieves a configuration item as a 64 bit integer, given its section, key, and default value. * @@ -170,6 +177,11 @@ LINPHONE_PUBLIC void linphone_config_set_range(LinphoneConfig *lpconfig, const c **/ LINPHONE_PUBLIC void linphone_config_set_int(LinphoneConfig *lpconfig,const char *section, const char *key, int value); +/** + * Sets a boolean config item +**/ +LINPHONE_PUBLIC void linphone_config_set_bool(LinphoneConfig *lpconfig,const char *section, const char *key, bool_t value); + /** * Sets an integer config item, but store it as hexadecimal **/ diff --git a/wrappers/java/classes/Utils.java b/wrappers/java/classes/Utils.java index 19eeb9718..0f9b55708 100644 --- a/wrappers/java/classes/Utils.java +++ b/wrappers/java/classes/Utils.java @@ -20,10 +20,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. package org.linphone.core; public class Utils { - public static int getPrefixFromE164(String e164) { + public static String getPrefixFromE164(String e164) { DialPlan[] dialPlans = Factory.instance().getDialPlans(); DialPlan dialPlan = dialPlans[0]; - return dialPlan.lookupCccFromE164(e164); + return String.valueOf(dialPlan.lookupCccFromE164(e164)); } public static int getCccFromIso(String countryIso) { diff --git a/wrappers/java/classes/tools/H264Helper.java b/wrappers/java/classes/tools/H264Helper.java index 421d44f6f..abebb882c 100644 --- a/wrappers/java/classes/tools/H264Helper.java +++ b/wrappers/java/classes/tools/H264Helper.java @@ -3,7 +3,7 @@ package org.linphone.core.tools; import android.os.Build; -import org.linphone.core.LinphoneCore; +import org.linphone.core.Core; import org.linphone.mediastream.Log; /** @@ -36,38 +36,38 @@ public class H264Helper { * - Mediacodec to enable Mediacodec only. * @param mode String value between Auto, OpenH264 and MediaCodec */ - public static void setH264Mode(String mode, LinphoneCore linphoneCore){ + public static void setH264Mode(String mode, Core linphoneCore){ if(mode.equals(MODE_OPENH264)){ Log.i("H264Helper"," setH264Mode MODE_OPENH264 - Mode = "+mode); - linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_DEC , false); - linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_ENC , false); - linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_DEC , true); - linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_ENC , true); + linphoneCore.getMediastreamerFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_DEC , false); + linphoneCore.getMediastreamerFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_ENC , false); + linphoneCore.getMediastreamerFactory().enableFilterFromName(FILTER_NAME_OPENH264_DEC , true); + linphoneCore.getMediastreamerFactory().enableFilterFromName(FILTER_NAME_OPENH264_ENC , true); }else if(mode.equals(MODE_MEDIA_CODEC)){ Log.i("H264Helper"," setH264Mode MODE_MEDIA_CODEC - Mode = "+mode); - linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_DEC , false); - linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_ENC , false); - linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_DEC , true); - linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_ENC , true); + linphoneCore.getMediastreamerFactory().enableFilterFromName(FILTER_NAME_OPENH264_DEC , false); + linphoneCore.getMediastreamerFactory().enableFilterFromName(FILTER_NAME_OPENH264_ENC , false); + linphoneCore.getMediastreamerFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_DEC , true); + linphoneCore.getMediastreamerFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_ENC , true); }else if(mode.equals(MODE_AUTO)){ Log.i("H264Helper"," setH264Mode MODE_AUTO - Mode = "+mode); // if android >= 5.0 use MediaCodec if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { Log.i("H264Helper"," setH264Mode MODE_AUTO 1 - Mode = "+mode); Log.i("H264Helper"," Openh264 disabled on the project, now using MediaCodec"); - linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_DEC , false); - linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_ENC , false); - linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_DEC , true); - linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_ENC , true); + linphoneCore.getMediastreamerFactory().enableFilterFromName(FILTER_NAME_OPENH264_DEC , false); + linphoneCore.getMediastreamerFactory().enableFilterFromName(FILTER_NAME_OPENH264_ENC , false); + linphoneCore.getMediastreamerFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_DEC , true); + linphoneCore.getMediastreamerFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_ENC , true); } //otherwise use OpenH264 else{ Log.i("H264Helper"," setH264Mode MODE_AUTO 2 - Mode = "+mode); Log.i("H264Helper"," Openh264 enabled on the project"); - linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_DEC , false); - linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_ENC , false); - linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_DEC , true); - linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_ENC , true); + linphoneCore.getMediastreamerFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_DEC , false); + linphoneCore.getMediastreamerFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_ENC , false); + linphoneCore.getMediastreamerFactory().enableFilterFromName(FILTER_NAME_OPENH264_DEC , true); + linphoneCore.getMediastreamerFactory().enableFilterFromName(FILTER_NAME_OPENH264_ENC , true); } }else { Log.i("H264Helper"," Error: Openh264 mode not reconized !"); diff --git a/wrappers/java/classes/tools/Lpc2Xml.java b/wrappers/java/classes/tools/Lpc2Xml.java index e61f4d2df..04bc6c5a2 100644 --- a/wrappers/java/classes/tools/Lpc2Xml.java +++ b/wrappers/java/classes/tools/Lpc2Xml.java @@ -1,6 +1,6 @@ package org.linphone.core.tools; -import org.linphone.core.LpConfig; +import org.linphone.core.Config; import org.linphone.mediastream.Log; public class Lpc2Xml { @@ -27,7 +27,7 @@ public class Lpc2Xml { destroy(); } - public native int setLpc(LpConfig lpc); + public native int setLpc(Config lpc); public native int convertFile(String file); public native int convertString(StringBuffer content); diff --git a/wrappers/java/classes/tools/Xml2Lpc.java b/wrappers/java/classes/tools/Xml2Lpc.java index 9b874152e..b805750ec 100644 --- a/wrappers/java/classes/tools/Xml2Lpc.java +++ b/wrappers/java/classes/tools/Xml2Lpc.java @@ -1,6 +1,6 @@ package org.linphone.core.tools; -import org.linphone.core.LpConfig; +import org.linphone.core.Config; import org.linphone.mediastream.Log; public class Xml2Lpc { @@ -34,7 +34,7 @@ public class Xml2Lpc { public native int setXsdString(String content); public native int validate(); - public native int convert(LpConfig config); + public native int convert(Config config); public void printLog(int level, String message) { if(level > 0 && level < LogLevel.values().length) { diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 6a8eaa29e..2ae0d1cf6 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -6,6 +6,7 @@ SED_END='{} \;' # Imports eval "$SED_START 's/import org.linphone.tools/import org.linphone.core.tools/g' $SED_END" eval "$SED_START 's/import org.linphone.core.OpenH264DownloadHelperListener/import org.linphone.core.tools.OpenH264DownloadHelperListener/g' $SED_END" +eval "$SED_START 's/import org.linphone.core.LinphoneCore.Transports;/import org.linphone.core.Transports/g' $SED_END" # Listeners eval "$SED_START 's/LinphoneAccountCreator.LinphoneAccountCreatorListener/AccountCreatorListener/g' $SED_END" @@ -116,6 +117,8 @@ eval "$SED_START 's/onAccountCreatorPhoneAccountRecovered/onRecoverAccount/g' $S eval "$SED_START 's/onAccountCreatorIsAccountLinked/onIsAccountLinked/g' $SED_END" eval "$SED_START 's/onAccountCreatorIsPhoneNumberUsed/onIsAliasUsed/g' $SED_END" eval "$SED_START 's/onAccountCreatorPasswordUpdated/onUpdateAccount/g' $SED_END" +eval "$SED_START 's/(AccountCreator accountCreator, Status status)/(AccountCreator accountCreator, Status status, String resp)/g' $SED_END" +eval "$SED_START 's/(AccountCreator accountCreator, AccountCreator.Status status)/(AccountCreator accountCreator, AccountCreator.Status status, String resp)/g' $SED_END" # # Chat message eval "$SED_START 's/onChatMessageStateChanged/onMsgStateChanged/g' $SED_END" @@ -125,7 +128,7 @@ eval "$SED_START 's/onChatMessageFileTransferProgressChanged/onFileTransferProgr # # Core eval "$SED_START 's/authInfoRequested/removed/g' $SED_END" # Removed -eval "$SED_START 's/show(Core/removed/g' $SED_END" # Removed +eval "$SED_START 's/show(Core/removed(/g' $SED_END" # Removed eval "$SED_START 's/displayStatus/removed/g' $SED_END" # Removed eval "$SED_START 's/displayMessage/removed/g' $SED_END" # Removed eval "$SED_START 's/displayWarning/removed/g' $SED_END" # Removed @@ -136,6 +139,7 @@ eval "$SED_START 's/notifyReceived(Core lc, Event/onNotifyReceived(Core lc, Even eval "$SED_START 's/notifyReceived/removed/g' $SED_END" # Removed #eval "$SED_START 's/ecCalibrationStatus//g' $SED_END" eval "$SED_START 's/publishStateChanged/onPublishStateChanged/g' $SED_END" # Removed +eval "$SED_START 's/messageReceivedUnableToDecrypted/removed/g' $SED_END" # Removed eval "$SED_START 's/callStatsUpdated/onCallStatsUpdated/g' $SED_END" eval "$SED_START 's/authenticationRequested/onAuthenticationRequested/g' $SED_END" eval "$SED_START 's/newSubscriptionRequest/onNewSubscriptionRequested/g' $SED_END" @@ -148,7 +152,6 @@ eval "$SED_START 's/globalState/onGlobalStateChanged/g' $SED_END" eval "$SED_START 's/registrationState/onRegistrationStateChanged/g' $SED_END" eval "$SED_START 's/configuringStatus/onConfiguringStatus/g' $SED_END" eval "$SED_START 's/messageReceived/onMessageReceived/g' $SED_END" -eval "$SED_START 's/messageReceivedUnableToDecrypted//g' $SED_END" eval "$SED_START 's/callState/onCallStateChanged/g' $SED_END" eval "$SED_START 's/callEncryptionChanged/onCallEncryptionChanged/g' $SED_END" eval "$SED_START 's/isComposingReceived/onIsComposingReceived/g' $SED_END" @@ -218,11 +221,13 @@ eval "$SED_START 's/lpc.getAddress()/lpc.getIdentityAddress()/g' $SED_END" eval "$SED_START 's/cfg.getAddress()/cfg.getIdentityAddress()/g' $SED_END" eval "$SED_START 's/prxCfg.getAddress()/prxCfg.getIdentityAddress()/g' $SED_END" eval "$SED_START 's/proxy.getAddress()/proxy.getIdentityAddress()/g' $SED_END" +eval "$SED_START 's/getProxyConfig(n).getAddress()/getProxyConfig(n).getIdentityAddress()/g' $SED_END" # eval "$SED_START 's/getCallDuration()/getDuration()/g' $SED_END" eval "$SED_START 's/isVCardSupported()/vcardSupported()/g' $SED_END" eval "$SED_START 's/getPresenceModelForUri(/getPresenceModelForUriOrTel(/g' $SED_END" eval "$SED_START 's/setAvpfRRInterval(/setAvpfRrInterval(/g' $SED_END" +eval "$SED_START 's/getAvpfRRInterval(/getAvpfRrInterval(/g' $SED_END" eval "$SED_START 's/getProxy()/getServerAddr()/g' $SED_END" eval "$SED_START 's/setProxy(/setServerAddr(/g' $SED_END" eval "$SED_START 's/setIdentity(/setIdentityAddress(/g' $SED_END" @@ -257,7 +262,8 @@ eval "$SED_START 's/migrateCallLogs()/migrateLogsFromRcToDb()/g' $SED_END" eval "$SED_START 's/setRLSUri/setRlsUri/g' $SED_END" eval "$SED_START 's/hasCrappyOpenGL(/hasCrappyOpenGl(/g' $SED_END" eval "$SED_START 's/needsEchoCalibration(/isEchoCancellerCalibrationRequired(/g' $SED_END" -eval "$SED_START 's//getCountryCode()/getCountryCallingCode()/g' $SED_END" +eval "$SED_START 's/getCountryCode()/getCountryCallingCode()/g' $SED_END" +eval "$SED_START 's/isEchoCancellationEnabled()/echoCancellationEnabled()/g' $SED_END" # Removed methods eval "$SED_START 's/.isRegistered()/.getState() == RegistrationState.Ok/g' $SED_END" @@ -270,10 +276,10 @@ eval "$SED_START 's/getVcardToString()/getVcard().asVcard4String()/g' $SED_END" eval "$SED_START 's/getVideoAutoInitiatePolicy()/getVideoActivationPolicy().getAutomaticallyInitiate()/g' $SED_END" eval "$SED_START 's/setFamilyName(/getVcard().setFamilyName(/g' $SED_END" eval "$SED_START 's/setGivenName(/getVcard().setGivenName(/g' $SED_END" -eval "$SED_START 's/setOrganization(/getVcard().setOrganization(/g' $SED_END" +eval "$SED_START 's/\.setOrganization(/\.getVcard().setOrganization(/g' $SED_END" eval "$SED_START 's/getFamilyName()/getVcard().getFamilyName()/g' $SED_END" eval "$SED_START 's/getGivenName()/getVcard().getGivenName()/g' $SED_END" -eval "$SED_START 's/getOrganization()/getVcard().getOrganization()/g' $SED_END" +eval "$SED_START 's/\.getOrganization()/\.getVcard().getOrganization()/g' $SED_END" eval "$SED_START 's/enableAvpf(/setAvpfMode(AVPFMode.Enabled)/g' $SED_END" eval "$SED_START 's/transports.udp = /transports.setUdpPort(/g' $SED_END" eval "$SED_START 's/transports.tcp = /transports.setTcpPort(/g' $SED_END" @@ -286,6 +292,8 @@ eval "$SED_START 's/getPrimaryContactDisplayName()/getPrimaryContactParsed().get eval "$SED_START 's/.sendDtmf(/.getCurrentCall().sendDtmf(/g' $SED_END" eval "$SED_START 's/content.getData() == null/content.getSize() == 0/'g $SED_END" eval "$SED_START 's/lc.downloadOpenH264Enabled()/OpenH264DownloadHelper.isOpenH264DownloadEnabled()/g' $SED_END" +eval "$SED_START 's/LinphoneManager.getLc().downloadOpenH264Enabled()/OpenH264DownloadHelper.isOpenH264DownloadEnabled()/g' $SED_END" +eval "$SED_START 's/getLc().enableDownloadOpenH264(/OpenH264DownloadHelper.setOpenH264DownloadEnabled(/g' $SED_END" eval "$SED_START 's/enableDownloadOpenH264(/OpenH264DownloadHelper.enableDownloadOpenH264(/g' $SED_END" eval "$SED_START 's/mLc.destroy()/mLc = null/g' $SED_END" eval "$SED_START 's/getAllDialPlan()/getDialPlans()/g' $SED_END" @@ -295,33 +303,68 @@ eval "$SED_START 's/accountCreator.getPrefix(/org.linphone.core.Utils.getPrefixF eval "$SED_START 's/proxyConfig.lookupCCCFromIso(/org.linphone.core.Utils.getCccFromIso(/g' $SED_END" eval "$SED_START 's/linkPhoneNumberWithAccount()/linkAccount()/g' $SED_END" eval "$SED_START 's/zoomVideo(/zoom(/g' $SED_END" +eval "$SED_START 's/mLc.setCpuCount(/\/\/mLc.setCpuCount(/g' $SED_END" -#Changes in library required -#Tunnel +#Core.setCpuCount() => Not needed anymore, can be removed +# TODO +#Tunnel, TunnelConfig #LinphoneBuffer -#AccountCreator.updatePassword +#AccountCreator.updatePassword => What to do ? +# XmlRpcStatus ! must be XmlRpcRequest.Status +# XmlRpcRequest and XmlRpcSession constructors... +# Factory.createContent( +# Callbacks with return like chat messages' file transfer +# createConfigFromString / createConfig +# #Android specifics not wrapped automatically #Core.startEchoCalibration -# For the payloads, get the list from the Core, call the method on the object directly and set it back if required -#Core.enablePayloadType() -#Core.isPayloadTypeEnabled() -#Core.payloadTypeIsVbr() -#Core.setPayloadTypeBitrate() +# Manual changes required +# Some callbacks no longer exist, their name will be "removed", remove them +# Above sed commands will create erros in syntax you need to manually fix: +# # !micEnabled() +# # (getConference() != null) +# # (AVPFMode.Enabled) +# # (port; +# Some methods that used to take or return String or LinphoneAddress now take the other +# createAddress, addAddress, addFriend, acceptCall, acceptCallWithParams no longer throws a CoreException +# AccountCreator's Status.Ok must be renamed in Status.RequestOk +# VideoDevices were int, now are String +# XmlRpcSessionImpl => XmlRpcSession +# getFriendsLists() returned Friend[], now is a FriendList[] +# No need anymore to cast to a Impl class to be able to use setUserData or getUserData +# findFriend now takes an Address instead of a String +# createOpenH264DownloadHelper() now takes a Context +# Factory.createCore(this, mConfigFile, mLinphoneFactoryConfigFile, null, c) => createCore(this, mConfigFile, mLinphoneFactoryConfigFile) +# startEchoTester and stopEchoTester now return void +# createProxyConfig no longer takes any parameter +# setPrimaryContact only takes one String argument +# AdaptiveRateAlgorithm was an enum, now is nothing +# createAddress(userName,domain,null); no longer exists +# # Factory #Factory.createLpConfigFromString => Config.newFromBuffer #Factory.createLpConfig => Config.newWithFactory or Core.createConfig -#Core.getVideoDevice and Core.setVideoDevice now takes/returns String instead of int #Factory.createAccountCreator() => Core.createAccountCreator() #Factory.createPresenceModel() => Core.createPresenceModel() -#CallParams.getJitterBufferSize() => CallStatsImpl.getJitterBufferSizeMs() +#Factory.instance().setLogCollectionPath(getFilesDir().getAbsolutePath()); => Core.setLogCollectionPath +#Factory.instance().enableLogCollection(isDebugEnabled); => Core.enableLogCollection +#Factory.instance().setDebugMode(isDebugEnabled, getString(R.string.app_name)); => Core.setLogLevelMask + +# # Core +#Core.getVideoDevice and Core.setVideoDevice now takes/returns String instead of int #Core.getSupportedVideoSizes() => Factory.getSupportedVideoDefinitions() #Core.removeFriend() => FriendList.removeFriend() #Core.getFriendsLists() => now returns a FriendList[] instead of a Friend[] #Core.enableSpeaker / isSpeakerEnabled() => mAudioManager.setSpeakerphoneOn(speakerOn); #Core.enableVideo(true, true) => Core.enableVideoCapture(bool) & Core.enableVideoDisplay(bool) -#Core.setCpuCount() => Not needed anymore, can be removed -#Factory.instance().setLogCollectionPath(getFilesDir().getAbsolutePath()); => Core.setLogCollectionPath -#Factory.instance().enableLogCollection(isDebugEnabled); => COre.enableLogCollection -#Factory.instance().setDebugMode(isDebugEnabled, getString(R.string.app_name)); => Core.setLogLevelMask + +# # Other +#CallParams.getJitterBufferSize() => CallStatsImpl.getJitterBufferSizeMs() + +# # Payloads +#Core.enablePayloadType() => PayloadType.enable() +#Core.isPayloadTypeEnabled() => PayloadType.enabled() +#Core.payloadTypeIsVbr() => PayloadType.isVbr() +#Core.setPayloadTypeBitrate() => PayloadType.setNormalBitrate() From 8a8aed0eb478336570a28f202ce5d5e09d095be2 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 17 Oct 2017 15:57:16 +0200 Subject: [PATCH 0524/2215] More work on Java's migration script --- wrappers/java/migration.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 2ae0d1cf6..201f80908 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -267,8 +267,6 @@ eval "$SED_START 's/isEchoCancellationEnabled()/echoCancellationEnabled()/g' $SE # Removed methods eval "$SED_START 's/.isRegistered()/.getState() == RegistrationState.Ok/g' $SED_END" -eval "$SED_START 's/getBool(/getInt(/g' $SED_END" -eval "$SED_START 's/setBool(/setInt(/g' $SED_END" eval "$SED_START 's/isInConference()/(getConference() != null)/g' $SED_END" eval "$SED_START 's/getAudioStats()/getStats(StreamType.Audio)/g' $SED_END" eval "$SED_START 's/getVideoStats()/getStats(StreamType.Video)/g' $SED_END" @@ -314,8 +312,6 @@ eval "$SED_START 's/mLc.setCpuCount(/\/\/mLc.setCpuCount(/g' $SED_END" # XmlRpcRequest and XmlRpcSession constructors... # Factory.createContent( # Callbacks with return like chat messages' file transfer -# createConfigFromString / createConfig -# #Android specifics not wrapped automatically #Core.startEchoCalibration From 249b7c0ee9d7fbbb2c4fc88a1ca22e30c48f52ec Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 17 Oct 2017 15:59:31 +0200 Subject: [PATCH 0525/2215] feat(ConferenceEvent): supports notifyId parameter --- src/CMakeLists.txt | 2 +- .../conference/conference-notified-event-p.h | 39 ++++++++++ .../conference/conference-notified-event.cpp | 75 +++++++++++++++++++ .../conference/conference-notified-event.h | 15 ++-- .../conference-participant-device-event.cpp | 3 + .../conference-participant-device-event.h | 1 + .../conference-participant-event-p.h | 4 +- .../conference-participant-event.cpp | 7 +- .../conference/conference-participant-event.h | 6 +- .../conference/conference-subject-event.cpp | 17 +++-- .../conference/conference-subject-event.h | 11 ++- tester/events-db-tester.cpp | 2 + 12 files changed, 162 insertions(+), 20 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 89f5eda14..f45dce5c3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -52,8 +52,8 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES chat/modifier/encryption-chat-message-modifier.h chat/modifier/multipart-chat-message-modifier.h chat/notification/imdn.h - chat/notification/is-composing.h chat/notification/is-composing-listener.h + chat/notification/is-composing.h conference/conference-listener.h conference/conference-p.h conference/conference.h diff --git a/src/event-log/conference/conference-notified-event-p.h b/src/event-log/conference/conference-notified-event-p.h index e69de29bb..af5855334 100644 --- a/src/event-log/conference/conference-notified-event-p.h +++ b/src/event-log/conference/conference-notified-event-p.h @@ -0,0 +1,39 @@ +/* + * conference-notified-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CONFERENCE_NOTIFIED_EVENT_P_H_ +#define _CONFERENCE_NOTIFIED_EVENT_P_H_ + +#include "conference-event-p.h" +#include "conference-notified-event.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ConferenceNotifiedEventPrivate : public ConferenceEventPrivate { +private: + unsigned int notifyId = 0; + + L_DECLARE_PUBLIC(ConferenceNotifiedEvent); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CONFERENCE_NOTIFIED_EVENT_P_H_ diff --git a/src/event-log/conference/conference-notified-event.cpp b/src/event-log/conference/conference-notified-event.cpp index e69de29bb..cca45750e 100644 --- a/src/event-log/conference/conference-notified-event.cpp +++ b/src/event-log/conference/conference-notified-event.cpp @@ -0,0 +1,75 @@ +/* + * conference-notified-event.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "conference-notified-event-p.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +// ----------------------------------------------------------------------------- + +ConferenceNotifiedEvent::ConferenceNotifiedEvent ( + Type type, + time_t time, + const Address &conferenceAddress, + unsigned int notifyId +) : ConferenceEvent(*new ConferenceNotifiedEventPrivate, type, time, conferenceAddress) { + L_D(); + d->notifyId = notifyId; +} + +ConferenceNotifiedEvent::ConferenceNotifiedEvent ( + const ConferenceNotifiedEvent &src +) : ConferenceNotifiedEvent( + src.getType(), + src.getTime(), + src.getConferenceAddress(), + src.getNotifyId() +) {} + +ConferenceNotifiedEvent::ConferenceNotifiedEvent ( + ConferenceNotifiedEventPrivate &p, + Type type, + time_t time, + const Address &conferenceAddress, + unsigned int notifyId +) : ConferenceEvent(p, type, time, conferenceAddress) { + L_D(); + d->notifyId = notifyId; +} + +ConferenceNotifiedEvent &ConferenceNotifiedEvent::operator= (const ConferenceNotifiedEvent &src) { + L_D(); + if (this != &src) { + ConferenceEvent::operator=(src); + d->notifyId = src.getPrivate()->notifyId; + } + + return *this; +} + +unsigned int ConferenceNotifiedEvent::getNotifyId () const { + L_D(); + return d->notifyId; +} + +LINPHONE_END_NAMESPACE diff --git a/src/event-log/conference/conference-notified-event.h b/src/event-log/conference/conference-notified-event.h index 5e87cf8bb..2f3c8f860 100644 --- a/src/event-log/conference/conference-notified-event.h +++ b/src/event-log/conference/conference-notified-event.h @@ -26,20 +26,25 @@ LINPHONE_BEGIN_NAMESPACE -class Address; class ConferenceNotifiedEventPrivate; -class LINPHONE_PUBLIC ConferenceNotifiedEvent : public EventLog { +class LINPHONE_PUBLIC ConferenceNotifiedEvent : public ConferenceEvent { public: - ConferenceNotifiedEvent (Type type, std::time_t time, const Address &conferenceAddress); + ConferenceNotifiedEvent (Type type, std::time_t time, const Address &conferenceAddress, unsigned int notifiyId); ConferenceNotifiedEvent (const ConferenceNotifiedEvent &src); ConferenceNotifiedEvent &operator= (const ConferenceNotifiedEvent &src); - const Address &getConferenceAddress () const; + unsigned int getNotifyId () const; protected: - ConferenceNotifiedEvent (ConferenceNotifiedEventPrivate &p, Type type, std::time_t time, const Address &conferenceAddress); + ConferenceNotifiedEvent ( + ConferenceNotifiedEventPrivate &p, + Type type, + std::time_t time, + const Address &conferenceAddress, + unsigned int notifyId + ); private: L_DECLARE_PRIVATE(ConferenceNotifiedEvent); diff --git a/src/event-log/conference/conference-participant-device-event.cpp b/src/event-log/conference/conference-participant-device-event.cpp index fd090f1df..83cc88398 100644 --- a/src/event-log/conference/conference-participant-device-event.cpp +++ b/src/event-log/conference/conference-participant-device-event.cpp @@ -37,6 +37,7 @@ ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent ( Type type, time_t time, const Address &conferenceAddress, + unsigned int notifyId, const Address &participantAddress, const Address &gruuAddress ) : ConferenceParticipantEvent( @@ -44,6 +45,7 @@ ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent ( type, time, conferenceAddress, + notifyId, participantAddress ) { L_D(); @@ -59,6 +61,7 @@ ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent (const Confer src.getType(), src.getTime(), src.getConferenceAddress(), + src.getNotifyId(), src.getParticipantAddress(), src.getGruuAddress() ) {} diff --git a/src/event-log/conference/conference-participant-device-event.h b/src/event-log/conference/conference-participant-device-event.h index d70d08549..3ee2b9a95 100644 --- a/src/event-log/conference/conference-participant-device-event.h +++ b/src/event-log/conference/conference-participant-device-event.h @@ -34,6 +34,7 @@ public: Type type, std::time_t time, const Address &conferenceAddress, + unsigned int notifyId, const Address &participantAddress, const Address &gruuAddress ); diff --git a/src/event-log/conference/conference-participant-event-p.h b/src/event-log/conference/conference-participant-event-p.h index 6aab2eb72..77210c562 100644 --- a/src/event-log/conference/conference-participant-event-p.h +++ b/src/event-log/conference/conference-participant-event-p.h @@ -20,14 +20,14 @@ #ifndef _CONFERENCE_PARTICIPANT_EVENT_P_H_ #define _CONFERENCE_PARTICIPANT_EVENT_P_H_ -#include "conference-event-p.h" +#include "conference-notified-event-p.h" #include "conference-participant-event.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE -class ConferenceParticipantEventPrivate : public ConferenceEventPrivate { +class ConferenceParticipantEventPrivate : public ConferenceNotifiedEventPrivate { private: Address participantAddress; diff --git a/src/event-log/conference/conference-participant-event.cpp b/src/event-log/conference/conference-participant-event.cpp index 3f6e560fd..b64e886b2 100644 --- a/src/event-log/conference/conference-participant-event.cpp +++ b/src/event-log/conference/conference-participant-event.cpp @@ -31,8 +31,9 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( Type type, time_t time, const Address &conferenceAddress, + unsigned int notifyId, const Address &participantAddress -) : ConferenceEvent(*new ConferenceParticipantEventPrivate, type, time, conferenceAddress) { +) : ConferenceNotifiedEvent(*new ConferenceParticipantEventPrivate, type, time, conferenceAddress, notifyId) { L_D(); L_ASSERT( type == Type::ConferenceParticipantAdded || @@ -49,6 +50,7 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( src.getType(), src.getTime(), src.getConferenceAddress(), + src.getNotifyId(), src.getParticipantAddress() ) {} @@ -57,8 +59,9 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( Type type, time_t time, const Address &conferenceAddress, + unsigned int notifyId, const Address &participantAddress -) : ConferenceEvent(p, type, time, conferenceAddress) { +) : ConferenceNotifiedEvent(p, type, time, conferenceAddress, notifyId) { L_D(); d->participantAddress = participantAddress; } diff --git a/src/event-log/conference/conference-participant-event.h b/src/event-log/conference/conference-participant-event.h index 5b69d84cb..d5127459a 100644 --- a/src/event-log/conference/conference-participant-event.h +++ b/src/event-log/conference/conference-participant-event.h @@ -20,7 +20,7 @@ #ifndef _CONFERENCE_PARTICIPANT_EVENT_H_ #define _CONFERENCE_PARTICIPANT_EVENT_H_ -#include "conference-event.h" +#include "conference-notified-event.h" // ============================================================================= @@ -28,12 +28,13 @@ LINPHONE_BEGIN_NAMESPACE class ConferenceParticipantEventPrivate; -class LINPHONE_PUBLIC ConferenceParticipantEvent : public ConferenceEvent { +class LINPHONE_PUBLIC ConferenceParticipantEvent : public ConferenceNotifiedEvent { public: ConferenceParticipantEvent ( Type type, std::time_t time, const Address &conferenceAddress, + unsigned int notifyId, const Address &participantAddress ); ConferenceParticipantEvent (const ConferenceParticipantEvent &src); @@ -48,6 +49,7 @@ protected: Type type, std::time_t time, const Address &conferenceAddress, + unsigned int notifyId, const Address &participantAddress ); diff --git a/src/event-log/conference/conference-subject-event.cpp b/src/event-log/conference/conference-subject-event.cpp index dc1073506..1dcd45a0b 100644 --- a/src/event-log/conference/conference-subject-event.cpp +++ b/src/event-log/conference/conference-subject-event.cpp @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "conference-event-p.h" +#include "conference-notified-event-p.h" #include "conference-subject-event.h" // ============================================================================= @@ -26,7 +26,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -class ConferenceSubjectEventPrivate : public ConferenceEventPrivate { +class ConferenceSubjectEventPrivate : public ConferenceNotifiedEventPrivate { public: string subject; }; @@ -35,15 +35,22 @@ public: ConferenceSubjectEvent::ConferenceSubjectEvent ( time_t time, - const Address &address, + const Address &conferenceAddress, + unsigned int notifyId, const string &subject -) : ConferenceEvent(*new ConferenceSubjectEventPrivate, Type::ConferenceSubjectChanged, time, address) { +) : ConferenceNotifiedEvent( + *new ConferenceSubjectEventPrivate, + Type::ConferenceSubjectChanged, + time, + conferenceAddress, + notifyId +) { L_D(); d->subject = subject; } ConferenceSubjectEvent::ConferenceSubjectEvent (const ConferenceSubjectEvent &src) : - ConferenceSubjectEvent(src.getTime(), src.getConferenceAddress(), src.getSubject()) {} + ConferenceSubjectEvent(src.getTime(), src.getConferenceAddress(), src.getNotifyId(), src.getSubject()) {} ConferenceSubjectEvent &ConferenceSubjectEvent::operator= (const ConferenceSubjectEvent &src) { L_D(); diff --git a/src/event-log/conference/conference-subject-event.h b/src/event-log/conference/conference-subject-event.h index 144fb8e48..20f5fe982 100644 --- a/src/event-log/conference/conference-subject-event.h +++ b/src/event-log/conference/conference-subject-event.h @@ -20,7 +20,7 @@ #ifndef _CONFERENCE_SUBJECT_EVENT_H_ #define _CONFERENCE_SUBJECT_EVENT_H_ -#include "conference-event.h" +#include "conference-notified-event.h" // ============================================================================= @@ -28,9 +28,14 @@ LINPHONE_BEGIN_NAMESPACE class ConferenceSubjectEventPrivate; -class LINPHONE_PUBLIC ConferenceSubjectEvent : public ConferenceEvent { +class LINPHONE_PUBLIC ConferenceSubjectEvent : public ConferenceNotifiedEvent { public: - ConferenceSubjectEvent (std::time_t time, const Address &conferenceAddress, const std::string &subject); + ConferenceSubjectEvent ( + std::time_t time, + const Address &conferenceAddress, + unsigned int notifyId, + const std::string &subject + ); ConferenceSubjectEvent (const ConferenceSubjectEvent &src); ConferenceSubjectEvent &operator= (const ConferenceSubjectEvent &src); diff --git a/tester/events-db-tester.cpp b/tester/events-db-tester.cpp index 159244c28..15f69aedf 100644 --- a/tester/events-db-tester.cpp +++ b/tester/events-db-tester.cpp @@ -38,6 +38,8 @@ static const string getDatabasePath () { static void open_database () { MainDb eventsDb; BC_ASSERT_TRUE(eventsDb.connect(MainDb::Sqlite3, getDatabasePath())); + + eventsDb.import(AbstractDb::Backend::Sqlite3, "/home/rabhamon/.local/share/linphone/message-history.db"); } static void get_events_count () { From 63a74d3ba8b6b29349b1fc922be7399100520716 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 17 Oct 2017 16:02:05 +0200 Subject: [PATCH 0526/2215] fix(EventsDbTester): remove import... --- tester/events-db-tester.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/tester/events-db-tester.cpp b/tester/events-db-tester.cpp index 15f69aedf..159244c28 100644 --- a/tester/events-db-tester.cpp +++ b/tester/events-db-tester.cpp @@ -38,8 +38,6 @@ static const string getDatabasePath () { static void open_database () { MainDb eventsDb; BC_ASSERT_TRUE(eventsDb.connect(MainDb::Sqlite3, getDatabasePath())); - - eventsDb.import(AbstractDb::Backend::Sqlite3, "/home/rabhamon/.local/share/linphone/message-history.db"); } static void get_events_count () { From c1a21d909031072a16b975f0877d8edfd7b8ea87 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 17 Oct 2017 16:29:29 +0200 Subject: [PATCH 0527/2215] Fixed issue in Java wrapper with XmlRpcRequest.Status --- wrappers/java/genwrapper.py | 2 ++ wrappers/java/migration.sh | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 3e8810a34..de8ec7d50 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -191,6 +191,8 @@ class JavaTranslator(object): return 'int' elif jni: return 'jint' + if _type.desc.name.to_camel_case() == "XmlRpcStatus": + return "XmlRpcRequest.Status" name = _type.desc.name.to_camel_case() if name in ENUMS_LIST: className = ENUMS_LIST[name] diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 201f80908..4cdde6d66 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -308,9 +308,7 @@ eval "$SED_START 's/mLc.setCpuCount(/\/\/mLc.setCpuCount(/g' $SED_END" #Tunnel, TunnelConfig #LinphoneBuffer #AccountCreator.updatePassword => What to do ? -# XmlRpcStatus ! must be XmlRpcRequest.Status -# XmlRpcRequest and XmlRpcSession constructors... -# Factory.createContent( +# XmlRpcRequest and XmlRpcSession constructors # Callbacks with return like chat messages' file transfer #Android specifics not wrapped automatically @@ -347,6 +345,7 @@ eval "$SED_START 's/mLc.setCpuCount(/\/\/mLc.setCpuCount(/g' $SED_END" #Factory.instance().setLogCollectionPath(getFilesDir().getAbsolutePath()); => Core.setLogCollectionPath #Factory.instance().enableLogCollection(isDebugEnabled); => Core.enableLogCollection #Factory.instance().setDebugMode(isDebugEnabled, getString(R.string.app_name)); => Core.setLogLevelMask +#Factory.createContent( => Core.createContent( # # Core #Core.getVideoDevice and Core.setVideoDevice now takes/returns String instead of int From b65fcaa271bb66854cf7fdca72b79e3eb979d1ff Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 17 Oct 2017 16:40:34 +0200 Subject: [PATCH 0528/2215] feat(EventLog): add a events file that contains all events --- src/CMakeLists.txt | 1 + src/event-log/events.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/event-log/events.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f45dce5c3..c6f00397b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -102,6 +102,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES event-log/conference/conference-subject-event.h event-log/event-log-p.h event-log/event-log.h + event-log/events.h hacks/hacks.h logger/logger.h nat/ice-agent.h diff --git a/src/event-log/events.h b/src/event-log/events.h new file mode 100644 index 000000000..5911acb3d --- /dev/null +++ b/src/event-log/events.h @@ -0,0 +1,28 @@ +/* + * events.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _EVENTS_H_ +#define _EVENTS_H_ + +#include "call/call-event.h" +#include "chat/chat-message-event.h" +#include "conference/conference-participant-device-event.h" +#include "conference/conference-subject-event.h" + +#endif // ifndef _EVENTS_H_ From 8882c8e2859cf3312d99398ec4859dbf882bdc62 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 17 Oct 2017 16:46:42 +0200 Subject: [PATCH 0529/2215] Improved Java's genwrapper to handle LinphoneBuffer --- wrappers/java/genwrapper.py | 14 +++++++++++--- wrappers/java/jni.mustache | 9 ++++++++- wrappers/java/migration.sh | 1 + 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index de8ec7d50..95d050dc1 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -136,6 +136,8 @@ class JavaTranslator(object): inttype = 'u' + inttype if t.isref: inttype = inttype + ' *' + if t.isconst: + inttype = 'const ' + inttype return inttype elif _type == 'boolean': return 'bool_t' @@ -206,6 +208,10 @@ class JavaTranslator(object): return 'jstring' return 'String' elif _type.name == 'integer': + if _type.size is not None and _type.isref: + if jni: + return 'jbyteArray' + return 'byte[]' if jni: return 'jint' return 'int' @@ -344,9 +350,10 @@ class JavaTranslator(object): methodDict['return'] = self.translate_type(_method.returnType, jni=True, isReturn=True) methodDict['hasListReturn'] = methodDict['return'] == 'jobjectArray' - methodDict['hasReturn'] = not methodDict['return'] == 'void' and not methodDict['hasListReturn'] + methodDict['hasByteArrayReturn'] = methodDict['return'] == 'jbyteArray' + methodDict['hasReturn'] = not methodDict['return'] == 'void' and not methodDict['hasListReturn'] and not methodDict['hasByteArrayReturn'] methodDict['hasStringReturn'] = methodDict['return'] == 'jstring' - methodDict['hasNormalReturn'] = not methodDict['hasListReturn'] and not methodDict['hasStringReturn'] + methodDict['hasNormalReturn'] = not methodDict['hasListReturn'] and not methodDict['hasStringReturn'] and not methodDict['hasByteArrayReturn'] methodDict['name'] = 'Java_' + self.jni_package + className.to_camel_case() + 'Impl_' + _method.name.to_camel_case(lower=True) methodDict['notStatic'] = not static methodDict['c_name'] = 'linphone_' + className.to_snake_case() + "_" + _method.name.to_snake_case() @@ -354,6 +361,7 @@ class JavaTranslator(object): methodDict['returnClassName'] = self.translate_type(_method.returnType) methodDict['isRealObjectArray'] = False methodDict['isStringObjectArray'] = False + methodDict['c_type_return'] = self.translate_as_c_base_type(_method.returnType) if methodDict['hasListReturn']: if type(_method.returnType) is AbsApi.BaseType and _method.returnType.name == 'string_array': @@ -731,7 +739,7 @@ class GenWrapper(object): project.initFromDir(xmldir) project.check() - self.parser = AbsApi.CParser(project, ['LinphoneBuffer']) + self.parser = AbsApi.CParser(project) self.parser.functionBl = \ ['linphone_vcard_get_belcard',\ 'linphone_core_get_current_vtable',\ diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index ba7172de0..378b17e92 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -326,7 +326,14 @@ jobject {{jni_package}}CoreImpl_getMediastreamerFactory(JNIEnv *env, jobject thi } list = bctbx_list_next(list); } - {{/hasListReturn}}{{#hasStringReturn}} + {{/hasListReturn}}{{#hasByteArrayReturn}} + {{c_type_return}} jni_result = {{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}}); + if (!jni_result) return NULL; + size_t jni_result_length = strlen((const char *)jni_result); + jbyteArray array = env->NewByteArray((int)jni_result_length); + env->SetByteArrayRegion(array, 0, (int)jni_result_length, (const jbyte*)jni_result); + return array; + {{/hasByteArrayReturn}}{{#hasStringReturn}} const char *c_string = {{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}}){{#returnObject}}){{/returnObject}}; jstring jni_result = (c_string != NULL) ? env->NewStringUTF(c_string) : NULL; {{/hasStringReturn}}{{#hasNormalReturn}} diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 4cdde6d66..106156d2c 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -73,6 +73,7 @@ eval "$SED_START 's/LinphoneCoreFactory/Factory/g' $SED_END" eval "$SED_START 's/LinphoneAccountCreator/AccountCreator/g' $SED_END" eval "$SED_START 's/LinphoneAddress/Address/g' $SED_END" eval "$SED_START 's/LinphoneAuthInfo/AuthInfo/g' $SED_END" +eval "$SED_START 's/LinphoneBuffer/Buffer/g' $SED_END" eval "$SED_START 's/LinphoneCallLog/CallLog/g' $SED_END" eval "$SED_START 's/LinphoneCallParams/CallParams/g' $SED_END" eval "$SED_START 's/LinphoneCallStats/CallStats/g' $SED_END" From 8906a4d89b03f23e2ac28ba4cb3771007cca845b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 17 Oct 2017 16:57:32 +0200 Subject: [PATCH 0530/2215] Fixed Java's genwrapper when byte[] in method's arguments --- wrappers/java/genwrapper.py | 6 +++++- wrappers/java/jni.mustache | 8 ++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 95d050dc1..9a4d28949 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -381,6 +381,7 @@ class JavaTranslator(object): methodDict['objects'] = [] methodDict['lists'] = [] methodDict['array'] = [] + methodDict['bytes'] = [] methodDict['returnedObjectGetter'] = '' for arg in _method.args: methodDict['params'] += ', ' @@ -411,7 +412,10 @@ class JavaTranslator(object): methodDict['params_impl'] += '(' + argCType + ') ' + argname elif type(arg.type) is AbsApi.BaseType: - if arg.type.name == 'string': + if arg.type.name == 'integer' and arg.type.size is not None and arg.type.isref: + methodDict['bytes'].append({'bytesargname': argname, 'bytesargtype' : self.translate_as_c_base_type(arg.type)}) + methodDict['params_impl'] += 'c_' + argname + elif arg.type.name == 'string': methodDict['strings'].append({'string': argname}) methodDict['params_impl'] += 'c_' + argname else: diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index 378b17e92..607f7af64 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -286,7 +286,9 @@ jobject {{jni_package}}CoreImpl_getMediastreamerFactory(JNIEnv *env, jobject thi {{return}} {{name}}({{params}}) { {{#notStatic}}{{classCName}} *cptr = ({{classCName}}*)ptr;{{/notStatic}}{{#strings}} const char* c_{{string}} = GetStringUTFChars(env, {{string}}); - {{/strings}}{{#objects}} + {{/strings}}{{#bytes}} + {{bytesargtype}} c_{{bytesargname}} = ({{bytesargtype}})env->GetByteArrayElements({{bytesargname}}, NULL); + {{/bytes}}{{#objects}} {{objectClassCName}}* c_{{object}} = NULL; if ({{object}}) c_{{object}} = ({{objectClassCName}}*)GetObjectNativePtr(env, {{object}}); {{/objects}}{{#lists}} @@ -340,7 +342,9 @@ jobject {{jni_package}}CoreImpl_getMediastreamerFactory(JNIEnv *env, jobject thi {{#hasReturn}}{{return}} jni_result = ({{return}}){{#returnObject}}get{{returnClassName}}(env, (Linphone{{returnClassName}} *){{/returnObject}}{{/hasReturn}}{{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}}){{#returnObject}}){{/returnObject}}; {{/hasNormalReturn}}{{#strings}} ReleaseStringUTFChars(env, {{string}}, c_{{string}}); - {{/strings}}{{#hasReturn}}return jni_result;{{/hasReturn}}{{#hasListReturn}}return jni_list_result;{{/hasListReturn}} + {{/strings}}{{#bytes}} + env->ReleaseByteArrayElements({{bytesargname}}, (jbyte*)c_{{bytesargname}}, JNI_ABORT); + {{/bytes}}{{#hasReturn}}return jni_result;{{/hasReturn}}{{#hasListReturn}}return jni_list_result;{{/hasListReturn}} } {{/methods}} \ No newline at end of file From 3a1a899c8388965ac9cb546a103aa2e1e9d20be5 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 17 Oct 2017 17:02:41 +0200 Subject: [PATCH 0531/2215] feat(MainDb): supports notify id in database --- src/c-wrapper/api/c-event-log.cpp | 4 +-- src/db/main-db-p.h | 1 + src/db/main-db.cpp | 54 ++++++++++++++++++++----------- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index e3e8cd467..5a32050c2 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -23,9 +23,7 @@ #include "c-wrapper/c-wrapper.h" #include "call/call.h" #include "chat/chat-message/chat-message.h" -#include "event-log/call/call-event.h" -#include "event-log/chat/chat-message-event.h" -#include "event-log/conference/conference-participant-event.h" +#include "event-log/events.h" // ============================================================================= diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 464cfa0c7..02ebe9cb3 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -71,6 +71,7 @@ private: long insertCallEvent (const EventLog &eventLog); long insertMessageEvent (const EventLog &eventLog); long insertConferenceEvent (const EventLog &eventLog); + long insertConferenceNotifiedEvent (const EventLog &eventLog); long insertConferenceParticipantEvent (const EventLog &eventLog); long insertConferenceParticipantDeviceEvent (const EventLog &eventLog); long insertConferenceSubjectEvent (const EventLog &eventLog); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 4576ebb32..c189fd26a 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -31,10 +31,7 @@ #include "content/content-type.h" #include "content/content.h" #include "db/session/db-session-provider.h" -#include "event-log/call/call-event.h" -#include "event-log/chat/chat-message-event.h" -#include "event-log/conference/conference-participant-device-event.h" -#include "event-log/conference/conference-subject-event.h" +#include "event-log/events.h" #include "event-log/event-log-p.h" #include "logger/logger.h" #include "main-db-p.h" @@ -266,14 +263,25 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return eventId; } - long MainDbPrivate::insertConferenceParticipantEvent (const EventLog &eventLog) { + long MainDbPrivate::insertConferenceNotifiedEvent (const EventLog &eventLog) { long eventId = insertConferenceEvent(eventLog); + + soci::session *session = dbSession.getBackendSession(); + *session << "INSERT INTO conference_notified_event (event_id, notify_id)" + " VALUES (:eventId, :notifyId)", soci::use(eventId), soci::use( + static_cast(eventLog).getNotifyId() + ); + return eventId; + } + + long MainDbPrivate::insertConferenceParticipantEvent (const EventLog &eventLog) { + long eventId = insertConferenceNotifiedEvent(eventLog); long participantAddressId = insertSipAddress( static_cast(eventLog).getParticipantAddress().asString() ); soci::session *session = dbSession.getBackendSession(); - *session << "INSERT INTO conference_participant_event (conference_event_id, participant_address_id)" + *session << "INSERT INTO conference_participant_event (event_id, participant_address_id)" " VALUES (:eventId, :participantAddressId)", soci::use(eventId), soci::use(participantAddressId); return eventId; } @@ -285,16 +293,16 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} ); soci::session *session = dbSession.getBackendSession(); - *session << "INSERT INTO conference_participant_device_event (conference_participant_event_id, gruu_address_id)" + *session << "INSERT INTO conference_participant_device_event (event_id, gruu_address_id)" " VALUES (:eventId, :gruuAddressId)", soci::use(eventId), soci::use(gruuAddressId); return eventId; } long MainDbPrivate::insertConferenceSubjectEvent (const EventLog &eventLog) { - long eventId = insertConferenceEvent(eventLog); + long eventId = insertConferenceNotifiedEvent(eventLog); soci::session *session = dbSession.getBackendSession(); - *session << "INSERT INTO conference_subject_event (conference_event_id, subject)" + *session << "INSERT INTO conference_subject_event (event_id, subject)" " VALUES (:eventId, :subject)", soci::use(eventId), soci::use( static_cast(eventLog).getSubject() ); @@ -406,13 +414,23 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} " ON DELETE CASCADE" ")"; + *session << + "CREATE TABLE IF NOT EXISTS conference_notified_event (" + " event_id INT UNSIGNED PRIMARY KEY," + " notify_id INT UNSIGNED NOT NULL," + + " FOREIGN KEY (event_id)" + " REFERENCES conference_event(event_id)" + " ON DELETE CASCADE" + ")"; + *session << "CREATE TABLE IF NOT EXISTS conference_participant_event (" - " conference_event_id INT UNSIGNED PRIMARY KEY," + " event_id INT UNSIGNED PRIMARY KEY," " participant_address_id INT UNSIGNED NOT NULL," - " FOREIGN KEY (conference_event_id)" - " REFERENCES event(event_id)" + " FOREIGN KEY (event_id)" + " REFERENCES conference_notified_event(event_id)" " ON DELETE CASCADE," " FOREIGN KEY (participant_address_id)" " REFERENCES sip_address(id)" @@ -421,11 +439,11 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS conference_participant_device_event (" - " conference_participant_event_id INT UNSIGNED PRIMARY KEY," + " event_id INT UNSIGNED PRIMARY KEY," " gruu_address_id INT UNSIGNED NOT NULL," - " FOREIGN KEY (conference_participant_event_id)" - " REFERENCES conference_participant_event(conference_event_id)" + " FOREIGN KEY (event_id)" + " REFERENCES conference_participant_event(event_id)" " ON DELETE CASCADE," " FOREIGN KEY (gruu_address_id)" " REFERENCES sip_address(id)" @@ -434,11 +452,11 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS conference_subject_event (" - " conference_event_id INT UNSIGNED PRIMARY KEY," + " event_id INT UNSIGNED PRIMARY KEY," " subject VARCHAR(255)," - " FOREIGN KEY (conference_event_id)" - " REFERENCES event(event_id)" + " FOREIGN KEY (event_id)" + " REFERENCES conference_notified_event(event_id)" " ON DELETE CASCADE" ")"; From 5c8fa71e9d77fe44497ef05c307fdf6476888742 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 17 Oct 2017 17:13:27 +0200 Subject: [PATCH 0532/2215] create event object on notifed conference event --- src/chat/chat-room/client-group-chat-room.cpp | 49 +++++++++++++++++++ .../remote-conference-event-handler-p.h | 5 -- .../remote-conference-event-handler.cpp | 7 ++- .../remote-conference-event-handler.h | 5 +- 4 files changed, 57 insertions(+), 9 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index af63cc759..b7151aa59 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -26,6 +26,7 @@ #include "conference/remote-conference-event-handler.h" #include "conference/remote-conference-p.h" #include "conference/session/call-session-p.h" +#include "event-log/events.h" #include "logger/logger.h" #include "sal/refer-op.h" @@ -274,6 +275,14 @@ void ClientGroupChatRoom::onParticipantAdded (time_t tm, const Address &addr) { LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAddedCb cb = linphone_chat_room_cbs_get_participant_added(cbs); + ConferenceParticipantEvent event( + EventLog::Type::ConferenceParticipantAdded, + tm, + dConference->conferenceAddress, + dConference->eventHandler->getLastNotify(), + addr + ); + if (cb) cb(cr, L_GET_C_BACK_PTR(participant)); } @@ -290,6 +299,13 @@ void ClientGroupChatRoom::onParticipantRemoved (time_t tm, const Address &addr) LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantRemovedCb cb = linphone_chat_room_cbs_get_participant_removed(cbs); + ConferenceParticipantEvent event( + EventLog::Type::ConferenceParticipantRemoved, + tm, + dConference->conferenceAddress, + dConference->eventHandler->getLastNotify(), + addr + ); if (cb) cb(cr, L_GET_C_BACK_PTR(participant)); @@ -298,6 +314,7 @@ void ClientGroupChatRoom::onParticipantRemoved (time_t tm, const Address &addr) } void ClientGroupChatRoom::onParticipantSetAdmin (time_t tm, const Address &addr, bool isAdmin) { + L_D_T(RemoteConference, dConference); shared_ptr participant; if (isMe(addr)) participant = getMe(); @@ -312,22 +329,37 @@ void ClientGroupChatRoom::onParticipantSetAdmin (time_t tm, const Address &addr, LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAdminStatusChangedCb cb = linphone_chat_room_cbs_get_participant_admin_status_changed(cbs); + ConferenceParticipantEvent event( + isAdmin ? EventLog::Type::ConferenceParticipantSetAdmin : EventLog::Type::ConferenceParticipantUnsetAdmin, + tm, + dConference->conferenceAddress, + dConference->eventHandler->getLastNotify(), + addr + ); if (cb) cb(cr, L_GET_C_BACK_PTR(participant), isAdmin); } void ClientGroupChatRoom::onSubjectChanged (time_t tm, const std::string &subject) { + L_D_T(RemoteConference, dConference); RemoteConference::setSubject(subject); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsSubjectChangedCb cb = linphone_chat_room_cbs_get_subject_changed(cbs); + ConferenceSubjectEvent event( + tm, + dConference->conferenceAddress, + dConference->eventHandler->getLastNotify(), + subject + ); if (cb) cb(cr, subject.c_str()); } void ClientGroupChatRoom::onParticipantDeviceAdded (time_t tm, const Address &addr, const Address &gruu) { + L_D_T(RemoteConference, dConference); shared_ptr participant; if (isMe(addr)) participant = getMe(); @@ -338,9 +370,18 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (time_t tm, const Address &ad return; } participant->getPrivate()->addDevice(gruu); + ConferenceParticipantDeviceEvent event( + EventLog::Type::ConferenceParticipantDeviceAdded, + tm, + dConference->conferenceAddress, + dConference->eventHandler->getLastNotify(), + addr, + gruu + ); } void ClientGroupChatRoom::onParticipantDeviceRemoved (time_t tm, const Address &addr, const Address &gruu) { + L_D_T(RemoteConference, dConference); shared_ptr participant; if (isMe(addr)) participant = getMe(); @@ -351,6 +392,14 @@ void ClientGroupChatRoom::onParticipantDeviceRemoved (time_t tm, const Address & return; } participant->getPrivate()->removeDevice(gruu); + ConferenceParticipantDeviceEvent event( + EventLog::Type::ConferenceParticipantDeviceRemoved, + tm, + dConference->conferenceAddress, + dConference->eventHandler->getLastNotify(), + addr, + gruu + ); } // ----------------------------------------------------------------------------- diff --git a/src/conference/remote-conference-event-handler-p.h b/src/conference/remote-conference-event-handler-p.h index 776435e08..88eba6168 100644 --- a/src/conference/remote-conference-event-handler-p.h +++ b/src/conference/remote-conference-event-handler-p.h @@ -29,11 +29,6 @@ LINPHONE_BEGIN_NAMESPACE class RemoteConferenceEventHandlerPrivate : public ObjectPrivate { -public: - inline unsigned int getLastNotify () const { - return lastNotify; - }; - private: LinphoneCore *core = nullptr; ConferenceListener *listener = nullptr; diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 685f2ef7d..41430353e 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -68,7 +68,7 @@ void RemoteConferenceEventHandler::unsubscribe () { } } -void RemoteConferenceEventHandler::notifyReceived (string xmlBody) { +void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { L_D(); lInfo() << "NOTIFY received for conference " << d->confAddress.asString(); istringstream data(xmlBody); @@ -133,4 +133,9 @@ const Address &RemoteConferenceEventHandler::getConfAddress () const { return d->confAddress; } +unsigned int RemoteConferenceEventHandler::getLastNotify () const { + L_D(); + return d->lastNotify; +}; + LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference-event-handler.h b/src/conference/remote-conference-event-handler.h index 810feb49d..993c1c9e2 100644 --- a/src/conference/remote-conference-event-handler.h +++ b/src/conference/remote-conference-event-handler.h @@ -22,8 +22,6 @@ #include -#include "linphone/types.h" - #include "object/object.h" #include "conference-listener.h" @@ -37,10 +35,11 @@ class RemoteConferenceEventHandler : public Object { ~RemoteConferenceEventHandler (); void subscribe (const Address &confAddress); - void notifyReceived (std::string xmlBody); + void notifyReceived (const std::string &xmlBody); void unsubscribe (); const Address &getConfAddress () const; + unsigned int getLastNotify () const; private: L_DECLARE_PRIVATE(RemoteConferenceEventHandler); From 74e73a84f19ff7e6a209da5dd48b7d28e9ccc90f Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 17 Oct 2017 17:16:02 +0200 Subject: [PATCH 0533/2215] fix(MainDb): better code --- src/db/main-db.cpp | 50 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index c189fd26a..5678d63aa 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -122,14 +122,14 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return q->getLastInsertId(); } - void MainDbPrivate::insertContent (long messageEventId, const Content &content) { + void MainDbPrivate::insertContent (long eventId, const Content &content) { L_Q(); soci::session *session = dbSession.getBackendSession(); long contentTypeId = insertContentType(content.getContentType().asString()); - *session << "INSERT INTO message_content (message_event_id, content_type_id, body) VALUES" - " (:messageEventId, :contentTypeId, :body)", soci::use(messageEventId), soci::use(contentTypeId), + *session << "INSERT INTO message_content (event_id, content_type_id, body) VALUES" + " (:eventId, :contentTypeId, :body)", soci::use(eventId), soci::use(contentTypeId), soci::use(content.getBodyAsString()); long messageContentId = q->getLastInsertId(); @@ -213,26 +213,26 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} soci::use(references.remoteSipAddressId), soci::use(state), soci::use(direction), soci::use(imdnMessageId), soci::use(isSecured ? 1 : 0); - long messageEventId = q->getLastInsertId(); + long eventId = q->getLastInsertId(); for (const auto &content : contents) - insertContent(messageEventId, content); + insertContent(eventId, content); - return messageEventId; + return eventId; } - void MainDbPrivate::insertMessageParticipant (long messageEventId, long sipAddressId, int state) { + void MainDbPrivate::insertMessageParticipant (long eventId, long sipAddressId, int state) { soci::session *session = dbSession.getBackendSession(); soci::statement statement = ( session->prepare << "UPDATE message_participant SET state = :state" - " WHERE message_event_id = :messageEventId AND sip_address_id = :sipAddressId", - soci::use(state), soci::use(messageEventId), soci::use(sipAddressId) + " WHERE event_id = :eventId AND sip_address_id = :sipAddressId", + soci::use(state), soci::use(eventId), soci::use(sipAddressId) ); statement.execute(true); if (statement.get_affected_rows() == 0 && state != static_cast(ChatMessage::State::Displayed)) - *session << "INSERT INTO message_participant (message_event_id, sip_address_id, state)" - " VALUES (:messageEventId, :sipAddressId, :state)", - soci::use(messageEventId), soci::use(sipAddressId), soci::use(state); + *session << "INSERT INTO message_participant (event_id, sip_address_id, state)" + " VALUES (:eventId, :sipAddressId, :state)", + soci::use(eventId), soci::use(sipAddressId), soci::use(state); } // ----------------------------------------------------------------------------- @@ -490,12 +490,12 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS message_participant (" - " message_event_id INT UNSIGNED NOT NULL," + " event_id INT UNSIGNED NOT NULL," " sip_address_id INT UNSIGNED NOT NULL," " state TINYINT UNSIGNED NOT NULL," - " PRIMARY KEY (message_event_id, sip_address_id)," - " FOREIGN KEY (message_event_id)" + " PRIMARY KEY (event_id, sip_address_id)," + " FOREIGN KEY (event_id)" " REFERENCES message_event(event_id)" " ON DELETE CASCADE," " FOREIGN KEY (sip_address_id)" @@ -506,11 +506,11 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS message_content (" " id" + primaryKeyAutoIncrementStr() + "," - " message_event_id INT UNSIGNED NOT NULL," + " event_id INT UNSIGNED NOT NULL," " content_type_id INT UNSIGNED NOT NULL," " body TEXT NOT NULL," - " FOREIGN KEY (message_event_id)" + " FOREIGN KEY (event_id)" " REFERENCES message_event(event_id)" " ON DELETE CASCADE," " FOREIGN KEY (content_type_id)" @@ -532,12 +532,12 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS message_crypto_data (" - " message_event_id INT UNSIGNED NOT NULL," + " event_id INT UNSIGNED NOT NULL," " key VARCHAR(255)," " data BLOB," - " PRIMARY KEY (message_event_id, key)," - " FOREIGN KEY (message_event_id)" + " PRIMARY KEY (event_id, key)," + " FOREIGN KEY (event_id)" " REFERENCES message_event(event_id)" " ON DELETE CASCADE" ")"; @@ -551,16 +551,16 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} participantMessageDeleter += displayedId; participantMessageDeleter += " AND (SELECT COUNT(*) FROM (" " SELECT state FROM message_participant WHERE" - " NEW.message_event_id = message_participant.message_event_id" + " NEW.event_id = message_participant.event_id" " AND state <> "; participantMessageDeleter += displayedId; participantMessageDeleter += " LIMIT 1" " )) = 0" " BEGIN" - " DELETE FROM message_participant WHERE NEW.message_event_id = message_participant.message_event_id;" + " DELETE FROM message_participant WHERE NEW.event_id = message_participant.event_id;" " UPDATE message_event SET state = "; participantMessageDeleter += displayedId; - participantMessageDeleter += " WHERE event_id = NEW.message_event_id;" + participantMessageDeleter += " WHERE event_id = NEW.event_id;" " END"; *session << participantMessageDeleter; @@ -933,7 +933,7 @@ shared_ptr MainDb::findChatRoom (const string &peerAddress) const { d->insertChatRoomParticipant(references.chatRoomId, references.remoteSipAddressId, false); - long messageEventId = d->insertMessageEvent ( + long eventId = d->insertMessageEvent ( references, state, direction, @@ -944,7 +944,7 @@ shared_ptr MainDb::findChatRoom (const string &peerAddress) const { if (state != static_cast(ChatMessage::State::Displayed)) d->insertMessageParticipant( - messageEventId, + eventId, references.remoteSipAddressId, state ); From fe807ccae1ac6fd01c3698f5bbc993cecb56022b Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 17 Oct 2017 17:18:57 +0200 Subject: [PATCH 0534/2215] fix build in tester --- tester/conference-event-tester.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index c12317ac7..437a60387 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -1082,7 +1082,7 @@ void send_subject_changed_notify () { BC_ASSERT_STRING_EQUAL(tester.confSubject.c_str(), "A random test subject"); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); - BC_ASSERT_EQUAL(L_GET_PRIVATE(tester.handler)->getLastNotify(), 1, int, "%d"); + BC_ASSERT_EQUAL(tester.handler->getLastNotify(), 1, int, "%d"); BC_ASSERT_EQUAL(localHandlerPrivate->getLastNotify(), 1, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(bobAddr.asString()) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(aliceAddr.asString()) != tester.participants.end()); @@ -1095,7 +1095,7 @@ void send_subject_changed_notify () { BC_ASSERT_STRING_EQUAL(tester.confSubject.c_str(), "Another random test subject..."); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); - BC_ASSERT_EQUAL(L_GET_PRIVATE(tester.handler)->getLastNotify(), 2, int, "%d"); + BC_ASSERT_EQUAL(tester.handler->getLastNotify(), 2, int, "%d"); BC_ASSERT_EQUAL(localHandlerPrivate->getLastNotify(), 2, int, "%d"); BC_ASSERT_TRUE(tester.participants.find(bobAddr.asString()) != tester.participants.end()); BC_ASSERT_TRUE(tester.participants.find(aliceAddr.asString()) != tester.participants.end()); From 0c9100d573138cdc4e28fe7302d38d989828e00d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 16 Oct 2017 14:08:38 +0200 Subject: [PATCH 0535/2215] Reworking of the EC calibrator API in order to be automatically wrapped --- coreapi/ec-calibrator.c | 33 ++++++++++++++++++++++++++++++++- coreapi/linphonecore.c | 15 +++++++++++++-- coreapi/private.h | 4 ++++ coreapi/vtables.c | 15 +++++++++++++++ include/linphone/callbacks.h | 20 ++++++++++++++++++++ include/linphone/core.h | 18 ++++++++++++++++++ include/linphone/core_utils.h | 23 ++++++++++++++++++----- 7 files changed, 120 insertions(+), 8 deletions(-) diff --git a/coreapi/ec-calibrator.c b/coreapi/ec-calibrator.c index 0c1ce7212..f82e597c1 100644 --- a/coreapi/ec-calibrator.c +++ b/coreapi/ec-calibrator.c @@ -24,7 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mediastreamer2/dtmfgen.h" #include "linphone/lpconfig.h" - +#include "c-wrapper/c-wrapper.h" static void ecc_init_filters(EcCalibrator *ecc){ @@ -325,6 +325,37 @@ int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibration return 0; } +static void _ec_calibration_result_cb(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms, void *user_data) { + linphone_core_notify_ec_calibration_result(lc, status, delay_ms); +} + +static void _ec_calibration_audio_init_cb(void *user_data) { + LinphoneCore *lc = (LinphoneCore *)user_data; + linphone_core_notify_ec_calibration_audio_init(lc); +} + +static void _ec_calibration_audio_uninit_cb(void *user_data) { + LinphoneCore *lc = (LinphoneCore *)user_data; + linphone_core_notify_ec_calibration_audio_uninit(lc); +} + +LinphoneStatus linphone_core_start_echo_canceller_calibration(LinphoneCore *lc) { + unsigned int rate; + + if (lc->ecc!=NULL){ + ms_error("Echo calibration is still on going !"); + return -1; + } + rate = (unsigned int)lp_config_get_int(lc->config,"sound","echo_cancellation_rate",8000); + lc->ecc=ec_calibrator_new(lc->factory, lc->sound_conf.play_sndcard, lc->sound_conf.capt_sndcard, rate, + _ec_calibration_result_cb, + _ec_calibration_audio_init_cb, + _ec_calibration_audio_uninit_cb, lc); + lc->ecc->play_cool_tones = !!lp_config_get_int(lc->config, "sound", "ec_calibrator_cool_tones", 0); + ec_calibrator_start(lc->ecc); + return 0; +} + bool_t linphone_core_has_builtin_echo_canceller(LinphoneCore *lc) { MSFactory * factory = linphone_core_get_ms_factory(lc); MSDevicesInfo *devices = ms_factory_get_devices_info(factory); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ea0417a84..96bb06105 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -436,6 +436,18 @@ void linphone_core_cbs_set_chat_room_instantiated (LinphoneCoreCbs *cbs, Linphon cbs->vtable->chat_room_instantiated = cb; } +void linphone_core_cbs_set_ec_calibration_result(LinphoneCoreCbs *cbs, LinphoneCoreCbsEcCalibrationResultCb cb) { + cbs->vtable->ec_calibration_result = cb; +} + +void linphone_core_cbs_set_ec_calibration_audio_init(LinphoneCoreCbs *cbs, LinphoneCoreCbsEcCalibrationAudioInitCb cb) { + cbs->vtable->ec_calibration_audio_init = cb; +} + +void linphone_core_cbs_set_ec_calibration_audio_uninit(LinphoneCoreCbs *cbs, LinphoneCoreCbsEcCalibrationAudioUninitCb cb) { + cbs->vtable->ec_calibration_audio_uninit = cb; +} + typedef belle_sip_object_t_vptr_t LinphoneCore_vptr_t; BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCore); @@ -2190,7 +2202,6 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig _linphone_core_add_callbacks(lc, internal_cbs, TRUE); belle_sip_object_unref(internal_cbs); - if (cbs != NULL) { _linphone_core_add_callbacks(lc, cbs, FALSE); } else { @@ -7379,4 +7390,4 @@ bool_t linphone_core_has_crappy_opengl(LinphoneCore *lc) { if (sound_description == NULL) return FALSE; if (sound_description->flags & DEVICE_HAS_CRAPPY_OPENGL) return TRUE; return FALSE; -} \ No newline at end of file +} diff --git a/coreapi/private.h b/coreapi/private.h index cd82d149a..be9d0150c 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -1475,6 +1475,10 @@ void linphone_core_notify_call_created(LinphoneCore *lc, LinphoneCall *call); void linphone_core_notify_version_update_check_result_received(LinphoneCore *lc, LinphoneVersionUpdateCheckResult result, const char *version, const char *url); void linphone_core_notify_chat_room_instantiated (LinphoneCore *lc, LinphoneChatRoom *cr); +void linphone_core_notify_ec_calibration_result(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms); +void linphone_core_notify_ec_calibration_audio_init(LinphoneCore *lc); +void linphone_core_notify_ec_calibration_audio_uninit(LinphoneCore *lc); + void set_playback_gain_db(AudioStream *st, float gain); LinphoneMediaDirection media_direction_from_sal_stream_dir(SalStreamDir dir); diff --git a/coreapi/vtables.c b/coreapi/vtables.c index b14221950..280283771 100644 --- a/coreapi/vtables.c +++ b/coreapi/vtables.c @@ -292,6 +292,21 @@ void linphone_core_notify_chat_room_instantiated (LinphoneCore *lc, LinphoneChat cleanup_dead_vtable_refs(lc); } +void linphone_core_notify_ec_calibration_result(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms) { + NOTIFY_IF_EXIST(ec_calibration_result, lc, status, delay_ms); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_ec_calibration_audio_init(LinphoneCore *lc) { + NOTIFY_IF_EXIST(ec_calibration_audio_init, lc); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_ec_calibration_audio_uninit(LinphoneCore *lc) { + NOTIFY_IF_EXIST(ec_calibration_audio_uninit, lc); + cleanup_dead_vtable_refs(lc); +} + static VTableReference * v_table_reference_new(LinphoneCoreCbs *cbs, bool_t internal){ VTableReference *ref=ms_new0(VTableReference,1); ref->valid=TRUE; diff --git a/include/linphone/callbacks.h b/include/linphone/callbacks.h index 1c9b8b9ba..b70febf8b 100644 --- a/include/linphone/callbacks.h +++ b/include/linphone/callbacks.h @@ -492,6 +492,26 @@ typedef void (*LinphoneFriendListCbsSyncStateChangedCb)(LinphoneFriendList *list * @{ */ +/** + * @brief Function prototype used by #linphone_core_cbs_set_ec_calibrator_result(). + * @param lc The core. + * @param status The state of the calibrator. + * @param delay_ms The measured delay if available. + */ +typedef void (*LinphoneCoreCbsEcCalibrationResultCb)(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms); + +/** + * @brief Function prototype used by #linphone_core_cbs_set_ec_calibrator_audio_init(). + * @param lc The core. + */ +typedef void (*LinphoneCoreCbsEcCalibrationAudioInitCb)(LinphoneCore *lc); + +/** + * @biref Function prototype used by #linphone_core_cbs_set_ec_calibrator_audio_uninit(). + * @param lc The core. + */ +typedef void (*LinphoneCoreCbsEcCalibrationAudioUninitCb)(LinphoneCore *lc); + /** * Callback to decrypt incoming LinphoneChatMessage * @param engine ImEncryptionEngine object diff --git a/include/linphone/core.h b/include/linphone/core.h index 9add3df87..3e06c01a0 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -186,6 +186,9 @@ typedef struct _LinphoneCoreVTable{ LinphoneCoreCbsCallCreatedCb call_created; LinphoneCoreCbsVersionUpdateCheckResultReceivedCb version_update_check_result_received; LinphoneCoreCbsChatRoomInstantiatedCb chat_room_instantiated; + LinphoneCoreCbsEcCalibrationResultCb ec_calibration_result; + LinphoneCoreCbsEcCalibrationAudioInitCb ec_calibration_audio_init; + LinphoneCoreCbsEcCalibrationAudioUninitCb ec_calibration_audio_uninit; void *user_data; /** Date: Tue, 17 Oct 2017 17:39:49 +0200 Subject: [PATCH 0536/2215] Handled in Java's genwrapper callbacks with return value --- wrappers/java/genwrapper.py | 19 +++++++++++++++++-- wrappers/java/jni.mustache | 13 +++++++++++-- wrappers/java/migration.sh | 5 ++--- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 9a4d28949..51465d7da 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -483,9 +483,19 @@ class JavaTranslator(object): methodDict['callbackName'] = methodDict['cPrefix'] + '_' + _method.name.to_snake_case() methodDict['jname'] = _method.name.to_camel_case(lower=True) methodDict['return'] = self.translate_as_c_base_type(_method.returnType) + methodDict['jniUpcallMethod'] = 'CallVoidMethod' + methodDict['isJniUpcallBasicType'] = False + methodDict['isJniUpcallObject'] = False if type(_method.returnType) is AbsApi.ClassType: methodDict['return'] += '*' - methodDict['returnIfFail'] = '' if methodDict['return'] == 'void' else ' NULL' #TODO + methodDict['jniUpcallMethod'] = 'CallObjectMethod' + methodDict['isJniUpcallObject'] = True + methodDict['jniUpcallType'] = 'jobject' + elif type(_method.returnType) is AbsApi.BaseType: + methodDict['jniUpcallMethod'] = 'CallIntMethod' + methodDict['jniUpcallType'] = self.translate_type(_method.returnType, jni=True) + methodDict['isJniUpcallBasicType'] = True + methodDict['returnIfFail'] = '' if methodDict['return'] == 'void' else ' NULL' methodDict['hasReturn'] = not methodDict['return'] == 'void' methodDict['isSingleListener'] = not _class.multilistener methodDict['isMultiListener'] = _class.multilistener @@ -531,7 +541,12 @@ class JavaTranslator(object): if (methodDict['return'] == 'void'): methodDict['jparams'] += 'V' else: - pass #TODO + if type(_method.returnType) is AbsApi.ClassType: + methodDict['jparams'] += 'L' + self.jni_path + _method.returnType.desc.name.to_camel_case() + ';' + elif type(_method.returnType) is AbsApi.BaseType: + methodDict['jparams'] += self.translate_java_jni_base_type_name(_method.returnType.name) + else: + pass #TODO return methodDict diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index 607f7af64..bb45e503d 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -210,7 +210,16 @@ static {{return}} {{callbackName}}({{params}}) { jstring j_{{stringName}} = {{stringName}} ? env->NewStringUTF({{stringName}}) : NULL; {{/jstrings}} - env->CallVoidMethod(jlistener, jcallback, {{params_impl}}); + {{#hasReturn}}{{jniUpcallType}} jni_upcall_result = {{/hasReturn}}env->{{jniUpcallMethod}}(jlistener, jcallback, {{params_impl}}); + {{#hasReturn}} + {{#isJniUpcallObject}} + {{return}} c_upcall_result = NULL; + if (jni_upcall_result) c_upcall_result = ({{return}})GetObjectNativePtr(env, jni_upcall_result); + {{/isJniUpcallObject}} + {{#isJniUpcallBasicType}} + {{return}} c_upcall_result = ({{return}}) jni_upcall_result; + {{/isJniUpcallBasicType}} + {{/hasReturn}} {{#jobjects}} if (j_{{objectName}}) { @@ -225,7 +234,7 @@ static {{return}} {{callbackName}}({{params}}) { handle_possible_java_exception(env, jlistener); {{#hasReturn}} - return 0; + return c_upcall_result; {{/hasReturn}} } diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 106156d2c..3d826c470 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -304,13 +304,10 @@ eval "$SED_START 's/linkPhoneNumberWithAccount()/linkAccount()/g' $SED_END" eval "$SED_START 's/zoomVideo(/zoom(/g' $SED_END" eval "$SED_START 's/mLc.setCpuCount(/\/\/mLc.setCpuCount(/g' $SED_END" -#Core.setCpuCount() => Not needed anymore, can be removed # TODO #Tunnel, TunnelConfig -#LinphoneBuffer #AccountCreator.updatePassword => What to do ? # XmlRpcRequest and XmlRpcSession constructors -# Callbacks with return like chat messages' file transfer #Android specifics not wrapped automatically #Core.startEchoCalibration @@ -337,6 +334,8 @@ eval "$SED_START 's/mLc.setCpuCount(/\/\/mLc.setCpuCount(/g' $SED_END" # setPrimaryContact only takes one String argument # AdaptiveRateAlgorithm was an enum, now is nothing # createAddress(userName,domain,null); no longer exists +# Buffer.setContent now takes the size as second parameter +# ChatMessageListener onFileTransferSend now returns the Buffer instead of having it as part of his arguments # # Factory #Factory.createLpConfigFromString => Config.newFromBuffer From b43f52173eef2d980687776279eb4e4fee35bfe9 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 17 Oct 2017 17:48:25 +0200 Subject: [PATCH 0537/2215] Added migration for startEchoCancellerCalibration --- wrappers/java/migration.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 3d826c470..3ffdd48ab 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -265,6 +265,7 @@ eval "$SED_START 's/hasCrappyOpenGL(/hasCrappyOpenGl(/g' $SED_END" eval "$SED_START 's/needsEchoCalibration(/isEchoCancellerCalibrationRequired(/g' $SED_END" eval "$SED_START 's/getCountryCode()/getCountryCallingCode()/g' $SED_END" eval "$SED_START 's/isEchoCancellationEnabled()/echoCancellationEnabled()/g' $SED_END" +eval "$SED_START 's/startEchoCalibration(/startEchoCancellerCalibration(/g' $SED_END" # Removed methods eval "$SED_START 's/.isRegistered()/.getState() == RegistrationState.Ok/g' $SED_END" @@ -310,7 +311,6 @@ eval "$SED_START 's/mLc.setCpuCount(/\/\/mLc.setCpuCount(/g' $SED_END" # XmlRpcRequest and XmlRpcSession constructors #Android specifics not wrapped automatically -#Core.startEchoCalibration # Manual changes required # Some callbacks no longer exist, their name will be "removed", remove them @@ -336,6 +336,7 @@ eval "$SED_START 's/mLc.setCpuCount(/\/\/mLc.setCpuCount(/g' $SED_END" # createAddress(userName,domain,null); no longer exists # Buffer.setContent now takes the size as second parameter # ChatMessageListener onFileTransferSend now returns the Buffer instead of having it as part of his arguments +# Core.startEchoCancellerCalibration no longer takes a parameter # # Factory #Factory.createLpConfigFromString => Config.newFromBuffer From 06032c0340a983a17af96140966d20ea1f1f21f8 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 17 Oct 2017 17:58:01 +0200 Subject: [PATCH 0538/2215] Added new constructors for XmlRpcRequest and XmlRpcSession --- coreapi/linphonecore.c | 4 ++++ coreapi/xmlrpc.c | 4 ++++ include/linphone/core.h | 9 +++++++++ include/linphone/xmlrpc.h | 9 +++++++++ wrappers/java/migration.sh | 2 -- 5 files changed, 26 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 96bb06105..1d9786313 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5962,6 +5962,10 @@ LinphoneAddress * linphone_core_create_address(LinphoneCore *lc, const char *add return linphone_address_new(address); } +LinphoneXmlRpcSession * linphone_core_create_xml_rpc_session(LinphoneCore *lc, const char *url) { + return linphone_xml_rpc_session_new(lc, url); +} + static void linphone_core_uninit(LinphoneCore *lc) { bctbx_list_t *elem = NULL; diff --git a/coreapi/xmlrpc.c b/coreapi/xmlrpc.c index 9410ae309..368e6c622 100644 --- a/coreapi/xmlrpc.c +++ b/coreapi/xmlrpc.c @@ -383,6 +383,10 @@ void linphone_xml_rpc_session_set_user_data(LinphoneXmlRpcSession *session, void session->user_data = ud; } +LinphoneXmlRpcRequest * linphone_xml_rpc_session_create_request(LinphoneXmlRpcSession *session, LinphoneXmlRpcArgType return_type, const char *method) { + return linphone_xml_rpc_request_new(return_type, method); +} + void linphone_xml_rpc_session_send_request(LinphoneXmlRpcSession *session, LinphoneXmlRpcRequest *request) { belle_http_request_listener_callbacks_t cbs = { 0 }; belle_http_request_listener_t *l; diff --git a/include/linphone/core.h b/include/linphone/core.h index 3e06c01a0..68dee15fc 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -5369,6 +5369,15 @@ LINPHONE_PUBLIC LinphoneNatPolicy * linphone_core_create_nat_policy_from_config( **/ LINPHONE_PUBLIC LinphoneAccountCreator * linphone_core_create_account_creator(LinphoneCore *core, const char *xmlrpc_url); +/** + * Create a LinphoneXmlRpcSession for a given url. + * @param[in] lc The LinphoneCore used for the XML-RPC communication + * @param[in] url The URL to the XML-RPC server. Must be NON NULL. + * @return The new LinphoneXmlRpcSession object. + * @ingroup misc +**/ +LINPHONE_PUBLIC LinphoneXmlRpcSession * linphone_core_create_xml_rpc_session(LinphoneCore *lc, const char *url); + #ifdef __cplusplus } diff --git a/include/linphone/xmlrpc.h b/include/linphone/xmlrpc.h index 36283bd15..67f8df2ad 100644 --- a/include/linphone/xmlrpc.h +++ b/include/linphone/xmlrpc.h @@ -208,6 +208,15 @@ LINPHONE_PUBLIC LinphoneXmlRpcRequestCbsResponseCb linphone_xml_rpc_request_cbs_ **/ LINPHONE_PUBLIC void linphone_xml_rpc_request_cbs_set_response(LinphoneXmlRpcRequestCbs *cbs, LinphoneXmlRpcRequestCbsResponseCb cb); +/** + * Creates a LinphoneXmlRpcRequest from a LinphoneXmlRpcSession + * @param[in] session the LinphoneXmlRpcSession + * @param[in] return_type the return type of the request as a LinphoneXmlRpcArgType + * @param[in] method the function name to call + * @return a LinphoneXmlRpcRequest object + */ +LINPHONE_PUBLIC LinphoneXmlRpcRequest * linphone_xml_rpc_session_create_request(LinphoneXmlRpcSession *session, LinphoneXmlRpcArgType return_type, const char *method); + /** * @} */ diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 3ffdd48ab..1f0570779 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -310,8 +310,6 @@ eval "$SED_START 's/mLc.setCpuCount(/\/\/mLc.setCpuCount(/g' $SED_END" #AccountCreator.updatePassword => What to do ? # XmlRpcRequest and XmlRpcSession constructors -#Android specifics not wrapped automatically - # Manual changes required # Some callbacks no longer exist, their name will be "removed", remove them # Above sed commands will create erros in syntax you need to manually fix: From 64438f644f917bc2b5782bc3916e19f8c5f87b24 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 17 Oct 2017 18:12:28 +0200 Subject: [PATCH 0539/2215] Added XmlRpcRequest/XmlRpcSession migration for Java's wrapper --- wrappers/java/migration.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 1f0570779..4049cef89 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -6,7 +6,10 @@ SED_END='{} \;' # Imports eval "$SED_START 's/import org.linphone.tools/import org.linphone.core.tools/g' $SED_END" eval "$SED_START 's/import org.linphone.core.OpenH264DownloadHelperListener/import org.linphone.core.tools.OpenH264DownloadHelperListener/g' $SED_END" -eval "$SED_START 's/import org.linphone.core.LinphoneCore.Transports;/import org.linphone.core.Transports/g' $SED_END" +eval "$SED_START 's/import org.linphone.core.LinphoneCore.Transports/import org.linphone.core.Transports/g' $SED_END" +eval "$SED_START 's/import org.linphone.core.LinphoneXmlRpcRequest.LinphoneXmlRpcRequestListener/import org.linphone.core.XmlRpcRequestListener/g' $SED_END" +eval "$SED_START 's/import org.linphone.core.LinphoneXmlRpcRequestImpl/\/\/import org.linphone.core.XmlRpcRequestImpl/g' $SED_END" +eval "$SED_START 's/import org.linphone.core.LinphoneXmlRpcSessionImpl/\/\/import org.linphone.core.XmlRpcSessionImpl/g' $SED_END" # Listeners eval "$SED_START 's/LinphoneAccountCreator.LinphoneAccountCreatorListener/AccountCreatorListener/g' $SED_END" @@ -304,11 +307,12 @@ eval "$SED_START 's/proxyConfig.lookupCCCFromIso(/org.linphone.core.Utils.getCcc eval "$SED_START 's/linkPhoneNumberWithAccount()/linkAccount()/g' $SED_END" eval "$SED_START 's/zoomVideo(/zoom(/g' $SED_END" eval "$SED_START 's/mLc.setCpuCount(/\/\/mLc.setCpuCount(/g' $SED_END" +eval "$SED_START 's/new XmlRpcRequestImpl(/xmlRpcSession.createRequest(/g' $SED_END" +eval "$SED_START 's/new XmlRpcSessionImpl(LinphoneManager.getLcIfManagerNotDestroyedOrNull(), /LinphoneManager.getLcIfManagerNotDestroyedOrNull().createXmlRpcSession(/g' $SED_END" # TODO #Tunnel, TunnelConfig #AccountCreator.updatePassword => What to do ? -# XmlRpcRequest and XmlRpcSession constructors # Manual changes required # Some callbacks no longer exist, their name will be "removed", remove them @@ -335,6 +339,8 @@ eval "$SED_START 's/mLc.setCpuCount(/\/\/mLc.setCpuCount(/g' $SED_END" # Buffer.setContent now takes the size as second parameter # ChatMessageListener onFileTransferSend now returns the Buffer instead of having it as part of his arguments # Core.startEchoCancellerCalibration no longer takes a parameter +# XmlRpcSession.createRequest takes first the return arg type and then the name of the method, until now it was the other way around + # # Factory #Factory.createLpConfigFromString => Config.newFromBuffer From f738e9bd2d80219510d6e2f0b41fbeb7f2716880 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 17 Oct 2017 18:26:49 +0200 Subject: [PATCH 0540/2215] Rewritten migration script to use only one find/sed instead of 270... --- wrappers/java/migration.sh | 577 +++++++++++++++++-------------------- 1 file changed, 268 insertions(+), 309 deletions(-) diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 4049cef89..f218f752a 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -1,314 +1,273 @@ #!/bin/sh -SED_START='find ./src/android/org/linphone/ -type f -exec sed -i -e ' -SED_END='{} \;' - -# Imports -eval "$SED_START 's/import org.linphone.tools/import org.linphone.core.tools/g' $SED_END" -eval "$SED_START 's/import org.linphone.core.OpenH264DownloadHelperListener/import org.linphone.core.tools.OpenH264DownloadHelperListener/g' $SED_END" -eval "$SED_START 's/import org.linphone.core.LinphoneCore.Transports/import org.linphone.core.Transports/g' $SED_END" -eval "$SED_START 's/import org.linphone.core.LinphoneXmlRpcRequest.LinphoneXmlRpcRequestListener/import org.linphone.core.XmlRpcRequestListener/g' $SED_END" -eval "$SED_START 's/import org.linphone.core.LinphoneXmlRpcRequestImpl/\/\/import org.linphone.core.XmlRpcRequestImpl/g' $SED_END" -eval "$SED_START 's/import org.linphone.core.LinphoneXmlRpcSessionImpl/\/\/import org.linphone.core.XmlRpcSessionImpl/g' $SED_END" - -# Listeners -eval "$SED_START 's/LinphoneAccountCreator.LinphoneAccountCreatorListener/AccountCreatorListener/g' $SED_END" -eval "$SED_START 's/AccountCreator.LinphoneAccountCreatorListener/AccountCreatorListener/g' $SED_END" -eval "$SED_START 's/LinphoneCoreListenerBase/CoreListenerStub/g' $SED_END" -eval "$SED_START 's/LinphoneCoreListener/CoreListener/g' $SED_END" -eval "$SED_START 's/LinphoneChatMessage.LinphoneChatMessageListener/ChatMessageListener/g' $SED_END" - -# Enums -eval "$SED_START 's/Core.LinphoneLimeState/Core.LimeState/g' $SED_END" -eval "$SED_START 's/LinphoneLimeState/LimeState/g' $SED_END" - -eval "$SED_START 's/GlobalState.GlobalOn/Core.GlobalState.On/g' $SED_END" - -eval "$SED_START 's/RegistrationState.RegistrationOk/RegistrationState.Ok/g' $SED_END" -eval "$SED_START 's/RegistrationState.RegistrationFailed/RegistrationState.Failed/g' $SED_END" -eval "$SED_START 's/RegistrationState.RegistrationCleared/RegistrationState.Cleared/g' $SED_END" -eval "$SED_START 's/RegistrationState.RegistrationProgress/RegistrationState.Progress/g' $SED_END" -eval "$SED_START 's/RegistrationState.RegistrationNone/RegistrationState.None/g' $SED_END" - -eval "$SED_START 's/RemoteProvisioningState.ConfiguringSuccessful/ConfiguringState.Successful/g' $SED_END" -eval "$SED_START 's/LinphoneCore.RemoteProvisioningState/Core.ConfiguringState/g' $SED_END" -eval "$SED_START 's/RemoteProvisioningState/ConfiguringState/g' $SED_END" -eval "$SED_START 's/ConfiguringFailed/Failed/g' $SED_END" - -eval "$SED_START 's/CallDirection/Call.Dir/g' $SED_END" - -eval "$SED_START 's/State.CallReleased/State.Released/g' $SED_END" -eval "$SED_START 's/State.CallEnd/State.End/g' $SED_END" -eval "$SED_START 's/State.CallUpdatedByRemote/State.UpdatedByRemote/g' $SED_END" -eval "$SED_START 's/State.CallIncomingEarlyMedia/State.IncomingEarlyMedia/g' $SED_END" -eval "$SED_START 's/State.CallUpdating/State.Updating/g' $SED_END" - -eval "$SED_START 's/LogCollectionUploadState.LogCollectionUploadStateInProgress/LogCollectionUploadState.InProgress/g' $SED_END" -eval "$SED_START 's/LogCollectionUploadState.LogCollectionUploadStateDelivered/LogCollectionUploadState.Delivered/g' $SED_END" -eval "$SED_START 's/LogCollectionUploadState.LogCollectionUploadStateNotDelivered/LogCollectionUploadState.NotDelivered/g' $SED_END" - -eval "$SED_START 's/AccountCreator.RequestStatus/AccountCreator.Status/g' $SED_END" -eval "$SED_START 's/RequestStatus/Status/g' $SED_END" -eval "$SED_START 's/AccountCreator.Status.Ok/AccountCreator.Status.RequestOk/g' $SED_END" -eval "$SED_START 's/AccountCreator.PasswordCheck/AccountCreator.PasswordStatus/g' $SED_END" -eval "$SED_START 's/AccountCreator.PhoneNumberCheck/AccountCreator.PhoneNumberStatus/g' $SED_END" -eval "$SED_START 's/AccountCreator.EmailCheck/AccountCreator.EmailStatus/g' $SED_END" -eval "$SED_START 's/AccountCreator.UsernameCheck/AccountCreator.UsernameStatus/g' $SED_END" -eval "$SED_START 's/AccountCreator.Status.Failed/AccountCreator.Status.RequestFailed/g' $SED_END" -eval "$SED_START 's/AccountCreator.Status.ErrorServer/AccountCreator.Status.ServerError/g' $SED_END" -eval "$SED_START 's/PhoneNumberStatus.CountryCodeInvalid/PhoneNumberStatus.InvalidCountryCode/g' $SED_END" - -eval "$SED_START 's/Reason.Media/Reason.NotAcceptable/g' $SED_END" -eval "$SED_START 's/Reason.BadCredentials/Reason.Forbidden/g' $SED_END" - -eval "$SED_START 's/TransportType.LinphoneTransportUdp/TransportType.Udp/g' $SED_END" -eval "$SED_START 's/TransportType.LinphoneTransportTcp/TransportType.Tcp/g' $SED_END" -eval "$SED_START 's/TransportType.LinphoneTransportTls/TransportType.Tls/g' $SED_END" -eval "$SED_START 's/TransportType.LinphoneTransportDtls/TransportType.Dtls/g' $SED_END" - -eval "$SED_START 's/AddressFamily.INET_6.getInt()/AddressFamily.Inet6.toInt()/g' $SED_END" -eval "$SED_START 's/AddressFamily.INET.getInt()/AddressFamily.Inet.toInt()/g' $SED_END" - -# Classes -eval "$SED_START 's/LpConfig/Config/g' $SED_END" -eval "$SED_START 's/LinphoneCoreException/CoreException/g' $SED_END" -eval "$SED_START 's/LinphoneCoreFactory/Factory/g' $SED_END" -eval "$SED_START 's/LinphoneAccountCreator/AccountCreator/g' $SED_END" -eval "$SED_START 's/LinphoneAddress/Address/g' $SED_END" -eval "$SED_START 's/LinphoneAuthInfo/AuthInfo/g' $SED_END" -eval "$SED_START 's/LinphoneBuffer/Buffer/g' $SED_END" -eval "$SED_START 's/LinphoneCallLog/CallLog/g' $SED_END" -eval "$SED_START 's/LinphoneCallParams/CallParams/g' $SED_END" -eval "$SED_START 's/LinphoneCallStats/CallStats/g' $SED_END" -eval "$SED_START 's/LinphoneCall/Call/g' $SED_END" -eval "$SED_START 's/LinphoneChatMessage/ChatMessage/g' $SED_END" -eval "$SED_START 's/LinphoneChatRoom/ChatRoom/g' $SED_END" -eval "$SED_START 's/LinphoneConferenceParams/ConferenceParams/g' $SED_END" -eval "$SED_START 's/LinphoneConference/Conference/g' $SED_END" -eval "$SED_START 's/LinphoneConfig/Config/g' $SED_END" -eval "$SED_START 's/LinphoneContent/Content/g' $SED_END" -eval "$SED_START 's/LinphoneCore/Core/g' $SED_END" -eval "$SED_START 's/LinphoneEvent/Event/g' $SED_END" -eval "$SED_START 's/LinphoneFriendList/FriendList/g' $SED_END" -eval "$SED_START 's/LinphoneFriend/Friend/g' $SED_END" -eval "$SED_START 's/LinphoneHeaders/Headers/g' $SED_END" -eval "$SED_START 's/LinphoneImNotifyPolicy/ImNotifyPolicy/g' $SED_END" -eval "$SED_START 's/LinphoneInfoMessage/InfoMessage/g' $SED_END" -eval "$SED_START 's/LinphoneNatPolicy/NatPolicy/g' $SED_END" -eval "$SED_START 's/LinphonePayloadType/PayloadType/g' $SED_END" -eval "$SED_START 's/LinphonePlayer/Player/g' $SED_END" -eval "$SED_START 's/LinphonePresence/Presence/g' $SED_END" -eval "$SED_START 's/LinphonePrivacy/Privacy/g' $SED_END" -eval "$SED_START 's/LinphoneProxyConfig/ProxyConfig/g' $SED_END" -eval "$SED_START 's/LinphonePublishState/PublishState/g' $SED_END" -eval "$SED_START 's/LinphoneRange/Range/g' $SED_END" -eval "$SED_START 's/LinphoneStreamType/StreamType/g' $SED_END" -eval "$SED_START 's/LinphoneSubscription/Subscription/g' $SED_END" -eval "$SED_START 's/LinphoneTransports/Transports/g' $SED_END" -eval "$SED_START 's/LinphoneTunnel/Tunnel/g' $SED_END" -eval "$SED_START 's/LinphoneVcard/Vcard/g' $SED_END" -eval "$SED_START 's/LinphoneXmlRpc/XmlRpc/g' $SED_END" - -# Callbacks -# # Account creator -eval "$SED_START 's/onAccountCreatorIsAccountUsed/onIsAccountExist/g' $SED_END" -eval "$SED_START 's/onAccountCreatorAccountCreated/onCreateAccount/g' $SED_END" -eval "$SED_START 's/onAccountCreatorAccountActivated/onActivateAccount/g' $SED_END" -eval "$SED_START 's/onAccountCreatorAccountLinkedWithPhoneNumber/onLinkAccount/g' $SED_END" -eval "$SED_START 's/onAccountCreatorPhoneNumberLinkActivated/onActivateAlias/g' $SED_END" -eval "$SED_START 's/onAccountCreatorIsAccountActivated/onIsAccountActivated/g' $SED_END" -eval "$SED_START 's/onAccountCreatorPhoneAccountRecovered/onRecoverAccount/g' $SED_END" -eval "$SED_START 's/onAccountCreatorIsAccountLinked/onIsAccountLinked/g' $SED_END" -eval "$SED_START 's/onAccountCreatorIsPhoneNumberUsed/onIsAliasUsed/g' $SED_END" -eval "$SED_START 's/onAccountCreatorPasswordUpdated/onUpdateAccount/g' $SED_END" -eval "$SED_START 's/(AccountCreator accountCreator, Status status)/(AccountCreator accountCreator, Status status, String resp)/g' $SED_END" -eval "$SED_START 's/(AccountCreator accountCreator, AccountCreator.Status status)/(AccountCreator accountCreator, AccountCreator.Status status, String resp)/g' $SED_END" - -# # Chat message -eval "$SED_START 's/onChatMessageStateChanged/onMsgStateChanged/g' $SED_END" -eval "$SED_START 's/onChatMessageFileTransferProgressChanged/onFileTransferProgressIndication/g' $SED_END" -#eval "$SED_START 's/onChatMessageFileTransferSent//g' $SED_END" -#eval "$SED_START 's/onChatMessageFileTransferReceived//g' $SED_END" - -# # Core -eval "$SED_START 's/authInfoRequested/removed/g' $SED_END" # Removed -eval "$SED_START 's/show(Core/removed(/g' $SED_END" # Removed -eval "$SED_START 's/displayStatus/removed/g' $SED_END" # Removed -eval "$SED_START 's/displayMessage/removed/g' $SED_END" # Removed -eval "$SED_START 's/displayWarning/removed/g' $SED_END" # Removed -eval "$SED_START 's/fileTransferProgressIndication/removed/g' $SED_END" # Removed -eval "$SED_START 's/fileTransferRecv/removed/g' $SED_END" # Removed -eval "$SED_START 's/fileTransferSend/removed/g' $SED_END" # Removed -eval "$SED_START 's/notifyReceived(Core lc, Event/onNotifyReceived(Core lc, Event/g' $SED_END" -eval "$SED_START 's/notifyReceived/removed/g' $SED_END" # Removed -#eval "$SED_START 's/ecCalibrationStatus//g' $SED_END" -eval "$SED_START 's/publishStateChanged/onPublishStateChanged/g' $SED_END" # Removed -eval "$SED_START 's/messageReceivedUnableToDecrypted/removed/g' $SED_END" # Removed -eval "$SED_START 's/callStatsUpdated/onCallStatsUpdated/g' $SED_END" -eval "$SED_START 's/authenticationRequested/onAuthenticationRequested/g' $SED_END" -eval "$SED_START 's/newSubscriptionRequest/onNewSubscriptionRequested/g' $SED_END" -eval "$SED_START 's/notifyPresenceReceived/onNotifyPresenceReceived/g' $SED_END" -eval "$SED_START 's/dtmfReceived/onDtmfReceived/g' $SED_END" -eval "$SED_START 's/transferState/onTransferStateChanged/g' $SED_END" -eval "$SED_START 's/infoReceived/onInfoReceived/g' $SED_END" -eval "$SED_START 's/subscriptionStateChanged/onSubscriptionStateChanged/g' $SED_END" -eval "$SED_START 's/globalState/onGlobalStateChanged/g' $SED_END" -eval "$SED_START 's/registrationState/onRegistrationStateChanged/g' $SED_END" -eval "$SED_START 's/configuringStatus/onConfiguringStatus/g' $SED_END" -eval "$SED_START 's/messageReceived/onMessageReceived/g' $SED_END" -eval "$SED_START 's/callState/onCallStateChanged/g' $SED_END" -eval "$SED_START 's/callEncryptionChanged/onCallEncryptionChanged/g' $SED_END" -eval "$SED_START 's/isComposingReceived/onIsComposingReceived/g' $SED_END" -eval "$SED_START 's/uploadProgressIndication/onLogCollectionUploadProgressIndication/g' $SED_END" -eval "$SED_START 's/uploadStateChanged/onLogCollectionUploadStateChanged/g' $SED_END" -eval "$SED_START 's/friendListCreated/onFriendListCreated/g' $SED_END" -eval "$SED_START 's/friendListRemoved/onFriendListRemoved/g' $SED_END" -eval "$SED_START 's/networkReachableChanged/onNetworkReachable/g' $SED_END" - -# # Friend list -eval "$SED_START 's/onFriendCreated/onContactCreated/g' $SED_END" -eval "$SED_START 's/onFriendUpdated/onContactUpdated/g' $SED_END" -eval "$SED_START 's/onFriendDeleted/onContactDeleted/g' $SED_END" -eval "$SED_START 's/onFriendSyncStatusChanged/onSyncStatusChanged/g' $SED_END" - -# # XmlRpc request -eval "$SED_START 's/onXmlRpcRequestResponse/onResponse/g' $SED_END" - -# Methods -eval "$SED_START 's/getFriendsLists()/getFriends()/g' $SED_END" -eval "$SED_START 's/getFriendLists()/getFriendsLists()/g' $SED_END" -eval "$SED_START 's/getFriendList(/getFriendsLists(/g' $SED_END" -eval "$SED_START 's/getIdentity(/getIdentityAddress(/g' $SED_END" -eval "$SED_START 's/isTunnelAvailable()/tunnelAvailable()/g' $SED_END" -eval "$SED_START 's/setZrtpSecretsCache(/setZrtpSecretsFile(/g' $SED_END" -eval "$SED_START 's/setRootCA(/setRootCa(/g' $SED_END" -eval "$SED_START 's/isInComingInvitePending()/isIncomingInvitePending()/g' $SED_END" -eval "$SED_START 's/getAudioCodecs()/getAudioPayloadTypes()/g' $SED_END" -eval "$SED_START 's/getVideoCodecs()/getVideoPayloadTypes()/g' $SED_END" -eval "$SED_START 's/getMime()/getMimeType()/g' $SED_END" -eval "$SED_START 's/getFrom()/getFromAddress()/g' $SED_END" -eval "$SED_START 's/getTo()/getToAddress()/g' $SED_END" -eval "$SED_START 's/getUserName()/getUsername()/g' $SED_END" -eval "$SED_START 's/getLimeEncryption()/limeEnabled()/g' $SED_END" -eval "$SED_START 's/getDirection/getDir/g' $SED_END" -eval "$SED_START 's/.getVideoEnabled()/.videoEnabled()/g' $SED_END" -eval "$SED_START 's/.getDataAsString()/.getStringBuffer()/g' $SED_END" -eval "$SED_START 's/getEventName()/getName()/g' $SED_END" -eval "$SED_START 's/setPlaybackGain(/setPlaybackGainDb(/g' $SED_END" -eval "$SED_START 's/isIncall()/inCall()/g' $SED_END" -eval "$SED_START 's/setVideoEnabled(/enableVideo(/g' $SED_END" -eval "$SED_START 's/setAudioBandwidth(/setAudioBandwidthLimit(/g' $SED_END" -eval "$SED_START 's/isAuthenticationTokenVerified()/getAuthenticationTokenVerified()/g' $SED_END" -eval "$SED_START 's/isMicMuted()/!micEnabled()/g' $SED_END" -eval "$SED_START 's/isLowBandwidthEnabled()/lowBandwidthEnabled()/g' $SED_END" -eval "$SED_START 's/muteMic(/enableMic(!/g' $SED_END" -eval "$SED_START 's/getRate()/getClockRate()/g' $SED_END" -eval "$SED_START 's/getSentVideoSize()/getSentVideoDefinition()/g' $SED_END" -eval "$SED_START 's/getReceivedVideoSize()/getReceivedVideoDefinition()/g' $SED_END" -eval "$SED_START 's/getUsedAudioCodec()/getUsedAudioPayloadType()/g' $SED_END" -eval "$SED_START 's/getUsedVideoCodec()/getUsedVideoPayloadType()/g' $SED_END" -eval "$SED_START 's/setVideoWindow(/setNativeVideoWindowId(/g' $SED_END" -eval "$SED_START 's/setPreviewWindow(/setNativePreviewWindowId(/g' $SED_END" -eval "$SED_START 's/islimeAvailable()/limeAvailable()/g' $SED_END" -eval "$SED_START 's/createChatMessage(/createMessage(/g' $SED_END" -#For messages only -eval "$SED_START 's/message.getStatus()/message.getState()/g' $SED_END" -# -eval "$SED_START 's/reSend()/resend()/g' $SED_END" -eval "$SED_START 's/setAppData(/setAppdata(/g' $SED_END" -eval "$SED_START 's/getAppData()/getAppdata()/g' $SED_END" -eval "$SED_START 's/getOrCreateChatRoom(/getChatRoomFromUri(/g' $SED_END" -eval "$SED_START 's/findFriendByAddress(/findFriend(/g' $SED_END" -eval "$SED_START 's/getTimestamp()/getStartDate()/g' $SED_END" -#For ProxyConfigs only -eval "$SED_START 's/lpc.getAddress()/lpc.getIdentityAddress()/g' $SED_END" -eval "$SED_START 's/cfg.getAddress()/cfg.getIdentityAddress()/g' $SED_END" -eval "$SED_START 's/prxCfg.getAddress()/prxCfg.getIdentityAddress()/g' $SED_END" -eval "$SED_START 's/proxy.getAddress()/proxy.getIdentityAddress()/g' $SED_END" -eval "$SED_START 's/getProxyConfig(n).getAddress()/getProxyConfig(n).getIdentityAddress()/g' $SED_END" -# -eval "$SED_START 's/getCallDuration()/getDuration()/g' $SED_END" -eval "$SED_START 's/isVCardSupported()/vcardSupported()/g' $SED_END" -eval "$SED_START 's/getPresenceModelForUri(/getPresenceModelForUriOrTel(/g' $SED_END" -eval "$SED_START 's/setAvpfRRInterval(/setAvpfRrInterval(/g' $SED_END" -eval "$SED_START 's/getAvpfRRInterval(/getAvpfRrInterval(/g' $SED_END" -eval "$SED_START 's/getProxy()/getServerAddr()/g' $SED_END" -eval "$SED_START 's/setProxy(/setServerAddr(/g' $SED_END" -eval "$SED_START 's/setIdentity(/setIdentityAddress(/g' $SED_END" -eval "$SED_START 's/setUserId(/setUserid(/g' $SED_END" -eval "$SED_START 's/getUserId(/getUserid(/g' $SED_END" -eval "$SED_START 's/getAuthInfosList(/getAuthInfoList(/g' $SED_END" -eval "$SED_START 's/getSignalingTransportPorts()/getTransports()/g' $SED_END" -eval "$SED_START 's/setSignalingTransportPorts(/setTransports(/g' $SED_END" -eval "$SED_START 's/isIpv6Enabled()/ipv6Enabled()/g' $SED_END" -eval "$SED_START 's/isAdaptiveRateControlEnabled()/adaptiveRateControlEnabled()/g' $SED_END" -eval "$SED_START 's/setLimeEncryption(/enableLime(/g' $SED_END" -#For enums only -eval "$SED_START 's/.value()/.toInt()/g' $SED_END" -# -eval "$SED_START 's/clearAuthInfos()/clearAllAuthInfo()/g' $SED_END" -eval "$SED_START 's/clearProxyConfigs()/clearProxyConfig()/g' $SED_END" -eval "$SED_START 's/isVideoSupported()/videoSupported()/g' $SED_END" -eval "$SED_START 's/VideoDefinition().toDisplayableString()/VideoDefinition().getName()/g' $SED_END" -eval "$SED_START 's/isAccountUsed()/isAccountExist()/g' $SED_END" -eval "$SED_START 's/loadXmlFile(/loadFromXmlFile(/g' $SED_END" -eval "$SED_START 's/activatePhoneNumberLink()/activateAlias()/g' $SED_END" -eval "$SED_START 's/isPhoneNumberUsed()/isAliasUsed()/g' $SED_END" -eval "$SED_START 's/recoverPhoneAccount()/recoverAccount()/g' $SED_END" -eval "$SED_START 's/isLimeEncryptionAvailable()/limeAvailable()/g' $SED_END" -eval "$SED_START 's/getUseRfc2833ForDtmfs/getUseRfc2833ForDtmf/g' $SED_END" -eval "$SED_START 's/setUseRfc2833ForDtmfs/setUseRfc2833ForDtmf/g' $SED_END" -eval "$SED_START 's/getUseSipInfoForDtmfs/getUseInfoForDtmf/g' $SED_END" -eval "$SED_START 's/setUseSipInfoForDtmfs/setUseInfoForDtmf/g' $SED_END" -eval "$SED_START 's/getIncomingTimeout/getIncTimeout/g' $SED_END" -eval "$SED_START 's/setIncomingTimeout/setIncTimeout/g' $SED_END" -eval "$SED_START 's/migrateCallLogs()/migrateLogsFromRcToDb()/g' $SED_END" -eval "$SED_START 's/setRLSUri/setRlsUri/g' $SED_END" -eval "$SED_START 's/hasCrappyOpenGL(/hasCrappyOpenGl(/g' $SED_END" -eval "$SED_START 's/needsEchoCalibration(/isEchoCancellerCalibrationRequired(/g' $SED_END" -eval "$SED_START 's/getCountryCode()/getCountryCallingCode()/g' $SED_END" -eval "$SED_START 's/isEchoCancellationEnabled()/echoCancellationEnabled()/g' $SED_END" -eval "$SED_START 's/startEchoCalibration(/startEchoCancellerCalibration(/g' $SED_END" - -# Removed methods -eval "$SED_START 's/.isRegistered()/.getState() == RegistrationState.Ok/g' $SED_END" -eval "$SED_START 's/isInConference()/(getConference() != null)/g' $SED_END" -eval "$SED_START 's/getAudioStats()/getStats(StreamType.Audio)/g' $SED_END" -eval "$SED_START 's/getVideoStats()/getStats(StreamType.Video)/g' $SED_END" -eval "$SED_START 's/getVcardToString()/getVcard().asVcard4String()/g' $SED_END" -eval "$SED_START 's/getVideoAutoInitiatePolicy()/getVideoActivationPolicy().getAutomaticallyInitiate()/g' $SED_END" -eval "$SED_START 's/setFamilyName(/getVcard().setFamilyName(/g' $SED_END" -eval "$SED_START 's/setGivenName(/getVcard().setGivenName(/g' $SED_END" -eval "$SED_START 's/\.setOrganization(/\.getVcard().setOrganization(/g' $SED_END" -eval "$SED_START 's/getFamilyName()/getVcard().getFamilyName()/g' $SED_END" -eval "$SED_START 's/getGivenName()/getVcard().getGivenName()/g' $SED_END" -eval "$SED_START 's/\.getOrganization()/\.getVcard().getOrganization()/g' $SED_END" -eval "$SED_START 's/enableAvpf(/setAvpfMode(AVPFMode.Enabled)/g' $SED_END" -eval "$SED_START 's/transports.udp = /transports.setUdpPort(/g' $SED_END" -eval "$SED_START 's/transports.tcp = /transports.setTcpPort(/g' $SED_END" -eval "$SED_START 's/transports.tls = /transports.setTlsPort(/g' $SED_END" -eval "$SED_START 's/transports.udp/transports.getUdpPort()/g' $SED_END" -eval "$SED_START 's/transports.tcp/transports.getTcpPort()/g' $SED_END" -eval "$SED_START 's/transports.tls/transports.getTlsPort()/g' $SED_END" -eval "$SED_START 's/getPrimaryContactUsername()/getPrimaryContactParsed().getUsername()/g' $SED_END" -eval "$SED_START 's/getPrimaryContactDisplayName()/getPrimaryContactParsed().getDisplayName()/g' $SED_END" -eval "$SED_START 's/.sendDtmf(/.getCurrentCall().sendDtmf(/g' $SED_END" -eval "$SED_START 's/content.getData() == null/content.getSize() == 0/'g $SED_END" -eval "$SED_START 's/lc.downloadOpenH264Enabled()/OpenH264DownloadHelper.isOpenH264DownloadEnabled()/g' $SED_END" -eval "$SED_START 's/LinphoneManager.getLc().downloadOpenH264Enabled()/OpenH264DownloadHelper.isOpenH264DownloadEnabled()/g' $SED_END" -eval "$SED_START 's/getLc().enableDownloadOpenH264(/OpenH264DownloadHelper.setOpenH264DownloadEnabled(/g' $SED_END" -eval "$SED_START 's/enableDownloadOpenH264(/OpenH264DownloadHelper.enableDownloadOpenH264(/g' $SED_END" -eval "$SED_START 's/mLc.destroy()/mLc = null/g' $SED_END" -eval "$SED_START 's/getAllDialPlan()/getDialPlans()/g' $SED_END" -eval "$SED_START 's/getCountryName()/getCountry()/g' $SED_END" -eval "$SED_START 's/getMSFactory()/getMediastreamerFactory()/g' $SED_END" -eval "$SED_START 's/accountCreator.getPrefix(/org.linphone.core.Utils.getPrefixFromE164(/g' $SED_END" -eval "$SED_START 's/proxyConfig.lookupCCCFromIso(/org.linphone.core.Utils.getCccFromIso(/g' $SED_END" -eval "$SED_START 's/linkPhoneNumberWithAccount()/linkAccount()/g' $SED_END" -eval "$SED_START 's/zoomVideo(/zoom(/g' $SED_END" -eval "$SED_START 's/mLc.setCpuCount(/\/\/mLc.setCpuCount(/g' $SED_END" -eval "$SED_START 's/new XmlRpcRequestImpl(/xmlRpcSession.createRequest(/g' $SED_END" -eval "$SED_START 's/new XmlRpcSessionImpl(LinphoneManager.getLcIfManagerNotDestroyedOrNull(), /LinphoneManager.getLcIfManagerNotDestroyedOrNull().createXmlRpcSession(/g' $SED_END" +find ./src/android/org/linphone/ -type f -exec sed -i -e "s/import org.linphone.tools/import org.linphone.core.tools/g; \ +s/import org.linphone.core.OpenH264DownloadHelperListener/import org.linphone.core.tools.OpenH264DownloadHelperListener/g; \ +s/import org.linphone.core.LinphoneCore.Transports/import org.linphone.core.Transports/g; \ +s/import org.linphone.core.LinphoneXmlRpcRequest.LinphoneXmlRpcRequestListener/import org.linphone.core.XmlRpcRequestListener/g; \ +s/import org.linphone.core.LinphoneXmlRpcRequestImpl/\/\/import org.linphone.core.XmlRpcRequestImpl/g; \ +s/import org.linphone.core.LinphoneXmlRpcSessionImpl/\/\/import org.linphone.core.XmlRpcSessionImpl/g; \ +s/LinphoneAccountCreator.LinphoneAccountCreatorListener/AccountCreatorListener/g; \ +s/AccountCreator.LinphoneAccountCreatorListener/AccountCreatorListener/g; \ +s/LinphoneCoreListenerBase/CoreListenerStub/g; \ +s/LinphoneCoreListener/CoreListener/g; \ +s/LinphoneChatMessage.LinphoneChatMessageListener/ChatMessageListener/g; \ +s/Core.LinphoneLimeState/Core.LimeState/g; \ +s/LinphoneLimeState/LimeState/g; \ +s/GlobalState.GlobalOn/Core.GlobalState.On/g; \ +s/RegistrationState.RegistrationOk/RegistrationState.Ok/g; \ +s/RegistrationState.RegistrationFailed/RegistrationState.Failed/g; \ +s/RegistrationState.RegistrationCleared/RegistrationState.Cleared/g; \ +s/RegistrationState.RegistrationProgress/RegistrationState.Progress/g; \ +s/RegistrationState.RegistrationNone/RegistrationState.None/g; \ +s/RemoteProvisioningState.ConfiguringSuccessful/ConfiguringState.Successful/g; \ +s/LinphoneCore.RemoteProvisioningState/Core.ConfiguringState/g; \ +s/RemoteProvisioningState/ConfiguringState/g; \ +s/ConfiguringFailed/Failed/g; \ +s/CallDirection/Call.Dir/g; \ +s/State.CallReleased/State.Released/g; \ +s/State.CallEnd/State.End/g; \ +s/State.CallUpdatedByRemote/State.UpdatedByRemote/g; \ +s/State.CallIncomingEarlyMedia/State.IncomingEarlyMedia/g; \ +s/State.CallUpdating/State.Updating/g; \ +s/LogCollectionUploadState.LogCollectionUploadStateInProgress/LogCollectionUploadState.InProgress/g; \ +s/LogCollectionUploadState.LogCollectionUploadStateDelivered/LogCollectionUploadState.Delivered/g; \ +s/LogCollectionUploadState.LogCollectionUploadStateNotDelivered/LogCollectionUploadState.NotDelivered/g; \ +s/AccountCreator.RequestStatus/AccountCreator.Status/g; \ +s/RequestStatus/Status/g; \ +s/AccountCreator.Status.Ok/AccountCreator.Status.RequestOk/g; \ +s/AccountCreator.PasswordCheck/AccountCreator.PasswordStatus/g; \ +s/AccountCreator.PhoneNumberCheck/AccountCreator.PhoneNumberStatus/g; \ +s/AccountCreator.EmailCheck/AccountCreator.EmailStatus/g; \ +s/AccountCreator.UsernameCheck/AccountCreator.UsernameStatus/g; \ +s/AccountCreator.Status.Failed/AccountCreator.Status.RequestFailed/g; \ +s/AccountCreator.Status.ErrorServer/AccountCreator.Status.ServerError/g; \ +s/PhoneNumberStatus.CountryCodeInvalid/PhoneNumberStatus.InvalidCountryCode/g; \ +s/Reason.Media/Reason.NotAcceptable/g; \ +s/Reason.BadCredentials/Reason.Forbidden/g; \ +s/TransportType.LinphoneTransportUdp/TransportType.Udp/g; \ +s/TransportType.LinphoneTransportTcp/TransportType.Tcp/g; \ +s/TransportType.LinphoneTransportTls/TransportType.Tls/g; \ +s/TransportType.LinphoneTransportDtls/TransportType.Dtls/g; \ +s/AddressFamily.INET_6.getInt()/AddressFamily.Inet6.toInt()/g; \ +s/AddressFamily.INET.getInt()/AddressFamily.Inet.toInt()/g; \ +s/LpConfig/Config/g; \ +s/LinphoneCoreException/CoreException/g; \ +s/LinphoneCoreFactory/Factory/g; \ +s/LinphoneAccountCreator/AccountCreator/g; \ +s/LinphoneAddress/Address/g; \ +s/LinphoneAuthInfo/AuthInfo/g; \ +s/LinphoneBuffer/Buffer/g; \ +s/LinphoneCallLog/CallLog/g; \ +s/LinphoneCallParams/CallParams/g; \ +s/LinphoneCallStats/CallStats/g; \ +s/LinphoneCall/Call/g; \ +s/LinphoneChatMessage/ChatMessage/g; \ +s/LinphoneChatRoom/ChatRoom/g; \ +s/LinphoneConferenceParams/ConferenceParams/g; \ +s/LinphoneConference/Conference/g; \ +s/LinphoneConfig/Config/g; \ +s/LinphoneContent/Content/g; \ +s/LinphoneCore/Core/g; \ +s/LinphoneEvent/Event/g; \ +s/LinphoneFriendList/FriendList/g; \ +s/LinphoneFriend/Friend/g; \ +s/LinphoneHeaders/Headers/g; \ +s/LinphoneImNotifyPolicy/ImNotifyPolicy/g; \ +s/LinphoneInfoMessage/InfoMessage/g; \ +s/LinphoneNatPolicy/NatPolicy/g; \ +s/LinphonePayloadType/PayloadType/g; \ +s/LinphonePlayer/Player/g; \ +s/LinphonePresence/Presence/g; \ +s/LinphonePrivacy/Privacy/g; \ +s/LinphoneProxyConfig/ProxyConfig/g; \ +s/LinphonePublishState/PublishState/g; \ +s/LinphoneRange/Range/g; \ +s/LinphoneStreamType/StreamType/g; \ +s/LinphoneSubscription/Subscription/g; \ +s/LinphoneTransports/Transports/g; \ +s/LinphoneTunnel/Tunnel/g; \ +s/LinphoneVcard/Vcard/g; \ +s/LinphoneXmlRpc/XmlRpc/g; \ +s/onAccountCreatorIsAccountUsed/onIsAccountExist/g; \ +s/onAccountCreatorAccountCreated/onCreateAccount/g; \ +s/onAccountCreatorAccountActivated/onActivateAccount/g; \ +s/onAccountCreatorAccountLinkedWithPhoneNumber/onLinkAccount/g; \ +s/onAccountCreatorPhoneNumberLinkActivated/onActivateAlias/g; \ +s/onAccountCreatorIsAccountActivated/onIsAccountActivated/g; \ +s/onAccountCreatorPhoneAccountRecovered/onRecoverAccount/g; \ +s/onAccountCreatorIsAccountLinked/onIsAccountLinked/g; \ +s/onAccountCreatorIsPhoneNumberUsed/onIsAliasUsed/g; \ +s/onAccountCreatorPasswordUpdated/onUpdateAccount/g; \ +s/(AccountCreator accountCreator, Status status)/(AccountCreator accountCreator, Status status, String resp)/g; \ +s/(AccountCreator accountCreator, AccountCreator.Status status)/(AccountCreator accountCreator, AccountCreator.Status status, String resp)/g; \ +s/onChatMessageStateChanged/onMsgStateChanged/g; \ +s/onChatMessageFileTransferProgressChanged/onFileTransferProgressIndication/g; \ +s/onChatMessageFileTransferSent/onFileTransferSend/g; \ +s/onChatMessageFileTransferReceived/onFileTransferRecv/g; \ +s/authInfoRequested/removed/g; \ +s/show(Core/removed(/g; \ +s/displayStatus/removed/g; \ +s/displayMessage/removed/g; \ +s/displayWarning/removed/g; \ +s/fileTransferProgressIndication/removed/g; \ +s/fileTransferRecv/removed/g; \ +s/fileTransferSend/removed/g; \ +s/notifyReceived(Core lc, Event/onNotifyReceived(Core lc, Event/g; \ +s/notifyReceived/removed/g; \ +s/ecCalibrationStatus/onEcCalibrationResult/g; \ +s/publishStateChanged/onPublishStateChanged/g; \ +s/messageReceivedUnableToDecrypted/removed/g; \ +s/callStatsUpdated/onCallStatsUpdated/g; \ +s/authenticationRequested/onAuthenticationRequested/g; \ +s/newSubscriptionRequest/onNewSubscriptionRequested/g; \ +s/notifyPresenceReceived/onNotifyPresenceReceived/g; \ +s/dtmfReceived/onDtmfReceived/g; \ +s/transferState/onTransferStateChanged/g; \ +s/infoReceived/onInfoReceived/g; \ +s/subscriptionStateChanged/onSubscriptionStateChanged/g; \ +s/globalState/onGlobalStateChanged/g; \ +s/registrationState/onRegistrationStateChanged/g; \ +s/configuringStatus/onConfiguringStatus/g; \ +s/messageReceived/onMessageReceived/g; \ +s/callState/onCallStateChanged/g; \ +s/callEncryptionChanged/onCallEncryptionChanged/g; \ +s/isComposingReceived/onIsComposingReceived/g; \ +s/uploadProgressIndication/onLogCollectionUploadProgressIndication/g; \ +s/uploadStateChanged/onLogCollectionUploadStateChanged/g; \ +s/friendListCreated/onFriendListCreated/g; \ +s/friendListRemoved/onFriendListRemoved/g; \ +s/networkReachableChanged/onNetworkReachable/g; \ +s/onFriendCreated/onContactCreated/g; \ +s/onFriendUpdated/onContactUpdated/g; \ +s/onFriendDeleted/onContactDeleted/g; \ +s/onFriendSyncStatusChanged/onSyncStatusChanged/g; \ +s/onXmlRpcRequestResponse/onResponse/g; \ +s/getFriendsLists()/getFriends()/g; \ +s/getFriendLists()/getFriendsLists()/g; \ +s/getFriendList(/getFriendsLists(/g; \ +s/getIdentity(/getIdentityAddress(/g; \ +s/isTunnelAvailable()/tunnelAvailable()/g; \ +s/setZrtpSecretsCache(/setZrtpSecretsFile(/g; \ +s/setRootCA(/setRootCa(/g; \ +s/isInComingInvitePending()/isIncomingInvitePending()/g; \ +s/getAudioCodecs()/getAudioPayloadTypes()/g; \ +s/getVideoCodecs()/getVideoPayloadTypes()/g; \ +s/getMime()/getMimeType()/g; \ +s/getFrom()/getFromAddress()/g; \ +s/getTo()/getToAddress()/g; \ +s/getUserName()/getUsername()/g; \ +s/getLimeEncryption()/limeEnabled()/g; \ +s/getDirection/getDir/g; \ +s/.getVideoEnabled()/.videoEnabled()/g; \ +s/.getDataAsString()/.getStringBuffer()/g; \ +s/getEventName()/getName()/g; \ +s/setPlaybackGain(/setPlaybackGainDb(/g; \ +s/isIncall()/inCall()/g; \ +s/setVideoEnabled(/enableVideo(/g; \ +s/setAudioBandwidth(/setAudioBandwidthLimit(/g; \ +s/isAuthenticationTokenVerified()/getAuthenticationTokenVerified()/g; \ +s/isMicMuted()/!micEnabled()/g; \ +s/isLowBandwidthEnabled()/lowBandwidthEnabled()/g; \ +s/muteMic(/enableMic(!/g; \ +s/getRate()/getClockRate()/g; \ +s/getSentVideoSize()/getSentVideoDefinition()/g; \ +s/getReceivedVideoSize()/getReceivedVideoDefinition()/g; \ +s/getUsedAudioCodec()/getUsedAudioPayloadType()/g; \ +s/getUsedVideoCodec()/getUsedVideoPayloadType()/g; \ +s/setVideoWindow(/setNativeVideoWindowId(/g; \ +s/setPreviewWindow(/setNativePreviewWindowId(/g; \ +s/islimeAvailable()/limeAvailable()/g; \ +s/createChatMessage(/createMessage(/g; \ +s/message.getStatus()/message.getState()/g; \ +s/reSend()/resend()/g; \ +s/setAppData(/setAppdata(/g; \ +s/getAppData()/getAppdata()/g; \ +s/getOrCreateChatRoom(/getChatRoomFromUri(/g; \ +s/findFriendByAddress(/findFriend(/g; \ +s/getTimestamp()/getStartDate()/g; \ +s/lpc.getAddress()/lpc.getIdentityAddress()/g; \ +s/cfg.getAddress()/cfg.getIdentityAddress()/g; \ +s/prxCfg.getAddress()/prxCfg.getIdentityAddress()/g; \ +s/proxy.getAddress()/proxy.getIdentityAddress()/g; \ +s/getProxyConfig(n).getAddress()/getProxyConfig(n).getIdentityAddress()/g; \ +s/getCallDuration()/getDuration()/g; \ +s/isVCardSupported()/vcardSupported()/g; \ +s/getPresenceModelForUri(/getPresenceModelForUriOrTel(/g; \ +s/setAvpfRRInterval(/setAvpfRrInterval(/g; \ +s/getAvpfRRInterval(/getAvpfRrInterval(/g; \ +s/getProxy()/getServerAddr()/g; \ +s/setProxy(/setServerAddr(/g; \ +s/setIdentity(/setIdentityAddress(/g; \ +s/setUserId(/setUserid(/g; \ +s/getUserId(/getUserid(/g; \ +s/getAuthInfosList(/getAuthInfoList(/g; \ +s/getSignalingTransportPorts()/getTransports()/g; \ +s/setSignalingTransportPorts(/setTransports(/g; \ +s/isIpv6Enabled()/ipv6Enabled()/g; \ +s/isAdaptiveRateControlEnabled()/adaptiveRateControlEnabled()/g; \ +s/setLimeEncryption(/enableLime(/g; \ +s/.value()/.toInt()/g; \ +s/clearAuthInfos()/clearAllAuthInfo()/g; \ +s/clearProxyConfigs()/clearProxyConfig()/g; \ +s/isVideoSupported()/videoSupported()/g; \ +s/VideoDefinition().toDisplayableString()/VideoDefinition().getName()/g; \ +s/isAccountUsed()/isAccountExist()/g; \ +s/loadXmlFile(/loadFromXmlFile(/g; \ +s/activatePhoneNumberLink()/activateAlias()/g; \ +s/isPhoneNumberUsed()/isAliasUsed()/g; \ +s/recoverPhoneAccount()/recoverAccount()/g; \ +s/isLimeEncryptionAvailable()/limeAvailable()/g; \ +s/getUseRfc2833ForDtmfs/getUseRfc2833ForDtmf/g; \ +s/setUseRfc2833ForDtmfs/setUseRfc2833ForDtmf/g; \ +s/getUseSipInfoForDtmfs/getUseInfoForDtmf/g; \ +s/setUseSipInfoForDtmfs/setUseInfoForDtmf/g; \ +s/getIncomingTimeout/getIncTimeout/g; \ +s/setIncomingTimeout/setIncTimeout/g; \ +s/migrateCallLogs()/migrateLogsFromRcToDb()/g; \ +s/setRLSUri/setRlsUri/g; \ +s/hasCrappyOpenGL(/hasCrappyOpenGl(/g; \ +s/needsEchoCalibration(/isEchoCancellerCalibrationRequired(/g; \ +s/getCountryCode()/getCountryCallingCode()/g; \ +s/isEchoCancellationEnabled()/echoCancellationEnabled()/g; \ +s/startEchoCalibration(/startEchoCancellerCalibration(/g; \ +s/.isRegistered()/.getState() == RegistrationState.Ok/g; \ +s/isInConference()/(getConference() != null)/g; \ +s/getAudioStats()/getStats(StreamType.Audio)/g; \ +s/getVideoStats()/getStats(StreamType.Video)/g; \ +s/getVcardToString()/getVcard().asVcard4String()/g; \ +s/getVideoAutoInitiatePolicy()/getVideoActivationPolicy().getAutomaticallyInitiate()/g; \ +s/setFamilyName(/getVcard().setFamilyName(/g; \ +s/setGivenName(/getVcard().setGivenName(/g; \ +s/\.setOrganization(/\.getVcard().setOrganization(/g; \ +s/getFamilyName()/getVcard().getFamilyName()/g; \ +s/getGivenName()/getVcard().getGivenName()/g; \ +s/\.getOrganization()/\.getVcard().getOrganization()/g; \ +s/enableAvpf(/setAvpfMode(AVPFMode.Enabled)/g; \ +s/transports.udp = /transports.setUdpPort(/g; \ +s/transports.tcp = /transports.setTcpPort(/g; \ +s/transports.tls = /transports.setTlsPort(/g; \ +s/transports.udp/transports.getUdpPort()/g; \ +s/transports.tcp/transports.getTcpPort()/g; \ +s/transports.tls/transports.getTlsPort()/g; \ +s/getPrimaryContactUsername()/getPrimaryContactParsed().getUsername()/g; \ +s/getPrimaryContactDisplayName()/getPrimaryContactParsed().getDisplayName()/g; \ +s/.sendDtmf(/.getCurrentCall().sendDtmf(/g; \ +s/content.getData() == null/content.getSize() == 0/g; \ +s/lc.downloadOpenH264Enabled()/OpenH264DownloadHelper.isOpenH264DownloadEnabled()/g; \ +s/LinphoneManager.getLc().downloadOpenH264Enabled()/OpenH264DownloadHelper.isOpenH264DownloadEnabled()/g; \ +s/getLc().enableDownloadOpenH264(/OpenH264DownloadHelper.setOpenH264DownloadEnabled(/g; \ +s/enableDownloadOpenH264(/OpenH264DownloadHelper.enableDownloadOpenH264(/g; \ +s/mLc.destroy()/mLc = null/g; \ +s/getAllDialPlan()/getDialPlans()/g; \ +s/getCountryName()/getCountry()/g; \ +s/getMSFactory()/getMediastreamerFactory()/g; \ +s/accountCreator.getPrefix(/org.linphone.core.Utils.getPrefixFromE164(/g; \ +s/proxyConfig.lookupCCCFromIso(/org.linphone.core.Utils.getCccFromIso(/g; \ +s/linkPhoneNumberWithAccount()/linkAccount()/g; \ +s/zoomVideo(/zoom(/g; \ +s/mLc.setCpuCount(/\/\/mLc.setCpuCount(/g; \ +s/new XmlRpcRequestImpl(/xmlRpcSession.createRequest(/g; \ +s/new XmlRpcSessionImpl(LinphoneManager.getLcIfManagerNotDestroyedOrNull(), /LinphoneManager.getLcIfManagerNotDestroyedOrNull().createXmlRpcSession(/g" {} \; # TODO #Tunnel, TunnelConfig From b83f1933c47b5dc55b8228387292e4f51332db26 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 17 Oct 2017 19:00:07 +0200 Subject: [PATCH 0541/2215] Fixed XmlRpcRequest.ArgType enum name in Java wrapper + added missing sed to migration --- wrappers/java/genwrapper.py | 2 ++ wrappers/java/migration.sh | 1 + 2 files changed, 3 insertions(+) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 51465d7da..e75335f98 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -195,6 +195,8 @@ class JavaTranslator(object): return 'jint' if _type.desc.name.to_camel_case() == "XmlRpcStatus": return "XmlRpcRequest.Status" + elif _type.desc.name.to_camel_case() == "XmlRpcArgType": + return "XmlRpcRequest.ArgType" name = _type.desc.name.to_camel_case() if name in ENUMS_LIST: className = ENUMS_LIST[name] diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index f218f752a..19400d4c3 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -195,6 +195,7 @@ s/isVCardSupported()/vcardSupported()/g; \ s/getPresenceModelForUri(/getPresenceModelForUriOrTel(/g; \ s/setAvpfRRInterval(/setAvpfRrInterval(/g; \ s/getAvpfRRInterval(/getAvpfRrInterval(/g; \ +s/hasBuiltInEchoCanceler()/hasBuiltinEchoCanceller()/g; \ s/getProxy()/getServerAddr()/g; \ s/setProxy(/setServerAddr(/g; \ s/setIdentity(/setIdentityAddress(/g; \ From 2a9d4afef2530dac32a07dd60180ef3f929e39b1 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 17 Oct 2017 19:57:19 +0200 Subject: [PATCH 0542/2215] Keep previous callback name in migration as prefix instead of removing it --- wrappers/java/migration.sh | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 19400d4c3..d51dcaa34 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -104,19 +104,19 @@ s/onChatMessageStateChanged/onMsgStateChanged/g; \ s/onChatMessageFileTransferProgressChanged/onFileTransferProgressIndication/g; \ s/onChatMessageFileTransferSent/onFileTransferSend/g; \ s/onChatMessageFileTransferReceived/onFileTransferRecv/g; \ -s/authInfoRequested/removed/g; \ -s/show(Core/removed(/g; \ -s/displayStatus/removed/g; \ -s/displayMessage/removed/g; \ -s/displayWarning/removed/g; \ -s/fileTransferProgressIndication/removed/g; \ -s/fileTransferRecv/removed/g; \ -s/fileTransferSend/removed/g; \ +s/authInfoRequested/authInfoRequested_removed/g; \ +s/show(Core/show_removed(Core/g; \ +s/displayStatus/displayStatus_removed/g; \ +s/displayMessage/displayMessage_removed/g; \ +s/displayWarning/displayWarning_removed/g; \ +s/fileTransferProgressIndication/fileTransferProgressIndication_removed/g; \ +s/fileTransferRecv/fileTransferRecv_removed/g; \ +s/fileTransferSend/fileTransferSend_removed/g; \ s/notifyReceived(Core lc, Event/onNotifyReceived(Core lc, Event/g; \ -s/notifyReceived/removed/g; \ +s/notifyReceived/notifyReceived_removed/g; \ s/ecCalibrationStatus/onEcCalibrationResult/g; \ s/publishStateChanged/onPublishStateChanged/g; \ -s/messageReceivedUnableToDecrypted/removed/g; \ +s/messageReceivedUnableToDecrypted/messageReceivedUnableToDecrypted_removed/g; \ s/callStatsUpdated/onCallStatsUpdated/g; \ s/authenticationRequested/onAuthenticationRequested/g; \ s/newSubscriptionRequest/onNewSubscriptionRequested/g; \ @@ -273,6 +273,11 @@ s/new XmlRpcSessionImpl(LinphoneManager.getLcIfManagerNotDestroyedOrNull(), /Lin # TODO #Tunnel, TunnelConfig #AccountCreator.updatePassword => What to do ? +#Core.removeFriend(friend) +#Factory.instance().enableLogCollection(isDebugEnabled); +#Factory.instance().setDebugMode(isDebugEnabled, context.getString(R.string.app_name)); +#setVideoDevice() +#Factory.instance().createBuffer(); # Manual changes required # Some callbacks no longer exist, their name will be "removed", remove them @@ -322,6 +327,7 @@ s/new XmlRpcSessionImpl(LinphoneManager.getLcIfManagerNotDestroyedOrNull(), /Lin # # Other #CallParams.getJitterBufferSize() => CallStatsImpl.getJitterBufferSizeMs() +#Core.findAuthInfo was (username, realm, domain) now is (realm, username, domain) # # Payloads #Core.enablePayloadType() => PayloadType.enable() From 88fbd50b769bc2960ee03f1868d952237a9b4dc1 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 18 Oct 2017 09:35:43 +0200 Subject: [PATCH 0543/2215] feat(MainDB): supports chat messages store --- src/chat/chat-message/chat-message.cpp | 8 ++++ src/chat/chat-message/chat-message.h | 2 + src/chat/chat-room/basic-chat-room.h | 2 +- src/chat/chat-room/chat-room.h | 4 +- src/chat/chat-room/client-group-chat-room.h | 2 +- src/chat/chat-room/real-time-text-chat-room.h | 2 +- src/db/main-db.cpp | 38 ++++++++++++++++++- 7 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index ed813723d..e80b6a0d6 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -1327,6 +1327,14 @@ void ChatMessage::setToAddress(Address to) { d->to = to; } +const Address &ChatMessage::getLocalAddress () const { + return getDirection() == Direction::Incoming ? getToAddress() : getFromAddress(); +} + +const Address &ChatMessage::getRemoteAddress () const { + return getDirection() != Direction::Incoming ? getToAddress() : getFromAddress(); +} + const string& ChatMessage::getFileTransferFilepath() const { L_D(); return d->fileTransferFilePath; diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index d4be49592..c45253e7f 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -85,6 +85,8 @@ public: const Address &getFromAddress () const; const Address &getToAddress () const; + const Address &getLocalAddress () const; + const Address &getRemoteAddress () const; const LinphoneErrorInfo *getErrorInfo () const; diff --git a/src/chat/chat-room/basic-chat-room.h b/src/chat/chat-room/basic-chat-room.h index 9e8bf1f72..b1bf7523b 100644 --- a/src/chat/chat-room/basic-chat-room.h +++ b/src/chat/chat-room/basic-chat-room.h @@ -33,7 +33,7 @@ public: BasicChatRoom (LinphoneCore *core, const Address &peerAddress); virtual ~BasicChatRoom () = default; - int getCapabilities () const override; + CapabilitiesMask getCapabilities () const override; /* ConferenceInterface. */ void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index d09203199..562387c65 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -39,10 +39,12 @@ public: L_DECLARE_ENUM(Capabilities, L_ENUM_VALUES_CHAT_ROOM_CAPABILITIES); L_DECLARE_ENUM(State, L_ENUM_VALUES_CHAT_ROOM_STATE); + typedef int CapabilitiesMask; + ChatRoom (LinphoneCore *core); virtual ~ChatRoom () = default; - virtual int getCapabilities () const = 0; + virtual CapabilitiesMask getCapabilities () const = 0; void compose (); std::shared_ptr createFileTransferMessage (const LinphoneContent *initialContent); diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 52f176d00..dc44e18fe 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -34,7 +34,7 @@ public: ClientGroupChatRoom (LinphoneCore *core, const Address &me, const std::string &uri, const std::string &subject); virtual ~ClientGroupChatRoom () = default; - int getCapabilities () const override; + CapabilitiesMask getCapabilities () const override; /* ConferenceInterface */ void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; diff --git a/src/chat/chat-room/real-time-text-chat-room.h b/src/chat/chat-room/real-time-text-chat-room.h index 01a84035d..430fcfafe 100644 --- a/src/chat/chat-room/real-time-text-chat-room.h +++ b/src/chat/chat-room/real-time-text-chat-room.h @@ -33,7 +33,7 @@ public: RealTimeTextChatRoom (LinphoneCore *core, const Address &peerAddress); virtual ~RealTimeTextChatRoom () = default; - int getCapabilities () const override; + CapabilitiesMask getCapabilities () const override; uint32_t getChar () const; LinphoneCall *getCall () const; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 5678d63aa..d5badd7ea 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -247,8 +247,37 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} } long MainDbPrivate::insertMessageEvent (const EventLog &eventLog) { - // TODO. - return 0; + shared_ptr chatMessage = static_cast(eventLog).getChatMessage(); + shared_ptr chatRoom = chatMessage->getChatRoom(); + if (!chatRoom) { + lError() << "Unable to get a valid chat room. It was removed from database."; + return -1; + } + + tm eventTime = Utils::getLongAsTm(static_cast(eventLog.getTime())); + + struct MessageEventReferences references; + references.eventId = insertEvent(EventLog::Type::ChatMessage, eventTime); + references.localSipAddressId = insertSipAddress(chatMessage->getLocalAddress().asString()); + references.remoteSipAddressId = insertSipAddress(chatMessage->getRemoteAddress().asString()); + references.chatRoomId = insertChatRoom( + references.remoteSipAddressId, + chatRoom->getCapabilities(), + eventTime + ); + + insertChatRoomParticipant(references.chatRoomId, references.remoteSipAddressId, false); + + long eventId = insertMessageEvent ( + references, + static_cast(chatMessage->getState()), + static_cast(chatMessage->getDirection()), + chatMessage->getImdnMessageId(), + chatMessage->isSecured(), + chatMessage->getContents() + ); + + return eventId; } long MainDbPrivate::insertConferenceEvent (const EventLog &eventLog) { @@ -260,6 +289,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_event (event_id, chat_room_id)" " VALUES (:eventId, :chatRoomId)", soci::use(eventId), soci::use(chatRoomId); + return eventId; } @@ -271,6 +301,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} " VALUES (:eventId, :notifyId)", soci::use(eventId), soci::use( static_cast(eventLog).getNotifyId() ); + return eventId; } @@ -283,6 +314,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_participant_event (event_id, participant_address_id)" " VALUES (:eventId, :participantAddressId)", soci::use(eventId), soci::use(participantAddressId); + return eventId; } @@ -295,6 +327,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_participant_device_event (event_id, gruu_address_id)" " VALUES (:eventId, :gruuAddressId)", soci::use(eventId), soci::use(gruuAddressId); + return eventId; } @@ -306,6 +339,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} " VALUES (:eventId, :subject)", soci::use(eventId), soci::use( static_cast(eventLog).getSubject() ); + return eventId; } From 24b2861eb9639050f2838993dc21a26aca160141 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 18 Oct 2017 09:37:15 +0200 Subject: [PATCH 0544/2215] feat(MainDb): hide MessageEventReferences struct --- src/db/main-db-p.h | 8 +------- src/db/main-db.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 02ebe9cb3..fef0bd127 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -29,13 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class Content; - -struct MessageEventReferences { - long eventId; - long localSipAddressId; - long remoteSipAddressId; - long chatRoomId; -}; +struct MessageEventReferences; class MainDbPrivate : public AbstractDbPrivate { public: diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index d5badd7ea..8df3f068b 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -42,6 +42,13 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +struct MessageEventReferences { + long eventId; + long localSipAddressId; + long remoteSipAddressId; + long chatRoomId; +}; + // ----------------------------------------------------------------------------- MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} From 84d94988a1375a93fa3dbabec40715689c043b27 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 18 Oct 2017 10:12:17 +0200 Subject: [PATCH 0545/2215] uniformize conference event --- include/linphone/api/c-callbacks.h | 23 ++++++++++--- include/linphone/api/c-chat-room-cbs.h | 27 ++++++++++++++++ include/linphone/api/c-types.h | 2 ++ src/c-wrapper/api/c-chat-room-cbs.cpp | 18 +++++++++++ src/c-wrapper/api/c-event-log.cpp | 2 ++ src/c-wrapper/c-wrapper.h | 2 ++ src/chat/chat-room/client-group-chat-room.cpp | 32 +++++++++++++------ 7 files changed, 91 insertions(+), 15 deletions(-) diff --git a/include/linphone/api/c-callbacks.h b/include/linphone/api/c-callbacks.h index 60ba99bc7..c99e1b8aa 100644 --- a/include/linphone/api/c-callbacks.h +++ b/include/linphone/api/c-callbacks.h @@ -96,7 +96,7 @@ typedef void (*LinphoneCallCbsAckProcessingCb)(LinphoneCall *call, LinphoneHeade * @addtogroup chatroom * @{ */ - + /** * Call back used to notify message delivery status * @param msg #LinphoneChatMessage object @@ -161,14 +161,14 @@ typedef void (*LinphoneChatRoomCbsMessageReceivedCb) (LinphoneChatRoom *cr, Linp * @param[in] cr #LinphoneChatRoom object * @param[in] participant The #LinphoneParticipant that has been added to the chat room */ -typedef void (*LinphoneChatRoomCbsParticipantAddedCb) (LinphoneChatRoom *cr, LinphoneParticipant *participant); +typedef void (*LinphoneChatRoomCbsParticipantAddedCb) (LinphoneChatRoom *cr, const LinphoneConferenceParticipantEvent *event); /** * Callback used to notify a chat room that a participant has been removed. * @param[in] cr #LinphoneChatRoom object * @param[in] participant The #LinphoneParticipant that has been removed from the chat room */ -typedef void (*LinphoneChatRoomCbsParticipantRemovedCb) (LinphoneChatRoom *cr, LinphoneParticipant *participant); +typedef void (*LinphoneChatRoomCbsParticipantRemovedCb) (LinphoneChatRoom *cr, const LinphoneConferenceParticipantEvent *event); /** * Callback used to notify a chat room that the admin status of a participant has been changed. @@ -176,7 +176,7 @@ typedef void (*LinphoneChatRoomCbsParticipantRemovedCb) (LinphoneChatRoom *cr, L * @param[in] participant The #LinphoneParticipant for which the admin status has been changed * @param[in] isAdmin The new admin status of the participant */ -typedef void (*LinphoneChatRoomCbsParticipantAdminStatusChangedCb) (LinphoneChatRoom *cr, LinphoneParticipant *participant, bool_t isAdmin); +typedef void (*LinphoneChatRoomCbsParticipantAdminStatusChangedCb) (LinphoneChatRoom *cr, const LinphoneConferenceParticipantEvent *event); /** * Callback used to notify a chat room state has changed. @@ -190,7 +190,7 @@ typedef void (*LinphoneChatRoomCbsStateChangedCb) (LinphoneChatRoom *cr, Linphon * @param[in] cr #LinphoneChatRoom object * @param[in] subject The new subject of the chat room */ -typedef void (*LinphoneChatRoomCbsSubjectChangedCb) (LinphoneChatRoom *cr, const char *subject); +typedef void (*LinphoneChatRoomCbsSubjectChangedCb) (LinphoneChatRoom *cr, const LinphoneConferenceSubjectEvent *event); /** * Callback used to notify a chat room that a message has been received but we were unable to decrypt it @@ -199,6 +199,19 @@ typedef void (*LinphoneChatRoomCbsSubjectChangedCb) (LinphoneChatRoom *cr, const */ typedef void (*LinphoneChatRoomCbsUndecryptableMessageReceivedCb) (LinphoneChatRoom *cr, LinphoneChatMessage *msg); +/** + * Callback used to notify a chat room that a participant has been added. + * @param[in] cr #LinphoneChatRoom object + * @param[in] participant The #LinphoneParticipant that has been added to the chat room + */ +typedef void (*LinphoneChatRoomCbsParticipantDeviceAddedCb) (LinphoneChatRoom *cr, const LinphoneConferenceParticipantDeviceEvent *event); + +/** + * Callback used to notify a chat room that a participant has been removed. + * @param[in] cr #LinphoneChatRoom object + * @param[in] participant The #LinphoneParticipant that has been removed from the chat room + */ +typedef void (*LinphoneChatRoomCbsParticipantDeviceRemovedCb) (LinphoneChatRoom *cr, const LinphoneConferenceParticipantDeviceEvent *event); /** * @} **/ diff --git a/include/linphone/api/c-chat-room-cbs.h b/include/linphone/api/c-chat-room-cbs.h index e3eeede9c..08331232e 100644 --- a/include/linphone/api/c-chat-room-cbs.h +++ b/include/linphone/api/c-chat-room-cbs.h @@ -173,6 +173,33 @@ LINPHONE_PUBLIC LinphoneChatRoomCbsUndecryptableMessageReceivedCb linphone_chat_ */ LINPHONE_PUBLIC void linphone_chat_room_cbs_set_undecryptable_message_received (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsUndecryptableMessageReceivedCb cb); +/** + * Get the participant device added callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @return The current participant device added callback. + */ +LINPHONE_PUBLIC LinphoneChatRoomCbsParticipantDeviceAddedCb linphone_chat_room_cbs_get_participant_device_added (const LinphoneChatRoomCbs *cbs); + +/** + * Set the participant device added callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @param[in] cb The participant device added callback to be used. + */ +LINPHONE_PUBLIC void linphone_chat_room_cbs_set_participant_device_added (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantDeviceAddedCb cb); + +/** + * Get the participant device removed callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @return The current participant device removed callback. + */ +LINPHONE_PUBLIC LinphoneChatRoomCbsParticipantDeviceRemovedCb linphone_chat_room_cbs_get_participant_device_removed (const LinphoneChatRoomCbs *cbs); + +/** + * Set the participant device removed callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @param[in] cb The participant device removed callback to be used. + */ +LINPHONE_PUBLIC void linphone_chat_room_cbs_set_participant_device_removed (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantDeviceRemovedCb cb); /** * @} */ diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index 980e40eec..cce57f2a4 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -130,6 +130,8 @@ typedef struct _LinphoneDialPlan LinphoneDialPlan; typedef struct _LinphoneCallEvent LinphoneCallEvent; typedef struct _LinphoneConferenceEvent LinphoneConferenceEvent; typedef struct _LinphoneConferenceParticipantEvent LinphoneConferenceParticipantEvent; +typedef struct _LinphoneConferenceParticipantDeviceEvent LinphoneConferenceParticipantDeviceEvent; +typedef struct _LinphoneConferenceSubjectEvent LinphoneConferenceSubjectEvent; typedef struct _LinphoneEventLog LinphoneEventLog; typedef struct _LinphoneChatMessageEvent LinphoneChatMessageEvent; diff --git a/src/c-wrapper/api/c-chat-room-cbs.cpp b/src/c-wrapper/api/c-chat-room-cbs.cpp index 3dd1d4340..d25707a78 100644 --- a/src/c-wrapper/api/c-chat-room-cbs.cpp +++ b/src/c-wrapper/api/c-chat-room-cbs.cpp @@ -30,6 +30,8 @@ struct _LinphoneChatRoomCbs { LinphoneChatRoomCbsMessageReceivedCb messageReceivedCb; LinphoneChatRoomCbsParticipantAddedCb participantAddedCb; LinphoneChatRoomCbsParticipantRemovedCb participantRemovedCb; + LinphoneChatRoomCbsParticipantDeviceAddedCb participantDeviceAddedCb; + LinphoneChatRoomCbsParticipantDeviceRemovedCb participantDeviceRemovedCb; LinphoneChatRoomCbsParticipantAdminStatusChangedCb participantAdminStatusChangedCb; LinphoneChatRoomCbsStateChangedCb stateChangedCb; LinphoneChatRoomCbsSubjectChangedCb subjectChangedCb; @@ -133,3 +135,19 @@ LinphoneChatRoomCbsUndecryptableMessageReceivedCb linphone_chat_room_cbs_get_und void linphone_chat_room_cbs_set_undecryptable_message_received (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsUndecryptableMessageReceivedCb cb) { cbs->undecryptableMessageReceivedCb = cb; } + +LinphoneChatRoomCbsParticipantDeviceAddedCb linphone_chat_room_cbs_get_participant_device_added (const LinphoneChatRoomCbs *cbs) { + return cbs->participantDeviceAddedCb; +} + +void linphone_chat_room_cbs_set_participant_device_added (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantDeviceAddedCb cb) { + cbs->participantDeviceAddedCb = cb; +} + +LinphoneChatRoomCbsParticipantDeviceRemovedCb linphone_chat_room_cbs_get_participant_device_removed (const LinphoneChatRoomCbs *cbs) { + return cbs->participantDeviceRemovedCb; +} + +void linphone_chat_room_cbs_set_participant_device_removed (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantDeviceRemovedCb cb) { + cbs->participantDeviceRemovedCb = cb; +} diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 5a32050c2..a80f76384 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -31,6 +31,8 @@ L_DECLARE_C_CLONABLE_STRUCT_IMPL(EventLog); L_DECLARE_C_CLONABLE_STRUCT_IMPL(CallEvent); L_DECLARE_C_CLONABLE_STRUCT_IMPL(ConferenceEvent); L_DECLARE_C_CLONABLE_STRUCT_IMPL(ConferenceParticipantEvent); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(ConferenceParticipantDeviceEvent); +L_DECLARE_C_CLONABLE_STRUCT_IMPL(ConferenceSubjectEvent); L_DECLARE_C_CLONABLE_STRUCT_IMPL(ChatMessageEvent); using namespace std; diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index 6b932c0c5..c9c9bbf53 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -37,6 +37,8 @@ F(ChatRoom, ChatRoom) \ F(ConferenceEvent, ConferenceEvent) \ F(ConferenceParticipantEvent, ConferenceParticipantEvent) \ + F(ConferenceParticipantDeviceEvent, ConferenceParticipantDeviceEvent) \ + F(ConferenceSubjectEvent, ConferenceSubjectEvent) \ F(DialPlan, DialPlan) \ F(EventLog, EventLog) \ F(MediaSessionParams, CallParams) \ diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index b7151aa59..0a6b8cdec 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -275,7 +275,7 @@ void ClientGroupChatRoom::onParticipantAdded (time_t tm, const Address &addr) { LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAddedCb cb = linphone_chat_room_cbs_get_participant_added(cbs); - ConferenceParticipantEvent event( + const ConferenceParticipantEvent event( EventLog::Type::ConferenceParticipantAdded, tm, dConference->conferenceAddress, @@ -284,7 +284,7 @@ void ClientGroupChatRoom::onParticipantAdded (time_t tm, const Address &addr) { ); if (cb) - cb(cr, L_GET_C_BACK_PTR(participant)); + cb(cr, L_GET_C_BACK_PTR(&event)); } void ClientGroupChatRoom::onParticipantRemoved (time_t tm, const Address &addr) { @@ -299,7 +299,7 @@ void ClientGroupChatRoom::onParticipantRemoved (time_t tm, const Address &addr) LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantRemovedCb cb = linphone_chat_room_cbs_get_participant_removed(cbs); - ConferenceParticipantEvent event( + const ConferenceParticipantEvent event( EventLog::Type::ConferenceParticipantRemoved, tm, dConference->conferenceAddress, @@ -308,7 +308,7 @@ void ClientGroupChatRoom::onParticipantRemoved (time_t tm, const Address &addr) ); if (cb) - cb(cr, L_GET_C_BACK_PTR(participant)); + cb(cr, L_GET_C_BACK_PTR(&event)); dConference->participants.remove(participant); } @@ -329,7 +329,7 @@ void ClientGroupChatRoom::onParticipantSetAdmin (time_t tm, const Address &addr, LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAdminStatusChangedCb cb = linphone_chat_room_cbs_get_participant_admin_status_changed(cbs); - ConferenceParticipantEvent event( + const ConferenceParticipantEvent event( isAdmin ? EventLog::Type::ConferenceParticipantSetAdmin : EventLog::Type::ConferenceParticipantUnsetAdmin, tm, dConference->conferenceAddress, @@ -338,7 +338,7 @@ void ClientGroupChatRoom::onParticipantSetAdmin (time_t tm, const Address &addr, ); if (cb) - cb(cr, L_GET_C_BACK_PTR(participant), isAdmin); + cb(cr, L_GET_C_BACK_PTR(&event)); } void ClientGroupChatRoom::onSubjectChanged (time_t tm, const std::string &subject) { @@ -347,7 +347,7 @@ void ClientGroupChatRoom::onSubjectChanged (time_t tm, const std::string &subjec LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsSubjectChangedCb cb = linphone_chat_room_cbs_get_subject_changed(cbs); - ConferenceSubjectEvent event( + const ConferenceSubjectEvent event( tm, dConference->conferenceAddress, dConference->eventHandler->getLastNotify(), @@ -355,7 +355,7 @@ void ClientGroupChatRoom::onSubjectChanged (time_t tm, const std::string &subjec ); if (cb) - cb(cr, subject.c_str()); + cb(cr, L_GET_C_BACK_PTR(&event)); } void ClientGroupChatRoom::onParticipantDeviceAdded (time_t tm, const Address &addr, const Address &gruu) { @@ -370,7 +370,10 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (time_t tm, const Address &ad return; } participant->getPrivate()->addDevice(gruu); - ConferenceParticipantDeviceEvent event( + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); + LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); + LinphoneChatRoomCbsParticipantDeviceAddedCb cb = linphone_chat_room_cbs_get_participant_device_added(cbs); + const ConferenceParticipantDeviceEvent event( EventLog::Type::ConferenceParticipantDeviceAdded, tm, dConference->conferenceAddress, @@ -378,6 +381,9 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (time_t tm, const Address &ad addr, gruu ); + + if (cb) + cb(cr, L_GET_C_BACK_PTR(&event)); } void ClientGroupChatRoom::onParticipantDeviceRemoved (time_t tm, const Address &addr, const Address &gruu) { @@ -392,7 +398,10 @@ void ClientGroupChatRoom::onParticipantDeviceRemoved (time_t tm, const Address & return; } participant->getPrivate()->removeDevice(gruu); - ConferenceParticipantDeviceEvent event( + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); + LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); + LinphoneChatRoomCbsParticipantDeviceRemovedCb cb = linphone_chat_room_cbs_get_participant_device_removed(cbs); + const ConferenceParticipantDeviceEvent event( EventLog::Type::ConferenceParticipantDeviceRemoved, tm, dConference->conferenceAddress, @@ -400,6 +409,9 @@ void ClientGroupChatRoom::onParticipantDeviceRemoved (time_t tm, const Address & addr, gruu ); + + if (cb) + cb(cr, L_GET_C_BACK_PTR(&event)); } // ----------------------------------------------------------------------------- From 927f2c50388717cb6fb93d52e57d58ef9fe23621 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 18 Oct 2017 10:15:17 +0200 Subject: [PATCH 0546/2215] Added constructors for objects in factory --- coreapi/factory.c | 28 ++++++++++ include/linphone/factory.h | 55 +++++++++++++++++++ .../classes/tools/OpenH264DownloadHelper.java | 4 +- wrappers/java/migration.sh | 5 +- 4 files changed, 87 insertions(+), 5 deletions(-) diff --git a/coreapi/factory.c b/coreapi/factory.c index 089dfca9e..33537d920 100644 --- a/coreapi/factory.c +++ b/coreapi/factory.c @@ -323,6 +323,34 @@ LinphoneVideoActivationPolicy *linphone_factory_create_video_activation_policy(L return linphone_video_activation_policy_new(); } +LinphoneContent *linphone_factory_create_content(LinphoneFactory *factory) { + return linphone_content_new(); +} + +LinphoneBuffer *linphone_factory_create_buffer(LinphoneFactory *factory) { + return linphone_buffer_new(); +} + +LinphoneBuffer *linphone_factory_create_buffer_from_data(LinphoneFactory *factory, const uint8_t *data, size_t size) { + return linphone_buffer_new_from_data(data, size); +} + +LinphoneBuffer *linphone_factory_create_buffer_from_string(LinphoneFactory *factory, const char *data) { + return linphone_buffer_new_from_string(data); +} + +LinphoneConfig *linphone_factory_create_config(LinphoneFactory *factory, const char *path) { + return linphone_config_new(path); +} + +LinphoneConfig *linphone_factory_create_config_with_factory(LinphoneFactory *factory, const char *path, const char *factory_path) { + return linphone_config_new_with_factory(path, factory_path); +} + +LinphoneConfig *linphone_factory_create_config_from_string(LinphoneFactory *factory, const char *data) { + return linphone_config_new_from_buffer(data); +} + const bctbx_list_t * linphone_factory_get_dial_plans(const LinphoneFactory *factory) { return linphone_dial_plan_get_all_list(); } diff --git a/include/linphone/factory.h b/include/linphone/factory.h index 351567478..1bdc50f4b 100644 --- a/include/linphone/factory.h +++ b/include/linphone/factory.h @@ -269,6 +269,61 @@ LINPHONE_PUBLIC LinphoneVideoActivationPolicy *linphone_factory_create_video_act */ LINPHONE_PUBLIC const bctbx_list_t * linphone_factory_get_dial_plans(const LinphoneFactory *factory); +/** + * Creates an object LinphoneContent + * @param[in] factory the LinphoneFactory + * @return a LinphoneContent + */ +LINPHONE_PUBLIC LinphoneContent *linphone_factory_create_content(LinphoneFactory *factory); + +/** + * Creates an object LinphoneBuffer + * @param[in] factory the LinphoneFactory + * @return a LinphoneBuffer + */ +LINPHONE_PUBLIC LinphoneBuffer *linphone_factory_create_buffer(LinphoneFactory *factory); + +/** + * Creates an object LinphoneBuffer + * @param[in] factory the LinphoneFactory + * @param[in] data the data to set in the buffer + * @param[in] size the size of the data + * @return a LinphoneBuffer + */ +LINPHONE_PUBLIC LinphoneBuffer *linphone_factory_create_buffer_from_data(LinphoneFactory *factory, const uint8_t *data, size_t size); + +/** + * Creates an object LinphoneBuffer + * @param[in] factory the LinphoneFactory + * @param[in] data the data to set in the buffer + * @return a LinphoneBuffer + */ +LINPHONE_PUBLIC LinphoneBuffer *linphone_factory_create_buffer_from_string(LinphoneFactory *factory, const char *data); + +/** + * Creates an object LinphoneConfig + * @param[in] factory the LinphoneFactory + * @param[in] the path of the config + * @return a LinphoneConfig + */ +LINPHONE_PUBLIC LinphoneConfig *linphone_factory_create_config(LinphoneFactory *factory, const char *path); + +/** + * Creates an object LinphoneConfig + * @param[in] factory the LinphoneFactory + * @param[in] the path of the config + * @param[in] the path of the factory + * @return a LinphoneConfig + */ +LINPHONE_PUBLIC LinphoneConfig *linphone_factory_create_config_with_factory(LinphoneFactory *factory, const char *path, const char *factory_path); + +/** + * Creates an object LinphoneConfig + * @param[in] factory the LinphoneFactory + * @return a LinphoneConfig + */ +LINPHONE_PUBLIC LinphoneConfig *linphone_factory_create_config_from_string(LinphoneFactory *factory, const char *data); + /** * Gets the user data in the LinphoneFactory object * @param[in] factory the LinphoneFactory diff --git a/wrappers/java/classes/tools/OpenH264DownloadHelper.java b/wrappers/java/classes/tools/OpenH264DownloadHelper.java index 170bda78d..eb35285a4 100644 --- a/wrappers/java/classes/tools/OpenH264DownloadHelper.java +++ b/wrappers/java/classes/tools/OpenH264DownloadHelper.java @@ -70,8 +70,8 @@ public class OpenH264DownloadHelper { isDownloadEnabled = false; } if (isCodecFound()) { - Log.i("OpenH264DownloadHelper"," Loading OpenH264 downloaded plugin:" + downloadHelper.getFullPathLib()); - System.load(downloadHelper.getFullPathLib()); + Log.i("OpenH264DownloadHelper"," Loading OpenH264 downloaded plugin:" + getFullPathLib()); + System.load(getFullPathLib()); } else { Log.i("OpenH264DownloadHelper"," Cannot load OpenH264 downloaded plugin"); } diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index d51dcaa34..1af0683ed 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -211,6 +211,8 @@ s/.value()/.toInt()/g; \ s/clearAuthInfos()/clearAllAuthInfo()/g; \ s/clearProxyConfigs()/clearProxyConfig()/g; \ s/isVideoSupported()/videoSupported()/g; \ +s/getReceivedVideoDefinition().width/getReceivedVideoDefinition().getWidth()/g; \ +s/getReceivedVideoDefinition().height/getReceivedVideoDefinition().getHeight()/g; \ s/VideoDefinition().toDisplayableString()/VideoDefinition().getName()/g; \ s/isAccountUsed()/isAccountExist()/g; \ s/loadXmlFile(/loadFromXmlFile(/g; \ @@ -273,11 +275,8 @@ s/new XmlRpcSessionImpl(LinphoneManager.getLcIfManagerNotDestroyedOrNull(), /Lin # TODO #Tunnel, TunnelConfig #AccountCreator.updatePassword => What to do ? -#Core.removeFriend(friend) #Factory.instance().enableLogCollection(isDebugEnabled); #Factory.instance().setDebugMode(isDebugEnabled, context.getString(R.string.app_name)); -#setVideoDevice() -#Factory.instance().createBuffer(); # Manual changes required # Some callbacks no longer exist, their name will be "removed", remove them From cf0502d382352dcbe8d87f14ce11d6c381db9f6c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 18 Oct 2017 10:19:59 +0200 Subject: [PATCH 0547/2215] Do not wrap the static methods in Java wrapper --- wrappers/java/java_class.mustache | 22 ---------------------- wrappers/java/migration.sh | 4 ---- 2 files changed, 26 deletions(-) diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index afe0d173c..0db3c1a6e 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -122,20 +122,6 @@ public {{#isLinphoneFactory}}abstract class{{/isLinphoneFactory}}{{#isNotLinphon * Gets the object stored in this object user's data */ {{#isLinphoneFactory}}abstract {{/isLinphoneFactory}}public Object getUserData(); - -{{#isNotLinphoneFactory}} -{{#staticMethods}} - {{#doc}} - /** - {{#lines}} - * {{line}} - {{/lines}} - */ - {{/doc}} - public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}}; - -{{/staticMethods}} -{{/isNotLinphoneFactory}} } class {{classImplName}} {{#isLinphoneFactory}}extends{{/isLinphoneFactory}}{{#isNotLinphoneFactory}}implements{{/isNotLinphoneFactory}} {{className}} { @@ -214,12 +200,4 @@ class {{classImplName}} {{#isLinphoneFactory}}extends{{/isLinphoneFactory}}{{#is public Object getUserData() { return userData; } - -{{#isNotLinphoneFactory}} -{{#staticMethods}} - @Override - public native {{return_native}} {{name}}({{static_native_params}}); - -{{/staticMethods}} -{{/isNotLinphoneFactory}} } \ No newline at end of file diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 1af0683ed..9d84a6273 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -305,16 +305,12 @@ s/new XmlRpcSessionImpl(LinphoneManager.getLcIfManagerNotDestroyedOrNull(), /Lin # Core.startEchoCancellerCalibration no longer takes a parameter # XmlRpcSession.createRequest takes first the return arg type and then the name of the method, until now it was the other way around - # # Factory -#Factory.createLpConfigFromString => Config.newFromBuffer -#Factory.createLpConfig => Config.newWithFactory or Core.createConfig #Factory.createAccountCreator() => Core.createAccountCreator() #Factory.createPresenceModel() => Core.createPresenceModel() #Factory.instance().setLogCollectionPath(getFilesDir().getAbsolutePath()); => Core.setLogCollectionPath #Factory.instance().enableLogCollection(isDebugEnabled); => Core.enableLogCollection #Factory.instance().setDebugMode(isDebugEnabled, getString(R.string.app_name)); => Core.setLogLevelMask -#Factory.createContent( => Core.createContent( # # Core #Core.getVideoDevice and Core.setVideoDevice now takes/returns String instead of int From abe39796fd8b4710d39102a00f132aa02ada0ee2 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 18 Oct 2017 10:25:27 +0200 Subject: [PATCH 0548/2215] Do wrap static methods but as non static --- wrappers/java/genwrapper.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index e75335f98..a0ddfabde 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -377,7 +377,7 @@ class JavaTranslator(object): methodDict['objectClassName'] = _method.returnType.containedTypeDesc.desc.name.to_camel_case() methodDict['objectClassImplName'] = _method.returnType.containedTypeDesc.desc.name.to_camel_case() + 'Impl' - methodDict['params'] = 'JNIEnv *env, jobject thiz' if static else 'JNIEnv *env, jobject thiz, jlong ptr' + methodDict['params'] = 'JNIEnv *env, jobject thiz, jlong ptr' methodDict['params_impl'] = '' methodDict['strings'] = [] methodDict['objects'] = [] @@ -430,7 +430,6 @@ class JavaTranslator(object): def translate_class(self, _class): classDict = { 'methods': [], - 'staticMethods': [], 'jniMethods': [], } @@ -458,7 +457,7 @@ class JavaTranslator(object): try: methodDict = self.translate_method(method) jniMethodDict = self.translate_jni_method(_class.name, method, True) - classDict['staticMethods'].append(methodDict) + classDict['methods'].append(methodDict) classDict['jniMethods'].append(jniMethodDict) except AbsApi.Error as e: print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0])) @@ -673,7 +672,6 @@ class JavaClass(object): self.filename = self.className + ".java" self.imports = [] self.methods = self._class['methods'] - self.staticMethods = self._class['staticMethods'] self.jniMethods = self._class['jniMethods'] self.doc = self._class['doc'] self.enums = [] From 9be191f71246c7f3b19233abe64971a3d0751434 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 18 Oct 2017 10:27:23 +0200 Subject: [PATCH 0549/2215] feat(MainDb): store last notify id --- src/db/main-db-p.h | 2 +- src/db/main-db.cpp | 27 ++++++++++++++------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index fef0bd127..84fdf413c 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -64,7 +64,7 @@ private: long insertEvent (const EventLog &eventLog); long insertCallEvent (const EventLog &eventLog); long insertMessageEvent (const EventLog &eventLog); - long insertConferenceEvent (const EventLog &eventLog); + long insertConferenceEvent (const EventLog &eventLog, long *chatRoomId = nullptr); long insertConferenceNotifiedEvent (const EventLog &eventLog); long insertConferenceParticipantEvent (const EventLog &eventLog); long insertConferenceParticipantDeviceEvent (const EventLog &eventLog); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 8df3f068b..5376a8f87 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -273,9 +273,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} eventTime ); - insertChatRoomParticipant(references.chatRoomId, references.remoteSipAddressId, false); - - long eventId = insertMessageEvent ( + return insertMessageEvent ( references, static_cast(chatMessage->getState()), static_cast(chatMessage->getDirection()), @@ -283,31 +281,34 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} chatMessage->isSecured(), chatMessage->getContents() ); - - return eventId; } - long MainDbPrivate::insertConferenceEvent (const EventLog &eventLog) { + long MainDbPrivate::insertConferenceEvent (const EventLog &eventLog, long *chatRoomId) { long eventId = insertEvent(eventLog); - long chatRoomId = insertSipAddress( + long curChatRoomId = insertSipAddress( static_cast(eventLog).getConferenceAddress().asString() ); soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_event (event_id, chat_room_id)" - " VALUES (:eventId, :chatRoomId)", soci::use(eventId), soci::use(chatRoomId); + " VALUES (:eventId, :chatRoomId)", soci::use(eventId), soci::use(curChatRoomId); + + if (chatRoomId) + *chatRoomId = curChatRoomId; return eventId; } long MainDbPrivate::insertConferenceNotifiedEvent (const EventLog &eventLog) { - long eventId = insertConferenceEvent(eventLog); + long chatRoomId; + long eventId = insertConferenceEvent(eventLog, &chatRoomId); + unsigned int lastNotifyId = static_cast(eventLog).getNotifyId(); soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_notified_event (event_id, notify_id)" - " VALUES (:eventId, :notifyId)", soci::use(eventId), soci::use( - static_cast(eventLog).getNotifyId() - ); + " VALUES (:eventId, :notifyId)", soci::use(eventId), soci::use(lastNotifyId); + *session << "UPDATE chat_room SET last_notify_id = :lastNotifyId WHERE peer_sip_address_id = :chatRoomId", + soci::use(lastNotifyId), soci::use(chatRoomId); return eventId; } @@ -420,7 +421,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} // Chatroom subject. " subject VARCHAR(255)," - " last_notify INT UNSIGNED," + " last_notify_id INT UNSIGNED," " FOREIGN KEY (peer_sip_address_id)" " REFERENCES sip_address(id)" From bebcee53d6bc9adb42649ca594543012939b4413 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 18 Oct 2017 10:32:03 +0200 Subject: [PATCH 0550/2215] Fixed java's listeners' stubs that return a value --- wrappers/java/genwrapper.py | 1 + wrappers/java/java_interface_stub.mustache | 3 +++ 2 files changed, 4 insertions(+) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index a0ddfabde..13e0c4ae5 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -310,6 +310,7 @@ class JavaTranslator(object): methodDict['return'] = self.translate_type(_method.returnType, isReturn=True) methodDict['return_native'] = self.translate_type(_method.returnType, native=True, isReturn=True) methodDict['return_keyword'] = '' if methodDict['return'] == 'void' else 'return ' + methodDict['hasReturn'] = not methodDict['return'] == 'void' methodDict['convertInputClassArrayToLongArray'] = False diff --git a/wrappers/java/java_interface_stub.mustache b/wrappers/java/java_interface_stub.mustache index 8cb3384b4..513c74558 100644 --- a/wrappers/java/java_interface_stub.mustache +++ b/wrappers/java/java_interface_stub.mustache @@ -28,6 +28,9 @@ public class {{classNameStub}} implements {{className}} { @Override public {{return}} {{name}}({{params}}){{#exception}} throws CoreException{{/exception}} { // Auto-generated method stub + {{#hasReturn}} + {{#classCast}}return null;{{/classCast}} + {{/hasReturn}} } {{/methods}} From 58c94c8672021502dfea6056c89c0072d6b9de46 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 18 Oct 2017 10:45:04 +0200 Subject: [PATCH 0551/2215] feat(Core): database access in progress --- src/CMakeLists.txt | 1 + src/core/core.cpp | 33 +++++++++++++++++++++++++++------ src/core/core.h | 13 +++++++++---- src/db/main-db.cpp | 8 ++++++++ src/db/main-db.h | 1 + 5 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c6f00397b..2e6c4a00b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -79,6 +79,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES conference/session/port-config.h content/content-type.h content/content.h + core/core-p.h core/core.h db/abstract/abstract-db-p.h db/abstract/abstract-db.h diff --git a/src/core/core.cpp b/src/core/core.cpp index ff9975e27..fe3e79218 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -17,21 +17,42 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include + +#include "address/address.h" +#include "chat/chat-room/basic-chat-room.h" +#include "core-p.h" +#include "db/main-db.h" #include "object/object-p.h" #include "core.h" // ============================================================================= -LINPHONE_BEGIN_NAMESPACE +using namespace std; -class CorePrivate : public ObjectPrivate { -public: - // TODO. -}; +LINPHONE_BEGIN_NAMESPACE // ----------------------------------------------------------------------------- -Core::Core (CorePrivate &p) : Object(p) {} +Core::Core () : Object(*new CorePrivate) {} + +// ----------------------------------------------------------------------------- + +shared_ptr Core::createClientGroupChatRoom (const string &subject) { + // TODO. + return shared_ptr(); +} + +shared_ptr Core::getOrCreateChatRoom (const string &peerAddress, bool isRtt) const { + return shared_ptr(); +} + +const list> &Core::getChatRooms () const { + L_D(); + return d->chatRooms; +} + +// ----------------------------------------------------------------------------- LINPHONE_END_NAMESPACE diff --git a/src/core/core.h b/src/core/core.h index 025c60d22..88251aea5 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -20,21 +20,26 @@ #ifndef _CORE_H_ #define _CORE_H_ -#include "object/object.h" +#include + +#include "chat/chat-room/chat-room.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE +class ChatRoom; class CorePrivate; class LINPHONE_PUBLIC Core : public Object { public: - // Nothing for the moment. + Core (); + + std::shared_ptr createClientGroupChatRoom (const std::string &subject); + std::shared_ptr getOrCreateChatRoom (const std::string &peerAddress, bool isRtt = false) const; + const std::list> &getChatRooms () const; private: - explicit Core (CorePrivate &p); - L_DECLARE_PRIVATE(Core); L_DISABLE_COPY(Core); }; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 5376a8f87..191932e60 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -854,6 +854,12 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} // ----------------------------------------------------------------------------- +list> MainDb::getChatRooms () const { + list> chatRooms; + // TODO. + return chatRooms; +} + shared_ptr MainDb::findChatRoom (const string &peerAddress) const { L_D(); @@ -875,6 +881,8 @@ shared_ptr MainDb::findChatRoom (const string &peerAddress) const { " )", soci::use(peerAddress), soci::into(creationDate), soci::into(lastUpdateDate), soci::use(capabilities), soci::use(subject); + // TODO. + L_END_LOG_EXCEPTION return shared_ptr(); diff --git a/src/db/main-db.h b/src/db/main-db.h index 1cc262bc1..ae1dfe40f 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -70,6 +70,7 @@ public: void cleanHistory (const std::string &peerAddress = "", FilterMask mask = NoFilter); // ChatRooms. + std::list> getChatRooms () const; std::shared_ptr findChatRoom (const std::string &peerAddress) const; // Import legacy messages from old db. From abe689070d86c01a72e32a9271e97ca08a8964a0 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 18 Oct 2017 10:45:34 +0200 Subject: [PATCH 0552/2215] fix(Core): add missing core-p.h --- src/core/core-p.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/core/core-p.h diff --git a/src/core/core-p.h b/src/core/core-p.h new file mode 100644 index 000000000..5ebe4443f --- /dev/null +++ b/src/core/core-p.h @@ -0,0 +1,44 @@ +/* + * core-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CORE_P_H_ +#define _CORE_P_H_ + +#include "core.h" +#include "db/main-db.h" +#include "object/object-p.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class CorePrivate : public ObjectPrivate { +public: + MainDb mainDb; + +private: + std::list> chatRooms; + std::unordered_map> chatRoomsMap; + + L_DECLARE_PUBLIC(Core); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CORE_P_H_ From 9154626ccc5abd75392522662d4a6a1856abf7d1 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 18 Oct 2017 10:45:55 +0200 Subject: [PATCH 0553/2215] Added missing methods on factory for Java wrapper --- coreapi/factory.c | 8 ++++ include/linphone/factory.h | 14 +++++++ wrappers/java/java_class.mustache | 5 +++ wrappers/java/jni.mustache | 62 +++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+) diff --git a/coreapi/factory.c b/coreapi/factory.c index 33537d920..2dfb35145 100644 --- a/coreapi/factory.c +++ b/coreapi/factory.c @@ -361,4 +361,12 @@ void *linphone_factory_get_user_data(const LinphoneFactory *factory) { void linphone_factory_set_user_data(LinphoneFactory *factory, void *data) { factory->user_data = data; +} + +void linphone_factory_log_collection_path(LinphoneFactory *factory, const char *path) { + linphone_core_set_log_collection_path(path); +} + +void linphone_factory_enable_log_collection(LinphoneFactory *factory, LinphoneLogCollectionState state) { + linphone_core_enable_log_collection(state); } \ No newline at end of file diff --git a/include/linphone/factory.h b/include/linphone/factory.h index 1bdc50f4b..b9e439d3a 100644 --- a/include/linphone/factory.h +++ b/include/linphone/factory.h @@ -338,6 +338,20 @@ LINPHONE_PUBLIC void *linphone_factory_get_user_data(const LinphoneFactory *fact */ LINPHONE_PUBLIC void linphone_factory_set_user_data(LinphoneFactory *factory, void *data); +/** + * Sets the log collection path + * @param[in] factory the LinphoneFactory + * @param[in] the path of the logs + */ +LINPHONE_PUBLIC void linphone_factory_log_collection_path(LinphoneFactory *factory, const char *path); + +/** + * Enables or disables log collection + * @param[in] factory the LinphoneFactory + * @param[in] the policy for log collection + */ +LINPHONE_PUBLIC void linphone_factory_enable_log_collection(LinphoneFactory *factory, LinphoneLogCollectionState state); + /** * @} */ diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 0db3c1a6e..658d80899 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -94,6 +94,8 @@ public {{#isLinphoneFactory}}abstract class{{/isLinphoneFactory}}{{#isNotLinphon } abstract public OpenH264DownloadHelper createOpenH264DownloadHelper(Context context); + + abstract public void setDebugMode(boolean enable, String tag); {{/isLinphoneFactory}} {{#isLinphoneCore}} /** @@ -162,6 +164,9 @@ class {{classImplName}} {{#isLinphoneFactory}}extends{{/isLinphoneFactory}}{{#is } return new OpenH264DownloadHelper(context); } + + @Override + public native void setDebugMode(boolean enable, String tag); {{/isLinphoneFactory}} {{#methods}} diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index bb45e503d..51cef6d93 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -69,6 +69,68 @@ static jlong GetObjectNativePtr(JNIEnv *env, jobject object) { ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void linphone_android_log_handler(int prio, char *str) { + char *current; + char *next; + + if (strlen(str) < 512) { + __android_log_write(prio, LogDomain, str); + } else { + current = str; + while ((next = strchr(current, '\n')) != NULL) { + + *next = '\0'; + if (next != str && next[-1] == '\r') + next[-1] = '\0'; + __android_log_write(prio, LogDomain, current); + current = next + 1; + } + __android_log_write(prio, LogDomain, current); + } +} + +static void linphone_android_ortp_log_handler(const char *domain, OrtpLogLevel lev, const char *fmt, va_list args) { + char* str = bctbx_strdup_vprintf(fmt, args); + const char *levname = "undef"; + + if (str == NULL) return; + + int prio; + switch(lev) { + case ORTP_DEBUG: prio = ANDROID_LOG_DEBUG; levname="debug"; break; + case ORTP_MESSAGE: prio = ANDROID_LOG_INFO; levname="message"; break; + case ORTP_WARNING: prio = ANDROID_LOG_WARN; levname="warning"; break; + case ORTP_ERROR: prio = ANDROID_LOG_ERROR; levname="error"; break; + case ORTP_FATAL: prio = ANDROID_LOG_FATAL; levname="fatal"; break; + default: prio = ANDROID_LOG_DEFAULT; break; + } + + if (handler_obj) { + JNIEnv *env = ms_get_jni_env(); + jstring jdomain = env->NewStringUTF(LogDomain); + jstring jlevname = env->NewStringUTF(levname); + jstring jstr = env->NewStringUTF(str); + env->CallVoidMethod(handler_obj, loghandler_id, jdomain, (jint)lev, jlevname, jstr, NULL); + if (jdomain) env->DeleteLocalRef(jdomain); + if (jlevname) env->DeleteLocalRef(jlevname); + if (jstr) env->DeleteLocalRef(jstr); + } else { + linphone_android_log_handler(prio, str); + } + bctbx_free(str); +} + +void Java_org_linphone_core_FactoryImpl_setDebugMode(JNIEnv* env, jobject thiz, jboolean isDebug, jstring jdebugTag) { + if (isDebug) { + LogDomain = GetStringUTFChars(env, jdebugTag); + linphone_core_enable_logs_with_cb(linphone_android_ortp_log_handler); + } else { + linphone_core_disable_logs(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + class LinphoneJavaBindings { public: LinphoneJavaBindings(JNIEnv *env) { From 4ec852cb08e800ef3364a34ff4ecbbc154862128 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 18 Oct 2017 10:49:19 +0200 Subject: [PATCH 0554/2215] Fixed jni compil --- wrappers/java/jni.mustache | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index 51cef6d93..14c268f79 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -40,6 +40,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #endif /* __ANDROID__ */ static JavaVM *jvm = NULL; +static const char* LogDomain = "Linphone"; +static jmethodID loghandler_id; +static jobject handler_obj=NULL; JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *ajvm, void *reserved) { #ifdef __ANDROID__ From e21f193a574ac6616e6c275534a002781293e60c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 18 Oct 2017 10:53:59 +0200 Subject: [PATCH 0555/2215] Fixed wrongly named method in factory --- coreapi/factory.c | 2 +- include/linphone/factory.h | 2 +- wrappers/java/migration.sh | 6 +----- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/coreapi/factory.c b/coreapi/factory.c index 2dfb35145..c85976ff5 100644 --- a/coreapi/factory.c +++ b/coreapi/factory.c @@ -363,7 +363,7 @@ void linphone_factory_set_user_data(LinphoneFactory *factory, void *data) { factory->user_data = data; } -void linphone_factory_log_collection_path(LinphoneFactory *factory, const char *path) { +void linphone_factory_set_log_collection_path(LinphoneFactory *factory, const char *path) { linphone_core_set_log_collection_path(path); } diff --git a/include/linphone/factory.h b/include/linphone/factory.h index b9e439d3a..26a5aa29b 100644 --- a/include/linphone/factory.h +++ b/include/linphone/factory.h @@ -343,7 +343,7 @@ LINPHONE_PUBLIC void linphone_factory_set_user_data(LinphoneFactory *factory, vo * @param[in] factory the LinphoneFactory * @param[in] the path of the logs */ -LINPHONE_PUBLIC void linphone_factory_log_collection_path(LinphoneFactory *factory, const char *path); +LINPHONE_PUBLIC void linphone_factory_set_log_collection_path(LinphoneFactory *factory, const char *path); /** * Enables or disables log collection diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index 9d84a6273..afc602ef7 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -275,8 +275,6 @@ s/new XmlRpcSessionImpl(LinphoneManager.getLcIfManagerNotDestroyedOrNull(), /Lin # TODO #Tunnel, TunnelConfig #AccountCreator.updatePassword => What to do ? -#Factory.instance().enableLogCollection(isDebugEnabled); -#Factory.instance().setDebugMode(isDebugEnabled, context.getString(R.string.app_name)); # Manual changes required # Some callbacks no longer exist, their name will be "removed", remove them @@ -308,9 +306,7 @@ s/new XmlRpcSessionImpl(LinphoneManager.getLcIfManagerNotDestroyedOrNull(), /Lin # # Factory #Factory.createAccountCreator() => Core.createAccountCreator() #Factory.createPresenceModel() => Core.createPresenceModel() -#Factory.instance().setLogCollectionPath(getFilesDir().getAbsolutePath()); => Core.setLogCollectionPath -#Factory.instance().enableLogCollection(isDebugEnabled); => Core.enableLogCollection -#Factory.instance().setDebugMode(isDebugEnabled, getString(R.string.app_name)); => Core.setLogLevelMask +#Factory.instance().enableLogCollection(isDebugEnabled); now takes a LogCollectionState # # Core #Core.getVideoDevice and Core.setVideoDevice now takes/returns String instead of int From 9f98fa5f6c73f482e2b089fc2e3012d4275db549 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 18 Oct 2017 11:17:48 +0200 Subject: [PATCH 0556/2215] Fixed some symbol errors --- coreapi/linphone_tunnel_stubs.c | 8 ++++++++ coreapi/vtables.c | 1 + 2 files changed, 9 insertions(+) diff --git a/coreapi/linphone_tunnel_stubs.c b/coreapi/linphone_tunnel_stubs.c index 7e2994e78..d4c901009 100644 --- a/coreapi/linphone_tunnel_stubs.c +++ b/coreapi/linphone_tunnel_stubs.c @@ -38,6 +38,14 @@ LinphoneTunnel* linphone_core_get_tunnel(const LinphoneCore *lc){ void linphone_tunnel_destroy(LinphoneTunnel *tunnel){ } +LinphoneTunnel *linphone_tunnel_ref(LinphoneTunnel *tunnel) { + ms_warning("linphone_tunnel_ref() - stubbed, no implementation"); + return tunnel; +} + +void linphone_tunnel_unref(LinphoneTunnel *tunnel) { + ms_warning("linphone_tunnel_unref() - stubbed, no implementation"); +} void linphone_tunnel_add_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config){ ms_warning("linphone_tunnel_add_server() - stubbed, no implementation"); diff --git a/coreapi/vtables.c b/coreapi/vtables.c index 280283771..6588ddbc0 100644 --- a/coreapi/vtables.c +++ b/coreapi/vtables.c @@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "private.h" +#include "linphone/wrapper_utils.h" LinphoneCoreVTable *linphone_core_v_table_new() { From 38f8ef4485e490860fc51624ba388347bcceb241 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 18 Oct 2017 11:18:40 +0200 Subject: [PATCH 0557/2215] connect cppCore with c_core and add received conference events in db --- coreapi/linphonecore.c | 4 ++++ coreapi/private.h | 5 +++++ src/chat/chat-room/client-group-chat-room.cpp | 7 +++++++ src/core/core.h | 1 + 4 files changed, 17 insertions(+) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1d9786313..2fb96205c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2233,6 +2233,8 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig lc->sal->set_user_pointer(lc); lc->sal->set_callbacks(&linphone_sal_callbacks); + new(&lc->cppCore) Core(); + #ifdef TUNNEL_ENABLED lc->tunnel=linphone_core_tunnel_new(lc); #endif @@ -5825,6 +5827,8 @@ void sip_config_uninit(LinphoneCore *lc) delete lc->sal; lc->sal=NULL; + lc->cppCore.~Core(); + if (lc->sip_conf.guessed_contact) ms_free(lc->sip_conf.guessed_contact); if (config->contact) diff --git a/coreapi/private.h b/coreapi/private.h index be9d0150c..eca250923 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -33,6 +33,7 @@ #include "linphone/conference.h" #include "address/address.h" #include "c-wrapper/internal/c-sal.h" +#include "core/core.h" #include "sal/call-op.h" #include "sal/event-op.h" #include "sal/message-op.h" @@ -810,6 +811,10 @@ struct _LinphoneCore MSList* vtable_refs; int vtable_notify_recursion; LinphonePrivate::Sal *sal; + + // For migration purposes + LinphonePrivate::Core cppCore; + LinphoneGlobalState state; struct _LpConfig *config; MSList *default_audio_codecs; diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 0a6b8cdec..1d51e386e 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -26,6 +26,7 @@ #include "conference/remote-conference-event-handler.h" #include "conference/remote-conference-p.h" #include "conference/session/call-session-p.h" +#include "core/core-p.h" #include "event-log/events.h" #include "logger/logger.h" #include "sal/refer-op.h" @@ -282,6 +283,7 @@ void ClientGroupChatRoom::onParticipantAdded (time_t tm, const Address &addr) { dConference->eventHandler->getLastNotify(), addr ); + Conference::getCore()->cppCore.getPrivate()->mainDb.addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(&event)); @@ -306,6 +308,7 @@ void ClientGroupChatRoom::onParticipantRemoved (time_t tm, const Address &addr) dConference->eventHandler->getLastNotify(), addr ); + Conference::getCore()->cppCore.getPrivate()->mainDb.addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(&event)); @@ -336,6 +339,7 @@ void ClientGroupChatRoom::onParticipantSetAdmin (time_t tm, const Address &addr, dConference->eventHandler->getLastNotify(), addr ); + Conference::getCore()->cppCore.getPrivate()->mainDb.addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(&event)); @@ -353,6 +357,7 @@ void ClientGroupChatRoom::onSubjectChanged (time_t tm, const std::string &subjec dConference->eventHandler->getLastNotify(), subject ); + Conference::getCore()->cppCore.getPrivate()->mainDb.addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(&event)); @@ -381,6 +386,7 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (time_t tm, const Address &ad addr, gruu ); + Conference::getCore()->cppCore.getPrivate()->mainDb.addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(&event)); @@ -409,6 +415,7 @@ void ClientGroupChatRoom::onParticipantDeviceRemoved (time_t tm, const Address & addr, gruu ); + Conference::getCore()->cppCore.getPrivate()->mainDb.addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(&event)); diff --git a/src/core/core.h b/src/core/core.h index 88251aea5..715abbaf9 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -32,6 +32,7 @@ class ChatRoom; class CorePrivate; class LINPHONE_PUBLIC Core : public Object { +friend class ClientGroupChatRoom; public: Core (); From 61652e08a893692fa42c86b8a5d999dbf9f8f1f1 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 18 Oct 2017 12:03:12 +0200 Subject: [PATCH 0558/2215] Added missing extern C in Java's JNI --- wrappers/java/jni.mustache | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index 14c268f79..a26da67df 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -123,7 +123,7 @@ static void linphone_android_ortp_log_handler(const char *domain, OrtpLogLevel l bctbx_free(str); } -void Java_org_linphone_core_FactoryImpl_setDebugMode(JNIEnv* env, jobject thiz, jboolean isDebug, jstring jdebugTag) { +extern "C" void Java_org_linphone_core_FactoryImpl_setDebugMode(JNIEnv* env, jobject thiz, jboolean isDebug, jstring jdebugTag) { if (isDebug) { LogDomain = GetStringUTFChars(env, jdebugTag); linphone_core_enable_logs_with_cb(linphone_android_ortp_log_handler); @@ -306,6 +306,10 @@ static {{return}} {{callbackName}}({{params}}) { {{/callbacks}} ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +extern "C" { +#endif + {{#interfaces}} {{#isSingleListener}} void {{jniPackage}}{{className}}Impl_setListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { @@ -421,4 +425,8 @@ jobject {{jni_package}}CoreImpl_getMediastreamerFactory(JNIEnv *env, jobject thi {{/bytes}}{{#hasReturn}}return jni_result;{{/hasReturn}}{{#hasListReturn}}return jni_list_result;{{/hasListReturn}} } -{{/methods}} \ No newline at end of file +{{/methods}} + +#ifdef __cplusplus +} +#endif \ No newline at end of file From 12e1ccfe58eb0b59410199bb4a111f390e8eb6ad Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 18 Oct 2017 13:17:22 +0200 Subject: [PATCH 0559/2215] Various fixes for JNI layer of Java wrapper --- wrappers/java/genwrapper.py | 13 ++++-- wrappers/java/java_class.mustache | 9 ++++ wrappers/java/jni.mustache | 68 +++++++++++++++++++++++++++---- 3 files changed, 78 insertions(+), 12 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 13e0c4ae5..fc2ef4566 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -494,9 +494,10 @@ class JavaTranslator(object): methodDict['isJniUpcallObject'] = True methodDict['jniUpcallType'] = 'jobject' elif type(_method.returnType) is AbsApi.BaseType: - methodDict['jniUpcallMethod'] = 'CallIntMethod' - methodDict['jniUpcallType'] = self.translate_type(_method.returnType, jni=True) - methodDict['isJniUpcallBasicType'] = True + if not _method.returnType.name == 'void': + methodDict['jniUpcallMethod'] = 'CallIntMethod' + methodDict['jniUpcallType'] = self.translate_type(_method.returnType, jni=True) + methodDict['isJniUpcallBasicType'] = True methodDict['returnIfFail'] = '' if methodDict['return'] == 'void' else ' NULL' methodDict['hasReturn'] = not methodDict['return'] == 'void' methodDict['isSingleListener'] = not _class.multilistener @@ -761,7 +762,11 @@ class GenWrapper(object): self.parser = AbsApi.CParser(project) self.parser.functionBl = \ - ['linphone_vcard_get_belcard',\ + ['linphone_factory_create_core_with_config',\ + 'linphone_factory_create_core',\ + 'linphone_factory_create_core_2',\ + 'linphone_factory_create_core_with_config_2',\ + 'linphone_vcard_get_belcard',\ 'linphone_core_get_current_vtable',\ 'linphone_factory_get',\ 'linphone_factory_clean',\ diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 658d80899..7490f9476 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -96,6 +96,9 @@ public {{#isLinphoneFactory}}abstract class{{/isLinphoneFactory}}{{#isNotLinphon abstract public OpenH264DownloadHelper createOpenH264DownloadHelper(Context context); abstract public void setDebugMode(boolean enable, String tag); + + abstract public Core createCore(CoreListener listener, String configPath, String factoryConfigPath); + {{/isLinphoneFactory}} {{#isLinphoneCore}} /** @@ -167,6 +170,12 @@ class {{classImplName}} {{#isLinphoneFactory}}extends{{/isLinphoneFactory}}{{#is @Override public native void setDebugMode(boolean enable, String tag); + + private native Core createCore(long nativePtr, CoreListener listener, String configPath, String factoryConfigPath); + @Override + public Core createCore(CoreListener listener, String configPath, String factoryConfigPath) { + return createCore(nativePtr, listener, configPath, factoryConfigPath); + } {{/isLinphoneFactory}} {{#methods}} diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index a26da67df..492a49034 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -181,6 +181,9 @@ public: }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +extern "C" { +#endif {{#objects}} jobject get{{className}}(JNIEnv *env, {{classCName}} *cptr) { @@ -306,16 +309,12 @@ static {{return}} {{callbackName}}({{params}}) { {{/callbacks}} ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#ifdef __cplusplus -extern "C" { -#endif - {{#interfaces}} {{#isSingleListener}} -void {{jniPackage}}{{className}}Impl_setListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { +void Java_{{jniPackage}}{{className}}Impl_setListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { {{/isSingleListener}} {{#isMultiListener}} -void {{jniPackage}}{{className}}Impl_addListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { +void Java_{{jniPackage}}{{className}}Impl_addListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { {{/isMultiListener}} {{classCName}} *cptr = ({{classCName}}*)ptr; jobject listener = env->NewGlobalRef(jlistener); @@ -335,7 +334,7 @@ void {{jniPackage}}{{className}}Impl_addListener(JNIEnv* env, jobject thiz, jlon } {{#isMultiListener}} -void {{jniPackage}}{{className}}Impl_removeListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { +void Java_{{jniPackage}}{{className}}Impl_removeListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { {{classCName}} *cptr = ({{classCName}}*)ptr; const bctbx_list_t *cbs_list = {{cPrefix}}_get_callbacks_list(cptr); bctbx_list_t *it; @@ -352,12 +351,65 @@ void {{jniPackage}}{{className}}Impl_removeListener(JNIEnv* env, jobject thiz, j {{/interfaces}} ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -jobject {{jni_package}}CoreImpl_getMediastreamerFactory(JNIEnv *env, jobject thiz, jlong ptr) { +jobject Java_{{jni_package}}CoreImpl_getMediastreamerFactory(JNIEnv *env, jobject thiz, jlong ptr) { LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_factory_get_user_data(linphone_factory_get()); MSFactory *factory = linphone_core_get_ms_factory((LinphoneCore*)ptr); return env->NewObject(ljb->ms_factory_class, ljb->ms_factory_class_constructor, (jlong)factory); } +jobject Java_{{jni_package}}FactoryImpl_createCore(JNIEnv *env, jobject thiz, jlong ptr, jobject jlistener, jstring jconfig_path, jstring jfactory_config_path) { + LinphoneFactory *cptr = (LinphoneFactory*)ptr; + + LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(cptr); + jobject listener = env->NewGlobalRef(jlistener); + + const char *config_path = GetStringUTFChars(env, jconfig_path); + const char *factory_config_path = GetStringUTFChars(env, jfactory_config_path); + LinphoneCore *core = NULL; + + linphone_core_cbs_set_user_data(cbs, listener); + linphone_core_cbs_set_transfer_state_changed(cbs, linphone_core_on_transfer_state_changed); + linphone_core_cbs_set_chat_room_instantiated(cbs, linphone_core_on_chat_room_instantiated); + linphone_core_cbs_set_friend_list_created(cbs, linphone_core_on_friend_list_created); + linphone_core_cbs_set_subscription_state_changed(cbs, linphone_core_on_subscription_state_changed); + linphone_core_cbs_set_call_log_updated(cbs, linphone_core_on_call_log_updated); + linphone_core_cbs_set_call_state_changed(cbs, linphone_core_on_call_state_changed); + linphone_core_cbs_set_authentication_requested(cbs, linphone_core_on_authentication_requested); + linphone_core_cbs_set_notify_presence_received_for_uri_or_tel(cbs, linphone_core_on_notify_presence_received_for_uri_or_tel); + linphone_core_cbs_set_buddy_info_updated(cbs, linphone_core_on_buddy_info_updated); + linphone_core_cbs_set_network_reachable(cbs, linphone_core_on_network_reachable); + linphone_core_cbs_set_notify_received(cbs, linphone_core_on_notify_received); + linphone_core_cbs_set_new_subscription_requested(cbs, linphone_core_on_new_subscription_requested); + linphone_core_cbs_set_registration_state_changed(cbs, linphone_core_on_registration_state_changed); + linphone_core_cbs_set_notify_presence_received(cbs, linphone_core_on_notify_presence_received); + linphone_core_cbs_set_ec_calibration_audio_init(cbs, linphone_core_on_ec_calibration_audio_init); + linphone_core_cbs_set_message_received(cbs, linphone_core_on_message_received); + linphone_core_cbs_set_ec_calibration_result(cbs, linphone_core_on_ec_calibration_result); + linphone_core_cbs_set_info_received(cbs, linphone_core_on_info_received); + linphone_core_cbs_set_call_stats_updated(cbs, linphone_core_on_call_stats_updated); + linphone_core_cbs_set_friend_list_removed(cbs, linphone_core_on_friend_list_removed); + linphone_core_cbs_set_refer_received(cbs, linphone_core_on_refer_received); + linphone_core_cbs_set_configuring_status(cbs, linphone_core_on_configuring_status); + linphone_core_cbs_set_call_created(cbs, linphone_core_on_call_created); + linphone_core_cbs_set_publish_state_changed(cbs, linphone_core_on_publish_state_changed); + linphone_core_cbs_set_call_encryption_changed(cbs, linphone_core_on_call_encryption_changed); + linphone_core_cbs_set_is_composing_received(cbs, linphone_core_on_is_composing_received); + linphone_core_cbs_set_message_received_unable_decrypt(cbs, linphone_core_on_message_received_unable_decrypt); + linphone_core_cbs_set_log_collection_upload_progress_indication(cbs, linphone_core_on_log_collection_upload_progress_indication); + linphone_core_cbs_set_version_update_check_result_received(cbs, linphone_core_on_version_update_check_result_received); + linphone_core_cbs_set_ec_calibration_audio_uninit(cbs, linphone_core_on_ec_calibration_audio_uninit); + linphone_core_cbs_set_global_state_changed(cbs, linphone_core_on_global_state_changed); + linphone_core_cbs_set_log_collection_upload_state_changed(cbs, linphone_core_on_log_collection_upload_state_changed); + linphone_core_cbs_set_dtmf_received(cbs, linphone_core_on_dtmf_received); + + core = linphone_factory_create_core(linphone_factory_get(), cbs, config_path, factory_config_path); + + ReleaseStringUTFChars(env, jconfig_path, config_path); + ReleaseStringUTFChars(env, jfactory_config_path, factory_config_path); + + return getCore(env, core); +} + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {{#methods}} From 9fa66fc345470d99073649e75579a1277c27e656 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 18 Oct 2017 13:33:05 +0200 Subject: [PATCH 0560/2215] Some fixes for Java wrapper --- wrappers/java/java_class.mustache | 4 ++-- wrappers/java/jni.mustache | 11 +++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 7490f9476..9dc920ec5 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -171,10 +171,10 @@ class {{classImplName}} {{#isLinphoneFactory}}extends{{/isLinphoneFactory}}{{#is @Override public native void setDebugMode(boolean enable, String tag); - private native Core createCore(long nativePtr, CoreListener listener, String configPath, String factoryConfigPath); + private native Core createCore(Factory factory, CoreListener listener, String configPath, String factoryConfigPath); @Override public Core createCore(CoreListener listener, String configPath, String factoryConfigPath) { - return createCore(nativePtr, listener, configPath, factoryConfigPath); + return createCore(this, listener, configPath, factoryConfigPath); } {{/isLinphoneFactory}} diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index 492a49034..8da4789f0 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -70,6 +70,12 @@ static jlong GetObjectNativePtr(JNIEnv *env, jobject object) { return nativePtr; } +static void SetObjectNativePtr(JNIEnv *env, jobject object, jlong ptr) { + jclass objClass = env->GetObjectClass(object); + jfieldID nativePtrId = env->GetFieldID(objClass, "nativePtr", "J"); + env->SetLongField(object, nativePtrId, ptr); +} + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void linphone_android_log_handler(int prio, char *str) { @@ -357,8 +363,9 @@ jobject Java_{{jni_package}}CoreImpl_getMediastreamerFactory(JNIEnv *env, jobjec return env->NewObject(ljb->ms_factory_class, ljb->ms_factory_class_constructor, (jlong)factory); } -jobject Java_{{jni_package}}FactoryImpl_createCore(JNIEnv *env, jobject thiz, jlong ptr, jobject jlistener, jstring jconfig_path, jstring jfactory_config_path) { - LinphoneFactory *cptr = (LinphoneFactory*)ptr; +jobject Java_{{jni_package}}FactoryImpl_createCore(JNIEnv *env, jobject thiz, jobject jfactory, jobject jlistener, jstring jconfig_path, jstring jfactory_config_path) { + LinphoneFactory *cptr = linphone_factory_get(); + SetObjectNativePtr(env, jfactory, (jlong)cptr); // Set the C factory ptr as Factory.nativePtr for next factory calls LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(cptr); jobject listener = env->NewGlobalRef(jlistener); From f1e0a444018a655088057e84f078dc9ac90f4211 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 18 Oct 2017 13:34:34 +0200 Subject: [PATCH 0561/2215] Fix crash for linphone_core_get_callbacks_list --- coreapi/vtables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/vtables.c b/coreapi/vtables.c index 6588ddbc0..33eab6ccb 100644 --- a/coreapi/vtables.c +++ b/coreapi/vtables.c @@ -349,7 +349,7 @@ void linphone_core_remove_listener(LinphoneCore *lc, const LinphoneCoreVTable *v } bctbx_list_t *linphone_core_get_callbacks_list(const LinphoneCore *lc) { - bctbx_list_t *result; + bctbx_list_t *result = NULL; bctbx_list_t *it; for(it=lc->vtable_refs; it!=NULL; it=it->next){ VTableReference *ref=(VTableReference*)it->data; From 88ef203bc7f1503df318976a7cb5858d6f2f8004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Wed, 18 Oct 2017 14:54:52 +0200 Subject: [PATCH 0562/2215] Fix C++ wrapper generation when the VCard support of Liblinphone is disabled. --- coreapi/vcard_stubs.c | 9 +++++++++ wrappers/cpp/class_header.mustache | 9 ++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/coreapi/vcard_stubs.c b/coreapi/vcard_stubs.c index 90bebe896..496898158 100644 --- a/coreapi/vcard_stubs.c +++ b/coreapi/vcard_stubs.c @@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "linphone/core.h" +#include "linphone/wrapper_utils.h" #include "vcard_private.h" struct _LinphoneVcardContext { @@ -179,3 +180,11 @@ bool_t linphone_core_vcard_supported(void) { void linphone_vcard_clean_cache(LinphoneVcard *vCard) { } + +void *linphone_vcard_get_belcard(LinphoneVcard *vCard) { + return NULL; +} + +LinphoneVcard *linphone_vcard_clone(const LinphoneVcard *vCard) { + return NULL; +} diff --git a/wrappers/cpp/class_header.mustache b/wrappers/cpp/class_header.mustache index b81329836..ae8f3394c 100644 --- a/wrappers/cpp/class_header.mustache +++ b/wrappers/cpp/class_header.mustache @@ -29,13 +29,16 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. {{/includes}} #include "object.hh" -{{#_class}}{{#isVcard}} -#include -{{/isVcard}}{{/_class}} {{#_class}}{{#isfactory}} #include "config.hh" {{/isfactory}}{{/_class}} +{{#_class}}{{#isVcard}} +namespace belcard { +class BelCard; +} +{{/isVcard}}{{/_class}} + {{#_class}} {{#isNotListener}} From a9e3caf17f8c233f5ab9a517a1382c6fd3453a24 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 18 Oct 2017 15:26:56 +0200 Subject: [PATCH 0563/2215] Fixed content_get_buffer and content_set_buffer methods in Java wrapper --- wrappers/java/genwrapper.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index fc2ef4566..095902c2a 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -249,9 +249,17 @@ class JavaTranslator(object): return 'char' elif _type.name == 'void': if isReturn: + if _type.isref and jni: + return 'jbyteArray' + if _type.isref: + return 'byte[]' return 'void' if jni: + if _type.isref and _type.isconst: + return 'jbyteArray' return 'jobject' + if _type.isref and _type.isconst: + return 'byte[]' return 'Object' return _type.name @@ -415,7 +423,7 @@ class JavaTranslator(object): methodDict['params_impl'] += '(' + argCType + ') ' + argname elif type(arg.type) is AbsApi.BaseType: - if arg.type.name == 'integer' and arg.type.size is not None and arg.type.isref: + if (arg.type.name == 'integer' and arg.type.size is not None and arg.type.isref) or (arg.type.name == 'void' and arg.type.isref and arg.type.isconst): methodDict['bytes'].append({'bytesargname': argname, 'bytesargtype' : self.translate_as_c_base_type(arg.type)}) methodDict['params_impl'] += 'c_' + argname elif arg.type.name == 'string': From aaf0eac9c79b8f69abba752a29c6b12ce18ed957 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 18 Oct 2017 15:44:11 +0200 Subject: [PATCH 0564/2215] Fixed crash in proxy config when dialplan is generic --- coreapi/proxy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index db2af889e..47fae5ed0 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -686,7 +686,7 @@ char* linphone_proxy_config_normalize_phone_number(LinphoneProxyConfig *proxy, c ms_debug("Using dial plan '%s'",linphone_dial_plan_get_country(dialplan)); /*if proxy has a dial prefix, modify phonenumber accordingly*/ - if (linphone_dial_plan_get_country_calling_code(dialplan)[0]!='\0') { + if (linphone_dial_plan_get_country_calling_code(dialplan) != NULL && linphone_dial_plan_get_country_calling_code(dialplan)[0]!='\0') { /* the number already starts with + or international prefix*/ /*0. keep at most national number significant digits */ char* nationnal_significant_number_start = nationnal_significant_number From a01787fbe675a6861c1dd7ff13c3d04daf86330f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 18 Oct 2017 15:52:41 +0200 Subject: [PATCH 0565/2215] Blacklisted 3 methods badly wrapper temporarily --- wrappers/java/genwrapper.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 095902c2a..af760c0be 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -779,6 +779,9 @@ class GenWrapper(object): 'linphone_factory_get',\ 'linphone_factory_clean',\ 'linphone_call_zoom_video',\ + 'linphone_core_get_native_video_window_id',\ + 'linphone_core_get_native_preview_window_id',\ + 'linphone_core_get_zrtp_cache_db',\ 'linphone_config_get_range'] self.parser.parse_all() self.translator = JavaTranslator(package, exceptions) From c0a2fcd05dd46f1202cee980127dd96db82f1855 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 18 Oct 2017 15:59:01 +0200 Subject: [PATCH 0566/2215] Unblacklisted 2 methods for Java wrapper because if getter is blacklisted, setter won't be wrapped... --- wrappers/java/genwrapper.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index af760c0be..6c4445e6c 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -779,8 +779,6 @@ class GenWrapper(object): 'linphone_factory_get',\ 'linphone_factory_clean',\ 'linphone_call_zoom_video',\ - 'linphone_core_get_native_video_window_id',\ - 'linphone_core_get_native_preview_window_id',\ 'linphone_core_get_zrtp_cache_db',\ 'linphone_config_get_range'] self.parser.parse_all() From d5e59ae6eef31be6600fa4ce875bfcea70f1d85e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 19 Oct 2017 10:39:42 +0200 Subject: [PATCH 0567/2215] content_set_buffer now takes a uint8_t* instead of a void* so it can be correctly wrapped automatically --- coreapi/content.c | 6 +++--- coreapi/proxy.c | 2 +- include/linphone/content.h | 4 ++-- .../local-conference-event-handler.cpp | 2 +- tester/eventapi_tester.c | 18 +++++++++--------- tester/flexisip_tester.c | 4 ++-- tester/message_tester.c | 2 +- wrappers/java/genwrapper.py | 10 +--------- 8 files changed, 20 insertions(+), 28 deletions(-) diff --git a/coreapi/content.c b/coreapi/content.c index 86d2cfbcc..055591ee5 100644 --- a/coreapi/content.c +++ b/coreapi/content.c @@ -118,11 +118,11 @@ void linphone_content_set_subtype(LinphoneContent *content, const char *subtype) sal_body_handler_set_subtype(content->body_handler, subtype); } -void * linphone_content_get_buffer(const LinphoneContent *content) { - return sal_body_handler_get_data(content->body_handler); +uint8_t * linphone_content_get_buffer(const LinphoneContent *content) { + return (uint8_t *)sal_body_handler_get_data(content->body_handler); } -void linphone_content_set_buffer(LinphoneContent *content, const void *buffer, size_t size) { +void linphone_content_set_buffer(LinphoneContent *content, const uint8_t *buffer, size_t size) { void *data; sal_body_handler_set_size(content->body_handler, size); data = belle_sip_malloc(size + 1); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 47fae5ed0..63a0af6eb 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -887,7 +887,7 @@ int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, LinphonePrese } content = linphone_content_new(); - linphone_content_set_buffer(content,presence_body,strlen(presence_body)); + linphone_content_set_buffer(content, (const uint8_t *)presence_body,strlen(presence_body)); linphone_content_set_type(content, "application"); linphone_content_set_subtype(content,"pidf+xml"); if (proxy->sip_etag) { diff --git a/include/linphone/content.h b/include/linphone/content.h index 653d4344a..78ebc3114 100644 --- a/include/linphone/content.h +++ b/include/linphone/content.h @@ -94,7 +94,7 @@ LINPHONE_PUBLIC void linphone_content_set_subtype(LinphoneContent *content, cons * @param[in] content LinphoneContent object. * @return The content data buffer. */ -LINPHONE_PUBLIC void * linphone_content_get_buffer(const LinphoneContent *content); +LINPHONE_PUBLIC uint8_t * linphone_content_get_buffer(const LinphoneContent *content); /** * Set the content data buffer, usually a string. @@ -102,7 +102,7 @@ LINPHONE_PUBLIC void * linphone_content_get_buffer(const LinphoneContent *conten * @param[in] buffer The content data buffer. * @param[in] size The size of the content data buffer. */ -LINPHONE_PUBLIC void linphone_content_set_buffer(LinphoneContent *content, const void *buffer, size_t size); +LINPHONE_PUBLIC void linphone_content_set_buffer(LinphoneContent *content, const uint8_t *buffer, size_t size); /** * Get the string content data buffer. diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 92c6149e2..94ca0c870 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -38,7 +38,7 @@ using namespace Xsd::ConferenceInfo; static void doNotify (const string ¬ify, LinphoneEvent *lev) { LinphoneContent *content = linphone_core_create_content(lev->lc); - linphone_content_set_buffer(content, notify.c_str(), strlen(notify.c_str())); + linphone_content_set_buffer(content, (const uint8_t *)notify.c_str(), strlen(notify.c_str())); linphone_event_notify(lev, content); linphone_content_unref(content); } diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index 7bbdbf24e..8d3e7d600 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -55,7 +55,7 @@ void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, Li content = linphone_core_create_content(lc); linphone_content_set_type(content,"application"); linphone_content_set_subtype(content,"somexml2"); - linphone_content_set_buffer(content,notify_content,strlen(notify_content)); + linphone_content_set_buffer(content,(const uint8_t *)notify_content,strlen(notify_content)); ms_message("Subscription state [%s] from [%s]",linphone_subscription_state_to_string(state),from); ms_free(from); @@ -138,7 +138,7 @@ static void subscribe_test_declined(void) { content = linphone_core_create_content(marie->lc); linphone_content_set_type(content,"application"); linphone_content_set_subtype(content,"somexml"); - linphone_content_set_buffer(content,subscribe_content,strlen(subscribe_content)); + linphone_content_set_buffer(content,(const uint8_t *)subscribe_content,strlen(subscribe_content)); pauline->decline_subscribe=TRUE; @@ -186,7 +186,7 @@ static void subscribe_test_with_args(bool_t terminated_by_subscriber, RefreshTes content = linphone_core_create_content(marie->lc); linphone_content_set_type(content,"application"); linphone_content_set_subtype(content,"somexml"); - linphone_content_set_buffer(content,subscribe_content,strlen(subscribe_content)); + linphone_content_set_buffer(content,(const uint8_t *)subscribe_content,strlen(subscribe_content)); lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",expires,content); linphone_event_ref(lev); @@ -244,7 +244,7 @@ static void subscribe_test_with_args2(bool_t terminated_by_subscriber, RefreshTe content = linphone_core_create_content(marie->lc); linphone_content_set_type(content,"application"); linphone_content_set_subtype(content,"somexml"); - linphone_content_set_buffer(content,subscribe_content,strlen(subscribe_content)); + linphone_content_set_buffer(content,(const uint8_t *)subscribe_content,strlen(subscribe_content)); lev=linphone_core_create_subscribe(marie->lc,pauline->identity,"dodo",expires); linphone_event_add_custom_header(lev,"My-Header","pouet"); @@ -332,7 +332,7 @@ static void subscribe_loosing_dialog(void) { content = linphone_core_create_content(marie->lc); linphone_content_set_type(content,"application"); linphone_content_set_subtype(content,"somexml"); - linphone_content_set_buffer(content,subscribe_content,strlen(subscribe_content)); + linphone_content_set_buffer(content,(const uint8_t *)subscribe_content,strlen(subscribe_content)); lev=linphone_core_create_subscribe(marie->lc,pauline->identity,"dodo",expires); linphone_event_add_custom_header(lev,"My-Header","pouet"); @@ -395,7 +395,7 @@ static void subscribe_with_io_error(void) { content = linphone_core_create_content(marie->lc); linphone_content_set_type(content,"application"); linphone_content_set_subtype(content,"somexml"); - linphone_content_set_buffer(content,subscribe_content,strlen(subscribe_content)); + linphone_content_set_buffer(content,(const uint8_t *)subscribe_content,strlen(subscribe_content)); lev=linphone_core_create_subscribe(marie->lc,pauline->identity,"dodo",expires); linphone_event_add_custom_header(lev,"My-Header","pouet"); @@ -449,7 +449,7 @@ static void subscribe_not_timely_responded(void) { content = linphone_core_create_content(marie->lc); linphone_content_set_type(content,"application"); linphone_content_set_subtype(content,"somexml"); - linphone_content_set_buffer(content,subscribe_content,strlen(subscribe_content)); + linphone_content_set_buffer(content,(const uint8_t *)subscribe_content,strlen(subscribe_content)); lev=linphone_core_create_subscribe(marie->lc,pauline->identity,"dodo",expires); linphone_event_add_custom_header(lev,"My-Header","pouet"); @@ -495,7 +495,7 @@ static void publish_test_with_args(bool_t refresh, int expires){ content = linphone_core_create_content(marie->lc); linphone_content_set_type(content,"application"); linphone_content_set_subtype(content,"somexml"); - linphone_content_set_buffer(content,subscribe_content,strlen(subscribe_content)); + linphone_content_set_buffer(content,(const uint8_t *)subscribe_content,strlen(subscribe_content)); lp_config_set_int(linphone_core_get_config(marie->lc),"sip","refresh_generic_publish",refresh); @@ -551,7 +551,7 @@ static void out_of_dialog_notify(void){ content = linphone_core_create_content(marie->lc); linphone_content_set_type(content,"application"); linphone_content_set_subtype(content,"somexml"); - linphone_content_set_buffer(content,notify_content,strlen(notify_content)); + linphone_content_set_buffer(content,(const uint8_t *)notify_content,strlen(notify_content)); lev = linphone_core_create_notify(marie->lc,pauline->identity,"dodo"); linphone_event_ref(lev); diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c index 9c46c2942..1eca49e28 100644 --- a/tester/flexisip_tester.c +++ b/tester/flexisip_tester.c @@ -42,7 +42,7 @@ static void subscribe_forking(void) { content = linphone_core_create_content(marie->lc); linphone_content_set_type(content,"application"); linphone_content_set_subtype(content,"somexml"); - linphone_content_set_buffer(content, liblinphone_tester_get_subscribe_content(), strlen(liblinphone_tester_get_subscribe_content())); + linphone_content_set_buffer(content, (const uint8_t *)liblinphone_tester_get_subscribe_content(), strlen(liblinphone_tester_get_subscribe_content())); lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",expires,content); @@ -1102,7 +1102,7 @@ static void test_list_subscribe (void) { linphone_content_set_type(content,"application"); linphone_content_set_subtype(content,"resource-lists+xml"); - linphone_content_set_buffer(content,subscribe_content,strlen(subscribe_content)); + linphone_content_set_buffer(content,(const uint8_t *)subscribe_content,strlen(subscribe_content)); lev=linphone_core_create_subscribe(marie->lc,list_name,"presence",60); diff --git a/tester/message_tester.c b/tester/message_tester.c index 0cd61f82a..98c7a1f83 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -833,7 +833,7 @@ void info_message_base(bool_t with_content) { LinphoneContent* ct=linphone_core_create_content(marie->lc); linphone_content_set_type(ct,"application"); linphone_content_set_subtype(ct,"somexml"); - linphone_content_set_buffer(ct,info_content,strlen(info_content)); + linphone_content_set_buffer(ct,(const uint8_t *)info_content,strlen(info_content)); linphone_info_message_set_content(info,ct); linphone_content_unref(ct); } diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 6c4445e6c..46fa2138e 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -249,17 +249,9 @@ class JavaTranslator(object): return 'char' elif _type.name == 'void': if isReturn: - if _type.isref and jni: - return 'jbyteArray' - if _type.isref: - return 'byte[]' return 'void' if jni: - if _type.isref and _type.isconst: - return 'jbyteArray' return 'jobject' - if _type.isref and _type.isconst: - return 'byte[]' return 'Object' return _type.name @@ -423,7 +415,7 @@ class JavaTranslator(object): methodDict['params_impl'] += '(' + argCType + ') ' + argname elif type(arg.type) is AbsApi.BaseType: - if (arg.type.name == 'integer' and arg.type.size is not None and arg.type.isref) or (arg.type.name == 'void' and arg.type.isref and arg.type.isconst): + if arg.type.name == 'integer' and arg.type.size is not None and arg.type.isref: methodDict['bytes'].append({'bytesargname': argname, 'bytesargtype' : self.translate_as_c_base_type(arg.type)}) methodDict['params_impl'] += 'c_' + argname elif arg.type.name == 'string': From ef94fd5090ca4e3fbdcb1edd3640205417151f35 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 13 Oct 2017 19:38:04 +0200 Subject: [PATCH 0568/2215] add helper class in java to access specific functions available only in Android SDK, such as retrieving DNS servers. Refactor wifi lock, multicast lock so that they use this new class. Manage the CPU lock required for call in the core, instead of app's LinphoneManager. --- coreapi/CMakeLists.txt | 3 + coreapi/android-helpers.cpp | 182 ++++++++++++++++++ coreapi/factory.c | 21 +- coreapi/linphonecall.c | 6 - coreapi/linphonecore.c | 57 ++---- coreapi/linphonecore_jni.cc | 51 +---- coreapi/platform-helpers.cpp | 49 +++++ coreapi/platform-helpers.h | 64 ++++++ coreapi/private.h | 30 ++- include/linphone/factory.h | 42 ++++ .../core/LinphoneCoreFactoryImpl.java | 6 +- .../org/linphone/core/LinphoneCoreImpl.java | 26 +-- .../core/util/AndroidPlatformHelper.java | 114 +++++++++++ 13 files changed, 518 insertions(+), 133 deletions(-) create mode 100644 coreapi/android-helpers.cpp create mode 100644 coreapi/platform-helpers.cpp create mode 100644 coreapi/platform-helpers.h create mode 100644 java/impl/org/linphone/core/util/AndroidPlatformHelper.java diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index f0a3bfdd6..11a8604fc 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -47,6 +47,7 @@ list(APPEND LINPHONE_PRIVATE_HEADER_FILES sqlite3_bctbx_vfs.h vcard_private.h xml2lpc.h + platform-helpers.h ) set(LINPHONE_SOURCE_FILES_C @@ -110,6 +111,8 @@ set(LINPHONE_SOURCE_FILES_C set(LINPHONE_SOURCE_FILES_CXX conference.cc tester_utils.cpp + platform-helpers.cpp + android-helpers.cpp ) set(LINPHONE_INCLUDE_DIRS ${LINPHONE_INCLUDE_DIRS}) if(ENABLE_JAVA_WRAPPER) diff --git a/coreapi/android-helpers.cpp b/coreapi/android-helpers.cpp new file mode 100644 index 000000000..bc1970a68 --- /dev/null +++ b/coreapi/android-helpers.cpp @@ -0,0 +1,182 @@ +/* +linphone +Copyright (C) 2017 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + + +#include "private.h" +#include "platform-helpers.h" +#include + + + +#ifdef __ANDROID__ + +namespace LinphonePrivate{ + +class AndroidPlatformHelpers : public PlatformHelpers{ +public: + AndroidPlatformHelpers(LinphoneCore *lc, void *system_context); + virtual void setDnsServers(); + virtual void acquireWifiLock(); + virtual void releaseWifiLock(); + virtual void acquireMcastLock(); + virtual void releaseMcastLock(); + virtual void acquireCpuLock(); + virtual void releaseCpuLock(); + ~AndroidPlatformHelpers(); +private: + int callVoidMethod(jmethodID id); + static jmethodID getMethodId(JNIEnv *env, jclass klass, const char *method, const char *signature); + jobject mJavaHelper; + jmethodID mWifiLockAcquireId; + jmethodID mWifiLockReleaseId; + jmethodID mMcastLockAcquireId; + jmethodID mMcastLockReleaseId; + jmethodID mCpuLockAcquireId; + jmethodID mCpuLockReleaseId; + jmethodID mGetDnsServersId; + jmethodID mGetPowerManagerId; + +}; + +jmethodID AndroidPlatformHelpers::getMethodId(JNIEnv *env, jclass klass, const char *method, const char *signature){ + jmethodID id = env->GetMethodID(klass, method, signature); + if (id == 0){ + ms_fatal("Could not find java method '%s %s'", method, signature); + } + return id; +} + +AndroidPlatformHelpers::AndroidPlatformHelpers(LinphoneCore *lc, void *system_context) : PlatformHelpers(lc) { + JNIEnv *env=ms_get_jni_env(); + jclass klass = env->FindClass("org/linphone/core/util/AndroidPlatformHelper"); + if (!klass){ + ms_fatal("Could not find java AndroidPlatformHelper class"); + return; + } + jmethodID ctor = env->GetMethodID(klass,"", "(Ljava/lang/Object;)V"); + mJavaHelper = env->NewObject(klass, ctor, (jobject)system_context); + if (!mJavaHelper){ + ms_error("Could not instanciate AndroidPlatformHelper object."); + return; + } + mJavaHelper = (jobject) env->NewGlobalRef(mJavaHelper); + + mWifiLockAcquireId = getMethodId(env, klass, "acquireWifiLock", "()V"); + mWifiLockReleaseId = getMethodId(env, klass, "releaseWifiLock", "()V"); + mMcastLockAcquireId = getMethodId(env, klass, "acquireMcastLock", "()V"); + mMcastLockReleaseId = getMethodId(env, klass, "releaseMcastLock", "()V"); + mCpuLockAcquireId = getMethodId(env, klass, "acquireCpuLock", "()V"); + mCpuLockReleaseId = getMethodId(env, klass, "releaseCpuLock", "()V"); + mGetDnsServersId = getMethodId(env, klass, "getDnsServers", "()[Ljava/lang/String;"); + mGetPowerManagerId = getMethodId(env, klass, "getPowerManager", "()Ljava/lang/Object;"); + + jobject pm = env->CallObjectMethod(mJavaHelper,mGetPowerManagerId); + belle_sip_wake_lock_init(env, pm); + + ms_message("AndroidPlatformHelpers is fully initialised"); +} + +AndroidPlatformHelpers::~AndroidPlatformHelpers(){ + if (mJavaHelper){ + JNIEnv *env = ms_get_jni_env(); + belle_sip_wake_lock_uninit(env); + env->DeleteGlobalRef(mJavaHelper); + mJavaHelper = NULL; + } +} + + +void AndroidPlatformHelpers::setDnsServers(){ + if (!mJavaHelper) return; + JNIEnv *env=ms_get_jni_env(); + if (env && mJavaHelper) { + jobjectArray jservers = (jobjectArray)env->CallObjectMethod(mJavaHelper,mGetDnsServersId); + bctbx_list_t *l = NULL; + if (env->ExceptionCheck()) { + env->ExceptionClear(); + ms_error("AndroidPlatformHelpers::setDnsServers() exception"); + return; + } + if (jservers != NULL){ + int count = env->GetArrayLength(jservers); + + for (int i=0; i < count; i++) { + jstring jserver = (jstring) env->GetObjectArrayElement(jservers, i); + const char *str = env->GetStringUTFChars(jserver, NULL); + if (str){ + l = bctbx_list_append(l, ms_strdup(str)); + env->ReleaseStringUTFChars(jserver, str); + } + } + } + linphone_core_set_dns_servers(mCore, l); + bctbx_list_free_with_data(l, ms_free); + } +} + +void AndroidPlatformHelpers::acquireWifiLock(){ + callVoidMethod(mWifiLockAcquireId); +} + +void AndroidPlatformHelpers::releaseWifiLock(){ + callVoidMethod(mWifiLockReleaseId); +} + +void AndroidPlatformHelpers::acquireMcastLock(){ + callVoidMethod(mMcastLockAcquireId); +} + +void AndroidPlatformHelpers::releaseMcastLock(){ + callVoidMethod(mMcastLockReleaseId); +} + +void AndroidPlatformHelpers::acquireCpuLock(){ + callVoidMethod(mCpuLockAcquireId); +} + +void AndroidPlatformHelpers::releaseCpuLock(){ + callVoidMethod(mCpuLockReleaseId); +} + + +int AndroidPlatformHelpers::callVoidMethod(jmethodID id) { + JNIEnv *env=ms_get_jni_env(); + if (env && mJavaHelper) { + env->CallVoidMethod(mJavaHelper,id); + if (env->ExceptionCheck()) { + env->ExceptionClear(); + return -1; + } else + return 0; + } else + return -1; +} + +PlatformHelpers *createAndroidPlatformHelpers(LinphoneCore *lc, void *system_context){ + return new AndroidPlatformHelpers(lc, system_context); +} + +}//end of namespace + + + + +#endif + diff --git a/coreapi/factory.c b/coreapi/factory.c index c85976ff5..80a0a42e7 100644 --- a/coreapi/factory.c +++ b/coreapi/factory.c @@ -32,7 +32,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define PACKAGE_DATA_DIR "." #endif -extern LinphoneCore *_linphone_core_new_with_config(LinphoneCoreCbs *cbs, struct _LpConfig *config, void *userdata); extern LinphoneAddress *_linphone_address_new(const char *addr); typedef belle_sip_object_t_vptr_t LinphoneFactory_vptr_t; @@ -149,16 +148,26 @@ void linphone_factory_clean(void){ } } -LinphoneCore *linphone_factory_create_core(const LinphoneFactory *factory, LinphoneCoreCbs *cbs, - const char *config_path, const char *factory_config_path) { +LinphoneCore *linphone_factory_create_core_2(const LinphoneFactory *factory, LinphoneCoreCbs *cbs, + const char *config_path, const char *factory_config_path, void *user_data, void *system_context) { + bctbx_init_logger(FALSE); LpConfig *config = lp_config_new_with_factory(config_path, factory_config_path); - LinphoneCore *lc = _linphone_core_new_with_config(cbs, config, NULL); + LinphoneCore *lc = _linphone_core_new_with_config(cbs, config, user_data, system_context); lp_config_unref(config); return lc; } +LinphoneCore *linphone_factory_create_core(const LinphoneFactory *factory, LinphoneCoreCbs *cbs, + const char *config_path, const char *factory_config_path){ + return linphone_factory_create_core_2(factory, cbs, config_path, factory_config_path, NULL, NULL); +} + LinphoneCore *linphone_factory_create_core_with_config(const LinphoneFactory *factory, LinphoneCoreCbs *cbs, LinphoneConfig *config) { - return _linphone_core_new_with_config(cbs, config, NULL); + return _linphone_core_new_with_config(cbs, config, NULL, NULL); +} + +LinphoneCore *linphone_factory_create_core_with_config_2(const LinphoneFactory *factory, LinphoneCoreCbs *cbs, LinphoneConfig *config, void *user_data, void *system_context) { + return _linphone_core_new_with_config(cbs, config, user_data, system_context); } LinphoneCoreCbs *linphone_factory_create_core_cbs(const LinphoneFactory *factory) { @@ -369,4 +378,4 @@ void linphone_factory_set_log_collection_path(LinphoneFactory *factory, const ch void linphone_factory_enable_log_collection(LinphoneFactory *factory, LinphoneLogCollectionState state) { linphone_core_enable_log_collection(state); -} \ No newline at end of file +} diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 9962d373a..a290202a0 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -120,9 +120,3 @@ const char* linphone_privacy_to_string(LinphonePrivacy privacy) { default: return "Unknown privacy mode"; } } - -void set_playback_gain_db(AudioStream *st, float gain){ - if (st->volrecv){ - ms_filter_call_method(st->volrecv,MS_VOLUME_SET_DB_GAIN,&gain); - }else ms_warning("Could not apply playback gain: gain control wasn't activated."); -} diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 2fb96205c..555d70537 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2191,6 +2191,7 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig lc->config=lp_config_ref(config); lc->data=userdata; lc->ringstream_autorelease=TRUE; + lc->platform_helper = new LinphonePrivate::StubbedPlatformHelpers(lc); linphone_task_list_init(&lc->hooks); @@ -2268,9 +2269,21 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig lc->group_chat_rooms = bctbx_mmap_cchar_new(); } -LinphoneCore *_linphone_core_new_with_config(LinphoneCoreCbs *cbs, struct _LpConfig *config, void *userdata) { +static void _linphone_core_set_platform_helpers(LinphoneCore *lc, LinphonePrivate::PlatformHelpers *ph){ + if (lc->platform_helper) delete getPlatformHelpers(lc); + lc->platform_helper = ph; +} + +static void _linphone_core_set_system_context(LinphoneCore *lc, void *system_context){ +#ifdef __ANDROID__ + _linphone_core_set_platform_helpers(lc, LinphonePrivate::createAndroidPlatformHelpers(lc, system_context)); +#endif +} + +LinphoneCore *_linphone_core_new_with_config(LinphoneCoreCbs *cbs, struct _LpConfig *config, void *userdata, void *system_context) { LinphoneCore *core = belle_sip_object_new(LinphoneCore); linphone_core_init(core, cbs, config, userdata); + _linphone_core_set_system_context(core, system_context); return core; } @@ -2280,7 +2293,7 @@ LinphoneCore *linphone_core_new_with_config(const LinphoneCoreVTable *vtable, st LinphoneCore *core = NULL; if (vtable != NULL) *local_vtable = *vtable; _linphone_core_cbs_set_v_table(cbs, local_vtable, TRUE); - core = _linphone_core_new_with_config(cbs, config, userdata); + core = _linphone_core_new_with_config(cbs, config, userdata, NULL); linphone_core_cbs_unref(cbs); return core; } @@ -6074,6 +6087,7 @@ static void linphone_core_uninit(LinphoneCore *lc) bctbx_list_free_with_data(lc->vtable_refs,(void (*)(void *))v_table_reference_destroy); ms_bandwidth_controller_destroy(lc->bw_controller); ms_factory_destroy(lc->factory); + if (lc->platform_helper) delete getPlatformHelpers(lc); bctbx_uninit_logger(); } @@ -6096,6 +6110,11 @@ static void set_sip_network_reachable(LinphoneCore* lc,bool_t is_sip_reachable, if (lc->sip_network_reachable==is_sip_reachable) return; // no change, ignore. lc->network_reachable_to_be_notified=TRUE; + + if (is_sip_reachable){ + getPlatformHelpers(lc)->setDnsServers(); + } + ms_message("SIP network reachability state is now [%s]",is_sip_reachable?"UP":"DOWN"); for(elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; @@ -6896,40 +6915,6 @@ const char * linphone_core_get_video_preset(const LinphoneCore *lc) { return lp_config_get_string(lc->config, "video", "preset", NULL); } -#ifdef __ANDROID__ -static int linphone_core_call_void_method(jobject obj, jmethodID id) { - JNIEnv *env=ms_get_jni_env(); - if (env && obj) { - env->CallVoidMethod(obj,id); - if (env->ExceptionCheck()) { - env->ExceptionClear(); - return -1; - } else - return 0; - } else - return -1; -} - -void linphone_core_wifi_lock_acquire(LinphoneCore *lc) { - if (linphone_core_call_void_method(lc->wifi_lock,lc->wifi_lock_acquire_id)) - ms_warning("No wifi lock configured or not usable for core [%p]",lc); -} - -void linphone_core_wifi_lock_release(LinphoneCore *lc) { - if (linphone_core_call_void_method(lc->wifi_lock,lc->wifi_lock_release_id)) - ms_warning("No wifi lock configured or not usable for core [%p]",lc); -} - -void linphone_core_multicast_lock_acquire(LinphoneCore *lc) { - if (linphone_core_call_void_method(lc->multicast_lock,lc->multicast_lock_acquire_id)) - ms_warning("No multicast lock configured or not usable for core [%p]",lc); -} - -void linphone_core_multicast_lock_release(LinphoneCore *lc) { - if (linphone_core_call_void_method(lc->multicast_lock,lc->multicast_lock_release_id)) - ms_warning("No wifi lock configured or not usable for core [%p]",lc); -} -#endif LINPHONE_PUBLIC const char *linphone_core_log_collection_upload_state_to_string(const LinphoneCoreLogCollectionUploadState lcus) { diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 27002061b..8a3687f07 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1635,7 +1635,7 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* ,jobject jlistener ,jstring juserConfig ,jstring jfactoryConfig - ,jobject juserdata){ + ,jobject juserdata, jobject context){ const char* userConfig = GetStringUTFChars(env, juserConfig); const char* factoryConfig = GetStringUTFChars(env, jfactoryConfig); @@ -1645,11 +1645,12 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* LinphoneCoreVTable *vTable = linphone_core_v_table_new(); LinphoneCoreData* ldata = new LinphoneCoreData(env, thiz, vTable, jlistener, ljb); linphone_core_v_table_set_user_data(vTable, ldata); - + LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get()); + _linphone_core_cbs_set_v_table(cbs, vTable, TRUE); jobject core = env->NewGlobalRef(thiz); ljb->setCore(core); - LinphoneCore *lc = linphone_core_new(vTable, userConfig, factoryConfig, ljb); + LinphoneCore *lc = linphone_factory_create_core_2(linphone_factory_get(), cbs, userConfig, factoryConfig, ljb, context); jlong nativePtr = (jlong)lc; ReleaseStringUTFChars(env, juserConfig, userConfig); @@ -1661,18 +1662,8 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_delete(JNIEnv* env, jobj LinphoneCore *lc=(LinphoneCore*)native_ptr; LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc); - jobject multicast_lock = lc->multicast_lock; - jobject multicast_lock_class = lc->multicast_lock_class; - jobject wifi_lock = lc->wifi_lock; - jobject wifi_lock_class = lc->wifi_lock_class; - linphone_core_destroy(lc); - if (wifi_lock) env->DeleteGlobalRef(wifi_lock); - if (wifi_lock_class) env->DeleteGlobalRef(wifi_lock_class); - if (multicast_lock) env->DeleteGlobalRef(multicast_lock); - if (multicast_lock_class) env->DeleteGlobalRef(multicast_lock_class); - if (ljb) { jobject core = ljb->getCore(); if (core) { @@ -5949,43 +5940,9 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setAndroidPowerManager(J /*released in Java_org_linphone_core_LinphoneCoreImpl_delete*/ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setAndroidWifiLock(JNIEnv *env, jobject thiz, jlong ptr, jobject wifi_lock) { -#ifdef __ANDROID__ - LinphoneCore *lc=(LinphoneCore*)ptr; - if (lc->wifi_lock) { - env->DeleteGlobalRef(lc->wifi_lock); - env->DeleteGlobalRef(lc->wifi_lock_class); - } - if (wifi_lock != NULL) { - lc->wifi_lock=env->NewGlobalRef(wifi_lock); - lc->wifi_lock_class = env->FindClass("android/net/wifi/WifiManager$WifiLock"); - lc->wifi_lock_class = (jclass)env->NewGlobalRef(lc->wifi_lock_class); /*to make sure methodid are preserved*/ - lc->wifi_lock_acquire_id = env->GetMethodID(lc->wifi_lock_class, "acquire", "()V"); - lc->wifi_lock_release_id = env->GetMethodID(lc->wifi_lock_class, "release", "()V"); - } else { - lc->wifi_lock=NULL; - lc->wifi_lock_class=NULL; - } -#endif } /*released in Java_org_linphone_core_LinphoneCoreImpl_delete*/ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setAndroidMulticastLock(JNIEnv *env, jobject thiz, jlong ptr, jobject multicast_lock) { -#ifdef __ANDROID__ - LinphoneCore *lc=(LinphoneCore*)ptr; - if (lc->multicast_lock) { - env->DeleteGlobalRef(lc->multicast_lock); - env->DeleteGlobalRef(lc->multicast_lock_class); - } - if (multicast_lock != NULL) { - lc->multicast_lock=env->NewGlobalRef(multicast_lock); - lc->multicast_lock_class = env->FindClass("android/net/wifi/WifiManager$MulticastLock"); - lc->multicast_lock_class = (jclass)env->NewGlobalRef(lc->multicast_lock_class);/*to make sure methodid are preserved*/ - lc->multicast_lock_acquire_id = env->GetMethodID(lc->multicast_lock_class, "acquire", "()V"); - lc->multicast_lock_release_id = env->GetMethodID(lc->multicast_lock_class, "release", "()V"); - } else { - lc->multicast_lock=NULL; - lc->multicast_lock_class=NULL; - } -#endif } extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getAudioDscp(JNIEnv* env,jobject thiz,jlong ptr){ diff --git a/coreapi/platform-helpers.cpp b/coreapi/platform-helpers.cpp new file mode 100644 index 000000000..05bbc00e6 --- /dev/null +++ b/coreapi/platform-helpers.cpp @@ -0,0 +1,49 @@ +/* +linphone +Copyright (C) 2017 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "private.h" + + +namespace LinphonePrivate{ + +PlatformHelpers::~PlatformHelpers(){ +} + +StubbedPlatformHelpers::StubbedPlatformHelpers(LinphoneCore *lc) : PlatformHelpers(lc){ +} + +void StubbedPlatformHelpers::setDnsServers(){ +} +void StubbedPlatformHelpers::acquireWifiLock(){ +} +void StubbedPlatformHelpers::releaseWifiLock(){ +} +void StubbedPlatformHelpers::acquireMcastLock(){ +} +void StubbedPlatformHelpers::releaseMcastLock(){ +} +void StubbedPlatformHelpers::acquireCpuLock(){ +} +void StubbedPlatformHelpers::releaseCpuLock(){ +} + +StubbedPlatformHelpers::~StubbedPlatformHelpers(){ +} + +} \ No newline at end of file diff --git a/coreapi/platform-helpers.h b/coreapi/platform-helpers.h new file mode 100644 index 000000000..8d4b6acf4 --- /dev/null +++ b/coreapi/platform-helpers.h @@ -0,0 +1,64 @@ +/* +linphone +Copyright (C) 2017 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef platform_helpers_h +#define platform_helpers_h + + +namespace LinphonePrivate{ + +/** + * This interface aims at abstracting some features offered by the platform, most often mobile platforms. + * A per platform implementation is to be made to implement these features, if available on the platform + */ +class PlatformHelpers{ + public: + //This method shall retrieve DNS server list from the platform and assign it to the core. + virtual void setDnsServers() = 0; + virtual void acquireWifiLock() = 0; + virtual void releaseWifiLock() = 0; + virtual void acquireMcastLock() = 0; + virtual void releaseMcastLock() = 0; + virtual void acquireCpuLock() = 0; + virtual void releaseCpuLock() = 0; + virtual ~PlatformHelpers(); + protected: + PlatformHelpers(LinphoneCore *lc) : mCore(lc){ + } + LinphoneCore *mCore; +}; + +class StubbedPlatformHelpers : public PlatformHelpers{ +public: + StubbedPlatformHelpers(LinphoneCore *lc); + virtual void setDnsServers(); + virtual void acquireWifiLock(); + virtual void releaseWifiLock(); + virtual void acquireMcastLock(); + virtual void releaseMcastLock(); + virtual void acquireCpuLock(); + virtual void releaseCpuLock(); + virtual ~StubbedPlatformHelpers(); +}; + +PlatformHelpers *createAndroidPlatformHelpers(LinphoneCore *lc, void *system_context); + +}//end of namespace + +#endif diff --git a/coreapi/private.h b/coreapi/private.h index eca250923..4cf7346a0 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -31,6 +31,7 @@ #include "linphone/tunnel.h" #include "linphone/core_utils.h" #include "linphone/conference.h" + #include "address/address.h" #include "c-wrapper/internal/c-sal.h" #include "core/core.h" @@ -39,6 +40,11 @@ #include "sal/message-op.h" #include "sal/presence-op.h" #include "sal/register-op.h" + +#ifdef __cplusplus +#include "platform-helpers.h" +#endif + #include "linphone/sipsetup.h" #include "quality_reporting.h" #include "linphone/ringtoneplayer.h" @@ -815,6 +821,8 @@ struct _LinphoneCore // For migration purposes LinphonePrivate::Core cppCore; + void *platform_helper; /*is a LinphonePrivate::PlatformHelpers but cannot be used as is because private.h is compiled as C in testers.*/ + LinphoneGlobalState state; struct _LpConfig *config; MSList *default_audio_codecs; @@ -920,16 +928,6 @@ struct _LinphoneCore LinphoneContent *log_collection_upload_information; LinphoneCoreCbs *current_cbs; // the latest LinphoneCoreCbs object to call a callback, see linphone_core_get_current_cbs() LinphoneRingtonePlayer *ringtoneplayer; -#ifdef __ANDROID__ - jobject wifi_lock; - jclass wifi_lock_class; - jmethodID wifi_lock_acquire_id; - jmethodID wifi_lock_release_id; - jobject multicast_lock; - jclass multicast_lock_class; - jmethodID multicast_lock_acquire_id; - jmethodID multicast_lock_release_id; -#endif LinphoneVcardContext *vcard_context; /*for tests only*/ @@ -945,6 +943,10 @@ struct _LinphoneCore MSBandwidthController *bw_controller; }; +#ifdef __cplusplus +#define getPlatformHelpers(lc) static_cast(lc->platform_helper) +#endif + struct _LinphoneEvent{ belle_sip_object_t base; @@ -1078,6 +1080,8 @@ LINPHONE_PUBLIC int linphone_core_get_call_history_size(LinphoneCore *lc); int linphone_core_get_edge_bw(LinphoneCore *lc); int linphone_core_get_edge_ptime(LinphoneCore *lc); +LinphoneCore *_linphone_core_new_with_config(LinphoneCoreCbs *cbs, struct _LpConfig *config, void *userdata, void *system_context); + int linphone_upnp_init(LinphoneCore *lc); void linphone_upnp_destroy(LinphoneCore *lc); @@ -1501,12 +1505,6 @@ SalStreamDir sal_dir_from_call_params_dir(LinphoneMediaDirection cpdir); */ void ** linphone_content_get_cryptoContext_address(LinphoneContent *content); -#ifdef __ANDROID__ -void linphone_core_wifi_lock_acquire(LinphoneCore *lc); -void linphone_core_wifi_lock_release(LinphoneCore *lc); -void linphone_core_multicast_lock_acquire(LinphoneCore *lc); -void linphone_core_multicast_lock_release(LinphoneCore *lc); -#endif struct _VTableReference{ LinphoneCoreCbs *cbs; diff --git a/include/linphone/factory.h b/include/linphone/factory.h index 26a5aa29b..7db488fbe 100644 --- a/include/linphone/factory.h +++ b/include/linphone/factory.h @@ -66,6 +66,32 @@ LINPHONE_PUBLIC void linphone_factory_clean(void); LINPHONE_PUBLIC LinphoneCore *linphone_factory_create_core(const LinphoneFactory *factory, LinphoneCoreCbs *cbs, const char *config_path, const char *factory_config_path); + +/** + * Instanciate a #LinphoneCore object. + * + * The LinphoneCore object is the primary handle for doing all phone actions. + * It should be unique within your application. + * @param factory The #LinphoneFactory singleton. + * @param cbs a #LinphoneCoreCbs object holding your application callbacks. A reference + * will be taken on it until the destruciton of the core or the unregistration + * with linphone_core_remove_cbs(). + * @param config_path a path to a config file. If it does not exists it will be created. + * The config file is used to store all settings, call logs, friends, proxies... so that all these settings + * become persistent over the life of the LinphoneCore object. + * It is allowed to set a NULL config file. In that case LinphoneCore will not store any settings. + * @param factory_config_path a path to a read-only config file that can be used to + * to store hard-coded preference such as proxy settings or internal preferences. + * The settings in this factory file always override the one in the normal config file. + * It is OPTIONAL, use NULL if unneeded. + * @param user_data an application pointer associated with the returned core. + * @param system_context a pointer to a system object required by the core to operate. Currently it is required to pass an android Context on android, pass NULL on other platforms. + * @see linphone_core_new_with_config + */ +LINPHONE_PUBLIC LinphoneCore *linphone_factory_create_core_2(const LinphoneFactory *factory, LinphoneCoreCbs *cbs, + const char *config_path, const char *factory_config_path, void *user_data, void *system_context); + + /** * Instantiates a LinphoneCore object with a given LpConfig. * @@ -80,6 +106,22 @@ LINPHONE_PUBLIC LinphoneCore *linphone_factory_create_core(const LinphoneFactory */ LINPHONE_PUBLIC LinphoneCore *linphone_factory_create_core_with_config(const LinphoneFactory *factory, LinphoneCoreCbs *cbs, LinphoneConfig *config); +/** + * Instantiates a LinphoneCore object with a given LpConfig. + * + * @param factory The #LinphoneFactory singleton. + * The LinphoneCore object is the primary handle for doing all phone actions. + * It should be unique within your application. + * @param cbs a #LinphoneCoreCbs object holding your application callbacks. A reference + * will be taken on it until the destruciton of the core or the unregistration + * with linphone_core_remove_cbs(). + * @param config a pointer to an LpConfig object holding the configuration of the LinphoneCore to be instantiated. + * @param user_data an application pointer associated with the returned core. + * @param system_context a pointer to a system object required by the core to operate. Currently it is required to pass an android Context on android, pass NULL on other platforms. + * @see linphone_core_new + */ +LINPHONE_PUBLIC LinphoneCore *linphone_factory_create_core_with_config_2(const LinphoneFactory *factory, LinphoneCoreCbs *cbs, LinphoneConfig *config, void *user_data, void *system_context); + /** * Instanciate a #LinphoneCoreCbs object. * @return a new #LinphoneCoreCbs. diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 915e6e0c0..ba951efb4 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -107,9 +107,8 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { MediastreamerAndroidContext.setContext(context); File user = userConfig == null ? null : new File(userConfig); File factory = factoryConfig == null ? null : new File(factoryConfig); - LinphoneCore lc = new LinphoneCoreImpl(listener, user, factory, userdata); + LinphoneCore lc = new LinphoneCoreImpl(listener, user, factory, userdata, context); lc.enableDownloadOpenH264(openh264DownloadEnabled); - if (context != null) lc.setContext(context); return lc; } catch (IOException e) { throw new LinphoneCoreException("Cannot create LinphoneCore",e); @@ -123,9 +122,8 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { boolean openh264DownloadEnabled = false; if (context != null) openh264DownloadEnabled = loadingDownloadedOpenH264(fcontext); MediastreamerAndroidContext.setContext(context); - LinphoneCore lc = new LinphoneCoreImpl(listener); + LinphoneCore lc = new LinphoneCoreImpl(listener, context); lc.enableDownloadOpenH264(openh264DownloadEnabled); - if (context != null) lc.setContext(context); return lc; } catch (IOException e) { throw new LinphoneCoreException("Cannot create LinphoneCore",e); diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 671fb1fcc..cd076e837 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -47,7 +47,7 @@ class LinphoneCoreImpl implements LinphoneCore { private AudioManager mAudioManager = null; private boolean openh264DownloadEnabled = false; private boolean mSpeakerEnabled = false; - private native long newLinphoneCore(LinphoneCoreListener listener,String userConfig,String factoryConfig,Object userdata); + private native long newLinphoneCore(LinphoneCoreListener listener,String userConfig,String factoryConfig,Object userdata, Object context); private native void iterate(long nativePtr); private native LinphoneProxyConfig getDefaultProxyConfig(long nativePtr); @@ -196,15 +196,17 @@ class LinphoneCoreImpl implements LinphoneCore { private native Object createFriendWithAddress(long nativePtr, String address); private native int getIncomingTimeout(long nativePtr); - LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig, File factoryConfig, Object userdata) throws IOException { + LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig, File factoryConfig, Object userdata, Object context) throws IOException { mListener = listener; String user = userConfig == null ? null : userConfig.getCanonicalPath(); String factory = factoryConfig == null ? null : factoryConfig.getCanonicalPath(); - nativePtr = newLinphoneCore(listener, user, factory, userdata); + nativePtr = newLinphoneCore(listener, user, factory, userdata, context); + setContext(context); } - LinphoneCoreImpl(LinphoneCoreListener listener) throws IOException { + LinphoneCoreImpl(LinphoneCoreListener listener, Object context) throws IOException { mListener = listener; - nativePtr = newLinphoneCore(listener,null,null,null); + nativePtr = newLinphoneCore(listener,null,null,null, context); + setContext(context); } protected void finalize() throws Throwable { @@ -223,19 +225,7 @@ class LinphoneCoreImpl implements LinphoneCore { ApplicationInfo info = mContext.getApplicationInfo(); reloadMsPlugins(info.nativeLibraryDir); mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); - setAndroidPowerManager(mContext.getSystemService(Context.POWER_SERVICE)); - if (Version.sdkAboveOrEqual(Version.API12_HONEYCOMB_MR1_31X)) { - WifiManager wifiManager=(WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); - WifiLock lock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "linphonecore ["+ nativePtr+"] wifi-lock"); - lock.setReferenceCounted(true); - setAndroidWifiLock(nativePtr,lock); - } - if (Version.sdkAboveOrEqual(Version.API14_ICE_CREAM_SANDWICH_40)) { - WifiManager wifiManager=(WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); - MulticastLock lock = wifiManager.createMulticastLock("linphonecore ["+ nativePtr+"] multicast-lock"); - lock.setReferenceCounted(true); - setAndroidMulticastLock(nativePtr, lock); - } + } public Context getContext() { diff --git a/java/impl/org/linphone/core/util/AndroidPlatformHelper.java b/java/impl/org/linphone/core/util/AndroidPlatformHelper.java new file mode 100644 index 000000000..aeb44e15b --- /dev/null +++ b/java/impl/org/linphone/core/util/AndroidPlatformHelper.java @@ -0,0 +1,114 @@ +/* +AndroidPlatformHelper.java +Copyright (C) 2017 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +package org.linphone.core.util; + +import org.linphone.mediastream.Log; + +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.MulticastLock; +import android.net.wifi.WifiManager.WifiLock; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkInfo; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; + +import java.net.InetAddress; +import java.util.List; +import android.os.Build; + +/** + * This class is instanciated directly by the linphone library in order to access specific features only accessible in java. +**/ + +public class AndroidPlatformHelper{ + private WifiManager.WifiLock mWifiLock; + private WifiManager.MulticastLock mMcastLock; + private ConnectivityManager mConnectivityManager; + private PowerManager mPowerManager; + private WakeLock mWakeLock; + + public AndroidPlatformHelper(Object ctx_obj){ + Context ctx = (Context) ctx_obj; + WifiManager wifiMgr = ctx.getSystemService(WifiManager.class); + mPowerManager = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE); + mConnectivityManager = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE); + + mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidPlatformHelper"); + mWakeLock.setReferenceCounted(true); + mMcastLock = wifiMgr.createMulticastLock("AndroidPlatformHelper"); + mMcastLock.setReferenceCounted(true); + mWifiLock = wifiMgr.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "AndroidPlatformHelper"); + mWifiLock.setReferenceCounted(true); + } + + public Object getPowerManager(){ + return mPowerManager; + } + + public String[] getDnsServers() { + if (mConnectivityManager == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.M) + return null; + + if (mConnectivityManager.getActiveNetwork() == null + || mConnectivityManager.getLinkProperties(mConnectivityManager.getActiveNetwork()) == null) + return null; + + int i = 0; + List inetServers = null; + inetServers = mConnectivityManager.getLinkProperties(mConnectivityManager.getActiveNetwork()).getDnsServers(); + + String[] servers = new String[inetServers.size()]; + + for (InetAddress address : inetServers) { + servers[i++] = address.getHostAddress(); + } + Log.i("getDnsServers() returning"); + return servers; + } + public void acquireWifiLock(){ + Log.i("acquireWifiLock()"); + mWifiLock.acquire(); + } + public void releaseWifiLock(){ + Log.i("releaseWifiLock()"); + mWifiLock.release(); + } + public void acquireMcastLock(){ + Log.i("acquireMcastLock()"); + mMcastLock.acquire(); + } + public void releaseMcastLock(){ + Log.i("releaseMcastLock()"); + mMcastLock.release(); + } + public void acquireCpuLock(){ + Log.i("acquireCpuLock()"); + mWakeLock.acquire(); + } + public void releaseCpuLock(){ + Log.i("releaseCpuLock()"); + mWakeLock.release(); + } +}; + + From 47dab4f437a4b5fd73792a7bbd45615e302d39b4 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 19 Oct 2017 11:07:35 +0200 Subject: [PATCH 0569/2215] only include jni.h for android --- coreapi/android-helpers.cpp | 15 ++++++--------- src/conference/session/call-session.cpp | 16 ++++++---------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/coreapi/android-helpers.cpp b/coreapi/android-helpers.cpp index bc1970a68..bfbacac7e 100644 --- a/coreapi/android-helpers.cpp +++ b/coreapi/android-helpers.cpp @@ -17,16 +17,13 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - - #include "private.h" #include "platform-helpers.h" -#include - - #ifdef __ANDROID__ +#include + namespace LinphonePrivate{ class AndroidPlatformHelpers : public PlatformHelpers{ @@ -52,7 +49,7 @@ private: jmethodID mCpuLockReleaseId; jmethodID mGetDnsServersId; jmethodID mGetPowerManagerId; - + }; jmethodID AndroidPlatformHelpers::getMethodId(JNIEnv *env, jclass klass, const char *method, const char *signature){ @@ -77,7 +74,7 @@ AndroidPlatformHelpers::AndroidPlatformHelpers(LinphoneCore *lc, void *system_co return; } mJavaHelper = (jobject) env->NewGlobalRef(mJavaHelper); - + mWifiLockAcquireId = getMethodId(env, klass, "acquireWifiLock", "()V"); mWifiLockReleaseId = getMethodId(env, klass, "releaseWifiLock", "()V"); mMcastLockAcquireId = getMethodId(env, klass, "acquireMcastLock", "()V"); @@ -86,10 +83,10 @@ AndroidPlatformHelpers::AndroidPlatformHelpers(LinphoneCore *lc, void *system_co mCpuLockReleaseId = getMethodId(env, klass, "releaseCpuLock", "()V"); mGetDnsServersId = getMethodId(env, klass, "getDnsServers", "()[Ljava/lang/String;"); mGetPowerManagerId = getMethodId(env, klass, "getPowerManager", "()Ljava/lang/Object;"); - + jobject pm = env->CallObjectMethod(mJavaHelper,mGetPowerManagerId); belle_sip_wake_lock_init(env, pm); - + ms_message("AndroidPlatformHelpers is fully initialised"); } diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index f56b7d84b..de2e583ee 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -108,11 +108,9 @@ void CallSessionPrivate::setState(LinphoneCallState newState, const string &mess switch (newState) { case LinphoneCallOutgoingInit: case LinphoneCallIncomingReceived: -#ifdef __ANDROID__ - lInfo() << "CallSession [" << q << "] acquires both wifi and multicast lock"; - linphone_core_wifi_lock_acquire(core); - linphone_core_multicast_lock_acquire(core); /* Does no affect battery more than regular rtp traffic */ -#endif + getPlatformHelpers(core)->acquireWifiLock(); + getPlatformHelpers(core)->acquireMcastLock(); + getPlatformHelpers(core)->acquireCpuLock(); break; case LinphoneCallEnd: case LinphoneCallError: @@ -152,11 +150,9 @@ void CallSessionPrivate::setState(LinphoneCallState newState, const string &mess log->connected_date_time = ms_time(nullptr); break; case LinphoneCallReleased: -#ifdef __ANDROID__ - lInfo() << "CallSession [" << q << "] releases wifi/multicast lock"; - linphone_core_wifi_lock_release(core); - linphone_core_multicast_lock_release(core); -#endif + getPlatformHelpers(core)->acquireWifiLock(); + getPlatformHelpers(core)->acquireMcastLock(); + getPlatformHelpers(core)->acquireCpuLock(); break; default: break; From a782ee90982f1846457c3cb506a414437fb0a577 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 19 Oct 2017 11:14:52 +0200 Subject: [PATCH 0570/2215] put back removed symbol --- coreapi/linphonecall.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index a290202a0..9962d373a 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -120,3 +120,9 @@ const char* linphone_privacy_to_string(LinphonePrivacy privacy) { default: return "Unknown privacy mode"; } } + +void set_playback_gain_db(AudioStream *st, float gain){ + if (st->volrecv){ + ms_filter_call_method(st->volrecv,MS_VOLUME_SET_DB_GAIN,&gain); + }else ms_warning("Could not apply playback gain: gain control wasn't activated."); +} From 95ead0586a79b4f6aba119a482a70a8900b4a857 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 19 Oct 2017 11:32:16 +0200 Subject: [PATCH 0571/2215] Fixed build issues with platform helper --- coreapi/linphonecore.c | 8 ++++++-- coreapi/platform-helpers.h | 14 +++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 555d70537..11ad32dbc 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2269,16 +2269,20 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig lc->group_chat_rooms = bctbx_mmap_cchar_new(); } +#ifdef __ANDROID__ static void _linphone_core_set_platform_helpers(LinphoneCore *lc, LinphonePrivate::PlatformHelpers *ph){ if (lc->platform_helper) delete getPlatformHelpers(lc); lc->platform_helper = ph; } static void _linphone_core_set_system_context(LinphoneCore *lc, void *system_context){ -#ifdef __ANDROID__ _linphone_core_set_platform_helpers(lc, LinphonePrivate::createAndroidPlatformHelpers(lc, system_context)); -#endif } +#else +static void _linphone_core_set_system_context(LinphoneCore *lc, void *system_context){ + +} +#endif LinphoneCore *_linphone_core_new_with_config(LinphoneCoreCbs *cbs, struct _LpConfig *config, void *userdata, void *system_context) { LinphoneCore *core = belle_sip_object_new(LinphoneCore); diff --git a/coreapi/platform-helpers.h b/coreapi/platform-helpers.h index 8d4b6acf4..b97c0fa2b 100644 --- a/coreapi/platform-helpers.h +++ b/coreapi/platform-helpers.h @@ -47,13 +47,13 @@ class PlatformHelpers{ class StubbedPlatformHelpers : public PlatformHelpers{ public: StubbedPlatformHelpers(LinphoneCore *lc); - virtual void setDnsServers(); - virtual void acquireWifiLock(); - virtual void releaseWifiLock(); - virtual void acquireMcastLock(); - virtual void releaseMcastLock(); - virtual void acquireCpuLock(); - virtual void releaseCpuLock(); + void setDnsServers() override; + void acquireWifiLock() override; + void releaseWifiLock() override; + void acquireMcastLock() override; + void releaseMcastLock() override; + void acquireCpuLock() override; + void releaseCpuLock() override; virtual ~StubbedPlatformHelpers(); }; From f545d1d9551799ca6a8cb6f0e115a8ca4123e45d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 19 Oct 2017 11:36:30 +0200 Subject: [PATCH 0572/2215] Use create_core_2 in Java wrapper --- wrappers/java/java_class.mustache | 8 ++++---- wrappers/java/jni.mustache | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 9dc920ec5..d9e17a999 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -97,7 +97,7 @@ public {{#isLinphoneFactory}}abstract class{{/isLinphoneFactory}}{{#isNotLinphon abstract public void setDebugMode(boolean enable, String tag); - abstract public Core createCore(CoreListener listener, String configPath, String factoryConfigPath); + abstract public Core createCore(CoreListener listener, String configPath, String factoryConfigPath, Context context); {{/isLinphoneFactory}} {{#isLinphoneCore}} @@ -171,10 +171,10 @@ class {{classImplName}} {{#isLinphoneFactory}}extends{{/isLinphoneFactory}}{{#is @Override public native void setDebugMode(boolean enable, String tag); - private native Core createCore(Factory factory, CoreListener listener, String configPath, String factoryConfigPath); + private native Core createCore(Factory factory, CoreListener listener, String configPath, String factoryConfigPath, Context context); @Override - public Core createCore(CoreListener listener, String configPath, String factoryConfigPath) { - return createCore(this, listener, configPath, factoryConfigPath); + public Core createCore(CoreListener listener, String configPath, String factoryConfigPath, Context context) { + return createCore(this, listener, configPath, factoryConfigPath, context); } {{/isLinphoneFactory}} diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index 8da4789f0..044e00fe4 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -363,7 +363,7 @@ jobject Java_{{jni_package}}CoreImpl_getMediastreamerFactory(JNIEnv *env, jobjec return env->NewObject(ljb->ms_factory_class, ljb->ms_factory_class_constructor, (jlong)factory); } -jobject Java_{{jni_package}}FactoryImpl_createCore(JNIEnv *env, jobject thiz, jobject jfactory, jobject jlistener, jstring jconfig_path, jstring jfactory_config_path) { +jobject Java_{{jni_package}}FactoryImpl_createCore(JNIEnv *env, jobject thiz, jobject jfactory, jobject jlistener, jstring jconfig_path, jstring jfactory_config_path, jobject jcontext) { LinphoneFactory *cptr = linphone_factory_get(); SetObjectNativePtr(env, jfactory, (jlong)cptr); // Set the C factory ptr as Factory.nativePtr for next factory calls @@ -409,7 +409,7 @@ jobject Java_{{jni_package}}FactoryImpl_createCore(JNIEnv *env, jobject thiz, jo linphone_core_cbs_set_log_collection_upload_state_changed(cbs, linphone_core_on_log_collection_upload_state_changed); linphone_core_cbs_set_dtmf_received(cbs, linphone_core_on_dtmf_received); - core = linphone_factory_create_core(linphone_factory_get(), cbs, config_path, factory_config_path); + core = linphone_factory_create_core_2(linphone_factory_get(), cbs, config_path, factory_config_path, NULL, (void *)jcontext); ReleaseStringUTFChars(env, jconfig_path, config_path); ReleaseStringUTFChars(env, jfactory_config_path, factory_config_path); From 8c1b1a176194c774fe2d1dd5822c06b7098b5a0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Tue, 17 Oct 2017 11:45:52 +0200 Subject: [PATCH 0573/2215] [Abstract API] Blacklists linphone_factory_create_core_2() and linphone_factory_cerate_core_with_config_2() while parsing This must be done since these functions must be manually wrapped for each targeted language. --- tools/abstractapi.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/abstractapi.py b/tools/abstractapi.py index d7010dbb0..51efb55bd 100644 --- a/tools/abstractapi.py +++ b/tools/abstractapi.py @@ -452,9 +452,11 @@ class CParser(object): self.regexFixedSizeInteger = '^(u?)int(\d?\d)_t$' self.methodBl = ['ref', 'unref', 'new', 'destroy', 'getCurrentCallbacks', 'setUserData', 'getUserData'] self.functionBl = [ - 'linphone_factory_create_core', # manualy wrapped - 'linphone_factory_create_core_with_config', # manualy wrapped - 'linphone_vcard_get_belcard'] # manualy wrapped + 'linphone_factory_create_core', # manually wrapped + 'linphone_factory_create_core_2', # manually wrapped + 'linphone_factory_create_core_with_config', # manually wrapped + 'linphone_factory_create_core_with_config_2', # manually wrapped + 'linphone_vcard_get_belcard'] # manually wrapped self.classBl = ['LpConfig'] # temporarly blacklisted for bl in classBlAppend: From 8a421e9c72d433026f605e462ff1f74c1fd9e12e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 19 Oct 2017 11:45:01 +0200 Subject: [PATCH 0574/2215] Forgot to move AndroidPlatfromHelper class --- .../classes/tools/AndroidPlatformHelper.java | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 wrappers/java/classes/tools/AndroidPlatformHelper.java diff --git a/wrappers/java/classes/tools/AndroidPlatformHelper.java b/wrappers/java/classes/tools/AndroidPlatformHelper.java new file mode 100644 index 000000000..92d4ea04f --- /dev/null +++ b/wrappers/java/classes/tools/AndroidPlatformHelper.java @@ -0,0 +1,114 @@ +/* +AndroidPlatformHelper.java +Copyright (C) 2017 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +package org.linphone.core.tools; + +import org.linphone.mediastream.Log; + +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.MulticastLock; +import android.net.wifi.WifiManager.WifiLock; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkInfo; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; + +import java.net.InetAddress; +import java.util.List; +import android.os.Build; + +/** + * This class is instanciated directly by the linphone library in order to access specific features only accessible in java. +**/ + +public class AndroidPlatformHelper{ + private WifiManager.WifiLock mWifiLock; + private WifiManager.MulticastLock mMcastLock; + private ConnectivityManager mConnectivityManager; + private PowerManager mPowerManager; + private WakeLock mWakeLock; + + public AndroidPlatformHelper(Object ctx_obj){ + Context ctx = (Context) ctx_obj; + WifiManager wifiMgr = ctx.getSystemService(WifiManager.class); + mPowerManager = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE); + mConnectivityManager = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE); + + mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidPlatformHelper"); + mWakeLock.setReferenceCounted(true); + mMcastLock = wifiMgr.createMulticastLock("AndroidPlatformHelper"); + mMcastLock.setReferenceCounted(true); + mWifiLock = wifiMgr.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "AndroidPlatformHelper"); + mWifiLock.setReferenceCounted(true); + } + + public Object getPowerManager(){ + return mPowerManager; + } + + public String[] getDnsServers() { + if (mConnectivityManager == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.M) + return null; + + if (mConnectivityManager.getActiveNetwork() == null + || mConnectivityManager.getLinkProperties(mConnectivityManager.getActiveNetwork()) == null) + return null; + + int i = 0; + List inetServers = null; + inetServers = mConnectivityManager.getLinkProperties(mConnectivityManager.getActiveNetwork()).getDnsServers(); + + String[] servers = new String[inetServers.size()]; + + for (InetAddress address : inetServers) { + servers[i++] = address.getHostAddress(); + } + Log.i("getDnsServers() returning"); + return servers; + } + public void acquireWifiLock(){ + Log.i("acquireWifiLock()"); + mWifiLock.acquire(); + } + public void releaseWifiLock(){ + Log.i("releaseWifiLock()"); + mWifiLock.release(); + } + public void acquireMcastLock(){ + Log.i("acquireMcastLock()"); + mMcastLock.acquire(); + } + public void releaseMcastLock(){ + Log.i("releaseMcastLock()"); + mMcastLock.release(); + } + public void acquireCpuLock(){ + Log.i("acquireCpuLock()"); + mWakeLock.acquire(); + } + public void releaseCpuLock(){ + Log.i("releaseCpuLock()"); + mWakeLock.release(); + } +}; + + From a44cbae88d82d5f26e5ab11a0361fdcd61630492 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 19 Oct 2017 11:50:19 +0200 Subject: [PATCH 0575/2215] Changed jni prefix of AndroidHelper class --- coreapi/android-helpers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/android-helpers.cpp b/coreapi/android-helpers.cpp index bfbacac7e..7b4e494ff 100644 --- a/coreapi/android-helpers.cpp +++ b/coreapi/android-helpers.cpp @@ -62,7 +62,7 @@ jmethodID AndroidPlatformHelpers::getMethodId(JNIEnv *env, jclass klass, const c AndroidPlatformHelpers::AndroidPlatformHelpers(LinphoneCore *lc, void *system_context) : PlatformHelpers(lc) { JNIEnv *env=ms_get_jni_env(); - jclass klass = env->FindClass("org/linphone/core/util/AndroidPlatformHelper"); + jclass klass = env->FindClass("org/linphone/core/tools/AndroidPlatformHelper"); if (!klass){ ms_fatal("Could not find java AndroidPlatformHelper class"); return; From 079cfcfb4480bff54adbff725e8e1c7f5046bff8 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 19 Oct 2017 11:53:54 +0200 Subject: [PATCH 0576/2215] add getDataPath and getconfigPath for iOS --- coreapi/linphonecore.c | 2 +- include/CMakeLists.txt | 1 + include/linphone/utils/paths.h | 42 ++++++++++++++++++++++++ src/CMakeLists.txt | 27 ++++++++++++++-- src/core/core-p.h | 1 + src/core/core.cpp | 17 +++++++++- src/core/core.h | 2 +- src/utils/paths/paths-android.cpp | 38 ++++++++++++++++++++++ src/utils/paths/paths-android.h | 38 ++++++++++++++++++++++ src/utils/paths/paths-apple.h | 38 ++++++++++++++++++++++ src/utils/paths/paths-apple.mm | 54 +++++++++++++++++++++++++++++++ src/utils/paths/paths-linux.cpp | 38 ++++++++++++++++++++++ src/utils/paths/paths-linux.h | 38 ++++++++++++++++++++++ src/utils/paths/paths-windows.cpp | 38 ++++++++++++++++++++++ src/utils/paths/paths-windows.h | 38 ++++++++++++++++++++++ src/utils/paths/paths.cpp | 48 +++++++++++++++++++++++++++ 16 files changed, 455 insertions(+), 5 deletions(-) create mode 100644 include/linphone/utils/paths.h create mode 100644 src/utils/paths/paths-android.cpp create mode 100644 src/utils/paths/paths-android.h create mode 100644 src/utils/paths/paths-apple.h create mode 100644 src/utils/paths/paths-apple.mm create mode 100644 src/utils/paths/paths-linux.cpp create mode 100644 src/utils/paths/paths-linux.h create mode 100644 src/utils/paths/paths-windows.cpp create mode 100644 src/utils/paths/paths-windows.h create mode 100644 src/utils/paths/paths.cpp diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 11ad32dbc..ad1331b12 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2234,7 +2234,7 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig lc->sal->set_user_pointer(lc); lc->sal->set_callbacks(&linphone_sal_callbacks); - new(&lc->cppCore) Core(); + new(&lc->cppCore) Core(lc); #ifdef TUNNEL_ENABLED lc->tunnel=linphone_core_tunnel_new(lc); diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 31f1c52d6..18579565f 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -100,6 +100,7 @@ set(UTILS_HEADER_FILES enum-generator.h general.h magic-macros.h + paths.h utils.h ) diff --git a/include/linphone/utils/paths.h b/include/linphone/utils/paths.h new file mode 100644 index 000000000..da968f719 --- /dev/null +++ b/include/linphone/utils/paths.h @@ -0,0 +1,42 @@ +/* + * paths.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _PATHS_H_ +#define _PATHS_H_ + +#include + +#include "linphone/utils/general.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +namespace Paths { + enum Type { + Data, + Config + }; + + LINPHONE_PUBLIC const std::string &getPath(Type type, void *context); +} + +LINPHONE_END_NAMESPACE + +#endif // ifndef _PATHS_H_ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2e6c4a00b..840e59621 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -199,6 +199,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES sal/register-op.cpp sal/sal.cpp utils/general.cpp + utils/paths/paths.cpp utils/payload-type-handler.cpp utils/utils.cpp variant/variant.cpp @@ -207,6 +208,27 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES xml/xml.cpp ) +set(LINPHONE_OBJC_SOURCE_FILES) +if (APPLE) + list(APPEND LINPHONE_OBJC_SOURCE_FILES utils/paths/paths-apple.mm) + list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES utils/paths/paths-apple.h) +endif() + +if (ANDROID) + list(APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES utils/paths/paths-android.cpp) + list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES utils/paths/paths-android.h) +endif() + +if (WIN32) + list(APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES utils/paths/paths-windows.cpp) + list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES utils/paths/paths-windows.h) +endif() + +if (UNIX AND NOT APPLE) + list(APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES utils/paths/paths-linux.cpp) + list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES utils/paths/paths-linux.h) +endif() + set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS} ${LIBXSD_INCLUDE_DIRS}) set(LINPHONE_CXX_OBJECTS_DEFINITIONS "-DLIBLINPHONE_EXPORTS") set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS}) @@ -223,11 +245,12 @@ endforeach() set(LINPHONE_PRIVATE_HEADER_FILES ${LINPHONE_PRIVATE_HEADER_FILES} PARENT_SCOPE) bc_apply_compile_flags(LINPHONE_CXX_OBJECTS_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX) +bc_apply_compile_flags(LINPHONE_OBJC_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX STRICT_OPTIONS_OBJC) if(ENABLE_STATIC) add_library( linphone-cxx-objects-static OBJECT - ${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES} ${LINPHONE_CXX_OBJECTS_SOURCE_FILES} + ${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES} ${LINPHONE_CXX_OBJECTS_SOURCE_FILES} ${LINPHONE_OBJC_SOURCE_FILES} ) target_compile_definitions(linphone-cxx-objects-static PRIVATE ${LINPHONE_CXX_OBJECTS_DEFINITIONS}) target_include_directories(linphone-cxx-objects-static SYSTEM PRIVATE ${LINPHONE_CXX_OBJECTS_INCLUDE_DIRS} ${LINPHONE_INCLUDE_DIRS}) @@ -236,7 +259,7 @@ endif() if(ENABLE_SHARED) add_library( linphone-cxx-objects OBJECT - ${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES} ${LINPHONE_CXX_OBJECTS_SOURCE_FILES} + ${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES} ${LINPHONE_CXX_OBJECTS_SOURCE_FILES} ${LINPHONE_OBJC_SOURCE_FILES} ) target_compile_definitions(linphone-cxx-objects PRIVATE ${LINPHONE_CXX_OBJECTS_DEFINITIONS}) target_include_directories(linphone-cxx-objects SYSTEM PRIVATE ${LINPHONE_CXX_OBJECTS_INCLUDE_DIRS} ${LINPHONE_INCLUDE_DIRS}) diff --git a/src/core/core-p.h b/src/core/core-p.h index 5ebe4443f..c402c6ccd 100644 --- a/src/core/core-p.h +++ b/src/core/core-p.h @@ -31,6 +31,7 @@ LINPHONE_BEGIN_NAMESPACE class CorePrivate : public ObjectPrivate { public: MainDb mainDb; + LinphoneCore *cCore; private: std::list> chatRooms; diff --git a/src/core/core.cpp b/src/core/core.cpp index fe3e79218..96bc6a01c 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -23,6 +23,7 @@ #include "chat/chat-room/basic-chat-room.h" #include "core-p.h" #include "db/main-db.h" +#include "linphone/core.h" #include "object/object-p.h" #include "core.h" @@ -35,7 +36,21 @@ LINPHONE_BEGIN_NAMESPACE // ----------------------------------------------------------------------------- -Core::Core () : Object(*new CorePrivate) {} +Core::Core (LinphoneCore *cCore) : Object(*new CorePrivate) { + L_D(); + d->cCore = cCore; + const char *uri = lp_config_get_string(linphone_core_get_config(d->cCore), "server", "db_uri", NULL); + if (uri) { + AbstractDb::Backend backend = + strcmp(lp_config_get_string(linphone_core_get_config(d->cCore), "server", "db_backend", NULL), "mysql") == 0 + ? MainDb::Mysql + : MainDb::Sqlite3; + d->mainDb.connect(backend, uri); + } else { + // TODO + // d->mainDb.connect(MainDb::Sqlite3, linphone_factory_get_writable_dir()/linphone.db); + } +} // ----------------------------------------------------------------------------- diff --git a/src/core/core.h b/src/core/core.h index 715abbaf9..a23b79f52 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -34,7 +34,7 @@ class CorePrivate; class LINPHONE_PUBLIC Core : public Object { friend class ClientGroupChatRoom; public: - Core (); + Core (LinphoneCore *cCore); std::shared_ptr createClientGroupChatRoom (const std::string &subject); std::shared_ptr getOrCreateChatRoom (const std::string &peerAddress, bool isRtt = false) const; diff --git a/src/utils/paths/paths-android.cpp b/src/utils/paths/paths-android.cpp new file mode 100644 index 000000000..d0f427689 --- /dev/null +++ b/src/utils/paths/paths-android.cpp @@ -0,0 +1,38 @@ +/* + * paths-android.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "linphone/utils/utils.h" + +#include "paths-android.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +const std::string &SysPaths::getDataPath (void *context) { + //TODO. + return Utils::getEmptyConstRefObject(); +} + +const std::string &SysPaths::getConfigPath (void *context) { + //TODO. + return Utils::getEmptyConstRefObject(); +} + +LINPHONE_END_NAMESPACE diff --git a/src/utils/paths/paths-android.h b/src/utils/paths/paths-android.h new file mode 100644 index 000000000..7cd7efd91 --- /dev/null +++ b/src/utils/paths/paths-android.h @@ -0,0 +1,38 @@ +/* + * paths-android.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _PATHS_ANDROID_H_ +#define _PATHS_ANDROID_H_ + +#include + +#include "linphone/utils/general.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +namespace SysPaths { + LINPHONE_PUBLIC const std::string &getDataPath (void *context); + LINPHONE_PUBLIC const std::string &getConfigPath (void *context); +} + +LINPHONE_END_NAMESPACE + +#endif // ifndef _PATHS_ANDROID_H_ diff --git a/src/utils/paths/paths-apple.h b/src/utils/paths/paths-apple.h new file mode 100644 index 000000000..db0cd35ff --- /dev/null +++ b/src/utils/paths/paths-apple.h @@ -0,0 +1,38 @@ +/* + * paths-apple.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _PATHS_APPLE_H_ +#define _PATHS_APPLE_H_ + +#include + +#include "linphone/utils/general.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +namespace SysPaths { + LINPHONE_PUBLIC const std::string &getDataPath (void *context); + LINPHONE_PUBLIC const std::string &getConfigPath (void *context); +} + +LINPHONE_END_NAMESPACE + +#endif // ifndef _PATHS_APPLE_H_ diff --git a/src/utils/paths/paths-apple.mm b/src/utils/paths/paths-apple.mm new file mode 100644 index 000000000..a9f65b248 --- /dev/null +++ b/src/utils/paths/paths-apple.mm @@ -0,0 +1,54 @@ +/* + * paths-apple.m + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#import "linphone/utils/utils.h" + +#import "paths-apple.h" + +#ifdef __OBJC__ +#import +#endif + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +const std::string &SysPaths::getDataPath (void *context) { +#ifdef __OBJC__ + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); + NSString *writablePath = [paths objectAtIndex:0]; + NSString *fullPath = [writablePath stringByAppendingString:@"/linphone/"]; + const char *ret = fullPath.UTF8String; + return ret; +#endif + return Utils::getEmptyConstRefObject(); +} + +const std::string &SysPaths::getConfigPath (void *context) { +#ifdef __OBJC__ + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); + NSString *configPath = [paths objectAtIndex:0]; + NSString *fullPath = [configPath stringByAppendingString:@"/Preferences/linphone/"]; + const char *ret = fullPath.UTF8String; + return ret; +#endif + return Utils::getEmptyConstRefObject(); +} + +LINPHONE_END_NAMESPACE diff --git a/src/utils/paths/paths-linux.cpp b/src/utils/paths/paths-linux.cpp new file mode 100644 index 000000000..11f47d29c --- /dev/null +++ b/src/utils/paths/paths-linux.cpp @@ -0,0 +1,38 @@ +/* + * paths-linux.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "linphone/utils/utils.h" + +#include "paths-linux.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +const std::string &SysPaths::getDataPath (void *context) { + //TODO. + return Utils::getEmptyConstRefObject(); +} + +const std::string &SysPaths::getConfigPath (void *context) { + //TODO. + return Utils::getEmptyConstRefObject(); +} + +LINPHONE_END_NAMESPACE diff --git a/src/utils/paths/paths-linux.h b/src/utils/paths/paths-linux.h new file mode 100644 index 000000000..85a1f284e --- /dev/null +++ b/src/utils/paths/paths-linux.h @@ -0,0 +1,38 @@ +/* + * paths-linux.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _PATHS_LINUX_H_ +#define _PATHS_LINUX_H_ + +#include + +#include "linphone/utils/general.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +namespace SysPaths { + LINPHONE_PUBLIC const std::string &getDataPath (void *context); + LINPHONE_PUBLIC const std::string &getConfigPath (void *context); +} + +LINPHONE_END_NAMESPACE + +#endif // ifndef _PATHS_LINUX_H_ diff --git a/src/utils/paths/paths-windows.cpp b/src/utils/paths/paths-windows.cpp new file mode 100644 index 000000000..fc6ec22f3 --- /dev/null +++ b/src/utils/paths/paths-windows.cpp @@ -0,0 +1,38 @@ +/* + * paths-windows.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "linphone/utils/utils.h" + +#include "paths-windows.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +const std::string &SysPaths::getDataPath (void *context) { + //TODO. + return Utils::getEmptyConstRefObject(); +} + +const std::string &SysPaths::getConfigPath (void *context) { + //TODO. + return Utils::getEmptyConstRefObject(); +} + +LINPHONE_END_NAMESPACE diff --git a/src/utils/paths/paths-windows.h b/src/utils/paths/paths-windows.h new file mode 100644 index 000000000..b67b65e7a --- /dev/null +++ b/src/utils/paths/paths-windows.h @@ -0,0 +1,38 @@ +/* + * paths-windws.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _PATHS_WINDOWS_H_ +#define _PATHS_WINDOWS_H_ + +#include + +#include "linphone/utils/general.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +namespace SysPaths { + LINPHONE_PUBLIC const std::string &getDataPath (void *context); + LINPHONE_PUBLIC const std::string &getConfigPath (void *context); +} + +LINPHONE_END_NAMESPACE + +#endif // ifndef _PATHS_WINDOWS_H_ diff --git a/src/utils/paths/paths.cpp b/src/utils/paths/paths.cpp new file mode 100644 index 000000000..63f6e959b --- /dev/null +++ b/src/utils/paths/paths.cpp @@ -0,0 +1,48 @@ +/* + * utils.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "linphone/utils/paths.h" + +#ifdef __APPLE__ +#include "paths-apple.h" +#elif defined(__ANDROID__) +#include "paths-android.h" +#elif defined(_WIN32) +#include "paths-windows.h" +#elif defined(__linux) +#include "paths-linux.h" +#else +#error "Unsupported system" +#endif +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +const string &Paths::getPath (Paths::Type type, void *context) { + switch (type) { + case Data: + return SysPaths::getDataPath(context); + case Config: + return SysPaths::getConfigPath(context); + } +} + +LINPHONE_END_NAMESPACE From df7f5059c2c81089b30fd8039125cdcaed2ba53a Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 19 Oct 2017 12:22:15 +0200 Subject: [PATCH 0577/2215] add getPaths method to platform helpers --- coreapi/android-helpers.cpp | 40 ++++++++++++++++--- coreapi/platform-helpers.cpp | 14 +++++-- coreapi/platform-helpers.h | 4 ++ .../core/util/AndroidPlatformHelper.java | 6 +-- src/utils/paths/paths-android.cpp | 2 + 5 files changed, 53 insertions(+), 13 deletions(-) diff --git a/coreapi/android-helpers.cpp b/coreapi/android-helpers.cpp index 7b4e494ff..d7b64ecea 100644 --- a/coreapi/android-helpers.cpp +++ b/coreapi/android-helpers.cpp @@ -17,6 +17,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "linphone/utils/utils.h" + #include "private.h" #include "platform-helpers.h" @@ -24,7 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include -namespace LinphonePrivate{ +LINPHONE_BEGIN_NAMESPACE class AndroidPlatformHelpers : public PlatformHelpers{ public: @@ -36,6 +38,8 @@ public: virtual void releaseMcastLock(); virtual void acquireCpuLock(); virtual void releaseCpuLock(); + virtual std::string getDataPath(); + virtual std::string getConfigPath(); ~AndroidPlatformHelpers(); private: int callVoidMethod(jmethodID id); @@ -49,9 +53,20 @@ private: jmethodID mCpuLockReleaseId; jmethodID mGetDnsServersId; jmethodID mGetPowerManagerId; + jmethodID mGetDataPathId; + jmethodID mGetConfigPathId; }; +static const char* GetStringUTFChars(JNIEnv* env, jstring string) { + const char *cstring = string ? env->GetStringUTFChars(string, NULL) : NULL; + return cstring; +} + +static void ReleaseStringUTFChars(JNIEnv* env, jstring string, const char *cstring) { + if (string) env->ReleaseStringUTFChars(string, cstring); +} + jmethodID AndroidPlatformHelpers::getMethodId(JNIEnv *env, jclass klass, const char *method, const char *signature){ jmethodID id = env->GetMethodID(klass, method, signature); if (id == 0){ @@ -83,6 +98,8 @@ AndroidPlatformHelpers::AndroidPlatformHelpers(LinphoneCore *lc, void *system_co mCpuLockReleaseId = getMethodId(env, klass, "releaseCpuLock", "()V"); mGetDnsServersId = getMethodId(env, klass, "getDnsServers", "()[Ljava/lang/String;"); mGetPowerManagerId = getMethodId(env, klass, "getPowerManager", "()Ljava/lang/Object;"); + mGetDataPathId = getMethodId(env, klass, "getDataPath", "()Ljava/lang/String;"); + mGetConfigPathId = getMethodId(env, klass, "getConfigPath", "()Ljava/lang/String;"); jobject pm = env->CallObjectMethod(mJavaHelper,mGetPowerManagerId); belle_sip_wake_lock_init(env, pm); @@ -152,6 +169,21 @@ void AndroidPlatformHelpers::releaseCpuLock(){ callVoidMethod(mCpuLockReleaseId); } +std::string AndroidPlatformHelpers::getDataPath(){ + jstring jdata_path = (jstring)env->CallObjectMethod(mJavaHelper,mGetDataPathId); + const char *data_path = GetStringUTFChars(env, jdata_path); + string dataPath = data_path; + ReleaseStringUTFChars(env, jdata_path, data_path); + return dataPath; +} + +std::string AndroidPlatformHelpers::getConfigPath(){ + jstring jconfig_path = (jstring)env->CallObjectMethod(mJavaHelper,mGetConfigPathId); + const char *config_path = GetStringUTFChars(env, jconfig_path); + string configPath = config_path; + ReleaseStringUTFChars(env, jconfig_path, config_path); + return configPath; +} int AndroidPlatformHelpers::callVoidMethod(jmethodID id) { JNIEnv *env=ms_get_jni_env(); @@ -170,10 +202,6 @@ PlatformHelpers *createAndroidPlatformHelpers(LinphoneCore *lc, void *system_con return new AndroidPlatformHelpers(lc, system_context); } -}//end of namespace - - - +LINPHONE_END_NAMESPACE #endif - diff --git a/coreapi/platform-helpers.cpp b/coreapi/platform-helpers.cpp index 05bbc00e6..89779599d 100644 --- a/coreapi/platform-helpers.cpp +++ b/coreapi/platform-helpers.cpp @@ -17,11 +17,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "linphone/utils/utils.h" + #include "private.h" +LINPHONE_BEGIN_NAMESPACE -namespace LinphonePrivate{ - PlatformHelpers::~PlatformHelpers(){ } @@ -42,8 +43,13 @@ void StubbedPlatformHelpers::acquireCpuLock(){ } void StubbedPlatformHelpers::releaseCpuLock(){ } - +std::string StubbedPlatformHelpers::getDataPath(){ + return Utils::getEmptyConstRefObject(); +} +std::string StubbedPlatformHelpers::getConfigPath(){ + return Utils::getEmptyConstRefObject(); +} StubbedPlatformHelpers::~StubbedPlatformHelpers(){ } -} \ No newline at end of file +LINPHONE_END_NAMESPACE diff --git a/coreapi/platform-helpers.h b/coreapi/platform-helpers.h index b97c0fa2b..de005c081 100644 --- a/coreapi/platform-helpers.h +++ b/coreapi/platform-helpers.h @@ -37,6 +37,8 @@ class PlatformHelpers{ virtual void releaseMcastLock() = 0; virtual void acquireCpuLock() = 0; virtual void releaseCpuLock() = 0; + virtual std::string getDataPath() = 0; + virtual std::string getConfigPath() = 0; virtual ~PlatformHelpers(); protected: PlatformHelpers(LinphoneCore *lc) : mCore(lc){ @@ -54,6 +56,8 @@ public: void releaseMcastLock() override; void acquireCpuLock() override; void releaseCpuLock() override; + std::string getDataPath() override; + std::string getConfigPath() override; virtual ~StubbedPlatformHelpers(); }; diff --git a/java/impl/org/linphone/core/util/AndroidPlatformHelper.java b/java/impl/org/linphone/core/util/AndroidPlatformHelper.java index aeb44e15b..ce3a8d715 100644 --- a/java/impl/org/linphone/core/util/AndroidPlatformHelper.java +++ b/java/impl/org/linphone/core/util/AndroidPlatformHelper.java @@ -52,7 +52,7 @@ public class AndroidPlatformHelper{ WifiManager wifiMgr = ctx.getSystemService(WifiManager.class); mPowerManager = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE); mConnectivityManager = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE); - + mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidPlatformHelper"); mWakeLock.setReferenceCounted(true); mMcastLock = wifiMgr.createMulticastLock("AndroidPlatformHelper"); @@ -60,11 +60,11 @@ public class AndroidPlatformHelper{ mWifiLock = wifiMgr.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "AndroidPlatformHelper"); mWifiLock.setReferenceCounted(true); } - + public Object getPowerManager(){ return mPowerManager; } - + public String[] getDnsServers() { if (mConnectivityManager == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return null; diff --git a/src/utils/paths/paths-android.cpp b/src/utils/paths/paths-android.cpp index d0f427689..f5601cba0 100644 --- a/src/utils/paths/paths-android.cpp +++ b/src/utils/paths/paths-android.cpp @@ -17,6 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include + #include "linphone/utils/utils.h" #include "paths-android.h" From 40ae364d217e5ba17aec115f5ba2cbca7be9b9b1 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 19 Oct 2017 12:22:17 +0200 Subject: [PATCH 0578/2215] Added getDataPath, getConfigPath and getCachePath to AndroidPlatformHelper --- .../classes/tools/AndroidPlatformHelper.java | 43 +++++++++++++------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/wrappers/java/classes/tools/AndroidPlatformHelper.java b/wrappers/java/classes/tools/AndroidPlatformHelper.java index 92d4ea04f..0da810886 100644 --- a/wrappers/java/classes/tools/AndroidPlatformHelper.java +++ b/wrappers/java/classes/tools/AndroidPlatformHelper.java @@ -40,18 +40,19 @@ import android.os.Build; * This class is instanciated directly by the linphone library in order to access specific features only accessible in java. **/ -public class AndroidPlatformHelper{ +public class AndroidPlatformHelper { + private Context mContext; private WifiManager.WifiLock mWifiLock; private WifiManager.MulticastLock mMcastLock; private ConnectivityManager mConnectivityManager; private PowerManager mPowerManager; private WakeLock mWakeLock; - public AndroidPlatformHelper(Object ctx_obj){ - Context ctx = (Context) ctx_obj; - WifiManager wifiMgr = ctx.getSystemService(WifiManager.class); - mPowerManager = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE); - mConnectivityManager = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE); + public AndroidPlatformHelper(Object ctx_obj) { + mContext = (Context) ctx_obj; + WifiManager wifiMgr = mContext.getSystemService(WifiManager.class); + mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + mConnectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidPlatformHelper"); mWakeLock.setReferenceCounted(true); @@ -61,7 +62,7 @@ public class AndroidPlatformHelper{ mWifiLock.setReferenceCounted(true); } - public Object getPowerManager(){ + public Object getPowerManager() { return mPowerManager; } @@ -85,26 +86,44 @@ public class AndroidPlatformHelper{ Log.i("getDnsServers() returning"); return servers; } - public void acquireWifiLock(){ + + public String getDataPath() { + return mContext.getFilesDir().getAbsolutePath(); + } + + public String getConfigPath() { + return mContext.getFilesDir().getAbsolutePath(); + } + + public String getCachePath() { + return mContext.getCacheDir().getAbsolutePath(); + } + + public void acquireWifiLock() { Log.i("acquireWifiLock()"); mWifiLock.acquire(); } - public void releaseWifiLock(){ + + public void releaseWifiLock() { Log.i("releaseWifiLock()"); mWifiLock.release(); } - public void acquireMcastLock(){ + + public void acquireMcastLock() { Log.i("acquireMcastLock()"); mMcastLock.acquire(); } - public void releaseMcastLock(){ + + public void releaseMcastLock() { Log.i("releaseMcastLock()"); mMcastLock.release(); } - public void acquireCpuLock(){ + + public void acquireCpuLock() { Log.i("acquireCpuLock()"); mWakeLock.acquire(); } + public void releaseCpuLock(){ Log.i("releaseCpuLock()"); mWakeLock.release(); From b1ae558b69002945c8f9dfc8f210502ad2cb28e5 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 19 Oct 2017 13:02:05 +0200 Subject: [PATCH 0579/2215] Fixed compil --- src/utils/paths/paths.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/paths/paths.cpp b/src/utils/paths/paths.cpp index 63f6e959b..3b88102d0 100644 --- a/src/utils/paths/paths.cpp +++ b/src/utils/paths/paths.cpp @@ -43,6 +43,7 @@ const string &Paths::getPath (Paths::Type type, void *context) { case Config: return SysPaths::getConfigPath(context); } + return NULL; } LINPHONE_END_NAMESPACE From 9d7d608375c6005fde2c64507069e875757a998c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 19 Oct 2017 13:31:18 +0200 Subject: [PATCH 0580/2215] Fixed android compilation issues --- coreapi/android-helpers.cpp | 6 ++++-- src/utils/paths/paths.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/coreapi/android-helpers.cpp b/coreapi/android-helpers.cpp index d7b64ecea..148e2d568 100644 --- a/coreapi/android-helpers.cpp +++ b/coreapi/android-helpers.cpp @@ -170,17 +170,19 @@ void AndroidPlatformHelpers::releaseCpuLock(){ } std::string AndroidPlatformHelpers::getDataPath(){ + JNIEnv *env = ms_get_jni_env(); jstring jdata_path = (jstring)env->CallObjectMethod(mJavaHelper,mGetDataPathId); const char *data_path = GetStringUTFChars(env, jdata_path); - string dataPath = data_path; + std::string dataPath = data_path; ReleaseStringUTFChars(env, jdata_path, data_path); return dataPath; } std::string AndroidPlatformHelpers::getConfigPath(){ + JNIEnv *env = ms_get_jni_env(); jstring jconfig_path = (jstring)env->CallObjectMethod(mJavaHelper,mGetConfigPathId); const char *config_path = GetStringUTFChars(env, jconfig_path); - string configPath = config_path; + std::string configPath = config_path; ReleaseStringUTFChars(env, jconfig_path, config_path); return configPath; } diff --git a/src/utils/paths/paths.cpp b/src/utils/paths/paths.cpp index 3b88102d0..c732bdf44 100644 --- a/src/utils/paths/paths.cpp +++ b/src/utils/paths/paths.cpp @@ -41,9 +41,9 @@ const string &Paths::getPath (Paths::Type type, void *context) { case Data: return SysPaths::getDataPath(context); case Config: + default: return SysPaths::getConfigPath(context); } - return NULL; } LINPHONE_END_NAMESPACE From ddf3fe65e2941763c936e8d2c6da23ae1e22bc90 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 19 Oct 2017 13:36:26 +0200 Subject: [PATCH 0581/2215] fix build & coding style --- coreapi/android-helpers.cpp | 72 ++++++++++++++++++------------------ coreapi/platform-helpers.cpp | 26 ++++++------- coreapi/platform-helpers.h | 69 +++++++++++++++++----------------- src/CMakeLists.txt | 9 ++--- src/utils/paths/paths.cpp | 1 + 5 files changed, 87 insertions(+), 90 deletions(-) diff --git a/coreapi/android-helpers.cpp b/coreapi/android-helpers.cpp index 148e2d568..afc4e2937 100644 --- a/coreapi/android-helpers.cpp +++ b/coreapi/android-helpers.cpp @@ -28,22 +28,22 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. LINPHONE_BEGIN_NAMESPACE -class AndroidPlatformHelpers : public PlatformHelpers{ +class AndroidPlatformHelpers : public PlatformHelpers { public: - AndroidPlatformHelpers(LinphoneCore *lc, void *system_context); - virtual void setDnsServers(); - virtual void acquireWifiLock(); - virtual void releaseWifiLock(); - virtual void acquireMcastLock(); - virtual void releaseMcastLock(); - virtual void acquireCpuLock(); - virtual void releaseCpuLock(); - virtual std::string getDataPath(); - virtual std::string getConfigPath(); - ~AndroidPlatformHelpers(); + AndroidPlatformHelpers (LinphoneCore *lc, void *system_context); + virtual void setDnsServers (); + virtual void acquireWifiLock (); + virtual void releaseWifiLock (); + virtual void acquireMcastLock (); + virtual void releaseMcastLock (); + virtual void acquireCpuLock (); + virtual void releaseCpuLock (); + virtual std::string getDataPath (); + virtual std::string getConfigPath (); + ~AndroidPlatformHelpers (); private: - int callVoidMethod(jmethodID id); - static jmethodID getMethodId(JNIEnv *env, jclass klass, const char *method, const char *signature); + int callVoidMethod (jmethodID id); + static jmethodID getMethodId (JNIEnv *env, jclass klass, const char *method, const char *signature); jobject mJavaHelper; jmethodID mWifiLockAcquireId; jmethodID mWifiLockReleaseId; @@ -58,33 +58,33 @@ private: }; -static const char* GetStringUTFChars(JNIEnv* env, jstring string) { +static const char* GetStringUTFChars (JNIEnv* env, jstring string) { const char *cstring = string ? env->GetStringUTFChars(string, NULL) : NULL; return cstring; } -static void ReleaseStringUTFChars(JNIEnv* env, jstring string, const char *cstring) { +static void ReleaseStringUTFChars (JNIEnv* env, jstring string, const char *cstring) { if (string) env->ReleaseStringUTFChars(string, cstring); } -jmethodID AndroidPlatformHelpers::getMethodId(JNIEnv *env, jclass klass, const char *method, const char *signature){ +jmethodID AndroidPlatformHelpers::getMethodId (JNIEnv *env, jclass klass, const char *method, const char *signature) { jmethodID id = env->GetMethodID(klass, method, signature); - if (id == 0){ + if (id == 0) { ms_fatal("Could not find java method '%s %s'", method, signature); } return id; } -AndroidPlatformHelpers::AndroidPlatformHelpers(LinphoneCore *lc, void *system_context) : PlatformHelpers(lc) { +AndroidPlatformHelpers::AndroidPlatformHelpers (LinphoneCore *lc, void *system_context) : PlatformHelpers(lc) { JNIEnv *env=ms_get_jni_env(); jclass klass = env->FindClass("org/linphone/core/tools/AndroidPlatformHelper"); - if (!klass){ + if (!klass) { ms_fatal("Could not find java AndroidPlatformHelper class"); return; } jmethodID ctor = env->GetMethodID(klass,"", "(Ljava/lang/Object;)V"); mJavaHelper = env->NewObject(klass, ctor, (jobject)system_context); - if (!mJavaHelper){ + if (!mJavaHelper) { ms_error("Could not instanciate AndroidPlatformHelper object."); return; } @@ -107,8 +107,8 @@ AndroidPlatformHelpers::AndroidPlatformHelpers(LinphoneCore *lc, void *system_co ms_message("AndroidPlatformHelpers is fully initialised"); } -AndroidPlatformHelpers::~AndroidPlatformHelpers(){ - if (mJavaHelper){ +AndroidPlatformHelpers::~AndroidPlatformHelpers () { + if (mJavaHelper) { JNIEnv *env = ms_get_jni_env(); belle_sip_wake_lock_uninit(env); env->DeleteGlobalRef(mJavaHelper); @@ -117,7 +117,7 @@ AndroidPlatformHelpers::~AndroidPlatformHelpers(){ } -void AndroidPlatformHelpers::setDnsServers(){ +void AndroidPlatformHelpers::setDnsServers () { if (!mJavaHelper) return; JNIEnv *env=ms_get_jni_env(); if (env && mJavaHelper) { @@ -128,13 +128,13 @@ void AndroidPlatformHelpers::setDnsServers(){ ms_error("AndroidPlatformHelpers::setDnsServers() exception"); return; } - if (jservers != NULL){ + if (jservers != NULL) { int count = env->GetArrayLength(jservers); for (int i=0; i < count; i++) { jstring jserver = (jstring) env->GetObjectArrayElement(jservers, i); const char *str = env->GetStringUTFChars(jserver, NULL); - if (str){ + if (str) { l = bctbx_list_append(l, ms_strdup(str)); env->ReleaseStringUTFChars(jserver, str); } @@ -145,31 +145,31 @@ void AndroidPlatformHelpers::setDnsServers(){ } } -void AndroidPlatformHelpers::acquireWifiLock(){ +void AndroidPlatformHelpers::acquireWifiLock () { callVoidMethod(mWifiLockAcquireId); } -void AndroidPlatformHelpers::releaseWifiLock(){ +void AndroidPlatformHelpers::releaseWifiLock () { callVoidMethod(mWifiLockReleaseId); } -void AndroidPlatformHelpers::acquireMcastLock(){ +void AndroidPlatformHelpers::acquireMcastLock () { callVoidMethod(mMcastLockAcquireId); } -void AndroidPlatformHelpers::releaseMcastLock(){ +void AndroidPlatformHelpers::releaseMcastLock () { callVoidMethod(mMcastLockReleaseId); } -void AndroidPlatformHelpers::acquireCpuLock(){ +void AndroidPlatformHelpers::acquireCpuLock () { callVoidMethod(mCpuLockAcquireId); } -void AndroidPlatformHelpers::releaseCpuLock(){ +void AndroidPlatformHelpers::releaseCpuLock () { callVoidMethod(mCpuLockReleaseId); } -std::string AndroidPlatformHelpers::getDataPath(){ +std::string AndroidPlatformHelpers::getDataPath () { JNIEnv *env = ms_get_jni_env(); jstring jdata_path = (jstring)env->CallObjectMethod(mJavaHelper,mGetDataPathId); const char *data_path = GetStringUTFChars(env, jdata_path); @@ -178,7 +178,7 @@ std::string AndroidPlatformHelpers::getDataPath(){ return dataPath; } -std::string AndroidPlatformHelpers::getConfigPath(){ +std::string AndroidPlatformHelpers::getConfigPath () { JNIEnv *env = ms_get_jni_env(); jstring jconfig_path = (jstring)env->CallObjectMethod(mJavaHelper,mGetConfigPathId); const char *config_path = GetStringUTFChars(env, jconfig_path); @@ -187,7 +187,7 @@ std::string AndroidPlatformHelpers::getConfigPath(){ return configPath; } -int AndroidPlatformHelpers::callVoidMethod(jmethodID id) { +int AndroidPlatformHelpers::callVoidMethod (jmethodID id) { JNIEnv *env=ms_get_jni_env(); if (env && mJavaHelper) { env->CallVoidMethod(mJavaHelper,id); @@ -200,7 +200,7 @@ int AndroidPlatformHelpers::callVoidMethod(jmethodID id) { return -1; } -PlatformHelpers *createAndroidPlatformHelpers(LinphoneCore *lc, void *system_context){ +PlatformHelpers *createAndroidPlatformHelpers (LinphoneCore *lc, void *system_context) { return new AndroidPlatformHelpers(lc, system_context); } diff --git a/coreapi/platform-helpers.cpp b/coreapi/platform-helpers.cpp index 89779599d..2ac0516ec 100644 --- a/coreapi/platform-helpers.cpp +++ b/coreapi/platform-helpers.cpp @@ -23,33 +23,31 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. LINPHONE_BEGIN_NAMESPACE -PlatformHelpers::~PlatformHelpers(){ -} +PlatformHelpers::~PlatformHelpers () {} -StubbedPlatformHelpers::StubbedPlatformHelpers(LinphoneCore *lc) : PlatformHelpers(lc){ -} +StubbedPlatformHelpers::StubbedPlatformHelpers (LinphoneCore *lc) : PlatformHelpers(lc) {} -void StubbedPlatformHelpers::setDnsServers(){ +void StubbedPlatformHelpers::setDnsServers () { } -void StubbedPlatformHelpers::acquireWifiLock(){ +void StubbedPlatformHelpers::acquireWifiLock () { } -void StubbedPlatformHelpers::releaseWifiLock(){ +void StubbedPlatformHelpers::releaseWifiLock () { } -void StubbedPlatformHelpers::acquireMcastLock(){ +void StubbedPlatformHelpers::acquireMcastLock () { } -void StubbedPlatformHelpers::releaseMcastLock(){ +void StubbedPlatformHelpers::releaseMcastLock () { } -void StubbedPlatformHelpers::acquireCpuLock(){ +void StubbedPlatformHelpers::acquireCpuLock () { } -void StubbedPlatformHelpers::releaseCpuLock(){ +void StubbedPlatformHelpers::releaseCpuLock () { } -std::string StubbedPlatformHelpers::getDataPath(){ +std::string StubbedPlatformHelpers::getDataPath () { return Utils::getEmptyConstRefObject(); } -std::string StubbedPlatformHelpers::getConfigPath(){ +std::string StubbedPlatformHelpers::getConfigPath () { return Utils::getEmptyConstRefObject(); } -StubbedPlatformHelpers::~StubbedPlatformHelpers(){ +StubbedPlatformHelpers::~StubbedPlatformHelpers () { } LINPHONE_END_NAMESPACE diff --git a/coreapi/platform-helpers.h b/coreapi/platform-helpers.h index de005c081..3302a17a5 100644 --- a/coreapi/platform-helpers.h +++ b/coreapi/platform-helpers.h @@ -20,49 +20,50 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef platform_helpers_h #define platform_helpers_h +#include "linphone/utils/general.h" -namespace LinphonePrivate{ +LINPHONE_BEGIN_NAMESPACE /** * This interface aims at abstracting some features offered by the platform, most often mobile platforms. * A per platform implementation is to be made to implement these features, if available on the platform */ -class PlatformHelpers{ - public: - //This method shall retrieve DNS server list from the platform and assign it to the core. - virtual void setDnsServers() = 0; - virtual void acquireWifiLock() = 0; - virtual void releaseWifiLock() = 0; - virtual void acquireMcastLock() = 0; - virtual void releaseMcastLock() = 0; - virtual void acquireCpuLock() = 0; - virtual void releaseCpuLock() = 0; - virtual std::string getDataPath() = 0; - virtual std::string getConfigPath() = 0; - virtual ~PlatformHelpers(); - protected: - PlatformHelpers(LinphoneCore *lc) : mCore(lc){ - } - LinphoneCore *mCore; -}; - -class StubbedPlatformHelpers : public PlatformHelpers{ +class PlatformHelpers { public: - StubbedPlatformHelpers(LinphoneCore *lc); - void setDnsServers() override; - void acquireWifiLock() override; - void releaseWifiLock() override; - void acquireMcastLock() override; - void releaseMcastLock() override; - void acquireCpuLock() override; - void releaseCpuLock() override; - std::string getDataPath() override; - std::string getConfigPath() override; - virtual ~StubbedPlatformHelpers(); + //This method shall retrieve DNS server list from the platform and assign it to the core. + virtual void setDnsServers () = 0; + virtual void acquireWifiLock () = 0; + virtual void releaseWifiLock () = 0; + virtual void acquireMcastLock () = 0; + virtual void releaseMcastLock () = 0; + virtual void acquireCpuLock () = 0; + virtual void releaseCpuLock () = 0; + virtual std::string getDataPath () = 0; + virtual std::string getConfigPath () = 0; + virtual ~PlatformHelpers (); + +protected: + inline PlatformHelpers (LinphoneCore *lc) : mCore(lc) {} + LinphoneCore *mCore; }; -PlatformHelpers *createAndroidPlatformHelpers(LinphoneCore *lc, void *system_context); +class StubbedPlatformHelpers : public PlatformHelpers { +public: + StubbedPlatformHelpers (LinphoneCore *lc); + void setDnsServers () override; + void acquireWifiLock () override; + void releaseWifiLock () override; + void acquireMcastLock () override; + void releaseMcastLock () override; + void acquireCpuLock () override; + void releaseCpuLock () override; + std::string getDataPath () override; + std::string getConfigPath () override; + virtual ~StubbedPlatformHelpers (); +}; -}//end of namespace +PlatformHelpers *createAndroidPlatformHelpers (LinphoneCore *lc, void *system_context); + +LINPHONE_END_NAMESPACE #endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 840e59621..bc07f9dab 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -212,19 +212,16 @@ set(LINPHONE_OBJC_SOURCE_FILES) if (APPLE) list(APPEND LINPHONE_OBJC_SOURCE_FILES utils/paths/paths-apple.mm) list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES utils/paths/paths-apple.h) -endif() -if (ANDROID) +elseif(ANDROID) list(APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES utils/paths/paths-android.cpp) list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES utils/paths/paths-android.h) -endif() -if (WIN32) +elseif(WIN32) list(APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES utils/paths/paths-windows.cpp) list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES utils/paths/paths-windows.h) -endif() -if (UNIX AND NOT APPLE) +elseif(UNIX) list(APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES utils/paths/paths-linux.cpp) list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES utils/paths/paths-linux.h) endif() diff --git a/src/utils/paths/paths.cpp b/src/utils/paths/paths.cpp index c732bdf44..e3a937fff 100644 --- a/src/utils/paths/paths.cpp +++ b/src/utils/paths/paths.cpp @@ -30,6 +30,7 @@ #else #error "Unsupported system" #endif + // ============================================================================= using namespace std; From 8b51263caee5cb15f273625e26393e6ddec7e14d Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 19 Oct 2017 14:06:57 +0200 Subject: [PATCH 0582/2215] pass platformHelper to Paths functions --- include/linphone/utils/paths.h | 3 ++- src/core/core.cpp | 7 +++++-- src/utils/paths/paths-android.cpp | 17 +++++++++++++---- src/utils/paths/paths-android.h | 5 +++-- src/utils/paths/paths-apple.h | 5 +++-- src/utils/paths/paths-apple.mm | 5 +++-- src/utils/paths/paths-linux.cpp | 5 +++-- src/utils/paths/paths-linux.h | 5 +++-- src/utils/paths/paths-windows.cpp | 5 +++-- src/utils/paths/paths-windows.h | 5 +++-- src/utils/paths/paths.cpp | 7 ++++--- 11 files changed, 45 insertions(+), 24 deletions(-) diff --git a/include/linphone/utils/paths.h b/include/linphone/utils/paths.h index da968f719..70deea899 100644 --- a/include/linphone/utils/paths.h +++ b/include/linphone/utils/paths.h @@ -28,13 +28,14 @@ LINPHONE_BEGIN_NAMESPACE +class PlatformHelper; namespace Paths { enum Type { Data, Config }; - LINPHONE_PUBLIC const std::string &getPath(Type type, void *context); + LINPHONE_PUBLIC const std::string &getPath(Type type, PlatformHelper *platformHelper); } LINPHONE_END_NAMESPACE diff --git a/src/core/core.cpp b/src/core/core.cpp index 96bc6a01c..bf9dfa3c0 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -24,8 +24,11 @@ #include "core-p.h" #include "db/main-db.h" #include "linphone/core.h" +#include "linphone/utils/paths.h" #include "object/object-p.h" +#include "private.h" + #include "core.h" // ============================================================================= @@ -47,8 +50,8 @@ Core::Core (LinphoneCore *cCore) : Object(*new CorePrivate) { : MainDb::Sqlite3; d->mainDb.connect(backend, uri); } else { - // TODO - // d->mainDb.connect(MainDb::Sqlite3, linphone_factory_get_writable_dir()/linphone.db); + string path = Paths::getPath(Paths::Data, static_cast(cCore->platform_helper)); + //d->mainDb.connect(MainDb::Sqlite3, linphone_factory_get_writable_dir()/linphone.db); } } diff --git a/src/utils/paths/paths-android.cpp b/src/utils/paths/paths-android.cpp index f5601cba0..bce2b600e 100644 --- a/src/utils/paths/paths-android.cpp +++ b/src/utils/paths/paths-android.cpp @@ -19,6 +19,7 @@ #include +#include "private.h" #include "linphone/utils/utils.h" #include "paths-android.h" @@ -28,13 +29,21 @@ LINPHONE_BEGIN_NAMESPACE const std::string &SysPaths::getDataPath (void *context) { - //TODO. - return Utils::getEmptyConstRefObject(); + if (!context) { + return Utils::getEmptyConstRefObject(); + } + + AndroidPlatformHelper *helper = static_cast(context); + return helper->getDataPath(); } const std::string &SysPaths::getConfigPath (void *context) { - //TODO. - return Utils::getEmptyConstRefObject(); + if (!context) { + return Utils::getEmptyConstRefObject(); + } + + AndroidPlatformHelper *helper = static_cast(context); + return helper->getConfigPath(); } LINPHONE_END_NAMESPACE diff --git a/src/utils/paths/paths-android.h b/src/utils/paths/paths-android.h index 7cd7efd91..7822cc993 100644 --- a/src/utils/paths/paths-android.h +++ b/src/utils/paths/paths-android.h @@ -28,9 +28,10 @@ LINPHONE_BEGIN_NAMESPACE +class PlatformHelper; namespace SysPaths { - LINPHONE_PUBLIC const std::string &getDataPath (void *context); - LINPHONE_PUBLIC const std::string &getConfigPath (void *context); + LINPHONE_PUBLIC const std::string &getDataPath (PlatformHelper *platformHelper); + LINPHONE_PUBLIC const std::string &getConfigPath (PlatformHelper *platformHelper); } LINPHONE_END_NAMESPACE diff --git a/src/utils/paths/paths-apple.h b/src/utils/paths/paths-apple.h index db0cd35ff..4cb7fe237 100644 --- a/src/utils/paths/paths-apple.h +++ b/src/utils/paths/paths-apple.h @@ -28,9 +28,10 @@ LINPHONE_BEGIN_NAMESPACE +class PlatformHelper; namespace SysPaths { - LINPHONE_PUBLIC const std::string &getDataPath (void *context); - LINPHONE_PUBLIC const std::string &getConfigPath (void *context); + LINPHONE_PUBLIC const std::string &getDataPath (PlatformHelper *platformHelper); + LINPHONE_PUBLIC const std::string &getConfigPath (PlatformHelper *platformHelper); } LINPHONE_END_NAMESPACE diff --git a/src/utils/paths/paths-apple.mm b/src/utils/paths/paths-apple.mm index a9f65b248..62be4965f 100644 --- a/src/utils/paths/paths-apple.mm +++ b/src/utils/paths/paths-apple.mm @@ -19,6 +19,7 @@ #import "linphone/utils/utils.h" +#include "private.h" #import "paths-apple.h" #ifdef __OBJC__ @@ -29,7 +30,7 @@ LINPHONE_BEGIN_NAMESPACE -const std::string &SysPaths::getDataPath (void *context) { +const std::string &SysPaths::getDataPath (PlatformHelper *platformHelper) { #ifdef __OBJC__ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); NSString *writablePath = [paths objectAtIndex:0]; @@ -40,7 +41,7 @@ const std::string &SysPaths::getDataPath (void *context) { return Utils::getEmptyConstRefObject(); } -const std::string &SysPaths::getConfigPath (void *context) { +const std::string &SysPaths::getConfigPath (PlatformHelper *platformHelper) { #ifdef __OBJC__ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); NSString *configPath = [paths objectAtIndex:0]; diff --git a/src/utils/paths/paths-linux.cpp b/src/utils/paths/paths-linux.cpp index 11f47d29c..9e79c8d6f 100644 --- a/src/utils/paths/paths-linux.cpp +++ b/src/utils/paths/paths-linux.cpp @@ -17,6 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "private.h" #include "linphone/utils/utils.h" #include "paths-linux.h" @@ -25,12 +26,12 @@ LINPHONE_BEGIN_NAMESPACE -const std::string &SysPaths::getDataPath (void *context) { +const std::string &SysPaths::getDataPath (PlatformHelper *platformHelper) { //TODO. return Utils::getEmptyConstRefObject(); } -const std::string &SysPaths::getConfigPath (void *context) { +const std::string &SysPaths::getConfigPath (PlatformHelper *platformHelper) { //TODO. return Utils::getEmptyConstRefObject(); } diff --git a/src/utils/paths/paths-linux.h b/src/utils/paths/paths-linux.h index 85a1f284e..6e4780d41 100644 --- a/src/utils/paths/paths-linux.h +++ b/src/utils/paths/paths-linux.h @@ -28,9 +28,10 @@ LINPHONE_BEGIN_NAMESPACE +class PlatformHelper; namespace SysPaths { - LINPHONE_PUBLIC const std::string &getDataPath (void *context); - LINPHONE_PUBLIC const std::string &getConfigPath (void *context); + LINPHONE_PUBLIC const std::string &getDataPath (PlatformHelper *platformHelper); + LINPHONE_PUBLIC const std::string &getConfigPath (PlatformHelper *platformHelper); } LINPHONE_END_NAMESPACE diff --git a/src/utils/paths/paths-windows.cpp b/src/utils/paths/paths-windows.cpp index fc6ec22f3..9ad20b968 100644 --- a/src/utils/paths/paths-windows.cpp +++ b/src/utils/paths/paths-windows.cpp @@ -17,6 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "private.h" #include "linphone/utils/utils.h" #include "paths-windows.h" @@ -25,12 +26,12 @@ LINPHONE_BEGIN_NAMESPACE -const std::string &SysPaths::getDataPath (void *context) { +const std::string &SysPaths::getDataPath (PlatformHelper *platformHelper) { //TODO. return Utils::getEmptyConstRefObject(); } -const std::string &SysPaths::getConfigPath (void *context) { +const std::string &SysPaths::getConfigPath (PlatformHelper *platformHelper) { //TODO. return Utils::getEmptyConstRefObject(); } diff --git a/src/utils/paths/paths-windows.h b/src/utils/paths/paths-windows.h index b67b65e7a..f0f9b387a 100644 --- a/src/utils/paths/paths-windows.h +++ b/src/utils/paths/paths-windows.h @@ -28,9 +28,10 @@ LINPHONE_BEGIN_NAMESPACE +class PlatformHelper; namespace SysPaths { - LINPHONE_PUBLIC const std::string &getDataPath (void *context); - LINPHONE_PUBLIC const std::string &getConfigPath (void *context); + LINPHONE_PUBLIC const std::string &getDataPath (PlatformHelper *platformHelper); + LINPHONE_PUBLIC const std::string &getConfigPath (PlatformHelper *platformHelper); } LINPHONE_END_NAMESPACE diff --git a/src/utils/paths/paths.cpp b/src/utils/paths/paths.cpp index e3a937fff..16e652547 100644 --- a/src/utils/paths/paths.cpp +++ b/src/utils/paths/paths.cpp @@ -17,6 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "private.h" #include "linphone/utils/paths.h" #ifdef __APPLE__ @@ -37,13 +38,13 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -const string &Paths::getPath (Paths::Type type, void *context) { +const string &Paths::getPath (Paths::Type type, PlatformHelper *platformHelper) { switch (type) { case Data: - return SysPaths::getDataPath(context); + return SysPaths::getDataPath(platformHelper); case Config: default: - return SysPaths::getConfigPath(context); + return SysPaths::getConfigPath(platformHelper); } } From 86dd768ae98096fdc536e1d78eea59164877f8f8 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 19 Oct 2017 14:11:27 +0200 Subject: [PATCH 0583/2215] fix android build --- src/utils/paths/paths-android.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/utils/paths/paths-android.cpp b/src/utils/paths/paths-android.cpp index bce2b600e..cf846471e 100644 --- a/src/utils/paths/paths-android.cpp +++ b/src/utils/paths/paths-android.cpp @@ -28,22 +28,18 @@ LINPHONE_BEGIN_NAMESPACE -const std::string &SysPaths::getDataPath (void *context) { - if (!context) { +const std::string &SysPaths::getDataPath (PlatformHelper *platformHelper) { + if (!platformHelper) { return Utils::getEmptyConstRefObject(); } - - AndroidPlatformHelper *helper = static_cast(context); - return helper->getDataPath(); + return platformHelper->getDataPath(); } -const std::string &SysPaths::getConfigPath (void *context) { - if (!context) { +const std::string &SysPaths::getConfigPath (PlatformHelper *platformHelper) { + if (!platformHelper) { return Utils::getEmptyConstRefObject(); } - - AndroidPlatformHelper *helper = static_cast(context); - return helper->getConfigPath(); + return platformHelper->getConfigPath(); } LINPHONE_END_NAMESPACE From 04b6f1386dba279087f1ea54e979ce728e38f1ec Mon Sep 17 00:00:00 2001 From: Erwan Croze Date: Thu, 14 Sep 2017 11:40:30 +0200 Subject: [PATCH 0584/2215] Adding and implementing find_contacts_by_char --- coreapi/linphonecore.c | 29 +++++++++++++++++++ coreapi/linphonecore_jni.cc | 24 +++++++++++++++ include/linphone/core.h | 9 ++++++ .../org/linphone/core/LinphoneCore.java | 8 +++++ .../org/linphone/core/LinphoneCoreImpl.java | 6 +++- 5 files changed, 75 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ad1331b12..8e8ab2df0 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2587,6 +2587,35 @@ void linphone_core_add_friend_list(LinphoneCore *lc, LinphoneFriendList *list) { linphone_core_notify_friend_list_created(lc, list); } +const bctbx_list_t * linphone_core_find_contacts_by_char(LinphoneCore *core, const char *filter, bool_t sip_only) { + // Get sipuri from filter if possible + bctbx_list_t *list, *_list = NULL; + LinphoneAddress *addr = linphone_core_interpret_url(core, (sip_only) ? filter : ""); + bctbx_list_t* listFriendsList = (bctbx_list_t*)linphone_core_get_friends_lists(core); + bctbx_list_t* listFriend = (listFriendsList != NULL) + ? (bctbx_list_t*)linphone_friend_list_get_friends((LinphoneFriendList*)listFriendsList->data) : NULL; + + if (addr != NULL) + list = bctbx_list_new(addr); + + while (listFriend != NULL && listFriend->data != NULL) { + LinphoneAddress *buff = (LinphoneAddress*)linphone_friend_get_address((LinphoneFriend*)listFriend->data); + if (buff != NULL) { + bctbx_list_t *new_list = bctbx_list_new(buff); + if (list == NULL) { + _list = list = new_list; + } else { + if (_list == NULL) _list = list; + _list->next = new_list; + _list = _list->next; + } + } + listFriend = listFriend->next; + } + + return list; +} + void linphone_core_enable_audio_adaptive_jittcomp(LinphoneCore* lc, bool_t val) { lc->rtp_conf.audio_adaptive_jitt_comp_enabled = val; } diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 8a3687f07..49450e0a8 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2436,6 +2436,30 @@ extern "C" jobjectArray Java_org_linphone_core_LinphoneCoreImpl_getFriendLists(J return jFriends; } +extern "C" jobjectArray Java_org_linphone_core_LinphoneCoreImpl_findContactsByChar(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jstring jfilter + ,jboolean jsiponly) { + const char* filter = GetStringUTFChars(env, jfilter); + const bctbx_list_t* contacts = linphone_core_find_contacts_by_char((LinphoneCore*)lc, filter, jsiponly); + size_t contactsSize = bctbx_list_size(contacts); + LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data((LinphoneCore *)lc); + jobjectArray jContacts = env->NewObjectArray(contactsSize, ljb->addressClass, NULL); + + for (size_t i = 0; i < contactsSize; i++) { + LinphoneAddress *addr = (LinphoneAddress*)contacts->data; + jobject jcontact = env->NewObject(ljb->addressClass, ljb->addressCtrId, (jlong)addr); + if(jcontact != NULL){ + env->SetObjectArrayElement(jContacts, i, jcontact); + } + contacts = contacts->next; + } + ReleaseStringUTFChars(env, jfilter, filter); + + return jContacts; +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPresenceInfo(JNIEnv* env ,jobject thiz ,jlong lc diff --git a/include/linphone/core.h b/include/linphone/core.h index 68dee15fc..336d1d7c4 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -5250,6 +5250,15 @@ LINPHONE_PUBLIC const bctbx_list_t * linphone_core_get_friends_lists(const Linph */ LINPHONE_PUBLIC LinphoneFriendList * linphone_core_get_default_friend_list(const LinphoneCore *lc); +/** + * Retrieves a list of LinphoneAddress sort and filter + * @param[in] lc LinphoneCore object + * @param[in] filter Chars used for the filter* + * @param[in] sip_only Only sip address or not + * @return \bctbx_list{LinphoneAddress} a list of filtered LinphoneAddress + the LinphoneAddress created with the filter +**/ +LINPHONE_PUBLIC const bctbx_list_t * linphone_core_find_contacts_by_char(LinphoneCore *core, const char *filter, bool_t sip_only); + /** * Create a LinphonePresenceActivity with the given type and description. * @param[in] lc #LinphoneCore object. diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index db64a5c82..c7abd5303 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -1100,6 +1100,14 @@ public interface LinphoneCore { */ LinphoneFriendList[] getFriendLists(); + /** + * Get filtered list by filter + * @param filter + * @param sipOnly get only sip address + * @return LinphoneAddress list + */ + LinphoneAddress[] findContactsByChar(String filter, boolean sipOnly); + /** * Set my presence status * @param minutes_away how long in away diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index cd076e837..b300a7fc0 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -195,7 +195,6 @@ class LinphoneCoreImpl implements LinphoneCore { private native Object createFriend(long nativePtr); private native Object createFriendWithAddress(long nativePtr, String address); private native int getIncomingTimeout(long nativePtr); - LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig, File factoryConfig, Object userdata, Object context) throws IOException { mListener = listener; String user = userConfig == null ? null : userConfig.getCanonicalPath(); @@ -495,6 +494,11 @@ class LinphoneCoreImpl implements LinphoneCore { return getFriendLists(nativePtr); } + private native LinphoneAddress[] findContactsByChar(long nativePtr, String filter, boolean sipOnly); + public synchronized LinphoneAddress[] findContactsByChar(String filter, boolean sipOnly) { + return findContactsByChar(nativePtr, filter, sipOnly); + } + @SuppressWarnings("deprecation") public synchronized void setPresenceInfo(int minutes_away, String alternative_contact, OnlineStatus status) { setPresenceInfo(nativePtr, minutes_away, alternative_contact, status.mValue); From 317a50848ad60c2a819cf70c14c1b63a0eb5afcc Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 19 Oct 2017 14:52:47 +0200 Subject: [PATCH 0585/2215] move platform-helpers and paths --- coreapi/CMakeLists.txt | 3 --- coreapi/private.h | 2 +- include/CMakeLists.txt | 1 - src/CMakeLists.txt | 21 +++++++++++-------- src/core/core.cpp | 16 ++++++++++---- src/core/core.h | 2 ++ src/{utils => core}/paths/paths-android.cpp | 2 +- src/{utils => core}/paths/paths-android.h | 0 src/{utils => core}/paths/paths-apple.h | 0 src/{utils => core}/paths/paths-apple.mm | 2 +- src/{utils => core}/paths/paths-linux.cpp | 2 +- src/{utils => core}/paths/paths-linux.h | 0 src/{utils => core}/paths/paths-windows.cpp | 2 +- src/{utils => core}/paths/paths-windows.h | 0 src/{utils => core}/paths/paths.cpp | 4 ++-- .../linphone/utils => src/core/paths}/paths.h | 0 .../platform-helpers}/android-helpers.cpp | 1 - .../platform-helpers}/platform-helpers.cpp | 0 .../core/platform-helpers}/platform-helpers.h | 3 +++ 19 files changed, 36 insertions(+), 25 deletions(-) rename src/{utils => core}/paths/paths-android.cpp (96%) rename src/{utils => core}/paths/paths-android.h (100%) rename src/{utils => core}/paths/paths-apple.h (100%) rename src/{utils => core}/paths/paths-apple.mm (97%) rename src/{utils => core}/paths/paths-linux.cpp (96%) rename src/{utils => core}/paths/paths-linux.h (100%) rename src/{utils => core}/paths/paths-windows.cpp (96%) rename src/{utils => core}/paths/paths-windows.h (100%) rename src/{utils => core}/paths/paths.cpp (95%) rename {include/linphone/utils => src/core/paths}/paths.h (100%) rename {coreapi => src/core/platform-helpers}/android-helpers.cpp (99%) rename {coreapi => src/core/platform-helpers}/platform-helpers.cpp (100%) rename {coreapi => src/core/platform-helpers}/platform-helpers.h (98%) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 11a8604fc..f0a3bfdd6 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -47,7 +47,6 @@ list(APPEND LINPHONE_PRIVATE_HEADER_FILES sqlite3_bctbx_vfs.h vcard_private.h xml2lpc.h - platform-helpers.h ) set(LINPHONE_SOURCE_FILES_C @@ -111,8 +110,6 @@ set(LINPHONE_SOURCE_FILES_C set(LINPHONE_SOURCE_FILES_CXX conference.cc tester_utils.cpp - platform-helpers.cpp - android-helpers.cpp ) set(LINPHONE_INCLUDE_DIRS ${LINPHONE_INCLUDE_DIRS}) if(ENABLE_JAVA_WRAPPER) diff --git a/coreapi/private.h b/coreapi/private.h index 4cf7346a0..e00100c3f 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -42,7 +42,7 @@ #include "sal/register-op.h" #ifdef __cplusplus -#include "platform-helpers.h" +#include "core/platform-helpers/platform-helpers.h" #endif #include "linphone/sipsetup.h" diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 18579565f..31f1c52d6 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -100,7 +100,6 @@ set(UTILS_HEADER_FILES enum-generator.h general.h magic-macros.h - paths.h utils.h ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bc07f9dab..3dcdcfb6c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -81,6 +81,8 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES content/content.h core/core-p.h core/core.h + core/paths/paths.h + core/platform-helpers/platform-helpers.h db/abstract/abstract-db-p.h db/abstract/abstract-db.h db/main-db-p.h @@ -169,6 +171,8 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES content/content-type.cpp content/content.cpp core/core.cpp + core/paths/paths.cpp + core/platform-helpers/platform-helpers.cpp db/abstract/abstract-db.cpp db/main-db.cpp db/session/db-session-provider.cpp @@ -199,7 +203,6 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES sal/register-op.cpp sal/sal.cpp utils/general.cpp - utils/paths/paths.cpp utils/payload-type-handler.cpp utils/utils.cpp variant/variant.cpp @@ -210,20 +213,20 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES set(LINPHONE_OBJC_SOURCE_FILES) if (APPLE) - list(APPEND LINPHONE_OBJC_SOURCE_FILES utils/paths/paths-apple.mm) - list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES utils/paths/paths-apple.h) + list(APPEND LINPHONE_OBJC_SOURCE_FILES core/paths/paths-apple.mm) + list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/paths/paths-apple.h) elseif(ANDROID) - list(APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES utils/paths/paths-android.cpp) - list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES utils/paths/paths-android.h) + list(APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES core/paths/paths-android.cpp core/platform-helpers/android-helpers.cpp) + list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/paths/paths-android.h) elseif(WIN32) - list(APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES utils/paths/paths-windows.cpp) - list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES utils/paths/paths-windows.h) + list(APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES core/paths/paths-windows.cpp) + list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/paths/paths-windows.h) elseif(UNIX) - list(APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES utils/paths/paths-linux.cpp) - list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES utils/paths/paths-linux.h) + list(APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES core/paths/paths-linux.cpp) + list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/paths/paths-linux.h) endif() set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS} ${LIBXSD_INCLUDE_DIRS}) diff --git a/src/core/core.cpp b/src/core/core.cpp index bf9dfa3c0..27fcd0e32 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -24,13 +24,11 @@ #include "core-p.h" #include "db/main-db.h" #include "linphone/core.h" -#include "linphone/utils/paths.h" #include "object/object-p.h" +#include "paths/paths.h" #include "private.h" -#include "core.h" - // ============================================================================= using namespace std; @@ -50,7 +48,7 @@ Core::Core (LinphoneCore *cCore) : Object(*new CorePrivate) { : MainDb::Sqlite3; d->mainDb.connect(backend, uri); } else { - string path = Paths::getPath(Paths::Data, static_cast(cCore->platform_helper)); + string path = getDataPath(); //d->mainDb.connect(MainDb::Sqlite3, linphone_factory_get_writable_dir()/linphone.db); } } @@ -71,6 +69,16 @@ const list> &Core::getChatRooms () const { return d->chatRooms; } +const std::string &Core::getDataPath() const { + L_D(); + return Paths::getPath(Paths::Data, static_cast(d->cCore->platform_helper)); +} + +const std::string &Core::getConfigPath() const { + L_D(); + return Paths::getPath(Paths::Config, static_cast(d->cCore->platform_helper)); +} + // ----------------------------------------------------------------------------- LINPHONE_END_NAMESPACE diff --git a/src/core/core.h b/src/core/core.h index a23b79f52..6a6086989 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -39,6 +39,8 @@ public: std::shared_ptr createClientGroupChatRoom (const std::string &subject); std::shared_ptr getOrCreateChatRoom (const std::string &peerAddress, bool isRtt = false) const; const std::list> &getChatRooms () const; + const std::string &getDataPath() const; + const std::string &getConfigPath() const; private: L_DECLARE_PRIVATE(Core); diff --git a/src/utils/paths/paths-android.cpp b/src/core/paths/paths-android.cpp similarity index 96% rename from src/utils/paths/paths-android.cpp rename to src/core/paths/paths-android.cpp index cf846471e..52ac08424 100644 --- a/src/utils/paths/paths-android.cpp +++ b/src/core/paths/paths-android.cpp @@ -19,7 +19,7 @@ #include -#include "private.h" +#include "core/platform-helpers/platform-helpers.h" #include "linphone/utils/utils.h" #include "paths-android.h" diff --git a/src/utils/paths/paths-android.h b/src/core/paths/paths-android.h similarity index 100% rename from src/utils/paths/paths-android.h rename to src/core/paths/paths-android.h diff --git a/src/utils/paths/paths-apple.h b/src/core/paths/paths-apple.h similarity index 100% rename from src/utils/paths/paths-apple.h rename to src/core/paths/paths-apple.h diff --git a/src/utils/paths/paths-apple.mm b/src/core/paths/paths-apple.mm similarity index 97% rename from src/utils/paths/paths-apple.mm rename to src/core/paths/paths-apple.mm index 62be4965f..6b13317a4 100644 --- a/src/utils/paths/paths-apple.mm +++ b/src/core/paths/paths-apple.mm @@ -19,7 +19,7 @@ #import "linphone/utils/utils.h" -#include "private.h" +#include "core/platform-helpers/platform-helpers.h" #import "paths-apple.h" #ifdef __OBJC__ diff --git a/src/utils/paths/paths-linux.cpp b/src/core/paths/paths-linux.cpp similarity index 96% rename from src/utils/paths/paths-linux.cpp rename to src/core/paths/paths-linux.cpp index 9e79c8d6f..b52bc05ff 100644 --- a/src/utils/paths/paths-linux.cpp +++ b/src/core/paths/paths-linux.cpp @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "private.h" +#include "core/platform-helpers/platform-helpers.h" #include "linphone/utils/utils.h" #include "paths-linux.h" diff --git a/src/utils/paths/paths-linux.h b/src/core/paths/paths-linux.h similarity index 100% rename from src/utils/paths/paths-linux.h rename to src/core/paths/paths-linux.h diff --git a/src/utils/paths/paths-windows.cpp b/src/core/paths/paths-windows.cpp similarity index 96% rename from src/utils/paths/paths-windows.cpp rename to src/core/paths/paths-windows.cpp index 9ad20b968..85d75c7be 100644 --- a/src/utils/paths/paths-windows.cpp +++ b/src/core/paths/paths-windows.cpp @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "private.h" +#include "core/platform-helpers/platform-helpers.h" #include "linphone/utils/utils.h" #include "paths-windows.h" diff --git a/src/utils/paths/paths-windows.h b/src/core/paths/paths-windows.h similarity index 100% rename from src/utils/paths/paths-windows.h rename to src/core/paths/paths-windows.h diff --git a/src/utils/paths/paths.cpp b/src/core/paths/paths.cpp similarity index 95% rename from src/utils/paths/paths.cpp rename to src/core/paths/paths.cpp index 16e652547..f8c0be1f4 100644 --- a/src/utils/paths/paths.cpp +++ b/src/core/paths/paths.cpp @@ -17,8 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "private.h" -#include "linphone/utils/paths.h" +#include "core/platform-helpers/platform-helpers.h" +#include "paths.h" #ifdef __APPLE__ #include "paths-apple.h" diff --git a/include/linphone/utils/paths.h b/src/core/paths/paths.h similarity index 100% rename from include/linphone/utils/paths.h rename to src/core/paths/paths.h diff --git a/coreapi/android-helpers.cpp b/src/core/platform-helpers/android-helpers.cpp similarity index 99% rename from coreapi/android-helpers.cpp rename to src/core/platform-helpers/android-helpers.cpp index afc4e2937..5b2812009 100644 --- a/coreapi/android-helpers.cpp +++ b/src/core/platform-helpers/android-helpers.cpp @@ -20,7 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/utils/utils.h" #include "private.h" -#include "platform-helpers.h" #ifdef __ANDROID__ diff --git a/coreapi/platform-helpers.cpp b/src/core/platform-helpers/platform-helpers.cpp similarity index 100% rename from coreapi/platform-helpers.cpp rename to src/core/platform-helpers/platform-helpers.cpp diff --git a/coreapi/platform-helpers.h b/src/core/platform-helpers/platform-helpers.h similarity index 98% rename from coreapi/platform-helpers.h rename to src/core/platform-helpers/platform-helpers.h index 3302a17a5..0c689a29e 100644 --- a/coreapi/platform-helpers.h +++ b/src/core/platform-helpers/platform-helpers.h @@ -20,6 +20,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef platform_helpers_h #define platform_helpers_h +#include + +#include "linphone/core.h" #include "linphone/utils/general.h" LINPHONE_BEGIN_NAMESPACE From aea1b1229d832453c45151c1780be3b3d17cfa6b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 19 Oct 2017 15:03:11 +0200 Subject: [PATCH 0586/2215] Replaced virtual by override --- src/core/platform-helpers/android-helpers.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/core/platform-helpers/android-helpers.cpp b/src/core/platform-helpers/android-helpers.cpp index 5b2812009..b4fd1b1e6 100644 --- a/src/core/platform-helpers/android-helpers.cpp +++ b/src/core/platform-helpers/android-helpers.cpp @@ -30,15 +30,15 @@ LINPHONE_BEGIN_NAMESPACE class AndroidPlatformHelpers : public PlatformHelpers { public: AndroidPlatformHelpers (LinphoneCore *lc, void *system_context); - virtual void setDnsServers (); - virtual void acquireWifiLock (); - virtual void releaseWifiLock (); - virtual void acquireMcastLock (); - virtual void releaseMcastLock (); - virtual void acquireCpuLock (); - virtual void releaseCpuLock (); - virtual std::string getDataPath (); - virtual std::string getConfigPath (); + void setDnsServers () override; + void acquireWifiLock () override; + void releaseWifiLock () override; + void acquireMcastLock () override; + void releaseMcastLock () override; + void acquireCpuLock () override; + void releaseCpuLock () override; + std::string getDataPath () override; + std::string getConfigPath () override; ~AndroidPlatformHelpers (); private: int callVoidMethod (jmethodID id); From 1b82a7570e68089af343bd349b7833d514538005 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 19 Oct 2017 15:06:49 +0200 Subject: [PATCH 0587/2215] use right class name ... --- src/core/core.cpp | 4 ++-- src/core/paths/paths-android.cpp | 4 ++-- src/core/paths/paths-android.h | 6 +++--- src/core/paths/paths-apple.h | 6 +++--- src/core/paths/paths-apple.mm | 4 ++-- src/core/paths/paths-linux.cpp | 4 ++-- src/core/paths/paths-linux.h | 6 +++--- src/core/paths/paths-windows.cpp | 4 ++-- src/core/paths/paths-windows.h | 6 +++--- src/core/paths/paths.cpp | 2 +- src/core/paths/paths.h | 4 ++-- src/core/platform-helpers/platform-helpers.h | 6 +++--- 12 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 27fcd0e32..9b43fe38c 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -71,12 +71,12 @@ const list> &Core::getChatRooms () const { const std::string &Core::getDataPath() const { L_D(); - return Paths::getPath(Paths::Data, static_cast(d->cCore->platform_helper)); + return Paths::getPath(Paths::Data, static_cast(d->cCore->platform_helper)); } const std::string &Core::getConfigPath() const { L_D(); - return Paths::getPath(Paths::Config, static_cast(d->cCore->platform_helper)); + return Paths::getPath(Paths::Config, static_cast(d->cCore->platform_helper)); } // ----------------------------------------------------------------------------- diff --git a/src/core/paths/paths-android.cpp b/src/core/paths/paths-android.cpp index 52ac08424..84533965d 100644 --- a/src/core/paths/paths-android.cpp +++ b/src/core/paths/paths-android.cpp @@ -28,14 +28,14 @@ LINPHONE_BEGIN_NAMESPACE -const std::string &SysPaths::getDataPath (PlatformHelper *platformHelper) { +const std::string &SysPaths::getDataPath (PlatformHelpers *platformHelper) { if (!platformHelper) { return Utils::getEmptyConstRefObject(); } return platformHelper->getDataPath(); } -const std::string &SysPaths::getConfigPath (PlatformHelper *platformHelper) { +const std::string &SysPaths::getConfigPath (PlatformHelpers *platformHelper) { if (!platformHelper) { return Utils::getEmptyConstRefObject(); } diff --git a/src/core/paths/paths-android.h b/src/core/paths/paths-android.h index 7822cc993..ab4848028 100644 --- a/src/core/paths/paths-android.h +++ b/src/core/paths/paths-android.h @@ -28,10 +28,10 @@ LINPHONE_BEGIN_NAMESPACE -class PlatformHelper; +class PlatformHelpers; namespace SysPaths { - LINPHONE_PUBLIC const std::string &getDataPath (PlatformHelper *platformHelper); - LINPHONE_PUBLIC const std::string &getConfigPath (PlatformHelper *platformHelper); + LINPHONE_PUBLIC const std::string &getDataPath (PlatformHelpers *platformHelper); + LINPHONE_PUBLIC const std::string &getConfigPath (PlatformHelpers *platformHelper); } LINPHONE_END_NAMESPACE diff --git a/src/core/paths/paths-apple.h b/src/core/paths/paths-apple.h index 4cb7fe237..f8b031892 100644 --- a/src/core/paths/paths-apple.h +++ b/src/core/paths/paths-apple.h @@ -28,10 +28,10 @@ LINPHONE_BEGIN_NAMESPACE -class PlatformHelper; +class PlatformHelpers; namespace SysPaths { - LINPHONE_PUBLIC const std::string &getDataPath (PlatformHelper *platformHelper); - LINPHONE_PUBLIC const std::string &getConfigPath (PlatformHelper *platformHelper); + LINPHONE_PUBLIC const std::string &getDataPath (PlatformHelpers *platformHelper); + LINPHONE_PUBLIC const std::string &getConfigPath (PlatformHelpers *platformHelper); } LINPHONE_END_NAMESPACE diff --git a/src/core/paths/paths-apple.mm b/src/core/paths/paths-apple.mm index 6b13317a4..e4d272713 100644 --- a/src/core/paths/paths-apple.mm +++ b/src/core/paths/paths-apple.mm @@ -30,7 +30,7 @@ LINPHONE_BEGIN_NAMESPACE -const std::string &SysPaths::getDataPath (PlatformHelper *platformHelper) { +const std::string &SysPaths::getDataPath (PlatformHelpers *platformHelper) { #ifdef __OBJC__ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); NSString *writablePath = [paths objectAtIndex:0]; @@ -41,7 +41,7 @@ const std::string &SysPaths::getDataPath (PlatformHelper *platformHelper) { return Utils::getEmptyConstRefObject(); } -const std::string &SysPaths::getConfigPath (PlatformHelper *platformHelper) { +const std::string &SysPaths::getConfigPath (PlatformHelpers *platformHelper) { #ifdef __OBJC__ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); NSString *configPath = [paths objectAtIndex:0]; diff --git a/src/core/paths/paths-linux.cpp b/src/core/paths/paths-linux.cpp index b52bc05ff..f1662690c 100644 --- a/src/core/paths/paths-linux.cpp +++ b/src/core/paths/paths-linux.cpp @@ -26,12 +26,12 @@ LINPHONE_BEGIN_NAMESPACE -const std::string &SysPaths::getDataPath (PlatformHelper *platformHelper) { +const std::string &SysPaths::getDataPath (PlatformHelpers *platformHelper) { //TODO. return Utils::getEmptyConstRefObject(); } -const std::string &SysPaths::getConfigPath (PlatformHelper *platformHelper) { +const std::string &SysPaths::getConfigPath (PlatformHelpers *platformHelper) { //TODO. return Utils::getEmptyConstRefObject(); } diff --git a/src/core/paths/paths-linux.h b/src/core/paths/paths-linux.h index 6e4780d41..6e7f4e4c5 100644 --- a/src/core/paths/paths-linux.h +++ b/src/core/paths/paths-linux.h @@ -28,10 +28,10 @@ LINPHONE_BEGIN_NAMESPACE -class PlatformHelper; +class PlatformHelpers; namespace SysPaths { - LINPHONE_PUBLIC const std::string &getDataPath (PlatformHelper *platformHelper); - LINPHONE_PUBLIC const std::string &getConfigPath (PlatformHelper *platformHelper); + LINPHONE_PUBLIC const std::string &getDataPath (PlatformHelpers *platformHelper); + LINPHONE_PUBLIC const std::string &getConfigPath (PlatformHelpers *platformHelper); } LINPHONE_END_NAMESPACE diff --git a/src/core/paths/paths-windows.cpp b/src/core/paths/paths-windows.cpp index 85d75c7be..749f62afa 100644 --- a/src/core/paths/paths-windows.cpp +++ b/src/core/paths/paths-windows.cpp @@ -26,12 +26,12 @@ LINPHONE_BEGIN_NAMESPACE -const std::string &SysPaths::getDataPath (PlatformHelper *platformHelper) { +const std::string &SysPaths::getDataPath (PlatformHelpers *platformHelper) { //TODO. return Utils::getEmptyConstRefObject(); } -const std::string &SysPaths::getConfigPath (PlatformHelper *platformHelper) { +const std::string &SysPaths::getConfigPath (PlatformHelpers *platformHelper) { //TODO. return Utils::getEmptyConstRefObject(); } diff --git a/src/core/paths/paths-windows.h b/src/core/paths/paths-windows.h index f0f9b387a..7390b3b83 100644 --- a/src/core/paths/paths-windows.h +++ b/src/core/paths/paths-windows.h @@ -28,10 +28,10 @@ LINPHONE_BEGIN_NAMESPACE -class PlatformHelper; +class PlatformHelpers; namespace SysPaths { - LINPHONE_PUBLIC const std::string &getDataPath (PlatformHelper *platformHelper); - LINPHONE_PUBLIC const std::string &getConfigPath (PlatformHelper *platformHelper); + LINPHONE_PUBLIC const std::string &getDataPath (PlatformHelpers *platformHelper); + LINPHONE_PUBLIC const std::string &getConfigPath (PlatformHelpers *platformHelper); } LINPHONE_END_NAMESPACE diff --git a/src/core/paths/paths.cpp b/src/core/paths/paths.cpp index f8c0be1f4..c9172c454 100644 --- a/src/core/paths/paths.cpp +++ b/src/core/paths/paths.cpp @@ -38,7 +38,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -const string &Paths::getPath (Paths::Type type, PlatformHelper *platformHelper) { +const string &Paths::getPath (Paths::Type type, PlatformHelpers *platformHelper) { switch (type) { case Data: return SysPaths::getDataPath(platformHelper); diff --git a/src/core/paths/paths.h b/src/core/paths/paths.h index 70deea899..ae4355f2b 100644 --- a/src/core/paths/paths.h +++ b/src/core/paths/paths.h @@ -28,14 +28,14 @@ LINPHONE_BEGIN_NAMESPACE -class PlatformHelper; +class PlatformHelpers; namespace Paths { enum Type { Data, Config }; - LINPHONE_PUBLIC const std::string &getPath(Type type, PlatformHelper *platformHelper); + LINPHONE_PUBLIC const std::string &getPath(Type type, PlatformHelpers *platformHelper); } LINPHONE_END_NAMESPACE diff --git a/src/core/platform-helpers/platform-helpers.h b/src/core/platform-helpers/platform-helpers.h index 0c689a29e..02c312629 100644 --- a/src/core/platform-helpers/platform-helpers.h +++ b/src/core/platform-helpers/platform-helpers.h @@ -17,8 +17,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef platform_helpers_h -#define platform_helpers_h +#ifndef _PLATFORM_HELPERS_H_ +#define _PLATFORM_HELPERS_H_ #include @@ -69,4 +69,4 @@ PlatformHelpers *createAndroidPlatformHelpers (LinphoneCore *lc, void *system_co LINPHONE_END_NAMESPACE -#endif +#endif // indef _PLATFORM_HELPERS_H_ From f291076f8816ca634b4e815eded9786a96e9f28a Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 19 Oct 2017 15:18:23 +0200 Subject: [PATCH 0588/2215] remove const to fix build --- src/core/core.cpp | 4 ++-- src/core/core.h | 4 ++-- src/core/paths/paths-android.cpp | 4 ++-- src/core/paths/paths-android.h | 4 ++-- src/core/paths/paths-apple.h | 4 ++-- src/core/paths/paths-apple.mm | 4 ++-- src/core/paths/paths-linux.cpp | 4 ++-- src/core/paths/paths-linux.h | 4 ++-- src/core/paths/paths-windows.cpp | 4 ++-- src/core/paths/paths-windows.h | 4 ++-- src/core/paths/paths.cpp | 2 +- src/core/paths/paths.h | 2 +- 12 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 9b43fe38c..ac7de2350 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -69,12 +69,12 @@ const list> &Core::getChatRooms () const { return d->chatRooms; } -const std::string &Core::getDataPath() const { +string Core::getDataPath() const { L_D(); return Paths::getPath(Paths::Data, static_cast(d->cCore->platform_helper)); } -const std::string &Core::getConfigPath() const { +string Core::getConfigPath() const { L_D(); return Paths::getPath(Paths::Config, static_cast(d->cCore->platform_helper)); } diff --git a/src/core/core.h b/src/core/core.h index 6a6086989..1e1c169a5 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -39,8 +39,8 @@ public: std::shared_ptr createClientGroupChatRoom (const std::string &subject); std::shared_ptr getOrCreateChatRoom (const std::string &peerAddress, bool isRtt = false) const; const std::list> &getChatRooms () const; - const std::string &getDataPath() const; - const std::string &getConfigPath() const; + std::string getDataPath() const; + std::string getConfigPath() const; private: L_DECLARE_PRIVATE(Core); diff --git a/src/core/paths/paths-android.cpp b/src/core/paths/paths-android.cpp index 84533965d..b53adbd22 100644 --- a/src/core/paths/paths-android.cpp +++ b/src/core/paths/paths-android.cpp @@ -28,14 +28,14 @@ LINPHONE_BEGIN_NAMESPACE -const std::string &SysPaths::getDataPath (PlatformHelpers *platformHelper) { +std::string SysPaths::getDataPath (PlatformHelpers *platformHelper) { if (!platformHelper) { return Utils::getEmptyConstRefObject(); } return platformHelper->getDataPath(); } -const std::string &SysPaths::getConfigPath (PlatformHelpers *platformHelper) { +std::string SysPaths::getConfigPath (PlatformHelpers *platformHelper) { if (!platformHelper) { return Utils::getEmptyConstRefObject(); } diff --git a/src/core/paths/paths-android.h b/src/core/paths/paths-android.h index ab4848028..7661ebb59 100644 --- a/src/core/paths/paths-android.h +++ b/src/core/paths/paths-android.h @@ -30,8 +30,8 @@ LINPHONE_BEGIN_NAMESPACE class PlatformHelpers; namespace SysPaths { - LINPHONE_PUBLIC const std::string &getDataPath (PlatformHelpers *platformHelper); - LINPHONE_PUBLIC const std::string &getConfigPath (PlatformHelpers *platformHelper); + LINPHONE_PUBLIC std::string getDataPath (PlatformHelpers *platformHelper); + LINPHONE_PUBLIC std::string getConfigPath (PlatformHelpers *platformHelper); } LINPHONE_END_NAMESPACE diff --git a/src/core/paths/paths-apple.h b/src/core/paths/paths-apple.h index f8b031892..acfe25ff0 100644 --- a/src/core/paths/paths-apple.h +++ b/src/core/paths/paths-apple.h @@ -30,8 +30,8 @@ LINPHONE_BEGIN_NAMESPACE class PlatformHelpers; namespace SysPaths { - LINPHONE_PUBLIC const std::string &getDataPath (PlatformHelpers *platformHelper); - LINPHONE_PUBLIC const std::string &getConfigPath (PlatformHelpers *platformHelper); + LINPHONE_PUBLIC std::string getDataPath (PlatformHelpers *platformHelper); + LINPHONE_PUBLIC std::string getConfigPath (PlatformHelpers *platformHelper); } LINPHONE_END_NAMESPACE diff --git a/src/core/paths/paths-apple.mm b/src/core/paths/paths-apple.mm index e4d272713..97bbef63b 100644 --- a/src/core/paths/paths-apple.mm +++ b/src/core/paths/paths-apple.mm @@ -30,7 +30,7 @@ LINPHONE_BEGIN_NAMESPACE -const std::string &SysPaths::getDataPath (PlatformHelpers *platformHelper) { +std::string SysPaths::getDataPath (PlatformHelpers *platformHelper) { #ifdef __OBJC__ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); NSString *writablePath = [paths objectAtIndex:0]; @@ -41,7 +41,7 @@ const std::string &SysPaths::getDataPath (PlatformHelpers *platformHelper) { return Utils::getEmptyConstRefObject(); } -const std::string &SysPaths::getConfigPath (PlatformHelpers *platformHelper) { +std::string SysPaths::getConfigPath (PlatformHelpers *platformHelper) { #ifdef __OBJC__ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); NSString *configPath = [paths objectAtIndex:0]; diff --git a/src/core/paths/paths-linux.cpp b/src/core/paths/paths-linux.cpp index f1662690c..7dd122b18 100644 --- a/src/core/paths/paths-linux.cpp +++ b/src/core/paths/paths-linux.cpp @@ -26,12 +26,12 @@ LINPHONE_BEGIN_NAMESPACE -const std::string &SysPaths::getDataPath (PlatformHelpers *platformHelper) { +std::string SysPaths::getDataPath (PlatformHelpers *platformHelper) { //TODO. return Utils::getEmptyConstRefObject(); } -const std::string &SysPaths::getConfigPath (PlatformHelpers *platformHelper) { +std::string SysPaths::getConfigPath (PlatformHelpers *platformHelper) { //TODO. return Utils::getEmptyConstRefObject(); } diff --git a/src/core/paths/paths-linux.h b/src/core/paths/paths-linux.h index 6e7f4e4c5..cc652b833 100644 --- a/src/core/paths/paths-linux.h +++ b/src/core/paths/paths-linux.h @@ -30,8 +30,8 @@ LINPHONE_BEGIN_NAMESPACE class PlatformHelpers; namespace SysPaths { - LINPHONE_PUBLIC const std::string &getDataPath (PlatformHelpers *platformHelper); - LINPHONE_PUBLIC const std::string &getConfigPath (PlatformHelpers *platformHelper); + LINPHONE_PUBLIC std::string getDataPath (PlatformHelpers *platformHelper); + LINPHONE_PUBLIC std::string getConfigPath (PlatformHelpers *platformHelper); } LINPHONE_END_NAMESPACE diff --git a/src/core/paths/paths-windows.cpp b/src/core/paths/paths-windows.cpp index 749f62afa..94b8705ca 100644 --- a/src/core/paths/paths-windows.cpp +++ b/src/core/paths/paths-windows.cpp @@ -26,12 +26,12 @@ LINPHONE_BEGIN_NAMESPACE -const std::string &SysPaths::getDataPath (PlatformHelpers *platformHelper) { +std::string SysPaths::getDataPath (PlatformHelpers *platformHelper) { //TODO. return Utils::getEmptyConstRefObject(); } -const std::string &SysPaths::getConfigPath (PlatformHelpers *platformHelper) { +std::string SysPaths::getConfigPath (PlatformHelpers *platformHelper) { //TODO. return Utils::getEmptyConstRefObject(); } diff --git a/src/core/paths/paths-windows.h b/src/core/paths/paths-windows.h index 7390b3b83..137be1f87 100644 --- a/src/core/paths/paths-windows.h +++ b/src/core/paths/paths-windows.h @@ -30,8 +30,8 @@ LINPHONE_BEGIN_NAMESPACE class PlatformHelpers; namespace SysPaths { - LINPHONE_PUBLIC const std::string &getDataPath (PlatformHelpers *platformHelper); - LINPHONE_PUBLIC const std::string &getConfigPath (PlatformHelpers *platformHelper); + LINPHONE_PUBLIC std::string getDataPath (PlatformHelpers *platformHelper); + LINPHONE_PUBLIC std::string getConfigPath (PlatformHelpers *platformHelper); } LINPHONE_END_NAMESPACE diff --git a/src/core/paths/paths.cpp b/src/core/paths/paths.cpp index c9172c454..01987fec5 100644 --- a/src/core/paths/paths.cpp +++ b/src/core/paths/paths.cpp @@ -38,7 +38,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -const string &Paths::getPath (Paths::Type type, PlatformHelpers *platformHelper) { +string Paths::getPath (Paths::Type type, PlatformHelpers *platformHelper) { switch (type) { case Data: return SysPaths::getDataPath(platformHelper); diff --git a/src/core/paths/paths.h b/src/core/paths/paths.h index ae4355f2b..e600a067e 100644 --- a/src/core/paths/paths.h +++ b/src/core/paths/paths.h @@ -35,7 +35,7 @@ namespace Paths { Config }; - LINPHONE_PUBLIC const std::string &getPath(Type type, PlatformHelpers *platformHelper); + LINPHONE_PUBLIC std::string getPath(Type type, PlatformHelpers *platformHelper); } LINPHONE_END_NAMESPACE From d160e5ab021b22f481095f047ce6b0330e83b954 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 19 Oct 2017 15:37:35 +0200 Subject: [PATCH 0589/2215] add data and config path getter for windows --- src/core/paths/paths-windows.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/core/paths/paths-windows.cpp b/src/core/paths/paths-windows.cpp index 94b8705ca..8af9d8a4a 100644 --- a/src/core/paths/paths-windows.cpp +++ b/src/core/paths/paths-windows.cpp @@ -17,6 +17,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include +#include "shlobj.h" + #include "core/platform-helpers/platform-helpers.h" #include "linphone/utils/utils.h" @@ -24,16 +27,27 @@ // ============================================================================= +using namespace std; + LINPHONE_BEGIN_NAMESPACE -std::string SysPaths::getDataPath (PlatformHelpers *platformHelper) { - //TODO. +string SysPaths::getDataPath (PlatformHelpers *platformHelper) { + TCHAR szPath[MAX_PATH]; + // Get path for each computer, non-user specific and non-roaming data. + if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, szPath))) { + stringstream path; + path << boost::lexical_cast(szPath) << "/linphone"; + string ret = path.str(); + boost::replace_all(ret, "\\", "\\\\"); + return ret; + } + return Utils::getEmptyConstRefObject(); } -std::string SysPaths::getConfigPath (PlatformHelpers *platformHelper) { - //TODO. - return Utils::getEmptyConstRefObject(); +string SysPaths::getConfigPath (PlatformHelpers *platformHelper) { + // seems to be the same directory + return getDataPath(platformHelper); } LINPHONE_END_NAMESPACE From 2941e64e3ea0bf4561d27104eebfd9ec39e9e3e0 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 19 Oct 2017 15:50:31 +0200 Subject: [PATCH 0590/2215] feat(Core): provide a low-level BaseObject --- include/linphone/api/c-event-log.h | 9 - include/linphone/utils/general.h | 54 ++--- src/CMakeLists.txt | 5 + src/c-wrapper/api/c-address.cpp | 2 +- src/c-wrapper/api/c-call-params.cpp | 2 +- src/c-wrapper/api/c-event-log.cpp | 14 +- src/c-wrapper/internal/c-tools.h | 197 +++++++++++++----- src/chat/chat-room/client-group-chat-room.h | 2 +- src/content/content.h | 2 +- src/event-log/call/call-event.cpp | 12 -- src/event-log/call/call-event.h | 4 +- src/event-log/chat/chat-message-event.cpp | 14 -- src/event-log/chat/chat-message-event.h | 4 +- src/event-log/conference/conference-event.cpp | 13 -- src/event-log/conference/conference-event.h | 4 +- .../conference/conference-notified-event.cpp | 19 -- .../conference/conference-notified-event.h | 4 +- .../conference-participant-device-event.cpp | 22 -- .../conference-participant-device-event.h | 4 +- .../conference-participant-event.cpp | 20 -- .../conference/conference-participant-event.h | 4 +- .../conference/conference-subject-event.cpp | 13 -- .../conference/conference-subject-event.h | 6 +- src/event-log/event-log-p.h | 5 +- src/event-log/event-log.cpp | 13 +- src/event-log/event-log.h | 8 +- src/object/base-object-p.h | 47 +++++ src/object/base-object.cpp | 38 ++++ src/object/base-object.h | 56 +++++ src/object/clonable-object-p.h | 4 + src/object/clonable-object.cpp | 2 + src/object/clonable-object.h | 7 + src/object/object-head-p.h | 38 ++++ src/object/object-head.h | 29 +++ src/object/object-p.h | 9 +- src/object/object.cpp | 10 +- src/object/object.h | 11 +- 37 files changed, 443 insertions(+), 264 deletions(-) create mode 100644 src/object/base-object-p.h create mode 100644 src/object/base-object.cpp create mode 100644 src/object/base-object.h create mode 100644 src/object/object-head-p.h create mode 100644 src/object/object-head.h diff --git a/include/linphone/api/c-event-log.h b/include/linphone/api/c-event-log.h index 9d71a30e5..06840e39d 100644 --- a/include/linphone/api/c-event-log.h +++ b/include/linphone/api/c-event-log.h @@ -29,7 +29,6 @@ #endif // ifdef __cplusplus LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_new (void); -LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_clone (const LinphoneEventLog *event_log); LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_ref (LinphoneEventLog *event_log); LINPHONE_PUBLIC LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *event_log); @@ -38,7 +37,6 @@ LINPHONE_PUBLIC LinphoneCallEvent *linphone_call_event_new ( time_t time, LinphoneCall *call ); -LINPHONE_PUBLIC LinphoneCallEvent *linphone_call_event_clone (const LinphoneCallEvent *call_event); LINPHONE_PUBLIC LinphoneCall *linphone_call_event_get_call (const LinphoneCallEvent *call_event); LINPHONE_PUBLIC LinphoneConferenceEvent *linphone_conference_event_new ( @@ -46,7 +44,6 @@ LINPHONE_PUBLIC LinphoneConferenceEvent *linphone_conference_event_new ( time_t time, const LinphoneAddress *address ); -LINPHONE_PUBLIC LinphoneConferenceEvent *linphone_conference_event_clone (const LinphoneConferenceEvent *conference_event); LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_event_get_address (const LinphoneConferenceEvent *conference_event); LINPHONE_PUBLIC LinphoneConferenceParticipantEvent *linphone_conference_participant_event_new ( @@ -55,9 +52,6 @@ LINPHONE_PUBLIC LinphoneConferenceParticipantEvent *linphone_conference_particip const LinphoneAddress *conferenceAddress, const LinphoneAddress *participantAddress ); -LINPHONE_PUBLIC LinphoneConferenceParticipantEvent *linphone_conference_participant_event_clone ( - const LinphoneConferenceParticipantEvent *conference_participant_event -); LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_participant_event_get_participant_address ( const LinphoneConferenceParticipantEvent *conference_participant_event ); @@ -66,9 +60,6 @@ LINPHONE_PUBLIC LinphoneChatMessageEvent *linphone_chat_message_event_new ( LinphoneChatMessage *chat_message, time_t time ); -LINPHONE_PUBLIC LinphoneChatMessageEvent *linphone_chat_message_event_clone ( - const LinphoneChatMessageEvent *chat_message_event -); LINPHONE_PUBLIC LinphoneChatMessage *linphone_chat_message_event_get_chat_message ( const LinphoneChatMessageEvent *chat_message_event ); diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index 7ade05a19..cbd62d338 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -82,27 +82,42 @@ void l_assert (const char *condition, const char *file, int line); #define L_UNLIKELY(EXPRESSION) EXPRESSION #endif +class BaseObject; +class BaseObjectPrivate; class ClonableObject; class ClonableObjectPrivate; class Object; class ObjectPrivate; -#define L_INTERNAL_DECLARE_PRIVATE(CLASS) \ - inline CLASS ## Private *getPrivate() { \ - return reinterpret_cast(mPrivate); \ - } \ - inline const CLASS ## Private *getPrivate() const { \ - return reinterpret_cast(mPrivate); \ - } \ - friend class CLASS ## Private; \ - friend class Wrapper; +#define L_INTERNAL_CHECK_OBJECT_INHERITANCE(CLASS) \ + static_assert( \ + !(std::is_base_of::value && std::is_base_of::value), \ + "Multiple inheritance between BaseObject and ClonableObject is not allowed." \ + ); -#define L_INTERNAL_DECLARE_PRIVATE_T(CLASS, PARENT_TYPE) \ - inline CLASS ## Private *getPrivate() { \ - return reinterpret_cast(PARENT_TYPE::mPrivate); \ +#define L_INTERNAL_GET_BETTER_PRIVATE_ANCESTOR(CLASS) \ + std::conditional< \ + std::is_base_of::value, \ + BaseObject, \ + std::conditional< \ + std::is_base_of::value, \ + ClonableObject, \ + CLASS \ + >::type \ + >::type + +#define L_INTERNAL_DECLARE_PRIVATE(CLASS) \ + inline CLASS ## Private *getPrivate () { \ + L_INTERNAL_CHECK_OBJECT_INHERITANCE(CLASS); \ + return reinterpret_cast( \ + L_INTERNAL_GET_BETTER_PRIVATE_ANCESTOR(CLASS)::mPrivate \ + ); \ } \ - inline const CLASS ## Private *getPrivate() const { \ - return reinterpret_cast(PARENT_TYPE::mPrivate); \ + inline const CLASS ## Private *getPrivate () const { \ + L_INTERNAL_CHECK_OBJECT_INHERITANCE(CLASS); \ + return reinterpret_cast( \ + L_INTERNAL_GET_BETTER_PRIVATE_ANCESTOR(CLASS)::mPrivate \ + ); \ } \ friend class CLASS ## Private; \ friend class Wrapper; @@ -111,17 +126,13 @@ class ObjectPrivate; // Gives a control to C Wrapper. #ifndef LINPHONE_TESTER #define L_DECLARE_PRIVATE(CLASS) L_INTERNAL_DECLARE_PRIVATE(CLASS) - #define L_DECLARE_PRIVATE_T(CLASS, PARENT_TYPE) L_INTERNAL_DECLARE_PRIVATE_T(CLASS, PARENT_TYPE) #else #define L_DECLARE_PRIVATE(CLASS) \ L_INTERNAL_DECLARE_PRIVATE(CLASS) \ friend class Tester; - #define L_DECLARE_PRIVATE_T(CLASS, PARENT_TYPE) \ - L_INTERNAL_DECLARE_PRIVATE_T(CLASS, PARENT_TYPE) \ - friend class Tester; #endif -// Generic public helper. (Neither ClonableObject nor Object.) +// Generic public helper. (Neither ClonableObject.) // `void *` is used to avoid downcasting. template constexpr T *getPublicHelper (void *object, const void *) { @@ -135,11 +146,6 @@ inline T *getPublicHelper (const U *map, const ClonableObjectPrivate *context) { return static_cast(it->second); } -template -constexpr T *getPublicHelper (Object *object, const ObjectPrivate *) { - return static_cast(object); -} - #define L_DECLARE_PUBLIC(CLASS) \ inline CLASS *getPublic () { \ L_ASSERT(mPublic); \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3dcdcfb6c..aa0916e7b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -111,8 +111,12 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES nat/ice-agent.h nat/stun-client.h object/app-data-container.h + object/base-object-p.h + object/base-object.h object/clonable-object-p.h object/clonable-object.h + object/object-head-p.h + object/object-head.h object/object-p.h object/object.h object/property-container.h @@ -191,6 +195,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES nat/ice-agent.cpp nat/stun-client.cpp object/app-data-container.cpp + object/base-object.cpp object/clonable-object.cpp object/object.cpp object/property-container.cpp diff --git a/src/c-wrapper/api/c-address.cpp b/src/c-wrapper/api/c-address.cpp index be302f841..98e51434a 100644 --- a/src/c-wrapper/api/c-address.cpp +++ b/src/c-wrapper/api/c-address.cpp @@ -22,7 +22,7 @@ // ============================================================================= -L_DECLARE_C_CLONABLE_STRUCT_IMPL(Address); +L_DECLARE_C_CLONABLE_OBJECT_IMPL(Address); using namespace std; diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index a02639025..51e1e7295 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -23,7 +23,7 @@ // ============================================================================= -L_DECLARE_C_CLONABLE_STRUCT_IMPL(CallParams) +L_DECLARE_C_CLONABLE_OBJECT_IMPL(CallParams) using namespace std; diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index a80f76384..b1469ec0c 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -27,13 +27,13 @@ // ============================================================================= -L_DECLARE_C_CLONABLE_STRUCT_IMPL(EventLog); -L_DECLARE_C_CLONABLE_STRUCT_IMPL(CallEvent); -L_DECLARE_C_CLONABLE_STRUCT_IMPL(ConferenceEvent); -L_DECLARE_C_CLONABLE_STRUCT_IMPL(ConferenceParticipantEvent); -L_DECLARE_C_CLONABLE_STRUCT_IMPL(ConferenceParticipantDeviceEvent); -L_DECLARE_C_CLONABLE_STRUCT_IMPL(ConferenceSubjectEvent); -L_DECLARE_C_CLONABLE_STRUCT_IMPL(ChatMessageEvent); +L_DECLARE_C_BASE_OBJECT_IMPL(EventLog); +L_DECLARE_C_BASE_OBJECT_IMPL(CallEvent); +L_DECLARE_C_BASE_OBJECT_IMPL(ConferenceEvent); +L_DECLARE_C_BASE_OBJECT_IMPL(ConferenceParticipantEvent); +L_DECLARE_C_BASE_OBJECT_IMPL(ConferenceParticipantDeviceEvent); +L_DECLARE_C_BASE_OBJECT_IMPL(ConferenceSubjectEvent); +L_DECLARE_C_BASE_OBJECT_IMPL(ChatMessageEvent); using namespace std; diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index e36e288f4..cefeaba33 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -41,6 +41,10 @@ LINPHONE_BEGIN_NAMESPACE +// ----------------------------------------------------------------------------- +// MetaInfo. +// ----------------------------------------------------------------------------- + template struct CppTypeMetaInfo { enum { @@ -60,22 +64,27 @@ struct CTypeMetaInfo { class Wrapper { private: + // --------------------------------------------------------------------------- + // IsCppObject traits. + // --------------------------------------------------------------------------- + template struct IsCppObject { enum { - value = std::is_base_of::value || std::is_base_of::value + value = std::is_base_of::value || std::is_base_of::value }; }; template struct IsPrivateCppObject { enum { - value = std::is_base_of::value || std::is_base_of::value + value = std::is_base_of::value || + std::is_base_of::value }; }; template - struct IsDefinedCppObject { + struct IsRegisteredCppObject { enum { value = CppTypeMetaInfo::defined && ( !CppTypeMetaInfo::isSubtype || @@ -84,30 +93,70 @@ private: }; }; + // --------------------------------------------------------------------------- + // IsDefined traits. + // --------------------------------------------------------------------------- + template - struct IsDefinedNotClonableCppObject { + struct IsDefinedBaseCppObject { enum { - value = IsDefinedCppObject::value && std::is_base_of::value + value = IsRegisteredCppObject::value && + std::is_base_of::value && + !std::is_base_of::value + }; + }; + + template + struct IsDefinedCppObject { + enum { + value = IsRegisteredCppObject::value && std::is_base_of::value }; }; template struct IsDefinedClonableCppObject { enum { - value = IsDefinedCppObject::value && std::is_base_of::value + value = IsRegisteredCppObject::value && std::is_base_of::value }; }; - template - struct WrappedObject { + // --------------------------------------------------------------------------- + // Wrapped Objects. + // --------------------------------------------------------------------------- + + template + struct WrappedBaseObject { belle_sip_object_t base; - std::shared_ptr cppPtr; + CppType *cppPtr; }; - template + template + struct WrappedObject { + belle_sip_object_t base; + std::shared_ptr cppPtr; + }; + + template struct WrappedClonableObject { belle_sip_object_t base; - CType *cppPtr; + CppType *cppPtr; + }; + + template + struct WrappedObjectResolver { + typedef typename std::conditional< + IsDefinedBaseCppObject::value, + WrappedBaseObject, + typename std::conditional< + IsDefinedCppObject::value, + WrappedObject, + typename std::conditional< + IsDefinedClonableCppObject::value, + WrappedClonableObject, + void + >::type + >::type + >::type type; }; // --------------------------------------------------------------------------- @@ -162,7 +211,7 @@ public: template< typename CType, typename CppType = typename CTypeMetaInfo::cppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static L_INTERNAL_WRAPPER_CONSTEXPR std::shared_ptr getCppPtrFromC (CType *cObject) { #ifdef DEBUG @@ -186,27 +235,29 @@ public: template< typename CType, typename CppType = typename CTypeMetaInfo::cppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static L_INTERNAL_WRAPPER_CONSTEXPR std::shared_ptr getCppPtrFromC (const CType *cObject) { #ifdef DEBUG return getCppPtrFromC(const_cast(cObject)); #else - return reinterpret_cast *>(cObject)->cppPtr; + return reinterpret_cast::type *>(cObject)->cppPtr; #endif } template< typename CType, typename CppType = typename CTypeMetaInfo::cppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if< + IsDefinedBaseCppObject::value || IsDefinedClonableCppObject::value, CppType + >::type > static L_INTERNAL_WRAPPER_CONSTEXPR CppType *getCppPtrFromC (CType *cObject) { #ifdef DEBUG typedef typename CTypeMetaInfo::cppType BaseType; typedef CppType DerivedType; - BaseType *cppObject = reinterpret_cast *>(cObject)->cppPtr; + BaseType *cppObject = reinterpret_cast::type *>(cObject)->cppPtr; if (!cppObject) abort("Cpp Object is null."); @@ -216,20 +267,22 @@ public: return derivedCppObject; #else - return reinterpret_cast *>(cObject)->cppPtr; + return reinterpret_cast::type *>(cObject)->cppPtr; #endif } template< typename CType, typename CppType = typename CTypeMetaInfo::cppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if< + IsDefinedBaseCppObject::value || IsDefinedClonableCppObject::value, CppType + >::type > static L_INTERNAL_WRAPPER_CONSTEXPR const CppType *getCppPtrFromC (const CType *cObject) { #ifdef DEBUG return getCppPtrFromC(const_cast(cObject)); #else - return reinterpret_cast *>(cObject)->cppPtr; + return reinterpret_cast::type *>(cObject)->cppPtr; #endif } @@ -240,11 +293,28 @@ public: template< typename CType, typename CppType = typename CTypeMetaInfo::cppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static inline void setCppPtrFromC (CType *cObject, const std::shared_ptr &cppObject) { reinterpret_cast *>(cObject)->cppPtr = cppObject; - cppObject->setProperty("LinphonePrivate::Wrapper::cBackPtr", cObject); + cppObject->setCBackPtr(cObject); + } + + template< + typename CType, + typename CppType = typename CTypeMetaInfo::cppType, + typename = typename std::enable_if< + IsDefinedBaseCppObject::value || IsDefinedClonableCppObject::value, CppType + >::type + > + static inline void setCppPtrFromC (CType *cObject, CppType* &&cppObject) { + CppType **cppObjectAddr = &reinterpret_cast::type *>(cObject)->cppPtr; + if (*cppObjectAddr == cppObject) + return; + delete *cppObjectAddr; + + *cppObjectAddr = cppObject; + (*cppObjectAddr)->setCBackPtr(cObject); } template< @@ -259,7 +329,7 @@ public: delete *cppObjectAddr; *cppObjectAddr = new CppType(*cppObject); - (*cppObjectAddr)->setProperty("LinphonePrivate::Wrapper::cBackPtr", cObject); + (*cppObjectAddr)->setCBackPtr(cObject); } // --------------------------------------------------------------------------- @@ -268,34 +338,28 @@ public: template< typename CppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value>::type > - static inline typename CppTypeMetaInfo::cType *getCBackPtr (const std::shared_ptr &cppObject) { - typedef typename CppTypeMetaInfo::cType RetType; - - if (L_UNLIKELY(!cppObject)) - return nullptr; - - Variant variant = cppObject->getProperty("LinphonePrivate::Wrapper::cBackPtr"); - void *value = variant.getValue(); - if (value) - return static_cast(value); - - RetType *cObject = CppTypeMetaInfo::init(); - setCppPtrFromC(cObject, cppObject); - return cObject; + static inline CppType * &&getResolvedCppPtr (const CppType *cppObject) { + // Exists only for `getCBackPtr` impl. + abort("Cannot get resolved cpp ptr from BaseObject."); + return std::move(const_cast(cppObject)); } template< typename CppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > - static inline typename CppTypeMetaInfo::cType *getCBackPtr (CppType *cppObject) { + static inline std::shared_ptr getResolvedCppPtr (const CppType *cppObject) { if (L_UNLIKELY(!cppObject)) return nullptr; try { - return getCBackPtr(std::static_pointer_cast(cppObject->getSharedFromThis())); + typedef typename std::decaygetSharedFromThis())>::type SharedFromThisType; + + return std::static_pointer_cast( + std::const_pointer_cast(cppObject->getSharedFromThis()) + ); } catch (const std::bad_weak_ptr &e) { abort(e.what()); } @@ -308,19 +372,29 @@ public: typename CppType, typename = typename std::enable_if::value, CppType>::type > + static constexpr const CppType *getResolvedCppPtr (const CppType *cppObject) { + return cppObject; + } + + template< + typename CppType, + typename = typename std::enable_if::value, CppType>::type + > static inline typename CppTypeMetaInfo::cType *getCBackPtr (const CppType *cppObject) { if (L_UNLIKELY(!cppObject)) return nullptr; typedef typename CppTypeMetaInfo::cType RetType; - Variant variant = cppObject->getProperty("LinphonePrivate::Wrapper::cBackPtr"); - void *value = variant.getValue(); - if (value) + void *value = cppObject->getCBackPtr(); + if (value || IsDefinedBaseCppObject::value) return static_cast(value); RetType *cObject = CppTypeMetaInfo::init(); - setCppPtrFromC(cObject, cppObject); + + // Can be set only on Object or ClonableObject. Not BaseObject. + setCppPtrFromC(cObject, getResolvedCppPtr(cppObject)); + return cObject; } @@ -364,12 +438,12 @@ public: template< typename CppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static inline bctbx_list_t *getResolvedCListFromCppList (const std::list> &cppList) { bctbx_list_t *result = nullptr; for (const auto &value : cppList) { - result = bctbx_list_append(result, belle_sip_object_ref(getCBackPtr(value))); + result = bctbx_list_append(result, belle_sip_object_ref(getCBackPtr(value.get()))); } return result; } @@ -388,7 +462,7 @@ public: template< typename CType, typename CppType = typename CTypeMetaInfo::cppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static inline std::list> getResolvedCppListFromCList (const bctbx_list_t *cList) { std::list> result; @@ -500,6 +574,30 @@ LINPHONE_END_NAMESPACE // C object declaration. // ----------------------------------------------------------------------------- +// Declare base wrapped C object. +#define L_DECLARE_C_BASE_OBJECT_IMPL(C_TYPE, ...) \ + static_assert(LinphonePrivate::CTypeMetaInfo::defined, "Type is not defined."); \ + struct _Linphone ## C_TYPE { \ + belle_sip_object_t base; \ + L_CPP_TYPE_OF_C_TYPE(C_TYPE) *cppPtr; \ + __VA_ARGS__ \ + }; \ + BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_TYPE); \ + Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init() { \ + return belle_sip_object_new(Linphone ## C_TYPE); \ + } \ + static void _linphone_ ## C_TYPE ## _uninit(Linphone ## C_TYPE * object) { \ + delete object->cppPtr; \ + } \ + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## C_TYPE); \ + BELLE_SIP_INSTANCIATE_VPTR( \ + Linphone ## C_TYPE, belle_sip_object_t, \ + _linphone_ ## C_TYPE ## _uninit, \ + NULL, \ + NULL, \ + FALSE \ + ); + // Declare wrapped C object with constructor/destructor. #define L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(C_TYPE, CONSTRUCTOR, DESTRUCTOR, ...) \ struct _Linphone ## C_TYPE { \ @@ -511,6 +609,7 @@ LINPHONE_END_NAMESPACE // Declare wrapped C object. #define L_DECLARE_C_OBJECT_IMPL(C_TYPE, ...) \ + static_assert(LinphonePrivate::CTypeMetaInfo::defined, "Type is not defined."); \ struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ std::shared_ptr cppPtr; \ @@ -519,7 +618,7 @@ LINPHONE_END_NAMESPACE L_INTERNAL_DECLARE_C_OBJECT_FUNCTIONS(C_TYPE, L_INTERNAL_C_OBJECT_NO_XTOR, L_INTERNAL_C_OBJECT_NO_XTOR) // Declare clonable wrapped C object. -#define L_DECLARE_C_CLONABLE_STRUCT_IMPL(C_TYPE, ...) \ +#define L_DECLARE_C_CLONABLE_OBJECT_IMPL(C_TYPE, ...) \ static_assert(LinphonePrivate::CTypeMetaInfo::defined, "Type is not defined."); \ struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ @@ -602,7 +701,7 @@ LINPHONE_END_NAMESPACE // Get the wrapped C object of a C++ object. #define L_GET_C_BACK_PTR(CPP_OBJECT) \ - LinphonePrivate::Wrapper::getCBackPtr(CPP_OBJECT) + LinphonePrivate::Wrapper::getCBackPtr(LinphonePrivate::Utils::getPtr(CPP_OBJECT)) // Get/set user data on a wrapped C object. #define L_GET_USER_DATA_FROM_C_OBJECT(C_OBJECT) \ diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index dc44e18fe..5575b6b70 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -69,7 +69,7 @@ private: void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) override; private: - L_DECLARE_PRIVATE_T(ClientGroupChatRoom, ChatRoom); + L_DECLARE_PRIVATE(ClientGroupChatRoom); L_DISABLE_COPY(ClientGroupChatRoom); }; diff --git a/src/content/content.h b/src/content/content.h index abf86c9d7..7f73b83f5 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -64,7 +64,7 @@ public: bool isEmpty () const; private: - L_DECLARE_PRIVATE_T(Content, ClonableObject); + L_DECLARE_PRIVATE(Content); }; LINPHONE_END_NAMESPACE diff --git a/src/event-log/call/call-event.cpp b/src/event-log/call/call-event.cpp index b4d6be335..a63dcc3ad 100644 --- a/src/event-log/call/call-event.cpp +++ b/src/event-log/call/call-event.cpp @@ -41,18 +41,6 @@ CallEvent::CallEvent (Type type, time_t time, const shared_ptr &call) : d->call = call; } -CallEvent::CallEvent (const CallEvent &src) : CallEvent(src.getType(), src.getTime(), src.getCall()) {} - -CallEvent &CallEvent::operator= (const CallEvent &src) { - L_D(); - if (this != &src) { - EventLog::operator=(src); - d->call = src.getPrivate()->call; - } - - return *this; -} - shared_ptr CallEvent::getCall () const { L_D(); return d->call; diff --git a/src/event-log/call/call-event.h b/src/event-log/call/call-event.h index 85ae6c28d..648973957 100644 --- a/src/event-log/call/call-event.h +++ b/src/event-log/call/call-event.h @@ -34,14 +34,12 @@ class CallEventPrivate; class LINPHONE_PUBLIC CallEvent : public EventLog { public: CallEvent (Type type, std::time_t time, const std::shared_ptr &message); - CallEvent (const CallEvent &src); - - CallEvent &operator= (const CallEvent &src); std::shared_ptr getCall () const; private: L_DECLARE_PRIVATE(CallEvent); + L_DISABLE_COPY(CallEvent); }; LINPHONE_END_NAMESPACE diff --git a/src/event-log/chat/chat-message-event.cpp b/src/event-log/chat/chat-message-event.cpp index 6e26e48e3..498c417ac 100644 --- a/src/event-log/chat/chat-message-event.cpp +++ b/src/event-log/chat/chat-message-event.cpp @@ -42,20 +42,6 @@ ChatMessageEvent::ChatMessageEvent ( d->chatMessage = chatMessage; } -ChatMessageEvent::ChatMessageEvent ( - const ChatMessageEvent &src -) : ChatMessageEvent(src.getTime(), src.getChatMessage()) {} - -ChatMessageEvent &ChatMessageEvent::operator= (const ChatMessageEvent &src) { - L_D(); - if (this != &src) { - EventLog::operator=(src); - d->chatMessage = src.getPrivate()->chatMessage; - } - - return *this; -} - shared_ptr ChatMessageEvent::getChatMessage () const { L_D(); return d->chatMessage; diff --git a/src/event-log/chat/chat-message-event.h b/src/event-log/chat/chat-message-event.h index becbdadd8..82ccc1804 100644 --- a/src/event-log/chat/chat-message-event.h +++ b/src/event-log/chat/chat-message-event.h @@ -34,14 +34,12 @@ class ChatMessageEventPrivate; class LINPHONE_PUBLIC ChatMessageEvent : public EventLog { public: ChatMessageEvent (std::time_t time, const std::shared_ptr &chatMessage); - ChatMessageEvent (const ChatMessageEvent &src); - - ChatMessageEvent &operator= (const ChatMessageEvent &src); std::shared_ptr getChatMessage () const; private: L_DECLARE_PRIVATE(ChatMessageEvent); + L_DISABLE_COPY(ChatMessageEvent); }; LINPHONE_END_NAMESPACE diff --git a/src/event-log/conference/conference-event.cpp b/src/event-log/conference/conference-event.cpp index c11c94428..daeac96a7 100644 --- a/src/event-log/conference/conference-event.cpp +++ b/src/event-log/conference/conference-event.cpp @@ -33,9 +33,6 @@ ConferenceEvent::ConferenceEvent (Type type, time_t time, const Address &confere d->conferenceAddress = conferenceAddress; } -ConferenceEvent::ConferenceEvent (const ConferenceEvent &src) : - ConferenceEvent(src.getType(), src.getTime(), src.getConferenceAddress()) {} - ConferenceEvent::ConferenceEvent ( ConferenceEventPrivate &p, Type type, @@ -46,16 +43,6 @@ ConferenceEvent::ConferenceEvent ( d->conferenceAddress = conferenceAddress; } -ConferenceEvent &ConferenceEvent::operator= (const ConferenceEvent &src) { - L_D(); - if (this != &src) { - EventLog::operator=(src); - d->conferenceAddress = src.getPrivate()->conferenceAddress; - } - - return *this; -} - const Address &ConferenceEvent::getConferenceAddress () const { L_D(); return d->conferenceAddress; diff --git a/src/event-log/conference/conference-event.h b/src/event-log/conference/conference-event.h index 05fb34dc4..080c9e9a2 100644 --- a/src/event-log/conference/conference-event.h +++ b/src/event-log/conference/conference-event.h @@ -32,9 +32,6 @@ class ConferenceEventPrivate; class LINPHONE_PUBLIC ConferenceEvent : public EventLog { public: ConferenceEvent (Type type, std::time_t time, const Address &conferenceAddress); - ConferenceEvent (const ConferenceEvent &src); - - ConferenceEvent &operator= (const ConferenceEvent &src); const Address &getConferenceAddress () const; @@ -43,6 +40,7 @@ protected: private: L_DECLARE_PRIVATE(ConferenceEvent); + L_DISABLE_COPY(ConferenceEvent); }; LINPHONE_END_NAMESPACE diff --git a/src/event-log/conference/conference-notified-event.cpp b/src/event-log/conference/conference-notified-event.cpp index cca45750e..5a0e4f857 100644 --- a/src/event-log/conference/conference-notified-event.cpp +++ b/src/event-log/conference/conference-notified-event.cpp @@ -37,15 +37,6 @@ ConferenceNotifiedEvent::ConferenceNotifiedEvent ( d->notifyId = notifyId; } -ConferenceNotifiedEvent::ConferenceNotifiedEvent ( - const ConferenceNotifiedEvent &src -) : ConferenceNotifiedEvent( - src.getType(), - src.getTime(), - src.getConferenceAddress(), - src.getNotifyId() -) {} - ConferenceNotifiedEvent::ConferenceNotifiedEvent ( ConferenceNotifiedEventPrivate &p, Type type, @@ -57,16 +48,6 @@ ConferenceNotifiedEvent::ConferenceNotifiedEvent ( d->notifyId = notifyId; } -ConferenceNotifiedEvent &ConferenceNotifiedEvent::operator= (const ConferenceNotifiedEvent &src) { - L_D(); - if (this != &src) { - ConferenceEvent::operator=(src); - d->notifyId = src.getPrivate()->notifyId; - } - - return *this; -} - unsigned int ConferenceNotifiedEvent::getNotifyId () const { L_D(); return d->notifyId; diff --git a/src/event-log/conference/conference-notified-event.h b/src/event-log/conference/conference-notified-event.h index 2f3c8f860..4f238e857 100644 --- a/src/event-log/conference/conference-notified-event.h +++ b/src/event-log/conference/conference-notified-event.h @@ -31,9 +31,6 @@ class ConferenceNotifiedEventPrivate; class LINPHONE_PUBLIC ConferenceNotifiedEvent : public ConferenceEvent { public: ConferenceNotifiedEvent (Type type, std::time_t time, const Address &conferenceAddress, unsigned int notifiyId); - ConferenceNotifiedEvent (const ConferenceNotifiedEvent &src); - - ConferenceNotifiedEvent &operator= (const ConferenceNotifiedEvent &src); unsigned int getNotifyId () const; @@ -48,6 +45,7 @@ protected: private: L_DECLARE_PRIVATE(ConferenceNotifiedEvent); + L_DISABLE_COPY(ConferenceNotifiedEvent); }; LINPHONE_END_NAMESPACE diff --git a/src/event-log/conference/conference-participant-device-event.cpp b/src/event-log/conference/conference-participant-device-event.cpp index 83cc88398..fbfbcceda 100644 --- a/src/event-log/conference/conference-participant-device-event.cpp +++ b/src/event-log/conference/conference-participant-device-event.cpp @@ -56,28 +56,6 @@ ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent ( d->gruuAddress = gruuAddress; } -ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent (const ConferenceParticipantDeviceEvent &src) : - ConferenceParticipantDeviceEvent( - src.getType(), - src.getTime(), - src.getConferenceAddress(), - src.getNotifyId(), - src.getParticipantAddress(), - src.getGruuAddress() - ) {} - -ConferenceParticipantDeviceEvent &ConferenceParticipantDeviceEvent::operator= ( - const ConferenceParticipantDeviceEvent &src -) { - L_D(); - if (this != &src) { - ConferenceParticipantEvent::operator=(src); - d->gruuAddress = src.getPrivate()->gruuAddress; - } - - return *this; -} - const Address &ConferenceParticipantDeviceEvent::getGruuAddress () const { L_D(); return d->gruuAddress; diff --git a/src/event-log/conference/conference-participant-device-event.h b/src/event-log/conference/conference-participant-device-event.h index 3ee2b9a95..d57834dd7 100644 --- a/src/event-log/conference/conference-participant-device-event.h +++ b/src/event-log/conference/conference-participant-device-event.h @@ -38,14 +38,12 @@ public: const Address &participantAddress, const Address &gruuAddress ); - ConferenceParticipantDeviceEvent (const ConferenceParticipantDeviceEvent &src); - - ConferenceParticipantDeviceEvent &operator= (const ConferenceParticipantDeviceEvent &src); const Address &getGruuAddress () const; private: L_DECLARE_PRIVATE(ConferenceParticipantDeviceEvent); + L_DISABLE_COPY(ConferenceParticipantDeviceEvent); }; LINPHONE_END_NAMESPACE diff --git a/src/event-log/conference/conference-participant-event.cpp b/src/event-log/conference/conference-participant-event.cpp index b64e886b2..b5e8406b6 100644 --- a/src/event-log/conference/conference-participant-event.cpp +++ b/src/event-log/conference/conference-participant-event.cpp @@ -44,16 +44,6 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( d->participantAddress = participantAddress; } -ConferenceParticipantEvent::ConferenceParticipantEvent ( - const ConferenceParticipantEvent &src -) : ConferenceParticipantEvent( - src.getType(), - src.getTime(), - src.getConferenceAddress(), - src.getNotifyId(), - src.getParticipantAddress() -) {} - ConferenceParticipantEvent::ConferenceParticipantEvent ( ConferenceParticipantEventPrivate &p, Type type, @@ -66,16 +56,6 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( d->participantAddress = participantAddress; } -ConferenceParticipantEvent &ConferenceParticipantEvent::operator= (const ConferenceParticipantEvent &src) { - L_D(); - if (this != &src) { - ConferenceEvent::operator=(src); - d->participantAddress = src.getPrivate()->participantAddress; - } - - return *this; -} - const Address &ConferenceParticipantEvent::getParticipantAddress () const { L_D(); return d->participantAddress; diff --git a/src/event-log/conference/conference-participant-event.h b/src/event-log/conference/conference-participant-event.h index d5127459a..792583dcf 100644 --- a/src/event-log/conference/conference-participant-event.h +++ b/src/event-log/conference/conference-participant-event.h @@ -37,9 +37,6 @@ public: unsigned int notifyId, const Address &participantAddress ); - ConferenceParticipantEvent (const ConferenceParticipantEvent &src); - - ConferenceParticipantEvent &operator= (const ConferenceParticipantEvent &src); const Address &getParticipantAddress () const; @@ -55,6 +52,7 @@ protected: private: L_DECLARE_PRIVATE(ConferenceParticipantEvent); + L_DISABLE_COPY(ConferenceParticipantEvent); }; LINPHONE_END_NAMESPACE diff --git a/src/event-log/conference/conference-subject-event.cpp b/src/event-log/conference/conference-subject-event.cpp index 1dcd45a0b..e07061dc2 100644 --- a/src/event-log/conference/conference-subject-event.cpp +++ b/src/event-log/conference/conference-subject-event.cpp @@ -49,19 +49,6 @@ ConferenceSubjectEvent::ConferenceSubjectEvent ( d->subject = subject; } -ConferenceSubjectEvent::ConferenceSubjectEvent (const ConferenceSubjectEvent &src) : - ConferenceSubjectEvent(src.getTime(), src.getConferenceAddress(), src.getNotifyId(), src.getSubject()) {} - -ConferenceSubjectEvent &ConferenceSubjectEvent::operator= (const ConferenceSubjectEvent &src) { - L_D(); - if (this != &src) { - ConferenceEvent::operator=(src); - d->subject = src.getPrivate()->subject; - } - - return *this; -} - const string &ConferenceSubjectEvent::getSubject () const { L_D(); return d->subject; diff --git a/src/event-log/conference/conference-subject-event.h b/src/event-log/conference/conference-subject-event.h index 20f5fe982..8ea9a039f 100644 --- a/src/event-log/conference/conference-subject-event.h +++ b/src/event-log/conference/conference-subject-event.h @@ -20,6 +20,8 @@ #ifndef _CONFERENCE_SUBJECT_EVENT_H_ #define _CONFERENCE_SUBJECT_EVENT_H_ +#include + #include "conference-notified-event.h" // ============================================================================= @@ -36,14 +38,12 @@ public: unsigned int notifyId, const std::string &subject ); - ConferenceSubjectEvent (const ConferenceSubjectEvent &src); - - ConferenceSubjectEvent &operator= (const ConferenceSubjectEvent &src); const std::string &getSubject () const; private: L_DECLARE_PRIVATE(ConferenceSubjectEvent); + L_DISABLE_COPY(ConferenceSubjectEvent); }; LINPHONE_END_NAMESPACE diff --git a/src/event-log/event-log-p.h b/src/event-log/event-log-p.h index 5732a56cc..ccfe7a721 100644 --- a/src/event-log/event-log-p.h +++ b/src/event-log/event-log-p.h @@ -20,14 +20,15 @@ #ifndef _EVENT_LOG_P_H_ #define _EVENT_LOG_P_H_ +#include "object/base-object-p.h" + #include "event-log.h" -#include "object/clonable-object-p.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE -class EventLogPrivate : public ClonableObjectPrivate { +class EventLogPrivate : public BaseObjectPrivate { public: long storageId = -1; diff --git a/src/event-log/event-log.cpp b/src/event-log/event-log.cpp index cdb2281bb..087ee6797 100644 --- a/src/event-log/event-log.cpp +++ b/src/event-log/event-log.cpp @@ -23,23 +23,14 @@ LINPHONE_BEGIN_NAMESPACE -EventLog::EventLog () : ClonableObject(*new EventLogPrivate) {} +EventLog::EventLog () : BaseObject(*new EventLogPrivate) {} -EventLog::EventLog (const EventLog &) : ClonableObject(*new EventLogPrivate) {} - -EventLog::EventLog (EventLogPrivate &p, Type type, time_t time) : ClonableObject(*new EventLogPrivate) { +EventLog::EventLog (EventLogPrivate &p, Type type, std::time_t time) : BaseObject(p) { L_D(); d->type = type; d->time = time; } -EventLog &EventLog::operator= (const EventLog &src) { - L_D(); - if (this != &src) - d->type = src.getPrivate()->type; - return *this; -} - EventLog::Type EventLog::getType () const { L_D(); return d->type; diff --git a/src/event-log/event-log.h b/src/event-log/event-log.h index e5f0d682a..3134421e8 100644 --- a/src/event-log/event-log.h +++ b/src/event-log/event-log.h @@ -25,7 +25,7 @@ #include "linphone/enums/event-log-enums.h" #include "linphone/utils/enum-generator.h" -#include "object/clonable-object.h" +#include "object/base-object.h" // ============================================================================= @@ -33,16 +33,13 @@ LINPHONE_BEGIN_NAMESPACE class EventLogPrivate; -class LINPHONE_PUBLIC EventLog : public ClonableObject { +class LINPHONE_PUBLIC EventLog : public BaseObject { friend class MainDb; public: L_DECLARE_ENUM(Type, L_ENUM_VALUES_EVENT_LOG_TYPE); EventLog (); - EventLog (const EventLog &src); - - EventLog &operator= (const EventLog &src); Type getType () const; std::time_t getTime () const; @@ -52,6 +49,7 @@ protected: private: L_DECLARE_PRIVATE(EventLog); + L_DISABLE_COPY(EventLog); }; LINPHONE_END_NAMESPACE diff --git a/src/object/base-object-p.h b/src/object/base-object-p.h new file mode 100644 index 000000000..3db55188e --- /dev/null +++ b/src/object/base-object-p.h @@ -0,0 +1,47 @@ +/* + * base-object-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + #ifndef _BASE_OBJECT_P_H_ + #define _BASE_OBJECT_P_H_ + +#include "linphone/utils/general.h" + +#include "object-head-p.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class BaseObjectPrivate { + L_OBJECT_PRIVATE; + +public: + BaseObjectPrivate () = default; + virtual ~BaseObjectPrivate () = default; + +protected: + BaseObject *mPublic = nullptr; + +private: + L_DECLARE_PUBLIC(BaseObject); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _BASE_OBJECT_P_H_ diff --git a/src/object/base-object.cpp b/src/object/base-object.cpp new file mode 100644 index 000000000..b1551c5ed --- /dev/null +++ b/src/object/base-object.cpp @@ -0,0 +1,38 @@ +/* + * base-object.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "base-object-p.h" + +#include "base-object.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +L_OBJECT_IMPL(BaseObject); + +BaseObject::BaseObject (BaseObjectPrivate &p) : mPrivate(&p) { + mPrivate->mPublic = this; +} + +BaseObject::~BaseObject () { + delete mPrivate; +} + +LINPHONE_END_NAMESPACE diff --git a/src/object/base-object.h b/src/object/base-object.h new file mode 100644 index 000000000..49d219f4a --- /dev/null +++ b/src/object/base-object.h @@ -0,0 +1,56 @@ +/* + * base-object.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _BASE_OBJECT_H_ +#define _BASE_OBJECT_H_ + +#include "linphone/utils/general.h" + +#include "object-head.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class BaseObjectPrivate; + +/* + * Base Object of Linphone. Cannot be cloned. Cannot be Shared. + * It's the base class of Object. It's useful for lightweight entities + * like Events. + */ +class LINPHONE_PUBLIC BaseObject { + L_OBJECT; + +public: + virtual ~BaseObject (); + +protected: + explicit BaseObject (BaseObjectPrivate &p); + + BaseObjectPrivate *mPrivate = nullptr; + +private: + L_DECLARE_PRIVATE(BaseObject); + L_DISABLE_COPY(BaseObject); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _BASE_OBJECT_H_ diff --git a/src/object/clonable-object-p.h b/src/object/clonable-object-p.h index c1de00036..af30d627c 100644 --- a/src/object/clonable-object-p.h +++ b/src/object/clonable-object-p.h @@ -24,11 +24,15 @@ #include "linphone/utils/general.h" +#include "object-head-p.h" + // ============================================================================= LINPHONE_BEGIN_NAMESPACE class ClonableObjectPrivate { + L_OBJECT_PRIVATE; + public: ClonableObjectPrivate () = default; virtual ~ClonableObjectPrivate () = default; diff --git a/src/object/clonable-object.cpp b/src/object/clonable-object.cpp index 4851cd2d8..831e7879a 100644 --- a/src/object/clonable-object.cpp +++ b/src/object/clonable-object.cpp @@ -42,6 +42,8 @@ void ClonableObjectPrivate::unref () { // ----------------------------------------------------------------------------- +L_OBJECT_IMPL(ClonableObject); + ClonableObject::ClonableObject (ClonableObjectPrivate &p) : mPrivate(&p) { // Q-pointer must be empty. It's a constructor that takes a new private data. L_ASSERT(!mPrivate->mPublic); diff --git a/src/object/clonable-object.h b/src/object/clonable-object.h index 34c91ef69..30df6b61f 100644 --- a/src/object/clonable-object.h +++ b/src/object/clonable-object.h @@ -20,13 +20,20 @@ #ifndef _CLONABLE_OBJECT_H_ #define _CLONABLE_OBJECT_H_ +#include "object-head.h" #include "property-container.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE +/* + * Clonable Object of Linphone. Generally it's just a data object with no + * intelligence. + */ class LINPHONE_PUBLIC ClonableObject : public PropertyContainer { + L_OBJECT; + public: virtual ~ClonableObject (); diff --git a/src/object/object-head-p.h b/src/object/object-head-p.h new file mode 100644 index 000000000..7f221ec5a --- /dev/null +++ b/src/object/object-head-p.h @@ -0,0 +1,38 @@ +/* + * object-head-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _OBJECT_HEAD_P_H_ +#define _OBJECT_HEAD_P_H_ + +// ============================================================================= + +#define L_OBJECT_IMPL(CLASS) \ + void *CLASS::getCBackPtr () const { \ + L_D(); \ + return d->cBackPtr; \ + } \ + void CLASS::setCBackPtr (void *cBackPtr) { \ + L_D(); \ + d->cBackPtr = cBackPtr; \ + } + +#define L_OBJECT_PRIVATE \ + void *cBackPtr = nullptr; + +#endif // ifndef _OBJECT_HEAD_P_H_ diff --git a/src/object/object-head.h b/src/object/object-head.h new file mode 100644 index 000000000..181a0c467 --- /dev/null +++ b/src/object/object-head.h @@ -0,0 +1,29 @@ +/* + * object-head.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _OBJECT_HEAD_H_ +#define _OBJECT_HEAD_H_ + +// ============================================================================= + +#define L_OBJECT \ + void *getCBackPtr () const; \ + void setCBackPtr (void *cBackPtr); + +#endif // ifndef _OBJECT_HEAD_H_ diff --git a/src/object/object-p.h b/src/object/object-p.h index c03afac98..842fd3c6f 100644 --- a/src/object/object-p.h +++ b/src/object/object-p.h @@ -23,21 +23,16 @@ #include #include +#include "base-object-p.h" #include "variant/variant.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE -class ObjectPrivate { +class ObjectPrivate : public BaseObjectPrivate { friend class ObjectFactory; -public: - virtual ~ObjectPrivate () = default; - -protected: - Object *mPublic = nullptr; - private: std::unordered_map properties; std::weak_ptr weak; diff --git a/src/object/object.cpp b/src/object/object.cpp index 7c62c0c42..179e2392a 100644 --- a/src/object/object.cpp +++ b/src/object/object.cpp @@ -30,13 +30,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -Object::Object (ObjectPrivate &p) : mPrivate(&p) { - mPrivate->mPublic = this; -} - -Object::~Object () { - delete mPrivate; -} +Object::Object (ObjectPrivate &p) : BaseObject(p) {} shared_ptr Object::getSharedFromThis () { return const_pointer_cast(static_cast(this)->getSharedFromThis()); @@ -46,7 +40,7 @@ shared_ptr Object::getSharedFromThis () const { shared_ptr object; try { - object = mPrivate->weak.lock(); + object = getPrivate()->weak.lock(); if (!object) lFatal() << GET_SHARED_FROM_THIS_FATAL_ERROR; } catch (const exception &) { diff --git a/src/object/object.h b/src/object/object.h index 843b48b9d..910d0bcb3 100644 --- a/src/object/object.h +++ b/src/object/object.h @@ -22,17 +22,22 @@ #include +#include "base-object.h" #include "property-container.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE -class LINPHONE_PUBLIC Object : public PropertyContainer { +/* + * Main Object of Linphone. Can be shared but is not Clonable. + * Must be built with ObjectFactory. + */ +class LINPHONE_PUBLIC Object : public BaseObject, public PropertyContainer { friend class ObjectFactory; public: - virtual ~Object (); + virtual ~Object () = default; protected: explicit Object (ObjectPrivate &p); @@ -40,8 +45,6 @@ protected: std::shared_ptr getSharedFromThis (); std::shared_ptr getSharedFromThis () const; - ObjectPrivate *mPrivate = nullptr; - private: L_DECLARE_PRIVATE(Object); L_DISABLE_COPY(Object); From 4e3c5d954884786d1faddf7ab4bcb2d9af2fe5fc Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 19 Oct 2017 16:58:51 +0200 Subject: [PATCH 0591/2215] fix(PlatformHelpers): clean code, fix coding style, use cpp logger... --- src/CMakeLists.txt | 26 ++-- src/core/core.cpp | 3 +- src/core/core.h | 4 +- ...lpers.cpp => android-platform-helpers.cpp} | 140 +++++++++--------- .../platform-helpers/platform-helpers.cpp | 75 +++++----- src/core/platform-helpers/platform-helpers.h | 52 ++++--- 6 files changed, 152 insertions(+), 148 deletions(-) rename src/core/platform-helpers/{android-helpers.cpp => android-platform-helpers.cpp} (59%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index aa0916e7b..0ea9757d2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -221,47 +221,47 @@ if (APPLE) list(APPEND LINPHONE_OBJC_SOURCE_FILES core/paths/paths-apple.mm) list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/paths/paths-apple.h) -elseif(ANDROID) - list(APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES core/paths/paths-android.cpp core/platform-helpers/android-helpers.cpp) +elseif (ANDROID) + list(APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES core/paths/paths-android.cpp core/platform-helpers/android-platform-helpers.cpp) list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/paths/paths-android.h) -elseif(WIN32) +elseif (WIN32) list(APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES core/paths/paths-windows.cpp) list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/paths/paths-windows.h) -elseif(UNIX) +elseif (UNIX) list(APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES core/paths/paths-linux.cpp) list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/paths/paths-linux.h) -endif() +endif () set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS} ${LIBXSD_INCLUDE_DIRS}) set(LINPHONE_CXX_OBJECTS_DEFINITIONS "-DLIBLINPHONE_EXPORTS") set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS}) -if(SOCI_FOUND) +if (SOCI_FOUND) list(APPEND LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${SOCI_INCLUDE_DIRS} ${SOCI_MYSQL_INCLUDES}) add_definitions(-DSOCI_ENABLED) -endif() +endif () set(LINPHONE_PRIVATE_HEADER_FILES) -foreach(header ${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES}) +foreach (header ${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES}) list(APPEND LINPHONE_PRIVATE_HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/${header}") -endforeach() +endforeach () set(LINPHONE_PRIVATE_HEADER_FILES ${LINPHONE_PRIVATE_HEADER_FILES} PARENT_SCOPE) bc_apply_compile_flags(LINPHONE_CXX_OBJECTS_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX) bc_apply_compile_flags(LINPHONE_OBJC_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX STRICT_OPTIONS_OBJC) -if(ENABLE_STATIC) +if (ENABLE_STATIC) add_library( linphone-cxx-objects-static OBJECT ${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES} ${LINPHONE_CXX_OBJECTS_SOURCE_FILES} ${LINPHONE_OBJC_SOURCE_FILES} ) target_compile_definitions(linphone-cxx-objects-static PRIVATE ${LINPHONE_CXX_OBJECTS_DEFINITIONS}) target_include_directories(linphone-cxx-objects-static SYSTEM PRIVATE ${LINPHONE_CXX_OBJECTS_INCLUDE_DIRS} ${LINPHONE_INCLUDE_DIRS}) -endif() +endif () -if(ENABLE_SHARED) +if (ENABLE_SHARED) add_library( linphone-cxx-objects OBJECT ${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES} ${LINPHONE_CXX_OBJECTS_SOURCE_FILES} ${LINPHONE_OBJC_SOURCE_FILES} @@ -269,4 +269,4 @@ if(ENABLE_SHARED) target_compile_definitions(linphone-cxx-objects PRIVATE ${LINPHONE_CXX_OBJECTS_DEFINITIONS}) target_include_directories(linphone-cxx-objects SYSTEM PRIVATE ${LINPHONE_CXX_OBJECTS_INCLUDE_DIRS} ${LINPHONE_INCLUDE_DIRS}) target_compile_options(linphone-cxx-objects PRIVATE "-fPIC") -endif() +endif () diff --git a/src/core/core.cpp b/src/core/core.cpp index ac7de2350..65832c42f 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -19,14 +19,13 @@ #include -#include "address/address.h" #include "chat/chat-room/basic-chat-room.h" #include "core-p.h" #include "db/main-db.h" -#include "linphone/core.h" #include "object/object-p.h" #include "paths/paths.h" +// TODO: Remove me later. #include "private.h" // ============================================================================= diff --git a/src/core/core.h b/src/core/core.h index 1e1c169a5..0aeff72e4 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -22,10 +22,12 @@ #include -#include "chat/chat-room/chat-room.h" +#include "object/object.h" // ============================================================================= +L_DECL_C_STRUCT(LinphoneCore); + LINPHONE_BEGIN_NAMESPACE class ChatRoom; diff --git a/src/core/platform-helpers/android-helpers.cpp b/src/core/platform-helpers/android-platform-helpers.cpp similarity index 59% rename from src/core/platform-helpers/android-helpers.cpp rename to src/core/platform-helpers/android-platform-helpers.cpp index b4fd1b1e6..4aee2bf64 100644 --- a/src/core/platform-helpers/android-helpers.cpp +++ b/src/core/platform-helpers/android-platform-helpers.cpp @@ -1,35 +1,41 @@ /* -linphone -Copyright (C) 2017 Belledonne Communications SARL - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "linphone/utils/utils.h" - -#include "private.h" - -#ifdef __ANDROID__ + * android-platform-helpers.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ #include +#include "platform-helpers.h" +#include "logger/logger.h" + +// TODO: Remove me later. +#include "private.h" + +// ============================================================================= + +using namespace std; + LINPHONE_BEGIN_NAMESPACE class AndroidPlatformHelpers : public PlatformHelpers { public: - AndroidPlatformHelpers (LinphoneCore *lc, void *system_context); + AndroidPlatformHelpers (LinphoneCore *lc, void *systemContext); + ~AndroidPlatformHelpers (); + void setDnsServers () override; void acquireWifiLock () override; void releaseWifiLock () override; @@ -37,9 +43,9 @@ public: void releaseMcastLock () override; void acquireCpuLock () override; void releaseCpuLock () override; - std::string getDataPath () override; - std::string getConfigPath () override; - ~AndroidPlatformHelpers (); + string getDataPath () override; + string getConfigPath () override; + private: int callVoidMethod (jmethodID id); static jmethodID getMethodId (JNIEnv *env, jclass klass, const char *method, const char *signature); @@ -54,40 +60,37 @@ private: jmethodID mGetPowerManagerId; jmethodID mGetDataPathId; jmethodID mGetConfigPathId; - }; -static const char* GetStringUTFChars (JNIEnv* env, jstring string) { - const char *cstring = string ? env->GetStringUTFChars(string, NULL) : NULL; - return cstring; +static const char *GetStringUTFChars (JNIEnv *env, jstring string) { + const char *cstring = string ? env->GetStringUTFChars(string, nullptr) : nullptr; + return cstring; } -static void ReleaseStringUTFChars (JNIEnv* env, jstring string, const char *cstring) { - if (string) env->ReleaseStringUTFChars(string, cstring); +static void ReleaseStringUTFChars (JNIEnv *env, jstring string, const char *cstring) { + if (string) env->ReleaseStringUTFChars(string, cstring); } jmethodID AndroidPlatformHelpers::getMethodId (JNIEnv *env, jclass klass, const char *method, const char *signature) { jmethodID id = env->GetMethodID(klass, method, signature); - if (id == 0) { - ms_fatal("Could not find java method '%s %s'", method, signature); - } + if (id == 0) + lFatal() << "Could not find java method: `" << method << ", " << signature << "`."; return id; } -AndroidPlatformHelpers::AndroidPlatformHelpers (LinphoneCore *lc, void *system_context) : PlatformHelpers(lc) { - JNIEnv *env=ms_get_jni_env(); +AndroidPlatformHelpers::AndroidPlatformHelpers (LinphoneCore *lc, void *systemContext) : PlatformHelpers(lc) { + JNIEnv *env = ms_get_jni_env(); jclass klass = env->FindClass("org/linphone/core/tools/AndroidPlatformHelper"); - if (!klass) { - ms_fatal("Could not find java AndroidPlatformHelper class"); - return; - } - jmethodID ctor = env->GetMethodID(klass,"", "(Ljava/lang/Object;)V"); - mJavaHelper = env->NewObject(klass, ctor, (jobject)system_context); + if (!klass) + lFatal() << "Could not find java AndroidPlatformHelper class."; + + jmethodID ctor = env->GetMethodID(klass, "", "(Ljava/lang/Object;)V"); + mJavaHelper = env->NewObject(klass, ctor, (jobject)systemContext); if (!mJavaHelper) { - ms_error("Could not instanciate AndroidPlatformHelper object."); + lError() << "Could not instanciate AndroidPlatformHelper object."; return; } - mJavaHelper = (jobject) env->NewGlobalRef(mJavaHelper); + mJavaHelper = (jobject)env->NewGlobalRef(mJavaHelper); mWifiLockAcquireId = getMethodId(env, klass, "acquireWifiLock", "()V"); mWifiLockReleaseId = getMethodId(env, klass, "releaseWifiLock", "()V"); @@ -100,10 +103,10 @@ AndroidPlatformHelpers::AndroidPlatformHelpers (LinphoneCore *lc, void *system_c mGetDataPathId = getMethodId(env, klass, "getDataPath", "()Ljava/lang/String;"); mGetConfigPathId = getMethodId(env, klass, "getConfigPath", "()Ljava/lang/String;"); - jobject pm = env->CallObjectMethod(mJavaHelper,mGetPowerManagerId); + jobject pm = env->CallObjectMethod(mJavaHelper, mGetPowerManagerId); belle_sip_wake_lock_init(env, pm); - ms_message("AndroidPlatformHelpers is fully initialised"); + lInfo() << "AndroidPlatformHelpers is fully initialised."; } AndroidPlatformHelpers::~AndroidPlatformHelpers () { @@ -111,28 +114,27 @@ AndroidPlatformHelpers::~AndroidPlatformHelpers () { JNIEnv *env = ms_get_jni_env(); belle_sip_wake_lock_uninit(env); env->DeleteGlobalRef(mJavaHelper); - mJavaHelper = NULL; + mJavaHelper = nullptr; } } - void AndroidPlatformHelpers::setDnsServers () { if (!mJavaHelper) return; - JNIEnv *env=ms_get_jni_env(); + JNIEnv *env = ms_get_jni_env(); if (env && mJavaHelper) { - jobjectArray jservers = (jobjectArray)env->CallObjectMethod(mJavaHelper,mGetDnsServersId); - bctbx_list_t *l = NULL; + jobjectArray jservers = (jobjectArray)env->CallObjectMethod(mJavaHelper, mGetDnsServersId); + bctbx_list_t *l = nullptr; if (env->ExceptionCheck()) { env->ExceptionClear(); - ms_error("AndroidPlatformHelpers::setDnsServers() exception"); + lError() << "AndroidPlatformHelpers::setDnsServers() exception."; return; } - if (jservers != NULL) { + if (jservers != nullptr) { int count = env->GetArrayLength(jservers); - for (int i=0; i < count; i++) { - jstring jserver = (jstring) env->GetObjectArrayElement(jservers, i); - const char *str = env->GetStringUTFChars(jserver, NULL); + for (int i = 0; i < count; i++) { + jstring jserver = (jstring)env->GetObjectArrayElement(jservers, i); + const char *str = env->GetStringUTFChars(jserver, nullptr); if (str) { l = bctbx_list_append(l, ms_strdup(str)); env->ReleaseStringUTFChars(jserver, str); @@ -168,28 +170,28 @@ void AndroidPlatformHelpers::releaseCpuLock () { callVoidMethod(mCpuLockReleaseId); } -std::string AndroidPlatformHelpers::getDataPath () { +string AndroidPlatformHelpers::getDataPath () { JNIEnv *env = ms_get_jni_env(); - jstring jdata_path = (jstring)env->CallObjectMethod(mJavaHelper,mGetDataPathId); + jstring jdata_path = (jstring)env->CallObjectMethod(mJavaHelper, mGetDataPathId); const char *data_path = GetStringUTFChars(env, jdata_path); - std::string dataPath = data_path; + string dataPath = data_path; ReleaseStringUTFChars(env, jdata_path, data_path); return dataPath; } -std::string AndroidPlatformHelpers::getConfigPath () { +string AndroidPlatformHelpers::getConfigPath () { JNIEnv *env = ms_get_jni_env(); - jstring jconfig_path = (jstring)env->CallObjectMethod(mJavaHelper,mGetConfigPathId); + jstring jconfig_path = (jstring)env->CallObjectMethod(mJavaHelper, mGetConfigPathId); const char *config_path = GetStringUTFChars(env, jconfig_path); - std::string configPath = config_path; + string configPath = config_path; ReleaseStringUTFChars(env, jconfig_path, config_path); return configPath; } int AndroidPlatformHelpers::callVoidMethod (jmethodID id) { - JNIEnv *env=ms_get_jni_env(); + JNIEnv *env = ms_get_jni_env(); if (env && mJavaHelper) { - env->CallVoidMethod(mJavaHelper,id); + env->CallVoidMethod(mJavaHelper, id); if (env->ExceptionCheck()) { env->ExceptionClear(); return -1; @@ -199,10 +201,8 @@ int AndroidPlatformHelpers::callVoidMethod (jmethodID id) { return -1; } -PlatformHelpers *createAndroidPlatformHelpers (LinphoneCore *lc, void *system_context) { - return new AndroidPlatformHelpers(lc, system_context); +PlatformHelpers *createAndroidPlatformHelpers (LinphoneCore *lc, void *systemContext) { + return new AndroidPlatformHelpers(lc, systemContext); } LINPHONE_END_NAMESPACE - -#endif diff --git a/src/core/platform-helpers/platform-helpers.cpp b/src/core/platform-helpers/platform-helpers.cpp index 2ac0516ec..624392072 100644 --- a/src/core/platform-helpers/platform-helpers.cpp +++ b/src/core/platform-helpers/platform-helpers.cpp @@ -1,53 +1,50 @@ /* -linphone -Copyright (C) 2017 Belledonne Communications SARL + * platform-helpers.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. +#include "platform-helpers.h" -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 "linphone/utils/utils.h" - -#include "private.h" +// ============================================================================= LINPHONE_BEGIN_NAMESPACE -PlatformHelpers::~PlatformHelpers () {} - StubbedPlatformHelpers::StubbedPlatformHelpers (LinphoneCore *lc) : PlatformHelpers(lc) {} -void StubbedPlatformHelpers::setDnsServers () { -} -void StubbedPlatformHelpers::acquireWifiLock () { -} -void StubbedPlatformHelpers::releaseWifiLock () { -} -void StubbedPlatformHelpers::acquireMcastLock () { -} -void StubbedPlatformHelpers::releaseMcastLock () { -} -void StubbedPlatformHelpers::acquireCpuLock () { -} -void StubbedPlatformHelpers::releaseCpuLock () { -} +void StubbedPlatformHelpers::setDnsServers () {} + +void StubbedPlatformHelpers::acquireWifiLock () {} + +void StubbedPlatformHelpers::releaseWifiLock () {} + +void StubbedPlatformHelpers::acquireMcastLock () {} + +void StubbedPlatformHelpers::releaseMcastLock () {} + +void StubbedPlatformHelpers::acquireCpuLock () {} + +void StubbedPlatformHelpers::releaseCpuLock () {} + std::string StubbedPlatformHelpers::getDataPath () { - return Utils::getEmptyConstRefObject(); + return ""; } + std::string StubbedPlatformHelpers::getConfigPath () { - return Utils::getEmptyConstRefObject(); -} -StubbedPlatformHelpers::~StubbedPlatformHelpers () { + return ""; } LINPHONE_END_NAMESPACE diff --git a/src/core/platform-helpers/platform-helpers.h b/src/core/platform-helpers/platform-helpers.h index 02c312629..25bd23852 100644 --- a/src/core/platform-helpers/platform-helpers.h +++ b/src/core/platform-helpers/platform-helpers.h @@ -1,39 +1,44 @@ /* -linphone -Copyright (C) 2017 Belledonne Communications SARL - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ + * platform-helpers.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ #ifndef _PLATFORM_HELPERS_H_ #define _PLATFORM_HELPERS_H_ #include -#include "linphone/core.h" #include "linphone/utils/general.h" +// ============================================================================= + +L_DECL_C_STRUCT(LinphoneCore); + LINPHONE_BEGIN_NAMESPACE /** * This interface aims at abstracting some features offered by the platform, most often mobile platforms. - * A per platform implementation is to be made to implement these features, if available on the platform + * A per platform implementation is to be made to implement these features, if available on the platform. */ class PlatformHelpers { public: - //This method shall retrieve DNS server list from the platform and assign it to the core. + virtual ~PlatformHelpers () = default; + + // This method shall retrieve DNS server list from the platform and assign it to the core. virtual void setDnsServers () = 0; virtual void acquireWifiLock () = 0; virtual void releaseWifiLock () = 0; @@ -43,16 +48,18 @@ public: virtual void releaseCpuLock () = 0; virtual std::string getDataPath () = 0; virtual std::string getConfigPath () = 0; - virtual ~PlatformHelpers (); protected: inline PlatformHelpers (LinphoneCore *lc) : mCore(lc) {} + LinphoneCore *mCore; }; class StubbedPlatformHelpers : public PlatformHelpers { public: StubbedPlatformHelpers (LinphoneCore *lc); + virtual ~StubbedPlatformHelpers () = default; + void setDnsServers () override; void acquireWifiLock () override; void releaseWifiLock () override; @@ -62,10 +69,9 @@ public: void releaseCpuLock () override; std::string getDataPath () override; std::string getConfigPath () override; - virtual ~StubbedPlatformHelpers (); }; -PlatformHelpers *createAndroidPlatformHelpers (LinphoneCore *lc, void *system_context); +PlatformHelpers *createAndroidPlatformHelpers (LinphoneCore *lc, void *systemContext); LINPHONE_END_NAMESPACE From 49540f6b6f5ab4553f52cae7bb998ebc167baecc Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 19 Oct 2017 16:59:20 +0200 Subject: [PATCH 0592/2215] add paths getter for linux --- src/core/paths/paths-linux.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/core/paths/paths-linux.cpp b/src/core/paths/paths-linux.cpp index 7dd122b18..06cdab9fb 100644 --- a/src/core/paths/paths-linux.cpp +++ b/src/core/paths/paths-linux.cpp @@ -26,14 +26,15 @@ LINPHONE_BEGIN_NAMESPACE +static std::string dataPath = "~/.local/share/linphone"; +static std::string configPath = "~/.config/linphone"; + std::string SysPaths::getDataPath (PlatformHelpers *platformHelper) { - //TODO. - return Utils::getEmptyConstRefObject(); + return dataPath; } std::string SysPaths::getConfigPath (PlatformHelpers *platformHelper) { - //TODO. - return Utils::getEmptyConstRefObject(); + return configPath; } LINPHONE_END_NAMESPACE From 3af62d98d220417bd7bf1df2664b285d39203d10 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 19 Oct 2017 17:41:01 +0200 Subject: [PATCH 0593/2215] Fixed crash in file transfer due to backgroundtaskid not being initialized + removed unused header in jni --- src/chat/chat-message/chat-message-p.h | 2 +- wrappers/java/jni.mustache | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index 1618639fe..bd60625ed 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -141,7 +141,7 @@ private: belle_http_request_listener_t *httpListener = nullptr; SalOp *salOp = nullptr; SalCustomHeader *salCustomHeaders = nullptr; - unsigned long backgroundTaskId; + unsigned long backgroundTaskId = 0; unsigned char currentSendStep = Step::None; bool applyModifiers = true; // Cache for returned values, used for compatibility with previous C API diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index 044e00fe4..8513e753c 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -36,7 +36,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifdef __ANDROID__ #include -#include #endif /* __ANDROID__ */ static JavaVM *jvm = NULL; From c88983da3d4a48aaadb1ea2d23f6062897fe31ac Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 20 Oct 2017 10:43:06 +0200 Subject: [PATCH 0594/2215] Fixed compil for android armv7, issue was cast increases required alignment from 4 to 8 --- coreapi/linphonecore.c | 2 +- coreapi/misc.c | 2 +- src/c-wrapper/api/c-call-stats.cpp | 2 +- tester/call_single_tester.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 8e8ab2df0..47be80186 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2317,7 +2317,7 @@ LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable, } LinphoneCore *linphone_core_ref(LinphoneCore *lc) { - return (LinphoneCore *)belle_sip_object_ref(BELLE_SIP_OBJECT(lc)); + return reinterpret_cast(belle_sip_object_ref(BELLE_SIP_OBJECT(lc))); } void linphone_core_unref(LinphoneCore *lc) { diff --git a/coreapi/misc.c b/coreapi/misc.c index c48265397..41f14fd92 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -167,7 +167,7 @@ int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, sock return -1; } if (!res) return -1; - memcpy(ss,res->ai_addr,res->ai_addrlen); + memcpy(ss,res->ai_addr,(size_t)res->ai_addrlen); *socklen=(socklen_t)res->ai_addrlen; freeaddrinfo(res); return 0; diff --git a/src/c-wrapper/api/c-call-stats.cpp b/src/c-wrapper/api/c-call-stats.cpp index 50caec3f8..76dfd56f0 100644 --- a/src/c-wrapper/api/c-call-stats.cpp +++ b/src/c-wrapper/api/c-call-stats.cpp @@ -160,7 +160,7 @@ bool_t _linphone_call_stats_rtcp_received_via_mux (const LinphoneCallStats *stat // ============================================================================= LinphoneCallStats *linphone_call_stats_ref (LinphoneCallStats* stats) { - return (LinphoneCallStats*) belle_sip_object_ref(stats); + return reinterpret_cast(belle_sip_object_ref(stats)); } void linphone_call_stats_unref (LinphoneCallStats* stats) { diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index 9d3d108c6..7e2d0126a 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -864,7 +864,7 @@ static void call_with_specified_codec_bitrate(void) { int max_bw=50; #ifdef __arm__ - if (ms_factory_get_cpu_count(marie->lc->factory) <2) { /*2 opus codec channel + resampler is too much for a single core*/ + if (ms_factory_get_cpu_count(linphone_core_get_ms_factory(marie->lc)) <2) { /*2 opus codec channel + resampler is too much for a single core*/ #ifndef __ANDROID__ codec = "speex"; rate = 8000; From e97343cb78f61217701668990cfe5f786c2c3c79 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 20 Oct 2017 13:51:48 +0200 Subject: [PATCH 0595/2215] feat(Event): ChatMessageEvent is now a ConferenceEvent --- include/linphone/api/c-event-log.h | 4 +- include/linphone/api/c-types.h | 2 +- include/linphone/enums/event-log-enums.h | 2 +- src/CMakeLists.txt | 3 +- src/c-wrapper/api/c-event-log.cpp | 16 +- src/c-wrapper/c-wrapper.h | 4 +- src/chat/chat-message/chat-message.cpp | 7 + src/chat/chat-message/chat-message.h | 1 + src/db/main-db-p.h | 17 +- src/db/main-db.cpp | 323 ++++++++---------- src/db/main-db.h | 6 +- .../conference-chat-message-event.cpp} | 20 +- .../conference-chat-message-event.h} | 12 +- src/event-log/events.h | 2 +- tester/events-db-tester.cpp | 6 +- 15 files changed, 195 insertions(+), 230 deletions(-) rename src/event-log/{chat/chat-message-event.cpp => conference/conference-chat-message-event.cpp} (70%) rename src/event-log/{chat/chat-message-event.h => conference/conference-chat-message-event.h} (77%) diff --git a/include/linphone/api/c-event-log.h b/include/linphone/api/c-event-log.h index 06840e39d..6450e24c2 100644 --- a/include/linphone/api/c-event-log.h +++ b/include/linphone/api/c-event-log.h @@ -56,12 +56,12 @@ LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_participant_event_get const LinphoneConferenceParticipantEvent *conference_participant_event ); -LINPHONE_PUBLIC LinphoneChatMessageEvent *linphone_chat_message_event_new ( +LINPHONE_PUBLIC LinphoneConferenceChatMessageEvent *linphone_chat_message_event_new ( LinphoneChatMessage *chat_message, time_t time ); LINPHONE_PUBLIC LinphoneChatMessage *linphone_chat_message_event_get_chat_message ( - const LinphoneChatMessageEvent *chat_message_event + const LinphoneConferenceChatMessageEvent *chat_message_event ); #ifdef __cplusplus diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index cce57f2a4..6eb782d4d 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -133,7 +133,7 @@ typedef struct _LinphoneConferenceParticipantEvent LinphoneConferenceParticipant typedef struct _LinphoneConferenceParticipantDeviceEvent LinphoneConferenceParticipantDeviceEvent; typedef struct _LinphoneConferenceSubjectEvent LinphoneConferenceSubjectEvent; typedef struct _LinphoneEventLog LinphoneEventLog; -typedef struct _LinphoneChatMessageEvent LinphoneChatMessageEvent; +typedef struct _LinphoneConferenceChatMessageEvent LinphoneConferenceChatMessageEvent; // ============================================================================= // C Enums. diff --git a/include/linphone/enums/event-log-enums.h b/include/linphone/enums/event-log-enums.h index b209427bb..e5c0c92f8 100644 --- a/include/linphone/enums/event-log-enums.h +++ b/include/linphone/enums/event-log-enums.h @@ -24,11 +24,11 @@ #define L_ENUM_VALUES_EVENT_LOG_TYPE(F) \ F(None) \ - F(ChatMessage) \ F(CallStart) \ F(CallEnd) \ F(ConferenceCreated) \ F(ConferenceDestroyed) \ + F(ConferenceChatMessage) \ F(ConferenceParticipantAdded) \ F(ConferenceParticipantRemoved) \ F(ConferenceParticipantSetAdmin) \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0ea9757d2..a861872d0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -94,7 +94,6 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES dial-plan/dial-plan.h enums.h event-log/call/call-event.h - event-log/chat/chat-message-event.h event-log/conference/conference-event-p.h event-log/conference/conference-event.h event-log/conference/conference-notified-event-p.h @@ -183,7 +182,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES db/session/db-session.cpp dial-plan/dial-plan.cpp event-log/call/call-event.cpp - event-log/chat/chat-message-event.cpp + event-log/conference/conference-chat-message-event.cpp event-log/conference/conference-event.cpp event-log/conference/conference-notified-event.cpp event-log/conference/conference-participant-device-event.cpp diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index b1469ec0c..c6a2a21d6 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -27,13 +27,13 @@ // ============================================================================= -L_DECLARE_C_BASE_OBJECT_IMPL(EventLog); L_DECLARE_C_BASE_OBJECT_IMPL(CallEvent); +L_DECLARE_C_BASE_OBJECT_IMPL(ConferenceChatMessageEvent); L_DECLARE_C_BASE_OBJECT_IMPL(ConferenceEvent); -L_DECLARE_C_BASE_OBJECT_IMPL(ConferenceParticipantEvent); L_DECLARE_C_BASE_OBJECT_IMPL(ConferenceParticipantDeviceEvent); +L_DECLARE_C_BASE_OBJECT_IMPL(ConferenceParticipantEvent); L_DECLARE_C_BASE_OBJECT_IMPL(ConferenceSubjectEvent); -L_DECLARE_C_BASE_OBJECT_IMPL(ChatMessageEvent); +L_DECLARE_C_BASE_OBJECT_IMPL(EventLog); using namespace std; @@ -124,11 +124,11 @@ const LinphoneAddress *linphone_conference_participant_event_get_participant_add // Message event. // ----------------------------------------------------------------------------- -LinphoneChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage *chat_message, time_t time) { - LinphoneChatMessageEvent *chat_message_event = _linphone_ChatMessageEvent_init(); +LinphoneConferenceChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage *chat_message, time_t time) { + LinphoneConferenceChatMessageEvent *chat_message_event = _linphone_ConferenceChatMessageEvent_init(); L_SET_CPP_PTR_FROM_C_OBJECT( chat_message_event, - new LinphonePrivate::ChatMessageEvent( + new LinphonePrivate::ConferenceChatMessageEvent( time, L_GET_CPP_PTR_FROM_C_OBJECT(chat_message) ) @@ -136,7 +136,9 @@ LinphoneChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage * return chat_message_event; } -LinphoneChatMessage *linphone_chat_message_event_get_chat_message (const LinphoneChatMessageEvent *chat_message_event) { +LinphoneChatMessage *linphone_chat_message_event_get_chat_message ( + const LinphoneConferenceChatMessageEvent *chat_message_event +) { return L_GET_C_BACK_PTR( L_GET_CPP_PTR_FROM_C_OBJECT(chat_message_event)->getChatMessage() ); diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index c9c9bbf53..08a8d26a4 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -33,11 +33,11 @@ F(Call, Call) \ F(CallEvent, CallEvent) \ F(ChatMessage, ChatMessage) \ - F(ChatMessageEvent, ChatMessageEvent) \ F(ChatRoom, ChatRoom) \ + F(ConferenceChatMessageEvent, ConferenceChatMessageEvent) \ F(ConferenceEvent, ConferenceEvent) \ - F(ConferenceParticipantEvent, ConferenceParticipantEvent) \ F(ConferenceParticipantDeviceEvent, ConferenceParticipantDeviceEvent) \ + F(ConferenceParticipantEvent, ConferenceParticipantEvent) \ F(ConferenceSubjectEvent, ConferenceSubjectEvent) \ F(DialPlan, DialPlan) \ F(EventLog, EventLog) \ diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index e80b6a0d6..6253922f5 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -1364,6 +1364,13 @@ const list& ChatMessage::getContents () const { return d->contents; } +void ChatMessage::addContent (Content &&content) { + L_D(); + if (d->isReadOnly) return; + + d->contents.push_back(move(content)); +} + void ChatMessage::addContent (const Content &content) { L_D(); if (d->isReadOnly) return; diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index c45253e7f..b1c0a0139 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -94,6 +94,7 @@ public: bool isReadOnly () const; const std::list &getContents () const; + void addContent (Content &&content); void addContent (const Content &content); void removeContent (const Content &content); diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 84fdf413c..421c0ecdf 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -42,29 +42,18 @@ private: long insertSipAddress (const std::string &sipAddress); void insertContent (long messageEventId, const Content &content); long insertContentType (const std::string &contentType); - long insertEvent (EventLog::Type type, const tm &date); long insertChatRoom (long sipAddressId, int capabilities, const tm &date); void insertChatRoomParticipant (long chatRoomId, long sipAddressId, bool isAdmin); - - long insertMessageEvent ( - const MessageEventReferences &references, - int state, - int direction, - const std::string &imdnMessageId, - bool isSecured, - const std::list &contents - ); - - void insertMessageParticipant (long messageEventId, long sipAddressId, int state); + void insertChatMessageParticipant (long messageEventId, long sipAddressId, int state); // --------------------------------------------------------------------------- // Events API. // --------------------------------------------------------------------------- long insertEvent (const EventLog &eventLog); - long insertCallEvent (const EventLog &eventLog); - long insertMessageEvent (const EventLog &eventLog); long insertConferenceEvent (const EventLog &eventLog, long *chatRoomId = nullptr); + long insertConferenceCallEvent (const EventLog &eventLog); + long insertConferenceChatMessageEvent (const EventLog &eventLog); long insertConferenceNotifiedEvent (const EventLog &eventLog); long insertConferenceParticipantEvent (const EventLog &eventLog); long insertConferenceParticipantDeviceEvent (const EventLog &eventLog); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 191932e60..5c250afa4 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -42,13 +42,6 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -struct MessageEventReferences { - long eventId; - long localSipAddressId; - long remoteSipAddressId; - long chatRoomId; -}; - // ----------------------------------------------------------------------------- MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} @@ -73,9 +66,13 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} } static constexpr EnumToSql eventFilterToSql[] = { - { MainDb::MessageFilter, "1" }, - { MainDb::CallFilter, "2" }, - { MainDb::ConferenceFilter, "3" } + { MainDb::ConferenceCallFilter, "type = 1 OR type = 2" }, + { MainDb::ConferenceChatMessageFilter, "type = 5" }, + { + MainDb::ConferenceInfoFilter, + "type = 3 OR type = 4 OR type = 6 OR type = 7 OR type = 8 OR " + "type = 9 OR type = 10 OR type = 11 OR type = 12" + } }; static constexpr const char *mapEventFilterToSql (MainDb::Filter filter) { @@ -107,7 +104,6 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} sql += " WHERE "; } else sql += " OR "; - sql += " type = "; sql += mapEventFilterToSql(filter); } @@ -135,13 +131,13 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} soci::session *session = dbSession.getBackendSession(); long contentTypeId = insertContentType(content.getContentType().asString()); - *session << "INSERT INTO message_content (event_id, content_type_id, body) VALUES" + *session << "INSERT INTO chat_message_content (event_id, content_type_id, body) VALUES" " (:eventId, :contentTypeId, :body)", soci::use(eventId), soci::use(contentTypeId), soci::use(content.getBodyAsString()); long messageContentId = q->getLastInsertId(); for (const auto &appData : content.getAppDataMap()) - *session << "INSERT INTO message_content_app_data (message_content_id, key, data) VALUES" + *session << "INSERT INTO chat_message_content_app_data (chat_message_content_id, key, data) VALUES" " (:messageContentId, :key, :data)", soci::use(messageContentId), soci::use(appData.first), soci::use(appData.second); } @@ -159,15 +155,6 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return q->getLastInsertId(); } - long MainDbPrivate::insertEvent (EventLog::Type type, const tm &date) { - L_Q(); - soci::session *session = dbSession.getBackendSession(); - - *session << "INSERT INTO event (type, date) VALUES (:type, :date)", - soci::use(static_cast(type)), soci::use(date); - return q->getLastInsertId(); - } - long MainDbPrivate::insertChatRoom (long sipAddressId, int capabilities, const tm &date) { soci::session *session = dbSession.getBackendSession(); @@ -199,45 +186,16 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} soci::use(chatRoomId), soci::use(sipAddressId), soci::use(static_cast(isAdmin)); } - long MainDbPrivate::insertMessageEvent ( - const MessageEventReferences &references, - int state, - int direction, - const string &imdnMessageId, - bool isSecured, - const list &contents - ) { - L_Q(); - soci::session *session = dbSession.getBackendSession(); - - *session << "INSERT INTO message_event (" - " event_id, chat_room_id, local_sip_address_id, remote_sip_address_id," - " state, direction, imdn_message_id, is_secured" - ") VALUES (" - " :eventId, :chatRoomId, :localSipaddressId, :remoteSipaddressId," - " :state, :direction, :imdnMessageId, :isSecured" - ")", soci::use(references.eventId), soci::use(references.chatRoomId), soci::use(references.localSipAddressId), - soci::use(references.remoteSipAddressId), soci::use(state), soci::use(direction), - soci::use(imdnMessageId), soci::use(isSecured ? 1 : 0); - - long eventId = q->getLastInsertId(); - - for (const auto &content : contents) - insertContent(eventId, content); - - return eventId; - } - - void MainDbPrivate::insertMessageParticipant (long eventId, long sipAddressId, int state) { + void MainDbPrivate::insertChatMessageParticipant (long eventId, long sipAddressId, int state) { soci::session *session = dbSession.getBackendSession(); soci::statement statement = ( - session->prepare << "UPDATE message_participant SET state = :state" + session->prepare << "UPDATE chat_message_participant SET state = :state" " WHERE event_id = :eventId AND sip_address_id = :sipAddressId", soci::use(state), soci::use(eventId), soci::use(sipAddressId) ); statement.execute(true); if (statement.get_affected_rows() == 0 && state != static_cast(ChatMessage::State::Displayed)) - *session << "INSERT INTO message_participant (event_id, sip_address_id, state)" + *session << "INSERT INTO chat_message_participant (event_id, sip_address_id, state)" " VALUES (:eventId, :sipAddressId, :state)", soci::use(eventId), soci::use(sipAddressId), soci::use(state); } @@ -245,42 +203,12 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} // ----------------------------------------------------------------------------- long MainDbPrivate::insertEvent (const EventLog &eventLog) { - return insertEvent(eventLog.getType(), Utils::getLongAsTm(eventLog.getTime())); - } + L_Q(); + soci::session *session = dbSession.getBackendSession(); - long MainDbPrivate::insertCallEvent (const EventLog &eventLog) { - // TODO. - return 0; - } - - long MainDbPrivate::insertMessageEvent (const EventLog &eventLog) { - shared_ptr chatMessage = static_cast(eventLog).getChatMessage(); - shared_ptr chatRoom = chatMessage->getChatRoom(); - if (!chatRoom) { - lError() << "Unable to get a valid chat room. It was removed from database."; - return -1; - } - - tm eventTime = Utils::getLongAsTm(static_cast(eventLog.getTime())); - - struct MessageEventReferences references; - references.eventId = insertEvent(EventLog::Type::ChatMessage, eventTime); - references.localSipAddressId = insertSipAddress(chatMessage->getLocalAddress().asString()); - references.remoteSipAddressId = insertSipAddress(chatMessage->getRemoteAddress().asString()); - references.chatRoomId = insertChatRoom( - references.remoteSipAddressId, - chatRoom->getCapabilities(), - eventTime - ); - - return insertMessageEvent ( - references, - static_cast(chatMessage->getState()), - static_cast(chatMessage->getDirection()), - chatMessage->getImdnMessageId(), - chatMessage->isSecured(), - chatMessage->getContents() - ); + *session << "INSERT INTO event (type, date) VALUES (:type, :date)", + soci::use(static_cast(eventLog.getType())), soci::use(Utils::getLongAsTm(eventLog.getTime())); + return q->getLastInsertId(); } long MainDbPrivate::insertConferenceEvent (const EventLog &eventLog, long *chatRoomId) { @@ -299,6 +227,44 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return eventId; } + long MainDbPrivate::insertConferenceCallEvent (const EventLog &eventLog) { + // TODO. + return 0; + } + + long MainDbPrivate::insertConferenceChatMessageEvent (const EventLog &eventLog) { + shared_ptr chatMessage = static_cast(eventLog).getChatMessage(); + shared_ptr chatRoom = chatMessage->getChatRoom(); + if (!chatRoom) { + lError() << "Unable to get a valid chat room. It was removed from database."; + return -1; + } + + tm eventTime = Utils::getLongAsTm(static_cast(eventLog.getTime())); + + long localSipAddressId = insertSipAddress(chatMessage->getLocalAddress().asString()); + long remoteSipAddressId = insertSipAddress(chatMessage->getRemoteAddress().asString()); + insertChatRoom(remoteSipAddressId, chatRoom->getCapabilities(), eventTime); + long eventId = insertConferenceEvent(eventLog); + + soci::session *session = dbSession.getBackendSession(); + + *session << "INSERT INTO conference_chat_message_event (" + " event_id, local_sip_address_id, remote_sip_address_id," + " state, direction, imdn_message_id, is_secured" + ") VALUES (" + " :eventId, :localSipaddressId, :remoteSipaddressId," + " :state, :direction, :imdnMessageId, :isSecured" + ")", soci::use(eventId), soci::use(localSipAddressId), soci::use(remoteSipAddressId), + soci::use(static_cast(chatMessage->getState())), soci::use(static_cast(chatMessage->getDirection())), + soci::use(chatMessage->getImdnMessageId()), soci::use(chatMessage->isSecured() ? 1 : 0); + + for (const auto &content : chatMessage->getContents()) + insertContent(eventId, content); + + return eventId; + } + long MainDbPrivate::insertConferenceNotifiedEvent (const EventLog &eventLog) { long chatRoomId; long eventId = insertConferenceEvent(eventLog, &chatRoomId); @@ -351,34 +317,6 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return eventId; } -// ----------------------------------------------------------------------------- - - #define LEGACY_MESSAGE_COL_LOCAL_ADDRESS 1 - #define LEGACY_MESSAGE_COL_REMOTE_ADDRESS 2 - #define LEGACY_MESSAGE_COL_DIRECTION 3 - #define LEGACY_MESSAGE_COL_TEXT 4 - #define LEGACY_MESSAGE_COL_STATE 7 - #define LEGACY_MESSAGE_COL_URL 8 - #define LEGACY_MESSAGE_COL_DATE 9 - #define LEGACY_MESSAGE_COL_APP_DATA 10 - #define LEGACY_MESSAGE_COL_CONTENT_ID 11 - #define LEGACY_MESSAGE_COL_IMDN_MESSAGE_ID 12 - #define LEGACY_MESSAGE_COL_CONTENT_TYPE 13 - #define LEGACY_MESSAGE_COL_IS_SECURED 14 - - template - static T getValueFromLegacyMessage (const soci::row &message, int index, bool &isNull) { - isNull = false; - - try { - return message.get(static_cast(index)); - } catch (const exception &) { - isNull = true; - } - - return T(); - } - // ----------------------------------------------------------------------------- void MainDb::init () { @@ -503,9 +441,8 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} ")"; *session << - "CREATE TABLE IF NOT EXISTS message_event (" + "CREATE TABLE IF NOT EXISTS conference_chat_message_event (" " event_id INT UNSIGNED PRIMARY KEY," - " chat_room_id INT UNSIGNED NOT NULL," " local_sip_address_id INT UNSIGNED NOT NULL," " remote_sip_address_id INT UNSIGNED NOT NULL," @@ -517,10 +454,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} " is_secured BOOLEAN NOT NULL," " FOREIGN KEY (event_id)" - " REFERENCES event(id)" - " ON DELETE CASCADE," - " FOREIGN KEY (chat_room_id)" - " REFERENCES chat_room(peer_sip_address_id)" + " REFERENCES conference_event(id)" " ON DELETE CASCADE," " FOREIGN KEY (local_sip_address_id)" " REFERENCES sip_address(id)" @@ -531,14 +465,14 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} ")"; *session << - "CREATE TABLE IF NOT EXISTS message_participant (" + "CREATE TABLE IF NOT EXISTS chat_message_participant (" " event_id INT UNSIGNED NOT NULL," " sip_address_id INT UNSIGNED NOT NULL," " state TINYINT UNSIGNED NOT NULL," " PRIMARY KEY (event_id, sip_address_id)," " FOREIGN KEY (event_id)" - " REFERENCES message_event(event_id)" + " REFERENCES conference_chat_message_event(event_id)" " ON DELETE CASCADE," " FOREIGN KEY (sip_address_id)" " REFERENCES sip_address(id)" @@ -546,14 +480,14 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} ")"; *session << - "CREATE TABLE IF NOT EXISTS message_content (" + "CREATE TABLE IF NOT EXISTS chat_message_content (" " id" + primaryKeyAutoIncrementStr() + "," " event_id INT UNSIGNED NOT NULL," " content_type_id INT UNSIGNED NOT NULL," " body TEXT NOT NULL," " FOREIGN KEY (event_id)" - " REFERENCES message_event(event_id)" + " REFERENCES conference_chat_message_event(event_id)" " ON DELETE CASCADE," " FOREIGN KEY (content_type_id)" " REFERENCES content_type(id)" @@ -561,46 +495,46 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} ")"; *session << - "CREATE TABLE IF NOT EXISTS message_content_app_data (" - " message_content_id INT UNSIGNED NOT NULL," + "CREATE TABLE IF NOT EXISTS chat_message_content_app_data (" + " chat_message_content_id INT UNSIGNED NOT NULL," " key VARCHAR(255)," " data BLOB," - " PRIMARY KEY (message_content_id, key)," - " FOREIGN KEY (message_content_id)" - " REFERENCES message_content(id)" + " PRIMARY KEY (chat_message_content_id, key)," + " FOREIGN KEY (chat_message_content_id)" + " REFERENCES chat_message_content(id)" " ON DELETE CASCADE" ")"; *session << - "CREATE TABLE IF NOT EXISTS message_crypto_data (" + "CREATE TABLE IF NOT EXISTS conference_message_crypto_data (" " event_id INT UNSIGNED NOT NULL," " key VARCHAR(255)," " data BLOB," " PRIMARY KEY (event_id, key)," " FOREIGN KEY (event_id)" - " REFERENCES message_event(event_id)" + " REFERENCES conference_chat_message_event(event_id)" " ON DELETE CASCADE" ")"; // Trigger to delete participant_message cache entries. string displayedId = Utils::toString(static_cast(ChatMessage::State::Displayed)); string participantMessageDeleter = - "CREATE TRIGGER IF NOT EXISTS message_participant_deleter" - " AFTER UPDATE OF state ON message_participant FOR EACH ROW" + "CREATE TRIGGER IF NOT EXISTS chat_message_participant_deleter" + " AFTER UPDATE OF state ON chat_message_participant FOR EACH ROW" " WHEN NEW.state = "; participantMessageDeleter += displayedId; participantMessageDeleter += " AND (SELECT COUNT(*) FROM (" - " SELECT state FROM message_participant WHERE" - " NEW.event_id = message_participant.event_id" + " SELECT state FROM chat_message_participant WHERE" + " NEW.event_id = chat_message_participant.event_id" " AND state <> "; participantMessageDeleter += displayedId; participantMessageDeleter += " LIMIT 1" " )) = 0" " BEGIN" - " DELETE FROM message_participant WHERE NEW.event_id = message_participant.event_id;" - " UPDATE message_event SET state = "; + " DELETE FROM chat_message_participant WHERE NEW.event_id = chat_message_participant.event_id;" + " UPDATE conference_chat_message_event SET state = "; participantMessageDeleter += displayedId; participantMessageDeleter += " WHERE event_id = NEW.event_id;" " END"; @@ -626,13 +560,13 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} case EventLog::Type::None: return false; - case EventLog::Type::ChatMessage: - d->insertMessageEvent(eventLog); + case EventLog::Type::ConferenceChatMessage: + d->insertConferenceChatMessageEvent(eventLog); break; case EventLog::Type::CallStart: case EventLog::Type::CallEnd: - d->insertCallEvent(eventLog); + d->insertConferenceCallEvent(eventLog); break; case EventLog::Type::ConferenceCreated: @@ -698,7 +632,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} } string query = "DELETE FROM event" + - buildSqlEventFilter({ MessageFilter, CallFilter, ConferenceFilter }, mask); + buildSqlEventFilter({ ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter }, mask); L_BEGIN_LOG_EXCEPTION @@ -717,7 +651,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} } string query = "SELECT COUNT(*) FROM event" + - buildSqlEventFilter({ MessageFilter, CallFilter, ConferenceFilter }, mask); + buildSqlEventFilter({ ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter }, mask); int count = 0; L_BEGIN_LOG_EXCEPTION @@ -744,12 +678,14 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} soci::session *session = d->dbSession.getBackendSession(); - string query = "SELECT COUNT(*) FROM message_event"; + string query = "SELECT COUNT(*) FROM conference_chat_message_event"; if (peerAddress.empty()) *session << query, soci::into(count); else { - query += " WHERE chat_room_id = (" - " SELECT id FROM sip_address WHERE value = :peerAddress" + query += " WHERE event_id IN (" + " SELECT event_id FROM conference_event WHERE chat_room_id = (" + " SELECT id FROM sip_address WHERE value = :peerAddress" + " )" ")"; *session << query, soci::use(peerAddress), soci::into(count); @@ -770,14 +706,16 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} int count = 0; - string query = "SELECT COUNT(*) FROM message_event WHERE"; + string query = "SELECT COUNT(*) FROM conference_chat_message_event WHERE"; if (!peerAddress.empty()) - query += " chat_room_id = (" - " SELECT id FROM sip_address WHERE value = :peerAddress" - ") AND "; + query += " event_id IN (" + " SELECT event_id FROM conference_event WHERE chat_room_id = (" + " SELECT id FROM sip_address WHERE value = :peerAddress" + " )" + ") AND"; query += " direction = " + Utils::toString(static_cast(ChatMessage::Direction::Incoming)) + - + " AND state <> " + Utils::toString(static_cast(ChatMessage::State::Displayed)); + + " AND state <> " + Utils::toString(static_cast(ChatMessage::State::Displayed)); L_BEGIN_LOG_EXCEPTION @@ -834,11 +772,9 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} } string query; - if (mask == MainDb::NoFilter || mask & MessageFilter) - query += "SELECT event_id FROM message_event WHERE chat_room_id = (" - " SELECT peer_sip_address_id FROM chat_room WHERE peer_sip_address_id = (" - " SELECT id FROM sip_address WHERE value = :peerAddress" - " )" + if (mask == MainDb::NoFilter || mask & ConferenceChatMessageFilter) + query += "SELECT event_id FROM conference_event WHERE chat_room_id = (" + " SELECT id FROM sip_address WHERE value = :peerAddress" ")"; if (query.empty()) @@ -890,6 +826,32 @@ shared_ptr MainDb::findChatRoom (const string &peerAddress) const { // ----------------------------------------------------------------------------- + #define LEGACY_MESSAGE_COL_LOCAL_ADDRESS 1 + #define LEGACY_MESSAGE_COL_REMOTE_ADDRESS 2 + #define LEGACY_MESSAGE_COL_DIRECTION 3 + #define LEGACY_MESSAGE_COL_TEXT 4 + #define LEGACY_MESSAGE_COL_STATE 7 + #define LEGACY_MESSAGE_COL_URL 8 + #define LEGACY_MESSAGE_COL_DATE 9 + #define LEGACY_MESSAGE_COL_APP_DATA 10 + #define LEGACY_MESSAGE_COL_CONTENT_ID 11 + #define LEGACY_MESSAGE_COL_IMDN_MESSAGE_ID 12 + #define LEGACY_MESSAGE_COL_CONTENT_TYPE 13 + #define LEGACY_MESSAGE_COL_IS_SECURED 14 + + template + static T getValueFromLegacyMessage (const soci::row &message, int index, bool &isNull) { + isNull = false; + + try { + return message.get(static_cast(index)); + } catch (const exception &) { + isNull = true; + } + + return T(); + } + bool MainDb::import (Backend, const string ¶meters) { L_D(); @@ -971,33 +933,32 @@ shared_ptr MainDb::findChatRoom (const string &peerAddress) const { content.setAppData("legacy", appData); } - struct MessageEventReferences references; - references.eventId = d->insertEvent(EventLog::Type::ChatMessage, date); - references.localSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_LOCAL_ADDRESS)); - references.remoteSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_REMOTE_ADDRESS)); - references.chatRoomId = d->insertChatRoom( - references.remoteSipAddressId, - static_cast(ChatRoom::Capabilities::Basic), - date - ); + soci::session *session = d->dbSession.getBackendSession(); + *session << "INSERT INTO event (type, date) VALUES (:type, :date)", + soci::use(static_cast(EventLog::Type::ConferenceChatMessage)), soci::use(date); - d->insertChatRoomParticipant(references.chatRoomId, references.remoteSipAddressId, false); + long eventId = getLastInsertId(); + long localSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_LOCAL_ADDRESS)); + long remoteSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_REMOTE_ADDRESS)); + long chatRoomId = d->insertChatRoom(remoteSipAddressId, static_cast(ChatRoom::Capabilities::Basic), date); - long eventId = d->insertMessageEvent ( - references, - state, - direction, - message.get(LEGACY_MESSAGE_COL_IMDN_MESSAGE_ID, ""), - !!message.get(LEGACY_MESSAGE_COL_IS_SECURED, 0), - { move(content) } - ); + *session << "INSERT INTO conference_event (event_id, chat_room_id)" + " VALUES (:eventId, :chatRoomId)", soci::use(eventId), soci::use(chatRoomId); + + *session << "INSERT INTO conference_chat_message_event (" + " event_id, local_sip_address_id, remote_sip_address_id," + " state, direction, imdn_message_id, is_secured" + ") VALUES (" + " :eventId, :localSipaddressId, :remoteSipaddressId," + " :state, :direction, '', :isSecured" + ")", soci::use(eventId), soci::use(localSipAddressId), soci::use(remoteSipAddressId), + soci::use(state), soci::use(direction), soci::use(message.get(LEGACY_MESSAGE_COL_IS_SECURED, 0)); + + d->insertContent(eventId, content); + d->insertChatRoomParticipant(chatRoomId, remoteSipAddressId, false); if (state != static_cast(ChatMessage::State::Displayed)) - d->insertMessageParticipant( - eventId, - references.remoteSipAddressId, - state - ); + d->insertChatMessageParticipant(eventId, remoteSipAddressId, state); } tr.commit(); diff --git a/src/db/main-db.h b/src/db/main-db.h index ae1dfe40f..08531f11d 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -38,9 +38,9 @@ class LINPHONE_PUBLIC MainDb : public AbstractDb { public: enum Filter { NoFilter = 0x0, - MessageFilter = 0x1, - CallFilter = 0x2, - ConferenceFilter = 0x4 + ConferenceCallFilter = 0x1, + ConferenceChatMessageFilter = 0x2, + ConferenceInfoFilter = 0x4 }; typedef int FilterMask; diff --git a/src/event-log/chat/chat-message-event.cpp b/src/event-log/conference/conference-chat-message-event.cpp similarity index 70% rename from src/event-log/chat/chat-message-event.cpp rename to src/event-log/conference/conference-chat-message-event.cpp index 498c417ac..cfc7981ef 100644 --- a/src/event-log/chat/chat-message-event.cpp +++ b/src/event-log/conference/conference-chat-message-event.cpp @@ -1,5 +1,5 @@ /* - * chat-message-event.cpp + * conference-chat-message-event.cpp * Copyright (C) 2010-2017 Belledonne Communications SARL * * This program is free software; you can redistribute it and/or @@ -17,8 +17,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "chat-message-event.h" -#include "event-log/event-log-p.h" +#include "chat/chat-message/chat-message.h" +#include "conference-chat-message-event.h" +#include "conference-event-p.h" // ============================================================================= @@ -26,23 +27,28 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -class ChatMessageEventPrivate : public EventLogPrivate { +class ConferenceChatMessageEventPrivate : public ConferenceEventPrivate { public: shared_ptr chatMessage; }; // ----------------------------------------------------------------------------- -ChatMessageEvent::ChatMessageEvent ( +ConferenceChatMessageEvent::ConferenceChatMessageEvent ( time_t time, const shared_ptr &chatMessage -) : EventLog(*new ChatMessageEventPrivate, EventLog::Type::ChatMessage, time) { +) : ConferenceEvent( + *new ConferenceChatMessageEventPrivate, + EventLog::Type::ConferenceChatMessage, + time, + chatMessage->getRemoteAddress() +) { L_D(); L_ASSERT(chatMessage); d->chatMessage = chatMessage; } -shared_ptr ChatMessageEvent::getChatMessage () const { +shared_ptr ConferenceChatMessageEvent::getChatMessage () const { L_D(); return d->chatMessage; } diff --git a/src/event-log/chat/chat-message-event.h b/src/event-log/conference/conference-chat-message-event.h similarity index 77% rename from src/event-log/chat/chat-message-event.h rename to src/event-log/conference/conference-chat-message-event.h index 82ccc1804..f64cf7afd 100644 --- a/src/event-log/chat/chat-message-event.h +++ b/src/event-log/conference/conference-chat-message-event.h @@ -22,24 +22,24 @@ #include -#include "event-log/event-log.h" +#include "conference-event.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE class ChatMessage; -class ChatMessageEventPrivate; +class ConferenceChatMessageEventPrivate; -class LINPHONE_PUBLIC ChatMessageEvent : public EventLog { +class LINPHONE_PUBLIC ConferenceChatMessageEvent : public ConferenceEvent { public: - ChatMessageEvent (std::time_t time, const std::shared_ptr &chatMessage); + ConferenceChatMessageEvent (std::time_t time, const std::shared_ptr &chatMessage); std::shared_ptr getChatMessage () const; private: - L_DECLARE_PRIVATE(ChatMessageEvent); - L_DISABLE_COPY(ChatMessageEvent); + L_DECLARE_PRIVATE(ConferenceChatMessageEvent); + L_DISABLE_COPY(ConferenceChatMessageEvent); }; LINPHONE_END_NAMESPACE diff --git a/src/event-log/events.h b/src/event-log/events.h index 5911acb3d..bc6b8bab9 100644 --- a/src/event-log/events.h +++ b/src/event-log/events.h @@ -21,7 +21,7 @@ #define _EVENTS_H_ #include "call/call-event.h" -#include "chat/chat-message-event.h" +#include "conference/conference-chat-message-event.h" #include "conference/conference-participant-device-event.h" #include "conference/conference-subject-event.h" diff --git a/tester/events-db-tester.cpp b/tester/events-db-tester.cpp index 159244c28..f27c425e4 100644 --- a/tester/events-db-tester.cpp +++ b/tester/events-db-tester.cpp @@ -44,9 +44,9 @@ static void get_events_count () { MainDb eventsDb; BC_ASSERT_TRUE(eventsDb.connect(MainDb::Sqlite3, getDatabasePath())); BC_ASSERT_EQUAL(eventsDb.getEventsCount(), 4976, int, "%d"); - BC_ASSERT_EQUAL(eventsDb.getEventsCount(MainDb::CallFilter), 0, int, "%d"); - BC_ASSERT_EQUAL(eventsDb.getEventsCount(MainDb::ConferenceFilter), 0, int, "%d"); - BC_ASSERT_EQUAL(eventsDb.getEventsCount(MainDb::MessageFilter), 4976, int, "%d"); + BC_ASSERT_EQUAL(eventsDb.getEventsCount(MainDb::ConferenceCallFilter), 0, int, "%d"); + BC_ASSERT_EQUAL(eventsDb.getEventsCount(MainDb::ConferenceInfoFilter), 0, int, "%d"); + BC_ASSERT_EQUAL(eventsDb.getEventsCount(MainDb::ConferenceChatMessageFilter), 4976, int, "%d"); BC_ASSERT_EQUAL(eventsDb.getEventsCount(MainDb::NoFilter), 4976, int, "%d"); } From 353411e16a3e28539910d41e52a192dd8b989ba1 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 20 Oct 2017 15:37:56 +0200 Subject: [PATCH 0596/2215] feat(MainDb): fetch partially history --- src/db/main-db.cpp | 81 ++++++++++++++++++++++++++++--------- tester/events-db-tester.cpp | 14 ++++++- 2 files changed, 74 insertions(+), 21 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 5c250afa4..c853dadd2 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -66,13 +66,9 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} } static constexpr EnumToSql eventFilterToSql[] = { - { MainDb::ConferenceCallFilter, "type = 1 OR type = 2" }, - { MainDb::ConferenceChatMessageFilter, "type = 5" }, - { - MainDb::ConferenceInfoFilter, - "type = 3 OR type = 4 OR type = 6 OR type = 7 OR type = 8 OR " - "type = 9 OR type = 10 OR type = 11 OR type = 12" - } + { MainDb::ConferenceCallFilter, "1, 2" }, + { MainDb::ConferenceChatMessageFilter, "5" }, + { MainDb::ConferenceInfoFilter, "3, 4, 6, 7, 8, 9, 10, 11, 12" } }; static constexpr const char *mapEventFilterToSql (MainDb::Filter filter) { @@ -83,7 +79,11 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} // ----------------------------------------------------------------------------- - static string buildSqlEventFilter (const list &filters, MainDb::FilterMask mask) { + static string buildSqlEventFilter ( + const list &filters, + MainDb::FilterMask mask, + const string &condKeyWord = "WHERE" + ) { L_ASSERT( find_if(filters.cbegin(), filters.cend(), [](const MainDb::Filter &filter) { return filter == MainDb::NoFilter; @@ -101,12 +101,15 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} if (isStart) { isStart = false; - sql += " WHERE "; + sql += " " + condKeyWord + " type IN ("; } else - sql += " OR "; + sql += ", "; sql += mapEventFilterToSql(filter); } + if (!isStart) + sql += ") "; + return sql; } @@ -738,9 +741,6 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} } // TODO. - (void)peerAddress; - (void)nLast; - (void)mask; return list>(); } @@ -750,17 +750,56 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} int end, FilterMask mask ) const { + L_D(); + + list> events; + if (!isConnected()) { lWarning() << "Unable to get history. Not connected."; - return list>(); + return events; } - // TODO. - (void)peerAddress; - (void)begin; - (void)end; - (void)mask; - return list>(); + if (begin < 0) + begin = 0; + + if (end > 0 && begin > end) { + lWarning() << "Unable to get history. Invalid range."; + return events; + } + + string query = "SELECT id, type, date FROM event" + " WHERE id IN (" + " SELECT event_id FROM conference_event WHERE chat_room_id = (" + " SELECT id FROM sip_address WHERE value = :peerAddress" + " )" + " )"; + query += buildSqlEventFilter({ + ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter + }, mask, "AND"); + query += " ORDER BY id DESC"; + + if (end >= 0) + query += " LIMIT " + Utils::toString(end + 1 - begin); + else + query += " LIMIT -1"; + + if (begin > 0) + query += " OFFSET " + Utils::toString(begin); + + L_BEGIN_LOG_EXCEPTION + + soci::session *session = d->dbSession.getBackendSession(); + soci::transaction tr(*session); + + soci::rowset rows = (session->prepare << query, soci::use(peerAddress)); + for (const auto &row : rows) { + (void)row; + events.push_back(std::make_shared()); + } + + L_END_LOG_EXCEPTION + + return events; } void MainDb::cleanHistory (const string &peerAddress, FilterMask mask) { @@ -771,6 +810,8 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return; } + // TODO: Deal with mask. + string query; if (mask == MainDb::NoFilter || mask & ConferenceChatMessageFilter) query += "SELECT event_id FROM conference_event WHERE chat_room_id = (" diff --git a/tester/events-db-tester.cpp b/tester/events-db-tester.cpp index f27c425e4..608297759 100644 --- a/tester/events-db-tester.cpp +++ b/tester/events-db-tester.cpp @@ -64,11 +64,23 @@ static void get_unread_messages_count () { BC_ASSERT_EQUAL(eventsDb.getUnreadMessagesCount("sip:test-7@sip.linphone.org"), 0, int, "%d"); } +static void get_history () { + MainDb eventsDb; + BC_ASSERT_TRUE(eventsDb.connect(MainDb::Sqlite3, getDatabasePath())); + BC_ASSERT_EQUAL( + eventsDb.getHistory("sip:test-7@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceChatMessageFilter).size(), + 3, + int, + "%d" + ); +} + test_t events_db_tests[] = { TEST_NO_TAG("Open database", open_database), TEST_NO_TAG("Get events count", get_events_count), TEST_NO_TAG("Get messages count", get_messages_count), - TEST_NO_TAG("Get unread messages count", get_unread_messages_count) + TEST_NO_TAG("Get unread messages count", get_unread_messages_count), + TEST_NO_TAG("Get history", get_history) }; test_suite_t events_db_test_suite = { From 44507caa790ac657cd0d557de27bdff994a7e584 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 20 Oct 2017 17:18:37 +0200 Subject: [PATCH 0597/2215] feat(MainDb): fetch in progress --- src/db/main-db-p.h | 8 +++++ src/db/main-db.cpp | 69 +++++++++++++++++++++++++++++++++++-- tester/events-db-tester.cpp | 6 ++++ 3 files changed, 81 insertions(+), 2 deletions(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 421c0ecdf..11dd2308b 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -50,6 +50,14 @@ private: // Events API. // --------------------------------------------------------------------------- + std::shared_ptr selectEvent (long eventId, EventLog::Type type, time_t date) const; + std::shared_ptr selectConferenceEvent (long eventId, EventLog::Type type, time_t date) const; + std::shared_ptr selectConferenceCallEvent (long eventId, EventLog::Type type, time_t date) const; + std::shared_ptr selectConferenceChatMessageEvent (long eventId, EventLog::Type type, time_t date) const; + std::shared_ptr selectConferenceParticipantEvent (long eventId, EventLog::Type type, time_t date) const; + std::shared_ptr selectConferenceParticipantDeviceEvent (long eventId, EventLog::Type type, time_t date) const; + std::shared_ptr selectConferenceSubjectEvent (long eventId, EventLog::Type type, time_t date) const; + long insertEvent (const EventLog &eventLog); long insertConferenceEvent (const EventLog &eventLog, long *chatRoomId = nullptr); long insertConferenceCallEvent (const EventLog &eventLog); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index c853dadd2..6c3ecffcb 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -203,6 +203,71 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} soci::use(eventId), soci::use(sipAddressId), soci::use(state); } +// ----------------------------------------------------------------------------- + + shared_ptr MainDbPrivate::selectEvent (long eventId, EventLog::Type type, time_t date) const { + switch (type) { + case EventLog::Type::None: + return nullptr; + + case EventLog::Type::ConferenceCreated: + case EventLog::Type::ConferenceDestroyed: + return selectConferenceEvent(eventId, type, date); + + case EventLog::Type::CallStart: + case EventLog::Type::CallEnd: + return selectConferenceCallEvent(eventId, type, date); + + case EventLog::Type::ConferenceChatMessage: + return selectConferenceChatMessageEvent(eventId, type, date); + + case EventLog::Type::ConferenceParticipantAdded: + case EventLog::Type::ConferenceParticipantRemoved: + case EventLog::Type::ConferenceParticipantSetAdmin: + case EventLog::Type::ConferenceParticipantUnsetAdmin: + return selectConferenceParticipantEvent(eventId, type, date); + + case EventLog::Type::ConferenceParticipantDeviceAdded: + case EventLog::Type::ConferenceParticipantDeviceRemoved: + return selectConferenceParticipantDeviceEvent(eventId, type, date); + + case EventLog::Type::ConferenceSubjectChanged: + return selectConferenceSubjectEvent(eventId, type, date); + } + + return nullptr; + } + + shared_ptr MainDbPrivate::selectConferenceEvent (long eventId, EventLog::Type type, time_t date) const { + // TODO. + return nullptr; + } + + shared_ptr MainDbPrivate::selectConferenceCallEvent (long eventId, EventLog::Type type, time_t date) const { + // TODO. + return nullptr; + } + + shared_ptr MainDbPrivate::selectConferenceChatMessageEvent (long eventId, EventLog::Type type, time_t date) const { + // TODO. + return nullptr; + } + + shared_ptr MainDbPrivate::selectConferenceParticipantEvent (long eventId, EventLog::Type type, time_t date) const { + // TODO. + return nullptr; + } + + shared_ptr MainDbPrivate::selectConferenceParticipantDeviceEvent (long eventId, EventLog::Type type, time_t date) const { + // TODO. + return nullptr; + } + + shared_ptr MainDbPrivate::selectConferenceSubjectEvent (long eventId, EventLog::Type type, time_t date) const { + // TODO. + return nullptr; + } + // ----------------------------------------------------------------------------- long MainDbPrivate::insertEvent (const EventLog &eventLog) { @@ -793,8 +858,8 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} soci::rowset rows = (session->prepare << query, soci::use(peerAddress)); for (const auto &row : rows) { - (void)row; - events.push_back(std::make_shared()); + tm date = row.get(2); + events.push_back(d->selectEvent(row.get(0), static_cast(row.get(1)), mktime(&date))); } L_END_LOG_EXCEPTION diff --git a/tester/events-db-tester.cpp b/tester/events-db-tester.cpp index 608297759..6a25f0e8f 100644 --- a/tester/events-db-tester.cpp +++ b/tester/events-db-tester.cpp @@ -73,6 +73,12 @@ static void get_history () { int, "%d" ); + BC_ASSERT_EQUAL( + eventsDb.getHistory("sip:test-7@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceCallFilter).size(), + 0, + int, + "%d" + ); } test_t events_db_tests[] = { From be19ba1a3e2e214ba559b1b7168e90f1551d88f0 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 23 Oct 2017 10:22:21 +0200 Subject: [PATCH 0598/2215] feat(MainDb): fetch ConferenceSubjectEvent => OK --- src/db/main-db-p.h | 55 ++++++++++++++++++++++++++---- src/db/main-db.cpp | 85 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 117 insertions(+), 23 deletions(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 11dd2308b..1d896dbf5 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -50,13 +50,54 @@ private: // Events API. // --------------------------------------------------------------------------- - std::shared_ptr selectEvent (long eventId, EventLog::Type type, time_t date) const; - std::shared_ptr selectConferenceEvent (long eventId, EventLog::Type type, time_t date) const; - std::shared_ptr selectConferenceCallEvent (long eventId, EventLog::Type type, time_t date) const; - std::shared_ptr selectConferenceChatMessageEvent (long eventId, EventLog::Type type, time_t date) const; - std::shared_ptr selectConferenceParticipantEvent (long eventId, EventLog::Type type, time_t date) const; - std::shared_ptr selectConferenceParticipantDeviceEvent (long eventId, EventLog::Type type, time_t date) const; - std::shared_ptr selectConferenceSubjectEvent (long eventId, EventLog::Type type, time_t date) const; + std::shared_ptr selectEventFromPeerAddress ( + long eventId, + EventLog::Type type, + time_t date, + const std::string &peerAddress + ) const; + + std::shared_ptr selectConferenceEvent ( + long eventId, + EventLog::Type type, + time_t date, + const std::string &peerAddress + ) const; + + std::shared_ptr selectConferenceCallEvent ( + long eventId, + EventLog::Type type, + time_t date, + const std::string &peerAddress + ) const; + + std::shared_ptr selectConferenceChatMessageEvent ( + long eventId, + EventLog::Type type, + time_t date, + const std::string &peerAddress + ) const; + + std::shared_ptr selectConferenceParticipantEvent ( + long eventId, + EventLog::Type type, + time_t date, + const std::string &peerAddress + ) const; + + std::shared_ptr selectConferenceParticipantDeviceEvent ( + long eventId, + EventLog::Type type, + time_t date, + const std::string &peerAddress + ) const; + + std::shared_ptr selectConferenceSubjectEvent ( + long eventId, + EventLog::Type type, + time_t date, + const std::string &peerAddress + ) const; long insertEvent (const EventLog &eventLog); long insertConferenceEvent (const EventLog &eventLog, long *chatRoomId = nullptr); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 6c3ecffcb..25cc4e00d 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -205,67 +205,115 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} // ----------------------------------------------------------------------------- - shared_ptr MainDbPrivate::selectEvent (long eventId, EventLog::Type type, time_t date) const { + shared_ptr MainDbPrivate::selectEventFromPeerAddress ( + long eventId, + EventLog::Type type, + time_t date, + const string &peerAddress + ) const { switch (type) { case EventLog::Type::None: return nullptr; case EventLog::Type::ConferenceCreated: case EventLog::Type::ConferenceDestroyed: - return selectConferenceEvent(eventId, type, date); + return selectConferenceEvent(eventId, type, date, peerAddress); case EventLog::Type::CallStart: case EventLog::Type::CallEnd: - return selectConferenceCallEvent(eventId, type, date); + return selectConferenceCallEvent(eventId, type, date, peerAddress); case EventLog::Type::ConferenceChatMessage: - return selectConferenceChatMessageEvent(eventId, type, date); + return selectConferenceChatMessageEvent(eventId, type, date, peerAddress); case EventLog::Type::ConferenceParticipantAdded: case EventLog::Type::ConferenceParticipantRemoved: case EventLog::Type::ConferenceParticipantSetAdmin: case EventLog::Type::ConferenceParticipantUnsetAdmin: - return selectConferenceParticipantEvent(eventId, type, date); + return selectConferenceParticipantEvent(eventId, type, date, peerAddress); case EventLog::Type::ConferenceParticipantDeviceAdded: case EventLog::Type::ConferenceParticipantDeviceRemoved: - return selectConferenceParticipantDeviceEvent(eventId, type, date); + return selectConferenceParticipantDeviceEvent(eventId, type, date, peerAddress); case EventLog::Type::ConferenceSubjectChanged: - return selectConferenceSubjectEvent(eventId, type, date); + return selectConferenceSubjectEvent(eventId, type, date, peerAddress); } return nullptr; } - shared_ptr MainDbPrivate::selectConferenceEvent (long eventId, EventLog::Type type, time_t date) const { + shared_ptr MainDbPrivate::selectConferenceEvent ( + long eventId, + EventLog::Type type, + time_t date, + const string &peerAddress + ) const { // TODO. return nullptr; } - shared_ptr MainDbPrivate::selectConferenceCallEvent (long eventId, EventLog::Type type, time_t date) const { + shared_ptr MainDbPrivate::selectConferenceCallEvent ( + long eventId, + EventLog::Type type, + time_t date, + const string &peerAddress + ) const { // TODO. return nullptr; } - shared_ptr MainDbPrivate::selectConferenceChatMessageEvent (long eventId, EventLog::Type type, time_t date) const { + shared_ptr MainDbPrivate::selectConferenceChatMessageEvent ( + long eventId, + EventLog::Type type, + time_t date, + const string &peerAddress + ) const { // TODO. return nullptr; } - shared_ptr MainDbPrivate::selectConferenceParticipantEvent (long eventId, EventLog::Type type, time_t date) const { + shared_ptr MainDbPrivate::selectConferenceParticipantEvent ( + long eventId, + EventLog::Type type, + time_t date, + const string &peerAddress + ) const { // TODO. return nullptr; } - shared_ptr MainDbPrivate::selectConferenceParticipantDeviceEvent (long eventId, EventLog::Type type, time_t date) const { + shared_ptr MainDbPrivate::selectConferenceParticipantDeviceEvent ( + long eventId, + EventLog::Type type, + time_t date, + const string &peerAddress + ) const { // TODO. return nullptr; } - shared_ptr MainDbPrivate::selectConferenceSubjectEvent (long eventId, EventLog::Type type, time_t date) const { - // TODO. - return nullptr; + shared_ptr MainDbPrivate::selectConferenceSubjectEvent ( + long eventId, + EventLog::Type type, + time_t date, + const string &peerAddress + ) const { + soci::session *session = dbSession.getBackendSession(); + + unsigned int notifyId; + string subject; + + *session << "SELECT notify_id, subject FROM conference_subject_event WHERE event_id = :eventId", + soci::use(eventId), soci::into(notifyId), soci::into(subject); + + // TODO: Use cache. + return make_shared( + date, + Address(peerAddress), + notifyId, + subject + ); } // ----------------------------------------------------------------------------- @@ -859,7 +907,12 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} soci::rowset rows = (session->prepare << query, soci::use(peerAddress)); for (const auto &row : rows) { tm date = row.get(2); - events.push_back(d->selectEvent(row.get(0), static_cast(row.get(1)), mktime(&date))); + events.push_back(d->selectConferenceEvent( + row.get(0), + static_cast(row.get(1)), + mktime(&date), + peerAddress + )); } L_END_LOG_EXCEPTION From 6627f3305accde39637a846f544177020cd5035c Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 23 Oct 2017 10:32:51 +0200 Subject: [PATCH 0599/2215] feat(MainDb): fetch ConferenceEvent => OK --- src/db/main-db-p.h | 2 +- src/db/main-db.cpp | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 1d896dbf5..bf2dc5ba8 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -50,7 +50,7 @@ private: // Events API. // --------------------------------------------------------------------------- - std::shared_ptr selectEventFromPeerAddress ( + std::shared_ptr selectGenericConferenceEvent ( long eventId, EventLog::Type type, time_t date, diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 25cc4e00d..e5b5ad26a 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -205,7 +205,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} // ----------------------------------------------------------------------------- - shared_ptr MainDbPrivate::selectEventFromPeerAddress ( + shared_ptr MainDbPrivate::selectGenericConferenceEvent ( long eventId, EventLog::Type type, time_t date, @@ -249,8 +249,15 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} time_t date, const string &peerAddress ) const { - // TODO. - return nullptr; + // Useless here. + (void)eventId; + + // TODO: Use cache. + return make_shared( + type, + date, + Address(peerAddress) + ); } shared_ptr MainDbPrivate::selectConferenceCallEvent ( @@ -907,7 +914,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} soci::rowset rows = (session->prepare << query, soci::use(peerAddress)); for (const auto &row : rows) { tm date = row.get(2); - events.push_back(d->selectConferenceEvent( + events.push_back(d->selectGenericConferenceEvent( row.get(0), static_cast(row.get(1)), mktime(&date), From be18e569fc45a0017044ca657c01ee38e6ea4795 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 23 Oct 2017 10:53:14 +0200 Subject: [PATCH 0600/2215] feat(MainDb): fetch ConferenceParticipantEvent => OK --- src/db/main-db.cpp | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index e5b5ad26a..0991adb06 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -286,8 +286,24 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} time_t date, const string &peerAddress ) const { - // TODO. - return nullptr; + unsigned int notifyId; + string participantAddress; + + soci::session *session = dbSession.getBackendSession(); + *session << "SELECT notify_id, participant_address_id" + " FROM conference_notified_event, conference_participant_event" + " WHERE conference_participant_event.event_id = :eventId" + " AND conference_notified_event.event_id = conference_participant_event.event_id", + soci::into(notifyId), soci::into(participantAddress), soci::use(eventId); + + // TODO: Use cache. + return make_shared( + type, + date, + Address(peerAddress), + notifyId, + Address(participantAddress) + ); } shared_ptr MainDbPrivate::selectConferenceParticipantDeviceEvent ( @@ -306,13 +322,15 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} time_t date, const string &peerAddress ) const { - soci::session *session = dbSession.getBackendSession(); - unsigned int notifyId; string subject; - *session << "SELECT notify_id, subject FROM conference_subject_event WHERE event_id = :eventId", - soci::use(eventId), soci::into(notifyId), soci::into(subject); + soci::session *session = dbSession.getBackendSession(); + *session << "SELECT notify_id, subject" + " FROM conference_notified_event, conference_subject_event" + " WHERE conference_subject_event.event_id = :eventId" + " AND conference_notified_event.event_id = conference_subject_event.event_id", + soci::into(notifyId), soci::into(subject), soci::use(eventId); // TODO: Use cache. return make_shared( From fea02c354c98a03e044a81478abb29c8322f024f Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 23 Oct 2017 11:01:48 +0200 Subject: [PATCH 0601/2215] feat(MainDb): fetch ConferenceParticipantDeviceEvent => OK --- src/db/main-db.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 0991adb06..b90190adb 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -312,8 +312,27 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} time_t date, const string &peerAddress ) const { - // TODO. - return nullptr; + unsigned int notifyId; + string participantAddress; + string gruuAddress; + + soci::session *session = dbSession.getBackendSession(); + *session << "SELECT notify_id, participant_address_id, gruu_address_id" + " FROM conference_notified_event, conference_participant_event, conference_participant_device_event" + " WHERE conference_participant_device_event.event_id = :eventId" + " AND conference_participant_event.event_id = conference_participant_device_event.event_id" + " AND conference_notified_event.event_id = conference_participant_event.event_id", + soci::into(notifyId), soci::into(participantAddress), soci::into(gruuAddress), soci::use(eventId); + + // TODO: Use cache. + return make_shared( + type, + date, + Address(peerAddress), + notifyId, + Address(participantAddress), + Address(gruuAddress) + ); } shared_ptr MainDbPrivate::selectConferenceSubjectEvent ( From 303e9805e2b6e168e2b444bbe483593200df19ad Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 23 Oct 2017 11:16:53 +0200 Subject: [PATCH 0602/2215] fix(MainDb): fetch correctly addresses, not ids --- src/db/main-db.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index b90190adb..f5e4a5af4 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -290,10 +290,11 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} string participantAddress; soci::session *session = dbSession.getBackendSession(); - *session << "SELECT notify_id, participant_address_id" - " FROM conference_notified_event, conference_participant_event" + *session << "SELECT notify_id, participant_address.value" + " FROM conference_notified_event, conference_participant_event, sip_address as participant_address" " WHERE conference_participant_event.event_id = :eventId" " AND conference_notified_event.event_id = conference_participant_event.event_id", + " AND participant_address.id = participant_address_id" soci::into(notifyId), soci::into(participantAddress), soci::use(eventId); // TODO: Use cache. @@ -317,11 +318,14 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} string gruuAddress; soci::session *session = dbSession.getBackendSession(); - *session << "SELECT notify_id, participant_address_id, gruu_address_id" - " FROM conference_notified_event, conference_participant_event, conference_participant_device_event" + *session << "SELECT notify_id, participant_address.value, gruu_address.value" + " FROM conference_notified_event, conference_participant_event, conference_participant_device_event," + " sip_address AS participant_address, sip_address AS gruu_address" " WHERE conference_participant_device_event.event_id = :eventId" " AND conference_participant_event.event_id = conference_participant_device_event.event_id" - " AND conference_notified_event.event_id = conference_participant_event.event_id", + " AND conference_notified_event.event_id = conference_participant_event.event_id" + " AND participant_address.id = participant_address_id" + " AND gruu_address.id = gruu_address_id", soci::into(notifyId), soci::into(participantAddress), soci::into(gruuAddress), soci::use(eventId); // TODO: Use cache. From 0e62f94557fe765f1c5a73667635e01ea7f68387 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 23 Oct 2017 11:29:37 +0200 Subject: [PATCH 0603/2215] feat(MainDb): rename tester --- src/c-wrapper/c-wrapper.h | 3 ++ src/c-wrapper/internal/c-tools.h | 5 +- src/db/main-db.cpp | 4 +- tester/CMakeLists.txt | 2 +- tester/liblinphone_tester.h | 2 +- ...vents-db-tester.cpp => main-db-tester.cpp} | 52 +++++++++---------- tester/tester.c | 2 +- 7 files changed, 36 insertions(+), 34 deletions(-) rename tester/{events-db-tester.cpp => main-db-tester.cpp} (51%) diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index 08a8d26a4..c1b5698e9 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -24,6 +24,9 @@ #include "internal/c-tools.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + // ============================================================================= // Declare exported C types. // ============================================================================= diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index cefeaba33..bc04192ef 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -22,10 +22,9 @@ #include -#include "linphone/utils/utils.h" +#include -// TODO: From coreapi. Remove me later. -#include "private.h" +#include "linphone/utils/utils.h" #include "object/property-container.h" diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index f5e4a5af4..85f653d6a 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -293,8 +293,8 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "SELECT notify_id, participant_address.value" " FROM conference_notified_event, conference_participant_event, sip_address as participant_address" " WHERE conference_participant_event.event_id = :eventId" - " AND conference_notified_event.event_id = conference_participant_event.event_id", - " AND participant_address.id = participant_address_id" + " AND conference_notified_event.event_id = conference_participant_event.event_id" + " AND participant_address.id = participant_address_id", soci::into(notifyId), soci::into(participantAddress), soci::use(eventId); // TODO: Use cache. diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index e9263093e..fff62034b 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -199,8 +199,8 @@ set(SOURCE_FILES_CXX conference-event-tester.cpp conference-tester.cpp cpim-tester.cpp + main-db-tester.cpp multipart-tester.cpp - events-db-tester.cpp property-container-tester.cpp ) diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 94c0cc7f0..804288955 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -49,7 +49,7 @@ extern test_suite_t conference_test_suite; extern test_suite_t cpim_test_suite; extern test_suite_t dtmf_test_suite; extern test_suite_t event_test_suite; -extern test_suite_t events_db_test_suite; +extern test_suite_t main_db_test_suite; extern test_suite_t flexisip_test_suite; extern test_suite_t log_collection_test_suite; extern test_suite_t message_test_suite; diff --git a/tester/events-db-tester.cpp b/tester/main-db-tester.cpp similarity index 51% rename from tester/events-db-tester.cpp rename to tester/main-db-tester.cpp index 6a25f0e8f..1623b6e1b 100644 --- a/tester/events-db-tester.cpp +++ b/tester/main-db-tester.cpp @@ -1,5 +1,5 @@ /* - * events-db-tester.cpp + * main-db-tester.cpp * Copyright (C) 2017 Belledonne Communications SARL * * This program is free software: you can redistribute it and/or modify @@ -36,52 +36,52 @@ static const string getDatabasePath () { // ----------------------------------------------------------------------------- static void open_database () { - MainDb eventsDb; - BC_ASSERT_TRUE(eventsDb.connect(MainDb::Sqlite3, getDatabasePath())); + MainDb mainDb; + BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); } static void get_events_count () { - MainDb eventsDb; - BC_ASSERT_TRUE(eventsDb.connect(MainDb::Sqlite3, getDatabasePath())); - BC_ASSERT_EQUAL(eventsDb.getEventsCount(), 4976, int, "%d"); - BC_ASSERT_EQUAL(eventsDb.getEventsCount(MainDb::ConferenceCallFilter), 0, int, "%d"); - BC_ASSERT_EQUAL(eventsDb.getEventsCount(MainDb::ConferenceInfoFilter), 0, int, "%d"); - BC_ASSERT_EQUAL(eventsDb.getEventsCount(MainDb::ConferenceChatMessageFilter), 4976, int, "%d"); - BC_ASSERT_EQUAL(eventsDb.getEventsCount(MainDb::NoFilter), 4976, int, "%d"); + MainDb mainDb; + BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); + BC_ASSERT_EQUAL(mainDb.getEventsCount(), 4976, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceCallFilter), 0, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceInfoFilter), 0, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceChatMessageFilter), 4976, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::NoFilter), 4976, int, "%d"); } static void get_messages_count () { - MainDb eventsDb; - BC_ASSERT_TRUE(eventsDb.connect(MainDb::Sqlite3, getDatabasePath())); - BC_ASSERT_EQUAL(eventsDb.getMessagesCount(), 4976, int, "%d"); - BC_ASSERT_EQUAL(eventsDb.getMessagesCount("sip:test-7@sip.linphone.org"), 3, int, "%d"); + MainDb mainDb; + BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); + BC_ASSERT_EQUAL(mainDb.getMessagesCount(), 4976, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getMessagesCount("sip:test-7@sip.linphone.org"), 3, int, "%d"); } static void get_unread_messages_count () { - MainDb eventsDb; - BC_ASSERT_TRUE(eventsDb.connect(MainDb::Sqlite3, getDatabasePath())); - BC_ASSERT_EQUAL(eventsDb.getUnreadMessagesCount(), 2, int, "%d"); - BC_ASSERT_EQUAL(eventsDb.getUnreadMessagesCount("sip:test-7@sip.linphone.org"), 0, int, "%d"); + MainDb mainDb; + BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); + BC_ASSERT_EQUAL(mainDb.getUnreadMessagesCount(), 2, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getUnreadMessagesCount("sip:test-7@sip.linphone.org"), 0, int, "%d"); } static void get_history () { - MainDb eventsDb; - BC_ASSERT_TRUE(eventsDb.connect(MainDb::Sqlite3, getDatabasePath())); + MainDb mainDb; + BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); BC_ASSERT_EQUAL( - eventsDb.getHistory("sip:test-7@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceChatMessageFilter).size(), + mainDb.getHistory("sip:test-7@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceChatMessageFilter).size(), 3, int, "%d" ); BC_ASSERT_EQUAL( - eventsDb.getHistory("sip:test-7@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceCallFilter).size(), + mainDb.getHistory("sip:test-7@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceCallFilter).size(), 0, int, "%d" ); } -test_t events_db_tests[] = { +test_t main_db_tests[] = { TEST_NO_TAG("Open database", open_database), TEST_NO_TAG("Get events count", get_events_count), TEST_NO_TAG("Get messages count", get_messages_count), @@ -89,7 +89,7 @@ test_t events_db_tests[] = { TEST_NO_TAG("Get history", get_history) }; -test_suite_t events_db_test_suite = { - "EventsDb", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each, - sizeof(events_db_tests) / sizeof(events_db_tests[0]), events_db_tests +test_suite_t main_db_test_suite = { + "MainDb", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each, + sizeof(main_db_tests) / sizeof(main_db_tests[0]), main_db_tests }; diff --git a/tester/tester.c b/tester/tester.c index 64e5551c7..4cef7a7e6 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -574,7 +574,7 @@ void liblinphone_tester_add_suites() { bc_tester_add_suite(&cpim_test_suite); bc_tester_add_suite(&multipart_test_suite); bc_tester_add_suite(&clonable_object_test_suite); - bc_tester_add_suite(&events_db_test_suite); + bc_tester_add_suite(&main_db_test_suite); bc_tester_add_suite(&property_container_test_suite); #if defined(VIDEO_ENABLED) && defined(HAVE_GTK) bc_tester_add_suite(&video_test_suite); From a9418e190d2d5e8dd34980b6931be0ac9122b583 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 23 Oct 2017 13:26:48 +0200 Subject: [PATCH 0604/2215] feat(Tester): provide a linphone.db --- tester/db/linphone.db | Bin 18432 -> 4031488 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tester/db/linphone.db b/tester/db/linphone.db index 948bb10a2d5072d623865650d9b3c5a006eefe49..b8881d7efdf0f4c51321ac0bbce98bcf7723b072 100644 GIT binary patch literal 4031488 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

    -3F0yy8laey92)vOI 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�nY>h{v=}M<|ks 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̚~k*tOt56v3_q2cQUcE!ZDLuxr77D1u!J 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 From fde89d36e2e987353e27401de76cfbf388b71ea2 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 23 Oct 2017 15:54:25 +0200 Subject: [PATCH 0605/2215] feat(MainDb): supports MySql types and rowid from sqlite --- src/db/abstract/abstract-db.cpp | 31 +++++-- src/db/abstract/abstract-db.h | 5 +- src/db/main-db-p.h | 42 ++++----- src/db/main-db.cpp | 148 +++++++++++++++++--------------- src/event-log/event-log-p.h | 2 +- tester/db/linphone.db | Bin 4031488 -> 643072 bytes tester/main-db-tester.cpp | 6 +- 7 files changed, 132 insertions(+), 102 deletions(-) diff --git a/src/db/abstract/abstract-db.cpp b/src/db/abstract/abstract-db.cpp index 838a2e9a4..f04940132 100644 --- a/src/db/abstract/abstract-db.cpp +++ b/src/db/abstract/abstract-db.cpp @@ -77,21 +77,38 @@ void AbstractDb::init () { // ----------------------------------------------------------------------------- -string AbstractDb::primaryKeyAutoIncrementStr (const string &type) const { +string AbstractDb::primaryKeyStr (const string &type) const { L_D(); switch (d->backend) { case Mysql: - return type + "UNSIGNED PRIMARY KEY AUTO_INCREMENT"; + return type + " PRIMARY KEY AUTO_INCREMENT"; case Sqlite3: - return " INTEGER PRIMARY KEY AUTOINCREMENT"; + // See: ROWIDs and the INTEGER PRIMARY KEY + // https://www.sqlite.org/lang_createtable.html + return " INTEGER PRIMARY KEY ASC"; } + L_ASSERT(false); return ""; } -long AbstractDb::getLastInsertId () const { - long result = 0; +string AbstractDb::primaryKeyRefStr (const string &type) const { + L_D(); + + switch (d->backend) { + case Mysql: + return " " + type; + case Sqlite3: + return " INTEGER"; + } + + L_ASSERT(false); + return ""; +} + +long long AbstractDb::getLastInsertId () const { + long long id = 0; #ifdef SOCI_ENABLED L_D(); @@ -110,10 +127,10 @@ long AbstractDb::getLastInsertId () const { } soci::session *session = d->dbSession.getBackendSession(); - *session << sql, soci::into(result); + *session << sql, soci::into(id); #endif // ifdef SOCI_ENABLED - return result; + return id; } LINPHONE_END_NAMESPACE diff --git a/src/db/abstract/abstract-db.h b/src/db/abstract/abstract-db.h index f8250f37b..2386c384e 100644 --- a/src/db/abstract/abstract-db.h +++ b/src/db/abstract/abstract-db.h @@ -51,9 +51,10 @@ protected: virtual void init (); - std::string primaryKeyAutoIncrementStr (const std::string &type = "INT") const; + std::string primaryKeyStr (const std::string &type = "INT") const; + std::string primaryKeyRefStr (const std::string &type = "INT") const; - long getLastInsertId () const; + long long getLastInsertId () const; private: L_DECLARE_PRIVATE(AbstractDb); diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index bf2dc5ba8..b026c59f8 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -39,74 +39,74 @@ private: // Low level API. // --------------------------------------------------------------------------- - long insertSipAddress (const std::string &sipAddress); - void insertContent (long messageEventId, const Content &content); - long insertContentType (const std::string &contentType); - long insertChatRoom (long sipAddressId, int capabilities, const tm &date); - void insertChatRoomParticipant (long chatRoomId, long sipAddressId, bool isAdmin); - void insertChatMessageParticipant (long messageEventId, long sipAddressId, int state); + long long insertSipAddress (const std::string &sipAddress); + void insertContent (long long messageEventId, const Content &content); + long long insertContentType (const std::string &contentType); + long long insertChatRoom (long long sipAddressId, int capabilities, const tm &date); + void insertChatRoomParticipant (long long chatRoomId, long long sipAddressId, bool isAdmin); + void insertChatMessageParticipant (long long messageEventId, long long sipAddressId, int state); // --------------------------------------------------------------------------- // Events API. // --------------------------------------------------------------------------- std::shared_ptr selectGenericConferenceEvent ( - long eventId, + long long eventId, EventLog::Type type, time_t date, const std::string &peerAddress ) const; std::shared_ptr selectConferenceEvent ( - long eventId, + long long eventId, EventLog::Type type, time_t date, const std::string &peerAddress ) const; std::shared_ptr selectConferenceCallEvent ( - long eventId, + long long eventId, EventLog::Type type, time_t date, const std::string &peerAddress ) const; std::shared_ptr selectConferenceChatMessageEvent ( - long eventId, + long long eventId, EventLog::Type type, time_t date, const std::string &peerAddress ) const; std::shared_ptr selectConferenceParticipantEvent ( - long eventId, + long long eventId, EventLog::Type type, time_t date, const std::string &peerAddress ) const; std::shared_ptr selectConferenceParticipantDeviceEvent ( - long eventId, + long long eventId, EventLog::Type type, time_t date, const std::string &peerAddress ) const; std::shared_ptr selectConferenceSubjectEvent ( - long eventId, + long long eventId, EventLog::Type type, time_t date, const std::string &peerAddress ) const; - long insertEvent (const EventLog &eventLog); - long insertConferenceEvent (const EventLog &eventLog, long *chatRoomId = nullptr); - long insertConferenceCallEvent (const EventLog &eventLog); - long insertConferenceChatMessageEvent (const EventLog &eventLog); - long insertConferenceNotifiedEvent (const EventLog &eventLog); - long insertConferenceParticipantEvent (const EventLog &eventLog); - long insertConferenceParticipantDeviceEvent (const EventLog &eventLog); - long insertConferenceSubjectEvent (const EventLog &eventLog); + long long insertEvent (const EventLog &eventLog); + long long insertConferenceEvent (const EventLog &eventLog, long long *chatRoomId = nullptr); + long long insertConferenceCallEvent (const EventLog &eventLog); + long long insertConferenceChatMessageEvent (const EventLog &eventLog); + long long insertConferenceNotifiedEvent (const EventLog &eventLog); + long long insertConferenceParticipantEvent (const EventLog &eventLog); + long long insertConferenceParticipantDeviceEvent (const EventLog &eventLog); + long long insertConferenceSubjectEvent (const EventLog &eventLog); L_DECLARE_PUBLIC(MainDb); }; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 85f653d6a..07df094ae 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -115,11 +115,11 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} // ----------------------------------------------------------------------------- - long MainDbPrivate::insertSipAddress (const string &sipAddress) { + long long MainDbPrivate::insertSipAddress (const string &sipAddress) { L_Q(); soci::session *session = dbSession.getBackendSession(); - long id; + long long id; *session << "SELECT id FROM sip_address WHERE value = :sipAddress", soci::use(sipAddress), soci::into(id); if (session->got_data()) return id; @@ -128,28 +128,28 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return q->getLastInsertId(); } - void MainDbPrivate::insertContent (long eventId, const Content &content) { + void MainDbPrivate::insertContent (long long eventId, const Content &content) { L_Q(); soci::session *session = dbSession.getBackendSession(); - long contentTypeId = insertContentType(content.getContentType().asString()); + long long contentTypeId = insertContentType(content.getContentType().asString()); *session << "INSERT INTO chat_message_content (event_id, content_type_id, body) VALUES" " (:eventId, :contentTypeId, :body)", soci::use(eventId), soci::use(contentTypeId), soci::use(content.getBodyAsString()); - long messageContentId = q->getLastInsertId(); + long long messageContentId = q->getLastInsertId(); for (const auto &appData : content.getAppDataMap()) *session << "INSERT INTO chat_message_content_app_data (chat_message_content_id, key, data) VALUES" " (:messageContentId, :key, :data)", soci::use(messageContentId), soci::use(appData.first), soci::use(appData.second); } - long MainDbPrivate::insertContentType (const string &contentType) { + long long MainDbPrivate::insertContentType (const string &contentType) { L_Q(); soci::session *session = dbSession.getBackendSession(); - long id; + long long id; *session << "SELECT id FROM content_type WHERE value = :contentType", soci::use(contentType), soci::into(id); if (session->got_data()) return id; @@ -158,10 +158,10 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return q->getLastInsertId(); } - long MainDbPrivate::insertChatRoom (long sipAddressId, int capabilities, const tm &date) { + long long MainDbPrivate::insertChatRoom (long long sipAddressId, int capabilities, const tm &date) { soci::session *session = dbSession.getBackendSession(); - long id; + long long id; *session << "SELECT peer_sip_address_id FROM chat_room WHERE peer_sip_address_id = :sipAddressId", soci::use(sipAddressId), soci::into(id); if (!session->got_data()) @@ -175,7 +175,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return sipAddressId; } - void MainDbPrivate::insertChatRoomParticipant (long chatRoomId, long sipAddressId, bool isAdmin) { + void MainDbPrivate::insertChatRoomParticipant (long long chatRoomId, long long sipAddressId, bool isAdmin) { soci::session *session = dbSession.getBackendSession(); soci::statement statement = ( session->prepare << "UPDATE chat_room_participant SET is_admin = :isAdmin" @@ -189,7 +189,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} soci::use(chatRoomId), soci::use(sipAddressId), soci::use(static_cast(isAdmin)); } - void MainDbPrivate::insertChatMessageParticipant (long eventId, long sipAddressId, int state) { + void MainDbPrivate::insertChatMessageParticipant (long long eventId, long long sipAddressId, int state) { soci::session *session = dbSession.getBackendSession(); soci::statement statement = ( session->prepare << "UPDATE chat_message_participant SET state = :state" @@ -206,7 +206,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} // ----------------------------------------------------------------------------- shared_ptr MainDbPrivate::selectGenericConferenceEvent ( - long eventId, + long long eventId, EventLog::Type type, time_t date, const string &peerAddress @@ -244,7 +244,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} } shared_ptr MainDbPrivate::selectConferenceEvent ( - long eventId, + long long eventId, EventLog::Type type, time_t date, const string &peerAddress @@ -261,7 +261,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} } shared_ptr MainDbPrivate::selectConferenceCallEvent ( - long eventId, + long long eventId, EventLog::Type type, time_t date, const string &peerAddress @@ -271,7 +271,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} } shared_ptr MainDbPrivate::selectConferenceChatMessageEvent ( - long eventId, + long long eventId, EventLog::Type type, time_t date, const string &peerAddress @@ -281,7 +281,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} } shared_ptr MainDbPrivate::selectConferenceParticipantEvent ( - long eventId, + long long eventId, EventLog::Type type, time_t date, const string &peerAddress @@ -308,7 +308,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} } shared_ptr MainDbPrivate::selectConferenceParticipantDeviceEvent ( - long eventId, + long long eventId, EventLog::Type type, time_t date, const string &peerAddress @@ -340,7 +340,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} } shared_ptr MainDbPrivate::selectConferenceSubjectEvent ( - long eventId, + long long eventId, EventLog::Type type, time_t date, const string &peerAddress @@ -366,7 +366,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} // ----------------------------------------------------------------------------- - long MainDbPrivate::insertEvent (const EventLog &eventLog) { + long long MainDbPrivate::insertEvent (const EventLog &eventLog) { L_Q(); soci::session *session = dbSession.getBackendSession(); @@ -375,9 +375,9 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return q->getLastInsertId(); } - long MainDbPrivate::insertConferenceEvent (const EventLog &eventLog, long *chatRoomId) { - long eventId = insertEvent(eventLog); - long curChatRoomId = insertSipAddress( + long long MainDbPrivate::insertConferenceEvent (const EventLog &eventLog, long long *chatRoomId) { + long long eventId = insertEvent(eventLog); + long long curChatRoomId = insertSipAddress( static_cast(eventLog).getConferenceAddress().asString() ); @@ -391,12 +391,12 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return eventId; } - long MainDbPrivate::insertConferenceCallEvent (const EventLog &eventLog) { + long long MainDbPrivate::insertConferenceCallEvent (const EventLog &eventLog) { // TODO. return 0; } - long MainDbPrivate::insertConferenceChatMessageEvent (const EventLog &eventLog) { + long long MainDbPrivate::insertConferenceChatMessageEvent (const EventLog &eventLog) { shared_ptr chatMessage = static_cast(eventLog).getChatMessage(); shared_ptr chatRoom = chatMessage->getChatRoom(); if (!chatRoom) { @@ -406,10 +406,10 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} tm eventTime = Utils::getLongAsTm(static_cast(eventLog.getTime())); - long localSipAddressId = insertSipAddress(chatMessage->getLocalAddress().asString()); - long remoteSipAddressId = insertSipAddress(chatMessage->getRemoteAddress().asString()); + long long localSipAddressId = insertSipAddress(chatMessage->getLocalAddress().asString()); + long long remoteSipAddressId = insertSipAddress(chatMessage->getRemoteAddress().asString()); insertChatRoom(remoteSipAddressId, chatRoom->getCapabilities(), eventTime); - long eventId = insertConferenceEvent(eventLog); + long long eventId = insertConferenceEvent(eventLog); soci::session *session = dbSession.getBackendSession(); @@ -429,9 +429,9 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return eventId; } - long MainDbPrivate::insertConferenceNotifiedEvent (const EventLog &eventLog) { - long chatRoomId; - long eventId = insertConferenceEvent(eventLog, &chatRoomId); + long long MainDbPrivate::insertConferenceNotifiedEvent (const EventLog &eventLog) { + long long chatRoomId; + long long eventId = insertConferenceEvent(eventLog, &chatRoomId); unsigned int lastNotifyId = static_cast(eventLog).getNotifyId(); soci::session *session = dbSession.getBackendSession(); @@ -443,9 +443,9 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return eventId; } - long MainDbPrivate::insertConferenceParticipantEvent (const EventLog &eventLog) { - long eventId = insertConferenceNotifiedEvent(eventLog); - long participantAddressId = insertSipAddress( + long long MainDbPrivate::insertConferenceParticipantEvent (const EventLog &eventLog) { + long long eventId = insertConferenceNotifiedEvent(eventLog); + long long participantAddressId = insertSipAddress( static_cast(eventLog).getParticipantAddress().asString() ); @@ -456,9 +456,9 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return eventId; } - long MainDbPrivate::insertConferenceParticipantDeviceEvent (const EventLog &eventLog) { - long eventId = insertConferenceParticipantEvent(eventLog); - long gruuAddressId = insertSipAddress( + long long MainDbPrivate::insertConferenceParticipantDeviceEvent (const EventLog &eventLog) { + long long eventId = insertConferenceParticipantEvent(eventLog); + long long gruuAddressId = insertSipAddress( static_cast(eventLog).getGruuAddress().asString() ); @@ -469,8 +469,8 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return eventId; } - long MainDbPrivate::insertConferenceSubjectEvent (const EventLog &eventLog) { - long eventId = insertConferenceNotifiedEvent(eventLog); + long long MainDbPrivate::insertConferenceSubjectEvent (const EventLog &eventLog) { + long long eventId = insertConferenceNotifiedEvent(eventLog); soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_subject_event (event_id, subject)" @@ -489,19 +489,19 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS sip_address (" - " id" + primaryKeyAutoIncrementStr() + "," + " id" + primaryKeyStr("UNSIGNED BIGINT") + "," " value VARCHAR(255) UNIQUE NOT NULL" ")"; *session << "CREATE TABLE IF NOT EXISTS content_type (" - " id" + primaryKeyAutoIncrementStr() + "," + " id" + primaryKeyStr("UNSIGNED SMALLINT") + "," " value VARCHAR(255) UNIQUE NOT NULL" ")"; *session << "CREATE TABLE IF NOT EXISTS event (" - " id" + primaryKeyAutoIncrementStr() + "," + " id" + primaryKeyStr("UNSIGNED BIGINT") + "," " type TINYINT UNSIGNED NOT NULL," " date DATE NOT NULL" ")"; @@ -509,7 +509,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS chat_room (" // Server (for conference) or user sip address. - " peer_sip_address_id INT UNSIGNED PRIMARY KEY," + " peer_sip_address_id" + primaryKeyStr("UNSIGNED BIGINT") + "," // Dialog creation date. " creation_date DATE NOT NULL," @@ -532,8 +532,9 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS chat_room_participant (" - " chat_room_id INT UNSIGNED NOT NULL," - " sip_address_id INT UNSIGNED NOT NULL," + " chat_room_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," + " sip_address_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," + " is_admin BOOLEAN NOT NULL," " PRIMARY KEY (chat_room_id, sip_address_id)," @@ -547,8 +548,9 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS conference_event (" - " event_id INT UNSIGNED PRIMARY KEY," - " chat_room_id INT UNSIGNED NOT NULL," + " event_id" + primaryKeyStr("UNSIGNED BIGINT") + "," + + " chat_room_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," " FOREIGN KEY (event_id)" " REFERENCES event(id)" @@ -560,7 +562,8 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS conference_notified_event (" - " event_id INT UNSIGNED PRIMARY KEY," + " event_id" + primaryKeyStr("UNSIGNED BIGINT") + "," + " notify_id INT UNSIGNED NOT NULL," " FOREIGN KEY (event_id)" @@ -570,8 +573,9 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS conference_participant_event (" - " event_id INT UNSIGNED PRIMARY KEY," - " participant_address_id INT UNSIGNED NOT NULL," + " event_id" + primaryKeyStr("UNSIGNED BIGINT") + "," + + " participant_address_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," " FOREIGN KEY (event_id)" " REFERENCES conference_notified_event(event_id)" @@ -583,8 +587,9 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS conference_participant_device_event (" - " event_id INT UNSIGNED PRIMARY KEY," - " gruu_address_id INT UNSIGNED NOT NULL," + " event_id" + primaryKeyStr("UNSIGNED BIGINT") + "," + + " gruu_address_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," " FOREIGN KEY (event_id)" " REFERENCES conference_participant_event(event_id)" @@ -596,7 +601,8 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS conference_subject_event (" - " event_id INT UNSIGNED PRIMARY KEY," + " event_id" + primaryKeyStr("BIGINT") + "," + " subject VARCHAR(255)," " FOREIGN KEY (event_id)" @@ -606,9 +612,10 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS conference_chat_message_event (" - " event_id INT UNSIGNED PRIMARY KEY," - " local_sip_address_id INT UNSIGNED NOT NULL," - " remote_sip_address_id INT UNSIGNED NOT NULL," + " event_id" + primaryKeyStr("UNSIGNED BIGINT") + "," + + " local_sip_address_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," + " remote_sip_address_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," // See: https://tools.ietf.org/html/rfc5438#section-6.3 " imdn_message_id VARCHAR(255) NOT NULL," @@ -630,8 +637,8 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS chat_message_participant (" - " event_id INT UNSIGNED NOT NULL," - " sip_address_id INT UNSIGNED NOT NULL," + " event_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," + " sip_address_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," " state TINYINT UNSIGNED NOT NULL," " PRIMARY KEY (event_id, sip_address_id)," @@ -645,9 +652,10 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS chat_message_content (" - " id" + primaryKeyAutoIncrementStr() + "," - " event_id INT UNSIGNED NOT NULL," - " content_type_id INT UNSIGNED NOT NULL," + " id" + primaryKeyStr("UNSIGNED BIGINT") + "," + + " event_id " + primaryKeyRefStr("UNSIGNED BIGINT") + "," + " content_type_id" + primaryKeyRefStr("UNSIGNED SMALLINT") + "," " body TEXT NOT NULL," " FOREIGN KEY (event_id)" @@ -660,7 +668,8 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS chat_message_content_app_data (" - " chat_message_content_id INT UNSIGNED NOT NULL," + " chat_message_content_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," + " key VARCHAR(255)," " data BLOB," @@ -672,7 +681,8 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << "CREATE TABLE IF NOT EXISTS conference_message_crypto_data (" - " event_id INT UNSIGNED NOT NULL," + " event_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," + " key VARCHAR(255)," " data BLOB," @@ -772,7 +782,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return false; } - long &storageId = const_cast(eventLog).getPrivate()->storageId; + long long &storageId = const_cast(eventLog).getPrivate()->storageId; if (storageId < 0) return false; @@ -956,7 +966,9 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} for (const auto &row : rows) { tm date = row.get(2); events.push_back(d->selectGenericConferenceEvent( - row.get(0), + // See: http://soci.sourceforge.net/doc/master/backends/ + // `row id` is not supported by soci on Sqlite3. It's necessary to cast id to int... + getBackend() == Sqlite3 ? static_cast(row.get(0)) : row.get(0), static_cast(row.get(1)), mktime(&date), peerAddress @@ -1144,10 +1156,10 @@ shared_ptr MainDb::findChatRoom (const string &peerAddress) const { *session << "INSERT INTO event (type, date) VALUES (:type, :date)", soci::use(static_cast(EventLog::Type::ConferenceChatMessage)), soci::use(date); - long eventId = getLastInsertId(); - long localSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_LOCAL_ADDRESS)); - long remoteSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_REMOTE_ADDRESS)); - long chatRoomId = d->insertChatRoom(remoteSipAddressId, static_cast(ChatRoom::Capabilities::Basic), date); + long long eventId = getLastInsertId(); + long long localSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_LOCAL_ADDRESS)); + long long remoteSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_REMOTE_ADDRESS)); + long long chatRoomId = d->insertChatRoom(remoteSipAddressId, static_cast(ChatRoom::Capabilities::Basic), date); *session << "INSERT INTO conference_event (event_id, chat_room_id)" " VALUES (:eventId, :chatRoomId)", soci::use(eventId), soci::use(chatRoomId); diff --git a/src/event-log/event-log-p.h b/src/event-log/event-log-p.h index ccfe7a721..06701bac7 100644 --- a/src/event-log/event-log-p.h +++ b/src/event-log/event-log-p.h @@ -30,7 +30,7 @@ LINPHONE_BEGIN_NAMESPACE class EventLogPrivate : public BaseObjectPrivate { public: - long storageId = -1; + long long storageId = -1; private: EventLog::Type type = EventLog::Type::None; diff --git a/tester/db/linphone.db b/tester/db/linphone.db index b8881d7efdf0f4c51321ac0bbce98bcf7723b072..6fb3f9ab68f4dc06f7b302db6aea93cbed3c0fd0 100644 GIT binary patch delta 172326 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
      0l&l0h|+`8+XTo z&^QG*umasU73jvPAnThjf~+9)O)fg9yn@g-sopBDAoNW^*VPK#?Uf&Lo#Sy;Rw(1d z<1f%5wIb)7>XE-9bWZR}NPN8_=bRLSb7EIjt0|7lI;Vimst}u5fz7DEt__&-U%`RX zD+H%iU{fowDHYh{3T#pZ2LGgeP#7qUg$@e+Z^7HcLTN#GD2>5HX$&q(W3W*ggN@Qy z=%d1SfREB*Fj4_a^4r5oX+d}?jloQ5Y8fdI zT3PC^fYZ_#td_>$wKN8^r7^fIjX}^f21U~tBrV61DrW3H4KA_g=&bV zhhm``a)T;Ar-tgOL#T#$d&RP9s6JYLRt*D|Rm0$s3#(zEf3VW|EQhMCgU_9xRl|UV zYN*5*v78zzmQzE;a%za4(ELyhaa=7tWXY+adcRN&mHw#%LpcmtP7PHor-q7U)iC&I zSv3q;P7T#tWYsYE*jY7Homu(iY8XC$3gwW0!~9SULzY!TyoHw!HDni6i~RiI+22fk zvaA>epCv1X!MkV0Fkm?`#Q0Y~KU724Q4b9Ab7E+MWyLV~*r6C=PxTBh6vL2(Vi>Ye z48fXU&rl3Q7K$NQEQxOssv&4C%gcutvKK_ZOg^-*ocQ^n6kyd znn_pDT@RLJi_O z653Qns6aV_`ojeMvPGyqT$L3;?O~Es47De>A1V)%mWZJ4@P3M*>f|Eb^$6-sZZ}jL zCUtQPY7HNw2r5mEpw57(`L}2$7NO4YL5iTtI9@mM0rG= zz|bQRjT9!KKm37ky23d+xlt!K=;V5xT&I)SI+>-DnM{I2%7w6g>P;0%dWCR)<;*LD z@neDxutNC0Tm-gHk)T_s5UwvrVETBs6UZxs=i>-|)tA z_`UM|{KC-gp??e|s1SCKkHX!pa9lZ2Cm*YmF*+HolTkXkQYRxpxc^C=?g~9LLMOv@ zGE66z>tv`-hUjFlPA}ORci|PnHHNq2i2B^H zb~yrPmm~0XIg+(?>X@vpYk~S-2w#`m54J8x;OcS&rY=X|>2d^?E=NK+3hH%XC`U{} zIbssZ5!e61tRAUP7s?Uu7s?TntQ@J`LOJ3{cl{$||_6v@hwBB31dZdo}}k*pjkl9eMxvT~$IC`Z9PzOX}u`VT$g>!^NlU5*NMIV#lU zs4y!>>X=ZD_}p1JQjt)OI1LBjugqtks?_+QY0%!ig@Ak4}MprN5LIdg+e*vNLG$iB$OkL z=yFsT$`MC&IVue0h$FfjB@1;uD$t8#fi6b{x*Qega#WzpQ9&q2!5yq1lp`j(92I2c zD2Z=WkkunavT~$IC`ZBPF38G}ie%+Tk*pjk63P)Dla(VC3FU|*EJv#ULxn;;ViL*` zKLLRp@vowujbznGk*pdil2s!`LN($q9;y+OtQx7^pho5SN5GUEmH+$&p&Ic)p&Bt6 z&btLqvI{~rViKy6s|MZ_glfbjR3j##8Zk+Ra>Q&<`MK2@vSOr2C`PkaF9>j`URn51yJHP#wz zooDs1PQ+A$T2|Ej8z~45n(vvfna`S!nHe)>E--JzWP>ZsOU!eSgrJ?-*sN|k@^|^Q zJRtYTm*ghQHYk*fk%nNloFIoM<%P00mLzB;>&wbg(l3~B@FDG@7ic4vEzG04X)aw$ z<7f!=r!z3+pgGm17!ncuAP$N5#p@!se8C(sMT`=cioRI7uzh*=fL9z=X-5s{Dh{hO zlb}im`lmu+o#s$jrcITBWBCSjFk5>{y@{j&O}&JfmV4rL9d ziiCBVBVnCp64q%ZVV!0YR%s^XRXVr|VU-Rd$>Ok1^L}BSW|FPb>LaK+9o(H2QI$GN zRISbuRjsomtk!(Cuv#+-t2O3dsnd1V4?0CBopf@tPEOLvi8|@1lMXs*uakBGQTnGo zLR&r5MkiT=sdj6nN3sS}MNZHoEp*acC(U$ne765ZouR27YNC_II%%YnhB|4WllnTT zr<1xmN!HO>ZJpH8Nll#`r;{2wsjic1I;pCYDp>;kE3TYnAeD5I&`De;F`Z-$rn-#2 z9`SVI>cnA!_Ln-y)Y*ESa=lKj)5&a| z%+kqBoy^e5wK`GrKeF{TJxwQ5buvXKlXWslClhsYjZU)uQhn8{bCIN%zADGO^mv_& z)5%z!jM2$xos81Sl{y)zlPf|Jtv`-hUjFlPA=1lE=K7bumioVwBd!D6NZ8x;+0TziVhPndoAa*2O5Ti&0t^ zqqHtYXHs9E=FlxjMBOorFAh%>tdAF#VDtd8{pr1__qqHtYX_bE>_pZ7a zrFAh%>tdAF#VDF@pZ2b7};li&0t^qqHtYX ztwp&0QSg<`}c6eA|O7!`$L#F0>p znCN0u6p9hnpHN@CT#W(}iV+{Ai&0T1MjQ#nh>0#nMWGmRL>HqXU5ttXF@pZ^et{a5 zlTeKKSx_iOuA?4dX2nQ7*U5^JB3Us~Bore)K~{`ZBorf#l;@vdc3%0rp4E~D@h5y|Cf#mvc(3uQ{Su>yofqb0k}>mH#LS>oteMdd)I zuwHXSH<=~bYOQw5R%=C2t#kgPBwMdlC|j=;=~I4VP~>c#oTZcAI_ag8Gj-BaC&@E( z)ZGGiI_RXmPTJ`t z^qA~FO4{h5);ejWla@L;K_@MA(p)FabaK2-nu28gM@bVs)L18tbka~K4RlgpC-rnv zS0{CJQah=$S~{tzljC$!Lnpe)EUBhPs_LYQPAca}(krQyV_r!@C%VZjiRqE3PJEqs zI&pR4=)?|5;6F+%J!I-c>V$M6bYkcvqLGY#firXT$c>7Ww|_G?=%MR%qMOXjY&|kd zCo^?2LnqhjWV%kK>HV*nsd{LNPA2PQl1@UC8Qk_V*XWT6I=NaWS7{`f8LzR7E=Cz$ zj54|yWppvh=wg)7#VDhTQAQV|OjeAP{$z&hA3+zRj4nnQU5qli7-e)Z%IIR0(ZwjE zi&2KfDAb<}s}Z+M%e~XMi--u zE=Cz$j54|yWppvh=wg)7#VDhTQ6{OYQAQV|j4no*?)rz*#VDhTQAQV|j4nnQU5qk0 zF@pYNa%u#ki%~`wql_*_8C{Grx)^12G0Ny-l+nc~6N(Y*PbO3&u12~TWppvh=wg)7 z#VDhTQAQV|j4nnQU5qkHjI#QZQEF7){>|uOl+nc~ql-~S7o$uA{RFxgWppvh=wg(q zQ{nblTR(#?Mj2gta-_i&3#IM#Z`q73*SDJYCnH;%VB?U#yE!u`Wi%x)>Gf zVpOb)QL!#Y#kv?3>td8F*43z37o%cbjEZ$JD%QoQSQn#WU5tu#F)G%@s5mP|!SlbY z8sX%PD%Fcusb0KF_2N~k7q8N6@j`(r)k{~YUb;&4(p4IiuJYSKsb0KF_2N~k z7q3#SczLC|*D2M#PAPjGb~mNE)hX4jPU%4Xc2KH&ol@QFln&6UNa^`H>93RXbka{J z=jx=dMv|rHXsoo4PR`cJSvu*hlU_PGQzt!ja)wTNloNG3DD7U(6ggcd-E?xAPO@Hy zP-?sCkuFSvUd~e8>Xe37ha+rt)N~B>uA$dqqI;dv(CctS_d2Dz*C}mZ{t?h&UD{43 zZOcE8inP%qtwTE+jKV5yrH5MT!XKelmcWjdhF*uSLg;mvWWA3161vwZ&3YXb z(Y;P-=ymu6q1E9ZuTuHDsvkVTgzac)To1)`64i;X6Hh0uP8^-sId)RU*fIA ztC)WHWMXZiG?AaUA43f1CT1gx@z}($#Knnzi8B*j6CDyQ5)ClaFoyMze~*73|2+P2 z{N4D@_>1w)SQU8{);wB@q{g>mW#lRGvGL2}1LNl)vGK|AR`EvhicUVus?CSSI=WSZ`!G?htE^Y(`aMZuIZyPnf2702z&T zL|=$L6j3mreb=3AOrFt?*nfah9_?F)_NJ_ zJ6h!3f<=_C@kV-=di}gJutriVuc24n^N{uENB48Aqx=>!AwT1;cOP=|+I-0R)R z$bB@}J>TtxY{+fhCT>kPhN+CdI7giW&O69}w8eSCS%sX)_d9nub1?vH~Sm=Gy8per~QKcq`d~S8dLT{`(}Fv@*|J1FSh$)apjZj6YTn! z+2~+-t;6a`4_bFy^Q_s{L}W%9gyD-lty8SlRwJv1^`R0A*?O1Ag3YJnDVh%8Sn_V%Ev8h?hjGKf!NngoNkU05uxm9kI zk6l6>}qrpAugrK1%FKypnh}u_3V%<@mnD?TH&O zRCY{aNMb;uH_C9kMAJmAL_9(9U*lh4xa_-_PP;X}G5$!r5J|Td#FO#q@$pEzH89=> zQ))ZLo5$l*WRbzd)^N3d9Tb{ z?Inx6CCJWolXorF^BV45gq+={dnbA=yn0?0&qmhn@7zP~2ktKSMR$|C*3G!f+(lUT zdloWxk3^=fe(o8VcH7Er=vH?<=Wpjn=W}Pj^Oo~6@^!7p)Z08{@V?Et-kI!-b_P4= zJH4DPSOL5Vrr*XKfi&JnllB43zo+V0{+abYR{DCudeT~hoZcyGp>;E+;$Dr_zAm=;Z4d95=`klp)kbDlZdoQNT}gUs{Hp5`fLvNdvg)i8ZCB7c%!$d54Y_7yDu zwLz{#Ua$M)?eYdJ4?ac?kpnRFwySI>o61@;E(zJbzrqsX@6zkY?zIu~a|`JKT0lwU z_Zp9!-vg-+b)$|Lf?Jm=lO=u^-(oeez2XgI{(ee4iuJ&jVw&#UNJOe4o7!_HwJs~I zi^O1MrMrZB9T&V-6TK+u;f~uyPKqRsCB931o;Z+rKk+6C>ej?liN`SKyC|_Nac|;| z#Lc+rPDzYUT#>jeaRJiDpONT-+wKX8MkutE6K=vl8u{;V<2?|6KmKO?6%^g4kT33` z_zD!>h4EXEGj2+J9G0cOBz|7JSNv2I;1l8vaq~^a<0dAC{}B5kb|Cg1O7V8we;F1_-<59pb_Rhua_!O^=*Tk#kB|Ovp9Yy@G`yp<~uei^-PaqXtk(+YwLLr~+ zPQooYImErdJ=^W(o`~t?4N%T~WU2qf`O5hedFkG8UPPw)$57Jqk(%xfERlGvbG37Y zb1Bl(or$vE4pYtRIF*s2?oay%B(49*ej9~-E7rVUgT(dA?7Q*A_1%pnVQ* z&L`Wg>_+x+cFZR07z+Hsr1b&r&o5ceSR1T|tpe)->rRyUnONcOO6xLAK<{mxYIU%h zBY$00%f%q`pUf}K1IS^w!+gPf%3O&|@0cNImlPAg(WCK}U`qIGQ^RMVr zWVd?*^V6TE$LJx-r^R#!YQVL0HSX7!BFEjC)P>s7@l*$Oz!raEAo}OxBk^`w<#DnY zvl(!27GePzT^QX#MrTIz$vB14?PPRfbSoJrGnz-nNsQ)_aU!Fe$>_-FCNerOnnOl= zMmLbrj?r~wv}H6qNk$unGstMoXgV3K7)>RkC8H^1oWN)@87&x1B%?W_31l>5bTt{r zGa64uQ%2*+Xu@bT8I2iTNk$`ul0pn8qakk`Mn(fhmy=PS(GW7~F&a!pT}GFYQHRmR zWYlIfkc?W4E+nHSqXA?b$EZIUH5m0HqdKE=$f)KfgUjECjHP<#vM!m?W z#OO>i5{%9uBhIKh88Jqk$%r!QM264kWHLNPCz0VYI*|;AQF|z_&9EIA7NfRgn2g$x zAsMwIgBZ0WLojMihQX*Q84*T}DDpR>h7|dWQC*7s$*2xR{$Ny_BEJVHDQZ#VH{Mv2 zBF7ljpvbR`s#D|_M%5_tGoz{$`H4{_iu}k3OFjO;2y-pIXB4H#cZ@uWe9OqC$Ty4} zihS+Lq$>RuMZV&Vk|IYL85H@FQG_C21jzV{BA+w*lOjhL{Xvn#jDDlYAx6h2a*)w4 z6#0zN&lLHT(T^1QgwgjDNgiPM9YsE7^esg`V)Qjd_A@$4kq;StNs)bwzM#kljE+!b zFQda0d7sfCioD0@Q;NLH=m16DVe~OY-e#2CPmw(g_fh06Mtdo;o6&m|d6Ut*6xqe- z9g4ic=xvJZWb_tAb}-sak=GgRqR4BEc2eY3Mms3-3ZvI4@-k4;5XNg1d5Jf^Op)!3 zwo~LqMlVui8>6ihd4bUuiagI~Gex#CdYU3z7;U1+bBvy($g_-|pvW_f)>C9NqsJ)n zbdupZifm%EmLg9vT0@a18Lg&B8KZ|OvXRkBiaf!ngd&eK%1~qjqhgAzXOyPMV~mO@ zvW`(9Mb=_cJjCc;ij*?C zn<6EQ7EvU_=q`#BGg?5Av_dHVcTl8=H{M2(LPobzq=3;a6j{M&E=BSg-As`@MmJGp zIinjX@*tz@D6)*vY>F&pG=m~3M%Pkg38QHgd4TVK2HMm2^TsJ=WHF;j6uFPlM2g(Y zXaYs8GowBfxyix#3jYbRC0^G@C&?n#G_E&1BG;W-vH`u4T~7oX(&rO=Hl6rZQ+mQyA2z$qeez zBnEY9B7<6VjidC(Fsjo8-c*&YW)P>V7{q8i1E0n*aA_<9o5nDZG@5~+Q2~hjO;+p<;BRZH6#Q*PiQw-E6c7G3l`%W1-na=x zgAGVP75uGBUhuazxxwF>X+!5=$vSaMsDpyrG$k! zq2I@kVA-iX@mJ$p(9B(p+|otKwJZYv(g( zud~b9?rcW$Z>6&WofQj^dufI1W_3hfrutSj%R|S-&*o9{6U@EbiG`jvp)pu$=Aq|e zzL}hZRiLjjM_>wOKePusVrKy*b`=H2p_-m!PAnr`OqQ>oxUidzCy3 zjsNf6Bj~EyQ!v0Z2=ZjP;wt&FWe9E)%_02D?oB_y)U7w2cgQne-(Y zY%(!f*I<)LN6284Ny&p`u**ba%3zm?ZUuu~ChaGKT_)!F8tgLZ12WiUqVZ+0%cS?n zV3&yw34>iGy-mi~{89Ii@fD-D$T-SqHyK|7!35EpWPHIJ-yq|2Mmxwj!svA}4l{a< zj6;lGA>$yUm&o{x(Tik!%4i!IpD@~L8V49XXBrSMM-qk?}Gk zv_oHFbR!wt8KFh`qC!bQ*ORf0H_jsC1x7Q;c%Bj3rdt_JC1VStNn||7=xQ?9Wunu` zV3&#X@&>z18bij@yx%A?*klq~pKLO5H!_}N6NJ{f!7h_Vkijk!N#+c8nKYCPcA4m& zGT3Dj+M(<+(JyPT%Otc&*=3^l%V3vD7n1QPe}oIjSi=Zy)76a5LnH7JhUb#8icv3V zJj@7f&XtUMkns>Bv^h%|bt9vM(P?C47@_r9%m}T|G^37W6fx>RMj<0KIST@mB(yo% zWl}3L*kz*E&R~~`+qA(hlbVvjE|VIQ!7h^;lEE&M>XX4Plj@PdE)%^T#smCzwaH+U zi8TNXHkouB88Dfu5s2<=gIy+7B7PBN}xgd5xhAl(1NYh+x_8($^kDn_`& zjc4>S8RHneM8;S~+sPQi2zR~FjJA<6DnRma5?3->PhupabtJA}w3fsOMyp8-=SwJ8 zkr>7sSCY7#Q7MU`j4~vKFiMjc%&3UOWsFvk7{n-##HEbzz~d4|OGsSI=m8QJF}h!h zfs7U>eQ_bf`$$~C=w1>77~MnSd`62%^k;M@iSroUL82d{`6SL|bQ_7jjOLLzhtXUT zeHh(L;%r7YkvL1Cq>yt+^yZB>lIX=~7Kt+%%^=Z}(R31LFq%rD2csz@x-*(g;&eun zNOWU#4T;kjT}|RtMpu#O%4jT!E`0x!V@P!7jiX7N!e|tUPK-v9IGNE15+^YlPU1vH zgGh8_bTNqzj0Tcu&*(xD?HHX$qAjCyNVH*e79~Y%hP_C%Vss{nmW+CkIDt`j5-k{Y zBhj4EX(XC4>O$gpMyHTy%BTa0CXCvVXw0Y$iAIcCk!Tp8q-;T=0dH(fqCTUBB4fL=8q&v6c;^DkQ2gs!XD)D?8!-Cy~Rn z3U7>)sLUuvq7tJhi3B6p7jfkajg!izTu$x7`;UBy1Xpyqodj2O`63Cf=<)>;s-oj< zwvga@E}tX8^;|wfg6p~5OoHpVe3}H;bGeBG*K_$439jezNfKPo#S1VGT+zkzWN<|n zTgl*xF1C=t6#_-@Hh-b;*dM@C2xSoqA$>4e}%E;h)E;f?E^;|qo2G?`3o(!(% z;xRIUdX64sm?W;~Vl5e5(Z!==a77o7kiivQl#;>qT)-}IJr@}=xSoq*GPs_LG#Oma z1&kBdb5TeJ*K<)o2G?`3f{eal4{|;kT+zjYWN<~tvsZ&Fx=4``RCFPhkiqp_z+iDb z7x$CF^<2PeaXlCJk-_y`+)D=6b8!zDT+hYbWN7bOCFBx!+3=4NS3@VRuX$Kc6V%EY<6rSo`nsHofqpFI|ccY8^vnGd^`vH zDf$H#UEYJIU|XUaqpPFoXezoedNZ;nPl%3;4#H#IUU&l5KH4l=H(CYDFaL?>Uq}4? z{+|CZ5MeGJeogSN@GtStP5M3jll_){12pkmEX4eScf|Y9+wHyNZT22R18=!^k9R8; zW1i%V@-FlGduO6`*T!q?9p^|BbH{WYga~!<=@e!KlqrY-ZLmD+ld) z^^|L$+$~?0&x8+n7t1^391KUeN{*11U@_-2WGC4g%Q@Gq@Q8N@GAunwYbZ@AT8Jf_ zX5azW2-w}0eW^RrES&)NR~2o}Ke3L}VX;rVDYlEJ#X3=fRLpm)`xXABHng+OD_gtI zynxEqEtCVO?BS2`h^%bod}@s+yzVRvLwLtPZm$1hZ_Gc`5>EzA@$h+Vg_by;@?Ys* zhA}C-7=P`SkJXZN%_ z+imTpc5OWMx2!)fM&$_dZ||{QwYFFrt<`w$ztmcUQ7YG2ldUmG!hNCD$2uKP{##lN zF-|3F3G-L1>irqY#x6Yj-)yeOK$R8d{YbZUlR3kjfYrSRnf=XP7^*;oRl(BJKzq zyj4gdxx`!O&Bf59N!}Q5sCS{)2g5y*CwY%x<@S_!7e+13MrgD*1fg@h9^r%X+FoVP z!N{eb-LKrwFdAex9+hu#%dn1n2}Un1b{Dueix=EkT-4R8dvgS%7SumM#Oi6ywTac! zy2&P1Piu}%te(~lHnDnI*V)ACY0a{U)zg|`6RW2+-6nR))>NC$VI8$5+ti0Y^h9Fu zv?kcZ;%QxF6N{%c&L$R5Ym7}Sp4KRvSUjzfHnDhGBWz;vw1(Nl;%N=FiN(_zY*ROW zvq5y4dJ=#OdkL{ewl1=XJ+gJ7OSz<& zW2?PQY>%zBHnBan+7Pilwp!VAd|B>?x;C*rwrbnN_SmXv6We2}hD~gbt!g&0J+`XY#P-;#WE0zCD{d3pV=Ec8 ziT$zV*~I?Xa%_S>hHtejo7f&((k8aYmavKKu@$ii`i%X|zif&#`opFequ*?bGWyjf zpV7}Yd5nIv$pu0q*!lg;QW3_)S^rA;QI&ux;74%Z^#>p3 zfK3rbAKBt>M*D5?7o&X`4Z>)zE&fO{e9soYGkV7szcJcli(`y-+u~P7yKM0bqn)<+ znbGUE_=(Z0w)m0J%eMG|(RN#W&uE)1zGL*fExu*6C25Oq7(Q!@uNiH&#aE0r+2UwW zSj{KJmkc(FFBm*7K4-9A9AU6d9A@ySIK;=Val}F1^oaP3!NcNH1`ml(u#>v}Xzd^1 z{YyxE%+Uhz5rcfOpTTnRA%kUNAA^+mfWZS|FN4M6eFpc6_ZZwQ-equ?c!$BA;%$Dj z1tj+H{l`Qj{w>~!M*MC@w~~01kGMtbVlY>{!Qf`Glfg}52ZN+|oex7p{xwE7ka(5R zG!m~cLbLp3MiWT91f;${+U47M<2Wf^WHeTaZH&gmpf5qWLIeGIMrfdKWppKpEsW4q ze~!@=B%Wo2M*B02&}iSx=yDQIGa5=_6IV!c2#Kd6iTRPufpA44R;t4;w}0y6p~grq zq4ofqRt1OI{cU=f5pIJk8R0hg5F^|MOM^>dpG74MdQpaBJ#8vxgu7sx(djl7F~VK2 zkP+^J1$<~{!di&x4sCa&d^>Xc$om6kB5Ob;+f z(EWTE?m>%rlSlV4aOhr+nMtC17-Hn(-5eFPh&LHTcLkfQzi1(YKj_XNX8lgIfHxhZ zJ9yJCHqGZvKhf>H=?9x`<4xbut-J|$p?SRNE4n3ANZf_yauj!=n;9MU=_W>peBz(U zI!M8TZ%EpwbR!3GJ5o=+vFRhao;U5YgD2nEv^RM24e(y@3P;O)(`#bXS5i*+13oy1y3r;&J+QCDEaRv}Vksk&M2e9lv4oM3;(-9kKS`j1sBU`s z2Z_bJ@feBw82w6u>xjg2L#`t7XA*aF^d}NrN92zr?&59VlUT^;TM}GLRZ`5_6eDe?oH zkoVh5Vh*GCNN`n=?~=HIx4lDx>xvxtHi_$a<69(VGulmJ7Na*waD9=xNX+1EJ4tYT zkvm9meUYz|;QAt8H3iof`3i|CxZ%!9y*bpFo>YA|ZE3_mv+u^nVCL^)hcK07SM0^u zrr6q81_PNF#cn~@O>$CfbZkg$!2fR(N%$GP8ocbF1Lw!2_qn&&^@Y=MQrG zyJxzcv5V)C>spm9%lzH^Hrs*ol=-MxY%Uv%5&E~9*CQ$RXmhZ6KHBJAFe0Og zS<{S}LjEF;qJjR7d=29Bhgy~G=l7#E2Puugin z*omGA+ zqvtSmV-03*EO+m7?{IHI@tBBV?L*yxZePsa=$2a1`A5k~)@W-8x^~V%2K7^{wpLTCwp9tG<_}EkIAZR{B&1id&e}$EwV5`Tnu{>8 z<2n?ZG3fZa(CmZN)=n~8nhi0tBZ`9aD>ABoCilu+ay!;sTQ48ROr#Ws^4yAb*QUs^ zC_Dq@IkG!eZf_NK{>dcD&$o0KBQV~^6pt5Z(|y*)KY7hrYrF+lkj@s;=#+1B6q zFNa+H@A~+X|H+W6_)u5G>&s^Y$&S~P&oHPfH#4XspAPQ5anF;R7*UO2f=TFTdE3+V zB^&Jc^7@huc6^yH*b+YwO6Ze8}`Vatotrb>wsWZvW38+mK|>60J&-JxjEbFWIw1JzuhC@smGD z$)?5sk|Y~?|8vQP-ajJQ(EEoa8+!kcWJB*Cl<+ICEB=AFWV_-&Mw0D{UqX`YiocK~ z+ZF#dU$R~CM1t_1rP{|u7sSNyId*{=BQ zNU~k=8}|2UFtSCW1WlI&Of>Ll5(c+Zn$zv4X@m+V)( zWpT-V#jE2>_A6d(U$R~CTwk(X@oZnRUGXemvR(0rB-<4)LXz!@d(4-xE6VY?zxtB> ziu(&m_ABl|l2d{U?0!aaGNVsPPGa;4$%#REa37Ow@!hp@0&iI()d*KtxQ|FR!WH0Q zIi3$&8JFW2JrtK?6-o-XBreDB#^Sgf&1iXCs&TG3_8zImxdJSbBRMwLmujFZHVu~} zc+;hEIh;{1Uvjsp+f!a1Y;sV)h6ejPZ^|LO>2+TYW|VxvmzObo-j{=TzenVyylEB5 zOBg*&@?u6SNnXV0A(8_bm6E)W5lY?#j4~t#Fv8b5pHEyQ`}3wklIH~|=@gLc#~W9W zJeN^E$-a#8;_@6uxFmfT-AnRpMvF+E#po`Qy&0jz_hPhwBjwfvfj!EoA>&j{$lVQ{mI~4`h)lW+Na+c9Zh=l8^bR>I>zV= zkA7wJxktY+I^xmKj1GJB6Qe^O{mAH`M?Wz7%%$%ced^J7j6U(`TmA$G=o{Yjkw;$# zC~5C^=_}s&VVsUK+9&BtM(^761*5lZ`kc{QHXUK~rcH+#y_K|+4KRUGMn}?dcvmn z89g4S_ZV%6)4Pn;+w=~j$836=(KZ%J)TZ5x*4XqWqdc2-F?!IZHyACo zX(yv4Htk?^zfG?*y3eN97~NyjtBe-e^a`VeHoeR!xxl8E7|yq8JEL1|dXdpBHf>{c zvrX*WV72La-Zsakt&DE4X$zy-Ha*8^rcKW>y4I#=7)`TjGoz_CJq-l^XHT|i6K|Yo z(^HHl*u?G)kMXIDw~e)FBcstaJ;CTon;vI$g-sh64Yz4Mqswi2jL{IA)-k%wrnQU) z+4N{lhL_m1hS5bft%i;LG=-r*A0>lrRVVwB%Wc(DNpiWZ+AJZt*j9S1h2&yeX~}Vt zi*2Ple96VO(mY>sv8^;SF1grNnh}>=Y%5(Gmt1TsO^Zt|wv{HIAi3C9x+-~`>%_SGxL|Jpm#Wt~wBp2Jn9hD>(+r*9aBp2Jn4Zh@J zo4DSWTx{dN*OOdqt zx73ncZsX52lw54%o9oN%Dvj8n$bm@WZA?_Z5!2F-$0YO}$o6q9@_W=nH_VIZdbuWc zMyz`D^XM~3%`qAc=9qr~i8t;*bGULP(FhDccm-3g zr#QWxS{PKY6@yF0V?aq|3?g|7EyyddD7R~Vh-J2JH7~nm68RK4Kw9&Yw0O@Wtrxd=c+leOSI%49H~+E4=d5VG z`1kx)8>X*tjm7ixS}#5^uhrrk3g#`|kk@*{=%x9X{}s6;vNwXH6DyHuVnCuP(n`FJ zR1(uMqoOWSMr=cxhzZCHQ4QH3He*7_C}e$zVnY1m$nG!{866}hbF4<@$7w=P;(RVC^SV|`(@^XZEH)_#r!_l9s85_DD z-A<`-qq+?%8#Sg|Pb0N`RJXRN(y`qJr@kN6t$k|s=xz&AjYoGIn(8zLfjOhQwO%~q zVC%(o4}G}!%+CfbK6Yr(;^p{z!Qs}6fB3BR;u{a&vbg@i%QoD*Z5kynj%1BElGj~p>O5zi&u6~;sBw8AO7(0zZW2({1s1Z35*_7%% zq1)(G$)s*WQV&nScfax)eB<{g;N@P0Z1wWoHMlY-UW4d+6T7u8YdF5!$0D_D94_C| z7RESAjkJtmsgBYZno65S+teb3cA3WD)Dda4Pi?WVt)>cmtOhAxN*i(NDGS9R8+f7)4H`z4W5bu_t+E^xcO7NRWnk%hvTYs8j5Q%Y8Wo(n4zFs zhT-M@q3TKwGmfNIUv9MiS6`ohq#Tv?Ut_Ensp>`el4A;uwq?DGj9-n^eSoP>g(wwE zm!iIvt-2R=IMwf7Y@M~(n4g*jRMvGqO3}admtS?zxI~m4-EZK>Zuz0HF!jVfe8Y_& z;@3T(P{SR#EL~nV=9jJ7fjv|GcNn+>y{xW?|CBmt_tV&`<&(G=Cv7q&8)aQrW9z^3 zB}wgWBHE@dZX}*eebG=1O`Ts!v@P3KNt}kd^atuvSyw5x(*y5{O%I$RTBmB0IF!2E zz)Qn}#)5z6FJ5L{D1I|ine)ZavWC5(TdBKy;Y!RpTg*>At?T$iWv6x)y^Pc;U9t7XE~0(eeO(0(TGIt* zDm@i1A1JivRD|uW2ybaDs{C6QoU)O(;cKTlTqhQ$KAwf|_RMu+a4I@m3`^C$9tG*D z+1NJgdb})Es8pft3hlWb*Wi1gvS%lXo<>>UYjB~;8eWDuzNu}4aCp~WQO6n|!wqrnqri7!?-acwYdZ0BOBwG8yn&}Z)r?Dj8uEE-u-L{ZAr)J$v^HZA_qB!-v3*YeQLVTmr zyRfb1UAREjZ3G`Ubsnxl&w2R5yKhJMw|Tfe+ooeSZmRQiwQ(jk&bS5k`n9=e%Vmb+ zJWYqeZET(q9fN$AK-!!PovhEdjO1uoT+71(n|0WB!IVi9)wx4uZ3cTqfMyoGPM z_f1@mJ#XQwU9}5W$Jq_~;4VZvDfII$+E_Mnx4H&P$6@{UvaSU9Hf& z>g9r(a$(A;4fJ76Ilt_r+7iBMTQvy@?fNS%EE{l)*1=pUxP1@p|Ce8t|C2d*wT{^- zwfi^|hADxU%n!H(nJ@9O`>?tqpUR$I$5q)smaeD*=Lb;d0?GLuwipQ&D^sh3IWxN(K-?~mdyUIM0TKllMvF!Ui6LLBuWiCk7UThvp?YT)@mswQ-u-I7z*X#mkH#*n9UtMbA|)XRDVp z)gh;=L;9R*KADfm-N+)BMPS1(P}O9Qjxzq;r1l>cMrUD>J^O%%*icA4mZ z+l?>t?wjV|)aYHfmZNs#(w_GwzI5qZ*tT_-xiHoDEzpPG#MQa#b#n=ojaX;yG|EP; zH_=_!dOZ%mXBAHL%1Rtr`Unm>d8PR;Hz5B|pVYPyrs{84ZKCgP+-K&nvc?C^{r_Ke z=N}zak>&Bcm+sf^y-or%Ftd=L#PCxMAwURp=S2tQN8kV=fXF?dn z-3ft}CX!TkO+bbiM+~4V%gbUC0z~AOGZ33GAUKFj05_syP{e@ysRZ`S&a&g^c!q8M zxaZc7*QCC6tLoOhRkxV1V8xi-G`Oe^Qn(8e+>Pw*tfL@jHz;-ANnYJ91P23kf*7|G zZqP0;IkMB4Xj}EpCqsKUE^<4u-s&8Yw~Hrn3B>mLoYJw-O6yu$ofw0QTfw5_VQ0Hl zG9&E3&2SCa&gIUr4>|iezHuCOY;Y{(sA*RsJJp1*B6iN8@V-QS`7sf0TX85g5pJzO zU7|jvj#RrSA1S|AUQ?DSla)SUU-7qJ|7SO=&d!QkUzO(!Qr9l_Mu}gAiM`|AN#t03qc9gbFoExDf2=2dTit~N7bdlOu zE3mWf&@kIv7%OMF;;{%_iH^`+o4ilR6V`7LIeK=7)D9hp3H>_3_oqbNPO$Q~BiBXF zi@X@+KH42)er)dGRPqdSFb7SK5-oW#*Mo1%>uCiQ=ID8%3x3uKKe2b9J2BUHMGetrRJT6XJ93kDD`&B%ns?xB`;GAe_vD8gKh@82Ms}s1NlZJ{737F?4&my$ zY3I4ATu3OoWa5w?^_-rW_T1lJIcP5Iw1{dYQ;?Yt^~xJ=jK? zlq#h_!7i@|ML2J>$G)tgBHi*L-MhM+?wugHPs+7;JNHHH8FT?bI<-iv64h%opO`3# zHy0c#7i$G#!eWxic~r^Hh0K&(Nv^isUY)1SQAF%wt-nZZaXe&iZo%0lygojhkRhx4 z_&P5`I~~evy{+xiurv7^HEHIpmvfBwkfgQyHP+GGqG&c<`Jz^G4@<6DayfY^ zmsATkxrTauAok2!fU&JhTvQU{KcHy(NhXrK545LMapt7vvy1Dr&^9#Lv2Qv~s&>{u z7n4ci09U3cO$4uJ2LRvRL_piv%hg|u?g>) zdXT&s57NA&lOc~yqVdFT@QF7kk^EQ|R7?TC8d>jiSsF8i&&ExbKQM*TSLA0oaJDtv zg}7NmT?O_=j|(+2*W+UGKj@H)|3S7N{(8rCmo3ZIpF0=u|8UvTiXGUl>(@9k#hw6- znH6xP+ZO^-2)#31EMQxz*^Z5@W^*;K#_-E9&v(d~J4eFgmk7oc zIoemG?>%jgcHecgmh!Ajoi+u==(tsr2I>bDQJbJAijsKUC(bA61)?QhXNdKOi@sBD zva_Offa%pmXDG$!=@>!avQ#~>=p6L|s$TF@y=Y9E`e^P~^`g=3>^>DIrrso?zjif= zn$0W~@s)DWZ2{YYN_rtja!r+x3dwceM3vwc250FeS3*dy_ZyGsOdsV3K(%jif1BRUSdVjrCu%D`bq0ts)u&NyrM8n)?@&ipjy106N#*;BOJ zI!Ti&J_I!XNs>7qk}Nq17HJ=ntUaaY3vZ*2<>Wo`#vdiGq>(ClMoVeFq#9=Q1Mh(1M6EC11afh#EVm1i~OKINq6ZmRFJ>An{0%bzbKD4UIzJL_@d%0SDC)c-xg5zI9RZ#Vqez|_PEs35 z<#fpAPScW&>#D>}J7V}( zS(36A(Ku26l))~zT4xvRk2f$XY1zg~@v$E?M)+xFVYbmE7Dz5{5x~s}e!)RyptaC8Ti+jS!!o4jg8F@*FleB=H|`qpRq>;2U&x(ssI<(9ii|VU@Ac zp1EC4S^8RvvrFmgigj>%N+FeH)V@$k?Lt`^Tt_mujAUFH_3G9lBFSqFW}+7WPxvc! zboEMI>gts&042ZHx3x`A56M&C?YjDGo)?(hp${j&4@8wk&50To)rt4;?8xQZwC_jk z_rnnzxH3H|qANkpYPb&l2#+f|dBW>uF20X5yYoEPZlj2xgdW4KpU}7HOZ5lzUc{2y z$9?oCcroio+K1Y|Yro_%tUG!1?YGXm*YncV2lkqIbx9w!wH;l)uBTlpQugT0awu zMwvK3hL}DvG}&wt&-XP8?D4mooD0%=o4Dbh>uCZ`ACn^oJxtEXbT+Y?U+8FpYOs^Z zuHeTe3dx|3RH)TVgw0`I_o9Ex#_-P{7{3|zOx#8^Bkdu?YSJ{MZ1YqzUpzgHywtM@ zM&&vBf8SXn-)=l-V8kjeMNPFcCYT$T@`syI?K;3;Vhz869rs@eAo{KzE;`8q)#rnqh=Nax$UKQ~XiSNn-`>=_=HTj9*$wNHhI<6b02 z;%G-q+nb16!~cngF2;r56Fww7p7$*dslWPfYk2hyt>L&YY51j0koQUfBW*2$5Ljy_ zxb?E6wrx$+R+Y11viqycsP$AC6+V)jQD*w6)w8`;xoTg?HD6G$ftu-dAkRcQTUes6 z2p7BO^1Ey1^4Vu|`79aY)=L+)f3`>!Gi7=FJc{Dxo2SK8ILe=BFMmQ6T^CTEKM&a* zy?~x-SU}BFvU=cA3dTH&c-B5@UUQD7hwZyQ`TZ>}FwFTQOY@j-w=}m;e)H8?sz-Gz zCzLHreh(wg0Q8v+sWYLKE5+Rr?sQv=a$_&^w;(DNUm_dFE<#FLAbA&&oIR4$zkme4M22E7 zB10`QFZqjWYr&MTx4w1k-C$1qA$(hD__myJ-=cW@y*flSl=qZP$`a*%rAOFB{@y?R zC!%dnlc?Y7Nwl9X@#KZ0k9iWstWpoNQyC;@9b|W@hrMEb!6*m-3h77NSr zu(7(_FD6ku-Y+KJt*;y3Hjj1qjVb~OAgUZ)GCP7S$hXnh_#AA%2;CMV-UVIE@ z$Ap+FaYsVTb%_kk?b6009xOr&ssX8A4REcOTyO{6Z>v3-_OTk^5_vTq)Y*Usb=JGa z!{8K@Z!Dr_$r_JO94nHr7kMzyt??w-dNKDWM9EgzmaU%N?GDvxVZj>--IS=YQMYoH zZx;_BJsLSQ(&Qc7%@Mzdm>AKMXPfuBZ@dtHH`ijyjVJt&GOA6Qdp{)m(-)H%7$y=-r zX_nl9PPOn#`X^ZI15%5TsG-( zOYWB+mksUG*3ej)8*7z@wsG`ACCw;tv~_5N?9j-z4vmoQ)Z23NEetTrEop#RZn1&u zXti4lLiN&W+5rY?{a)F?ODX>FBCl+e6ZOOVi}7!u0lAh2Rl$ z7dNk0rBb}u;%;*AZs2*>BKdJDwY%NT&5FUPsqC8ur%HKAqNL<_N`f7CqD_8|OZhn| r}e)2W)jRVr1fpPQ32ZA{Ym$?3DkFbvHL@dU@j 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

      aTH3?Vrn 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

      ciI&>ES|niT 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�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 TxZ5NY%*M^9hkM4|w)Fo1!QX=I diff --git a/tester/main-db-tester.cpp b/tester/main-db-tester.cpp index 1623b6e1b..2ab90d43e 100644 --- a/tester/main-db-tester.cpp +++ b/tester/main-db-tester.cpp @@ -54,21 +54,21 @@ static void get_messages_count () { MainDb mainDb; BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); BC_ASSERT_EQUAL(mainDb.getMessagesCount(), 4976, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getMessagesCount("sip:test-7@sip.linphone.org"), 3, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getMessagesCount("sip:test-39@sip.linphone.org"), 3, int, "%d"); } static void get_unread_messages_count () { MainDb mainDb; BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); BC_ASSERT_EQUAL(mainDb.getUnreadMessagesCount(), 2, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getUnreadMessagesCount("sip:test-7@sip.linphone.org"), 0, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getUnreadMessagesCount("sip:test-39@sip.linphone.org"), 0, int, "%d"); } static void get_history () { MainDb mainDb; BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); BC_ASSERT_EQUAL( - mainDb.getHistory("sip:test-7@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceChatMessageFilter).size(), + mainDb.getHistory("sip:test-39@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceChatMessageFilter).size(), 3, int, "%d" From d9964748fb773e55e5a0b0d6b6a2b8d68137bf5d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 23 Oct 2017 17:32:55 +0200 Subject: [PATCH 0606/2215] Added a C method to get a list of composing addresses in a chat room --- include/linphone/api/c-chat-room.h | 7 +++++++ src/c-wrapper/api/c-chat-room.cpp | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index 33bedd0c4..4aceee53f 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -333,6 +333,13 @@ LINPHONE_PUBLIC void linphone_chat_room_set_participant_admin_status (LinphoneCh */ LINPHONE_PUBLIC void linphone_chat_room_set_subject (LinphoneChatRoom *cr, const char *subject); +/** + * Gets the list of participants that are currently composing + * @param[in] cr A LinphoneChatRoom object + * @return \bctbx_list{LinphoneAddress *} list of addresses that are in the is_composing state + */ +LINPHONE_PUBLIC bctbx_list_t * linphone_chat_room_get_composing_addresses(LinphoneChatRoom *cr); + /** * Returns back pointer to #LinphoneCore object. * @deprecated use linphone_chat_room_get_core() diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index f92827208..08a0ff47e 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -274,6 +274,15 @@ void linphone_chat_room_set_subject (LinphoneChatRoom *cr, const char *subject) L_GET_CPP_PTR_FROM_C_OBJECT(cr)->setSubject(L_C_TO_STRING(subject)); } +bctbx_list_t * linphone_chat_room_get_composing_addresses(LinphoneChatRoom *cr) { + LinphonePrivate::ChatRoomPrivate *room = L_GET_PRIVATE_FROM_C_OBJECT(cr); + bctbx_list_t *result = NULL; + for (auto i = room->remoteIsComposing.begin(); i != room->remoteIsComposing.end(); ++i) { + result = bctbx_list_append(result, linphone_address_new((*i).c_str())); + } + return result; +} + // ============================================================================= // Reference and user data handling functions. // ============================================================================= From 9add45af7ea223593cc7ef3cb213eb9ebe606581 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 24 Oct 2017 09:15:07 +0200 Subject: [PATCH 0607/2215] Fixed doc for function added in previous commit --- include/linphone/api/c-chat-room.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index 4aceee53f..aa7fdda4c 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -336,7 +336,7 @@ LINPHONE_PUBLIC void linphone_chat_room_set_subject (LinphoneChatRoom *cr, const /** * Gets the list of participants that are currently composing * @param[in] cr A LinphoneChatRoom object - * @return \bctbx_list{LinphoneAddress *} list of addresses that are in the is_composing state + * @return \bctbx_list{LinphoneAddress} list of addresses that are in the is_composing state */ LINPHONE_PUBLIC bctbx_list_t * linphone_chat_room_get_composing_addresses(LinphoneChatRoom *cr); From 4bfbe3d9d4357305d890dd8f2d6e235b5c885204 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 24 Oct 2017 10:00:39 +0200 Subject: [PATCH 0608/2215] Added more tests to multipart tester --- tester/multipart-tester.cpp | 48 +++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/tester/multipart-tester.cpp b/tester/multipart-tester.cpp index 29a6544cb..677b5f62d 100644 --- a/tester/multipart-tester.cpp +++ b/tester/multipart-tester.cpp @@ -30,7 +30,7 @@ using namespace std; using namespace LinphonePrivate; -static void chat_message_multipart_modifier_base(bool first_file_transfer, bool second_file_transfer) { +static void chat_message_multipart_modifier_base(bool first_file_transfer, bool second_file_transfer, bool use_cpim) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); @@ -39,14 +39,27 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer, bool shared_ptr marieMessage; if (first_file_transfer) { - //TODO - marieMessage = marieRoom->createFileTransferMessage(NULL); + LinphoneContent *content = linphone_core_create_content(marie->lc); + belle_sip_object_set_name(BELLE_SIP_OBJECT(content), "sintel trailer content"); + linphone_content_set_type(content,"video"); + linphone_content_set_subtype(content,"mkv"); + linphone_content_set_name(content,"sintel_trailer_opus_h264.mkv"); + marieMessage = marieRoom->createFileTransferMessage(content); } else { marieMessage = marieRoom->createMessage("Hello Part 1"); } if (second_file_transfer) { - //TODO + LinphoneContent *initialContent = linphone_core_create_content(marie->lc); + belle_sip_object_set_name(BELLE_SIP_OBJECT(initialContent), "sintel trailer content"); + linphone_content_set_type(initialContent,"video"); + linphone_content_set_subtype(initialContent,"mkv"); + linphone_content_set_name(initialContent,"sintel_trailer_opus_h264.mkv"); + + Content content; + content.setContentType(ContentType::FileTransfer); + content.setBody(linphone_content_get_string_buffer(initialContent)); + marieMessage->addContent(content); } else { Content content; content.setContentType(ContentType::PlainText); @@ -66,11 +79,36 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer, bool } static void multipart_two_text_content(void) { - chat_message_multipart_modifier_base(false, false); + chat_message_multipart_modifier_base(false, false, false); +} + +static void multipart_two_text_content_with_cpim(void) { + chat_message_multipart_modifier_base(false, false, true); +} + +static void multipart_one_text_and_one_file_content(void) { + chat_message_multipart_modifier_base(true, false, false); +} + +static void multipart_one_text_and_one_file_content_with_cpim(void) { + chat_message_multipart_modifier_base(true, false, true); +} + +static void multipart_two_file_content(void) { + chat_message_multipart_modifier_base(true, true, false); +} + +static void multipart_two_file_content_with_cpim(void) { + chat_message_multipart_modifier_base(true, true, true); } test_t multipart_tests[] = { TEST_NO_TAG("Chat message multipart 2 text content", multipart_two_text_content), + TEST_NO_TAG("Chat message multipart 2 text content with CPIM", multipart_two_text_content_with_cpim), + TEST_NO_TAG("Chat message multipart 1 file content and 1 text content", multipart_one_text_and_one_file_content), + TEST_NO_TAG("Chat message multipart 1 file content and 1 text content with CPIM", multipart_one_text_and_one_file_content_with_cpim), + TEST_NO_TAG("Chat message multipart 2 file content", multipart_two_file_content), + TEST_NO_TAG("Chat message multipart 2 file content with CPIM", multipart_two_file_content_with_cpim), }; test_suite_t multipart_test_suite = { From be1d6f99ede425ad561821c08925b8fac8bc7701 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 24 Oct 2017 11:15:42 +0200 Subject: [PATCH 0609/2215] feat(Event): events are now shared --- src/c-wrapper/api/c-dial-plan.cpp | 41 +++--- src/c-wrapper/api/c-event-log.cpp | 20 +-- src/c-wrapper/internal/c-tools.h | 138 ++++++------------ src/chat/chat-room/client-group-chat-room.cpp | 24 +-- src/db/main-db-p.h | 16 +- src/db/main-db.cpp | 40 ++--- src/db/main-db.h | 4 +- src/event-log/event-log.h | 1 + src/object/base-object.h | 2 +- src/object/object.h | 1 + 10 files changed, 120 insertions(+), 167 deletions(-) diff --git a/src/c-wrapper/api/c-dial-plan.cpp b/src/c-wrapper/api/c-dial-plan.cpp index beafd3ecd..534d0d417 100644 --- a/src/c-wrapper/api/c-dial-plan.cpp +++ b/src/c-wrapper/api/c-dial-plan.cpp @@ -18,7 +18,6 @@ */ #include "linphone/api/c-dial-plan.h" -#include "linphone/wrapper_utils.h" #include "c-wrapper/c-wrapper.h" #include "dial-plan/dial-plan.h" @@ -29,61 +28,61 @@ using namespace std; L_DECLARE_C_OBJECT_IMPL(DialPlan); -LinphoneDialPlan *linphone_dial_plan_ref(LinphoneDialPlan *dp) { - return (LinphoneDialPlan *)belle_sip_object_ref(dp); +LinphoneDialPlan *linphone_dial_plan_ref (LinphoneDialPlan *dp) { + return reinterpret_cast(belle_sip_object_ref(dp)); } -void linphone_dial_plan_unref(LinphoneDialPlan *dp) { +void linphone_dial_plan_unref (LinphoneDialPlan *dp) { belle_sip_object_unref(dp); } -const char * linphone_dial_plan_get_country(const LinphoneDialPlan *dp) { +const char *linphone_dial_plan_get_country (const LinphoneDialPlan *dp) { return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(dp)->getCountry()); } -const char * linphone_dial_plan_get_iso_country_code(const LinphoneDialPlan *dp) { +const char *linphone_dial_plan_get_iso_country_code (const LinphoneDialPlan *dp) { return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(dp)->getIsoCountryCode()); } -const char * linphone_dial_plan_get_country_calling_code(const LinphoneDialPlan *dp) { +const char *linphone_dial_plan_get_country_calling_code (const LinphoneDialPlan *dp) { return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(dp)->getCountryCallingCode()); } -int linphone_dial_plan_get_national_number_length(const LinphoneDialPlan *dp) { +int linphone_dial_plan_get_national_number_length (const LinphoneDialPlan *dp) { return L_GET_CPP_PTR_FROM_C_OBJECT(dp)->getNationalNumberLength(); } -const char * linphone_dial_plan_get_international_call_prefix(const LinphoneDialPlan *dp) { +const char *linphone_dial_plan_get_international_call_prefix (const LinphoneDialPlan *dp) { return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(dp)->getInternationalCallPrefix()); } -int linphone_dial_plan_lookup_ccc_from_e164(const char* e164) { - return LinphonePrivate::DialPlan::lookupCccFromE164(L_C_TO_STRING(e164)); +int linphone_dial_plan_lookup_ccc_from_e164 (const char *e164) { + return LinphonePrivate::DialPlan::lookupCccFromE164(L_C_TO_STRING(e164)); } -int linphone_dial_plan_lookup_ccc_from_iso(const char* iso) { +int linphone_dial_plan_lookup_ccc_from_iso (const char *iso) { return LinphonePrivate::DialPlan::lookupCccFromIso(L_C_TO_STRING(iso)); } -const LinphoneDialPlan* linphone_dial_plan_by_ccc_as_int(int ccc) { - const LinphonePrivate::DialPlan& dp = LinphonePrivate::DialPlan::findByCccAsInt(ccc); +const LinphoneDialPlan *linphone_dial_plan_by_ccc_as_int (int ccc) { + const LinphonePrivate::DialPlan &dp = LinphonePrivate::DialPlan::findByCccAsInt(ccc); return L_GET_C_BACK_PTR(&dp); } -const LinphoneDialPlan* linphone_dial_plan_by_ccc(const char *ccc) { - const LinphonePrivate::DialPlan& dp = LinphonePrivate::DialPlan::findByCcc(L_C_TO_STRING(ccc)); +const LinphoneDialPlan *linphone_dial_plan_by_ccc (const char *ccc) { + const LinphonePrivate::DialPlan &dp = LinphonePrivate::DialPlan::findByCcc(L_C_TO_STRING(ccc)); return L_GET_C_BACK_PTR(&dp); } -const LinphoneDialPlan* linphone_dial_plan_get_all() { - return NULL; +const LinphoneDialPlan *linphone_dial_plan_get_all () { + return nullptr; } -const bctbx_list_t * linphone_dial_plan_get_all_list() { - const list& dps = LinphonePrivate::DialPlan::getAllDialPlans(); +const bctbx_list_t *linphone_dial_plan_get_all_list () { + const list &dps = LinphonePrivate::DialPlan::getAllDialPlans(); return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(dps); } -bool_t linphone_dial_plan_is_generic(const LinphoneDialPlan *ccc) { +bool_t linphone_dial_plan_is_generic (const LinphoneDialPlan *ccc) { return L_GET_CPP_PTR_FROM_C_OBJECT(ccc)->isGeneric(); } diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index c6a2a21d6..b4af02343 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -27,13 +27,13 @@ // ============================================================================= -L_DECLARE_C_BASE_OBJECT_IMPL(CallEvent); -L_DECLARE_C_BASE_OBJECT_IMPL(ConferenceChatMessageEvent); -L_DECLARE_C_BASE_OBJECT_IMPL(ConferenceEvent); -L_DECLARE_C_BASE_OBJECT_IMPL(ConferenceParticipantDeviceEvent); -L_DECLARE_C_BASE_OBJECT_IMPL(ConferenceParticipantEvent); -L_DECLARE_C_BASE_OBJECT_IMPL(ConferenceSubjectEvent); -L_DECLARE_C_BASE_OBJECT_IMPL(EventLog); +L_DECLARE_C_OBJECT_IMPL(CallEvent); +L_DECLARE_C_OBJECT_IMPL(ConferenceChatMessageEvent); +L_DECLARE_C_OBJECT_IMPL(ConferenceEvent); +L_DECLARE_C_OBJECT_IMPL(ConferenceParticipantDeviceEvent); +L_DECLARE_C_OBJECT_IMPL(ConferenceParticipantEvent); +L_DECLARE_C_OBJECT_IMPL(ConferenceSubjectEvent); +L_DECLARE_C_OBJECT_IMPL(EventLog); using namespace std; @@ -43,7 +43,7 @@ using namespace std; LinphoneEventLog *linphone_event_log_new () { LinphoneEventLog *event_log = _linphone_EventLog_init(); - L_SET_CPP_PTR_FROM_C_OBJECT(event_log, new LinphonePrivate::EventLog()); + L_SET_CPP_PTR_FROM_C_OBJECT(event_log, make_shared()); return event_log; } @@ -66,7 +66,7 @@ LinphoneCallEvent *linphone_call_event_new (LinphoneEventLogType type, time_t ti LinphoneCallEvent *call_event = _linphone_CallEvent_init(); L_SET_CPP_PTR_FROM_C_OBJECT( call_event, - new LinphonePrivate::CallEvent( + make_shared( static_cast(type), time, L_GET_CPP_PTR_FROM_C_OBJECT(call) @@ -128,7 +128,7 @@ LinphoneConferenceChatMessageEvent *linphone_chat_message_event_new (LinphoneCha LinphoneConferenceChatMessageEvent *chat_message_event = _linphone_ConferenceChatMessageEvent_init(); L_SET_CPP_PTR_FROM_C_OBJECT( chat_message_event, - new LinphonePrivate::ConferenceChatMessageEvent( + make_shared( time, L_GET_CPP_PTR_FROM_C_OBJECT(chat_message) ) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index bc04192ef..3783688c6 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -99,16 +99,14 @@ private: template struct IsDefinedBaseCppObject { enum { - value = IsRegisteredCppObject::value && - std::is_base_of::value && - !std::is_base_of::value + value = IsRegisteredCppObject::value && std::is_base_of::value }; }; template struct IsDefinedCppObject { enum { - value = IsRegisteredCppObject::value && std::is_base_of::value + value = IsDefinedBaseCppObject::value && std::is_base_of::value }; }; @@ -125,12 +123,6 @@ private: template struct WrappedBaseObject { - belle_sip_object_t base; - CppType *cppPtr; - }; - - template - struct WrappedObject { belle_sip_object_t base; std::shared_ptr cppPtr; }; @@ -141,23 +133,6 @@ private: CppType *cppPtr; }; - template - struct WrappedObjectResolver { - typedef typename std::conditional< - IsDefinedBaseCppObject::value, - WrappedBaseObject, - typename std::conditional< - IsDefinedCppObject::value, - WrappedObject, - typename std::conditional< - IsDefinedClonableCppObject::value, - WrappedClonableObject, - void - >::type - >::type - >::type type; - }; - // --------------------------------------------------------------------------- // Runtime checker. // --------------------------------------------------------------------------- @@ -210,14 +185,14 @@ public: template< typename CType, typename CppType = typename CTypeMetaInfo::cppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static L_INTERNAL_WRAPPER_CONSTEXPR std::shared_ptr getCppPtrFromC (CType *cObject) { #ifdef DEBUG typedef typename CTypeMetaInfo::cppType BaseType; typedef CppType DerivedType; - std::shared_ptr cppObject = reinterpret_cast *>(cObject)->cppPtr; + std::shared_ptr cppObject = reinterpret_cast *>(cObject)->cppPtr; if (!cppObject) abort("Cpp Object is null."); @@ -227,36 +202,34 @@ public: return derivedCppObject; #else - return reinterpret_cast *>(cObject)->cppPtr; + return reinterpret_cast *>(cObject)->cppPtr; #endif } template< typename CType, typename CppType = typename CTypeMetaInfo::cppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static L_INTERNAL_WRAPPER_CONSTEXPR std::shared_ptr getCppPtrFromC (const CType *cObject) { #ifdef DEBUG return getCppPtrFromC(const_cast(cObject)); #else - return reinterpret_cast::type *>(cObject)->cppPtr; + return reinterpret_cast *>(cObject)->cppPtr; #endif } template< typename CType, typename CppType = typename CTypeMetaInfo::cppType, - typename = typename std::enable_if< - IsDefinedBaseCppObject::value || IsDefinedClonableCppObject::value, CppType - >::type + typename = typename std::enable_if::value, CppType>::type > static L_INTERNAL_WRAPPER_CONSTEXPR CppType *getCppPtrFromC (CType *cObject) { #ifdef DEBUG typedef typename CTypeMetaInfo::cppType BaseType; typedef CppType DerivedType; - BaseType *cppObject = reinterpret_cast::type *>(cObject)->cppPtr; + BaseType *cppObject = reinterpret_cast *>(cObject)->cppPtr; if (!cppObject) abort("Cpp Object is null."); @@ -266,22 +239,20 @@ public: return derivedCppObject; #else - return reinterpret_cast::type *>(cObject)->cppPtr; + return reinterpret_cast *>(cObject)->cppPtr; #endif } template< typename CType, typename CppType = typename CTypeMetaInfo::cppType, - typename = typename std::enable_if< - IsDefinedBaseCppObject::value || IsDefinedClonableCppObject::value, CppType - >::type + typename = typename std::enable_if::value, CppType>::type > static L_INTERNAL_WRAPPER_CONSTEXPR const CppType *getCppPtrFromC (const CType *cObject) { #ifdef DEBUG return getCppPtrFromC(const_cast(cObject)); #else - return reinterpret_cast::type *>(cObject)->cppPtr; + return reinterpret_cast *>(cObject)->cppPtr; #endif } @@ -292,22 +263,20 @@ public: template< typename CType, typename CppType = typename CTypeMetaInfo::cppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static inline void setCppPtrFromC (CType *cObject, const std::shared_ptr &cppObject) { - reinterpret_cast *>(cObject)->cppPtr = cppObject; + reinterpret_cast *>(cObject)->cppPtr = cppObject; cppObject->setCBackPtr(cObject); } template< typename CType, typename CppType = typename CTypeMetaInfo::cppType, - typename = typename std::enable_if< - IsDefinedBaseCppObject::value || IsDefinedClonableCppObject::value, CppType - >::type + typename = typename std::enable_if::value, CppType>::type > static inline void setCppPtrFromC (CType *cObject, CppType* &&cppObject) { - CppType **cppObjectAddr = &reinterpret_cast::type *>(cObject)->cppPtr; + CppType **cppObjectAddr = &reinterpret_cast *>(cObject)->cppPtr; if (*cppObjectAddr == cppObject) return; delete *cppObjectAddr; @@ -322,13 +291,7 @@ public: typename = typename std::enable_if::value, CppType>::type > static inline void setCppPtrFromC (CType *cObject, const CppType *cppObject) { - CppType **cppObjectAddr = &reinterpret_cast *>(cObject)->cppPtr; - if (*cppObjectAddr == cppObject) - return; - delete *cppObjectAddr; - - *cppObjectAddr = new CppType(*cppObject); - (*cppObjectAddr)->setCBackPtr(cObject); + setCppPtrFromC(cObject, new CppType(*cppObject)); } // --------------------------------------------------------------------------- @@ -337,17 +300,7 @@ public: template< typename CppType, - typename = typename std::enable_if::value>::type - > - static inline CppType * &&getResolvedCppPtr (const CppType *cppObject) { - // Exists only for `getCBackPtr` impl. - abort("Cannot get resolved cpp ptr from BaseObject."); - return std::move(const_cast(cppObject)); - } - - template< - typename CppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static inline std::shared_ptr getResolvedCppPtr (const CppType *cppObject) { if (L_UNLIKELY(!cppObject)) @@ -377,7 +330,9 @@ public: template< typename CppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if< + IsDefinedCppObject::value || IsDefinedClonableCppObject::value, CppType + >::type > static inline typename CppTypeMetaInfo::cType *getCBackPtr (const CppType *cppObject) { if (L_UNLIKELY(!cppObject)) @@ -386,7 +341,7 @@ public: typedef typename CppTypeMetaInfo::cType RetType; void *value = cppObject->getCBackPtr(); - if (value || IsDefinedBaseCppObject::value) + if (value) return static_cast(value); RetType *cObject = CppTypeMetaInfo::init(); @@ -397,6 +352,27 @@ public: return cObject; } + template< + typename CppType, + typename = typename std::enable_if::value, CppType>::type + > + static inline typename CppTypeMetaInfo::cType *getCBackPtr (const std::shared_ptr &cppObject) { + if (L_UNLIKELY(!cppObject)) + return nullptr; + + typedef typename CppTypeMetaInfo::cType RetType; + + void *value = cppObject->getCBackPtr(); + if (value) + return static_cast(value); + + RetType *cObject = CppTypeMetaInfo::init(); + + setCppPtrFromC(cObject, cppObject); + + return cObject; + } + // --------------------------------------------------------------------------- // Get/set user data. // --------------------------------------------------------------------------- @@ -442,7 +418,7 @@ public: static inline bctbx_list_t *getResolvedCListFromCppList (const std::list> &cppList) { bctbx_list_t *result = nullptr; for (const auto &value : cppList) { - result = bctbx_list_append(result, belle_sip_object_ref(getCBackPtr(value.get()))); + result = bctbx_list_append(result, belle_sip_object_ref(getCBackPtr(value))); } return result; } @@ -573,30 +549,6 @@ LINPHONE_END_NAMESPACE // C object declaration. // ----------------------------------------------------------------------------- -// Declare base wrapped C object. -#define L_DECLARE_C_BASE_OBJECT_IMPL(C_TYPE, ...) \ - static_assert(LinphonePrivate::CTypeMetaInfo::defined, "Type is not defined."); \ - struct _Linphone ## C_TYPE { \ - belle_sip_object_t base; \ - L_CPP_TYPE_OF_C_TYPE(C_TYPE) *cppPtr; \ - __VA_ARGS__ \ - }; \ - BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_TYPE); \ - Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init() { \ - return belle_sip_object_new(Linphone ## C_TYPE); \ - } \ - static void _linphone_ ## C_TYPE ## _uninit(Linphone ## C_TYPE * object) { \ - delete object->cppPtr; \ - } \ - BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## C_TYPE); \ - BELLE_SIP_INSTANCIATE_VPTR( \ - Linphone ## C_TYPE, belle_sip_object_t, \ - _linphone_ ## C_TYPE ## _uninit, \ - NULL, \ - NULL, \ - FALSE \ - ); - // Declare wrapped C object with constructor/destructor. #define L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(C_TYPE, CONSTRUCTOR, DESTRUCTOR, ...) \ struct _Linphone ## C_TYPE { \ @@ -700,7 +652,7 @@ LINPHONE_END_NAMESPACE // Get the wrapped C object of a C++ object. #define L_GET_C_BACK_PTR(CPP_OBJECT) \ - LinphonePrivate::Wrapper::getCBackPtr(LinphonePrivate::Utils::getPtr(CPP_OBJECT)) + LinphonePrivate::Wrapper::getCBackPtr(CPP_OBJECT) // Get/set user data on a wrapped C object. #define L_GET_USER_DATA_FROM_C_OBJECT(C_OBJECT) \ diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 1d51e386e..6d8b6ede5 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -276,7 +276,7 @@ void ClientGroupChatRoom::onParticipantAdded (time_t tm, const Address &addr) { LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAddedCb cb = linphone_chat_room_cbs_get_participant_added(cbs); - const ConferenceParticipantEvent event( + shared_ptr event = make_shared( EventLog::Type::ConferenceParticipantAdded, tm, dConference->conferenceAddress, @@ -286,7 +286,7 @@ void ClientGroupChatRoom::onParticipantAdded (time_t tm, const Address &addr) { Conference::getCore()->cppCore.getPrivate()->mainDb.addEvent(event); if (cb) - cb(cr, L_GET_C_BACK_PTR(&event)); + cb(cr, L_GET_C_BACK_PTR(event)); } void ClientGroupChatRoom::onParticipantRemoved (time_t tm, const Address &addr) { @@ -301,7 +301,7 @@ void ClientGroupChatRoom::onParticipantRemoved (time_t tm, const Address &addr) LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantRemovedCb cb = linphone_chat_room_cbs_get_participant_removed(cbs); - const ConferenceParticipantEvent event( + shared_ptr event = make_shared( EventLog::Type::ConferenceParticipantRemoved, tm, dConference->conferenceAddress, @@ -311,7 +311,7 @@ void ClientGroupChatRoom::onParticipantRemoved (time_t tm, const Address &addr) Conference::getCore()->cppCore.getPrivate()->mainDb.addEvent(event); if (cb) - cb(cr, L_GET_C_BACK_PTR(&event)); + cb(cr, L_GET_C_BACK_PTR(event)); dConference->participants.remove(participant); } @@ -332,7 +332,7 @@ void ClientGroupChatRoom::onParticipantSetAdmin (time_t tm, const Address &addr, LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAdminStatusChangedCb cb = linphone_chat_room_cbs_get_participant_admin_status_changed(cbs); - const ConferenceParticipantEvent event( + shared_ptr event = make_shared( isAdmin ? EventLog::Type::ConferenceParticipantSetAdmin : EventLog::Type::ConferenceParticipantUnsetAdmin, tm, dConference->conferenceAddress, @@ -342,7 +342,7 @@ void ClientGroupChatRoom::onParticipantSetAdmin (time_t tm, const Address &addr, Conference::getCore()->cppCore.getPrivate()->mainDb.addEvent(event); if (cb) - cb(cr, L_GET_C_BACK_PTR(&event)); + cb(cr, L_GET_C_BACK_PTR(event)); } void ClientGroupChatRoom::onSubjectChanged (time_t tm, const std::string &subject) { @@ -351,7 +351,7 @@ void ClientGroupChatRoom::onSubjectChanged (time_t tm, const std::string &subjec LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsSubjectChangedCb cb = linphone_chat_room_cbs_get_subject_changed(cbs); - const ConferenceSubjectEvent event( + shared_ptr event = make_shared( tm, dConference->conferenceAddress, dConference->eventHandler->getLastNotify(), @@ -360,7 +360,7 @@ void ClientGroupChatRoom::onSubjectChanged (time_t tm, const std::string &subjec Conference::getCore()->cppCore.getPrivate()->mainDb.addEvent(event); if (cb) - cb(cr, L_GET_C_BACK_PTR(&event)); + cb(cr, L_GET_C_BACK_PTR(event)); } void ClientGroupChatRoom::onParticipantDeviceAdded (time_t tm, const Address &addr, const Address &gruu) { @@ -378,7 +378,7 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (time_t tm, const Address &ad LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantDeviceAddedCb cb = linphone_chat_room_cbs_get_participant_device_added(cbs); - const ConferenceParticipantDeviceEvent event( + shared_ptr event = make_shared( EventLog::Type::ConferenceParticipantDeviceAdded, tm, dConference->conferenceAddress, @@ -389,7 +389,7 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (time_t tm, const Address &ad Conference::getCore()->cppCore.getPrivate()->mainDb.addEvent(event); if (cb) - cb(cr, L_GET_C_BACK_PTR(&event)); + cb(cr, L_GET_C_BACK_PTR(event)); } void ClientGroupChatRoom::onParticipantDeviceRemoved (time_t tm, const Address &addr, const Address &gruu) { @@ -407,7 +407,7 @@ void ClientGroupChatRoom::onParticipantDeviceRemoved (time_t tm, const Address & LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantDeviceRemovedCb cb = linphone_chat_room_cbs_get_participant_device_removed(cbs); - const ConferenceParticipantDeviceEvent event( + shared_ptr event = make_shared( EventLog::Type::ConferenceParticipantDeviceRemoved, tm, dConference->conferenceAddress, @@ -418,7 +418,7 @@ void ClientGroupChatRoom::onParticipantDeviceRemoved (time_t tm, const Address & Conference::getCore()->cppCore.getPrivate()->mainDb.addEvent(event); if (cb) - cb(cr, L_GET_C_BACK_PTR(&event)); + cb(cr, L_GET_C_BACK_PTR(event)); } // ----------------------------------------------------------------------------- diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index b026c59f8..9f916d47c 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -99,14 +99,14 @@ private: const std::string &peerAddress ) const; - long long insertEvent (const EventLog &eventLog); - long long insertConferenceEvent (const EventLog &eventLog, long long *chatRoomId = nullptr); - long long insertConferenceCallEvent (const EventLog &eventLog); - long long insertConferenceChatMessageEvent (const EventLog &eventLog); - long long insertConferenceNotifiedEvent (const EventLog &eventLog); - long long insertConferenceParticipantEvent (const EventLog &eventLog); - long long insertConferenceParticipantDeviceEvent (const EventLog &eventLog); - long long insertConferenceSubjectEvent (const EventLog &eventLog); + long long insertEvent (const std::shared_ptr &eventLog); + long long insertConferenceEvent (const std::shared_ptr &eventLog, long long *chatRoomId = nullptr); + long long insertConferenceCallEvent (const std::shared_ptr &eventLog); + long long insertConferenceChatMessageEvent (const std::shared_ptr &eventLog); + long long insertConferenceNotifiedEvent (const std::shared_ptr &eventLog); + long long insertConferenceParticipantEvent (const std::shared_ptr &eventLog); + long long insertConferenceParticipantDeviceEvent (const std::shared_ptr &eventLog); + long long insertConferenceSubjectEvent (const std::shared_ptr &eventLog); L_DECLARE_PUBLIC(MainDb); }; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 07df094ae..7adbc9075 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -366,19 +366,19 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} // ----------------------------------------------------------------------------- - long long MainDbPrivate::insertEvent (const EventLog &eventLog) { + long long MainDbPrivate::insertEvent (const shared_ptr &eventLog) { L_Q(); soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO event (type, date) VALUES (:type, :date)", - soci::use(static_cast(eventLog.getType())), soci::use(Utils::getLongAsTm(eventLog.getTime())); + soci::use(static_cast(eventLog->getType())), soci::use(Utils::getLongAsTm(eventLog->getTime())); return q->getLastInsertId(); } - long long MainDbPrivate::insertConferenceEvent (const EventLog &eventLog, long long *chatRoomId) { + long long MainDbPrivate::insertConferenceEvent (const shared_ptr &eventLog, long long *chatRoomId) { long long eventId = insertEvent(eventLog); long long curChatRoomId = insertSipAddress( - static_cast(eventLog).getConferenceAddress().asString() + static_pointer_cast(eventLog)->getConferenceAddress().asString() ); soci::session *session = dbSession.getBackendSession(); @@ -391,20 +391,20 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return eventId; } - long long MainDbPrivate::insertConferenceCallEvent (const EventLog &eventLog) { + long long MainDbPrivate::insertConferenceCallEvent (const shared_ptr &eventLog) { // TODO. return 0; } - long long MainDbPrivate::insertConferenceChatMessageEvent (const EventLog &eventLog) { - shared_ptr chatMessage = static_cast(eventLog).getChatMessage(); + long long MainDbPrivate::insertConferenceChatMessageEvent (const shared_ptr &eventLog) { + shared_ptr chatMessage = static_pointer_cast(eventLog)->getChatMessage(); shared_ptr chatRoom = chatMessage->getChatRoom(); if (!chatRoom) { lError() << "Unable to get a valid chat room. It was removed from database."; return -1; } - tm eventTime = Utils::getLongAsTm(static_cast(eventLog.getTime())); + tm eventTime = Utils::getLongAsTm(static_cast(eventLog->getTime())); long long localSipAddressId = insertSipAddress(chatMessage->getLocalAddress().asString()); long long remoteSipAddressId = insertSipAddress(chatMessage->getRemoteAddress().asString()); @@ -429,10 +429,10 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return eventId; } - long long MainDbPrivate::insertConferenceNotifiedEvent (const EventLog &eventLog) { + long long MainDbPrivate::insertConferenceNotifiedEvent (const shared_ptr &eventLog) { long long chatRoomId; long long eventId = insertConferenceEvent(eventLog, &chatRoomId); - unsigned int lastNotifyId = static_cast(eventLog).getNotifyId(); + unsigned int lastNotifyId = static_pointer_cast(eventLog)->getNotifyId(); soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_notified_event (event_id, notify_id)" @@ -443,10 +443,10 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return eventId; } - long long MainDbPrivate::insertConferenceParticipantEvent (const EventLog &eventLog) { + long long MainDbPrivate::insertConferenceParticipantEvent (const shared_ptr &eventLog) { long long eventId = insertConferenceNotifiedEvent(eventLog); long long participantAddressId = insertSipAddress( - static_cast(eventLog).getParticipantAddress().asString() + static_pointer_cast(eventLog)->getParticipantAddress().asString() ); soci::session *session = dbSession.getBackendSession(); @@ -456,10 +456,10 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return eventId; } - long long MainDbPrivate::insertConferenceParticipantDeviceEvent (const EventLog &eventLog) { + long long MainDbPrivate::insertConferenceParticipantDeviceEvent (const shared_ptr &eventLog) { long long eventId = insertConferenceParticipantEvent(eventLog); long long gruuAddressId = insertSipAddress( - static_cast(eventLog).getGruuAddress().asString() + static_pointer_cast(eventLog)->getGruuAddress().asString() ); soci::session *session = dbSession.getBackendSession(); @@ -469,13 +469,13 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return eventId; } - long long MainDbPrivate::insertConferenceSubjectEvent (const EventLog &eventLog) { + long long MainDbPrivate::insertConferenceSubjectEvent (const shared_ptr &eventLog) { long long eventId = insertConferenceNotifiedEvent(eventLog); soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_subject_event (event_id, subject)" " VALUES (:eventId, :subject)", soci::use(eventId), soci::use( - static_cast(eventLog).getSubject() + static_pointer_cast(eventLog)->getSubject() ); return eventId; @@ -716,7 +716,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} *session << participantMessageDeleter; } - bool MainDb::addEvent (const EventLog &eventLog) { + bool MainDb::addEvent (const shared_ptr &eventLog) { L_D(); if (!isConnected()) { @@ -730,7 +730,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} soci::transaction tr(*d->dbSession.getBackendSession()); - switch (eventLog.getType()) { + switch (eventLog->getType()) { case EventLog::Type::None: return false; @@ -774,7 +774,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return soFarSoGood; } - bool MainDb::deleteEvent (const EventLog &eventLog) { + bool MainDb::deleteEvent (const shared_ptr &eventLog) { L_D(); if (!isConnected()) { @@ -782,7 +782,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} return false; } - long long &storageId = const_cast(eventLog).getPrivate()->storageId; + long long &storageId = eventLog->getPrivate()->storageId; if (storageId < 0) return false; diff --git a/src/db/main-db.h b/src/db/main-db.h index 08531f11d..1d22ba3a5 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -48,8 +48,8 @@ public: MainDb (); // Generic. - bool addEvent (const EventLog &eventLog); - bool deleteEvent (const EventLog &eventLog); + bool addEvent (const std::shared_ptr &eventLog); + bool deleteEvent (const std::shared_ptr &eventLog); void cleanEvents (FilterMask mask = NoFilter); int getEventsCount (FilterMask mask = NoFilter) const; diff --git a/src/event-log/event-log.h b/src/event-log/event-log.h index 3134421e8..98acbe238 100644 --- a/src/event-log/event-log.h +++ b/src/event-log/event-log.h @@ -21,6 +21,7 @@ #define _EVENT_LOG_H_ #include +#include #include "linphone/enums/event-log-enums.h" #include "linphone/utils/enum-generator.h" diff --git a/src/object/base-object.h b/src/object/base-object.h index 49d219f4a..b19ff3a6d 100644 --- a/src/object/base-object.h +++ b/src/object/base-object.h @@ -31,7 +31,7 @@ LINPHONE_BEGIN_NAMESPACE class BaseObjectPrivate; /* - * Base Object of Linphone. Cannot be cloned. Cannot be Shared. + * Base Object of Linphone. Cannot be cloned. Can be Shared. * It's the base class of Object. It's useful for lightweight entities * like Events. */ diff --git a/src/object/object.h b/src/object/object.h index 910d0bcb3..0721cc0ef 100644 --- a/src/object/object.h +++ b/src/object/object.h @@ -31,6 +31,7 @@ LINPHONE_BEGIN_NAMESPACE /* * Main Object of Linphone. Can be shared but is not Clonable. + * Supports properties and shared from this. * Must be built with ObjectFactory. */ class LINPHONE_PUBLIC Object : public BaseObject, public PropertyContainer { From 942b3aac4796fed613a4cb43c82ef528ea1f2613 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 24 Oct 2017 11:21:30 +0200 Subject: [PATCH 0610/2215] fix(c-types): sort --- include/linphone/api/c-types.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index 6eb782d4d..c7d4488c8 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -128,12 +128,12 @@ typedef struct _LinphoneDialPlan LinphoneDialPlan; // ----------------------------------------------------------------------------- typedef struct _LinphoneCallEvent LinphoneCallEvent; +typedef struct _LinphoneConferenceChatMessageEvent LinphoneConferenceChatMessageEvent; typedef struct _LinphoneConferenceEvent LinphoneConferenceEvent; -typedef struct _LinphoneConferenceParticipantEvent LinphoneConferenceParticipantEvent; typedef struct _LinphoneConferenceParticipantDeviceEvent LinphoneConferenceParticipantDeviceEvent; +typedef struct _LinphoneConferenceParticipantEvent LinphoneConferenceParticipantEvent; typedef struct _LinphoneConferenceSubjectEvent LinphoneConferenceSubjectEvent; typedef struct _LinphoneEventLog LinphoneEventLog; -typedef struct _LinphoneConferenceChatMessageEvent LinphoneConferenceChatMessageEvent; // ============================================================================= // C Enums. From 16d229224cd696d8b2f40dba3ea95af2d7d6a062 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 24 Oct 2017 11:42:16 +0200 Subject: [PATCH 0611/2215] fix(c-types): add doc --- include/linphone/api/c-types.h | 123 ++++++++++++++++++++++++++------- 1 file changed, 98 insertions(+), 25 deletions(-) diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index c7d4488c8..ec95bf661 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -53,6 +53,10 @@ // C Structures. // ============================================================================= +// ----------------------------------------------------------------------------- +// Address. +// ----------------------------------------------------------------------------- + /** * Object that represents a SIP address. * @@ -67,6 +71,10 @@ */ typedef struct _LinphoneAddress LinphoneAddress; +// ----------------------------------------------------------------------------- +// Call. +// ----------------------------------------------------------------------------- + /** * The LinphoneCall object represents a call issued or received by the LinphoneCore * @ingroup call_control @@ -86,18 +94,9 @@ typedef void (*LinphoneCallCbFunc) (LinphoneCall *call, void *ud); */ typedef struct _LinphoneCallCbs LinphoneCallCbs; -/** - * A chat room is the place where text messages are exchanged. - * Can be created by linphone_core_create_chat_room(). - * @ingroup chatroom - */ -typedef struct _LinphoneChatRoom LinphoneChatRoom; - -/** - * An object to handle the callbacks for the handling a LinphoneChatRoom objects. - * @ingroup chatroom - */ -typedef struct _LinphoneChatRoomCbs LinphoneChatRoomCbs; +// ----------------------------------------------------------------------------- +// ChatRoom. +// ----------------------------------------------------------------------------- /** * An chat message is the object that is sent and received through LinphoneChatRooms. @@ -112,38 +111,93 @@ typedef struct _LinphoneChatMessage LinphoneChatMessage; typedef struct _LinphoneChatMessageCbs LinphoneChatMessageCbs; /** -* The LinphoneParticipant object represents a participant of a conference. -* @ingroup misc -**/ -typedef struct _LinphoneParticipant LinphoneParticipant; + * A chat room is the place where text messages are exchanged. + * Can be created by linphone_core_create_chat_room(). + * @ingroup chatroom + */ +typedef struct _LinphoneChatRoom LinphoneChatRoom; /** -* Represents a dial plan -* @ingroup misc -**/ -typedef struct _LinphoneDialPlan LinphoneDialPlan; + * An object to handle the callbacks for the handling a LinphoneChatRoom objects. + * @ingroup chatroom + */ +typedef struct _LinphoneChatRoomCbs LinphoneChatRoomCbs; // ----------------------------------------------------------------------------- // EventLog. // ----------------------------------------------------------------------------- +/** + * Call start/end events. + * @ingroup events + */ typedef struct _LinphoneCallEvent LinphoneCallEvent; + +/** + * Chat message event. + * @ingroup events + */ typedef struct _LinphoneConferenceChatMessageEvent LinphoneConferenceChatMessageEvent; + +/** + * Conference created/destroyed events. + * @ingroup events + */ typedef struct _LinphoneConferenceEvent LinphoneConferenceEvent; + +/** + * Conference notified event. + * @ingroup events + */ +typedef struct _LinphoneConferenceNotifiedEvent LinphoneConferenceNotifiedEvent; + +/** + * Conference participant device added/removed events. + * @ingroup events + */ typedef struct _LinphoneConferenceParticipantDeviceEvent LinphoneConferenceParticipantDeviceEvent; + +/** + * Conference participant added/removed & set/unset admin events. + * @ingroup events + */ typedef struct _LinphoneConferenceParticipantEvent LinphoneConferenceParticipantEvent; + +/** + * Conference subject changed event. + * @ingroup events + */ typedef struct _LinphoneConferenceSubjectEvent LinphoneConferenceSubjectEvent; + +/** + * Base object of events. + * @ingroup events + */ typedef struct _LinphoneEventLog LinphoneEventLog; +// ----------------------------------------------------------------------------- +// Misc. +// ----------------------------------------------------------------------------- + +/** + * Represents a dial plan + * @ingroup misc +**/ +typedef struct _LinphoneDialPlan LinphoneDialPlan; + +/** + * The LinphoneParticipant object represents a participant of a conference. + * @ingroup misc +**/ +typedef struct _LinphoneParticipant LinphoneParticipant; + // ============================================================================= // C Enums. // ============================================================================= -/** - * LinphoneChatMessageState is used to notify if messages have been succesfully delivered or not. - * @ingroup chatroom - */ -L_DECLARE_C_ENUM(ChatMessageState, L_ENUM_VALUES_CHAT_MESSAGE_STATE); +// ----------------------------------------------------------------------------- +// ChatRoom. +// ----------------------------------------------------------------------------- /** * LinphoneChatMessageDirection is used to indicate if a message is outgoing or incoming. @@ -151,7 +205,26 @@ L_DECLARE_C_ENUM(ChatMessageState, L_ENUM_VALUES_CHAT_MESSAGE_STATE); */ L_DECLARE_C_ENUM(ChatMessageDirection, L_ENUM_VALUES_CHAT_MESSAGE_DIRECTION); +/** + * LinphoneChatMessageState is used to notify if messages have been succesfully delivered or not. + * @ingroup chatroom +*/ +L_DECLARE_C_ENUM(ChatMessageState, L_ENUM_VALUES_CHAT_MESSAGE_STATE); + +/** + * LinphoneChatRoomState is used to indicate the current state of a chat room. + * @ingroup chatroom + */ L_DECLARE_C_ENUM(ChatRoomState, L_ENUM_VALUES_CHAT_ROOM_STATE); + +// ----------------------------------------------------------------------------- +// EventLog. +// ----------------------------------------------------------------------------- + +/** + * LinphoneEventLogType is used to indicate the type of an event. Useful for cast. + * @ingroup chatroom + */ L_DECLARE_C_ENUM(EventLogType, L_ENUM_VALUES_EVENT_LOG_TYPE); #ifdef __cplusplus From 3e54de8d6a781d615de65381c4c67ba9fedecab6 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 24 Oct 2017 11:55:08 +0200 Subject: [PATCH 0612/2215] fix(MainDb): fix compil when soci is not used --- src/db/main-db.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 7adbc9075..d580b9993 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1202,11 +1202,11 @@ shared_ptr MainDb::findChatRoom (const string &peerAddress) const { void MainDb::init () {} - bool MainDb::addEvent (const EventLog &) { + bool MainDb::addEvent (const shared_ptr &) { return false; } - bool MainDb::deleteEvent (const EventLog &) { + bool MainDb::deleteEvent (const shared_ptr &) { return false; } From 65d61523e0d79e0403eb398ed1490f24db8cc898 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 24 Oct 2017 12:04:12 +0200 Subject: [PATCH 0613/2215] fix(c-wrapper): add missing ConferenceNotifiedEvent --- src/c-wrapper/c-wrapper.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index c1b5698e9..7f7ebcb8e 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -39,6 +39,7 @@ F(ChatRoom, ChatRoom) \ F(ConferenceChatMessageEvent, ConferenceChatMessageEvent) \ F(ConferenceEvent, ConferenceEvent) \ + F(ConferenceNotifiedEvent, ConferenceNotifiedEvent) \ F(ConferenceParticipantDeviceEvent, ConferenceParticipantDeviceEvent) \ F(ConferenceParticipantEvent, ConferenceParticipantEvent) \ F(ConferenceSubjectEvent, ConferenceSubjectEvent) \ From d15d7dfc52041ee6e983e677735542cbeb63f5a8 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 24 Oct 2017 14:07:05 +0200 Subject: [PATCH 0614/2215] Put ChatRoomState into ChatRoom --- wrappers/java/genwrapper.py | 1 + 1 file changed, 1 insertion(+) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 46fa2138e..dfa46c236 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -46,6 +46,7 @@ ENUMS_LIST = { 'CallDir': 'Call', 'CallState': 'Call', 'CallStatus': 'CallLog', + 'ChatRoomState': 'ChatRoom', 'ChatMessageState': 'ChatMessage', 'ConfiguringState': 'Core', 'CoreLogCollectionUploadState': 'Core', From 8aa93022dd29dcc73a2ba0a29b256568cb7a3f44 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 24 Oct 2017 14:16:54 +0200 Subject: [PATCH 0615/2215] Added back wrapper_utils include in dial-plan --- src/c-wrapper/api/c-dial-plan.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/c-wrapper/api/c-dial-plan.cpp b/src/c-wrapper/api/c-dial-plan.cpp index 534d0d417..7dc7ef030 100644 --- a/src/c-wrapper/api/c-dial-plan.cpp +++ b/src/c-wrapper/api/c-dial-plan.cpp @@ -18,6 +18,7 @@ */ #include "linphone/api/c-dial-plan.h" +#include "linphone/wrapper_utils.h" #include "c-wrapper/c-wrapper.h" #include "dial-plan/dial-plan.h" From 9bfaca593efc41ea26af7af201c00ac8fc48cdb0 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 24 Oct 2017 14:37:28 +0200 Subject: [PATCH 0616/2215] Add EventLogType as enum of EventLog --- wrappers/java/genwrapper.py | 1 + 1 file changed, 1 insertion(+) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index dfa46c236..8614e901a 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -51,6 +51,7 @@ ENUMS_LIST = { 'ConfiguringState': 'Core', 'CoreLogCollectionUploadState': 'Core', 'EcCalibratorStatus': 'Core', + 'EventLogType': 'EventLog', 'GlobalState': 'Core', 'FriendListStatus': 'FriendList', 'IceState': 'CallStats', From 0442a244c000f4050da1dc9c4ce30ca437135fc2 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 24 Oct 2017 14:46:11 +0200 Subject: [PATCH 0617/2215] More enums added to parent classes --- wrappers/java/genwrapper.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 8614e901a..a86e3995b 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -42,27 +42,38 @@ ENUMS_LIST = { 'AccountCreatorTransportStatus': 'AccountCreator', 'AccountCreatorUsernameStatus': 'AccountCreator', 'AddressFamily': 'CallStats', + 'AudioRoute': 'Call', 'AuthMethod': 'Core', 'CallDir': 'Call', 'CallState': 'Call', 'CallStatus': 'CallLog', 'ChatRoomState': 'ChatRoom', + 'ChatMessageDirection': 'ChatMessage', 'ChatMessageState': 'ChatMessage', 'ConfiguringState': 'Core', + 'ConsolidatedPresence': 'PresenceModel', 'CoreLogCollectionUploadState': 'Core', 'EcCalibratorStatus': 'Core', 'EventLogType': 'EventLog', 'GlobalState': 'Core', 'FriendListStatus': 'FriendList', + 'FriendListSyncStatus': 'FriendList', 'IceState': 'CallStats', 'LimeState': 'Core', + 'LogCollectionState': 'Core', 'MediaDirection': 'Core', 'MediaEncryption': 'Core', 'PlayerState': 'Player', + 'PresenceActivityType': 'PresenceActivity', + 'PublishState': 'Event', 'RegistrationState': 'Core', + 'StreamType': 'CallStats', + 'SubscriptionDir': 'Event', 'SubscribePolicy': 'Friend', 'TransportType': 'Address', 'TunnelMode': 'Tunnel', + 'UpnpState': 'Core', + 'VersionUpdateCheckResult': 'Core', 'XmlRpcRequestArgType': 'XmlRpcRequest', 'XmlRpcRequestStatus': 'XmlRpcRequest', } From 40b8e7b6fc8772c1b953bc5a342cc31eff55b704 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 24 Oct 2017 14:50:27 +0200 Subject: [PATCH 0618/2215] feat(c-event-log): add docs and functions proto --- include/linphone/api/c-event-log.h | 159 ++++++++++++++++++++++++++--- include/linphone/api/c-types.h | 2 +- src/event-log/call/call-event.h | 2 +- tools/abstractapi.py | 3 +- 4 files changed, 149 insertions(+), 17 deletions(-) diff --git a/include/linphone/api/c-event-log.h b/include/linphone/api/c-event-log.h index 6450e24c2..2e09a8f2f 100644 --- a/include/linphone/api/c-event-log.h +++ b/include/linphone/api/c-event-log.h @@ -28,44 +28,177 @@ extern "C" { #endif // ifdef __cplusplus +/** + * @addtogroup events + * @{ + */ + +// ----------------------------------------------------------------------------- +// EventLog. +// ----------------------------------------------------------------------------- + LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_new (void); LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_ref (LinphoneEventLog *event_log); +LINPHONE_PUBLIC void linphone_event_log_unref (LinphoneEventLog *event_log); + +/** + * Returns the type of a event log. + * @param[in] event_log A EventLog object + * @return The event type + */ LINPHONE_PUBLIC LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *event_log); +/** + * Returns the time of a event log. + * @param[in] event_log A EventLog object + * @return The event time + */ +LINPHONE_PUBLIC time_t linphone_event_log_get_time (const LinphoneEventLog *event_log); + +// ----------------------------------------------------------------------------- +// ConferenceEvent. +// ----------------------------------------------------------------------------- + +LINPHONE_PUBLIC LinphoneConferenceEvent *linphone_conference_event_new ( + LinphoneEventLogType type, + time_t time, + const LinphoneAddress *conference_address +); + +/** + * Returns the conference address of a conference event. + * @param[in] conference_event A ConferenceEvent object + * @return The conference address + */ +LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_event_get_conference_address ( + const LinphoneConferenceEvent *conference_event +); + +// ----------------------------------------------------------------------------- +// ConferenceNotifiedEvent. +// ----------------------------------------------------------------------------- + +LINPHONE_PUBLIC LinphoneConferenceNotifiedEvent *linphone_conference_notified_event_new ( + LinphoneEventLogType type, + time_t time, + const LinphoneAddress *conference_address, + unsigned int notify_id +); + +/** + * Returns the notify id of a conference notified event. + * @param[in] conference_notified_event A ConferenceNotifiedEvent object + * @return The conference notify id + */ +LINPHONE_PUBLIC unsigned int linphone_conference_event_get_notify_id ( + const LinphoneConferenceNotifiedEvent *conference_notified_event +); + +// ----------------------------------------------------------------------------- +// CallEvent. +// ----------------------------------------------------------------------------- + LINPHONE_PUBLIC LinphoneCallEvent *linphone_call_event_new ( LinphoneEventLogType type, time_t time, LinphoneCall *call ); + +/** + * Returns the call of a conference call event. + * @param[in] conference_call_event A ConferenceCallEvent object + * @return The conference call + */ LINPHONE_PUBLIC LinphoneCall *linphone_call_event_get_call (const LinphoneCallEvent *call_event); -LINPHONE_PUBLIC LinphoneConferenceEvent *linphone_conference_event_new ( - LinphoneEventLogType type, +// ----------------------------------------------------------------------------- +// ConferenceChatMessageEvent. +// ----------------------------------------------------------------------------- + +LINPHONE_PUBLIC LinphoneConferenceChatMessageEvent *linphone_conference_chat_message_event_new ( time_t time, - const LinphoneAddress *address + LinphoneChatMessage *chat_message ); -LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_event_get_address (const LinphoneConferenceEvent *conference_event); + +/** + * Returns the chat message of a conference chat message event. + * @param[in] conference_chat_message_event A ConferenceChatMessageEvent object + * @return The conference chat message + */ +LINPHONE_PUBLIC LinphoneChatMessage *linphone_conference_chat_message_event_get_chat_message ( + const LinphoneConferenceChatMessageEvent *conference_chat_message_event +); + +// ----------------------------------------------------------------------------- +// ConferenceParticipantEvent. +// ----------------------------------------------------------------------------- LINPHONE_PUBLIC LinphoneConferenceParticipantEvent *linphone_conference_participant_event_new ( LinphoneEventLogType type, time_t time, - const LinphoneAddress *conferenceAddress, - const LinphoneAddress *participantAddress + const LinphoneAddress *conference_address, + unsigned int notify_id, + const LinphoneAddress *participant_address ); -LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_participant_event_get_participant_address ( + +/** + * Returns the participant address of a conference participant event. + * @param[in] conference_participant_event A ConferenceParticipantEvent object + * @return The conference participant address + */ +LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_participant_get_participant_address ( const LinphoneConferenceParticipantEvent *conference_participant_event ); -LINPHONE_PUBLIC LinphoneConferenceChatMessageEvent *linphone_chat_message_event_new ( - LinphoneChatMessage *chat_message, - time_t time +// ----------------------------------------------------------------------------- +// ConferenceParticipantDeviceEvent. +// ----------------------------------------------------------------------------- + +LINPHONE_PUBLIC LinphoneConferenceParticipantDeviceEvent *linphone_conference_participant_device_event_new ( + LinphoneEventLogType type, + time_t time, + const LinphoneAddress *conference_address, + unsigned int notify_id, + const LinphoneAddress *participant_address, + const LinphoneAddress *gruu_address ); -LINPHONE_PUBLIC LinphoneChatMessage *linphone_chat_message_event_get_chat_message ( - const LinphoneConferenceChatMessageEvent *chat_message_event + +/** + * Returns the gruu address of a conference participant device event. + * @param[in] conference_participant_device_event A ConferenceParticipantDeviceEvent object + * @return The conference gruu address + */ +LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_participant_device_get_gruu_address ( + const LinphoneConferenceParticipantDeviceEvent *conference_participant_device_event ); +// ----------------------------------------------------------------------------- +// ConferenceSubjectEvent. +// ----------------------------------------------------------------------------- + +LINPHONE_PUBLIC LinphoneConferenceSubjectEvent *linphone_conference_subject_event_new ( + LinphoneEventLogType type, + time_t time, + const LinphoneAddress *conference_address, + unsigned int notify_id, + const char *subject +); + +/** + * Returns the subject of a conference subject event. + * @param[in] conference_subject_event A ConferenceSubjectEvent object + * @return The conference subject + */ +LINPHONE_PUBLIC const char *linphone_conference_subject_get_subject ( + const LinphoneConferenceSubjectEvent *conference_subject_event +); + +/** + * @} + */ + #ifdef __cplusplus } -#endif +#endif // ifdef __cplusplus #endif // ifndef _C_EVENT_LOG_H_ diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index ec95bf661..4538b5976 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -223,7 +223,7 @@ L_DECLARE_C_ENUM(ChatRoomState, L_ENUM_VALUES_CHAT_ROOM_STATE); /** * LinphoneEventLogType is used to indicate the type of an event. Useful for cast. - * @ingroup chatroom + * @ingroup events */ L_DECLARE_C_ENUM(EventLogType, L_ENUM_VALUES_EVENT_LOG_TYPE); diff --git a/src/event-log/call/call-event.h b/src/event-log/call/call-event.h index 648973957..426f49a4e 100644 --- a/src/event-log/call/call-event.h +++ b/src/event-log/call/call-event.h @@ -33,7 +33,7 @@ class CallEventPrivate; class LINPHONE_PUBLIC CallEvent : public EventLog { public: - CallEvent (Type type, std::time_t time, const std::shared_ptr &message); + CallEvent (Type type, std::time_t time, const std::shared_ptr &call); std::shared_ptr getCall () const; diff --git a/tools/abstractapi.py b/tools/abstractapi.py index 51efb55bd..6ba861a96 100644 --- a/tools/abstractapi.py +++ b/tools/abstractapi.py @@ -405,7 +405,7 @@ class Class(DocumentableObject): self.classMethods = [] self._listenerInterface = None self.multilistener = False - self.refcountable = False + self.refcountable = True def add_property(self, property): self.properties.append(property) @@ -660,7 +660,6 @@ class CParser(object): name.from_camel_case(cclass.name, namespace=self.namespace.name) _class = Class(name) _class.briefDescription = cclass.briefDoc - _class.refcountable = self._class_is_refcountable(cclass) for cproperty in cclass.properties.values(): try: From 7e0834590b148301ea0d134991bad8e209bd9c5a Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 24 Oct 2017 15:24:43 +0200 Subject: [PATCH 0619/2215] feat(Events): better names, fix doc, ... --- include/linphone/api/c-event-log.h | 73 +++++++++++++------ include/linphone/api/c-types.h | 2 +- include/linphone/enums/event-log-enums.h | 4 +- src/CMakeLists.txt | 4 +- src/c-wrapper/api/c-event-log.cpp | 16 ++-- src/c-wrapper/c-wrapper.h | 2 +- src/db/main-db.cpp | 22 +++--- .../conference-call-event.cpp} | 14 ++-- .../conference-call-event.h} | 18 ++--- src/event-log/events.h | 2 +- 10 files changed, 92 insertions(+), 65 deletions(-) rename src/event-log/{call/call-event.cpp => conference/conference-call-event.cpp} (73%) rename src/event-log/{call/call-event.h => conference/conference-call-event.h} (72%) diff --git a/include/linphone/api/c-event-log.h b/include/linphone/api/c-event-log.h index 2e09a8f2f..82fe4247c 100644 --- a/include/linphone/api/c-event-log.h +++ b/include/linphone/api/c-event-log.h @@ -37,20 +37,24 @@ // EventLog. // ----------------------------------------------------------------------------- +/** + * Constructs a #LinphoneEventLog object. + **/ LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_new (void); + LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_ref (LinphoneEventLog *event_log); LINPHONE_PUBLIC void linphone_event_log_unref (LinphoneEventLog *event_log); /** * Returns the type of a event log. - * @param[in] event_log A EventLog object + * @param[in] event_log A #LinphoneEventLog object * @return The event type */ LINPHONE_PUBLIC LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *event_log); /** * Returns the time of a event log. - * @param[in] event_log A EventLog object + * @param[in] event_log A #LinphoneEventLog object * @return The event time */ LINPHONE_PUBLIC time_t linphone_event_log_get_time (const LinphoneEventLog *event_log); @@ -59,6 +63,9 @@ LINPHONE_PUBLIC time_t linphone_event_log_get_time (const LinphoneEventLog *even // ConferenceEvent. // ----------------------------------------------------------------------------- +/** + * Constructs a #LinphoneConferenceEvent object. + **/ LINPHONE_PUBLIC LinphoneConferenceEvent *linphone_conference_event_new ( LinphoneEventLogType type, time_t time, @@ -67,8 +74,8 @@ LINPHONE_PUBLIC LinphoneConferenceEvent *linphone_conference_event_new ( /** * Returns the conference address of a conference event. - * @param[in] conference_event A ConferenceEvent object - * @return The conference address + * @param[in] conference_event A #LinphoneConferenceEvent object. + * @return The conference address. */ LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_event_get_conference_address ( const LinphoneConferenceEvent *conference_event @@ -78,6 +85,9 @@ LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_event_get_conference_ // ConferenceNotifiedEvent. // ----------------------------------------------------------------------------- +/** + * Constructs a #LinphoneConferenceNotifiedEvent object. + **/ LINPHONE_PUBLIC LinphoneConferenceNotifiedEvent *linphone_conference_notified_event_new ( LinphoneEventLogType type, time_t time, @@ -87,18 +97,21 @@ LINPHONE_PUBLIC LinphoneConferenceNotifiedEvent *linphone_conference_notified_ev /** * Returns the notify id of a conference notified event. - * @param[in] conference_notified_event A ConferenceNotifiedEvent object - * @return The conference notify id + * @param[in] conference_notified_event A #LinphoneConferenceNotifiedEvent object. + * @return The conference notify id. */ -LINPHONE_PUBLIC unsigned int linphone_conference_event_get_notify_id ( +LINPHONE_PUBLIC unsigned int linphone_conference_notified_event_get_notify_id ( const LinphoneConferenceNotifiedEvent *conference_notified_event ); // ----------------------------------------------------------------------------- -// CallEvent. +// ConferenceCallEvent. // ----------------------------------------------------------------------------- -LINPHONE_PUBLIC LinphoneCallEvent *linphone_call_event_new ( +/** + * Constructs a #LinphoneConferenceCallEvent object. + **/ +LINPHONE_PUBLIC LinphoneConferenceCallEvent *linphone_conference_call_event_new ( LinphoneEventLogType type, time_t time, LinphoneCall *call @@ -106,15 +119,20 @@ LINPHONE_PUBLIC LinphoneCallEvent *linphone_call_event_new ( /** * Returns the call of a conference call event. - * @param[in] conference_call_event A ConferenceCallEvent object - * @return The conference call + * @param[in] conference_conference_call_event A #LinphoneConferenceCallEvent object. + * @return The conference call. */ -LINPHONE_PUBLIC LinphoneCall *linphone_call_event_get_call (const LinphoneCallEvent *call_event); +LINPHONE_PUBLIC LinphoneCall *linphone_conference_call_event_get_call ( + const LinphoneConferenceCallEvent *conference_call_event +); // ----------------------------------------------------------------------------- // ConferenceChatMessageEvent. // ----------------------------------------------------------------------------- +/** + * Constructs a #LinphoneConferenceChatMessageEvent object. + **/ LINPHONE_PUBLIC LinphoneConferenceChatMessageEvent *linphone_conference_chat_message_event_new ( time_t time, LinphoneChatMessage *chat_message @@ -122,8 +140,8 @@ LINPHONE_PUBLIC LinphoneConferenceChatMessageEvent *linphone_conference_chat_mes /** * Returns the chat message of a conference chat message event. - * @param[in] conference_chat_message_event A ConferenceChatMessageEvent object - * @return The conference chat message + * @param[in] conference_chat_message_event A #LinphoneConferenceChatMessageEvent object. + * @return The conference chat message. */ LINPHONE_PUBLIC LinphoneChatMessage *linphone_conference_chat_message_event_get_chat_message ( const LinphoneConferenceChatMessageEvent *conference_chat_message_event @@ -133,6 +151,9 @@ LINPHONE_PUBLIC LinphoneChatMessage *linphone_conference_chat_message_event_get_ // ConferenceParticipantEvent. // ----------------------------------------------------------------------------- +/** + * Constructs a #LinphoneConferenceParticipantEvent object. + **/ LINPHONE_PUBLIC LinphoneConferenceParticipantEvent *linphone_conference_participant_event_new ( LinphoneEventLogType type, time_t time, @@ -143,10 +164,10 @@ LINPHONE_PUBLIC LinphoneConferenceParticipantEvent *linphone_conference_particip /** * Returns the participant address of a conference participant event. - * @param[in] conference_participant_event A ConferenceParticipantEvent object - * @return The conference participant address + * @param[in] conference_participant_event A ConferenceParticipantEvent object. + * @return The conference participant address. */ -LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_participant_get_participant_address ( +LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_participant_event_get_participant_address ( const LinphoneConferenceParticipantEvent *conference_participant_event ); @@ -154,6 +175,9 @@ LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_participant_get_parti // ConferenceParticipantDeviceEvent. // ----------------------------------------------------------------------------- +/** + * Constructs a #LinphoneConferenceParticipantDeviceEvent object. + **/ LINPHONE_PUBLIC LinphoneConferenceParticipantDeviceEvent *linphone_conference_participant_device_event_new ( LinphoneEventLogType type, time_t time, @@ -165,10 +189,10 @@ LINPHONE_PUBLIC LinphoneConferenceParticipantDeviceEvent *linphone_conference_pa /** * Returns the gruu address of a conference participant device event. - * @param[in] conference_participant_device_event A ConferenceParticipantDeviceEvent object - * @return The conference gruu address + * @param[in] conference_participant_device_event A #LinphoneConferenceParticipantDeviceEvent object. + * @return The conference gruu address. */ -LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_participant_device_get_gruu_address ( +LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_participant_device_event_get_gruu_address ( const LinphoneConferenceParticipantDeviceEvent *conference_participant_device_event ); @@ -176,6 +200,9 @@ LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_participant_device_ge // ConferenceSubjectEvent. // ----------------------------------------------------------------------------- +/** + * Constructs a #LinphoneConferenceSubjectEvent object. + **/ LINPHONE_PUBLIC LinphoneConferenceSubjectEvent *linphone_conference_subject_event_new ( LinphoneEventLogType type, time_t time, @@ -186,10 +213,10 @@ LINPHONE_PUBLIC LinphoneConferenceSubjectEvent *linphone_conference_subject_even /** * Returns the subject of a conference subject event. - * @param[in] conference_subject_event A ConferenceSubjectEvent object - * @return The conference subject + * @param[in] conference_subject_event A #LinphoneConferenceSubjectEvent object. + * @return The conference subject. */ -LINPHONE_PUBLIC const char *linphone_conference_subject_get_subject ( +LINPHONE_PUBLIC const char *linphone_conference_subject_event_get_subject ( const LinphoneConferenceSubjectEvent *conference_subject_event ); diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index 4538b5976..07ac41960 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -131,7 +131,7 @@ typedef struct _LinphoneChatRoomCbs LinphoneChatRoomCbs; * Call start/end events. * @ingroup events */ -typedef struct _LinphoneCallEvent LinphoneCallEvent; +typedef struct _LinphoneConferenceCallEvent LinphoneConferenceCallEvent; /** * Chat message event. diff --git a/include/linphone/enums/event-log-enums.h b/include/linphone/enums/event-log-enums.h index e5c0c92f8..b6465b7fb 100644 --- a/include/linphone/enums/event-log-enums.h +++ b/include/linphone/enums/event-log-enums.h @@ -24,10 +24,10 @@ #define L_ENUM_VALUES_EVENT_LOG_TYPE(F) \ F(None) \ - F(CallStart) \ - F(CallEnd) \ F(ConferenceCreated) \ F(ConferenceDestroyed) \ + F(ConferenceCallStart) \ + F(ConferenceCallEnd) \ F(ConferenceChatMessage) \ F(ConferenceParticipantAdded) \ F(ConferenceParticipantRemoved) \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a861872d0..8ca281a42 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -93,7 +93,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES dial-plan/dial-plan-p.h dial-plan/dial-plan.h enums.h - event-log/call/call-event.h + event-log/conference/conference-call-event.h event-log/conference/conference-event-p.h event-log/conference/conference-event.h event-log/conference/conference-notified-event-p.h @@ -181,7 +181,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES db/session/db-session-provider.cpp db/session/db-session.cpp dial-plan/dial-plan.cpp - event-log/call/call-event.cpp + event-log/conference/conference-call-event.cpp event-log/conference/conference-chat-message-event.cpp event-log/conference/conference-event.cpp event-log/conference/conference-notified-event.cpp diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index b4af02343..94f926e07 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -27,7 +27,7 @@ // ============================================================================= -L_DECLARE_C_OBJECT_IMPL(CallEvent); +L_DECLARE_C_OBJECT_IMPL(ConferenceCallEvent); L_DECLARE_C_OBJECT_IMPL(ConferenceChatMessageEvent); L_DECLARE_C_OBJECT_IMPL(ConferenceEvent); L_DECLARE_C_OBJECT_IMPL(ConferenceParticipantDeviceEvent); @@ -62,22 +62,22 @@ LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *event_ // Call event. // ----------------------------------------------------------------------------- -LinphoneCallEvent *linphone_call_event_new (LinphoneEventLogType type, time_t time, LinphoneCall *call) { - LinphoneCallEvent *call_event = _linphone_CallEvent_init(); +LinphoneConferenceCallEvent *linphone_conference_call_event_new (LinphoneEventLogType type, time_t time, LinphoneCall *call) { + LinphoneConferenceCallEvent *conference_call_event = _linphone_ConferenceCallEvent_init(); L_SET_CPP_PTR_FROM_C_OBJECT( - call_event, - make_shared( + conference_call_event, + make_shared( static_cast(type), time, L_GET_CPP_PTR_FROM_C_OBJECT(call) ) ); - return call_event; + return conference_call_event; } -LinphoneCall *linphone_call_event_get_call (const LinphoneCallEvent *call_event) { +LinphoneCall *linphone_conference_call_event_get_call (const LinphoneConferenceCallEvent *conference_call_event) { return L_GET_C_BACK_PTR( - L_GET_CPP_PTR_FROM_C_OBJECT(call_event)->getCall() + L_GET_CPP_PTR_FROM_C_OBJECT(conference_call_event)->getCall() ); } diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index 7f7ebcb8e..1cb7063a6 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -34,9 +34,9 @@ #define L_REGISTER_TYPES(F) \ F(Address, Address) \ F(Call, Call) \ - F(CallEvent, CallEvent) \ F(ChatMessage, ChatMessage) \ F(ChatRoom, ChatRoom) \ + F(ConferenceCallEvent, ConferenceCallEvent) \ F(ConferenceChatMessageEvent, ConferenceChatMessageEvent) \ F(ConferenceEvent, ConferenceEvent) \ F(ConferenceNotifiedEvent, ConferenceNotifiedEvent) \ diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index d580b9993..732971b5a 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -219,8 +219,8 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} case EventLog::Type::ConferenceDestroyed: return selectConferenceEvent(eventId, type, date, peerAddress); - case EventLog::Type::CallStart: - case EventLog::Type::CallEnd: + case EventLog::Type::ConferenceCallStart: + case EventLog::Type::ConferenceCallEnd: return selectConferenceCallEvent(eventId, type, date, peerAddress); case EventLog::Type::ConferenceChatMessage: @@ -734,20 +734,20 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} case EventLog::Type::None: return false; - case EventLog::Type::ConferenceChatMessage: - d->insertConferenceChatMessageEvent(eventLog); - break; - - case EventLog::Type::CallStart: - case EventLog::Type::CallEnd: - d->insertConferenceCallEvent(eventLog); - break; - case EventLog::Type::ConferenceCreated: case EventLog::Type::ConferenceDestroyed: d->insertConferenceEvent(eventLog); break; + case EventLog::Type::ConferenceCallStart: + case EventLog::Type::ConferenceCallEnd: + d->insertConferenceCallEvent(eventLog); + break; + + case EventLog::Type::ConferenceChatMessage: + d->insertConferenceChatMessageEvent(eventLog); + break; + case EventLog::Type::ConferenceParticipantAdded: case EventLog::Type::ConferenceParticipantRemoved: case EventLog::Type::ConferenceParticipantSetAdmin: diff --git a/src/event-log/call/call-event.cpp b/src/event-log/conference/conference-call-event.cpp similarity index 73% rename from src/event-log/call/call-event.cpp rename to src/event-log/conference/conference-call-event.cpp index a63dcc3ad..4aea7b025 100644 --- a/src/event-log/call/call-event.cpp +++ b/src/event-log/conference/conference-call-event.cpp @@ -1,5 +1,5 @@ /* - * call-event.cpp + * conference-call-event.cpp * Copyright (C) 2010-2017 Belledonne Communications SARL * * This program is free software; you can redistribute it and/or @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "call-event.h" +#include "conference-call-event.h" #include "event-log/event-log-p.h" // ============================================================================= @@ -26,22 +26,22 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -class CallEventPrivate : public EventLogPrivate { +class ConferenceCallEventPrivate : public EventLogPrivate { public: shared_ptr call; }; // ----------------------------------------------------------------------------- -CallEvent::CallEvent (Type type, time_t time, const shared_ptr &call) : - EventLog(*new CallEventPrivate, type, time) { +ConferenceCallEvent::ConferenceCallEvent (Type type, time_t time, const shared_ptr &call) : + EventLog(*new ConferenceCallEventPrivate, type, time) { L_D(); L_ASSERT(call); - L_ASSERT(type == Type::CallStart || type == Type::CallEnd); + L_ASSERT(type == Type::ConferenceCallStart || type == Type::ConferenceCallEnd); d->call = call; } -shared_ptr CallEvent::getCall () const { +shared_ptr ConferenceCallEvent::getCall () const { L_D(); return d->call; } diff --git a/src/event-log/call/call-event.h b/src/event-log/conference/conference-call-event.h similarity index 72% rename from src/event-log/call/call-event.h rename to src/event-log/conference/conference-call-event.h index 426f49a4e..f2e58b893 100644 --- a/src/event-log/call/call-event.h +++ b/src/event-log/conference/conference-call-event.h @@ -1,5 +1,5 @@ /* - * call-event.h + * conference-call-event.h * Copyright (C) 2010-2017 Belledonne Communications SARL * * This program is free software; you can redistribute it and/or @@ -17,8 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef _CALL_EVENT_H_ -#define _CALL_EVENT_H_ +#ifndef _CONFERENCE_CALL_EVENT_H_ +#define _CONFERENCE_CALL_EVENT_H_ #include @@ -29,19 +29,19 @@ LINPHONE_BEGIN_NAMESPACE class Call; -class CallEventPrivate; +class ConferenceCallEventPrivate; -class LINPHONE_PUBLIC CallEvent : public EventLog { +class LINPHONE_PUBLIC ConferenceCallEvent : public EventLog { public: - CallEvent (Type type, std::time_t time, const std::shared_ptr &call); + ConferenceCallEvent (Type type, std::time_t time, const std::shared_ptr &call); std::shared_ptr getCall () const; private: - L_DECLARE_PRIVATE(CallEvent); - L_DISABLE_COPY(CallEvent); + L_DECLARE_PRIVATE(ConferenceCallEvent); + L_DISABLE_COPY(ConferenceCallEvent); }; LINPHONE_END_NAMESPACE -#endif // ifndef _CALL_EVENT_H_ +#endif // ifndef _CONFERENCE_CALL_EVENT_H_ diff --git a/src/event-log/events.h b/src/event-log/events.h index bc6b8bab9..2722deb8a 100644 --- a/src/event-log/events.h +++ b/src/event-log/events.h @@ -20,7 +20,7 @@ #ifndef _EVENTS_H_ #define _EVENTS_H_ -#include "call/call-event.h" +#include "conference/conference-call-event.h" #include "conference/conference-chat-message-event.h" #include "conference/conference-participant-device-event.h" #include "conference/conference-subject-event.h" From b969749cde670dd65a3448cdbe1281726812efdc Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 24 Oct 2017 16:42:25 +0200 Subject: [PATCH 0620/2215] feat(c-event-log): add impl --- include/linphone/api/c-event-log.h | 1 - src/c-wrapper/api/c-event-log.cpp | 238 ++++++++++++++++++++++------- 2 files changed, 187 insertions(+), 52 deletions(-) diff --git a/include/linphone/api/c-event-log.h b/include/linphone/api/c-event-log.h index 82fe4247c..81fd18990 100644 --- a/include/linphone/api/c-event-log.h +++ b/include/linphone/api/c-event-log.h @@ -204,7 +204,6 @@ LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_participant_device_ev * Constructs a #LinphoneConferenceSubjectEvent object. **/ LINPHONE_PUBLIC LinphoneConferenceSubjectEvent *linphone_conference_subject_event_new ( - LinphoneEventLogType type, time_t time, const LinphoneAddress *conference_address, unsigned int notify_id, diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 94f926e07..ee6625104 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -17,7 +17,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "linphone/api/c-chat-message.h" #include "linphone/api/c-event-log.h" #include "c-wrapper/c-wrapper.h" @@ -30,6 +29,7 @@ L_DECLARE_C_OBJECT_IMPL(ConferenceCallEvent); L_DECLARE_C_OBJECT_IMPL(ConferenceChatMessageEvent); L_DECLARE_C_OBJECT_IMPL(ConferenceEvent); +L_DECLARE_C_OBJECT_IMPL(ConferenceNotifiedEvent); L_DECLARE_C_OBJECT_IMPL(ConferenceParticipantDeviceEvent); L_DECLARE_C_OBJECT_IMPL(ConferenceParticipantEvent); L_DECLARE_C_OBJECT_IMPL(ConferenceSubjectEvent); @@ -38,11 +38,11 @@ L_DECLARE_C_OBJECT_IMPL(EventLog); using namespace std; // ----------------------------------------------------------------------------- -// Event log. +// EventLog. // ----------------------------------------------------------------------------- LinphoneEventLog *linphone_event_log_new () { - LinphoneEventLog *event_log = _linphone_EventLog_init(); + LinphoneEventLog *event_log = L_INIT(EventLog); L_SET_CPP_PTR_FROM_C_OBJECT(event_log, make_shared()); return event_log; } @@ -52,18 +52,88 @@ LinphoneEventLog *linphone_event_log_ref (LinphoneEventLog *event_log) { return event_log; } +void linphone_event_log_unref (LinphoneEventLog *event_log) { + belle_sip_object_unref(event_log); +} + LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *event_log) { return static_cast( L_GET_CPP_PTR_FROM_C_OBJECT(event_log)->getType() ); } +time_t linphone_event_log_get_time (const LinphoneEventLog *event_log) { + return L_GET_CPP_PTR_FROM_C_OBJECT(event_log)->getTime(); +} + // ----------------------------------------------------------------------------- -// Call event. +// ConferenceEvent. // ----------------------------------------------------------------------------- -LinphoneConferenceCallEvent *linphone_conference_call_event_new (LinphoneEventLogType type, time_t time, LinphoneCall *call) { - LinphoneConferenceCallEvent *conference_call_event = _linphone_ConferenceCallEvent_init(); +LinphoneConferenceEvent *linphone_conference_event_new ( + LinphoneEventLogType type, + time_t time, + const LinphoneAddress *conference_address +) { + LinphoneConferenceEvent *conference_event = L_INIT(ConferenceEvent); + L_SET_CPP_PTR_FROM_C_OBJECT( + conference_event, + make_shared( + static_cast(type), + time, + *L_GET_CPP_PTR_FROM_C_OBJECT(conference_address) + ) + ); + return conference_event; +} + +const LinphoneAddress *linphone_conference_event_get_conference_address ( + const LinphoneConferenceEvent *conference_event +) { + return L_GET_C_BACK_PTR( + &L_GET_CPP_PTR_FROM_C_OBJECT(conference_event)->getConferenceAddress() + ); +} + +// ----------------------------------------------------------------------------- +// ConferenceNotifiedEvent. +// ----------------------------------------------------------------------------- + +LinphoneConferenceNotifiedEvent *linphone_conference_notified_event_new ( + LinphoneEventLogType type, + time_t time, + const LinphoneAddress *conference_address, + unsigned int notify_id +) { + LinphoneConferenceNotifiedEvent *conference_notified_event = L_INIT(ConferenceNotifiedEvent); + L_SET_CPP_PTR_FROM_C_OBJECT( + conference_notified_event, + make_shared( + static_cast(type), + time, + *L_GET_CPP_PTR_FROM_C_OBJECT(conference_address), + notify_id + ) + ); + return conference_notified_event; +} + +unsigned int linphone_conference_notified_event_get_notify_id ( + const LinphoneConferenceNotifiedEvent *conference_notified_event +) { + return L_GET_CPP_PTR_FROM_C_OBJECT(conference_notified_event)->getNotifyId(); +} + +// ----------------------------------------------------------------------------- +// ConferenceCallEvent. +// ----------------------------------------------------------------------------- + +LinphoneConferenceCallEvent *linphone_conference_call_event_new ( + LinphoneEventLogType type, + time_t time, + LinphoneCall *call +) { + LinphoneConferenceCallEvent *conference_call_event = L_INIT(ConferenceCallEvent); L_SET_CPP_PTR_FROM_C_OBJECT( conference_call_event, make_shared( @@ -82,64 +152,130 @@ LinphoneCall *linphone_conference_call_event_get_call (const LinphoneConferenceC } // ----------------------------------------------------------------------------- -// Conference event. +// ConferenceChatMessageEvent. // ----------------------------------------------------------------------------- -LinphoneConferenceEvent *linphone_conference_event_new ( - LinphoneEventLogType type, +LinphoneConferenceChatMessageEvent *linphone_conference_chat_message_event_new ( time_t time, - const LinphoneAddress *address + LinphoneChatMessage *chat_message ) { - // TODO. - return nullptr; -} - -const LinphoneAddress *linphone_conference_event_get_address (const LinphoneConferenceEvent *conference_event) { - // TODO. - return nullptr; -} - -// ----------------------------------------------------------------------------- -// Conference participant event. -// ----------------------------------------------------------------------------- - -LinphoneConferenceParticipantEvent *linphone_conference_participant_event_new ( - LinphoneEventLogType type, - time_t time, - const LinphoneAddress *conferenceAddress, - const LinphoneAddress *participantAddress -) { - // TODO. - return nullptr; -} - -const LinphoneAddress *linphone_conference_participant_event_get_participant_address ( - const LinphoneConferenceParticipantEvent *conference_participant_event -) { - // TODO. - return nullptr; -} - -// ----------------------------------------------------------------------------- -// Message event. -// ----------------------------------------------------------------------------- - -LinphoneConferenceChatMessageEvent *linphone_chat_message_event_new (LinphoneChatMessage *chat_message, time_t time) { - LinphoneConferenceChatMessageEvent *chat_message_event = _linphone_ConferenceChatMessageEvent_init(); + LinphoneConferenceChatMessageEvent *conference_chat_message_event = L_INIT(ConferenceChatMessageEvent); L_SET_CPP_PTR_FROM_C_OBJECT( - chat_message_event, + conference_chat_message_event, make_shared( time, L_GET_CPP_PTR_FROM_C_OBJECT(chat_message) ) ); - return chat_message_event; + return conference_chat_message_event; } -LinphoneChatMessage *linphone_chat_message_event_get_chat_message ( - const LinphoneConferenceChatMessageEvent *chat_message_event +LinphoneChatMessage *linphone_conference_chat_message_event_get_chat_message ( + const LinphoneConferenceChatMessageEvent *conference_chat_message_event ) { return L_GET_C_BACK_PTR( - L_GET_CPP_PTR_FROM_C_OBJECT(chat_message_event)->getChatMessage() + L_GET_CPP_PTR_FROM_C_OBJECT(conference_chat_message_event)->getChatMessage() + ); +} + +// ----------------------------------------------------------------------------- +// ConferenceParticipantEvent. +// ----------------------------------------------------------------------------- + +LinphoneConferenceParticipantEvent *linphone_conference_participant_event_new ( + LinphoneEventLogType type, + time_t time, + const LinphoneAddress *conference_address, + unsigned int notify_id, + const LinphoneAddress *participant_address +) { + LinphoneConferenceParticipantEvent *conference_participant_event = L_INIT(ConferenceParticipantEvent); + L_SET_CPP_PTR_FROM_C_OBJECT( + conference_participant_event, + make_shared( + static_cast(type), + time, + *L_GET_CPP_PTR_FROM_C_OBJECT(conference_address), + notify_id, + *L_GET_CPP_PTR_FROM_C_OBJECT(participant_address) + ) + ); + return conference_participant_event; +} + +const LinphoneAddress *linphone_conference_participant_event_get_participant_address ( + const LinphoneConferenceParticipantEvent *conference_participant_event +) { + return L_GET_C_BACK_PTR( + &L_GET_CPP_PTR_FROM_C_OBJECT(conference_participant_event)->getParticipantAddress() + ); +} + +// ----------------------------------------------------------------------------- +// ConferenceParticipantDeviceEvent. +// ----------------------------------------------------------------------------- + +LinphoneConferenceParticipantDeviceEvent *linphone_conference_participant_device_event_new ( + LinphoneEventLogType type, + time_t time, + const LinphoneAddress *conference_address, + unsigned int notify_id, + const LinphoneAddress *participant_address, + const LinphoneAddress *gruu_address +) { + LinphoneConferenceParticipantDeviceEvent *conference_participant_device_event = L_INIT( + ConferenceParticipantDeviceEvent + ); + L_SET_CPP_PTR_FROM_C_OBJECT( + conference_participant_device_event, + make_shared( + static_cast(type), + time, + *L_GET_CPP_PTR_FROM_C_OBJECT(conference_address), + notify_id, + *L_GET_CPP_PTR_FROM_C_OBJECT(participant_address), + *L_GET_CPP_PTR_FROM_C_OBJECT(gruu_address) + ) + ); + return conference_participant_device_event; +} + +const LinphoneAddress *linphone_conference_participant_device_event_get_gruu_address ( + const LinphoneConferenceParticipantDeviceEvent *conference_participant_device_event +) { + return L_GET_C_BACK_PTR( + &L_GET_CPP_PTR_FROM_C_OBJECT(conference_participant_device_event)->getGruuAddress() + ); +} + +// ----------------------------------------------------------------------------- +// ConferenceSubjectEvent. +// ----------------------------------------------------------------------------- + +LinphoneConferenceSubjectEvent *linphone_conference_subject_event_new ( + LinphoneEventLogType type, + time_t time, + const LinphoneAddress *conference_address, + unsigned int notify_id, + const char *subject +) { + LinphoneConferenceSubjectEvent *conference_subject_event = L_INIT(ConferenceSubjectEvent); + L_SET_CPP_PTR_FROM_C_OBJECT( + conference_subject_event, + make_shared( + time, + *L_GET_CPP_PTR_FROM_C_OBJECT(conference_address), + notify_id, + L_C_TO_STRING(subject) + ) + ); + return conference_subject_event; +} + +LINPHONE_PUBLIC const char *linphone_conference_subject_event_get_subject ( + const LinphoneConferenceSubjectEvent *conference_subject_event +) { + return L_STRING_TO_C( + L_GET_CPP_PTR_FROM_C_OBJECT(conference_subject_event)->getSubject() ); } From 56ce4a19b112aa2a13beaa7c197e6ce4e5477519 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 24 Oct 2017 16:51:08 +0200 Subject: [PATCH 0621/2215] add db connection on core creation --- src/core/core.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 65832c42f..820f7ed05 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -18,6 +18,7 @@ */ #include +#include #include "chat/chat-room/basic-chat-room.h" #include "core-p.h" @@ -47,8 +48,9 @@ Core::Core (LinphoneCore *cCore) : Object(*new CorePrivate) { : MainDb::Sqlite3; d->mainDb.connect(backend, uri); } else { - string path = getDataPath(); - //d->mainDb.connect(MainDb::Sqlite3, linphone_factory_get_writable_dir()/linphone.db); + stringstream path; + path << getDataPath() << "/linphone.db"; + d->mainDb.connect(MainDb::Sqlite3, path.str()); } } From 935e7b392e96f4f5f5c3432a91a07c8628a2c283 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 24 Oct 2017 17:01:32 +0200 Subject: [PATCH 0622/2215] feat(c-event-log): add ref/unref methods --- include/linphone/api/c-event-log.h | 103 +++++++++++++++++++++++++++++ src/c-wrapper/api/c-event-log.cpp | 87 ++++++++++++++++++++++++ 2 files changed, 190 insertions(+) diff --git a/include/linphone/api/c-event-log.h b/include/linphone/api/c-event-log.h index 81fd18990..c701d5202 100644 --- a/include/linphone/api/c-event-log.h +++ b/include/linphone/api/c-event-log.h @@ -42,7 +42,14 @@ **/ LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_new (void); +/** + * Increment reference count of #LinphoneEventLog object. + **/ LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_ref (LinphoneEventLog *event_log); + +/** + * Decrement reference count of #LinphoneEventLog object. When dropped to zero, memory is freed. + **/ LINPHONE_PUBLIC void linphone_event_log_unref (LinphoneEventLog *event_log); /** @@ -72,6 +79,16 @@ LINPHONE_PUBLIC LinphoneConferenceEvent *linphone_conference_event_new ( const LinphoneAddress *conference_address ); +/** + * Increment reference count of #LinphoneConferenceEvent object. + **/ +LINPHONE_PUBLIC LinphoneConferenceEvent *linphone_conference_event_ref (LinphoneConferenceEvent *conference_event); + +/** + * Decrement reference count of #LinphoneConferenceEvent object. When dropped to zero, memory is freed. + **/ +LINPHONE_PUBLIC void linphone_conference_event_unref (LinphoneConferenceEvent *conference_event); + /** * Returns the conference address of a conference event. * @param[in] conference_event A #LinphoneConferenceEvent object. @@ -95,6 +112,20 @@ LINPHONE_PUBLIC LinphoneConferenceNotifiedEvent *linphone_conference_notified_ev unsigned int notify_id ); +/** + * Increment reference count of #LinphoneConferenceNotifiedEvent object. + **/ +LINPHONE_PUBLIC LinphoneConferenceNotifiedEvent *linphone_conference_notified_event_ref ( + LinphoneConferenceNotifiedEvent *conference_notified_event +); + +/** + * Decrement reference count of #LinphoneConferenceNotifiedEvent object. When dropped to zero, memory is freed. + **/ +LINPHONE_PUBLIC void linphone_conference_notified_event_unref ( + LinphoneConferenceNotifiedEvent *conference_notified_event +); + /** * Returns the notify id of a conference notified event. * @param[in] conference_notified_event A #LinphoneConferenceNotifiedEvent object. @@ -117,6 +148,20 @@ LINPHONE_PUBLIC LinphoneConferenceCallEvent *linphone_conference_call_event_new LinphoneCall *call ); +/** + * Increment reference count of #LinphoneConferenceCallEvent object. + **/ +LINPHONE_PUBLIC LinphoneConferenceCallEvent *linphone_conference_call_event_ref ( + LinphoneConferenceCallEvent *conference_call_event +); + +/** + * Decrement reference count of #LinphoneConferenceCallEvent object. When dropped to zero, memory is freed. + **/ +LINPHONE_PUBLIC void linphone_conference_call_event_unref ( + LinphoneConferenceCallEvent *conference_call_event +); + /** * Returns the call of a conference call event. * @param[in] conference_conference_call_event A #LinphoneConferenceCallEvent object. @@ -138,6 +183,20 @@ LINPHONE_PUBLIC LinphoneConferenceChatMessageEvent *linphone_conference_chat_mes LinphoneChatMessage *chat_message ); +/** + * Increment reference count of #LinphoneConferenceChatMessageEvent object. + **/ +LINPHONE_PUBLIC LinphoneConferenceChatMessageEvent *linphone_conference_chat_message_event_ref ( + LinphoneConferenceChatMessageEvent *conference_chat_message_event +); + +/** + * Decrement reference count of #LinphoneConferenceChatMessageEvent object. When dropped to zero, memory is freed. + **/ +LINPHONE_PUBLIC void linphone_conference_chat_message_event_unref ( + LinphoneConferenceChatMessageEvent *conference_chat_message_event +); + /** * Returns the chat message of a conference chat message event. * @param[in] conference_chat_message_event A #LinphoneConferenceChatMessageEvent object. @@ -162,6 +221,20 @@ LINPHONE_PUBLIC LinphoneConferenceParticipantEvent *linphone_conference_particip const LinphoneAddress *participant_address ); +/** + * Increment reference count of #LinphoneConferenceParticipantEvent object. + **/ +LINPHONE_PUBLIC LinphoneConferenceParticipantEvent *linphone_conference_participant_event_ref ( + LinphoneConferenceParticipantEvent *conference_participant_event +); + +/** + * Decrement reference count of #LinphoneConferenceParticipantEvent object. When dropped to zero, memory is freed. + **/ +LINPHONE_PUBLIC void linphone_conference_participant_event_unref ( + LinphoneConferenceParticipantEvent *conference_participant_event +); + /** * Returns the participant address of a conference participant event. * @param[in] conference_participant_event A ConferenceParticipantEvent object. @@ -187,6 +260,21 @@ LINPHONE_PUBLIC LinphoneConferenceParticipantDeviceEvent *linphone_conference_pa const LinphoneAddress *gruu_address ); +/** + * Increment reference count of #LinphoneConferenceParticipantDeviceEvent object. + **/ +LINPHONE_PUBLIC LinphoneConferenceParticipantDeviceEvent *linphone_conference_participant_device_event_ref ( + LinphoneConferenceParticipantDeviceEvent *conference_participant_device_event +); + +/** + * Decrement reference count of #LinphoneConferenceParticipantDeviceEvent object. + * When dropped to zero, memory is freed. + **/ +LINPHONE_PUBLIC void linphone_conference_participant_device_event_unref ( + LinphoneConferenceParticipantDeviceEvent *conference_participant_device_event +); + /** * Returns the gruu address of a conference participant device event. * @param[in] conference_participant_device_event A #LinphoneConferenceParticipantDeviceEvent object. @@ -210,6 +298,21 @@ LINPHONE_PUBLIC LinphoneConferenceSubjectEvent *linphone_conference_subject_even const char *subject ); +/** + * Increment reference count of #LinphoneConferenceSubjectEvent object. + **/ +LINPHONE_PUBLIC LinphoneConferenceSubjectEvent *linphone_conference_subject_event_ref ( + LinphoneConferenceSubjectEvent *conference_subject_event +); + +/** + * Decrement reference count of #LinphoneConferenceSubjectEvent object. + * When dropped to zero, memory is freed. + **/ +LINPHONE_PUBLIC void linphone_conference_subject_event_unref ( + LinphoneConferenceSubjectEvent *conference_subject_event +); + /** * Returns the subject of a conference subject event. * @param[in] conference_subject_event A #LinphoneConferenceSubjectEvent object. diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index ee6625104..151f11c51 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -87,6 +87,15 @@ LinphoneConferenceEvent *linphone_conference_event_new ( return conference_event; } +LinphoneConferenceEvent *linphone_conference_event_ref (LinphoneConferenceEvent *conference_event) { + belle_sip_object_ref(conference_event); + return conference_event; +} + +void linphone_conference_event_unref (LinphoneConferenceEvent *conference_event) { + belle_sip_object_unref(conference_event); +} + const LinphoneAddress *linphone_conference_event_get_conference_address ( const LinphoneConferenceEvent *conference_event ) { @@ -118,6 +127,19 @@ LinphoneConferenceNotifiedEvent *linphone_conference_notified_event_new ( return conference_notified_event; } +LinphoneConferenceNotifiedEvent *linphone_conference_notified_event_ref ( + LinphoneConferenceNotifiedEvent *conference_notified_event +) { + belle_sip_object_ref(conference_notified_event); + return conference_notified_event; +} + +void linphone_conference_notified_event_unref ( + LinphoneConferenceNotifiedEvent *conference_notified_event +) { + belle_sip_object_unref(conference_notified_event); +} + unsigned int linphone_conference_notified_event_get_notify_id ( const LinphoneConferenceNotifiedEvent *conference_notified_event ) { @@ -145,6 +167,19 @@ LinphoneConferenceCallEvent *linphone_conference_call_event_new ( return conference_call_event; } +LinphoneConferenceCallEvent *linphone_conference_call_event_ref ( + LinphoneConferenceCallEvent *conference_call_event +) { + belle_sip_object_ref(conference_call_event); + return conference_call_event; +} + +void linphone_conference_call_event_unref ( + LinphoneConferenceCallEvent *conference_call_event +) { + belle_sip_object_unref(conference_call_event); +} + LinphoneCall *linphone_conference_call_event_get_call (const LinphoneConferenceCallEvent *conference_call_event) { return L_GET_C_BACK_PTR( L_GET_CPP_PTR_FROM_C_OBJECT(conference_call_event)->getCall() @@ -170,6 +205,19 @@ LinphoneConferenceChatMessageEvent *linphone_conference_chat_message_event_new ( return conference_chat_message_event; } +LinphoneConferenceChatMessageEvent *linphone_conference_chat_message_event_ref ( + LinphoneConferenceChatMessageEvent *conference_chat_message_event +) { + belle_sip_object_ref(conference_chat_message_event); + return conference_chat_message_event; +} + +void linphone_conference_chat_message_event_unref ( + LinphoneConferenceChatMessageEvent *conference_chat_message_event +) { + belle_sip_object_unref(conference_chat_message_event); +} + LinphoneChatMessage *linphone_conference_chat_message_event_get_chat_message ( const LinphoneConferenceChatMessageEvent *conference_chat_message_event ) { @@ -203,6 +251,19 @@ LinphoneConferenceParticipantEvent *linphone_conference_participant_event_new ( return conference_participant_event; } +LinphoneConferenceParticipantEvent *linphone_conference_participant_event_ref ( + LinphoneConferenceParticipantEvent *conference_participant_event +) { + belle_sip_object_ref(conference_participant_event); + return conference_participant_event; +} + +void linphone_conference_participant_event_unref ( + LinphoneConferenceParticipantEvent *conference_participant_event +) { + belle_sip_object_unref(conference_participant_event); +} + const LinphoneAddress *linphone_conference_participant_event_get_participant_address ( const LinphoneConferenceParticipantEvent *conference_participant_event ) { @@ -240,6 +301,19 @@ LinphoneConferenceParticipantDeviceEvent *linphone_conference_participant_device return conference_participant_device_event; } +LinphoneConferenceParticipantDeviceEvent *linphone_conference_participant_device_event_ref ( + LinphoneConferenceParticipantDeviceEvent *conference_participant_device_event +) { + belle_sip_object_ref(conference_participant_device_event); + return conference_participant_device_event; +} + +void linphone_conference_participant_device_event_unref ( + LinphoneConferenceParticipantDeviceEvent *conference_participant_device_event +) { + belle_sip_object_unref(conference_participant_device_event); +} + const LinphoneAddress *linphone_conference_participant_device_event_get_gruu_address ( const LinphoneConferenceParticipantDeviceEvent *conference_participant_device_event ) { @@ -272,6 +346,19 @@ LinphoneConferenceSubjectEvent *linphone_conference_subject_event_new ( return conference_subject_event; } +LinphoneConferenceSubjectEvent *linphone_conference_subject_event_ref ( + LinphoneConferenceSubjectEvent *conference_subject_event +) { + belle_sip_object_ref(conference_subject_event); + return conference_subject_event; +} + +void linphone_conference_subject_event_unref ( + LinphoneConferenceSubjectEvent *conference_subject_event +) { + belle_sip_object_unref(conference_subject_event); +} + LINPHONE_PUBLIC const char *linphone_conference_subject_event_get_subject ( const LinphoneConferenceSubjectEvent *conference_subject_event ) { From d3486aa40a670d7459ba513ba2020e2d63f4691d Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 24 Oct 2017 17:08:39 +0200 Subject: [PATCH 0623/2215] fix(Core): avoid stringstream usage (bazooka) --- src/core/core.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 820f7ed05..16b8eb60e 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -47,11 +47,11 @@ Core::Core (LinphoneCore *cCore) : Object(*new CorePrivate) { ? MainDb::Mysql : MainDb::Sqlite3; d->mainDb.connect(backend, uri); - } else { - stringstream path; - path << getDataPath() << "/linphone.db"; - d->mainDb.connect(MainDb::Sqlite3, path.str()); + return; } + + static string path = getDataPath() + "/linphone.db"; + d->mainDb.connect(MainDb::Sqlite3, path); } // ----------------------------------------------------------------------------- From 84ef68ebc1d198d21ab1bf87ab3e9e109c189a4e Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 24 Oct 2017 17:27:14 +0200 Subject: [PATCH 0624/2215] add log --- src/core/core.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/core.cpp b/src/core/core.cpp index 16b8eb60e..d91f75e02 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -46,11 +46,13 @@ Core::Core (LinphoneCore *cCore) : Object(*new CorePrivate) { strcmp(lp_config_get_string(linphone_core_get_config(d->cCore), "server", "db_backend", NULL), "mysql") == 0 ? MainDb::Mysql : MainDb::Sqlite3; + lInfo << "Creating linphone.db at : " << uri; d->mainDb.connect(backend, uri); return; } static string path = getDataPath() + "/linphone.db"; + lInfo << "Creating linphone.db at : " << path; d->mainDb.connect(MainDb::Sqlite3, path); } From 6467c770428700501110d76dfc4ce4ff276531e5 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 24 Oct 2017 17:31:46 +0200 Subject: [PATCH 0625/2215] feat(MainDb): supports getHistory and getHistoryRange --- src/db/main-db.cpp | 12 +++--------- src/db/main-db.h | 2 +- tester/main-db-tester.cpp | 16 ++++++++++++++-- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 732971b5a..df3d034c2 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -906,16 +906,10 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} } list> MainDb::getHistory (const string &peerAddress, int nLast, FilterMask mask) const { - if (!isConnected()) { - lWarning() << "Unable to get history. Not connected."; - return list>(); - } - - // TODO. - return list>(); + return getHistoryRange(peerAddress, 0, nLast - 1, mask); } - list> MainDb::getHistory ( + list> MainDb::getHistoryRange ( const string &peerAddress, int begin, int end, @@ -1228,7 +1222,7 @@ shared_ptr MainDb::findChatRoom (const string &peerAddress) const { return list>(); } - list> MainDb::getHistory (const string &, int, int, FilterMask) const { + list> MainDb::getHistoryRange (const string &, int, int, FilterMask) const { return list>(); } diff --git a/src/db/main-db.h b/src/db/main-db.h index 1d22ba3a5..7a0367a62 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -61,7 +61,7 @@ public: int nLast, FilterMask mask = NoFilter ) const; - std::list> getHistory ( + std::list> getHistoryRange ( const std::string &peerAddress, int begin, int end, diff --git a/tester/main-db-tester.cpp b/tester/main-db-tester.cpp index 2ab90d43e..8691b575c 100644 --- a/tester/main-db-tester.cpp +++ b/tester/main-db-tester.cpp @@ -68,17 +68,29 @@ static void get_history () { MainDb mainDb; BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); BC_ASSERT_EQUAL( - mainDb.getHistory("sip:test-39@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceChatMessageFilter).size(), + mainDb.getHistoryRange("sip:test-39@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceChatMessageFilter).size(), 3, int, "%d" ); BC_ASSERT_EQUAL( - mainDb.getHistory("sip:test-7@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceCallFilter).size(), + mainDb.getHistoryRange("sip:test-7@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceCallFilter).size(), 0, int, "%d" ); + BC_ASSERT_EQUAL( + mainDb.getHistoryRange("sip:test-1@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceChatMessageFilter).size(), + 862, + int, + "%d" + ); + BC_ASSERT_EQUAL( + mainDb.getHistory("sip:test-1@sip.linphone.org", 100, MainDb::Filter::ConferenceChatMessageFilter).size(), + 100, + int, + "%d" + ); } test_t main_db_tests[] = { From 18690440ee3627bfc01e3733c274c174b006f943 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 24 Oct 2017 17:37:48 +0200 Subject: [PATCH 0626/2215] fix(Core): fix build and provide a LINPHONE_DB define --- src/core/core.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index d91f75e02..3c34658c4 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -23,12 +23,15 @@ #include "chat/chat-room/basic-chat-room.h" #include "core-p.h" #include "db/main-db.h" +#include "logger/logger.h" #include "object/object-p.h" #include "paths/paths.h" // TODO: Remove me later. #include "private.h" +#define LINPHONE_DB "linphone.db" + // ============================================================================= using namespace std; @@ -46,13 +49,13 @@ Core::Core (LinphoneCore *cCore) : Object(*new CorePrivate) { strcmp(lp_config_get_string(linphone_core_get_config(d->cCore), "server", "db_backend", NULL), "mysql") == 0 ? MainDb::Mysql : MainDb::Sqlite3; - lInfo << "Creating linphone.db at : " << uri; + lInfo() << "Creating " LINPHONE_DB " at: " << uri; d->mainDb.connect(backend, uri); return; } - static string path = getDataPath() + "/linphone.db"; - lInfo << "Creating linphone.db at : " << path; + static string path = getDataPath() + "/" LINPHONE_DB; + lInfo() << "Creating " LINPHONE_DB " at: " << path; d->mainDb.connect(MainDb::Sqlite3, path); } From c26031d755c62661ced02d11908376799e12810c Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 24 Oct 2017 18:03:20 +0200 Subject: [PATCH 0627/2215] feat(c-chat-room): provide a way to get history events --- include/linphone/api/c-chat-room.h | 19 ++++++++++++++++++- src/c-wrapper/api/c-chat-room.cpp | 21 +++++++++++++++++++++ src/c-wrapper/internal/c-tools.h | 2 +- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index aa7fdda4c..a190ac8be 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -165,7 +165,7 @@ LINPHONE_PUBLIC int linphone_chat_room_get_history_size(LinphoneChatRoom *cr); * @param[in] nb_message Number of message to retrieve. 0 means everything. * @return \bctbx_list{LinphoneChatMessage} */ -LINPHONE_PUBLIC bctbx_list_t *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message); +LINPHONE_PUBLIC bctbx_list_t *linphone_chat_room_get_history (LinphoneChatRoom *cr,int nb_message); /** * Gets the partial list of messages in the given range, sorted from oldest to most recent. @@ -176,6 +176,23 @@ LINPHONE_PUBLIC bctbx_list_t *linphone_chat_room_get_history(LinphoneChatRoom *c */ LINPHONE_PUBLIC bctbx_list_t *linphone_chat_room_get_history_range(LinphoneChatRoom *cr, int begin, int end); +/** + * Gets nb_events most recent events from cr chat room, sorted from oldest to most recent. + * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which events should be retrieved + * @param[in] nb_events Number of events to retrieve. 0 means everything. + * @return \bctbx_list{LinphoneEventLog} + */ +LINPHONE_PUBLIC bctbx_list_t *linphone_chat_room_get_history_events (LinphoneChatRoom *cr, int nb_events); + +/** + * Gets the partial list of events in the given range, sorted from oldest to most recent. + * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which events should be retrieved + * @param[in] begin The first event of the range to be retrieved. History most recent event has index 0. + * @param[in] end The last event of the range to be retrieved. History oldest event has index of history size - 1 + * @return \bctbx_list{LinphoneEventLog} + */ +LINPHONE_PUBLIC bctbx_list_t *linphone_chat_room_get_history_range_events (LinphoneChatRoom *cr, int begin, int end); + LINPHONE_PUBLIC LinphoneChatMessage * linphone_chat_room_find_message(LinphoneChatRoom *cr, const char *message_id); /** diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 08a0ff47e..e112f83c4 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -23,11 +23,13 @@ #include "linphone/wrapper_utils.h" #include "linphone/api/c-chat-room.h" +#include "event-log/event-log.h" #include "c-wrapper/c-wrapper.h" #include "chat/chat-room/basic-chat-room.h" #include "chat/chat-room/client-group-chat-room.h" #include "chat/chat-room/real-time-text-chat-room-p.h" #include "conference/participant.h" +#include "core/core-p.h" // ============================================================================= @@ -201,6 +203,25 @@ bctbx_list_t *linphone_chat_room_get_history (LinphoneChatRoom *cr, int nb_messa return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistory(nb_message)); } +bctbx_list_t *linphone_chat_room_get_history_events (LinphoneChatRoom *cr, int nb_events) { + return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST( + L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore()->cppCore)->mainDb.getHistory( + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getPeerAddress().asStringUriOnly(), + nb_events + ) + ); +} + +bctbx_list_t *linphone_chat_room_get_history_range_events (LinphoneChatRoom *cr, int begin, int end) { + return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST( + L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore()->cppCore)->mainDb.getHistory( + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getPeerAddress().asStringUriOnly(), + begin, + end + ) + ); +} + LinphoneChatMessage *linphone_chat_room_find_message (LinphoneChatRoom *cr, const char *message_id) { return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findMessage(message_id)); } diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 3783688c6..7ec402e3c 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -413,7 +413,7 @@ public: template< typename CppType, - typename = typename std::enable_if::value, CppType>::type + typename = typename std::enable_if::value, CppType>::type > static inline bctbx_list_t *getResolvedCListFromCppList (const std::list> &cppList) { bctbx_list_t *result = nullptr; From 79001f54d07b70e20e037a3b4ee0409f72479379 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 25 Oct 2017 11:05:33 +0200 Subject: [PATCH 0628/2215] feat(EventLog): wrap only one C object --- include/linphone/api/c-callbacks.h | 12 +- include/linphone/api/c-event-log.h | 212 +-------------- include/linphone/api/c-types.h | 42 --- src/c-wrapper/api/c-event-log.cpp | 405 +++++++++++------------------ src/c-wrapper/c-wrapper.h | 16 +- src/core/core.h | 5 +- src/db/main-db.cpp | 2 +- 7 files changed, 185 insertions(+), 509 deletions(-) diff --git a/include/linphone/api/c-callbacks.h b/include/linphone/api/c-callbacks.h index c99e1b8aa..b45d705df 100644 --- a/include/linphone/api/c-callbacks.h +++ b/include/linphone/api/c-callbacks.h @@ -161,14 +161,14 @@ typedef void (*LinphoneChatRoomCbsMessageReceivedCb) (LinphoneChatRoom *cr, Linp * @param[in] cr #LinphoneChatRoom object * @param[in] participant The #LinphoneParticipant that has been added to the chat room */ -typedef void (*LinphoneChatRoomCbsParticipantAddedCb) (LinphoneChatRoom *cr, const LinphoneConferenceParticipantEvent *event); +typedef void (*LinphoneChatRoomCbsParticipantAddedCb) (LinphoneChatRoom *cr, const LinphoneEventLog *event_log); /** * Callback used to notify a chat room that a participant has been removed. * @param[in] cr #LinphoneChatRoom object * @param[in] participant The #LinphoneParticipant that has been removed from the chat room */ -typedef void (*LinphoneChatRoomCbsParticipantRemovedCb) (LinphoneChatRoom *cr, const LinphoneConferenceParticipantEvent *event); +typedef void (*LinphoneChatRoomCbsParticipantRemovedCb) (LinphoneChatRoom *cr, const LinphoneEventLog *event_log); /** * Callback used to notify a chat room that the admin status of a participant has been changed. @@ -176,7 +176,7 @@ typedef void (*LinphoneChatRoomCbsParticipantRemovedCb) (LinphoneChatRoom *cr, c * @param[in] participant The #LinphoneParticipant for which the admin status has been changed * @param[in] isAdmin The new admin status of the participant */ -typedef void (*LinphoneChatRoomCbsParticipantAdminStatusChangedCb) (LinphoneChatRoom *cr, const LinphoneConferenceParticipantEvent *event); +typedef void (*LinphoneChatRoomCbsParticipantAdminStatusChangedCb) (LinphoneChatRoom *cr, const LinphoneEventLog *event_log); /** * Callback used to notify a chat room state has changed. @@ -190,7 +190,7 @@ typedef void (*LinphoneChatRoomCbsStateChangedCb) (LinphoneChatRoom *cr, Linphon * @param[in] cr #LinphoneChatRoom object * @param[in] subject The new subject of the chat room */ -typedef void (*LinphoneChatRoomCbsSubjectChangedCb) (LinphoneChatRoom *cr, const LinphoneConferenceSubjectEvent *event); +typedef void (*LinphoneChatRoomCbsSubjectChangedCb) (LinphoneChatRoom *cr, const LinphoneEventLog *event_log); /** * Callback used to notify a chat room that a message has been received but we were unable to decrypt it @@ -204,14 +204,14 @@ typedef void (*LinphoneChatRoomCbsUndecryptableMessageReceivedCb) (LinphoneChatR * @param[in] cr #LinphoneChatRoom object * @param[in] participant The #LinphoneParticipant that has been added to the chat room */ -typedef void (*LinphoneChatRoomCbsParticipantDeviceAddedCb) (LinphoneChatRoom *cr, const LinphoneConferenceParticipantDeviceEvent *event); +typedef void (*LinphoneChatRoomCbsParticipantDeviceAddedCb) (LinphoneChatRoom *cr, const LinphoneEventLog *event_log); /** * Callback used to notify a chat room that a participant has been removed. * @param[in] cr #LinphoneChatRoom object * @param[in] participant The #LinphoneParticipant that has been removed from the chat room */ -typedef void (*LinphoneChatRoomCbsParticipantDeviceRemovedCb) (LinphoneChatRoom *cr, const LinphoneConferenceParticipantDeviceEvent *event); +typedef void (*LinphoneChatRoomCbsParticipantDeviceRemovedCb) (LinphoneChatRoom *cr, const LinphoneEventLog *event_log); /** * @} **/ diff --git a/include/linphone/api/c-event-log.h b/include/linphone/api/c-event-log.h index c701d5202..46dac0017 100644 --- a/include/linphone/api/c-event-log.h +++ b/include/linphone/api/c-event-log.h @@ -37,11 +37,6 @@ // EventLog. // ----------------------------------------------------------------------------- -/** - * Constructs a #LinphoneEventLog object. - **/ -LINPHONE_PUBLIC LinphoneEventLog *linphone_event_log_new (void); - /** * Increment reference count of #LinphoneEventLog object. **/ @@ -70,257 +65,78 @@ LINPHONE_PUBLIC time_t linphone_event_log_get_time (const LinphoneEventLog *even // ConferenceEvent. // ----------------------------------------------------------------------------- -/** - * Constructs a #LinphoneConferenceEvent object. - **/ -LINPHONE_PUBLIC LinphoneConferenceEvent *linphone_conference_event_new ( - LinphoneEventLogType type, - time_t time, - const LinphoneAddress *conference_address -); - -/** - * Increment reference count of #LinphoneConferenceEvent object. - **/ -LINPHONE_PUBLIC LinphoneConferenceEvent *linphone_conference_event_ref (LinphoneConferenceEvent *conference_event); - -/** - * Decrement reference count of #LinphoneConferenceEvent object. When dropped to zero, memory is freed. - **/ -LINPHONE_PUBLIC void linphone_conference_event_unref (LinphoneConferenceEvent *conference_event); - /** * Returns the conference address of a conference event. - * @param[in] conference_event A #LinphoneConferenceEvent object. + * @param[in] event_log A #LinphoneEventLog object. * @return The conference address. */ -LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_event_get_conference_address ( - const LinphoneConferenceEvent *conference_event -); +LINPHONE_PUBLIC const LinphoneAddress *linphone_event_log_get_conference_address (const LinphoneEventLog *event_log); // ----------------------------------------------------------------------------- // ConferenceNotifiedEvent. // ----------------------------------------------------------------------------- -/** - * Constructs a #LinphoneConferenceNotifiedEvent object. - **/ -LINPHONE_PUBLIC LinphoneConferenceNotifiedEvent *linphone_conference_notified_event_new ( - LinphoneEventLogType type, - time_t time, - const LinphoneAddress *conference_address, - unsigned int notify_id -); - -/** - * Increment reference count of #LinphoneConferenceNotifiedEvent object. - **/ -LINPHONE_PUBLIC LinphoneConferenceNotifiedEvent *linphone_conference_notified_event_ref ( - LinphoneConferenceNotifiedEvent *conference_notified_event -); - -/** - * Decrement reference count of #LinphoneConferenceNotifiedEvent object. When dropped to zero, memory is freed. - **/ -LINPHONE_PUBLIC void linphone_conference_notified_event_unref ( - LinphoneConferenceNotifiedEvent *conference_notified_event -); - /** * Returns the notify id of a conference notified event. - * @param[in] conference_notified_event A #LinphoneConferenceNotifiedEvent object. + * @param[in] event_log A #LinphoneEventLog object. * @return The conference notify id. */ -LINPHONE_PUBLIC unsigned int linphone_conference_notified_event_get_notify_id ( - const LinphoneConferenceNotifiedEvent *conference_notified_event -); +LINPHONE_PUBLIC unsigned int linphone_event_log_get_notify_id (const LinphoneEventLog *event_log); // ----------------------------------------------------------------------------- // ConferenceCallEvent. // ----------------------------------------------------------------------------- -/** - * Constructs a #LinphoneConferenceCallEvent object. - **/ -LINPHONE_PUBLIC LinphoneConferenceCallEvent *linphone_conference_call_event_new ( - LinphoneEventLogType type, - time_t time, - LinphoneCall *call -); - -/** - * Increment reference count of #LinphoneConferenceCallEvent object. - **/ -LINPHONE_PUBLIC LinphoneConferenceCallEvent *linphone_conference_call_event_ref ( - LinphoneConferenceCallEvent *conference_call_event -); - -/** - * Decrement reference count of #LinphoneConferenceCallEvent object. When dropped to zero, memory is freed. - **/ -LINPHONE_PUBLIC void linphone_conference_call_event_unref ( - LinphoneConferenceCallEvent *conference_call_event -); - /** * Returns the call of a conference call event. - * @param[in] conference_conference_call_event A #LinphoneConferenceCallEvent object. + * @param[in] event_log A #LinphoneEventLog object. * @return The conference call. */ -LINPHONE_PUBLIC LinphoneCall *linphone_conference_call_event_get_call ( - const LinphoneConferenceCallEvent *conference_call_event -); +LINPHONE_PUBLIC LinphoneCall *linphone_event_log_get_call (const LinphoneEventLog *event_log); // ----------------------------------------------------------------------------- // ConferenceChatMessageEvent. // ----------------------------------------------------------------------------- -/** - * Constructs a #LinphoneConferenceChatMessageEvent object. - **/ -LINPHONE_PUBLIC LinphoneConferenceChatMessageEvent *linphone_conference_chat_message_event_new ( - time_t time, - LinphoneChatMessage *chat_message -); - -/** - * Increment reference count of #LinphoneConferenceChatMessageEvent object. - **/ -LINPHONE_PUBLIC LinphoneConferenceChatMessageEvent *linphone_conference_chat_message_event_ref ( - LinphoneConferenceChatMessageEvent *conference_chat_message_event -); - -/** - * Decrement reference count of #LinphoneConferenceChatMessageEvent object. When dropped to zero, memory is freed. - **/ -LINPHONE_PUBLIC void linphone_conference_chat_message_event_unref ( - LinphoneConferenceChatMessageEvent *conference_chat_message_event -); - /** * Returns the chat message of a conference chat message event. - * @param[in] conference_chat_message_event A #LinphoneConferenceChatMessageEvent object. + * @param[in] event_log A #LinphoneEventLog object. * @return The conference chat message. */ -LINPHONE_PUBLIC LinphoneChatMessage *linphone_conference_chat_message_event_get_chat_message ( - const LinphoneConferenceChatMessageEvent *conference_chat_message_event -); +LINPHONE_PUBLIC LinphoneChatMessage *linphone_event_log_get_chat_message (const LinphoneEventLog *event_log); // ----------------------------------------------------------------------------- // ConferenceParticipantEvent. // ----------------------------------------------------------------------------- -/** - * Constructs a #LinphoneConferenceParticipantEvent object. - **/ -LINPHONE_PUBLIC LinphoneConferenceParticipantEvent *linphone_conference_participant_event_new ( - LinphoneEventLogType type, - time_t time, - const LinphoneAddress *conference_address, - unsigned int notify_id, - const LinphoneAddress *participant_address -); - -/** - * Increment reference count of #LinphoneConferenceParticipantEvent object. - **/ -LINPHONE_PUBLIC LinphoneConferenceParticipantEvent *linphone_conference_participant_event_ref ( - LinphoneConferenceParticipantEvent *conference_participant_event -); - -/** - * Decrement reference count of #LinphoneConferenceParticipantEvent object. When dropped to zero, memory is freed. - **/ -LINPHONE_PUBLIC void linphone_conference_participant_event_unref ( - LinphoneConferenceParticipantEvent *conference_participant_event -); - /** * Returns the participant address of a conference participant event. - * @param[in] conference_participant_event A ConferenceParticipantEvent object. + * @param[in] event_log A ConferenceParticipantEvent object. * @return The conference participant address. */ -LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_participant_event_get_participant_address ( - const LinphoneConferenceParticipantEvent *conference_participant_event -); +LINPHONE_PUBLIC const LinphoneAddress *linphone_event_log_get_participant_address (const LinphoneEventLog *event_log); // ----------------------------------------------------------------------------- // ConferenceParticipantDeviceEvent. // ----------------------------------------------------------------------------- -/** - * Constructs a #LinphoneConferenceParticipantDeviceEvent object. - **/ -LINPHONE_PUBLIC LinphoneConferenceParticipantDeviceEvent *linphone_conference_participant_device_event_new ( - LinphoneEventLogType type, - time_t time, - const LinphoneAddress *conference_address, - unsigned int notify_id, - const LinphoneAddress *participant_address, - const LinphoneAddress *gruu_address -); - -/** - * Increment reference count of #LinphoneConferenceParticipantDeviceEvent object. - **/ -LINPHONE_PUBLIC LinphoneConferenceParticipantDeviceEvent *linphone_conference_participant_device_event_ref ( - LinphoneConferenceParticipantDeviceEvent *conference_participant_device_event -); - -/** - * Decrement reference count of #LinphoneConferenceParticipantDeviceEvent object. - * When dropped to zero, memory is freed. - **/ -LINPHONE_PUBLIC void linphone_conference_participant_device_event_unref ( - LinphoneConferenceParticipantDeviceEvent *conference_participant_device_event -); - /** * Returns the gruu address of a conference participant device event. - * @param[in] conference_participant_device_event A #LinphoneConferenceParticipantDeviceEvent object. + * @param[in] event_log A #LinphoneEventLog object. * @return The conference gruu address. */ -LINPHONE_PUBLIC const LinphoneAddress *linphone_conference_participant_device_event_get_gruu_address ( - const LinphoneConferenceParticipantDeviceEvent *conference_participant_device_event -); +LINPHONE_PUBLIC const LinphoneAddress *linphone_event_log_get_gruu_address (const LinphoneEventLog *event_log); // ----------------------------------------------------------------------------- // ConferenceSubjectEvent. // ----------------------------------------------------------------------------- -/** - * Constructs a #LinphoneConferenceSubjectEvent object. - **/ -LINPHONE_PUBLIC LinphoneConferenceSubjectEvent *linphone_conference_subject_event_new ( - time_t time, - const LinphoneAddress *conference_address, - unsigned int notify_id, - const char *subject -); - -/** - * Increment reference count of #LinphoneConferenceSubjectEvent object. - **/ -LINPHONE_PUBLIC LinphoneConferenceSubjectEvent *linphone_conference_subject_event_ref ( - LinphoneConferenceSubjectEvent *conference_subject_event -); - -/** - * Decrement reference count of #LinphoneConferenceSubjectEvent object. - * When dropped to zero, memory is freed. - **/ -LINPHONE_PUBLIC void linphone_conference_subject_event_unref ( - LinphoneConferenceSubjectEvent *conference_subject_event -); - /** * Returns the subject of a conference subject event. - * @param[in] conference_subject_event A #LinphoneConferenceSubjectEvent object. + * @param[in] event_log A #LinphoneEventLog object. * @return The conference subject. */ -LINPHONE_PUBLIC const char *linphone_conference_subject_event_get_subject ( - const LinphoneConferenceSubjectEvent *conference_subject_event -); +LINPHONE_PUBLIC const char *linphone_event_get_subject (const LinphoneEventLog *event_log); /** * @} diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index 07ac41960..a673db45d 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -127,48 +127,6 @@ typedef struct _LinphoneChatRoomCbs LinphoneChatRoomCbs; // EventLog. // ----------------------------------------------------------------------------- -/** - * Call start/end events. - * @ingroup events - */ -typedef struct _LinphoneConferenceCallEvent LinphoneConferenceCallEvent; - -/** - * Chat message event. - * @ingroup events - */ -typedef struct _LinphoneConferenceChatMessageEvent LinphoneConferenceChatMessageEvent; - -/** - * Conference created/destroyed events. - * @ingroup events - */ -typedef struct _LinphoneConferenceEvent LinphoneConferenceEvent; - -/** - * Conference notified event. - * @ingroup events - */ -typedef struct _LinphoneConferenceNotifiedEvent LinphoneConferenceNotifiedEvent; - -/** - * Conference participant device added/removed events. - * @ingroup events - */ -typedef struct _LinphoneConferenceParticipantDeviceEvent LinphoneConferenceParticipantDeviceEvent; - -/** - * Conference participant added/removed & set/unset admin events. - * @ingroup events - */ -typedef struct _LinphoneConferenceParticipantEvent LinphoneConferenceParticipantEvent; - -/** - * Conference subject changed event. - * @ingroup events - */ -typedef struct _LinphoneConferenceSubjectEvent LinphoneConferenceSubjectEvent; - /** * Base object of events. * @ingroup events diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 151f11c51..132982327 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -26,27 +26,126 @@ // ============================================================================= -L_DECLARE_C_OBJECT_IMPL(ConferenceCallEvent); -L_DECLARE_C_OBJECT_IMPL(ConferenceChatMessageEvent); -L_DECLARE_C_OBJECT_IMPL(ConferenceEvent); -L_DECLARE_C_OBJECT_IMPL(ConferenceNotifiedEvent); -L_DECLARE_C_OBJECT_IMPL(ConferenceParticipantDeviceEvent); -L_DECLARE_C_OBJECT_IMPL(ConferenceParticipantEvent); -L_DECLARE_C_OBJECT_IMPL(ConferenceSubjectEvent); L_DECLARE_C_OBJECT_IMPL(EventLog); using namespace std; // ----------------------------------------------------------------------------- -// EventLog. +// Helpers. // ----------------------------------------------------------------------------- -LinphoneEventLog *linphone_event_log_new () { - LinphoneEventLog *event_log = L_INIT(EventLog); - L_SET_CPP_PTR_FROM_C_OBJECT(event_log, make_shared()); - return event_log; +static bool isConferenceType (LinphoneEventLogType type) { + switch (type) { + case LinphoneEventLogTypeConferenceCallEnd: + case LinphoneEventLogTypeConferenceCallStart: + case LinphoneEventLogTypeConferenceChatMessage: + case LinphoneEventLogTypeConferenceCreated: + case LinphoneEventLogTypeConferenceDestroyed: + case LinphoneEventLogTypeConferenceParticipantAdded: + case LinphoneEventLogTypeConferenceParticipantDeviceAdded: + case LinphoneEventLogTypeConferenceParticipantDeviceRemoved: + case LinphoneEventLogTypeConferenceParticipantRemoved: + case LinphoneEventLogTypeConferenceParticipantSetAdmin: + case LinphoneEventLogTypeConferenceParticipantUnsetAdmin: + case LinphoneEventLogTypeConferenceSubjectChanged: + return true; + + default: + break; + } + + return false; } +static bool isConferenceCallType (LinphoneEventLogType type) { + switch (type) { + case LinphoneEventLogTypeConferenceCallEnd: + case LinphoneEventLogTypeConferenceCallStart: + return true; + + default: + break; + } + + return false; +} + +static bool isConferenceChatMessageType (LinphoneEventLogType type) { + switch (type) { + case LinphoneEventLogTypeConferenceChatMessage: + return true; + + default: + break; + } + + return false; +} + +static bool isConferenceNotifiedType (LinphoneEventLogType type) { + switch (type) { + case LinphoneEventLogTypeConferenceParticipantAdded: + case LinphoneEventLogTypeConferenceParticipantDeviceAdded: + case LinphoneEventLogTypeConferenceParticipantDeviceRemoved: + case LinphoneEventLogTypeConferenceParticipantRemoved: + case LinphoneEventLogTypeConferenceParticipantSetAdmin: + case LinphoneEventLogTypeConferenceParticipantUnsetAdmin: + case LinphoneEventLogTypeConferenceSubjectChanged: + return true; + + default: + break; + } + + return false; +} + +static bool isConferenceParticipantType (LinphoneEventLogType type) { + switch (type) { + case LinphoneEventLogTypeConferenceParticipantAdded: + case LinphoneEventLogTypeConferenceParticipantDeviceAdded: + case LinphoneEventLogTypeConferenceParticipantDeviceRemoved: + case LinphoneEventLogTypeConferenceParticipantRemoved: + case LinphoneEventLogTypeConferenceParticipantSetAdmin: + case LinphoneEventLogTypeConferenceParticipantUnsetAdmin: + return true; + + default: + break; + } + + return false; +} + +static bool isConferenceParticipantDeviceType (LinphoneEventLogType type) { + switch (type) { + case LinphoneEventLogTypeConferenceParticipantDeviceAdded: + case LinphoneEventLogTypeConferenceParticipantDeviceRemoved: + return true; + + default: + break; + } + + return false; +} + +static bool isConferenceSubjectType (LinphoneEventLogType type) { + switch (type) { + case LinphoneEventLogTypeConferenceSubjectChanged: + return true; + + default: + break; + } + + return false; +} + +// ----------------------------------------------------------------------------- +// EventLog. +// ----------------------------------------------------------------------------- + LinphoneEventLog *linphone_event_log_ref (LinphoneEventLog *event_log) { belle_sip_object_ref(event_log); return event_log; @@ -70,37 +169,14 @@ time_t linphone_event_log_get_time (const LinphoneEventLog *event_log) { // ConferenceEvent. // ----------------------------------------------------------------------------- -LinphoneConferenceEvent *linphone_conference_event_new ( - LinphoneEventLogType type, - time_t time, - const LinphoneAddress *conference_address -) { - LinphoneConferenceEvent *conference_event = L_INIT(ConferenceEvent); - L_SET_CPP_PTR_FROM_C_OBJECT( - conference_event, - make_shared( - static_cast(type), - time, - *L_GET_CPP_PTR_FROM_C_OBJECT(conference_address) - ) - ); - return conference_event; -} +const LinphoneAddress *linphone_event_log_get_conference_address (const LinphoneEventLog *event_log) { + if (!isConferenceType(linphone_event_log_get_type(event_log))) + return nullptr; -LinphoneConferenceEvent *linphone_conference_event_ref (LinphoneConferenceEvent *conference_event) { - belle_sip_object_ref(conference_event); - return conference_event; -} - -void linphone_conference_event_unref (LinphoneConferenceEvent *conference_event) { - belle_sip_object_unref(conference_event); -} - -const LinphoneAddress *linphone_conference_event_get_conference_address ( - const LinphoneConferenceEvent *conference_event -) { return L_GET_C_BACK_PTR( - &L_GET_CPP_PTR_FROM_C_OBJECT(conference_event)->getConferenceAddress() + &static_pointer_cast( + L_GET_CPP_PTR_FROM_C_OBJECT(event_log) + )->getConferenceAddress() ); } @@ -108,81 +184,27 @@ const LinphoneAddress *linphone_conference_event_get_conference_address ( // ConferenceNotifiedEvent. // ----------------------------------------------------------------------------- -LinphoneConferenceNotifiedEvent *linphone_conference_notified_event_new ( - LinphoneEventLogType type, - time_t time, - const LinphoneAddress *conference_address, - unsigned int notify_id -) { - LinphoneConferenceNotifiedEvent *conference_notified_event = L_INIT(ConferenceNotifiedEvent); - L_SET_CPP_PTR_FROM_C_OBJECT( - conference_notified_event, - make_shared( - static_cast(type), - time, - *L_GET_CPP_PTR_FROM_C_OBJECT(conference_address), - notify_id - ) - ); - return conference_notified_event; -} +unsigned int linphone_event_log_get_notify_id (const LinphoneEventLog *event_log) { + if (!isConferenceNotifiedType(linphone_event_log_get_type(event_log))) + return 0; -LinphoneConferenceNotifiedEvent *linphone_conference_notified_event_ref ( - LinphoneConferenceNotifiedEvent *conference_notified_event -) { - belle_sip_object_ref(conference_notified_event); - return conference_notified_event; -} - -void linphone_conference_notified_event_unref ( - LinphoneConferenceNotifiedEvent *conference_notified_event -) { - belle_sip_object_unref(conference_notified_event); -} - -unsigned int linphone_conference_notified_event_get_notify_id ( - const LinphoneConferenceNotifiedEvent *conference_notified_event -) { - return L_GET_CPP_PTR_FROM_C_OBJECT(conference_notified_event)->getNotifyId(); + return static_pointer_cast( + L_GET_CPP_PTR_FROM_C_OBJECT(event_log) + )->getNotifyId(); } // ----------------------------------------------------------------------------- // ConferenceCallEvent. // ----------------------------------------------------------------------------- -LinphoneConferenceCallEvent *linphone_conference_call_event_new ( - LinphoneEventLogType type, - time_t time, - LinphoneCall *call -) { - LinphoneConferenceCallEvent *conference_call_event = L_INIT(ConferenceCallEvent); - L_SET_CPP_PTR_FROM_C_OBJECT( - conference_call_event, - make_shared( - static_cast(type), - time, - L_GET_CPP_PTR_FROM_C_OBJECT(call) - ) - ); - return conference_call_event; -} +LinphoneCall *linphone_event_log_get_call (const LinphoneEventLog *event_log) { + if (!isConferenceCallType(linphone_event_log_get_type(event_log))) + return nullptr; -LinphoneConferenceCallEvent *linphone_conference_call_event_ref ( - LinphoneConferenceCallEvent *conference_call_event -) { - belle_sip_object_ref(conference_call_event); - return conference_call_event; -} - -void linphone_conference_call_event_unref ( - LinphoneConferenceCallEvent *conference_call_event -) { - belle_sip_object_unref(conference_call_event); -} - -LinphoneCall *linphone_conference_call_event_get_call (const LinphoneConferenceCallEvent *conference_call_event) { return L_GET_C_BACK_PTR( - L_GET_CPP_PTR_FROM_C_OBJECT(conference_call_event)->getCall() + static_pointer_cast( + L_GET_CPP_PTR_FROM_C_OBJECT(event_log) + )->getCall() ); } @@ -190,39 +212,14 @@ LinphoneCall *linphone_conference_call_event_get_call (const LinphoneConferenceC // ConferenceChatMessageEvent. // ----------------------------------------------------------------------------- -LinphoneConferenceChatMessageEvent *linphone_conference_chat_message_event_new ( - time_t time, - LinphoneChatMessage *chat_message -) { - LinphoneConferenceChatMessageEvent *conference_chat_message_event = L_INIT(ConferenceChatMessageEvent); - L_SET_CPP_PTR_FROM_C_OBJECT( - conference_chat_message_event, - make_shared( - time, - L_GET_CPP_PTR_FROM_C_OBJECT(chat_message) - ) - ); - return conference_chat_message_event; -} +LinphoneChatMessage *linphone_event_log_get_chat_message (const LinphoneEventLog *event_log) { + if (!isConferenceChatMessageType(linphone_event_log_get_type(event_log))) + return nullptr; -LinphoneConferenceChatMessageEvent *linphone_conference_chat_message_event_ref ( - LinphoneConferenceChatMessageEvent *conference_chat_message_event -) { - belle_sip_object_ref(conference_chat_message_event); - return conference_chat_message_event; -} - -void linphone_conference_chat_message_event_unref ( - LinphoneConferenceChatMessageEvent *conference_chat_message_event -) { - belle_sip_object_unref(conference_chat_message_event); -} - -LinphoneChatMessage *linphone_conference_chat_message_event_get_chat_message ( - const LinphoneConferenceChatMessageEvent *conference_chat_message_event -) { return L_GET_C_BACK_PTR( - L_GET_CPP_PTR_FROM_C_OBJECT(conference_chat_message_event)->getChatMessage() + static_pointer_cast( + L_GET_CPP_PTR_FROM_C_OBJECT(event_log) + )->getChatMessage() ); } @@ -230,45 +227,14 @@ LinphoneChatMessage *linphone_conference_chat_message_event_get_chat_message ( // ConferenceParticipantEvent. // ----------------------------------------------------------------------------- -LinphoneConferenceParticipantEvent *linphone_conference_participant_event_new ( - LinphoneEventLogType type, - time_t time, - const LinphoneAddress *conference_address, - unsigned int notify_id, - const LinphoneAddress *participant_address -) { - LinphoneConferenceParticipantEvent *conference_participant_event = L_INIT(ConferenceParticipantEvent); - L_SET_CPP_PTR_FROM_C_OBJECT( - conference_participant_event, - make_shared( - static_cast(type), - time, - *L_GET_CPP_PTR_FROM_C_OBJECT(conference_address), - notify_id, - *L_GET_CPP_PTR_FROM_C_OBJECT(participant_address) - ) - ); - return conference_participant_event; -} +const LinphoneAddress *linphone_event_log_get_participant_address (const LinphoneEventLog *event_log) { + if (!isConferenceParticipantType(linphone_event_log_get_type(event_log))) + return nullptr; -LinphoneConferenceParticipantEvent *linphone_conference_participant_event_ref ( - LinphoneConferenceParticipantEvent *conference_participant_event -) { - belle_sip_object_ref(conference_participant_event); - return conference_participant_event; -} - -void linphone_conference_participant_event_unref ( - LinphoneConferenceParticipantEvent *conference_participant_event -) { - belle_sip_object_unref(conference_participant_event); -} - -const LinphoneAddress *linphone_conference_participant_event_get_participant_address ( - const LinphoneConferenceParticipantEvent *conference_participant_event -) { return L_GET_C_BACK_PTR( - &L_GET_CPP_PTR_FROM_C_OBJECT(conference_participant_event)->getParticipantAddress() + &static_pointer_cast( + L_GET_CPP_PTR_FROM_C_OBJECT(event_log) + )->getParticipantAddress() ); } @@ -276,49 +242,14 @@ const LinphoneAddress *linphone_conference_participant_event_get_participant_add // ConferenceParticipantDeviceEvent. // ----------------------------------------------------------------------------- -LinphoneConferenceParticipantDeviceEvent *linphone_conference_participant_device_event_new ( - LinphoneEventLogType type, - time_t time, - const LinphoneAddress *conference_address, - unsigned int notify_id, - const LinphoneAddress *participant_address, - const LinphoneAddress *gruu_address -) { - LinphoneConferenceParticipantDeviceEvent *conference_participant_device_event = L_INIT( - ConferenceParticipantDeviceEvent - ); - L_SET_CPP_PTR_FROM_C_OBJECT( - conference_participant_device_event, - make_shared( - static_cast(type), - time, - *L_GET_CPP_PTR_FROM_C_OBJECT(conference_address), - notify_id, - *L_GET_CPP_PTR_FROM_C_OBJECT(participant_address), - *L_GET_CPP_PTR_FROM_C_OBJECT(gruu_address) - ) - ); - return conference_participant_device_event; -} +const LinphoneAddress *linphone_event_log_get_gruu_address (const LinphoneEventLog *event_log) { + if (!isConferenceParticipantDeviceType(linphone_event_log_get_type(event_log))) + return nullptr; -LinphoneConferenceParticipantDeviceEvent *linphone_conference_participant_device_event_ref ( - LinphoneConferenceParticipantDeviceEvent *conference_participant_device_event -) { - belle_sip_object_ref(conference_participant_device_event); - return conference_participant_device_event; -} - -void linphone_conference_participant_device_event_unref ( - LinphoneConferenceParticipantDeviceEvent *conference_participant_device_event -) { - belle_sip_object_unref(conference_participant_device_event); -} - -const LinphoneAddress *linphone_conference_participant_device_event_get_gruu_address ( - const LinphoneConferenceParticipantDeviceEvent *conference_participant_device_event -) { return L_GET_C_BACK_PTR( - &L_GET_CPP_PTR_FROM_C_OBJECT(conference_participant_device_event)->getGruuAddress() + &static_pointer_cast( + L_GET_CPP_PTR_FROM_C_OBJECT(event_log) + )->getGruuAddress() ); } @@ -326,43 +257,13 @@ const LinphoneAddress *linphone_conference_participant_device_event_get_gruu_add // ConferenceSubjectEvent. // ----------------------------------------------------------------------------- -LinphoneConferenceSubjectEvent *linphone_conference_subject_event_new ( - LinphoneEventLogType type, - time_t time, - const LinphoneAddress *conference_address, - unsigned int notify_id, - const char *subject -) { - LinphoneConferenceSubjectEvent *conference_subject_event = L_INIT(ConferenceSubjectEvent); - L_SET_CPP_PTR_FROM_C_OBJECT( - conference_subject_event, - make_shared( - time, - *L_GET_CPP_PTR_FROM_C_OBJECT(conference_address), - notify_id, - L_C_TO_STRING(subject) - ) - ); - return conference_subject_event; -} +LINPHONE_PUBLIC const char *linphone_event_log_get_subject (const LinphoneEventLog *event_log) { + if (!isConferenceSubjectType(linphone_event_log_get_type(event_log))) + return nullptr; -LinphoneConferenceSubjectEvent *linphone_conference_subject_event_ref ( - LinphoneConferenceSubjectEvent *conference_subject_event -) { - belle_sip_object_ref(conference_subject_event); - return conference_subject_event; -} - -void linphone_conference_subject_event_unref ( - LinphoneConferenceSubjectEvent *conference_subject_event -) { - belle_sip_object_unref(conference_subject_event); -} - -LINPHONE_PUBLIC const char *linphone_conference_subject_event_get_subject ( - const LinphoneConferenceSubjectEvent *conference_subject_event -) { return L_STRING_TO_C( - L_GET_CPP_PTR_FROM_C_OBJECT(conference_subject_event)->getSubject() + static_pointer_cast( + L_GET_CPP_PTR_FROM_C_OBJECT(event_log) + )->getSubject() ); } diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index 1cb7063a6..851385f5b 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -36,13 +36,6 @@ F(Call, Call) \ F(ChatMessage, ChatMessage) \ F(ChatRoom, ChatRoom) \ - F(ConferenceCallEvent, ConferenceCallEvent) \ - F(ConferenceChatMessageEvent, ConferenceChatMessageEvent) \ - F(ConferenceEvent, ConferenceEvent) \ - F(ConferenceNotifiedEvent, ConferenceNotifiedEvent) \ - F(ConferenceParticipantDeviceEvent, ConferenceParticipantDeviceEvent) \ - F(ConferenceParticipantEvent, ConferenceParticipantEvent) \ - F(ConferenceSubjectEvent, ConferenceSubjectEvent) \ F(DialPlan, DialPlan) \ F(EventLog, EventLog) \ F(MediaSessionParams, CallParams) \ @@ -51,7 +44,14 @@ #define L_REGISTER_SUBTYPES(F) \ F(ChatRoom, BasicChatRoom) \ F(ChatRoom, ClientGroupChatRoom) \ - F(ChatRoom, RealTimeTextChatRoom) + F(ChatRoom, RealTimeTextChatRoom) \ + F(EventLog, ConferenceCallEvent) \ + F(EventLog, ConferenceChatMessageEvent) \ + F(EventLog, ConferenceEvent) \ + F(EventLog, ConferenceNotifiedEvent) \ + F(EventLog, ConferenceParticipantDeviceEvent) \ + F(EventLog, ConferenceParticipantEvent) \ + F(EventLog, ConferenceSubjectEvent) // ============================================================================= // Register belle-sip ID. diff --git a/src/core/core.h b/src/core/core.h index 0aeff72e4..d0eb6ac4b 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -38,11 +38,12 @@ friend class ClientGroupChatRoom; public: Core (LinphoneCore *cCore); + std::string getDataPath() const; + std::string getConfigPath() const; + std::shared_ptr createClientGroupChatRoom (const std::string &subject); std::shared_ptr getOrCreateChatRoom (const std::string &peerAddress, bool isRtt = false) const; const std::list> &getChatRooms () const; - std::string getDataPath() const; - std::string getConfigPath() const; private: L_DECLARE_PRIVATE(Core); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index df3d034c2..0dab63c1b 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -941,7 +941,7 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} query += buildSqlEventFilter({ ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter }, mask, "AND"); - query += " ORDER BY id DESC"; + query += " ORDER BY date DESC"; if (end >= 0) query += " LIMIT " + Utils::toString(end + 1 - begin); From 639792b0e760e23bb59feaf86db64d4430dce8a2 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 25 Oct 2017 11:10:10 +0200 Subject: [PATCH 0629/2215] fix(c-event-log): wrap correctly get_subject --- include/linphone/api/c-event-log.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linphone/api/c-event-log.h b/include/linphone/api/c-event-log.h index 46dac0017..c3f9e67c6 100644 --- a/include/linphone/api/c-event-log.h +++ b/include/linphone/api/c-event-log.h @@ -136,7 +136,7 @@ LINPHONE_PUBLIC const LinphoneAddress *linphone_event_log_get_gruu_address (cons * @param[in] event_log A #LinphoneEventLog object. * @return The conference subject. */ -LINPHONE_PUBLIC const char *linphone_event_get_subject (const LinphoneEventLog *event_log); +LINPHONE_PUBLIC const char *linphone_event_log_get_subject (const LinphoneEventLog *event_log); /** * @} From a0e041ec1e9fd32b214e7a14e491aca14f7bf5f1 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 25 Oct 2017 11:46:23 +0200 Subject: [PATCH 0630/2215] feat(MainDb): basix fetch of chatrooms --- src/core/core.h | 3 ++- src/db/main-db.cpp | 54 +++++++++++++++++++++++++++------------------- src/db/main-db.h | 1 - 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/core/core.h b/src/core/core.h index d0eb6ac4b..4e4cf5d04 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -41,9 +41,10 @@ public: std::string getDataPath() const; std::string getConfigPath() const; + const std::list> &getChatRooms () const; + std::shared_ptr createClientGroupChatRoom (const std::string &subject); std::shared_ptr getOrCreateChatRoom (const std::string &peerAddress, bool isRtt = false) const; - const std::list> &getChatRooms () const; private: L_DECLARE_PRIVATE(Core); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 0dab63c1b..6888d5487 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1004,37 +1004,51 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} // ----------------------------------------------------------------------------- list> MainDb::getChatRooms () const { - list> chatRooms; - // TODO. - return chatRooms; -} + static const string query = "SELECT value, creation_date, last_update_date, capabilities, subject, last_notify_id" + " FROM chat_room, sip_address" + " WHERE peer_sip_address_id = id"; -shared_ptr MainDb::findChatRoom (const string &peerAddress) const { L_D(); - // TODO: Use core cache. + list> chatRooms; L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); - tm creationDate; - tm lastUpdateDate; - int capabilities; - string subject; + soci::rowset rows = (session->prepare << query); + for (const auto &row : rows) { + string sipAddress = row.get(0); + tm creationDate = row.get(1); + tm lastUpdateDate = row.get(2); + int capabilities = row.get(3); + string subject = row.get(4); + unsigned int lastNotifyId = row.get(5); - *session << "SELECT creation_date, last_update_date, capabilities, subject " - " FROM chat_room" - " WHERE peer_sip_address_id = (" - " SELECT id from sip_address WHERE value = :peerAddress" - " )", soci::use(peerAddress), soci::into(creationDate), soci::into(lastUpdateDate), - soci::use(capabilities), soci::use(subject); + (void)sipAddress; + (void)creationDate; + (void)lastUpdateDate; + (void)capabilities; + (void)subject; + (void)lastNotifyId; - // TODO. + if (capabilities & static_cast(ChatRoom::Capabilities::Basic)) { + if (capabilities & static_cast(ChatRoom::Capabilities::RealTimeText)) { + // TODO. + continue; + } + // TODO. + continue; + } + + if (capabilities & static_cast(ChatRoom::Capabilities::Conference)) { + // TODO. + } + } L_END_LOG_EXCEPTION - return shared_ptr(); + return chatRooms; } // ----------------------------------------------------------------------------- @@ -1228,10 +1242,6 @@ shared_ptr MainDb::findChatRoom (const string &peerAddress) const { void MainDb::cleanHistory (const string &, FilterMask) {} - shared_ptr MainDb::findChatRoom (const string &) const { - return nullptr; - } - bool MainDb::import (Backend, const string &) { return false; } diff --git a/src/db/main-db.h b/src/db/main-db.h index 7a0367a62..86edc9ca1 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -71,7 +71,6 @@ public: // ChatRooms. std::list> getChatRooms () const; - std::shared_ptr findChatRoom (const std::string &peerAddress) const; // Import legacy messages from old db. bool import (Backend backend, const std::string ¶meters) override; From 2243783c16095ebc9b2b364dc7f955fccea232e7 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 25 Oct 2017 11:50:10 +0200 Subject: [PATCH 0631/2215] add possibility to notify conference event to only one participant --- .../local-conference-event-handler-p.h | 17 ++--- .../local-conference-event-handler.cpp | 64 +++++++++++++------ 2 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/conference/local-conference-event-handler-p.h b/src/conference/local-conference-event-handler-p.h index 82b11f083..b194d65c4 100644 --- a/src/conference/local-conference-event-handler-p.h +++ b/src/conference/local-conference-event-handler-p.h @@ -33,13 +33,14 @@ public: void notifyFullState (const std::string ¬ify, LinphoneEvent *lev); void notifyAllExcept (const std::string ¬ify, const Address &addr); void notifyAll (const std::string ¬ify); - std::string createNotifyFullState (); - std::string createNotifyParticipantAdded (const Address &addr); - std::string createNotifyParticipantRemoved (const Address &addr); - std::string createNotifyParticipantAdmined (const Address &addr, bool isAdmin); - std::string createNotifySubjectChanged (); - std::string createNotifyParticipantDeviceAdded (const Address &addr, const Address &gruu); - std::string createNotifyParticipantDeviceRemoved (const Address &addr, const Address &gruu); + void notifyParticipant (const std::string ¬ify, const Address &addr); + std::string createNotifyFullState (int notifyId = -1); + std::string createNotifyParticipantAdded (const Address &addr, int notifyId = -1); + std::string createNotifyParticipantRemoved (const Address &addr, int notifyId = -1); + std::string createNotifyParticipantAdmined (const Address &addr, bool isAdmin, int notifyId = -1); + std::string createNotifySubjectChanged (int notifyId = -1); + std::string createNotifyParticipantDeviceAdded (const Address &addr, const Address &gruu, int notifyId = -1); + std::string createNotifyParticipantDeviceRemoved (const Address &addr, const Address &gruu, int notifyId = -1); inline unsigned int getLastNotify () const { return lastNotify; }; @@ -48,7 +49,7 @@ private: LocalConference *conf = nullptr; unsigned int lastNotify = 0; - std::string createNotify (Xsd::ConferenceInfo::ConferenceType confInfo); + std::string createNotify (Xsd::ConferenceInfo::ConferenceType confInfo, int notifyId = -1); void sendNotify (const std::string ¬ify, const Address &addr); L_DECLARE_PUBLIC(LocalConferenceEventHandler); diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 94ca0c870..0eb844d3d 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -23,6 +23,7 @@ #include "conference/participant-p.h" #include "linphone/utils/utils.h" #include "local-conference-event-handler-p.h" +#include "logger/logger.h" #include "object/object-p.h" #include "private.h" @@ -67,9 +68,22 @@ void LocalConferenceEventHandlerPrivate::notifyAll (const string ¬ify) { } } -string LocalConferenceEventHandlerPrivate::createNotify (ConferenceType confInfo) { - lastNotify = lastNotify + 1; - confInfo.setVersion(lastNotify); +void LocalConferenceEventHandlerPrivate::notifyParticipant (const string ¬ify, const Address &addr) { + Address cleanedAddr(addr); + cleanedAddr.setPort(0); + shared_ptr participant = conf->findParticipant(cleanedAddr); + if (participant->getPrivate()->isSubscribedToConferenceEventPackage()) + sendNotify(notify, participant->getAddress()); +} + +string LocalConferenceEventHandlerPrivate::createNotify (ConferenceType confInfo, int notifyId) { + if (notifyId == -1) { + lastNotify = lastNotify + 1; + confInfo.setVersion(lastNotify); + } else { + confInfo.setVersion(static_cast(notifyId)); + } + if (!confInfo.getConferenceDescription()) { ConferenceDescriptionType description = ConferenceDescriptionType(); confInfo.setConferenceDescription(description); @@ -85,7 +99,7 @@ string LocalConferenceEventHandlerPrivate::createNotify (ConferenceType confInfo return notify.str(); } -string LocalConferenceEventHandlerPrivate::createNotifyFullState () { +string LocalConferenceEventHandlerPrivate::createNotifyFullState (int notifyId) { string entity = conf->getConferenceAddress().asStringUriOnly(); string subject = conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); @@ -116,10 +130,10 @@ string LocalConferenceEventHandlerPrivate::createNotifyFullState () { confInfo.getUsers()->getUser().push_back(user); } - return createNotify(confInfo); + return createNotify(confInfo, notifyId); } -string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const Address &addr) { +string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const Address &addr, int notifyId) { string entity = conf->getConferenceAddress().asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; @@ -146,10 +160,10 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const A confInfo.getUsers()->getUser().push_back(user); - return createNotify(confInfo); + return createNotify(confInfo, notifyId); } -string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved (const Address &addr) { +string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved (const Address &addr, int notifyId) { string entity = conf->getConferenceAddress().asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; @@ -160,10 +174,10 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved (const user.setState("deleted"); confInfo.getUsers()->getUser().push_back(user); - return createNotify(confInfo); + return createNotify(confInfo, notifyId); } -string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined (const Address &addr, bool isAdmin) { +string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined (const Address &addr, bool isAdmin, int notifyId) { string entity = conf->getConferenceAddress().asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; @@ -177,10 +191,10 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined (const user.setState("partial"); confInfo.getUsers()->getUser().push_back(user); - return createNotify(confInfo); + return createNotify(confInfo, notifyId); } -string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged () { +string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged (int notifyId) { string entity = conf->getConferenceAddress().asStringUriOnly(); string subject = conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); @@ -188,10 +202,10 @@ string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged () { confDescr.setSubject(subject); confInfo.setConferenceDescription((const ConferenceDescriptionType)confDescr); - return createNotify(confInfo); + return createNotify(confInfo, notifyId); } -string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceAdded (const Address &addr, const Address &gruu) { +string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceAdded (const Address &addr, const Address &gruu, int notifyId) { string entity = conf->getConferenceAddress().asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; @@ -212,10 +226,10 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceAdded (c confInfo.getUsers()->getUser().push_back(user); - return createNotify(confInfo); + return createNotify(confInfo, notifyId); } -string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceRemoved (const Address &addr, const Address &gruu) { +string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceRemoved (const Address &addr, const Address &gruu, int notifyId) { string entity = conf->getConferenceAddress().asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); UsersType users; @@ -236,7 +250,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceRemoved confInfo.getUsers()->getUser().push_back(user); - return createNotify(confInfo); + return createNotify(confInfo, notifyId); } void LocalConferenceEventHandlerPrivate::sendNotify (const string ¬ify, const Address &addr) { @@ -250,7 +264,8 @@ void LocalConferenceEventHandlerPrivate::sendNotify (const string ¬ify, const // ============================================================================= -LocalConferenceEventHandler::LocalConferenceEventHandler (LinphoneCore *core, LocalConference *localConf) : Object(*new LocalConferenceEventHandlerPrivate) { +LocalConferenceEventHandler::LocalConferenceEventHandler (LinphoneCore *core, LocalConference *localConf) : + Object(*new LocalConferenceEventHandlerPrivate) { L_D(); xercesc::XMLPlatformUtils::Initialize(); d->conf = localConf; @@ -272,12 +287,19 @@ void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) { bctbx_free(addrStr); if (participant) { if (linphone_event_get_subscription_state(lev) == LinphoneSubscriptionActive) { - int lastNotify = Utils::stoi(linphone_event_get_custom_header(lev, "Last-Notify-Version")); - if(lastNotify == 0) { + unsigned int lastNotify = static_cast(Utils::stoi(linphone_event_get_custom_header(lev, "Last-Notify-Version"))); + if (lastNotify == 0) { + lInfo() << "Sending initial notify of conference:" << d->conf->getConferenceAddress().asStringUriOnly() << " to: " << addrStr; participant->getPrivate()->subscribeToConferenceEventPackage(true); d->notifyFullState(d->createNotifyFullState(), lev); - } else { + } else if (lastNotify < d->lastNotify) { + lInfo() << "Sending all missed notify for conference:" << d->conf->getConferenceAddress().asStringUriOnly() << + " from: " << lastNotify << " to: " << addrStr; // TODO : send all missed notify from lastNotify to d->lastNotify + } else if (lastNotify > d->lastNotify) { + lError() << "last notify received by client: [" << lastNotify <<"] for confernce:" << + d->conf->getConferenceAddress().asStringUriOnly() << + " should not be higher than last notify sent by server: [" << d->lastNotify << "]."; } } else if (linphone_event_get_subscription_state(lev) == LinphoneSubscriptionTerminated) participant->getPrivate()->subscribeToConferenceEventPackage(false); From 34b2882e3831f9b176a88a4f99618e7058a9f5bd Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 26 Oct 2017 10:08:53 +0200 Subject: [PATCH 0632/2215] feat(Core): use chat room api from new core --- coreapi/callbacks.c | 16 +- coreapi/chat.c | 100 ++--------- coreapi/linphonecore.c | 70 ++------ coreapi/private.h | 18 +- coreapi/tester_utils.h | 3 +- include/linphone/utils/utils.h | 1 + src/c-wrapper/api/c-chat-room.cpp | 16 +- src/chat/chat-room/basic-chat-room.cpp | 3 +- src/chat/chat-room/chat-room.h | 1 + src/chat/chat-room/client-group-chat-room.cpp | 14 +- .../chat-room/real-time-text-chat-room.cpp | 5 +- src/core/core-p.h | 12 +- src/core/core.cpp | 165 +++++++++++++++--- src/core/core.h | 21 ++- src/core/paths/paths-android.cpp | 19 +- src/core/paths/paths-android.h | 1 + src/core/paths/paths-apple.h | 1 + src/core/paths/paths-linux.cpp | 24 ++- src/core/paths/paths-linux.h | 1 + src/core/paths/paths-windows.cpp | 6 +- src/core/paths/paths-windows.h | 1 + src/core/paths/paths.cpp | 16 +- src/core/paths/paths.h | 2 +- .../platform-helpers/platform-helpers.cpp | 6 +- src/db/main-db-p.h | 2 + src/db/main-db.cpp | 95 ++++++---- src/db/main-db.h | 5 +- src/utils/utils.cpp | 4 + tester/main-db-tester.cpp | 10 +- 29 files changed, 359 insertions(+), 279 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index b1dd16297..ba4cea411 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -45,6 +45,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "conference/session/call-session.h" #include "conference/session/media-session-p.h" #include "conference/session/media-session.h" +#include "core/core-p.h" using namespace LinphonePrivate; @@ -724,7 +725,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ LinphoneCore *lc = reinterpret_cast(op->get_sal()->get_user_pointer()); if (addr.hasUriParam("method") && (addr.getUriParamValue("method") == "BYE")) { // The server asks a participant to leave a chat room - LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, addr.asStringUriOnly().c_str()); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(addr)); if (cr) { L_GET_CPP_PTR_FROM_C_OBJECT(cr)->leave(); static_cast(op)->reply(SalReasonNone); @@ -732,7 +733,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ } static_cast(op)->reply(SalReasonDeclined); } else if (addr.hasParam("admin")) { - LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, op->get_to()); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(Address(op->get_to()))); if (cr) { Address fromAddr(op->get_from()); std::shared_ptr participant = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(fromAddr); @@ -749,11 +750,12 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ return; } } else { - LinphoneChatRoom *cr = _linphone_core_join_client_group_chat_room(lc, addr); - if (cr) { - static_cast(op)->reply(SalReasonNone); - return; - } + LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); + L_GET_PRIVATE(lc->cppCore)->insertChatRoomWithDb(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); + + static_cast(op)->reply(SalReasonNone); + return; } } } diff --git a/coreapi/chat.c b/coreapi/chat.c index dad0c6940..75a4e9636 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -38,9 +38,10 @@ #include "c-wrapper/c-wrapper.h" #include "chat/chat-room/basic-chat-room.h" #include "chat/chat-room/client-group-chat-room.h" -#include "chat/chat-room/real-time-text-chat-room.h" #include "chat/chat-room/real-time-text-chat-room-p.h" +#include "chat/chat-room/real-time-text-chat-room.h" #include "content/content-type.h" +#include "core/core.h" using namespace std; @@ -56,14 +57,11 @@ bool_t linphone_core_chat_enabled(const LinphoneCore *lc) { return lc->chat_deny_code != LinphoneReasonNone; } -const bctbx_list_t *linphone_core_get_chat_rooms(LinphoneCore *lc) { - return lc->chatrooms; -} - -static LinphoneChatRoom *_linphone_core_create_chat_room(LinphoneCore *lc, const LinphoneAddress *addr) { - LinphoneChatRoom *cr = linphone_chat_room_new(lc, addr); - lc->chatrooms = bctbx_list_append(lc->chatrooms, (void *)cr); - return cr; +const bctbx_list_t *linphone_core_get_chat_rooms (LinphoneCore *lc) { + if (lc->chat_rooms) + bctbx_list_free_with_data(lc->chat_rooms, (bctbx_list_free_func)linphone_chat_room_unref); + lc->chat_rooms = L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(lc->cppCore->getChatRooms()); + return lc->chat_rooms; } LinphoneChatRoom *_linphone_core_create_chat_room_from_call(LinphoneCall *call){ @@ -73,91 +71,25 @@ LinphoneChatRoom *_linphone_core_create_chat_room_from_call(LinphoneCall *call){ return cr; } -static LinphoneChatRoom *_linphone_core_create_chat_room_from_url(LinphoneCore *lc, const char *to) { - LinphoneAddress *parsed_url = NULL; - if ((parsed_url = linphone_core_interpret_url(lc, to)) != NULL) { - return _linphone_core_create_chat_room(lc, parsed_url); - } - return NULL; +LinphoneChatRoom *linphone_core_get_chat_room (LinphoneCore *lc, const LinphoneAddress *addr) { + return L_GET_C_BACK_PTR(lc->cppCore->getOrCreateBasicChatRoom(*L_GET_CPP_PTR_FROM_C_OBJECT(addr))); } -static bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from) { - LinphoneAddress *addr = linphone_address_new(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getPeerAddress().asString().c_str()); - bool_t result = linphone_address_weak_equal(addr, from); - linphone_address_unref(addr); - return result; +LinphoneChatRoom *linphone_core_create_client_group_chat_room (LinphoneCore *lc, const char *subject) { + return L_GET_C_BACK_PTR(lc->cppCore->createClientGroupChatRoom(L_C_TO_STRING(subject))); } -LinphoneChatRoom *_linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr) { - LinphoneChatRoom *cr = NULL; - bctbx_list_t *elem; - for (elem = lc->chatrooms; elem != NULL; elem = bctbx_list_next(elem)) { - cr = (LinphoneChatRoom *)elem->data; - if (linphone_chat_room_matches(cr, addr)) { - break; - } - cr = NULL; - } - return cr; -} - -static LinphoneChatRoom *_linphone_core_get_or_create_chat_room(LinphoneCore *lc, const char *to) { - LinphoneAddress *to_addr = linphone_core_interpret_url(lc, to); - LinphoneChatRoom *ret; - - if (to_addr == NULL) { - ms_error("linphone_core_get_or_create_chat_room(): Cannot make a valid address with %s", to); - return NULL; - } - ret = _linphone_core_get_chat_room(lc, to_addr); - linphone_address_unref(to_addr); - if (!ret) { - ret = _linphone_core_create_chat_room_from_url(lc, to); - } - return ret; -} - -LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr) { - LinphoneChatRoom *ret = _linphone_core_get_chat_room(lc, addr); - if (!ret) { - ret = _linphone_core_create_chat_room(lc, addr); - } - return ret; -} - -LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, const char *subject) { - const char *factoryUri = linphone_core_get_conference_factory_uri(lc); - if (!factoryUri) - return nullptr; - LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, factoryUri, subject); - lc->chatrooms = bctbx_list_append(lc->chatrooms, cr); - return cr; -} - -LinphoneChatRoom *_linphone_core_join_client_group_chat_room (LinphoneCore *lc, const LinphonePrivate::Address &addr) { - LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); - lc->chatrooms = bctbx_list_append(lc->chatrooms, cr); - return cr; -} - -void linphone_core_delete_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr) { - if (bctbx_list_find(lc->chatrooms, cr)) { - lc->chatrooms = bctbx_list_remove(lc->chatrooms, cr); - linphone_chat_room_delete_history(cr); - linphone_chat_room_unref(cr); - } else { - ms_error("linphone_core_delete_chat_room(): chatroom [%p] isn't part of LinphoneCore.", cr); - } +void linphone_core_delete_chat_room (LinphoneCore *, LinphoneChatRoom *cr) { + LinphonePrivate::Core::deleteChatRoom(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); } LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const char *to) { - return _linphone_core_get_or_create_chat_room(lc, to); + return L_GET_C_BACK_PTR(lc->cppCore->getOrCreateBasicChatRoom(L_C_TO_STRING(to))); } int linphone_core_message_received(LinphoneCore *lc, LinphonePrivate::SalOp *op, const SalMessage *sal_msg) { LinphoneReason reason = LinphoneReasonNotAcceptable; - LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, op->get_from()); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(LinphonePrivate::Address(op->get_from()))); if (cr) reason = L_GET_PRIVATE_FROM_C_OBJECT(cr)->messageReceived(op, sal_msg); else { @@ -171,8 +103,6 @@ int linphone_core_message_received(LinphoneCore *lc, LinphonePrivate::SalOp *op, return reason; } - - void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, uint32_t character, LinphoneCall *call) { if (linphone_core_realtime_text_enabled(lc)) { shared_ptr rttcr = diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 47be80186..2221eef8b 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -37,6 +37,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include #include + #include "mediastreamer2/dtmfgen.h" #include "mediastreamer2/mediastream.h" #include "mediastreamer2/msequalizer.h" @@ -45,8 +46,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mediastreamer2/msjpegwriter.h" #include "mediastreamer2/msogl.h" #include "mediastreamer2/msvolume.h" + #include "chat/chat-room/client-group-chat-room-p.h" #include "conference/remote-conference-event-handler.h" +#include "core/core.h" // For migration purpose. #include "address/address-p.h" @@ -2128,9 +2131,7 @@ static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEve } } else if (strcmp(notified_event, "conference") == 0) { const LinphoneAddress *resource = linphone_event_get_resource(lev); - char *resourceUri = linphone_address_as_string_uri_only(resource); - LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, resourceUri); - bctbx_free(resourceUri); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(*L_GET_CPP_PTR_FROM_C_OBJECT(resource))); if (cr) L_GET_PRIVATE_FROM_C_OBJECT(cr, ClientGroupChatRoom)->notifyReceived(linphone_content_get_string_buffer(body)); } @@ -2234,7 +2235,8 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig lc->sal->set_user_pointer(lc); lc->sal->set_callbacks(&linphone_sal_callbacks); - new(&lc->cppCore) Core(lc); + new(&lc->cppCore) std::shared_ptr(); + lc->cppCore = ObjectFactory::create(lc); #ifdef TUNNEL_ENABLED lc->tunnel=linphone_core_tunnel_new(lc); @@ -2266,7 +2268,6 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig linphone_configuring_terminated(lc, LinphoneConfiguringSkipped, NULL); } // else linphone_core_start will be called after the remote provisioning (see linphone_core_iterate) lc->bw_controller = ms_bandwidth_controller_new(); - lc->group_chat_rooms = bctbx_mmap_cchar_new(); } #ifdef __ANDROID__ @@ -2280,7 +2281,7 @@ static void _linphone_core_set_system_context(LinphoneCore *lc, void *system_con } #else static void _linphone_core_set_system_context(LinphoneCore *lc, void *system_context){ - + } #endif @@ -5873,7 +5874,7 @@ void sip_config_uninit(LinphoneCore *lc) delete lc->sal; lc->sal=NULL; - lc->cppCore.~Core(); + lc->cppCore.~shared_ptr(); if (lc->sip_conf.guessed_contact) ms_free(lc->sip_conf.guessed_contact); @@ -6043,9 +6044,7 @@ static void linphone_core_uninit(LinphoneCore *lc) ms_usleep(10000); } - lc->chatrooms = bctbx_list_free_with_data(lc->chatrooms, (MSIterateFunc)linphone_chat_room_release); - if (lc->group_chat_rooms) - bctbx_mmap_cchar_delete_with_data(lc->group_chat_rooms, (void (*)(void *))linphone_chat_room_unref); + lc->chat_rooms = bctbx_list_free_with_data(lc->chat_rooms, (bctbx_list_free_func)linphone_chat_room_unref); linphone_core_set_state(lc,LinphoneGlobalShutdown,"Shutting down"); #ifdef VIDEO_ENABLED @@ -6143,11 +6142,11 @@ static void set_sip_network_reachable(LinphoneCore* lc,bool_t is_sip_reachable, if (lc->sip_network_reachable==is_sip_reachable) return; // no change, ignore. lc->network_reachable_to_be_notified=TRUE; - + if (is_sip_reachable){ getPlatformHelpers(lc)->setDnsServers(); } - + ms_message("SIP network reachability state is now [%s]",is_sip_reachable?"UP":"DOWN"); for(elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; @@ -7149,53 +7148,6 @@ const char * linphone_core_get_conference_factory_uri(const LinphoneCore *lc) { return lp_config_get_string(linphone_core_get_config(lc), "misc", "conference_factory_uri", nullptr); } -bool_t _linphone_core_has_group_chat_room(const LinphoneCore *lc, const char *id) { - bool_t result; - bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, id); - bctbx_iterator_t *endit = bctbx_map_cchar_end(lc->group_chat_rooms); - result = !bctbx_iterator_cchar_equals(it, endit); - bctbx_iterator_cchar_delete(endit); - bctbx_iterator_cchar_delete(it); - return result; -} - -void _linphone_core_add_group_chat_room(LinphoneCore *lc, const LinphonePrivate::Address &addr, LinphoneChatRoom *cr) { - Address cleanedAddr(addr); - cleanedAddr.clean(); - cleanedAddr.setPort(0); - bctbx_pair_t *pair = reinterpret_cast(bctbx_pair_cchar_new(cleanedAddr.asStringUriOnly().c_str(), linphone_chat_room_ref(cr))); - bctbx_map_cchar_insert_and_delete(lc->group_chat_rooms, pair); -} - -void _linphone_core_remove_group_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr) { - const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(cr); - Address cleanedAddr(*L_GET_CPP_PTR_FROM_C_OBJECT(confAddr)); - cleanedAddr.clean(); - cleanedAddr.setPort(0); - bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, cleanedAddr.asStringUriOnly().c_str()); - bctbx_iterator_t *endit = bctbx_map_cchar_end(lc->group_chat_rooms); - if (!bctbx_iterator_cchar_equals(it, endit)) { - bctbx_map_cchar_erase(lc->group_chat_rooms, it); - linphone_chat_room_unref(cr); - } - bctbx_iterator_cchar_delete(endit); - bctbx_iterator_cchar_delete(it); -} - -LinphoneChatRoom *_linphone_core_find_group_chat_room(const LinphoneCore *lc, const char *id) { - LinphoneChatRoom *result = nullptr; - Address cleanedAddr(id); - cleanedAddr.clean(); - cleanedAddr.setPort(0); - bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, cleanedAddr.asStringUriOnly().c_str()); - bctbx_iterator_t *endit = bctbx_map_cchar_end(lc->group_chat_rooms); - if (!bctbx_iterator_cchar_equals(it, endit)) - result = reinterpret_cast(bctbx_pair_cchar_get_second(bctbx_iterator_cchar_get_pair(it))); - bctbx_iterator_cchar_delete(endit); - bctbx_iterator_cchar_delete(it); - return result; -} - void linphone_core_set_tls_cert(LinphoneCore *lc, const char *tls_cert) { if (lc->tls_cert) { ms_free(lc->tls_cert); diff --git a/coreapi/private.h b/coreapi/private.h index e00100c3f..be2eec3f1 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -25,6 +25,8 @@ #ifndef _PRIVATE_H #define _PRIVATE_H +#include + #include "linphone/core.h" #include "linphone/friend.h" #include "linphone/friendlist.h" @@ -34,7 +36,6 @@ #include "address/address.h" #include "c-wrapper/internal/c-sal.h" -#include "core/core.h" #include "sal/call-op.h" #include "sal/event-op.h" #include "sal/message-op.h" @@ -456,9 +457,6 @@ bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription extern LinphonePrivate::Sal::Callbacks linphone_sal_callbacks; LINPHONE_PUBLIC bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); LINPHONE_PUBLIC bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc); -bool_t _linphone_core_has_group_chat_room (const LinphoneCore *lc, const char *id); -void _linphone_core_add_group_chat_room (LinphoneCore *lc, const LinphonePrivate::Address &addr, LinphoneChatRoom *cr); -void _linphone_core_remove_group_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr); void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description); @@ -473,7 +471,6 @@ void _linphone_proxy_config_release_ops(LinphoneProxyConfig *obj); /*chat*/ LinphoneChatRoom * linphone_chat_room_new(LinphoneCore *core, const LinphoneAddress *addr); -LinphoneChatRoom *_linphone_core_join_client_group_chat_room (LinphoneCore *core, const LinphonePrivate::Address &addr); LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, const char *uri, const char *subject); void linphone_chat_room_release(LinphoneChatRoom *cr); void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call); @@ -810,6 +807,10 @@ typedef struct _LCCallbackObj { void *_user_data; } LCCallbackObj; +namespace LinphonePrivate { + class Core; +}; + struct _LinphoneCore { belle_sip_object_t base; @@ -819,7 +820,7 @@ struct _LinphoneCore LinphonePrivate::Sal *sal; // For migration purposes - LinphonePrivate::Core cppCore; + std::shared_ptr cppCore; void *platform_helper; /*is a LinphonePrivate::PlatformHelpers but cannot be used as is because private.h is compiled as C in testers.*/ @@ -847,8 +848,6 @@ struct _LinphoneCore MSList *calls; /* all the processed calls */ MSList *queued_calls; /* used by the autoreplier */ MSList *call_logs; - MSList *chatrooms; - bctbx_map_t *group_chat_rooms; int max_call_logs; int missed_calls; VideoPreview *previewstream; @@ -941,6 +940,9 @@ struct _LinphoneCore LinphoneImEncryptionEngine *im_encryption_engine; struct _LinphoneAccountCreatorService *default_ac_service; MSBandwidthController *bw_controller; + + // For migration purpose. + bctbx_list_t *chat_rooms; }; #ifdef __cplusplus diff --git a/coreapi/tester_utils.h b/coreapi/tester_utils.h index 0431d80de..12cf9b401 100644 --- a/coreapi/tester_utils.h +++ b/coreapi/tester_utils.h @@ -24,7 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/core.h" #include "linphone/tunnel.h" #include "c-wrapper/internal/c-sal.h" -#include +#include #include "quality_reporting.h" #include "vcard_private.h" @@ -94,7 +94,6 @@ LINPHONE_PUBLIC mblk_t *_linphone_call_stats_get_received_rtcp (const LinphoneCa LINPHONE_PUBLIC LinphoneQualityReporting *linphone_call_log_get_quality_reporting(LinphoneCallLog *call_log); LINPHONE_PUBLIC reporting_session_report_t **linphone_quality_reporting_get_reports(LinphoneQualityReporting *qreporting); -LINPHONE_PUBLIC LinphoneChatRoom *_linphone_core_find_group_chat_room(const LinphoneCore *lc, const char *id); LINPHONE_PUBLIC bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr); LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_from_db(LinphoneCore *lc, LinphoneFriendList *list); diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h index 6f5569192..f8e8a0929 100644 --- a/include/linphone/utils/utils.h +++ b/include/linphone/utils/utils.h @@ -106,6 +106,7 @@ namespace Utils { } LINPHONE_PUBLIC std::tm getLongAsTm (long time); + LINPHONE_PUBLIC long getTmAsLong (const std::tm &time); } LINPHONE_END_NAMESPACE diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index e112f83c4..c86f16391 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -205,7 +205,7 @@ bctbx_list_t *linphone_chat_room_get_history (LinphoneChatRoom *cr, int nb_messa bctbx_list_t *linphone_chat_room_get_history_events (LinphoneChatRoom *cr, int nb_events) { return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST( - L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore()->cppCore)->mainDb.getHistory( + L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore()->cppCore)->mainDb->getHistory( L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getPeerAddress().asStringUriOnly(), nb_events ) @@ -214,7 +214,7 @@ bctbx_list_t *linphone_chat_room_get_history_events (LinphoneChatRoom *cr, int n bctbx_list_t *linphone_chat_room_get_history_range_events (LinphoneChatRoom *cr, int begin, int end) { return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST( - L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore()->cppCore)->mainDb.getHistory( + L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore()->cppCore)->mainDb->getHistory( L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getPeerAddress().asStringUriOnly(), begin, end @@ -330,14 +330,10 @@ void linphone_chat_room_set_user_data (LinphoneChatRoom *cr, void *ud) { // ============================================================================= LinphoneChatRoom *linphone_chat_room_new (LinphoneCore *core, const LinphoneAddress *addr) { - LinphoneChatRoom *cr = L_INIT(ChatRoom); - if (linphone_core_realtime_text_enabled(core)) - L_SET_CPP_PTR_FROM_C_OBJECT(cr, LinphonePrivate::ObjectFactory::create(core, *L_GET_CPP_PTR_FROM_C_OBJECT(addr))); - else - L_SET_CPP_PTR_FROM_C_OBJECT(cr, LinphonePrivate::ObjectFactory::create(core, *L_GET_CPP_PTR_FROM_C_OBJECT(addr))); - L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); - L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Created); - return cr; + return L_GET_C_BACK_PTR(core->cppCore->getOrCreateBasicChatRoom( + *L_GET_CPP_PTR_FROM_C_OBJECT(addr), + linphone_core_realtime_text_enabled(core) + )); } LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, const char *uri, const char *subject) { diff --git a/src/chat/chat-room/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp index c439570fe..93d3ba079 100644 --- a/src/chat/chat-room/basic-chat-room.cpp +++ b/src/chat/chat-room/basic-chat-room.cpp @@ -35,7 +35,8 @@ BasicChatRoomPrivate::BasicChatRoomPrivate (LinphoneCore *core, const Address &p // ============================================================================= -BasicChatRoom::BasicChatRoom (LinphoneCore *core, const Address &peerAddress) : ChatRoom(*new BasicChatRoomPrivate(core, peerAddress)) {} +BasicChatRoom::BasicChatRoom (LinphoneCore *core, const Address &peerAddress) : + ChatRoom(*new BasicChatRoomPrivate(core, peerAddress)) {} // ----------------------------------------------------------------------------- diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index 562387c65..01a5108c8 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -30,6 +30,7 @@ LINPHONE_BEGIN_NAMESPACE class ChatRoomPrivate; class LINPHONE_PUBLIC ChatRoom : public Object, public ConferenceInterface { + friend class Core; friend class ChatMessage; friend class ChatMessagePrivate; diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 6d8b6ede5..73ac9d595 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -251,7 +251,7 @@ void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { dConference->conferenceAddress = addr; d->peerAddress = addr; d->setState(ChatRoom::State::Created); - _linphone_core_add_group_chat_room(d->core, addr, L_GET_C_BACK_PTR(this)); + d->core->cppCore->getPrivate()->insertChatRoomWithDb(getSharedFromThis()); } void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { @@ -283,7 +283,7 @@ void ClientGroupChatRoom::onParticipantAdded (time_t tm, const Address &addr) { dConference->eventHandler->getLastNotify(), addr ); - Conference::getCore()->cppCore.getPrivate()->mainDb.addEvent(event); + Conference::getCore()->cppCore->getPrivate()->mainDb->addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(event)); @@ -308,7 +308,7 @@ void ClientGroupChatRoom::onParticipantRemoved (time_t tm, const Address &addr) dConference->eventHandler->getLastNotify(), addr ); - Conference::getCore()->cppCore.getPrivate()->mainDb.addEvent(event); + Conference::getCore()->cppCore->getPrivate()->mainDb->addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(event)); @@ -339,7 +339,7 @@ void ClientGroupChatRoom::onParticipantSetAdmin (time_t tm, const Address &addr, dConference->eventHandler->getLastNotify(), addr ); - Conference::getCore()->cppCore.getPrivate()->mainDb.addEvent(event); + Conference::getCore()->cppCore->getPrivate()->mainDb->addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(event)); @@ -357,7 +357,7 @@ void ClientGroupChatRoom::onSubjectChanged (time_t tm, const std::string &subjec dConference->eventHandler->getLastNotify(), subject ); - Conference::getCore()->cppCore.getPrivate()->mainDb.addEvent(event); + Conference::getCore()->cppCore->getPrivate()->mainDb->addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(event)); @@ -386,7 +386,7 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (time_t tm, const Address &ad addr, gruu ); - Conference::getCore()->cppCore.getPrivate()->mainDb.addEvent(event); + Conference::getCore()->cppCore->getPrivate()->mainDb->addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(event)); @@ -415,7 +415,7 @@ void ClientGroupChatRoom::onParticipantDeviceRemoved (time_t tm, const Address & addr, gruu ); - Conference::getCore()->cppCore.getPrivate()->mainDb.addEvent(event); + Conference::getCore()->cppCore->getPrivate()->mainDb->addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(event)); diff --git a/src/chat/chat-room/real-time-text-chat-room.cpp b/src/chat/chat-room/real-time-text-chat-room.cpp index 1c47fd0c1..388a0d313 100644 --- a/src/chat/chat-room/real-time-text-chat-room.cpp +++ b/src/chat/chat-room/real-time-text-chat-room.cpp @@ -69,7 +69,7 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp pendingMessage->setToAddress( Address( linphone_call_get_dest_proxy(call) - ? linphone_address_as_string(linphone_call_get_dest_proxy(call)->identity_address) + ? linphone_address_as_string(linphone_call_get_dest_proxy(call)->identity_address) : linphone_core_get_identity(core) ) ); @@ -106,7 +106,8 @@ void RealTimeTextChatRoomPrivate::sendMessage (const std::shared_ptr(Capabilities::Basic) | static_cast(Capabilities::RealTimeText); diff --git a/src/core/core-p.h b/src/core/core-p.h index c402c6ccd..243fed9ac 100644 --- a/src/core/core-p.h +++ b/src/core/core-p.h @@ -30,12 +30,18 @@ LINPHONE_BEGIN_NAMESPACE class CorePrivate : public ObjectPrivate { public: - MainDb mainDb; - LinphoneCore *cCore; + std::unique_ptr mainDb; + LinphoneCore *cCore = nullptr; + + void insertChatRoomWithDb (const std::shared_ptr &chatRoom); + void deleteChatRoomWithDb (const std::string &peerAddress); private: + void insertChatRoom (const std::shared_ptr &chatRoom); + void deleteChatRoom (const std::string &peerAddress); + std::list> chatRooms; - std::unordered_map> chatRoomsMap; + std::unordered_map> chatRoomsByUri; L_DECLARE_PUBLIC(Core); }; diff --git a/src/core/core.cpp b/src/core/core.cpp index 3c34658c4..2bc55abf6 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -21,6 +21,8 @@ #include #include "chat/chat-room/basic-chat-room.h" +#include "chat/chat-room/chat-room-p.h" +#include "chat/chat-room/real-time-text-chat-room.h" #include "core-p.h" #include "db/main-db.h" #include "logger/logger.h" @@ -28,6 +30,7 @@ #include "paths/paths.h" // TODO: Remove me later. +#include "c-wrapper/c-wrapper.h" #include "private.h" #define LINPHONE_DB "linphone.db" @@ -39,41 +42,83 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE // ----------------------------------------------------------------------------- +// Helpers. +// ----------------------------------------------------------------------------- + +static inline Address getCleanedPeerAddress (const Address &peerAddress) { + Address cleanedAddress = peerAddress; + cleanedAddress.clean(); + cleanedAddress.setPort(0); + return cleanedAddress; +} + +// ----------------------------------------------------------------------------- +// CorePrivate: ChatRoom. +// ----------------------------------------------------------------------------- + +void CorePrivate::insertChatRoom (const shared_ptr &chatRoom) { + L_ASSERT(chatRoom); + L_ASSERT(chatRoom->getState() == ChatRoom::State::Created); + + string peerAddress = getCleanedPeerAddress(chatRoom->getPeerAddress()).asStringUriOnly(); + deleteChatRoom(peerAddress); + + chatRooms.push_back(chatRoom); + chatRoomsByUri[peerAddress] = chatRoom; +} + +void CorePrivate::deleteChatRoom (const string &peerAddress) { + auto it = chatRoomsByUri.find(peerAddress); + if (it != chatRoomsByUri.end()) + chatRooms.erase( + find_if(chatRooms.begin(), chatRooms.end(), [&peerAddress](const shared_ptr &chatRoom) { + return peerAddress == chatRoom->getPeerAddress().asStringUriOnly(); + }) + ); +} + +void CorePrivate::insertChatRoomWithDb (const shared_ptr &chatRoom) { + insertChatRoom(chatRoom); + mainDb->insertChatRoom( + getCleanedPeerAddress(chatRoom->getPeerAddress()).asStringUriOnly(), + chatRoom->getCapabilities() + ); +} + +void CorePrivate::deleteChatRoomWithDb (const string &peerAddress) { + deleteChatRoom(peerAddress); + mainDb->deleteChatRoom(peerAddress); +} + +// ============================================================================= Core::Core (LinphoneCore *cCore) : Object(*new CorePrivate) { L_D(); d->cCore = cCore; - const char *uri = lp_config_get_string(linphone_core_get_config(d->cCore), "server", "db_uri", NULL); - if (uri) { - AbstractDb::Backend backend = - strcmp(lp_config_get_string(linphone_core_get_config(d->cCore), "server", "db_backend", NULL), "mysql") == 0 + d->mainDb.reset(new MainDb(this)); + + AbstractDb::Backend backend; + string uri = L_C_TO_STRING(lp_config_get_string(linphone_core_get_config(d->cCore), "server", "db_uri", NULL)); + if (!uri.empty()) + backend = strcmp(lp_config_get_string(linphone_core_get_config(d->cCore), "server", "db_backend", NULL), "mysql") == 0 ? MainDb::Mysql : MainDb::Sqlite3; - lInfo() << "Creating " LINPHONE_DB " at: " << uri; - d->mainDb.connect(backend, uri); - return; + else { + backend = AbstractDb::Sqlite3; + uri = getDataPath() + "/" LINPHONE_DB; } - static string path = getDataPath() + "/" LINPHONE_DB; - lInfo() << "Creating " LINPHONE_DB " at: " << path; - d->mainDb.connect(MainDb::Sqlite3, path); + lInfo() << "Opening " LINPHONE_DB " at: " << uri; + if (!d->mainDb->connect(backend, uri)) + lFatal() << "Unable to open linphone database."; + + for (auto &chatRoom : d->mainDb->getChatRooms()) + d->insertChatRoom(chatRoom); } // ----------------------------------------------------------------------------- - -shared_ptr Core::createClientGroupChatRoom (const string &subject) { - // TODO. - return shared_ptr(); -} - -shared_ptr Core::getOrCreateChatRoom (const string &peerAddress, bool isRtt) const { - return shared_ptr(); -} - -const list> &Core::getChatRooms () const { - L_D(); - return d->chatRooms; -} +// Paths. +// ----------------------------------------------------------------------------- string Core::getDataPath() const { L_D(); @@ -85,6 +130,78 @@ string Core::getConfigPath() const { return Paths::getPath(Paths::Config, static_cast(d->cCore->platform_helper)); } +// ----------------------------------------------------------------------------- +// ChatRoom. +// ----------------------------------------------------------------------------- + +const list> &Core::getChatRooms () const { + L_D(); + return d->chatRooms; +} + +shared_ptr Core::findChatRoom (const Address &peerAddress) const { + L_D(); + auto it = d->chatRoomsByUri.find(getCleanedPeerAddress(peerAddress).asStringUriOnly()); + return it == d->chatRoomsByUri.cend() ? shared_ptr() : it->second; +} + +shared_ptr Core::createClientGroupChatRoom (const string &subject) { + L_D(); + + const char *factoryUri = linphone_core_get_conference_factory_uri(d->cCore); + if (!factoryUri) + return nullptr; + + return L_GET_CPP_PTR_FROM_C_OBJECT( + _linphone_client_group_chat_room_new(d->cCore, factoryUri, L_STRING_TO_C(subject)) + ); +} + +shared_ptr Core::getOrCreateBasicChatRoom (const Address &peerAddress, bool isRtt) { + L_D(); + + if (!peerAddress.isValid()) { + lWarning() << "Cannot find get or create chat room with invalid peer address."; + return nullptr; + } + + shared_ptr chatRoom = findChatRoom(peerAddress); + if (chatRoom) + return chatRoom; + + if (isRtt) + chatRoom = ObjectFactory::create(d->cCore, peerAddress); + else + chatRoom = ObjectFactory::create(d->cCore, peerAddress); + + chatRoom->getPrivate()->setState(ChatRoom::State::Instantiated); + chatRoom->getPrivate()->setState(ChatRoom::State::Created); + + d->insertChatRoomWithDb(chatRoom); + + return chatRoom; +} + +shared_ptr Core::getOrCreateBasicChatRoom (const string &peerAddress, bool isRtt) { + L_D(); + + LinphoneAddress *address = linphone_core_interpret_url(d->cCore, L_STRING_TO_C(peerAddress)); + if (!address) { + lError() << "Cannot make a valid address with: `" << peerAddress << "`."; + return nullptr; + } + + shared_ptr chatRoom = getOrCreateBasicChatRoom(*L_GET_CPP_PTR_FROM_C_OBJECT(address), isRtt); + linphone_address_unref(address); + return chatRoom; +} + +void Core::deleteChatRoom (const shared_ptr &chatRoom) { + CorePrivate *d = chatRoom->getCore()->cppCore->getPrivate(); + string peerAddress = getCleanedPeerAddress(chatRoom->getPeerAddress()).asStringUriOnly(); + d->deleteChatRoomWithDb(peerAddress); +} + // ----------------------------------------------------------------------------- LINPHONE_END_NAMESPACE diff --git a/src/core/core.h b/src/core/core.h index 4e4cf5d04..207e3275b 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -30,21 +30,36 @@ L_DECL_C_STRUCT(LinphoneCore); LINPHONE_BEGIN_NAMESPACE +class Address; class ChatRoom; class CorePrivate; class LINPHONE_PUBLIC Core : public Object { -friend class ClientGroupChatRoom; + friend class ClientGroupChatRoom; + public: + L_OVERRIDE_SHARED_FROM_THIS(Core); + Core (LinphoneCore *cCore); + // --------------------------------------------------------------------------- + // Paths. + // --------------------------------------------------------------------------- + std::string getDataPath() const; std::string getConfigPath() const; - const std::list> &getChatRooms () const; + // --------------------------------------------------------------------------- + // ChatRoom. + // --------------------------------------------------------------------------- + const std::list> &getChatRooms () const; + std::shared_ptr findChatRoom (const Address &peerAddress) const; std::shared_ptr createClientGroupChatRoom (const std::string &subject); - std::shared_ptr getOrCreateChatRoom (const std::string &peerAddress, bool isRtt = false) const; + std::shared_ptr getOrCreateBasicChatRoom (const Address &peerAddress, bool isRtt = false); + std::shared_ptr getOrCreateBasicChatRoom (const std::string &peerAddress, bool isRtt = false); + + static void deleteChatRoom (const std::shared_ptr &chatRoom); private: L_DECLARE_PRIVATE(Core); diff --git a/src/core/paths/paths-android.cpp b/src/core/paths/paths-android.cpp index b53adbd22..275c4ef7c 100644 --- a/src/core/paths/paths-android.cpp +++ b/src/core/paths/paths-android.cpp @@ -19,26 +19,27 @@ #include -#include "core/platform-helpers/platform-helpers.h" #include "linphone/utils/utils.h" +#include "core/platform-helpers/platform-helpers.h" + #include "paths-android.h" // ============================================================================= +using namespace std; + LINPHONE_BEGIN_NAMESPACE -std::string SysPaths::getDataPath (PlatformHelpers *platformHelper) { - if (!platformHelper) { - return Utils::getEmptyConstRefObject(); - } +string SysPaths::getDataPath (PlatformHelpers *platformHelper) { + if (!platformHelper) + return Utils::getEmptyConstRefObject(); return platformHelper->getDataPath(); } -std::string SysPaths::getConfigPath (PlatformHelpers *platformHelper) { - if (!platformHelper) { - return Utils::getEmptyConstRefObject(); - } +string SysPaths::getConfigPath (PlatformHelpers *platformHelper) { + if (!platformHelper) + return Utils::getEmptyConstRefObject(); return platformHelper->getConfigPath(); } diff --git a/src/core/paths/paths-android.h b/src/core/paths/paths-android.h index 7661ebb59..f4ac148cc 100644 --- a/src/core/paths/paths-android.h +++ b/src/core/paths/paths-android.h @@ -29,6 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class PlatformHelpers; + namespace SysPaths { LINPHONE_PUBLIC std::string getDataPath (PlatformHelpers *platformHelper); LINPHONE_PUBLIC std::string getConfigPath (PlatformHelpers *platformHelper); diff --git a/src/core/paths/paths-apple.h b/src/core/paths/paths-apple.h index acfe25ff0..f7942e646 100644 --- a/src/core/paths/paths-apple.h +++ b/src/core/paths/paths-apple.h @@ -29,6 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class PlatformHelpers; + namespace SysPaths { LINPHONE_PUBLIC std::string getDataPath (PlatformHelpers *platformHelper); LINPHONE_PUBLIC std::string getConfigPath (PlatformHelpers *platformHelper); diff --git a/src/core/paths/paths-linux.cpp b/src/core/paths/paths-linux.cpp index 06cdab9fb..7261a326e 100644 --- a/src/core/paths/paths-linux.cpp +++ b/src/core/paths/paths-linux.cpp @@ -17,23 +17,37 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "core/platform-helpers/platform-helpers.h" #include "linphone/utils/utils.h" +#include "core/platform-helpers/platform-helpers.h" +#include "logger/logger.h" + #include "paths-linux.h" // ============================================================================= +using namespace std; + LINPHONE_BEGIN_NAMESPACE -static std::string dataPath = "~/.local/share/linphone"; -static std::string configPath = "~/.config/linphone"; +static string getBaseDirectory () { + static string base; + if (base.empty()) { + char *dir = getenv("HOME"); + if (!dir) + lFatal() << "Unable to get home directory."; + base = dir; + } + return base; +} -std::string SysPaths::getDataPath (PlatformHelpers *platformHelper) { +string SysPaths::getDataPath (PlatformHelpers *platformHelper) { + static string dataPath = getBaseDirectory() + "/.local/share/linphone"; return dataPath; } -std::string SysPaths::getConfigPath (PlatformHelpers *platformHelper) { +string SysPaths::getConfigPath (PlatformHelpers *platformHelper) { + static string configPath = getBaseDirectory() + "/.config/linphone"; return configPath; } diff --git a/src/core/paths/paths-linux.h b/src/core/paths/paths-linux.h index cc652b833..c2fd0a117 100644 --- a/src/core/paths/paths-linux.h +++ b/src/core/paths/paths-linux.h @@ -29,6 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class PlatformHelpers; + namespace SysPaths { LINPHONE_PUBLIC std::string getDataPath (PlatformHelpers *platformHelper); LINPHONE_PUBLIC std::string getConfigPath (PlatformHelpers *platformHelper); diff --git a/src/core/paths/paths-windows.cpp b/src/core/paths/paths-windows.cpp index 8af9d8a4a..fd2ba5d27 100644 --- a/src/core/paths/paths-windows.cpp +++ b/src/core/paths/paths-windows.cpp @@ -18,11 +18,13 @@ */ #include + #include "shlobj.h" -#include "core/platform-helpers/platform-helpers.h" #include "linphone/utils/utils.h" +#include "core/platform-helpers/platform-helpers.h" + #include "paths-windows.h" // ============================================================================= @@ -46,7 +48,7 @@ string SysPaths::getDataPath (PlatformHelpers *platformHelper) { } string SysPaths::getConfigPath (PlatformHelpers *platformHelper) { - // seems to be the same directory + // Seems to be the same directory. return getDataPath(platformHelper); } diff --git a/src/core/paths/paths-windows.h b/src/core/paths/paths-windows.h index 137be1f87..80b4aa5b3 100644 --- a/src/core/paths/paths-windows.h +++ b/src/core/paths/paths-windows.h @@ -29,6 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class PlatformHelpers; + namespace SysPaths { LINPHONE_PUBLIC std::string getDataPath (PlatformHelpers *platformHelper); LINPHONE_PUBLIC std::string getConfigPath (PlatformHelpers *platformHelper); diff --git a/src/core/paths/paths.cpp b/src/core/paths/paths.cpp index 01987fec5..31b12289e 100644 --- a/src/core/paths/paths.cpp +++ b/src/core/paths/paths.cpp @@ -21,16 +21,16 @@ #include "paths.h" #ifdef __APPLE__ -#include "paths-apple.h" + #include "paths-apple.h" #elif defined(__ANDROID__) -#include "paths-android.h" + #include "paths-android.h" #elif defined(_WIN32) -#include "paths-windows.h" + #include "paths-windows.h" #elif defined(__linux) -#include "paths-linux.h" + #include "paths-linux.h" #else -#error "Unsupported system" -#endif + #error "Unsupported system." +#endif // ifdef __APPLE__ // ============================================================================= @@ -43,9 +43,11 @@ string Paths::getPath (Paths::Type type, PlatformHelpers *platformHelper) { case Data: return SysPaths::getDataPath(platformHelper); case Config: - default: return SysPaths::getConfigPath(platformHelper); } + + L_ASSERT(false); + return ""; } LINPHONE_END_NAMESPACE diff --git a/src/core/paths/paths.h b/src/core/paths/paths.h index e600a067e..c54a40893 100644 --- a/src/core/paths/paths.h +++ b/src/core/paths/paths.h @@ -35,7 +35,7 @@ namespace Paths { Config }; - LINPHONE_PUBLIC std::string getPath(Type type, PlatformHelpers *platformHelper); + LINPHONE_PUBLIC std::string getPath (Type type, PlatformHelpers *platformHelper); } LINPHONE_END_NAMESPACE diff --git a/src/core/platform-helpers/platform-helpers.cpp b/src/core/platform-helpers/platform-helpers.cpp index 624392072..15ed502dd 100644 --- a/src/core/platform-helpers/platform-helpers.cpp +++ b/src/core/platform-helpers/platform-helpers.cpp @@ -21,6 +21,8 @@ // ============================================================================= +using namespace std; + LINPHONE_BEGIN_NAMESPACE StubbedPlatformHelpers::StubbedPlatformHelpers (LinphoneCore *lc) : PlatformHelpers(lc) {} @@ -39,11 +41,11 @@ void StubbedPlatformHelpers::acquireCpuLock () {} void StubbedPlatformHelpers::releaseCpuLock () {} -std::string StubbedPlatformHelpers::getDataPath () { +string StubbedPlatformHelpers::getDataPath () { return ""; } -std::string StubbedPlatformHelpers::getConfigPath () { +string StubbedPlatformHelpers::getConfigPath () { return ""; } diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 9f916d47c..01b9692b8 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -108,6 +108,8 @@ private: long long insertConferenceParticipantDeviceEvent (const std::shared_ptr &eventLog); long long insertConferenceSubjectEvent (const std::shared_ptr &eventLog); + Core *core; + L_DECLARE_PUBLIC(MainDb); }; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 6888d5487..a49285647 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -30,9 +30,10 @@ #include "conference/participant.h" #include "content/content-type.h" #include "content/content.h" +#include "core/core.h" #include "db/session/db-session-provider.h" -#include "event-log/events.h" #include "event-log/event-log-p.h" +#include "event-log/events.h" #include "logger/logger.h" #include "main-db-p.h" @@ -44,7 +45,10 @@ LINPHONE_BEGIN_NAMESPACE // ----------------------------------------------------------------------------- -MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} +MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { + L_D(); + d->core = core; +} #ifdef SOCI_ENABLED @@ -1003,53 +1007,72 @@ MainDb::MainDb () : AbstractDb(*new MainDbPrivate) {} // ----------------------------------------------------------------------------- -list> MainDb::getChatRooms () const { - static const string query = "SELECT value, creation_date, last_update_date, capabilities, subject, last_notify_id" - " FROM chat_room, sip_address" - " WHERE peer_sip_address_id = id"; + list> MainDb::getChatRooms () const { + static const string query = "SELECT value, creation_date, last_update_date, capabilities, subject, last_notify_id" + " FROM chat_room, sip_address" + " WHERE peer_sip_address_id = id"; - L_D(); + L_D(); - list> chatRooms; + list> chatRooms; - L_BEGIN_LOG_EXCEPTION + L_BEGIN_LOG_EXCEPTION - soci::session *session = d->dbSession.getBackendSession(); + soci::session *session = d->dbSession.getBackendSession(); - soci::rowset rows = (session->prepare << query); - for (const auto &row : rows) { - string sipAddress = row.get(0); - tm creationDate = row.get(1); - tm lastUpdateDate = row.get(2); - int capabilities = row.get(3); - string subject = row.get(4); - unsigned int lastNotifyId = row.get(5); + soci::rowset rows = (session->prepare << query); + for (const auto &row : rows) { + string sipAddress = row.get(0); + tm creationDate = row.get(1); + tm lastUpdateDate = row.get(2); + int capabilities = row.get(3); + string subject = row.get(4); + unsigned int lastNotifyId = row.get(5); - (void)sipAddress; - (void)creationDate; - (void)lastUpdateDate; - (void)capabilities; - (void)subject; - (void)lastNotifyId; + // TODO: Use me. + (void)creationDate; + (void)lastUpdateDate; + (void)subject; + (void)lastNotifyId; - if (capabilities & static_cast(ChatRoom::Capabilities::Basic)) { - if (capabilities & static_cast(ChatRoom::Capabilities::RealTimeText)) { - // TODO. - continue; + shared_ptr chatRoom; + if (capabilities & static_cast(ChatRoom::Capabilities::Basic)) { + chatRoom = d->core ? d->core->getOrCreateBasicChatRoom( + Address(sipAddress), + capabilities & static_cast(ChatRoom::Capabilities::RealTimeText) + ) : nullptr; + } else if (capabilities & static_cast(ChatRoom::Capabilities::Conference)) { + // TODO: Set sip address and participants. } - // TODO. - continue; + + if (!chatRoom) + continue; // Not fetched. + + chatRooms.push_back(chatRoom); } - if (capabilities & static_cast(ChatRoom::Capabilities::Conference)) { - // TODO. - } + L_END_LOG_EXCEPTION + + return chatRooms; } - L_END_LOG_EXCEPTION + void MainDb::insertChatRoom (const string &peerAddress, int capabilities) { + L_D(); + d->insertChatRoom(d->insertSipAddress(peerAddress), capabilities, Utils::getLongAsTm(0)); + } - return chatRooms; -} + void MainDb::deleteChatRoom (const std::string &peerAddress) { + L_D(); + + L_BEGIN_LOG_EXCEPTION + + soci::session *session = d->dbSession.getBackendSession(); + *session << "DELETE FROM chat_room WHERE peer_sip_address_id IN (" + " SELECT id FROM sip_address WHERE value = :peerAddress" + ")", soci::use(peerAddress); + + L_END_LOG_EXCEPTION + } // ----------------------------------------------------------------------------- diff --git a/src/db/main-db.h b/src/db/main-db.h index 86edc9ca1..af06cdcda 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -29,6 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class ChatRoom; +class Core; class EventLog; class MainDbPrivate; @@ -45,7 +46,7 @@ public: typedef int FilterMask; - MainDb (); + MainDb (Core *core); // Generic. bool addEvent (const std::shared_ptr &eventLog); @@ -71,6 +72,8 @@ public: // ChatRooms. std::list> getChatRooms () const; + void insertChatRoom (const std::string &peerAddress, int capabilities); + void deleteChatRoom (const std::string &peerAddress); // Import legacy messages from old db. bool import (Backend backend, const std::string ¶meters) override; diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 5a106897a..cfde5c7ac 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -178,4 +178,8 @@ tm Utils::getLongAsTm (long time) { return *gmtime_r(&static_cast(time), &result); } +long Utils::getTmAsLong (const tm &time) { + return timegm(&const_cast(time)); +} + LINPHONE_END_NAMESPACE diff --git a/tester/main-db-tester.cpp b/tester/main-db-tester.cpp index 8691b575c..2d4b6037a 100644 --- a/tester/main-db-tester.cpp +++ b/tester/main-db-tester.cpp @@ -36,12 +36,12 @@ static const string getDatabasePath () { // ----------------------------------------------------------------------------- static void open_database () { - MainDb mainDb; + MainDb mainDb(nullptr); BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); } static void get_events_count () { - MainDb mainDb; + MainDb mainDb(nullptr); BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); BC_ASSERT_EQUAL(mainDb.getEventsCount(), 4976, int, "%d"); BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceCallFilter), 0, int, "%d"); @@ -51,21 +51,21 @@ static void get_events_count () { } static void get_messages_count () { - MainDb mainDb; + MainDb mainDb(nullptr); BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); BC_ASSERT_EQUAL(mainDb.getMessagesCount(), 4976, int, "%d"); BC_ASSERT_EQUAL(mainDb.getMessagesCount("sip:test-39@sip.linphone.org"), 3, int, "%d"); } static void get_unread_messages_count () { - MainDb mainDb; + MainDb mainDb(nullptr); BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); BC_ASSERT_EQUAL(mainDb.getUnreadMessagesCount(), 2, int, "%d"); BC_ASSERT_EQUAL(mainDb.getUnreadMessagesCount("sip:test-39@sip.linphone.org"), 0, int, "%d"); } static void get_history () { - MainDb mainDb; + MainDb mainDb(nullptr); BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); BC_ASSERT_EQUAL( mainDb.getHistoryRange("sip:test-39@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceChatMessageFilter).size(), From c5ad52bd4218835126f8ea984dd4413bdaf3c598 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 26 Oct 2017 10:19:00 +0200 Subject: [PATCH 0633/2215] fix(MainDb): add missing symbols (if soci is not enabled) --- src/db/main-db.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index a49285647..10b9b8fcf 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1263,6 +1263,14 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { return list>(); } + list> MainDb::getChatRooms () const { + return list>(); + } + + void MainDb::insertChatRoom (const string &, int) {} + + void MainDb::deleteChatRoom (const string &) {} + void MainDb::cleanHistory (const string &, FilterMask) {} bool MainDb::import (Backend, const string &) { From 42e2f7f6efcdb1de077c4f2687d14b781f8568d6 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 26 Oct 2017 10:39:26 +0200 Subject: [PATCH 0634/2215] fix(main-db): add logs --- src/db/main-db.cpp | 2 +- src/db/session/db-session-provider.cpp | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 10b9b8fcf..d09d85de3 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1061,7 +1061,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { d->insertChatRoom(d->insertSipAddress(peerAddress), capabilities, Utils::getLongAsTm(0)); } - void MainDb::deleteChatRoom (const std::string &peerAddress) { + void MainDb::deleteChatRoom (const string &peerAddress) { L_D(); L_BEGIN_LOG_EXCEPTION diff --git a/src/db/session/db-session-provider.cpp b/src/db/session/db-session-provider.cpp index e87e9d2e2..da1c9f270 100644 --- a/src/db/session/db-session-provider.cpp +++ b/src/db/session/db-session-provider.cpp @@ -22,6 +22,7 @@ #endif // ifdef SOCI_ENABLED #include "db-session-p.h" +#include "logger/logger.h" #include "object/object-p.h" #include "db-session-provider.h" @@ -59,9 +60,12 @@ DbSession DbSessionProvider::getSession (const string &uri) { d->sessions[uri] = make_pair(backendSession, p); } else // Share session. session.setRef(*d->sessions[uri].second); - } catch (const exception &) {} + } catch (const exception &e) { + lWarning() << "Unable to get db session: " << e.what(); + } #else DbSession session(DbSession::None); + lWarning() << "Unable to get db session: soci not enabled."; #endif // ifdef SOCI_ENABLED // Remove invalid weak ptrs. From 9c291ba2c422e3e2c01279d66d347c9e3fb913a3 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 26 Oct 2017 10:52:48 +0200 Subject: [PATCH 0635/2215] add content-manager and content-manager tester --- src/CMakeLists.txt | 2 + src/content/content-manager.cpp | 111 +++++++++++ src/content/content-manager.h | 45 +++++ src/content/content-type.cpp | 1 + src/content/content-type.h | 1 + tester/CMakeLists.txt | 1 + tester/content-manager-tester.cpp | 303 ++++++++++++++++++++++++++++++ tester/liblinphone_tester.h | 1 + tester/tester.c | 1 + 9 files changed, 466 insertions(+) create mode 100644 src/content/content-manager.cpp create mode 100644 src/content/content-manager.h create mode 100644 tester/content-manager-tester.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8ca281a42..17bc2550b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -77,6 +77,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES conference/session/call-session.h conference/session/media-session.h conference/session/port-config.h + content/content-manager.h content/content-type.h content/content.h core/core-p.h @@ -171,6 +172,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES conference/remote-conference.cpp conference/session/call-session.cpp conference/session/media-session.cpp + content/content-manager.cpp content/content-type.cpp content/content.cpp core/core.cpp diff --git a/src/content/content-manager.cpp b/src/content/content-manager.cpp new file mode 100644 index 000000000..c3071ca19 --- /dev/null +++ b/src/content/content-manager.cpp @@ -0,0 +1,111 @@ +/* + * content-manager.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include "belle-sip/belle-sip.h" +#include "content-manager.h" +#include "content-type.h" +#include "linphone/content.h" +#include "linphone/core.h" +#include "logger/logger.h" +#include "private.h" + +// ============================================================================= + +#define MULTIPART_BOUNDARY "---------------------------14737809831466499882746641449" + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +ContentManager::ContentManager (LinphoneCore *core) { + mCore = core; +} + +list ContentManager::multipartToContentLists (Content content) const { + belle_sip_multipart_body_handler_t *mpbh = belle_sip_multipart_body_handler_new_from_buffer((void *)content.getBodyAsString().c_str(), content.getBodyAsString().length(), MULTIPART_BOUNDARY); + belle_sip_object_ref(mpbh); + + const belle_sip_list_t *parts = belle_sip_multipart_body_handler_get_parts(mpbh); + list contentsList = list(); + while (parts) { + belle_sip_body_handler_t *part = BELLE_SIP_BODY_HANDLER(parts->data); + const belle_sip_list_t *part_headers = belle_sip_body_handler_get_headers(part); + belle_sip_list_t *it; + belle_sip_header_content_type_t *part_content_type=NULL;; + for(it = (belle_sip_list_t *)part_headers;it!=NULL;it=it->next) { + belle_sip_header_t *header = BELLE_SIP_HEADER(it->data); + if(strcasecmp("Content-Type",belle_sip_header_get_name(header)) == 0) { + part_content_type=BELLE_SIP_HEADER_CONTENT_TYPE(header); + break; + } + } + belle_sip_header_content_type_get_type(part_content_type); + belle_sip_memory_body_handler_get_buffer(BELLE_SIP_MEMORY_BODY_HANDLER(part)); + Content retContent = Content(); + ContentType type(belle_sip_header_content_type_get_type(part_content_type), belle_sip_header_content_type_get_subtype(part_content_type)); + retContent.setBody((const char *)belle_sip_memory_body_handler_get_buffer(BELLE_SIP_MEMORY_BODY_HANDLER(part))); + retContent.setContentType(type); + contentsList.push_back(retContent); + parts = parts->next; + } + + belle_sip_object_unref(mpbh); + return contentsList; +} + +Content ContentManager::contentsListToMultipart (list contents) const { + char *desc; + string sub; + belle_sip_memory_body_handler_t *mbh; + belle_sip_multipart_body_handler_t *mpbh = belle_sip_multipart_body_handler_new(NULL, NULL, NULL, MULTIPART_BOUNDARY); + belle_sip_object_ref(mpbh); + for (const auto &content : contents) { + const ContentType &contentType = content.getContentType(); + stringstream subtype; + sub = contentType.getSubType(); + subtype << sub << "; charset=\"UTF-8\""; + belle_sip_header_t *content_type = BELLE_SIP_HEADER( + belle_sip_header_content_type_create( + contentType.getType().c_str(), + subtype.str().c_str() + ) + ); + mbh = belle_sip_memory_body_handler_new_copy_from_buffer( + (void *)content.getBodyAsString().c_str(), + content.getBodyAsString().length(), + NULL, + NULL + ); + belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(mbh), content_type); + belle_sip_multipart_body_handler_add_part(mpbh, BELLE_SIP_BODY_HANDLER(mbh)); + } + desc = belle_sip_object_to_string(mpbh); + belle_sip_object_unref(mpbh); + belle_sip_object_ref(mbh); + + Content retContent = Content(); + ContentType type("application", sub); + retContent.setBody(desc); + retContent.setContentType(type); + return retContent; +} + +LINPHONE_END_NAMESPACE diff --git a/src/content/content-manager.h b/src/content/content-manager.h new file mode 100644 index 000000000..0b020616a --- /dev/null +++ b/src/content/content-manager.h @@ -0,0 +1,45 @@ +/* + * content-manager.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CONTENT_MANAGER_H_ +#define _CONTENT_MANAGER_H_ + +#include + +#include "content.h" +#include "linphone/types.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ContentManager { +public: + ContentManager (LinphoneCore *core); + + std::list multipartToContentLists (Content content) const; + Content contentsListToMultipart (std::list contents) const; + +private: + LinphoneCore *mCore = nullptr; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CONTENT_MANAGER_H_ diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index c6772c207..4be8f9626 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -46,6 +46,7 @@ const ContentType ContentType::ImIsComposing("application/im-iscomposing+xml"); const ContentType ContentType::PlainText("text/plain"); const ContentType ContentType::ResourceLists("application/resource-lists+xml"); const ContentType ContentType::Sdp("application/sdp"); +const ContentType ContentType::ConferenceInfo("application/conference-info+xml"); // ----------------------------------------------------------------------------- diff --git a/src/content/content-type.h b/src/content/content-type.h index c2a1d0ba1..f3039c164 100644 --- a/src/content/content-type.h +++ b/src/content/content-type.h @@ -66,6 +66,7 @@ public: static const ContentType PlainText; static const ContentType ResourceLists; static const ContentType Sdp; + static const ContentType ConferenceInfo; private: L_DECLARE_PRIVATE(ContentType); diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index fff62034b..3e58928c1 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -198,6 +198,7 @@ set(SOURCE_FILES_CXX clonable-object-tester.cpp conference-event-tester.cpp conference-tester.cpp + content-manager-tester.cpp cpim-tester.cpp main-db-tester.cpp multipart-tester.cpp diff --git a/tester/content-manager-tester.cpp b/tester/content-manager-tester.cpp new file mode 100644 index 000000000..db5fc375a --- /dev/null +++ b/tester/content-manager-tester.cpp @@ -0,0 +1,303 @@ +/* + * conference-event-tester.cpp + * Copyright (C) 2017 Belledonne Communications SARL + * + * 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, see . + */ +#include +#include + +#include "content/content-manager.h" +#include "content/content-type.h" +#include "liblinphone_tester.h" + +using namespace LinphonePrivate; +using namespace std; + +static const char* multipart = \ +"-----------------------------14737809831466499882746641449\r\n" \ +"Content-Type: application/rlmi+xml;charset=\"UTF-8\"\r\n\r\n" \ +"" \ +"" \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +"" \ +"-----------------------------14737809831466499882746641449\r\n" \ +"Content-Type: application/pidf+xml;charset=\"UTF-8\"\r\n\r\n" \ +"" \ +"" \ +" " \ +" " \ +" open" \ +" " \ +" sip:+YYYYYYYYYY@sip.linphone.org;user=phone" \ +" 2017-10-25T13:18:26" \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +"" \ +"-----------------------------14737809831466499882746641449\r\n" \ +"Content-Type: application/pidf+xml;charset=\"UTF-8\"\r\n\r\n" \ +"" \ +"" \ +" " \ +" " \ +" open" \ +" " \ +" sip:+XXXXXXXXXX@sip.linphone.org;user=phone" \ +" 2017-10-25T13:18:26" \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +"" \ +"-----------------------------14737809831466499882746641449\r\n" \ +"Content-Type: application/pidf+xml;charset=\"UTF-8\"\r\n\r\n" \ +"" \ +"" \ +" " \ +" " \ +" open" \ +" " \ +" sip:someone@sip.linphone.org" \ +" 2017-10-25T13:18:26" \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +"" \ +"-----------------------------14737809831466499882746641449--\r\n"; + +static const char* part1 = \ +"" \ +"" \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +""; + +static const char* part2 = \ +"" \ +"" \ +" " \ +" " \ +" open" \ +" " \ +" sip:+YYYYYYYYYY@sip.linphone.org;user=phone" \ +" 2017-10-25T13:18:26" \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +"" ; + +static const char* part3 = \ +"" \ +"" \ +" " \ +" " \ +" open" \ +" " \ +" sip:+XXXXXXXXXX@sip.linphone.org;user=phone" \ +" 2017-10-25T13:18:26" \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +""; + +static const char* part4 = \ +"" \ +"" \ +" " \ +" " \ +" open" \ +" " \ +" sip:someone@sip.linphone.org" \ +" 2017-10-25T13:18:26" \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +""; + +void multipart_to_list () { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + ContentManager manager(marie->lc); + + Content multipartContent = Content(); + multipartContent.setBody(multipart); + multipartContent.setContentType(ContentType("multipart", "related")); + + list contents = manager.multipartToContentLists(multipartContent); + BC_ASSERT_EQUAL(contents.size(), 4, int, "%d"); + Content content1 = contents.front(); + contents.pop_front(); + string originalStr1(part1); + originalStr1.erase(std::remove(originalStr1.begin(), originalStr1.end(), ' '), originalStr1.end()); + originalStr1.erase(std::remove(originalStr1.begin(), originalStr1.end(), '\t'), originalStr1.end()); + originalStr1.erase(std::remove(originalStr1.begin(), originalStr1.end(), '\r'), originalStr1.end()); + originalStr1.erase(std::remove(originalStr1.begin(), originalStr1.end(), '\n'), originalStr1.end()); + string generatedStr1 = content1.getBodyAsString(); + generatedStr1.erase(std::remove(generatedStr1.begin(), generatedStr1.end(), ' '), generatedStr1.end()); + generatedStr1.erase(std::remove(generatedStr1.begin(), generatedStr1.end(), '\t'), generatedStr1.end()); + generatedStr1.erase(std::remove(generatedStr1.begin(), generatedStr1.end(), '\r'), generatedStr1.end()); + generatedStr1.erase(std::remove(generatedStr1.begin(), generatedStr1.end(), '\n'), generatedStr1.end()); + ms_message("\n\n----- Generated part 1 -----"); + ms_message("%s", generatedStr1.c_str()); + ms_message("\n\n----- Original part 1 -----"); + ms_message("%s", originalStr1.c_str()); + BC_ASSERT_TRUE(originalStr1 == generatedStr1); + + Content content2 = contents.front(); + contents.pop_front(); + string originalStr2(part2); + originalStr2.erase(std::remove(originalStr2.begin(), originalStr2.end(), ' '), originalStr2.end()); + originalStr2.erase(std::remove(originalStr2.begin(), originalStr2.end(), '\t'), originalStr2.end()); + originalStr2.erase(std::remove(originalStr2.begin(), originalStr2.end(), '\r'), originalStr2.end()); + originalStr2.erase(std::remove(originalStr2.begin(), originalStr2.end(), '\n'), originalStr2.end()); + string generatedStr2 = content2.getBodyAsString(); + generatedStr2.erase(std::remove(generatedStr2.begin(), generatedStr2.end(), ' '), generatedStr2.end()); + generatedStr2.erase(std::remove(generatedStr2.begin(), generatedStr2.end(), '\t'), generatedStr2.end()); + generatedStr2.erase(std::remove(generatedStr2.begin(), generatedStr2.end(), '\r'), generatedStr2.end()); + generatedStr2.erase(std::remove(generatedStr2.begin(), generatedStr2.end(), '\n'), generatedStr2.end()); + ms_message("\n\n----- Generated part 2 -----"); + ms_message("%s", generatedStr2.c_str()); + ms_message("\n\n----- Original part 2 -----"); + ms_message("%s", originalStr2.c_str()); + BC_ASSERT_TRUE(originalStr2 == generatedStr2); + + Content content3 = contents.front(); + contents.pop_front(); + string originalStr3(part3); + originalStr3.erase(std::remove(originalStr3.begin(), originalStr3.end(), ' '), originalStr3.end()); + originalStr3.erase(std::remove(originalStr3.begin(), originalStr3.end(), '\t'), originalStr3.end()); + originalStr3.erase(std::remove(originalStr3.begin(), originalStr3.end(), '\r'), originalStr3.end()); + originalStr3.erase(std::remove(originalStr3.begin(), originalStr3.end(), '\n'), originalStr3.end()); + string generatedStr3 = content3.getBodyAsString(); + generatedStr3.erase(std::remove(generatedStr3.begin(), generatedStr3.end(), ' '), generatedStr3.end()); + generatedStr3.erase(std::remove(generatedStr3.begin(), generatedStr3.end(), '\t'), generatedStr3.end()); + generatedStr3.erase(std::remove(generatedStr3.begin(), generatedStr3.end(), '\r'), generatedStr3.end()); + generatedStr3.erase(std::remove(generatedStr3.begin(), generatedStr3.end(), '\n'), generatedStr3.end()); + ms_message("\n\n----- Generated part 3 -----"); + ms_message("%s", generatedStr3.c_str()); + ms_message("\n\n----- Original part 3 -----"); + ms_message("%s", originalStr3.c_str()); + BC_ASSERT_TRUE(originalStr3 == generatedStr3); + + Content content4 = contents.front(); + contents.pop_front(); + string originalStr4(part4); + originalStr4.erase(std::remove(originalStr4.begin(), originalStr4.end(), ' '), originalStr4.end()); + originalStr4.erase(std::remove(originalStr4.begin(), originalStr4.end(), '\t'), originalStr4.end()); + originalStr4.erase(std::remove(originalStr4.begin(), originalStr4.end(), '\r'), originalStr4.end()); + originalStr4.erase(std::remove(originalStr4.begin(), originalStr4.end(), '\n'), originalStr4.end()); + string generatedStr4 = content4.getBodyAsString(); + generatedStr4.erase(std::remove(generatedStr4.begin(), generatedStr4.end(), ' '), generatedStr4.end()); + generatedStr4.erase(std::remove(generatedStr4.begin(), generatedStr4.end(), '\t'), generatedStr4.end()); + generatedStr4.erase(std::remove(generatedStr4.begin(), generatedStr4.end(), '\r'), generatedStr4.end()); + generatedStr4.erase(std::remove(generatedStr4.begin(), generatedStr4.end(), '\n'), generatedStr4.end()); + ms_message("\n\n----- Generated part 4 -----"); + ms_message("%s", generatedStr3.c_str()); + ms_message("\n\n----- Original part 4 -----"); + ms_message("%s", originalStr4.c_str()); + BC_ASSERT_TRUE(originalStr4 == generatedStr4); + + linphone_core_manager_destroy(marie); +} + +void list_to_multipart () { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + ContentManager manager(marie->lc); + + Content content1 = Content(); + content1.setBody(part1); + content1.setContentType(ContentType("application", "rlmi+xml")); + Content content2 = Content(); + content2.setBody(part2); + content2.setContentType(ContentType("application", "pidf+xml")); + Content content3 = Content(); + content3.setBody(part3); + content3.setContentType(ContentType("application", "pidf+xml")); + Content content4 = Content(); + content4.setBody(part4); + content4.setContentType(ContentType("application", "pidf+xml")); + list contents; + contents.push_back(content1); + contents.push_back(content2); + contents.push_back(content3); + contents.push_back(content4); + + Content multipartContent = manager.contentsListToMultipart(contents); + string originalStr(multipart); + originalStr.erase(std::remove(originalStr.begin(), originalStr.end(), ' '), originalStr.end()); + originalStr.erase(std::remove(originalStr.begin(), originalStr.end(), '\t'), originalStr.end()); + originalStr.erase(std::remove(originalStr.begin(), originalStr.end(), '\r'), originalStr.end()); + originalStr.erase(std::remove(originalStr.begin(), originalStr.end(), '\n'), originalStr.end()); + + string generatedStr = multipartContent.getBodyAsString(); + generatedStr.erase(std::remove(generatedStr.begin(), generatedStr.end(), ' '), generatedStr.end()); + generatedStr.erase(std::remove(generatedStr.begin(), generatedStr.end(), '\t'), generatedStr.end()); + generatedStr.erase(std::remove(generatedStr.begin(), generatedStr.end(), '\r'), generatedStr.end()); + generatedStr.erase(std::remove(generatedStr.begin(), generatedStr.end(), '\n'), generatedStr.end()); + + ms_message("\n\n----- Generated multipart -----"); + ms_message("%s", generatedStr.c_str()); + + ms_message("\n\n----- Original multipart -----"); + ms_message("%s", originalStr.c_str()); + BC_ASSERT_TRUE(originalStr == generatedStr); + + linphone_core_manager_destroy(marie); +} + +test_t content_manager_tests[] = { + TEST_NO_TAG("Multipart to list", multipart_to_list), + TEST_NO_TAG("List to multipart", list_to_multipart) +}; + +test_suite_t content_manager_test_suite = { + "Content manager", + nullptr, + nullptr, + liblinphone_tester_before_each, + liblinphone_tester_after_each, + sizeof(content_manager_tests) / sizeof(content_manager_tests[0]), content_manager_tests +}; diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 804288955..11a7a712c 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -46,6 +46,7 @@ extern test_suite_t call_video_test_suite; extern test_suite_t clonable_object_test_suite; extern test_suite_t conference_event_test_suite; extern test_suite_t conference_test_suite; +extern test_suite_t content_manager_test_suite; extern test_suite_t cpim_test_suite; extern test_suite_t dtmf_test_suite; extern test_suite_t event_test_suite; diff --git a/tester/tester.c b/tester/tester.c index 4cef7a7e6..48708461e 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -565,6 +565,7 @@ void liblinphone_tester_add_suites() { bc_tester_add_suite(&event_test_suite); bc_tester_add_suite(&conference_event_test_suite); bc_tester_add_suite(&conference_test_suite); + bc_tester_add_suite(&content_manager_test_suite); bc_tester_add_suite(&flexisip_test_suite); bc_tester_add_suite(&remote_provisioning_test_suite); bc_tester_add_suite(&quality_reporting_test_suite); From f20bca4c8f68be73027754a04cbd5d770ca8f2be Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 26 Oct 2017 14:07:53 +0200 Subject: [PATCH 0636/2215] fix getDataPath on iOS --- coreapi/CMakeLists.txt | 5 ++++- src/CMakeLists.txt | 2 +- src/core/core.cpp | 2 +- src/core/paths/paths-apple.mm | 12 ++---------- src/core/paths/paths-linux.cpp | 4 ++-- src/core/paths/paths-windows.cpp | 2 +- 6 files changed, 11 insertions(+), 16 deletions(-) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index f0a3bfdd6..4a783cdda 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -207,7 +207,7 @@ if(ENABLE_STATIC) add_dependencies(linphone-static liblinphone-git-version) target_include_directories(linphone-static PUBLIC ${LINPHONE_INCLUDE_DIRS}) target_link_libraries(linphone-static INTERFACE ${LIBS}) - if(IOS) + if(APPLE) target_link_libraries(linphone-static INTERFACE "-framework Foundation" "-framework AVFoundation") endif() install(TARGETS linphone-static EXPORT ${EXPORT_TARGETS_NAME}Targets @@ -248,6 +248,9 @@ if(ENABLE_SHARED) add_dependencies(linphone liblinphone-git-version) target_include_directories(linphone PUBLIC ${LINPHONE_INCLUDE_DIRS}) target_link_libraries(linphone PRIVATE ${LIBS}) + if(APPLE) + target_link_libraries(linphone PRIVATE "-framework Foundation" "-framework AVFoundation") + endif() if(WIN32 AND CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") set_target_properties(linphone PROPERTIES PREFIX "lib") elseif(ANDROID) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 17bc2550b..37de6f4dd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -251,7 +251,7 @@ endforeach () set(LINPHONE_PRIVATE_HEADER_FILES ${LINPHONE_PRIVATE_HEADER_FILES} PARENT_SCOPE) bc_apply_compile_flags(LINPHONE_CXX_OBJECTS_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX) -bc_apply_compile_flags(LINPHONE_OBJC_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX STRICT_OPTIONS_OBJC) +bc_apply_compile_flags(LINPHONE_OBJC_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_OBJC) if (ENABLE_STATIC) add_library( diff --git a/src/core/core.cpp b/src/core/core.cpp index 2bc55abf6..8a587f74c 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -105,7 +105,7 @@ Core::Core (LinphoneCore *cCore) : Object(*new CorePrivate) { : MainDb::Sqlite3; else { backend = AbstractDb::Sqlite3; - uri = getDataPath() + "/" LINPHONE_DB; + uri = getDataPath() + LINPHONE_DB; } lInfo() << "Opening " LINPHONE_DB " at: " << uri; diff --git a/src/core/paths/paths-apple.mm b/src/core/paths/paths-apple.mm index 97bbef63b..55b35e59b 100644 --- a/src/core/paths/paths-apple.mm +++ b/src/core/paths/paths-apple.mm @@ -1,5 +1,5 @@ /* - * paths-apple.m + * paths-apple.mm * Copyright (C) 2010-2017 Belledonne Communications SARL * * This program is free software; you can redistribute it and/or @@ -19,37 +19,29 @@ #import "linphone/utils/utils.h" -#include "core/platform-helpers/platform-helpers.h" +#import "core/platform-helpers/platform-helpers.h" #import "paths-apple.h" -#ifdef __OBJC__ #import -#endif // ============================================================================= LINPHONE_BEGIN_NAMESPACE std::string SysPaths::getDataPath (PlatformHelpers *platformHelper) { -#ifdef __OBJC__ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); NSString *writablePath = [paths objectAtIndex:0]; NSString *fullPath = [writablePath stringByAppendingString:@"/linphone/"]; const char *ret = fullPath.UTF8String; return ret; -#endif - return Utils::getEmptyConstRefObject(); } std::string SysPaths::getConfigPath (PlatformHelpers *platformHelper) { -#ifdef __OBJC__ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); NSString *configPath = [paths objectAtIndex:0]; NSString *fullPath = [configPath stringByAppendingString:@"/Preferences/linphone/"]; const char *ret = fullPath.UTF8String; return ret; -#endif - return Utils::getEmptyConstRefObject(); } LINPHONE_END_NAMESPACE diff --git a/src/core/paths/paths-linux.cpp b/src/core/paths/paths-linux.cpp index 7261a326e..70b38c6d7 100644 --- a/src/core/paths/paths-linux.cpp +++ b/src/core/paths/paths-linux.cpp @@ -42,12 +42,12 @@ static string getBaseDirectory () { } string SysPaths::getDataPath (PlatformHelpers *platformHelper) { - static string dataPath = getBaseDirectory() + "/.local/share/linphone"; + static string dataPath = getBaseDirectory() + "/.local/share/linphone/"; return dataPath; } string SysPaths::getConfigPath (PlatformHelpers *platformHelper) { - static string configPath = getBaseDirectory() + "/.config/linphone"; + static string configPath = getBaseDirectory() + "/.config/linphone/"; return configPath; } diff --git a/src/core/paths/paths-windows.cpp b/src/core/paths/paths-windows.cpp index fd2ba5d27..39b10a80c 100644 --- a/src/core/paths/paths-windows.cpp +++ b/src/core/paths/paths-windows.cpp @@ -38,7 +38,7 @@ string SysPaths::getDataPath (PlatformHelpers *platformHelper) { // Get path for each computer, non-user specific and non-roaming data. if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, szPath))) { stringstream path; - path << boost::lexical_cast(szPath) << "/linphone"; + path << boost::lexical_cast(szPath) << "\\linphone\\"; string ret = path.str(); boost::replace_all(ret, "\\", "\\\\"); return ret; From 5c0b416b76e91bdbc87b94f00b9e3545c8bfd659 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 26 Oct 2017 14:55:16 +0200 Subject: [PATCH 0637/2215] feat(MainDb): supports correctly foreign keys, fix db schema, ... --- src/db/abstract/abstract-db.cpp | 17 +++++++++++++++++ src/db/abstract/abstract-db.h | 2 ++ src/db/main-db.cpp | 21 ++++++++++++++++++--- src/db/main-db.h | 5 +++++ tester/db/linphone.db | Bin 643072 -> 724992 bytes 5 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/db/abstract/abstract-db.cpp b/src/db/abstract/abstract-db.cpp index f04940132..ce64805ae 100644 --- a/src/db/abstract/abstract-db.cpp +++ b/src/db/abstract/abstract-db.cpp @@ -43,7 +43,9 @@ bool AbstractDb::connect (Backend backend, const string ¶meters) { if (d->dbSession) { try { + enableForeignKeys(false); init(); + enableForeignKeys(true); } catch (const exception &e) { lWarning() << "Unable to init database: " << e.what(); @@ -133,4 +135,19 @@ long long AbstractDb::getLastInsertId () const { return id; } +void AbstractDb::enableForeignKeys (bool status) { + #ifdef SOCI_ENABLED + L_D(); + soci::session *session = d->dbSession.getBackendSession(); + switch (d->backend) { + case Mysql: + *session << string("SET FOREIGN_KEY_CHECKS = ") + (status ? "1" : "0"); + break; + case Sqlite3: + *session << string("PRAGMA foreign_keys = ") + (status ? "ON" : "OFF"); + break; + } + #endif // ifdef SOCI_ENABLED +} + LINPHONE_END_NAMESPACE diff --git a/src/db/abstract/abstract-db.h b/src/db/abstract/abstract-db.h index 2386c384e..9987d9647 100644 --- a/src/db/abstract/abstract-db.h +++ b/src/db/abstract/abstract-db.h @@ -56,6 +56,8 @@ protected: long long getLastInsertId () const; + void enableForeignKeys (bool status); + private: L_DECLARE_PRIVATE(AbstractDb); L_DISABLE_COPY(AbstractDb); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index d09d85de3..23ab4e17d 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -607,7 +607,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { "CREATE TABLE IF NOT EXISTS conference_subject_event (" " event_id" + primaryKeyStr("BIGINT") + "," - " subject VARCHAR(255)," + " subject VARCHAR(255) NOT NULL," " FOREIGN KEY (event_id)" " REFERENCES conference_notified_event(event_id)" @@ -629,7 +629,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { " is_secured BOOLEAN NOT NULL," " FOREIGN KEY (event_id)" - " REFERENCES conference_event(id)" + " REFERENCES conference_event(event_id)" " ON DELETE CASCADE," " FOREIGN KEY (local_sip_address_id)" " REFERENCES sip_address(id)" @@ -842,6 +842,14 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { return count; } + list> MainDb::getHistorySinceNotifyId ( + const string &peerAddress, + unsigned int notifyId + ) { + // TODO. + return list>(); + } + int MainDb::getMessagesCount (const string &peerAddress) const { L_D(); @@ -1067,7 +1075,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); - *session << "DELETE FROM chat_room WHERE peer_sip_address_id IN (" + *session << "DELETE FROM chat_room WHERE peer_sip_address_id = (" " SELECT id FROM sip_address WHERE value = :peerAddress" ")", soci::use(peerAddress); @@ -1247,6 +1255,13 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { return 0; } + list> MainDb::getHistorySinceNotifyId ( + const string &peerAddress, + unsigned int notifyId + ) { + return list>(); + } + int MainDb::getMessagesCount (const string &) const { return 0; } diff --git a/src/db/main-db.h b/src/db/main-db.h index af06cdcda..71889472b 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -55,6 +55,11 @@ public: int getEventsCount (FilterMask mask = NoFilter) const; // Messages, calls and conferences. + std::list> getHistorySinceNotifyId ( + const std::string &peerAddress, + unsigned int notifyId + ); + int getMessagesCount (const std::string &peerAddress = "") const; int getUnreadMessagesCount (const std::string &peerAddress = "") const; std::list> getHistory ( diff --git a/tester/db/linphone.db b/tester/db/linphone.db index 6fb3f9ab68f4dc06f7b302db6aea93cbed3c0fd0..9b76ebd676d04bf310b1599c8b83d6fac694517d 100644 GIT binary patch delta 11291 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�bQJ-T{Wb^q!f)#r0%|EASOHLm=* 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

      A~v7Dx0KH83p}iP3*F1;a03vGQ6g@)uS2- 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 Date: Thu, 26 Oct 2017 16:55:05 +0200 Subject: [PATCH 0638/2215] Added soci_core to list of library to load --- wrappers/java/java_class.mustache | 1 + 1 file changed, 1 insertion(+) diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index d9e17a999..8f0153c8d 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -152,6 +152,7 @@ class {{classImplName}} {{#isLinphoneFactory}}extends{{/isLinphoneFactory}}{{#is static { System.loadLibrary("gnustl_shared"); loadOptionalLibrary("ffmpeg-linphone"); + System.loadLibrary("soci_core"); System.loadLibrary("bctoolbox"); System.loadLibrary("ortp"); System.loadLibrary("mediastreamer_base"); From cb28cd4ccdfc618979731c373c693bcb2df6a5b5 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 26 Oct 2017 16:55:32 +0200 Subject: [PATCH 0639/2215] fix(AbstractDb): please use :'( --- src/db/abstract/abstract-db.cpp | 2 +- src/db/main-db-p.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/db/abstract/abstract-db.cpp b/src/db/abstract/abstract-db.cpp index ce64805ae..a3cb11e0a 100644 --- a/src/db/abstract/abstract-db.cpp +++ b/src/db/abstract/abstract-db.cpp @@ -31,7 +31,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -AbstractDb::AbstractDb (AbstractDbPrivate &p) : Object(*new AbstractDbPrivate) {} +AbstractDb::AbstractDb (AbstractDbPrivate &p) : Object(p) {} bool AbstractDb::connect (Backend backend, const string ¶meters) { L_D(); diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 01b9692b8..b7133a055 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -108,7 +108,7 @@ private: long long insertConferenceParticipantDeviceEvent (const std::shared_ptr &eventLog); long long insertConferenceSubjectEvent (const std::shared_ptr &eventLog); - Core *core; + Core *core = nullptr; L_DECLARE_PUBLIC(MainDb); }; From 2f97587d53020be683a98a4b6404f76f9a8e24a5 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 26 Oct 2017 18:04:43 +0200 Subject: [PATCH 0640/2215] Fixed issue with android platform helper and DNS servers + added logs into android platform helper --- coreapi/linphonecore.c | 13 +++++++++---- .../platform-helpers/android-platform-helpers.cpp | 9 ++++++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 2221eef8b..92b84d072 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2176,7 +2176,7 @@ static void _linphone_core_init_account_creator_service(LinphoneCore *lc) { linphone_core_set_account_creator_service(lc, service); } -static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig *config, void * userdata){ +static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig *config, void * userdata, void *system_context){ const char *remote_provisioning_uri = NULL; LinphoneFactory *lfactory = linphone_factory_get(); LinphoneCoreCbs *internal_cbs = _linphone_core_cbs_new(); @@ -2192,7 +2192,13 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig lc->config=lp_config_ref(config); lc->data=userdata; lc->ringstream_autorelease=TRUE; - lc->platform_helper = new LinphonePrivate::StubbedPlatformHelpers(lc); + +#ifdef __ANDROID__ + if (system_context) + lc->platform_helper = LinphonePrivate::createAndroidPlatformHelpers(lc, system_context); +#endif + if (lc->platform_helper == NULL) + lc->platform_helper = new LinphonePrivate::StubbedPlatformHelpers(lc); linphone_task_list_init(&lc->hooks); @@ -2287,8 +2293,7 @@ static void _linphone_core_set_system_context(LinphoneCore *lc, void *system_con LinphoneCore *_linphone_core_new_with_config(LinphoneCoreCbs *cbs, struct _LpConfig *config, void *userdata, void *system_context) { LinphoneCore *core = belle_sip_object_new(LinphoneCore); - linphone_core_init(core, cbs, config, userdata); - _linphone_core_set_system_context(core, system_context); + linphone_core_init(core, cbs, config, userdata, system_context); return core; } diff --git a/src/core/platform-helpers/android-platform-helpers.cpp b/src/core/platform-helpers/android-platform-helpers.cpp index 4aee2bf64..e7eb9f346 100644 --- a/src/core/platform-helpers/android-platform-helpers.cpp +++ b/src/core/platform-helpers/android-platform-helpers.cpp @@ -116,10 +116,14 @@ AndroidPlatformHelpers::~AndroidPlatformHelpers () { env->DeleteGlobalRef(mJavaHelper); mJavaHelper = nullptr; } + lInfo() << "AndroidPlatformHelpers has been destroyed."; } void AndroidPlatformHelpers::setDnsServers () { - if (!mJavaHelper) return; + if (!mJavaHelper) { + lError() << "AndroidPlatformHelpers' mJavaHelper is null."; + return; + } JNIEnv *env = ms_get_jni_env(); if (env && mJavaHelper) { jobjectArray jservers = (jobjectArray)env->CallObjectMethod(mJavaHelper, mGetDnsServersId); @@ -136,10 +140,13 @@ void AndroidPlatformHelpers::setDnsServers () { jstring jserver = (jstring)env->GetObjectArrayElement(jservers, i); const char *str = env->GetStringUTFChars(jserver, nullptr); if (str) { + lInfo() << "AndroidPlatformHelpers found DNS server " << str; l = bctbx_list_append(l, ms_strdup(str)); env->ReleaseStringUTFChars(jserver, str); } } + } else { + lError() << "AndroidPlatformHelpers::setDnsServers() failed to get DNS servers list"; } linphone_core_set_dns_servers(mCore, l); bctbx_list_free_with_data(l, ms_free); From b64ae8a57b96762adf64757bceea6cac064e4c35 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 27 Oct 2017 09:23:27 +0200 Subject: [PATCH 0641/2215] fix(Core): load correctly chat rooms --- src/chat/chat-room/chat-room.h | 1 + src/core/core-p.h | 2 ++ src/core/core.cpp | 24 ++++++++++++++++-------- src/core/core.h | 1 + src/db/main-db.cpp | 12 ++++++++---- 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index 01a5108c8..cabe8f6e4 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -31,6 +31,7 @@ class ChatRoomPrivate; class LINPHONE_PUBLIC ChatRoom : public Object, public ConferenceInterface { friend class Core; + friend class CorePrivate; friend class ChatMessage; friend class ChatMessagePrivate; diff --git a/src/core/core-p.h b/src/core/core-p.h index 243fed9ac..36c70a3a7 100644 --- a/src/core/core-p.h +++ b/src/core/core-p.h @@ -36,6 +36,8 @@ public: void insertChatRoomWithDb (const std::shared_ptr &chatRoom); void deleteChatRoomWithDb (const std::string &peerAddress); + std::shared_ptr createChatRoom (const Address &peerAddress, bool isRtt); + private: void insertChatRoom (const std::shared_ptr &chatRoom); void deleteChatRoom (const std::string &peerAddress); diff --git a/src/core/core.cpp b/src/core/core.cpp index 8a587f74c..f13d69707 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -56,6 +56,21 @@ static inline Address getCleanedPeerAddress (const Address &peerAddress) { // CorePrivate: ChatRoom. // ----------------------------------------------------------------------------- +shared_ptr CorePrivate::createChatRoom (const Address &peerAddress, bool isRtt) { + shared_ptr chatRoom; + + if (isRtt) + chatRoom = ObjectFactory::create(cCore, peerAddress); + else + chatRoom = ObjectFactory::create(cCore, peerAddress); + + ChatRoomPrivate *dChatRoom = chatRoom->getPrivate(); + dChatRoom->setState(ChatRoom::State::Instantiated); + dChatRoom->setState(ChatRoom::State::Created); + + return chatRoom; +} + void CorePrivate::insertChatRoom (const shared_ptr &chatRoom) { L_ASSERT(chatRoom); L_ASSERT(chatRoom->getState() == ChatRoom::State::Created); @@ -169,14 +184,7 @@ shared_ptr Core::getOrCreateBasicChatRoom (const Address &peerAddress, if (chatRoom) return chatRoom; - if (isRtt) - chatRoom = ObjectFactory::create(d->cCore, peerAddress); - else - chatRoom = ObjectFactory::create(d->cCore, peerAddress); - - chatRoom->getPrivate()->setState(ChatRoom::State::Instantiated); - chatRoom->getPrivate()->setState(ChatRoom::State::Created); - + chatRoom = d->createChatRoom(peerAddress, isRtt); d->insertChatRoomWithDb(chatRoom); return chatRoom; diff --git a/src/core/core.h b/src/core/core.h index 207e3275b..8a2cd3aa8 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -36,6 +36,7 @@ class CorePrivate; class LINPHONE_PUBLIC Core : public Object { friend class ClientGroupChatRoom; + friend class MainDb; public: L_OVERRIDE_SHARED_FROM_THIS(Core); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 23ab4e17d..94473a522 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -30,7 +30,7 @@ #include "conference/participant.h" #include "content/content-type.h" #include "content/content.h" -#include "core/core.h" +#include "core/core-p.h" #include "db/session/db-session-provider.h" #include "event-log/event-log-p.h" #include "event-log/events.h" @@ -1035,7 +1035,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { tm lastUpdateDate = row.get(2); int capabilities = row.get(3); string subject = row.get(4); - unsigned int lastNotifyId = row.get(5); + unsigned int lastNotifyId = static_cast(row.get(5, 0)); // TODO: Use me. (void)creationDate; @@ -1045,7 +1045,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { shared_ptr chatRoom; if (capabilities & static_cast(ChatRoom::Capabilities::Basic)) { - chatRoom = d->core ? d->core->getOrCreateBasicChatRoom( + chatRoom = d->core ? d->core->getPrivate()->createChatRoom( Address(sipAddress), capabilities & static_cast(ChatRoom::Capabilities::RealTimeText) ) : nullptr; @@ -1066,7 +1066,11 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { void MainDb::insertChatRoom (const string &peerAddress, int capabilities) { L_D(); - d->insertChatRoom(d->insertSipAddress(peerAddress), capabilities, Utils::getLongAsTm(0)); + d->insertChatRoom( + d->insertSipAddress(peerAddress), + capabilities, + Utils::getLongAsTm(static_cast(time(0))) + ); } void MainDb::deleteChatRoom (const string &peerAddress) { From a100df852426344c920188b471f59f9fcc91a222 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 27 Oct 2017 09:36:15 +0200 Subject: [PATCH 0642/2215] feat(Tester): add some data in linphone.db --- tester/db/linphone.db | Bin 724992 -> 724992 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tester/db/linphone.db b/tester/db/linphone.db index 9b76ebd676d04bf310b1599c8b83d6fac694517d..eed573f25761176c713adb02dbe30d19c5878a60 100644 GIT binary patch delta 1797 zcmbW0O=uHA6vt;Xlg#ec`iveLKae1PC!4QLEcB#!^bnzXP(iFVruC~eY1GuVTRbS} zrJ_(g89$hK5tXPF^q}HFJ!ntrL9vL6phzi#CZExF|F|xU?Lbs80s|>fwbgRNu)vD@Y3AZd% zl~q;li&aj~$#|znwK1ai>g)7~u4-cyHTX!gme5w^A2N$BqG?|`pW+a+} zvE~*t)e=wC2r-#lFqt&|W0#oOOeUlyF47W% zXsM`7dMY{-Xexu~s?3zfdtkyozTzK!3-g@=qt1a*$r)TG@ByB|J-CdfC0Oehc-dw4 z7v>9FcVxEp1e1Pw^{Fw_FEEj*v4me>T2o{3bN^9xtJ3GvWl%WNk zYFbUHb5+9M@Q3^oKgo-HGhfY@@L_{LJ77~_3wF){Q1|(7^@3MXrdqDI{#wW8X>XXP<6CJFNdh4TN6nQrtQ9pR(& zng`4B5w%#^gEbv;Dmd&^aM)>ykkb;l$d9}|5{Au2Fn!?;X5sBKcQ9u!XZB#{*v@`|c_I@~wt%Ib ZBOQcUftU@5*@2h?h&i`&q;vgP0RU~kJpup# From 54e0f253f564c481dd217757f9c6ca6cc9d05f9b Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 27 Oct 2017 10:44:37 +0200 Subject: [PATCH 0643/2215] feat(MainDb): add getConferenceNotifiedEvents impl --- coreapi/linphonecore.c | 4 -- include/linphone/utils/utils.h | 4 +- src/db/main-db.cpp | 77 +++++++++++++++++++++++++++------- src/db/main-db.h | 4 +- src/utils/utils.cpp | 6 +-- 5 files changed, 69 insertions(+), 26 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 92b84d072..156df2ba2 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2284,10 +2284,6 @@ static void _linphone_core_set_platform_helpers(LinphoneCore *lc, LinphonePrivat static void _linphone_core_set_system_context(LinphoneCore *lc, void *system_context){ _linphone_core_set_platform_helpers(lc, LinphonePrivate::createAndroidPlatformHelpers(lc, system_context)); -} -#else -static void _linphone_core_set_system_context(LinphoneCore *lc, void *system_context){ - } #endif diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h index f8e8a0929..6fea7d5c2 100644 --- a/include/linphone/utils/utils.h +++ b/include/linphone/utils/utils.h @@ -105,8 +105,8 @@ namespace Utils { return object; } - LINPHONE_PUBLIC std::tm getLongAsTm (long time); - LINPHONE_PUBLIC long getTmAsLong (const std::tm &time); + LINPHONE_PUBLIC std::tm getTimeTAsTm (std::time_t time); + LINPHONE_PUBLIC std::time_t getTmAsTimeT (const std::tm &time); } LINPHONE_END_NAMESPACE diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 94473a522..895e89dd4 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -70,9 +70,9 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { } static constexpr EnumToSql eventFilterToSql[] = { - { MainDb::ConferenceCallFilter, "1, 2" }, + { MainDb::ConferenceCallFilter, "3, 4" }, { MainDb::ConferenceChatMessageFilter, "5" }, - { MainDb::ConferenceInfoFilter, "3, 4, 6, 7, 8, 9, 10, 11, 12" } + { MainDb::ConferenceInfoFilter, "1, 2, 6, 7, 8, 9, 10, 11, 12" } }; static constexpr const char *mapEventFilterToSql (MainDb::Filter filter) { @@ -375,7 +375,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO event (type, date) VALUES (:type, :date)", - soci::use(static_cast(eventLog->getType())), soci::use(Utils::getLongAsTm(eventLog->getTime())); + soci::use(static_cast(eventLog->getType())), soci::use(Utils::getTimeTAsTm(eventLog->getTime())); return q->getLastInsertId(); } @@ -408,7 +408,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { return -1; } - tm eventTime = Utils::getLongAsTm(static_cast(eventLog->getTime())); + tm eventTime = Utils::getTimeTAsTm(eventLog->getTime()); long long localSipAddressId = insertSipAddress(chatMessage->getLocalAddress().asString()); long long remoteSipAddressId = insertSipAddress(chatMessage->getRemoteAddress().asString()); @@ -842,12 +842,45 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { return count; } - list> MainDb::getHistorySinceNotifyId ( + list> MainDb::getConferenceNotifiedEvents ( const string &peerAddress, - unsigned int notifyId + unsigned int lastNotifyId ) { - // TODO. - return list>(); + static const string query = "SELECT id, type, date FROM event" + " WHERE id IN (" + " SELECT event_id FROM conference_notified_event WHERE event_id IN (" + " SELECT event_id FROM conference_event WHERE chat_room_id = (" + " SELECT id FROM sip_address WHERE value = :peerAddress" + " )" + " ) AND notify_id > :lastNotifyId" + " )"; + + L_D(); + + if (!isConnected()) { + lWarning() << "Unable to get conference notified events. Not connected."; + return list>(); + } + + list> events; + + L_BEGIN_LOG_EXCEPTION + + soci::session *session = d->dbSession.getBackendSession(); + soci::transaction tr(*session); + + soci::rowset rows = (session->prepare << query, soci::use(peerAddress), soci::use(lastNotifyId)); + for (const auto &row : rows) + events.push_back(d->selectGenericConferenceEvent( + getBackend() == Sqlite3 ? static_cast(row.get(0)) : row.get(0), + static_cast(row.get(1)), + Utils::getTmAsTimeT(row.get(2)), + peerAddress + )); + + L_END_LOG_EXCEPTION + + return events; } int MainDb::getMessagesCount (const string &peerAddress) const { @@ -969,17 +1002,15 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { soci::transaction tr(*session); soci::rowset rows = (session->prepare << query, soci::use(peerAddress)); - for (const auto &row : rows) { - tm date = row.get(2); + for (const auto &row : rows) events.push_back(d->selectGenericConferenceEvent( // See: http://soci.sourceforge.net/doc/master/backends/ // `row id` is not supported by soci on Sqlite3. It's necessary to cast id to int... getBackend() == Sqlite3 ? static_cast(row.get(0)) : row.get(0), static_cast(row.get(1)), - mktime(&date), + Utils::getTmAsTimeT(row.get(2)), peerAddress )); - } L_END_LOG_EXCEPTION @@ -1022,6 +1053,11 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { L_D(); + if (!isConnected()) { + lWarning() << "Unable to get chat rooms. Not connected."; + return list>(); + } + list> chatRooms; L_BEGIN_LOG_EXCEPTION @@ -1066,16 +1102,27 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { void MainDb::insertChatRoom (const string &peerAddress, int capabilities) { L_D(); + + if (!isConnected()) { + lWarning() << "Unable to insert chat room. Not connected."; + return; + } + d->insertChatRoom( d->insertSipAddress(peerAddress), capabilities, - Utils::getLongAsTm(static_cast(time(0))) + Utils::getTimeTAsTm(time(0)) ); } void MainDb::deleteChatRoom (const string &peerAddress) { L_D(); + if (!isConnected()) { + lWarning() << "Unable to delete chat room. Not connected."; + return; + } + L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); @@ -1154,7 +1201,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { continue; } - const tm date = Utils::getLongAsTm(message.get(LEGACY_MESSAGE_COL_DATE, 0)); + const tm date = Utils::getTimeTAsTm(message.get(LEGACY_MESSAGE_COL_DATE, 0)); bool isNull; const string url = getValueFromLegacyMessage(message, LEGACY_MESSAGE_COL_URL, isNull); @@ -1259,7 +1306,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { return 0; } - list> MainDb::getHistorySinceNotifyId ( + list> MainDb::getConferenceNotifiedEvents ( const string &peerAddress, unsigned int notifyId ) { diff --git a/src/db/main-db.h b/src/db/main-db.h index 71889472b..200d70999 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -55,9 +55,9 @@ public: int getEventsCount (FilterMask mask = NoFilter) const; // Messages, calls and conferences. - std::list> getHistorySinceNotifyId ( + std::list> getConferenceNotifiedEvents ( const std::string &peerAddress, - unsigned int notifyId + unsigned int lastNotifyId ); int getMessagesCount (const std::string &peerAddress = "") const; diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index cfde5c7ac..0013cb2f5 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -173,12 +173,12 @@ char *Utils::utf8ToChar (uint32_t ic) { // ----------------------------------------------------------------------------- -tm Utils::getLongAsTm (long time) { +tm Utils::getTimeTAsTm (time_t time) { tm result; - return *gmtime_r(&static_cast(time), &result); + return *gmtime_r(&time, &result); } -long Utils::getTmAsLong (const tm &time) { +long Utils::getTmAsTimeT (const tm &time) { return timegm(&const_cast(time)); } From a5c246f29fde0a462137394a9a792dd968ada3d1 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 27 Oct 2017 10:58:32 +0200 Subject: [PATCH 0644/2215] fix(MainDbTester): use new data --- tester/main-db-tester.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tester/main-db-tester.cpp b/tester/main-db-tester.cpp index 2d4b6037a..31d3c3114 100644 --- a/tester/main-db-tester.cpp +++ b/tester/main-db-tester.cpp @@ -43,11 +43,11 @@ static void open_database () { static void get_events_count () { MainDb mainDb(nullptr); BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); - BC_ASSERT_EQUAL(mainDb.getEventsCount(), 4976, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventsCount(), 4994, int, "%d"); BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceCallFilter), 0, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceInfoFilter), 0, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceInfoFilter), 18, int, "%d"); BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceChatMessageFilter), 4976, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::NoFilter), 4976, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::NoFilter), 4994, int, "%d"); } static void get_messages_count () { From c30a7b48f5f212609546650efd24340943bd1542 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 27 Oct 2017 11:05:17 +0200 Subject: [PATCH 0645/2215] feat(MainDb): fetch chat rooms ordered by last update --- src/db/main-db.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 895e89dd4..899ed49b1 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1049,7 +1049,8 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { list> MainDb::getChatRooms () const { static const string query = "SELECT value, creation_date, last_update_date, capabilities, subject, last_notify_id" " FROM chat_room, sip_address" - " WHERE peer_sip_address_id = id"; + " WHERE peer_sip_address_id = id" + " ORDER BY last_update_date DESC"; L_D(); From bd9af1601ecd3d78fd2b54662ed218a54c6305f7 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 27 Oct 2017 12:00:41 +0200 Subject: [PATCH 0646/2215] feat(MainDbTester): add a get_conference_notified_events test --- tester/main-db-tester.cpp | 50 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/tester/main-db-tester.cpp b/tester/main-db-tester.cpp index 31d3c3114..714ce9e2c 100644 --- a/tester/main-db-tester.cpp +++ b/tester/main-db-tester.cpp @@ -16,7 +16,9 @@ * along with this program. If not, see . */ +#include "address/address.h" #include "db/main-db.h" +#include "event-log/events.h" #include "liblinphone_tester.h" @@ -93,12 +95,58 @@ static void get_history () { ); } +static void get_conference_notified_events () { + MainDb mainDb(nullptr); + BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); + list> events = mainDb.getConferenceNotifiedEvents("sip:fake-group-2@sip.linphone.org", 1); + BC_ASSERT_EQUAL(events.size(), 3, int, "%d"); + if (events.size() != 3) + return; + + shared_ptr event; + auto it = events.cbegin(); + + event = *it; + if (!BC_ASSERT_TRUE(event->getType() == EventLog::Type::ConferenceParticipantRemoved)) return; + { + shared_ptr participantEvent = static_pointer_cast(event); + BC_ASSERT_TRUE(participantEvent->getConferenceAddress().asStringUriOnly() == "sip:fake-group-2@sip.linphone.org"); + BC_ASSERT_TRUE(participantEvent->getParticipantAddress().asStringUriOnly() == "sip:test-11@sip.linphone.org"); + BC_ASSERT_TRUE(participantEvent->getNotifyId() == 2); + } + + event = *++it; + if (!BC_ASSERT_TRUE(event->getType() == EventLog::Type::ConferenceParticipantDeviceAdded)) return; + { + shared_ptr deviceEvent = static_pointer_cast< + ConferenceParticipantDeviceEvent + >(event); + BC_ASSERT_TRUE(deviceEvent->getConferenceAddress().asStringUriOnly() == "sip:fake-group-2@sip.linphone.org"); + BC_ASSERT_TRUE(deviceEvent->getParticipantAddress().asStringUriOnly() == "sip:test-11@sip.linphone.org"); + BC_ASSERT_TRUE(deviceEvent->getNotifyId() == 3); + BC_ASSERT_TRUE(deviceEvent->getGruuAddress().asStringUriOnly() == "sip:gruu-address-1@sip.linphone.org"); + } + + event = *++it; + if (!BC_ASSERT_TRUE(event->getType() == EventLog::Type::ConferenceParticipantDeviceRemoved)) return; + { + shared_ptr deviceEvent = static_pointer_cast< + ConferenceParticipantDeviceEvent + >(event); + BC_ASSERT_TRUE(deviceEvent->getConferenceAddress().asStringUriOnly() == "sip:fake-group-2@sip.linphone.org"); + BC_ASSERT_TRUE(deviceEvent->getParticipantAddress().asStringUriOnly() == "sip:test-11@sip.linphone.org"); + BC_ASSERT_TRUE(deviceEvent->getNotifyId() == 4); + BC_ASSERT_TRUE(deviceEvent->getGruuAddress().asStringUriOnly() == "sip:gruu-address-1@sip.linphone.org"); + } +} + test_t main_db_tests[] = { TEST_NO_TAG("Open database", open_database), TEST_NO_TAG("Get events count", get_events_count), TEST_NO_TAG("Get messages count", get_messages_count), TEST_NO_TAG("Get unread messages count", get_unread_messages_count), - TEST_NO_TAG("Get history", get_history) + TEST_NO_TAG("Get history", get_history), + TEST_NO_TAG("Get conference events", get_conference_notified_events) }; test_suite_t main_db_test_suite = { From 64e550f7643b456ec4c8d7de69d0711ad8f08b09 Mon Sep 17 00:00:00 2001 From: Erwan Croze Date: Fri, 27 Oct 2017 13:44:42 +0200 Subject: [PATCH 0647/2215] Merge fix for client group chat room --- coreapi/callbacks.c | 59 ++++++- coreapi/chat.c | 60 ++++++- coreapi/linphonecore.c | 97 ++++++++++- coreapi/private.h | 6 + include/linphone/core.h | 15 ++ src/CMakeLists.txt | 3 + src/address/address.h | 2 + src/c-wrapper/api/c-chat-room.cpp | 10 ++ src/c-wrapper/c-wrapper.h | 3 +- src/chat/chat-message/chat-message.h | 1 + src/chat/chat-room/client-group-chat-room.cpp | 3 +- src/chat/chat-room/server-group-chat-room-p.h | 66 ++++++++ .../chat-room/server-group-chat-room-stub.cpp | 157 ++++++++++++++++++ src/chat/chat-room/server-group-chat-room.h | 72 ++++++++ src/conference/local-conference.h | 2 + src/conference/participant.h | 2 + .../remote-conference-event-handler.cpp | 8 +- src/conference/session/call-session.h | 2 + src/sal/op.cpp | 2 +- 19 files changed, 552 insertions(+), 18 deletions(-) create mode 100644 src/chat/chat-room/server-group-chat-room-p.h create mode 100644 src/chat/chat-room/server-group-chat-room-stub.cpp create mode 100644 src/chat/chat-room/server-group-chat-room.h diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index ba4cea411..866ace059 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -40,6 +40,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" #include "call/call-p.h" #include "chat/chat-room/chat-room.h" +#include "chat/chat-room/server-group-chat-room-p.h" #include "conference/participant.h" #include "conference/session/call-session-p.h" #include "conference/session/call-session.h" @@ -115,6 +116,28 @@ static void call_received(SalCallOp *h) { fromAddr = linphone_address_new(h->get_from()); LinphoneAddress *toAddr = linphone_address_new(h->get_to()); + if (_linphone_core_is_conference_creation(lc, toAddr)) { + if (sal_address_has_param(h->get_remote_contact_address(), "text")) + _linphone_core_create_server_group_chat_room(lc, h); + // TODO: handle media conference creation if the "text" feature tag is not present + linphone_address_unref(toAddr); + linphone_address_unref(fromAddr); + return; + } else if (sal_address_has_param(h->get_remote_contact_address(), "text")) { + linphone_address_unref(toAddr); + linphone_address_unref(fromAddr); + LinphonePrivate::Address addr(h->get_to()); + if (addr.isValid()) { + LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, addr.asStringUriOnly().c_str()); + if (cr) { + L_GET_PRIVATE_FROM_C_OBJECT(cr, ServerGroupChatRoom)->confirmJoining(h); + return; + } + } + } else { + // TODO: handle media conference joining if the "text" feature tag is not present + } + /* First check if we can answer successfully to this invite */ LinphonePresenceActivity *activity = nullptr; if ((linphone_presence_model_get_basic_status(lc->presence_model) == LinphonePresenceBasicStatusClosed) @@ -720,18 +743,38 @@ static void on_notify_response(SalOp *op){ static void refer_received(SalOp *op, const SalAddress *refer_to){ if (sal_address_has_param(refer_to, "text")) { - LinphonePrivate::Address addr(sal_address_as_string(refer_to)); + char *refer_uri = sal_address_as_string(refer_to); + LinphonePrivate::Address addr(refer_uri); + bctbx_free(refer_uri); if (addr.isValid()) { LinphoneCore *lc = reinterpret_cast(op->get_sal()->get_user_pointer()); if (addr.hasUriParam("method") && (addr.getUriParamValue("method") == "BYE")) { - // The server asks a participant to leave a chat room - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(addr)); - if (cr) { - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->leave(); - static_cast(op)->reply(SalReasonNone); - return; + if (linphone_core_conference_server_enabled(lc)) { + // Removal of a participant at the server side + LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, op->get_to()); + if (cr) { + Address fromAddr(op->get_from()); + std::shared_ptr participant = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(fromAddr); + if (!participant || !participant->isAdmin()) { + static_cast(op)->reply(SalReasonDeclined); + return; + } + participant = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(addr); + if (participant) + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->removeParticipant(participant); + static_cast(op)->reply(SalReasonNone); + return; + } + } else { + // The server asks a participant to leave a chat room + LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, addr.asStringUriOnly().c_str()); + if (cr) { + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->leave(); + static_cast(op)->reply(SalReasonNone); + return; + } + static_cast(op)->reply(SalReasonDeclined); } - static_cast(op)->reply(SalReasonDeclined); } else if (addr.hasParam("admin")) { LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(Address(op->get_to()))); if (cr) { diff --git a/coreapi/chat.c b/coreapi/chat.c index 75a4e9636..87f07bc2e 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -79,8 +79,61 @@ LinphoneChatRoom *linphone_core_create_client_group_chat_room (LinphoneCore *lc, return L_GET_C_BACK_PTR(lc->cppCore->createClientGroupChatRoom(L_C_TO_STRING(subject))); } -void linphone_core_delete_chat_room (LinphoneCore *, LinphoneChatRoom *cr) { - LinphonePrivate::Core::deleteChatRoom(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); +static LinphoneChatRoom *_linphone_core_get_or_create_chat_room(LinphoneCore *lc, const char *to) { + LinphoneAddress *to_addr = linphone_core_interpret_url(lc, to); + LinphoneChatRoom *ret; + + if (to_addr == NULL) { + ms_error("linphone_core_get_or_create_chat_room(): Cannot make a valid address with %s", to); + return NULL; + } + ret = _linphone_core_get_chat_room(lc, to_addr); + linphone_address_unref(to_addr); + if (!ret) { + ret = _linphone_core_create_chat_room_from_url(lc, to); + } + return ret; +} + +LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr) { + LinphoneChatRoom *ret = _linphone_core_get_chat_room(lc, addr); + if (!ret) { + ret = _linphone_core_create_chat_room(lc, addr); + } + return ret; +} + +LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, const char *subject) { + const char *factoryUri = linphone_core_get_conference_factory_uri(lc); + if (!factoryUri) + return nullptr; + LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, factoryUri, subject); + lc->chatrooms = bctbx_list_append(lc->chatrooms, cr); + return cr; +} + +LinphoneChatRoom *_linphone_core_join_client_group_chat_room (LinphoneCore *lc, const LinphonePrivate::Address &addr) { + LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); + lc->chatrooms = bctbx_list_append(lc->chatrooms, cr); + return cr; +} + +LinphoneChatRoom *_linphone_core_create_server_group_chat_room (LinphoneCore *lc, LinphonePrivate::SalCallOp *op) { + LinphoneChatRoom *cr = _linphone_server_group_chat_room_new(lc, op); + _linphone_core_add_group_chat_room(lc, L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getConferenceAddress(), cr); + lc->chatrooms = bctbx_list_append(lc->chatrooms, cr); + return cr; +} + +void linphone_core_delete_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr) { + if (bctbx_list_find(lc->chatrooms, cr)) { + lc->chatrooms = bctbx_list_remove(lc->chatrooms, cr); + linphone_chat_room_delete_history(cr); + linphone_chat_room_unref(cr); + } else { + ms_error("linphone_core_delete_chat_room(): chatroom [%p] isn't part of LinphoneCore.", cr); + } } LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const char *to) { @@ -89,7 +142,8 @@ LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const c int linphone_core_message_received(LinphoneCore *lc, LinphonePrivate::SalOp *op, const SalMessage *sal_msg) { LinphoneReason reason = LinphoneReasonNotAcceptable; - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(LinphonePrivate::Address(op->get_from()))); + LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, + linphone_core_conference_server_enabled(lc) ? op->get_to() : op->get_from()); if (cr) reason = L_GET_PRIVATE_FROM_C_OBJECT(cr)->messageReceived(op, sal_msg); else { diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 156df2ba2..1a8145e96 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "quality_reporting.h" #include "lime.h" #include "conference_private.h" +#include "logger/logger.h" #ifdef SQLITE_STORAGE_ENABLED #include "sqlite3_bctbx_vfs.h" @@ -48,6 +49,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mediastreamer2/msvolume.h" #include "chat/chat-room/client-group-chat-room-p.h" +#include "chat/chat-room/server-group-chat-room-p.h" #include "conference/remote-conference-event-handler.h" #include "core/core.h" @@ -2137,11 +2139,25 @@ static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEve } } +static void _linphone_core_conference_subscription_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state) { + if ((linphone_event_get_subscription_dir(lev) == LinphoneSubscriptionIncoming) && (state == LinphoneSubscriptionIncomingReceived)) { + const LinphoneAddress *resource = linphone_event_get_resource(lev); + char *resourceUri = linphone_address_as_string_uri_only(resource); + LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, resourceUri); + bctbx_free(resourceUri); + if (cr) { + linphone_event_accept_subscription(lev); + L_GET_PRIVATE_FROM_C_OBJECT(cr, ServerGroupChatRoom)->subscribeReceived(lev); + } else + linphone_event_deny_subscription(lev, LinphoneReasonDeclined); + } +} + static void linphone_core_internal_subscription_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state) { if (strcasecmp(linphone_event_get_name(lev), "Presence") == 0) { linphone_friend_list_subscription_state_changed(lc, lev, state); } else if (strcmp(linphone_event_get_name(lev), "conference") == 0) { - + _linphone_core_conference_subscription_state_changed(lc, lev, state); } } @@ -7146,7 +7162,84 @@ void linphone_core_set_conference_factory_uri(LinphoneCore *lc, const char *uri) } const char * linphone_core_get_conference_factory_uri(const LinphoneCore *lc) { - return lp_config_get_string(linphone_core_get_config(lc), "misc", "conference_factory_uri", nullptr); + return lp_config_get_string(linphone_core_get_config(lc), "misc", "conference_factory_uri", "sip:"); +} + +bool_t _linphone_core_has_group_chat_room(const LinphoneCore *lc, const char *id) { + bool_t result; + bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, id); + bctbx_iterator_t *endit = bctbx_map_cchar_end(lc->group_chat_rooms); + result = !bctbx_iterator_cchar_equals(it, endit); + bctbx_iterator_cchar_delete(endit); + bctbx_iterator_cchar_delete(it); + return result; +} + +void _linphone_core_add_group_chat_room(LinphoneCore *lc, const LinphonePrivate::Address &addr, LinphoneChatRoom *cr) { + Address cleanedAddr(addr); + cleanedAddr.clean(); + cleanedAddr.setPort(0); + bctbx_pair_t *pair = reinterpret_cast(bctbx_pair_cchar_new(cleanedAddr.asStringUriOnly().c_str(), linphone_chat_room_ref(cr))); + bctbx_map_cchar_insert_and_delete(lc->group_chat_rooms, pair); +} + +void _linphone_core_remove_group_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr) { + const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(cr); + Address cleanedAddr(*L_GET_CPP_PTR_FROM_C_OBJECT(confAddr)); + cleanedAddr.clean(); + cleanedAddr.setPort(0); + bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, cleanedAddr.asStringUriOnly().c_str()); + bctbx_iterator_t *endit = bctbx_map_cchar_end(lc->group_chat_rooms); + if (!bctbx_iterator_cchar_equals(it, endit)) { + bctbx_map_cchar_erase(lc->group_chat_rooms, it); + linphone_chat_room_unref(cr); + } + bctbx_iterator_cchar_delete(endit); + bctbx_iterator_cchar_delete(it); +} + +LinphoneChatRoom *_linphone_core_find_group_chat_room(const LinphoneCore *lc, const char *id) { + LinphoneChatRoom *result = nullptr; + Address cleanedAddr(id); + cleanedAddr.clean(); + cleanedAddr.setPort(0); + bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, cleanedAddr.asStringUriOnly().c_str()); + bctbx_iterator_t *endit = bctbx_map_cchar_end(lc->group_chat_rooms); + if (!bctbx_iterator_cchar_equals(it, endit)) { + result = reinterpret_cast(bctbx_pair_cchar_get_second(bctbx_iterator_cchar_get_pair(it))); + } else { + bctbx_iterator_cchar_delete(it); + Address backupAddress(cleanedAddr); + Address factoryAddress(linphone_core_get_conference_factory_uri(lc)); + backupAddress.setDomain(factoryAddress.getDomain()); + lWarning() << "We don't found the chat room with address " << id << " as a temporary workaround, searching with " << backupAddress.asString(); + it = bctbx_map_cchar_find_key(lc->group_chat_rooms, backupAddress.asStringUriOnly().c_str()); + + if (!bctbx_iterator_cchar_equals(it, endit)) { + result = reinterpret_cast(bctbx_pair_cchar_get_second(bctbx_iterator_cchar_get_pair(it))); + } + if (!result) lWarning() << "Chatroom " << id << " or " << backupAddress.asString() << " not found!"; + } + bctbx_iterator_cchar_delete(endit); + bctbx_iterator_cchar_delete(it); + return result; +} + +void linphone_core_enable_conference_server (LinphoneCore *lc, bool_t enable) { + lp_config_set_int(linphone_core_get_config(lc), "misc", "conference_server_enabled", enable); +} + +bool_t linphone_core_conference_server_enabled (const LinphoneCore *lc) { + return lp_config_get_int(linphone_core_get_config(lc), "misc", "conference_server_enabled", FALSE) ? TRUE : FALSE; +} + +bool_t _linphone_core_is_conference_creation (const LinphoneCore *lc, const LinphoneAddress *addr) { + LinphoneAddress *factoryAddr = linphone_address_new(linphone_core_get_conference_factory_uri(lc)); + if (!factoryAddr) + return FALSE; + bool_t result = linphone_address_weak_equal(factoryAddr, addr); + linphone_address_unref(factoryAddr); + return result; } void linphone_core_set_tls_cert(LinphoneCore *lc, const char *tls_cert) { diff --git a/coreapi/private.h b/coreapi/private.h index be2eec3f1..7186c546d 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -457,6 +457,11 @@ bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription extern LinphonePrivate::Sal::Callbacks linphone_sal_callbacks; LINPHONE_PUBLIC bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); LINPHONE_PUBLIC bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc); +bool_t _linphone_core_has_group_chat_room (const LinphoneCore *lc, const char *id); +void _linphone_core_add_group_chat_room (LinphoneCore *lc, const LinphonePrivate::Address &addr, LinphoneChatRoom *cr); +void _linphone_core_remove_group_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr); +bool_t _linphone_core_is_conference_creation (const LinphoneCore *lc, const LinphoneAddress *addr); +LinphoneChatRoom *_linphone_core_create_server_group_chat_room (LinphoneCore *lc, LinphonePrivate::SalCallOp *op); void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description); @@ -472,6 +477,7 @@ void _linphone_proxy_config_release_ops(LinphoneProxyConfig *obj); /*chat*/ LinphoneChatRoom * linphone_chat_room_new(LinphoneCore *core, const LinphoneAddress *addr); LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, const char *uri, const char *subject); +LinphoneChatRoom *_linphone_server_group_chat_room_new (LinphoneCore *core, LinphonePrivate::SalCallOp *op); void linphone_chat_room_release(LinphoneChatRoom *cr); void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call); bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr); diff --git a/include/linphone/core.h b/include/linphone/core.h index 336d1d7c4..0ecc1ae5d 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -4235,6 +4235,21 @@ void linphone_core_set_conference_factory_uri(LinphoneCore *lc, const char *uri) */ const char * linphone_core_get_conference_factory_uri(const LinphoneCore *lc); +/** + * Enable the conference server feature. This has the effect to listen of the conference factory uri + * to create new conferences when receiving INVITE messages there. + * @param[in] lc A #LinphoneCore object + * @param[in] enable A boolean value telling whether to enable or disable the conference server feature + */ +void linphone_core_enable_conference_server (LinphoneCore *lc, bool_t enable); + +/** + * Tells whether the conference server feature is enabled. + * @param[in] lc A #LinphoneCore object + * @return A boolean value telling whether the conference server feature is enabled or not + */ +bool_t linphone_core_conference_server_enabled (const LinphoneCore *lc); + /** * @} */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 37de6f4dd..98304a28c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -39,6 +39,8 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES chat/chat-room/client-group-chat-room.h chat/chat-room/real-time-text-chat-room-p.h chat/chat-room/real-time-text-chat-room.h + chat/chat-room/server-group-chat-room-p.h + chat/chat-room/server-group-chat-room.h chat/cpim/cpim.h chat/cpim/header/cpim-core-headers.h chat/cpim/header/cpim-generic-header.h @@ -150,6 +152,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES chat/chat-room/chat-room.cpp chat/chat-room/client-group-chat-room.cpp chat/chat-room/real-time-text-chat-room.cpp + chat/chat-room/server-group-chat-room-stub.cpp chat/cpim/header/cpim-core-headers.cpp chat/cpim/header/cpim-generic-header.cpp chat/cpim/header/cpim-header.cpp diff --git a/src/address/address.h b/src/address/address.h index b765067d3..af3dc0f1f 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -34,6 +34,8 @@ class LINPHONE_PUBLIC Address : public ClonableObject { friend class CallSession; friend class ClientGroupChatRoom; friend class ClientGroupChatRoomPrivate; + friend class ServerGroupChatRoom; + friend class ServerGroupChatRoomPrivate; public: explicit Address (const std::string &address = ""); diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index c86f16391..c30abf7dc 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -28,8 +28,10 @@ #include "chat/chat-room/basic-chat-room.h" #include "chat/chat-room/client-group-chat-room.h" #include "chat/chat-room/real-time-text-chat-room-p.h" +#include "chat/chat-room/server-group-chat-room-p.h" #include "conference/participant.h" #include "core/core-p.h" +#include "content/content.h" // ============================================================================= @@ -352,6 +354,14 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, cons return cr; } +LinphoneChatRoom *_linphone_server_group_chat_room_new (LinphoneCore *core, LinphonePrivate::SalCallOp *op) { + LinphoneChatRoom *cr = L_INIT(ChatRoom); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, LinphonePrivate::ObjectFactory::create(core, op)); + L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); + L_GET_PRIVATE_FROM_C_OBJECT(cr, ServerGroupChatRoom)->confirmCreation(); + return cr; +} + /* DEPRECATED */ void linphone_chat_room_destroy (LinphoneChatRoom *cr) { linphone_chat_room_unref(cr); diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index 851385f5b..885a1c809 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -51,7 +51,8 @@ F(EventLog, ConferenceNotifiedEvent) \ F(EventLog, ConferenceParticipantDeviceEvent) \ F(EventLog, ConferenceParticipantEvent) \ - F(EventLog, ConferenceSubjectEvent) + F(EventLog, ConferenceSubjectEvent) \ + F(ChatRoom, ServerGroupChatRoom) // ============================================================================= // Register belle-sip ID. diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index b1c0a0139..76ae99890 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -41,6 +41,7 @@ class LINPHONE_PUBLIC ChatMessage : public Object { friend class ChatRoomPrivate; friend class CpimChatMessageModifier; friend class RealTimeTextChatRoomPrivate; + friend class ServerGroupChatRoomPrivate; public: L_OVERRIDE_SHARED_FROM_THIS(ChatMessage); diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 73ac9d595..1e89cf723 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -441,8 +441,7 @@ void ClientGroupChatRoom::onCallSessionStateChanged ( if (state == LinphoneCallConnected) { if (d->state == ChatRoom::State::CreationPending) { - Address addr(session->getRemoteContact()); - addr.clean(); + Address addr(session->getRemoteContactAddress()->asStringUriOnly()); onConferenceCreated(addr); if (session->getRemoteContactAddress()->hasParam("isfocus")) dConference->eventHandler->subscribe(getConferenceAddress()); diff --git a/src/chat/chat-room/server-group-chat-room-p.h b/src/chat/chat-room/server-group-chat-room-p.h new file mode 100644 index 000000000..5df197179 --- /dev/null +++ b/src/chat/chat-room/server-group-chat-room-p.h @@ -0,0 +1,66 @@ +/* + * server-group-chat-room-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _SERVER_GROUP_CHAT_ROOM_P_H_ +#define _SERVER_GROUP_CHAT_ROOM_P_H_ + +// From coreapi. +#include "private.h" + +#include "address/address.h" +#include "chat-room-p.h" +#include "server-group-chat-room.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class Participant; + +class ServerGroupChatRoomPrivate : public ChatRoomPrivate { +public: + ServerGroupChatRoomPrivate (LinphoneCore *core); + virtual ~ServerGroupChatRoomPrivate () = default; + + std::shared_ptr addParticipant (const Address &addr); + void confirmCreation (); + void confirmJoining (SalCallOp *op); + std::shared_ptr findRemovedParticipant (const std::shared_ptr &session) const; + std::string generateConferenceId () const; + void removeParticipant (const std::shared_ptr &participant); + void subscribeReceived (LinphoneEvent *event); + void update (SalCallOp *op); + + void dispatchMessage (const Address &fromAddr, const Content &content); + void storeOrUpdateMessage (const std::shared_ptr &msg) override; + LinphoneReason messageReceived (SalOp *op, const SalMessage *msg) override; + +private: + void designateAdmin (); + bool isAdminLeft () const; + +private: + L_DECLARE_PUBLIC(ServerGroupChatRoom); + + std::list> removedParticipants; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _SERVER_GROUP_CHAT_ROOM_P_H_ diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp new file mode 100644 index 000000000..da4ef27a3 --- /dev/null +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -0,0 +1,157 @@ +/* + * server-group-chat-room.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include "address/address-p.h" +#include "address/address.h" +#include "c-wrapper/c-wrapper.h" +#include "chat/chat-message/chat-message-p.h" +#include "chat/modifier/cpim-chat-message-modifier.h" +#include "conference/local-conference-event-handler.h" +#include "conference/local-conference-p.h" +#include "conference/participant-p.h" +#include "conference/session/call-session-p.h" +#include "content/content-type.h" +#include "logger/logger.h" +#include "sal/refer-op.h" +#include "server-group-chat-room-p.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +ServerGroupChatRoomPrivate::ServerGroupChatRoomPrivate (LinphoneCore *core) : ChatRoomPrivate(core) {} + +// ----------------------------------------------------------------------------- + +shared_ptr ServerGroupChatRoomPrivate::addParticipant (const Address &addr) { + return nullptr; +} + +void ServerGroupChatRoomPrivate::confirmCreation () { +} + +void ServerGroupChatRoomPrivate::confirmJoining (SalCallOp *op) { +} + +shared_ptr ServerGroupChatRoomPrivate::findRemovedParticipant (const shared_ptr &session) const { + return nullptr; +} + +string ServerGroupChatRoomPrivate::generateConferenceId () const { + return ""; +} + +void ServerGroupChatRoomPrivate::removeParticipant (const shared_ptr &participant) { +} + +void ServerGroupChatRoomPrivate::subscribeReceived (LinphoneEvent *event) { +} + +void ServerGroupChatRoomPrivate::update (SalCallOp *op) { +} + +// ----------------------------------------------------------------------------- + +void ServerGroupChatRoomPrivate::dispatchMessage (const Address &fromAddr, const Content &content) { +} + +void ServerGroupChatRoomPrivate::storeOrUpdateMessage (const std::shared_ptr &msg) { +} + +LinphoneReason ServerGroupChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *salMsg) { + return LinphoneReasonNone; +} + +// ----------------------------------------------------------------------------- + +void ServerGroupChatRoomPrivate::designateAdmin () { +} + +bool ServerGroupChatRoomPrivate::isAdminLeft () const { + return false; +} + +// ============================================================================= + +ServerGroupChatRoom::ServerGroupChatRoom (LinphoneCore *core, SalCallOp *op) + : ChatRoom(*new ServerGroupChatRoomPrivate(core)), LocalConference(core, Address(op->get_to()), nullptr) { +} + +int ServerGroupChatRoom::getCapabilities () const { + return 0; +} + +// ----------------------------------------------------------------------------- + +void ServerGroupChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { +} + +void ServerGroupChatRoom::addParticipants (const list

      &addresses, const CallSessionParams *params, bool hasMedia) { +} + +bool ServerGroupChatRoom::canHandleParticipants () const { + return FALSE; +} + +shared_ptr ServerGroupChatRoom::findParticipant (const Address &addr) const { + return nullptr; +} + +const Address &ServerGroupChatRoom::getConferenceAddress () const { + return LocalConference::getConferenceAddress(); +} + +int ServerGroupChatRoom::getNbParticipants () const { + return 0; +} + +list> ServerGroupChatRoom::getParticipants () const { + return LocalConference::getParticipants(); +} + +const string &ServerGroupChatRoom::getSubject () const { + return LocalConference::getSubject(); +} + +void ServerGroupChatRoom::join () {} + +void ServerGroupChatRoom::leave () {} + +void ServerGroupChatRoom::removeParticipant (const shared_ptr &participant) { +} + +void ServerGroupChatRoom::removeParticipants (const list> &participants) { +} + +void ServerGroupChatRoom::setParticipantAdminStatus (shared_ptr &participant, bool isAdmin) { +} + +void ServerGroupChatRoom::setSubject (const std::string &subject) { +} + +// ----------------------------------------------------------------------------- + +void ServerGroupChatRoom::onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) { +} + +LINPHONE_END_NAMESPACE diff --git a/src/chat/chat-room/server-group-chat-room.h b/src/chat/chat-room/server-group-chat-room.h new file mode 100644 index 000000000..efe5f79f0 --- /dev/null +++ b/src/chat/chat-room/server-group-chat-room.h @@ -0,0 +1,72 @@ +/* + * server-group-chat-room.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _SERVER_GROUP_CHAT_ROOM_H_ +#define _SERVER_GROUP_CHAT_ROOM_H_ + +// From coreapi +#include "private.h" + +#include "chat/chat-room/chat-room.h" +#include "conference/local-conference.h" + +#include "linphone/types.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ServerGroupChatRoomPrivate; + +class ServerGroupChatRoom : public ChatRoom, public LocalConference { +public: + ServerGroupChatRoom (LinphoneCore *core, SalCallOp *op); + virtual ~ServerGroupChatRoom () = default; + + int getCapabilities () const override; + +public: + /* ConferenceInterface */ + void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; + void addParticipants (const std::list
      &addresses, const CallSessionParams *params, bool hasMedia) override; + bool canHandleParticipants () const override; + std::shared_ptr findParticipant (const Address &addr) const override; + const Address &getConferenceAddress () const override; + int getNbParticipants () const override; + std::list> getParticipants () const override; + const std::string &getSubject () const override; + void join () override; + void leave () override; + void removeParticipant (const std::shared_ptr &participant) override; + void removeParticipants (const std::list> &participants) override; + void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) override; + void setSubject (const std::string &subject) override; + +private: + /* CallSessionListener */ + void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) override; + +private: + L_DECLARE_PRIVATE(ServerGroupChatRoom); + L_DISABLE_COPY(ServerGroupChatRoom); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _SERVER_GROUP_CHAT_ROOM_H_ diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h index 0c425447a..f27b8f75b 100644 --- a/src/conference/local-conference.h +++ b/src/conference/local-conference.h @@ -29,6 +29,8 @@ LINPHONE_BEGIN_NAMESPACE class LocalConferencePrivate; class LocalConference : public Conference { + friend class ServerGroupChatRoomPrivate; + public: LocalConference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); diff --git a/src/conference/participant.h b/src/conference/participant.h index a1b2904c3..aefe33fab 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -45,6 +45,8 @@ class Participant : public Object { friend class LocalConferenceEventHandlerPrivate; friend class MediaSessionPrivate; friend class RemoteConference; + friend class ServerGroupChatRoom; + friend class ServerGroupChatRoomPrivate; public: explicit Participant (const Address &address); diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 41430353e..da3f19de8 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -78,8 +78,14 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { tm = static_cast(Utils::stoll(confInfo->getConferenceDescription()->getFreeText().get())); Address cleanedConfAddress = d->confAddress; + cleanedConfAddress.clean(); cleanedConfAddress.setPort(0); - if (confInfo->getEntity() == cleanedConfAddress.asString()) { + // Temporary workaround + Address entityAddress(confInfo->getEntity().c_str()); + Address cleanedConfAddress2(cleanedConfAddress); + cleanedConfAddress2.setDomain(entityAddress.getDomain()); + if (confInfo->getEntity() == cleanedConfAddress.asString() + || confInfo->getEntity() == cleanedConfAddress2.asString()) { if (confInfo->getConferenceDescription().present() && confInfo->getConferenceDescription().get().getSubject().present()) d->listener->onSubjectChanged(tm, confInfo->getConferenceDescription().get().getSubject().get()); diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index c0eaccc8b..70470d443 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -40,6 +40,8 @@ class LINPHONE_PUBLIC CallSession : public Object { friend class ClientGroupChatRoom; friend class ClientGroupChatRoomPrivate; friend class Conference; + friend class ServerGroupChatRoom; + friend class ServerGroupChatRoomPrivate; public: L_OVERRIDE_SHARED_FROM_THIS(CallSession); diff --git a/src/sal/op.cpp b/src/sal/op.cpp index e9a07b34a..896aafd45 100644 --- a/src/sal/op.cpp +++ b/src/sal/op.cpp @@ -426,7 +426,7 @@ int SalOp::process_redirect(){ belle_sip_request_set_uri(request, redirect_uri); redirect_uri = BELLE_SIP_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(redirect_uri))); belle_sip_uri_set_port(redirect_uri, 0); - belle_sip_uri_set_transport_param(redirect_uri, nullptr); + belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(redirect_uri), "transport"); belle_sip_header_address_set_uri((belle_sip_header_address_t*)to, redirect_uri); send_request(request); return 0; From 90d8d651cb9dec8572997c6d1c077b804c9eae6e Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 27 Oct 2017 14:11:34 +0200 Subject: [PATCH 0648/2215] feat(Core): use a separate file for chat-room low api --- src/CMakeLists.txt | 1 + src/core/core-chat-room.cpp | 162 ++++++++++++++++++++++++++++++++++++ src/core/core.cpp | 150 +-------------------------------- 3 files changed, 165 insertions(+), 148 deletions(-) create mode 100644 src/core/core-chat-room.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 98304a28c..ef57a4de0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -178,6 +178,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES content/content-manager.cpp content/content-type.cpp content/content.cpp + core/core-chat-room.cpp core/core.cpp core/paths/paths.cpp core/platform-helpers/platform-helpers.cpp diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp new file mode 100644 index 000000000..ac50b37fa --- /dev/null +++ b/src/core/core-chat-room.cpp @@ -0,0 +1,162 @@ +/* + * core-chat-room.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include "chat/chat-room/basic-chat-room.h" +#include "chat/chat-room/chat-room-p.h" +#include "chat/chat-room/real-time-text-chat-room.h" +#include "core-p.h" +#include "logger/logger.h" + +// TODO: Remove me later. +#include "c-wrapper/c-wrapper.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +// ----------------------------------------------------------------------------- +// Helpers. +// ----------------------------------------------------------------------------- + +static inline Address getCleanedPeerAddress (const Address &peerAddress) { + Address cleanedAddress = peerAddress; + cleanedAddress.clean(); + cleanedAddress.setPort(0); + return cleanedAddress; +} + +// ----------------------------------------------------------------------------- + +shared_ptr CorePrivate::createChatRoom (const Address &peerAddress, bool isRtt) { + shared_ptr chatRoom; + + if (isRtt) + chatRoom = ObjectFactory::create(cCore, peerAddress); + else + chatRoom = ObjectFactory::create(cCore, peerAddress); + + ChatRoomPrivate *dChatRoom = chatRoom->getPrivate(); + dChatRoom->setState(ChatRoom::State::Instantiated); + dChatRoom->setState(ChatRoom::State::Created); + + return chatRoom; +} + +void CorePrivate::insertChatRoom (const shared_ptr &chatRoom) { + L_ASSERT(chatRoom); + L_ASSERT(chatRoom->getState() == ChatRoom::State::Created); + + string peerAddress = getCleanedPeerAddress(chatRoom->getPeerAddress()).asStringUriOnly(); + deleteChatRoom(peerAddress); + + chatRooms.push_back(chatRoom); + chatRoomsByUri[peerAddress] = chatRoom; +} + +void CorePrivate::deleteChatRoom (const string &peerAddress) { + auto it = chatRoomsByUri.find(peerAddress); + if (it != chatRoomsByUri.end()) + chatRooms.erase( + find_if(chatRooms.begin(), chatRooms.end(), [&peerAddress](const shared_ptr &chatRoom) { + return peerAddress == chatRoom->getPeerAddress().asStringUriOnly(); + }) + ); +} + +void CorePrivate::insertChatRoomWithDb (const shared_ptr &chatRoom) { + insertChatRoom(chatRoom); + mainDb->insertChatRoom( + getCleanedPeerAddress(chatRoom->getPeerAddress()).asStringUriOnly(), + chatRoom->getCapabilities() + ); +} + +void CorePrivate::deleteChatRoomWithDb (const string &peerAddress) { + deleteChatRoom(peerAddress); + mainDb->deleteChatRoom(peerAddress); +} + +// ----------------------------------------------------------------------------- + +const list> &Core::getChatRooms () const { + L_D(); + return d->chatRooms; +} + +shared_ptr Core::findChatRoom (const Address &peerAddress) const { + L_D(); + auto it = d->chatRoomsByUri.find(getCleanedPeerAddress(peerAddress).asStringUriOnly()); + return it == d->chatRoomsByUri.cend() ? shared_ptr() : it->second; +} + +shared_ptr Core::createClientGroupChatRoom (const string &subject) { + L_D(); + + const char *factoryUri = linphone_core_get_conference_factory_uri(d->cCore); + if (!factoryUri) + return nullptr; + + return L_GET_CPP_PTR_FROM_C_OBJECT( + _linphone_client_group_chat_room_new(d->cCore, factoryUri, L_STRING_TO_C(subject)) + ); +} + +shared_ptr Core::getOrCreateBasicChatRoom (const Address &peerAddress, bool isRtt) { + L_D(); + + if (!peerAddress.isValid()) { + lWarning() << "Cannot find get or create chat room with invalid peer address."; + return nullptr; + } + + shared_ptr chatRoom = findChatRoom(peerAddress); + if (chatRoom) + return chatRoom; + + chatRoom = d->createChatRoom(peerAddress, isRtt); + d->insertChatRoomWithDb(chatRoom); + + return chatRoom; +} + +shared_ptr Core::getOrCreateBasicChatRoom (const string &peerAddress, bool isRtt) { + L_D(); + + LinphoneAddress *address = linphone_core_interpret_url(d->cCore, L_STRING_TO_C(peerAddress)); + if (!address) { + lError() << "Cannot make a valid address with: `" << peerAddress << "`."; + return nullptr; + } + + shared_ptr chatRoom = getOrCreateBasicChatRoom(*L_GET_CPP_PTR_FROM_C_OBJECT(address), isRtt); + linphone_address_unref(address); + return chatRoom; +} + +void Core::deleteChatRoom (const shared_ptr &chatRoom) { + CorePrivate *d = chatRoom->getCore()->cppCore->getPrivate(); + string peerAddress = getCleanedPeerAddress(chatRoom->getPeerAddress()).asStringUriOnly(); + d->deleteChatRoomWithDb(peerAddress); +} + +LINPHONE_END_NAMESPACE diff --git a/src/core/core.cpp b/src/core/core.cpp index f13d69707..152276c9a 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -17,96 +17,21 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include -#include - -#include "chat/chat-room/basic-chat-room.h" -#include "chat/chat-room/chat-room-p.h" -#include "chat/chat-room/real-time-text-chat-room.h" #include "core-p.h" -#include "db/main-db.h" #include "logger/logger.h" -#include "object/object-p.h" #include "paths/paths.h" // TODO: Remove me later. #include "c-wrapper/c-wrapper.h" -#include "private.h" - -#define LINPHONE_DB "linphone.db" // ============================================================================= +#define LINPHONE_DB "linphone.db" + using namespace std; LINPHONE_BEGIN_NAMESPACE -// ----------------------------------------------------------------------------- -// Helpers. -// ----------------------------------------------------------------------------- - -static inline Address getCleanedPeerAddress (const Address &peerAddress) { - Address cleanedAddress = peerAddress; - cleanedAddress.clean(); - cleanedAddress.setPort(0); - return cleanedAddress; -} - -// ----------------------------------------------------------------------------- -// CorePrivate: ChatRoom. -// ----------------------------------------------------------------------------- - -shared_ptr CorePrivate::createChatRoom (const Address &peerAddress, bool isRtt) { - shared_ptr chatRoom; - - if (isRtt) - chatRoom = ObjectFactory::create(cCore, peerAddress); - else - chatRoom = ObjectFactory::create(cCore, peerAddress); - - ChatRoomPrivate *dChatRoom = chatRoom->getPrivate(); - dChatRoom->setState(ChatRoom::State::Instantiated); - dChatRoom->setState(ChatRoom::State::Created); - - return chatRoom; -} - -void CorePrivate::insertChatRoom (const shared_ptr &chatRoom) { - L_ASSERT(chatRoom); - L_ASSERT(chatRoom->getState() == ChatRoom::State::Created); - - string peerAddress = getCleanedPeerAddress(chatRoom->getPeerAddress()).asStringUriOnly(); - deleteChatRoom(peerAddress); - - chatRooms.push_back(chatRoom); - chatRoomsByUri[peerAddress] = chatRoom; -} - -void CorePrivate::deleteChatRoom (const string &peerAddress) { - auto it = chatRoomsByUri.find(peerAddress); - if (it != chatRoomsByUri.end()) - chatRooms.erase( - find_if(chatRooms.begin(), chatRooms.end(), [&peerAddress](const shared_ptr &chatRoom) { - return peerAddress == chatRoom->getPeerAddress().asStringUriOnly(); - }) - ); -} - -void CorePrivate::insertChatRoomWithDb (const shared_ptr &chatRoom) { - insertChatRoom(chatRoom); - mainDb->insertChatRoom( - getCleanedPeerAddress(chatRoom->getPeerAddress()).asStringUriOnly(), - chatRoom->getCapabilities() - ); -} - -void CorePrivate::deleteChatRoomWithDb (const string &peerAddress) { - deleteChatRoom(peerAddress); - mainDb->deleteChatRoom(peerAddress); -} - -// ============================================================================= - Core::Core (LinphoneCore *cCore) : Object(*new CorePrivate) { L_D(); d->cCore = cCore; @@ -131,10 +56,6 @@ Core::Core (LinphoneCore *cCore) : Object(*new CorePrivate) { d->insertChatRoom(chatRoom); } -// ----------------------------------------------------------------------------- -// Paths. -// ----------------------------------------------------------------------------- - string Core::getDataPath() const { L_D(); return Paths::getPath(Paths::Data, static_cast(d->cCore->platform_helper)); @@ -145,71 +66,4 @@ string Core::getConfigPath() const { return Paths::getPath(Paths::Config, static_cast(d->cCore->platform_helper)); } -// ----------------------------------------------------------------------------- -// ChatRoom. -// ----------------------------------------------------------------------------- - -const list> &Core::getChatRooms () const { - L_D(); - return d->chatRooms; -} - -shared_ptr Core::findChatRoom (const Address &peerAddress) const { - L_D(); - auto it = d->chatRoomsByUri.find(getCleanedPeerAddress(peerAddress).asStringUriOnly()); - return it == d->chatRoomsByUri.cend() ? shared_ptr() : it->second; -} - -shared_ptr Core::createClientGroupChatRoom (const string &subject) { - L_D(); - - const char *factoryUri = linphone_core_get_conference_factory_uri(d->cCore); - if (!factoryUri) - return nullptr; - - return L_GET_CPP_PTR_FROM_C_OBJECT( - _linphone_client_group_chat_room_new(d->cCore, factoryUri, L_STRING_TO_C(subject)) - ); -} - -shared_ptr Core::getOrCreateBasicChatRoom (const Address &peerAddress, bool isRtt) { - L_D(); - - if (!peerAddress.isValid()) { - lWarning() << "Cannot find get or create chat room with invalid peer address."; - return nullptr; - } - - shared_ptr chatRoom = findChatRoom(peerAddress); - if (chatRoom) - return chatRoom; - - chatRoom = d->createChatRoom(peerAddress, isRtt); - d->insertChatRoomWithDb(chatRoom); - - return chatRoom; -} - -shared_ptr Core::getOrCreateBasicChatRoom (const string &peerAddress, bool isRtt) { - L_D(); - - LinphoneAddress *address = linphone_core_interpret_url(d->cCore, L_STRING_TO_C(peerAddress)); - if (!address) { - lError() << "Cannot make a valid address with: `" << peerAddress << "`."; - return nullptr; - } - - shared_ptr chatRoom = getOrCreateBasicChatRoom(*L_GET_CPP_PTR_FROM_C_OBJECT(address), isRtt); - linphone_address_unref(address); - return chatRoom; -} - -void Core::deleteChatRoom (const shared_ptr &chatRoom) { - CorePrivate *d = chatRoom->getCore()->cppCore->getPrivate(); - string peerAddress = getCleanedPeerAddress(chatRoom->getPeerAddress()).asStringUriOnly(); - d->deleteChatRoomWithDb(peerAddress); -} - -// ----------------------------------------------------------------------------- - LINPHONE_END_NAMESPACE From 4315f674f734cb644044c6d6cf15485ae0813408 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 27 Oct 2017 14:28:05 +0200 Subject: [PATCH 0649/2215] fix(callbacks): fix partially previous merge --- coreapi/callbacks.c | 10 +++++++--- src/c-wrapper/api/c-chat-room.cpp | 2 +- src/c-wrapper/c-wrapper.h | 4 ++-- src/conference/remote-conference-event-handler.cpp | 11 ++++++++--- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 866ace059..faf7813d8 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -128,7 +128,7 @@ static void call_received(SalCallOp *h) { linphone_address_unref(fromAddr); LinphonePrivate::Address addr(h->get_to()); if (addr.isValid()) { - LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, addr.asStringUriOnly().c_str()); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(addr)); if (cr) { L_GET_PRIVATE_FROM_C_OBJECT(cr, ServerGroupChatRoom)->confirmJoining(h); return; @@ -751,7 +751,9 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ if (addr.hasUriParam("method") && (addr.getUriParamValue("method") == "BYE")) { if (linphone_core_conference_server_enabled(lc)) { // Removal of a participant at the server side - LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, op->get_to()); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR( + lc->cppCore->findChatRoom(Address(op->get_to())) + ); if (cr) { Address fromAddr(op->get_from()); std::shared_ptr participant = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(fromAddr); @@ -767,7 +769,9 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ } } else { // The server asks a participant to leave a chat room - LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, addr.asStringUriOnly().c_str()); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR( + lc->cppCore->findChatRoom(addr) + ); if (cr) { L_GET_CPP_PTR_FROM_C_OBJECT(cr)->leave(); static_cast(op)->reply(SalReasonNone); diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index c30abf7dc..2e4bf0ec9 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -31,7 +31,7 @@ #include "chat/chat-room/server-group-chat-room-p.h" #include "conference/participant.h" #include "core/core-p.h" -#include "content/content.h" +#include "event-log/event-log.h" // ============================================================================= diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index 885a1c809..41df151db 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -45,14 +45,14 @@ F(ChatRoom, BasicChatRoom) \ F(ChatRoom, ClientGroupChatRoom) \ F(ChatRoom, RealTimeTextChatRoom) \ + F(ChatRoom, ServerGroupChatRoom) \ F(EventLog, ConferenceCallEvent) \ F(EventLog, ConferenceChatMessageEvent) \ F(EventLog, ConferenceEvent) \ F(EventLog, ConferenceNotifiedEvent) \ F(EventLog, ConferenceParticipantDeviceEvent) \ F(EventLog, ConferenceParticipantEvent) \ - F(EventLog, ConferenceSubjectEvent) \ - F(ChatRoom, ServerGroupChatRoom) + F(EventLog, ConferenceSubjectEvent) // ============================================================================= // Register belle-sip ID. diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index da3f19de8..8c83664bd 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -84,9 +84,14 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { Address entityAddress(confInfo->getEntity().c_str()); Address cleanedConfAddress2(cleanedConfAddress); cleanedConfAddress2.setDomain(entityAddress.getDomain()); - if (confInfo->getEntity() == cleanedConfAddress.asString() - || confInfo->getEntity() == cleanedConfAddress2.asString()) { - if (confInfo->getConferenceDescription().present() && confInfo->getConferenceDescription().get().getSubject().present()) + if ( + confInfo->getEntity() == cleanedConfAddress.asString() || + confInfo->getEntity() == cleanedConfAddress2.asString() + ) { + if ( + confInfo->getConferenceDescription().present() && + confInfo->getConferenceDescription().get().getSubject().present() + ) d->listener->onSubjectChanged(tm, confInfo->getConferenceDescription().get().getSubject().get()); if (confInfo->getVersion().present()) From 6aabd89f5a76b353f9c3d13c229a45c7c339e5a1 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 27 Oct 2017 14:34:29 +0200 Subject: [PATCH 0650/2215] fix(chat): fix partially previous merge --- coreapi/chat.c | 48 ++++--------------------------- coreapi/linphonecore.c | 27 ----------------- src/c-wrapper/api/c-chat-room.cpp | 3 +- 3 files changed, 6 insertions(+), 72 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 87f07bc2e..a62bdd03b 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -79,39 +79,6 @@ LinphoneChatRoom *linphone_core_create_client_group_chat_room (LinphoneCore *lc, return L_GET_C_BACK_PTR(lc->cppCore->createClientGroupChatRoom(L_C_TO_STRING(subject))); } -static LinphoneChatRoom *_linphone_core_get_or_create_chat_room(LinphoneCore *lc, const char *to) { - LinphoneAddress *to_addr = linphone_core_interpret_url(lc, to); - LinphoneChatRoom *ret; - - if (to_addr == NULL) { - ms_error("linphone_core_get_or_create_chat_room(): Cannot make a valid address with %s", to); - return NULL; - } - ret = _linphone_core_get_chat_room(lc, to_addr); - linphone_address_unref(to_addr); - if (!ret) { - ret = _linphone_core_create_chat_room_from_url(lc, to); - } - return ret; -} - -LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr) { - LinphoneChatRoom *ret = _linphone_core_get_chat_room(lc, addr); - if (!ret) { - ret = _linphone_core_create_chat_room(lc, addr); - } - return ret; -} - -LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, const char *subject) { - const char *factoryUri = linphone_core_get_conference_factory_uri(lc); - if (!factoryUri) - return nullptr; - LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, factoryUri, subject); - lc->chatrooms = bctbx_list_append(lc->chatrooms, cr); - return cr; -} - LinphoneChatRoom *_linphone_core_join_client_group_chat_room (LinphoneCore *lc, const LinphonePrivate::Address &addr) { LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); @@ -126,14 +93,8 @@ LinphoneChatRoom *_linphone_core_create_server_group_chat_room (LinphoneCore *lc return cr; } -void linphone_core_delete_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr) { - if (bctbx_list_find(lc->chatrooms, cr)) { - lc->chatrooms = bctbx_list_remove(lc->chatrooms, cr); - linphone_chat_room_delete_history(cr); - linphone_chat_room_unref(cr); - } else { - ms_error("linphone_core_delete_chat_room(): chatroom [%p] isn't part of LinphoneCore.", cr); - } +void linphone_core_delete_chat_room (LinphoneCore *, LinphoneChatRoom *cr) { + LinphonePrivate::Core::deleteChatRoom(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); } LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const char *to) { @@ -142,8 +103,9 @@ LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const c int linphone_core_message_received(LinphoneCore *lc, LinphonePrivate::SalOp *op, const SalMessage *sal_msg) { LinphoneReason reason = LinphoneReasonNotAcceptable; - LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, - linphone_core_conference_server_enabled(lc) ? op->get_to() : op->get_from()); + const char *peerAddress = linphone_core_conference_server_enabled(lc) ? op->get_to() : op->get_from(); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(LinphonePrivate::Address(peerAddress))); + if (cr) reason = L_GET_PRIVATE_FROM_C_OBJECT(cr)->messageReceived(op, sal_msg); else { diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1a8145e96..7fa996cd2 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -7198,33 +7198,6 @@ void _linphone_core_remove_group_chat_room(LinphoneCore *lc, LinphoneChatRoom *c bctbx_iterator_cchar_delete(it); } -LinphoneChatRoom *_linphone_core_find_group_chat_room(const LinphoneCore *lc, const char *id) { - LinphoneChatRoom *result = nullptr; - Address cleanedAddr(id); - cleanedAddr.clean(); - cleanedAddr.setPort(0); - bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, cleanedAddr.asStringUriOnly().c_str()); - bctbx_iterator_t *endit = bctbx_map_cchar_end(lc->group_chat_rooms); - if (!bctbx_iterator_cchar_equals(it, endit)) { - result = reinterpret_cast(bctbx_pair_cchar_get_second(bctbx_iterator_cchar_get_pair(it))); - } else { - bctbx_iterator_cchar_delete(it); - Address backupAddress(cleanedAddr); - Address factoryAddress(linphone_core_get_conference_factory_uri(lc)); - backupAddress.setDomain(factoryAddress.getDomain()); - lWarning() << "We don't found the chat room with address " << id << " as a temporary workaround, searching with " << backupAddress.asString(); - it = bctbx_map_cchar_find_key(lc->group_chat_rooms, backupAddress.asStringUriOnly().c_str()); - - if (!bctbx_iterator_cchar_equals(it, endit)) { - result = reinterpret_cast(bctbx_pair_cchar_get_second(bctbx_iterator_cchar_get_pair(it))); - } - if (!result) lWarning() << "Chatroom " << id << " or " << backupAddress.asString() << " not found!"; - } - bctbx_iterator_cchar_delete(endit); - bctbx_iterator_cchar_delete(it); - return result; -} - void linphone_core_enable_conference_server (LinphoneCore *lc, bool_t enable) { lp_config_set_int(linphone_core_get_config(lc), "misc", "conference_server_enabled", enable); } diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 2e4bf0ec9..10ef56188 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -20,10 +20,9 @@ // TODO: Remove me later. #include "linphone/chat.h" -#include "linphone/wrapper_utils.h" #include "linphone/api/c-chat-room.h" +#include "linphone/wrapper_utils.h" -#include "event-log/event-log.h" #include "c-wrapper/c-wrapper.h" #include "chat/chat-room/basic-chat-room.h" #include "chat/chat-room/client-group-chat-room.h" From 7106d92b84e6f0710870a00c2f911cbb9fd97bb9 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 27 Oct 2017 14:41:27 +0200 Subject: [PATCH 0651/2215] fix(ChatRoom): remove useless includes in ServerGroupChatRoomStub, fix conding style, ... --- .../chat-room/server-group-chat-room-stub.cpp | 80 +++++++------------ 1 file changed, 28 insertions(+), 52 deletions(-) diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index da4ef27a3..c5f994a48 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -1,5 +1,5 @@ /* - * server-group-chat-room.cpp + * server-group-chat-room-stub.cpp * Copyright (C) 2010-2017 Belledonne Communications SARL * * This program is free software; you can redistribute it and/or @@ -17,20 +17,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include - -#include "address/address-p.h" -#include "address/address.h" -#include "c-wrapper/c-wrapper.h" -#include "chat/chat-message/chat-message-p.h" -#include "chat/modifier/cpim-chat-message-modifier.h" -#include "conference/local-conference-event-handler.h" -#include "conference/local-conference-p.h" -#include "conference/participant-p.h" -#include "conference/session/call-session-p.h" -#include "content/content-type.h" -#include "logger/logger.h" -#include "sal/refer-op.h" #include "server-group-chat-room-p.h" // ============================================================================= @@ -43,17 +29,17 @@ ServerGroupChatRoomPrivate::ServerGroupChatRoomPrivate (LinphoneCore *core) : Ch // ----------------------------------------------------------------------------- -shared_ptr ServerGroupChatRoomPrivate::addParticipant (const Address &addr) { +shared_ptr ServerGroupChatRoomPrivate::addParticipant (const Address &) { return nullptr; } -void ServerGroupChatRoomPrivate::confirmCreation () { -} +void ServerGroupChatRoomPrivate::confirmCreation () {} -void ServerGroupChatRoomPrivate::confirmJoining (SalCallOp *op) { -} +void ServerGroupChatRoomPrivate::confirmJoining (SalCallOp *) {} -shared_ptr ServerGroupChatRoomPrivate::findRemovedParticipant (const shared_ptr &session) const { +shared_ptr ServerGroupChatRoomPrivate::findRemovedParticipant ( + const shared_ptr & +) const { return nullptr; } @@ -61,31 +47,25 @@ string ServerGroupChatRoomPrivate::generateConferenceId () const { return ""; } -void ServerGroupChatRoomPrivate::removeParticipant (const shared_ptr &participant) { -} +void ServerGroupChatRoomPrivate::removeParticipant (const shared_ptr &) {} -void ServerGroupChatRoomPrivate::subscribeReceived (LinphoneEvent *event) { -} +void ServerGroupChatRoomPrivate::subscribeReceived (LinphoneEvent *) {} -void ServerGroupChatRoomPrivate::update (SalCallOp *op) { -} +void ServerGroupChatRoomPrivate::update (SalCallOp *) {} // ----------------------------------------------------------------------------- -void ServerGroupChatRoomPrivate::dispatchMessage (const Address &fromAddr, const Content &content) { -} +void ServerGroupChatRoomPrivate::dispatchMessage (const Address &, const Content &) {} -void ServerGroupChatRoomPrivate::storeOrUpdateMessage (const std::shared_ptr &msg) { -} +void ServerGroupChatRoomPrivate::storeOrUpdateMessage (const shared_ptr &) {} -LinphoneReason ServerGroupChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *salMsg) { +LinphoneReason ServerGroupChatRoomPrivate::messageReceived (SalOp *, const SalMessage *) { return LinphoneReasonNone; } // ----------------------------------------------------------------------------- -void ServerGroupChatRoomPrivate::designateAdmin () { -} +void ServerGroupChatRoomPrivate::designateAdmin () {} bool ServerGroupChatRoomPrivate::isAdminLeft () const { return false; @@ -94,8 +74,7 @@ bool ServerGroupChatRoomPrivate::isAdminLeft () const { // ============================================================================= ServerGroupChatRoom::ServerGroupChatRoom (LinphoneCore *core, SalCallOp *op) - : ChatRoom(*new ServerGroupChatRoomPrivate(core)), LocalConference(core, Address(op->get_to()), nullptr) { -} + : ChatRoom(*new ServerGroupChatRoomPrivate(core)), LocalConference(core, Address(op->get_to()), nullptr) {} int ServerGroupChatRoom::getCapabilities () const { return 0; @@ -103,17 +82,15 @@ int ServerGroupChatRoom::getCapabilities () const { // ----------------------------------------------------------------------------- -void ServerGroupChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { -} +void ServerGroupChatRoom::addParticipant (const Address &, const CallSessionParams *, bool) {} -void ServerGroupChatRoom::addParticipants (const list
      &addresses, const CallSessionParams *params, bool hasMedia) { -} +void ServerGroupChatRoom::addParticipants (const list
      &, const CallSessionParams *, bool) {} bool ServerGroupChatRoom::canHandleParticipants () const { - return FALSE; + return false; } -shared_ptr ServerGroupChatRoom::findParticipant (const Address &addr) const { +shared_ptr ServerGroupChatRoom::findParticipant (const Address &) const { return nullptr; } @@ -137,21 +114,20 @@ void ServerGroupChatRoom::join () {} void ServerGroupChatRoom::leave () {} -void ServerGroupChatRoom::removeParticipant (const shared_ptr &participant) { -} +void ServerGroupChatRoom::removeParticipant (const shared_ptr &) {} -void ServerGroupChatRoom::removeParticipants (const list> &participants) { -} +void ServerGroupChatRoom::removeParticipants (const list> &) {} -void ServerGroupChatRoom::setParticipantAdminStatus (shared_ptr &participant, bool isAdmin) { -} +void ServerGroupChatRoom::setParticipantAdminStatus (shared_ptr &, bool) {} -void ServerGroupChatRoom::setSubject (const std::string &subject) { -} +void ServerGroupChatRoom::setSubject (const string &) {} // ----------------------------------------------------------------------------- -void ServerGroupChatRoom::onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) { -} +void ServerGroupChatRoom::onCallSessionStateChanged ( + const shared_ptr &, + LinphoneCallState, + const string & +) {} LINPHONE_END_NAMESPACE From b914ae974171e587f09bffe1fb53c35acb45cddf Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 27 Oct 2017 14:41:41 +0200 Subject: [PATCH 0652/2215] Do not add event from history if shared_ptr is null --- src/db/main-db.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 899ed49b1..38c935bd8 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1002,15 +1002,17 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { soci::transaction tr(*session); soci::rowset rows = (session->prepare << query, soci::use(peerAddress)); - for (const auto &row : rows) - events.push_back(d->selectGenericConferenceEvent( + for (const auto &row : rows) { + shared_ptr log = d->selectGenericConferenceEvent( // See: http://soci.sourceforge.net/doc/master/backends/ // `row id` is not supported by soci on Sqlite3. It's necessary to cast id to int... getBackend() == Sqlite3 ? static_cast(row.get(0)) : row.get(0), static_cast(row.get(1)), Utils::getTmAsTimeT(row.get(2)), peerAddress - )); + ); + if (log) events.push_back(log); + } L_END_LOG_EXCEPTION From d94a764999ae184dbbf48ba226f83cf7077bcd43 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 27 Oct 2017 14:58:22 +0200 Subject: [PATCH 0653/2215] feat(Core): add tmp workaround on findChatRoom --- src/core/core-chat-room.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index ac50b37fa..84ae4d63a 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -105,7 +105,18 @@ const list> &Core::getChatRooms () const { shared_ptr Core::findChatRoom (const Address &peerAddress) const { L_D(); - auto it = d->chatRoomsByUri.find(getCleanedPeerAddress(peerAddress).asStringUriOnly()); + + Address cleanedAddress = getCleanedPeerAddress(peerAddress); + auto it = d->chatRoomsByUri.find(cleanedAddress.asStringUriOnly()); + if (it != d->chatRoomsByUri.cend()) + return it->second; + + // TODO: Remove me, temp workaround. + cleanedAddress.setDomain(Address(linphone_core_get_conference_factory_uri(d->cCore)).getDomain()); + lWarning() << "We don't found the chat room with address " << peerAddress.asString() << + " as a temporary workaround, searching with " << cleanedAddress.asString(); + + it = d->chatRoomsByUri.find(cleanedAddress.asStringUriOnly()); return it == d->chatRoomsByUri.cend() ? shared_ptr() : it->second; } From 77639532bd5de75c44609b8286f64d98ce9f57eb Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 27 Oct 2017 15:02:52 +0200 Subject: [PATCH 0654/2215] fix(MainDb): log unfetched events --- src/db/main-db.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 38c935bd8..28194aa8f 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1003,15 +1003,19 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { soci::rowset rows = (session->prepare << query, soci::use(peerAddress)); for (const auto &row : rows) { - shared_ptr log = d->selectGenericConferenceEvent( - // See: http://soci.sourceforge.net/doc/master/backends/ - // `row id` is not supported by soci on Sqlite3. It's necessary to cast id to int... - getBackend() == Sqlite3 ? static_cast(row.get(0)) : row.get(0), + // See: http://soci.sourceforge.net/doc/master/backends/ + // `row id` is not supported by soci on Sqlite3. It's necessary to cast id to int... + long long eventId = getBackend() == Sqlite3 ? static_cast(row.get(0)) : row.get(0); + shared_ptr event = d->selectGenericConferenceEvent( + eventId, static_cast(row.get(1)), Utils::getTmAsTimeT(row.get(2)), peerAddress ); - if (log) events.push_back(log); + if (event) + events.push_back(event); + else + lWarning() << "Unable to fetch event: " << eventId; } L_END_LOG_EXCEPTION From 8523c03debd793a54b75a4a5d2fa4df9f05aa482 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 27 Oct 2017 15:24:20 +0200 Subject: [PATCH 0655/2215] fix(core): repair build --- coreapi/chat.c | 7 +++---- coreapi/linphonecore.c | 42 +++++------------------------------------- coreapi/private.h | 3 --- 3 files changed, 8 insertions(+), 44 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index a62bdd03b..ba45d60b2 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -41,7 +41,7 @@ #include "chat/chat-room/real-time-text-chat-room-p.h" #include "chat/chat-room/real-time-text-chat-room.h" #include "content/content-type.h" -#include "core/core.h" +#include "core/core-p.h" using namespace std; @@ -82,14 +82,13 @@ LinphoneChatRoom *linphone_core_create_client_group_chat_room (LinphoneCore *lc, LinphoneChatRoom *_linphone_core_join_client_group_chat_room (LinphoneCore *lc, const LinphonePrivate::Address &addr) { LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); - lc->chatrooms = bctbx_list_append(lc->chatrooms, cr); + L_GET_PRIVATE(lc->cppCore)->insertChatRoomWithDb(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); return cr; } LinphoneChatRoom *_linphone_core_create_server_group_chat_room (LinphoneCore *lc, LinphonePrivate::SalCallOp *op) { LinphoneChatRoom *cr = _linphone_server_group_chat_room_new(lc, op); - _linphone_core_add_group_chat_room(lc, L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getConferenceAddress(), cr); - lc->chatrooms = bctbx_list_append(lc->chatrooms, cr); + L_GET_PRIVATE(lc->cppCore)->insertChatRoomWithDb(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); return cr; } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 7fa996cd2..4b5611301 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2140,11 +2140,12 @@ static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEve } static void _linphone_core_conference_subscription_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state) { - if ((linphone_event_get_subscription_dir(lev) == LinphoneSubscriptionIncoming) && (state == LinphoneSubscriptionIncomingReceived)) { + if ( + linphone_event_get_subscription_dir(lev) == LinphoneSubscriptionIncoming && + state == LinphoneSubscriptionIncomingReceived + ) { const LinphoneAddress *resource = linphone_event_get_resource(lev); - char *resourceUri = linphone_address_as_string_uri_only(resource); - LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, resourceUri); - bctbx_free(resourceUri); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(*L_GET_CPP_PTR_FROM_C_OBJECT(resource))); if (cr) { linphone_event_accept_subscription(lev); L_GET_PRIVATE_FROM_C_OBJECT(cr, ServerGroupChatRoom)->subscribeReceived(lev); @@ -7165,39 +7166,6 @@ const char * linphone_core_get_conference_factory_uri(const LinphoneCore *lc) { return lp_config_get_string(linphone_core_get_config(lc), "misc", "conference_factory_uri", "sip:"); } -bool_t _linphone_core_has_group_chat_room(const LinphoneCore *lc, const char *id) { - bool_t result; - bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, id); - bctbx_iterator_t *endit = bctbx_map_cchar_end(lc->group_chat_rooms); - result = !bctbx_iterator_cchar_equals(it, endit); - bctbx_iterator_cchar_delete(endit); - bctbx_iterator_cchar_delete(it); - return result; -} - -void _linphone_core_add_group_chat_room(LinphoneCore *lc, const LinphonePrivate::Address &addr, LinphoneChatRoom *cr) { - Address cleanedAddr(addr); - cleanedAddr.clean(); - cleanedAddr.setPort(0); - bctbx_pair_t *pair = reinterpret_cast(bctbx_pair_cchar_new(cleanedAddr.asStringUriOnly().c_str(), linphone_chat_room_ref(cr))); - bctbx_map_cchar_insert_and_delete(lc->group_chat_rooms, pair); -} - -void _linphone_core_remove_group_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr) { - const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(cr); - Address cleanedAddr(*L_GET_CPP_PTR_FROM_C_OBJECT(confAddr)); - cleanedAddr.clean(); - cleanedAddr.setPort(0); - bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, cleanedAddr.asStringUriOnly().c_str()); - bctbx_iterator_t *endit = bctbx_map_cchar_end(lc->group_chat_rooms); - if (!bctbx_iterator_cchar_equals(it, endit)) { - bctbx_map_cchar_erase(lc->group_chat_rooms, it); - linphone_chat_room_unref(cr); - } - bctbx_iterator_cchar_delete(endit); - bctbx_iterator_cchar_delete(it); -} - void linphone_core_enable_conference_server (LinphoneCore *lc, bool_t enable) { lp_config_set_int(linphone_core_get_config(lc), "misc", "conference_server_enabled", enable); } diff --git a/coreapi/private.h b/coreapi/private.h index 7186c546d..b28e80d05 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -457,9 +457,6 @@ bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription extern LinphonePrivate::Sal::Callbacks linphone_sal_callbacks; LINPHONE_PUBLIC bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); LINPHONE_PUBLIC bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc); -bool_t _linphone_core_has_group_chat_room (const LinphoneCore *lc, const char *id); -void _linphone_core_add_group_chat_room (LinphoneCore *lc, const LinphonePrivate::Address &addr, LinphoneChatRoom *cr); -void _linphone_core_remove_group_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr); bool_t _linphone_core_is_conference_creation (const LinphoneCore *lc, const LinphoneAddress *addr); LinphoneChatRoom *_linphone_core_create_server_group_chat_room (LinphoneCore *lc, LinphonePrivate::SalCallOp *op); From 20f8fe59a4c77322a479b0d6c2d5258c04bbd4c0 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 27 Oct 2017 15:52:44 +0200 Subject: [PATCH 0656/2215] fix crash in soci in Android and iOS --- cmake/FindSoci.cmake | 4 ++++ src/db/abstract/abstract-db.cpp | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/cmake/FindSoci.cmake b/cmake/FindSoci.cmake index 91c4e376d..e930f93a9 100644 --- a/cmake/FindSoci.cmake +++ b/cmake/FindSoci.cmake @@ -61,6 +61,10 @@ IF(SOCI_INCLUDE_DIRS AND SOCI_LIBRARIES) IF(SOCI_${plugin}_PLUGIN) MESSAGE(STATUS " * Plugin ${plugin} found ${SOCI_${plugin}_PLUGIN}.") SET(SOCI_${plugin}_FOUND True) + + if(IOS OR ANDROID) + list(APPEND SOCI_LIBRARIES ${SOCI_${plugin}_PLUGIN}) + endif() ELSE() MESSAGE(STATUS " * Plugin ${plugin} not found.") SET(SOCI_${plugin}_FOUND False) diff --git a/src/db/abstract/abstract-db.cpp b/src/db/abstract/abstract-db.cpp index a3cb11e0a..4c101eb06 100644 --- a/src/db/abstract/abstract-db.cpp +++ b/src/db/abstract/abstract-db.cpp @@ -33,9 +33,14 @@ LINPHONE_BEGIN_NAMESPACE AbstractDb::AbstractDb (AbstractDbPrivate &p) : Object(p) {} +extern "C" void register_factory_sqlite3(); + bool AbstractDb::connect (Backend backend, const string ¶meters) { L_D(); - +#if defined(__APPLE__) || defined(__ANDROID__) + if (backend == Sqlite3) + register_factory_sqlite3(); +#endif // defined(__APPLE__) || defined(__ANDROID__)*/ d->backend = backend; d->dbSession = DbSessionProvider::getInstance()->getSession( (backend == Mysql ? "mysql://" : "sqlite3://") + parameters From a859c185b5345cc4e05a4e7c4c3367cea5241a72 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 27 Oct 2017 15:54:43 +0200 Subject: [PATCH 0657/2215] create data path and config path on ios if they do not exist --- src/core/paths/paths-apple.mm | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/core/paths/paths-apple.mm b/src/core/paths/paths-apple.mm index 55b35e59b..75ecebe91 100644 --- a/src/core/paths/paths-apple.mm +++ b/src/core/paths/paths-apple.mm @@ -20,6 +20,7 @@ #import "linphone/utils/utils.h" #import "core/platform-helpers/platform-helpers.h" +#import "logger/logger.h" #import "paths-apple.h" #import @@ -32,6 +33,17 @@ std::string SysPaths::getDataPath (PlatformHelpers *platformHelper) { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); NSString *writablePath = [paths objectAtIndex:0]; NSString *fullPath = [writablePath stringByAppendingString:@"/linphone/"]; + if(![[NSFileManager defaultManager] fileExistsAtPath:fullPath]) { + NSError *error; + lInfo() << "Data path " << fullPath.UTF8String << " does not exist, creating it."; + if (![[NSFileManager defaultManager] createDirectoryAtPath:fullPath + withIntermediateDirectories:YES + attributes:nil + error:&error]) { + lError() << "Create data path directory error: " << error.description; + } + } + const char *ret = fullPath.UTF8String; return ret; } @@ -40,6 +52,17 @@ std::string SysPaths::getConfigPath (PlatformHelpers *platformHelper) { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); NSString *configPath = [paths objectAtIndex:0]; NSString *fullPath = [configPath stringByAppendingString:@"/Preferences/linphone/"]; + if(![[NSFileManager defaultManager] fileExistsAtPath:fullPath]) { + NSError *error; + lInfo() << "Config path " << fullPath.UTF8String << " does not exist, creating it."; + if (![[NSFileManager defaultManager] createDirectoryAtPath:fullPath + withIntermediateDirectories:YES + attributes:nil + error:&error]) { + lError() << "Create config path directory error: " << error.description; + } + } + const char *ret = fullPath.UTF8String; return ret; } From 22986f184056cf74cfb8e657f9db7603e577ee1f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 27 Oct 2017 16:06:48 +0200 Subject: [PATCH 0658/2215] Do not load soci shared lib anymore --- wrappers/java/java_class.mustache | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index 8f0153c8d..ea8ffbd55 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -152,7 +152,6 @@ class {{classImplName}} {{#isLinphoneFactory}}extends{{/isLinphoneFactory}}{{#is static { System.loadLibrary("gnustl_shared"); loadOptionalLibrary("ffmpeg-linphone"); - System.loadLibrary("soci_core"); System.loadLibrary("bctoolbox"); System.loadLibrary("ortp"); System.loadLibrary("mediastreamer_base"); @@ -215,4 +214,4 @@ class {{classImplName}} {{#isLinphoneFactory}}extends{{/isLinphoneFactory}}{{#is public Object getUserData() { return userData; } -} \ No newline at end of file +} From f276a82f4625c25cb8243fcbf77cd86defa741e5 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 27 Oct 2017 16:42:59 +0200 Subject: [PATCH 0659/2215] Fixed crash in deleteChatRoom --- src/core/core-chat-room.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 84ae4d63a..42104a2a5 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -75,12 +75,13 @@ void CorePrivate::insertChatRoom (const shared_ptr &chatRoom) { void CorePrivate::deleteChatRoom (const string &peerAddress) { auto it = chatRoomsByUri.find(peerAddress); - if (it != chatRoomsByUri.end()) - chatRooms.erase( - find_if(chatRooms.begin(), chatRooms.end(), [&peerAddress](const shared_ptr &chatRoom) { - return peerAddress == chatRoom->getPeerAddress().asStringUriOnly(); - }) - ); + if (it != chatRoomsByUri.end()) { + auto it = find_if(chatRooms.begin(), chatRooms.end(), [&peerAddress](const shared_ptr &chatRoom) { + return peerAddress == chatRoom->getPeerAddress().asStringUriOnly(); + }); + if (it == chatRooms.end()) return; + chatRooms.erase(it); + } } void CorePrivate::insertChatRoomWithDb (const shared_ptr &chatRoom) { From f337228785a1bba275c70d7919da42b7ed924fe1 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 30 Oct 2017 09:25:48 +0100 Subject: [PATCH 0660/2215] fix(Core): fix log text --- src/core/core-chat-room.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 42104a2a5..b39c8703b 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -114,7 +114,7 @@ shared_ptr Core::findChatRoom (const Address &peerAddress) const { // TODO: Remove me, temp workaround. cleanedAddress.setDomain(Address(linphone_core_get_conference_factory_uri(d->cCore)).getDomain()); - lWarning() << "We don't found the chat room with address " << peerAddress.asString() << + lWarning() << "We don't find the chat room with address " << peerAddress.asString() << " as a temporary workaround, searching with " << cleanedAddress.asString(); it = d->chatRoomsByUri.find(cleanedAddress.asStringUriOnly()); From 43947bee19cc38ef36701a12152b3b81cb063c71 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 30 Oct 2017 09:35:49 +0100 Subject: [PATCH 0661/2215] fix(Core): more robust deleteChatRoom impl --- src/core/core-chat-room.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index b39c8703b..fd3b50175 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -79,8 +79,28 @@ void CorePrivate::deleteChatRoom (const string &peerAddress) { auto it = find_if(chatRooms.begin(), chatRooms.end(), [&peerAddress](const shared_ptr &chatRoom) { return peerAddress == chatRoom->getPeerAddress().asStringUriOnly(); }); - if (it == chatRooms.end()) return; - chatRooms.erase(it); + if (it != chatRooms.end()) { + chatRooms.erase(it); + return; + } + + // TODO: Remove me, temp workaround. + string workaroundAddress; + { + Address address(peerAddress); + address.setDomain(Address(linphone_core_get_conference_factory_uri(cCore)).getDomain()); + workaroundAddress = address.asStringUriOnly(); + } + + lWarning() << "We don't find the chat room with address " << peerAddress << + " as a temporary workaround, searching with " << workaroundAddress; + it = find_if(chatRooms.begin(), chatRooms.end(), [&workaroundAddress](const shared_ptr &chatRoom) { + return workaroundAddress == chatRoom->getPeerAddress().asStringUriOnly(); + }); + if (it != chatRooms.end()) + chatRooms.erase(it); + else + lError() << "Unable to remove chat room: " << peerAddress; } } From c927f68ad093a6e4b1006534d97f093f322a6979 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 30 Oct 2017 10:30:01 +0100 Subject: [PATCH 0662/2215] feat(MainDb): add logs --- src/db/main-db.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 28194aa8f..e1bd72e3e 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -128,6 +128,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { if (session->got_data()) return id; + lInfo() << "Insert new sip address in database: `" << sipAddress << "`."; *session << "INSERT INTO sip_address (value) VALUES (:sipAddress)", soci::use(sipAddress); return q->getLastInsertId(); } @@ -158,6 +159,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { if (session->got_data()) return id; + lInfo() << "Insert new content type in database: `" << contentType << "`."; *session << "INSERT INTO content_type (value) VALUES (:contentType)", soci::use(contentType); return q->getLastInsertId(); } @@ -168,10 +170,12 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { long long id; *session << "SELECT peer_sip_address_id FROM chat_room WHERE peer_sip_address_id = :sipAddressId", soci::use(sipAddressId), soci::into(id); - if (!session->got_data()) + if (!session->got_data()) { + lInfo() << "Insert new chat room in database: `" << sipAddressId << "` (capabilities=" << capabilities << ")."; *session << "INSERT INTO chat_room (peer_sip_address_id, creation_date, last_update_date, capabilities, subject) VALUES" " (:sipAddressId, :creationDate, :lastUpdateDate, :capabilities, '')", soci::use(sipAddressId), soci::use(date), soci::use(date), soci::use(capabilities); + } else *session << "UPDATE chat_room SET last_update_date = :lastUpdateDate WHERE peer_sip_address_id = :sipAddressId", soci::use(date), soci::use(sipAddressId); @@ -187,10 +191,12 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { soci::use(static_cast(isAdmin)), soci::use(chatRoomId), soci::use(sipAddressId) ); statement.execute(true); - if (statement.get_affected_rows() == 0) + if (statement.get_affected_rows() == 0) { + lInfo() << "Insert new chat room participant in database: `" << sipAddressId << "` (isAdmin=" << isAdmin << ")."; *session << "INSERT INTO chat_room_participant (chat_room_id, sip_address_id, is_admin)" " VALUES (:chatRoomId, :sipAddressId, :isAdmin)", soci::use(chatRoomId), soci::use(sipAddressId), soci::use(static_cast(isAdmin)); + } } void MainDbPrivate::insertChatMessageParticipant (long long eventId, long long sipAddressId, int state) { From f702e9a8fe0d487ef7cd529287d010ae55512a06 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 30 Oct 2017 11:50:50 +0100 Subject: [PATCH 0663/2215] Added new callback for message received on chat room with chat event log --- include/linphone/api/c-callbacks.h | 7 +++++++ include/linphone/api/c-chat-room-cbs.h | 14 ++++++++++++++ src/c-wrapper/api/c-chat-room-cbs.cpp | 9 +++++++++ src/chat/chat-room/basic-chat-room.cpp | 4 ++++ src/chat/chat-room/basic-chat-room.h | 1 + src/chat/chat-room/chat-room.cpp | 14 ++++++++++++++ src/chat/chat-room/chat-room.h | 1 + src/chat/chat-room/client-group-chat-room.cpp | 4 ++++ src/chat/chat-room/client-group-chat-room.h | 3 +++ src/chat/chat-room/real-time-text-chat-room.cpp | 2 ++ src/chat/chat-room/real-time-text-chat-room.h | 1 + src/chat/chat-room/server-group-chat-room-stub.cpp | 2 ++ src/chat/chat-room/server-group-chat-room.h | 1 + 13 files changed, 63 insertions(+) diff --git a/include/linphone/api/c-callbacks.h b/include/linphone/api/c-callbacks.h index b45d705df..a88a6ed3f 100644 --- a/include/linphone/api/c-callbacks.h +++ b/include/linphone/api/c-callbacks.h @@ -156,6 +156,13 @@ typedef void (*LinphoneChatRoomCbsIsComposingReceivedCb) (LinphoneChatRoom *cr, */ typedef void (*LinphoneChatRoomCbsMessageReceivedCb) (LinphoneChatRoom *cr, LinphoneChatMessage *msg); +/** + * Callback used to notify a chat room that a chat message has been received. + * @param[in] cr #LinphoneChatRoom object + * @param[in] event_log The #LinphoneChatMessage event log that has been received + */ +typedef void (*LinphoneChatRoomCbsChatMessageReceivedCb) (LinphoneChatRoom *cr, const LinphoneEventLog *event_log); + /** * Callback used to notify a chat room that a participant has been added. * @param[in] cr #LinphoneChatRoom object diff --git a/include/linphone/api/c-chat-room-cbs.h b/include/linphone/api/c-chat-room-cbs.h index 08331232e..746d25444 100644 --- a/include/linphone/api/c-chat-room-cbs.h +++ b/include/linphone/api/c-chat-room-cbs.h @@ -89,6 +89,20 @@ LINPHONE_PUBLIC LinphoneChatRoomCbsMessageReceivedCb linphone_chat_room_cbs_get_ */ LINPHONE_PUBLIC void linphone_chat_room_cbs_set_message_received (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsMessageReceivedCb cb); +/** + * Get the chat message received callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @return The current chat message received callback. + */ +LINPHONE_PUBLIC LinphoneChatRoomCbsChatMessageReceivedCb linphone_chat_room_cbs_get_chat_message_received (const LinphoneChatRoomCbs *cbs); + +/** + * Set the chat message received callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @param[in] cb The chat message received callback to be used. + */ +LINPHONE_PUBLIC void linphone_chat_room_cbs_set_chat_message_received (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsChatMessageReceivedCb cb); + /** * Get the participant added callback. * @param[in] cbs LinphoneChatRoomCbs object. diff --git a/src/c-wrapper/api/c-chat-room-cbs.cpp b/src/c-wrapper/api/c-chat-room-cbs.cpp index d25707a78..e6e38114a 100644 --- a/src/c-wrapper/api/c-chat-room-cbs.cpp +++ b/src/c-wrapper/api/c-chat-room-cbs.cpp @@ -36,6 +36,7 @@ struct _LinphoneChatRoomCbs { LinphoneChatRoomCbsStateChangedCb stateChangedCb; LinphoneChatRoomCbsSubjectChangedCb subjectChangedCb; LinphoneChatRoomCbsUndecryptableMessageReceivedCb undecryptableMessageReceivedCb; + LinphoneChatRoomCbsChatMessageReceivedCb chatMessageReceivedCb; }; BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneChatRoomCbs); @@ -88,6 +89,14 @@ void linphone_chat_room_cbs_set_message_received (LinphoneChatRoomCbs *cbs, Linp cbs->messageReceivedCb = cb; } +LinphoneChatRoomCbsChatMessageReceivedCb linphone_chat_room_cbs_get_chat_message_received (const LinphoneChatRoomCbs *cbs) { + return cbs->chatMessageReceivedCb; +} + +void linphone_chat_room_cbs_set_chat_message_received (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsChatMessageReceivedCb cb) { + cbs->chatMessageReceivedCb = cb; +} + LinphoneChatRoomCbsParticipantAddedCb linphone_chat_room_cbs_get_participant_added (const LinphoneChatRoomCbs *cbs) { return cbs->participantAddedCb; } diff --git a/src/chat/chat-room/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp index 93d3ba079..c07afa0af 100644 --- a/src/chat/chat-room/basic-chat-room.cpp +++ b/src/chat/chat-room/basic-chat-room.cpp @@ -40,6 +40,10 @@ BasicChatRoom::BasicChatRoom (LinphoneCore *core, const Address &peerAddress) : // ----------------------------------------------------------------------------- +void BasicChatRoom::onChatMessageReceived (const shared_ptr &msg) { + +} + int BasicChatRoom::getCapabilities () const { return static_cast(Capabilities::Basic); } diff --git a/src/chat/chat-room/basic-chat-room.h b/src/chat/chat-room/basic-chat-room.h index b1bf7523b..56906844b 100644 --- a/src/chat/chat-room/basic-chat-room.h +++ b/src/chat/chat-room/basic-chat-room.h @@ -35,6 +35,7 @@ public: CapabilitiesMask getCapabilities () const override; + void onChatMessageReceived (const std::shared_ptr &msg) override; /* ConferenceInterface. */ void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
      &addresses, const CallSessionParams *params, bool hasMedia) override; diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 238e2fcb2..d604bf8e0 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -20,6 +20,7 @@ #include #include "c-wrapper/c-wrapper.h" +#include "event-log/conference/conference-chat-message-event.h" #include "chat/chat-message/chat-message-p.h" #include "chat/chat-room/chat-room-p.h" #include "chat/notification/imdn.h" @@ -435,8 +436,21 @@ end: // ----------------------------------------------------------------------------- void ChatRoomPrivate::chatMessageReceived (const shared_ptr &msg) { + L_Q(); + if ((msg->getPrivate()->getContentType() != ContentType::Imdn) && (msg->getPrivate()->getContentType() != ContentType::ImIsComposing)) { + q->onChatMessageReceived(msg); + + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); + LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); + LinphoneChatRoomCbsParticipantAddedCb cb = linphone_chat_room_cbs_get_chat_message_received(cbs); + shared_ptr event = make_shared(msg->getTime(), msg); + if (cb) { + cb(cr, L_GET_C_BACK_PTR(event)); + } + // Legacy notifyChatMessageReceived(msg); + remoteIsComposing.erase(msg->getFromAddress().asStringUriOnly()); isComposingHandler.stopRemoteRefreshTimer(msg->getFromAddress().asStringUriOnly()); notifyIsComposingReceived(msg->getFromAddress(), false); diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index cabe8f6e4..fc883fb6b 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -69,6 +69,7 @@ public: State getState () const; protected: + virtual void onChatMessageReceived (const std::shared_ptr &msg) = 0; explicit ChatRoom (ChatRoomPrivate &p); private: diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 1e89cf723..45a412023 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -245,6 +245,10 @@ void ClientGroupChatRoom::setSubject (const string &subject) { // ----------------------------------------------------------------------------- +void ClientGroupChatRoom::onChatMessageReceived (const shared_ptr &msg) { + +} + void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { L_D(); L_D_T(RemoteConference, dConference); diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 5575b6b70..c5d9396b1 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -52,6 +52,9 @@ public: void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) override; void setSubject (const std::string &subject) override; +private: + void onChatMessageReceived (const std::shared_ptr &msg) override; + private: /* ConferenceListener */ void onConferenceCreated (const Address &addr) override; diff --git a/src/chat/chat-room/real-time-text-chat-room.cpp b/src/chat/chat-room/real-time-text-chat-room.cpp index 388a0d313..ae302c82f 100644 --- a/src/chat/chat-room/real-time-text-chat-room.cpp +++ b/src/chat/chat-room/real-time-text-chat-room.cpp @@ -135,6 +135,8 @@ LinphoneCall *RealTimeTextChatRoom::getCall () const { // ----------------------------------------------------------------------------- +void RealTimeTextChatRoom::onChatMessageReceived(const shared_ptr &msg) {} + void RealTimeTextChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { lError() << "addParticipant() is not allowed on a RealTimeTextChatRoom"; } diff --git a/src/chat/chat-room/real-time-text-chat-room.h b/src/chat/chat-room/real-time-text-chat-room.h index 430fcfafe..d480700e9 100644 --- a/src/chat/chat-room/real-time-text-chat-room.h +++ b/src/chat/chat-room/real-time-text-chat-room.h @@ -38,6 +38,7 @@ public: uint32_t getChar () const; LinphoneCall *getCall () const; + void onChatMessageReceived (const std::shared_ptr &msg) override; /* ConferenceInterface */ void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
      &addresses, const CallSessionParams *params, bool hasMedia) override; diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index c5f994a48..d392490a6 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -82,6 +82,8 @@ int ServerGroupChatRoom::getCapabilities () const { // ----------------------------------------------------------------------------- +void ServerGroupChatRoom::onChatMessageReceived(const shared_ptr &msg) {} + void ServerGroupChatRoom::addParticipant (const Address &, const CallSessionParams *, bool) {} void ServerGroupChatRoom::addParticipants (const list
      &, const CallSessionParams *, bool) {} diff --git a/src/chat/chat-room/server-group-chat-room.h b/src/chat/chat-room/server-group-chat-room.h index efe5f79f0..828e7917a 100644 --- a/src/chat/chat-room/server-group-chat-room.h +++ b/src/chat/chat-room/server-group-chat-room.h @@ -59,6 +59,7 @@ public: void setSubject (const std::string &subject) override; private: + void onChatMessageReceived (const std::shared_ptr &msg) override; /* CallSessionListener */ void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) override; From edf85afab948d37854664f1eb95d35a09fdbe479 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 30 Oct 2017 11:56:24 +0100 Subject: [PATCH 0664/2215] fix(Core): use better workaround for bad conference sip addresses returned by flexisip --- src/chat/chat-room/chat-room.cpp | 2 - src/chat/chat-room/chat-room.h | 1 - src/core/core-chat-room.cpp | 72 +++++++++++++++++--------------- src/core/core-p.h | 3 +- 4 files changed, 40 insertions(+), 38 deletions(-) diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index d604bf8e0..0386a1016 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -537,8 +537,6 @@ void ChatRoomPrivate::onIsComposingRefreshNeeded () { // ============================================================================= -ChatRoom::ChatRoom (LinphoneCore *core) : Object(*new ChatRoomPrivate(core)) {} - ChatRoom::ChatRoom (ChatRoomPrivate &p) : Object(p) {} // ----------------------------------------------------------------------------- diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index fc883fb6b..b0e29e3ef 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -43,7 +43,6 @@ public: typedef int CapabilitiesMask; - ChatRoom (LinphoneCore *core); virtual ~ChatRoom () = default; virtual CapabilitiesMask getCapabilities () const = 0; diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index fd3b50175..5cbe89f40 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -45,6 +45,16 @@ static inline Address getCleanedPeerAddress (const Address &peerAddress) { return cleanedAddress; } +// TODO: Remove me later. +static inline string resolveWorkaroundClientGroupChatRoomAddress ( + const CorePrivate &corePrivate, + const Address &peerAddress +) { + Address workaroundAddress = peerAddress; + workaroundAddress.setDomain(Address(linphone_core_get_conference_factory_uri(corePrivate.cCore)).getDomain()); + return workaroundAddress.asStringUriOnly(); +} + // ----------------------------------------------------------------------------- shared_ptr CorePrivate::createChatRoom (const Address &peerAddress, bool isRtt) { @@ -66,7 +76,12 @@ void CorePrivate::insertChatRoom (const shared_ptr &chatRoom) { L_ASSERT(chatRoom); L_ASSERT(chatRoom->getState() == ChatRoom::State::Created); - string peerAddress = getCleanedPeerAddress(chatRoom->getPeerAddress()).asStringUriOnly(); + Address cleanedPeerAddress = getCleanedPeerAddress(chatRoom->getPeerAddress()); + + const string peerAddress = chatRoom->getCapabilities() & static_cast(ChatRoom::Capabilities::Conference) + ? resolveWorkaroundClientGroupChatRoomAddress(*this, cleanedPeerAddress) + : cleanedPeerAddress.asStringUriOnly(); + deleteChatRoom(peerAddress); chatRooms.push_back(chatRoom); @@ -84,31 +99,19 @@ void CorePrivate::deleteChatRoom (const string &peerAddress) { return; } - // TODO: Remove me, temp workaround. - string workaroundAddress; - { - Address address(peerAddress); - address.setDomain(Address(linphone_core_get_conference_factory_uri(cCore)).getDomain()); - workaroundAddress = address.asStringUriOnly(); - } - - lWarning() << "We don't find the chat room with address " << peerAddress << - " as a temporary workaround, searching with " << workaroundAddress; - it = find_if(chatRooms.begin(), chatRooms.end(), [&workaroundAddress](const shared_ptr &chatRoom) { - return workaroundAddress == chatRoom->getPeerAddress().asStringUriOnly(); - }); - if (it != chatRooms.end()) - chatRooms.erase(it); - else - lError() << "Unable to remove chat room: " << peerAddress; + lError() << "Unable to remove chat room: " << peerAddress; } } void CorePrivate::insertChatRoomWithDb (const shared_ptr &chatRoom) { insertChatRoom(chatRoom); + + ChatRoom::CapabilitiesMask capabilities = chatRoom->getCapabilities(); mainDb->insertChatRoom( - getCleanedPeerAddress(chatRoom->getPeerAddress()).asStringUriOnly(), - chatRoom->getCapabilities() + capabilities & static_cast(ChatRoom::Capabilities::Conference) + ? resolveWorkaroundClientGroupChatRoomAddress(*this, chatRoom->getPeerAddress()) + : chatRoom->getPeerAddress().asStringUriOnly(), + capabilities ); } @@ -132,24 +135,23 @@ shared_ptr Core::findChatRoom (const Address &peerAddress) const { if (it != d->chatRoomsByUri.cend()) return it->second; - // TODO: Remove me, temp workaround. - cleanedAddress.setDomain(Address(linphone_core_get_conference_factory_uri(d->cCore)).getDomain()); - lWarning() << "We don't find the chat room with address " << peerAddress.asString() << - " as a temporary workaround, searching with " << cleanedAddress.asString(); + lInfo() << "Unable to find chat room: `" << peerAddress.asStringUriOnly() << "`."; - it = d->chatRoomsByUri.find(cleanedAddress.asStringUriOnly()); + // TODO: Remove me, temp workaround. + const string workaroundAddress = resolveWorkaroundClientGroupChatRoomAddress(*d, cleanedAddress); + lWarning() << "Workaround: searching chat room with: `" << workaroundAddress << "`."; + it = d->chatRoomsByUri.find(workaroundAddress); return it == d->chatRoomsByUri.cend() ? shared_ptr() : it->second; } shared_ptr Core::createClientGroupChatRoom (const string &subject) { L_D(); - - const char *factoryUri = linphone_core_get_conference_factory_uri(d->cCore); - if (!factoryUri) - return nullptr; - return L_GET_CPP_PTR_FROM_C_OBJECT( - _linphone_client_group_chat_room_new(d->cCore, factoryUri, L_STRING_TO_C(subject)) + _linphone_client_group_chat_room_new( + d->cCore, + linphone_core_get_conference_factory_uri(d->cCore), + L_STRING_TO_C(subject) + ) ); } @@ -187,8 +189,12 @@ shared_ptr Core::getOrCreateBasicChatRoom (const string &peerAddress, void Core::deleteChatRoom (const shared_ptr &chatRoom) { CorePrivate *d = chatRoom->getCore()->cppCore->getPrivate(); - string peerAddress = getCleanedPeerAddress(chatRoom->getPeerAddress()).asStringUriOnly(); - d->deleteChatRoomWithDb(peerAddress); + const Address cleanedPeerAddress = getCleanedPeerAddress(chatRoom->getPeerAddress()); + d->deleteChatRoomWithDb( + chatRoom->getCapabilities() & static_cast(ChatRoom::Capabilities::Conference) + ? resolveWorkaroundClientGroupChatRoomAddress(*d, cleanedPeerAddress) + : cleanedPeerAddress.asStringUriOnly() + ); } LINPHONE_END_NAMESPACE diff --git a/src/core/core-p.h b/src/core/core-p.h index 36c70a3a7..227c0bea3 100644 --- a/src/core/core-p.h +++ b/src/core/core-p.h @@ -34,13 +34,12 @@ public: LinphoneCore *cCore = nullptr; void insertChatRoomWithDb (const std::shared_ptr &chatRoom); - void deleteChatRoomWithDb (const std::string &peerAddress); - std::shared_ptr createChatRoom (const Address &peerAddress, bool isRtt); private: void insertChatRoom (const std::shared_ptr &chatRoom); void deleteChatRoom (const std::string &peerAddress); + void deleteChatRoomWithDb (const std::string &peerAddress); std::list> chatRooms; std::unordered_map> chatRoomsByUri; From 637595573d79e14f1fcfcbc1a5d3e5e928d6664d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 30 Oct 2017 14:45:57 +0100 Subject: [PATCH 0665/2215] Added callback on message being sent --- include/linphone/api/c-callbacks.h | 7 +++++++ include/linphone/api/c-chat-room-cbs.h | 14 ++++++++++++++ src/c-wrapper/api/c-chat-room-cbs.cpp | 9 +++++++++ src/chat/chat-room/chat-room.cpp | 10 ++++++++++ 4 files changed, 40 insertions(+) diff --git a/include/linphone/api/c-callbacks.h b/include/linphone/api/c-callbacks.h index a88a6ed3f..f31219d14 100644 --- a/include/linphone/api/c-callbacks.h +++ b/include/linphone/api/c-callbacks.h @@ -163,6 +163,13 @@ typedef void (*LinphoneChatRoomCbsMessageReceivedCb) (LinphoneChatRoom *cr, Linp */ typedef void (*LinphoneChatRoomCbsChatMessageReceivedCb) (LinphoneChatRoom *cr, const LinphoneEventLog *event_log); +/** + * Callback used to notify a chat room that a chat message is being sent. + * @param[in] cr #LinphoneChatRoom object + * @param[in] event_log The #LinphoneChatMessage event log that is being sent + */ +typedef void (*LinphoneChatRoomCbsChatMessageSentCb) (LinphoneChatRoom *cr, const LinphoneEventLog *event_log); + /** * Callback used to notify a chat room that a participant has been added. * @param[in] cr #LinphoneChatRoom object diff --git a/include/linphone/api/c-chat-room-cbs.h b/include/linphone/api/c-chat-room-cbs.h index 746d25444..ae515cc9d 100644 --- a/include/linphone/api/c-chat-room-cbs.h +++ b/include/linphone/api/c-chat-room-cbs.h @@ -103,6 +103,20 @@ LINPHONE_PUBLIC LinphoneChatRoomCbsChatMessageReceivedCb linphone_chat_room_cbs_ */ LINPHONE_PUBLIC void linphone_chat_room_cbs_set_chat_message_received (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsChatMessageReceivedCb cb); +/** + * Get the chat message sent callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @return The current chat message sent callback. + */ +LINPHONE_PUBLIC LinphoneChatRoomCbsChatMessageSentCb linphone_chat_room_cbs_get_chat_message_sent (const LinphoneChatRoomCbs *cbs); + +/** + * Set the chat message sent callback. + * @param[in] cbs LinphoneChatRoomCbs object. + * @param[in] cb The chat message sent callback to be used. + */ +LINPHONE_PUBLIC void linphone_chat_room_cbs_set_chat_message_sent (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsChatMessageSentCb cb); + /** * Get the participant added callback. * @param[in] cbs LinphoneChatRoomCbs object. diff --git a/src/c-wrapper/api/c-chat-room-cbs.cpp b/src/c-wrapper/api/c-chat-room-cbs.cpp index e6e38114a..9bcb058d7 100644 --- a/src/c-wrapper/api/c-chat-room-cbs.cpp +++ b/src/c-wrapper/api/c-chat-room-cbs.cpp @@ -37,6 +37,7 @@ struct _LinphoneChatRoomCbs { LinphoneChatRoomCbsSubjectChangedCb subjectChangedCb; LinphoneChatRoomCbsUndecryptableMessageReceivedCb undecryptableMessageReceivedCb; LinphoneChatRoomCbsChatMessageReceivedCb chatMessageReceivedCb; + LinphoneChatRoomCbsChatMessageSentCb chatMessageSentCb; }; BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneChatRoomCbs); @@ -97,6 +98,14 @@ void linphone_chat_room_cbs_set_chat_message_received (LinphoneChatRoomCbs *cbs, cbs->chatMessageReceivedCb = cb; } +LinphoneChatRoomCbsChatMessageSentCb linphone_chat_room_cbs_get_chat_message_sent (const LinphoneChatRoomCbs *cbs) { + return cbs->chatMessageSentCb; +} + +void linphone_chat_room_cbs_set_chat_message_sent (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsChatMessageSentCb cb) { + cbs->chatMessageSentCb = cb; +} + LinphoneChatRoomCbsParticipantAddedCb linphone_chat_room_cbs_get_participant_added (const LinphoneChatRoomCbs *cbs) { return cbs->participantAddedCb; } diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 0386a1016..4553bff2f 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -347,6 +347,8 @@ void ChatRoomPrivate::storeOrUpdateMessage (const shared_ptr &msg) } void ChatRoomPrivate::sendMessage (const shared_ptr &msg) { + L_Q(); + msg->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); /* Add to transient list */ @@ -355,6 +357,14 @@ void ChatRoomPrivate::sendMessage (const shared_ptr &msg) { msg->getPrivate()->setTime(ms_time(0)); msg->getPrivate()->send(); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); + LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); + LinphoneChatRoomCbsParticipantAddedCb cb = linphone_chat_room_cbs_get_chat_message_sent(cbs); + shared_ptr event = make_shared(msg->getTime(), msg); + if (cb) { + cb(cr, L_GET_C_BACK_PTR(event)); + } + storeOrUpdateMessage(msg); if (isComposing) From 3b4e32cb8e7d15add5f8c04fdbd043ecf557ba1d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 30 Oct 2017 15:17:26 +0100 Subject: [PATCH 0666/2215] Fixed sent message getText() and getContentType() values --- src/chat/chat-message/chat-message.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 6253922f5..1c0eeef27 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -1201,11 +1201,11 @@ void ChatMessagePrivate::send() { } //TODO Remove : This won't be necessary once we store the contentsList - if (!getText().empty() && getText() == clearTextMessage) { + if (!getText().empty() && getText() != clearTextMessage) { /* We replace the encrypted message by the original one so it can be correctly stored and displayed by the application */ setText(clearTextMessage); } - if (getContentType().isValid() && (getContentType() == clearTextContentType)) { + if (getContentType().isValid() && (getContentType() != clearTextContentType)) { /* We replace the encrypted content type by the original one */ setContentType(clearTextContentType); } From 087aeaf0d02984a4d21e3d3767bb034adedb9065 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 31 Oct 2017 09:31:22 +0100 Subject: [PATCH 0667/2215] confernce is already created when the refer is received --- coreapi/callbacks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index faf7813d8..7930e3029 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -799,8 +799,8 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ } else { LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); + L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Created); L_GET_PRIVATE(lc->cppCore)->insertChatRoomWithDb(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); - static_cast(op)->reply(SalReasonNone); return; } From 94c08dce7f21f9ce03361282cad8ca12b1258d1a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 31 Oct 2017 10:01:08 +0100 Subject: [PATCH 0668/2215] Use CPIM by default --- src/chat/chat-message/chat-message.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 1c0eeef27..eb33fdc22 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -1170,7 +1170,7 @@ void ChatMessagePrivate::send() { if ((currentSendStep & ChatMessagePrivate::Step::Cpim) == ChatMessagePrivate::Step::Cpim) { lInfo() << "Cpim step already done, skipping"; } else { - if (lp_config_get_int(chatRoom->getCore()->config, "sip", "use_cpim", 0) == 1) { + if (lp_config_get_int(chatRoom->getCore()->config, "sip", "use_cpim", 1) == 1) { CpimChatMessageModifier ccmm; ccmm.encode(q->getSharedFromThis(), errorCode); } From 53c83d3585fdca5cc00940adb0f21f9e83bf53e6 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 31 Oct 2017 17:34:13 +0100 Subject: [PATCH 0669/2215] Fixed ChatRoom state changed with Created state before RAM insertion breaking find --- coreapi/callbacks.c | 1 + coreapi/chat.c | 2 ++ src/chat/chat-room/client-group-chat-room.cpp | 1 + src/core/core-chat-room.cpp | 4 ++-- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 7930e3029..9897bea60 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -799,6 +799,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ } else { LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); + L_GET_PRIVATE(lc->cppCore)->insertChatRoom(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Created); L_GET_PRIVATE(lc->cppCore)->insertChatRoomWithDb(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); static_cast(op)->reply(SalReasonNone); diff --git a/coreapi/chat.c b/coreapi/chat.c index ba45d60b2..352c01cd8 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -82,12 +82,14 @@ LinphoneChatRoom *linphone_core_create_client_group_chat_room (LinphoneCore *lc, LinphoneChatRoom *_linphone_core_join_client_group_chat_room (LinphoneCore *lc, const LinphonePrivate::Address &addr) { LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); + L_GET_PRIVATE(lc->cppCore)->insertChatRoom(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); L_GET_PRIVATE(lc->cppCore)->insertChatRoomWithDb(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); return cr; } LinphoneChatRoom *_linphone_core_create_server_group_chat_room (LinphoneCore *lc, LinphonePrivate::SalCallOp *op) { LinphoneChatRoom *cr = _linphone_server_group_chat_room_new(lc, op); + L_GET_PRIVATE(lc->cppCore)->insertChatRoom(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); L_GET_PRIVATE(lc->cppCore)->insertChatRoomWithDb(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); return cr; } diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 45a412023..e47f34fba 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -254,6 +254,7 @@ void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { L_D_T(RemoteConference, dConference); dConference->conferenceAddress = addr; d->peerAddress = addr; + d->core->cppCore->getPrivate()->insertChatRoom(getSharedFromThis()); d->setState(ChatRoom::State::Created); d->core->cppCore->getPrivate()->insertChatRoomWithDb(getSharedFromThis()); } diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 5cbe89f40..3e8e668c9 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -66,6 +66,7 @@ shared_ptr CorePrivate::createChatRoom (const Address &peerAddress, bo chatRoom = ObjectFactory::create(cCore, peerAddress); ChatRoomPrivate *dChatRoom = chatRoom->getPrivate(); + insertChatRoom(chatRoom); dChatRoom->setState(ChatRoom::State::Instantiated); dChatRoom->setState(ChatRoom::State::Created); @@ -74,7 +75,6 @@ shared_ptr CorePrivate::createChatRoom (const Address &peerAddress, bo void CorePrivate::insertChatRoom (const shared_ptr &chatRoom) { L_ASSERT(chatRoom); - L_ASSERT(chatRoom->getState() == ChatRoom::State::Created); Address cleanedPeerAddress = getCleanedPeerAddress(chatRoom->getPeerAddress()); @@ -104,7 +104,7 @@ void CorePrivate::deleteChatRoom (const string &peerAddress) { } void CorePrivate::insertChatRoomWithDb (const shared_ptr &chatRoom) { - insertChatRoom(chatRoom); + L_ASSERT(chatRoom->getState() == ChatRoom::State::Created); ChatRoom::CapabilitiesMask capabilities = chatRoom->getCapabilities(); mainDb->insertChatRoom( From 2a64f69f359745c72dff28f9778eefa712f60cbd Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 31 Oct 2017 17:35:43 +0100 Subject: [PATCH 0670/2215] Moved insertChatRoom to public part of private core --- src/core/core-p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/core-p.h b/src/core/core-p.h index 227c0bea3..6b894ce86 100644 --- a/src/core/core-p.h +++ b/src/core/core-p.h @@ -33,11 +33,11 @@ public: std::unique_ptr mainDb; LinphoneCore *cCore = nullptr; + void insertChatRoom (const std::shared_ptr &chatRoom); void insertChatRoomWithDb (const std::shared_ptr &chatRoom); std::shared_ptr createChatRoom (const Address &peerAddress, bool isRtt); private: - void insertChatRoom (const std::shared_ptr &chatRoom); void deleteChatRoom (const std::string &peerAddress); void deleteChatRoomWithDb (const std::string &peerAddress); From 8e05e6a21f0770e4e00fbf316568645bebaf41c0 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 31 Oct 2017 18:20:27 +0100 Subject: [PATCH 0671/2215] Fixed a crash with group chat rooms created when receiving a REFER, see comment for details and check it doesn't impact server --- coreapi/callbacks.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 9897bea60..1ec25c68a 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -799,9 +799,12 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ } else { LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); - L_GET_PRIVATE(lc->cppCore)->insertChatRoom(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); + /* The following causes a crash because chat room hasn't yet a peer address. + The above call to join() will create a CallSession which will call onConferenceCreated when it'll reach the Connected state. + onConferenceCreated will then call the following commented lines, no need for them here. */ + /*L_GET_PRIVATE(lc->cppCore)->insertChatRoom(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Created); - L_GET_PRIVATE(lc->cppCore)->insertChatRoomWithDb(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); + L_GET_PRIVATE(lc->cppCore)->insertChatRoomWithDb(L_GET_CPP_PTR_FROM_C_OBJECT(cr));*/ static_cast(op)->reply(SalReasonNone); return; } From 223bd817a9f829d2f2029d45aa4eb206ed980abb Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 2 Nov 2017 11:57:31 +0100 Subject: [PATCH 0672/2215] feat(core): break completely old message storage api impl --- coreapi/CMakeLists.txt | 1 - coreapi/linphonecore.c | 104 ++- coreapi/message_storage.c | 626 --------------- coreapi/private.h | 10 - coreapi/tester_utils.cpp | 4 - coreapi/tester_utils.h | 1 - src/CMakeLists.txt | 2 + src/c-wrapper/api/c-chat-room.cpp | 17 +- src/chat/chat-message/chat-message-p.h | 17 +- src/chat/chat-message/chat-message.cpp | 745 +++++++++++------- src/chat/chat-message/chat-message.h | 4 +- src/chat/chat-room/basic-chat-room-p.h | 3 +- src/chat/chat-room/basic-chat-room.cpp | 10 +- src/chat/chat-room/basic-chat-room.h | 3 +- src/chat/chat-room/chat-room-p.h | 16 +- src/chat/chat-room/chat-room.cpp | 330 ++------ src/chat/chat-room/chat-room.h | 11 +- src/chat/chat-room/client-group-chat-room-p.h | 3 +- src/chat/chat-room/client-group-chat-room.cpp | 31 +- src/chat/chat-room/client-group-chat-room.h | 11 +- .../chat-room/real-time-text-chat-room-p.h | 4 +- .../chat-room/real-time-text-chat-room.cpp | 31 +- src/chat/chat-room/real-time-text-chat-room.h | 6 +- src/chat/chat-room/server-group-chat-room-p.h | 3 +- .../chat-room/server-group-chat-room-stub.cpp | 9 +- src/chat/chat-room/server-group-chat-room.h | 4 +- .../encryption-chat-message-modifier.cpp | 5 +- .../multipart-chat-message-modifier.cpp | 3 +- src/chat/notification/imdn.cpp | 9 +- src/core/core-accessor.cpp | 58 ++ src/core/core-accessor.h | 52 ++ src/core/core-chat-room.cpp | 8 +- src/core/core.cpp | 5 + src/core/core.h | 8 + src/db/main-db.cpp | 89 ++- src/db/main-db.h | 35 +- src/db/session/db-session-provider.cpp | 42 +- src/db/session/db-session-provider.h | 1 - tester/CMakeLists.txt | 2 +- tester/cpim-tester.cpp | 6 +- tester/main-db-tester.cpp | 8 +- tester/message_tester.c | 157 ---- tester/multipart-tester.cpp | 10 +- tester/tester.c | 2 +- 44 files changed, 984 insertions(+), 1522 deletions(-) delete mode 100644 coreapi/message_storage.c create mode 100644 src/core/core-accessor.cpp create mode 100644 src/core/core-accessor.h diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 4a783cdda..3b05f7ca9 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -87,7 +87,6 @@ set(LINPHONE_SOURCE_FILES_C lpc2xml.c lpconfig.c lsd.c - message_storage.c misc.c nat_policy.c offeranswer.c diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 4b5611301..fadfd6224 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -6106,9 +6106,6 @@ static void linphone_core_uninit(LinphoneCore *lc) if(lc->rec_file!=NULL){ ms_free(lc->rec_file); } - if (lc->chat_db_file){ - ms_free(lc->chat_db_file); - } if (lc->logs_db_file) { ms_free(lc->logs_db_file); } @@ -6127,7 +6124,6 @@ static void linphone_core_uninit(LinphoneCore *lc) linphone_core_free_payload_types(lc); if (lc->supported_formats) ms_free((void *)lc->supported_formats); - linphone_core_message_storage_close(lc); linphone_core_call_log_storage_close(lc); linphone_core_friends_storage_close(lc); linphone_core_zrtp_cache_close(lc); @@ -6508,6 +6504,90 @@ void linphone_core_remove_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook } +// ============================================================================= +// TODO: Remove me later, code found in message_storage.c. +// ============================================================================= + +#ifdef SQLITE_STORAGE_ENABLED + +#ifndef _WIN32 + #if !defined(__QNXNTO__) && !defined(__ANDROID__) + #include + #include + #include + #include + #include + #endif +#else + #include +#endif + +#define MAX_DB_PATH_SIZE 1024 + +static char *utf8_convert(const char *filename){ + char db_file_utf8[MAX_DB_PATH_SIZE] = ""; +#if defined(_WIN32) + wchar_t db_file_utf16[MAX_DB_PATH_SIZE]={0}; + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, filename, -1, db_file_utf16, MAX_DB_PATH_SIZE); + WideCharToMultiByte(CP_UTF8, 0, db_file_utf16, -1, db_file_utf8, sizeof(db_file_utf8), NULL, NULL); +#elif defined(__QNXNTO__) || defined(__ANDROID__) + strncpy(db_file_utf8, filename, MAX_DB_PATH_SIZE - 1); +#else + char db_file_locale[MAX_DB_PATH_SIZE] = {'\0'}; + char *inbuf=db_file_locale, *outbuf=db_file_utf8; + size_t inbyteleft = MAX_DB_PATH_SIZE, outbyteleft = MAX_DB_PATH_SIZE; + iconv_t cb; + + if (strcasecmp("UTF-8", nl_langinfo(CODESET)) == 0) { + strncpy(db_file_utf8, filename, MAX_DB_PATH_SIZE - 1); + } else { + strncpy(db_file_locale, filename, MAX_DB_PATH_SIZE-1); + cb = iconv_open("UTF-8", nl_langinfo(CODESET)); + if (cb != (iconv_t)-1) { + int ret; + ret = static_cast(iconv(cb, &inbuf, &inbyteleft, &outbuf, &outbyteleft)); + if(ret == -1) db_file_utf8[0] = '\0'; + iconv_close(cb); + } + } +#endif + return ms_strdup(db_file_utf8); +} + +int _linphone_sqlite3_open(const char *db_file, sqlite3 **db) { + char* errmsg = NULL; + int ret; + int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; + +#if TARGET_OS_IPHONE + /* the secured filesystem of the iPHone doesn't allow writing while the app is in background mode, which is problematic. + * We workaround by asking that the open is made with no protection*/ + flags |= SQLITE_OPEN_FILEPROTECTION_NONE; +#endif + + /*since we plug our vfs into sqlite, we convert to UTF-8. + * On Windows, the filename has to be converted back to windows native charset.*/ + char *utf8_filename = utf8_convert(db_file); + ret = sqlite3_open_v2(utf8_filename, db, flags, LINPHONE_SQLITE3_VFS); + ms_free(utf8_filename); + + if (ret != SQLITE_OK) return ret; + // Some platforms do not provide a way to create temporary files which are needed + // for transactions... so we work in memory only + // see http ://www.sqlite.org/compile.html#temp_store + ret = sqlite3_exec(*db, "PRAGMA temp_store=MEMORY", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + ms_error("Cannot set sqlite3 temporary store to memory: %s.", errmsg); + sqlite3_free(errmsg); + } + + return ret; +} + +#endif + +// ============================================================================= + void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file){ LinphoneProxyConfig *proxy = linphone_core_get_default_proxy_config(lc); if (lc->zrtp_secrets_cache != NULL) { @@ -6821,19 +6901,13 @@ int linphone_core_get_video_dscp(const LinphoneCore *lc){ return lp_config_get_int(lc->config,"rtp","video_dscp",0); } -void linphone_core_set_chat_database_path(LinphoneCore *lc, const char *path){ - if (lc->chat_db_file){ - ms_free(lc->chat_db_file); - lc->chat_db_file=NULL; - } - if (path) { - lc->chat_db_file=ms_strdup(path); - linphone_core_message_storage_init(lc); - } +void linphone_core_set_chat_database_path (LinphoneCore *, const char *) { + lError() << "Do not use `linphone_core_set_chat_database_path`. Not necessary."; } -const char* linphone_core_get_chat_database_path(const LinphoneCore *lc) { - return lc->chat_db_file; +const char *linphone_core_get_chat_database_path (const LinphoneCore *) { + lError() << "Do not use `linphone_core_get_chat_database_path`. Not necessary."; + return ""; } void linphone_core_enable_sdp_200_ack(LinphoneCore *lc, bool_t enable) { diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c deleted file mode 100644 index 803ab530b..000000000 --- a/coreapi/message_storage.c +++ /dev/null @@ -1,626 +0,0 @@ -/* -message_storage.c -Copyright (C) 2012 Belledonne Communications, Grenoble, France - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "private.h" -#include "linphone/core.h" - -#ifdef SQLITE_STORAGE_ENABLED - -#include "chat/chat-room/chat-room.h" - -#ifndef _WIN32 -#if !defined(__QNXNTO__) && !defined(__ANDROID__) -#include -#include -#include -#include -#include -#endif -#else -#include -#endif - -#define MAX_PATH_SIZE 1024 - -#include "sqlite3.h" -#include - - -static char *utf8_convert(const char *filename){ - char db_file_utf8[MAX_PATH_SIZE] = ""; -#if defined(_WIN32) - wchar_t db_file_utf16[MAX_PATH_SIZE]={0}; - MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, filename, -1, db_file_utf16, MAX_PATH_SIZE); - WideCharToMultiByte(CP_UTF8, 0, db_file_utf16, -1, db_file_utf8, sizeof(db_file_utf8), NULL, NULL); -#elif defined(__QNXNTO__) || defined(__ANDROID__) - strncpy(db_file_utf8, filename, MAX_PATH_SIZE - 1); -#else - char db_file_locale[MAX_PATH_SIZE] = {'\0'}; - char *inbuf=db_file_locale, *outbuf=db_file_utf8; - size_t inbyteleft = MAX_PATH_SIZE, outbyteleft = MAX_PATH_SIZE; - iconv_t cb; - - if (strcasecmp("UTF-8", nl_langinfo(CODESET)) == 0) { - strncpy(db_file_utf8, filename, MAX_PATH_SIZE - 1); - } else { - strncpy(db_file_locale, filename, MAX_PATH_SIZE-1); - cb = iconv_open("UTF-8", nl_langinfo(CODESET)); - if (cb != (iconv_t)-1) { - int ret; - ret = (int)iconv(cb, &inbuf, &inbyteleft, &outbuf, &outbyteleft); - if(ret == -1) db_file_utf8[0] = '\0'; - iconv_close(cb); - } - } -#endif - return ms_strdup(db_file_utf8); -} - - -int _linphone_sqlite3_open(const char *db_file, sqlite3 **db) { - char* errmsg = NULL; - int ret; - int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; - -#if TARGET_OS_IPHONE - /* the secured filesystem of the iPHone doesn't allow writing while the app is in background mode, which is problematic. - * We workaround by asking that the open is made with no protection*/ - flags |= SQLITE_OPEN_FILEPROTECTION_NONE; -#endif - - /*since we plug our vfs into sqlite, we convert to UTF-8. - * On Windows, the filename has to be converted back to windows native charset.*/ - char *utf8_filename = utf8_convert(db_file); - ret = sqlite3_open_v2(utf8_filename, db, flags, LINPHONE_SQLITE3_VFS); - ms_free(utf8_filename); - - if (ret != SQLITE_OK) return ret; - // Some platforms do not provide a way to create temporary files which are needed - // for transactions... so we work in memory only - // see http ://www.sqlite.org/compile.html#temp_store - ret = sqlite3_exec(*db, "PRAGMA temp_store=MEMORY", NULL, NULL, &errmsg); - if (ret != SQLITE_OK) { - ms_error("Cannot set sqlite3 temporary store to memory: %s.", errmsg); - sqlite3_free(errmsg); - } - - /* the lines below have been disabled because they are likely an - * outdated hack */ -#if 0 && TARGET_OS_IPHONE - ret = sqlite3_exec(*db, "PRAGMA journal_mode = OFF", NULL, NULL, &errmsg); - if (ret != SQLITE_OK) { - ms_error("Cannot set sqlite3 journal_mode to off: %s.", errmsg); - sqlite3_free(errmsg); - } -#endif - return ret; -} -#endif - - - -#ifdef SQLITE_STORAGE_ENABLED - -/* DB layout: - * | 0 | storage_id - * | 1 | type - * | 2 | subtype - * | 3 | name - * | 4 | encoding - * | 5 | size - * | 6 | data (currently not stored) - * | 7 | key size - * | 8 | key - */ -// Callback for sql request when getting linphone content -static int callback_content(void *data, int argc, char **argv, char **colName) { - LinphoneChatMessage *message = (LinphoneChatMessage *)data; - - LinphoneContent *content = linphone_content_new(); - if (argv[1]) linphone_content_set_type(content, argv[1]); - if (argv[2]) linphone_content_set_subtype(content, argv[2]); - if (argv[3]) linphone_content_set_name(content, argv[3]); - if (argv[4]) linphone_content_set_encoding(content, argv[4]); - linphone_content_set_size(content, (size_t)atoi(argv[5])); - if (argv[8]) linphone_content_set_key(content, argv[8], (size_t)atol(argv[7])); - linphone_chat_message_set_file_transfer_information(message, content); - - return 0; -} - -void linphone_chat_message_fetch_content_from_database(sqlite3 *db, LinphoneChatMessage *message, int content_id) { - char* errmsg = NULL; - int ret; - char * buf; - - buf = sqlite3_mprintf("SELECT * FROM content WHERE id = %i", content_id); - ret = sqlite3_exec(db, buf, callback_content, message, &errmsg); - if (ret != SQLITE_OK) { - ms_error("Error in creation: %s.", errmsg); - sqlite3_free(errmsg); - } - sqlite3_free(buf); -} - -// Called when fetching all conversations from database -static int callback_all(void *data, int argc, char **argv, char **colName){ - LinphoneCore* lc = (LinphoneCore*) data; - char* address = argv[0]; - LinphoneAddress *addr = linphone_address_new(address); - if (addr){ - linphone_core_get_chat_room(lc, addr); - linphone_address_unref(addr); - } - return 0; -} - -int linphone_sql_request(sqlite3* db,const char *stmt){ - char* errmsg=NULL; - int ret; - ret=sqlite3_exec(db,stmt,NULL,NULL,&errmsg); - if(ret != SQLITE_OK) { - ms_error("linphone_sql_request: statement %s -> error sqlite3_exec(): %s.", stmt, errmsg); - sqlite3_free(errmsg); - } - return ret; -} - -// Process the request to fetch all chat contacts -void linphone_sql_request_all(sqlite3* db,const char *stmt, LinphoneCore* lc){ - char* errmsg=NULL; - int ret; - ret=sqlite3_exec(db,stmt,callback_all,lc,&errmsg); - if(ret != SQLITE_OK) { - ms_error("linphone_sql_request_all: error sqlite3_exec(): %s.", errmsg); - sqlite3_free(errmsg); - } -} - -static int linphone_chat_message_store_content(LinphoneChatMessage *msg) { - LinphoneCore *lc = linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)); - int id = -1; - if (lc->db) { - LinphoneContent *content = linphone_chat_message_get_file_transfer_information(msg); - char *buf = sqlite3_mprintf("INSERT INTO content VALUES(NULL,%Q,%Q,%Q,%Q,%i,%Q,%lld,%Q);", - linphone_content_get_type(content), - linphone_content_get_subtype(content), - linphone_content_get_name(content), - linphone_content_get_encoding(content), - linphone_content_get_size(content), - NULL, - (int64_t)linphone_content_get_key_size(content), - linphone_content_get_key(content) - ); - linphone_sql_request(lc->db, buf); - sqlite3_free(buf); - id = (int) sqlite3_last_insert_rowid (lc->db); - } - return id; -} - -unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){ - LinphoneCore *lc=linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)); - unsigned int id = 0; - - if (lc->db){ - int content_id = -1; - char *peer; - char *local_contact; - char *buf; - if (linphone_chat_message_get_file_transfer_information(msg)) { - content_id = linphone_chat_message_store_content(msg); - } - - peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(linphone_chat_message_get_chat_room(msg))); - local_contact=linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg)); - buf = sqlite3_mprintf("INSERT INTO history VALUES(NULL,%Q,%Q,%i,%Q,%Q,%i,%i,%Q,%lld,%Q,%i,%Q,%Q,%i);", - local_contact, - peer, - linphone_chat_message_get_direction(msg), - linphone_chat_message_get_text(msg), - "-1", /* use UTC field now */ - FALSE, /* use state == LinphoneChatMessageStateDisplayed now */ - linphone_chat_message_get_state(msg), - linphone_chat_message_get_external_body_url(msg), - (int64_t)linphone_chat_message_get_time(msg), - linphone_chat_message_get_appdata(msg), - content_id, - linphone_chat_message_get_message_id(msg), - linphone_chat_message_get_content_type(msg), - (int)linphone_chat_message_is_secured(msg) - ); - linphone_sql_request(lc->db,buf); - sqlite3_free(buf); - ms_free(local_contact); - ms_free(peer); - id = (unsigned int) sqlite3_last_insert_rowid (lc->db); - } - linphone_chat_message_set_storage_id(msg, id); - return id; -} - -void linphone_chat_message_store_update(LinphoneChatMessage *msg) { - LinphoneCore *lc = linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)); - - if (lc->db) { - char *peer; - char *local_contact; - char *buf; - - peer = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(linphone_chat_message_get_chat_room(msg))); - local_contact = linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg)); - buf = sqlite3_mprintf("UPDATE history SET" - " localContact = %Q," - " remoteContact = %Q," - " message = %Q," - " status = %i," - " appdata = %Q," - " messageId = %Q," - " content_type = %Q" - " WHERE (id = %u);", - local_contact, - peer, - linphone_chat_message_get_text(msg), - linphone_chat_message_get_state(msg), - linphone_chat_message_get_appdata(msg), - linphone_chat_message_get_message_id(msg), - linphone_chat_message_get_content_type(msg), - linphone_chat_message_get_storage_id(msg) - ); - linphone_sql_request(lc->db, buf); - sqlite3_free(buf); - ms_free(local_contact); - ms_free(peer); - } -} - -void linphone_chat_message_store_state(LinphoneChatMessage *msg){ - LinphoneCore *lc=linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)); - if (lc->db){ - char *buf=sqlite3_mprintf("UPDATE history SET status=%i WHERE (id = %u);", - linphone_chat_message_get_state(msg), linphone_chat_message_get_storage_id(msg)); - linphone_sql_request(lc->db,buf); - sqlite3_free(buf); - } -} - -void linphone_chat_message_store_appdata(LinphoneChatMessage* msg){ - LinphoneCore *lc=linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)); - if (lc->db){ - char *buf=sqlite3_mprintf("UPDATE history SET appdata=%Q WHERE id=%u;", - linphone_chat_message_get_appdata(msg), linphone_chat_message_get_storage_id(msg)); - linphone_sql_request(lc->db,buf); - sqlite3_free(buf); - } -} - -static void linphone_create_history_table(sqlite3* db){ - char* errmsg=NULL; - int ret; - ret=sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS history (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "localContact TEXT NOT NULL," - "remoteContact TEXT NOT NULL," - "direction INTEGER," - "message TEXT," - "time TEXT NOT NULL," - "read INTEGER," - "status INTEGER" - ");", - 0,0,&errmsg); - if(ret != SQLITE_OK) { - ms_error("Error in creation: %s.\n", errmsg); - sqlite3_free(errmsg); - } -} - - -static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; -static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; -static time_t parse_time_from_db( const char* time ){ - /* messages used to be stored in the DB by using string-based time */ - struct tm ret={0}; - char tmp1[80]={0}; - char tmp2[80]={0}; - int i,j; - time_t parsed = 0; - - if( sscanf(time,"%3c %3c%d%d:%d:%d %d",tmp1,tmp2,&ret.tm_mday, - &ret.tm_hour,&ret.tm_min,&ret.tm_sec,&ret.tm_year) == 7 ){ - ret.tm_year-=1900; - for(i=0;i<7;i++) { - if(strcmp(tmp1,days[i])==0) ret.tm_wday=i; - } - for(j=0;j<12;j++) { - if(strcmp(tmp2,months[j])==0) ret.tm_mon=j; - } - ret.tm_isdst=-1; - parsed = mktime(&ret); - } - return parsed; -} - - -static int migrate_messages_timestamp(void* data,int argc, char** argv, char** column_names) { - time_t new_time = parse_time_from_db(argv[1]); - if( new_time ){ - /* replace 'time' by -1 and set 'utc' to the timestamp */ - char *buf = sqlite3_mprintf("UPDATE history SET utc=%lld,time='-1' WHERE id=%i;", (int64_t)new_time, atoi(argv[0])); - if( buf) { - linphone_sql_request((sqlite3*)data, buf); - sqlite3_free(buf); - } - } else { - ms_warning("Cannot parse time %s from id %s", argv[1], argv[0]); - } - return 0; -} - -static void linphone_migrate_timestamps(sqlite3* db){ - int ret; - char* errmsg = NULL; - uint64_t begin=ortp_get_cur_time_ms(); - - linphone_sql_request(db,"BEGIN TRANSACTION"); - - ret = sqlite3_exec(db,"SELECT id,time,direction FROM history WHERE time != '-1';", migrate_messages_timestamp, db, &errmsg); - if( ret != SQLITE_OK ){ - ms_warning("Error migrating outgoing messages: %s.\n", errmsg); - sqlite3_free(errmsg); - linphone_sql_request(db, "ROLLBACK"); - } else { - uint64_t end; - linphone_sql_request(db, "COMMIT"); - end=ortp_get_cur_time_ms(); - ms_message("Migrated message timestamps to UTC in %lu ms",(unsigned long)(end-begin)); - } -} - -static void linphone_update_history_table(sqlite3* db) { - char* errmsg=NULL; - char *buf; - int ret; - - // for image url storage - ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN url TEXT;",NULL,NULL,&errmsg); - if(ret != SQLITE_OK) { - ms_message("Table already up to date: %s.", errmsg); - sqlite3_free(errmsg); - } else { - ms_debug("Table history updated successfully for URL."); - } - - // for UTC timestamp storage - ret = sqlite3_exec(db, "ALTER TABLE history ADD COLUMN utc INTEGER;", NULL,NULL,&errmsg); - if( ret != SQLITE_OK ){ - ms_message("Table already up to date: %s.", errmsg); - sqlite3_free(errmsg); - } else { - ms_debug("Table history updated successfully for UTC."); - // migrate from old text-based timestamps to unix time-based timestamps - linphone_migrate_timestamps(db); - } - - // new field for app-specific storage - ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN appdata TEXT;",NULL,NULL,&errmsg); - if(ret != SQLITE_OK) { - ms_message("Table already up to date: %s.", errmsg); - sqlite3_free(errmsg); - } else { - ms_debug("Table history updated successfully for app-specific data."); - } - - // new field for linphone content storage - ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN content INTEGER;",NULL,NULL,&errmsg); - if(ret != SQLITE_OK) { - ms_message("Table already up to date: %s.", errmsg); - sqlite3_free(errmsg); - } else { - ms_debug("Table history updated successfully for content data."); - ret = sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS content (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "type TEXT," - "subtype TEXT," - "name TEXT," - "encoding TEXT," - "size INTEGER," - "data BLOB" - ");", - 0,0,&errmsg); - if(ret != SQLITE_OK) { - ms_error("Error in creation: %s.\n", errmsg); - sqlite3_free(errmsg); - } else { - ms_debug("Table content successfully created."); - } - } - - // new fields for content key storage when using lime - ret=sqlite3_exec(db,"ALTER TABLE content ADD COLUMN key_size INTEGER;",NULL,NULL,&errmsg); - if(ret != SQLITE_OK) { - ms_message("Table already up to date: %s.", errmsg); - sqlite3_free(errmsg); - } else { - ret=sqlite3_exec(db,"ALTER TABLE content ADD COLUMN key TEXT;",NULL,NULL,&errmsg); - if(ret != SQLITE_OK) { - ms_message("Table already up to date: %s.", errmsg); - sqlite3_free(errmsg); - } else { - ms_debug("Table history content successfully for lime key storage data."); - } - } - - // new field for message_id - ret = sqlite3_exec(db, "ALTER TABLE history ADD COLUMN messageId TEXT;", NULL, NULL, &errmsg); - if (ret != SQLITE_OK) { - ms_message("Table already up to date: %s", errmsg); - sqlite3_free(errmsg); - } else { - ms_message("Table history updated successfully for messageId data."); - } - - // Convert is_read to LinphoneChatMessageStateDisplayed - buf = sqlite3_mprintf("UPDATE history SET status=%i WHERE read=1 AND direction=%i;", LinphoneChatMessageStateDisplayed, LinphoneChatMessageIncoming); - linphone_sql_request(db, buf); - sqlite3_free(buf); - - /* New field for content type */ - ret = sqlite3_exec(db, "ALTER TABLE history ADD COLUMN content_type TEXT;", NULL, NULL, &errmsg); - if (ret != SQLITE_OK) { - ms_message("Table already up to date: %s", errmsg); - sqlite3_free(errmsg); - } else { - ms_message("Table history updated successfully for content_type data."); - } - - // new field for secured flag - ret = sqlite3_exec(db, "ALTER TABLE history ADD COLUMN is_secured INTEGER DEFAULT 0;", NULL, NULL, &errmsg); - if (ret != SQLITE_OK) { - ms_message("Table already up to date: %s", errmsg); - sqlite3_free(errmsg); - } else { - ms_message("Table history updated successfully for is_secured data."); - } -} - -static void linphone_fix_outgoing_messages_state(sqlite3* db) { - /* Convert Idle and InProgress states of outgoing messages to NotDelivered */ - char *buf = sqlite3_mprintf("UPDATE history SET status=%i WHERE direction=%i AND (status=%i OR status=%i);", - LinphoneChatMessageStateNotDelivered, LinphoneChatMessageOutgoing, LinphoneChatMessageStateIdle, LinphoneChatMessageStateInProgress); - linphone_sql_request(db, buf); - sqlite3_free(buf); -} - -void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { - char *buf; - - if (lc->db==NULL) return; - buf=sqlite3_mprintf("SELECT remoteContact FROM history GROUP BY remoteContact;"); - linphone_sql_request_all(lc->db,buf,lc); - sqlite3_free(buf); -} - -static void _linphone_message_storage_profile(void*data,const char*statement, sqlite3_uint64 duration){ - ms_warning("SQL statement '%s' took %llu microseconds", statement, (unsigned long long)(duration / 1000LL) ); -} - -static void linphone_message_storage_activate_debug(sqlite3* db, bool_t debug){ - if( debug ){ - sqlite3_profile(db, _linphone_message_storage_profile, NULL ); - } else { - sqlite3_profile(db, NULL, NULL ); - } -} - -void linphone_core_message_storage_set_debug(LinphoneCore *lc, bool_t debug){ - - lc->debug_storage = debug; - - if( lc->db ){ - linphone_message_storage_activate_debug(lc->db, debug); - } -} - -void linphone_core_message_storage_init(LinphoneCore *lc){ - int ret; - const char *errmsg; - sqlite3 *db = NULL; - - linphone_core_message_storage_close(lc); - - ret=_linphone_sqlite3_open(lc->chat_db_file,&db); - if(ret != SQLITE_OK) { - errmsg=sqlite3_errmsg(db); - ms_error("Error in the opening: %s.\n", errmsg); - sqlite3_close(db); - return; - } - - linphone_message_storage_activate_debug(db, lc->debug_storage); - - linphone_create_history_table(db); - linphone_update_history_table(db); - linphone_fix_outgoing_messages_state(db); - lc->db=db; - - // Create a chatroom for each contact in the chat history - linphone_message_storage_init_chat_rooms(lc); -} - -void linphone_core_message_storage_close(LinphoneCore *lc){ - if (lc->db){ - sqlite3_close(lc->db); - lc->db=NULL; - } -} - -#else - -unsigned int linphone_chat_message_store(LinphoneChatMessage *cr){ - return 0; -} - -void linphone_chat_message_store_state(LinphoneChatMessage *cr){ -} - -void linphone_chat_message_store_appdata(LinphoneChatMessage *msg){ -} - -void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){ -} - -bctbx_list_t *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ - return NULL; -} - -bctbx_list_t *linphone_chat_room_get_history_range(LinphoneChatRoom *cr, int begin, int end){ - return NULL; -} - -LinphoneChatMessage * linphone_chat_room_find_message(LinphoneChatRoom *cr, const char *message_id) { - return NULL; -} - -void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { -} - -void linphone_chat_room_delete_history(LinphoneChatRoom *cr){ -} - -void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { -} - -void linphone_core_message_storage_init(LinphoneCore *lc){ -} - -void linphone_core_message_storage_close(LinphoneCore *lc){ -} - -int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){ - return 0; -} - -int linphone_chat_room_get_history_size(LinphoneChatRoom *cr){ - return 0; -} - -void linphone_chat_message_store_update(LinphoneChatMessage *msg){ -} - -#endif diff --git a/coreapi/private.h b/coreapi/private.h index b28e80d05..630e1cdc3 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -906,12 +906,10 @@ struct _LinphoneCore int max_calls; LinphoneTunnel *tunnel; char* device_id; - char *chat_db_file; char *logs_db_file; char *friends_db_file; #ifdef SQLITE_STORAGE_ENABLED sqlite3 *zrtp_cache_db; /**< zrtp sqlite cache, used by both zrtp and lime */ - sqlite3 *db; sqlite3 *logs_db; sqlite3 *friends_db; bool_t debug_storage; @@ -1092,15 +1090,7 @@ void linphone_upnp_destroy(LinphoneCore *lc); #ifdef SQLITE_STORAGE_ENABLED int _linphone_sqlite3_open(const char *db_file, sqlite3 **db); -sqlite3 * linphone_message_storage_init(void); -void linphone_message_storage_init_chat_rooms(LinphoneCore *lc); #endif -void linphone_chat_message_store_update(LinphoneChatMessage *msg); -void linphone_chat_message_store_state(LinphoneChatMessage *msg); -void linphone_chat_message_store_appdata(LinphoneChatMessage* msg); -void linphone_core_message_storage_init(LinphoneCore *lc); -void linphone_core_message_storage_close(LinphoneCore *lc); -void linphone_core_message_storage_set_debug(LinphoneCore *lc, bool_t debug); void linphone_chat_message_set_time(LinphoneChatMessage* msg, time_t time); void linphone_chat_message_set_incoming(LinphoneChatMessage *msg); diff --git a/coreapi/tester_utils.cpp b/coreapi/tester_utils.cpp index 77c30ad4c..c48407774 100644 --- a/coreapi/tester_utils.cpp +++ b/coreapi/tester_utils.cpp @@ -36,10 +36,6 @@ void linphone_core_enable_send_call_stats_periodical_updates(LinphoneCore *lc, b lc->send_call_stats_periodical_updates = enabled; } -sqlite3 *linphone_core_get_sqlite_database(const LinphoneCore *lc) { - return lc->db; -} - void linphone_core_set_zrtp_cache_db(LinphoneCore *lc, sqlite3 *cache_db) { lc->zrtp_cache_db = cache_db; } diff --git a/coreapi/tester_utils.h b/coreapi/tester_utils.h index 12cf9b401..c486e59f6 100644 --- a/coreapi/tester_utils.h +++ b/coreapi/tester_utils.h @@ -60,7 +60,6 @@ LINPHONE_PUBLIC int linphone_run_stun_tests(LinphoneCore *lc, int audioPort, int char *audioCandidateAddr, int *audioCandidatePort, char *videoCandidateAddr, int *videoCandidatePort, char *textCandidateAddr, int *textCandidatePort); LINPHONE_PUBLIC void linphone_core_enable_short_turn_refresh(LinphoneCore *lc, bool_t enable); -LINPHONE_PUBLIC sqlite3 *linphone_core_get_sqlite_database(const LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_set_zrtp_cache_db(LinphoneCore *lc, sqlite3 *cache_db); LINPHONE_PUBLIC LinphoneCoreCbs *linphone_core_get_first_callbacks(const LinphoneCore *lc); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ef57a4de0..53ae3b8ff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -82,6 +82,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES content/content-manager.h content/content-type.h content/content.h + core/core-accessor.h core/core-p.h core/core.h core/paths/paths.h @@ -178,6 +179,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES content/content-manager.cpp content/content-type.cpp content/content.cpp + core/core-accessor.cpp core/core-chat-room.cpp core/core.cpp core/paths/paths.cpp diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 10ef56188..6292f863c 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -89,7 +89,7 @@ LinphoneCore *linphone_chat_room_get_lc (const LinphoneChatRoom *cr) { } LinphoneCore *linphone_chat_room_get_core (const LinphoneChatRoom *cr) { - return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore(); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore()->getCCore(); } const LinphoneAddress *linphone_chat_room_get_peer_address (LinphoneChatRoom *cr) { @@ -181,7 +181,7 @@ void linphone_chat_room_mark_as_read (LinphoneChatRoom *cr) { } int linphone_chat_room_get_unread_messages_count (LinphoneChatRoom *cr) { - return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getUnreadMessagesCount(); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getUnreadChatMessagesCount(); } int linphone_chat_room_get_history_size (LinphoneChatRoom *cr) { @@ -206,7 +206,7 @@ bctbx_list_t *linphone_chat_room_get_history (LinphoneChatRoom *cr, int nb_messa bctbx_list_t *linphone_chat_room_get_history_events (LinphoneChatRoom *cr, int nb_events) { return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST( - L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore()->cppCore)->mainDb->getHistory( + L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore())->mainDb->getHistory( L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getPeerAddress().asStringUriOnly(), nb_events ) @@ -215,7 +215,7 @@ bctbx_list_t *linphone_chat_room_get_history_events (LinphoneChatRoom *cr, int n bctbx_list_t *linphone_chat_room_get_history_range_events (LinphoneChatRoom *cr, int begin, int end) { return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST( - L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore()->cppCore)->mainDb->getHistory( + L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore())->mainDb->getHistory( L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getPeerAddress().asStringUriOnly(), begin, end @@ -348,14 +348,19 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, cons from = linphone_core_get_primary_contact(core); LinphonePrivate::Address me(from); LinphoneChatRoom *cr = L_INIT(ChatRoom); - L_SET_CPP_PTR_FROM_C_OBJECT(cr, LinphonePrivate::ObjectFactory::create(core, me, L_C_TO_STRING(uri), L_C_TO_STRING(subject))); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, LinphonePrivate::ObjectFactory::create( + core->cppCore, me, L_C_TO_STRING(uri), L_C_TO_STRING(subject)) + ); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); return cr; } LinphoneChatRoom *_linphone_server_group_chat_room_new (LinphoneCore *core, LinphonePrivate::SalCallOp *op) { LinphoneChatRoom *cr = L_INIT(ChatRoom); - L_SET_CPP_PTR_FROM_C_OBJECT(cr, LinphonePrivate::ObjectFactory::create(core, op)); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, LinphonePrivate::ObjectFactory::create( + core->cppCore, + op + )); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); L_GET_PRIVATE_FROM_C_OBJECT(cr, ServerGroupChatRoom)->confirmCreation(); return cr; diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index bd60625ed..b321bb286 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -47,8 +47,8 @@ public: Cpim = 1 << 4 }; - ChatMessagePrivate (const std::shared_ptr &room); - virtual ~ChatMessagePrivate (); + ChatMessagePrivate (); + ~ChatMessagePrivate (); void setChatRoom (std::shared_ptr chatRoom); @@ -119,7 +119,10 @@ public: void send(); private: - std::shared_ptr chatRoom; + std::weak_ptr chatRoom; + Address peerAddress; + + // TODO: Clean attributes. ChatMessage::Direction direction = ChatMessage::Direction::Incoming; ChatMessage::State state = ChatMessage::State::Idle; unsigned int storageId = 0; @@ -157,9 +160,13 @@ private: void fileUploadEndBackgroundTask(); void fileUploadBeginBackgroundTask(); bool isFileTransferInProgressAndValid(); - int startHttpTransfer(std::string url, std::string action, belle_http_request_listener_callbacks_t *cbs); + int startHttpTransfer( + const std::string &url, + const std::string &action, + belle_http_request_listener_callbacks_t *cbs + ); void releaseHttpRequest(); - void createFileTransferInformationsFromVndGsmaRcsFtHttpXml(std::string body); + void createFileTransferInformationsFromVndGsmaRcsFtHttpXml(const std::string &body); L_DECLARE_PUBLIC(ChatMessage); }; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index eb33fdc22..26e657128 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -26,12 +26,13 @@ #include "chat/chat-message/chat-message-p.h" -#include "content/content.h" #include "chat/chat-room/chat-room-p.h" #include "chat/chat-room/real-time-text-chat-room.h" #include "chat/modifier/cpim-chat-message-modifier.h" #include "chat/modifier/encryption-chat-message-modifier.h" #include "chat/modifier/multipart-chat-message-modifier.h" +#include "content/content.h" +#include "core/core.h" #include "logger/logger.h" #include "ortp/b64.h" @@ -47,9 +48,7 @@ using namespace std; // ChatMessagePrivate // ============================================================================= -ChatMessagePrivate::ChatMessagePrivate (const shared_ptr &room) -: chatRoom(room) { -} +ChatMessagePrivate::ChatMessagePrivate () {} ChatMessagePrivate::~ChatMessagePrivate () { if (salOp) @@ -66,82 +65,95 @@ void ChatMessagePrivate::setDirection (ChatMessage::Direction dir) { direction = dir; } -void ChatMessagePrivate::setTime(time_t t) { +void ChatMessagePrivate::setTime (time_t t) { time = t; } -void ChatMessagePrivate::setIsReadOnly(bool readOnly) { +void ChatMessagePrivate::setIsReadOnly (bool readOnly) { isReadOnly = readOnly; } -void ChatMessagePrivate::setState(ChatMessage::State s) { +void ChatMessagePrivate::setState (ChatMessage::State s) { L_Q(); - if (s != state && chatRoom) { - if (((state == ChatMessage::State::Displayed) || (state == ChatMessage::State::DeliveredToUser)) - && ((s == ChatMessage::State::DeliveredToUser) || (s == ChatMessage::State::Delivered) || (s == ChatMessage::State::NotDelivered))) { - return; - } - lInfo() << "Chat message " << this << ": moving from state " << linphone_chat_message_state_to_string((LinphoneChatMessageState)state) << " to " << linphone_chat_message_state_to_string((LinphoneChatMessageState)s); - state = s; - LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); - if (linphone_chat_message_get_message_state_changed_cb(msg)) { - linphone_chat_message_get_message_state_changed_cb(msg)(msg, (LinphoneChatMessageState)state, linphone_chat_message_get_message_state_changed_cb_user_data(msg)); - } - LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); - if (cbs && linphone_chat_message_cbs_get_msg_state_changed(cbs)) { - linphone_chat_message_cbs_get_msg_state_changed(cbs)(msg, linphone_chat_message_get_state(msg)); - } - } + if (s == state || !q->getChatRoom()) + return; + + if ( + (state == ChatMessage::State::Displayed || state == ChatMessage::State::DeliveredToUser) && + ( + s == ChatMessage::State::DeliveredToUser || + s == ChatMessage::State::Delivered || + s == ChatMessage::State::NotDelivered + ) + ) + return; + + lInfo() << "Chat message " << this << ": moving from state " << + linphone_chat_message_state_to_string((LinphoneChatMessageState)state) << " to " << + linphone_chat_message_state_to_string((LinphoneChatMessageState)s); + state = s; + + LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); + if (linphone_chat_message_get_message_state_changed_cb(msg)) + linphone_chat_message_get_message_state_changed_cb(msg)( + msg, + (LinphoneChatMessageState)state, + linphone_chat_message_get_message_state_changed_cb_user_data(msg) + ); + + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); + if (cbs && linphone_chat_message_cbs_get_msg_state_changed(cbs)) + linphone_chat_message_cbs_get_msg_state_changed(cbs)(msg, linphone_chat_message_get_state(msg)); } -unsigned int ChatMessagePrivate::getStorageId() const { +unsigned int ChatMessagePrivate::getStorageId () const { return storageId; } -void ChatMessagePrivate::setStorageId(unsigned int id) { +void ChatMessagePrivate::setStorageId (unsigned int id) { storageId = id; } -belle_http_request_t *ChatMessagePrivate::getHttpRequest() const { +belle_http_request_t *ChatMessagePrivate::getHttpRequest () const { return httpRequest; } -void ChatMessagePrivate::setHttpRequest(belle_http_request_t *request) { +void ChatMessagePrivate::setHttpRequest (belle_http_request_t *request) { httpRequest = request; } -SalOp *ChatMessagePrivate::getSalOp() const { +SalOp *ChatMessagePrivate::getSalOp () const { return salOp; } -void ChatMessagePrivate::setSalOp(SalOp *op) { +void ChatMessagePrivate::setSalOp (SalOp *op) { salOp = op; } -SalCustomHeader *ChatMessagePrivate::getSalCustomHeaders() const { +SalCustomHeader *ChatMessagePrivate::getSalCustomHeaders () const { return salCustomHeaders; } -void ChatMessagePrivate::setSalCustomHeaders(SalCustomHeader *headers) { +void ChatMessagePrivate::setSalCustomHeaders (SalCustomHeader *headers) { salCustomHeaders = headers; } -void ChatMessagePrivate::addSalCustomHeader(const string& name, const string& value) { +void ChatMessagePrivate::addSalCustomHeader (const string &name, const string &value) { salCustomHeaders = sal_custom_header_append(salCustomHeaders, name.c_str(), value.c_str()); } -void ChatMessagePrivate::removeSalCustomHeader(const string& name) { +void ChatMessagePrivate::removeSalCustomHeader (const string &name) { salCustomHeaders = sal_custom_header_remove(salCustomHeaders, name.c_str()); } -string ChatMessagePrivate::getSalCustomHeaderValue(const string& name) { +string ChatMessagePrivate::getSalCustomHeaderValue (const string &name) { return L_C_TO_STRING(sal_custom_header_find(salCustomHeaders, name.c_str())); } // ----------------------------------------------------------------------------- -const ContentType& ChatMessagePrivate::getContentType() { +const ContentType &ChatMessagePrivate::getContentType () { if (direction == ChatMessage::Direction::Incoming) { if (contents.size() > 0) { Content content = contents.front(); @@ -162,11 +174,11 @@ const ContentType& ChatMessagePrivate::getContentType() { return cContentType; } -void ChatMessagePrivate::setContentType(const ContentType &contentType) { +void ChatMessagePrivate::setContentType (const ContentType &contentType) { internalContent.setContentType(contentType); } -const string& ChatMessagePrivate::getText() { +const string &ChatMessagePrivate::getText () { if (direction == ChatMessage::Direction::Incoming) { if (contents.size() > 0) { Content content = contents.front(); @@ -187,53 +199,53 @@ const string& ChatMessagePrivate::getText() { return cText; } -void ChatMessagePrivate::setText(const string& text) { +void ChatMessagePrivate::setText (const string &text) { internalContent.setBody(text); } -LinphoneContent * ChatMessagePrivate::getFileTransferInformation() const { +LinphoneContent *ChatMessagePrivate::getFileTransferInformation () const { return cFileTransferInformation; } -void ChatMessagePrivate::setFileTransferInformation(LinphoneContent *content) { +void ChatMessagePrivate::setFileTransferInformation (LinphoneContent *content) { if (cFileTransferInformation) { linphone_content_unref(cFileTransferInformation); - cFileTransferInformation = NULL; + cFileTransferInformation = nullptr; } cFileTransferInformation = content; } // ----------------------------------------------------------------------------- -string ChatMessagePrivate::createImdnXml(Imdn::Type imdnType, LinphoneReason reason) { +string ChatMessagePrivate::createImdnXml (Imdn::Type imdnType, LinphoneReason reason) { xmlBufferPtr buf; xmlTextWriterPtr writer; int err; string content; - char *datetime = NULL; + char *datetime = nullptr; - // Check that the chat message has a message id - if (id.empty()) return NULL; + // Check that the chat message has a message id. + if (id.empty()) return nullptr; buf = xmlBufferCreate(); - if (buf == NULL) { + if (buf == nullptr) { lError() << "Error creating the XML buffer"; return content; } writer = xmlNewTextWriterMemory(buf, 0); - if (writer == NULL) { + if (writer == nullptr) { lError() << "Error creating the XML writer"; return content; } datetime = linphone_timestamp_to_rfc3339_string(time); - err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); + err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", nullptr); if (err >= 0) { - err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"imdn", - (const xmlChar *)"urn:ietf:params:xml:ns:imdn"); + err = xmlTextWriterStartElementNS(writer, nullptr, (const xmlChar *)"imdn", + (const xmlChar *)"urn:ietf:params:xml:ns:imdn"); } if ((err >= 0) && (reason != LinphoneReasonNone)) { - err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"linphoneimdn", NULL, (const xmlChar *)"http://www.linphone.org/xsds/imdn.xsd"); + err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"linphoneimdn", nullptr, (const xmlChar *)"http://www.linphone.org/xsds/imdn.xsd"); } if (err >= 0) { err = xmlTextWriterWriteElement(writer, (const xmlChar *)"message-id", (const xmlChar *)id.c_str()); @@ -267,7 +279,7 @@ string ChatMessagePrivate::createImdnXml(Imdn::Type imdnType, LinphoneReason rea err = xmlTextWriterEndElement(writer); } if ((err >= 0) && (reason != LinphoneReasonNone)) { - err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"linphoneimdn", (const xmlChar *)"reason", NULL); + err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"linphoneimdn", (const xmlChar *)"reason", nullptr); if (err >= 0) { char codestr[16]; snprintf(codestr, 16, "%d", linphone_reason_to_error_code(reason)); @@ -305,23 +317,35 @@ string ChatMessagePrivate::createImdnXml(Imdn::Type imdnType, LinphoneReason rea return content; } -void ChatMessagePrivate::sendImdn(Imdn::Type imdnType, LinphoneReason reason) { - string content = createImdnXml(imdnType, reason); - chatRoom->getPrivate()->sendImdn(content, reason); +void ChatMessagePrivate::sendImdn (Imdn::Type imdnType, LinphoneReason reason) { + L_Q(); + shared_ptr chatRoom = q->getChatRoom(); + if (chatRoom) + chatRoom->getPrivate()->sendImdn(createImdnXml(imdnType, reason), reason); } -static void _chat_message_file_transfer_on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *m, - void *data, size_t offset, size_t total) { +static void _chat_message_file_transfer_on_progress ( + belle_sip_body_handler_t *bh, + belle_sip_message_t *m, + void *data, + size_t offset, + size_t total +) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->fileTransferOnProgress(bh, m, offset, total); } -void ChatMessagePrivate::fileTransferOnProgress(belle_sip_body_handler_t *bh, belle_sip_message_t *m, - size_t offset, size_t total) { +void ChatMessagePrivate::fileTransferOnProgress ( + belle_sip_body_handler_t *bh, + belle_sip_message_t *m, + size_t offset, + size_t total +) { L_Q(); if (!isFileTransferInProgressAndValid()) { - lWarning() << "Cancelled request for " << (chatRoom ? "" : "ORPHAN") << " msg [" << this << "], ignoring " << __FUNCTION__; + lWarning() << "Cancelled request for " << (chatRoom.lock() ? "" : "ORPHAN") << " msg [" << this << + "], ignoring " << __FUNCTION__; releaseHttpRequest(); return; } @@ -331,44 +355,62 @@ void ChatMessagePrivate::fileTransferOnProgress(belle_sip_body_handler_t *bh, be if (linphone_chat_message_cbs_get_file_transfer_progress_indication(cbs)) { linphone_chat_message_cbs_get_file_transfer_progress_indication(cbs)(msg, cFileTransferInformation, offset, total); } else { - // Legacy: call back given by application level - linphone_core_notify_file_transfer_progress_indication(chatRoom->getCore(), msg, cFileTransferInformation, offset, total); + // Legacy: call back given by application level. + shared_ptr core = q->getCore(); + if (core) + linphone_core_notify_file_transfer_progress_indication( + core->getCCore(), + msg, + cFileTransferInformation, + offset, + total + ); } } -static int _chat_message_on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, - void *data, size_t offset, uint8_t *buffer, size_t *size) { +static int _chat_message_on_send_body ( + belle_sip_user_body_handler_t *bh, + belle_sip_message_t *m, + void *data, + size_t offset, + uint8_t *buffer, + size_t *size +) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; return d->onSendBody(bh, m, offset, buffer, size); } -int ChatMessagePrivate::onSendBody(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, - size_t offset, uint8_t *buffer, size_t *size) { +int ChatMessagePrivate::onSendBody ( + belle_sip_user_body_handler_t *bh, + belle_sip_message_t *m, + size_t offset, + uint8_t *buffer, + size_t *size +) { L_Q(); - LinphoneCore *lc = NULL; - LinphoneImEncryptionEngine *imee = NULL; int retval = -1; LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); if (!isFileTransferInProgressAndValid()) { if (httpRequest) { - lWarning() << "Cancelled request for " << (chatRoom ? "" : "ORPHAN") << " msg [" << this << "], ignoring " << __FUNCTION__; + lWarning() << "Cancelled request for " << (chatRoom.lock() ? "" : "ORPHAN") << + " msg [" << this << "], ignoring " << __FUNCTION__; releaseHttpRequest(); } return BELLE_SIP_STOP; } - lc = chatRoom->getCore(); // if we've not reach the end of file yet, ask for more data // in case of file body handler, won't be called if (fileTransferFilePath.empty() && offset < linphone_content_get_size(cFileTransferInformation)) { // get data from call back LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); - LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = linphone_chat_message_cbs_get_file_transfer_send(cbs); + LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = + linphone_chat_message_cbs_get_file_transfer_send(cbs); if (file_transfer_send_cb) { LinphoneBuffer *lb = file_transfer_send_cb(msg, cFileTransferInformation, offset, *size); - if (lb == NULL) { + if (lb == nullptr) { *size = 0; } else { *size = linphone_buffer_get_size(lb); @@ -377,14 +419,21 @@ int ChatMessagePrivate::onSendBody(belle_sip_user_body_handler_t *bh, belle_sip_ } } else { // Legacy - linphone_core_notify_file_transfer_send(lc, msg, cFileTransferInformation, (char *)buffer, size); + shared_ptr core = q->getCore(); + if (core) + linphone_core_notify_file_transfer_send(core->getCCore(), msg, cFileTransferInformation, (char *)buffer, size); } } - imee = linphone_core_get_im_encryption_engine(lc); + LinphoneImEncryptionEngine *imee = nullptr; + shared_ptr core = q->getCore(); + if (core) + imee = linphone_core_get_im_encryption_engine(core->getCCore()); + if (imee) { LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); + LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = + linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); if (cb_process_uploading_file) { size_t max_size = *size; uint8_t *encrypted_buffer = (uint8_t *)ms_malloc0(max_size); @@ -403,27 +452,29 @@ int ChatMessagePrivate::onSendBody(belle_sip_user_body_handler_t *bh, belle_sip_ return retval <= 0 ? BELLE_SIP_CONTINUE : BELLE_SIP_STOP; } -static void _chat_message_on_send_end(belle_sip_user_body_handler_t *bh, void *data) { +static void _chat_message_on_send_end (belle_sip_user_body_handler_t *bh, void *data) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->onSendEnd(bh); } -void ChatMessagePrivate::onSendEnd(belle_sip_user_body_handler_t *bh) { +void ChatMessagePrivate::onSendEnd (belle_sip_user_body_handler_t *bh) { L_Q(); - LinphoneCore *lc = chatRoom->getCore(); - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); + LinphoneImEncryptionEngine *imee = nullptr; + shared_ptr core = q->getCore(); + if (core) + imee = linphone_core_get_im_encryption_engine(core->getCCore()); if (imee) { LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); if (cb_process_uploading_file) { - cb_process_uploading_file(imee, L_GET_C_BACK_PTR(q), 0, NULL, NULL, NULL); + cb_process_uploading_file(imee, L_GET_C_BACK_PTR(q), 0, nullptr, nullptr, nullptr); } } } -void ChatMessagePrivate::fileUploadEndBackgroundTask() { +void ChatMessagePrivate::fileUploadEndBackgroundTask () { if (backgroundTaskId) { lInfo() << "channel [" << this << "]: ending file upload background task with id=[" << backgroundTaskId << "]."; sal_end_background_task(backgroundTaskId); @@ -431,45 +482,38 @@ void ChatMessagePrivate::fileUploadEndBackgroundTask() { } } -static void _chat_message_file_upload_background_task_ended(void *data) { +static void _chat_message_file_upload_background_task_ended (void *data) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->fileUploadBackgroundTaskEnded(); } -void ChatMessagePrivate::fileUploadBackgroundTaskEnded() { +void ChatMessagePrivate::fileUploadBackgroundTaskEnded () { lWarning() << "channel [" << this << "]: file upload background task has to be ended now, but work isn't finished."; fileUploadEndBackgroundTask(); } -void ChatMessagePrivate::fileUploadBeginBackgroundTask() { +void ChatMessagePrivate::fileUploadBeginBackgroundTask () { if (backgroundTaskId == 0) { backgroundTaskId = sal_begin_background_task("file transfer upload", _chat_message_file_upload_background_task_ended, this); if (backgroundTaskId) lInfo() << "channel [" << this << "]: starting file upload background task with id=[" << backgroundTaskId << "]."; } } -static void _chat_message_on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset, uint8_t *buffer, size_t size) { +static void _chat_message_on_recv_body (belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset, uint8_t *buffer, size_t size) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->onRecvBody(bh, m, offset, buffer, size); } -void ChatMessagePrivate::onRecvBody(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, size_t offset, uint8_t *buffer, size_t size) { +void ChatMessagePrivate::onRecvBody (belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, size_t offset, uint8_t *buffer, size_t size) { L_Q(); - LinphoneCore *lc = NULL; - LinphoneImEncryptionEngine *imee = NULL; int retval = -1; - uint8_t *decrypted_buffer = NULL; + uint8_t *decrypted_buffer = nullptr; - if (!chatRoom) { + if (!chatRoom.lock()) { q->cancelFileTransfer(); return; } - lc = chatRoom->getCore(); - - if (lc == NULL) { - return; // might happen during linphone_core_destroy() - } if (!httpRequest || belle_http_request_is_cancelled(httpRequest)) { lWarning() << "Cancelled request for msg [" << this << "], ignoring " << __FUNCTION__; @@ -482,7 +526,12 @@ void ChatMessagePrivate::onRecvBody(belle_sip_user_body_handler_t *bh, belle_sip } decrypted_buffer = (uint8_t *)ms_malloc0(size); - imee = linphone_core_get_im_encryption_engine(lc); + + LinphoneImEncryptionEngine *imee = nullptr; + shared_ptr core = q->getCore(); + if (core) + imee = linphone_core_get_im_encryption_engine(core->getCCore()); + if (imee) { LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); @@ -505,34 +554,35 @@ void ChatMessagePrivate::onRecvBody(belle_sip_user_body_handler_t *bh, belle_sip linphone_buffer_unref(lb); } else { // Legacy: call back given by application level - linphone_core_notify_file_transfer_recv(lc, msg, cFileTransferInformation, (const char *)buffer, size); + linphone_core_notify_file_transfer_recv(core->getCCore(), msg, cFileTransferInformation, (const char *)buffer, size); } } } else { lWarning() << "File transfer decrypt failed with code " << (int)retval; setState(ChatMessage::State::FileTransferError); } - - return; } -static void _chat_message_on_recv_end(belle_sip_user_body_handler_t *bh, void *data) { +static void _chat_message_on_recv_end (belle_sip_user_body_handler_t *bh, void *data) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->onRecvEnd(bh); } -void ChatMessagePrivate::onRecvEnd(belle_sip_user_body_handler_t *bh) { +void ChatMessagePrivate::onRecvEnd (belle_sip_user_body_handler_t *bh) { L_Q(); - LinphoneCore *lc = chatRoom->getCore(); - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); + shared_ptr core = q->getCore(); + if (!core) + return; + + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(core->getCCore()); int retval = -1; if (imee) { LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); if (cb_process_downloading_file) { - retval = cb_process_downloading_file(imee, L_GET_C_BACK_PTR(q), 0, NULL, 0, NULL); + retval = cb_process_downloading_file(imee, L_GET_C_BACK_PTR(q), 0, nullptr, 0, nullptr); } } @@ -546,7 +596,7 @@ void ChatMessagePrivate::onRecvEnd(belle_sip_user_body_handler_t *bh) { linphone_buffer_unref(lb); } else { // Legacy: call back given by application level - linphone_core_notify_file_transfer_recv(lc, msg, cFileTransferInformation, NULL, 0); + linphone_core_notify_file_transfer_recv(core->getCCore(), msg, cFileTransferInformation, nullptr, 0); } } } @@ -556,20 +606,23 @@ void ChatMessagePrivate::onRecvEnd(belle_sip_user_body_handler_t *bh) { } } -bool ChatMessagePrivate::isFileTransferInProgressAndValid() { - return (chatRoom && chatRoom->getCore() && httpRequest && !belle_http_request_is_cancelled(httpRequest)); +bool ChatMessagePrivate::isFileTransferInProgressAndValid () { + L_Q(); + shared_ptr chatRoom = q->getChatRoom(); + return chatRoom && q->getCore() && httpRequest && !belle_http_request_is_cancelled(httpRequest); } -static void _chat_message_process_response_from_post_file(void *data, const belle_http_response_event_t *event) { +static void _chat_message_process_response_from_post_file (void *data, const belle_http_response_event_t *event) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->processResponseFromPostFile(event); } -void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_event_t *event) { +void ChatMessagePrivate::processResponseFromPostFile (const belle_http_response_event_t *event) { L_Q(); if (httpRequest && !isFileTransferInProgressAndValid()) { - lWarning() << "Cancelled request for " << (chatRoom ? "" : "ORPHAN") << " msg [" << this << "], ignoring " << __FUNCTION__; + lWarning() << "Cancelled request for " << (chatRoom.lock() ? "" : "ORPHAN") << + " msg [" << this << "], ignoring " << __FUNCTION__; releaseHttpRequest(); return; } @@ -584,8 +637,15 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e belle_sip_body_handler_t *first_part_bh; bool_t is_file_encryption_enabled = FALSE; - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(chatRoom->getCore()); - if (imee) { + LinphoneImEncryptionEngine *imee = nullptr; + + shared_ptr core = q->getCore(); + shared_ptr chatRoom = q->getChatRoom(); + + if (core) + imee = linphone_core_get_im_encryption_engine(core->getCCore()); + + if (imee && chatRoom) { LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer_cb = linphone_im_encryption_engine_cbs_get_is_encryption_enabled_for_file_transfer(imee_cbs); @@ -594,7 +654,7 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e } } // shall we encrypt the file - if (is_file_encryption_enabled) { + if (is_file_encryption_enabled && chatRoom) { LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb generate_file_transfer_key_cb = linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(imee_cbs); @@ -607,54 +667,54 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e first_part_header = "form-data; name=\"File\"; filename=\"filename.txt\""; } else { // temporary storage for the Content-disposition header value - first_part_header = "form-data; name=\"File\"; filename=\"" +string(linphone_content_get_name(cFileTransferInformation)) + "\""; + first_part_header = "form-data; name=\"File\"; filename=\"" + string(linphone_content_get_name(cFileTransferInformation)) + "\""; } // create a user body handler to take care of the file and add the content disposition and content-type headers first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new( linphone_content_get_size(cFileTransferInformation), - _chat_message_file_transfer_on_progress, NULL, NULL, + _chat_message_file_transfer_on_progress, nullptr, nullptr, _chat_message_on_send_body, _chat_message_on_send_end, this); if (!fileTransferFilePath.empty()) { belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh; // No need to add again the callback for progression, otherwise it will be called twice - first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(fileTransferFilePath.c_str(), NULL, this); + first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(fileTransferFilePath.c_str(), nullptr, this); linphone_content_set_size(cFileTransferInformation, belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh)); belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)first_part_bh, body_handler); - } else if (linphone_content_get_buffer(cFileTransferInformation) != NULL) { + } else if (linphone_content_get_buffer(cFileTransferInformation) != nullptr) { first_part_bh = (belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer( - linphone_content_get_buffer(cFileTransferInformation), - linphone_content_get_size(cFileTransferInformation), _chat_message_file_transfer_on_progress, this); + linphone_content_get_buffer(cFileTransferInformation), + linphone_content_get_size(cFileTransferInformation), _chat_message_file_transfer_on_progress, this); } belle_sip_body_handler_add_header(first_part_bh, - belle_sip_header_create("Content-disposition", first_part_header.c_str())); + belle_sip_header_create("Content-disposition", first_part_header.c_str())); belle_sip_body_handler_add_header(first_part_bh, - (belle_sip_header_t *)belle_sip_header_content_type_create( - linphone_content_get_type(cFileTransferInformation), - linphone_content_get_subtype(cFileTransferInformation))); + (belle_sip_header_t *)belle_sip_header_content_type_create( + linphone_content_get_type(cFileTransferInformation), + linphone_content_get_subtype(cFileTransferInformation))); // insert it in a multipart body handler which will manage the boundaries of multipart msg - bh = belle_sip_multipart_body_handler_new(_chat_message_file_transfer_on_progress, this, first_part_bh, NULL); + bh = belle_sip_multipart_body_handler_new(_chat_message_file_transfer_on_progress, this, first_part_bh, nullptr); releaseHttpRequest(); fileUploadBeginBackgroundTask(); q->uploadFile(); belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(httpRequest), BELLE_SIP_BODY_HANDLER(bh)); - } else if (code == 200) { // file has been uploaded correctly, get server reply and send it + } else if (code == 200) { // file has been uploaded correctly, get server reply and send it const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); if (body && strlen(body) > 0) { // if we have an encryption key for the file, we must insert it into the msg and restore the correct filename const char *content_key = linphone_content_get_key(cFileTransferInformation); size_t content_key_size = linphone_content_get_key_size(cFileTransferInformation); - if (content_key != NULL) { + if (content_key != nullptr) { // parse the msg body xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body); xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody); - if (cur != NULL) { + if (cur != nullptr) { cur = cur->xmlChildrenNode; - while (cur != NULL) { + while (cur != nullptr) { // we found a file info node, check it has a type="file" attribute if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); @@ -663,20 +723,20 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e // need to parse the children node to update the file-name one xmlNodePtr fileInfoNodeChildren = cur->xmlChildrenNode; // convert key to base64 - size_t b64Size = b64_encode(NULL, content_key_size, NULL, 0); + size_t b64Size = b64_encode(nullptr, content_key_size, nullptr, 0); char *keyb64 = (char *)ms_malloc0(b64Size + 1); int xmlStringLength; b64Size = b64_encode(content_key, content_key_size, keyb64, b64Size); - keyb64[b64Size] = '\0'; // libxml need a null terminated string + keyb64[b64Size] = '\0'; // libxml need a null terminated string // add the node containing the key to the file-info node - xmlNewTextChild(cur, NULL, (const xmlChar *)"file-key", (const xmlChar *)keyb64); + xmlNewTextChild(cur, nullptr, (const xmlChar *)"file-key", (const xmlChar *)keyb64); xmlFree(typeAttribute); ms_free(keyb64); // look for the file-name node and update its content - while (fileInfoNodeChildren != NULL) { + while (fileInfoNodeChildren != nullptr) { // we found a the file-name node, update its content with the real filename if (!xmlStrcmp(fileInfoNodeChildren->name, (const xmlChar *)"file-name")) { // update node content @@ -698,7 +758,7 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e } } xmlFreeDoc(xmlMessageBody); - } else { // no encryption key, transfer in plain, just copy the msg sent by server + } else { // no encryption key, transfer in plain, just copy the msg sent by server setText(body); } setContentType(ContentType::FileTransfer); @@ -721,19 +781,17 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e } } -static void _chat_process_response_headers_from_get_file(void *data, const belle_http_response_event_t *event) { +static void _chat_process_response_headers_from_get_file (void *data, const belle_http_response_event_t *event) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->processResponseHeadersFromGetFile(event); } -static LinphoneContent *createFileTransferInformationFromHeaders(const belle_sip_message_t *m) { +static LinphoneContent *createFileTransferInformationFromHeaders (const belle_sip_message_t *m) { LinphoneContent *content = linphone_content_new(); - belle_sip_header_content_length_t *content_length_hdr = - BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(m, "Content-Length")); - belle_sip_header_content_type_t *content_type_hdr = - BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(m, "Content-Type")); - const char *type = NULL, *subtype = NULL; + belle_sip_header_content_length_t *content_length_hdr = BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(m, "Content-Length")); + belle_sip_header_content_type_t *content_type_hdr = BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(m, "Content-Type")); + const char *type = nullptr, *subtype = nullptr; linphone_content_set_name(content, ""); @@ -757,15 +815,15 @@ static LinphoneContent *createFileTransferInformationFromHeaders(const belle_sip return content; } -void ChatMessagePrivate::processResponseHeadersFromGetFile(const belle_http_response_event_t *event) { +void ChatMessagePrivate::processResponseHeadersFromGetFile (const belle_http_response_event_t *event) { if (event->response) { - //we are receiving a response, set a specific body handler to acquire the response. + // we are receiving a response, set a specific body handler to acquire the response. // if not done, belle-sip will create a memory body handler, the default belle_sip_message_t *response = BELLE_SIP_MESSAGE(event->response); - belle_sip_body_handler_t *body_handler = NULL; + belle_sip_body_handler_t *body_handler = nullptr; size_t body_size = 0; - if (cFileTransferInformation == NULL) { + if (cFileTransferInformation == nullptr) { lWarning() << "No file transfer information for msg [" << this << "]: creating..."; cFileTransferInformation = createFileTransferInformationFromHeaders(response); } @@ -775,8 +833,8 @@ void ChatMessagePrivate::processResponseHeadersFromGetFile(const belle_http_resp } body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, _chat_message_file_transfer_on_progress, - NULL, _chat_message_on_recv_body, - NULL, _chat_message_on_recv_end, this); + nullptr, _chat_message_on_recv_body, + nullptr, _chat_message_on_recv_end, this); if (!fileTransferFilePath.empty()) { belle_sip_user_body_handler_t *bh = (belle_sip_user_body_handler_t *)body_handler; body_handler = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(fileTransferFilePath.c_str(), _chat_message_file_transfer_on_progress, this); @@ -791,12 +849,12 @@ void ChatMessagePrivate::processResponseHeadersFromGetFile(const belle_http_resp } } -static void _chat_message_process_auth_requested_download(void *data, belle_sip_auth_event *event) { +static void _chat_message_process_auth_requested_download (void *data, belle_sip_auth_event *event) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->processAuthRequestedDownload(event); } -void ChatMessagePrivate::processAuthRequestedDownload(const belle_sip_auth_event *event) { +void ChatMessagePrivate::processAuthRequestedDownload (const belle_sip_auth_event *event) { L_Q(); lError() << "Error during file download : auth requested for msg [" << this << "]"; @@ -804,38 +862,46 @@ void ChatMessagePrivate::processAuthRequestedDownload(const belle_sip_auth_event releaseHttpRequest(); } -static void _chat_message_process_io_error_upload(void *data, const belle_sip_io_error_event_t *event) { +static void _chat_message_process_io_error_upload (void *data, const belle_sip_io_error_event_t *event) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->processIoErrorUpload(event); } -void ChatMessagePrivate::processIoErrorUpload(const belle_sip_io_error_event_t *event) { +void ChatMessagePrivate::processIoErrorUpload (const belle_sip_io_error_event_t *event) { L_Q(); + lError() << "I/O Error during file upload of msg [" << this << "]"; q->updateState(ChatMessage::State::NotDelivered); releaseHttpRequest(); - chatRoom->getPrivate()->removeTransientMessage(q->getSharedFromThis()); + + shared_ptr chatRoom = q->getChatRoom(); + if (chatRoom) + chatRoom->getPrivate()->removeTransientMessage(q->getSharedFromThis()); } -static void _chat_message_process_auth_requested_upload(void *data, belle_sip_auth_event *event) { +static void _chat_message_process_auth_requested_upload (void *data, belle_sip_auth_event *event) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->processAuthRequestedUpload(event); } -void ChatMessagePrivate::processAuthRequestedUpload(const belle_sip_auth_event *event) { +void ChatMessagePrivate::processAuthRequestedUpload (const belle_sip_auth_event *event) { L_Q(); + lError() << "Error during file upload: auth requested for msg [" << this << "]"; q->updateState(ChatMessage::State::NotDelivered); releaseHttpRequest(); - chatRoom->getPrivate()->removeTransientMessage(q->getSharedFromThis()); + + shared_ptr chatRoom = q->getChatRoom(); + if (chatRoom) + chatRoom->getPrivate()->removeTransientMessage(q->getSharedFromThis()); } -static void _chat_message_process_io_error_download(void *data, const belle_sip_io_error_event_t *event) { +static void _chat_message_process_io_error_download (void *data, const belle_sip_io_error_event_t *event) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->processIoErrorDownload(event); } -void ChatMessagePrivate::processIoErrorDownload(const belle_sip_io_error_event_t *event) { +void ChatMessagePrivate::processIoErrorDownload (const belle_sip_io_error_event_t *event) { L_Q(); lError() << "I/O Error during file download msg [" << this << "]"; @@ -843,12 +909,12 @@ void ChatMessagePrivate::processIoErrorDownload(const belle_sip_io_error_event_t releaseHttpRequest(); } -static void _chat_message_process_response_from_get_file(void *data, const belle_http_response_event_t *event) { +static void _chat_message_process_response_from_get_file (void *data, const belle_http_response_event_t *event) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->processResponseFromGetFile(event); } -void ChatMessagePrivate::processResponseFromGetFile(const belle_http_response_event_t *event) { +void ChatMessagePrivate::processResponseFromGetFile (const belle_http_response_event_t *event) { // check the answer code if (event->response) { int code = belle_http_response_get_status_code(event->response); @@ -862,23 +928,35 @@ void ChatMessagePrivate::processResponseFromGetFile(const belle_http_response_ev } } -int ChatMessagePrivate::startHttpTransfer(std::string url, std::string action, belle_http_request_listener_callbacks_t *cbs) { - belle_generic_uri_t *uri = NULL; - const char* ua = linphone_core_get_user_agent(chatRoom->getCore()); +int ChatMessagePrivate::startHttpTransfer ( + const string &url, + const string &action, + belle_http_request_listener_callbacks_t *cbs +) { + L_Q(); + + belle_generic_uri_t *uri = nullptr; + + shared_ptr core = q->getCore(); + if (!core) + return -1; + + const char *ua = linphone_core_get_user_agent(core->getCCore()); if (url.empty()) { lWarning() << "Cannot process file transfer msg [" << this << "]: no file remote URI configured."; goto error; } uri = belle_generic_uri_parse(url.c_str()); - if (uri == NULL || belle_generic_uri_get_host(uri) == NULL) { - lWarning() << "Cannot process file transfer msg [" << this << "]: incorrect file remote URI configured '" << url << "'."; + if (uri == nullptr || belle_generic_uri_get_host(uri) == nullptr) { + lWarning() << "Cannot process file transfer msg [" << this << "]: incorrect file remote URI configured '" << + url << "'."; goto error; } - httpRequest = belle_http_request_create(action.c_str(), uri, belle_sip_header_create("User-Agent", ua), NULL); + httpRequest = belle_http_request_create(action.c_str(), uri, belle_sip_header_create("User-Agent", ua), nullptr); - if (httpRequest == NULL) { + if (httpRequest == nullptr) { lWarning() << "Could not create http request for uri " << url; goto error; } @@ -887,8 +965,9 @@ int ChatMessagePrivate::startHttpTransfer(std::string url, std::string action, b // give msg to listener to be able to start the actual file upload when server answer a 204 No content httpListener = belle_http_request_listener_create_from_callbacks(cbs, this); - belle_http_provider_send_request(chatRoom->getCore()->http_provider, httpRequest, httpListener); + belle_http_provider_send_request(core->getCCore()->http_provider, httpRequest, httpListener); return 0; + error: if (uri) { belle_sip_object_unref(uri); @@ -896,19 +975,19 @@ error: return -1; } -void ChatMessagePrivate::releaseHttpRequest() { +void ChatMessagePrivate::releaseHttpRequest () { if (httpRequest) { belle_sip_object_unref(httpRequest); - httpRequest = NULL; - if (httpListener){ + httpRequest = nullptr; + if (httpListener) { belle_sip_object_unref(httpListener); - httpListener = NULL; + httpListener = nullptr; } } } -void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml(string body) { - xmlChar *file_url = NULL; +void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml (const string &body) { + xmlChar *file_url = nullptr; xmlDocPtr xmlMessageBody; xmlNodePtr cur; /* parse the msg body to get all informations from it */ @@ -917,18 +996,18 @@ void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml(s setFileTransferInformation(content); cur = xmlDocGetRootElement(xmlMessageBody); - if (cur != NULL) { + if (cur != nullptr) { cur = cur->xmlChildrenNode; - while (cur != NULL) { + while (cur != nullptr) { if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { /* we found a file info node, check if it has a type="file" attribute */ xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); - if (!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for */ - cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */ - while (cur != NULL) { + if (!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for */ + cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */ + while (cur != nullptr) { if (!xmlStrcmp(cur->name, (const xmlChar *)"file-size")) { xmlChar *fileSizeString = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - linphone_content_set_size(content, (size_t)strtol((const char *)fileSizeString, NULL, 10)); + linphone_content_set_size(content, (size_t)strtol((const char *)fileSizeString, nullptr, 10)); xmlFree(fileSizeString); } @@ -961,7 +1040,7 @@ void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml(s /* there is a key in the msg: file has been encrypted */ /* convert the key from base 64 */ xmlChar *keyb64 = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - size_t keyLength = b64::b64_decode((char *)keyb64, strlen((char *)keyb64), NULL, 0); + size_t keyLength = b64::b64_decode((char *)keyb64, strlen((char *)keyb64), nullptr, 0); uint8_t *keyBuffer = (uint8_t *)malloc(keyLength); /* decode the key into local key buffer */ b64::b64_decode((char *)keyb64, strlen((char *)keyb64), keyBuffer, keyLength); @@ -987,11 +1066,14 @@ void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml(s xmlFree(file_url); } -LinphoneReason ChatMessagePrivate::receive() { +LinphoneReason ChatMessagePrivate::receive () { L_Q(); int errorCode = 0; LinphoneReason reason = LinphoneReasonNone; + shared_ptr core = q->getCore(); + shared_ptr chatRoom = q->getChatRoom(); + // --------------------------------------- // Start of message modification // --------------------------------------- @@ -1005,7 +1087,8 @@ LinphoneReason ChatMessagePrivate::receive() { ChatMessageModifier::Result result = ecmm.decode(q->getSharedFromThis(), errorCode); if (result == ChatMessageModifier::Result::Error) { /* Unable to decrypt message */ - chatRoom->getPrivate()->notifyUndecryptableMessageReceived(q->getSharedFromThis()); + if (chatRoom) + chatRoom->getPrivate()->notifyUndecryptableMessageReceived(q->getSharedFromThis()); reason = linphone_error_code_to_reason(errorCode); q->sendDeliveryNotification(reason); return reason; @@ -1025,13 +1108,14 @@ LinphoneReason ChatMessagePrivate::receive() { if (errorCode <= 0) { bool foundSupportContentType = false; - for (const auto &c : contents) { - if (linphone_core_is_content_type_supported(chatRoom->getCore(), c.getContentType().asString().c_str())) { - foundSupportContentType = true; - break; - } else - lError() << "Unsupported content-type: " << c.getContentType().asString(); - } + if (core) + for (const auto &c : contents) { + if (linphone_core_is_content_type_supported(core->getCCore(), c.getContentType().asString().c_str())) { + foundSupportContentType = true; + break; + } else + lError() << "Unsupported content-type: " << c.getContentType().asString(); + } if (!foundSupportContentType) { errorCode = 415; @@ -1039,14 +1123,16 @@ LinphoneReason ChatMessagePrivate::receive() { } } - // Check if this is in fact an outgoing message (case where this is a message sent by us from an other device) - Address me(linphone_core_get_identity(chatRoom->getCore())); - if (me.weakEqual(from)) - setDirection(ChatMessage::Direction::Outgoing); + // Check if this is in fact an outgoing message (case where this is a message sent by us from an other device). + if (core) { + Address me(linphone_core_get_identity(core->getCCore())); + if (me.weakEqual(from)) + setDirection(ChatMessage::Direction::Outgoing); + } - /* Check if this is a duplicate message */ - if (chatRoom->findMessageWithDirection(q->getImdnMessageId(), q->getDirection())) - return chatRoom->getCore()->chat_deny_code; + // Check if this is a duplicate message. + if (chatRoom && chatRoom->findMessageWithDirection(q->getImdnMessageId(), q->getDirection())) + return core->getCCore()->chat_deny_code; if (errorCode > 0) { reason = linphone_error_code_to_reason(errorCode); @@ -1068,13 +1154,13 @@ LinphoneReason ChatMessagePrivate::receive() { return reason; } -void ChatMessagePrivate::send() { +void ChatMessagePrivate::send () { L_Q(); SalOp *op = salOp; - LinphoneCall *call = NULL; + LinphoneCall *call = nullptr; int errorCode = 0; - if ((currentSendStep & ChatMessagePrivate::Step::FileUpload) == ChatMessagePrivate::Step::FileUpload) { + if ((currentSendStep &ChatMessagePrivate::Step::FileUpload) == ChatMessagePrivate::Step::FileUpload) { lInfo() << "File upload step already done, skipping"; } else { if (getFileTransferInformation()) { @@ -1087,22 +1173,23 @@ void ChatMessagePrivate::send() { } } - if (lp_config_get_int(chatRoom->getCore()->config, "sip", "chat_use_call_dialogs", 0) != 0) { - call = linphone_core_get_call_by_remote_address(chatRoom->getCore(), to.asString().c_str()); + shared_ptr core = q->getCore(); + if (core && lp_config_get_int(core->getCCore()->config, "sip", "chat_use_call_dialogs", 0) != 0) { + call = linphone_core_get_call_by_remote_address(core->getCCore(), to.asString().c_str()); if (call) { if (linphone_call_get_state(call) == LinphoneCallConnected || linphone_call_get_state(call) == LinphoneCallStreamsRunning || - linphone_call_get_state(call) == LinphoneCallPaused || linphone_call_get_state(call) == LinphoneCallPausing || - linphone_call_get_state(call) == LinphoneCallPausedByRemote) { + linphone_call_get_state(call) == LinphoneCallPaused || linphone_call_get_state(call) == LinphoneCallPausing || + linphone_call_get_state(call) == LinphoneCallPausedByRemote) { lInfo() << "send SIP msg through the existing call."; op = linphone_call_get_op(call); - string identity = linphone_core_find_best_identity(chatRoom->getCore(), linphone_call_get_remote_address(call)); + string identity = linphone_core_find_best_identity(core->getCCore(), linphone_call_get_remote_address(call)); if (identity.empty()) { LinphoneAddress *addr = linphone_address_new(to.asString().c_str()); - LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(chatRoom->getCore(), addr); + LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core->getCCore(), addr); if (proxy) { identity = L_GET_CPP_PTR_FROM_C_OBJECT(linphone_proxy_config_get_identity_address(proxy))->asString(); } else { - identity = linphone_core_get_primary_contact(chatRoom->getCore()); + identity = linphone_core_get_primary_contact(core->getCCore()); } linphone_address_unref(addr); } @@ -1111,15 +1198,15 @@ void ChatMessagePrivate::send() { } } - if (!op) { + if (core && !op) { LinphoneAddress *peer = linphone_address_new(to.asString().c_str()); /* Sending out of call */ - salOp = op = new SalMessageOp(chatRoom->getCore()->sal); + salOp = op = new SalMessageOp(core->getCCore()->sal); linphone_configure_op( - chatRoom->getCore(), op, peer, getSalCustomHeaders(), - !!lp_config_get_int(chatRoom->getCore()->config, "sip", "chat_msg_with_contact", 0) + core->getCCore(), op, peer, getSalCustomHeaders(), + !!lp_config_get_int(core->getCCore()->config, "sip", "chat_msg_with_contact", 0) ); - op->set_user_pointer(L_GET_C_BACK_PTR(q)); /* If out of call, directly store msg */ + op->set_user_pointer(L_GET_C_BACK_PTR(q)); /* If out of call, directly store msg */ linphone_address_unref(peer); } @@ -1127,7 +1214,7 @@ void ChatMessagePrivate::send() { // Start of message modification // --------------------------------------- - //TODO Remove : This won't be necessary once we store the contentsList + // TODO Remove : This won't be necessary once we store the contentsList string clearTextMessage; ContentType clearTextContentType; @@ -1137,10 +1224,10 @@ void ChatMessagePrivate::send() { if (getContentType().isValid()) { clearTextContentType = getContentType(); } - //End of TODO Remove + // End of TODO Remove if (applyModifiers) { - if ((currentSendStep & ChatMessagePrivate::Step::Multipart) == ChatMessagePrivate::Step::Multipart) { + if ((currentSendStep &ChatMessagePrivate::Step::Multipart) == ChatMessagePrivate::Step::Multipart) { lInfo() << "Multipart step already done, skipping"; } else { if (contents.size() > 1) { @@ -1150,7 +1237,7 @@ void ChatMessagePrivate::send() { currentSendStep |= ChatMessagePrivate::Step::Multipart; } - if ((currentSendStep & ChatMessagePrivate::Step::Encryption) == ChatMessagePrivate::Step::Encryption) { + if ((currentSendStep &ChatMessagePrivate::Step::Encryption) == ChatMessagePrivate::Step::Encryption) { lInfo() << "Encryption step already done, skipping"; } else { EncryptionChatMessageModifier ecmm; @@ -1167,10 +1254,10 @@ void ChatMessagePrivate::send() { currentSendStep |= ChatMessagePrivate::Step::Encryption; } - if ((currentSendStep & ChatMessagePrivate::Step::Cpim) == ChatMessagePrivate::Step::Cpim) { + if ((currentSendStep &ChatMessagePrivate::Step::Cpim) == ChatMessagePrivate::Step::Cpim) { lInfo() << "Cpim step already done, skipping"; } else { - if (lp_config_get_int(chatRoom->getCore()->config, "sip", "use_cpim", 1) == 1) { + if (core && lp_config_get_int(core->getCCore()->config, "sip", "use_cpim", 0) == 1) { CpimChatMessageModifier ccmm; ccmm.encode(q->getSharedFromThis(), errorCode); } @@ -1200,8 +1287,8 @@ void ChatMessagePrivate::send() { } } - //TODO Remove : This won't be necessary once we store the contentsList - if (!getText().empty() && getText() != clearTextMessage) { + // TODO Remove : This won't be necessary once we store the contentsList + if (!getText().empty() && getText() == clearTextMessage) { /* We replace the encrypted message by the original one so it can be correctly stored and displayed by the application */ setText(clearTextMessage); } @@ -1209,9 +1296,9 @@ void ChatMessagePrivate::send() { /* We replace the encrypted content type by the original one */ setContentType(clearTextContentType); } - //End of TODO Remove + // End of TODO Remove - q->setImdnMessageId(op->get_call_id()); /* must be known at that time */ + q->setImdnMessageId(op->get_call_id()); /* must be known at that time */ if (call && linphone_call_get_op(call) == op) { /* In this case, chat delivery status is not notified, so unrefing chat message right now */ @@ -1228,25 +1315,37 @@ void ChatMessagePrivate::send() { // ----------------------------------------------------------------------------- -// ============================================================================= -// ChatMessage -// ============================================================================= +ChatMessage::ChatMessage (const shared_ptr &chatRoom) : + Object(*new ChatMessagePrivate), + CoreAccessor(chatRoom->getCore()) { + L_ASSERT(chatRoom); + L_D(); -ChatMessage::ChatMessage (const shared_ptr &room) : Object(*new ChatMessagePrivate(room)) {} + d->chatRoom = chatRoom; + d->peerAddress = chatRoom->getPeerAddress(); +} shared_ptr ChatMessage::getChatRoom () const { L_D(); - return d->chatRoom; + + shared_ptr chatRoom = d->chatRoom.lock(); + if (!chatRoom) { + shared_ptr core = getCore(); + if (core) + chatRoom = core->getOrCreateBasicChatRoom(d->peerAddress); + } + + return chatRoom; } // ----------------------------------------------------------------------------- -const string& ChatMessage::getExternalBodyUrl() const { +const string &ChatMessage::getExternalBodyUrl () const { L_D(); return d->externalBodyUrl; } -void ChatMessage::setExternalBodyUrl(const string &url) { +void ChatMessage::setExternalBodyUrl (const string &url) { L_D(); d->externalBodyUrl = url; } @@ -1261,7 +1360,7 @@ bool ChatMessage::isSecured () const { return d->isSecured; } -void ChatMessage::setIsSecured(bool isSecured) { +void ChatMessage::setIsSecured (bool isSecured) { L_D(); d->isSecured = isSecured; } @@ -1271,32 +1370,42 @@ ChatMessage::Direction ChatMessage::getDirection () const { return d->direction; } -ChatMessage::State ChatMessage::getState() const { +ChatMessage::State ChatMessage::getState () const { L_D(); return d->state; } -const string& ChatMessage::getImdnMessageId () const { +const string &ChatMessage::getImdnMessageId () const { L_D(); return d->id; } -void ChatMessage::setImdnMessageId (const string& id) { +void ChatMessage::setImdnMessageId (const string &id) { L_D(); d->id = id; } -bool ChatMessage::isRead() const { - return false; +bool ChatMessage::isRead () const { L_D(); - LinphoneCore *lc = d->chatRoom->getCore(); - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); - if (linphone_im_notif_policy_get_recv_imdn_displayed(policy) && d->state == State::Displayed) return true; - if (linphone_im_notif_policy_get_recv_imdn_delivered(policy) && (d->state == State::DeliveredToUser || d->state == State::Displayed)) return true; + + shared_ptr core = getCore(); + if (!core) + return false; + + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(core->getCCore()); + if (linphone_im_notif_policy_get_recv_imdn_displayed(policy) && d->state == State::Displayed) + return true; + + if ( + linphone_im_notif_policy_get_recv_imdn_delivered(policy) && + (d->state == State::DeliveredToUser || d->state == State::Displayed) + ) + return true; + return d->state == State::Delivered || d->state == State::Displayed || d->state == State::DeliveredToUser; } -const string& ChatMessage::getAppdata () const { +const string &ChatMessage::getAppdata () const { L_D(); return d->appData; } @@ -1304,25 +1413,27 @@ const string& ChatMessage::getAppdata () const { void ChatMessage::setAppdata (const string &appData) { L_D(); d->appData = appData; - linphone_chat_message_store_appdata(L_GET_C_BACK_PTR(this)); + + // TODO: history. + // linphone_chat_message_store_appdata(L_GET_C_BACK_PTR(this)); } -const Address& ChatMessage::getFromAddress () const { +const Address &ChatMessage::getFromAddress () const { L_D(); return d->from; } -void ChatMessage::setFromAddress(Address from) { +void ChatMessage::setFromAddress (Address from) { L_D(); d->from = from; } -const Address& ChatMessage::getToAddress () const { +const Address &ChatMessage::getToAddress () const { L_D(); return d->to; } -void ChatMessage::setToAddress(Address to) { +void ChatMessage::setToAddress (Address to) { L_D(); d->to = to; } @@ -1335,21 +1446,21 @@ const Address &ChatMessage::getRemoteAddress () const { return getDirection() != Direction::Incoming ? getToAddress() : getFromAddress(); } -const string& ChatMessage::getFileTransferFilepath() const { +const string &ChatMessage::getFileTransferFilepath () const { L_D(); return d->fileTransferFilePath; } -void ChatMessage::setFileTransferFilepath(const string &path) { +void ChatMessage::setFileTransferFilepath (const string &path) { L_D(); d->fileTransferFilePath = path; } // ----------------------------------------------------------------------------- -const LinphoneErrorInfo * ChatMessage::getErrorInfo() const { +const LinphoneErrorInfo *ChatMessage::getErrorInfo () const { L_D(); - if (!d->errorInfo) d->errorInfo = linphone_error_info_new(); //let's do it mutable + if (!d->errorInfo) d->errorInfo = linphone_error_info_new(); // let's do it mutable linphone_error_info_from_sal_op(d->errorInfo, d->salOp); return d->errorInfo; } @@ -1359,7 +1470,7 @@ bool ChatMessage::isReadOnly () const { return d->isReadOnly; } -const list& ChatMessage::getContents () const { +const list &ChatMessage::getContents () const { L_D(); return d->contents; } @@ -1378,19 +1489,19 @@ void ChatMessage::addContent (const Content &content) { d->contents.push_back(content); } -void ChatMessage::removeContent (const Content& content) { +void ChatMessage::removeContent (const Content &content) { L_D(); if (d->isReadOnly) return; d->contents.remove(content); } -const Content& ChatMessage::getInternalContent() const { +const Content &ChatMessage::getInternalContent () const { L_D(); return d->internalContent; } -void ChatMessage::setInternalContent(const Content& content) { +void ChatMessage::setInternalContent (const Content &content) { L_D(); d->internalContent = content; } @@ -1421,80 +1532,98 @@ void ChatMessage::removeCustomHeader (const string &headerName) { // ----------------------------------------------------------------------------- -void ChatMessage::store() { +void ChatMessage::store () { L_D(); if (d->storageId != 0) { /* The message has already been stored (probably because of file transfer), update it */ - linphone_chat_message_store_update(L_GET_C_BACK_PTR(this)); + // TODO: history. + // linphone_chat_message_store_update(L_GET_C_BACK_PTR(this)); } else { /* Store the new message */ - linphone_chat_message_store(L_GET_C_BACK_PTR(this)); + // TODO: history. + // linphone_chat_message_store(L_GET_C_BACK_PTR(this)); } } -void ChatMessage::updateState(State state) { +void ChatMessage::updateState (State state) { L_D(); d->setState(state); - linphone_chat_message_store_state(L_GET_C_BACK_PTR(this)); + // TODO: history. + // linphone_chat_message_store_state(L_GET_C_BACK_PTR(this)); - if (state == State::Delivered || state == State::NotDelivered) - d->chatRoom->getPrivate()->moveTransientMessageToWeakMessages(getSharedFromThis()); + if (state == State::Delivered || state == State::NotDelivered) { + shared_ptr chatRoom = getChatRoom(); + if (chatRoom) + chatRoom->getPrivate()->moveTransientMessageToWeakMessages(getSharedFromThis()); + } } void ChatMessage::send () { L_D(); // Do not allow sending a message that is already being sent or that has been correctly delivered/displayed - if ((d->state == State::InProgress) || (d->state == State::Delivered) || (d->state == State::FileTransferDone) - || (d->state == State::DeliveredToUser) || (d->state == State::Displayed)) { + if ((d->state == State::InProgress) || (d->state == State::Delivered) || (d->state == State::FileTransferDone) || + (d->state == State::DeliveredToUser) || (d->state == State::Displayed)) { lWarning() << "Cannot send chat message in state " << linphone_chat_message_state_to_string((LinphoneChatMessageState)d->state); return; } - d->chatRoom->getPrivate()->sendMessage(getSharedFromThis()); + shared_ptr chatRoom = getChatRoom(); + if (chatRoom) + chatRoom->getPrivate()->sendMessage(getSharedFromThis()); } -void ChatMessage::sendDeliveryNotification(LinphoneReason reason) { +void ChatMessage::sendDeliveryNotification (LinphoneReason reason) { L_D(); - LinphoneCore *lc = d->chatRoom->getCore(); - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); - if (linphone_im_notif_policy_get_send_imdn_delivered(policy)) { + + shared_ptr core = getCore(); + if (!core) + return; + + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(core->getCCore()); + if (linphone_im_notif_policy_get_send_imdn_delivered(policy)) d->sendImdn(Imdn::Type::Delivery, reason); - } } -void ChatMessage::sendDisplayNotification() { +void ChatMessage::sendDisplayNotification () { L_D(); - LinphoneCore *lc = d->chatRoom->getCore(); - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); - if (linphone_im_notif_policy_get_send_imdn_displayed(policy)) { + + shared_ptr core = getCore(); + if (!core) + return; + + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(core->getCCore()); + if (linphone_im_notif_policy_get_send_imdn_displayed(policy)) d->sendImdn(Imdn::Type::Display, LinphoneReasonNone); - } } -int ChatMessage::uploadFile() { +int ChatMessage::uploadFile () { L_D(); + shared_ptr core = getCore(); + if (!core) + return -1; + if (d->httpRequest) { lError() << "linphone_chat_room_upload_file(): there is already an upload in progress."; return -1; } - belle_http_request_listener_callbacks_t cbs = {0}; + belle_http_request_listener_callbacks_t cbs = { 0 }; cbs.process_response = _chat_message_process_response_from_post_file; cbs.process_io_error = _chat_message_process_io_error_upload; cbs.process_auth_requested = _chat_message_process_auth_requested_upload; - int err = d->startHttpTransfer(linphone_core_get_file_transfer_server(d->chatRoom->getCore()), "POST", &cbs); - if (err == -1) { + int err = d->startHttpTransfer(linphone_core_get_file_transfer_server(core->getCCore()), "POST", &cbs); + if (err == -1) d->setState(State::NotDelivered); - } + return err; } -int ChatMessage::downloadFile() { +int ChatMessage::downloadFile () { L_D(); if (d->httpRequest) { @@ -1502,7 +1631,7 @@ int ChatMessage::downloadFile() { return -1; } - belle_http_request_listener_callbacks_t cbs = {0}; + belle_http_request_listener_callbacks_t cbs = { 0 }; cbs.process_response_headers = _chat_process_response_headers_from_get_file; cbs.process_response = _chat_message_process_response_from_get_file; cbs.process_io_error = _chat_message_process_io_error_download; @@ -1515,16 +1644,22 @@ int ChatMessage::downloadFile() { return 0; } -void ChatMessage::cancelFileTransfer() { +void ChatMessage::cancelFileTransfer () { L_D(); if (d->httpRequest) { if (d->state == State::InProgress) { d->setState(State::NotDelivered); } if (!belle_http_request_is_cancelled(d->httpRequest)) { - if (d->chatRoom) { - lInfo() << "Canceling file transfer " << (d->externalBodyUrl.empty() ? linphone_core_get_file_transfer_server(d->chatRoom->getCore()) : d->externalBodyUrl.c_str()); - belle_http_provider_cancel_request(d->chatRoom->getCore()->http_provider, d->httpRequest); + shared_ptr chatRoom = getChatRoom(); + shared_ptr core = getCore(); + if (chatRoom && core) { + lInfo() << "Canceling file transfer " << ( + d->externalBodyUrl.empty() + ? linphone_core_get_file_transfer_server(core->getCCore()) + : d->externalBodyUrl.c_str() + ); + belle_http_provider_cancel_request(core->getCCore()->http_provider, d->httpRequest); } else { lInfo() << "Warning: http request still running for ORPHAN msg: this is a memory leak"; } @@ -1535,39 +1670,53 @@ void ChatMessage::cancelFileTransfer() { } } -int ChatMessage::putCharacter(uint32_t character) { +int ChatMessage::putCharacter (uint32_t character) { L_D(); - LinphoneCore *lc = d->chatRoom->getCore(); - if (linphone_core_realtime_text_enabled(lc)) { - shared_ptr rttcr = - static_pointer_cast(d->chatRoom); - LinphoneCall *call = rttcr->getCall(); - const uint32_t new_line = 0x2028; - const uint32_t crlf = 0x0D0A; - const uint32_t lf = 0x0A; - if (!call || !linphone_call_get_stream(call, LinphoneStreamTypeText)) { + shared_ptr core = getCore(); + if (!core) + return -1; + + if (linphone_core_realtime_text_enabled(core->getCCore())) { + static const uint32_t new_line = 0x2028; + static const uint32_t crlf = 0x0D0A; + static const uint32_t lf = 0x0A; + + shared_ptr chatRoom = getChatRoom(); + if (!chatRoom) + return -1; + + shared_ptr rttcr = + static_pointer_cast(chatRoom); + LinphoneCall *call = rttcr->getCall(); + + if (!call || !linphone_call_get_stream(call, LinphoneStreamTypeText)) return -1; - } if (character == new_line || character == crlf || character == lf) { - if (lc && lp_config_get_int(lc->config, "misc", "store_rtt_messages", 1) == 1) { + if (lp_config_get_int(core->getCCore()->config, "misc", "store_rtt_messages", 1) == 1) { lDebug() << "New line sent, forge a message with content " << d->rttMessage.c_str(); d->setTime(ms_time(0)); d->state = State::Displayed; d->direction = Direction::Outgoing; - setFromAddress(LinphonePrivate::Address(linphone_address_as_string(linphone_address_new(linphone_core_get_identity(lc))))); - linphone_chat_message_store(L_GET_C_BACK_PTR(this)); + setFromAddress(LinphonePrivate::Address( + linphone_address_as_string(linphone_address_new(linphone_core_get_identity(core->getCCore()))) + )); + // TODO: History. + // linphone_chat_message_store(L_GET_C_BACK_PTR(this)); d->rttMessage = ""; } } else { char *value = LinphonePrivate::Utils::utf8ToChar(character); d->rttMessage = d->rttMessage + string(value); - lDebug() << "Sent RTT character: " << value << "(" << (unsigned long)character << "), pending text is " << d->rttMessage.c_str(); + lDebug() << "Sent RTT character: " << value << "(" << (unsigned long)character << + "), pending text is " << d->rttMessage.c_str(); delete value; } - text_stream_putchar32(reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeText)), character); + text_stream_putchar32(reinterpret_cast( + linphone_call_get_stream(call, LinphoneStreamTypeText)), character + ); return 0; } return -1; diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index 76ae99890..cb2742fc6 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -25,6 +25,7 @@ #include "linphone/api/c-types.h" #include "linphone/enums/chat-message-enums.h" +#include "core/core-accessor.h" #include "object/object.h" // ============================================================================= @@ -36,7 +37,7 @@ class ChatRoom; class Content; class ChatMessagePrivate; -class LINPHONE_PUBLIC ChatMessage : public Object { +class LINPHONE_PUBLIC ChatMessage : public Object, public CoreAccessor { friend class ChatRoom; friend class ChatRoomPrivate; friend class CpimChatMessageModifier; @@ -49,6 +50,7 @@ public: L_DECLARE_ENUM(State, L_ENUM_VALUES_CHAT_MESSAGE_STATE); L_DECLARE_ENUM(Direction, L_ENUM_VALUES_CHAT_MESSAGE_DIRECTION); + // TODO: Make me private. ChatMessage (const std::shared_ptr &chatRoom); // ----- TODO: Remove me. diff --git a/src/chat/chat-room/basic-chat-room-p.h b/src/chat/chat-room/basic-chat-room-p.h index 12b4b986b..a6103d172 100644 --- a/src/chat/chat-room/basic-chat-room-p.h +++ b/src/chat/chat-room/basic-chat-room-p.h @@ -29,8 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class BasicChatRoomPrivate : public ChatRoomPrivate { public: - BasicChatRoomPrivate (LinphoneCore *core, const Address &peerAddress); - virtual ~BasicChatRoomPrivate () = default; + BasicChatRoomPrivate () = default; private: std::string subject; diff --git a/src/chat/chat-room/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp index c07afa0af..bb602f9c6 100644 --- a/src/chat/chat-room/basic-chat-room.cpp +++ b/src/chat/chat-room/basic-chat-room.cpp @@ -29,14 +29,8 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -BasicChatRoomPrivate::BasicChatRoomPrivate (LinphoneCore *core, const Address &peerAddress) : ChatRoomPrivate(core) { - this->peerAddress = peerAddress; -} - -// ============================================================================= - -BasicChatRoom::BasicChatRoom (LinphoneCore *core, const Address &peerAddress) : - ChatRoom(*new BasicChatRoomPrivate(core, peerAddress)) {} +BasicChatRoom::BasicChatRoom (const shared_ptr &core, const Address &peerAddress) : + ChatRoom(*new BasicChatRoomPrivate, core, peerAddress) {} // ----------------------------------------------------------------------------- diff --git a/src/chat/chat-room/basic-chat-room.h b/src/chat/chat-room/basic-chat-room.h index 56906844b..402ce990f 100644 --- a/src/chat/chat-room/basic-chat-room.h +++ b/src/chat/chat-room/basic-chat-room.h @@ -30,8 +30,7 @@ class BasicChatRoomPrivate; class LINPHONE_PUBLIC BasicChatRoom : public ChatRoom { public: - BasicChatRoom (LinphoneCore *core, const Address &peerAddress); - virtual ~BasicChatRoom () = default; + BasicChatRoom (const std::shared_ptr &core, const Address &peerAddress); CapabilitiesMask getCapabilities () const override; diff --git a/src/chat/chat-room/chat-room-p.h b/src/chat/chat-room/chat-room-p.h index 069814e53..1c4513389 100644 --- a/src/chat/chat-room/chat-room-p.h +++ b/src/chat/chat-room/chat-room-p.h @@ -34,8 +34,7 @@ class ChatRoomPrivate : public ObjectPrivate, public IsComposingListener { friend class ChatMessagePrivate; public: - ChatRoomPrivate (LinphoneCore *core); - virtual ~ChatRoomPrivate (); + ChatRoomPrivate () = default; private: static int createChatMessageFromDb (void *data, int argc, char **argv, char **colName); @@ -53,7 +52,6 @@ public: void release (); void sendImdn (const std::string &content, LinphoneReason reason); - int getMessagesCount (bool unreadOnly); void setState (ChatRoom::State newState); virtual void sendMessage (const std::shared_ptr &msg); @@ -64,8 +62,6 @@ protected: int createChatMessageFromDb (int argc, char **argv, char **colName); std::shared_ptr getTransientMessage (unsigned int storageId) const; std::shared_ptr getWeakMessage (unsigned int storageId) const; - int sqlRequest (sqlite3 *db, const std::string &stmt); - void sqlRequestMessage (sqlite3 *db, const std::string &stmt); std::list> findMessages (const std::string &messageId); virtual void storeOrUpdateMessage (const std::shared_ptr &msg); @@ -91,18 +87,20 @@ private: void onIsComposingRefreshNeeded () override; public: - LinphoneCore *core = nullptr; LinphoneCall *call = nullptr; ChatRoom::State state = ChatRoom::State::None; Address peerAddress; - int unreadCount = -1; bool isComposing = false; std::unordered_set remoteIsComposing; - std::list> messages; std::list> transientMessages; + std::list> weakMessages; + + // TODO: Remove me. Must be present only in rtt chat room. std::shared_ptr pendingMessage; - IsComposing isComposingHandler; + + // TODO: Use CoreAccessor on IsComposing. And avoid pointer if possible. + std::unique_ptr isComposingHandler; private: L_DECLARE_PUBLIC(ChatRoom); diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 4553bff2f..96401619d 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -25,6 +25,7 @@ #include "chat/chat-room/chat-room-p.h" #include "chat/notification/imdn.h" #include "logger/logger.h" +#include "core/core-p.h" // ============================================================================= @@ -32,11 +33,6 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ChatRoomPrivate::ChatRoomPrivate (LinphoneCore *core) - : core(core), isComposingHandler(core, this) {} - -ChatRoomPrivate::~ChatRoomPrivate () {} - // ----------------------------------------------------------------------------- int ChatRoomPrivate::createChatMessageFromDb (void *data, int argc, char **argv, char **colName) { @@ -79,38 +75,44 @@ void ChatRoomPrivate::removeTransientMessage (const shared_ptr &msg void ChatRoomPrivate::release () { L_Q(); - isComposingHandler.stopTimers(); + isComposingHandler->stopTimers(); + // TODO: Remove me? + // Why chat room is set to nullptr? Avoid shared ptr lock?! Wtf?! for (auto &message : weakMessages) { try { shared_ptr msg(message); msg->cancelFileTransfer(); msg->getPrivate()->setChatRoom(nullptr); - } catch(const std::bad_weak_ptr& e) {} + } catch (const bad_weak_ptr &) {} } for (auto &message : transientMessages) { message->cancelFileTransfer(); message->getPrivate()->setChatRoom(nullptr); } - core = nullptr; linphone_chat_room_unref(L_GET_C_BACK_PTR(q)); } void ChatRoomPrivate::sendImdn (const string &payload, LinphoneReason reason) { L_Q(); + shared_ptr core = q->getCore(); + if (!core) + return; + LinphoneCore *cCore = core->getCCore(); + const char *identity = nullptr; LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str()); - LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core, peer); + LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(cCore, peer); if (proxy) identity = linphone_address_as_string(linphone_proxy_config_get_identity_address(proxy)); else - identity = linphone_core_get_primary_contact(core); + identity = linphone_core_get_primary_contact(cCore); /* Sending out of call */ - SalMessageOp *op = new SalMessageOp(core->sal); - linphone_configure_op(core, op, peer, nullptr, !!lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0)); + SalMessageOp *op = new SalMessageOp(cCore->sal); + linphone_configure_op(cCore, op, peer, nullptr, !!lp_config_get_int(cCore->config, "sip", "chat_msg_with_contact", 0)); shared_ptr msg = q->createMessage(); msg->setFromAddress(Address(identity)); @@ -123,7 +125,7 @@ void ChatRoomPrivate::sendImdn (const string &payload, LinphoneReason reason) { /* Do not try to encrypt the notification when it is reporting an error (maybe it should be bypassed only for some reasons). */ int retval = -1; - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(core); + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(cCore); if (imee && (reason == LinphoneReasonNone)) { LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); @@ -142,42 +144,12 @@ void ChatRoomPrivate::sendImdn (const string &payload, LinphoneReason reason) { // ----------------------------------------------------------------------------- -int ChatRoomPrivate::getMessagesCount (bool unreadOnly) { - if (!core->db) return 0; - - /* Optimization: do not read database if the count is already available in memory */ - if (unreadOnly && unreadCount >= 0) return unreadCount; - - string peer = peerAddress.asStringUriOnly(); - char *option = nullptr; - if (unreadOnly) - option = bctbx_strdup_printf("AND status!=%i AND direction=%i", LinphoneChatMessageStateDisplayed, LinphoneChatMessageIncoming); - char *buf = sqlite3_mprintf("SELECT count(*) FROM history WHERE remoteContact = %Q %s;", peer.c_str(), unreadOnly ? option : ""); - sqlite3_stmt *selectStatement; - int numrows = 0; - int returnValue = sqlite3_prepare_v2(core->db, buf, -1, &selectStatement, nullptr); - if (returnValue == SQLITE_OK) { - if (sqlite3_step(selectStatement) == SQLITE_ROW) { - numrows = sqlite3_column_int(selectStatement, 0); - } - } - sqlite3_finalize(selectStatement); - sqlite3_free(buf); - - /* No need to test the sign of unreadCount here because it has been tested above */ - if (unreadOnly) { - unreadCount = numrows; - } - if (option) bctbx_free(option); - return numrows; -} - void ChatRoomPrivate::setState (ChatRoom::State newState) { L_Q(); if (newState != state) { state = newState; if (state == ChatRoom::State::Instantiated) - linphone_core_notify_chat_room_instantiated(core, L_GET_C_BACK_PTR(q)); + linphone_core_notify_chat_room_instantiated(q->getCore()->getCCore(), L_GET_C_BACK_PTR(q)); notifyStateChanged(); } } @@ -186,9 +158,9 @@ void ChatRoomPrivate::setState (ChatRoom::State newState) { void ChatRoomPrivate::sendIsComposingNotification () { L_Q(); - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(core); + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(q->getCore()->getCCore()); if (linphone_im_notif_policy_get_send_is_composing(policy)) { - string payload = isComposingHandler.marshal(isComposing); + string payload = isComposingHandler->marshal(isComposing); if (!payload.empty()) { shared_ptr msg = q->createMessage(); Content content; @@ -222,72 +194,7 @@ void ChatRoomPrivate::sendIsComposingNotification () { * | 14 | secured flag */ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colName) { - L_Q(); - unsigned int storageId = (unsigned int)atoi(argv[0]); - - /* Check if the message exists in the weak messages list, in which case we should return that one. */ - shared_ptr message = getWeakMessage(storageId); - if (!message) { - /* Check if the message exists in the transient list, in which case we should return that one. */ - message = getTransientMessage(storageId); - } - if (!message) { - message = q->createMessage(); - - Content content; - if (argv[4]) { - content.setBody(argv[4]); - } - if (argv[13]) { - content.setContentType(argv[13]); - } - message->addContent(content); - - Address peer(peerAddress.asString()); - if (atoi(argv[3]) == static_cast(ChatMessage::Direction::Incoming)) { - message->getPrivate()->setDirection(ChatMessage::Direction::Incoming); - message->setFromAddress(peer); - } else { - message->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); - message->setToAddress(peer); - } - - message->getPrivate()->setTime((time_t)atol(argv[9])); - message->getPrivate()->setState((ChatMessage::State)atoi(argv[7])); - message->getPrivate()->setStorageId(storageId); - if (argv[8]) { - message->setExternalBodyUrl(argv[8]); - } - if (argv[10]) { - message->setAppdata(argv[10]); - } - if (argv[12]) { - message->setImdnMessageId(argv[12]); - } - message->setIsSecured((bool)atoi(argv[14])); - - if (argv[11]) { - int id = atoi(argv[11]); - if (id >= 0) - linphone_chat_message_fetch_content_from_database(core->db, L_GET_C_BACK_PTR(message), id); - } - - /* Fix content type for old messages that were stored without it */ - /* To keep ? - if (message->getPrivate()->getContentType().empty()) { - if (message->getPrivate()->getFileTransferInformation()) { - message->getPrivate()->setContentType("application/vnd.gsma.rcs-ft-http+xml"); - } else if (!message->getExternalBodyUrl().empty()) { - message->getPrivate()->setContentType("message/external-body"); - } else { - message->getPrivate()->setContentType("text/plain"); - } - }*/ - - /* Add the new message to the weak messages list. */ - addWeakMessage(message); - } - messages.push_front(message); + // TODO: history. return 0; } @@ -310,36 +217,9 @@ std::shared_ptr ChatRoomPrivate::getWeakMessage (unsigned int stora return nullptr; } -int ChatRoomPrivate::sqlRequest (sqlite3 *db, const string &stmt) { - char *errmsg = nullptr; - int ret = sqlite3_exec(db, stmt.c_str(), nullptr, nullptr, &errmsg); - if (ret != SQLITE_OK) { - lError() << "ChatRoomPrivate::sqlRequest: statement " << stmt << " -> error sqlite3_exec(): " << errmsg; - sqlite3_free(errmsg); - } - return ret; -} - -void ChatRoomPrivate::sqlRequestMessage (sqlite3 *db, const string &stmt) { - char *errmsg = nullptr; - int ret = sqlite3_exec(db, stmt.c_str(), createChatMessageFromDb, this, &errmsg); - if (ret != SQLITE_OK) { - lError() << "Error in creation: " << errmsg; - sqlite3_free(errmsg); - } -} - list > ChatRoomPrivate::findMessages (const string &messageId) { - if (!core->db) - return list >(); - string peer = peerAddress.asStringUriOnly(); - char *buf = sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q AND messageId = %Q", peer.c_str(), messageId.c_str()); - messages.clear(); - sqlRequestMessage(core->db, buf); - sqlite3_free(buf); - list > result = messages; - messages.clear(); - return result; + // TODO: history. + return list>(); } void ChatRoomPrivate::storeOrUpdateMessage (const shared_ptr &msg) { @@ -369,8 +249,8 @@ void ChatRoomPrivate::sendMessage (const shared_ptr &msg) { if (isComposing) isComposing = false; - isComposingHandler.stopIdleTimer(); - isComposingHandler.stopRefreshTimer(); + isComposingHandler->stopIdleTimer(); + isComposingHandler->stopRefreshTimer(); } // ----------------------------------------------------------------------------- @@ -382,6 +262,11 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa LinphoneReason reason = LinphoneReasonNone; shared_ptr msg; + shared_ptr core = q->getCore(); + if (!core) + return reason; + LinphoneCore *cCore = core->getCCore(); + msg = q->createMessage(); Content content; @@ -389,7 +274,7 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa content.setBody(salMsg->text ? salMsg->text : ""); msg->setInternalContent(content); - msg->setToAddress(Address(op->get_to() ? op->get_to() : linphone_core_get_identity(core))); + msg->setToAddress(Address(op->get_to() ? op->get_to() : linphone_core_get_identity(cCore))); msg->setFromAddress(peerAddress); msg->getPrivate()->setTime(salMsg->time); msg->getPrivate()->setState(ChatMessage::State::Delivered); @@ -413,22 +298,18 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa if (msg->getPrivate()->getContentType() == ContentType::ImIsComposing) { isComposingReceived(msg->getFromAddress(), msg->getPrivate()->getText()); increaseMsgCount = FALSE; - if (lp_config_get_int(core->config, "sip", "deliver_imdn", 0) != 1) { + if (lp_config_get_int(cCore->config, "sip", "deliver_imdn", 0) != 1) { goto end; } } else if (msg->getPrivate()->getContentType() == ContentType::Imdn) { imdnReceived(msg->getPrivate()->getText()); increaseMsgCount = FALSE; - if (lp_config_get_int(core->config, "sip", "deliver_imdn", 0) != 1) { + if (lp_config_get_int(cCore->config, "sip", "deliver_imdn", 0) != 1) { goto end; } } if (increaseMsgCount) { - if (unreadCount < 0) - unreadCount = 1; - else - unreadCount++; /* Mark the message as pending so that if ChatRoom::markAsRead() is called in the * ChatRoomPrivate::chatMessageReceived() callback, it will effectively be marked as * being read before being stored. */ @@ -462,7 +343,7 @@ void ChatRoomPrivate::chatMessageReceived (const shared_ptr &msg) { notifyChatMessageReceived(msg); remoteIsComposing.erase(msg->getFromAddress().asStringUriOnly()); - isComposingHandler.stopRemoteRefreshTimer(msg->getFromAddress().asStringUriOnly()); + isComposingHandler->stopRemoteRefreshTimer(msg->getFromAddress().asStringUriOnly()); notifyIsComposingReceived(msg->getFromAddress(), false); msg->sendDeliveryNotification(LinphoneReasonNone); } @@ -474,7 +355,7 @@ void ChatRoomPrivate::imdnReceived (const string &text) { } void ChatRoomPrivate::isComposingReceived (const Address &remoteAddr, const string &text) { - isComposingHandler.parse(remoteAddr, text); + isComposingHandler->parse(remoteAddr, text); } // ----------------------------------------------------------------------------- @@ -484,13 +365,18 @@ void ChatRoomPrivate::notifyChatMessageReceived (const shared_ptr & LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); if (!msg->getPrivate()->getText().empty()) { /* Legacy API */ - linphone_core_notify_text_message_received(core, cr, L_GET_C_BACK_PTR(&msg->getFromAddress()), msg->getPrivate()->getText().c_str()); + linphone_core_notify_text_message_received( + q->getCore()->getCCore(), + cr, + L_GET_C_BACK_PTR(&msg->getFromAddress()), + msg->getPrivate()->getText().c_str() + ); } LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsMessageReceivedCb cb = linphone_chat_room_cbs_get_message_received(cbs); if (cb) cb(cr, L_GET_C_BACK_PTR(msg)); - linphone_core_notify_message_received(core, cr, L_GET_C_BACK_PTR(msg)); + linphone_core_notify_message_received(q->getCore()->getCCore(), cr, L_GET_C_BACK_PTR(msg)); } void ChatRoomPrivate::notifyIsComposingReceived (const Address &remoteAddr, bool isComposing) { @@ -504,7 +390,7 @@ void ChatRoomPrivate::notifyIsComposingReceived (const Address &remoteAddr, bool linphone_address_unref(lAddr); } // Legacy notification - linphone_core_notify_is_composing_received(core, cr); + linphone_core_notify_is_composing_received(q->getCore()->getCCore(), cr); } void ChatRoomPrivate::notifyStateChanged () { @@ -523,7 +409,7 @@ void ChatRoomPrivate::notifyUndecryptableMessageReceived (const shared_ptrgetCore()->getCCore(), cr, L_GET_C_BACK_PTR(msg)); } // ----------------------------------------------------------------------------- @@ -547,7 +433,15 @@ void ChatRoomPrivate::onIsComposingRefreshNeeded () { // ============================================================================= -ChatRoom::ChatRoom (ChatRoomPrivate &p) : Object(p) {} +ChatRoom::ChatRoom ( + ChatRoomPrivate &p, + const shared_ptr &core, + const Address &peerAddress +) : Object(p), CoreAccessor(core) { + L_D(); + d->peerAddress = peerAddress; + d->isComposingHandler.reset(new IsComposing(core->getCCore(), d)); +} // ----------------------------------------------------------------------------- @@ -556,9 +450,9 @@ void ChatRoom::compose () { if (!d->isComposing) { d->isComposing = true; d->sendIsComposingNotification(); - d->isComposingHandler.startRefreshTimer(); + d->isComposingHandler->startRefreshTimer(); } - d->isComposingHandler.startIdleTimer(); + d->isComposingHandler->startIdleTimer(); } shared_ptr ChatRoom::createFileTransferMessage (const LinphoneContent *initialContent) { @@ -588,31 +482,17 @@ shared_ptr ChatRoom::createMessage () { L_D(); shared_ptr chatMessage = ObjectFactory::create(getSharedFromThis()); chatMessage->setToAddress(d->peerAddress); - chatMessage->setFromAddress(Address(linphone_core_get_identity(d->core))); + chatMessage->setFromAddress(Address(linphone_core_get_identity(getCore()->getCCore()))); chatMessage->getPrivate()->setTime(ms_time(0)); return chatMessage; } void ChatRoom::deleteHistory () { - L_D(); - if (!d->core->db) return; - string peer = d->peerAddress.asStringUriOnly(); - char *buf = sqlite3_mprintf("DELETE FROM history WHERE remoteContact = %Q;", peer.c_str()); - d->sqlRequest(d->core->db, buf); - sqlite3_free(buf); - if (d->unreadCount > 0) d->unreadCount = 0; + // TODO: history. } void ChatRoom::deleteMessage (const shared_ptr &msg) { - L_D(); - if (!d->core->db) return; - char *buf = sqlite3_mprintf("DELETE FROM history WHERE id = %u;", msg->getPrivate()->getStorageId()); - d->sqlRequest(d->core->db, buf); - sqlite3_free(buf); - - /* Invalidate unread_count when we modify the database, so that next - time we need it it will be recomputed from latest database state */ - d->unreadCount = -1; + // TODO: history. } shared_ptr ChatRoom::findMessage (const string &messageId) { @@ -644,66 +524,19 @@ list > ChatRoom::getHistory (int nbMessages) { int ChatRoom::getHistorySize () { L_D(); - return d->getMessagesCount(false); + shared_ptr core = getCore(); + return core ? core->getPrivate()->mainDb->getChatMessagesCount(d->peerAddress.asStringUriOnly()) : 0; } list > ChatRoom::getHistoryRange (int startm, int endm) { - L_D(); - if (!d->core->db) return list >(); - string peer = d->peerAddress.asStringUriOnly(); - d->messages.clear(); - - /* Since we want to append query parameters depending on arguments given, we use malloc instead of sqlite3_mprintf */ - const int bufMaxSize = 512; - char *buf = reinterpret_cast(ms_malloc(bufMaxSize)); - buf = sqlite3_snprintf(bufMaxSize - 1, buf, "SELECT * FROM history WHERE remoteContact = %Q ORDER BY id DESC", peer.c_str()); - - if (startm < 0) startm = 0; - if (((endm > 0) && (endm >= startm)) || ((startm == 0) && (endm == 0))) { - char *buf2 = ms_strdup_printf("%s LIMIT %i ", buf, endm + 1 - startm); - ms_free(buf); - buf = buf2; - } else if (startm > 0) { - lInfo() << __FUNCTION__ << "(): end is lower than start (" << endm << " < " << startm << "). Assuming no end limit."; - char *buf2 = ms_strdup_printf("%s LIMIT -1", buf); - ms_free(buf); - buf = buf2; - } - if (startm > 0) { - char *buf2 = ms_strdup_printf("%s OFFSET %i ", buf, startm); - ms_free(buf); - buf = buf2; - } - - uint64_t begin = ortp_get_cur_time_ms(); - d->sqlRequestMessage(d->core->db, buf); - uint64_t end = ortp_get_cur_time_ms(); - - if ((endm + 1 - startm) > 1) { - /* Display message only if at least 2 messages are loaded */ - lInfo() << __FUNCTION__ << "(): completed in " << (int)(end - begin) << " ms"; - } - ms_free(buf); - - if (!d->messages.empty()) { - /* Fill local addr with core identity instead of per message */ - for (auto &message : d->messages) { - if (message->getDirection() == ChatMessage::Direction::Outgoing) { - message->setFromAddress(Address(linphone_core_get_identity(d->core))); - } else { - message->setToAddress(Address(linphone_core_get_identity(d->core))); - } - } - } - - list > result = d->messages; - d->messages.clear(); - return result; + // TODO: history. + return list>(); } -int ChatRoom::getUnreadMessagesCount () { +int ChatRoom::getUnreadChatMessagesCount () { L_D(); - return d->getMessagesCount(true); + shared_ptr core = getCore(); + return core ? core->getPrivate()->mainDb->getUnreadChatMessagesCount(d->peerAddress.asStringUriOnly()) : 0; } bool ChatRoom::isRemoteComposing () const { @@ -714,36 +547,21 @@ bool ChatRoom::isRemoteComposing () const { void ChatRoom::markAsRead () { L_D(); - if (!d->core->db) return; + if (getUnreadChatMessagesCount() == 0) + return; - /* Optimization: do not modify the database if no message is marked as unread */ - if (getUnreadMessagesCount() == 0) return; + shared_ptr core = getCore(); + if (!core) + return; - string peer = d->peerAddress.asStringUriOnly(); - char *buf = sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q AND direction = %i AND status != %i", peer.c_str(), ChatMessage::Direction::Incoming, ChatMessage::State::Displayed); - d->sqlRequestMessage(d->core->db, buf); - sqlite3_free(buf); - for (auto &message : d->messages) { - message->sendDisplayNotification(); - } - d->messages.clear(); - buf = sqlite3_mprintf("UPDATE history SET status=%i WHERE remoteContact=%Q AND direction=%i;", ChatMessage::State::Displayed, peer.c_str(), ChatMessage::Direction::Incoming); - d->sqlRequest(d->core->db, buf); - sqlite3_free(buf); + CorePrivate *dCore = core->getPrivate(); + const string peerAddress = d->peerAddress.asStringUriOnly(); + list> chatMessages = dCore->mainDb->getUnreadChatMessages(peerAddress); - if (d->pendingMessage) { - d->pendingMessage->updateState(ChatMessage::State::Displayed); - d->pendingMessage->sendDisplayNotification(); - } + for (auto &chatMessage : chatMessages) + chatMessage->sendDisplayNotification(); - d->unreadCount = 0; -} - -// ----------------------------------------------------------------------------- - -LinphoneCore *ChatRoom::getCore () const { - L_D(); - return d->core; + dCore->mainDb->markChatMessagesAsRead(peerAddress); } // ----------------------------------------------------------------------------- diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index b0e29e3ef..db5c1d4c8 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -22,6 +22,7 @@ #include "chat/chat-message/chat-message.h" #include "conference/conference-interface.h" +#include "core/core-accessor.h" // ============================================================================= @@ -29,7 +30,7 @@ LINPHONE_BEGIN_NAMESPACE class ChatRoomPrivate; -class LINPHONE_PUBLIC ChatRoom : public Object, public ConferenceInterface { +class LINPHONE_PUBLIC ChatRoom : public Object, public CoreAccessor, public ConferenceInterface { friend class Core; friend class CorePrivate; friend class ChatMessage; @@ -58,18 +59,18 @@ public: std::list> getHistory (int nbMessages); int getHistorySize (); std::list> getHistoryRange (int startm, int endm); - int getUnreadMessagesCount (); + int getUnreadChatMessagesCount (); bool isRemoteComposing () const; - void markAsRead (); - LinphoneCore *getCore () const; + virtual void markAsRead (); const Address &getPeerAddress () const; State getState () const; protected: + explicit ChatRoom (ChatRoomPrivate &p, const std::shared_ptr &core, const Address &address); + virtual void onChatMessageReceived (const std::shared_ptr &msg) = 0; - explicit ChatRoom (ChatRoomPrivate &p); private: L_DECLARE_PRIVATE(ChatRoom); diff --git a/src/chat/chat-room/client-group-chat-room-p.h b/src/chat/chat-room/client-group-chat-room-p.h index ef874027d..3eeb5ae47 100644 --- a/src/chat/chat-room/client-group-chat-room-p.h +++ b/src/chat/chat-room/client-group-chat-room-p.h @@ -29,8 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class ClientGroupChatRoomPrivate : public ChatRoomPrivate { public: - ClientGroupChatRoomPrivate (LinphoneCore *core); - virtual ~ClientGroupChatRoomPrivate () = default; + ClientGroupChatRoomPrivate () = default; std::shared_ptr createSession (); void notifyReceived (std::string body); diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index e47f34fba..7b0e25656 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -37,8 +37,6 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core) : ChatRoomPrivate(core) {} - // ----------------------------------------------------------------------------- shared_ptr ClientGroupChatRoomPrivate::createSession () { @@ -68,11 +66,11 @@ void ClientGroupChatRoomPrivate::notifyReceived (string body) { // ============================================================================= ClientGroupChatRoom::ClientGroupChatRoom ( - LinphoneCore *core, + const std::shared_ptr &core, const Address &me, - const string &uri, - const string &subject -) : ChatRoom(*new ClientGroupChatRoomPrivate(core)), RemoteConference(core, me, nullptr) { + const std::string &uri, + const std::string &subject +) : ChatRoom(*new ClientGroupChatRoomPrivate, core, me), RemoteConference(core->getCCore(), me, nullptr) { L_D_T(RemoteConference, dConference); dConference->focus = ObjectFactory::create(Address(uri)); RemoteConference::setSubject(subject); @@ -178,10 +176,11 @@ void ClientGroupChatRoom::leave () { } void ClientGroupChatRoom::removeParticipant (const shared_ptr &participant) { - L_D(); - SalReferOp *referOp = new SalReferOp(d->core->sal); + LinphoneCore *cCore = CoreAccessor::getCore()->getCCore(); + + SalReferOp *referOp = new SalReferOp(cCore->sal); LinphoneAddress *lAddr = linphone_address_new(getConferenceAddress().asString().c_str()); - linphone_configure_op(d->core, referOp, lAddr, nullptr, false); + linphone_configure_op(cCore, referOp, lAddr, nullptr, false); linphone_address_unref(lAddr); Address referToAddr = participant->getAddress(); referToAddr.setParam("text"); @@ -197,8 +196,6 @@ void ClientGroupChatRoom::removeParticipants (const list } void ClientGroupChatRoom::setParticipantAdminStatus (shared_ptr &participant, bool isAdmin) { - L_D(); - if (isAdmin == participant->isAdmin()) return; @@ -207,9 +204,11 @@ void ClientGroupChatRoom::setParticipantAdminStatus (shared_ptr &pa return; } - SalReferOp *referOp = new SalReferOp(d->core->sal); + LinphoneCore *cCore = CoreAccessor::getCore()->getCCore(); + + SalReferOp *referOp = new SalReferOp(cCore->sal); LinphoneAddress *lAddr = linphone_address_new(getConferenceAddress().asString().c_str()); - linphone_configure_op(d->core, referOp, lAddr, nullptr, false); + linphone_configure_op(cCore, referOp, lAddr, nullptr, false); linphone_address_unref(lAddr); Address referToAddr = participant->getAddress(); referToAddr.setParam("text"); @@ -246,7 +245,7 @@ void ClientGroupChatRoom::setSubject (const string &subject) { // ----------------------------------------------------------------------------- void ClientGroupChatRoom::onChatMessageReceived (const shared_ptr &msg) { - + } void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { @@ -254,9 +253,9 @@ void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { L_D_T(RemoteConference, dConference); dConference->conferenceAddress = addr; d->peerAddress = addr; - d->core->cppCore->getPrivate()->insertChatRoom(getSharedFromThis()); + CoreAccessor::getCore()->getPrivate()->insertChatRoom(getSharedFromThis()); d->setState(ChatRoom::State::Created); - d->core->cppCore->getPrivate()->insertChatRoomWithDb(getSharedFromThis()); + CoreAccessor::getCore()->getPrivate()->insertChatRoomWithDb(getSharedFromThis()); } void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index c5d9396b1..7ff063a27 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -31,8 +31,13 @@ class ClientGroupChatRoomPrivate; class LINPHONE_PUBLIC ClientGroupChatRoom : public ChatRoom, public RemoteConference { public: - ClientGroupChatRoom (LinphoneCore *core, const Address &me, const std::string &uri, const std::string &subject); - virtual ~ClientGroupChatRoom () = default; + // TODO: Make me private. + ClientGroupChatRoom ( + const std::shared_ptr &core, + const Address &me, + const std::string &uri, + const std::string &subject + ); CapabilitiesMask getCapabilities () const override; @@ -52,7 +57,7 @@ public: void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) override; void setSubject (const std::string &subject) override; -private: +protected: void onChatMessageReceived (const std::shared_ptr &msg) override; private: diff --git a/src/chat/chat-room/real-time-text-chat-room-p.h b/src/chat/chat-room/real-time-text-chat-room-p.h index e99f3b8ad..91c2a9cbb 100644 --- a/src/chat/chat-room/real-time-text-chat-room-p.h +++ b/src/chat/chat-room/real-time-text-chat-room-p.h @@ -29,8 +29,8 @@ LINPHONE_BEGIN_NAMESPACE class RealTimeTextChatRoomPrivate : public ChatRoomPrivate { public: - RealTimeTextChatRoomPrivate (LinphoneCore *core, const Address &peerAddress); - virtual ~RealTimeTextChatRoomPrivate (); + RealTimeTextChatRoomPrivate () = default; + ~RealTimeTextChatRoomPrivate (); public: void setCall (LinphoneCall *call) { diff --git a/src/chat/chat-room/real-time-text-chat-room.cpp b/src/chat/chat-room/real-time-text-chat-room.cpp index ae302c82f..6c0dce359 100644 --- a/src/chat/chat-room/real-time-text-chat-room.cpp +++ b/src/chat/chat-room/real-time-text-chat-room.cpp @@ -20,6 +20,7 @@ #include "c-wrapper/c-wrapper.h" #include "chat/chat-message/chat-message-p.h" #include "conference/participant.h" +#include "core/core.h" #include "logger/logger.h" #include "real-time-text-chat-room-p.h" @@ -29,11 +30,6 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -RealTimeTextChatRoomPrivate::RealTimeTextChatRoomPrivate (LinphoneCore *core, const Address &peerAddress) - : ChatRoomPrivate(core) { - this->peerAddress = peerAddress; -} - RealTimeTextChatRoomPrivate::~RealTimeTextChatRoomPrivate () { if (!receivedRttCharacters.empty()) { for (auto &rttChars : receivedRttCharacters) @@ -49,6 +45,9 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp const uint32_t crlf = 0x0D0A; const uint32_t lf = 0x0A; + shared_ptr core = q->getCore(); + LinphoneCore *cCore = core->getCCore(); + if (call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) { LinphoneChatMessageCharacter *cmc = bctbx_new0(LinphoneChatMessageCharacter, 1); @@ -60,7 +59,7 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp receivedRttCharacters.push_back(cmc); remoteIsComposing.insert(peerAddress.asStringUriOnly()); - linphone_core_notify_is_composing_received(core, L_GET_C_BACK_PTR(q)); + linphone_core_notify_is_composing_received(cCore, L_GET_C_BACK_PTR(q)); if ((character == new_line) || (character == crlf) || (character == lf)) { /* End of message */ @@ -70,18 +69,15 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp Address( linphone_call_get_dest_proxy(call) ? linphone_address_as_string(linphone_call_get_dest_proxy(call)->identity_address) - : linphone_core_get_identity(core) + : linphone_core_get_identity(cCore) ) ); pendingMessage->getPrivate()->setState(ChatMessage::State::Delivered); pendingMessage->getPrivate()->setDirection(ChatMessage::Direction::Incoming); - if (lp_config_get_int(core->config, "misc", "store_rtt_messages", 1) == 1) + if (lp_config_get_int(cCore->config, "misc", "store_rtt_messages", 1) == 1) storeOrUpdateMessage(pendingMessage); - if (unreadCount < 0) unreadCount = 1; - else unreadCount++; - chatMessageReceived(pendingMessage); pendingMessage = nullptr; for (auto &rttChars : receivedRttCharacters) @@ -106,8 +102,8 @@ void RealTimeTextChatRoomPrivate::sendMessage (const std::shared_ptr &core, const Address &peerAddress) : + ChatRoom(*new RealTimeTextChatRoomPrivate, core, peerAddress) {} int RealTimeTextChatRoom::getCapabilities () const { return static_cast(Capabilities::Basic) | static_cast(Capabilities::RealTimeText); @@ -133,6 +129,15 @@ LinphoneCall *RealTimeTextChatRoom::getCall () const { return d->call; } +void RealTimeTextChatRoom::markAsRead () { + L_D(); + ChatRoom::markAsRead(); + if (d->pendingMessage) { + d->pendingMessage->updateState(ChatMessage::State::Displayed); + d->pendingMessage->sendDisplayNotification(); + } +} + // ----------------------------------------------------------------------------- void RealTimeTextChatRoom::onChatMessageReceived(const shared_ptr &msg) {} diff --git a/src/chat/chat-room/real-time-text-chat-room.h b/src/chat/chat-room/real-time-text-chat-room.h index d480700e9..31a24b166 100644 --- a/src/chat/chat-room/real-time-text-chat-room.h +++ b/src/chat/chat-room/real-time-text-chat-room.h @@ -30,14 +30,16 @@ class RealTimeTextChatRoomPrivate; class LINPHONE_PUBLIC RealTimeTextChatRoom : public ChatRoom { public: - RealTimeTextChatRoom (LinphoneCore *core, const Address &peerAddress); - virtual ~RealTimeTextChatRoom () = default; + // TODO: Make me private. + RealTimeTextChatRoom (const std::shared_ptr &core, const Address &peerAddress); CapabilitiesMask getCapabilities () const override; uint32_t getChar () const; LinphoneCall *getCall () const; + void markAsRead () override; + void onChatMessageReceived (const std::shared_ptr &msg) override; /* ConferenceInterface */ void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; diff --git a/src/chat/chat-room/server-group-chat-room-p.h b/src/chat/chat-room/server-group-chat-room-p.h index 5df197179..d5c2e7bbc 100644 --- a/src/chat/chat-room/server-group-chat-room-p.h +++ b/src/chat/chat-room/server-group-chat-room-p.h @@ -35,8 +35,7 @@ class Participant; class ServerGroupChatRoomPrivate : public ChatRoomPrivate { public: - ServerGroupChatRoomPrivate (LinphoneCore *core); - virtual ~ServerGroupChatRoomPrivate () = default; + ServerGroupChatRoomPrivate () = default; std::shared_ptr addParticipant (const Address &addr); void confirmCreation (); diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index d392490a6..306051cd5 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -17,6 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "core/core.h" + #include "server-group-chat-room-p.h" // ============================================================================= @@ -25,8 +27,6 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ServerGroupChatRoomPrivate::ServerGroupChatRoomPrivate (LinphoneCore *core) : ChatRoomPrivate(core) {} - // ----------------------------------------------------------------------------- shared_ptr ServerGroupChatRoomPrivate::addParticipant (const Address &) { @@ -73,8 +73,9 @@ bool ServerGroupChatRoomPrivate::isAdminLeft () const { // ============================================================================= -ServerGroupChatRoom::ServerGroupChatRoom (LinphoneCore *core, SalCallOp *op) - : ChatRoom(*new ServerGroupChatRoomPrivate(core)), LocalConference(core, Address(op->get_to()), nullptr) {} +ServerGroupChatRoom::ServerGroupChatRoom (const shared_ptr &core, SalCallOp *op) : + ChatRoom(*new ServerGroupChatRoomPrivate, core, Address(op->get_to())), + LocalConference(core->getCCore(), Address(op->get_to()), nullptr) {} int ServerGroupChatRoom::getCapabilities () const { return 0; diff --git a/src/chat/chat-room/server-group-chat-room.h b/src/chat/chat-room/server-group-chat-room.h index 828e7917a..7f1c54eea 100644 --- a/src/chat/chat-room/server-group-chat-room.h +++ b/src/chat/chat-room/server-group-chat-room.h @@ -36,12 +36,10 @@ class ServerGroupChatRoomPrivate; class ServerGroupChatRoom : public ChatRoom, public LocalConference { public: - ServerGroupChatRoom (LinphoneCore *core, SalCallOp *op); - virtual ~ServerGroupChatRoom () = default; + ServerGroupChatRoom (const std::shared_ptr &core, SalCallOp *op); int getCapabilities () const override; -public: /* ConferenceInterface */ void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
      &addresses, const CallSessionParams *params, bool hasMedia) override; diff --git a/src/chat/modifier/encryption-chat-message-modifier.cpp b/src/chat/modifier/encryption-chat-message-modifier.cpp index e6887b35d..3bb3b28a0 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.cpp +++ b/src/chat/modifier/encryption-chat-message-modifier.cpp @@ -23,6 +23,7 @@ #include "chat/chat-room/chat-room.h" #include "content/content-type.h" #include "content/content.h" +#include "core/core.h" #include "encryption-chat-message-modifier.h" @@ -37,7 +38,7 @@ ChatMessageModifier::Result EncryptionChatMessageModifier::encode ( int &errorCode ) { shared_ptr chatRoom = message->getChatRoom(); - LinphoneImEncryptionEngine *imee = chatRoom->getCore()->im_encryption_engine; + LinphoneImEncryptionEngine *imee = chatRoom->getCore()->getCCore()->im_encryption_engine; if (!imee) return ChatMessageModifier::Result::Skipped; @@ -70,7 +71,7 @@ ChatMessageModifier::Result EncryptionChatMessageModifier::decode ( int &errorCode ) { shared_ptr chatRoom = message->getChatRoom(); - LinphoneImEncryptionEngine *imee = chatRoom->getCore()->im_encryption_engine; + LinphoneImEncryptionEngine *imee = chatRoom->getCore()->getCCore()->im_encryption_engine; if (!imee) return ChatMessageModifier::Result::Skipped; diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index 10eb02133..7ccdff1e1 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -25,6 +25,7 @@ #include "chat/chat-room/chat-room.h" #include "content/content-type.h" #include "logger/logger.h" +#include "core/core.h" #include "multipart-chat-message-modifier.h" @@ -41,7 +42,7 @@ ChatMessageModifier::Result MultipartChatMessageModifier::encode ( if (message->getContents().size() <= 1) return ChatMessageModifier::Result::Skipped; - LinphoneCore *lc = message->getChatRoom()->getCore(); + LinphoneCore *lc = message->getChatRoom()->getCore()->getCCore(); char tmp[64]; lc->sal->create_uuid(tmp, sizeof(tmp)); string boundary = tmp; diff --git a/src/chat/notification/imdn.cpp b/src/chat/notification/imdn.cpp index 8a63b1966..4fc01dbc6 100644 --- a/src/chat/notification/imdn.cpp +++ b/src/chat/notification/imdn.cpp @@ -17,11 +17,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "logger/logger.h" - #include "chat/chat-message/chat-message.h" #include "chat/chat-room/chat-room.h" -#include "chat/notification/imdn.h" +#include "core/core.h" +#include "logger/logger.h" + +#include "imdn.h" // ============================================================================= @@ -66,7 +67,7 @@ void Imdn::parse (ChatRoom &cr, xmlparsing_context_t *xmlCtx) { if (!cm) { lWarning() << "Received IMDN for unknown message " << messageIdStr; } else { - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(cr.getCore()); + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(cr.getCore()->getCCore()); snprintf(xpathStr, sizeof(xpathStr), "%s[1]/imdn:delivery-notification/imdn:status", imdnPrefix.c_str()); xmlXPathObjectPtr deliveryStatusObject = linphone_get_xml_xpath_object_for_node_list(xmlCtx, xpathStr); snprintf(xpathStr, sizeof(xpathStr), "%s[1]/imdn:display-notification/imdn:status", imdnPrefix.c_str()); diff --git a/src/core/core-accessor.cpp b/src/core/core-accessor.cpp new file mode 100644 index 000000000..676847cfa --- /dev/null +++ b/src/core/core-accessor.cpp @@ -0,0 +1,58 @@ +/* + * core-accessor.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "logger/logger.h" + +#include "core-accessor.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +class CoreAccessorPrivate { +public: + weak_ptr core; +}; + +// ----------------------------------------------------------------------------- + +CoreAccessor::CoreAccessor (const shared_ptr &core) { + L_D(); + d->core = core; +} + +CoreAccessor::CoreAccessor (const shared_ptr &&core) { + L_D(); + d->core = move(core); +} + +CoreAccessor::~CoreAccessor () {} + +shared_ptr CoreAccessor::getCore () const { + L_D(); + + shared_ptr core = d->core.lock(); + if (!core) + lWarning() << "Unable to get valid core instance."; + return core; +} + +LINPHONE_END_NAMESPACE diff --git a/src/core/core-accessor.h b/src/core/core-accessor.h new file mode 100644 index 000000000..0608b1983 --- /dev/null +++ b/src/core/core-accessor.h @@ -0,0 +1,52 @@ +/* + * core-accessor.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CORE_ACCESSOR_H_ +#define _CORE_ACCESSOR_H_ + +#include + +#include "linphone/utils/general.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class Core; +class CoreAccessorPrivate; + +class CoreAccessor { +public: + CoreAccessor (const std::shared_ptr &core); + CoreAccessor (const std::shared_ptr &&core); + + virtual ~CoreAccessor () = 0; + + std::shared_ptr getCore () const; + +private: + CoreAccessorPrivate *mPrivate = nullptr; + + L_DISABLE_COPY(CoreAccessor); + L_DECLARE_PRIVATE(CoreAccessor); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CORE_ACCESSOR_H_ diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 3e8e668c9..63fd95a85 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -58,12 +58,14 @@ static inline string resolveWorkaroundClientGroupChatRoomAddress ( // ----------------------------------------------------------------------------- shared_ptr CorePrivate::createChatRoom (const Address &peerAddress, bool isRtt) { + L_Q(); + shared_ptr chatRoom; if (isRtt) - chatRoom = ObjectFactory::create(cCore, peerAddress); + chatRoom = ObjectFactory::create(q->getSharedFromThis(), peerAddress); else - chatRoom = ObjectFactory::create(cCore, peerAddress); + chatRoom = ObjectFactory::create(q->getSharedFromThis(), peerAddress); ChatRoomPrivate *dChatRoom = chatRoom->getPrivate(); insertChatRoom(chatRoom); @@ -188,7 +190,7 @@ shared_ptr Core::getOrCreateBasicChatRoom (const string &peerAddress, } void Core::deleteChatRoom (const shared_ptr &chatRoom) { - CorePrivate *d = chatRoom->getCore()->cppCore->getPrivate(); + CorePrivate *d = chatRoom->getCore()->getPrivate(); const Address cleanedPeerAddress = getCleanedPeerAddress(chatRoom->getPeerAddress()); d->deleteChatRoomWithDb( chatRoom->getCapabilities() & static_cast(ChatRoom::Capabilities::Conference) diff --git a/src/core/core.cpp b/src/core/core.cpp index 152276c9a..a554ab223 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -56,6 +56,11 @@ Core::Core (LinphoneCore *cCore) : Object(*new CorePrivate) { d->insertChatRoom(chatRoom); } +LinphoneCore *Core::getCCore () const { + L_D(); + return d->cCore; +} + string Core::getDataPath() const { L_D(); return Paths::getPath(Paths::Data, static_cast(d->cCore->platform_helper)); diff --git a/src/core/core.h b/src/core/core.h index 8a2cd3aa8..80f94a04c 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -35,6 +35,7 @@ class ChatRoom; class CorePrivate; class LINPHONE_PUBLIC Core : public Object { + friend class ChatRoom; friend class ClientGroupChatRoom; friend class MainDb; @@ -43,6 +44,13 @@ public: Core (LinphoneCore *cCore); + // --------------------------------------------------------------------------- + // C-Core. + // --------------------------------------------------------------------------- + + // TODO: Remove me later. + LinphoneCore *getCCore () const; + // --------------------------------------------------------------------------- // Paths. // --------------------------------------------------------------------------- diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index e1bd72e3e..ee45b2af5 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -286,8 +286,24 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { time_t date, const string &peerAddress ) const { - // TODO. - return nullptr; + soci::session *session = dbSession.getBackendSession(); + *session << "SELECT event_id, type, date, local_sip_address.value, " + "remote_sip_address.value, imdn_message_id, state, direction, is_secured" + " FROM event, conference_chat_message_event, sip_address AS local_sip_address," + " sip_address AS remote_sip_address" + " WHERE event_id = event.id" + " AND local_sip_address_id = local_sip_address.id" + " AND remote_sip_address_id = remote_sip_address.id" + " AND remote_sip_address.value = :peerAddress", soci::use(peerAddress); + + // TODO: Create me. + shared_ptr chatMessage; + + // TODO: Use cache. + return make_shared( + date, + chatMessage + ); } shared_ptr MainDbPrivate::selectConferenceParticipantEvent ( @@ -889,7 +905,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { return events; } - int MainDb::getMessagesCount (const string &peerAddress) const { + int MainDb::getChatMessagesCount (const string &peerAddress) const { L_D(); if (!isConnected()) { @@ -921,7 +937,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { return count; } - int MainDb::getUnreadMessagesCount (const string &peerAddress) const { + int MainDb::getUnreadChatMessagesCount (const string &peerAddress) const { L_D(); if (!isConnected()) { @@ -956,6 +972,45 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { return count; } + void MainDb::markChatMessagesAsRead (const string &peerAddress) const { + L_D(); + + if (!isConnected()) { + lWarning() << "Unable to mark messages as read. Not connected."; + return; + } + + if (getUnreadChatMessagesCount(peerAddress) == 0) + return; + + string query = "UPDATE FROM conference_chat_message_event" + " SET state = " + Utils::toString(static_cast(ChatMessage::State::Displayed)); + query += "WHERE"; + if (!peerAddress.empty()) + query += " event_id IN (" + " SELECT event_id FROM conference_event WHERE chat_room_id = (" + " SELECT id FROM sip_address WHERE value = :peerAddress" + " )" + ") AND"; + query += " direction = " + Utils::toString(static_cast(ChatMessage::Direction::Incoming)); + + L_BEGIN_LOG_EXCEPTION + + soci::session *session = d->dbSession.getBackendSession(); + + if (peerAddress.empty()) + *session << query; + else + *session << query, soci::use(peerAddress); + + L_END_LOG_EXCEPTION + } + + list> MainDb::getUnreadChatMessages (const std::string &peerAddress) const { + // TODO. + return list>(); + } + list> MainDb::getHistory (const string &peerAddress, int nLast, FilterMask mask) const { return getHistoryRange(peerAddress, 0, nLast - 1, mask); } @@ -1080,6 +1135,13 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { soci::rowset rows = (session->prepare << query); for (const auto &row : rows) { string sipAddress = row.get(0); + shared_ptr chatRoom = d->core->findChatRoom(Address(sipAddress)); + if (chatRoom) { + lInfo() << "Don't fetch chat room from database: `" << sipAddress << "`, it already exists."; + chatRooms.push_back(chatRoom); + continue; + } + tm creationDate = row.get(1); tm lastUpdateDate = row.get(2); int capabilities = row.get(3); @@ -1092,7 +1154,6 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { (void)subject; (void)lastNotifyId; - shared_ptr chatRoom; if (capabilities & static_cast(ChatRoom::Capabilities::Basic)) { chatRoom = d->core ? d->core->getPrivate()->createChatRoom( Address(sipAddress), @@ -1121,11 +1182,19 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { return; } + L_BEGIN_LOG_EXCEPTION + + soci::transaction tr(*d->dbSession.getBackendSession()); + d->insertChatRoom( d->insertSipAddress(peerAddress), capabilities, Utils::getTimeTAsTm(time(0)) ); + + tr.commit(); + + L_END_LOG_EXCEPTION } void MainDb::deleteChatRoom (const string &peerAddress) { @@ -1326,14 +1395,20 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { return list>(); } - int MainDb::getMessagesCount (const string &) const { + int MainDb::getChatMessagesCount (const string &) const { return 0; } - int MainDb::getUnreadMessagesCount (const string &) const { + int MainDb::getUnreadChatMessagesCount (const string &) const { return 0; } + void MainDb::markChatMessagesAsRead (const string &) const {} + + list> MainDb::getUnreadChatMessages (const std::string &) const { + return list>(); + } + list> MainDb::getHistory (const string &, int, FilterMask) const { return list>(); } diff --git a/src/db/main-db.h b/src/db/main-db.h index 200d70999..161e6c66f 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -28,14 +28,13 @@ LINPHONE_BEGIN_NAMESPACE +class ChatMessage; class ChatRoom; class Core; class EventLog; class MainDbPrivate; class LINPHONE_PUBLIC MainDb : public AbstractDb { - friend class ChatRoomProvider; - public: enum Filter { NoFilter = 0x0, @@ -48,20 +47,37 @@ public: MainDb (Core *core); + // --------------------------------------------------------------------------- // Generic. + // --------------------------------------------------------------------------- + bool addEvent (const std::shared_ptr &eventLog); bool deleteEvent (const std::shared_ptr &eventLog); void cleanEvents (FilterMask mask = NoFilter); int getEventsCount (FilterMask mask = NoFilter) const; - // Messages, calls and conferences. + // --------------------------------------------------------------------------- + // Conference notified events. + // --------------------------------------------------------------------------- + std::list> getConferenceNotifiedEvents ( const std::string &peerAddress, unsigned int lastNotifyId ); - int getMessagesCount (const std::string &peerAddress = "") const; - int getUnreadMessagesCount (const std::string &peerAddress = "") const; + // --------------------------------------------------------------------------- + // Conference chat message events. + // --------------------------------------------------------------------------- + + int getChatMessagesCount (const std::string &peerAddress = "") const; + int getUnreadChatMessagesCount (const std::string &peerAddress = "") const; + void markChatMessagesAsRead (const std::string &peerAddress = "") const; + std::list> getUnreadChatMessages (const std::string &peerAddress = "") const; + + // --------------------------------------------------------------------------- + // Conference events. + // --------------------------------------------------------------------------- + std::list> getHistory ( const std::string &peerAddress, int nLast, @@ -75,11 +91,18 @@ public: ) const; void cleanHistory (const std::string &peerAddress = "", FilterMask mask = NoFilter); - // ChatRooms. + // --------------------------------------------------------------------------- + // Chat rooms. + // --------------------------------------------------------------------------- + std::list> getChatRooms () const; void insertChatRoom (const std::string &peerAddress, int capabilities); void deleteChatRoom (const std::string &peerAddress); + // --------------------------------------------------------------------------- + // Other. + // --------------------------------------------------------------------------- + // Import legacy messages from old db. bool import (Backend backend, const std::string ¶meters) override; diff --git a/src/db/session/db-session-provider.cpp b/src/db/session/db-session-provider.cpp index da1c9f270..6ce81babe 100644 --- a/src/db/session/db-session-provider.cpp +++ b/src/db/session/db-session-provider.cpp @@ -27,59 +27,31 @@ #include "db-session-provider.h" -#define CLEAN_COUNTER_MAX 1000 - // ============================================================================= using namespace std; LINPHONE_BEGIN_NAMESPACE -class DbSessionProviderPrivate : public ObjectPrivate { -public: - typedef pair, DbSessionPrivate *> InternalSession; - unordered_map sessions; - int cleanCounter = 0; -}; - -DbSessionProvider::DbSessionProvider () : Singleton(*new DbSessionProviderPrivate) {} +DbSessionProvider::DbSessionProvider () : Singleton(*new ObjectPrivate) {} DbSession DbSessionProvider::getSession (const string &uri) { - L_D(); + DbSession session(DbSession::None); #ifdef SOCI_ENABLED - DbSession session(DbSession::Soci); try { - shared_ptr backendSession = d->sessions[uri].first.lock(); - ++d->cleanCounter; - if (!backendSession) { // Create new session. - backendSession = make_shared(uri); - DbSessionPrivate *p = session.getPrivate(); - p->backendSession = backendSession; - p->isValid = true; - d->sessions[uri] = make_pair(backendSession, p); - } else // Share session. - session.setRef(*d->sessions[uri].second); + session = DbSession(DbSession::Soci); + DbSessionPrivate *p = session.getPrivate(); + p->backendSession = make_shared(uri); + p->isValid = true; } catch (const exception &e) { + session = DbSession(DbSession::None); lWarning() << "Unable to get db session: " << e.what(); } #else - DbSession session(DbSession::None); lWarning() << "Unable to get db session: soci not enabled."; #endif // ifdef SOCI_ENABLED - // Remove invalid weak ptrs. - if (d->cleanCounter >= CLEAN_COUNTER_MAX) { - d->cleanCounter = 0; - - for (auto it = d->sessions.begin(), itEnd = d->sessions.end(); it != itEnd;) { - if (it->second.first.expired()) - it = d->sessions.erase(it); - else - ++it; - } - } - return session; } diff --git a/src/db/session/db-session-provider.h b/src/db/session/db-session-provider.h index 82a41c739..f471a7db0 100644 --- a/src/db/session/db-session-provider.h +++ b/src/db/session/db-session-provider.h @@ -38,7 +38,6 @@ public: private: DbSessionProvider (); - L_DECLARE_PRIVATE(DbSessionProvider); L_DISABLE_COPY(DbSessionProvider); }; diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index 3e58928c1..7f280fd10 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -196,7 +196,7 @@ set(SOURCE_FILES_C set(SOURCE_FILES_CXX clonable-object-tester.cpp - conference-event-tester.cpp + #conference-event-tester.cpp conference-tester.cpp content-manager-tester.cpp cpim-tester.cpp diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index 2b486a58f..ab0a11d2c 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -22,6 +22,10 @@ #include "chat/cpim/cpim.h" #include "content/content-type.h" #include "content/content.h" +#include "core/core.h" + +// TODO: Remove me later. +#include "private.h" #include "liblinphone_tester.h" @@ -391,7 +395,7 @@ static void cpim_chat_message_modifier_base(bool_t use_multipart) { lp_config_set_int(config, "sip", "use_cpim", 1); Address paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); - shared_ptr marieRoom = ObjectFactory::create(marie->lc, paulineAddress); + shared_ptr marieRoom = ObjectFactory::create(marie->lc->cppCore, paulineAddress); shared_ptr marieMessage = marieRoom->createMessage("Hello CPIM"); if (use_multipart) { diff --git a/tester/main-db-tester.cpp b/tester/main-db-tester.cpp index 714ce9e2c..495671421 100644 --- a/tester/main-db-tester.cpp +++ b/tester/main-db-tester.cpp @@ -55,15 +55,15 @@ static void get_events_count () { static void get_messages_count () { MainDb mainDb(nullptr); BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); - BC_ASSERT_EQUAL(mainDb.getMessagesCount(), 4976, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getMessagesCount("sip:test-39@sip.linphone.org"), 3, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getChatMessagesCount(), 4976, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getChatMessagesCount("sip:test-39@sip.linphone.org"), 3, int, "%d"); } static void get_unread_messages_count () { MainDb mainDb(nullptr); BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); - BC_ASSERT_EQUAL(mainDb.getUnreadMessagesCount(), 2, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getUnreadMessagesCount("sip:test-39@sip.linphone.org"), 0, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getUnreadChatMessagesCount(), 2, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getUnreadChatMessagesCount("sip:test-39@sip.linphone.org"), 0, int, "%d"); } static void get_history () { diff --git a/tester/message_tester.c b/tester/message_tester.c index 98c7a1f83..62efe5b44 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -1575,156 +1575,6 @@ void history_message_count_helper(LinphoneChatRoom* chatroom, int x, int y, unsi bctbx_list_free_with_data(messages, (void (*)(void *))linphone_chat_message_unref); } -static void database_migration(void) { - LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); - char *src_db = bc_tester_res("messages.db"); - char *tmp_db = bc_tester_file("tmp.db"); - const bctbx_list_t* chatrooms; - LinphoneChatRoom *cr; - - BC_ASSERT_EQUAL(message_tester_copy_file(src_db, tmp_db), 0, int, "%d"); - - // enable to test the performances of the migration step - //linphone_core_message_storage_set_debug(marie->lc, TRUE); - - // the messages.db has 10000 dummy messages with the very first DB scheme. - // This will test the migration procedure - linphone_core_set_chat_database_path(marie->lc, tmp_db); - BC_ASSERT_PTR_NOT_NULL(linphone_core_get_sqlite_database(marie->lc)); - if (!linphone_core_get_sqlite_database(marie->lc)) goto end; - - chatrooms = linphone_core_get_chat_rooms(marie->lc); - BC_ASSERT(bctbx_list_size(chatrooms) > 0); - - // check that all messages have been migrated to the UTC time storage - BC_ASSERT(sqlite3_exec(linphone_core_get_sqlite_database(marie->lc), "SELECT COUNT(*) FROM history WHERE time != '-1';", check_no_strange_time, NULL, NULL) == SQLITE_OK); - - // check that the read messages (field read=1) has been migrated to the LinphoneChatMessageStateDisplayed state - cr = linphone_core_get_chat_room_from_uri(marie->lc, "sip:Marielle@sip.linphone.org"); - BC_ASSERT_EQUAL(linphone_chat_room_get_unread_messages_count(cr), 8, int, "%i"); - -end: - linphone_core_manager_destroy(marie); - remove(tmp_db); - bc_free(src_db); - bc_free(tmp_db); -} - -static void history_range(void){ - LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); - LinphoneAddress *jehan_addr = linphone_address_new(""); - LinphoneChatRoom *chatroom; - char *src_db = bc_tester_res("messages.db"); - char *tmp_db = bc_tester_file("tmp.db"); - - BC_ASSERT_EQUAL(message_tester_copy_file(src_db, tmp_db), 0, int, "%d"); - - linphone_core_set_chat_database_path(marie->lc, tmp_db); - BC_ASSERT_PTR_NOT_NULL(linphone_core_get_sqlite_database(marie->lc)); - if (!linphone_core_get_sqlite_database(marie->lc)) goto end; - - chatroom = linphone_core_get_chat_room(marie->lc, jehan_addr); - BC_ASSERT_PTR_NOT_NULL(chatroom); - if (chatroom){ - // We have 20 tests to perform to fully qualify the function, here they are: - history_message_count_helper(chatroom, 0, 0, 1); - history_message_count_helper(chatroom, -1, 0, 1); - history_message_count_helper(chatroom, 0, -1, 1270); - history_message_count_helper(chatroom, 1, 3, 3); - history_message_count_helper(chatroom, 3, 1, 1270-3); - history_message_count_helper(chatroom, 10, 10, 1); - history_message_count_helper(chatroom, -1, -1, 1270); - history_message_count_helper(chatroom, -1, -2, 1270); - history_message_count_helper(chatroom, -2, -1, 1270); - history_message_count_helper(chatroom, 3, -1, 1270-3); - history_message_count_helper(chatroom, 1, -3, 1270-1); - history_message_count_helper(chatroom, 2, -2, 1270-2); - history_message_count_helper(chatroom, 2, 0, 1270-2); - history_message_count_helper(chatroom, 0, 2, 3); - history_message_count_helper(chatroom, -1, 3, 4); - history_message_count_helper(chatroom, -2, 2, 3); - history_message_count_helper(chatroom, -3, 1, 2); - } - -end: - linphone_core_manager_destroy(marie); - linphone_address_unref(jehan_addr); - remove(tmp_db); - bc_free(src_db); - bc_free(tmp_db); -} - -static void history_count(void) { - LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); - LinphoneAddress *jehan_addr = linphone_address_new(""); - LinphoneChatRoom *chatroom; - bctbx_list_t *messages; - char *src_db = bc_tester_res("messages.db"); - char *tmp_db = bc_tester_file("tmp.db"); - - BC_ASSERT_EQUAL(message_tester_copy_file(src_db, tmp_db), 0, int, "%d"); - - linphone_core_set_chat_database_path(marie->lc, tmp_db); - BC_ASSERT_PTR_NOT_NULL(linphone_core_get_sqlite_database(marie->lc)); - if (!linphone_core_get_sqlite_database(marie->lc)) goto end; - - chatroom = linphone_core_get_chat_room(marie->lc, jehan_addr); - BC_ASSERT_PTR_NOT_NULL(chatroom); - if (chatroom){ - messages=linphone_chat_room_get_history(chatroom,10); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(messages), 10, unsigned int, "%u"); - bctbx_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); - - messages=linphone_chat_room_get_history(chatroom,1); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(messages), 1, unsigned int, "%u"); - bctbx_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); - - messages=linphone_chat_room_get_history(chatroom,0); - BC_ASSERT_EQUAL(linphone_chat_room_get_history_size(chatroom), 1270, int, "%d"); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(messages), 1270, unsigned int, "%u"); - - /*check the second most recent msg*/ - BC_ASSERT_PTR_NOT_NULL(messages); - if (messages){ - BC_ASSERT_PTR_NOT_NULL(messages->next->data); - if (messages->next->data){ - BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text((LinphoneChatMessage *)messages->next->data), "Fore and aft follow each other."); - } - } - - bctbx_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); - - /*test offset+limit: retrieve the 42th latest msg only and check its content*/ - messages=linphone_chat_room_get_history_range(chatroom, 42, 42); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(messages), 1, unsigned int, "%u"); - BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text((LinphoneChatMessage *)messages->data), "If you open yourself to the Tao is intangible and evasive, yet prefers to keep us at the mercy of the kingdom, then all of the streams of hundreds of valleys because of its limitless possibilities."); - bctbx_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); - - /*test offset without limit*/ - messages = linphone_chat_room_get_history_range(chatroom, 1265, -1); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(messages), 1270-1265, unsigned int, "%u"); - bctbx_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); - - /*test limit without offset*/ - messages = linphone_chat_room_get_history_range(chatroom, 0, 5); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(messages), 6, unsigned int, "%u"); - bctbx_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); - - /*test invalid start*/ - messages = linphone_chat_room_get_history_range(chatroom, 1265, 1260); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(messages), 1270-1265, unsigned int, "%u"); - bctbx_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); - } - -end: - linphone_core_manager_destroy(marie); - linphone_address_unref(jehan_addr); - remove(tmp_db); - bc_free(src_db); - bc_free(tmp_db); -} - - void crash_during_file_transfer(void) { LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_tcp_rc"); @@ -1847,10 +1697,6 @@ static void real_time_text(bool_t audio_stream_enabled, bool_t srtp_enabled, boo if (sql_storage) { linphone_core_set_chat_database_path(marie->lc, marie_db); linphone_core_set_chat_database_path(pauline->lc, pauline_db); -#ifdef SQLITE_STORAGE_ENABLED - BC_ASSERT_PTR_NOT_NULL(linphone_core_get_sqlite_database(marie->lc)); - BC_ASSERT_PTR_NOT_NULL(linphone_core_get_sqlite_database(pauline->lc)); -#endif if (do_not_store_rtt_messages_in_sql_storage) { lp_config_set_int(linphone_core_get_config(marie->lc), "misc", "store_rtt_messages", 0); @@ -2506,9 +2352,6 @@ test_t message_tests[] = { TEST_ONE_TAG("Lime transfer message without encryption 2", lime_transfer_message_without_encryption_2, "LIME"), TEST_ONE_TAG("Lime cache migration", lime_cache_migration, "LIME"), TEST_ONE_TAG("Lime unitary", lime_unit, "LIME"), - TEST_NO_TAG("Database migration", database_migration), - TEST_NO_TAG("History range", history_range), - TEST_NO_TAG("History count", history_count), #endif TEST_NO_TAG("Transfer not sent if invalid url", file_transfer_not_sent_if_invalid_url), TEST_NO_TAG("Transfer not sent if host not found", file_transfer_not_sent_if_host_not_found), diff --git a/tester/multipart-tester.cpp b/tester/multipart-tester.cpp index 677b5f62d..4e781281d 100644 --- a/tester/multipart-tester.cpp +++ b/tester/multipart-tester.cpp @@ -21,6 +21,10 @@ #include "chat/chat-room/basic-chat-room.h" #include "content/content-type.h" #include "content/content.h" +#include "core/core.h" + +// TODO: Remove me later. +#include "private.h" #include "liblinphone_tester.h" @@ -32,10 +36,10 @@ using namespace LinphonePrivate; static void chat_message_multipart_modifier_base(bool first_file_transfer, bool second_file_transfer, bool use_cpim) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc"); Address paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); - shared_ptr marieRoom = ObjectFactory::create(marie->lc, paulineAddress); + shared_ptr marieRoom = ObjectFactory::create(marie->lc->cppCore, paulineAddress); shared_ptr marieMessage; if (first_file_transfer) { @@ -55,7 +59,7 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer, bool linphone_content_set_type(initialContent,"video"); linphone_content_set_subtype(initialContent,"mkv"); linphone_content_set_name(initialContent,"sintel_trailer_opus_h264.mkv"); - + Content content; content.setContentType(ContentType::FileTransfer); content.setBody(linphone_content_get_string_buffer(initialContent)); diff --git a/tester/tester.c b/tester/tester.c index 48708461e..ca41f129a 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -563,7 +563,7 @@ void liblinphone_tester_add_suites() { bc_tester_add_suite(&account_creator_test_suite); bc_tester_add_suite(&stun_test_suite); bc_tester_add_suite(&event_test_suite); - bc_tester_add_suite(&conference_event_test_suite); + //bc_tester_add_suite(&conference_event_test_suite); bc_tester_add_suite(&conference_test_suite); bc_tester_add_suite(&content_manager_test_suite); bc_tester_add_suite(&flexisip_test_suite); From a7ff19566dcbd66534461f4a27945ebdb5de5cf3 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 3 Nov 2017 10:38:50 +0100 Subject: [PATCH 0673/2215] fix(core): misc => - return nullptr if conference factory uri is not set - Address object is now more robust - remove custom SharedFromThis object - CoreAccessor throw exception if core is destroyed - Core must be created with a static method - Partial fetch of chat message - ... --- coreapi/linphonecore.c | 10 +++- src/address/address.cpp | 58 ++++++++++++++----- src/c-wrapper/api/c-call.cpp | 4 +- src/c-wrapper/api/c-chat-room.cpp | 4 +- src/chat/chat-message/chat-message.h | 1 + src/chat/chat-room/basic-chat-room.cpp | 2 +- src/chat/chat-room/chat-room.cpp | 2 +- src/chat/chat-room/client-group-chat-room.cpp | 4 +- .../chat-room/real-time-text-chat-room.cpp | 2 +- src/conference/conference.cpp | 2 +- src/conference/local-conference.cpp | 2 +- src/conference/participant.cpp | 4 +- src/conference/remote-conference.cpp | 2 +- src/core/core-accessor.cpp | 19 ++++-- src/core/core-accessor.h | 4 +- src/core/core-chat-room.cpp | 13 ++++- src/core/core.cpp | 20 +++++-- src/core/core.h | 5 +- src/db/main-db-p.h | 5 -- src/db/main-db.cpp | 58 ++++++++++++++----- src/db/main-db.h | 7 ++- src/object/object-p.h | 3 - src/object/object.cpp | 19 +----- src/object/object.h | 29 +++------- tester/cpim-tester.cpp | 2 +- tester/main-db-tester.cpp | 50 ++++++++++++---- tester/multipart-tester.cpp | 2 +- 27 files changed, 209 insertions(+), 124 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index fadfd6224..6a2f3dcbf 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2259,7 +2259,7 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig lc->sal->set_callbacks(&linphone_sal_callbacks); new(&lc->cppCore) std::shared_ptr(); - lc->cppCore = ObjectFactory::create(lc); + lc->cppCore = Core::create(lc); #ifdef TUNNEL_ENABLED lc->tunnel=linphone_core_tunnel_new(lc); @@ -7237,7 +7237,7 @@ void linphone_core_set_conference_factory_uri(LinphoneCore *lc, const char *uri) } const char * linphone_core_get_conference_factory_uri(const LinphoneCore *lc) { - return lp_config_get_string(linphone_core_get_config(lc), "misc", "conference_factory_uri", "sip:"); + return lp_config_get_string(linphone_core_get_config(lc), "misc", "conference_factory_uri", nullptr); } void linphone_core_enable_conference_server (LinphoneCore *lc, bool_t enable) { @@ -7249,7 +7249,11 @@ bool_t linphone_core_conference_server_enabled (const LinphoneCore *lc) { } bool_t _linphone_core_is_conference_creation (const LinphoneCore *lc, const LinphoneAddress *addr) { - LinphoneAddress *factoryAddr = linphone_address_new(linphone_core_get_conference_factory_uri(lc)); + const char *uri = linphone_core_get_conference_factory_uri(lc); + if (!uri) + return FALSE; + + LinphoneAddress *factoryAddr = linphone_address_new(uri); if (!factoryAddr) return FALSE; bool_t result = linphone_address_weak_equal(factoryAddr, addr); diff --git a/src/address/address.cpp b/src/address/address.cpp index 1be60feb0..257fe7e1b 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -83,12 +83,20 @@ bool Address::isValid () const { const string &Address::getScheme () const { L_D(); + + if (!d->internalAddress) + return Utils::getEmptyConstRefObject(); + d->cache.scheme = L_C_TO_STRING(sal_address_get_scheme(d->internalAddress)); return d->cache.scheme; } const string &Address::getDisplayName () const { L_D(); + + if (!d->internalAddress) + return Utils::getEmptyConstRefObject(); + d->cache.displayName = L_C_TO_STRING(sal_address_get_display_name(d->internalAddress)); return d->cache.displayName; } @@ -105,6 +113,10 @@ bool Address::setDisplayName (const string &displayName) { const string &Address::getUsername () const { L_D(); + + if (!d->internalAddress) + return Utils::getEmptyConstRefObject(); + d->cache.username = L_C_TO_STRING(sal_address_get_username(d->internalAddress)); return d->cache.username; } @@ -121,6 +133,10 @@ bool Address::setUsername (const string &username) { const string &Address::getDomain () const { L_D(); + + if (!d->internalAddress) + return Utils::getEmptyConstRefObject(); + d->cache.domain = L_C_TO_STRING(sal_address_get_domain(d->internalAddress)); return d->cache.domain; } @@ -187,6 +203,10 @@ bool Address::isSip () const { const string &Address::getMethodParam () const { L_D(); + + if (!d->internalAddress) + return Utils::getEmptyConstRefObject(); + d->cache.methodParam = L_C_TO_STRING(sal_address_get_method_param(d->internalAddress)); return d->cache.methodParam; } @@ -203,6 +223,10 @@ bool Address::setMethodParam (const string &methodParam) { const string &Address::getPassword () const { L_D(); + + if (!d->internalAddress) + return Utils::getEmptyConstRefObject(); + d->cache.password = L_C_TO_STRING(sal_address_get_password(d->internalAddress)); return d->cache.password; } @@ -260,10 +284,12 @@ bool Address::weakEqual (const Address &address) const { const string &Address::getHeaderValue (const string &headerName) const { L_D(); - const char *value = sal_address_get_header(d->internalAddress, L_STRING_TO_C(headerName)); - if (value) { - d->cache.headers[headerName] = value; - return d->cache.headers[headerName]; + if (d->internalAddress) { + const char *value = sal_address_get_header(d->internalAddress, L_STRING_TO_C(headerName)); + if (value) { + d->cache.headers[headerName] = value; + return d->cache.headers[headerName]; + } } return Utils::getEmptyConstRefObject(); @@ -281,16 +307,18 @@ bool Address::setHeader (const string &headerName, const string &headerValue) { bool Address::hasParam (const string ¶mName) const { L_D(); - return !!sal_address_has_param(d->internalAddress, L_STRING_TO_C(paramName)); + return d->internalAddress && !!sal_address_has_param(d->internalAddress, L_STRING_TO_C(paramName)); } const string &Address::getParamValue (const string ¶mName) const { L_D(); - const char *value = sal_address_get_param(d->internalAddress, L_STRING_TO_C(paramName)); - if (value) { - d->cache.params[paramName] = value; - return d->cache.params[paramName]; + if (d->internalAddress) { + const char *value = sal_address_get_param(d->internalAddress, L_STRING_TO_C(paramName)); + if (value) { + d->cache.params[paramName] = value; + return d->cache.params[paramName]; + } } return Utils::getEmptyConstRefObject(); @@ -318,16 +346,18 @@ bool Address::setParams (const string ¶ms) { bool Address::hasUriParam (const string &uriParamName) const { L_D(); - return !!sal_address_has_uri_param(d->internalAddress, L_STRING_TO_C(uriParamName)); + return d->internalAddress && !!sal_address_has_uri_param(d->internalAddress, L_STRING_TO_C(uriParamName)); } const string &Address::getUriParamValue (const string &uriParamName) const { L_D(); - const char *value = sal_address_get_uri_param(d->internalAddress, L_STRING_TO_C(uriParamName)); - if (value) { - d->cache.uriParams[uriParamName] = value; - return d->cache.uriParams[uriParamName]; + if (d->internalAddress) { + const char *value = sal_address_get_uri_param(d->internalAddress, L_STRING_TO_C(uriParamName)); + if (value) { + d->cache.uriParams[uriParamName] = value; + return d->cache.uriParams[uriParamName]; + } } return Utils::getEmptyConstRefObject(); diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 3f1d13002..dc86b5a1c 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -1148,7 +1148,7 @@ void linphone_call_set_user_data (LinphoneCall *call, void *ud) { LinphoneCall *linphone_call_new_outgoing (LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg) { LinphoneCall *call = L_INIT(Call); - L_SET_CPP_PTR_FROM_C_OBJECT(call, LinphonePrivate::ObjectFactory::create(call, lc, LinphoneCallOutgoing, + L_SET_CPP_PTR_FROM_C_OBJECT(call, make_shared(call, lc, LinphoneCallOutgoing, *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), cfg, nullptr, L_GET_CPP_PTR_FROM_C_OBJECT(params))); call->currentParamsCache = linphone_call_params_new_for_wrapper(); @@ -1160,7 +1160,7 @@ LinphoneCall *linphone_call_new_outgoing (LinphoneCore *lc, const LinphoneAddres LinphoneCall *linphone_call_new_incoming (LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, LinphonePrivate::SalCallOp *op) { LinphoneCall *call = L_INIT(Call); - L_SET_CPP_PTR_FROM_C_OBJECT(call, LinphonePrivate::ObjectFactory::create(call, lc, LinphoneCallIncoming, + L_SET_CPP_PTR_FROM_C_OBJECT(call, make_shared(call, lc, LinphoneCallIncoming, *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), nullptr, op, nullptr)); call->currentParamsCache = linphone_call_params_new_for_wrapper(); diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 6292f863c..d0f25a116 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -348,7 +348,7 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, cons from = linphone_core_get_primary_contact(core); LinphonePrivate::Address me(from); LinphoneChatRoom *cr = L_INIT(ChatRoom); - L_SET_CPP_PTR_FROM_C_OBJECT(cr, LinphonePrivate::ObjectFactory::create( + L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared( core->cppCore, me, L_C_TO_STRING(uri), L_C_TO_STRING(subject)) ); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); @@ -357,7 +357,7 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, cons LinphoneChatRoom *_linphone_server_group_chat_room_new (LinphoneCore *core, LinphonePrivate::SalCallOp *op) { LinphoneChatRoom *cr = L_INIT(ChatRoom); - L_SET_CPP_PTR_FROM_C_OBJECT(cr, LinphonePrivate::ObjectFactory::create( + L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared( core->cppCore, op )); diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index cb2742fc6..00c41df82 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -41,6 +41,7 @@ class LINPHONE_PUBLIC ChatMessage : public Object, public CoreAccessor { friend class ChatRoom; friend class ChatRoomPrivate; friend class CpimChatMessageModifier; + friend class MainDbPrivate; friend class RealTimeTextChatRoomPrivate; friend class ServerGroupChatRoomPrivate; diff --git a/src/chat/chat-room/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp index bb602f9c6..4d9d9e470 100644 --- a/src/chat/chat-room/basic-chat-room.cpp +++ b/src/chat/chat-room/basic-chat-room.cpp @@ -71,7 +71,7 @@ int BasicChatRoom::getNbParticipants () const { list> BasicChatRoom::getParticipants () const { L_D(); list> l; - l.push_back(ObjectFactory::create(d->peerAddress)); + l.push_back(make_shared(d->peerAddress)); return l; } diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 96401619d..03bd1950f 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -480,7 +480,7 @@ shared_ptr ChatRoom::createMessage (const string &message) { shared_ptr ChatRoom::createMessage () { L_D(); - shared_ptr chatMessage = ObjectFactory::create(getSharedFromThis()); + shared_ptr chatMessage = make_shared(getSharedFromThis()); chatMessage->setToAddress(d->peerAddress); chatMessage->setFromAddress(Address(linphone_core_get_identity(getCore()->getCCore()))); chatMessage->getPrivate()->setTime(ms_time(0)); diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 7b0e25656..e50b13e35 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -72,7 +72,7 @@ ClientGroupChatRoom::ClientGroupChatRoom ( const std::string &subject ) : ChatRoom(*new ClientGroupChatRoomPrivate, core, me), RemoteConference(core->getCCore(), me, nullptr) { L_D_T(RemoteConference, dConference); - dConference->focus = ObjectFactory::create(Address(uri)); + dConference->focus = make_shared(Address(uri)); RemoteConference::setSubject(subject); } @@ -275,7 +275,7 @@ void ClientGroupChatRoom::onParticipantAdded (time_t tm, const Address &addr) { return; } - participant = ObjectFactory::create(addr); + participant = make_shared(addr); dConference->participants.push_back(participant); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); diff --git a/src/chat/chat-room/real-time-text-chat-room.cpp b/src/chat/chat-room/real-time-text-chat-room.cpp index 6c0dce359..2242cdd3c 100644 --- a/src/chat/chat-room/real-time-text-chat-room.cpp +++ b/src/chat/chat-room/real-time-text-chat-room.cpp @@ -171,7 +171,7 @@ int RealTimeTextChatRoom::getNbParticipants () const { list> RealTimeTextChatRoom::getParticipants () const { L_D(); list> l; - l.push_back(ObjectFactory::create(d->peerAddress)); + l.push_back(make_shared(d->peerAddress)); return l; } diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 0d97d880f..c0ac545ab 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -34,7 +34,7 @@ Conference::Conference (ConferencePrivate &p, LinphoneCore *core, const Address d->mPublic = this; d->core = core; d->callListener = listener; - d->me = ObjectFactory::create(myAddress); + d->me = make_shared(myAddress); } Conference::~Conference () { diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index 872e6da9e..11e41e4e8 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -41,7 +41,7 @@ void LocalConference::addParticipant (const Address &addr, const CallSessionPara shared_ptr participant = findParticipant(addr); if (participant) return; - participant = ObjectFactory::create(addr); + participant = make_shared(addr); d->participants.push_back(participant); if (!d->activeParticipant) d->activeParticipant = participant; diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index f4ef38269..ecafa17fd 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -36,9 +36,9 @@ shared_ptr ParticipantPrivate::createSession ( const Conference &conference, const CallSessionParams *params, bool hasMedia, CallSessionListener *listener ) { if (hasMedia && (!params || dynamic_cast(params))) { - session = ObjectFactory::create(conference, params, listener); + session = make_shared(conference, params, listener); } else { - session = ObjectFactory::create(conference, params, listener); + session = make_shared(conference, params, listener); } return session; } diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index 3b317a10e..d746a495f 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -46,7 +46,7 @@ void RemoteConference::addParticipant (const Address &addr, const CallSessionPar shared_ptr participant = findParticipant(addr); if (participant) return; - participant = ObjectFactory::create(addr); + participant = make_shared(addr); participant->getPrivate()->createSession(*this, params, hasMedia, this); d->participants.push_back(participant); if (!d->activeParticipant) diff --git a/src/core/core-accessor.cpp b/src/core/core-accessor.cpp index 676847cfa..bbd1fe784 100644 --- a/src/core/core-accessor.cpp +++ b/src/core/core-accessor.cpp @@ -35,23 +35,30 @@ public: // ----------------------------------------------------------------------------- CoreAccessor::CoreAccessor (const shared_ptr &core) { - L_D(); - d->core = core; + L_ASSERT(core); + mPrivate = new CoreAccessorPrivate(); + mPrivate->core = core; } CoreAccessor::CoreAccessor (const shared_ptr &&core) { - L_D(); - d->core = move(core); + L_ASSERT(core); + mPrivate = new CoreAccessorPrivate(); + mPrivate->core = move(core); } -CoreAccessor::~CoreAccessor () {} +CoreAccessor::~CoreAccessor () { + delete mPrivate; +} shared_ptr CoreAccessor::getCore () const { L_D(); shared_ptr core = d->core.lock(); - if (!core) + if (!core) { lWarning() << "Unable to get valid core instance."; + throw std::bad_weak_ptr(); + } + return core; } diff --git a/src/core/core-accessor.h b/src/core/core-accessor.h index 0608b1983..cb5ff623b 100644 --- a/src/core/core-accessor.h +++ b/src/core/core-accessor.h @@ -31,13 +31,15 @@ LINPHONE_BEGIN_NAMESPACE class Core; class CoreAccessorPrivate; -class CoreAccessor { +// Decorator to get a valid core instance. +LINPHONE_PUBLIC class CoreAccessor { public: CoreAccessor (const std::shared_ptr &core); CoreAccessor (const std::shared_ptr &&core); virtual ~CoreAccessor () = 0; + // Returns a valid core instance. Or throw one std::bad_weak_ptr exception if core is destroyed. std::shared_ptr getCore () const; private: diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 63fd95a85..c5d1484d3 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -39,6 +39,9 @@ LINPHONE_BEGIN_NAMESPACE // ----------------------------------------------------------------------------- static inline Address getCleanedPeerAddress (const Address &peerAddress) { + if (!peerAddress.isValid()) + return Address(); + Address cleanedAddress = peerAddress; cleanedAddress.clean(); cleanedAddress.setPort(0); @@ -50,8 +53,12 @@ static inline string resolveWorkaroundClientGroupChatRoomAddress ( const CorePrivate &corePrivate, const Address &peerAddress ) { + const char *uri = linphone_core_get_conference_factory_uri(corePrivate.cCore); + if (!uri) + return ""; + Address workaroundAddress = peerAddress; - workaroundAddress.setDomain(Address(linphone_core_get_conference_factory_uri(corePrivate.cCore)).getDomain()); + workaroundAddress.setDomain(Address(uri).getDomain()); return workaroundAddress.asStringUriOnly(); } @@ -63,9 +70,9 @@ shared_ptr CorePrivate::createChatRoom (const Address &peerAddress, bo shared_ptr chatRoom; if (isRtt) - chatRoom = ObjectFactory::create(q->getSharedFromThis(), peerAddress); + chatRoom = make_shared(q->getSharedFromThis(), peerAddress); else - chatRoom = ObjectFactory::create(q->getSharedFromThis(), peerAddress); + chatRoom = make_shared(q->getSharedFromThis(), peerAddress); ChatRoomPrivate *dChatRoom = chatRoom->getPrivate(); insertChatRoom(chatRoom); diff --git a/src/core/core.cpp b/src/core/core.cpp index a554ab223..bd47d7ef0 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -32,20 +32,26 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -Core::Core (LinphoneCore *cCore) : Object(*new CorePrivate) { - L_D(); +Core::Core () : Object(*new CorePrivate) {} + +shared_ptr Core::create (LinphoneCore *cCore) { + // Do not use `make_shared` => Private constructor. + shared_ptr core = shared_ptr(new Core); + + CorePrivate * const d = core->getPrivate(); + d->cCore = cCore; - d->mainDb.reset(new MainDb(this)); + d->mainDb.reset(new MainDb(core->getSharedFromThis())); AbstractDb::Backend backend; - string uri = L_C_TO_STRING(lp_config_get_string(linphone_core_get_config(d->cCore), "server", "db_uri", NULL)); + string uri = L_C_TO_STRING(lp_config_get_string(linphone_core_get_config(d->cCore), "storage", "backend", nullptr)); if (!uri.empty()) - backend = strcmp(lp_config_get_string(linphone_core_get_config(d->cCore), "server", "db_backend", NULL), "mysql") == 0 + backend = strcmp(lp_config_get_string(linphone_core_get_config(d->cCore), "storage", "uri", nullptr), "mysql") == 0 ? MainDb::Mysql : MainDb::Sqlite3; else { backend = AbstractDb::Sqlite3; - uri = getDataPath() + LINPHONE_DB; + uri = core->getDataPath() + LINPHONE_DB; } lInfo() << "Opening " LINPHONE_DB " at: " << uri; @@ -54,6 +60,8 @@ Core::Core (LinphoneCore *cCore) : Object(*new CorePrivate) { for (auto &chatRoom : d->mainDb->getChatRooms()) d->insertChatRoom(chatRoom); + + return core; } LinphoneCore *Core::getCCore () const { diff --git a/src/core/core.h b/src/core/core.h index 80f94a04c..0eb899f9a 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -42,7 +42,8 @@ class LINPHONE_PUBLIC Core : public Object { public: L_OVERRIDE_SHARED_FROM_THIS(Core); - Core (LinphoneCore *cCore); + // Return a new Core instance. Entry point of Linphone. + static std::shared_ptr create (LinphoneCore *cCore); // --------------------------------------------------------------------------- // C-Core. @@ -71,6 +72,8 @@ public: static void deleteChatRoom (const std::shared_ptr &chatRoom); private: + Core (); + L_DECLARE_PRIVATE(Core); L_DISABLE_COPY(Core); }; diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index b7133a055..9a2715a67 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -29,11 +29,8 @@ LINPHONE_BEGIN_NAMESPACE class Content; -struct MessageEventReferences; class MainDbPrivate : public AbstractDbPrivate { -public: - private: // --------------------------------------------------------------------------- // Low level API. @@ -108,8 +105,6 @@ private: long long insertConferenceParticipantDeviceEvent (const std::shared_ptr &eventLog); long long insertConferenceSubjectEvent (const std::shared_ptr &eventLog); - Core *core = nullptr; - L_DECLARE_PUBLIC(MainDb); }; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index ee45b2af5..40f2be4f0 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -26,6 +26,7 @@ #include "linphone/utils/utils.h" +#include "chat/chat-message/chat-message-p.h" #include "chat/chat-room/chat-room.h" #include "conference/participant.h" #include "content/content-type.h" @@ -45,10 +46,7 @@ LINPHONE_BEGIN_NAMESPACE // ----------------------------------------------------------------------------- -MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { - L_D(); - d->core = core; -} +MainDb::MainDb (const shared_ptr &core) : CoreAccessor(core), AbstractDb(*new MainDbPrivate) {} #ifdef SOCI_ENABLED @@ -286,18 +284,49 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { time_t date, const string &peerAddress ) const { + L_Q(); + + shared_ptr core = q->getCore(); + L_ASSERT(core); + + // TODO: Avoid address creation. + shared_ptr chatRoom = core->findChatRoom(Address(peerAddress)); + if (!chatRoom) + return nullptr; + + string localSipAddress; + string remoteSipAddress; + string imdnMessageId; + int state; + int direction; + int isSecured; + soci::session *session = dbSession.getBackendSession(); - *session << "SELECT event_id, type, date, local_sip_address.value, " - "remote_sip_address.value, imdn_message_id, state, direction, is_secured" + *session << "SELECT local_sip_address.value, remote_sip_address.value, imdn_message_id, state, direction, is_secured" " FROM event, conference_chat_message_event, sip_address AS local_sip_address," " sip_address AS remote_sip_address" " WHERE event_id = event.id" " AND local_sip_address_id = local_sip_address.id" " AND remote_sip_address_id = remote_sip_address.id" - " AND remote_sip_address.value = :peerAddress", soci::use(peerAddress); + " AND remote_sip_address.value = :peerAddress", soci::into(localSipAddress), soci::into(remoteSipAddress), + soci::into(imdnMessageId), soci::into(state), soci::into(direction), soci::into(isSecured), + soci::use(peerAddress); // TODO: Create me. - shared_ptr chatMessage; + // TODO: Use cache, do not fetch the same message twice. + shared_ptr chatMessage = make_shared(chatRoom); + + chatMessage->getPrivate()->setState(static_cast(state)); + chatMessage->getPrivate()->setDirection(static_cast(direction)); + chatMessage->setIsSecured(static_cast(isSecured)); + + if (direction == static_cast(ChatMessage::Direction::Outgoing)) { + chatMessage->setFromAddress(Address(localSipAddress)); + chatMessage->setToAddress(Address(remoteSipAddress)); + } else { + chatMessage->setFromAddress(Address(remoteSipAddress)); + chatMessage->setToAddress(Address(localSipAddress)); + } // TODO: Use cache. return make_shared( @@ -867,7 +896,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { list> MainDb::getConferenceNotifiedEvents ( const string &peerAddress, unsigned int lastNotifyId - ) { + ) const { static const string query = "SELECT id, type, date FROM event" " WHERE id IN (" " SELECT event_id FROM conference_notified_event WHERE event_id IN (" @@ -1126,6 +1155,9 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { return list>(); } + shared_ptr core = getCore(); + L_ASSERT(core); + list> chatRooms; L_BEGIN_LOG_EXCEPTION @@ -1135,7 +1167,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { soci::rowset rows = (session->prepare << query); for (const auto &row : rows) { string sipAddress = row.get(0); - shared_ptr chatRoom = d->core->findChatRoom(Address(sipAddress)); + shared_ptr chatRoom = core->findChatRoom(Address(sipAddress)); if (chatRoom) { lInfo() << "Don't fetch chat room from database: `" << sipAddress << "`, it already exists."; chatRooms.push_back(chatRoom); @@ -1155,10 +1187,10 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { (void)lastNotifyId; if (capabilities & static_cast(ChatRoom::Capabilities::Basic)) { - chatRoom = d->core ? d->core->getPrivate()->createChatRoom( + chatRoom = core->getPrivate()->createChatRoom( Address(sipAddress), capabilities & static_cast(ChatRoom::Capabilities::RealTimeText) - ) : nullptr; + ); } else if (capabilities & static_cast(ChatRoom::Capabilities::Conference)) { // TODO: Set sip address and participants. } @@ -1391,7 +1423,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { list> MainDb::getConferenceNotifiedEvents ( const string &peerAddress, unsigned int notifyId - ) { + ) const { return list>(); } diff --git a/src/db/main-db.h b/src/db/main-db.h index 161e6c66f..6fb3ef51c 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -23,6 +23,7 @@ #include #include "abstract/abstract-db.h" +#include "core/core-accessor.h" // ============================================================================= @@ -34,7 +35,7 @@ class Core; class EventLog; class MainDbPrivate; -class LINPHONE_PUBLIC MainDb : public AbstractDb { +class LINPHONE_PUBLIC MainDb : public CoreAccessor, public AbstractDb { public: enum Filter { NoFilter = 0x0, @@ -45,7 +46,7 @@ public: typedef int FilterMask; - MainDb (Core *core); + MainDb (const std::shared_ptr &core); // --------------------------------------------------------------------------- // Generic. @@ -63,7 +64,7 @@ public: std::list> getConferenceNotifiedEvents ( const std::string &peerAddress, unsigned int lastNotifyId - ); + ) const; // --------------------------------------------------------------------------- // Conference chat message events. diff --git a/src/object/object-p.h b/src/object/object-p.h index 842fd3c6f..bcc3b787e 100644 --- a/src/object/object-p.h +++ b/src/object/object-p.h @@ -31,11 +31,8 @@ LINPHONE_BEGIN_NAMESPACE class ObjectPrivate : public BaseObjectPrivate { - friend class ObjectFactory; - private: std::unordered_map properties; - std::weak_ptr weak; L_DECLARE_PUBLIC(Object); }; diff --git a/src/object/object.cpp b/src/object/object.cpp index 179e2392a..e22adb37f 100644 --- a/src/object/object.cpp +++ b/src/object/object.cpp @@ -24,8 +24,6 @@ // ============================================================================= -#define GET_SHARED_FROM_THIS_FATAL_ERROR "Object was not created with `ObjectFactory::create`." - using namespace std; LINPHONE_BEGIN_NAMESPACE @@ -37,24 +35,13 @@ shared_ptr Object::getSharedFromThis () { } shared_ptr Object::getSharedFromThis () const { - shared_ptr object; - try { - object = getPrivate()->weak.lock(); - if (!object) - lFatal() << GET_SHARED_FROM_THIS_FATAL_ERROR; + return shared_from_this(); } catch (const exception &) { - lFatal() << GET_SHARED_FROM_THIS_FATAL_ERROR; + lFatal() << "Object " << this << " was not created with make_shared."; } - return object; -} - -void ObjectFactory::setPublic (const shared_ptr &object) { - L_ASSERT(object); - ObjectPrivate *d = object->getPrivate(); - d->mPublic = object.get(); - d->weak = object; + return nullptr; } LINPHONE_END_NAMESPACE diff --git a/src/object/object.h b/src/object/object.h index 0721cc0ef..f929df63a 100644 --- a/src/object/object.h +++ b/src/object/object.h @@ -34,41 +34,26 @@ LINPHONE_BEGIN_NAMESPACE * Supports properties and shared from this. * Must be built with ObjectFactory. */ -class LINPHONE_PUBLIC Object : public BaseObject, public PropertyContainer { +class LINPHONE_PUBLIC Object : + public std::enable_shared_from_this, + public BaseObject, + public PropertyContainer { friend class ObjectFactory; public: virtual ~Object () = default; -protected: - explicit Object (ObjectPrivate &p); - std::shared_ptr getSharedFromThis (); std::shared_ptr getSharedFromThis () const; +protected: + explicit Object (ObjectPrivate &p); + private: L_DECLARE_PRIVATE(Object); L_DISABLE_COPY(Object); }; -class ObjectFactory { -public: - template - static inline std::shared_ptr create (Args &&...args) { - static_assert(std::is_base_of::value, "Not an object."); - std::shared_ptr object = std::make_shared(args...); - setPublic(object); - return object; - } - -private: - ObjectFactory () = delete; - - static void setPublic (const std::shared_ptr &object); - - L_DISABLE_COPY(ObjectFactory); -}; - LINPHONE_END_NAMESPACE #endif // ifndef _OBJECT_H_ diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index ab0a11d2c..079ff130b 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -395,7 +395,7 @@ static void cpim_chat_message_modifier_base(bool_t use_multipart) { lp_config_set_int(config, "sip", "use_cpim", 1); Address paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); - shared_ptr marieRoom = ObjectFactory::create(marie->lc->cppCore, paulineAddress); + shared_ptr marieRoom = make_shared(marie->lc->cppCore, paulineAddress); shared_ptr marieMessage = marieRoom->createMessage("Hello CPIM"); if (use_multipart) { diff --git a/tester/main-db-tester.cpp b/tester/main-db-tester.cpp index 495671421..99b98de2f 100644 --- a/tester/main-db-tester.cpp +++ b/tester/main-db-tester.cpp @@ -17,9 +17,12 @@ */ #include "address/address.h" +#include "core/core.h" #include "db/main-db.h" #include "event-log/events.h" +#include "private.h" + #include "liblinphone_tester.h" // ============================================================================= @@ -37,14 +40,37 @@ static const string getDatabasePath () { // ----------------------------------------------------------------------------- +class MainDbProvider { +public: + MainDbProvider () { + mCoreManager = linphone_core_manager_new("marie_rc"); + mMainDb = new MainDb(mCoreManager->lc->cppCore->getSharedFromThis()); + BC_ASSERT_TRUE(mMainDb->connect(MainDb::Sqlite3, getDatabasePath())); + } + + ~MainDbProvider () { + delete mMainDb; + linphone_core_manager_destroy(mCoreManager); + } + + const MainDb &getMainDb () { + return *mMainDb; + } + +private: + LinphoneCoreManager *mCoreManager; + MainDb *mMainDb; +}; + +// ----------------------------------------------------------------------------- + static void open_database () { - MainDb mainDb(nullptr); - BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); + MainDbProvider provider; } static void get_events_count () { - MainDb mainDb(nullptr); - BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); + MainDbProvider provider; + const MainDb &mainDb = provider.getMainDb(); BC_ASSERT_EQUAL(mainDb.getEventsCount(), 4994, int, "%d"); BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceCallFilter), 0, int, "%d"); BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceInfoFilter), 18, int, "%d"); @@ -53,22 +79,22 @@ static void get_events_count () { } static void get_messages_count () { - MainDb mainDb(nullptr); - BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); + MainDbProvider provider; + const MainDb &mainDb = provider.getMainDb(); BC_ASSERT_EQUAL(mainDb.getChatMessagesCount(), 4976, int, "%d"); BC_ASSERT_EQUAL(mainDb.getChatMessagesCount("sip:test-39@sip.linphone.org"), 3, int, "%d"); } static void get_unread_messages_count () { - MainDb mainDb(nullptr); - BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); + MainDbProvider provider; + const MainDb &mainDb = provider.getMainDb(); BC_ASSERT_EQUAL(mainDb.getUnreadChatMessagesCount(), 2, int, "%d"); BC_ASSERT_EQUAL(mainDb.getUnreadChatMessagesCount("sip:test-39@sip.linphone.org"), 0, int, "%d"); } static void get_history () { - MainDb mainDb(nullptr); - BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); + MainDbProvider provider; + const MainDb &mainDb = provider.getMainDb(); BC_ASSERT_EQUAL( mainDb.getHistoryRange("sip:test-39@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceChatMessageFilter).size(), 3, @@ -96,8 +122,8 @@ static void get_history () { } static void get_conference_notified_events () { - MainDb mainDb(nullptr); - BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); + MainDbProvider provider; + const MainDb &mainDb = provider.getMainDb(); list> events = mainDb.getConferenceNotifiedEvents("sip:fake-group-2@sip.linphone.org", 1); BC_ASSERT_EQUAL(events.size(), 3, int, "%d"); if (events.size() != 3) diff --git a/tester/multipart-tester.cpp b/tester/multipart-tester.cpp index 4e781281d..f1b6617e6 100644 --- a/tester/multipart-tester.cpp +++ b/tester/multipart-tester.cpp @@ -39,7 +39,7 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer, bool LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc"); Address paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); - shared_ptr marieRoom = ObjectFactory::create(marie->lc->cppCore, paulineAddress); + shared_ptr marieRoom = make_shared(marie->lc->cppCore, paulineAddress); shared_ptr marieMessage; if (first_file_transfer) { From fb18a7c7a9e2cd427cdcebdce3ab8be32723f889 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 3 Nov 2017 11:12:20 +0100 Subject: [PATCH 0674/2215] fix(ChatMessage): remove useless test on getCore --- src/chat/chat-message/chat-message.cpp | 73 ++++++++------------------ src/core/core.cpp | 4 ++ src/core/core.h | 2 + tester/main-db-tester.cpp | 2 +- 4 files changed, 29 insertions(+), 52 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 26e657128..1bc7f2d02 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -642,8 +642,7 @@ void ChatMessagePrivate::processResponseFromPostFile (const belle_http_response_ shared_ptr core = q->getCore(); shared_ptr chatRoom = q->getChatRoom(); - if (core) - imee = linphone_core_get_im_encryption_engine(core->getCCore()); + imee = linphone_core_get_im_encryption_engine(core->getCCore()); if (imee && chatRoom) { LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); @@ -938,9 +937,6 @@ int ChatMessagePrivate::startHttpTransfer ( belle_generic_uri_t *uri = nullptr; shared_ptr core = q->getCore(); - if (!core) - return -1; - const char *ua = linphone_core_get_user_agent(core->getCCore()); if (url.empty()) { @@ -1108,14 +1104,13 @@ LinphoneReason ChatMessagePrivate::receive () { if (errorCode <= 0) { bool foundSupportContentType = false; - if (core) - for (const auto &c : contents) { - if (linphone_core_is_content_type_supported(core->getCCore(), c.getContentType().asString().c_str())) { - foundSupportContentType = true; - break; - } else - lError() << "Unsupported content-type: " << c.getContentType().asString(); - } + for (const auto &c : contents) { + if (linphone_core_is_content_type_supported(core->getCCore(), c.getContentType().asString().c_str())) { + foundSupportContentType = true; + break; + } else + lError() << "Unsupported content-type: " << c.getContentType().asString(); + } if (!foundSupportContentType) { errorCode = 415; @@ -1124,11 +1119,9 @@ LinphoneReason ChatMessagePrivate::receive () { } // Check if this is in fact an outgoing message (case where this is a message sent by us from an other device). - if (core) { - Address me(linphone_core_get_identity(core->getCCore())); - if (me.weakEqual(from)) - setDirection(ChatMessage::Direction::Outgoing); - } + Address me(linphone_core_get_identity(core->getCCore())); + if (me.weakEqual(from)) + setDirection(ChatMessage::Direction::Outgoing); // Check if this is a duplicate message. if (chatRoom && chatRoom->findMessageWithDirection(q->getImdnMessageId(), q->getDirection())) @@ -1174,7 +1167,7 @@ void ChatMessagePrivate::send () { } shared_ptr core = q->getCore(); - if (core && lp_config_get_int(core->getCCore()->config, "sip", "chat_use_call_dialogs", 0) != 0) { + if (lp_config_get_int(core->getCCore()->config, "sip", "chat_use_call_dialogs", 0) != 0) { call = linphone_core_get_call_by_remote_address(core->getCCore(), to.asString().c_str()); if (call) { if (linphone_call_get_state(call) == LinphoneCallConnected || linphone_call_get_state(call) == LinphoneCallStreamsRunning || @@ -1198,7 +1191,7 @@ void ChatMessagePrivate::send () { } } - if (core && !op) { + if (!op) { LinphoneAddress *peer = linphone_address_new(to.asString().c_str()); /* Sending out of call */ salOp = op = new SalMessageOp(core->getCCore()->sal); @@ -1257,7 +1250,7 @@ void ChatMessagePrivate::send () { if ((currentSendStep &ChatMessagePrivate::Step::Cpim) == ChatMessagePrivate::Step::Cpim) { lInfo() << "Cpim step already done, skipping"; } else { - if (core && lp_config_get_int(core->getCCore()->config, "sip", "use_cpim", 0) == 1) { + if (lp_config_get_int(core->getCCore()->config, "sip", "use_cpim", 0) == 1) { CpimChatMessageModifier ccmm; ccmm.encode(q->getSharedFromThis(), errorCode); } @@ -1329,11 +1322,8 @@ shared_ptr ChatMessage::getChatRoom () const { L_D(); shared_ptr chatRoom = d->chatRoom.lock(); - if (!chatRoom) { - shared_ptr core = getCore(); - if (core) - chatRoom = core->getOrCreateBasicChatRoom(d->peerAddress); - } + if (!chatRoom) + chatRoom = getCore()->getOrCreateBasicChatRoom(d->peerAddress); return chatRoom; } @@ -1388,11 +1378,7 @@ void ChatMessage::setImdnMessageId (const string &id) { bool ChatMessage::isRead () const { L_D(); - shared_ptr core = getCore(); - if (!core) - return false; - - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(core->getCCore()); + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(getCore()->getCCore()); if (linphone_im_notif_policy_get_recv_imdn_displayed(policy) && d->state == State::Displayed) return true; @@ -1578,11 +1564,7 @@ void ChatMessage::send () { void ChatMessage::sendDeliveryNotification (LinphoneReason reason) { L_D(); - shared_ptr core = getCore(); - if (!core) - return; - - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(core->getCCore()); + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(getCore()->getCCore()); if (linphone_im_notif_policy_get_send_imdn_delivered(policy)) d->sendImdn(Imdn::Type::Delivery, reason); } @@ -1590,11 +1572,7 @@ void ChatMessage::sendDeliveryNotification (LinphoneReason reason) { void ChatMessage::sendDisplayNotification () { L_D(); - shared_ptr core = getCore(); - if (!core) - return; - - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(core->getCCore()); + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(getCore()->getCCore()); if (linphone_im_notif_policy_get_send_imdn_displayed(policy)) d->sendImdn(Imdn::Type::Display, LinphoneReasonNone); } @@ -1602,10 +1580,6 @@ void ChatMessage::sendDisplayNotification () { int ChatMessage::uploadFile () { L_D(); - shared_ptr core = getCore(); - if (!core) - return -1; - if (d->httpRequest) { lError() << "linphone_chat_room_upload_file(): there is already an upload in progress."; return -1; @@ -1616,7 +1590,7 @@ int ChatMessage::uploadFile () { cbs.process_io_error = _chat_message_process_io_error_upload; cbs.process_auth_requested = _chat_message_process_auth_requested_upload; - int err = d->startHttpTransfer(linphone_core_get_file_transfer_server(core->getCCore()), "POST", &cbs); + int err = d->startHttpTransfer(linphone_core_get_file_transfer_server(getCore()->getCCore()), "POST", &cbs); if (err == -1) d->setState(State::NotDelivered); @@ -1652,8 +1626,8 @@ void ChatMessage::cancelFileTransfer () { } if (!belle_http_request_is_cancelled(d->httpRequest)) { shared_ptr chatRoom = getChatRoom(); - shared_ptr core = getCore(); - if (chatRoom && core) { + if (chatRoom) { + shared_ptr core = getCore(); lInfo() << "Canceling file transfer " << ( d->externalBodyUrl.empty() ? linphone_core_get_file_transfer_server(core->getCCore()) @@ -1674,9 +1648,6 @@ int ChatMessage::putCharacter (uint32_t character) { L_D(); shared_ptr core = getCore(); - if (!core) - return -1; - if (linphone_core_realtime_text_enabled(core->getCCore())) { static const uint32_t new_line = 0x2028; static const uint32_t crlf = 0x0D0A; diff --git a/src/core/core.cpp b/src/core/core.cpp index bd47d7ef0..505cc4c8d 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -34,6 +34,10 @@ LINPHONE_BEGIN_NAMESPACE Core::Core () : Object(*new CorePrivate) {} +Core::~Core () { + lInfo() << "Destroying core: " << this; +} + shared_ptr Core::create (LinphoneCore *cCore) { // Do not use `make_shared` => Private constructor. shared_ptr core = shared_ptr(new Core); diff --git a/src/core/core.h b/src/core/core.h index 0eb899f9a..a56807681 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -42,6 +42,8 @@ class LINPHONE_PUBLIC Core : public Object { public: L_OVERRIDE_SHARED_FROM_THIS(Core); + ~Core (); + // Return a new Core instance. Entry point of Linphone. static std::shared_ptr create (LinphoneCore *cCore); diff --git a/tester/main-db-tester.cpp b/tester/main-db-tester.cpp index 99b98de2f..70b7a2e79 100644 --- a/tester/main-db-tester.cpp +++ b/tester/main-db-tester.cpp @@ -34,7 +34,7 @@ using namespace LinphonePrivate; // ----------------------------------------------------------------------------- static const string getDatabasePath () { - static const string path = string(bc_tester_get_resource_dir_prefix()) + "/db/linphone.db"; + static const string path = string(bc_tester_get_resource_dir_prefix()) + "db/linphone.db"; return path; } From 58d5c632aa1850aae2bb1f1f8dc367e9bdbc682d Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 3 Nov 2017 11:23:32 +0100 Subject: [PATCH 0675/2215] fix(MainDb): remove L_ASSERT(core) --- src/db/main-db.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 40f2be4f0..2c47d5a59 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -287,7 +287,6 @@ MainDb::MainDb (const shared_ptr &core) : CoreAccessor(core), AbstractDb(* L_Q(); shared_ptr core = q->getCore(); - L_ASSERT(core); // TODO: Avoid address creation. shared_ptr chatRoom = core->findChatRoom(Address(peerAddress)); From e26ce48bfdc8653fe1a09c83776edb1de4ee214c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 3 Nov 2017 11:34:02 +0100 Subject: [PATCH 0676/2215] Call chatroom state changed with CreationError state when group chat room fails --- src/chat/chat-room/client-group-chat-room.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index e50b13e35..1d039086e 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -451,8 +451,11 @@ void ClientGroupChatRoom::onCallSessionStateChanged ( dConference->eventHandler->subscribe(getConferenceAddress()); } else if (d->state == ChatRoom::State::TerminationPending) dConference->focus->getPrivate()->getSession()->terminate(); - } else if (state == LinphoneCallReleased && d->state == ChatRoom::State::TerminationPending) + } else if (state == LinphoneCallReleased && d->state == ChatRoom::State::TerminationPending) { onConferenceTerminated(getConferenceAddress()); + } else if (state == LinphoneCallError && d->state == ChatRoom::State::CreationPending) { + d->setState(ChatRoom::State::CreationFailed); + } } LINPHONE_END_NAMESPACE From b18d8a700119b1ac8b94ed2d9ae3d9be42ba3568 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 3 Nov 2017 11:41:51 +0100 Subject: [PATCH 0677/2215] Added missing final slash in Android paths --- src/core/platform-helpers/android-platform-helpers.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/platform-helpers/android-platform-helpers.cpp b/src/core/platform-helpers/android-platform-helpers.cpp index e7eb9f346..194e72275 100644 --- a/src/core/platform-helpers/android-platform-helpers.cpp +++ b/src/core/platform-helpers/android-platform-helpers.cpp @@ -181,7 +181,7 @@ string AndroidPlatformHelpers::getDataPath () { JNIEnv *env = ms_get_jni_env(); jstring jdata_path = (jstring)env->CallObjectMethod(mJavaHelper, mGetDataPathId); const char *data_path = GetStringUTFChars(env, jdata_path); - string dataPath = data_path; + string dataPath = data_path + "/"; ReleaseStringUTFChars(env, jdata_path, data_path); return dataPath; } @@ -190,7 +190,7 @@ string AndroidPlatformHelpers::getConfigPath () { JNIEnv *env = ms_get_jni_env(); jstring jconfig_path = (jstring)env->CallObjectMethod(mJavaHelper, mGetConfigPathId); const char *config_path = GetStringUTFChars(env, jconfig_path); - string configPath = config_path; + string configPath = config_path + "/"; ReleaseStringUTFChars(env, jconfig_path, config_path); return configPath; } From 4a046d10f78b51caf9f77dd42160ecc97430012b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 3 Nov 2017 11:45:01 +0100 Subject: [PATCH 0678/2215] Fixed previous commit --- src/core/platform-helpers/android-platform-helpers.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/platform-helpers/android-platform-helpers.cpp b/src/core/platform-helpers/android-platform-helpers.cpp index 194e72275..9123fb1ef 100644 --- a/src/core/platform-helpers/android-platform-helpers.cpp +++ b/src/core/platform-helpers/android-platform-helpers.cpp @@ -181,18 +181,18 @@ string AndroidPlatformHelpers::getDataPath () { JNIEnv *env = ms_get_jni_env(); jstring jdata_path = (jstring)env->CallObjectMethod(mJavaHelper, mGetDataPathId); const char *data_path = GetStringUTFChars(env, jdata_path); - string dataPath = data_path + "/"; + string dataPath = data_path; ReleaseStringUTFChars(env, jdata_path, data_path); - return dataPath; + return dataPath + "/"; } string AndroidPlatformHelpers::getConfigPath () { JNIEnv *env = ms_get_jni_env(); jstring jconfig_path = (jstring)env->CallObjectMethod(mJavaHelper, mGetConfigPathId); const char *config_path = GetStringUTFChars(env, jconfig_path); - string configPath = config_path + "/"; + string configPath = config_path; ReleaseStringUTFChars(env, jconfig_path, config_path); - return configPath; + return configPath + "/"; } int AndroidPlatformHelpers::callVoidMethod (jmethodID id) { From e7f35139b688e3d11c40d7ebfc4272a7d9057834 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 3 Nov 2017 12:02:44 +0100 Subject: [PATCH 0679/2215] fix(AbstractDb): test correctly IOS backend --- src/db/abstract/abstract-db.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/db/abstract/abstract-db.cpp b/src/db/abstract/abstract-db.cpp index 4c101eb06..e6f688e9d 100644 --- a/src/db/abstract/abstract-db.cpp +++ b/src/db/abstract/abstract-db.cpp @@ -21,6 +21,10 @@ #include #endif // ifdef SOCI_ENABLED +#ifdef __APPLE__ + #include +#endif // ifdef __APPLE__ + #include "abstract-db-p.h" #include "db/session/db-session-provider.h" #include "logger/logger.h" @@ -33,14 +37,19 @@ LINPHONE_BEGIN_NAMESPACE AbstractDb::AbstractDb (AbstractDbPrivate &p) : Object(p) {} -extern "C" void register_factory_sqlite3(); +// Force static sqlite3 linking for IOS and Android. +#if defined(TARGET_OS_IPHONE) || defined(__ANDROID__) + extern "C" void register_factory_sqlite3(); +#endif // defined(TARGET_OS_IPHONE) || defined(__ANDROID__) bool AbstractDb::connect (Backend backend, const string ¶meters) { L_D(); -#if defined(__APPLE__) || defined(__ANDROID__) - if (backend == Sqlite3) - register_factory_sqlite3(); -#endif // defined(__APPLE__) || defined(__ANDROID__)*/ + + #if defined(TARGET_OS_IPHONE) || defined(__ANDROID__) + if (backend == Sqlite3) + register_factory_sqlite3(); + #endif // defined(TARGET_OS_IPHONE) || defined(__ANDROID__) + d->backend = backend; d->dbSession = DbSessionProvider::getInstance()->getSession( (backend == Mysql ? "mysql://" : "sqlite3://") + parameters From 975cfd80482e6f69e6d1fbe4e8059a66ad71b2d0 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 3 Nov 2017 15:55:07 +0100 Subject: [PATCH 0680/2215] correct use of APPLE targets --- src/db/abstract/abstract-db.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/db/abstract/abstract-db.cpp b/src/db/abstract/abstract-db.cpp index e6f688e9d..dee423903 100644 --- a/src/db/abstract/abstract-db.cpp +++ b/src/db/abstract/abstract-db.cpp @@ -38,14 +38,14 @@ LINPHONE_BEGIN_NAMESPACE AbstractDb::AbstractDb (AbstractDbPrivate &p) : Object(p) {} // Force static sqlite3 linking for IOS and Android. -#if defined(TARGET_OS_IPHONE) || defined(__ANDROID__) +#if TARGET_OS_IPHONE || defined(__ANDROID__) extern "C" void register_factory_sqlite3(); -#endif // defined(TARGET_OS_IPHONE) || defined(__ANDROID__) +#endif // TARGET_OS_IPHONE || defined(__ANDROID__) bool AbstractDb::connect (Backend backend, const string ¶meters) { L_D(); - #if defined(TARGET_OS_IPHONE) || defined(__ANDROID__) + #if TARGET_OS_IPHONE || defined(__ANDROID__) if (backend == Sqlite3) register_factory_sqlite3(); #endif // defined(TARGET_OS_IPHONE) || defined(__ANDROID__) From d97c796d26027bb92c49078738c49d8298e7ec4f Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 3 Nov 2017 15:56:19 +0100 Subject: [PATCH 0681/2215] add isFullState info to conference-event-packages-callbacks --- src/chat/chat-room/client-group-chat-room.cpp | 12 +++++----- src/chat/chat-room/client-group-chat-room.h | 12 +++++----- src/conference/conference-listener.h | 12 +++++----- .../local-conference-event-handler-p.h | 2 +- .../local-conference-event-handler.cpp | 6 ++--- .../remote-conference-event-handler.cpp | 13 +++++----- src/conference/remote-conference.cpp | 12 +++++----- src/conference/remote-conference.h | 12 +++++----- tester/conference-event-tester.cpp | 24 +++++++++---------- 9 files changed, 53 insertions(+), 52 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 1d039086e..d24b398ac 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -263,7 +263,7 @@ void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { d->setState(ChatRoom::State::Terminated); } -void ClientGroupChatRoom::onParticipantAdded (time_t tm, const Address &addr) { +void ClientGroupChatRoom::onParticipantAdded (time_t tm, bool isFullState, const Address &addr) { L_D_T(RemoteConference, dConference); if (isMe(addr)) @@ -293,7 +293,7 @@ void ClientGroupChatRoom::onParticipantAdded (time_t tm, const Address &addr) { cb(cr, L_GET_C_BACK_PTR(event)); } -void ClientGroupChatRoom::onParticipantRemoved (time_t tm, const Address &addr) { +void ClientGroupChatRoom::onParticipantRemoved (time_t tm, bool isFullState, const Address &addr) { L_D_T(RemoteConference, dConference); shared_ptr participant = findParticipant(addr); @@ -320,7 +320,7 @@ void ClientGroupChatRoom::onParticipantRemoved (time_t tm, const Address &addr) dConference->participants.remove(participant); } -void ClientGroupChatRoom::onParticipantSetAdmin (time_t tm, const Address &addr, bool isAdmin) { +void ClientGroupChatRoom::onParticipantSetAdmin (time_t tm, bool isFullState, const Address &addr, bool isAdmin) { L_D_T(RemoteConference, dConference); shared_ptr participant; if (isMe(addr)) @@ -349,7 +349,7 @@ void ClientGroupChatRoom::onParticipantSetAdmin (time_t tm, const Address &addr, cb(cr, L_GET_C_BACK_PTR(event)); } -void ClientGroupChatRoom::onSubjectChanged (time_t tm, const std::string &subject) { +void ClientGroupChatRoom::onSubjectChanged (time_t tm, bool isFullState, const std::string &subject) { L_D_T(RemoteConference, dConference); RemoteConference::setSubject(subject); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); @@ -367,7 +367,7 @@ void ClientGroupChatRoom::onSubjectChanged (time_t tm, const std::string &subjec cb(cr, L_GET_C_BACK_PTR(event)); } -void ClientGroupChatRoom::onParticipantDeviceAdded (time_t tm, const Address &addr, const Address &gruu) { +void ClientGroupChatRoom::onParticipantDeviceAdded (time_t tm, bool isFullState, const Address &addr, const Address &gruu) { L_D_T(RemoteConference, dConference); shared_ptr participant; if (isMe(addr)) @@ -396,7 +396,7 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (time_t tm, const Address &ad cb(cr, L_GET_C_BACK_PTR(event)); } -void ClientGroupChatRoom::onParticipantDeviceRemoved (time_t tm, const Address &addr, const Address &gruu) { +void ClientGroupChatRoom::onParticipantDeviceRemoved (time_t tm, bool isFullState, const Address &addr, const Address &gruu) { L_D_T(RemoteConference, dConference); shared_ptr participant; if (isMe(addr)) diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 7ff063a27..e938fcfd5 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -64,12 +64,12 @@ private: /* ConferenceListener */ void onConferenceCreated (const Address &addr) override; void onConferenceTerminated (const Address &addr) override; - void onParticipantAdded (time_t tm, const Address &addr) override; - void onParticipantRemoved (time_t tm, const Address &addr) override; - void onParticipantSetAdmin (time_t tm, const Address &addr, bool isAdmin) override; - void onSubjectChanged (time_t tm, const std::string &subject) override; - void onParticipantDeviceAdded (time_t tm, const Address &addr, const Address &gruu) override; - void onParticipantDeviceRemoved (time_t tm, const Address &addr, const Address &gruu) override; + void onParticipantAdded (time_t tm, bool isFullState, const Address &addr) override; + void onParticipantRemoved (time_t tm, bool isFullState, const Address &addr) override; + void onParticipantSetAdmin (time_t tm, bool isFullState, const Address &addr, bool isAdmin) override; + void onSubjectChanged (time_t tm, bool isFullState, const std::string &subject) override; + void onParticipantDeviceAdded (time_t tm, bool isFullState, const Address &addr, const Address &gruu) override; + void onParticipantDeviceRemoved (time_t tm, bool isFullState, const Address &addr, const Address &gruu) override; private: /* CallSessionListener */ diff --git a/src/conference/conference-listener.h b/src/conference/conference-listener.h index 248052fb6..4bad04c11 100644 --- a/src/conference/conference-listener.h +++ b/src/conference/conference-listener.h @@ -35,12 +35,12 @@ class ConferenceListener { public: virtual void onConferenceCreated (const Address &addr) = 0; virtual void onConferenceTerminated (const Address &addr) = 0; - virtual void onParticipantAdded (time_t tm, const Address &addr) = 0; - virtual void onParticipantRemoved (time_t tm, const Address &addr) = 0; - virtual void onParticipantSetAdmin (time_t tm, const Address &addr, bool isAdmin) = 0; - virtual void onSubjectChanged (time_t tm, const std::string &subject) = 0; - virtual void onParticipantDeviceAdded (time_t tm, const Address &addr, const Address &gruu) = 0; - virtual void onParticipantDeviceRemoved (time_t tm, const Address &addr, const Address &gruu) = 0; + virtual void onParticipantAdded (time_t tm, bool isFullState, const Address &addr) = 0; + virtual void onParticipantRemoved (time_t tm, bool isFullState, const Address &addr) = 0; + virtual void onParticipantSetAdmin (time_t tm, bool isFullState, const Address &addr, bool isAdmin) = 0; + virtual void onSubjectChanged (time_t tm, bool isFullState, const std::string &subject) = 0; + virtual void onParticipantDeviceAdded (time_t tm, bool isFullState, const Address &addr, const Address &gruu) = 0; + virtual void onParticipantDeviceRemoved (time_t tm, bool isFullState, const Address &addr, const Address &gruu) = 0; }; LINPHONE_END_NAMESPACE diff --git a/src/conference/local-conference-event-handler-p.h b/src/conference/local-conference-event-handler-p.h index b194d65c4..88e851bd3 100644 --- a/src/conference/local-conference-event-handler-p.h +++ b/src/conference/local-conference-event-handler-p.h @@ -49,7 +49,7 @@ private: LocalConference *conf = nullptr; unsigned int lastNotify = 0; - std::string createNotify (Xsd::ConferenceInfo::ConferenceType confInfo, int notifyId = -1); + std::string createNotify (Xsd::ConferenceInfo::ConferenceType confInfo, int notifyId = -1, bool isFullState = FALSE); void sendNotify (const std::string ¬ify, const Address &addr); L_DECLARE_PUBLIC(LocalConferenceEventHandler); diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 0eb844d3d..1bf56b528 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -76,14 +76,14 @@ void LocalConferenceEventHandlerPrivate::notifyParticipant (const string ¬ify sendNotify(notify, participant->getAddress()); } -string LocalConferenceEventHandlerPrivate::createNotify (ConferenceType confInfo, int notifyId) { +string LocalConferenceEventHandlerPrivate::createNotify (ConferenceType confInfo, int notifyId, bool isFullState) { if (notifyId == -1) { lastNotify = lastNotify + 1; confInfo.setVersion(lastNotify); } else { confInfo.setVersion(static_cast(notifyId)); } - + confInfo.setState(isFullState ? "full" : "optional"); if (!confInfo.getConferenceDescription()) { ConferenceDescriptionType description = ConferenceDescriptionType(); confInfo.setConferenceDescription(description); @@ -130,7 +130,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyFullState (int notifyId) confInfo.getUsers()->getUser().push_back(user); } - return createNotify(confInfo, notifyId); + return createNotify(confInfo, notifyId, TRUE); } string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const Address &addr, int notifyId) { diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 8c83664bd..21c2f5a7b 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -77,6 +77,7 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { if (confInfo->getConferenceDescription()->getFreeText().present()) tm = static_cast(Utils::stoll(confInfo->getConferenceDescription()->getFreeText().get())); + bool isFullState = (confInfo->getState() == "full"); Address cleanedConfAddress = d->confAddress; cleanedConfAddress.clean(); cleanedConfAddress.setPort(0); @@ -92,7 +93,7 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { confInfo->getConferenceDescription().present() && confInfo->getConferenceDescription().get().getSubject().present() ) - d->listener->onSubjectChanged(tm, confInfo->getConferenceDescription().get().getSubject().get()); + d->listener->onSubjectChanged(tm, isFullState, confInfo->getConferenceDescription().get().getSubject().get()); if (confInfo->getVersion().present()) d->lastNotify = confInfo->getVersion().get(); @@ -106,7 +107,7 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { Address addr(cAddrStr); bctbx_free(cAddrStr); if (user.getState() == "deleted") - d->listener->onParticipantRemoved(tm, addr); + d->listener->onParticipantRemoved(tm, isFullState, addr); else { bool isAdmin = false; if (user.getRoles()) { @@ -118,17 +119,17 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { } } if (user.getState() == "full") - d->listener->onParticipantAdded(tm, addr); - d->listener->onParticipantSetAdmin(tm, addr, isAdmin); + d->listener->onParticipantAdded(tm, isFullState, addr); + d->listener->onParticipantSetAdmin(tm, isFullState, addr, isAdmin); for (const auto &endpoint : user.getEndpoint()) { if (!endpoint.getEntity().present()) break; Address gruu(endpoint.getEntity().get()); if (endpoint.getState() == "deleted") - d->listener->onParticipantDeviceRemoved(tm, addr, gruu); + d->listener->onParticipantDeviceRemoved(tm, isFullState, addr, gruu); else if (endpoint.getState() == "full") - d->listener->onParticipantDeviceAdded(tm, addr, gruu); + d->listener->onParticipantDeviceAdded(tm, isFullState, addr, gruu); } } diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index d746a495f..ff27f5f00 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -89,16 +89,16 @@ void RemoteConference::onConferenceTerminated (const Address &addr) { d->eventHandler->unsubscribe(); } -void RemoteConference::onParticipantAdded (time_t tm, const Address &addr) {} +void RemoteConference::onParticipantAdded (time_t tm, bool isFullState, const Address &addr) {} -void RemoteConference::onParticipantRemoved (time_t tm, const Address &addr) {} +void RemoteConference::onParticipantRemoved (time_t tm, bool isFullState, const Address &addr) {} -void RemoteConference::onParticipantSetAdmin (time_t tm, const Address &addr, bool isAdmin) {} +void RemoteConference::onParticipantSetAdmin (time_t tm, bool isFullState, const Address &addr, bool isAdmin) {} -void RemoteConference::onSubjectChanged (time_t tm, const std::string &subject) {} +void RemoteConference::onSubjectChanged (time_t tm, bool isFullState, const std::string &subject) {} -void RemoteConference::onParticipantDeviceAdded (time_t tm, const Address &addr, const Address &gruu) {} +void RemoteConference::onParticipantDeviceAdded (time_t tm, bool isFullState, const Address &addr, const Address &gruu) {} -void RemoteConference::onParticipantDeviceRemoved (time_t tm, const Address &addr, const Address &gruu) {} +void RemoteConference::onParticipantDeviceRemoved (time_t tm, bool isFullState, const Address &addr, const Address &gruu) {} LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index f1898f10c..5487170f3 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -46,12 +46,12 @@ protected: /* ConferenceListener */ void onConferenceCreated (const Address &addr) override; void onConferenceTerminated (const Address &addr) override; - void onParticipantAdded (time_t tm, const Address &addr) override; - void onParticipantRemoved (time_t tm, const Address &addr) override; - void onParticipantSetAdmin (time_t tm, const Address &addr, bool isAdmin) override; - void onSubjectChanged (time_t tm, const std::string &subject) override; - void onParticipantDeviceAdded (time_t tm, const Address &addr, const Address &gruu) override; - void onParticipantDeviceRemoved (time_t tm, const Address &addr, const Address &gruu) override; + void onParticipantAdded (time_t tm, bool isFullState, const Address &addr) override; + void onParticipantRemoved (time_t tm, bool isFullState, const Address &addr) override; + void onParticipantSetAdmin (time_t tm, bool isFullState, const Address &addr, bool isAdmin) override; + void onSubjectChanged (time_t tm, bool isFullState, const std::string &subject) override; + void onParticipantDeviceAdded (time_t tm, bool isFullState, const Address &addr, const Address &gruu) override; + void onParticipantDeviceRemoved (time_t tm, bool isFullState, const Address &addr, const Address &gruu) override; private: L_DECLARE_PRIVATE(RemoteConference); diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index 437a60387..2d003586a 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -447,12 +447,12 @@ public: private: void onConferenceCreated (const Address &addr) override; void onConferenceTerminated (const Address &addr) override; - void onParticipantAdded (time_t tm, const Address &addr) override; - void onParticipantRemoved (time_t tm, const Address &addr) override; - void onParticipantSetAdmin (time_t tm, const Address &addr, bool isAdmin) override; - void onSubjectChanged (time_t tm, const string &subject) override; - void onParticipantDeviceAdded (time_t tm, const Address &addr, const Address &gruu) override; - void onParticipantDeviceRemoved (time_t tm, const Address &addr, const Address &gruu) override; + void onParticipantAdded (time_t tm, bool isFullState, const Address &addr) override; + void onParticipantRemoved (time_t tm, bool isFullState, const Address &addr) override; + void onParticipantSetAdmin (time_t tm, bool isFullState, const Address &addr, bool isAdmin) override; + void onSubjectChanged (time_t tm, bool isFullState, const string &subject) override; + void onParticipantDeviceAdded (time_t tm, bool isFullState, const Address &addr, const Address &gruu) override; + void onParticipantDeviceRemoved (time_t tm, bool isFullState, const Address &addr, const Address &gruu) override; public: RemoteConferenceEventHandler *handler; @@ -473,33 +473,33 @@ void ConferenceEventTester::onConferenceCreated (const Address &addr) {} void ConferenceEventTester::onConferenceTerminated (const Address &addr) {} -void ConferenceEventTester::onParticipantAdded (time_t tm, const Address &addr) { +void ConferenceEventTester::onParticipantAdded (time_t tm, bool isFullState, const Address &addr) { participants.insert(pair(addr.asString(), FALSE)); participantDevices.insert(pair(addr.asString(), 0)); } -void ConferenceEventTester::onParticipantRemoved (time_t tm, const Address &addr) { +void ConferenceEventTester::onParticipantRemoved (time_t tm, bool isFullState, const Address &addr) { participants.erase(addr.asString()); participantDevices.erase(addr.asString()); } -void ConferenceEventTester::onParticipantSetAdmin (time_t tm, const Address &addr, bool isAdmin) { +void ConferenceEventTester::onParticipantSetAdmin (time_t tm, bool isFullState, const Address &addr, bool isAdmin) { auto it = participants.find(addr.asString()); if (it != participants.end()) it->second = isAdmin; } -void ConferenceEventTester::onSubjectChanged(time_t tm, const string &subject) { +void ConferenceEventTester::onSubjectChanged(time_t tm, bool isFullState, const string &subject) { confSubject = subject; } -void ConferenceEventTester::onParticipantDeviceAdded (time_t tm, const Address &addr, const Address &gruu) { +void ConferenceEventTester::onParticipantDeviceAdded (time_t tm, bool isFullState, const Address &addr, const Address &gruu) { auto it = participantDevices.find(addr.asString()); if (it != participantDevices.end()) it->second++; } -void ConferenceEventTester::onParticipantDeviceRemoved (time_t tm, const Address &addr, const Address &gruu) { +void ConferenceEventTester::onParticipantDeviceRemoved (time_t tm, bool isFullState, const Address &addr, const Address &gruu) { auto it = participantDevices.find(addr.asString()); if (it != participantDevices.end() && it->second > 0) it->second--; From a9c557ae37fb3c7250a9015e360eba9d0046bde2 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 3 Nov 2017 16:59:00 +0100 Subject: [PATCH 0682/2215] Do not store calls made to conference factory inside database --- coreapi/misc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/coreapi/misc.c b/coreapi/misc.c index 41f14fd92..e7e0a0d9e 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -940,6 +940,15 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, void linphone_core_report_call_log(LinphoneCore *lc, LinphoneCallLog *call_log){ bool_t call_logs_sqlite_db_found = FALSE; + // Do not add calls made to the conference factory in the history + char *to = linphone_address_as_string(call_log->to); + const char *conference_factory_uri = linphone_core_get_conference_factory_uri(lc); + if (strcmp(conference_factory_uri, to) == 0) { + ms_free(to); + return; + } + ms_free(to); + #ifdef SQLITE_STORAGE_ENABLED if (lc->logs_db) { call_logs_sqlite_db_found = TRUE; From cb045ce1b10c26078920f9b5bc27db566e9afdb7 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 6 Nov 2017 09:17:47 +0100 Subject: [PATCH 0683/2215] fix(ChatRoom): rename some functions --- src/core/core-chat-room.cpp | 7 ++++--- src/core/core-p.h | 2 +- src/db/main-db.cpp | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index c5d1484d3..91a25a0f2 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -64,7 +64,7 @@ static inline string resolveWorkaroundClientGroupChatRoomAddress ( // ----------------------------------------------------------------------------- -shared_ptr CorePrivate::createChatRoom (const Address &peerAddress, bool isRtt) { +shared_ptr CorePrivate::createBasicChatRoom (const Address &peerAddress, bool isRtt) { L_Q(); shared_ptr chatRoom; @@ -75,7 +75,7 @@ shared_ptr CorePrivate::createChatRoom (const Address &peerAddress, bo chatRoom = make_shared(q->getSharedFromThis(), peerAddress); ChatRoomPrivate *dChatRoom = chatRoom->getPrivate(); - insertChatRoom(chatRoom); + dChatRoom->setState(ChatRoom::State::Instantiated); dChatRoom->setState(ChatRoom::State::Created); @@ -176,7 +176,8 @@ shared_ptr Core::getOrCreateBasicChatRoom (const Address &peerAddress, if (chatRoom) return chatRoom; - chatRoom = d->createChatRoom(peerAddress, isRtt); + chatRoom = d->createBasicChatRoom(peerAddress, isRtt); + d->insertChatRoom(chatRoom); d->insertChatRoomWithDb(chatRoom); return chatRoom; diff --git a/src/core/core-p.h b/src/core/core-p.h index 6b894ce86..c136caf94 100644 --- a/src/core/core-p.h +++ b/src/core/core-p.h @@ -35,7 +35,7 @@ public: void insertChatRoom (const std::shared_ptr &chatRoom); void insertChatRoomWithDb (const std::shared_ptr &chatRoom); - std::shared_ptr createChatRoom (const Address &peerAddress, bool isRtt); + std::shared_ptr createBasicChatRoom (const Address &peerAddress, bool isRtt); private: void deleteChatRoom (const std::string &peerAddress); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 2c47d5a59..5fddd7267 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1186,7 +1186,7 @@ MainDb::MainDb (const shared_ptr &core) : CoreAccessor(core), AbstractDb(* (void)lastNotifyId; if (capabilities & static_cast(ChatRoom::Capabilities::Basic)) { - chatRoom = core->getPrivate()->createChatRoom( + chatRoom = core->getPrivate()->createBasicChatRoom( Address(sipAddress), capabilities & static_cast(ChatRoom::Capabilities::RealTimeText) ); From 1e2d9d9a0eec4041ac8900f9bd35b2236c3afdc1 Mon Sep 17 00:00:00 2001 From: Erwan Croze Date: Mon, 6 Nov 2017 10:46:00 +0100 Subject: [PATCH 0684/2215] Fixing precompiled headers in xml parser --- src/xml/conference-info.cpp | 57 ++++++++++++++++++------------------- src/xml/conference-info.h | 54 +++++++++++++++++------------------ src/xml/resource-lists.cpp | 19 ++++++------- src/xml/resource-lists.h | 32 ++++++++++----------- src/xml/xml.cpp | 11 ++++--- src/xml/xml.h | 2 +- 6 files changed, 86 insertions(+), 89 deletions(-) diff --git a/src/xml/conference-info.cpp b/src/xml/conference-info.cpp index 934688d90..5089051d7 100644 --- a/src/xml/conference-info.cpp +++ b/src/xml/conference-info.cpp @@ -36,7 +36,7 @@ #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" -#ifndef __ANDROID__ +#if __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1) #pragma GCC diagnostic ignored "-Wsuggest-override" #endif #endif @@ -54,7 +54,7 @@ namespace LinphonePrivate namespace ConferenceInfo { // ConferenceType - // + // const ConferenceType::ConferenceDescriptionOptional& ConferenceType:: getConferenceDescription () const @@ -376,7 +376,7 @@ namespace LinphonePrivate // StateType - // + // StateType:: StateType (Value v) @@ -413,7 +413,7 @@ namespace LinphonePrivate StateType& StateType:: operator= (Value v) { - static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = + static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_StateType_literals_[v]); return *this; @@ -421,7 +421,7 @@ namespace LinphonePrivate // ConferenceDescriptionType - // + // const ConferenceDescriptionType::DisplayTextOptional& ConferenceDescriptionType:: getDisplayText () const @@ -707,7 +707,7 @@ namespace LinphonePrivate // HostType - // + // const HostType::DisplayTextOptional& HostType:: getDisplayText () const @@ -849,7 +849,7 @@ namespace LinphonePrivate // ConferenceStateType - // + // const ConferenceStateType::UserCountOptional& ConferenceStateType:: getUserCount () const @@ -973,7 +973,7 @@ namespace LinphonePrivate // ConferenceMediaType - // + // const ConferenceMediaType::EntrySequence& ConferenceMediaType:: getEntry () const @@ -1025,7 +1025,7 @@ namespace LinphonePrivate // ConferenceMediumType - // + // const ConferenceMediumType::DisplayTextOptional& ConferenceMediumType:: getDisplayText () const @@ -1197,7 +1197,7 @@ namespace LinphonePrivate // UrisType - // + // const UrisType::EntrySequence& UrisType:: getEntry () const @@ -1285,7 +1285,7 @@ namespace LinphonePrivate // UriType - // + // const UriType::UriType1& UriType:: getUri () const @@ -1481,7 +1481,7 @@ namespace LinphonePrivate } // UsersType - // + // const UsersType::UserSequence& UsersType:: getUser () const @@ -1587,7 +1587,7 @@ namespace LinphonePrivate // UserType - // + // const UserType::DisplayTextOptional& UserType:: getDisplayText () const @@ -1873,7 +1873,7 @@ namespace LinphonePrivate // UserRolesType - // + // const UserRolesType::EntrySequence& UserRolesType:: getEntry () const @@ -1949,7 +1949,7 @@ namespace LinphonePrivate } // EndpointType - // + // const EndpointType::DisplayTextOptional& EndpointType:: getDisplayText () const @@ -2325,7 +2325,7 @@ namespace LinphonePrivate // EndpointStatusType - // + // EndpointStatusType:: EndpointStatusType (Value v) @@ -2362,7 +2362,7 @@ namespace LinphonePrivate EndpointStatusType& EndpointStatusType:: operator= (Value v) { - static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = + static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_EndpointStatusType_literals_[v]); return *this; @@ -2370,7 +2370,7 @@ namespace LinphonePrivate // JoiningType - // + // JoiningType:: JoiningType (Value v) @@ -2407,7 +2407,7 @@ namespace LinphonePrivate JoiningType& JoiningType:: operator= (Value v) { - static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = + static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_JoiningType_literals_[v]); return *this; @@ -2415,7 +2415,7 @@ namespace LinphonePrivate // DisconnectionType - // + // DisconnectionType:: DisconnectionType (Value v) @@ -2452,7 +2452,7 @@ namespace LinphonePrivate DisconnectionType& DisconnectionType:: operator= (Value v) { - static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = + static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_DisconnectionType_literals_[v]); return *this; @@ -2460,7 +2460,7 @@ namespace LinphonePrivate // ExecutionType - // + // const ExecutionType::WhenOptional& ExecutionType:: getWhen () const @@ -2584,7 +2584,7 @@ namespace LinphonePrivate // CallType - // + // const CallType::SipOptional& CallType:: getSip () const @@ -2666,7 +2666,7 @@ namespace LinphonePrivate // SipDialogIdType - // + // const SipDialogIdType::DisplayTextOptional& SipDialogIdType:: getDisplayText () const @@ -2838,7 +2838,7 @@ namespace LinphonePrivate // MediaType - // + // const MediaType::DisplayTextOptional& MediaType:: getDisplayText () const @@ -3070,7 +3070,7 @@ namespace LinphonePrivate // MediaStatusType - // + // MediaStatusType:: MediaStatusType (Value v) @@ -3107,7 +3107,7 @@ namespace LinphonePrivate MediaStatusType& MediaStatusType:: operator= (Value v) { - static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = + static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_MediaStatusType_literals_[v]); return *this; @@ -3115,7 +3115,7 @@ namespace LinphonePrivate // SidebarsByValType - // + // const SidebarsByValType::EntrySequence& SidebarsByValType:: getEntry () const @@ -9309,4 +9309,3 @@ namespace LinphonePrivate #endif // // End epilogue. - diff --git a/src/xml/conference-info.h b/src/xml/conference-info.h index d748952de..79e9e19c3 100644 --- a/src/xml/conference-info.h +++ b/src/xml/conference-info.h @@ -51,7 +51,7 @@ #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" -#ifndef __ANDROID__ +#if __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1) #pragma GCC diagnostic ignored "-Wsuggest-override" #endif #endif @@ -573,7 +573,7 @@ namespace LinphonePrivate ConferenceType& operator= (const ConferenceType& x); - virtual + virtual ~ConferenceType (); // Implementation. @@ -882,7 +882,7 @@ namespace LinphonePrivate ConferenceDescriptionType& operator= (const ConferenceDescriptionType& x); - virtual + virtual ~ConferenceDescriptionType (); // Implementation. @@ -1030,7 +1030,7 @@ namespace LinphonePrivate HostType& operator= (const HostType& x); - virtual + virtual ~HostType (); // Implementation. @@ -1164,7 +1164,7 @@ namespace LinphonePrivate ConferenceStateType& operator= (const ConferenceStateType& x); - virtual + virtual ~ConferenceStateType (); // Implementation. @@ -1246,7 +1246,7 @@ namespace LinphonePrivate ConferenceMediaType& operator= (const ConferenceMediaType& x); - virtual + virtual ~ConferenceMediaType (); // Implementation. @@ -1406,7 +1406,7 @@ namespace LinphonePrivate ConferenceMediumType& operator= (const ConferenceMediumType& x); - virtual + virtual ~ConferenceMediumType (); // Implementation. @@ -1512,7 +1512,7 @@ namespace LinphonePrivate UrisType& operator= (const UrisType& x); - virtual + virtual ~UrisType (); // Implementation. @@ -1674,7 +1674,7 @@ namespace LinphonePrivate UriType& operator= (const UriType& x); - virtual + virtual ~UriType (); // Implementation. @@ -1730,7 +1730,7 @@ namespace LinphonePrivate _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; - virtual + virtual ~KeywordsType (); }; @@ -1834,7 +1834,7 @@ namespace LinphonePrivate UsersType& operator= (const UsersType& x); - virtual + virtual ~UsersType (); // Implementation. @@ -2080,7 +2080,7 @@ namespace LinphonePrivate UserType& operator= (const UserType& x); - virtual + virtual ~UserType (); // Implementation. @@ -2168,7 +2168,7 @@ namespace LinphonePrivate UserRolesType& operator= (const UserRolesType& x); - virtual + virtual ~UserRolesType (); // Implementation. @@ -2220,7 +2220,7 @@ namespace LinphonePrivate _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; - virtual + virtual ~UserLanguagesType (); }; @@ -2513,7 +2513,7 @@ namespace LinphonePrivate EndpointType& operator= (const EndpointType& x); - virtual + virtual ~EndpointType (); // Implementation. @@ -2828,7 +2828,7 @@ namespace LinphonePrivate ExecutionType& operator= (const ExecutionType& x); - virtual + virtual ~ExecutionType (); // Implementation. @@ -2928,7 +2928,7 @@ namespace LinphonePrivate CallType& operator= (const CallType& x); - virtual + virtual ~CallType (); // Implementation. @@ -3089,7 +3089,7 @@ namespace LinphonePrivate SipDialogIdType& operator= (const SipDialogIdType& x); - virtual + virtual ~SipDialogIdType (); // Implementation. @@ -3295,7 +3295,7 @@ namespace LinphonePrivate MediaType& operator= (const MediaType& x); - virtual + virtual ~MediaType (); // Implementation. @@ -3461,7 +3461,7 @@ namespace LinphonePrivate SidebarsByValType& operator= (const SidebarsByValType& x); - virtual + virtual ~SidebarsByValType (); // Implementation. @@ -3708,14 +3708,14 @@ namespace LinphonePrivate void serializeConferenceInfo (::std::ostream& os, - const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), const ::std::string& e = "UTF-8", ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); void serializeConferenceInfo (::std::ostream& os, - const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& eh, const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), const ::std::string& e = "UTF-8", @@ -3723,7 +3723,7 @@ namespace LinphonePrivate void serializeConferenceInfo (::std::ostream& os, - const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, ::xercesc::DOMErrorHandler& eh, const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), const ::std::string& e = "UTF-8", @@ -3734,14 +3734,14 @@ namespace LinphonePrivate void serializeConferenceInfo (::xercesc::XMLFormatTarget& ft, - const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), const ::std::string& e = "UTF-8", ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); void serializeConferenceInfo (::xercesc::XMLFormatTarget& ft, - const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& eh, const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), const ::std::string& e = "UTF-8", @@ -3749,7 +3749,7 @@ namespace LinphonePrivate void serializeConferenceInfo (::xercesc::XMLFormatTarget& ft, - const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, + const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, ::xercesc::DOMErrorHandler& eh, const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), const ::std::string& e = "UTF-8", @@ -3767,7 +3767,7 @@ namespace LinphonePrivate // ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > - serializeConferenceInfo (const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, + serializeConferenceInfo (const ::LinphonePrivate::Xsd::ConferenceInfo::ConferenceType& x, const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); diff --git a/src/xml/resource-lists.cpp b/src/xml/resource-lists.cpp index df290b542..5d42e0137 100644 --- a/src/xml/resource-lists.cpp +++ b/src/xml/resource-lists.cpp @@ -36,7 +36,7 @@ #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" -#ifndef __ANDROID__ +#if __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1) #pragma GCC diagnostic ignored "-Wsuggest-override" #endif #endif @@ -54,7 +54,7 @@ namespace LinphonePrivate namespace ResourceLists { // ListType - // + // const ListType::DisplayNameOptional& ListType:: getDisplayName () const @@ -238,7 +238,7 @@ namespace LinphonePrivate // EntryType - // + // const EntryType::DisplayNameOptional& EntryType:: getDisplayName () const @@ -350,7 +350,7 @@ namespace LinphonePrivate // EntryRefType - // + // const EntryRefType::DisplayNameOptional& EntryRefType:: getDisplayName () const @@ -462,7 +462,7 @@ namespace LinphonePrivate // ExternalType - // + // const ExternalType::DisplayNameOptional& ExternalType:: getDisplayName () const @@ -574,7 +574,7 @@ namespace LinphonePrivate // DisplayNameType - // + // const DisplayNameType::LangOptional& DisplayNameType:: getLang () const @@ -608,15 +608,15 @@ namespace LinphonePrivate // List - // + // // DisplayName - // + // // ResourceLists - // + // const ResourceLists::ListSequence& ResourceLists:: getList () const @@ -2488,4 +2488,3 @@ namespace LinphonePrivate #endif // // End epilogue. - diff --git a/src/xml/resource-lists.h b/src/xml/resource-lists.h index 9ad3ebc70..1062cfb31 100644 --- a/src/xml/resource-lists.h +++ b/src/xml/resource-lists.h @@ -51,7 +51,7 @@ #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" -#ifndef __ANDROID__ +#if __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1) #pragma GCC diagnostic ignored "-Wsuggest-override" #endif #endif @@ -480,7 +480,7 @@ namespace LinphonePrivate ListType& operator= (const ListType& x); - virtual + virtual ~ListType (); // Implementation. @@ -604,7 +604,7 @@ namespace LinphonePrivate EntryType& operator= (const EntryType& x); - virtual + virtual ~EntryType (); // Implementation. @@ -724,7 +724,7 @@ namespace LinphonePrivate EntryRefType& operator= (const EntryRefType& x); - virtual + virtual ~EntryRefType (); // Implementation. @@ -845,7 +845,7 @@ namespace LinphonePrivate ExternalType& operator= (const ExternalType& x); - virtual + virtual ~ExternalType (); // Implementation. @@ -913,7 +913,7 @@ namespace LinphonePrivate DisplayNameType& operator= (const DisplayNameType& x); - virtual + virtual ~DisplayNameType (); // Implementation. @@ -946,7 +946,7 @@ namespace LinphonePrivate _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; - virtual + virtual ~List (); }; @@ -975,7 +975,7 @@ namespace LinphonePrivate _clone (::LinphonePrivate::Xsd::XmlSchema::Flags f = 0, ::LinphonePrivate::Xsd::XmlSchema::Container* c = 0) const; - virtual + virtual ~DisplayName (); }; @@ -1018,7 +1018,7 @@ namespace LinphonePrivate ResourceLists& operator= (const ResourceLists& x); - virtual + virtual ~ResourceLists (); // Implementation. @@ -1209,14 +1209,14 @@ namespace LinphonePrivate void serializeResourceLists (::std::ostream& os, - const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), const ::std::string& e = "UTF-8", ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); void serializeResourceLists (::std::ostream& os, - const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& eh, const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), const ::std::string& e = "UTF-8", @@ -1224,7 +1224,7 @@ namespace LinphonePrivate void serializeResourceLists (::std::ostream& os, - const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, ::xercesc::DOMErrorHandler& eh, const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), const ::std::string& e = "UTF-8", @@ -1235,14 +1235,14 @@ namespace LinphonePrivate void serializeResourceLists (::xercesc::XMLFormatTarget& ft, - const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), const ::std::string& e = "UTF-8", ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); void serializeResourceLists (::xercesc::XMLFormatTarget& ft, - const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, ::LinphonePrivate::Xsd::XmlSchema::ErrorHandler& eh, const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), const ::std::string& e = "UTF-8", @@ -1250,7 +1250,7 @@ namespace LinphonePrivate void serializeResourceLists (::xercesc::XMLFormatTarget& ft, - const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, + const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, ::xercesc::DOMErrorHandler& eh, const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), const ::std::string& e = "UTF-8", @@ -1268,7 +1268,7 @@ namespace LinphonePrivate // ::LinphonePrivate::Xsd::XmlSchema::dom::unique_ptr< ::xercesc::DOMDocument > - serializeResourceLists (const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, + serializeResourceLists (const ::LinphonePrivate::Xsd::ResourceLists::ResourceLists& x, const ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap& m = ::LinphonePrivate::Xsd::XmlSchema::NamespaceInfomap (), ::LinphonePrivate::Xsd::XmlSchema::Flags f = 0); diff --git a/src/xml/xml.cpp b/src/xml/xml.cpp index 8025cbaec..b8c204909 100644 --- a/src/xml/xml.cpp +++ b/src/xml/xml.cpp @@ -36,7 +36,7 @@ #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" -#ifndef __ANDROID__ +#if __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1) #pragma GCC diagnostic ignored "-Wsuggest-override" #endif #endif @@ -73,7 +73,7 @@ namespace namespace_ } // Space - // + // Space:: Space (Value v) @@ -110,7 +110,7 @@ namespace namespace_ Space& Space:: operator= (Value v) { - static_cast< ::LinphonePrivate::Xsd::XmlSchema::Ncname& > (*this) = + static_cast< ::LinphonePrivate::Xsd::XmlSchema::Ncname& > (*this) = ::LinphonePrivate::Xsd::XmlSchema::Ncname (_xsd_Space_literals_[v]); return *this; @@ -118,7 +118,7 @@ namespace namespace_ // Lang_member - // + // Lang_member:: Lang_member (Value v) @@ -155,7 +155,7 @@ namespace namespace_ Lang_member& Lang_member:: operator= (Value v) { - static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = + static_cast< ::LinphonePrivate::Xsd::XmlSchema::String& > (*this) = ::LinphonePrivate::Xsd::XmlSchema::String (_xsd_Lang_member_literals_[v]); return *this; @@ -458,4 +458,3 @@ namespace namespace_ #endif // // End epilogue. - diff --git a/src/xml/xml.h b/src/xml/xml.h index 4bc12340b..af3c3c3a2 100644 --- a/src/xml/xml.h +++ b/src/xml/xml.h @@ -51,7 +51,7 @@ #if __clang__ || __GNUC__ >= 4 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" -#ifndef __ANDROID__ +#if __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1) #pragma GCC diagnostic ignored "-Wsuggest-override" #endif #endif From af0db8a7eaba3e3c41bbde0e747a3a2d1f4436db Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 6 Nov 2017 11:05:38 +0100 Subject: [PATCH 0685/2215] Added new APIs to manipulate Contents inside ChatMessage --- coreapi/chat_file_transfer.c | 3 -- include/linphone/api/c-chat-message.h | 28 +++++++++++++++++ src/c-wrapper/api/c-chat-message.cpp | 24 +++++++++++++++ src/c-wrapper/api/c-chat-room.cpp | 4 +++ src/chat/chat-message/chat-message.cpp | 42 +++++++++++++++++++++++++- src/chat/chat-message/chat-message.h | 6 ++++ src/chat/chat-room/chat-room.cpp | 3 +- src/content/content.cpp | 2 ++ src/content/content.h | 2 ++ 9 files changed, 108 insertions(+), 6 deletions(-) diff --git a/coreapi/chat_file_transfer.c b/coreapi/chat_file_transfer.c index d3ded3de2..210551f45 100644 --- a/coreapi/chat_file_transfer.c +++ b/coreapi/chat_file_transfer.c @@ -28,6 +28,3 @@ #include "c-wrapper/c-wrapper.h" #include "chat/chat-room/chat-room.h" -LinphoneChatMessage *linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent *initial_content) { - return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createFileTransferMessage(initial_content)); -} diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index 4dabfcf8e..ce5da7eed 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -346,6 +346,34 @@ LINPHONE_PUBLIC LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessag */ LINPHONE_PUBLIC LinphoneChatMessageCbs * linphone_chat_message_get_callbacks(const LinphoneChatMessage *msg); +/** + * Adds a content to the ChatMessage + * @param[in] msg LinphoneChatMessage object + * @param[in] c_content LinphoneContent object + */ +LINPHONE_PUBLIC void linphone_chat_message_add_text_content(LinphoneChatMessage *msg, const LinphoneContent *c_content); + +/** + * Returns true if the chat message has a text content + * @param[in] msg LinphoneChatMessage object + * @return true if it has one, false otherwise + */ +LINPHONE_PUBLIC bool_t linphone_chat_message_has_text_content(const LinphoneChatMessage *msg); + +/** + * Returns true if the chat message has a file transfer content + * @param[in] msg LinphoneChatMessage object + * @return true if it has one, false otherwise + */ +LINPHONE_PUBLIC bool_t linphone_chat_message_has_file_content(const LinphoneChatMessage *msg); + +/** + * Gets the text content if available as a string + * @param[in] msg LinphoneChatMessage object + * @return the LinphoneContent buffer if available, null otherwise + */ +LINPHONE_PUBLIC const char* linphone_chat_message_get_text_content(const LinphoneChatMessage *msg); + /** * @} */ diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 1c0db2089..949ccde7f 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -297,6 +297,30 @@ LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg, uint32_t return ((LinphoneStatus)L_GET_CPP_PTR_FROM_C_OBJECT(msg)->putCharacter(character)); } +void linphone_chat_message_add_text_content(LinphoneChatMessage *msg, const char *c_content) { + LinphonePrivate::Content content; + LinphonePrivate::ContentType contentType = LinphonePrivate::ContentType::PlainText; + content.setContentType(contentType); + content.setBody(L_C_TO_STRING(c_content)); + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->addContent(content); +} + +bool_t linphone_chat_message_has_text_content(const LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->hasTextContent(); +} + +bool_t linphone_chat_message_has_file_content(const LinphoneChatMessage *msg) { + return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->hasFileTransferContent(); +} + +const char * linphone_chat_message_get_text_content(const LinphoneChatMessage *msg) { + LinphonePrivate::Content content = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getTextContent(); + if (content == LinphonePrivate::Content::Empty) { + return NULL; + } + return L_STRING_TO_C(content.getBodyAsString()); +} + // ============================================================================= // Old listener // ============================================================================= diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index d0f25a116..91fac588c 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -305,6 +305,10 @@ bctbx_list_t * linphone_chat_room_get_composing_addresses(LinphoneChatRoom *cr) return result; } +LinphoneChatMessage *linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent *initial_content) { + return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createFileTransferMessage(initial_content)); +} + // ============================================================================= // Reference and user data handling functions. // ============================================================================= diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 1bc7f2d02..be50e0f27 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -1153,7 +1153,7 @@ void ChatMessagePrivate::send () { LinphoneCall *call = nullptr; int errorCode = 0; - if ((currentSendStep &ChatMessagePrivate::Step::FileUpload) == ChatMessagePrivate::Step::FileUpload) { + if ((currentSendStep & ChatMessagePrivate::Step::FileUpload) == ChatMessagePrivate::Step::FileUpload) { lInfo() << "File upload step already done, skipping"; } else { if (getFileTransferInformation()) { @@ -1516,6 +1516,46 @@ void ChatMessage::removeCustomHeader (const string &headerName) { d->customHeaders.erase(headerName); } +bool ChatMessage::hasTextContent() const { + L_D(); + for (const auto &c : d->contents) { + if (c.getContentType() == ContentType::PlainText) { + return true; + } + } + return false; +} + +const Content &ChatMessage::getTextContent() const { + L_D(); + for (const auto &c : d->contents) { + if (c.getContentType() == ContentType::PlainText) { + return c; + } + } + return Content::Empty; +} + +bool ChatMessage::hasFileTransferContent() const { + L_D(); + for (const auto &c : d->contents) { + if (c.getContentType() == ContentType::FileTransfer) { + return true; + } + } + return false; +} + +const Content &ChatMessage::getFileTransferContent() const { + L_D(); + for (const auto &c : d->contents) { + if (c.getContentType() == ContentType::FileTransfer) { + return c; + } + } + return Content::Empty; +} + // ----------------------------------------------------------------------------- void ChatMessage::store () { diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index 00c41df82..f4227665c 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -102,6 +102,12 @@ public: void addContent (const Content &content); void removeContent (const Content &content); + bool hasTextContent() const; + const Content &getTextContent() const; + + bool hasFileTransferContent() const; + const Content &getFileTransferContent() const; + const Content &getInternalContent () const; void setInternalContent (const Content &content); diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 03bd1950f..3d085d61d 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -458,8 +458,7 @@ void ChatRoom::compose () { shared_ptr ChatRoom::createFileTransferMessage (const LinphoneContent *initialContent) { shared_ptr chatMessage = createMessage(); - /* TODO - Content content; + /*Content content; content.setContentType(ContentType::FileTransfer); content.setBody(linphone_content_get_string_buffer(initialContent)); chatMessage->addContent(content);*/ diff --git a/src/content/content.cpp b/src/content/content.cpp index 7a28ad53e..978f5db3b 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -35,6 +35,8 @@ public: string contentDisposition; }; +const Content Content::Empty; + // ----------------------------------------------------------------------------- Content::Content () : ClonableObject(*new ContentPrivate) {} diff --git a/src/content/content.h b/src/content/content.h index 7f73b83f5..3e5f5fb8d 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -63,6 +63,8 @@ public: bool isEmpty () const; + static const Content Empty; + private: L_DECLARE_PRIVATE(Content); }; From eb33a86e2122da879f193d9326402e4b8766b768 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 6 Nov 2017 11:13:44 +0100 Subject: [PATCH 0686/2215] Fixed wrong type in header --- include/linphone/api/c-chat-message.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index ce5da7eed..af7aae13d 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -351,7 +351,7 @@ LINPHONE_PUBLIC LinphoneChatMessageCbs * linphone_chat_message_get_callbacks(con * @param[in] msg LinphoneChatMessage object * @param[in] c_content LinphoneContent object */ -LINPHONE_PUBLIC void linphone_chat_message_add_text_content(LinphoneChatMessage *msg, const LinphoneContent *c_content); +LINPHONE_PUBLIC void linphone_chat_message_add_text_content(LinphoneChatMessage *msg, const char *c_content); /** * Returns true if the chat message has a text content From 7b06d0109799c934b84f2c55ba3da5c4f9ad2329 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 6 Nov 2017 11:24:40 +0100 Subject: [PATCH 0687/2215] use bool instead of bool_t in c++ --- src/conference/local-conference-event-handler-p.h | 2 +- src/conference/local-conference-event-handler.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/conference/local-conference-event-handler-p.h b/src/conference/local-conference-event-handler-p.h index 88e851bd3..88e26d437 100644 --- a/src/conference/local-conference-event-handler-p.h +++ b/src/conference/local-conference-event-handler-p.h @@ -49,7 +49,7 @@ private: LocalConference *conf = nullptr; unsigned int lastNotify = 0; - std::string createNotify (Xsd::ConferenceInfo::ConferenceType confInfo, int notifyId = -1, bool isFullState = FALSE); + std::string createNotify (Xsd::ConferenceInfo::ConferenceType confInfo, int notifyId = -1, bool isFullState = false); void sendNotify (const std::string ¬ify, const Address &addr); L_DECLARE_PUBLIC(LocalConferenceEventHandler); diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 1bf56b528..6ff0222f2 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -130,7 +130,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyFullState (int notifyId) confInfo.getUsers()->getUser().push_back(user); } - return createNotify(confInfo, notifyId, TRUE); + return createNotify(confInfo, notifyId, true); } string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const Address &addr, int notifyId) { From c0363431518d009535266d928a8e08bd3c186e11 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 6 Nov 2017 11:45:13 +0100 Subject: [PATCH 0688/2215] Added a test for file transfer with text content --- src/chat/chat-message/chat-message.cpp | 6 +++ tester/message_tester.c | 62 ++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index be50e0f27..b893a0886 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -761,6 +761,12 @@ void ChatMessagePrivate::processResponseFromPostFile (const belle_http_response_ setText(body); } setContentType(ContentType::FileTransfer); + + Content fileTransferContent; + fileTransferContent.setContentType(ContentType::FileTransfer); + fileTransferContent.setBody(linphone_content_get_string_buffer(cFileTransferInformation)); + q->addContent(fileTransferContent); + q->updateState(ChatMessage::State::FileTransferDone); releaseHttpRequest(); send(); diff --git a/tester/message_tester.c b/tester/message_tester.c index 62efe5b44..0cf6d26b4 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -2306,7 +2306,69 @@ void im_encryption_engine_b64_async(void) { im_encryption_engine_b64_base(TRUE); } +void file_and_text_message(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc"); + + char *send_filepath = bc_tester_res("sounds/sintel_trailer_opus_h264.mkv"); + char *receive_filepath = bc_tester_file("receive_file.dump"); + LinphoneChatRoom* chat_room; + LinphoneChatMessage* msg; + LinphoneChatMessageCbs *cbs; + + /* Remove any previously downloaded file */ + remove(receive_filepath); + + /* Globally configure an http file transfer server. */ + linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php"); + + /* create a chatroom on pauline's side */ + chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + + /* create a file transfer msg */ + msg = create_file_transfer_message_from_sintel_trailer(chat_room); + linphone_chat_message_add_text_content(msg, "Text message"); + + BC_ASSERT_TRUE(linphone_chat_message_has_text_content(msg)); + BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text_content(msg), "Text message"); + BC_ASSERT_FALSE(linphone_chat_message_has_file_content(msg)); + + linphone_chat_room_send_chat_message(chat_room, msg); + + BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageReceivedWithFile, 1, 60000)); + if (marie->stat.last_received_chat_message) { + LinphoneChatMessage *recv_msg; + recv_msg = marie->stat.last_received_chat_message; + + BC_ASSERT_TRUE(linphone_chat_message_has_text_content(recv_msg)); + BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text_content(recv_msg), "Text message"); + BC_ASSERT_TRUE(linphone_chat_message_has_file_content(recv_msg)); + + cbs = linphone_chat_message_get_callbacks(recv_msg); + linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_message_cbs_set_file_transfer_recv(cbs, file_transfer_received); + linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication); + linphone_chat_message_set_file_transfer_filepath(recv_msg, receive_filepath); + linphone_chat_message_download_file(recv_msg); + + /* wait for a long time in case the DNS SRV resolution takes times - it should be immediate though */ + if (BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneFileTransferDownloadSuccessful, 1, 55000))) { + compare_files(send_filepath, receive_filepath); + } + } + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress, 2, int, "%d"); //sent twice because of file transfer + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageDelivered, 1, int, "%d"); + + remove(receive_filepath); + bc_free(send_filepath); + bc_free(receive_filepath); + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); +} + test_t message_tests[] = { + TEST_NO_TAG("File + Text message", file_and_text_message), TEST_NO_TAG("Text message", text_message), TEST_NO_TAG("Text message within call dialog", text_message_within_call_dialog), TEST_NO_TAG("Text message with credentials from auth callback", text_message_with_credential_from_auth_callback), From c1ceea6c2d2c84fc3eb274d30203e7b655adeccc Mon Sep 17 00:00:00 2001 From: Erwan Croze Date: Mon, 6 Nov 2017 11:58:21 +0100 Subject: [PATCH 0689/2215] Fix database init --- src/core/core.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 505cc4c8d..4e294ec3f 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -48,9 +48,9 @@ shared_ptr Core::create (LinphoneCore *cCore) { d->mainDb.reset(new MainDb(core->getSharedFromThis())); AbstractDb::Backend backend; - string uri = L_C_TO_STRING(lp_config_get_string(linphone_core_get_config(d->cCore), "storage", "backend", nullptr)); + string uri = L_C_TO_STRING(lp_config_get_string(linphone_core_get_config(d->cCore), "storage", "uri", nullptr)); if (!uri.empty()) - backend = strcmp(lp_config_get_string(linphone_core_get_config(d->cCore), "storage", "uri", nullptr), "mysql") == 0 + backend = strcmp(lp_config_get_string(linphone_core_get_config(d->cCore), "storage", "backend", nullptr), "mysql") == 0 ? MainDb::Mysql : MainDb::Sqlite3; else { From bea9b7f3d9a823bceea7f70c39ba1d9228646a46 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 6 Nov 2017 13:36:18 +0100 Subject: [PATCH 0690/2215] uses event directly in internal conference callbacks --- src/chat/chat-room/client-group-chat-room.cpp | 72 ++++--------------- src/chat/chat-room/client-group-chat-room.h | 12 ++-- src/conference/conference-listener.h | 13 ++-- .../local-conference-event-handler.cpp | 22 +++--- .../remote-conference-event-handler.cpp | 71 ++++++++++++++---- .../remote-conference-event-handler.h | 2 +- src/conference/remote-conference.cpp | 12 ++-- src/conference/remote-conference.h | 12 ++-- src/db/main-db.cpp | 3 + .../conference/conference-notified-event-p.h | 1 + .../conference/conference-notified-event.cpp | 9 +++ .../conference/conference-notified-event.h | 9 ++- .../conference-participant-device-event.cpp | 2 + .../conference-participant-device-event.h | 1 + .../conference-participant-event.cpp | 20 +++++- .../conference/conference-participant-event.h | 2 + .../conference/conference-subject-event.cpp | 2 + .../conference/conference-subject-event.h | 1 + tester/CMakeLists.txt | 2 +- tester/conference-event-tester.cpp | 43 ++++++----- tester/tester.c | 2 +- 21 files changed, 182 insertions(+), 131 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index d24b398ac..29b77d680 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -263,9 +263,10 @@ void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { d->setState(ChatRoom::State::Terminated); } -void ClientGroupChatRoom::onParticipantAdded (time_t tm, bool isFullState, const Address &addr) { +void ClientGroupChatRoom::onParticipantAdded (shared_ptr event) { L_D_T(RemoteConference, dConference); + const Address &addr = event->getParticipantAddress(); if (isMe(addr)) return; @@ -280,22 +281,16 @@ void ClientGroupChatRoom::onParticipantAdded (time_t tm, bool isFullState, const LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAddedCb cb = linphone_chat_room_cbs_get_participant_added(cbs); - shared_ptr event = make_shared( - EventLog::Type::ConferenceParticipantAdded, - tm, - dConference->conferenceAddress, - dConference->eventHandler->getLastNotify(), - addr - ); Conference::getCore()->cppCore->getPrivate()->mainDb->addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(event)); } -void ClientGroupChatRoom::onParticipantRemoved (time_t tm, bool isFullState, const Address &addr) { +void ClientGroupChatRoom::onParticipantRemoved (shared_ptr event) { L_D_T(RemoteConference, dConference); + const Address &addr = event->getParticipantAddress(); shared_ptr participant = findParticipant(addr); if (!participant) { lWarning() << "Participant " << addr.asString() << " removed but not in the list of participants!"; @@ -305,13 +300,6 @@ void ClientGroupChatRoom::onParticipantRemoved (time_t tm, bool isFullState, con LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantRemovedCb cb = linphone_chat_room_cbs_get_participant_removed(cbs); - shared_ptr event = make_shared( - EventLog::Type::ConferenceParticipantRemoved, - tm, - dConference->conferenceAddress, - dConference->eventHandler->getLastNotify(), - addr - ); Conference::getCore()->cppCore->getPrivate()->mainDb->addEvent(event); if (cb) @@ -320,8 +308,8 @@ void ClientGroupChatRoom::onParticipantRemoved (time_t tm, bool isFullState, con dConference->participants.remove(participant); } -void ClientGroupChatRoom::onParticipantSetAdmin (time_t tm, bool isFullState, const Address &addr, bool isAdmin) { - L_D_T(RemoteConference, dConference); +void ClientGroupChatRoom::onParticipantSetAdmin (shared_ptr event) { + const Address &addr = event->getParticipantAddress(); shared_ptr participant; if (isMe(addr)) participant = getMe(); @@ -332,43 +320,29 @@ void ClientGroupChatRoom::onParticipantSetAdmin (time_t tm, bool isFullState, co return; } - participant->getPrivate()->setAdmin(isAdmin); + participant->getPrivate()->setAdmin(event->getType() == EventLog::Type::ConferenceParticipantSetAdmin); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAdminStatusChangedCb cb = linphone_chat_room_cbs_get_participant_admin_status_changed(cbs); - shared_ptr event = make_shared( - isAdmin ? EventLog::Type::ConferenceParticipantSetAdmin : EventLog::Type::ConferenceParticipantUnsetAdmin, - tm, - dConference->conferenceAddress, - dConference->eventHandler->getLastNotify(), - addr - ); Conference::getCore()->cppCore->getPrivate()->mainDb->addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(event)); } -void ClientGroupChatRoom::onSubjectChanged (time_t tm, bool isFullState, const std::string &subject) { - L_D_T(RemoteConference, dConference); - RemoteConference::setSubject(subject); +void ClientGroupChatRoom::onSubjectChanged (shared_ptr event) { + RemoteConference::setSubject(event->getSubject()); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsSubjectChangedCb cb = linphone_chat_room_cbs_get_subject_changed(cbs); - shared_ptr event = make_shared( - tm, - dConference->conferenceAddress, - dConference->eventHandler->getLastNotify(), - subject - ); Conference::getCore()->cppCore->getPrivate()->mainDb->addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(event)); } -void ClientGroupChatRoom::onParticipantDeviceAdded (time_t tm, bool isFullState, const Address &addr, const Address &gruu) { - L_D_T(RemoteConference, dConference); +void ClientGroupChatRoom::onParticipantDeviceAdded (shared_ptr event) { + const Address &addr = event->getParticipantAddress(); shared_ptr participant; if (isMe(addr)) participant = getMe(); @@ -378,26 +352,18 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (time_t tm, bool isFullState, lWarning() << "Participant " << participant << " added a device but is not in the list of participants!"; return; } - participant->getPrivate()->addDevice(gruu); + participant->getPrivate()->addDevice(event->getGruuAddress()); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantDeviceAddedCb cb = linphone_chat_room_cbs_get_participant_device_added(cbs); - shared_ptr event = make_shared( - EventLog::Type::ConferenceParticipantDeviceAdded, - tm, - dConference->conferenceAddress, - dConference->eventHandler->getLastNotify(), - addr, - gruu - ); Conference::getCore()->cppCore->getPrivate()->mainDb->addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(event)); } -void ClientGroupChatRoom::onParticipantDeviceRemoved (time_t tm, bool isFullState, const Address &addr, const Address &gruu) { - L_D_T(RemoteConference, dConference); +void ClientGroupChatRoom::onParticipantDeviceRemoved (shared_ptr event) { + const Address &addr = event->getParticipantAddress(); shared_ptr participant; if (isMe(addr)) participant = getMe(); @@ -407,18 +373,10 @@ void ClientGroupChatRoom::onParticipantDeviceRemoved (time_t tm, bool isFullStat lWarning() << "Participant " << participant << " removed a device but is not in the list of participants!"; return; } - participant->getPrivate()->removeDevice(gruu); + participant->getPrivate()->removeDevice(event->getGruuAddress()); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantDeviceRemovedCb cb = linphone_chat_room_cbs_get_participant_device_removed(cbs); - shared_ptr event = make_shared( - EventLog::Type::ConferenceParticipantDeviceRemoved, - tm, - dConference->conferenceAddress, - dConference->eventHandler->getLastNotify(), - addr, - gruu - ); Conference::getCore()->cppCore->getPrivate()->mainDb->addEvent(event); if (cb) diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index e938fcfd5..9d96aac54 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -64,12 +64,12 @@ private: /* ConferenceListener */ void onConferenceCreated (const Address &addr) override; void onConferenceTerminated (const Address &addr) override; - void onParticipantAdded (time_t tm, bool isFullState, const Address &addr) override; - void onParticipantRemoved (time_t tm, bool isFullState, const Address &addr) override; - void onParticipantSetAdmin (time_t tm, bool isFullState, const Address &addr, bool isAdmin) override; - void onSubjectChanged (time_t tm, bool isFullState, const std::string &subject) override; - void onParticipantDeviceAdded (time_t tm, bool isFullState, const Address &addr, const Address &gruu) override; - void onParticipantDeviceRemoved (time_t tm, bool isFullState, const Address &addr, const Address &gruu) override; + void onParticipantAdded (std::shared_ptr event) override; + void onParticipantRemoved (std::shared_ptr event) override; + void onParticipantSetAdmin (std::shared_ptr event) override; + void onSubjectChanged (std::shared_ptr event) override; + void onParticipantDeviceAdded (std::shared_ptr event) override; + void onParticipantDeviceRemoved (std::shared_ptr event) override; private: /* CallSessionListener */ diff --git a/src/conference/conference-listener.h b/src/conference/conference-listener.h index 4bad04c11..fe0dbc90d 100644 --- a/src/conference/conference-listener.h +++ b/src/conference/conference-listener.h @@ -23,6 +23,7 @@ #include #include +#include "event-log/events.h" #include "linphone/utils/general.h" // ============================================================================= @@ -35,12 +36,12 @@ class ConferenceListener { public: virtual void onConferenceCreated (const Address &addr) = 0; virtual void onConferenceTerminated (const Address &addr) = 0; - virtual void onParticipantAdded (time_t tm, bool isFullState, const Address &addr) = 0; - virtual void onParticipantRemoved (time_t tm, bool isFullState, const Address &addr) = 0; - virtual void onParticipantSetAdmin (time_t tm, bool isFullState, const Address &addr, bool isAdmin) = 0; - virtual void onSubjectChanged (time_t tm, bool isFullState, const std::string &subject) = 0; - virtual void onParticipantDeviceAdded (time_t tm, bool isFullState, const Address &addr, const Address &gruu) = 0; - virtual void onParticipantDeviceRemoved (time_t tm, bool isFullState, const Address &addr, const Address &gruu) = 0; + virtual void onParticipantAdded (std::shared_ptr event) = 0; + virtual void onParticipantRemoved (std::shared_ptr event) = 0; + virtual void onParticipantSetAdmin (std::shared_ptr event) = 0; + virtual void onSubjectChanged (std::shared_ptr event) = 0; + virtual void onParticipantDeviceAdded (std::shared_ptr event) = 0; + virtual void onParticipantDeviceRemoved (std::shared_ptr event) = 0; }; LINPHONE_END_NAMESPACE diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 6ff0222f2..b731aba69 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -83,7 +83,7 @@ string LocalConferenceEventHandlerPrivate::createNotify (ConferenceType confInfo } else { confInfo.setVersion(static_cast(notifyId)); } - confInfo.setState(isFullState ? "full" : "optional"); + confInfo.setState(isFullState ? StateType::full : StateType::partial); if (!confInfo.getConferenceDescription()) { ConferenceDescriptionType description = ConferenceDescriptionType(); confInfo.setConferenceDescription(description); @@ -117,13 +117,13 @@ string LocalConferenceEventHandlerPrivate::createNotifyFullState (int notifyId) user.setEndpoint(endpoints); user.setEntity(participant->getAddress().asStringUriOnly()); user.getRoles()->getEntry().push_back(participant->isAdmin() ? "admin" : "participant"); - user.setState("full"); + user.setState(StateType::full); for (const auto &device : participant->getPrivate()->getDevices()) { const string &gruu = device.getGruu().asStringUriOnly(); EndpointType endpoint = EndpointType(); endpoint.setEntity(gruu); - endpoint.setState("full"); + endpoint.setState(StateType::full); user.getEndpoint().push_back(endpoint); } @@ -148,7 +148,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const A const string &gruu = device.getGruu().asStringUriOnly(); EndpointType endpoint = EndpointType(); endpoint.setEntity(gruu); - endpoint.setState("full"); + endpoint.setState(StateType::full); user.getEndpoint().push_back(endpoint); } } @@ -156,7 +156,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const A user.setRoles(roles); user.setEntity(addr.asStringUriOnly()); user.getRoles()->getEntry().push_back("participant"); - user.setState("full"); + user.setState(StateType::full); confInfo.getUsers()->getUser().push_back(user); @@ -171,7 +171,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved (const UserType user = UserType(); user.setEntity(addr.asStringUriOnly()); - user.setState("deleted"); + user.setState(StateType::deleted); confInfo.getUsers()->getUser().push_back(user); return createNotify(confInfo, notifyId); @@ -188,7 +188,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined (const user.setRoles(roles); user.setEntity(addr.asStringUriOnly()); user.getRoles()->getEntry().push_back(isAdmin ? "admin" : "participant"); - user.setState("partial"); + user.setState(StateType::partial); confInfo.getUsers()->getUser().push_back(user); return createNotify(confInfo, notifyId); @@ -217,11 +217,11 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceAdded (c user.setRoles(roles); user.setEntity(addr.asStringUriOnly()); user.getRoles()->getEntry().push_back("participant"); - user.setState("partial"); + user.setState(StateType::partial); EndpointType endpoint = EndpointType(); endpoint.setEntity(gruu.asStringUriOnly()); - endpoint.setState("full"); + endpoint.setState(StateType::full); user.getEndpoint().push_back(endpoint); confInfo.getUsers()->getUser().push_back(user); @@ -241,11 +241,11 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceRemoved user.setRoles(roles); user.setEntity(addr.asStringUriOnly()); user.getRoles()->getEntry().push_back("participant"); - user.setState("partial"); + user.setState(StateType::partial); EndpointType endpoint = EndpointType(); endpoint.setEntity(gruu.asStringUriOnly()); - endpoint.setState("deleted"); + endpoint.setState(StateType::deleted); user.getEndpoint().push_back(endpoint); confInfo.getUsers()->getUser().push_back(user); diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 21c2f5a7b..180d7e27b 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -77,7 +77,7 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { if (confInfo->getConferenceDescription()->getFreeText().present()) tm = static_cast(Utils::stoll(confInfo->getConferenceDescription()->getFreeText().get())); - bool isFullState = (confInfo->getState() == "full"); + bool isFullState = (confInfo->getState() == StateType::full); Address cleanedConfAddress = d->confAddress; cleanedConfAddress.clean(); cleanedConfAddress.setPort(0); @@ -93,8 +93,13 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { confInfo->getConferenceDescription().present() && confInfo->getConferenceDescription().get().getSubject().present() ) - d->listener->onSubjectChanged(tm, isFullState, confInfo->getConferenceDescription().get().getSubject().get()); - + d->listener->onSubjectChanged(make_shared( + tm, + isFullState, + d->confAddress, + d->lastNotify, + confInfo->getConferenceDescription().get().getSubject().get() + )); if (confInfo->getVersion().present()) d->lastNotify = confInfo->getVersion().get(); @@ -106,9 +111,16 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { char *cAddrStr = linphone_address_as_string(cAddr); Address addr(cAddrStr); bctbx_free(cAddrStr); - if (user.getState() == "deleted") - d->listener->onParticipantRemoved(tm, isFullState, addr); - else { + if (user.getState() == StateType::deleted) { + d->listener->onParticipantRemoved(make_shared( + EventLog::Type::ConferenceParticipantRemoved, + tm, + isFullState, + d->confAddress, + d->lastNotify, + addr + )); + } else { bool isAdmin = false; if (user.getRoles()) { for (const auto &entry : user.getRoles()->getEntry()) { @@ -118,19 +130,50 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { } } } - if (user.getState() == "full") - d->listener->onParticipantAdded(tm, isFullState, addr); - d->listener->onParticipantSetAdmin(tm, isFullState, addr, isAdmin); + if (user.getState() == StateType::full) { + d->listener->onParticipantAdded(make_shared( + EventLog::Type::ConferenceParticipantAdded, + tm, + isFullState, + d->confAddress, + d->lastNotify, + addr + )); + } + d->listener->onParticipantSetAdmin(make_shared( + isAdmin ? EventLog::Type::ConferenceParticipantSetAdmin : EventLog::Type::ConferenceParticipantUnsetAdmin, + tm, + isFullState, + d->confAddress, + d->lastNotify, + addr + )); for (const auto &endpoint : user.getEndpoint()) { if (!endpoint.getEntity().present()) break; Address gruu(endpoint.getEntity().get()); - if (endpoint.getState() == "deleted") - d->listener->onParticipantDeviceRemoved(tm, isFullState, addr, gruu); - else if (endpoint.getState() == "full") - d->listener->onParticipantDeviceAdded(tm, isFullState, addr, gruu); - + if (endpoint.getState() == StateType::deleted) { + d->listener->onParticipantDeviceRemoved(make_shared( + EventLog::Type::ConferenceParticipantDeviceRemoved, + tm, + isFullState, + d->confAddress, + d->lastNotify, + addr, + gruu + )); + } else if (endpoint.getState() == StateType::full) { + d->listener->onParticipantDeviceAdded(make_shared( + EventLog::Type::ConferenceParticipantDeviceAdded, + tm, + isFullState, + d->confAddress, + d->lastNotify, + addr, + gruu + )); + } } } linphone_address_unref(cAddr); diff --git a/src/conference/remote-conference-event-handler.h b/src/conference/remote-conference-event-handler.h index 993c1c9e2..b6cb6949f 100644 --- a/src/conference/remote-conference-event-handler.h +++ b/src/conference/remote-conference-event-handler.h @@ -22,8 +22,8 @@ #include -#include "object/object.h" #include "conference-listener.h" +#include "object/object.h" LINPHONE_BEGIN_NAMESPACE diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index ff27f5f00..68b6b990f 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -89,16 +89,16 @@ void RemoteConference::onConferenceTerminated (const Address &addr) { d->eventHandler->unsubscribe(); } -void RemoteConference::onParticipantAdded (time_t tm, bool isFullState, const Address &addr) {} +void RemoteConference::onParticipantAdded (std::shared_ptr event) {} -void RemoteConference::onParticipantRemoved (time_t tm, bool isFullState, const Address &addr) {} +void RemoteConference::onParticipantRemoved (std::shared_ptr event) {} -void RemoteConference::onParticipantSetAdmin (time_t tm, bool isFullState, const Address &addr, bool isAdmin) {} +void RemoteConference::onParticipantSetAdmin (std::shared_ptr event) {} -void RemoteConference::onSubjectChanged (time_t tm, bool isFullState, const std::string &subject) {} +void RemoteConference::onSubjectChanged (std::shared_ptr event) {} -void RemoteConference::onParticipantDeviceAdded (time_t tm, bool isFullState, const Address &addr, const Address &gruu) {} +void RemoteConference::onParticipantDeviceAdded (std::shared_ptr event) {} -void RemoteConference::onParticipantDeviceRemoved (time_t tm, bool isFullState, const Address &addr, const Address &gruu) {} +void RemoteConference::onParticipantDeviceRemoved (std::shared_ptr event) {} LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index 5487170f3..9b4e40c8d 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -46,12 +46,12 @@ protected: /* ConferenceListener */ void onConferenceCreated (const Address &addr) override; void onConferenceTerminated (const Address &addr) override; - void onParticipantAdded (time_t tm, bool isFullState, const Address &addr) override; - void onParticipantRemoved (time_t tm, bool isFullState, const Address &addr) override; - void onParticipantSetAdmin (time_t tm, bool isFullState, const Address &addr, bool isAdmin) override; - void onSubjectChanged (time_t tm, bool isFullState, const std::string &subject) override; - void onParticipantDeviceAdded (time_t tm, bool isFullState, const Address &addr, const Address &gruu) override; - void onParticipantDeviceRemoved (time_t tm, bool isFullState, const Address &addr, const Address &gruu) override; + void onParticipantAdded (std::shared_ptr event) override; + void onParticipantRemoved (std::shared_ptr event) override; + void onParticipantSetAdmin (std::shared_ptr event) override; + void onSubjectChanged (std::shared_ptr event) override; + void onParticipantDeviceAdded (std::shared_ptr event) override; + void onParticipantDeviceRemoved (std::shared_ptr event) override; private: L_DECLARE_PRIVATE(RemoteConference); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 5fddd7267..244c45188 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -355,6 +355,7 @@ MainDb::MainDb (const shared_ptr &core) : CoreAccessor(core), AbstractDb(* return make_shared( type, date, + false, Address(peerAddress), notifyId, Address(participantAddress) @@ -386,6 +387,7 @@ MainDb::MainDb (const shared_ptr &core) : CoreAccessor(core), AbstractDb(* return make_shared( type, date, + false, Address(peerAddress), notifyId, Address(participantAddress), @@ -412,6 +414,7 @@ MainDb::MainDb (const shared_ptr &core) : CoreAccessor(core), AbstractDb(* // TODO: Use cache. return make_shared( date, + false, Address(peerAddress), notifyId, subject diff --git a/src/event-log/conference/conference-notified-event-p.h b/src/event-log/conference/conference-notified-event-p.h index af5855334..20f55c352 100644 --- a/src/event-log/conference/conference-notified-event-p.h +++ b/src/event-log/conference/conference-notified-event-p.h @@ -30,6 +30,7 @@ LINPHONE_BEGIN_NAMESPACE class ConferenceNotifiedEventPrivate : public ConferenceEventPrivate { private: unsigned int notifyId = 0; + bool isFullState = false; L_DECLARE_PUBLIC(ConferenceNotifiedEvent); }; diff --git a/src/event-log/conference/conference-notified-event.cpp b/src/event-log/conference/conference-notified-event.cpp index 5a0e4f857..3eba64c71 100644 --- a/src/event-log/conference/conference-notified-event.cpp +++ b/src/event-log/conference/conference-notified-event.cpp @@ -30,22 +30,26 @@ LINPHONE_BEGIN_NAMESPACE ConferenceNotifiedEvent::ConferenceNotifiedEvent ( Type type, time_t time, + bool isFullState, const Address &conferenceAddress, unsigned int notifyId ) : ConferenceEvent(*new ConferenceNotifiedEventPrivate, type, time, conferenceAddress) { L_D(); d->notifyId = notifyId; + d->isFullState = isFullState; } ConferenceNotifiedEvent::ConferenceNotifiedEvent ( ConferenceNotifiedEventPrivate &p, Type type, time_t time, + bool isFullState, const Address &conferenceAddress, unsigned int notifyId ) : ConferenceEvent(p, type, time, conferenceAddress) { L_D(); d->notifyId = notifyId; + d->isFullState = isFullState; } unsigned int ConferenceNotifiedEvent::getNotifyId () const { @@ -53,4 +57,9 @@ unsigned int ConferenceNotifiedEvent::getNotifyId () const { return d->notifyId; } +bool ConferenceNotifiedEvent::isFullState () const { + L_D(); + return d->isFullState; +} + LINPHONE_END_NAMESPACE diff --git a/src/event-log/conference/conference-notified-event.h b/src/event-log/conference/conference-notified-event.h index 4f238e857..bbb765e1d 100644 --- a/src/event-log/conference/conference-notified-event.h +++ b/src/event-log/conference/conference-notified-event.h @@ -30,15 +30,22 @@ class ConferenceNotifiedEventPrivate; class LINPHONE_PUBLIC ConferenceNotifiedEvent : public ConferenceEvent { public: - ConferenceNotifiedEvent (Type type, std::time_t time, const Address &conferenceAddress, unsigned int notifiyId); + ConferenceNotifiedEvent ( + Type type, std::time_t time, + bool isFullState, + const Address &conferenceAddress, + unsigned int notifiyId + ); unsigned int getNotifyId () const; + bool isFullState() const; protected: ConferenceNotifiedEvent ( ConferenceNotifiedEventPrivate &p, Type type, std::time_t time, + bool isFullState, const Address &conferenceAddress, unsigned int notifyId ); diff --git a/src/event-log/conference/conference-participant-device-event.cpp b/src/event-log/conference/conference-participant-device-event.cpp index fbfbcceda..30850259d 100644 --- a/src/event-log/conference/conference-participant-device-event.cpp +++ b/src/event-log/conference/conference-participant-device-event.cpp @@ -36,6 +36,7 @@ public: ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent ( Type type, time_t time, + bool isFullState, const Address &conferenceAddress, unsigned int notifyId, const Address &participantAddress, @@ -44,6 +45,7 @@ ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent ( *new ConferenceParticipantDeviceEventPrivate, type, time, + isFullState, conferenceAddress, notifyId, participantAddress diff --git a/src/event-log/conference/conference-participant-device-event.h b/src/event-log/conference/conference-participant-device-event.h index d57834dd7..27b315121 100644 --- a/src/event-log/conference/conference-participant-device-event.h +++ b/src/event-log/conference/conference-participant-device-event.h @@ -33,6 +33,7 @@ public: ConferenceParticipantDeviceEvent ( Type type, std::time_t time, + bool isFullState, const Address &conferenceAddress, unsigned int notifyId, const Address &participantAddress, diff --git a/src/event-log/conference/conference-participant-event.cpp b/src/event-log/conference/conference-participant-event.cpp index b5e8406b6..c5ece237a 100644 --- a/src/event-log/conference/conference-participant-event.cpp +++ b/src/event-log/conference/conference-participant-event.cpp @@ -30,10 +30,18 @@ LINPHONE_BEGIN_NAMESPACE ConferenceParticipantEvent::ConferenceParticipantEvent ( Type type, time_t time, + bool isFullState, const Address &conferenceAddress, unsigned int notifyId, const Address &participantAddress -) : ConferenceNotifiedEvent(*new ConferenceParticipantEventPrivate, type, time, conferenceAddress, notifyId) { +) : ConferenceNotifiedEvent( + *new ConferenceParticipantEventPrivate, + type, + time, + isFullState, + conferenceAddress, + notifyId +) { L_D(); L_ASSERT( type == Type::ConferenceParticipantAdded || @@ -48,10 +56,18 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( ConferenceParticipantEventPrivate &p, Type type, time_t time, + bool isFullState, const Address &conferenceAddress, unsigned int notifyId, const Address &participantAddress -) : ConferenceNotifiedEvent(p, type, time, conferenceAddress, notifyId) { +) : ConferenceNotifiedEvent( + p, + type, + time, + isFullState, + conferenceAddress, + notifyId +) { L_D(); d->participantAddress = participantAddress; } diff --git a/src/event-log/conference/conference-participant-event.h b/src/event-log/conference/conference-participant-event.h index 792583dcf..ce96da04c 100644 --- a/src/event-log/conference/conference-participant-event.h +++ b/src/event-log/conference/conference-participant-event.h @@ -33,6 +33,7 @@ public: ConferenceParticipantEvent ( Type type, std::time_t time, + bool isFullState, const Address &conferenceAddress, unsigned int notifyId, const Address &participantAddress @@ -45,6 +46,7 @@ protected: ConferenceParticipantEventPrivate &p, Type type, std::time_t time, + bool isFullState, const Address &conferenceAddress, unsigned int notifyId, const Address &participantAddress diff --git a/src/event-log/conference/conference-subject-event.cpp b/src/event-log/conference/conference-subject-event.cpp index e07061dc2..817cb6157 100644 --- a/src/event-log/conference/conference-subject-event.cpp +++ b/src/event-log/conference/conference-subject-event.cpp @@ -35,6 +35,7 @@ public: ConferenceSubjectEvent::ConferenceSubjectEvent ( time_t time, + bool isFullState, const Address &conferenceAddress, unsigned int notifyId, const string &subject @@ -42,6 +43,7 @@ ConferenceSubjectEvent::ConferenceSubjectEvent ( *new ConferenceSubjectEventPrivate, Type::ConferenceSubjectChanged, time, + isFullState, conferenceAddress, notifyId ) { diff --git a/src/event-log/conference/conference-subject-event.h b/src/event-log/conference/conference-subject-event.h index 8ea9a039f..aced99de5 100644 --- a/src/event-log/conference/conference-subject-event.h +++ b/src/event-log/conference/conference-subject-event.h @@ -34,6 +34,7 @@ class LINPHONE_PUBLIC ConferenceSubjectEvent : public ConferenceNotifiedEvent { public: ConferenceSubjectEvent ( std::time_t time, + bool isFullState, const Address &conferenceAddress, unsigned int notifyId, const std::string &subject diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index 7f280fd10..3e58928c1 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -196,7 +196,7 @@ set(SOURCE_FILES_C set(SOURCE_FILES_CXX clonable-object-tester.cpp - #conference-event-tester.cpp + conference-event-tester.cpp conference-tester.cpp content-manager-tester.cpp cpim-tester.cpp diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index 2d003586a..82d797c3a 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -145,7 +145,7 @@ static const char *participant_added_notify = \ " "\ +" state=\"partial\" version=\"1\">"\ " "\ @@ -202,7 +202,7 @@ static const char *participant_not_added_notify = \ " "\ +" state=\"partial\" version=\"1\">"\ " "\ @@ -259,7 +259,7 @@ static const char *participant_deleted_notify = \ " "\ +" state=\"partial\" version=\"1\">"\ " "\ @@ -316,7 +316,7 @@ static const char *participant_admined_notify = \ " "\ +" state=\"partial\" version=\"1\">"\ " "\ @@ -377,7 +377,7 @@ static const char *participant_unadmined_notify = \ " "\ +" state=\"partial\" version=\"1\">"\ " "\ @@ -447,12 +447,12 @@ public: private: void onConferenceCreated (const Address &addr) override; void onConferenceTerminated (const Address &addr) override; - void onParticipantAdded (time_t tm, bool isFullState, const Address &addr) override; - void onParticipantRemoved (time_t tm, bool isFullState, const Address &addr) override; - void onParticipantSetAdmin (time_t tm, bool isFullState, const Address &addr, bool isAdmin) override; - void onSubjectChanged (time_t tm, bool isFullState, const string &subject) override; - void onParticipantDeviceAdded (time_t tm, bool isFullState, const Address &addr, const Address &gruu) override; - void onParticipantDeviceRemoved (time_t tm, bool isFullState, const Address &addr, const Address &gruu) override; + void onParticipantAdded (shared_ptr event) override; + void onParticipantRemoved (shared_ptr event) override; + void onParticipantSetAdmin (shared_ptr event) override; + void onSubjectChanged (shared_ptr event) override; + void onParticipantDeviceAdded (shared_ptr event) override; + void onParticipantDeviceRemoved (shared_ptr event) override; public: RemoteConferenceEventHandler *handler; @@ -473,33 +473,38 @@ void ConferenceEventTester::onConferenceCreated (const Address &addr) {} void ConferenceEventTester::onConferenceTerminated (const Address &addr) {} -void ConferenceEventTester::onParticipantAdded (time_t tm, bool isFullState, const Address &addr) { +void ConferenceEventTester::onParticipantAdded (shared_ptr event) { + const Address addr = event->getParticipantAddress(); participants.insert(pair(addr.asString(), FALSE)); participantDevices.insert(pair(addr.asString(), 0)); } -void ConferenceEventTester::onParticipantRemoved (time_t tm, bool isFullState, const Address &addr) { +void ConferenceEventTester::onParticipantRemoved (shared_ptr event) { + const Address addr = event->getParticipantAddress(); participants.erase(addr.asString()); participantDevices.erase(addr.asString()); } -void ConferenceEventTester::onParticipantSetAdmin (time_t tm, bool isFullState, const Address &addr, bool isAdmin) { +void ConferenceEventTester::onParticipantSetAdmin (shared_ptr event) { + const Address addr = event->getParticipantAddress(); auto it = participants.find(addr.asString()); if (it != participants.end()) - it->second = isAdmin; + it->second = (event->getType() == EventLog::Type::ConferenceParticipantSetAdmin); } -void ConferenceEventTester::onSubjectChanged(time_t tm, bool isFullState, const string &subject) { - confSubject = subject; +void ConferenceEventTester::onSubjectChanged(shared_ptr event) { + confSubject = event->getSubject(); } -void ConferenceEventTester::onParticipantDeviceAdded (time_t tm, bool isFullState, const Address &addr, const Address &gruu) { +void ConferenceEventTester::onParticipantDeviceAdded (shared_ptr event) { + const Address addr = event->getParticipantAddress(); auto it = participantDevices.find(addr.asString()); if (it != participantDevices.end()) it->second++; } -void ConferenceEventTester::onParticipantDeviceRemoved (time_t tm, bool isFullState, const Address &addr, const Address &gruu) { +void ConferenceEventTester::onParticipantDeviceRemoved (shared_ptr event) { + const Address addr = event->getParticipantAddress(); auto it = participantDevices.find(addr.asString()); if (it != participantDevices.end() && it->second > 0) it->second--; diff --git a/tester/tester.c b/tester/tester.c index ca41f129a..48708461e 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -563,7 +563,7 @@ void liblinphone_tester_add_suites() { bc_tester_add_suite(&account_creator_test_suite); bc_tester_add_suite(&stun_test_suite); bc_tester_add_suite(&event_test_suite); - //bc_tester_add_suite(&conference_event_test_suite); + bc_tester_add_suite(&conference_event_test_suite); bc_tester_add_suite(&conference_test_suite); bc_tester_add_suite(&content_manager_test_suite); bc_tester_add_suite(&flexisip_test_suite); From a4a221dc0602d8ce170dbd3ffac75b72395a41fc Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 6 Nov 2017 14:04:53 +0100 Subject: [PATCH 0691/2215] add c-wrapping of ConferenceNotifiedEvent::isFullState --- include/linphone/api/c-event-log.h | 7 +++++++ src/c-wrapper/api/c-event-log.cpp | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/include/linphone/api/c-event-log.h b/include/linphone/api/c-event-log.h index c3f9e67c6..4a13f21d6 100644 --- a/include/linphone/api/c-event-log.h +++ b/include/linphone/api/c-event-log.h @@ -83,6 +83,13 @@ LINPHONE_PUBLIC const LinphoneAddress *linphone_event_log_get_conference_address */ LINPHONE_PUBLIC unsigned int linphone_event_log_get_notify_id (const LinphoneEventLog *event_log); +/** + * Returns whether or not the event comes from a full state notify. + * @param[in] event_log A #LinphoneEventLog object. + * @return whether or not the event comes from a full state notify. + */ +LINPHONE_PUBLIC bool_t linphone_event_log_is_full_state (const LinphoneEventLog *event_log); + // ----------------------------------------------------------------------------- // ConferenceCallEvent. // ----------------------------------------------------------------------------- diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 132982327..a9514ee67 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -193,6 +193,15 @@ unsigned int linphone_event_log_get_notify_id (const LinphoneEventLog *event_log )->getNotifyId(); } +bool_t linphone_event_log_is_full_state (const LinphoneEventLog *event_log) { + if (!isConferenceNotifiedType(linphone_event_log_get_type(event_log))) + return FALSE; + + return static_pointer_cast( + L_GET_CPP_PTR_FROM_C_OBJECT(event_log) + )->isFullState(); +} + // ----------------------------------------------------------------------------- // ConferenceCallEvent. // ----------------------------------------------------------------------------- From f308510501d8e59d7a74de1dee2bcac3db227c70 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 6 Nov 2017 14:32:48 +0100 Subject: [PATCH 0692/2215] Fixed multipart chat message with text + file transfer --- include/linphone/api/c-chat-message.h | 2 +- src/c-wrapper/api/c-chat-message.cpp | 2 +- src/chat/chat-message/chat-message.cpp | 2 +- tester/message_tester.c | 11 ++++++++--- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index af7aae13d..8196cecc4 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -365,7 +365,7 @@ LINPHONE_PUBLIC bool_t linphone_chat_message_has_text_content(const LinphoneChat * @param[in] msg LinphoneChatMessage object * @return true if it has one, false otherwise */ -LINPHONE_PUBLIC bool_t linphone_chat_message_has_file_content(const LinphoneChatMessage *msg); +LINPHONE_PUBLIC bool_t linphone_chat_message_has_file_transfer_content(const LinphoneChatMessage *msg); /** * Gets the text content if available as a string diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 949ccde7f..ce1b1cdf8 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -309,7 +309,7 @@ bool_t linphone_chat_message_has_text_content(const LinphoneChatMessage *msg) { return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->hasTextContent(); } -bool_t linphone_chat_message_has_file_content(const LinphoneChatMessage *msg) { +bool_t linphone_chat_message_has_file_transfer_content(const LinphoneChatMessage *msg) { return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->hasFileTransferContent(); } diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index b893a0886..d673e8466 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -764,7 +764,7 @@ void ChatMessagePrivate::processResponseFromPostFile (const belle_http_response_ Content fileTransferContent; fileTransferContent.setContentType(ContentType::FileTransfer); - fileTransferContent.setBody(linphone_content_get_string_buffer(cFileTransferInformation)); + fileTransferContent.setBody(getText()); q->addContent(fileTransferContent); q->updateState(ChatMessage::State::FileTransferDone); diff --git a/tester/message_tester.c b/tester/message_tester.c index 0cf6d26b4..ccd535f27 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -2310,6 +2310,9 @@ void file_and_text_message(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc"); + LpConfig *config = linphone_core_get_config(pauline->lc); + lp_config_set_int(config, "sip", "use_cpim", 1); + char *send_filepath = bc_tester_res("sounds/sintel_trailer_opus_h264.mkv"); char *receive_filepath = bc_tester_file("receive_file.dump"); LinphoneChatRoom* chat_room; @@ -2331,18 +2334,20 @@ void file_and_text_message(void) { BC_ASSERT_TRUE(linphone_chat_message_has_text_content(msg)); BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text_content(msg), "Text message"); - BC_ASSERT_FALSE(linphone_chat_message_has_file_content(msg)); + BC_ASSERT_FALSE(linphone_chat_message_has_file_transfer_content(msg)); // On sender side, content is a file content, not a file transfer linphone_chat_room_send_chat_message(chat_room, msg); - BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageReceivedWithFile, 1, 60000)); + BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageReceived, 1, 60000)); + BC_ASSERT_TRUE(linphone_chat_message_has_file_transfer_content(msg)); // Once sent, it should have the file transfer content + if (marie->stat.last_received_chat_message) { LinphoneChatMessage *recv_msg; recv_msg = marie->stat.last_received_chat_message; BC_ASSERT_TRUE(linphone_chat_message_has_text_content(recv_msg)); BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text_content(recv_msg), "Text message"); - BC_ASSERT_TRUE(linphone_chat_message_has_file_content(recv_msg)); + BC_ASSERT_TRUE(linphone_chat_message_has_file_transfer_content(recv_msg)); cbs = linphone_chat_message_get_callbacks(recv_msg); linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); From a77a4f857e1969feb9767b4daceca40627f3a327 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 6 Nov 2017 14:39:43 +0100 Subject: [PATCH 0693/2215] Fixed crash with AbstractDB, TODO investigate why it was crashing and this makes it work... --- src/db/main-db.cpp | 2 +- src/db/main-db.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 244c45188..28d4bd509 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -46,7 +46,7 @@ LINPHONE_BEGIN_NAMESPACE // ----------------------------------------------------------------------------- -MainDb::MainDb (const shared_ptr &core) : CoreAccessor(core), AbstractDb(*new MainDbPrivate) {} +MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), CoreAccessor(core) {} #ifdef SOCI_ENABLED diff --git a/src/db/main-db.h b/src/db/main-db.h index 6fb3ef51c..f04c6d779 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -35,7 +35,7 @@ class Core; class EventLog; class MainDbPrivate; -class LINPHONE_PUBLIC MainDb : public CoreAccessor, public AbstractDb { +class LINPHONE_PUBLIC MainDb : public AbstractDb, public CoreAccessor { public: enum Filter { NoFilter = 0x0, From fcbce75165fb2bd3f62820e1bdc6429f784dd9af Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 6 Nov 2017 15:06:06 +0100 Subject: [PATCH 0694/2215] feat(c-wrapper): deal with floating references --- src/c-wrapper/internal/c-tools.h | 156 +++++++++++++++++++++++++------ src/object/base-object.cpp | 4 + 2 files changed, 130 insertions(+), 30 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 7ec402e3c..becf60c5a 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -121,10 +121,19 @@ private: // Wrapped Objects. // --------------------------------------------------------------------------- + enum class WrappedObjectOwner : int { + Internal, + External + }; + template struct WrappedBaseObject { belle_sip_object_t base; std::shared_ptr cppPtr; + std::weak_ptr weakCppPtr; + + // By default: Internal. + WrappedObjectOwner owner; }; template @@ -143,6 +152,23 @@ private: } public: + // --------------------------------------------------------------------------- + // Belle sip handlers. + // Deal with floating references. + // --------------------------------------------------------------------------- + + static void onBelleSipFirstRef (belle_sip_object_t *base) { + WrappedBaseObject *wrappedObject = reinterpret_cast *>(base); + if (wrappedObject->owner == WrappedObjectOwner::Internal) + wrappedObject->cppPtr = wrappedObject->weakCppPtr.lock(); + } + + static void onBelleSipLastRef (belle_sip_object_t *base) { + WrappedBaseObject *wrappedObject = reinterpret_cast *>(base); + if (wrappedObject->owner == WrappedObjectOwner::Internal) + wrappedObject->cppPtr.reset(); + } + // --------------------------------------------------------------------------- // Casts. // --------------------------------------------------------------------------- @@ -178,6 +204,20 @@ public: return cppObject->getPrivate(); } + // --------------------------------------------------------------------------- + // Deal with cpp ptr destruction. + // --------------------------------------------------------------------------- + + template< + typename CppType, + typename = typename std::enable_if::value, CppType>::type + > + static void signalCppPtrDestruction (CppType *cppObject) { + void *value = cppObject->getCBackPtr(); + if (value && static_cast *>(value)->owner == WrappedObjectOwner::Internal) + belle_sip_object_unref(value); + } + // --------------------------------------------------------------------------- // Get c/cpp ptr helpers. // --------------------------------------------------------------------------- @@ -187,12 +227,19 @@ public: typename CppType = typename CTypeMetaInfo::cppType, typename = typename std::enable_if::value, CppType>::type > - static L_INTERNAL_WRAPPER_CONSTEXPR std::shared_ptr getCppPtrFromC (CType *cObject) { + static inline std::shared_ptr getCppPtrFromC (CType *cObject) { #ifdef DEBUG typedef typename CTypeMetaInfo::cppType BaseType; typedef CppType DerivedType; - std::shared_ptr cppObject = reinterpret_cast *>(cObject)->cppPtr; + std::shared_ptr cppObject; + { + WrappedBaseObject *wrappedObject = reinterpret_cast *>(cObject); + cppObject = wrappedObject->owner == WrappedObjectOwner::Internal + ? wrappedObject->weakCppPtr.lock() + : wrappedObject->cppPtr; + } + if (!cppObject) abort("Cpp Object is null."); @@ -202,7 +249,10 @@ public: return derivedCppObject; #else - return reinterpret_cast *>(cObject)->cppPtr; + WrappedBaseObject *wrappedObject = reinterpret_cast *>(cObject); + return wrappedObject->owner == WrappedObjectOwner::Internal + ? wrappedObject->weakCppPtr.lock() + : wrappedObject->cppPtr; #endif } @@ -211,12 +261,8 @@ public: typename CppType = typename CTypeMetaInfo::cppType, typename = typename std::enable_if::value, CppType>::type > - static L_INTERNAL_WRAPPER_CONSTEXPR std::shared_ptr getCppPtrFromC (const CType *cObject) { - #ifdef DEBUG - return getCppPtrFromC(const_cast(cObject)); - #else - return reinterpret_cast *>(cObject)->cppPtr; - #endif + static inline std::shared_ptr getCppPtrFromC (const CType *cObject) { + return getCppPtrFromC(const_cast(cObject)); } template< @@ -266,7 +312,23 @@ public: typename = typename std::enable_if::value, CppType>::type > static inline void setCppPtrFromC (CType *cObject, const std::shared_ptr &cppObject) { - reinterpret_cast *>(cObject)->cppPtr = cppObject; + WrappedBaseObject *wrappedObject = reinterpret_cast *>(cObject); + std::shared_ptr oldCppObject; + + if (wrappedObject->owner == WrappedObjectOwner::Internal) { + oldCppObject = wrappedObject->weakCppPtr.lock(); + wrappedObject->weakCppPtr = cppObject; + if (reinterpret_cast(cObject)->ref > 1) + wrappedObject->cppPtr = cppObject; + else + wrappedObject->cppPtr.reset(); + } else { + oldCppObject = wrappedObject->cppPtr; + wrappedObject->cppPtr = cppObject; + } + + if (oldCppObject) + oldCppObject->setCBackPtr(nullptr); cppObject->setCBackPtr(cObject); } @@ -295,7 +357,8 @@ public: } // --------------------------------------------------------------------------- - // Get c back ptr helpers. + // Get cpp ptr (shared if BaseObject, not shared if ClonableObject) + // from cpp object. // --------------------------------------------------------------------------- template< @@ -328,13 +391,23 @@ public: return cppObject; } + // --------------------------------------------------------------------------- + // Get c back ptr resolver helpers. + // --------------------------------------------------------------------------- + template< typename CppType, - typename = typename std::enable_if< - IsDefinedCppObject::value || IsDefinedClonableCppObject::value, CppType - >::type + typename = typename std::enable_if::value, CppType>::type > - static inline typename CppTypeMetaInfo::cType *getCBackPtr (const CppType *cppObject) { + static inline typename CppTypeMetaInfo::cType *getCBackPtrResolver (const std::shared_ptr &cppObject) { + return getCBackPtr(cppObject); + } + + template< + typename CppType, + typename = typename std::enable_if::value, CppType>::type + > + static inline typename CppTypeMetaInfo::cType *getCBackPtrResolver (const CppType *cppObject) { if (L_UNLIKELY(!cppObject)) return nullptr; @@ -345,13 +418,25 @@ public: return static_cast(value); RetType *cObject = CppTypeMetaInfo::init(); - - // Can be set only on Object or ClonableObject. Not BaseObject. - setCppPtrFromC(cObject, getResolvedCppPtr(cppObject)); + setCppPtrFromC(cObject, cppObject); return cObject; } + // --------------------------------------------------------------------------- + // Get c back ptr helpers. + // --------------------------------------------------------------------------- + + template< + typename CppType, + typename = typename std::enable_if< + IsDefinedCppObject::value || IsDefinedClonableCppObject::value, CppType + >::type + > + static inline typename CppTypeMetaInfo::cType *getCBackPtr (const CppType *cppObject) { + return getCBackPtrResolver(getResolvedCppPtr(cppObject)); + } + template< typename CppType, typename = typename std::enable_if::value, CppType>::type @@ -367,6 +452,7 @@ public: return static_cast(value); RetType *cObject = CppTypeMetaInfo::init(); + reinterpret_cast *>(cObject)->owner = WrappedObjectOwner::Internal; setCppPtrFromC(cObject, cppObject); @@ -470,25 +556,38 @@ LINPHONE_END_NAMESPACE #define L_INTERNAL_C_OBJECT_NO_XTOR(C_OBJECT) +#define L_INTERNAL_DECLARE_C_OBJECT(C_TYPE, CPP_TYPE, ...) \ + struct _Linphone ## C_TYPE { \ + belle_sip_object_t base; \ + std::shared_ptr cppPtr; \ + std::weak_ptr weakCppPtr; \ + int owner; \ + __VA_ARGS__ \ + }; + #define L_INTERNAL_DECLARE_C_OBJECT_FUNCTIONS(C_TYPE, CONSTRUCTOR, DESTRUCTOR) \ BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_TYPE); \ Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init () { \ Linphone ## C_TYPE * object = belle_sip_object_new(Linphone ## C_TYPE); \ new(&object->cppPtr) std::shared_ptr(); \ + new(&object->weakCppPtr) std::weak_ptr(); \ CONSTRUCTOR(object); \ return object; \ } \ static void _linphone_ ## C_TYPE ## _uninit(Linphone ## C_TYPE * object) { \ DESTRUCTOR(object); \ - object->cppPtr.~shared_ptr (); \ + object->cppPtr.~shared_ptr(); \ + object->weakCppPtr.~weak_ptr(); \ } \ BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## C_TYPE); \ - BELLE_SIP_INSTANCIATE_VPTR( \ + BELLE_SIP_INSTANCIATE_VPTR2( \ Linphone ## C_TYPE, \ belle_sip_object_t, \ _linphone_ ## C_TYPE ## _uninit, \ NULL, \ NULL, \ + LinphonePrivate::Wrapper::onBelleSipFirstRef, \ + LinphonePrivate::Wrapper::onBelleSipLastRef, \ FALSE \ ); @@ -551,21 +650,14 @@ LINPHONE_END_NAMESPACE // Declare wrapped C object with constructor/destructor. #define L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(C_TYPE, CONSTRUCTOR, DESTRUCTOR, ...) \ - struct _Linphone ## C_TYPE { \ - belle_sip_object_t base; \ - std::shared_ptr cppPtr; \ - __VA_ARGS__ \ - }; \ + static_assert(LinphonePrivate::CTypeMetaInfo::defined, "Type is not defined."); \ + L_INTERNAL_DECLARE_C_OBJECT(C_TYPE, L_CPP_TYPE_OF_C_TYPE(C_TYPE), __VA_ARGS__) \ L_INTERNAL_DECLARE_C_OBJECT_FUNCTIONS(C_TYPE, CONSTRUCTOR, DESTRUCTOR) // Declare wrapped C object. #define L_DECLARE_C_OBJECT_IMPL(C_TYPE, ...) \ static_assert(LinphonePrivate::CTypeMetaInfo::defined, "Type is not defined."); \ - struct _Linphone ## C_TYPE { \ - belle_sip_object_t base; \ - std::shared_ptr cppPtr; \ - __VA_ARGS__ \ - }; \ + L_INTERNAL_DECLARE_C_OBJECT(C_TYPE, L_CPP_TYPE_OF_C_TYPE(C_TYPE), __VA_ARGS__) \ L_INTERNAL_DECLARE_C_OBJECT_FUNCTIONS(C_TYPE, L_INTERNAL_C_OBJECT_NO_XTOR, L_INTERNAL_C_OBJECT_NO_XTOR) // Declare clonable wrapped C object. @@ -607,6 +699,10 @@ LINPHONE_END_NAMESPACE // Call the init function of wrapped C object. #define L_INIT(C_TYPE) _linphone_ ## C_TYPE ## _init() +// Signal to wrapper the destruction of cpp base object. +#define L_SIGNAL_CPP_PTR_DESTRUCTION(CPP_OBJECT) \ + LinphonePrivate::Wrapper::signalCppPtrDestruction(CPP_OBJECT); + // Get/set the cpp-ptr of a wrapped C object. #define L_GET_CPP_PTR_FROM_C_OBJECT_1_ARGS(C_OBJECT) \ LinphonePrivate::Wrapper::getCppPtrFromC(C_OBJECT) diff --git a/src/object/base-object.cpp b/src/object/base-object.cpp index b1551c5ed..dca0953d5 100644 --- a/src/object/base-object.cpp +++ b/src/object/base-object.cpp @@ -19,6 +19,9 @@ #include "base-object-p.h" +// Necessary for: L_SIGNAL_CPP_PTR_DESTRUCTION. +#include "c-wrapper/internal/c-tools.h" + #include "base-object.h" // ============================================================================= @@ -32,6 +35,7 @@ BaseObject::BaseObject (BaseObjectPrivate &p) : mPrivate(&p) { } BaseObject::~BaseObject () { + L_SIGNAL_CPP_PTR_DESTRUCTION(this); delete mPrivate; } From e37f307c5f38662aebd5b3503528604916e63c11 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 6 Nov 2017 15:24:18 +0100 Subject: [PATCH 0695/2215] fix(c-tools): use only one assert for test defined type in c object declaration --- src/c-wrapper/internal/c-tools.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index becf60c5a..5c03c244d 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -557,6 +557,7 @@ LINPHONE_END_NAMESPACE #define L_INTERNAL_C_OBJECT_NO_XTOR(C_OBJECT) #define L_INTERNAL_DECLARE_C_OBJECT(C_TYPE, CPP_TYPE, ...) \ + static_assert(LinphonePrivate::CTypeMetaInfo::defined, "Type is not defined."); \ struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ std::shared_ptr cppPtr; \ @@ -650,13 +651,11 @@ LINPHONE_END_NAMESPACE // Declare wrapped C object with constructor/destructor. #define L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(C_TYPE, CONSTRUCTOR, DESTRUCTOR, ...) \ - static_assert(LinphonePrivate::CTypeMetaInfo::defined, "Type is not defined."); \ L_INTERNAL_DECLARE_C_OBJECT(C_TYPE, L_CPP_TYPE_OF_C_TYPE(C_TYPE), __VA_ARGS__) \ L_INTERNAL_DECLARE_C_OBJECT_FUNCTIONS(C_TYPE, CONSTRUCTOR, DESTRUCTOR) // Declare wrapped C object. #define L_DECLARE_C_OBJECT_IMPL(C_TYPE, ...) \ - static_assert(LinphonePrivate::CTypeMetaInfo::defined, "Type is not defined."); \ L_INTERNAL_DECLARE_C_OBJECT(C_TYPE, L_CPP_TYPE_OF_C_TYPE(C_TYPE), __VA_ARGS__) \ L_INTERNAL_DECLARE_C_OBJECT_FUNCTIONS(C_TYPE, L_INTERNAL_C_OBJECT_NO_XTOR, L_INTERNAL_C_OBJECT_NO_XTOR) From b8be3fa05b44820856cae33de0d812bf749640e9 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 6 Nov 2017 15:53:28 +0100 Subject: [PATCH 0696/2215] fix(c-wrapper): add private on some functions, owner is by default External --- src/c-wrapper/internal/c-tools.h | 100 ++++++++++++++++--------------- 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 5c03c244d..ebb68f6ed 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -122,8 +122,8 @@ private: // --------------------------------------------------------------------------- enum class WrappedObjectOwner : int { - Internal, - External + External, + Internal }; template @@ -132,7 +132,7 @@ private: std::shared_ptr cppPtr; std::weak_ptr weakCppPtr; - // By default: Internal. + // By default: External. WrappedObjectOwner owner; }; @@ -151,22 +151,39 @@ private: std::terminate(); } -public: // --------------------------------------------------------------------------- - // Belle sip handlers. - // Deal with floating references. + // Get cpp ptr (shared if BaseObject, not shared if ClonableObject) + // from cpp object. // --------------------------------------------------------------------------- - static void onBelleSipFirstRef (belle_sip_object_t *base) { - WrappedBaseObject *wrappedObject = reinterpret_cast *>(base); - if (wrappedObject->owner == WrappedObjectOwner::Internal) - wrappedObject->cppPtr = wrappedObject->weakCppPtr.lock(); + template< + typename CppType, + typename = typename std::enable_if::value, CppType>::type + > + static inline std::shared_ptr getResolvedCppPtr (const CppType *cppObject) { + if (L_UNLIKELY(!cppObject)) + return nullptr; + + try { + typedef typename std::decaygetSharedFromThis())>::type SharedFromThisType; + + return std::static_pointer_cast( + std::const_pointer_cast(cppObject->getSharedFromThis()) + ); + } catch (const std::bad_weak_ptr &e) { + abort(e.what()); + } + + L_ASSERT(false); + return nullptr; } - static void onBelleSipLastRef (belle_sip_object_t *base) { - WrappedBaseObject *wrappedObject = reinterpret_cast *>(base); - if (wrappedObject->owner == WrappedObjectOwner::Internal) - wrappedObject->cppPtr.reset(); + template< + typename CppType, + typename = typename std::enable_if::value, CppType>::type + > + static constexpr const CppType *getResolvedCppPtr (const CppType *cppObject) { + return cppObject; } // --------------------------------------------------------------------------- @@ -192,6 +209,24 @@ public: #endif } +public: + // --------------------------------------------------------------------------- + // Belle sip handlers. + // Deal with floating references. + // --------------------------------------------------------------------------- + + static void onBelleSipFirstRef (belle_sip_object_t *base) { + WrappedBaseObject *wrappedObject = reinterpret_cast *>(base); + if (wrappedObject->owner == WrappedObjectOwner::Internal) + wrappedObject->cppPtr = wrappedObject->weakCppPtr.lock(); + } + + static void onBelleSipLastRef (belle_sip_object_t *base) { + WrappedBaseObject *wrappedObject = reinterpret_cast *>(base); + if (wrappedObject->owner == WrappedObjectOwner::Internal) + wrappedObject->cppPtr.reset(); + } + // --------------------------------------------------------------------------- // Get private data of cpp Object. // --------------------------------------------------------------------------- @@ -356,45 +391,11 @@ public: setCppPtrFromC(cObject, new CppType(*cppObject)); } - // --------------------------------------------------------------------------- - // Get cpp ptr (shared if BaseObject, not shared if ClonableObject) - // from cpp object. - // --------------------------------------------------------------------------- - - template< - typename CppType, - typename = typename std::enable_if::value, CppType>::type - > - static inline std::shared_ptr getResolvedCppPtr (const CppType *cppObject) { - if (L_UNLIKELY(!cppObject)) - return nullptr; - - try { - typedef typename std::decaygetSharedFromThis())>::type SharedFromThisType; - - return std::static_pointer_cast( - std::const_pointer_cast(cppObject->getSharedFromThis()) - ); - } catch (const std::bad_weak_ptr &e) { - abort(e.what()); - } - - L_ASSERT(false); - return nullptr; - } - - template< - typename CppType, - typename = typename std::enable_if::value, CppType>::type - > - static constexpr const CppType *getResolvedCppPtr (const CppType *cppObject) { - return cppObject; - } - // --------------------------------------------------------------------------- // Get c back ptr resolver helpers. // --------------------------------------------------------------------------- +private: template< typename CppType, typename = typename std::enable_if::value, CppType>::type @@ -427,6 +428,7 @@ public: // Get c back ptr helpers. // --------------------------------------------------------------------------- +public: template< typename CppType, typename = typename std::enable_if< From 30dbfe2bf6a03e42557d8edf6d415fe50caf8fdf Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 6 Nov 2017 16:02:52 +0100 Subject: [PATCH 0697/2215] Add linphone_core_find_chat_room() function for testers. --- coreapi/tester_utils.cpp | 12 ++++++++++++ coreapi/tester_utils.h | 1 + 2 files changed, 13 insertions(+) diff --git a/coreapi/tester_utils.cpp b/coreapi/tester_utils.cpp index c48407774..4589778a7 100644 --- a/coreapi/tester_utils.cpp +++ b/coreapi/tester_utils.cpp @@ -20,6 +20,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "tester_utils.h" #include "private.h" +#include "chat/chat-room/chat-room.h" +#include "core/core.h" +#include "c-wrapper/c-wrapper.h" + LinphoneVcardContext *linphone_core_get_vcard_context(const LinphoneCore *lc) { return lc->vcard_context; } @@ -48,6 +52,14 @@ bctbx_list_t **linphone_core_get_call_logs_attribute(LinphoneCore *lc) { return &lc->call_logs; } +LinphoneChatRoom * linphone_core_find_chat_room (const LinphoneCore *lc, const LinphoneAddress *addr) { + const LinphonePrivate::Address *cppAddr = L_GET_CPP_PTR_FROM_C_OBJECT(addr); + std::shared_ptr cr = lc->cppCore->findChatRoom(*cppAddr); + if (!cr) + return nullptr; + return L_GET_C_BACK_PTR(cr); +} + void linphone_core_cbs_set_auth_info_requested(LinphoneCoreCbs *cbs, LinphoneCoreAuthInfoRequestedCb cb) { cbs->vtable->auth_info_requested = cb; } diff --git a/coreapi/tester_utils.h b/coreapi/tester_utils.h index c486e59f6..1d6f7f701 100644 --- a/coreapi/tester_utils.h +++ b/coreapi/tester_utils.h @@ -94,6 +94,7 @@ LINPHONE_PUBLIC LinphoneQualityReporting *linphone_call_log_get_quality_reportin LINPHONE_PUBLIC reporting_session_report_t **linphone_quality_reporting_get_reports(LinphoneQualityReporting *qreporting); LINPHONE_PUBLIC bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr); +LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_find_chat_room (const LinphoneCore *lc, const LinphoneAddress *addr); LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_from_db(LinphoneCore *lc, LinphoneFriendList *list); LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_lists_from_db(LinphoneCore *lc); From d51acdf7391a70d05186376d98b63cae95a3b8ef Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 6 Nov 2017 16:03:32 +0100 Subject: [PATCH 0698/2215] Some small fixes in the addresses handling for conferences. --- coreapi/linphonecore.c | 7 ++++++- src/chat/chat-room/client-group-chat-room.cpp | 9 ++++++++- src/conference/remote-conference-event-handler.cpp | 6 +----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 6a2f3dcbf..090f90641 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -7256,8 +7256,13 @@ bool_t _linphone_core_is_conference_creation (const LinphoneCore *lc, const Linp LinphoneAddress *factoryAddr = linphone_address_new(uri); if (!factoryAddr) return FALSE; - bool_t result = linphone_address_weak_equal(factoryAddr, addr); + // Do not compare ports + linphone_address_set_port(factoryAddr, 0); + LinphoneAddress *testedAddr = linphone_address_clone(addr); + linphone_address_set_port(testedAddr, 0); + bool_t result = linphone_address_weak_equal(factoryAddr, testedAddr); linphone_address_unref(factoryAddr); + linphone_address_unref(testedAddr); return result; } diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 29b77d680..a850e6c57 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -320,7 +320,11 @@ void ClientGroupChatRoom::onParticipantSetAdmin (shared_ptrgetPrivate()->setAdmin(event->getType() == EventLog::Type::ConferenceParticipantSetAdmin); + bool isAdmin = event->getType() == EventLog::Type::ConferenceParticipantSetAdmin; + if (participant->isAdmin() == isAdmin) + return; // No change in the local admin status, do not notify + participant->getPrivate()->setAdmin(isAdmin); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAdminStatusChangedCb cb = linphone_chat_room_cbs_get_participant_admin_status_changed(cbs); @@ -331,7 +335,10 @@ void ClientGroupChatRoom::onParticipantSetAdmin (shared_ptr event) { + if (getSubject() == event->getSubject()) + return; // No change in the local subject, do not notify RemoteConference::setSubject(event->getSubject()); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsSubjectChangedCb cb = linphone_chat_room_cbs_get_subject_changed(cbs); diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 180d7e27b..1c768441d 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -80,15 +80,11 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { bool isFullState = (confInfo->getState() == StateType::full); Address cleanedConfAddress = d->confAddress; cleanedConfAddress.clean(); - cleanedConfAddress.setPort(0); // Temporary workaround Address entityAddress(confInfo->getEntity().c_str()); Address cleanedConfAddress2(cleanedConfAddress); cleanedConfAddress2.setDomain(entityAddress.getDomain()); - if ( - confInfo->getEntity() == cleanedConfAddress.asString() || - confInfo->getEntity() == cleanedConfAddress2.asString() - ) { + if (entityAddress.weakEqual(cleanedConfAddress) || entityAddress.weakEqual(cleanedConfAddress2)) { if ( confInfo->getConferenceDescription().present() && confInfo->getConferenceDescription().get().getSubject().present() From ab07fa2b2f4ef78ee21ce2a74959c65b1b7974ac Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 6 Nov 2017 17:08:37 +0100 Subject: [PATCH 0699/2215] Use correct way to create amsg --- src/c-wrapper/api/c-chat-room.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 91fac588c..ad3447da1 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -306,7 +306,10 @@ bctbx_list_t * linphone_chat_room_get_composing_addresses(LinphoneChatRoom *cr) } LinphoneChatMessage *linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent *initial_content) { - return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createFileTransferMessage(initial_content)); + shared_ptr cppPtr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createFileTransferMessage(initial_content); + LinphoneChatMessage *object = L_INIT(ChatMessage); + L_SET_CPP_PTR_FROM_C_OBJECT(object, cppPtr); + return object; } // ============================================================================= From f47dd800b82e4eea1ffcd99b50a2c336be0d5f27 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 6 Nov 2017 17:39:09 +0100 Subject: [PATCH 0700/2215] Fix crash temporarily, leak instead --- src/c-wrapper/internal/c-tools.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index ebb68f6ed..af5c551df 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -249,8 +249,9 @@ public: > static void signalCppPtrDestruction (CppType *cppObject) { void *value = cppObject->getCBackPtr(); - if (value && static_cast *>(value)->owner == WrappedObjectOwner::Internal) - belle_sip_object_unref(value); + //TODO + /*if (value && static_cast *>(value)->owner == WrappedObjectOwner::Internal) + belle_sip_object_unref(value);*/ } // --------------------------------------------------------------------------- From ce8805e463b1cbe4046b2f4f2849f444ffadd362 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 6 Nov 2017 17:40:35 +0100 Subject: [PATCH 0701/2215] Fixed compil --- src/c-wrapper/internal/c-tools.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index af5c551df..2fbaa2940 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -248,7 +248,7 @@ public: typename = typename std::enable_if::value, CppType>::type > static void signalCppPtrDestruction (CppType *cppObject) { - void *value = cppObject->getCBackPtr(); + //void *value = cppObject->getCBackPtr(); //TODO /*if (value && static_cast *>(value)->owner == WrappedObjectOwner::Internal) belle_sip_object_unref(value);*/ From b0349952fee08c345b0cc873be36026480b18e09 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 6 Nov 2017 17:52:55 +0100 Subject: [PATCH 0702/2215] Fix linphone_chat_room_create_message(). --- src/c-wrapper/api/c-chat-room.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index ad3447da1..0717bee48 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -101,7 +101,10 @@ const LinphoneAddress *linphone_chat_room_get_peer_address (LinphoneChatRoom *cr } LinphoneChatMessage *linphone_chat_room_create_message (LinphoneChatRoom *cr, const char *message) { - return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createMessage(L_C_TO_STRING(message))); + shared_ptr cppPtr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createMessage(L_C_TO_STRING(message)); + LinphoneChatMessage *object = L_INIT(ChatMessage); + L_SET_CPP_PTR_FROM_C_OBJECT(object, cppPtr); + return object; } LinphoneChatMessage *linphone_chat_room_create_message_2 ( From 3df2ee859e99890742fb99fefb4d2e77656ca7f7 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 6 Nov 2017 18:16:06 +0100 Subject: [PATCH 0703/2215] feat(c-tools): reset back ptr when belle sip object is destroyed --- src/c-wrapper/internal/c-tools.h | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 2fbaa2940..0b94a1681 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -210,6 +210,19 @@ private: } public: + // --------------------------------------------------------------------------- + // Back ptr reset, used by uninit c object function. + // --------------------------------------------------------------------------- + + template< + typename CppType, + typename = typename std::enable_if::value, CppType>::type + > + static void resetCBackPtr (const std::shared_ptr &cppObject) { + if (cppObject) + cppObject->setCBackPtr(nullptr); + } + // --------------------------------------------------------------------------- // Belle sip handlers. // Deal with floating references. @@ -331,11 +344,7 @@ public: typename = typename std::enable_if::value, CppType>::type > static L_INTERNAL_WRAPPER_CONSTEXPR const CppType *getCppPtrFromC (const CType *cObject) { - #ifdef DEBUG - return getCppPtrFromC(const_cast(cObject)); - #else - return reinterpret_cast *>(cObject)->cppPtr; - #endif + return getCppPtrFromC(const_cast(cObject)); } // --------------------------------------------------------------------------- @@ -580,6 +589,12 @@ LINPHONE_END_NAMESPACE } \ static void _linphone_ ## C_TYPE ## _uninit(Linphone ## C_TYPE * object) { \ DESTRUCTOR(object); \ + { \ + std::shared_ptr wrappedObject = object->weakCppPtr.lock(); \ + if (!wrappedObject) \ + wrappedObject = object->cppPtr; \ + LinphonePrivate::Wrapper::resetCBackPtr(wrappedObject); \ + } \ object->cppPtr.~shared_ptr(); \ object->weakCppPtr.~weak_ptr(); \ } \ From e59e06b49512a1914104643beadd86e3ec060598 Mon Sep 17 00:00:00 2001 From: Erwan Croze Date: Mon, 6 Nov 2017 14:58:53 +0100 Subject: [PATCH 0704/2215] Fix database for mysql --- src/db/abstract/abstract-db.cpp | 2 +- src/db/main-db.cpp | 46 ++++++++++++++++----------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/db/abstract/abstract-db.cpp b/src/db/abstract/abstract-db.cpp index dee423903..eea755fa7 100644 --- a/src/db/abstract/abstract-db.cpp +++ b/src/db/abstract/abstract-db.cpp @@ -98,7 +98,7 @@ string AbstractDb::primaryKeyStr (const string &type) const { switch (d->backend) { case Mysql: - return type + " PRIMARY KEY AUTO_INCREMENT"; + return " " + type + " AUTO_INCREMENT PRIMARY KEY"; case Sqlite3: // See: ROWIDs and the INTEGER PRIMARY KEY // https://www.sqlite.org/lang_createtable.html diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 28d4bd509..f6b7d57ba 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -546,19 +546,19 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS sip_address (" - " id" + primaryKeyStr("UNSIGNED BIGINT") + "," + " id" + primaryKeyStr("BIGINT UNSIGNED") + "," " value VARCHAR(255) UNIQUE NOT NULL" ")"; *session << "CREATE TABLE IF NOT EXISTS content_type (" - " id" + primaryKeyStr("UNSIGNED SMALLINT") + "," + " id" + primaryKeyStr("SMALLINT UNSIGNED") + "," " value VARCHAR(255) UNIQUE NOT NULL" ")"; *session << "CREATE TABLE IF NOT EXISTS event (" - " id" + primaryKeyStr("UNSIGNED BIGINT") + "," + " id" + primaryKeyStr("BIGINT UNSIGNED") + "," " type TINYINT UNSIGNED NOT NULL," " date DATE NOT NULL" ")"; @@ -566,7 +566,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS chat_room (" // Server (for conference) or user sip address. - " peer_sip_address_id" + primaryKeyStr("UNSIGNED BIGINT") + "," + " peer_sip_address_id" + primaryKeyStr("BIGINT UNSIGNED") + "," // Dialog creation date. " creation_date DATE NOT NULL," @@ -589,8 +589,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS chat_room_participant (" - " chat_room_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," - " sip_address_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," + " chat_room_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," " is_admin BOOLEAN NOT NULL," @@ -605,9 +605,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS conference_event (" - " event_id" + primaryKeyStr("UNSIGNED BIGINT") + "," + " event_id" + primaryKeyStr("BIGINT UNSIGNED") + "," - " chat_room_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," + " chat_room_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," " FOREIGN KEY (event_id)" " REFERENCES event(id)" @@ -619,7 +619,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS conference_notified_event (" - " event_id" + primaryKeyStr("UNSIGNED BIGINT") + "," + " event_id" + primaryKeyStr("BIGINT UNSIGNED") + "," " notify_id INT UNSIGNED NOT NULL," @@ -630,9 +630,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS conference_participant_event (" - " event_id" + primaryKeyStr("UNSIGNED BIGINT") + "," + " event_id" + primaryKeyStr("BIGINT UNSIGNED") + "," - " participant_address_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," + " participant_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," " FOREIGN KEY (event_id)" " REFERENCES conference_notified_event(event_id)" @@ -644,9 +644,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS conference_participant_device_event (" - " event_id" + primaryKeyStr("UNSIGNED BIGINT") + "," + " event_id" + primaryKeyStr("BIGINT UNSIGNED") + "," - " gruu_address_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," + " gruu_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," " FOREIGN KEY (event_id)" " REFERENCES conference_participant_event(event_id)" @@ -669,10 +669,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS conference_chat_message_event (" - " event_id" + primaryKeyStr("UNSIGNED BIGINT") + "," + " event_id" + primaryKeyStr("BIGINT UNSIGNED") + "," - " local_sip_address_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," - " remote_sip_address_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," + " local_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " remote_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," // See: https://tools.ietf.org/html/rfc5438#section-6.3 " imdn_message_id VARCHAR(255) NOT NULL," @@ -694,8 +694,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS chat_message_participant (" - " event_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," - " sip_address_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," + " event_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," " state TINYINT UNSIGNED NOT NULL," " PRIMARY KEY (event_id, sip_address_id)," @@ -709,10 +709,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS chat_message_content (" - " id" + primaryKeyStr("UNSIGNED BIGINT") + "," + " id" + primaryKeyStr("BIGINT UNSIGNED") + "," - " event_id " + primaryKeyRefStr("UNSIGNED BIGINT") + "," - " content_type_id" + primaryKeyRefStr("UNSIGNED SMALLINT") + "," + " event_id " + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " content_type_id" + primaryKeyRefStr("SMALLINT UNSIGNED") + "," " body TEXT NOT NULL," " FOREIGN KEY (event_id)" @@ -725,7 +725,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS chat_message_content_app_data (" - " chat_message_content_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," + " chat_message_content_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," " key VARCHAR(255)," " data BLOB," @@ -738,7 +738,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS conference_message_crypto_data (" - " event_id" + primaryKeyRefStr("UNSIGNED BIGINT") + "," + " event_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," " key VARCHAR(255)," " data BLOB," From 72442d192d1f013eca2c897f234a0ce73bef489e Mon Sep 17 00:00:00 2001 From: Erwan Croze Date: Tue, 7 Nov 2017 09:17:45 +0100 Subject: [PATCH 0705/2215] Fix: change reserved keyword on database init --- src/db/main-db.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index f6b7d57ba..8d5ca0822 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -727,10 +727,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), "CREATE TABLE IF NOT EXISTS chat_message_content_app_data (" " chat_message_content_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," - " key VARCHAR(255)," + " name VARCHAR(255)," " data BLOB," - " PRIMARY KEY (chat_message_content_id, key)," + " PRIMARY KEY (chat_message_content_id, name)," " FOREIGN KEY (chat_message_content_id)" " REFERENCES chat_message_content(id)" " ON DELETE CASCADE" @@ -740,10 +740,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), "CREATE TABLE IF NOT EXISTS conference_message_crypto_data (" " event_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," - " key VARCHAR(255)," + " name VARCHAR(255)," " data BLOB," - " PRIMARY KEY (event_id, key)," + " PRIMARY KEY (event_id, name)," " FOREIGN KEY (event_id)" " REFERENCES conference_chat_message_event(event_id)" " ON DELETE CASCADE" From f18fcbdf2f2bbdc5c34f0ec9160d19f17e3586da Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 7 Nov 2017 10:12:29 +0100 Subject: [PATCH 0706/2215] feat(c-wrapper): misc => - use correct macro in Wrapped DialPlan - add a type verification in c object declaration (compil time) - reset c back pointer if belle sip object is destroyed before cpp object --- src/c-wrapper/api/c-dial-plan.cpp | 2 +- src/c-wrapper/internal/c-tools.h | 167 +++++++++++++++++------------- 2 files changed, 97 insertions(+), 72 deletions(-) diff --git a/src/c-wrapper/api/c-dial-plan.cpp b/src/c-wrapper/api/c-dial-plan.cpp index 7dc7ef030..a3aad76fb 100644 --- a/src/c-wrapper/api/c-dial-plan.cpp +++ b/src/c-wrapper/api/c-dial-plan.cpp @@ -27,7 +27,7 @@ using namespace std; -L_DECLARE_C_OBJECT_IMPL(DialPlan); +L_DECLARE_C_CLONABLE_OBJECT_IMPL(DialPlan); LinphoneDialPlan *linphone_dial_plan_ref (LinphoneDialPlan *dp) { return reinterpret_cast(belle_sip_object_ref(dp)); diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 0b94a1681..75ec2445e 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -61,62 +61,62 @@ struct CTypeMetaInfo { typedef void cppType; }; +// --------------------------------------------------------------------------- +// IsCppObject traits. +// --------------------------------------------------------------------------- + +template +struct IsCppObject { + enum { + value = std::is_base_of::value || std::is_base_of::value + }; +}; + +template +struct IsPrivateCppObject { + enum { + value = std::is_base_of::value || + std::is_base_of::value + }; +}; + +template +struct IsRegisteredCppObject { + enum { + value = CppTypeMetaInfo::defined && ( + !CppTypeMetaInfo::isSubtype || + std::is_base_of::cType>::cppType, CppType>::value + ) + }; +}; + +// --------------------------------------------------------------------------- +// IsDefined traits. +// --------------------------------------------------------------------------- + +template +struct IsDefinedBaseCppObject { + enum { + value = IsRegisteredCppObject::value && std::is_base_of::value + }; +}; + +template +struct IsDefinedCppObject { + enum { + value = IsDefinedBaseCppObject::value && std::is_base_of::value + }; +}; + +template +struct IsDefinedClonableCppObject { + enum { + value = IsRegisteredCppObject::value && std::is_base_of::value + }; +}; + class Wrapper { private: - // --------------------------------------------------------------------------- - // IsCppObject traits. - // --------------------------------------------------------------------------- - - template - struct IsCppObject { - enum { - value = std::is_base_of::value || std::is_base_of::value - }; - }; - - template - struct IsPrivateCppObject { - enum { - value = std::is_base_of::value || - std::is_base_of::value - }; - }; - - template - struct IsRegisteredCppObject { - enum { - value = CppTypeMetaInfo::defined && ( - !CppTypeMetaInfo::isSubtype || - std::is_base_of::cType>::cppType, CppType>::value - ) - }; - }; - - // --------------------------------------------------------------------------- - // IsDefined traits. - // --------------------------------------------------------------------------- - - template - struct IsDefinedBaseCppObject { - enum { - value = IsRegisteredCppObject::value && std::is_base_of::value - }; - }; - - template - struct IsDefinedCppObject { - enum { - value = IsDefinedBaseCppObject::value && std::is_base_of::value - }; - }; - - template - struct IsDefinedClonableCppObject { - enum { - value = IsRegisteredCppObject::value && std::is_base_of::value - }; - }; - // --------------------------------------------------------------------------- // Wrapped Objects. // --------------------------------------------------------------------------- @@ -215,12 +215,31 @@ public: // --------------------------------------------------------------------------- template< - typename CppType, - typename = typename std::enable_if::value, CppType>::type + typename CType, + typename CppType = typename CTypeMetaInfo::cppType, + typename = typename std::enable_if::value, CppType>::type > - static void resetCBackPtr (const std::shared_ptr &cppObject) { + static void uninitBaseCppObject (CType *cObject) { + WrappedBaseObject *wrappedObject = reinterpret_cast *>(cObject); + + std::shared_ptr cppObject = wrappedObject->owner == WrappedObjectOwner::Internal + ? wrappedObject->weakCppPtr.lock() + : wrappedObject->cppPtr; + if (cppObject) - cppObject->setCBackPtr(nullptr); + cppObject->setCBackPtr(nullptr); \ + + wrappedObject->cppPtr.~shared_ptr(); + wrappedObject->weakCppPtr.~weak_ptr(); + } + + template< + typename CType, + typename CppType = typename CTypeMetaInfo::cppType, + typename = typename std::enable_if::value, CppType>::type + > + static void uninitClonableCppObject (CType *cObject) { + delete reinterpret_cast *>(cObject)->cppPtr; } // --------------------------------------------------------------------------- @@ -261,10 +280,11 @@ public: typename = typename std::enable_if::value, CppType>::type > static void signalCppPtrDestruction (CppType *cppObject) { - //void *value = cppObject->getCBackPtr(); - //TODO - /*if (value && static_cast *>(value)->owner == WrappedObjectOwner::Internal) - belle_sip_object_unref(value);*/ + // TODO: Remove commented section in the future. + // Repair message storage first. + // void *value = cppObject->getCBackPtr(); + // if (value && static_cast *>(value)->owner == WrappedObjectOwner::Internal) + // belle_sip_object_unref(value); } // --------------------------------------------------------------------------- @@ -570,6 +590,12 @@ LINPHONE_END_NAMESPACE #define L_INTERNAL_DECLARE_C_OBJECT(C_TYPE, CPP_TYPE, ...) \ static_assert(LinphonePrivate::CTypeMetaInfo::defined, "Type is not defined."); \ + static_assert( \ + LinphonePrivate::IsDefinedBaseCppObject< \ + LinphonePrivate::CTypeMetaInfo::cppType \ + >::value, \ + "Type is not declared as base object." \ + ); \ struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ std::shared_ptr cppPtr; \ @@ -589,14 +615,7 @@ LINPHONE_END_NAMESPACE } \ static void _linphone_ ## C_TYPE ## _uninit(Linphone ## C_TYPE * object) { \ DESTRUCTOR(object); \ - { \ - std::shared_ptr wrappedObject = object->weakCppPtr.lock(); \ - if (!wrappedObject) \ - wrappedObject = object->cppPtr; \ - LinphonePrivate::Wrapper::resetCBackPtr(wrappedObject); \ - } \ - object->cppPtr.~shared_ptr(); \ - object->weakCppPtr.~weak_ptr(); \ + LinphonePrivate::Wrapper::uninitBaseCppObject(object); \ } \ BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## C_TYPE); \ BELLE_SIP_INSTANCIATE_VPTR2( \ @@ -680,6 +699,12 @@ LINPHONE_END_NAMESPACE // Declare clonable wrapped C object. #define L_DECLARE_C_CLONABLE_OBJECT_IMPL(C_TYPE, ...) \ static_assert(LinphonePrivate::CTypeMetaInfo::defined, "Type is not defined."); \ + static_assert( \ + LinphonePrivate::IsDefinedClonableCppObject< \ + LinphonePrivate::CTypeMetaInfo::cppType \ + >::value, \ + "Type is not declared as clonable object." \ + ); \ struct _Linphone ## C_TYPE { \ belle_sip_object_t base; \ L_CPP_TYPE_OF_C_TYPE(C_TYPE) *cppPtr; \ @@ -690,7 +715,7 @@ LINPHONE_END_NAMESPACE return belle_sip_object_new(Linphone ## C_TYPE); \ } \ static void _linphone_ ## C_TYPE ## _uninit(Linphone ## C_TYPE * object) { \ - delete object->cppPtr; \ + LinphonePrivate::Wrapper::uninitClonableCppObject(object); \ } \ static void _linphone_ ## C_TYPE ## _clone(Linphone ## C_TYPE * dest, const Linphone ## C_TYPE * src) { \ L_ASSERT(src->cppPtr); \ From bcfa66e447526bdbb9eef664238f1be8786b75b0 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 7 Nov 2017 10:23:16 +0100 Subject: [PATCH 0707/2215] Deprecated getText() on ChatMessage + attempt to fix getText() --- include/linphone/api/c-chat-message.h | 1 + src/chat/chat-message/chat-message-p.h | 2 +- src/chat/chat-message/chat-message.cpp | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index 8196cecc4..e487a3b5f 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -135,6 +135,7 @@ LINPHONE_PUBLIC void linphone_chat_message_set_content_type(LinphoneChatMessage /** * Get text part of this message * @return text or NULL if no text. + * @deprecated use getTextContent() instead */ LINPHONE_PUBLIC const char* linphone_chat_message_get_text(LinphoneChatMessage* msg); diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index b321bb286..b33d43fff 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -81,7 +81,7 @@ public: std::string getSalCustomHeaderValue(const std::string& name); // ----------------------------------------------------------------------------- - // Methods only used for C wrapper + // Methods only used for C wrapper, to be removed some day... // ----------------------------------------------------------------------------- const ContentType &getContentType(); diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index d673e8466..b9b1138b8 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -187,7 +187,9 @@ const string &ChatMessagePrivate::getText () { cText = internalContent.getBodyAsString(); } } else { - if (!internalContent.isEmpty()) { + if (hasTextContent()) { + cText = getTextContent.getBodyAsString(); + } else if (!internalContent.isEmpty()) { cText = internalContent.getBodyAsString(); } else { if (contents.size() > 0) { From 95ab4ff5855b0472b1d187dafe4e35fe4beefb82 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 7 Nov 2017 10:25:25 +0100 Subject: [PATCH 0708/2215] Fixed broken compil due to dumb mistake --- src/chat/chat-message/chat-message.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index b9b1138b8..7a2c37352 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -179,6 +179,7 @@ void ChatMessagePrivate::setContentType (const ContentType &contentType) { } const string &ChatMessagePrivate::getText () { + L_Q(); if (direction == ChatMessage::Direction::Incoming) { if (contents.size() > 0) { Content content = contents.front(); @@ -187,8 +188,8 @@ const string &ChatMessagePrivate::getText () { cText = internalContent.getBodyAsString(); } } else { - if (hasTextContent()) { - cText = getTextContent.getBodyAsString(); + if (q->hasTextContent()) { + cText = q->getTextContent().getBodyAsString(); } else if (!internalContent.isEmpty()) { cText = internalContent.getBodyAsString(); } else { From 31c00aa3df13c9fe4b4e4d84ae22ee12455d2335 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 7 Nov 2017 13:17:55 +0100 Subject: [PATCH 0709/2215] Fixed issue with file + text message --- src/chat/chat-message/chat-message.cpp | 2 +- src/chat/chat-room/chat-room.cpp | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 7a2c37352..068821313 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -767,7 +767,7 @@ void ChatMessagePrivate::processResponseFromPostFile (const belle_http_response_ Content fileTransferContent; fileTransferContent.setContentType(ContentType::FileTransfer); - fileTransferContent.setBody(getText()); + fileTransferContent.setBody(internalContent.getBodyAsString()); q->addContent(fileTransferContent); q->updateState(ChatMessage::State::FileTransferDone); diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 3d085d61d..cfba88fd7 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -458,11 +458,6 @@ void ChatRoom::compose () { shared_ptr ChatRoom::createFileTransferMessage (const LinphoneContent *initialContent) { shared_ptr chatMessage = createMessage(); - /*Content content; - content.setContentType(ContentType::FileTransfer); - content.setBody(linphone_content_get_string_buffer(initialContent)); - chatMessage->addContent(content);*/ - chatMessage->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); chatMessage->getPrivate()->setFileTransferInformation(linphone_content_copy(initialContent)); return chatMessage; From 5e13c30a04afd5f1c939f48de5991d9c288a6daa Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 7 Nov 2017 14:37:36 +0100 Subject: [PATCH 0710/2215] fix(general): avoid usage of void* cast in getPublic helper, very dangerous in multi inheritance case!!! --- include/linphone/utils/general.h | 58 ++++++++++++++++++++++++++------ src/db/main-db.cpp | 2 +- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index cbd62d338..b03c23804 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -68,10 +68,10 @@ LINPHONE_BEGIN_NAMESPACE void l_assert (const char *condition, const char *file, int line); -#ifndef DEBUG - #define L_ASSERT(CONDITION) static_cast(false && (CONDITION)) -#else +#ifdef DEBUG #define L_ASSERT(CONDITION) ((CONDITION) ? static_cast(0) : LinphonePrivate::l_assert(#CONDITION, __FILE__, __LINE__)) +#else + #define L_ASSERT(CONDITION) static_cast(false && (CONDITION)) #endif #ifndef _MSC_VER @@ -132,18 +132,54 @@ class ObjectPrivate; friend class Tester; #endif -// Generic public helper. (Neither ClonableObject.) -// `void *` is used to avoid downcasting. +namespace Private { + // See: http://en.cppreference.com/w/cpp/types/void_t + template struct MakeVoid { + typedef void type; + }; + template + using void_t = typename MakeVoid::type; + + template + struct IsMapContainerImpl : std::false_type {}; + + template + struct IsMapContainerImpl< + T, + void_t< + typename T::key_type, + typename T::mapped_type, + decltype(std::declval()[std::declval()]) + > + > : std::true_type {}; +}; + +// Check if a type is a std container like map, unordered_map... template -constexpr T *getPublicHelper (void *object, const void *) { - return static_cast(object); +struct IsMapContainer : Private::IsMapContainerImpl::type {}; + +// Generic public helper. +template< + typename R, + typename P, + typename C, + typename = typename std::enable_if::value, P>::type +> +constexpr R *getPublicHelper (P *object, const C *) { + return static_cast(object); } -template -inline T *getPublicHelper (const U *map, const ClonableObjectPrivate *context) { +// Generic public helper. Deal with shared data. +template< + typename R, + typename P, + typename C, + typename = typename std::enable_if::value, P>::type +> +inline R *getPublicHelper (const P *map, const C *context) { auto it = map->find(context); - L_ASSERT(it != map->end()); - return static_cast(it->second); + L_ASSERT(it != map->cend()); + return static_cast(it->second); } #define L_DECLARE_PUBLIC(CLASS) \ diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 8d5ca0822..989d1ce68 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -711,7 +711,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), "CREATE TABLE IF NOT EXISTS chat_message_content (" " id" + primaryKeyStr("BIGINT UNSIGNED") + "," - " event_id " + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " event_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," " content_type_id" + primaryKeyRefStr("SMALLINT UNSIGNED") + "," " body TEXT NOT NULL," From 120117f7b3cac1ba1a53bf5cc63cfbaddac6b8c5 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 7 Nov 2017 15:27:09 +0100 Subject: [PATCH 0711/2215] Add the SimpleAddress class to ease the comparison of addresses for the conference participants and the list of chat rooms. --- src/CMakeLists.txt | 3 + src/address/address.cpp | 16 ++- src/address/address.h | 3 + src/address/simple-address-p.h | 41 ++++++ src/address/simple-address.cpp | 117 ++++++++++++++++++ src/address/simple-address.h | 65 ++++++++++ src/chat/chat-room/client-group-chat-room.cpp | 2 +- src/conference/conference.cpp | 14 +-- .../local-conference-event-handler.cpp | 18 ++- src/conference/participant-p.h | 6 +- src/conference/participant.cpp | 13 +- src/conference/participant.h | 4 +- src/core/core-chat-room.cpp | 76 ++++++------ 13 files changed, 307 insertions(+), 71 deletions(-) create mode 100644 src/address/simple-address-p.h create mode 100644 src/address/simple-address.cpp create mode 100644 src/address/simple-address.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 53ae3b8ff..e668511fb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,6 +23,8 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES address/address-p.h address/address.h + address/simple-address-p.h + address/simple-address.h c-wrapper/c-wrapper.h c-wrapper/internal/c-sal.h c-wrapper/internal/c-tools.h @@ -134,6 +136,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES set(LINPHONE_CXX_OBJECTS_SOURCE_FILES address/address.cpp + address/simple-address.cpp c-wrapper/api/c-address.cpp c-wrapper/api/c-call-cbs.cpp c-wrapper/api/c-call-params.cpp diff --git a/src/address/address.cpp b/src/address/address.cpp index 257fe7e1b..551975285 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -22,6 +22,7 @@ #include "address-p.h" #include "c-wrapper/c-wrapper.h" #include "logger/logger.h" +#include "address/simple-address.h" // ============================================================================= @@ -34,8 +35,7 @@ LINPHONE_BEGIN_NAMESPACE Address::Address (const string &address) : ClonableObject(*new AddressPrivate) { L_D(); if (!(d->internalAddress = sal_address_new(L_STRING_TO_C(address)))) { - lWarning() << "Cannot create address, bad uri [" << address << "]."; - return; + lWarning() << "Cannot create Address, bad uri [" << address << "]"; } } @@ -46,6 +46,18 @@ Address::Address (const Address &src) : ClonableObject(*new AddressPrivate) { d->internalAddress = sal_address_clone(salAddress); } +Address::Address (const SimpleAddress &src) : ClonableObject(*new AddressPrivate) { + L_D(); + string uri = src.getScheme() + ":" + src.getUsername() + "@"; + if (src.getDomain().find(':') != string::npos) + uri += "[" + src.getDomain() + "]"; + else + uri += src.getDomain(); + if (!(d->internalAddress = sal_address_new(L_STRING_TO_C(uri)))) { + lWarning() << "Cannot create Address, bad SimpleAddress source"; + } +} + Address::~Address () { L_D(); if (d->internalAddress) diff --git a/src/address/address.h b/src/address/address.h index af3dc0f1f..540bf7be4 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -28,6 +28,7 @@ LINPHONE_BEGIN_NAMESPACE class AddressPrivate; +class SimpleAddress; class LINPHONE_PUBLIC Address : public ClonableObject { // TODO: Remove me later. @@ -36,10 +37,12 @@ class LINPHONE_PUBLIC Address : public ClonableObject { friend class ClientGroupChatRoomPrivate; friend class ServerGroupChatRoom; friend class ServerGroupChatRoomPrivate; + friend class SimpleAddress; public: explicit Address (const std::string &address = ""); Address (const Address &src); + Address (const SimpleAddress &src); ~Address (); Address &operator= (const Address &src); diff --git a/src/address/simple-address-p.h b/src/address/simple-address-p.h new file mode 100644 index 000000000..49ac82f7f --- /dev/null +++ b/src/address/simple-address-p.h @@ -0,0 +1,41 @@ +/* + * simple-address-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _SIMPLE_ADDRESS_P_H_ +#define _SIMPLE_ADDRESS_P_H_ + +#include "simple-address.h" +#include "object/clonable-object-p.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class SimpleAddressPrivate : public ClonableObjectPrivate { +private: + std::string scheme; + std::string username; + std::string domain; + + L_DECLARE_PUBLIC(SimpleAddress); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _SIMPLE_ADDRESS_P_H_ diff --git a/src/address/simple-address.cpp b/src/address/simple-address.cpp new file mode 100644 index 000000000..19a1da395 --- /dev/null +++ b/src/address/simple-address.cpp @@ -0,0 +1,117 @@ +/* + * simple-address.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "linphone/utils/utils.h" + +#include "simple-address-p.h" +#include "c-wrapper/c-wrapper.h" +#include "logger/logger.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +// ----------------------------------------------------------------------------- + +SimpleAddress::SimpleAddress (const string &address) : ClonableObject(*new SimpleAddressPrivate) { + L_D(); + Address tmpAddress(address); + if (tmpAddress.isValid()) { + d->scheme = tmpAddress.getScheme(); + d->username = tmpAddress.getUsername(); + d->domain = tmpAddress.getDomain(); + } +} + +SimpleAddress::SimpleAddress (const SimpleAddress &src) : ClonableObject(*new SimpleAddressPrivate) { + L_D(); + d->scheme = src.getScheme(); + d->username = src.getUsername(); + d->domain = src.getDomain(); +} + +SimpleAddress::SimpleAddress (const Address &src) : ClonableObject(*new SimpleAddressPrivate) { + L_D(); + d->scheme = src.getScheme(); + d->username = src.getUsername(); + d->domain = src.getDomain(); +} + +SimpleAddress &SimpleAddress::operator= (const SimpleAddress &src) { + L_D(); + if (this != &src) { + d->scheme = src.getScheme(); + d->username = src.getUsername(); + d->domain = src.getDomain(); + } + return *this; +} + +bool SimpleAddress::operator== (const SimpleAddress &address) const { + return asString() == address.asString(); +} + +bool SimpleAddress::operator!= (const SimpleAddress &address) const { + return !(*this == address); +} + +bool SimpleAddress::operator< (const SimpleAddress &address) const { + return asString() < address.asString(); +} + +const string &SimpleAddress::getScheme () const { + L_D(); + return d->scheme; +} + +const string &SimpleAddress::getUsername () const { + L_D(); + return d->username; +} + +bool SimpleAddress::setUsername (const string &username) { + L_D(); + d->username = username; + return true; +} + +const string &SimpleAddress::getDomain () const { + L_D(); + return d->domain; +} + +bool SimpleAddress::setDomain (const string &domain) { + L_D(); + d->domain = domain; + return true; +} + +string SimpleAddress::asString () const { + Address tmpAddress(*this); + return tmpAddress.asString(); +} + +string SimpleAddress::asStringUriOnly () const { + Address tmpAddress(*this); + return tmpAddress.asStringUriOnly(); +} + +LINPHONE_END_NAMESPACE diff --git a/src/address/simple-address.h b/src/address/simple-address.h new file mode 100644 index 000000000..4a76a83ee --- /dev/null +++ b/src/address/simple-address.h @@ -0,0 +1,65 @@ +/* + * simple-address.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _SIMPLE_ADDRESS_H_ +#define _SIMPLE_ADDRESS_H_ + +#include "object/clonable-object.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class Address; +class SimpleAddressPrivate; + +class LINPHONE_PUBLIC SimpleAddress : public ClonableObject { +public: + explicit SimpleAddress (const std::string &address = ""); + SimpleAddress (const SimpleAddress &src); + SimpleAddress (const Address &src); + ~SimpleAddress () = default; + + SimpleAddress &operator= (const SimpleAddress &src); + + bool operator== (const SimpleAddress &address) const; + bool operator!= (const SimpleAddress &address) const; + + bool operator< (const SimpleAddress &address) const; + + const std::string &getScheme () const; + + const std::string &getUsername () const; + bool setUsername (const std::string &username); + + const std::string &getDomain () const; + bool setDomain (const std::string &domain); + + bool isSip () const; + + std::string asString () const; + std::string asStringUriOnly () const; + +private: + L_DECLARE_PRIVATE(SimpleAddress); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _SIMPLE_ADDRESS_H_ diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index a850e6c57..b5430c0e5 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -49,7 +49,7 @@ shared_ptr ClientGroupChatRoomPrivate::createSession () { shared_ptr focus = qConference->getPrivate()->focus; shared_ptr session = focus->getPrivate()->createSession(*q, &csp, false, q); const Address &myAddress = q->getMe()->getAddress(); - session->configure(LinphoneCallOutgoing, nullptr, nullptr, myAddress, focus->getAddress()); + session->configure(LinphoneCallOutgoing, nullptr, nullptr, myAddress, focus->getContactAddress()); session->initiateOutgoing(); Address addr = myAddress; diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index c0ac545ab..1ad341793 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -212,12 +212,9 @@ void Conference::onResetFirstVideoFrameDecoded (const shared_ptr Conference::findParticipant (const Address &addr) const { L_D(); - Address testedAddr = addr; - testedAddr.setPort(0); + SimpleAddress simpleAddr(addr); for (const auto &participant : d->participants) { - Address participantAddr = participant->getAddress(); - participantAddr.setPort(0); - if (testedAddr.weakEqual(participantAddr)) + if (participant->getAddress() == simpleAddr) return participant; } @@ -237,11 +234,8 @@ shared_ptr Conference::findParticipant (const shared_ptrme->getAddress(); - cleanedMe.setPort(0); - Address cleanedAddr = addr; - cleanedAddr.setPort(0); - return cleanedAddr == cleanedMe; + SimpleAddress simpleAddr(addr); + return d->me->getAddress() == simpleAddr; } LINPHONE_END_NAMESPACE diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index b731aba69..518dd4abe 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -51,29 +51,25 @@ void LocalConferenceEventHandlerPrivate::notifyFullState (const string ¬ify, } void LocalConferenceEventHandlerPrivate::notifyAllExcept (const string ¬ify, const Address &addr) { - Address cleanedAddr(addr); - cleanedAddr.setPort(0); + SimpleAddress simpleAddr(addr); for (const auto &participant : conf->getParticipants()) { - Address cleanedParticipantAddr(participant->getAddress()); - cleanedParticipantAddr.setPort(0); - if (participant->getPrivate()->isSubscribedToConferenceEventPackage() && !cleanedAddr.weakEqual(cleanedParticipantAddr)) - sendNotify(notify, participant->getAddress()); + if (participant->getPrivate()->isSubscribedToConferenceEventPackage() && (participant->getAddress() != simpleAddr)) + sendNotify(notify, participant->getContactAddress()); } } void LocalConferenceEventHandlerPrivate::notifyAll (const string ¬ify) { for (const auto &participant : conf->getParticipants()) { if (participant->getPrivate()->isSubscribedToConferenceEventPackage()) - sendNotify(notify, participant->getAddress()); + sendNotify(notify, participant->getContactAddress()); } } void LocalConferenceEventHandlerPrivate::notifyParticipant (const string ¬ify, const Address &addr) { - Address cleanedAddr(addr); - cleanedAddr.setPort(0); - shared_ptr participant = conf->findParticipant(cleanedAddr); + SimpleAddress simpleAddr(addr); + shared_ptr participant = conf->findParticipant(simpleAddr); if (participant->getPrivate()->isSubscribedToConferenceEventPackage()) - sendNotify(notify, participant->getAddress()); + sendNotify(notify, participant->getContactAddress()); } string LocalConferenceEventHandlerPrivate::createNotify (ConferenceType confInfo, int notifyId, bool isFullState) { diff --git a/src/conference/participant-p.h b/src/conference/participant-p.h index 258c65d7b..58993cd97 100644 --- a/src/conference/participant-p.h +++ b/src/conference/participant-p.h @@ -44,15 +44,17 @@ public: inline bool isSubscribedToConferenceEventPackage () const { return _isSubscribedToConferenceEventPackage; } inline void subscribeToConferenceEventPackage (bool value) { _isSubscribedToConferenceEventPackage = value; } inline void removeSession () { session.reset(); } - inline void setAddress (const Address &newAddr) { addr = newAddr; } + inline void setAddress (const SimpleAddress &newAddr) { addr = newAddr; } inline void setAdmin (bool isAdmin) { this->isAdmin = isAdmin; } + inline void setContactAddress (const Address &contactAddr) { this->contactAddr = contactAddr; } const std::list::const_iterator findDevice (const Address &gruu) const; const std::list &getDevices () const; void addDevice (const Address &gruu); void removeDevice (const Address &gruu); private: - Address addr; + SimpleAddress addr; + Address contactAddr; bool isAdmin = false; bool _isSubscribedToConferenceEventPackage = false; std::shared_ptr session; diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index ecafa17fd..cf2e370b4 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -70,21 +70,28 @@ void ParticipantPrivate::removeDevice (const Address &gruu) { Participant::Participant (const Address &address) : Object(*new ParticipantPrivate) { L_D(); - d->addr = address; + d->contactAddr = address; + d->addr = SimpleAddress(address); } Participant::Participant (Address &&address) : Object(*new ParticipantPrivate) { L_D(); - d->addr = move(address); + d->contactAddr = move(address); + d->addr = SimpleAddress(address); } // ----------------------------------------------------------------------------- -const Address& Participant::getAddress () const { +const SimpleAddress& Participant::getAddress () const { L_D(); return d->addr; } +const Address& Participant::getContactAddress () const { + L_D(); + return d->contactAddr; +} + // ----------------------------------------------------------------------------- bool Participant::isAdmin () const { diff --git a/src/conference/participant.h b/src/conference/participant.h index aefe33fab..41c0fab02 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -23,6 +23,7 @@ #include #include "address/address.h" +#include "address/simple-address.h" #include "object/object.h" #include "conference/params/call-session-params.h" #include "conference/participant-device.h" @@ -52,7 +53,8 @@ public: explicit Participant (const Address &address); explicit Participant (Address &&address); - const Address& getAddress () const; + const SimpleAddress& getAddress () const; + const Address& getContactAddress () const; bool isAdmin () const; private: diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 91a25a0f2..369d9ea17 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -19,6 +19,7 @@ #include +#include "address/simple-address.h" #include "chat/chat-room/basic-chat-room.h" #include "chat/chat-room/chat-room-p.h" #include "chat/chat-room/real-time-text-chat-room.h" @@ -38,28 +39,18 @@ LINPHONE_BEGIN_NAMESPACE // Helpers. // ----------------------------------------------------------------------------- -static inline Address getCleanedPeerAddress (const Address &peerAddress) { - if (!peerAddress.isValid()) - return Address(); - - Address cleanedAddress = peerAddress; - cleanedAddress.clean(); - cleanedAddress.setPort(0); - return cleanedAddress; -} - // TODO: Remove me later. static inline string resolveWorkaroundClientGroupChatRoomAddress ( const CorePrivate &corePrivate, - const Address &peerAddress + const SimpleAddress &peerAddr ) { const char *uri = linphone_core_get_conference_factory_uri(corePrivate.cCore); if (!uri) return ""; - Address workaroundAddress = peerAddress; - workaroundAddress.setDomain(Address(uri).getDomain()); - return workaroundAddress.asStringUriOnly(); + SimpleAddress workaroundAddr(peerAddr); + workaroundAddr.setDomain(Address(uri).getDomain()); + return workaroundAddr.asString(); } // ----------------------------------------------------------------------------- @@ -85,48 +76,48 @@ shared_ptr CorePrivate::createBasicChatRoom (const Address &peerAddres void CorePrivate::insertChatRoom (const shared_ptr &chatRoom) { L_ASSERT(chatRoom); - Address cleanedPeerAddress = getCleanedPeerAddress(chatRoom->getPeerAddress()); - + const SimpleAddress simpleAddr(chatRoom->getPeerAddress()); const string peerAddress = chatRoom->getCapabilities() & static_cast(ChatRoom::Capabilities::Conference) - ? resolveWorkaroundClientGroupChatRoomAddress(*this, cleanedPeerAddress) - : cleanedPeerAddress.asStringUriOnly(); + ? resolveWorkaroundClientGroupChatRoomAddress(*this, simpleAddr) + : simpleAddr.asString(); deleteChatRoom(peerAddress); - chatRooms.push_back(chatRoom); chatRoomsByUri[peerAddress] = chatRoom; } -void CorePrivate::deleteChatRoom (const string &peerAddress) { - auto it = chatRoomsByUri.find(peerAddress); +void CorePrivate::deleteChatRoom (const string &peerAddr) { + const SimpleAddress simpleAddr(peerAddr); + auto it = chatRoomsByUri.find(simpleAddr.asString()); if (it != chatRoomsByUri.end()) { - auto it = find_if(chatRooms.begin(), chatRooms.end(), [&peerAddress](const shared_ptr &chatRoom) { - return peerAddress == chatRoom->getPeerAddress().asStringUriOnly(); + auto it = find_if(chatRooms.begin(), chatRooms.end(), [&peerAddr, &simpleAddr](const shared_ptr &chatRoom) { + return peerAddr == simpleAddr.asString(); }); if (it != chatRooms.end()) { chatRooms.erase(it); return; } - - lError() << "Unable to remove chat room: " << peerAddress; + lError() << "Unable to remove chat room: " << peerAddr; } } void CorePrivate::insertChatRoomWithDb (const shared_ptr &chatRoom) { L_ASSERT(chatRoom->getState() == ChatRoom::State::Created); + const SimpleAddress simpleAddr(chatRoom->getPeerAddress()); ChatRoom::CapabilitiesMask capabilities = chatRoom->getCapabilities(); mainDb->insertChatRoom( capabilities & static_cast(ChatRoom::Capabilities::Conference) - ? resolveWorkaroundClientGroupChatRoomAddress(*this, chatRoom->getPeerAddress()) - : chatRoom->getPeerAddress().asStringUriOnly(), + ? resolveWorkaroundClientGroupChatRoomAddress(*this, simpleAddr) + : simpleAddr.asString(), capabilities ); } -void CorePrivate::deleteChatRoomWithDb (const string &peerAddress) { - deleteChatRoom(peerAddress); - mainDb->deleteChatRoom(peerAddress); +void CorePrivate::deleteChatRoomWithDb (const string &peerAddr) { + const SimpleAddress simpleAddr(peerAddr); + deleteChatRoom(simpleAddr.asString()); + mainDb->deleteChatRoom(simpleAddr.asString()); } // ----------------------------------------------------------------------------- @@ -136,21 +127,24 @@ const list> &Core::getChatRooms () const { return d->chatRooms; } -shared_ptr Core::findChatRoom (const Address &peerAddress) const { +shared_ptr Core::findChatRoom (const Address &peerAddr) const { L_D(); - Address cleanedAddress = getCleanedPeerAddress(peerAddress); - auto it = d->chatRoomsByUri.find(cleanedAddress.asStringUriOnly()); + const SimpleAddress simpleAddr(peerAddr); + auto it = d->chatRoomsByUri.find(simpleAddr.asString()); if (it != d->chatRoomsByUri.cend()) return it->second; - lInfo() << "Unable to find chat room: `" << peerAddress.asStringUriOnly() << "`."; + lInfo() << "Unable to find chat room: `" << simpleAddr.asString() << "`"; // TODO: Remove me, temp workaround. - const string workaroundAddress = resolveWorkaroundClientGroupChatRoomAddress(*d, cleanedAddress); - lWarning() << "Workaround: searching chat room with: `" << workaroundAddress << "`."; - it = d->chatRoomsByUri.find(workaroundAddress); - return it == d->chatRoomsByUri.cend() ? shared_ptr() : it->second; + const string workaroundAddress = resolveWorkaroundClientGroupChatRoomAddress(*d, simpleAddr); + if (!workaroundAddress.empty()) { + lWarning() << "Workaround: searching chat room with: `" << workaroundAddress << "`"; + it = d->chatRoomsByUri.find(workaroundAddress); + return it == d->chatRoomsByUri.cend() ? shared_ptr() : it->second; + } + return shared_ptr(); } shared_ptr Core::createClientGroupChatRoom (const string &subject) { @@ -199,11 +193,11 @@ shared_ptr Core::getOrCreateBasicChatRoom (const string &peerAddress, void Core::deleteChatRoom (const shared_ptr &chatRoom) { CorePrivate *d = chatRoom->getCore()->getPrivate(); - const Address cleanedPeerAddress = getCleanedPeerAddress(chatRoom->getPeerAddress()); + const SimpleAddress simpleAddr(chatRoom->getPeerAddress()); d->deleteChatRoomWithDb( chatRoom->getCapabilities() & static_cast(ChatRoom::Capabilities::Conference) - ? resolveWorkaroundClientGroupChatRoomAddress(*d, cleanedPeerAddress) - : cleanedPeerAddress.asStringUriOnly() + ? resolveWorkaroundClientGroupChatRoomAddress(*d, simpleAddr) + : simpleAddr.asString() ); } From d3948801497a0e99baeed934b4a38a630dcb1f38 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 7 Nov 2017 15:40:31 +0100 Subject: [PATCH 0712/2215] Removed cFileTransferContent to use only Content objects in chat-message.cpp for file transfer. Fix upload when not using file body handler to do --- src/chat/chat-message/chat-message-p.h | 7 +- src/chat/chat-message/chat-message.cpp | 171 +++++++++++++++---------- src/chat/chat-room/chat-room.cpp | 2 +- src/content/content.cpp | 11 ++ src/content/content.h | 3 + 5 files changed, 122 insertions(+), 72 deletions(-) diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index b33d43fff..a83781a53 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -81,7 +81,7 @@ public: std::string getSalCustomHeaderValue(const std::string& name); // ----------------------------------------------------------------------------- - // Methods only used for C wrapper, to be removed some day... + // Deprecated methods only used for C wrapper, to be removed some day... // ----------------------------------------------------------------------------- const ContentType &getContentType(); @@ -91,7 +91,7 @@ public: void setText(const std::string &text); LinphoneContent *getFileTransferInformation() const; - void setFileTransferInformation(LinphoneContent *content); + void setFileTransferInformation(const LinphoneContent *content); // ----------------------------------------------------------------------------- // Need to be public to be called from static C callbacks @@ -138,6 +138,7 @@ private: bool isReadOnly = false; std::list contents; Content internalContent; + Content *currentFileTransferContent; std::unordered_map customHeaders; mutable LinphoneErrorInfo * errorInfo = nullptr; belle_http_request_t *httpRequest = nullptr; @@ -150,8 +151,6 @@ private: // Cache for returned values, used for compatibility with previous C API ContentType cContentType; std::string cText; - // Used for compatibility with previous C API - LinphoneContent *cFileTransferInformation = nullptr; // ----------------------------------------------------------------------------- diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 068821313..b5b7a7a08 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -207,15 +207,25 @@ void ChatMessagePrivate::setText (const string &text) { } LinphoneContent *ChatMessagePrivate::getFileTransferInformation () const { - return cFileTransferInformation; + L_Q(); + //TODO cache and unref to prevent leak + if (q->hasFileTransferContent()) { + return q->getFileTransferContent().toLinphoneContent(); + } + return NULL; } -void ChatMessagePrivate::setFileTransferInformation (LinphoneContent *content) { - if (cFileTransferInformation) { - linphone_content_unref(cFileTransferInformation); - cFileTransferInformation = nullptr; +void ChatMessagePrivate::setFileTransferInformation (const LinphoneContent *c_content) { + L_Q(); + + Content content; + ContentType contentType(linphone_content_get_type(c_content), linphone_content_get_subtype(c_content)); + content.setContentType(contentType); + if (linphone_content_get_string_buffer(c_content) != NULL) { + content.setBody(linphone_content_get_string_buffer(c_content)); } - cFileTransferInformation = content; + content.setContentDisposition(linphone_content_get_name(c_content)); + q->addContent(content); } // ----------------------------------------------------------------------------- @@ -355,8 +365,9 @@ void ChatMessagePrivate::fileTransferOnProgress ( LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); + LinphoneContent *content = currentFileTransferContent->toLinphoneContent(); if (linphone_chat_message_cbs_get_file_transfer_progress_indication(cbs)) { - linphone_chat_message_cbs_get_file_transfer_progress_indication(cbs)(msg, cFileTransferInformation, offset, total); + linphone_chat_message_cbs_get_file_transfer_progress_indication(cbs)(msg, content, offset, total); } else { // Legacy: call back given by application level. shared_ptr core = q->getCore(); @@ -364,11 +375,12 @@ void ChatMessagePrivate::fileTransferOnProgress ( linphone_core_notify_file_transfer_progress_indication( core->getCCore(), msg, - cFileTransferInformation, + content, offset, total ); } + linphone_content_unref(content); } static int _chat_message_on_send_body ( @@ -406,13 +418,14 @@ int ChatMessagePrivate::onSendBody ( // if we've not reach the end of file yet, ask for more data // in case of file body handler, won't be called - if (fileTransferFilePath.empty() && offset < linphone_content_get_size(cFileTransferInformation)) { + if (fileTransferFilePath.empty() && offset < currentFileTransferContent->getSize()) { // get data from call back LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = linphone_chat_message_cbs_get_file_transfer_send(cbs); + LinphoneContent *content = currentFileTransferContent->toLinphoneContent(); if (file_transfer_send_cb) { - LinphoneBuffer *lb = file_transfer_send_cb(msg, cFileTransferInformation, offset, *size); + LinphoneBuffer *lb = file_transfer_send_cb(msg, content, offset, *size); if (lb == nullptr) { *size = 0; } else { @@ -424,8 +437,9 @@ int ChatMessagePrivate::onSendBody ( // Legacy shared_ptr core = q->getCore(); if (core) - linphone_core_notify_file_transfer_send(core->getCCore(), msg, cFileTransferInformation, (char *)buffer, size); + linphone_core_notify_file_transfer_send(core->getCCore(), msg, content, (char *)buffer, size); } + linphone_content_unref(content); } LinphoneImEncryptionEngine *imee = nullptr; @@ -551,14 +565,16 @@ void ChatMessagePrivate::onRecvBody (belle_sip_user_body_handler_t *bh, belle_si if (fileTransferFilePath.empty()) { LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); + LinphoneContent *content = currentFileTransferContent->toLinphoneContent(); if (linphone_chat_message_cbs_get_file_transfer_recv(cbs)) { LinphoneBuffer *lb = linphone_buffer_new_from_data(buffer, size); - linphone_chat_message_cbs_get_file_transfer_recv(cbs)(msg, cFileTransferInformation, lb); + linphone_chat_message_cbs_get_file_transfer_recv(cbs)(msg, content, lb); linphone_buffer_unref(lb); } else { // Legacy: call back given by application level - linphone_core_notify_file_transfer_recv(core->getCCore(), msg, cFileTransferInformation, (const char *)buffer, size); + linphone_core_notify_file_transfer_recv(core->getCCore(), msg, content, (const char *)buffer, size); } + linphone_content_unref(content); } } else { lWarning() << "File transfer decrypt failed with code " << (int)retval; @@ -593,14 +609,16 @@ void ChatMessagePrivate::onRecvEnd (belle_sip_user_body_handler_t *bh) { if (fileTransferFilePath.empty()) { LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); + LinphoneContent *content = currentFileTransferContent->toLinphoneContent(); if (linphone_chat_message_cbs_get_file_transfer_recv(cbs)) { LinphoneBuffer *lb = linphone_buffer_new(); - linphone_chat_message_cbs_get_file_transfer_recv(cbs)(msg, cFileTransferInformation, lb); + linphone_chat_message_cbs_get_file_transfer_recv(cbs)(msg, content, lb); linphone_buffer_unref(lb); } else { // Legacy: call back given by application level - linphone_core_notify_file_transfer_recv(core->getCCore(), msg, cFileTransferInformation, nullptr, 0); + linphone_core_notify_file_transfer_recv(core->getCCore(), msg, content, nullptr, 0); } + linphone_content_unref(content); } } @@ -669,32 +687,31 @@ void ChatMessagePrivate::processResponseFromPostFile (const belle_http_response_ first_part_header = "form-data; name=\"File\"; filename=\"filename.txt\""; } else { // temporary storage for the Content-disposition header value - first_part_header = "form-data; name=\"File\"; filename=\"" + string(linphone_content_get_name(cFileTransferInformation)) + "\""; + first_part_header = "form-data; name=\"File\"; filename=\"" + currentFileTransferContent->getContentDisposition() + "\""; } // create a user body handler to take care of the file and add the content disposition and content-type headers - first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new( - linphone_content_get_size(cFileTransferInformation), + first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(currentFileTransferContent->getSize(), _chat_message_file_transfer_on_progress, nullptr, nullptr, _chat_message_on_send_body, _chat_message_on_send_end, this); if (!fileTransferFilePath.empty()) { belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh; // No need to add again the callback for progression, otherwise it will be called twice first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(fileTransferFilePath.c_str(), nullptr, this); - linphone_content_set_size(cFileTransferInformation, belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh)); + //linphone_content_set_size(cFileTransferInformation, belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh)); belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)first_part_bh, body_handler); - } else if (linphone_content_get_buffer(cFileTransferInformation) != nullptr) { + } else if (!currentFileTransferContent->isEmpty()) { first_part_bh = (belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer( - linphone_content_get_buffer(cFileTransferInformation), - linphone_content_get_size(cFileTransferInformation), _chat_message_file_transfer_on_progress, this); + ms_strdup(currentFileTransferContent->getBodyAsString().c_str()), + currentFileTransferContent->getSize(), _chat_message_file_transfer_on_progress, this); } belle_sip_body_handler_add_header(first_part_bh, belle_sip_header_create("Content-disposition", first_part_header.c_str())); belle_sip_body_handler_add_header(first_part_bh, (belle_sip_header_t *)belle_sip_header_content_type_create( - linphone_content_get_type(cFileTransferInformation), - linphone_content_get_subtype(cFileTransferInformation))); + currentFileTransferContent->getContentType().getType().c_str(), + currentFileTransferContent->getContentType().getSubType().c_str())); // insert it in a multipart body handler which will manage the boundaries of multipart msg bh = belle_sip_multipart_body_handler_new(_chat_message_file_transfer_on_progress, this, first_part_bh, nullptr); @@ -706,8 +723,9 @@ void ChatMessagePrivate::processResponseFromPostFile (const belle_http_response_ } else if (code == 200) { // file has been uploaded correctly, get server reply and send it const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); if (body && strlen(body) > 0) { + //TODO // if we have an encryption key for the file, we must insert it into the msg and restore the correct filename - const char *content_key = linphone_content_get_key(cFileTransferInformation); + /*const char *content_key = linphone_content_get_key(cFileTransferInformation); size_t content_key_size = linphone_content_get_key_size(cFileTransferInformation); if (content_key != nullptr) { // parse the msg body @@ -760,15 +778,13 @@ void ChatMessagePrivate::processResponseFromPostFile (const belle_http_response_ } } xmlFreeDoc(xmlMessageBody); - } else { // no encryption key, transfer in plain, just copy the msg sent by server + } else { // no encryption key, transfer in plain, just copy the msg sent by server setText(body); } - setContentType(ContentType::FileTransfer); + setContentType(ContentType::FileTransfer);*/ - Content fileTransferContent; - fileTransferContent.setContentType(ContentType::FileTransfer); - fileTransferContent.setBody(internalContent.getBodyAsString()); - q->addContent(fileTransferContent); + (*currentFileTransferContent).setContentType(ContentType::FileTransfer); + (*currentFileTransferContent).setBody(body); q->updateState(ChatMessage::State::FileTransferDone); releaseHttpRequest(); @@ -794,36 +810,32 @@ static void _chat_process_response_headers_from_get_file (void *data, const bell d->processResponseHeadersFromGetFile(event); } -static LinphoneContent *createFileTransferInformationFromHeaders (const belle_sip_message_t *m) { - LinphoneContent *content = linphone_content_new(); +static Content createFileTransferInformationFromHeaders (const belle_sip_message_t *m) { + Content content; belle_sip_header_content_length_t *content_length_hdr = BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(m, "Content-Length")); belle_sip_header_content_type_t *content_type_hdr = BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(m, "Content-Type")); const char *type = nullptr, *subtype = nullptr; - linphone_content_set_name(content, ""); - if (content_type_hdr) { type = belle_sip_header_content_type_get_type(content_type_hdr); subtype = belle_sip_header_content_type_get_subtype(content_type_hdr); lInfo() << "Extracted content type " << type << " / " << subtype << " from header"; - if (type) { - linphone_content_set_type(content, type); - } - if (subtype) { - linphone_content_set_subtype(content, subtype); - } + ContentType contentType(type, subtype); } - if (content_length_hdr) { - linphone_content_set_size(content, belle_sip_header_content_length_get_content_length(content_length_hdr)); - lInfo() << "Extracted content length " << linphone_content_get_size(content) << " from header"; + // This is a ugly workaround required to be able to get the total size of the file in the content + vector empty(belle_sip_header_content_length_get_content_length(content_length_hdr)); + content.setBody(empty); + lInfo() << "Extracted content length " << content.getSize() << " from header"; } return content; } void ChatMessagePrivate::processResponseHeadersFromGetFile (const belle_http_response_event_t *event) { + L_Q(); + if (event->response) { // we are receiving a response, set a specific body handler to acquire the response. // if not done, belle-sip will create a memory body handler, the default @@ -831,13 +843,20 @@ void ChatMessagePrivate::processResponseHeadersFromGetFile (const belle_http_res belle_sip_body_handler_t *body_handler = nullptr; size_t body_size = 0; - if (cFileTransferInformation == nullptr) { + if (currentFileTransferContent == nullptr) { lWarning() << "No file transfer information for msg [" << this << "]: creating..."; - cFileTransferInformation = createFileTransferInformationFromHeaders(response); + Content content = createFileTransferInformationFromHeaders(response); + q->addContent(content); + } else { + belle_sip_header_content_length_t *content_length_hdr = BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(response, "Content-Length")); + // This is a ugly workaround required to be able to get the total size of the file in the content + vector empty(belle_sip_header_content_length_get_content_length(content_length_hdr)); + currentFileTransferContent->setBody(empty); + lInfo() << "Extracted content length " << currentFileTransferContent->getSize() << " from header"; } - if (cFileTransferInformation) { - body_size = linphone_content_get_size(cFileTransferInformation); + if (q->hasFileTransferContent()) { + body_size = q->getFileTransferContent().getSize(); } body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, _chat_message_file_transfer_on_progress, @@ -992,13 +1011,13 @@ void ChatMessagePrivate::releaseHttpRequest () { } void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml (const string &body) { + L_Q(); xmlChar *file_url = nullptr; xmlDocPtr xmlMessageBody; xmlNodePtr cur; /* parse the msg body to get all informations from it */ xmlMessageBody = xmlParseDoc((const xmlChar *)body.c_str()); - LinphoneContent *content = linphone_content_new(); - setFileTransferInformation(content); + Content content; cur = xmlDocGetRootElement(xmlMessageBody); if (cur != nullptr) { @@ -1012,48 +1031,52 @@ void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml ( while (cur != nullptr) { if (!xmlStrcmp(cur->name, (const xmlChar *)"file-size")) { xmlChar *fileSizeString = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - linphone_content_set_size(content, (size_t)strtol((const char *)fileSizeString, nullptr, 10)); + size_t size = (size_t)strtol((const char *)fileSizeString, nullptr, 10); + // This is a ugly workaround required to be able to get the total size of the file in the content + vector empty(size); + content.setBody(empty); xmlFree(fileSizeString); } if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) { xmlChar *filename = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - linphone_content_set_name(content, (char *)filename); + content.setContentDisposition((char *)filename); xmlFree(filename); } if (!xmlStrcmp(cur->name, (const xmlChar *)"content-type")) { - xmlChar *contentType = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); + xmlChar *content_type = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); int contentTypeIndex = 0; char *type; char *subtype; - while (contentType[contentTypeIndex] != '/' && contentType[contentTypeIndex] != '\0') { + while (content_type[contentTypeIndex] != '/' && content_type[contentTypeIndex] != '\0') { contentTypeIndex++; } - type = ms_strndup((char *)contentType, contentTypeIndex); - subtype = ms_strdup(((char *)contentType + contentTypeIndex + 1)); - linphone_content_set_type(content, type); - linphone_content_set_subtype(content, subtype); + type = ms_strndup((char *)content_type, contentTypeIndex); + subtype = ms_strdup(((char *)content_type + contentTypeIndex + 1)); + ContentType contentType(type, subtype); + content.setContentType(contentType); ms_free(subtype); ms_free(type); - xmlFree(contentType); + ms_free(content_type); } if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) { file_url = xmlGetProp(cur, (const xmlChar *)"url"); } - if (!xmlStrcmp(cur->name, (const xmlChar *)"file-key")) { - /* there is a key in the msg: file has been encrypted */ - /* convert the key from base 64 */ + //TODO + /*if (!xmlStrcmp(cur->name, (const xmlChar *)"file-key")) { + // there is a key in the msg: file has been encrypted + // convert the key from base 64 xmlChar *keyb64 = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); size_t keyLength = b64::b64_decode((char *)keyb64, strlen((char *)keyb64), nullptr, 0); uint8_t *keyBuffer = (uint8_t *)malloc(keyLength); - /* decode the key into local key buffer */ + // decode the key into local key buffer b64::b64_decode((char *)keyb64, strlen((char *)keyb64), keyBuffer, keyLength); linphone_content_set_key(content, (char *)keyBuffer, keyLength); - /* duplicate key value into the linphone content private structure */ + // duplicate key value into the linphone content private structure xmlFree(keyb64); free(keyBuffer); - } + }*/ cur = cur->next; } @@ -1068,6 +1091,7 @@ void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml ( xmlFreeDoc(xmlMessageBody); externalBodyUrl = string((const char *)file_url); + q->addContent(content); xmlFree(file_url); } @@ -1165,14 +1189,23 @@ void ChatMessagePrivate::send () { if ((currentSendStep & ChatMessagePrivate::Step::FileUpload) == ChatMessagePrivate::Step::FileUpload) { lInfo() << "File upload step already done, skipping"; } else { - if (getFileTransferInformation()) { + currentFileTransferContent = nullptr; + for (Content &content : contents) { + ContentType contentType = content.getContentType(); + if (contentType != ContentType::FileTransfer && contentType != ContentType::PlainText) { + lInfo() << "Found content with content type " << contentType.asString() << ", set it for file upload"; + currentFileTransferContent = &content; + break; + } + } + if (currentFileTransferContent != nullptr) { /* Open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */ if (q->uploadFile() == 0) { setState(ChatMessage::State::InProgress); - currentSendStep |= ChatMessagePrivate::Step::FileUpload; } return; } + currentSendStep |= ChatMessagePrivate::Step::FileUpload; } shared_ptr core = q->getCore(); @@ -1654,6 +1687,10 @@ int ChatMessage::downloadFile () { return -1; } + if (hasFileTransferContent()) { + d->currentFileTransferContent = (Content *)&getFileTransferContent(); + } + belle_http_request_listener_callbacks_t cbs = { 0 }; cbs.process_response_headers = _chat_process_response_headers_from_get_file; cbs.process_response = _chat_message_process_response_from_get_file; diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index cfba88fd7..9e341f041 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -459,7 +459,7 @@ shared_ptr ChatRoom::createFileTransferMessage (const LinphoneConte shared_ptr chatMessage = createMessage(); chatMessage->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); - chatMessage->getPrivate()->setFileTransferInformation(linphone_content_copy(initialContent)); + chatMessage->getPrivate()->setFileTransferInformation(initialContent); return chatMessage; } diff --git a/src/content/content.cpp b/src/content/content.cpp index 978f5db3b..c94fc1449 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -21,6 +21,7 @@ #include "object/clonable-object-p.h" #include "content.h" +#include "linphone/core.h" // ============================================================================= @@ -153,4 +154,14 @@ bool Content::isValid() const { return d->contentType.isValid() || d->body.empty(); } +LinphoneContent * Content::toLinphoneContent() const { + LinphoneContent* content; + content = linphone_core_create_content(NULL); + linphone_content_set_type(content, getContentType().getType().c_str()); + linphone_content_set_subtype(content, getContentType().getSubType().c_str()); + linphone_content_set_size(content, getSize()); + linphone_content_set_name(content, getContentDisposition().c_str()); + return content; +} + LINPHONE_END_NAMESPACE diff --git a/src/content/content.h b/src/content/content.h index 3e5f5fb8d..1fb1ae98e 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -24,6 +24,7 @@ #include "object/app-data-container.h" #include "object/clonable-object.h" +#include "linphone/content.h" // ============================================================================= @@ -63,6 +64,8 @@ public: bool isEmpty () const; + LinphoneContent * toLinphoneContent() const; + static const Content Empty; private: From e97502299a6ce62a90bccbe7f7d8172edd545e84 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 7 Nov 2017 15:51:46 +0100 Subject: [PATCH 0713/2215] fix(object-p): add missing import --- src/object/object-p.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/object/object-p.h b/src/object/object-p.h index bcc3b787e..e4b46c53f 100644 --- a/src/object/object-p.h +++ b/src/object/object-p.h @@ -24,6 +24,7 @@ #include #include "base-object-p.h" +#include "object.h" #include "variant/variant.h" // ============================================================================= From 1fa52f708e6b09d3071907eea6777081f59a7f22 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 7 Nov 2017 15:55:10 +0100 Subject: [PATCH 0714/2215] Forgot to set file size when creating the file transfer informations --- src/chat/chat-message/chat-message.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index b5b7a7a08..cbe40188e 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -225,6 +225,11 @@ void ChatMessagePrivate::setFileTransferInformation (const LinphoneContent *c_co content.setBody(linphone_content_get_string_buffer(c_content)); } content.setContentDisposition(linphone_content_get_name(c_content)); + + // This is a ugly workaround required to be able to get the total size of the file in the content + vector empty(linphone_content_get_size(c_content)); + content.setBody(empty); + q->addContent(content); } From c6894b4c86f7f919eb874008bc53fdcf7c7d43bf Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 7 Nov 2017 16:28:44 +0100 Subject: [PATCH 0715/2215] Fixed file transfer --- src/chat/chat-message/chat-message.cpp | 27 +++++++++----------------- src/content/content.cpp | 17 +++++++++++++++- src/content/content.h | 3 +++ 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index cbe40188e..40c1266ca 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -225,10 +225,7 @@ void ChatMessagePrivate::setFileTransferInformation (const LinphoneContent *c_co content.setBody(linphone_content_get_string_buffer(c_content)); } content.setContentDisposition(linphone_content_get_name(c_content)); - - // This is a ugly workaround required to be able to get the total size of the file in the content - vector empty(linphone_content_get_size(c_content)); - content.setBody(empty); + content.setExpectedSize(linphone_content_get_size(c_content)); q->addContent(content); } @@ -423,7 +420,7 @@ int ChatMessagePrivate::onSendBody ( // if we've not reach the end of file yet, ask for more data // in case of file body handler, won't be called - if (fileTransferFilePath.empty() && offset < currentFileTransferContent->getSize()) { + if (fileTransferFilePath.empty() && offset < currentFileTransferContent->getExpectedSize()) { // get data from call back LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = @@ -696,7 +693,7 @@ void ChatMessagePrivate::processResponseFromPostFile (const belle_http_response_ } // create a user body handler to take care of the file and add the content disposition and content-type headers - first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(currentFileTransferContent->getSize(), + first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(currentFileTransferContent->getExpectedSize(), _chat_message_file_transfer_on_progress, nullptr, nullptr, _chat_message_on_send_body, _chat_message_on_send_end, this); if (!fileTransferFilePath.empty()) { @@ -829,10 +826,8 @@ static Content createFileTransferInformationFromHeaders (const belle_sip_message ContentType contentType(type, subtype); } if (content_length_hdr) { - // This is a ugly workaround required to be able to get the total size of the file in the content - vector empty(belle_sip_header_content_length_get_content_length(content_length_hdr)); - content.setBody(empty); - lInfo() << "Extracted content length " << content.getSize() << " from header"; + content.setExpectedSize(belle_sip_header_content_length_get_content_length(content_length_hdr)); + lInfo() << "Extracted content length " << content.getExpectedSize() << " from header"; } return content; @@ -854,14 +849,12 @@ void ChatMessagePrivate::processResponseHeadersFromGetFile (const belle_http_res q->addContent(content); } else { belle_sip_header_content_length_t *content_length_hdr = BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(response, "Content-Length")); - // This is a ugly workaround required to be able to get the total size of the file in the content - vector empty(belle_sip_header_content_length_get_content_length(content_length_hdr)); - currentFileTransferContent->setBody(empty); - lInfo() << "Extracted content length " << currentFileTransferContent->getSize() << " from header"; + currentFileTransferContent->setExpectedSize(belle_sip_header_content_length_get_content_length(content_length_hdr)); + lInfo() << "Extracted content length " << currentFileTransferContent->getExpectedSize() << " from header"; } if (q->hasFileTransferContent()) { - body_size = q->getFileTransferContent().getSize(); + body_size = q->getFileTransferContent().getExpectedSize(); } body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, _chat_message_file_transfer_on_progress, @@ -1037,9 +1030,7 @@ void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml ( if (!xmlStrcmp(cur->name, (const xmlChar *)"file-size")) { xmlChar *fileSizeString = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); size_t size = (size_t)strtol((const char *)fileSizeString, nullptr, 10); - // This is a ugly workaround required to be able to get the total size of the file in the content - vector empty(size); - content.setBody(empty); + content.setExpectedSize(size); xmlFree(fileSizeString); } diff --git a/src/content/content.cpp b/src/content/content.cpp index c94fc1449..327dbfe90 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -34,6 +34,7 @@ public: vector body; ContentType contentType; string contentDisposition; + size_t expectedSize; }; const Content Content::Empty; @@ -47,6 +48,7 @@ Content::Content (const Content &src) : ClonableObject(*new ContentPrivate), App d->body = src.getBody(); d->contentType = src.getContentType(); d->contentDisposition = src.getContentDisposition(); + d->expectedSize = src.getExpectedSize(); } Content::Content (Content &&src) : ClonableObject(*new ContentPrivate), AppDataContainer(move(src)) { @@ -54,6 +56,7 @@ Content::Content (Content &&src) : ClonableObject(*new ContentPrivate), AppDataC d->body = move(src.getPrivate()->body); d->contentType = move(src.getPrivate()->contentType); d->contentDisposition = move(src.getPrivate()->contentDisposition); + d->expectedSize = move(src.getExpectedSize()); } Content &Content::operator= (const Content &src) { @@ -62,6 +65,7 @@ Content &Content::operator= (const Content &src) { d->body = src.getBody(); d->contentType = src.getContentType(); d->contentDisposition = src.getContentDisposition(); + d->expectedSize = src.getExpectedSize(); AppDataContainer::operator=(src); } @@ -73,6 +77,7 @@ Content &Content::operator= (Content &&src) { d->body = move(src.getPrivate()->body); d->contentType = move(src.getPrivate()->contentType); d->contentDisposition = move(src.getPrivate()->contentDisposition); + d->expectedSize = move(src.getExpectedSize()); AppDataContainer::operator=(move(src)); return *this; } @@ -145,6 +150,16 @@ size_t Content::getSize () const { return d->body.size(); } +void Content::setExpectedSize(size_t expectedSize) { + L_D(); + d->expectedSize = expectedSize; +} + +size_t Content::getExpectedSize() const { + L_D(); + return d->expectedSize; +} + bool Content::isEmpty () const { return getSize() == 0; } @@ -159,7 +174,7 @@ LinphoneContent * Content::toLinphoneContent() const { content = linphone_core_create_content(NULL); linphone_content_set_type(content, getContentType().getType().c_str()); linphone_content_set_subtype(content, getContentType().getSubType().c_str()); - linphone_content_set_size(content, getSize()); + linphone_content_set_size(content, getExpectedSize()); linphone_content_set_name(content, getContentDisposition().c_str()); return content; } diff --git a/src/content/content.h b/src/content/content.h index 1fb1ae98e..450f1c0eb 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -60,6 +60,9 @@ public: size_t getSize () const; + void setExpectedSize(size_t expectedSize); + size_t getExpectedSize() const; + bool isValid() const; bool isEmpty () const; From 61d11efdc730d43c30a40ce34171b7746e5dda61 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 7 Nov 2017 16:38:15 +0100 Subject: [PATCH 0716/2215] Fixed idmn, composing etc... messages trying to be file uploaded... --- src/chat/chat-message/chat-message.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 40c1266ca..ddea3c8c2 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -1188,10 +1188,15 @@ void ChatMessagePrivate::send () { currentFileTransferContent = nullptr; for (Content &content : contents) { ContentType contentType = content.getContentType(); - if (contentType != ContentType::FileTransfer && contentType != ContentType::PlainText) { - lInfo() << "Found content with content type " << contentType.asString() << ", set it for file upload"; - currentFileTransferContent = &content; - break; + //TODO Improve ! + if (contentType != ContentType::FileTransfer && contentType != ContentType::PlainText && + contentType != ContentType::ExternalBody && contentType != ContentType::Imdn && + contentType != ContentType::ImIsComposing && contentType != ContentType::ResourceLists && + contentType != ContentType::Sdp && contentType != ContentType::ConferenceInfo && + contentType != ContentType::Cpim) { + lInfo() << "Found content with type " << contentType.asString() << ", set it for file upload"; + currentFileTransferContent = &content; + break; } } if (currentFileTransferContent != nullptr) { From 79e6d1ca3cbf9fb61e2c1329327217db99205aae Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 7 Nov 2017 16:45:49 +0100 Subject: [PATCH 0717/2215] use simple address in remote-conference-event-handler --- src/conference/remote-conference-event-handler.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 1c768441d..aa79c5fcb 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -17,6 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "address/simple-address.h" #include "private.h" #include "logger/logger.h" #include "remote-conference-event-handler-p.h" @@ -78,13 +79,12 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { tm = static_cast(Utils::stoll(confInfo->getConferenceDescription()->getFreeText().get())); bool isFullState = (confInfo->getState() == StateType::full); - Address cleanedConfAddress = d->confAddress; - cleanedConfAddress.clean(); + SimpleAddress simpleConfAddress(d->confAddress); // Temporary workaround - Address entityAddress(confInfo->getEntity().c_str()); - Address cleanedConfAddress2(cleanedConfAddress); - cleanedConfAddress2.setDomain(entityAddress.getDomain()); - if (entityAddress.weakEqual(cleanedConfAddress) || entityAddress.weakEqual(cleanedConfAddress2)) { + SimpleAddress entityAddress(confInfo->getEntity().c_str()); + SimpleAddress simpleConfAddress2(simpleConfAddress); + simpleConfAddress2.setDomain(entityAddress.getDomain()); + if ((entityAddress == simpleConfAddress) || (entityAddress == simpleConfAddress2)) { if ( confInfo->getConferenceDescription().present() && confInfo->getConferenceDescription().get().getSubject().present() From 5b0cfaa137538099d42480ff9f8e7ef76376f4c1 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 7 Nov 2017 17:04:58 +0100 Subject: [PATCH 0718/2215] Added missing C API for file transfer file name --- include/linphone/api/c-chat-message.h | 7 +++++++ src/c-wrapper/api/c-chat-message.cpp | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index e487a3b5f..b69cab0ba 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -375,6 +375,13 @@ LINPHONE_PUBLIC bool_t linphone_chat_message_has_file_transfer_content(const Lin */ LINPHONE_PUBLIC const char* linphone_chat_message_get_text_content(const LinphoneChatMessage *msg); +/** + * Gets the file transfer content if available as a string + * @param[in] msg LinphoneChatMessage object + * @return the file name if available, null otherwise + */ +LINPHONE_PUBLIC const char* linphone_chat_message_get_file_transfer_content_file_name(const LinphoneChatMessage *msg); + /** * @} */ diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index ce1b1cdf8..6402943fb 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -321,6 +321,14 @@ const char * linphone_chat_message_get_text_content(const LinphoneChatMessage *m return L_STRING_TO_C(content.getBodyAsString()); } +const char* linphone_chat_message_get_file_transfer_content_file_name(const LinphoneChatMessage *msg) { + LinphonePrivate::Content content = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFileTransferContent(); + if (content == LinphonePrivate::Content::Empty) { + return NULL; + } + return L_STRING_TO_C(content.getContentDisposition()); +} + // ============================================================================= // Old listener // ============================================================================= From adf574413b7b82d5dd051f100f0192372dbdbf12 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 7 Nov 2017 17:30:20 +0100 Subject: [PATCH 0719/2215] fix(MainDb): remove cleanEvents functions => not easy to implement for events life --- src/db/main-db.cpp | 21 --------------------- src/db/main-db.h | 1 - 2 files changed, 22 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 989d1ce68..8b335d972 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -854,25 +854,6 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return storageId == -1; } - void MainDb::cleanEvents (FilterMask mask) { - L_D(); - - if (!isConnected()) { - lWarning() << "Unable to clean events. Not connected."; - return; - } - - string query = "DELETE FROM event" + - buildSqlEventFilter({ ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter }, mask); - - L_BEGIN_LOG_EXCEPTION - - soci::session *session = d->dbSession.getBackendSession(); - *session << query; - - L_END_LOG_EXCEPTION - } - int MainDb::getEventsCount (FilterMask mask) const { L_D(); @@ -1416,8 +1397,6 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return false; } - void MainDb::cleanEvents (FilterMask) {} - int MainDb::getEventsCount (FilterMask) const { return 0; } diff --git a/src/db/main-db.h b/src/db/main-db.h index f04c6d779..3f96b1dde 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -54,7 +54,6 @@ public: bool addEvent (const std::shared_ptr &eventLog); bool deleteEvent (const std::shared_ptr &eventLog); - void cleanEvents (FilterMask mask = NoFilter); int getEventsCount (FilterMask mask = NoFilter) const; // --------------------------------------------------------------------------- From 25ea1d7c69439ca5459d653c819d7d23119cc4aa Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 7 Nov 2017 17:37:08 +0100 Subject: [PATCH 0720/2215] Actually this is not needed. The file name after file transfer is in a Content with the object type (ie image/jpeg) --- include/linphone/api/c-chat-message.h | 14 -------------- src/c-wrapper/api/c-chat-message.cpp | 12 ------------ 2 files changed, 26 deletions(-) diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index b69cab0ba..b00e8f9ae 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -361,13 +361,6 @@ LINPHONE_PUBLIC void linphone_chat_message_add_text_content(LinphoneChatMessage */ LINPHONE_PUBLIC bool_t linphone_chat_message_has_text_content(const LinphoneChatMessage *msg); -/** - * Returns true if the chat message has a file transfer content - * @param[in] msg LinphoneChatMessage object - * @return true if it has one, false otherwise - */ -LINPHONE_PUBLIC bool_t linphone_chat_message_has_file_transfer_content(const LinphoneChatMessage *msg); - /** * Gets the text content if available as a string * @param[in] msg LinphoneChatMessage object @@ -375,13 +368,6 @@ LINPHONE_PUBLIC bool_t linphone_chat_message_has_file_transfer_content(const Lin */ LINPHONE_PUBLIC const char* linphone_chat_message_get_text_content(const LinphoneChatMessage *msg); -/** - * Gets the file transfer content if available as a string - * @param[in] msg LinphoneChatMessage object - * @return the file name if available, null otherwise - */ -LINPHONE_PUBLIC const char* linphone_chat_message_get_file_transfer_content_file_name(const LinphoneChatMessage *msg); - /** * @} */ diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 6402943fb..8cdd4d4c1 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -309,10 +309,6 @@ bool_t linphone_chat_message_has_text_content(const LinphoneChatMessage *msg) { return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->hasTextContent(); } -bool_t linphone_chat_message_has_file_transfer_content(const LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->hasFileTransferContent(); -} - const char * linphone_chat_message_get_text_content(const LinphoneChatMessage *msg) { LinphonePrivate::Content content = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getTextContent(); if (content == LinphonePrivate::Content::Empty) { @@ -321,14 +317,6 @@ const char * linphone_chat_message_get_text_content(const LinphoneChatMessage *m return L_STRING_TO_C(content.getBodyAsString()); } -const char* linphone_chat_message_get_file_transfer_content_file_name(const LinphoneChatMessage *msg) { - LinphonePrivate::Content content = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFileTransferContent(); - if (content == LinphonePrivate::Content::Empty) { - return NULL; - } - return L_STRING_TO_C(content.getContentDisposition()); -} - // ============================================================================= // Old listener // ============================================================================= From 5d47a1093d05682b1e8405572aa729ef85d49112 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 7 Nov 2017 17:47:58 +0100 Subject: [PATCH 0721/2215] Fixed compil --- tester/message_tester.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tester/message_tester.c b/tester/message_tester.c index ccd535f27..b97a28cb0 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -2334,12 +2334,10 @@ void file_and_text_message(void) { BC_ASSERT_TRUE(linphone_chat_message_has_text_content(msg)); BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text_content(msg), "Text message"); - BC_ASSERT_FALSE(linphone_chat_message_has_file_transfer_content(msg)); // On sender side, content is a file content, not a file transfer linphone_chat_room_send_chat_message(chat_room, msg); BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageReceived, 1, 60000)); - BC_ASSERT_TRUE(linphone_chat_message_has_file_transfer_content(msg)); // Once sent, it should have the file transfer content if (marie->stat.last_received_chat_message) { LinphoneChatMessage *recv_msg; @@ -2347,7 +2345,6 @@ void file_and_text_message(void) { BC_ASSERT_TRUE(linphone_chat_message_has_text_content(recv_msg)); BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text_content(recv_msg), "Text message"); - BC_ASSERT_TRUE(linphone_chat_message_has_file_transfer_content(recv_msg)); cbs = linphone_chat_message_get_callbacks(recv_msg); linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); From dfbf8e031e0e7f9dbaedc838d98d16cd140d7ec9 Mon Sep 17 00:00:00 2001 From: Erwan Croze Date: Wed, 8 Nov 2017 11:39:00 +0100 Subject: [PATCH 0722/2215] Fix uninitialized variable --- coreapi/linphonecore.c | 2 +- src/content/content-manager.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 090f90641..86893059d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2608,7 +2608,7 @@ void linphone_core_add_friend_list(LinphoneCore *lc, LinphoneFriendList *list) { const bctbx_list_t * linphone_core_find_contacts_by_char(LinphoneCore *core, const char *filter, bool_t sip_only) { // Get sipuri from filter if possible - bctbx_list_t *list, *_list = NULL; + bctbx_list_t *list = NULL, *_list = NULL; LinphoneAddress *addr = linphone_core_interpret_url(core, (sip_only) ? filter : ""); bctbx_list_t* listFriendsList = (bctbx_list_t*)linphone_core_get_friends_lists(core); bctbx_list_t* listFriend = (listFriendsList != NULL) diff --git a/src/content/content-manager.cpp b/src/content/content-manager.cpp index c3071ca19..285c3f998 100644 --- a/src/content/content-manager.cpp +++ b/src/content/content-manager.cpp @@ -74,7 +74,7 @@ list ContentManager::multipartToContentLists (Content content) const { Content ContentManager::contentsListToMultipart (list contents) const { char *desc; string sub; - belle_sip_memory_body_handler_t *mbh; + belle_sip_memory_body_handler_t *mbh = NULL; belle_sip_multipart_body_handler_t *mpbh = belle_sip_multipart_body_handler_new(NULL, NULL, NULL, MULTIPART_BOUNDARY); belle_sip_object_ref(mpbh); for (const auto &content : contents) { From fe014194707d08440e6b388ac5241626f6a54e30 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 8 Nov 2017 11:58:02 +0100 Subject: [PATCH 0723/2215] Do not store nor notify app for full state generated events --- include/linphone/api/c-event-log.h | 7 -- src/c-wrapper/api/c-event-log.cpp | 9 -- src/chat/chat-room/client-group-chat-room.cpp | 30 ++++- src/chat/chat-room/client-group-chat-room.h | 12 +- src/conference/conference-listener.h | 15 +-- .../remote-conference-event-handler.cpp | 107 ++++++++++-------- src/conference/remote-conference.cpp | 30 ++++- src/conference/remote-conference.h | 12 +- src/db/main-db.cpp | 3 - .../conference/conference-notified-event-p.h | 1 - .../conference/conference-notified-event.cpp | 9 -- .../conference/conference-notified-event.h | 3 - .../conference-participant-device-event.cpp | 2 - .../conference-participant-device-event.h | 1 - .../conference-participant-event.cpp | 4 - .../conference/conference-participant-event.h | 2 - .../conference/conference-subject-event.cpp | 2 - .../conference/conference-subject-event.h | 1 - tester/conference-event-tester.cpp | 30 +++-- 19 files changed, 147 insertions(+), 133 deletions(-) diff --git a/include/linphone/api/c-event-log.h b/include/linphone/api/c-event-log.h index 4a13f21d6..c3f9e67c6 100644 --- a/include/linphone/api/c-event-log.h +++ b/include/linphone/api/c-event-log.h @@ -83,13 +83,6 @@ LINPHONE_PUBLIC const LinphoneAddress *linphone_event_log_get_conference_address */ LINPHONE_PUBLIC unsigned int linphone_event_log_get_notify_id (const LinphoneEventLog *event_log); -/** - * Returns whether or not the event comes from a full state notify. - * @param[in] event_log A #LinphoneEventLog object. - * @return whether or not the event comes from a full state notify. - */ -LINPHONE_PUBLIC bool_t linphone_event_log_is_full_state (const LinphoneEventLog *event_log); - // ----------------------------------------------------------------------------- // ConferenceCallEvent. // ----------------------------------------------------------------------------- diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index a9514ee67..132982327 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -193,15 +193,6 @@ unsigned int linphone_event_log_get_notify_id (const LinphoneEventLog *event_log )->getNotifyId(); } -bool_t linphone_event_log_is_full_state (const LinphoneEventLog *event_log) { - if (!isConferenceNotifiedType(linphone_event_log_get_type(event_log))) - return FALSE; - - return static_pointer_cast( - L_GET_CPP_PTR_FROM_C_OBJECT(event_log) - )->isFullState(); -} - // ----------------------------------------------------------------------------- // ConferenceCallEvent. // ----------------------------------------------------------------------------- diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index b5430c0e5..329ef2c8c 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -263,7 +263,7 @@ void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { d->setState(ChatRoom::State::Terminated); } -void ClientGroupChatRoom::onParticipantAdded (shared_ptr event) { +void ClientGroupChatRoom::onParticipantAdded (const shared_ptr &event, bool isFullState) { L_D_T(RemoteConference, dConference); const Address &addr = event->getParticipantAddress(); @@ -278,6 +278,10 @@ void ClientGroupChatRoom::onParticipantAdded (shared_ptr(addr); dConference->participants.push_back(participant); + + if (isFullState) + return; + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAddedCb cb = linphone_chat_room_cbs_get_participant_added(cbs); @@ -287,7 +291,9 @@ void ClientGroupChatRoom::onParticipantAdded (shared_ptr event) { +void ClientGroupChatRoom::onParticipantRemoved (const shared_ptr &event, bool isFullState) { + (void)isFullState; // unused + L_D_T(RemoteConference, dConference); const Address &addr = event->getParticipantAddress(); @@ -308,7 +314,7 @@ void ClientGroupChatRoom::onParticipantRemoved (shared_ptrparticipants.remove(participant); } -void ClientGroupChatRoom::onParticipantSetAdmin (shared_ptr event) { +void ClientGroupChatRoom::onParticipantSetAdmin (const shared_ptr &event, bool isFullState) { const Address &addr = event->getParticipantAddress(); shared_ptr participant; if (isMe(addr)) @@ -325,6 +331,9 @@ void ClientGroupChatRoom::onParticipantSetAdmin (shared_ptrgetPrivate()->setAdmin(isAdmin); + if (isFullState) + return; + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAdminStatusChangedCb cb = linphone_chat_room_cbs_get_participant_admin_status_changed(cbs); @@ -334,11 +343,14 @@ void ClientGroupChatRoom::onParticipantSetAdmin (shared_ptr event) { +void ClientGroupChatRoom::onSubjectChanged (const shared_ptr &event, bool isFullState) { if (getSubject() == event->getSubject()) return; // No change in the local subject, do not notify RemoteConference::setSubject(event->getSubject()); + if (isFullState) + return; + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsSubjectChangedCb cb = linphone_chat_room_cbs_get_subject_changed(cbs); @@ -348,7 +360,7 @@ void ClientGroupChatRoom::onSubjectChanged (shared_ptr e cb(cr, L_GET_C_BACK_PTR(event)); } -void ClientGroupChatRoom::onParticipantDeviceAdded (shared_ptr event) { +void ClientGroupChatRoom::onParticipantDeviceAdded (const shared_ptr &event, bool isFullState) { const Address &addr = event->getParticipantAddress(); shared_ptr participant; if (isMe(addr)) @@ -360,6 +372,10 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (shared_ptrgetPrivate()->addDevice(event->getGruuAddress()); + + if (isFullState) + return; + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantDeviceAddedCb cb = linphone_chat_room_cbs_get_participant_device_added(cbs); @@ -369,7 +385,9 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (shared_ptr event) { +void ClientGroupChatRoom::onParticipantDeviceRemoved (const shared_ptr &event, bool isFullState) { + (void)isFullState; // unused + const Address &addr = event->getParticipantAddress(); shared_ptr participant; if (isMe(addr)) diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 9d96aac54..d9a3f0dc4 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -64,12 +64,12 @@ private: /* ConferenceListener */ void onConferenceCreated (const Address &addr) override; void onConferenceTerminated (const Address &addr) override; - void onParticipantAdded (std::shared_ptr event) override; - void onParticipantRemoved (std::shared_ptr event) override; - void onParticipantSetAdmin (std::shared_ptr event) override; - void onSubjectChanged (std::shared_ptr event) override; - void onParticipantDeviceAdded (std::shared_ptr event) override; - void onParticipantDeviceRemoved (std::shared_ptr event) override; + void onParticipantAdded (const std::shared_ptr &event, bool isFullState) override; + void onParticipantRemoved (const std::shared_ptr &event, bool isFullState) override; + void onParticipantSetAdmin (const std::shared_ptr &event, bool isFullState) override; + void onSubjectChanged (const std::shared_ptr &event, bool isFullState) override; + void onParticipantDeviceAdded (const std::shared_ptr &event, bool isFullState) override; + void onParticipantDeviceRemoved (const std::shared_ptr &event, bool isFullState) override; private: /* CallSessionListener */ diff --git a/src/conference/conference-listener.h b/src/conference/conference-listener.h index fe0dbc90d..de5e4604c 100644 --- a/src/conference/conference-listener.h +++ b/src/conference/conference-listener.h @@ -23,9 +23,10 @@ #include #include -#include "event-log/events.h" #include "linphone/utils/general.h" +#include "event-log/events.h" + // ============================================================================= LINPHONE_BEGIN_NAMESPACE @@ -36,12 +37,12 @@ class ConferenceListener { public: virtual void onConferenceCreated (const Address &addr) = 0; virtual void onConferenceTerminated (const Address &addr) = 0; - virtual void onParticipantAdded (std::shared_ptr event) = 0; - virtual void onParticipantRemoved (std::shared_ptr event) = 0; - virtual void onParticipantSetAdmin (std::shared_ptr event) = 0; - virtual void onSubjectChanged (std::shared_ptr event) = 0; - virtual void onParticipantDeviceAdded (std::shared_ptr event) = 0; - virtual void onParticipantDeviceRemoved (std::shared_ptr event) = 0; + virtual void onParticipantAdded (const std::shared_ptr &event, bool isFullState) = 0; + virtual void onParticipantRemoved (const std::shared_ptr &event, bool isFullState) = 0; + virtual void onParticipantSetAdmin (const std::shared_ptr &event, bool isFullState) = 0; + virtual void onSubjectChanged (const std::shared_ptr &event, bool isFullState) = 0; + virtual void onParticipantDeviceAdded (const std::shared_ptr &event, bool isFullState) = 0; + virtual void onParticipantDeviceRemoved (const std::shared_ptr &event, bool isFullState) = 0; }; LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index aa79c5fcb..7578c9b82 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -89,13 +89,15 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { confInfo->getConferenceDescription().present() && confInfo->getConferenceDescription().get().getSubject().present() ) - d->listener->onSubjectChanged(make_shared( - tm, - isFullState, - d->confAddress, - d->lastNotify, - confInfo->getConferenceDescription().get().getSubject().get() - )); + d->listener->onSubjectChanged( + make_shared( + tm, + d->confAddress, + d->lastNotify, + confInfo->getConferenceDescription().get().getSubject().get() + ), + isFullState + ); if (confInfo->getVersion().present()) d->lastNotify = confInfo->getVersion().get(); @@ -108,14 +110,16 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { Address addr(cAddrStr); bctbx_free(cAddrStr); if (user.getState() == StateType::deleted) { - d->listener->onParticipantRemoved(make_shared( - EventLog::Type::ConferenceParticipantRemoved, - tm, - isFullState, - d->confAddress, - d->lastNotify, - addr - )); + d->listener->onParticipantRemoved( + make_shared( + EventLog::Type::ConferenceParticipantRemoved, + tm, + d->confAddress, + d->lastNotify, + addr + ), + isFullState + ); } else { bool isAdmin = false; if (user.getRoles()) { @@ -126,49 +130,60 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { } } } + if (user.getState() == StateType::full) { - d->listener->onParticipantAdded(make_shared( - EventLog::Type::ConferenceParticipantAdded, + d->listener->onParticipantAdded( + make_shared( + EventLog::Type::ConferenceParticipantAdded, + tm, + d->confAddress, + d->lastNotify, + addr + ), + isFullState + ); + } + + d->listener->onParticipantSetAdmin( + make_shared( + isAdmin ? EventLog::Type::ConferenceParticipantSetAdmin : EventLog::Type::ConferenceParticipantUnsetAdmin, tm, - isFullState, d->confAddress, d->lastNotify, addr - )); - } - d->listener->onParticipantSetAdmin(make_shared( - isAdmin ? EventLog::Type::ConferenceParticipantSetAdmin : EventLog::Type::ConferenceParticipantUnsetAdmin, - tm, - isFullState, - d->confAddress, - d->lastNotify, - addr - )); + ), + isFullState + ); + for (const auto &endpoint : user.getEndpoint()) { if (!endpoint.getEntity().present()) break; Address gruu(endpoint.getEntity().get()); if (endpoint.getState() == StateType::deleted) { - d->listener->onParticipantDeviceRemoved(make_shared( - EventLog::Type::ConferenceParticipantDeviceRemoved, - tm, - isFullState, - d->confAddress, - d->lastNotify, - addr, - gruu - )); + d->listener->onParticipantDeviceRemoved( + make_shared( + EventLog::Type::ConferenceParticipantDeviceRemoved, + tm, + d->confAddress, + d->lastNotify, + addr, + gruu + ), + isFullState + ); } else if (endpoint.getState() == StateType::full) { - d->listener->onParticipantDeviceAdded(make_shared( - EventLog::Type::ConferenceParticipantDeviceAdded, - tm, - isFullState, - d->confAddress, - d->lastNotify, - addr, - gruu - )); + d->listener->onParticipantDeviceAdded( + make_shared( + EventLog::Type::ConferenceParticipantDeviceAdded, + tm, + d->confAddress, + d->lastNotify, + addr, + gruu + ), + isFullState + ); } } } diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index 68b6b990f..4ace4ee14 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -89,16 +89,34 @@ void RemoteConference::onConferenceTerminated (const Address &addr) { d->eventHandler->unsubscribe(); } -void RemoteConference::onParticipantAdded (std::shared_ptr event) {} +void RemoteConference::onParticipantAdded (const std::shared_ptr &event, bool isFullState) { + (void)event; // unused + (void)isFullState; // unused +} -void RemoteConference::onParticipantRemoved (std::shared_ptr event) {} +void RemoteConference::onParticipantRemoved (const std::shared_ptr &event, bool isFullState) { + (void)event; // unused + (void)isFullState; // unused +} -void RemoteConference::onParticipantSetAdmin (std::shared_ptr event) {} +void RemoteConference::onParticipantSetAdmin (const std::shared_ptr &event, bool isFullState) { + (void)event; // unused + (void)isFullState; // unused +} -void RemoteConference::onSubjectChanged (std::shared_ptr event) {} +void RemoteConference::onSubjectChanged (const std::shared_ptr &event, bool isFullState) { + (void)event; // unused + (void)isFullState; // unused +} -void RemoteConference::onParticipantDeviceAdded (std::shared_ptr event) {} +void RemoteConference::onParticipantDeviceAdded (const std::shared_ptr &event, bool isFullState) { + (void)event; // unused + (void)isFullState; // unused +} -void RemoteConference::onParticipantDeviceRemoved (std::shared_ptr event) {} +void RemoteConference::onParticipantDeviceRemoved (const std::shared_ptr &event, bool isFullState) { + (void)event; // unused + (void)isFullState; // unused +} LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index 9b4e40c8d..0567160a2 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -46,12 +46,12 @@ protected: /* ConferenceListener */ void onConferenceCreated (const Address &addr) override; void onConferenceTerminated (const Address &addr) override; - void onParticipantAdded (std::shared_ptr event) override; - void onParticipantRemoved (std::shared_ptr event) override; - void onParticipantSetAdmin (std::shared_ptr event) override; - void onSubjectChanged (std::shared_ptr event) override; - void onParticipantDeviceAdded (std::shared_ptr event) override; - void onParticipantDeviceRemoved (std::shared_ptr event) override; + void onParticipantAdded (const std::shared_ptr &event, bool isFullState) override; + void onParticipantRemoved (const std::shared_ptr &event, bool isFullState) override; + void onParticipantSetAdmin (const std::shared_ptr &event, bool isFullState) override; + void onSubjectChanged (const std::shared_ptr &event, bool isFullState) override; + void onParticipantDeviceAdded (const std::shared_ptr &event, bool isFullState) override; + void onParticipantDeviceRemoved (const std::shared_ptr &event, bool isFullState) override; private: L_DECLARE_PRIVATE(RemoteConference); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 8b335d972..cc7c18b6e 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -355,7 +355,6 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return make_shared( type, date, - false, Address(peerAddress), notifyId, Address(participantAddress) @@ -387,7 +386,6 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return make_shared( type, date, - false, Address(peerAddress), notifyId, Address(participantAddress), @@ -414,7 +412,6 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), // TODO: Use cache. return make_shared( date, - false, Address(peerAddress), notifyId, subject diff --git a/src/event-log/conference/conference-notified-event-p.h b/src/event-log/conference/conference-notified-event-p.h index 20f55c352..af5855334 100644 --- a/src/event-log/conference/conference-notified-event-p.h +++ b/src/event-log/conference/conference-notified-event-p.h @@ -30,7 +30,6 @@ LINPHONE_BEGIN_NAMESPACE class ConferenceNotifiedEventPrivate : public ConferenceEventPrivate { private: unsigned int notifyId = 0; - bool isFullState = false; L_DECLARE_PUBLIC(ConferenceNotifiedEvent); }; diff --git a/src/event-log/conference/conference-notified-event.cpp b/src/event-log/conference/conference-notified-event.cpp index 3eba64c71..5a0e4f857 100644 --- a/src/event-log/conference/conference-notified-event.cpp +++ b/src/event-log/conference/conference-notified-event.cpp @@ -30,26 +30,22 @@ LINPHONE_BEGIN_NAMESPACE ConferenceNotifiedEvent::ConferenceNotifiedEvent ( Type type, time_t time, - bool isFullState, const Address &conferenceAddress, unsigned int notifyId ) : ConferenceEvent(*new ConferenceNotifiedEventPrivate, type, time, conferenceAddress) { L_D(); d->notifyId = notifyId; - d->isFullState = isFullState; } ConferenceNotifiedEvent::ConferenceNotifiedEvent ( ConferenceNotifiedEventPrivate &p, Type type, time_t time, - bool isFullState, const Address &conferenceAddress, unsigned int notifyId ) : ConferenceEvent(p, type, time, conferenceAddress) { L_D(); d->notifyId = notifyId; - d->isFullState = isFullState; } unsigned int ConferenceNotifiedEvent::getNotifyId () const { @@ -57,9 +53,4 @@ unsigned int ConferenceNotifiedEvent::getNotifyId () const { return d->notifyId; } -bool ConferenceNotifiedEvent::isFullState () const { - L_D(); - return d->isFullState; -} - LINPHONE_END_NAMESPACE diff --git a/src/event-log/conference/conference-notified-event.h b/src/event-log/conference/conference-notified-event.h index bbb765e1d..eca259f49 100644 --- a/src/event-log/conference/conference-notified-event.h +++ b/src/event-log/conference/conference-notified-event.h @@ -32,20 +32,17 @@ class LINPHONE_PUBLIC ConferenceNotifiedEvent : public ConferenceEvent { public: ConferenceNotifiedEvent ( Type type, std::time_t time, - bool isFullState, const Address &conferenceAddress, unsigned int notifiyId ); unsigned int getNotifyId () const; - bool isFullState() const; protected: ConferenceNotifiedEvent ( ConferenceNotifiedEventPrivate &p, Type type, std::time_t time, - bool isFullState, const Address &conferenceAddress, unsigned int notifyId ); diff --git a/src/event-log/conference/conference-participant-device-event.cpp b/src/event-log/conference/conference-participant-device-event.cpp index 30850259d..fbfbcceda 100644 --- a/src/event-log/conference/conference-participant-device-event.cpp +++ b/src/event-log/conference/conference-participant-device-event.cpp @@ -36,7 +36,6 @@ public: ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent ( Type type, time_t time, - bool isFullState, const Address &conferenceAddress, unsigned int notifyId, const Address &participantAddress, @@ -45,7 +44,6 @@ ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent ( *new ConferenceParticipantDeviceEventPrivate, type, time, - isFullState, conferenceAddress, notifyId, participantAddress diff --git a/src/event-log/conference/conference-participant-device-event.h b/src/event-log/conference/conference-participant-device-event.h index 27b315121..d57834dd7 100644 --- a/src/event-log/conference/conference-participant-device-event.h +++ b/src/event-log/conference/conference-participant-device-event.h @@ -33,7 +33,6 @@ public: ConferenceParticipantDeviceEvent ( Type type, std::time_t time, - bool isFullState, const Address &conferenceAddress, unsigned int notifyId, const Address &participantAddress, diff --git a/src/event-log/conference/conference-participant-event.cpp b/src/event-log/conference/conference-participant-event.cpp index c5ece237a..29cc92949 100644 --- a/src/event-log/conference/conference-participant-event.cpp +++ b/src/event-log/conference/conference-participant-event.cpp @@ -30,7 +30,6 @@ LINPHONE_BEGIN_NAMESPACE ConferenceParticipantEvent::ConferenceParticipantEvent ( Type type, time_t time, - bool isFullState, const Address &conferenceAddress, unsigned int notifyId, const Address &participantAddress @@ -38,7 +37,6 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( *new ConferenceParticipantEventPrivate, type, time, - isFullState, conferenceAddress, notifyId ) { @@ -56,7 +54,6 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( ConferenceParticipantEventPrivate &p, Type type, time_t time, - bool isFullState, const Address &conferenceAddress, unsigned int notifyId, const Address &participantAddress @@ -64,7 +61,6 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( p, type, time, - isFullState, conferenceAddress, notifyId ) { diff --git a/src/event-log/conference/conference-participant-event.h b/src/event-log/conference/conference-participant-event.h index ce96da04c..792583dcf 100644 --- a/src/event-log/conference/conference-participant-event.h +++ b/src/event-log/conference/conference-participant-event.h @@ -33,7 +33,6 @@ public: ConferenceParticipantEvent ( Type type, std::time_t time, - bool isFullState, const Address &conferenceAddress, unsigned int notifyId, const Address &participantAddress @@ -46,7 +45,6 @@ protected: ConferenceParticipantEventPrivate &p, Type type, std::time_t time, - bool isFullState, const Address &conferenceAddress, unsigned int notifyId, const Address &participantAddress diff --git a/src/event-log/conference/conference-subject-event.cpp b/src/event-log/conference/conference-subject-event.cpp index 817cb6157..e07061dc2 100644 --- a/src/event-log/conference/conference-subject-event.cpp +++ b/src/event-log/conference/conference-subject-event.cpp @@ -35,7 +35,6 @@ public: ConferenceSubjectEvent::ConferenceSubjectEvent ( time_t time, - bool isFullState, const Address &conferenceAddress, unsigned int notifyId, const string &subject @@ -43,7 +42,6 @@ ConferenceSubjectEvent::ConferenceSubjectEvent ( *new ConferenceSubjectEventPrivate, Type::ConferenceSubjectChanged, time, - isFullState, conferenceAddress, notifyId ) { diff --git a/src/event-log/conference/conference-subject-event.h b/src/event-log/conference/conference-subject-event.h index aced99de5..8ea9a039f 100644 --- a/src/event-log/conference/conference-subject-event.h +++ b/src/event-log/conference/conference-subject-event.h @@ -34,7 +34,6 @@ class LINPHONE_PUBLIC ConferenceSubjectEvent : public ConferenceNotifiedEvent { public: ConferenceSubjectEvent ( std::time_t time, - bool isFullState, const Address &conferenceAddress, unsigned int notifyId, const std::string &subject diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index 82d797c3a..76fe22e6e 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -447,12 +447,12 @@ public: private: void onConferenceCreated (const Address &addr) override; void onConferenceTerminated (const Address &addr) override; - void onParticipantAdded (shared_ptr event) override; - void onParticipantRemoved (shared_ptr event) override; - void onParticipantSetAdmin (shared_ptr event) override; - void onSubjectChanged (shared_ptr event) override; - void onParticipantDeviceAdded (shared_ptr event) override; - void onParticipantDeviceRemoved (shared_ptr event) override; + void onParticipantAdded (const shared_ptr &event, bool isFullState) override; + void onParticipantRemoved (const shared_ptr &event, bool isFullState) override; + void onParticipantSetAdmin (const shared_ptr &event, bool isFullState) override; + void onSubjectChanged (const shared_ptr &event, bool isFullState) override; + void onParticipantDeviceAdded (const shared_ptr &event, bool isFullState) override; + void onParticipantDeviceRemoved (const shared_ptr &event, bool isFullState) override; public: RemoteConferenceEventHandler *handler; @@ -473,29 +473,34 @@ void ConferenceEventTester::onConferenceCreated (const Address &addr) {} void ConferenceEventTester::onConferenceTerminated (const Address &addr) {} -void ConferenceEventTester::onParticipantAdded (shared_ptr event) { +void ConferenceEventTester::onParticipantAdded (const shared_ptr &event, bool isFullState) { + (void)isFullState; // unused const Address addr = event->getParticipantAddress(); participants.insert(pair(addr.asString(), FALSE)); participantDevices.insert(pair(addr.asString(), 0)); } -void ConferenceEventTester::onParticipantRemoved (shared_ptr event) { +void ConferenceEventTester::onParticipantRemoved (const shared_ptr &event, bool isFullState) { + (void)isFullState; // unused const Address addr = event->getParticipantAddress(); participants.erase(addr.asString()); participantDevices.erase(addr.asString()); } -void ConferenceEventTester::onParticipantSetAdmin (shared_ptr event) { +void ConferenceEventTester::onParticipantSetAdmin (const shared_ptr &event, bool isFullState) { + (void)isFullState; // unused const Address addr = event->getParticipantAddress(); auto it = participants.find(addr.asString()); if (it != participants.end()) it->second = (event->getType() == EventLog::Type::ConferenceParticipantSetAdmin); } -void ConferenceEventTester::onSubjectChanged(shared_ptr event) { +void ConferenceEventTester::onSubjectChanged(const shared_ptr &event, bool isFullState) { + (void)isFullState; // unused confSubject = event->getSubject(); } -void ConferenceEventTester::onParticipantDeviceAdded (shared_ptr event) { +void ConferenceEventTester::onParticipantDeviceAdded (const shared_ptr &event, bool isFullState) { + (void)isFullState; // unused const Address addr = event->getParticipantAddress(); auto it = participantDevices.find(addr.asString()); if (it != participantDevices.end()) @@ -503,7 +508,8 @@ void ConferenceEventTester::onParticipantDeviceAdded (shared_ptr event) { +void ConferenceEventTester::onParticipantDeviceRemoved (const shared_ptr &event, bool isFullState) { + (void)isFullState; // unused const Address addr = event->getParticipantAddress(); auto it = participantDevices.find(addr.asString()); if (it != participantDevices.end() && it->second > 0) From 4cd5e7aeabef65ca9d20e6f168f8b346088b0a9a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 8 Nov 2017 12:14:02 +0100 Subject: [PATCH 0724/2215] Change the state of the ClientGroupChatRoom to created only when the first NOTIFY has been received. --- src/chat/chat-room/client-group-chat-room.cpp | 8 ++++++-- src/chat/chat-room/client-group-chat-room.h | 1 + src/conference/conference-listener.h | 1 + src/conference/remote-conference-event-handler.cpp | 3 +++ src/conference/remote-conference.cpp | 2 ++ src/conference/remote-conference.h | 1 + tester/conference-event-tester.cpp | 3 +++ 7 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 329ef2c8c..071e88193 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -254,8 +254,6 @@ void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { dConference->conferenceAddress = addr; d->peerAddress = addr; CoreAccessor::getCore()->getPrivate()->insertChatRoom(getSharedFromThis()); - d->setState(ChatRoom::State::Created); - CoreAccessor::getCore()->getPrivate()->insertChatRoomWithDb(getSharedFromThis()); } void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { @@ -263,6 +261,12 @@ void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { d->setState(ChatRoom::State::Terminated); } +void ClientGroupChatRoom::onFirstNotifyReceived (const Address &addr) { + L_D(); + d->setState(ChatRoom::State::Created); + CoreAccessor::getCore()->getPrivate()->insertChatRoomWithDb(getSharedFromThis()); +} + void ClientGroupChatRoom::onParticipantAdded (const shared_ptr &event, bool isFullState) { L_D_T(RemoteConference, dConference); diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index d9a3f0dc4..9d1614ccf 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -64,6 +64,7 @@ private: /* ConferenceListener */ void onConferenceCreated (const Address &addr) override; void onConferenceTerminated (const Address &addr) override; + void onFirstNotifyReceived (const Address &addr) override; void onParticipantAdded (const std::shared_ptr &event, bool isFullState) override; void onParticipantRemoved (const std::shared_ptr &event, bool isFullState) override; void onParticipantSetAdmin (const std::shared_ptr &event, bool isFullState) override; diff --git a/src/conference/conference-listener.h b/src/conference/conference-listener.h index de5e4604c..b4946cd9d 100644 --- a/src/conference/conference-listener.h +++ b/src/conference/conference-listener.h @@ -37,6 +37,7 @@ class ConferenceListener { public: virtual void onConferenceCreated (const Address &addr) = 0; virtual void onConferenceTerminated (const Address &addr) = 0; + virtual void onFirstNotifyReceived (const Address &addr) = 0; virtual void onParticipantAdded (const std::shared_ptr &event, bool isFullState) = 0; virtual void onParticipantRemoved (const std::shared_ptr &event, bool isFullState) = 0; virtual void onParticipantSetAdmin (const std::shared_ptr &event, bool isFullState) = 0; diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 7578c9b82..d3a8ae260 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -189,6 +189,9 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { } linphone_address_unref(cAddr); } + + if (isFullState) + d->listener->onFirstNotifyReceived(d->confAddress); } } diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index 4ace4ee14..9386b93cd 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -89,6 +89,8 @@ void RemoteConference::onConferenceTerminated (const Address &addr) { d->eventHandler->unsubscribe(); } +void RemoteConference::onFirstNotifyReceived (const Address &addr) {} + void RemoteConference::onParticipantAdded (const std::shared_ptr &event, bool isFullState) { (void)event; // unused (void)isFullState; // unused diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index 0567160a2..bf630cfb1 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -46,6 +46,7 @@ protected: /* ConferenceListener */ void onConferenceCreated (const Address &addr) override; void onConferenceTerminated (const Address &addr) override; + void onFirstNotifyReceived (const Address &addr) override; void onParticipantAdded (const std::shared_ptr &event, bool isFullState) override; void onParticipantRemoved (const std::shared_ptr &event, bool isFullState) override; void onParticipantSetAdmin (const std::shared_ptr &event, bool isFullState) override; diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index 76fe22e6e..9152e1dac 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -447,6 +447,7 @@ public: private: void onConferenceCreated (const Address &addr) override; void onConferenceTerminated (const Address &addr) override; + void onFirstNotifyReceived (const Address &addr) override; void onParticipantAdded (const shared_ptr &event, bool isFullState) override; void onParticipantRemoved (const shared_ptr &event, bool isFullState) override; void onParticipantSetAdmin (const shared_ptr &event, bool isFullState) override; @@ -473,6 +474,8 @@ void ConferenceEventTester::onConferenceCreated (const Address &addr) {} void ConferenceEventTester::onConferenceTerminated (const Address &addr) {} +void ConferenceEventTester::onFirstNotifyReceived (const Address &addr) {} + void ConferenceEventTester::onParticipantAdded (const shared_ptr &event, bool isFullState) { (void)isFullState; // unused const Address addr = event->getParticipantAddress(); From f7b64d5ad50003b1c5336db16a4982c3c17d5567 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 8 Nov 2017 12:14:33 +0100 Subject: [PATCH 0725/2215] When adding participants to a ClientGroupChatRoom, check that they are not already in the chat room. --- src/chat/chat-room/client-group-chat-room-p.h | 1 + src/chat/chat-room/client-group-chat-room.cpp | 23 ++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room-p.h b/src/chat/chat-room/client-group-chat-room-p.h index 3eeb5ae47..39b8313b3 100644 --- a/src/chat/chat-room/client-group-chat-room-p.h +++ b/src/chat/chat-room/client-group-chat-room-p.h @@ -31,6 +31,7 @@ class ClientGroupChatRoomPrivate : public ChatRoomPrivate { public: ClientGroupChatRoomPrivate () = default; + std::list
      cleanAddressesList (const std::list
      &addresses) const; std::shared_ptr createSession (); void notifyReceived (std::string body); diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 071e88193..be899e8f5 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -39,6 +39,20 @@ LINPHONE_BEGIN_NAMESPACE // ----------------------------------------------------------------------------- +list
      ClientGroupChatRoomPrivate::cleanAddressesList (const list
      &addresses) const { + L_Q(); + list
      cleanedList(addresses); + cleanedList.sort(); + cleanedList.unique(); + for (auto it = cleanedList.begin(); it != cleanedList.end();) { + if (q->findParticipant(*it)) + it = cleanedList.erase(it); + else + it++; + } + return cleanedList; +} + shared_ptr ClientGroupChatRoomPrivate::createSession () { L_Q(); L_Q_T(RemoteConference, qConference); @@ -94,7 +108,8 @@ void ClientGroupChatRoom::addParticipants ( L_D(); L_D_T(RemoteConference, dConference); - if (addresses.empty()) + list
      addressesList = d->cleanAddressesList(addresses); + if (addressesList.empty()) return; if ((d->state != ChatRoom::State::Instantiated) && (d->state != ChatRoom::State::Created)) { @@ -102,12 +117,8 @@ void ClientGroupChatRoom::addParticipants ( return; } - list
      sortedAddresses(addresses); - sortedAddresses.sort(); - sortedAddresses.unique(); - Content content; - content.setBody(getResourceLists(sortedAddresses)); + content.setBody(getResourceLists(addressesList)); content.setContentType("application/resource-lists+xml"); content.setContentDisposition("recipient-list"); From bc32805af0b5290321e303e433060acd97798e48 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 8 Nov 2017 14:08:13 +0100 Subject: [PATCH 0726/2215] feat(MainDb): provide a way to check stored events --- src/CMakeLists.txt | 3 ++ src/db/main-db-event-key-p.h | 38 ++++++++++++++++++++ src/db/main-db-event-key.cpp | 69 ++++++++++++++++++++++++++++++++++++ src/db/main-db-event-key.h | 53 +++++++++++++++++++++++++++ src/db/main-db.cpp | 49 ++++++++++++++++--------- src/db/main-db.h | 4 +-- src/event-log/event-log-p.h | 3 +- src/event-log/event-log.cpp | 1 + src/event-log/event-log.h | 1 - src/logger/logger.h | 3 +- 10 files changed, 203 insertions(+), 21 deletions(-) create mode 100644 src/db/main-db-event-key-p.h create mode 100644 src/db/main-db-event-key.cpp create mode 100644 src/db/main-db-event-key.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e668511fb..10c0ed793 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -91,6 +91,8 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/platform-helpers/platform-helpers.h db/abstract/abstract-db-p.h db/abstract/abstract-db.h + db/main-db-event-key-p.h + db/main-db-event-key.h db/main-db-p.h db/main-db.h db/session/db-session-p.h @@ -188,6 +190,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES core/paths/paths.cpp core/platform-helpers/platform-helpers.cpp db/abstract/abstract-db.cpp + db/main-db-event-key.cpp db/main-db.cpp db/session/db-session-provider.cpp db/session/db-session.cpp diff --git a/src/db/main-db-event-key-p.h b/src/db/main-db-event-key-p.h new file mode 100644 index 000000000..62e4f6eaa --- /dev/null +++ b/src/db/main-db-event-key-p.h @@ -0,0 +1,38 @@ +/* + * main-db-event-key-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _MAIN_DB_EVENT_KEY_P_H_ +#define _MAIN_DB_EVENT_KEY_P_H_ + +#include "main-db-event-key.h" +#include "object/clonable-object-p.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class MainDbEventKeyPrivate : public ClonableObjectPrivate { +public: + std::weak_ptr core; + long long storageId = -1; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _MAIN_DB_EVENT_KEY_P_H_ diff --git a/src/db/main-db-event-key.cpp b/src/db/main-db-event-key.cpp new file mode 100644 index 000000000..a363ba3c4 --- /dev/null +++ b/src/db/main-db-event-key.cpp @@ -0,0 +1,69 @@ +/* + * main-db-event-key.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "main-db-event-key-p.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +// ----------------------------------------------------------------------------- + +MainDbEventKey::MainDbEventKey () : ClonableObject(*new MainDbEventKeyPrivate) {} + +MainDbEventKey::MainDbEventKey (const shared_ptr &core, long long storageId) : MainDbEventKey() { + L_D(); + d->core = core; + d->storageId = storageId; +} + +MainDbEventKey::MainDbEventKey (const MainDbEventKey &src) : MainDbEventKey() { + L_D(); + const MainDbEventKeyPrivate *dSrc = src.getPrivate(); + + d->core = dSrc->core; + d->storageId = dSrc->storageId; +} + +MainDbEventKey::~MainDbEventKey () { + if (isValid()) { + // TODO: Remove key from main db references if necessary. + } +} + +MainDbEventKey &MainDbEventKey::operator= (const MainDbEventKey &src) { + L_D(); + + if (this != &src) { + const MainDbEventKeyPrivate *dSrc = src.getPrivate(); + d->core = dSrc->core; + d->storageId = dSrc->storageId; + } + + return *this; +} + +bool MainDbEventKey::isValid () const { + L_D(); + return !d->core.expired() && d->storageId >= 0; +} + +LINPHONE_END_NAMESPACE diff --git a/src/db/main-db-event-key.h b/src/db/main-db-event-key.h new file mode 100644 index 000000000..37ea05c35 --- /dev/null +++ b/src/db/main-db-event-key.h @@ -0,0 +1,53 @@ +/* + * main-db-event-key.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _MAIN_DB_EVENT_KEY_H_ +#define _MAIN_DB_EVENT_KEY_H_ + +#include + +#include "object/clonable-object.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class Core; +class MainDbEventKeyPrivate; + +class MainDbEventKey : public ClonableObject { + friend class MainDb; + +public: + MainDbEventKey (); + MainDbEventKey (const std::shared_ptr &core, long long storageId); + MainDbEventKey (const MainDbEventKey &src); + ~MainDbEventKey (); + + MainDbEventKey &operator= (const MainDbEventKey &src); + + bool isValid () const; + +private: + L_DECLARE_PRIVATE(MainDbEventKey); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _MAIN_DB_EVENT_KEY_H_ diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index cc7c18b6e..84d413e1f 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -36,6 +36,7 @@ #include "event-log/event-log-p.h" #include "event-log/events.h" #include "logger/logger.h" +#include "main-db-event-key-p.h" #include "main-db-p.h" // ============================================================================= @@ -778,7 +779,14 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return false; } + const EventLogPrivate *dEventLog = eventLog->getPrivate(); + if (dEventLog->dbKey.isValid()) { + lWarning() << "Unable to add an event twice!!!"; + return false; + } + bool soFarSoGood = false; + long long storageId; L_BEGIN_LOG_EXCEPTION @@ -790,32 +798,32 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), case EventLog::Type::ConferenceCreated: case EventLog::Type::ConferenceDestroyed: - d->insertConferenceEvent(eventLog); + storageId = d->insertConferenceEvent(eventLog); break; case EventLog::Type::ConferenceCallStart: case EventLog::Type::ConferenceCallEnd: - d->insertConferenceCallEvent(eventLog); + storageId = d->insertConferenceCallEvent(eventLog); break; case EventLog::Type::ConferenceChatMessage: - d->insertConferenceChatMessageEvent(eventLog); + storageId = d->insertConferenceChatMessageEvent(eventLog); break; case EventLog::Type::ConferenceParticipantAdded: case EventLog::Type::ConferenceParticipantRemoved: case EventLog::Type::ConferenceParticipantSetAdmin: case EventLog::Type::ConferenceParticipantUnsetAdmin: - d->insertConferenceParticipantEvent(eventLog); + storageId = d->insertConferenceParticipantEvent(eventLog); break; case EventLog::Type::ConferenceParticipantDeviceAdded: case EventLog::Type::ConferenceParticipantDeviceRemoved: - d->insertConferenceParticipantDeviceEvent(eventLog); + storageId = d->insertConferenceParticipantDeviceEvent(eventLog); break; case EventLog::Type::ConferenceSubjectChanged: - d->insertConferenceSubjectEvent(eventLog); + storageId = d->insertConferenceSubjectEvent(eventLog); break; } @@ -825,30 +833,39 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), L_END_LOG_EXCEPTION + if (soFarSoGood) + dEventLog->dbKey = MainDbEventKey(getCore(), storageId); + return soFarSoGood; } bool MainDb::deleteEvent (const shared_ptr &eventLog) { - L_D(); + EventLogPrivate *dEventLog = eventLog->getPrivate(); + if (!dEventLog->dbKey.isValid()) { + lWarning() << "Unable to delete invalid event."; + return false; + } - if (!isConnected()) { + MainDbEventKeyPrivate *dEventKey = dEventLog->dbKey.getPrivate(); + shared_ptr core = dEventKey->core.lock(); + L_ASSERT(core); + + MainDb &mainDb = *core->getPrivate()->mainDb.get(); + if (!mainDb.isConnected()) { lWarning() << "Unable to delete event. Not connected."; return false; } - long long &storageId = eventLog->getPrivate()->storageId; - if (storageId < 0) - return false; - L_BEGIN_LOG_EXCEPTION - soci::session *session = d->dbSession.getBackendSession(); - *session << "DELETE FROM event WHERE id = :id", soci::use(storageId); - storageId = -1; + soci::session *session = mainDb.getPrivate()->dbSession.getBackendSession(); + *session << "DELETE FROM event WHERE id = :id", soci::use(dEventKey->storageId); L_END_LOG_EXCEPTION - return storageId == -1; + dEventLog->dbKey = MainDbEventKey(); + + return true; } int MainDb::getEventsCount (FilterMask mask) const { diff --git a/src/db/main-db.h b/src/db/main-db.h index 3f96b1dde..acfae01c7 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -35,7 +35,7 @@ class Core; class EventLog; class MainDbPrivate; -class LINPHONE_PUBLIC MainDb : public AbstractDb, public CoreAccessor { +class MainDb : public AbstractDb, public CoreAccessor { public: enum Filter { NoFilter = 0x0, @@ -53,7 +53,7 @@ public: // --------------------------------------------------------------------------- bool addEvent (const std::shared_ptr &eventLog); - bool deleteEvent (const std::shared_ptr &eventLog); + static bool deleteEvent (const std::shared_ptr &eventLog); int getEventsCount (FilterMask mask = NoFilter) const; // --------------------------------------------------------------------------- diff --git a/src/event-log/event-log-p.h b/src/event-log/event-log-p.h index 06701bac7..4c4085883 100644 --- a/src/event-log/event-log-p.h +++ b/src/event-log/event-log-p.h @@ -20,6 +20,7 @@ #ifndef _EVENT_LOG_P_H_ #define _EVENT_LOG_P_H_ +#include "db/main-db-event-key.h" #include "object/base-object-p.h" #include "event-log.h" @@ -30,7 +31,7 @@ LINPHONE_BEGIN_NAMESPACE class EventLogPrivate : public BaseObjectPrivate { public: - long long storageId = -1; + mutable MainDbEventKey dbKey; private: EventLog::Type type = EventLog::Type::None; diff --git a/src/event-log/event-log.cpp b/src/event-log/event-log.cpp index 087ee6797..9ccfa8afc 100644 --- a/src/event-log/event-log.cpp +++ b/src/event-log/event-log.cpp @@ -17,6 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "core/core-p.h" #include "event-log-p.h" // ============================================================================= diff --git a/src/event-log/event-log.h b/src/event-log/event-log.h index 98acbe238..3134421e8 100644 --- a/src/event-log/event-log.h +++ b/src/event-log/event-log.h @@ -21,7 +21,6 @@ #define _EVENT_LOG_H_ #include -#include #include "linphone/enums/event-log-enums.h" #include "linphone/utils/enum-generator.h" diff --git a/src/logger/logger.h b/src/logger/logger.h index 5c8a9ea19..e968e5794 100644 --- a/src/logger/logger.h +++ b/src/logger/logger.h @@ -59,7 +59,8 @@ LINPHONE_END_NAMESPACE #define lFatal() LinphonePrivate::Logger(LinphonePrivate::Logger::Fatal).getOutput() #define L_BEGIN_LOG_EXCEPTION try { - #define L_END_LOG_EXCEPTION \ + +#define L_END_LOG_EXCEPTION \ } catch (const exception &e) { \ lWarning() << "Error: " << e.what(); \ } From 0118f6ee53b093c2b88a8847db8242f8dc802c8e Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 8 Nov 2017 14:11:50 +0100 Subject: [PATCH 0727/2215] feat(core): remove useless doc on (void)arg --- src/chat/chat-room/client-group-chat-room.cpp | 4 ++-- src/conference/remote-conference.cpp | 24 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index be899e8f5..0b5defc37 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -307,7 +307,7 @@ void ClientGroupChatRoom::onParticipantAdded (const shared_ptr &event, bool isFullState) { - (void)isFullState; // unused + (void)isFullState; L_D_T(RemoteConference, dConference); @@ -401,7 +401,7 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (const shared_ptr &event, bool isFullState) { - (void)isFullState; // unused + (void)isFullState; const Address &addr = event->getParticipantAddress(); shared_ptr participant; diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index 9386b93cd..c93dde6ce 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -92,33 +92,33 @@ void RemoteConference::onConferenceTerminated (const Address &addr) { void RemoteConference::onFirstNotifyReceived (const Address &addr) {} void RemoteConference::onParticipantAdded (const std::shared_ptr &event, bool isFullState) { - (void)event; // unused - (void)isFullState; // unused + (void)event; + (void)isFullState; } void RemoteConference::onParticipantRemoved (const std::shared_ptr &event, bool isFullState) { - (void)event; // unused - (void)isFullState; // unused + (void)event; + (void)isFullState; } void RemoteConference::onParticipantSetAdmin (const std::shared_ptr &event, bool isFullState) { - (void)event; // unused - (void)isFullState; // unused + (void)event; + (void)isFullState; } void RemoteConference::onSubjectChanged (const std::shared_ptr &event, bool isFullState) { - (void)event; // unused - (void)isFullState; // unused + (void)event; + (void)isFullState; } void RemoteConference::onParticipantDeviceAdded (const std::shared_ptr &event, bool isFullState) { - (void)event; // unused - (void)isFullState; // unused + (void)event; + (void)isFullState; } void RemoteConference::onParticipantDeviceRemoved (const std::shared_ptr &event, bool isFullState) { - (void)event; // unused - (void)isFullState; // unused + (void)event; + (void)isFullState; } LINPHONE_END_NAMESPACE From ba89633e453376728db146127d760df427fa1101 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 8 Nov 2017 14:14:19 +0100 Subject: [PATCH 0728/2215] More work related to ChatMessage file transfer --- src/CMakeLists.txt | 5 + src/c-wrapper/api/c-chat-message.cpp | 6 +- src/chat/chat-message/chat-message-p.h | 11 +- src/chat/chat-message/chat-message.cpp | 401 ++++++++++++++----------- src/chat/chat-message/chat-message.h | 5 +- src/content/content-p.h | 43 +++ src/content/content.cpp | 30 +- src/content/content.h | 8 +- src/content/file-content.cpp | 126 ++++++++ src/content/file-content.h | 58 ++++ src/content/file-transfer-content.cpp | 123 ++++++++ src/content/file-transfer-content.h | 59 ++++ 12 files changed, 655 insertions(+), 220 deletions(-) create mode 100644 src/content/content-p.h create mode 100644 src/content/file-content.cpp create mode 100644 src/content/file-content.h create mode 100644 src/content/file-transfer-content.cpp create mode 100644 src/content/file-transfer-content.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 10c0ed793..899677ab1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -84,6 +84,9 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES content/content-manager.h content/content-type.h content/content.h + content/content-p.h + content/file-content.h + content/file-transfer-content.h core/core-accessor.h core/core-p.h core/core.h @@ -184,6 +187,8 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES content/content-manager.cpp content/content-type.cpp content/content.cpp + content/file-content.cpp + content/file-transfer-content.cpp core/core-accessor.cpp core/core-chat-room.cpp core/core.cpp diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 8cdd4d4c1..4f64cb6cd 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -252,12 +252,8 @@ const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChat // Methods // ============================================================================= -int linphone_chat_room_upload_file(LinphoneChatMessage *msg) { - return ((LinphoneStatus)L_GET_CPP_PTR_FROM_C_OBJECT(msg)->uploadFile()); -} - LinphoneStatus linphone_chat_message_download_file(LinphoneChatMessage *msg) { - return ((LinphoneStatus)L_GET_CPP_PTR_FROM_C_OBJECT(msg)->downloadFile()); + return ((LinphoneStatus)L_GET_PRIVATE_FROM_C_OBJECT(msg)->downloadFile()); } void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg) { diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index a83781a53..733fc5a42 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -25,6 +25,8 @@ #include "chat/chat-message/chat-message.h" #include "chat/notification/imdn.h" #include "content/content.h" +#include "content/file-content.h" +#include "content/file-transfer-content.h" #include "content/content-type.h" #include "object/object-p.h" #include "sal/sal.h" @@ -92,6 +94,8 @@ public: LinphoneContent *getFileTransferInformation() const; void setFileTransferInformation(const LinphoneContent *content); + + int downloadFile (); // ----------------------------------------------------------------------------- // Need to be public to be called from static C callbacks @@ -138,7 +142,7 @@ private: bool isReadOnly = false; std::list contents; Content internalContent; - Content *currentFileTransferContent; + FileContent *currentFileContentToTransfer; std::unordered_map customHeaders; mutable LinphoneErrorInfo * errorInfo = nullptr; belle_http_request_t *httpRequest = nullptr; @@ -153,7 +157,8 @@ private: std::string cText; // ----------------------------------------------------------------------------- - + + int uploadFile (); std::string createImdnXml(Imdn::Type imdnType, LinphoneReason reason); void fileUploadEndBackgroundTask(); @@ -165,7 +170,7 @@ private: belle_http_request_listener_callbacks_t *cbs ); void releaseHttpRequest(); - void createFileTransferInformationsFromVndGsmaRcsFtHttpXml(const std::string &body); + void createFileTransferInformationsFromVndGsmaRcsFtHttpXml(FileTransferContent &content); L_DECLARE_PUBLIC(ChatMessage); }; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index ddea3c8c2..209b83c79 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -31,6 +31,7 @@ #include "chat/modifier/cpim-chat-message-modifier.h" #include "chat/modifier/encryption-chat-message-modifier.h" #include "chat/modifier/multipart-chat-message-modifier.h" +#include "content/file-content.h" #include "content/content.h" #include "core/core.h" @@ -151,6 +152,8 @@ string ChatMessagePrivate::getSalCustomHeaderValue (const string &name) { return L_C_TO_STRING(sal_custom_header_find(salCustomHeaders, name.c_str())); } +// ----------------------------------------------------------------------------- +// Below methods are only for C API backward compatibility... // ----------------------------------------------------------------------------- const ContentType &ChatMessagePrivate::getContentType () { @@ -208,7 +211,6 @@ void ChatMessagePrivate::setText (const string &text) { LinphoneContent *ChatMessagePrivate::getFileTransferInformation () const { L_Q(); - //TODO cache and unref to prevent leak if (q->hasFileTransferContent()) { return q->getFileTransferContent().toLinphoneContent(); } @@ -218,16 +220,29 @@ LinphoneContent *ChatMessagePrivate::getFileTransferInformation () const { void ChatMessagePrivate::setFileTransferInformation (const LinphoneContent *c_content) { L_Q(); - Content content; + // Create a FileContent, it will create the FileTransferContent at upload time + FileContent fileContent; ContentType contentType(linphone_content_get_type(c_content), linphone_content_get_subtype(c_content)); - content.setContentType(contentType); + fileContent.setContentType(contentType); + fileContent.setFileSize(linphone_content_get_size(c_content)); + fileContent.setFileName(linphone_content_get_name(c_content)); if (linphone_content_get_string_buffer(c_content) != NULL) { - content.setBody(linphone_content_get_string_buffer(c_content)); + fileContent.setBody(linphone_content_get_string_buffer(c_content)); } - content.setContentDisposition(linphone_content_get_name(c_content)); - content.setExpectedSize(linphone_content_get_size(c_content)); - q->addContent(content); + q->addContent(fileContent); +} + +int ChatMessagePrivate::downloadFile () { + L_Q(); + + for (Content& content : contents) { + if (content.getContentType() == ContentType::FileTransfer) { + return q->downloadFile(static_cast(content)); + } + } + + return 0; } // ----------------------------------------------------------------------------- @@ -367,7 +382,7 @@ void ChatMessagePrivate::fileTransferOnProgress ( LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); - LinphoneContent *content = currentFileTransferContent->toLinphoneContent(); + LinphoneContent *content = currentFileContentToTransfer->toLinphoneContent(); if (linphone_chat_message_cbs_get_file_transfer_progress_indication(cbs)) { linphone_chat_message_cbs_get_file_transfer_progress_indication(cbs)(msg, content, offset, total); } else { @@ -420,12 +435,12 @@ int ChatMessagePrivate::onSendBody ( // if we've not reach the end of file yet, ask for more data // in case of file body handler, won't be called - if (fileTransferFilePath.empty() && offset < currentFileTransferContent->getExpectedSize()) { + if (currentFileContentToTransfer->getFilePath().empty() && offset < currentFileContentToTransfer->getFileSize()) { // get data from call back LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = linphone_chat_message_cbs_get_file_transfer_send(cbs); - LinphoneContent *content = currentFileTransferContent->toLinphoneContent(); + LinphoneContent *content = currentFileContentToTransfer->toLinphoneContent(); if (file_transfer_send_cb) { LinphoneBuffer *lb = file_transfer_send_cb(msg, content, offset, *size); if (lb == nullptr) { @@ -564,10 +579,10 @@ void ChatMessagePrivate::onRecvBody (belle_sip_user_body_handler_t *bh, belle_si ms_free(decrypted_buffer); if (retval <= 0) { - if (fileTransferFilePath.empty()) { + if (currentFileContentToTransfer->getFilePath().empty()) { LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); - LinphoneContent *content = currentFileTransferContent->toLinphoneContent(); + LinphoneContent *content = currentFileContentToTransfer->toLinphoneContent(); if (linphone_chat_message_cbs_get_file_transfer_recv(cbs)) { LinphoneBuffer *lb = linphone_buffer_new_from_data(buffer, size); linphone_chat_message_cbs_get_file_transfer_recv(cbs)(msg, content, lb); @@ -608,10 +623,10 @@ void ChatMessagePrivate::onRecvEnd (belle_sip_user_body_handler_t *bh) { } if (retval <= 0) { - if (fileTransferFilePath.empty()) { + if (currentFileContentToTransfer->getFilePath().empty()) { LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); - LinphoneContent *content = currentFileTransferContent->toLinphoneContent(); + LinphoneContent *content = currentFileContentToTransfer->toLinphoneContent(); if (linphone_chat_message_cbs_get_file_transfer_recv(cbs)) { LinphoneBuffer *lb = linphone_buffer_new(); linphone_chat_message_cbs_get_file_transfer_recv(cbs)(msg, content, lb); @@ -625,6 +640,18 @@ void ChatMessagePrivate::onRecvEnd (belle_sip_user_body_handler_t *bh) { } if (retval <= 0 && state != ChatMessage::State::FileTransferError) { + // Remove the FileTransferContent from the message and store the FileContent + FileContent fileContent = *currentFileContentToTransfer; + q->addContent(fileContent); + for (Content &content : contents) { + if (content.getContentType() == ContentType::FileTransfer) { + FileTransferContent fileTransferContent = static_cast(content); + if (fileTransferContent.getFileContent() == fileContent) { + q->removeContent(content); + break; + } + } + } setState(ChatMessage::State::FileTransferDone); } } @@ -689,38 +716,38 @@ void ChatMessagePrivate::processResponseFromPostFile (const belle_http_response_ first_part_header = "form-data; name=\"File\"; filename=\"filename.txt\""; } else { // temporary storage for the Content-disposition header value - first_part_header = "form-data; name=\"File\"; filename=\"" + currentFileTransferContent->getContentDisposition() + "\""; + first_part_header = "form-data; name=\"File\"; filename=\"" + currentFileContentToTransfer->getContentDisposition() + "\""; } // create a user body handler to take care of the file and add the content disposition and content-type headers - first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(currentFileTransferContent->getExpectedSize(), + first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(currentFileContentToTransfer->getFileSize(), _chat_message_file_transfer_on_progress, nullptr, nullptr, _chat_message_on_send_body, _chat_message_on_send_end, this); - if (!fileTransferFilePath.empty()) { + if (!currentFileContentToTransfer->getFilePath().empty()) { belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh; // No need to add again the callback for progression, otherwise it will be called twice - first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(fileTransferFilePath.c_str(), nullptr, this); + first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(currentFileContentToTransfer->getFilePath().c_str(), nullptr, this); //linphone_content_set_size(cFileTransferInformation, belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh)); belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)first_part_bh, body_handler); - } else if (!currentFileTransferContent->isEmpty()) { + } else if (!currentFileContentToTransfer->isEmpty()) { first_part_bh = (belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer( - ms_strdup(currentFileTransferContent->getBodyAsString().c_str()), - currentFileTransferContent->getSize(), _chat_message_file_transfer_on_progress, this); + ms_strdup(currentFileContentToTransfer->getBodyAsString().c_str()), + currentFileContentToTransfer->getSize(), _chat_message_file_transfer_on_progress, this); } belle_sip_body_handler_add_header(first_part_bh, belle_sip_header_create("Content-disposition", first_part_header.c_str())); belle_sip_body_handler_add_header(first_part_bh, (belle_sip_header_t *)belle_sip_header_content_type_create( - currentFileTransferContent->getContentType().getType().c_str(), - currentFileTransferContent->getContentType().getSubType().c_str())); + currentFileContentToTransfer->getContentType().getType().c_str(), + currentFileContentToTransfer->getContentType().getSubType().c_str())); // insert it in a multipart body handler which will manage the boundaries of multipart msg bh = belle_sip_multipart_body_handler_new(_chat_message_file_transfer_on_progress, this, first_part_bh, nullptr); releaseHttpRequest(); fileUploadBeginBackgroundTask(); - q->uploadFile(); + uploadFile(); belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(httpRequest), BELLE_SIP_BODY_HANDLER(bh)); } else if (code == 200) { // file has been uploaded correctly, get server reply and send it const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); @@ -784,9 +811,15 @@ void ChatMessagePrivate::processResponseFromPostFile (const belle_http_response_ setText(body); } setContentType(ContentType::FileTransfer);*/ - - (*currentFileTransferContent).setContentType(ContentType::FileTransfer); - (*currentFileTransferContent).setBody(body); + FileContent fileContent = *currentFileContentToTransfer; + + FileTransferContent fileTransferContent; + fileTransferContent.setContentType(ContentType::FileTransfer); + fileTransferContent.setFileContent(fileContent); + fileTransferContent.setBody(body); + + q->removeContent(fileContent); + q->addContent(fileTransferContent); q->updateState(ChatMessage::State::FileTransferDone); releaseHttpRequest(); @@ -812,8 +845,8 @@ static void _chat_process_response_headers_from_get_file (void *data, const bell d->processResponseHeadersFromGetFile(event); } -static Content createFileTransferInformationFromHeaders (const belle_sip_message_t *m) { - Content content; +static FileContent createFileTransferInformationFromHeaders (const belle_sip_message_t *m) { + FileContent content; belle_sip_header_content_length_t *content_length_hdr = BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(m, "Content-Length")); belle_sip_header_content_type_t *content_type_hdr = BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(m, "Content-Type")); @@ -824,10 +857,11 @@ static Content createFileTransferInformationFromHeaders (const belle_sip_message subtype = belle_sip_header_content_type_get_subtype(content_type_hdr); lInfo() << "Extracted content type " << type << " / " << subtype << " from header"; ContentType contentType(type, subtype); + content.setContentType(contentType); } if (content_length_hdr) { - content.setExpectedSize(belle_sip_header_content_length_get_content_length(content_length_hdr)); - lInfo() << "Extracted content length " << content.getExpectedSize() << " from header"; + content.setFileSize(belle_sip_header_content_length_get_content_length(content_length_hdr)); + lInfo() << "Extracted content length " << content.getFileSize() << " from header"; } return content; @@ -843,26 +877,26 @@ void ChatMessagePrivate::processResponseHeadersFromGetFile (const belle_http_res belle_sip_body_handler_t *body_handler = nullptr; size_t body_size = 0; - if (currentFileTransferContent == nullptr) { + if (currentFileContentToTransfer == nullptr) { lWarning() << "No file transfer information for msg [" << this << "]: creating..."; - Content content = createFileTransferInformationFromHeaders(response); + FileContent content = createFileTransferInformationFromHeaders(response); q->addContent(content); } else { belle_sip_header_content_length_t *content_length_hdr = BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(response, "Content-Length")); - currentFileTransferContent->setExpectedSize(belle_sip_header_content_length_get_content_length(content_length_hdr)); - lInfo() << "Extracted content length " << currentFileTransferContent->getExpectedSize() << " from header"; + currentFileContentToTransfer->setFileSize(belle_sip_header_content_length_get_content_length(content_length_hdr)); + lInfo() << "Extracted content length " << currentFileContentToTransfer->getFileSize() << " from header"; } - if (q->hasFileTransferContent()) { - body_size = q->getFileTransferContent().getExpectedSize(); + if (currentFileContentToTransfer) { + body_size = currentFileContentToTransfer->getFileSize(); } body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, _chat_message_file_transfer_on_progress, nullptr, _chat_message_on_recv_body, nullptr, _chat_message_on_recv_end, this); - if (!fileTransferFilePath.empty()) { + if (!currentFileContentToTransfer->getFilePath().empty()) { belle_sip_user_body_handler_t *bh = (belle_sip_user_body_handler_t *)body_handler; - body_handler = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(fileTransferFilePath.c_str(), _chat_message_file_transfer_on_progress, this); + body_handler = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(currentFileContentToTransfer->getFilePath().c_str(), _chat_message_file_transfer_on_progress, this); if (belle_sip_body_handler_get_size((belle_sip_body_handler_t *)body_handler) == 0) { // If the size of the body has not been initialized from the file stat, use the one from the // file_transfer_information. @@ -1008,14 +1042,38 @@ void ChatMessagePrivate::releaseHttpRequest () { } } -void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml (const string &body) { +int ChatMessagePrivate::uploadFile () { L_Q(); + + if (httpRequest) { + lError() << "linphone_chat_room_upload_file(): there is already an upload in progress."; + return -1; + } + + // THIS IS ONLY FOR BACKWARD C API COMPAT + if (currentFileContentToTransfer->getFilePath().empty() && !q->getFileTransferFilepath().empty()) { + currentFileContentToTransfer->setFilePath(q->getFileTransferFilepath()); + } + + belle_http_request_listener_callbacks_t cbs = { 0 }; + cbs.process_response = _chat_message_process_response_from_post_file; + cbs.process_io_error = _chat_message_process_io_error_upload; + cbs.process_auth_requested = _chat_message_process_auth_requested_upload; + + int err = startHttpTransfer(linphone_core_get_file_transfer_server(q->getCore()->getCCore()), "POST", &cbs); + if (err == -1) + setState(ChatMessage::State::NotDelivered); + + return err; +} + +void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml (FileTransferContent &fileTransferContent) { xmlChar *file_url = nullptr; xmlDocPtr xmlMessageBody; xmlNodePtr cur; /* parse the msg body to get all informations from it */ - xmlMessageBody = xmlParseDoc((const xmlChar *)body.c_str()); - Content content; + xmlMessageBody = xmlParseDoc((const xmlChar *)fileTransferContent.getBodyAsString().c_str()); + FileContent fileContent; cur = xmlDocGetRootElement(xmlMessageBody); if (cur != nullptr) { @@ -1030,13 +1088,13 @@ void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml ( if (!xmlStrcmp(cur->name, (const xmlChar *)"file-size")) { xmlChar *fileSizeString = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); size_t size = (size_t)strtol((const char *)fileSizeString, nullptr, 10); - content.setExpectedSize(size); + fileContent.setFileSize(size); xmlFree(fileSizeString); } if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) { xmlChar *filename = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - content.setContentDisposition((char *)filename); + fileContent.setFileName((char *)filename); xmlFree(filename); } if (!xmlStrcmp(cur->name, (const xmlChar *)"content-type")) { @@ -1050,7 +1108,7 @@ void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml ( type = ms_strndup((char *)content_type, contentTypeIndex); subtype = ms_strdup(((char *)content_type + contentTypeIndex + 1)); ContentType contentType(type, subtype); - content.setContentType(contentType); + fileContent.setContentType(contentType); ms_free(subtype); ms_free(type); ms_free(content_type); @@ -1086,8 +1144,12 @@ void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml ( } xmlFreeDoc(xmlMessageBody); - externalBodyUrl = string((const char *)file_url); - q->addContent(content); + fileContent.setFilePath(fileTransferContent.getFilePath()); // Copy file path from file transfer content to file content for file body handler + fileTransferContent.setFileUrl(string((const char *)file_url)); // Set file url in the file transfer content for the download + + // Link the FileContent to the FileTransferContent + fileTransferContent.setFileContent(fileContent); + xmlFree(file_url); } @@ -1163,12 +1225,10 @@ LinphoneReason ChatMessagePrivate::receive () { } bool messageToBeStored = false; - for (const auto &c : contents) { - if (c.getContentType() == ContentType::FileTransfer) { - messageToBeStored = true; - createFileTransferInformationsFromVndGsmaRcsFtHttpXml(c.getBodyAsString()); - } else if (c.getContentType() == ContentType::PlainText) + for (Content &c : contents) { + if (c.getContentType() == ContentType::FileTransfer || c.getContentType() == ContentType::PlainText) { messageToBeStored = true; + } } if (messageToBeStored) q->store(); @@ -1185,23 +1245,24 @@ void ChatMessagePrivate::send () { if ((currentSendStep & ChatMessagePrivate::Step::FileUpload) == ChatMessagePrivate::Step::FileUpload) { lInfo() << "File upload step already done, skipping"; } else { - currentFileTransferContent = nullptr; + currentFileContentToTransfer = nullptr; + // For each FileContent, upload it and create a FileTransferContent for (Content &content : contents) { ContentType contentType = content.getContentType(); - //TODO Improve ! + //TODO Improve if (contentType != ContentType::FileTransfer && contentType != ContentType::PlainText && contentType != ContentType::ExternalBody && contentType != ContentType::Imdn && contentType != ContentType::ImIsComposing && contentType != ContentType::ResourceLists && contentType != ContentType::Sdp && contentType != ContentType::ConferenceInfo && contentType != ContentType::Cpim) { lInfo() << "Found content with type " << contentType.asString() << ", set it for file upload"; - currentFileTransferContent = &content; + currentFileContentToTransfer = (FileContent *)&content; break; } } - if (currentFileTransferContent != nullptr) { + if (currentFileContentToTransfer != nullptr) { /* Open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */ - if (q->uploadFile() == 0) { + if (uploadFile() == 0) { setState(ChatMessage::State::InProgress); } return; @@ -1250,18 +1311,6 @@ void ChatMessagePrivate::send () { // Start of message modification // --------------------------------------- - // TODO Remove : This won't be necessary once we store the contentsList - string clearTextMessage; - ContentType clearTextContentType; - - if (!getText().empty()) { - clearTextMessage = getText().c_str(); - } - if (getContentType().isValid()) { - clearTextContentType = getContentType(); - } - // End of TODO Remove - if (applyModifiers) { if ((currentSendStep &ChatMessagePrivate::Step::Multipart) == ChatMessagePrivate::Step::Multipart) { lInfo() << "Multipart step already done, skipping"; @@ -1309,7 +1358,7 @@ void ChatMessagePrivate::send () { internalContent = contents.front(); } - if (!externalBodyUrl.empty()) { + if (!externalBodyUrl.empty()) { // Deprecated way of sending files char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", externalBodyUrl.c_str()); auto msgOp = dynamic_cast(op); msgOp->send_message(from.asString().c_str(), to.asString().c_str(), content_type, nullptr, nullptr); @@ -1323,16 +1372,14 @@ void ChatMessagePrivate::send () { } } - // TODO Remove : This won't be necessary once we store the contentsList - if (!getText().empty() && getText() == clearTextMessage) { - /* We replace the encrypted message by the original one so it can be correctly stored and displayed by the application */ - setText(clearTextMessage); + for (Content &content : contents) { + // Restore FileContents and remove FileTransferContents + if (content.getContentType() == ContentType::FileTransfer) { + FileTransferContent fileTransferContent = static_cast(content); + q->removeContent(content); + q->addContent(fileTransferContent.getFileContent()); + } } - if (getContentType().isValid() && (getContentType() != clearTextContentType)) { - /* We replace the encrypted content type by the original one */ - setContentType(clearTextContentType); - } - // End of TODO Remove q->setImdnMessageId(op->get_call_id()); /* must be known at that time */ @@ -1373,16 +1420,6 @@ shared_ptr ChatMessage::getChatRoom () const { // ----------------------------------------------------------------------------- -const string &ChatMessage::getExternalBodyUrl () const { - L_D(); - return d->externalBodyUrl; -} - -void ChatMessage::setExternalBodyUrl (const string &url) { - L_D(); - d->externalBodyUrl = url; -} - time_t ChatMessage::getTime () const { L_D(); return d->time; @@ -1434,19 +1471,6 @@ bool ChatMessage::isRead () const { return d->state == State::Delivered || d->state == State::Displayed || d->state == State::DeliveredToUser; } -const string &ChatMessage::getAppdata () const { - L_D(); - return d->appData; -} - -void ChatMessage::setAppdata (const string &appData) { - L_D(); - d->appData = appData; - - // TODO: history. - // linphone_chat_message_store_appdata(L_GET_C_BACK_PTR(this)); -} - const Address &ChatMessage::getFromAddress () const { L_D(); return d->from; @@ -1475,16 +1499,6 @@ const Address &ChatMessage::getRemoteAddress () const { return getDirection() != Direction::Incoming ? getToAddress() : getFromAddress(); } -const string &ChatMessage::getFileTransferFilepath () const { - L_D(); - return d->fileTransferFilePath; -} - -void ChatMessage::setFileTransferFilepath (const string &path) { - L_D(); - d->fileTransferFilePath = path; -} - // ----------------------------------------------------------------------------- const LinphoneErrorInfo *ChatMessage::getErrorInfo () const { @@ -1559,48 +1573,6 @@ void ChatMessage::removeCustomHeader (const string &headerName) { d->customHeaders.erase(headerName); } -bool ChatMessage::hasTextContent() const { - L_D(); - for (const auto &c : d->contents) { - if (c.getContentType() == ContentType::PlainText) { - return true; - } - } - return false; -} - -const Content &ChatMessage::getTextContent() const { - L_D(); - for (const auto &c : d->contents) { - if (c.getContentType() == ContentType::PlainText) { - return c; - } - } - return Content::Empty; -} - -bool ChatMessage::hasFileTransferContent() const { - L_D(); - for (const auto &c : d->contents) { - if (c.getContentType() == ContentType::FileTransfer) { - return true; - } - } - return false; -} - -const Content &ChatMessage::getFileTransferContent() const { - L_D(); - for (const auto &c : d->contents) { - if (c.getContentType() == ContentType::FileTransfer) { - return c; - } - } - return Content::Empty; -} - -// ----------------------------------------------------------------------------- - void ChatMessage::store () { L_D(); @@ -1660,44 +1632,32 @@ void ChatMessage::sendDisplayNotification () { d->sendImdn(Imdn::Type::Display, LinphoneReasonNone); } -int ChatMessage::uploadFile () { +int ChatMessage::downloadFile(FileTransferContent& fileTransferContent) { L_D(); - - if (d->httpRequest) { - lError() << "linphone_chat_room_upload_file(): there is already an upload in progress."; - return -1; - } - - belle_http_request_listener_callbacks_t cbs = { 0 }; - cbs.process_response = _chat_message_process_response_from_post_file; - cbs.process_io_error = _chat_message_process_io_error_upload; - cbs.process_auth_requested = _chat_message_process_auth_requested_upload; - - int err = d->startHttpTransfer(linphone_core_get_file_transfer_server(getCore()->getCCore()), "POST", &cbs); - if (err == -1) - d->setState(State::NotDelivered); - - return err; -} - -int ChatMessage::downloadFile () { - L_D(); - + if (d->httpRequest) { lError() << "linphone_chat_message_download_file(): there is already a download in progress"; return -1; } - if (hasFileTransferContent()) { - d->currentFileTransferContent = (Content *)&getFileTransferContent(); + if (fileTransferContent.getContentType() != ContentType::FileTransfer) { + lError() << "linphone_chat_message_download_file(): content type is not FileTransfer"; + return -1; } + d->createFileTransferInformationsFromVndGsmaRcsFtHttpXml(fileTransferContent); + FileContent fileContent = fileTransferContent.getFileContent(); + d->currentFileContentToTransfer = &fileContent; + if (d->currentFileContentToTransfer == nullptr) { + return -1; + } + belle_http_request_listener_callbacks_t cbs = { 0 }; cbs.process_response_headers = _chat_process_response_headers_from_get_file; cbs.process_response = _chat_message_process_response_from_get_file; cbs.process_io_error = _chat_message_process_io_error_download; cbs.process_auth_requested = _chat_message_process_auth_requested_download; - int err = d->startHttpTransfer(d->externalBodyUrl, "GET", &cbs); + int err = d->startHttpTransfer(fileTransferContent.getFileUrl(), "GET", &cbs); // File URL has been set by createFileTransferInformationsFromVndGsmaRcsFtHttpXml if (err == -1) return -1; // start the download, status is In Progress @@ -1716,9 +1676,9 @@ void ChatMessage::cancelFileTransfer () { if (chatRoom) { shared_ptr core = getCore(); lInfo() << "Canceling file transfer " << ( - d->externalBodyUrl.empty() + d->currentFileContentToTransfer->getFilePath().empty() ? linphone_core_get_file_transfer_server(core->getCCore()) - : d->externalBodyUrl.c_str() + : d->currentFileContentToTransfer->getFilePath().c_str() ); belle_http_provider_cancel_request(core->getCCore()->http_provider, d->httpRequest); } else { @@ -1780,4 +1740,83 @@ int ChatMessage::putCharacter (uint32_t character) { return -1; } +// ----------------------------------------------------------------------------- +// Below methods are only for C API backward compatibility... +// ----------------------------------------------------------------------------- + +bool ChatMessage::hasTextContent() const { + L_D(); + for (const auto &c : d->contents) { + if (c.getContentType() == ContentType::PlainText) { + return true; + } + } + return false; +} + +const Content &ChatMessage::getTextContent() const { + L_D(); + for (const auto &c : d->contents) { + if (c.getContentType() == ContentType::PlainText) { + return c; + } + } + return Content::Empty; +} + +bool ChatMessage::hasFileTransferContent() const { + L_D(); + for (const auto &c : d->contents) { + if (c.getContentType() == ContentType::FileTransfer) { + return true; + } + } + return false; +} + +const Content &ChatMessage::getFileTransferContent() const { + L_D(); + for (const auto &c : d->contents) { + if (c.getContentType() == ContentType::FileTransfer) { + return c; + } + } + return Content::Empty; +} + +const string &ChatMessage::getFileTransferFilepath () const { + L_D(); + return d->fileTransferFilePath; +} + +void ChatMessage::setFileTransferFilepath (const string &path) { + L_D(); + d->fileTransferFilePath = path; +} + +const string &ChatMessage::getAppdata () const { + L_D(); + return d->appData; +} + +void ChatMessage::setAppdata (const string &appData) { + L_D(); + d->appData = appData; + + // TODO: history. + // linphone_chat_message_store_appdata(L_GET_C_BACK_PTR(this)); +} + +const string &ChatMessage::getExternalBodyUrl () const { + L_D(); + return d->externalBodyUrl; +} + +void ChatMessage::setExternalBodyUrl (const string &url) { + L_D(); + d->externalBodyUrl = url; +} + +// ----------------------------------------------------------------------------- + LINPHONE_END_NAMESPACE diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index f4227665c..4db4998c0 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -35,6 +35,7 @@ LINPHONE_BEGIN_NAMESPACE class Address; class ChatRoom; class Content; +class FileTransferContent; class ChatMessagePrivate; class LINPHONE_PUBLIC ChatMessage : public Object, public CoreAccessor { @@ -61,8 +62,6 @@ public: void setAppdata (const std::string &appData); const std::string &getExternalBodyUrl () const; void setExternalBodyUrl (const std::string &url); - int uploadFile (); - int downloadFile (); void cancelFileTransfer (); int putCharacter (uint32_t character); void updateState (State state); @@ -115,6 +114,8 @@ public: void addCustomHeader (const std::string &headerName, const std::string &headerValue); void removeCustomHeader (const std::string &headerName); + int downloadFile (FileTransferContent& content); + private: L_DECLARE_PRIVATE(ChatMessage); L_DISABLE_COPY(ChatMessage); diff --git a/src/content/content-p.h b/src/content/content-p.h new file mode 100644 index 000000000..b3045b429 --- /dev/null +++ b/src/content/content-p.h @@ -0,0 +1,43 @@ +/* + * content-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CONTENT_P_H_ +#define _CONTENT_P_H_ + +#include + +#include "object/clonable-object-p.h" +#include "object/object-p.h" +#include "content-type.h" +#include "content.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ContentPrivate : public ClonableObjectPrivate { +public: + std::vector body; + ContentType contentType; + std::string contentDisposition; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CONTENT_P_H_ diff --git a/src/content/content.cpp b/src/content/content.cpp index 327dbfe90..dd646d198 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -18,8 +18,8 @@ */ #include "content-type.h" -#include "object/clonable-object-p.h" +#include "content-p.h" #include "content.h" #include "linphone/core.h" @@ -29,14 +29,6 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -class ContentPrivate : public ClonableObjectPrivate { -public: - vector body; - ContentType contentType; - string contentDisposition; - size_t expectedSize; -}; - const Content Content::Empty; // ----------------------------------------------------------------------------- @@ -48,7 +40,6 @@ Content::Content (const Content &src) : ClonableObject(*new ContentPrivate), App d->body = src.getBody(); d->contentType = src.getContentType(); d->contentDisposition = src.getContentDisposition(); - d->expectedSize = src.getExpectedSize(); } Content::Content (Content &&src) : ClonableObject(*new ContentPrivate), AppDataContainer(move(src)) { @@ -56,7 +47,10 @@ Content::Content (Content &&src) : ClonableObject(*new ContentPrivate), AppDataC d->body = move(src.getPrivate()->body); d->contentType = move(src.getPrivate()->contentType); d->contentDisposition = move(src.getPrivate()->contentDisposition); - d->expectedSize = move(src.getExpectedSize()); +} + +Content::Content (ContentPrivate &p) : ClonableObject(p) { + } Content &Content::operator= (const Content &src) { @@ -65,7 +59,6 @@ Content &Content::operator= (const Content &src) { d->body = src.getBody(); d->contentType = src.getContentType(); d->contentDisposition = src.getContentDisposition(); - d->expectedSize = src.getExpectedSize(); AppDataContainer::operator=(src); } @@ -77,7 +70,6 @@ Content &Content::operator= (Content &&src) { d->body = move(src.getPrivate()->body); d->contentType = move(src.getPrivate()->contentType); d->contentDisposition = move(src.getPrivate()->contentDisposition); - d->expectedSize = move(src.getExpectedSize()); AppDataContainer::operator=(move(src)); return *this; } @@ -150,16 +142,6 @@ size_t Content::getSize () const { return d->body.size(); } -void Content::setExpectedSize(size_t expectedSize) { - L_D(); - d->expectedSize = expectedSize; -} - -size_t Content::getExpectedSize() const { - L_D(); - return d->expectedSize; -} - bool Content::isEmpty () const { return getSize() == 0; } @@ -174,8 +156,6 @@ LinphoneContent * Content::toLinphoneContent() const { content = linphone_core_create_content(NULL); linphone_content_set_type(content, getContentType().getType().c_str()); linphone_content_set_subtype(content, getContentType().getSubType().c_str()); - linphone_content_set_size(content, getExpectedSize()); - linphone_content_set_name(content, getContentDisposition().c_str()); return content; } diff --git a/src/content/content.h b/src/content/content.h index 450f1c0eb..0047f6a46 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -60,17 +60,17 @@ public: size_t getSize () const; - void setExpectedSize(size_t expectedSize); - size_t getExpectedSize() const; - bool isValid() const; bool isEmpty () const; - LinphoneContent * toLinphoneContent() const; + virtual LinphoneContent * toLinphoneContent() const; static const Content Empty; +protected: + explicit Content (ContentPrivate &p); + private: L_DECLARE_PRIVATE(Content); }; diff --git a/src/content/file-content.cpp b/src/content/file-content.cpp new file mode 100644 index 000000000..e78252533 --- /dev/null +++ b/src/content/file-content.cpp @@ -0,0 +1,126 @@ +/* + * file-content.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "content-p.h" +#include "file-content.h" +#include "linphone/core.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +class FileContentPrivate : public ContentPrivate { +public: + string fileName; + string filePath; + size_t fileSize; +}; + +// ----------------------------------------------------------------------------- + +FileContent::FileContent() : Content(*new FileContentPrivate()) { + +} + +FileContent::FileContent (const FileContent &src) : Content(*new FileContentPrivate) { + L_D(); + d->fileName = src.getFileName(); + d->filePath = src.getFilePath(); + d->fileSize = src.getFileSize(); +} + +FileContent::FileContent (FileContent &&src) : Content(*new FileContentPrivate) { + L_D(); + d->fileName = move(src.getPrivate()->fileName); + d->filePath = move(src.getPrivate()->filePath); + d->fileSize = move(src.getPrivate()->fileSize); +} + +FileContent &FileContent::operator= (const FileContent &src) { + L_D(); + if (this != &src) { + Content::operator=(src); + d->fileName = src.getFileName(); + d->filePath = src.getFilePath(); + d->fileSize = src.getFileSize(); + } + + return *this; +} + +FileContent &FileContent::operator= (FileContent &&src) { + L_D(); + Content::operator=(move(src)); + d->fileName = move(src.getPrivate()->fileName); + d->filePath = move(src.getPrivate()->filePath); + d->fileSize = move(src.getPrivate()->fileSize); + return *this; +} + +bool FileContent::operator== (const FileContent &content) const { + L_D(); + return Content::operator==(content) && + d->fileName == content.getFileName() && + d->filePath == content.getFilePath() && + d->fileSize == content.getFileSize(); +} + +void FileContent::setFileSize(size_t size) { + L_D(); + d->fileSize = size; +} + +size_t FileContent::getFileSize() const { + L_D(); + return d->fileSize; +} + +void FileContent::setFileName(const string &name) { + L_D(); + d->fileName = name; +} + +string FileContent::getFileName() const { + L_D(); + return d->fileName; +} + +void FileContent::setFilePath(const string &path) { + L_D(); + d->filePath = path; +} + +string FileContent::getFilePath() const { + L_D(); + return d->filePath; +} + +LinphoneContent * FileContent::toLinphoneContent() const { + LinphoneContent* content; + content = linphone_core_create_content(NULL); + linphone_content_set_type(content, getContentType().getType().c_str()); + linphone_content_set_subtype(content, getContentType().getSubType().c_str()); + linphone_content_set_name(content, getFileName().c_str()); + linphone_content_set_size(content, getFileSize()); + return content; +} + +LINPHONE_END_NAMESPACE diff --git a/src/content/file-content.h b/src/content/file-content.h new file mode 100644 index 000000000..41ecab838 --- /dev/null +++ b/src/content/file-content.h @@ -0,0 +1,58 @@ +/* + * file-content.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _FILE_CONTENT_H_ +#define _FILE_CONTENT_H_ + +#include "content.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class FileContentPrivate; + +class LINPHONE_PUBLIC FileContent : public Content { +public: + FileContent(); + FileContent (const FileContent &src); + FileContent (FileContent &&src); + + FileContent &operator= (const FileContent &src); + FileContent &operator= (FileContent &&src); + bool operator== (const FileContent &content) const; + + void setFileSize(size_t size); + size_t getFileSize() const; + + void setFileName(const std::string &name); + std::string getFileName() const; + + void setFilePath(const std::string &path); + std::string getFilePath() const; + + LinphoneContent * toLinphoneContent() const override; + +private: + L_DECLARE_PRIVATE(FileContent); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _FILE_CONTENT_H_ diff --git a/src/content/file-transfer-content.cpp b/src/content/file-transfer-content.cpp new file mode 100644 index 000000000..9f96eba67 --- /dev/null +++ b/src/content/file-transfer-content.cpp @@ -0,0 +1,123 @@ +/* + * file-transfer-content.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "content-p.h" +#include "file-transfer-content.h" +#include "linphone/core.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +class FileTransferContentPrivate : public ContentPrivate { +public: + string fileUrl; + string filePath; + FileContent fileContent; +}; + +// ----------------------------------------------------------------------------- + +FileTransferContent::FileTransferContent() : Content(*new FileTransferContentPrivate()) { + +} + +FileTransferContent::FileTransferContent (const FileTransferContent &src) : Content(*new FileTransferContentPrivate) { + L_D(); + d->fileUrl = src.getFileUrl(); + d->filePath = src.getFilePath(); + d->fileContent = src.getFileContent(); +} + +FileTransferContent::FileTransferContent (FileTransferContent &&src) : Content(*new FileTransferContentPrivate) { + L_D(); + d->fileUrl = move(src.getPrivate()->fileUrl); + d->filePath = move(src.getPrivate()->filePath); + d->fileContent = move(src.getPrivate()->fileContent); +} + +FileTransferContent &FileTransferContent::operator= (const FileTransferContent &src) { + L_D(); + if (this != &src) { + Content::operator=(src); + d->fileUrl = src.getFileUrl(); + d->filePath = src.getFilePath(); + d->fileContent = src.getFileContent(); + } + + return *this; +} + +FileTransferContent &FileTransferContent::operator= (FileTransferContent &&src) { + L_D(); + Content::operator=(move(src)); + d->fileUrl = move(src.getPrivate()->fileUrl); + d->filePath = move(src.getPrivate()->filePath); + d->fileContent = move(src.getPrivate()->fileContent); + return *this; +} + +bool FileTransferContent::operator== (const FileTransferContent &content) const { + L_D(); + return Content::operator==(content) && + d->fileUrl == content.getFileUrl() && + d->filePath == content.getFilePath(); +} + +void FileTransferContent::setFileUrl(const string &url) { + L_D(); + d->fileUrl = url; +} + +string FileTransferContent::getFileUrl() const { + L_D(); + return d->fileUrl; +} + +void FileTransferContent::setFilePath(const string &path) { + L_D(); + d->filePath = path; +} + +string FileTransferContent::getFilePath() const { + L_D(); + return d->filePath; +} + +void FileTransferContent::setFileContent(const FileContent &content) { + L_D(); + d->fileContent = content; +} + +FileContent FileTransferContent::getFileContent() const { + L_D(); + return d->fileContent; +} + +LinphoneContent * FileTransferContent::toLinphoneContent() const { + LinphoneContent* content; + content = linphone_core_create_content(NULL); + linphone_content_set_type(content, getContentType().getType().c_str()); + linphone_content_set_subtype(content, getContentType().getSubType().c_str()); + return content; +} + +LINPHONE_END_NAMESPACE diff --git a/src/content/file-transfer-content.h b/src/content/file-transfer-content.h new file mode 100644 index 000000000..61b13089b --- /dev/null +++ b/src/content/file-transfer-content.h @@ -0,0 +1,59 @@ +/* + * file-transfer-content.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _FILE_TRANSFER_CONTENT_H_ +#define _FILE_TRANSFER_CONTENT_H_ + +#include "content.h" +#include "file-content.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class FileTransferContentPrivate; + +class LINPHONE_PUBLIC FileTransferContent : public Content { +public: + FileTransferContent(); + FileTransferContent (const FileTransferContent &src); + FileTransferContent (FileTransferContent &&src); + + FileTransferContent &operator= (const FileTransferContent &src); + FileTransferContent &operator= (FileTransferContent &&src); + bool operator== (const FileTransferContent &content) const; + + void setFileUrl(const std::string &url); + std::string getFileUrl() const; + + void setFilePath(const std::string &path); + std::string getFilePath() const; + + void setFileContent(const FileContent &content); + FileContent getFileContent() const; + + LinphoneContent * toLinphoneContent() const override; + +private: + L_DECLARE_PRIVATE(FileTransferContent); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _FILE_TRANSFER_CONTENT_H_ From 057db03349b1eb950cdbf5ccfccbb328b41d593a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 8 Nov 2017 15:15:47 +0100 Subject: [PATCH 0729/2215] Moved from a list of Content to a list of Content* to be able to cast content to specialized version --- src/c-wrapper/api/c-chat-message.cpp | 12 +- src/chat/chat-message/chat-message-p.h | 4 +- src/chat/chat-message/chat-message.cpp | 170 +++++++++--------- src/chat/chat-message/chat-message.h | 13 +- src/chat/chat-room/chat-room.cpp | 18 +- .../modifier/cpim-chat-message-modifier.cpp | 18 +- .../multipart-chat-message-modifier.cpp | 18 +- src/content/file-content.cpp | 6 +- src/content/file-content.h | 4 +- src/content/file-transfer-content.cpp | 10 +- src/content/file-transfer-content.h | 8 +- src/db/main-db.cpp | 4 +- tester/cpim-tester.cpp | 6 +- tester/multipart-tester.cpp | 13 +- 14 files changed, 154 insertions(+), 150 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 4f64cb6cd..0293b479e 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -294,10 +294,10 @@ LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg, uint32_t } void linphone_chat_message_add_text_content(LinphoneChatMessage *msg, const char *c_content) { - LinphonePrivate::Content content; + LinphonePrivate::Content *content = new LinphonePrivate::Content(); LinphonePrivate::ContentType contentType = LinphonePrivate::ContentType::PlainText; - content.setContentType(contentType); - content.setBody(L_C_TO_STRING(c_content)); + content->setContentType(contentType); + content->setBody(L_C_TO_STRING(c_content)); L_GET_CPP_PTR_FROM_C_OBJECT(msg)->addContent(content); } @@ -306,11 +306,11 @@ bool_t linphone_chat_message_has_text_content(const LinphoneChatMessage *msg) { } const char * linphone_chat_message_get_text_content(const LinphoneChatMessage *msg) { - LinphonePrivate::Content content = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getTextContent(); - if (content == LinphonePrivate::Content::Empty) { + const LinphonePrivate::Content *content = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getTextContent(); + if (*content == LinphonePrivate::Content::Empty) { return NULL; } - return L_STRING_TO_C(content.getBodyAsString()); + return L_STRING_TO_C(content->getBodyAsString()); } // ============================================================================= diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index 733fc5a42..6eeca943c 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -140,7 +140,7 @@ private: std::string rttMessage; bool isSecured = false; bool isReadOnly = false; - std::list contents; + std::list contents; Content internalContent; FileContent *currentFileContentToTransfer; std::unordered_map customHeaders; @@ -170,7 +170,7 @@ private: belle_http_request_listener_callbacks_t *cbs ); void releaseHttpRequest(); - void createFileTransferInformationsFromVndGsmaRcsFtHttpXml(FileTransferContent &content); + void createFileTransferInformationsFromVndGsmaRcsFtHttpXml(FileTransferContent* content); L_DECLARE_PUBLIC(ChatMessage); }; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 209b83c79..2dd2266a9 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -159,8 +159,8 @@ string ChatMessagePrivate::getSalCustomHeaderValue (const string &name) { const ContentType &ChatMessagePrivate::getContentType () { if (direction == ChatMessage::Direction::Incoming) { if (contents.size() > 0) { - Content content = contents.front(); - cContentType = content.getContentType(); + Content *content = contents.front(); + cContentType = content->getContentType(); } else { cContentType = internalContent.getContentType(); } @@ -169,8 +169,8 @@ const ContentType &ChatMessagePrivate::getContentType () { cContentType = internalContent.getContentType(); } else { if (contents.size() > 0) { - Content content = contents.front(); - cContentType = content.getContentType(); + Content *content = contents.front(); + cContentType = content->getContentType(); } } } @@ -184,21 +184,23 @@ void ChatMessagePrivate::setContentType (const ContentType &contentType) { const string &ChatMessagePrivate::getText () { L_Q(); if (direction == ChatMessage::Direction::Incoming) { - if (contents.size() > 0) { - Content content = contents.front(); - cText = content.getBodyAsString(); + if (q->hasTextContent()) { + cText = q->getTextContent()->getBodyAsString(); + } else if (contents.size() > 0) { + Content *content = contents.front(); + cText = content->getBodyAsString(); } else { cText = internalContent.getBodyAsString(); } } else { if (q->hasTextContent()) { - cText = q->getTextContent().getBodyAsString(); + cText = q->getTextContent()->getBodyAsString(); } else if (!internalContent.isEmpty()) { cText = internalContent.getBodyAsString(); } else { if (contents.size() > 0) { - Content content = contents.front(); - cText = content.getBodyAsString(); + Content *content = contents.front(); + cText = content->getBodyAsString(); } } } @@ -212,7 +214,7 @@ void ChatMessagePrivate::setText (const string &text) { LinphoneContent *ChatMessagePrivate::getFileTransferInformation () const { L_Q(); if (q->hasFileTransferContent()) { - return q->getFileTransferContent().toLinphoneContent(); + return q->getFileTransferContent()->toLinphoneContent(); } return NULL; } @@ -221,13 +223,13 @@ void ChatMessagePrivate::setFileTransferInformation (const LinphoneContent *c_co L_Q(); // Create a FileContent, it will create the FileTransferContent at upload time - FileContent fileContent; + FileContent *fileContent = new FileContent(); ContentType contentType(linphone_content_get_type(c_content), linphone_content_get_subtype(c_content)); - fileContent.setContentType(contentType); - fileContent.setFileSize(linphone_content_get_size(c_content)); - fileContent.setFileName(linphone_content_get_name(c_content)); + fileContent->setContentType(contentType); + fileContent->setFileSize(linphone_content_get_size(c_content)); + fileContent->setFileName(linphone_content_get_name(c_content)); if (linphone_content_get_string_buffer(c_content) != NULL) { - fileContent.setBody(linphone_content_get_string_buffer(c_content)); + fileContent->setBody(linphone_content_get_string_buffer(c_content)); } q->addContent(fileContent); @@ -236,9 +238,9 @@ void ChatMessagePrivate::setFileTransferInformation (const LinphoneContent *c_co int ChatMessagePrivate::downloadFile () { L_Q(); - for (Content& content : contents) { - if (content.getContentType() == ContentType::FileTransfer) { - return q->downloadFile(static_cast(content)); + for (Content *content : contents) { + if (content->getContentType() == ContentType::FileTransfer) { + return q->downloadFile((FileTransferContent*)content); } } @@ -641,13 +643,14 @@ void ChatMessagePrivate::onRecvEnd (belle_sip_user_body_handler_t *bh) { if (retval <= 0 && state != ChatMessage::State::FileTransferError) { // Remove the FileTransferContent from the message and store the FileContent - FileContent fileContent = *currentFileContentToTransfer; + FileContent *fileContent = currentFileContentToTransfer; q->addContent(fileContent); - for (Content &content : contents) { - if (content.getContentType() == ContentType::FileTransfer) { - FileTransferContent fileTransferContent = static_cast(content); - if (fileTransferContent.getFileContent() == fileContent) { + for (Content *content : contents) { + if (content->getContentType() == ContentType::FileTransfer) { + FileTransferContent *fileTransferContent = (FileTransferContent*)content; + if (fileTransferContent->getFileContent() == fileContent) { q->removeContent(content); + free(fileTransferContent); break; } } @@ -811,12 +814,12 @@ void ChatMessagePrivate::processResponseFromPostFile (const belle_http_response_ setText(body); } setContentType(ContentType::FileTransfer);*/ - FileContent fileContent = *currentFileContentToTransfer; + FileContent *fileContent = currentFileContentToTransfer; - FileTransferContent fileTransferContent; - fileTransferContent.setContentType(ContentType::FileTransfer); - fileTransferContent.setFileContent(fileContent); - fileTransferContent.setBody(body); + FileTransferContent *fileTransferContent = new FileTransferContent(); + fileTransferContent->setContentType(ContentType::FileTransfer); + fileTransferContent->setFileContent(fileContent); + fileTransferContent->setBody(body); q->removeContent(fileContent); q->addContent(fileTransferContent); @@ -845,8 +848,8 @@ static void _chat_process_response_headers_from_get_file (void *data, const bell d->processResponseHeadersFromGetFile(event); } -static FileContent createFileTransferInformationFromHeaders (const belle_sip_message_t *m) { - FileContent content; +static FileContent* createFileTransferInformationFromHeaders (const belle_sip_message_t *m) { + FileContent *fileContent = new FileContent(); belle_sip_header_content_length_t *content_length_hdr = BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(m, "Content-Length")); belle_sip_header_content_type_t *content_type_hdr = BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(m, "Content-Type")); @@ -857,14 +860,14 @@ static FileContent createFileTransferInformationFromHeaders (const belle_sip_mes subtype = belle_sip_header_content_type_get_subtype(content_type_hdr); lInfo() << "Extracted content type " << type << " / " << subtype << " from header"; ContentType contentType(type, subtype); - content.setContentType(contentType); + fileContent->setContentType(contentType); } if (content_length_hdr) { - content.setFileSize(belle_sip_header_content_length_get_content_length(content_length_hdr)); - lInfo() << "Extracted content length " << content.getFileSize() << " from header"; + fileContent->setFileSize(belle_sip_header_content_length_get_content_length(content_length_hdr)); + lInfo() << "Extracted content length " << fileContent->getFileSize() << " from header"; } - return content; + return fileContent; } void ChatMessagePrivate::processResponseHeadersFromGetFile (const belle_http_response_event_t *event) { @@ -879,7 +882,7 @@ void ChatMessagePrivate::processResponseHeadersFromGetFile (const belle_http_res if (currentFileContentToTransfer == nullptr) { lWarning() << "No file transfer information for msg [" << this << "]: creating..."; - FileContent content = createFileTransferInformationFromHeaders(response); + FileContent *content = createFileTransferInformationFromHeaders(response); q->addContent(content); } else { belle_sip_header_content_length_t *content_length_hdr = BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(response, "Content-Length")); @@ -1067,13 +1070,13 @@ int ChatMessagePrivate::uploadFile () { return err; } -void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml (FileTransferContent &fileTransferContent) { +void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml (FileTransferContent *fileTransferContent) { xmlChar *file_url = nullptr; xmlDocPtr xmlMessageBody; xmlNodePtr cur; /* parse the msg body to get all informations from it */ - xmlMessageBody = xmlParseDoc((const xmlChar *)fileTransferContent.getBodyAsString().c_str()); - FileContent fileContent; + xmlMessageBody = xmlParseDoc((const xmlChar *)fileTransferContent->getBodyAsString().c_str()); + FileContent *fileContent = new FileContent(); cur = xmlDocGetRootElement(xmlMessageBody); if (cur != nullptr) { @@ -1088,13 +1091,13 @@ void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml ( if (!xmlStrcmp(cur->name, (const xmlChar *)"file-size")) { xmlChar *fileSizeString = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); size_t size = (size_t)strtol((const char *)fileSizeString, nullptr, 10); - fileContent.setFileSize(size); + fileContent->setFileSize(size); xmlFree(fileSizeString); } if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) { xmlChar *filename = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - fileContent.setFileName((char *)filename); + fileContent->setFileName((char *)filename); xmlFree(filename); } if (!xmlStrcmp(cur->name, (const xmlChar *)"content-type")) { @@ -1108,7 +1111,7 @@ void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml ( type = ms_strndup((char *)content_type, contentTypeIndex); subtype = ms_strdup(((char *)content_type + contentTypeIndex + 1)); ContentType contentType(type, subtype); - fileContent.setContentType(contentType); + fileContent->setContentType(contentType); ms_free(subtype); ms_free(type); ms_free(content_type); @@ -1144,11 +1147,11 @@ void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml ( } xmlFreeDoc(xmlMessageBody); - fileContent.setFilePath(fileTransferContent.getFilePath()); // Copy file path from file transfer content to file content for file body handler - fileTransferContent.setFileUrl(string((const char *)file_url)); // Set file url in the file transfer content for the download + fileContent->setFilePath(fileTransferContent->getFilePath()); // Copy file path from file transfer content to file content for file body handler + fileTransferContent->setFileUrl(string((const char *)file_url)); // Set file url in the file transfer content for the download // Link the FileContent to the FileTransferContent - fileTransferContent.setFileContent(fileContent); + fileTransferContent->setFileContent(fileContent); xmlFree(file_url); } @@ -1186,7 +1189,7 @@ LinphoneReason ChatMessagePrivate::receive () { if (contents.size() == 0) { // All previous modifiers only altered the internal content, let's fill the content list - contents.push_back(internalContent); + contents.push_back(&internalContent); } // --------------------------------------- @@ -1195,12 +1198,12 @@ LinphoneReason ChatMessagePrivate::receive () { if (errorCode <= 0) { bool foundSupportContentType = false; - for (const auto &c : contents) { - if (linphone_core_is_content_type_supported(core->getCCore(), c.getContentType().asString().c_str())) { + for (Content *c : contents) { + if (linphone_core_is_content_type_supported(core->getCCore(), c->getContentType().asString().c_str())) { foundSupportContentType = true; break; } else - lError() << "Unsupported content-type: " << c.getContentType().asString(); + lError() << "Unsupported content-type: " << c->getContentType().asString(); } if (!foundSupportContentType) { @@ -1225,8 +1228,8 @@ LinphoneReason ChatMessagePrivate::receive () { } bool messageToBeStored = false; - for (Content &c : contents) { - if (c.getContentType() == ContentType::FileTransfer || c.getContentType() == ContentType::PlainText) { + for (Content *c : contents) { + if (c->getContentType() == ContentType::FileTransfer || c->getContentType() == ContentType::PlainText) { messageToBeStored = true; } } @@ -1247,8 +1250,8 @@ void ChatMessagePrivate::send () { } else { currentFileContentToTransfer = nullptr; // For each FileContent, upload it and create a FileTransferContent - for (Content &content : contents) { - ContentType contentType = content.getContentType(); + for (Content *content : contents) { + ContentType contentType = content->getContentType(); //TODO Improve if (contentType != ContentType::FileTransfer && contentType != ContentType::PlainText && contentType != ContentType::ExternalBody && contentType != ContentType::Imdn && @@ -1256,7 +1259,8 @@ void ChatMessagePrivate::send () { contentType != ContentType::Sdp && contentType != ContentType::ConferenceInfo && contentType != ContentType::Cpim) { lInfo() << "Found content with type " << contentType.asString() << ", set it for file upload"; - currentFileContentToTransfer = (FileContent *)&content; + FileContent *fileContent = (FileContent *)content; + currentFileContentToTransfer = fileContent; break; } } @@ -1355,7 +1359,7 @@ void ChatMessagePrivate::send () { // --------------------------------------- if (internalContent.isEmpty()) { - internalContent = contents.front(); + internalContent = *(contents.front()); } if (!externalBodyUrl.empty()) { // Deprecated way of sending files @@ -1372,12 +1376,13 @@ void ChatMessagePrivate::send () { } } - for (Content &content : contents) { + for (Content *content : contents) { // Restore FileContents and remove FileTransferContents - if (content.getContentType() == ContentType::FileTransfer) { - FileTransferContent fileTransferContent = static_cast(content); + if (content->getContentType() == ContentType::FileTransfer) { + FileTransferContent *fileTransferContent = (FileTransferContent *)content; q->removeContent(content); - q->addContent(fileTransferContent.getFileContent()); + free(fileTransferContent); + q->addContent(fileTransferContent->getFileContent()); } } @@ -1513,26 +1518,19 @@ bool ChatMessage::isReadOnly () const { return d->isReadOnly; } -const list &ChatMessage::getContents () const { +const list &ChatMessage::getContents () const { L_D(); return d->contents; } -void ChatMessage::addContent (Content &&content) { - L_D(); - if (d->isReadOnly) return; - - d->contents.push_back(move(content)); -} - -void ChatMessage::addContent (const Content &content) { +void ChatMessage::addContent (Content *content) { L_D(); if (d->isReadOnly) return; d->contents.push_back(content); } -void ChatMessage::removeContent (const Content &content) { +void ChatMessage::removeContent (Content *content) { L_D(); if (d->isReadOnly) return; @@ -1632,7 +1630,7 @@ void ChatMessage::sendDisplayNotification () { d->sendImdn(Imdn::Type::Display, LinphoneReasonNone); } -int ChatMessage::downloadFile(FileTransferContent& fileTransferContent) { +int ChatMessage::downloadFile(FileTransferContent *fileTransferContent) { L_D(); if (d->httpRequest) { @@ -1640,14 +1638,14 @@ int ChatMessage::downloadFile(FileTransferContent& fileTransferContent) { return -1; } - if (fileTransferContent.getContentType() != ContentType::FileTransfer) { + if (fileTransferContent->getContentType() != ContentType::FileTransfer) { lError() << "linphone_chat_message_download_file(): content type is not FileTransfer"; return -1; } d->createFileTransferInformationsFromVndGsmaRcsFtHttpXml(fileTransferContent); - FileContent fileContent = fileTransferContent.getFileContent(); - d->currentFileContentToTransfer = &fileContent; + FileContent *fileContent = fileTransferContent->getFileContent(); + d->currentFileContentToTransfer = fileContent; if (d->currentFileContentToTransfer == nullptr) { return -1; } @@ -1657,7 +1655,7 @@ int ChatMessage::downloadFile(FileTransferContent& fileTransferContent) { cbs.process_response = _chat_message_process_response_from_get_file; cbs.process_io_error = _chat_message_process_io_error_download; cbs.process_auth_requested = _chat_message_process_auth_requested_download; - int err = d->startHttpTransfer(fileTransferContent.getFileUrl(), "GET", &cbs); // File URL has been set by createFileTransferInformationsFromVndGsmaRcsFtHttpXml + int err = d->startHttpTransfer(fileTransferContent->getFileUrl(), "GET", &cbs); // File URL has been set by createFileTransferInformationsFromVndGsmaRcsFtHttpXml if (err == -1) return -1; // start the download, status is In Progress @@ -1746,42 +1744,42 @@ int ChatMessage::putCharacter (uint32_t character) { bool ChatMessage::hasTextContent() const { L_D(); - for (const auto &c : d->contents) { - if (c.getContentType() == ContentType::PlainText) { + for (const Content *c : d->contents) { + if (c->getContentType() == ContentType::PlainText) { return true; } } return false; } -const Content &ChatMessage::getTextContent() const { +const Content* ChatMessage::getTextContent() const { L_D(); - for (const auto &c : d->contents) { - if (c.getContentType() == ContentType::PlainText) { + for (const Content *c : d->contents) { + if (c->getContentType() == ContentType::PlainText) { return c; } } - return Content::Empty; + return &Content::Empty; } bool ChatMessage::hasFileTransferContent() const { L_D(); - for (const auto &c : d->contents) { - if (c.getContentType() == ContentType::FileTransfer) { + for (const Content *c : d->contents) { + if (c->getContentType() == ContentType::FileTransfer) { return true; } } return false; } -const Content &ChatMessage::getFileTransferContent() const { +const Content* ChatMessage::getFileTransferContent() const { L_D(); - for (const auto &c : d->contents) { - if (c.getContentType() == ContentType::FileTransfer) { + for (const Content *c : d->contents) { + if (c->getContentType() == ContentType::FileTransfer) { return c; } } - return Content::Empty; + return &Content::Empty; } const string &ChatMessage::getFileTransferFilepath () const { diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index 4db4998c0..f6f67e917 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -96,16 +96,15 @@ public: bool isRead () const; bool isReadOnly () const; - const std::list &getContents () const; - void addContent (Content &&content); - void addContent (const Content &content); - void removeContent (const Content &content); + const std::list &getContents () const; + void addContent (Content *content); + void removeContent (Content *content); bool hasTextContent() const; - const Content &getTextContent() const; + const Content* getTextContent() const; bool hasFileTransferContent() const; - const Content &getFileTransferContent() const; + const Content* getFileTransferContent() const; const Content &getInternalContent () const; void setInternalContent (const Content &content); @@ -114,7 +113,7 @@ public: void addCustomHeader (const std::string &headerName, const std::string &headerValue); void removeCustomHeader (const std::string &headerName); - int downloadFile (FileTransferContent& content); + int downloadFile (FileTransferContent *content); private: L_DECLARE_PRIVATE(ChatMessage); diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 9e341f041..eeddb572b 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -118,9 +118,9 @@ void ChatRoomPrivate::sendImdn (const string &payload, LinphoneReason reason) { msg->setFromAddress(Address(identity)); msg->setToAddress(peerAddress); - Content content; - content.setContentType("message/imdn+xml"); - content.setBody(payload); + Content *content = new Content(); + content->setContentType("message/imdn+xml"); + content->setBody(payload); msg->addContent(content); /* Do not try to encrypt the notification when it is reporting an error (maybe it should be bypassed only for some reasons). */ @@ -163,9 +163,9 @@ void ChatRoomPrivate::sendIsComposingNotification () { string payload = isComposingHandler->marshal(isComposing); if (!payload.empty()) { shared_ptr msg = q->createMessage(); - Content content; - content.setContentType("application/im-iscomposing+xml"); - content.setBody(payload); + Content *content = new Content(); + content->setContentType("application/im-iscomposing+xml"); + content->setBody(payload); msg->addContent(content); msg->getPrivate()->send(); } @@ -465,9 +465,9 @@ shared_ptr ChatRoom::createFileTransferMessage (const LinphoneConte shared_ptr ChatRoom::createMessage (const string &message) { shared_ptr chatMessage = createMessage(); - Content content; - content.setContentType(ContentType::PlainText); - content.setBody(message); + Content *content = new Content(); + content->setContentType(ContentType::PlainText); + content->setBody(message); chatMessage->addContent(content); return chatMessage; } diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index c017ce9fb..f96e28941 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -46,10 +46,10 @@ ChatMessageModifier::Result CpimChatMessageModifier::encode (const shared_ptrgetToAddress())); cpimMessage.addMessageHeader(cpimToHeader); - Content content; + const Content *content; if (!message->getInternalContent().isEmpty()) { // Another ChatMessageModifier was called before this one, we apply our changes on the private content - content = message->getInternalContent(); + content = &(message->getInternalContent()); } else { // We're the first ChatMessageModifier to be called, we'll create the private content from the public one // We take the first one because if there is more of them, the multipart modifier should have been called first @@ -59,10 +59,10 @@ ChatMessageModifier::Result CpimChatMessageModifier::encode (const shared_ptrgetContentType().asString()); cpimMessage.addContentHeader(contentTypeHeader); - const string contentBody = content.getBodyAsString(); + const string contentBody = content->getBodyAsString(); cpimMessage.setContent(contentBody); if (!cpimMessage.isValid()) { @@ -80,18 +80,18 @@ ChatMessageModifier::Result CpimChatMessageModifier::encode (const shared_ptr &message, int &errorCode) { - Content content; + const Content *content; if (!message->getInternalContent().isEmpty()) - content = message->getInternalContent(); + content = &(message->getInternalContent()); else content = message->getContents().front(); - if (content.getContentType() != ContentType::Cpim) { - lError() << "[CPIM] Message is not CPIM but " << content.getContentType().asString(); + if (content->getContentType() != ContentType::Cpim) { + lError() << "[CPIM] Message is not CPIM but " << content->getContentType().asString(); return ChatMessageModifier::Result::Skipped; } - const string contentBody = content.getBodyAsString(); + const string contentBody = content->getBodyAsString(); const shared_ptr cpimMessage = Cpim::Message::createFromString(contentBody); if (!cpimMessage || !cpimMessage->isValid()) { lError() << "[CPIM] Message is invalid: " << contentBody; diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index 7ccdff1e1..59b1d840f 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -24,6 +24,7 @@ #include "chat/chat-message/chat-message.h" #include "chat/chat-room/chat-room.h" #include "content/content-type.h" +#include "content/file-transfer-content.h" #include "logger/logger.h" #include "core/core.h" @@ -49,10 +50,10 @@ ChatMessageModifier::Result MultipartChatMessageModifier::encode ( stringstream multipartMessage; multipartMessage << "--" << boundary; - for (const auto &content : message->getContents()) { + for (Content *content : message->getContents()) { multipartMessage << "\r\n"; - multipartMessage << "Content-Type: " << content.getContentType().asString() << "\r\n\r\n"; - multipartMessage << content.getBodyAsString() << "\r\n\r\n"; + multipartMessage << "Content-Type: " << content->getContentType().asString() << "\r\n\r\n"; + multipartMessage << content->getBodyAsString() << "\r\n\r\n"; multipartMessage << "--" << boundary; } multipartMessage << "--"; @@ -111,9 +112,14 @@ ChatMessageModifier::Result MultipartChatMessageModifier::decode (const shared_p endOfLinePos += 4; // 4 is two time the size of \r\n string contentBody = contentString.substr(endOfLinePos, contentString.length() - (endOfLinePos + 4)); // 4 is two time the size of \r\n - Content content; - content.setContentType(contentType); - content.setBody(contentBody); + Content *content; + if (contentType == ContentType::FileTransfer) { + content = new FileTransferContent(); + } else { + content = new Content(); + } + content->setContentType(contentType); + content->setBody(contentBody); message->addContent(content); lInfo() << "Parsed and added content with type " << contentType.asString(); diff --git a/src/content/file-content.cpp b/src/content/file-content.cpp index e78252533..8bb303e09 100644 --- a/src/content/file-content.cpp +++ b/src/content/file-content.cpp @@ -31,7 +31,7 @@ class FileContentPrivate : public ContentPrivate { public: string fileName; string filePath; - size_t fileSize; + size_t fileSize = 0; }; // ----------------------------------------------------------------------------- @@ -98,7 +98,7 @@ void FileContent::setFileName(const string &name) { d->fileName = name; } -string FileContent::getFileName() const { +const string& FileContent::getFileName() const { L_D(); return d->fileName; } @@ -108,7 +108,7 @@ void FileContent::setFilePath(const string &path) { d->filePath = path; } -string FileContent::getFilePath() const { +const string& FileContent::getFilePath() const { L_D(); return d->filePath; } diff --git a/src/content/file-content.h b/src/content/file-content.h index 41ecab838..15aa279e1 100644 --- a/src/content/file-content.h +++ b/src/content/file-content.h @@ -42,10 +42,10 @@ public: size_t getFileSize() const; void setFileName(const std::string &name); - std::string getFileName() const; + const std::string& getFileName() const; void setFilePath(const std::string &path); - std::string getFilePath() const; + const std::string& getFilePath() const; LinphoneContent * toLinphoneContent() const override; diff --git a/src/content/file-transfer-content.cpp b/src/content/file-transfer-content.cpp index 9f96eba67..a5583ad58 100644 --- a/src/content/file-transfer-content.cpp +++ b/src/content/file-transfer-content.cpp @@ -31,7 +31,7 @@ class FileTransferContentPrivate : public ContentPrivate { public: string fileUrl; string filePath; - FileContent fileContent; + FileContent *fileContent = nullptr; }; // ----------------------------------------------------------------------------- @@ -87,7 +87,7 @@ void FileTransferContent::setFileUrl(const string &url) { d->fileUrl = url; } -string FileTransferContent::getFileUrl() const { +const string& FileTransferContent::getFileUrl() const { L_D(); return d->fileUrl; } @@ -97,17 +97,17 @@ void FileTransferContent::setFilePath(const string &path) { d->filePath = path; } -string FileTransferContent::getFilePath() const { +const string& FileTransferContent::getFilePath() const { L_D(); return d->filePath; } -void FileTransferContent::setFileContent(const FileContent &content) { +void FileTransferContent::setFileContent(FileContent *content) { L_D(); d->fileContent = content; } -FileContent FileTransferContent::getFileContent() const { +FileContent* FileTransferContent::getFileContent() const { L_D(); return d->fileContent; } diff --git a/src/content/file-transfer-content.h b/src/content/file-transfer-content.h index 61b13089b..c2965bb29 100644 --- a/src/content/file-transfer-content.h +++ b/src/content/file-transfer-content.h @@ -40,13 +40,13 @@ public: bool operator== (const FileTransferContent &content) const; void setFileUrl(const std::string &url); - std::string getFileUrl() const; + const std::string& getFileUrl() const; void setFilePath(const std::string &path); - std::string getFilePath() const; + const std::string& getFilePath() const; - void setFileContent(const FileContent &content); - FileContent getFileContent() const; + void setFileContent(FileContent *content); + FileContent* getFileContent() const; LinphoneContent * toLinphoneContent() const override; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 84d413e1f..a10495446 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -478,8 +478,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::use(static_cast(chatMessage->getState())), soci::use(static_cast(chatMessage->getDirection())), soci::use(chatMessage->getImdnMessageId()), soci::use(chatMessage->isSecured() ? 1 : 0); - for (const auto &content : chatMessage->getContents()) - insertContent(eventId, content); + for (Content *content : chatMessage->getContents()) + insertContent(eventId, *content); return eventId; } diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index 079ff130b..239a3690e 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -399,9 +399,9 @@ static void cpim_chat_message_modifier_base(bool_t use_multipart) { shared_ptr marieMessage = marieRoom->createMessage("Hello CPIM"); if (use_multipart) { - Content content; - content.setContentType(ContentType::PlainText); - content.setBody("Hello Part 2"); + Content *content = new Content(); + content->setContentType(ContentType::PlainText); + content->setBody("Hello Part 2"); marieMessage->addContent(content); } marieMessage->send(); diff --git a/tester/multipart-tester.cpp b/tester/multipart-tester.cpp index f1b6617e6..8430fe372 100644 --- a/tester/multipart-tester.cpp +++ b/tester/multipart-tester.cpp @@ -21,6 +21,7 @@ #include "chat/chat-room/basic-chat-room.h" #include "content/content-type.h" #include "content/content.h" +#include "content/file-content.h" #include "core/core.h" // TODO: Remove me later. @@ -60,14 +61,14 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer, bool linphone_content_set_subtype(initialContent,"mkv"); linphone_content_set_name(initialContent,"sintel_trailer_opus_h264.mkv"); - Content content; - content.setContentType(ContentType::FileTransfer); - content.setBody(linphone_content_get_string_buffer(initialContent)); + FileContent *content = new FileContent(); + content->setContentType(ContentType::FileTransfer); + content->setBody(linphone_content_get_string_buffer(initialContent)); marieMessage->addContent(content); } else { - Content content; - content.setContentType(ContentType::PlainText); - content.setBody("Hello Part 2"); + Content *content = new Content(); + content->setContentType(ContentType::PlainText); + content->setBody("Hello Part 2"); marieMessage->addContent(content); } marieMessage->send(); From 9d4a1f3cd59c24afc9a7b26437c998b04618ca5e Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 8 Nov 2017 15:21:51 +0100 Subject: [PATCH 0730/2215] feat(MainDb): add a weak list of event references --- src/core/core.h | 1 + src/db/main-db-event-key.cpp | 9 ++++++--- src/db/main-db-p.h | 3 +++ src/db/main-db.cpp | 4 +++- src/db/main-db.h | 2 ++ 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/core/core.h b/src/core/core.h index a56807681..ab0063512 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -38,6 +38,7 @@ class LINPHONE_PUBLIC Core : public Object { friend class ChatRoom; friend class ClientGroupChatRoom; friend class MainDb; + friend class MainDbEventKey; public: L_OVERRIDE_SHARED_FROM_THIS(Core); diff --git a/src/db/main-db-event-key.cpp b/src/db/main-db-event-key.cpp index a363ba3c4..fdc354be9 100644 --- a/src/db/main-db-event-key.cpp +++ b/src/db/main-db-event-key.cpp @@ -17,7 +17,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "core/core-p.h" #include "main-db-event-key-p.h" +#include "main-db-p.h" // ============================================================================= @@ -44,9 +46,10 @@ MainDbEventKey::MainDbEventKey (const MainDbEventKey &src) : MainDbEventKey() { } MainDbEventKey::~MainDbEventKey () { - if (isValid()) { - // TODO: Remove key from main db references if necessary. - } + L_D(); + + if (isValid()) + d->core.lock()->getPrivate()->mainDb->getPrivate()->storageIdToEvent.erase(d->storageId); } MainDbEventKey &MainDbEventKey::operator= (const MainDbEventKey &src) { diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 9a2715a67..ba4a9c23c 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -31,6 +31,9 @@ LINPHONE_BEGIN_NAMESPACE class Content; class MainDbPrivate : public AbstractDbPrivate { +public: + std::unordered_map> storageIdToEvent; + private: // --------------------------------------------------------------------------- // Low level API. diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index a10495446..700cf46d6 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -833,8 +833,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), L_END_LOG_EXCEPTION - if (soFarSoGood) + if (soFarSoGood) { dEventLog->dbKey = MainDbEventKey(getCore(), storageId); + d->storageIdToEvent[storageId] = eventLog; + } return soFarSoGood; } diff --git a/src/db/main-db.h b/src/db/main-db.h index acfae01c7..d675a0186 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -36,6 +36,8 @@ class EventLog; class MainDbPrivate; class MainDb : public AbstractDb, public CoreAccessor { + friend class MainDbEventKey; + public: enum Filter { NoFilter = 0x0, From 8fcc2ea86f344fac68e62510f5005f786913b349 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 8 Nov 2017 15:24:35 +0100 Subject: [PATCH 0731/2215] Fix Refer-To address in REFER messages sent by the ClientGroupChatRoom. --- src/chat/chat-room/client-group-chat-room.cpp | 4 ---- src/sal/refer-op.cpp | 7 +++++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 0b5defc37..8b25a87e4 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -196,8 +196,6 @@ void ClientGroupChatRoom::removeParticipant (const shared_ptr Address referToAddr = participant->getAddress(); referToAddr.setParam("text"); referToAddr.setUriParam("method", "BYE"); - referToAddr.setDomain(""); - referToAddr.setPort(-1); referOp->send_refer(referToAddr.getPrivate()->getInternalAddress()); referOp->unref(); } @@ -224,8 +222,6 @@ void ClientGroupChatRoom::setParticipantAdminStatus (shared_ptr &pa Address referToAddr = participant->getAddress(); referToAddr.setParam("text"); referToAddr.setParam("admin", Utils::toString(isAdmin)); - referToAddr.setDomain(""); - referToAddr.setPort(-1); referOp->send_refer(referToAddr.getPrivate()->getInternalAddress()); referOp->unref(); } diff --git a/src/sal/refer-op.cpp b/src/sal/refer-op.cpp index bf666f43b..a6ea0425f 100644 --- a/src/sal/refer-op.cpp +++ b/src/sal/refer-op.cpp @@ -89,8 +89,11 @@ int SalReferOp::send_refer(const SalAddress *refer_to) { belle_sip_request_t* req=build_request("REFER"); if (req == NULL ) return -1; if (get_contact_address()) belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(create_contact())); - belle_sip_header_refer_to_t *refer_to_header = belle_sip_header_refer_to_create(BELLE_SIP_HEADER_ADDRESS(refer_to)); - belle_sip_header_address_set_automatic(BELLE_SIP_HEADER_ADDRESS(refer_to_header), true); + belle_sip_header_address_t *address = BELLE_SIP_HEADER_ADDRESS(refer_to); + belle_sip_uri_t *uri = belle_sip_header_address_get_uri(address); + if (!belle_sip_uri_get_host(uri)) + belle_sip_header_address_set_automatic(address, true); + belle_sip_header_refer_to_t *refer_to_header = belle_sip_header_refer_to_create(address); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req), BELLE_SIP_HEADER(refer_to_header)); return send_request(req); } From 64802f026b3e2dfb2942db2e530f0e77e1d9dbb6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 8 Nov 2017 15:28:54 +0100 Subject: [PATCH 0732/2215] Remove useless conference tester. --- tester/CMakeLists.txt | 1 - tester/conference-tester.cpp | 121 ----------------------------------- tester/tester.c | 1 - 3 files changed, 123 deletions(-) delete mode 100644 tester/conference-tester.cpp diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index 3e58928c1..e876aeef0 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -197,7 +197,6 @@ set(SOURCE_FILES_C set(SOURCE_FILES_CXX clonable-object-tester.cpp conference-event-tester.cpp - conference-tester.cpp content-manager-tester.cpp cpim-tester.cpp main-db-tester.cpp diff --git a/tester/conference-tester.cpp b/tester/conference-tester.cpp deleted file mode 100644 index ca195fbfa..000000000 --- a/tester/conference-tester.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * conference-event-tester.cpp - * Copyright (C) 2017 Belledonne Communications SARL - * - * 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, see . - */ - -#include "linphone/core.h" -#include "private.h" -#include "liblinphone_tester.h" -#include "conference/local-conference.h" -#include "conference/remote-conference.h" - -using namespace LinphonePrivate; -using namespace std; - -static const string firstInvite = "" -"" -"" -" " -" Le Bricoleur" -" " -" " -" Sarah" -"" -""; - -static const string aliceAddr = "sip:alice@sip.linphone.org"; -static const string bobAddr = "sip:bob@sip.linphone.org"; -static const string johnAddr = "sip:john-doe@sip.linphone.org"; -static const string anneAddr = "sip:anne-onyme@sip.linphone.org"; -static const string sarahAddr = "sip:sarah-bache@sip.linphone.org"; - -static const string bobName = "Le Bricoleur"; -static const string sarahName = "Sarah"; - -static void check_first_invite(LinphoneCore *core, const Address &address, string invite) { - LocalConference localConf(core, address); - list
      addresses = localConf.parseResourceLists(invite); - BC_ASSERT_EQUAL(addresses.size(), 5, int, "%d"); - if (addresses.size() != 5) - return; - BC_ASSERT_TRUE(addresses.front().asStringUriOnly() == aliceAddr); - BC_ASSERT_TRUE(addresses.front().getDisplayName().empty()); - addresses.pop_front(); - - BC_ASSERT_TRUE(addresses.front().asStringUriOnly() == bobAddr); - BC_ASSERT_TRUE(addresses.front().getDisplayName() == bobName); - addresses.pop_front(); - - BC_ASSERT_TRUE(addresses.front().asStringUriOnly() == johnAddr); - BC_ASSERT_TRUE(addresses.front().getDisplayName().empty()); - addresses.pop_front(); - - BC_ASSERT_TRUE(addresses.front().asStringUriOnly() == anneAddr); - BC_ASSERT_TRUE(addresses.front().getDisplayName().empty()); - addresses.pop_front(); - - BC_ASSERT_TRUE(addresses.front().asStringUriOnly() == sarahAddr); - BC_ASSERT_TRUE(addresses.front().getDisplayName() == sarahName); - addresses.pop_front(); -} - -void first_invite_parsing () { - LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); - const Address marieIdentity(linphone_address_as_string_uri_only(marie->identity)); - check_first_invite(marie->lc, marieIdentity, firstInvite); - linphone_core_manager_destroy(marie); -} - -void first_invite_serializing() { - LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); - const Address marieIdentity(linphone_address_as_string_uri_only(marie->identity)); - RemoteConference remoteConf(marie->lc, marieIdentity); - list
      addresses = list
      (); - string xmlBody; - - Address aliceIdentity(aliceAddr); - Address bobIdentity(bobAddr); - Address johnIdentity(johnAddr); - Address anneIdentity(anneAddr); - Address sarahIdentity(sarahAddr); - - bobIdentity.setDisplayName(bobName); - sarahIdentity.setDisplayName(sarahName); - - addresses.push_back(aliceIdentity); - addresses.push_back(bobIdentity); - addresses.push_back(johnIdentity); - addresses.push_back(anneIdentity); - addresses.push_back(sarahIdentity); - - xmlBody = remoteConf.getResourceLists(addresses); - check_first_invite(marie->lc, marieIdentity, xmlBody); - linphone_core_manager_destroy(marie); -} - -test_t conference_tests[] = { - TEST_NO_TAG("First invite parsing", first_invite_parsing), - TEST_NO_TAG("First invite serializing", first_invite_serializing) -}; - -test_suite_t conference_test_suite = { - "Conference", - nullptr, - nullptr, - liblinphone_tester_before_each, - liblinphone_tester_after_each, - sizeof(conference_tests) / sizeof(conference_tests[0]), conference_tests -}; diff --git a/tester/tester.c b/tester/tester.c index 48708461e..38394a740 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -564,7 +564,6 @@ void liblinphone_tester_add_suites() { bc_tester_add_suite(&stun_test_suite); bc_tester_add_suite(&event_test_suite); bc_tester_add_suite(&conference_event_test_suite); - bc_tester_add_suite(&conference_test_suite); bc_tester_add_suite(&content_manager_test_suite); bc_tester_add_suite(&flexisip_test_suite); bc_tester_add_suite(&remote_provisioning_test_suite); From 7dd5d9671759d6c0345f86741e1c632684b07bf6 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 8 Nov 2017 15:37:01 +0100 Subject: [PATCH 0733/2215] Fixed text + file chat message test --- src/chat/chat-message/chat-message.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 2dd2266a9..7c296bb3c 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -719,7 +719,7 @@ void ChatMessagePrivate::processResponseFromPostFile (const belle_http_response_ first_part_header = "form-data; name=\"File\"; filename=\"filename.txt\""; } else { // temporary storage for the Content-disposition header value - first_part_header = "form-data; name=\"File\"; filename=\"" + currentFileContentToTransfer->getContentDisposition() + "\""; + first_part_header = "form-data; name=\"File\"; filename=\"" + currentFileContentToTransfer->getFileName() + "\""; } // create a user body handler to take care of the file and add the content disposition and content-type headers @@ -1650,6 +1650,11 @@ int ChatMessage::downloadFile(FileTransferContent *fileTransferContent) { return -1; } + // THIS IS ONLY FOR BACKWARD C API COMPAT + if (d->currentFileContentToTransfer->getFilePath().empty() && !getFileTransferFilepath().empty()) { + d->currentFileContentToTransfer->setFilePath(getFileTransferFilepath()); + } + belle_http_request_listener_callbacks_t cbs = { 0 }; cbs.process_response_headers = _chat_process_response_headers_from_get_file; cbs.process_response = _chat_message_process_response_from_get_file; From d9f022bb3f07b5a3dd64502db8e6e0155b2cae24 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 8 Nov 2017 15:37:12 +0100 Subject: [PATCH 0734/2215] feat(MainDb): getConferenceNotifiedEvents supports events cache --- src/db/main-db-p.h | 6 ++++++ src/db/main-db.cpp | 23 ++++++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index ba4a9c23c..290c0d42f 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -108,6 +108,12 @@ private: long long insertConferenceParticipantDeviceEvent (const std::shared_ptr &eventLog); long long insertConferenceSubjectEvent (const std::shared_ptr &eventLog); + // --------------------------------------------------------------------------- + // Cache API. + // --------------------------------------------------------------------------- + + std::shared_ptr getEventFromCache (long long eventId) const; + L_DECLARE_PUBLIC(MainDb); }; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 700cf46d6..a9d657136 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -536,6 +536,19 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return eventId; } +// ----------------------------------------------------------------------------- + + shared_ptr MainDbPrivate::getEventFromCache (long long eventId) const { + auto it = storageIdToEvent.find(eventId); + if (it == storageIdToEvent.cend()) + return nullptr; + + shared_ptr eventLog = it->second.lock(); + // Must exist. If not, implementation bug. + L_ASSERT(eventLog); + return eventLog; + } + // ----------------------------------------------------------------------------- void MainDb::init () { @@ -920,13 +933,17 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::transaction tr(*session); soci::rowset rows = (session->prepare << query, soci::use(peerAddress), soci::use(lastNotifyId)); - for (const auto &row : rows) - events.push_back(d->selectGenericConferenceEvent( - getBackend() == Sqlite3 ? static_cast(row.get(0)) : row.get(0), + for (const auto &row : rows) { + long long eventId = getBackend() == Sqlite3 ? static_cast(row.get(0)) : row.get(0); + shared_ptr eventLog = d->getEventFromCache(eventId); + + events.push_back(eventLog ? eventLog : d->selectGenericConferenceEvent( + eventId, static_cast(row.get(1)), Utils::getTmAsTimeT(row.get(2)), peerAddress )); + } L_END_LOG_EXCEPTION From 34ae5427ceb61fa504d4742fe5389fe362325b12 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 8 Nov 2017 15:49:50 +0100 Subject: [PATCH 0735/2215] Fixed crash in file transfer message tests --- src/chat/chat-message/chat-message.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 7c296bb3c..8b1d12e1d 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -1148,7 +1148,7 @@ void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml ( xmlFreeDoc(xmlMessageBody); fileContent->setFilePath(fileTransferContent->getFilePath()); // Copy file path from file transfer content to file content for file body handler - fileTransferContent->setFileUrl(string((const char *)file_url)); // Set file url in the file transfer content for the download + fileTransferContent->setFileUrl((const char *)file_url); // Set file url in the file transfer content for the download // Link the FileContent to the FileTransferContent fileTransferContent->setFileContent(fileContent); @@ -1189,7 +1189,15 @@ LinphoneReason ChatMessagePrivate::receive () { if (contents.size() == 0) { // All previous modifiers only altered the internal content, let's fill the content list - contents.push_back(&internalContent); + // But first check if content type is file transfer + if (internalContent.getContentType() == ContentType::FileTransfer) { + FileTransferContent *content = new FileTransferContent(); + content->setContentType(internalContent.getContentType()); + content->setBody(internalContent.getBody()); + contents.push_back(content); + } else { + contents.push_back(&internalContent); + } } // --------------------------------------- From f5fa5101fc85f9fcf4987b4bd9b477201dd9158d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 8 Nov 2017 16:14:45 +0100 Subject: [PATCH 0736/2215] Improved two file transfer test --- tester/multipart-tester.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tester/multipart-tester.cpp b/tester/multipart-tester.cpp index 8430fe372..3bce05fc3 100644 --- a/tester/multipart-tester.cpp +++ b/tester/multipart-tester.cpp @@ -44,40 +44,40 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer, bool shared_ptr marieMessage; if (first_file_transfer) { + char *send_filepath = bc_tester_res("sounds/sintel_trailer_opus_h264.mkv"); LinphoneContent *content = linphone_core_create_content(marie->lc); belle_sip_object_set_name(BELLE_SIP_OBJECT(content), "sintel trailer content"); linphone_content_set_type(content,"video"); linphone_content_set_subtype(content,"mkv"); linphone_content_set_name(content,"sintel_trailer_opus_h264.mkv"); marieMessage = marieRoom->createFileTransferMessage(content); + marieMessage->setFileTransferFilepath(send_filepath); + bc_free(send_filepath); } else { marieMessage = marieRoom->createMessage("Hello Part 1"); } if (second_file_transfer) { - LinphoneContent *initialContent = linphone_core_create_content(marie->lc); - belle_sip_object_set_name(BELLE_SIP_OBJECT(initialContent), "sintel trailer content"); - linphone_content_set_type(initialContent,"video"); - linphone_content_set_subtype(initialContent,"mkv"); - linphone_content_set_name(initialContent,"sintel_trailer_opus_h264.mkv"); - + char *send_filepath = bc_tester_res("vcards/vcards.vcf"); FileContent *content = new FileContent(); - content->setContentType(ContentType::FileTransfer); - content->setBody(linphone_content_get_string_buffer(initialContent)); + content->setContentType("file/vcf"); + content->setFilePath(send_filepath); + content->setFileName("vcards.vcf"); marieMessage->addContent(content); + bc_free(send_filepath); } else { Content *content = new Content(); content->setContentType(ContentType::PlainText); content->setBody("Hello Part 2"); marieMessage->addContent(content); } + + linphone_core_set_file_transfer_server(marie->lc,"https://www.linphone.org:444/lft.php"); marieMessage->send(); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageReceived,1)); - BC_ASSERT_STRING_EQUAL(marieMessage->getInternalContent().getContentType().asString().c_str(), "multipart/mixed"); - BC_ASSERT_PTR_NOT_NULL(pauline->stat.last_received_chat_message); - //TODO + BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_content_type(pauline->stat.last_received_chat_message), "multipart/mixed"); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); From fc2fe482ecf2b7330212d45f54b06506748ded8c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 8 Nov 2017 16:36:46 +0100 Subject: [PATCH 0737/2215] Created a FileTransferChatMessageModifier, next step is to move into it file transfer related code from ChatMessage --- src/CMakeLists.txt | 2 + src/chat/chat-message/chat-message-p.h | 1 + src/chat/chat-message/chat-message.cpp | 12 +++++ .../file-transfer-chat-message-modifier.cpp | 46 +++++++++++++++++++ .../file-transfer-chat-message-modifier.h | 42 +++++++++++++++++ 5 files changed, 103 insertions(+) create mode 100644 src/chat/modifier/file-transfer-chat-message-modifier.cpp create mode 100644 src/chat/modifier/file-transfer-chat-message-modifier.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 899677ab1..f633fc847 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,6 +54,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES chat/modifier/chat-message-modifier.h chat/modifier/cpim-chat-message-modifier.h chat/modifier/encryption-chat-message-modifier.h + chat/modifier/file-transfer-chat-message-modifier.h chat/modifier/multipart-chat-message-modifier.h chat/notification/imdn.h chat/notification/is-composing-listener.h @@ -170,6 +171,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES chat/cpim/parser/cpim-parser.cpp chat/modifier/cpim-chat-message-modifier.cpp chat/modifier/encryption-chat-message-modifier.cpp + chat/modifier/file-transfer-chat-message-modifier.cpp chat/modifier/multipart-chat-message-modifier.cpp chat/notification/imdn.cpp chat/notification/is-composing.cpp diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index 6eeca943c..f5ed8b223 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -39,6 +39,7 @@ class ChatMessagePrivate : public ObjectPrivate { friend class CpimChatMessageModifier; friend class EncryptionChatMessageModifier; friend class MultipartChatMessageModifier; + friend class FileTransferChatMessageModifier; public: enum Step { diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 8b1d12e1d..0fb01f56e 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -30,6 +30,7 @@ #include "chat/chat-room/real-time-text-chat-room.h" #include "chat/modifier/cpim-chat-message-modifier.h" #include "chat/modifier/encryption-chat-message-modifier.h" +#include "chat/modifier/file-transfer-chat-message-modifier.h" #include "chat/modifier/multipart-chat-message-modifier.h" #include "content/file-content.h" #include "content/content.h" @@ -1256,6 +1257,17 @@ void ChatMessagePrivate::send () { if ((currentSendStep & ChatMessagePrivate::Step::FileUpload) == ChatMessagePrivate::Step::FileUpload) { lInfo() << "File upload step already done, skipping"; } else { + // TODO + /*FileTransferChatMessageModifier ftcmm; + ChatMessageModifier::Result result = ftcmm.encode(q->getSharedFromThis(), errorCode); + if (result == ChatMessageModifier::Result::Error) { + return; + } else if (result == ChatMessageModifier::Result::Suspended) { + setState(ChatMessage::State::InProgress); + return; + } + currentSendStep |= ChatMessagePrivate::Step::FileUpload;*/ + currentFileContentToTransfer = nullptr; // For each FileContent, upload it and create a FileTransferContent for (Content *content : contents) { diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.cpp b/src/chat/modifier/file-transfer-chat-message-modifier.cpp new file mode 100644 index 000000000..e193b376c --- /dev/null +++ b/src/chat/modifier/file-transfer-chat-message-modifier.cpp @@ -0,0 +1,46 @@ +/* + * file-transfer-chat-message-modifier.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "address/address.h" +#include "chat/chat-message/chat-message-p.h" +#include "content/content-type.h" +#include "content/content.h" +#include "logger/logger.h" + +#include "file-transfer-chat-message-modifier.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +ChatMessageModifier::Result FileTransferMessageModifier::encode (const shared_ptr &message, int &errorCode) { + chatMessage = message; + + return ChatMessageModifier::Result::Done; +} + +ChatMessageModifier::Result FileTransferMessageModifier::decode (const shared_ptr &message, int &errorCode) { + chatMessage = message; + + return ChatMessageModifier::Result::Done; +} + +LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.h b/src/chat/modifier/file-transfer-chat-message-modifier.h new file mode 100644 index 000000000..a03ceba31 --- /dev/null +++ b/src/chat/modifier/file-transfer-chat-message-modifier.h @@ -0,0 +1,42 @@ +/* + * file-transfer-chat-message-modifier.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _FILE_TRANSFER_CHAT_MESSAGE_MODIFIER_H_ +#define _FILE_TRANSFER_CHAT_MESSAGE_MODIFIER_H_ + +#include "chat-message-modifier.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class FileTransferMessageModifier : public ChatMessageModifier { +public: + FileTransferMessageModifier () = default; + + Result encode (const std::shared_ptr &message, int &errorCode) override; + Result decode (const std::shared_ptr &message, int &errorCode) override; + +private: + std::shared_ptr chatMessage; +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _FILE_TRANSFER_CHAT_MESSAGE_MODIFIER_H_ From ad896ab4f83c8681d31a0268fe9398ffd1e5495e Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 8 Nov 2017 17:05:19 +0100 Subject: [PATCH 0738/2215] feat(MainDb): create a new table: chat_message_file_content --- src/db/main-db.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index a9d657136..b146db248 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -734,6 +734,19 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " ON DELETE CASCADE" ")"; + *session << + "CREATE TABLE IF NOT EXISTS chat_message_file_content (" + " chat_message_content_id" + primaryKeyStr("BIGINT UNSIGNED") + "," + + " name VARCHAR(256) NOT NULL," + " size INT UNSIGNED NOT NULL," + " path VARCHAR(512) NOT NULL," + + " FOREIGN KEY (chat_message_content_id)" + " REFERENCES chat_message_content(id)" + " ON DELETE CASCADE" + ")"; + *session << "CREATE TABLE IF NOT EXISTS chat_message_content_app_data (" " chat_message_content_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," From cc5ebffda436dca94403b0534fafaa266a9c1fb5 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 8 Nov 2017 17:12:00 +0100 Subject: [PATCH 0739/2215] Add linphone_chat_room_get_me() API. --- include/linphone/api/c-chat-room.h | 8 ++++++++ src/c-wrapper/api/c-chat-room.cpp | 4 ++++ src/chat/chat-room/basic-chat-room.cpp | 5 +++++ src/chat/chat-room/basic-chat-room.h | 1 + src/chat/chat-room/client-group-chat-room.cpp | 4 ++++ src/chat/chat-room/client-group-chat-room.h | 1 + src/chat/chat-room/real-time-text-chat-room.cpp | 5 +++++ src/chat/chat-room/real-time-text-chat-room.h | 1 + src/conference/conference-interface.h | 1 + src/conference/conference.cpp | 10 +++++----- src/conference/conference.h | 2 +- 11 files changed, 36 insertions(+), 6 deletions(-) diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index a190ac8be..61650f833 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -284,6 +284,7 @@ LINPHONE_PUBLIC bool_t linphone_chat_room_can_handle_participants (const Linphon * Find a participant of a chat room from its address. * @param[in] cr A LinphoneChatRoom object * @param[in] addr The address to search in the list of participants of the chat room + * @return The participant if found, NULL otherwise. */ LINPHONE_PUBLIC LinphoneParticipant *linphone_chat_room_find_participant (const LinphoneChatRoom *cr, const LinphoneAddress *addr); @@ -294,6 +295,13 @@ LINPHONE_PUBLIC LinphoneParticipant *linphone_chat_room_find_participant (const */ LINPHONE_PUBLIC const LinphoneAddress *linphone_chat_room_get_conference_address (const LinphoneChatRoom *cr); +/** + * Get the participant representing myself in the chat room. + * @param[in] cr A LinphoneChatRoom object + * @return The participant representing myself in the conference. + */ +LINPHONE_PUBLIC LinphoneParticipant *linphone_chat_room_get_me (const LinphoneChatRoom *cr); + /** * Get the number of participants in the chat room (that is without ourselves). * @param[in] cr A LinphoneChatRoom object diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 0717bee48..ef3aa923f 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -266,6 +266,10 @@ const LinphoneAddress *linphone_chat_room_get_conference_address (const Linphone return cr->conferenceAddressCache; } +LinphoneParticipant *linphone_chat_room_get_me (const LinphoneChatRoom *cr) { + return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getMe()); +} + int linphone_chat_room_get_nb_participants (const LinphoneChatRoom *cr) { return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getNbParticipants(); } diff --git a/src/chat/chat-room/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp index 4d9d9e470..c67a830d2 100644 --- a/src/chat/chat-room/basic-chat-room.cpp +++ b/src/chat/chat-room/basic-chat-room.cpp @@ -64,6 +64,11 @@ const Address &BasicChatRoom::getConferenceAddress () const { return Utils::getEmptyConstRefObject
      (); } +shared_ptr BasicChatRoom::getMe () const { + lError() << "a BasicChatRoom does not handle participants"; + return nullptr; +} + int BasicChatRoom::getNbParticipants () const { return 1; } diff --git a/src/chat/chat-room/basic-chat-room.h b/src/chat/chat-room/basic-chat-room.h index 402ce990f..d4dc2e948 100644 --- a/src/chat/chat-room/basic-chat-room.h +++ b/src/chat/chat-room/basic-chat-room.h @@ -41,6 +41,7 @@ public: bool canHandleParticipants () const override; std::shared_ptr findParticipant (const Address &addr) const override; const Address &getConferenceAddress () const override; + std::shared_ptr getMe () const override; int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 8b25a87e4..d04aedf98 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -145,6 +145,10 @@ const Address &ClientGroupChatRoom::getConferenceAddress () const { return RemoteConference::getConferenceAddress(); } +shared_ptr ClientGroupChatRoom::getMe () const { + return RemoteConference::getMe(); +} + int ClientGroupChatRoom::getNbParticipants () const { return RemoteConference::getNbParticipants(); } diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 9d1614ccf..8b4ae10c0 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -47,6 +47,7 @@ public: bool canHandleParticipants () const override; std::shared_ptr findParticipant (const Address &addr) const override; const Address &getConferenceAddress () const override; + std::shared_ptr getMe () const override; int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; diff --git a/src/chat/chat-room/real-time-text-chat-room.cpp b/src/chat/chat-room/real-time-text-chat-room.cpp index 2242cdd3c..6c872b9eb 100644 --- a/src/chat/chat-room/real-time-text-chat-room.cpp +++ b/src/chat/chat-room/real-time-text-chat-room.cpp @@ -164,6 +164,11 @@ const Address &RealTimeTextChatRoom::getConferenceAddress () const { return Utils::getEmptyConstRefObject
      (); } +shared_ptr RealTimeTextChatRoom::getMe () const { + lError() << "a RealTimeTextChatRoom does not handle participants"; + return nullptr; +} + int RealTimeTextChatRoom::getNbParticipants () const { return 1; } diff --git a/src/chat/chat-room/real-time-text-chat-room.h b/src/chat/chat-room/real-time-text-chat-room.h index 31a24b166..71ffc59ae 100644 --- a/src/chat/chat-room/real-time-text-chat-room.h +++ b/src/chat/chat-room/real-time-text-chat-room.h @@ -47,6 +47,7 @@ public: bool canHandleParticipants () const override; std::shared_ptr findParticipant (const Address &addr) const override; const Address &getConferenceAddress () const override; + std::shared_ptr getMe () const override; int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index 42bdca4e2..104d7dbbc 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -42,6 +42,7 @@ public: virtual bool canHandleParticipants () const = 0; virtual std::shared_ptr findParticipant (const Address &addr) const = 0; virtual const Address &getConferenceAddress () const = 0; + virtual std::shared_ptr getMe () const = 0; virtual int getNbParticipants () const = 0; virtual std::list> getParticipants () const = 0; virtual const std::string &getSubject () const = 0; diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 1ad341793..3cbc5c93b 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -48,11 +48,6 @@ shared_ptr Conference::getActiveParticipant () const { return d->activeParticipant; } -shared_ptr Conference::getMe () const { - L_D(); - return d->me; -} - LinphoneCore *Conference::getCore () const { L_D(); return d->core; @@ -84,6 +79,11 @@ const Address &Conference::getConferenceAddress () const { return d->conferenceAddress; } +shared_ptr Conference::getMe () const { + L_D(); + return d->me; +} + int Conference::getNbParticipants () const { L_D(); return static_cast(d->participants.size()); diff --git a/src/conference/conference.h b/src/conference/conference.h index b89117c25..6bd9eb783 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -40,7 +40,6 @@ public: virtual ~Conference(); std::shared_ptr getActiveParticipant () const; - std::shared_ptr getMe () const; LinphoneCore * getCore () const; @@ -52,6 +51,7 @@ public: bool canHandleParticipants () const override; std::shared_ptr findParticipant (const Address &addr) const override; const Address &getConferenceAddress () const override; + std::shared_ptr getMe () const override; int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; From 2e2c39b7bc7d276f6ce0967135fa41ee33d71c6e Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 8 Nov 2017 17:14:23 +0100 Subject: [PATCH 0740/2215] feat(MainDb): getHistoryRange supports events cache --- src/db/main-db.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index b146db248..79a6a211d 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1125,12 +1125,16 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), // See: http://soci.sourceforge.net/doc/master/backends/ // `row id` is not supported by soci on Sqlite3. It's necessary to cast id to int... long long eventId = getBackend() == Sqlite3 ? static_cast(row.get(0)) : row.get(0); - shared_ptr event = d->selectGenericConferenceEvent( - eventId, - static_cast(row.get(1)), - Utils::getTmAsTimeT(row.get(2)), - peerAddress - ); + shared_ptr event = d->getEventFromCache(eventId); + + if (!event) + event = d->selectGenericConferenceEvent( + eventId, + static_cast(row.get(1)), + Utils::getTmAsTimeT(row.get(2)), + peerAddress + ); + if (event) events.push_back(event); else From 5c857c2db1d466824f7d1357fdf3177691703fdd Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 8 Nov 2017 17:16:52 +0100 Subject: [PATCH 0741/2215] Fix build. --- src/chat/chat-room/server-group-chat-room-stub.cpp | 4 ++++ src/chat/chat-room/server-group-chat-room.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index 306051cd5..35493ede0 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -101,6 +101,10 @@ const Address &ServerGroupChatRoom::getConferenceAddress () const { return LocalConference::getConferenceAddress(); } +shared_ptr ServerGroupChatRoom::getMe () const { + return nullptr; +} + int ServerGroupChatRoom::getNbParticipants () const { return 0; } diff --git a/src/chat/chat-room/server-group-chat-room.h b/src/chat/chat-room/server-group-chat-room.h index 7f1c54eea..fc2c21918 100644 --- a/src/chat/chat-room/server-group-chat-room.h +++ b/src/chat/chat-room/server-group-chat-room.h @@ -46,6 +46,7 @@ public: bool canHandleParticipants () const override; std::shared_ptr findParticipant (const Address &addr) const override; const Address &getConferenceAddress () const override; + std::shared_ptr getMe () const override; int getNbParticipants () const override; std::list> getParticipants () const override; const std::string &getSubject () const override; From 987fca949969c1e762f9c8f14b383a6c0ff6b606 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 8 Nov 2017 17:51:38 +0100 Subject: [PATCH 0742/2215] fix(ChatRoom): mark as read correctly chat message --- src/chat/chat-room/chat-room.cpp | 7 ++++++- src/chat/chat-room/real-time-text-chat-room.cpp | 9 --------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index eeddb572b..c8b2f51a6 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -228,7 +228,7 @@ void ChatRoomPrivate::storeOrUpdateMessage (const shared_ptr &msg) void ChatRoomPrivate::sendMessage (const shared_ptr &msg) { L_Q(); - + msg->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); /* Add to transient list */ @@ -556,6 +556,11 @@ void ChatRoom::markAsRead () { chatMessage->sendDisplayNotification(); dCore->mainDb->markChatMessagesAsRead(peerAddress); + + if (d->pendingMessage) { + d->pendingMessage->updateState(ChatMessage::State::Displayed); + d->pendingMessage->sendDisplayNotification(); + } } // ----------------------------------------------------------------------------- diff --git a/src/chat/chat-room/real-time-text-chat-room.cpp b/src/chat/chat-room/real-time-text-chat-room.cpp index 6c872b9eb..fa7acf95f 100644 --- a/src/chat/chat-room/real-time-text-chat-room.cpp +++ b/src/chat/chat-room/real-time-text-chat-room.cpp @@ -129,15 +129,6 @@ LinphoneCall *RealTimeTextChatRoom::getCall () const { return d->call; } -void RealTimeTextChatRoom::markAsRead () { - L_D(); - ChatRoom::markAsRead(); - if (d->pendingMessage) { - d->pendingMessage->updateState(ChatMessage::State::Displayed); - d->pendingMessage->sendDisplayNotification(); - } -} - // ----------------------------------------------------------------------------- void RealTimeTextChatRoom::onChatMessageReceived(const shared_ptr &msg) {} From f6c4f0f5d9caa943ea0e5faa24b5c709e43fad96 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 8 Nov 2017 17:53:22 +0100 Subject: [PATCH 0743/2215] Started to move file transfer related code in ChatMessage into FileTransferChatMessageModifier --- src/chat/chat-message/chat-message-p.h | 3 +- src/chat/chat-message/chat-message.cpp | 30 +- src/chat/chat-message/chat-message.h | 1 + src/chat/chat-room/chat-room.h | 1 + .../file-transfer-chat-message-modifier.cpp | 494 +++++++++++++++++- .../file-transfer-chat-message-modifier.h | 27 +- 6 files changed, 521 insertions(+), 35 deletions(-) diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index f5ed8b223..e2127c01d 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -27,6 +27,7 @@ #include "content/content.h" #include "content/file-content.h" #include "content/file-transfer-content.h" +#include "chat/modifier/file-transfer-chat-message-modifier.h" #include "content/content-type.h" #include "object/object-p.h" #include "sal/sal.h" @@ -39,7 +40,6 @@ class ChatMessagePrivate : public ObjectPrivate { friend class CpimChatMessageModifier; friend class EncryptionChatMessageModifier; friend class MultipartChatMessageModifier; - friend class FileTransferChatMessageModifier; public: enum Step { @@ -153,6 +153,7 @@ private: unsigned long backgroundTaskId = 0; unsigned char currentSendStep = Step::None; bool applyModifiers = true; + FileTransferChatMessageModifier fileTransferChatMessageModifier; // Cache for returned values, used for compatibility with previous C API ContentType cContentType; std::string cText; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 0fb01f56e..e5cc4a201 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -1257,40 +1257,14 @@ void ChatMessagePrivate::send () { if ((currentSendStep & ChatMessagePrivate::Step::FileUpload) == ChatMessagePrivate::Step::FileUpload) { lInfo() << "File upload step already done, skipping"; } else { - // TODO - /*FileTransferChatMessageModifier ftcmm; - ChatMessageModifier::Result result = ftcmm.encode(q->getSharedFromThis(), errorCode); + ChatMessageModifier::Result result = fileTransferChatMessageModifier.encode(q->getSharedFromThis(), errorCode); if (result == ChatMessageModifier::Result::Error) { + setState(ChatMessage::State::NotDelivered); return; } else if (result == ChatMessageModifier::Result::Suspended) { setState(ChatMessage::State::InProgress); return; } - currentSendStep |= ChatMessagePrivate::Step::FileUpload;*/ - - currentFileContentToTransfer = nullptr; - // For each FileContent, upload it and create a FileTransferContent - for (Content *content : contents) { - ContentType contentType = content->getContentType(); - //TODO Improve - if (contentType != ContentType::FileTransfer && contentType != ContentType::PlainText && - contentType != ContentType::ExternalBody && contentType != ContentType::Imdn && - contentType != ContentType::ImIsComposing && contentType != ContentType::ResourceLists && - contentType != ContentType::Sdp && contentType != ContentType::ConferenceInfo && - contentType != ContentType::Cpim) { - lInfo() << "Found content with type " << contentType.asString() << ", set it for file upload"; - FileContent *fileContent = (FileContent *)content; - currentFileContentToTransfer = fileContent; - break; - } - } - if (currentFileContentToTransfer != nullptr) { - /* Open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */ - if (uploadFile() == 0) { - setState(ChatMessage::State::InProgress); - } - return; - } currentSendStep |= ChatMessagePrivate::Step::FileUpload; } diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index f6f67e917..c17cb4a64 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -42,6 +42,7 @@ class LINPHONE_PUBLIC ChatMessage : public Object, public CoreAccessor { friend class ChatRoom; friend class ChatRoomPrivate; friend class CpimChatMessageModifier; + friend class FileTransferChatMessageModifier; friend class MainDbPrivate; friend class RealTimeTextChatRoomPrivate; friend class ServerGroupChatRoomPrivate; diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index db5c1d4c8..12a3259bd 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -35,6 +35,7 @@ class LINPHONE_PUBLIC ChatRoom : public Object, public CoreAccessor, public Conf friend class CorePrivate; friend class ChatMessage; friend class ChatMessagePrivate; + friend class FileTransferChatMessageModifier; public: L_OVERRIDE_SHARED_FROM_THIS(ChatRoom); diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.cpp b/src/chat/modifier/file-transfer-chat-message-modifier.cpp index e193b376c..b3e12826e 100644 --- a/src/chat/modifier/file-transfer-chat-message-modifier.cpp +++ b/src/chat/modifier/file-transfer-chat-message-modifier.cpp @@ -17,10 +17,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "c-wrapper/c-wrapper.h" #include "address/address.h" #include "chat/chat-message/chat-message-p.h" #include "content/content-type.h" #include "content/content.h" +#include "chat/chat-room/chat-room-p.h" +#include "core/core.h" #include "logger/logger.h" #include "file-transfer-chat-message-modifier.h" @@ -31,16 +34,499 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ChatMessageModifier::Result FileTransferMessageModifier::encode (const shared_ptr &message, int &errorCode) { +ChatMessageModifier::Result FileTransferChatMessageModifier::encode (const shared_ptr &message, int &errorCode) { + chatMessage = message; + + currentFileContentToTransfer = nullptr; + // For each FileContent, upload it and create a FileTransferContent + for (Content *content : chatMessage->getContents()) { + ContentType contentType = content->getContentType(); + //TODO Improve + if (contentType != ContentType::FileTransfer && contentType != ContentType::PlainText && + contentType != ContentType::ExternalBody && contentType != ContentType::Imdn && + contentType != ContentType::ImIsComposing && contentType != ContentType::ResourceLists && + contentType != ContentType::Sdp && contentType != ContentType::ConferenceInfo && + contentType != ContentType::Cpim) { + lInfo() << "Found content with type " << contentType.asString() << ", set it for file upload"; + FileContent *fileContent = (FileContent *)content; + currentFileContentToTransfer = fileContent; + break; + } + } + if (currentFileContentToTransfer != nullptr) { + /* Open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */ + if (uploadFile() == 0) { + return ChatMessageModifier::Result::Suspended; + } + return ChatMessageModifier::Result::Error; + } + + return ChatMessageModifier::Result::Skipped; +} + +// ---------------------------------------------------------- + +static void _chat_message_file_transfer_on_progress ( + belle_sip_body_handler_t *bh, + belle_sip_message_t *m, + void *data, + size_t offset, + size_t total +) { + FileTransferChatMessageModifier *d = (FileTransferChatMessageModifier *)data; + d->fileTransferOnProgress(bh, m, offset, total); +} + +void FileTransferChatMessageModifier::fileTransferOnProgress ( + belle_sip_body_handler_t *bh, + belle_sip_message_t *m, + size_t offset, + size_t total +) { + if (!isFileTransferInProgressAndValid()) { + /*lWarning() << "Cancelled request for " << (chatRoom->lock() ? "" : "ORPHAN") << " msg [" << this << + "], ignoring " << __FUNCTION__;*/ + releaseHttpRequest(); + return; + } + + LinphoneChatMessage *msg = L_GET_C_BACK_PTR(chatMessage); + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); + LinphoneContent *content = currentFileContentToTransfer->toLinphoneContent(); + if (linphone_chat_message_cbs_get_file_transfer_progress_indication(cbs)) { + linphone_chat_message_cbs_get_file_transfer_progress_indication(cbs)(msg, content, offset, total); + } else { + // Legacy: call back given by application level. + shared_ptr core = chatMessage->getCore(); + if (core) + linphone_core_notify_file_transfer_progress_indication( + core->getCCore(), + msg, + content, + offset, + total + ); + } + linphone_content_unref(content); +} + +static int _chat_message_on_send_body ( + belle_sip_user_body_handler_t *bh, + belle_sip_message_t *m, + void *data, + size_t offset, + uint8_t *buffer, + size_t *size +) { + FileTransferChatMessageModifier *d = (FileTransferChatMessageModifier *)data; + return d->onSendBody(bh, m, offset, buffer, size); +} + +int FileTransferChatMessageModifier::onSendBody ( + belle_sip_user_body_handler_t *bh, + belle_sip_message_t *m, + size_t offset, + uint8_t *buffer, + size_t *size +) { + int retval = -1; + LinphoneChatMessage *msg = L_GET_C_BACK_PTR(chatMessage); + + if (!isFileTransferInProgressAndValid()) { + if (httpRequest) { + /*lWarning() << "Cancelled request for " << (chatRoom->lock() ? "" : "ORPHAN") << + " msg [" << this << "], ignoring " << __FUNCTION__;*/ + releaseHttpRequest(); + } + return BELLE_SIP_STOP; + } + + // if we've not reach the end of file yet, ask for more data + // in case of file body handler, won't be called + if (currentFileContentToTransfer->getFilePath().empty() && offset < currentFileContentToTransfer->getFileSize()) { + // get data from call back + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); + LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = + linphone_chat_message_cbs_get_file_transfer_send(cbs); + LinphoneContent *content = currentFileContentToTransfer->toLinphoneContent(); + if (file_transfer_send_cb) { + LinphoneBuffer *lb = file_transfer_send_cb(msg, content, offset, *size); + if (lb == nullptr) { + *size = 0; + } else { + *size = linphone_buffer_get_size(lb); + memcpy(buffer, linphone_buffer_get_content(lb), *size); + linphone_buffer_unref(lb); + } + } else { + // Legacy + shared_ptr core = chatMessage->getCore(); + if (core) + linphone_core_notify_file_transfer_send(core->getCCore(), msg, content, (char *)buffer, size); + } + linphone_content_unref(content); + } + + LinphoneImEncryptionEngine *imee = nullptr; + shared_ptr core = chatMessage->getCore(); + if (core) + imee = linphone_core_get_im_encryption_engine(core->getCCore()); + + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = + linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); + if (cb_process_uploading_file) { + size_t max_size = *size; + uint8_t *encrypted_buffer = (uint8_t *)ms_malloc0(max_size); + retval = cb_process_uploading_file(imee, msg, offset, (const uint8_t *)buffer, size, encrypted_buffer); + if (retval == 0) { + if (*size > max_size) { + lError() << "IM encryption engine process upload file callback returned a size bigger than the size of the buffer, so it will be truncated !"; + *size = max_size; + } + memcpy(buffer, encrypted_buffer, *size); + } + ms_free(encrypted_buffer); + } + } + + return retval <= 0 ? BELLE_SIP_CONTINUE : BELLE_SIP_STOP; +} + +static void _chat_message_on_send_end (belle_sip_user_body_handler_t *bh, void *data) { + FileTransferChatMessageModifier *d = (FileTransferChatMessageModifier *)data; + d->onSendEnd(bh); +} + +void FileTransferChatMessageModifier::onSendEnd (belle_sip_user_body_handler_t *bh) { + LinphoneImEncryptionEngine *imee = nullptr; + shared_ptr core = chatMessage->getCore(); + if (core) + imee = linphone_core_get_im_encryption_engine(core->getCCore()); + + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); + if (cb_process_uploading_file) { + cb_process_uploading_file(imee, L_GET_C_BACK_PTR(chatMessage), 0, nullptr, nullptr, nullptr); + } + } +} + +static void _chat_message_process_response_from_post_file (void *data, const belle_http_response_event_t *event) { + FileTransferChatMessageModifier *d = (FileTransferChatMessageModifier *)data; + d->processResponseFromPostFile(event); +} + +void FileTransferChatMessageModifier::processResponseFromPostFile (const belle_http_response_event_t *event) { + if (httpRequest && !isFileTransferInProgressAndValid()) { + /*lWarning() << "Cancelled request for " << (chatRoom->lock() ? "" : "ORPHAN") << + " msg [" << this << "], ignoring " << __FUNCTION__;*/ + releaseHttpRequest(); + return; + } + + // check the answer code + if (event->response) { + int code = belle_http_response_get_status_code(event->response); + if (code == 204) { // this is the reply to the first post to the server - an empty msg + // start uploading the file + belle_sip_multipart_body_handler_t *bh; + string first_part_header; + belle_sip_body_handler_t *first_part_bh; + + bool_t is_file_encryption_enabled = FALSE; + LinphoneImEncryptionEngine *imee = nullptr; + + shared_ptr core = chatMessage->getCore(); + + imee = linphone_core_get_im_encryption_engine(core->getCCore()); + + if (imee && chatRoom) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer_cb = + linphone_im_encryption_engine_cbs_get_is_encryption_enabled_for_file_transfer(imee_cbs); + if (is_encryption_enabled_for_file_transfer_cb) { + is_file_encryption_enabled = is_encryption_enabled_for_file_transfer_cb(imee, L_GET_C_BACK_PTR(chatRoom)); + } + } + // shall we encrypt the file + if (is_file_encryption_enabled && chatRoom) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb generate_file_transfer_key_cb = + linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(imee_cbs); + if (generate_file_transfer_key_cb) { + generate_file_transfer_key_cb(imee, L_GET_C_BACK_PTR(chatRoom), L_GET_C_BACK_PTR(chatMessage)); + } + // temporary storage for the Content-disposition header value : use a generic filename to not leak it + // Actual filename stored in msg->file_transfer_information->name will be set in encrypted msg + // sended to the + first_part_header = "form-data; name=\"File\"; filename=\"filename.txt\""; + } else { + // temporary storage for the Content-disposition header value + first_part_header = "form-data; name=\"File\"; filename=\"" + currentFileContentToTransfer->getFileName() + "\""; + } + + // create a user body handler to take care of the file and add the content disposition and content-type headers + first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(currentFileContentToTransfer->getFileSize(), + _chat_message_file_transfer_on_progress, nullptr, nullptr, + _chat_message_on_send_body, _chat_message_on_send_end, this); + if (!currentFileContentToTransfer->getFilePath().empty()) { + belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh; + // No need to add again the callback for progression, otherwise it will be called twice + first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(currentFileContentToTransfer->getFilePath().c_str(), nullptr, this); + //linphone_content_set_size(cFileTransferInformation, belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh)); + belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)first_part_bh, body_handler); + } else if (!currentFileContentToTransfer->isEmpty()) { + first_part_bh = (belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer( + ms_strdup(currentFileContentToTransfer->getBodyAsString().c_str()), + currentFileContentToTransfer->getSize(), _chat_message_file_transfer_on_progress, this); + } + + belle_sip_body_handler_add_header(first_part_bh, + belle_sip_header_create("Content-disposition", first_part_header.c_str())); + belle_sip_body_handler_add_header(first_part_bh, + (belle_sip_header_t *)belle_sip_header_content_type_create( + currentFileContentToTransfer->getContentType().getType().c_str(), + currentFileContentToTransfer->getContentType().getSubType().c_str())); + + // insert it in a multipart body handler which will manage the boundaries of multipart msg + bh = belle_sip_multipart_body_handler_new(_chat_message_file_transfer_on_progress, this, first_part_bh, nullptr); + + releaseHttpRequest(); + fileUploadBeginBackgroundTask(); + uploadFile(); + belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(httpRequest), BELLE_SIP_BODY_HANDLER(bh)); + } else if (code == 200) { // file has been uploaded correctly, get server reply and send it + const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); + if (body && strlen(body) > 0) { + //TODO + // if we have an encryption key for the file, we must insert it into the msg and restore the correct filename + /*const char *content_key = linphone_content_get_key(cFileTransferInformation); + size_t content_key_size = linphone_content_get_key_size(cFileTransferInformation); + if (content_key != nullptr) { + // parse the msg body + xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body); + + xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody); + if (cur != nullptr) { + cur = cur->xmlChildrenNode; + while (cur != nullptr) { + // we found a file info node, check it has a type="file" attribute + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { + xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); + // this is the node we are looking for : add a file-key children node + if (!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { + // need to parse the children node to update the file-name one + xmlNodePtr fileInfoNodeChildren = cur->xmlChildrenNode; + // convert key to base64 + size_t b64Size = b64_encode(nullptr, content_key_size, nullptr, 0); + char *keyb64 = (char *)ms_malloc0(b64Size + 1); + int xmlStringLength; + + b64Size = b64_encode(content_key, content_key_size, keyb64, b64Size); + keyb64[b64Size] = '\0'; // libxml need a null terminated string + + // add the node containing the key to the file-info node + xmlNewTextChild(cur, nullptr, (const xmlChar *)"file-key", (const xmlChar *)keyb64); + xmlFree(typeAttribute); + ms_free(keyb64); + + // look for the file-name node and update its content + while (fileInfoNodeChildren != nullptr) { + // we found a the file-name node, update its content with the real filename + if (!xmlStrcmp(fileInfoNodeChildren->name, (const xmlChar *)"file-name")) { + // update node content + xmlNodeSetContent(fileInfoNodeChildren, (const xmlChar *)(linphone_content_get_name(cFileTransferInformation))); + break; + } + fileInfoNodeChildren = fileInfoNodeChildren->next; + } + + // dump the xml into msg->message + char *buffer; + xmlDocDumpFormatMemoryEnc(xmlMessageBody, (xmlChar **)&buffer, &xmlStringLength, "UTF-8", 0); + setText(buffer); + break; + } + xmlFree(typeAttribute); + } + cur = cur->next; + } + } + xmlFreeDoc(xmlMessageBody); + } else { // no encryption key, transfer in plain, just copy the msg sent by server + setText(body); + } + setContentType(ContentType::FileTransfer);*/ + FileContent *fileContent = currentFileContentToTransfer; + + FileTransferContent *fileTransferContent = new FileTransferContent(); + fileTransferContent->setContentType(ContentType::FileTransfer); + fileTransferContent->setFileContent(fileContent); + fileTransferContent->setBody(body); + + chatMessage->removeContent(fileContent); + chatMessage->addContent(fileTransferContent); + + chatMessage->updateState(ChatMessage::State::FileTransferDone); + releaseHttpRequest(); + chatMessage->getPrivate()->send(); + fileUploadEndBackgroundTask(); + } else { + lWarning() << "Received empty response from server, file transfer failed"; + chatMessage->updateState(ChatMessage::State::NotDelivered); + releaseHttpRequest(); + fileUploadEndBackgroundTask(); + } + } else { + lWarning() << "Unhandled HTTP code response " << code << " for file transfer"; + chatMessage->updateState(ChatMessage::State::NotDelivered); + releaseHttpRequest(); + fileUploadEndBackgroundTask(); + } + } +} + +static void _chat_message_process_io_error_upload (void *data, const belle_sip_io_error_event_t *event) { + FileTransferChatMessageModifier *d = (FileTransferChatMessageModifier *)data; + d->processIoErrorUpload(event); +} + +void FileTransferChatMessageModifier::processIoErrorUpload (const belle_sip_io_error_event_t *event) { + lError() << "I/O Error during file upload of msg [" << this << "]"; + chatMessage->updateState(ChatMessage::State::NotDelivered); + releaseHttpRequest(); + + if (chatRoom) + chatRoom->getPrivate()->removeTransientMessage(chatMessage); +} + +static void _chat_message_process_auth_requested_upload (void *data, belle_sip_auth_event *event) { + FileTransferChatMessageModifier *d = (FileTransferChatMessageModifier *)data; + d->processAuthRequestedUpload(event); +} + +void FileTransferChatMessageModifier::processAuthRequestedUpload (const belle_sip_auth_event *event) { + lError() << "Error during file upload: auth requested for msg [" << this << "]"; + chatMessage->updateState(ChatMessage::State::NotDelivered); + releaseHttpRequest(); + + if (chatRoom) + chatRoom->getPrivate()->removeTransientMessage(chatMessage); +} + +int FileTransferChatMessageModifier::uploadFile () { + if (httpRequest) { + lError() << "linphone_chat_room_upload_file(): there is already an upload in progress."; + return -1; + } + + // THIS IS ONLY FOR BACKWARD C API COMPAT + if (currentFileContentToTransfer->getFilePath().empty() && !chatMessage->getFileTransferFilepath().empty()) { + currentFileContentToTransfer->setFilePath(chatMessage->getFileTransferFilepath()); + } + + belle_http_request_listener_callbacks_t cbs = { 0 }; + cbs.process_response = _chat_message_process_response_from_post_file; + cbs.process_io_error = _chat_message_process_io_error_upload; + cbs.process_auth_requested = _chat_message_process_auth_requested_upload; + + int err = startHttpTransfer(linphone_core_get_file_transfer_server(chatMessage->getCore()->getCCore()), "POST", &cbs); + return err; +} + +int FileTransferChatMessageModifier::startHttpTransfer (const string &url, const string &action, belle_http_request_listener_callbacks_t *cbs) { + belle_generic_uri_t *uri = nullptr; + + shared_ptr core = chatMessage->getCore(); + const char *ua = linphone_core_get_user_agent(core->getCCore()); + + if (url.empty()) { + lWarning() << "Cannot process file transfer msg [" << this << "]: no file remote URI configured."; + goto error; + } + uri = belle_generic_uri_parse(url.c_str()); + if (uri == nullptr || belle_generic_uri_get_host(uri) == nullptr) { + lWarning() << "Cannot process file transfer msg [" << this << "]: incorrect file remote URI configured '" << + url << "'."; + goto error; + } + + httpRequest = belle_http_request_create(action.c_str(), uri, belle_sip_header_create("User-Agent", ua), nullptr); + + if (httpRequest == nullptr) { + lWarning() << "Could not create http request for uri " << url; + goto error; + } + // keep a reference to the http request to be able to cancel it during upload + belle_sip_object_ref(httpRequest); + + // give msg to listener to be able to start the actual file upload when server answer a 204 No content + httpListener = belle_http_request_listener_create_from_callbacks(cbs, this); + belle_http_provider_send_request(core->getCCore()->http_provider, httpRequest, httpListener); + return 0; + +error: + if (uri) { + belle_sip_object_unref(uri); + } + return -1; +} + +static void _chat_message_file_upload_background_task_ended (void *data) { + FileTransferChatMessageModifier *d = (FileTransferChatMessageModifier *)data; + d->fileUploadBackgroundTaskEnded(); +} + +void FileTransferChatMessageModifier::fileUploadBackgroundTaskEnded () { + lWarning() << "channel [" << this << "]: file upload background task has to be ended now, but work isn't finished."; + fileUploadEndBackgroundTask(); +} + +void FileTransferChatMessageModifier::fileUploadBeginBackgroundTask () { + if (backgroundTaskId == 0) { + backgroundTaskId = sal_begin_background_task("file transfer upload", _chat_message_file_upload_background_task_ended, this); + if (backgroundTaskId) lInfo() << "channel [" << this << "]: starting file upload background task with id=[" << backgroundTaskId << "]."; + } +} + +void FileTransferChatMessageModifier::fileUploadEndBackgroundTask () { + if (backgroundTaskId) { + lInfo() << "channel [" << this << "]: ending file upload background task with id=[" << backgroundTaskId << "]."; + sal_end_background_task(backgroundTaskId); + backgroundTaskId = 0; + } +} + +// ---------------------------------------------------------- + +ChatMessageModifier::Result FileTransferChatMessageModifier::decode (const shared_ptr &message, int &errorCode) { chatMessage = message; return ChatMessageModifier::Result::Done; } -ChatMessageModifier::Result FileTransferMessageModifier::decode (const shared_ptr &message, int &errorCode) { - chatMessage = message; +// ---------------------------------------------------------- - return ChatMessageModifier::Result::Done; +//TODO + +// ---------------------------------------------------------- + +bool FileTransferChatMessageModifier::isFileTransferInProgressAndValid () { + return httpRequest && !belle_http_request_is_cancelled(httpRequest); +} + +void FileTransferChatMessageModifier::releaseHttpRequest () { + if (httpRequest) { + belle_sip_object_unref(httpRequest); + httpRequest = nullptr; + if (httpListener) { + belle_sip_object_unref(httpListener); + httpListener = nullptr; + } + } } LINPHONE_END_NAMESPACE diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.h b/src/chat/modifier/file-transfer-chat-message-modifier.h index a03ceba31..c17dba5b2 100644 --- a/src/chat/modifier/file-transfer-chat-message-modifier.h +++ b/src/chat/modifier/file-transfer-chat-message-modifier.h @@ -26,15 +26,38 @@ LINPHONE_BEGIN_NAMESPACE -class FileTransferMessageModifier : public ChatMessageModifier { +class Core; + +class FileTransferChatMessageModifier : public ChatMessageModifier { public: - FileTransferMessageModifier () = default; + FileTransferChatMessageModifier () = default; Result encode (const std::shared_ptr &message, int &errorCode) override; Result decode (const std::shared_ptr &message, int &errorCode) override; + + int onSendBody (belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, size_t offset, uint8_t *buffer, size_t *size); + void onSendEnd (belle_sip_user_body_handler_t *bh); + void fileUploadBackgroundTaskEnded(); + void fileTransferOnProgress (belle_sip_body_handler_t *bh, belle_sip_message_t *m, size_t offset, size_t total); + void processResponseFromPostFile (const belle_http_response_event_t *event); + void processIoErrorUpload (const belle_sip_io_error_event_t *event); + void processAuthRequestedUpload (const belle_sip_auth_event *event); private: + std::shared_ptr chatRoom; std::shared_ptr chatMessage; + FileContent* currentFileContentToTransfer; + unsigned long backgroundTaskId = 0; + belle_http_request_t *httpRequest = nullptr; + belle_http_request_listener_t *httpListener = nullptr; + + int uploadFile(); + int startHttpTransfer(const std::string &url, const std::string &action, belle_http_request_listener_callbacks_t *cbs); + void fileUploadBeginBackgroundTask(); + void fileUploadEndBackgroundTask(); + + bool isFileTransferInProgressAndValid(); + void releaseHttpRequest(); }; LINPHONE_END_NAMESPACE From 2111b62d757a09d343e077a24cc74da300688159 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 9 Nov 2017 10:25:53 +0100 Subject: [PATCH 0744/2215] Finished moving file transfer related code from ChatMessage to FileTransferChatMessageModifier --- src/chat/chat-message/chat-message-p.h | 37 +- src/chat/chat-message/chat-message.cpp | 857 +----------------- src/chat/chat-room/real-time-text-chat-room.h | 2 - .../file-transfer-chat-message-modifier.cpp | 384 +++++++- .../file-transfer-chat-message-modifier.h | 15 +- 5 files changed, 400 insertions(+), 895 deletions(-) diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index e2127c01d..3fd393d15 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -98,26 +98,6 @@ public: int downloadFile (); - // ----------------------------------------------------------------------------- - // Need to be public to be called from static C callbacks - // ----------------------------------------------------------------------------- - - void fileTransferOnProgress(belle_sip_body_handler_t *bh, belle_sip_message_t *m, size_t offset, size_t total); - int onSendBody(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, size_t offset, uint8_t *buffer, size_t *size); - void onSendEnd(belle_sip_user_body_handler_t *bh); - void onRecvBody(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, size_t offset, uint8_t *buffer, size_t size); - void onRecvEnd(belle_sip_user_body_handler_t *bh); - void fileUploadBackgroundTaskEnded(); - void processResponseFromPostFile(const belle_http_response_event_t *event); - void processResponseHeadersFromGetFile(const belle_http_response_event_t *event); - void processAuthRequestedDownload(const belle_sip_auth_event *event); - void processIoErrorUpload(const belle_sip_io_error_event_t *event); - void processAuthRequestedUpload(const belle_sip_auth_event *event); - void processIoErrorDownload(const belle_sip_io_error_event_t *event); - void processResponseFromGetFile(const belle_http_response_event_t *event); - - // ----------------------------------------------------------------------------- - void sendImdn(Imdn::Type imdnType, LinphoneReason reason); LinphoneReason receive(); @@ -143,37 +123,22 @@ private: bool isReadOnly = false; std::list contents; Content internalContent; - FileContent *currentFileContentToTransfer; std::unordered_map customHeaders; mutable LinphoneErrorInfo * errorInfo = nullptr; - belle_http_request_t *httpRequest = nullptr; - belle_http_request_listener_t *httpListener = nullptr; SalOp *salOp = nullptr; SalCustomHeader *salCustomHeaders = nullptr; - unsigned long backgroundTaskId = 0; unsigned char currentSendStep = Step::None; bool applyModifiers = true; FileTransferChatMessageModifier fileTransferChatMessageModifier; + // Cache for returned values, used for compatibility with previous C API ContentType cContentType; std::string cText; // ----------------------------------------------------------------------------- - int uploadFile (); std::string createImdnXml(Imdn::Type imdnType, LinphoneReason reason); - void fileUploadEndBackgroundTask(); - void fileUploadBeginBackgroundTask(); - bool isFileTransferInProgressAndValid(); - int startHttpTransfer( - const std::string &url, - const std::string &action, - belle_http_request_listener_callbacks_t *cbs - ); - void releaseHttpRequest(); - void createFileTransferInformationsFromVndGsmaRcsFtHttpXml(FileTransferContent* content); - L_DECLARE_PUBLIC(ChatMessage); }; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index e5cc4a201..f7eeb68e4 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -118,11 +118,11 @@ void ChatMessagePrivate::setStorageId (unsigned int id) { } belle_http_request_t *ChatMessagePrivate::getHttpRequest () const { - return httpRequest; + return fileTransferChatMessageModifier.getHttpRequest(); } void ChatMessagePrivate::setHttpRequest (belle_http_request_t *request) { - httpRequest = request; + fileTransferChatMessageModifier.setHttpRequest(request); } SalOp *ChatMessagePrivate::getSalOp () const { @@ -357,806 +357,6 @@ void ChatMessagePrivate::sendImdn (Imdn::Type imdnType, LinphoneReason reason) { chatRoom->getPrivate()->sendImdn(createImdnXml(imdnType, reason), reason); } -static void _chat_message_file_transfer_on_progress ( - belle_sip_body_handler_t *bh, - belle_sip_message_t *m, - void *data, - size_t offset, - size_t total -) { - ChatMessagePrivate *d = (ChatMessagePrivate *)data; - d->fileTransferOnProgress(bh, m, offset, total); -} - -void ChatMessagePrivate::fileTransferOnProgress ( - belle_sip_body_handler_t *bh, - belle_sip_message_t *m, - size_t offset, - size_t total -) { - L_Q(); - - if (!isFileTransferInProgressAndValid()) { - lWarning() << "Cancelled request for " << (chatRoom.lock() ? "" : "ORPHAN") << " msg [" << this << - "], ignoring " << __FUNCTION__; - releaseHttpRequest(); - return; - } - - LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); - LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); - LinphoneContent *content = currentFileContentToTransfer->toLinphoneContent(); - if (linphone_chat_message_cbs_get_file_transfer_progress_indication(cbs)) { - linphone_chat_message_cbs_get_file_transfer_progress_indication(cbs)(msg, content, offset, total); - } else { - // Legacy: call back given by application level. - shared_ptr core = q->getCore(); - if (core) - linphone_core_notify_file_transfer_progress_indication( - core->getCCore(), - msg, - content, - offset, - total - ); - } - linphone_content_unref(content); -} - -static int _chat_message_on_send_body ( - belle_sip_user_body_handler_t *bh, - belle_sip_message_t *m, - void *data, - size_t offset, - uint8_t *buffer, - size_t *size -) { - ChatMessagePrivate *d = (ChatMessagePrivate *)data; - return d->onSendBody(bh, m, offset, buffer, size); -} - -int ChatMessagePrivate::onSendBody ( - belle_sip_user_body_handler_t *bh, - belle_sip_message_t *m, - size_t offset, - uint8_t *buffer, - size_t *size -) { - L_Q(); - - int retval = -1; - LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); - - if (!isFileTransferInProgressAndValid()) { - if (httpRequest) { - lWarning() << "Cancelled request for " << (chatRoom.lock() ? "" : "ORPHAN") << - " msg [" << this << "], ignoring " << __FUNCTION__; - releaseHttpRequest(); - } - return BELLE_SIP_STOP; - } - - // if we've not reach the end of file yet, ask for more data - // in case of file body handler, won't be called - if (currentFileContentToTransfer->getFilePath().empty() && offset < currentFileContentToTransfer->getFileSize()) { - // get data from call back - LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); - LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = - linphone_chat_message_cbs_get_file_transfer_send(cbs); - LinphoneContent *content = currentFileContentToTransfer->toLinphoneContent(); - if (file_transfer_send_cb) { - LinphoneBuffer *lb = file_transfer_send_cb(msg, content, offset, *size); - if (lb == nullptr) { - *size = 0; - } else { - *size = linphone_buffer_get_size(lb); - memcpy(buffer, linphone_buffer_get_content(lb), *size); - linphone_buffer_unref(lb); - } - } else { - // Legacy - shared_ptr core = q->getCore(); - if (core) - linphone_core_notify_file_transfer_send(core->getCCore(), msg, content, (char *)buffer, size); - } - linphone_content_unref(content); - } - - LinphoneImEncryptionEngine *imee = nullptr; - shared_ptr core = q->getCore(); - if (core) - imee = linphone_core_get_im_encryption_engine(core->getCCore()); - - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = - linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); - if (cb_process_uploading_file) { - size_t max_size = *size; - uint8_t *encrypted_buffer = (uint8_t *)ms_malloc0(max_size); - retval = cb_process_uploading_file(imee, msg, offset, (const uint8_t *)buffer, size, encrypted_buffer); - if (retval == 0) { - if (*size > max_size) { - lError() << "IM encryption engine process upload file callback returned a size bigger than the size of the buffer, so it will be truncated !"; - *size = max_size; - } - memcpy(buffer, encrypted_buffer, *size); - } - ms_free(encrypted_buffer); - } - } - - return retval <= 0 ? BELLE_SIP_CONTINUE : BELLE_SIP_STOP; -} - -static void _chat_message_on_send_end (belle_sip_user_body_handler_t *bh, void *data) { - ChatMessagePrivate *d = (ChatMessagePrivate *)data; - d->onSendEnd(bh); -} - -void ChatMessagePrivate::onSendEnd (belle_sip_user_body_handler_t *bh) { - L_Q(); - - LinphoneImEncryptionEngine *imee = nullptr; - shared_ptr core = q->getCore(); - if (core) - imee = linphone_core_get_im_encryption_engine(core->getCCore()); - - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); - if (cb_process_uploading_file) { - cb_process_uploading_file(imee, L_GET_C_BACK_PTR(q), 0, nullptr, nullptr, nullptr); - } - } -} - -void ChatMessagePrivate::fileUploadEndBackgroundTask () { - if (backgroundTaskId) { - lInfo() << "channel [" << this << "]: ending file upload background task with id=[" << backgroundTaskId << "]."; - sal_end_background_task(backgroundTaskId); - backgroundTaskId = 0; - } -} - -static void _chat_message_file_upload_background_task_ended (void *data) { - ChatMessagePrivate *d = (ChatMessagePrivate *)data; - d->fileUploadBackgroundTaskEnded(); -} - -void ChatMessagePrivate::fileUploadBackgroundTaskEnded () { - lWarning() << "channel [" << this << "]: file upload background task has to be ended now, but work isn't finished."; - fileUploadEndBackgroundTask(); -} - -void ChatMessagePrivate::fileUploadBeginBackgroundTask () { - if (backgroundTaskId == 0) { - backgroundTaskId = sal_begin_background_task("file transfer upload", _chat_message_file_upload_background_task_ended, this); - if (backgroundTaskId) lInfo() << "channel [" << this << "]: starting file upload background task with id=[" << backgroundTaskId << "]."; - } -} - -static void _chat_message_on_recv_body (belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset, uint8_t *buffer, size_t size) { - ChatMessagePrivate *d = (ChatMessagePrivate *)data; - d->onRecvBody(bh, m, offset, buffer, size); -} - -void ChatMessagePrivate::onRecvBody (belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, size_t offset, uint8_t *buffer, size_t size) { - L_Q(); - - int retval = -1; - uint8_t *decrypted_buffer = nullptr; - - if (!chatRoom.lock()) { - q->cancelFileTransfer(); - return; - } - - if (!httpRequest || belle_http_request_is_cancelled(httpRequest)) { - lWarning() << "Cancelled request for msg [" << this << "], ignoring " << __FUNCTION__; - return; - } - - // first call may be with a zero size, ignore it - if (size == 0) { - return; - } - - decrypted_buffer = (uint8_t *)ms_malloc0(size); - - LinphoneImEncryptionEngine *imee = nullptr; - shared_ptr core = q->getCore(); - if (core) - imee = linphone_core_get_im_encryption_engine(core->getCCore()); - - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); - if (cb_process_downloading_file) { - retval = cb_process_downloading_file(imee, L_GET_C_BACK_PTR(q), offset, (const uint8_t *)buffer, size, decrypted_buffer); - if (retval == 0) { - memcpy(buffer, decrypted_buffer, size); - } - } - } - ms_free(decrypted_buffer); - - if (retval <= 0) { - if (currentFileContentToTransfer->getFilePath().empty()) { - LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); - LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); - LinphoneContent *content = currentFileContentToTransfer->toLinphoneContent(); - if (linphone_chat_message_cbs_get_file_transfer_recv(cbs)) { - LinphoneBuffer *lb = linphone_buffer_new_from_data(buffer, size); - linphone_chat_message_cbs_get_file_transfer_recv(cbs)(msg, content, lb); - linphone_buffer_unref(lb); - } else { - // Legacy: call back given by application level - linphone_core_notify_file_transfer_recv(core->getCCore(), msg, content, (const char *)buffer, size); - } - linphone_content_unref(content); - } - } else { - lWarning() << "File transfer decrypt failed with code " << (int)retval; - setState(ChatMessage::State::FileTransferError); - } -} - -static void _chat_message_on_recv_end (belle_sip_user_body_handler_t *bh, void *data) { - ChatMessagePrivate *d = (ChatMessagePrivate *)data; - d->onRecvEnd(bh); -} - -void ChatMessagePrivate::onRecvEnd (belle_sip_user_body_handler_t *bh) { - L_Q(); - - shared_ptr core = q->getCore(); - if (!core) - return; - - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(core->getCCore()); - int retval = -1; - - if (imee) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); - if (cb_process_downloading_file) { - retval = cb_process_downloading_file(imee, L_GET_C_BACK_PTR(q), 0, nullptr, 0, nullptr); - } - } - - if (retval <= 0) { - if (currentFileContentToTransfer->getFilePath().empty()) { - LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); - LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); - LinphoneContent *content = currentFileContentToTransfer->toLinphoneContent(); - if (linphone_chat_message_cbs_get_file_transfer_recv(cbs)) { - LinphoneBuffer *lb = linphone_buffer_new(); - linphone_chat_message_cbs_get_file_transfer_recv(cbs)(msg, content, lb); - linphone_buffer_unref(lb); - } else { - // Legacy: call back given by application level - linphone_core_notify_file_transfer_recv(core->getCCore(), msg, content, nullptr, 0); - } - linphone_content_unref(content); - } - } - - if (retval <= 0 && state != ChatMessage::State::FileTransferError) { - // Remove the FileTransferContent from the message and store the FileContent - FileContent *fileContent = currentFileContentToTransfer; - q->addContent(fileContent); - for (Content *content : contents) { - if (content->getContentType() == ContentType::FileTransfer) { - FileTransferContent *fileTransferContent = (FileTransferContent*)content; - if (fileTransferContent->getFileContent() == fileContent) { - q->removeContent(content); - free(fileTransferContent); - break; - } - } - } - setState(ChatMessage::State::FileTransferDone); - } -} - -bool ChatMessagePrivate::isFileTransferInProgressAndValid () { - L_Q(); - shared_ptr chatRoom = q->getChatRoom(); - return chatRoom && q->getCore() && httpRequest && !belle_http_request_is_cancelled(httpRequest); -} - -static void _chat_message_process_response_from_post_file (void *data, const belle_http_response_event_t *event) { - ChatMessagePrivate *d = (ChatMessagePrivate *)data; - d->processResponseFromPostFile(event); -} - -void ChatMessagePrivate::processResponseFromPostFile (const belle_http_response_event_t *event) { - L_Q(); - - if (httpRequest && !isFileTransferInProgressAndValid()) { - lWarning() << "Cancelled request for " << (chatRoom.lock() ? "" : "ORPHAN") << - " msg [" << this << "], ignoring " << __FUNCTION__; - releaseHttpRequest(); - return; - } - - // check the answer code - if (event->response) { - int code = belle_http_response_get_status_code(event->response); - if (code == 204) { // this is the reply to the first post to the server - an empty msg - // start uploading the file - belle_sip_multipart_body_handler_t *bh; - string first_part_header; - belle_sip_body_handler_t *first_part_bh; - - bool_t is_file_encryption_enabled = FALSE; - LinphoneImEncryptionEngine *imee = nullptr; - - shared_ptr core = q->getCore(); - shared_ptr chatRoom = q->getChatRoom(); - - imee = linphone_core_get_im_encryption_engine(core->getCCore()); - - if (imee && chatRoom) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer_cb = - linphone_im_encryption_engine_cbs_get_is_encryption_enabled_for_file_transfer(imee_cbs); - if (is_encryption_enabled_for_file_transfer_cb) { - is_file_encryption_enabled = is_encryption_enabled_for_file_transfer_cb(imee, L_GET_C_BACK_PTR(chatRoom)); - } - } - // shall we encrypt the file - if (is_file_encryption_enabled && chatRoom) { - LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb generate_file_transfer_key_cb = - linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(imee_cbs); - if (generate_file_transfer_key_cb) { - generate_file_transfer_key_cb(imee, L_GET_C_BACK_PTR(chatRoom), L_GET_C_BACK_PTR(q)); - } - // temporary storage for the Content-disposition header value : use a generic filename to not leak it - // Actual filename stored in msg->file_transfer_information->name will be set in encrypted msg - // sended to the - first_part_header = "form-data; name=\"File\"; filename=\"filename.txt\""; - } else { - // temporary storage for the Content-disposition header value - first_part_header = "form-data; name=\"File\"; filename=\"" + currentFileContentToTransfer->getFileName() + "\""; - } - - // create a user body handler to take care of the file and add the content disposition and content-type headers - first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(currentFileContentToTransfer->getFileSize(), - _chat_message_file_transfer_on_progress, nullptr, nullptr, - _chat_message_on_send_body, _chat_message_on_send_end, this); - if (!currentFileContentToTransfer->getFilePath().empty()) { - belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh; - // No need to add again the callback for progression, otherwise it will be called twice - first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(currentFileContentToTransfer->getFilePath().c_str(), nullptr, this); - //linphone_content_set_size(cFileTransferInformation, belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh)); - belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)first_part_bh, body_handler); - } else if (!currentFileContentToTransfer->isEmpty()) { - first_part_bh = (belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer( - ms_strdup(currentFileContentToTransfer->getBodyAsString().c_str()), - currentFileContentToTransfer->getSize(), _chat_message_file_transfer_on_progress, this); - } - - belle_sip_body_handler_add_header(first_part_bh, - belle_sip_header_create("Content-disposition", first_part_header.c_str())); - belle_sip_body_handler_add_header(first_part_bh, - (belle_sip_header_t *)belle_sip_header_content_type_create( - currentFileContentToTransfer->getContentType().getType().c_str(), - currentFileContentToTransfer->getContentType().getSubType().c_str())); - - // insert it in a multipart body handler which will manage the boundaries of multipart msg - bh = belle_sip_multipart_body_handler_new(_chat_message_file_transfer_on_progress, this, first_part_bh, nullptr); - - releaseHttpRequest(); - fileUploadBeginBackgroundTask(); - uploadFile(); - belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(httpRequest), BELLE_SIP_BODY_HANDLER(bh)); - } else if (code == 200) { // file has been uploaded correctly, get server reply and send it - const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); - if (body && strlen(body) > 0) { - //TODO - // if we have an encryption key for the file, we must insert it into the msg and restore the correct filename - /*const char *content_key = linphone_content_get_key(cFileTransferInformation); - size_t content_key_size = linphone_content_get_key_size(cFileTransferInformation); - if (content_key != nullptr) { - // parse the msg body - xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body); - - xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody); - if (cur != nullptr) { - cur = cur->xmlChildrenNode; - while (cur != nullptr) { - // we found a file info node, check it has a type="file" attribute - if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { - xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); - // this is the node we are looking for : add a file-key children node - if (!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { - // need to parse the children node to update the file-name one - xmlNodePtr fileInfoNodeChildren = cur->xmlChildrenNode; - // convert key to base64 - size_t b64Size = b64_encode(nullptr, content_key_size, nullptr, 0); - char *keyb64 = (char *)ms_malloc0(b64Size + 1); - int xmlStringLength; - - b64Size = b64_encode(content_key, content_key_size, keyb64, b64Size); - keyb64[b64Size] = '\0'; // libxml need a null terminated string - - // add the node containing the key to the file-info node - xmlNewTextChild(cur, nullptr, (const xmlChar *)"file-key", (const xmlChar *)keyb64); - xmlFree(typeAttribute); - ms_free(keyb64); - - // look for the file-name node and update its content - while (fileInfoNodeChildren != nullptr) { - // we found a the file-name node, update its content with the real filename - if (!xmlStrcmp(fileInfoNodeChildren->name, (const xmlChar *)"file-name")) { - // update node content - xmlNodeSetContent(fileInfoNodeChildren, (const xmlChar *)(linphone_content_get_name(cFileTransferInformation))); - break; - } - fileInfoNodeChildren = fileInfoNodeChildren->next; - } - - // dump the xml into msg->message - char *buffer; - xmlDocDumpFormatMemoryEnc(xmlMessageBody, (xmlChar **)&buffer, &xmlStringLength, "UTF-8", 0); - setText(buffer); - break; - } - xmlFree(typeAttribute); - } - cur = cur->next; - } - } - xmlFreeDoc(xmlMessageBody); - } else { // no encryption key, transfer in plain, just copy the msg sent by server - setText(body); - } - setContentType(ContentType::FileTransfer);*/ - FileContent *fileContent = currentFileContentToTransfer; - - FileTransferContent *fileTransferContent = new FileTransferContent(); - fileTransferContent->setContentType(ContentType::FileTransfer); - fileTransferContent->setFileContent(fileContent); - fileTransferContent->setBody(body); - - q->removeContent(fileContent); - q->addContent(fileTransferContent); - - q->updateState(ChatMessage::State::FileTransferDone); - releaseHttpRequest(); - send(); - fileUploadEndBackgroundTask(); - } else { - lWarning() << "Received empty response from server, file transfer failed"; - q->updateState(ChatMessage::State::NotDelivered); - releaseHttpRequest(); - fileUploadEndBackgroundTask(); - } - } else { - lWarning() << "Unhandled HTTP code response " << code << " for file transfer"; - q->updateState(ChatMessage::State::NotDelivered); - releaseHttpRequest(); - fileUploadEndBackgroundTask(); - } - } -} - -static void _chat_process_response_headers_from_get_file (void *data, const belle_http_response_event_t *event) { - ChatMessagePrivate *d = (ChatMessagePrivate *)data; - d->processResponseHeadersFromGetFile(event); -} - -static FileContent* createFileTransferInformationFromHeaders (const belle_sip_message_t *m) { - FileContent *fileContent = new FileContent(); - - belle_sip_header_content_length_t *content_length_hdr = BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(m, "Content-Length")); - belle_sip_header_content_type_t *content_type_hdr = BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(m, "Content-Type")); - const char *type = nullptr, *subtype = nullptr; - - if (content_type_hdr) { - type = belle_sip_header_content_type_get_type(content_type_hdr); - subtype = belle_sip_header_content_type_get_subtype(content_type_hdr); - lInfo() << "Extracted content type " << type << " / " << subtype << " from header"; - ContentType contentType(type, subtype); - fileContent->setContentType(contentType); - } - if (content_length_hdr) { - fileContent->setFileSize(belle_sip_header_content_length_get_content_length(content_length_hdr)); - lInfo() << "Extracted content length " << fileContent->getFileSize() << " from header"; - } - - return fileContent; -} - -void ChatMessagePrivate::processResponseHeadersFromGetFile (const belle_http_response_event_t *event) { - L_Q(); - - if (event->response) { - // we are receiving a response, set a specific body handler to acquire the response. - // if not done, belle-sip will create a memory body handler, the default - belle_sip_message_t *response = BELLE_SIP_MESSAGE(event->response); - belle_sip_body_handler_t *body_handler = nullptr; - size_t body_size = 0; - - if (currentFileContentToTransfer == nullptr) { - lWarning() << "No file transfer information for msg [" << this << "]: creating..."; - FileContent *content = createFileTransferInformationFromHeaders(response); - q->addContent(content); - } else { - belle_sip_header_content_length_t *content_length_hdr = BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(response, "Content-Length")); - currentFileContentToTransfer->setFileSize(belle_sip_header_content_length_get_content_length(content_length_hdr)); - lInfo() << "Extracted content length " << currentFileContentToTransfer->getFileSize() << " from header"; - } - - if (currentFileContentToTransfer) { - body_size = currentFileContentToTransfer->getFileSize(); - } - - body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, _chat_message_file_transfer_on_progress, - nullptr, _chat_message_on_recv_body, - nullptr, _chat_message_on_recv_end, this); - if (!currentFileContentToTransfer->getFilePath().empty()) { - belle_sip_user_body_handler_t *bh = (belle_sip_user_body_handler_t *)body_handler; - body_handler = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(currentFileContentToTransfer->getFilePath().c_str(), _chat_message_file_transfer_on_progress, this); - if (belle_sip_body_handler_get_size((belle_sip_body_handler_t *)body_handler) == 0) { - // If the size of the body has not been initialized from the file stat, use the one from the - // file_transfer_information. - belle_sip_body_handler_set_size((belle_sip_body_handler_t *)body_handler, body_size); - } - belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)body_handler, bh); - } - belle_sip_message_set_body_handler((belle_sip_message_t *)event->response, body_handler); - } -} - -static void _chat_message_process_auth_requested_download (void *data, belle_sip_auth_event *event) { - ChatMessagePrivate *d = (ChatMessagePrivate *)data; - d->processAuthRequestedDownload(event); -} - -void ChatMessagePrivate::processAuthRequestedDownload (const belle_sip_auth_event *event) { - L_Q(); - - lError() << "Error during file download : auth requested for msg [" << this << "]"; - q->updateState(ChatMessage::State::FileTransferError); - releaseHttpRequest(); -} - -static void _chat_message_process_io_error_upload (void *data, const belle_sip_io_error_event_t *event) { - ChatMessagePrivate *d = (ChatMessagePrivate *)data; - d->processIoErrorUpload(event); -} - -void ChatMessagePrivate::processIoErrorUpload (const belle_sip_io_error_event_t *event) { - L_Q(); - - lError() << "I/O Error during file upload of msg [" << this << "]"; - q->updateState(ChatMessage::State::NotDelivered); - releaseHttpRequest(); - - shared_ptr chatRoom = q->getChatRoom(); - if (chatRoom) - chatRoom->getPrivate()->removeTransientMessage(q->getSharedFromThis()); -} - -static void _chat_message_process_auth_requested_upload (void *data, belle_sip_auth_event *event) { - ChatMessagePrivate *d = (ChatMessagePrivate *)data; - d->processAuthRequestedUpload(event); -} - -void ChatMessagePrivate::processAuthRequestedUpload (const belle_sip_auth_event *event) { - L_Q(); - - lError() << "Error during file upload: auth requested for msg [" << this << "]"; - q->updateState(ChatMessage::State::NotDelivered); - releaseHttpRequest(); - - shared_ptr chatRoom = q->getChatRoom(); - if (chatRoom) - chatRoom->getPrivate()->removeTransientMessage(q->getSharedFromThis()); -} - -static void _chat_message_process_io_error_download (void *data, const belle_sip_io_error_event_t *event) { - ChatMessagePrivate *d = (ChatMessagePrivate *)data; - d->processIoErrorDownload(event); -} - -void ChatMessagePrivate::processIoErrorDownload (const belle_sip_io_error_event_t *event) { - L_Q(); - - lError() << "I/O Error during file download msg [" << this << "]"; - q->updateState(ChatMessage::State::FileTransferError); - releaseHttpRequest(); -} - -static void _chat_message_process_response_from_get_file (void *data, const belle_http_response_event_t *event) { - ChatMessagePrivate *d = (ChatMessagePrivate *)data; - d->processResponseFromGetFile(event); -} - -void ChatMessagePrivate::processResponseFromGetFile (const belle_http_response_event_t *event) { - // check the answer code - if (event->response) { - int code = belle_http_response_get_status_code(event->response); - if (code >= 400 && code < 500) { - lWarning() << "File transfer failed with code " << code; - setState(ChatMessage::State::FileTransferError); - } else if (code != 200) { - lWarning() << "Unhandled HTTP code response " << code << " for file transfer"; - } - releaseHttpRequest(); - } -} - -int ChatMessagePrivate::startHttpTransfer ( - const string &url, - const string &action, - belle_http_request_listener_callbacks_t *cbs -) { - L_Q(); - - belle_generic_uri_t *uri = nullptr; - - shared_ptr core = q->getCore(); - const char *ua = linphone_core_get_user_agent(core->getCCore()); - - if (url.empty()) { - lWarning() << "Cannot process file transfer msg [" << this << "]: no file remote URI configured."; - goto error; - } - uri = belle_generic_uri_parse(url.c_str()); - if (uri == nullptr || belle_generic_uri_get_host(uri) == nullptr) { - lWarning() << "Cannot process file transfer msg [" << this << "]: incorrect file remote URI configured '" << - url << "'."; - goto error; - } - - httpRequest = belle_http_request_create(action.c_str(), uri, belle_sip_header_create("User-Agent", ua), nullptr); - - if (httpRequest == nullptr) { - lWarning() << "Could not create http request for uri " << url; - goto error; - } - // keep a reference to the http request to be able to cancel it during upload - belle_sip_object_ref(httpRequest); - - // give msg to listener to be able to start the actual file upload when server answer a 204 No content - httpListener = belle_http_request_listener_create_from_callbacks(cbs, this); - belle_http_provider_send_request(core->getCCore()->http_provider, httpRequest, httpListener); - return 0; - -error: - if (uri) { - belle_sip_object_unref(uri); - } - return -1; -} - -void ChatMessagePrivate::releaseHttpRequest () { - if (httpRequest) { - belle_sip_object_unref(httpRequest); - httpRequest = nullptr; - if (httpListener) { - belle_sip_object_unref(httpListener); - httpListener = nullptr; - } - } -} - -int ChatMessagePrivate::uploadFile () { - L_Q(); - - if (httpRequest) { - lError() << "linphone_chat_room_upload_file(): there is already an upload in progress."; - return -1; - } - - // THIS IS ONLY FOR BACKWARD C API COMPAT - if (currentFileContentToTransfer->getFilePath().empty() && !q->getFileTransferFilepath().empty()) { - currentFileContentToTransfer->setFilePath(q->getFileTransferFilepath()); - } - - belle_http_request_listener_callbacks_t cbs = { 0 }; - cbs.process_response = _chat_message_process_response_from_post_file; - cbs.process_io_error = _chat_message_process_io_error_upload; - cbs.process_auth_requested = _chat_message_process_auth_requested_upload; - - int err = startHttpTransfer(linphone_core_get_file_transfer_server(q->getCore()->getCCore()), "POST", &cbs); - if (err == -1) - setState(ChatMessage::State::NotDelivered); - - return err; -} - -void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml (FileTransferContent *fileTransferContent) { - xmlChar *file_url = nullptr; - xmlDocPtr xmlMessageBody; - xmlNodePtr cur; - /* parse the msg body to get all informations from it */ - xmlMessageBody = xmlParseDoc((const xmlChar *)fileTransferContent->getBodyAsString().c_str()); - FileContent *fileContent = new FileContent(); - - cur = xmlDocGetRootElement(xmlMessageBody); - if (cur != nullptr) { - cur = cur->xmlChildrenNode; - while (cur != nullptr) { - if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { - /* we found a file info node, check if it has a type="file" attribute */ - xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); - if (!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for */ - cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */ - while (cur != nullptr) { - if (!xmlStrcmp(cur->name, (const xmlChar *)"file-size")) { - xmlChar *fileSizeString = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - size_t size = (size_t)strtol((const char *)fileSizeString, nullptr, 10); - fileContent->setFileSize(size); - xmlFree(fileSizeString); - } - - if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) { - xmlChar *filename = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - fileContent->setFileName((char *)filename); - xmlFree(filename); - } - if (!xmlStrcmp(cur->name, (const xmlChar *)"content-type")) { - xmlChar *content_type = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - int contentTypeIndex = 0; - char *type; - char *subtype; - while (content_type[contentTypeIndex] != '/' && content_type[contentTypeIndex] != '\0') { - contentTypeIndex++; - } - type = ms_strndup((char *)content_type, contentTypeIndex); - subtype = ms_strdup(((char *)content_type + contentTypeIndex + 1)); - ContentType contentType(type, subtype); - fileContent->setContentType(contentType); - ms_free(subtype); - ms_free(type); - ms_free(content_type); - } - if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) { - file_url = xmlGetProp(cur, (const xmlChar *)"url"); - } - - //TODO - /*if (!xmlStrcmp(cur->name, (const xmlChar *)"file-key")) { - // there is a key in the msg: file has been encrypted - // convert the key from base 64 - xmlChar *keyb64 = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - size_t keyLength = b64::b64_decode((char *)keyb64, strlen((char *)keyb64), nullptr, 0); - uint8_t *keyBuffer = (uint8_t *)malloc(keyLength); - // decode the key into local key buffer - b64::b64_decode((char *)keyb64, strlen((char *)keyb64), keyBuffer, keyLength); - linphone_content_set_key(content, (char *)keyBuffer, keyLength); - // duplicate key value into the linphone content private structure - xmlFree(keyb64); - free(keyBuffer); - }*/ - - cur = cur->next; - } - xmlFree(typeAttribute); - break; - } - xmlFree(typeAttribute); - } - cur = cur->next; - } - } - xmlFreeDoc(xmlMessageBody); - - fileContent->setFilePath(fileTransferContent->getFilePath()); // Copy file path from file transfer content to file content for file body handler - fileTransferContent->setFileUrl((const char *)file_url); // Set file url in the file transfer content for the download - - // Link the FileContent to the FileTransferContent - fileTransferContent->setFileContent(fileContent); - - xmlFree(file_url); -} - LinphoneReason ChatMessagePrivate::receive () { L_Q(); int errorCode = 0; @@ -1626,63 +826,16 @@ void ChatMessage::sendDisplayNotification () { int ChatMessage::downloadFile(FileTransferContent *fileTransferContent) { L_D(); - - if (d->httpRequest) { - lError() << "linphone_chat_message_download_file(): there is already a download in progress"; - return -1; - } - - if (fileTransferContent->getContentType() != ContentType::FileTransfer) { - lError() << "linphone_chat_message_download_file(): content type is not FileTransfer"; - return -1; - } - - d->createFileTransferInformationsFromVndGsmaRcsFtHttpXml(fileTransferContent); - FileContent *fileContent = fileTransferContent->getFileContent(); - d->currentFileContentToTransfer = fileContent; - if (d->currentFileContentToTransfer == nullptr) { - return -1; - } - - // THIS IS ONLY FOR BACKWARD C API COMPAT - if (d->currentFileContentToTransfer->getFilePath().empty() && !getFileTransferFilepath().empty()) { - d->currentFileContentToTransfer->setFilePath(getFileTransferFilepath()); - } - - belle_http_request_listener_callbacks_t cbs = { 0 }; - cbs.process_response_headers = _chat_process_response_headers_from_get_file; - cbs.process_response = _chat_message_process_response_from_get_file; - cbs.process_io_error = _chat_message_process_io_error_download; - cbs.process_auth_requested = _chat_message_process_auth_requested_download; - int err = d->startHttpTransfer(fileTransferContent->getFileUrl(), "GET", &cbs); // File URL has been set by createFileTransferInformationsFromVndGsmaRcsFtHttpXml - - if (err == -1) return -1; - // start the download, status is In Progress - d->setState(State::InProgress); - return 0; + return d->fileTransferChatMessageModifier.downloadFile(getSharedFromThis(), fileTransferContent); } void ChatMessage::cancelFileTransfer () { L_D(); - if (d->httpRequest) { + if (d->fileTransferChatMessageModifier.isFileTransferInProgressAndValid()) { if (d->state == State::InProgress) { d->setState(State::NotDelivered); } - if (!belle_http_request_is_cancelled(d->httpRequest)) { - shared_ptr chatRoom = getChatRoom(); - if (chatRoom) { - shared_ptr core = getCore(); - lInfo() << "Canceling file transfer " << ( - d->currentFileContentToTransfer->getFilePath().empty() - ? linphone_core_get_file_transfer_server(core->getCCore()) - : d->currentFileContentToTransfer->getFilePath().c_str() - ); - belle_http_provider_cancel_request(core->getCCore()->http_provider, d->httpRequest); - } else { - lInfo() << "Warning: http request still running for ORPHAN msg: this is a memory leak"; - } - } - d->releaseHttpRequest(); + d->fileTransferChatMessageModifier.cancelFileTransfer(); } else { lInfo() << "No existing file transfer - nothing to cancel"; } diff --git a/src/chat/chat-room/real-time-text-chat-room.h b/src/chat/chat-room/real-time-text-chat-room.h index 71ffc59ae..6a89593a3 100644 --- a/src/chat/chat-room/real-time-text-chat-room.h +++ b/src/chat/chat-room/real-time-text-chat-room.h @@ -38,8 +38,6 @@ public: uint32_t getChar () const; LinphoneCall *getCall () const; - void markAsRead () override; - void onChatMessageReceived (const std::shared_ptr &msg) override; /* ConferenceInterface */ void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.cpp b/src/chat/modifier/file-transfer-chat-message-modifier.cpp index b3e12826e..5c1c053ae 100644 --- a/src/chat/modifier/file-transfer-chat-message-modifier.cpp +++ b/src/chat/modifier/file-transfer-chat-message-modifier.cpp @@ -34,6 +34,14 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +belle_http_request_t *FileTransferChatMessageModifier::getHttpRequest () const { + return httpRequest; +} + +void FileTransferChatMessageModifier::setHttpRequest (belle_http_request_t *request) { + httpRequest = request; +} + ChatMessageModifier::Result FileTransferChatMessageModifier::encode (const shared_ptr &message, int &errorCode) { chatMessage = message; @@ -503,17 +511,385 @@ void FileTransferChatMessageModifier::fileUploadEndBackgroundTask () { // ---------------------------------------------------------- ChatMessageModifier::Result FileTransferChatMessageModifier::decode (const shared_ptr &message, int &errorCode) { - chatMessage = message; - - return ChatMessageModifier::Result::Done; + return ChatMessageModifier::Result::Skipped; } // ---------------------------------------------------------- -//TODO +static void createFileTransferInformationsFromVndGsmaRcsFtHttpXml (FileTransferContent *fileTransferContent) { + xmlChar *file_url = nullptr; + xmlDocPtr xmlMessageBody; + xmlNodePtr cur; + /* parse the msg body to get all informations from it */ + xmlMessageBody = xmlParseDoc((const xmlChar *)fileTransferContent->getBodyAsString().c_str()); + FileContent *fileContent = new FileContent(); + + cur = xmlDocGetRootElement(xmlMessageBody); + if (cur != nullptr) { + cur = cur->xmlChildrenNode; + while (cur != nullptr) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { + /* we found a file info node, check if it has a type="file" attribute */ + xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); + if (!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for */ + cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */ + while (cur != nullptr) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-size")) { + xmlChar *fileSizeString = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); + size_t size = (size_t)strtol((const char *)fileSizeString, nullptr, 10); + fileContent->setFileSize(size); + xmlFree(fileSizeString); + } + + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) { + xmlChar *filename = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); + fileContent->setFileName((char *)filename); + xmlFree(filename); + } + if (!xmlStrcmp(cur->name, (const xmlChar *)"content-type")) { + xmlChar *content_type = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); + int contentTypeIndex = 0; + char *type; + char *subtype; + while (content_type[contentTypeIndex] != '/' && content_type[contentTypeIndex] != '\0') { + contentTypeIndex++; + } + type = ms_strndup((char *)content_type, contentTypeIndex); + subtype = ms_strdup(((char *)content_type + contentTypeIndex + 1)); + ContentType contentType(type, subtype); + fileContent->setContentType(contentType); + ms_free(subtype); + ms_free(type); + ms_free(content_type); + } + if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) { + file_url = xmlGetProp(cur, (const xmlChar *)"url"); + } + + //TODO + /*if (!xmlStrcmp(cur->name, (const xmlChar *)"file-key")) { + // there is a key in the msg: file has been encrypted + // convert the key from base 64 + xmlChar *keyb64 = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); + size_t keyLength = b64::b64_decode((char *)keyb64, strlen((char *)keyb64), nullptr, 0); + uint8_t *keyBuffer = (uint8_t *)malloc(keyLength); + // decode the key into local key buffer + b64::b64_decode((char *)keyb64, strlen((char *)keyb64), keyBuffer, keyLength); + linphone_content_set_key(content, (char *)keyBuffer, keyLength); + // duplicate key value into the linphone content private structure + xmlFree(keyb64); + free(keyBuffer); + }*/ + + cur = cur->next; + } + xmlFree(typeAttribute); + break; + } + xmlFree(typeAttribute); + } + cur = cur->next; + } + } + xmlFreeDoc(xmlMessageBody); + + fileContent->setFilePath(fileTransferContent->getFilePath()); // Copy file path from file transfer content to file content for file body handler + fileTransferContent->setFileUrl((const char *)file_url); // Set file url in the file transfer content for the download + + // Link the FileContent to the FileTransferContent + fileTransferContent->setFileContent(fileContent); + + xmlFree(file_url); +} + +static void _chat_message_on_recv_body (belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset, uint8_t *buffer, size_t size) { + FileTransferChatMessageModifier *d = (FileTransferChatMessageModifier *)data; + d->onRecvBody(bh, m, offset, buffer, size); +} + +void FileTransferChatMessageModifier::onRecvBody (belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, size_t offset, uint8_t *buffer, size_t size) { + int retval = -1; + uint8_t *decrypted_buffer = nullptr; + + /*if (!chatRoom.lock()) { + q->cancelFileTransfer(); + return; + }*/ + + if (!httpRequest || belle_http_request_is_cancelled(httpRequest)) { + lWarning() << "Cancelled request for msg [" << this << "], ignoring " << __FUNCTION__; + return; + } + + // first call may be with a zero size, ignore it + if (size == 0) { + return; + } + + decrypted_buffer = (uint8_t *)ms_malloc0(size); + + LinphoneImEncryptionEngine *imee = nullptr; + shared_ptr core = chatMessage->getCore(); + if (core) + imee = linphone_core_get_im_encryption_engine(core->getCCore()); + + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); + if (cb_process_downloading_file) { + retval = cb_process_downloading_file(imee, L_GET_C_BACK_PTR(chatMessage), offset, (const uint8_t *)buffer, size, decrypted_buffer); + if (retval == 0) { + memcpy(buffer, decrypted_buffer, size); + } + } + } + ms_free(decrypted_buffer); + + if (retval <= 0) { + if (currentFileContentToTransfer->getFilePath().empty()) { + LinphoneChatMessage *msg = L_GET_C_BACK_PTR(chatMessage); + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); + LinphoneContent *content = currentFileContentToTransfer->toLinphoneContent(); + if (linphone_chat_message_cbs_get_file_transfer_recv(cbs)) { + LinphoneBuffer *lb = linphone_buffer_new_from_data(buffer, size); + linphone_chat_message_cbs_get_file_transfer_recv(cbs)(msg, content, lb); + linphone_buffer_unref(lb); + } else { + // Legacy: call back given by application level + linphone_core_notify_file_transfer_recv(core->getCCore(), msg, content, (const char *)buffer, size); + } + linphone_content_unref(content); + } + } else { + lWarning() << "File transfer decrypt failed with code " << (int)retval; + chatMessage->getPrivate()->setState(ChatMessage::State::FileTransferError); + } +} + +static void _chat_message_on_recv_end (belle_sip_user_body_handler_t *bh, void *data) { + FileTransferChatMessageModifier *d = (FileTransferChatMessageModifier *)data; + d->onRecvEnd(bh); +} + +void FileTransferChatMessageModifier::onRecvEnd (belle_sip_user_body_handler_t *bh) { + shared_ptr core = chatMessage->getCore(); + if (!core) + return; + + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(core->getCCore()); + int retval = -1; + + if (imee) { + LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); + LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); + if (cb_process_downloading_file) { + retval = cb_process_downloading_file(imee, L_GET_C_BACK_PTR(chatMessage), 0, nullptr, 0, nullptr); + } + } + + if (retval <= 0) { + if (currentFileContentToTransfer->getFilePath().empty()) { + LinphoneChatMessage *msg = L_GET_C_BACK_PTR(chatMessage); + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); + LinphoneContent *content = currentFileContentToTransfer->toLinphoneContent(); + if (linphone_chat_message_cbs_get_file_transfer_recv(cbs)) { + LinphoneBuffer *lb = linphone_buffer_new(); + linphone_chat_message_cbs_get_file_transfer_recv(cbs)(msg, content, lb); + linphone_buffer_unref(lb); + } else { + // Legacy: call back given by application level + linphone_core_notify_file_transfer_recv(core->getCCore(), msg, content, nullptr, 0); + } + linphone_content_unref(content); + } + } + + if (retval <= 0 && chatMessage->getState() != ChatMessage::State::FileTransferError) { + // Remove the FileTransferContent from the message and store the FileContent + FileContent *fileContent = currentFileContentToTransfer; + chatMessage->addContent(fileContent); + for (Content *content : chatMessage->getContents()) { + if (content->getContentType() == ContentType::FileTransfer) { + FileTransferContent *fileTransferContent = (FileTransferContent*)content; + if (fileTransferContent->getFileContent() == fileContent) { + chatMessage->removeContent(content); + free(fileTransferContent); + break; + } + } + } + chatMessage->getPrivate()->setState(ChatMessage::State::FileTransferDone); + } +} + +static void _chat_process_response_headers_from_get_file (void *data, const belle_http_response_event_t *event) { + FileTransferChatMessageModifier *d = (FileTransferChatMessageModifier *)data; + d->processResponseHeadersFromGetFile(event); +} + +static FileContent* createFileTransferInformationFromHeaders (const belle_sip_message_t *m) { + FileContent *fileContent = new FileContent(); + + belle_sip_header_content_length_t *content_length_hdr = BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(m, "Content-Length")); + belle_sip_header_content_type_t *content_type_hdr = BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(m, "Content-Type")); + const char *type = nullptr, *subtype = nullptr; + + if (content_type_hdr) { + type = belle_sip_header_content_type_get_type(content_type_hdr); + subtype = belle_sip_header_content_type_get_subtype(content_type_hdr); + lInfo() << "Extracted content type " << type << " / " << subtype << " from header"; + ContentType contentType(type, subtype); + fileContent->setContentType(contentType); + } + if (content_length_hdr) { + fileContent->setFileSize(belle_sip_header_content_length_get_content_length(content_length_hdr)); + lInfo() << "Extracted content length " << fileContent->getFileSize() << " from header"; + } + + return fileContent; +} + +void FileTransferChatMessageModifier::processResponseHeadersFromGetFile (const belle_http_response_event_t *event) { + if (event->response) { + // we are receiving a response, set a specific body handler to acquire the response. + // if not done, belle-sip will create a memory body handler, the default + belle_sip_message_t *response = BELLE_SIP_MESSAGE(event->response); + belle_sip_body_handler_t *body_handler = nullptr; + size_t body_size = 0; + + if (currentFileContentToTransfer == nullptr) { + lWarning() << "No file transfer information for msg [" << this << "]: creating..."; + FileContent *content = createFileTransferInformationFromHeaders(response); + chatMessage->addContent(content); + } else { + belle_sip_header_content_length_t *content_length_hdr = BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(response, "Content-Length")); + currentFileContentToTransfer->setFileSize(belle_sip_header_content_length_get_content_length(content_length_hdr)); + lInfo() << "Extracted content length " << currentFileContentToTransfer->getFileSize() << " from header"; + } + + if (currentFileContentToTransfer) { + body_size = currentFileContentToTransfer->getFileSize(); + } + + body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, _chat_message_file_transfer_on_progress, + nullptr, _chat_message_on_recv_body, + nullptr, _chat_message_on_recv_end, this); + if (!currentFileContentToTransfer->getFilePath().empty()) { + belle_sip_user_body_handler_t *bh = (belle_sip_user_body_handler_t *)body_handler; + body_handler = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(currentFileContentToTransfer->getFilePath().c_str(), _chat_message_file_transfer_on_progress, this); + if (belle_sip_body_handler_get_size((belle_sip_body_handler_t *)body_handler) == 0) { + // If the size of the body has not been initialized from the file stat, use the one from the + // file_transfer_information. + belle_sip_body_handler_set_size((belle_sip_body_handler_t *)body_handler, body_size); + } + belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)body_handler, bh); + } + belle_sip_message_set_body_handler((belle_sip_message_t *)event->response, body_handler); + } +} + +static void _chat_message_process_auth_requested_download (void *data, belle_sip_auth_event *event) { + FileTransferChatMessageModifier *d = (FileTransferChatMessageModifier *)data; + d->processAuthRequestedDownload(event); +} + +void FileTransferChatMessageModifier::processAuthRequestedDownload (const belle_sip_auth_event *event) { + lError() << "Error during file download : auth requested for msg [" << this << "]"; + chatMessage->updateState(ChatMessage::State::FileTransferError); + releaseHttpRequest(); +} + +static void _chat_message_process_io_error_download (void *data, const belle_sip_io_error_event_t *event) { + FileTransferChatMessageModifier *d = (FileTransferChatMessageModifier *)data; + d->processIoErrorDownload(event); +} + +void FileTransferChatMessageModifier::processIoErrorDownload (const belle_sip_io_error_event_t *event) { + lError() << "I/O Error during file download msg [" << this << "]"; + chatMessage->updateState(ChatMessage::State::FileTransferError); + releaseHttpRequest(); +} + +static void _chat_message_process_response_from_get_file (void *data, const belle_http_response_event_t *event) { + FileTransferChatMessageModifier *d = (FileTransferChatMessageModifier *)data; + d->processResponseFromGetFile(event); +} + +void FileTransferChatMessageModifier::processResponseFromGetFile (const belle_http_response_event_t *event) { + // check the answer code + if (event->response) { + int code = belle_http_response_get_status_code(event->response); + if (code >= 400 && code < 500) { + lWarning() << "File transfer failed with code " << code; + chatMessage->getPrivate()->setState(ChatMessage::State::FileTransferError); + } else if (code != 200) { + lWarning() << "Unhandled HTTP code response " << code << " for file transfer"; + } + releaseHttpRequest(); + } +} + +int FileTransferChatMessageModifier::downloadFile(const shared_ptr &message, FileTransferContent *fileTransferContent) { + chatMessage = message; + + if (httpRequest) { + lError() << "linphone_chat_message_download_file(): there is already a download in progress"; + return -1; + } + + if (fileTransferContent->getContentType() != ContentType::FileTransfer) { + lError() << "linphone_chat_message_download_file(): content type is not FileTransfer"; + return -1; + } + + createFileTransferInformationsFromVndGsmaRcsFtHttpXml(fileTransferContent); + FileContent *fileContent = fileTransferContent->getFileContent(); + currentFileContentToTransfer = fileContent; + if (currentFileContentToTransfer == nullptr) { + return -1; + } + + // THIS IS ONLY FOR BACKWARD C API COMPAT + if (currentFileContentToTransfer->getFilePath().empty() && !chatMessage->getFileTransferFilepath().empty()) { + currentFileContentToTransfer->setFilePath(chatMessage->getFileTransferFilepath()); + } + + belle_http_request_listener_callbacks_t cbs = { 0 }; + cbs.process_response_headers = _chat_process_response_headers_from_get_file; + cbs.process_response = _chat_message_process_response_from_get_file; + cbs.process_io_error = _chat_message_process_io_error_download; + cbs.process_auth_requested = _chat_message_process_auth_requested_download; + int err = startHttpTransfer(fileTransferContent->getFileUrl(), "GET", &cbs); // File URL has been set by createFileTransferInformationsFromVndGsmaRcsFtHttpXml + + if (err == -1) return -1; + // start the download, status is In Progress + chatMessage->getPrivate()->setState(ChatMessage::State::InProgress); + return 0; +} // ---------------------------------------------------------- +void FileTransferChatMessageModifier::cancelFileTransfer () { + if (httpRequest) { + if (!belle_http_request_is_cancelled(httpRequest)) { + if (chatRoom) { + shared_ptr core = chatRoom->getCore(); + lInfo() << "Canceling file transfer " << ( + currentFileContentToTransfer->getFilePath().empty() + ? linphone_core_get_file_transfer_server(core->getCCore()) + : currentFileContentToTransfer->getFilePath().c_str() + ); + belle_http_provider_cancel_request(core->getCCore()->http_provider, httpRequest); + } else { + lInfo() << "Warning: http request still running for ORPHAN msg: this is a memory leak"; + } + } + releaseHttpRequest(); + } else { + lInfo() << "No existing file transfer - nothing to cancel"; + } +} + bool FileTransferChatMessageModifier::isFileTransferInProgressAndValid () { return httpRequest && !belle_http_request_is_cancelled(httpRequest); } diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.h b/src/chat/modifier/file-transfer-chat-message-modifier.h index c17dba5b2..81c67cf76 100644 --- a/src/chat/modifier/file-transfer-chat-message-modifier.h +++ b/src/chat/modifier/file-transfer-chat-message-modifier.h @@ -34,6 +34,9 @@ public: Result encode (const std::shared_ptr &message, int &errorCode) override; Result decode (const std::shared_ptr &message, int &errorCode) override; + + belle_http_request_t *getHttpRequest() const; + void setHttpRequest(belle_http_request_t *request); int onSendBody (belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, size_t offset, uint8_t *buffer, size_t *size); void onSendEnd (belle_sip_user_body_handler_t *bh); @@ -43,6 +46,17 @@ public: void processIoErrorUpload (const belle_sip_io_error_event_t *event); void processAuthRequestedUpload (const belle_sip_auth_event *event); + void onRecvBody(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, size_t offset, uint8_t *buffer, size_t size); + void onRecvEnd(belle_sip_user_body_handler_t *bh); + void processResponseHeadersFromGetFile(const belle_http_response_event_t *event); + void processAuthRequestedDownload(const belle_sip_auth_event *event); + void processIoErrorDownload(const belle_sip_io_error_event_t *event); + void processResponseFromGetFile(const belle_http_response_event_t *event); + + int downloadFile(const std::shared_ptr &message, FileTransferContent *fileTransferContent); + void cancelFileTransfer(); + bool isFileTransferInProgressAndValid(); + private: std::shared_ptr chatRoom; std::shared_ptr chatMessage; @@ -56,7 +70,6 @@ private: void fileUploadBeginBackgroundTask(); void fileUploadEndBackgroundTask(); - bool isFileTransferInProgressAndValid(); void releaseHttpRequest(); }; From 6ef85b29d7dbf212f6c35bdbf8635db29e52e310 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 9 Nov 2017 10:16:39 +0100 Subject: [PATCH 0745/2215] feat(MainDb): provide a way to invalid events from query --- src/db/main-db-p.h | 1 + src/db/main-db.cpp | 56 ++++++++++++++++++++++++--------------- src/event-log/event-log.h | 1 + 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 290c0d42f..fb30249f0 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -113,6 +113,7 @@ private: // --------------------------------------------------------------------------- std::shared_ptr getEventFromCache (long long eventId) const; + void invalidEventsFromQuery (const std::string &query, const std::string &peerAddress); L_DECLARE_PUBLIC(MainDb); }; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 79a6a211d..d7b194bf1 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -89,8 +89,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), ) { L_ASSERT( find_if(filters.cbegin(), filters.cend(), [](const MainDb::Filter &filter) { - return filter == MainDb::NoFilter; - }) == filters.cend() + return filter == MainDb::NoFilter; + }) == filters.cend() ); if (mask == MainDb::NoFilter) @@ -134,7 +134,6 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), void MainDbPrivate::insertContent (long long eventId, const Content &content) { L_Q(); - soci::session *session = dbSession.getBackendSession(); long long contentTypeId = insertContentType(content.getContentType().asString()); @@ -253,15 +252,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } shared_ptr MainDbPrivate::selectConferenceEvent ( - long long eventId, + long long, EventLog::Type type, time_t date, const string &peerAddress ) const { - // Useless here. - (void)eventId; - - // TODO: Use cache. return make_shared( type, date, @@ -352,7 +347,6 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " AND participant_address.id = participant_address_id", soci::into(notifyId), soci::into(participantAddress), soci::use(eventId); - // TODO: Use cache. return make_shared( type, date, @@ -383,7 +377,6 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " AND gruu_address.id = gruu_address_id", soci::into(notifyId), soci::into(participantAddress), soci::into(gruuAddress), soci::use(eventId); - // TODO: Use cache. return make_shared( type, date, @@ -410,7 +403,6 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " AND conference_notified_event.event_id = conference_subject_event.event_id", soci::into(notifyId), soci::into(subject), soci::use(eventId); - // TODO: Use cache. return make_shared( date, Address(peerAddress), @@ -478,7 +470,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::use(static_cast(chatMessage->getState())), soci::use(static_cast(chatMessage->getDirection())), soci::use(chatMessage->getImdnMessageId()), soci::use(chatMessage->isSecured() ? 1 : 0); - for (Content *content : chatMessage->getContents()) + for (const Content *content : chatMessage->getContents()) insertContent(eventId, *content); return eventId; @@ -549,6 +541,23 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return eventLog; } + void MainDbPrivate::invalidEventsFromQuery (const string &query, const string &peerAddress) { + L_Q(); + + soci::session *session = dbSession.getBackendSession(); + soci::rowset rows = (session->prepare << query, soci::use(peerAddress)); + for (const auto &row : rows) { + shared_ptr eventLog = getEventFromCache( + q->getBackend() == AbstractDb::Sqlite3 ? static_cast(row.get(0)) : row.get(0) + ); + if (eventLog) { + const EventLogPrivate *dEventLog = eventLog->getPrivate(); + L_ASSERT(dEventLog->dbKey.isValid()); + dEventLog->dbKey = MainDbEventKey(); + } + } + } + // ----------------------------------------------------------------------------- void MainDb::init () { @@ -1154,19 +1163,15 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return; } - // TODO: Deal with mask. - - string query; - if (mask == MainDb::NoFilter || mask & ConferenceChatMessageFilter) - query += "SELECT event_id FROM conference_event WHERE chat_room_id = (" - " SELECT id FROM sip_address WHERE value = :peerAddress" - ")"; - - if (query.empty()) - return; + string query = "SELECT event_id FROM conference_event WHERE chat_room_id = (" + " SELECT id FROM sip_address WHERE value = :peerAddress" + ")" + buildSqlEventFilter({ + ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter + }, mask); L_BEGIN_LOG_EXCEPTION + d->invalidEventsFromQuery(query, peerAddress); soci::session *session = d->dbSession.getBackendSession(); *session << "DELETE FROM event WHERE id IN (" + query + ")", soci::use(peerAddress); @@ -1272,6 +1277,13 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), L_BEGIN_LOG_EXCEPTION + d->invalidEventsFromQuery( + "SELECT event_id FROM conference_event WHERE chat_room_id = (" + " SELECT id FROM sip_address WHERE value = :peerAddress" + ")", + peerAddress + ); + soci::session *session = d->dbSession.getBackendSession(); *session << "DELETE FROM chat_room WHERE peer_sip_address_id = (" " SELECT id FROM sip_address WHERE value = :peerAddress" diff --git a/src/event-log/event-log.h b/src/event-log/event-log.h index 3134421e8..9e43aec8c 100644 --- a/src/event-log/event-log.h +++ b/src/event-log/event-log.h @@ -35,6 +35,7 @@ class EventLogPrivate; class LINPHONE_PUBLIC EventLog : public BaseObject { friend class MainDb; + friend class MainDbPrivate; public: L_DECLARE_ENUM(Type, L_ENUM_VALUES_EVENT_LOG_TYPE); From f2af53f2d3255a9cecf58c6d396e986a062fc5af Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 9 Nov 2017 11:10:12 +0100 Subject: [PATCH 0746/2215] feat(MainDb): force utf8 charset --- src/db/main-db.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index d7b194bf1..e412dcc95 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -568,20 +568,20 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), "CREATE TABLE IF NOT EXISTS sip_address (" " id" + primaryKeyStr("BIGINT UNSIGNED") + "," " value VARCHAR(255) UNIQUE NOT NULL" - ")"; + ") DEFAULT CHARSET=utf8"; *session << "CREATE TABLE IF NOT EXISTS content_type (" " id" + primaryKeyStr("SMALLINT UNSIGNED") + "," " value VARCHAR(255) UNIQUE NOT NULL" - ")"; + ") DEFAULT CHARSET=utf8"; *session << "CREATE TABLE IF NOT EXISTS event (" " id" + primaryKeyStr("BIGINT UNSIGNED") + "," " type TINYINT UNSIGNED NOT NULL," " date DATE NOT NULL" - ")"; + ") DEFAULT CHARSET=utf8"; *session << "CREATE TABLE IF NOT EXISTS chat_room (" @@ -605,7 +605,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (peer_sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" - ")"; + ") DEFAULT CHARSET=utf8"; *session << "CREATE TABLE IF NOT EXISTS chat_room_participant (" @@ -621,7 +621,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" - ")"; + ") DEFAULT CHARSET=utf8"; *session << "CREATE TABLE IF NOT EXISTS conference_event (" @@ -635,7 +635,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (chat_room_id)" " REFERENCES chat_room(peer_sip_address_id)" " ON DELETE CASCADE" - ")"; + ") DEFAULT CHARSET=utf8"; *session << "CREATE TABLE IF NOT EXISTS conference_notified_event (" @@ -646,7 +646,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (event_id)" " REFERENCES conference_event(event_id)" " ON DELETE CASCADE" - ")"; + ") DEFAULT CHARSET=utf8"; *session << "CREATE TABLE IF NOT EXISTS conference_participant_event (" @@ -660,7 +660,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (participant_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" - ")"; + ") DEFAULT CHARSET=utf8"; *session << "CREATE TABLE IF NOT EXISTS conference_participant_device_event (" @@ -674,7 +674,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (gruu_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" - ")"; + ") DEFAULT CHARSET=utf8"; *session << "CREATE TABLE IF NOT EXISTS conference_subject_event (" @@ -685,7 +685,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (event_id)" " REFERENCES conference_notified_event(event_id)" " ON DELETE CASCADE" - ")"; + ") DEFAULT CHARSET=utf8"; *session << "CREATE TABLE IF NOT EXISTS conference_chat_message_event (" @@ -710,7 +710,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (remote_sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" - ")"; + ") DEFAULT CHARSET=utf8"; *session << "CREATE TABLE IF NOT EXISTS chat_message_participant (" @@ -725,7 +725,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" - ")"; + ") DEFAULT CHARSET=utf8"; *session << "CREATE TABLE IF NOT EXISTS chat_message_content (" @@ -741,7 +741,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (content_type_id)" " REFERENCES content_type(id)" " ON DELETE CASCADE" - ")"; + ") DEFAULT CHARSET=utf8"; *session << "CREATE TABLE IF NOT EXISTS chat_message_file_content (" @@ -754,7 +754,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (chat_message_content_id)" " REFERENCES chat_message_content(id)" " ON DELETE CASCADE" - ")"; + ") DEFAULT CHARSET=utf8"; *session << "CREATE TABLE IF NOT EXISTS chat_message_content_app_data (" @@ -767,7 +767,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (chat_message_content_id)" " REFERENCES chat_message_content(id)" " ON DELETE CASCADE" - ")"; + ") DEFAULT CHARSET=utf8"; *session << "CREATE TABLE IF NOT EXISTS conference_message_crypto_data (" @@ -780,7 +780,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (event_id)" " REFERENCES conference_chat_message_event(event_id)" " ON DELETE CASCADE" - ")"; + ") DEFAULT CHARSET=utf8"; // Trigger to delete participant_message cache entries. string displayedId = Utils::toString(static_cast(ChatMessage::State::Displayed)); From a77734766bb0dd9d99a70e9a22949b1056035ec9 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 9 Nov 2017 11:25:37 +0100 Subject: [PATCH 0747/2215] fix(MainDb): use utf8 charset only on Mysql --- src/db/main-db.cpp | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index e412dcc95..1226e59bc 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -562,26 +562,28 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), void MainDb::init () { L_D(); + + const string charset = getBackend() == Mysql ? "DEFAULT CHARSET=utf8" : ""; soci::session *session = d->dbSession.getBackendSession(); *session << "CREATE TABLE IF NOT EXISTS sip_address (" " id" + primaryKeyStr("BIGINT UNSIGNED") + "," " value VARCHAR(255) UNIQUE NOT NULL" - ") DEFAULT CHARSET=utf8"; + ") " + charset; *session << "CREATE TABLE IF NOT EXISTS content_type (" " id" + primaryKeyStr("SMALLINT UNSIGNED") + "," " value VARCHAR(255) UNIQUE NOT NULL" - ") DEFAULT CHARSET=utf8"; + ") " + charset; *session << "CREATE TABLE IF NOT EXISTS event (" " id" + primaryKeyStr("BIGINT UNSIGNED") + "," " type TINYINT UNSIGNED NOT NULL," " date DATE NOT NULL" - ") DEFAULT CHARSET=utf8"; + ") " + charset; *session << "CREATE TABLE IF NOT EXISTS chat_room (" @@ -605,7 +607,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (peer_sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" - ") DEFAULT CHARSET=utf8"; + ") " + charset; *session << "CREATE TABLE IF NOT EXISTS chat_room_participant (" @@ -621,7 +623,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" - ") DEFAULT CHARSET=utf8"; + ") " + charset; *session << "CREATE TABLE IF NOT EXISTS conference_event (" @@ -635,7 +637,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (chat_room_id)" " REFERENCES chat_room(peer_sip_address_id)" " ON DELETE CASCADE" - ") DEFAULT CHARSET=utf8"; + ") " + charset; *session << "CREATE TABLE IF NOT EXISTS conference_notified_event (" @@ -646,7 +648,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (event_id)" " REFERENCES conference_event(event_id)" " ON DELETE CASCADE" - ") DEFAULT CHARSET=utf8"; + ") " + charset; *session << "CREATE TABLE IF NOT EXISTS conference_participant_event (" @@ -660,7 +662,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (participant_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" - ") DEFAULT CHARSET=utf8"; + ") " + charset; *session << "CREATE TABLE IF NOT EXISTS conference_participant_device_event (" @@ -674,7 +676,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (gruu_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" - ") DEFAULT CHARSET=utf8"; + ") " + charset; *session << "CREATE TABLE IF NOT EXISTS conference_subject_event (" @@ -685,7 +687,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (event_id)" " REFERENCES conference_notified_event(event_id)" " ON DELETE CASCADE" - ") DEFAULT CHARSET=utf8"; + ") " + charset; *session << "CREATE TABLE IF NOT EXISTS conference_chat_message_event (" @@ -710,7 +712,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (remote_sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" - ") DEFAULT CHARSET=utf8"; + ") " + charset; *session << "CREATE TABLE IF NOT EXISTS chat_message_participant (" @@ -725,7 +727,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" - ") DEFAULT CHARSET=utf8"; + ") " + charset; *session << "CREATE TABLE IF NOT EXISTS chat_message_content (" @@ -741,7 +743,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (content_type_id)" " REFERENCES content_type(id)" " ON DELETE CASCADE" - ") DEFAULT CHARSET=utf8"; + ") " + charset; *session << "CREATE TABLE IF NOT EXISTS chat_message_file_content (" @@ -754,7 +756,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (chat_message_content_id)" " REFERENCES chat_message_content(id)" " ON DELETE CASCADE" - ") DEFAULT CHARSET=utf8"; + ") " + charset; *session << "CREATE TABLE IF NOT EXISTS chat_message_content_app_data (" @@ -767,7 +769,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (chat_message_content_id)" " REFERENCES chat_message_content(id)" " ON DELETE CASCADE" - ") DEFAULT CHARSET=utf8"; + ") " + charset; *session << "CREATE TABLE IF NOT EXISTS conference_message_crypto_data (" @@ -780,7 +782,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (event_id)" " REFERENCES conference_chat_message_event(event_id)" " ON DELETE CASCADE" - ") DEFAULT CHARSET=utf8"; + ") " + charset; // Trigger to delete participant_message cache entries. string displayedId = Utils::toString(static_cast(ChatMessage::State::Displayed)); From bb0b486a0eb0eb5bf42ac8c3b0a6e35cb26a4b06 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 9 Nov 2017 11:39:45 +0100 Subject: [PATCH 0748/2215] Use LinphoneEvent from the SUBSCRIBE to send all NOTIFY messages in the LocalConferenceEventHandler. --- .../local-conference-event-handler-p.h | 10 ++-- .../local-conference-event-handler.cpp | 59 ++++++++----------- src/conference/participant-p.h | 9 +-- src/conference/participant.cpp | 17 ++++++ 4 files changed, 52 insertions(+), 43 deletions(-) diff --git a/src/conference/local-conference-event-handler-p.h b/src/conference/local-conference-event-handler-p.h index 88e26d437..55fefde4e 100644 --- a/src/conference/local-conference-event-handler-p.h +++ b/src/conference/local-conference-event-handler-p.h @@ -28,12 +28,14 @@ LINPHONE_BEGIN_NAMESPACE +class Participant; + class LocalConferenceEventHandlerPrivate : public ObjectPrivate { public: - void notifyFullState (const std::string ¬ify, LinphoneEvent *lev); - void notifyAllExcept (const std::string ¬ify, const Address &addr); + void notifyFullState (const std::string ¬ify, const std::shared_ptr &participant); + void notifyAllExcept (const std::string ¬ify, const std::shared_ptr &exceptParticipant); void notifyAll (const std::string ¬ify); - void notifyParticipant (const std::string ¬ify, const Address &addr); + void notifyParticipant (const std::string ¬ify, const std::shared_ptr &participant); std::string createNotifyFullState (int notifyId = -1); std::string createNotifyParticipantAdded (const Address &addr, int notifyId = -1); std::string createNotifyParticipantRemoved (const Address &addr, int notifyId = -1); @@ -50,7 +52,7 @@ private: unsigned int lastNotify = 0; std::string createNotify (Xsd::ConferenceInfo::ConferenceType confInfo, int notifyId = -1, bool isFullState = false); - void sendNotify (const std::string ¬ify, const Address &addr); + void sendNotify (const std::string ¬ify, const std::shared_ptr &participant); L_DECLARE_PUBLIC(LocalConferenceEventHandler); }; diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 518dd4abe..93e970114 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -37,39 +37,25 @@ using namespace Xsd::ConferenceInfo; // ----------------------------------------------------------------------------- -static void doNotify (const string ¬ify, LinphoneEvent *lev) { - LinphoneContent *content = linphone_core_create_content(lev->lc); - linphone_content_set_buffer(content, (const uint8_t *)notify.c_str(), strlen(notify.c_str())); - linphone_event_notify(lev, content); - linphone_content_unref(content); +void LocalConferenceEventHandlerPrivate::notifyFullState (const string ¬ify, const shared_ptr &participant) { + sendNotify(notify, participant); } -// ----------------------------------------------------------------------------- - -void LocalConferenceEventHandlerPrivate::notifyFullState (const string ¬ify, LinphoneEvent *lev) { - doNotify(notify, lev); -} - -void LocalConferenceEventHandlerPrivate::notifyAllExcept (const string ¬ify, const Address &addr) { - SimpleAddress simpleAddr(addr); +void LocalConferenceEventHandlerPrivate::notifyAllExcept (const string ¬ify, const shared_ptr &exceptParticipant) { for (const auto &participant : conf->getParticipants()) { - if (participant->getPrivate()->isSubscribedToConferenceEventPackage() && (participant->getAddress() != simpleAddr)) - sendNotify(notify, participant->getContactAddress()); + if (participant->getPrivate()->isSubscribedToConferenceEventPackage() && (participant != exceptParticipant)) + sendNotify(notify, participant); } } void LocalConferenceEventHandlerPrivate::notifyAll (const string ¬ify) { - for (const auto &participant : conf->getParticipants()) { - if (participant->getPrivate()->isSubscribedToConferenceEventPackage()) - sendNotify(notify, participant->getContactAddress()); - } + for (const auto &participant : conf->getParticipants()) + notifyParticipant(notify, participant); } -void LocalConferenceEventHandlerPrivate::notifyParticipant (const string ¬ify, const Address &addr) { - SimpleAddress simpleAddr(addr); - shared_ptr participant = conf->findParticipant(simpleAddr); +void LocalConferenceEventHandlerPrivate::notifyParticipant (const string ¬ify, const shared_ptr &participant) { if (participant->getPrivate()->isSubscribedToConferenceEventPackage()) - sendNotify(notify, participant->getContactAddress()); + sendNotify(notify, participant); } string LocalConferenceEventHandlerPrivate::createNotify (ConferenceType confInfo, int notifyId, bool isFullState) { @@ -249,13 +235,14 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceRemoved return createNotify(confInfo, notifyId); } -void LocalConferenceEventHandlerPrivate::sendNotify (const string ¬ify, const Address &addr) { - LinphoneAddress *cAddr = linphone_address_new(addr.asString().c_str()); - LinphoneEvent *lev = linphone_core_create_notify(core, cAddr, "conference"); - // Fix the From header to put the chat room URI - lev->op->set_from(conf->getConferenceAddress().asString().c_str()); - linphone_address_unref(cAddr); - doNotify(notify, lev); +void LocalConferenceEventHandlerPrivate::sendNotify (const string ¬ify, const shared_ptr &participant) { + LinphoneEvent *ev = participant->getPrivate()->getConferenceSubscribeEvent(); + if (!ev) + return; + LinphoneContent *content = linphone_core_create_content(ev->lc); + linphone_content_set_buffer(content, (const uint8_t *)notify.c_str(), strlen(notify.c_str())); + linphone_event_notify(ev, content); + linphone_content_unref(content); } // ============================================================================= @@ -286,8 +273,8 @@ void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) { unsigned int lastNotify = static_cast(Utils::stoi(linphone_event_get_custom_header(lev, "Last-Notify-Version"))); if (lastNotify == 0) { lInfo() << "Sending initial notify of conference:" << d->conf->getConferenceAddress().asStringUriOnly() << " to: " << addrStr; - participant->getPrivate()->subscribeToConferenceEventPackage(true); - d->notifyFullState(d->createNotifyFullState(), lev); + participant->getPrivate()->setConferenceSubscribeEvent(lev); + d->notifyFullState(d->createNotifyFullState(), participant); } else if (lastNotify < d->lastNotify) { lInfo() << "Sending all missed notify for conference:" << d->conf->getConferenceAddress().asStringUriOnly() << " from: " << lastNotify << " to: " << addrStr; @@ -298,18 +285,20 @@ void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) { " should not be higher than last notify sent by server: [" << d->lastNotify << "]."; } } else if (linphone_event_get_subscription_state(lev) == LinphoneSubscriptionTerminated) - participant->getPrivate()->subscribeToConferenceEventPackage(false); + participant->getPrivate()->setConferenceSubscribeEvent(nullptr); } } void LocalConferenceEventHandler::notifyParticipantAdded (const Address &addr) { L_D(); - d->notifyAllExcept(d->createNotifyParticipantAdded(addr), addr); + shared_ptr participant = d->conf->findParticipant(addr); + d->notifyAllExcept(d->createNotifyParticipantAdded(addr), participant); } void LocalConferenceEventHandler::notifyParticipantRemoved (const Address &addr) { L_D(); - d->notifyAllExcept(d->createNotifyParticipantRemoved(addr), addr); + shared_ptr participant = d->conf->findParticipant(addr); + d->notifyAllExcept(d->createNotifyParticipantRemoved(addr), participant); } void LocalConferenceEventHandler::notifyParticipantSetAdmin (const Address &addr, bool isAdmin) { diff --git a/src/conference/participant-p.h b/src/conference/participant-p.h index 58993cd97..a412d4cb7 100644 --- a/src/conference/participant-p.h +++ b/src/conference/participant-p.h @@ -37,12 +37,13 @@ LINPHONE_BEGIN_NAMESPACE class ParticipantPrivate : public ObjectPrivate { public: - virtual ~ParticipantPrivate () = default; + virtual ~ParticipantPrivate (); std::shared_ptr createSession (const Conference &conference, const CallSessionParams *params, bool hasMedia, CallSessionListener *listener); inline std::shared_ptr getSession () const { return session; } - inline bool isSubscribedToConferenceEventPackage () const { return _isSubscribedToConferenceEventPackage; } - inline void subscribeToConferenceEventPackage (bool value) { _isSubscribedToConferenceEventPackage = value; } + inline bool isSubscribedToConferenceEventPackage () const { return conferenceSubscribeEvent != nullptr; } + LinphoneEvent *getConferenceSubscribeEvent () const { return conferenceSubscribeEvent; } + void setConferenceSubscribeEvent (LinphoneEvent *ev); inline void removeSession () { session.reset(); } inline void setAddress (const SimpleAddress &newAddr) { addr = newAddr; } inline void setAdmin (bool isAdmin) { this->isAdmin = isAdmin; } @@ -56,7 +57,7 @@ private: SimpleAddress addr; Address contactAddr; bool isAdmin = false; - bool _isSubscribedToConferenceEventPackage = false; + LinphoneEvent *conferenceSubscribeEvent = nullptr; std::shared_ptr session; std::list devices; diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index cf2e370b4..289b483d0 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -26,12 +26,21 @@ #include "params/media-session-params.h" #include "session/media-session.h" +#include "linphone/event.h" + using namespace std; LINPHONE_BEGIN_NAMESPACE // ============================================================================= +ParticipantPrivate::~ParticipantPrivate () { + if (conferenceSubscribeEvent) + linphone_event_unref(conferenceSubscribeEvent); +} + +// ----------------------------------------------------------------------------- + shared_ptr ParticipantPrivate::createSession ( const Conference &conference, const CallSessionParams *params, bool hasMedia, CallSessionListener *listener ) { @@ -45,6 +54,14 @@ shared_ptr ParticipantPrivate::createSession ( // ----------------------------------------------------------------------------- +void ParticipantPrivate::setConferenceSubscribeEvent (LinphoneEvent *ev) { + if (conferenceSubscribeEvent) + linphone_event_unref(conferenceSubscribeEvent); + conferenceSubscribeEvent = linphone_event_ref(ev); +} + +// ----------------------------------------------------------------------------- + const list::const_iterator ParticipantPrivate::findDevice (const Address &gruu) const { ParticipantDevice device(gruu); return find(devices.cbegin(), devices.cend(), device); From deb7f90ab93ae73b55ebd20b50c530e6945582a9 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 9 Nov 2017 11:44:35 +0100 Subject: [PATCH 0749/2215] Prevent adding ourselves as a participant of a client group chat room. --- src/chat/chat-room/client-group-chat-room.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index d04aedf98..3422a19b7 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -45,7 +45,7 @@ list
      ClientGroupChatRoomPrivate::cleanAddressesList (const list
      findParticipant(*it)) + if (q->findParticipant(*it) || (q->getMe()->getAddress() == SimpleAddress(*it))) it = cleanedList.erase(it); else it++; From 4957187dfb7e2149cb5699da4b8cdbffac000ab2 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 9 Nov 2017 12:27:24 +0100 Subject: [PATCH 0750/2215] More cleanup in ChatMessage --- src/c-wrapper/api/c-chat-message.cpp | 16 +- src/chat/chat-message/chat-message-p.h | 19 +- src/chat/chat-message/chat-message.cpp | 171 ++++++++---------- src/chat/chat-message/chat-message.h | 12 -- src/chat/chat-room/chat-room.cpp | 4 +- .../file-transfer-chat-message-modifier.cpp | 8 +- tester/multipart-tester.cpp | 19 +- 7 files changed, 113 insertions(+), 136 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 0293b479e..c728761ee 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -98,11 +98,11 @@ LinphoneChatRoom *linphone_chat_message_get_chat_room(const LinphoneChatMessage } const char *linphone_chat_message_get_external_body_url(const LinphoneChatMessage *msg) { - return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getExternalBodyUrl()); + return L_STRING_TO_C(L_GET_PRIVATE_FROM_C_OBJECT(msg)->getExternalBodyUrl()); } void linphone_chat_message_set_external_body_url(LinphoneChatMessage *msg, const char *url) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setExternalBodyUrl(L_C_TO_STRING(url)); + } time_t linphone_chat_message_get_time(const LinphoneChatMessage *msg) { @@ -166,11 +166,11 @@ bool_t linphone_chat_message_is_read(LinphoneChatMessage *msg) { } const char *linphone_chat_message_get_appdata(const LinphoneChatMessage *msg) { - return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getAppdata()); + return L_STRING_TO_C(L_GET_PRIVATE_FROM_C_OBJECT(msg)->getAppdata()); } void linphone_chat_message_set_appdata(LinphoneChatMessage *msg, const char *data) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setAppdata(L_C_TO_STRING(data)); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setAppdata(L_C_TO_STRING(data)); } const LinphoneAddress *linphone_chat_message_get_from_address(LinphoneChatMessage *msg) { @@ -200,11 +200,11 @@ void linphone_chat_message_set_to_address(LinphoneChatMessage *msg, const Linpho } const char *linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage *msg) { - return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getFileTransferFilepath()); + return L_STRING_TO_C(L_GET_PRIVATE_FROM_C_OBJECT(msg)->getFileTransferFilepath()); } void linphone_chat_message_set_file_transfer_filepath(LinphoneChatMessage *msg, const char *filepath) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFileTransferFilepath(L_C_TO_STRING(filepath)); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setFileTransferFilepath(L_C_TO_STRING(filepath)); } belle_http_request_t * linphone_chat_message_get_http_request(LinphoneChatMessage *msg) { @@ -302,11 +302,11 @@ void linphone_chat_message_add_text_content(LinphoneChatMessage *msg, const char } bool_t linphone_chat_message_has_text_content(const LinphoneChatMessage *msg) { - return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->hasTextContent(); + return L_GET_PRIVATE_FROM_C_OBJECT(msg)->hasTextContent(); } const char * linphone_chat_message_get_text_content(const LinphoneChatMessage *msg) { - const LinphonePrivate::Content *content = L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getTextContent(); + const LinphonePrivate::Content *content = L_GET_PRIVATE_FROM_C_OBJECT(msg)->getTextContent(); if (*content == LinphonePrivate::Content::Empty) { return NULL; } diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index 3fd393d15..a4163b196 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -93,6 +93,20 @@ public: const std::string &getText(); void setText(const std::string &text); + const std::string &getFileTransferFilepath () const; + void setFileTransferFilepath (const std::string &path); + + const std::string &getAppdata () const; + void setAppdata (const std::string &appData); + + const std::string &getExternalBodyUrl () const; + + bool hasTextContent() const; + const Content* getTextContent() const; + + bool hasFileTransferContent() const; + const Content* getFileTransferContent() const; + LinphoneContent *getFileTransferInformation() const; void setFileTransferInformation(const LinphoneContent *content); @@ -115,9 +129,6 @@ private: Address to; time_t time = 0; std::string id; - std::string appData; - std::string fileTransferFilePath; - std::string externalBodyUrl; std::string rttMessage; bool isSecured = false; bool isReadOnly = false; @@ -132,6 +143,8 @@ private: FileTransferChatMessageModifier fileTransferChatMessageModifier; // Cache for returned values, used for compatibility with previous C API + std::string appData; + std::string fileTransferFilePath; ContentType cContentType; std::string cText; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index f7eeb68e4..dd5d21be3 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -157,6 +157,69 @@ string ChatMessagePrivate::getSalCustomHeaderValue (const string &name) { // Below methods are only for C API backward compatibility... // ----------------------------------------------------------------------------- +bool ChatMessagePrivate::hasTextContent() const { + for (const Content *c : contents) { + if (c->getContentType() == ContentType::PlainText) { + return true; + } + } + return false; +} + +const Content* ChatMessagePrivate::getTextContent() const { + for (const Content *c : contents) { + if (c->getContentType() == ContentType::PlainText) { + return c; + } + } + return &Content::Empty; +} + +bool ChatMessagePrivate::hasFileTransferContent() const { + for (const Content *c : contents) { + if (c->getContentType() == ContentType::FileTransfer) { + return true; + } + } + return false; +} + +const Content* ChatMessagePrivate::getFileTransferContent() const { + for (const Content *c : contents) { + if (c->getContentType() == ContentType::FileTransfer) { + return c; + } + } + return &Content::Empty; +} + +const string &ChatMessagePrivate::getFileTransferFilepath () const { + return fileTransferFilePath; +} + +void ChatMessagePrivate::setFileTransferFilepath (const string &path) { + fileTransferFilePath = path; +} + +const string &ChatMessagePrivate::getAppdata () const { + return appData; +} + +void ChatMessagePrivate::setAppdata (const string &data) { + appData = data; + + // TODO: history. + // linphone_chat_message_store_appdata(L_GET_C_BACK_PTR(this)); +} + +const string &ChatMessagePrivate::getExternalBodyUrl () const { + if (hasFileTransferContent()) { + FileTransferContent *content = (FileTransferContent*) getFileTransferContent(); + return content->getFileUrl(); + } + return Utils::getEmptyConstRefObject(); +} + const ContentType &ChatMessagePrivate::getContentType () { if (direction == ChatMessage::Direction::Incoming) { if (contents.size() > 0) { @@ -183,10 +246,9 @@ void ChatMessagePrivate::setContentType (const ContentType &contentType) { } const string &ChatMessagePrivate::getText () { - L_Q(); if (direction == ChatMessage::Direction::Incoming) { - if (q->hasTextContent()) { - cText = q->getTextContent()->getBodyAsString(); + if (hasTextContent()) { + cText = getTextContent()->getBodyAsString(); } else if (contents.size() > 0) { Content *content = contents.front(); cText = content->getBodyAsString(); @@ -194,8 +256,8 @@ const string &ChatMessagePrivate::getText () { cText = internalContent.getBodyAsString(); } } else { - if (q->hasTextContent()) { - cText = q->getTextContent()->getBodyAsString(); + if (hasTextContent()) { + cText = getTextContent()->getBodyAsString(); } else if (!internalContent.isEmpty()) { cText = internalContent.getBodyAsString(); } else { @@ -213,9 +275,8 @@ void ChatMessagePrivate::setText (const string &text) { } LinphoneContent *ChatMessagePrivate::getFileTransferInformation () const { - L_Q(); - if (q->hasFileTransferContent()) { - return q->getFileTransferContent()->toLinphoneContent(); + if (hasFileTransferContent()) { + return getFileTransferContent()->toLinphoneContent(); } return NULL; } @@ -556,18 +617,11 @@ void ChatMessagePrivate::send () { internalContent = *(contents.front()); } - if (!externalBodyUrl.empty()) { // Deprecated way of sending files - char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", externalBodyUrl.c_str()); - auto msgOp = dynamic_cast(op); - msgOp->send_message(from.asString().c_str(), to.asString().c_str(), content_type, nullptr, nullptr); - ms_free(content_type); + auto msgOp = dynamic_cast(op); + if (internalContent.getContentType().isValid()) { + msgOp->send_message(from.asString().c_str(), to.asString().c_str(), internalContent.getContentType().asString().c_str(), internalContent.getBodyAsString().c_str(), to.asStringUriOnly().c_str()); } else { - auto msgOp = dynamic_cast(op); - if (internalContent.getContentType().isValid()) { - msgOp->send_message(from.asString().c_str(), to.asString().c_str(), internalContent.getContentType().asString().c_str(), internalContent.getBodyAsString().c_str(), to.asStringUriOnly().c_str()); - } else { - msgOp->send_message(from.asString().c_str(), to.asString().c_str(), internalContent.getBodyAsString().c_str()); - } + msgOp->send_message(from.asString().c_str(), to.asString().c_str(), internalContent.getBodyAsString().c_str()); } for (Content *content : contents) { @@ -890,83 +944,4 @@ int ChatMessage::putCharacter (uint32_t character) { return -1; } -// ----------------------------------------------------------------------------- -// Below methods are only for C API backward compatibility... -// ----------------------------------------------------------------------------- - -bool ChatMessage::hasTextContent() const { - L_D(); - for (const Content *c : d->contents) { - if (c->getContentType() == ContentType::PlainText) { - return true; - } - } - return false; -} - -const Content* ChatMessage::getTextContent() const { - L_D(); - for (const Content *c : d->contents) { - if (c->getContentType() == ContentType::PlainText) { - return c; - } - } - return &Content::Empty; -} - -bool ChatMessage::hasFileTransferContent() const { - L_D(); - for (const Content *c : d->contents) { - if (c->getContentType() == ContentType::FileTransfer) { - return true; - } - } - return false; -} - -const Content* ChatMessage::getFileTransferContent() const { - L_D(); - for (const Content *c : d->contents) { - if (c->getContentType() == ContentType::FileTransfer) { - return c; - } - } - return &Content::Empty; -} - -const string &ChatMessage::getFileTransferFilepath () const { - L_D(); - return d->fileTransferFilePath; -} - -void ChatMessage::setFileTransferFilepath (const string &path) { - L_D(); - d->fileTransferFilePath = path; -} - -const string &ChatMessage::getAppdata () const { - L_D(); - return d->appData; -} - -void ChatMessage::setAppdata (const string &appData) { - L_D(); - d->appData = appData; - - // TODO: history. - // linphone_chat_message_store_appdata(L_GET_C_BACK_PTR(this)); -} - -const string &ChatMessage::getExternalBodyUrl () const { - L_D(); - return d->externalBodyUrl; -} - -void ChatMessage::setExternalBodyUrl (const string &url) { - L_D(); - d->externalBodyUrl = url; -} - -// ----------------------------------------------------------------------------- - LINPHONE_END_NAMESPACE diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index c17cb4a64..6914373f6 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -57,12 +57,6 @@ public: ChatMessage (const std::shared_ptr &chatRoom); // ----- TODO: Remove me. - const std::string &getFileTransferFilepath () const; - void setFileTransferFilepath (const std::string &path); - const std::string &getAppdata () const; - void setAppdata (const std::string &appData); - const std::string &getExternalBodyUrl () const; - void setExternalBodyUrl (const std::string &url); void cancelFileTransfer (); int putCharacter (uint32_t character); void updateState (State state); @@ -101,12 +95,6 @@ public: void addContent (Content *content); void removeContent (Content *content); - bool hasTextContent() const; - const Content* getTextContent() const; - - bool hasFileTransferContent() const; - const Content* getFileTransferContent() const; - const Content &getInternalContent () const; void setInternalContent (const Content &content); diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index c8b2f51a6..091217e49 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -284,8 +284,8 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa const SalCustomHeader *ch = op->get_recv_custom_header(); if (ch) msg->getPrivate()->setSalCustomHeaders(sal_custom_header_clone(ch)); - if (salMsg->url) - msg->setExternalBodyUrl(salMsg->url); + /*if (salMsg->url) + msg->getPrivate()->setExternalBodyUrl(salMsg->url);*/ reason = msg->getPrivate()->receive(); diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.cpp b/src/chat/modifier/file-transfer-chat-message-modifier.cpp index 5c1c053ae..6f4014c3c 100644 --- a/src/chat/modifier/file-transfer-chat-message-modifier.cpp +++ b/src/chat/modifier/file-transfer-chat-message-modifier.cpp @@ -432,8 +432,8 @@ int FileTransferChatMessageModifier::uploadFile () { } // THIS IS ONLY FOR BACKWARD C API COMPAT - if (currentFileContentToTransfer->getFilePath().empty() && !chatMessage->getFileTransferFilepath().empty()) { - currentFileContentToTransfer->setFilePath(chatMessage->getFileTransferFilepath()); + if (currentFileContentToTransfer->getFilePath().empty() && !chatMessage->getPrivate()->getFileTransferFilepath().empty()) { + currentFileContentToTransfer->setFilePath(chatMessage->getPrivate()->getFileTransferFilepath()); } belle_http_request_listener_callbacks_t cbs = { 0 }; @@ -850,8 +850,8 @@ int FileTransferChatMessageModifier::downloadFile(const shared_ptr } // THIS IS ONLY FOR BACKWARD C API COMPAT - if (currentFileContentToTransfer->getFilePath().empty() && !chatMessage->getFileTransferFilepath().empty()) { - currentFileContentToTransfer->setFilePath(chatMessage->getFileTransferFilepath()); + if (currentFileContentToTransfer->getFilePath().empty() && !chatMessage->getPrivate()->getFileTransferFilepath().empty()) { + currentFileContentToTransfer->setFilePath(chatMessage->getPrivate()->getFileTransferFilepath()); } belle_http_request_listener_callbacks_t cbs = { 0 }; diff --git a/tester/multipart-tester.cpp b/tester/multipart-tester.cpp index 3bce05fc3..d9c3b65bc 100644 --- a/tester/multipart-tester.cpp +++ b/tester/multipart-tester.cpp @@ -42,19 +42,20 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer, bool Address paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); shared_ptr marieRoom = make_shared(marie->lc->cppCore, paulineAddress); - shared_ptr marieMessage; + shared_ptr marieMessage = marieRoom->createMessage(); if (first_file_transfer) { char *send_filepath = bc_tester_res("sounds/sintel_trailer_opus_h264.mkv"); - LinphoneContent *content = linphone_core_create_content(marie->lc); - belle_sip_object_set_name(BELLE_SIP_OBJECT(content), "sintel trailer content"); - linphone_content_set_type(content,"video"); - linphone_content_set_subtype(content,"mkv"); - linphone_content_set_name(content,"sintel_trailer_opus_h264.mkv"); - marieMessage = marieRoom->createFileTransferMessage(content); - marieMessage->setFileTransferFilepath(send_filepath); + FileContent *content = new FileContent(); + content->setContentType("video/mkv"); + content->setFilePath(send_filepath); + content->setFileName("sintel_trailer_opus_h264.mkv"); + marieMessage->addContent(content); bc_free(send_filepath); } else { - marieMessage = marieRoom->createMessage("Hello Part 1"); + Content *content = new Content(); + content->setContentType(ContentType::PlainText); + content->setBody("Hello Part 1"); + marieMessage->addContent(content); } if (second_file_transfer) { From b764f9bb603bc6f42e17d93dfd5527f944cc447a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 9 Nov 2017 12:36:49 +0100 Subject: [PATCH 0751/2215] Removed appData in ChatMessage --- src/chat/chat-message/chat-message-p.h | 1 - src/chat/chat-message/chat-message.cpp | 18 +++++++++++++----- .../file-transfer-chat-message-modifier.cpp | 7 +------ src/content/content-type.cpp | 12 ++++++++++++ src/content/content-type.h | 1 + 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index a4163b196..f512f5abc 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -143,7 +143,6 @@ private: FileTransferChatMessageModifier fileTransferChatMessageModifier; // Cache for returned values, used for compatibility with previous C API - std::string appData; std::string fileTransferFilePath; ContentType cContentType; std::string cText; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index dd5d21be3..c3a520072 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -202,14 +202,22 @@ void ChatMessagePrivate::setFileTransferFilepath (const string &path) { } const string &ChatMessagePrivate::getAppdata () const { - return appData; + for (const Content *c : contents) { + if (c->getContentType().isFile()) { + FileContent *fileContent = (FileContent *)c; + return fileContent->getFilePath(); + } + } + return Utils::getEmptyConstRefObject(); } void ChatMessagePrivate::setAppdata (const string &data) { - appData = data; - - // TODO: history. - // linphone_chat_message_store_appdata(L_GET_C_BACK_PTR(this)); + for (const Content *c : contents) { + if (c->getContentType().isFile()) { + FileContent *fileContent = (FileContent *)c; + return fileContent->setFilePath(data); + } + } } const string &ChatMessagePrivate::getExternalBodyUrl () const { diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.cpp b/src/chat/modifier/file-transfer-chat-message-modifier.cpp index 6f4014c3c..e167a7a7e 100644 --- a/src/chat/modifier/file-transfer-chat-message-modifier.cpp +++ b/src/chat/modifier/file-transfer-chat-message-modifier.cpp @@ -49,12 +49,7 @@ ChatMessageModifier::Result FileTransferChatMessageModifier::encode (const share // For each FileContent, upload it and create a FileTransferContent for (Content *content : chatMessage->getContents()) { ContentType contentType = content->getContentType(); - //TODO Improve - if (contentType != ContentType::FileTransfer && contentType != ContentType::PlainText && - contentType != ContentType::ExternalBody && contentType != ContentType::Imdn && - contentType != ContentType::ImIsComposing && contentType != ContentType::ResourceLists && - contentType != ContentType::Sdp && contentType != ContentType::ConferenceInfo && - contentType != ContentType::Cpim) { + if (contentType.isFile()) { lInfo() << "Found content with type " << contentType.asString() << ", set it for file upload"; FileContent *fileContent = (FileContent *)content; currentFileContentToTransfer = fileContent; diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index 4be8f9626..00805bfc6 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -154,6 +154,18 @@ bool ContentType::isValid () const { return !d->type.empty() && !d->subType.empty(); } +bool ContentType::isFile() const { + //TODO Improve + if (*this != ContentType::FileTransfer && *this != ContentType::PlainText && + *this != ContentType::ExternalBody && *this != ContentType::Imdn && + *this != ContentType::ImIsComposing && *this != ContentType::ResourceLists && + *this != ContentType::Sdp && *this != ContentType::Cpim && + *this != ContentType::ConferenceInfo) { + return true; + } + return false; +} + string ContentType::asString () const { L_D(); if (isValid()) { diff --git a/src/content/content-type.h b/src/content/content-type.h index f3039c164..fe5147645 100644 --- a/src/content/content-type.h +++ b/src/content/content-type.h @@ -46,6 +46,7 @@ public: bool operator!= (const std::string &contentType) const = delete; bool isValid () const; + bool isFile () const; const std::string &getType () const; bool setType (const std::string &type); From ad05dbbdba1159e788d101e829c59bb9336b0a43 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 9 Nov 2017 12:47:55 +0100 Subject: [PATCH 0752/2215] fix(MainDb): fix sql schema --- src/db/main-db.cpp | 4 ++-- tester/db/linphone.db | Bin 724992 -> 3905536 bytes tester/main-db-tester.cpp | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 1226e59bc..06a90f184 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -143,8 +143,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long messageContentId = q->getLastInsertId(); for (const auto &appData : content.getAppDataMap()) - *session << "INSERT INTO chat_message_content_app_data (chat_message_content_id, key, data) VALUES" - " (:messageContentId, :key, :data)", + *session << "INSERT INTO chat_message_content_app_data (chat_message_content_id, name, data) VALUES" + " (:messageContentId, :name, :data)", soci::use(messageContentId), soci::use(appData.first), soci::use(appData.second); } diff --git a/tester/db/linphone.db b/tester/db/linphone.db index eed573f25761176c713adb02dbe30d19c5878a60..7775bed9c9bc95664051382a63501ebff8522f4b 100644 GIT binary patch literal 3905536 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�%>N7ds*0zQaL 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�|GZJTG-*2mlCS+(`&ZS(Bf`b672 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

      P}nfE_j|;sdszfYLInV;c+$RTDaO?7EyP!nREF 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

      yYj#-tv(z&f z!YE+_hRbR72>BtXG7t;@s_ym7oHoY^~kB_%nQNnkP4&D5bKn-^JzV$K?H zz(t)AFI@rLvOZDI?PjK~=Kw@!{xU?Z{iEYG-^{+@E37`5XcjzOt#kSNt+C-ZSYKT_ zMwX2-WHy_STY4P^gqdO)3yg27Bup`ZU_R*3xJ}XN>_-e6gEJl&Z7KOb?oj>zwk1vD;DMt5(AYfmhC&51>?KC$RkClir6(b-cICW z4KV@Mk3V-C(Ltk^;{BZMMF%zG*~=nUL#*0j$~|jIbl_M%hrv*ay>`R)qL@6-+)kvC zUdl60AYz6*eO1ILJ94yGc~4sw&8+ex#r}Uq=d+#uKlJ~$|L6Tr_Wz*&;r_4n-`oF% z{?GJ(y#JQ|_w>K5Kkk2h|4scb@4vqPivElF1fJ1U~}BD|@%~UekM7 z?-t-8Xl?tNSh8AtahYxgzXmv>*(y|MdD-i7PBkM3UEy`p<*_h@&2_deb8 zyXSV-yQg>8x+irzozHtv|Mka@?RR$e$B!xhKDzw-sPgY4%fF8(|319@`>^uwwdLQ3 zmVd7)|6X1Gy{i0sW%>7t^6x{+zn7PPA6)*uto-|+^6#bP-v^d|FDd_CT>ibN{ClkY zd$jy}r2Koh{ClYUd(gjw@qvD)+aHYg*Wv-SxPL9~SBv}BVxM9-7~iKBd-KQs_}=9r zdsI#xj4!OB3nChf&#%S3YH`n6+@luf)#8h5ac(Wnsm0xEads`fs1|3{V!al3tHoVw zab_*2oKlP3wOFgNVXf_|wVk!tQHzsnagxI6cdE5PE&8?S zRav*zI;A*%TP<#_#VxgXLoHrki`UiSwY7LnEnZ!VSJmQ`wRlA>Zmz}4Yw@yLytEcC zsl}Jn;>ERiQ7v9ri<@fkf?7Pk7SF52jkS1gEuK@0XV>Ccic<&2Z>Y6rDh7k&-I z>mQ$%Vut_o`OW|41{V_myjDqkzfT$tiFx-NzAGm(}MdiwShEwWe{OF)`78^5?9VCLp#h623 zDa6(4rc|_WG&L=GU1-0F{-+7@=*JTd4Tzz%F+Qv5icPw(^TX^5@IlSb2|?Er!c5uJ z8VE43IvuRjizg%g5buIhp%C_I=uBT7cx+=_!y)$$Cp_9wbm`rJqrC?ZM?5slW{PR( zvJ^&dDiASn8ucM8�A*4W@+~GAd&@vm$T{n`p@4IJ7 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 z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk 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 zB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St- zPy!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T z0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wqua zB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St- zPy!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T z0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wqua zB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St- zPy!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T z0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wqua zB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St- zPy!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T z0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wqua zB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St- zPy!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T z0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wqua zB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St- zPy!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T z0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wquaB~St-Py!`T0wqua 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 zD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0v zff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz z5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZ zD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0v zff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz z5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZ zD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0v zff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz z5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZ zD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0v zff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz z5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZ zD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0v zff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz z5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZ zD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0v zff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz z5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZ zD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0v zff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz z5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZ zD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0vff6Wz5-5QZD1j0v zff6Wz|6dTe(k?Hbykv6brZZ1D`rXU!K6?3O&ph+TM~lfX`{E1MW>o@_jBzFjS*9=P0?Ww+elbHzCG72ElAx>@^%-D16- zuBMB{>SVoJFE{3#EqCknV!PPP)+gKbc4^}2Zf23o*=o0$``T{1o^LkGxy^2u_P#m2 z=f1b&`+F`QXTE&C!g#vctd<*ln_4`i z%N+T7Hk+}e#eBNhI@8$#c}KcrGb>iJhIzBvS*Qcu&K4VHxSZ|px!*YR{XBjdV_a_* zp1!ee-!ZeQ9PDhdS~!*MY-^U;X1%fL>3p|hsEeI7GY{u8bA~fVZ$I19d+sx0z7L0B z%CWqK|LuJ9JnM@oA?(EMV>w-&EEhA5uw5L#IP)*gHu;+w>xoArvIY!-6%pA? znGq;7=444^SPMUOSPW&knQ^)8nis7s&ZAb#?QXum`*fW77YK%ru|tboGWgwYal#}S z#&))0Zj05H%xq7#e88CzAIsd%=)mq|J{Z}0YB@f`Vb9Vb7D`C9Q6NhnlW!4}?whVm(Fq!^ai>4F7VxktnXP z0&lZs$h#S_Yktl+^G`9PDU(^PR<^%jPUr~? z)=oL++|y}MD?1m*L^(3<5TcY+mc|JR+l6mHe@YtmcRzca`6uZKvvrCIUsI|*i+)=m z3tyU?)v{;gZ5W6ZgIjK_GLd0JIT*PEnr}kXP7eP6b(72Px$HS-{_M=HXWswl509=p z+D_g)`MSyUo$dc`o&WUiM-KZtzV@!1EED6_Q(NX^omx+0^HDx8e zu?&c3Css4(RLM1*+=^rK)rXHKa>p_T!LW%iTa;ex#62kpbCUxQDozGF?{T6Wg7b>m zW)sqRJ@?*NEQ?`czW?;@_a2vgJBNs?u54-PV96i56XTX5Afxhe@~~c>Y*vGuv!Voj z`AA>{9gEvCIkqW;?(crsxa8M*T(oG)o_Q(PUhPh7j3q918~$fLsx&*9vB-RdfBKO0 zh+(bfS*~Cl(TcAuHy7`I=rHs7Yrid9=7YX#PAfSi%)KwG4^f>D><*QM|^7?APC*6?;bcB)N&-C5_oSsOW#{{Q6J0)W@*H@V zzy*r9v!;g+8d2OzJ7tL6$NucqK9Ql|0lI5I1Y$96e+%INFrIqP6ki zi+4Y8ocER_H;!Ymnld{M;URR6cQ{i~C%U*;4tcUoVNSB_#`<N7YxwB8EGG{u3ivu3=ApABm z7M3TICU_@~UrrTWO+SX(K;g zN;ZZ_or$G$Ia5AGxA|@Y%EH9H5PO@&rIIQym-|a!JTCc*EzENnd1Tl3iMnRy6_Q&y z+R8UAS1e};Px1_kuybSth)Znas1b2B#Z1B{N5AxikXC;aLI#NhfHWI}{p<)+e ziSuVgE4dJlig0nl#Cds!B$I+6Y3Af0CT^x|>m7qc2lLM>!}ByGV7PjHXU*l_X& z@o>6H;U(MgjHz8_rAt{>k}~TVGUb&-c5dbujWfTjx&ELogsgw#hRCCPX4b%7`<#xkY!GD z5z8WZtb%o_os^|35|da%>bKVXMdQq0L{uE?YN!h+3FmM!&@wMsv*3Ufc~B-R7n3N9 zgTg6mBed1QZL}DOjCiYt5Y*^L`UN+K44t(2PmaekP;%Q6n&5@`hAXG zY!nvc$>I)yV(Ai7Ikq6^o2Ifs*^4QM>`;J6ZGU>{{l_K0zsEBvDW31KmLwC|Bv}&g zm~+-9(epH6ZAP0?pi2+tGopacaSw_(1x;5 zB0yc_<_aX=D{>18+(LqZ)Be&^$0a{CgzROI)C2@x70M|<4ow5zoy-j`_NN9&L%>;> z$iuX$5`B|v*rJ4Bf9WaX%ujL7kq#Y)JR{kwG(=%Sbn&qsbUC{US2Rz!qr8c7O!Y)b zl%zJz48oBv!e)Qz$>YpV78te)T9uvymes^f@>}_%-bV_$98mHS4@1(f@m#5ud8v7>K-cPPbs{x`0 zHbnUeyRXIjm76p?S*rYz@S`ZksvHR%w{vuIS}B2CULqj3oXG>mj@q^N)#yn}jdPI3 zL>!qRT)fctrXmow__8va;qx$cFFoe9Yk)bmERhkK+>vZ|`%8z0%!O<3lPn^NDu!@s zA5tBvY?ZgAxI>f5KnoS)FL5NBS_ZaEQmby7wLTmnR(u&L$B_U*WQ~f2udVP z1SR>YfY_bA(MO^rAC^7{S*c9pzobhJl*VZSK~7i)!kR=+3qCaJE?j#rYhs&;(F)uo z{|XVCw?^Sm1Sf;BYhO#Zi}BlrFl6DBRwoP!$)>U(p?6Mc51qQ>Yu^o~h~7HsrbxMP zNJ?B0INiP^Y!)KG7BOr#LiTnPd0dE z1R*WejU;`j?&QI9$Lb@jg~p^IX30_QSVR1ru_(e%FP#}?KEC!0Na-FVJs=qAghZma z5<%dU3D^=4dI9eFYFJ+S%V{TA=m|qtU|EY?l#wrmhRL|#iBi-u#R2<{m>_v#`w2D5RH1Ge z{mV%up_T8aKOrWtK!24zp{!gGHl!T~|NrX0=>I*H|9|t*YVxa-ubv$LWk-Fd{Q2~* zL)+{4nxD5->Xz{={jCI-w`cG(tj8_4!`%SJSSh`@0TJ zuM5}wtQ2oaUl}bwr#{L%y=e!@0O?R#7-Vd%`IBmx{O})N_hkKQ*j7W3#Gg`7M2+0GufaQLH2V%(T%`H`7ywn;68)*q7!w_g1*38=L%Ovv}TJ zho;vfulXqwq~wuj`EJt0&?B(yb?f9%Pn$-6i(%5y^gqaLBBL-Udu7(*UCL{T?_z(~ z*zvmNCkdS`r>~M+omVLh(}ba6^q=~Q)nr4i&mo4CCCcL)5<1fHRetj%HMT=qE%$dl z>!2#v{DdAS|EB7cG)-rZ5m=z$Bm9PLrYAyGTm~d}AO0-`P$nj^Aep4ll6Cono%Q~% zXO1)fc+xZyLg!MVB5Rf*p>pJ+TN3s(>(zlNnPmHVaZ=f2u^2m<%<5nIG`ZW@-}Q`f z<{uMGIJpz>Q5quATMCfVlvjgfF>$OJAxsiAWRe(q211<3FS<#z+s2bz9Q^;Kf8qa6 za`X4nu?Bb-`2Xo$hfd7#HMh}Ohk!R#muYc9wW(|?iI#jw@YWuXIol{3m32FPhs?GF zMMjX{3tJ8^HQMQ2hepitHMf#=K1B5NnVBFrk*3SRMH4E^T2%}}QM_NeC+JHn1wbJs zZANp_9+D(HMMd^^jcv4RUh5=P7NU@bHyu&GE<|*zPYy6t7P5t8>7K4S9`4NIN_1QQ zcg6g`H#l!geI$xMfea)2=)7jW}2dFOCd z#Y>V1F)Uts=t^C<<`&SC3?L_Lc{r06d0DnBlLv5gZlwn0qP)%)9H8!+Zy6dmL(yPs zv=+Ze>;p!NzxmLljYcO?7TZ&YKcqPfS0Ot`&PXY>?PGsU9D^k+z_IJJK zIP;B(Gb~tE5E=|$eaTsJggQHx&15_<%IlMO(#V2#roo%pEb;U{+iDc@LYbld7&EVQM-rcl<6BfK_U)#gq~Be)0CU( zPm5%ZZAde@F{58+CA<0l&d(fI{Fy_ZC>?b7&lYpuf+P=!Q~JE~QGGIT`HB+X>Ybf~ z^+6fh&_x%wW5W7xIv1yRe#S8K@im{JV~~s^elz%=fS^*3=5v4BfI`*mOW6{$R}o1; z{xOPFb-Tux`8)yEsL@jXT2#!v{;5kH9E5q*c7ef-kHi!O*oP~>eXrgi& zEjklvmBz2MB%Rg8J6|x&eEymjSg5=w9fovd7sDTg2`g4F3b1)oW0zu&K*&MT zezF#;;m`bOyT9{OMiieS525LjeIQ%02ti$5}nnKVa}L%-4kQ_h);|GP+$F6FHS*_tLoUT}%J zN(++NMLOQ<|1U}W_uh}UfS#=L{}S>48;)j^N4-<>{kNU;;+>BjkNB}k6lKk#9bQt? zMUv)NWx4^PKS9r{G=z(a30&kEpvU5q6_`Xbo&hKISJR~hsSu1SQ-Mf+bQkyiosS=9emr$hJfr|{(!N*TEX5L| z#k^$ILz~^#v>Y7?F=HxeGqVlhBPEK+9!C`cc=7(u$Bi>TPM%D&9lnUfLr8e8^=&;J zJ`U>AIO1?30b-ZFmNF4QNqK6_6hMPi;>LX0<;gg+gfr<$jLR>SHW%{t#Ykn1oDWw; zZk#K3e?A$NW$r^IPmWl*?*U&_=ZyP1A2ZJU7!UGBg>?w2WPW2f;{l z0gxOkbMw2rj-f%yk?D6dEqSd?t@d{wk24>qqZ5(l6bS*6yGRHKLkqzd(&bjE<<2}e zDBrBxA1Cszy??;VGepD*ZNOd~5?jR*%sfX2Oyq{rdJNk=33w_D)C*Uwe z02yL5VvscAPit)P5dR1NKfM3*q%rsZrFY5uf2VgGZUB$Z{kIgkR%)sCr2LZbIpu^P zewBh({DHz{hg>q<7}DwM_UDxep(L54AdtFEyJLUH;R5i&x&O-6lX2>NdJ9968UbJ$ ziN0oH!~!HA&RZU-%@biHdMYOG|48P!CyII9jpI@9{T<`|(YgN;6=Kf(k^d<&xSDr; zWG)`b{LNwhn7kCxSM}9$g^G+jW-DY$>LNNESFkQ zFwCi_2DdAnoTif5uI-YIq(w(L;;%GKSQn;ei~SwrZRoi_^+y^m45$#}8X+40Oyfje zDG)I)Uz74hD02#;k*B(5Npm{!AXgVjE?4X6{*LiB^xU81sv!*+2SY#e@_|Rx1M?G(eE9-e0cx&rIYh-8>-(q zzdya>&`LW#_p?K5i-F~8hgAsd!cZ>jU}w;D*mm((d8Ro;VXfRH3)z)p`5%LGcvPM(q|cqyn4?)m-eeF|#JNZo14ynq z-`_F5Kz8n@BsWSMF)aQV`&G<3GD(c5<<%Y?3Fb+(hQvdlb$67MZg?Bi)CqVJlf-z} z8T&iNcG|h01TXfW0%07?$2we1v#BBPq8FTqZ702z^rkaT9P`%d@UlwYqRhLuW=>hV zot@rsXr~>Y`-wzIt@}hnA$f&B+U9mZ+PR5lL@wsthN|y9f+$F5QXzS>kS=?2u2Fm+ zQCMwG?>KbRj?evgk~>MSlTJp&78F^@rOlEKg3o7}xn|8CR-$#(l_%vX1SsIKNST5um!rqWs)vZJF1k7-Dml%(3IN?2X2FsX?8lN zEFXG^(&v5@9_xcX(JM8LBt3b%Xr+Zf{g?+*d+QVsr6oJ`F9C^7YmH3yJTt$r`%@Y4(j!rN-X#z&0x52>WtGP*In`UN@@&7Bl z=>I>w|NFN0|NA?}T+})Z1c&1I@SmoNz%Pgu+%@SG=6_r%66%i~)#!JaF#=|SGFsbkS zD{Jwa{T*X2cJ7jN#ba~FoxtfV^I~H5%buVh7|FZDkAyJhH$)nbU`|v_Di|m7t^Q1u z*w5iD$P4H0Qo?dQv4glUJVPGU24i(6v z%zSta^1``01tkkhjhyh|cyye2U9uv+D+hqygY%jN%7lW+_*^=l?wRH0RzIA(FWUOW zI}YzbosG#5vNzbr(& z!&{IS&fV_u`5wJCnRW^@??U*BrKC?0S*Ol&y4=e#DgI*Sq~3XhD=Dyza1TbIpqXMZ z_HWOY9kA%;M0% zy>RX|Y|CpSQYmsR%<1Imh7!^AA(7GGa639&StDtw&O~dFPjVeqnV_LgG_#lk{&@fQ zl8K-D$xi?bKlyX`Ss?lUJ3s#KZy%dS=RS?0`kxS&>{9Ri%0;P-2%p%jy31L&xO8x#x$!Z_15JtS~)Y!YiuAv=d`>2v~Kxim7ZF z5Je1qAguUnR>D}um0Zt$)gy5a;mmO$%J>uET2uoi5aDBLv{0-wV1}JOlRTA zv}vaQsZ0|tBPm>%u8C*s)7w9OnECkJ$6J$4CV}vM$%~nsq=+UtL9aY;_=Et?&Z@|3 z>Xo>L=&YZw=3`LNpJ=Yj|Jx6pvr+mr@q?0VQKk6{!`FA~fncWH$0j z^$_3EW{R-JSQ%A%(}eN#_OX|C?o-8>A9hfD`V=wL8ry#=}(}MA7F_=I`C7B*J#DhriaNo;0*pVuP^a)13rsw1ekzNWSv=}tOf~*lV z=HeI>BJv`XKXEjSPfV*OO~~BW5brdKlAcg6ZYwT}f9xG)Dy9_lRlk>mbtf#lH#?z1rr(G%1$4;!1zvT)^ z=7ObDA;)qvyG{L1w0(ny2QwC}_^6D)K2tg91)R*=_n~wPj6q0OHL*nUyu7s?s$>*t<=WxY9vx( z3A;NAT>&TRNv35j@_jEXScgCvXZ8TuG2h+aJ|CByqEDC?5ZJB+AnB>*yP7oBu1j5yx0zkN2&EcN8zB!&ChZ|pGlr@mSI@r`igje=|g z{{*WTYRcjCUb4y*tCClVb_&-0?bC5)f+vkSG(LGn4l5a43h}(HZVtX?MyYecBdV$F z6h0&^uhPqca{c0ktfAUp?{6PFt>+%kgM8Cq%UqnRnFaQgZ4&iVx`KoYZjLK9>MBIp zD7UzfOK3YZ$@U!4^5X4dqx{@si4K#OJrfD#vCK)EiZ3vTAxJrS0n*nZrveb2O*HjD zb*Kf%R3d0eU*@~F>Hj^;{ol8~&Cmb6D}Mg>^!CHg(jK3?g6>MQ@~%cAqLLz=^Sq5C zdrU(nw@_Zvjl?I*5yuEyS}#5pK_uX5(x^0JD*M~VAM!kRIT03zd1vkxmE4ja;Ujkk zxo=M36pj=da&#*YtMbl@$jKT&l)_2FqnfHs9>Yn;mle<5k2a?xCK#q-bBJ8I%HlZJg9u$3L*b= zAg}z$70HUum7PuRr8N;ha z5i~h(3VnH4)*VF<%p>gkV=6mO@z2p$8f^?aD#w^q`FBF(P&2rhe zG$y&HVlL_UA$QlUvZ44F z$|11w+7p;*ttuvIO)lq?Yo${x4WKKB_Z2UkJHz4Gx4b94nOF}u$u*R1r_RwMA_at( zB?q(5ezBEa`krozx@1f-v7_tpSOVC1^0iG)7KtyrsH@2&Gdt* zSb~apG!%n8JLPd0+lJ&oOpEX42$JBXuW!r4yQ2{`yyc({Z#BF4+C$28{@s5=nwGSm z`Q?UH9Ke{Tq^+z5cJjiG(48O7(pM(R$WTiMBKkWye(#&*oyykP{j+l6XyMEKYCp9n@D%)Q#6Z? z0tFwJ7la)YFLy}kHBw`>ka&@1OoDE^r2rt?H#aE*+p~c#7IRIoP+_<5cKnj= z%D?73QQgFoI}%ONr6euF1n11Q2}BQpb6+-rWSqo@ElL+gflWMEs1Q-59e2;k&;2U9 zW!gYR%sr2g$m=6sqTv(xoA^q}Py#9LQUHJ?N@d&U!oN~DGEV3tSNZ?--v9B4ivMf; z*Z)lNaK~H<6HHxEvY}eEG#q!V<=o$6hjfMWNh#T`3I;NJxiDXovX=96pJbq+43Z((FNTdp5KP2otAwpGO^6(}PEx`^h3^!^ zO_&hf-;QSzE+R7>cbw(i_s~M|3*!V3pMUo%en7@U@ez*a}Y3GIK`S|NbV(N?aB#<5l+!A&Lc4-K3C8VU{{ z9B8iS?e9IR*ZU<;0OK zxOZH#i)+W>agt>MT*9f{fZf2|Fu*)4KfoQD$a*_^SLZI@Mbz}!jN-J?2cM<}f(f}B z7RGu2vOKs8BnIULkg}X`$6}d{F)@e_pG3Egwxg~;Z|-fPO!|8g6OstZv$)34Aozr^ z`RpWA78fu7lPGb(yp({Fmb8?>N~cSLwxt|eZGNG*^4D`z?Wikc&wa2w@GbBsj<8Om zNh1P@xwwV5D!v(bf4W6^HvYdjNX4-VbMun0y;y+CK#cPbxb9tJ)&bUzoj=5J^_s(R;cpzei+5(z|rDJA0SMQ0-nUnxx?_6&wzLKS(kaZ)_?tvVgkqSwaSN zRYlEa4oB}US6-NVcc@4k1cK8!frU+yi0$K#1f+rsBtK~+z)N7$lI+`e*dhd{$^nnY zA*9hkJM`$C-G$#NcqeKmc@IQK*e97TRS8Z3zNU8kjYcp+;6Fm)1~Srh^_UQq_9>Rk z4e7HQb)Bqp?-0}_7Tla6(K?}=%S!AAC7D3#t(+2=?&hWj*l763`U=j9qk%WzKDRXO z;iz`9F3i21y5hQpC|1M(@c-#L3lbE@BI`g`{xLzAYfGdTUy{&($?nX_`WEzIE7!~O z|N9XAmHjWwf35%jI{bf*{~wO7>_m2DA*@7@6r;k7F>awVVV=W->VmegVB(^UEI!^e z1<^e10O-l(xgsA26b%Or*I*e<^w>Yn|@g;A~G z%sABH=<%H}9uHOoLdy|T;e!p+Kv|G}DMD~Ee5?#fD6xMQRiZSZ;?m%tq$~axV3XKB z93AT}e9RUl-3{rM^-{7_(~>%%I$(xqt(_O$a$!c1K9ADzwvuN$vd0_+z2utK*V@t1 zP8OV{NxX$TyzZ!y3v6HYzB5<@8WNQGFz=s>-s?3@SxikK+xk~(BKUe?%mi~$ULi6*z zFZMpsTW>yK_?~~-QPWMQN$*VdBovoKBPn32cH%h^NUIAsl~+N;voS;22XazuD`-0e z3;w=1#@OysJL+{;?!|d9A3in#kY6cTvt320kvV5f#XMOTOhXl2nd^}k0o-wPArevz z;Vs$Ck@a@-mU`vcuf^Iq*YwMnmMg>OL?$bWgXZeNFag9y1eK6;vU_V}Ir@RJD0{_0 z+bw?L2>JZAF+oS?%=JMIj+`T8$f4iBIBqheRg^d(j(j0>e-rs6=#qRGfst6HILA~f z_J`(WsqN;?-75bZP!#Qz9n)oc;5vDMpSU3}!07Q5sYc{Q5qYW(Z^TL%tChurxT!UV zGtKlcCCh*; z(ojW&>oc1-7VI+nU-~nfH`KrW=YG4{by?2-1-HP@^6z3CClW44CELyT7ia%dc}gM#oA4d_mK!D1ShH9{sHv2ST`B^0 zO_mp%77ZYZfU)=(3Mc>)lW@J(Zgzc^v;UEv2!1TrZmq6Pi0~jg6MmRI>{_ zb35)E#mLU=5S!qg#AV?#VOcVmidqP^Ko-z~mbaVF>TK+1Gv6#liw2j+?dRN?DxCTi}@-`?c1P7fxe5BpHsuS`*DW;rcm|0Vi@XM+b1j*=d(GrrptfBVJ zFkXBDA0+6|aaR^pD56cJ89?n}it*I$%0JBt8EF6;vV~R>St-@RLBZq2yIV~K1oyxH$YlMnjNM-g>fkR z5daA~5?mPS+o6CE@=*Jh`Gx*@-hf>cl z{0U}xTcT|PDfmy~3nLp6jb11Fgo%ATvB?a0WwMUh#=Y?%uH5ItxAvG4-;m{buM%-v=4IuI=d;U+_Mv zi>zTj3QT+(y%s)`!3q`jm+Rw9^t}ZbBzfh*i79|OkS_6r5lDuxT8D;rSJGnPg7-4( zLIu%=gm{8xftX5QCTvkS3s{0+?KB+<`9QpOIKJ1%SeRRyFSS3kJiNPd77G`=Comnj z$is-%Ws@Nyuu-67Gz=|SPLzfpms0ROyd$p<_izjRZQzISl9C1OY45I-#o`6;4mb%5 zmP|WWpjvQ5Sh_$M`wpmEX|xfV^Fu1m^Q6m|?Q$z@fu{?llG@S6-IXkxzu;X-0xPT+ zdu7UQ!nc4&yftOwyl|fE$B}z*X$#ZPLBvLr0fgt^Zqn}{|NjjB|MLFen%=Fo{@=TN z@V(tTfInk!>Q8&7YpOr+LZ~HGIkGT=IIQFxv@n__PQ>w%AVuVk3OW*@m?Df7HU)47 z(1S_o01o9)d#1LLFCMrCsf3K--vWPWh+UETA}}nm2#`TA94Q5g#iDHju?4cJ_lS*g z+2}O?rs-nU0$wn+i2uox_RO&Q;se9LJ9lH#fFLXrj+Y*A4T75>K|)L)h!9;^1+XYf zjB1lh{Jn^h%1!cG*~gLg%tm+Rjr7K_2LFc4~3iV1m+S*imR~+d>y1sfPo`=#ZuV`s}jH% zfSDIErdY~1(px?<_H?v8(>)Av;96Qut<5#W6OG4tCH`|(eqz2BZxp}AS-F~|TsKbY zxM|%tS1YAajDXvvpY56MVTc1Szzm4d7U&qM!Y+A>xQY3^2jYZE-ke^UpP)f(0F$)Q zrGwomI`C-c#R~RfElbJNw+tI9YbTGDQX4N;Qo;wz#*+; z{vt-=zNAU;vLS~z&eUfX<_}zLC#=$Ffl$a8s|*~ZyrFkfKyfd5i3m@F1+yUdc=N*C zsEn``hHA=3*L%HOs)1IkSh{Xesgd<>5 zQja4~i&>ImvPy=AaM*`#pc zPC4=L+JHK@&IRYOgAlO75RVBDq{}3UtpWi@6+;yq1PM@e?db4KeMiN@frpp^6$iGZ z?KCejEL}gM9qk6O*$mZDzevs2yk!IQnCg~liES2fe2*CtA7LEqrhJeA)3$g6Np4J0 z9$>-(APZ8J0*jLfDOz#F3=saYb~jBUdD0Cz50o8{5ofw_=E8F2`2!cmHDnBo5vVC^ zdIv~|c(&L<8c__5kS!6`R#U)5Fu;lC z#PF`#(YUbx@28#7pOBN*A09mlZ61DJ&?hwoRTZg|(IS0-uJ}9U-Q;>e5=)9nn#9r7 z;a#<%abf=tSaDX(xw|k+vBzAMEs;Z&P|k0qqlp+TPwGf-$<=4&O5h%BBQ(HirnY`) zc-LapnEn5IvU8i_OTq&mA*`{n_y;H6;+qX;eFaWhoV!h~d=-(oX42<6aq zch!D^i}!y&03TE5`yeVGOsXrgh#$!gnHF4ViwnQa^U`$sPKrTpX>DfxDXIytahX1T zba+>7vRK&vee9C4*v9zDBoczO>BdvA7%`Mf3AvPQH8CDBT!sPRKaMjFkwXBv1>i&N zU0qMh{_hQ=;-Zw!KY?0#Ji%tBK{*6fr~!^P>56sdPOfT-d?HOU2jolei2oxO*M@g> z-5dM=9_g7>N+sYc1z`m49odo&=glElJ&7ipOFDzhrtD%2hihB7Ku$Chf+3dMyK48w z;{H!2)gxJVMj3`ZK&rwk@NNJHrG`RHlB40q2|v*xRXEW_2WfGbRGl@%ln<>QXr9OZ zuk7`{()?8O=H6ZPIl$hPc@s!8=>1slL%rp{OdW@J9_Xy?0LcJg?47M z1)GQ&Qvy!;j-^2(1?~zc$@Y&7@2qXM3;Xvb&ox)pW*|+A5UZZqq;pVZ zp`n-?lcgPukOBISs;0A*ia=orVQvu$d9A&(>sZ}?pG5oQFvW-|cR~e&cMD3-c|~zW zvC_N~SL}+h*uY#U+t*l+t)t4k+wzhALwXP0O;*D@Yj5wu{u!B%6fz{3S5xcg>2SkPd(v78{gj9wf646uK?$2v@Lu{B&>9m1TcL| zY%4@nOpKr?eISrX7b=9N#or~ra%aelXn9Rb`S1P$nD)-uvi*zuXYC+g!7HOKV`(M# zF3c7m9fB)PGwdzBD||Yv%XcRK3H(pe$1mD7D2hCXcV5sb)&)r+_*(+Xdg*%H|lokQDJoCY=C*B%-di zp=90x(clg>N;HomCRV4|2mr)8FfZ%CpvYM6tj+9;`}fIo5kbi!QZOiB!hWWEGFTvC zik#AOP7#vXig`FpMv_)B?kM=!F1R-HKf2o9*>$t;KR>Cw6x-zDnDZPUtzh&FLx`8` z1f95YuwYmx!7P3{NKgLn6hNfj0W}=F_T#r;M^WZKKbxhQq$%EPjkb+En9y(x-`DeBScW0I*kCERITrf0P;f~g11{TTAVr2|ZpFhOcvV2mgdu%4Kt3L^8c-ImVSUb~y` zxOaZu-cf1A#l3$T{@woB4DL5vlnkpZAAsc309sRp?ks^uu^PK4z$TRo>t;-{3Jek| z`P#|aoU*w0%hG(COR$NjB+2*VWOyoDmAVRlE8GUlp)?bsZCUznSp})E*6<3+grrUAH`766C7X^JOpJjKn|ET1p@?T+eN?Pf~x2KE)<`KflZq(z76bS)#iP8 zMn;58HmMQHKv&y4y2hft z{{aunJBlDFFd$^)V?wHlfdFm*$+Cd7xB3}lXFo(Lbh1%?tgs{Dd<3t2;?RNqv)KPq zZ}7b4Z{q+S-}~LcCwt$}TPp7Y`$Yc}+jVbvdu0F?X2z(Nfa+w;cEb#iT40d&JYut5 z9F3TjUrrz}@o~axYTC)J5_C*7e$#3~7_PUscLc!9h`4OOjf(SyC<}0gYTU%Exi1N) zjg;ZoAXbD3an%sOmKfNU?1~k;iS1t6xV_8tX1>!kq^>qQ#Uz4dvpKLp`y~<~0qCPC zQygxKv!RQ;fRrqhRrq(%lB-CFYHzQZ-r~&PNtWUZT#9U$QWJXGxRV2MgHVa+gJ8>p zqAktu}%#8B@7iU<(*NLAC%LQk&Ut}Fjz=Uppk|iG^B!@cY zXwrg~Zb92p+H{~Zu3pgQ8AWk81{ss!U2tno4gdQPY+ERR;Us*jAh`*s744I zMwNm^*6M1d$ZDEFmx@ABUb(rv6fWT%%J2W%*IVo*|8Krk*Z-%R&*wb={WISGxj40h z8@E;OHb3*uN=aBcuf1?V=F!~yzNaD zo6fw6!lk&)=3IaQm)8h{MpJ}>Iv5VVBa9+!$xV_z>}}tY`?*glI5-jtix6Bk;Wu^@ zeq(^U`K5otm3<;v51UQ7fm4Yw3um$f#B^{mU>0^V)uZTa?qIVE% zAxN2T7Hy>rb|@4f3OMG&f=jjE6)8_h#uCeIu*C(vTMWc5^BCS%yTcb|-ewL-F2Pm0 zOe(Z9X(Y0YAnYYa9$$cQ#gc+}Vi6g0K}ju4GUz4DVel^ef7@F-DZdqzVaB2btPR|A z6q#|*J|pM5O^e34NNQpv4?^2!AusJ;e7Fx%G&WG$ob2Blx+}kdRRr3A9+E1shN*=` z;3dT2-cN_q}}XlXtTdqvQ_b#IEkGa@PD$J0_n_AQ0A^;^+7v1r?!m7 z$E?D~V1b%;Q%>GsxLIpE3$yL}Ba|#3o?HIS|82|5_gHi}4s(GUm=KI3rQhW`)sU*MzIWMpY9XQYd6W zluiqoI}0j-LFvyD>m>Gfn)(e?=kuwLaFK z>3XpbfSPogx0WmbJOxFk7boR!k_i}#&kD;Uw1^bRox?(>KO>1+pxmBW>85O_xi(&x zF{Z&SY^?1I_SKaTQlHZT#1((tUm)ezu$fi`WkO-FMvCcNd14cTzdY1l2&L%DP|PO_E{`|QcBnY zo(aOa)PR>tGy$i=znegMI;dgL020;BxPAS<>Hk@&zyJ5od*9ewY1-b``rqAuZu2M2 zB?h;30QGu9p1;|9eDMW#B*EOZXia!c4i5T@7qD_Zfys&(1eLxZFfHNObZ|ScH<&1` zjiFdQV6-yi_;cOo z$%L1dn;+~wY*zyx3Xr+!3xQQ4cX1PEM&e(>w*;y9GcH=7vS9%n67u8_LTSOnygF=~ z5S1uIu+-$x1|;LU3)gZ<;f_PWgxZAZR6A^G+BZ_+B?26Hc|j0c0GdSml-_7N`mL0X z`4#FNJ~)pWJY(0j{FMhb;I~X}BXKO%lDJ$p249HMqBBCmIpegGu^~=96js!k2Lodh zBe@?&ksn4C8Q~Bo`DJaw%4;iIlYEX=D9A?J; zxpq>4mDTH@BiEgOk*_m!K-*?Bf6P7DMW!5-Y?*iHo7J;N%=1yTbrE!I2qpiY*0OK2J3r=(-P8vBwk+3GMG=$Sw!Qp`gh zzLzo=SCnT16TYlckW;jSN_j+fJG`-8_eK+g&;u|L!$-_0aTvbmzQG6SY&4G&Nrho!$`H(-kYmTGOgKxSEWS71 zEDbD>L^LIp!J)S6T=#k&SR@k`Sz++Ma8ioe?25qXmTL>-Dq=!*p~t1vfvu9a6xqUu zg~32V+s~szPafsEH^cY@Yz3f^9nC*-T3JI}zFWnuNw2ep510a}k z)OP5(qg?kU+f(*5tR@_i=q!np`$E+0TjVVHhe`%d9`z4oJowInNrIzSdeXM`*_3M<2@uUw}^ z+;!(aBmxGKRjBU{BqBK#tVk=KR}}ZRs5H^QdM+NYCz>);Yn6sDqNLR#$Iw&cne7Md zms43EcaxwOkV67t|MD{{OO*^K5J*Tv0IFzWFbyS-lTB0w5fc4ZyZ8V2{hxXJ=U3{R zKg;{SKi&JA`~9CA$7^|WzW0r>-;m`|APSs{PT&LP%b&<1JiW)wY$kY3f#h9wRGthp z&=0s1uvSCje3xHzy!H@0y7vtMkwLprHi06!2+!+h%#yDFRP&Z6-{AmgDC~u0L2;2I z^v1kMjIJ~7L+$Ze%3ti=%BTcteh5VY-O=#S6b0=iePq*wE#mV(#pw%d)*yQ51!Ofr z3V=#>T2i>OIy_!$`3t>|19$YKFgpAO2|&{+Kc$uu=glv&Px{ZbCn|+7g^#Ego|)7n zlWDC<(arSQ<6X}~?_(iVqASVYTwge6oj3}Bj7uO$jN2oolp1~(>Hz(}NK z;r3@`c)Y%(YoT`vz)g-!c5&SBbm&P&X_=I7$Kqn6zmO-lXb=;rM3@o`!4h4hSLyY zZL6#8@$RwC-U%To+Y5uH0h1>2DU37>8J`Iyn;+qqN4235@gVRKIiQ!HO9^a%;ZZL9 zxZv0x?;g1A9Z!`op^J~^F{vo;mMg@4ilrogeJe;9oJe^hMNR&Mc?1~6f5&Odbdp+o z|IcUP|K(ou^78(V{04w4d*9SsZU)Wg4Sn_=0H8g7znbIp{ub-xq)E#@l9xCTrZ4

      !7-4q5_}aPf?yfpL(o`5`Yj+WpV)`2D;4-XUez!Wa4ugcMlZ zFcdZO4vk%&(d6tYh%trbOIx^7NucK7j#qp)^zYl5}`m@J!rt#_-|{? zeAx~4a*Mz-cnb-_upl^VN9S{J)Kl&kck2s8(;h$2UHMy5S4sX!LlneQ>kt0*Ne;l8 zgLC5LXcw@O1Tiv8exeFXE-C3yl+=aXZ{^VN`2J29-)vWS>ta*XhC`J|nQMR^8v{ML zLSS2rNJ3y91eHuPC{rRr*En%o=O4LvegEHyv+=+F{*TlFf3tVuZ|3*^w#T2;3GK%@ zfe_~smsmx-pAEEB86r6`8qybstu0`j)JkzQxo6@uC+-WWGVz@Vx5LBZPwa&DV=$fU zFD^0#(v&QDaDqw#Wi#-LEG$pLfDTf#sAsqpmYI&1!1UlI+u^WmH|l#j7J5I*!z9kc zO_f$q_yM7-4fDFK2;WQWi!I$$g|I6U6Hrla>MftgY;MX4c0 zG`qBgvoUxAK_L4H2vtO6YUytb@dDvf@)C5(Dkm@~Ra%Exj&(x*5&58SQ8OD}hQ|}w z*;WE&@D$~8QNESxaI~W`IOj4{sblQZ78-`$sNpXQdlJ4@0)ll(UmSG=&Sc^cVYVmxcWVcdo(>Au{p5V}^VGkKIfnn#7xfjd~=IK#F8xW4Ki@ zE1@w-zrAIsFdGX_kEd@zN8!9-z0{r$x5qnXxc5V0B`hNs5X5by?IRI@m#+X=`6*GE zdy+c1t-VVXiD#tUd=3B-3PU9JQOZ=G|9@QU|7sP$yZcw^`@5|<)cbVrW4*_13nati zwVuAv`#s$i031P=R;}m>$T?+ksF)JS-R!bMg&gveovVsB(+u6Z0N)0OeMnLwEmJ2Ol^AzBu}ak1_3t{&U_ z9GIJY4h(>Hl9?eBLZ|Vuuz`S0KWTu>k4PAAfxVcG#4uN+Shz3zS?rfc+T&e4z4zI$ zkWosp$EZlHgCj{bnFt^u!YrI0p|PP^!qK|{iO88C5MNOBPM#!T09uB}U)LGx?@C&j zPihhZ7xqi#PDW*iFhk}^`s5-*Pa&SpbDU<0d`l5qqz;4$(FD7%54MrKC%$lh?3h&<&R|xjs`5oj#3UG&%}-lkH4n7@b5qjQgRkw z;Gf;~d==kqrwFjP&P0P0Uj$4h#wR4TA_W1&DJ-2-J!}VGxpDl}<-+s5-)1FY@c~oz zXiq}WWX5UXP;3b0U_*`DTV`puWnqcC@tLXHiT=44gs5lv_^Y}J|ND3~DjE{pKJfHJ z3{k?xoKnynyc$FW(U=r13o54GsIx#~^A*_5f&XRZ?eSNZ3orJ5tL7DX8$}_(csoj4 zd|gD7=cjC59teYjz?%317D8Ka0?1I<-{-Xa>NnIaSI#^V;A*uohD6hId? zPSm2~d~*dL9^u3@&?lPC-jn&o(vyucJ<*1rhFEDZ(NlbO!FO|`d4(Hv8y-FW#H#KM z68%IiT+TO_n|a}*)W7CdIl~B2D#C$jg5DB125*a#G#DWwUT9PkK*j$$MKi{Qqf)2uKzm712-Rj&grvk&s@_T8ORa*ulJ%zp+ExT5@_iu+L#uJKKtOl}ixq0jV0fZ?;Hp^+ zyb49YzSEm$%T(nclmOP?Sy9eLQTu=(xp(Q}OPgf6meSsGU_rsQ6IQkXdX-J zUBgoNjKp(lg)4-6#7KEHVCx$$5=z^h;sc>?a31JoSh{JrjqI6;fHbukb%8!a>dKUFL=?g$n(5e9v9sXd`~ zRIYrDO%7lP?ZhHn$L^&>FLcM%hBTy{3gJWoutMme5&~IdETR;UR6G?#5{%TIP(CVG zzB;+5B|)f38I&T^@SLeBcCrH3vGHV2gn8n@x*h=l^2@lKog3u!>(|d z36E3{!YRUFc4=?StOLM!k+45>oX3n0DP12nHANNSl->d|t32Vex(Pokc|L8UGyca$ zC<&m(2-qRFl)8Ycyv@_tcie zlU){8&C&&Zn#%WEb~Yk*;#%@nLg81Uh1MlEA$tL&!~d5Kuz!C4Pw%76T6zC(-U0p_ zlkfl9I9Yk#`R265qaZ>CWTK48j9Ghtd-zVN6x$4KMJ0nsEuzFd^+yS2xFAbTbvd(X zPbeD|jlY>!NSL4?avWJ8ePN~1yEx|T1;|UgaX}DN8aE~16kVqWW=bArUx-xF5a+hs z3{Q3pa&rpjZhJ_bkTjjy(WO0CeObT_q&~4=bKM@l(1g2@93N)A%TbOU{9OaGahHJ=`y ztmO1UbCMMb2^_q23T6rFzTuj5P~484C94!WQwrm-7=VD$B+mRo-~D7qzxS-#y&+j=np2dsj0jb#fd+Kploq_veuUun~x^q zN@1g7@!lmB;>1d>ms~0VoMKZKxt(bde3<&g5J?QFvG7p4rUrGa4^OBmmJPfqS)Y#= zb+R2o7@|IO1r?*-XoJA>JV#)U!oOk`%v9t?H_#@=FN>3!h}cID4^OBumkZyRQf>H5 z$biiy1{aDrJ1u>nA4y#(Zd?w{H4ov%G9sU(^Zo&s66FK9h9?x6%Y|={mhd`ktB5ta z%EwV*76>;4AaT@kA<9h%uxU0B_R(vQqN15#X#~{R;8OSdKTG_t^*_J=qjyX5&CN>h zS9_P7O#p@`pVr;}XY8?bB{d<2EVvci9Y18x5-!q_4Qj}UNRV}~&Sa{TDU7LzPXm$& zvRI!Up1iWV@K1){7ZUUFNDHP-z(Ym34r3s)tICBJn|~7O*tW_q=}6cE05pN3%ou`;=^FsI11*III~Ti!p2c!%mne`}#^1nV z?a8NhSN>^(aL}Z^+4(A%3(q5Ut^7`=P zQ#xV%6e%V|g!4f4u66WXd;`ksZ=2Bg=8vBTB;l*FM`6m;ckReE|X?d@^-QLQLc|#n1gTm zP&lMQ=GFj&@R|ip*Lhjt=Rx~@;QzG22IKgDRUOSU-AEf=l@duFTDTB!6(aGKtD0X z|F4dMp+f_?0jk0tSEP66Ra8;)jp zvOe{)(0q}r0I2M7k`Zo}Xn7LW6^h%`aS_m@{jk688Ydr8m!G4s`AWiA!S1wI%&R=; zV)J_(kBDMJlh4LU)F()in7Cr>o8Tpo%s382iXv|ENPu?w`)F<&KiL#v`O3!0cNQtn zH-Auw_*CTudb^!iuZlsRsj`Ws8ct87(jhF>GI#*{%G^^-lXeOm60yVux-mTYj?T4s zfRt8Cd9%zE3Gi@GC=>8i^GK~F_{Gntxi3$2C@FdpB_e{P$SxMo==JNsAsHJ4A zlr8#^>P_OibxKGes&J~p5X-f)fQW!R@FG}@qYrTx5rtbi+MeuK;pTJMe;Z{r6gp@m zFS+1ElP9M*LcN$yh{eUXk1Q=VUt&K=FHJ1DCA7;~ z%k(M@r5=1){{$&>#Gto7s-wi%_;nhUq4^R_*^WXX}67`qBH9-c8-_0DDZ0 z|HDzOJ}k`f)1hWU9lO7%Z;i1Jd(88SXB?3!m{9n8s|dX$xjC)-ii z<2{!gFb_}!pPLp?%6W%YFj-Za#K%;nf@*kvszCjs2tmUH8*AV&tyxqF)!&XfR&ve| zJuM!^J>>;95!q~eA$|)Qk)fu z<^DWWf*M1mK5j@dB+eny|0Dz^>BQEA0WBKq8XR(rU(S>(i*6iE zXk}IyUl4vhL=9pxa!{G~pWi?R&V(&VUXiu}zj2}?Sm$^L(se@-i&rGH@}y=-0-0)< zXr6~H@$D4drbN5xfGxDNbpB8jP(##B4@x_#1nc75WdI?hXI_Lw*YT5KWe77S!oXn; zAvD!(e_(T2OU@Gud=C9$ZNYT{JdN}VZ7RjOIJd}^0U;1pyiPoY()(I-iJ{*(>sBH|Iigk!H$)$*gu^nyx!C%_@ z(~kCaH{K_Mq2MX`vjxf)Di7tu0z~E*v&ot<$Q=YGe*AJs z+S9l&cfR=cn=K znh2w<*qWEarN5@exSRPo; zzk!CSGjNE9{4R~IV{z_2u{p7q0*6uoJnX)m;-`}!BUVyX#nccR{ZBxq4Z;a!NwUFb z@Y42>Td`k)PGzzd=g#xl;^BEI*$S+cZfC?jF|*n5vyyv>4;(}T@+c4uhPOgB*wds% z@pb;6JdB&Igwx{Op5Q=ekCTK=6oGt3I4hVzJm*4uBOM*w8j2z1z<@6yGBhEO$cr(1 z3Llbdjc4h47Uu@h#26P~V>z5#dJ$x80ccE{Ur3$|(g`{|j`bxUEZmiFVMjPgj?8>% z)6w$#fA<0UrT@2d|8?*G&u{-*n9!|_(M4se=jSfsiW7q)X6{{Zh_^8Xq0k=W=?LZ? z+4JL;&S*dxC<_GwftaCC>zf=k1mBJx(W%fQ=zxTf^~jsEACmq!6}ueXT<)CI2@A!M zM}NR>%EtS{X`#X4Bp4!LBDwGC+Q#VN-Hace&YUC-@NROFB>0?)Ww2GJu1qeu8}Do# zaX(;QoPkwXA&^t_5g^PmSwXk0kp%Vr2A(Pg?Cq$Wb>@(R4iMkige zLm^HQRN@b9V8v_#3DtaPcjbqsVM#ExzL1tFC0Vzf4RK=)fnhwM>Q+K#NXvp|l1(5A zWCT%lfGSWg;CVQDNV)RD+(QHq{2F{KK13D;K=En3nz(5~W|*Ie9|;rCx=1HvAjS$5 z2qu6jqs+{&9d+-#n0v4pM5IYh90NDp;nL~DokP~;< ze|@>?;@pLljg(+0ns)TS zPB9*sFd##Lc3}jmXULFL4)`FkNAgY413Hs`r41#-iy)HnVDVX|$~lE9AhY$uXX}4? z<9F%)U#We-e*f<+6a3%itE>9V{Y`oBIvv?Qa5tmE5*>VtgP<-M`nwV@a94{QWcpMDq zQIwtPgfRfq_>0xyW^I{RnEfqwBEHysnwDygYBOC;vOvCM%tAS{)D@T(Gi0GInv_@q zo3uZxH0h+7hy9X{m)5!~LLVKBV82Y5Z^p6yTuCR?} z?bD%xOE;d!_1o^szXIRG00Es+sDcma3Vq^E{fujYA|xDoV9clzZmF&LyZ8}0ln#L_ z+36%_?dGt%@-HW!fJUQt{I~QcPtc2E$xWdPQh{nngM!tpK-Qc;`~y;uIrCu}FGLTw zJ922a`I1gEehnf`{+@DblsX{}1yrJ)%}S2N>F2^E13_^naH&|3UJjrw73KKw5Y)cj zZoasi@~_5gq=sjsI1+{;W8k#K`D6yx%#o70o29~IkLh6AoOxIYb}&}h7n>4pR?f2d zitfsvcFj0p+sdH^JfxTu}wnb)1g#zkxtR^JZobKA2q+vZOu%ed9(N%xPuRr1_Ro|MMQ8-YGwx_|tB79K`IGqO{U@6RxE>sUW=u{!*Mul`e|s%eg}^5j@gvzP^*j zXKgDdor(dg$_Eo1H1nVeEI3IdebyHm)D>V2Y6-w%72o0;*?PAN>ZX^=hc`BBljZ!Z zCQC+YzXKiVya>o!M^Vc5fjb;_dUDtXeFL-75G-bHm3j@AakTrFWY%&>CnN=m+myQbZphoOLiVwI(%^R#XAfw z9XYms2P?cOF`@?9S~_}c-Bz06b9Wj#bZp(wb9Ne9 zDr)oW9fsCiljNVZ^U$)PXYMpa4-GwI=b>dwe)=v$1ogC?hn7tKs-1=oA6uvMPu*$A zl3nmAI}a^WfGc+yGWjR(GDPxE+I{GWy9|}z|9e&MuHN9QgU=6sZSZr0pBVgu!S@XA z9DLK@=D~XguOGC7=M0`WSQ|{(tHJVgEDzU+VvC|5N=R%NQja>L}wN9xJmEPM0% z$&(LHe(Xb&BOjbR`M~7K`zOEizR8jIPL8~1^5orJh^W2A^1#etz(?gP$7w$lxCiet<9d&cU}2 zZX0~V;KbmD!TSgA7`$=ts=qc;f4u+0{r|K7ecmbZ9sI?&z!SIhKiq#$|E>Mk^j{Rj4E`!oHf`HSYO&6iaof2;YG=HI{_Kizz)`M;aL-+Z#!Z0_`o!Z-3M zH~J05?`+=Gyt;Ww^TOu2&C{AEHiw!k_?JgE4{q+?>~GHN{kPtKw7~Aqp3xHqz2?$A zqsQ07v3fXK4@c_Za6KHVhxK|`tB2KkSaI05XS7@oOZ9L?JzQQ7kE@5v>S3`S9$OC! z^>ArD%-6#u^>A@LJfcggX-a6JzQ81 z53Gl;uZIWJ!~N^we)aHm^)Octv-NO6JshZq{q?Y~9?q|az4b6t5BIHy`_#jE^{}TN z2KCUd2fuP6V(pc~<}LMbb3NQt4>#7s4fXJmdbqwGK3oqUs)rBO!w2f&{q^v^dU$U= zyr&-CT@UZ7hj-S)JL=)>_3$=_!Jf^x*27!s;m!5%rh0gz!@fP6Z>WdY*B`#Fp1rmn zUQ-XRu7_7SxaKSC;S~-S?%8~KJ-n+0b}_3*-axV9c% zP!G?qhimHL>KrQncX{~#`uyKhn=dw>XbzYB|MJ26na#%L`%1PnKl{}eZF&ufHpEBI z{#l48%r{;Pp{6e%MIRP7e4W$-d6zOkUWOsTP1Yf)35Bl5CMkPK$*se_NWa75%eL}D8MBq)NeJ;u7z5Nsh$M9s89DO8{gEsa zGLeK@j%-YZ=kLfp8Lo^p92gedjOE369#cienSDCrr2OeKm0zYk4oi%h3E|XkzPFq4 zSNuE)JkB!L#?46V#!?tdM^%VExp1n$$QAO$SEVTCvXcC8g3?(mPZl8~rX*S~a0B5MYs=Zf z>>tXO!?1?f2&I|E38f(-D>VZdZMNH1sQ}t$OkLF!cg6{%K`?EwxFSNq1Z`|~T~@Py zke1|>3|%-n6Sgi34;e==bOjBYZdSRrEV}$_+vs!J`Ou<~mOr8Rmc78X>#~~t53ZQy zyKFW_^FtV_6lGja7ZO6idi9`DZhPlms+A!su=IEe)?_}WQ>bKBmd)B_wK)6bLLA8G z^QcTT0RQP5GXB&M(NsvAQ0%w{%7_iH!$f8@jm4?)gd0;^qbvx9g8%Q${D0J+&NL2R zw7f1?PqsE{b|32PI<$Gq?n5{4G9)FtX@{XCqH^*Z?=iG?Y-#P-y0rF&orl(Bh99}d zkVUN=TatHOzthlixz~qx9$J%=e`xoi5AHm)YVsf0Wymz%zw^+F$-i&sp=7-8-C=0; z=&@BYe9t|GRs`WckDj&_ML{7jxCYK+qMtcVv}Ds`M2&gglsbO zmU|2x2}PAndGpRgx!{|29tv&r#(NAM#x#{_ykVyy%7z+v{qzu~Z1vdMp<_#iUU!e7 zm18K6HAAo6VF*RFYAauJk0DBU_*i!N)jJI_%%cbTS9|_$HRYzb_Fg{9S}xvx==uV zfMZuEcS%I6=&0JNB#xyX)dv_B=bonCl(MsMro^TsgqYWVnj$+ooMTQ0X*!x~tr-f? z52*Nyp;y8c)DXq+LAc>G3N8;v^>KiOxu?2Dh*qof`SKis=SE5!N&3VS=Mse!6ckEI ziQF~P8m`e$*a^*>kg2+5`kpfwbx$zNU6r;0kvH6TnjREERQ_C!d@GcAvKIX zVW?7&Z@LX(vibusq_)-hHYs<{8O%Kez$h(k_ARSSyRl*_d>|kSlmb)QA5ywXp+vk! z`-@Gu<-8XqMI<#QB{yh|F#BKb-3v`c!_hN4C3vQoPReQav1xFb)u$$mj8B7)m|KcU zX$noHB@f&v2&mI2f(VDHe5soRl=$gNeiQV4{nw7_V}*-z&q)W2jrBdOI4o;BbP)%l z!Ce%VUZjyVs#<13;;u+*C>anb><6j@Q`iR$z@z$H;o{u0{Xmfbu%q8}A_ZF;uPPDT z<0pDJEGaLnRlF%3rcr9^im|9sDAc7TLB%qq49yVTlZA87%DL*d9uh@ZbJcf}XPhiC zi>EP%QyAM5l_o0XFKJ?JthaR%~(1Uj$deBZo;KtE|ql3E-UAX(u z19u<#`rU^fu=~*ccOSan?n7U<%g~X7qq*IOW_KUDVE3T|yASQ(eQ4hGV9Lz5@#lP7DFC##buD`!tqg;}0FS(-e#V)Eqj z$&<%To?JG0vN(D2*vXTH$&*VbPv$32E}1;Jc=F^ilP8a!JbBdQ$s;FEE}A@f#N^4t zCr=(WdGgT7lZQ;6Jb3ctL6av3Cr>V%JbB>c$=6SwJYe$V{*x#7n>_it$&B)c_a8rw>;lSA7|vRgy$wXGz3 zc1WYd=n2!_dTWRyfBY^(WO!_sA@@4E%h2k<(UBd7R*t6dK03V15NRCRWylQIcNsFn zwOxi*4vtoL9*P32Ob=B=xqeKC!f1K-p`~4h?AH~$4_&_d(BpO=x@`BM#a)I7>an{F z5!Av?LqIe^UAp_w{O&`S>@rmNzkR(+C!YV&xI%NmiOzVe-baN8!-H=d@n6qdBh|gadIc!n=6N}8`b{b zi|1ac){rMS!qj^F3PYgV%(vxl+Uw-Ml3o3rT1>UVX%yF#CfP+6ylEvbE z+fmm%I`;|;gcKNCpbtJ&F>2MDZA?t2jaWxo;8*iHsU&#ejMGD&XM{X^?4l?Hd2K#L zGgq{0#JNg^WYz|Hl*=_&MGF&*(XhB_euvP;^lWypEbk61jVFJDHalW%=g z1W^-dMD+SA5$1M$5y%gfbu=}Y!CRMH^{GP)|u^n+AKEVbxLeky-X z84Gi-O&5QIs-dZQpOwcqy8i9CR+gVWRO|M5b-F(BU7;*gnLHRsKPBqO4bsSiu&9jG z9O`ptc~~S8j@J8lbkLl;{_VM8)Jy-PLJ1i#D2q-rH0~or5JH0h)03Y!S)fda2Qz0T z6f`ZJ$~_i`#7bF8QRn}6_5X3|@q6}+Q;&B@J>DVpc!ye#AEzEavuB)oyhE+Wk83@C zT+$1Sj~~~1{J7TR$F&|mPCfp@J>%5l zFWoavJ>DVpc!$*E9a4{XNIl*m^>~NW;~i3ucSt?nA@z8N)Z-m$J${^eyk({y?~r=D zL#@Y;YdwBk>+$2%cVb3V_c&!?#$NORG@eZlSJJfpoDE0UY z_l#1HcSt?n7gCRRNIl*m^>~NW;~i3ucSt?nA@z8N)Z-mek9SBt-XZmPht%U8Qjd2? zJ>DVpc!$*EwJW3^?~r=DL+bG+n0maAq#o~(db~sG@eZlSJER`(kb1mB>hTWGtB2>- z!*lB4+4b5|OyQmOxy zg2!lEN#X32>EVQj8V`$}=nxdZE(YBJz))0)htt7KG1b1yK$!ra| z*S3<()({B2tt7KG1VV2s$!rZtL$;M<&JL}a;kJ^@){tquY8tI=4VlI(cNsE`SL`wb zG;Zsm-nt;kZ|k9+9NN}Hy)|TAFWLECtM0X}hx*7x%YdtnS4-a3Lw$Bgd3Cg{huV(s<5JLpA4p_6|d9ij?K~->Z7xzPgLL3wYj8ukY@+J z*87UzF#M~%f7Sc(-v8D6yQXpW&-vpmk^}oU-Xb}2vPE*_WQ*j;$rj0xlP!`XCkM_l z9y!@Rd9rWvWUH4rAM1LFHKF#;A9uaPduR3-+3F?EN!LqUM<#oT$6YURy})EI@wn?H zuHR|S&H%$Up6n$aP4*IxCVPoTlfA^F$zI~oWH0fk>m{x&)Lk!eJ(=t!9&Pm!U(i2) zwAD+TldWFjoOHd!duQ&03VdIk_1>9`y!Y%9G}VsYGkNmvvmaX+oIiTk*%9I$z4Poy zzVnW=BRP5d}~iR($%Ok7X8X5xC%H51p9u9>)=bj`%|q-!S5 z$-a?h;%=!SUbni5bJBGa*NxojCLR!Q*G*h6_oB&Zzi{&8+H)s~|L1$uzpMCvNB=3_ z|N9B=0n79Me-nS&QGNJtaqg{Y6;zOy)ykLiSe-{xC3ofhLV2XjGTP+iS4Q}S`&k><)heZUh- zo}JEPjPh&+XU}@Msq|eUo_DCqprp(x6St%8{armu+$OsP=`-*JY zRb9&sC3VvGkRNF)48`GbdP$*VTt(iTi7amqV3EB=cGhNpJVe;@lhZLXN!H26ZE^ zFYEMHC4C{uyYs}FuaS9PhnNQ&^ANhfX;a8c0aC11T(_@j7?GJC+8EWR^ycSYFLjoH zOL1+8RePU6e*caq`_sLrDJ0DiUXG5TaUXpQg*Qp-rN^vkg6!TN9i>}BhTP@!q2WD1wuaICDJyUmH^GCIy&taA|ubF;v&2Z#>)`u zQ+kVYuSFV3w9^+z&8!^3p@{+?f?%>14^ZP$bgk++EbsnFvw~h(9U$bR=x-Yc*W65) z0u4v?`OSs7*J!3x-}gN;LusK#ADkwd(ypz23da|Bt6jvMZ|><@q^%V`~S;(5}ZZA@`at$<`qqRLT(J>5^+yx@pMVnP+GMV6ntyCBwL48mQ(T=_ovX>%5s6V5+&fM$P@WrtLZ^EuyCH}jlRw=;_KT1n$wiWk#8lyzujRpxkbG~GjaZpgi+dngS_DD;M|y5MvVWrip=bWMiSJ(SBT z6v;t6zp=>7kmHtD)%s`2+F)Smpoo`+v^9|Nq9 zIX<+!-6ORF9bICz@Fonocfz}#>~P0{EQOcOt0EK)h=qqvLpp*u58+ zc2~X;TG5}6ZcYt>J#L`h|I)XCr0>)4rB?lFr@^VovfCz3nh-SAK??Vv<6ZD`R zk<==VstsLVE`0Ia^}rLp+`qcy(^8mUDeiHEJeN|+LMkqKjfrPfU;z6`y~?Y(yjm0_ zB#Ph_u|HeWjy~K;;=|5Ug$j7fTMz6r9ia8f1yE@8R~aF?BF@`W#RO)PC-w7|zVeEp zC{bRcX97o5oj%lE`9pbxM19FE6>w}C5T@gnEIcX_6VODcPNg>F!4H-LFTrH+mJV6` zzb7_=gcP3g@)AP3*W>?mNp_WgT06F;TrU_-mt?yku}gHFF3DzySL5T?500lxvgd|G zyy=qc>QY>CdJPOsmt^aZz^ng%JYAAKHzX!cmt?nwR()%_Bztbix28+7TSNM;$I~U* zl|rGdiVTAMbV>Hykb7M`<*n-wXb>4bW{07rJYjKg{OIjN;t3gwc;o3F$`x@^OcTBi z9UM>hP}ZTP^1Q})x`#4DqAM9%@^la7){s{NjHi1j>(I)Pg1n}CC|A}CHF!9k{Nw2! z%5y{3HQhtm4N(vGn(m=o(L%3Jel4$!7(ZxQ8g?mt}T3RhI6|Nnc?g% zL#6)rzh?j6xT85LNw!6EJQPW`MRSCI+oCygvPE;`q@y|N1zvEL^T^2a>q#BCX7XgK zn=l{S>L$!d*G*Wzv(-(Qk*#jRoOIoUduNbRqo^;)W^#WVng!#@^H(^e?Zo>Mp zuA6Z0%wvr_Hq@nkpQ z_>pJVlUaA&g!MjMH(@=Q>?Ryfb`y>#y9vjW-Gt-GZo=_oH{p1)n{eE96W04Y@a%MO zrQ@$ZE5wNR0q0J(_`gr)?O)~HUtegxrCIe>j=vfHZ+NPE&vXBB92XRe*~rs1USx%* z(CCq_2|Yx3pTcG3ol<#P*Mkg*D6|IrhvtE=p}4Rmc^EhCKEqS>J*R6DW@_#3H5P$E97>i=pyLSDiU|$*TvLllJ5ZP%lT**klfQSsKz)9^=a0Yo7ay za3b0ecGGQwgvuivrkBT5u|7~Ft`Ye35S1)T5(1Y>fIQM`@fblc(3QhtdGl5t^KDN( zwgSlhW7BdIh6tF>lP~0vSJM^=<b+^r3sa`R>Z|SUdNXsp*H3CsLFAo)hy0?DMLu{A04xSyxCe5ut_%#AW6cd(u14L7NgD zG7r~Wcj}UI<%|25^l@AOgW+bMQ z98%Jk*RZa4@Bh1avj5MUK-quZ|9Npo0JNvNx5xEgBh{2|x))hUIMWMQUh|i%EXzt7 zM>Rc)W`*J0QPmbG%kutDyG!w;K_<$o&7(b4+X@%^uMXp$m%`B)T1f9{PZDTyK+wA! zHSyQvVu)$Ujs(-VCPP1C@!SIrxV(zhL-w?%d$VZ&RbfQwlb@!8PyZO&fdp7aUfyV@ zBar-7fb#kPPk*JOi;bn}Ejz;M8KN?PmAK#VRQG1l{wtGOG0NnRAzt$&9_vf8Tb}ke z!#qF7J>@3!Cc8yI6c~R^3h{AT$nvT<3frFQdJFrnKxNou3)H8_d&vRwMn|ViPHwDB zLLL-KA08d&m(r=0We~j=Cs29JKfXD6vE+T@RP8OC@29tr#N@=hkXulRJlz*z()T=E zDSzYyJn4_?mS869#`c@C4oNv9L5CKP2Cc2Or@GF<{>zBBK9xx`X#h{9guudm3Sn+0 zet=r=`cDQ&+&Ps?htyA5BQh%rVAhP7EV|CZ{!2{^qhuqpeW|DrCJUI7h1qp zkxssx9#VeI>h#wUgHubRbj%i=)Sl`(3;Qpz$v*G7LX)$msHBWs+MLEZy2Mqx2;*mT z3^L1!pOQioh84vvdJ%;wWb4hj>n!ZQI9^m#FlXvRqxe!xml-35sC41WXcUV~eMGk@ zqjFPo(Ya>|)P%Fk8!~A7Q4Xu?EbO<+JP9>Sjd@Z3JeJBUVGA$=dPeht3HzE?0x~@W zPkz%x9t%|R5*5WCbp`9;2=hkW#Q%N0^7}uo?tj%Afb;vmZf?G*S@wHCy5IlNo^Cqt zbKC_e3YAkWNv|xSS}lu~*1Y6@(a26LmOoD%C*)ZhxdL_r`67sZZ44JiN}9iFOu z*Fyg$qGkWFPR5chMZb4}%jIojrrf9dVmz=?d<@m6oA{5!yi{!5)$4CvJr35-+tVF6 z+5aetDO5=ufGg$6V{{>_5@p2Fyaqv=W_&Xuhe8Q6Od@aCh_Z&kq@8A?Pt-h?s82^u z_HS|D*jSW~PobUp9T}xe1QVDgPfLyR_6Q-7)bg4MlAxUEu81qIc;$l=ToE+wsg73c z-;5umwxPGu3mZbsCbMb&M!}OLI3hvPgU&%P6heX0>d6pS6$VI5r4RO(;8*#=j{NK2 z7@i7sEeO~U{HvUrMF@-RS3Blb@oLDW7oyGz%x8?d#dCA`X36X zOBpr$5+j7nlgDS7b9|V;g^|6kr~{D}79Tz}7_^7{aqKQcJ=r#=0|&J+BY`xiH0hVfE>Ct%0jL@%?Q1aIy6rH6n* z-kVy$UwO3)6+l7;eX{L9HUer-KcTzwk1`qVB}stTZ0_`(=VH11Ew#7*ATQV<1aPF1 z25?73A;oT-aDo@;l~{x(b!<;RzPs|Lf~M&V86;LxA>RN2f==+EJT5#AvjKqN)Hxd7 zQ!0`-4d7U@!t^B`J?bwawWp7DSN@TtEBrXKgo1d2m_7BTR0JYq=UMP%9lTWRCz(q& z+_C~_I16~)%}dbt@%HqQ?#lltdJ^r6!^PnWW%iqWrKGFWZyI?Ou&Xfj@WP@F8!t#O zzlJGXGgrzL6)?IwxV*PAwWa^vli}$nm$@wTe}ZX)Kv^7FTPYt3hL<>8{2*Ny>B}ma zdYJEoVK9PK@mT~7P}moPc@Z~B zvw>CdBla;x8A|7A2ysm;G{8YhD?}9G?8JIEdIaCZ~m+OKcDu)srP^HzV83Yk@j@= za-;s2EmrXb5aX4tM}n0Xh6kf^n9gH10(tojAbHmVgf5&gJ`u~7Mk7fz@rDo&t!$jG zuPmSMe@RLwWw7a#CT7kgl0o`X5V8;;!12zE(Hvl|eA<7;Set5H;6h%o&tI=_R$b3h z|M!zk$s4&}z>H{f4eH1%L1QvX3M^3MS4jGz8%7^FW^lm0;P@z^ludOqX#CLdbnRJM z=zr0ueau5W!T?`Hu|+d=A|}Q;C4PoRNI8yHGkCB9!~z<{14zNWK%2bfB$m2yx_f1L z|Mx^Dt|G%6u*}Nrh?Q!HoM9*ko{Qp8(i0=oC+D>&l|D0K(dmSV|H_QbE*lvP=7lNwTV6JvU2|h9&5|Vm!_!^EQvdVC zGbbRXp6fcME&k^rUS>8@d^|2fmh z?~W8a*q#W$-{Xp)A-DuU)AGevp>J4>oisyFLkan|HqQhpcXPpdYl43za3W3jTJip8 z`DMP2_(=kujLGGf%Onp<4Lncpa42cAO2lTJ_Jk%07hdS*D`BS;8U+RbY)z!;T9*31 z8(s&-&$C|HKC|(SxYN)bWaM!uQY^o|F_=?^L^>3M!6#=SUx2khT>$fN_xt}Y>-C>H z_@utSL%mNoU-X;6|D=D$8@(@^w(Q}@?^7N2;A3E8uy@Lv1e7i;YEOX!lIUAtQj8!k zQwaa4+UYKSTv4)CiKJAgm1^$Hbj)JH_2pf zW@+Xw6#MNWAyoWDdXVq9`52Yf%(Hkcb8g1YGzYP;S@#BAi&cfD*4j z$faR`qYui=ROvnx0wD}PUX!?m!EwvS5Qvv)XAJVmZ$skg@>`pz4_gu};%#V^pTlRO z6CdC@QejK5-Mo@*w%oOikJaR2esClCy97I9K03^ZH7GfNnuhuz2gTufQ)AL;CM9;c z1#yHm;UM#{p_@sxMBVn|duq%ZoU%~Xmu<63GGU-LC7xU@ofgFL*sA4Yk&0J*mtS5;Ki{t6TB!!Lguwb6k z<6A;v$l@}A6^h*N6!}E*Me3DwlZ%H5wIYUz7y1tOXP4>>317ujah8ro71P-A@!C-wsCXTf{5u5iV^8egZ5=R&@ZYr)Q zVzgJXt&acO`u(4GCjak#`}fUT`TwoeJQw$z2XD|2*Rya+6-=f3&;n^IUzr^VZv>H0 z5YqvmI5-x9C*Z7v4gf3uFw#7_+}_&l@gBc1EdgELXbDMLTuun0Ar{K9SurV=Ou!Y; zdEuwvD!L{Uz%|EJmX~+=3L|cB?e=)jKsb@`2)}X4g~BlxMh9IOKoFS-{Dmlv4-Q?z zLcvAAUTY0x+!g+hgS zW_XCPxbvgKkDqmfU$X^?@ZfCl1xzCMOP?BM2%*iZZt-X zLCj4YkQn1U5BYrGwMr0`NWA2qdkZK|owN5^@B0kD=lA@cckLsXeHQ=(ungI=t5N+aK+bI22^ zn|+WksgYAhcY4^BZ{*VNBrNqSd;|g(L;^`Ym3P24N~wD1T1S0lsQ8gG-Z3uEXf?Uw zTLO0wox^Wky?K^dHhw#nrYBa(-M6Bsd5Kqyu(I-e2|38*0t@czo4o}waN%wPhv4#l%wDrKF+I67qNVd$x1D<*}8N5sN~ zRU%M#V#rS%0WQt5Xk|ulx`{lxr}qvvidjh*Un~ptwjPQmj}F;g~4o(A|I% zvd#aTj;qw73uJh7^HWcK{J8Riw|%@N2OKyLED(@nIkO2!6C(lRVAq{gcN|gnYj0DB z5*gSjNwMl~@h6V1PCaN|?t>7Sq!(Bj8yXTTK_-Ob!g^2L6Q=@SSR?Uj7_lnL05=d) zD08uWN;afwb?Slhl^=+xXdLXaxKrvBc|8szq>1WF>azykD4Dfjv_htq3#KL@0hrnr zC?t!diJd(4fN|x6+a3@Tj*Hu)bk*g>3OoGfim+pJ+Ld~yOc2Yh=>&C;WoJT3rHI-5 z|LWBJ=M~?-uFR`Nn+^pf%Af!PU^TrXFlfDmjf0m8kh=jhSs9LtVrY+#2@EgfM1iwB z^>O3Mo7+AP=fQ8`cJn_xc8azn{iI?ZY^K3HZJCcC0^Er{>C%fkmQgg?vxY+)f9$;E zkFCYSSQG*^pdkRa@I-IWKu9ojP9KIJacGEYjx@=^F5vtJ&q*Qd_ot&n_S7_c%dwpK@F7rzUazC zZjcYa9ca0)9u;1QlGJ@{=J3(wsV9#sZ*F@sC$T)0mi4=Gt`?}`)IHFQ`W}g&WLijDfW+TBP%SaJ?b9L%T^OBz=;?=umeQnV~RaC?W`IH~>VHi~T&cEUnGL<1v zNLeT$Pm)jn%h$T$0Nn9>qRXqhVO+LRS-DJ;st zs$HE+s`1HF( zsDJ+bzhnMq`gg=rxnKQ0#s7ox&*kkCP2b%1hE%bdJ5v)>7;t$3wE~3!GtU#$bLj8uwgDDDe6P?g6^$jxu z1F{U_+aOE2gc?1u^sQ}Q4I=Cq8`SJbN`^x!2!!_71|X}>9DN)NRG6wX;wM}f22!I1 zHG^XAvg(%AshOs4d#x?N*pcX+?YE{xGMLsW8N0v?rhM!sqPWsg)6YuUv6xP6cfvl; zbKt3&rf+)4-vLmXTwkyT8)PV`tEVXJ;Sf@N6%odC#+2u4#*$ElavYr$E!yE-)wL$|$3 zTTsC*9=Q?{2d4mm8LOh~>{|U2gYi98(xQPEt3oWn5Z$T225aKc=YM^rYWaZj|0#ZR z&;0z)+5RwmMxzeY0gmXwYXK3rM95AoZ=X&8Zf^VQ>bQ!FiLfoGWgw*#I%!VpO5Kn`}#U^3uZSv7g&O^4`Yw4h^YoGal%nBkn$*|OF$vJ*S))L zy-L>}2M%so-aZ}E+uZi{now+#+v|N=d*D2TXH93aem!MlD1Yis#E;h}MTiWUS`VwP zS`ys4?e?ibzG>TE1vW!jP}pHf=$GuI=|Lpy1N3Xy04+IBY3j6OV=H^H;?7y2_bFc$ ziJMoq-{@n%E~pfi#qH=3I0pYGK?ca;3k#>pMP!GhY)`@{nu5q89>!;NX70({So+?@ z75RT;ZT&+QpSt#w<5K{BdF{;Fk;S*K-@CZthkxkL^7dmh$@x|&0@zVnJ{Iw^M#a>T z;ehf%Bm}0WJM{}NpD~A|U#2;wCJlfQ@+0V6NFW`ZNzUJm@8VXXS^@6Rf)o-lV29!S zNY&zRk_s0`0-Lc!%VAr_Lt^hb;eI-&oy#eBRNw3H|C&12sV3_{3yUYzb2x z6}U}Y5Q(qi89}M? zm#rXx9(M5WDngWl`jVx{GK1T|Fm1;19=#0oKaf8sZ$B{`_uCn!1_)LNnS!ORjKiU? z2$9_QR07a|YA)+PCA+)@I>;VOL6SPod>DM+Jg&RB?eCyRHa5gGEFi1Z7Al$SQu9;@ ztL>wKMWzZIo@L4o(~#~|4%I`r0k-3ZR<|FSz4Ev5?xdo)TNn#1__;X^=8qMs&Z%^X z=T&I7>OewpoopHr6Z>`v>Pr%&^YFanzlD1VAJ*VRJZB6e;YuB>!o}f5KY>gw0P{Ll zT4U77WW%e#M7d!}Udu^)*S=Z)KkYs9|MdSmRR5>>1dt!}pS88yPEUHtP22A;!Yf#c zi*jgb;9V^R-D;x(fvsBp>h!D#ZGWJGL^Mb26v=K#aPP1JR6~acXF`RP72*IUj>x46 z`N{=Zrg}6+{|GB^KXlY${*Wa3#|PBv^sISpe^BifcEnB4phpY>LqxhsfiPi?6p^M- zu#-m>ygC4Vu+p7Q0-?fId4>WWU7ntlsm<*Vh$a9rMV=o=W8ydl_E2w8+o!04CPUAl zD5J}TYN249eoL6FQ8x8F%KDKH)YSDC4tjPHW~iekvC|oWasDLfstM7}tJ9M%wYB}@ zWVqlJ*Dy-X__DUJ_E=t7UlOav#oDS!f=73*GsC45s{y@cBYr*PoI|cW3sc)awkv19 zR42%(Kpjd=QH-nlN%V{XF6g$YL*+%yL2=R1T?R@LbwfIVFk7Dfm?`47e~gA8$daCb zr_*=Rnz=A0um%6s8@I6Yl3S;R5zqyO7Nhr)RIsi4KrOCWo&M-4Nwxk?q6Et}jlqqs?M!O3Rr}MuL>+^q_`uF)iKfU%k2yoOBKo7f- zT&vUb?|9q(Wp)J|2fz-pDL2y^EAXPQ)+t9S!@x9FD~kk+ntvs462vM_Y(1u1-(C zJ#K6JizT`=aUD4p!xIcW$diwQo zTiajcqUl>hdgNq&Hsr`P)wilABv)0f_^>=wf&2Qqn5St zQ*#)gQR^4sY_2NSYH|T9b|R0N7YYZ$7@d5!S|!Z(m>XKCFw4{PS*YzkzX_#;PZ(yM zfud|F>P^KX?T(~SM}UHhNi4w6P%Z(1kEVo@e;8Pp|-!k?!*rcsb?w(N!{&rIi_4sL%_+$Y77 zv@9Gk;V4lP7aN4&g0ML>4pEZIdQFT7A~fn9JF}xYG;9#}@_l(`@36(@_O}9s#!yWx zQXT4@lw`$j@N4T#oi><~R7I)0o!K)R`7Ir(8lpBa$9?ykuY4w8ud#_YNYO+)Mi#_F zcdICX(@q-%#BvE$Z8P>ZN~2r@9STHgu3)Ur?4GZD+I?y#i>HpbTWv}|#ZM84o)qS+ z-7p{N@grug$E^?3%B9dlQo~aSUWS>L;z^h!_CFhz(}c%aBJ9 z)|fc@c`!mbM52Kz8E2wo%)2c-$5)`*r`9zBehk^Q2+ zvyDtrqPR<~H#RfX|IYud|7A13<7@9+yqgw?3;Yr1|ISR!?&kKt0hz=m{-& zq%o2!avPHir+)pfpW{sv4oD-d6osSFGw;{4Ti2oGnW^X8-2N?zI;uh?8MXCO2m(f&0ca+ZevXq$=Frrz0!gd)YX|;^VrmHaWwl2Pqi7O5#x zp*c7E$5fNUb1!Z|vaoEMz(pq0PR8E%mJNps98Z&|bx zz}`AWCn$4YfR;%X-rD}nb(o5R4nt$;zETiCwK{PEmi-t~^$Q{ad|X{WrHUos@r4_Z zo-~O-EcK3!Ct>*D_P^dB)qCX_XT>=~aFv4a1IIcC33;@ax3q>qufQbhNBLcP90B;W0oGOaF1l%r)) z7dt`7K&hnRF||tHp%D;-sVA{VS2J>A9Fd9F)#M0+WBff4$*t`_!w?uQ?isXzL|j$spBoH-X6R%)H4FN0mU`k9-D^jB>rJ>2;jYodK%Hi_N)KzY7|5=pAQWC3ja>qoP>MEQZ?I+1T z0N?WbftkQVEFZXidz_ia-ra*8#_(m|y-+ec{&j{~iUB;6hS+>g|FJWl^WN z4sD5H#MZDtg+n|jb%AL;f6O_y2s+Gt#UbiE)qfBAfA!jrjGX_)_09nI830G#^ZfrE zkDG#K$K%8oJE?(Kja+XjWLKT6D#${Ei3mQfwLyEgC8Wl7Wpfmz&>bUpAY5hn|MgHpQ} zZuB;s(YiQ+{hrfUdA`8+AkPPwaP#_Aehzjyh;KuX+>yP&QPfz{-$l@n9p12ML*4}ge|Be~g zcDzXS5}4wg+@OhIpdsGJbNE}POFcY>FKTE7OEVV<$aWpKQ(Kf8jdc@ShFje+&0& zHw1*=LOFX$jFeE7tdr>-I#F7wYrPvZg(SfhSP;MJ^k^v{g!GV5oIIE29e>f41iH9L zlN(->e2Qn2quLaE5VBf*>+Bpe&Gt+9!`itrsGG^-40^ zB9hkvEe!z+0a}F(U}}6v%dME1v`SpfN?9s0W?gv4m)eC$OK`02NWUUpNVN&T6e60e zjHeBFqA*ZT!G(mFrp#a>4Jl-i-K#rhDRjq|@I>Oh<9>on`&@mAeDe*wZp1LASDZD@ z>&Qphs}?jW3LxZEXFoz%X#rVg2D{^n#VdFY18qEgx06Ld9=c@5WP^r$kk1X=Tg6W- zQuXz7Dd#XvK?lVka$wfX+IBp@!iq`>YT=~)08EIAe6t1?Wmoa&6H>HL)Jx?|=&85y zPf@S6aT@^cEuGytzJ25EYcE;!Q1iaS>pR!i7r*Uycl`X~-B`c{zX|Z2iyvA1!1`Mj z|9bIH7vHn^j`cS!{_f&i{6>%eYyEYLd)J@2{-4)>bo~c69<%;$*Z=wY_pbkg^>5qw zbL)R|{hQXmZvEQE(TzuJe1hK_@^KpH2#tgW>H3S-zi8vB z8&BN$%#Gh%f6n^PuK(1=FK_(Z#=AED%f>r4p11fGYkGEju)e1+?%nuvR{EIVCvord z#o~wV^ji=Y|LRV(Z}HFX+~x1@yZl;z|AWgf_4jvNexbkr{^ieSzeisFJYRq7<Rq37>7?(RyYzT}pS|=T-~W|M zAK~wJU2=$d@#6EIIp6z}=O5zhFFya#UjNYZ`+fbw^V@v?r_Q~|*DpBtTz^03+~@lH zS?8YYH6MQtQC)1Dd!)ZV?;LWs*n93{{r&W_ulD!;vtQ!xeP_SGD<5>WyYD&s1b;vE z>|^}>w=WyhFD_pC;|cYcw--+AY={QYBhKFZ%;cK&hx{*}8v#^1kq#fh&yzkcNzzW(_uthD&q zD?W{R-%aNq?(c`3d!@ghd(P|kJ?Gp3e?R!#4zKx|3s3j;^DeZngBP;uYcH_Lp8s*- zp}v0Q1vXi%U&tn}xWFchm!5Z>#Y@g-lNX);Tz`N0dGB5P=3QCiH}1+BZ@IYi_vwpv zz3&q)w(CFYOK+~ezCy}0nxpTF>O-+BFoFZK7@h39zh z!!A6+_kZsEi+tzT?%M9}U%m1w-#>Ka%Y6UWu6(k;fAxx8?D>^DpX#Uo`OeSs_kX%G z3;&BdKg{=k`7$f*`K3!@Y2VhRPxbdFUKAU9f8yfH-1iqR^3=Y~i(lyLzp z9(&`T8}D#%^nL%>i7Wr+U1DtUdv~q;{mXYf$#;I^t~~O)cirkP|Mjl@d+luZ+7s8- z-agd-=@S6owK%u-MCbn>@qvun*Va~NKXR@HcXsYr`A`XfX=mc`nmT=T7_`FC)I;ir z5=zNTZUz6yRSc}s+%b=41_ZF7*qoiG1Uv3XY|tth%|@5tBk{`hJMOK7)bi9|Gz(JJ zRWV|RdKUwTLC0VLJVCZ9?=_5c;(bl`C;0dB>@<+w+;K(OYVCxfki5psnE^F$s1Tqy z{P%q&3)O_h2uy;2Sq4E^UD68yZZo75y<;cOe#Efh!5x=z{VuDXBMmiiJ=yPiv5-L} z^%HhTMI5N#MG5d2G4*GRE8Pt<(onm>^6ZC?>u&D2U-&c|DUY~W{ZW*ji7XhA z!!Bs%+^8NR0JybQ&s>f$lH7~^TK(bUtFs?AJN=?gwP|JZ_a-o?m6Ai>^<74MqX)0j?>m2qQZLZ!L&Lr z-Z&8jz?F!kiD#%DZifGBQe9I8Wc`z8KV&xYc|^EY*kTbL1X`z}Yrz&>xDQ~!C@6?d zt@PGfSx&KgS_b+>Cgi&KjQ8W?tFs5@6`#}NMaNKV8n5Dvf-CkoMMw9rSG2D2m{TZR zVZRxR-RlCh8}3s(fOSfgX4lKJ(*SOB$5|{;1S{)>5q5z<2qZKFCqk~fG2JuEW6_jX z5rJA5mPG(`BN(<&&Gp`MV(;P?hW@wyn#Eo3QUBH-+IfJ*FZkj6{#l;=oUzBv9pBGZ z_?q6Sjy9_7SJI+m_+I+S(BhkY^0%e{XA&Qc&rzrz?|}l|Uvn88&^XS1_H4X=mlV!Q zn0Zsx4q=OYJ%g4Z4hke_BeA=b0VnqUzEt+QNA7vsLiYK6kjG#|Rf-%IC9Z4GXvC_;kR%f3)U-{n(nkGV>QR58s zSeL5pk_VEcQxAP1tCF@F0SGa1tLf2ZG#st_bF+@J(e4f}&pv53^S_DZcEY6P>P$pQ zpQ;pFwN;6WJ#uP8MphT%wkE-_K&e*a9my5Tf?OMVWaH2WuBM%R+Ps#3PfbJqg<;v5Hd~cc~y(<8deDs5|1RT zn@M!YqZ8M3Q|CJ{+EBRO%!&nwY_()B8cn%$ct4*2v^;xq-q3&GM}Vv=;t}~KLz_}- zro=O?s}Ts*MNOipq5r;7FH65^HjKHmC!4YvV|&i}>}~Uff6zCJKVq1s2M#r(=9F98Zvir9%Gt8?=QE$rMt;8M{UkF=BC(mRUCL=WCm zm#8X;1^GaN(WbajCI{Q@Di>)kn&r``A3J>8x#;{Wcz<>-jOHa-= zBA5D&1IYfS65J;g@f%_=B%QkXMnV;M26Btl+4%vk9ls|6!FW=uNF4d$z<>$}poYMl zz(&D#zK!J(r8b>%WxW;W!V2=S4mv|K*elIZ&Y}X(*Bp{ zro-KvJJaEZSgEL_3Px0{d(!0^qIWE!pjXMn$k4Uz4S|Vn5UrZ9fCiod-p5a#n~ugG z+{xfdcr%IWJxc?3sl!xi*f`=RmK;7+Fe(knAtsDbV&sWLRm{c8Y|tx~=jP`gc6J?v z9L?3-2pthYL?g(=(*<~gN-0>jh*)n?mXWxM6i}ei~#aP%`A`R9oV? zAaX_IfV~;Ba}Ior3ZPK}A00F_DZo2nz}<|@RpLjU`ypz-IyW8v-`Z)Zifl<9r%pHv z06KXRztWW&HsmX$4fq01LY@tZe}TlSvK$m*ce)|D9zyg3}ogDMx5lb?h>G zD@{U+raFpGLn*OmV|E9_N+9^)UZ{t@U~r!!O4xkwbjO- zS^wt6%hs;0trnD%5Ae@z=Uy?O@TQ%w0Ia+R8X`Kixz!e1#6nP%xQL7cCCWj-KTcva zA4OqsKAnZM9!&z=TAurgxm11y@Yn1s<9QdN=vl*L;sK62$Y2eWgzE$n`lqI%0vrdl zDyZznUb-ht-jUvOFPWkHB@#bFVpuJ=qaan0xFWCV;8jgsqW)8LXnH58!C92mnK1o| zS6GHLYp{L%@ao))=PSS1f;zdZmhy7VH}afL-E2RS578S_baVsecQhOsNJtP9NHMGe z=9Z+ksC>7szvcbSqR)N#eA_PvuXO}MSPPJDJU&G!AO%GtyqZ?vThE9YeQ9YAxH_Ta zUkq2%)uc*}tj^76!FPUHVu6IUDfS8dOE|@pSL9N&Vd2*2GszlXOH%5-pK6@-Joe?s zsH>(JYdLgimfU$$4|3{f3KxWg*bTP~-)ES5ig(ao_gmpMXL&vag3tU4c1@qYP<@rh2 z+uV7Fmp1={t!M*UA(K&g9KJH-e#v?Woi{sl)R91uB&1I<%L~Yvqpefo3C(0YGk~H4^Ro#oNk}mP0zzgFr>0j0nmaB}(l(c4BpY&wS;# zFn7G7v&ASQ23X$(??jt=0qLzvUXW)ZiF_tsq?q$|>MJ+{e3U`%NfteE^XmM3n0Dux z@W1hKl@ze3zltO}SiP>wdRGWRs%rEa{S5Sgr;`Q#(XlGl4df!($5!X(!?Zh3Gjhz^ zvg>N(IgHdsyRbUilWCZ;H{#Mmj}RqljMo+6us99N!zV?2@}D)&hiP}-K6Z_L*0_-e zH4+^y7IKWIt_zSl2P`z-d$T6Rdi6BZ=^(`~-AE6vL$>?n`ROq2=FU^XA{i6RBeY3P zE)11qnz@@wl7iSH0nz}^YET>5h)XmY=i@qfZ%_9j+MJ)-!L6NdMq-2oev?JDJ4TJh z?|Onf1()(V@-wlGruRJN3TE-b^PR~!rF$oHuH#8L5HH-uSf+G80z#3TgKr};5VS| z@ap{h6!p%pi^swXS4PZa3MSqsIz%TW1*J%~E6U0W#Az$2PI#+iJ9>2e z&-w_ZKmO11{KLkUHg~>V-tiKg(m`=KVAEd01~G!e;lRUk8Ee2~wOEBrTgzBx2t935 z>^GS|vOGVZz1{g&>wDFxnh((?kSt!d*}OVOCCP|BiHYf1zE*Qsv;({2u!baQY7RTl z+T%T`YwY>I{WyGV0q|s9y||WMOgv-__0-8CWq|KQf<}wmZAE_B zZ;!sm$Nm4v(odSN{MYL?1b`oid^N{=(c2WQP6`2Pfa6GfZ90^3KQDl%sw7oJQuioAnzOGX z!}BrV6Od&(aK5?o8)~JEJV-ws%T(|jrUiRqq{ouM7y#|*BxZ`*0l=tMOrb{`@Xbym zs9b=7=(1P4zkBWFH=h4>_HXUqt-ahcz?}v9p#520n9*a`mf9xMGyrgsD^+hCG71GQ zL70t#E7iHb5IA!Tm{PywNt@&k<))cVCs|nS(CWhM++CkYouZ&5pH@~Nt%g)t_Ghqq z*Bu1ZX?^+P-SvGEP$TRNxN-`Z%I+XVxYnkdxpM)Zm<8Oc_3SzoY3nsd7 z^jtXN2jbBNAz{5??*$GL$!mLTjTE@LFz3>)Pby>@v%wMN5qo#$R+y_i4COM4yRZ~K zqHN3#B#q2rUU*_-V8iQTVk!GamKUao-`ur1Dji_*no?Dq+of6uPAmN~UH)R%CQ2| zM;`6cONM0RtsFSP{MN3AB|sKktdL%fqgZpQ0!s|;Yb~7ut$~0PE}z@RGowv~ZMLq0 zt@Y|mwYo6j{MN3Us+eJYvKL<=Mx)6o1-wP$%B^gqVHC4V?kKL;+<?FX*xt(ritf$}j~iX!uE(wKyztoR%g3%S zFHDDBH+Ma{k8!eLtQ0>+MuK;hv2VI514|hbL#TpfTFEAwmK6Z!| zc2AaAUYO1nZ|?duS3+ThE@RczN_@BQ&C$x+42Crh1;^Jo%58AXq;_?hdr-*aBuQH< zvAQrFE#BJo7#qe%*SbW zeR6|b#1%JHgd-(D1I4c>k^l4>RtXE62qEndSg`3+pihr4#LGlG$1tci0|d;+&Ug7O z)aVU&NE8HffO+MIUXTps4T4={srI;K)FXqA7iwx=}-Ts4{O5{q_W-(xWyp(L{m33Plu|GTxe@eT9u|9sry z-QzjHANTy<)*r~C)x{g0{vLr11F2l zx;UR9-{topadKEk>4p{T-Ixs1gV1r{`fr&(&M3(QMGxB;G*{Mz?=@$#OE=Elt~{S1 z-}Mg~1`Vk6Dwl|D=ybeR=?zQ~$xsP@!4lmE=SE{NOo_lC2u-3sr1xJ8ad~kH`psS6 ziIKwbh!ay*TWLe6mRPrAlz{{gt|I}_vE-w{gMg1=Y2hxpT_0g%>swA^m^)i)f<0F8%Ga(lWvd4D2R4@%j)73@mst8zL>U$ zW|8R=kkkQOF@*->XqcLX}A)d1$2DQ%gN?^dQE(hH(GMo&b%5x~IT5#*~;yl&b_3aoIUnu6n zD=e`??LPdlvIecT;=f|WrCk8JV0@rIkB%{zjo|3=S27$rd2yafy5FkksUW0pmi$Sf{%945|R<*ddgJ`rK-)F3%yXi)ASAx%|6lx2okP_jm^u)6s9 z^Ob*m^a#iZ9M<|vbyt?)u2Xda(d>fx(W@#|E*c?C5+WhVtrROBPN%n=a_QOQ%A331 z8D;~BX6FOjyE3J`5rCy5?m{2GcQ@$@cu`#af>&TKqCq%$5%glLloQ@zKcv56Zmz?sRzAeqNXLaN`%V2j>5Zk=IX(uhjV0^>{x0KuWOzVHYK z)^)TexI6eOECaFdHX=78wBk$*^Y>+0faUhxmhjoyMODG!Pv_|Y3zi{m}bP9+fG zqtd8d^4;2h7^3`lO%6&QPl;_cdl#RDB09zLKNjD;c){9bIPfIT{(o|lfVCH|Z7w#} z{^1{B0q^<8>f&@R5ES?EOm z&yH#!NSNk4Tf2Uvj4thxGL*^++VqP=%EuQ`Za?8G|#RGo$)98?3UyAt(!2~O2jY5~Q*H~Wvk;x?EavU0?zbCJKJ>mU7o z&xKu_=1ZHqemxG-xmU43dx8+yo=8rA!>Mt5i_%vyL&po$Jm{pVqRC}a7~iQzwVHR2 z9$#IY=B!)0ehr1E>ZnPgK)|OVH}HWy0;$osG{LUMMVdJcl$R#*gA{XS6%pcNGXFl2pC7{XckOER~qnA`$eSI?|H6Atx)Q1l* zFMid0;oss@9-zFA`lx_m$nG^*z1W8g5v#aGR? z_)V>@&Q0YMx}se0SzgM7Tgf!U&2++isZLrC6l)B_g%08+TOv^2OEU_ikL_KYk^eWX zt)J`Jzx5M~A6t9v#y70pwDCFXzqbBS9u8;%u)H*D0J|R*9jd%>Ty#ju(aw#&JHbe8 z=)4FGpd(dLzeu7=h6t#D){8tf!G>PVe^!^~Mr`*d$1v;V`5C(a5zG#7>n~I@+rlqE zLHqLmTop;j8GT`v=DRXPu7J5dGwk^C(nRq#ch_aHzd|o4tx)5sLdRoCd!{M1LY5g0 zb>`3Q`MO}K+HuK98(0P|G_5CAmnMd{wHpsrX4sSY(;rhn__Iz01?d}#yYPlXV%Key zeRQm%(orl_pi!gOxOi&Z`p>L+NaRoZXX9n`ocYh{(%g;i{&U#4rCN=A3==wwMA+*9 z6bC7Os+ARKQ$#hliD}#o-l10dY_^IggIu91#g~^RZoav@_?3MDZ>KRx5E`HgUe?Zf zoy7riUN8z&@c_idP^~Xtr(Q-sj^00ft1xqtcYPr zs(r#t6oxC)wWxGGcYT=4&PErH|JB$)^fH}Uwb-cYN3%n2# z3Qa6Y`GswR5K1JSTmrDIPyGMkeg0pc|9y4+ace)m_NJi$oLGDKdki+dT3(uuH}5{l zeS9w0Ysh0AJrX?_0IGvXqPL0<-DI#(&eh##ra#%1gLP{HocQ5j%F zR2>>?TF|zha<5AgRftQ>KQRzUBGRajBPMb0#_Zj+K13-QS$yQ=rRkx9gS$T)xO5`N zz7bg37q2|Lb|J8#qW~m5vBeFU8lqQ58q}aoh|LgvF-46)lze$6x@|q{m@O4dmpX&MrX2`SFU~Pa!Lacc>{q6@9GRL_}hj zp#E!rV&8$oS~`{&;I$$_t+~Z?a6C%;>Mf$4*|Fo@h9@`-xr*IJ&ER6Tn%C z9D!`c)9nm@NM200z(VVfY)8<+fDU)xy1ev+iCOG^0%ymM+)u8{Vba53hE@euq+3x) zr0yoM7N{mc>r$a7%*^uL95gda`9J^u-_HN^*?&L1ch` zwMMZ_V5BL6#NajdgH0=Z=r7~+X^dKBbqDd_B0p&AuBZ(Xqq1m$2`(ouPbWwY?tb$y zFF4^tYZKnO9ABt-;$QL#q7(`opQNEhvbToCKn&JE4eODI5(JtaUtONgk8JIJlYpk$ zsudxFHlY~;aB;%hl!ixq{taYtI@FxWf^U zA|z-ORAm(0(PsIMA%$jmg)j~hVhZ|{SXO1O%39BI^Rd|Zx z&;te_JW)Y)SByH|qUyr}7B@NOzXpYU5TF!J3XPh`!qw&Jxq_|TueS(A3;-}CxJ4Ii zoC)ksAgEU;Ks|x2L9g^5@}VCri|PZsQc9k(GunM#uIk0J$DYIAvz zYUS&iX+%^aM2ED4l^vk17lLSZTjCqiH1OE#=*o`8bJrICaC-V@@mx>-Kl+1}>i?g- z?&|Vmr{-<<_l`L?ct=fPlu)HP=y0OHN(enI3^Q`j5kL^YGe&tREhZ(#fq=v--;2Oo z*x;9vn!}qBKTI|RZi}4L=!dLhk^!Gz|1?X6|f`nvrFa_i={_65P zAlv;t3=8!UPCTenrMA!`#FhL6Fs9;hDjn!j|s zN5qd+tO!9%q`_YD(X7z!{*R__c#X7(*eL!sRjcl@kP+&_IVBRcqJ;}0%^tcIbtV)F zf31l3HRY2Her8KPbK+0?XL)(jc{g|e2$&{o@F#E7UPoN8c!iCSLC2F!>=YPjMACis!byS%WDB5Q_q4onaSu909{0T zDDLW(|DIT0zR_d-U@NOUDq38rI~kuC9%r^cGczuhMtu-2)gtYJq7g*mEJ<`qp>}y> zB1}EDygWb8y!+qBg3^*))jJX~A~~9-+DBtIOuM5y5u;d%?6OQijXip8U*TioPuTlw zb$Nd5c=rzgH!@pldk3MKKwv&PH>6%0!4$$G^;;&09Yjq=H_!o?%^yR8VUF53_gP-P z(I9_+YfB#{3JB^rT3iwzcN4aalfChz8E%WAh0)A$~v$FVFNaW4Yoz`=ra`LeS<>l z95B{LQ)#ZMMzyd2KzDoc%Jh**2k-Z8|D%P4SN`e539Y9>NwQNoB}bPhI!Iw^uUo1hRELiwZ|!lGt@garU}VgZe9 z*+h+l)@60&1@o1E3RjU9xJ9G9WCRe$9V&cd0rCxMz9jZBjw5_HKesU0=! ztns3G%|9n38CNFD5DNsiuB`NG7F0;p0*1;!aiHi)sUo!YorkSiOXFX-2InGnw;o?! z`OmP;xKW}aET^N890E_3v0sgf0@&AASds|?2*Yl>Z*z>$*HbmK>T%+j9p*rht-@*;B zP#_|W%)@Gt<#;}ZS`t=!E2r@bD8#8j%q^?C=Cc!fz5x73R^ey!U6G?@5N#NE%0T>5 z)l^(!m7%FC_q+oJ3FbhqX)Nff9F{|U+SK?2srTN;AN}?6t|?JB_q+f+C}LVstVWtQ zhr0qa#U_j^K^}uco&G48Q5mETA=T9-e=lOsWP{bajiA73w zoDR!M>18mfi1PLEHjTP^_D~)01_jo&l8V3*cEoh(`s%Ld&i;5VsH_8*ic(I#L5=|5Bj z+`(d1xF&~)+?s&OLs8|KeL0&sZ!> z0l#AH;XcXl*?+X(-}k$#yXVKM_xzozXUt45s~!lnjx@4?n5@-Gt`n6Wp%5jYuRhDd z#fAc}P;+fR5RTDeve?~^oc;AT>QIG-00=iZDX$k4F%eM!(G=Q#IXttnQ0fP(fPcac z{4bEaED}QZKeX{3Ypc8GdETCH=kbOFwbGVHQ=$H;gEi{@W&P@!3O*jXYtD%8fMO+1 zjaOuHN#Uq`g}atLjk31(e4E><+KNHX7*NTkn$ltmvy>Pqml`C(b)MAg9$6}8RW+TG zeF|u3k76VT-93F2!PcH{l~`HJ+taZ7uZ_mitj8+03W?>+0+%Y26*)=Ya4Mo@!1m%7p;^5!XNqv`y$lpkND$cNm0MSLPxFthJ^u>t7bI!(c#{8@>VQOA82ENv zhJ960n|0&Fv=BtNcQi#Y(iJBjM9IZ6*tY5q^kM9~r{U4oo__;g#uQo@i3&@w$#l3f zK`MZ8@av?gI}(4Tga#0I*6)L@I2`_7vex_RW>ea5ay!$WAh3Q|wWI!h5T}I7^q>ZszN-L)l zWk#!NRwU1oC7TO~6lB%EI5N)8!UEX~mv?{GeBpoY>fD{8A;j%f5OeyqYPj~qRD_jJJY;GW-^U`%kwCD0P#5oJgSv*(B=tgjJf zCs_dThEwZy#|L3b307#FB8HZC&*%U4{5E590bEm4Vw@2M^To)uS|Y;4iEEdW*nU`n z&LnFYZn&Z zafc3#3uC&DDn~F_-94ZG+w+@nD%|CMO$uLdGWZ;WVG-W!Bl{~kYOhWbY$gjclQV(p zN7zC?j{FO^qvQ8~>|J}NPqkjWaQzkQ_uu%HjdySS_+tOY8#lJrzklu9{OEuC&+4AJ z&)WN30U_{VT|FBjCMP`g+4(!$RvvgjunJ}I%ru}=A#fljiog=d-2rW*U+8&kdC%Nu z?R}2@(g`>uEZ`DLH{bwQ+)`j$LJAtfMYK1swNC?)V(-Sh0JHtc?ZLx3BJ*I_0gsU#PtepYXEe6dp8O zYmrC;w2UJ)bL`Bf%wafPbyq9rs?}o2ed{#+Q0%VmnZ=g9U%)&dNEE3Z*)nnsmTf!S zV@VAVt5k%AdOkt>gbQvVUYe^|zHCiog~h9TK7Wq7&mRZ8I{HVk>ofzfb7kNJNJ7rA zB6e$Cl|%M)?c$*+1!bMx(&g*CB8WThdDeKybnmm)ci!{N>C0#O@)^^Y&scx2^FRI8 zkGsd`|D5yL-#@nYf9(9vJ#$^!`wCr+CSHu(Vc2O)M_ z83HFVqaiW1L%b;6o*=ttI_Fs?PYcsUmsl`M`LVDp5<*c^wWT4ZthJxE$X$Il9c+}vc zH{h&MLAo|bc-lSFCp|r6?@M_XK@$HKCs)x!)!&-bL4neEuwgh9sNR1EjA*kXv5eWb}&S@5XEG>-H8At=-p*JhwGqsmg5&oM8 z3wvLbJ_@kpMuSCU)?*hBmimf%eAxI7S!c7of9|NB)6 zKe9M7p8=RZ1MIzi|IfYCVehSdCJFdqbRwQV<}T=YL|IS`VbmJ1_8I{X=RmmHKvFQ% zN!m=7FJw$!7MJ%as7G?geUpagt8swnlj3xpNfBSS=%LfmIJN1=!?RZ9JY==Zv4 zeau05P?IG8>fTv1-1o>D6$RdFa8m#;nx#H(^0>iv#of{(wh5(jNqzFeV!)$D5~LK) z-ttTkuI`;wp{;!=8&od&IYRCWa;G^rd!EV1GE@#VdfQoXsaR;2$( zz=)gHhn>?&Yk7!KigtQKLNz|B=>WXoC4Yh&$?W$2=YFhzxPS>mv%lIxMT2 ziH%?cL?)FsMs>#&sWb;zfaPl;st>wC5@mo=>gsJ-{pj-ES>xOnk5Iw9&Ss|Gr(>%e z#K?u1DADEi3AVydF3J>`=yIJmhb#`E#u*ekxPD}>5BJ>btk>f0)A_%(AC~tA*MEBb z9qZq}c+&bS*B`uiq?g=wb!yOW+V{FBHKRf?v4}CbB1K#<$kk{jCuh-8;rY2kLB@{F~VpIqz#|L%GhW& z7>8wHP4!)fLuczgd38RKyzh;b1O{&^1cLaX-Yn*eF)Jc)N#T?i_#KC1?HN~OIR&g| zWX#kzRkS(H%{#Ad3~syc4eL9vu1{aS-j|E%%dc5q-8(lxqR>sWOKRXa z;kqm`9TmhQ5w$aR#9fYK#P(cW;b{y49*(G!ld!P0@2emZH~1!09U~1jrzX;O8chnd zgh1^QG$_+Lx#cVYlB_u+Fvw9G@%pJ6?p-`#oc~+62&wf0+U|8ni_wHNk5fqv!DjX$fa`=-8S-yK3XKAy^wNMp?)XdL!YJ}O(Bnk*Tg z@pBRn{MI)CQ0z~P3mBC~2W5T7j;^lmp09kG^#EG34<>>B4Zp`|I&?MKXmcy4%0z}Z z=RM(-^oEa*fvYw+C3qN;A68eVv-?~7-ds6`PXVP|Mahy)6M}(fvF)^;1REgKL46=5M=}}v13$gB z7D{bvvZIgTJvC27u-!Q4)cN0hXnA$-xbEh@x7K3wCw2l`#3wMQ8 zBr@V%FGQsDGO2_x)(?VnZ$gHy?wL*T7WE(1!-C=q2C^1KZWcklkr)C6tPFumh7(NP zkDsD)KsDVW1Z5Z{gz1)7?>8^`jHOn%1D$beHW|+%*saYJ`YFQB2 zP${YvSR@BBtN*9hc5(Ci53Rp?acETkhpj(!@vk<%e*GgC|88;GkNr7$b(%jM-1m>; z=vk-1B3}2&ZmcUY$;PZ|?g(OO$wt z^a586RxC?AbOv5l)Kxakk#=e#(|CozR!a?7RdDqmdnAZO7LOlYUY*X|Z|?hEz7jaV zNsM>_Ys;eAS!)wZzTGsdd+D3RgGI}udI+@74kK1rIIsa{H?OXK+U(+ggsOC|L}V&| zz#R4xA!=5{kB}VPJ7K8liz{G)_EFS`c6^Ad2@P6Z*lisfk68P(KR(O;1V33`o#tAb z`~GR1Gny)m#IRiMqi1^TL)0`qVCn>;c%a}PgbkVy6@-mAt|qC`_MobkhtpW=;J$y7 z!lfb7Jyz_6AvBS05mzxjd?m(fuh@7HUF58Oh1$#g!aiWZw{!=GR#zW0+wyx4dxl(1f*dR}-sCD)|9BABARgR^}kg7yJwGxnd^6GS6{@}jvZrf(#DUcRy zJgNg}`eNU-rur2j;aEXht8{@B3a2{aIUJadtiza*M^O!4@Y@CdU-;t}?tDOhmRF}~ z=;pqER(}mOYJ!6FI6W7TX_&U$0(F&0J7Y+Q;B`1y@;6RUXDt=mnn*{d_AWkJ{eS*+ z{(t)Ie?Oz@KYx4%*ax)4_w(Y_wYf>$FX;+N1x|c~(9zNkloOt6PR5*GkdideW0b7v zD8v&G4$7f=DE=q_UYm5Zx;8h7`!Qc}6XO}A0+hry&?+zqPvu};m*)gIQ^1M?97VPk z0w@={C#sMnRa1FB6fwU4AG@X1wYgK@4}xGj!Y%!w91K@;YzD6vzL9&Y<^mkuW_qdI z869B|tyM#6dwx{KrYjvgw7fQT>YMvjEjb%igRi=MqLxMrL@|q{rbL2CPSr~22vahA zsm3df>e3j%VS_^jq%WSlHZ{Em_jj_ivoM`s8qz;J@;331)Yy}e(62F6YyvOCJiy?f zu+m;mvXvzEzjUb8wYlfruNvaQRJ0+q!BI@P$$5tpkTDky3#1IZhlud2Nz#4(`X?R9`m(O%wwuF+RgpWP<&Uu+{XNVrZRE7nsE#c#RB036wxi z80Z5z1nKJ9EIRFfWc?#9#SiwX3cEBuoPu4CuIMDCc6thGs`eHw@T}N0J5B&k#iw%J zsbHeU^4cS&`oI4X5(8(F9pF+)>mdl$wjve5QDJ?%vl=2LmH@U?wPf?2OBs~X7VN90 z;Hc04-jx5Zc+cnmKE~(&zQQv=cPv7?57wXMwP(%yc^3ZxBMwv>AVKNW<0zPfnjoFa zDhO@E3MF0-#Hv{Sp?lVD2p~jQZEs$3bb0NW^M#)&T7;6KE#3luBU8>wh-ud*TtENe;w&%zOIMX-$4*{*#<2In{m)=gU@PprPjJesJ~~8ugpD_^0KBMy zD3$4&KRM>3Q|h%4I6O~?S~X8nf{z?qU7JUb`#+D8?#*GL$;DYF)&Q)!%CSyp* z#^EWO?g3X&?KDXgWp!;H@$O&6aOBGrV^}@Vr&819$H0nB12MCHyfxoqJ`Et4-+32w zTA)SUg=52vqhtPmzdq(`eEwfg{!hOHWUbHt^V_R`|IhMmlLEN8|8;I>d4Ppn<`{#B zgk!qCG}bJQii2f>zeU>kQ2bK+tU!TAyu@0QSF2*3)wM|j+}i)uToq?bO|Q4N|HM6* z<%NPJTd3T6TL0H^tw_4SFP1w>(*Rat4AzR*-@LpwiGZ8?Ut4l0X5LdRBEzWpcoZ~7 z`MAej{7+c9KDxkba=!?tT5^vFQd(1?!1s}(C$CL%+`;{?ax<2cJ>hTXUOJ8u#+VKG zfiG>=Ng7PnCB#Btgg+P*Z$W)DwRrYQhi1X>9cv1DA1*LPc)JT zsNl@vyUnS%*7BG~-|6NcRNC1Xo&d3C&1?Uwp+f!n2*ti`TGO#cGZFzQ*2Eq5-lv`j z|3Nddz1@$~YC?r61&~5mDOg>bHLv|&1usChYE1o^R7B;UQ{s^YL9Lf1>ftht(w4xS z>S^kvx~Pg&%1A$SL-khI<|9`7zp};>r!3?oC8U6|Ozl>@S%XF|u_dULc&ij74XEqF zOk{dXgu;Ju6ZW|Im^S*S zd?bUyNaX?+=)i;Did~fi<-*rMH$qIIun&31u3jZhA@b^NvskkKEfh(K(MUpqcSu+X zM%Tb_&EQaXs&>-TEuTQ#NwYC4PR?uQdL>zB0 z!WNLN=L$+dH6;BlERK2%NG;@(B&y6DR-HYm zIO$7TCrd>jEqOYX8gH0r1q|(Rd45X|hz>|JxV?JYq{D6PKcnh6QIwR}vGYI6 z>mM;Tw|U?ra3EY$bz(XlSLScHVQa~*D4#lK;hj7SHe;43yL^jjj@C?krK$&VhnCmp z@H%jyQsy%G0vq2c`vG`!aDrMW(b&w&r?NFbF( zKhFkLL{wIU47Q0RT3!kqsz^r$8Jd>(Da1etT1BfeaI=UyjU%h;Gd3Lf&@87AMp_lr zPP{@GwOPyqmvkr5F0B=ZzJ({cZf7ByrK29?I5$(gU;y_muTSW?dEi6XQ^|AWLGD!I zRUF3P7kj`)RN9uwp=1lmhv^ejfNDc%K-laa5o<==ZC2MOY}h)mpJ{atfD4&W!ui&c zt*?EDIBw;w&HB{*NS-xUmDPxf9JKB+OkJH7;Cid;^Em9lz7a<#xzv-KP?5+K`2+My zu=W-f*g;b|z{#(A1=>SRjjf4vmWwBFOq%)X`V9C7_7)P{Ab5w1cv7z>sL>FwhKm;B z-F=QpV-kCzv7})Nx#)oM#L($4V&JgP|N2h#|G9nsf1m$-Po?{-244M@RJqk)oI(^&?=TK9D9P&Z#a116O#KP3$hUak|bdl z^+V&vUl=b(%HC#C)z_g1cWte|216Q1c@SSaz;l-N{(kA!$?MZ^0y=o$6Y;+KGnlC@ zg)8jdP^@aHKXgmC>&R#PJPiyH;}#UT-IV)4#;8wHftS_w&3XTuPy#oA-%!9n9wBu8 zM@Xi-ViEF0BJd9n1WFbWH4~o-@|Y$%%K~fEY%zTN`0Dz>`N{`X^V){E4MBlRig5p=GqOyeHlrg?jSJEBQq2$&dyghDJ-N@<)wR@Wag zU-==Dyb7*h$`cES3CK8Kh&v@Eo|C{XV{vD%?4!FB4SUerV4F)qRDOkpMki}14fAF~S!2=IQ zE-kzM-p`eOzI z_$9yp^R1r!`;Tj{d#{gxT3$anZohfpq{tFp5+PN!4Pu-^6QiuM)QP06C4+UYMTsfn zQobV7(OmIsJ)#;2oLFAJZNBhrlq$Wq*F&v748jhzw_rtuZ*T!72h1xTuGol9Ee5Ri z6{M;rafBLo?f~;on_cm=!lRKM}QKWLvu1+hqTp7G$8eDPf z;pO$unT_!|!mpk=&=MgsOL*IdB(hc8bUlP)go+hNym6qZE<^kloJ82(VoVK-eFsKqPf$inW--;(J24&Y>xrYw>+=(z z2c8%=k3FcVq7CmH-GqHHE((SDYKQIBH@Im z>fGr}@nx+K?|>5svGue*%@akSROu83PE;UiWaHO5VWIAeLA7sz-%p;c{N#?X3g)E0 zp_O6?$@*M26p~m~9gkYi070SLWe)AR4&CP zT>-SUY1Ci2Vn8YjF{cn0gB)7LXi#riu?!2-cjy-U{=a_z=dJzz&wuD+051$4@GEP# zj^6>+Xa9fYAM>d4^1kWV$>xDmVVT;Rpe0LXuq8nsRW$&$2U#HH)LlFY-Rk91Nd{9} zrB-EKwq!{JaCP5wh;Hk^*8&0Ni8Dl%Szqr4>0LrjLi!L?qitW|K@VC95;2NLof(bbhe$6a(@RH@Lp3k;iOX~z9Y!O-0nM#riLp2 zMPS^%N?I{=l>NT-`O2?{HONzk-D|fAzS_cc0sWDGVuDs|yB)JpGaFXv)tmhbLc!x! zf?fr5aX8%Q=TG?YAFKQ3lUfH(Jun|!~~nM8$Dn1sqwEteiH!Mpw{)U9dqa@J%hmkkmRm zcCfip64M81q-!m7~cQ|tH;x=prv@1 z@&J{OA3J&9d|dLt8@&qRqa$JknKr)CMhKQzH^K&+RTxf{WU)mV(3DCpCQL)Y5J_Jq z^W5vk=YLJzf1mxi_=&|^u>U{s`@ip-I`pjrm&J{UbWdi+T$C;8hl!9@>V^;;6o)75 zITj*W`w9g`u(@UwN6=Kit-HB(dEbqe_fqO`$0ebmAmwWC;KHJZ(<3n;Ot`ok&@>VU zUBzz^NpB8e`&aO1b4RE>aK;tNqjScWA|T1SO9_ zFnA(ViB7OHf-RLMO?h?Sjh6QU#|KWSu5z>>*DJcRW)8IxmBoY)5O4URz6DNW_|HSt z+(NZEeQg42c%ch?QU{`xfn>#vO?AAg5|dW&0Ej|TMXB-xd$nAkSt{#)M-%0S zUMC2Tvhs~y`m9uL$#6?66CKfI0fJgsOIPs8)fP`EB@-sH_$NS%tOKP;*a&CL(0)(A z>KncE9bRFh(ogUz0_t7^Z%k#30ur*A-c{1Lb4YAXqN=p^7Ib@Y#KR4M(xKITH+t!} zA_TS<=!u8)I`V|l7+p++2qVQ|dZ7ql$zhQYG~L-BJ8&PBDAq~QzHe5v54=U%x}UT} zi|Z{^U8+7b7S5ygNF3G5_gZ|kN$9yHzp;ipLoDUnz4)ohHOr0%&J+`3j(xo#B-L{Y zQ88QS+h<2o&1wZ@et=b_Wk`X4r>)lQ5?u%<(VHp%A2QAVr_cYMe)sPWuf1mNA*1_W z-S?om%3K#(qLn=3?gM+rAXFMD9e1 zwSE>Lm5Dr(R(EC{AW1}qd;gQYJCC>QF6(^1_dZotK!V9BMO0cDOb&+wSaYR7kx2#x zE-Gg)R6s?0YI2^X(MH619^1Zs)wZ3wRUB}{_O{b~f7V(N zS_zul>g)b-3sN~bXYaLszi0S9-{<@M);<9|q5^t=mN|yNMbeWv7$-kBp*^g4JY>G| z9Wq{iD`HBc#z3sVLLsS;1_x2MuT#CbuR3I-`q1bl*`A>N>|;vN$?d~CS;J?1Ol z4n`F_)sO>lFgE8c=@r|zJu#C!Dh(VKNJcDY}y#?3p_=9@`GM9@KyHx+v%8W`onhU3!^r?b}h5WnCSH2Y{R=36mMW6G<*Rx(KJ?O-W6dnd|9FLr@?t^1zWc%BmA5Z@72EisAQgOF z9G^F)hxsED&~xQY04{!cEoP#a6?;06#29$z`$8{k2)cKjm;9CL4WC)oID@ll)XQ=J zTmHlx*;mfEh(3(-GJj#xC~4#q!G;y%nmtA|-2I^W%3mS>(%Qn}9-4}6K@m$+Qms-d zC~`_?v;pnSmi4+SuR4^VEC?wD%9&I;aMh*Dr}}*{#}}(-EPikCrLq5wr)*rc@tDQ& z<(pRjVfp3bDd3;|2P)uj_u+X#-`<+5@IsubX~jTPWovnSf#wNF!G^D8#U_`YY+^i- zBFY$0IC)jHOD$u%bt9tEtORAlY8Vz@=HuUJ>2$n zm1;mee~>!dy)$3=>uZTd<`T$AI*=FN5`el-Otj9Ws!H@gjzC{Q(PKPvr0S)v3hDx= zlNEh9(|!9*^uyirY17NTv+1U27cs0<#+X<(OuGnree7T1z(;mGdYj~%bPb=fyb3y`Lujq@x&1K04U z?l-lXpA{xd5CBGlM6lSYi$w}h{#uc8Uy*>RmoC3r|Nqp*@|lZ2UfjNV=jH2Qz;joB zv3Tn0tCt_Sd=F0q{2%{VDDOI2w!GiT?H4Jf<(*tk2TFX1o74oju?hzP@mi>7ktLf~ zaS7Q>^F0y^K}GTsn7()Dc}`Qg?AG(uv5s(8t3-GVO2ud_&YHHWIY4!j3iXfDwpk7W zC$yozI)uB9xtc(Cm(|zWK z*C`M}X5?G)#}f#<>&XafTT`780}#hIumZTqQyD};a52II^1&A!V-Sg65fqV8sRIZ> zP%djQ07B5}lNS%UH~X(0k!vd-Uh0Q>2`m}|q{SgpRNg(cmo-W5T5k{sZt|YuC4~h+ zhD0cZpPd1LXw=#Pxvu+R1aOtN#;ah{CeUBJRtXbNAe8lefgd-^>iiK#>YSj8*gQ6? z0OKTghQNsJ<367$T{{rjT0T;F46du@=`VVqvEaw_c^o&>c1328T4ketOTdv)Minw1 zngfcvbn(Ln*Uq1I-4}|(=500*XV>@(1DGg?Z@fT^fdmT6MVBP}}^haDI)p+j!(d+Kt1x{R;JcwNIOch?|v zTo@-0xq9mS`@cK?_pkD2I5|`G#a)0|pQX1Iz~ZYD%kCL=`(fISRMWaPBE`gRr6^nVwD$xgLoDYG@4q^)bEa= zql7AvMhcSD6!UUv!;A#RD2j40oSdop;ttfU8B%jL4WCX~y88#}lzAQ1?O3oYyPCT* zKTmMK^pTHXBIhNHxeFFGoSdop;&zu*gh2+Z5k+PU9i8toB1$)1n2+?G1-w>28B0M6 z8ignL2wkV(RFKY`vBpf*7q{6~!hjj)f+*fW{9CxNmsMt6p8}sCs2m89Isu$Z=m1vX%neeQlP#gnd; zay}!o`0|=RE5)O63IW-~2mHk8MSkA%Q-Z1<&AsidqKohMjGHb@Bx5?JK3X)Pap~eW z)&B#FX>r5iz;d|}poy89mk5y*1lXc}0iiqSl$*c!~ zwOZ4TTXqaMVk&C2e*&+mr)CktdZVI}>?~8(C#R>(wiiF7nMwo10;LYa6G~EuqUh`t z3K#73?Nm?~XpY7`szQ()(Mtv%l}M8|#~R<>If3Ei^k~)2;zz8yflYl%XW8VJXL%xL zsj}`|M%$ELK?*mu(cB1bZ;~r4jWl$C2_6ZQqn!5sBWK%Qd@oW|@JdGR$!nb{Rci%W zXGHo^c-baLGH8bYYnuJI1M|gLHAD2+=&|VVef`YRlhem^?ks+^d9!LRBqg_sz^Xk~ zjFJdx;3NZKt_D(~fk0&3%S{ZdEMi*fiC_IhJ^A6|>yy)?q1%feOgxb^bQpV5dA%!n z+e_nq$wn$!T7RC8_i>q)v~c$c7A%`YD^c75e;ZCt&xY2dqpFhwd!CA9{;EX(n%!7%0_)Jte<9 z5e@-An2foLZ#X3`Fb`>s2~`)=VS(BqXVl^7?#b!t(5=Py;RE8pqGJaQm~0%*+Ik9B zV-AX;x{&x7Qy&GB$cg+Hcd{Qaxm9s!#q*Pri#Jqjq~ESn;WN1?!_%j@L-!=3-}DIfoF@%f8~Z#-xD*M1Y|9m}&m8vL&o zuNh9xv&Y3xH8Orw_*H5nRO^$b+v~oCujR(#6yg>5w;}lgrkBa5}BXP2qhyi$Wk&o_BKkgx)I_ zKQ0ut#s--Jg#e^1Yq_Fh5kZk>n`8BXR(*GTiFi#Tv`9rxg=#h>6OXKhw>LjLIiELJ z{5%j4Z>lr6Kpx2gP0px%*rbYx5!S09!D2S>7x(!}7wxXs|3JmaWp4LOp&M~7M(pRILW)7h~;P01? z`~2U-$>})6&f@398mrc@l!j%6%tms?Y6DoMBn70g6P1B>z_->8iA0|5(C2(hj)@-? zQ=U%eA+{DjtCta?)e5h}0l2TZMft1%jqP3r?Omcy*{(NK>m73sxrssGN9>M=5r&iV z34p~wd% z7C%=U z``o`@UA}SpO<;>t|KJq;?$s}yM2O`}n{2QH>dXK#5CWD%7$xE%UgQ}=sh)b>Vh}$< zoKV@k*$7{tX$JI9ahUOhdkx3%<{jT}WQ7cB}ok*74V{wA%WAL3#RVmY=7|IJS@ zQLKF|A(b(-#zk>qptF0mzH~*LSbk)qvTQGibRW$LsJfj_YW&(HslJ5THFhyYS-ZlM z>Q&)m>#gZ=cODt8rlq*<&hkY-qp2Bq9h-X@57cY1_2PHT zWz0S{nQG5S$ak;)=y}B-4U|DyI#JWfUU_@@65HlXsh9pV23=0^GRG0S)&@wT3=1C zVCC)Q3)uqc#C5@70t}P0h01FzsJ-#8<~W+8s$*wj+^oOEdraGlWSo%cgvn9Q|9-jp z|JcRy@r&PBT)(!9HmG1fb7bo*AM0Dc3w|xaJY_2G6n_3yC-(iXKHBuKoco#5W$UN-u7sf#ycZiYaF_(3e`z1dui8LpXo_2r%QLhMz-iE3n^7S07F zfKH;!L|XfV`tUK3*CPov`O@hiq1MoIbWA6bPOPt)diCw)9r07yDqV=*O;DT4qL8W` zYo{*)Dfrv^B@bw*4~tHYl5C++`@*!M@#t{P+^R2c*9q}cxw9dz;mAxMm)hF25?qTW9BfW#i1dY#$GT zp^OFqG(`N&HOiOZM~SINsqy-7J^(reSHpqfnpuTe-erD>iAl0z-d39&SGnTWU7_j) zA)zNQE(gMTL8|kR_ef_h(W;*`6y*!r?LYLvCR1OX%$2FW3 z+j`*<`15x}#KwfotxMm)~FTa|sqGI`nE2cVD)Qec0tT_(0me>Hr zP;Ivt8OR0PMcz2EfW*G}Qrt=5>HHtQ_WP?ZT^(QkiW7hr7gxmqme+Uy@Vk99z}sv! zhihhvz5EFQj*c*43L1Gt&))bA&yOA9-3+QcW-(nfIwDjIq-w_?0o%KP(qo?$ii5*7 z6VusQj!b8qqOu=$SMSz27$q}|Q)ytPXakrm078XyEnu_|X{g0i&L~+444`1RW>Oe- zmOrG61rp)A4AQr!N#JCxr;h;xKqL@CR=h5g#WDJKxe#$GY48wGlr*;by??@QOTD)Y z7_ON~Hex-BF)HY%n3e{GEfr%0N(-ry)LN;ZBnGKJ%@&4h z=B|JFqoa;gv@=B$HbJKy6<~BL7jG8tb_jHb2;3&w&n-HfT&{^>+*c=uJHQffF^eY4 zA88%REtEkE7@QXpwUS^IDBGwqVo~M|BAf-)JHhH_JbJzcuIQT@Miu{_v` zztw8_HPcf7iz`>RI~wpei`Onb(?h`5&POIz4_4I`e&k{t7O6C9Of@7>5?IZA<$g_} zGU&%jfNn`ZI{^e&r5hCtv9$}fSYJCGrrTa^IuB6tTAuz!4)^p;pPS+@jbFoxOfQVO zurxtpt)c>`mY|%XZ=U@v+tAB3?>Gj07hK8%+|Rg}o5z6bW5fts*DOESOlQ z$R(;5#l~$LVvpUGMhh1kuAL9ltuAW_j^{9Es-Ar|KoI3{J2fPk$B%eI;na>xGN@jW zM=~`9TmhNEhu8I=s~5aI5#ZYCpybZ#ohuchrO*0M`GeiC6$iD_xL4fJF5N<@5UHhM zb4V3Y%143GM#?*yE6$G&*Ul#;SNm}-!6sHHwVFs2Nz7Op`&p?DBjl^mk{ar6sTE2| zOmZQNk{FN)y-npgkWBgh_Xc|ZgzxWOJB<~#R`2G@1pc|Pjh=TN(!vm|1U4P6&4L{% zhfS(-a-$DyI7v*R{L_9_msZQ~y!^=q4o*K6Xef zZX-q#4)u3I%rT$;_W|<1`oDa=Ujy3t|Nm|E-xpV{?pi%{@wbcb@;d+@yLclMcrA}T zIR&b8z*b zw?ARHcIF+c4~Xhpb96b*WM_%$mF^^t`jS8&R8q9qPHgDj(o{@zfFUju!K($wn2V= ztB-koi`U=wSHrb)*;_pe09ZMc6=pEc9*GgSMQtD25TWH3Q(ZL-1I!w>j8@A$+3D7- zG6qPWjBsFm?Zh&-S05x6Tv%bi=;An_-;^_RVF;Z`%-32s$;n8{CWzFU=z0JlpW=aH z02JaPj#^(k%W11;l1YLRMg`~atJbC(ldz>nbq#uiTd^!5$0~$bY*g8^uR203W~^A; zxW0B`T-&Q>bcDBd!E4PNg(TFsWrYj%7elb4CV=!ZYFM#KfKJ!Z0mKn_xPB1u!C#)9 z2-nu?>Dos(R%y|FBAR89Ppm*d$2MFeWF$hREn~~ECzdx9a~Ow56bZ&4G}KmIy8J-- z|Ad9l|9#!^#XkS{!iL`ivUtMyDF7?a|9tk_JAJi2H9exSy*i^5A<$J%Mn(Zh!}a;F z3fYn7R>cG~Wvx<;WJf3DAQfV4Bpb~ZlfkiqKb+b-2@R`L1&oqbvtNUgu-6!T(s-~p za-*p4Lr_GzNe*uA#VnkHJrYgxYdsXc(NT`|sp*-S?bX%Rs$L?kOpNLUP2M4PG$alC z6UYQuqC$mI=ZC@d-2@kPQDW-stQHDfbsPvh_-*CKaB9!Im1~7LF47|nO-Euc5D@Q# z%4Uqho9sZ8z;PVLluJdmF;ejFD1! z+^Z)fgkX}K?iS|Qlcn<%f~XcX71m+1MDu#82+!EZTYvV`+uGLjz2Ve5&P%v4vP%eZ zsam7XABZ;nU_O=||i(vv+P^6~Yl>A9lq)eVx9IEt?( z(y=zfDAODvTccQlqR8kNJi!ZBX}D8TS1sDP#z@|hPF! zU;UT{npXsmc8;_lg~?e+BuioR?!av-wJMKK2{!CdiNeL}1q80J@HZ@C0ACHK=GJue zqsW0^hl^=VX$Gvz<^GNE)lrIVz89zbkU}j8;&x)k&an$)*5w>~uw z7*{`uVkZ*t3;cJ2QuvG?$X21$ScB&VSS0ySA6tRLAJ6K*+&W#amF?qvu`@_27x1wYlgm^0(5fG= zL#wfY7ZN!Px4Mx!@h^TKqybj4g{9SQN}ght94CmC7_e7G(99>mu1`$`WP9}^A#@!X zqyt0vGh9w9^lybDK#YA788~}%wZ^QmlKw%M0h$n~MuESNA6lQ9_}cdBhizL`vsiU5 zI|1irEUexZI=BYBAQSJ7s}jnt9He)^qhq<;+w99X4jmaz-9wvxsAn+bNNsX;c%(!2 z4#s4(xQ80e%z7%o#?*YqM2Li>F+GB&DMWyMm(pqRyQl7IrA%Y9 zZ?6bsBdHxP(e{DE5Z*K-5kbHnoS*;MHve1QHs!qe-^KJlpa1jLHDEaP*)s(F_l_O_ zDm2ZCqt}U>^~l9Yt%U;2{OYDZ&S1i7=q4RhX`rB*`icBV`bQgvQ?Hn>{O9r`2}2E5 zN|aZGtH;@G739YCn%n8Jt)L8c(~!pfWu15rTJ?J6D-M59ntsN39tuBs5hf`hxKK6AYC*6L5Z444Q{g<3bo9{I`}tRuz* z#?-s2N?G5<*)odr>RALJ(FX_D`=;QQ z_MshdcvMfCrK?;}%tRQYWw>hIr_QE$Q^Jr))(>OIa-^=p^{VVq{IJknIWN}7Q4_1f zd+b6VTzksODKj$dkg$09yyQ1GtO66Ft`jAE4yqYMT3I(ha>Z&AF2yL;oNnDq6FFr+ z;D$v^FTAD1aO!3AlK-sJ0(9F_A2t_|Em@>6V6iM#L_xm*Oq>f!rB0YA$)Xz_5a1=R zPBCCU481>VUh<#1rWm#^7h?!uNbFAvlv@0rNm#0f7R8`FxKvuEYH0vqyKvDJ>Ms;? z=YM+s|8e^N#VePei~aj8;ETu2p8>k_qu67v$gTwf{th+a)JZl z+Azk-g%tKAVXQT6Ob)rd+M;w#NkcEIg9id5_tTpmIy782&$u?;%j`q`F)*B?6tfyu zTk{u4pxi{onu2le7<8+#X+1K)8EQR8I##`sx2Fvc*UdAojrXL&Xy6OSwb8rf0&@}`2z`$v{Pe=nbs@U{#$eQ$l;G}77Lc&KXL zHQf}12w`Q0GR{W@i2{&#DL`u##<@rMg>ptY5-mo;WqC|Nr)paB4?n{1x~(ZNH@1+> z*hE^4f+o7_X8bp)fd4SDWUodHi4SeA>6q*b(8aTS<-dHPmh$Rw-Ieo|uk2CQP7%~s z;`?kQM{FmB-OU=?)(5*AG)b=$jieV?0AkhQwvsTxQ`pSW^>tTFA-{2j8q?t=3@7p0 z*a8&-wQ6K1NE&{}BMPPxOT;*1tZ!0^h%1T+mo|E@E(reNx<|}QeuP)Mt7@zOyNY*> z(|5P3^#W2N1bstdBusBtVMl$bv%H{F%1RDCW6}r%!|C|s$;|H z2h6_sVrv!3Y*5&VAN03#;&?BF2QFZQ!Q4!7c5w#t(;%>q7AYY(1~KW#1ROdzoSvkK zosBc98F7r+Q*t1T65mnGlqA>;{A0sZjG!PyyfEq}IclsVKoxetv3}}eBS3>P-|IL}V!${= z;c=0FcsMi~=F^RKZHWS2C=*i@_{QqJHdQq+UjpkI?jra}^AiJnl@6@Z7Q z^M8+AEPs1>)A*S`M{t1Wtlqr%<;BUxBku_$6Ts7Rm$&i508gN+s<~$*DVhz}Qxe_B zPNZU>sT`>O(4VVxCw3Q5z@NI595{MrI6ZfH8$YCZWmqm(jIb1l9kXG0`>19KF&-b! zn-&OIta8GfkxCP>dYn#Ym;#0CY&Lay+Z#WaAc&Jwo?XQ|k%uPTpqU{kYPhpCBKoC= zaI_G`)?1Qislw%bEV!oQfasr3V{g2{w&L^}b*Vxk1b987Y!^rvy30O_5oc%(lD=zj z>$hoc4%jR9t}Q8)5%(lco_@dC&EHci5gk%8Vu~>!q)NI3h=7%lkIn)uwWQcX{UD>e zf}2JZV}Bq-T%MhW)9*Xu?CUh;0*4_j1l{Q+odjr-&Fl(}tcea0Y22DU_)m_jtgLLa zwG?G*N-i`XPEQXx>}-5*VgX$lR=^PPOAoR5vpJmpWxIB67&hlZf7SBtWSU3c;)Sl-$ow zwCPT&uoP_W@fZnJ2(vTN!7G5N;eU~aIby`(VB-~w%ie;RJ}LF|+{|zMA%a0!P*rqg ze2WsINIjLT4`T*_(V1A}Q-QEQ)sd~nMi|_g($TKSUdXORxz=!c?u|FzRQ@W!z)+)7I6j|(c_V~kIjulz>Uj!vM6i+1KnzmRoxgmt3c z8|_fK-K1VM-BdQeM=Lq_)gF<*0g6P(ibu=)LiSHfkmrM1}Kl#sadJt=ico1e}2N^_IdvIr16u$_AFlC z@BdtUt-tT>_nr;cKW4K29weZ%ED0iF1bqqDBjZ||sBnE>l>?`)sb(~0;|bM3+F?YR zB2|}nlT}of>$m4CZ-Y#sfbEZML!J5fU>>6b%dT0Q>B?md)YfIB=*mAFWw>|Q@Lty_Dp1RbeLA`<4vX2evLYhc5WxQ7cTP6x>{A8abLDw+XHZ9*!aGJg4`qw{lilse|WCt5Xs?kh4sCmN;^%?MitwI}q(>%8VQ3@W=#ZWEvqn|5G zwqh{~!20^Bx8L5gHNI1FG-SZl)AGZNfexo|lwlj1%dsR;>$h2(Y2o)+T@6;@9 z5te_V^K#P%K;3(o4%ffW?4tK!?sO%9Q!yIV%nYe8)}rGVsqeKtz+#+9!31Qec!f<( z6FR|GEYwgP8?JxseC5ZcYlv3zPMrq$;%H@mgb+j+s^;)c1jRiH05)SI$VF}zVv-q2 zL~KyM;|GW9A3b0B(ew-@lbs^;HHaPHVy3h_2@g!*S)+8!7FQ4xBfc)jXMZoU$K24*?VD=0(`!1`eAU9is9y?Jz zTLItcgarJyW^Px;3sE7b9YB~zid)#QlXO0?zWzhU>u&G)P@J8Vqc*^Ch?4wZv;nl; z1*jU^M=^98vZwix>JNymBfT}DB+mkSqJ)NYxPE%@YiG}M1zD4vRA(AjtRu}dZkbM% zWFaiai3PAko78TeL<=Kaxf1r1AZT*x*MS4Xl6(K4j_ao<__p_ah%~EO13(2~q`-P^ zc`;J*#>m34Lq^F}D9>0Qn*<~2sYLWOfoC_WuMi)upP!K1^T8rP@-l0~R>7N;C2dp- z(JxdYSYz8mJC!Cyz=u??P)u4Wu2M& z#|5KD#57+ywmhsAK`HKM5T~;uJ5c=PU zG53s&&!wQdBgUu&&zSqgaGc} zSbVZmz~@#kx_9qSKN-%<{qUYQxVmSeI~6xHF5` zXnl~1QE8NiqIfuS)x7W5l4J#IeJ4f_l-1sz%@+=I!8k@yOFeaS-cXG@)E4q}iq}`( z>slZCPG`b)G1C8^u>ujcxgYzdI$=Jde19ys9&z zD*z&b_@}3~QD^hz8rJUk>AhNDVMJ1bRc`4nBwnKLDAiyPzG9 zxs9Dp@-)w~@1fz$q!aAy`5wfmM#mcB_n-nxmu(7m%-e+ zUYCK69UIO(ZjO=f#`!zo%Ag~`t&K__k<=DZRi_Hb9LJJ$13d=AR|?^Id5m9mvrBAr@i^i;`iHs$fFD($Rwszlb^;sB*|?FleG2B~^+9 zm3$C6JrZ>vKho^X-2d04VN?}`#zb}Nezmt0C zTbxxHkS91Uh(^%?n*ibv;;__DjTz2NbKadjZ%zpo%oIWdnpQW}9La%n${3-bI8sR9 zXG&(JS)}l@Llc4*yh2TPM+Fewqq}FOLGRX{KhvtXW$7-O#zBWLkSUr2OHR8)T}nR{ zUOu77Sek&-p^0%`s$oT9BHzc>XXY{Qo>S=>IVp^|o#{lxmrH2vS+^Cv2;kc7};sAEdFGJ*>)>u%8?Rg?PRh;9JL z6g6&OOGDI5HBnab+f2Z1%yMQrVzIO5kLzT_x4y4Ro&v;nEJyR_7*Ze520heCWh(D# zRJo;zUo%z8f<`Rn9ick{Jm)hOd;TcySHAPBjbrJJBKbf605EpcvrF|PngsBGUL#tl zxN$+EnjlVo1j>gqvn;dc55-F6>A6ltj zst!d{74``CO|s1Po;T6GRb_PofZMQ!OPab*zAL^(wSq$xj9^r7NU#eT+|@-qfF#`0J6J>< z@*p=}x_E{9|B&VC(&e`=KWz02i@#lcp84NH7UwsfJ>2j)6SD689Q}A5qU@7%JdC6p z3&oT*WYm)+7xh{=3Z$T4eGjOSAgV(nOLdc57>$H_WcAX;`}||9;;nwZzTtBxAm01A zX}R$xffC`033PZQ7`8hp?hZhA0t5evtJOM6@wzwxr_>^W7NY81wHj`iA!6^#m7%`d z)Uq7+7Q{HkPg6D4R{aOamjuno5+ivLSV>%@gEO%&&McL}l;MUcm3Q`jR%1tr5`j%36K@N!b+%V(*-d8kfh}hMF z+j!i)M+2ojSVIjp6>fpA=!1Nl2S9(Kc855TfDy03RE&v}h8yN%ID20<_7lku0vNjC zp<%p&Emf-3vI}-_G|phl0?M8I040}I1ZBxnWXm&)@@q2Q{(~MjeBPWepO<#jth?t| zq%pc`;zTZp8Fq9e9RatJ?8;AKChY6@RDz+rRg9!l;-Vcvwe=0t>AUT{pRFGN!LDrA zss|q?J_!dwN_XC;tJas*a?)4^bD6{IRbj*%!JZYnFrClFv^Y8fD} zhoYDaHy)X<{2gTwW`LHu1S}R_9YM7w?z9Zdfbrc80*QVOtRYDq2*5450*coZwdStF zjfdwef4h{>YR6Tw9uC+kbH>pqx(|Zo%oYdJ`gqWLsl)nn`U&yICH)XU)M_<2J#uKc z@z8wbZ?k27;lTh*GRP^zNztUBXfBEo=_PSTeiyYE%c;Q%uvUFDPtgMy5d3W`6A98*aX;+W+SC=>hSJH^34Dox@yh-k z^Jl!`Qme(+OdK^nd~|)|gv#4{|3{)1{N>3onfsgf#k=@H#@EB?HJa^})~b1R7&yp3 zE~(eD*?bjmKDNH`9$NB$XJ{mWq81ld39+r}ro2w?q(0PX3oZ%(x+!BDCR;RroU(R{}2D?^S*d7I?i!DTWWNNC?f#jm`w`OkNKGtOvA$_OnY!-^5erFO#U^8FBYn{a zG|6y-RL_Vz4FOqEH1PpcSxk_;tR3gW#+z3(ay+(r;l0lghMVST=)P?Y0V8<}Ljtq< zydo6ktVLyxXy*7#hRDht)*#}<5eC%QAoJqU_Q!h1hMT6z2Xm=F{=AsMbA7DueC$@!Wtym#OY>pKht6$$V4FI?IJt}cC;@?D5B*kW{EA{<= zK?uvZ^1*_n&ls~{R*6H%ya~H%lA6p;hw}M9H_894^52QS`SZVe24KtQe?8M2peKNh zd2X7Y{@M50F~w+AbZKPQoyq`qj4S}fW&K*DP928Lkse54Cxi-%5Pd3h+5kUcUBgYY zfVA&3_$w|PX`qR91j{VGqa_-SktB+bd^z9|gaMLU* z?E5VChOwy~s9^jVl}Lj?kZL$WeNoae1vab3G(u_u&}8>G*KdEIjOc zg)qdrW}p_+TBzKTOvB}JQJt1SG{MnysgAW<_J)%No*1 z-2_+#50Fz-MV-!))X8Jbr{RF!u&P_Vl5hgKd6_TKVyzaIMi9{yIRE#9`2TA+rgJ~b zPg;G&>iu;8o8#ww+;^}2tG#2m`5vhKdQgJbV0?q3pb%gKOq4mx8K<(FoSI#X3ybXv;DrK(OWOG%l&s#Y`cF2BZzM|2k z5K079M5wT}K^4-22iG@GbYy$q1vk_tL?yMo2_F;=U~J{EwOsY)6v6n0_EoaVMl4t~ zAaUbq3K|HWLVIt3!CKP~~8faAWK(wFRsScLU zJ^%Yf>i-q1#T7mQ>_1IU{?1dtFUeRw9xRj1N2d0DgC&k~hx8dkRc`dmY=p4L<@>0x z>1aK9ox4(DIn94ywm5=K4mGG9k*H%X{(S%Zv;P@xo{x|1`z8&(fP~Km73o~YQ3NL< zUDNV@h>`Ml%4Z)_4`6WWK;LY_2IcRNnx zdH+&A8z4d!EK>yaSvP`E(8L8fs9sL(SGVDDcAnJBoqgXaI#ibiburW?kKh|EZEQ<} zz<(^Q&lXD*B`xT-c}D2l3Ft8wYg=NZ6Lu$H&m`1s@B0q*ic(WzKofjKtkj(fy_#9M z!jHO8X6f)+55>Kw06g4|ws`Zb)9w23C-{zT}Kvf)^zgN?ZhPOi+Aug*iG@J35p51Uitn|BroP^$ zb54!++A)07k91Om_aXPIu_x73D?03W$>ZKM}Vj%^8mB2u>mMiYmT zRaUF35KToQx>m>FyWZ+DH#QViVH0%Dk@4yAcO zWXe){SOkPu2nVu~sl?2|!+WLPvsQiJ)9Pg#|6}9NR{wV6O&h68&BJK;>P1Pj;z)jkKK6W#>1U0dhW)9HZI$^|Hhux2d@5R^%tu@S^fU% zw^qNl`lZz`tbTg+)YXqVee}B3YgSKKeaq_WoI2_g$X>O2evk;4g38skJO)?H8boz-2BSuB=6eb>YN{Zn^6*xx^XmxtL_&%E=q{QZnOKi=O@zw?E@ z|1)=btnz`6yYuP3^RzpC)Ya;#cakPnPrma?e?Rfg_wduJ?tBN={M9?0a$g<4<5Rus zXYa7u)zLeikSNQ(E zTR+<0du|m`W!@asnyxHJfS+=@{aRe-jNA(dI_I~ zluGZ&GH^!4rzNuj4jhe7FST4s0Ay#gPM4^s42Z@m3AKWU53O&x-+1NiOYWEM%-YHj zL8{{#Evx-#YZTEm0=G$3ppN8<3>1aI$@M{y??qpW(S^$?$hEyuRg~=B2(9 z8l=Xj{-~a|)Mq|e5*mm!BMhv^I1H(fVvA7%Z9Efe*l=7vK;t_0gp3?IzP{yw^MxOX z)*&kOEj`!A2LgcybO7R588%(c%pH_8SHhJ#u7Sw#nhKrIyST8YwA24?xpcnprB>&v zxTOo}#8P~*?FN~KRrW%*NOtGSntriZ%clG%33dafM`lqWob#%qm%@%3WFlq+SQeL&bWjf@!eaYkEyFwKEa|>;o$km#PZ&Bwbb+&12 z9ucV*C3yIYs>hJA%=rA+)g#xM(?cGY-!t4YJr25a$y21gTjK5b5#Ebuq3V4Gnc&p> z)%hZHPQoFg_<4s9Ei;RDoHs5Pk?Z7#s5yRQxMe=KdC8M}i_Tc@h>rD&4$ittM;N4> zJPjsfnCE-^B~OG=%`gj4PEM8cnW7dehHJ@W z9T)<7dK+7A$X*-*tR9XPG?D8vz2@-f;oV!N)6iR&ygw79s0ey+ps^JETHz#5jW+1B zv^3R`eZmm7pgGmpcaW0t!E|$GaVlqqTjnFnm%LvCFi1+~NWRR8&F)P9nyof#0b6dP zrH2X(P`|B-#8#QCpA+~-yy8k{4cE6!2bQ-ldEX!gVU|nO5}_d$V%;G2x_0UM4F#d8 zU}C7w;dN)78+A}C3fV|5qD;9_3w-OUt1ew#l>d)gte&%c^YV`6lQ%9berNmy&@b~T zKrdOnC$2F5{SOyAyz)6CB<b<3_NV}@U-|U$%G>vQIy_*{oY^UT5Y)r&=0zhc@wfkbi|o|MkEDZ)<|J64 zUs?%R7XVtCa%5%w%BRg2ep>x}lOlISS;oOqPeFC=Po-CSgnSBT50+vcV~91&5OsB? z+?|AG;puB9)~}pC%whX}AE0u>9U>)A#~n1RNeVDWNI;F+bE;4mu1chYjD?WboUjCe zExw~o<`rBn{66R(hTwht&U}LFmCu^}^(S%WRPX3mhrzsl?!Vc;yGpSN@>!=m^qUC5ZDWziLLB&L|rwP)!8s3fLR-!H@KY zk~%0}r`M$3%a8Va>83XZLeG}HJE z!G^Sc!YO`y)%^Rv%>RCC`NgB|cgQDzKgXy4{i4tR*!nvI4>!zm``#U_EhUV-dOyL1 zwBDq((MuUav9^nfTe`MmX!uC{Dig30hAARS930Apc5j&E_N~2-Vs*Zz$5KBHLE3*u z{XuWjEO(k169ki84C5|^6l88nFaNzs@{JS3qw5=H(R=SU;E>RCC?=KT4M`~L;J^Pg z7vf$9@_{Z%(j7ZuHk|gy+U-b233Xh*1U%P;=+k5szSN1egCyq0P$`-U4HHpS20hgmD?$ZNt~%c9ld78|4X15661 zNg+GW2Ojo561&GXa54y#C=Wc%i7cV#SbIPg6pnmK1naqK zB*$J;;Zb%{OOy63K;LR?{#iSkP_QvxZT|NR^`AKLhs!rCU%L2m6M(Y+@#AL!troBIctG=|xAkW@Gxw-_ zZltGMCvQptM2CV3#XB-3>tg0HYEj@U27MNCzzdt^6!+P_gw3{ zb(a9dS4||wPYYogp5_Z^T%j7Nv^2tJU3#2`8SViN2kON~PELtEv3hqOqI|D^hBNOl zZ^-92>((3e1;+3}>*9!01zl()6GKIosW4U-`zu<{v}1V}NX>mZ_2N1@j5B-ZE1y!C z*i>a;VO7&tkOz3-HT=^FXXc^5r=RqcPWp1$tQ=sjQV&n)aS4WOVK(y?{J+?CcW!u5IXb+V2R6eweRuT`pl%^ zZ14Hv$PqyGn)(!o3!3$Jc3~72QvoA57C6)ZrGiws%j(Wt>dw^#3xdc%{E(+7X9;J| z4Wbi*#6AU~lnI$pJcf_QAuF)j`r()gkjELQjDtI}N$DvBDo*44*%O1axU%PrPFp?i zV38Lz(s$;huWNV`XUcb&$j|sK91&p}F>{QLym3TX0npjg!MWq>Gqbp|=X%zH$4a3X zGEHjfJqXM70JjPtTJ*YdK=+s(U6Z_EJ5~%=D*JAT@iG6gM3Hy&LBG?Ryof)3aQC|Bj~CwBc)m`_61gghm7=HlcFh#6$`NLtupwjv3+aQzd##MZvcZlH zL05)ud+YJ5*4Is+O|ZQ&u-ACv91#Gt8ad?+Js-zVbr)_za`7yN;A5FW$ko)UZl+<2 zTg$Fg1`)fy?jvSPe1!W5HLOb^H`hVm!(tbNMOhbv@e}l<(@$2a4babeheluX-~~#a z6@V52GFTj5Uz=-TGuNmKxlP-$HLMhom(g#SB=kD^y~www?m8d51lo;4tXs$LzAAiy~`Imj5#o3H#lMYh3R zZJ-8Im)cRSo?XnX5e|Oup#=-YctkC5?PLMc=X+tZbWI&r8Jz4{U-zN2F+LQxNdl4! zXp(nBA?srzX&vqX5xiJWgkJXCi(NBw%n&sUy8t5bRm4`FhU-3LUh;=P%<2Z%5Ny^j z>Y8yz$q+C#*ri}OWd~FtE6}mlIc{Z&sY#Oy`d?C3%y)eL_Z>U`_uI=a8Gq-;;prq0 z{{Ka9h5x%(&r-V zca`6mI_Y{l%f~eq9pM6z;R_yx-BO0?ge=4_Qi+AP*9l%J3e8i_^|)dOGgN8hFPbS8 zjtp1N59%zrMg%fYCwx>4xspfI`coXV61IbU%1A4XXpZW(yMb)g$u8kDHp$|O&(Y!P zc}llA70gLj|S+U%`vKV-Z#QdM50WCvXcCq;BKHq2cOzdNzTR!du!Xho!rLI`9PR!hPjRU5ml zNKzkSC_e-<;{lcWwJMH^t`pNp_bnJ9{@h1rv z&>R#dLy_P*Ib%N^%244TyTA_}^{jQkP!wp^we|VGa*hc>a?LWV7*5W|iWh$j6YD{t zt;&bjaRKruzJtRCfTNO8;#TVOshr8rc!luA7=fqE=nKmjPEN;)cNTvHnvxO65OWW; zkrvYh88agxA+5*I`*FKfEjB}0AHO{RX>i; zo+2~+jsuq&e3(Kt6Utd@Z0;p8XHSN=Wq3M7mMi47tT8ZWO_kzrk0sxsbhfC!&4 z5d04-6+s<9itlD=u46sWc4U3>6K7-mZYdV7bR3t2#BREJQ3OgY2Y&iOFXr8G(vcE# zNLp7ai<;(+Oe9TNXz)Cc%uWmO2^i!eiqI`}N~MD3`a*P$e) zNdu*XrqGN^L?8XT`akFYZL25w{XZxDCXl0^2Y5^WH(dOfX#x9xb37)=9T1+v#IK2= zb_BH%v_@ns)1gV5tN}_)cc%be2*YpsKwOZ=y!gm)@gwIe|0+UT`K?#&+@hWKNDeWu z+^aTW`oP)2Qtz!N5Q}aq<4Nj#5l90|9pT8bhKnzrulyTu4-b^+N%IPU-Z}$yEC68z zy4aJLl?X2Am68h#;qlT*Kdxxoi4DageQ&t<(essmy%K3JCR9;&H6b1$L0gFiSE$r0 zbsWm-2Sgz&d9rJ6N9YQFNX6(g=$Q*S*}AxiYBIjKt*cK)x$7nbD~ z`d-j8{WxHNaxATyMqO=m_u`AjD{t-pFA-8pfr!m3nM1gYOQ&5jA`C=D(S5C@=z%@r zO;8Cd^$JpsN8Z=R$iusZ%&Mn<%N4FWvg zgsn-WY&l$<`?vkS$f2NnB7McL&8Y$`keZ6Q)m&!Ldc67v*KM8ygn=eoXJBi>HDUmM z|JSdp|BqcPUpVo8XYSsAaeDFC<;L>2{OH&J=Q_W>_?X$*-`FQOX{6gTPl%(XERA||UQj2;8 zT|w;TDiD0Kc)?fAMN4E|z{JG*d8Jd}Tf8eY13z)#LoZIE?IZSIfMI&3d|Z+U(Z{%G zePBh3AnKFsCa8>7 z8Gb6S6*haZxN0_n)cG6G7iYn6>w+z%jyGLB-K)lIeQ}x#ZSVj3=&lXe4&RxRg%_hp zqz>Y#6eXaCmWLu zlxFD(&C;c=B3~a9txg}&Ah@Q|Eyr*jRbaR{&lUE64WjA0nnhkCCa|lZX$Dk4tDxu+ z(qQfZO%!cm4Q%)wTzGax0TW9+lo-w)2ZoFDTw(vkL@#ALQCEc3=2?raLTX$kQAP})TOI;mH+F-^7WJQzkJE+j@6Tw_g{RAZ~njjGhFz% zIh{W)E({iAxtbn5p*JbnAX;>>X~86muy2XaOHft~%MC{S25*9PSRNF-u^^h2f{XKArev_h#MK=HII-$O)RTnxwiTW)+3 zC?Zc`X^Mu6$sH6yaZy)Ne=*IZL<0v;rquTcS6fu((b}Wy3sX_w-v6QqV__wlsv_xW zJr@?+v}~{$`BB~UtBPiWZGA*aVP_@kZIbEn7a{--&GS3|MDGt5UNYP5B@rOE(a1GF z>6kzgj##el6vry2eW6*hpKZm4E=*23>;no2H`*_a%&6=hIlOyeBAr|NKL!yI&lOS( zvet#Kfq@n)KrMe2TnJF)o_ae*(2ySy){=TH&0krs{)f4+IV5?i-ivRCk zm`?U>?SDe`Kwi11<$)||K*`eDpcJVUpbT#h^m`5g=ry-jUi$d4@KebVB8<{9h6}Sw zx8KtFQ-u*WW9#WlwYOFQ*=cemr1)Pt3k5LOBPHM@$LY-WMEEE0#ko;UjDIWXvYe5Hho_+hVO;X;goo`(c!`@^XwNMDG`{0TE;Z2SYIKa zr4|(mqzP!>gQ{bBaR)FAaAcXao{q|*_fzKsQj@6@8wDVCFZ8{f;;=)7sN`)(4LnJKy(XWR=1+~CQpis7`VQNX$eTW zJ=I^jvk)3n34yQ~1wlC?ODC0ld;jCdNfY2rSCM@-Dg7Ooa)DA%fJu`hE+Q@&6k4~r zOgEmZVvE3Sj8If!xG+o3`$3yx7mhT&s(m4e$2fC+-7GT6tIP}$TwRdoDhiBakK(h1 zBG|fdbp+l{^S?*EMgMzJzX@pU{;%<|AaC_&ePLoZ+xs6WL^w{WTLBX2Qt4iqU)ZuY zQdRek=&J)2%vho5fr3&2&K4tug#vZx;O>Qq+-&XNLgvLGvS@8+LCwA(6K@b%$wI}k za^#fxBuwQUrXUOkJ#50T6e^(5LXMyc6Z_uTf2AxJ52_=?R)Vzg4CK~SVYMf9R&S{= zxsbr&Bq zr80PN$AY$?uLY|)6P67*B=({8h3PcS_Wt+A3BjeaTb8X9i6;TxGnQ(({@E&Fz1fc* z)V7idaAMVln(kiGfzKHesUoO}`S~!-{ztSX*Q@BZ4!b2o2h5SjN=S#G;H)t+TgK80 z84e(hvqg{D>ca7CoLFnJdto}Xw6*`?rrI(jn^Ff8v&>X^g(pF2lh85SNe$knb86ZL zvN=`G5j85%V_hp1g#3JDY5&83MdddMQllk&dNLYhDf-$n7i%DIb%JT6R3piP_UK6S zV+&$=e&Erhmf^xfXTtJOY2(H%E0GmDNJ~yahpkwP$kGc6T3f1_hpLUZ6+lFfW5RSh zwhT~eGwTcQHC}mp|9iowqRX1mSq>n6$!*n)ML86ZU@4$FEhWw;Wo_Cb+$=%@<$M=- z+V5e;c+Yvs?}^sRB;i`TgJ{Xk$lby#p(77AoZ(Wn*;Z(Atd9{WljRmz;b$tKH}Th$ z|5q%Q|80Es_fMBMj#I$&|1bPI{eOM_Wz)Vk|I8gKua=!V3v<&4383%>rai2P7hyUw zzIIZGE77vQiHYJz@6nlw%290@&d;A`vH7PdH-cR$ioKTD)DgXyU>6T5U_d27*G|Tq z;i0sE7`}9`!;0l3ShdCB{4`kD+58i`tiHKssV&T0IZM-X+Dr9BNCSlEp+bR4;49KM zv07Flm2MF5D1V0!uFp@Ch3(Bh7Cg#T4TlJmh&Hb8m9wH1R5U2UySM_e)^{|Oq8hjc zT@!%I6;Oph@QD8p=Vy_A^Gz&Vj{svuTs@-`3v8_9C}4>Ujh!WbDp4blh@jdBcH$N8 z6J|8*XexR1&~SdzrFS-eSKo;zS#p}Qn1&Foxyg5gQKnm$Gq@ukwm04c3Q$F1BH!6? zqHfa@c?DO_&%=<-KLWnC62Y=vL0(`&0i-$xA`lvrCU2EK%pl3tk>tVBpx_{1#r-w< zTsfSdhasCjrI+)iAaW0a5j-wWKXL&PF97QGQ{>U4$O~FlaTDHHa5b9?*%uB4WJibd z)5v0H^A8w^@E zenkX|3OB|=FQ#yIcXUx^jvO2URB^g&j8MKZ900JI;sNyVG+^_S_4#RLvAy|wx;0$W z3Ry)W+Z&z?3t2a%x8O@=u^liHCzXB5QZUOIm8*y?uHXd+=JUT-n*Y=PocwbN;C3^B zBTfPR+lA*Nr$58_>1mUl%{L%!Wv8Ic1Bq4rVqb(y22`DTUZe9zDqO8k8bhKH+;D$# zh(1S#BP&8wAPncH$4z!NzgKAKfVFL@OzGAQ0CmXedzxa_5uiFn2^{YhhL}RF1nSqb zE69&vMR;tDW;dLlT9%#7*Y_lVVj1V+Vg#UB$cV2B0^0>$2&n#@_{sLH$8w5=delZ5S4V4;WaOLuh}?A8wCdVy<*xF`%rl$b zd|liCVu*ZYxPYi}j@b0977H~&5ij){99b@m#V}Zg6l@?FI1+4SbW=VbPi zo&LBr-hxaEePs-0S*4#hWQo9wepTDr#_?F^;Mh=PDlKxPCUQ7GH=Uc`Wo_kC-V=~f z{4&P|cuL;XsY1kli?}PMTcTY4cHi0|QKFaPJ7uNwR>ybGPfh36=4-82uq8a!DZw|@ zeoS2%DzvM1u*A&*XvVVRO0srM@f6J>SWBdApa8ODZaFvqUHAynM3;NpP-;;JP<3R! zk;p)VWvbc$wAzaZnBj0tDfVn;cob zX7R9l*8evDJ)ED#=FP8D!(vQ89?#V*WH#*F<&o%&z7a> zfy3+bQ}?#Lc|mQi=37aPP!<<@+valY020Ulj+b+0;Jcenpph- zlx2Q?WAi*7?xpGM&`gwarRRSHQ^P934K%35ste?byF~)!o(nq*sT_cBke1#6dB`{C z=Vu`{&)IjwuqKnR$f}zxM0fBM7btF2b`{6IaI7>6K*I_nB?xd8oQ6GW5u6;(&+Xgh zSyFY?ymo_lDtQDb;1uc%9z&Bk+CcO~xkq8lPmqj!9dq+NHnaYNv;KEw{r|Jl z{8mrwB;ce2zNP-J&wb9^0DKN{SIGkMVgUO9dguqk0b_M3SyKCGZY8nBf}6lzASe;* zC@VW$<~zz06<|2`*;8Y)`Pr-<1beT>EyyJ3s^*}o>(n=QNpt&T54A1GVI?wvzI`MF zNmm``)Q}uLIGlUMeC1b&8bFP&xo;F+XIxp=3x=*Lf`SZPT-loVw0c{X%M?!YqOPm- zYD^^WRl~WL&sToAR*V-izw1G`sED$O`XFKP-O8`0RvV2WJHm-eDLCTWfClG~*P8kI zO2FyLQ=hf7`7-ti+M8DhupS6^%oEO~Ej0En)fD26tCef^Er2x#^33WJ4jtu8q4|n#k2nVTWh$Mn7!rD{V9ACq}>Bka<$K{6Hi$ES< zpPLVGZGL8LDfCswkWGnU6;at1*YdkW?{J&rn@n-6ep zeumps3jw5_rrKDp!%~U_e}ZUtu>-UI)V@wwvA$KfHykUOwMPlbN-d;apPPD??afb* z%Z|(90KV~48i&TJ&{A2HwXhsMHM`?9ZcYJE&6~N2Q<|271d=1R!?}A}mQRx+IDrZ% z)k%J}bCw4?SpbR(ugZrqQqF{Ik*tV7^)g%x_lZM(A|nnD=k93@KeaeUPVLT*6OcQK z0CFoA`aeP8F1qbhl99sNiGo!Z(UBM86PD1>q8A+Z{Qm*<|GgK>-}BtxbA2w)U8|># zz5jbJzjS$E`W*nnxmilz92Ic35x}Sl#(^ZdJ0DYXRNZ>5Y8!ElX{*4^OhtInqkIUY zu_K9RspXRN9$u4(z&}&T!{2HTBq>8lw|b)c$MUg;dzCa%a$jO z?w*?n@7AUuA)~o6N{*GNvv>oOn4F-rUK=yD3zri3NtbSw%vwNMZ8Sv0i>RuB%IlL> z{ssRG=k6h=mLub#UGx&vDI7Ge%0Ut)KLcVrsIZ{AB}CE-dvUVBVnbC$-r-LY>+pf~ zxdStZBm0h+GhvVg?X=!D>r6-y>K!VugdioTL+F-dcf;CWQS7B6vkZ;YdXrD5JU6S; zn`(80^->+N|xKI6j=4j~8#+ zTs^&i;UG~-Xrs}QVL_KnkVhS@fjIoAVWbse7Dz|OuZc+NmOSJ^E3@p~bJOwStxdQh zn%E)MHdbiy>v}yL#_NTpxNs5IVgi-Z=ApJ$q=)SAk$54vNc%Xxdu}?yy|vi`Kmb%l zZ>AxVy;cJi9!0*Yl+aAKXaist9=C9b(Jb5`xHij10uh92_uPDddlO~hwebw6U}bDV zy95mIn!mA&ooYGp1WcA0;exN@sGZ-UMPLuw6hrLZ$53S5>d0zb>1i*hIj^SX5rxHB2UY%HxXO z?zxRI(6=@>Bz{ngGw9|u!&TAZ$je0FC}V0io5CtRzUt7HeOWQG4QHhW{Y0dOKeGPC z|ALwC(!1y0VP5$=s0E_2xiJ)%*``n=fl*?YuqqXVO~|ALRqtUwZ%PL677||NmRKeJEE&b2p1DdQZ1EL zWjnk+x0*p^1vL>t5Ui&`%nM!>hf~wo+^R87ov8$9I#K7W`Vva}g$wFyR5&dja!HEe z+;Up-<}!RpNAHlJq`{*tg(VOkMcI$YWXhj581}$5#Y3l1M6pkSQsyHT45S#r!Nt7f z1tGy6Wq8d5^nqU*0CvP!1X7wY-iOmwN`*~WEaMasQLgHCB+Z(95l9bbzi77d-&$!y zwj73{h}}Lp7Lx}qTxczfR%cPzRSgAp4}c#U&VJ#1<-g$x?I07{ z4g)eUN+mUcZ9O7_QV*bZ8tr-|AgNTV#C_6g)GuXNF@#P$JD&d^pZ_WUpFQe-x9I`W z|Nf`v|Ia>iUciqrBpOuLZI5EGMqGp_$z!9XZLCo;p^;+}xXHCN!oX_SA!wVj!-$-s za%_F}8Iw0I|54$fKX4#HW1c7;h+zzZkt&1i4!v7meVM;HGSiG3XQ~-(lgY;**|*ncpEfV~ zhZQVYz0F8Raxa%k(D7vmoeuDK%HyjfA)e`v$jn&tq>$6XpFZ=@y z=2fenhi7ml3z?3LD=`9DMHU?RBQyki>QjuD3Ir`R8|rHFBPLhzIN-=|c2-$0|K6Hh zOBD%XQm9wweSs^Ctj9L1m3rP3E!B;l1oV|}(V9#J9axdkaSl~&IQs#!m48S;0SK0^ zYg3EUJuB{Nrb?EeAfNgeOc_c->m*Q{iC(2}Xwun&2l%P%9?m{>zVZ+9c!XRnnfhJ^ z6kbN!HMcQfsi^PMAl161$Vs#mh{g@H0n9)t;-^&0!-v;rpFErS`^$2dsC2So(u>9i zAXJQ9m#l+C=r$md2A8~O84a#G+8};JO)V?B-ilrLN%MujPq4sJKZPI=IQdvv=Oydp zmRPWrTXJLC@XilAng*e0x-6kgrybB>gx7F(*55CGLzpZM$K^pKallt%h}D&~B*8d_ zD-zi}14pZo6GKh3E9tuDYN=7j~#>;{A*?%+J z?M|`5LL8l`;1=ai{$=vmq$pINB4g~s$0L_gF{l}2EXdd6QQ@>5QdAD?o_)x8;jPQ> zP(hg>^#XqgJ)N6Gi?!lP&@k`<8^l~zrDx> zWeS0oyDlHQ#n)xlsM$d+nB3elaZjQ~L}j0tkx!aKm(>nJ#Zec6E$=>?;x^Hx?$q0+ z=`te1DRMCHXl$-WTqAm%ujx@z(nr~(=bJk0E*JBSceuvo|P4b(yO+jI1_@< zs+x`RL~OO?&3S-<7>Nmw1J@%g@y@d)zRU&qq4%U`Mn{SO7iMylP3(^aOT57dbuh9| z=T!GPU#<``Hw8iI8|UKpSI-*K<)0}HoDUZ({v_5S zgc!bU)h*TKK$8$pUn2)3ruY>sZk;X|SCCht4YG*d;nnk`_wrAX(PB7d7_@V)2q&~K zq72t;qA84sZ;TX}%K?;X5bx{Z6#w1->Lo~O5^(+MY0|rW`6mP9iuyRCWYYhKz59T( z?5fU0e?x@ZaE!ch3f&w+`;l?lUnFKee@(Iz~B=PJ!TX? z9h8P7I4?si@dCQt>( zOsE$w;=pbOOGl1bZ}L31n}Ah0uY>6W1OU)~|G`OJnYLr}MDvT%X5#bA%oM^=--~a- z(~$4*u;6r@j$sz;6joCxkaY0;aF>Ai(s>p3smW9#NT@pR=Ac-|h83loy_-afcf&x!9SLnZD zmfK*%VgujhxJDs4i_j#~a0!?{p0xVk=xJ~|)10`FMrUzE%!;xEm(%h-?r=gbok`tt{I! zm<-lsGL}h6BhT_|EF7Sa7Jbo~FKy3!DR)TX5HN-dVIr!dz{@y>PkJ8E65&T%S&U$dwG02_$tCTXFA>q;gHOLHnMybiJD6Hgd=fYCQ!G84Is#F$FCKwl zra`(ikR_|&_zvygJDxnKJ@bR2HyZ}LE}BqQwgh0^Req3=?m2;QiU^E^I!6X#w_sK- zloT=CCDRRj2t6y4i_4kkM;DhEBW)?=kJJeYmFAaMSgxqijmQ`qR ztZ8xQc=EvZ%nvkd;dX{!I6=fYG5?R;oTzTD(_&+Qm@Rh1$Jk5aFNlO#01ntNz$B!A z#+e_`p7{Z$L`ElGB=2BTLRb1dl9kBHl9>S$xhyJY3X*Uj)FB5l7S}OsXacaygfp-4 zZ?G{6fN%0I z){9UDd}&yszZ)>%Qc0$d6ptru^?h__Cw8O!7@ELT(45x@@uDQd+{9%=rU)6yFEVoM zAU$TJCQb%b5&+F0yycH8liI8>KblYOD4;oM+9$(bN{C}S#zXk48Z1jR|7mV4>O!I4 zX~!_Zp}#0(CT3}IJZXCsMt3p-FdP|zP@!9?bc8;bbz>6$$9l|BL^PJoh*2011_fj` zPV1J~MIJ+vyL50;tJ6D1XD}1M3htsLNnk+~h6TiuGEfYhA)_3x2ZIbLSy@sdX3tYf zQWPm9q}&~!)>_bMpv?^d5`-~~5SWS#rZa(8V2SP#er=NYY1EC_N{X5=GQCHJ+oc7X zGzGzy+5#{?+QEl1ZxYZ*>84wNOQ^^6aim0Vb&GVHIK3|EC)`9pa3`%8z9SzjJRiU2|gnaK@y^xBw0!7C1`*i6RZLPZipD33g%AsVLK@B~ScCVNMVu=W;K4y7ACnAXcwi4!mNtDc53Kk~N$dBH zS0CS=`HQ?qdJ7q1`bY?xl6D$F*t~)nW5=^aLTs0XCM*Sh2tJ`0?ta+Z+Bf zR#nD`(PP=c6}gCKFl$MxaF^8I(kseuWe5z$SIw_nNHQG&Vse3j(A9n8)kn2w{!>Vr zsg4#E(@E29G#0ieq$Tx{d$Fo8Tw`0}q^V$C3P>gGO;eFyV=2bb-~WDt`k%l5yW8LY zed*x1{zqyi;P3ywvwy$-p!ajV=l6ahRj-4GD+KJA`>GSim%wh(d*pHE84ef`)dt98 z64+A~U!)P82}V!nupFAvn?<}RuxB_d{jc`3F!zPrI7jyF{EsIx40e)kg8&X7kAzbG zkRtbRbxn3af$x-VTF{9}C7cEw$gzj30nN{So;QjN<_%`=Dw6>zg}_xNzNpM|;4xdZkFFx*Cf2m_#{nM{ZaiXDwdKtt3v z0*^8pw@mRT&0i(l!t*+5M2W#8dbj&FCB~J*6(8p3zU1b`I6=lU^DV%lrAW?T3UC;E z%*pr!dDy(TlADkBsSrRE|Hr@p3)^$ED~BsQ%+Gz1`zL~=375AZ^N5PP&g>?hU_hn@ zyn8s-(k9f~1}WbL68#UcA^&p|kK!&cm^4zu_wnI2;>`WI85YA*jes0HDYU0#As{5|)_6$J zREESwgJx*>Q@{rC3JS;G@-|K0+w1Gv9z9dNh*|8T2!&%MW3LU^vh zoFaxeSD2#55r*)$tnE;zPYY8s3Y=@3zzxa!^WbMJ!jwbod$BpC)Z zw>03UhamG1Z89ejzoR1fiFpwLC|=RVG8G=%eR-7e;VO48%)JwO0Ot_37*GI$MkXDP zVh=$?M>k0{hsZ*C5HqIZcFa#aG4z>PaYRutNLc0Lg}JwdL!nH_M=FM9-2H_$c>*;! zMUJ8@5CoApi048{^>9c71ZRb4mKkXYpyI(RhesuT%+I|EB8fe+p71MZ7F{plh(CvY zac1{UTzAK%k}4f%`}jgyG7?Y1j5E=IQ0vd(R-&JKhcKL)dt~U)Lk}0p%aAZ&8DcGy zNcN=}JUE(IsuLyiWtiqZbt=FCkiurhhpR-tF!y%894ZrCS^5zBl1{l9;cKKUD)GkwxI zw;d2?W1&X{Eg5C_U78`6m$&xsQTzXYYu3^$;{cx+TyI_z;-fYBvUAFf>)3v=IV zLQF-{W&qE<*f3@uK`vQ?sg{r$K64v+1(c{mx&XX3RmcsO^`zihBrq&1hiY5K{M@xk z4cMtK0!MaE6Nm&8{Rf9L<&qct6tbpZA*Q*Od5;XiYh(zF6HFBzwR6{C+qZq^_u(70 zbM|ug!uLs1B8~ax5%AFkQ-{UBc^bTnT5TBBvr1t_X!SD*Q0k{d4N)CAPO5J;Xxq&* z_o5(D%Dh1lplhDY{&NpF~D?6)GbRu{L>6e5rOU zEzG@?2S&1hI$W4jGq3nfcm{*uI>1DPhNyB5mgomEMHZa&mYc@Rn6e=(k#2mrZCRRo zNmhABT464JFOBwe1uzyFImu=+eP%5FhZdVu)F3H{1RZFaaSn>aWO`&dX1wkHnR_u( z5*YD2tVpQK?8-nwf`u`Li)T8S=RgPWO5b#j)Q#{MsP6hqEGLzt>^<85KR8SMFYo;R z{iF52YkNo6|E(OVI{p0IWdX%FkBeaH96ztOrZAQyUrYz$%1eHhn9qMbU4$iWn)V~! z1#MAN99RIb7Q2<{=Pr$ShDWnQIO%-m0I^WNav}lB0mvzB4uNtOVUKqUs;pj#5C)hn z5S?;RhIxFb6_DpH4+1a#mE5^)wIBR4USK!m5olas?Iei)a8HX%wq24o&Q zRAu@da~ClHcPiAB+w=f=e@pTj7lE`<`A{?`Hgl2HebMl-RRknp@60La1Qz$Z4FF_Aoj9QTCYpX1CmvAnK zE0EHbN^nb710!KyTv3UsDy;CqAh<)O$SZ)fjKsiZFdRX6l6`xzNLyu@dr*iz9w`>) z$>kAD315$lA~vFXj6sm#OR|qLVr(M~78)-j4YC^?o6=Hd)tPIRWnu2(5-mieaC-OT z_oDzCQ29}5kz@@(Kv+vf&V+dodO(O`c{WCEd>BvM*ZY4Dwfg_u1^h0|7jy|^CK3cH z0vkJ7Luw*M+?^(tM1C@hAcoCneMQEZy3R7(hDt!lbJhRuQ1!oB|NDIZwf+`(*8lsf zq4_sHw6mRM1}lrs2qohY*1?ynOV5*8F@Qpc60Spu!8UY`v0>bf;J)Br%ORGh_|NDrp7oWe$D71X&bp04vZU6PJop)LE!NHZj=gSLM_zhnC8j z=jV(9lk($mF=ieiQLQ-S2vJS6L08;O$cyOX(EwENAlV>aqEX@b7^YZ*ypIpnF8YNz zQ(qjM3S*9qD!E*-fI)MS@KdlKatLek6T7cWVdZZY&uF zx^N1QJO@KS(v7eI1?*B*;3rsN4}n+1n|1&Lz%W5o?vsncI1nrkA0N7Fd*-`F1i&lc zhUpRhBi(>F5Edqd@GyC)87U#zau%n$Z<7%b9CR65wv4@np0S~oLua zmY!)zcuXL)HJu(D(s5dY8IHqXsOzC!F5{UwYpA2v* z0LOt6kx*DTQIa;_bq#kfGJt#;s9+NPoUs(L};q}Hrs7c<- zvgOJ}D+XiC-4H{Bs1Ye2xdSj8_65ax?sWaXG5~J?iw5xdqwoJ1ueXiOv)?pCR8qF< zL2xAamIp)UL?$zDa-#!8G)oMZPl*Y|ce3C;HUWY>Sj>vIS=e|@o#xqpb~B0QP6j*p zJD16dca)9BP$&|XjKr9O6n7bM2tG@ecgT>Fcp6NxO{^4y$LlX>&-_nr0}*4-xNi^& zi4Fjy3@M#V2APH=G%ukpX5%spBGzSsI2hUi$vp^MNO4TV%5AN5!B%`8B zr)e%CxiTMaNYTT*%ma)Fz(yI*yQ)x6cxmK3p(}`vNH{C|InwsmScVmbAa5&dH@TCOs-q z?-&M)MT0$2{Elw`$s{10iISd*EU`cYV@&XCW&MTiDE~`}>5RZwamtKtO7aLwDwsgS z1bG}b7ipfe^9Z(=XTy)gen1l}Gu0F;v2^{&lGA^1gnt1wybMJLDygNRfiWkM%XE@C z7&z=GbvOnX9z%FD7zkETFlhEB(`<~_k1RR;dnm|J!`C1uhG7>mgjnj*k_{fgCP6RY z@-6TXyvg-gi{Sz(Fxa4U`sRVWi=-;!qO2dY5 zERy4A1~bSQ{lqPZTFJhXEg&rk;K9+IAgeA|SeX6g>WYbPOhR~L&&j?^PpVrBF^rnX zB_T9)M=2tLh^kp7;OfbbA`6OvKy78cu2`6#{jZ!W9ZLCrw5Jr*oY|F<^`Xxw73AT$ zz7t`^m9tVpY)axKMe|d^KS9EnjMvX^vGA8*BaWGPsW_v6?CFv?Q>uA73*vloT%5oi z8Lc338n@Gdfd*q5D2FLARzlAnD0`pw%)dzNanBMKV@QP02Vn}WH4I1vj)*_NZ;*pC z^8@rfU0LA-ViwrsA9)DBYF5VU_ioSp$x`QLx}1_uAevh8lC<9W@RvM$?hinE1Q8&F zD0*dhn|n4KzyX3qu`@K@g;G~pEX@9b(eYqriamsRf`_EvVh=>X>I^hMp)ZH6@Z5CL zngFcGv&lE*)r71p5nheh0;gG-*QlcIr(LuTnJS zl}1qg5yBxHf>35peUVp;*XzQ9h1s7sX3QO&C4a=f-Kq%;Oh@@(haeiB%OZk1;gQA* zB&6=cTV0hLA%dis?V8p9@6;=Q^)vPVy#Mcd^?%jC-kmD{FFC;a)^<9s59lPHbCYHv z1QfQV_7Lr!^Ca;XT0Jg%lu&|thGDR%lHAw>8QiGaf#W?q^``BaUnexm;yt>QI6Vpp zI=sYb1BuBNQ9(@4e1k{9L=pzXAcgNqY=pwt2%RTEcHhDE6U&)*%)XWh@lU86dJ%mp zHE$<%B2%A$?d-|+{U5Rh{0uxUzmiIq&@JYXUip$T>pKT|%%o zs-D3)(tu%#;s=qa3=5oLM}_4^00?L?H=!V)w^N+HNjns;Hc!HAg1dWRMp$%Mj<9Rq zRii?wr9TWvIP@)`E1OAdRQhE}91m%C&n%eWG+sZxJ+r?bR}_oPB9tvOP8fO;tXFAve)i>VD{MSOg+38-Zk#~^m56&~U?cbz>Ksf- z8sHh6-Pj8(&MBi4Ntrz2I9{*n_`>YVFm3l19|;~snw2So**tp*?jpXZ}4Q!ikgF7zPZA_pt`7n8k7J zj13)vnbpNCQ7T;&)5bozMmdhiA*yVCF;(@fM*jEz8?QgSy_NrIP!hS)k%>b@A*Mz| znq&36+$c&rV4*Nh)?wUiK4wHp$TCZ1o=8=Y%t#j!!9U8$x zK#d)f<{FHOa=@b8L&*SLUuZ1;B}QOf?j+n}W&I)Lyz{faPb^PciEtBQ2IeA0Is=pT z#EJLOa`;WDdOMPCK1dM(*?*bR1Zhf=2U<214{nFzf8;mgq9wf$-dSh_62TGwG6sw@ z)RI8L)J2{oAh?MLh%kX1lfyZma%xWv~Cq+V|7Hy8IRJ89hH&{`<{q<8O}F zS_yvkLcG!t7y&ovhQuXwEyWbPfmdY8(62x$8idn2kZ2SS=H)^=K4tC-p`g2t*Qx}+ zF#AB(kgNuXM++CPgf6fPcRgUTD==yl7@e8+l~CMd8WN4H>B=0%wo4&NbRMs@8vN`7 zDpL{sN)qnFe2KjPj^TmeOqzfRdznHy#-O`YGU}CDJ)ncnlqhZ{>0k76pCft0{WLJR zt|v;Ak`gf<$SI>VGbBxBY*t;(DZ!k8VaU)y_wH)qE&&MQOVsZ-Ls4`xHPIJ(Vs@vy60RfYQx*I-Bivgz|`2Y0BQ`TB#diH`) z(YQMERCP#sJ0)6JU|fVTHJaoTX?tRK3AI5%vmcD(6KTbW%_Cb$^}NNQW^g-Z{mpwb zABG!3<0?=9FJ#Qg2~1~nN$H536ElxyX}~-zq%vV(mc5x@!77!w@mkHY7H02Dar3Aw zK-wIsPK=URxD(-+P8KJ#X9Ud)*NrF;pOa*;Cngr6tK2~liv;VHMMu)C^MxH#C$luw zECcSdO3cJ1k{p4XR^HpE0v1& z!vb^f!EmO-EIcTCPktONz^EIb#74lQb%-CbRv@3c*4F-=`2Vwy=>K{9->>(cO#^r> z4d8#*zm>JRoOyosY$jebw`4#_JAx@N;#ld`7K@XYn&Lp0=Mh@NIn5=10C70F=M#wh zVoJGQ8quzEpS@R96)Z04Q1Gwh+~SR~%gBZA6)MX@Sw{+cEGQ@=sz(W6qD3e%4N*81c*nxoVb1b6_JROo^H#-7FI-T}48JVmU8{ zPUE#B>Ek&7$=QqnSagnPhO~aM)I&0g2)dvvYa@LzwkAMJ-h*t#Sh-8uUJ7P=^6}bP zZD2Y}<6Ibeuo0?-Nq}zLChSE3gt?$6d2__Rs(8YA;RzgJ15#tun4TBt;4v#}_iUr| zJq1I_xT*v9GygIp_a|JZl2TfZg*Se$3}he}MXVx`*4HAm`AXzsXlSOF#f~E{EWJlz zKOw}Wwa#4`_` zWGSLB%SC%q6Y;asc7@Ft)U>N4R-+b3BwkH_vXr_VPW8o3HxfyH|uUV;~hyHpg2K(SWa5jmnr3E);dBP-0VT%9wo$Qjr!6MIaZJ+D5%W zo7x_-*|!(k4sc=!_(;W-y5_Sc+8KdBp*7Dv<~tC1V#?BXOD%taZHJ zw(8Bkja|E*G}k!C$Tu%6i+K zHv3kTj;-)D`A$+dPak$lR7ll{VT(=VT>(Qt$bd<*fupg~;260baPFA zk`kCK;XhJZOh39zA)CRH%&IfeRNN{0gvNkD0LwNr6yhj&Nuq_T?U$yvU5m4C;?)eE zL-L0j&JD7#9iErbDSUXeR(h;0CG{CXIgA|W2*C_yCASwNr z(LFF97LZP?2ucNi(|hSl#+}h7R0v91i&PeQxm!+uSW2UNR@S$*Cw_ef#~qXtGe*&ib~Rp1XixjiDb2GGD=|#tBBL2Kb9df#iYh-2U{>ch}@=Tfs?qh z!7$Wr*gYnJjO>wA7lBO1=V^eF=quYd&!C?*vEkw$e1WH~thMW`XD|0#o);hW6Jz%_fRIOTY}DJmL76MqFc;Zbml zMxOqtNR}MRg`?v+KUo326UBI`tR_r=3sWe@Yi$S6>?Lsl-oYKsZAfg|HbcivvKw|Q z0T&?vf}3LC?n`Q>K4qDSDXtm(NQGnBJ4+1NO~bpKvUM0svFmaVTekU zM_028dW@JsV$dw6tYk4YNQ1LNQeL{&F0-D!SR4VeDx~QUkb8N04_Ty?6m(2wZW*wU zM54r(sxcctJ1x(MWC=Zjk{DQMR_)(fn7xS63gv*$&s8{*oM!Zj6o_~6Zy_d`G~aTY z9v#K<@F|l^pi+kw4ve-GMA4)AfBW};zA^Z~;6DAY9F70efB$E#t^t^zy_HD=;YAC| zkV@Lp@xwLfRiZWF#h8Y(%lHCfg7)jheaks*!d%jgVsfK!Cy zeWi9Cc?u<9K&8*jeX|f_pHw+@cTelTJ=A#Z2pc*Hrm%bTk7~sXSq(uewIdNI8Gzb> zke2=;a)U2=46qn^l)zd%3E>EHHHBPYymo{Q-6A4`nPPH$(l>Dwgtmm6+>7{cK!5(8#--v&g}^d0Y8ebpewMa1rX+xP|pT23!swP1J)uY z@H=N^8!SP!htHX7H@>n~snGoFthq6A2{;MD#@P3xyn+BjCVIJFxPpc{Yb-E%d!8ic zC1~*x&yzR;^O;*^LJPB_LPed#^h!NK9E6et83V?|#Fo4%f!lDxG!HO>$Vr|_#B-m* zMPx;A1uU1^`u`nzwd1G%T3x`)SpzWD|F`z&HsC#4_;C@&hp0s1Lh%GL#$vL8cEU$G zcv1&2%Slq=qH!+i8O(t7OrzXA{fgnV>l$YtWonac!EA1<+L|N}Liw4JP0HD6lo2UP z^{g}>MDmex#&i?0O$x@tsEqqwZ%lqWI2K@+-WGVkRZH9? z4WvKHA>$1+Oo7|lyEtAuqS0UB98m~)TqG#)8;_125U!d;xCFsyE0mC=2$)4;K7EYO z!n!nJp?m^8?nGIr8vVlTLk(W?1xW3HR5|s6gjTeSIWuI#z+;FjEL%`!*65q+VqR8} z0;8w~UBL_nvD;fZkErwykuLeN$Uu!tvhI|;937W-C47>-!pBXiOQht*quhkrqVhx9 z4WfWb<>0;CeZ2OF)-oQEJ7B}fvpuN?vzCVR;*6nwoEPy*;P&uIvEnqDMdT%acm+bZ z7i(Olq7f$+P4*W9pq z_oA-2cBJa|Fb)s9ofnNY&M8{pJ%Bk{OA?64qV#0$PmuM{fD7c|i%OyF$k>AH=x97` z$@{!g!KZ&YEJW`KS*5#Qk#Z^p45^AXD28r zLN1C9kj8i@2_?jnlme=g3V=8$36emtL`vxQX13OvM!(MnjB<&LhK&W}wR*;i4&Wp% z$zeQ2^g*7S@WLRBU)BJH7;+V$PKXlg7rkY)&5K6=!w6$pf{<}F?E&@rqE3$oJR{~O~B%HQPg}EMcBc8yH=Vu0~!5}y8~*h9o8Fc#EK(;EhH*I zEk0vrB0hz#`7(|la$>d%FYz-I3uVQK<@~|&?@&)(X{yc7k3JJt%zwkj+z($1sD|9i zR3d=#hSZi*vJ4X{x+f5d>jsBV0kI>KCQ|M4zQUSt&W}EAdca63{HZR63xNy?vxf;r z`e#au?BP84Xt)c{EZJ=`de&hA*boF=^p?K1-aGm|32qoFYE=-P8v{AGo#J?Y5?oDX zfqx2`A}XYz#JEwFh499b0VLz3kpS?fO*u!uTUbh=Y)Pl$@opI)d1}s>d1ndIOYoa$ zYQ{5k1|_Xm(VW3=@;v%T(#frZi~0ZVVgJ1T*Zc47{dw;Vz1@Si*IMA<`v%{)p#_ec zwo`rdgZLYo6dTOT2vU)WDxH!R1%?i5)Fe(tPX`4@@Szj0GL)fYxT zz?j0wO}7hxUZ$d7*+{eTAiX;@Jlq{o3grzy$XOy97}5kuv<8PxaY@$K)VA;W(TBun zlO7gVBB?tJ>r1C-0)HZtbUXQ4OaqjqrQgZoGaijSAp)tY^BuHcrKvse^P>-o=0ywQ z0P<14o-z^e6bAWv015vL`2dg%*DwpEas^Z@q0oaROLh4onvI*b1%CAXQDCA=U_0(m zu)@s~C(#Bj!7tbf?2SAKT{v1o4^VrDt4y+Ymu?Ox;^y+tn zb1V*#w4P#N9>Q?=JF!9G08XZFO@v|uZXm5pEL+4)EhbGRh10Si@qfVoFHQZ=+rNwc z=kNdaKGeI^8$teG{X5t^u8i-F(HEo&K|aAU5f`>4H3p;{INlqJ)H_&`WF#$O3#&(} zNF|sAM+`;J`YN$y*TLqo?Rh^RZWJ6rp*&b@KFz6Sf!o5gtd4@z8J2(z1CPp;1cN4# zm~LL9qZKVKktzTGo%~yA+P7tlzQ`H5jG7dR%6ZKs{g(3w=0(k9onfGopHkEpy})xs z$mAAcR(h4BB;;ORxPPU2OnJun(dXa`+d*@LaGEBD<;^r~o3;8S&K}mDGBnD9F$y=% z3p3NQ6n2C+O5xeDShj!fN>fv~`O%+Am9P{uz=!FG5^0JP6p=0@nwp3t8EQr1OK^{i z;R!S=iM*>rF>pw*lCHYBanojSqd$!{m;y&3=vB?Yd1a;E#%u+HF_3vGNXAzA{)xxmdrv%;nchi zKE}PUf#j1^z?G(E0P~|icIJ?GcprD1Z2jX}br{Cm-j(hCp#k zYA^P&h(Zdbj^n27Q5$`hewmoTywF9kEhFVqP!hJl@H7*n4AggfZjbDZ;K-g`(D%@9 zxFOzPhH1xW^Z)k!Us?ZmR{wMDDxm52|F`|4qgO?*G9D3;-J(g1fGpIe)(CAVr&KH! zZ^AjDOC+b{hnTI&2nFMZMdI+yJ^K$fwSRQS=#@CC+2k}KSOIONB9NY;D1}ytjL-|I znFQpYd13}G>S+y&*kBlnlq(L8o3?v&^a|ILVT2HQ^r(xZ1uPwTlSD#(HGHYN^F|~k zEk$w_3Sb6d8lA#nv(A!J8M)odD^1%yI(m8Nt_kovM%2)Pl$df`N zTB)#5eUgDAOv1TnV8F*s?HyehT^AY1FeOf6n7D7ULY~3p3WqC-Lpl~fHBy^eqK6Ps zCF!DH)ORBTzw(584f3Fkr7vZIiAPBU5^?09cxhS%;(+nWuxX$yl#7VTx+7FYo%C#y zE|)VA;SuJ0w^-V5&-@a0VERK*z!PpyC4(VQPjEHqrFH|=Wxl z@XV_aU)-Mg#b5$jsPnnyRA5YH!9u3SzTK{&fVLTXdXt;Ogg9%`WA3M)$Sd89lfcPAxxB1oIT>Y37cGr(VIX1%k*8th~Z7SS6E@HVHadg zUJ-~%zXXp00^_C@j~7O7q_3C?rYpR-19p@}9%-V9t|YdZJ(&P`A(B+8-O_Z04?mZS zB`kq*mkLfWzHw8l#|xu3i2f3za1@Y97z6X}*(aU=T4<;dzu32tl;B0Wljx=L&BKVM ztkhkJU3n(&ylQIscwzK<41vXoz%lsL5j4&k#EfQC2P`-#0d|rM3F4V!rtbeT&V^e= zY%^}W3fhjFc3sHm`e;_*)9fclPQaygKzk3Ku}`7}#F7yuGMZ5X%y7_A%m%M8$+APL zCpX|VD@|P&GCz8q0T4bIKI9Z3Oq5s#cb&s8=K|60QuD}qvyw6g_yTT)mxZ^a_7fK9 z1x`&}7P2sUtuYFrchEgEOgtHJ25+oWya2aA&)nwuet+5;{_ zQ&*aHVaVt;3Hnh%Q7Kj%(kXl8IP4H%Oi?Zc04hDyDIHB5hDQsD33*AZ@FfvVypRcu zn|5Ky=+(>tMn=VEcc~(#!(Oy3@hUu24v9CAWx#cu#q`rPWtrtg4`>{>si-6nE+47? z`P1r*6xIURwOcd2VjF|j4KV(Ab|Ip z!P4O28H|F_T%wxPMz4j@&x%}V9CqRWBe5G*m(@ta0gV5EF`~T~W+?MaiRQUT-gg!b z#lO=i=4VRW2bA)^OvFg0nV z-$@OdRqrRqha#_Nuh%uh6W}r=hG;p8U|Z6jDE)RCCA{&8Hg3aEdRfj}Qxu3s#1kTV;^}5xR>r|fi%}+8 zG~4B#ceQ8!F&+uY+?5oJq=P8nW$9~6WRS~ZNC6k1ZU|z)@IJ;W7tAUc4v`T9S1G0K zB&+N%XPzJZbi7~6nn)R_GTQu~C8sD8BM(7qF_))m4^Wd}CylBF~b0LsZ2;;cf+m6Lg z0t8lTEc|+YP4a^4#|DuKNLCbY^b%JBdqE{e1hkon2FaA7<;@8wqM@lAH+$MM|AeU* z6O3LxC1T-j7M;p-CGCum;W#IhR5~) zs{eNH`}(utA?tsZ20t*kY;b=EzxChBr0vTb-IHze8~4Hf!HhZ1tBVutxT$0&5sTsnlTHb6ch%_ss)H{ib@&sNOk~Qsqc?{@z2i(1lTWL6IsLm`8;rv>lNHbq=u?)sR-Rz#lwSDnPNh zNYC;;=EI9sV8!#VsIKAZNm*X1k*8#cfQ#m_Qp*d3CSvZd&+XDS)5JF*k_HLQEn zH-3H{mj9K{@uWtah0)z(D>4>0&B#O$Tq{t7uA!%bjg%z>ED;$5WEQ1wVw!P9K$2vM z3W6E?iypF-*mr^#eb>MEH@I>C!$k@FT5reTUHu2j!TyWC1xhqseRc()nXiWhMW#vq zfvO7}ZUC^A)nkOV%(ajfg2qm8AByz^I1wZg1_hKMwmx9O2yS@wAcL`${jBOT1mQP zFi<9_5Z^Zuk+MS*Xh{?;a~;i!%SJE@GfYzKxeXo*O)tfG_37=I|2hE}Z-uC4LUw6n zjTL4rlq8a*0FpC{YM3*EL0sl6hKY9W(YRhNmAqaC6u~{Kh`#fGa*H2{~c%N?upeQ z3GgR93z4RAIuxACOBpnEl(I||GZ15NWQ7P)sJ7oRpXdg+T;9F1`pk0X`I)bYX?{_5 z1xO=S#Fis^q2)1qgCvlFXrqr2a}M+?w<4PJ4v|0dO}aN?a^BwlJ?$<3EjJKs0S`G{ z#7M6eW*FHvVCB0J6T&Z+0}~GDVUiMBW!quas-8g z!J){l#!aAfD+mNo&ZrdFE-Vvo-F5k-uCzI0bY77WB%=WVvbD6s)EZtkN>D1guhZj} zekOQ825xK`qgqD?OOiml#W;6~B6aoA!szUDj$(GaAj&eJl=#MRgbB(|(h(FSk)N~Ic3iAIBI!ul&oSkl zs5tTwI|v;L{zU(X{tZHsP8(ubi-$R)0d4wRy_HE_s5d{lf99GGF=kgbD!4C-8%Q@1 z5)0Lj9tbs!{$9CI#1sLUI~>J27* z5V6w(9&wzjK~+frC&7!-J}x-J2+^KiR(Q z2#%+Iq{vKPl1uZ_0E+t)bd7T|zv#EQ1eLB`r8l|{3gy-~sw~gLkzw2&;*ew!exmgZ zF#mvKo?3q?|9O#@EqMcrVMsLO5r2IONJPN@GO&=>y@zp zY)LS=xakcZW15j$BOHl7hEBS*cr^b%TK_wz|E1nb{RNQxJ%H}}KPD%&Hg*zYi8g^o zB-%jP^fozVGLjV54KeT+AbUu0{}Px2K%=0bP}qSNo`A=AKe0ML?6Q*T)v#1 z&?D5bs+0_!IT+z;rZKV6yrI8g67WD;hGWDm!yj;jl}X!`I=ZoQm_;^3Dz2C(C@NN9JLDZ!+D~$0uO)krs|>dqfv+~3DF(m*8z}FXTuqG3s=QF zLMt94@bI^YeXNV2!oegBs0L^>r{bC{WMxw2(D~5}!)AVlAi1y6N=7dF1bJ{LrWr9^ z<&MR31=itQzi$zrpogZxrt%xvSES!%^T0g;-1N6jzuw=1JCD{ZS zj>1BrJ?u@%$@h&`QeU>5F5#6)6+`DoTiF-}4s-xax^&o95pH=u6f%YGrNeMipdrfoyHsfrdR_elK@uVBrwyCi|2EYHnnI60UKD-&x{ zEQTBjS0T*;94Fk`KhQg|cV@5m$Gundf4qN%b%1#f*k^lZ4qi66bMJ?GR}Vkh+kf6_ ziSa9|HM5(a`8iKjd=D_vHU#~wc~4~^#tQ$_bODhi2?0~_F}W0bp+ay`$x)Oa2x0I& z?Rd53y9+Zv6>T_yqogM!6XO%JBb=r0g7G1&5mUoRDc~L#6&8@4Nl8|0X350Acme>$ z)!T%3<|mm69|IUgt&v%Vg9jL3EGG`+bEPOoJi;^hk!+D4=C3_O9s}M9s3CB~lfg}U zr)?e-9T~5-a^B2G`C3V1W1S&zPV1BrO60Lz39XH`l$SPz-bN!eW`T0WF?2e_6wIXL z#=Z7mzFLKcGiH7oqVwCr`B5BRg_(MIIYk6aq@78Wzd#5hCG28b2$XZH&qj-6KLiQ> z%<%?){_V4mmSxQRyiv;_v%#PRL)GM;2^I{Z_(Yg+!|H!(qUJo#o#70+NAY5yG49la zW8%x>)s~RW{1+z78<_=Z%Qb=uvJd_)I2L6kRdN+MZ4aDJe1R4sVIEX@-R}w?rV4+xL)GU?XTn#Rv(`G`%hW)@MWkO_y z0^%a#089vX9N^`+Vwx*^8Ua2{@?E3|5$C`w=wf;CMAj-=yB7+Kge{$oHNK$(r-76 z#R!4P#U#=23&5J1$UN}WkfcIu=so(u)%w1T9W%e0n-Zy@LZ};qiTH$!rqUNd*|X6C zq|#A-oK?Pr>5vz)0>P8}jr^)e18G-Q>w78YXMV*1(3&C}-8C1x;JoGYA)t(J7M zaMFZXmjQwxLDDKYPMA-4anEgvHuGOO3MQfZBdxg+$q>^FL{4Z_ksDZ@7deSarRzUw z8`I|G`#%qJ6ucn5nnq>H9_phwhgmr%A7ZRpeB?L$qK_sGnsY37?Rw_;vvYskN5@1srUC(gfA0g02 zUuni<`yc)=UTt&7nNRpZvP0&X`jCn``-hgU7PtwaOGu5_;B0O!0mryUJ7&#sEt4M( zP|7#u{ohaT{dI5nkHfzmer5Q%;b(@wH~fv^FAsly_|f5y4nI6xAHIM1j^P`JuO7a1 zc+K!x!>0@%H+=Z;!NW_27YxrE-eb6Xc-P^M;icb@2CtzZ!gL@F#;m z82t9&*9N~h`1s%_2S22jc;ek+Zyj7ec*Wq_!Se>s7+gJg^x(?D!NEm?`wq??>>n%- z76x}1+-7jn;AVs42mSs(^}p8tsyC5*w*Tq=Z}vac|3v>|{U7W9K>twx1O0beqxhQs zb^RCipWT0I|MC4t^dHi{wEuwqz5Dm<@9E#If2aOw{ZsmL{hRi0)cd#IKX}0Q-t;|l{krLu&FZyv^WwUBQQf?-Zmy}D7u3!3>*jfN z^W3_5PTf4aZk|;)&#as8u{m+e>ND!z(`|-ZR-aZkPpzA$)MHPsn~FDuX~r(&82m7N!>iCZZ58yi|XdWx_MyTJfLnasGIxO&HZdn-m-e%x;el8 z@IG~O@47j!ZqBv2^On_f>gMdaxmVqsRX6vvai907o4eP|0h{ButnROyeRZ?f#^mg& zo85J@t8RAI&2rr=+1zQ%>SEp8t^V+?b#rDmssEqeySO*}{P0(XKRA5r@cF~5`1PHJ zTL*tT`1Igs2CMw_NrMLsb`MVJe^YPZr}`i1zoq}Y{=@p`_ILDe+WVW{@AW>``(W?o zy{nyO`|9Oedi|X@f{=U9RFzsZQ|%mQG#T zePDU%1H1Mf*yXqObPiEutIh8@u+wPl-u%$6 zO%8eFoyQ#7#e)v)Hebsd9NOhjtN;1?A2shU@BJ_D{_6hykJY+hYGLNnsWr*E3iHCn zlKj(`rGq$-{28ZKNynSXB?wpK#;~Qxpe0K{%#l?hjbtT^X}r2pRmGX#!?+Obo7cz!x=$qG-7EW$j@6b`)k=vs~G^ z$kWlA3-KmAMd=H7Gvtv|_3xqRhB+M#_-UzC;oI1x2TK+hE`4cx=KqfIQkA7z;of9g z1BvTLU7(Xma-79us;|+P)ZtQa)e~i6O{1Tw*}17w|CjP5Pmola@T6K&Zw$7W#)H~3|E4@j(vs9W8aI6* zasx|}94Aeo6i|ya7NOKKsVugMdJq{psi7e-#U2s&z=jkkea3`YU5Ehgw;^u$*~*=D&FeKE=TZXQ_&_ zBN`EN$y_EgNCHFBWoXVOLw0ep0>dMBF&ekx&e)u9??2lA-~VDofd2KR2l$x3|2;X< zj@^$CAL)j)W2oeuY_9Yxr_LcCSI+UEWqq3ICJ;&8qG*y!HNrC6=p}j1)LHf_njC4z z?xl1iX(BAitRlJ7$Ym;&z~n-5J7=ehD4O_98D-Q5w!ugvu11(hLrR)E>A#^!c42$X89gw;&2WaCJvQGhAU#TnDobDhEDq#-<2@8tIpC4JRjysq8Y z^E3Zu;G?F24HIkvCFasRqFZzr)D6bKw31+E`xI|`2Nh6u*HLd;p zbL0ni7uRNbfj5@PhZrj(XZaC7*iVMR9Ya_?BSm%5lDkLbA!MaQE!|&QS$%G6KmR~> zP^6`=v}cw5bpN;t~8OV8VQM}!;Yl(Nv$J6lwP6n>WkW2{#OE! zn+V`UO3jm}C0DBJhfsx;Yb{7;u{kEj1KFhYX(R$I9GlIXyPzYZ-L<^3`oi{>|ApI7 zGSadbZJ71a(o#Mu&F--=EATC*O;1ncP);EAO|d0Q<0w3-bI|Ew1<}|jzo5P4e{us6 znRmRZ6qXlgC5aEQve6|@Cq;VLZN{`ptZnll%X!29O=v4+CQHzs!i#ugEtKJ z^gq*kv;Mz*c>{>-y4U+??^(UO9?6}%+wtT!^-)K+aSzeZpdoE5NUg_2ba1U;m}iYp zuj-#-CKZw_!%3sD8WJ%$>Z#vV%uZ!z*V1@$tM<&df@+apGM7>KKzW=XU5}iT7EK;>X7UJx0x67|>ch=J&B^VVPd1Iwg=kLV2}viCS2Xa{pIBi)irfQ4 z#eMh3QT$7Q#|a3NK?Y7^!Xkr@TDqNCBQ z0>cm=_rff>i!CGx6JSZv8A+u~-0cWikcd+lrIpDk<;?S=Q^bpuTc96{HI7;G%uDbg zfih87%aB0KrUX%s3sm59>1r#cDY}=LWL3%xE0bHcC%z@mE=`qb6bcRF3Jf^fJ!9un zL082t{FZkaEFOr#g#8qB5KPmIuFk_@Qcc|6o_M`Qo{jY9)Su?0ySQtmHDftN96y>?b_kK9iTDUoXB_^H?~VYCGv;n8Cf13 z$7Kb4#zok1nziu+bj)pMiGetgmQ6MA-7NRE?U`>Ydbp#M^;3!vxV-iSA%gjr`W_nQsk$oX1B@#M<(7p_dFB+9_GOlk^x>f%v-Gc2B#z2kFc zIl8dP#7@H=5hH}%6_8<1<`9OL-O)3MmONOA5%};j~HDP@Yt7pplsp)6--ja}&J)QAt2(`6xa$BhanmK&_}UsJb7?C z7!MXm`LdaVP2p4GC~pcUVt1~BAqvx>x9R`NGBj3*cNldc&z@mU(uI4mNyFUcv!k&@ zHk~UFG~w21vf3}>=f@&Ix;;q$hCcR}v%oT3!H+$fN%te6kL$WA9#F|~|@PG1a?*K~G%bTAY+j3x}o z4S;z~s=jSBgg~&X6@uTNX%G?8bV$fRGSV?a7$ln(;A3%KL5Y4*E>wpyY1kO zgT1{Ay#wqs!;1$0(7&&PAMlJsH7(6#LG5K?MFJP{0Z^<#ob2 zj7`X3)SN#RvXF;DS$RIKKshgQYdmRtHb>8bm7Fc$42_wVnM#=skquMw|Aq9XJ|oO1 z4~Z>tlJryJNenM*Sd%%5IefhT-@k3oUfYB^dJcOtqP#9$P0R*jyHP-j351K9YPXB! zAP{g5zf0iez^E7)M+SuwW}Kp_I~q^ghU(F?0Wl*<))4y!MG9i+tA}$@6r39dh|S=~ z1_oq0aRYHAKg&3!HCdd@vAwGJC${NCJSc5d%x@Y|8qM^qh9mH=>NOukmTRzY;uSe`s|Gl?IQm^YlA~O zNtXoAXKr#x)!=(JIJCI?K$QGv9CL^|P04rY=~IW6_Lnlme)Ws(t54hD(4x|YYdv+N zLpkU6)u$YD$WZJ(uA=OIYerH;wFdO;S)AFUnW@*RhuUxS-bELmQ z{(vQ;p)el3@UZ$aiVhEXaRebRJzLTR3_6*nXy$lSNC|{u$4c|$mP>zCqLP^6nNeE5 zC}$8pM8o7(Zr7?=#Fc&|63SaMO8Ui|7%`Ped0t^R6P3Dv*Q!0C< zWkpURTg?|us}qUcBrojNFB+mWi$pF-W3#A~B+h(_eF+~1xm{&7`pXDs?oYy#_qI28^30wPW!WQ^_a_Nfb#F6fN}^ zJcZ)~dA3V`P-e+FnV?*tXau1KnxV3YEA%$Gx>=OIHCMN1{<2>cc^RF2HyQ}@kk%se zg0W`^)prT0ZfYt~>O56ClqCRII@=MpMQUsvn_V`4Pi)Wp=lBqjimHOX#y?6D7UmJd5`1`|O8~)tzNA&!> zbNJffi-*q`K4v)9=X1~D;_&q0NyD2A{zY%kpALR^@XLdb4L+hb;H`sK4qh;L%HR=J z3!krt=PrZW4Q2;7>VLyq#6R2rEo+K?vj3s}`}%LBCO)VC#Qv52i}elc)}M2${x;dg z-+9~UAN2m4Rfa#>JLEQQ_;i7qNL?+6e+{jmo^tEUAwFfZv+_xJ0Tk6pS#9$aZ3-jEUw5E?r%uN~IVWpPp_r%pmG;%B`G_$@Uhmn-s@vV!d03#98C z%NAyjLkP$?lGF&Yt}pzmWhegS-b(X!viHhZ;4-9F?hvb~JS8wk<2Mx1vbbgnCguGab@unDJFgMe5d~Ga-aQVw%(z zGng1_`Vhs`4vgC6Yjp+C8M9lBx3e)Wydq^He3x9Kn1Rh@{bLq5WYLW2!g|bDq!9&I zq#z=PVWlKvJMQ0`#oP5ivo~dCR2(`Mb0Yx>;o&TPA(R&v!m!j*u#K2B_r!@vV(IG0 z+EEPE9U&*tv{3^3|97|lZ*t01rjh(#B18h%zkPDc%@1wg{LsmpA3AB1L;JQ*Zn62H zn{R$-ZsS8cop5&ZL!-?P&1`sr73RuvCZI}6P6jKE(lOGyme>ERtesxYJU@FnR96rX4G@&%)X~tTNYm*cZvL6er87QW;?umAPkdFJk!XY0jjZ=1kf& zr+%$XbL!4YCmWg^?CxCN-MOs0b7^1ox65-&g|~orMt7x-MMpjXTH00r|!;< z?#>;%J7;uv?$F&iy}NV!?#^l5om0Czx9jfQw!3qi?#`{dJGbiYoN~j?cb)%FFUdH{ z|CQ?|(@Qd@4oxq~m^w7QBxCB(^pcDl4k3-xOERVoO)tr~;n2?QlkSp?TD&aD%Wj9d zOESLYP|YHaism|37N|Z&TOfHg!F2Q`h4*bv>?xe2Aoz(TXle!*vQrF{7>U!KsU5`7d z>v1P_J?^Bg$DL$7u2su*J?U!KsU5`7d>v1P_ zJ?^Bg$DP#mxRbgbcT(5mPU?ExNnMXSsq1kkbv^E+uE(9!^|+I|9(PjL<4)>&+(})J zJE`k&Cv`pUBgLXMGha7%s+%2kbH}cOl?d#^Wx;eFOZdW(At()6q^Iebs(=8co zbls%|X!~TkCF6!eqU&@^#?+zdmW-)G(=8cOho)OHrVdTFWK12JZpoNBG~JSM!y(ai zx+P=k&~!`2)S>B?jH8DZo$&IF(0W(aE?%~*HGVZEx$FrhI;DI^cw1^ zL(^-hrw&c8p}ygeI61wBdg{>h8tSP-(`%@w4o$D2o;ozWhI;DI^cw1^L(^-h+e4bo zgwW|V)KiD1*HBL#nqEUab!d7G_0*wrHk!(M8)t8R=w6!~LcP!0>`?swgx*Vg{XG=G ziw0l!j*fGBe-sVS5C22{jn@aQGWAjo3`7;$2xUnhMieQ<7zzj>Lpuo-L+wQAEXAC> zGDT@oWifBoNkK1aM^u-nYH7Lf2X*TLz=hds33S9N1rm}9AS$%phwCa75!m#CZByw{#jDv zH_~yeKSl!=oz%G~Y!S?iDH$!R7D^$}TZ>FF5i6Zz6f%>bN>_Vy7iM4Nr1vomZqJQCezkKkSuQiw~8i3yj)9tl=A8k43J6k{ao17t*q5H-TB!UMs%bPD*O_V zwJk+6RQb(f3OzZ7imH~@d7VJMsYIx$hc>MBN7;=|oHYo_c3I9sHa)mj8?JZEUZZP= z44I{WS+&Wyl#-1$+0J|!8sp@&_LvikP^C3YI_O*~?O+yjW=*fo^~}b2t?mDveL?!H z6{b_mB-yHKYKUXWk!KBXSxdq=%2}APCa%A@{Qp0v{?~M6 zj;1SfG+mja>B<~USLSFsGRFzcEpN~~PH47wcTVo^bi0X~ZZ}cW?Ivov-9$~do2cn_ z6E)p#qNdwT)O5Rvnr=5y)9of|y4^%gx0|Txb`v$-Zlb2`CMvRL)9of|y4^%gx0|Tx zb`v$-Zlb2&9i47B(d63Bk;#j@J1^?)ys*1-O?T%7-JR!mcb?bXd2V;7+f6j-b`wpy z-9(daH__y1H&GhN+HRsM3Lotz%8|C4s2*v%iRwe!O((L=|UWRD&?wj_J>(6J@iqlccm5nGc(xsB&+a){*l?9C4yyN04(%WoaKhT`a< zW7kj|J#_3Eih4*1eR>T=OKaV{L(^+0rVdT7p_n=}y@q1y(DWLLsYBCiD5efguc5f% z(C+P%=`|Enho;w1OdXnDLosz|dJV6{W`70r{e!i^hrG4#C%ggd6S{qWeegTp=l92hFATowyahJIG?4RikW~b>y zzD56LM^l|`YZEPN+g2y1_Uv#SzYpZ+^SV%+qQi0Nk01@ykD=k^_w5` ziu|qr`ay4)-TIFoc(`=x&L6l(uQyovz%6}V_WtMiyyX3t`Mmi3mZ1+Wct6Y?ocF$~ zeV+3^e=U1(&-dNI=bra@-@;(|y;u2MeDB?T&cAoN&pW)w0?fgw@43|HZQgS?pC`ZP zrao`}?kD;jz1yFc8Ekv^={~o<+fxiqc-O;x9{;WbK5z7{lYI`}`7G1>&+oj%=QrNz zbq@W%d8Z|U{l9$26MTN<9ryA1rFY!k=jYyjtNBf#fBRb>@AIv1y|>Rdz4bJo*T3b(K41HmD}284E!JrFU-p(; z_`LSb-{bQ|Z@$>)3*LMepU->qO?*D{O^7BKF@jSBYmEK-4>tszix-mi>|xC=cU&@#pn2CGd{0)S^l!~ z!(X=I^RX{`zRxGU{MJ67_VRoAeCEp^<@33(hzq>%6?xbFOJ4B+pD%yKQ+>Yrl_Q_8 ze`R_Y-}K6{&$quae+lPZuey!T54`GZpOaTT+UKEH-`MAeUp?>hBd>m-&!2kr(|msX zHM2fH@tWN}Klz#m`~1{vuJQS6ug$Xc-+b*kKL6mgkMa50*B$5cPhWRupa1l_3k}N& zuY0=B`RnI=-u-%u7yIX4{}7+&U;jd%_j~>Ad|vSSbA4X)`p5db_zlPVy!;IdJ`cX( zBA*X=!!vwd@y46`e8d~~`h4^oAL{e5Z+wx@$G_=RpHF_%d3pFt2fozX_SwPf{y+5n zR}8+_N`hw%o;rBK;8ETSy5gOK7Yyz_IBT%an?dg~xZ~i|!71fN-RuAV?|<(IZ2QCi zi=S-!^kF`;?Y9r}pKZT&m@jSn^~3yX+piwtW7|G;h`(+7r9*sg+b0k4!)-sm&L_A1 z+&cf<_Ot7Jb=ybR`0cizTI0jpeqxP3Z~L(|zP;^-8-Bj+hZ=uhZrg{OJNo>-X2>Ed zC{%!`U{Qgif=C6F3N96BD(F-Is$f)sse)7mtO{Ng$SSB+fU96vfv1@Q{#72GS(SJ1Bkpaz2)7;2EH0iyO&2AXEcV8=PvOszIv;uo}#2V5>py(Bu(Y8Pa$2{h!UTC0VO(m+~ghX2X)K zqx-iv8}9-d$VB=bv?9U4|P4XVGngZv~82;a;*(}sOxWS*h4LQWuhDQP}f5n_E6VD z8}?AwL&tA)hxO2gJ=FEkjW_u%`Sp!9KeT1DL-GIrv+Dn~9^ce@d{gW3O|8c_wI1Kp zdVEvs@lCDAH?+wyk$2YYe-_&}1Q|s|ft;aXD9^ce@d{gW3O|8c_wI1Kp zdVKS^QkQLNJ-(^+_@>t5n_7==YCXQG_4uaNt5n_7==YCXQG_4uaN+wyk$2YYe-_&}1Q|s|ft;aXD9^ce@d{gW3 zO|8c_wI1KpdVEvs@lCDAH?+wyk$2YYe-_&}1Q|s|ft;aXD9^ce@d{gW3 zO|8c_cdXA>>+wyk$2YYe-_&}1Q|s|ft;aXD9^ce@d{gT2Tbf(fv)rm~PN|z)*3I_1 zIk|35s+(KX&CTm(u5M=QW>hybb#t@2*;Y4Ovx)!zC)NMEGH273Ih(G`*>q*jrYmzc z9hvil=E@s1&l8#}x;qc;?sU6}n{GF8)9og1y4}Q0x0|@RynD88H*wSLCT_aj#7(!G zxVgA{f^Ii))9og1y4}Q0x0|@>b`v+b`v+kl+;qE%n{GF8 z)9og1Zr?q@Y2BSuZ`j$|zqk57f#J*jpXooU_r~Feh7TJ2LvPREeS`CQ-|YRg_kZ54 z_hs9k4p6N7$iMOW&bDU%qZV*vQH725AbBx`KjmmyZED9Bnp(D@f~w-K44YMu`5S$f zAXsgw#;Tlbv101)4ylP|J?D7+Zta(z3zdc$fG zaG=C6^)g}-EiKOra0}SmNR>;nq?Du6jIx@%0dT$rOtzszU_+$*YDb1_an;D76#@0 zAE`p8dh7*=YP0z}N*5-*Ld8=ZU3K>fs30V!xdh#xF3&Zk_ ztVGfi;WZ{+E|NDf8fNc%^RQV#v$DQi&OAT+BY9_;^<4%g@89qeEia&RpZ>$z?!4Pm zzlDY9+7dhglTkX)BkAPumbR?8&D}7eywGIlzVZ4}d&@s;vAM-i&X9ap%EHx8& zSBMUgvLrpTouyvP-6DA(yv(YltVz#$=&UcY;AiQ~7>E(i`gm;tc>&0GJ^w$pB}-=I zJz4UTV_UM09y+!q>*%5Lk4atXA*I1%Te6NGI<_V2=%N3+y)yx~tg7z(J?B&vRfVq@ zUWrcu1p&)v3BIXbRS^fK03w4!)w`&GOaWvT5m6AWil9LpI&CLLjTH6HKKCYHz9g-7 zG$w6K+BU{$VvMnkQ9ErrCF#%Dier%U@4wf+x7Is%U!{}E_nA*iIrp5m?mffa`|Q2f z|NmcWpE~}8qmr!QuSO+VL(`}v%S<2?qmrzlX;hLmG(Ba^9dg1a=S-|@0eJB<<4vP6 z6kN-GH5x-PG>yhk3{9gk6lMYqSsZg4m_}nLhQAt(p%|J*VBbi$bD;##9I6!t4Hl+hT9Xqx3$qcIfGBsgp|hQdr+rk1Dkw;{~y@ncL} zYg5hyD!1SB|1FPFvP4$L{AA0cl&qQP8b&GEp=p$o9h$DnJe97+2}dc};jgY3|Ep0- z)_z4_GfK%0O_ya(NUp(os(+M{r6TzuZ}KQ5J2YLKKcRm0g7Kz{#+Ya{qZ(?v7N!fv z|7ui2J^a20E&t9-2lq)I-zKm^vMgho(^t_0V+gnCIek9o10tD+W=zhO=|OGSf50n0Ot|8fW_P_5W+{=G5NJ zslA(1dpD={Zcgpoob~l%_W3;P>qq;8BmIF_6V_f$SbH^L?bU>}R}x29Wyqd7~YQoy932Uz=ti77B_G-e~s|o7^{B^vVuwLyg ztNcOb4@!Sf_=Ao+Sbn8HxWga3!XJ1w;j&i~E_*fMvR4x>do|&*R}(IKHQ};X6E5HE zFY48V%U(^m?A3(JUQM`sgFk^+6E1r-;j&i~E_*fMvR4x>do|&*R}(H@>96C}gv&qY zEtmU)%k~|Z|BpOC{{Ln8|8X6#&erl*%99FP|Kmx;j^Y^B`TIcU^+R`XDO{QSr?23e z;C(6KyjFNZ5{?)jbvT}kk};BgATD#WoeZ7Iq!F`tN!5;6nKdi4>w6HdI2Ml?E>XHVrv2e5QyXDqPWKY$B)J9 zQWAE-5d63sE>36uTbwqu=KPu4k(`=Lqe^m3jzqk0Em5J=;oFsbO!-DQ6i$JfUP;2@ zB2eV{P<9A1SON;j|3{B8_TN&tG?mpCa7oExfj6wopTG@DWT8wQToqRtq(M$>%nYKO z`NS&7YmFI7$Z;F1vg58E8~^CSwbO{)C7e;`Mwuv2q|Uhp)+o{8Wr`WGL}Ct~=Skl?z1;kuV1S7<0N&eo8P7kfMxnU=5u4 z=hB(K#KR!bC%XvQR1oI#d$N;J#sYds(xMzJloOfzCCmq70D@6W2Y3y4z!s=O$x-a> z**dcnE>CUfixem?1MrhV9JD?$iOBHzc}Hj&3Xvh5EvN#GM_EhAW+$Kuc!Df_{7mhh z%ph8sixxe<-{=4JC?(5ucdPvWdX$ni)7Ghal#(5qMk(2$X_S&3nno$vp=p$o9hycd z*`aBak~P!fR6R<`4o#z!?9eny$qr3bX11m>basI~F&^~H8%e0*(ud~JMuZG3!f ze0*(ud~JMuZG3!fe0*(ud~JMuZG3!fe0*(ud~JMuZG3!fe0*(ud~JMuZG3!fe0*(u zd~JMuZG3!fe0*(ud~JMuZG3!fe0+V1J(2P8^+|SQe0*(ud~JMuZG3!fe0*(ud~JMu zZG3!fe0*(ud~JMuZG3!fe0*(ud~JMuZG3!fe0*(ud~JMuZG3!fe0*(ud~JMuZG3!f ze0*(ud~JMuZG3!fe0=>_dm`iG>!a+*`1soR_}cjR+W7d|`1soR_}cjR+W7d|`1soR z_}cjR+W7d|`1soR_}cjR+W7d|`1soR_&W0OtLlf@y&PyC>+NHmeXO;Q1MFjseXO>R zRrXQYM`<60eRSf-@+5{a*%8?P2?(to)ld#iqZ-Pg zX;ecwG>vK~ho(^t<UQJYcHBs%= zM738F)m}|hdo@w*)kL*d6V+Z#RC_g1?bSrJR}XZmtG!ylaP z4}R7koaPTs^#`Z;gOmNiN&djAiE6JVs=b=1_G+TqtBGo_CaS%fsP<~2+N+6buO_O! znyB__qS~v8YOf}$y_%@@YNFb!iE6JVs=b=1_G+TqtBGo_CaS%fsD8XJw@v=war+MT z`}m)uWHg@8@8&3(WXe%8$&{mHk|{^Y$V6Y5qhyjPN692pj*>~H93_)XIZ7s(a+Hir zKpr_tCYhd|@2&N#Gsm0G7;nmHDAKiZ8VZ@f8gd$nWXfqMk}0R5NT!^IBAId;ie$=Z zC}aZi$Z05&DW{=GrksW%nQ|J6WXfqMk}0R5kZED6&S@x;DW{=GrksW%nYN6nWv;a_ z-ZVeXG|~AI`oD!vaS_P>x#j&a|Ia<0g<@6l6--~sLBKnkLn0WtY4Q++T0oQ__Xw@P z{y}{acY$0Z{{pK9fdwN)loeGk`w~%Y7G$bEQ4*6%36tDw6rerK7qt!i(V|= z^FsmpZgZ%?wv&ef8zam@jHoriNX^4_NLK^E%Q6n2xCjGb9aw3KI{`umgJ*dNu7fxX z#8t^+xC<@wr5i&;w$#|l8q<^OwNgA_Evh)7uUY_;TLqO>G8`>Jfm)7YVYv!!L3w<5 z0Pz+|#7){3G-{-pLEr`e&X*M!JCm!LaewPJlj#vB0n$}#q!H4RQxralp_NuUO7Y^- zYEgv;nvN_HRKe9aKkKL<=!B{uE&I&uQe&%hOiym$SBMA! zty!#;c1BAedlJE#=8PYm1DEL?x1yY4vNJ^)!#b+Ryx{WQ; zv3YWW%tT6?4krPQk2nrm$@F+IA>y=z;Oq9Jm4ttyg#+Jnd!)}H%M!Pt^iu%o)Fe%N z%TiMQHU~t(a=h%63eoL z8hL`CP@qPZ8e9Bjdh$TtHl9PPv%#lOo=PJQS%E|loy=`YOe_whdq$+F@ly>%9nHB%OnHB%OnHB%OnHB%On#Y8umg=Ec?g=Ec? zg=Ec?g=Ec?g=Ec?g=8@Slw6zdt!27qyy@!krmTj_u9ekLVFD=0YN*VV)liu!tD!Pe zRzqc`oQ8@KZw|;Kr=d!woQ5iyavG{+%4w*QDW{=IrksXKCLoWThANqI8meT#p-uOUQJYcHBs%=M738F)m}|hdo@w*)kL*d6V+Z#RC_g1?bSrJ zR}*SK=4ul5Ho+;^b&|0jz73&zI<IKJ}wv^ z7mSY!#>WNY@s_@o~ZUxL|x-Fg`9A9~X>|3&zI<IKJ}wv^7mSY!#>WNY@s_@o~ZUxL|x- zFg`9A9~X>|3&zI<IKJ}wv^7mSY!#>WNY@s_@o~ZUxL|x-ZG2p9d|Vy*xK;J- zk)5k=vyYeC$II;FR{MCVecWOnFR_oC?c>Gvag%+#$Ubhgj~ndcdi%IeANza$A99q; z+_n?vXQo1ql1Zicz1+owW~l1Zi$&}Mj$uv6^avCZ#)j17SGUYT>$&}MjB~w;I zg|7i9dt0WKsTU zB*ltd1ohe3OeL&wY7Px2(Tm7j71N7$aZdS@0iB{m7I;X}jeuENx^*iURb0-O#LR^H zvO*fr4|oT#nwCJF-MX`RL^|&y_@UM$29yJ%LSKxomvew1>24%o22~;W6BH9@i7;iJ zfHh|UX8^YdqXq0DQWM!Ji~cPLlp}rMzwqDA#@3J9G4OM{+)Cvw^G>#mm#9!Uh;c6s*u#+6Vv{H?2(QpoUTS3(%#gcorC=fB%}dS^pc|k z2$FFfDf0}~pmN@r&b*O;W^g}nMZOIltpy5?SM)uYDiU%;&T0lMa7`rvwR0-s^T7l` z(m6AQOZ%m$!8K=8?c4VI_@AR>7&I0Zrb3RANv0enlT0~ECYf@SOfuytnPkdQGBPnh z#p-uO&xvNe{i-xc!obX%O5=5 zADrnA&hQ7P`vb2g3SLbVyqYL@HBs#p-uOZALPuzE~-^c$PB{NT|35L)d zC6i1!N+y|dl#EOap*cz>nR1j&GUX_l`57@@AxFtzLR=YgluR<^C>fdXlXH|zGUX_l zWZIeOt&?fTc++#nn{pZ|osde&X{eGZr=gOGp(dxHn%l0-3n8bWN~WBKN+t>_r=d!w zoQ6s!Za$}>l8LsF(@@F8G$f~?!nDA1fnMb_RLPXnP$g4NLzPT94OKGbG*roS za;BCs%>!(mG~V>Iai)o48vp;L$^S3kTAtMT^Uh1jtN;2!xzqox{_Sj@7af{Slg|SJ zz_Ujwg!`q4UR?F#@nUe?v@f3sXG{wvX?c4bE_{DP8E74lGbl2cm`q$wEV%4QJD!^y zrRU-g5dcgeDjB{=bwq5dQZ1pm!1csS#IM7ZBHmMBtEf|OE%75+ItrH;SB({`6iG=O zGfuE1AC$y;D~)b*VYBDf>iNzIYBi~q&)qD?ko2XmiB3u9^5uWM!>6Xt|CE~b(v2epmM}@+PxMcaz^0JY` z0AiryQgAS?sTM55|5g-l^o`Npu(%e_2=)S+0z%V`XWlf~l}HJcN8%X31j53BloT_L zl!b>!xq}c1+y`9?$Oq0Y<%z?M!wzNxVi6ycT91Lr6!KEK<0a4zlrfx9+9%3|Cm_!k z*N}t@a02ZbVZ$?ovu{_(I+cOEh%zCzUEjl(m;8tu1B^n|(`|O9Gw%fOKzPP!X%*i4^O939V4Dxinyig=l+o-DXER^A4I2k|oNG z$3y?570p;94~T>qWY8;=K)ee0`m|($CKQY!lR;*-uvT1*`jrrkhgNd5`KbT-iQ@kn z3fvXzvaeRo6<3oHLAL8Tq z5Ff{f_&7eq$MGRPZq=$rd>kL*;|^NYh>yc2K8_FZaeRo6<3oHLAL8Tq5Ff{f_&7eq z$MGRPjt}v1e29f;~L}R8sp;{@s_@o~ZUxL|x-Fg`9A9~X>|3&zI<fcU~H zTQjq@WP0g%(=FpoISu7}%qJgm8p>qKX(*E^r=d)yoQ5))avDmR@EUR&%4EuEC}m=j zpVLq#Q%*xE6Od<4LzzrD4P`RrG?bVGDCRVjIGbBAE>T5|&XqKcV zw1cE3w1cE3w1cE3w1c6VP-h#e33ZUvg!Z+hCbWa0nowW!YQkoyCX~gi37e!Qv=baM zC^r_*Yz`ijs16SD2OIpsggZD5c>UYnMNYG49+ZCV_r=d!woQ5iyavG{+%4w)%qLyM^FdiOyek4(uE){O_Fdo5KH!FLz$nIl8!~nCpBRz-wo7LxN#$K*R&Uf-r}; zArKnDZ^#S)dO#vj_V8Dtp%58>HGothJ^=nwzJ4&VMN*n6jXi1xDMtY2y3O?o(zqVr zY8%oJ0?SZaAh!Y3BYhd-A-)Y*!7q@ykiHDb1CS3F1c(7Ak`@N&1Gy0}4c{Qx3jM=^ zV9V8=ZgW#Q{Y?@gfnzNI(Ez?FUP>W#NGl{E(US6U6;;$9bhG=26f`e$q+|5ONGMyvRFL{4bg{e zSM?zZlFUejrS>*(GQ`OjDvlI9 zj)D_32VhG31(j8$5#I>Hh;9c}5Xl!o;{@IU$5FUIq%#x{nBAhHK54ZC#;X2OGQ`QN zl)n)R=%K(zR!<;Z~dJ4q^Riw#+2rkY| zfPk#;uqx}X(E||wTl_(BMdv*Ffs>1asuRk;>)hHA^!-r(b$f%*%GdL9k(HCCMVS$+ zh~$jrCy-82hqP*{lcJzDklF#hDs-4WMY<-ULV6qxKq?+UH2HB^!C=4)fFmqZs&1zdY)p^+9 z`F8Xy1o^nhHz`Bk_?AEM=5hB_GYv<<$7rq84bcIDz!F|b2NjcU zazERadV{#od+54g7$S-eKOvBq1vo(N5pYGsnb(k_K{`iW3Pq=FQK$4Xi@?y}yewBi zh_SjsTK$%#-XJdYbqK%ci)fQ-Q2dfIeYTztfX%B-C^($yfFIqP?WkLV!mb)-&j~=n*9Lq@UGO z6W>fGPiZnmKv2}Q7Ty&qkJpgCYq8t2@ZZgoZ=kyA@YD%OBnPuWg%f`)p&q>(bqu9I zPbZb9E(d3UP*1rrsST+L>4xbyC>X7{vSmxRXHnUkC-0^Sh&|%%)1|3o0?6qqc-N^R znw>Cuj*KqR7fac6H`Y^0kee?f!=s5{TEfj}c1V*`C+ z3|6O8RhCj(D?MMt<7xW52yxJX+fWxoS04qR45Hh+y|tSOmsW@f4IAkBDNBNTR0o@|LxE9KbsaM%gk^Kn)VYH znB%o5*`bMaVMhR)0{vvkKK)s@GL_R4=M7ue#M))l;gO z>X_=VYF+t2`H$rn%D*Zf79o8^7wo6Fa*YWH>J#pQF#)64Cw)BTw8&~kP0-QpjL z&li7De6V;=@$1E}7H=wkzPP1$VR1omUU5pXrFeXCc(I`fb#;XY%uO@7~ zny~R|!p5r!8?Pp8yqd7_YQn~=2^+5_YkrQH2WR^O zuO@7~ny~R|!p5r!8?Pp8yqd7_YQn~=2^+5_Y`mJV@oK`xs|g#gCTzT#u<>fb#;XaN zp_;Iw!Fn}elhlOPuDzPDNoqo~BsHNOBsHNOEckMpw*#}x?X&E6{I5mH&~-8Xg8Zyn2!d{WKD<4rFZW8%458p`3dxWkr)a$ph|*3wW8O`Nc$q4cJf zhH_}43|ksXZ)#~MhbHc@rJ?kumWFa@VnWfip_i%nMGfo?LCIPN+6j zM^%rk4y_KXR+T>}zg>R4{QL5Y<>$*!m!Bv5D%-OLyI<=*n`sC(E) z+`|@a4_l-?Y*F^GMcBg@T@PDiJ#10+utn6v7EKRZBt2|V^sq(H!xlXcTjV@!QS-1x z%)=Hf4_l->Y*F&CMaaVz9S>V%JZw?%utmhf_Hl8Ggok|;JZus0utmSa_UO1py~94@ z9kyt9*dpCwi*ko8!X38gcGx1@VT)>qEutN^Xm;2l*s#Nk;4{2&bn2N>2Vs<<22Ia zpguA^PGfqU#`HLi>2Vs<<20tnX{5)QT-BH!r!hTFbA|oU^f-;_aT?R(G^WRCF0rqe z9;Y!qPGfqUChBokH5b@do^Kz|vybQ6$NBcrwT~tH*l8a-?BhB1@of8emVG?aKF+g` zbM50CeM}Vhfd6gk6bqfd>Fg?36~7J+cpfVNZz_M4H^){0dUvPW+m--`_i9yH@Mi^a z3b_Ek0n!10V968|nV=4&T?2Cfpow@E;GdG-0aXGAgLrA_S+Hi1G~jUZn00%$66@y4 zcLI|D;3~3Lx!pkP1ZI-~FseksdO&bUxh8G^U`K1$U;sZt@(E}ItSDRvfi03rQo?PU zS?bwRtkaYK8MI9BlVC@XSP&bcSy2EZ6h-7K@J@i767uPHf)54q0?cn09E?@;1;8Q@ z8qd3JXU|q*-8A{z3WI!{~S)BXP)bbH%VtNUG0I56udeg*ub z5?EOn=`Ifd{7>>ekW$v=;qk!1gwhii%~Mk)T8)aPLqbT^pnzL};5&O;6Hxaaa9}Y` zgv4?d;l+Y^mGe;x5dlTgtbxvyP7ij9Dh11?=!w~-)q~v$r{l{sa*51$^cLfJkDL4* z_$WYOkuj7!Uj+;W7X`8A+=^^hd^QlRS~LxgDy6m2*ofvO5}7v(28jj^vPgUG_R z-=Fwj&rz}ho8c!H0767~_8cYKHaSXmg=uc8=P22>$x*UxlcQw!nSiynPxTxnyTY_E z)pL|=+vF(Ow#iYlZPS{4^RBkZQL-yc6x6CQzrs|FHY@3{h za)k+B!)YknCa0m?XTqDKc%6n4)7+xe5JC-kWT&CrXCe&=PT7t7s*-4hx#$`!2(q1O zZpfJCXBE8ET%R$?E06L2XLj~B|RMMOL;ihm+)|~FWuo_U$Vo&{t<5faJT;`xBp1DKjrox;r0)6 z`ww^f8{Ph-+dtIpAL8~8cKZjped!Db_bi#=U|%Z3!M;R>gMDcX2m6v34)&!m9PA(9 z_N6Zz{9W?G!M@amgMEn$2m8_%4)!H29PCS3nD!e93kUns6%O_#D;(_K?)GnU`!9F< zFLV31y8V~B{af7rONRTx{|;pS&#eC(vVTYYPt^W=rn8Gb5B_y~r=^+L2O$=jLNi}t zZUO}fyUA*d%$OjoN!bni2t$hpz_gKBFf$R&=n;|-HATW4CMS@;nxcvRN38%geri1P z^yGij_mnF|#5=QCWOi~eh;6O-u1Uri!NV%l9C=!i188c)Suw=?E zf|yC55)Co6?DkGhMe&Es#hC2Ex*~6YMwWAcu19&T5v9yYT?1v0bApQkyDgarEHjfp z&Bc@liOCoQE%Ru2a0;f|J1L#{15)|${mA@7l{2SCBg5Ia4Sf}_gY!t`48d}liZ11C+J|j7xLS%!-Hx@%9LM^MB;98>Byg9 zo{u-dOnPP!eqHRl)>+jeo{-vGxaX&)Gru2~gM{9q*tOxNVZ525Q>L7p*)tWZ$VmCnF)g=#Smkb7>ODE0d3y5qsUtNsTs_K;dnF{1`%`S8 z6ex-UMEXIQ;wd3|;`tRBiXM%Erftx4I3N7Fs+itYQ@$cbgAO>MUS!U>xLva?o zOEez156U7>0pP;oN68(NW`S1<|A_*jl+nE)Oi`|Toq{Uw_D)P?@jlcuQjwwc!FiS^ zOD1w^C6*hWteOp4DrpFCdMPn99lVZIn)3f>2c#t$Bj2R4R!m3PD9-`ISus+)8bU`=rPyAMmnfv5x_m-aKsohPq%z#I`N0+ zN#Z8xik=We5{(ueCG!Ci&T&>Ls_5cb-b3n7DUuap&4YmjA&BKhxlf7rG+mIUs@ppw zmBk-3h(uwPG<`~5z=TIqV1OZJ1|U<+jHIKRE`Xg3>Dlw z#Yw53+b;Qk`SDWk+*AO6#{DUvpPFG#!MMre5F`)w1;{1I9DfB5V^s>~Qbgu+PmCUv z8U>{RoDm-tEWhXfAXnYqIjI0XrY}osXHx(nbgbAS9V@?4ErO~_u}j3eav3ly;Yk&M zjtCV@LTD7HSIPm2)E1d#ot@77Q6$)4V~pQimv+JY48U141(fKj5sHq{S5f)`Y=M_G zKdRO92$!j@L;~cq^R3FJ)QYO+!``ENhFn#fTm2PAwrZkj>by!20~*}a=h+S zq3&%bChh`X4o)Hn@g+vGHqZIjbbwoNCGxec!6G?XiT1vcz7lx>sKP_|7@L)kVt4Q1Qp zG?Xh$vr|2%p=_I+hO%vP8p^iGX((5im_#p*DJV=^#+w$#nauxxVyF7G>RIJ?%6F8f zq1^k$Vq52bcJAyvapjP+)VnqILerDqjX79gOBg@s+%)nsjIp7=6TgAmi5i;TlzvRX zG>mu1&b1yB&M;qK)JC5kM;JUGhLM-1?(I8_J9KKy5#X`pjp7$UmElz5^)rHq{D6j0 z+ynswx*R!L={DIVs7J0UuBBFl!V$ukV(7mm-SW2;i~vT!O)K>(omPrln7<{3YsEX^IZDZ(vNxJ24F~{JW60hUz%c+u7pKh6l z!2QFER)5+U6^-lQfRWhz4smzg-XPZM8$>4%2O*YM z9w%-m%ULlH! zUmjRfKQ2gt2m;|3F@121iC};e>Ku>@!p|^RN%n23R#jIA5Mf@tp1&QS3_aY*>0PUQJ9wJVtGH?!tAf~rJ~YNi9K#Onb&%Y20Ui=j+Py3C^q)Dn8dB#Gju=0t~U3Mw3JN6+Hr zj+^`%^-7CjlC8)W`S~CK%wdVkQ?Lz418>0$NwoBK(&YHmES8Blk3}*f00M|-Fbifi z(f|Lk#{c^cU+p`5weRrNzQb4h4qxp#e6{EB)t6o>vm(!M+sAgMA5<2m8_|5B4Qb9_&k< zJlK~wd9W{S@?c-mb_%%4dFTetR3LfwyFoExf3w$SRU;`icRv5uIzzOb#6}$yr@M@UBi{J*I z4Lf)`{NRZ&geSleJ{FenFnGfCFoh4o6@CM@@XPRppMf#_GdROPf;Iddc*9?ZIeZ5= z!!N=f-c`PeD1w{I>){YDg+*L~M?4EA@u_f$bFhhzgHL=EjN*oJZCS!9ej8r#?_m}{ z54ZRU*u@X6oTvQc9aa6P0PIHvU_UAV`%wYdj|#wkQ~>s)0Zd>_-J)KPmwG zQ32SG3c!9;0QRE-upbqG{ip!!M+IO%DggUY0oacUzs(0y>_r7& zFDd|gQ32SC3cy}e0QRB+uoo48y{G`}MFn6_3c#v|0+1~NK(^@r*dqU9i~5f(;y<=% z|JWk^V~g^SEy6#x=>FIu`(umhk1e7SW+fRhB~vde$uLt^ zl3}Kml8m8vX&zT|r6gm8$w@N2w?-oOo|9y>O-_>0HeHwZ)^x&a$D6JhW5P3ZF%&DV zg~`QGv`sFCqHVfz{I#waZ*nmd{)FTj>A4t+w#mg%v`sFCVucAR=aT$w5DnRLF%AB;tb^aI=&|7z$$^8Fml<>Ct zH#*?Yl&7Gye?#Y0D(cZYxkhu!r7LKfyl!-~kUj!GB z*Ck>czkRDBs{sPEhz=+_ZVpJ~T(@7w({A2aO23NBgq$-vZos%e(|BHBm-t+`qqwp1 zCzXanh$cQe*ArCA)o@!uG(~KJ3=kH*4V?E5JM-j&5zC8V6ZI3I3>nL_xq4&t^a6^UR zDxU@38;-cVQibiKn}(ak_vP7vE98nQEeWNATZV@=)9n|jGzy4u+<$OkZiXq^V z7Z{LNbUcLwJb@=I-L=F7N-V-3@SkCj0W#$5YKEq6zZOmpdLjWDP^;GCo&6w;)sM0HX{MT7Q`$sPq+Mi ziENcin4o-#C{zG&2HXtT0ip%5Ai!B#o*XDeBo>efx(W~xq`Oc9Ko3HG;AiyTQtxHy z#NVU2Q&9ro08JGCkEmNO6F3^l1^^@=KUD7MPeiYAS4twyOT&9=uK*~E66v6JSd8)i z>yi4P{XeN#sG8y{FoEA>?XSNnf5qv4{_UpJ-F`~*uyF$@2knuk5}iTQ;?|WW2S`cG z9>qjkraF+O0Q6BfU~wo&NJoQE2aN}04AsTAc^@T5TI$iS97q~=dK=gzzD4`tr4SrAv(&dFA=4WV=C?F6lo*0@ zAgQG3AUliLAhkle2Pv1(bU-oD#qb|(3-FPqOYR;Tx)eAPh*QT~XS@BhfYio^E5{3$ z#s`Y8Ns0dGO=m_G>}!`CG{jggj6edAgB@DrL=AeAU7p*%)KBR@ zHXcN?rsJd0Q*!j(>L%#F>4oT-ghJ9c1D%nrMya9bn$(q2PRb7zAy9GxX&EcJFkbS7 zZr>JY+r04+^vax=O6R2^-47@%f*d9EiQNcY4&5z+Aqts&o}7wc9OBA=(lmVyHxxQg zLl4Y-EcIS3^O35DBrcILk1sA?qOGfhIR&-HV?awn zV@lCP-_7g5h|@nLo%s-yOk7s2iH6BAM=iroDn3PRNl-Jx0c{z;9eh@#EX6>DqpJct zrXNyXB$1-3!kI0rd9!aI63}t*e?0 z>uqQI;oiY)|ERf;?faV}*}f~hknL}UEo^(CWP4|QD%(A^zIo5`m2BU*{8YAY-}?%- zzqt45Y~Q-~D7OFMzFXM7`M#6co^l^c6>K79@D_TJ%auWfYZ>l&T;`sVR$ZwNQDy)m4`H$NVZX8RYl?)=sDIqZL;eiHld zSiXtvOO|yHw=6%J?MwH*80)9@Ud8s)dkU3D*4+3?r>N3i{Lzhe8z-mPq}?p?Fkz2n$_MQ;uJ zA8l@D|BoBp$sNse_{+zdGueM-gM?zk?>3YC<n`&MC7iwMoHML6V#kJ~dZ>{UTwpNMVTGd~%tq zZ+P7@*PZyQNU*VZ+Pz>gxY-?_q3z zWpBau<@a67_AU2y+5V^d&Sv|w_bu}M&)oL}_D{R-D7L5G_i(mr@9VH#v*&885AHdO z?PvF>Bv0DIHz&Tmhi^`NYtMmfAGnwDpZM;**RcJ{y*&G>m)y&D$~WA56c60lpYcEa zF_Nr>?Nj|Rk}R3VNU~%aBgv9!j3i5@F_J98r2AteSu%~0WXUu}k|om^NtR4wBv~?z zkz_4wo$4Q)_ts=OXuN5|c+;2|DxL6QV}7+b)z8LI0m@*?#!#6l8$)HLYz&o|4j6MA zTc-MJ#+z1;H)Ug}xE3eO#!#6l8$)HLYz!5qg{givhANtR*%&G_Wn-w!^olXhg#hIC z@uu6xm_W*2KF*}~|LF4O{Sg1diGKR;rzP+ZN?={z#V_@b9dc3Y`p3Ba$GZKa-TqN- z|1oa=(Qf}px9{SY`YwK{@8XyGE`F)+;+Og^eyQ)`m-;S#sqf;K`YwK{@8XyGE`F)+ z;+Og^eyQ)`m-;S#sqf;K`YwK{@8XyGE`F)+;+Og^eyQ)`m-_qSmnMogLYP0kfTw#4 z@prq~U4-vDyLcm6IUc3|S%r4{w!ru1jYr_iDp(m;8P7}ThT?Ce)?w`|V7Z9y;cEl) zD7pjf1S$zBbND*gn3N523UR|hQTTngZ;MlJ-gr2w9n>+>6Dysj5?|tf0~+FcN-={I z4?2a@%kO|t1WO?(R)C3?rotn{x#Rlsyt)3?txJ7doqBrXqwse)0ge;6CGIhvH-0*< zI~Wd8KOm73suHL#4JF8l%_-0is1U!zXO-K9GrxUXwbVZ{xzk7D$MP`vb5XCP zXN~|Dw~g@6~i$O$uPZ@_LFa|>eia}~a)1ZOlnu8aBWdrkqE70t? z5Um?nw%dP9^3oq8>92B;0{?+f5_U!lrRfQW z3F6I=9tnVruOrNg`k!^xM5p=^{{3&k@xKgD{Zx2-O$>he@24g3lT-pz{p0fUWY*;A zkBOm@X-o{2Ok-lGWEvAg#Y!3dF)>s!jftU>X-o{2Oh=A+F4q71GVwoio#H}``f&w- zQ#$u_=8CHLDyA=wR)2SwaU7dF-v^2Y;iO9e*rjV_;0BA7=u^QUO2Q&VFfp-U)S%>% zt7EuR;%Q{I41x;c;0wUJ>eS}DyNu-6-1(kBR(fCby^6kN^i@)D5KaC@cS{!y1wzLu zevpwD3Wy<{o>GG=aTYKqXe$|!mCOb(dA@j02YhYJzwWL?2X+2QLBWJn>i3M?OmaYw z5uOrDgd7-tfhXjEjua?2(q;7V2u&emVtRf$UtoBKcNjzli<#~&Q`~Oue3O*%^tl?I zKxLU?08t~y1gRAn2WLkSKqEo0DF#&=rd2Vn75OTxr66-)WUi*L*LkI6pB?i!`9F7e z8JV`Z^8f@I;60Onw1qwzQ})qih63vf>PtTL>|z8oe@F`-3W=9r1mLb83#n>0FJ>P86pmPP}Ej`FJ(kAc5dcc;g|+#J*?= zhJ~HGOir+=^B`;@HATNbKLjhqsYC|Dd5IvR-W6&NjRR#y`=ZZ)E~a#d2ZKyRp+M_b zxVRP;Kp(JUmx&3E>->QJfp<(aCR`P>OD2psB+NY})~5YI^K)J%iBuuiX9lVC0{lsL z&DWu(UPLD^MQKQ6Z;$4lI+vw#W6PZg> zrF8og466oEteTqBmh?9seYU&H!~mN+|E$meX4W)Dx(Z$qTDn$C;5z(WFDxZM1A(EV zrm0ujer#OKjuptS7faH0=D9S7IRN+$VEBIc2XMc0_v+ZNHx;X4%;<+=7Xfw2@FI>= z^XfP!#}VWi70Jn1Mmf+xc_V3lv`CKd8e)IU18JPv-rc<_y)dhg+N(ThJv5{k>%z;S zaSm67PLgIJQ9gqjmG`83pLkmUf%^X1b`PVNpmQZ5slc zpUL$RwG8J-6TuNtqaZ~a!x){5Vp$ZliZer#qvdD40!|0CE8PtDO&uy8LHACJRL%;0SLD5X z6VbE8V$y#zrt(@b8qz25y4r#%n~N7}IRxH6k-B^%syztu!P{aWMUWzW3hj@6pErl` zfp?Xcg0jVTXQUFRE+Gw51I2l6pXu&SE2b1z=|L%5f*ln_BY_CN;PG+HXq^mlk=ms~ z>8W{jDJeP&LSm#|;k{CH5K15@Yu*6<-rap=s^lx_RT%_nB9uL&I&%Vwopykhh;cu0wM44|*MNiNc^IAqX-G!0NdCX0epmzFx!YF6*;HJkp)@? z0G;AS#R^G5q|uY=)k+>hQyBS~V#VuI+*_sop=~QfhvAT2=AH~Cyb;tm4!)Ea)DK+x zZVRN@TwJdSRt(>v2ckuT8F4;($6lqPGS2U6Lx^}(QOlFxyP^ju1XrMGwUS66f%NWrzX_QRD z81LeQth@W#)aI_`wL+0b3_0~c1<~S}jxv5JJc{~4zCa&K<{Xt6vls4=Nj8JO;-yp? zymoZ-%#uLUc$X$R-{bv1z0=ua3PAGpU)VW4<^fvOxxTZxdJ<~@{m6gaJCoL~e2_}g zQ}7B=JIu{__vt?4T{G3EZWyd-Wt21DV{B%E#an>FjyOBTFVRy`jl5V|+G%EC>CO~$ zSbmo`g_@+X^Fm9T$2d*F(+qgi(BSX_N%0_=1sxK7v($C`ofs-Q2+i8~nP57-*jwky zL&$q%|Ca8uNyBtiFn$UuWR#(&Eq!G5h6C=^r&IqP+o35&Wi+Mim7%!xtG-c*~j9@RXW{ z^GylVaA*KkyLYDPeE9$!pc3>%{ShT3O&?Q8Zh{@21OH1>J%oa^ab9D3YRM^S6O0>- zF*F91C!ncjcC(Pu9Z2?v{I7dgno3k1CVWgn=nsV~Nw^8b$xzBW$)B0M)9)&%PO}vp zHr_ z6FrNv7SQ||jp==uDROd3gz1mE0?Gn6Qpo2VuR+rPmEYsBBnZ_V31OsHW?sd8GcRTU zkWh@`pmEVP>tZx@HCFVEjLLM>^qyRnSD%?N_b^c&-Z`MSvQzva5y0n_-!85sL-(l< zx%z+l#fMe`-Mf-2RjuJ&)=0vuCdXC%68#v{{D>^mP}tOaz| zkW4ShEQ{fpInCDYUFJ${u1b0?8W8nOg)?`QKS@u(JWZGk;~MS~uZuhr$wHZw&_Qb= z6a|WMGqrvn-2f6hMiDImh7{;W|697t7N?r7)@teoB+aB&qY+~+=mir8gx1V$)uC!0 z#|_At*SB!O)MwBt>7sf0XqZgL>HX+HSoP|z18mf*4qz_HZ({&1Ju99L&V+(=z8hBO#%#!+S}uqcCKg8r11=LLe_uU=nZ6!qQ#l08Ce_qa2<2DG#k;l_#WC3vpuU zfH@CmpkSDH()V!xjGW9uaE+quj@i0=T@;RTgLtU!UC9HeR?$iEwo@76e{hs25fBRc zFqL@C*N4=KQ_KV(;FWvU`;bx%>-$dqDTQ$nKT+Afz!jVtl^S(ke149iU}g# zCG%A9I<HS&xgBGnA}T;l7=>egC8bhiw886R1ed2o zYvs%|VEj@VGBhY|iGovNK?Jj~GPR?enK)8Dpr0b}n9WOc%pf3FjJ`s?NwXBY_9ZaJYTALcAdfxdlPd0&pIHSQfWUu=?cz#pRvi{So!Mzqnj; z|9>a#``^iJcJH?J0yeM4qZ2?LB?{Cq@(KJxh6GKK>HK+nh>xLWg{=zpQUnPjfbcRQ z3wR!YA3r}3cs!mFPYx(oG7@|fx&*!D%IY=Sz1x;=*t}Y=w-5$8AKpHuK)m0~7eqM; z@!L z!VFB#KJx%|ampjAR}V*mK8q7DItxXh4~XMG6k3GBz-{pCK&e5amhL`2-7?(+P9aks zIzL0g1+mk$flJVF;_lJa)2%S4WO@L&MK{Ak3+v*0bkBUMc!U_>q)imRh5l!6r&uET z{^7;%bsnfLW}>n8$LH1R-jmioU9(oBmS$>9#F*3o0nl5@Q^%(UNWixj2(I)gyhRF& zqwes*DwoYl7x3npNPv$w~rG|=dDpd{jflIMn#qn z#wQmF&M?HAh+_>WMlJBxfm}pdhZeMD`_erLQCL%m=cF;v6rmCLJ||;($F1SaGqDHB z#fyWy;zreyX)%g6WSk^YMh8r%@fOu&=o=QxKi;=iard4y*IctoV339n#xPzY4X#_b zRgJfl6c-W=AvYHHm4Sx7AFh<)oi|V`Tky&2!j&i&hK0GgrF#4t`>ZL2J?dq}^<^Mu zP$xo$*Me5dKqzOHc|7-pf6R&Hx{FHVRCH0GFE{`UqIlvI4^!{i>V5yZg+}g4p2nI3 zxBzv;8!pU3QvzY8cw&+JqUTn7qjO*?&&w}Bk^ahnYl@Ov6|=-_fT=fyvoP1aCpms= z)@W1*5@0IMvs1tLLSP}Z9WZkceX5;m5hx>6ommBwC^`RX@1S`+E^Uv~(xz#7^CCom J?f$j@{vUgqzrFwf delta 47455 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 diff --git a/tester/main-db-tester.cpp b/tester/main-db-tester.cpp index 70b7a2e79..0cf5f0575 100644 --- a/tester/main-db-tester.cpp +++ b/tester/main-db-tester.cpp @@ -45,7 +45,7 @@ public: MainDbProvider () { mCoreManager = linphone_core_manager_new("marie_rc"); mMainDb = new MainDb(mCoreManager->lc->cppCore->getSharedFromThis()); - BC_ASSERT_TRUE(mMainDb->connect(MainDb::Sqlite3, getDatabasePath())); + mMainDb->connect(MainDb::Sqlite3, getDatabasePath()); } ~MainDbProvider () { @@ -66,6 +66,7 @@ private: static void open_database () { MainDbProvider provider; + BC_ASSERT_TRUE(provider.getMainDb().isConnected()); } static void get_events_count () { From f1f84e7c60d27d7870b616661c52787f5c0e5006 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 9 Nov 2017 12:59:29 +0100 Subject: [PATCH 0753/2215] Changes & improvements for FileTransfer --- src/chat/chat-message/chat-message.cpp | 13 ++-- .../file-transfer-chat-message-modifier.cpp | 67 ++++++++++++++++++- src/content/file-transfer-content.cpp | 17 +++++ src/content/file-transfer-content.h | 3 + 4 files changed, 89 insertions(+), 11 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index c3a520072..7b80dd35c 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -457,17 +457,12 @@ LinphoneReason ChatMessagePrivate::receive () { MultipartChatMessageModifier mcmm; mcmm.decode(q->getSharedFromThis(), errorCode); + // This will check if internal content is FileTransfer and make the appropriate changes + fileTransferChatMessageModifier.decode(q->getSharedFromThis(), errorCode); + if (contents.size() == 0) { // All previous modifiers only altered the internal content, let's fill the content list - // But first check if content type is file transfer - if (internalContent.getContentType() == ContentType::FileTransfer) { - FileTransferContent *content = new FileTransferContent(); - content->setContentType(internalContent.getContentType()); - content->setBody(internalContent.getBody()); - contents.push_back(content); - } else { - contents.push_back(&internalContent); - } + contents.push_back(&internalContent); } // --------------------------------------- diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.cpp b/src/chat/modifier/file-transfer-chat-message-modifier.cpp index e167a7a7e..38f01d55e 100644 --- a/src/chat/modifier/file-transfer-chat-message-modifier.cpp +++ b/src/chat/modifier/file-transfer-chat-message-modifier.cpp @@ -505,7 +505,71 @@ void FileTransferChatMessageModifier::fileUploadEndBackgroundTask () { // ---------------------------------------------------------- +static void fillFileTransferContentInformationsFromVndGsmaRcsFtHttpXml(FileTransferContent *fileTransferContent) { + xmlChar *file_url = nullptr; + xmlDocPtr xmlMessageBody; + xmlNodePtr cur; + /* parse the msg body to get all informations from it */ + xmlMessageBody = xmlParseDoc((const xmlChar *)fileTransferContent->getBodyAsString().c_str()); + + cur = xmlDocGetRootElement(xmlMessageBody); + if (cur != nullptr) { + cur = cur->xmlChildrenNode; + while (cur != nullptr) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { + /* we found a file info node, check if it has a type="file" attribute */ + xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); + if (!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for */ + cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */ + while (cur != nullptr) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) { + xmlChar *filename = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); + fileTransferContent->setFileName((char *)filename); + + xmlFree(filename); + } + if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) { + file_url = xmlGetProp(cur, (const xmlChar *)"url"); + } + + cur = cur->next; + } + xmlFree(typeAttribute); + break; + } + xmlFree(typeAttribute); + } + cur = cur->next; + } + } + xmlFreeDoc(xmlMessageBody); + + fileTransferContent->setFileUrl((const char *)file_url); // Set file url in the file transfer content for the download + + xmlFree(file_url); +} + ChatMessageModifier::Result FileTransferChatMessageModifier::decode (const shared_ptr &message, int &errorCode) { + chatMessage = message; + + Content internalContent = chatMessage->getInternalContent(); + if (internalContent.getContentType() == ContentType::FileTransfer) { + FileTransferContent *fileTransferContent = new FileTransferContent(); + fileTransferContent->setContentType(internalContent.getContentType()); + fileTransferContent->setBody(internalContent.getBody()); + fillFileTransferContentInformationsFromVndGsmaRcsFtHttpXml(fileTransferContent); + chatMessage->addContent(fileTransferContent); + return ChatMessageModifier::Result::Done; + } else { + for (Content *content : chatMessage->getContents()) { + if (content->getContentType() == ContentType::FileTransfer) { + FileTransferContent *fileTransferContent = (FileTransferContent *)content; + fillFileTransferContentInformationsFromVndGsmaRcsFtHttpXml(fileTransferContent); + } + } + return ChatMessageModifier::Result::Done; + } + return ChatMessageModifier::Result::Skipped; } @@ -539,6 +603,7 @@ static void createFileTransferInformationsFromVndGsmaRcsFtHttpXml (FileTransferC if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) { xmlChar *filename = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); fileContent->setFileName((char *)filename); + xmlFree(filename); } if (!xmlStrcmp(cur->name, (const xmlChar *)"content-type")) { @@ -589,8 +654,6 @@ static void createFileTransferInformationsFromVndGsmaRcsFtHttpXml (FileTransferC xmlFreeDoc(xmlMessageBody); fileContent->setFilePath(fileTransferContent->getFilePath()); // Copy file path from file transfer content to file content for file body handler - fileTransferContent->setFileUrl((const char *)file_url); // Set file url in the file transfer content for the download - // Link the FileContent to the FileTransferContent fileTransferContent->setFileContent(fileContent); diff --git a/src/content/file-transfer-content.cpp b/src/content/file-transfer-content.cpp index a5583ad58..9c851177b 100644 --- a/src/content/file-transfer-content.cpp +++ b/src/content/file-transfer-content.cpp @@ -29,6 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class FileTransferContentPrivate : public ContentPrivate { public: + string fileName; string fileUrl; string filePath; FileContent *fileContent = nullptr; @@ -42,6 +43,7 @@ FileTransferContent::FileTransferContent() : Content(*new FileTransferContentPri FileTransferContent::FileTransferContent (const FileTransferContent &src) : Content(*new FileTransferContentPrivate) { L_D(); + d->fileName = src.getFileName(); d->fileUrl = src.getFileUrl(); d->filePath = src.getFilePath(); d->fileContent = src.getFileContent(); @@ -49,6 +51,7 @@ FileTransferContent::FileTransferContent (const FileTransferContent &src) : Cont FileTransferContent::FileTransferContent (FileTransferContent &&src) : Content(*new FileTransferContentPrivate) { L_D(); + d->fileName = move(src.getPrivate()->fileName); d->fileUrl = move(src.getPrivate()->fileUrl); d->filePath = move(src.getPrivate()->filePath); d->fileContent = move(src.getPrivate()->fileContent); @@ -58,6 +61,7 @@ FileTransferContent &FileTransferContent::operator= (const FileTransferContent & L_D(); if (this != &src) { Content::operator=(src); + d->fileName = src.getFileName(); d->fileUrl = src.getFileUrl(); d->filePath = src.getFilePath(); d->fileContent = src.getFileContent(); @@ -69,6 +73,7 @@ FileTransferContent &FileTransferContent::operator= (const FileTransferContent & FileTransferContent &FileTransferContent::operator= (FileTransferContent &&src) { L_D(); Content::operator=(move(src)); + d->fileName = move(src.getPrivate()->fileName); d->fileUrl = move(src.getPrivate()->fileUrl); d->filePath = move(src.getPrivate()->filePath); d->fileContent = move(src.getPrivate()->fileContent); @@ -78,10 +83,21 @@ FileTransferContent &FileTransferContent::operator= (FileTransferContent &&src) bool FileTransferContent::operator== (const FileTransferContent &content) const { L_D(); return Content::operator==(content) && + d->fileName == content.getFileName() && d->fileUrl == content.getFileUrl() && d->filePath == content.getFilePath(); } +void FileTransferContent::setFileName(const string &name) { + L_D(); + d->fileName = name; +} + +const string& FileTransferContent::getFileName() const { + L_D(); + return d->fileName; +} + void FileTransferContent::setFileUrl(const string &url) { L_D(); d->fileUrl = url; @@ -117,6 +133,7 @@ LinphoneContent * FileTransferContent::toLinphoneContent() const { content = linphone_core_create_content(NULL); linphone_content_set_type(content, getContentType().getType().c_str()); linphone_content_set_subtype(content, getContentType().getSubType().c_str()); + linphone_content_set_name(content, getFileName().c_str()); return content; } diff --git a/src/content/file-transfer-content.h b/src/content/file-transfer-content.h index c2965bb29..09615ca8b 100644 --- a/src/content/file-transfer-content.h +++ b/src/content/file-transfer-content.h @@ -39,6 +39,9 @@ public: FileTransferContent &operator= (FileTransferContent &&src); bool operator== (const FileTransferContent &content) const; + void setFileName(const std::string &name); + const std::string& getFileName() const; + void setFileUrl(const std::string &url); const std::string& getFileUrl() const; From 7018a708c318e29a5fea288cb024ece801f79253 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 9 Nov 2017 13:09:28 +0100 Subject: [PATCH 0754/2215] Fixed old C API for file transfer --- src/chat/chat-message/chat-message.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 7b80dd35c..3fe4c2831 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -286,6 +286,12 @@ LinphoneContent *ChatMessagePrivate::getFileTransferInformation () const { if (hasFileTransferContent()) { return getFileTransferContent()->toLinphoneContent(); } + for (const Content *c : contents) { + if (c->getContentType().isFile()) { + FileContent *fileContent = (FileContent *)c; + return fileContent->toLinphoneContent(); + } + } return NULL; } From 43f0d863693911f6c73b614077ddd16504013d8f Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 9 Nov 2017 14:42:16 +0100 Subject: [PATCH 0755/2215] set use_cpim default value depending on using group chat --- src/chat/chat-message/chat-message.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 3fe4c2831..b1fcd5d47 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -610,7 +610,8 @@ void ChatMessagePrivate::send () { if ((currentSendStep &ChatMessagePrivate::Step::Cpim) == ChatMessagePrivate::Step::Cpim) { lInfo() << "Cpim step already done, skipping"; } else { - if (lp_config_get_int(core->getCCore()->config, "sip", "use_cpim", 0) == 1) { + int defaultValue = !!lp_config_get_string(core->getCCore()->config, "misc", "conference_factory_uri", nullptr); + if (lp_config_get_int(core->getCCore()->config, "sip", "use_cpim", defaultValue) == 1) { CpimChatMessageModifier ccmm; ccmm.encode(q->getSharedFromThis(), errorCode); } From dc00b58e983967360644fd74265e7be008960449 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 9 Nov 2017 14:48:11 +0100 Subject: [PATCH 0756/2215] feat(MainDb): log durations --- src/db/main-db.cpp | 34 ++++++++++++++++++++++++++++++++++ src/logger/logger.cpp | 37 ++++++++++++++++++++++++++++++++++--- src/logger/logger.h | 22 +++++++++++++++++----- tester/main-db-tester.cpp | 4 ++-- 4 files changed, 87 insertions(+), 10 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 06a90f184..44fd21390 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -919,6 +919,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), buildSqlEventFilter({ ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter }, mask); int count = 0; + DurationLogger durationLogger( + "Get events count with mask=" + Utils::toString(static_cast(mask)) + "." + ); + L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); @@ -951,6 +955,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), list> events; + DurationLogger durationLogger( + "Get conference notified events of: `" + peerAddress + + "` (lastNotifyId=" + Utils::toString(lastNotifyId) + ")." + ); + L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); @@ -984,6 +993,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), int count = 0; + DurationLogger durationLogger("Get chat messages count of: `" + peerAddress + "`."); + L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); @@ -1027,6 +1038,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), query += " direction = " + Utils::toString(static_cast(ChatMessage::Direction::Incoming)) + + " AND state <> " + Utils::toString(static_cast(ChatMessage::State::Displayed)); + DurationLogger durationLogger("Get unread chat messages count of: `" + peerAddress + "`."); + L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); @@ -1063,6 +1076,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), ") AND"; query += " direction = " + Utils::toString(static_cast(ChatMessage::Direction::Incoming)); + DurationLogger durationLogger("Mark chat messages as read of: `" + peerAddress + "`."); + L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); @@ -1076,6 +1091,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } list> MainDb::getUnreadChatMessages (const std::string &peerAddress) const { + DurationLogger durationLogger("Get unread chat messages: `" + peerAddress + "`."); + // TODO. return list>(); } @@ -1126,6 +1143,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), if (begin > 0) query += " OFFSET " + Utils::toString(begin); + DurationLogger durationLogger( + "Get history range of: `" + peerAddress + + "` (begin=" + Utils::toString(begin) + ", end=" + Utils::toString(end) + ")." + ); + L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); @@ -1171,6 +1193,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter }, mask); + DurationLogger durationLogger( + "Clean history of: `" + peerAddress + "` (mask=" + Utils::toString(static_cast(mask)) + ")." + ); + L_BEGIN_LOG_EXCEPTION d->invalidEventsFromQuery(query, peerAddress); @@ -1200,6 +1226,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), list> chatRooms; + DurationLogger durationLogger("Get chat rooms."); + L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); @@ -1254,6 +1282,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return; } + DurationLogger durationLogger( + "Insert chat room: `" + peerAddress + "` (capabilities=" + Utils::toString(capabilities) + ")." + ); + L_BEGIN_LOG_EXCEPTION soci::transaction tr(*d->dbSession.getBackendSession()); @@ -1277,6 +1309,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return; } + DurationLogger durationLogger("Delete chat room: `" + peerAddress + "`."); + L_BEGIN_LOG_EXCEPTION d->invalidEventsFromQuery( diff --git a/src/logger/logger.cpp b/src/logger/logger.cpp index 78ccc1ae6..68e718b7e 100644 --- a/src/logger/logger.cpp +++ b/src/logger/logger.cpp @@ -17,9 +17,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include +#include + #include "linphone/core.h" -#include "object/object-p.h" +#include "object/base-object-p.h" #include "logger.h" @@ -29,7 +32,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -class LoggerPrivate : public ObjectPrivate { +class LoggerPrivate : public BaseObjectPrivate { public: Logger::Level level; ostringstream os; @@ -37,7 +40,7 @@ public: // ----------------------------------------------------------------------------- -Logger::Logger (Level level) : Object(*new LoggerPrivate) { +Logger::Logger (Level level) : BaseObject(*new LoggerPrivate) { L_D(); d->level = level; } @@ -73,4 +76,32 @@ ostringstream &Logger::getOutput () { return d->os; } +// ----------------------------------------------------------------------------- + +class DurationLoggerPrivate : public BaseObjectPrivate { +public: + unique_ptr logger; + + chrono::high_resolution_clock::time_point start; +}; + +// ----------------------------------------------------------------------------- + +DurationLogger::DurationLogger (const string &label, Logger::Level level) : BaseObject(*new DurationLoggerPrivate) { + L_D(); + + d->logger.reset(new Logger(level)); + d->logger->getOutput() << "Duration of [" + label + "]: "; + d->start = chrono::high_resolution_clock::now(); + + Logger(level).getOutput() << "Start measurement of [" + label + "]."; +} + +DurationLogger::~DurationLogger () { + L_D(); + + chrono::high_resolution_clock::time_point end = chrono::high_resolution_clock::now(); + d->logger->getOutput() << chrono::duration_cast(end - d->start).count() << "ms."; +} + LINPHONE_END_NAMESPACE diff --git a/src/logger/logger.h b/src/logger/logger.h index e968e5794..032086556 100644 --- a/src/logger/logger.h +++ b/src/logger/logger.h @@ -22,7 +22,7 @@ #include -#include "object/object.h" +#include "object/base-object.h" // ============================================================================= @@ -30,7 +30,7 @@ LINPHONE_BEGIN_NAMESPACE class LoggerPrivate; -class LINPHONE_PUBLIC Logger : public Object { +class LINPHONE_PUBLIC Logger : public BaseObject { public: enum Level { Debug, @@ -50,6 +50,18 @@ private: L_DISABLE_COPY(Logger); }; +class DurationLoggerPrivate; + +class DurationLogger : public BaseObject { +public: + DurationLogger (const std::string &label, Logger::Level level = Logger::Info); + ~DurationLogger (); + +private: + L_DECLARE_PRIVATE(DurationLogger); + L_DISABLE_COPY(DurationLogger); +}; + LINPHONE_END_NAMESPACE #define lDebug() LinphonePrivate::Logger(LinphonePrivate::Logger::Debug).getOutput() @@ -61,8 +73,8 @@ LINPHONE_END_NAMESPACE #define L_BEGIN_LOG_EXCEPTION try { #define L_END_LOG_EXCEPTION \ -} catch (const exception &e) { \ - lWarning() << "Error: " << e.what(); \ -} + } catch (const exception &e) { \ + lWarning() << "Error: " << e.what(); \ + } #endif // ifndef _LOGGER_H_ diff --git a/tester/main-db-tester.cpp b/tester/main-db-tester.cpp index 0cf5f0575..93a8649b6 100644 --- a/tester/main-db-tester.cpp +++ b/tester/main-db-tester.cpp @@ -75,14 +75,14 @@ static void get_events_count () { BC_ASSERT_EQUAL(mainDb.getEventsCount(), 4994, int, "%d"); BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceCallFilter), 0, int, "%d"); BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceInfoFilter), 18, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceChatMessageFilter), 4976, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceChatMessageFilter), 5157, int, "%d"); BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::NoFilter), 4994, int, "%d"); } static void get_messages_count () { MainDbProvider provider; const MainDb &mainDb = provider.getMainDb(); - BC_ASSERT_EQUAL(mainDb.getChatMessagesCount(), 4976, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getChatMessagesCount(), 5157, int, "%d"); BC_ASSERT_EQUAL(mainDb.getChatMessagesCount("sip:test-39@sip.linphone.org"), 3, int, "%d"); } From 9f2db02565e9d4deb7fcccb859d3f0d3912daa87 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 9 Nov 2017 15:42:09 +0100 Subject: [PATCH 0757/2215] fix(MainDb): fetch correctly chat messages (no contents), no all chat messages for one message!!! --- src/chat/chat-message/chat-message-p.h | 10 +++++----- src/chat/chat-message/chat-message.cpp | 5 ++++- src/db/main-db.cpp | 11 +++++------ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index f512f5abc..10f572bca 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -61,7 +61,7 @@ public: void setDirection (ChatMessage::Direction dir); - void setState(ChatMessage::State state); + void setState(ChatMessage::State state, bool force = false); void setTime(time_t time); @@ -100,16 +100,16 @@ public: void setAppdata (const std::string &appData); const std::string &getExternalBodyUrl () const; - + bool hasTextContent() const; const Content* getTextContent() const; - + bool hasFileTransferContent() const; const Content* getFileTransferContent() const; LinphoneContent *getFileTransferInformation() const; void setFileTransferInformation(const LinphoneContent *content); - + int downloadFile (); void sendImdn(Imdn::Type imdnType, LinphoneReason reason); @@ -148,7 +148,7 @@ private: std::string cText; // ----------------------------------------------------------------------------- - + std::string createImdnXml(Imdn::Type imdnType, LinphoneReason reason); L_DECLARE_PUBLIC(ChatMessage); diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index b1fcd5d47..2ea06ec53 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -75,9 +75,12 @@ void ChatMessagePrivate::setIsReadOnly (bool readOnly) { isReadOnly = readOnly; } -void ChatMessagePrivate::setState (ChatMessage::State s) { +void ChatMessagePrivate::setState (ChatMessage::State s, bool force) { L_Q(); + if (force) + state = s; + if (s == state || !q->getChatRoom()) return; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 44fd21390..89b2a475d 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -300,18 +300,17 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "SELECT local_sip_address.value, remote_sip_address.value, imdn_message_id, state, direction, is_secured" " FROM event, conference_chat_message_event, sip_address AS local_sip_address," " sip_address AS remote_sip_address" - " WHERE event_id = event.id" + " WHERE event_id = :eventId" + " AND event_id = event.id" " AND local_sip_address_id = local_sip_address.id" - " AND remote_sip_address_id = remote_sip_address.id" - " AND remote_sip_address.value = :peerAddress", soci::into(localSipAddress), soci::into(remoteSipAddress), - soci::into(imdnMessageId), soci::into(state), soci::into(direction), soci::into(isSecured), - soci::use(peerAddress); + " AND remote_sip_address_id = remote_sip_address.id", soci::into(localSipAddress), soci::into(remoteSipAddress), + soci::into(imdnMessageId), soci::into(state), soci::into(direction), soci::into(isSecured), soci::use(eventId); // TODO: Create me. // TODO: Use cache, do not fetch the same message twice. shared_ptr chatMessage = make_shared(chatRoom); - chatMessage->getPrivate()->setState(static_cast(state)); + chatMessage->getPrivate()->setState(static_cast(state), true); chatMessage->getPrivate()->setDirection(static_cast(direction)); chatMessage->setIsSecured(static_cast(isSecured)); From 88c9e1e59388da9d121892f9e94d390e984abc2e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 9 Nov 2017 16:00:50 +0100 Subject: [PATCH 0758/2215] Use the CallSessionParams to add parameters to the contact address. This fixes the GRUU address in the contact of an INVITE. --- src/chat/chat-room/client-group-chat-room.cpp | 5 +--- src/conference/params/call-session-params-p.h | 5 ++++ src/conference/params/call-session-params.cpp | 25 +++++++++++++++++++ src/conference/params/call-session-params.h | 4 +++ src/conference/session/call-session.cpp | 8 ++++-- 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 3422a19b7..75e4eb03e 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -59,16 +59,13 @@ shared_ptr ClientGroupChatRoomPrivate::createSession () { CallSessionParams csp; csp.addCustomHeader("Require", "recipient-list-invite"); + csp.addCustomContactParameter("text"); shared_ptr focus = qConference->getPrivate()->focus; shared_ptr session = focus->getPrivate()->createSession(*q, &csp, false, q); const Address &myAddress = q->getMe()->getAddress(); session->configure(LinphoneCallOutgoing, nullptr, nullptr, myAddress, focus->getContactAddress()); session->initiateOutgoing(); - - Address addr = myAddress; - addr.setParam("text"); - session->getPrivate()->getOp()->set_contact_address(addr.getPrivate()->getInternalAddress()); return session; } diff --git a/src/conference/params/call-session-params-p.h b/src/conference/params/call-session-params-p.h index e56e0bb26..23e3eb2ed 100644 --- a/src/conference/params/call-session-params-p.h +++ b/src/conference/params/call-session-params-p.h @@ -20,6 +20,8 @@ #ifndef _CALL_SESSION_PARAMS_P_H_ #define _CALL_SESSION_PARAMS_P_H_ +#include + #include "object/clonable-object-p.h" #include "call-session-params.h" @@ -48,6 +50,8 @@ public: SalCustomHeader * getCustomHeaders () const; void setCustomHeaders (const SalCustomHeader *ch); + const std::unordered_map &getCustomContactParameters () const { return customContactParameters; } + LinphoneCall *getReferer () const { return referer; } void setReferer (LinphoneCall *call) { referer = call; } @@ -61,6 +65,7 @@ private: bool internalCallUpdate = false; bool noUserConsent = false; /* When set to true an UPDATE request will be used instead of reINVITE */ SalCustomHeader *customHeaders = nullptr; + std::unordered_map customContactParameters; LinphoneCall *referer = nullptr; /* In case call creation is consecutive to an incoming transfer, this points to the original call */ L_DECLARE_PUBLIC(CallSessionParams); diff --git a/src/conference/params/call-session-params.cpp b/src/conference/params/call-session-params.cpp index 463e490d2..828d5a50d 100644 --- a/src/conference/params/call-session-params.cpp +++ b/src/conference/params/call-session-params.cpp @@ -54,6 +54,7 @@ void CallSessionParamsPrivate::clone (const CallSessionParamsPrivate &src, CallS /* The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient. */ if (src.customHeaders) dst.customHeaders = sal_custom_header_clone(src.customHeaders); + dst.customContactParameters = src.customContactParameters; dst.referer = src.referer; } @@ -137,4 +138,28 @@ const char * CallSessionParams::getCustomHeader (const string &headerName) const return sal_custom_header_find(d->customHeaders, headerName.c_str()); } +// ----------------------------------------------------------------------------- + +void CallSessionParams::addCustomContactParameter (const std::string ¶mName, const std::string ¶mValue) { + L_D(); + auto it = d->customContactParameters.find(paramName); + if (it != d->customContactParameters.end()) + d->customContactParameters.erase(it); + pair param(paramName, paramValue); + d->customContactParameters.insert(param); +} + +void CallSessionParams::clearCustomContactParameters () { + L_D(); + d->customContactParameters.clear(); +} + +std::string CallSessionParams::getCustomContactParameter (const std::string ¶mName) const { + L_D(); + auto it = d->customContactParameters.find(paramName); + if (it == d->customContactParameters.end()) + return ""; + return it->second; +} + LINPHONE_END_NAMESPACE diff --git a/src/conference/params/call-session-params.h b/src/conference/params/call-session-params.h index 70ed155aa..1d152308f 100644 --- a/src/conference/params/call-session-params.h +++ b/src/conference/params/call-session-params.h @@ -56,6 +56,10 @@ public: void clearCustomHeaders (); const char * getCustomHeader (const std::string &headerName) const; + void addCustomContactParameter (const std::string ¶mName, const std::string ¶mValue = ""); + void clearCustomContactParameters (); + std::string getCustomContactParameter (const std::string ¶mName) const; + protected: explicit CallSessionParams (CallSessionParamsPrivate &p); diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index de2e583ee..ccb20d225 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -600,9 +600,13 @@ void CallSessionPrivate::updateCurrentParams () const {} // ----------------------------------------------------------------------------- void CallSessionPrivate::setContactOp () { + L_Q(); SalAddress *salAddress = nullptr; LinphoneAddress *contact = getFixedContact(); if (contact) { + auto contactParams = q->getParams()->getPrivate()->getCustomContactParameters(); + for (auto it = contactParams.begin(); it != contactParams.end(); it++) + linphone_address_set_param(contact, it->first.c_str(), it->second.empty() ? nullptr : it->second.c_str()); salAddress = const_cast(L_GET_PRIVATE_FROM_C_OBJECT(contact)->getInternalAddress()); op->set_contact_address(salAddress); linphone_address_unref(contact); @@ -652,10 +656,10 @@ LinphoneAddress * CallSessionPrivate::getFixedContact () const { char *addr = sal_address_as_string(pingOp->get_contact_address()); result = linphone_address_new(addr); ms_free(addr); - } else if (destProxy && destProxy->op && _linphone_proxy_config_get_contact_without_params(destProxy)) { + } else if (destProxy && destProxy->op && linphone_proxy_config_get_contact(destProxy)) { /* If using a proxy, use the contact address as guessed with the REGISTERs */ lInfo() << "Contact has been fixed using proxy"; - result = linphone_address_clone(_linphone_proxy_config_get_contact_without_params(destProxy)); + result = linphone_address_clone(linphone_proxy_config_get_contact(destProxy)); } else { result = linphone_core_get_primary_contact_parsed(core); if (result) { From fd1084b8755559f2d6f1b59be07fb2dd7bce94ba Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 9 Nov 2017 16:46:14 +0100 Subject: [PATCH 0759/2215] Free the contents upon ChatMessage destruction --- src/chat/chat-message/chat-message.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 2ea06ec53..43af1c22e 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -53,6 +53,9 @@ using namespace std; ChatMessagePrivate::ChatMessagePrivate () {} ChatMessagePrivate::~ChatMessagePrivate () { + for (Content *content : contents) { + free(content); + } if (salOp) salOp->release(); } From 87c7236d7fcf1f5e0fef1b0bd62a429ef58fcbac Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 9 Nov 2017 16:48:58 +0100 Subject: [PATCH 0760/2215] feat(MainDb): fetch contents of messages --- src/content/content-type.cpp | 25 ++++++---- src/content/content-type.h | 2 + src/content/content.cpp | 2 +- src/content/content.h | 4 +- src/db/main-db.cpp | 95 ++++++++++++++++++++++++++---------- 5 files changed, 89 insertions(+), 39 deletions(-) diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index 00805bfc6..4aeac8869 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -154,16 +154,8 @@ bool ContentType::isValid () const { return !d->type.empty() && !d->subType.empty(); } -bool ContentType::isFile() const { - //TODO Improve - if (*this != ContentType::FileTransfer && *this != ContentType::PlainText && - *this != ContentType::ExternalBody && *this != ContentType::Imdn && - *this != ContentType::ImIsComposing && *this != ContentType::ResourceLists && - *this != ContentType::Sdp && *this != ContentType::Cpim && - *this != ContentType::ConferenceInfo) { - return true; - } - return false; +bool ContentType::isFile () const { + return isFile(*this); } string ContentType::asString () const { @@ -178,4 +170,17 @@ string ContentType::asString () const { return ""; } +bool ContentType::isFile (const ContentType &contentType) { + // TODO Improve. + return contentType != FileTransfer && + contentType != PlainText && + contentType != ExternalBody && + contentType != Imdn && + contentType != ImIsComposing && + contentType != ResourceLists && + contentType != Sdp && + contentType != Cpim && + contentType != ConferenceInfo; +} + LINPHONE_END_NAMESPACE diff --git a/src/content/content-type.h b/src/content/content-type.h index fe5147645..a66955a94 100644 --- a/src/content/content-type.h +++ b/src/content/content-type.h @@ -59,6 +59,8 @@ public: std::string asString () const; + static bool isFile (const ContentType &contentType); + static const ContentType Cpim; static const ContentType ExternalBody; static const ContentType FileTransfer; diff --git a/src/content/content.cpp b/src/content/content.cpp index dd646d198..e94c0ecee 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -121,7 +121,7 @@ void Content::setBody (const vector &body) { d->body = body; } -void Content::setBody (std::vector &&body) { +void Content::setBody (vector &&body) { L_D(); d->body = move(body); } diff --git a/src/content/content.h b/src/content/content.h index 0047f6a46..4635898bf 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -22,9 +22,11 @@ #include +// TODO: Remove me. +#include "linphone/content.h" + #include "object/app-data-container.h" #include "object/clonable-object.h" -#include "linphone/content.h" // ============================================================================= diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 89b2a475d..2fe78c568 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -289,37 +289,78 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), if (!chatRoom) return nullptr; - string localSipAddress; - string remoteSipAddress; - string imdnMessageId; - int state; - int direction; - int isSecured; - - soci::session *session = dbSession.getBackendSession(); - *session << "SELECT local_sip_address.value, remote_sip_address.value, imdn_message_id, state, direction, is_secured" - " FROM event, conference_chat_message_event, sip_address AS local_sip_address," - " sip_address AS remote_sip_address" - " WHERE event_id = :eventId" - " AND event_id = event.id" - " AND local_sip_address_id = local_sip_address.id" - " AND remote_sip_address_id = remote_sip_address.id", soci::into(localSipAddress), soci::into(remoteSipAddress), - soci::into(imdnMessageId), soci::into(state), soci::into(direction), soci::into(isSecured), soci::use(eventId); - - // TODO: Create me. // TODO: Use cache, do not fetch the same message twice. + + // 1 - Fetch chat message. shared_ptr chatMessage = make_shared(chatRoom); + { + string localSipAddress; + string remoteSipAddress; + string imdnMessageId; + int state; + int direction; + int isSecured; - chatMessage->getPrivate()->setState(static_cast(state), true); - chatMessage->getPrivate()->setDirection(static_cast(direction)); - chatMessage->setIsSecured(static_cast(isSecured)); + soci::session *session = dbSession.getBackendSession(); + *session << "SELECT local_sip_address.value, remote_sip_address.value, imdn_message_id, state, direction, is_secured" + " FROM event, conference_chat_message_event, sip_address AS local_sip_address," + " sip_address AS remote_sip_address" + " WHERE event_id = :eventId" + " AND event_id = event.id" + " AND local_sip_address_id = local_sip_address.id" + " AND remote_sip_address_id = remote_sip_address.id", soci::into(localSipAddress), soci::into(remoteSipAddress), + soci::into(imdnMessageId), soci::into(state), soci::into(direction), soci::into(isSecured), soci::use(eventId); - if (direction == static_cast(ChatMessage::Direction::Outgoing)) { - chatMessage->setFromAddress(Address(localSipAddress)); - chatMessage->setToAddress(Address(remoteSipAddress)); - } else { - chatMessage->setFromAddress(Address(remoteSipAddress)); - chatMessage->setToAddress(Address(localSipAddress)); + chatMessage->getPrivate()->setState(static_cast(state), true); + chatMessage->getPrivate()->setDirection(static_cast(direction)); + chatMessage->setIsSecured(static_cast(isSecured)); + + if (direction == static_cast(ChatMessage::Direction::Outgoing)) { + chatMessage->setFromAddress(Address(localSipAddress)); + chatMessage->setToAddress(Address(remoteSipAddress)); + } else { + chatMessage->setFromAddress(Address(remoteSipAddress)); + chatMessage->setToAddress(Address(localSipAddress)); + } + } + + // 2 - Fetch contents. + { + soci::session *session = dbSession.getBackendSession(); + const string query = "SELECT content_type.value, body FROM chat_message_content, content_type" + " WHERE event_id = :eventId AND content_type_id = content_type.id"; + soci::rowset rows = (session->prepare << query, soci::use(eventId)); + for (const auto &row : rows) { + ContentType contentType(row.get(1)); + Content *content; + + if (contentType == ContentType::FileTransfer) + content = new FileTransferContent(); + else if (contentType.isFile()) { + long long contentId = q->getBackend() == AbstractDb::Sqlite3 + ? static_cast(row.get(0)) + : row.get(0); + + string name; + int size; + string path; + + *session << "SELECT name, size, path FROM chat_message_file_content" + " WHERE chat_message_content_id = :contentId", soci::use(contentId); + + FileContent *fileContent = new FileContent(); + fileContent->setFileName(name); + fileContent->setFileSize(static_cast(size)); + fileContent->setFilePath(path); + + content = fileContent; + } else + Content *content = new Content(); + + content->setContentType(contentType); + content->setBody(row.get(2)); + chatMessage.addContent(content); + } } // TODO: Use cache. From 2600d5f4d8b45f7e5a7baa1bb9ab9a24c1e1c9b1 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 9 Nov 2017 16:50:31 +0100 Subject: [PATCH 0761/2215] fix(MainDb): call addContent correctly --- src/db/main-db.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 2fe78c568..4d1fbb1bc 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -359,7 +359,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), content->setContentType(contentType); content->setBody(row.get(2)); - chatMessage.addContent(content); + chatMessage->addContent(content); } } From 1dda2e3d367bfa571dd3485db2c3cbc80ad222c7 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 9 Nov 2017 16:52:38 +0100 Subject: [PATCH 0762/2215] fix(MainDb): Schrodinger commit --- src/db/main-db.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 4d1fbb1bc..15f28a15b 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -346,7 +346,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), string path; *session << "SELECT name, size, path FROM chat_message_file_content" - " WHERE chat_message_content_id = :contentId", soci::use(contentId); + " WHERE chat_message_content_id = :contentId", + soci::into(name), soci::into(size), soci::into(path) soci::use(contentId); FileContent *fileContent = new FileContent(); fileContent->setFileName(name); @@ -355,7 +356,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), content = fileContent; } else - Content *content = new Content(); + content = new Content(); content->setContentType(contentType); content->setBody(row.get(2)); From b0bf790f6ba4fefbe08105c711290c73be2ab80f Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 9 Nov 2017 16:53:20 +0100 Subject: [PATCH 0763/2215] fix(MainDb): Schrodinger commit 2 --- src/db/main-db.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 15f28a15b..0a527dee5 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -347,7 +347,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "SELECT name, size, path FROM chat_message_file_content" " WHERE chat_message_content_id = :contentId", - soci::into(name), soci::into(size), soci::into(path) soci::use(contentId); + soci::into(name), soci::into(size), soci::into(path), soci::use(contentId); FileContent *fileContent = new FileContent(); fileContent->setFileName(name); From d7f31689373b67000c9692c8db29b92a2d61e4eb Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 9 Nov 2017 17:27:43 +0100 Subject: [PATCH 0764/2215] fix(MainDb): fetch conference chat rooms --- src/db/main-db.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 0a527dee5..23e76488b 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -28,6 +28,7 @@ #include "chat/chat-message/chat-message-p.h" #include "chat/chat-room/chat-room.h" +#include "chat/chat-room/client-group-chat-room.h" #include "conference/participant.h" #include "content/content-type.h" #include "content/content.h" @@ -1275,10 +1276,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::rowset rows = (session->prepare << query); for (const auto &row : rows) { - string sipAddress = row.get(0); - shared_ptr chatRoom = core->findChatRoom(Address(sipAddress)); + Address peerAddress = Address(row.get(0)); + shared_ptr chatRoom = core->findChatRoom(peerAddress); if (chatRoom) { - lInfo() << "Don't fetch chat room from database: `" << sipAddress << "`, it already exists."; chatRooms.push_back(chatRoom); continue; } @@ -1292,16 +1292,20 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), // TODO: Use me. (void)creationDate; (void)lastUpdateDate; - (void)subject; (void)lastNotifyId; if (capabilities & static_cast(ChatRoom::Capabilities::Basic)) { chatRoom = core->getPrivate()->createBasicChatRoom( - Address(sipAddress), + peerAddress, capabilities & static_cast(ChatRoom::Capabilities::RealTimeText) ); } else if (capabilities & static_cast(ChatRoom::Capabilities::Conference)) { - // TODO: Set sip address and participants. + chatRoom = make_shared( + getCore(), + Address("sip:titi@sip.linphone.org"), // TODO: Fix me!!! + peerAddress.asStringUriOnly(), + subject + ); } if (!chatRoom) From a30050c8bdf0d1a4480344bba9d387be75a85aa8 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 9 Nov 2017 17:30:27 +0100 Subject: [PATCH 0765/2215] Correct handling of client group chat room joining after it has been left. --- coreapi/callbacks.c | 4 +++- src/chat/chat-room/client-group-chat-room.cpp | 8 +++++--- src/conference/remote-conference-event-handler.cpp | 5 +++++ src/conference/remote-conference-event-handler.h | 1 + 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 1ec25c68a..b08409a4e 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -797,7 +797,9 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ return; } } else { - LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(addr)); + if (!cr) + cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); /* The following causes a crash because chat room hasn't yet a peer address. The above call to join() will create a CallSession which will call onConferenceCreated when it'll reach the Connected state. diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 75e4eb03e..9c1ba2eb5 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -163,7 +163,7 @@ void ClientGroupChatRoom::join () { L_D_T(RemoteConference, dConference); shared_ptr session = dConference->focus->getPrivate()->getSession(); - if (!session && d->state == ChatRoom::State::Instantiated) { + if (!session && ((d->state == ChatRoom::State::Instantiated) || (d->state == ChatRoom::State::Terminated))) { session = d->createSession(); session->startInvite(nullptr, "", nullptr); d->setState(ChatRoom::State::CreationPending); @@ -266,6 +266,8 @@ void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { L_D(); + L_D_T(RemoteConference, dConference); + dConference->eventHandler->resetLastNotify(); d->setState(ChatRoom::State::Terminated); } @@ -446,9 +448,9 @@ void ClientGroupChatRoom::onCallSessionStateChanged ( dConference->eventHandler->subscribe(getConferenceAddress()); } else if (d->state == ChatRoom::State::TerminationPending) dConference->focus->getPrivate()->getSession()->terminate(); - } else if (state == LinphoneCallReleased && d->state == ChatRoom::State::TerminationPending) { + } else if ((state == LinphoneCallReleased) && (d->state == ChatRoom::State::TerminationPending)) { onConferenceTerminated(getConferenceAddress()); - } else if (state == LinphoneCallError && d->state == ChatRoom::State::CreationPending) { + } else if ((state == LinphoneCallError) && (d->state == ChatRoom::State::CreationPending)) { d->setState(ChatRoom::State::CreationFailed); } } diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index d3a8ae260..9daa6363b 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -207,4 +207,9 @@ unsigned int RemoteConferenceEventHandler::getLastNotify () const { return d->lastNotify; }; +void RemoteConferenceEventHandler::resetLastNotify () { + L_D(); + d->lastNotify = 0; +} + LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference-event-handler.h b/src/conference/remote-conference-event-handler.h index b6cb6949f..2422fdb8d 100644 --- a/src/conference/remote-conference-event-handler.h +++ b/src/conference/remote-conference-event-handler.h @@ -40,6 +40,7 @@ class RemoteConferenceEventHandler : public Object { const Address &getConfAddress () const; unsigned int getLastNotify () const; + void resetLastNotify (); private: L_DECLARE_PRIVATE(RemoteConferenceEventHandler); From c4fadd417bf15d3ace4e2ade7f9683695a844bfc Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 10 Nov 2017 09:25:12 +0100 Subject: [PATCH 0766/2215] fix(Variant): use `swap` when possible --- src/variant/variant.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index 8f9b4e9e6..efa7d084a 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -108,8 +108,7 @@ Variant::Variant (const Variant &src) { Variant::Variant (Variant &&src) { // Don't call placement new. L_ASSERT(!mPrivate); - mPrivate = src.mPrivate; - src.mPrivate = nullptr; + ::swap(mPrivate, src.mPrivate); } Variant::Variant (int value) : Variant(Int) { @@ -220,13 +219,7 @@ Variant &Variant::operator= (const Variant &variant) { } Variant &Variant::operator= (Variant &&variant) { - // Unset old d. - delete mPrivate; - - // Set new d. - mPrivate = variant.mPrivate; - variant.mPrivate = nullptr; - + ::swap(mPrivate, variant.mPrivate); return *this; } From e536ded32d85483e834f541ef3986a6ae13bf618 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 10 Nov 2017 09:34:01 +0100 Subject: [PATCH 0767/2215] fix(ClientGroupChatRoom): do not create base ChatRoom with me!!! --- src/chat/chat-room/client-group-chat-room.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 9c1ba2eb5..1cf7f0250 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -81,7 +81,7 @@ ClientGroupChatRoom::ClientGroupChatRoom ( const Address &me, const std::string &uri, const std::string &subject -) : ChatRoom(*new ClientGroupChatRoomPrivate, core, me), RemoteConference(core->getCCore(), me, nullptr) { +) : ChatRoom(*new ClientGroupChatRoomPrivate, core, Address()), RemoteConference(core->getCCore(), me, nullptr) { L_D_T(RemoteConference, dConference); dConference->focus = make_shared(Address(uri)); RemoteConference::setSubject(subject); From 33edd95a159680c5ab1a1472dbbe508916dd49e9 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 10 Nov 2017 11:25:29 +0100 Subject: [PATCH 0768/2215] fix(Core): remove useless includes --- src/object/object-p.h | 2 -- src/object/object.cpp | 2 -- src/object/object.h | 2 -- src/object/property-container.cpp | 8 +++++--- src/utils/utils.cpp | 4 ++-- src/variant/variant.cpp | 2 ++ 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/object/object-p.h b/src/object/object-p.h index e4b46c53f..eafbb9ce4 100644 --- a/src/object/object-p.h +++ b/src/object/object-p.h @@ -20,12 +20,10 @@ #ifndef _OBJECT_P_H_ #define _OBJECT_P_H_ -#include #include #include "base-object-p.h" #include "object.h" -#include "variant/variant.h" // ============================================================================= diff --git a/src/object/object.cpp b/src/object/object.cpp index e22adb37f..77e333aa2 100644 --- a/src/object/object.cpp +++ b/src/object/object.cpp @@ -20,8 +20,6 @@ #include "logger/logger.h" #include "object-p.h" -#include "object.h" - // ============================================================================= using namespace std; diff --git a/src/object/object.h b/src/object/object.h index f929df63a..e132fc075 100644 --- a/src/object/object.h +++ b/src/object/object.h @@ -41,8 +41,6 @@ class LINPHONE_PUBLIC Object : friend class ObjectFactory; public: - virtual ~Object () = default; - std::shared_ptr getSharedFromThis (); std::shared_ptr getSharedFromThis () const; diff --git a/src/object/property-container.cpp b/src/object/property-container.cpp index 44d2cb1de..36cbe6993 100644 --- a/src/object/property-container.cpp +++ b/src/object/property-container.cpp @@ -36,9 +36,11 @@ public: PropertyContainer::PropertyContainer () : mPrivate(new PropertyContainerPrivate) {} -// Empty copy constructor. Don't change this pattern. -// PropertyContainer is an Entity component, not a simple structure. -// An Entity is UNIQUE. +/* + * Empty copy constructor. Don't change this pattern. + * PropertyContainer is an Entity component, not a simple structure. + * An Entity is UNIQUE. + */ PropertyContainer::PropertyContainer (const PropertyContainer &) : mPrivate(new PropertyContainerPrivate) {} PropertyContainer::~PropertyContainer () { diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 0013cb2f5..8d4f55efe 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -94,10 +94,10 @@ string Utils::toString (const void *val) { // ----------------------------------------------------------------------------- #define STRING_TO_NUMBER_IMPL(TYPE, SUFFIX) \ - TYPE Utils::sto ## SUFFIX(const string &str, size_t *idx, int base) { \ + TYPE Utils::sto ## SUFFIX (const string &str, size_t *idx, int base) { \ return sto ## SUFFIX(str.c_str(), idx, base); \ } \ - TYPE Utils::sto ## SUFFIX(const char *str, size_t *idx, int base) { \ + TYPE Utils::sto ## SUFFIX (const char *str, size_t *idx, int base) { \ char *p; \ TYPE v = strto ## SUFFIX(str, &p, base); \ if (idx) \ diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index efa7d084a..45aea40bc 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -77,6 +77,8 @@ private: int type = Variant::Invalid; }; +// ----------------------------------------------------------------------------- + Variant::Variant () { // Private can exist. (placement new) if (!mPrivate) From e43d58fb2b1a9d88ebee6d0afdc47d283dd82455 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 10 Nov 2017 14:36:30 +0100 Subject: [PATCH 0769/2215] Remove participant before the onParticipantRemoved callback on ChatRoom so the participants list is correct in the callback --- src/chat/chat-room/client-group-chat-room.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 1cf7f0250..662a7b36e 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -317,6 +317,8 @@ void ClientGroupChatRoom::onParticipantRemoved (const shared_ptrparticipants.remove(participant); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantRemovedCb cb = linphone_chat_room_cbs_get_participant_removed(cbs); @@ -324,8 +326,6 @@ void ClientGroupChatRoom::onParticipantRemoved (const shared_ptrparticipants.remove(participant); } void ClientGroupChatRoom::onParticipantSetAdmin (const shared_ptr &event, bool isFullState) { From 098660726fb189c58cde0b4e7f143ea8591a2afa Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 10 Nov 2017 15:27:06 +0100 Subject: [PATCH 0770/2215] feat(ChatRoom): add a chat room identifier object --- src/CMakeLists.txt | 2 + src/chat/chat-room/chat-room-id.cpp | 67 +++++++++++++++++++++++++++++ src/chat/chat-room/chat-room-id.h | 47 ++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 src/chat/chat-room/chat-room-id.cpp create mode 100644 src/chat/chat-room/chat-room-id.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f633fc847..f90b0134d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -35,6 +35,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES chat/chat-message/chat-message.h chat/chat-room/basic-chat-room-p.h chat/chat-room/basic-chat-room.h + chat/chat-room/chat-room-id.h chat/chat-room/chat-room-p.h chat/chat-room/chat-room.h chat/chat-room/client-group-chat-room-p.h @@ -159,6 +160,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES call/call.cpp chat/chat-message/chat-message.cpp chat/chat-room/basic-chat-room.cpp + chat/chat-room/chat-room-id.cpp chat/chat-room/chat-room.cpp chat/chat-room/client-group-chat-room.cpp chat/chat-room/real-time-text-chat-room.cpp diff --git a/src/chat/chat-room/chat-room-id.cpp b/src/chat/chat-room/chat-room-id.cpp new file mode 100644 index 000000000..9887f1229 --- /dev/null +++ b/src/chat/chat-room/chat-room-id.cpp @@ -0,0 +1,67 @@ +/* + * chat-room-id.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "object/clonable-object-p.h" + +#include "chat-room-id.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +class ChatRoomIdPrivate : public ClonableObjectPrivate { +public: + SimpleAddress peerAddress; + SimpleAddress localAddress; +}; + +// ----------------------------------------------------------------------------- + +ChatRoomId::ChatRoomId ( + const SimpleAddress &peerAddress, + const SimpleAddress &localAddress +) : ClonableObject(*new ChatRoomIdPrivate) { + L_D(); + d->peerAddress = peerAddress; + d->localAddress = localAddress; +} + +bool ChatRoomId::operator== (const ChatRoomId &chatRoomId) const { + L_D(); + const ChatRoomIdPrivate *dChatRoomId = chatRoomId.getPrivate(); + return d->peerAddress == dChatRoomId->peerAddress && d->localAddress == dChatRoomId->localAddress; +} + +bool ChatRoomId::operator!= (const ChatRoomId &chatRoomId) const { + return !(*this == chatRoomId); +} + +const SimpleAddress &ChatRoomId::getPeerAddress () const { + L_D(); + return d->peerAddress; +} + +const SimpleAddress &ChatRoomId::getLocalAddress () const { + L_D(); + return d->localAddress; +} + +LINPHONE_END_NAMESPACE diff --git a/src/chat/chat-room/chat-room-id.h b/src/chat/chat-room/chat-room-id.h new file mode 100644 index 000000000..3ab346e01 --- /dev/null +++ b/src/chat/chat-room/chat-room-id.h @@ -0,0 +1,47 @@ +/* + * chat-room-id.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CHAT_ROOM_ID_H_ +#define _CHAT_ROOM_ID_H_ + +#include "address/simple-address.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ChatRoomIdPrivate; + +class LINPHONE_PUBLIC ChatRoomId : public ClonableObject { +public: + ChatRoomId (const SimpleAddress &peerAddress, const SimpleAddress &localAddress); + + bool operator== (const ChatRoomId &chatRoomId) const; + bool operator!= (const ChatRoomId &chatRoomId) const; + + const SimpleAddress &getPeerAddress () const; + const SimpleAddress &getLocalAddress () const; + +private: + L_DECLARE_PRIVATE(ChatRoomId); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CHAT_ROOM_ID_H_ From e98ce1ea4a445d680fb4f5e16560b1cf96689e78 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 10 Nov 2017 15:27:54 +0100 Subject: [PATCH 0771/2215] Some cleaning. --- src/chat/chat-room/client-group-chat-room-p.h | 2 +- src/chat/chat-room/client-group-chat-room.cpp | 6 +++--- src/chat/chat-room/client-group-chat-room.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room-p.h b/src/chat/chat-room/client-group-chat-room-p.h index 39b8313b3..72ffd2206 100644 --- a/src/chat/chat-room/client-group-chat-room-p.h +++ b/src/chat/chat-room/client-group-chat-room-p.h @@ -33,7 +33,7 @@ public: std::list
      cleanAddressesList (const std::list
      &addresses) const; std::shared_ptr createSession (); - void notifyReceived (std::string body); + void notifyReceived (const std::string &body); private: L_DECLARE_PUBLIC(ClientGroupChatRoom); diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 662a7b36e..2c801a177 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -69,7 +69,7 @@ shared_ptr ClientGroupChatRoomPrivate::createSession () { return session; } -void ClientGroupChatRoomPrivate::notifyReceived (string body) { +void ClientGroupChatRoomPrivate::notifyReceived (const string &body) { L_Q_T(RemoteConference, qConference); qConference->getPrivate()->eventHandler->notifyReceived(body); } @@ -79,11 +79,11 @@ void ClientGroupChatRoomPrivate::notifyReceived (string body) { ClientGroupChatRoom::ClientGroupChatRoom ( const std::shared_ptr &core, const Address &me, - const std::string &uri, + const std::string &factoryUri, const std::string &subject ) : ChatRoom(*new ClientGroupChatRoomPrivate, core, Address()), RemoteConference(core->getCCore(), me, nullptr) { L_D_T(RemoteConference, dConference); - dConference->focus = make_shared(Address(uri)); + dConference->focus = make_shared(Address(factoryUri)); RemoteConference::setSubject(subject); } diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 8b4ae10c0..709684167 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -35,7 +35,7 @@ public: ClientGroupChatRoom ( const std::shared_ptr &core, const Address &me, - const std::string &uri, + const std::string &factoryUri, const std::string &subject ); From 8c7b408d4e99287fc77c5210f1d4d320c00b5dae Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 10 Nov 2017 15:28:40 +0100 Subject: [PATCH 0772/2215] Add GruuAddress class. --- src/CMakeLists.txt | 3 + src/address/gruu-address-p.h | 40 ++++++++ src/address/gruu-address.cpp | 93 +++++++++++++++++++ src/address/gruu-address.h | 56 +++++++++++ src/address/simple-address.cpp | 5 - src/address/simple-address.h | 3 +- .../local-conference-event-handler.cpp | 2 +- src/conference/session/media-session.cpp | 10 +- 8 files changed, 199 insertions(+), 13 deletions(-) create mode 100644 src/address/gruu-address-p.h create mode 100644 src/address/gruu-address.cpp create mode 100644 src/address/gruu-address.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f90b0134d..2ad611b2e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,6 +23,8 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES address/address-p.h address/address.h + address/gruu-address-p.h + address/gruu-address.h address/simple-address-p.h address/simple-address.h c-wrapper/c-wrapper.h @@ -143,6 +145,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES set(LINPHONE_CXX_OBJECTS_SOURCE_FILES address/address.cpp + address/gruu-address.cpp address/simple-address.cpp c-wrapper/api/c-address.cpp c-wrapper/api/c-call-cbs.cpp diff --git a/src/address/gruu-address-p.h b/src/address/gruu-address-p.h new file mode 100644 index 000000000..116707db5 --- /dev/null +++ b/src/address/gruu-address-p.h @@ -0,0 +1,40 @@ +/* + * gruu-address-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _GRUU_ADDRESS_P_H_ +#define _GRUU_ADDRESS_P_H_ + +#include "gruu-address.h" +#include "address/simple-address-p.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class GruuAddressPrivate : public SimpleAddressPrivate { +private: + std::string urn; + bool valid = false; + + L_DECLARE_PUBLIC(GruuAddress); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _GRUU_ADDRESS_P_H_ diff --git a/src/address/gruu-address.cpp b/src/address/gruu-address.cpp new file mode 100644 index 000000000..da125764d --- /dev/null +++ b/src/address/gruu-address.cpp @@ -0,0 +1,93 @@ +/* + * gruu-address.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "linphone/utils/utils.h" + +#include "gruu-address-p.h" +#include "c-wrapper/c-wrapper.h" +#include "logger/logger.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +// ----------------------------------------------------------------------------- + +GruuAddress::GruuAddress (const string &address) : SimpleAddress(address) { + L_D(); + Address tmpAddress(address); + if (tmpAddress.isValid()) { + if (!tmpAddress.hasUriParam("gr")) + return; + d->urn = tmpAddress.getUriParamValue("gr"); + d->valid = true; + } +} + +GruuAddress::GruuAddress (const GruuAddress &src) : SimpleAddress(src) { + L_D(); + d->urn = src.getPrivate()->urn; + d->valid = src.getPrivate()->valid; +} + +GruuAddress::GruuAddress (const Address &src) : SimpleAddress(src) { + L_D(); + if (src.isValid()) { + if (!src.hasUriParam("gr")) + return; + d->urn = src.getUriParamValue("gr"); + d->valid = true; + } +} + +GruuAddress &GruuAddress::operator= (const GruuAddress &src) { + L_D(); + if (this != &src) { + SimpleAddress::operator=(src); + d->urn = src.getPrivate()->urn; + d->valid = src.getPrivate()->valid; + } + return *this; +} + +bool GruuAddress::operator== (const GruuAddress &address) const { + return asString() == address.asString(); +} + +bool GruuAddress::operator!= (const GruuAddress &address) const { + return !(*this == address); +} + +bool GruuAddress::operator< (const GruuAddress &address) const { + return asString() < address.asString(); +} + +bool GruuAddress::isValid () const { + L_D(); + return d->valid; +} + +string GruuAddress::asString () const { + Address tmpAddress(*this); + return tmpAddress.asString(); +} + +LINPHONE_END_NAMESPACE diff --git a/src/address/gruu-address.h b/src/address/gruu-address.h new file mode 100644 index 000000000..8de6a8edf --- /dev/null +++ b/src/address/gruu-address.h @@ -0,0 +1,56 @@ +/* + * gruu-address.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _GRUU_ADDRESS_H_ +#define _GRUU_ADDRESS_H_ + +#include "address/simple-address.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class Address; +class GruuAddressPrivate; + +class LINPHONE_PUBLIC GruuAddress : public SimpleAddress { +public: + explicit GruuAddress (const std::string &address = ""); + GruuAddress (const GruuAddress &src); + GruuAddress (const Address &src); + ~GruuAddress () = default; + + GruuAddress &operator= (const GruuAddress &src); + + bool operator== (const GruuAddress &address) const; + bool operator!= (const GruuAddress &address) const; + + bool operator< (const GruuAddress &address) const; + + bool isValid () const; + + std::string asString () const override; + +private: + L_DECLARE_PRIVATE(GruuAddress); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _GRUU_ADDRESS_H_ diff --git a/src/address/simple-address.cpp b/src/address/simple-address.cpp index 19a1da395..cf7112390 100644 --- a/src/address/simple-address.cpp +++ b/src/address/simple-address.cpp @@ -109,9 +109,4 @@ string SimpleAddress::asString () const { return tmpAddress.asString(); } -string SimpleAddress::asStringUriOnly () const { - Address tmpAddress(*this); - return tmpAddress.asStringUriOnly(); -} - LINPHONE_END_NAMESPACE diff --git a/src/address/simple-address.h b/src/address/simple-address.h index 4a76a83ee..991bacd01 100644 --- a/src/address/simple-address.h +++ b/src/address/simple-address.h @@ -53,8 +53,7 @@ public: bool isSip () const; - std::string asString () const; - std::string asStringUriOnly () const; + virtual std::string asString () const; private: L_DECLARE_PRIVATE(SimpleAddress); diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 93e970114..97bd83af2 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -97,7 +97,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyFullState (int notifyId) UserType::EndpointSequence endpoints; user.setRoles(roles); user.setEndpoint(endpoints); - user.setEntity(participant->getAddress().asStringUriOnly()); + user.setEntity(participant->getAddress().asString()); user.getRoles()->getEntry().push_back(participant->isAdmin() ? "admin" : "participant"); user.setState(StateType::full); diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index e51fc7069..9a8f6ae56 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -1263,7 +1263,7 @@ void MediaSessionPrivate::makeLocalMediaDescription () { md->streams[mainAudioStreamIndex].payloads = l; if (audioStream && audioStream->ms.sessions.rtp_session) { md->streams[mainAudioStreamIndex].rtp_ssrc = rtp_session_get_send_ssrc(audioStream->ms.sessions.rtp_session); - strncpy(md->streams[mainAudioStreamIndex].rtcp_cname, conference.getMe()->getAddress().asStringUriOnly().c_str(), sizeof(md->streams[mainAudioStreamIndex].rtcp_cname)); + strncpy(md->streams[mainAudioStreamIndex].rtcp_cname, conference.getMe()->getAddress().asString().c_str(), sizeof(md->streams[mainAudioStreamIndex].rtcp_cname)); } else lWarning() << "Cannot get audio local ssrc for CallSession [" << q << "]"; @@ -1295,7 +1295,7 @@ void MediaSessionPrivate::makeLocalMediaDescription () { md->streams[mainVideoStreamIndex].payloads = l; if (videoStream && videoStream->ms.sessions.rtp_session) { md->streams[mainVideoStreamIndex].rtp_ssrc = rtp_session_get_send_ssrc(videoStream->ms.sessions.rtp_session); - strncpy(md->streams[mainVideoStreamIndex].rtcp_cname, conference.getMe()->getAddress().asStringUriOnly().c_str(), sizeof(md->streams[mainVideoStreamIndex].rtcp_cname)); + strncpy(md->streams[mainVideoStreamIndex].rtcp_cname, conference.getMe()->getAddress().asString().c_str(), sizeof(md->streams[mainVideoStreamIndex].rtcp_cname)); } else lWarning() << "Cannot get video local ssrc for CallSession [" << q << "]"; if (mainVideoStreamIndex > maxIndex) @@ -1327,7 +1327,7 @@ void MediaSessionPrivate::makeLocalMediaDescription () { md->streams[mainTextStreamIndex].payloads = l; if (textStream && textStream->ms.sessions.rtp_session) { md->streams[mainTextStreamIndex].rtp_ssrc = rtp_session_get_send_ssrc(textStream->ms.sessions.rtp_session); - strncpy(md->streams[mainTextStreamIndex].rtcp_cname, conference.getMe()->getAddress().asStringUriOnly().c_str(), sizeof(md->streams[mainTextStreamIndex].rtcp_cname)); + strncpy(md->streams[mainTextStreamIndex].rtcp_cname, conference.getMe()->getAddress().asString().c_str(), sizeof(md->streams[mainTextStreamIndex].rtcp_cname)); } else lWarning() << "Cannot get text local ssrc for CallSession [" << q << "]"; if (mainTextStreamIndex > maxIndex) @@ -2201,7 +2201,7 @@ void MediaSessionPrivate::initializeAudioStream () { rtp_session_enable_network_simulation(audioStream->ms.sessions.rtp_session, &core->net_conf.netsim_params); applyJitterBufferParams(audioStream->ms.sessions.rtp_session, LinphoneStreamTypeAudio); string userAgent = linphone_core_get_user_agent(core); - audio_stream_set_rtcp_information(audioStream, conference.getMe()->getAddress().asStringUriOnly().c_str(), userAgent.c_str()); + audio_stream_set_rtcp_information(audioStream, conference.getMe()->getAddress().asString().c_str(), userAgent.c_str()); rtp_session_set_symmetric_rtp(audioStream->ms.sessions.rtp_session, linphone_core_symmetric_rtp_enabled(core)); setupDtlsParams(&audioStream->ms); @@ -2354,7 +2354,7 @@ void MediaSessionPrivate::initializeVideoStream () { rtp_session_enable_network_simulation(videoStream->ms.sessions.rtp_session, &core->net_conf.netsim_params); applyJitterBufferParams(videoStream->ms.sessions.rtp_session, LinphoneStreamTypeVideo); string userAgent = linphone_core_get_user_agent(core); - video_stream_set_rtcp_information(videoStream, conference.getMe()->getAddress().asStringUriOnly().c_str(), userAgent.c_str()); + video_stream_set_rtcp_information(videoStream, conference.getMe()->getAddress().asString().c_str(), userAgent.c_str()); rtp_session_set_symmetric_rtp(videoStream->ms.sessions.rtp_session, linphone_core_symmetric_rtp_enabled(core)); setupDtlsParams(&videoStream->ms); /* Initialize zrtp even if we didn't explicitely set it, just in case peer offers it */ From 2ad1f46105fb9e63c83278bb4d183ecdd874f1e1 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 13 Nov 2017 11:11:35 +0100 Subject: [PATCH 0773/2215] fix(ClonableObject): fix a fatal bug in ClonableObject: - Create a A Object - Create a B Object - Copy A in B - Delete B - Use L_Q or access public => Crash --- include/CMakeLists.txt | 7 ++-- include/linphone/utils/general.h | 52 ++++---------------------- include/linphone/utils/traits.h | 57 +++++++++++++++++++++++++++++ src/address/address-p.h | 2 + src/chat/chat-room/chat-room-id.cpp | 2 + src/chat/chat-room/chat-room-id.h | 3 ++ src/db/session/db-session.cpp | 4 +- src/object/clonable-object-p.h | 9 +---- src/object/clonable-object.cpp | 49 +++++++------------------ src/object/clonable-object.h | 16 +++++--- 10 files changed, 104 insertions(+), 97 deletions(-) create mode 100644 include/linphone/utils/traits.h diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 31f1c52d6..f78e49c63 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -76,14 +76,14 @@ set(ROOT_HEADER_FILES set(C_API_HEADER_FILES c-address.h c-api.h - c-call.h c-call-cbs.h c-call-stats.h + c-call.h c-callbacks.h - c-chat-message.h c-chat-message-cbs.h - c-chat-room.h + c-chat-message.h c-chat-room-cbs.h + c-chat-room.h c-dial-plan.h c-event-log.h c-participant.h @@ -100,6 +100,7 @@ set(UTILS_HEADER_FILES enum-generator.h general.h magic-macros.h + traits.h utils.h ) diff --git a/include/linphone/utils/general.h b/include/linphone/utils/general.h index b03c23804..3f73757fd 100644 --- a/include/linphone/utils/general.h +++ b/include/linphone/utils/general.h @@ -132,38 +132,11 @@ class ObjectPrivate; friend class Tester; #endif -namespace Private { - // See: http://en.cppreference.com/w/cpp/types/void_t - template struct MakeVoid { - typedef void type; - }; - template - using void_t = typename MakeVoid::type; - - template - struct IsMapContainerImpl : std::false_type {}; - - template - struct IsMapContainerImpl< - T, - void_t< - typename T::key_type, - typename T::mapped_type, - decltype(std::declval()[std::declval()]) - > - > : std::true_type {}; -}; - -// Check if a type is a std container like map, unordered_map... -template -struct IsMapContainer : Private::IsMapContainerImpl::type {}; - // Generic public helper. template< typename R, typename P, - typename C, - typename = typename std::enable_if::value, P>::type + typename C > constexpr R *getPublicHelper (P *object, const C *) { return static_cast(object); @@ -173,22 +146,19 @@ constexpr R *getPublicHelper (P *object, const C *) { template< typename R, typename P, - typename C, - typename = typename std::enable_if::value, P>::type + typename C > -inline R *getPublicHelper (const P *map, const C *context) { - auto it = map->find(context); - L_ASSERT(it != map->cend()); - return static_cast(it->second); +inline R *getPublicHelper (const P &objectSet, const C *) { + auto it = objectSet.cbegin(); + L_ASSERT(it != objectSet.cend()); + return static_cast(*it); } #define L_DECLARE_PUBLIC(CLASS) \ inline CLASS *getPublic () { \ - L_ASSERT(mPublic); \ return getPublicHelper(mPublic, this); \ } \ inline const CLASS *getPublic () const { \ - L_ASSERT(mPublic); \ return getPublicHelper(mPublic, this); \ } \ friend class CLASS; @@ -239,14 +209,6 @@ struct AddConstMirror { return std::static_pointer_cast(Object::getSharedFromThis()); \ } -#define L_USE_DEFAULT_SHARE_IMPL(CLASS, PARENT_CLASS) \ - CLASS::CLASS (const CLASS &src) : PARENT_CLASS(*src.getPrivate()) {} \ - CLASS &CLASS::operator= (const CLASS &src) { \ - if (this != &src) \ - setRef(*src.getPrivate()); \ - return *this; \ - } - // ----------------------------------------------------------------------------- // Wrapper public. // ----------------------------------------------------------------------------- @@ -254,7 +216,7 @@ struct AddConstMirror { #define L_DECL_C_STRUCT(STRUCT) typedef struct _ ## STRUCT STRUCT; #define L_DECL_C_STRUCT_PREFIX_LESS(STRUCT) typedef struct STRUCT STRUCT; -#endif +#endif // ifdef __cplusplus LINPHONE_END_NAMESPACE diff --git a/include/linphone/utils/traits.h b/include/linphone/utils/traits.h new file mode 100644 index 000000000..87c413510 --- /dev/null +++ b/include/linphone/utils/traits.h @@ -0,0 +1,57 @@ +/* + * traits.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _TRAITS_H_ +#define _TRAITS_H_ + +#include "general.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +namespace Private { + // See: http://en.cppreference.com/w/cpp/types/void_t + template struct MakeVoid { + typedef void type; + }; + template + using void_t = typename MakeVoid::type; + + template + struct IsMapContainerImpl : std::false_type {}; + + template + struct IsMapContainerImpl< + T, + void_t< + typename T::key_type, + typename T::mapped_type, + decltype(std::declval()[std::declval()]) + > + > : std::true_type {}; +}; + +// Check if a type is a std container like map, unordered_map... +template +struct IsMapContainer : Private::IsMapContainerImpl::type {}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _TRAITS_H_ diff --git a/src/address/address-p.h b/src/address/address-p.h index 8dac81823..ce7d273b5 100644 --- a/src/address/address-p.h +++ b/src/address/address-p.h @@ -20,6 +20,8 @@ #ifndef _ADDRESS_P_H_ #define _ADDRESS_P_H_ +#include + #include "address.h" #include "object/clonable-object-p.h" diff --git a/src/chat/chat-room/chat-room-id.cpp b/src/chat/chat-room/chat-room-id.cpp index 9887f1229..9f5a4482c 100644 --- a/src/chat/chat-room/chat-room-id.cpp +++ b/src/chat/chat-room/chat-room-id.cpp @@ -44,6 +44,8 @@ ChatRoomId::ChatRoomId ( d->localAddress = localAddress; } +L_USE_DEFAULT_CLONABLE_OBJECT_SHARED_IMPL(ChatRoomId); + bool ChatRoomId::operator== (const ChatRoomId &chatRoomId) const { L_D(); const ChatRoomIdPrivate *dChatRoomId = chatRoomId.getPrivate(); diff --git a/src/chat/chat-room/chat-room-id.h b/src/chat/chat-room/chat-room-id.h index 3ab346e01..4703600d5 100644 --- a/src/chat/chat-room/chat-room-id.h +++ b/src/chat/chat-room/chat-room-id.h @@ -31,6 +31,9 @@ class ChatRoomIdPrivate; class LINPHONE_PUBLIC ChatRoomId : public ClonableObject { public: ChatRoomId (const SimpleAddress &peerAddress, const SimpleAddress &localAddress); + ChatRoomId (const ChatRoomId &src); + + ChatRoomId &operator= (const ChatRoomId &src); bool operator== (const ChatRoomId &chatRoomId) const; bool operator!= (const ChatRoomId &chatRoomId) const; diff --git a/src/db/session/db-session.cpp b/src/db/session/db-session.cpp index 1dd0610cc..471caad0d 100644 --- a/src/db/session/db-session.cpp +++ b/src/db/session/db-session.cpp @@ -30,13 +30,13 @@ DbSession::DbSession (Type type) : ClonableObject(*new DbSessionPrivate) { d->type = type; } -L_USE_DEFAULT_SHARE_IMPL(DbSession, ClonableObject); - DbSession::operator bool () const { L_D(); return d->isValid; } +L_USE_DEFAULT_CLONABLE_OBJECT_SHARED_IMPL(DbSession); + DbSession::Type DbSession::getBackendType () const { L_D(); return d->type; diff --git a/src/object/clonable-object-p.h b/src/object/clonable-object-p.h index af30d627c..9faad38c0 100644 --- a/src/object/clonable-object-p.h +++ b/src/object/clonable-object-p.h @@ -20,7 +20,7 @@ #ifndef _CLONABLE_OBJECT_P_H_ #define _CLONABLE_OBJECT_P_H_ -#include +#include #include "linphone/utils/general.h" @@ -38,14 +38,9 @@ public: virtual ~ClonableObjectPrivate () = default; protected: - std::unordered_map *mPublic = nullptr; + std::set mPublic; private: - void ref (); - void unref (); - - int nRefs = 0; - L_DECLARE_PUBLIC(ClonableObject); // It's forbidden to copy directly one Clonable object private. diff --git a/src/object/clonable-object.cpp b/src/object/clonable-object.cpp index 831e7879a..961c13d67 100644 --- a/src/object/clonable-object.cpp +++ b/src/object/clonable-object.cpp @@ -27,62 +27,41 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -// TODO: Use atomic counter? - -void ClonableObjectPrivate::ref () { - ++nRefs; -} - -void ClonableObjectPrivate::unref () { - if (--nRefs == 0) { - delete mPublic; - delete this; - } -} - // ----------------------------------------------------------------------------- L_OBJECT_IMPL(ClonableObject); -ClonableObject::ClonableObject (ClonableObjectPrivate &p) : mPrivate(&p) { - // Q-pointer must be empty. It's a constructor that takes a new private data. - L_ASSERT(!mPrivate->mPublic); - - mPrivate->mPublic = new remove_pointermPublic)>::type(); - (*mPrivate->mPublic)[mPrivate] = this; - mPrivate->ref(); -} - -ClonableObject::ClonableObject (const ClonableObjectPrivate &p) { - // Cannot access to Q-pointer. It's a copy constructor from private data. - L_ASSERT(!mPrivate); - +ClonableObject::ClonableObject (ClonableObjectPrivate &p) { setRef(p); } +#define UNREF() \ + do { \ + auto &h = mPrivate->mPublic; \ + h.erase(this); \ + if (h.empty()) \ + delete mPrivate; \ + } while (false); + ClonableObject::~ClonableObject () { - mPrivate->mPublic->erase(mPrivate); - mPrivate->unref(); + UNREF(); } void ClonableObject::setRef (const ClonableObjectPrivate &p) { // Q-pointer must exist if private data is defined. - L_ASSERT(!mPrivate || mPrivate->mPublic); + L_ASSERT(!mPrivate || !mPrivate->mPublic.empty()); // Nothing, same reference. if (&p == mPrivate) return; // Unref previous private data. - if (mPrivate) { - mPrivate->mPublic->erase(mPrivate); - mPrivate->unref(); - } + if (mPrivate) + UNREF(); // Add and reference new private data. mPrivate = const_cast(&p); - (*mPrivate->mPublic)[mPrivate] = this; - mPrivate->ref(); + mPrivate->mPublic.insert(this); } LINPHONE_END_NAMESPACE diff --git a/src/object/clonable-object.h b/src/object/clonable-object.h index 30df6b61f..4decdc8e4 100644 --- a/src/object/clonable-object.h +++ b/src/object/clonable-object.h @@ -25,6 +25,16 @@ // ============================================================================= +#define L_USE_DEFAULT_CLONABLE_OBJECT_SHARED_IMPL(CLASS) \ + CLASS::CLASS (const CLASS &src) : ClonableObject( \ + const_cast::type &>(*src.getPrivate()) \ + ) {} \ + CLASS &CLASS::operator= (const CLASS &src) { \ + if (this != &src) \ + setRef(*src.getPrivate()); \ + return *this; \ + } + LINPHONE_BEGIN_NAMESPACE /* @@ -38,13 +48,9 @@ public: virtual ~ClonableObject (); protected: - // Use a new ClonableObjectPrivate without owner. explicit ClonableObject (ClonableObjectPrivate &p); - // If you want share an existing ClonableObjectPrivate, call this function. - explicit ClonableObject (const ClonableObjectPrivate &p); - - // Change the ClonableObjectPrivate, it can be shared. + // Change the ClonableObjectPrivate. Unref previous. void setRef (const ClonableObjectPrivate &p); ClonableObjectPrivate *mPrivate = nullptr; From 84585852660bbdb719914ba5eea7c1f93ac67697 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 13 Nov 2017 11:23:12 +0100 Subject: [PATCH 0774/2215] Fix GruuAddress and use it in ParticipantDevice. --- src/address/address.cpp | 14 +++++++ src/address/address.h | 2 + src/address/gruu-address.cpp | 22 +++++++++-- src/address/gruu-address.h | 3 ++ src/address/simple-address.cpp | 11 +++++- src/address/simple-address.h | 4 ++ .../local-conference-event-handler.cpp | 4 +- src/conference/participant-device.cpp | 4 +- src/conference/participant-device.h | 19 ++++++--- src/conference/participant-p.h | 11 +++--- src/conference/participant.cpp | 39 +++++++++++++------ 11 files changed, 103 insertions(+), 30 deletions(-) diff --git a/src/address/address.cpp b/src/address/address.cpp index 551975285..924eb9ad0 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -22,6 +22,7 @@ #include "address-p.h" #include "c-wrapper/c-wrapper.h" #include "logger/logger.h" +#include "address/gruu-address.h" #include "address/simple-address.h" // ============================================================================= @@ -46,6 +47,19 @@ Address::Address (const Address &src) : ClonableObject(*new AddressPrivate) { d->internalAddress = sal_address_clone(salAddress); } +Address::Address (const GruuAddress &src) : ClonableObject(*new AddressPrivate) { + L_D(); + string uri = src.getScheme() + ":" + src.getUsername() + "@"; + if (src.getDomain().find(':') != string::npos) + uri += "[" + src.getDomain() + "]"; + else + uri += src.getDomain(); + uri += "?gr=" + src.getUrn(); + if (!(d->internalAddress = sal_address_new(L_STRING_TO_C(uri)))) { + lWarning() << "Cannot create Address, bad GruuAddress source"; + } +} + Address::Address (const SimpleAddress &src) : ClonableObject(*new AddressPrivate) { L_D(); string uri = src.getScheme() + ":" + src.getUsername() + "@"; diff --git a/src/address/address.h b/src/address/address.h index 540bf7be4..e3c5f7ef4 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -28,6 +28,7 @@ LINPHONE_BEGIN_NAMESPACE class AddressPrivate; +class GruuAddress; class SimpleAddress; class LINPHONE_PUBLIC Address : public ClonableObject { @@ -42,6 +43,7 @@ class LINPHONE_PUBLIC Address : public ClonableObject { public: explicit Address (const std::string &address = ""); Address (const Address &src); + Address (const GruuAddress &src); Address (const SimpleAddress &src); ~Address (); diff --git a/src/address/gruu-address.cpp b/src/address/gruu-address.cpp index da125764d..636e8d929 100644 --- a/src/address/gruu-address.cpp +++ b/src/address/gruu-address.cpp @@ -31,28 +31,32 @@ LINPHONE_BEGIN_NAMESPACE // ----------------------------------------------------------------------------- -GruuAddress::GruuAddress (const string &address) : SimpleAddress(address) { +GruuAddress::GruuAddress (const string &address) : SimpleAddress(*new GruuAddressPrivate) { L_D(); Address tmpAddress(address); if (tmpAddress.isValid()) { if (!tmpAddress.hasUriParam("gr")) return; + SimpleAddress base(address); + SimpleAddress::clone(base); d->urn = tmpAddress.getUriParamValue("gr"); d->valid = true; } } -GruuAddress::GruuAddress (const GruuAddress &src) : SimpleAddress(src) { +GruuAddress::GruuAddress (const GruuAddress &src) : SimpleAddress(*new GruuAddressPrivate) { L_D(); + SimpleAddress::clone(src); d->urn = src.getPrivate()->urn; d->valid = src.getPrivate()->valid; } -GruuAddress::GruuAddress (const Address &src) : SimpleAddress(src) { +GruuAddress::GruuAddress (const Address &src) : SimpleAddress(*new GruuAddressPrivate) { L_D(); if (src.isValid()) { if (!src.hasUriParam("gr")) return; + SimpleAddress::clone(SimpleAddress(src)); d->urn = src.getUriParamValue("gr"); d->valid = true; } @@ -85,9 +89,19 @@ bool GruuAddress::isValid () const { return d->valid; } +string GruuAddress::getUrn () const { + L_D(); + return d->urn; +} + +void GruuAddress::setUrn (const string &urn) { + L_D(); + d->urn = urn; +} + string GruuAddress::asString () const { Address tmpAddress(*this); - return tmpAddress.asString(); + return tmpAddress.asStringUriOnly(); } LINPHONE_END_NAMESPACE diff --git a/src/address/gruu-address.h b/src/address/gruu-address.h index 8de6a8edf..d9c5d269d 100644 --- a/src/address/gruu-address.h +++ b/src/address/gruu-address.h @@ -45,6 +45,9 @@ public: bool isValid () const; + std::string getUrn () const; + void setUrn (const std::string &urn); + std::string asString () const override; private: diff --git a/src/address/simple-address.cpp b/src/address/simple-address.cpp index cf7112390..09d539a42 100644 --- a/src/address/simple-address.cpp +++ b/src/address/simple-address.cpp @@ -55,6 +55,8 @@ SimpleAddress::SimpleAddress (const Address &src) : ClonableObject(*new SimpleAd d->domain = src.getDomain(); } +SimpleAddress::SimpleAddress (SimpleAddressPrivate &p) : ClonableObject(p) {} + SimpleAddress &SimpleAddress::operator= (const SimpleAddress &src) { L_D(); if (this != &src) { @@ -106,7 +108,14 @@ bool SimpleAddress::setDomain (const string &domain) { string SimpleAddress::asString () const { Address tmpAddress(*this); - return tmpAddress.asString(); + return tmpAddress.asStringUriOnly(); +} + +void SimpleAddress::clone (const SimpleAddress &src) { + L_D(); + d->scheme = src.getPrivate()->scheme; + d->username = src.getPrivate()->username; + d->domain = src.getPrivate()->domain; } LINPHONE_END_NAMESPACE diff --git a/src/address/simple-address.h b/src/address/simple-address.h index 991bacd01..fe01071b8 100644 --- a/src/address/simple-address.h +++ b/src/address/simple-address.h @@ -55,6 +55,10 @@ public: virtual std::string asString () const; +protected: + explicit SimpleAddress (SimpleAddressPrivate &p); + void clone (const SimpleAddress &src); + private: L_DECLARE_PRIVATE(SimpleAddress); }; diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 97bd83af2..f5d07ec37 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -102,7 +102,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyFullState (int notifyId) user.setState(StateType::full); for (const auto &device : participant->getPrivate()->getDevices()) { - const string &gruu = device.getGruu().asStringUriOnly(); + const string &gruu = device->getGruu().asString(); EndpointType endpoint = EndpointType(); endpoint.setEntity(gruu); endpoint.setState(StateType::full); @@ -127,7 +127,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const A shared_ptr p = conf->findParticipant(addr); if (p) { for (const auto &device : p->getPrivate()->getDevices()) { - const string &gruu = device.getGruu().asStringUriOnly(); + const string &gruu = device->getGruu().asString(); EndpointType endpoint = EndpointType(); endpoint.setEntity(gruu); endpoint.setState(StateType::full); diff --git a/src/conference/participant-device.cpp b/src/conference/participant-device.cpp index 16a2130c3..e7d60f385 100644 --- a/src/conference/participant-device.cpp +++ b/src/conference/participant-device.cpp @@ -25,7 +25,9 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ParticipantDevice::ParticipantDevice (const Address &gruu) { +ParticipantDevice::ParticipantDevice () {} + +ParticipantDevice::ParticipantDevice (const GruuAddress &gruu) { mGruu = gruu; } diff --git a/src/conference/participant-device.h b/src/conference/participant-device.h index 38f495b21..d889d9e22 100644 --- a/src/conference/participant-device.h +++ b/src/conference/participant-device.h @@ -20,27 +20,34 @@ #ifndef _PARTICIPANT_DEVICE_H_ #define _PARTICIPANT_DEVICE_H_ +#include #include -#include "address/address.h" +#include "address/gruu-address.h" #include "linphone/utils/general.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE +class CallSession; + class ParticipantDevice { public: - explicit ParticipantDevice (const Address &gruu); + ParticipantDevice (); + explicit ParticipantDevice (const GruuAddress &gruu); bool operator== (const ParticipantDevice &device) const; - inline const Address &getGruu () const { - return mGruu; - }; + inline const GruuAddress &getGruu () const { return mGruu; } + inline std::shared_ptr getSession () const { return mSession; } + inline void setSession (std::shared_ptr session) { mSession = session; } + + bool isValid () const { return mGruu.isValid(); } private: - Address mGruu; + GruuAddress mGruu; + std::shared_ptr mSession; }; LINPHONE_END_NAMESPACE diff --git a/src/conference/participant-p.h b/src/conference/participant-p.h index a412d4cb7..7327ee9d2 100644 --- a/src/conference/participant-p.h +++ b/src/conference/participant-p.h @@ -48,10 +48,11 @@ public: inline void setAddress (const SimpleAddress &newAddr) { addr = newAddr; } inline void setAdmin (bool isAdmin) { this->isAdmin = isAdmin; } inline void setContactAddress (const Address &contactAddr) { this->contactAddr = contactAddr; } - const std::list::const_iterator findDevice (const Address &gruu) const; - const std::list &getDevices () const; - void addDevice (const Address &gruu); - void removeDevice (const Address &gruu); + std::shared_ptr findDevice (const GruuAddress &gruu) const; + std::shared_ptr findDevice (const std::shared_ptr &session); + const std::list> &getDevices () const; + std::shared_ptr addDevice (const GruuAddress &gruu); + void removeDevice (const GruuAddress &gruu); private: SimpleAddress addr; @@ -59,7 +60,7 @@ private: bool isAdmin = false; LinphoneEvent *conferenceSubscribeEvent = nullptr; std::shared_ptr session; - std::list devices; + std::list> devices; L_DECLARE_PUBLIC(Participant); }; diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index 289b483d0..d8d1b89be 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -62,25 +62,42 @@ void ParticipantPrivate::setConferenceSubscribeEvent (LinphoneEvent *ev) { // ----------------------------------------------------------------------------- -const list::const_iterator ParticipantPrivate::findDevice (const Address &gruu) const { - ParticipantDevice device(gruu); - return find(devices.cbegin(), devices.cend(), device); +shared_ptr ParticipantPrivate::findDevice (const GruuAddress &gruu) const { + for (const auto &device : devices) { + if (device->getGruu() == gruu) + return device; + } + return nullptr; } -const list &ParticipantPrivate::getDevices () const { +shared_ptr ParticipantPrivate::findDevice (const shared_ptr &session) { + for (const auto &device : devices) { + if (device->getSession() == session) + return device; + } + return nullptr; +} + +const list> &ParticipantPrivate::getDevices () const { return devices; } -void ParticipantPrivate::addDevice (const Address &gruu) { - ParticipantDevice device(gruu); - if(findDevice(gruu) == devices.cend()) +shared_ptr ParticipantPrivate::addDevice (const GruuAddress &gruu) { + if (!findDevice(gruu)) { + shared_ptr device = make_shared(gruu); devices.push_back(device); + return device; + } + return nullptr; } -void ParticipantPrivate::removeDevice (const Address &gruu) { - ParticipantDevice device(gruu); - if(findDevice(gruu) != devices.cend()) - devices.remove(device); +void ParticipantPrivate::removeDevice (const GruuAddress &gruu) { + for (auto it = devices.begin(); it != devices.end(); it++) { + if ((*it)->getGruu() == gruu) { + devices.erase(it); + return; + } + } } // ============================================================================= From c574c641111c01a0c62bea920f969ec3953331b7 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 13 Nov 2017 13:16:46 +0100 Subject: [PATCH 0775/2215] Added asynchronism for chat message reception --- src/chat/chat-message/chat-message-p.h | 1 + src/chat/chat-message/chat-message.cpp | 56 +++++++++++++------ .../encryption-chat-message-modifier.cpp | 3 + 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index 10f572bca..3abd2f972 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -139,6 +139,7 @@ private: SalOp *salOp = nullptr; SalCustomHeader *salCustomHeaders = nullptr; unsigned char currentSendStep = Step::None; + unsigned char currentRecvStep = Step::None; bool applyModifiers = true; FileTransferChatMessageModifier fileTransferChatMessageModifier; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 43af1c22e..abb579b71 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -450,27 +450,51 @@ LinphoneReason ChatMessagePrivate::receive () { // Start of message modification // --------------------------------------- - if (internalContent.getContentType() == ContentType::Cpim) { - CpimChatMessageModifier ccmm; - ccmm.decode(q->getSharedFromThis(), errorCode); + + if ((currentRecvStep &ChatMessagePrivate::Step::Cpim) == ChatMessagePrivate::Step::Cpim) { + lInfo() << "Cpim step already done, skipping"; + } else { + if (internalContent.getContentType() == ContentType::Cpim) { + CpimChatMessageModifier ccmm; + ccmm.decode(q->getSharedFromThis(), errorCode); + } + currentRecvStep |= ChatMessagePrivate::Step::Cpim; } - EncryptionChatMessageModifier ecmm; - ChatMessageModifier::Result result = ecmm.decode(q->getSharedFromThis(), errorCode); - if (result == ChatMessageModifier::Result::Error) { - /* Unable to decrypt message */ - if (chatRoom) - chatRoom->getPrivate()->notifyUndecryptableMessageReceived(q->getSharedFromThis()); - reason = linphone_error_code_to_reason(errorCode); - q->sendDeliveryNotification(reason); - return reason; + if ((currentRecvStep &ChatMessagePrivate::Step::Encryption) == ChatMessagePrivate::Step::Encryption) { + lInfo() << "Encryption step already done, skipping"; + } else { + EncryptionChatMessageModifier ecmm; + ChatMessageModifier::Result result = ecmm.decode(q->getSharedFromThis(), errorCode); + if (result == ChatMessageModifier::Result::Error) { + /* Unable to decrypt message */ + if (chatRoom) + chatRoom->getPrivate()->notifyUndecryptableMessageReceived(q->getSharedFromThis()); + reason = linphone_error_code_to_reason(errorCode); + q->sendDeliveryNotification(reason); + return reason; + } else if (result == ChatMessageModifier::Result::Suspended) { + currentRecvStep |= ChatMessagePrivate::Step::Encryption; + return LinphoneReasonNone; + } + currentRecvStep |= ChatMessagePrivate::Step::Encryption; } - MultipartChatMessageModifier mcmm; - mcmm.decode(q->getSharedFromThis(), errorCode); + if ((currentRecvStep &ChatMessagePrivate::Step::Multipart) == ChatMessagePrivate::Step::Multipart) { + lInfo() << "Multipart step already done, skipping"; + } else { + MultipartChatMessageModifier mcmm; + mcmm.decode(q->getSharedFromThis(), errorCode); + currentRecvStep |= ChatMessagePrivate::Step::Multipart; + } - // This will check if internal content is FileTransfer and make the appropriate changes - fileTransferChatMessageModifier.decode(q->getSharedFromThis(), errorCode); + if ((currentRecvStep & ChatMessagePrivate::Step::FileUpload) == ChatMessagePrivate::Step::FileUpload) { + lInfo() << "File upload step already done, skipping"; + } else { + // This will check if internal content is FileTransfer and make the appropriate changes + fileTransferChatMessageModifier.decode(q->getSharedFromThis(), errorCode); + currentRecvStep |= ChatMessagePrivate::Step::FileUpload; + } if (contents.size() == 0) { // All previous modifiers only altered the internal content, let's fill the content list diff --git a/src/chat/modifier/encryption-chat-message-modifier.cpp b/src/chat/modifier/encryption-chat-message-modifier.cpp index 3bb3b28a0..cd9193490 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.cpp +++ b/src/chat/modifier/encryption-chat-message-modifier.cpp @@ -93,6 +93,9 @@ ChatMessageModifier::Result EncryptionChatMessageModifier::decode ( return ChatMessageModifier::Result::Skipped; message->setIsSecured(true); + if (retval == 1) + return ChatMessageModifier::Result::Suspended; + return ChatMessageModifier::Result::Done; } From 36e73b29f215a835eb2445712f2ebc8c5f1b0492 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 13 Nov 2017 13:26:41 +0100 Subject: [PATCH 0776/2215] Fixed message log --- src/chat/chat-message/chat-message.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index abb579b71..86aa4fd90 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -489,7 +489,7 @@ LinphoneReason ChatMessagePrivate::receive () { } if ((currentRecvStep & ChatMessagePrivate::Step::FileUpload) == ChatMessagePrivate::Step::FileUpload) { - lInfo() << "File upload step already done, skipping"; + lInfo() << "File download step already done, skipping"; } else { // This will check if internal content is FileTransfer and make the appropriate changes fileTransferChatMessageModifier.decode(q->getSharedFromThis(), errorCode); From fbc239661b9273ca593c672e7dbe9431fe25444a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 13 Nov 2017 16:01:22 +0100 Subject: [PATCH 0777/2215] Add API to get the remote contact of a SIP event. --- coreapi/event.c | 14 ++++++++++++++ coreapi/private.h | 1 + include/linphone/event.h | 7 +++++++ 3 files changed, 22 insertions(+) diff --git a/coreapi/event.c b/coreapi/event.c index a8fe6a043..d4e8541da 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -442,6 +442,7 @@ static void linphone_event_destroy(LinphoneEvent *lev){ if (lev->send_custom_headers) sal_custom_header_free(lev->send_custom_headers); if (lev->to_address) linphone_address_unref(lev->to_address); if (lev->from_address) linphone_address_unref(lev->from_address); + if (lev->remote_contact_address) linphone_address_unref(lev->remote_contact_address); ms_free(lev->name); } @@ -480,6 +481,15 @@ static const LinphoneAddress *_linphone_event_cache_from (const LinphoneEvent *l return lev->from_address; } +static const LinphoneAddress *_linphone_event_cache_remote_contact (const LinphoneEvent *lev) { + if (lev->remote_contact_address) + linphone_address_unref(lev->remote_contact_address); + char *buf = sal_address_as_string(lev->op->get_remote_contact_address()); + ((LinphoneEvent *)lev)->remote_contact_address = linphone_address_new(buf); + ms_free(buf); + return lev->remote_contact_address; +} + const LinphoneAddress *linphone_event_get_from (const LinphoneEvent *lev) { if (lev->is_out_of_dialog_op && lev->dir == LinphoneSubscriptionOutgoing) return _linphone_event_cache_to(lev); @@ -492,6 +502,10 @@ const LinphoneAddress *linphone_event_get_resource(const LinphoneEvent *lev){ return _linphone_event_cache_to(lev); } +const LinphoneAddress *linphone_event_get_remote_contact (const LinphoneEvent *lev) { + return _linphone_event_cache_remote_contact(lev); +} + LinphoneCore *linphone_event_get_core(const LinphoneEvent *lev){ return lev->lc; } diff --git a/coreapi/private.h b/coreapi/private.h index 630e1cdc3..2e57f4a93 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -972,6 +972,7 @@ struct _LinphoneEvent{ // Cache. LinphoneAddress *to_address; LinphoneAddress *from_address; + LinphoneAddress *remote_contact_address; }; BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneEvent); diff --git a/include/linphone/event.h b/include/linphone/event.h index b9b34686f..c49ab0167 100644 --- a/include/linphone/event.h +++ b/include/linphone/event.h @@ -191,6 +191,13 @@ LINPHONE_PUBLIC const LinphoneAddress *linphone_event_get_from(const LinphoneEve **/ LINPHONE_PUBLIC const LinphoneAddress *linphone_event_get_resource(const LinphoneEvent *lev); +/** + * Get the "contact" address of the subscription. + * @param[in] lev LinphoneEvent object + * @return The "contact" address of the subscription + */ +LINPHONE_PUBLIC const LinphoneAddress *linphone_event_get_remote_contact (const LinphoneEvent *lev); + /** * Returns back pointer to the LinphoneCore that created this LinphoneEvent **/ From c69320a15dd46f4701154a185730f97ab96fa27d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 13 Nov 2017 16:01:52 +0100 Subject: [PATCH 0778/2215] Handle sending of conference NOTIFY messages for each device. --- .../local-conference-event-handler-p.h | 3 +- .../local-conference-event-handler.cpp | 75 ++++++++++--------- src/conference/participant-device.cpp | 13 ++++ src/conference/participant-device.h | 7 ++ src/conference/participant-p.h | 8 -- src/conference/participant.cpp | 27 ++----- 6 files changed, 67 insertions(+), 66 deletions(-) diff --git a/src/conference/local-conference-event-handler-p.h b/src/conference/local-conference-event-handler-p.h index 55fefde4e..53c2761eb 100644 --- a/src/conference/local-conference-event-handler-p.h +++ b/src/conference/local-conference-event-handler-p.h @@ -35,7 +35,6 @@ public: void notifyFullState (const std::string ¬ify, const std::shared_ptr &participant); void notifyAllExcept (const std::string ¬ify, const std::shared_ptr &exceptParticipant); void notifyAll (const std::string ¬ify); - void notifyParticipant (const std::string ¬ify, const std::shared_ptr &participant); std::string createNotifyFullState (int notifyId = -1); std::string createNotifyParticipantAdded (const Address &addr, int notifyId = -1); std::string createNotifyParticipantRemoved (const Address &addr, int notifyId = -1); @@ -52,7 +51,7 @@ private: unsigned int lastNotify = 0; std::string createNotify (Xsd::ConferenceInfo::ConferenceType confInfo, int notifyId = -1, bool isFullState = false); - void sendNotify (const std::string ¬ify, const std::shared_ptr &participant); + void notifyParticipant (const std::string ¬ify, const std::shared_ptr &participant); L_DECLARE_PUBLIC(LocalConferenceEventHandler); }; diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index f5d07ec37..27a57a1ef 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -38,13 +38,13 @@ using namespace Xsd::ConferenceInfo; // ----------------------------------------------------------------------------- void LocalConferenceEventHandlerPrivate::notifyFullState (const string ¬ify, const shared_ptr &participant) { - sendNotify(notify, participant); + notifyParticipant(notify, participant); } void LocalConferenceEventHandlerPrivate::notifyAllExcept (const string ¬ify, const shared_ptr &exceptParticipant) { for (const auto &participant : conf->getParticipants()) { - if (participant->getPrivate()->isSubscribedToConferenceEventPackage() && (participant != exceptParticipant)) - sendNotify(notify, participant); + if (participant != exceptParticipant) + notifyParticipant(notify, participant); } } @@ -54,8 +54,15 @@ void LocalConferenceEventHandlerPrivate::notifyAll (const string ¬ify) { } void LocalConferenceEventHandlerPrivate::notifyParticipant (const string ¬ify, const shared_ptr &participant) { - if (participant->getPrivate()->isSubscribedToConferenceEventPackage()) - sendNotify(notify, participant); + for (const auto &device : participant->getPrivate()->getDevices()) { + if (device->isSubscribedToConferenceEventPackage()) { + LinphoneEvent *ev = device->getConferenceSubscribeEvent(); + LinphoneContent *content = linphone_core_create_content(ev->lc); + linphone_content_set_buffer(content, (const uint8_t *)notify.c_str(), strlen(notify.c_str())); + linphone_event_notify(ev, content); + linphone_content_unref(content); + } + } } string LocalConferenceEventHandlerPrivate::createNotify (ConferenceType confInfo, int notifyId, bool isFullState) { @@ -235,16 +242,6 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceRemoved return createNotify(confInfo, notifyId); } -void LocalConferenceEventHandlerPrivate::sendNotify (const string ¬ify, const shared_ptr &participant) { - LinphoneEvent *ev = participant->getPrivate()->getConferenceSubscribeEvent(); - if (!ev) - return; - LinphoneContent *content = linphone_core_create_content(ev->lc); - linphone_content_set_buffer(content, (const uint8_t *)notify.c_str(), strlen(notify.c_str())); - linphone_event_notify(ev, content); - linphone_content_unref(content); -} - // ============================================================================= LocalConferenceEventHandler::LocalConferenceEventHandler (LinphoneCore *core, LocalConference *localConf) : @@ -268,25 +265,35 @@ void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) { char *addrStr = linphone_address_as_string(lAddr); shared_ptr participant = d->conf->findParticipant(Address(addrStr)); bctbx_free(addrStr); - if (participant) { - if (linphone_event_get_subscription_state(lev) == LinphoneSubscriptionActive) { - unsigned int lastNotify = static_cast(Utils::stoi(linphone_event_get_custom_header(lev, "Last-Notify-Version"))); - if (lastNotify == 0) { - lInfo() << "Sending initial notify of conference:" << d->conf->getConferenceAddress().asStringUriOnly() << " to: " << addrStr; - participant->getPrivate()->setConferenceSubscribeEvent(lev); - d->notifyFullState(d->createNotifyFullState(), participant); - } else if (lastNotify < d->lastNotify) { - lInfo() << "Sending all missed notify for conference:" << d->conf->getConferenceAddress().asStringUriOnly() << - " from: " << lastNotify << " to: " << addrStr; - // TODO : send all missed notify from lastNotify to d->lastNotify - } else if (lastNotify > d->lastNotify) { - lError() << "last notify received by client: [" << lastNotify <<"] for confernce:" << - d->conf->getConferenceAddress().asStringUriOnly() << - " should not be higher than last notify sent by server: [" << d->lastNotify << "]."; - } - } else if (linphone_event_get_subscription_state(lev) == LinphoneSubscriptionTerminated) - participant->getPrivate()->setConferenceSubscribeEvent(nullptr); - } + if (!participant) + return; + + const LinphoneAddress *lContactAddr = linphone_event_get_remote_contact(lev); + char *contactAddrStr = linphone_address_as_string(lContactAddr); + Address contactAddr(contactAddrStr); + bctbx_free(contactAddrStr); + if (contactAddr.getUriParamValue("gr").empty()) + return; + GruuAddress gruu(contactAddr); + shared_ptr device = participant->getPrivate()->addDevice(gruu); + + if (linphone_event_get_subscription_state(lev) == LinphoneSubscriptionActive) { + unsigned int lastNotify = static_cast(Utils::stoi(linphone_event_get_custom_header(lev, "Last-Notify-Version"))); + if (lastNotify == 0) { + lInfo() << "Sending initial notify of conference:" << d->conf->getConferenceAddress().asStringUriOnly() << " to: " << participant->getAddress().asString(); + device->setConferenceSubscribeEvent(lev); + d->notifyFullState(d->createNotifyFullState(), participant); + } else if (lastNotify < d->lastNotify) { + lInfo() << "Sending all missed notify for conference:" << d->conf->getConferenceAddress().asStringUriOnly() << + " from: " << lastNotify << " to: " << participant->getAddress().asString(); + // TODO : send all missed notify from lastNotify to d->lastNotify + } else if (lastNotify > d->lastNotify) { + lError() << "last notify received by client: [" << lastNotify <<"] for conference:" << + d->conf->getConferenceAddress().asStringUriOnly() << + " should not be higher than last notify sent by server: [" << d->lastNotify << "]"; + } + } else if (linphone_event_get_subscription_state(lev) == LinphoneSubscriptionTerminated) + device->setConferenceSubscribeEvent(nullptr); } void LocalConferenceEventHandler::notifyParticipantAdded (const Address &addr) { diff --git a/src/conference/participant-device.cpp b/src/conference/participant-device.cpp index e7d60f385..7aefa714d 100644 --- a/src/conference/participant-device.cpp +++ b/src/conference/participant-device.cpp @@ -19,6 +19,8 @@ #include "participant-device.h" +#include "linphone/event.h" + using namespace std; // ============================================================================= @@ -31,8 +33,19 @@ ParticipantDevice::ParticipantDevice (const GruuAddress &gruu) { mGruu = gruu; } +ParticipantDevice::~ParticipantDevice () { + if (mConferenceSubscribeEvent) + linphone_event_unref(mConferenceSubscribeEvent); +} + bool ParticipantDevice::operator== (const ParticipantDevice &device) const { return (mGruu == device.getGruu()); } +void ParticipantDevice::setConferenceSubscribeEvent (LinphoneEvent *ev) { + if (mConferenceSubscribeEvent) + linphone_event_unref(mConferenceSubscribeEvent); + mConferenceSubscribeEvent = linphone_event_ref(ev); +} + LINPHONE_END_NAMESPACE diff --git a/src/conference/participant-device.h b/src/conference/participant-device.h index d889d9e22..890f8246e 100644 --- a/src/conference/participant-device.h +++ b/src/conference/participant-device.h @@ -24,6 +24,7 @@ #include #include "address/gruu-address.h" +#include "linphone/types.h" #include "linphone/utils/general.h" // ============================================================================= @@ -36,6 +37,7 @@ class ParticipantDevice { public: ParticipantDevice (); explicit ParticipantDevice (const GruuAddress &gruu); + virtual ~ParticipantDevice (); bool operator== (const ParticipantDevice &device) const; @@ -43,11 +45,16 @@ public: inline std::shared_ptr getSession () const { return mSession; } inline void setSession (std::shared_ptr session) { mSession = session; } + inline bool isSubscribedToConferenceEventPackage () const { return mConferenceSubscribeEvent != nullptr; } + LinphoneEvent *getConferenceSubscribeEvent () const { return mConferenceSubscribeEvent; } + void setConferenceSubscribeEvent (LinphoneEvent *ev); + bool isValid () const { return mGruu.isValid(); } private: GruuAddress mGruu; std::shared_ptr mSession; + LinphoneEvent *mConferenceSubscribeEvent = nullptr; }; LINPHONE_END_NAMESPACE diff --git a/src/conference/participant-p.h b/src/conference/participant-p.h index 7327ee9d2..2db34d89e 100644 --- a/src/conference/participant-p.h +++ b/src/conference/participant-p.h @@ -29,21 +29,14 @@ #include "conference/session/call-session-listener.h" #include "conference/params/call-session-params.h" -#include "linphone/types.h" - // ============================================================================= LINPHONE_BEGIN_NAMESPACE class ParticipantPrivate : public ObjectPrivate { public: - virtual ~ParticipantPrivate (); - std::shared_ptr createSession (const Conference &conference, const CallSessionParams *params, bool hasMedia, CallSessionListener *listener); inline std::shared_ptr getSession () const { return session; } - inline bool isSubscribedToConferenceEventPackage () const { return conferenceSubscribeEvent != nullptr; } - LinphoneEvent *getConferenceSubscribeEvent () const { return conferenceSubscribeEvent; } - void setConferenceSubscribeEvent (LinphoneEvent *ev); inline void removeSession () { session.reset(); } inline void setAddress (const SimpleAddress &newAddr) { addr = newAddr; } inline void setAdmin (bool isAdmin) { this->isAdmin = isAdmin; } @@ -58,7 +51,6 @@ private: SimpleAddress addr; Address contactAddr; bool isAdmin = false; - LinphoneEvent *conferenceSubscribeEvent = nullptr; std::shared_ptr session; std::list> devices; diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index d8d1b89be..d8be578b4 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -26,21 +26,12 @@ #include "params/media-session-params.h" #include "session/media-session.h" -#include "linphone/event.h" - using namespace std; LINPHONE_BEGIN_NAMESPACE // ============================================================================= -ParticipantPrivate::~ParticipantPrivate () { - if (conferenceSubscribeEvent) - linphone_event_unref(conferenceSubscribeEvent); -} - -// ----------------------------------------------------------------------------- - shared_ptr ParticipantPrivate::createSession ( const Conference &conference, const CallSessionParams *params, bool hasMedia, CallSessionListener *listener ) { @@ -54,14 +45,6 @@ shared_ptr ParticipantPrivate::createSession ( // ----------------------------------------------------------------------------- -void ParticipantPrivate::setConferenceSubscribeEvent (LinphoneEvent *ev) { - if (conferenceSubscribeEvent) - linphone_event_unref(conferenceSubscribeEvent); - conferenceSubscribeEvent = linphone_event_ref(ev); -} - -// ----------------------------------------------------------------------------- - shared_ptr ParticipantPrivate::findDevice (const GruuAddress &gruu) const { for (const auto &device : devices) { if (device->getGruu() == gruu) @@ -83,12 +66,12 @@ const list> &ParticipantPrivate::getDevices () con } shared_ptr ParticipantPrivate::addDevice (const GruuAddress &gruu) { - if (!findDevice(gruu)) { - shared_ptr device = make_shared(gruu); - devices.push_back(device); + shared_ptr device = findDevice(gruu); + if (device) return device; - } - return nullptr; + device = make_shared(gruu); + devices.push_back(device); + return device; } void ParticipantPrivate::removeDevice (const GruuAddress &gruu) { From 54ed679844063cefecbbf1a581b8c9bf64342d04 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 13 Nov 2017 17:02:46 +0100 Subject: [PATCH 0779/2215] fix(ChatMessage): avoid heap corruption, use delete instead of free --- src/chat/chat-message/chat-message.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 86aa4fd90..ef6b78c91 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -53,9 +53,9 @@ using namespace std; ChatMessagePrivate::ChatMessagePrivate () {} ChatMessagePrivate::~ChatMessagePrivate () { - for (Content *content : contents) { - free(content); - } + for (Content *content : contents) + delete content; + if (salOp) salOp->release(); } From 105e63f27154600fa894f06a26cbe1cb96f5620c Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 13 Nov 2017 16:47:39 +0100 Subject: [PATCH 0780/2215] feat(core): provide a local address on chat room (the core is dead now) --- coreapi/callbacks.c | 44 ++- coreapi/chat.c | 21 +- coreapi/linphonecore.c | 26 +- coreapi/private.h | 1 - coreapi/tester_utils.cpp | 16 +- include/linphone/api/c-chat-message.h | 14 - include/linphone/api/c-chat-room.h | 1 + src/c-wrapper/api/c-chat-message.cpp | 17 +- src/c-wrapper/api/c-chat-room.cpp | 25 +- src/chat/chat-message/chat-message-p.h | 39 +-- src/chat/chat-message/chat-message.cpp | 154 +++++----- src/chat/chat-message/chat-message.h | 29 +- src/chat/chat-room/basic-chat-room.cpp | 86 +++--- src/chat/chat-room/basic-chat-room.h | 36 ++- src/chat/chat-room/chat-room-id.cpp | 8 + src/chat/chat-room/chat-room-id.h | 12 + src/chat/chat-room/chat-room-p.h | 17 +- src/chat/chat-room/chat-room.cpp | 198 ++++++------- src/chat/chat-room/chat-room.h | 11 +- src/chat/chat-room/client-group-chat-room.cpp | 154 +++++----- src/chat/chat-room/client-group-chat-room.h | 35 ++- .../chat-room/real-time-text-chat-room-p.h | 13 +- .../chat-room/real-time-text-chat-room.cpp | 101 +------ src/chat/chat-room/real-time-text-chat-room.h | 29 +- src/chat/chat-room/server-group-chat-room-p.h | 5 +- .../chat-room/server-group-chat-room-stub.cpp | 34 +-- src/chat/chat-room/server-group-chat-room.h | 33 ++- .../modifier/cpim-chat-message-modifier.cpp | 4 +- .../file-transfer-chat-message-modifier.cpp | 22 +- .../file-transfer-chat-message-modifier.h | 7 +- .../multipart-chat-message-modifier.cpp | 2 +- src/core/core-chat-room.cpp | 150 ++++++---- src/core/core-p.h | 15 +- src/core/core.h | 15 +- src/db/main-db.cpp | 27 +- src/db/main-db.h | 21 +- tester/cpim-tester.cpp | 6 +- tester/main-db-tester.cpp | 278 +++++++++--------- tester/multipart-tester.cpp | 12 +- 39 files changed, 856 insertions(+), 862 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index b08409a4e..ea68b4db5 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -48,6 +48,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "conference/session/media-session.h" #include "core/core-p.h" +using namespace std; + using namespace LinphonePrivate; static void register_failure(SalOp *op); @@ -126,13 +128,12 @@ static void call_received(SalCallOp *h) { } else if (sal_address_has_param(h->get_remote_contact_address(), "text")) { linphone_address_unref(toAddr); linphone_address_unref(fromAddr); - LinphonePrivate::Address addr(h->get_to()); - if (addr.isValid()) { - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(addr)); - if (cr) { - L_GET_PRIVATE_FROM_C_OBJECT(cr, ServerGroupChatRoom)->confirmJoining(h); - return; - } + shared_ptr chatRoom = lc->cppCore->findChatRoom( + ChatRoomId(SimpleAddress(h->get_to()), SimpleAddress(h->get_from())) + ); + if (chatRoom) { + L_GET_PRIVATE(static_pointer_cast(chatRoom))->confirmJoining(h); + return; } } else { // TODO: handle media conference joining if the "text" feature tag is not present @@ -751,26 +752,25 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ if (addr.hasUriParam("method") && (addr.getUriParamValue("method") == "BYE")) { if (linphone_core_conference_server_enabled(lc)) { // Removal of a participant at the server side - LinphoneChatRoom *cr = L_GET_C_BACK_PTR( - lc->cppCore->findChatRoom(Address(op->get_to())) + shared_ptr chatRoom = lc->cppCore->findChatRoom( + ChatRoomId(SimpleAddress(op->get_to()), SimpleAddress(op->get_from())) ); - if (cr) { - Address fromAddr(op->get_from()); - std::shared_ptr participant = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(fromAddr); + if (chatRoom) { + std::shared_ptr participant = chatRoom->findParticipant(chatRoom->getLocalAddress()); if (!participant || !participant->isAdmin()) { static_cast(op)->reply(SalReasonDeclined); return; } - participant = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(addr); + participant = chatRoom->findParticipant(addr); if (participant) - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->removeParticipant(participant); + chatRoom->removeParticipant(participant); static_cast(op)->reply(SalReasonNone); return; } } else { // The server asks a participant to leave a chat room LinphoneChatRoom *cr = L_GET_C_BACK_PTR( - lc->cppCore->findChatRoom(addr) + lc->cppCore->findChatRoom(ChatRoomId(addr, SimpleAddress(op->get_from()))) ); if (cr) { L_GET_CPP_PTR_FROM_C_OBJECT(cr)->leave(); @@ -780,7 +780,9 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ static_cast(op)->reply(SalReasonDeclined); } } else if (addr.hasParam("admin")) { - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(Address(op->get_to()))); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom( + ChatRoomId(SimpleAddress(op->get_to()), SimpleAddress(op->get_from())) + )); if (cr) { Address fromAddr(op->get_from()); std::shared_ptr participant = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(fromAddr); @@ -797,16 +799,12 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ return; } } else { - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(addr)); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom( + ChatRoomId(addr, SimpleAddress(op->get_from())) + )); if (!cr) cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); - /* The following causes a crash because chat room hasn't yet a peer address. - The above call to join() will create a CallSession which will call onConferenceCreated when it'll reach the Connected state. - onConferenceCreated will then call the following commented lines, no need for them here. */ - /*L_GET_PRIVATE(lc->cppCore)->insertChatRoom(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); - L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Created); - L_GET_PRIVATE(lc->cppCore)->insertChatRoomWithDb(L_GET_CPP_PTR_FROM_C_OBJECT(cr));*/ static_cast(op)->reply(SalReasonNone); return; } diff --git a/coreapi/chat.c b/coreapi/chat.c index 352c01cd8..8ad8a7232 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -64,6 +64,13 @@ const bctbx_list_t *linphone_core_get_chat_rooms (LinphoneCore *lc) { return lc->chat_rooms; } +static LinphoneChatRoom *linphone_chat_room_new (LinphoneCore *core, const LinphoneAddress *addr) { + return L_GET_C_BACK_PTR(core->cppCore->getOrCreateBasicChatRoom( + *L_GET_CPP_PTR_FROM_C_OBJECT(addr), + linphone_core_realtime_text_enabled(core) + )); +} + LinphoneChatRoom *_linphone_core_create_chat_room_from_call(LinphoneCall *call){ LinphoneChatRoom *cr = linphone_chat_room_new(linphone_call_get_core(call), linphone_address_clone(linphone_call_get_remote_address(call))); @@ -99,20 +106,24 @@ void linphone_core_delete_chat_room (LinphoneCore *, LinphoneChatRoom *cr) { } LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const char *to) { - return L_GET_C_BACK_PTR(lc->cppCore->getOrCreateBasicChatRoom(L_C_TO_STRING(to))); + return L_GET_C_BACK_PTR(lc->cppCore->getOrCreateBasicChatRoomFromUri(L_C_TO_STRING(to))); } int linphone_core_message_received(LinphoneCore *lc, LinphonePrivate::SalOp *op, const SalMessage *sal_msg) { LinphoneReason reason = LinphoneReasonNotAcceptable; const char *peerAddress = linphone_core_conference_server_enabled(lc) ? op->get_to() : op->get_from(); - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(LinphonePrivate::Address(peerAddress))); - if (cr) - reason = L_GET_PRIVATE_FROM_C_OBJECT(cr)->messageReceived(op, sal_msg); + // TODO: Use local address. + list> chatRooms = lc->cppCore->findChatRooms( + LinphonePrivate::SimpleAddress(peerAddress) + ); + + if (!chatRooms.empty()) + reason = L_GET_PRIVATE(chatRooms.front())->messageReceived(op, sal_msg); else { LinphoneAddress *addr = linphone_address_new(sal_msg->from); linphone_address_clean(addr); - cr = linphone_core_get_chat_room(lc, addr); + LinphoneChatRoom *cr = linphone_core_get_chat_room(lc, addr); if (cr) reason = L_GET_PRIVATE_FROM_C_OBJECT(cr)->messageReceived(op, sal_msg); linphone_address_unref(addr); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 86893059d..fb06d3135 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -148,6 +148,8 @@ static void toggle_video_preview(LinphoneCore *lc, bool_t val); #define HOLD_MUSIC_WAV "toy-mono.wav" #define HOLD_MUSIC_MKV "dont_wait_too_long.mkv" +using namespace std; + using namespace LinphonePrivate; extern Sal::Callbacks linphone_sal_callbacks; @@ -2133,9 +2135,16 @@ static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEve } } else if (strcmp(notified_event, "conference") == 0) { const LinphoneAddress *resource = linphone_event_get_resource(lev); - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(*L_GET_CPP_PTR_FROM_C_OBJECT(resource))); - if (cr) - L_GET_PRIVATE_FROM_C_OBJECT(cr, ClientGroupChatRoom)->notifyReceived(linphone_content_get_string_buffer(body)); + + // TODO: Ensure it is the good solution. + list> chatRooms = lc->cppCore->findChatRooms( + SimpleAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(resource)) + ); + + if (!chatRooms.empty()) + L_GET_PRIVATE(static_pointer_cast(chatRooms.front()))->notifyReceived( + linphone_content_get_string_buffer(body) + ); } } @@ -2145,10 +2154,15 @@ static void _linphone_core_conference_subscription_state_changed(LinphoneCore *l state == LinphoneSubscriptionIncomingReceived ) { const LinphoneAddress *resource = linphone_event_get_resource(lev); - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(*L_GET_CPP_PTR_FROM_C_OBJECT(resource))); - if (cr) { + + // TODO: Ensure it is the good solution. + list> chatRooms = lc->cppCore->findChatRooms( + SimpleAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(resource)) + ); + + if (!chatRooms.empty()) { linphone_event_accept_subscription(lev); - L_GET_PRIVATE_FROM_C_OBJECT(cr, ServerGroupChatRoom)->subscribeReceived(lev); + L_GET_PRIVATE(static_pointer_cast(chatRooms.front()))->subscribeReceived(lev); } else linphone_event_deny_subscription(lev, LinphoneReasonDeclined); } diff --git a/coreapi/private.h b/coreapi/private.h index 2e57f4a93..6c28c481e 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -472,7 +472,6 @@ void _linphone_proxy_config_unregister(LinphoneProxyConfig *obj); void _linphone_proxy_config_release_ops(LinphoneProxyConfig *obj); /*chat*/ -LinphoneChatRoom * linphone_chat_room_new(LinphoneCore *core, const LinphoneAddress *addr); LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, const char *uri, const char *subject); LinphoneChatRoom *_linphone_server_group_chat_room_new (LinphoneCore *core, LinphonePrivate::SalCallOp *op); void linphone_chat_room_release(LinphoneChatRoom *cr); diff --git a/coreapi/tester_utils.cpp b/coreapi/tester_utils.cpp index 4589778a7..15523fdcc 100644 --- a/coreapi/tester_utils.cpp +++ b/coreapi/tester_utils.cpp @@ -24,6 +24,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "core/core.h" #include "c-wrapper/c-wrapper.h" +using namespace std; + +using namespace LinphonePrivate; + LinphoneVcardContext *linphone_core_get_vcard_context(const LinphoneCore *lc) { return lc->vcard_context; } @@ -53,11 +57,13 @@ bctbx_list_t **linphone_core_get_call_logs_attribute(LinphoneCore *lc) { } LinphoneChatRoom * linphone_core_find_chat_room (const LinphoneCore *lc, const LinphoneAddress *addr) { - const LinphonePrivate::Address *cppAddr = L_GET_CPP_PTR_FROM_C_OBJECT(addr); - std::shared_ptr cr = lc->cppCore->findChatRoom(*cppAddr); - if (!cr) - return nullptr; - return L_GET_C_BACK_PTR(cr); + list> chatRooms = lc->cppCore->findChatRooms( + SimpleAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr)) + ); + + if (!chatRooms.empty()) + return L_GET_C_BACK_PTR(chatRooms.front()); + return nullptr; } void linphone_core_cbs_set_auth_info_requested(LinphoneCoreCbs *cbs, LinphoneCoreAuthInfoRequestedCb cb) { diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index b00e8f9ae..8b29ed040 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -96,13 +96,6 @@ LINPHONE_PUBLIC bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage* ms */ LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_from_address(LinphoneChatMessage* msg); -/** - * Set origin of the message - * @param[in] message #LinphoneChatMessage obj - * @param[in] from #LinphoneAddress origin of this message (copied) - */ -LINPHONE_PUBLIC void linphone_chat_message_set_from_address(LinphoneChatMessage* msg, const LinphoneAddress* from); - /** * Get destination of the message * @param[in] message #LinphoneChatMessage obj @@ -110,13 +103,6 @@ LINPHONE_PUBLIC void linphone_chat_message_set_from_address(LinphoneChatMessage* */ LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_to_address(LinphoneChatMessage* msg); -/** - * Set destination of the message - * @param[in] message #LinphoneChatMessage obj - * @param[in] addr #LinphoneAddress destination of this message (copied) - */ -LINPHONE_PUBLIC void linphone_chat_message_set_to_address(LinphoneChatMessage* msg, const LinphoneAddress* addr); - /** * Get the content type of a chat message. * @param[in] message LinphoneChatMessage object diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index 61650f833..14da77ffa 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -78,6 +78,7 @@ LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message(LinphoneC * @param is_read TRUE if the message should be flagged as read, FALSE otherwise. * @param is_incoming TRUE if the message has been received, FALSE otherwise. * @return a new #LinphoneChatMessage + * @deprecated Use #linphone_chat_room_create_message() instead. Deprecated since 2017-11-14. * @donotwrap */ LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message_2(LinphoneChatRoom *cr, const char* message, const char* external_body_url, LinphoneChatMessageState state, time_t time, bool_t is_read, bool_t is_incoming); diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index c728761ee..6482a9d91 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -102,7 +102,7 @@ const char *linphone_chat_message_get_external_body_url(const LinphoneChatMessag } void linphone_chat_message_set_external_body_url(LinphoneChatMessage *msg, const char *url) { - + } time_t linphone_chat_message_get_time(const LinphoneChatMessage *msg) { @@ -180,12 +180,6 @@ const LinphoneAddress *linphone_chat_message_get_from_address(LinphoneChatMessag return msg->from; } -void linphone_chat_message_set_from_address(LinphoneChatMessage *msg, const LinphoneAddress *from) { - LinphonePrivate::Address addr; - if (from) addr = LinphonePrivate::Address(linphone_address_as_string(from)); - else L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setFromAddress(addr); -} - const LinphoneAddress *linphone_chat_message_get_to_address(LinphoneChatMessage *msg) { if (msg->to) linphone_address_unref(msg->to); @@ -193,12 +187,6 @@ const LinphoneAddress *linphone_chat_message_get_to_address(LinphoneChatMessage return msg->to; } -void linphone_chat_message_set_to_address(LinphoneChatMessage *msg, const LinphoneAddress *to) { - LinphonePrivate::Address addr; - if (to) addr = LinphonePrivate::Address(linphone_address_as_string(to)); - else L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setToAddress(addr); -} - const char *linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage *msg) { return L_STRING_TO_C(L_GET_PRIVATE_FROM_C_OBJECT(msg)->getFileTransferFilepath()); } @@ -278,7 +266,6 @@ void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMe void linphone_chat_message_deactivate(LinphoneChatMessage *msg){ L_GET_CPP_PTR_FROM_C_OBJECT(msg)->cancelFileTransfer(); - L_GET_PRIVATE_FROM_C_OBJECT(msg)->setChatRoom(nullptr); } void linphone_chat_message_send_delivery_notification(LinphoneChatMessage *msg, LinphoneReason reason) { @@ -298,7 +285,7 @@ void linphone_chat_message_add_text_content(LinphoneChatMessage *msg, const char LinphonePrivate::ContentType contentType = LinphonePrivate::ContentType::PlainText; content->setContentType(contentType); content->setBody(L_C_TO_STRING(c_content)); - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->addContent(content); + L_GET_CPP_PTR_FROM_C_OBJECT(msg)->addContent(*content); } bool_t linphone_chat_message_has_text_content(const LinphoneChatMessage *msg) { diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index ef3aa923f..153d15cc3 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -117,20 +117,10 @@ LinphoneChatMessage *linphone_chat_room_create_message_2 ( bool_t is_incoming ) { LinphoneChatMessage *msg = linphone_chat_room_create_message(cr, message); - LinphoneCore *lc = linphone_chat_room_get_core(cr); linphone_chat_message_set_external_body_url(msg, external_body_url ? ms_strdup(external_body_url) : NULL); linphone_chat_message_set_time(msg, time); linphone_chat_message_set_is_secured(msg, FALSE); linphone_chat_message_set_state(msg, state); - if (is_incoming) { - linphone_chat_message_set_incoming(msg); - linphone_chat_message_set_from_address(msg, linphone_chat_room_get_peer_address(cr)); - linphone_chat_message_set_to_address(msg, linphone_address_new(linphone_core_get_identity(lc))); - } else { - linphone_chat_message_set_outgoing(msg); - linphone_chat_message_set_to_address(msg, linphone_chat_room_get_peer_address(cr)); - linphone_chat_message_set_from_address(msg, linphone_address_new(linphone_core_get_identity(lc))); - } return msg; } @@ -172,7 +162,7 @@ LinphoneCall *linphone_chat_room_get_call (const LinphoneChatRoom *cr) { void linphone_chat_room_set_call (LinphoneChatRoom *cr, LinphoneCall *call) { if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) - L_GET_PRIVATE_FROM_C_OBJECT(cr, RealTimeTextChatRoom)->setCall(call); + L_GET_PRIVATE_FROM_C_OBJECT(cr, RealTimeTextChatRoom)->call = call; } bctbx_list_t *linphone_chat_room_get_transient_messages (const LinphoneChatRoom *cr) { @@ -210,7 +200,7 @@ bctbx_list_t *linphone_chat_room_get_history (LinphoneChatRoom *cr, int nb_messa bctbx_list_t *linphone_chat_room_get_history_events (LinphoneChatRoom *cr, int nb_events) { return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST( L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore())->mainDb->getHistory( - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getPeerAddress().asStringUriOnly(), + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getChatRoomId(), nb_events ) ); @@ -219,7 +209,7 @@ bctbx_list_t *linphone_chat_room_get_history_events (LinphoneChatRoom *cr, int n bctbx_list_t *linphone_chat_room_get_history_range_events (LinphoneChatRoom *cr, int begin, int end) { return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST( L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore())->mainDb->getHistory( - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getPeerAddress().asStringUriOnly(), + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getChatRoomId(), begin, end ) @@ -344,13 +334,6 @@ void linphone_chat_room_set_user_data (LinphoneChatRoom *cr, void *ud) { // Constructor and destructor functions. // ============================================================================= -LinphoneChatRoom *linphone_chat_room_new (LinphoneCore *core, const LinphoneAddress *addr) { - return L_GET_C_BACK_PTR(core->cppCore->getOrCreateBasicChatRoom( - *L_GET_CPP_PTR_FROM_C_OBJECT(addr), - linphone_core_realtime_text_enabled(core) - )); -} - LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, const char *uri, const char *subject) { LinphoneAddress *addr = linphone_address_new(uri); LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core, addr); @@ -363,7 +346,7 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, cons LinphonePrivate::Address me(from); LinphoneChatRoom *cr = L_INIT(ChatRoom); L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared( - core->cppCore, me, L_C_TO_STRING(uri), L_C_TO_STRING(subject)) + core->cppCore, L_C_TO_STRING(uri), me, L_C_TO_STRING(subject)) ); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); return cr; diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index 3abd2f972..d89accaa3 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -23,12 +23,13 @@ #include #include "chat/chat-message/chat-message.h" +#include "chat/chat-room/chat-room-id.h" +#include "chat/modifier/file-transfer-chat-message-modifier.h" #include "chat/notification/imdn.h" +#include "content/content-type.h" #include "content/content.h" #include "content/file-content.h" #include "content/file-transfer-content.h" -#include "chat/modifier/file-transfer-chat-message-modifier.h" -#include "content/content-type.h" #include "object/object-p.h" #include "sal/sal.h" @@ -50,12 +51,7 @@ public: Cpim = 1 << 4 }; - ChatMessagePrivate (); - ~ChatMessagePrivate (); - - void setChatRoom (std::shared_ptr chatRoom); - - // ----------------------------------------------------------------------------- + ChatMessagePrivate () = default; void setApplyModifiers (bool value) { applyModifiers = value; } @@ -67,6 +63,10 @@ public: void setIsReadOnly(bool readOnly); + inline void forceFromAddress (const SimpleAddress &fromAddress) { + this->fromAddress = fromAddress; + } + unsigned int getStorageId() const; void setStorageId(unsigned int id); @@ -110,7 +110,7 @@ public: LinphoneContent *getFileTransferInformation() const; void setFileTransferInformation(const LinphoneContent *content); - int downloadFile (); + bool downloadFile (); void sendImdn(Imdn::Type imdnType, LinphoneReason reason); @@ -118,16 +118,9 @@ public: void send(); private: - std::weak_ptr chatRoom; - Address peerAddress; - // TODO: Clean attributes. - ChatMessage::Direction direction = ChatMessage::Direction::Incoming; - ChatMessage::State state = ChatMessage::State::Idle; unsigned int storageId = 0; - Address from; - Address to; - time_t time = 0; + time_t time = ::ms_time(0); // TODO: Change me in all files. std::string id; std::string rttMessage; bool isSecured = false; @@ -148,10 +141,18 @@ private: ContentType cContentType; std::string cText; - // ----------------------------------------------------------------------------- - std::string createImdnXml(Imdn::Type imdnType, LinphoneReason reason); + // TODO: Remove my comment. VARIABLES OK. + // Do not expose. + + std::weak_ptr chatRoom; + ChatRoomId chatRoomId; + SimpleAddress fromAddress; + + ChatMessage::State state = ChatMessage::State::Idle; + ChatMessage::Direction direction = ChatMessage::Direction::Incoming; + L_DECLARE_PUBLIC(ChatMessage); }; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index ef6b78c91..eb9d3fe49 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -35,36 +35,17 @@ #include "content/file-content.h" #include "content/content.h" #include "core/core.h" - #include "logger/logger.h" + #include "ortp/b64.h" // ============================================================================= -LINPHONE_BEGIN_NAMESPACE - -using namespace B64_NAMESPACE; using namespace std; -// ============================================================================= -// ChatMessagePrivate -// ============================================================================= +using namespace B64_NAMESPACE; -ChatMessagePrivate::ChatMessagePrivate () {} - -ChatMessagePrivate::~ChatMessagePrivate () { - for (Content *content : contents) - delete content; - - if (salOp) - salOp->release(); -} - -// ----------------------------------------------------------------------------- - -void ChatMessagePrivate::setChatRoom (shared_ptr cr) { - chatRoom = cr; -} +LINPHONE_BEGIN_NAMESPACE void ChatMessagePrivate::setDirection (ChatMessage::Direction dir) { direction = dir; @@ -314,19 +295,17 @@ void ChatMessagePrivate::setFileTransferInformation (const LinphoneContent *c_co fileContent->setBody(linphone_content_get_string_buffer(c_content)); } - q->addContent(fileContent); + q->addContent(*fileContent); } -int ChatMessagePrivate::downloadFile () { +bool ChatMessagePrivate::downloadFile () { L_Q(); - for (Content *content : contents) { - if (content->getContentType() == ContentType::FileTransfer) { - return q->downloadFile((FileTransferContent*)content); - } - } + for (auto &content : contents) + if (content->getContentType() == ContentType::FileTransfer) + return q->downloadFile(*static_cast(content)); - return 0; + return false; } // ----------------------------------------------------------------------------- @@ -432,10 +411,9 @@ string ChatMessagePrivate::createImdnXml (Imdn::Type imdnType, LinphoneReason re } void ChatMessagePrivate::sendImdn (Imdn::Type imdnType, LinphoneReason reason) { - L_Q(); - shared_ptr chatRoom = q->getChatRoom(); - if (chatRoom) - chatRoom->getPrivate()->sendImdn(createImdnXml(imdnType, reason), reason); + // FIXME: Add impl. + // L_Q(); + // q->getChatRoom()->getPrivate()->sendImdn(createImdnXml(imdnType, reason), reason); } LinphoneReason ChatMessagePrivate::receive () { @@ -523,11 +501,11 @@ LinphoneReason ChatMessagePrivate::receive () { // Check if this is in fact an outgoing message (case where this is a message sent by us from an other device). Address me(linphone_core_get_identity(core->getCCore())); - if (me.weakEqual(from)) + if (me.weakEqual(q->getFromAddress())) setDirection(ChatMessage::Direction::Outgoing); // Check if this is a duplicate message. - if (chatRoom && chatRoom->findMessageWithDirection(q->getImdnMessageId(), q->getDirection())) + if (chatRoom && chatRoom->findMessageWithDirection(q->getImdnMessageId(), direction)) return core->getCCore()->chat_deny_code; if (errorCode > 0) { @@ -570,7 +548,7 @@ void ChatMessagePrivate::send () { shared_ptr core = q->getCore(); if (lp_config_get_int(core->getCCore()->config, "sip", "chat_use_call_dialogs", 0) != 0) { - call = linphone_core_get_call_by_remote_address(core->getCCore(), to.asString().c_str()); + call = linphone_core_get_call_by_remote_address(core->getCCore(), q->getToAddress().asString().c_str()); if (call) { if (linphone_call_get_state(call) == LinphoneCallConnected || linphone_call_get_state(call) == LinphoneCallStreamsRunning || linphone_call_get_state(call) == LinphoneCallPaused || linphone_call_get_state(call) == LinphoneCallPausing || @@ -579,7 +557,7 @@ void ChatMessagePrivate::send () { op = linphone_call_get_op(call); string identity = linphone_core_find_best_identity(core->getCCore(), linphone_call_get_remote_address(call)); if (identity.empty()) { - LinphoneAddress *addr = linphone_address_new(to.asString().c_str()); + LinphoneAddress *addr = linphone_address_new(q->getToAddress().asString().c_str()); LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core->getCCore(), addr); if (proxy) { identity = L_GET_CPP_PTR_FROM_C_OBJECT(linphone_proxy_config_get_identity_address(proxy))->asString(); @@ -588,13 +566,12 @@ void ChatMessagePrivate::send () { } linphone_address_unref(addr); } - q->setFromAddress(Address(identity)); } } } if (!op) { - LinphoneAddress *peer = linphone_address_new(to.asString().c_str()); + LinphoneAddress *peer = linphone_address_new(q->getToAddress().asString().c_str()); /* Sending out of call */ salOp = op = new SalMessageOp(core->getCCore()->sal); linphone_configure_op( @@ -659,18 +636,28 @@ void ChatMessagePrivate::send () { auto msgOp = dynamic_cast(op); if (internalContent.getContentType().isValid()) { - msgOp->send_message(from.asString().c_str(), to.asString().c_str(), internalContent.getContentType().asString().c_str(), internalContent.getBodyAsString().c_str(), to.asStringUriOnly().c_str()); + msgOp->send_message( + q->getFromAddress().asString().c_str(), + q->getToAddress().asString().c_str(), + internalContent.getContentType().asString().c_str(), + internalContent.getBodyAsString().c_str(), + q->getToAddress().asString().c_str() + ); } else { - msgOp->send_message(from.asString().c_str(), to.asString().c_str(), internalContent.getBodyAsString().c_str()); + msgOp->send_message( + q->getFromAddress().asString().c_str(), + q->getToAddress().asString().c_str(), + internalContent.getBodyAsString().c_str() + ); } for (Content *content : contents) { // Restore FileContents and remove FileTransferContents if (content->getContentType() == ContentType::FileTransfer) { FileTransferContent *fileTransferContent = (FileTransferContent *)content; - q->removeContent(content); - free(fileTransferContent); - q->addContent(fileTransferContent->getFileContent()); + q->removeContent(*content); + q->addContent(*fileTransferContent->getFileContent()); + delete fileTransferContent; } } @@ -683,7 +670,7 @@ void ChatMessagePrivate::send () { } /* If operation failed, we should not change message state */ - if (q->getDirection() == ChatMessage::Direction::Outgoing) { + if (direction == ChatMessage::Direction::Outgoing) { setIsReadOnly(true); setState(ChatMessage::State::InProgress); } @@ -692,13 +679,34 @@ void ChatMessagePrivate::send () { // ----------------------------------------------------------------------------- ChatMessage::ChatMessage (const shared_ptr &chatRoom) : - Object(*new ChatMessagePrivate), - CoreAccessor(chatRoom->getCore()) { + Object(*new ChatMessagePrivate), CoreAccessor(chatRoom->getCore()) { L_ASSERT(chatRoom); L_D(); d->chatRoom = chatRoom; - d->peerAddress = chatRoom->getPeerAddress(); + d->chatRoomId = chatRoom->getChatRoomId(); + d->fromAddress = chatRoom->getLocalAddress(); + d->direction = Direction::Outgoing; +} + +ChatMessage::ChatMessage (const shared_ptr &chatRoom, const SimpleAddress &fromAddress) : + Object(*new ChatMessagePrivate), CoreAccessor(chatRoom->getCore()) { + L_ASSERT(chatRoom); + L_D(); + + d->chatRoom = chatRoom; + d->chatRoomId = chatRoom->getChatRoomId(); + d->fromAddress = fromAddress; + d->direction = Direction::Incoming; +} + +ChatMessage::~ChatMessage () { + L_D(); + for (Content *content : d->contents) + delete content; + + if (d->salOp) + d->salOp->release(); } shared_ptr ChatMessage::getChatRoom () const { @@ -706,7 +714,7 @@ shared_ptr ChatMessage::getChatRoom () const { shared_ptr chatRoom = d->chatRoom.lock(); if (!chatRoom) - chatRoom = getCore()->getOrCreateBasicChatRoom(d->peerAddress); + chatRoom = getCore()->getOrCreateBasicChatRoom(d->chatRoomId); return chatRoom; } @@ -764,32 +772,24 @@ bool ChatMessage::isRead () const { return d->state == State::Delivered || d->state == State::Displayed || d->state == State::DeliveredToUser; } -const Address &ChatMessage::getFromAddress () const { +const SimpleAddress &ChatMessage::getFromAddress () const { L_D(); - return d->from; + return d->fromAddress; } -void ChatMessage::setFromAddress (Address from) { +const SimpleAddress &ChatMessage::getToAddress () const { L_D(); - d->from = from; + return d->direction == Direction::Outgoing ? d->chatRoomId.getPeerAddress() : d->chatRoomId.getLocalAddress(); } -const Address &ChatMessage::getToAddress () const { +const SimpleAddress &ChatMessage::getLocalAddress () const { L_D(); - return d->to; + return d->chatRoomId.getLocalAddress(); } -void ChatMessage::setToAddress (Address to) { +const SimpleAddress &ChatMessage::getRemoteAddress () const { L_D(); - d->to = to; -} - -const Address &ChatMessage::getLocalAddress () const { - return getDirection() == Direction::Incoming ? getToAddress() : getFromAddress(); -} - -const Address &ChatMessage::getRemoteAddress () const { - return getDirection() != Direction::Incoming ? getToAddress() : getFromAddress(); + return d->direction == Direction::Outgoing ? d->chatRoomId.getPeerAddress() : d->fromAddress; } // ----------------------------------------------------------------------------- @@ -811,18 +811,18 @@ const list &ChatMessage::getContents () const { return d->contents; } -void ChatMessage::addContent (Content *content) { +void ChatMessage::addContent (Content &content) { L_D(); if (d->isReadOnly) return; - d->contents.push_back(content); + d->contents.push_back(&content); } -void ChatMessage::removeContent (Content *content) { +void ChatMessage::removeContent (const Content &content) { L_D(); if (d->isReadOnly) return; - d->contents.remove(content); + d->contents.remove(&const_cast(content)); } const Content &ChatMessage::getInternalContent () const { @@ -918,9 +918,9 @@ void ChatMessage::sendDisplayNotification () { d->sendImdn(Imdn::Type::Display, LinphoneReasonNone); } -int ChatMessage::downloadFile(FileTransferContent *fileTransferContent) { +bool ChatMessage::downloadFile(FileTransferContent &fileTransferContent) { L_D(); - return d->fileTransferChatMessageModifier.downloadFile(getSharedFromThis(), fileTransferContent); + return d->fileTransferChatMessageModifier.downloadFile(getSharedFromThis(), &fileTransferContent); } void ChatMessage::cancelFileTransfer () { @@ -957,14 +957,14 @@ int ChatMessage::putCharacter (uint32_t character) { if (character == new_line || character == crlf || character == lf) { if (lp_config_get_int(core->getCCore()->config, "misc", "store_rtt_messages", 1) == 1) { + // TODO: History. lDebug() << "New line sent, forge a message with content " << d->rttMessage.c_str(); d->setTime(ms_time(0)); d->state = State::Displayed; - d->direction = Direction::Outgoing; - setFromAddress(LinphonePrivate::Address( - linphone_address_as_string(linphone_address_new(linphone_core_get_identity(core->getCCore()))) - )); - // TODO: History. + // d->direction = Direction::Outgoing; + // setFromAddress(Address( + // linphone_address_as_string(linphone_address_new(linphone_core_get_identity(core->getCCore()))) + // )); // linphone_chat_message_store(L_GET_C_BACK_PTR(this)); d->rttMessage = ""; } diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index 6914373f6..f2eb00bf3 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -25,6 +25,9 @@ #include "linphone/api/c-types.h" #include "linphone/enums/chat-message-enums.h" +// TODO: Remove me later? +#include "address/simple-address.h" + #include "core/core-accessor.h" #include "object/object.h" @@ -32,7 +35,6 @@ LINPHONE_BEGIN_NAMESPACE -class Address; class ChatRoom; class Content; class FileTransferContent; @@ -54,8 +56,15 @@ public: L_DECLARE_ENUM(Direction, L_ENUM_VALUES_CHAT_MESSAGE_DIRECTION); // TODO: Make me private. + + // Build an outgoing message. ChatMessage (const std::shared_ptr &chatRoom); + // Build and incoming message. + ChatMessage (const std::shared_ptr &chatRoom, const SimpleAddress &fromAddress); + + ~ChatMessage (); + // ----- TODO: Remove me. void cancelFileTransfer (); int putCharacter (uint32_t character); @@ -64,8 +73,6 @@ public: void sendDisplayNotification (); void setImdnMessageId (const std::string &imdnMessageId); void setIsSecured (bool isSecured); - void setFromAddress (Address from); - void setToAddress (Address to); void store (); // ----- TODO: Remove me. @@ -81,19 +88,21 @@ public: const std::string &getImdnMessageId () const; - const Address &getFromAddress () const; - const Address &getToAddress () const; - const Address &getLocalAddress () const; - const Address &getRemoteAddress () const; + const SimpleAddress &getFromAddress () const; + const SimpleAddress &getToAddress () const; + const SimpleAddress &getLocalAddress () const; + const SimpleAddress &getRemoteAddress () const; + + // TODO: Return a cpp reference. const LinphoneErrorInfo *getErrorInfo () const; bool isRead () const; bool isReadOnly () const; const std::list &getContents () const; - void addContent (Content *content); - void removeContent (Content *content); + void addContent (Content &content); + void removeContent (const Content &content); const Content &getInternalContent () const; void setInternalContent (const Content &content); @@ -102,7 +111,7 @@ public: void addCustomHeader (const std::string &headerName, const std::string &headerValue); void removeCustomHeader (const std::string &headerName); - int downloadFile (FileTransferContent *content); + bool downloadFile (FileTransferContent &content); private: L_DECLARE_PRIVATE(ChatMessage); diff --git a/src/chat/chat-room/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp index c67a830d2..a02a58657 100644 --- a/src/chat/chat-room/basic-chat-room.cpp +++ b/src/chat/chat-room/basic-chat-room.cpp @@ -29,43 +29,51 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -BasicChatRoom::BasicChatRoom (const shared_ptr &core, const Address &peerAddress) : - ChatRoom(*new BasicChatRoomPrivate, core, peerAddress) {} +BasicChatRoom::BasicChatRoom (const shared_ptr &core, const ChatRoomId &chatRoomId) : + ChatRoom(*new BasicChatRoomPrivate, core, chatRoomId) {} -// ----------------------------------------------------------------------------- +BasicChatRoom::BasicChatRoom ( + BasicChatRoomPrivate &p, + const std::shared_ptr &core, + const ChatRoomId &chatRoomId +) : ChatRoom(p, core, chatRoomId) {} -void BasicChatRoom::onChatMessageReceived (const shared_ptr &msg) { - -} - -int BasicChatRoom::getCapabilities () const { - return static_cast(Capabilities::Basic); -} - -void BasicChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { - lError() << "addParticipant() is not allowed on a BasicChatRoom"; -} - -void BasicChatRoom::addParticipants (const list
      &addresses, const CallSessionParams *params, bool hasMedia) { - lError() << "addParticipants() is not allowed on a BasicChatRoom"; +BasicChatRoom::CapabilitiesMask BasicChatRoom::getCapabilities () const { + return static_cast(Capabilities::Basic); } bool BasicChatRoom::canHandleParticipants () const { return false; } -shared_ptr BasicChatRoom::findParticipant (const Address &addr) const { - lError() << "findParticipant() is not allowed on a BasicChatRoom"; - return nullptr; -} - const Address &BasicChatRoom::getConferenceAddress () const { lError() << "a BasicChatRoom does not have a conference address"; return Utils::getEmptyConstRefObject
      (); } +void BasicChatRoom::addParticipant (const Address &, const CallSessionParams *, bool) { + lError() << "addParticipant() is not allowed on a BasicChatRoom"; +} + +void BasicChatRoom::addParticipants (const list
      &, const CallSessionParams *, bool) { + lError() << "addParticipants() is not allowed on a BasicChatRoom"; +} + +void BasicChatRoom::removeParticipant (const shared_ptr &) { + lError() << "removeParticipant() is not allowed on a BasicChatRoom"; +} + +void BasicChatRoom::removeParticipants (const list> &) { + lError() << "removeParticipants() is not allowed on a BasicChatRoom"; +} + +shared_ptr BasicChatRoom::findParticipant (const Address &) const { + lError() << "findParticipant() is not allowed on a BasicChatRoom"; + return nullptr; +} + shared_ptr BasicChatRoom::getMe () const { - lError() << "a BasicChatRoom does not handle participants"; + lError() << "getMe() is not allowed on a BasicChatRoom"; return nullptr; } @@ -74,10 +82,11 @@ int BasicChatRoom::getNbParticipants () const { } list> BasicChatRoom::getParticipants () const { - L_D(); - list> l; - l.push_back(make_shared(d->peerAddress)); - return l; + return { make_shared(getPeerAddress()) }; +} + +void BasicChatRoom::setParticipantAdminStatus (shared_ptr &, bool) { + lError() << "setParticipantAdminStatus() is not allowed on a BasicChatRoom"; } const string &BasicChatRoom::getSubject () const { @@ -85,6 +94,11 @@ const string &BasicChatRoom::getSubject () const { return d->subject; } +void BasicChatRoom::setSubject (const string &subject) { + L_D(); + d->subject = subject; +} + void BasicChatRoom::join () { lError() << "join() is not allowed on a BasicChatRoom"; } @@ -93,21 +107,7 @@ void BasicChatRoom::leave () { lError() << "leave() is not allowed on a BasicChatRoom"; } -void BasicChatRoom::removeParticipant (const shared_ptr &participant) { - lError() << "removeParticipant() is not allowed on a BasicChatRoom"; -} - -void BasicChatRoom::removeParticipants (const list> &participants) { - lError() << "removeParticipants() is not allowed on a BasicChatRoom"; -} - -void BasicChatRoom::setParticipantAdminStatus (shared_ptr &participant, bool isAdmin) { - lError() << "setParticipantAdminStatus() is not allowed on a BasicChatRoom"; -} - -void BasicChatRoom::setSubject (const string &subject) { - L_D(); - d->subject = subject; -} +// TODO: Move me in BasicChatRoomPrivate. +void BasicChatRoom::onChatMessageReceived (const shared_ptr &) {} LINPHONE_END_NAMESPACE diff --git a/src/chat/chat-room/basic-chat-room.h b/src/chat/chat-room/basic-chat-room.h index d4dc2e948..21268e29d 100644 --- a/src/chat/chat-room/basic-chat-room.h +++ b/src/chat/chat-room/basic-chat-room.h @@ -29,30 +29,44 @@ LINPHONE_BEGIN_NAMESPACE class BasicChatRoomPrivate; class LINPHONE_PUBLIC BasicChatRoom : public ChatRoom { -public: - BasicChatRoom (const std::shared_ptr &core, const Address &peerAddress); + friend class CorePrivate; +public: CapabilitiesMask getCapabilities () const override; - void onChatMessageReceived (const std::shared_ptr &msg) override; - /* ConferenceInterface. */ + const Address &getConferenceAddress () const override; + + bool canHandleParticipants () const override; + void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
      &addresses, const CallSessionParams *params, bool hasMedia) override; - bool canHandleParticipants () const override; + + void removeParticipant (const std::shared_ptr &participant) override; + void removeParticipants (const std::list> &participants) override; + std::shared_ptr findParticipant (const Address &addr) const override; - const Address &getConferenceAddress () const override; + std::shared_ptr getMe () const override; int getNbParticipants () const override; std::list> getParticipants () const override; - const std::string &getSubject () const override; - void join () override; - void leave () override; - void removeParticipant (const std::shared_ptr &participant) override; - void removeParticipants (const std::list> &participants) override; + void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) override; + + const std::string &getSubject () const override; void setSubject (const std::string &subject) override; + void join () override; + void leave () override; + +protected: + explicit BasicChatRoom (BasicChatRoomPrivate &p, const std::shared_ptr &core, const ChatRoomId &chatRoomId); + private: + BasicChatRoom (const std::shared_ptr &core, const ChatRoomId &chatRoomId); + + // TODO: Remove me. Move me in private object. + void onChatMessageReceived (const std::shared_ptr &msg) override; + L_DECLARE_PRIVATE(BasicChatRoom); L_DISABLE_COPY(BasicChatRoom); }; diff --git a/src/chat/chat-room/chat-room-id.cpp b/src/chat/chat-room/chat-room-id.cpp index 9f5a4482c..73c907628 100644 --- a/src/chat/chat-room/chat-room-id.cpp +++ b/src/chat/chat-room/chat-room-id.cpp @@ -35,6 +35,8 @@ public: // ----------------------------------------------------------------------------- +ChatRoomId::ChatRoomId () : ClonableObject(*new ChatRoomIdPrivate) {} + ChatRoomId::ChatRoomId ( const SimpleAddress &peerAddress, const SimpleAddress &localAddress @@ -56,6 +58,12 @@ bool ChatRoomId::operator!= (const ChatRoomId &chatRoomId) const { return !(*this == chatRoomId); } +bool ChatRoomId::operator< (const ChatRoomId &chatRoomId) const { + L_D(); + const ChatRoomIdPrivate *dChatRoomId = chatRoomId.getPrivate(); + return d->peerAddress < dChatRoomId->peerAddress || d->localAddress < dChatRoomId->localAddress; +} + const SimpleAddress &ChatRoomId::getPeerAddress () const { L_D(); return d->peerAddress; diff --git a/src/chat/chat-room/chat-room-id.h b/src/chat/chat-room/chat-room-id.h index 4703600d5..d83926611 100644 --- a/src/chat/chat-room/chat-room-id.h +++ b/src/chat/chat-room/chat-room-id.h @@ -30,6 +30,7 @@ class ChatRoomIdPrivate; class LINPHONE_PUBLIC ChatRoomId : public ClonableObject { public: + ChatRoomId (); ChatRoomId (const SimpleAddress &peerAddress, const SimpleAddress &localAddress); ChatRoomId (const ChatRoomId &src); @@ -38,6 +39,8 @@ public: bool operator== (const ChatRoomId &chatRoomId) const; bool operator!= (const ChatRoomId &chatRoomId) const; + bool operator< (const ChatRoomId &chatRoomId) const; + const SimpleAddress &getPeerAddress () const; const SimpleAddress &getLocalAddress () const; @@ -47,4 +50,13 @@ private: LINPHONE_END_NAMESPACE +// Add map key support. +template<> +struct std::hash { + std::size_t operator() (const LinphonePrivate::ChatRoomId &chatRoomId) const { + return hash()(chatRoomId.getPeerAddress().asString()) ^ + (hash()(chatRoomId.getLocalAddress().asString()) << 1); + } +}; + #endif // ifndef _CHAT_ROOM_ID_H_ diff --git a/src/chat/chat-room/chat-room-p.h b/src/chat/chat-room/chat-room-p.h index 1c4513389..be04ac5be 100644 --- a/src/chat/chat-room/chat-room-p.h +++ b/src/chat/chat-room/chat-room-p.h @@ -30,16 +30,13 @@ LINPHONE_BEGIN_NAMESPACE +// TODO: clean and order methods! class ChatRoomPrivate : public ObjectPrivate, public IsComposingListener { - friend class ChatMessagePrivate; - public: ChatRoomPrivate () = default; -private: static int createChatMessageFromDb (void *data, int argc, char **argv, char **colName); -public: void addTransientMessage (const std::shared_ptr &msg); void addWeakMessage (const std::shared_ptr &msg); std::list> getTransientMessages () const { @@ -56,40 +53,36 @@ public: virtual void sendMessage (const std::shared_ptr &msg); -protected: void sendIsComposingNotification (); int createChatMessageFromDb (int argc, char **argv, char **colName); std::shared_ptr getTransientMessage (unsigned int storageId) const; std::shared_ptr getWeakMessage (unsigned int storageId) const; std::list> findMessages (const std::string &messageId); + virtual void storeOrUpdateMessage (const std::shared_ptr &msg); -public: virtual LinphoneReason messageReceived (SalOp *op, const SalMessage *msg); void realtimeTextReceived (uint32_t character, LinphoneCall *call); -protected: void chatMessageReceived (const std::shared_ptr &msg); void imdnReceived (const std::string &text); void isComposingReceived (const Address &remoteAddr, const std::string &text); -private: void notifyChatMessageReceived (const std::shared_ptr &msg); void notifyIsComposingReceived (const Address &remoteAddr, bool isComposing); void notifyStateChanged (); void notifyUndecryptableMessageReceived (const std::shared_ptr &msg); -private: /* IsComposingListener */ void onIsComposingStateChanged (bool isComposing) override; void onIsRemoteComposingStateChanged (const Address &remoteAddr, bool isComposing) override; void onIsComposingRefreshNeeded () override; -public: + std::shared_ptr createChatMessage (ChatMessage::Direction direction); + LinphoneCall *call = nullptr; ChatRoom::State state = ChatRoom::State::None; - Address peerAddress; bool isComposing = false; std::unordered_set remoteIsComposing; std::list> transientMessages; @@ -102,6 +95,8 @@ public: // TODO: Use CoreAccessor on IsComposing. And avoid pointer if possible. std::unique_ptr isComposingHandler; + ChatRoomId chatRoomId; + private: L_DECLARE_PUBLIC(ChatRoom); }; diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 091217e49..319cce5e3 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -74,72 +74,61 @@ void ChatRoomPrivate::removeTransientMessage (const shared_ptr &msg // ----------------------------------------------------------------------------- void ChatRoomPrivate::release () { - L_Q(); isComposingHandler->stopTimers(); - // TODO: Remove me? - // Why chat room is set to nullptr? Avoid shared ptr lock?! Wtf?! - for (auto &message : weakMessages) { - try { - shared_ptr msg(message); - msg->cancelFileTransfer(); - msg->getPrivate()->setChatRoom(nullptr); - } catch (const bad_weak_ptr &) {} - } - for (auto &message : transientMessages) { - message->cancelFileTransfer(); - message->getPrivate()->setChatRoom(nullptr); - } + for (auto &message : weakMessages) + message.lock()->cancelFileTransfer(); - linphone_chat_room_unref(L_GET_C_BACK_PTR(q)); + for (auto &message : transientMessages) + message->cancelFileTransfer(); } void ChatRoomPrivate::sendImdn (const string &payload, LinphoneReason reason) { - L_Q(); - - shared_ptr core = q->getCore(); - if (!core) - return; - LinphoneCore *cCore = core->getCCore(); - - const char *identity = nullptr; - LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str()); - LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(cCore, peer); - if (proxy) - identity = linphone_address_as_string(linphone_proxy_config_get_identity_address(proxy)); - else - identity = linphone_core_get_primary_contact(cCore); - - /* Sending out of call */ - SalMessageOp *op = new SalMessageOp(cCore->sal); - linphone_configure_op(cCore, op, peer, nullptr, !!lp_config_get_int(cCore->config, "sip", "chat_msg_with_contact", 0)); - - shared_ptr msg = q->createMessage(); - msg->setFromAddress(Address(identity)); - msg->setToAddress(peerAddress); - - Content *content = new Content(); - content->setContentType("message/imdn+xml"); - content->setBody(payload); - msg->addContent(content); - - /* Do not try to encrypt the notification when it is reporting an error (maybe it should be bypassed only for some reasons). */ - int retval = -1; - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(cCore); - if (imee && (reason == LinphoneReasonNone)) { - LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); - if (cbProcessOutgoingMessage) { - retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(q), L_GET_C_BACK_PTR(msg)); - } - } - - if (retval <= 0) { - op->send_message(identity, peerAddress.asString().c_str(), msg->getPrivate()->getContentType().asString().c_str(), msg->getPrivate()->getText().c_str(), nullptr); - } - - linphone_address_unref(peer); - op->unref(); + // L_Q(); + // + // shared_ptr core = q->getCore(); + // LinphoneCore *cCore = core->getCCore(); + // + // // TODO: Use ChatRoomId. + // const char *identity = nullptr; + // LinphoneAddress *peer = linphone_address_new(q->getPeerAddress().asString().c_str()); + // LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(cCore, peer); + // if (proxy) + // identity = linphone_address_as_string(linphone_proxy_config_get_identity_address(proxy)); + // else + // identity = linphone_core_get_primary_contact(cCore); + // + // /* Sending out of call */ + // SalMessageOp *op = new SalMessageOp(cCore->sal); + // linphone_configure_op(cCore, op, peer, nullptr, !!lp_config_get_int(cCore->config, "sip", "chat_msg_with_contact", 0)); + // + // // shared_ptr msg = createChatMessage( + // // ChatMessage::Direction::Outgoing, + // // ChatRoomId(q->getPeerAddress(), Address(identity)) + // // ); + // + // Content *content = new Content(); + // content->setContentType("message/imdn+xml"); + // content->setBody(payload); + // msg->addContent(*content); + // + // /* Do not try to encrypt the notification when it is reporting an error (maybe it should be bypassed only for some reasons). */ + // int retval = -1; + // LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(cCore); + // if (imee && (reason == LinphoneReasonNone)) { + // LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); + // LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); + // if (cbProcessOutgoingMessage) { + // retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(q), L_GET_C_BACK_PTR(msg)); + // } + // } + // + // if (retval <= 0) { + // op->send_message(identity, q->getPeerAddress().asString().c_str(), msg->getPrivate()->getContentType().asString().c_str(), msg->getPrivate()->getText().c_str(), nullptr); + // } + // + // linphone_address_unref(peer); + // op->unref(); } // ----------------------------------------------------------------------------- @@ -164,9 +153,9 @@ void ChatRoomPrivate::sendIsComposingNotification () { if (!payload.empty()) { shared_ptr msg = q->createMessage(); Content *content = new Content(); - content->setContentType("application/im-iscomposing+xml"); + content->setContentType(ContentType::ImIsComposing); content->setBody(payload); - msg->addContent(content); + msg->addContent(*content); msg->getPrivate()->send(); } } @@ -174,6 +163,30 @@ void ChatRoomPrivate::sendIsComposingNotification () { // ----------------------------------------------------------------------------- +shared_ptr ChatRoomPrivate::createChatMessage (ChatMessage::Direction direction) { + // TODO: Create me. + return nullptr; +} + +// ----------------------------------------------------------------------------- + +const ChatRoomId &ChatRoom::getChatRoomId () const { + L_D(); + return d->chatRoomId; +} + +const SimpleAddress &ChatRoom::getPeerAddress () const { + L_D(); + return d->chatRoomId.getPeerAddress(); +} + +const SimpleAddress &ChatRoom::getLocalAddress () const { + L_D(); + return d->chatRoomId.getLocalAddress(); +} + +// ----------------------------------------------------------------------------- + /** * DB layout: * @@ -229,7 +242,7 @@ void ChatRoomPrivate::storeOrUpdateMessage (const shared_ptr &msg) void ChatRoomPrivate::sendMessage (const shared_ptr &msg) { L_Q(); - msg->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); + // TODO: Check direction. /* Add to transient list */ addTransientMessage(msg); @@ -267,25 +280,24 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa return reason; LinphoneCore *cCore = core->getCCore(); - msg = q->createMessage(); + msg = createChatMessage( + SimpleAddress(op->get_from()) == q->getLocalAddress() + ? ChatMessage::Direction::Outgoing + : ChatMessage::Direction::Incoming + ); Content content; content.setContentType(salMsg->content_type); content.setBody(salMsg->text ? salMsg->text : ""); msg->setInternalContent(content); - msg->setToAddress(Address(op->get_to() ? op->get_to() : linphone_core_get_identity(cCore))); - msg->setFromAddress(peerAddress); msg->getPrivate()->setTime(salMsg->time); msg->getPrivate()->setState(ChatMessage::State::Delivered); - msg->getPrivate()->setDirection(ChatMessage::Direction::Incoming); msg->setImdnMessageId(op->get_call_id()); const SalCustomHeader *ch = op->get_recv_custom_header(); if (ch) msg->getPrivate()->setSalCustomHeaders(sal_custom_header_clone(ch)); - /*if (salMsg->url) - msg->getPrivate()->setExternalBodyUrl(salMsg->url);*/ reason = msg->getPrivate()->receive(); @@ -342,8 +354,9 @@ void ChatRoomPrivate::chatMessageReceived (const shared_ptr &msg) { // Legacy notifyChatMessageReceived(msg); - remoteIsComposing.erase(msg->getFromAddress().asStringUriOnly()); - isComposingHandler->stopRemoteRefreshTimer(msg->getFromAddress().asStringUriOnly()); + const string fromAddress = msg->getFromAddress().asString(); + remoteIsComposing.erase(fromAddress); + isComposingHandler->stopRemoteRefreshTimer(fromAddress); notifyIsComposingReceived(msg->getFromAddress(), false); msg->sendDeliveryNotification(LinphoneReasonNone); } @@ -365,12 +378,14 @@ void ChatRoomPrivate::notifyChatMessageReceived (const shared_ptr & LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); if (!msg->getPrivate()->getText().empty()) { /* Legacy API */ + LinphoneAddress *fromAddress = linphone_address_new(msg->getFromAddress().asString().c_str()); linphone_core_notify_text_message_received( q->getCore()->getCCore(), cr, - L_GET_C_BACK_PTR(&msg->getFromAddress()), + fromAddress, msg->getPrivate()->getText().c_str() ); + linphone_address_unref(fromAddress); } LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsMessageReceivedCb cb = linphone_chat_room_cbs_get_message_received(cbs); @@ -433,13 +448,11 @@ void ChatRoomPrivate::onIsComposingRefreshNeeded () { // ============================================================================= -ChatRoom::ChatRoom ( - ChatRoomPrivate &p, - const shared_ptr &core, - const Address &peerAddress -) : Object(p), CoreAccessor(core) { +ChatRoom::ChatRoom (ChatRoomPrivate &p, const shared_ptr &core, const ChatRoomId &chatRoomId) : + Object(p), CoreAccessor(core) { L_D(); - d->peerAddress = peerAddress; + + d->chatRoomId = chatRoomId; d->isComposingHandler.reset(new IsComposing(core->getCCore(), d)); } @@ -457,8 +470,6 @@ void ChatRoom::compose () { shared_ptr ChatRoom::createFileTransferMessage (const LinphoneContent *initialContent) { shared_ptr chatMessage = createMessage(); - - chatMessage->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); chatMessage->getPrivate()->setFileTransferInformation(initialContent); return chatMessage; } @@ -468,17 +479,13 @@ shared_ptr ChatRoom::createMessage (const string &message) { Content *content = new Content(); content->setContentType(ContentType::PlainText); content->setBody(message); - chatMessage->addContent(content); + chatMessage->addContent(*content); return chatMessage; } shared_ptr ChatRoom::createMessage () { L_D(); - shared_ptr chatMessage = make_shared(getSharedFromThis()); - chatMessage->setToAddress(d->peerAddress); - chatMessage->setFromAddress(Address(linphone_core_get_identity(getCore()->getCCore()))); - chatMessage->getPrivate()->setTime(ms_time(0)); - return chatMessage; + return d->createChatMessage(ChatMessage::Direction::Outgoing); } void ChatRoom::deleteHistory () { @@ -517,9 +524,7 @@ list > ChatRoom::getHistory (int nbMessages) { } int ChatRoom::getHistorySize () { - L_D(); - shared_ptr core = getCore(); - return core ? core->getPrivate()->mainDb->getChatMessagesCount(d->peerAddress.asStringUriOnly()) : 0; + return getCore()->getPrivate()->mainDb->getChatMessagesCount(getChatRoomId()); } list > ChatRoom::getHistoryRange (int startm, int endm) { @@ -528,9 +533,7 @@ list > ChatRoom::getHistoryRange (int startm, int endm) } int ChatRoom::getUnreadChatMessagesCount () { - L_D(); - shared_ptr core = getCore(); - return core ? core->getPrivate()->mainDb->getUnreadChatMessagesCount(d->peerAddress.asStringUriOnly()) : 0; + return getCore()->getPrivate()->mainDb->getUnreadChatMessagesCount(getChatRoomId()); } bool ChatRoom::isRemoteComposing () const { @@ -549,13 +552,13 @@ void ChatRoom::markAsRead () { return; CorePrivate *dCore = core->getPrivate(); - const string peerAddress = d->peerAddress.asStringUriOnly(); - list> chatMessages = dCore->mainDb->getUnreadChatMessages(peerAddress); + const string peerAddress = getPeerAddress().asString(); + list> chatMessages = dCore->mainDb->getUnreadChatMessages(d->chatRoomId); for (auto &chatMessage : chatMessages) chatMessage->sendDisplayNotification(); - dCore->mainDb->markChatMessagesAsRead(peerAddress); + dCore->mainDb->markChatMessagesAsRead(d->chatRoomId); if (d->pendingMessage) { d->pendingMessage->updateState(ChatMessage::State::Displayed); @@ -565,11 +568,6 @@ void ChatRoom::markAsRead () { // ----------------------------------------------------------------------------- -const Address& ChatRoom::getPeerAddress () const { - L_D(); - return d->peerAddress; -} - ChatRoom::State ChatRoom::getState () const { L_D(); return d->state; diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index 12a3259bd..113b754b3 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -21,8 +21,8 @@ #define _CHAT_ROOM_H_ #include "chat/chat-message/chat-message.h" +#include "chat/chat-room/chat-room-id.h" #include "conference/conference-interface.h" -#include "core/core-accessor.h" // ============================================================================= @@ -47,8 +47,14 @@ public: virtual ~ChatRoom () = default; + const ChatRoomId &getChatRoomId () const; + + const SimpleAddress &getPeerAddress () const; + const SimpleAddress &getLocalAddress () const; + virtual CapabilitiesMask getCapabilities () const = 0; + // TODO: Remove useless functions. void compose (); std::shared_ptr createFileTransferMessage (const LinphoneContent *initialContent); std::shared_ptr createMessage (const std::string &msg); @@ -65,11 +71,10 @@ public: virtual void markAsRead (); - const Address &getPeerAddress () const; State getState () const; protected: - explicit ChatRoom (ChatRoomPrivate &p, const std::shared_ptr &core, const Address &address); + explicit ChatRoom (ChatRoomPrivate &p, const std::shared_ptr &core, const ChatRoomId &chatRoomId); virtual void onChatMessageReceived (const std::shared_ptr &msg) = 0; diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 2c801a177..4cf37f8f8 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -78,17 +78,27 @@ void ClientGroupChatRoomPrivate::notifyReceived (const string &body) { ClientGroupChatRoom::ClientGroupChatRoom ( const std::shared_ptr &core, - const Address &me, const std::string &factoryUri, + const SimpleAddress &me, const std::string &subject -) : ChatRoom(*new ClientGroupChatRoomPrivate, core, Address()), RemoteConference(core->getCCore(), me, nullptr) { +) : +ChatRoom(*new ClientGroupChatRoomPrivate, core, ChatRoomId(SimpleAddress(), me)), +RemoteConference(core->getCCore(), me, nullptr) { L_D_T(RemoteConference, dConference); dConference->focus = make_shared(Address(factoryUri)); RemoteConference::setSubject(subject); } -int ClientGroupChatRoom::getCapabilities () const { - return static_cast(Capabilities::Conference); +ClientGroupChatRoom::CapabilitiesMask ClientGroupChatRoom::getCapabilities () const { + return static_cast(Capabilities::Conference); +} + +bool ClientGroupChatRoom::canHandleParticipants () const { + return RemoteConference::canHandleParticipants(); +} + +const Address &ClientGroupChatRoom::getConferenceAddress () const { + return RemoteConference::getConferenceAddress(); } void ClientGroupChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { @@ -130,18 +140,28 @@ void ClientGroupChatRoom::addParticipants ( } } -bool ClientGroupChatRoom::canHandleParticipants () const { - return RemoteConference::canHandleParticipants(); +void ClientGroupChatRoom::removeParticipant (const shared_ptr &participant) { + LinphoneCore *cCore = CoreAccessor::getCore()->getCCore(); + + SalReferOp *referOp = new SalReferOp(cCore->sal); + LinphoneAddress *lAddr = linphone_address_new(getConferenceAddress().asString().c_str()); + linphone_configure_op(cCore, referOp, lAddr, nullptr, false); + linphone_address_unref(lAddr); + Address referToAddr = participant->getAddress(); + referToAddr.setParam("text"); + referToAddr.setUriParam("method", "BYE"); + referOp->send_refer(referToAddr.getPrivate()->getInternalAddress()); + referOp->unref(); +} + +void ClientGroupChatRoom::removeParticipants (const list> &participants) { + RemoteConference::removeParticipants(participants); } shared_ptr ClientGroupChatRoom::findParticipant (const Address &addr) const { return RemoteConference::findParticipant(addr); } -const Address &ClientGroupChatRoom::getConferenceAddress () const { - return RemoteConference::getConferenceAddress(); -} - shared_ptr ClientGroupChatRoom::getMe () const { return RemoteConference::getMe(); } @@ -154,10 +174,55 @@ list> ClientGroupChatRoom::getParticipants () const { return RemoteConference::getParticipants(); } +void ClientGroupChatRoom::setParticipantAdminStatus (shared_ptr &participant, bool isAdmin) { + if (isAdmin == participant->isAdmin()) + return; + + if (!getMe()->isAdmin()) { + lError() << "Cannot change the participant admin status because I am not admin"; + return; + } + + LinphoneCore *cCore = CoreAccessor::getCore()->getCCore(); + + SalReferOp *referOp = new SalReferOp(cCore->sal); + LinphoneAddress *lAddr = linphone_address_new(getConferenceAddress().asString().c_str()); + linphone_configure_op(cCore, referOp, lAddr, nullptr, false); + linphone_address_unref(lAddr); + Address referToAddr = participant->getAddress(); + referToAddr.setParam("text"); + referToAddr.setParam("admin", Utils::toString(isAdmin)); + referOp->send_refer(referToAddr.getPrivate()->getInternalAddress()); + referOp->unref(); +} + const string &ClientGroupChatRoom::getSubject () const { return RemoteConference::getSubject(); } +void ClientGroupChatRoom::setSubject (const string &subject) { + L_D(); + L_D_T(RemoteConference, dConference); + + if (d->state != ChatRoom::State::Created) { + lError() << "Cannot change the ClientGroupChatRoom subject in a state other than Created"; + return; + } + + if (!getMe()->isAdmin()) { + lError() << "Cannot change the ClientGroupChatRoom subject because I am not admin"; + return; + } + + shared_ptr session = dConference->focus->getPrivate()->getSession(); + if (session) + session->update(nullptr, subject); + else { + session = d->createSession(); + session->startInvite(nullptr, subject, nullptr); + } +} + void ClientGroupChatRoom::join () { L_D(); L_D_T(RemoteConference, dConference); @@ -187,80 +252,15 @@ void ClientGroupChatRoom::leave () { d->setState(ChatRoom::State::TerminationPending); } -void ClientGroupChatRoom::removeParticipant (const shared_ptr &participant) { - LinphoneCore *cCore = CoreAccessor::getCore()->getCCore(); - - SalReferOp *referOp = new SalReferOp(cCore->sal); - LinphoneAddress *lAddr = linphone_address_new(getConferenceAddress().asString().c_str()); - linphone_configure_op(cCore, referOp, lAddr, nullptr, false); - linphone_address_unref(lAddr); - Address referToAddr = participant->getAddress(); - referToAddr.setParam("text"); - referToAddr.setUriParam("method", "BYE"); - referOp->send_refer(referToAddr.getPrivate()->getInternalAddress()); - referOp->unref(); -} - -void ClientGroupChatRoom::removeParticipants (const list> &participants) { - RemoteConference::removeParticipants(participants); -} - -void ClientGroupChatRoom::setParticipantAdminStatus (shared_ptr &participant, bool isAdmin) { - if (isAdmin == participant->isAdmin()) - return; - - if (!getMe()->isAdmin()) { - lError() << "Cannot change the participant admin status because I am not admin"; - return; - } - - LinphoneCore *cCore = CoreAccessor::getCore()->getCCore(); - - SalReferOp *referOp = new SalReferOp(cCore->sal); - LinphoneAddress *lAddr = linphone_address_new(getConferenceAddress().asString().c_str()); - linphone_configure_op(cCore, referOp, lAddr, nullptr, false); - linphone_address_unref(lAddr); - Address referToAddr = participant->getAddress(); - referToAddr.setParam("text"); - referToAddr.setParam("admin", Utils::toString(isAdmin)); - referOp->send_refer(referToAddr.getPrivate()->getInternalAddress()); - referOp->unref(); -} - -void ClientGroupChatRoom::setSubject (const string &subject) { - L_D(); - L_D_T(RemoteConference, dConference); - - if (d->state != ChatRoom::State::Created) { - lError() << "Cannot change the ClientGroupChatRoom subject in a state other than Created"; - return; - } - - if (!getMe()->isAdmin()) { - lError() << "Cannot change the ClientGroupChatRoom subject because I am not admin"; - return; - } - - shared_ptr session = dConference->focus->getPrivate()->getSession(); - if (session) - session->update(nullptr, subject); - else { - session = d->createSession(); - session->startInvite(nullptr, subject, nullptr); - } -} - // ----------------------------------------------------------------------------- -void ClientGroupChatRoom::onChatMessageReceived (const shared_ptr &msg) { - -} +void ClientGroupChatRoom::onChatMessageReceived (const shared_ptr &msg) {} void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { L_D(); L_D_T(RemoteConference, dConference); dConference->conferenceAddress = addr; - d->peerAddress = addr; + d->chatRoomId = ChatRoomId(addr, d->chatRoomId.getLocalAddress()); CoreAccessor::getCore()->getPrivate()->insertChatRoom(getSharedFromThis()); } diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 709684167..584d72601 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -34,35 +34,43 @@ public: // TODO: Make me private. ClientGroupChatRoom ( const std::shared_ptr &core, - const Address &me, const std::string &factoryUri, + const SimpleAddress &me, const std::string &subject ); CapabilitiesMask getCapabilities () const override; - /* ConferenceInterface */ + const Address &getConferenceAddress () const override; + + bool canHandleParticipants () const override; + void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
      &addresses, const CallSessionParams *params, bool hasMedia) override; - bool canHandleParticipants () const override; + + void removeParticipant (const std::shared_ptr &participant) override; + void removeParticipants (const std::list> &participants) override; + std::shared_ptr findParticipant (const Address &addr) const override; - const Address &getConferenceAddress () const override; + std::shared_ptr getMe () const override; int getNbParticipants () const override; std::list> getParticipants () const override; - const std::string &getSubject () const override; - void join () override; - void leave () override; - void removeParticipant (const std::shared_ptr &participant) override; - void removeParticipants (const std::list> &participants) override; + void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) override; + + const std::string &getSubject () const override; void setSubject (const std::string &subject) override; -protected: - void onChatMessageReceived (const std::shared_ptr &msg) override; + void join () override; + void leave () override; private: - /* ConferenceListener */ + // TODO: Move me in ClientGroupChatRoomPrivate. + // ALL METHODS AFTER THIS POINT. + + void onChatMessageReceived (const std::shared_ptr &msg) override; + void onConferenceCreated (const Address &addr) override; void onConferenceTerminated (const Address &addr) override; void onFirstNotifyReceived (const Address &addr) override; @@ -73,12 +81,9 @@ private: void onParticipantDeviceAdded (const std::shared_ptr &event, bool isFullState) override; void onParticipantDeviceRemoved (const std::shared_ptr &event, bool isFullState) override; -private: - /* CallSessionListener */ void onCallSessionSetReleased (const std::shared_ptr &session) override; void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) override; -private: L_DECLARE_PRIVATE(ClientGroupChatRoom); L_DISABLE_COPY(ClientGroupChatRoom); }; diff --git a/src/chat/chat-room/real-time-text-chat-room-p.h b/src/chat/chat-room/real-time-text-chat-room-p.h index 91c2a9cbb..c07697a38 100644 --- a/src/chat/chat-room/real-time-text-chat-room-p.h +++ b/src/chat/chat-room/real-time-text-chat-room-p.h @@ -20,35 +20,26 @@ #ifndef _REAL_TIME_TEXT_CHAT_ROOM_P_H_ #define _REAL_TIME_TEXT_CHAT_ROOM_P_H_ -#include "chat/chat-room/chat-room-p.h" +#include "chat/chat-room/basic-chat-room-p.h" #include "chat/chat-room/real-time-text-chat-room.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE -class RealTimeTextChatRoomPrivate : public ChatRoomPrivate { +class RealTimeTextChatRoomPrivate : public BasicChatRoomPrivate { public: RealTimeTextChatRoomPrivate () = default; ~RealTimeTextChatRoomPrivate (); -public: - void setCall (LinphoneCall *call) { - this->call = call; - } - void realtimeTextReceived (uint32_t character, LinphoneCall *call); - void sendMessage (const std::shared_ptr &msg) override; -public: LinphoneCall *call = nullptr; std::list receivedRttCharacters; std::shared_ptr pendingMessage = nullptr; private: - std::string subject; - L_DECLARE_PUBLIC(RealTimeTextChatRoom); }; diff --git a/src/chat/chat-room/real-time-text-chat-room.cpp b/src/chat/chat-room/real-time-text-chat-room.cpp index fa7acf95f..d4ed5ee45 100644 --- a/src/chat/chat-room/real-time-text-chat-room.cpp +++ b/src/chat/chat-room/real-time-text-chat-room.cpp @@ -58,20 +58,21 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp cmc->has_been_read = FALSE; receivedRttCharacters.push_back(cmc); - remoteIsComposing.insert(peerAddress.asStringUriOnly()); + remoteIsComposing.insert(q->getPeerAddress().asString()); linphone_core_notify_is_composing_received(cCore, L_GET_C_BACK_PTR(q)); if ((character == new_line) || (character == crlf) || (character == lf)) { /* End of message */ lDebug() << "New line received, forge a message with content " << pendingMessage->getPrivate()->getText().c_str(); - pendingMessage->setFromAddress(peerAddress); - pendingMessage->setToAddress( - Address( - linphone_call_get_dest_proxy(call) - ? linphone_address_as_string(linphone_call_get_dest_proxy(call)->identity_address) - : linphone_core_get_identity(cCore) - ) - ); + // TODO: REPAIR ME. + // pendingMessage->setFromAddress(peerAddress); + // pendingMessage->setToAddress( + // Address( + // linphone_call_get_dest_proxy(call) + // ? linphone_address_as_string(linphone_call_get_dest_proxy(call)->identity_address) + // : linphone_core_get_identity(cCore) + // ) + // ); pendingMessage->getPrivate()->setState(ChatMessage::State::Delivered); pendingMessage->getPrivate()->setDirection(ChatMessage::Direction::Incoming); @@ -93,7 +94,7 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp } } -void RealTimeTextChatRoomPrivate::sendMessage (const std::shared_ptr &msg) { +void RealTimeTextChatRoomPrivate::sendMessage (const shared_ptr &msg) { if (call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) { uint32_t new_line = 0x2028; msg->putCharacter(new_line); @@ -102,11 +103,11 @@ void RealTimeTextChatRoomPrivate::sendMessage (const std::shared_ptr &core, const Address &peerAddress) : - ChatRoom(*new RealTimeTextChatRoomPrivate, core, peerAddress) {} +RealTimeTextChatRoom::RealTimeTextChatRoom (const shared_ptr &core, const ChatRoomId &chatRoomId) : + BasicChatRoom(*new RealTimeTextChatRoomPrivate, core, chatRoomId) {} -int RealTimeTextChatRoom::getCapabilities () const { - return static_cast(Capabilities::Basic) | static_cast(Capabilities::RealTimeText); +RealTimeTextChatRoom::CapabilitiesMask RealTimeTextChatRoom::getCapabilities () const { + return BasicChatRoom::getCapabilities() | static_cast(Capabilities::RealTimeText); } uint32_t RealTimeTextChatRoom::getChar () const { @@ -129,76 +130,4 @@ LinphoneCall *RealTimeTextChatRoom::getCall () const { return d->call; } -// ----------------------------------------------------------------------------- - -void RealTimeTextChatRoom::onChatMessageReceived(const shared_ptr &msg) {} - -void RealTimeTextChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { - lError() << "addParticipant() is not allowed on a RealTimeTextChatRoom"; -} - -void RealTimeTextChatRoom::addParticipants (const list
      &addresses, const CallSessionParams *params, bool hasMedia) { - lError() << "addParticipants() is not allowed on a RealTimeTextChatRoom"; -} - -bool RealTimeTextChatRoom::canHandleParticipants () const { - return false; -} - -shared_ptr RealTimeTextChatRoom::findParticipant (const Address &addr) const { - lError() << "findParticipant() is not allowed on a RealTimeTextChatRoom"; - return nullptr; -} - -const Address &RealTimeTextChatRoom::getConferenceAddress () const { - lError() << "a RealTimeTextChatRoom does not have a conference address"; - return Utils::getEmptyConstRefObject
      (); -} - -shared_ptr RealTimeTextChatRoom::getMe () const { - lError() << "a RealTimeTextChatRoom does not handle participants"; - return nullptr; -} - -int RealTimeTextChatRoom::getNbParticipants () const { - return 1; -} - -list> RealTimeTextChatRoom::getParticipants () const { - L_D(); - list> l; - l.push_back(make_shared(d->peerAddress)); - return l; -} - -const string &RealTimeTextChatRoom::getSubject () const { - L_D(); - return d->subject; -} - -void RealTimeTextChatRoom::join () { - lError() << "join() is not allowed on a RealTimeTextChatRoom"; -} - -void RealTimeTextChatRoom::leave () { - lError() << "leave() is not allowed on a RealTimeTextChatRoom"; -} - -void RealTimeTextChatRoom::removeParticipant (const shared_ptr &participant) { - lError() << "removeParticipant() is not allowed on a RealTimeTextChatRoom"; -} - -void RealTimeTextChatRoom::removeParticipants (const list> &participants) { - lError() << "removeParticipants() is not allowed on a RealTimeTextChatRoom"; -} - -void RealTimeTextChatRoom::setParticipantAdminStatus (shared_ptr &participant, bool isAdmin) { - lError() << "setParticipantAdminStatus() is not allowed on a RealTimeTextChatRoom"; -} - -void RealTimeTextChatRoom::setSubject (const string &subject) { - L_D(); - d->subject = subject; -} - LINPHONE_END_NAMESPACE diff --git a/src/chat/chat-room/real-time-text-chat-room.h b/src/chat/chat-room/real-time-text-chat-room.h index 6a89593a3..216c52113 100644 --- a/src/chat/chat-room/real-time-text-chat-room.h +++ b/src/chat/chat-room/real-time-text-chat-room.h @@ -20,7 +20,7 @@ #ifndef _REAL_TIME_TEXT_CHAT_ROOM_H_ #define _REAL_TIME_TEXT_CHAT_ROOM_H_ -#include "chat/chat-room/chat-room.h" +#include "chat/chat-room/basic-chat-room.h" // ============================================================================= @@ -28,35 +28,18 @@ LINPHONE_BEGIN_NAMESPACE class RealTimeTextChatRoomPrivate; -class LINPHONE_PUBLIC RealTimeTextChatRoom : public ChatRoom { -public: - // TODO: Make me private. - RealTimeTextChatRoom (const std::shared_ptr &core, const Address &peerAddress); +class LINPHONE_PUBLIC RealTimeTextChatRoom : public BasicChatRoom { + friend class CorePrivate; +public: CapabilitiesMask getCapabilities () const override; uint32_t getChar () const; LinphoneCall *getCall () const; - void onChatMessageReceived (const std::shared_ptr &msg) override; - /* ConferenceInterface */ - void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; - void addParticipants (const std::list
      &addresses, const CallSessionParams *params, bool hasMedia) override; - bool canHandleParticipants () const override; - std::shared_ptr findParticipant (const Address &addr) const override; - const Address &getConferenceAddress () const override; - std::shared_ptr getMe () const override; - int getNbParticipants () const override; - std::list> getParticipants () const override; - const std::string &getSubject () const override; - void join () override; - void leave () override; - void removeParticipant (const std::shared_ptr &participant) override; - void removeParticipants (const std::list> &participants) override; - void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) override; - void setSubject (const std::string &subject) override; - private: + RealTimeTextChatRoom (const std::shared_ptr &core, const ChatRoomId &chatRoomId); + L_DECLARE_PRIVATE(RealTimeTextChatRoom); L_DISABLE_COPY(RealTimeTextChatRoom); }; diff --git a/src/chat/chat-room/server-group-chat-room-p.h b/src/chat/chat-room/server-group-chat-room-p.h index d5c2e7bbc..b288e0979 100644 --- a/src/chat/chat-room/server-group-chat-room-p.h +++ b/src/chat/chat-room/server-group-chat-room-p.h @@ -54,10 +54,9 @@ private: void designateAdmin (); bool isAdminLeft () const; -private: - L_DECLARE_PUBLIC(ServerGroupChatRoom); - std::list> removedParticipants; + + L_DECLARE_PUBLIC(ServerGroupChatRoom); }; LINPHONE_END_NAMESPACE diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index 35493ede0..bc89f2ba1 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -74,33 +74,33 @@ bool ServerGroupChatRoomPrivate::isAdminLeft () const { // ============================================================================= ServerGroupChatRoom::ServerGroupChatRoom (const shared_ptr &core, SalCallOp *op) : - ChatRoom(*new ServerGroupChatRoomPrivate, core, Address(op->get_to())), + ChatRoom(*new ServerGroupChatRoomPrivate, core, ChatRoomId(SimpleAddress(op->get_to()), SimpleAddress())), LocalConference(core->getCCore(), Address(op->get_to()), nullptr) {} int ServerGroupChatRoom::getCapabilities () const { return 0; } -// ----------------------------------------------------------------------------- - -void ServerGroupChatRoom::onChatMessageReceived(const shared_ptr &msg) {} +bool ServerGroupChatRoom::canHandleParticipants () const { + return false; +} void ServerGroupChatRoom::addParticipant (const Address &, const CallSessionParams *, bool) {} void ServerGroupChatRoom::addParticipants (const list
      &, const CallSessionParams *, bool) {} -bool ServerGroupChatRoom::canHandleParticipants () const { - return false; +const Address &ServerGroupChatRoom::getConferenceAddress () const { + return LocalConference::getConferenceAddress(); } +void ServerGroupChatRoom::removeParticipant (const shared_ptr &) {} + +void ServerGroupChatRoom::removeParticipants (const list> &) {} + shared_ptr ServerGroupChatRoom::findParticipant (const Address &) const { return nullptr; } -const Address &ServerGroupChatRoom::getConferenceAddress () const { - return LocalConference::getConferenceAddress(); -} - shared_ptr ServerGroupChatRoom::getMe () const { return nullptr; } @@ -113,24 +113,22 @@ list> ServerGroupChatRoom::getParticipants () const { return LocalConference::getParticipants(); } +void ServerGroupChatRoom::setParticipantAdminStatus (shared_ptr &, bool) {} + const string &ServerGroupChatRoom::getSubject () const { return LocalConference::getSubject(); } +void ServerGroupChatRoom::setSubject (const string &) {} + void ServerGroupChatRoom::join () {} void ServerGroupChatRoom::leave () {} -void ServerGroupChatRoom::removeParticipant (const shared_ptr &) {} - -void ServerGroupChatRoom::removeParticipants (const list> &) {} - -void ServerGroupChatRoom::setParticipantAdminStatus (shared_ptr &, bool) {} - -void ServerGroupChatRoom::setSubject (const string &) {} - // ----------------------------------------------------------------------------- +void ServerGroupChatRoom::onChatMessageReceived(const shared_ptr &msg) {} + void ServerGroupChatRoom::onCallSessionStateChanged ( const shared_ptr &, LinphoneCallState, diff --git a/src/chat/chat-room/server-group-chat-room.h b/src/chat/chat-room/server-group-chat-room.h index fc2c21918..f57606722 100644 --- a/src/chat/chat-room/server-group-chat-room.h +++ b/src/chat/chat-room/server-group-chat-room.h @@ -36,33 +36,40 @@ class ServerGroupChatRoomPrivate; class ServerGroupChatRoom : public ChatRoom, public LocalConference { public: + // TODO: Make me private! ServerGroupChatRoom (const std::shared_ptr &core, SalCallOp *op); - int getCapabilities () const override; + CapabilitiesMask getCapabilities () const override; + + const Address &getConferenceAddress () const override; + + bool canHandleParticipants () const override; - /* ConferenceInterface */ void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
      &addresses, const CallSessionParams *params, bool hasMedia) override; - bool canHandleParticipants () const override; + + void removeParticipant (const std::shared_ptr &participant) override; + void removeParticipants (const std::list> &participants) override; + std::shared_ptr findParticipant (const Address &addr) const override; - const Address &getConferenceAddress () const override; + std::shared_ptr getMe () const override; int getNbParticipants () const override; std::list> getParticipants () const override; - const std::string &getSubject () const override; - void join () override; - void leave () override; - void removeParticipant (const std::shared_ptr &participant) override; - void removeParticipants (const std::list> &participants) override; + void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) override; + + const std::string &getSubject () const override; void setSubject (const std::string &subject) override; -private: - void onChatMessageReceived (const std::shared_ptr &msg) override; - /* CallSessionListener */ - void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) override; + void join () override; + void leave () override; private: + // TODO: Move me in ServerGroupChatRoomPrivate. + void onChatMessageReceived (const std::shared_ptr &msg) override; + void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) override; + L_DECLARE_PRIVATE(ServerGroupChatRoom); L_DISABLE_COPY(ServerGroupChatRoom); }; diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index f96e28941..b3de39ef5 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -133,9 +133,7 @@ ChatMessageModifier::Result CpimChatMessageModifier::decode (const shared_ptrsetInternalContent(newContent); if (cpimFromAddress.isValid()) - message->setFromAddress(cpimFromAddress); - if (cpimToAddress.isValid()) - message->setToAddress(cpimToAddress); + message->getPrivate()->forceFromAddress(cpimFromAddress); return ChatMessageModifier::Result::Done; } diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.cpp b/src/chat/modifier/file-transfer-chat-message-modifier.cpp index 38f01d55e..377be8e81 100644 --- a/src/chat/modifier/file-transfer-chat-message-modifier.cpp +++ b/src/chat/modifier/file-transfer-chat-message-modifier.cpp @@ -370,8 +370,8 @@ void FileTransferChatMessageModifier::processResponseFromPostFile (const belle_h fileTransferContent->setFileContent(fileContent); fileTransferContent->setBody(body); - chatMessage->removeContent(fileContent); - chatMessage->addContent(fileTransferContent); + chatMessage->removeContent(*fileContent); + chatMessage->addContent(*fileTransferContent); chatMessage->updateState(ChatMessage::State::FileTransferDone); releaseHttpRequest(); @@ -525,7 +525,7 @@ static void fillFileTransferContentInformationsFromVndGsmaRcsFtHttpXml(FileTrans if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) { xmlChar *filename = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); fileTransferContent->setFileName((char *)filename); - + xmlFree(filename); } if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) { @@ -558,7 +558,7 @@ ChatMessageModifier::Result FileTransferChatMessageModifier::decode (const share fileTransferContent->setContentType(internalContent.getContentType()); fileTransferContent->setBody(internalContent.getBody()); fillFileTransferContentInformationsFromVndGsmaRcsFtHttpXml(fileTransferContent); - chatMessage->addContent(fileTransferContent); + chatMessage->addContent(*fileTransferContent); return ChatMessageModifier::Result::Done; } else { for (Content *content : chatMessage->getContents()) { @@ -603,7 +603,7 @@ static void createFileTransferInformationsFromVndGsmaRcsFtHttpXml (FileTransferC if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) { xmlChar *filename = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); fileContent->setFileName((char *)filename); - + xmlFree(filename); } if (!xmlStrcmp(cur->name, (const xmlChar *)"content-type")) { @@ -765,12 +765,12 @@ void FileTransferChatMessageModifier::onRecvEnd (belle_sip_user_body_handler_t * if (retval <= 0 && chatMessage->getState() != ChatMessage::State::FileTransferError) { // Remove the FileTransferContent from the message and store the FileContent FileContent *fileContent = currentFileContentToTransfer; - chatMessage->addContent(fileContent); + chatMessage->addContent(*fileContent); for (Content *content : chatMessage->getContents()) { if (content->getContentType() == ContentType::FileTransfer) { FileTransferContent *fileTransferContent = (FileTransferContent*)content; if (fileTransferContent->getFileContent() == fileContent) { - chatMessage->removeContent(content); + chatMessage->removeContent(*content); free(fileTransferContent); break; } @@ -818,7 +818,7 @@ void FileTransferChatMessageModifier::processResponseHeadersFromGetFile (const b if (currentFileContentToTransfer == nullptr) { lWarning() << "No file transfer information for msg [" << this << "]: creating..."; FileContent *content = createFileTransferInformationFromHeaders(response); - chatMessage->addContent(content); + chatMessage->addContent(*content); } else { belle_sip_header_content_length_t *content_length_hdr = BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(response, "Content-Length")); currentFileContentToTransfer->setFileSize(belle_sip_header_content_length_get_content_length(content_length_hdr)); @@ -889,7 +889,7 @@ void FileTransferChatMessageModifier::processResponseFromGetFile (const belle_ht int FileTransferChatMessageModifier::downloadFile(const shared_ptr &message, FileTransferContent *fileTransferContent) { chatMessage = message; - + if (httpRequest) { lError() << "linphone_chat_message_download_file(): there is already a download in progress"; return -1; @@ -906,12 +906,12 @@ int FileTransferChatMessageModifier::downloadFile(const shared_ptr if (currentFileContentToTransfer == nullptr) { return -1; } - + // THIS IS ONLY FOR BACKWARD C API COMPAT if (currentFileContentToTransfer->getFilePath().empty() && !chatMessage->getPrivate()->getFileTransferFilepath().empty()) { currentFileContentToTransfer->setFilePath(chatMessage->getPrivate()->getFileTransferFilepath()); } - + belle_http_request_listener_callbacks_t cbs = { 0 }; cbs.process_response_headers = _chat_process_response_headers_from_get_file; cbs.process_response = _chat_message_process_response_from_get_file; diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.h b/src/chat/modifier/file-transfer-chat-message-modifier.h index 81c67cf76..ba758a2d9 100644 --- a/src/chat/modifier/file-transfer-chat-message-modifier.h +++ b/src/chat/modifier/file-transfer-chat-message-modifier.h @@ -20,13 +20,18 @@ #ifndef _FILE_TRANSFER_CHAT_MESSAGE_MODIFIER_H_ #define _FILE_TRANSFER_CHAT_MESSAGE_MODIFIER_H_ +#include + #include "chat-message-modifier.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE +class ChatRoom; class Core; +class FileContent; +class FileTransferContent; class FileTransferChatMessageModifier : public ChatMessageModifier { public: @@ -37,7 +42,7 @@ public: belle_http_request_t *getHttpRequest() const; void setHttpRequest(belle_http_request_t *request); - + int onSendBody (belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, size_t offset, uint8_t *buffer, size_t *size); void onSendEnd (belle_sip_user_body_handler_t *bh); void fileUploadBackgroundTaskEnded(); diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index 59b1d840f..e10bc1de3 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -120,7 +120,7 @@ ChatMessageModifier::Result MultipartChatMessageModifier::decode (const shared_p } content->setContentType(contentType); content->setBody(contentBody); - message->addContent(content); + message->addContent(*content); lInfo() << "Parsed and added content with type " << contentType.asString(); } diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 369d9ea17..fc10049ff 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -40,30 +40,59 @@ LINPHONE_BEGIN_NAMESPACE // ----------------------------------------------------------------------------- // TODO: Remove me later. -static inline string resolveWorkaroundClientGroupChatRoomAddress ( +static inline ChatRoomId resolveWorkaroundClientGroupChatRoomId ( const CorePrivate &corePrivate, - const SimpleAddress &peerAddr + const ChatRoomId &chatRoomId ) { const char *uri = linphone_core_get_conference_factory_uri(corePrivate.cCore); if (!uri) - return ""; + return ChatRoomId(); - SimpleAddress workaroundAddr(peerAddr); - workaroundAddr.setDomain(Address(uri).getDomain()); - return workaroundAddr.asString(); + SimpleAddress peerAddress = chatRoomId.getPeerAddress(); + peerAddress.setDomain(Address(uri).getDomain()); + return ChatRoomId(peerAddress, chatRoomId.getLocalAddress()); +} + +// TODO: Remove me later. +static inline ChatRoomId resolveWorkaroundClientGroupChatRoomId ( + const CorePrivate &corePrivate, + const shared_ptr &chatRoom +) { + if (!(chatRoom->getCapabilities() & static_cast(ChatRoom::Capabilities::Conference))) + return chatRoom->getChatRoomId(); + return resolveWorkaroundClientGroupChatRoomId(corePrivate, chatRoom->getChatRoomId()); +} + +// Return the better local address to talk with peer address. +static SimpleAddress getDefaultLocalAddress (const shared_ptr &core, const SimpleAddress &peerAddress) { + LinphoneCore *cCore = core->getCCore(); + + LinphoneAddress *cPeerAddress = linphone_address_new(peerAddress.asString().c_str()); + LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(cCore, cPeerAddress); + linphone_address_unref(cPeerAddress); + + SimpleAddress localAddress; + if (proxy) { + char *identity = linphone_address_as_string(linphone_proxy_config_get_identity_address(proxy)); + localAddress = SimpleAddress(identity); + bctbx_free(identity); + } else + localAddress = SimpleAddress(linphone_core_get_primary_contact(cCore)); + + return localAddress; } // ----------------------------------------------------------------------------- -shared_ptr CorePrivate::createBasicChatRoom (const Address &peerAddress, bool isRtt) { +shared_ptr CorePrivate::createBasicChatRoom (const ChatRoomId &chatRoomId, bool isRtt) { L_Q(); shared_ptr chatRoom; if (isRtt) - chatRoom = make_shared(q->getSharedFromThis(), peerAddress); + chatRoom.reset(new RealTimeTextChatRoom(q->getSharedFromThis(), chatRoomId)); else - chatRoom = make_shared(q->getSharedFromThis(), peerAddress); + chatRoom.reset(new BasicChatRoom(q->getSharedFromThis(), chatRoomId)); ChatRoomPrivate *dChatRoom = chatRoom->getPrivate(); @@ -76,48 +105,40 @@ shared_ptr CorePrivate::createBasicChatRoom (const Address &peerAddres void CorePrivate::insertChatRoom (const shared_ptr &chatRoom) { L_ASSERT(chatRoom); - const SimpleAddress simpleAddr(chatRoom->getPeerAddress()); - const string peerAddress = chatRoom->getCapabilities() & static_cast(ChatRoom::Capabilities::Conference) - ? resolveWorkaroundClientGroupChatRoomAddress(*this, simpleAddr) - : simpleAddr.asString(); + const ChatRoomId &chatRoomId = resolveWorkaroundClientGroupChatRoomId(*this, chatRoom); - deleteChatRoom(peerAddress); + deleteChatRoom(chatRoomId); chatRooms.push_back(chatRoom); - chatRoomsByUri[peerAddress] = chatRoom; + chatRoomsById[chatRoomId] = chatRoom; } -void CorePrivate::deleteChatRoom (const string &peerAddr) { - const SimpleAddress simpleAddr(peerAddr); - auto it = chatRoomsByUri.find(simpleAddr.asString()); - if (it != chatRoomsByUri.end()) { - auto it = find_if(chatRooms.begin(), chatRooms.end(), [&peerAddr, &simpleAddr](const shared_ptr &chatRoom) { - return peerAddr == simpleAddr.asString(); +void CorePrivate::deleteChatRoom (const ChatRoomId &chatRoomId) { + auto it = chatRoomsById.find(chatRoomId); + if (it != chatRoomsById.end()) { + auto it = find_if(chatRooms.begin(), chatRooms.end(), [&chatRoomId](const shared_ptr &chatRoom) { + return chatRoomId == chatRoom->getChatRoomId(); }); if (it != chatRooms.end()) { chatRooms.erase(it); return; } - lError() << "Unable to remove chat room: " << peerAddr; + lError() << "Unable to remove chat room: (peer=" << + chatRoomId.getPeerAddress().asString() << ", local=" << chatRoomId.getLocalAddress().asString() << ")."; } } void CorePrivate::insertChatRoomWithDb (const shared_ptr &chatRoom) { L_ASSERT(chatRoom->getState() == ChatRoom::State::Created); - const SimpleAddress simpleAddr(chatRoom->getPeerAddress()); + const ChatRoomId &chatRoomId = resolveWorkaroundClientGroupChatRoomId(*this, chatRoom); + ChatRoom::CapabilitiesMask capabilities = chatRoom->getCapabilities(); - mainDb->insertChatRoom( - capabilities & static_cast(ChatRoom::Capabilities::Conference) - ? resolveWorkaroundClientGroupChatRoomAddress(*this, simpleAddr) - : simpleAddr.asString(), - capabilities - ); + mainDb->insertChatRoom(chatRoomId, capabilities); } -void CorePrivate::deleteChatRoomWithDb (const string &peerAddr) { - const SimpleAddress simpleAddr(peerAddr); - deleteChatRoom(simpleAddr.asString()); - mainDb->deleteChatRoom(simpleAddr.asString()); +void CorePrivate::deleteChatRoomWithDb (const ChatRoomId &chatRoomId) { + deleteChatRoom(chatRoomId); + mainDb->deleteChatRoom(chatRoomId); } // ----------------------------------------------------------------------------- @@ -127,24 +148,28 @@ const list> &Core::getChatRooms () const { return d->chatRooms; } -shared_ptr Core::findChatRoom (const Address &peerAddr) const { +shared_ptr Core::findChatRoom (const ChatRoomId &chatRoomId) const { L_D(); - const SimpleAddress simpleAddr(peerAddr); - auto it = d->chatRoomsByUri.find(simpleAddr.asString()); - if (it != d->chatRoomsByUri.cend()) + auto it = d->chatRoomsById.find(chatRoomId); + if (it != d->chatRoomsById.cend()) return it->second; - lInfo() << "Unable to find chat room: `" << simpleAddr.asString() << "`"; + lInfo() << "Unable to find chat room: (peer=" << + chatRoomId.getPeerAddress().asString() << ", local=" << chatRoomId.getLocalAddress().asString() << ")."; // TODO: Remove me, temp workaround. - const string workaroundAddress = resolveWorkaroundClientGroupChatRoomAddress(*d, simpleAddr); - if (!workaroundAddress.empty()) { - lWarning() << "Workaround: searching chat room with: `" << workaroundAddress << "`"; - it = d->chatRoomsByUri.find(workaroundAddress); - return it == d->chatRoomsByUri.cend() ? shared_ptr() : it->second; - } - return shared_ptr(); + ChatRoomId workaroundChatRoomId = resolveWorkaroundClientGroupChatRoomId(*d, chatRoomId); + lWarning() << "Workaround: searching chat room with: (peer=" << + chatRoomId.getPeerAddress().asString() << ", local=" << chatRoomId.getLocalAddress().asString() << ")."; + + it = d->chatRoomsById.find(workaroundChatRoomId); + return it == d->chatRoomsById.cend() ? shared_ptr() : it->second; +} + +list> Core::findChatRooms (const SimpleAddress &peerAddress) const { + // TODO: DEV GROUP CHAT. + return list>(); } shared_ptr Core::createClientGroupChatRoom (const string &subject) { @@ -158,26 +183,38 @@ shared_ptr Core::createClientGroupChatRoom (const string &subject) { ); } -shared_ptr Core::getOrCreateBasicChatRoom (const Address &peerAddress, bool isRtt) { +shared_ptr Core::getOrCreateBasicChatRoom (const ChatRoomId &chatRoomId, bool isRtt) { L_D(); - if (!peerAddress.isValid()) { - lWarning() << "Cannot find get or create chat room with invalid peer address."; - return nullptr; - } - - shared_ptr chatRoom = findChatRoom(peerAddress); + shared_ptr chatRoom = findChatRoom(chatRoomId); if (chatRoom) return chatRoom; - chatRoom = d->createBasicChatRoom(peerAddress, isRtt); + chatRoom = d->createBasicChatRoom(chatRoomId, isRtt); d->insertChatRoom(chatRoom); d->insertChatRoomWithDb(chatRoom); return chatRoom; } -shared_ptr Core::getOrCreateBasicChatRoom (const string &peerAddress, bool isRtt) { +shared_ptr Core::getOrCreateBasicChatRoom (const SimpleAddress &peerAddress, bool isRtt) { + L_D(); + + list> chatRooms = findChatRooms(peerAddress); + if (!chatRooms.empty()) + return chatRooms.front(); + + shared_ptr chatRoom = d->createBasicChatRoom( + ChatRoomId(peerAddress, getDefaultLocalAddress(getSharedFromThis(), peerAddress)), + isRtt + ); + d->insertChatRoom(chatRoom); + d->insertChatRoomWithDb(chatRoom); + + return chatRoom; +} + +shared_ptr Core::getOrCreateBasicChatRoomFromUri (const string &peerAddress, bool isRtt) { L_D(); LinphoneAddress *address = linphone_core_interpret_url(d->cCore, L_STRING_TO_C(peerAddress)); @@ -193,11 +230,8 @@ shared_ptr Core::getOrCreateBasicChatRoom (const string &peerAddress, void Core::deleteChatRoom (const shared_ptr &chatRoom) { CorePrivate *d = chatRoom->getCore()->getPrivate(); - const SimpleAddress simpleAddr(chatRoom->getPeerAddress()); d->deleteChatRoomWithDb( - chatRoom->getCapabilities() & static_cast(ChatRoom::Capabilities::Conference) - ? resolveWorkaroundClientGroupChatRoomAddress(*d, simpleAddr) - : simpleAddr.asString() + resolveWorkaroundClientGroupChatRoomId(*d, chatRoom->getChatRoomId()) ); } diff --git a/src/core/core-p.h b/src/core/core-p.h index c136caf94..386c1b140 100644 --- a/src/core/core-p.h +++ b/src/core/core-p.h @@ -20,6 +20,7 @@ #ifndef _CORE_P_H_ #define _CORE_P_H_ +#include "chat/chat-room/chat-room-id.h" #include "core.h" #include "db/main-db.h" #include "object/object-p.h" @@ -30,19 +31,19 @@ LINPHONE_BEGIN_NAMESPACE class CorePrivate : public ObjectPrivate { public: + void insertChatRoom (const std::shared_ptr &chatRoom); + void insertChatRoomWithDb (const std::shared_ptr &chatRoom); + std::shared_ptr createBasicChatRoom (const ChatRoomId &chatRoomId, bool isRtt); + std::unique_ptr mainDb; LinphoneCore *cCore = nullptr; - void insertChatRoom (const std::shared_ptr &chatRoom); - void insertChatRoomWithDb (const std::shared_ptr &chatRoom); - std::shared_ptr createBasicChatRoom (const Address &peerAddress, bool isRtt); - private: - void deleteChatRoom (const std::string &peerAddress); - void deleteChatRoomWithDb (const std::string &peerAddress); + void deleteChatRoom (const ChatRoomId &chatRoomId); + void deleteChatRoomWithDb (const ChatRoomId &chatRoomId); std::list> chatRooms; - std::unordered_map> chatRoomsByUri; + std::unordered_map> chatRoomsById; L_DECLARE_PUBLIC(Core); }; diff --git a/src/core/core.h b/src/core/core.h index ab0063512..8ef97983d 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -32,7 +32,9 @@ LINPHONE_BEGIN_NAMESPACE class Address; class ChatRoom; +class ChatRoomId; class CorePrivate; +class SimpleAddress; class LINPHONE_PUBLIC Core : public Object { friend class ChatRoom; @@ -67,10 +69,17 @@ public: // --------------------------------------------------------------------------- const std::list> &getChatRooms () const; - std::shared_ptr findChatRoom (const Address &peerAddress) const; + + std::shared_ptr findChatRoom (const ChatRoomId &chatRoomId) const; + std::list> findChatRooms (const SimpleAddress &peerAddress) const; + std::shared_ptr createClientGroupChatRoom (const std::string &subject); - std::shared_ptr getOrCreateBasicChatRoom (const Address &peerAddress, bool isRtt = false); - std::shared_ptr getOrCreateBasicChatRoom (const std::string &peerAddress, bool isRtt = false); + std::shared_ptr createClientGroupChatRoom (const std::string &subject, const SimpleAddress &localAddress); + + std::shared_ptr getOrCreateBasicChatRoom (const ChatRoomId &chatRoomId, bool isRtt = false); + std::shared_ptr getOrCreateBasicChatRoom (const SimpleAddress &peerAddress, bool isRtt = false); + + std::shared_ptr getOrCreateBasicChatRoomFromUri (const std::string &uri, bool isRtt = false); static void deleteChatRoom (const std::shared_ptr &chatRoom); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 23e76488b..52969d8df 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -20,6 +20,11 @@ #include #include +// TODO: Remove me. +#ifdef SOCI_ENABLED + #undef SOCI_ENABLED +#endif + #ifdef SOCI_ENABLED #include #endif // ifdef SOCI_ENABLED @@ -1545,31 +1550,31 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } list> MainDb::getConferenceNotifiedEvents ( - const string &peerAddress, - unsigned int notifyId + const ChatRoomId &, + unsigned int ) const { return list>(); } - int MainDb::getChatMessagesCount (const string &) const { + int MainDb::getChatMessagesCount (const ChatRoomId &) const { return 0; } - int MainDb::getUnreadChatMessagesCount (const string &) const { + int MainDb::getUnreadChatMessagesCount (const ChatRoomId &) const { return 0; } - void MainDb::markChatMessagesAsRead (const string &) const {} + void MainDb::markChatMessagesAsRead (const ChatRoomId &) const {} - list> MainDb::getUnreadChatMessages (const std::string &) const { + list> MainDb::getUnreadChatMessages (const ChatRoomId &) const { return list>(); } - list> MainDb::getHistory (const string &, int, FilterMask) const { + list> MainDb::getHistory (const ChatRoomId &, int, FilterMask) const { return list>(); } - list> MainDb::getHistoryRange (const string &, int, int, FilterMask) const { + list> MainDb::getHistoryRange (const ChatRoomId &, int, int, FilterMask) const { return list>(); } @@ -1577,11 +1582,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return list>(); } - void MainDb::insertChatRoom (const string &, int) {} + void MainDb::insertChatRoom (const ChatRoomId &, int) {} - void MainDb::deleteChatRoom (const string &) {} + void MainDb::deleteChatRoom (const ChatRoomId &) {} - void MainDb::cleanHistory (const string &, FilterMask) {} + void MainDb::cleanHistory (const ChatRoomId &, FilterMask) {} bool MainDb::import (Backend, const string &) { return false; diff --git a/src/db/main-db.h b/src/db/main-db.h index d675a0186..8a6358839 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -23,6 +23,7 @@ #include #include "abstract/abstract-db.h" +#include "chat/chat-room/chat-room-id.h" #include "core/core-accessor.h" // ============================================================================= @@ -63,7 +64,7 @@ public: // --------------------------------------------------------------------------- std::list> getConferenceNotifiedEvents ( - const std::string &peerAddress, + const ChatRoomId &chatRoomId, unsigned int lastNotifyId ) const; @@ -71,35 +72,35 @@ public: // Conference chat message events. // --------------------------------------------------------------------------- - int getChatMessagesCount (const std::string &peerAddress = "") const; - int getUnreadChatMessagesCount (const std::string &peerAddress = "") const; - void markChatMessagesAsRead (const std::string &peerAddress = "") const; - std::list> getUnreadChatMessages (const std::string &peerAddress = "") const; + int getChatMessagesCount (const ChatRoomId &chatRoomId = ChatRoomId()) const; + int getUnreadChatMessagesCount (const ChatRoomId &chatRoomId = ChatRoomId()) const; + void markChatMessagesAsRead (const ChatRoomId &chatRoomId = ChatRoomId()) const; + std::list> getUnreadChatMessages (const ChatRoomId &chatRoomId = ChatRoomId()) const; // --------------------------------------------------------------------------- // Conference events. // --------------------------------------------------------------------------- std::list> getHistory ( - const std::string &peerAddress, + const ChatRoomId &chatRoomId, int nLast, FilterMask mask = NoFilter ) const; std::list> getHistoryRange ( - const std::string &peerAddress, + const ChatRoomId &chatRoomId, int begin, int end, FilterMask mask = NoFilter ) const; - void cleanHistory (const std::string &peerAddress = "", FilterMask mask = NoFilter); + void cleanHistory (const ChatRoomId &chatRoomId, FilterMask mask = NoFilter); // --------------------------------------------------------------------------- // Chat rooms. // --------------------------------------------------------------------------- std::list> getChatRooms () const; - void insertChatRoom (const std::string &peerAddress, int capabilities); - void deleteChatRoom (const std::string &peerAddress); + void insertChatRoom (const ChatRoomId &chatRoomId, int capabilities); + void deleteChatRoom (const ChatRoomId &chatRoomId); // --------------------------------------------------------------------------- // Other. diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index 239a3690e..cefca8260 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -394,15 +394,15 @@ static void cpim_chat_message_modifier_base(bool_t use_multipart) { LpConfig *config = linphone_core_get_config(marie->lc); lp_config_set_int(config, "sip", "use_cpim", 1); - Address paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); - shared_ptr marieRoom = make_shared(marie->lc->cppCore, paulineAddress); + SimpleAddress paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); + shared_ptr marieRoom = marie->lc->cppCore->getOrCreateBasicChatRoom(paulineAddress); shared_ptr marieMessage = marieRoom->createMessage("Hello CPIM"); if (use_multipart) { Content *content = new Content(); content->setContentType(ContentType::PlainText); content->setBody("Hello Part 2"); - marieMessage->addContent(content); + marieMessage->addContent(*content); } marieMessage->send(); diff --git a/tester/main-db-tester.cpp b/tester/main-db-tester.cpp index 93a8649b6..365e63095 100644 --- a/tester/main-db-tester.cpp +++ b/tester/main-db-tester.cpp @@ -33,147 +33,149 @@ using namespace LinphonePrivate; // ----------------------------------------------------------------------------- -static const string getDatabasePath () { - static const string path = string(bc_tester_get_resource_dir_prefix()) + "db/linphone.db"; - return path; -} +// TODO: DEV GROUP CHAT -// ----------------------------------------------------------------------------- - -class MainDbProvider { -public: - MainDbProvider () { - mCoreManager = linphone_core_manager_new("marie_rc"); - mMainDb = new MainDb(mCoreManager->lc->cppCore->getSharedFromThis()); - mMainDb->connect(MainDb::Sqlite3, getDatabasePath()); - } - - ~MainDbProvider () { - delete mMainDb; - linphone_core_manager_destroy(mCoreManager); - } - - const MainDb &getMainDb () { - return *mMainDb; - } - -private: - LinphoneCoreManager *mCoreManager; - MainDb *mMainDb; -}; - -// ----------------------------------------------------------------------------- - -static void open_database () { - MainDbProvider provider; - BC_ASSERT_TRUE(provider.getMainDb().isConnected()); -} - -static void get_events_count () { - MainDbProvider provider; - const MainDb &mainDb = provider.getMainDb(); - BC_ASSERT_EQUAL(mainDb.getEventsCount(), 4994, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceCallFilter), 0, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceInfoFilter), 18, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceChatMessageFilter), 5157, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::NoFilter), 4994, int, "%d"); -} - -static void get_messages_count () { - MainDbProvider provider; - const MainDb &mainDb = provider.getMainDb(); - BC_ASSERT_EQUAL(mainDb.getChatMessagesCount(), 5157, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getChatMessagesCount("sip:test-39@sip.linphone.org"), 3, int, "%d"); -} - -static void get_unread_messages_count () { - MainDbProvider provider; - const MainDb &mainDb = provider.getMainDb(); - BC_ASSERT_EQUAL(mainDb.getUnreadChatMessagesCount(), 2, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getUnreadChatMessagesCount("sip:test-39@sip.linphone.org"), 0, int, "%d"); -} - -static void get_history () { - MainDbProvider provider; - const MainDb &mainDb = provider.getMainDb(); - BC_ASSERT_EQUAL( - mainDb.getHistoryRange("sip:test-39@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceChatMessageFilter).size(), - 3, - int, - "%d" - ); - BC_ASSERT_EQUAL( - mainDb.getHistoryRange("sip:test-7@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceCallFilter).size(), - 0, - int, - "%d" - ); - BC_ASSERT_EQUAL( - mainDb.getHistoryRange("sip:test-1@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceChatMessageFilter).size(), - 862, - int, - "%d" - ); - BC_ASSERT_EQUAL( - mainDb.getHistory("sip:test-1@sip.linphone.org", 100, MainDb::Filter::ConferenceChatMessageFilter).size(), - 100, - int, - "%d" - ); -} - -static void get_conference_notified_events () { - MainDbProvider provider; - const MainDb &mainDb = provider.getMainDb(); - list> events = mainDb.getConferenceNotifiedEvents("sip:fake-group-2@sip.linphone.org", 1); - BC_ASSERT_EQUAL(events.size(), 3, int, "%d"); - if (events.size() != 3) - return; - - shared_ptr event; - auto it = events.cbegin(); - - event = *it; - if (!BC_ASSERT_TRUE(event->getType() == EventLog::Type::ConferenceParticipantRemoved)) return; - { - shared_ptr participantEvent = static_pointer_cast(event); - BC_ASSERT_TRUE(participantEvent->getConferenceAddress().asStringUriOnly() == "sip:fake-group-2@sip.linphone.org"); - BC_ASSERT_TRUE(participantEvent->getParticipantAddress().asStringUriOnly() == "sip:test-11@sip.linphone.org"); - BC_ASSERT_TRUE(participantEvent->getNotifyId() == 2); - } - - event = *++it; - if (!BC_ASSERT_TRUE(event->getType() == EventLog::Type::ConferenceParticipantDeviceAdded)) return; - { - shared_ptr deviceEvent = static_pointer_cast< - ConferenceParticipantDeviceEvent - >(event); - BC_ASSERT_TRUE(deviceEvent->getConferenceAddress().asStringUriOnly() == "sip:fake-group-2@sip.linphone.org"); - BC_ASSERT_TRUE(deviceEvent->getParticipantAddress().asStringUriOnly() == "sip:test-11@sip.linphone.org"); - BC_ASSERT_TRUE(deviceEvent->getNotifyId() == 3); - BC_ASSERT_TRUE(deviceEvent->getGruuAddress().asStringUriOnly() == "sip:gruu-address-1@sip.linphone.org"); - } - - event = *++it; - if (!BC_ASSERT_TRUE(event->getType() == EventLog::Type::ConferenceParticipantDeviceRemoved)) return; - { - shared_ptr deviceEvent = static_pointer_cast< - ConferenceParticipantDeviceEvent - >(event); - BC_ASSERT_TRUE(deviceEvent->getConferenceAddress().asStringUriOnly() == "sip:fake-group-2@sip.linphone.org"); - BC_ASSERT_TRUE(deviceEvent->getParticipantAddress().asStringUriOnly() == "sip:test-11@sip.linphone.org"); - BC_ASSERT_TRUE(deviceEvent->getNotifyId() == 4); - BC_ASSERT_TRUE(deviceEvent->getGruuAddress().asStringUriOnly() == "sip:gruu-address-1@sip.linphone.org"); - } -} +// static const string getDatabasePath () { +// static const string path = string(bc_tester_get_resource_dir_prefix()) + "db/linphone.db"; +// return path; +// } +// +// // ----------------------------------------------------------------------------- +// +// class MainDbProvider { +// public: +// MainDbProvider () { +// mCoreManager = linphone_core_manager_new("marie_rc"); +// mMainDb = new MainDb(mCoreManager->lc->cppCore->getSharedFromThis()); +// mMainDb->connect(MainDb::Sqlite3, getDatabasePath()); +// } +// +// ~MainDbProvider () { +// delete mMainDb; +// linphone_core_manager_destroy(mCoreManager); +// } +// +// const MainDb &getMainDb () { +// return *mMainDb; +// } +// +// private: +// LinphoneCoreManager *mCoreManager; +// MainDb *mMainDb; +// }; +// +// // ----------------------------------------------------------------------------- +// +// static void open_database () { +// MainDbProvider provider; +// BC_ASSERT_TRUE(provider.getMainDb().isConnected()); +// } +// +// static void get_events_count () { +// MainDbProvider provider; +// const MainDb &mainDb = provider.getMainDb(); +// BC_ASSERT_EQUAL(mainDb.getEventsCount(), 4994, int, "%d"); +// BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceCallFilter), 0, int, "%d"); +// BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceInfoFilter), 18, int, "%d"); +// BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceChatMessageFilter), 5157, int, "%d"); +// BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::NoFilter), 4994, int, "%d"); +// } +// +// static void get_messages_count () { +// MainDbProvider provider; +// const MainDb &mainDb = provider.getMainDb(); +// BC_ASSERT_EQUAL(mainDb.getChatMessagesCount(), 5157, int, "%d"); +// BC_ASSERT_EQUAL(mainDb.getChatMessagesCount("sip:test-39@sip.linphone.org"), 3, int, "%d"); +// } +// +// static void get_unread_messages_count () { +// MainDbProvider provider; +// const MainDb &mainDb = provider.getMainDb(); +// BC_ASSERT_EQUAL(mainDb.getUnreadChatMessagesCount(), 2, int, "%d"); +// BC_ASSERT_EQUAL(mainDb.getUnreadChatMessagesCount("sip:test-39@sip.linphone.org"), 0, int, "%d"); +// } +// +// static void get_history () { +// MainDbProvider provider; +// const MainDb &mainDb = provider.getMainDb(); +// BC_ASSERT_EQUAL( +// mainDb.getHistoryRange("sip:test-39@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceChatMessageFilter).size(), +// 3, +// int, +// "%d" +// ); +// BC_ASSERT_EQUAL( +// mainDb.getHistoryRange("sip:test-7@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceCallFilter).size(), +// 0, +// int, +// "%d" +// ); +// BC_ASSERT_EQUAL( +// mainDb.getHistoryRange("sip:test-1@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceChatMessageFilter).size(), +// 862, +// int, +// "%d" +// ); +// BC_ASSERT_EQUAL( +// mainDb.getHistory("sip:test-1@sip.linphone.org", 100, MainDb::Filter::ConferenceChatMessageFilter).size(), +// 100, +// int, +// "%d" +// ); +// } +// +// static void get_conference_notified_events () { +// MainDbProvider provider; +// const MainDb &mainDb = provider.getMainDb(); +// list> events = mainDb.getConferenceNotifiedEvents("sip:fake-group-2@sip.linphone.org", 1); +// BC_ASSERT_EQUAL(events.size(), 3, int, "%d"); +// if (events.size() != 3) +// return; +// +// shared_ptr event; +// auto it = events.cbegin(); +// +// event = *it; +// if (!BC_ASSERT_TRUE(event->getType() == EventLog::Type::ConferenceParticipantRemoved)) return; +// { +// shared_ptr participantEvent = static_pointer_cast(event); +// BC_ASSERT_TRUE(participantEvent->getConferenceAddress().asStringUriOnly() == "sip:fake-group-2@sip.linphone.org"); +// BC_ASSERT_TRUE(participantEvent->getParticipantAddress().asStringUriOnly() == "sip:test-11@sip.linphone.org"); +// BC_ASSERT_TRUE(participantEvent->getNotifyId() == 2); +// } +// +// event = *++it; +// if (!BC_ASSERT_TRUE(event->getType() == EventLog::Type::ConferenceParticipantDeviceAdded)) return; +// { +// shared_ptr deviceEvent = static_pointer_cast< +// ConferenceParticipantDeviceEvent +// >(event); +// BC_ASSERT_TRUE(deviceEvent->getConferenceAddress().asStringUriOnly() == "sip:fake-group-2@sip.linphone.org"); +// BC_ASSERT_TRUE(deviceEvent->getParticipantAddress().asStringUriOnly() == "sip:test-11@sip.linphone.org"); +// BC_ASSERT_TRUE(deviceEvent->getNotifyId() == 3); +// BC_ASSERT_TRUE(deviceEvent->getGruuAddress().asStringUriOnly() == "sip:gruu-address-1@sip.linphone.org"); +// } +// +// event = *++it; +// if (!BC_ASSERT_TRUE(event->getType() == EventLog::Type::ConferenceParticipantDeviceRemoved)) return; +// { +// shared_ptr deviceEvent = static_pointer_cast< +// ConferenceParticipantDeviceEvent +// >(event); +// BC_ASSERT_TRUE(deviceEvent->getConferenceAddress().asStringUriOnly() == "sip:fake-group-2@sip.linphone.org"); +// BC_ASSERT_TRUE(deviceEvent->getParticipantAddress().asStringUriOnly() == "sip:test-11@sip.linphone.org"); +// BC_ASSERT_TRUE(deviceEvent->getNotifyId() == 4); +// BC_ASSERT_TRUE(deviceEvent->getGruuAddress().asStringUriOnly() == "sip:gruu-address-1@sip.linphone.org"); +// } +// } test_t main_db_tests[] = { - TEST_NO_TAG("Open database", open_database), - TEST_NO_TAG("Get events count", get_events_count), - TEST_NO_TAG("Get messages count", get_messages_count), - TEST_NO_TAG("Get unread messages count", get_unread_messages_count), - TEST_NO_TAG("Get history", get_history), - TEST_NO_TAG("Get conference events", get_conference_notified_events) + // TEST_NO_TAG("Open database", open_database), + // TEST_NO_TAG("Get events count", get_events_count), + // TEST_NO_TAG("Get messages count", get_messages_count), + // TEST_NO_TAG("Get unread messages count", get_unread_messages_count), + // TEST_NO_TAG("Get history", get_history), + // TEST_NO_TAG("Get conference events", get_conference_notified_events) }; test_suite_t main_db_test_suite = { diff --git a/tester/multipart-tester.cpp b/tester/multipart-tester.cpp index d9c3b65bc..4a104201f 100644 --- a/tester/multipart-tester.cpp +++ b/tester/multipart-tester.cpp @@ -39,8 +39,8 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer, bool LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc"); - Address paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); - shared_ptr marieRoom = make_shared(marie->lc->cppCore, paulineAddress); + SimpleAddress paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); + shared_ptr marieRoom = pauline->lc->cppCore->getOrCreateBasicChatRoom(paulineAddress); shared_ptr marieMessage = marieRoom->createMessage(); if (first_file_transfer) { @@ -49,13 +49,13 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer, bool content->setContentType("video/mkv"); content->setFilePath(send_filepath); content->setFileName("sintel_trailer_opus_h264.mkv"); - marieMessage->addContent(content); + marieMessage->addContent(*content); bc_free(send_filepath); } else { Content *content = new Content(); content->setContentType(ContentType::PlainText); content->setBody("Hello Part 1"); - marieMessage->addContent(content); + marieMessage->addContent(*content); } if (second_file_transfer) { @@ -64,13 +64,13 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer, bool content->setContentType("file/vcf"); content->setFilePath(send_filepath); content->setFileName("vcards.vcf"); - marieMessage->addContent(content); + marieMessage->addContent(*content); bc_free(send_filepath); } else { Content *content = new Content(); content->setContentType(ContentType::PlainText); content->setBody("Hello Part 2"); - marieMessage->addContent(content); + marieMessage->addContent(*content); } linphone_core_set_file_transfer_server(marie->lc,"https://www.linphone.org:444/lft.php"); From d70c38f9f50938dbbeb3b6441318614a87f67157 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 15 Nov 2017 15:38:14 +0100 Subject: [PATCH 0781/2215] fix(Object): little fixes, remove useless friend and add assert and getSharedFromThis --- src/object/app-data-container.cpp | 2 ++ src/object/base-object-p.h | 4 ++-- src/object/object.cpp | 4 ++++ src/object/object.h | 1 - src/object/property-container.cpp | 2 ++ src/utils/utils.cpp | 2 ++ src/variant/variant.cpp | 2 ++ 7 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/object/app-data-container.cpp b/src/object/app-data-container.cpp index 7d6117bd7..2f26bc886 100644 --- a/src/object/app-data-container.cpp +++ b/src/object/app-data-container.cpp @@ -27,6 +27,8 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +// ----------------------------------------------------------------------------- + class AppDataContainerPrivate { public: shared_ptr> appData; diff --git a/src/object/base-object-p.h b/src/object/base-object-p.h index 3db55188e..a46d1f701 100644 --- a/src/object/base-object-p.h +++ b/src/object/base-object-p.h @@ -17,8 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - #ifndef _BASE_OBJECT_P_H_ - #define _BASE_OBJECT_P_H_ +#ifndef _BASE_OBJECT_P_H_ +#define _BASE_OBJECT_P_H_ #include "linphone/utils/general.h" diff --git a/src/object/object.cpp b/src/object/object.cpp index 77e333aa2..2fd8c65cf 100644 --- a/src/object/object.cpp +++ b/src/object/object.cpp @@ -26,6 +26,8 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +// ----------------------------------------------------------------------------- + Object::Object (ObjectPrivate &p) : BaseObject(p) {} shared_ptr Object::getSharedFromThis () { @@ -39,6 +41,8 @@ shared_ptr Object::getSharedFromThis () const { lFatal() << "Object " << this << " was not created with make_shared."; } + // Unable to reach this point. + L_ASSERT(false); return nullptr; } diff --git a/src/object/object.h b/src/object/object.h index e132fc075..fec368cba 100644 --- a/src/object/object.h +++ b/src/object/object.h @@ -38,7 +38,6 @@ class LINPHONE_PUBLIC Object : public std::enable_shared_from_this, public BaseObject, public PropertyContainer { - friend class ObjectFactory; public: std::shared_ptr getSharedFromThis (); diff --git a/src/object/property-container.cpp b/src/object/property-container.cpp index 36cbe6993..c23e628ef 100644 --- a/src/object/property-container.cpp +++ b/src/object/property-container.cpp @@ -27,6 +27,8 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +// ----------------------------------------------------------------------------- + class PropertyContainerPrivate { public: unordered_map properties; diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 8d4f55efe..e3819de39 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -31,6 +31,8 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +// ----------------------------------------------------------------------------- + bool Utils::iequals (const string &a, const string &b) { size_t size = a.size(); if (b.size() != size) diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index 45aea40bc..ca8b4b746 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -27,6 +27,8 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +// ----------------------------------------------------------------------------- + class VariantPrivate { public: union Value { From 013c31bc6dfb6f84d3962f4e72d78ed2afd0c0ce Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 15 Nov 2017 15:47:20 +0100 Subject: [PATCH 0782/2215] fix(logger): use bctbx log functions instead of ms functions --- src/logger/logger.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/logger/logger.cpp b/src/logger/logger.cpp index 68e718b7e..44dff8426 100644 --- a/src/logger/logger.cpp +++ b/src/logger/logger.cpp @@ -20,7 +20,7 @@ #include #include -#include "linphone/core.h" +#include #include "object/base-object-p.h" @@ -53,20 +53,20 @@ Logger::~Logger () { switch (d->level) { case Debug: #if DEBUG_LOGS - ms_debug("%s", str.c_str()); + bctbx_debug("%s", str.c_str()); #endif // if DEBUG_LOGS break; case Info: - ms_message("%s", str.c_str()); + bctbx_message("%s", str.c_str()); break; case Warning: - ms_warning("%s", str.c_str()); + bctbx_warning("%s", str.c_str()); break; case Error: - ms_error("%s", str.c_str()); + bctbx_error("%s", str.c_str()); break; case Fatal: - ms_fatal("%s", str.c_str()); + bctbx_fatal("%s", str.c_str()); break; } } From 476d0c07e5496ace57956218831665a6951fe3bd Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 15 Nov 2017 15:49:31 +0100 Subject: [PATCH 0783/2215] feat(hacks): enforce doc --- src/hacks/hacks.cpp | 2 ++ src/hacks/hacks.h | 9 ++++----- src/logger/logger.cpp | 2 ++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/hacks/hacks.cpp b/src/hacks/hacks.cpp index a4123a9ad..2fa8fe12a 100644 --- a/src/hacks/hacks.cpp +++ b/src/hacks/hacks.cpp @@ -25,4 +25,6 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +// Place your hacks here. + LINPHONE_END_NAMESPACE diff --git a/src/hacks/hacks.h b/src/hacks/hacks.h index 5e58d07fa..b278f765d 100644 --- a/src/hacks/hacks.h +++ b/src/hacks/hacks.h @@ -20,22 +20,21 @@ #ifndef _HACKS_H_ #define _HACKS_H_ -#include - #include "linphone/utils/general.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE -// This class has the purpose to centralize the temporary hacks so that they -// can be located more easily. +/* + * This class has the purpose to centralize the TEMPORARY (!!!) hacks so that they + * can be located more easily. Useful for dev cpp refactoring. + */ class Hacks { public: Hacks () = delete; private: - L_DISABLE_COPY(Hacks); }; diff --git a/src/logger/logger.cpp b/src/logger/logger.cpp index 44dff8426..bfa5365fb 100644 --- a/src/logger/logger.cpp +++ b/src/logger/logger.cpp @@ -32,6 +32,8 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +// ----------------------------------------------------------------------------- + class LoggerPrivate : public BaseObjectPrivate { public: Logger::Level level; From a69efcb3255bc358d719b8cae5130c595ce4fdd5 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 15 Nov 2017 16:03:45 +0100 Subject: [PATCH 0784/2215] fix(core): replace all std::time_t by time_t because `std::` is useless (see 20.5.4.3.4 of C++17 standard) --- include/linphone/utils/utils.h | 4 ++-- src/event-log/conference/conference-call-event.h | 2 +- src/event-log/conference/conference-chat-message-event.h | 2 +- src/event-log/conference/conference-event.h | 4 ++-- src/event-log/conference/conference-notified-event.h | 4 ++-- .../conference/conference-participant-device-event.h | 2 +- src/event-log/conference/conference-participant-event.h | 4 ++-- src/event-log/conference/conference-subject-event.h | 2 +- src/event-log/event-log-p.h | 2 +- src/event-log/event-log.cpp | 4 ++-- src/event-log/event-log.h | 4 ++-- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/include/linphone/utils/utils.h b/include/linphone/utils/utils.h index 6fea7d5c2..b11154255 100644 --- a/include/linphone/utils/utils.h +++ b/include/linphone/utils/utils.h @@ -105,8 +105,8 @@ namespace Utils { return object; } - LINPHONE_PUBLIC std::tm getTimeTAsTm (std::time_t time); - LINPHONE_PUBLIC std::time_t getTmAsTimeT (const std::tm &time); + LINPHONE_PUBLIC std::tm getTimeTAsTm (time_t time); + LINPHONE_PUBLIC time_t getTmAsTimeT (const std::tm &time); } LINPHONE_END_NAMESPACE diff --git a/src/event-log/conference/conference-call-event.h b/src/event-log/conference/conference-call-event.h index f2e58b893..53a4667ff 100644 --- a/src/event-log/conference/conference-call-event.h +++ b/src/event-log/conference/conference-call-event.h @@ -33,7 +33,7 @@ class ConferenceCallEventPrivate; class LINPHONE_PUBLIC ConferenceCallEvent : public EventLog { public: - ConferenceCallEvent (Type type, std::time_t time, const std::shared_ptr &call); + ConferenceCallEvent (Type type, time_t time, const std::shared_ptr &call); std::shared_ptr getCall () const; diff --git a/src/event-log/conference/conference-chat-message-event.h b/src/event-log/conference/conference-chat-message-event.h index f64cf7afd..64a210e90 100644 --- a/src/event-log/conference/conference-chat-message-event.h +++ b/src/event-log/conference/conference-chat-message-event.h @@ -33,7 +33,7 @@ class ConferenceChatMessageEventPrivate; class LINPHONE_PUBLIC ConferenceChatMessageEvent : public ConferenceEvent { public: - ConferenceChatMessageEvent (std::time_t time, const std::shared_ptr &chatMessage); + ConferenceChatMessageEvent (time_t time, const std::shared_ptr &chatMessage); std::shared_ptr getChatMessage () const; diff --git a/src/event-log/conference/conference-event.h b/src/event-log/conference/conference-event.h index 080c9e9a2..93a64a160 100644 --- a/src/event-log/conference/conference-event.h +++ b/src/event-log/conference/conference-event.h @@ -31,12 +31,12 @@ class ConferenceEventPrivate; class LINPHONE_PUBLIC ConferenceEvent : public EventLog { public: - ConferenceEvent (Type type, std::time_t time, const Address &conferenceAddress); + ConferenceEvent (Type type, time_t time, const Address &conferenceAddress); const Address &getConferenceAddress () const; protected: - ConferenceEvent (ConferenceEventPrivate &p, Type type, std::time_t time, const Address &conferenceAddress); + ConferenceEvent (ConferenceEventPrivate &p, Type type, time_t time, const Address &conferenceAddress); private: L_DECLARE_PRIVATE(ConferenceEvent); diff --git a/src/event-log/conference/conference-notified-event.h b/src/event-log/conference/conference-notified-event.h index eca259f49..0c16de48f 100644 --- a/src/event-log/conference/conference-notified-event.h +++ b/src/event-log/conference/conference-notified-event.h @@ -31,7 +31,7 @@ class ConferenceNotifiedEventPrivate; class LINPHONE_PUBLIC ConferenceNotifiedEvent : public ConferenceEvent { public: ConferenceNotifiedEvent ( - Type type, std::time_t time, + Type type, time_t time, const Address &conferenceAddress, unsigned int notifiyId ); @@ -42,7 +42,7 @@ protected: ConferenceNotifiedEvent ( ConferenceNotifiedEventPrivate &p, Type type, - std::time_t time, + time_t time, const Address &conferenceAddress, unsigned int notifyId ); diff --git a/src/event-log/conference/conference-participant-device-event.h b/src/event-log/conference/conference-participant-device-event.h index d57834dd7..a4e1aca79 100644 --- a/src/event-log/conference/conference-participant-device-event.h +++ b/src/event-log/conference/conference-participant-device-event.h @@ -32,7 +32,7 @@ class LINPHONE_PUBLIC ConferenceParticipantDeviceEvent : public ConferencePartic public: ConferenceParticipantDeviceEvent ( Type type, - std::time_t time, + time_t time, const Address &conferenceAddress, unsigned int notifyId, const Address &participantAddress, diff --git a/src/event-log/conference/conference-participant-event.h b/src/event-log/conference/conference-participant-event.h index 792583dcf..d699adc9b 100644 --- a/src/event-log/conference/conference-participant-event.h +++ b/src/event-log/conference/conference-participant-event.h @@ -32,7 +32,7 @@ class LINPHONE_PUBLIC ConferenceParticipantEvent : public ConferenceNotifiedEven public: ConferenceParticipantEvent ( Type type, - std::time_t time, + time_t time, const Address &conferenceAddress, unsigned int notifyId, const Address &participantAddress @@ -44,7 +44,7 @@ protected: ConferenceParticipantEvent ( ConferenceParticipantEventPrivate &p, Type type, - std::time_t time, + time_t time, const Address &conferenceAddress, unsigned int notifyId, const Address &participantAddress diff --git a/src/event-log/conference/conference-subject-event.h b/src/event-log/conference/conference-subject-event.h index 8ea9a039f..02e1bcf67 100644 --- a/src/event-log/conference/conference-subject-event.h +++ b/src/event-log/conference/conference-subject-event.h @@ -33,7 +33,7 @@ class ConferenceSubjectEventPrivate; class LINPHONE_PUBLIC ConferenceSubjectEvent : public ConferenceNotifiedEvent { public: ConferenceSubjectEvent ( - std::time_t time, + time_t time, const Address &conferenceAddress, unsigned int notifyId, const std::string &subject diff --git a/src/event-log/event-log-p.h b/src/event-log/event-log-p.h index 4c4085883..a5a566594 100644 --- a/src/event-log/event-log-p.h +++ b/src/event-log/event-log-p.h @@ -35,7 +35,7 @@ public: private: EventLog::Type type = EventLog::Type::None; - std::time_t time = -1; + time_t time = -1; L_DECLARE_PUBLIC(EventLog); }; diff --git a/src/event-log/event-log.cpp b/src/event-log/event-log.cpp index 9ccfa8afc..e6a821f1c 100644 --- a/src/event-log/event-log.cpp +++ b/src/event-log/event-log.cpp @@ -26,7 +26,7 @@ LINPHONE_BEGIN_NAMESPACE EventLog::EventLog () : BaseObject(*new EventLogPrivate) {} -EventLog::EventLog (EventLogPrivate &p, Type type, std::time_t time) : BaseObject(p) { +EventLog::EventLog (EventLogPrivate &p, Type type, time_t time) : BaseObject(p) { L_D(); d->type = type; d->time = time; @@ -37,7 +37,7 @@ EventLog::Type EventLog::getType () const { return d->type; } -std::time_t EventLog::getTime () const { +time_t EventLog::getTime () const { L_D(); return d->time; } diff --git a/src/event-log/event-log.h b/src/event-log/event-log.h index 9e43aec8c..265a63ce7 100644 --- a/src/event-log/event-log.h +++ b/src/event-log/event-log.h @@ -43,10 +43,10 @@ public: EventLog (); Type getType () const; - std::time_t getTime () const; + time_t getTime () const; protected: - EventLog (EventLogPrivate &p, Type type, std::time_t time); + EventLog (EventLogPrivate &p, Type type, time_t time); private: L_DECLARE_PRIVATE(EventLog); From a39d7d01b92593ee6d89ad16269fd05eedcccad3 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 15 Nov 2017 16:56:18 +0100 Subject: [PATCH 0785/2215] Workaround bug in doxygen before version 1.8.8. --- include/linphone/utils/enum-generator.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/include/linphone/utils/enum-generator.h b/include/linphone/utils/enum-generator.h index 246834782..09c04328f 100644 --- a/include/linphone/utils/enum-generator.h +++ b/include/linphone/utils/enum-generator.h @@ -32,12 +32,12 @@ LINPHONE_BEGIN_NAMESPACE // Declare one enum value. `value` is optional, it can be generated. // It's useful to force value in the case of mask. -#define L_DECLARE_ENUM_VALUE_1_ARGS(NAME) NAME, +#define L_DECLARE_ENUM_VALUE_1_ARG(NAME) NAME, #define L_DECLARE_ENUM_VALUE_2_ARGS(NAME, VALUE) NAME = VALUE, // Call the right macro. (With or without value.) #define L_DECLARE_ENUM_MACRO_CHOOSER(...) \ - L_GET_ARG_3(__VA_ARGS__, L_DECLARE_ENUM_VALUE_2_ARGS, L_DECLARE_ENUM_VALUE_1_ARGS) + L_GET_ARG_3(__VA_ARGS__, L_DECLARE_ENUM_VALUE_2_ARGS, L_DECLARE_ENUM_VALUE_1_ARG) // Enum value declaration. #define L_DECLARE_ENUM_VALUE(...) L_DECLARE_ENUM_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__) @@ -53,10 +53,24 @@ LINPHONE_BEGIN_NAMESPACE #define L_C_ENUM_PREFIX Linphone +// TODO: This macro should be used but it is triggering a bug in doxygen that +// has been fixed in the 1.8.8 version. See https://bugzilla.gnome.org/show_bug.cgi?id=731985 +// Meanwhile use 2 different macros +#if 0 #define L_DECLARE_C_ENUM(NAME, VALUES) \ typedef enum L_CONCAT(_, L_CONCAT(L_C_ENUM_PREFIX, NAME)) { \ L_APPLY(L_CONCAT, L_CONCAT(L_C_ENUM_PREFIX, NAME), L_GET_HEAP(VALUES(L_DECLARE_ENUM_VALUE))) \ } L_CONCAT(L_C_ENUM_PREFIX, NAME) +#else +#define L_DECLARE_C_ENUM(NAME, VALUES) \ + typedef enum L_CONCAT(_, L_CONCAT(L_C_ENUM_PREFIX, NAME)) { \ + L_APPLY(L_CONCAT, L_CONCAT(L_C_ENUM_PREFIX, NAME), L_GET_HEAP(VALUES(L_DECLARE_ENUM_VALUE_1_ARG))) \ + } L_CONCAT(L_C_ENUM_PREFIX, NAME) +#define L_DECLARE_C_ENUM_FIXED_VALUES(NAME, VALUES) \ + typedef enum L_CONCAT(_, L_CONCAT(L_C_ENUM_PREFIX, NAME)) { \ + L_APPLY(L_CONCAT, L_CONCAT(L_C_ENUM_PREFIX, NAME), L_GET_HEAP(VALUES(L_DECLARE_ENUM_VALUE_2_ARGS))) \ + } L_CONCAT(L_C_ENUM_PREFIX, NAME) +#endif LINPHONE_END_NAMESPACE From f117ff958c17777f3b8fe8e5c15b6098d1bb1bb2 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 16 Nov 2017 14:08:36 +0100 Subject: [PATCH 0786/2215] Fix chat related code that was broken with the introduction of ChatRoomId. --- coreapi/callbacks.c | 14 ++++++------- coreapi/chat.c | 18 +++++++++++------ coreapi/linphonecore.c | 27 +++++++++++++------------- coreapi/tester_utils.cpp | 13 +++++++------ coreapi/tester_utils.h | 2 +- src/chat/chat-message/chat-message-p.h | 5 +++++ src/chat/chat-message/chat-message.cpp | 25 ++++++++++-------------- src/chat/chat-message/chat-message.h | 10 ++-------- src/chat/chat-room/chat-room.cpp | 6 +++--- src/core/core-chat-room.cpp | 4 +++- 10 files changed, 62 insertions(+), 62 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index ea68b4db5..8d497bd97 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -129,7 +129,7 @@ static void call_received(SalCallOp *h) { linphone_address_unref(toAddr); linphone_address_unref(fromAddr); shared_ptr chatRoom = lc->cppCore->findChatRoom( - ChatRoomId(SimpleAddress(h->get_to()), SimpleAddress(h->get_from())) + ChatRoomId(SimpleAddress(h->get_to()), SimpleAddress(h->get_to())) ); if (chatRoom) { L_GET_PRIVATE(static_pointer_cast(chatRoom))->confirmJoining(h); @@ -753,10 +753,10 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ if (linphone_core_conference_server_enabled(lc)) { // Removal of a participant at the server side shared_ptr chatRoom = lc->cppCore->findChatRoom( - ChatRoomId(SimpleAddress(op->get_to()), SimpleAddress(op->get_from())) + ChatRoomId(SimpleAddress(op->get_to()), SimpleAddress(op->get_to())) ); if (chatRoom) { - std::shared_ptr participant = chatRoom->findParticipant(chatRoom->getLocalAddress()); + std::shared_ptr participant = chatRoom->findParticipant(SimpleAddress(op->get_from())); if (!participant || !participant->isAdmin()) { static_cast(op)->reply(SalReasonDeclined); return; @@ -770,7 +770,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ } else { // The server asks a participant to leave a chat room LinphoneChatRoom *cr = L_GET_C_BACK_PTR( - lc->cppCore->findChatRoom(ChatRoomId(addr, SimpleAddress(op->get_from()))) + lc->cppCore->findChatRoom(ChatRoomId(addr, SimpleAddress(op->get_to()))) ); if (cr) { L_GET_CPP_PTR_FROM_C_OBJECT(cr)->leave(); @@ -781,7 +781,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ } } else if (addr.hasParam("admin")) { LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom( - ChatRoomId(SimpleAddress(op->get_to()), SimpleAddress(op->get_from())) + ChatRoomId(SimpleAddress(op->get_to()), SimpleAddress(op->get_to())) )); if (cr) { Address fromAddr(op->get_from()); @@ -799,9 +799,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ return; } } else { - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom( - ChatRoomId(addr, SimpleAddress(op->get_from())) - )); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(ChatRoomId(addr, SimpleAddress(op->get_to())))); if (!cr) cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); diff --git a/coreapi/chat.c b/coreapi/chat.c index 8ad8a7232..8a0900a67 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -111,15 +111,21 @@ LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const c int linphone_core_message_received(LinphoneCore *lc, LinphonePrivate::SalOp *op, const SalMessage *sal_msg) { LinphoneReason reason = LinphoneReasonNotAcceptable; - const char *peerAddress = linphone_core_conference_server_enabled(lc) ? op->get_to() : op->get_from(); + const char *peerAddress; + const char *localAddress; + if (linphone_core_conference_server_enabled(lc)) { + localAddress = peerAddress = op->get_to(); + } else { + peerAddress = op->get_from(); + localAddress = op->get_to(); + } - // TODO: Use local address. - list> chatRooms = lc->cppCore->findChatRooms( - LinphonePrivate::SimpleAddress(peerAddress) + shared_ptr chatRoom = lc->cppCore->findChatRoom( + LinphonePrivate::ChatRoomId(LinphonePrivate::SimpleAddress(peerAddress), LinphonePrivate::SimpleAddress(localAddress)) ); - if (!chatRooms.empty()) - reason = L_GET_PRIVATE(chatRooms.front())->messageReceived(op, sal_msg); + if (chatRoom) + reason = L_GET_PRIVATE(chatRoom)->messageReceived(op, sal_msg); else { LinphoneAddress *addr = linphone_address_new(sal_msg->from); linphone_address_clean(addr); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index fb06d3135..8d280a322 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2135,16 +2135,17 @@ static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEve } } else if (strcmp(notified_event, "conference") == 0) { const LinphoneAddress *resource = linphone_event_get_resource(lev); + const LinphoneAddress *from = linphone_event_get_from(lev); - // TODO: Ensure it is the good solution. - list> chatRooms = lc->cppCore->findChatRooms( - SimpleAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(resource)) - ); + shared_ptr chatRoom = lc->cppCore->findChatRoom(LinphonePrivate::ChatRoomId( + SimpleAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(resource)), + SimpleAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(from)) + )); - if (!chatRooms.empty()) - L_GET_PRIVATE(static_pointer_cast(chatRooms.front()))->notifyReceived( + if (chatRoom) + L_GET_PRIVATE(static_pointer_cast(chatRoom))->notifyReceived( linphone_content_get_string_buffer(body) - ); + ); } } @@ -2154,15 +2155,13 @@ static void _linphone_core_conference_subscription_state_changed(LinphoneCore *l state == LinphoneSubscriptionIncomingReceived ) { const LinphoneAddress *resource = linphone_event_get_resource(lev); - - // TODO: Ensure it is the good solution. - list> chatRooms = lc->cppCore->findChatRooms( + shared_ptr chatRoom = lc->cppCore->findChatRoom(LinphonePrivate::ChatRoomId( + SimpleAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(resource)), SimpleAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(resource)) - ); - - if (!chatRooms.empty()) { + )); + if (chatRoom) { linphone_event_accept_subscription(lev); - L_GET_PRIVATE(static_pointer_cast(chatRooms.front()))->subscribeReceived(lev); + L_GET_PRIVATE(static_pointer_cast(chatRoom))->subscribeReceived(lev); } else linphone_event_deny_subscription(lev, LinphoneReasonDeclined); } diff --git a/coreapi/tester_utils.cpp b/coreapi/tester_utils.cpp index 15523fdcc..b166d2947 100644 --- a/coreapi/tester_utils.cpp +++ b/coreapi/tester_utils.cpp @@ -56,13 +56,14 @@ bctbx_list_t **linphone_core_get_call_logs_attribute(LinphoneCore *lc) { return &lc->call_logs; } -LinphoneChatRoom * linphone_core_find_chat_room (const LinphoneCore *lc, const LinphoneAddress *addr) { - list> chatRooms = lc->cppCore->findChatRooms( - SimpleAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr)) - ); +LinphoneChatRoom * linphone_core_find_chat_room (const LinphoneCore *lc, const LinphoneAddress *peerAddr, const LinphoneAddress *localAddr) { + shared_ptr chatRoom = lc->cppCore->findChatRoom(ChatRoomId( + SimpleAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(peerAddr)), + SimpleAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(localAddr)) + )); - if (!chatRooms.empty()) - return L_GET_C_BACK_PTR(chatRooms.front()); + if (chatRoom) + return L_GET_C_BACK_PTR(chatRoom); return nullptr; } diff --git a/coreapi/tester_utils.h b/coreapi/tester_utils.h index 1d6f7f701..2dade201e 100644 --- a/coreapi/tester_utils.h +++ b/coreapi/tester_utils.h @@ -94,7 +94,7 @@ LINPHONE_PUBLIC LinphoneQualityReporting *linphone_call_log_get_quality_reportin LINPHONE_PUBLIC reporting_session_report_t **linphone_quality_reporting_get_reports(LinphoneQualityReporting *qreporting); LINPHONE_PUBLIC bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr); -LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_find_chat_room (const LinphoneCore *lc, const LinphoneAddress *addr); +LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_find_chat_room (const LinphoneCore *lc, const LinphoneAddress *peerAddr, const LinphoneAddress *localAddr); LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_from_db(LinphoneCore *lc, LinphoneFriendList *list); LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_lists_from_db(LinphoneCore *lc); diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index d89accaa3..82303a0b4 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -67,6 +67,10 @@ public: this->fromAddress = fromAddress; } + inline void forceToAddress (const SimpleAddress &toAddress) { + this->toAddress = toAddress; + } + unsigned int getStorageId() const; void setStorageId(unsigned int id); @@ -149,6 +153,7 @@ private: std::weak_ptr chatRoom; ChatRoomId chatRoomId; SimpleAddress fromAddress; + SimpleAddress toAddress; ChatMessage::State state = ChatMessage::State::Idle; ChatMessage::Direction direction = ChatMessage::Direction::Incoming; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index eb9d3fe49..181b9c53f 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -678,26 +678,21 @@ void ChatMessagePrivate::send () { // ----------------------------------------------------------------------------- -ChatMessage::ChatMessage (const shared_ptr &chatRoom) : +ChatMessage::ChatMessage (const shared_ptr &chatRoom, ChatMessage::Direction direction) : Object(*new ChatMessagePrivate), CoreAccessor(chatRoom->getCore()) { L_ASSERT(chatRoom); L_D(); d->chatRoom = chatRoom; d->chatRoomId = chatRoom->getChatRoomId(); - d->fromAddress = chatRoom->getLocalAddress(); - d->direction = Direction::Outgoing; -} - -ChatMessage::ChatMessage (const shared_ptr &chatRoom, const SimpleAddress &fromAddress) : - Object(*new ChatMessagePrivate), CoreAccessor(chatRoom->getCore()) { - L_ASSERT(chatRoom); - L_D(); - - d->chatRoom = chatRoom; - d->chatRoomId = chatRoom->getChatRoomId(); - d->fromAddress = fromAddress; - d->direction = Direction::Incoming; + if (direction == Direction::Outgoing) { + d->fromAddress = chatRoom->getLocalAddress(); + d->toAddress = chatRoom->getPeerAddress(); + } else { + d->fromAddress = chatRoom->getPeerAddress(); + d->toAddress = chatRoom->getLocalAddress(); + } + d->direction = direction; } ChatMessage::~ChatMessage () { @@ -779,7 +774,7 @@ const SimpleAddress &ChatMessage::getFromAddress () const { const SimpleAddress &ChatMessage::getToAddress () const { L_D(); - return d->direction == Direction::Outgoing ? d->chatRoomId.getPeerAddress() : d->chatRoomId.getLocalAddress(); + return d->toAddress; } const SimpleAddress &ChatMessage::getLocalAddress () const { diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index f2eb00bf3..8bca457ff 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -55,14 +55,6 @@ public: L_DECLARE_ENUM(State, L_ENUM_VALUES_CHAT_MESSAGE_STATE); L_DECLARE_ENUM(Direction, L_ENUM_VALUES_CHAT_MESSAGE_DIRECTION); - // TODO: Make me private. - - // Build an outgoing message. - ChatMessage (const std::shared_ptr &chatRoom); - - // Build and incoming message. - ChatMessage (const std::shared_ptr &chatRoom, const SimpleAddress &fromAddress); - ~ChatMessage (); // ----- TODO: Remove me. @@ -114,6 +106,8 @@ public: bool downloadFile (FileTransferContent &content); private: + ChatMessage (const std::shared_ptr &chatRoom, ChatMessage::Direction direction); + L_DECLARE_PRIVATE(ChatMessage); L_DISABLE_COPY(ChatMessage); }; diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 319cce5e3..b4b29ead7 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -151,7 +151,7 @@ void ChatRoomPrivate::sendIsComposingNotification () { if (linphone_im_notif_policy_get_send_is_composing(policy)) { string payload = isComposingHandler->marshal(isComposing); if (!payload.empty()) { - shared_ptr msg = q->createMessage(); + shared_ptr msg = createChatMessage(ChatMessage::Direction::Outgoing); Content *content = new Content(); content->setContentType(ContentType::ImIsComposing); content->setBody(payload); @@ -164,8 +164,8 @@ void ChatRoomPrivate::sendIsComposingNotification () { // ----------------------------------------------------------------------------- shared_ptr ChatRoomPrivate::createChatMessage (ChatMessage::Direction direction) { - // TODO: Create me. - return nullptr; + L_Q(); + return shared_ptr(new ChatMessage(q->getSharedFromThis(), direction)); } // ----------------------------------------------------------------------------- diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index fc10049ff..186748997 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -50,7 +50,9 @@ static inline ChatRoomId resolveWorkaroundClientGroupChatRoomId ( SimpleAddress peerAddress = chatRoomId.getPeerAddress(); peerAddress.setDomain(Address(uri).getDomain()); - return ChatRoomId(peerAddress, chatRoomId.getLocalAddress()); + SimpleAddress localAddress = chatRoomId.getLocalAddress(); + localAddress.setDomain(Address(uri).getDomain()); + return ChatRoomId(peerAddress, localAddress); } // TODO: Remove me later. From 902cb5010433689d4a9515a8113062de3ee7f706 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 16 Nov 2017 16:05:18 +0100 Subject: [PATCH 0787/2215] Merge SimpleAddress and GruuAddress classes into a single IdentityAddress class. --- coreapi/callbacks.c | 12 +- coreapi/chat.c | 2 +- coreapi/linphonecore.c | 8 +- coreapi/tester_utils.cpp | 4 +- src/CMakeLists.txt | 9 +- src/address/address.cpp | 24 +--- src/address/address.h | 8 +- src/address/gruu-address-p.h | 40 ------- src/address/gruu-address.cpp | 107 ------------------ src/address/gruu-address.h | 59 ---------- ...imple-address-p.h => identity-address-p.h} | 16 +-- ...imple-address.cpp => identity-address.cpp} | 73 +++++++----- .../{simple-address.h => identity-address.h} | 40 ++++--- src/chat/chat-message/chat-message-p.h | 8 +- src/chat/chat-message/chat-message.cpp | 8 +- src/chat/chat-message/chat-message.h | 10 +- src/chat/chat-room/chat-room-id.cpp | 12 +- src/chat/chat-room/chat-room-id.h | 8 +- src/chat/chat-room/chat-room.cpp | 6 +- src/chat/chat-room/chat-room.h | 4 +- src/chat/chat-room/client-group-chat-room.cpp | 6 +- src/chat/chat-room/client-group-chat-room.h | 2 +- .../chat-room/server-group-chat-room-stub.cpp | 2 +- src/conference/conference.cpp | 4 +- .../local-conference-event-handler.cpp | 2 +- src/conference/participant-device.cpp | 2 +- src/conference/participant-device.h | 8 +- src/conference/participant-p.h | 10 +- src/conference/participant.cpp | 12 +- src/conference/participant.h | 4 +- .../remote-conference-event-handler.cpp | 8 +- src/core/core-chat-room.cpp | 18 +-- src/core/core.h | 8 +- tester/cpim-tester.cpp | 2 +- tester/multipart-tester.cpp | 2 +- 35 files changed, 167 insertions(+), 381 deletions(-) delete mode 100644 src/address/gruu-address-p.h delete mode 100644 src/address/gruu-address.cpp delete mode 100644 src/address/gruu-address.h rename src/address/{simple-address-p.h => identity-address-p.h} (78%) rename src/address/{simple-address.cpp => identity-address.cpp} (54%) rename src/address/{simple-address.h => identity-address.h} (60%) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 8d497bd97..2c1d6a8c9 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -129,7 +129,7 @@ static void call_received(SalCallOp *h) { linphone_address_unref(toAddr); linphone_address_unref(fromAddr); shared_ptr chatRoom = lc->cppCore->findChatRoom( - ChatRoomId(SimpleAddress(h->get_to()), SimpleAddress(h->get_to())) + ChatRoomId(IdentityAddress(h->get_to()), IdentityAddress(h->get_to())) ); if (chatRoom) { L_GET_PRIVATE(static_pointer_cast(chatRoom))->confirmJoining(h); @@ -753,10 +753,10 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ if (linphone_core_conference_server_enabled(lc)) { // Removal of a participant at the server side shared_ptr chatRoom = lc->cppCore->findChatRoom( - ChatRoomId(SimpleAddress(op->get_to()), SimpleAddress(op->get_to())) + ChatRoomId(IdentityAddress(op->get_to()), IdentityAddress(op->get_to())) ); if (chatRoom) { - std::shared_ptr participant = chatRoom->findParticipant(SimpleAddress(op->get_from())); + std::shared_ptr participant = chatRoom->findParticipant(IdentityAddress(op->get_from())); if (!participant || !participant->isAdmin()) { static_cast(op)->reply(SalReasonDeclined); return; @@ -770,7 +770,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ } else { // The server asks a participant to leave a chat room LinphoneChatRoom *cr = L_GET_C_BACK_PTR( - lc->cppCore->findChatRoom(ChatRoomId(addr, SimpleAddress(op->get_to()))) + lc->cppCore->findChatRoom(ChatRoomId(addr, IdentityAddress(op->get_to()))) ); if (cr) { L_GET_CPP_PTR_FROM_C_OBJECT(cr)->leave(); @@ -781,7 +781,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ } } else if (addr.hasParam("admin")) { LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom( - ChatRoomId(SimpleAddress(op->get_to()), SimpleAddress(op->get_to())) + ChatRoomId(IdentityAddress(op->get_to()), IdentityAddress(op->get_to())) )); if (cr) { Address fromAddr(op->get_from()); @@ -799,7 +799,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ return; } } else { - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(ChatRoomId(addr, SimpleAddress(op->get_to())))); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(ChatRoomId(addr, IdentityAddress(op->get_to())))); if (!cr) cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); diff --git a/coreapi/chat.c b/coreapi/chat.c index 8a0900a67..0ebe80b6e 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -121,7 +121,7 @@ int linphone_core_message_received(LinphoneCore *lc, LinphonePrivate::SalOp *op, } shared_ptr chatRoom = lc->cppCore->findChatRoom( - LinphonePrivate::ChatRoomId(LinphonePrivate::SimpleAddress(peerAddress), LinphonePrivate::SimpleAddress(localAddress)) + LinphonePrivate::ChatRoomId(LinphonePrivate::IdentityAddress(peerAddress), LinphonePrivate::IdentityAddress(localAddress)) ); if (chatRoom) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 8d280a322..bc5be81cd 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2138,8 +2138,8 @@ static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEve const LinphoneAddress *from = linphone_event_get_from(lev); shared_ptr chatRoom = lc->cppCore->findChatRoom(LinphonePrivate::ChatRoomId( - SimpleAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(resource)), - SimpleAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(from)) + IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(resource)), + IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(from)) )); if (chatRoom) @@ -2156,8 +2156,8 @@ static void _linphone_core_conference_subscription_state_changed(LinphoneCore *l ) { const LinphoneAddress *resource = linphone_event_get_resource(lev); shared_ptr chatRoom = lc->cppCore->findChatRoom(LinphonePrivate::ChatRoomId( - SimpleAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(resource)), - SimpleAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(resource)) + IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(resource)), + IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(resource)) )); if (chatRoom) { linphone_event_accept_subscription(lev); diff --git a/coreapi/tester_utils.cpp b/coreapi/tester_utils.cpp index b166d2947..f5d50e8e3 100644 --- a/coreapi/tester_utils.cpp +++ b/coreapi/tester_utils.cpp @@ -58,8 +58,8 @@ bctbx_list_t **linphone_core_get_call_logs_attribute(LinphoneCore *lc) { LinphoneChatRoom * linphone_core_find_chat_room (const LinphoneCore *lc, const LinphoneAddress *peerAddr, const LinphoneAddress *localAddr) { shared_ptr chatRoom = lc->cppCore->findChatRoom(ChatRoomId( - SimpleAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(peerAddr)), - SimpleAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(localAddr)) + IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(peerAddr)), + IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(localAddr)) )); if (chatRoom) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2ad611b2e..2df1a80a2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,10 +23,8 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES address/address-p.h address/address.h - address/gruu-address-p.h - address/gruu-address.h - address/simple-address-p.h - address/simple-address.h + address/identity-address-p.h + address/identity-address.h c-wrapper/c-wrapper.h c-wrapper/internal/c-sal.h c-wrapper/internal/c-tools.h @@ -145,8 +143,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES set(LINPHONE_CXX_OBJECTS_SOURCE_FILES address/address.cpp - address/gruu-address.cpp - address/simple-address.cpp + address/identity-address.cpp c-wrapper/api/c-address.cpp c-wrapper/api/c-call-cbs.cpp c-wrapper/api/c-call-params.cpp diff --git a/src/address/address.cpp b/src/address/address.cpp index 924eb9ad0..75d38cab3 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -22,8 +22,7 @@ #include "address-p.h" #include "c-wrapper/c-wrapper.h" #include "logger/logger.h" -#include "address/gruu-address.h" -#include "address/simple-address.h" +#include "address/identity-address.h" // ============================================================================= @@ -47,28 +46,17 @@ Address::Address (const Address &src) : ClonableObject(*new AddressPrivate) { d->internalAddress = sal_address_clone(salAddress); } -Address::Address (const GruuAddress &src) : ClonableObject(*new AddressPrivate) { +Address::Address (const IdentityAddress &src) : ClonableObject(*new AddressPrivate) { L_D(); - string uri = src.getScheme() + ":" + src.getUsername() + "@"; + string uri = "sip:" + src.getUsername() + "@"; if (src.getDomain().find(':') != string::npos) uri += "[" + src.getDomain() + "]"; else uri += src.getDomain(); - uri += "?gr=" + src.getUrn(); + if (src.hasGruu()) + uri += "?gr=" + src.getGruu(); if (!(d->internalAddress = sal_address_new(L_STRING_TO_C(uri)))) { - lWarning() << "Cannot create Address, bad GruuAddress source"; - } -} - -Address::Address (const SimpleAddress &src) : ClonableObject(*new AddressPrivate) { - L_D(); - string uri = src.getScheme() + ":" + src.getUsername() + "@"; - if (src.getDomain().find(':') != string::npos) - uri += "[" + src.getDomain() + "]"; - else - uri += src.getDomain(); - if (!(d->internalAddress = sal_address_new(L_STRING_TO_C(uri)))) { - lWarning() << "Cannot create Address, bad SimpleAddress source"; + lWarning() << "Cannot create Address, bad IdentityAddress source"; } } diff --git a/src/address/address.h b/src/address/address.h index e3c5f7ef4..718273731 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -28,8 +28,7 @@ LINPHONE_BEGIN_NAMESPACE class AddressPrivate; -class GruuAddress; -class SimpleAddress; +class IdentityAddress; class LINPHONE_PUBLIC Address : public ClonableObject { // TODO: Remove me later. @@ -38,13 +37,12 @@ class LINPHONE_PUBLIC Address : public ClonableObject { friend class ClientGroupChatRoomPrivate; friend class ServerGroupChatRoom; friend class ServerGroupChatRoomPrivate; - friend class SimpleAddress; + friend class IdentityAddress; public: explicit Address (const std::string &address = ""); Address (const Address &src); - Address (const GruuAddress &src); - Address (const SimpleAddress &src); + Address (const IdentityAddress &src); ~Address (); Address &operator= (const Address &src); diff --git a/src/address/gruu-address-p.h b/src/address/gruu-address-p.h deleted file mode 100644 index 116707db5..000000000 --- a/src/address/gruu-address-p.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * gruu-address-p.h - * Copyright (C) 2010-2017 Belledonne Communications SARL - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _GRUU_ADDRESS_P_H_ -#define _GRUU_ADDRESS_P_H_ - -#include "gruu-address.h" -#include "address/simple-address-p.h" - -// ============================================================================= - -LINPHONE_BEGIN_NAMESPACE - -class GruuAddressPrivate : public SimpleAddressPrivate { -private: - std::string urn; - bool valid = false; - - L_DECLARE_PUBLIC(GruuAddress); -}; - -LINPHONE_END_NAMESPACE - -#endif // ifndef _GRUU_ADDRESS_P_H_ diff --git a/src/address/gruu-address.cpp b/src/address/gruu-address.cpp deleted file mode 100644 index 636e8d929..000000000 --- a/src/address/gruu-address.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * gruu-address.cpp - * Copyright (C) 2010-2017 Belledonne Communications SARL - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "linphone/utils/utils.h" - -#include "gruu-address-p.h" -#include "c-wrapper/c-wrapper.h" -#include "logger/logger.h" - -// ============================================================================= - -using namespace std; - -LINPHONE_BEGIN_NAMESPACE - -// ----------------------------------------------------------------------------- - -GruuAddress::GruuAddress (const string &address) : SimpleAddress(*new GruuAddressPrivate) { - L_D(); - Address tmpAddress(address); - if (tmpAddress.isValid()) { - if (!tmpAddress.hasUriParam("gr")) - return; - SimpleAddress base(address); - SimpleAddress::clone(base); - d->urn = tmpAddress.getUriParamValue("gr"); - d->valid = true; - } -} - -GruuAddress::GruuAddress (const GruuAddress &src) : SimpleAddress(*new GruuAddressPrivate) { - L_D(); - SimpleAddress::clone(src); - d->urn = src.getPrivate()->urn; - d->valid = src.getPrivate()->valid; -} - -GruuAddress::GruuAddress (const Address &src) : SimpleAddress(*new GruuAddressPrivate) { - L_D(); - if (src.isValid()) { - if (!src.hasUriParam("gr")) - return; - SimpleAddress::clone(SimpleAddress(src)); - d->urn = src.getUriParamValue("gr"); - d->valid = true; - } -} - -GruuAddress &GruuAddress::operator= (const GruuAddress &src) { - L_D(); - if (this != &src) { - SimpleAddress::operator=(src); - d->urn = src.getPrivate()->urn; - d->valid = src.getPrivate()->valid; - } - return *this; -} - -bool GruuAddress::operator== (const GruuAddress &address) const { - return asString() == address.asString(); -} - -bool GruuAddress::operator!= (const GruuAddress &address) const { - return !(*this == address); -} - -bool GruuAddress::operator< (const GruuAddress &address) const { - return asString() < address.asString(); -} - -bool GruuAddress::isValid () const { - L_D(); - return d->valid; -} - -string GruuAddress::getUrn () const { - L_D(); - return d->urn; -} - -void GruuAddress::setUrn (const string &urn) { - L_D(); - d->urn = urn; -} - -string GruuAddress::asString () const { - Address tmpAddress(*this); - return tmpAddress.asStringUriOnly(); -} - -LINPHONE_END_NAMESPACE diff --git a/src/address/gruu-address.h b/src/address/gruu-address.h deleted file mode 100644 index d9c5d269d..000000000 --- a/src/address/gruu-address.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * gruu-address.h - * Copyright (C) 2010-2017 Belledonne Communications SARL - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _GRUU_ADDRESS_H_ -#define _GRUU_ADDRESS_H_ - -#include "address/simple-address.h" - -// ============================================================================= - -LINPHONE_BEGIN_NAMESPACE - -class Address; -class GruuAddressPrivate; - -class LINPHONE_PUBLIC GruuAddress : public SimpleAddress { -public: - explicit GruuAddress (const std::string &address = ""); - GruuAddress (const GruuAddress &src); - GruuAddress (const Address &src); - ~GruuAddress () = default; - - GruuAddress &operator= (const GruuAddress &src); - - bool operator== (const GruuAddress &address) const; - bool operator!= (const GruuAddress &address) const; - - bool operator< (const GruuAddress &address) const; - - bool isValid () const; - - std::string getUrn () const; - void setUrn (const std::string &urn); - - std::string asString () const override; - -private: - L_DECLARE_PRIVATE(GruuAddress); -}; - -LINPHONE_END_NAMESPACE - -#endif // ifndef _GRUU_ADDRESS_H_ diff --git a/src/address/simple-address-p.h b/src/address/identity-address-p.h similarity index 78% rename from src/address/simple-address-p.h rename to src/address/identity-address-p.h index 49ac82f7f..b570fccc9 100644 --- a/src/address/simple-address-p.h +++ b/src/address/identity-address-p.h @@ -1,5 +1,5 @@ /* - * simple-address-p.h + * identity-address-p.h * Copyright (C) 2010-2017 Belledonne Communications SARL * * This program is free software; you can redistribute it and/or @@ -17,25 +17,25 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef _SIMPLE_ADDRESS_P_H_ -#define _SIMPLE_ADDRESS_P_H_ +#ifndef _IDENTITY_ADDRESS_P_H_ +#define _IDENTITY_ADDRESS_P_H_ -#include "simple-address.h" +#include "identity-address.h" #include "object/clonable-object-p.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE -class SimpleAddressPrivate : public ClonableObjectPrivate { +class IdentityAddressPrivate : public ClonableObjectPrivate { private: - std::string scheme; std::string username; std::string domain; + std::string gruu; - L_DECLARE_PUBLIC(SimpleAddress); + L_DECLARE_PUBLIC(IdentityAddress); }; LINPHONE_END_NAMESPACE -#endif // ifndef _SIMPLE_ADDRESS_P_H_ +#endif // ifndef _IDENTITY_ADDRESS_P_H_ diff --git a/src/address/simple-address.cpp b/src/address/identity-address.cpp similarity index 54% rename from src/address/simple-address.cpp rename to src/address/identity-address.cpp index 09d539a42..8ce4b059b 100644 --- a/src/address/simple-address.cpp +++ b/src/address/identity-address.cpp @@ -1,5 +1,5 @@ /* - * simple-address.cpp + * identity-address.cpp * Copyright (C) 2010-2017 Belledonne Communications SARL * * This program is free software; you can redistribute it and/or @@ -19,7 +19,7 @@ #include "linphone/utils/utils.h" -#include "simple-address-p.h" +#include "identity-address-p.h" #include "c-wrapper/c-wrapper.h" #include "logger/logger.h" @@ -31,91 +31,102 @@ LINPHONE_BEGIN_NAMESPACE // ----------------------------------------------------------------------------- -SimpleAddress::SimpleAddress (const string &address) : ClonableObject(*new SimpleAddressPrivate) { +IdentityAddress::IdentityAddress (const string &address) : ClonableObject(*new IdentityAddressPrivate) { L_D(); Address tmpAddress(address); - if (tmpAddress.isValid()) { - d->scheme = tmpAddress.getScheme(); + if (tmpAddress.isValid() && (tmpAddress.getScheme() == "sip")) { d->username = tmpAddress.getUsername(); d->domain = tmpAddress.getDomain(); + if (tmpAddress.hasUriParam("gr")) { + d->gruu = tmpAddress.getUriParamValue("gr"); + } } } -SimpleAddress::SimpleAddress (const SimpleAddress &src) : ClonableObject(*new SimpleAddressPrivate) { +IdentityAddress::IdentityAddress (const IdentityAddress &src) : ClonableObject(*new IdentityAddressPrivate) { L_D(); - d->scheme = src.getScheme(); d->username = src.getUsername(); d->domain = src.getDomain(); + d->gruu = src.getGruu(); } -SimpleAddress::SimpleAddress (const Address &src) : ClonableObject(*new SimpleAddressPrivate) { +IdentityAddress::IdentityAddress (const Address &src) : ClonableObject(*new IdentityAddressPrivate) { L_D(); - d->scheme = src.getScheme(); d->username = src.getUsername(); d->domain = src.getDomain(); + if (src.hasUriParam("gr")) { + d->gruu = src.getUriParamValue("gr"); + } } -SimpleAddress::SimpleAddress (SimpleAddressPrivate &p) : ClonableObject(p) {} - -SimpleAddress &SimpleAddress::operator= (const SimpleAddress &src) { +IdentityAddress &IdentityAddress::operator= (const IdentityAddress &src) { L_D(); if (this != &src) { - d->scheme = src.getScheme(); d->username = src.getUsername(); d->domain = src.getDomain(); + d->gruu = src.getGruu(); } return *this; } -bool SimpleAddress::operator== (const SimpleAddress &address) const { +bool IdentityAddress::operator== (const IdentityAddress &address) const { return asString() == address.asString(); } -bool SimpleAddress::operator!= (const SimpleAddress &address) const { +bool IdentityAddress::operator!= (const IdentityAddress &address) const { return !(*this == address); } -bool SimpleAddress::operator< (const SimpleAddress &address) const { +bool IdentityAddress::operator< (const IdentityAddress &address) const { return asString() < address.asString(); } -const string &SimpleAddress::getScheme () const { - L_D(); - return d->scheme; +bool IdentityAddress::isValid () const { + Address tmpAddress(*this); + return tmpAddress.isValid(); } -const string &SimpleAddress::getUsername () const { +const string &IdentityAddress::getUsername () const { L_D(); return d->username; } -bool SimpleAddress::setUsername (const string &username) { +bool IdentityAddress::setUsername (const string &username) { L_D(); d->username = username; return true; } -const string &SimpleAddress::getDomain () const { +const string &IdentityAddress::getDomain () const { L_D(); return d->domain; } -bool SimpleAddress::setDomain (const string &domain) { +bool IdentityAddress::setDomain (const string &domain) { L_D(); d->domain = domain; return true; } -string SimpleAddress::asString () const { +bool IdentityAddress::hasGruu () const { + L_D(); + return !d->gruu.empty(); +} + +const string &IdentityAddress::getGruu () const { + L_D(); + return d->gruu; +} + +bool IdentityAddress::setGruu (const string &gruu) { + L_D(); + d->gruu = gruu; + return true; +} + +string IdentityAddress::asString () const { Address tmpAddress(*this); return tmpAddress.asStringUriOnly(); } -void SimpleAddress::clone (const SimpleAddress &src) { - L_D(); - d->scheme = src.getPrivate()->scheme; - d->username = src.getPrivate()->username; - d->domain = src.getPrivate()->domain; -} - LINPHONE_END_NAMESPACE diff --git a/src/address/simple-address.h b/src/address/identity-address.h similarity index 60% rename from src/address/simple-address.h rename to src/address/identity-address.h index fe01071b8..b99e03513 100644 --- a/src/address/simple-address.h +++ b/src/address/identity-address.h @@ -1,5 +1,5 @@ /* - * simple-address.h + * identity-address.h * Copyright (C) 2010-2017 Belledonne Communications SARL * * This program is free software; you can redistribute it and/or @@ -17,8 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef _SIMPLE_ADDRESS_H_ -#define _SIMPLE_ADDRESS_H_ +#ifndef _IDENTITY_ADDRESS_H_ +#define _IDENTITY_ADDRESS_H_ #include "object/clonable-object.h" @@ -27,23 +27,23 @@ LINPHONE_BEGIN_NAMESPACE class Address; -class SimpleAddressPrivate; +class IdentityAddressPrivate; -class LINPHONE_PUBLIC SimpleAddress : public ClonableObject { +class LINPHONE_PUBLIC IdentityAddress : public ClonableObject { public: - explicit SimpleAddress (const std::string &address = ""); - SimpleAddress (const SimpleAddress &src); - SimpleAddress (const Address &src); - ~SimpleAddress () = default; + explicit IdentityAddress (const std::string &address = ""); + IdentityAddress (const IdentityAddress &src); + IdentityAddress (const Address &src); + ~IdentityAddress () = default; - SimpleAddress &operator= (const SimpleAddress &src); + IdentityAddress &operator= (const IdentityAddress &src); - bool operator== (const SimpleAddress &address) const; - bool operator!= (const SimpleAddress &address) const; + bool operator== (const IdentityAddress &address) const; + bool operator!= (const IdentityAddress &address) const; - bool operator< (const SimpleAddress &address) const; + bool operator< (const IdentityAddress &address) const; - const std::string &getScheme () const; + bool isValid () const; const std::string &getUsername () const; bool setUsername (const std::string &username); @@ -51,18 +51,16 @@ public: const std::string &getDomain () const; bool setDomain (const std::string &domain); - bool isSip () const; + bool hasGruu () const; + const std::string &getGruu () const; + bool setGruu (const std::string &gruu); virtual std::string asString () const; -protected: - explicit SimpleAddress (SimpleAddressPrivate &p); - void clone (const SimpleAddress &src); - private: - L_DECLARE_PRIVATE(SimpleAddress); + L_DECLARE_PRIVATE(IdentityAddress); }; LINPHONE_END_NAMESPACE -#endif // ifndef _SIMPLE_ADDRESS_H_ +#endif // ifndef _IDENTITY_ADDRESS_H_ diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index 82303a0b4..92e33a994 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -63,11 +63,11 @@ public: void setIsReadOnly(bool readOnly); - inline void forceFromAddress (const SimpleAddress &fromAddress) { + inline void forceFromAddress (const IdentityAddress &fromAddress) { this->fromAddress = fromAddress; } - inline void forceToAddress (const SimpleAddress &toAddress) { + inline void forceToAddress (const IdentityAddress &toAddress) { this->toAddress = toAddress; } @@ -152,8 +152,8 @@ private: std::weak_ptr chatRoom; ChatRoomId chatRoomId; - SimpleAddress fromAddress; - SimpleAddress toAddress; + IdentityAddress fromAddress; + IdentityAddress toAddress; ChatMessage::State state = ChatMessage::State::Idle; ChatMessage::Direction direction = ChatMessage::Direction::Incoming; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 181b9c53f..bf6b40df1 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -767,22 +767,22 @@ bool ChatMessage::isRead () const { return d->state == State::Delivered || d->state == State::Displayed || d->state == State::DeliveredToUser; } -const SimpleAddress &ChatMessage::getFromAddress () const { +const IdentityAddress &ChatMessage::getFromAddress () const { L_D(); return d->fromAddress; } -const SimpleAddress &ChatMessage::getToAddress () const { +const IdentityAddress &ChatMessage::getToAddress () const { L_D(); return d->toAddress; } -const SimpleAddress &ChatMessage::getLocalAddress () const { +const IdentityAddress &ChatMessage::getLocalAddress () const { L_D(); return d->chatRoomId.getLocalAddress(); } -const SimpleAddress &ChatMessage::getRemoteAddress () const { +const IdentityAddress &ChatMessage::getRemoteAddress () const { L_D(); return d->direction == Direction::Outgoing ? d->chatRoomId.getPeerAddress() : d->fromAddress; } diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index 8bca457ff..67988c153 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -26,7 +26,7 @@ #include "linphone/enums/chat-message-enums.h" // TODO: Remove me later? -#include "address/simple-address.h" +#include "address/identity-address.h" #include "core/core-accessor.h" #include "object/object.h" @@ -80,11 +80,11 @@ public: const std::string &getImdnMessageId () const; - const SimpleAddress &getFromAddress () const; - const SimpleAddress &getToAddress () const; + const IdentityAddress &getFromAddress () const; + const IdentityAddress &getToAddress () const; - const SimpleAddress &getLocalAddress () const; - const SimpleAddress &getRemoteAddress () const; + const IdentityAddress &getLocalAddress () const; + const IdentityAddress &getRemoteAddress () const; // TODO: Return a cpp reference. const LinphoneErrorInfo *getErrorInfo () const; diff --git a/src/chat/chat-room/chat-room-id.cpp b/src/chat/chat-room/chat-room-id.cpp index 73c907628..02bec15d9 100644 --- a/src/chat/chat-room/chat-room-id.cpp +++ b/src/chat/chat-room/chat-room-id.cpp @@ -29,8 +29,8 @@ LINPHONE_BEGIN_NAMESPACE class ChatRoomIdPrivate : public ClonableObjectPrivate { public: - SimpleAddress peerAddress; - SimpleAddress localAddress; + IdentityAddress peerAddress; + IdentityAddress localAddress; }; // ----------------------------------------------------------------------------- @@ -38,8 +38,8 @@ public: ChatRoomId::ChatRoomId () : ClonableObject(*new ChatRoomIdPrivate) {} ChatRoomId::ChatRoomId ( - const SimpleAddress &peerAddress, - const SimpleAddress &localAddress + const IdentityAddress &peerAddress, + const IdentityAddress &localAddress ) : ClonableObject(*new ChatRoomIdPrivate) { L_D(); d->peerAddress = peerAddress; @@ -64,12 +64,12 @@ bool ChatRoomId::operator< (const ChatRoomId &chatRoomId) const { return d->peerAddress < dChatRoomId->peerAddress || d->localAddress < dChatRoomId->localAddress; } -const SimpleAddress &ChatRoomId::getPeerAddress () const { +const IdentityAddress &ChatRoomId::getPeerAddress () const { L_D(); return d->peerAddress; } -const SimpleAddress &ChatRoomId::getLocalAddress () const { +const IdentityAddress &ChatRoomId::getLocalAddress () const { L_D(); return d->localAddress; } diff --git a/src/chat/chat-room/chat-room-id.h b/src/chat/chat-room/chat-room-id.h index d83926611..f0340d871 100644 --- a/src/chat/chat-room/chat-room-id.h +++ b/src/chat/chat-room/chat-room-id.h @@ -20,7 +20,7 @@ #ifndef _CHAT_ROOM_ID_H_ #define _CHAT_ROOM_ID_H_ -#include "address/simple-address.h" +#include "address/identity-address.h" // ============================================================================= @@ -31,7 +31,7 @@ class ChatRoomIdPrivate; class LINPHONE_PUBLIC ChatRoomId : public ClonableObject { public: ChatRoomId (); - ChatRoomId (const SimpleAddress &peerAddress, const SimpleAddress &localAddress); + ChatRoomId (const IdentityAddress &peerAddress, const IdentityAddress &localAddress); ChatRoomId (const ChatRoomId &src); ChatRoomId &operator= (const ChatRoomId &src); @@ -41,8 +41,8 @@ public: bool operator< (const ChatRoomId &chatRoomId) const; - const SimpleAddress &getPeerAddress () const; - const SimpleAddress &getLocalAddress () const; + const IdentityAddress &getPeerAddress () const; + const IdentityAddress &getLocalAddress () const; private: L_DECLARE_PRIVATE(ChatRoomId); diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index b4b29ead7..cc9b2e5b7 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -175,12 +175,12 @@ const ChatRoomId &ChatRoom::getChatRoomId () const { return d->chatRoomId; } -const SimpleAddress &ChatRoom::getPeerAddress () const { +const IdentityAddress &ChatRoom::getPeerAddress () const { L_D(); return d->chatRoomId.getPeerAddress(); } -const SimpleAddress &ChatRoom::getLocalAddress () const { +const IdentityAddress &ChatRoom::getLocalAddress () const { L_D(); return d->chatRoomId.getLocalAddress(); } @@ -281,7 +281,7 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa LinphoneCore *cCore = core->getCCore(); msg = createChatMessage( - SimpleAddress(op->get_from()) == q->getLocalAddress() + IdentityAddress(op->get_from()) == q->getLocalAddress() ? ChatMessage::Direction::Outgoing : ChatMessage::Direction::Incoming ); diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index 113b754b3..b11d28d93 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -49,8 +49,8 @@ public: const ChatRoomId &getChatRoomId () const; - const SimpleAddress &getPeerAddress () const; - const SimpleAddress &getLocalAddress () const; + const IdentityAddress &getPeerAddress () const; + const IdentityAddress &getLocalAddress () const; virtual CapabilitiesMask getCapabilities () const = 0; diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 4cf37f8f8..50fd91d5a 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -45,7 +45,7 @@ list
      ClientGroupChatRoomPrivate::cleanAddressesList (const list
      findParticipant(*it) || (q->getMe()->getAddress() == SimpleAddress(*it))) + if (q->findParticipant(*it) || (q->getMe()->getAddress() == IdentityAddress(*it))) it = cleanedList.erase(it); else it++; @@ -79,10 +79,10 @@ void ClientGroupChatRoomPrivate::notifyReceived (const string &body) { ClientGroupChatRoom::ClientGroupChatRoom ( const std::shared_ptr &core, const std::string &factoryUri, - const SimpleAddress &me, + const IdentityAddress &me, const std::string &subject ) : -ChatRoom(*new ClientGroupChatRoomPrivate, core, ChatRoomId(SimpleAddress(), me)), +ChatRoom(*new ClientGroupChatRoomPrivate, core, ChatRoomId(IdentityAddress(), me)), RemoteConference(core->getCCore(), me, nullptr) { L_D_T(RemoteConference, dConference); dConference->focus = make_shared(Address(factoryUri)); diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 584d72601..6d63aa704 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -35,7 +35,7 @@ public: ClientGroupChatRoom ( const std::shared_ptr &core, const std::string &factoryUri, - const SimpleAddress &me, + const IdentityAddress &me, const std::string &subject ); diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index bc89f2ba1..9356180ec 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -74,7 +74,7 @@ bool ServerGroupChatRoomPrivate::isAdminLeft () const { // ============================================================================= ServerGroupChatRoom::ServerGroupChatRoom (const shared_ptr &core, SalCallOp *op) : - ChatRoom(*new ServerGroupChatRoomPrivate, core, ChatRoomId(SimpleAddress(op->get_to()), SimpleAddress())), + ChatRoom(*new ServerGroupChatRoomPrivate, core, ChatRoomId(IdentityAddress(op->get_to()), IdentityAddress(op->get_to()))), LocalConference(core->getCCore(), Address(op->get_to()), nullptr) {} int ServerGroupChatRoom::getCapabilities () const { diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 3cbc5c93b..4af0f39f6 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -212,7 +212,7 @@ void Conference::onResetFirstVideoFrameDecoded (const shared_ptr Conference::findParticipant (const Address &addr) const { L_D(); - SimpleAddress simpleAddr(addr); + IdentityAddress simpleAddr(addr); for (const auto &participant : d->participants) { if (participant->getAddress() == simpleAddr) return participant; @@ -234,7 +234,7 @@ shared_ptr Conference::findParticipant (const shared_ptrme->getAddress() == simpleAddr; } diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index 27a57a1ef..c9854e1f4 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -274,7 +274,7 @@ void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) { bctbx_free(contactAddrStr); if (contactAddr.getUriParamValue("gr").empty()) return; - GruuAddress gruu(contactAddr); + IdentityAddress gruu(contactAddr); shared_ptr device = participant->getPrivate()->addDevice(gruu); if (linphone_event_get_subscription_state(lev) == LinphoneSubscriptionActive) { diff --git a/src/conference/participant-device.cpp b/src/conference/participant-device.cpp index 7aefa714d..9e4695218 100644 --- a/src/conference/participant-device.cpp +++ b/src/conference/participant-device.cpp @@ -29,7 +29,7 @@ LINPHONE_BEGIN_NAMESPACE ParticipantDevice::ParticipantDevice () {} -ParticipantDevice::ParticipantDevice (const GruuAddress &gruu) { +ParticipantDevice::ParticipantDevice (const IdentityAddress &gruu) { mGruu = gruu; } diff --git a/src/conference/participant-device.h b/src/conference/participant-device.h index 890f8246e..d466df80f 100644 --- a/src/conference/participant-device.h +++ b/src/conference/participant-device.h @@ -23,7 +23,7 @@ #include #include -#include "address/gruu-address.h" +#include "address/identity-address.h" #include "linphone/types.h" #include "linphone/utils/general.h" @@ -36,12 +36,12 @@ class CallSession; class ParticipantDevice { public: ParticipantDevice (); - explicit ParticipantDevice (const GruuAddress &gruu); + explicit ParticipantDevice (const IdentityAddress &gruu); virtual ~ParticipantDevice (); bool operator== (const ParticipantDevice &device) const; - inline const GruuAddress &getGruu () const { return mGruu; } + inline const IdentityAddress &getGruu () const { return mGruu; } inline std::shared_ptr getSession () const { return mSession; } inline void setSession (std::shared_ptr session) { mSession = session; } @@ -52,7 +52,7 @@ public: bool isValid () const { return mGruu.isValid(); } private: - GruuAddress mGruu; + IdentityAddress mGruu; std::shared_ptr mSession; LinphoneEvent *mConferenceSubscribeEvent = nullptr; }; diff --git a/src/conference/participant-p.h b/src/conference/participant-p.h index 2db34d89e..aa754c2af 100644 --- a/src/conference/participant-p.h +++ b/src/conference/participant-p.h @@ -38,17 +38,17 @@ public: std::shared_ptr createSession (const Conference &conference, const CallSessionParams *params, bool hasMedia, CallSessionListener *listener); inline std::shared_ptr getSession () const { return session; } inline void removeSession () { session.reset(); } - inline void setAddress (const SimpleAddress &newAddr) { addr = newAddr; } + inline void setAddress (const IdentityAddress &newAddr) { addr = newAddr; } inline void setAdmin (bool isAdmin) { this->isAdmin = isAdmin; } inline void setContactAddress (const Address &contactAddr) { this->contactAddr = contactAddr; } - std::shared_ptr findDevice (const GruuAddress &gruu) const; + std::shared_ptr findDevice (const IdentityAddress &gruu) const; std::shared_ptr findDevice (const std::shared_ptr &session); const std::list> &getDevices () const; - std::shared_ptr addDevice (const GruuAddress &gruu); - void removeDevice (const GruuAddress &gruu); + std::shared_ptr addDevice (const IdentityAddress &gruu); + void removeDevice (const IdentityAddress &gruu); private: - SimpleAddress addr; + IdentityAddress addr; Address contactAddr; bool isAdmin = false; std::shared_ptr session; diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index d8be578b4..47aac4c06 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -45,7 +45,7 @@ shared_ptr ParticipantPrivate::createSession ( // ----------------------------------------------------------------------------- -shared_ptr ParticipantPrivate::findDevice (const GruuAddress &gruu) const { +shared_ptr ParticipantPrivate::findDevice (const IdentityAddress &gruu) const { for (const auto &device : devices) { if (device->getGruu() == gruu) return device; @@ -65,7 +65,7 @@ const list> &ParticipantPrivate::getDevices () con return devices; } -shared_ptr ParticipantPrivate::addDevice (const GruuAddress &gruu) { +shared_ptr ParticipantPrivate::addDevice (const IdentityAddress &gruu) { shared_ptr device = findDevice(gruu); if (device) return device; @@ -74,7 +74,7 @@ shared_ptr ParticipantPrivate::addDevice (const GruuAddress & return device; } -void ParticipantPrivate::removeDevice (const GruuAddress &gruu) { +void ParticipantPrivate::removeDevice (const IdentityAddress &gruu) { for (auto it = devices.begin(); it != devices.end(); it++) { if ((*it)->getGruu() == gruu) { devices.erase(it); @@ -88,18 +88,18 @@ void ParticipantPrivate::removeDevice (const GruuAddress &gruu) { Participant::Participant (const Address &address) : Object(*new ParticipantPrivate) { L_D(); d->contactAddr = address; - d->addr = SimpleAddress(address); + d->addr = IdentityAddress(address); } Participant::Participant (Address &&address) : Object(*new ParticipantPrivate) { L_D(); d->contactAddr = move(address); - d->addr = SimpleAddress(address); + d->addr = IdentityAddress(address); } // ----------------------------------------------------------------------------- -const SimpleAddress& Participant::getAddress () const { +const IdentityAddress& Participant::getAddress () const { L_D(); return d->addr; } diff --git a/src/conference/participant.h b/src/conference/participant.h index 41c0fab02..9b1b3b482 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -23,7 +23,7 @@ #include #include "address/address.h" -#include "address/simple-address.h" +#include "address/identity-address.h" #include "object/object.h" #include "conference/params/call-session-params.h" #include "conference/participant-device.h" @@ -53,7 +53,7 @@ public: explicit Participant (const Address &address); explicit Participant (Address &&address); - const SimpleAddress& getAddress () const; + const IdentityAddress& getAddress () const; const Address& getContactAddress () const; bool isAdmin () const; diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/remote-conference-event-handler.cpp index 9daa6363b..01bd441a7 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/remote-conference-event-handler.cpp @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "address/simple-address.h" +#include "address/identity-address.h" #include "private.h" #include "logger/logger.h" #include "remote-conference-event-handler-p.h" @@ -79,10 +79,10 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { tm = static_cast(Utils::stoll(confInfo->getConferenceDescription()->getFreeText().get())); bool isFullState = (confInfo->getState() == StateType::full); - SimpleAddress simpleConfAddress(d->confAddress); + IdentityAddress simpleConfAddress(d->confAddress); // Temporary workaround - SimpleAddress entityAddress(confInfo->getEntity().c_str()); - SimpleAddress simpleConfAddress2(simpleConfAddress); + IdentityAddress entityAddress(confInfo->getEntity().c_str()); + IdentityAddress simpleConfAddress2(simpleConfAddress); simpleConfAddress2.setDomain(entityAddress.getDomain()); if ((entityAddress == simpleConfAddress) || (entityAddress == simpleConfAddress2)) { if ( diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 186748997..11cf7009f 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -19,7 +19,7 @@ #include -#include "address/simple-address.h" +#include "address/identity-address.h" #include "chat/chat-room/basic-chat-room.h" #include "chat/chat-room/chat-room-p.h" #include "chat/chat-room/real-time-text-chat-room.h" @@ -48,9 +48,9 @@ static inline ChatRoomId resolveWorkaroundClientGroupChatRoomId ( if (!uri) return ChatRoomId(); - SimpleAddress peerAddress = chatRoomId.getPeerAddress(); + IdentityAddress peerAddress = chatRoomId.getPeerAddress(); peerAddress.setDomain(Address(uri).getDomain()); - SimpleAddress localAddress = chatRoomId.getLocalAddress(); + IdentityAddress localAddress = chatRoomId.getLocalAddress(); localAddress.setDomain(Address(uri).getDomain()); return ChatRoomId(peerAddress, localAddress); } @@ -66,20 +66,20 @@ static inline ChatRoomId resolveWorkaroundClientGroupChatRoomId ( } // Return the better local address to talk with peer address. -static SimpleAddress getDefaultLocalAddress (const shared_ptr &core, const SimpleAddress &peerAddress) { +static IdentityAddress getDefaultLocalAddress (const shared_ptr &core, const IdentityAddress &peerAddress) { LinphoneCore *cCore = core->getCCore(); LinphoneAddress *cPeerAddress = linphone_address_new(peerAddress.asString().c_str()); LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(cCore, cPeerAddress); linphone_address_unref(cPeerAddress); - SimpleAddress localAddress; + IdentityAddress localAddress; if (proxy) { char *identity = linphone_address_as_string(linphone_proxy_config_get_identity_address(proxy)); - localAddress = SimpleAddress(identity); + localAddress = IdentityAddress(identity); bctbx_free(identity); } else - localAddress = SimpleAddress(linphone_core_get_primary_contact(cCore)); + localAddress = IdentityAddress(linphone_core_get_primary_contact(cCore)); return localAddress; } @@ -169,7 +169,7 @@ shared_ptr Core::findChatRoom (const ChatRoomId &chatRoomId) const { return it == d->chatRoomsById.cend() ? shared_ptr() : it->second; } -list> Core::findChatRooms (const SimpleAddress &peerAddress) const { +list> Core::findChatRooms (const IdentityAddress &peerAddress) const { // TODO: DEV GROUP CHAT. return list>(); } @@ -199,7 +199,7 @@ shared_ptr Core::getOrCreateBasicChatRoom (const ChatRoomId &chatRoomI return chatRoom; } -shared_ptr Core::getOrCreateBasicChatRoom (const SimpleAddress &peerAddress, bool isRtt) { +shared_ptr Core::getOrCreateBasicChatRoom (const IdentityAddress &peerAddress, bool isRtt) { L_D(); list> chatRooms = findChatRooms(peerAddress); diff --git a/src/core/core.h b/src/core/core.h index 8ef97983d..635dca487 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -34,7 +34,7 @@ class Address; class ChatRoom; class ChatRoomId; class CorePrivate; -class SimpleAddress; +class IdentityAddress; class LINPHONE_PUBLIC Core : public Object { friend class ChatRoom; @@ -71,13 +71,13 @@ public: const std::list> &getChatRooms () const; std::shared_ptr findChatRoom (const ChatRoomId &chatRoomId) const; - std::list> findChatRooms (const SimpleAddress &peerAddress) const; + std::list> findChatRooms (const IdentityAddress &peerAddress) const; std::shared_ptr createClientGroupChatRoom (const std::string &subject); - std::shared_ptr createClientGroupChatRoom (const std::string &subject, const SimpleAddress &localAddress); + std::shared_ptr createClientGroupChatRoom (const std::string &subject, const IdentityAddress &localAddress); std::shared_ptr getOrCreateBasicChatRoom (const ChatRoomId &chatRoomId, bool isRtt = false); - std::shared_ptr getOrCreateBasicChatRoom (const SimpleAddress &peerAddress, bool isRtt = false); + std::shared_ptr getOrCreateBasicChatRoom (const IdentityAddress &peerAddress, bool isRtt = false); std::shared_ptr getOrCreateBasicChatRoomFromUri (const std::string &uri, bool isRtt = false); diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index cefca8260..5619f5336 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -394,7 +394,7 @@ static void cpim_chat_message_modifier_base(bool_t use_multipart) { LpConfig *config = linphone_core_get_config(marie->lc); lp_config_set_int(config, "sip", "use_cpim", 1); - SimpleAddress paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); + IdentityAddress paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); shared_ptr marieRoom = marie->lc->cppCore->getOrCreateBasicChatRoom(paulineAddress); shared_ptr marieMessage = marieRoom->createMessage("Hello CPIM"); diff --git a/tester/multipart-tester.cpp b/tester/multipart-tester.cpp index 4a104201f..dea0166f1 100644 --- a/tester/multipart-tester.cpp +++ b/tester/multipart-tester.cpp @@ -39,7 +39,7 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer, bool LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc"); - SimpleAddress paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); + IdentityAddress paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); shared_ptr marieRoom = pauline->lc->cppCore->getOrCreateBasicChatRoom(paulineAddress); shared_ptr marieMessage = marieRoom->createMessage(); From a97c04842065478137bb60cbdc95fc57578571b4 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 16 Nov 2017 17:06:12 +0100 Subject: [PATCH 0788/2215] feat(EventLog): refactoring, use IdentityAddress and rename time arg --- include/linphone/api/c-event-log.h | 12 ++-- src/c-wrapper/api/c-event-log.cpp | 70 +++++++++++++------ src/c-wrapper/internal/c-tools.h | 2 +- src/chat/chat-room/client-group-chat-room.cpp | 4 +- .../conference/conference-call-event.cpp | 6 +- .../conference/conference-call-event.h | 2 +- .../conference-chat-message-event.cpp | 6 +- .../conference-chat-message-event.h | 2 +- src/event-log/conference/conference-event-p.h | 4 +- src/event-log/conference/conference-event.cpp | 15 ++-- src/event-log/conference/conference-event.h | 8 +-- .../conference/conference-notified-event.cpp | 12 ++-- .../conference/conference-notified-event.h | 8 +-- .../conference-participant-device-event.cpp | 20 +++--- .../conference-participant-device-event.h | 10 +-- .../conference-participant-event-p.h | 2 +- .../conference-participant-event.cpp | 18 ++--- .../conference/conference-participant-event.h | 14 ++-- .../conference/conference-subject-event.cpp | 8 ++- .../conference/conference-subject-event.h | 4 +- src/event-log/event-log-p.h | 2 +- src/event-log/event-log.cpp | 9 ++- src/event-log/event-log.h | 4 +- 23 files changed, 140 insertions(+), 102 deletions(-) diff --git a/include/linphone/api/c-event-log.h b/include/linphone/api/c-event-log.h index c3f9e67c6..6edb53ffc 100644 --- a/include/linphone/api/c-event-log.h +++ b/include/linphone/api/c-event-log.h @@ -55,11 +55,11 @@ LINPHONE_PUBLIC void linphone_event_log_unref (LinphoneEventLog *event_log); LINPHONE_PUBLIC LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *event_log); /** - * Returns the time of a event log. + * Returns the creation time of a event log. * @param[in] event_log A #LinphoneEventLog object - * @return The event time + * @return The event creation time */ -LINPHONE_PUBLIC time_t linphone_event_log_get_time (const LinphoneEventLog *event_log); +LINPHONE_PUBLIC time_t linphone_event_log_get_creation_time (const LinphoneEventLog *event_log); // ----------------------------------------------------------------------------- // ConferenceEvent. @@ -121,11 +121,11 @@ LINPHONE_PUBLIC const LinphoneAddress *linphone_event_log_get_participant_addres // ----------------------------------------------------------------------------- /** - * Returns the gruu address of a conference participant device event. + * Returns the device address of a conference participant device event. * @param[in] event_log A #LinphoneEventLog object. - * @return The conference gruu address. + * @return The conference device address. */ -LINPHONE_PUBLIC const LinphoneAddress *linphone_event_log_get_gruu_address (const LinphoneEventLog *event_log); +LINPHONE_PUBLIC const LinphoneAddress *linphone_event_log_get_device_address (const LinphoneEventLog *event_log); // ----------------------------------------------------------------------------- // ConferenceSubjectEvent. diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 132982327..2b93bc2d0 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -26,10 +26,31 @@ // ============================================================================= -L_DECLARE_C_OBJECT_IMPL(EventLog); - using namespace std; +static void _linphone_event_log_constructor (LinphoneEventLog *event_log); +static void _linphone_event_log_destructor (LinphoneEventLog *event_log); + +L_DECLARE_C_OBJECT_IMPL_WITH_XTORS( + EventLog, + _linphone_event_log_constructor, + _linphone_event_log_destructor, + mutable LinphoneAddress *conferenceAddressCache; + mutable LinphoneAddress *participantAddressCache; + mutable LinphoneAddress *deviceAddressCache; +); + +void _linphone_event_log_constructor (LinphoneEventLog *) {} + +void _linphone_event_log_destructor (LinphoneEventLog *event_log) { + if (event_log->conferenceAddressCache) + linphone_address_unref(event_log->conferenceAddressCache); + if (event_log->participantAddressCache) + linphone_address_unref(event_log->participantAddressCache); + if (event_log->deviceAddressCache) + linphone_address_unref(event_log->deviceAddressCache); +} + // ----------------------------------------------------------------------------- // Helpers. // ----------------------------------------------------------------------------- @@ -161,8 +182,8 @@ LinphoneEventLogType linphone_event_log_get_type (const LinphoneEventLog *event_ ); } -time_t linphone_event_log_get_time (const LinphoneEventLog *event_log) { - return L_GET_CPP_PTR_FROM_C_OBJECT(event_log)->getTime(); +time_t linphone_event_log_get_creation_time (const LinphoneEventLog *event_log) { + return L_GET_CPP_PTR_FROM_C_OBJECT(event_log)->getCreationTime(); } // ----------------------------------------------------------------------------- @@ -173,11 +194,14 @@ const LinphoneAddress *linphone_event_log_get_conference_address (const Linphone if (!isConferenceType(linphone_event_log_get_type(event_log))) return nullptr; - return L_GET_C_BACK_PTR( - &static_pointer_cast( - L_GET_CPP_PTR_FROM_C_OBJECT(event_log) - )->getConferenceAddress() - ); + if (!event_log->conferenceAddressCache) + event_log->conferenceAddressCache = linphone_address_new( + static_pointer_cast( + L_GET_CPP_PTR_FROM_C_OBJECT(event_log) + )->getConferenceAddress().asString().c_str() + ); + + return event_log->conferenceAddressCache; } // ----------------------------------------------------------------------------- @@ -231,26 +255,32 @@ const LinphoneAddress *linphone_event_log_get_participant_address (const Linphon if (!isConferenceParticipantType(linphone_event_log_get_type(event_log))) return nullptr; - return L_GET_C_BACK_PTR( - &static_pointer_cast( - L_GET_CPP_PTR_FROM_C_OBJECT(event_log) - )->getParticipantAddress() - ); + if (!event_log->participantAddressCache) + event_log->participantAddressCache = linphone_address_new( + static_pointer_cast( + L_GET_CPP_PTR_FROM_C_OBJECT(event_log) + )->getParticipantAddress().asString().c_str() + ); + + return event_log->participantAddressCache; } // ----------------------------------------------------------------------------- // ConferenceParticipantDeviceEvent. // ----------------------------------------------------------------------------- -const LinphoneAddress *linphone_event_log_get_gruu_address (const LinphoneEventLog *event_log) { +const LinphoneAddress *linphone_event_log_get_device_address (const LinphoneEventLog *event_log) { if (!isConferenceParticipantDeviceType(linphone_event_log_get_type(event_log))) return nullptr; - return L_GET_C_BACK_PTR( - &static_pointer_cast( - L_GET_CPP_PTR_FROM_C_OBJECT(event_log) - )->getGruuAddress() - ); + if (!event_log->deviceAddressCache) + event_log->deviceAddressCache = linphone_address_new( + static_pointer_cast( + L_GET_CPP_PTR_FROM_C_OBJECT(event_log) + )->getDeviceAddress().asString().c_str() + ); + + return event_log->deviceAddressCache; } // ----------------------------------------------------------------------------- diff --git a/src/c-wrapper/internal/c-tools.h b/src/c-wrapper/internal/c-tools.h index 75ec2445e..4635cc280 100644 --- a/src/c-wrapper/internal/c-tools.h +++ b/src/c-wrapper/internal/c-tools.h @@ -613,7 +613,7 @@ LINPHONE_END_NAMESPACE CONSTRUCTOR(object); \ return object; \ } \ - static void _linphone_ ## C_TYPE ## _uninit(Linphone ## C_TYPE * object) { \ + static void _linphone_ ## C_TYPE ## _uninit(Linphone ## C_TYPE *object) { \ DESTRUCTOR(object); \ LinphonePrivate::Wrapper::uninitBaseCppObject(object); \ } \ diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 50fd91d5a..24fe71db5 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -385,7 +385,7 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (const shared_ptrgetPrivate()->addDevice(event->getGruuAddress()); + participant->getPrivate()->addDevice(event->getDeviceAddress()); if (isFullState) return; @@ -412,7 +412,7 @@ void ClientGroupChatRoom::onParticipantDeviceRemoved (const shared_ptrgetPrivate()->removeDevice(event->getGruuAddress()); + participant->getPrivate()->removeDevice(event->getDeviceAddress()); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantDeviceRemovedCb cb = linphone_chat_room_cbs_get_participant_device_removed(cbs); diff --git a/src/event-log/conference/conference-call-event.cpp b/src/event-log/conference/conference-call-event.cpp index 4aea7b025..6263c5f29 100644 --- a/src/event-log/conference/conference-call-event.cpp +++ b/src/event-log/conference/conference-call-event.cpp @@ -26,6 +26,8 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +// ----------------------------------------------------------------------------- + class ConferenceCallEventPrivate : public EventLogPrivate { public: shared_ptr call; @@ -33,8 +35,8 @@ public: // ----------------------------------------------------------------------------- -ConferenceCallEvent::ConferenceCallEvent (Type type, time_t time, const shared_ptr &call) : - EventLog(*new ConferenceCallEventPrivate, type, time) { +ConferenceCallEvent::ConferenceCallEvent (Type type, time_t creationTime, const shared_ptr &call) : + EventLog(*new ConferenceCallEventPrivate, type, creationTime) { L_D(); L_ASSERT(call); L_ASSERT(type == Type::ConferenceCallStart || type == Type::ConferenceCallEnd); diff --git a/src/event-log/conference/conference-call-event.h b/src/event-log/conference/conference-call-event.h index 53a4667ff..6125e7456 100644 --- a/src/event-log/conference/conference-call-event.h +++ b/src/event-log/conference/conference-call-event.h @@ -33,7 +33,7 @@ class ConferenceCallEventPrivate; class LINPHONE_PUBLIC ConferenceCallEvent : public EventLog { public: - ConferenceCallEvent (Type type, time_t time, const std::shared_ptr &call); + ConferenceCallEvent (Type type, time_t creationTime, const std::shared_ptr &call); std::shared_ptr getCall () const; diff --git a/src/event-log/conference/conference-chat-message-event.cpp b/src/event-log/conference/conference-chat-message-event.cpp index cfc7981ef..a33819fc2 100644 --- a/src/event-log/conference/conference-chat-message-event.cpp +++ b/src/event-log/conference/conference-chat-message-event.cpp @@ -27,6 +27,8 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +// ----------------------------------------------------------------------------- + class ConferenceChatMessageEventPrivate : public ConferenceEventPrivate { public: shared_ptr chatMessage; @@ -35,12 +37,12 @@ public: // ----------------------------------------------------------------------------- ConferenceChatMessageEvent::ConferenceChatMessageEvent ( - time_t time, + time_t creationTime, const shared_ptr &chatMessage ) : ConferenceEvent( *new ConferenceChatMessageEventPrivate, EventLog::Type::ConferenceChatMessage, - time, + creationTime, chatMessage->getRemoteAddress() ) { L_D(); diff --git a/src/event-log/conference/conference-chat-message-event.h b/src/event-log/conference/conference-chat-message-event.h index 64a210e90..40b5a8990 100644 --- a/src/event-log/conference/conference-chat-message-event.h +++ b/src/event-log/conference/conference-chat-message-event.h @@ -33,7 +33,7 @@ class ConferenceChatMessageEventPrivate; class LINPHONE_PUBLIC ConferenceChatMessageEvent : public ConferenceEvent { public: - ConferenceChatMessageEvent (time_t time, const std::shared_ptr &chatMessage); + ConferenceChatMessageEvent (time_t creationTime, const std::shared_ptr &chatMessage); std::shared_ptr getChatMessage () const; diff --git a/src/event-log/conference/conference-event-p.h b/src/event-log/conference/conference-event-p.h index 85e7ae92e..ac633fb7c 100644 --- a/src/event-log/conference/conference-event-p.h +++ b/src/event-log/conference/conference-event-p.h @@ -20,7 +20,7 @@ #ifndef _CONFERENCE_EVENT_P_H_ #define _CONFERENCE_EVENT_P_H_ -#include "address/address.h" +#include "address/identity-address.h" #include "conference-event.h" #include "event-log/event-log-p.h" @@ -30,7 +30,7 @@ LINPHONE_BEGIN_NAMESPACE class ConferenceEventPrivate : public EventLogPrivate { private: - Address conferenceAddress; + IdentityAddress conferenceAddress; L_DECLARE_PUBLIC(ConferenceEvent); }; diff --git a/src/event-log/conference/conference-event.cpp b/src/event-log/conference/conference-event.cpp index daeac96a7..38d39206b 100644 --- a/src/event-log/conference/conference-event.cpp +++ b/src/event-log/conference/conference-event.cpp @@ -17,7 +17,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "address/address.h" #include "conference-event-p.h" // ============================================================================= @@ -26,8 +25,10 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ConferenceEvent::ConferenceEvent (Type type, time_t time, const Address &conferenceAddress) : - EventLog(*new ConferenceEventPrivate, type, time) { +// ----------------------------------------------------------------------------- + +ConferenceEvent::ConferenceEvent (Type type, time_t creationTime, const IdentityAddress &conferenceAddress) : + EventLog(*new ConferenceEventPrivate, type, creationTime) { L_D(); L_ASSERT(type == Type::ConferenceCreated || type == Type::ConferenceDestroyed); d->conferenceAddress = conferenceAddress; @@ -36,14 +37,14 @@ ConferenceEvent::ConferenceEvent (Type type, time_t time, const Address &confere ConferenceEvent::ConferenceEvent ( ConferenceEventPrivate &p, Type type, - time_t time, - const Address &conferenceAddress -) : EventLog(p, type, time) { + time_t creationTime, + const IdentityAddress &conferenceAddress +) : EventLog(p, type, creationTime) { L_D(); d->conferenceAddress = conferenceAddress; } -const Address &ConferenceEvent::getConferenceAddress () const { +const IdentityAddress &ConferenceEvent::getConferenceAddress () const { L_D(); return d->conferenceAddress; } diff --git a/src/event-log/conference/conference-event.h b/src/event-log/conference/conference-event.h index 93a64a160..25cdf9a10 100644 --- a/src/event-log/conference/conference-event.h +++ b/src/event-log/conference/conference-event.h @@ -26,17 +26,17 @@ LINPHONE_BEGIN_NAMESPACE -class Address; class ConferenceEventPrivate; +class IdentityAddress; class LINPHONE_PUBLIC ConferenceEvent : public EventLog { public: - ConferenceEvent (Type type, time_t time, const Address &conferenceAddress); + ConferenceEvent (Type type, time_t creationTime, const IdentityAddress &conferenceAddress); - const Address &getConferenceAddress () const; + const IdentityAddress &getConferenceAddress () const; protected: - ConferenceEvent (ConferenceEventPrivate &p, Type type, time_t time, const Address &conferenceAddress); + ConferenceEvent (ConferenceEventPrivate &p, Type type, time_t creationTime, const IdentityAddress &conferenceAddress); private: L_DECLARE_PRIVATE(ConferenceEvent); diff --git a/src/event-log/conference/conference-notified-event.cpp b/src/event-log/conference/conference-notified-event.cpp index 5a0e4f857..4f36e6d7d 100644 --- a/src/event-log/conference/conference-notified-event.cpp +++ b/src/event-log/conference/conference-notified-event.cpp @@ -29,10 +29,10 @@ LINPHONE_BEGIN_NAMESPACE ConferenceNotifiedEvent::ConferenceNotifiedEvent ( Type type, - time_t time, - const Address &conferenceAddress, + time_t creationTime, + const IdentityAddress &conferenceAddress, unsigned int notifyId -) : ConferenceEvent(*new ConferenceNotifiedEventPrivate, type, time, conferenceAddress) { +) : ConferenceEvent(*new ConferenceNotifiedEventPrivate, type, creationTime, conferenceAddress) { L_D(); d->notifyId = notifyId; } @@ -40,10 +40,10 @@ ConferenceNotifiedEvent::ConferenceNotifiedEvent ( ConferenceNotifiedEvent::ConferenceNotifiedEvent ( ConferenceNotifiedEventPrivate &p, Type type, - time_t time, - const Address &conferenceAddress, + time_t creationTime, + const IdentityAddress &conferenceAddress, unsigned int notifyId -) : ConferenceEvent(p, type, time, conferenceAddress) { +) : ConferenceEvent(p, type, creationTime, conferenceAddress) { L_D(); d->notifyId = notifyId; } diff --git a/src/event-log/conference/conference-notified-event.h b/src/event-log/conference/conference-notified-event.h index 0c16de48f..f93dd0402 100644 --- a/src/event-log/conference/conference-notified-event.h +++ b/src/event-log/conference/conference-notified-event.h @@ -31,8 +31,8 @@ class ConferenceNotifiedEventPrivate; class LINPHONE_PUBLIC ConferenceNotifiedEvent : public ConferenceEvent { public: ConferenceNotifiedEvent ( - Type type, time_t time, - const Address &conferenceAddress, + Type type, time_t creationTime, + const IdentityAddress &conferenceAddress, unsigned int notifiyId ); @@ -42,8 +42,8 @@ protected: ConferenceNotifiedEvent ( ConferenceNotifiedEventPrivate &p, Type type, - time_t time, - const Address &conferenceAddress, + time_t creationTime, + const IdentityAddress &conferenceAddress, unsigned int notifyId ); diff --git a/src/event-log/conference/conference-participant-device-event.cpp b/src/event-log/conference/conference-participant-device-event.cpp index fbfbcceda..9f44bd540 100644 --- a/src/event-log/conference/conference-participant-device-event.cpp +++ b/src/event-log/conference/conference-participant-device-event.cpp @@ -26,24 +26,26 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +// ----------------------------------------------------------------------------- + class ConferenceParticipantDeviceEventPrivate : public ConferenceParticipantEventPrivate { public: - Address gruuAddress; + IdentityAddress deviceAddress; }; // ----------------------------------------------------------------------------- ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent ( Type type, - time_t time, - const Address &conferenceAddress, + time_t creationTime, + const IdentityAddress &conferenceAddress, unsigned int notifyId, - const Address &participantAddress, - const Address &gruuAddress + const IdentityAddress &participantAddress, + const IdentityAddress &deviceAddress ) : ConferenceParticipantEvent( *new ConferenceParticipantDeviceEventPrivate, type, - time, + creationTime, conferenceAddress, notifyId, participantAddress @@ -53,12 +55,12 @@ ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent ( type == Type::ConferenceParticipantDeviceAdded || type == Type::ConferenceParticipantDeviceRemoved ); - d->gruuAddress = gruuAddress; + d->deviceAddress = deviceAddress; } -const Address &ConferenceParticipantDeviceEvent::getGruuAddress () const { +const IdentityAddress &ConferenceParticipantDeviceEvent::getDeviceAddress () const { L_D(); - return d->gruuAddress; + return d->deviceAddress; } LINPHONE_END_NAMESPACE diff --git a/src/event-log/conference/conference-participant-device-event.h b/src/event-log/conference/conference-participant-device-event.h index a4e1aca79..62f9a3ed9 100644 --- a/src/event-log/conference/conference-participant-device-event.h +++ b/src/event-log/conference/conference-participant-device-event.h @@ -32,14 +32,14 @@ class LINPHONE_PUBLIC ConferenceParticipantDeviceEvent : public ConferencePartic public: ConferenceParticipantDeviceEvent ( Type type, - time_t time, - const Address &conferenceAddress, + time_t creationTime, + const IdentityAddress &conferenceAddress, unsigned int notifyId, - const Address &participantAddress, - const Address &gruuAddress + const IdentityAddress &participantAddress, + const IdentityAddress &deviceAddress ); - const Address &getGruuAddress () const; + const IdentityAddress &getDeviceAddress () const; private: L_DECLARE_PRIVATE(ConferenceParticipantDeviceEvent); diff --git a/src/event-log/conference/conference-participant-event-p.h b/src/event-log/conference/conference-participant-event-p.h index 77210c562..984763418 100644 --- a/src/event-log/conference/conference-participant-event-p.h +++ b/src/event-log/conference/conference-participant-event-p.h @@ -29,7 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class ConferenceParticipantEventPrivate : public ConferenceNotifiedEventPrivate { private: - Address participantAddress; + IdentityAddress participantAddress; L_DECLARE_PUBLIC(ConferenceParticipantEvent); }; diff --git a/src/event-log/conference/conference-participant-event.cpp b/src/event-log/conference/conference-participant-event.cpp index 29cc92949..0c9c3c4aa 100644 --- a/src/event-log/conference/conference-participant-event.cpp +++ b/src/event-log/conference/conference-participant-event.cpp @@ -29,14 +29,14 @@ LINPHONE_BEGIN_NAMESPACE ConferenceParticipantEvent::ConferenceParticipantEvent ( Type type, - time_t time, - const Address &conferenceAddress, + time_t creationTime, + const IdentityAddress &conferenceAddress, unsigned int notifyId, - const Address &participantAddress + const IdentityAddress &participantAddress ) : ConferenceNotifiedEvent( *new ConferenceParticipantEventPrivate, type, - time, + creationTime, conferenceAddress, notifyId ) { @@ -53,14 +53,14 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( ConferenceParticipantEvent::ConferenceParticipantEvent ( ConferenceParticipantEventPrivate &p, Type type, - time_t time, - const Address &conferenceAddress, + time_t creationTime, + const IdentityAddress &conferenceAddress, unsigned int notifyId, - const Address &participantAddress + const IdentityAddress &participantAddress ) : ConferenceNotifiedEvent( p, type, - time, + creationTime, conferenceAddress, notifyId ) { @@ -68,7 +68,7 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( d->participantAddress = participantAddress; } -const Address &ConferenceParticipantEvent::getParticipantAddress () const { +const IdentityAddress &ConferenceParticipantEvent::getParticipantAddress () const { L_D(); return d->participantAddress; } diff --git a/src/event-log/conference/conference-participant-event.h b/src/event-log/conference/conference-participant-event.h index d699adc9b..76731dcbc 100644 --- a/src/event-log/conference/conference-participant-event.h +++ b/src/event-log/conference/conference-participant-event.h @@ -32,22 +32,22 @@ class LINPHONE_PUBLIC ConferenceParticipantEvent : public ConferenceNotifiedEven public: ConferenceParticipantEvent ( Type type, - time_t time, - const Address &conferenceAddress, + time_t creationTime, + const IdentityAddress &conferenceAddress, unsigned int notifyId, - const Address &participantAddress + const IdentityAddress &participantAddress ); - const Address &getParticipantAddress () const; + const IdentityAddress &getParticipantAddress () const; protected: ConferenceParticipantEvent ( ConferenceParticipantEventPrivate &p, Type type, - time_t time, - const Address &conferenceAddress, + time_t creationTime, + const IdentityAddress &conferenceAddress, unsigned int notifyId, - const Address &participantAddress + const IdentityAddress &participantAddress ); private: diff --git a/src/event-log/conference/conference-subject-event.cpp b/src/event-log/conference/conference-subject-event.cpp index e07061dc2..7d084e82d 100644 --- a/src/event-log/conference/conference-subject-event.cpp +++ b/src/event-log/conference/conference-subject-event.cpp @@ -26,6 +26,8 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +// ----------------------------------------------------------------------------- + class ConferenceSubjectEventPrivate : public ConferenceNotifiedEventPrivate { public: string subject; @@ -34,14 +36,14 @@ public: // ----------------------------------------------------------------------------- ConferenceSubjectEvent::ConferenceSubjectEvent ( - time_t time, - const Address &conferenceAddress, + time_t creationTime, + const IdentityAddress &conferenceAddress, unsigned int notifyId, const string &subject ) : ConferenceNotifiedEvent( *new ConferenceSubjectEventPrivate, Type::ConferenceSubjectChanged, - time, + creationTime, conferenceAddress, notifyId ) { diff --git a/src/event-log/conference/conference-subject-event.h b/src/event-log/conference/conference-subject-event.h index 02e1bcf67..7eba0cab2 100644 --- a/src/event-log/conference/conference-subject-event.h +++ b/src/event-log/conference/conference-subject-event.h @@ -33,8 +33,8 @@ class ConferenceSubjectEventPrivate; class LINPHONE_PUBLIC ConferenceSubjectEvent : public ConferenceNotifiedEvent { public: ConferenceSubjectEvent ( - time_t time, - const Address &conferenceAddress, + time_t creationTime, + const IdentityAddress &conferenceAddress, unsigned int notifyId, const std::string &subject ); diff --git a/src/event-log/event-log-p.h b/src/event-log/event-log-p.h index a5a566594..c33870d13 100644 --- a/src/event-log/event-log-p.h +++ b/src/event-log/event-log-p.h @@ -35,7 +35,7 @@ public: private: EventLog::Type type = EventLog::Type::None; - time_t time = -1; + time_t creationTime = -1; L_DECLARE_PUBLIC(EventLog); }; diff --git a/src/event-log/event-log.cpp b/src/event-log/event-log.cpp index e6a821f1c..86e92a668 100644 --- a/src/event-log/event-log.cpp +++ b/src/event-log/event-log.cpp @@ -17,7 +17,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "core/core-p.h" #include "event-log-p.h" // ============================================================================= @@ -26,10 +25,10 @@ LINPHONE_BEGIN_NAMESPACE EventLog::EventLog () : BaseObject(*new EventLogPrivate) {} -EventLog::EventLog (EventLogPrivate &p, Type type, time_t time) : BaseObject(p) { +EventLog::EventLog (EventLogPrivate &p, Type type, time_t creationTime) : BaseObject(p) { L_D(); d->type = type; - d->time = time; + d->creationTime = creationTime; } EventLog::Type EventLog::getType () const { @@ -37,9 +36,9 @@ EventLog::Type EventLog::getType () const { return d->type; } -time_t EventLog::getTime () const { +time_t EventLog::getCreationTime () const { L_D(); - return d->time; + return d->creationTime; } LINPHONE_END_NAMESPACE diff --git a/src/event-log/event-log.h b/src/event-log/event-log.h index 265a63ce7..b12a4cfc4 100644 --- a/src/event-log/event-log.h +++ b/src/event-log/event-log.h @@ -43,10 +43,10 @@ public: EventLog (); Type getType () const; - time_t getTime () const; + time_t getCreationTime () const; protected: - EventLog (EventLogPrivate &p, Type type, time_t time); + EventLog (EventLogPrivate &p, Type type, time_t creationTime); private: L_DECLARE_PRIVATE(EventLog); From 5cf9e549f30f8f195388013ddce3ed04104b1eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Thu, 16 Nov 2017 17:21:04 +0100 Subject: [PATCH 0789/2215] Partial merge from 'master' about wrapper and documentation generation scripts --- CMakeLists.txt | 2 +- coreapi/help/doc/CMakeLists.txt | 33 +- coreapi/help/doc/doxygen/CMakeLists.txt | 36 +- coreapi/help/doc/doxygen/doxygen.dox | 5 + coreapi/help/doc/sphinx/CMakeLists.txt | 61 ++ coreapi/help/doc/sphinx/class_page.mustache | 151 +++++ coreapi/help/doc/sphinx/conf.py.in | 158 +++++ coreapi/help/doc/sphinx/enums_page.mustache | 30 + coreapi/help/doc/sphinx/gendoc.py | 377 +++++++++++ coreapi/help/doc/sphinx/index_page.mustache | 19 + coreapi/help/doc/sphinx/source/index.rst | 24 + include/linphone/types.h | 4 + tools/abstractapi.py | 675 ++++++++++++++------ tools/genapixml.py | 17 +- tools/metadoc.py | 589 +++++++++++++++-- tools/metaname.py | 340 ++++++++++ wrappers/cpp/CMakeLists.txt | 1 + wrappers/cpp/class_header.mustache | 44 +- wrappers/cpp/class_impl.mustache | 1 + wrappers/cpp/enums_header.mustache | 4 +- wrappers/cpp/genwrapper.py | 339 ++-------- wrappers/csharp/genwrapper.py | 204 ++---- wrappers/csharp/wrapper_impl.mustache | 4 +- wrappers/java/genwrapper.py | 30 +- 24 files changed, 2379 insertions(+), 769 deletions(-) create mode 100644 coreapi/help/doc/sphinx/CMakeLists.txt create mode 100644 coreapi/help/doc/sphinx/class_page.mustache create mode 100644 coreapi/help/doc/sphinx/conf.py.in create mode 100644 coreapi/help/doc/sphinx/enums_page.mustache create mode 100755 coreapi/help/doc/sphinx/gendoc.py create mode 100644 coreapi/help/doc/sphinx/index_page.mustache create mode 100644 coreapi/help/doc/sphinx/source/index.rst create mode 100644 tools/metaname.py diff --git a/CMakeLists.txt b/CMakeLists.txt index c7d648143..8c964a8f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,7 +171,7 @@ if(ENABLE_LIME) endif() set(HAVE_LIME 1) endif() -if(ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRAPPER) +if(ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRAPPER OR ENABLE_SPHINX_DOC) find_package(PythonInterp REQUIRED) endif() diff --git a/coreapi/help/doc/CMakeLists.txt b/coreapi/help/doc/CMakeLists.txt index c4d5481de..d90be026e 100644 --- a/coreapi/help/doc/CMakeLists.txt +++ b/coreapi/help/doc/CMakeLists.txt @@ -21,22 +21,23 @@ ############################################################################ add_subdirectory(doxygen) +add_subdirectory(sphinx) if(ENABLE_JAVADOC) - find_package(Java REQUIRED) - set(JAVADOC_PACKAGES "org.linphone.core org.linphone.mediastream") - set(JAVADOC_CLASSPATHS - "${PROJECT_SOURCE_DIR}/java/common" - "${PROJECT_SOURCE_DIR}/java/j2se" - "${PROJECT_SOURCE_DIR}/mediastreamer2/java/src" - ) - string(REPLACE ";" ":" JAVADOC_CLASSPATHS "${JAVADOC_CLASSPATHS}") - set(JAVADOC_TITLE "Linphone SDK ${PROJECT_VERSION} reference documentation") - set(JAVADOC_JAVA_REFERENCE "http://docs.oracle.com/javase/8/docs/api/") - set(JAVADOC_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/doc/java") - set(JAVADOC_LOGFILE "${CMAKE_CURRENT_BINARY_DIR}/javadoc.log") - configure_file("generate_javadoc.sh.in" "generate_javadoc.sh" @ONLY) - add_custom_target(javadoc ALL - COMMAND "${CMAKE_CURRENT_BINARY_DIR}/generate_javadoc.sh" - ) + find_package(Java REQUIRED) + set(JAVADOC_PACKAGES "org.linphone.core org.linphone.mediastream") + set(JAVADOC_CLASSPATHS + "${PROJECT_SOURCE_DIR}/java/common" + "${PROJECT_SOURCE_DIR}/java/j2se" + "${PROJECT_SOURCE_DIR}/mediastreamer2/java/src" + ) + string(REPLACE ";" ":" JAVADOC_CLASSPATHS "${JAVADOC_CLASSPATHS}") + set(JAVADOC_TITLE "Linphone SDK ${PROJECT_VERSION} reference documentation") + set(JAVADOC_JAVA_REFERENCE "http://docs.oracle.com/javase/8/docs/api/") + set(JAVADOC_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/doc/java") + set(JAVADOC_LOGFILE "${CMAKE_CURRENT_BINARY_DIR}/javadoc.log") + configure_file("generate_javadoc.sh.in" "generate_javadoc.sh" @ONLY) + add_custom_target(javadoc ALL + COMMAND "${CMAKE_CURRENT_BINARY_DIR}/generate_javadoc.sh" + ) endif() diff --git a/coreapi/help/doc/doxygen/CMakeLists.txt b/coreapi/help/doc/doxygen/CMakeLists.txt index 8d066161b..ef96a784f 100644 --- a/coreapi/help/doc/doxygen/CMakeLists.txt +++ b/coreapi/help/doc/doxygen/CMakeLists.txt @@ -22,12 +22,9 @@ if (ENABLE_DOC OR ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRAPPER) find_package(Doxygen) - if (DOXYGEN_FOUND) - if (DOXYGEN_DOT_FOUND) - set(DOC_INPUT_FILES ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile - ${CMAKE_CURRENT_SOURCE_DIR}/doxygen.dox - ${LINPHONE_HEADER_FILES} - ) + if(DOXYGEN_FOUND) + if(DOXYGEN_DOT_FOUND) + set(top_srcdir "${PROJECT_SOURCE_DIR}") set(DOXYGEN_INPUT "") foreach (HEADER_FILE ${LINPHONE_HEADER_FILES}) string(CONCAT DOXYGEN_INPUT ${DOXYGEN_INPUT} " \"${HEADER_FILE}\"") @@ -35,21 +32,28 @@ if (ENABLE_DOC OR ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRA string(CONCAT DOXYGEN_INPUT ${DOXYGEN_INPUT} " \"${CMAKE_CURRENT_SOURCE_DIR}\"") string(CONCAT DOXYGEN_INPUT ${DOXYGEN_INPUT} " \"${PROJECT_SOURCE_DIR}/coreapi/help/examples/C\"") configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) - add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/html/index.html" "${CMAKE_CURRENT_BINARY_DIR}/xml/index.xml" + set(DOC_INPUT_FILES ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + ${CMAKE_CURRENT_SOURCE_DIR}/doxygen.dox + ${LINPHONE_HEADER_FILES} + ) + set(XML_DIR "${CMAKE_CURRENT_BINARY_DIR}/xml") + set(LINPHONE_DOXYGEN_XML_DIR ${XML_DIR} PARENT_SCOPE) + add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/html/index.html" "${XML_DIR}/index.xml" + COMMAND ${CMAKE_COMMAND} -E remove -f html/* xml/* COMMAND ${CMAKE_COMMAND} -E remove -f html/* xml/* COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile DEPENDS ${DOC_INPUT_FILES} ) - add_custom_target(linphone-doc ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/html/index.html" "${CMAKE_CURRENT_BINARY_DIR}/xml/index.xml") - install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html" "${CMAKE_CURRENT_BINARY_DIR}/xml" - DESTINATION "${CMAKE_INSTALL_DATADIR}/doc/linphone-${LINPHONE_VERSION}") - else () + add_custom_target(linphone-doc ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/html/index.html" "${XML_DIR}/index.xml") + install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html" "${XML_DIR}" + DESTINATION "${CMAKE_INSTALL_DATADIR}/doc/linphone-${LINPHONE_VERSION}") + else() if (ENABLE_CXX_WRAPPER) message(FATAL_ERROR "The dot program is needed to generate the linphone documentation. You can get it from http://www.graphviz.org/.") - else () + else() message(WARNING "The dot program is needed to generate the linphone documentation. You can get it from http://www.graphviz.org/.") - endif () - endif () - endif () -endif () + endif() + endif() + endif() +endif() diff --git a/coreapi/help/doc/doxygen/doxygen.dox b/coreapi/help/doc/doxygen/doxygen.dox index 38002841c..4158c7a70 100644 --- a/coreapi/help/doc/doxygen/doxygen.dox +++ b/coreapi/help/doc/doxygen/doxygen.dox @@ -34,6 +34,11 @@ * @brief Initializing liblinphone. **/ +/** + * @defgroup logging Logging + * @brief Logging service of Linphone. + */ + /** * @defgroup call_control Call control * @brief Placing and receiving calls. diff --git a/coreapi/help/doc/sphinx/CMakeLists.txt b/coreapi/help/doc/sphinx/CMakeLists.txt new file mode 100644 index 000000000..15abb7480 --- /dev/null +++ b/coreapi/help/doc/sphinx/CMakeLists.txt @@ -0,0 +1,61 @@ +############################################################################ +# CMakeLists.txt +# Copyright (C) 2017 Belledonne Communications, Grenoble France +# +############################################################################ +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +############################################################################ + +if (ENABLE_SPHINX_DOC) + set(GENERATED_LANGUAGES c cpp csharp) + set(DOCUMENTATION_DIRS ) + set(GENERATED_SPHINX_SOURCES ) + foreach(LANGUAGE_ ${GENERATED_LANGUAGES}) + set(DOCUMENTATION_DIR ${CMAKE_CURRENT_BINARY_DIR}/source/${LANGUAGE_}) + list(APPEND DOCUMENTATION_DIRS ${DOCUMENTATION_DIR}) + list(APPEND GENERATED_SPHINX_SOURCES ${DOCUMENTATION_DIR}/index.rst) + endforeach(LANGUAGE_) + + set(PYTHON_SCRIPTS gendoc.py + ${linphone_SOURCE_DIR}/tools/abstractapi.py + ${linphone_SOURCE_DIR}/tools/genapixml.py + ${linphone_SOURCE_DIR}/tools/metadoc.py + ${linphone_SOURCE_DIR}/tools/metaname.py + ) + set(MUSTACHE_TEMPLATES class_page.mustache + enums_page.mustache + index_page.mustache + ) + configure_file(conf.py.in source/conf.py) + configure_file(source/index.rst source/index.rst COPYONLY) + add_custom_command(OUTPUT ${GENERATED_SPHINX_SOURCES} + COMMAND ${CMAKE_COMMAND} -E remove -f ${DOCUMENTATION_DIRS} + COMMAND ${PYTHON_EXECUTABLE} '${CMAKE_CURRENT_SOURCE_DIR}/gendoc.py' '${LINPHONE_DOXYGEN_XML_DIR}' -o 'source' + DEPENDS ${PYTHON_SCRIPTS} + ${MUSTACHE_TEMPLATES} + ${LINPHONE_DOXYGEN_XML_DIR}/index.xml + linphone-doc + ) + add_custom_command(OUTPUT build/html/index.html + COMMAND ${CMAKE_COMMAND} -E remove_directory build + COMMAND ${PYTHON_EXECUTABLE} -msphinx -M html 'source' 'build' + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/source/conf.py + ${CMAKE_CURRENT_BINARY_DIR}/source/index.rst + ${GENERATED_SPHINX_SOURCES} + ) + add_custom_target(sphinx-doc ALL DEPENDS build/html/index.html) +endif() diff --git a/coreapi/help/doc/sphinx/class_page.mustache b/coreapi/help/doc/sphinx/class_page.mustache new file mode 100644 index 000000000..f835c5c3e --- /dev/null +++ b/coreapi/help/doc/sphinx/class_page.mustache @@ -0,0 +1,151 @@ +{{#make_chapter}}{{{className}}} class{{/make_chapter}} + +.. {{#write_declarator}}class{{/write_declarator}}:: {{{fullClassName}}} + + {{#briefDoc}} + {{#lines}} + {{{line}}} + {{/lines}} + {{/briefDoc}} + + {{#detailedDoc}} + {{#lines}} + {{{line}}} + {{/lines}} + {{/detailedDoc}} + + {{{selector}}} + + +Summary +======= + +{{#hasProperties}} +Properties +---------- + +{{{propertiesSummary}}} +{{/hasProperties}} + +{{#hasMethods}} +Methods +------- + +{{{instanceMethodsSummary}}} +{{/hasMethods}} + +{{#hasClassMethods}} +Class methods +------------- + +{{{classMethodsSummary}}} +{{/hasClassMethods}} + +Detailed descriptions +===================== + +{{#hasProperties}} +Properties +---------- + +{{#properties}} +{{{title}}} + +{{#hasNamespaceDeclarator}} +.. {{#write_declarator}}namespace{{/write_declarator}}:: {{{fullClassName}}} +{{/hasNamespaceDeclarator}} + +{{#getter}} +.. {{#write_declarator}}method{{/write_declarator}}:: {{{prototype}}} + + {{#briefDoc}} + {{#lines}} + {{{line}}} + {{/lines}} + {{/briefDoc}} + + {{#detailedDoc}} + {{#lines}} + {{{line}}} + {{/lines}} + {{/detailedDoc}} + + {{{selector}}} +{{/getter}} + +{{#setter}} +.. {{#write_declarator}}method{{/write_declarator}}:: {{{prototype}}} + + {{#briefDoc}} + {{#lines}} + {{{line}}} + {{/lines}} + {{/briefDoc}} + + {{#detailedDoc}} + {{#lines}} + {{{line}}} + {{/lines}} + {{/detailedDoc}} + + {{{selector}}} +{{/setter}} + +{{/properties}} +{{/hasProperties}} + +{{#hasMethods}} +Public methods +-------------- + +{{#hasNamespaceDeclarator}} +.. {{#write_declarator}}namespace{{/write_declarator}}:: {{{fullClassName}}} +{{/hasNamespaceDeclarator}} + +{{#methods}} +.. {{#write_declarator}}method{{/write_declarator}}:: {{{prototype}}} + + {{#briefDoc}} + {{#lines}} + {{{line}}} + {{/lines}} + {{/briefDoc}} + + {{#detailedDoc}} + {{#lines}} + {{{line}}} + {{/lines}} + {{/detailedDoc}} + + {{{selector}}} + +{{/methods}} + +{{/hasMethods}} +{{#hasClassMethods}} +Class methods +------------- + +{{#hasNamespaceDeclarator}} +.. {{#write_declarator}}namespace{{/write_declarator}}:: {{{fullClassName}}} +{{/hasNamespaceDeclarator}} + +{{#classMethods}} +.. {{#write_declarator}}method{{/write_declarator}}:: static {{{prototype}}} + + {{#briefDoc}} + {{#lines}} + {{{line}}} + {{/lines}} + {{/briefDoc}} + + {{#detailedDoc}} + {{#lines}} + {{{line}}} + {{/lines}} + {{/detailedDoc}} + + {{{selector}}} + +{{/classMethods}} +{{/hasClassMethods}} diff --git a/coreapi/help/doc/sphinx/conf.py.in b/coreapi/help/doc/sphinx/conf.py.in new file mode 100644 index 000000000..378b84244 --- /dev/null +++ b/coreapi/help/doc/sphinx/conf.py.in @@ -0,0 +1,158 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Linphone API documentation build configuration file, created by +# sphinx-quickstart on Mon Jun 19 11:58:21 2017. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['sphinx_csharp.csharp'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'Linphone Core API' +copyright = '2017, Belledonne Communications SARL' +author = 'Belledonne Communications SARL' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '${LINPHONE_MAJOR_VERSION}.${LINPHONE_MINOR_VERSION}' +# The full version, including alpha/beta/rc tags. +release = '${LINPHONE_VERSION}' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = [] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +#html_theme = 'alabaster' +html_theme = 'classic' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + + +# -- Options for HTMLHelp output ------------------------------------------ + +# Output file base name for HTML help builder. +htmlhelp_basename = 'LinphoneAPIdoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'LinphoneAPI.tex', 'Linphone API Documentation', + 'Belledonne Communications SARL', 'manual'), +] + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'linphoneapi', 'Linphone Core API Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'LinphoneCoreAPI', 'Linphone Core API Documentation', + author, 'LinphoneCoreAPI', 'One line description of project.', + 'Miscellaneous'), +] + + + diff --git a/coreapi/help/doc/sphinx/enums_page.mustache b/coreapi/help/doc/sphinx/enums_page.mustache new file mode 100644 index 000000000..fd013094a --- /dev/null +++ b/coreapi/help/doc/sphinx/enums_page.mustache @@ -0,0 +1,30 @@ +{{#enums}} +{{{sectionName}}} + +.. {{#write_declarator}}enum{{/write_declarator}}:: {{{fullName}}} + + {{#briefDesc}} + {{#lines}} + {{{line}}} + {{/lines}} + {{/briefDesc}} + + {{{selector}}} + + {{#hasNamespaceDeclarator}} + .. {{#write_declarator}}namespace{{/write_declarator}}:: {{{namespace}}} + {{/hasNamespaceDeclarator}} + + {{#enumerators}} + .. {{#write_declarator}}enumerator{{/write_declarator}}:: {{{name}}}{{#value}} = {{{value}}}{{/value}} + + {{#briefDesc}} + {{#lines}} + {{{line}}} + {{/lines}} + {{/briefDesc}} + + {{{selector}}} + + {{/enumerators}} +{{/enums}} diff --git a/coreapi/help/doc/sphinx/gendoc.py b/coreapi/help/doc/sphinx/gendoc.py new file mode 100755 index 000000000..800d57bc6 --- /dev/null +++ b/coreapi/help/doc/sphinx/gendoc.py @@ -0,0 +1,377 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (C) 2017 Belledonne Communications SARL +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +import sys +import os +import argparse +import pystache + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', 'tools')) +import abstractapi +import genapixml as capi +import metaname +import metadoc + + +class RstTools: + @staticmethod + def make_chapter(text): + return RstTools.make_section(text, char='*', overline=True) + + @staticmethod + def make_section(text, char='=', overline=False): + size = len(text) + underline = (char*size) + lines = [text, underline] + if overline: + lines.insert(0, underline) + return '\n'.join(lines) + + @staticmethod + def make_subsection(text): + return RstTools.make_section(text, char='-') + + @staticmethod + def make_subsubsection(text): + return RstTools.make_section(text, char='^') + + class Table: + def __init__(self): + self._rows = [] + self._widths = [] + self._heights = [] + + @property + def rows(self): + return self._rows + + def addrow(self, row): + if len(self._widths) == 0: + self._widths.append(0) + self._widths *= len(row) + elif len(row) != len(self._widths): + raise ValueError('row width mismatch table width') + + height = 0 + row2 = [] + + i = 0 + while i 0 + + @property + def hasClassMethods(self): + return len(self.classMethods) > 0 + + @property + def hasProperties(self): + return len(self.properties) > 0 + + def _translate_properties(self, properties): + translatedProperties = [] + for property_ in properties: + propertyAttr = { + 'name' : property_.name.translate(self.lang.nameTranslator), + 'ref_label' : '{0}_{1}'.format(self.lang.langCode, property_.name.to_snake_case(fullName=True)), + 'getter' : self._translate_method(property_.getter) if property_.getter is not None else None, + 'setter' : self._translate_method(property_.setter) if property_.setter is not None else None + } + propertyAttr['title'] = RstTools.make_subsubsection(propertyAttr['name']) + translatedProperties.append(propertyAttr) + return translatedProperties + + def _translate_methods(self, methods): + translatedMethods = [] + for method in methods: + translatedMethods.append(self._translate_method(method)) + return translatedMethods + + def _translate_method(self, method): + prototypeParams = {} + if self.lang.langCode == 'Cpp': + prototypeParams['showStdNs'] = True + methAttr = { + 'prototype' : method.translate_as_prototype(self.lang.langTranslator, **prototypeParams), + 'briefDoc' : method.briefDescription.translate(self.docTranslator), + 'detailedDoc' : method.detailedDescription.translate(self.docTranslator), + 'selector' : self._make_selector(method) + } + reference = metadoc.FunctionReference(None) + reference.relatedObject = method + methAttr['link'] = reference.translate(self.lang.docTranslator) + return methAttr + + @property + def propertiesSummary(self): + table = RstTools.Table() + for property_ in self.properties: + reference = ':ref:`{0}`'.format(property_['ref_label']) + briefDoc = property_['getter']['briefDoc'] if property_['getter'] is not None else property_['setter']['briefDoc'] + briefDoc = '\n'.join([line['line'] for line in briefDoc['lines']]) + table.addrow([reference, briefDoc]) + return table + + @property + def instanceMethodsSummary(self): + table = RstTools.Table() + for method in self.methods: + briefDoc = '\n'.join([line['line'] for line in method['briefDoc']['lines']]) + table.addrow([method['link'], briefDoc]) + return table + + @property + def classMethodsSummary(self): + table = RstTools.Table() + for method in self.classMethods: + briefDoc = '\n'.join([line['line'] for line in method['briefDoc']['lines']]) + table.addrow([method['link'], briefDoc]) + return table + + +class DocGenerator: + def __init__(self, api): + self.api = api + self.languages = [ + LangInfo('C'), + LangInfo('Cpp'), + LangInfo('CSharp') + ] + + def generate(self, outputdir): + for lang in self.languages: + subdirectory = lang.langCode.lower() + directory = os.path.join(args.outputdir, subdirectory) + if not os.path.exists(directory): + os.mkdir(directory) + + enumsPage = EnumsPage(lang, self.languages, absApiParser.enums) + enumsPage.write(directory) + + indexPage = IndexPage(lang, self.languages) + for _class in absApiParser.classes: + page = ClassPage(_class, lang, self.languages) + page.write(directory) + indexPage.add_class_entry(_class) + + indexPage.write(directory) + + +if __name__ == '__main__': + argparser = argparse.ArgumentParser(description='Generate a sphinx project to generate the documentation of Linphone Core API.') + argparser.add_argument('xmldir', type=str, help='directory holding the XML documentation of the C API generated by Doxygen') + argparser.add_argument('-o --output', type=str, help='directory into where Sphinx source files will be written', dest='outputdir', default='.') + args = argparser.parse_args() + + cProject = capi.Project() + cProject.initFromDir(args.xmldir) + cProject.check() + + absApiParser = abstractapi.CParser(cProject) + absApiParser.parse_all() + + docGenerator = DocGenerator(absApiParser) + docGenerator.generate(args.outputdir) + diff --git a/coreapi/help/doc/sphinx/index_page.mustache b/coreapi/help/doc/sphinx/index_page.mustache new file mode 100644 index 000000000..2fa38ec83 --- /dev/null +++ b/coreapi/help/doc/sphinx/index_page.mustache @@ -0,0 +1,19 @@ +{{#make_section}}{{{language}}} API{{/make_section}} + +Index of classes +---------------- + +.. toctree:: + :maxdepth: 1 + + {{#tocEntries}} + {{{entryName}}} + {{/tocEntries}} + +Index of enums +-------------- + +.. toctree:: + :maxdepth 1 + + enums.rst diff --git a/coreapi/help/doc/sphinx/source/index.rst b/coreapi/help/doc/sphinx/source/index.rst new file mode 100644 index 000000000..530adfcc3 --- /dev/null +++ b/coreapi/help/doc/sphinx/source/index.rst @@ -0,0 +1,24 @@ +.. Linphone API documentation master file, created by + sphinx-quickstart on Mon Jun 19 11:58:21 2017. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to Linphone API's documentation! +======================================== + +.. toctree:: + :maxdepth: 1 + :caption: Contents: + + c/index.rst + cpp/index.rst + csharp/index.rst + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/include/linphone/types.h b/include/linphone/types.h index c1c46e835..4df0f956c 100644 --- a/include/linphone/types.h +++ b/include/linphone/types.h @@ -1055,6 +1055,10 @@ typedef enum _LinphoneTransportType { */ typedef struct _LinphoneTunnel LinphoneTunnel; +/** + * @brief Tunnel settings. + * @ingroup tunnel + */ typedef struct _LinphoneTunnelConfig LinphoneTunnelConfig; /** diff --git a/tools/abstractapi.py b/tools/abstractapi.py index 6ba861a96..9f7a4d451 100644 --- a/tools/abstractapi.py +++ b/tools/abstractapi.py @@ -1,3 +1,4 @@ + # Copyright (C) 2017 Belledonne Communications SARL # # This program is free software; you can redistribute it and/or @@ -17,6 +18,7 @@ import re import genapixml as CApi +import metaname class Error(RuntimeError): @@ -27,170 +29,24 @@ class BlacklistedException(Error): pass -class Name(object): - camelCaseParsingRegex = re.compile('[A-Z][a-z0-9]*') - lowerCamelCaseSplitingRegex = re.compile('([a-z][a-z0-9]*)([A-Z][a-z0-9]*)') - - def __init__(self): - self.words = [] - self.prev = None - - def copy(self): - nameType = type(self) - name = nameType() - name.words = list(self.words) - name.prev = None if self.prev is None else self.prev.copy() - return name - - def delete_prefix(self, prefix): - it = self - _next = None - while it is not None and it.words != prefix.words: - _next = it - it = it.prev - - if it is None or it != prefix: - raise Error('no common prefix') - elif _next is not None: - _next.prev = None - - def _set_namespace(self, namespace): - self.prev = namespace - if self.prev is not None: - prefix = namespace.to_word_list() - i = 0 - while i 0: - suffix = self.words[-1] - if MethodName.regex.match(suffix) is not None: - self.overloadRef = int(suffix) - del self.words[-1] - - def to_c(self): - suffix = ('_' + str(self.overloadRef)) if self.overloadRef > 0 else '' - return self.to_snake_case(fullName=True) + suffix - - -class ArgName(Name): - def to_c(self): - return self.to_snake_case() - - -class PropertyName(ArgName): - pass - - -class NamespaceName(Name): - def __init__(self, *params): - Name.__init__(self) - if len(params) > 0: - self.words = params[0] + def translate(self, langTranslator): + return langTranslator.trueConstantToken if self else langTranslator.falseConstantToken class Object(object): @@ -199,9 +55,12 @@ class Object(object): self.parent = None self.deprecated = False - def find_first_ancestor_by_type(self, _type): + def __lt__(self, other): + return self.name < other.name + + def find_first_ancestor_by_type(self, *types): ancestor = self.parent - while ancestor is not None and type(ancestor) is not _type: + while ancestor is not None and type(ancestor) not in types: ancestor = ancestor.parent return ancestor @@ -211,7 +70,7 @@ class Type(Object): Object.__init__(self, name) self.isconst = isconst self.isref = isref - self.cname = None + self.cDecl = None class BaseType(Type): @@ -219,18 +78,27 @@ class BaseType(Type): Type.__init__(self, name, isconst=isconst, isref=isref) self.size = size self.isUnsigned = isUnsigned + + def translate(self, translator, **params): + return translator.translate_base_type(self, **params) class EnumType(Type): def __init__(self, name, isconst=False, isref=False, enumDesc=None): Type.__init__(self, name, isconst=isconst, isref=isref) self.desc = enumDesc + + def translate(self, translator, **params): + return translator.translate_enum_type(self, **params) class ClassType(Type): def __init__(self, name, isconst=False, isref=False, classDesc=None): Type.__init__(self, name, isconst=isconst, isref=isref) self.desc = classDesc + + def translate(self, translator, **params): + return translator.translate_class_type(self, **params) class ListType(Type): @@ -239,23 +107,43 @@ class ListType(Type): self.containedTypeName = containedTypeName self._containedTypeDesc = None - def set_contained_type_desc(self, desc): + def _set_contained_type_desc(self, desc): self._containedTypeDesc = desc desc.parent = self - def get_contained_type_desc(self): + def _get_contained_type_desc(self): return self._containedTypeDesc - containedTypeDesc = property(fset=set_contained_type_desc, fget=get_contained_type_desc) + containedTypeDesc = property(fset=_set_contained_type_desc, fget=_get_contained_type_desc) + + def translate(self, translator, **params): + return translator.translate_list_type(self, **params) class DocumentableObject(Object): def __init__(self, name): Object.__init__(self, name) - self.briefDescription = None - self.detailedDescription = None + self._briefDescription = None + self._detailedDescription = None self.deprecated = None + def _get_brief_description(self): + return self._briefDescription + + def _set_brief_description(self, description): + self._briefDescription = description + description.relatedObject = self + + def _get_detailed_description(self): + return self._detailedDescription + + def _set_detailed_description(self, description): + self._detailedDescription = description + description.relatedObject = self + + briefDescription = property(fget=_get_brief_description, fset=_set_brief_description) + detailedDescription = property(fget=_get_detailed_description, fset=_set_detailed_description) + def set_from_c(self, cObject, namespace=None): self.briefDescription = cObject.briefDescription self.detailedDescription = cObject.detailedDescription @@ -281,32 +169,38 @@ class Namespace(DocumentableObject): child.parent = self +GlobalNs = Namespace('') + + class Flag: def __init__(self, position): self.position = position -class EnumValue(DocumentableObject): +class Enumerator(DocumentableObject): def __init__(self, name): DocumentableObject.__init__(self, name) self.value = None def value_from_string(self, stringValue): - m = re.match('^1\s*<<\s*([0-9]+)$', stringValue) + m = re.match('^\s*1\s*<<\s*([0-9]+)$', stringValue) if m is not None: self.value = Flag(int(m.group(1))) else: self.value = int(stringValue, base=0) + + def translate_value(self, translator): + return translator.translate_enumerator_value(self.value) class Enum(DocumentableObject): def __init__(self, name): DocumentableObject.__init__(self, name) - self.values = [] + self.enumerators = [] - def add_value(self, value): - self.values.append(value) - value.parent = self + def add_enumerator(self, enumerator): + self.enumerators.append(enumerator) + enumerator.parent = self def set_from_c(self, cEnum, namespace=None): Object.set_from_c(self, cEnum, namespace=namespace) @@ -316,14 +210,14 @@ class Enum(DocumentableObject): else: name = cEnum.name - self.name = EnumName() + self.name = metaname.EnumName() self.name.prev = None if namespace is None else namespace.name self.name.set_from_c(name) for cEnumValue in cEnum.values: - aEnumValue = EnumValue() + aEnumValue = Enumerator() aEnumValue.set_from_c(cEnumValue, namespace=self) - self.add_value(aEnumValue) + self.add_enumerator(aEnumValue) class Argument(DocumentableObject): @@ -342,6 +236,9 @@ class Argument(DocumentableObject): return self._type type = property(fset=_set_type, fget=_get_type) + + def translate(self, translator, **params): + return translator.translate_argument(self, **params) class Method(DocumentableObject): @@ -352,10 +249,14 @@ class Method(DocumentableObject): def __init__(self, name, type=Type.Instance): DocumentableObject.__init__(self, name) self.type = type - self.constMethod = False + self.isconst = False self.args = [] self._returnType = None - + + def add_arguments(self, arg): + self.args.append(arg) + arg.parent = self + def _set_return_type(self, returnType): self._returnType = returnType returnType.parent = self @@ -363,11 +264,10 @@ class Method(DocumentableObject): def _get_return_type(self): return self._returnType - def add_arguments(self, arg): - self.args.append(arg) - arg.parent = self - returnType = property(fset=_set_return_type, fget=_get_return_type) + + def translate_as_prototype(self, translator, **params): + return translator.translate_method_as_prototype(self, **params) class Property(DocumentableObject): @@ -427,6 +327,11 @@ class Class(DocumentableObject): return self._listenerInterface listenerInterface = property(fget=get_listener_interface, fset=set_listener_interface) + + def sort(self): + self.properties.sort() + self.instanceMethods.sort() + self.classMethods.sort() class Interface(DocumentableObject): @@ -443,6 +348,9 @@ class Interface(DocumentableObject): return self._listenedClass listenedClass = property(fget=get_listened_class) + + def sort(self): + self.methods.sort() class CParser(object): @@ -469,6 +377,7 @@ class CParser(object): self.cProject = cProject self.enumsIndex = {} + self.enums = [] for enum in self.cProject.enums: if enum.associatedTypedef is None: self.enumsIndex[enum.name] = None @@ -477,6 +386,8 @@ class CParser(object): self.classesIndex = {} self.interfacesIndex = {} + self.classes = [] + self.interfaces = [] for _class in self.cProject.classes: if _class.name not in self.classBl: if _class.name.endswith('Cbs'): @@ -496,15 +407,15 @@ class CParser(object): if _property.getter is not None: self.methodsIndex[_property.getter.name] = None - name = NamespaceName() + name = metaname.NamespaceName() name.from_snake_case('linphone') self.namespace = Namespace(name) def _is_blacklisted(self, name): - if type(name) is MethodName: + if type(name) is metaname.MethodName: return name.to_camel_case(lower=True) in self.methodBl or name.to_c() in self.functionBl - elif type(name) is ClassName: + elif type(name) is metaname.ClassName: return name.to_c() in self.classBl else: return False @@ -526,6 +437,7 @@ class CParser(object): self._clean_all_indexes() + self._sortall() self._fix_all_types() self._fix_all_docs() @@ -542,6 +454,15 @@ class CParser(object): for key in keysToRemove: del index[key] + def _sortall(self): + self.enums.sort() + self.classes.sort() + self.interfaces.sort() + for class_ in self.classes: + class_.sort() + for interface in self.interfaces: + interface.sort() + def _class_is_refcountable(self, _class): if _class.name in self.forcedRefcountableClasses: return True @@ -609,11 +530,19 @@ class CParser(object): def _fix_all_docs(self): for _class in self.classesIndex.values(): - if _class.briefDescription is not None: - _class.briefDescription.resolve_all_references(self) + self._fix_doc(_class) + for enum in self.enumsIndex.values(): + self._fix_doc(enum) + for enumerator in enum.enumerators: + self._fix_doc(enumerator) for method in self.methodsIndex.values(): - if method.briefDescription is not None: - method.briefDescription.resolve_all_references(self) + self._fix_doc(method) + + def _fix_doc(self, obj): + if obj.briefDescription is not None: + obj.briefDescription.resolve_all_references(self) + if obj.detailedDescription is not None: + obj.detailedDescription.resolve_all_references(self) def parse_enum(self, cenum): if 'associatedTypedef' in dir(cenum): @@ -621,25 +550,28 @@ class CParser(object): else: nameStr = cenum.name - name = EnumName() + name = metaname.EnumName() name.from_camel_case(nameStr, namespace=self.namespace.name) enum = Enum(name) enum.briefDescription = cenum.briefDoc + enum.detailedDescription = cenum.detailedDoc self.namespace.add_child(enum) for cEnumValue in cenum.values: - valueName = EnumValueName() + valueName = metaname.EnumeratorName() valueName.from_camel_case(cEnumValue.name, namespace=name) - aEnumValue = EnumValue(valueName) + aEnumValue = Enumerator(valueName) aEnumValue.briefDescription = cEnumValue.briefDoc + aEnumValue.detailedDescription = cEnumValue.detailedDoc if cEnumValue.value is not None: try: aEnumValue.value_from_string(cEnumValue.value) except ValueError: raise Error('{0} enum value has an invalid definition ({1})'.format(cEnumValue.name, cEnumValue.value)) - enum.add_value(aEnumValue) + enum.add_enumerator(aEnumValue) self.enumsIndex[nameStr] = enum + self.enums.append(enum) return enum def parse_class(self, cclass): @@ -649,17 +581,20 @@ class CParser(object): if cclass.name.endswith('Cbs'): _class = self._parse_listener(cclass) self.interfacesIndex[cclass.name] = _class + self.interfaces.append(_class) else: _class = self._parse_class(cclass) self.classesIndex[cclass.name] = _class + self.classes.append(_class) self.namespace.add_child(_class) return _class def _parse_class(self, cclass): - name = ClassName() + name = metaname.ClassName() name.from_camel_case(cclass.name, namespace=self.namespace.name) _class = Class(name) _class.briefDescription = cclass.briefDoc + _class.detailedDescription = cclass.detailedDoc for cproperty in cclass.properties.values(): try: @@ -700,7 +635,7 @@ class CParser(object): return _class def _parse_property(self, cproperty, namespace=None): - name = PropertyName() + name = metaname.PropertyName() name.from_snake_case(cproperty.name) if (cproperty.setter is not None and len(cproperty.setter.arguments) == 1) or (cproperty.getter is not None and len(cproperty.getter.arguments) == 0): methodType = Method.Type.Class @@ -717,7 +652,7 @@ class CParser(object): def _parse_listener(self, cclass): - name = InterfaceName() + name = metaname.InterfaceName() name.from_camel_case(cclass.name, namespace=self.namespace.name) if name.words[len(name.words)-1] == 'cbs': @@ -727,6 +662,7 @@ class CParser(object): listener = Interface(name) listener.briefDescription = cclass.briefDoc + listener.detailedDescription = cclass.detailedDoc for property in cclass.properties.values(): if property.name != 'user_data': @@ -739,7 +675,7 @@ class CParser(object): return listener def _parse_listener_property(self, property, listener, events): - methodName = MethodName() + methodName = metaname.MethodName() methodName.from_snake_case(property.name) methodName.words.insert(0, 'on') methodName.prev = listener.name @@ -759,7 +695,7 @@ class CParser(object): method = Method(methodName) method.returnType = self.parse_type(event.returnArgument) for arg in event.arguments: - argName = ArgName() + argName = metaname.ArgName() argName.from_snake_case(arg.name) argument = Argument(argName, self.parse_type(arg)) method.add_arguments(argument) @@ -767,7 +703,7 @@ class CParser(object): return method def parse_method(self, cfunction, namespace, type=Method.Type.Instance): - name = MethodName() + name = metaname.MethodName() name.from_snake_case(cfunction.name, namespace=namespace) if self._is_blacklisted(name): @@ -775,15 +711,16 @@ class CParser(object): method = Method(name, type=type) method.briefDescription = cfunction.briefDoc + method.detailedDescription = cfunction.detailedDoc method.deprecated = cfunction.deprecated method.returnType = self.parse_type(cfunction.returnArgument) for arg in cfunction.arguments: if type == Method.Type.Instance and arg is cfunction.arguments[0]: - method.constMethod = ('const' in arg.completeType.split(' ')) + method.isconst = ('const' in arg.completeType.split(' ')) else: aType = self.parse_type(arg) - argName = ArgName() + argName = metaname.ArgName() argName.from_snake_case(arg.name) absArg = Argument(argName, aType) method.add_arguments(absArg) @@ -807,7 +744,7 @@ class CParser(object): else: raise Error('Unknown C type \'{0}\''.format(cType.ctype)) - absType.cname = cType.completeType + absType.cDecl = cType.completeType return absType def parse_c_base_type(self, cDecl): @@ -871,3 +808,341 @@ class CParser(object): return BaseType(name, **param) else: raise Error('could not find type in \'{0}\''.format(cDecl)) + + +class Translator: + instances = {} + + @staticmethod + def get(langCode): + try: + if langCode not in Translator.instances: + className = langCode + 'LangTranslator' + _class = globals()[className] + Translator.instances[langCode] = _class() + + return Translator.instances[langCode] + except KeyError: + raise ValueError("Invalid language code: '{0}'".format(langCode)) + + +class CLikeLangTranslator(Translator): + def translate_enumerator_value(self, value): + if value is None: + return None + elif isinstance(value, int): + return str(value) + elif isinstance(value, Flag): + return '1<<{0}'.format(value.position) + else: + raise TypeError('invalid enumerator value type: {0}'.format(value)) + + def translate_argument(self, argument, **kargs): + return '{0} {1}'.format(argument.type.translate(self, **kargs), argument.name.translate(self.nameTranslator)) + + +class CLangTranslator(CLikeLangTranslator): + def __init__(self): + self.nameTranslator = metaname.Translator.get('C') + self.nilToken = 'NULL' + self.falseConstantToken = 'FALSE' + self.trueConstantToken = 'TRUE' + + def translate_base_type(self, _type): + return _type.cDecl + + def translate_enum_type(self, _type): + return _type.cDecl + + def translate_class_type(self, _type): + return _type.cDecl + + def translate_list_type(self, _type): + return _type.cDecl + + def translate_enumerator_value(self, value): + if value is None: + return None + elif isinstance(value, int): + return str(value) + elif isinstance(value, Flag): + return '1<<{0}'.format(value.position) + else: + raise TypeError('invalid enumerator value type: {0}'.format(value)) + + def translate_method_as_prototype(self, method, **params): + _class = method.find_first_ancestor_by_type(Class) + params = '{const}{className} *obj'.format( + className=_class.name.to_c(), + const='const ' if method.isconst else '' + ) + for arg in method.args: + params += (', ' + arg.translate(self)) + + return '{returnType} {name}({params})'.format( + returnType=method.returnType.translate(self), + name=method.name.translate(self.nameTranslator), + params=params + ) + + +class CppLangTranslator(CLikeLangTranslator): + def __init__(self): + self.nameTranslator = metaname.Translator.get('Cpp') + self.nilToken = 'nullptr' + self.falseConstantToken = 'false' + self.trueConstantToken = 'true' + self.ambigousTypes = [] + + def translate_base_type(self, _type, showStdNs=True, namespace=None): + if _type.name == 'void': + if _type.isref: + return 'void *' + else: + return 'void' + elif _type.name == 'boolean': + res = 'bool' + elif _type.name == 'character': + res = 'char' + elif _type.name == 'size': + res = 'size_t' + elif _type.name == 'time': + res = 'time_t' + elif _type.name == 'integer': + if _type.size is None: + res = 'int' + elif isinstance(_type.size, str): + res = _type.size + else: + res = 'int{0}_t'.format(_type.size) + + elif _type.name == 'floatant': + if _type.size is not None and _type.size == 'double': + res = 'double' + else: + res = 'float' + elif _type.name == 'status': + res = 'linphone::Status' + elif _type.name == 'string': + res = CppLangTranslator.prepend_std('string', showStdNs) + if type(_type.parent) is Argument: + res += ' &' + elif _type.name == 'string_array': + res = '{0}<{1}>'.format( + CppLangTranslator.prepend_std('list', showStdNs), + CppLangTranslator.prepend_std('string', showStdNs) + ) + if type(_type.parent) is Argument: + res += ' &' + else: + raise Error('\'{0}\' is not a base abstract type'.format(_type.name)) + + if _type.isUnsigned: + if _type.name == 'integer' and isinstance(_type.size, int): + res = 'u' + res + else: + res = 'unsigned ' + res + + if _type.isconst: + if _type.name not in ['string', 'string_array'] or type(_type.parent) is Argument: + res = 'const ' + res + + if _type.isref: + res += ' *' + return res + + def translate_enum_type(self, _type, showStdNs=True, namespace=None): + if _type.desc is None: + raise Error('{0} has not been fixed'.format(_type.name)) + + if namespace is not None: + nsName = namespace.name if namespace is not GlobalNs else None + else: + method = _type.find_first_ancestor_by_type(Method) + nsName = metaname.Name.find_common_parent(_type.desc.name, method.name) + + return _type.desc.name.translate(self.nameTranslator, recursive=True, topAncestor=nsName) + + def translate_class_type(self, _type, showStdNs=True, namespace=None): + if _type.desc is None: + raise Error('{0} has not been fixed'.format(_type.name)) + + if namespace is not None: + nsName = namespace.name if namespace is not GlobalNs else None + else: + method = _type.find_first_ancestor_by_type(Method) + nsName = metaname.Name.find_common_parent(_type.desc.name, method.name) + + if _type.desc.name.to_c() in self.ambigousTypes: + nsName = None + + res = _type.desc.name.translate(self.nameTranslator, recursive=True, topAncestor=nsName) + + if _type.desc.refcountable: + if _type.isconst: + res = 'const ' + res + if type(_type.parent) is Argument: + return 'const {0}<{1}> &'.format( + CppLangTranslator.prepend_std('shared_ptr', showStdNs), + res + ) + else: + return '{0}<{1}>'.format( + CppLangTranslator.prepend_std('shared_ptr', showStdNs), + res + ) + else: + if type(_type.parent) is Argument: + return 'const {0} &'.format(res) + else: + return '{0}'.format(res) + + def translate_list_type(self, _type, showStdNs=True, namespace=None): + if _type.containedTypeDesc is None: + raise Error('{0} has not been fixed'.format(_type.containedTypeName)) + elif isinstance(_type.containedTypeDesc, BaseType): + res = _type.containedTypeDesc.translate(self) + else: + res = _type.containedTypeDesc.translate(self, showStdNs=showStdNs, namespace=namespace) + + if type(_type.parent) is Argument: + return 'const {0}<{1} > &'.format( + CppLangTranslator.prepend_std('list', showStdNs), + res + ) + else: + return '{0}<{1} >'.format( + CppLangTranslator.prepend_std('list', showStdNs), + res + ) + + def translate_method_as_prototype(self, method, showStdNs=True, namespace=None): + _class = method.find_first_ancestor_by_type(Class, Interface) + if namespace is not None: + if _class.name.to_c() in self.ambigousTypes: + nsName = None + else: + nsName = namespace.name if namespace is not GlobalNs else None + else: + nsName = _class.name + + argsString = '' + argStrings = [] + for arg in method.args: + argStrings.append(arg.translate(self, showStdNs=showStdNs, namespace=namespace)) + argsString = ', '.join(argStrings) + + return '{_return} {name}({args}){const}'.format( + _return=method.returnType.translate(self, ), + name=method.name.translate(self.nameTranslator, recursive=True, topAncestor=nsName), + args=argsString, + const=' const' if method.isconst else '' + ) + + @staticmethod + def prepend_std(string, prepend): + return 'std::' + string if prepend else string + + +class CSharpLangTranslator(CLikeLangTranslator): + def __init__(self): + self.nameTranslator = metaname.Translator.get('CSharp') + self.nilToken = 'null' + self.falseConstantToken = 'false' + self.trueConstantToken = 'true' + + def translate_base_type(self, _type, dllImport=True): + if _type.name == 'void': + if _type.isref: + return 'IntPtr' + return 'void' + elif _type.name == 'status': + if dllImport: + return 'int' + else: + return 'void' + elif _type.name == 'boolean': + if dllImport: + res = 'char' + else: + res = 'bool' + elif _type.name == 'integer': + if _type.isUnsigned: + res = 'uint' + else: + res = 'int' + elif _type.name == 'string': + if dllImport: + if type(_type.parent) is Argument: + return 'string' + else: + res = 'IntPtr' # Return as IntPtr and get string with Marshal.PtrToStringAnsi() + else: + return 'string' + elif _type.name == 'character': + if _type.isUnsigned: + res = 'byte' + else: + res = 'sbyte' + elif _type.name == 'time': + res = 'long' #TODO check + elif _type.name == 'size': + res = 'long' #TODO check + elif _type.name == 'floatant': + return 'float' + elif _type.name == 'string_array': + if dllImport or type(_type.parent) is Argument: + return 'IntPtr' + else: + return 'IEnumerable' + else: + raise Error('\'{0}\' is not a base abstract type'.format(_type.name)) + + return res + + def translate_enum_type(self, _type, dllImport=True): + if dllImport and type(_type.parent) is Argument: + return 'int' + else: + return _type.desc.name.translate(self.nameTranslator) + + def translate_class_type(self, _type, dllImport=True): + return "IntPtr" if dllImport else _type.desc.name.translate(self.nameTranslator) + + def translate_list_type(self, _type, dllImport=True): + if dllImport: + return 'IntPtr' + else: + if type(_type.containedTypeDesc) is BaseType: + if _type.containedTypeDesc.name == 'string': + return 'IEnumerable' + else: + raise Error('translation of bctbx_list_t of basic C types is not supported') + elif type(_type.containedTypeDesc) is ClassType: + ptrType = _type.containedTypeDesc.desc.name.translate(self.nameTranslator) + return 'IEnumerable<' + ptrType + '>' + else: + if _type.containedTypeDesc: + raise Error('translation of bctbx_list_t of enums') + else: + raise Error('translation of bctbx_list_t of unknow type !') + + def translate_argument(self, arg, dllImport=True): + return '{0} {1}'.format( + arg.type.translate(self, dllImport=dllImport), + arg.name.translate(self.nameTranslator) + ) + + def translate_method_as_prototype(self, method): + kargs = { + 'static' : 'static ' if method.type == Method.Type.Class else '', + 'override' : 'override ' if method.name.translate(self.nameTranslator) == 'ToString' else '', + 'returnType' : method.returnType.translate(self, dllImport=False), + 'name' : method.name.translate(self.nameTranslator), + 'args' : '' + } + for arg in method.args: + if kargs['args'] != '': + kargs['args'] += ', ' + kargs['args'] += arg.translate(self, dllImport=False) + return '{static}{override}{returnType} {name}({args})'.format(**kargs) diff --git a/tools/genapixml.py b/tools/genapixml.py index 8666c0574..29a0dedf8 100755 --- a/tools/genapixml.py +++ b/tools/genapixml.py @@ -33,6 +33,7 @@ class CObject: self.detailedDescription = None self.deprecated = False self.briefDoc = None + self.detailedDoc = None class CEnumValue(CObject): @@ -339,6 +340,7 @@ class Project: if st.associatedTypedef == td: cclass = CClass(st) cclass.briefDoc = td.briefDoc + cclass.detailedDoc = td.detailedDoc self.add(cclass) break elif ('Linphone' + td.definition) == td.name: @@ -346,6 +348,7 @@ class Project: st.associatedTypedef = td cclass = CClass(st) cclass.briefDoc = td.briefDoc + cclass.detailedDoc = td.detailedDoc self.add(st) self.add(cclass) # Sort classes by length of name (longest first), so that methods are put in the right class @@ -389,6 +392,7 @@ class Project: ev.deprecated = True ev.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip() ev.briefDoc = self.docparser.parse_description(node.find('./briefdescription')) + ev.detailedDoc = self.docparser.parse_description(node.find('./detaileddescription')) ev.detailedDescription = self.__cleanDescription(node.find('./detaileddescription')) return ev @@ -401,6 +405,7 @@ class Project: e.deprecated = True e.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip() e.briefDoc = self.docparser.parse_description(node.find('./briefdescription')) + e.detailedDoc = self.docparser.parse_description(node.find('./detaileddescription')) e.detailedDescription = self.__cleanDescription(node.find('./detaileddescription')) enumvalues = node.findall("enumvalue[@prot='public']") for enumvalue in enumvalues: @@ -424,6 +429,7 @@ class Project: sm.deprecated = True sm.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip() sm.briefDoc = self.docparser.parse_description(node.find('./briefdescription')) + sm.detailedDoc = self.docparser.parse_description(node.find('./detaileddescription')) sm.detailedDescription = self.__cleanDescription(node.find('./detaileddescription')) return sm @@ -434,6 +440,7 @@ class Project: s.deprecated = True s.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip() s.briefDoc = self.docparser.parse_description(node.find('./briefdescription')) + s.detailedDoc = self.docparser.parse_description(node.find('./detaileddescription')) s.detailedDescription = self.__cleanDescription(node.find('./detaileddescription')) structmembers = node.findall("sectiondef/memberdef[@kind='variable'][@prot='public']") for structmember in structmembers: @@ -503,6 +510,7 @@ class Project: f.deprecated = True f.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip() f.briefDoc = self.docparser.parse_description(node.find('./briefdescription')) + f.detailedDoc = self.docparser.parse_description(node.find('./detaileddescription')) f.detailedDescription = self.__cleanDescription(node.find('./detaileddescription')) return f else: @@ -515,6 +523,7 @@ class Project: td.deprecated = True td.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip() td.briefDoc = self.docparser.parse_description(node.find('./briefdescription')) + td.detailedDoc = self.docparser.parse_description(node.find('./detaileddescription')) td.detailedDescription = self.__cleanDescription(node.find('./detaileddescription')) return td return None @@ -531,6 +540,11 @@ class Project: internal = node.find("./detaileddescription/internal") if internal is not None: return None + + # The doc must be parsed here since the XML tree is to be modified in below code + briefDoc = self.docparser.parse_description(node.find('./briefdescription')) + detailedDoc = self.docparser.parse_description(node.find('./detaileddescription')) + missingDocWarning = '' name = node.find('./name').text t = ''.join(node.find('./type').itertext()) @@ -574,10 +588,11 @@ class Project: if deprecatedNode is not None: f.deprecated = True f.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip() - f.briefDoc = self.docparser.parse_description(node.find('./briefdescription')) f.detailedDescription = self.__cleanDescription(node.find('./detaileddescription')) if f.briefDescription == '' and ''.join(f.detailedDescription.itertext()).strip() == '': return None + f.briefDoc = briefDoc + f.detailedDoc = detailedDoc locationNode = node.find('./location') if locationNode is not None: f.location = locationNode.get('file') diff --git a/tools/metadoc.py b/tools/metadoc.py index fd985a11f..e2dcdc091 100644 --- a/tools/metadoc.py +++ b/tools/metadoc.py @@ -1,5 +1,3 @@ -#!/usr/bin/python - # Copyright (C) 2017 Belledonne Communications SARL # # This program is free software; you can redistribute it and/or @@ -16,17 +14,131 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +import metaname import abstractapi +import re -class Nil: +class ParsingError(RuntimeError): pass -class Reference: +class UnreleasedNodeError(ValueError): + pass + + +class ChildrenList(list): + def __init__(self, node): + list.__init__(self) + self.node = node + + def __setitem__(self, key, child): + if child.parent is not None: + raise UnreleasedNodeError() + self[key].parent = None + list.__setitem__(self, key, child) + child.parent = self.node + + def __delitem__(self, key): + self[key].parent = None + list.__delitem__(self, key) + + def __iadd__(self, other): + list.__iadd__(self, other) + for child in other: + child.parent = self.node + return self + + def append(self, child): + list.append(self, child) + child.parent = self.node + + def removeall(self): + children = [] + while len(self) > 0: + children.append(self[0]) + del self[0] + return children + + +class TreeNode(object): + def __init__(self): + self.parent = None + + def find_ancestor(self, ancestorType): + ancestor = self.parent + while ancestor is not None and type(ancestor) is not ancestorType: + ancestor = ancestor.parent + return ancestor + + def find_root(self): + node = self + while node.parent is not None: + node = node.parent + return node + + +class SingleChildTreeNode(TreeNode): + def __init__(self): + TreeNode.__init__(self) + self._child = None + + def _setchild(self, child): + if child is not None and child.parent is not None: + raise UnreleasedNodeError() + if self._child is not None: + self._child.parent = None + self._child = child + if child is not None: + child.parent = self + + def _getchild(self): + return self._child + + def _delchild(self): + if self._child is not None: + self._child.parent = None + del self._child + + child = property(fset=_setchild, fget=_getchild, fdel=_delchild) + + +class MultiChildTreeNode(TreeNode): + def __init__(self): + TreeNode.__init__(self) + self.children = ChildrenList(self) + + +class ParagraphPart(TreeNode): + pass + + +class TextPart(ParagraphPart): + def __init__(self, text): + ParagraphPart.__init__(self) + self.text = text + + def translate(self, docTranslator, **kargs): + return docTranslator.translate_text(self) + + +class LanguageKeyword(ParagraphPart): + def __init__(self, keyword): + ParagraphPart.__init__(self) + self.keyword = keyword + + def translate(self, docTranslator, **kargs): + return docTranslator.translate_keyword(self) + + +class Reference(ParagraphPart): def __init__(self, cname): + ParagraphPart.__init__(self) self.cname = cname self.relatedObject = None + + def translate(self, docTranslator, **kargs): + return docTranslator.translate_reference(self, **kargs) class ClassReference(Reference): @@ -45,54 +157,210 @@ class FunctionReference(Reference): print('doc reference pointing on an unknown object ({0})'.format(self.cname)) -class Paragraph: - def __init__(self): - self.parts = [] +class Paragraph(MultiChildTreeNode): + @property + def parts(self): + return self.children + + @parts.setter + def parts(self, parts): + self.children = parts def resolve_all_references(self, api): for part in self.parts: if isinstance(part, Reference): part.resolve(api) + elif isinstance(part, (Section, ParameterList)): + part.resolve_all_references(api) + + def translate(self, docTranslator, **kargs): + return docTranslator._translate_paragraph(self, **kargs) -class Description: +class Section(SingleChildTreeNode): + def __init__(self, kind): + SingleChildTreeNode.__init__(self) + self.kind = kind + + @property + def paragraph(self): + return self.child + + @paragraph.setter + def paragraph(self, paragraph): + self.child = paragraph + + def resolve_all_references(self, api): + if self.paragraph is not None: + self.paragraph.resolve_all_references(api) + + def translate(self, docTranslator, **kargs): + return docTranslator._translate_section(self, **kargs) + + +class ParameterDescription(SingleChildTreeNode): + def __init__(self, name, desc): + SingleChildTreeNode.__init__(self) + self.name = name + self.child = desc + + @property + def desc(self): + return self.child + + @desc.setter + def desc(self, desc): + self.child = desc + + def is_self_parameter(self): + method = self.find_ancestor(Description).relatedObject + return method.type == abstractapi.Method.Type.Instance and self.name not in [arg.name for arg in method.args] + + +class ParameterList(MultiChildTreeNode): + @property + def parameters(self): + return self.children + + @parameters.setter + def parameters(self, parameters): + self.children = parameters + + def resolve_all_references(self, api): + for parameter in self.parameters: + if parameter.desc is not None: + parameter.desc.resolve_all_references(api) + + def translate(self, docTranslator, **kargs): + return docTranslator._translate_parameter_list(self, **kargs) + + +class Description(MultiChildTreeNode): def __init__(self): - self.paragraphs = [] + MultiChildTreeNode.__init__(self) + self.relatedObject = None + + @property + def paragraphs(self): + return self.children + + @paragraphs.setter + def paragraphs(self, paragraphs): + self.children = paragraphs def resolve_all_references(self, api): for paragraph in self.paragraphs: paragraph.resolve_all_references(api) + + def translate(self, translator, **kargs): + return translator.translate_description(self, **kargs) class Parser: + def __init__(self): + self.constants_regex = re.compile('(?:^|\W)(TRUE|FALSE|NULL)(?:\W|$)') + def parse_description(self, node): + if node is None: + return None + desc = Description() for paraNode in node.findall('./para'): - desc.paragraphs.append(self._parse_paragraph(paraNode)) + desc.paragraphs += self._parse_paragraph(paraNode) return desc def _parse_paragraph(self, node): + paragraphs = [] paragraph = Paragraph() - for partNode in node.iter(): - if partNode is node: + + text = node.text + if text is not None: + paragraph.parts += self._parse_text(text) + + for partNode in node.findall('*'): + if partNode.tag == 'ref': + ref = self._parse_reference(partNode) + if ref is not None: + paragraph.parts.append(ref) + elif partNode.tag == 'simplesect': + paragraphs.append(paragraph) + paragraph.parts.append(self._parse_simple_section(partNode)) + paragraph = Paragraph() + elif partNode.tag == 'xrefsect': + paragraphs.append(paragraph) + paragraph.parts.append(self._parse_xref_section(partNode)) + paragraph = Paragraph() + elif partNode.tag == 'parameterlist' and partNode.get('kind') == 'param': + paragraphs.append(paragraph) + paragraphs.append(self._parse_parameter_list(partNode)) + paragraph = Paragraph() + else: text = partNode.text if text is not None: - paragraph.parts.append(text) - else: - if partNode.tag == 'ref': - ref = self._parse_reference(partNode) - if ref is not None: - paragraph.parts.append(ref) - else: - text = partNode.text - if text is not None: - paragraph.parts.append(text) - - tail = partNode.tail - if tail is not None: - paragraph.parts.append(tail) + paragraph.parts += self._parse_text(text) + + text = partNode.tail + if text is not None: + text = text.strip('\n') + if len(text) > 0: + paragraph.parts += self._parse_text(text) - return paragraph + paragraphs.append(paragraph) + return [x for x in paragraphs if type(x) is not Paragraph or len(x.parts) > 0] + + def _parse_text(self, text): + parts = [] + lastIndex = 0 + + match = self.constants_regex.search(text) + while match is not None: + if match.start(1)-lastIndex > 0: + parts.append(TextPart(text[lastIndex:match.start(1)])) + parts.append(self._parse_constant(text[match.start(1):match.end(1)])) + lastIndex = match.end(1) + match = self.constants_regex.search(text, lastIndex) + + if lastIndex < len(text): + parts.append(TextPart(text[lastIndex:])) + + return parts + + def _parse_constant(self, token): + if token == 'TRUE': + return LanguageKeyword(abstractapi.Boolean(True)) + elif token == 'FALSE': + return LanguageKeyword(abstractapi.Boolean(False)) + elif token == 'NULL': + return LanguageKeyword(abstractapi.Nil()) + else: + raise ValueError("invalid C constant token '{0}'".format(token)) + + def _parse_simple_section(self, sectionNode): + section = Section(sectionNode.get('kind')) + para = sectionNode.find('./para') + paragraphs = self._parse_paragraph(para) + section.paragraph = paragraphs[0] if len(paragraphs) > 0 else None + return section + + def _parse_parameter_list(self, paramListNode): + paramList = ParameterList() + for paramItemNode in paramListNode.findall('./parameteritem'): + name = metaname.ArgName() + name.from_snake_case(paramItemNode.find('./parameternamelist/parametername').text) + desc = self.parse_description(paramItemNode.find('parameterdescription')) + paramList.parameters.append(ParameterDescription(name, desc)) + return paramList + + def _parse_xref_section(self, sectionNode): + sectionId = sectionNode.get('id') + if sectionId.startswith('deprecated_'): + section = Section('deprecated') + description = self.parse_description(sectionNode.find('./xrefdescription')) + paras = description.paragraphs.removeall() + section.paragraph = paras[0] if len(paras) > 0 else None + return section + else: + raise ParsingError('unknown xrefsect type ({0})'.format(sectionId)) def _parse_reference(self, node): if node.text.endswith('()'): @@ -101,50 +369,92 @@ class Parser: return ClassReference(node.text) -class Translator: - def __init__(self): - self.textWidth = 80 +class TranslationError(Exception): + pass + + +class ReferenceTranslationError(TranslationError): + def __init__(self, refName): + Exception.__init__(self, refName) - def translate(self, description): + def msg(self): + return '{0} reference could not been translated'.format(self.args[0]) + + +class Translator: + def __init__(self, langCode): + self.textWidth = 80 + self.nameTranslator = metaname.Translator.get(langCode) + self.langTranslator = abstractapi.Translator.get(langCode) + self.displaySelfParam = True if langCode == 'C' else False + + def translate_description(self, description, tagAsBrief=False): if description is None: return None - lines = [] - for para in description.paragraphs: - if para is not description.paragraphs[0]: - lines.append('') - lines.append(self._translate_paragraph(para)) + paras = self._translate_description(description) + + lines = self._paragraphs_to_lines(paras) + + if tagAsBrief: + self._tag_as_brief(lines) - self._tag_as_brief(lines) lines = self._crop_text(lines, self.textWidth) translatedDoc = {'lines': []} for line in lines: translatedDoc['lines'].append({'line': line}) - + return translatedDoc + def translate_reference(self, ref, absName=False, namespace=None): + if ref.relatedObject is None: + raise ReferenceTranslationError(ref.cname) + if absName: + commonName = None + else: + if namespace is None: + description = ref.find_root() + namespaceObj = description.relatedObject.find_first_ancestor_by_type(abstractapi.Namespace, abstractapi.Class) + namespace = namespaceObj.name + if namespace.is_prefix_of(ref.relatedObject.name): + commonName = namespace + else: + commonName = metaname.Name.find_common_parent(ref.relatedObject.name, namespace) + return ref.relatedObject.name.translate(self.nameTranslator, recursive=True, topAncestor=commonName) + + def translate_keyword(self, keyword): + return keyword.keyword.translate(self.langTranslator) + + def translate_text(self, textpart): + return textpart.text + + def _translate_description(self, desc): + paras = [] + for para in desc.paragraphs: + paras.append(para.translate(self)) + return [para for para in paras if para != ''] + def _translate_paragraph(self, para): strPara = '' for part in para.parts: - if isinstance(part, str): - strPara += part - elif isinstance(part, Reference): - try: - strPara += self._translate_reference(part) - except ReferenceTranslationError as e: - print('could not translate one reference in docstrings ({0})'.format(e.args[0])) - strPara += Translator._translate_reference(self, part) - else: - raise TypeError('untranslatable paragraph element ({0})'.format(part)) + try: + if isinstance(part, str): + strPara += part + else: + strPara += part.translate(self) + except TranslationError as e: + print('error: {0}'.format(e.msg())) return strPara - def _translate_reference(self, ref): - if isinstance(ref, FunctionReference): - return ref.cname + '()' - else: - return ref.cname + def _paragraphs_to_lines(self, paragraphs): + lines = [] + for para in paragraphs: + if para is not paragraphs[0]: + lines.append('') + lines += para.split('\n') + return lines def _crop_text(self, inputLines, width): outputLines = [] @@ -152,7 +462,12 @@ class Translator: outputLines += self._split_line(line, width) return outputLines - def _split_line(self, line, width): + def _split_line(self, line, width, indent=False): + firstNonTab = next((c for c in line if c != '\t'), None) + tabCount = line.index(firstNonTab) if firstNonTab is not None else 0 + linePrefix = ('\t' * tabCount) + line = line[tabCount:] + lines = [] while len(line) > width: cutIndex = line.rfind(' ', 0, width) @@ -163,36 +478,170 @@ class Translator: cutIndex = width lines.append(line[0:cutIndex]) line = line[cutIndex:] - lines.append(line) - return lines + + if indent: + lines = [line if line is lines[0] else '\t' + line for line in lines] + + return [linePrefix + line for line in lines] + + def _tag_as_brief(self, lines): + pass -class ReferenceTranslationError(RuntimeError): - pass - - -class DoxygenCppTranslator(Translator): +class DoxygenTranslator(Translator): def _tag_as_brief(self, lines): if len(lines) > 0: lines[0] = '@brief ' + lines[0] - def _translate_reference(self, ref): + def translate_reference(self, ref): + refStr = Translator.translate_reference(self, ref) if isinstance(ref.relatedObject, (abstractapi.Class, abstractapi.Enum)): - return '#' + ref.relatedObject.name.to_c() + return '#' + refStr elif isinstance(ref.relatedObject, abstractapi.Method): - return ref.relatedObject.name.to_c() + '()' + return refStr + '()' else: raise ReferenceTranslationError(ref.cname) + + def _translate_section(self, section): + return '@{0} {1}'.format( + section.kind, + self._translate_paragraph(section.paragraph) + ) + + def _translate_parameter_list(self, parameterList): + text = '' + for paramDesc in parameterList.parameters: + if self.displaySelfParam or not paramDesc.is_self_parameter(): + desc = self._translate_description(paramDesc.desc) + desc = desc[0] if len(desc) > 0 else '' + text = ('@param {0} {1}'.format(paramDesc.name.translate(self.nameTranslator), desc)) + return text -class SandcastleCSharpTranslator(Translator): +class JavaDocTranslator(DoxygenTranslator): + def __init__(self): + DoxygenTranslator.__init__(self, 'C') + + def _tag_as_brief(self, lines): + pass + + +class SphinxTranslator(Translator): + def __init__(self, langCode): + Translator.__init__(self, langCode) + if langCode == 'C': + self.domain = 'c' + self.classDeclarator = 'type' + self.methodDeclarator = 'function' + self.enumDeclarator = 'type' + self.enumeratorDeclarator = 'var' + self.enumeratorReferencer = 'data' + self.methodReferencer = 'func' + elif langCode == 'Cpp': + self.domain = 'cpp' + self.classDeclarator = 'class' + self.methodDeclarator = 'function' + self.enumDeclarator = 'enum' + self.enumeratorDeclarator = 'enumerator' + self.namespaceDeclarator = 'namespace' + self.methodReferencer = 'func' + elif langCode == 'CSharp': + self.domain = 'csharp' + self.classDeclarator = 'class' + self.methodDeclarator = 'method' + self.enumDeclarator = 'enum' + self.enumeratorDeclarator = 'value' + self.namespaceDeclarator = 'namespace' + self.classReferencer = 'type' + self.enumReferencer = 'type' + self.enumeratorReferencer = 'enum' + self.methodReferencer = 'meth' + else: + raise ValueError('invalid language code: {0}'.format(langCode)) + + def get_declarator(self, typeName): + try: + attrName = typeName + 'Declarator' + declarator = getattr(self, attrName) + return '{0}:{1}'.format(self.domain, declarator) + except AttributeError: + raise ValueError("'{0}' declarator type not supported".format(typeName)) + + def get_referencer(self, typeName): + try: + attrName = typeName + 'Referencer' + if attrName in dir(self): + referencer = getattr(self, attrName) + return '{0}:{1}'.format(self.domain, referencer) + else: + return self.get_declarator(typeName) + except AttributeError: + raise ValueError("'{0}' referencer type not supported".format(typeName)) + + def translate_reference(self, ref, label=None, namespace=None): + strRef = Translator.translate_reference(self, ref, absName=True) + kargs = { + 'tag' : self._sphinx_ref_tag(ref), + 'ref' : strRef, + } + kargs['label'] = label if label is not None else Translator.translate_reference(self, ref, namespace=namespace) + if isinstance(ref, FunctionReference): + kargs['label'] += '()' + + return ':{tag}:`{label} <{ref}>`'.format(**kargs) + + def translate_keyword(self, keyword): + translatedKeyword = Translator.translate_keyword(self, keyword) + return '``{0}``'.format(translatedKeyword) + + def _translate_section(self, section): + strPara = self._translate_paragraph(section.paragraph) + if section.kind == 'deprecated': + return '**Deprecated:** {0}\n'.format(strPara) + else: + if section.kind == 'see': + kind = 'seealso' + else: + kind = section.kind + + if section.kind == 'return': + return ':return: {0}'.format(strPara) + else: + return '.. {0}::\n\t\n\t{1}\n\n'.format(kind, strPara) + + def _translate_parameter_list(self, parameterList): + text = '' + for paramDesc in parameterList.parameters: + if self.displaySelfParam or not paramDesc.is_self_parameter(): + desc = self._translate_description(paramDesc.desc) + desc = desc[0] if len(desc) > 0 else '' + text += (':param {0}: {1}\n'.format(paramDesc.name.translate(self.nameTranslator), desc)) + text += '\n' + return text + + def _sphinx_ref_tag(self, ref): + typeName = type(ref.relatedObject).__name__.lower() + return self.get_referencer(typeName) + + isParamDescRegex = re.compile('\t*:(?:param\s+\w+|return):') + + def _split_line(self, line, width): + if SphinxTranslator.isParamDescRegex.match(line) is not None: + lines = Translator._split_line(self, line, width, indent=True) + return lines + else: + return Translator._split_line(self, line, width) + + +class SandCastleTranslator(Translator): def _tag_as_brief(self, lines): if len(lines) > 0: lines.insert(0, '') lines.append('') - - -class SandcastleJavaTranslator(Translator): - def _tag_as_brief(self, lines): - pass + + def translate_reference(self, ref): + refStr = Translator.translate_reference(self, ref, absName=True) + if isinstance(ref, FunctionReference): + refStr += '()' + return ''.format(refStr) diff --git a/tools/metaname.py b/tools/metaname.py new file mode 100644 index 000000000..6a76e6f71 --- /dev/null +++ b/tools/metaname.py @@ -0,0 +1,340 @@ +# Copyright (C) 2017 Belledonne Communications SARL +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +import re + + +class Name(object): + camelCaseParsingRegex = re.compile('[A-Z][a-z0-9]*') + lowerCamelCaseSplitingRegex = re.compile('([a-z][a-z0-9]*)([A-Z][a-z0-9]*)') + + def __init__(self): + self.words = [] + self.prev = None + + def __eq__(self, other): + return (other is not None and self.words == other.words) and (self.prev == other.prev) + + def __lt__(self, other): + return self.to_camel_case() < other.to_camel_case() + + def copy(self): + nameType = type(self) + name = nameType() + name.words = list(self.words) + name.prev = None if self.prev is None else self.prev.copy() + return name + + def delete_prefix(self, prefix): + it = self + _next = None + while it is not None and it.words != prefix.words: + _next = it + it = it.prev + + if it is None or it != prefix: + raise Error('no common prefix') + elif _next is not None: + _next.prev = None + + def _set_namespace(self, namespace): + self.prev = namespace + if self.prev is not None: + prefix = namespace.to_word_list() + i = 0 + while i 0: + suffix = self.words[-1] + if MethodName.regex.match(suffix) is not None: + self.overloadRef = int(suffix) + del self.words[-1] + + def to_c(self): + suffix = ('_' + str(self.overloadRef)) if self.overloadRef > 0 else '' + return self.to_snake_case(fullName=True) + suffix + + def translate(self, translator, **params): + return translator.translate_method_name(self, **params) + + +class ArgName(Name): + def to_c(self): + return self.to_snake_case() + + def translate(self, translator, **params): + return translator.translate_argument_name(self, **params) + + +class PropertyName(ArgName): + def translate(self, translator, **params): + return translator.translate_property_name(self, **params) + + +class NamespaceName(Name): + def __init__(self, *params): + Name.__init__(self) + if len(params) > 0: + self.words = params[0] + + def translate(self, translator, **params): + return translator.translate_namespace_name(self, **params) + + +class Translator: + instances = {} + + @staticmethod + def get(langCode): + try: + if langCode == '': + raise ValueError('Empty language code') + if langCode not in Translator.instances: + className = langCode + 'Translator' + _class = globals()[className] + Translator.instances[langCode] = _class() + + return Translator.instances[langCode] + except KeyError: + raise ValueError("Invalid language code: '{0}'".format(langCode)) + + +class CTranslator(Translator): + def translate_class_name(self, name, **params): + return name.to_c() + + def translate_interface_name(self, name, **params): + return name.to_c() + + def translate_enum_name(self, name, **params): + return name.to_c() + + def translate_enumerator_name(self, name, **params): + return name.to_c() + + def translate_method_name(self, name, **params): + return name.to_c() + + def translate_namespace_name(self, name, **params): + return None + + def translate_argument_name(self, name, **params): + return name.to_c() + + def translate_property_name(self, name, **params): + return name.to_c() + + +class JavaTranslator(Translator): + def __init__(self): + self.nsSep = '.' + self.keyWordEscapes = {} + self.lowerMethodNames = True + self.lowerNamespaceNames = True + + def translate_class_name(self, name, recursive=False, topAncestor=None): + if name.prev is None or not recursive or name.prev is topAncestor: + return name.to_camel_case() + else: + params = {'recursive': recursive, 'topAncestor': topAncestor} + return name.prev.translate(self, **params) + self.nsSep + name.to_camel_case() + + def translate_interface_name(self, name, **params): + return self.translate_class_name(name, **params) + + def translate_enum_name(self, name, **params): + return self.translate_class_name(name, **params) + + def translate_enumerator_name(self, name, **params): + return self.translate_class_name(name, **params) + + def translate_method_name(self, name, recursive=False, topAncestor=None): + translatedName = name.to_camel_case(lower=self.lowerMethodNames) + translatedName = self._escape_keyword(translatedName) + + if name.prev is None or not recursive or name.prev is topAncestor: + return translatedName + else: + params = {'recursive': recursive, 'topAncestor': topAncestor} + return name.prev.translate(self, **params) + self.nsSep + translatedName + + def translate_namespace_name(self, name, recursive=False, topAncestor=None): + translatedName = name.concatenate() if self.lowerNamespaceNames else name.to_camel_case() + if name.prev is None or not recursive or name.prev is topAncestor: + return translatedName + else: + params = {'recursive': recursive, 'topAncestor': topAncestor} + return name.prev.translate(self, **params) + self.nsSep + translatedName + + def translate_argument_name(self, name): + argname = name.to_camel_case(lower=True) + return self._escape_keyword(argname) + + def translate_property_name(self, name): + return self.translate_argument_name(name) + + def _escape_keyword(self, keyword): + try: + return self.keyWordEscapes[keyword] + except KeyError: + return keyword + + +class CppTranslator(JavaTranslator): + def __init__(self): + JavaTranslator.__init__(self) + self.nsSep = '::' + self.keyWordEscapes = {'new' : '_new'} + + def translate_enumerator_name(self, name, **params): + return self.translate_enum_name(name.prev, **params) + name.to_camel_case() + + +class CSharpTranslator(JavaTranslator): + def __init__(self): + JavaTranslator.__init__(self) + self.keyWordEscapes = { + 'params' : 'parameters', + 'event' : 'ev', + 'ref' : 'reference', + 'value' : 'val', + 'new' : '_new' + } + self.lowerMethodNames = False + self.lowerNamespaceNames = False + + def translate_property_name(self, name): + return name.to_camel_case() diff --git a/wrappers/cpp/CMakeLists.txt b/wrappers/cpp/CMakeLists.txt index 32dc090e6..5fedcd2b0 100644 --- a/wrappers/cpp/CMakeLists.txt +++ b/wrappers/cpp/CMakeLists.txt @@ -24,6 +24,7 @@ add_custom_command(OUTPUT include/linphone++/linphone.hh src/linphone++.cc COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/genwrapper.py" "${PROJECT_BINARY_DIR}/coreapi/help/doc/doxygen/xml" DEPENDS ${PROJECT_SOURCE_DIR}/tools/genapixml.py ${PROJECT_SOURCE_DIR}/tools/metadoc.py + ${PROJECT_SOURCE_DIR}/tools/metaname.py ${PROJECT_SOURCE_DIR}/tools/abstractapi.py genwrapper.py class_header.mustache diff --git a/wrappers/cpp/class_header.mustache b/wrappers/cpp/class_header.mustache index ae8f3394c..71bd810fb 100644 --- a/wrappers/cpp/class_header.mustache +++ b/wrappers/cpp/class_header.mustache @@ -54,13 +54,19 @@ namespace linphone { {{/priorDeclarations}} {{#_class}} - {{#doc}} /** + {{#briefDoc}} {{#lines}} * {{{line}}} {{/lines}} + {{/briefDoc}} + * + {{#detailedDoc}} + {{#lines}} + * {{{line}}} + {{/lines}} + {{/detailedDoc}} */ - {{/doc}} class {{className}}{{#parentClassName}}: public {{{parentClassName}}}{{/parentClassName}} { {{#friendClasses}} friend class {{name}}; @@ -102,25 +108,37 @@ namespace linphone { {{#methods}} - {{#doc}} /** - {{#lines}} + {{#briefDoc}} + {{#lines}} * {{{line}}} - {{/lines}} + {{/lines}} + {{/briefDoc}} + * + {{#detailedDoc}} + {{#lines}} + * {{{line}}} + {{/lines}} + {{/detailedDoc}} */ - {{/doc}} - {{{prototype}}} + LINPHONECXX_PUBLIC {{#deprecated}}LINPHONECXX_DEPRECATED {{/deprecated}}{{#isListener}}virtual {{/isListener}}{{{declPrototype}}}{{{suffix}}}; {{/methods}} - {{#staticMethods}} - {{#doc}} + {{#staticMethods}}; /** - {{#lines}} + {{#briefDoc}} + {{#lines}} * {{{line}}} - {{/lines}} + {{/lines}} + {{/briefDoc}} + * + {{#detailedDoc}} + {{#lines}} + * {{{line}}} + {{/lines}} + {{/detailedDoc}} */ - {{/doc}} - {{{prototype}}} + LINPHONECXX_PUBLIC {{#deprecated}}LINPHONECXX_DEPRECATED {{/deprecated}}static {{{declPrototype}}}; {{/staticMethods}} diff --git a/wrappers/cpp/class_impl.mustache b/wrappers/cpp/class_impl.mustache index ec0c55c07..8c3a83e70 100644 --- a/wrappers/cpp/class_impl.mustache +++ b/wrappers/cpp/class_impl.mustache @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include #include +#include #include "linphone++/linphone.hh" #include "tools.hh" diff --git a/wrappers/cpp/enums_header.mustache b/wrappers/cpp/enums_header.mustache index 1eff69b46..648a19e77 100644 --- a/wrappers/cpp/enums_header.mustache +++ b/wrappers/cpp/enums_header.mustache @@ -31,7 +31,7 @@ namespace linphone { */ {{/doc}} enum {{name}} { - {{#values}} + {{#enumerators}} {{#doc}} /** {{#lines}} @@ -40,7 +40,7 @@ namespace linphone { */ {{/doc}} {{name}}{{#value}} = {{{value}}}{{/value}}{{#notLast}},{{/notLast}} - {{/values}} + {{/enumerators}} }; {{/enums}} diff --git a/wrappers/cpp/genwrapper.py b/wrappers/cpp/genwrapper.py index d5f0cb0ba..1ec10effc 100755 --- a/wrappers/cpp/genwrapper.py +++ b/wrappers/cpp/genwrapper.py @@ -23,19 +23,23 @@ import argparse import os import sys import errno + sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'tools')) import genapixml as CApi import abstractapi as AbsApi import metadoc +import metaname class CppTranslator(object): sharedPtrTypeExtractor = re.compile('^(const )?std::shared_ptr<(.+)>( &)?$') def __init__(self): - self.ignore = [] self.ambigousTypes = ['LinphonePayloadType'] - self.docTranslator = metadoc.DoxygenCppTranslator() + self.nameTranslator = metaname.Translator.get('Cpp') + self.langTranslator = AbsApi.Translator.get('Cpp') + self.langTranslator.ambigousTypes.append('LinphonePayloadType') + self.docTranslator = metadoc.DoxygenTranslator('Cpp') def is_ambigous_type(self, _type): return _type.name in self.ambigousTypes or (_type.name == 'list' and self.is_ambigous_type(_type.containedTypeDesc)) @@ -43,32 +47,23 @@ class CppTranslator(object): def translate_enum(self, enum): enumDict = {} enumDict['name'] = enum.name.to_camel_case() - enumDict['doc'] = self.docTranslator.translate(enum.briefDescription) - enumDict['values'] = [] - i = 0 - for enumValue in enum.values: - enumValDict = self.translate_enum_value(enumValue) - enumValDict['notLast'] = (i != len(enum.values)-1) - enumDict['values'].append(enumValDict) - i += 1 + enumDict['doc'] = enum.briefDescription.translate(self.docTranslator) + enumDict['enumerators'] = [] + for enumerator in enum.enumerators: + enumeratorDict = self.translate_enumerator(enumerator) + enumeratorDict['notLast'] = (enumerator is not enum.enumerators[-1]) + enumDict['enumerators'].append(enumeratorDict) return enumDict - def translate_enum_value(self, enumValue): - enumValueDict = {} - enumValueDict['name'] = CppTranslator.translate_enum_value_name(enumValue.name) - enumValueDict['doc'] = self.docTranslator.translate(enumValue.briefDescription) - if type(enumValue.value) is int: - enumValueDict['value'] = str(enumValue.value) - elif type(enumValue.value) is AbsApi.Flag: - enumValueDict['value'] = '1<<' + str(enumValue.value.position) - else: - enumValueDict['value'] = None - return enumValueDict + def translate_enumerator(self, enumerator): + enumeratorDict = { + 'name' : enumerator.name.translate(self.nameTranslator), + 'doc' : enumerator.briefDescription.translate(self.docTranslator), + 'value' : enumerator.translate_value(self.langTranslator) + } + return enumeratorDict def translate_class(self, _class): - if _class.name.to_camel_case(fullName=True) in self.ignore: - raise AbsApi.Error('{0} has been escaped'.format(_class.name.to_camel_case(fullName=True))) - islistenable = _class.listenerInterface is not None ismonolistenable = (islistenable and not _class.multilistener) ismultilistenable = (islistenable and _class.multilistener) @@ -81,9 +76,10 @@ class CppTranslator(object): 'isrefcountable' : _class.refcountable, 'isnotrefcountable' : not _class.refcountable, 'isNotListener' : True, + 'isListener' : False, 'isfactory' : (_class.name.to_c() == 'LinphoneFactory'), 'isVcard' : (_class.name.to_c() == 'LinphoneVcard'), - 'className' : CppTranslator.translate_class_name(_class.name), + 'className' : _class.name.translate(self.nameTranslator), 'cClassName' : '::' + _class.name.to_c(), 'privCClassName' : '_' + _class.name.to_c(), 'parentClassName' : 'Object' if _class.refcountable else None, @@ -96,12 +92,13 @@ class CppTranslator(object): if _class.name.to_c() == 'LinphoneCore': classDict['friendClasses'].append({'name': 'Factory'}); - classDict['doc'] = self.docTranslator.translate(_class.briefDescription) + classDict['briefDoc'] = _class.briefDescription.translate(self.docTranslator, tagAsBrief=True) + classDict['detailedDoc'] = _class.detailedDescription.translate(self.docTranslator) if islistenable: - classDict['listenerClassName'] = CppTranslator.translate_class_name(_class.listenerInterface.name) + classDict['listenerClassName'] = _class.listenerInterface.name.translate(self.nameTranslator) classDict['cListenerName'] = _class.listenerInterface.name.to_c() - classDict['cppListenerName'] = CppTranslator.translate_class_name(_class.listenerInterface.name) + classDict['cppListenerName'] = _class.listenerInterface.name.translate(self.nameTranslator) for method in _class.listenerInterface.methods: classDict['wrapperCbs'].append(self._generate_wrapper_callback(_class, method)) @@ -148,10 +145,10 @@ class CppTranslator(object): args = [] wrappedArgs = [] for arg in method.args: - args.append(arg.type.cname + ' ' + arg.name.to_c()) + args.append(arg.type.cDecl + ' ' + arg.name.to_c()) wrappedArgs.append(self._wrap_c_expression_to_cpp(arg.name.to_c(), arg.type, usedNamespace=namespace)) params['params'] = ', '.join(args) - params['returnType'] = method.returnType.cname + params['returnType'] = method.returnType.cDecl wrapperCbDict = {} wrapperCbDict['cbName'] = params['name'] @@ -168,16 +165,15 @@ class CppTranslator(object): return wrapperCbDict def translate_interface(self, interface): - if interface.name.to_camel_case(fullName=True) in self.ignore: - raise AbsApi.Error('{0} has been escaped'.format(interface.name.to_camel_case(fullName=True))) - - intDict = {} - intDict['inheritFrom'] = {'name': 'Listener'} - intDict['className'] = CppTranslator.translate_class_name(interface.name) - intDict['constructor'] = None - intDict['parentClassName'] = 'Listener' - intDict['isNotListener'] = False - intDict['methods'] = [] + intDict = { + 'inheritFrom' : {'name': 'Listener'}, + 'className' : interface.name.translate(self.nameTranslator), + 'constructor' : None, + 'parentClassName' : 'Listener', + 'isNotListener' : False, + 'isListener' : True, + 'methods' : [] + } for method in interface.methods: try: methodDict = self.translate_method(method, genImpl=False) @@ -196,57 +192,26 @@ class CppTranslator(object): return res def translate_method(self, method, genImpl=True): - if method.name.to_snake_case(fullName=True) in self.ignore: - raise AbsApi.Error('{0} has been escaped'.format(method.name.to_snake_case(fullName=True))) - namespace = method.find_first_ancestor_by_type(AbsApi.Namespace) - methodElems = {} - methodElems['return'] = self.translate_type(method.returnType) - methodElems['name'] = CppTranslator.translate_method_name(method.name) + methodDict = { + 'declPrototype': method.translate_as_prototype(self.langTranslator), + 'implPrototype': method.translate_as_prototype(self.langTranslator, namespace=namespace), + 'deprecated': method.deprecated, + 'suffix': '', + 'briefDoc': method.briefDescription.translate(self.docTranslator, tagAsBrief=True) if method.briefDescription is not None else None, + 'detailedDoc': method.detailedDescription.translate(self.docTranslator) if method.detailedDescription is not None else None + } - methodElems['params'] = '' - for arg in method.args: - if arg is not method.args[0]: - methodElems['params'] += ', ' - methodElems['params'] += self.translate_argument(arg) - - methodElems['const'] = ' const' if method.constMethod else '' - methodElems['semicolon'] = ';' - if type(method.parent) is AbsApi.Class and method.type == AbsApi.Method.Type.Class: - methodElems['methodType'] = 'static ' - elif type(method.parent) is AbsApi.Interface: - methodElems['methodType'] = 'virtual ' + if type(method.parent) is AbsApi.Interface: if isinstance(method.returnType, AbsApi.BaseType) and method.returnType.name == 'void': - methodElems['semicolon'] = ' {}' + methodDict['suffix'] = ' {}' else: - methodElems['semicolon'] = ' = 0;' - else: - methodElems['methodType'] = '' - - methodElems['deprecated'] = 'LINPHONECXX_DEPRECATED ' if method.deprecated else '' - - methodDict = {} - methodDict['prototype'] = 'LINPHONECXX_PUBLIC {deprecated}{methodType}{return} {name}({params}){const}{semicolon}'.format(**methodElems) + methodDict['suffix'] = ' = 0' if genImpl: - if not self.is_ambigous_type(method.returnType): - methodElems['implReturn'] = self.translate_type(method.returnType, namespace=namespace) - else: - methodElems['implReturn'] = self.translate_type(method.returnType, namespace=None) - - methodElems['longname'] = CppTranslator.translate_method_name(method.name, recursive=True) - methodElems['implParams'] = '' - for arg in method.args: - if arg is not method.args[0]: - methodElems['implParams'] += ', ' - methodElems['implParams'] += self.translate_argument(arg, namespace=namespace) - - methodDict['implPrototype'] = '{implReturn} {longname}({implParams}){const}'.format(**methodElems) methodDict['sourceCode' ] = self._generate_source_code(method, usedNamespace=namespace) - methodDict['doc'] = self.docTranslator.translate(method.briefDescription) if method.briefDescription is not None else None - return methodDict def _generate_source_code(self, method, usedNamespace=None): @@ -291,7 +256,7 @@ class CppTranslator(object): elif type(exprtype) is AbsApi.ClassType: cPtrType = exprtype.desc.name.to_c() if exprtype.desc.refcountable: - ptrType = self.translate_class_type(exprtype, namespace=usedNamespace) + ptrType = exprtype.translate(self.langTranslator, namespace=usedNamespace) ptrType = CppTranslator.sharedPtrTypeExtractor.match(ptrType).group(2) param = { 'ptrType' : ptrType, @@ -309,7 +274,7 @@ class CppTranslator(object): if type(exprtype.containedTypeDesc) is AbsApi.BaseType and exprtype.containedTypeDesc.name == 'string': cExpr = 'StringBctbxListWrapper({0}).c_list()'.format(cppExpr) elif type(exprtype.containedTypeDesc) is AbsApi.ClassType: - ptrType = self.translate_class_type(exprtype.containedTypeDesc, namespace=usedNamespace) + ptrType = exprtype.containedTypeDesc.translate(self.langTranslator, namespace=usedNamespace) if exprtype.containedTypeDesc.desc.refcountable: ptrType = CppTranslator.sharedPtrTypeExtractor.match(ptrType).group(2) cExpr = 'ObjectBctbxListWrapper<{0}>({1}).c_list()'.format(ptrType, cppExpr) @@ -335,10 +300,10 @@ class CppTranslator(object): else: return cExpr elif type(exprtype) is AbsApi.EnumType: - cppEnumName = self.translate_enum_type(exprtype, namespace=usedNamespace) + cppEnumName = exprtype.translate(self.langTranslator, namespace=usedNamespace) return '({0}){1}'.format(cppEnumName, cExpr) elif type(exprtype) is AbsApi.ClassType: - cppReturnType = self.translate_class_type(exprtype, namespace=usedNamespace) + cppReturnType = exprtype.translate(self.langTranslator, namespace=usedNamespace) if exprtype.desc.refcountable: cppReturnType = CppTranslator.sharedPtrTypeExtractor.match(cppReturnType).group(2) @@ -358,7 +323,7 @@ class CppTranslator(object): if type(exprtype.containedTypeDesc) is AbsApi.BaseType and exprtype.containedTypeDesc.name == 'string': return 'StringBctbxListWrapper::bctbxListToCppList({0})'.format(cExpr) elif type(exprtype.containedTypeDesc) is AbsApi.ClassType: - cppReturnType = self.translate_class_type(exprtype.containedTypeDesc, namespace=usedNamespace) + cppReturnType = exprtype.containedTypeDesc.translate(self.langTranslator, namespace=usedNamespace) if exprtype.containedTypeDesc.desc.refcountable: cppReturnType = CppTranslator.sharedPtrTypeExtractor.match(cppReturnType).group(2) return 'ObjectBctbxListWrapper<{0}>::bctbxListToCppList({1})'.format(cppReturnType, cExpr) @@ -370,198 +335,6 @@ class CppTranslator(object): else: return cExpr - def translate_argument(self, arg, **params): - return '{0} {1}'.format(self.translate_type(arg.type, **params), CppTranslator.translate_argument_name(arg.name)) - - def translate_type(self, aType, **params): - if type(aType) is AbsApi.BaseType: - return self.translate_base_type(aType) - elif type(aType) is AbsApi.EnumType: - return self.translate_enum_type(aType, **params) - elif type(aType) is AbsApi.ClassType: - return self.translate_class_type(aType, **params) - elif type(aType) is AbsApi.ListType: - return self.translate_list_type(aType, **params) - else: - CppTranslator.fail(aType) - - def translate_base_type(self, _type): - if _type.name == 'void': - if _type.isref: - return 'void *' - else: - return 'void' - elif _type.name == 'boolean': - res = 'bool' - elif _type.name == 'character': - res = 'char' - elif _type.name == 'size': - res = 'size_t' - elif _type.name == 'time': - res = 'time_t' - elif _type.name == 'integer': - if _type.size is None: - res = 'int' - elif isinstance(_type.size, str): - res = _type.size - else: - res = 'int{0}_t'.format(_type.size) - - elif _type.name == 'floatant': - if _type.size is not None and _type.size == 'double': - res = 'double' - else: - res = 'float' - elif _type.name == 'status': - res = 'linphone::Status' - elif _type.name == 'string': - res = 'std::string' - if type(_type.parent) is AbsApi.Argument: - res += ' &' - elif _type.name == 'string_array': - res = 'std::list' - if type(_type.parent) is AbsApi.Argument: - res += ' &' - else: - raise AbsApi.Error('\'{0}\' is not a base abstract type'.format(_type.name)) - - if _type.isUnsigned: - if _type.name == 'integer' and isinstance(_type.size, int): - res = 'u' + res - else: - res = 'unsigned ' + res - - if _type.isconst: - if _type.name not in ['string', 'string_array'] or type(_type.parent) is AbsApi.Argument: - res = 'const ' + res - - if _type.isref: - res += ' *' - return res - - def translate_enum_type(self, _type, **params): - if _type.name in self.ignore: - raise AbsApi.Error('{0} has been escaped'.format(_type.name)) - - if _type.desc is None: - raise AbsApi.Error('{0} has not been fixed'.format(_type.name)) - - if 'namespace' in params: - nsName = params['namespace'].name if params['namespace'] is not None else None - else: - method = _type.find_first_ancestor_by_type(AbsApi.Method) - nsName = AbsApi.Name.find_common_parent(_type.desc.name, method.name) - - return CppTranslator.translate_enum_name(_type.desc.name, recursive=True, topAncestor=nsName) - - def translate_class_type(self, _type, **params): - if _type.name in self.ignore: - raise AbsApi.Error('{0} has been escaped'.format(_type.name)) - - if _type.desc is None: - raise AbsApi.Error('{0} has not been fixed'.format(_type.name)) - - if 'namespace' in params: - nsName = params['namespace'].name if params['namespace'] is not None else None - else: - method = _type.find_first_ancestor_by_type(AbsApi.Method) - nsName = AbsApi.Name.find_common_parent(_type.desc.name, method.name) - - res = CppTranslator.translate_class_name(_type.desc.name, recursive=True, topAncestor=nsName) - - if _type.desc.refcountable: - if _type.isconst: - res = 'const ' + res - if type(_type.parent) is AbsApi.Argument: - return 'const std::shared_ptr<{0}> &'.format(res) - else: - return 'std::shared_ptr<{0}>'.format(res) - else: - if type(_type.parent) is AbsApi.Argument: - return 'const {0} &'.format(res) - else: - return '{0}'.format(res) - - def translate_list_type(self, _type, **params): - if _type.containedTypeDesc is None: - raise AbsApi.Error('{0} has not been fixed'.format(_type.containedTypeName)) - elif isinstance(_type.containedTypeDesc, AbsApi.BaseType): - res = self.translate_type(_type.containedTypeDesc) - else: - res = self.translate_type(_type.containedTypeDesc, **params) - - if type(_type.parent) is AbsApi.Argument: - return 'const std::list<{0} > &'.format(res) - else: - return 'std::list<{0} >'.format(res) - - @staticmethod - def translate_name(aName, **params): - if type(aName) is AbsApi.ClassName: - return CppTranslator.translate_class_name(aName, **params) - elif type(aName) is AbsApi.InterfaceName: - return CppTranslator.translate_class_name(aName, **params) - elif type(aName) is AbsApi.EnumName: - return CppTranslator.translate_enum_name(aName, **params) - elif type(aName) is AbsApi.EnumValueName: - return CppTranslator.translate_enum_value_name(aName, **params) - elif type(aName) is AbsApi.MethodName: - return CppTranslator.translate_method_name(aName, **params) - elif type(aName) is AbsApi.ArgName: - return CppTranslator.translate_argument_name(aName, **params) - elif type(aName) is AbsApi.NamespaceName: - return CppTranslator.translate_namespace_name(aName, **params) - elif type(aName) is AbsApi.PropertyName: - return CppTranslator.translate_property_name(aName, **params) - else: - CppTranslator.fail(aName) - - @staticmethod - def translate_class_name(name, recursive=False, topAncestor=None): - if name.prev is None or not recursive or name.prev is topAncestor: - return name.to_camel_case() - else: - params = {'recursive': recursive, 'topAncestor': topAncestor} - return CppTranslator.translate_name(name.prev, **params) + '::' + name.to_camel_case() - - @staticmethod - def translate_enum_name(name, recursive=False, topAncestor=None): - params = {'recursive': recursive, 'topAncestor': topAncestor} - return CppTranslator.translate_class_name(name, **params) - - @staticmethod - def translate_enum_value_name(name, recursive=False, topAncestor=None): - params = {'recursive': recursive, 'topAncestor': topAncestor} - return CppTranslator.translate_enum_name(name.prev, **params) + name.to_camel_case() - - @staticmethod - def translate_method_name(name, recursive=False, topAncestor=None): - translatedName = name.to_camel_case(lower=True) - if translatedName == 'new': - translatedName = '_new' - - if name.prev is None or not recursive or name.prev is topAncestor: - return translatedName - else: - params = {'recursive': recursive, 'topAncestor': topAncestor} - return CppTranslator.translate_name(name.prev, **params) + '::' + translatedName - - @staticmethod - def translate_namespace_name(name, recursive=False, topAncestor=None): - if name.prev is None or not recursive or name.prev is topAncestor: - return name.concatenate() - else: - params = {'recursive': recursive, 'topAncestor': topAncestor} - return CppTranslator.translate_namespace_name(name.prev, **params) + '::' + name.concatenate() - - @staticmethod - def translate_argument_name(name): - return name.to_camel_case(lower=True) - - @staticmethod - def translate_property_name(name): - CppTranslator.translate_argument_name(name) - @staticmethod def fail(obj): raise AbsApi.Error('Cannot translate {0} type'.format(type(obj))) @@ -594,7 +367,7 @@ class ClassHeader(object): if include == 'enums': self.includes['internal'].append({'name': include}) else: - className = AbsApi.ClassName() + className = metaname.ClassName() className.from_snake_case(include) self.priorDeclarations.append({'name': className.to_camel_case()}) @@ -682,7 +455,7 @@ class GenWrapper(object): self.parser = AbsApi.CParser(project) self.parser.parse_all() self.translator = CppTranslator() - self.renderer = pystache.Renderer() + self.renderer = pystache.Renderer() self.mainHeader = MainHeader() self.impl = ClassImpl() @@ -743,14 +516,14 @@ def main(): os.makedirs(includedir) except OSError as e: if e.errno != errno.EEXIST: - print("Cannot create '{0}' dircetory: {1}".format(includedir, e.strerror)) + print("Cannot create '{0}' directory: {1}".format(includedir, e.strerror)) sys.exit(1) try: os.makedirs(srcdir) except OSError as e: if e.errno != errno.EEXIST: - print("Cannot create '{0}' dircetory: {1}".format(srcdir, e.strerror)) + print("Cannot create '{0}' directory: {1}".format(srcdir, e.strerror)) sys.exit(1) genwrapper = GenWrapper(includedir, srcdir, args.xmldir) diff --git a/wrappers/csharp/genwrapper.py b/wrappers/csharp/genwrapper.py index f83c68361..a8b9e268b 100644 --- a/wrappers/csharp/genwrapper.py +++ b/wrappers/csharp/genwrapper.py @@ -22,15 +22,17 @@ import sys import pystache sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'tools')) -print(sys.path) import genapixml as CApi import abstractapi as AbsApi import metadoc +import metaname class CsharpTranslator(object): def __init__(self): self.ignore = [] - self.docTranslator = metadoc.SandcastleCSharpTranslator() + self.docTranslator = metadoc.SandCastleTranslator('CSharp') + self.nameTranslator = metaname.Translator.get('CSharp') + self.langTranslator = AbsApi.Translator.get('CSharp') def init_method_dict(self): methodDict = {} @@ -52,114 +54,16 @@ class CsharpTranslator(object): if length > 11 and name[:11] == 'IEnumerable': return name[12:length-1] return None - + def is_generic(self, methodDict): return not methodDict['is_string'] and not methodDict['is_bool'] and not methodDict['is_class'] and not methodDict['is_enum'] and methodDict['list_type'] == None - def translate_method_name(self, name, recursive=False, topAncestor=None): - translatedName = name.to_camel_case(lower=True) - - if name.prev is None or not recursive or name.prev is topAncestor: - return translatedName - - def translate_argument_name(self, name): - argname = name.to_camel_case(lower=True) - arg = argname - if argname == "params": - arg = "parameters" - elif argname == "event": - arg = "ev" - elif argname == "ref": - arg = "reference" - elif argname == "value": - arg = "val" - return arg - - def translate_base_type(self, _type, isArg, dllImport=True): - if _type.name == 'void': - if _type.isref: - return 'IntPtr' - return 'void' - elif _type.name == 'status': - if dllImport: - return 'int' - else: - return 'void' - elif _type.name == 'boolean': - if dllImport: - res = 'int' # In C the bool_t is an integer - else: - res = 'bool' - elif _type.name == 'integer': - if _type.isUnsigned: - res = 'uint' - else: - res = 'int' - elif _type.name == 'string': - if dllImport: - if isArg: - return 'string' - else: - res = 'IntPtr' # Return as IntPtr and get string with Marshal.PtrToStringAnsi() - else: - return 'string' - elif _type.name == 'character': - if _type.isUnsigned: - res = 'byte' - else: - res = 'sbyte' - elif _type.name == 'time': - res = 'long' #TODO check - elif _type.name == 'size': - res = 'long' #TODO check - elif _type.name == 'floatant': - return 'float' - elif _type.name == 'string_array': - if dllImport or isArg: - return 'IntPtr' - else: - return 'IEnumerable' - else: - raise AbsApi.Error('\'{0}\' is not a base abstract type'.format(_type.name)) - - return res - def is_linphone_type(self, _type, isArg, dllImport=True): if type(_type) is AbsApi.ClassType: return False if dllImport else True elif type(_type) is AbsApi.EnumType: return False if dllImport else True - def translate_type(self, _type, isArg, dllImport=True): - if type(_type) is AbsApi.EnumType: - if dllImport and isArg: - return 'int' - return _type.desc.name.to_camel_case() - elif type(_type) is AbsApi.ClassType: - return "IntPtr" if dllImport else _type.desc.name.to_camel_case() - elif type(_type) is AbsApi.BaseType: - return self.translate_base_type(_type, isArg, dllImport) - elif type(_type) is AbsApi.ListType: - if dllImport: - return 'IntPtr' - else: - if type(_type.containedTypeDesc) is AbsApi.BaseType: - if _type.containedTypeDesc.name == 'string': - return 'IEnumerable' - else: - raise AbsApi.Error('translation of bctbx_list_t of basic C types is not supported') - elif type(_type.containedTypeDesc) is AbsApi.ClassType: - ptrType = _type.containedTypeDesc.desc.name.to_camel_case() - return 'IEnumerable<' + ptrType + '>' - else: - if _type.containedTypeDesc: - raise AbsApi.Error('translation of bctbx_list_t of enums') - else: - raise AbsApi.Error('translation of bctbx_list_t of unknow type !') - - def translate_argument(self, arg, dllImport=True): - return '{0} {1}'.format(self.translate_type(arg.type, True, dllImport), self.translate_argument_name(arg.name)) - def throws_exception(self, return_type): if type(return_type) is AbsApi.BaseType: if return_type.name == 'status': @@ -167,31 +71,31 @@ class CsharpTranslator(object): return False def translate_method(self, method, static=False, genImpl=True): - if method.name.to_snake_case(fullName=True) in self.ignore: - raise AbsApi.Error('{0} has been escaped'.format(method.name.to_snake_case(fullName=True))) + if method.name.to_c() in self.ignore: + raise AbsApi.Error('{0} has been escaped'.format(method.name.to_c())) methodElems = {} - methodElems['return'] = self.translate_type(method.returnType, False) + methodElems['return'] = method.returnType.translate(self.langTranslator) methodElems['name'] = method.name.to_c() methodElems['params'] = '' if static else 'IntPtr thiz' for arg in method.args: if arg is not method.args[0] or not static: methodElems['params'] += ', ' - methodElems['params'] += self.translate_argument(arg) + methodElems['params'] += arg.translate(self.langTranslator) methodDict = {} methodDict['prototype'] = "static extern {return} {name}({params});".format(**methodElems) - methodDict['doc'] = self.docTranslator.translate(method.briefDescription) + methodDict['doc'] = method.briefDescription.translate(self.docTranslator, tagAsBrief=True) methodDict['has_impl'] = genImpl if genImpl: methodDict['impl'] = {} methodDict['impl']['static'] = 'static ' if static else '' methodDict['impl']['exception'] = self.throws_exception(method.returnType) - methodDict['impl']['type'] = self.translate_type(method.returnType, False, False) - methodDict['impl']['name'] = method.name.to_camel_case() - methodDict['impl']['override'] = 'override ' if method.name.to_camel_case() == 'ToString' else '' + methodDict['impl']['type'] = method.returnType.translate(self.langTranslator, dllImport=False) + methodDict['impl']['name'] = method.name.translate(self.nameTranslator) + methodDict['impl']['override'] = 'override ' if method.name.translate(self.nameTranslator) == 'ToString' else '' methodDict['impl']['return'] = '' if methodDict['impl']['type'] == "void" else 'return ' methodDict['impl']['c_name'] = method.name.to_c() methodDict['impl']['nativePtr'] = '' if static else ('nativePtr, ' if len(method.args) > 0 else 'nativePtr') @@ -218,21 +122,21 @@ class CsharpTranslator(object): methodDict['impl']['c_args'] += ', ' if self.is_linphone_type(arg.type, False, False): if type(arg.type) is AbsApi.ClassType: - argname = self.translate_argument_name(arg.name) + argname = arg.name.translate(self.nameTranslator) methodDict['impl']['c_args'] += argname + " != null ? " + argname + ".nativePtr : IntPtr.Zero" else: - methodDict['impl']['c_args'] += '(int)' + self.translate_argument_name(arg.name) - elif self.translate_type(arg.type, False, False) == "bool": - methodDict['impl']['c_args'] += self.translate_argument_name(arg.name) + " ? 1 : 0" - elif self.get_class_array_type(self.translate_type(arg.type, False, False)) is not None: - listtype = self.get_class_array_type(self.translate_type(arg.type, False, False)) + methodDict['impl']['c_args'] += '(int)' + arg.name.translate(self.nameTranslator) + elif arg.type.translate(self.langTranslator, dllImport=False) == "bool": + methodDict['impl']['c_args'] += arg.name.translate(self.nameTranslator) + " ? (char)1 : (char)0" + elif self.get_class_array_type(arg.type.translate(self.langTranslator, dllImport=False)) is not None: + listtype = self.get_class_array_type(arg.type.translate(self.langTranslator, dllImport=False)) if listtype == 'string': - methodDict['impl']['c_args'] += "StringArrayToBctbxList(" + self.translate_argument_name(arg.name) + ")" + methodDict['impl']['c_args'] += "StringArrayToBctbxList(" + arg.name.translate(self.nameTranslator) + ")" else: - methodDict['impl']['c_args'] += "ObjectArrayToBctbxList<" + listtype + ">(" + self.translate_argument_name(arg.name) + ")" + methodDict['impl']['c_args'] += "ObjectArrayToBctbxList<" + listtype + ">(" + arg.name.translate(self.nameTranslator) + ")" else: - methodDict['impl']['c_args'] += self.translate_argument_name(arg.name) - methodDict['impl']['args'] += self.translate_argument(arg, False) + methodDict['impl']['c_args'] += arg.name.translate(self.nameTranslator) + methodDict['impl']['args'] += arg.translate(self.langTranslator, dllImport=False) return methodDict @@ -242,7 +146,7 @@ class CsharpTranslator(object): methodDict = self.translate_method(prop, static, False) methodDict['property_static'] = 'static ' if static else '' - methodDict['property_return'] = self.translate_type(prop.returnType, False, False) + methodDict['property_return'] = prop.returnType.translate(self.langTranslator, dllImport=False) methodDict['property_name'] = (name[3:] if len(name) > 3 else 'Instance') if name[:3] == "Get" else name methodDict['has_property'] = True @@ -273,7 +177,7 @@ class CsharpTranslator(object): methodDict = self.translate_method(prop, static, False) methodDict['property_static'] = 'static ' if static else '' - methodDict['property_return'] = self.translate_type(prop.args[0].type, True, False) + methodDict['property_return'] = prop.args[0].type.translate(self.langTranslator, dllImport=False) methodDict['property_name'] = (name[3:] if len(name) > 3 else 'Instance') if name[:3] == "Set" else name methodDict['has_property'] = True @@ -297,7 +201,7 @@ class CsharpTranslator(object): return methodDict def translate_property_getter_setter(self, getter, setter, name, static=False): - methodDict = self.translate_property_getter(getter, name, static) + methodDict = self.translate_property_getter(getter, name, static=static) methodDictSet = self.translate_property_setter(setter, name, static) protoElems = {} @@ -314,7 +218,7 @@ class CsharpTranslator(object): def translate_property(self, prop): res = [] - name = prop.name.to_camel_case() + name = prop.name.translate(self.nameTranslator) if prop.getter is not None: if prop.setter is not None: res.append(self.translate_property_getter_setter(prop.getter, prop.setter, name)) @@ -331,7 +235,7 @@ class CsharpTranslator(object): listenerDict = {} c_name_setter = listenedClass.name.to_snake_case(fullName=True) + '_cbs_set_' + method.name.to_snake_case()[3:] - delegate_name_public = method.name.to_camel_case() + "Delegate" + delegate_name_public = method.name.translate(self.nameTranslator) + "Delegate" delegate_name_private = delegate_name_public + "Private" listenerDict['cb_setter'] = {} listenerDict['cb_setter']['name'] = c_name_setter @@ -345,9 +249,9 @@ class CsharpTranslator(object): listenerDict['delegate']['var_public'] = var_name_public listenerDict['delegate']['var_private'] = var_name_private listenerDict['delegate']['cb_name'] = method.name.to_snake_case() - listenerDict['delegate']['name'] = method.name.to_camel_case() + listenerDict['delegate']['name'] = method.name.translate(self.nameTranslator) - listenerDict['delegate']['interfaceClassName'] = listenedClass.name.to_camel_case() + listenerDict['delegate']['interfaceClassName'] = listenedClass.name.translate(self.nameTranslator) listenerDict['delegate']['isSimpleListener'] = not listenedClass.multilistener listenerDict['delegate']['isMultiListener'] = listenedClass.multilistener @@ -355,10 +259,10 @@ class CsharpTranslator(object): listenerDict['delegate']['params_private'] = "" listenerDict['delegate']['params'] = "" for arg in method.args: - dllImportType = self.translate_type(arg.type, True, True) - normalType = self.translate_type(arg.type, True, False) + dllImportType = arg.type.translate(self.langTranslator, dllImport=True) + normalType = arg.type.translate(self.langTranslator, dllImport=False) - argName = self.translate_argument_name(arg.name) + argName = arg.name.translate(self.nameTranslator) if arg != method.args[0]: listenerDict['delegate']['params_public'] += ', ' listenerDict['delegate']['params_private'] += ', ' @@ -369,9 +273,9 @@ class CsharpTranslator(object): else: if normalType == "bool": listenerDict['delegate']['params'] += argName + " == 0" - elif self.is_linphone_type(arg.type, True, False) and type(arg.type) is AbsApi.ClassType: + elif self.is_linphone_type(arg.type, True, dllImport=False) and type(arg.type) is AbsApi.ClassType: listenerDict['delegate']['params'] += "fromNativePtr<" + normalType + ">(" + argName + ")" - elif self.is_linphone_type(arg.type, True, False) and type(arg.type) is AbsApi.EnumType: + elif self.is_linphone_type(arg.type, True, dllImport=False) and type(arg.type) is AbsApi.EnumType: listenerDict['delegate']['params'] += "(" + normalType + ")" + argName + "" else: raise("Error") @@ -439,15 +343,15 @@ class CsharpTranslator(object): def translate_enum(self, enum): enumDict = {} - enumDict['enumName'] = enum.name.to_camel_case() - enumDict['doc'] = self.docTranslator.translate(enum.briefDescription) + enumDict['enumName'] = enum.name.translate(self.nameTranslator) + enumDict['doc'] = enum.briefDescription.translate(self.docTranslator, tagAsBrief=True) enumDict['values'] = [] i = 0 lastValue = None - for enumValue in enum.values: + for enumValue in enum.enumerators: enumValDict = {} - enumValDict['name'] = enumValue.name.to_camel_case() - enumValDict['doc'] = self.docTranslator.translate(enumValue.briefDescription) + enumValDict['name'] = enumValue.name.translate(self.nameTranslator) + enumValDict['doc'] = enumValue.briefDescription.translate(self.docTranslator, tagAsBrief=True) if type(enumValue.value) is int: lastValue = enumValue.value enumValDict['value'] = str(enumValue.value) @@ -464,21 +368,21 @@ class CsharpTranslator(object): return enumDict def translate_class(self, _class): - if _class.name.to_camel_case(fullName=True) in self.ignore: - raise AbsApi.Error('{0} has been escaped'.format(_class.name.to_camel_case(fullName=True))) + if _class.name.to_c() in self.ignore: + raise AbsApi.Error('{0} has been escaped'.format(_class.name.to_c())) classDict = {} - classDict['className'] = _class.name.to_camel_case() - classDict['isLinphoneFactory'] = _class.name.to_camel_case() == "Factory" + classDict['className'] = _class.name.translate(self.nameTranslator) + classDict['isLinphoneFactory'] = classDict['className'] == "Factory" classDict['isLinphoneCall'] = _class.name.to_camel_case() == "Call" classDict['isLinphoneCore'] = _class.name.to_camel_case() == "Core" - classDict['doc'] = self.docTranslator.translate(_class.briefDescription) + classDict['doc'] = _class.briefDescription.translate(self.docTranslator, tagAsBrief=True) classDict['dllImports'] = [] islistenable = _class.listenerInterface is not None ismonolistenable = (islistenable and not _class.multilistener) if islistenable: - listenerName = _class.listenerInterface.name.to_camel_case() + listenerName = _class.listenerInterface.name.translate(self.nameTranslator) if ismonolistenable: classDict['dllImports'].append(self.generate_getter_for_listener_callbacks(_class, listenerName)) else: @@ -488,7 +392,7 @@ class CsharpTranslator(object): for method in _class.classMethods: try: if 'get' in method.name.to_word_list(): - methodDict = self.translate_property_getter(method, method.name.to_camel_case(), True) + methodDict = self.translate_property_getter(method, method.name.translate(self.nameTranslator), True) #The following doesn't work because there a at least one method that has both getter and setter, #and because it doesn't do both of them at once, property is declared twice #elif 'set' in method.name.to_word_list(): @@ -497,29 +401,29 @@ class CsharpTranslator(object): methodDict = self.translate_method(method, static=True, genImpl=True) classDict['dllImports'].append(methodDict) except AbsApi.Error as e: - print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0])) + print('Could not translate {0}: {1}'.format(method.name.to_c(), e.args[0])) for prop in _class.properties: try: classDict['dllImports'] += self.translate_property(prop) except AbsApi.Error as e: - print('error while translating {0} property: {1}'.format(prop.name.to_snake_case(), e.args[0])) + print('error while translating {0} property: {1}'.format(prop.name.to_c(), e.args[0])) for method in _class.instanceMethods: try: methodDict = self.translate_method(method, static=False, genImpl=True) classDict['dllImports'].append(methodDict) except AbsApi.Error as e: - print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0])) + print('Could not translate {0}: {1}'.format(method.name.to_c(), e.args[0])) return classDict def translate_interface(self, interface): - if interface.name.to_camel_case(fullName=True) in self.ignore: - raise AbsApi.Error('{0} has been escaped'.format(interface.name.to_camel_case(fullName=True))) + if interface.name.to_c() in self.ignore: + raise AbsApi.Error('{0} has been escaped'.format(interface.name.to_c())) interfaceDict = {} - interfaceDict['interfaceName'] = interface.name.to_camel_case() + interfaceDict['interfaceName'] = interface.name.translate(self.nameTranslator) interfaceDict['methods'] = [] for method in interface.methods: interfaceDict['methods'].append(self.translate_listener(interface, method)) @@ -615,7 +519,7 @@ def main(): impl = InterfaceImpl(_class, translator) interfaces.append(impl) except AbsApi.Error as e: - print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) + print('Could not translate {0}: {1}'.format(_class.name.to_c(), e.args[0])) wrapper = WrapperImpl(enums, interfaces, classes) render(renderer, wrapper, args.outputdir + "/" + args.outputfile) diff --git a/wrappers/csharp/wrapper_impl.mustache b/wrappers/csharp/wrapper_impl.mustache index f66c504fe..8837b4475 100644 --- a/wrappers/csharp/wrapper_impl.mustache +++ b/wrappers/csharp/wrapper_impl.mustache @@ -484,7 +484,7 @@ namespace Linphone {{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}} {{/is_string}} {{#is_bool}} - {{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}value ? 1 : 0); + {{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}value ? (char)1 : (char)0); {{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}} {{/is_bool}} {{#is_class}} @@ -525,7 +525,7 @@ namespace Linphone return Marshal.PtrToStringAnsi(stringPtr); {{/is_string}} {{#is_bool}} - {{return}}{{c_name}}({{nativePtr}}{{c_args}}) == 0 ? false : true; + {{return}}{{c_name}}({{nativePtr}}{{c_args}}) == (char)0 ? false : true; {{/is_bool}} {{#is_class}} IntPtr ptr = {{c_name}}({{nativePtr}}{{c_args}}); diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index a86e3995b..1299fa367 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -90,7 +90,7 @@ class JavaTranslator(object): self.jni_package += directory + '_' self.jni_path += directory + '/' - self.docTranslator = metadoc.SandcastleJavaTranslator() + self.docTranslator = metadoc.JavaDocTranslator() def throws_exception(self, _type): if not self.exceptions: @@ -353,7 +353,7 @@ class JavaTranslator(object): methodDict['native_params_impl'] += self.translate_argument_name(arg.name) methodDict['deprecated'] = _method.deprecated - methodDict['doc'] = self.docTranslator.translate(_method.briefDescription) if _method.briefDescription is not None else None + methodDict['doc'] = _method.briefDescription.translate(self.docTranslator) if _method.briefDescription is not None else None return methodDict @@ -449,7 +449,7 @@ class JavaTranslator(object): classDict['isLinphoneFactory'] = _class.name.to_camel_case() == "Factory" classDict['isLinphoneCore'] = _class.name.to_camel_case() == "Core" - classDict['doc'] = self.docTranslator.translate(_class.briefDescription) if _class.briefDescription is not None else None + classDict['doc'] = _class.briefDescription.translate(self.docTranslator) if _class.briefDescription is not None else None for _property in _class.properties: try: @@ -572,7 +572,7 @@ class JavaTranslator(object): 'jniMethods': [], } - interfaceDict['doc'] = self.docTranslator.translate(_class.briefDescription) + interfaceDict['doc'] = _class.briefDescription.translate(self.docTranslator) for method in _class.methods: interfaceDict['methods'].append(self.translate_method(method)) @@ -580,23 +580,23 @@ class JavaTranslator(object): return interfaceDict - def translate_enum(self, _class): + def translate_enum(self, enum): enumDict = { 'jniMethods': [], } - enumDict['name'] = _class.name.to_camel_case() - enumDict['doc'] = self.docTranslator.translate(_class.briefDescription) + enumDict['name'] = enum.name.to_camel_case() + enumDict['doc'] = enum.briefDescription.translate(self.docTranslator) enumDict['values'] = [] i = 0 lastValue = None enumDict['jniPath'] = self.jni_path - for enumValue in _class.values: + for enumValue in enum.enumerators: enumValDict = {} enumValDict['name'] = enumValue.name.to_camel_case() - enumValDict['doc'] = self.docTranslator.translate(enumValue.briefDescription) + enumValDict['doc'] = enumValue.briefDescription.translate(self.docTranslator) if type(enumValue.value) is int: lastValue = enumValue.value enumValDict['value'] = str(enumValue.value) @@ -609,7 +609,7 @@ class JavaTranslator(object): else: enumValDict['value'] = i i += 1 - enumValDict['commarorsemicolon'] = ';' if i == len(_class.values) else ',' + enumValDict['commarorsemicolon'] = ';' if i == len(enum.enumerators) else ',' enumDict['values'].append(enumValDict) return enumDict @@ -805,22 +805,22 @@ class GenWrapper(object): if _enum[1] is not None: self.render_java_enum(_enum[1]) - for name, value in self.enums.iteritems(): + for name, value in self.enums.items(): self.jni.add_enum(value) if name in ENUMS_LIST: className = ENUMS_LIST[name] - print 'Enum ' + name + ' belongs to class ' + className + print('Enum ' + name + ' belongs to class ' + className) self.classes[className].add_enum(value) self.enums_to_remove.append(name) for enum in self.enums_to_remove: self.enums.pop(enum, None) - for name, value in self.enums.iteritems(): + for name, value in self.enums.items(): self.render(value, self.javadir + '/' + value.filename) - for name, value in self.interfaces.iteritems(): + for name, value in self.interfaces.items(): self.render(value, self.javadir + '/' + value.filename) - for name, value in self.classes.iteritems(): + for name, value in self.classes.items(): self.render(value, self.javadir + '/' + value.filename) self.jni.add_object(value) From b12a245ed9d6d791c408af5b74b2c9933b570988 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 16 Nov 2017 18:08:50 +0100 Subject: [PATCH 0790/2215] Add ENABLE_SPHINX_DOC CMake option definition and fix CPP wrapper compilation. --- CMakeLists.txt | 1 + wrappers/cpp/class_impl.mustache | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c964a8f9..2e5888b95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,7 @@ option(ENABLE_DAEMON "Enable the linphone daemon interface." YES) option(ENABLE_DATE "Use build date in internal version number." NO) option(ENABLE_DEBUG_LOGS "Turn on or off debug level logs." NO) option(ENABLE_DOC "Enable documentation generation with Doxygen." YES) +option(ENABLE_SPHINX_DOC "Enable sphinx documentation generation." NO) option(ENABLE_JAVADOC "Add a target to generate documentation for Java API" NO) option(ENABLE_LDAP "Enable LDAP support." NO) option(ENABLE_RELATIVE_PREFIX "Find resources relatively to the installation directory." NO) diff --git a/wrappers/cpp/class_impl.mustache b/wrappers/cpp/class_impl.mustache index 8c3a83e70..ec0c55c07 100644 --- a/wrappers/cpp/class_impl.mustache +++ b/wrappers/cpp/class_impl.mustache @@ -21,7 +21,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include #include -#include #include "linphone++/linphone.hh" #include "tools.hh" From d4d88312ae4427b157b663eab5fcd533233deb63 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 16 Nov 2017 18:09:37 +0100 Subject: [PATCH 0791/2215] Add a callback on the ChatRoom to generate the conference address. --- include/linphone/api/c-callbacks.h | 8 ++++++++ include/linphone/api/c-chat-room-cbs.h | 15 +++++++++++++++ include/linphone/api/c-chat-room.h | 8 ++++++++ src/c-wrapper/api/c-chat-room-cbs.cpp | 9 +++++++++ src/c-wrapper/api/c-chat-room.cpp | 9 +++++++++ src/chat/chat-room/server-group-chat-room-p.h | 2 ++ .../chat-room/server-group-chat-room-stub.cpp | 4 ++++ 7 files changed, 55 insertions(+) diff --git a/include/linphone/api/c-callbacks.h b/include/linphone/api/c-callbacks.h index f31219d14..c8cfc7142 100644 --- a/include/linphone/api/c-callbacks.h +++ b/include/linphone/api/c-callbacks.h @@ -226,6 +226,14 @@ typedef void (*LinphoneChatRoomCbsParticipantDeviceAddedCb) (LinphoneChatRoom *c * @param[in] participant The #LinphoneParticipant that has been removed from the chat room */ typedef void (*LinphoneChatRoomCbsParticipantDeviceRemovedCb) (LinphoneChatRoom *cr, const LinphoneEventLog *event_log); + +/** + * Callback used when a group chat room is created server-side to generate the address of the chat room. + * The function linphone_chat_room_set_conference_address() needs to be called by this callback. + * @param[in] cr #LinphoneChatRoom object + */ +typedef void (*LinphoneChatRoomCbsConferenceAddressGenerationCb) (LinphoneChatRoom *cr); + /** * @} **/ diff --git a/include/linphone/api/c-chat-room-cbs.h b/include/linphone/api/c-chat-room-cbs.h index ae515cc9d..49f5629db 100644 --- a/include/linphone/api/c-chat-room-cbs.h +++ b/include/linphone/api/c-chat-room-cbs.h @@ -228,6 +228,21 @@ LINPHONE_PUBLIC LinphoneChatRoomCbsParticipantDeviceRemovedCb linphone_chat_room * @param[in] cb The participant device removed callback to be used. */ LINPHONE_PUBLIC void linphone_chat_room_cbs_set_participant_device_removed (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantDeviceRemovedCb cb); + +/** + * Get the conference address generation callback. + * @param[in] cbs LinphoneChatRoomCbs object + * @return The current conference address generation callback + */ +LINPHONE_PUBLIC LinphoneChatRoomCbsConferenceAddressGenerationCb linphone_chat_room_cbs_get_conference_address_generation (const LinphoneChatRoomCbs *cbs); + +/** + * Set the conference address generation callback. + * @param[in] cbs LinphoneChatRoomCbs object + * @param[in] cb The conference address generation callback to be used + */ +LINPHONE_PUBLIC void linphone_chat_room_cbs_set_conference_address_generation (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsConferenceAddressGenerationCb cb); + /** * @} */ diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index 14da77ffa..244afe477 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -366,6 +366,14 @@ LINPHONE_PUBLIC void linphone_chat_room_set_subject (LinphoneChatRoom *cr, const */ LINPHONE_PUBLIC bctbx_list_t * linphone_chat_room_get_composing_addresses(LinphoneChatRoom *cr); +/** + * Set the conference address of a group chat room. This function needs to be called from the + * LinphoneChatRoomCbsConferenceAddressGenerationCb callback and only there. + * @param[in] cr A LinphoneChatRoom object + * @param[in] confAddr The conference address to be used by the group chat room + */ +LINPHONE_PUBLIC void linphone_chat_room_set_conference_address (LinphoneChatRoom *cr, const LinphoneAddress *confAddr); + /** * Returns back pointer to #LinphoneCore object. * @deprecated use linphone_chat_room_get_core() diff --git a/src/c-wrapper/api/c-chat-room-cbs.cpp b/src/c-wrapper/api/c-chat-room-cbs.cpp index 9bcb058d7..dc1beebbf 100644 --- a/src/c-wrapper/api/c-chat-room-cbs.cpp +++ b/src/c-wrapper/api/c-chat-room-cbs.cpp @@ -38,6 +38,7 @@ struct _LinphoneChatRoomCbs { LinphoneChatRoomCbsUndecryptableMessageReceivedCb undecryptableMessageReceivedCb; LinphoneChatRoomCbsChatMessageReceivedCb chatMessageReceivedCb; LinphoneChatRoomCbsChatMessageSentCb chatMessageSentCb; + LinphoneChatRoomCbsConferenceAddressGenerationCb conferenceAddressGenerationCb; }; BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneChatRoomCbs); @@ -169,3 +170,11 @@ LinphoneChatRoomCbsParticipantDeviceRemovedCb linphone_chat_room_cbs_get_partici void linphone_chat_room_cbs_set_participant_device_removed (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantDeviceRemovedCb cb) { cbs->participantDeviceRemovedCb = cb; } + +LinphoneChatRoomCbsConferenceAddressGenerationCb linphone_chat_room_cbs_get_conference_address_generation (const LinphoneChatRoomCbs *cbs) { + return cbs->conferenceAddressGenerationCb; +} + +void linphone_chat_room_cbs_set_conference_address_generation (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsConferenceAddressGenerationCb cb) { + cbs->conferenceAddressGenerationCb = cb; +} diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 153d15cc3..e3014b4e4 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -24,6 +24,7 @@ #include "linphone/wrapper_utils.h" #include "c-wrapper/c-wrapper.h" +#include "address/identity-address.h" #include "chat/chat-room/basic-chat-room.h" #include "chat/chat-room/client-group-chat-room.h" #include "chat/chat-room/real-time-text-chat-room-p.h" @@ -309,6 +310,14 @@ LinphoneChatMessage *linphone_chat_room_create_file_transfer_message(LinphoneCha return object; } +void linphone_chat_room_set_conference_address (LinphoneChatRoom *cr, const LinphoneAddress *confAddr) { + char *addrStr = linphone_address_as_string(confAddr); + LinphonePrivate::ServerGroupChatRoomPrivate *sgcr = dynamic_cast(L_GET_PRIVATE_FROM_C_OBJECT(cr)); + if (sgcr) + sgcr->setConferenceAddress(LinphonePrivate::IdentityAddress(addrStr)); + bctbx_free(addrStr); +} + // ============================================================================= // Reference and user data handling functions. // ============================================================================= diff --git a/src/chat/chat-room/server-group-chat-room-p.h b/src/chat/chat-room/server-group-chat-room-p.h index b288e0979..9a8b18c17 100644 --- a/src/chat/chat-room/server-group-chat-room-p.h +++ b/src/chat/chat-room/server-group-chat-room-p.h @@ -49,9 +49,11 @@ public: void dispatchMessage (const Address &fromAddr, const Content &content); void storeOrUpdateMessage (const std::shared_ptr &msg) override; LinphoneReason messageReceived (SalOp *op, const SalMessage *msg) override; + void setConferenceAddress (const IdentityAddress &confAddr); private: void designateAdmin (); + void finalizeCreation (); bool isAdminLeft () const; std::list> removedParticipants; diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index 9356180ec..faace05d4 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -63,10 +63,14 @@ LinphoneReason ServerGroupChatRoomPrivate::messageReceived (SalOp *, const SalMe return LinphoneReasonNone; } +void ServerGroupChatRoomPrivate::setConferenceAddress (const IdentityAddress &confAddr) {} + // ----------------------------------------------------------------------------- void ServerGroupChatRoomPrivate::designateAdmin () {} +void ServerGroupChatRoomPrivate::finalizeCreation () {} + bool ServerGroupChatRoomPrivate::isAdminLeft () const { return false; } From e2013f1aa07b62dfe9349791ab6fbafed3edf3da Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 17 Nov 2017 09:54:24 +0100 Subject: [PATCH 0792/2215] Fix build with some GCC versions. --- src/chat/chat-room/chat-room-id.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/chat/chat-room/chat-room-id.h b/src/chat/chat-room/chat-room-id.h index f0340d871..c78a2b51f 100644 --- a/src/chat/chat-room/chat-room-id.h +++ b/src/chat/chat-room/chat-room-id.h @@ -51,12 +51,14 @@ private: LINPHONE_END_NAMESPACE // Add map key support. -template<> -struct std::hash { - std::size_t operator() (const LinphonePrivate::ChatRoomId &chatRoomId) const { - return hash()(chatRoomId.getPeerAddress().asString()) ^ - (hash()(chatRoomId.getLocalAddress().asString()) << 1); - } -}; +namespace std { + template<> + struct hash { + std::size_t operator() (const LinphonePrivate::ChatRoomId &chatRoomId) const { + return hash()(chatRoomId.getPeerAddress().asString()) ^ + (hash()(chatRoomId.getLocalAddress().asString()) << 1); + } + }; +} #endif // ifndef _CHAT_ROOM_ID_H_ From c50ba6614d81fc3eab55b389782a1d864d6e12d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Fri, 17 Nov 2017 09:33:09 +0100 Subject: [PATCH 0793/2215] Fills the body of Content objects on destruction This commit is a duplicate of bd08e5940c7358a945fff0d0e47678440a1b4ba5 in master --- src/content/content.cpp | 7 +++++++ src/content/content.h | 1 + 2 files changed, 8 insertions(+) diff --git a/src/content/content.cpp b/src/content/content.cpp index e94c0ecee..359d70fb4 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -53,6 +53,13 @@ Content::Content (ContentPrivate &p) : ClonableObject(p) { } +Content::~Content () { + L_D(); + /* Fills the body with zeros before releasing since it may contain + private data like cipher keys or decoded messages. */ + d->body.assign(d->body.size(), 0); +} + Content &Content::operator= (const Content &src) { L_D(); if (this != &src) { diff --git a/src/content/content.h b/src/content/content.h index 4635898bf..d51c51e7e 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -40,6 +40,7 @@ public: Content (); Content (const Content &src); Content (Content &&src); + ~Content (); Content &operator= (const Content &src); Content &operator= (Content &&src); From e127ef09faa3ca1d8f13106497ee3463c1099891 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 17 Nov 2017 10:44:09 +0100 Subject: [PATCH 0794/2215] Send full state NOTIFY of a conference to a specific device. --- .../local-conference-event-handler-p.h | 4 ++- .../local-conference-event-handler.cpp | 27 ++++++++++--------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/conference/local-conference-event-handler-p.h b/src/conference/local-conference-event-handler-p.h index 53c2761eb..16ee8c9f1 100644 --- a/src/conference/local-conference-event-handler-p.h +++ b/src/conference/local-conference-event-handler-p.h @@ -29,10 +29,11 @@ LINPHONE_BEGIN_NAMESPACE class Participant; +class ParticipantDevice; class LocalConferenceEventHandlerPrivate : public ObjectPrivate { public: - void notifyFullState (const std::string ¬ify, const std::shared_ptr &participant); + void notifyFullState (const std::string ¬ify, const std::shared_ptr &device); void notifyAllExcept (const std::string ¬ify, const std::shared_ptr &exceptParticipant); void notifyAll (const std::string ¬ify); std::string createNotifyFullState (int notifyId = -1); @@ -52,6 +53,7 @@ private: std::string createNotify (Xsd::ConferenceInfo::ConferenceType confInfo, int notifyId = -1, bool isFullState = false); void notifyParticipant (const std::string ¬ify, const std::shared_ptr &participant); + void notifyParticipantDevice (const std::string ¬ify, const std::shared_ptr &device); L_DECLARE_PUBLIC(LocalConferenceEventHandler); }; diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/local-conference-event-handler.cpp index c9854e1f4..75f2fd85d 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/local-conference-event-handler.cpp @@ -37,8 +37,8 @@ using namespace Xsd::ConferenceInfo; // ----------------------------------------------------------------------------- -void LocalConferenceEventHandlerPrivate::notifyFullState (const string ¬ify, const shared_ptr &participant) { - notifyParticipant(notify, participant); +void LocalConferenceEventHandlerPrivate::notifyFullState (const string ¬ify, const shared_ptr &device) { + notifyParticipantDevice(notify, device); } void LocalConferenceEventHandlerPrivate::notifyAllExcept (const string ¬ify, const shared_ptr &exceptParticipant) { @@ -54,14 +54,17 @@ void LocalConferenceEventHandlerPrivate::notifyAll (const string ¬ify) { } void LocalConferenceEventHandlerPrivate::notifyParticipant (const string ¬ify, const shared_ptr &participant) { - for (const auto &device : participant->getPrivate()->getDevices()) { - if (device->isSubscribedToConferenceEventPackage()) { - LinphoneEvent *ev = device->getConferenceSubscribeEvent(); - LinphoneContent *content = linphone_core_create_content(ev->lc); - linphone_content_set_buffer(content, (const uint8_t *)notify.c_str(), strlen(notify.c_str())); - linphone_event_notify(ev, content); - linphone_content_unref(content); - } + for (const auto &device : participant->getPrivate()->getDevices()) + notifyParticipantDevice(notify, device); +} + +void LocalConferenceEventHandlerPrivate::notifyParticipantDevice (const string ¬ify, const shared_ptr &device) { + if (device->isSubscribedToConferenceEventPackage()) { + LinphoneEvent *ev = device->getConferenceSubscribeEvent(); + LinphoneContent *content = linphone_core_create_content(ev->lc); + linphone_content_set_buffer(content, (const uint8_t *)notify.c_str(), strlen(notify.c_str())); + linphone_event_notify(ev, content); + linphone_content_unref(content); } } @@ -280,9 +283,9 @@ void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) { if (linphone_event_get_subscription_state(lev) == LinphoneSubscriptionActive) { unsigned int lastNotify = static_cast(Utils::stoi(linphone_event_get_custom_header(lev, "Last-Notify-Version"))); if (lastNotify == 0) { - lInfo() << "Sending initial notify of conference:" << d->conf->getConferenceAddress().asStringUriOnly() << " to: " << participant->getAddress().asString(); + lInfo() << "Sending initial notify of conference:" << d->conf->getConferenceAddress().asStringUriOnly() << " to: " << device->getGruu().asString(); device->setConferenceSubscribeEvent(lev); - d->notifyFullState(d->createNotifyFullState(), participant); + d->notifyFullState(d->createNotifyFullState(), device); } else if (lastNotify < d->lastNotify) { lInfo() << "Sending all missed notify for conference:" << d->conf->getConferenceAddress().asStringUriOnly() << " from: " << lastNotify << " to: " << participant->getAddress().asString(); From b133c5899fa9249652fc6e230808d4a3b7d1088c Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 17 Nov 2017 14:14:04 +0100 Subject: [PATCH 0795/2215] fix tester build on ios --- coreapi/CMakeLists.txt | 2 +- tester/account_creator_tester.c | 1 + tester/audio_bypass_tester.c | 1 + tester/call_multi_tester.c | 1 + tester/call_multicast_tester.c | 1 + tester/call_single_tester.c | 59 ++++++++++--------- tester/call_video_tester.c | 1 + tester/clonable-object-tester.cpp | 1 + tester/complex_sip_case_tester.c | 9 +-- tester/conference-event-tester.cpp | 1 + tester/content-manager-tester.cpp | 3 +- tester/cpim-tester.cpp | 1 + tester/dtmf_tester.c | 1 + tester/eventapi_tester.c | 25 ++++---- tester/flexisip_tester.c | 5 +- tester/liblinphone_tester.c | 3 +- tester/liblinphone_tester.h | 1 - tester/liblinphone_tester_ios.m | 2 +- tester/liblinphone_tester_windows.cpp | 1 + tester/log_collection_tester.c | 1 + tester/main-db-tester.cpp | 1 + tester/message_tester.c | 3 +- tester/multipart-tester.cpp | 1 + tester/offeranswer_tester.c | 5 +- tester/player_tester.c | 1 + tester/presence_server_tester.c | 85 ++++++++++++++------------- tester/presence_tester.c | 27 +++++---- tester/property-container-tester.cpp | 1 + tester/proxy_config_tester.c | 19 +++--- tester/quality_reporting_tester.c | 17 +++--- tester/register_tester.c | 7 ++- tester/remote_provisioning_tester.c | 1 + tester/setup_tester.c | 2 + tester/stun_tester.c | 1 + tester/tester.c | 1 + tester/tunnel_tester.c | 5 +- tester/vcard_tester.c | 32 +++++----- tester/video_tester.c | 1 + 38 files changed, 183 insertions(+), 147 deletions(-) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 3b05f7ca9..f0005fc12 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -229,7 +229,7 @@ if(ENABLE_SHARED) set_target_properties(linphone PROPERTIES FRAMEWORK TRUE MACOSX_FRAMEWORK_IDENTIFIER org.linphone.linphone - MACOSX_FRAMEWORK_INFO_PLIST Info.plist.in + MACOSX_FRAMEWORK_INFO_PLIST Info.plist.in PUBLIC_HEADER "${LINPHONE_HEADER_FILES}" ) endif() diff --git a/tester/account_creator_tester.c b/tester/account_creator_tester.c index 5588ae4c1..3ae77ff98 100644 --- a/tester/account_creator_tester.c +++ b/tester/account_creator_tester.c @@ -17,6 +17,7 @@ */ #include "liblinphone_tester.h" +#include "tester_utils.h" #include static const char XMLRPC_URL[] = "https://sip2.linphone.org:446/xmlrpc.php"; diff --git a/tester/audio_bypass_tester.c b/tester/audio_bypass_tester.c index 98809f1f3..c6d1f7e23 100644 --- a/tester/audio_bypass_tester.c +++ b/tester/audio_bypass_tester.c @@ -17,6 +17,7 @@ */ #include "liblinphone_tester.h" +#include "tester_utils.h" #include "audio_bypass_wav_header.h" // This is a copy of mediastreamer2/src/audiofilters/wav_header.h /********************************************************************** diff --git a/tester/call_multi_tester.c b/tester/call_multi_tester.c index 56581a1e8..bf874805e 100644 --- a/tester/call_multi_tester.c +++ b/tester/call_multi_tester.c @@ -22,6 +22,7 @@ #include "linphone/core.h" #include "linphone/lpconfig.h" #include "liblinphone_tester.h" +#include "tester_utils.h" #include "mediastreamer2/msutils.h" #include "belle-sip/sipstack.h" diff --git a/tester/call_multicast_tester.c b/tester/call_multicast_tester.c index cf1758705..4b21370e8 100644 --- a/tester/call_multicast_tester.c +++ b/tester/call_multicast_tester.c @@ -18,6 +18,7 @@ #include "liblinphone_tester.h" +#include "tester_utils.h" #include "linphone/core.h" #include "belle-sip/belle-sip.h" diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index 7e2d0126a..5e79fdd79 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -22,6 +22,7 @@ #include "linphone/core.h" #include "linphone/lpconfig.h" #include "liblinphone_tester.h" +#include "tester_utils.h" #include "mediastreamer2/msutils.h" #include "belle-sip/sipstack.h" #include @@ -223,7 +224,7 @@ void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreMana } wait_for_until(caller->lc,callee->lc,NULL,0,20); /*just to sleep while iterating*/ }while (!liblinphone_tester_clock_elapsed(&ts,max_time_to_wait)); - + reset_call_stats(audio_stats1, linphone_call_get_audio_stats(c1)); reset_call_stats(video_stats1, linphone_call_get_video_stats(c1)); reset_call_stats(audio_stats2, linphone_call_get_audio_stats(c2)); @@ -262,12 +263,12 @@ void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreMana } } - + if (audio_stats1) linphone_call_stats_unref(audio_stats1); if (audio_stats2) linphone_call_stats_unref(audio_stats2); if (video_stats1) linphone_call_stats_unref(video_stats1); if (video_stats2) linphone_call_stats_unref(video_stats2); - + linphone_call_unref(c1); linphone_call_unref(c2); } @@ -1136,20 +1137,20 @@ static void cancel_other_device_after_accept(void) { BC_ASSERT_TRUE(wait_for(caller_mgr->lc, callee_mgr->lc, &caller_mgr->stat.number_of_LinphoneCallOutgoingProgress, 1)); call_callee = linphone_core_get_current_call(callee_mgr->lc); if (BC_ASSERT_PTR_NOT_NULL(call_callee)) { - + linphone_call_ref(call_callee); - + BC_ASSERT_TRUE(wait_for(caller_mgr->lc, callee_mgr_2->lc, &callee_mgr_2->stat.number_of_LinphoneCallIncomingReceived, 1)); call_callee_2 = linphone_core_get_current_call(callee_mgr_2->lc); linphone_call_ref(call_callee_2); BC_ASSERT_PTR_NOT_NULL(call_callee_2); - + BC_ASSERT_EQUAL( linphone_call_accept(call_callee), 0 , int, "%d"); BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallConnected,1)); BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr->lc, &caller_mgr->stat.number_of_LinphoneCallStreamsRunning, 1)); BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr_2->lc,&callee_mgr_2->stat.number_of_LinphoneCallEnd,1)); BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr_2->lc,&callee_mgr_2->stat.number_of_LinphoneCallReleased,1)); - + rei = linphone_call_get_error_info(call_callee_2); BC_ASSERT_PTR_NOT_NULL(rei); if (rei){ @@ -1189,12 +1190,12 @@ static void cancel_other_device_after_decline(void) { call_callee = linphone_core_get_current_call(callee_mgr->lc); if (BC_ASSERT_PTR_NOT_NULL(call_callee)) { linphone_call_ref(call_callee); - + BC_ASSERT_TRUE(wait_for(caller_mgr->lc, callee_mgr_2->lc, &callee_mgr_2->stat.number_of_LinphoneCallIncomingReceived, 1)); call_callee_2 = linphone_core_get_current_call(callee_mgr_2->lc); linphone_call_ref(call_callee_2); BC_ASSERT_PTR_NOT_NULL(call_callee_2); - + BC_ASSERT_EQUAL(linphone_call_decline(call_callee, LinphoneReasonDeclined), 0 , int, "%d"); BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr->lc, &caller_mgr->stat.number_of_LinphoneCallEnd,1)); BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr->lc, &caller_mgr->stat.number_of_LinphoneCallReleased, 1)); @@ -1202,7 +1203,7 @@ static void cancel_other_device_after_decline(void) { BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr->lc, &callee_mgr->stat.number_of_LinphoneCallReleased, 1)); BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr_2->lc, &callee_mgr_2->stat.number_of_LinphoneCallEnd,1)); BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr_2->lc, &callee_mgr_2->stat.number_of_LinphoneCallReleased,1)); - + rei = linphone_call_get_error_info(call_callee_2); BC_ASSERT_PTR_NOT_NULL(rei); if (rei){ @@ -1324,11 +1325,11 @@ static void cancelled_ringing_call(void) { LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); const bctbx_list_t * call_history; LinphoneCall* out_call; - + char * db_path= bctbx_strdup_printf("%s,%s",bc_tester_get_writable_dir_prefix(),"tmp_call_log.db"); linphone_core_set_call_logs_database_path(marie->lc,db_path); - - + + out_call = linphone_core_invite_address(pauline->lc,marie->identity); linphone_call_ref(out_call); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); @@ -1338,12 +1339,12 @@ static void cancelled_ringing_call(void) { BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1)); BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallEnd,1, int, "%d"); BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1, int, "%d"); - + call_history = linphone_core_get_call_history(marie->lc); BC_ASSERT_PTR_NOT_NULL(call_history); BC_ASSERT_EQUAL((int)bctbx_list_size(call_history),1, int,"%i"); BC_ASSERT_EQUAL(linphone_call_log_get_status((LinphoneCallLog*)bctbx_list_get_data(call_history)), LinphoneCallMissed, LinphoneCallStatus, "%i"); - + linphone_call_unref(out_call); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -1717,7 +1718,7 @@ static void on_ack_processing(LinphoneCall *call, LinphoneHeaders *ack, bool_t i static void call_created(LinphoneCore *lc, LinphoneCall *call){ LinphoneCallCbs *cbs = linphone_factory_create_call_cbs(linphone_factory_get()); linphone_call_cbs_set_ack_processing(cbs, on_ack_processing); - linphone_call_add_callbacks(call, cbs); + linphone_call_add_callbacks(call, cbs); linphone_call_cbs_unref(cbs); } @@ -1736,7 +1737,7 @@ static void call_with_custom_headers(void) { char* tmp=linphone_address_as_string_uri_only(marie->identity); char tmp2[256]; LinphoneCoreCbs *core_cbs = linphone_factory_create_core_cbs(linphone_factory_get()); - + snprintf(tmp2,sizeof(tmp2),"%s?uriHeader=myUriHeader",tmp); marie_identity=linphone_address_new(tmp2); ms_free(tmp); @@ -1746,7 +1747,7 @@ static void call_with_custom_headers(void) { params=linphone_core_create_call_params(marie->lc, NULL); linphone_call_params_add_custom_header(params,"Weather","bad"); linphone_call_params_add_custom_header(params,"Working","yes"); - + linphone_core_cbs_set_call_created(core_cbs, call_created); linphone_core_add_callbacks(marie->lc, core_cbs); linphone_core_add_callbacks(pauline->lc, core_cbs); @@ -1781,11 +1782,11 @@ static void call_with_custom_headers(void) { BC_ASSERT_PTR_NOT_NULL(marie_remote_contact_header); BC_ASSERT_STRING_EQUAL(pauline_remote_contact,pauline_remote_contact_header); BC_ASSERT_STRING_EQUAL(marie_remote_contact,marie_remote_contact_header); - - + + /*we need to wait for the ack to arrive*/ wait_for_until(marie->lc, pauline->lc, NULL, 0, 3000); - + BC_ASSERT_TRUE(linphone_call_get_user_data(call_marie) == (void*)1); BC_ASSERT_TRUE(linphone_call_get_user_data(call_pauline) == (void*)1); @@ -6228,18 +6229,18 @@ static void simple_call_with_gruu(void) { linphone_core_manager_init(pauline, "pauline_tcp_rc", NULL); linphone_core_add_supported_tag(pauline->lc,"gruu"); linphone_core_manager_start(pauline,TRUE); - + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneRegistrationOk, 1)); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneRegistrationOk, 1)); pauline_cfg = linphone_core_get_default_proxy_config(pauline->lc); pauline_addr = linphone_proxy_config_get_contact(pauline_cfg); - + BC_ASSERT_PTR_NOT_NULL(pauline_addr); BC_ASSERT_TRUE(linphone_address_has_uri_param(pauline_addr,"gr")); BC_ASSERT_STRING_EQUAL(linphone_address_get_domain(pauline_addr),"sip.example.org"); - + marie_call = linphone_core_invite_address(marie->lc, pauline_addr); BC_ASSERT_PTR_NOT_NULL(marie_call); if(!marie_call) goto end; @@ -6247,7 +6248,7 @@ static void simple_call_with_gruu(void) { pauline_call = linphone_core_get_current_call(pauline->lc); BC_ASSERT_PTR_NOT_NULL(pauline_call); if(!pauline_call) goto end; - + marie_addr = linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(marie->lc)); BC_ASSERT_TRUE(linphone_address_has_uri_param(marie_addr,"gr")); BC_ASSERT_STRING_EQUAL(linphone_address_get_domain(marie_addr),"sip.example.org"); @@ -6260,12 +6261,12 @@ static void simple_call_with_gruu(void) { ms_free(result); } linphone_address_unref(contact_addr); - + linphone_call_accept(pauline_call); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1)); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1)); - + contact_addr = linphone_address_new(linphone_call_get_remote_contact(marie_call)); if (!BC_ASSERT_TRUE(linphone_address_equal(contact_addr, pauline_addr))) { char* expected = linphone_address_as_string(pauline_addr); @@ -6275,10 +6276,10 @@ static void simple_call_with_gruu(void) { ms_free(result); } linphone_address_unref(contact_addr); - + liblinphone_tester_check_rtcp(marie,pauline); end_call(marie,pauline); - + //BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1)); //BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); diff --git a/tester/call_video_tester.c b/tester/call_video_tester.c index 1f3872d05..d12308e70 100644 --- a/tester/call_video_tester.c +++ b/tester/call_video_tester.c @@ -18,6 +18,7 @@ #include "linphone/core.h" #include "liblinphone_tester.h" +#include "tester_utils.h" #ifdef VIDEO_ENABLED static void call_paused_resumed_with_video_base_call_cb(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message) { diff --git a/tester/clonable-object-tester.cpp b/tester/clonable-object-tester.cpp index 28264732d..c23cd55c1 100644 --- a/tester/clonable-object-tester.cpp +++ b/tester/clonable-object-tester.cpp @@ -20,6 +20,7 @@ #include "object/clonable-object.h" #include "liblinphone_tester.h" +#include "tester_utils.h" // ============================================================================= diff --git a/tester/complex_sip_case_tester.c b/tester/complex_sip_case_tester.c index eacf21aba..e347bd766 100644 --- a/tester/complex_sip_case_tester.c +++ b/tester/complex_sip_case_tester.c @@ -20,6 +20,7 @@ #include "linphone/core.h" #include "liblinphone_tester.h" #include "linphone/lpconfig.h" +#include "tester_utils.h" #if HAVE_SIPP @@ -99,16 +100,16 @@ LinphoneAddress * linphone_core_manager_resolve(LinphoneCoreManager *mgr, const int err; int port = linphone_address_get_port(source); LinphoneAddress * dest; - + sal_resolve_a(linphone_core_get_sal(mgr->lc) ,linphone_address_get_domain(source) ,linphone_address_get_port(source) ,AF_INET ,dest_server_server_resolved ,&addrinfo); - + dest=linphone_address_new(NULL); - + wait_for(mgr->lc, mgr->lc, (int*)&addrinfo, 1); err=bctbx_getnameinfo((struct sockaddr*)addrinfo->ai_addr,addrinfo->ai_addrlen,ipstring,INET6_ADDRSTRLEN,NULL,0,NI_NUMERICHOST); if (err !=0 ){ @@ -117,7 +118,7 @@ LinphoneAddress * linphone_core_manager_resolve(LinphoneCoreManager *mgr, const linphone_address_set_domain(dest, ipstring); if (port > 0) linphone_address_set_port(dest, port); - + return dest; } diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index 9152e1dac..db70d0896 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -28,6 +28,7 @@ #include "liblinphone_tester.h" #include "linphone/core.h" #include "private.h" +#include "tester_utils.h" #include "tools/private-access.h" #include "tools/tester.h" diff --git a/tester/content-manager-tester.cpp b/tester/content-manager-tester.cpp index db5fc375a..3ce12ac04 100644 --- a/tester/content-manager-tester.cpp +++ b/tester/content-manager-tester.cpp @@ -21,6 +21,7 @@ #include "content/content-manager.h" #include "content/content-type.h" #include "liblinphone_tester.h" +#include "tester_utils.h" using namespace LinphonePrivate; using namespace std; @@ -161,7 +162,7 @@ static const char* part4 = \ void multipart_to_list () { LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); ContentManager manager(marie->lc); - + Content multipartContent = Content(); multipartContent.setBody(multipart); multipartContent.setContentType(ContentType("multipart", "related")); diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index 5619f5336..4653bc7f4 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -28,6 +28,7 @@ #include "private.h" #include "liblinphone_tester.h" +#include "tester_utils.h" // ============================================================================= diff --git a/tester/dtmf_tester.c b/tester/dtmf_tester.c index 58723d9b9..6fdb7bdc3 100644 --- a/tester/dtmf_tester.c +++ b/tester/dtmf_tester.c @@ -17,6 +17,7 @@ */ #include "liblinphone_tester.h" +#include "tester_utils.h" void dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf) { stats* counters = get_stats(lc); diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index 8d3e7d600..2119f3500 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -22,6 +22,7 @@ #include "linphone/lpconfig.h" #include #include "liblinphone_tester.h" +#include "tester_utils.h" static const char *subscribe_content="blabla"; static const char *notify_content="blabla"; @@ -342,7 +343,7 @@ static void subscribe_loosing_dialog(void) { BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingProgress,1,1000)); BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,3000)); - + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,5000)); BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionActive,1,5000)); @@ -357,7 +358,7 @@ static void subscribe_loosing_dialog(void) { linphone_core_manager_destroy(pauline); pauline = linphone_core_manager_new( "pauline_tcp_rc"); lcs = bctbx_list_append(lcs, pauline->lc); - + /* Marie will retry the subscription. * She will first receive a 503 Service unavailable from flexisip thanks the ICMP error returned by the no longer existing Pauline. * Then she will forge a new SUBSCRIBE in order to restart a new dialog, and this one will reach the new Pauline.*/ @@ -367,10 +368,10 @@ static void subscribe_loosing_dialog(void) { BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionActive,1,5000)); BC_ASSERT_PTR_NOT_NULL(pauline->lev); if (pauline->lev) BC_ASSERT_EQUAL(linphone_event_get_subscription_state(pauline->lev), LinphoneSubscriptionActive, int, "%d"); - + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,2,5000)); linphone_event_terminate(lev); - + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionTerminated,1,5000)); BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,5000)); @@ -405,7 +406,7 @@ static void subscribe_with_io_error(void) { BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingProgress,1,1000)); BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,3000)); - + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,5000)); BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionActive,1,5000)); @@ -414,18 +415,18 @@ static void subscribe_with_io_error(void) { /* now marie gets network errors when refreshing*/ sal_set_send_error(linphone_core_get_sal(marie->lc), -1); - + /*marie will retry the subscription*/ BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingProgress,2,8000)); sal_set_send_error(linphone_core_get_sal(marie->lc), 0); - + /*and get it accepted again*/ BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,2,10000)); BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionActive,2,5000)); BC_ASSERT_EQUAL(linphone_event_get_subscription_state(pauline->lev), LinphoneSubscriptionActive, int, "%d"); BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,2,5000)); linphone_event_terminate(lev); - + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionTerminated,1,5000)); BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,5000)); @@ -459,7 +460,7 @@ static void subscribe_not_timely_responded(void) { BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingProgress,1,1000)); BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,3000)); - + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,5000)); BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionActive,1,5000)); @@ -470,7 +471,7 @@ static void subscribe_not_timely_responded(void) { lcs = bctbx_list_remove(lcs, pauline->lc); /*marie's dialog will expire while the SUBSCRIBE refresh is in progress*/ wait_for_list(lcs, NULL, 0, 8000); - + lcs = bctbx_list_append(lcs, pauline->lc); wait_for_list(lcs, NULL, 0, 3000); linphone_event_terminate(lev); @@ -503,7 +504,7 @@ static void publish_test_with_args(bool_t refresh, int expires){ linphone_event_add_custom_header(lev,"CustomHeader","someValue"); linphone_event_ref(lev); linphone_event_send_publish(lev,content); - + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishProgress,1,1000)); BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishOk,1,3000)); @@ -557,7 +558,7 @@ static void out_of_dialog_notify(void){ linphone_event_ref(lev); linphone_event_add_custom_header(lev,"CustomHeader","someValue"); linphone_event_notify(lev,content); - + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,1,3000)); BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionTerminated,1,3000)); diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c index 1eca49e28..8443d2ee6 100644 --- a/tester/flexisip_tester.c +++ b/tester/flexisip_tester.c @@ -20,6 +20,7 @@ #include "linphone/core.h" #include "linphone/lpconfig.h" #include "liblinphone_tester.h" +#include "tester_utils.h" static void setPublish(LinphoneProxyConfig * proxy_config, bool_t enable) { linphone_proxy_config_edit(proxy_config); @@ -1208,11 +1209,11 @@ static void redis_publish_subscribe(void) { linphone_call_accept(linphone_core_get_current_call(marie2->lc)); BC_ASSERT_TRUE(wait_for_until(marie2->lc, pauline->lc, &marie2->stat.number_of_LinphoneCallStreamsRunning, 1, 3000)); BC_ASSERT_TRUE(wait_for_until(marie2->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1, 3000)); - + liblinphone_tester_check_rtcp(marie2, pauline); linphone_call_terminate(linphone_core_get_current_call(marie2->lc)); - + BC_ASSERT_TRUE(wait_for_until(marie2->lc, pauline->lc, &marie2->stat.number_of_LinphoneCallEnd, 1, 3000)); BC_ASSERT_TRUE(wait_for_until(marie2->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1, 3000)); diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 67c17d71f..aed90912b 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -19,6 +19,7 @@ #include "linphone/core.h" #include "liblinphone_tester.h" +#include "tester_utils.h" #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) #pragma GCC diagnostic push @@ -193,7 +194,7 @@ int liblinphone_tester_set_log_file(const char *filename) { return -1; } ms_message("Redirecting traces to file [%s]", filename); - linphone_core_set_log_file(log_file); + linphone_core_set_log_file(log_file); return 0; } diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 11a7a712c..4c9ed780c 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -25,7 +25,6 @@ #include #include "linphone/core.h" #include -#include "tester_utils.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/tester/liblinphone_tester_ios.m b/tester/liblinphone_tester_ios.m index 6f3e54495..36dfd5237 100644 --- a/tester/liblinphone_tester_ios.m +++ b/tester/liblinphone_tester_ios.m @@ -25,6 +25,7 @@ #include #include #include "liblinphone_tester.h" +#include "tester_utils.h" int g_argc; char** g_argv; @@ -64,5 +65,4 @@ int main(int argc, char * argv[]) { return 0; } - #endif // target IPHONE diff --git a/tester/liblinphone_tester_windows.cpp b/tester/liblinphone_tester_windows.cpp index 03ae5912a..ebb814d2c 100644 --- a/tester/liblinphone_tester_windows.cpp +++ b/tester/liblinphone_tester_windows.cpp @@ -1,6 +1,7 @@ #include #include "liblinphone_tester_windows.h" +#include "tester_utils.h" using namespace BelledonneCommunications::Linphone::Tester; using namespace Platform; diff --git a/tester/log_collection_tester.c b/tester/log_collection_tester.c index 15c9f6256..6027e7d13 100644 --- a/tester/log_collection_tester.c +++ b/tester/log_collection_tester.c @@ -22,6 +22,7 @@ #include #include "linphone/core.h" #include "liblinphone_tester.h" +#include "tester_utils.h" #ifdef HAVE_ZLIB #include diff --git a/tester/main-db-tester.cpp b/tester/main-db-tester.cpp index 365e63095..681c94303 100644 --- a/tester/main-db-tester.cpp +++ b/tester/main-db-tester.cpp @@ -24,6 +24,7 @@ #include "private.h" #include "liblinphone_tester.h" +#include "tester_utils.h" // ============================================================================= diff --git a/tester/message_tester.c b/tester/message_tester.c index b97a28cb0..f9754608a 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -20,6 +20,7 @@ #include "linphone/core.h" #include "liblinphone_tester.h" +#include "tester_utils.h" #include "lime.h" #include "bctoolbox/crypto.h" #include @@ -2336,7 +2337,7 @@ void file_and_text_message(void) { BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text_content(msg), "Text message"); linphone_chat_room_send_chat_message(chat_room, msg); - + BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageReceived, 1, 60000)); if (marie->stat.last_received_chat_message) { diff --git a/tester/multipart-tester.cpp b/tester/multipart-tester.cpp index dea0166f1..9f1c628e5 100644 --- a/tester/multipart-tester.cpp +++ b/tester/multipart-tester.cpp @@ -28,6 +28,7 @@ #include "private.h" #include "liblinphone_tester.h" +#include "tester_utils.h" // ============================================================================= diff --git a/tester/offeranswer_tester.c b/tester/offeranswer_tester.c index 4d1c9f720..ab1a860ba 100644 --- a/tester/offeranswer_tester.c +++ b/tester/offeranswer_tester.c @@ -21,6 +21,7 @@ #include "linphone/core.h" #include "linphone/lpconfig.h" #include "liblinphone_tester.h" +#include "tester_utils.h" static int get_codec_position(const MSList *l, const char *mime_type, int rate){ const MSList *elem; @@ -446,7 +447,7 @@ static void compatible_avpf_features(void) { bool_t call_ok; if (configure_core_for_avpf_and_video(marie->lc) == NULL) goto end; - + pt = configure_core_for_avpf_and_video(pauline->lc); BC_ASSERT_TRUE((call_ok=call(marie, pauline))); @@ -470,7 +471,7 @@ static void incompatible_avpf_features(void) { bool_t call_ok; if (configure_core_for_avpf_and_video(marie->lc) == NULL) goto end; - + pt = configure_core_for_avpf_and_video(pauline->lc); pt->avpf.features = PAYLOAD_TYPE_AVPF_NONE; diff --git a/tester/player_tester.c b/tester/player_tester.c index 533ceec09..f4171f6fc 100644 --- a/tester/player_tester.c +++ b/tester/player_tester.c @@ -17,6 +17,7 @@ */ #include "liblinphone_tester.h" +#include "tester_utils.h" #include static bool_t wait_for_eof(bool_t *eof, int *time,int time_refresh, int timeout) { diff --git a/tester/presence_server_tester.c b/tester/presence_server_tester.c index 50e0955c7..7c4639687 100644 --- a/tester/presence_server_tester.c +++ b/tester/presence_server_tester.c @@ -19,6 +19,7 @@ #include "linphone/core.h" #include "liblinphone_tester.h" +#include "tester_utils.h" #include "linphone/core_utils.h" static void enable_publish(LinphoneCoreManager *mgr, bool_t enable) { @@ -49,7 +50,7 @@ static void simple(void) { LinphoneFriend* f = linphone_core_create_friend_with_address(marie->lc, get_identity(pauline)); LinphonePresenceActivity *activity = NULL; LinphoneCoreCbs *callbacks = linphone_factory_create_core_cbs(linphone_factory_get()); - + linphone_core_cbs_set_publish_state_changed(callbacks, linphone_publish_state_changed); _linphone_core_add_callbacks(pauline->lc, callbacks, TRUE); linphone_core_cbs_unref(callbacks); @@ -74,7 +75,7 @@ static void simple(void) { } BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphonePublishOk,2)); - + linphone_friend_invalidate_subscription(f); linphone_friend_enable_subscribes(f, FALSE); wait_for_until(marie->lc, NULL, NULL, 0, 5000); @@ -85,7 +86,7 @@ static void simple(void) { linphone_core_manager_stop(marie); linphone_core_manager_destroy(marie); - + linphone_core_manager_stop(pauline); BC_ASSERT_EQUAL(pauline->stat.number_of_LinphonePublishCleared,1,int,"%i"); BC_ASSERT_EQUAL(pauline->stat.number_of_LinphonePublishOk,2,int,"%i"); @@ -766,7 +767,7 @@ static void presence_list_subscribe_network_changes(void) { BC_ASSERT_FALSE(linphone_friend_is_presence_received(lf)); BC_ASSERT_TRUE(wait_for_until(laure->lc, pauline->lc, &laure->stat.number_of_LinphonePresenceActivityVacation, 2, 6000)); - + // Simulate network changes linphone_core_set_network_reachable(laure->lc,FALSE); ms_sleep(1); @@ -860,14 +861,14 @@ static void long_term_presence_phone_alias2(void) { static void long_term_presence_list(void) { if (linphone_core_vcard_supported()){ - + LinphoneFriend *f1, *f2; LinphoneFriendList* friends; const LinphonePresenceModel *presence; const char *e164_phone_number = "+33" "123456789"; const char *nationnal_phone_number = "0123456789"; LinphoneProxyConfig * pauline_proxy_config; - + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); linphone_core_set_user_agent(pauline->lc, "bypass", NULL); enable_publish(pauline, FALSE); @@ -891,9 +892,9 @@ static void long_term_presence_list(void) { f1 = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(pauline->lc), "sip:liblinphone_tester@sip.example.org"); BC_ASSERT_EQUAL(linphone_presence_model_get_basic_status(linphone_friend_get_presence_model(f1)), LinphonePresenceBasicStatusOpen, int, "%d"); - + presence = linphone_friend_get_presence_model_for_uri_or_tel(f1, e164_phone_number); - + if (BC_ASSERT_PTR_NOT_NULL(presence)) { BC_ASSERT_STRING_EQUAL(linphone_presence_model_get_contact(presence), "sip:liblinphone_tester@sip.example.org"); } @@ -905,9 +906,9 @@ static void long_term_presence_list(void) { linphone_proxy_config_set_dial_prefix(pauline_proxy_config, "33"); linphone_proxy_config_done(pauline_proxy_config); presence = linphone_friend_get_presence_model_for_uri_or_tel(f1, nationnal_phone_number); - + BC_ASSERT_PTR_NOT_NULL(presence); - + f2 = linphone_friend_list_find_friend_by_uri(linphone_core_get_default_friend_list(pauline->lc), "sip:random_unknown@sip.example.org"); BC_ASSERT_EQUAL(linphone_presence_model_get_basic_status(linphone_friend_get_presence_model(f2)), LinphonePresenceBasicStatusClosed, int, "%d"); BC_ASSERT_FALSE(linphone_friend_is_presence_received(f2)); @@ -968,36 +969,36 @@ static void long_term_presence_with_phone_without_sip(void) { char *presence_contact; LinphoneCoreManager *marie = NULL; char * identity=NULL; - + while ((dialPlan = linphone_dial_plan_by_ccc_as_int(bctbx_random()%900)) == linphone_dial_plan_by_ccc(NULL)); /*now with have a dialplan*/ for (i = 0; i < MIN((size_t)linphone_dial_plan_get_national_number_length(dialPlan),sizeof(phone)-1); i++) { phone[i] = '0' + rand() % 10; } phone[i]='\0'; - + e164=ms_strdup_printf("+%s%s",linphone_dial_plan_get_country_calling_code(dialPlan),phone); - + ms_message("Phone number is %s, e164 is %s", phone, e164); - + marie = linphone_core_manager_new3("marie_rc", TRUE, e164); linphone_core_set_user_agent(marie->lc, "bypass", NULL); identity = linphone_address_as_string_uri_only(marie->identity); - + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); linphone_core_set_user_agent(pauline->lc, "full-presence-support-bypass", NULL); - + friend2=linphone_core_create_friend(pauline->lc); linphone_friend_add_phone_number(friend2, phone); linphone_core_add_friend(pauline->lc,friend2); - + linphone_friend_list_set_rls_uri(linphone_core_get_default_friend_list(pauline->lc), "sip:rls@sip.example.org"); linphone_friend_list_enable_subscriptions(linphone_core_get_default_friend_list(pauline->lc), TRUE); linphone_core_refresh_registers(pauline->lc); - + /*because phone is not normalized*/ BC_ASSERT_FALSE(wait_for_until(pauline->lc,NULL,&pauline->stat.number_of_LinphonePresenceActivityAway,1,2000)); - + /*know adding ccc to proxy config*/ proxy_config = linphone_core_get_default_proxy_config(pauline->lc); linphone_proxy_config_edit(proxy_config); @@ -1005,11 +1006,11 @@ static void long_term_presence_with_phone_without_sip(void) { linphone_proxy_config_done(proxy_config); /*re-create sub list*/ linphone_friend_list_enable_subscriptions(linphone_core_get_default_friend_list(pauline->lc), FALSE); - + wait_for_until(pauline->lc, NULL, NULL, 0,2000); /*wait for unsubscribe*/ linphone_friend_list_enable_subscriptions(linphone_core_get_default_friend_list(pauline->lc), TRUE); - + BC_ASSERT_TRUE(wait_for(pauline->lc,NULL,&pauline->stat.number_of_LinphonePresenceActivityAway,1)); BC_ASSERT_EQUAL(pauline->stat.number_of_LinphonePresenceActivityAway, 1, int, "%d"); BC_ASSERT_EQUAL(linphone_presence_model_get_basic_status(linphone_friend_get_presence_model(friend2)), LinphonePresenceBasicStatusOpen, int, "%d"); @@ -1036,7 +1037,7 @@ static char * generate_random_e164_phone_from_dial_plan(const LinphoneDialPlan * phone[i] = '0' + rand() % 10; } phone[i]='\0'; - + return ms_strdup_printf("+%s%s",linphone_dial_plan_get_country_calling_code(dialPlan),phone); } /* use case: @@ -1051,14 +1052,14 @@ static void long_term_presence_with_crossed_references(void) { const LinphoneDialPlan *dialPlan; char *e164_marie, *e164_pauline, *e164_laure; LinphoneFriend* friend2; - - + + while ((dialPlan = linphone_dial_plan_by_ccc_as_int(bctbx_random()%900)) == linphone_dial_plan_by_ccc(NULL)); - + ms_message("Marie's phone number is %s", e164_marie=generate_random_e164_phone_from_dial_plan(dialPlan)); ms_message("Pauline's phone number is %s", e164_pauline=generate_random_e164_phone_from_dial_plan(dialPlan)); ms_message("Laure's phone number is %s", e164_laure=generate_random_e164_phone_from_dial_plan(dialPlan)); - + /*pauline has marie as friend*/ LinphoneCoreManager *pauline = linphone_core_manager_new3("pauline_tcp_rc",TRUE,e164_pauline); linphone_core_set_user_agent(pauline->lc, "full-presence-support-bypass", NULL); @@ -1069,7 +1070,7 @@ static void long_term_presence_with_crossed_references(void) { linphone_friend_list_set_rls_uri(linphone_core_get_default_friend_list(pauline->lc), "sip:rls@sip.example.org"); linphone_friend_list_enable_subscriptions(linphone_core_get_default_friend_list(pauline->lc), TRUE); linphone_core_refresh_registers(pauline->lc); - + //Laure has marie as friend LinphoneCoreManager *laure = linphone_core_manager_new3("laure_tcp_rc",TRUE,e164_laure); linphone_core_set_user_agent(laure->lc, "full-presence-support-bypass", NULL); @@ -1080,11 +1081,11 @@ static void long_term_presence_with_crossed_references(void) { linphone_friend_list_set_rls_uri(linphone_core_get_default_friend_list(laure->lc), "sip:rls@sip.example.org"); linphone_friend_list_enable_subscriptions(linphone_core_get_default_friend_list(laure->lc), TRUE); linphone_core_refresh_registers(laure->lc); - + /*because marie is not registered yet*/ BC_ASSERT_FALSE(wait_for_until(pauline->lc,laure->lc,&pauline->stat.number_of_LinphonePresenceActivityAway,1,2000)); BC_ASSERT_FALSE(wait_for_until(pauline->lc,laure->lc,&laure->stat.number_of_LinphonePresenceActivityAway,1,2000)); - + //Now, marie register to the service LinphoneCoreManager *marie = linphone_core_manager_new3("marie_rc", TRUE, e164_marie); linphone_core_set_user_agent(marie->lc, "bypass", NULL); @@ -1095,21 +1096,21 @@ static void long_term_presence_with_crossed_references(void) { linphone_friend_list_set_rls_uri(linphone_core_get_default_friend_list(marie->lc), "sip:rls@sip.example.org"); linphone_friend_list_enable_subscriptions(linphone_core_get_default_friend_list(marie->lc), TRUE); linphone_core_refresh_registers(marie->lc); - + //Pauline is already registered so I must be notified very rapidely BC_ASSERT_TRUE(wait_for_until(marie->lc,marie->lc,&marie->stat.number_of_LinphonePresenceActivityAway,1,4000)); - + //For Pauline and Laure long term presence check was already performed so they will not be notified until new subscription BC_ASSERT_FALSE(wait_for_until(pauline->lc,laure->lc,&laure->stat.number_of_LinphonePresenceActivityAway,1,4000)); BC_ASSERT_FALSE(wait_for_until(pauline->lc,laure->lc,&pauline->stat.number_of_LinphonePresenceActivityAway,1,4000)); - + //re-subscribe to get notification. linphone_friend_list_enable_subscriptions(linphone_core_get_default_friend_list(pauline->lc), FALSE); wait_for_until(pauline->lc, NULL, NULL, 0,2000); /*wait for unsubscribe*/ linphone_friend_list_enable_subscriptions(linphone_core_get_default_friend_list(pauline->lc), TRUE); - + BC_ASSERT_TRUE(wait_for_until(pauline->lc,pauline->lc,&pauline->stat.number_of_LinphonePresenceActivityAway,1,4000)); - + linphone_core_manager_destroy(pauline); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(laure); @@ -1251,7 +1252,7 @@ static void extended_notify_only_both_side_subscribed(void) { BC_ASSERT_FALSE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivityDinner,1)); BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_NotifyPresenceReceived,1)); - + linphone_friend_enable_subscribes(f2, TRUE); linphone_friend_set_inc_subscribe_policy(f2,LinphoneSPAccept); /* Accept incoming subscription request for this friend*/ linphone_core_add_friend(pauline->lc, f2); @@ -1323,7 +1324,7 @@ static void extended_notify_only_both_side_subscribed2(void) { BC_ASSERT_FALSE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivityDinner,1)); BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_NotifyPresenceReceived,1)); - + linphone_friend_enable_subscribes(f2, TRUE); linphone_friend_set_inc_subscribe_policy(f2,LinphoneSPAccept); /* Accept incoming subscription request for this friend*/ linphone_core_add_friend(pauline->lc, f2); @@ -1349,7 +1350,7 @@ static void extended_notify_only_both_side_subscribed2(void) { linphone_friend_list_enable_subscriptions(linphone_core_get_default_friend_list(marie->lc), FALSE); linphone_friend_list_enable_subscriptions(linphone_core_get_default_friend_list(pauline->lc), FALSE); wait_for_list(lcs,NULL, 0, 2000); // wait for unsubscritptions - + linphone_core_manager_stop(marie); BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishCleared,1,int,"%i"); BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,2,int,"%i"); @@ -1392,7 +1393,7 @@ static void extended_notify_sub_unsub_sub(void) { linphone_friend_enable_subscribes(f, TRUE); linphone_friend_set_inc_subscribe_policy(f,LinphoneSPAccept); /* Accept incoming subscription request for this friend*/ linphone_core_add_friend(marie->lc, f); - + linphone_friend_enable_subscribes(f2, TRUE); linphone_friend_set_inc_subscribe_policy(f2,LinphoneSPAccept); /* Accept incoming subscription request for this friend*/ linphone_core_add_friend(pauline->lc, f2); @@ -1433,7 +1434,7 @@ static void extended_notify_sub_unsub_sub(void) { linphone_friend_list_enable_subscriptions(linphone_core_get_default_friend_list(marie->lc), FALSE); linphone_friend_list_enable_subscriptions(linphone_core_get_default_friend_list(pauline->lc), FALSE); wait_for_list(lcs,NULL, 0, 2000); // wait for unsubscritptions - + linphone_core_manager_stop(marie); BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishCleared,1,int,"%i"); BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,1,int,"%i"); @@ -1482,11 +1483,11 @@ static void extended_notify_sub_unsub_sub2(void) { linphone_presence_model_unref(pauline_presence); linphone_presence_model_unref(pauline_presence2); linphone_presence_model_unref(marie_presence); - + linphone_friend_enable_subscribes(f2, TRUE); linphone_friend_set_inc_subscribe_policy(f2,LinphoneSPAccept); /* Accept incoming subscription request for this friend*/ linphone_core_add_friend(pauline->lc, f2); - + linphone_friend_enable_subscribes(f3, TRUE); linphone_friend_set_inc_subscribe_policy(f3,LinphoneSPAccept); /* Accept incoming subscription request for this friend*/ linphone_core_add_friend(pauline2->lc, f3); @@ -1546,7 +1547,7 @@ static void extended_notify_sub_unsub_sub2(void) { linphone_friend_list_enable_subscriptions(linphone_core_get_default_friend_list(pauline->lc), FALSE); linphone_friend_list_enable_subscriptions(linphone_core_get_default_friend_list(pauline2->lc), FALSE); wait_for_list(lcs,NULL, 0, 2000); // wait for unsubscritptions - + linphone_core_manager_stop(marie); BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishCleared,1,int,"%i"); BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,1,int,"%i"); diff --git a/tester/presence_tester.c b/tester/presence_tester.c index 176bba7d5..c14ce5b8e 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -19,6 +19,7 @@ #include "linphone/core.h" #include "liblinphone_tester.h" +#include "tester_utils.h" static LinphoneCoreManager* presence_linphone_core_manager_new_with_rc_name(char* username, char * rc_name) { LinphoneCoreManager* mgr= linphone_core_manager_new2( rc_name, FALSE); @@ -146,7 +147,7 @@ static void simple_publish_with_expire(int expires) { LinphoneProxyConfig* proxy; LinphonePresenceModel* presence; LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get()); - + linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed); _linphone_core_add_callbacks(marie->lc, cbs, TRUE); linphone_core_cbs_unref(cbs); @@ -215,26 +216,26 @@ static void publish_with_dual_identity(void) { LinphoneCoreManager* pauline = linphone_core_manager_new("multi_account_rc"); const bctbx_list_t* proxies; LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get()); - + linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed); _linphone_core_add_callbacks(pauline->lc, cbs, TRUE); linphone_core_cbs_unref(cbs); - + for (proxies = linphone_core_get_proxy_config_list(pauline->lc); proxies!=NULL; proxies = proxies->next) { LinphoneProxyConfig *proxy = (LinphoneProxyConfig *) proxies->data; linphone_proxy_config_edit(proxy); linphone_proxy_config_enable_publish(proxy,TRUE); linphone_proxy_config_done(proxy); } - + BC_ASSERT_TRUE(wait_for(pauline->lc,pauline->lc,&pauline->stat.number_of_LinphonePublishProgress,4)); BC_ASSERT_TRUE(wait_for(pauline->lc,pauline->lc,&pauline->stat.number_of_LinphonePublishOk,4)); - + linphone_core_manager_stop(pauline); BC_ASSERT_EQUAL(pauline->stat.number_of_LinphonePublishCleared,4,int,"%i"); BC_ASSERT_EQUAL(pauline->stat.number_of_LinphonePublishOk,4,int,"%i"); linphone_core_manager_destroy(pauline); - + } static bool_t subscribe_to_callee_presence(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { stats initial_caller=caller_mgr->stat; @@ -309,30 +310,30 @@ static void publish_with_network_state_changes(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneProxyConfig* proxy; LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get()); - + linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed); _linphone_core_add_callbacks(marie->lc, cbs,TRUE); linphone_core_cbs_unref(cbs); - + proxy = linphone_core_get_default_proxy_config(marie->lc); linphone_proxy_config_edit(proxy); linphone_proxy_config_enable_publish(proxy,TRUE); linphone_proxy_config_done(proxy); - + BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,1)); BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,1)); - + linphone_core_set_network_reachable(marie->lc, FALSE); BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphoneRegistrationNone,1)); BC_ASSERT_FALSE(wait_for_until(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,2,1000)); BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,1,int,"%i"); BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishError,0,int,"%i"); - + linphone_core_set_network_reachable(marie->lc, TRUE); BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,2)); BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,2)); - - + + linphone_core_manager_stop(marie); BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishCleared,1,int,"%i"); /*yes it is 3 because when we change the expires, a new LinphoneEvent is created*/ BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,2,int,"%i"); diff --git a/tester/property-container-tester.cpp b/tester/property-container-tester.cpp index 2decc9164..17b4fcc2a 100644 --- a/tester/property-container-tester.cpp +++ b/tester/property-container-tester.cpp @@ -19,6 +19,7 @@ #include "object/property-container.h" #include "liblinphone_tester.h" +#include "tester_utils.h" // ============================================================================= diff --git a/tester/proxy_config_tester.c b/tester/proxy_config_tester.c index c11f352db..a2bf63066 100644 --- a/tester/proxy_config_tester.c +++ b/tester/proxy_config_tester.c @@ -17,6 +17,7 @@ */ #include "liblinphone_tester.h" +#include "tester_utils.h" #include @@ -131,15 +132,15 @@ static void phone_normalization_with_proxy(void) { linphone_proxy_config_set_dial_prefix(proxy, "52"); BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "+5217227718184"), "+5217227718184"); /*this is a mobile phone number */ BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "+528127718184"), "+528127718184"); /*this is a landline phone number from Monterrey*/ - + // Phone normalization for myanmar dial plans linphone_proxy_config_set_dial_prefix(proxy, "95"); BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "9965066691"), "+959965066691"); - + // Phone normalization for cameroon dial plans linphone_proxy_config_set_dial_prefix(proxy, "237"); BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "674788175"), "+237674788175"); - + linphone_proxy_config_unref(proxy); } @@ -220,16 +221,16 @@ static void load_dynamic_proxy_config(void) { ""; BC_ASSERT_FALSE(linphone_config_load_from_xml_string(linphone_core_get_config(lauriane->lc),config)); proxy = linphone_core_create_proxy_config(lauriane->lc); - + read = linphone_address_new(linphone_proxy_config_get_server_addr(proxy)); expected = linphone_address_new("sip:sip.linphone.org;transport=tls"); - + BC_ASSERT_TRUE(linphone_address_equal(read,expected)); linphone_address_unref(read); linphone_address_unref(expected); - + nat_policy = linphone_proxy_config_get_nat_policy(proxy); - + if (BC_ASSERT_PTR_NOT_NULL(nat_policy)) { BC_ASSERT_TRUE(linphone_nat_policy_ice_enabled(nat_policy)); BC_ASSERT_TRUE(linphone_nat_policy_stun_enabled(nat_policy)); @@ -237,9 +238,9 @@ static void load_dynamic_proxy_config(void) { } linphone_proxy_config_unref(proxy); linphone_core_manager_destroy(lauriane); - + //BC_ASSERT_STRING_EQUAL(linphone_proxy_config_get(proxy), "sip:sip.linphone.org;transport=tls"); - + } test_t proxy_config_tests[] = { diff --git a/tester/quality_reporting_tester.c b/tester/quality_reporting_tester.c index 590ab6694..1ebe8e1d0 100644 --- a/tester/quality_reporting_tester.c +++ b/tester/quality_reporting_tester.c @@ -19,6 +19,7 @@ #include #include "linphone/core.h" #include "liblinphone_tester.h" +#include "tester_utils.h" #include "quality_reporting.h" /*avoid crash if x is NULL on libc versions <4.5.26 */ @@ -133,7 +134,7 @@ static void quality_reporting_not_used_without_config(void) { LinphoneCall* call_marie = NULL; LinphoneCall* call_pauline = NULL; reporting_session_report_t **quality_reports = NULL; - + if (create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline, NULL, NULL)) { // marie has stats collection enabled but pauline has not @@ -329,7 +330,7 @@ static void quality_reporting_session_report_if_video_stopped(void) { BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishOk,2,5000)); } linphone_call_params_unref(marie_params); - + linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -420,7 +421,7 @@ static void quality_reporting_interval_report_video_and_rtt(void) { } linphone_chat_room_send_chat_message(pauline_chat_room, rtt_message); } - + end_call(marie, pauline); /*wait that all publish complete*/ BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishOk,marie->stat.number_of_LinphonePublishProgress,60000)); @@ -439,30 +440,30 @@ static void video_bandwidth_estimation(void){ LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_rc"); LinphoneVideoPolicy pol = {0}; OrtpNetworkSimulatorParams simparams = { 0 }; - + linphone_core_set_video_device(marie->lc, "Mire: Mire (synthetic moving picture)"); linphone_core_enable_video_capture(marie->lc, TRUE); linphone_core_enable_video_display(marie->lc, TRUE); linphone_core_enable_video_capture(pauline->lc, TRUE); linphone_core_enable_video_display(pauline->lc, TRUE); - + pol.automatically_accept = TRUE; pol.automatically_initiate = TRUE; linphone_core_set_video_policy(marie->lc, &pol); linphone_core_set_video_policy(pauline->lc, &pol); - + linphone_core_set_preferred_video_size_by_name(marie->lc, "vga"); simparams.mode = OrtpNetworkSimulatorOutbound; simparams.enabled = TRUE; simparams.max_bandwidth = 300000; linphone_core_set_network_simulator_params(marie->lc, &simparams); - + if (BC_ASSERT_TRUE(call(marie, pauline))){ /*wait for the first TMMBR*/ BC_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &marie->stat.number_of_tmmbr_received, 1, 50000)); BC_ASSERT_GREATER((float)marie->stat.last_tmmbr_value_received, 270000.f, float, "%f"); BC_ASSERT_LOWER((float)marie->stat.last_tmmbr_value_received, 330000.f, float, "%f"); - + end_call(marie, pauline); } linphone_core_manager_destroy(marie); diff --git a/tester/register_tester.c b/tester/register_tester.c index eeeec13ec..a40817f89 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -19,6 +19,7 @@ #include "linphone/core.h" #include "liblinphone_tester.h" +#include "tester_utils.h" static void authentication_requested(LinphoneCore *lc, LinphoneAuthInfo *auth_info, LinphoneAuthMethod method) { @@ -1205,14 +1206,14 @@ static void multi_devices_register_with_gruu(void) { linphone_core_add_supported_tag(marie->lc,"gruu"); linphone_core_manager_start(marie,TRUE); LinphoneProxyConfig *cfg=linphone_core_get_default_proxy_config(marie->lc); - + if(cfg) { const LinphoneAddress *addr = linphone_proxy_config_get_contact(cfg); BC_ASSERT_PTR_NOT_NULL(addr); BC_ASSERT_STRING_EQUAL(linphone_address_get_domain(addr),linphone_proxy_config_get_domain(cfg)); BC_ASSERT_TRUE(linphone_address_has_uri_param(addr,"gr")); } - + linphone_core_set_network_reachable(marie->lc,FALSE); /*to make sure first instance is not unregistered*/ linphone_core_manager_destroy(marie); @@ -1224,7 +1225,7 @@ static void multi_devices_register_with_gruu(void) { BC_ASSERT_STRING_EQUAL(linphone_address_get_domain(addr),linphone_proxy_config_get_domain(cfg)); BC_ASSERT_TRUE(linphone_address_has_uri_param(addr,"gr")); } - + linphone_core_manager_destroy(marie); } diff --git a/tester/remote_provisioning_tester.c b/tester/remote_provisioning_tester.c index 25fc22d17..8aba68be2 100644 --- a/tester/remote_provisioning_tester.c +++ b/tester/remote_provisioning_tester.c @@ -19,6 +19,7 @@ #include "linphone/core.h" #include "liblinphone_tester.h" +#include "tester_utils.h" void linphone_configuration_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) { stats* counters; diff --git a/tester/setup_tester.c b/tester/setup_tester.c index 3e37b6965..e34dcc4cb 100644 --- a/tester/setup_tester.c +++ b/tester/setup_tester.c @@ -19,7 +19,9 @@ #include "linphone/core.h" #include "liblinphone_tester.h" +#include "tester_utils.h" #include "linphone/lpconfig.h" +#include "tester_utils.h" static void linphone_version_test(void){ const char *version=linphone_core_get_version(); diff --git a/tester/stun_tester.c b/tester/stun_tester.c index 3c6768c86..d9e123a79 100644 --- a/tester/stun_tester.c +++ b/tester/stun_tester.c @@ -18,6 +18,7 @@ #include "linphone/core.h" #include "liblinphone_tester.h" +#include "tester_utils.h" #include "mediastreamer2/stun.h" #include "ortp/port.h" diff --git a/tester/tester.c b/tester/tester.c index 38394a740..22138b0ee 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -21,6 +21,7 @@ #include "linphone/core.h" #include "liblinphone_tester.h" #include +#include "tester_utils.h" #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) #pragma GCC diagnostic push diff --git a/tester/tunnel_tester.c b/tester/tunnel_tester.c index 03df655db..ac66c4591 100644 --- a/tester/tunnel_tester.c +++ b/tester/tunnel_tester.c @@ -21,6 +21,7 @@ #include "linphone/core.h" #include "linphone/lpconfig.h" #include "liblinphone_tester.h" +#include "tester_utils.h" /* Retrieve the public IP from a given hostname */ int get_ip_from_hostname(const char * tunnel_hostname, char *ip, size_t ip_size){ @@ -59,7 +60,7 @@ static void call_with_tunnel_base(LinphoneTunnelMode tunnel_mode, bool_t with_si BC_ASSERT_FALSE(get_ip_from_hostname("tunnel.linphone.org",tunnel_ip,sizeof(tunnel_ip))); linphone_core_remove_supported_tag(pauline->lc,"gruu"); /*with gruu, we have no access to the "public IP from contact*/ linphone_core_remove_supported_tag(marie->lc,"gruu"); - + BC_ASSERT_TRUE(wait_for(pauline->lc,NULL,&pauline->stat.number_of_LinphoneRegistrationOk,1)); public_ip = get_public_contact_ip(pauline->lc); BC_ASSERT_STRING_NOT_EQUAL(public_ip, tunnel_ip); @@ -263,7 +264,7 @@ static void register_on_second_tunnel(void) { LinphoneTunnelConfig *config2 = linphone_tunnel_config_new(); char tunnel_ip[64]; char* public_ip; - + BC_ASSERT_FALSE(get_ip_from_hostname("tunnel.linphone.org",tunnel_ip,sizeof(tunnel_ip))); linphone_tunnel_simulate_udp_loss(tunnel, TRUE); diff --git a/tester/vcard_tester.c b/tester/vcard_tester.c index abad43f2d..ee131cdf4 100644 --- a/tester/vcard_tester.c +++ b/tester/vcard_tester.c @@ -18,10 +18,12 @@ #include "linphone/core.h" + #ifdef VCARD_ENABLED #include "liblinphone_tester.h" +#include "tester_utils.h" #include "carddav.h" #include @@ -37,7 +39,7 @@ static void linphone_vcard_import_export_friends_test(void) { char *export_filepath = bc_tester_file("export_vcards.vcf"); int count = 0; BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(friends), 0, unsigned int, "%u"); - + count = linphone_friend_list_import_friends_from_vcard4_file(lfl, import_filepath); BC_ASSERT_EQUAL(count, 3, int, "%d"); friends = linphone_friend_list_get_friends(lfl); @@ -344,7 +346,7 @@ static void friends_sqlite_storage(void) { laddress2 = linphone_friend_get_address(lf2); address2 = linphone_address_as_string(laddress2); BC_ASSERT_STRING_EQUAL(address2, address); - + ms_free(address); ms_free(address2); @@ -392,7 +394,7 @@ static void friends_sqlite_store_lot_of_friends(void) { BC_ASSERT_TRUE(ret ==SQLITE_OK); ret = sqlite3_exec(db,"BEGIN",0,0,&errmsg); BC_ASSERT_TRUE(ret ==SQLITE_OK); - + ret = sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS friends (" "id INTEGER PRIMARY KEY AUTOINCREMENT," @@ -430,12 +432,12 @@ static void friends_sqlite_store_lot_of_friends(void) { BC_ASSERT_TRUE(ret ==SQLITE_OK); sqlite3_free(buf); } - + ret = sqlite3_exec(db,"END",0,0,&errmsg); BC_ASSERT_TRUE(ret ==SQLITE_OK); - + ms_message("End :\n"); - + ret = sqlite3_exec(db,"BEGIN",0,0,&errmsg); BC_ASSERT_TRUE(ret ==SQLITE_OK); ret = sqlite3_exec(db, "DELETE FROM friends;",0,0,&errmsg); @@ -460,7 +462,7 @@ static void friends_sqlite_find_friend_in_lot_of_friends(void) { BC_ASSERT_TRUE(ret ==SQLITE_OK); ret = sqlite3_exec(db,"BEGIN",0,0,&errmsg); BC_ASSERT_TRUE(ret ==SQLITE_OK); - + ret = sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS friends (" "id INTEGER PRIMARY KEY AUTOINCREMENT," @@ -477,7 +479,7 @@ static void friends_sqlite_find_friend_in_lot_of_friends(void) { BC_ASSERT_TRUE(ret ==SQLITE_OK); ret = sqlite3_exec(db,"END",0,0,&errmsg); BC_ASSERT_TRUE(ret ==SQLITE_OK); - + ret = sqlite3_exec(db,"BEGIN",0,0,&errmsg); BC_ASSERT_TRUE(ret ==SQLITE_OK); for (i = 0; i < 20000; i++) { @@ -492,30 +494,30 @@ static void friends_sqlite_find_friend_in_lot_of_friends(void) { NULL, 0 ); - + ret = sqlite3_exec(db,buf,0,0,&errmsg); BC_ASSERT_TRUE(ret ==SQLITE_OK); sqlite3_free(buf); //ms_message("%i",i); } - + ret = sqlite3_exec(db,"END",0,0,&errmsg); BC_ASSERT_TRUE(ret ==SQLITE_OK); - + bctbx_get_cur_time(&t1); ms_message("Start : %li : %li\n", (long int)t1.tv_sec, (long int)t1.tv_nsec); for (i = 0; i < 20000; i++) { buf = sqlite3_mprintf("SELECT * FROM friends WHERE ref_key LIKE 'key_%i';", i); - + ret = sqlite3_exec(db,buf,0,0,&errmsg); BC_ASSERT_TRUE(ret ==SQLITE_OK); sqlite3_free(buf); } - + bctbx_get_cur_time(&t2); ms_message("End : %li : %li\n", (long int)t2.tv_sec, (long int)t2.tv_nsec); - + ret = sqlite3_exec(db,"BEGIN",0,0,&errmsg); BC_ASSERT_TRUE(ret ==SQLITE_OK); ret = sqlite3_exec(db, "DELETE FROM friends;",0,0,&errmsg); @@ -977,7 +979,7 @@ static void insert_lot_of_friends_map_test(void) { int i; bctbx_map_t *friends_map = bctbx_mmap_cchar_new(); bctbx_pair_cchar_t *pair; - + char key[64]; ms_message("Start\n"); for(i = 0; i < 20000; i++) { diff --git a/tester/video_tester.c b/tester/video_tester.c index 95cc03ef0..2f168b1ac 100644 --- a/tester/video_tester.c +++ b/tester/video_tester.c @@ -21,6 +21,7 @@ #include "linphone/core.h" #include "liblinphone_tester.h" +#include "tester_utils.h" #include "linphone/lpconfig.h" #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) From 46a194d5b3a5309daf2be3c32676eac89d951453 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 17 Nov 2017 10:27:33 +0100 Subject: [PATCH 0796/2215] feat(core): add findChatRooms impl --- src/core/core-chat-room.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 11cf7009f..6bb25eb60 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -170,8 +170,18 @@ shared_ptr Core::findChatRoom (const ChatRoomId &chatRoomId) const { } list> Core::findChatRooms (const IdentityAddress &peerAddress) const { - // TODO: DEV GROUP CHAT. - return list>(); + L_D(); + + // TODO: Improve performance if necessary. + list> output; + copy_if( + d->chatRooms.begin(), d->chatRooms.end(), + back_inserter(output), [&peerAddress](const shared_ptr &chatRoom) { + return chatRoom->getPeerAddress() == peerAddress; + } + ); + + return output; } shared_ptr Core::createClientGroupChatRoom (const string &subject) { From 6dd6e829a3496c825da7d9ebeec771ded2f6333d Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 17 Nov 2017 15:02:25 +0100 Subject: [PATCH 0797/2215] feat(conference): refactoring, use CoreAccessor and ChatRoomId --- coreapi/linphonecore.c | 2 +- include/linphone/api/c-event-log.h | 13 +++- src/CMakeLists.txt | 12 +-- src/c-wrapper/api/c-event-log.cpp | 34 +++++++-- src/call/call.cpp | 4 +- src/chat/chat-room/basic-chat-room.cpp | 4 +- src/chat/chat-room/chat-room.cpp | 2 +- src/chat/chat-room/chat-room.h | 2 +- src/chat/chat-room/client-group-chat-room.cpp | 28 +++---- .../chat-room/real-time-text-chat-room.cpp | 2 +- .../chat-room/server-group-chat-room-stub.cpp | 6 +- src/conference/conference-p.h | 6 -- src/conference/conference.cpp | 13 ++-- src/conference/conference.h | 10 ++- .../local-conference-event-handler-p.h | 1 - .../local-conference-event-handler.cpp | 10 ++- .../local-conference-event-handler.h | 32 ++++---- .../remote-conference-event-handler-p.h | 11 ++- .../remote-conference-event-handler.cpp | 75 +++++++++++-------- .../remote-conference-event-handler.h | 32 ++++---- src/conference/local-conference.cpp | 8 +- src/conference/local-conference.h | 2 +- src/conference/remote-conference.cpp | 11 ++- src/conference/remote-conference.h | 3 +- src/conference/session/call-session.cpp | 6 +- src/db/main-db.cpp | 13 ++-- .../conference-chat-message-event.cpp | 3 +- src/event-log/conference/conference-event-p.h | 4 +- src/event-log/conference/conference-event.cpp | 12 +-- src/event-log/conference/conference-event.h | 8 +- .../conference/conference-notified-event.cpp | 8 +- .../conference/conference-notified-event.h | 4 +- .../conference-participant-device-event.cpp | 4 +- .../conference-participant-device-event.h | 2 +- .../conference-participant-event.cpp | 8 +- .../conference/conference-participant-event.h | 5 +- .../conference/conference-subject-event.cpp | 4 +- .../conference/conference-subject-event.h | 2 +- 38 files changed, 227 insertions(+), 179 deletions(-) rename src/conference/{ => handlers}/local-conference-event-handler-p.h (98%) rename src/conference/{ => handlers}/local-conference-event-handler.cpp (98%) rename src/conference/{ => handlers}/local-conference-event-handler.h (62%) rename src/conference/{ => handlers}/remote-conference-event-handler-p.h (91%) rename src/conference/{ => handlers}/remote-conference-event-handler.cpp (73%) rename src/conference/{ => handlers}/remote-conference-event-handler.h (66%) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index bc5be81cd..1a19a1a43 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -50,7 +50,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "chat/chat-room/client-group-chat-room-p.h" #include "chat/chat-room/server-group-chat-room-p.h" -#include "conference/remote-conference-event-handler.h" +#include "conference/handlers/remote-conference-event-handler.h" #include "core/core.h" // For migration purpose. diff --git a/include/linphone/api/c-event-log.h b/include/linphone/api/c-event-log.h index 6edb53ffc..5ebcae081 100644 --- a/include/linphone/api/c-event-log.h +++ b/include/linphone/api/c-event-log.h @@ -66,11 +66,18 @@ LINPHONE_PUBLIC time_t linphone_event_log_get_creation_time (const LinphoneEvent // ----------------------------------------------------------------------------- /** - * Returns the conference address of a conference event. + * Returns the peer address of a conference event. * @param[in] event_log A #LinphoneEventLog object. - * @return The conference address. + * @return The peer address. */ -LINPHONE_PUBLIC const LinphoneAddress *linphone_event_log_get_conference_address (const LinphoneEventLog *event_log); +LINPHONE_PUBLIC const LinphoneAddress *linphone_event_log_get_peer_address (const LinphoneEventLog *event_log); + +/** + * Returns the local address of a conference event. + * @param[in] event_log A #LinphoneEventLog object. + * @return The local address. + */ +LINPHONE_PUBLIC const LinphoneAddress *linphone_event_log_get_local_address (const LinphoneEventLog *event_log); // ----------------------------------------------------------------------------- // ConferenceNotifiedEvent. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2df1a80a2..30575da1e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -63,8 +63,10 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES conference/conference-listener.h conference/conference-p.h conference/conference.h - conference/local-conference-event-handler-p.h - conference/local-conference-event-handler.h + conference/handlers/local-conference-event-handler-p.h + conference/handlers/local-conference-event-handler.h + conference/handlers/remote-conference-event-handler-p.h + conference/handlers/remote-conference-event-handler.h conference/local-conference-p.h conference/local-conference.h conference/params/call-session-params-p.h @@ -74,8 +76,6 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES conference/participant-device.h conference/participant-p.h conference/participant.h - conference/remote-conference-event-handler-p.h - conference/remote-conference-event-handler.h conference/remote-conference-p.h conference/remote-conference.h conference/session/call-session-listener.h @@ -178,13 +178,13 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES chat/notification/imdn.cpp chat/notification/is-composing.cpp conference/conference.cpp - conference/local-conference-event-handler.cpp + conference/handlers/local-conference-event-handler.cpp + conference/handlers/remote-conference-event-handler.cpp conference/local-conference.cpp conference/params/call-session-params.cpp conference/params/media-session-params.cpp conference/participant-device.cpp conference/participant.cpp - conference/remote-conference-event-handler.cpp conference/remote-conference.cpp conference/session/call-session.cpp conference/session/media-session.cpp diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 2b93bc2d0..0a12eefbb 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -22,6 +22,7 @@ #include "c-wrapper/c-wrapper.h" #include "call/call.h" #include "chat/chat-message/chat-message.h" +#include "chat/chat-room/chat-room-id.h" #include "event-log/events.h" // ============================================================================= @@ -35,7 +36,8 @@ L_DECLARE_C_OBJECT_IMPL_WITH_XTORS( EventLog, _linphone_event_log_constructor, _linphone_event_log_destructor, - mutable LinphoneAddress *conferenceAddressCache; + mutable LinphoneAddress *peerAddressCache; + mutable LinphoneAddress *localAddressCache; mutable LinphoneAddress *participantAddressCache; mutable LinphoneAddress *deviceAddressCache; ); @@ -43,8 +45,10 @@ L_DECLARE_C_OBJECT_IMPL_WITH_XTORS( void _linphone_event_log_constructor (LinphoneEventLog *) {} void _linphone_event_log_destructor (LinphoneEventLog *event_log) { - if (event_log->conferenceAddressCache) - linphone_address_unref(event_log->conferenceAddressCache); + if (event_log->peerAddressCache) + linphone_address_unref(event_log->peerAddressCache); + if (event_log->localAddressCache) + linphone_address_unref(event_log->localAddressCache); if (event_log->participantAddressCache) linphone_address_unref(event_log->participantAddressCache); if (event_log->deviceAddressCache) @@ -190,18 +194,32 @@ time_t linphone_event_log_get_creation_time (const LinphoneEventLog *event_log) // ConferenceEvent. // ----------------------------------------------------------------------------- -const LinphoneAddress *linphone_event_log_get_conference_address (const LinphoneEventLog *event_log) { +const LinphoneAddress *linphone_event_log_get_peer_address (const LinphoneEventLog *event_log) { if (!isConferenceType(linphone_event_log_get_type(event_log))) return nullptr; - if (!event_log->conferenceAddressCache) - event_log->conferenceAddressCache = linphone_address_new( + if (!event_log->peerAddressCache) + event_log->peerAddressCache = linphone_address_new( static_pointer_cast( L_GET_CPP_PTR_FROM_C_OBJECT(event_log) - )->getConferenceAddress().asString().c_str() + )->getChatRoomId().getPeerAddress().asString().c_str() ); - return event_log->conferenceAddressCache; + return event_log->peerAddressCache; +} + +const LinphoneAddress *linphone_event_log_get_local_address (const LinphoneEventLog *event_log) { + if (!isConferenceType(linphone_event_log_get_type(event_log))) + return nullptr; + + if (!event_log->localAddressCache) + event_log->localAddressCache = linphone_address_new( + static_pointer_cast( + L_GET_CPP_PTR_FROM_C_OBJECT(event_log) + )->getChatRoomId().getLocalAddress().asString().c_str() + ); + + return event_log->localAddressCache; } // ----------------------------------------------------------------------------- diff --git a/src/call/call.cpp b/src/call/call.cpp index ea85c024d..3a6eeef86 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -227,9 +227,9 @@ Call::Call ( const Address *myAddress = (direction == LinphoneCallIncoming) ? &to : &from; string confType = lp_config_get_string(linphone_core_get_config(core), "misc", "conference_type", "local"); if (confType == "remote") { - d->conference = new RemoteConference(core, *myAddress, d); + d->conference = new RemoteConference(core->cppCore, *myAddress, d); } else { - d->conference = new LocalConference(core, *myAddress, d); + d->conference = new LocalConference(core->cppCore, *myAddress, d); } const Address *remoteAddress = (direction == LinphoneCallIncoming) ? &from : &to; d->conference->addParticipant(*remoteAddress, msp, true); diff --git a/src/chat/chat-room/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp index a02a58657..985b09519 100644 --- a/src/chat/chat-room/basic-chat-room.cpp +++ b/src/chat/chat-room/basic-chat-room.cpp @@ -30,13 +30,13 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE BasicChatRoom::BasicChatRoom (const shared_ptr &core, const ChatRoomId &chatRoomId) : - ChatRoom(*new BasicChatRoomPrivate, core, chatRoomId) {} + BasicChatRoom(*new BasicChatRoomPrivate, core, chatRoomId) {} BasicChatRoom::BasicChatRoom ( BasicChatRoomPrivate &p, const std::shared_ptr &core, const ChatRoomId &chatRoomId -) : ChatRoom(p, core, chatRoomId) {} +) : CoreAccessor(core), ChatRoom(p, core, chatRoomId) {} BasicChatRoom::CapabilitiesMask BasicChatRoom::getCapabilities () const { return static_cast(Capabilities::Basic); diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index cc9b2e5b7..0e2b77c6c 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -449,7 +449,7 @@ void ChatRoomPrivate::onIsComposingRefreshNeeded () { // ============================================================================= ChatRoom::ChatRoom (ChatRoomPrivate &p, const shared_ptr &core, const ChatRoomId &chatRoomId) : - Object(p), CoreAccessor(core) { + CoreAccessor(core), Object(p) { L_D(); d->chatRoomId = chatRoomId; diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index b11d28d93..51f4c59cd 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -30,7 +30,7 @@ LINPHONE_BEGIN_NAMESPACE class ChatRoomPrivate; -class LINPHONE_PUBLIC ChatRoom : public Object, public CoreAccessor, public ConferenceInterface { +class LINPHONE_PUBLIC ChatRoom : public Object, virtual public CoreAccessor, public ConferenceInterface { friend class Core; friend class CorePrivate; friend class ChatMessage; diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 24fe71db5..5d22c36a9 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -22,8 +22,8 @@ #include "address/address-p.h" #include "c-wrapper/c-wrapper.h" #include "client-group-chat-room-p.h" +#include "conference/handlers/remote-conference-event-handler.h" #include "conference/participant-p.h" -#include "conference/remote-conference-event-handler.h" #include "conference/remote-conference-p.h" #include "conference/session/call-session-p.h" #include "core/core-p.h" @@ -81,9 +81,9 @@ ClientGroupChatRoom::ClientGroupChatRoom ( const std::string &factoryUri, const IdentityAddress &me, const std::string &subject -) : +) : CoreAccessor(core), ChatRoom(*new ClientGroupChatRoomPrivate, core, ChatRoomId(IdentityAddress(), me)), -RemoteConference(core->getCCore(), me, nullptr) { +RemoteConference(core, me, nullptr) { L_D_T(RemoteConference, dConference); dConference->focus = make_shared(Address(factoryUri)); RemoteConference::setSubject(subject); @@ -141,7 +141,7 @@ void ClientGroupChatRoom::addParticipants ( } void ClientGroupChatRoom::removeParticipant (const shared_ptr &participant) { - LinphoneCore *cCore = CoreAccessor::getCore()->getCCore(); + LinphoneCore *cCore = getCore()->getCCore(); SalReferOp *referOp = new SalReferOp(cCore->sal); LinphoneAddress *lAddr = linphone_address_new(getConferenceAddress().asString().c_str()); @@ -183,7 +183,7 @@ void ClientGroupChatRoom::setParticipantAdminStatus (shared_ptr &pa return; } - LinphoneCore *cCore = CoreAccessor::getCore()->getCCore(); + LinphoneCore *cCore = getCore()->getCCore(); SalReferOp *referOp = new SalReferOp(cCore->sal); LinphoneAddress *lAddr = linphone_address_new(getConferenceAddress().asString().c_str()); @@ -261,7 +261,7 @@ void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { L_D_T(RemoteConference, dConference); dConference->conferenceAddress = addr; d->chatRoomId = ChatRoomId(addr, d->chatRoomId.getLocalAddress()); - CoreAccessor::getCore()->getPrivate()->insertChatRoom(getSharedFromThis()); + getCore()->getPrivate()->insertChatRoom(getSharedFromThis()); } void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { @@ -274,7 +274,7 @@ void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { void ClientGroupChatRoom::onFirstNotifyReceived (const Address &addr) { L_D(); d->setState(ChatRoom::State::Created); - CoreAccessor::getCore()->getPrivate()->insertChatRoomWithDb(getSharedFromThis()); + getCore()->getPrivate()->insertChatRoomWithDb(getSharedFromThis()); } void ClientGroupChatRoom::onParticipantAdded (const shared_ptr &event, bool isFullState) { @@ -299,7 +299,7 @@ void ClientGroupChatRoom::onParticipantAdded (const shared_ptrcppCore->getPrivate()->mainDb->addEvent(event); + getCore()->getPrivate()->mainDb->addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(event)); @@ -322,7 +322,7 @@ void ClientGroupChatRoom::onParticipantRemoved (const shared_ptrcppCore->getPrivate()->mainDb->addEvent(event); + getCore()->getPrivate()->mainDb->addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(event)); @@ -351,7 +351,7 @@ void ClientGroupChatRoom::onParticipantSetAdmin (const shared_ptrcppCore->getPrivate()->mainDb->addEvent(event); + getCore()->getPrivate()->mainDb->addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(event)); @@ -368,7 +368,7 @@ void ClientGroupChatRoom::onSubjectChanged (const shared_ptrcppCore->getPrivate()->mainDb->addEvent(event); + getCore()->getPrivate()->mainDb->addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(event)); @@ -393,7 +393,7 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (const shared_ptrcppCore->getPrivate()->mainDb->addEvent(event); + getCore()->getPrivate()->mainDb->addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(event)); @@ -416,7 +416,7 @@ void ClientGroupChatRoom::onParticipantDeviceRemoved (const shared_ptrcppCore->getPrivate()->mainDb->addEvent(event); + getCore()->getPrivate()->mainDb->addEvent(event); if (cb) cb(cr, L_GET_C_BACK_PTR(event)); @@ -445,7 +445,7 @@ void ClientGroupChatRoom::onCallSessionStateChanged ( Address addr(session->getRemoteContactAddress()->asStringUriOnly()); onConferenceCreated(addr); if (session->getRemoteContactAddress()->hasParam("isfocus")) - dConference->eventHandler->subscribe(getConferenceAddress()); + dConference->eventHandler->subscribe(getChatRoomId()); } else if (d->state == ChatRoom::State::TerminationPending) dConference->focus->getPrivate()->getSession()->terminate(); } else if ((state == LinphoneCallReleased) && (d->state == ChatRoom::State::TerminationPending)) { diff --git a/src/chat/chat-room/real-time-text-chat-room.cpp b/src/chat/chat-room/real-time-text-chat-room.cpp index d4ed5ee45..7a8cb8ef6 100644 --- a/src/chat/chat-room/real-time-text-chat-room.cpp +++ b/src/chat/chat-room/real-time-text-chat-room.cpp @@ -104,7 +104,7 @@ void RealTimeTextChatRoomPrivate::sendMessage (const shared_ptr &ms // ============================================================================= RealTimeTextChatRoom::RealTimeTextChatRoom (const shared_ptr &core, const ChatRoomId &chatRoomId) : - BasicChatRoom(*new RealTimeTextChatRoomPrivate, core, chatRoomId) {} + CoreAccessor(core), BasicChatRoom(*new RealTimeTextChatRoomPrivate, core, chatRoomId) {} RealTimeTextChatRoom::CapabilitiesMask RealTimeTextChatRoom::getCapabilities () const { return BasicChatRoom::getCapabilities() | static_cast(Capabilities::RealTimeText); diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index faace05d4..a1fe25c89 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -77,9 +77,9 @@ bool ServerGroupChatRoomPrivate::isAdminLeft () const { // ============================================================================= -ServerGroupChatRoom::ServerGroupChatRoom (const shared_ptr &core, SalCallOp *op) : - ChatRoom(*new ServerGroupChatRoomPrivate, core, ChatRoomId(IdentityAddress(op->get_to()), IdentityAddress(op->get_to()))), - LocalConference(core->getCCore(), Address(op->get_to()), nullptr) {} +ServerGroupChatRoom::ServerGroupChatRoom (const shared_ptr &core, SalCallOp *op) : CoreAccessor(core), +ChatRoom(*new ServerGroupChatRoomPrivate, core, ChatRoomId(IdentityAddress(op->get_to()), IdentityAddress(op->get_to()))), +LocalConference(core, Address(op->get_to()), nullptr) {} int ServerGroupChatRoom::getCapabilities () const { return 0; diff --git a/src/conference/conference-p.h b/src/conference/conference-p.h index 1b0421da4..f036e6da0 100644 --- a/src/conference/conference-p.h +++ b/src/conference/conference-p.h @@ -20,11 +20,6 @@ #ifndef _CONFERENCE_P_H_ #define _CONFERENCE_P_H_ -#include -#include - -#include "linphone/types.h" - #include "address/address.h" #include "conference.h" @@ -41,7 +36,6 @@ public: std::list> participants; protected: - LinphoneCore *core = nullptr; CallListener *callListener = nullptr; std::shared_ptr activeParticipant; diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 4af0f39f6..bb7cd4e67 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -29,10 +29,14 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -Conference::Conference (ConferencePrivate &p, LinphoneCore *core, const Address &myAddress, CallListener *listener) : mPrivate(&p) { +Conference::Conference ( + ConferencePrivate &p, + const shared_ptr &core, + const Address &myAddress, + CallListener *listener +) : CoreAccessor(core), mPrivate(&p) { L_D(); d->mPublic = this; - d->core = core; d->callListener = listener; d->me = make_shared(myAddress); } @@ -48,11 +52,6 @@ shared_ptr Conference::getActiveParticipant () const { return d->activeParticipant; } -LinphoneCore *Conference::getCore () const { - L_D(); - return d->core; -} - // ----------------------------------------------------------------------------- void Conference::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { diff --git a/src/conference/conference.h b/src/conference/conference.h index 6bd9eb783..6489a11b4 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -24,6 +24,7 @@ #include "conference/conference-interface.h" #include "conference/session/call-session-listener.h" +#include "core/core-accessor.h" // ============================================================================= @@ -33,7 +34,10 @@ class CallListener; class CallSessionPrivate; class ConferencePrivate; -class LINPHONE_PUBLIC Conference : public ConferenceInterface, public CallSessionListener { +class LINPHONE_PUBLIC Conference : + public ConferenceInterface, + public CallSessionListener, + virtual public CoreAccessor { friend class CallSessionPrivate; public: @@ -41,8 +45,6 @@ public: std::shared_ptr getActiveParticipant () const; - LinphoneCore * getCore () const; - std::shared_ptr findParticipant (const std::shared_ptr &session) const; /* ConferenceInterface */ @@ -82,7 +84,7 @@ private: protected: explicit Conference ( ConferencePrivate &p, - LinphoneCore *core, + const std::shared_ptr &core, const Address &myAddress, CallListener *listener = nullptr ); diff --git a/src/conference/local-conference-event-handler-p.h b/src/conference/handlers/local-conference-event-handler-p.h similarity index 98% rename from src/conference/local-conference-event-handler-p.h rename to src/conference/handlers/local-conference-event-handler-p.h index 16ee8c9f1..14211f0fa 100644 --- a/src/conference/local-conference-event-handler-p.h +++ b/src/conference/handlers/local-conference-event-handler-p.h @@ -47,7 +47,6 @@ public: inline unsigned int getLastNotify () const { return lastNotify; }; private: - LinphoneCore *core = nullptr; LocalConference *conf = nullptr; unsigned int lastNotify = 0; diff --git a/src/conference/local-conference-event-handler.cpp b/src/conference/handlers/local-conference-event-handler.cpp similarity index 98% rename from src/conference/local-conference-event-handler.cpp rename to src/conference/handlers/local-conference-event-handler.cpp index 75f2fd85d..b364f4547 100644 --- a/src/conference/local-conference-event-handler.cpp +++ b/src/conference/handlers/local-conference-event-handler.cpp @@ -19,12 +19,15 @@ #include +#include "linphone/utils/utils.h" + #include "conference/local-conference.h" #include "conference/participant-p.h" -#include "linphone/utils/utils.h" #include "local-conference-event-handler-p.h" #include "logger/logger.h" #include "object/object-p.h" + +// TODO: remove me. #include "private.h" // ============================================================================= @@ -247,12 +250,11 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceRemoved // ============================================================================= -LocalConferenceEventHandler::LocalConferenceEventHandler (LinphoneCore *core, LocalConference *localConf) : +LocalConferenceEventHandler::LocalConferenceEventHandler (LocalConference *localConference) : Object(*new LocalConferenceEventHandlerPrivate) { L_D(); xercesc::XMLPlatformUtils::Initialize(); - d->conf = localConf; - d->core = core; + d->conf = localConference; // TODO : init d->lastNotify = last notify } diff --git a/src/conference/local-conference-event-handler.h b/src/conference/handlers/local-conference-event-handler.h similarity index 62% rename from src/conference/local-conference-event-handler.h rename to src/conference/handlers/local-conference-event-handler.h index f34eaee7d..bdb14700b 100644 --- a/src/conference/local-conference-event-handler.h +++ b/src/conference/handlers/local-conference-event-handler.h @@ -20,31 +20,35 @@ #ifndef _LOCAL_CONFERENCE_EVENT_HANDLER_H_ #define _LOCAL_CONFERENCE_EVENT_HANDLER_H_ -#include "address/address.h" #include "linphone/types.h" + +#include "address/address.h" +#include "core/core-accessor.h" #include "object/object.h" +// ============================================================================= + LINPHONE_BEGIN_NAMESPACE class LocalConference; class LocalConferenceEventHandlerPrivate; class LocalConferenceEventHandler : public Object { - public: - LocalConferenceEventHandler (LinphoneCore *core, LocalConference *localConf); - ~LocalConferenceEventHandler (); +public: + LocalConferenceEventHandler (LocalConference *localConference); + ~LocalConferenceEventHandler (); - void subscribeReceived (LinphoneEvent *lev); - void notifyParticipantAdded (const Address &addr); - void notifyParticipantRemoved (const Address &addr); - void notifyParticipantSetAdmin (const Address &addr, bool isAdmin); - void notifySubjectChanged (); - void notifyParticipantDeviceAdded (const Address &addr, const Address &gruu); - void notifyParticipantDeviceRemoved (const Address &addr, const Address &gruu); + void subscribeReceived (LinphoneEvent *lev); + void notifyParticipantAdded (const Address &addr); + void notifyParticipantRemoved (const Address &addr); + void notifyParticipantSetAdmin (const Address &addr, bool isAdmin); + void notifySubjectChanged (); + void notifyParticipantDeviceAdded (const Address &addr, const Address &gruu); + void notifyParticipantDeviceRemoved (const Address &addr, const Address &gruu); - private: - L_DECLARE_PRIVATE(LocalConferenceEventHandler); - L_DISABLE_COPY(LocalConferenceEventHandler); +private: + L_DECLARE_PRIVATE(LocalConferenceEventHandler); + L_DISABLE_COPY(LocalConferenceEventHandler); }; LINPHONE_END_NAMESPACE diff --git a/src/conference/remote-conference-event-handler-p.h b/src/conference/handlers/remote-conference-event-handler-p.h similarity index 91% rename from src/conference/remote-conference-event-handler-p.h rename to src/conference/handlers/remote-conference-event-handler-p.h index 88eba6168..fb69feab3 100644 --- a/src/conference/remote-conference-event-handler-p.h +++ b/src/conference/handlers/remote-conference-event-handler-p.h @@ -20,7 +20,9 @@ #ifndef _REMOTE_CONFERENCE_EVENT_HANDLER_P_H_ #define _REMOTE_CONFERENCE_EVENT_HANDLER_P_H_ -#include "address/address.h" +#include "linphone/types.h" + +#include "chat/chat-room/chat-room-id.h" #include "object/object-p.h" #include "remote-conference-event-handler.h" @@ -30,10 +32,11 @@ LINPHONE_BEGIN_NAMESPACE class RemoteConferenceEventHandlerPrivate : public ObjectPrivate { private: - LinphoneCore *core = nullptr; - ConferenceListener *listener = nullptr; - Address confAddress; + ChatRoomId chatRoomId; + + RemoteConference *conf = nullptr; LinphoneEvent *lev = nullptr; + unsigned int lastNotify = 0; L_DECLARE_PUBLIC(RemoteConferenceEventHandler); diff --git a/src/conference/remote-conference-event-handler.cpp b/src/conference/handlers/remote-conference-event-handler.cpp similarity index 73% rename from src/conference/remote-conference-event-handler.cpp rename to src/conference/handlers/remote-conference-event-handler.cpp index 01bd441a7..df4b8b56a 100644 --- a/src/conference/remote-conference-event-handler.cpp +++ b/src/conference/handlers/remote-conference-event-handler.cpp @@ -17,13 +17,17 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "address/identity-address.h" -#include "private.h" +#include "linphone/utils/utils.h" + +#include "conference/remote-conference.h" +#include "core/core.h" #include "logger/logger.h" #include "remote-conference-event-handler-p.h" -#include "linphone/utils/utils.h" #include "xml/conference-info.h" +// TODO: Remove me later. +#include "private.h" + // ============================================================================= using namespace std; @@ -34,12 +38,11 @@ using namespace Xsd::ConferenceInfo; // ----------------------------------------------------------------------------- -RemoteConferenceEventHandler::RemoteConferenceEventHandler (LinphoneCore *core, ConferenceListener *listener) - : Object(*new RemoteConferenceEventHandlerPrivate) { +RemoteConferenceEventHandler::RemoteConferenceEventHandler (RemoteConference *remoteConference) : +Object(*new RemoteConferenceEventHandlerPrivate) { L_D(); xercesc::XMLPlatformUtils::Initialize(); - d->core = core; - d->listener = listener; + d->conf = remoteConference; // TODO : d->lastNotify = lastNotify } @@ -49,11 +52,11 @@ RemoteConferenceEventHandler::~RemoteConferenceEventHandler () { // ----------------------------------------------------------------------------- -void RemoteConferenceEventHandler::subscribe (const Address &addr) { +void RemoteConferenceEventHandler::subscribe (const ChatRoomId &chatRoomId) { L_D(); - d->confAddress = addr; - LinphoneAddress *lAddr = linphone_address_new(d->confAddress.asString().c_str()); - d->lev = linphone_core_create_subscribe(d->core, lAddr, "conference", 600); + d->chatRoomId = chatRoomId; + LinphoneAddress *lAddr = linphone_address_new(d->chatRoomId.getPeerAddress().asString().c_str()); + d->lev = linphone_core_create_subscribe(d->conf->getCore()->getCCore(), lAddr, "conference", 600); linphone_event_add_custom_header(d->lev, "Last-Notify-Version", Utils::toString(d->lastNotify).c_str()); linphone_address_unref(lAddr); linphone_event_set_internal(d->lev, TRUE); @@ -71,7 +74,10 @@ void RemoteConferenceEventHandler::unsubscribe () { void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { L_D(); - lInfo() << "NOTIFY received for conference " << d->confAddress.asString(); + + lInfo() << "NOTIFY received for conference: (remote=" << d->chatRoomId.getPeerAddress().asString() << + ", local=" << d->chatRoomId.getLocalAddress().asString() << ")."; + istringstream data(xmlBody); unique_ptr confInfo = parseConferenceInfo(data, Xsd::XmlSchema::Flags::dont_validate); time_t tm = time(nullptr); @@ -79,20 +85,23 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { tm = static_cast(Utils::stoll(confInfo->getConferenceDescription()->getFreeText().get())); bool isFullState = (confInfo->getState() == StateType::full); - IdentityAddress simpleConfAddress(d->confAddress); - // Temporary workaround + + ConferenceListener *confListener = static_cast(d->conf); + + // TODO: Temporary workaround, remove me. + const IdentityAddress &peerAddress = d->chatRoomId.getPeerAddress(); IdentityAddress entityAddress(confInfo->getEntity().c_str()); - IdentityAddress simpleConfAddress2(simpleConfAddress); - simpleConfAddress2.setDomain(entityAddress.getDomain()); - if ((entityAddress == simpleConfAddress) || (entityAddress == simpleConfAddress2)) { + IdentityAddress peerAddressWorkaround = peerAddress; + peerAddressWorkaround.setDomain(entityAddress.getDomain()); + if ((entityAddress == peerAddress) || (entityAddress == peerAddressWorkaround)) { if ( confInfo->getConferenceDescription().present() && confInfo->getConferenceDescription().get().getSubject().present() ) - d->listener->onSubjectChanged( + confListener->onSubjectChanged( make_shared( tm, - d->confAddress, + d->chatRoomId, d->lastNotify, confInfo->getConferenceDescription().get().getSubject().get() ), @@ -105,16 +114,16 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { return; for (const auto &user : confInfo->getUsers()->getUser()) { - LinphoneAddress *cAddr = linphone_core_interpret_url(d->core, user.getEntity()->c_str()); + LinphoneAddress *cAddr = linphone_core_interpret_url(d->conf->getCore()->getCCore(), user.getEntity()->c_str()); char *cAddrStr = linphone_address_as_string(cAddr); Address addr(cAddrStr); bctbx_free(cAddrStr); if (user.getState() == StateType::deleted) { - d->listener->onParticipantRemoved( + confListener->onParticipantRemoved( make_shared( EventLog::Type::ConferenceParticipantRemoved, tm, - d->confAddress, + d->chatRoomId, d->lastNotify, addr ), @@ -132,11 +141,11 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { } if (user.getState() == StateType::full) { - d->listener->onParticipantAdded( + confListener->onParticipantAdded( make_shared( EventLog::Type::ConferenceParticipantAdded, tm, - d->confAddress, + d->chatRoomId, d->lastNotify, addr ), @@ -144,11 +153,11 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { ); } - d->listener->onParticipantSetAdmin( + confListener->onParticipantSetAdmin( make_shared( isAdmin ? EventLog::Type::ConferenceParticipantSetAdmin : EventLog::Type::ConferenceParticipantUnsetAdmin, tm, - d->confAddress, + d->chatRoomId, d->lastNotify, addr ), @@ -161,11 +170,11 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { Address gruu(endpoint.getEntity().get()); if (endpoint.getState() == StateType::deleted) { - d->listener->onParticipantDeviceRemoved( + confListener->onParticipantDeviceRemoved( make_shared( EventLog::Type::ConferenceParticipantDeviceRemoved, tm, - d->confAddress, + d->chatRoomId, d->lastNotify, addr, gruu @@ -173,11 +182,11 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { isFullState ); } else if (endpoint.getState() == StateType::full) { - d->listener->onParticipantDeviceAdded( + confListener->onParticipantDeviceAdded( make_shared( EventLog::Type::ConferenceParticipantDeviceAdded, tm, - d->confAddress, + d->chatRoomId, d->lastNotify, addr, gruu @@ -191,15 +200,15 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { } if (isFullState) - d->listener->onFirstNotifyReceived(d->confAddress); + confListener->onFirstNotifyReceived(d->chatRoomId.getPeerAddress()); } } // ----------------------------------------------------------------------------- -const Address &RemoteConferenceEventHandler::getConfAddress () const { +const ChatRoomId &RemoteConferenceEventHandler::getChatRoomId () const { L_D(); - return d->confAddress; + return d->chatRoomId; } unsigned int RemoteConferenceEventHandler::getLastNotify () const { diff --git a/src/conference/remote-conference-event-handler.h b/src/conference/handlers/remote-conference-event-handler.h similarity index 66% rename from src/conference/remote-conference-event-handler.h rename to src/conference/handlers/remote-conference-event-handler.h index 2422fdb8d..7598283d2 100644 --- a/src/conference/remote-conference-event-handler.h +++ b/src/conference/handlers/remote-conference-event-handler.h @@ -20,31 +20,33 @@ #ifndef _REMOTE_CONFERENCE_EVENT_HANDLER_H_ #define _REMOTE_CONFERENCE_EVENT_HANDLER_H_ -#include - -#include "conference-listener.h" #include "object/object.h" +// ============================================================================= + LINPHONE_BEGIN_NAMESPACE +class ChatRoomId; +class RemoteConference; class RemoteConferenceEventHandlerPrivate; class RemoteConferenceEventHandler : public Object { - public: - RemoteConferenceEventHandler (LinphoneCore *core, ConferenceListener *listener); - ~RemoteConferenceEventHandler (); +public: + RemoteConferenceEventHandler (RemoteConference *remoteConference); + ~RemoteConferenceEventHandler (); - void subscribe (const Address &confAddress); - void notifyReceived (const std::string &xmlBody); - void unsubscribe (); + void subscribe (const ChatRoomId &chatRoomId); + void notifyReceived (const std::string &xmlBody); + void unsubscribe (); - const Address &getConfAddress () const; - unsigned int getLastNotify () const; - void resetLastNotify (); + const ChatRoomId &getChatRoomId () const; - private: - L_DECLARE_PRIVATE(RemoteConferenceEventHandler); - L_DISABLE_COPY(RemoteConferenceEventHandler); + unsigned int getLastNotify () const; + void resetLastNotify (); + +private: + L_DECLARE_PRIVATE(RemoteConferenceEventHandler); + L_DISABLE_COPY(RemoteConferenceEventHandler); }; LINPHONE_END_NAMESPACE diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index 11e41e4e8..36ad2cf57 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "local-conference-event-handler.h" +#include "handlers/local-conference-event-handler.h" #include "local-conference-p.h" #include "participant-p.h" #include "xml/resource-lists.h" @@ -28,10 +28,10 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -LocalConference::LocalConference (LinphoneCore *core, const Address &myAddress, CallListener *listener) - : Conference(*new LocalConferencePrivate, core, myAddress, listener) { +LocalConference::LocalConference (const shared_ptr &core, const Address &myAddress, CallListener *listener) + : CoreAccessor(core), Conference(*new LocalConferencePrivate, core, myAddress, listener) { L_D(); - d->eventHandler.reset(new LocalConferenceEventHandler(core, this)); + d->eventHandler.reset(new LocalConferenceEventHandler(this)); } // ----------------------------------------------------------------------------- diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h index f27b8f75b..58198518e 100644 --- a/src/conference/local-conference.h +++ b/src/conference/local-conference.h @@ -32,7 +32,7 @@ class LocalConference : public Conference { friend class ServerGroupChatRoomPrivate; public: - LocalConference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); + LocalConference (const std::shared_ptr &core, const Address &myAddress, CallListener *listener = nullptr); /* ConferenceInterface */ void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index c93dde6ce..194a1235c 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -17,8 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "handlers/remote-conference-event-handler.h" #include "participant-p.h" -#include "remote-conference-event-handler.h" #include "remote-conference-p.h" #include "xml/resource-lists.h" @@ -28,10 +28,13 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -RemoteConference::RemoteConference (LinphoneCore *core, const Address &myAddress, CallListener *listener) - : Conference(*new RemoteConferencePrivate, core, myAddress, listener) { +RemoteConference::RemoteConference ( + const shared_ptr &core, + const Address &myAddress, + CallListener *listener +) : CoreAccessor(core), Conference(*new RemoteConferencePrivate, core, myAddress, listener) { L_D(); - d->eventHandler.reset(new RemoteConferenceEventHandler(core, this)); + d->eventHandler.reset(new RemoteConferenceEventHandler(this)); } RemoteConference::~RemoteConference () { diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index bf630cfb1..fa85faeb6 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -22,6 +22,7 @@ #include "conference-listener.h" #include "conference.h" +#include "core/core-accessor.h" // ============================================================================= @@ -33,7 +34,7 @@ class LINPHONE_PUBLIC RemoteConference : public Conference, public ConferenceLis friend class ClientGroupChatRoomPrivate; public: - RemoteConference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr); + RemoteConference (const std::shared_ptr &core, const Address &myAddress, CallListener *listener = nullptr); virtual ~RemoteConference(); /* ConferenceInterface */ diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index ccb20d225..fe11ac162 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -22,11 +22,11 @@ #include "c-wrapper/c-wrapper.h" #include "address/address-p.h" -#include "conference/session/call-session-p.h" #include "call/call-p.h" #include "conference/params/call-session-params-p.h" - +#include "conference/session/call-session-p.h" #include "conference/session/call-session.h" +#include "core/core.h" #include "logger/logger.h" @@ -45,7 +45,7 @@ CallSessionPrivate::CallSessionPrivate (const Conference &conference, const Call if (params) this->params = new CallSessionParams(*params); currentParams = new CallSessionParams(); - core = conference.getCore(); + core = conference.getCore()->getCCore(); ei = linphone_error_info_new(); } diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 52969d8df..ff4d64310 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -20,10 +20,7 @@ #include #include -// TODO: Remove me. -#ifdef SOCI_ENABLED - #undef SOCI_ENABLED -#endif +#undef SOCI_ENABLED #ifdef SOCI_ENABLED #include @@ -635,7 +632,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS chat_room (" // Server (for conference) or user sip address. - " peer_sip_address_id" + primaryKeyStr("BIGINT UNSIGNED") + "," + " peer_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + + " local_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," // Dialog creation date. " creation_date DATE NOT NULL," @@ -651,9 +650,13 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " last_notify_id INT UNSIGNED," + " PRIMARY KEY (peer_sip_address_id, local_sip_address_id)," " FOREIGN KEY (peer_sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" + " FOREIGN KEY (local_sip_address_id)" + " REFERENCES sip_address(id)" + " ON DELETE CASCADE" ") " + charset; *session << diff --git a/src/event-log/conference/conference-chat-message-event.cpp b/src/event-log/conference/conference-chat-message-event.cpp index a33819fc2..c3dc766c0 100644 --- a/src/event-log/conference/conference-chat-message-event.cpp +++ b/src/event-log/conference/conference-chat-message-event.cpp @@ -18,6 +18,7 @@ */ #include "chat/chat-message/chat-message.h" +#include "chat/chat-room/chat-room.h" #include "conference-chat-message-event.h" #include "conference-event-p.h" @@ -43,7 +44,7 @@ ConferenceChatMessageEvent::ConferenceChatMessageEvent ( *new ConferenceChatMessageEventPrivate, EventLog::Type::ConferenceChatMessage, creationTime, - chatMessage->getRemoteAddress() + chatMessage->getChatRoom()->getChatRoomId() ) { L_D(); L_ASSERT(chatMessage); diff --git a/src/event-log/conference/conference-event-p.h b/src/event-log/conference/conference-event-p.h index ac633fb7c..18f11ad66 100644 --- a/src/event-log/conference/conference-event-p.h +++ b/src/event-log/conference/conference-event-p.h @@ -20,7 +20,7 @@ #ifndef _CONFERENCE_EVENT_P_H_ #define _CONFERENCE_EVENT_P_H_ -#include "address/identity-address.h" +#include "chat/chat-room/chat-room-id.h" #include "conference-event.h" #include "event-log/event-log-p.h" @@ -30,7 +30,7 @@ LINPHONE_BEGIN_NAMESPACE class ConferenceEventPrivate : public EventLogPrivate { private: - IdentityAddress conferenceAddress; + ChatRoomId chatRoomId; L_DECLARE_PUBLIC(ConferenceEvent); }; diff --git a/src/event-log/conference/conference-event.cpp b/src/event-log/conference/conference-event.cpp index 38d39206b..5f6d88bb8 100644 --- a/src/event-log/conference/conference-event.cpp +++ b/src/event-log/conference/conference-event.cpp @@ -27,26 +27,26 @@ LINPHONE_BEGIN_NAMESPACE // ----------------------------------------------------------------------------- -ConferenceEvent::ConferenceEvent (Type type, time_t creationTime, const IdentityAddress &conferenceAddress) : +ConferenceEvent::ConferenceEvent (Type type, time_t creationTime, const ChatRoomId &chatRoomId) : EventLog(*new ConferenceEventPrivate, type, creationTime) { L_D(); L_ASSERT(type == Type::ConferenceCreated || type == Type::ConferenceDestroyed); - d->conferenceAddress = conferenceAddress; + d->chatRoomId = chatRoomId; } ConferenceEvent::ConferenceEvent ( ConferenceEventPrivate &p, Type type, time_t creationTime, - const IdentityAddress &conferenceAddress + const ChatRoomId &chatRoomId ) : EventLog(p, type, creationTime) { L_D(); - d->conferenceAddress = conferenceAddress; + d->chatRoomId = chatRoomId; } -const IdentityAddress &ConferenceEvent::getConferenceAddress () const { +const ChatRoomId &ConferenceEvent::getChatRoomId () const { L_D(); - return d->conferenceAddress; + return d->chatRoomId; } LINPHONE_END_NAMESPACE diff --git a/src/event-log/conference/conference-event.h b/src/event-log/conference/conference-event.h index 25cdf9a10..077c971f6 100644 --- a/src/event-log/conference/conference-event.h +++ b/src/event-log/conference/conference-event.h @@ -27,16 +27,16 @@ LINPHONE_BEGIN_NAMESPACE class ConferenceEventPrivate; -class IdentityAddress; +class ChatRoomId; class LINPHONE_PUBLIC ConferenceEvent : public EventLog { public: - ConferenceEvent (Type type, time_t creationTime, const IdentityAddress &conferenceAddress); + ConferenceEvent (Type type, time_t creationTime, const ChatRoomId &chatRoomId); - const IdentityAddress &getConferenceAddress () const; + const ChatRoomId &getChatRoomId () const; protected: - ConferenceEvent (ConferenceEventPrivate &p, Type type, time_t creationTime, const IdentityAddress &conferenceAddress); + ConferenceEvent (ConferenceEventPrivate &p, Type type, time_t creationTime, const ChatRoomId &chatRoomId); private: L_DECLARE_PRIVATE(ConferenceEvent); diff --git a/src/event-log/conference/conference-notified-event.cpp b/src/event-log/conference/conference-notified-event.cpp index 4f36e6d7d..372a7e30e 100644 --- a/src/event-log/conference/conference-notified-event.cpp +++ b/src/event-log/conference/conference-notified-event.cpp @@ -30,9 +30,9 @@ LINPHONE_BEGIN_NAMESPACE ConferenceNotifiedEvent::ConferenceNotifiedEvent ( Type type, time_t creationTime, - const IdentityAddress &conferenceAddress, + const ChatRoomId &chatRoomId, unsigned int notifyId -) : ConferenceEvent(*new ConferenceNotifiedEventPrivate, type, creationTime, conferenceAddress) { +) : ConferenceEvent(*new ConferenceNotifiedEventPrivate, type, creationTime, chatRoomId) { L_D(); d->notifyId = notifyId; } @@ -41,9 +41,9 @@ ConferenceNotifiedEvent::ConferenceNotifiedEvent ( ConferenceNotifiedEventPrivate &p, Type type, time_t creationTime, - const IdentityAddress &conferenceAddress, + const ChatRoomId &chatRoomId, unsigned int notifyId -) : ConferenceEvent(p, type, creationTime, conferenceAddress) { +) : ConferenceEvent(p, type, creationTime, chatRoomId) { L_D(); d->notifyId = notifyId; } diff --git a/src/event-log/conference/conference-notified-event.h b/src/event-log/conference/conference-notified-event.h index f93dd0402..1520d930e 100644 --- a/src/event-log/conference/conference-notified-event.h +++ b/src/event-log/conference/conference-notified-event.h @@ -32,7 +32,7 @@ class LINPHONE_PUBLIC ConferenceNotifiedEvent : public ConferenceEvent { public: ConferenceNotifiedEvent ( Type type, time_t creationTime, - const IdentityAddress &conferenceAddress, + const ChatRoomId &chatRoomId, unsigned int notifiyId ); @@ -43,7 +43,7 @@ protected: ConferenceNotifiedEventPrivate &p, Type type, time_t creationTime, - const IdentityAddress &conferenceAddress, + const ChatRoomId &chatRoomId, unsigned int notifyId ); diff --git a/src/event-log/conference/conference-participant-device-event.cpp b/src/event-log/conference/conference-participant-device-event.cpp index 9f44bd540..682618d69 100644 --- a/src/event-log/conference/conference-participant-device-event.cpp +++ b/src/event-log/conference/conference-participant-device-event.cpp @@ -38,7 +38,7 @@ public: ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent ( Type type, time_t creationTime, - const IdentityAddress &conferenceAddress, + const ChatRoomId &chatRoomId, unsigned int notifyId, const IdentityAddress &participantAddress, const IdentityAddress &deviceAddress @@ -46,7 +46,7 @@ ConferenceParticipantDeviceEvent::ConferenceParticipantDeviceEvent ( *new ConferenceParticipantDeviceEventPrivate, type, creationTime, - conferenceAddress, + chatRoomId, notifyId, participantAddress ) { diff --git a/src/event-log/conference/conference-participant-device-event.h b/src/event-log/conference/conference-participant-device-event.h index 62f9a3ed9..979f48061 100644 --- a/src/event-log/conference/conference-participant-device-event.h +++ b/src/event-log/conference/conference-participant-device-event.h @@ -33,7 +33,7 @@ public: ConferenceParticipantDeviceEvent ( Type type, time_t creationTime, - const IdentityAddress &conferenceAddress, + const ChatRoomId &chatRoomId, unsigned int notifyId, const IdentityAddress &participantAddress, const IdentityAddress &deviceAddress diff --git a/src/event-log/conference/conference-participant-event.cpp b/src/event-log/conference/conference-participant-event.cpp index 0c9c3c4aa..d50b86633 100644 --- a/src/event-log/conference/conference-participant-event.cpp +++ b/src/event-log/conference/conference-participant-event.cpp @@ -30,14 +30,14 @@ LINPHONE_BEGIN_NAMESPACE ConferenceParticipantEvent::ConferenceParticipantEvent ( Type type, time_t creationTime, - const IdentityAddress &conferenceAddress, + const ChatRoomId &chatRoomId, unsigned int notifyId, const IdentityAddress &participantAddress ) : ConferenceNotifiedEvent( *new ConferenceParticipantEventPrivate, type, creationTime, - conferenceAddress, + chatRoomId, notifyId ) { L_D(); @@ -54,14 +54,14 @@ ConferenceParticipantEvent::ConferenceParticipantEvent ( ConferenceParticipantEventPrivate &p, Type type, time_t creationTime, - const IdentityAddress &conferenceAddress, + const ChatRoomId &chatRoomId, unsigned int notifyId, const IdentityAddress &participantAddress ) : ConferenceNotifiedEvent( p, type, creationTime, - conferenceAddress, + chatRoomId, notifyId ) { L_D(); diff --git a/src/event-log/conference/conference-participant-event.h b/src/event-log/conference/conference-participant-event.h index 76731dcbc..20f5e71de 100644 --- a/src/event-log/conference/conference-participant-event.h +++ b/src/event-log/conference/conference-participant-event.h @@ -27,13 +27,14 @@ LINPHONE_BEGIN_NAMESPACE class ConferenceParticipantEventPrivate; +class IdentityAddress; class LINPHONE_PUBLIC ConferenceParticipantEvent : public ConferenceNotifiedEvent { public: ConferenceParticipantEvent ( Type type, time_t creationTime, - const IdentityAddress &conferenceAddress, + const ChatRoomId &ChatRoomId, unsigned int notifyId, const IdentityAddress &participantAddress ); @@ -45,7 +46,7 @@ protected: ConferenceParticipantEventPrivate &p, Type type, time_t creationTime, - const IdentityAddress &conferenceAddress, + const ChatRoomId &ChatRoomId, unsigned int notifyId, const IdentityAddress &participantAddress ); diff --git a/src/event-log/conference/conference-subject-event.cpp b/src/event-log/conference/conference-subject-event.cpp index 7d084e82d..55c7c8ae7 100644 --- a/src/event-log/conference/conference-subject-event.cpp +++ b/src/event-log/conference/conference-subject-event.cpp @@ -37,14 +37,14 @@ public: ConferenceSubjectEvent::ConferenceSubjectEvent ( time_t creationTime, - const IdentityAddress &conferenceAddress, + const ChatRoomId &chatRoomId, unsigned int notifyId, const string &subject ) : ConferenceNotifiedEvent( *new ConferenceSubjectEventPrivate, Type::ConferenceSubjectChanged, creationTime, - conferenceAddress, + chatRoomId, notifyId ) { L_D(); diff --git a/src/event-log/conference/conference-subject-event.h b/src/event-log/conference/conference-subject-event.h index 7eba0cab2..d36d47fe3 100644 --- a/src/event-log/conference/conference-subject-event.h +++ b/src/event-log/conference/conference-subject-event.h @@ -34,7 +34,7 @@ class LINPHONE_PUBLIC ConferenceSubjectEvent : public ConferenceNotifiedEvent { public: ConferenceSubjectEvent ( time_t creationTime, - const IdentityAddress &conferenceAddress, + const ChatRoomId &chatRoomId, unsigned int notifyId, const std::string &subject ); From 1ca9d64af87fd88baa009c5fac2200c4ccb27574 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 17 Nov 2017 15:48:43 +0100 Subject: [PATCH 0798/2215] feat(core): avoid virtual inheritance of CoreAccessor --- src/chat/chat-room/basic-chat-room.cpp | 4 +- src/chat/chat-room/chat-room.cpp | 2 +- src/chat/chat-room/chat-room.h | 2 +- src/chat/chat-room/client-group-chat-room.cpp | 7 ++- src/chat/chat-room/client-group-chat-room.h | 2 + .../chat-room/real-time-text-chat-room.cpp | 2 +- .../chat-room/server-group-chat-room-stub.cpp | 2 +- src/conference/conference.h | 2 +- src/conference/local-conference.cpp | 2 +- src/conference/remote-conference.cpp | 2 +- tester/conference-event-tester.cpp | 58 ++++++++++--------- 11 files changed, 46 insertions(+), 39 deletions(-) diff --git a/src/chat/chat-room/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp index 985b09519..a02a58657 100644 --- a/src/chat/chat-room/basic-chat-room.cpp +++ b/src/chat/chat-room/basic-chat-room.cpp @@ -30,13 +30,13 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE BasicChatRoom::BasicChatRoom (const shared_ptr &core, const ChatRoomId &chatRoomId) : - BasicChatRoom(*new BasicChatRoomPrivate, core, chatRoomId) {} + ChatRoom(*new BasicChatRoomPrivate, core, chatRoomId) {} BasicChatRoom::BasicChatRoom ( BasicChatRoomPrivate &p, const std::shared_ptr &core, const ChatRoomId &chatRoomId -) : CoreAccessor(core), ChatRoom(p, core, chatRoomId) {} +) : ChatRoom(p, core, chatRoomId) {} BasicChatRoom::CapabilitiesMask BasicChatRoom::getCapabilities () const { return static_cast(Capabilities::Basic); diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 0e2b77c6c..cc9b2e5b7 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -449,7 +449,7 @@ void ChatRoomPrivate::onIsComposingRefreshNeeded () { // ============================================================================= ChatRoom::ChatRoom (ChatRoomPrivate &p, const shared_ptr &core, const ChatRoomId &chatRoomId) : - CoreAccessor(core), Object(p) { + Object(p), CoreAccessor(core) { L_D(); d->chatRoomId = chatRoomId; diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index 51f4c59cd..b11d28d93 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -30,7 +30,7 @@ LINPHONE_BEGIN_NAMESPACE class ChatRoomPrivate; -class LINPHONE_PUBLIC ChatRoom : public Object, virtual public CoreAccessor, public ConferenceInterface { +class LINPHONE_PUBLIC ChatRoom : public Object, public CoreAccessor, public ConferenceInterface { friend class Core; friend class CorePrivate; friend class ChatMessage; diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 5d22c36a9..9c70f7bc1 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -81,14 +81,17 @@ ClientGroupChatRoom::ClientGroupChatRoom ( const std::string &factoryUri, const IdentityAddress &me, const std::string &subject -) : CoreAccessor(core), -ChatRoom(*new ClientGroupChatRoomPrivate, core, ChatRoomId(IdentityAddress(), me)), +) : ChatRoom(*new ClientGroupChatRoomPrivate, core, ChatRoomId(IdentityAddress(), me)), RemoteConference(core, me, nullptr) { L_D_T(RemoteConference, dConference); dConference->focus = make_shared(Address(factoryUri)); RemoteConference::setSubject(subject); } +shared_ptr ClientGroupChatRoom::getCore () const { + return ChatRoom::getCore(); +} + ClientGroupChatRoom::CapabilitiesMask ClientGroupChatRoom::getCapabilities () const { return static_cast(Capabilities::Conference); } diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 6d63aa704..3edaabb55 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -39,6 +39,8 @@ public: const std::string &subject ); + std::shared_ptr getCore () const; + CapabilitiesMask getCapabilities () const override; const Address &getConferenceAddress () const override; diff --git a/src/chat/chat-room/real-time-text-chat-room.cpp b/src/chat/chat-room/real-time-text-chat-room.cpp index 7a8cb8ef6..d4ed5ee45 100644 --- a/src/chat/chat-room/real-time-text-chat-room.cpp +++ b/src/chat/chat-room/real-time-text-chat-room.cpp @@ -104,7 +104,7 @@ void RealTimeTextChatRoomPrivate::sendMessage (const shared_ptr &ms // ============================================================================= RealTimeTextChatRoom::RealTimeTextChatRoom (const shared_ptr &core, const ChatRoomId &chatRoomId) : - CoreAccessor(core), BasicChatRoom(*new RealTimeTextChatRoomPrivate, core, chatRoomId) {} + BasicChatRoom(*new RealTimeTextChatRoomPrivate, core, chatRoomId) {} RealTimeTextChatRoom::CapabilitiesMask RealTimeTextChatRoom::getCapabilities () const { return BasicChatRoom::getCapabilities() | static_cast(Capabilities::RealTimeText); diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index a1fe25c89..97e694bc3 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -77,7 +77,7 @@ bool ServerGroupChatRoomPrivate::isAdminLeft () const { // ============================================================================= -ServerGroupChatRoom::ServerGroupChatRoom (const shared_ptr &core, SalCallOp *op) : CoreAccessor(core), +ServerGroupChatRoom::ServerGroupChatRoom (const shared_ptr &core, SalCallOp *op) : ChatRoom(*new ServerGroupChatRoomPrivate, core, ChatRoomId(IdentityAddress(op->get_to()), IdentityAddress(op->get_to()))), LocalConference(core, Address(op->get_to()), nullptr) {} diff --git a/src/conference/conference.h b/src/conference/conference.h index 6489a11b4..d89536343 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -37,7 +37,7 @@ class ConferencePrivate; class LINPHONE_PUBLIC Conference : public ConferenceInterface, public CallSessionListener, - virtual public CoreAccessor { + public CoreAccessor { friend class CallSessionPrivate; public: diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index 36ad2cf57..203e899cd 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -29,7 +29,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE LocalConference::LocalConference (const shared_ptr &core, const Address &myAddress, CallListener *listener) - : CoreAccessor(core), Conference(*new LocalConferencePrivate, core, myAddress, listener) { + : Conference(*new LocalConferencePrivate, core, myAddress, listener) { L_D(); d->eventHandler.reset(new LocalConferenceEventHandler(this)); } diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index 194a1235c..603939bbf 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -32,7 +32,7 @@ RemoteConference::RemoteConference ( const shared_ptr &core, const Address &myAddress, CallListener *listener -) : CoreAccessor(core), Conference(*new RemoteConferencePrivate, core, myAddress, listener) { +) : Conference(*new RemoteConferencePrivate, core, myAddress, listener) { L_D(); d->eventHandler.reset(new RemoteConferenceEventHandler(this)); } diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index db70d0896..ff1ae2930 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -19,12 +19,14 @@ #include #include +#include "address/identity-address.h" #include "conference/conference-listener.h" -#include "conference/local-conference-event-handler-p.h" +#include "conference/handlers/local-conference-event-handler-p.h" +#include "conference/handlers/remote-conference-event-handler-p.h" #include "conference/local-conference-p.h" #include "conference/local-conference.h" #include "conference/participant-p.h" -#include "conference/remote-conference-event-handler-p.h" +#include "conference/remote-conference.h" #include "liblinphone_tester.h" #include "linphone/core.h" #include "private.h" @@ -440,7 +442,7 @@ static const char *confUri = "sips:conf233@example.com"; L_ENABLE_ATTR_ACCESS(LocalConferencePrivate, unique_ptr, eventHandler); -class ConferenceEventTester : public ConferenceListener { +class ConferenceEventTester : public RemoteConference { public: ConferenceEventTester (LinphoneCore *core, const Address &confAddr); ~ConferenceEventTester (); @@ -463,8 +465,8 @@ public: string confSubject; }; -ConferenceEventTester::ConferenceEventTester (LinphoneCore *core, const Address &confAddr) { - handler = new RemoteConferenceEventHandler(core, this); +ConferenceEventTester::ConferenceEventTester (LinphoneCore *core, const Address &confAddr) : RemoteConference(core->cppCore, confAddr) { + handler = new RemoteConferenceEventHandler(this); } ConferenceEventTester::~ConferenceEventTester () { @@ -533,7 +535,7 @@ void first_notify_parsing() { size_t size = strlen(first_notify) + strlen(confUri); char *notify = new char[size]; - const_cast
      (tester.handler->getConfAddress()) = addr; + const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -570,7 +572,7 @@ void first_notify_parsing_wrong_conf() { size_t size = strlen(first_notify) + strlen(confUri); char *notify = new char[size]; - const_cast
      (tester.handler->getConfAddress()) = addr; + const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -601,7 +603,7 @@ void participant_added_parsing() { size_t size2 = strlen(participant_added_notify) + strlen(confUri); char *notify_added = new char[size2]; - const_cast
      (tester.handler->getConfAddress()) = addr; + const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -646,7 +648,7 @@ void participant_not_added_parsing() { size_t size2 = strlen(participant_not_added_notify) + strlen(confUri); char *notify_not_added = new char[size2]; - const_cast
      (tester.handler->getConfAddress()) = addr; + const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -688,7 +690,7 @@ void participant_deleted_parsing() { size_t size2 = strlen(participant_deleted_notify) + strlen(confUri); char *notify_deleted = new char[size2]; - const_cast
      (tester.handler->getConfAddress()) = addr; + const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -730,7 +732,7 @@ void participant_admined_parsing() { size_t size2 = strlen(participant_admined_notify) + strlen(confUri); char *notify_admined = new char[size2]; - const_cast
      (tester.handler->getConfAddress()) = addr; + const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -771,7 +773,7 @@ void participant_unadmined_parsing() { size_t size2 = strlen(participant_unadmined_notify) + strlen(confUri); char *notify_unadmined = new char[size2]; - const_cast
      (tester.handler->getConfAddress()) = addr; + const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; snprintf(notify, size, first_notify, confUri); tester.handler->notifyReceived(notify); @@ -804,7 +806,7 @@ void send_first_notify() { Address addr(identityStr); bctbx_free(identityStr); ConferenceEventTester tester(marie->lc, addr); - LocalConference localConf(pauline->lc, addr); + LocalConference localConf(pauline->lc->cppCore, addr); LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); char *bobAddrStr = linphone_address_as_string(cBobAddr); Address bobAddr(bobAddrStr); @@ -828,7 +830,7 @@ void send_first_notify() { const_cast
      (localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); - const_cast
      (tester.handler->getConfAddress()) = addr; + const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; tester.handler->notifyReceived(notify); BC_ASSERT_STRING_EQUAL(tester.confSubject.c_str(), "A random test subject"); @@ -849,7 +851,7 @@ void send_added_notify() { Address addr(identityStr); bctbx_free(identityStr); ConferenceEventTester tester(marie->lc, addr); - LocalConference localConf(pauline->lc, addr); + LocalConference localConf(pauline->lc->cppCore, addr); LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); char *bobAddrStr = linphone_address_as_string(cBobAddr); Address bobAddr(bobAddrStr); @@ -877,7 +879,7 @@ void send_added_notify() { const_cast
      (localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); - const_cast
      (tester.handler->getConfAddress()) = addr; + const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; tester.handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); @@ -910,7 +912,7 @@ void send_removed_notify() { Address addr(identityStr); bctbx_free(identityStr); ConferenceEventTester tester(marie->lc, addr); - LocalConference localConf(pauline->lc, addr); + LocalConference localConf(pauline->lc->cppCore, addr); LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); char *bobAddrStr = linphone_address_as_string(cBobAddr); Address bobAddr(bobAddrStr); @@ -933,7 +935,7 @@ void send_removed_notify() { const_cast
      (localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); - const_cast
      (tester.handler->getConfAddress()) = addr; + const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; tester.handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); @@ -963,7 +965,7 @@ void send_admined_notify() { Address addr(identityStr); bctbx_free(identityStr); ConferenceEventTester tester(marie->lc, addr); - LocalConference localConf(pauline->lc, addr); + LocalConference localConf(pauline->lc->cppCore, addr); LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); char *bobAddrStr = linphone_address_as_string(cBobAddr); Address bobAddr(bobAddrStr); @@ -986,7 +988,7 @@ void send_admined_notify() { const_cast
      (localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); - const_cast
      (tester.handler->getConfAddress()) = addr; + const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; tester.handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester.participants.size(), 2, int, "%d"); @@ -1015,7 +1017,7 @@ void send_unadmined_notify() { Address addr(identityStr); bctbx_free(identityStr); ConferenceEventTester tester(marie->lc, addr); - LocalConference localConf(pauline->lc, addr); + LocalConference localConf(pauline->lc->cppCore, addr); LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); char *bobAddrStr = linphone_address_as_string(cBobAddr); Address bobAddr(bobAddrStr); @@ -1038,7 +1040,7 @@ void send_unadmined_notify() { const_cast
      (localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); - const_cast
      (tester.handler->getConfAddress()) = addr; + const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; tester.handler->notifyReceived(notify); @@ -1068,7 +1070,7 @@ void send_subject_changed_notify () { Address addr(identityStr); bctbx_free(identityStr); ConferenceEventTester tester(marie->lc, addr); - LocalConference localConf(pauline->lc, addr); + LocalConference localConf(pauline->lc->cppCore, addr); LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); char *bobAddrStr = linphone_address_as_string(cBobAddr); Address bobAddr(bobAddrStr); @@ -1092,7 +1094,7 @@ void send_subject_changed_notify () { const_cast
      (localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); - const_cast
      (tester.handler->getConfAddress()) = addr; + const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; tester.handler->notifyReceived(notify); BC_ASSERT_STRING_EQUAL(tester.confSubject.c_str(), "A random test subject"); @@ -1128,7 +1130,7 @@ void send_device_added_notify() { Address addr(identityStr); bctbx_free(identityStr); ConferenceEventTester tester(marie->lc, addr); - LocalConference localConf(pauline->lc, addr); + LocalConference localConf(pauline->lc->cppCore, addr); LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); char *bobAddrStr = linphone_address_as_string(cBobAddr); Address bobAddr(bobAddrStr); @@ -1151,7 +1153,7 @@ void send_device_added_notify() { const_cast
      (localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); - const_cast
      (tester.handler->getConfAddress()) = addr; + const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; tester.handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester.participantDevices.size(), 2, int, "%d"); @@ -1180,7 +1182,7 @@ void send_device_removed_notify() { Address addr(identityStr); bctbx_free(identityStr); ConferenceEventTester tester(marie->lc, addr); - LocalConference localConf(pauline->lc, addr); + LocalConference localConf(pauline->lc->cppCore, addr); LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); char *bobAddrStr = linphone_address_as_string(cBobAddr); Address bobAddr(bobAddrStr); @@ -1204,7 +1206,7 @@ void send_device_removed_notify() { const_cast
      (localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); - const_cast
      (tester.handler->getConfAddress()) = addr; + const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; tester.handler->notifyReceived(notify); BC_ASSERT_EQUAL(tester.participantDevices.size(), 2, int, "%d"); From cf7c300b070029ebfe031463111689c1cced50fe Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 17 Nov 2017 16:57:48 +0100 Subject: [PATCH 0799/2215] Use GRUU address in From header when sending messages. --- coreapi/linphonecore.c | 9 ++++++++- coreapi/proxy.c | 11 ++++++++--- src/chat/chat-message/chat-message.cpp | 21 +++++---------------- src/sal/call-op.cpp | 4 ++-- src/sal/call-op.h | 2 +- src/sal/message-op-interface.h | 5 ++--- src/sal/message-op.cpp | 17 +++++++---------- src/sal/message-op.h | 2 +- src/sal/op.h | 4 ++++ 9 files changed, 38 insertions(+), 37 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1a19a1a43..e0a23f2d2 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3542,9 +3542,11 @@ static void linphone_transfer_routes_to_op(bctbx_list_t *routes, SalOp *op){ void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact, LinphoneProxyConfig *proxy){ bctbx_list_t *routes=NULL; + const LinphoneAddress *contactAddr = nullptr; const char *identity; if (proxy){ + contactAddr = linphone_proxy_config_get_contact(proxy); identity=linphone_proxy_config_get_identity(proxy); if (linphone_proxy_config_get_privacy(proxy)!=LinphonePrivacyDefault) { op->set_privacy(linphone_proxy_config_get_privacy(proxy)); @@ -3569,7 +3571,12 @@ void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const Linphon ms_free(addr); } - op->set_from(identity); + if (op->getUseGruuInFrom() && contactAddr && linphone_address_has_uri_param(contactAddr, "gr")) { + char *contactAddrStr = linphone_address_as_string_uri_only(contactAddr); + op->set_from(contactAddrStr); + bctbx_free(contactAddrStr); + } else + op->set_from(identity); op->set_sent_custom_header(headers); op->set_realm(linphone_proxy_config_get_realm(proxy)); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 63a0af6eb..fd8bdbbd2 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1433,11 +1433,16 @@ uint8_t linphone_proxy_config_get_avpf_rr_interval(const LinphoneProxyConfig *cf const LinphoneAddress *linphone_proxy_config_get_contact (const LinphoneProxyConfig *cfg) { // Workaround for wrapping. - if (cfg->contact_address) - linphone_address_unref(cfg->contact_address); + if (cfg->contact_address) { + linphone_address_unref(cfg->contact_address); + const_cast(cfg)->contact_address = NULL; + } // Warning : Do not remove, the op can change its contact_address - char *buf = sal_address_as_string(cfg->op->get_contact_address()); + const SalAddress *salAddr = cfg->op->get_contact_address(); + if (!salAddr) + return NULL; + char *buf = sal_address_as_string(salAddr); const_cast(cfg)->contact_address = linphone_address_new(buf); ms_free(buf); diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index bf6b40df1..cab953b15 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -574,6 +574,7 @@ void ChatMessagePrivate::send () { LinphoneAddress *peer = linphone_address_new(q->getToAddress().asString().c_str()); /* Sending out of call */ salOp = op = new SalMessageOp(core->getCCore()->sal); + op->setUseGruuInFrom(true); linphone_configure_op( core->getCCore(), op, peer, getSalCustomHeaders(), !!lp_config_get_int(core->getCCore()->config, "sip", "chat_msg_with_contact", 0) @@ -630,26 +631,14 @@ void ChatMessagePrivate::send () { // End of message modification // --------------------------------------- - if (internalContent.isEmpty()) { + if (internalContent.isEmpty()) internalContent = *(contents.front()); - } auto msgOp = dynamic_cast(op); if (internalContent.getContentType().isValid()) { - msgOp->send_message( - q->getFromAddress().asString().c_str(), - q->getToAddress().asString().c_str(), - internalContent.getContentType().asString().c_str(), - internalContent.getBodyAsString().c_str(), - q->getToAddress().asString().c_str() - ); - } else { - msgOp->send_message( - q->getFromAddress().asString().c_str(), - q->getToAddress().asString().c_str(), - internalContent.getBodyAsString().c_str() - ); - } + msgOp->send_message(internalContent.getContentType().asString().c_str(), internalContent.getBodyAsString().c_str()); + } else + msgOp->send_message(ContentType::PlainText.asString().c_str(), internalContent.getBodyAsString().c_str()); for (Content *content : contents) { // Restore FileContents and remove FileTransferContents diff --git a/src/sal/call-op.cpp b/src/sal/call-op.cpp index 8fac3f4e2..bd6d4ba16 100644 --- a/src/sal/call-op.cpp +++ b/src/sal/call-op.cpp @@ -1501,10 +1501,10 @@ void SalCallOp::process_notify(const belle_sip_request_event_t *event, belle_sip } } -int SalCallOp::send_message(const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri) { +int SalCallOp::send_message(const char* content_type, const char *msg) { if (!this->dialog) return -1; belle_sip_request_t* req=belle_sip_dialog_create_queued_request(this->dialog,"MESSAGE"); - prepare_message_request(req, content_type, msg, peer_uri); + prepare_message_request(req, content_type, msg); return send_request(req); } diff --git a/src/sal/call-op.h b/src/sal/call-op.h index 82da673db..1144d78d3 100644 --- a/src/sal/call-op.h +++ b/src/sal/call-op.h @@ -65,7 +65,7 @@ public: void set_sdp_handling(SalOpSDPHandling handling); // Implementation of SalMessageOpInterface - int send_message(const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri) override; + int send_message(const char* content_type, const char *msg) override; int reply(SalReason reason) override {return SalOp::reply_message(reason);} private: diff --git a/src/sal/message-op-interface.h b/src/sal/message-op-interface.h index 3854d94a7..d53e30b0a 100644 --- a/src/sal/message-op-interface.h +++ b/src/sal/message-op-interface.h @@ -26,12 +26,11 @@ class SalMessageOpInterface { public: virtual ~SalMessageOpInterface() = default; - int send_message(const char *from, const char *to, const char *msg) {return send_message(from,to,"text/plain",msg, nullptr);} - virtual int send_message(const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri) = 0; + virtual int send_message(const char* content_type, const char *msg) = 0; virtual int reply(SalReason reason) = 0; protected: - void prepare_message_request(belle_sip_request_t *req, const char* content_type, const char *msg, const char *peer_uri); + void prepare_message_request(belle_sip_request_t *req, const char* content_type, const char *msg); }; LINPHONE_END_NAMESPACE diff --git a/src/sal/message-op.cpp b/src/sal/message-op.cpp index 697781979..85146eca5 100644 --- a/src/sal/message-op.cpp +++ b/src/sal/message-op.cpp @@ -77,7 +77,7 @@ void SalMessageOp::fill_cbs() { this->type=Type::Message; } -void SalMessageOpInterface::prepare_message_request(belle_sip_request_t *req, const char* content_type, const char *msg, const char *peer_uri) { +void SalMessageOpInterface::prepare_message_request(belle_sip_request_t *req, const char* content_type, const char *msg) { char content_type_raw[256]; size_t content_length = msg?strlen(msg):0; time_t curtime = ms_time(NULL); @@ -91,16 +91,13 @@ void SalMessageOpInterface::prepare_message_request(belle_sip_request_t *req, co } } -int SalMessageOp::send_message(const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri) { +int SalMessageOp::send_message(const char* content_type, const char *msg) { fill_cbs(); - if (from) set_from(from); - if (to) set_to(to); - this->dir=Dir::Outgoing; - - belle_sip_request_t* req=build_request("MESSAGE"); - if (req == NULL ) return -1; - if (get_contact_address()) belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(create_contact())); - prepare_message_request(req, content_type, msg, peer_uri); + this->dir = Dir::Outgoing; + belle_sip_request_t *req = build_request("MESSAGE"); + if (!req) + return -1; + prepare_message_request(req, content_type, msg); return send_request(req); } diff --git a/src/sal/message-op.h b/src/sal/message-op.h index 5f8b8b32f..73d6056b6 100644 --- a/src/sal/message-op.h +++ b/src/sal/message-op.h @@ -29,7 +29,7 @@ class SalMessageOp: public SalOp, public SalMessageOpInterface { public: SalMessageOp(Sal *sal): SalOp(sal) {} - int send_message(const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri) override; + int send_message(const char* content_type, const char *msg) override; int reply(SalReason reason) override {return SalOp::reply_message(reason);} private: diff --git a/src/sal/op.h b/src/sal/op.h index 06c009909..d461cf7fb 100644 --- a/src/sal/op.h +++ b/src/sal/op.h @@ -84,6 +84,9 @@ public: void set_sent_custom_header(SalCustomHeader* ch); + bool getUseGruuInFrom () { return useGruuInFrom; } + void setUseGruuInFrom (bool value) { useGruuInFrom = value; } + void enable_cnx_ip_to_0000_if_sendonly(bool_t yesno) {this->_cnx_ip_to_0000_if_sendonly_enabled = yesno;} bool_t cnx_ip_to_0000_if_sendonly_enabled() const {return this->_cnx_ip_to_0000_if_sendonly_enabled;} @@ -253,6 +256,7 @@ protected: bool_t has_auth_pending = FALSE; bool_t supports_session_timers = FALSE; bool_t op_released = FALSE; + bool useGruuInFrom = false; friend class Sal; }; From e1122d15f57e099a9b5f07a1e3f46d708cb50540 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 20 Nov 2017 14:52:15 +0100 Subject: [PATCH 0800/2215] add multipart notify support for conference events --- coreapi/linphonecore.c | 14 +- src/chat/chat-room/client-group-chat-room-p.h | 1 + src/chat/chat-room/client-group-chat-room.cpp | 5 + .../local-conference-event-handler-p.h | 2 + .../local-conference-event-handler.cpp | 102 ++++++- .../remote-conference-event-handler-p.h | 2 + .../remote-conference-event-handler.cpp | 263 ++++++++++-------- .../remote-conference-event-handler.h | 1 + src/conference/local-conference.cpp | 2 +- src/conference/local-conference.h | 2 +- src/content/content-manager.cpp | 12 +- src/content/content-manager.h | 12 +- src/core/core.h | 1 + tester/conference-event-tester.cpp | 4 +- tester/content-manager-tester.cpp | 26 +- 15 files changed, 285 insertions(+), 164 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index e0a23f2d2..95dd2aed2 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2142,10 +2142,16 @@ static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEve IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(from)) )); - if (chatRoom) - L_GET_PRIVATE(static_pointer_cast(chatRoom))->notifyReceived( - linphone_content_get_string_buffer(body) - ); + if (chatRoom) { + if (linphone_content_is_multipart(body)) + L_GET_PRIVATE(static_pointer_cast(chatRoom))->multipartNotifyReceived( + linphone_content_get_string_buffer(body) + ); + else + L_GET_PRIVATE(static_pointer_cast(chatRoom))->notifyReceived( + linphone_content_get_string_buffer(body) + ); + } } } diff --git a/src/chat/chat-room/client-group-chat-room-p.h b/src/chat/chat-room/client-group-chat-room-p.h index 72ffd2206..6a8871cd5 100644 --- a/src/chat/chat-room/client-group-chat-room-p.h +++ b/src/chat/chat-room/client-group-chat-room-p.h @@ -34,6 +34,7 @@ public: std::list
      cleanAddressesList (const std::list
      &addresses) const; std::shared_ptr createSession (); void notifyReceived (const std::string &body); + void multipartNotifyReceived (const std::string &body); private: L_DECLARE_PUBLIC(ClientGroupChatRoom); diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 9c70f7bc1..0661a4627 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -74,6 +74,11 @@ void ClientGroupChatRoomPrivate::notifyReceived (const string &body) { qConference->getPrivate()->eventHandler->notifyReceived(body); } +void ClientGroupChatRoomPrivate::multipartNotifyReceived (const string &body) { + L_Q_T(RemoteConference, qConference); + qConference->getPrivate()->eventHandler->multipartNotifyReceived(body); +} + // ============================================================================= ClientGroupChatRoom::ClientGroupChatRoom ( diff --git a/src/conference/handlers/local-conference-event-handler-p.h b/src/conference/handlers/local-conference-event-handler-p.h index 14211f0fa..e5822c9a9 100644 --- a/src/conference/handlers/local-conference-event-handler-p.h +++ b/src/conference/handlers/local-conference-event-handler-p.h @@ -37,6 +37,7 @@ public: void notifyAllExcept (const std::string ¬ify, const std::shared_ptr &exceptParticipant); void notifyAll (const std::string ¬ify); std::string createNotifyFullState (int notifyId = -1); + std::string createNotifyMultipart (int notifyId); std::string createNotifyParticipantAdded (const Address &addr, int notifyId = -1); std::string createNotifyParticipantRemoved (const Address &addr, int notifyId = -1); std::string createNotifyParticipantAdmined (const Address &addr, bool isAdmin, int notifyId = -1); @@ -51,6 +52,7 @@ private: unsigned int lastNotify = 0; std::string createNotify (Xsd::ConferenceInfo::ConferenceType confInfo, int notifyId = -1, bool isFullState = false); + std::string createNotifySubjectChanged (const std::string &subject, int notifyId = -1); void notifyParticipant (const std::string ¬ify, const std::shared_ptr &participant); void notifyParticipantDevice (const std::string ¬ify, const std::shared_ptr &device); diff --git a/src/conference/handlers/local-conference-event-handler.cpp b/src/conference/handlers/local-conference-event-handler.cpp index b364f4547..63a8633d2 100644 --- a/src/conference/handlers/local-conference-event-handler.cpp +++ b/src/conference/handlers/local-conference-event-handler.cpp @@ -21,8 +21,15 @@ #include "linphone/utils/utils.h" +#include "chat/chat-room/chat-room-id.h" #include "conference/local-conference.h" #include "conference/participant-p.h" +#include "content/content-manager.h" +#include "content/content-type.h" +#include "content/content.h" +#include "core/core-p.h" +#include "db/main-db.h" +#include "event-log/events.h" #include "local-conference-event-handler-p.h" #include "logger/logger.h" #include "object/object-p.h" @@ -128,6 +135,94 @@ string LocalConferenceEventHandlerPrivate::createNotifyFullState (int notifyId) return createNotify(confInfo, notifyId, true); } +string LocalConferenceEventHandlerPrivate::createNotifyMultipart (int notifyId) { + list> events = conf->getCore()->getPrivate()->mainDb->getConferenceNotifiedEvents( + ChatRoomId(conf->getConferenceAddress(), conf->getConferenceAddress()), + static_cast(notifyId) + ); + + list contents; + for (const auto &eventLog : events) { + Content content; + content.setContentType(ContentType("application","conference-info")); + string body; + shared_ptr notifiedEvent = static_pointer_cast(eventLog); + int eventNotifyId = static_cast(notifiedEvent->getNotifyId()); + switch (eventLog->getType()) { + case EventLog::Type::ConferenceParticipantAdded: { + shared_ptr addedEvent = static_pointer_cast(eventLog); + body = createNotifyParticipantAdded( + addedEvent->getParticipantAddress(), + eventNotifyId + ); + } break; + + case EventLog::Type::ConferenceParticipantRemoved: { + shared_ptr removedEvent = static_pointer_cast(eventLog); + body = createNotifyParticipantRemoved( + removedEvent->getParticipantAddress(), + eventNotifyId + ); + } break; + + case EventLog::Type::ConferenceParticipantSetAdmin: { + shared_ptr setAdminEvent = static_pointer_cast(eventLog); + body = createNotifyParticipantAdmined( + setAdminEvent->getParticipantAddress(), + true, + eventNotifyId + ); + } break; + + case EventLog::Type::ConferenceParticipantUnsetAdmin: { + shared_ptr unsetAdminEvent = static_pointer_cast(eventLog); + body = createNotifyParticipantAdmined( + unsetAdminEvent->getParticipantAddress(), + false, + eventNotifyId + ); + } break; + + case EventLog::Type::ConferenceParticipantDeviceAdded: { + shared_ptr deviceAddedEvent = static_pointer_cast(eventLog); + body = createNotifyParticipantDeviceAdded( + deviceAddedEvent->getParticipantAddress(), + deviceAddedEvent->getDeviceAddress(), + eventNotifyId + ); + } break; + + case EventLog::Type::ConferenceParticipantDeviceRemoved: { + shared_ptr deviceRemovedEvent = static_pointer_cast(eventLog); + body = createNotifyParticipantDeviceRemoved( + deviceRemovedEvent->getParticipantAddress(), + deviceRemovedEvent->getDeviceAddress(), + eventNotifyId + ); + } break; + + case EventLog::Type::ConferenceSubjectChanged: { + shared_ptr subjectEvent = static_pointer_cast(eventLog); + body = createNotifySubjectChanged( + subjectEvent->getSubject(), + eventNotifyId + ); + } break; + + default: + // We should never pass here! + L_ASSERT(false); + continue; + } + content.setBody(body); + contents.push_back(content); + } + + ContentManager contentManager; + Content multipart = contentManager.contentsListToMultipart(contents); + return multipart.getBodyAsString(); +} + string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const Address &addr, int notifyId) { string entity = conf->getConferenceAddress().asStringUriOnly(); ConferenceType confInfo = ConferenceType(entity); @@ -190,8 +285,11 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined (const } string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged (int notifyId) { + return createNotifySubjectChanged(conf->getSubject(), notifyId); +} + +string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged (const string &subject, int notifyId) { string entity = conf->getConferenceAddress().asStringUriOnly(); - string subject = conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); ConferenceDescriptionType confDescr = ConferenceDescriptionType(); confDescr.setSubject(subject); @@ -291,7 +389,7 @@ void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) { } else if (lastNotify < d->lastNotify) { lInfo() << "Sending all missed notify for conference:" << d->conf->getConferenceAddress().asStringUriOnly() << " from: " << lastNotify << " to: " << participant->getAddress().asString(); - // TODO : send all missed notify from lastNotify to d->lastNotify + d->notifyParticipantDevice(d->createNotifyMultipart(static_cast(lastNotify)), device); } else if (lastNotify > d->lastNotify) { lError() << "last notify received by client: [" << lastNotify <<"] for conference:" << d->conf->getConferenceAddress().asStringUriOnly() << diff --git a/src/conference/handlers/remote-conference-event-handler-p.h b/src/conference/handlers/remote-conference-event-handler-p.h index fb69feab3..87992f7b5 100644 --- a/src/conference/handlers/remote-conference-event-handler-p.h +++ b/src/conference/handlers/remote-conference-event-handler-p.h @@ -32,6 +32,8 @@ LINPHONE_BEGIN_NAMESPACE class RemoteConferenceEventHandlerPrivate : public ObjectPrivate { private: + void simpleNotifyReceived (const std::string &xmlBody); + ChatRoomId chatRoomId; RemoteConference *conf = nullptr; diff --git a/src/conference/handlers/remote-conference-event-handler.cpp b/src/conference/handlers/remote-conference-event-handler.cpp index df4b8b56a..2ce85abae 100644 --- a/src/conference/handlers/remote-conference-event-handler.cpp +++ b/src/conference/handlers/remote-conference-event-handler.cpp @@ -20,6 +20,8 @@ #include "linphone/utils/utils.h" #include "conference/remote-conference.h" +#include "content/content-manager.h" +#include "content/content.h" #include "core/core.h" #include "logger/logger.h" #include "remote-conference-event-handler-p.h" @@ -38,6 +40,135 @@ using namespace Xsd::ConferenceInfo; // ----------------------------------------------------------------------------- +void RemoteConferenceEventHandlerPrivate::simpleNotifyReceived (const string &xmlBody) { + istringstream data(xmlBody); + unique_ptr confInfo = parseConferenceInfo(data, Xsd::XmlSchema::Flags::dont_validate); + time_t tm = time(nullptr); + if (confInfo->getConferenceDescription()->getFreeText().present()) + tm = static_cast(Utils::stoll(confInfo->getConferenceDescription()->getFreeText().get())); + + bool isFullState = (confInfo->getState() == StateType::full); + + ConferenceListener *confListener = static_cast(conf); + + // TODO: Temporary workaround, remove me. + const IdentityAddress &peerAddress = chatRoomId.getPeerAddress(); + IdentityAddress entityAddress(confInfo->getEntity().c_str()); + IdentityAddress peerAddressWorkaround = peerAddress; + peerAddressWorkaround.setDomain(entityAddress.getDomain()); + if ((entityAddress == peerAddress) || (entityAddress == peerAddressWorkaround)) { + if ( + confInfo->getConferenceDescription().present() && + confInfo->getConferenceDescription().get().getSubject().present() + ) + confListener->onSubjectChanged( + make_shared( + tm, + chatRoomId, + lastNotify, + confInfo->getConferenceDescription().get().getSubject().get() + ), + isFullState + ); + if (confInfo->getVersion().present()) + lastNotify = confInfo->getVersion().get(); + + if (!confInfo->getUsers().present()) + return; + + for (const auto &user : confInfo->getUsers()->getUser()) { + LinphoneAddress *cAddr = linphone_core_interpret_url(conf->getCore()->getCCore(), user.getEntity()->c_str()); + char *cAddrStr = linphone_address_as_string(cAddr); + Address addr(cAddrStr); + bctbx_free(cAddrStr); + if (user.getState() == StateType::deleted) { + confListener->onParticipantRemoved( + make_shared( + EventLog::Type::ConferenceParticipantRemoved, + tm, + chatRoomId, + lastNotify, + addr + ), + isFullState + ); + } else { + bool isAdmin = false; + if (user.getRoles()) { + for (const auto &entry : user.getRoles()->getEntry()) { + if (entry == "admin") { + isAdmin = true; + break; + } + } + } + + if (user.getState() == StateType::full) { + confListener->onParticipantAdded( + make_shared( + EventLog::Type::ConferenceParticipantAdded, + tm, + chatRoomId, + lastNotify, + addr + ), + isFullState + ); + } + + confListener->onParticipantSetAdmin( + make_shared( + isAdmin ? EventLog::Type::ConferenceParticipantSetAdmin : EventLog::Type::ConferenceParticipantUnsetAdmin, + tm, + chatRoomId, + lastNotify, + addr + ), + isFullState + ); + + for (const auto &endpoint : user.getEndpoint()) { + if (!endpoint.getEntity().present()) + break; + + Address gruu(endpoint.getEntity().get()); + if (endpoint.getState() == StateType::deleted) { + confListener->onParticipantDeviceRemoved( + make_shared( + EventLog::Type::ConferenceParticipantDeviceRemoved, + tm, + chatRoomId, + lastNotify, + addr, + gruu + ), + isFullState + ); + } else if (endpoint.getState() == StateType::full) { + confListener->onParticipantDeviceAdded( + make_shared( + EventLog::Type::ConferenceParticipantDeviceAdded, + tm, + chatRoomId, + lastNotify, + addr, + gruu + ), + isFullState + ); + } + } + } + linphone_address_unref(cAddr); + } + + if (isFullState) + confListener->onFirstNotifyReceived(chatRoomId.getPeerAddress()); + } +} + +// ----------------------------------------------------------------------------- + RemoteConferenceEventHandler::RemoteConferenceEventHandler (RemoteConference *remoteConference) : Object(*new RemoteConferenceEventHandlerPrivate) { L_D(); @@ -78,129 +209,21 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { lInfo() << "NOTIFY received for conference: (remote=" << d->chatRoomId.getPeerAddress().asString() << ", local=" << d->chatRoomId.getLocalAddress().asString() << ")."; - istringstream data(xmlBody); - unique_ptr confInfo = parseConferenceInfo(data, Xsd::XmlSchema::Flags::dont_validate); - time_t tm = time(nullptr); - if (confInfo->getConferenceDescription()->getFreeText().present()) - tm = static_cast(Utils::stoll(confInfo->getConferenceDescription()->getFreeText().get())); + d->simpleNotifyReceived(xmlBody); +} - bool isFullState = (confInfo->getState() == StateType::full); +void RemoteConferenceEventHandler::multipartNotifyReceived (const string &xmlBody) { + L_D(); - ConferenceListener *confListener = static_cast(d->conf); + lInfo() << "multipart NOTIFY received for conference: (remote=" << d->chatRoomId.getPeerAddress().asString() << + ", local=" << d->chatRoomId.getLocalAddress().asString() << ")."; - // TODO: Temporary workaround, remove me. - const IdentityAddress &peerAddress = d->chatRoomId.getPeerAddress(); - IdentityAddress entityAddress(confInfo->getEntity().c_str()); - IdentityAddress peerAddressWorkaround = peerAddress; - peerAddressWorkaround.setDomain(entityAddress.getDomain()); - if ((entityAddress == peerAddress) || (entityAddress == peerAddressWorkaround)) { - if ( - confInfo->getConferenceDescription().present() && - confInfo->getConferenceDescription().get().getSubject().present() - ) - confListener->onSubjectChanged( - make_shared( - tm, - d->chatRoomId, - d->lastNotify, - confInfo->getConferenceDescription().get().getSubject().get() - ), - isFullState - ); - if (confInfo->getVersion().present()) - d->lastNotify = confInfo->getVersion().get(); - - if (!confInfo->getUsers().present()) - return; - - for (const auto &user : confInfo->getUsers()->getUser()) { - LinphoneAddress *cAddr = linphone_core_interpret_url(d->conf->getCore()->getCCore(), user.getEntity()->c_str()); - char *cAddrStr = linphone_address_as_string(cAddr); - Address addr(cAddrStr); - bctbx_free(cAddrStr); - if (user.getState() == StateType::deleted) { - confListener->onParticipantRemoved( - make_shared( - EventLog::Type::ConferenceParticipantRemoved, - tm, - d->chatRoomId, - d->lastNotify, - addr - ), - isFullState - ); - } else { - bool isAdmin = false; - if (user.getRoles()) { - for (const auto &entry : user.getRoles()->getEntry()) { - if (entry == "admin") { - isAdmin = true; - break; - } - } - } - - if (user.getState() == StateType::full) { - confListener->onParticipantAdded( - make_shared( - EventLog::Type::ConferenceParticipantAdded, - tm, - d->chatRoomId, - d->lastNotify, - addr - ), - isFullState - ); - } - - confListener->onParticipantSetAdmin( - make_shared( - isAdmin ? EventLog::Type::ConferenceParticipantSetAdmin : EventLog::Type::ConferenceParticipantUnsetAdmin, - tm, - d->chatRoomId, - d->lastNotify, - addr - ), - isFullState - ); - - for (const auto &endpoint : user.getEndpoint()) { - if (!endpoint.getEntity().present()) - break; - - Address gruu(endpoint.getEntity().get()); - if (endpoint.getState() == StateType::deleted) { - confListener->onParticipantDeviceRemoved( - make_shared( - EventLog::Type::ConferenceParticipantDeviceRemoved, - tm, - d->chatRoomId, - d->lastNotify, - addr, - gruu - ), - isFullState - ); - } else if (endpoint.getState() == StateType::full) { - confListener->onParticipantDeviceAdded( - make_shared( - EventLog::Type::ConferenceParticipantDeviceAdded, - tm, - d->chatRoomId, - d->lastNotify, - addr, - gruu - ), - isFullState - ); - } - } - } - linphone_address_unref(cAddr); - } - - if (isFullState) - confListener->onFirstNotifyReceived(d->chatRoomId.getPeerAddress()); + Content multipart; + multipart.setBody(xmlBody); + ContentManager manager; + list contents = manager.multipartToContentLists(multipart); + for (const auto &content : contents) { + d->simpleNotifyReceived(content.getBodyAsString()); } } diff --git a/src/conference/handlers/remote-conference-event-handler.h b/src/conference/handlers/remote-conference-event-handler.h index 7598283d2..ecd443e19 100644 --- a/src/conference/handlers/remote-conference-event-handler.h +++ b/src/conference/handlers/remote-conference-event-handler.h @@ -37,6 +37,7 @@ public: void subscribe (const ChatRoomId &chatRoomId); void notifyReceived (const std::string &xmlBody); + void multipartNotifyReceived (const std::string &xmlBody); void unsubscribe (); const ChatRoomId &getChatRoomId () const; diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index 203e899cd..f550bb59f 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -57,7 +57,7 @@ void LocalConference::removeParticipant (const shared_ptr &pa } } -list
      LocalConference::parseResourceLists (string xmlBody) { +list
      LocalConference::parseResourceLists (const string &xmlBody) { istringstream data(xmlBody); unique_ptr rl = LinphonePrivate::Xsd::ResourceLists::parseResourceLists( data, diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h index 58198518e..079acda7e 100644 --- a/src/conference/local-conference.h +++ b/src/conference/local-conference.h @@ -38,7 +38,7 @@ public: void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void removeParticipant (const std::shared_ptr &participant) override; - std::list
      parseResourceLists (std::string xmlBody); + std::list
      parseResourceLists (const std::string &xmlBody); private: L_DECLARE_PRIVATE(LocalConference); diff --git a/src/content/content-manager.cpp b/src/content/content-manager.cpp index 285c3f998..79e515cb7 100644 --- a/src/content/content-manager.cpp +++ b/src/content/content-manager.cpp @@ -20,12 +20,11 @@ #include #include "belle-sip/belle-sip.h" + #include "content-manager.h" #include "content-type.h" #include "linphone/content.h" -#include "linphone/core.h" #include "logger/logger.h" -#include "private.h" // ============================================================================= @@ -35,11 +34,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ContentManager::ContentManager (LinphoneCore *core) { - mCore = core; -} - -list ContentManager::multipartToContentLists (Content content) const { +list ContentManager::multipartToContentLists (const Content &content) const { belle_sip_multipart_body_handler_t *mpbh = belle_sip_multipart_body_handler_new_from_buffer((void *)content.getBodyAsString().c_str(), content.getBodyAsString().length(), MULTIPART_BOUNDARY); belle_sip_object_ref(mpbh); @@ -71,7 +66,7 @@ list ContentManager::multipartToContentLists (Content content) const { return contentsList; } -Content ContentManager::contentsListToMultipart (list contents) const { +Content ContentManager::contentsListToMultipart (const list &contents) const { char *desc; string sub; belle_sip_memory_body_handler_t *mbh = NULL; @@ -99,7 +94,6 @@ Content ContentManager::contentsListToMultipart (list contents) const { } desc = belle_sip_object_to_string(mpbh); belle_sip_object_unref(mpbh); - belle_sip_object_ref(mbh); Content retContent = Content(); ContentType type("application", sub); diff --git a/src/content/content-manager.h b/src/content/content-manager.h index 0b020616a..8b15bb6a2 100644 --- a/src/content/content-manager.h +++ b/src/content/content-manager.h @@ -22,8 +22,9 @@ #include +#include "linphone/utils/general.h" + #include "content.h" -#include "linphone/types.h" // ============================================================================= @@ -31,13 +32,10 @@ LINPHONE_BEGIN_NAMESPACE class ContentManager { public: - ContentManager (LinphoneCore *core); + ContentManager () = default; - std::list multipartToContentLists (Content content) const; - Content contentsListToMultipart (std::list contents) const; - -private: - LinphoneCore *mCore = nullptr; + std::list multipartToContentLists (const Content &content) const; + Content contentsListToMultipart (const std::list &contents) const; }; LINPHONE_END_NAMESPACE diff --git a/src/core/core.h b/src/core/core.h index 635dca487..35514f5e0 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -39,6 +39,7 @@ class IdentityAddress; class LINPHONE_PUBLIC Core : public Object { friend class ChatRoom; friend class ClientGroupChatRoom; + friend class LocalConferenceEventHandlerPrivate; friend class MainDb; friend class MainDbEventKey; diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index ff1ae2930..8b91e5661 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -438,7 +438,7 @@ static const char *participant_unadmined_notify = \ static const char *bobUri = "sip:bob@example.com"; static const char *aliceUri = "sip:alice@example.com"; static const char *frankUri = "sip:frank@example.com"; -static const char *confUri = "sips:conf233@example.com"; +static const char *confUri = "sip:conf233@example.com"; L_ENABLE_ATTR_ACCESS(LocalConferencePrivate, unique_ptr, eventHandler); @@ -561,7 +561,7 @@ void first_notify_parsing() { void first_notify_parsing_wrong_conf() { LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); - LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, "sips:conf322@example.com"); + LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, "sip:conf322@example.com"); char *confAddressStr = linphone_address_as_string(confAddress); Address addr(confAddressStr); bctbx_free(confAddressStr); diff --git a/tester/content-manager-tester.cpp b/tester/content-manager-tester.cpp index 3ce12ac04..05e4eb893 100644 --- a/tester/content-manager-tester.cpp +++ b/tester/content-manager-tester.cpp @@ -160,10 +160,9 @@ static const char* part4 = \ ""; void multipart_to_list () { - LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); - ContentManager manager(marie->lc); + ContentManager manager; - Content multipartContent = Content(); + Content multipartContent; multipartContent.setBody(multipart); multipartContent.setContentType(ContentType("multipart", "related")); @@ -240,31 +239,24 @@ void multipart_to_list () { ms_message("\n\n----- Original part 4 -----"); ms_message("%s", originalStr4.c_str()); BC_ASSERT_TRUE(originalStr4 == generatedStr4); - - linphone_core_manager_destroy(marie); } void list_to_multipart () { - LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); - ContentManager manager(marie->lc); + ContentManager manager; - Content content1 = Content(); + Content content1; content1.setBody(part1); content1.setContentType(ContentType("application", "rlmi+xml")); - Content content2 = Content(); + Content content2; content2.setBody(part2); content2.setContentType(ContentType("application", "pidf+xml")); - Content content3 = Content(); + Content content3; content3.setBody(part3); content3.setContentType(ContentType("application", "pidf+xml")); - Content content4 = Content(); + Content content4; content4.setBody(part4); content4.setContentType(ContentType("application", "pidf+xml")); - list contents; - contents.push_back(content1); - contents.push_back(content2); - contents.push_back(content3); - contents.push_back(content4); + list contents = {content1, content2, content3, content4}; Content multipartContent = manager.contentsListToMultipart(contents); string originalStr(multipart); @@ -285,8 +277,6 @@ void list_to_multipart () { ms_message("\n\n----- Original multipart -----"); ms_message("%s", originalStr.c_str()); BC_ASSERT_TRUE(originalStr == generatedStr); - - linphone_core_manager_destroy(marie); } test_t content_manager_tests[] = { From 76c4e7ed259e7ba10b48f777361ad32b325bf2d9 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 20 Nov 2017 16:47:36 +0100 Subject: [PATCH 0801/2215] Handle IdentityAddress with sips scheme. --- src/address/address.cpp | 2 +- src/address/identity-address-p.h | 1 + src/address/identity-address.cpp | 11 ++++++++++- src/address/identity-address.h | 2 ++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/address/address.cpp b/src/address/address.cpp index 75d38cab3..7c562f198 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -48,7 +48,7 @@ Address::Address (const Address &src) : ClonableObject(*new AddressPrivate) { Address::Address (const IdentityAddress &src) : ClonableObject(*new AddressPrivate) { L_D(); - string uri = "sip:" + src.getUsername() + "@"; + string uri = src.getScheme() + ":" + src.getUsername() + "@"; if (src.getDomain().find(':') != string::npos) uri += "[" + src.getDomain() + "]"; else diff --git a/src/address/identity-address-p.h b/src/address/identity-address-p.h index b570fccc9..f8f27294a 100644 --- a/src/address/identity-address-p.h +++ b/src/address/identity-address-p.h @@ -29,6 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class IdentityAddressPrivate : public ClonableObjectPrivate { private: + std::string scheme; std::string username; std::string domain; std::string gruu; diff --git a/src/address/identity-address.cpp b/src/address/identity-address.cpp index 8ce4b059b..45c2d9383 100644 --- a/src/address/identity-address.cpp +++ b/src/address/identity-address.cpp @@ -34,7 +34,8 @@ LINPHONE_BEGIN_NAMESPACE IdentityAddress::IdentityAddress (const string &address) : ClonableObject(*new IdentityAddressPrivate) { L_D(); Address tmpAddress(address); - if (tmpAddress.isValid() && (tmpAddress.getScheme() == "sip")) { + if (tmpAddress.isValid() && ((tmpAddress.getScheme() == "sip") || (tmpAddress.getScheme() == "sips"))) { + d->scheme = tmpAddress.getScheme(); d->username = tmpAddress.getUsername(); d->domain = tmpAddress.getDomain(); if (tmpAddress.hasUriParam("gr")) { @@ -45,6 +46,7 @@ IdentityAddress::IdentityAddress (const string &address) : ClonableObject(*new I IdentityAddress::IdentityAddress (const IdentityAddress &src) : ClonableObject(*new IdentityAddressPrivate) { L_D(); + d->scheme = src.getScheme(); d->username = src.getUsername(); d->domain = src.getDomain(); d->gruu = src.getGruu(); @@ -52,6 +54,7 @@ IdentityAddress::IdentityAddress (const IdentityAddress &src) : ClonableObject(* IdentityAddress::IdentityAddress (const Address &src) : ClonableObject(*new IdentityAddressPrivate) { L_D(); + d->scheme = src.getScheme(); d->username = src.getUsername(); d->domain = src.getDomain(); if (src.hasUriParam("gr")) { @@ -62,6 +65,7 @@ IdentityAddress::IdentityAddress (const Address &src) : ClonableObject(*new Iden IdentityAddress &IdentityAddress::operator= (const IdentityAddress &src) { L_D(); if (this != &src) { + d->scheme = src.getScheme(); d->username = src.getUsername(); d->domain = src.getDomain(); d->gruu = src.getGruu(); @@ -86,6 +90,11 @@ bool IdentityAddress::isValid () const { return tmpAddress.isValid(); } +const string &IdentityAddress::getScheme () const { + L_D(); + return d->scheme; +} + const string &IdentityAddress::getUsername () const { L_D(); return d->username; diff --git a/src/address/identity-address.h b/src/address/identity-address.h index b99e03513..5587bb0c1 100644 --- a/src/address/identity-address.h +++ b/src/address/identity-address.h @@ -45,6 +45,8 @@ public: bool isValid () const; + const std::string &getScheme () const; + const std::string &getUsername () const; bool setUsername (const std::string &username); From 1a791f0d8cff7c6cb0c5da417357277c1b9c12a4 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 20 Nov 2017 17:21:35 +0100 Subject: [PATCH 0802/2215] add sips to conference event tester --- tester/conference-event-tester.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index 8b91e5661..ff1ae2930 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -438,7 +438,7 @@ static const char *participant_unadmined_notify = \ static const char *bobUri = "sip:bob@example.com"; static const char *aliceUri = "sip:alice@example.com"; static const char *frankUri = "sip:frank@example.com"; -static const char *confUri = "sip:conf233@example.com"; +static const char *confUri = "sips:conf233@example.com"; L_ENABLE_ATTR_ACCESS(LocalConferencePrivate, unique_ptr, eventHandler); @@ -561,7 +561,7 @@ void first_notify_parsing() { void first_notify_parsing_wrong_conf() { LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); - LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, "sip:conf322@example.com"); + LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, "sips:conf322@example.com"); char *confAddressStr = linphone_address_as_string(confAddress); Address addr(confAddressStr); bctbx_free(confAddressStr); From e6f58de87e6f1179c4d18ce1b786ff5605f52189 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 21 Nov 2017 10:37:29 +0100 Subject: [PATCH 0803/2215] Fix probable crash. --- coreapi/proxy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index fd8bdbbd2..134c2bdf1 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1439,6 +1439,8 @@ const LinphoneAddress *linphone_proxy_config_get_contact (const LinphoneProxyCon } // Warning : Do not remove, the op can change its contact_address + if (!cfg->op) + return NULL; const SalAddress *salAddr = cfg->op->get_contact_address(); if (!salAddr) return NULL; From 7b3df0c474929c5ec412b766cf0fd2cbc85944d1 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 21 Nov 2017 10:37:45 +0100 Subject: [PATCH 0804/2215] Fix compilation warnings. --- coreapi/private.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/coreapi/private.h b/coreapi/private.h index 6c28c481e..5b22e4fac 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -31,7 +31,20 @@ #include "linphone/friend.h" #include "linphone/friendlist.h" #include "linphone/tunnel.h" + +#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) +#pragma GCC diagnostic push +#endif +#ifdef _MSC_VER +#pragma warning(disable : 4996) +#else +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif #include "linphone/core_utils.h" +#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) +#pragma GCC diagnostic pop +#endif + #include "linphone/conference.h" #include "address/address.h" @@ -1011,10 +1024,21 @@ struct _EcCalibrator{ MSFilter *play, *gen, *sndwrite; MSFilter *read_resampler,*write_resampler; MSTicker *ticker; +#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) +#pragma GCC diagnostic push +#endif +#ifdef _MSC_VER +#pragma warning(disable : 4996) +#else +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif LinphoneEcCalibrationCallback cb; void *cb_data; LinphoneEcCalibrationAudioInit audio_init_cb; LinphoneEcCalibrationAudioUninit audio_uninit_cb; +#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) +#pragma GCC diagnostic pop +#endif int64_t acc; int delay; unsigned int rate; From bb5b22b93259a20fd22e5539c77d5a5a9b44b31a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 21 Nov 2017 10:43:20 +0100 Subject: [PATCH 0805/2215] Use IdentityAddress in conference. --- src/c-wrapper/api/c-chat-room.cpp | 6 ++- src/chat/chat-room/basic-chat-room.cpp | 10 ++--- src/chat/chat-room/basic-chat-room.h | 8 ++-- src/chat/chat-room/client-group-chat-room-p.h | 2 +- src/chat/chat-room/client-group-chat-room.cpp | 38 +++++++++---------- src/chat/chat-room/client-group-chat-room.h | 14 +++---- src/chat/chat-room/server-group-chat-room-p.h | 4 +- .../chat-room/server-group-chat-room-stub.cpp | 14 +++---- src/chat/chat-room/server-group-chat-room.h | 8 ++-- src/conference/conference-interface.h | 10 ++--- src/conference/conference-listener.h | 8 ++-- src/conference/conference-p.h | 4 +- src/conference/conference.cpp | 19 +++++----- src/conference/conference.h | 12 +++--- .../local-conference-event-handler.cpp | 24 ++++++------ src/conference/local-conference.cpp | 12 +++--- src/conference/local-conference.h | 6 +-- src/conference/participant-device.cpp | 2 +- src/conference/participant-device.h | 2 +- src/conference/participant-p.h | 2 - src/conference/participant.cpp | 19 +++------- src/conference/participant.h | 6 +-- src/conference/remote-conference.cpp | 16 ++++---- src/conference/remote-conference.h | 12 +++--- tester/conference-event-tester.cpp | 38 +++++++++---------- 25 files changed, 143 insertions(+), 153 deletions(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index e3014b4e4..9ea256016 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -234,7 +234,11 @@ void linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAdd } void linphone_chat_room_add_participants (LinphoneChatRoom *cr, const bctbx_list_t *addresses) { - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->addParticipants(L_GET_RESOLVED_CPP_LIST_FROM_C_LIST(addresses, Address), nullptr, false); + list lAddr = L_GET_RESOLVED_CPP_LIST_FROM_C_LIST(addresses, Address); + list lIdentAddr; + for (const auto &addr : lAddr) + lIdentAddr.push_back(LinphonePrivate::IdentityAddress(addr)); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->addParticipants(lIdentAddr, nullptr, false); } bool_t linphone_chat_room_can_handle_participants (const LinphoneChatRoom *cr) { diff --git a/src/chat/chat-room/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp index a02a58657..42bfa4459 100644 --- a/src/chat/chat-room/basic-chat-room.cpp +++ b/src/chat/chat-room/basic-chat-room.cpp @@ -46,16 +46,16 @@ bool BasicChatRoom::canHandleParticipants () const { return false; } -const Address &BasicChatRoom::getConferenceAddress () const { +const IdentityAddress &BasicChatRoom::getConferenceAddress () const { lError() << "a BasicChatRoom does not have a conference address"; - return Utils::getEmptyConstRefObject
      (); + return Utils::getEmptyConstRefObject(); } -void BasicChatRoom::addParticipant (const Address &, const CallSessionParams *, bool) { +void BasicChatRoom::addParticipant (const IdentityAddress &, const CallSessionParams *, bool) { lError() << "addParticipant() is not allowed on a BasicChatRoom"; } -void BasicChatRoom::addParticipants (const list
      &, const CallSessionParams *, bool) { +void BasicChatRoom::addParticipants (const list &, const CallSessionParams *, bool) { lError() << "addParticipants() is not allowed on a BasicChatRoom"; } @@ -67,7 +67,7 @@ void BasicChatRoom::removeParticipants (const list> &) { lError() << "removeParticipants() is not allowed on a BasicChatRoom"; } -shared_ptr BasicChatRoom::findParticipant (const Address &) const { +shared_ptr BasicChatRoom::findParticipant (const IdentityAddress &) const { lError() << "findParticipant() is not allowed on a BasicChatRoom"; return nullptr; } diff --git a/src/chat/chat-room/basic-chat-room.h b/src/chat/chat-room/basic-chat-room.h index 21268e29d..a234eee30 100644 --- a/src/chat/chat-room/basic-chat-room.h +++ b/src/chat/chat-room/basic-chat-room.h @@ -34,17 +34,17 @@ class LINPHONE_PUBLIC BasicChatRoom : public ChatRoom { public: CapabilitiesMask getCapabilities () const override; - const Address &getConferenceAddress () const override; + const IdentityAddress &getConferenceAddress () const override; bool canHandleParticipants () const override; - void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; - void addParticipants (const std::list
      &addresses, const CallSessionParams *params, bool hasMedia) override; + void addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) override; + void addParticipants (const std::list &addresses, const CallSessionParams *params, bool hasMedia) override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; - std::shared_ptr findParticipant (const Address &addr) const override; + std::shared_ptr findParticipant (const IdentityAddress &addr) const override; std::shared_ptr getMe () const override; int getNbParticipants () const override; diff --git a/src/chat/chat-room/client-group-chat-room-p.h b/src/chat/chat-room/client-group-chat-room-p.h index 6a8871cd5..82366fef3 100644 --- a/src/chat/chat-room/client-group-chat-room-p.h +++ b/src/chat/chat-room/client-group-chat-room-p.h @@ -31,7 +31,7 @@ class ClientGroupChatRoomPrivate : public ChatRoomPrivate { public: ClientGroupChatRoomPrivate () = default; - std::list
      cleanAddressesList (const std::list
      &addresses) const; + std::list cleanAddressesList (const std::list &addresses) const; std::shared_ptr createSession (); void notifyReceived (const std::string &body); void multipartNotifyReceived (const std::string &body); diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 0661a4627..996ece990 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -39,13 +39,13 @@ LINPHONE_BEGIN_NAMESPACE // ----------------------------------------------------------------------------- -list
      ClientGroupChatRoomPrivate::cleanAddressesList (const list
      &addresses) const { +list ClientGroupChatRoomPrivate::cleanAddressesList (const list &addresses) const { L_Q(); - list
      cleanedList(addresses); + list cleanedList(addresses); cleanedList.sort(); cleanedList.unique(); for (auto it = cleanedList.begin(); it != cleanedList.end();) { - if (q->findParticipant(*it) || (q->getMe()->getAddress() == IdentityAddress(*it))) + if (q->findParticipant(*it) || (q->getMe()->getAddress() == *it)) it = cleanedList.erase(it); else it++; @@ -64,7 +64,7 @@ shared_ptr ClientGroupChatRoomPrivate::createSession () { shared_ptr focus = qConference->getPrivate()->focus; shared_ptr session = focus->getPrivate()->createSession(*q, &csp, false, q); const Address &myAddress = q->getMe()->getAddress(); - session->configure(LinphoneCallOutgoing, nullptr, nullptr, myAddress, focus->getContactAddress()); + session->configure(LinphoneCallOutgoing, nullptr, nullptr, myAddress, focus->getAddress()); session->initiateOutgoing(); return session; } @@ -105,25 +105,25 @@ bool ClientGroupChatRoom::canHandleParticipants () const { return RemoteConference::canHandleParticipants(); } -const Address &ClientGroupChatRoom::getConferenceAddress () const { +const IdentityAddress &ClientGroupChatRoom::getConferenceAddress () const { return RemoteConference::getConferenceAddress(); } -void ClientGroupChatRoom::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { - list
      addresses; +void ClientGroupChatRoom::addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) { + list addresses; addresses.push_back(addr); addParticipants(addresses, params, hasMedia); } void ClientGroupChatRoom::addParticipants ( - const list
      &addresses, + const list &addresses, const CallSessionParams *params, bool hasMedia ) { L_D(); L_D_T(RemoteConference, dConference); - list
      addressesList = d->cleanAddressesList(addresses); + list addressesList = d->cleanAddressesList(addresses); if (addressesList.empty()) return; @@ -166,7 +166,7 @@ void ClientGroupChatRoom::removeParticipants (const list RemoteConference::removeParticipants(participants); } -shared_ptr ClientGroupChatRoom::findParticipant (const Address &addr) const { +shared_ptr ClientGroupChatRoom::findParticipant (const IdentityAddress &addr) const { return RemoteConference::findParticipant(addr); } @@ -264,7 +264,7 @@ void ClientGroupChatRoom::leave () { void ClientGroupChatRoom::onChatMessageReceived (const shared_ptr &msg) {} -void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { +void ClientGroupChatRoom::onConferenceCreated (const IdentityAddress &addr) { L_D(); L_D_T(RemoteConference, dConference); dConference->conferenceAddress = addr; @@ -272,14 +272,14 @@ void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { getCore()->getPrivate()->insertChatRoom(getSharedFromThis()); } -void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { +void ClientGroupChatRoom::onConferenceTerminated (const IdentityAddress &addr) { L_D(); L_D_T(RemoteConference, dConference); dConference->eventHandler->resetLastNotify(); d->setState(ChatRoom::State::Terminated); } -void ClientGroupChatRoom::onFirstNotifyReceived (const Address &addr) { +void ClientGroupChatRoom::onFirstNotifyReceived (const IdentityAddress &addr) { L_D(); d->setState(ChatRoom::State::Created); getCore()->getPrivate()->insertChatRoomWithDb(getSharedFromThis()); @@ -288,7 +288,7 @@ void ClientGroupChatRoom::onFirstNotifyReceived (const Address &addr) { void ClientGroupChatRoom::onParticipantAdded (const shared_ptr &event, bool isFullState) { L_D_T(RemoteConference, dConference); - const Address &addr = event->getParticipantAddress(); + const IdentityAddress &addr = event->getParticipantAddress(); if (isMe(addr)) return; @@ -318,7 +318,7 @@ void ClientGroupChatRoom::onParticipantRemoved (const shared_ptrgetParticipantAddress(); + const IdentityAddress &addr = event->getParticipantAddress(); shared_ptr participant = findParticipant(addr); if (!participant) { lWarning() << "Participant " << addr.asString() << " removed but not in the list of participants!"; @@ -337,7 +337,7 @@ void ClientGroupChatRoom::onParticipantRemoved (const shared_ptr &event, bool isFullState) { - const Address &addr = event->getParticipantAddress(); + const IdentityAddress &addr = event->getParticipantAddress(); shared_ptr participant; if (isMe(addr)) participant = getMe(); @@ -383,7 +383,7 @@ void ClientGroupChatRoom::onSubjectChanged (const shared_ptr &event, bool isFullState) { - const Address &addr = event->getParticipantAddress(); + const IdentityAddress &addr = event->getParticipantAddress(); shared_ptr participant; if (isMe(addr)) participant = getMe(); @@ -410,7 +410,7 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (const shared_ptr &event, bool isFullState) { (void)isFullState; - const Address &addr = event->getParticipantAddress(); + const IdentityAddress &addr = event->getParticipantAddress(); shared_ptr participant; if (isMe(addr)) participant = getMe(); @@ -450,7 +450,7 @@ void ClientGroupChatRoom::onCallSessionStateChanged ( if (state == LinphoneCallConnected) { if (d->state == ChatRoom::State::CreationPending) { - Address addr(session->getRemoteContactAddress()->asStringUriOnly()); + IdentityAddress addr(session->getRemoteContactAddress()->asStringUriOnly()); onConferenceCreated(addr); if (session->getRemoteContactAddress()->hasParam("isfocus")) dConference->eventHandler->subscribe(getChatRoomId()); diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 3edaabb55..0702f59c9 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -43,17 +43,17 @@ public: CapabilitiesMask getCapabilities () const override; - const Address &getConferenceAddress () const override; + const IdentityAddress &getConferenceAddress () const override; bool canHandleParticipants () const override; - void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; - void addParticipants (const std::list
      &addresses, const CallSessionParams *params, bool hasMedia) override; + void addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) override; + void addParticipants (const std::list &addresses, const CallSessionParams *params, bool hasMedia) override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; - std::shared_ptr findParticipant (const Address &addr) const override; + std::shared_ptr findParticipant (const IdentityAddress &addr) const override; std::shared_ptr getMe () const override; int getNbParticipants () const override; @@ -73,9 +73,9 @@ private: void onChatMessageReceived (const std::shared_ptr &msg) override; - void onConferenceCreated (const Address &addr) override; - void onConferenceTerminated (const Address &addr) override; - void onFirstNotifyReceived (const Address &addr) override; + void onConferenceCreated (const IdentityAddress &addr) override; + void onConferenceTerminated (const IdentityAddress &addr) override; + void onFirstNotifyReceived (const IdentityAddress &addr) override; void onParticipantAdded (const std::shared_ptr &event, bool isFullState) override; void onParticipantRemoved (const std::shared_ptr &event, bool isFullState) override; void onParticipantSetAdmin (const std::shared_ptr &event, bool isFullState) override; diff --git a/src/chat/chat-room/server-group-chat-room-p.h b/src/chat/chat-room/server-group-chat-room-p.h index 9a8b18c17..b2a945e0d 100644 --- a/src/chat/chat-room/server-group-chat-room-p.h +++ b/src/chat/chat-room/server-group-chat-room-p.h @@ -37,7 +37,7 @@ class ServerGroupChatRoomPrivate : public ChatRoomPrivate { public: ServerGroupChatRoomPrivate () = default; - std::shared_ptr addParticipant (const Address &addr); + std::shared_ptr addParticipant (const IdentityAddress &addr); void confirmCreation (); void confirmJoining (SalCallOp *op); std::shared_ptr findRemovedParticipant (const std::shared_ptr &session) const; @@ -46,7 +46,7 @@ public: void subscribeReceived (LinphoneEvent *event); void update (SalCallOp *op); - void dispatchMessage (const Address &fromAddr, const Content &content); + void dispatchMessage (const IdentityAddress &fromAddr, const Content &content); void storeOrUpdateMessage (const std::shared_ptr &msg) override; LinphoneReason messageReceived (SalOp *op, const SalMessage *msg) override; void setConferenceAddress (const IdentityAddress &confAddr); diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index 97e694bc3..6ad6d6d73 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -29,7 +29,7 @@ LINPHONE_BEGIN_NAMESPACE // ----------------------------------------------------------------------------- -shared_ptr ServerGroupChatRoomPrivate::addParticipant (const Address &) { +shared_ptr ServerGroupChatRoomPrivate::addParticipant (const IdentityAddress &) { return nullptr; } @@ -55,7 +55,7 @@ void ServerGroupChatRoomPrivate::update (SalCallOp *) {} // ----------------------------------------------------------------------------- -void ServerGroupChatRoomPrivate::dispatchMessage (const Address &, const Content &) {} +void ServerGroupChatRoomPrivate::dispatchMessage (const IdentityAddress &, const Content &) {} void ServerGroupChatRoomPrivate::storeOrUpdateMessage (const shared_ptr &) {} @@ -79,7 +79,7 @@ bool ServerGroupChatRoomPrivate::isAdminLeft () const { ServerGroupChatRoom::ServerGroupChatRoom (const shared_ptr &core, SalCallOp *op) : ChatRoom(*new ServerGroupChatRoomPrivate, core, ChatRoomId(IdentityAddress(op->get_to()), IdentityAddress(op->get_to()))), -LocalConference(core, Address(op->get_to()), nullptr) {} +LocalConference(core, IdentityAddress(op->get_to()), nullptr) {} int ServerGroupChatRoom::getCapabilities () const { return 0; @@ -89,11 +89,11 @@ bool ServerGroupChatRoom::canHandleParticipants () const { return false; } -void ServerGroupChatRoom::addParticipant (const Address &, const CallSessionParams *, bool) {} +void ServerGroupChatRoom::addParticipant (const IdentityAddress &, const CallSessionParams *, bool) {} -void ServerGroupChatRoom::addParticipants (const list
      &, const CallSessionParams *, bool) {} +void ServerGroupChatRoom::addParticipants (const list &, const CallSessionParams *, bool) {} -const Address &ServerGroupChatRoom::getConferenceAddress () const { +const IdentityAddress &ServerGroupChatRoom::getConferenceAddress () const { return LocalConference::getConferenceAddress(); } @@ -101,7 +101,7 @@ void ServerGroupChatRoom::removeParticipant (const shared_ptr void ServerGroupChatRoom::removeParticipants (const list> &) {} -shared_ptr ServerGroupChatRoom::findParticipant (const Address &) const { +shared_ptr ServerGroupChatRoom::findParticipant (const IdentityAddress &) const { return nullptr; } diff --git a/src/chat/chat-room/server-group-chat-room.h b/src/chat/chat-room/server-group-chat-room.h index f57606722..c93e593de 100644 --- a/src/chat/chat-room/server-group-chat-room.h +++ b/src/chat/chat-room/server-group-chat-room.h @@ -41,17 +41,17 @@ public: CapabilitiesMask getCapabilities () const override; - const Address &getConferenceAddress () const override; + const IdentityAddress &getConferenceAddress () const override; bool canHandleParticipants () const override; - void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; - void addParticipants (const std::list
      &addresses, const CallSessionParams *params, bool hasMedia) override; + void addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) override; + void addParticipants (const std::list &addresses, const CallSessionParams *params, bool hasMedia) override; void removeParticipant (const std::shared_ptr &participant) override; void removeParticipants (const std::list> &participants) override; - std::shared_ptr findParticipant (const Address &addr) const override; + std::shared_ptr findParticipant (const IdentityAddress &addr) const override; std::shared_ptr getMe () const override; int getNbParticipants () const override; diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index 104d7dbbc..fd08fc0c3 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -29,7 +29,7 @@ LINPHONE_BEGIN_NAMESPACE -class Address; +class IdentityAddress; class CallSessionParams; class Participant; @@ -37,11 +37,11 @@ class LINPHONE_PUBLIC ConferenceInterface { public: virtual ~ConferenceInterface() = default; - virtual void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) = 0; - virtual void addParticipants (const std::list
      &addresses, const CallSessionParams *params, bool hasMedia) = 0; + virtual void addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) = 0; + virtual void addParticipants (const std::list &addresses, const CallSessionParams *params, bool hasMedia) = 0; virtual bool canHandleParticipants () const = 0; - virtual std::shared_ptr findParticipant (const Address &addr) const = 0; - virtual const Address &getConferenceAddress () const = 0; + virtual std::shared_ptr findParticipant (const IdentityAddress &addr) const = 0; + virtual const IdentityAddress &getConferenceAddress () const = 0; virtual std::shared_ptr getMe () const = 0; virtual int getNbParticipants () const = 0; virtual std::list> getParticipants () const = 0; diff --git a/src/conference/conference-listener.h b/src/conference/conference-listener.h index b4946cd9d..e6e6ab402 100644 --- a/src/conference/conference-listener.h +++ b/src/conference/conference-listener.h @@ -31,13 +31,13 @@ LINPHONE_BEGIN_NAMESPACE -class Address; +class IdentityAddress; class ConferenceListener { public: - virtual void onConferenceCreated (const Address &addr) = 0; - virtual void onConferenceTerminated (const Address &addr) = 0; - virtual void onFirstNotifyReceived (const Address &addr) = 0; + virtual void onConferenceCreated (const IdentityAddress &addr) = 0; + virtual void onConferenceTerminated (const IdentityAddress &addr) = 0; + virtual void onFirstNotifyReceived (const IdentityAddress &addr) = 0; virtual void onParticipantAdded (const std::shared_ptr &event, bool isFullState) = 0; virtual void onParticipantRemoved (const std::shared_ptr &event, bool isFullState) = 0; virtual void onParticipantSetAdmin (const std::shared_ptr &event, bool isFullState) = 0; diff --git a/src/conference/conference-p.h b/src/conference/conference-p.h index f036e6da0..1a163cf34 100644 --- a/src/conference/conference-p.h +++ b/src/conference/conference-p.h @@ -20,7 +20,7 @@ #ifndef _CONFERENCE_P_H_ #define _CONFERENCE_P_H_ -#include "address/address.h" +#include "address/identity-address.h" #include "conference.h" // ============================================================================= @@ -32,7 +32,7 @@ class Participant; class ConferencePrivate { public: - Address conferenceAddress; + IdentityAddress conferenceAddress; std::list> participants; protected: diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index bb7cd4e67..8ea32bedc 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -32,7 +32,7 @@ LINPHONE_BEGIN_NAMESPACE Conference::Conference ( ConferencePrivate &p, const shared_ptr &core, - const Address &myAddress, + const IdentityAddress &myAddress, CallListener *listener ) : CoreAccessor(core), mPrivate(&p) { L_D(); @@ -54,12 +54,12 @@ shared_ptr Conference::getActiveParticipant () const { // ----------------------------------------------------------------------------- -void Conference::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { +void Conference::addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) { lError() << "Conference class does not handle addParticipant() generically"; } -void Conference::addParticipants (const list
      &addresses, const CallSessionParams *params, bool hasMedia) { - list
      sortedAddresses(addresses); +void Conference::addParticipants (const list &addresses, const CallSessionParams *params, bool hasMedia) { + list sortedAddresses(addresses); sortedAddresses.sort(); sortedAddresses.unique(); for (const auto &addr: sortedAddresses) { @@ -73,7 +73,7 @@ bool Conference::canHandleParticipants () const { return true; } -const Address &Conference::getConferenceAddress () const { +const IdentityAddress &Conference::getConferenceAddress () const { L_D(); return d->conferenceAddress; } @@ -208,12 +208,13 @@ void Conference::onResetFirstVideoFrameDecoded (const shared_ptr Conference::findParticipant (const Address &addr) const { +shared_ptr Conference::findParticipant (const IdentityAddress &addr) const { L_D(); - IdentityAddress simpleAddr(addr); + IdentityAddress searchedAddr(addr); + searchedAddr.setGruu(""); for (const auto &participant : d->participants) { - if (participant->getAddress() == simpleAddr) + if (participant->getAddress() == searchedAddr) return participant; } @@ -231,7 +232,7 @@ shared_ptr Conference::findParticipant (const shared_ptrme->getAddress() == simpleAddr; diff --git a/src/conference/conference.h b/src/conference/conference.h index d89536343..f7a723cd4 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -48,11 +48,11 @@ public: std::shared_ptr findParticipant (const std::shared_ptr &session) const; /* ConferenceInterface */ - void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; - void addParticipants (const std::list
      &addresses, const CallSessionParams *params, bool hasMedia) override; + void addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) override; + void addParticipants (const std::list &addresses, const CallSessionParams *params, bool hasMedia) override; bool canHandleParticipants () const override; - std::shared_ptr findParticipant (const Address &addr) const override; - const Address &getConferenceAddress () const override; + std::shared_ptr findParticipant (const IdentityAddress &addr) const override; + const IdentityAddress &getConferenceAddress () const override; std::shared_ptr getMe () const override; int getNbParticipants () const override; std::list> getParticipants () const override; @@ -85,11 +85,11 @@ protected: explicit Conference ( ConferencePrivate &p, const std::shared_ptr &core, - const Address &myAddress, + const IdentityAddress &myAddress, CallListener *listener = nullptr ); - bool isMe (const Address &addr) const; + bool isMe (const IdentityAddress &addr) const; ConferencePrivate *mPrivate = nullptr; diff --git a/src/conference/handlers/local-conference-event-handler.cpp b/src/conference/handlers/local-conference-event-handler.cpp index 63a8633d2..6876e3d13 100644 --- a/src/conference/handlers/local-conference-event-handler.cpp +++ b/src/conference/handlers/local-conference-event-handler.cpp @@ -102,7 +102,7 @@ string LocalConferenceEventHandlerPrivate::createNotify (ConferenceType confInfo } string LocalConferenceEventHandlerPrivate::createNotifyFullState (int notifyId) { - string entity = conf->getConferenceAddress().asStringUriOnly(); + string entity = conf->getConferenceAddress().asString(); string subject = conf->getSubject(); ConferenceType confInfo = ConferenceType(entity); UsersType users; @@ -122,7 +122,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyFullState (int notifyId) user.setState(StateType::full); for (const auto &device : participant->getPrivate()->getDevices()) { - const string &gruu = device->getGruu().asString(); + const string &gruu = device->getAddress().asString(); EndpointType endpoint = EndpointType(); endpoint.setEntity(gruu); endpoint.setState(StateType::full); @@ -224,7 +224,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyMultipart (int notifyId) } string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const Address &addr, int notifyId) { - string entity = conf->getConferenceAddress().asStringUriOnly(); + string entity = conf->getConferenceAddress().asString(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -235,7 +235,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const A shared_ptr p = conf->findParticipant(addr); if (p) { for (const auto &device : p->getPrivate()->getDevices()) { - const string &gruu = device->getGruu().asString(); + const string &gruu = device->getAddress().asString(); EndpointType endpoint = EndpointType(); endpoint.setEntity(gruu); endpoint.setState(StateType::full); @@ -254,7 +254,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const A } string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved (const Address &addr, int notifyId) { - string entity = conf->getConferenceAddress().asStringUriOnly(); + string entity = conf->getConferenceAddress().asString(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -268,7 +268,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved (const } string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined (const Address &addr, bool isAdmin, int notifyId) { - string entity = conf->getConferenceAddress().asStringUriOnly(); + string entity = conf->getConferenceAddress().asString(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -289,7 +289,7 @@ string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged (int notif } string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged (const string &subject, int notifyId) { - string entity = conf->getConferenceAddress().asStringUriOnly(); + string entity = conf->getConferenceAddress().asString(); ConferenceType confInfo = ConferenceType(entity); ConferenceDescriptionType confDescr = ConferenceDescriptionType(); confDescr.setSubject(subject); @@ -299,7 +299,7 @@ string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged (const str } string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceAdded (const Address &addr, const Address &gruu, int notifyId) { - string entity = conf->getConferenceAddress().asStringUriOnly(); + string entity = conf->getConferenceAddress().asString(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -323,7 +323,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceAdded (c } string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceRemoved (const Address &addr, const Address &gruu, int notifyId) { - string entity = conf->getConferenceAddress().asStringUriOnly(); + string entity = conf->getConferenceAddress().asString(); ConferenceType confInfo = ConferenceType(entity); UsersType users; confInfo.setUsers(users); @@ -383,16 +383,16 @@ void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) { if (linphone_event_get_subscription_state(lev) == LinphoneSubscriptionActive) { unsigned int lastNotify = static_cast(Utils::stoi(linphone_event_get_custom_header(lev, "Last-Notify-Version"))); if (lastNotify == 0) { - lInfo() << "Sending initial notify of conference:" << d->conf->getConferenceAddress().asStringUriOnly() << " to: " << device->getGruu().asString(); + lInfo() << "Sending initial notify of conference:" << d->conf->getConferenceAddress().asString() << " to: " << device->getAddress().asString(); device->setConferenceSubscribeEvent(lev); d->notifyFullState(d->createNotifyFullState(), device); } else if (lastNotify < d->lastNotify) { - lInfo() << "Sending all missed notify for conference:" << d->conf->getConferenceAddress().asStringUriOnly() << + lInfo() << "Sending all missed notify for conference:" << d->conf->getConferenceAddress().asString() << " from: " << lastNotify << " to: " << participant->getAddress().asString(); d->notifyParticipantDevice(d->createNotifyMultipart(static_cast(lastNotify)), device); } else if (lastNotify > d->lastNotify) { lError() << "last notify received by client: [" << lastNotify <<"] for conference:" << - d->conf->getConferenceAddress().asStringUriOnly() << + d->conf->getConferenceAddress().asString() << " should not be higher than last notify sent by server: [" << d->lastNotify << "]"; } } else if (linphone_event_get_subscription_state(lev) == LinphoneSubscriptionTerminated) diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index f550bb59f..45c3707c5 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -28,7 +28,7 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -LocalConference::LocalConference (const shared_ptr &core, const Address &myAddress, CallListener *listener) +LocalConference::LocalConference (const shared_ptr &core, const IdentityAddress &myAddress, CallListener *listener) : Conference(*new LocalConferencePrivate, core, myAddress, listener) { L_D(); d->eventHandler.reset(new LocalConferenceEventHandler(this)); @@ -36,7 +36,7 @@ LocalConference::LocalConference (const shared_ptr &core, const Address &m // ----------------------------------------------------------------------------- -void LocalConference::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { +void LocalConference::addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) { L_D(); shared_ptr participant = findParticipant(addr); if (participant) @@ -57,18 +57,16 @@ void LocalConference::removeParticipant (const shared_ptr &pa } } -list
      LocalConference::parseResourceLists (const string &xmlBody) { +list LocalConference::parseResourceLists (const string &xmlBody) { istringstream data(xmlBody); unique_ptr rl = LinphonePrivate::Xsd::ResourceLists::parseResourceLists( data, Xsd::XmlSchema::Flags::dont_validate ); - list
      addresses = list
      (); + list addresses = list(); for (const auto &l : rl->getList()) { for (const auto &entry : l.getEntry()) { - Address addr(entry.getUri()); - if (entry.getDisplayName().present()) - addr.setDisplayName(entry.getDisplayName().get()); + IdentityAddress addr(entry.getUri()); addresses.push_back(addr); } } diff --git a/src/conference/local-conference.h b/src/conference/local-conference.h index 079acda7e..6948f3010 100644 --- a/src/conference/local-conference.h +++ b/src/conference/local-conference.h @@ -32,13 +32,13 @@ class LocalConference : public Conference { friend class ServerGroupChatRoomPrivate; public: - LocalConference (const std::shared_ptr &core, const Address &myAddress, CallListener *listener = nullptr); + LocalConference (const std::shared_ptr &core, const IdentityAddress &myAddress, CallListener *listener = nullptr); /* ConferenceInterface */ - void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; + void addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) override; void removeParticipant (const std::shared_ptr &participant) override; - std::list
      parseResourceLists (const std::string &xmlBody); + std::list parseResourceLists (const std::string &xmlBody); private: L_DECLARE_PRIVATE(LocalConference); diff --git a/src/conference/participant-device.cpp b/src/conference/participant-device.cpp index 9e4695218..d7e759484 100644 --- a/src/conference/participant-device.cpp +++ b/src/conference/participant-device.cpp @@ -39,7 +39,7 @@ ParticipantDevice::~ParticipantDevice () { } bool ParticipantDevice::operator== (const ParticipantDevice &device) const { - return (mGruu == device.getGruu()); + return (mGruu == device.getAddress()); } void ParticipantDevice::setConferenceSubscribeEvent (LinphoneEvent *ev) { diff --git a/src/conference/participant-device.h b/src/conference/participant-device.h index d466df80f..0190baa66 100644 --- a/src/conference/participant-device.h +++ b/src/conference/participant-device.h @@ -41,7 +41,7 @@ public: bool operator== (const ParticipantDevice &device) const; - inline const IdentityAddress &getGruu () const { return mGruu; } + inline const IdentityAddress &getAddress () const { return mGruu; } inline std::shared_ptr getSession () const { return mSession; } inline void setSession (std::shared_ptr session) { mSession = session; } diff --git a/src/conference/participant-p.h b/src/conference/participant-p.h index aa754c2af..1f5af8552 100644 --- a/src/conference/participant-p.h +++ b/src/conference/participant-p.h @@ -40,7 +40,6 @@ public: inline void removeSession () { session.reset(); } inline void setAddress (const IdentityAddress &newAddr) { addr = newAddr; } inline void setAdmin (bool isAdmin) { this->isAdmin = isAdmin; } - inline void setContactAddress (const Address &contactAddr) { this->contactAddr = contactAddr; } std::shared_ptr findDevice (const IdentityAddress &gruu) const; std::shared_ptr findDevice (const std::shared_ptr &session); const std::list> &getDevices () const; @@ -49,7 +48,6 @@ public: private: IdentityAddress addr; - Address contactAddr; bool isAdmin = false; std::shared_ptr session; std::list> devices; diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index 47aac4c06..d4f8b2746 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -47,7 +47,7 @@ shared_ptr ParticipantPrivate::createSession ( shared_ptr ParticipantPrivate::findDevice (const IdentityAddress &gruu) const { for (const auto &device : devices) { - if (device->getGruu() == gruu) + if (device->getAddress() == gruu) return device; } return nullptr; @@ -76,7 +76,7 @@ shared_ptr ParticipantPrivate::addDevice (const IdentityAddre void ParticipantPrivate::removeDevice (const IdentityAddress &gruu) { for (auto it = devices.begin(); it != devices.end(); it++) { - if ((*it)->getGruu() == gruu) { + if ((*it)->getAddress() == gruu) { devices.erase(it); return; } @@ -85,16 +85,14 @@ void ParticipantPrivate::removeDevice (const IdentityAddress &gruu) { // ============================================================================= -Participant::Participant (const Address &address) : Object(*new ParticipantPrivate) { +Participant::Participant (const IdentityAddress &address) : Object(*new ParticipantPrivate) { L_D(); - d->contactAddr = address; - d->addr = IdentityAddress(address); + d->addr = address; } -Participant::Participant (Address &&address) : Object(*new ParticipantPrivate) { +Participant::Participant (IdentityAddress &&address) : Object(*new ParticipantPrivate) { L_D(); - d->contactAddr = move(address); - d->addr = IdentityAddress(address); + d->addr = address; } // ----------------------------------------------------------------------------- @@ -104,11 +102,6 @@ const IdentityAddress& Participant::getAddress () const { return d->addr; } -const Address& Participant::getContactAddress () const { - L_D(); - return d->contactAddr; -} - // ----------------------------------------------------------------------------- bool Participant::isAdmin () const { diff --git a/src/conference/participant.h b/src/conference/participant.h index 9b1b3b482..00c0a687a 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -22,7 +22,6 @@ #include -#include "address/address.h" #include "address/identity-address.h" #include "object/object.h" #include "conference/params/call-session-params.h" @@ -50,11 +49,10 @@ class Participant : public Object { friend class ServerGroupChatRoomPrivate; public: - explicit Participant (const Address &address); - explicit Participant (Address &&address); + explicit Participant (const IdentityAddress &address); + explicit Participant (IdentityAddress &&address); const IdentityAddress& getAddress () const; - const Address& getContactAddress () const; bool isAdmin () const; private: diff --git a/src/conference/remote-conference.cpp b/src/conference/remote-conference.cpp index 603939bbf..eced72bde 100644 --- a/src/conference/remote-conference.cpp +++ b/src/conference/remote-conference.cpp @@ -30,7 +30,7 @@ LINPHONE_BEGIN_NAMESPACE RemoteConference::RemoteConference ( const shared_ptr &core, - const Address &myAddress, + const IdentityAddress &myAddress, CallListener *listener ) : Conference(*new RemoteConferencePrivate, core, myAddress, listener) { L_D(); @@ -44,7 +44,7 @@ RemoteConference::~RemoteConference () { // ----------------------------------------------------------------------------- -void RemoteConference::addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) { +void RemoteConference::addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) { L_D(); shared_ptr participant = findParticipant(addr); if (participant) @@ -66,13 +66,11 @@ void RemoteConference::removeParticipant (const shared_ptr &p } } -string RemoteConference::getResourceLists (const list
      &addresses) const { +string RemoteConference::getResourceLists (const list &addresses) const { Xsd::ResourceLists::ResourceLists rl = Xsd::ResourceLists::ResourceLists(); Xsd::ResourceLists::ListType l = Xsd::ResourceLists::ListType(); for (const auto &addr : addresses) { - Xsd::ResourceLists::EntryType entry = Xsd::ResourceLists::EntryType(addr.asStringUriOnly()); - if (!addr.getDisplayName().empty()) - entry.setDisplayName(Xsd::ResourceLists::DisplayName(addr.getDisplayName())); + Xsd::ResourceLists::EntryType entry = Xsd::ResourceLists::EntryType(addr.asString()); l.getEntry().push_back(entry); } rl.getList().push_back(l); @@ -85,14 +83,14 @@ string RemoteConference::getResourceLists (const list
      &addresses) const // ----------------------------------------------------------------------------- -void RemoteConference::onConferenceCreated (const Address &addr) {} +void RemoteConference::onConferenceCreated (const IdentityAddress &addr) {} -void RemoteConference::onConferenceTerminated (const Address &addr) { +void RemoteConference::onConferenceTerminated (const IdentityAddress &addr) { L_D(); d->eventHandler->unsubscribe(); } -void RemoteConference::onFirstNotifyReceived (const Address &addr) {} +void RemoteConference::onFirstNotifyReceived (const IdentityAddress &addr) {} void RemoteConference::onParticipantAdded (const std::shared_ptr &event, bool isFullState) { (void)event; diff --git a/src/conference/remote-conference.h b/src/conference/remote-conference.h index fa85faeb6..13613c615 100644 --- a/src/conference/remote-conference.h +++ b/src/conference/remote-conference.h @@ -34,20 +34,20 @@ class LINPHONE_PUBLIC RemoteConference : public Conference, public ConferenceLis friend class ClientGroupChatRoomPrivate; public: - RemoteConference (const std::shared_ptr &core, const Address &myAddress, CallListener *listener = nullptr); + RemoteConference (const std::shared_ptr &core, const IdentityAddress &myAddress, CallListener *listener = nullptr); virtual ~RemoteConference(); /* ConferenceInterface */ - void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; + void addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) override; void removeParticipant (const std::shared_ptr &participant) override; - std::string getResourceLists (const std::list
      &addresses) const; + std::string getResourceLists (const std::list &addresses) const; protected: /* ConferenceListener */ - void onConferenceCreated (const Address &addr) override; - void onConferenceTerminated (const Address &addr) override; - void onFirstNotifyReceived (const Address &addr) override; + void onConferenceCreated (const IdentityAddress &addr) override; + void onConferenceTerminated (const IdentityAddress &addr) override; + void onFirstNotifyReceived (const IdentityAddress &addr) override; void onParticipantAdded (const std::shared_ptr &event, bool isFullState) override; void onParticipantRemoved (const std::shared_ptr &event, bool isFullState) override; void onParticipantSetAdmin (const std::shared_ptr &event, bool isFullState) override; diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index ff1ae2930..5cb142c5b 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -448,9 +448,9 @@ public: ~ConferenceEventTester (); private: - void onConferenceCreated (const Address &addr) override; - void onConferenceTerminated (const Address &addr) override; - void onFirstNotifyReceived (const Address &addr) override; + void onConferenceCreated (const IdentityAddress &addr) override; + void onConferenceTerminated (const IdentityAddress &addr) override; + void onFirstNotifyReceived (const IdentityAddress &addr) override; void onParticipantAdded (const shared_ptr &event, bool isFullState) override; void onParticipantRemoved (const shared_ptr &event, bool isFullState) override; void onParticipantSetAdmin (const shared_ptr &event, bool isFullState) override; @@ -473,28 +473,28 @@ ConferenceEventTester::~ConferenceEventTester () { delete handler; } -void ConferenceEventTester::onConferenceCreated (const Address &addr) {} +void ConferenceEventTester::onConferenceCreated (const IdentityAddress &addr) {} -void ConferenceEventTester::onConferenceTerminated (const Address &addr) {} +void ConferenceEventTester::onConferenceTerminated (const IdentityAddress &addr) {} -void ConferenceEventTester::onFirstNotifyReceived (const Address &addr) {} +void ConferenceEventTester::onFirstNotifyReceived (const IdentityAddress &addr) {} void ConferenceEventTester::onParticipantAdded (const shared_ptr &event, bool isFullState) { (void)isFullState; // unused - const Address addr = event->getParticipantAddress(); + const IdentityAddress addr = event->getParticipantAddress(); participants.insert(pair(addr.asString(), FALSE)); participantDevices.insert(pair(addr.asString(), 0)); } void ConferenceEventTester::onParticipantRemoved (const shared_ptr &event, bool isFullState) { (void)isFullState; // unused - const Address addr = event->getParticipantAddress(); + const IdentityAddress addr = event->getParticipantAddress(); participants.erase(addr.asString()); participantDevices.erase(addr.asString()); } void ConferenceEventTester::onParticipantSetAdmin (const shared_ptr &event, bool isFullState) { (void)isFullState; // unused - const Address addr = event->getParticipantAddress(); + const IdentityAddress addr = event->getParticipantAddress(); auto it = participants.find(addr.asString()); if (it != participants.end()) it->second = (event->getType() == EventLog::Type::ConferenceParticipantSetAdmin); @@ -507,7 +507,7 @@ void ConferenceEventTester::onSubjectChanged(const shared_ptr &event, bool isFullState) { (void)isFullState; // unused - const Address addr = event->getParticipantAddress(); + const IdentityAddress addr = event->getParticipantAddress(); auto it = participantDevices.find(addr.asString()); if (it != participantDevices.end()) it->second++; @@ -516,7 +516,7 @@ void ConferenceEventTester::onParticipantDeviceAdded (const shared_ptr &event, bool isFullState) { (void)isFullState; // unused - const Address addr = event->getParticipantAddress(); + const IdentityAddress addr = event->getParticipantAddress(); auto it = participantDevices.find(addr.asString()); if (it != participantDevices.end() && it->second > 0) it->second--; @@ -827,7 +827,7 @@ void send_first_notify() { LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE( L_ATTR_GET(L_GET_PRIVATE(localConf), eventHandler) ); - const_cast
      (localConf.getConferenceAddress()) = addr; + const_cast(localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; @@ -876,7 +876,7 @@ void send_added_notify() { LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE( L_ATTR_GET(L_GET_PRIVATE(localConf), eventHandler) ); - const_cast
      (localConf.getConferenceAddress()) = addr; + const_cast(localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; @@ -932,7 +932,7 @@ void send_removed_notify() { LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE( L_ATTR_GET(L_GET_PRIVATE(localConf), eventHandler) ); - const_cast
      (localConf.getConferenceAddress()) = addr; + const_cast(localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; @@ -985,7 +985,7 @@ void send_admined_notify() { LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE( L_ATTR_GET(L_GET_PRIVATE(localConf), eventHandler) ); - const_cast
      (localConf.getConferenceAddress()) = addr; + const_cast(localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; @@ -1037,7 +1037,7 @@ void send_unadmined_notify() { LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE( L_ATTR_GET(L_GET_PRIVATE(localConf), eventHandler) ); - const_cast
      (localConf.getConferenceAddress()) = addr; + const_cast(localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; @@ -1091,7 +1091,7 @@ void send_subject_changed_notify () { LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE( L_ATTR_GET(L_GET_PRIVATE(localConf), eventHandler) ); - const_cast
      (localConf.getConferenceAddress()) = addr; + const_cast(localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; @@ -1150,7 +1150,7 @@ void send_device_added_notify() { LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE( L_ATTR_GET(L_GET_PRIVATE(localConf), eventHandler) ); - const_cast
      (localConf.getConferenceAddress()) = addr; + const_cast(localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; @@ -1203,7 +1203,7 @@ void send_device_removed_notify() { LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE( L_ATTR_GET(L_GET_PRIVATE(localConf), eventHandler) ); - const_cast
      (localConf.getConferenceAddress()) = addr; + const_cast(localConf.getConferenceAddress()) = addr; string notify = localHandlerPrivate->createNotifyFullState(); const_cast(tester.handler->getChatRoomId().getPeerAddress()) = addr; From d2a7cfafb30a1dc858a68009bc8138c40cb81d88 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 21 Nov 2017 10:52:13 +0100 Subject: [PATCH 0806/2215] Call new mediastreamer2 stream type API to fix ringing from linphone in wrong stream on Android --- coreapi/linphonecore.c | 1 + src/conference/session/media-session.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 95dd2aed2..e1ea4e478 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3697,6 +3697,7 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ if (lc->ringstream && lc->dmfs_playing_start_time!=0){ linphone_core_stop_dtmf_stream(lc); } + ms_snd_card_set_stream_type(ringcard, MS_SND_CARD_STREAM_RING); linphone_ringtoneplayer_start(lc->factory, lc->ringtoneplayer, ringcard, lc->sound_conf.local_ring, 2000); }else{ /* else play a tone within the context of the current call */ diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 9a8f6ae56..74def1064 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -2584,6 +2584,11 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool captcard = playcard = nullptr; } #endif + + if (playcard) { + ms_snd_card_set_stream_type(playcard, MS_SND_CARD_STREAM_VOICE); + } + bool useEc = captcard && linphone_core_echo_cancellation_enabled(core); audio_stream_enable_echo_canceller(audioStream, useEc); if (playcard && (stream->max_rate > 0)) From 13f4afe16552cb5630eaf88d2f4b4ef11bd58476 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 21 Nov 2017 14:21:22 +0100 Subject: [PATCH 0807/2215] feat(MainDb): supports local chat room id --- src/chat/chat-message/chat-message.cpp | 18 +- src/chat/chat-message/chat-message.h | 3 - src/chat/chat-room/chat-room-id.cpp | 5 + src/chat/chat-room/chat-room-id.h | 2 + src/db/main-db-p.h | 30 +- src/db/main-db.cpp | 478 +++++++++++++++---------- tester/main-db-tester.cpp | 303 ++++++++-------- 7 files changed, 478 insertions(+), 361 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index cab953b15..8b758762c 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -675,11 +675,11 @@ ChatMessage::ChatMessage (const shared_ptr &chatRoom, ChatMessage::Dir d->chatRoom = chatRoom; d->chatRoomId = chatRoom->getChatRoomId(); if (direction == Direction::Outgoing) { - d->fromAddress = chatRoom->getLocalAddress(); - d->toAddress = chatRoom->getPeerAddress(); + d->fromAddress = d->chatRoomId.getLocalAddress(); + d->toAddress = d->chatRoomId.getPeerAddress(); } else { - d->fromAddress = chatRoom->getPeerAddress(); - d->toAddress = chatRoom->getLocalAddress(); + d->fromAddress = d->chatRoomId.getPeerAddress(); + d->toAddress = d->chatRoomId.getLocalAddress(); } d->direction = direction; } @@ -766,16 +766,6 @@ const IdentityAddress &ChatMessage::getToAddress () const { return d->toAddress; } -const IdentityAddress &ChatMessage::getLocalAddress () const { - L_D(); - return d->chatRoomId.getLocalAddress(); -} - -const IdentityAddress &ChatMessage::getRemoteAddress () const { - L_D(); - return d->direction == Direction::Outgoing ? d->chatRoomId.getPeerAddress() : d->fromAddress; -} - // ----------------------------------------------------------------------------- const LinphoneErrorInfo *ChatMessage::getErrorInfo () const { diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index 67988c153..952b3abd3 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -83,9 +83,6 @@ public: const IdentityAddress &getFromAddress () const; const IdentityAddress &getToAddress () const; - const IdentityAddress &getLocalAddress () const; - const IdentityAddress &getRemoteAddress () const; - // TODO: Return a cpp reference. const LinphoneErrorInfo *getErrorInfo () const; diff --git a/src/chat/chat-room/chat-room-id.cpp b/src/chat/chat-room/chat-room-id.cpp index 02bec15d9..5f5023d2e 100644 --- a/src/chat/chat-room/chat-room-id.cpp +++ b/src/chat/chat-room/chat-room-id.cpp @@ -74,4 +74,9 @@ const IdentityAddress &ChatRoomId::getLocalAddress () const { return d->localAddress; } +bool ChatRoomId::isValid () const { + L_D(); + return d->peerAddress.isValid() && d->localAddress.isValid(); +} + LINPHONE_END_NAMESPACE diff --git a/src/chat/chat-room/chat-room-id.h b/src/chat/chat-room/chat-room-id.h index c78a2b51f..b496a3340 100644 --- a/src/chat/chat-room/chat-room-id.h +++ b/src/chat/chat-room/chat-room-id.h @@ -44,6 +44,8 @@ public: const IdentityAddress &getPeerAddress () const; const IdentityAddress &getLocalAddress () const; + bool isValid () const; + private: L_DECLARE_PRIVATE(ChatRoomId); }; diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index fb30249f0..bd35e0615 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -42,10 +42,20 @@ private: long long insertSipAddress (const std::string &sipAddress); void insertContent (long long messageEventId, const Content &content); long long insertContentType (const std::string &contentType); - long long insertChatRoom (long long sipAddressId, int capabilities, const tm &date); + long long insertChatRoom ( + long long peerSipAddressId, + long long localSipAddressId, + int capabilities, + const tm &date + ); + long long insertChatRoom (const ChatRoomId &chatRoomId, int capabilities, const tm &date); void insertChatRoomParticipant (long long chatRoomId, long long sipAddressId, bool isAdmin); void insertChatMessageParticipant (long long messageEventId, long long sipAddressId, int state); + long long selectSipAddressId (const std::string &sipAddress) const; + long long selectChatRoomId (long long peerSipAddressId, long long localSipAddressId) const; + long long selectChatRoomId (const ChatRoomId &chatRoomId) const; + // --------------------------------------------------------------------------- // Events API. // --------------------------------------------------------------------------- @@ -54,56 +64,56 @@ private: long long eventId, EventLog::Type type, time_t date, - const std::string &peerAddress + const ChatRoomId &chatRoomId ) const; std::shared_ptr selectConferenceEvent ( long long eventId, EventLog::Type type, time_t date, - const std::string &peerAddress + const ChatRoomId &chatRoomId ) const; std::shared_ptr selectConferenceCallEvent ( long long eventId, EventLog::Type type, time_t date, - const std::string &peerAddress + const ChatRoomId &chatRoomId ) const; std::shared_ptr selectConferenceChatMessageEvent ( long long eventId, EventLog::Type type, time_t date, - const std::string &peerAddress + const ChatRoomId &chatRoomId ) const; std::shared_ptr selectConferenceParticipantEvent ( long long eventId, EventLog::Type type, time_t date, - const std::string &peerAddress + const ChatRoomId &chatRoomId ) const; std::shared_ptr selectConferenceParticipantDeviceEvent ( long long eventId, EventLog::Type type, time_t date, - const std::string &peerAddress + const ChatRoomId &chatRoomId ) const; std::shared_ptr selectConferenceSubjectEvent ( long long eventId, EventLog::Type type, time_t date, - const std::string &peerAddress + const ChatRoomId &chatRoomId ) const; long long insertEvent (const std::shared_ptr &eventLog); long long insertConferenceEvent (const std::shared_ptr &eventLog, long long *chatRoomId = nullptr); long long insertConferenceCallEvent (const std::shared_ptr &eventLog); long long insertConferenceChatMessageEvent (const std::shared_ptr &eventLog); - long long insertConferenceNotifiedEvent (const std::shared_ptr &eventLog); + long long insertConferenceNotifiedEvent (const std::shared_ptr &eventLog, long long *chatRoomId = nullptr); long long insertConferenceParticipantEvent (const std::shared_ptr &eventLog); long long insertConferenceParticipantDeviceEvent (const std::shared_ptr &eventLog); long long insertConferenceSubjectEvent (const std::shared_ptr &eventLog); @@ -113,7 +123,7 @@ private: // --------------------------------------------------------------------------- std::shared_ptr getEventFromCache (long long eventId) const; - void invalidEventsFromQuery (const std::string &query, const std::string &peerAddress); + void invalidConferenceEventsFromQuery (const std::string &query, long long chatRoomId); L_DECLARE_PUBLIC(MainDb); }; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index ff4d64310..f008e2d03 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -20,8 +20,6 @@ #include #include -#undef SOCI_ENABLED - #ifdef SOCI_ENABLED #include #endif // ifdef SOCI_ENABLED @@ -29,7 +27,6 @@ #include "linphone/utils/utils.h" #include "chat/chat-message/chat-message-p.h" -#include "chat/chat-room/chat-room.h" #include "chat/chat-room/client-group-chat-room.h" #include "conference/participant.h" #include "content/content-type.h" @@ -125,9 +122,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), L_Q(); soci::session *session = dbSession.getBackendSession(); - long long id; - *session << "SELECT id FROM sip_address WHERE value = :sipAddress", soci::use(sipAddress), soci::into(id); - if (session->got_data()) + long long id = selectSipAddressId(sipAddress); + if (id >= 0) return id; lInfo() << "Insert new sip address in database: `" << sipAddress << "`."; @@ -165,23 +161,44 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return q->getLastInsertId(); } - long long MainDbPrivate::insertChatRoom (long long sipAddressId, int capabilities, const tm &date) { + long long MainDbPrivate::insertChatRoom ( + long long peerSipAddressId, + long long localSipAddressId, + int capabilities, + const tm &date + ) { + L_Q(); + soci::session *session = dbSession.getBackendSession(); - long long id; - *session << "SELECT peer_sip_address_id FROM chat_room WHERE peer_sip_address_id = :sipAddressId", - soci::use(sipAddressId), soci::into(id); - if (!session->got_data()) { - lInfo() << "Insert new chat room in database: `" << sipAddressId << "` (capabilities=" << capabilities << ")."; - *session << "INSERT INTO chat_room (peer_sip_address_id, creation_date, last_update_date, capabilities, subject) VALUES" - " (:sipAddressId, :creationDate, :lastUpdateDate, :capabilities, '')", - soci::use(sipAddressId), soci::use(date), soci::use(date), soci::use(capabilities); - } - else - *session << "UPDATE chat_room SET last_update_date = :lastUpdateDate WHERE peer_sip_address_id = :sipAddressId", - soci::use(date), soci::use(sipAddressId); + long long id = selectChatRoomId(peerSipAddressId, localSipAddressId); + if (id < 0) { + lInfo() << "Insert new chat room in database: (peer=" << peerSipAddressId << + ", local=" << localSipAddressId << ", capabilities=" << capabilities << ")."; + *session << "INSERT INTO chat_room (" + " peer_sip_address_id, local_sip_address_id, creation_date, last_update_date, capabilities, subject" + ") VALUES (:peerSipAddressId, :localSipAddressId, :creationDate, :lastUpdateDate, :capabilities, '')", + soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::use(date), soci::use(date), + soci::use(capabilities); - return sipAddressId; + return q->getLastInsertId(); + } + + // Update date if chat room exists. Do not touch capabilities. + *session << "UPDATE chat_room SET last_update_date = :lastUpdateDate" + " WHERE id = :chatRoomId", + soci::use(date), soci::use(id); + + return id; + } + + long long MainDbPrivate::insertChatRoom (const ChatRoomId &chatRoomId, int capabilities, const tm &date) { + return insertChatRoom ( + insertSipAddress(chatRoomId.getPeerAddress().asString()), + insertSipAddress(chatRoomId.getLocalAddress().asString()), + capabilities, + date + ); } void MainDbPrivate::insertChatRoomParticipant (long long chatRoomId, long long sipAddressId, bool isAdmin) { @@ -214,13 +231,43 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::use(eventId), soci::use(sipAddressId), soci::use(state); } + long long MainDbPrivate::selectSipAddressId (const std::string &sipAddress) const { + soci::session *session = dbSession.getBackendSession(); + + long long id; + *session << "SELECT id FROM sip_address WHERE value = :sipAddress", soci::use(sipAddress), soci::into(id); + return session->got_data() ? id : -1; + } + + long long MainDbPrivate::selectChatRoomId (long long peerSipAddressId, long long localSipAddressId) const { + soci::session *session = dbSession.getBackendSession(); + + long long id; + *session << "SELECT id FROM chat_room" + " WHERE peer_sip_address_id = :peerSipAddressId AND local_sip_address_id = :localSipAddressId", + soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::into(id); + return session->got_data() ? id : -1; + } + + long long MainDbPrivate::selectChatRoomId (const ChatRoomId &chatRoomId) const { + long long peerSipAddressId = selectSipAddressId(chatRoomId.getPeerAddress().asString()); + if (peerSipAddressId < 0) + return -1; + + long long localSipAddressId = selectSipAddressId(chatRoomId.getLocalAddress().asString()); + if (localSipAddressId < 0) + return -1; + + return selectChatRoomId(peerSipAddressId, localSipAddressId); + } + // ----------------------------------------------------------------------------- shared_ptr MainDbPrivate::selectGenericConferenceEvent ( long long eventId, EventLog::Type type, time_t date, - const string &peerAddress + const ChatRoomId &chatRoomId ) const { switch (type) { case EventLog::Type::None: @@ -228,27 +275,27 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), case EventLog::Type::ConferenceCreated: case EventLog::Type::ConferenceDestroyed: - return selectConferenceEvent(eventId, type, date, peerAddress); + return selectConferenceEvent(eventId, type, date, chatRoomId); case EventLog::Type::ConferenceCallStart: case EventLog::Type::ConferenceCallEnd: - return selectConferenceCallEvent(eventId, type, date, peerAddress); + return selectConferenceCallEvent(eventId, type, date, chatRoomId); case EventLog::Type::ConferenceChatMessage: - return selectConferenceChatMessageEvent(eventId, type, date, peerAddress); + return selectConferenceChatMessageEvent(eventId, type, date, chatRoomId); case EventLog::Type::ConferenceParticipantAdded: case EventLog::Type::ConferenceParticipantRemoved: case EventLog::Type::ConferenceParticipantSetAdmin: case EventLog::Type::ConferenceParticipantUnsetAdmin: - return selectConferenceParticipantEvent(eventId, type, date, peerAddress); + return selectConferenceParticipantEvent(eventId, type, date, chatRoomId); case EventLog::Type::ConferenceParticipantDeviceAdded: case EventLog::Type::ConferenceParticipantDeviceRemoved: - return selectConferenceParticipantDeviceEvent(eventId, type, date, peerAddress); + return selectConferenceParticipantDeviceEvent(eventId, type, date, chatRoomId); case EventLog::Type::ConferenceSubjectChanged: - return selectConferenceSubjectEvent(eventId, type, date, peerAddress); + return selectConferenceSubjectEvent(eventId, type, date, chatRoomId); } return nullptr; @@ -258,12 +305,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long, EventLog::Type type, time_t date, - const string &peerAddress + const ChatRoomId &chatRoomId ) const { return make_shared( type, date, - Address(peerAddress) + chatRoomId ); } @@ -271,7 +318,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long eventId, EventLog::Type type, time_t date, - const string &peerAddress + const ChatRoomId &chatRoomId ) const { // TODO. return nullptr; @@ -281,50 +328,47 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long eventId, EventLog::Type type, time_t date, - const string &peerAddress + const ChatRoomId &chatRoomId ) const { L_Q(); shared_ptr core = q->getCore(); - // TODO: Avoid address creation. - shared_ptr chatRoom = core->findChatRoom(Address(peerAddress)); + shared_ptr chatRoom = core->findChatRoom(chatRoomId); if (!chatRoom) return nullptr; // TODO: Use cache, do not fetch the same message twice. // 1 - Fetch chat message. - shared_ptr chatMessage = make_shared(chatRoom); + shared_ptr chatMessage; { - string localSipAddress; - string remoteSipAddress; + string fromSipAddress; + string toSipAddress; string imdnMessageId; int state; int direction; int isSecured; soci::session *session = dbSession.getBackendSession(); - *session << "SELECT local_sip_address.value, remote_sip_address.value, imdn_message_id, state, direction, is_secured" - " FROM event, conference_chat_message_event, sip_address AS local_sip_address," - " sip_address AS remote_sip_address" + *session << "SELECT from_sip_address.value, to_sip_address.value, imdn_message_id, state, direction, is_secured" + " FROM event, conference_chat_message_event, sip_address AS from_sip_address," + " sip_address AS to_sip_address" " WHERE event_id = :eventId" " AND event_id = event.id" - " AND local_sip_address_id = local_sip_address.id" - " AND remote_sip_address_id = remote_sip_address.id", soci::into(localSipAddress), soci::into(remoteSipAddress), + " AND from_sip_address_id = from_sip_address.id" + " AND to_sip_address_id = to_sip_address.id", soci::into(fromSipAddress), soci::into(toSipAddress), soci::into(imdnMessageId), soci::into(state), soci::into(direction), soci::into(isSecured), soci::use(eventId); + chatMessage = shared_ptr(new ChatMessage( + chatRoom, + static_cast(direction) + )); chatMessage->getPrivate()->setState(static_cast(state), true); - chatMessage->getPrivate()->setDirection(static_cast(direction)); chatMessage->setIsSecured(static_cast(isSecured)); - if (direction == static_cast(ChatMessage::Direction::Outgoing)) { - chatMessage->setFromAddress(Address(localSipAddress)); - chatMessage->setToAddress(Address(remoteSipAddress)); - } else { - chatMessage->setFromAddress(Address(remoteSipAddress)); - chatMessage->setToAddress(Address(localSipAddress)); - } + chatMessage->getPrivate()->forceFromAddress(IdentityAddress(fromSipAddress)); + chatMessage->getPrivate()->forceToAddress(IdentityAddress(toSipAddress)); } // 2 - Fetch contents. @@ -363,7 +407,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), content->setContentType(contentType); content->setBody(row.get(2)); - chatMessage->addContent(content); + chatMessage->addContent(*content); } } @@ -378,7 +422,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long eventId, EventLog::Type type, time_t date, - const string &peerAddress + const ChatRoomId &chatRoomId ) const { unsigned int notifyId; string participantAddress; @@ -394,9 +438,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return make_shared( type, date, - Address(peerAddress), + chatRoomId, notifyId, - Address(participantAddress) + IdentityAddress(participantAddress) ); } @@ -404,30 +448,30 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long eventId, EventLog::Type type, time_t date, - const string &peerAddress + const ChatRoomId &chatRoomId ) const { unsigned int notifyId; string participantAddress; - string gruuAddress; + string deviceAddress; soci::session *session = dbSession.getBackendSession(); - *session << "SELECT notify_id, participant_address.value, gruu_address.value" + *session << "SELECT notify_id, participant_address.value, device_address.value" " FROM conference_notified_event, conference_participant_event, conference_participant_device_event," - " sip_address AS participant_address, sip_address AS gruu_address" + " sip_address AS participant_address, sip_address AS device_address" " WHERE conference_participant_device_event.event_id = :eventId" " AND conference_participant_event.event_id = conference_participant_device_event.event_id" " AND conference_notified_event.event_id = conference_participant_event.event_id" " AND participant_address.id = participant_address_id" - " AND gruu_address.id = gruu_address_id", - soci::into(notifyId), soci::into(participantAddress), soci::into(gruuAddress), soci::use(eventId); + " AND device_address.id = device_address_id", + soci::into(notifyId), soci::into(participantAddress), soci::into(deviceAddress), soci::use(eventId); return make_shared( type, date, - Address(peerAddress), + chatRoomId, notifyId, - Address(participantAddress), - Address(gruuAddress) + IdentityAddress(participantAddress), + IdentityAddress(deviceAddress) ); } @@ -435,7 +479,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long eventId, EventLog::Type type, time_t date, - const string &peerAddress + const ChatRoomId &chatRoomId ) const { unsigned int notifyId; string subject; @@ -449,7 +493,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return make_shared( date, - Address(peerAddress), + chatRoomId, notifyId, subject ); @@ -462,19 +506,34 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO event (type, date) VALUES (:type, :date)", - soci::use(static_cast(eventLog->getType())), soci::use(Utils::getTimeTAsTm(eventLog->getTime())); + soci::use(static_cast(eventLog->getType())), + soci::use(Utils::getTimeTAsTm(eventLog->getCreationTime())); return q->getLastInsertId(); } long long MainDbPrivate::insertConferenceEvent (const shared_ptr &eventLog, long long *chatRoomId) { - long long eventId = insertEvent(eventLog); - long long curChatRoomId = insertSipAddress( - static_pointer_cast(eventLog)->getConferenceAddress().asString() - ); + shared_ptr conferenceEvent = static_pointer_cast(eventLog); - soci::session *session = dbSession.getBackendSession(); - *session << "INSERT INTO conference_event (event_id, chat_room_id)" - " VALUES (:eventId, :chatRoomId)", soci::use(eventId), soci::use(curChatRoomId); + long long eventId = -1; + long long curChatRoomId = selectChatRoomId(conferenceEvent->getChatRoomId()); + if (curChatRoomId < 0) { + // A conference event can be inserted in database only if chat room exists. + // Otherwise it's an error. + const ChatRoomId &chatRoomId = conferenceEvent->getChatRoomId(); + lError() << "Unable to find chat room storage id of (peer=" + + chatRoomId.getPeerAddress().asString() + + ", local=" + chatRoomId.getLocalAddress().asString() + "`)."; + } else { + eventId = insertEvent(eventLog); + + soci::session *session = dbSession.getBackendSession(); + *session << "INSERT INTO conference_event (event_id, chat_room_id)" + " VALUES (:eventId, :chatRoomId)", soci::use(eventId), soci::use(curChatRoomId); + + *session << "UPDATE chat_room SET last_update_date = :lastUpdateDate" + " WHERE id = :chatRoomId", soci::use(Utils::getTimeTAsTm(eventLog->getCreationTime())), + soci::use(curChatRoomId); + } if (chatRoomId) *chatRoomId = curChatRoomId; @@ -495,22 +554,21 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return -1; } - tm eventTime = Utils::getTimeTAsTm(eventLog->getTime()); - - long long localSipAddressId = insertSipAddress(chatMessage->getLocalAddress().asString()); - long long remoteSipAddressId = insertSipAddress(chatMessage->getRemoteAddress().asString()); - insertChatRoom(remoteSipAddressId, chatRoom->getCapabilities(), eventTime); long long eventId = insertConferenceEvent(eventLog); + if (eventId < 0) + return -1; + + long long fromSipAddressId = insertSipAddress(chatMessage->getFromAddress().asString()); + long long toSipAddressId = insertSipAddress(chatMessage->getToAddress().asString()); soci::session *session = dbSession.getBackendSession(); - *session << "INSERT INTO conference_chat_message_event (" - " event_id, local_sip_address_id, remote_sip_address_id," + " event_id, from_sip_address_id, to_sip_address_id," " state, direction, imdn_message_id, is_secured" ") VALUES (" " :eventId, :localSipaddressId, :remoteSipaddressId," " :state, :direction, :imdnMessageId, :isSecured" - ")", soci::use(eventId), soci::use(localSipAddressId), soci::use(remoteSipAddressId), + ")", soci::use(eventId), soci::use(fromSipAddressId), soci::use(toSipAddressId), soci::use(static_cast(chatMessage->getState())), soci::use(static_cast(chatMessage->getDirection())), soci::use(chatMessage->getImdnMessageId()), soci::use(chatMessage->isSecured() ? 1 : 0); @@ -520,22 +578,31 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return eventId; } - long long MainDbPrivate::insertConferenceNotifiedEvent (const shared_ptr &eventLog) { - long long chatRoomId; - long long eventId = insertConferenceEvent(eventLog, &chatRoomId); + long long MainDbPrivate::insertConferenceNotifiedEvent (const shared_ptr &eventLog, long long *chatRoomId) { + long long curChatRoomId; + long long eventId = insertConferenceEvent(eventLog, &curChatRoomId); + if (eventId < 0) + return -1; + unsigned int lastNotifyId = static_pointer_cast(eventLog)->getNotifyId(); soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_notified_event (event_id, notify_id)" " VALUES (:eventId, :notifyId)", soci::use(eventId), soci::use(lastNotifyId); *session << "UPDATE chat_room SET last_notify_id = :lastNotifyId WHERE peer_sip_address_id = :chatRoomId", - soci::use(lastNotifyId), soci::use(chatRoomId); + soci::use(lastNotifyId), soci::use(curChatRoomId); + + if (chatRoomId) + *chatRoomId = curChatRoomId; return eventId; } long long MainDbPrivate::insertConferenceParticipantEvent (const shared_ptr &eventLog) { long long eventId = insertConferenceNotifiedEvent(eventLog); + if (eventId < 0) + return -1; + long long participantAddressId = insertSipAddress( static_pointer_cast(eventLog)->getParticipantAddress().asString() ); @@ -549,25 +616,34 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long MainDbPrivate::insertConferenceParticipantDeviceEvent (const shared_ptr &eventLog) { long long eventId = insertConferenceParticipantEvent(eventLog); - long long gruuAddressId = insertSipAddress( - static_pointer_cast(eventLog)->getGruuAddress().asString() + if (eventId < 0) + return -1; + + long long deviceAddressId = insertSipAddress( + static_pointer_cast(eventLog)->getDeviceAddress().asString() ); soci::session *session = dbSession.getBackendSession(); - *session << "INSERT INTO conference_participant_device_event (event_id, gruu_address_id)" - " VALUES (:eventId, :gruuAddressId)", soci::use(eventId), soci::use(gruuAddressId); + *session << "INSERT INTO conference_participant_device_event (event_id, device_address_id)" + " VALUES (:eventId, :deviceAddressId)", soci::use(eventId), soci::use(deviceAddressId); return eventId; } long long MainDbPrivate::insertConferenceSubjectEvent (const shared_ptr &eventLog) { - long long eventId = insertConferenceNotifiedEvent(eventLog); + long long chatRoomId; + long long eventId = insertConferenceNotifiedEvent(eventLog, &chatRoomId); + if (eventId < 0) + return -1; + + const string &subject = static_pointer_cast(eventLog)->getSubject(); soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_subject_event (event_id, subject)" - " VALUES (:eventId, :subject)", soci::use(eventId), soci::use( - static_pointer_cast(eventLog)->getSubject() - ); + " VALUES (:eventId, :subject)", soci::use(eventId), soci::use(subject); + + *session << "UPDATE chat_room SET subject = :subject" + " WHERE id = :chatRoomId", soci::use(subject), soci::use(chatRoomId); return eventId; } @@ -585,11 +661,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return eventLog; } - void MainDbPrivate::invalidEventsFromQuery (const string &query, const string &peerAddress) { + void MainDbPrivate::invalidConferenceEventsFromQuery (const string &query, long long chatRoomId) { L_Q(); soci::session *session = dbSession.getBackendSession(); - soci::rowset rows = (session->prepare << query, soci::use(peerAddress)); + soci::rowset rows = (session->prepare << query, soci::use(chatRoomId)); for (const auto &row : rows) { shared_ptr eventLog = getEventFromCache( q->getBackend() == AbstractDb::Sqlite3 ? static_cast(row.get(0)) : row.get(0) @@ -631,6 +707,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS chat_room (" + " id" + primaryKeyStr("BIGINT UNSIGNED") + "," + // Server (for conference) or user sip address. " peer_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," @@ -643,17 +721,16 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " last_update_date DATE NOT NULL," // ConferenceChatRoom, BasicChatRoom, RTT... - "capabilities TINYINT UNSIGNED," + " capabilities TINYINT UNSIGNED," // Chatroom subject. " subject VARCHAR(255)," " last_notify_id INT UNSIGNED," - " PRIMARY KEY (peer_sip_address_id, local_sip_address_id)," " FOREIGN KEY (peer_sip_address_id)" " REFERENCES sip_address(id)" - " ON DELETE CASCADE" + " ON DELETE CASCADE," " FOREIGN KEY (local_sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" @@ -718,12 +795,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), "CREATE TABLE IF NOT EXISTS conference_participant_device_event (" " event_id" + primaryKeyStr("BIGINT UNSIGNED") + "," - " gruu_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " device_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," " FOREIGN KEY (event_id)" " REFERENCES conference_participant_event(event_id)" " ON DELETE CASCADE," - " FOREIGN KEY (gruu_address_id)" + " FOREIGN KEY (device_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" ") " + charset; @@ -743,8 +820,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), "CREATE TABLE IF NOT EXISTS conference_chat_message_event (" " event_id" + primaryKeyStr("BIGINT UNSIGNED") + "," - " local_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," - " remote_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " from_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " to_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," // See: https://tools.ietf.org/html/rfc5438#section-6.3 " imdn_message_id VARCHAR(255) NOT NULL," @@ -756,10 +833,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FOREIGN KEY (event_id)" " REFERENCES conference_event(event_id)" " ON DELETE CASCADE," - " FOREIGN KEY (local_sip_address_id)" + " FOREIGN KEY (from_sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE," - " FOREIGN KEY (remote_sip_address_id)" + " FOREIGN KEY (to_sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" ") " + charset; @@ -916,7 +993,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), tr.commit(); - soFarSoGood = true; + soFarSoGood = storageId >= 0; L_END_LOG_EXCEPTION @@ -984,15 +1061,13 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } list> MainDb::getConferenceNotifiedEvents ( - const string &peerAddress, + const ChatRoomId &chatRoomId, unsigned int lastNotifyId ) const { static const string query = "SELECT id, type, date FROM event" " WHERE id IN (" " SELECT event_id FROM conference_notified_event WHERE event_id IN (" - " SELECT event_id FROM conference_event WHERE chat_room_id = (" - " SELECT id FROM sip_address WHERE value = :peerAddress" - " )" + " SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" " ) AND notify_id > :lastNotifyId" " )"; @@ -1006,8 +1081,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), list> events; DurationLogger durationLogger( - "Get conference notified events of: `" + peerAddress + - "` (lastNotifyId=" + Utils::toString(lastNotifyId) + ")." + "Get conference notified events of: (peer=" + chatRoomId.getPeerAddress().asString() + + ", local=" + chatRoomId.getLocalAddress().asString() + + ", lastNotifyId=" + Utils::toString(lastNotifyId) + ")." ); L_BEGIN_LOG_EXCEPTION @@ -1015,7 +1091,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = d->dbSession.getBackendSession(); soci::transaction tr(*session); - soci::rowset rows = (session->prepare << query, soci::use(peerAddress), soci::use(lastNotifyId)); + soci::rowset rows = (session->prepare << query, soci::use(d->selectChatRoomId(chatRoomId)), soci::use(lastNotifyId)); for (const auto &row : rows) { long long eventId = getBackend() == Sqlite3 ? static_cast(row.get(0)) : row.get(0); shared_ptr eventLog = d->getEventFromCache(eventId); @@ -1024,7 +1100,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), eventId, static_cast(row.get(1)), Utils::getTmAsTimeT(row.get(2)), - peerAddress + chatRoomId )); } @@ -1033,7 +1109,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return events; } - int MainDb::getChatMessagesCount (const string &peerAddress) const { + int MainDb::getChatMessagesCount (const ChatRoomId &chatRoomId) const { L_D(); if (!isConnected()) { @@ -1043,23 +1119,24 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), int count = 0; - DurationLogger durationLogger("Get chat messages count of: `" + peerAddress + "`."); + DurationLogger durationLogger( + "Get chat messages count of: (peer=" + chatRoomId.getPeerAddress().asString() + + ", local=" + chatRoomId.getLocalAddress().asString() + ")." + ); L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); string query = "SELECT COUNT(*) FROM conference_chat_message_event"; - if (peerAddress.empty()) + if (!chatRoomId.isValid()) *session << query, soci::into(count); else { query += " WHERE event_id IN (" - " SELECT event_id FROM conference_event WHERE chat_room_id = (" - " SELECT id FROM sip_address WHERE value = :peerAddress" - " )" + " SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" ")"; - *session << query, soci::use(peerAddress), soci::into(count); + *session << query, soci::use(d->selectChatRoomId(chatRoomId)), soci::into(count); } L_END_LOG_EXCEPTION @@ -1067,7 +1144,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return count; } - int MainDb::getUnreadChatMessagesCount (const string &peerAddress) const { + int MainDb::getUnreadChatMessagesCount (const ChatRoomId &chatRoomId) const { L_D(); if (!isConnected()) { @@ -1078,33 +1155,34 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), int count = 0; string query = "SELECT COUNT(*) FROM conference_chat_message_event WHERE"; - if (!peerAddress.empty()) + if (chatRoomId.isValid()) query += " event_id IN (" - " SELECT event_id FROM conference_event WHERE chat_room_id = (" - " SELECT id FROM sip_address WHERE value = :peerAddress" - " )" + " SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" ") AND"; query += " direction = " + Utils::toString(static_cast(ChatMessage::Direction::Incoming)) + + " AND state <> " + Utils::toString(static_cast(ChatMessage::State::Displayed)); - DurationLogger durationLogger("Get unread chat messages count of: `" + peerAddress + "`."); + DurationLogger durationLogger( + "Get unread chat messages count of: (peer=" + chatRoomId.getPeerAddress().asString() + + ", local=" + chatRoomId.getLocalAddress().asString() + ")." + ); L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); - if (peerAddress.empty()) + if (!chatRoomId.isValid()) *session << query, soci::into(count); else - *session << query, soci::use(peerAddress), soci::into(count); + *session << query, soci::use(d->selectChatRoomId(chatRoomId)), soci::into(count); L_END_LOG_EXCEPTION return count; } - void MainDb::markChatMessagesAsRead (const string &peerAddress) const { + void MainDb::markChatMessagesAsRead (const ChatRoomId &chatRoomId) const { L_D(); if (!isConnected()) { @@ -1112,47 +1190,51 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return; } - if (getUnreadChatMessagesCount(peerAddress) == 0) + if (getUnreadChatMessagesCount(chatRoomId) == 0) return; string query = "UPDATE FROM conference_chat_message_event" " SET state = " + Utils::toString(static_cast(ChatMessage::State::Displayed)); query += "WHERE"; - if (!peerAddress.empty()) + if (chatRoomId.isValid()) query += " event_id IN (" - " SELECT event_id FROM conference_event WHERE chat_room_id = (" - " SELECT id FROM sip_address WHERE value = :peerAddress" - " )" + " SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" ") AND"; query += " direction = " + Utils::toString(static_cast(ChatMessage::Direction::Incoming)); - DurationLogger durationLogger("Mark chat messages as read of: `" + peerAddress + "`."); + DurationLogger durationLogger( + "Mark chat messages as read of: (peer=" + chatRoomId.getPeerAddress().asString() + + ", local=" + chatRoomId.getLocalAddress().asString() + ")." + ); L_BEGIN_LOG_EXCEPTION soci::session *session = d->dbSession.getBackendSession(); - if (peerAddress.empty()) + if (!chatRoomId.isValid()) *session << query; else - *session << query, soci::use(peerAddress); + *session << query, soci::use(d->selectChatRoomId(chatRoomId)); L_END_LOG_EXCEPTION } - list> MainDb::getUnreadChatMessages (const std::string &peerAddress) const { - DurationLogger durationLogger("Get unread chat messages: `" + peerAddress + "`."); + list> MainDb::getUnreadChatMessages (const ChatRoomId &chatRoomId) const { + DurationLogger durationLogger( + "Get unread chat messages: (peer=" + chatRoomId.getPeerAddress().asString() + + ", local=" + chatRoomId.getLocalAddress().asString() + ")." + ); // TODO. return list>(); } - list> MainDb::getHistory (const string &peerAddress, int nLast, FilterMask mask) const { - return getHistoryRange(peerAddress, 0, nLast - 1, mask); + list> MainDb::getHistory (const ChatRoomId &chatRoomId, int nLast, FilterMask mask) const { + return getHistoryRange(chatRoomId, 0, nLast - 1, mask); } list> MainDb::getHistoryRange ( - const string &peerAddress, + const ChatRoomId &chatRoomId, int begin, int end, FilterMask mask @@ -1176,9 +1258,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), string query = "SELECT id, type, date FROM event" " WHERE id IN (" - " SELECT event_id FROM conference_event WHERE chat_room_id = (" - " SELECT id FROM sip_address WHERE value = :peerAddress" - " )" + " SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" " )"; query += buildSqlEventFilter({ ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter @@ -1194,8 +1274,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), query += " OFFSET " + Utils::toString(begin); DurationLogger durationLogger( - "Get history range of: `" + peerAddress + - "` (begin=" + Utils::toString(begin) + ", end=" + Utils::toString(end) + ")." + "Get history range of: (peer=" + chatRoomId.getPeerAddress().asString() + + ", local=" + chatRoomId.getLocalAddress().asString() + + ", begin=" + Utils::toString(begin) + ", end=" + Utils::toString(end) + ")." ); L_BEGIN_LOG_EXCEPTION @@ -1203,7 +1284,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = d->dbSession.getBackendSession(); soci::transaction tr(*session); - soci::rowset rows = (session->prepare << query, soci::use(peerAddress)); + soci::rowset rows = (session->prepare << query, soci::use(d->selectChatRoomId(chatRoomId))); for (const auto &row : rows) { // See: http://soci.sourceforge.net/doc/master/backends/ // `row id` is not supported by soci on Sqlite3. It's necessary to cast id to int... @@ -1215,7 +1296,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), eventId, static_cast(row.get(1)), Utils::getTmAsTimeT(row.get(2)), - peerAddress + chatRoomId ); if (event) @@ -1229,7 +1310,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return events; } - void MainDb::cleanHistory (const string &peerAddress, FilterMask mask) { + void MainDb::cleanHistory (const ChatRoomId &chatRoomId, FilterMask mask) { L_D(); if (!isConnected()) { @@ -1237,21 +1318,24 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return; } - string query = "SELECT event_id FROM conference_event WHERE chat_room_id = (" - " SELECT id FROM sip_address WHERE value = :peerAddress" - ")" + buildSqlEventFilter({ + string query = "SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" + + buildSqlEventFilter({ ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter }, mask); DurationLogger durationLogger( - "Clean history of: `" + peerAddress + "` (mask=" + Utils::toString(static_cast(mask)) + ")." + "Clean history of: (peer=" + chatRoomId.getPeerAddress().asString() + + ", local=" + chatRoomId.getLocalAddress().asString() + + ", mask=" + Utils::toString(static_cast(mask)) + ")." ); L_BEGIN_LOG_EXCEPTION - d->invalidEventsFromQuery(query, peerAddress); + long long dbChatRoomId = d->selectChatRoomId(chatRoomId); + + d->invalidConferenceEventsFromQuery(query, dbChatRoomId); soci::session *session = d->dbSession.getBackendSession(); - *session << "DELETE FROM event WHERE id IN (" + query + ")", soci::use(peerAddress); + *session << "DELETE FROM event WHERE id IN (" + query + ")", soci::use(dbChatRoomId); L_END_LOG_EXCEPTION } @@ -1259,9 +1343,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), // ----------------------------------------------------------------------------- list> MainDb::getChatRooms () const { - static const string query = "SELECT value, creation_date, last_update_date, capabilities, subject, last_notify_id" - " FROM chat_room, sip_address" - " WHERE peer_sip_address_id = id" + static const string query = "SELECT peer_sip_address.value, local_sip_address.value, creation_date, last_update_date, capabilities, subject, last_notify_id" + " FROM chat_room, sip_address AS peer_sip_address, sip_address AS local_sip_address" + " WHERE chat_room.peer_sip_address_id = peer_sip_address.id AND chat_room.local_sip_address_id = local_sip_address.id" " ORDER BY last_update_date DESC"; L_D(); @@ -1272,8 +1356,6 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } shared_ptr core = getCore(); - L_ASSERT(core); - list> chatRooms; DurationLogger durationLogger("Get chat rooms."); @@ -1284,18 +1366,21 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::rowset rows = (session->prepare << query); for (const auto &row : rows) { - Address peerAddress = Address(row.get(0)); - shared_ptr chatRoom = core->findChatRoom(peerAddress); + ChatRoomId chatRoomId = ChatRoomId( + IdentityAddress(row.get(0)), + IdentityAddress(row.get(1)) + ); + shared_ptr chatRoom = core->findChatRoom(chatRoomId); if (chatRoom) { chatRooms.push_back(chatRoom); continue; } - tm creationDate = row.get(1); - tm lastUpdateDate = row.get(2); - int capabilities = row.get(3); - string subject = row.get(4); - unsigned int lastNotifyId = static_cast(row.get(5, 0)); + tm creationDate = row.get(2); + tm lastUpdateDate = row.get(3); + int capabilities = row.get(4); + string subject = row.get(5); + unsigned int lastNotifyId = static_cast(row.get(6, 0)); // TODO: Use me. (void)creationDate; @@ -1304,16 +1389,17 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), if (capabilities & static_cast(ChatRoom::Capabilities::Basic)) { chatRoom = core->getPrivate()->createBasicChatRoom( - peerAddress, + chatRoomId, capabilities & static_cast(ChatRoom::Capabilities::RealTimeText) ); } else if (capabilities & static_cast(ChatRoom::Capabilities::Conference)) { - chatRoom = make_shared( - getCore(), - Address("sip:titi@sip.linphone.org"), // TODO: Fix me!!! - peerAddress.asStringUriOnly(), - subject - ); + // TODO: Fetch! + // chatRoom = make_shared( + // getCore(), + // Address("sip:titi@sip.linphone.org"), // TODO: Fix me!!! + // chatRoomId, + // subject + // ); } if (!chatRoom) @@ -1327,7 +1413,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return chatRooms; } - void MainDb::insertChatRoom (const string &peerAddress, int capabilities) { + void MainDb::insertChatRoom (const ChatRoomId &chatRoomId, int capabilities) { L_D(); if (!isConnected()) { @@ -1336,25 +1422,23 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } DurationLogger durationLogger( - "Insert chat room: `" + peerAddress + "` (capabilities=" + Utils::toString(capabilities) + ")." + "Insert chat room: peer=" + chatRoomId.getPeerAddress().asString() + + ", local=" + chatRoomId.getLocalAddress().asString() + + ", capabilities=" + Utils::toString(capabilities) + ")." ); L_BEGIN_LOG_EXCEPTION soci::transaction tr(*d->dbSession.getBackendSession()); - d->insertChatRoom( - d->insertSipAddress(peerAddress), - capabilities, - Utils::getTimeTAsTm(time(0)) - ); + d->insertChatRoom(chatRoomId, capabilities, Utils::getTimeTAsTm(time(0))); tr.commit(); L_END_LOG_EXCEPTION } - void MainDb::deleteChatRoom (const string &peerAddress) { + void MainDb::deleteChatRoom (const ChatRoomId &chatRoomId) { L_D(); if (!isConnected()) { @@ -1362,21 +1446,22 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return; } - DurationLogger durationLogger("Delete chat room: `" + peerAddress + "`."); + DurationLogger durationLogger( + "Delete chat room: (peer=" + chatRoomId.getPeerAddress().asString() + + ", local=" + chatRoomId.getLocalAddress().asString() + "`)." + ); L_BEGIN_LOG_EXCEPTION - d->invalidEventsFromQuery( - "SELECT event_id FROM conference_event WHERE chat_room_id = (" - " SELECT id FROM sip_address WHERE value = :peerAddress" - ")", - peerAddress + long long dbChatRoomId = d->selectChatRoomId(chatRoomId); + + d->invalidConferenceEventsFromQuery( + "SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId", + dbChatRoomId ); soci::session *session = d->dbSession.getBackendSession(); - *session << "DELETE FROM chat_room WHERE peer_sip_address_id = (" - " SELECT id FROM sip_address WHERE value = :peerAddress" - ")", soci::use(peerAddress); + *session << "DELETE FROM chat_room WHERE id = :chatRoomId", soci::use(dbChatRoomId); L_END_LOG_EXCEPTION } @@ -1497,16 +1582,21 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long eventId = getLastInsertId(); long long localSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_LOCAL_ADDRESS)); long long remoteSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_REMOTE_ADDRESS)); - long long chatRoomId = d->insertChatRoom(remoteSipAddressId, static_cast(ChatRoom::Capabilities::Basic), date); + long long chatRoomId = d->insertChatRoom( + remoteSipAddressId, + localSipAddressId, + static_cast(ChatRoom::Capabilities::Basic), + date + ); *session << "INSERT INTO conference_event (event_id, chat_room_id)" " VALUES (:eventId, :chatRoomId)", soci::use(eventId), soci::use(chatRoomId); *session << "INSERT INTO conference_chat_message_event (" - " event_id, local_sip_address_id, remote_sip_address_id," + " event_id, from_sip_address_id, to_sip_address_id," " state, direction, imdn_message_id, is_secured" ") VALUES (" - " :eventId, :localSipaddressId, :remoteSipaddressId," + " :eventId, :localSipAddressId, :remoteSipAddressId," " :state, :direction, '', :isSecured" ")", soci::use(eventId), soci::use(localSipAddressId), soci::use(remoteSipAddressId), soci::use(state), soci::use(direction), soci::use(message.get(LEGACY_MESSAGE_COL_IS_SECURED, 0)); diff --git a/tester/main-db-tester.cpp b/tester/main-db-tester.cpp index 681c94303..8fea5a552 100644 --- a/tester/main-db-tester.cpp +++ b/tester/main-db-tester.cpp @@ -34,149 +34,172 @@ using namespace LinphonePrivate; // ----------------------------------------------------------------------------- -// TODO: DEV GROUP CHAT +static const string getDatabasePath () { + static const string path = string(bc_tester_get_resource_dir_prefix()) + "db/linphone.db"; + return path; +} -// static const string getDatabasePath () { -// static const string path = string(bc_tester_get_resource_dir_prefix()) + "db/linphone.db"; -// return path; -// } -// -// // ----------------------------------------------------------------------------- -// -// class MainDbProvider { -// public: -// MainDbProvider () { -// mCoreManager = linphone_core_manager_new("marie_rc"); -// mMainDb = new MainDb(mCoreManager->lc->cppCore->getSharedFromThis()); -// mMainDb->connect(MainDb::Sqlite3, getDatabasePath()); -// } -// -// ~MainDbProvider () { -// delete mMainDb; -// linphone_core_manager_destroy(mCoreManager); -// } -// -// const MainDb &getMainDb () { -// return *mMainDb; -// } -// -// private: -// LinphoneCoreManager *mCoreManager; -// MainDb *mMainDb; -// }; -// -// // ----------------------------------------------------------------------------- -// -// static void open_database () { -// MainDbProvider provider; -// BC_ASSERT_TRUE(provider.getMainDb().isConnected()); -// } -// -// static void get_events_count () { -// MainDbProvider provider; -// const MainDb &mainDb = provider.getMainDb(); -// BC_ASSERT_EQUAL(mainDb.getEventsCount(), 4994, int, "%d"); -// BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceCallFilter), 0, int, "%d"); -// BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceInfoFilter), 18, int, "%d"); -// BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceChatMessageFilter), 5157, int, "%d"); -// BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::NoFilter), 4994, int, "%d"); -// } -// -// static void get_messages_count () { -// MainDbProvider provider; -// const MainDb &mainDb = provider.getMainDb(); -// BC_ASSERT_EQUAL(mainDb.getChatMessagesCount(), 5157, int, "%d"); -// BC_ASSERT_EQUAL(mainDb.getChatMessagesCount("sip:test-39@sip.linphone.org"), 3, int, "%d"); -// } -// -// static void get_unread_messages_count () { -// MainDbProvider provider; -// const MainDb &mainDb = provider.getMainDb(); -// BC_ASSERT_EQUAL(mainDb.getUnreadChatMessagesCount(), 2, int, "%d"); -// BC_ASSERT_EQUAL(mainDb.getUnreadChatMessagesCount("sip:test-39@sip.linphone.org"), 0, int, "%d"); -// } -// -// static void get_history () { -// MainDbProvider provider; -// const MainDb &mainDb = provider.getMainDb(); -// BC_ASSERT_EQUAL( -// mainDb.getHistoryRange("sip:test-39@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceChatMessageFilter).size(), -// 3, -// int, -// "%d" -// ); -// BC_ASSERT_EQUAL( -// mainDb.getHistoryRange("sip:test-7@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceCallFilter).size(), -// 0, -// int, -// "%d" -// ); -// BC_ASSERT_EQUAL( -// mainDb.getHistoryRange("sip:test-1@sip.linphone.org", 0, -1, MainDb::Filter::ConferenceChatMessageFilter).size(), -// 862, -// int, -// "%d" -// ); -// BC_ASSERT_EQUAL( -// mainDb.getHistory("sip:test-1@sip.linphone.org", 100, MainDb::Filter::ConferenceChatMessageFilter).size(), -// 100, -// int, -// "%d" -// ); -// } -// -// static void get_conference_notified_events () { -// MainDbProvider provider; -// const MainDb &mainDb = provider.getMainDb(); -// list> events = mainDb.getConferenceNotifiedEvents("sip:fake-group-2@sip.linphone.org", 1); -// BC_ASSERT_EQUAL(events.size(), 3, int, "%d"); -// if (events.size() != 3) -// return; -// -// shared_ptr event; -// auto it = events.cbegin(); -// -// event = *it; -// if (!BC_ASSERT_TRUE(event->getType() == EventLog::Type::ConferenceParticipantRemoved)) return; -// { -// shared_ptr participantEvent = static_pointer_cast(event); -// BC_ASSERT_TRUE(participantEvent->getConferenceAddress().asStringUriOnly() == "sip:fake-group-2@sip.linphone.org"); -// BC_ASSERT_TRUE(participantEvent->getParticipantAddress().asStringUriOnly() == "sip:test-11@sip.linphone.org"); -// BC_ASSERT_TRUE(participantEvent->getNotifyId() == 2); -// } -// -// event = *++it; -// if (!BC_ASSERT_TRUE(event->getType() == EventLog::Type::ConferenceParticipantDeviceAdded)) return; -// { -// shared_ptr deviceEvent = static_pointer_cast< -// ConferenceParticipantDeviceEvent -// >(event); -// BC_ASSERT_TRUE(deviceEvent->getConferenceAddress().asStringUriOnly() == "sip:fake-group-2@sip.linphone.org"); -// BC_ASSERT_TRUE(deviceEvent->getParticipantAddress().asStringUriOnly() == "sip:test-11@sip.linphone.org"); -// BC_ASSERT_TRUE(deviceEvent->getNotifyId() == 3); -// BC_ASSERT_TRUE(deviceEvent->getGruuAddress().asStringUriOnly() == "sip:gruu-address-1@sip.linphone.org"); -// } -// -// event = *++it; -// if (!BC_ASSERT_TRUE(event->getType() == EventLog::Type::ConferenceParticipantDeviceRemoved)) return; -// { -// shared_ptr deviceEvent = static_pointer_cast< -// ConferenceParticipantDeviceEvent -// >(event); -// BC_ASSERT_TRUE(deviceEvent->getConferenceAddress().asStringUriOnly() == "sip:fake-group-2@sip.linphone.org"); -// BC_ASSERT_TRUE(deviceEvent->getParticipantAddress().asStringUriOnly() == "sip:test-11@sip.linphone.org"); -// BC_ASSERT_TRUE(deviceEvent->getNotifyId() == 4); -// BC_ASSERT_TRUE(deviceEvent->getGruuAddress().asStringUriOnly() == "sip:gruu-address-1@sip.linphone.org"); -// } -// } +// ----------------------------------------------------------------------------- + +class MainDbProvider { +public: + MainDbProvider () { + mCoreManager = linphone_core_manager_new("marie_rc"); + mMainDb = new MainDb(mCoreManager->lc->cppCore->getSharedFromThis()); + mMainDb->connect(MainDb::Sqlite3, getDatabasePath()); + } + + ~MainDbProvider () { + delete mMainDb; + linphone_core_manager_destroy(mCoreManager); + } + + const MainDb &getMainDb () { + return *mMainDb; + } + +private: + LinphoneCoreManager *mCoreManager; + MainDb *mMainDb; +}; + +// ----------------------------------------------------------------------------- + +static void open_database () { + MainDbProvider provider; + BC_ASSERT_TRUE(provider.getMainDb().isConnected()); +} + +static void get_events_count () { + MainDbProvider provider; + const MainDb &mainDb = provider.getMainDb(); + BC_ASSERT_EQUAL(mainDb.getEventsCount(), 4994, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceCallFilter), 0, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceInfoFilter), 18, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceChatMessageFilter), 5157, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::NoFilter), 4994, int, "%d"); +} + +static void get_messages_count () { + MainDbProvider provider; + const MainDb &mainDb = provider.getMainDb(); + BC_ASSERT_EQUAL(mainDb.getChatMessagesCount(), 5157, int, "%d"); + BC_ASSERT_EQUAL( + mainDb.getChatMessagesCount( + ChatRoomId(IdentityAddress("sip:test-39@sip.linphone.org"), IdentityAddress("sip:test-39@sip.linphone.org")) + ), + 3, int, "%d" + ); +} + +static void get_unread_messages_count () { + MainDbProvider provider; + const MainDb &mainDb = provider.getMainDb(); + BC_ASSERT_EQUAL(mainDb.getUnreadChatMessagesCount(), 2, int, "%d"); + BC_ASSERT_EQUAL( + mainDb.getUnreadChatMessagesCount( + ChatRoomId(IdentityAddress("sip:test-39@sip.linphone.org"), IdentityAddress("sip:test-39@sip.linphone.org")) + ), + 0, int, "%d" + ); +} + +static void get_history () { + MainDbProvider provider; + const MainDb &mainDb = provider.getMainDb(); + BC_ASSERT_EQUAL( + mainDb.getHistoryRange( + ChatRoomId(IdentityAddress("sip:test-39@sip.linphone.org"), IdentityAddress("sip:test-39@sip.linphone.org")), + 0, -1, MainDb::Filter::ConferenceChatMessageFilter + ).size(), + 3, + int, + "%d" + ); + BC_ASSERT_EQUAL( + mainDb.getHistoryRange( + ChatRoomId(IdentityAddress("sip:test-7@sip.linphone.org"), IdentityAddress("sip:test-7@sip.linphone.org")), + 0, -1, MainDb::Filter::ConferenceCallFilter + ).size(), + 0, + int, + "%d" + ); + BC_ASSERT_EQUAL( + mainDb.getHistoryRange( + ChatRoomId(IdentityAddress("sip:test-1@sip.linphone.org"), IdentityAddress("sip:test-1@sip.linphone.org")), + 0, -1, MainDb::Filter::ConferenceChatMessageFilter + ).size(), + 862, + int, + "%d" + ); + BC_ASSERT_EQUAL( + mainDb.getHistory( + ChatRoomId(IdentityAddress("sip:test-1@sip.linphone.org"), IdentityAddress("sip:test-1@sip.linphone.org")), + 100, MainDb::Filter::ConferenceChatMessageFilter + ).size(), + 100, + int, + "%d" + ); +} + +static void get_conference_notified_events () { + MainDbProvider provider; + const MainDb &mainDb = provider.getMainDb(); + list> events = mainDb.getConferenceNotifiedEvents( + ChatRoomId(IdentityAddress("sip:fake-group-2@sip.linphone.org"), IdentityAddress("sip:fake-group-2@sip.linphone.org")), + 1 + ); + BC_ASSERT_EQUAL(events.size(), 3, int, "%d"); + if (events.size() != 3) + return; + + shared_ptr event; + auto it = events.cbegin(); + + event = *it; + if (!BC_ASSERT_TRUE(event->getType() == EventLog::Type::ConferenceParticipantRemoved)) return; + { + shared_ptr participantEvent = static_pointer_cast(event); + BC_ASSERT_TRUE(participantEvent->getChatRoomId().getPeerAddress().asString() == "sip:fake-group-2@sip.linphone.org"); + BC_ASSERT_TRUE(participantEvent->getParticipantAddress().asString() == "sip:test-11@sip.linphone.org"); + BC_ASSERT_TRUE(participantEvent->getNotifyId() == 2); + } + + event = *++it; + if (!BC_ASSERT_TRUE(event->getType() == EventLog::Type::ConferenceParticipantDeviceAdded)) return; + { + shared_ptr deviceEvent = static_pointer_cast< + ConferenceParticipantDeviceEvent + >(event); + BC_ASSERT_TRUE(deviceEvent->getChatRoomId().getPeerAddress().asString() == "sip:fake-group-2@sip.linphone.org"); + BC_ASSERT_TRUE(deviceEvent->getParticipantAddress().asString() == "sip:test-11@sip.linphone.org"); + BC_ASSERT_TRUE(deviceEvent->getNotifyId() == 3); + BC_ASSERT_TRUE(deviceEvent->getDeviceAddress().asString() == "sip:gruu-address-1@sip.linphone.org"); + } + + event = *++it; + if (!BC_ASSERT_TRUE(event->getType() == EventLog::Type::ConferenceParticipantDeviceRemoved)) return; + { + shared_ptr deviceEvent = static_pointer_cast< + ConferenceParticipantDeviceEvent + >(event); + BC_ASSERT_TRUE(deviceEvent->getChatRoomId().getPeerAddress().asString() == "sip:fake-group-2@sip.linphone.org"); + BC_ASSERT_TRUE(deviceEvent->getParticipantAddress().asString() == "sip:test-11@sip.linphone.org"); + BC_ASSERT_TRUE(deviceEvent->getNotifyId() == 4); + BC_ASSERT_TRUE(deviceEvent->getDeviceAddress().asString() == "sip:gruu-address-1@sip.linphone.org"); + } +} test_t main_db_tests[] = { - // TEST_NO_TAG("Open database", open_database), - // TEST_NO_TAG("Get events count", get_events_count), - // TEST_NO_TAG("Get messages count", get_messages_count), - // TEST_NO_TAG("Get unread messages count", get_unread_messages_count), - // TEST_NO_TAG("Get history", get_history), - // TEST_NO_TAG("Get conference events", get_conference_notified_events) + TEST_NO_TAG("Open database", open_database), + TEST_NO_TAG("Get events count", get_events_count), + TEST_NO_TAG("Get messages count", get_messages_count), + TEST_NO_TAG("Get unread messages count", get_unread_messages_count), + TEST_NO_TAG("Get history", get_history), + TEST_NO_TAG("Get conference events", get_conference_notified_events) }; test_suite_t main_db_test_suite = { From 8c7241bb133fbc257cfa550eda2781b8821a50f2 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 21 Nov 2017 14:43:12 +0100 Subject: [PATCH 0808/2215] fix(MainDb): references correctly chat room id from conference event --- src/db/main-db.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index f008e2d03..5a9a1826f 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -745,7 +745,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " PRIMARY KEY (chat_room_id, sip_address_id)," " FOREIGN KEY (chat_room_id)" - " REFERENCES chat_room(peer_sip_address_id)" + " REFERENCES chat_room(id)" " ON DELETE CASCADE," " FOREIGN KEY (sip_address_id)" " REFERENCES sip_address(id)" @@ -762,7 +762,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " REFERENCES event(id)" " ON DELETE CASCADE," " FOREIGN KEY (chat_room_id)" - " REFERENCES chat_room(peer_sip_address_id)" + " REFERENCES chat_room(id)" " ON DELETE CASCADE" ") " + charset; From 82f04ddb29e24062f951a849fdb19a26cce5fc4d Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 21 Nov 2017 15:39:08 +0100 Subject: [PATCH 0809/2215] feat(MainDb): enforce chat_room table, add unique and not null constraints on peer/local ids --- src/db/main-db.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 5a9a1826f..8da8c2517 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -710,9 +710,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " id" + primaryKeyStr("BIGINT UNSIGNED") + "," // Server (for conference) or user sip address. - " peer_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " peer_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," - " local_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " local_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," // Dialog creation date. " creation_date DATE NOT NULL," @@ -721,13 +721,15 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " last_update_date DATE NOT NULL," // ConferenceChatRoom, BasicChatRoom, RTT... - " capabilities TINYINT UNSIGNED," + " capabilities TINYINT UNSIGNED NOT NULL," // Chatroom subject. " subject VARCHAR(255)," " last_notify_id INT UNSIGNED," + " UNIQUE (peer_sip_address_id, local_sip_address_id)," + " FOREIGN KEY (peer_sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE," From e3ff46be758ef88fa4bfc3c3fcb19704f9bcb610 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 21 Nov 2017 15:43:43 +0100 Subject: [PATCH 0810/2215] feat(MainDb): enforce conference_event table, primary key is now (event_id, chat_room_id) --- src/db/main-db.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 8da8c2517..2e79fe642 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -746,6 +746,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " is_admin BOOLEAN NOT NULL," " PRIMARY KEY (chat_room_id, sip_address_id)," + " FOREIGN KEY (chat_room_id)" " REFERENCES chat_room(id)" " ON DELETE CASCADE," @@ -756,10 +757,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS conference_event (" - " event_id" + primaryKeyStr("BIGINT UNSIGNED") + "," - + " event_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," " chat_room_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " PRIMARY KEY (event_id, chat_room_id)," + " FOREIGN KEY (event_id)" " REFERENCES event(id)" " ON DELETE CASCADE," From 6611f820f3f48a11291e3d3802f8cdc29b0a7aa0 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 21 Nov 2017 16:41:21 +0100 Subject: [PATCH 0811/2215] feat(MainDb): add NOT NULL constraint on some fields --- src/db/main-db.cpp | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 2e79fe642..a0e908fdc 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -205,13 +205,13 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); soci::statement statement = ( session->prepare << "UPDATE chat_room_participant SET is_admin = :isAdmin" - " WHERE chat_room_id = :chatRoomId AND sip_address_id = :sipAddressId", + " WHERE chat_room_id = :chatRoomId AND participant_address_id = :sipAddressId", soci::use(static_cast(isAdmin)), soci::use(chatRoomId), soci::use(sipAddressId) ); statement.execute(true); if (statement.get_affected_rows() == 0) { lInfo() << "Insert new chat room participant in database: `" << sipAddressId << "` (isAdmin=" << isAdmin << ")."; - *session << "INSERT INTO chat_room_participant (chat_room_id, sip_address_id, is_admin)" + *session << "INSERT INTO chat_room_participant (chat_room_id, participant_address_id, is_admin)" " VALUES (:chatRoomId, :sipAddressId, :isAdmin)", soci::use(chatRoomId), soci::use(sipAddressId), soci::use(static_cast(isAdmin)); } @@ -221,12 +221,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); soci::statement statement = ( session->prepare << "UPDATE chat_message_participant SET state = :state" - " WHERE event_id = :eventId AND sip_address_id = :sipAddressId", + " WHERE event_id = :eventId AND participant_address_id = :sipAddressId", soci::use(state), soci::use(eventId), soci::use(sipAddressId) ); statement.execute(true); if (statement.get_affected_rows() == 0 && state != static_cast(ChatMessage::State::Displayed)) - *session << "INSERT INTO chat_message_participant (event_id, sip_address_id, state)" + *session << "INSERT INTO chat_message_participant (event_id, participant_address_id, state)" " VALUES (:eventId, :sipAddressId, :state)", soci::use(eventId), soci::use(sipAddressId), soci::use(state); } @@ -741,26 +741,25 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS chat_room_participant (" " chat_room_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," - " sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " participant_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," " is_admin BOOLEAN NOT NULL," - " PRIMARY KEY (chat_room_id, sip_address_id)," + " PRIMARY KEY (chat_room_id, participant_address_id)," " FOREIGN KEY (chat_room_id)" " REFERENCES chat_room(id)" " ON DELETE CASCADE," - " FOREIGN KEY (sip_address_id)" + " FOREIGN KEY (participant_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" ") " + charset; *session << "CREATE TABLE IF NOT EXISTS conference_event (" - " event_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," - " chat_room_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " event_id" + primaryKeyStr("BIGINT UNSIGNED") + "," - " PRIMARY KEY (event_id, chat_room_id)," + " chat_room_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," " FOREIGN KEY (event_id)" " REFERENCES event(id)" @@ -785,7 +784,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), "CREATE TABLE IF NOT EXISTS conference_participant_event (" " event_id" + primaryKeyStr("BIGINT UNSIGNED") + "," - " participant_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " participant_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," " FOREIGN KEY (event_id)" " REFERENCES conference_notified_event(event_id)" @@ -799,7 +798,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), "CREATE TABLE IF NOT EXISTS conference_participant_device_event (" " event_id" + primaryKeyStr("BIGINT UNSIGNED") + "," - " device_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " device_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," " FOREIGN KEY (event_id)" " REFERENCES conference_participant_event(event_id)" @@ -824,8 +823,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), "CREATE TABLE IF NOT EXISTS conference_chat_message_event (" " event_id" + primaryKeyStr("BIGINT UNSIGNED") + "," - " from_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," - " to_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " from_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," + " to_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," // See: https://tools.ietf.org/html/rfc5438#section-6.3 " imdn_message_id VARCHAR(255) NOT NULL," @@ -847,15 +846,14 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS chat_message_participant (" - " event_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," - " sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " event_id" + primaryKeyStr("BIGINT UNSIGNED") + "," + " participant_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," " state TINYINT UNSIGNED NOT NULL," - " PRIMARY KEY (event_id, sip_address_id)," " FOREIGN KEY (event_id)" " REFERENCES conference_chat_message_event(event_id)" " ON DELETE CASCADE," - " FOREIGN KEY (sip_address_id)" + " FOREIGN KEY (participant_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" ") " + charset; @@ -864,8 +862,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), "CREATE TABLE IF NOT EXISTS chat_message_content (" " id" + primaryKeyStr("BIGINT UNSIGNED") + "," - " event_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," - " content_type_id" + primaryKeyRefStr("SMALLINT UNSIGNED") + "," + " event_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," + " content_type_id" + primaryKeyRefStr("SMALLINT UNSIGNED") + " NOT NULL," " body TEXT NOT NULL," " FOREIGN KEY (event_id)" @@ -894,7 +892,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " chat_message_content_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," " name VARCHAR(255)," - " data BLOB," + " data BLOB NOT NULL," " PRIMARY KEY (chat_message_content_id, name)," " FOREIGN KEY (chat_message_content_id)" @@ -907,7 +905,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " event_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," " name VARCHAR(255)," - " data BLOB," + " data BLOB NOT NULL," " PRIMARY KEY (event_id, name)," " FOREIGN KEY (event_id)" From eb0fa39f97c2aff17b0fbcb3505f01acb4f1a454 Mon Sep 17 00:00:00 2001 From: Danmei Chen Date: Wed, 8 Nov 2017 13:03:22 +0100 Subject: [PATCH 0812/2215] Add test for MD5 and SHA-256 in register_test. Tests SHA-256 are supported with flexisip --- coreapi/authentication.c | 29 ++++++++++++++++++++-- coreapi/bellesip_sal/sal_impl.c | 6 +++++ coreapi/callbacks.c | 10 ++++++++ coreapi/private.h | 1 + include/linphone/auth_info.h | 6 +++-- src/c-wrapper/internal/c-sal.cpp | 2 ++ src/c-wrapper/internal/c-sal.h | 4 ++++ tester/register_tester.c | 41 ++++++++++++++++++++++++++++---- 8 files changed, 91 insertions(+), 8 deletions(-) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 4d8603f63..971294280 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -53,6 +53,19 @@ LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *useri return obj; } +LinphoneAuthInfo *linphone_auth_info_new_for_algorithm(const char *username, const char *userid, const char *passwd, const char *ha1, const char *realm, const char *domain, const char *algorithm){ + LinphoneAuthInfo *obj=linphone_auth_info_new(username,userid,passwd,ha1,realm,domain); + /* Default algorithm is MD5 if it's NULL*/ + if(algorithm && strcmp(algorithm, "MD5") && strcmp(algorithm, "SHA-256")){ + ms_error("Given algorithm %s is not correct.", algorithm); + return NULL; + } + if(algorithm){ + obj->algorithm=ms_strdup(algorithm); + } + return obj; +} + static void _linphone_auth_info_copy(LinphoneAuthInfo *dst, const LinphoneAuthInfo *src) { if (src->username) dst->username = ms_strdup(src->username); if (src->userid) dst->userid = ms_strdup(src->userid); @@ -64,6 +77,7 @@ static void _linphone_auth_info_copy(LinphoneAuthInfo *dst, const LinphoneAuthIn if (src->tls_key) dst->tls_key = ms_strdup(src->tls_key); if (src->tls_cert_path) dst->tls_cert_path = ms_strdup(src->tls_cert_path); if (src->tls_key_path) dst->tls_key_path = ms_strdup(src->tls_key_path); + if (src->algorithm) dst->algorithm = ms_strdup(src->algorithm); } LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo *ai){ @@ -217,6 +231,7 @@ static void _linphone_auth_info_uninit(LinphoneAuthInfo *obj) { if (obj->tls_key != NULL) ms_free(obj->tls_key); if (obj->tls_cert_path != NULL) ms_free(obj->tls_cert_path); if (obj->tls_key_path != NULL) ms_free(obj->tls_key_path); + if (obj->algorithm != NULL) ms_free(obj->algorithm); } /** @@ -238,8 +253,14 @@ void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, in } if (!obj->ha1 && obj->realm && obj->passwd && (obj->username || obj->userid) && store_ha1_passwd) { /*compute ha1 to avoid storing clear text password*/ - obj->ha1 = reinterpret_cast(ms_malloc(33)); - sal_auth_compute_ha1(obj->userid ? obj->userid : obj->username, obj->realm, obj->passwd, obj->ha1); + if((obj->algorithm==NULL)||(!(strcmp(obj->algorithm, "MD5")))){ + obj->ha1 = reinterpret_cast(ms_malloc(33)); + sal_auth_compute_ha1(obj->userid ? obj->userid : obj->username, obj->realm, obj->passwd, obj->ha1); + } + if((obj->algorithm)&&(!(strcmp(obj->algorithm, "SHA-256")))){ + obj->ha1 = reinterpret_cast(ms_malloc(65)); + sal_auth_compute_ha1_for_algorithm(obj->userid ? obj->userid : obj->username, obj->realm, obj->passwd, obj->ha1,65, obj->algorithm); + } } if (obj->username != NULL) { lp_config_set_string(config, key, "username", obj->username); @@ -271,6 +292,9 @@ void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, in if (obj->tls_key_path != NULL) { lp_config_set_string(config, key, "client_cert_key", obj->tls_key_path); } + if (obj->algorithm != NULL) { + lp_config_set_string(config, key, "algorithm", obj->algorithm); + } } LinphoneAuthInfo *linphone_auth_info_new_from_config_file(LpConfig * config, int pos) @@ -455,6 +479,7 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) sai.realm=ai->realm; sai.password=ai->passwd; sai.ha1=ai->ha1; + sai.algorithm=ai->algorithm; if (ai->tls_cert && ai->tls_key) { sal_certificates_chain_parse(&sai, ai->tls_cert, SAL_CERTIFICATE_RAW_FORMAT_PEM); sal_signing_key_parse(&sai, ai->tls_key, ""); diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 7803b92a5..41c562183 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -65,6 +65,7 @@ SalAuthInfo* sal_auth_info_create(belle_sip_auth_event_t* event) { auth_info->username = ms_strdup(belle_sip_auth_event_get_username(event)); auth_info->domain = ms_strdup(belle_sip_auth_event_get_domain(event)); auth_info->mode = (SalAuthMode)belle_sip_auth_event_get_mode(event); + auth_info->algorithm = ms_strdup(belle_sip_auth_event_get_algorithm(event)); return auth_info; } @@ -83,6 +84,11 @@ int sal_auth_compute_ha1(const char* userid,const char* realm,const char* passwo return belle_sip_auth_helper_compute_ha1(userid, realm, password, ha1); } +int sal_auth_compute_ha1_for_algorithm(const char* userid,const char* realm,const char* password, char* ha1, + size_t size, const char* algo) { + return belle_sip_auth_helper_compute_ha1_for_algorithm(userid, realm, password, ha1, size, algo); +} + SalCustomHeader *sal_custom_header_ref(SalCustomHeader *ch){ if (ch == NULL) return NULL; belle_sip_object_ref(ch); diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 2c1d6a8c9..b6f95d591 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -526,6 +526,16 @@ static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) { } if (ai) { if (sai->mode == SalAuthModeHttpDigest) { + /* Compare algorithm of server(sai) with algorithm of client(ai), if they are not correspondant, + exit. The default algorithm is MD5 if it's NULL. */ + if(sai->algorithm && ai->algorithm) { + if(strcmp(ai->algorithm, sai->algorithm)) + return TRUE; + } + else if((ai->algorithm && strcmp(ai->algorithm, "MD5")) || + (sai->algorithm && strcmp(sai->algorithm, "MD5"))) + return TRUE; + sai->userid = ms_strdup(ai->userid ? ai->userid : ai->username); sai->password = ai->passwd?ms_strdup(ai->passwd) : NULL; sai->ha1 = ai->ha1 ? ms_strdup(ai->ha1) : NULL; diff --git a/coreapi/private.h b/coreapi/private.h index 5b22e4fac..528b9c35a 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -562,6 +562,7 @@ struct _LinphoneAuthInfo char *tls_key; char *tls_cert_path; char *tls_key_path; + char *algorithm; }; typedef enum _LinphoneIsComposingState { diff --git a/include/linphone/auth_info.h b/include/linphone/auth_info.h index c14433056..0eec7924f 100644 --- a/include/linphone/auth_info.h +++ b/include/linphone/auth_info.h @@ -52,8 +52,10 @@ extern "C" { * passed through linphone_core_add_auth_info(). **/ LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid, - const char *passwd, const char *ha1,const char *realm, const char *domain); - + const char *passwd, const char *ha1,const char *realm, const char *domain); + +LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_new_for_algorithm(const char *username, const char *userid, + const char *passwd, const char *ha1,const char *realm, const char *domain, const char *algorithm); /** * Instantiates a new auth info with values from source. * @param[in] source The #LinphoneAuthInfo object to be cloned diff --git a/src/c-wrapper/internal/c-sal.cpp b/src/c-wrapper/internal/c-sal.cpp index 32a1633bb..69f6842fb 100644 --- a/src/c-wrapper/internal/c-sal.cpp +++ b/src/c-wrapper/internal/c-sal.cpp @@ -762,6 +762,7 @@ SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info) { new_auth_info->realm=auth_info->realm?ms_strdup(auth_info->realm):NULL; new_auth_info->domain=auth_info->realm?ms_strdup(auth_info->domain):NULL; new_auth_info->password=auth_info->password?ms_strdup(auth_info->password):NULL; + new_auth_info->algorithm=auth_info->algorithm?ms_strdup(auth_info->algorithm):NULL; return new_auth_info; } @@ -774,6 +775,7 @@ void sal_auth_info_delete(SalAuthInfo* auth_info) { if (auth_info->ha1) ms_free(auth_info->ha1); if (auth_info->certificates) sal_certificates_chain_delete(auth_info->certificates); if (auth_info->key) sal_signing_key_delete(auth_info->key); + if (auth_info->algorithm) ms_free(auth_info->algorithm); ms_free(auth_info); } diff --git a/src/c-wrapper/internal/c-sal.h b/src/c-wrapper/internal/c-sal.h index 6b869f02b..10d58ad11 100644 --- a/src/c-wrapper/internal/c-sal.h +++ b/src/c-wrapper/internal/c-sal.h @@ -474,6 +474,7 @@ typedef struct SalAuthInfo{ char *realm; char *domain; char *ha1; + char *algorithm; SalAuthMode mode; belle_sip_signing_key_t *key; belle_sip_certificates_chain_t *certificates; @@ -488,6 +489,9 @@ SalAuthInfo* sal_auth_info_new(void); SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info); void sal_auth_info_delete(SalAuthInfo* auth_info); LINPHONE_PUBLIC int sal_auth_compute_ha1(const char* userid,const char* realm,const char* password, char ha1[33]); +LINPHONE_PUBLIC int sal_auth_compute_ha1_for_algorithm(const char* userid,const char* realm,const char* password, char *ha1,size_t size,const char* algo); +/*LINPHONE_PUBLIC int sal_auth_compute_ha1_for_algorithm(const char* userid,const char* realm,const char* password, char *ha1, + size_t size, const char* algo);*/ SalAuthMode sal_auth_info_get_mode(const SalAuthInfo* auth_info); belle_sip_signing_key_t *sal_auth_info_get_signing_key(const SalAuthInfo* auth_info); belle_sip_certificates_chain_t *sal_auth_info_get_certificates_chain(const SalAuthInfo* auth_info); diff --git a/tester/register_tester.c b/tester/register_tester.c index a40817f89..05806abfc 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -113,7 +113,7 @@ static void register_with_refresh_base_3(LinphoneCore* lc if (counters->number_of_auth_info_requested>0 && linphone_proxy_config_get_state(proxy_cfg) == LinphoneRegistrationFailed && late_auth_info) { if (!linphone_core_get_auth_info_list(lc)) { BC_ASSERT_EQUAL(linphone_proxy_config_get_error(proxy_cfg),LinphoneReasonUnauthorized, int, "%d"); - info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ + info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ linphone_auth_info_unref(info); } @@ -165,7 +165,7 @@ static void register_with_refresh_with_send_error(void) { int retry=0; LinphoneCoreManager* lcm = create_lcm_with_auth(1); stats* counters = &lcm->stat; - LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ char route[256]; sprintf(route,"sip:%s",test_route); linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ @@ -310,7 +310,7 @@ static void simple_tls_register(void){ static void simple_authenticated_register(void){ stats* counters; LinphoneCoreManager* lcm = create_lcm(); - LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ + LinphoneAuthInfo *info=linphone_auth_info_new_for_algorithm(test_username,NULL,test_password,NULL,auth_domain,NULL,NULL); /*create authentication structure from identity*/ char route[256]; sprintf(route,"sip:%s",test_route); linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ @@ -321,6 +321,20 @@ static void simple_authenticated_register(void){ linphone_core_manager_destroy(lcm); } +static void simple_authenticated_register_for_algorithm(void){ + stats* counters; + LinphoneCoreManager* lcm = create_lcm(); + LinphoneAuthInfo *info=linphone_auth_info_new_for_algorithm(test_username,NULL,test_password,NULL,auth_domain,NULL,"SHA-256"); /*create authentication structure from identity*/ + char route[256]; + sprintf(route,"sip:%s",test_route); + linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ + linphone_auth_info_unref(info); + counters = &lcm->stat; + register_with_refresh(lcm,FALSE,auth_domain,route); + BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,0, int, "%d"); + linphone_core_manager_destroy(lcm); +} + static void ha1_authenticated_register(void){ stats* counters; LinphoneCoreManager* lcm = create_lcm(); @@ -328,7 +342,7 @@ static void ha1_authenticated_register(void){ LinphoneAuthInfo *info; char route[256]; sal_auth_compute_ha1(test_username,auth_domain,test_password,ha1); - info=linphone_auth_info_new(test_username,NULL,NULL,ha1,auth_domain,NULL); /*create authentication structure from identity*/ + info=linphone_auth_info_new_for_algorithm(test_username,NULL,NULL,ha1,auth_domain,NULL,NULL); /*create authentication structure from identity*/ sprintf(route,"sip:%s",test_route); linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ linphone_auth_info_unref(info); @@ -338,6 +352,23 @@ static void ha1_authenticated_register(void){ linphone_core_manager_destroy(lcm); } +static void ha1_authenticated_register_for_algorithm(void){ + stats* counters; + LinphoneCoreManager* lcm = create_lcm(); + char ha1[65]; + LinphoneAuthInfo *info; + char route[256]; + sal_auth_compute_ha1_for_algorithm(test_username,auth_domain,test_password,ha1,65,"SHA-256"); + info=linphone_auth_info_new_for_algorithm(test_username,NULL,NULL,ha1,auth_domain,NULL,"SHA-256"); /*create authentication structure from identity*/ + sprintf(route,"sip:%s",test_route); + linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ + linphone_auth_info_unref(info); + counters = &lcm->stat; + register_with_refresh(lcm,FALSE,auth_domain,route); + BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,0, int, "%d"); + linphone_core_manager_destroy(lcm); +} + static void authenticated_register_with_no_initial_credentials(void){ LinphoneCoreManager *lcm; LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get()); @@ -1243,7 +1274,9 @@ test_t register_tests[] = { TEST_NO_TAG("TLS certificate given by string instead of file",tls_certificate_data), TEST_NO_TAG("TLS with non tls server",tls_with_non_tls_server), TEST_NO_TAG("Simple authenticated register", simple_authenticated_register), + TEST_NO_TAG("Simple authenticated register SHA-256", simple_authenticated_register_for_algorithm), TEST_NO_TAG("Ha1 authenticated register", ha1_authenticated_register), + TEST_NO_TAG("Ha1 authenticated register SHA-256", ha1_authenticated_register_for_algorithm), TEST_NO_TAG("Digest auth without initial credentials", authenticated_register_with_no_initial_credentials), TEST_NO_TAG("Digest auth with wrong credentials", authenticated_register_with_wrong_credentials), TEST_NO_TAG("Digest auth with wrong credentials, check if registration attempts are stopped", authenticated_register_with_wrong_credentials_2), From 2e98261441d64db7bc224ca3b083dfa3850c485d Mon Sep 17 00:00:00 2001 From: Danmei Chen Date: Wed, 8 Nov 2017 14:27:58 +0100 Subject: [PATCH 0813/2215] add comment and change linphone_auth_info_new for auth_info for auth_info including algorithm --- coreapi/authentication.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 971294280..0f4d44907 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -43,23 +43,26 @@ BELLE_SIP_INSTANCIATE_VPTR( ); LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid, const char *passwd, const char *ha1, const char *realm, const char *domain){ - LinphoneAuthInfo *obj=belle_sip_object_new(LinphoneAuthInfo); - if (username!=NULL && (strlen(username)>0) ) obj->username=ms_strdup(username); - if (userid!=NULL && (strlen(userid)>0)) obj->userid=ms_strdup(userid); - if (passwd!=NULL && (strlen(passwd)>0)) obj->passwd=ms_strdup(passwd); - if (ha1!=NULL && (strlen(ha1)>0)) obj->ha1=ms_strdup(ha1); - if (realm!=NULL && (strlen(realm)>0)) obj->realm=ms_strdup(realm); - if (domain!=NULL && (strlen(domain)>0)) obj->domain=ms_strdup(domain); - return obj; + return linphone_auth_info_new_for_algorithm(username, userid, passwd, ha1, realm, domain, NULL); } LinphoneAuthInfo *linphone_auth_info_new_for_algorithm(const char *username, const char *userid, const char *passwd, const char *ha1, const char *realm, const char *domain, const char *algorithm){ - LinphoneAuthInfo *obj=linphone_auth_info_new(username,userid,passwd,ha1,realm,domain); + LinphoneAuthInfo *obj=belle_sip_object_new(LinphoneAuthInfo); + if (username!=NULL && (strlen(username)>0) ) obj->username=ms_strdup(username); + if (userid!=NULL && (strlen(userid)>0)) obj->userid=ms_strdup(userid); + if (passwd!=NULL && (strlen(passwd)>0)) obj->passwd=ms_strdup(passwd); + if (ha1!=NULL && (strlen(ha1)>0)) obj->ha1=ms_strdup(ha1); + if (realm!=NULL && (strlen(realm)>0)) obj->realm=ms_strdup(realm); + if (domain!=NULL && (strlen(domain)>0)) obj->domain=ms_strdup(domain); /* Default algorithm is MD5 if it's NULL*/ + if(algorithm==NULL) + obj->algorithm = ms_strdup("MD5"); + /* If algorithm is neither MD5 or SHA-256, exit wit error*/ if(algorithm && strcmp(algorithm, "MD5") && strcmp(algorithm, "SHA-256")){ ms_error("Given algorithm %s is not correct.", algorithm); return NULL; } + /*Else, set algorithm for obj */ if(algorithm){ obj->algorithm=ms_strdup(algorithm); } @@ -253,10 +256,12 @@ void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, in } if (!obj->ha1 && obj->realm && obj->passwd && (obj->username || obj->userid) && store_ha1_passwd) { /*compute ha1 to avoid storing clear text password*/ + /* Default algorithm is MD5 if it's NULL */ if((obj->algorithm==NULL)||(!(strcmp(obj->algorithm, "MD5")))){ obj->ha1 = reinterpret_cast(ms_malloc(33)); sal_auth_compute_ha1(obj->userid ? obj->userid : obj->username, obj->realm, obj->passwd, obj->ha1); } + /* If algorithm is SHA-256, calcul ha1 by sha256*/ if((obj->algorithm)&&(!(strcmp(obj->algorithm, "SHA-256")))){ obj->ha1 = reinterpret_cast(ms_malloc(65)); sal_auth_compute_ha1_for_algorithm(obj->userid ? obj->userid : obj->username, obj->realm, obj->passwd, obj->ha1,65, obj->algorithm); From 5bf7df6627be1efa55a65c015634669acd70a0fb Mon Sep 17 00:00:00 2001 From: Danmei Chen Date: Mon, 20 Nov 2017 11:33:57 +0100 Subject: [PATCH 0814/2215] change tests for SHA-256 to use different account --- tester/` | 4 +++ tester/liblinphone_tester.h | 2 ++ tester/register_tester.c | 58 +++++++++++++++++++++++++------------ tester/tester.c | 30 ++++++++++++------- 4 files changed, 64 insertions(+), 30 deletions(-) create mode 100644 tester/` diff --git a/tester/` b/tester/` new file mode 100644 index 000000000..4a0ed127e --- /dev/null +++ b/tester/` @@ -0,0 +1,4 @@ +127.0.0.1 sip2.linphone.org sip.example.org sipopen.example.org auth.example.org auth1.example.org auth2.example.org altname.linphone.org sip.wildcard1.linphone.org altname.wildcard2.linphone.org sipv4.example.org +2a01:cb15:82a0:5900:1422:ce1a:a8fe:6ccc sip2.linphone.org sip.example.org sipopen.example.org auth.example.org auth1.example.org auth2.example.org altname.linphone.org sip.wildcard1.linphone.org altname.wildcard2.linphone.org +188.165.46.90 tunnel.wildcard2.linphone.org +64:ff9b::94.23.19.176 sipv4-nat64.example.org diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 4c9ed780c..dc29319fa 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -119,6 +119,7 @@ extern void liblinphone_tester_clear_accounts(void); extern const char* test_domain; extern const char* auth_domain; extern const char* test_username; +extern const char* test_sha_username; extern const char* test_password; extern const char* test_route; extern const char* userhostsfile; @@ -339,6 +340,7 @@ void dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf); void call_stats_updated(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats); LinphoneAddress * create_linphone_address(const char * domain); +LinphoneAddress * create_linphone_address_for_algo(const char * domain, const char * username); bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value); bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms); bool_t wait_for_until(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value,int timout_ms); diff --git a/tester/register_tester.c b/tester/register_tester.c index 05806abfc..bffbdbeb7 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -64,13 +64,14 @@ void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *c } } -static void register_with_refresh_base_3(LinphoneCore* lc +static void register_with_refresh_base_3_for_algo(LinphoneCore* lc , bool_t refresh ,const char* domain ,const char* route ,bool_t late_auth_info ,LinphoneTransports *transport - ,LinphoneRegistrationState expected_final_state) { + ,LinphoneRegistrationState expected_final_state + ,const char* username) { int retry=0; char* addr; LinphoneProxyConfig* proxy_cfg; @@ -88,7 +89,7 @@ static void register_with_refresh_base_3(LinphoneCore* lc proxy_cfg = linphone_proxy_config_new(); - from = create_linphone_address(domain); + from = create_linphone_address_for_algo(domain, username); linphone_proxy_config_set_identity(proxy_cfg,addr=linphone_address_as_string(from)); ms_free(addr); @@ -136,6 +137,16 @@ static void register_with_refresh_base_3(LinphoneCore* lc linphone_proxy_config_unref(proxy_cfg); } +static void register_with_refresh_base_3(LinphoneCore* lc + , bool_t refresh + ,const char* domain + ,const char* route + ,bool_t late_auth_info + ,LinphoneTransports *transport + ,LinphoneRegistrationState expected_final_state) { + register_with_refresh_base_3_for_algo(lc, refresh, domain, route, late_auth_info, transport, expected_final_state, NULL); +} + static void register_with_refresh_base_2(LinphoneCore* lc , bool_t refresh ,const char* domain @@ -144,21 +155,30 @@ static void register_with_refresh_base_2(LinphoneCore* lc ,LinphoneTransports *transport) { register_with_refresh_base_3(lc, refresh, domain, route, late_auth_info, transport,LinphoneRegistrationOk ); } + +static void register_with_refresh_base_for_algo(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route, const char* username) { + LinphoneTransports *transport = linphone_factory_create_transports(linphone_factory_get()); + linphone_transports_set_udp_port(transport, 5070); + linphone_transports_set_tcp_port(transport, 5070); + linphone_transports_set_tls_port(transport, 5071); + linphone_transports_set_dtls_port(transport, 0); + register_with_refresh_base_3_for_algo(lc,refresh,domain,route,FALSE,transport,LinphoneRegistrationOk,username); + linphone_transports_unref(transport); +} + static void register_with_refresh_base(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { - LinphoneTransports *transport = linphone_factory_create_transports(linphone_factory_get()); - linphone_transports_set_udp_port(transport, 5070); - linphone_transports_set_tcp_port(transport, 5070); - linphone_transports_set_tls_port(transport, 5071); - linphone_transports_set_dtls_port(transport, 0); - register_with_refresh_base_2(lc,refresh,domain,route,FALSE,transport); - linphone_transports_unref(transport); + register_with_refresh_base_for_algo(lc, refresh, domain, route, NULL); +} + +static void register_with_refresh_for_algo(LinphoneCoreManager* lcm, bool_t refresh,const char* domain,const char* route,const char* username) { + stats* counters = &lcm->stat; + register_with_refresh_base_for_algo(lcm->lc,refresh,domain,route,username); + linphone_core_manager_stop(lcm); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,1, int, "%d"); } static void register_with_refresh(LinphoneCoreManager* lcm, bool_t refresh,const char* domain,const char* route) { - stats* counters = &lcm->stat; - register_with_refresh_base(lcm->lc,refresh,domain,route); - linphone_core_manager_stop(lcm); - BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,1, int, "%d"); + register_with_refresh_for_algo(lcm, refresh, domain, route, NULL); } static void register_with_refresh_with_send_error(void) { @@ -324,13 +344,13 @@ static void simple_authenticated_register(void){ static void simple_authenticated_register_for_algorithm(void){ stats* counters; LinphoneCoreManager* lcm = create_lcm(); - LinphoneAuthInfo *info=linphone_auth_info_new_for_algorithm(test_username,NULL,test_password,NULL,auth_domain,NULL,"SHA-256"); /*create authentication structure from identity*/ + LinphoneAuthInfo *info=linphone_auth_info_new_for_algorithm(test_sha_username,NULL,test_password,NULL,auth_domain,NULL,"SHA-256"); /*create authentication structure from identity*/ char route[256]; sprintf(route,"sip:%s",test_route); linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ linphone_auth_info_unref(info); counters = &lcm->stat; - register_with_refresh(lcm,FALSE,auth_domain,route); + register_with_refresh_for_algo(lcm,FALSE,auth_domain,route,test_sha_username); BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,0, int, "%d"); linphone_core_manager_destroy(lcm); } @@ -358,13 +378,13 @@ static void ha1_authenticated_register_for_algorithm(void){ char ha1[65]; LinphoneAuthInfo *info; char route[256]; - sal_auth_compute_ha1_for_algorithm(test_username,auth_domain,test_password,ha1,65,"SHA-256"); - info=linphone_auth_info_new_for_algorithm(test_username,NULL,NULL,ha1,auth_domain,NULL,"SHA-256"); /*create authentication structure from identity*/ + sal_auth_compute_ha1_for_algorithm(test_sha_username,auth_domain,test_password,ha1,65,"SHA-256"); + info=linphone_auth_info_new_for_algorithm(test_sha_username,NULL,NULL,ha1,auth_domain,NULL,"SHA-256"); /*create authentication structure from identity*/ sprintf(route,"sip:%s",test_route); linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ linphone_auth_info_unref(info); counters = &lcm->stat; - register_with_refresh(lcm,FALSE,auth_domain,route); + register_with_refresh_for_algo(lcm,FALSE,auth_domain,route,test_sha_username); BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,0, int, "%d"); linphone_core_manager_destroy(lcm); } diff --git a/tester/tester.c b/tester/tester.c index 22138b0ee..31242e9d0 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -55,6 +55,7 @@ const MSAudioDiffParams audio_cmp_params = {10,2000}; const char* test_domain="sipopen.example.org"; const char* auth_domain="sip.example.org"; const char* test_username="liblinphone_tester"; +const char* test_sha_username="liblinphone_sha_tester"; const char* test_password="secret"; const char* test_route="sip2.linphone.org"; const char *userhostsfile = "tester_hosts"; @@ -89,17 +90,24 @@ bool_t liblinphone_tester_clock_elapsed(const MSTimeSpec *start, int value_ms){ LinphoneAddress * create_linphone_address(const char * domain) { - LinphoneAddress *addr = linphone_address_new(NULL); - if (!BC_ASSERT_PTR_NOT_NULL(addr)) return NULL; - linphone_address_set_username(addr,test_username); - BC_ASSERT_STRING_EQUAL(test_username,linphone_address_get_username(addr)); - if (!domain) domain= test_route; - linphone_address_set_domain(addr,domain); - BC_ASSERT_STRING_EQUAL(domain,linphone_address_get_domain(addr)); - linphone_address_set_display_name(addr, NULL); - linphone_address_set_display_name(addr, "Mr Tester"); - BC_ASSERT_STRING_EQUAL("Mr Tester",linphone_address_get_display_name(addr)); - return addr; + return create_linphone_address_for_algo(domain,NULL); +} + +LinphoneAddress * create_linphone_address_for_algo(const char * domain, const char* username) { + LinphoneAddress *addr = linphone_address_new(NULL); + if (!BC_ASSERT_PTR_NOT_NULL(addr)) return NULL; + /* For clients who support different algorithms, their usernames must be differnet for having diffrent forms of password */ + if(username) linphone_address_set_username(addr,username); + else linphone_address_set_username(addr,test_username); + if(username) BC_ASSERT_STRING_EQUAL(username,linphone_address_get_username(addr)); + else BC_ASSERT_STRING_EQUAL(test_username,linphone_address_get_username(addr)); + if (!domain) domain= test_route; + linphone_address_set_domain(addr,domain); + BC_ASSERT_STRING_EQUAL(domain,linphone_address_get_domain(addr)); + linphone_address_set_display_name(addr, NULL); + linphone_address_set_display_name(addr, "Mr Tester"); + BC_ASSERT_STRING_EQUAL("Mr Tester",linphone_address_get_display_name(addr)); + return addr; } static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { From 6aa85b154196d4e1c5dbbfc3198ddcc6b20e7a0d Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 22 Nov 2017 10:38:43 +0100 Subject: [PATCH 0815/2215] simplify for loop --- src/c-wrapper/api/c-chat-room.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 9ea256016..f2a0da4b5 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -301,8 +301,8 @@ void linphone_chat_room_set_subject (LinphoneChatRoom *cr, const char *subject) bctbx_list_t * linphone_chat_room_get_composing_addresses(LinphoneChatRoom *cr) { LinphonePrivate::ChatRoomPrivate *room = L_GET_PRIVATE_FROM_C_OBJECT(cr); bctbx_list_t *result = NULL; - for (auto i = room->remoteIsComposing.begin(); i != room->remoteIsComposing.end(); ++i) { - result = bctbx_list_append(result, linphone_address_new((*i).c_str())); + for (const auto &uri : room->remoteIsComposing) { + result = bctbx_list_append(result, linphone_address_new(uri.c_str())); } return result; } From 60ad6765047ee651ca74e236064158cb63f0178e Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 22 Nov 2017 10:42:38 +0100 Subject: [PATCH 0816/2215] fix(address): avoid logs... --- src/address/address.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/address/address.cpp b/src/address/address.cpp index 7c562f198..9dd1e915f 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -48,16 +48,22 @@ Address::Address (const Address &src) : ClonableObject(*new AddressPrivate) { Address::Address (const IdentityAddress &src) : ClonableObject(*new AddressPrivate) { L_D(); - string uri = src.getScheme() + ":" + src.getUsername() + "@"; - if (src.getDomain().find(':') != string::npos) - uri += "[" + src.getDomain() + "]"; - else - uri += src.getDomain(); + + const string &username = src.getUsername(); + if (username.empty()) + return; + const string &domain = src.getDomain(); + if (domain.empty()) + return; + + string uri = src.getScheme() + ":" + username + "@" + ( + domain.find(':') != string::npos ? "[" + domain + "]" : domain + ); + if (src.hasGruu()) uri += "?gr=" + src.getGruu(); - if (!(d->internalAddress = sal_address_new(L_STRING_TO_C(uri)))) { - lWarning() << "Cannot create Address, bad IdentityAddress source"; - } + + d->internalAddress = sal_address_new(L_STRING_TO_C(uri)); } Address::~Address () { From fec4923ad009436620fa0967b91123f9f32d2762 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 22 Nov 2017 11:02:48 +0100 Subject: [PATCH 0817/2215] Reworked IDMN --- src/chat/chat-message/chat-message.cpp | 13 +++++-- src/chat/chat-room/chat-room-p.h | 1 - src/chat/chat-room/chat-room.cpp | 48 -------------------------- 3 files changed, 10 insertions(+), 52 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 8b758762c..a26c1ca90 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -411,9 +411,16 @@ string ChatMessagePrivate::createImdnXml (Imdn::Type imdnType, LinphoneReason re } void ChatMessagePrivate::sendImdn (Imdn::Type imdnType, LinphoneReason reason) { - // FIXME: Add impl. - // L_Q(); - // q->getChatRoom()->getPrivate()->sendImdn(createImdnXml(imdnType, reason), reason); + L_Q(); + + shared_ptr msg = q->getChatRoom()->createMessage(); + + Content *content = new Content(); + content->setContentType("message/imdn+xml"); + content->setBody(createImdnXml(imdnType, reason)); + msg->addContent(*content); + + msg->send(); } LinphoneReason ChatMessagePrivate::receive () { diff --git a/src/chat/chat-room/chat-room-p.h b/src/chat/chat-room/chat-room-p.h index be04ac5be..650b7d3b6 100644 --- a/src/chat/chat-room/chat-room-p.h +++ b/src/chat/chat-room/chat-room-p.h @@ -47,7 +47,6 @@ public: void removeTransientMessage (const std::shared_ptr &msg); void release (); - void sendImdn (const std::string &content, LinphoneReason reason); void setState (ChatRoom::State newState); diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index cc9b2e5b7..27e11113b 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -83,54 +83,6 @@ void ChatRoomPrivate::release () { message->cancelFileTransfer(); } -void ChatRoomPrivate::sendImdn (const string &payload, LinphoneReason reason) { - // L_Q(); - // - // shared_ptr core = q->getCore(); - // LinphoneCore *cCore = core->getCCore(); - // - // // TODO: Use ChatRoomId. - // const char *identity = nullptr; - // LinphoneAddress *peer = linphone_address_new(q->getPeerAddress().asString().c_str()); - // LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(cCore, peer); - // if (proxy) - // identity = linphone_address_as_string(linphone_proxy_config_get_identity_address(proxy)); - // else - // identity = linphone_core_get_primary_contact(cCore); - // - // /* Sending out of call */ - // SalMessageOp *op = new SalMessageOp(cCore->sal); - // linphone_configure_op(cCore, op, peer, nullptr, !!lp_config_get_int(cCore->config, "sip", "chat_msg_with_contact", 0)); - // - // // shared_ptr msg = createChatMessage( - // // ChatMessage::Direction::Outgoing, - // // ChatRoomId(q->getPeerAddress(), Address(identity)) - // // ); - // - // Content *content = new Content(); - // content->setContentType("message/imdn+xml"); - // content->setBody(payload); - // msg->addContent(*content); - // - // /* Do not try to encrypt the notification when it is reporting an error (maybe it should be bypassed only for some reasons). */ - // int retval = -1; - // LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(cCore); - // if (imee && (reason == LinphoneReasonNone)) { - // LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); - // LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); - // if (cbProcessOutgoingMessage) { - // retval = cbProcessOutgoingMessage(imee, L_GET_C_BACK_PTR(q), L_GET_C_BACK_PTR(msg)); - // } - // } - // - // if (retval <= 0) { - // op->send_message(identity, q->getPeerAddress().asString().c_str(), msg->getPrivate()->getContentType().asString().c_str(), msg->getPrivate()->getText().c_str(), nullptr); - // } - // - // linphone_address_unref(peer); - // op->unref(); -} - // ----------------------------------------------------------------------------- void ChatRoomPrivate::setState (ChatRoom::State newState) { From b7d0db120fd7da6d387d23694478c76321300d34 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 22 Nov 2017 11:08:50 +0100 Subject: [PATCH 0818/2215] Directly send the IMDN, do not go through the chatRoom --- src/chat/chat-message/chat-message.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index a26c1ca90..137a684e6 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -420,7 +420,7 @@ void ChatMessagePrivate::sendImdn (Imdn::Type imdnType, LinphoneReason reason) { content->setBody(createImdnXml(imdnType, reason)); msg->addContent(*content); - msg->send(); + msg->getPrivate()->send(); } LinphoneReason ChatMessagePrivate::receive () { From d41e2d5df5c2bd5372429ce20b35e6fdbc8415ed Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 22 Nov 2017 11:18:31 +0100 Subject: [PATCH 0819/2215] fix(core): coding style, avoid spaces => use tabs instead, alignment... --- coreapi/authentication.c | 74 +++++++-------- coreapi/bellesip_sal/sal_impl.c | 14 ++- coreapi/callbacks.c | 21 ++-- coreapi/private.h | 2 +- include/linphone/auth_info.h | 24 ++++- src/c-wrapper/internal/c-sal.cpp | 4 +- src/c-wrapper/internal/c-sal.h | 24 +++-- tester/register_tester.c | 158 ++++++++++++++++--------------- 8 files changed, 173 insertions(+), 148 deletions(-) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 0f4d44907..59a9db475 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -43,30 +43,29 @@ BELLE_SIP_INSTANCIATE_VPTR( ); LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid, const char *passwd, const char *ha1, const char *realm, const char *domain){ - return linphone_auth_info_new_for_algorithm(username, userid, passwd, ha1, realm, domain, NULL); + return linphone_auth_info_new_for_algorithm(username, userid, passwd, ha1, realm, domain, NULL); } LinphoneAuthInfo *linphone_auth_info_new_for_algorithm(const char *username, const char *userid, const char *passwd, const char *ha1, const char *realm, const char *domain, const char *algorithm){ - LinphoneAuthInfo *obj=belle_sip_object_new(LinphoneAuthInfo); - if (username!=NULL && (strlen(username)>0) ) obj->username=ms_strdup(username); - if (userid!=NULL && (strlen(userid)>0)) obj->userid=ms_strdup(userid); - if (passwd!=NULL && (strlen(passwd)>0)) obj->passwd=ms_strdup(passwd); - if (ha1!=NULL && (strlen(ha1)>0)) obj->ha1=ms_strdup(ha1); - if (realm!=NULL && (strlen(realm)>0)) obj->realm=ms_strdup(realm); - if (domain!=NULL && (strlen(domain)>0)) obj->domain=ms_strdup(domain); - /* Default algorithm is MD5 if it's NULL*/ - if(algorithm==NULL) - obj->algorithm = ms_strdup("MD5"); - /* If algorithm is neither MD5 or SHA-256, exit wit error*/ - if(algorithm && strcmp(algorithm, "MD5") && strcmp(algorithm, "SHA-256")){ - ms_error("Given algorithm %s is not correct.", algorithm); - return NULL; - } - /*Else, set algorithm for obj */ - if(algorithm){ - obj->algorithm=ms_strdup(algorithm); - } - return obj; + LinphoneAuthInfo *obj=belle_sip_object_new(LinphoneAuthInfo); + if (username!=NULL && (strlen(username)>0) ) obj->username=ms_strdup(username); + if (userid!=NULL && (strlen(userid)>0)) obj->userid=ms_strdup(userid); + if (passwd!=NULL && (strlen(passwd)>0)) obj->passwd=ms_strdup(passwd); + if (ha1!=NULL && (strlen(ha1)>0)) obj->ha1=ms_strdup(ha1); + if (realm!=NULL && (strlen(realm)>0)) obj->realm=ms_strdup(realm); + if (domain!=NULL && (strlen(domain)>0)) obj->domain=ms_strdup(domain); + + if (!algorithm) + obj->algorithm = ms_strdup("MD5"); + + if(algorithm && strcmp(algorithm, "MD5") && strcmp(algorithm, "SHA-256")){ + ms_error("Given algorithm %s is not correct.", algorithm); + return NULL; + } + + if(algorithm) + obj->algorithm=ms_strdup(algorithm); + return obj; } static void _linphone_auth_info_copy(LinphoneAuthInfo *dst, const LinphoneAuthInfo *src) { @@ -80,7 +79,7 @@ static void _linphone_auth_info_copy(LinphoneAuthInfo *dst, const LinphoneAuthIn if (src->tls_key) dst->tls_key = ms_strdup(src->tls_key); if (src->tls_cert_path) dst->tls_cert_path = ms_strdup(src->tls_cert_path); if (src->tls_key_path) dst->tls_key_path = ms_strdup(src->tls_key_path); - if (src->algorithm) dst->algorithm = ms_strdup(src->algorithm); + if (src->algorithm) dst->algorithm = ms_strdup(src->algorithm); } LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo *ai){ @@ -234,7 +233,7 @@ static void _linphone_auth_info_uninit(LinphoneAuthInfo *obj) { if (obj->tls_key != NULL) ms_free(obj->tls_key); if (obj->tls_cert_path != NULL) ms_free(obj->tls_cert_path); if (obj->tls_key_path != NULL) ms_free(obj->tls_key_path); - if (obj->algorithm != NULL) ms_free(obj->algorithm); + if (obj->algorithm != NULL) ms_free(obj->algorithm); } /** @@ -255,17 +254,16 @@ void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, in return; } if (!obj->ha1 && obj->realm && obj->passwd && (obj->username || obj->userid) && store_ha1_passwd) { - /*compute ha1 to avoid storing clear text password*/ - /* Default algorithm is MD5 if it's NULL */ - if((obj->algorithm==NULL)||(!(strcmp(obj->algorithm, "MD5")))){ - obj->ha1 = reinterpret_cast(ms_malloc(33)); - sal_auth_compute_ha1(obj->userid ? obj->userid : obj->username, obj->realm, obj->passwd, obj->ha1); - } - /* If algorithm is SHA-256, calcul ha1 by sha256*/ - if((obj->algorithm)&&(!(strcmp(obj->algorithm, "SHA-256")))){ - obj->ha1 = reinterpret_cast(ms_malloc(65)); - sal_auth_compute_ha1_for_algorithm(obj->userid ? obj->userid : obj->username, obj->realm, obj->passwd, obj->ha1,65, obj->algorithm); - } + /* Default algorithm is MD5 if it's NULL */ + if((obj->algorithm==NULL)||(!(strcmp(obj->algorithm, "MD5")))){ + obj->ha1 = reinterpret_cast(ms_malloc(33)); + sal_auth_compute_ha1(obj->userid ? obj->userid : obj->username, obj->realm, obj->passwd, obj->ha1); + } + /* If algorithm is SHA-256, calcul ha1 by sha256*/ + if((obj->algorithm)&&(!(strcmp(obj->algorithm, "SHA-256")))){ + obj->ha1 = reinterpret_cast(ms_malloc(65)); + sal_auth_compute_ha1_for_algorithm(obj->userid ? obj->userid : obj->username, obj->realm, obj->passwd, obj->ha1,65, obj->algorithm); + } } if (obj->username != NULL) { lp_config_set_string(config, key, "username", obj->username); @@ -297,9 +295,9 @@ void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, in if (obj->tls_key_path != NULL) { lp_config_set_string(config, key, "client_cert_key", obj->tls_key_path); } - if (obj->algorithm != NULL) { - lp_config_set_string(config, key, "algorithm", obj->algorithm); - } + if (obj->algorithm != NULL) { + lp_config_set_string(config, key, "algorithm", obj->algorithm); + } } LinphoneAuthInfo *linphone_auth_info_new_from_config_file(LpConfig * config, int pos) @@ -484,7 +482,7 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) sai.realm=ai->realm; sai.password=ai->passwd; sai.ha1=ai->ha1; - sai.algorithm=ai->algorithm; + sai.algorithm=ai->algorithm; if (ai->tls_cert && ai->tls_key) { sal_certificates_chain_parse(&sai, ai->tls_cert, SAL_CERTIFICATE_RAW_FORMAT_PEM); sal_signing_key_parse(&sai, ai->tls_key, ""); diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 41c562183..ad11525fb 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -65,7 +65,7 @@ SalAuthInfo* sal_auth_info_create(belle_sip_auth_event_t* event) { auth_info->username = ms_strdup(belle_sip_auth_event_get_username(event)); auth_info->domain = ms_strdup(belle_sip_auth_event_get_domain(event)); auth_info->mode = (SalAuthMode)belle_sip_auth_event_get_mode(event); - auth_info->algorithm = ms_strdup(belle_sip_auth_event_get_algorithm(event)); + auth_info->algorithm = ms_strdup(belle_sip_auth_event_get_algorithm(event)); return auth_info; } @@ -84,9 +84,15 @@ int sal_auth_compute_ha1(const char* userid,const char* realm,const char* passwo return belle_sip_auth_helper_compute_ha1(userid, realm, password, ha1); } -int sal_auth_compute_ha1_for_algorithm(const char* userid,const char* realm,const char* password, char* ha1, - size_t size, const char* algo) { - return belle_sip_auth_helper_compute_ha1_for_algorithm(userid, realm, password, ha1, size, algo); +int sal_auth_compute_ha1_for_algorithm( + const char *userid, + const char *realm, + const char *password, + char *ha1, + size_t size, + const char *algo +) { + return belle_sip_auth_helper_compute_ha1_for_algorithm(userid, realm, password, ha1, size, algo); } SalCustomHeader *sal_custom_header_ref(SalCustomHeader *ch){ diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index b6f95d591..e83c4bac4 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -526,15 +526,18 @@ static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) { } if (ai) { if (sai->mode == SalAuthModeHttpDigest) { - /* Compare algorithm of server(sai) with algorithm of client(ai), if they are not correspondant, - exit. The default algorithm is MD5 if it's NULL. */ - if(sai->algorithm && ai->algorithm) { - if(strcmp(ai->algorithm, sai->algorithm)) - return TRUE; - } - else if((ai->algorithm && strcmp(ai->algorithm, "MD5")) || - (sai->algorithm && strcmp(sai->algorithm, "MD5"))) - return TRUE; + /* + * Compare algorithm of server(sai) with algorithm of client(ai), if they are not correspondant, + * exit. The default algorithm is MD5 if it's NULL. + */ + if (sai->algorithm && ai->algorithm) { + if (strcmp(ai->algorithm, sai->algorithm)) + return TRUE; + } else if ( + (ai->algorithm && strcmp(ai->algorithm, "MD5")) || + (sai->algorithm && strcmp(sai->algorithm, "MD5")) + ) + return TRUE; sai->userid = ms_strdup(ai->userid ? ai->userid : ai->username); sai->password = ai->passwd?ms_strdup(ai->passwd) : NULL; diff --git a/coreapi/private.h b/coreapi/private.h index 528b9c35a..efe81bb52 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -562,7 +562,7 @@ struct _LinphoneAuthInfo char *tls_key; char *tls_cert_path; char *tls_key_path; - char *algorithm; + char *algorithm; }; typedef enum _LinphoneIsComposingState { diff --git a/include/linphone/auth_info.h b/include/linphone/auth_info.h index 0eec7924f..5b9e3a6b1 100644 --- a/include/linphone/auth_info.h +++ b/include/linphone/auth_info.h @@ -51,11 +51,25 @@ extern "C" { * @return A #LinphoneAuthInfo object. linphone_auth_info_destroy() must be used to destroy it when no longer needed. The LinphoneCore makes a copy of LinphoneAuthInfo * passed through linphone_core_add_auth_info(). **/ -LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid, - const char *passwd, const char *ha1,const char *realm, const char *domain); - -LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_new_for_algorithm(const char *username, const char *userid, - const char *passwd, const char *ha1,const char *realm, const char *domain, const char *algorithm); +LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_new( + const char *username, + const char *userid, + const char *passwd, + const char *ha1, + const char *rfealm, + const char *domain +); + +LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_new_for_algorithm( + const char *username, + const char *userid, + const char *passwd, + const char *ha1, + const char *realm, + const char *domain, + const char *algorithm +); + /** * Instantiates a new auth info with values from source. * @param[in] source The #LinphoneAuthInfo object to be cloned diff --git a/src/c-wrapper/internal/c-sal.cpp b/src/c-wrapper/internal/c-sal.cpp index 69f6842fb..1ed9aecb1 100644 --- a/src/c-wrapper/internal/c-sal.cpp +++ b/src/c-wrapper/internal/c-sal.cpp @@ -762,7 +762,7 @@ SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info) { new_auth_info->realm=auth_info->realm?ms_strdup(auth_info->realm):NULL; new_auth_info->domain=auth_info->realm?ms_strdup(auth_info->domain):NULL; new_auth_info->password=auth_info->password?ms_strdup(auth_info->password):NULL; - new_auth_info->algorithm=auth_info->algorithm?ms_strdup(auth_info->algorithm):NULL; + new_auth_info->algorithm=auth_info->algorithm?ms_strdup(auth_info->algorithm):NULL; return new_auth_info; } @@ -775,7 +775,7 @@ void sal_auth_info_delete(SalAuthInfo* auth_info) { if (auth_info->ha1) ms_free(auth_info->ha1); if (auth_info->certificates) sal_certificates_chain_delete(auth_info->certificates); if (auth_info->key) sal_signing_key_delete(auth_info->key); - if (auth_info->algorithm) ms_free(auth_info->algorithm); + if (auth_info->algorithm) ms_free(auth_info->algorithm); ms_free(auth_info); } diff --git a/src/c-wrapper/internal/c-sal.h b/src/c-wrapper/internal/c-sal.h index 10d58ad11..6a53665b5 100644 --- a/src/c-wrapper/internal/c-sal.h +++ b/src/c-wrapper/internal/c-sal.h @@ -23,11 +23,11 @@ protocols and implementations under linphone, for example SIP, JINGLE... **/ -#ifndef sal_h -#define sal_h +#ifndef _C_SAL_H_ +#define _C_SAL_H_ #ifdef HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif #include "mediastreamer2/mediastream.h" @@ -263,7 +263,7 @@ typedef struct SalStreamDescription{ SalSrtpCryptoAlgo crypto[SAL_CRYPTO_ALGO_MAX]; unsigned int crypto_local_tag; int max_rate; - bool_t implicit_rtcp_fb; + bool_t implicit_rtcp_fb; OrtpRtcpFbConfiguration rtcp_fb; OrtpRtcpXrConfiguration rtcp_xr; SalCustomSdpAttribute *custom_sdp_attributes; @@ -474,7 +474,7 @@ typedef struct SalAuthInfo{ char *realm; char *domain; char *ha1; - char *algorithm; + char *algorithm; SalAuthMode mode; belle_sip_signing_key_t *key; belle_sip_certificates_chain_t *certificates; @@ -488,10 +488,8 @@ extern "C" { SalAuthInfo* sal_auth_info_new(void); SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info); void sal_auth_info_delete(SalAuthInfo* auth_info); -LINPHONE_PUBLIC int sal_auth_compute_ha1(const char* userid,const char* realm,const char* password, char ha1[33]); -LINPHONE_PUBLIC int sal_auth_compute_ha1_for_algorithm(const char* userid,const char* realm,const char* password, char *ha1,size_t size,const char* algo); -/*LINPHONE_PUBLIC int sal_auth_compute_ha1_for_algorithm(const char* userid,const char* realm,const char* password, char *ha1, - size_t size, const char* algo);*/ +LINPHONE_PUBLIC int sal_auth_compute_ha1(const char *userid, const char *realm, const char *password, char ha1[33]); +LINPHONE_PUBLIC int sal_auth_compute_ha1_for_algorithm(const char *userid, const char *realm, const char *password, char *ha1, size_t size, const char *algo); SalAuthMode sal_auth_info_get_mode(const SalAuthInfo* auth_info); belle_sip_signing_key_t *sal_auth_info_get_signing_key(const SalAuthInfo* auth_info); belle_sip_certificates_chain_t *sal_auth_info_get_certificates_chain(const SalAuthInfo* auth_info); @@ -579,13 +577,13 @@ typedef enum _SalPrivacy { SalPrivacyCritical=0x10, SalPrivacyDefault=0x8000 } SalPrivacy; -typedef unsigned int SalPrivacyMask; +typedef unsigned int SalPrivacyMask; #ifdef __cplusplus extern "C" { #endif -const char* sal_privacy_to_string(SalPrivacy privacy); +const char* sal_privacy_to_string(SalPrivacy privacy); #ifdef __cplusplus } @@ -593,8 +591,8 @@ const char* sal_privacy_to_string(SalPrivacy privacy); -#define payload_type_set_number(pt,n) (pt)->user_data=(void*)((intptr_t)n); -#define payload_type_get_number(pt) ((int)(intptr_t)(pt)->user_data) +#define payload_type_set_number(pt,n) (pt)->user_data=(void*)((intptr_t)n); +#define payload_type_get_number(pt) ((int)(intptr_t)(pt)->user_data) #ifdef __cplusplus extern "C" { diff --git a/tester/register_tester.c b/tester/register_tester.c index bffbdbeb7..cf7dc0c1f 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -64,14 +64,16 @@ void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *c } } -static void register_with_refresh_base_3_for_algo(LinphoneCore* lc - , bool_t refresh - ,const char* domain - ,const char* route - ,bool_t late_auth_info - ,LinphoneTransports *transport - ,LinphoneRegistrationState expected_final_state - ,const char* username) { +static void register_with_refresh_base_3_for_algo( + LinphoneCore* lc, + bool_t refresh, + const char* domain, + const char* route, + bool_t late_auth_info, + LinphoneTransports *transport, + LinphoneRegistrationState expected_final_state, + const char* username +) { int retry=0; char* addr; LinphoneProxyConfig* proxy_cfg; @@ -89,7 +91,7 @@ static void register_with_refresh_base_3_for_algo(LinphoneCore* lc proxy_cfg = linphone_proxy_config_new(); - from = create_linphone_address_for_algo(domain, username); + from = create_linphone_address_for_algo(domain, username); linphone_proxy_config_set_identity(proxy_cfg,addr=linphone_address_as_string(from)); ms_free(addr); @@ -114,7 +116,7 @@ static void register_with_refresh_base_3_for_algo(LinphoneCore* lc if (counters->number_of_auth_info_requested>0 && linphone_proxy_config_get_state(proxy_cfg) == LinphoneRegistrationFailed && late_auth_info) { if (!linphone_core_get_auth_info_list(lc)) { BC_ASSERT_EQUAL(linphone_proxy_config_get_error(proxy_cfg),LinphoneReasonUnauthorized, int, "%d"); - info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ + info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ linphone_auth_info_unref(info); } @@ -137,55 +139,59 @@ static void register_with_refresh_base_3_for_algo(LinphoneCore* lc linphone_proxy_config_unref(proxy_cfg); } -static void register_with_refresh_base_3(LinphoneCore* lc - , bool_t refresh - ,const char* domain - ,const char* route - ,bool_t late_auth_info - ,LinphoneTransports *transport - ,LinphoneRegistrationState expected_final_state) { - register_with_refresh_base_3_for_algo(lc, refresh, domain, route, late_auth_info, transport, expected_final_state, NULL); +static void register_with_refresh_base_3( + LinphoneCore* lc, + bool_t refresh, + const char *domain, + const char *route, + bool_t late_auth_info, + LinphoneTransports *transport, + LinphoneRegistrationState expected_final_state +) { + register_with_refresh_base_3_for_algo(lc, refresh, domain, route, late_auth_info, transport, expected_final_state, NULL); } -static void register_with_refresh_base_2(LinphoneCore* lc - , bool_t refresh - ,const char* domain - ,const char* route - ,bool_t late_auth_info - ,LinphoneTransports *transport) { - register_with_refresh_base_3(lc, refresh, domain, route, late_auth_info, transport,LinphoneRegistrationOk ); +static void register_with_refresh_base_2( + LinphoneCore* lc, + bool_t refresh, + const char *domain, + const char *route, + bool_t late_auth_info, + LinphoneTransports *transport +) { + register_with_refresh_base_3(lc, refresh, domain, route, late_auth_info, transport,LinphoneRegistrationOk); } -static void register_with_refresh_base_for_algo(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route, const char* username) { - LinphoneTransports *transport = linphone_factory_create_transports(linphone_factory_get()); - linphone_transports_set_udp_port(transport, 5070); - linphone_transports_set_tcp_port(transport, 5070); - linphone_transports_set_tls_port(transport, 5071); - linphone_transports_set_dtls_port(transport, 0); - register_with_refresh_base_3_for_algo(lc,refresh,domain,route,FALSE,transport,LinphoneRegistrationOk,username); - linphone_transports_unref(transport); +static void register_with_refresh_base_for_algo(LinphoneCore* lc, bool_t refresh, const char *domain,const char *route, const char *username) { + LinphoneTransports *transport = linphone_factory_create_transports(linphone_factory_get()); + linphone_transports_set_udp_port(transport, 5070); + linphone_transports_set_tcp_port(transport, 5070); + linphone_transports_set_tls_port(transport, 5071); + linphone_transports_set_dtls_port(transport, 0); + register_with_refresh_base_3_for_algo(lc,refresh,domain,route,FALSE,transport,LinphoneRegistrationOk,username); + linphone_transports_unref(transport); } -static void register_with_refresh_base(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { - register_with_refresh_base_for_algo(lc, refresh, domain, route, NULL); +static void register_with_refresh_base(LinphoneCore *lc, bool_t refresh, const char *domain, const char *route) { + register_with_refresh_base_for_algo(lc, refresh, domain, route, NULL); } -static void register_with_refresh_for_algo(LinphoneCoreManager* lcm, bool_t refresh,const char* domain,const char* route,const char* username) { - stats* counters = &lcm->stat; - register_with_refresh_base_for_algo(lcm->lc,refresh,domain,route,username); - linphone_core_manager_stop(lcm); - BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,1, int, "%d"); +static void register_with_refresh_for_algo(LinphoneCoreManager *lcm, bool_t refresh, const char *domain, const char*route, const char *username) { + stats* counters = &lcm->stat; + register_with_refresh_base_for_algo(lcm->lc,refresh,domain,route,username); + linphone_core_manager_stop(lcm); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,1, int, "%d"); } static void register_with_refresh(LinphoneCoreManager* lcm, bool_t refresh,const char* domain,const char* route) { - register_with_refresh_for_algo(lcm, refresh, domain, route, NULL); + register_with_refresh_for_algo(lcm, refresh, domain, route, NULL); } static void register_with_refresh_with_send_error(void) { int retry=0; LinphoneCoreManager* lcm = create_lcm_with_auth(1); stats* counters = &lcm->stat; - LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ char route[256]; sprintf(route,"sip:%s",test_route); linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ @@ -330,7 +336,7 @@ static void simple_tls_register(void){ static void simple_authenticated_register(void){ stats* counters; LinphoneCoreManager* lcm = create_lcm(); - LinphoneAuthInfo *info=linphone_auth_info_new_for_algorithm(test_username,NULL,test_password,NULL,auth_domain,NULL,NULL); /*create authentication structure from identity*/ + LinphoneAuthInfo *info=linphone_auth_info_new_for_algorithm(test_username,NULL,test_password,NULL,auth_domain,NULL,NULL); /*create authentication structure from identity*/ char route[256]; sprintf(route,"sip:%s",test_route); linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ @@ -342,17 +348,17 @@ static void simple_authenticated_register(void){ } static void simple_authenticated_register_for_algorithm(void){ - stats* counters; - LinphoneCoreManager* lcm = create_lcm(); - LinphoneAuthInfo *info=linphone_auth_info_new_for_algorithm(test_sha_username,NULL,test_password,NULL,auth_domain,NULL,"SHA-256"); /*create authentication structure from identity*/ - char route[256]; - sprintf(route,"sip:%s",test_route); - linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ - linphone_auth_info_unref(info); - counters = &lcm->stat; - register_with_refresh_for_algo(lcm,FALSE,auth_domain,route,test_sha_username); - BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,0, int, "%d"); - linphone_core_manager_destroy(lcm); + stats* counters; + LinphoneCoreManager* lcm = create_lcm(); + LinphoneAuthInfo *info=linphone_auth_info_new_for_algorithm(test_sha_username,NULL,test_password,NULL,auth_domain,NULL,"SHA-256"); /*create authentication structure from identity*/ + char route[256]; + sprintf(route,"sip:%s",test_route); + linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ + linphone_auth_info_unref(info); + counters = &lcm->stat; + register_with_refresh_for_algo(lcm,FALSE,auth_domain,route,test_sha_username); + BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,0, int, "%d"); + linphone_core_manager_destroy(lcm); } static void ha1_authenticated_register(void){ @@ -373,20 +379,20 @@ static void ha1_authenticated_register(void){ } static void ha1_authenticated_register_for_algorithm(void){ - stats* counters; - LinphoneCoreManager* lcm = create_lcm(); - char ha1[65]; - LinphoneAuthInfo *info; - char route[256]; - sal_auth_compute_ha1_for_algorithm(test_sha_username,auth_domain,test_password,ha1,65,"SHA-256"); - info=linphone_auth_info_new_for_algorithm(test_sha_username,NULL,NULL,ha1,auth_domain,NULL,"SHA-256"); /*create authentication structure from identity*/ - sprintf(route,"sip:%s",test_route); - linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ - linphone_auth_info_unref(info); - counters = &lcm->stat; - register_with_refresh_for_algo(lcm,FALSE,auth_domain,route,test_sha_username); - BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,0, int, "%d"); - linphone_core_manager_destroy(lcm); + stats* counters; + LinphoneCoreManager* lcm = create_lcm(); + char ha1[65]; + LinphoneAuthInfo *info; + char route[256]; + sal_auth_compute_ha1_for_algorithm(test_sha_username,auth_domain,test_password,ha1,65,"SHA-256"); + info=linphone_auth_info_new_for_algorithm(test_sha_username,NULL,NULL,ha1,auth_domain,NULL,"SHA-256"); /*create authentication structure from identity*/ + sprintf(route,"sip:%s",test_route); + linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ + linphone_auth_info_unref(info); + counters = &lcm->stat; + register_with_refresh_for_algo(lcm,FALSE,auth_domain,route,test_sha_username); + BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,0, int, "%d"); + linphone_core_manager_destroy(lcm); } static void authenticated_register_with_no_initial_credentials(void){ @@ -419,7 +425,7 @@ static void authenticated_register_with_late_credentials(void){ sprintf(route,"sip:%s",test_route); - lcm = linphone_core_manager_new(NULL); + lcm = linphone_core_manager_new(NULL); transport = linphone_factory_create_transports(linphone_factory_get()); linphone_transports_set_udp_port(transport, 5070); linphone_transports_set_tcp_port(transport, 5070); @@ -443,7 +449,7 @@ static void authenticated_register_with_provided_credentials(void){ sprintf(route,"sip:%s",test_route); - lcm = linphone_core_manager_new(NULL); + lcm = linphone_core_manager_new(NULL); counters = get_stats(lcm->lc); cfg = linphone_core_create_proxy_config(lcm->lc); @@ -485,7 +491,7 @@ static void authenticated_register_with_wrong_late_credentials(void){ sprintf(route,"sip:%s",test_route); - lcm = linphone_core_manager_new(NULL); + lcm = linphone_core_manager_new(NULL); transport = linphone_factory_create_transports(linphone_factory_get()); linphone_transports_set_udp_port(transport, 5070); linphone_transports_set_tcp_port(transport, 5070); @@ -738,8 +744,8 @@ static void proxy_transport_change(void){ } /* * On ios, some firewal require to disable flow label (livebox with default firewall level). - * sudo sysctl net.inet6.ip6.auto_flowlabel=0 - * It might be possible to found a sockopt for such purpose. + * sudo sysctl net.inet6.ip6.auto_flowlabel=0 + * It might be possible to found a sockopt for such purpose. */ static void proxy_transport_change_with_wrong_port(void) { LinphoneCoreManager* lcm = create_lcm(); @@ -962,7 +968,7 @@ static void tls_certificate_failure(void){ } char *read_file(const char *path) { - long numbytes = 0; + long numbytes = 0; size_t readbytes; char *buffer = NULL; FILE *infile = fopen(path, "rb"); @@ -1294,9 +1300,9 @@ test_t register_tests[] = { TEST_NO_TAG("TLS certificate given by string instead of file",tls_certificate_data), TEST_NO_TAG("TLS with non tls server",tls_with_non_tls_server), TEST_NO_TAG("Simple authenticated register", simple_authenticated_register), - TEST_NO_TAG("Simple authenticated register SHA-256", simple_authenticated_register_for_algorithm), + TEST_NO_TAG("Simple authenticated register SHA-256", simple_authenticated_register_for_algorithm), TEST_NO_TAG("Ha1 authenticated register", ha1_authenticated_register), - TEST_NO_TAG("Ha1 authenticated register SHA-256", ha1_authenticated_register_for_algorithm), + TEST_NO_TAG("Ha1 authenticated register SHA-256", ha1_authenticated_register_for_algorithm), TEST_NO_TAG("Digest auth without initial credentials", authenticated_register_with_no_initial_credentials), TEST_NO_TAG("Digest auth with wrong credentials", authenticated_register_with_wrong_credentials), TEST_NO_TAG("Digest auth with wrong credentials, check if registration attempts are stopped", authenticated_register_with_wrong_credentials_2), From 385284596ed405a02de88ebc70b5c95c4eb2f438 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 22 Nov 2017 11:23:30 +0100 Subject: [PATCH 0820/2215] feat(ChatRoom): provide a get creation/last update time accessor --- src/chat/chat-room/chat-room-p.h | 6 ++++ src/chat/chat-room/chat-room.cpp | 12 ++++++++ src/chat/chat-room/chat-room.h | 8 +++-- src/db/main-db.cpp | 50 ++++++++++++++++++-------------- tester/main-db-tester.cpp | 18 ++++++------ 5 files changed, 62 insertions(+), 32 deletions(-) diff --git a/src/chat/chat-room/chat-room-p.h b/src/chat/chat-room/chat-room-p.h index 650b7d3b6..1a06de91d 100644 --- a/src/chat/chat-room/chat-room-p.h +++ b/src/chat/chat-room/chat-room-p.h @@ -94,8 +94,14 @@ public: // TODO: Use CoreAccessor on IsComposing. And avoid pointer if possible. std::unique_ptr isComposingHandler; + // TODO: Check all fields before this point. + +public: ChatRoomId chatRoomId; + time_t creationTime = -1; + time_t lastUpdateTime = -1; + private: L_DECLARE_PUBLIC(ChatRoom); }; diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 27e11113b..0d5bbea64 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -139,6 +139,18 @@ const IdentityAddress &ChatRoom::getLocalAddress () const { // ----------------------------------------------------------------------------- +time_t ChatRoom::getCreationTime () const { + L_D(); + return d->creationTime; +} + +time_t ChatRoom::getLastUpdateTime () const { + L_D(); + return d->lastUpdateTime; +} + +// ----------------------------------------------------------------------------- + /** * DB layout: * diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index b11d28d93..e98af035a 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -31,11 +31,12 @@ LINPHONE_BEGIN_NAMESPACE class ChatRoomPrivate; class LINPHONE_PUBLIC ChatRoom : public Object, public CoreAccessor, public ConferenceInterface { - friend class Core; - friend class CorePrivate; friend class ChatMessage; friend class ChatMessagePrivate; + friend class Core; + friend class CorePrivate; friend class FileTransferChatMessageModifier; + friend class MainDb; public: L_OVERRIDE_SHARED_FROM_THIS(ChatRoom); @@ -52,6 +53,9 @@ public: const IdentityAddress &getPeerAddress () const; const IdentityAddress &getLocalAddress () const; + time_t getCreationTime () const; + time_t getLastUpdateTime () const; + virtual CapabilitiesMask getCapabilities () const = 0; // TODO: Remove useless functions. diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index a0e908fdc..76af6928e 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -28,6 +28,7 @@ #include "chat/chat-message/chat-message-p.h" #include "chat/chat-room/client-group-chat-room.h" +#include "chat/chat-room/chat-room-p.h" #include "conference/participant.h" #include "content/content-type.h" #include "content/content.h" @@ -205,13 +206,13 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); soci::statement statement = ( session->prepare << "UPDATE chat_room_participant SET is_admin = :isAdmin" - " WHERE chat_room_id = :chatRoomId AND participant_address_id = :sipAddressId", + " WHERE chat_room_id = :chatRoomId AND participant_sip_address_id = :sipAddressId", soci::use(static_cast(isAdmin)), soci::use(chatRoomId), soci::use(sipAddressId) ); statement.execute(true); if (statement.get_affected_rows() == 0) { lInfo() << "Insert new chat room participant in database: `" << sipAddressId << "` (isAdmin=" << isAdmin << ")."; - *session << "INSERT INTO chat_room_participant (chat_room_id, participant_address_id, is_admin)" + *session << "INSERT INTO chat_room_participant (chat_room_id, participant_sip_address_id, is_admin)" " VALUES (:chatRoomId, :sipAddressId, :isAdmin)", soci::use(chatRoomId), soci::use(sipAddressId), soci::use(static_cast(isAdmin)); } @@ -221,12 +222,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); soci::statement statement = ( session->prepare << "UPDATE chat_message_participant SET state = :state" - " WHERE event_id = :eventId AND participant_address_id = :sipAddressId", + " WHERE event_id = :eventId AND participant_sip_address_id = :sipAddressId", soci::use(state), soci::use(eventId), soci::use(sipAddressId) ); statement.execute(true); if (statement.get_affected_rows() == 0 && state != static_cast(ChatMessage::State::Displayed)) - *session << "INSERT INTO chat_message_participant (event_id, participant_address_id, state)" + *session << "INSERT INTO chat_message_participant (event_id, participant_sip_address_id, state)" " VALUES (:eventId, :sipAddressId, :state)", soci::use(eventId), soci::use(sipAddressId), soci::use(state); } @@ -432,7 +433,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " FROM conference_notified_event, conference_participant_event, sip_address as participant_address" " WHERE conference_participant_event.event_id = :eventId" " AND conference_notified_event.event_id = conference_participant_event.event_id" - " AND participant_address.id = participant_address_id", + " AND participant_address.id = participant_sip_address_id", soci::into(notifyId), soci::into(participantAddress), soci::use(eventId); return make_shared( @@ -461,8 +462,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " WHERE conference_participant_device_event.event_id = :eventId" " AND conference_participant_event.event_id = conference_participant_device_event.event_id" " AND conference_notified_event.event_id = conference_participant_event.event_id" - " AND participant_address.id = participant_address_id" - " AND device_address.id = device_address_id", + " AND participant_address.id = participant_sip_address_id" + " AND device_address.id = device_sip_address_id", soci::into(notifyId), soci::into(participantAddress), soci::into(deviceAddress), soci::use(eventId); return make_shared( @@ -608,7 +609,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), ); soci::session *session = dbSession.getBackendSession(); - *session << "INSERT INTO conference_participant_event (event_id, participant_address_id)" + *session << "INSERT INTO conference_participant_event (event_id, participant_sip_address_id)" " VALUES (:eventId, :participantAddressId)", soci::use(eventId), soci::use(participantAddressId); return eventId; @@ -624,7 +625,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), ); soci::session *session = dbSession.getBackendSession(); - *session << "INSERT INTO conference_participant_device_event (event_id, device_address_id)" + *session << "INSERT INTO conference_participant_device_event (event_id, device_sip_address_id)" " VALUES (:eventId, :deviceAddressId)", soci::use(eventId), soci::use(deviceAddressId); return eventId; @@ -741,16 +742,16 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS chat_room_participant (" " chat_room_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," - " participant_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " participant_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," " is_admin BOOLEAN NOT NULL," - " PRIMARY KEY (chat_room_id, participant_address_id)," + " PRIMARY KEY (chat_room_id, participant_sip_address_id)," " FOREIGN KEY (chat_room_id)" " REFERENCES chat_room(id)" " ON DELETE CASCADE," - " FOREIGN KEY (participant_address_id)" + " FOREIGN KEY (participant_sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" ") " + charset; @@ -784,12 +785,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), "CREATE TABLE IF NOT EXISTS conference_participant_event (" " event_id" + primaryKeyStr("BIGINT UNSIGNED") + "," - " participant_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," + " participant_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," " FOREIGN KEY (event_id)" " REFERENCES conference_notified_event(event_id)" " ON DELETE CASCADE," - " FOREIGN KEY (participant_address_id)" + " FOREIGN KEY (participant_sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" ") " + charset; @@ -798,12 +799,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), "CREATE TABLE IF NOT EXISTS conference_participant_device_event (" " event_id" + primaryKeyStr("BIGINT UNSIGNED") + "," - " device_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," + " device_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," " FOREIGN KEY (event_id)" " REFERENCES conference_participant_event(event_id)" " ON DELETE CASCADE," - " FOREIGN KEY (device_address_id)" + " FOREIGN KEY (device_sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" ") " + charset; @@ -846,14 +847,16 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS chat_message_participant (" - " event_id" + primaryKeyStr("BIGINT UNSIGNED") + "," - " participant_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " event_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " participant_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," " state TINYINT UNSIGNED NOT NULL," + " PRIMARY KEY (event_id, participant_sip_address_id)," + " FOREIGN KEY (event_id)" " REFERENCES conference_chat_message_event(event_id)" " ON DELETE CASCADE," - " FOREIGN KEY (participant_address_id)" + " FOREIGN KEY (participant_sip_address_id)" " REFERENCES sip_address(id)" " ON DELETE CASCADE" ") " + charset; @@ -866,6 +869,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " content_type_id" + primaryKeyRefStr("SMALLINT UNSIGNED") + " NOT NULL," " body TEXT NOT NULL," + " UNIQUE (id, event_id)," + " FOREIGN KEY (event_id)" " REFERENCES conference_chat_message_event(event_id)" " ON DELETE CASCADE," @@ -1385,8 +1390,6 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), unsigned int lastNotifyId = static_cast(row.get(6, 0)); // TODO: Use me. - (void)creationDate; - (void)lastUpdateDate; (void)lastNotifyId; if (capabilities & static_cast(ChatRoom::Capabilities::Basic)) { @@ -1394,6 +1397,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), chatRoomId, capabilities & static_cast(ChatRoom::Capabilities::RealTimeText) ); + chatRoom->setSubject(subject); + + ChatRoomPrivate *dChatRoom = chatRoom->getPrivate(); + dChatRoom->creationTime = Utils::getTmAsTimeT(creationDate); + dChatRoom->lastUpdateTime = Utils::getTmAsTimeT(lastUpdateDate); } else if (capabilities & static_cast(ChatRoom::Capabilities::Conference)) { // TODO: Fetch! // chatRoom = make_shared( diff --git a/tester/main-db-tester.cpp b/tester/main-db-tester.cpp index 8fea5a552..e6ee22ba8 100644 --- a/tester/main-db-tester.cpp +++ b/tester/main-db-tester.cpp @@ -73,11 +73,11 @@ static void open_database () { static void get_events_count () { MainDbProvider provider; const MainDb &mainDb = provider.getMainDb(); - BC_ASSERT_EQUAL(mainDb.getEventsCount(), 4994, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventsCount(), 5175, int, "%d"); BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceCallFilter), 0, int, "%d"); BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceInfoFilter), 18, int, "%d"); BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceChatMessageFilter), 5157, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::NoFilter), 4994, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::NoFilter), 5175, int, "%d"); } static void get_messages_count () { @@ -86,9 +86,9 @@ static void get_messages_count () { BC_ASSERT_EQUAL(mainDb.getChatMessagesCount(), 5157, int, "%d"); BC_ASSERT_EQUAL( mainDb.getChatMessagesCount( - ChatRoomId(IdentityAddress("sip:test-39@sip.linphone.org"), IdentityAddress("sip:test-39@sip.linphone.org")) + ChatRoomId(IdentityAddress("sip:test-3@sip.linphone.org"), IdentityAddress("sip:test-1@sip.linphone.org")) ), - 3, int, "%d" + 861, int, "%d" ); } @@ -98,7 +98,7 @@ static void get_unread_messages_count () { BC_ASSERT_EQUAL(mainDb.getUnreadChatMessagesCount(), 2, int, "%d"); BC_ASSERT_EQUAL( mainDb.getUnreadChatMessagesCount( - ChatRoomId(IdentityAddress("sip:test-39@sip.linphone.org"), IdentityAddress("sip:test-39@sip.linphone.org")) + ChatRoomId(IdentityAddress("sip:test-3@sip.linphone.org"), IdentityAddress("sip:test-1@sip.linphone.org")) ), 0, int, "%d" ); @@ -109,10 +109,10 @@ static void get_history () { const MainDb &mainDb = provider.getMainDb(); BC_ASSERT_EQUAL( mainDb.getHistoryRange( - ChatRoomId(IdentityAddress("sip:test-39@sip.linphone.org"), IdentityAddress("sip:test-39@sip.linphone.org")), + ChatRoomId(IdentityAddress("sip:test-4@sip.linphone.org"), IdentityAddress("sip:test-1@sip.linphone.org")), 0, -1, MainDb::Filter::ConferenceChatMessageFilter ).size(), - 3, + 54, int, "%d" ); @@ -177,7 +177,7 @@ static void get_conference_notified_events () { BC_ASSERT_TRUE(deviceEvent->getChatRoomId().getPeerAddress().asString() == "sip:fake-group-2@sip.linphone.org"); BC_ASSERT_TRUE(deviceEvent->getParticipantAddress().asString() == "sip:test-11@sip.linphone.org"); BC_ASSERT_TRUE(deviceEvent->getNotifyId() == 3); - BC_ASSERT_TRUE(deviceEvent->getDeviceAddress().asString() == "sip:gruu-address-1@sip.linphone.org"); + BC_ASSERT_TRUE(deviceEvent->getDeviceAddress().asString() == "sip:device-address-1@sip.linphone.org"); } event = *++it; @@ -189,7 +189,7 @@ static void get_conference_notified_events () { BC_ASSERT_TRUE(deviceEvent->getChatRoomId().getPeerAddress().asString() == "sip:fake-group-2@sip.linphone.org"); BC_ASSERT_TRUE(deviceEvent->getParticipantAddress().asString() == "sip:test-11@sip.linphone.org"); BC_ASSERT_TRUE(deviceEvent->getNotifyId() == 4); - BC_ASSERT_TRUE(deviceEvent->getDeviceAddress().asString() == "sip:gruu-address-1@sip.linphone.org"); + BC_ASSERT_TRUE(deviceEvent->getDeviceAddress().asString() == "sip:device-address-1@sip.linphone.org"); } } From 39c18909054285d47bf16e838b2e7588f56cb85b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 22 Nov 2017 11:49:14 +0100 Subject: [PATCH 0821/2215] Fix gruu parameter in IdentityAddress. --- src/address/address.cpp | 2 +- src/address/identity-address.cpp | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/address/address.cpp b/src/address/address.cpp index 9dd1e915f..504c7986f 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -61,7 +61,7 @@ Address::Address (const IdentityAddress &src) : ClonableObject(*new AddressPriva ); if (src.hasGruu()) - uri += "?gr=" + src.getGruu(); + uri += ";gr=" + src.getGruu(); d->internalAddress = sal_address_new(L_STRING_TO_C(uri)); } diff --git a/src/address/identity-address.cpp b/src/address/identity-address.cpp index 45c2d9383..982c55a69 100644 --- a/src/address/identity-address.cpp +++ b/src/address/identity-address.cpp @@ -38,9 +38,7 @@ IdentityAddress::IdentityAddress (const string &address) : ClonableObject(*new I d->scheme = tmpAddress.getScheme(); d->username = tmpAddress.getUsername(); d->domain = tmpAddress.getDomain(); - if (tmpAddress.hasUriParam("gr")) { - d->gruu = tmpAddress.getUriParamValue("gr"); - } + d->gruu = tmpAddress.getUriParamValue("gr"); } } @@ -57,9 +55,7 @@ IdentityAddress::IdentityAddress (const Address &src) : ClonableObject(*new Iden d->scheme = src.getScheme(); d->username = src.getUsername(); d->domain = src.getDomain(); - if (src.hasUriParam("gr")) { - d->gruu = src.getUriParamValue("gr"); - } + d->gruu = src.getUriParamValue("gr"); } IdentityAddress &IdentityAddress::operator= (const IdentityAddress &src) { From 7ac3d57f689c0c6ce6bbbfdf541ddfc143e389a8 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 22 Nov 2017 11:49:30 +0100 Subject: [PATCH 0822/2215] Document some LinphoneAddress functions for automatic wrapper generation. --- include/linphone/api/c-address.h | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/include/linphone/api/c-address.h b/include/linphone/api/c-address.h index 4648be378..f5ad85981 100644 --- a/include/linphone/api/c-address.h +++ b/include/linphone/api/c-address.h @@ -202,18 +202,54 @@ LINPHONE_PUBLIC const char *linphone_address_get_header (const LinphoneAddress * **/ LINPHONE_PUBLIC void linphone_address_set_header (LinphoneAddress *address, const char *header_name, const char *header_value); +/** + * Tell whether a parameter is present in the address + * @param[in] address LinphoneAddress object + * @param[in] param_name The name of the parameter + * @return A boolean value telling whether the parameter is present in the address + */ LINPHONE_PUBLIC bool_t linphone_address_has_param (const LinphoneAddress *address, const char *param_name); +/** + * Get the value of a parameter of the address + * @param[in] address LinphoneAddress object + * @param[in] param_name The name of the parameter + * @return The value of the parameter + */ LINPHONE_PUBLIC const char *linphone_address_get_param (const LinphoneAddress *address, const char *param_name); +/** + * Set the value of a parameter of the address + * @param[in] address LinphoneAddress object + * @param[in] param_name The name of the parameter + * @param[in] param_value The new value of the parameter + */ LINPHONE_PUBLIC void linphone_address_set_param (LinphoneAddress *address, const char *param_name, const char *param_value); LINPHONE_PUBLIC void linphone_address_set_params (LinphoneAddress *address, const char *params); +/** + * Tell whether a parameter is present in the URI of the address + * @param[in] address LinphoneAddress object + * @param[in] uri_param_name The name of the parameter + * @return A boolean value telling whether the parameter is present in the URI of the address + */ LINPHONE_PUBLIC bool_t linphone_address_has_uri_param (const LinphoneAddress *address, const char *uri_param_name); +/** + * Get the value of a parameter of the URI of the address + * @param[in] address LinphoneAddress object + * @param[in] uri_param_name The name of the parameter + * @return The value of the parameter + */ LINPHONE_PUBLIC const char *linphone_address_get_uri_param (const LinphoneAddress *address, const char *uri_param_name); +/** + * Set the value of a parameter of the URI of the address + * @param[in] address LinphoneAddress object + * @param[in] uri_param_name The name of the parameter + * @param[in] uri_param_value The new value of the parameter + */ LINPHONE_PUBLIC void linphone_address_set_uri_param (LinphoneAddress *address, const char *uri_param_name, const char *uri_param_value); LINPHONE_PUBLIC void linphone_address_set_uri_params (LinphoneAddress *address, const char *params); From f492097cfd869c178ecbcd6db36ced62c2275dbf Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 22 Nov 2017 11:50:00 +0100 Subject: [PATCH 0823/2215] Do not insert server group chat room for now. --- coreapi/chat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 0ebe80b6e..670cd1b77 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -96,8 +96,8 @@ LinphoneChatRoom *_linphone_core_join_client_group_chat_room (LinphoneCore *lc, LinphoneChatRoom *_linphone_core_create_server_group_chat_room (LinphoneCore *lc, LinphonePrivate::SalCallOp *op) { LinphoneChatRoom *cr = _linphone_server_group_chat_room_new(lc, op); - L_GET_PRIVATE(lc->cppCore)->insertChatRoom(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); - L_GET_PRIVATE(lc->cppCore)->insertChatRoomWithDb(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); + //L_GET_PRIVATE(lc->cppCore)->insertChatRoom(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); + //L_GET_PRIVATE(lc->cppCore)->insertChatRoomWithDb(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); return cr; } From fa861d553d24a5758cf2839dfbd0a1b9777110dd Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 22 Nov 2017 13:54:30 +0100 Subject: [PATCH 0824/2215] fix(core): add explicit on some constructors --- include/linphone/utils/enum-generator.h | 2 +- src/address/address.cpp | 40 ++++++++++---------- src/address/address.h | 2 +- src/address/identity-address.cpp | 17 +++++---- src/address/identity-address.h | 2 +- src/c-wrapper/api/c-chat-room.cpp | 12 ++++-- src/c-wrapper/api/c-participant.cpp | 2 +- src/content/content.cpp | 10 ++--- src/core/core.cpp | 2 +- src/core/platform-helpers/platform-helpers.h | 4 +- 10 files changed, 49 insertions(+), 44 deletions(-) diff --git a/include/linphone/utils/enum-generator.h b/include/linphone/utils/enum-generator.h index 09c04328f..9dbfbb49a 100644 --- a/include/linphone/utils/enum-generator.h +++ b/include/linphone/utils/enum-generator.h @@ -55,7 +55,7 @@ LINPHONE_BEGIN_NAMESPACE // TODO: This macro should be used but it is triggering a bug in doxygen that // has been fixed in the 1.8.8 version. See https://bugzilla.gnome.org/show_bug.cgi?id=731985 -// Meanwhile use 2 different macros +// Meanwhile use 2 different macros. #if 0 #define L_DECLARE_C_ENUM(NAME, VALUES) \ typedef enum L_CONCAT(_, L_CONCAT(L_C_ENUM_PREFIX, NAME)) { \ diff --git a/src/address/address.cpp b/src/address/address.cpp index 504c7986f..273fe0a20 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -39,6 +39,26 @@ Address::Address (const string &address) : ClonableObject(*new AddressPrivate) { } } +Address::Address (const IdentityAddress &identityAddress) : ClonableObject(*new AddressPrivate) { + L_D(); + + const string &username = identityAddress.getUsername(); + if (username.empty()) + return; + const string &domain = identityAddress.getDomain(); + if (domain.empty()) + return; + + string uri = identityAddress.getScheme() + ":" + username + "@" + ( + domain.find(':') != string::npos ? "[" + domain + "]" : domain + ); + + if (identityAddress.hasGruu()) + uri += ";gr=" + identityAddress.getGruu(); + + d->internalAddress = sal_address_new(L_STRING_TO_C(uri)); +} + Address::Address (const Address &src) : ClonableObject(*new AddressPrivate) { L_D(); SalAddress *salAddress = src.getPrivate()->internalAddress; @@ -46,26 +66,6 @@ Address::Address (const Address &src) : ClonableObject(*new AddressPrivate) { d->internalAddress = sal_address_clone(salAddress); } -Address::Address (const IdentityAddress &src) : ClonableObject(*new AddressPrivate) { - L_D(); - - const string &username = src.getUsername(); - if (username.empty()) - return; - const string &domain = src.getDomain(); - if (domain.empty()) - return; - - string uri = src.getScheme() + ":" + username + "@" + ( - domain.find(':') != string::npos ? "[" + domain + "]" : domain - ); - - if (src.hasGruu()) - uri += ";gr=" + src.getGruu(); - - d->internalAddress = sal_address_new(L_STRING_TO_C(uri)); -} - Address::~Address () { L_D(); if (d->internalAddress) diff --git a/src/address/address.h b/src/address/address.h index 718273731..a34a0081a 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -41,8 +41,8 @@ class LINPHONE_PUBLIC Address : public ClonableObject { public: explicit Address (const std::string &address = ""); + Address (const IdentityAddress &identityAddress); Address (const Address &src); - Address (const IdentityAddress &src); ~Address (); Address &operator= (const Address &src); diff --git a/src/address/identity-address.cpp b/src/address/identity-address.cpp index 982c55a69..b4cd58714 100644 --- a/src/address/identity-address.cpp +++ b/src/address/identity-address.cpp @@ -42,6 +42,15 @@ IdentityAddress::IdentityAddress (const string &address) : ClonableObject(*new I } } +IdentityAddress::IdentityAddress (const Address &address) : ClonableObject(*new IdentityAddressPrivate) { + L_D(); + d->scheme = address.getScheme(); + d->username = address.getUsername(); + d->domain = address.getDomain(); + if (address.hasUriParam("gr")) + d->gruu = address.getUriParamValue("gr"); +} + IdentityAddress::IdentityAddress (const IdentityAddress &src) : ClonableObject(*new IdentityAddressPrivate) { L_D(); d->scheme = src.getScheme(); @@ -50,14 +59,6 @@ IdentityAddress::IdentityAddress (const IdentityAddress &src) : ClonableObject(* d->gruu = src.getGruu(); } -IdentityAddress::IdentityAddress (const Address &src) : ClonableObject(*new IdentityAddressPrivate) { - L_D(); - d->scheme = src.getScheme(); - d->username = src.getUsername(); - d->domain = src.getDomain(); - d->gruu = src.getUriParamValue("gr"); -} - IdentityAddress &IdentityAddress::operator= (const IdentityAddress &src) { L_D(); if (this != &src) { diff --git a/src/address/identity-address.h b/src/address/identity-address.h index 5587bb0c1..2d131623e 100644 --- a/src/address/identity-address.h +++ b/src/address/identity-address.h @@ -32,8 +32,8 @@ class IdentityAddressPrivate; class LINPHONE_PUBLIC IdentityAddress : public ClonableObject { public: explicit IdentityAddress (const std::string &address = ""); + IdentityAddress (const Address &address); IdentityAddress (const IdentityAddress &src); - IdentityAddress (const Address &src); ~IdentityAddress () = default; IdentityAddress &operator= (const IdentityAddress &src); diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index f2a0da4b5..5f81c0f7b 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -230,7 +230,9 @@ LinphoneChatRoomState linphone_chat_room_get_state (const LinphoneChatRoom *cr) } void linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr) { - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->addParticipant(*L_GET_CPP_PTR_FROM_C_OBJECT(addr), nullptr, false); + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->addParticipant( + LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr)), nullptr, false + ); } void linphone_chat_room_add_participants (LinphoneChatRoom *cr, const bctbx_list_t *addresses) { @@ -246,14 +248,16 @@ bool_t linphone_chat_room_can_handle_participants (const LinphoneChatRoom *cr) { } LinphoneParticipant *linphone_chat_room_find_participant (const LinphoneChatRoom *cr, const LinphoneAddress *addr) { - return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(*L_GET_CPP_PTR_FROM_C_OBJECT(addr))); + return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant( + LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr)) + )); } const LinphoneAddress *linphone_chat_room_get_conference_address (const LinphoneChatRoom *cr) { if (cr->conferenceAddressCache) linphone_address_unref(cr->conferenceAddressCache); - const LinphonePrivate::Address &address = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getConferenceAddress(); + const LinphonePrivate::IdentityAddress &address = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getConferenceAddress(); if (address.isValid()) cr->conferenceAddressCache = linphone_address_new(address.asString().c_str()); else @@ -356,7 +360,7 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, cons from = L_GET_CPP_PTR_FROM_C_OBJECT(linphone_proxy_config_get_identity_address(proxy))->asString(); if (from.empty()) from = linphone_core_get_primary_contact(core); - LinphonePrivate::Address me(from); + LinphonePrivate::IdentityAddress me(from); LinphoneChatRoom *cr = L_INIT(ChatRoom); L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared( core->cppCore, L_C_TO_STRING(uri), me, L_C_TO_STRING(subject)) diff --git a/src/c-wrapper/api/c-participant.cpp b/src/c-wrapper/api/c-participant.cpp index 783c92ca3..af6fc1815 100644 --- a/src/c-wrapper/api/c-participant.cpp +++ b/src/c-wrapper/api/c-participant.cpp @@ -48,7 +48,7 @@ void linphone_participant_set_user_data(LinphoneParticipant *participant, void * } const LinphoneAddress *linphone_participant_get_address (const LinphoneParticipant *participant) { - LinphonePrivate::Address addr = L_GET_CPP_PTR_FROM_C_OBJECT(participant)->getAddress(); + LinphonePrivate::Address addr(L_GET_CPP_PTR_FROM_C_OBJECT(participant)->getAddress()); if (participant->addressCache) linphone_address_unref(participant->addressCache); participant->addressCache = linphone_address_new(addr.asString().c_str()); diff --git a/src/content/content.cpp b/src/content/content.cpp index 359d70fb4..1033332f9 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -49,14 +49,14 @@ Content::Content (Content &&src) : ClonableObject(*new ContentPrivate), AppDataC d->contentDisposition = move(src.getPrivate()->contentDisposition); } -Content::Content (ContentPrivate &p) : ClonableObject(p) { - -} +Content::Content (ContentPrivate &p) : ClonableObject(p) {} Content::~Content () { L_D(); - /* Fills the body with zeros before releasing since it may contain - private data like cipher keys or decoded messages. */ + /* + * Fills the body with zeros before releasing since it may contain + * private data like cipher keys or decoded messages. + */ d->body.assign(d->body.size(), 0); } diff --git a/src/core/core.cpp b/src/core/core.cpp index 4e294ec3f..3f68e32d9 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -42,7 +42,7 @@ shared_ptr Core::create (LinphoneCore *cCore) { // Do not use `make_shared` => Private constructor. shared_ptr core = shared_ptr(new Core); - CorePrivate * const d = core->getPrivate(); + CorePrivate *const d = core->getPrivate(); d->cCore = cCore; d->mainDb.reset(new MainDb(core->getSharedFromThis())); diff --git a/src/core/platform-helpers/platform-helpers.h b/src/core/platform-helpers/platform-helpers.h index 25bd23852..e41bf9fae 100644 --- a/src/core/platform-helpers/platform-helpers.h +++ b/src/core/platform-helpers/platform-helpers.h @@ -50,14 +50,14 @@ public: virtual std::string getConfigPath () = 0; protected: - inline PlatformHelpers (LinphoneCore *lc) : mCore(lc) {} + inline explicit PlatformHelpers (LinphoneCore *lc) : mCore(lc) {} LinphoneCore *mCore; }; class StubbedPlatformHelpers : public PlatformHelpers { public: - StubbedPlatformHelpers (LinphoneCore *lc); + explicit StubbedPlatformHelpers (LinphoneCore *lc); virtual ~StubbedPlatformHelpers () = default; void setDnsServers () override; From bb9cf6a74fc99bbdf61349821170f8ec7a39c1f5 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 22 Nov 2017 14:02:35 +0100 Subject: [PATCH 0825/2215] Reworked iscomposing addresses cache --- include/linphone/api/c-chat-room.h | 2 +- src/c-wrapper/api/c-chat-room.cpp | 9 ++------- src/chat/chat-room/chat-room-p.h | 2 +- src/chat/chat-room/chat-room.cpp | 16 +++++++++++----- src/chat/chat-room/chat-room.h | 1 + .../chat-room/real-time-text-chat-room.cpp | 2 +- tester/message_tester.c | 19 +++++++++++++++---- 7 files changed, 32 insertions(+), 19 deletions(-) diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index 244afe477..7d05bdcee 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -364,7 +364,7 @@ LINPHONE_PUBLIC void linphone_chat_room_set_subject (LinphoneChatRoom *cr, const * @param[in] cr A LinphoneChatRoom object * @return \bctbx_list{LinphoneAddress} list of addresses that are in the is_composing state */ -LINPHONE_PUBLIC bctbx_list_t * linphone_chat_room_get_composing_addresses(LinphoneChatRoom *cr); +LINPHONE_PUBLIC const bctbx_list_t * linphone_chat_room_get_composing_addresses(LinphoneChatRoom *cr); /** * Set the conference address of a group chat room. This function needs to be called from the diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 5f81c0f7b..d8185943b 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -302,13 +302,8 @@ void linphone_chat_room_set_subject (LinphoneChatRoom *cr, const char *subject) L_GET_CPP_PTR_FROM_C_OBJECT(cr)->setSubject(L_C_TO_STRING(subject)); } -bctbx_list_t * linphone_chat_room_get_composing_addresses(LinphoneChatRoom *cr) { - LinphonePrivate::ChatRoomPrivate *room = L_GET_PRIVATE_FROM_C_OBJECT(cr); - bctbx_list_t *result = NULL; - for (const auto &uri : room->remoteIsComposing) { - result = bctbx_list_append(result, linphone_address_new(uri.c_str())); - } - return result; +const bctbx_list_t * linphone_chat_room_get_composing_addresses(LinphoneChatRoom *cr) { + return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getComposingAddresses()); } LinphoneChatMessage *linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent *initial_content) { diff --git a/src/chat/chat-room/chat-room-p.h b/src/chat/chat-room/chat-room-p.h index 1a06de91d..9fafcb6f5 100644 --- a/src/chat/chat-room/chat-room-p.h +++ b/src/chat/chat-room/chat-room-p.h @@ -83,7 +83,7 @@ public: LinphoneCall *call = nullptr; ChatRoom::State state = ChatRoom::State::None; bool isComposing = false; - std::unordered_set remoteIsComposing; + std::list
      remoteIsComposing; std::list> transientMessages; std::list> weakMessages; diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 0d5bbea64..2135002cb 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -319,7 +319,6 @@ void ChatRoomPrivate::chatMessageReceived (const shared_ptr &msg) { notifyChatMessageReceived(msg); const string fromAddress = msg->getFromAddress().asString(); - remoteIsComposing.erase(fromAddress); isComposingHandler->stopRemoteRefreshTimer(fromAddress); notifyIsComposingReceived(msg->getFromAddress(), false); msg->sendDeliveryNotification(LinphoneReasonNone); @@ -360,6 +359,12 @@ void ChatRoomPrivate::notifyChatMessageReceived (const shared_ptr & void ChatRoomPrivate::notifyIsComposingReceived (const Address &remoteAddr, bool isComposing) { L_Q(); + + if (isComposing) + remoteIsComposing.push_back(remoteAddr); + else + remoteIsComposing.remove(remoteAddr); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsIsComposingReceivedCb cb = linphone_chat_room_cbs_get_is_composing_received(cbs); @@ -399,10 +404,6 @@ void ChatRoomPrivate::onIsComposingStateChanged (bool isComposing) { } void ChatRoomPrivate::onIsRemoteComposingStateChanged (const Address &remoteAddr, bool isComposing) { - if (isComposing) - remoteIsComposing.insert(remoteAddr.asStringUriOnly()); - else - remoteIsComposing.erase(remoteAddr.asStringUriOnly()); notifyIsComposingReceived(remoteAddr, isComposing); } @@ -505,6 +506,11 @@ bool ChatRoom::isRemoteComposing () const { return d->remoteIsComposing.size() > 0; } +std::list
      ChatRoom::getComposingAddresses () const { + L_D(); + return d->remoteIsComposing; +} + void ChatRoom::markAsRead () { L_D(); diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index e98af035a..f6c671b3f 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -72,6 +72,7 @@ public: std::list> getHistoryRange (int startm, int endm); int getUnreadChatMessagesCount (); bool isRemoteComposing () const; + std::list
      getComposingAddresses () const; virtual void markAsRead (); diff --git a/src/chat/chat-room/real-time-text-chat-room.cpp b/src/chat/chat-room/real-time-text-chat-room.cpp index d4ed5ee45..6242b51b1 100644 --- a/src/chat/chat-room/real-time-text-chat-room.cpp +++ b/src/chat/chat-room/real-time-text-chat-room.cpp @@ -58,7 +58,7 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp cmc->has_been_read = FALSE; receivedRttCharacters.push_back(cmc); - remoteIsComposing.insert(q->getPeerAddress().asString()); + remoteIsComposing.push_back(q->getPeerAddress()); linphone_core_notify_is_composing_received(cCore, L_GET_C_BACK_PTR(q)); if ((character == new_line) || (character == crlf) || (character == lf)) { diff --git a/tester/message_tester.c b/tester/message_tester.c index f9754608a..34909e35f 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -942,8 +942,10 @@ static int enable_lime_for_message_test(LinphoneCoreManager *marie, LinphoneCore } static void _is_composing_notification(bool_t lime_enabled) { - LinphoneChatRoom* chat_room; + LinphoneChatRoom* pauline_chat_room; + LinphoneChatRoom* marie_chat_room; int dummy = 0; + const bctbx_list_t *composing_addresses = NULL; LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); @@ -952,13 +954,22 @@ static void _is_composing_notification(bool_t lime_enabled) { if (enable_lime_for_message_test(marie, pauline) < 0) goto end; } - chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + pauline_chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + marie_chat_room = linphone_core_get_chat_room(marie->lc, pauline->identity); linphone_core_get_chat_room(marie->lc, pauline->identity); /*make marie create the chatroom with pauline, which is necessary for receiving the is-composing*/ - linphone_chat_room_compose(chat_room); + linphone_chat_room_compose(pauline_chat_room); wait_for_until(pauline->lc, marie->lc, &dummy, 1, 1500); /*just to sleep while iterating*/ - linphone_chat_room_send_message(chat_room, "Composing a msg"); + linphone_chat_room_send_message(pauline_chat_room, "Composing a msg"); BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneIsComposingActiveReceived, 1)); + composing_addresses = linphone_chat_room_get_composing_addresses(marie_chat_room); + BC_ASSERT_GREATER(bctbx_list_size(composing_addresses), 0, int, "%i"); + if (bctbx_list_size(composing_addresses) > 0) { + LinphoneAddress *addr = (LinphoneAddress *)bctbx_list_get_data(composing_addresses); + BC_ASSERT_STRING_EQUAL(linphone_address_as_string(addr), linphone_address_as_string(pauline->identity)); + } BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneIsComposingIdleReceived, 2)); + composing_addresses = linphone_chat_room_get_composing_addresses(marie_chat_room); + BC_ASSERT_EQUAL(bctbx_list_size(composing_addresses), 0, int, "%i"); end: linphone_core_manager_destroy(marie); From f661520d27b02cdce424007dd402934c0f36a7f3 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 22 Nov 2017 14:30:03 +0100 Subject: [PATCH 0826/2215] Improved test --- tester/message_tester.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tester/message_tester.c b/tester/message_tester.c index 34909e35f..77242f3ef 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -1013,15 +1013,16 @@ static void _imdn_notifications(bool_t with_lime) { marie_chat_room = linphone_core_get_chat_room(marie->lc, pauline->identity); history = linphone_chat_room_get_history(marie_chat_room, 1); BC_ASSERT_EQUAL((int)bctbx_list_size(history), 1, int, "%d"); - received_cm = (LinphoneChatMessage *)bctbx_list_nth_data(history, 0); - BC_ASSERT_PTR_NOT_NULL(received_cm); - if (received_cm != NULL) { - BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneMessageDeliveredToUser, 1)); - linphone_chat_room_mark_as_read(marie_chat_room); /* This sends the display notification */ - BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneMessageDisplayed, 1)); - bctbx_list_free_with_data(history, (bctbx_list_free_func)linphone_chat_message_unref); + if (bctbx_list_size(history) > 0) { + received_cm = (LinphoneChatMessage *)bctbx_list_nth_data(history, 0); + BC_ASSERT_PTR_NOT_NULL(received_cm); + if (received_cm != NULL) { + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneMessageDeliveredToUser, 1)); + linphone_chat_room_mark_as_read(marie_chat_room); /* This sends the display notification */ + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneMessageDisplayed, 1)); + bctbx_list_free_with_data(history, (bctbx_list_free_func)linphone_chat_message_unref); + } } - linphone_chat_message_unref(sent_cm); end: From ec2ffd8a143fe8c6b98e9d74063c1260484743ab Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 22 Nov 2017 15:20:08 +0100 Subject: [PATCH 0827/2215] Added a proguard file generation to the Java wrapper (todo: test it) --- wrappers/java/genwrapper.py | 16 ++++++++++++++++ wrappers/java/proguard.mustache | 17 +++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 wrappers/java/proguard.mustache diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 1299fa367..45399eba2 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -760,6 +760,19 @@ class Jni(object): for method in methods: self.methods.append(method) +class Proguard(object): + def __init__(self, package): + self.package = package + self.classes = [] + + def add_class(self, javaClass): + obj = { + 'package': self.package, + 'className': javaClass.className, + 'classImplName': javaClass.classImplName, + } + self.classes.append(obj) + ########################################################################## class GenWrapper(object): @@ -790,6 +803,7 @@ class GenWrapper(object): self.translator = JavaTranslator(package, exceptions) self.renderer = pystache.Renderer() self.jni = Jni(package) + self.proguard = Proguard(package) self.enums = {} self.interfaces = {} @@ -823,8 +837,10 @@ class GenWrapper(object): for name, value in self.classes.items(): self.render(value, self.javadir + '/' + value.filename) self.jni.add_object(value) + self.proguard.add_class(value) self.render(self.jni, self.srcdir + '/linphone_jni.cc') + self.render(self.proguard, self.srcdir + '/proguard.txt') def render(self, item, path): tmppath = path + '.tmp' diff --git a/wrappers/java/proguard.mustache b/wrappers/java/proguard.mustache new file mode 100644 index 000000000..6bb199a26 --- /dev/null +++ b/wrappers/java/proguard.mustache @@ -0,0 +1,17 @@ +# Don't warn stuff that we are not "proguarding", warnings would make the build fail. +-dontwarn org.linphone.** + +# The following intefaces are referenced from JNI +{{#classes}} +-keep interface {{package}}.{{className}} {*;} +-keep class {{package}}.{{classImplName}} {*;} +{{/classes}} + +# Mediastreamer classes +-keep class org.linphone.mediastream.Factory {*;} +-keep class org.linphone.mediastream.MediastreamerAndroidContext {*;} +-keep class org.linphone.mediastream.video.capture.AndroidVideoApi9JniWrapper {*;} +-keep class org.linphone.mediastream.video.capture.AndroidVideoApi8JniWrapper {*;} +-keep class org.linphone.mediastream.video.capture.AndroidVideoApi5JniWrapper {*;} +-keep class org.linphone.mediastream.video.AndroidVideoWindowImpl {*;} +-keep class org.linphone.mediastream.Version {*;} From 90b653f60fb1933b4d57819fb7af7b0c85b142b3 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 22 Nov 2017 15:26:10 +0100 Subject: [PATCH 0828/2215] fix(chat-room): hide public onChatMessageReceived handler! --- src/c-wrapper/api/c-chat-message.cpp | 7 +++---- src/chat/chat-message/chat-message.cpp | 6 +++--- src/chat/chat-room/basic-chat-room-p.h | 2 ++ src/chat/chat-room/basic-chat-room.cpp | 9 ++++++--- src/chat/chat-room/basic-chat-room.h | 3 --- src/chat/chat-room/chat-room-p.h | 2 ++ src/chat/chat-room/chat-room.cpp | 2 +- src/chat/chat-room/chat-room.h | 2 -- src/chat/chat-room/client-group-chat-room-p.h | 2 ++ src/chat/chat-room/client-group-chat-room.cpp | 4 ++-- src/chat/chat-room/client-group-chat-room.h | 2 -- src/chat/chat-room/server-group-chat-room-p.h | 2 ++ .../chat-room/server-group-chat-room-stub.cpp | 4 ++-- src/chat/chat-room/server-group-chat-room.h | 1 - src/content/content.cpp | 2 -- src/content/content.h | 5 ++--- src/content/file-content.cpp | 15 ++++++-------- src/content/file-content.h | 20 +++++++++---------- src/core/core.cpp | 8 ++++++-- src/core/core.h | 14 ++++++------- 20 files changed, 56 insertions(+), 56 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 6482a9d91..c04cee0d6 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -292,11 +292,10 @@ bool_t linphone_chat_message_has_text_content(const LinphoneChatMessage *msg) { return L_GET_PRIVATE_FROM_C_OBJECT(msg)->hasTextContent(); } -const char * linphone_chat_message_get_text_content(const LinphoneChatMessage *msg) { +const char *linphone_chat_message_get_text_content(const LinphoneChatMessage *msg) { const LinphonePrivate::Content *content = L_GET_PRIVATE_FROM_C_OBJECT(msg)->getTextContent(); - if (*content == LinphonePrivate::Content::Empty) { - return NULL; - } + if (content->isEmpty()) + return nullptr; return L_STRING_TO_C(content->getBodyAsString()); } diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 137a684e6..220602ff8 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -159,7 +159,7 @@ const Content* ChatMessagePrivate::getTextContent() const { return c; } } - return &Content::Empty; + return &Utils::getEmptyConstRefObject(); } bool ChatMessagePrivate::hasFileTransferContent() const { @@ -177,7 +177,7 @@ const Content* ChatMessagePrivate::getFileTransferContent() const { return c; } } - return &Content::Empty; + return &Utils::getEmptyConstRefObject(); } const string &ChatMessagePrivate::getFileTransferFilepath () const { @@ -414,7 +414,7 @@ void ChatMessagePrivate::sendImdn (Imdn::Type imdnType, LinphoneReason reason) { L_Q(); shared_ptr msg = q->getChatRoom()->createMessage(); - + Content *content = new Content(); content->setContentType("message/imdn+xml"); content->setBody(createImdnXml(imdnType, reason)); diff --git a/src/chat/chat-room/basic-chat-room-p.h b/src/chat/chat-room/basic-chat-room-p.h index a6103d172..2429431bf 100644 --- a/src/chat/chat-room/basic-chat-room-p.h +++ b/src/chat/chat-room/basic-chat-room-p.h @@ -32,6 +32,8 @@ public: BasicChatRoomPrivate () = default; private: + void onChatMessageReceived (const std::shared_ptr &chatMessage) override; + std::string subject; L_DECLARE_PUBLIC(BasicChatRoom); diff --git a/src/chat/chat-room/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp index 42bfa4459..7b580914c 100644 --- a/src/chat/chat-room/basic-chat-room.cpp +++ b/src/chat/chat-room/basic-chat-room.cpp @@ -29,6 +29,12 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +// ----------------------------------------------------------------------------- + +void BasicChatRoomPrivate::onChatMessageReceived (const shared_ptr &) {} + +// ----------------------------------------------------------------------------- + BasicChatRoom::BasicChatRoom (const shared_ptr &core, const ChatRoomId &chatRoomId) : ChatRoom(*new BasicChatRoomPrivate, core, chatRoomId) {} @@ -107,7 +113,4 @@ void BasicChatRoom::leave () { lError() << "leave() is not allowed on a BasicChatRoom"; } -// TODO: Move me in BasicChatRoomPrivate. -void BasicChatRoom::onChatMessageReceived (const shared_ptr &) {} - LINPHONE_END_NAMESPACE diff --git a/src/chat/chat-room/basic-chat-room.h b/src/chat/chat-room/basic-chat-room.h index a234eee30..283a2ad80 100644 --- a/src/chat/chat-room/basic-chat-room.h +++ b/src/chat/chat-room/basic-chat-room.h @@ -64,9 +64,6 @@ protected: private: BasicChatRoom (const std::shared_ptr &core, const ChatRoomId &chatRoomId); - // TODO: Remove me. Move me in private object. - void onChatMessageReceived (const std::shared_ptr &msg) override; - L_DECLARE_PRIVATE(BasicChatRoom); L_DISABLE_COPY(BasicChatRoom); }; diff --git a/src/chat/chat-room/chat-room-p.h b/src/chat/chat-room/chat-room-p.h index 9fafcb6f5..a4fd64b20 100644 --- a/src/chat/chat-room/chat-room-p.h +++ b/src/chat/chat-room/chat-room-p.h @@ -97,6 +97,8 @@ public: // TODO: Check all fields before this point. public: + virtual void onChatMessageReceived (const std::shared_ptr &chatMessage) = 0; + ChatRoomId chatRoomId; time_t creationTime = -1; diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 2135002cb..652c30d83 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -306,7 +306,7 @@ void ChatRoomPrivate::chatMessageReceived (const shared_ptr &msg) { L_Q(); if ((msg->getPrivate()->getContentType() != ContentType::Imdn) && (msg->getPrivate()->getContentType() != ContentType::ImIsComposing)) { - q->onChatMessageReceived(msg); + onChatMessageReceived(msg); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index f6c671b3f..b7e557353 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -81,8 +81,6 @@ public: protected: explicit ChatRoom (ChatRoomPrivate &p, const std::shared_ptr &core, const ChatRoomId &chatRoomId); - virtual void onChatMessageReceived (const std::shared_ptr &msg) = 0; - private: L_DECLARE_PRIVATE(ChatRoom); L_DISABLE_COPY(ChatRoom); diff --git a/src/chat/chat-room/client-group-chat-room-p.h b/src/chat/chat-room/client-group-chat-room-p.h index 82366fef3..f261c191b 100644 --- a/src/chat/chat-room/client-group-chat-room-p.h +++ b/src/chat/chat-room/client-group-chat-room-p.h @@ -37,6 +37,8 @@ public: void multipartNotifyReceived (const std::string &body); private: + void onChatMessageReceived (const std::shared_ptr &chatMessage) override; + L_DECLARE_PUBLIC(ClientGroupChatRoom); }; diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 996ece990..501beb279 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -79,6 +79,8 @@ void ClientGroupChatRoomPrivate::multipartNotifyReceived (const string &body) { qConference->getPrivate()->eventHandler->multipartNotifyReceived(body); } +void ClientGroupChatRoomPrivate::onChatMessageReceived (const shared_ptr &) {} + // ============================================================================= ClientGroupChatRoom::ClientGroupChatRoom ( @@ -262,8 +264,6 @@ void ClientGroupChatRoom::leave () { // ----------------------------------------------------------------------------- -void ClientGroupChatRoom::onChatMessageReceived (const shared_ptr &msg) {} - void ClientGroupChatRoom::onConferenceCreated (const IdentityAddress &addr) { L_D(); L_D_T(RemoteConference, dConference); diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 0702f59c9..8efa00801 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -71,8 +71,6 @@ private: // TODO: Move me in ClientGroupChatRoomPrivate. // ALL METHODS AFTER THIS POINT. - void onChatMessageReceived (const std::shared_ptr &msg) override; - void onConferenceCreated (const IdentityAddress &addr) override; void onConferenceTerminated (const IdentityAddress &addr) override; void onFirstNotifyReceived (const IdentityAddress &addr) override; diff --git a/src/chat/chat-room/server-group-chat-room-p.h b/src/chat/chat-room/server-group-chat-room-p.h index b2a945e0d..2b003fdac 100644 --- a/src/chat/chat-room/server-group-chat-room-p.h +++ b/src/chat/chat-room/server-group-chat-room-p.h @@ -56,6 +56,8 @@ private: void finalizeCreation (); bool isAdminLeft () const; + void onChatMessageReceived (const std::shared_ptr &) override; + std::list> removedParticipants; L_DECLARE_PUBLIC(ServerGroupChatRoom); diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index 6ad6d6d73..1a3999e9f 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -75,6 +75,8 @@ bool ServerGroupChatRoomPrivate::isAdminLeft () const { return false; } +void ServerGroupChatRoomPrivate::onChatMessageReceived(const shared_ptr &) {} + // ============================================================================= ServerGroupChatRoom::ServerGroupChatRoom (const shared_ptr &core, SalCallOp *op) : @@ -131,8 +133,6 @@ void ServerGroupChatRoom::leave () {} // ----------------------------------------------------------------------------- -void ServerGroupChatRoom::onChatMessageReceived(const shared_ptr &msg) {} - void ServerGroupChatRoom::onCallSessionStateChanged ( const shared_ptr &, LinphoneCallState, diff --git a/src/chat/chat-room/server-group-chat-room.h b/src/chat/chat-room/server-group-chat-room.h index c93e593de..73d0295de 100644 --- a/src/chat/chat-room/server-group-chat-room.h +++ b/src/chat/chat-room/server-group-chat-room.h @@ -67,7 +67,6 @@ public: private: // TODO: Move me in ServerGroupChatRoomPrivate. - void onChatMessageReceived (const std::shared_ptr &msg) override; void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) override; L_DECLARE_PRIVATE(ServerGroupChatRoom); diff --git a/src/content/content.cpp b/src/content/content.cpp index 1033332f9..0bd2554d0 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -29,8 +29,6 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -const Content Content::Empty; - // ----------------------------------------------------------------------------- Content::Content () : ClonableObject(*new ContentPrivate) {} diff --git a/src/content/content.h b/src/content/content.h index d51c51e7e..762b2fd01 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -67,9 +67,8 @@ public: bool isEmpty () const; - virtual LinphoneContent * toLinphoneContent() const; - - static const Content Empty; + // TODO: Remove me later. + virtual LinphoneContent *toLinphoneContent() const; protected: explicit Content (ContentPrivate &p); diff --git a/src/content/file-content.cpp b/src/content/file-content.cpp index 8bb303e09..ecf445dbd 100644 --- a/src/content/file-content.cpp +++ b/src/content/file-content.cpp @@ -36,9 +36,7 @@ public: // ----------------------------------------------------------------------------- -FileContent::FileContent() : Content(*new FileContentPrivate()) { - -} +FileContent::FileContent() : Content(*new FileContentPrivate()) {} FileContent::FileContent (const FileContent &src) : Content(*new FileContentPrivate) { L_D(); @@ -102,20 +100,19 @@ const string& FileContent::getFileName() const { L_D(); return d->fileName; } - -void FileContent::setFilePath(const string &path) { + +void FileContent::setFilePath (const string &path) { L_D(); d->filePath = path; } -const string& FileContent::getFilePath() const { +const string& FileContent::getFilePath () const { L_D(); return d->filePath; } -LinphoneContent * FileContent::toLinphoneContent() const { - LinphoneContent* content; - content = linphone_core_create_content(NULL); +LinphoneContent *FileContent::toLinphoneContent() const { + LinphoneContent *content = linphone_core_create_content(nullptr); linphone_content_set_type(content, getContentType().getType().c_str()); linphone_content_set_subtype(content, getContentType().getSubType().c_str()); linphone_content_set_name(content, getFileName().c_str()); diff --git a/src/content/file-content.h b/src/content/file-content.h index 15aa279e1..9aefb0552 100644 --- a/src/content/file-content.h +++ b/src/content/file-content.h @@ -30,7 +30,7 @@ class FileContentPrivate; class LINPHONE_PUBLIC FileContent : public Content { public: - FileContent(); + FileContent (); FileContent (const FileContent &src); FileContent (FileContent &&src); @@ -38,16 +38,16 @@ public: FileContent &operator= (FileContent &&src); bool operator== (const FileContent &content) const; - void setFileSize(size_t size); - size_t getFileSize() const; - - void setFileName(const std::string &name); - const std::string& getFileName() const; - - void setFilePath(const std::string &path); - const std::string& getFilePath() const; + void setFileSize (size_t size); + size_t getFileSize () const; - LinphoneContent * toLinphoneContent() const override; + void setFileName (const std::string &name); + const std::string &getFileName() const; + + void setFilePath (const std::string &path); + const std::string &getFilePath() const; + + LinphoneContent *toLinphoneContent() const override; private: L_DECLARE_PRIVATE(FileContent); diff --git a/src/core/core.cpp b/src/core/core.cpp index 3f68e32d9..906b135d7 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -24,10 +24,10 @@ // TODO: Remove me later. #include "c-wrapper/c-wrapper.h" -// ============================================================================= - #define LINPHONE_DB "linphone.db" +// ============================================================================= + using namespace std; LINPHONE_BEGIN_NAMESPACE @@ -73,6 +73,10 @@ LinphoneCore *Core::getCCore () const { return d->cCore; } +// ----------------------------------------------------------------------------- +// Paths. +// ----------------------------------------------------------------------------- + string Core::getDataPath() const { L_D(); return Paths::getPath(Paths::Data, static_cast(d->cCore->platform_helper)); diff --git a/src/core/core.h b/src/core/core.h index 35514f5e0..2558e49bc 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -58,13 +58,6 @@ public: // TODO: Remove me later. LinphoneCore *getCCore () const; - // --------------------------------------------------------------------------- - // Paths. - // --------------------------------------------------------------------------- - - std::string getDataPath() const; - std::string getConfigPath() const; - // --------------------------------------------------------------------------- // ChatRoom. // --------------------------------------------------------------------------- @@ -84,6 +77,13 @@ public: static void deleteChatRoom (const std::shared_ptr &chatRoom); + // --------------------------------------------------------------------------- + // Paths. + // --------------------------------------------------------------------------- + + std::string getDataPath() const; + std::string getConfigPath() const; + private: Core (); From 6999d35423cd9be86a48e8ea078000c5d6913722 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 22 Nov 2017 16:43:12 +0100 Subject: [PATCH 0829/2215] Add friend class. --- src/core/core.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/core.h b/src/core/core.h index 2558e49bc..283615bb8 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -42,6 +42,7 @@ class LINPHONE_PUBLIC Core : public Object { friend class LocalConferenceEventHandlerPrivate; friend class MainDb; friend class MainDbEventKey; + friend class ServerGroupChatRoomPrivate; public: L_OVERRIDE_SHARED_FROM_THIS(Core); From ef26482305899765fdf8044dad4baeffeb66b26b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 22 Nov 2017 16:44:51 +0100 Subject: [PATCH 0830/2215] Do not remove gr parameter from the address put in a To header. --- coreapi/linphonecore.c | 14 +------------- src/sal/op.cpp | 1 - 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index e1ea4e478..88c8b1bc9 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3564,19 +3564,7 @@ void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const Linphon linphone_transfer_routes_to_op(routes,op); } - const SalAddress *sal_dest = L_GET_PRIVATE_FROM_C_OBJECT(dest)->getInternalAddress(); - if (sal_address_has_uri_param(sal_dest,"gr")) { - /*in case of gruu destination remove gruu parram from to*/ - SalAddress *dest_copy = sal_address_clone(sal_dest); - sal_address_remove_uri_param(dest_copy,"gr"); - op->set_to_address(dest_copy); - sal_address_unref(dest_copy); - } else { - char *addr = linphone_address_as_string(dest); - op->set_to(addr); - ms_free(addr); - } - + op->set_to_address(L_GET_PRIVATE_FROM_C_OBJECT(dest)->getInternalAddress()); if (op->getUseGruuInFrom() && contactAddr && linphone_address_has_uri_param(contactAddr, "gr")) { char *contactAddrStr = linphone_address_as_string_uri_only(contactAddr); op->set_from(contactAddrStr); diff --git a/src/sal/op.cpp b/src/sal/op.cpp index 896aafd45..32398aa15 100644 --- a/src/sal/op.cpp +++ b/src/sal/op.cpp @@ -620,7 +620,6 @@ belle_sip_request_t* SalOp::build_request(const char* method) { belle_sip_uri_set_secure(req_uri,is_secure()); to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(to_address),NULL); - belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to_header))), "gr"); /*remove gruu in any case*/ call_id_header = belle_sip_provider_create_call_id(prov); if (get_call_id()) { belle_sip_header_call_id_set_call_id(call_id_header, get_call_id()); From 4eb6176daebb1846ffc1b7f3e1cb5f204d9bbe44 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 22 Nov 2017 16:45:23 +0100 Subject: [PATCH 0831/2215] Insertion of chat rooms in Core and DB is handled directly by ClientGroupChatRoom and ServerGroupChatRoom classes. --- coreapi/chat.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 670cd1b77..c5b5d1200 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -89,16 +89,11 @@ LinphoneChatRoom *linphone_core_create_client_group_chat_room (LinphoneCore *lc, LinphoneChatRoom *_linphone_core_join_client_group_chat_room (LinphoneCore *lc, const LinphonePrivate::Address &addr) { LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); - L_GET_PRIVATE(lc->cppCore)->insertChatRoom(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); - L_GET_PRIVATE(lc->cppCore)->insertChatRoomWithDb(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); return cr; } LinphoneChatRoom *_linphone_core_create_server_group_chat_room (LinphoneCore *lc, LinphonePrivate::SalCallOp *op) { - LinphoneChatRoom *cr = _linphone_server_group_chat_room_new(lc, op); - //L_GET_PRIVATE(lc->cppCore)->insertChatRoom(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); - //L_GET_PRIVATE(lc->cppCore)->insertChatRoomWithDb(L_GET_CPP_PTR_FROM_C_OBJECT(cr)); - return cr; + return _linphone_server_group_chat_room_new(lc, op); } void linphone_core_delete_chat_room (LinphoneCore *, LinphoneChatRoom *cr) { From faa6ef529c2bce7e30dbcf674dc2f3078fd824a2 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 22 Nov 2017 16:43:02 +0100 Subject: [PATCH 0832/2215] fix(content-manager): clean code, avoid leaks --- .../local-conference-event-handler.cpp | 4 +- .../remote-conference-event-handler.cpp | 6 +- src/content/content-manager.cpp | 85 ++++++++++--------- src/content/content-manager.h | 11 +-- src/content/content.h | 5 +- tester/content-manager-tester.cpp | 8 +- 6 files changed, 55 insertions(+), 64 deletions(-) diff --git a/src/conference/handlers/local-conference-event-handler.cpp b/src/conference/handlers/local-conference-event-handler.cpp index 6876e3d13..927245f9d 100644 --- a/src/conference/handlers/local-conference-event-handler.cpp +++ b/src/conference/handlers/local-conference-event-handler.cpp @@ -218,9 +218,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyMultipart (int notifyId) contents.push_back(content); } - ContentManager contentManager; - Content multipart = contentManager.contentsListToMultipart(contents); - return multipart.getBodyAsString(); + return ContentManager::contentListToMultipart(contents).getBodyAsString(); } string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const Address &addr, int notifyId) { diff --git a/src/conference/handlers/remote-conference-event-handler.cpp b/src/conference/handlers/remote-conference-event-handler.cpp index 2ce85abae..aadfd5d60 100644 --- a/src/conference/handlers/remote-conference-event-handler.cpp +++ b/src/conference/handlers/remote-conference-event-handler.cpp @@ -220,11 +220,9 @@ void RemoteConferenceEventHandler::multipartNotifyReceived (const string &xmlBod Content multipart; multipart.setBody(xmlBody); - ContentManager manager; - list contents = manager.multipartToContentLists(multipart); - for (const auto &content : contents) { + + for (const auto &content : ContentManager::multipartToContentList(multipart)) d->simpleNotifyReceived(content.getBodyAsString()); - } } // ----------------------------------------------------------------------------- diff --git a/src/content/content-manager.cpp b/src/content/content-manager.cpp index 79e515cb7..e65647124 100644 --- a/src/content/content-manager.cpp +++ b/src/content/content-manager.cpp @@ -17,89 +17,92 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include - -#include "belle-sip/belle-sip.h" +#include #include "content-manager.h" #include "content-type.h" -#include "linphone/content.h" -#include "logger/logger.h" - -// ============================================================================= +#include "content/content.h" #define MULTIPART_BOUNDARY "---------------------------14737809831466499882746641449" +// ============================================================================= + using namespace std; LINPHONE_BEGIN_NAMESPACE -list ContentManager::multipartToContentLists (const Content &content) const { - belle_sip_multipart_body_handler_t *mpbh = belle_sip_multipart_body_handler_new_from_buffer((void *)content.getBodyAsString().c_str(), content.getBodyAsString().length(), MULTIPART_BOUNDARY); +list ContentManager::multipartToContentList (const Content &content) { + belle_sip_multipart_body_handler_t *mpbh = belle_sip_multipart_body_handler_new_from_buffer( + (void *)content.getBodyAsString().c_str(), + content.getBodyAsString().length(), + MULTIPART_BOUNDARY + ); belle_sip_object_ref(mpbh); - const belle_sip_list_t *parts = belle_sip_multipart_body_handler_get_parts(mpbh); - list contentsList = list(); - while (parts) { + list contents; + for (const belle_sip_list_t *parts = belle_sip_multipart_body_handler_get_parts(mpbh); parts; parts = parts->next) { belle_sip_body_handler_t *part = BELLE_SIP_BODY_HANDLER(parts->data); const belle_sip_list_t *part_headers = belle_sip_body_handler_get_headers(part); - belle_sip_list_t *it; - belle_sip_header_content_type_t *part_content_type=NULL;; - for(it = (belle_sip_list_t *)part_headers;it!=NULL;it=it->next) { + belle_sip_header_content_type_t *part_content_type = nullptr; + for (belle_sip_list_t *it = (belle_sip_list_t *)part_headers; it; it = it->next) { belle_sip_header_t *header = BELLE_SIP_HEADER(it->data); - if(strcasecmp("Content-Type",belle_sip_header_get_name(header)) == 0) { - part_content_type=BELLE_SIP_HEADER_CONTENT_TYPE(header); + if (strcasecmp("Content-Type", belle_sip_header_get_name(header)) == 0) { + part_content_type = BELLE_SIP_HEADER_CONTENT_TYPE(header); break; } } - belle_sip_header_content_type_get_type(part_content_type); - belle_sip_memory_body_handler_get_buffer(BELLE_SIP_MEMORY_BODY_HANDLER(part)); - Content retContent = Content(); - ContentType type(belle_sip_header_content_type_get_type(part_content_type), belle_sip_header_content_type_get_subtype(part_content_type)); + + Content retContent; retContent.setBody((const char *)belle_sip_memory_body_handler_get_buffer(BELLE_SIP_MEMORY_BODY_HANDLER(part))); - retContent.setContentType(type); - contentsList.push_back(retContent); - parts = parts->next; + retContent.setContentType(ContentType( + belle_sip_header_content_type_get_type(part_content_type), + belle_sip_header_content_type_get_subtype(part_content_type) + )); + contents.push_back(retContent); } belle_sip_object_unref(mpbh); - return contentsList; + return contents; } -Content ContentManager::contentsListToMultipart (const list &contents) const { - char *desc; +Content ContentManager::contentListToMultipart (const list &contents) { string sub; - belle_sip_memory_body_handler_t *mbh = NULL; - belle_sip_multipart_body_handler_t *mpbh = belle_sip_multipart_body_handler_new(NULL, NULL, NULL, MULTIPART_BOUNDARY); + + belle_sip_memory_body_handler_t *mbh = nullptr; + belle_sip_multipart_body_handler_t *mpbh = belle_sip_multipart_body_handler_new( + nullptr, nullptr, nullptr, MULTIPART_BOUNDARY + ); belle_sip_object_ref(mpbh); + for (const auto &content : contents) { const ContentType &contentType = content.getContentType(); stringstream subtype; sub = contentType.getSubType(); subtype << sub << "; charset=\"UTF-8\""; - belle_sip_header_t *content_type = BELLE_SIP_HEADER( + belle_sip_header_t *cContentType = BELLE_SIP_HEADER( belle_sip_header_content_type_create( contentType.getType().c_str(), subtype.str().c_str() ) ); + + string body = content.getBodyAsString(); mbh = belle_sip_memory_body_handler_new_copy_from_buffer( - (void *)content.getBodyAsString().c_str(), - content.getBodyAsString().length(), - NULL, - NULL + (void *)body.c_str(), body.length(), nullptr, nullptr ); - belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(mbh), content_type); + belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(mbh), cContentType); belle_sip_multipart_body_handler_add_part(mpbh, BELLE_SIP_BODY_HANDLER(mbh)); } - desc = belle_sip_object_to_string(mpbh); + char *desc = belle_sip_object_to_string(mpbh); + + Content content; + content.setBody(desc); + content.setContentType(ContentType("application", sub)); + + belle_sip_free(desc); belle_sip_object_unref(mpbh); - Content retContent = Content(); - ContentType type("application", sub); - retContent.setBody(desc); - retContent.setContentType(type); - return retContent; + return content; } LINPHONE_END_NAMESPACE diff --git a/src/content/content-manager.h b/src/content/content-manager.h index 8b15bb6a2..f91adc2ab 100644 --- a/src/content/content-manager.h +++ b/src/content/content-manager.h @@ -24,18 +24,15 @@ #include "linphone/utils/general.h" -#include "content.h" - // ============================================================================= LINPHONE_BEGIN_NAMESPACE -class ContentManager { -public: - ContentManager () = default; +class Content; - std::list multipartToContentLists (const Content &content) const; - Content contentsListToMultipart (const std::list &contents) const; +namespace ContentManager { + std::list multipartToContentList (const Content &content); + Content contentListToMultipart (const std::list &contents); }; LINPHONE_END_NAMESPACE diff --git a/src/content/content.h b/src/content/content.h index 762b2fd01..23aa0446a 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -22,14 +22,13 @@ #include -// TODO: Remove me. -#include "linphone/content.h" - #include "object/app-data-container.h" #include "object/clonable-object.h" // ============================================================================= +L_DECL_C_STRUCT(LinphoneContent); + LINPHONE_BEGIN_NAMESPACE class ContentType; diff --git a/tester/content-manager-tester.cpp b/tester/content-manager-tester.cpp index 05e4eb893..17cf4328d 100644 --- a/tester/content-manager-tester.cpp +++ b/tester/content-manager-tester.cpp @@ -160,13 +160,11 @@ static const char* part4 = \ ""; void multipart_to_list () { - ContentManager manager; - Content multipartContent; multipartContent.setBody(multipart); multipartContent.setContentType(ContentType("multipart", "related")); - list contents = manager.multipartToContentLists(multipartContent); + list contents = ContentManager::multipartToContentList(multipartContent); BC_ASSERT_EQUAL(contents.size(), 4, int, "%d"); Content content1 = contents.front(); contents.pop_front(); @@ -242,8 +240,6 @@ void multipart_to_list () { } void list_to_multipart () { - ContentManager manager; - Content content1; content1.setBody(part1); content1.setContentType(ContentType("application", "rlmi+xml")); @@ -258,7 +254,7 @@ void list_to_multipart () { content4.setContentType(ContentType("application", "pidf+xml")); list contents = {content1, content2, content3, content4}; - Content multipartContent = manager.contentsListToMultipart(contents); + Content multipartContent = ContentManager::contentListToMultipart(contents); string originalStr(multipart); originalStr.erase(std::remove(originalStr.begin(), originalStr.end(), ' '), originalStr.end()); originalStr.erase(std::remove(originalStr.begin(), originalStr.end(), '\t'), originalStr.end()); From 01694c2baca1d58ffb43bd7b82e740ab3c048e38 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 22 Nov 2017 16:57:10 +0100 Subject: [PATCH 0833/2215] feat(content): clean code --- src/content/content-manager.cpp | 2 ++ src/content/content-manager.h | 2 +- src/content/content-p.h | 7 +++--- src/content/content-type.cpp | 40 ++++++++++++++++----------------- src/content/content.cpp | 13 +++++------ src/content/content.h | 4 ++-- 6 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/content/content-manager.cpp b/src/content/content-manager.cpp index e65647124..afdcd6ff3 100644 --- a/src/content/content-manager.cpp +++ b/src/content/content-manager.cpp @@ -31,6 +31,8 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +// ----------------------------------------------------------------------------- + list ContentManager::multipartToContentList (const Content &content) { belle_sip_multipart_body_handler_t *mpbh = belle_sip_multipart_body_handler_new_from_buffer( (void *)content.getBodyAsString().c_str(), diff --git a/src/content/content-manager.h b/src/content/content-manager.h index f91adc2ab..a7b2b97b0 100644 --- a/src/content/content-manager.h +++ b/src/content/content-manager.h @@ -33,7 +33,7 @@ class Content; namespace ContentManager { std::list multipartToContentList (const Content &content); Content contentListToMultipart (const std::list &contents); -}; +} LINPHONE_END_NAMESPACE diff --git a/src/content/content-p.h b/src/content/content-p.h index b3045b429..c5685c297 100644 --- a/src/content/content-p.h +++ b/src/content/content-p.h @@ -22,20 +22,21 @@ #include -#include "object/clonable-object-p.h" -#include "object/object-p.h" #include "content-type.h" #include "content.h" +#include "object/clonable-object-p.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE class ContentPrivate : public ClonableObjectPrivate { -public: +private: std::vector body; ContentType contentType; std::string contentDisposition; + + L_DECLARE_PUBLIC(Content); }; LINPHONE_END_NAMESPACE diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index 4aeac8869..8c8d69859 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -19,9 +19,8 @@ #include "linphone/utils/utils.h" -#include "object/clonable-object-p.h" -#include "logger/logger.h" #include "content-type.h" +#include "object/clonable-object-p.h" // ============================================================================= @@ -29,6 +28,8 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +// ----------------------------------------------------------------------------- + class ContentTypePrivate : public ClonableObjectPrivate { public: string type; @@ -60,34 +61,32 @@ ContentType::ContentType (const string &contentType) : ClonableObject(*new Conte return; if (setType(contentType.substr(0, pos))) { - if (posParam != string::npos) { + if (posParam != string::npos) end = posParam; - } if (!setSubType(contentType.substr(pos + 1, end - (pos + 1)))) d->type.clear(); } - if (posParam != string::npos) { - setParameter(contentType.substr(posParam + 2)); // We remove the blankspace after the ; - } + if (posParam != string::npos) + setParameter(contentType.substr(posParam + 2)); // We remove the blankspace after the ;. } ContentType::ContentType (const string &type, const string &subType) : ClonableObject(*new ContentTypePrivate) { L_D(); - if (setType(type)) { - if (!setSubType(subType)) - d->type.clear(); - } + if (setType(type) && !setSubType(subType)) + d->type.clear(); } -ContentType::ContentType (const string &type, const string &subType, const string ¶meter) : ClonableObject(*new ContentTypePrivate) { +ContentType::ContentType ( + const string &type, + const string &subType, + const string ¶meter +) : ClonableObject(*new ContentTypePrivate) { L_D(); - if (setType(type)) { - if (!setSubType(subType)) - d->type.clear(); - } + if (setType(type) && !setSubType(subType)) + d->type.clear(); setParameter(parameter); } @@ -104,11 +103,13 @@ ContentType &ContentType::operator= (const ContentType &src) { } bool ContentType::operator== (const ContentType &contentType) const { - return getType() == contentType.getType() && getSubType() == contentType.getSubType() && getParameter() == contentType.getParameter(); + return getType() == contentType.getType() && + getSubType() == contentType.getSubType() && + getParameter() == contentType.getParameter(); } bool ContentType::operator!= (const ContentType &contentType) const { - return !operator==(contentType); + return !(*this == contentType); } const string &ContentType::getType () const { @@ -162,9 +163,8 @@ string ContentType::asString () const { L_D(); if (isValid()) { string asString = d->type + "/" + d->subType; - if (!d->parameter.empty()) { + if (!d->parameter.empty()) asString += "; " + d->parameter; - } return asString; } return ""; diff --git a/src/content/content.cpp b/src/content/content.cpp index 0bd2554d0..68d86e9fd 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -17,11 +17,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "content-type.h" +// TODO: Remove me later. +#include "linphone/core.h" #include "content-p.h" -#include "content.h" -#include "linphone/core.h" +#include "content-type.h" // ============================================================================= @@ -151,14 +151,13 @@ bool Content::isEmpty () const { return getSize() == 0; } -bool Content::isValid() const { +bool Content::isValid () const { L_D(); return d->contentType.isValid() || d->body.empty(); } -LinphoneContent * Content::toLinphoneContent() const { - LinphoneContent* content; - content = linphone_core_create_content(NULL); +LinphoneContent *Content::toLinphoneContent () const { + LinphoneContent *content = linphone_core_create_content(nullptr); linphone_content_set_type(content, getContentType().getType().c_str()); linphone_content_set_subtype(content, getContentType().getSubType().c_str()); return content; diff --git a/src/content/content.h b/src/content/content.h index 23aa0446a..850bb7c50 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -62,12 +62,12 @@ public: size_t getSize () const; - bool isValid() const; + bool isValid () const; bool isEmpty () const; // TODO: Remove me later. - virtual LinphoneContent *toLinphoneContent() const; + virtual LinphoneContent *toLinphoneContent () const; protected: explicit Content (ContentPrivate &p); From 213164ae0a5b722de2cce5c9122d3ad8d499b508 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 22 Nov 2017 17:04:55 +0100 Subject: [PATCH 0834/2215] fix(content): clean file/file-transfert content --- src/content/content.h | 1 + src/content/file-content.cpp | 20 ++++++++++------- src/content/file-content.h | 8 ++++--- src/content/file-transfer-content.cpp | 31 ++++++++++++++------------- src/content/file-transfer-content.h | 30 ++++++++++++++------------ 5 files changed, 50 insertions(+), 40 deletions(-) diff --git a/src/content/content.h b/src/content/content.h index 850bb7c50..2cdaa4d73 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -43,6 +43,7 @@ public: Content &operator= (const Content &src); Content &operator= (Content &&src); + bool operator== (const Content &content) const; const ContentType &getContentType () const; diff --git a/src/content/file-content.cpp b/src/content/file-content.cpp index ecf445dbd..b19b0226c 100644 --- a/src/content/file-content.cpp +++ b/src/content/file-content.cpp @@ -17,9 +17,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +// TODO: Remove me later. +#include "linphone/core.h" + #include "content-p.h" #include "file-content.h" -#include "linphone/core.h" // ============================================================================= @@ -27,6 +29,8 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +// ----------------------------------------------------------------------------- + class FileContentPrivate : public ContentPrivate { public: string fileName; @@ -36,7 +40,7 @@ public: // ----------------------------------------------------------------------------- -FileContent::FileContent() : Content(*new FileContentPrivate()) {} +FileContent::FileContent () : Content(*new FileContentPrivate) {} FileContent::FileContent (const FileContent &src) : Content(*new FileContentPrivate) { L_D(); @@ -81,22 +85,22 @@ bool FileContent::operator== (const FileContent &content) const { d->fileSize == content.getFileSize(); } -void FileContent::setFileSize(size_t size) { +void FileContent::setFileSize (size_t size) { L_D(); d->fileSize = size; } -size_t FileContent::getFileSize() const { +size_t FileContent::getFileSize () const { L_D(); return d->fileSize; } -void FileContent::setFileName(const string &name) { +void FileContent::setFileName (const string &name) { L_D(); d->fileName = name; } -const string& FileContent::getFileName() const { +const string &FileContent::getFileName () const { L_D(); return d->fileName; } @@ -106,12 +110,12 @@ void FileContent::setFilePath (const string &path) { d->filePath = path; } -const string& FileContent::getFilePath () const { +const string &FileContent::getFilePath () const { L_D(); return d->filePath; } -LinphoneContent *FileContent::toLinphoneContent() const { +LinphoneContent *FileContent::toLinphoneContent () const { LinphoneContent *content = linphone_core_create_content(nullptr); linphone_content_set_type(content, getContentType().getType().c_str()); linphone_content_set_subtype(content, getContentType().getSubType().c_str()); diff --git a/src/content/file-content.h b/src/content/file-content.h index 9aefb0552..693e69b03 100644 --- a/src/content/file-content.h +++ b/src/content/file-content.h @@ -36,18 +36,20 @@ public: FileContent &operator= (const FileContent &src); FileContent &operator= (FileContent &&src); + bool operator== (const FileContent &content) const; void setFileSize (size_t size); size_t getFileSize () const; void setFileName (const std::string &name); - const std::string &getFileName() const; + const std::string &getFileName () const; void setFilePath (const std::string &path); - const std::string &getFilePath() const; + const std::string &getFilePath () const; - LinphoneContent *toLinphoneContent() const override; + // TODO: Remove me later. + LinphoneContent *toLinphoneContent () const override; private: L_DECLARE_PRIVATE(FileContent); diff --git a/src/content/file-transfer-content.cpp b/src/content/file-transfer-content.cpp index 9c851177b..f35398a6b 100644 --- a/src/content/file-transfer-content.cpp +++ b/src/content/file-transfer-content.cpp @@ -17,9 +17,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +// TODO: Remove me later. +#include "linphone/core.h" + #include "content-p.h" #include "file-transfer-content.h" -#include "linphone/core.h" // ============================================================================= @@ -27,6 +29,8 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +// ----------------------------------------------------------------------------- + class FileTransferContentPrivate : public ContentPrivate { public: string fileName; @@ -37,9 +41,7 @@ public: // ----------------------------------------------------------------------------- -FileTransferContent::FileTransferContent() : Content(*new FileTransferContentPrivate()) { - -} +FileTransferContent::FileTransferContent () : Content(*new FileTransferContentPrivate) {} FileTransferContent::FileTransferContent (const FileTransferContent &src) : Content(*new FileTransferContentPrivate) { L_D(); @@ -88,49 +90,48 @@ bool FileTransferContent::operator== (const FileTransferContent &content) const d->filePath == content.getFilePath(); } -void FileTransferContent::setFileName(const string &name) { +void FileTransferContent::setFileName (const string &name) { L_D(); d->fileName = name; } -const string& FileTransferContent::getFileName() const { +const string &FileTransferContent::getFileName () const { L_D(); return d->fileName; } -void FileTransferContent::setFileUrl(const string &url) { +void FileTransferContent::setFileUrl (const string &url) { L_D(); d->fileUrl = url; } -const string& FileTransferContent::getFileUrl() const { +const string &FileTransferContent::getFileUrl () const { L_D(); return d->fileUrl; } -void FileTransferContent::setFilePath(const string &path) { +void FileTransferContent::setFilePath (const string &path) { L_D(); d->filePath = path; } -const string& FileTransferContent::getFilePath() const { +const string &FileTransferContent::getFilePath () const { L_D(); return d->filePath; } -void FileTransferContent::setFileContent(FileContent *content) { +void FileTransferContent::setFileContent (FileContent *content) { L_D(); d->fileContent = content; } -FileContent* FileTransferContent::getFileContent() const { +FileContent *FileTransferContent::getFileContent () const { L_D(); return d->fileContent; } -LinphoneContent * FileTransferContent::toLinphoneContent() const { - LinphoneContent* content; - content = linphone_core_create_content(NULL); +LinphoneContent *FileTransferContent::toLinphoneContent () const { + LinphoneContent *content = linphone_core_create_content(nullptr); linphone_content_set_type(content, getContentType().getType().c_str()); linphone_content_set_subtype(content, getContentType().getSubType().c_str()); linphone_content_set_name(content, getFileName().c_str()); diff --git a/src/content/file-transfer-content.h b/src/content/file-transfer-content.h index 09615ca8b..1d24f09bf 100644 --- a/src/content/file-transfer-content.h +++ b/src/content/file-transfer-content.h @@ -21,37 +21,39 @@ #define _FILE_TRANSFER_CONTENT_H_ #include "content.h" -#include "file-content.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE +class FileContent; class FileTransferContentPrivate; class LINPHONE_PUBLIC FileTransferContent : public Content { public: - FileTransferContent(); + FileTransferContent (); FileTransferContent (const FileTransferContent &src); FileTransferContent (FileTransferContent &&src); FileTransferContent &operator= (const FileTransferContent &src); FileTransferContent &operator= (FileTransferContent &&src); + bool operator== (const FileTransferContent &content) const; - - void setFileName(const std::string &name); - const std::string& getFileName() const; - - void setFileUrl(const std::string &url); - const std::string& getFileUrl() const; - - void setFilePath(const std::string &path); - const std::string& getFilePath() const; - void setFileContent(FileContent *content); - FileContent* getFileContent() const; + void setFileName (const std::string &name); + const std::string &getFileName () const; - LinphoneContent * toLinphoneContent() const override; + void setFileUrl (const std::string &url); + const std::string &getFileUrl () const; + + void setFilePath (const std::string &path); + const std::string &getFilePath () const; + + void setFileContent (FileContent *content); + FileContent *getFileContent () const; + + // TODO: Remove me later. + LinphoneContent *toLinphoneContent () const override; private: L_DECLARE_PRIVATE(FileTransferContent); From 9d5d9ffc289be8c100100db2f279e9671bef97a8 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 22 Nov 2017 17:16:09 +0100 Subject: [PATCH 0835/2215] fix(content-manager-tester): fix build --- tester/content-manager-tester.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tester/content-manager-tester.cpp b/tester/content-manager-tester.cpp index 17cf4328d..e21cc6399 100644 --- a/tester/content-manager-tester.cpp +++ b/tester/content-manager-tester.cpp @@ -20,6 +20,7 @@ #include "content/content-manager.h" #include "content/content-type.h" +#include "content/content.h" #include "liblinphone_tester.h" #include "tester_utils.h" From 7148e56f7c92a653884e2944868f2090bd7c3eb4 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 22 Nov 2017 17:24:20 +0100 Subject: [PATCH 0836/2215] fix(content-manager): set correctly multi part content --- src/content/content-manager.cpp | 7 ++----- src/content/content-type.cpp | 3 ++- src/content/content-type.h | 3 ++- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/content/content-manager.cpp b/src/content/content-manager.cpp index afdcd6ff3..752a74445 100644 --- a/src/content/content-manager.cpp +++ b/src/content/content-manager.cpp @@ -68,8 +68,6 @@ list ContentManager::multipartToContentList (const Content &content) { } Content ContentManager::contentListToMultipart (const list &contents) { - string sub; - belle_sip_memory_body_handler_t *mbh = nullptr; belle_sip_multipart_body_handler_t *mpbh = belle_sip_multipart_body_handler_new( nullptr, nullptr, nullptr, MULTIPART_BOUNDARY @@ -79,8 +77,7 @@ Content ContentManager::contentListToMultipart (const list &contents) { for (const auto &content : contents) { const ContentType &contentType = content.getContentType(); stringstream subtype; - sub = contentType.getSubType(); - subtype << sub << "; charset=\"UTF-8\""; + subtype << contentType.getSubType() << "; charset=\"UTF-8\""; belle_sip_header_t *cContentType = BELLE_SIP_HEADER( belle_sip_header_content_type_create( contentType.getType().c_str(), @@ -99,7 +96,7 @@ Content ContentManager::contentListToMultipart (const list &contents) { Content content; content.setBody(desc); - content.setContentType(ContentType("application", sub)); + content.setContentType(ContentType::Multipart); belle_sip_free(desc); belle_sip_object_unref(mpbh); diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index 8c8d69859..7245bf36f 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -39,15 +39,16 @@ public: // ----------------------------------------------------------------------------- +const ContentType ContentType::ConferenceInfo("application/conference-info+xml"); const ContentType ContentType::Cpim("message/cpim"); const ContentType ContentType::ExternalBody("message/external-body"); const ContentType ContentType::FileTransfer("application/vnd.gsma.rcs-ft-http+xml"); const ContentType ContentType::Imdn("message/imdn+xml"); const ContentType ContentType::ImIsComposing("application/im-iscomposing+xml"); +const ContentType ContentType::Multipart("multipart/mixed"); const ContentType ContentType::PlainText("text/plain"); const ContentType ContentType::ResourceLists("application/resource-lists+xml"); const ContentType ContentType::Sdp("application/sdp"); -const ContentType ContentType::ConferenceInfo("application/conference-info+xml"); // ----------------------------------------------------------------------------- diff --git a/src/content/content-type.h b/src/content/content-type.h index a66955a94..6969ce843 100644 --- a/src/content/content-type.h +++ b/src/content/content-type.h @@ -61,15 +61,16 @@ public: static bool isFile (const ContentType &contentType); + static const ContentType ConferenceInfo; static const ContentType Cpim; static const ContentType ExternalBody; static const ContentType FileTransfer; static const ContentType Imdn; static const ContentType ImIsComposing; + static const ContentType Multipart; static const ContentType PlainText; static const ContentType ResourceLists; static const ContentType Sdp; - static const ContentType ConferenceInfo; private: L_DECLARE_PRIVATE(ContentType); From 23000b1ec9d1074852589a4d89c6c90e35619ff4 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 23 Nov 2017 10:01:10 +0100 Subject: [PATCH 0837/2215] Remove workaround on chat room ids. --- .../remote-conference-event-handler.cpp | 6 +-- src/core/core-chat-room.cpp | 44 ++----------------- 2 files changed, 5 insertions(+), 45 deletions(-) diff --git a/src/conference/handlers/remote-conference-event-handler.cpp b/src/conference/handlers/remote-conference-event-handler.cpp index aadfd5d60..6bf3718ce 100644 --- a/src/conference/handlers/remote-conference-event-handler.cpp +++ b/src/conference/handlers/remote-conference-event-handler.cpp @@ -51,12 +51,8 @@ void RemoteConferenceEventHandlerPrivate::simpleNotifyReceived (const string &xm ConferenceListener *confListener = static_cast(conf); - // TODO: Temporary workaround, remove me. - const IdentityAddress &peerAddress = chatRoomId.getPeerAddress(); IdentityAddress entityAddress(confInfo->getEntity().c_str()); - IdentityAddress peerAddressWorkaround = peerAddress; - peerAddressWorkaround.setDomain(entityAddress.getDomain()); - if ((entityAddress == peerAddress) || (entityAddress == peerAddressWorkaround)) { + if (entityAddress == chatRoomId.getPeerAddress()) { if ( confInfo->getConferenceDescription().present() && confInfo->getConferenceDescription().get().getSubject().present() diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 6bb25eb60..1fad063c2 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -39,32 +39,6 @@ LINPHONE_BEGIN_NAMESPACE // Helpers. // ----------------------------------------------------------------------------- -// TODO: Remove me later. -static inline ChatRoomId resolveWorkaroundClientGroupChatRoomId ( - const CorePrivate &corePrivate, - const ChatRoomId &chatRoomId -) { - const char *uri = linphone_core_get_conference_factory_uri(corePrivate.cCore); - if (!uri) - return ChatRoomId(); - - IdentityAddress peerAddress = chatRoomId.getPeerAddress(); - peerAddress.setDomain(Address(uri).getDomain()); - IdentityAddress localAddress = chatRoomId.getLocalAddress(); - localAddress.setDomain(Address(uri).getDomain()); - return ChatRoomId(peerAddress, localAddress); -} - -// TODO: Remove me later. -static inline ChatRoomId resolveWorkaroundClientGroupChatRoomId ( - const CorePrivate &corePrivate, - const shared_ptr &chatRoom -) { - if (!(chatRoom->getCapabilities() & static_cast(ChatRoom::Capabilities::Conference))) - return chatRoom->getChatRoomId(); - return resolveWorkaroundClientGroupChatRoomId(corePrivate, chatRoom->getChatRoomId()); -} - // Return the better local address to talk with peer address. static IdentityAddress getDefaultLocalAddress (const shared_ptr &core, const IdentityAddress &peerAddress) { LinphoneCore *cCore = core->getCCore(); @@ -107,8 +81,7 @@ shared_ptr CorePrivate::createBasicChatRoom (const ChatRoomId &chatRoo void CorePrivate::insertChatRoom (const shared_ptr &chatRoom) { L_ASSERT(chatRoom); - const ChatRoomId &chatRoomId = resolveWorkaroundClientGroupChatRoomId(*this, chatRoom); - + const ChatRoomId &chatRoomId = chatRoom->getChatRoomId(); deleteChatRoom(chatRoomId); chatRooms.push_back(chatRoom); chatRoomsById[chatRoomId] = chatRoom; @@ -132,8 +105,7 @@ void CorePrivate::deleteChatRoom (const ChatRoomId &chatRoomId) { void CorePrivate::insertChatRoomWithDb (const shared_ptr &chatRoom) { L_ASSERT(chatRoom->getState() == ChatRoom::State::Created); - const ChatRoomId &chatRoomId = resolveWorkaroundClientGroupChatRoomId(*this, chatRoom); - + const ChatRoomId &chatRoomId = chatRoom->getChatRoomId(); ChatRoom::CapabilitiesMask capabilities = chatRoom->getCapabilities(); mainDb->insertChatRoom(chatRoomId, capabilities); } @@ -160,13 +132,7 @@ shared_ptr Core::findChatRoom (const ChatRoomId &chatRoomId) const { lInfo() << "Unable to find chat room: (peer=" << chatRoomId.getPeerAddress().asString() << ", local=" << chatRoomId.getLocalAddress().asString() << ")."; - // TODO: Remove me, temp workaround. - ChatRoomId workaroundChatRoomId = resolveWorkaroundClientGroupChatRoomId(*d, chatRoomId); - lWarning() << "Workaround: searching chat room with: (peer=" << - chatRoomId.getPeerAddress().asString() << ", local=" << chatRoomId.getLocalAddress().asString() << ")."; - - it = d->chatRoomsById.find(workaroundChatRoomId); - return it == d->chatRoomsById.cend() ? shared_ptr() : it->second; + return shared_ptr(); } list> Core::findChatRooms (const IdentityAddress &peerAddress) const { @@ -242,9 +208,7 @@ shared_ptr Core::getOrCreateBasicChatRoomFromUri (const string &peerAd void Core::deleteChatRoom (const shared_ptr &chatRoom) { CorePrivate *d = chatRoom->getCore()->getPrivate(); - d->deleteChatRoomWithDb( - resolveWorkaroundClientGroupChatRoomId(*d, chatRoom->getChatRoomId()) - ); + d->deleteChatRoomWithDb(chatRoom->getChatRoomId()); } LINPHONE_END_NAMESPACE From 4fa3a224cf8e2c051fdc589e05a7c04756335914 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 23 Nov 2017 10:26:38 +0100 Subject: [PATCH 0838/2215] Load the correct C++ library on Android --- wrappers/java/java_class.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache index ea8ffbd55..fa544482b 100644 --- a/wrappers/java/java_class.mustache +++ b/wrappers/java/java_class.mustache @@ -150,7 +150,7 @@ class {{classImplName}} {{#isLinphoneFactory}}extends{{/isLinphoneFactory}}{{#is } static { - System.loadLibrary("gnustl_shared"); + System.loadLibrary("c++_shared"); loadOptionalLibrary("ffmpeg-linphone"); System.loadLibrary("bctoolbox"); System.loadLibrary("ortp"); From eeee4736820954b6053e7c33233607f0dd60abf4 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 23 Nov 2017 11:04:35 +0100 Subject: [PATCH 0839/2215] Moved IMDN xml creation to imdn.cpp instead of chat-message --- src/chat/chat-message/chat-message.cpp | 103 +------------------------ src/chat/notification/imdn.cpp | 100 ++++++++++++++++++++++++ src/chat/notification/imdn.h | 1 + 3 files changed, 103 insertions(+), 101 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 220602ff8..fbed81566 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -36,6 +36,7 @@ #include "content/content.h" #include "core/core.h" #include "logger/logger.h" +#include "chat/notification/imdn.h" #include "ortp/b64.h" @@ -310,106 +311,6 @@ bool ChatMessagePrivate::downloadFile () { // ----------------------------------------------------------------------------- -string ChatMessagePrivate::createImdnXml (Imdn::Type imdnType, LinphoneReason reason) { - xmlBufferPtr buf; - xmlTextWriterPtr writer; - int err; - string content; - char *datetime = nullptr; - - // Check that the chat message has a message id. - if (id.empty()) return nullptr; - - buf = xmlBufferCreate(); - if (buf == nullptr) { - lError() << "Error creating the XML buffer"; - return content; - } - writer = xmlNewTextWriterMemory(buf, 0); - if (writer == nullptr) { - lError() << "Error creating the XML writer"; - return content; - } - - datetime = linphone_timestamp_to_rfc3339_string(time); - err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", nullptr); - if (err >= 0) { - err = xmlTextWriterStartElementNS(writer, nullptr, (const xmlChar *)"imdn", - (const xmlChar *)"urn:ietf:params:xml:ns:imdn"); - } - if ((err >= 0) && (reason != LinphoneReasonNone)) { - err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"linphoneimdn", nullptr, (const xmlChar *)"http://www.linphone.org/xsds/imdn.xsd"); - } - if (err >= 0) { - err = xmlTextWriterWriteElement(writer, (const xmlChar *)"message-id", (const xmlChar *)id.c_str()); - } - if (err >= 0) { - err = xmlTextWriterWriteElement(writer, (const xmlChar *)"datetime", (const xmlChar *)datetime); - } - if (err >= 0) { - if (imdnType == Imdn::Type::Delivery) { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivery-notification"); - } else { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"display-notification"); - } - } - if (err >= 0) { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"status"); - } - if (err >= 0) { - if (reason == LinphoneReasonNone) { - if (imdnType == Imdn::Type::Delivery) { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivered"); - } else { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"displayed"); - } - } else { - err = xmlTextWriterStartElement(writer, (const xmlChar *)"error"); - } - } - if (err >= 0) { - // Close the "delivered", "displayed" or "error" element. - err = xmlTextWriterEndElement(writer); - } - if ((err >= 0) && (reason != LinphoneReasonNone)) { - err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"linphoneimdn", (const xmlChar *)"reason", nullptr); - if (err >= 0) { - char codestr[16]; - snprintf(codestr, 16, "%d", linphone_reason_to_error_code(reason)); - err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"code", (const xmlChar *)codestr); - } - if (err >= 0) { - err = xmlTextWriterWriteString(writer, (const xmlChar *)linphone_reason_to_string(reason)); - } - if (err >= 0) { - err = xmlTextWriterEndElement(writer); - } - } - if (err >= 0) { - // Close the "status" element. - err = xmlTextWriterEndElement(writer); - } - if (err >= 0) { - // Close the "delivery-notification" or "display-notification" element. - err = xmlTextWriterEndElement(writer); - } - if (err >= 0) { - // Close the "imdn" element. - err = xmlTextWriterEndElement(writer); - } - if (err >= 0) { - err = xmlTextWriterEndDocument(writer); - } - if (err > 0) { - // xmlTextWriterEndDocument returns the size of the content. - content = string((char *)buf->content); - } - xmlFreeTextWriter(writer); - xmlBufferFree(buf); - ms_free(datetime); - return content; -} - void ChatMessagePrivate::sendImdn (Imdn::Type imdnType, LinphoneReason reason) { L_Q(); @@ -417,7 +318,7 @@ void ChatMessagePrivate::sendImdn (Imdn::Type imdnType, LinphoneReason reason) { Content *content = new Content(); content->setContentType("message/imdn+xml"); - content->setBody(createImdnXml(imdnType, reason)); + content->setBody(Imdn::createXml(id, time, imdnType, reason)); msg->addContent(*content); msg->getPrivate()->send(); diff --git a/src/chat/notification/imdn.cpp b/src/chat/notification/imdn.cpp index 4fc01dbc6..72ed7eb20 100644 --- a/src/chat/notification/imdn.cpp +++ b/src/chat/notification/imdn.cpp @@ -32,6 +32,106 @@ LINPHONE_BEGIN_NAMESPACE const string Imdn::imdnPrefix = "/imdn:imdn"; +string Imdn::createXml (string id, time_t time, Imdn::Type imdnType, LinphoneReason reason) { + xmlBufferPtr buf; + xmlTextWriterPtr writer; + int err; + string content; + char *datetime = nullptr; + + // Check that the chat message has a message id. + if (id.empty()) return nullptr; + + buf = xmlBufferCreate(); + if (buf == nullptr) { + lError() << "Error creating the XML buffer"; + return content; + } + writer = xmlNewTextWriterMemory(buf, 0); + if (writer == nullptr) { + lError() << "Error creating the XML writer"; + return content; + } + + datetime = linphone_timestamp_to_rfc3339_string(time); + err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", nullptr); + if (err >= 0) { + err = xmlTextWriterStartElementNS(writer, nullptr, (const xmlChar *)"imdn", + (const xmlChar *)"urn:ietf:params:xml:ns:imdn"); + } + if ((err >= 0) && (reason != LinphoneReasonNone)) { + err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"linphoneimdn", nullptr, (const xmlChar *)"http://www.linphone.org/xsds/imdn.xsd"); + } + if (err >= 0) { + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"message-id", (const xmlChar *)id.c_str()); + } + if (err >= 0) { + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"datetime", (const xmlChar *)datetime); + } + if (err >= 0) { + if (imdnType == Imdn::Type::Delivery) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivery-notification"); + } else { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"display-notification"); + } + } + if (err >= 0) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"status"); + } + if (err >= 0) { + if (reason == LinphoneReasonNone) { + if (imdnType == Imdn::Type::Delivery) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivered"); + } else { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"displayed"); + } + } else { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"error"); + } + } + if (err >= 0) { + // Close the "delivered", "displayed" or "error" element. + err = xmlTextWriterEndElement(writer); + } + if ((err >= 0) && (reason != LinphoneReasonNone)) { + err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"linphoneimdn", (const xmlChar *)"reason", nullptr); + if (err >= 0) { + char codestr[16]; + snprintf(codestr, 16, "%d", linphone_reason_to_error_code(reason)); + err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"code", (const xmlChar *)codestr); + } + if (err >= 0) { + err = xmlTextWriterWriteString(writer, (const xmlChar *)linphone_reason_to_string(reason)); + } + if (err >= 0) { + err = xmlTextWriterEndElement(writer); + } + } + if (err >= 0) { + // Close the "status" element. + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + // Close the "delivery-notification" or "display-notification" element. + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + // Close the "imdn" element. + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + err = xmlTextWriterEndDocument(writer); + } + if (err > 0) { + // xmlTextWriterEndDocument returns the size of the content. + content = string((char *)buf->content); + } + xmlFreeTextWriter(writer); + xmlBufferFree(buf); + ms_free(datetime); + return content; +} + void Imdn::parse (ChatRoom &cr, const string &text) { xmlparsing_context_t *xmlCtx = linphone_xmlparsing_context_new(); xmlSetGenericErrorFunc(xmlCtx, linphone_xmlparsing_genericxml_error); diff --git a/src/chat/notification/imdn.h b/src/chat/notification/imdn.h index 8bb57486a..15e41905a 100644 --- a/src/chat/notification/imdn.h +++ b/src/chat/notification/imdn.h @@ -37,6 +37,7 @@ public: Display }; + static std::string createXml(std::string id, time_t time, Imdn::Type imdnType, LinphoneReason reason); static void parse (ChatRoom &cr, const std::string &content); private: From 5c7fe8a92b57883b89f5dd4940090a4b12ac36b0 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 23 Nov 2017 11:32:05 +0100 Subject: [PATCH 0840/2215] feat(MainDb): supports fetching of client group chat room --- src/chat/chat-room/client-group-chat-room.cpp | 26 +++++++++++++++---- src/chat/chat-room/client-group-chat-room.h | 6 +++++ src/conference/conference-p.h | 13 +++++----- src/db/main-db.cpp | 19 +++++--------- 4 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 501beb279..a30efac9c 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -84,10 +84,10 @@ void ClientGroupChatRoomPrivate::onChatMessageReceived (const shared_ptr &core, - const std::string &factoryUri, + const shared_ptr &core, + const string &factoryUri, const IdentityAddress &me, - const std::string &subject + const string &subject ) : ChatRoom(*new ClientGroupChatRoomPrivate, core, ChatRoomId(IdentityAddress(), me)), RemoteConference(core, me, nullptr) { L_D_T(RemoteConference, dConference); @@ -95,6 +95,21 @@ RemoteConference(core, me, nullptr) { RemoteConference::setSubject(subject); } +ClientGroupChatRoom::ClientGroupChatRoom ( + const shared_ptr &core, + const ChatRoomId &chatRoomId, + const string &subject +) : ChatRoom(*new ClientGroupChatRoomPrivate, core, chatRoomId), +RemoteConference(core, chatRoomId.getLocalAddress(), nullptr) { + L_D(); + L_D_T(RemoteConference, dConference); + const IdentityAddress &peerAddress = chatRoomId.getPeerAddress(); + dConference->focus = make_shared(peerAddress); + dConference->conferenceAddress = peerAddress; + dConference->subject = subject; + d->state = ChatRoom::State::Created; +} + shared_ptr ClientGroupChatRoom::getCore () const { return ChatRoom::getCore(); } @@ -268,6 +283,7 @@ void ClientGroupChatRoom::onConferenceCreated (const IdentityAddress &addr) { L_D(); L_D_T(RemoteConference, dConference); dConference->conferenceAddress = addr; + dConference->focus = make_shared(addr); d->chatRoomId = ChatRoomId(addr, d->chatRoomId.getLocalAddress()); getCore()->getPrivate()->insertChatRoom(getSharedFromThis()); } @@ -432,7 +448,7 @@ void ClientGroupChatRoom::onParticipantDeviceRemoved (const shared_ptr &session) { +void ClientGroupChatRoom::onCallSessionSetReleased (const shared_ptr &session) { L_D_T(RemoteConference, dConference); ParticipantPrivate *participantPrivate = dConference->focus->getPrivate(); @@ -441,7 +457,7 @@ void ClientGroupChatRoom::onCallSessionSetReleased (const std::shared_ptr &session, + const shared_ptr &session, LinphoneCallState state, const string &message ) { diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 8efa00801..a8e569945 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -39,6 +39,12 @@ public: const std::string &subject ); + ClientGroupChatRoom ( + const std::shared_ptr &core, + const ChatRoomId &chatRoomId, + const std::string &subject + ); + std::shared_ptr getCore () const; CapabilitiesMask getCapabilities () const override; diff --git a/src/conference/conference-p.h b/src/conference/conference-p.h index 1a163cf34..f738da3a5 100644 --- a/src/conference/conference-p.h +++ b/src/conference/conference-p.h @@ -34,17 +34,18 @@ class ConferencePrivate { public: IdentityAddress conferenceAddress; std::list> participants; - -protected: - CallListener *callListener = nullptr; - - std::shared_ptr activeParticipant; - std::shared_ptr me; std::string subject; +protected: Conference *mPublic = nullptr; + std::shared_ptr activeParticipant; + private: + CallListener *callListener = nullptr; + + std::shared_ptr me; + L_DECLARE_PUBLIC(Conference); }; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 76af6928e..09dbad22b 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1398,23 +1398,16 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), capabilities & static_cast(ChatRoom::Capabilities::RealTimeText) ); chatRoom->setSubject(subject); - - ChatRoomPrivate *dChatRoom = chatRoom->getPrivate(); - dChatRoom->creationTime = Utils::getTmAsTimeT(creationDate); - dChatRoom->lastUpdateTime = Utils::getTmAsTimeT(lastUpdateDate); - } else if (capabilities & static_cast(ChatRoom::Capabilities::Conference)) { - // TODO: Fetch! - // chatRoom = make_shared( - // getCore(), - // Address("sip:titi@sip.linphone.org"), // TODO: Fix me!!! - // chatRoomId, - // subject - // ); - } + } else if (capabilities & static_cast(ChatRoom::Capabilities::Conference)) + chatRoom = make_shared(core, chatRoomId, subject); if (!chatRoom) continue; // Not fetched. + ChatRoomPrivate *dChatRoom = chatRoom->getPrivate(); + dChatRoom->creationTime = Utils::getTmAsTimeT(creationDate); + dChatRoom->lastUpdateTime = Utils::getTmAsTimeT(lastUpdateDate); + chatRooms.push_back(chatRoom); } From a947f8bd6c472a9f960cbde9e45ad7a603af3e67 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 23 Nov 2017 11:46:32 +0100 Subject: [PATCH 0841/2215] feat(c-chat-room): add a method to get local address --- include/linphone/api/c-chat-room.h | 8 ++++++++ src/c-wrapper/api/c-chat-room.cpp | 24 ++++++++++++++++-------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index 7d05bdcee..d4e0d65b9 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -99,6 +99,14 @@ LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_file_transfer_mes */ LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr); +/** + * get local address \link linphone_core_get_chat_room() associated to \endlink this #LinphoneChatRoom + * @param cr #LinphoneChatRoom object + * @return #LinphoneAddress local address + */ +LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_room_get_local_address(LinphoneChatRoom *cr); + + /** * Send a message to peer member of this chat room. * @deprecated Use linphone_chat_message_send() instead. diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index d8185943b..7f329f082 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -45,7 +45,8 @@ L_DECLARE_C_OBJECT_IMPL_WITH_XTORS( _linphone_chat_room_constructor, _linphone_chat_room_destructor, LinphoneChatRoomCbs *cbs; mutable LinphoneAddress *conferenceAddressCache; - LinphoneAddress *peerAddressCache; + mutable LinphoneAddress *peerAddressCache; + mutable LinphoneAddress *localAddressCache; ) static void _linphone_chat_room_constructor (LinphoneChatRoom *cr) { @@ -54,15 +55,12 @@ static void _linphone_chat_room_constructor (LinphoneChatRoom *cr) { static void _linphone_chat_room_destructor (LinphoneChatRoom *cr) { linphone_chat_room_cbs_unref(cr->cbs); - cr->cbs = nullptr; - if (cr->conferenceAddressCache) { + if (cr->conferenceAddressCache) linphone_address_unref(cr->conferenceAddressCache); - cr->conferenceAddressCache = nullptr; - } - if (cr->peerAddressCache) { + if (cr->peerAddressCache) linphone_address_unref(cr->peerAddressCache); - cr->peerAddressCache = nullptr; - } + if (cr->localAddressCache) + linphone_address_unref(cr->localAddressCache); } // ============================================================================= @@ -97,10 +95,20 @@ const LinphoneAddress *linphone_chat_room_get_peer_address (LinphoneChatRoom *cr if (cr->peerAddressCache) { linphone_address_unref(cr->peerAddressCache); } + cr->peerAddressCache = linphone_address_new(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getPeerAddress().asString().c_str()); return cr->peerAddressCache; } +const LinphoneAddress *linphone_chat_room_get_local_address (LinphoneChatRoom *cr) { + if (cr->localAddressCache) { + linphone_address_unref(cr->localAddressCache); + } + + cr->localAddressCache = linphone_address_new(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getLocalAddress().asString().c_str()); + return cr->localAddressCache; +} + LinphoneChatMessage *linphone_chat_room_create_message (LinphoneChatRoom *cr, const char *message) { shared_ptr cppPtr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createMessage(L_C_TO_STRING(message)); LinphoneChatMessage *object = L_INIT(ChatMessage); From 97cd45702cc7c7774807d4b0e97e332c2373286f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 23 Nov 2017 13:58:57 +0100 Subject: [PATCH 0842/2215] Should fix crash in getTextContent --- src/c-wrapper/api/c-chat-message.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index c04cee0d6..d53df4dbe 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -47,6 +47,7 @@ L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(ChatMessage, LinphoneChatMessageStateChangedCb message_state_changed_cb; void* message_state_changed_user_data; mutable char *contentTypeCache; + mutable std::string textContentBody; ) static void _linphone_chat_message_constructor (LinphoneChatMessage *msg) { @@ -296,7 +297,8 @@ const char *linphone_chat_message_get_text_content(const LinphoneChatMessage *ms const LinphonePrivate::Content *content = L_GET_PRIVATE_FROM_C_OBJECT(msg)->getTextContent(); if (content->isEmpty()) return nullptr; - return L_STRING_TO_C(content->getBodyAsString()); + msg->textContentBody = content->getBodyAsString(); + return L_STRING_TO_C(msg->textContentBody); } // ============================================================================= From a2f363ac642e0a989c6a0ac1e1e21507817eb47b Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 23 Nov 2017 15:02:42 +0100 Subject: [PATCH 0843/2215] fix(MainDb): insert chatroom subject properly --- src/core/core-chat-room.cpp | 9 +++++---- src/db/main-db-p.h | 5 +++-- src/db/main-db.cpp | 34 +++++++++++++++++++--------------- src/db/main-db.h | 2 +- 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 1fad063c2..0bff00f42 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -104,10 +104,11 @@ void CorePrivate::deleteChatRoom (const ChatRoomId &chatRoomId) { void CorePrivate::insertChatRoomWithDb (const shared_ptr &chatRoom) { L_ASSERT(chatRoom->getState() == ChatRoom::State::Created); - - const ChatRoomId &chatRoomId = chatRoom->getChatRoomId(); - ChatRoom::CapabilitiesMask capabilities = chatRoom->getCapabilities(); - mainDb->insertChatRoom(chatRoomId, capabilities); + mainDb->insertChatRoom( + chatRoom->getChatRoomId(), + chatRoom->getCapabilities(), + chatRoom->getSubject() + ); } void CorePrivate::deleteChatRoomWithDb (const ChatRoomId &chatRoomId) { diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index bd35e0615..d51e9ca0b 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -46,9 +46,10 @@ private: long long peerSipAddressId, long long localSipAddressId, int capabilities, - const tm &date + const tm &date, + const std::string &subject ); - long long insertChatRoom (const ChatRoomId &chatRoomId, int capabilities, const tm &date); + long long insertChatRoom (const ChatRoomId &chatRoomId, int capabilities, const tm &date, const std::string &subject); void insertChatRoomParticipant (long long chatRoomId, long long sipAddressId, bool isAdmin); void insertChatMessageParticipant (long long messageEventId, long long sipAddressId, int state); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 09dbad22b..5266f322d 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -166,7 +166,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long peerSipAddressId, long long localSipAddressId, int capabilities, - const tm &date + const tm &date, + const string &subject ) { L_Q(); @@ -178,27 +179,28 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), ", local=" << localSipAddressId << ", capabilities=" << capabilities << ")."; *session << "INSERT INTO chat_room (" " peer_sip_address_id, local_sip_address_id, creation_date, last_update_date, capabilities, subject" - ") VALUES (:peerSipAddressId, :localSipAddressId, :creationDate, :lastUpdateDate, :capabilities, '')", + ") VALUES (:peerSipAddressId, :localSipAddressId, :creationDate, :lastUpdateDate, :capabilities, subject)", soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::use(date), soci::use(date), - soci::use(capabilities); + soci::use(capabilities), soci::use(subject); return q->getLastInsertId(); } - // Update date if chat room exists. Do not touch capabilities. - *session << "UPDATE chat_room SET last_update_date = :lastUpdateDate" - " WHERE id = :chatRoomId", - soci::use(date), soci::use(id); - return id; } - long long MainDbPrivate::insertChatRoom (const ChatRoomId &chatRoomId, int capabilities, const tm &date) { + long long MainDbPrivate::insertChatRoom ( + const ChatRoomId &chatRoomId, + int capabilities, + const tm &date, + const string &subject + ) { return insertChatRoom ( insertSipAddress(chatRoomId.getPeerAddress().asString()), insertSipAddress(chatRoomId.getLocalAddress().asString()), capabilities, - date + date, + subject ); } @@ -1416,7 +1418,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return chatRooms; } - void MainDb::insertChatRoom (const ChatRoomId &chatRoomId, int capabilities) { + void MainDb::insertChatRoom (const ChatRoomId &chatRoomId, int capabilities, const string &subject) { L_D(); if (!isConnected()) { @@ -1427,14 +1429,15 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), DurationLogger durationLogger( "Insert chat room: peer=" + chatRoomId.getPeerAddress().asString() + ", local=" + chatRoomId.getLocalAddress().asString() + - ", capabilities=" + Utils::toString(capabilities) + ")." + ", capabilities=" + Utils::toString(capabilities) + + ", subject=" + subject + ")." ); L_BEGIN_LOG_EXCEPTION soci::transaction tr(*d->dbSession.getBackendSession()); - d->insertChatRoom(chatRoomId, capabilities, Utils::getTimeTAsTm(time(0))); + d->insertChatRoom(chatRoomId, capabilities, Utils::getTimeTAsTm(time(0)), subject); tr.commit(); @@ -1589,7 +1592,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), remoteSipAddressId, localSipAddressId, static_cast(ChatRoom::Capabilities::Basic), - date + date, + "" ); *session << "INSERT INTO conference_event (event_id, chat_room_id)" @@ -1678,7 +1682,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return list>(); } - void MainDb::insertChatRoom (const ChatRoomId &, int) {} + void MainDb::insertChatRoom (const ChatRoomId &, int, const string &) {} void MainDb::deleteChatRoom (const ChatRoomId &) {} diff --git a/src/db/main-db.h b/src/db/main-db.h index 8a6358839..5e776482b 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -99,7 +99,7 @@ public: // --------------------------------------------------------------------------- std::list> getChatRooms () const; - void insertChatRoom (const ChatRoomId &chatRoomId, int capabilities); + void insertChatRoom (const ChatRoomId &chatRoomId, int capabilities, const std::string &subject); void deleteChatRoom (const ChatRoomId &chatRoomId); // --------------------------------------------------------------------------- From f6cd06d37d20373a78d34ab757002f5c5f8e39c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Wed, 22 Nov 2017 11:16:06 +0100 Subject: [PATCH 0844/2215] Wrappers generator: logging system reworking --- coreapi/help/doc/sphinx/gendoc.py | 9 +- include/linphone/api/c-call.h | 19 +-- include/linphone/call_log.h | 2 + include/linphone/call_params.h | 14 +- include/linphone/core.h | 95 +++++++----- include/linphone/core_utils.h | 2 +- include/linphone/lpconfig.h | 6 +- include/linphone/nat_policy.h | 1 + tools/abstractapi.py | 234 ++++++++++++++++++------------ tools/genapixml.py | 62 ++++---- tools/metadoc.py | 12 +- tools/metaname.py | 13 +- tools/python/apixml2python.py | 13 -- wrappers/cpp/genwrapper.py | 124 ++++++++-------- wrappers/csharp/genwrapper.py | 23 +-- wrappers/java/genwrapper.py | 35 ++--- 16 files changed, 366 insertions(+), 298 deletions(-) diff --git a/coreapi/help/doc/sphinx/gendoc.py b/coreapi/help/doc/sphinx/gendoc.py index 800d57bc6..256ab1fe4 100755 --- a/coreapi/help/doc/sphinx/gendoc.py +++ b/coreapi/help/doc/sphinx/gendoc.py @@ -18,10 +18,11 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -import sys -import os import argparse +import logging +import os import pystache +import sys sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', 'tools')) import abstractapi @@ -363,7 +364,11 @@ if __name__ == '__main__': argparser = argparse.ArgumentParser(description='Generate a sphinx project to generate the documentation of Linphone Core API.') argparser.add_argument('xmldir', type=str, help='directory holding the XML documentation of the C API generated by Doxygen') argparser.add_argument('-o --output', type=str, help='directory into where Sphinx source files will be written', dest='outputdir', default='.') + argparser.add_argument('-v --verbose', action='store_true', default=False, dest='verbose_mode', help='Show warning and info messages') args = argparser.parse_args() + + loglevel = logging.INFO if args.verbose_mode else logging.ERROR + logging.basicConfig(format='%(levelname)s[%(name)s]: %(message)s', level=loglevel) cProject = capi.Project() cProject.initFromDir(args.xmldir) diff --git a/include/linphone/api/c-call.h b/include/linphone/api/c-call.h index da3dbaaa5..47140a8ba 100644 --- a/include/linphone/api/c-call.h +++ b/include/linphone/api/c-call.h @@ -350,26 +350,23 @@ LINPHONE_PUBLIC void linphone_call_set_audio_route (LinphoneCall *call, Linphone LINPHONE_PUBLIC int linphone_call_get_stream_count (const LinphoneCall *call); /** - * Returns the type of stream for the given stream index. - * @param call - * @param stream_index + * @brief Returns the type of stream for the given stream index. * @return the type (MSAudio, MSVideo, MSText) of the stream of given index. + * @donotwrap **/ LINPHONE_PUBLIC MSFormatType linphone_call_get_stream_type (const LinphoneCall *call, int stream_index); /** - * Returns the meta rtp transport for the given stream index. - * @param call - * @param stream_index - * @return a pointer to the meta rtp transport if it exists, NULL otherwise + * @brief Returns the meta rtp transport for the given stream index. + * @return a pointer to the meta rtp transport if it exists, NULL otherwise. + * @donotwrap **/ LINPHONE_PUBLIC RtpTransport *linphone_call_get_meta_rtp_transport (const LinphoneCall *call, int stream_index); /** - * Returns the meta rtcp transport for the given stream index. - * @param call - * @param stream_index - * @return a pointer to the meta rtcp transport if it exists, NULL otherwise + * @brief Returns the meta rtcp transport for the given stream index. + * @return a pointer to the meta rtcp transport if it exists, NULL otherwise. + * @donotwrap **/ LINPHONE_PUBLIC RtpTransport *linphone_call_get_meta_rtcp_transport (const LinphoneCall *call, int stream_index); diff --git a/include/linphone/call_log.h b/include/linphone/call_log.h index cd833391c..205865fad 100644 --- a/include/linphone/call_log.h +++ b/include/linphone/call_log.h @@ -68,6 +68,7 @@ LINPHONE_PUBLIC const LinphoneAddress * linphone_call_log_get_from_address(const * Get the RTP statistics computed locally regarding the call. * @param[in] cl LinphoneCallLog object * @return The RTP statistics that have been computed locally for the call. + * @donotwrap **/ LINPHONE_PUBLIC const rtp_stats_t * linphone_call_log_get_local_stats(const LinphoneCallLog *cl); @@ -101,6 +102,7 @@ LINPHONE_PUBLIC LinphoneAddress * linphone_call_log_get_remote_address(const Lin * @note Not implemented yet. * @param[in] cl LinphoneCallLog object * @return The RTP statistics that have been computed by the remote end for the call. + * @donotwrap **/ LINPHONE_PUBLIC const rtp_stats_t * linphone_call_log_get_remote_stats(const LinphoneCallLog *cl); diff --git a/include/linphone/call_params.h b/include/linphone/call_params.h index a483232cc..9d3a88211 100644 --- a/include/linphone/call_params.h +++ b/include/linphone/call_params.h @@ -140,10 +140,11 @@ LINPHONE_PUBLIC float linphone_call_params_get_received_framerate(const Linphone LINPHONE_PUBLIC const LinphoneVideoDefinition * linphone_call_params_get_received_video_definition(const LinphoneCallParams *cp); /** - * Get the size of the video that is received. - * @param[in] cp LinphoneCallParams object + * @brief Get the size of the video that is received. + * @param[in] cp #LinphoneCallParams object * @return The received video size or MS_VIDEO_SIZE_UNKNOWN if not available. - * @deprecated Use linphone_call_params_get_received_video_definition() instead + * @deprecated Use #linphone_call_params_get_received_video_definition() instead. Deprecated since 2017-03-28. + * @donotwrap */ LINPHONE_PUBLIC LINPHONE_DEPRECATED MSVideoSize linphone_call_params_get_received_video_size(const LinphoneCallParams *cp); @@ -176,10 +177,11 @@ LINPHONE_PUBLIC float linphone_call_params_get_sent_framerate(const LinphoneCall LINPHONE_PUBLIC const LinphoneVideoDefinition * linphone_call_params_get_sent_video_definition(const LinphoneCallParams *cp); /** - * Gets the size of the video that is sent. - * @param[in] cp LinphoneCalParams object + * @biref Gets the size of the video that is sent. + * @param[in] cp #LinphoneCalParams object * @return The sent video size or MS_VIDEO_SIZE_UNKNOWN if not available. - * @deprecated Use linphone_call_params_get_sent_video_definition() instead + * @deprecated Use #linphone_call_params_get_sent_video_definition() instead. Deprecated since 2017-03-28. + * @donotwrap */ LINPHONE_PUBLIC LINPHONE_DEPRECATED MSVideoSize linphone_call_params_get_sent_video_size(const LinphoneCallParams *cp); diff --git a/include/linphone/core.h b/include/linphone/core.h index 0ecc1ae5d..166430666 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -193,22 +193,25 @@ typedef struct _LinphoneCoreVTable{ } LinphoneCoreVTable; /** - * Instantiate a vtable with all arguments set to NULL - * @return newly allocated vtable + * @brief Instantiate a vtable with all arguments set to NULL. + * @return newly allocated vtable. + * @donotwrap */ LINPHONE_PUBLIC LinphoneCoreVTable *linphone_core_v_table_new(void); /** - * Sets a user data pointer in the vtable. - * @param table the vtable - * @param data the user data to attach + * @brief Sets a user data pointer in the vtable. + * @param table the vtable. + * @param data the user data to attach. + * @donotwrap */ LINPHONE_PUBLIC void linphone_core_v_table_set_user_data(LinphoneCoreVTable *table, void *data); /** - * Gets a user data pointer in the vtable. - * @param table the vtable - * @return the data attached to the vtable + * @brief Gets a user data pointer in the vtable. + * @param table the vtable. + * @return the data attached to the vtable. + * @donotwrap */ LINPHONE_PUBLIC void* linphone_core_v_table_get_user_data(const LinphoneCoreVTable *table); @@ -222,8 +225,9 @@ LINPHONE_PUBLIC void* linphone_core_v_table_get_user_data(const LinphoneCoreVTab LINPHONE_PUBLIC LinphoneCoreVTable *linphone_core_get_current_vtable(LinphoneCore *lc); /** - * Destroy a vtable. - * @param table to be destroyed + * @brief Destroy a vtable. + * @param table to be destroyed. + * @donotwrap */ LINPHONE_PUBLIC void linphone_core_v_table_destroy(LinphoneCoreVTable* table); @@ -786,25 +790,25 @@ LINPHONE_PUBLIC char * linphone_core_compress_log_collection(void); LINPHONE_PUBLIC void linphone_core_reset_log_collection(void); /** - * Define a log handler. - * + * @bref Define a log handler. * @param logfunc The function pointer of the log handler. + * @donotwrap */ LINPHONE_PUBLIC void linphone_core_set_log_handler(OrtpLogFunc logfunc); /** - * Define a log file. + * @brief Define a log file. * * If the file pointer passed as an argument is NULL, stdout is used instead. - * * @param file A pointer to the FILE structure of the file to write to. + * @donotwrap */ LINPHONE_PUBLIC void linphone_core_set_log_file(FILE *file); /** - * Define the minimum level for logging. - * + * @brief Define the minimum level for logging. * @param loglevel Minimum level for logging messages. + * @donotwrap **/ LINPHONE_PUBLIC void linphone_core_set_log_level(OrtpLogLevel loglevel); @@ -3303,7 +3307,8 @@ LINPHONE_PUBLIC bool_t linphone_core_video_display_enabled(LinphoneCore *lc); * @param[in] lc LinphoneCore object * @param[in] policy The video policy to use * @ingroup media_parameters - * @deprecated + * @deprecated Deprecated since 2017-04-19. + * @donotwrap **/ LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_core_set_video_policy(LinphoneCore *lc, const LinphoneVideoPolicy *policy); @@ -3313,7 +3318,8 @@ LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_core_set_video_policy(Linphone * @param[in] lc LinphoneCore object * @return The video policy being used * @ingroup media_parameters - * @deprecated + * @deprecated Deprecated since 2017-04-19. + * @donotwrap **/ LINPHONE_PUBLIC LINPHONE_DEPRECATED const LinphoneVideoPolicy *linphone_core_get_video_policy(const LinphoneCore *lc); @@ -3400,9 +3406,10 @@ LINPHONE_PUBLIC void linphone_core_set_video_activation_policy(LinphoneCore *lc, LINPHONE_PUBLIC LinphoneVideoActivationPolicy *linphone_core_get_video_activation_policy(const LinphoneCore *lc); /** - * Returns the zero terminated table of supported video resolutions. + * @brief Returns the zero terminated table of supported video resolutions. * @ingroup media_parameters - * @deprecated Use linphone_factory_get_supported_video_definitions() instead + * @deprecated Use #linphone_factory_get_supported_video_definitions() instead. Deprecated since 2017-03-28. + * @donotwrap **/ LINPHONE_PUBLIC LINPHONE_DEPRECATED const MSVideoSizeDef *linphone_core_get_supported_video_sizes(LinphoneCore *lc); @@ -3416,12 +3423,13 @@ LINPHONE_PUBLIC LINPHONE_DEPRECATED const MSVideoSizeDef *linphone_core_get_supp LINPHONE_PUBLIC void linphone_core_set_preferred_video_definition(LinphoneCore *lc, LinphoneVideoDefinition *vdef); /** - * Sets the preferred video size. + * @brief Sets the preferred video size. * * This applies only to the stream that is captured and sent to the remote party, * since we accept all standard video size on the receive path. * @ingroup media_parameters - * @deprecated Use linphone_core_set_preferred_video_definition() instead + * @deprecated Use linphone_core_set_preferred_video_definition() instead. Deprecated since 2017-03-28. + * @donotwrap **/ LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_core_set_preferred_video_size(LinphoneCore *lc, MSVideoSize vsize); @@ -3437,14 +3445,16 @@ LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_core_set_preferred_video_size( LINPHONE_PUBLIC void linphone_core_set_preview_video_definition(LinphoneCore *lc, LinphoneVideoDefinition *vdef); /** - * Sets the video size for the captured (preview) video. + * @biref Sets the video size for the captured (preview) video. + * * This method is for advanced usage where a video capture must be set independently of the size of the stream actually sent through the call. * This allows for example to have the preview window with HD resolution even if due to bandwidth constraint the sent video size is small. * Using this feature increases the CPU consumption, since a rescaling will be done internally. * @ingroup media_parameters * @param lc the linphone core * @param vsize the video resolution choosed for capuring and previewing. It can be (0,0) to not request any specific preview size and let the core optimize the processing. - * @deprecated Use linphone_core_set_preview_video_definition() instead + * @deprecated Use #linphone_core_set_preview_video_definition() instead. Deprecated since 2017-03-28. + * @donotwrap **/ LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_core_set_preview_video_size(LinphoneCore *lc, MSVideoSize vsize); @@ -3467,12 +3477,13 @@ LINPHONE_PUBLIC void linphone_core_set_preview_video_size_by_name(LinphoneCore * LINPHONE_PUBLIC const LinphoneVideoDefinition * linphone_core_get_preview_video_definition(const LinphoneCore *lc); /** - * Returns video size for the captured video if it was previously set by linphone_core_set_preview_video_size(), otherwise returns a 0,0 size. - * @see linphone_core_set_preview_video_size() + * @brief Returns video size for the captured video if it was previously set by #linphone_core_set_preview_video_size(), otherwise returns a 0,0 size. + * @see #linphone_core_set_preview_video_size() * @ingroup media_parameters * @param lc the core - * @return a MSVideoSize - * @deprecated Use linphone_core_get_preview_video_definition() instead + * @return a #MSVideoSize + * @deprecated Use #linphone_core_get_preview_video_definition() instead. Since 2017-03-28. + * @donotwrap **/ LINPHONE_PUBLIC LINPHONE_DEPRECATED MSVideoSize linphone_core_get_preview_video_size(const LinphoneCore *lc); @@ -3487,13 +3498,15 @@ LINPHONE_PUBLIC LINPHONE_DEPRECATED MSVideoSize linphone_core_get_preview_video_ LINPHONE_PUBLIC LinphoneVideoDefinition * linphone_core_get_current_preview_video_definition(const LinphoneCore *lc); /** - * Returns the effective video size for the captured video as provided by the camera. + * @brief Returns the effective video size for the captured video as provided by the camera. + * * When preview is disabled or not yet started, this function returns a zeroed video size. - * @see linphone_core_set_preview_video_size() + * @see #linphone_core_set_preview_video_size() * @ingroup media_parameters * @param lc the core - * @return a MSVideoSize - * @deprecated Use linphone_core_get_current_preview_video_definition() instead + * @return a #MSVideoSize + * @deprecated Use #linphone_core_get_current_preview_video_definition() instead. Deprecated since 2017-03-28. + * @donotwrap **/ LINPHONE_PUBLIC LINPHONE_DEPRECATED MSVideoSize linphone_core_get_current_preview_video_size(const LinphoneCore *lc); @@ -3506,9 +3519,10 @@ LINPHONE_PUBLIC LINPHONE_DEPRECATED MSVideoSize linphone_core_get_current_previe LINPHONE_PUBLIC const LinphoneVideoDefinition * linphone_core_get_preferred_video_definition(const LinphoneCore *lc); /** - * Returns the current preferred video size for sending. + * @brief Returns the current preferred video size for sending. * @ingroup media_parameters - * @deprecated Use linphone_core_get_preferred_video_definition() instead + * @deprecated Use linphone_core_get_preferred_video_definition() instead. Deprecated since 2017-03-28. + * @donotwrap **/ LINPHONE_PUBLIC LINPHONE_DEPRECATED MSVideoSize linphone_core_get_preferred_video_size(const LinphoneCore *lc); @@ -4708,24 +4722,27 @@ LINPHONE_PUBLIC void linphone_core_enable_video_multicast(LinphoneCore *core, bo LINPHONE_PUBLIC bool_t linphone_core_video_multicast_enabled(const LinphoneCore *core); /** - * Set the network simulator parameters. + * @brief Set the network simulator parameters. + * * Liblinphone has the capabability of simulating the effects of a network (latency, lost packets, jitter, max bandwidth). * Please refer to the oRTP documentation for the meaning of the parameters of the OrtpNetworkSimulatorParams structure. * This function has effect for future calls, but not for currently running calls, though this behavior may be changed in future versions. * @warning Due to design of network simulation in oRTP, simulation is applied independently for audio and video stream. This means for example that a bandwidth * limit of 250kbit/s will have no effect on an audio stream running at 40kbit/s while a videostream targetting 400kbit/s will be highly affected. - * @param lc the LinphoneCore + * @param lc the #LinphoneCore * @param params the parameters used for the network simulation. * @return 0 if successful, -1 otherwise. * @ingroup media_parameters + * @donotwrap **/ LINPHONE_PUBLIC LinphoneStatus linphone_core_set_network_simulator_params(LinphoneCore *lc, const OrtpNetworkSimulatorParams *params); /** - * Get the previously set network simulation parameters. + * @brief Get the previously set network simulation parameters. * @see linphone_core_set_network_simulator_params - * @return a OrtpNetworkSimulatorParams structure. + * @return a #OrtpNetworkSimulatorParams structure. * @ingroup media_parameters + * @donotwrap **/ LINPHONE_PUBLIC const OrtpNetworkSimulatorParams *linphone_core_get_network_simulator_params(const LinphoneCore *lc); @@ -4862,6 +4879,7 @@ LINPHONE_PUBLIC const char *linphone_core_get_tls_key_path(const LinphoneCore *l * @param lc LinphoneCore object * @param imee LinphoneImEncryptionEngine object * @ingroup chatroom + * @donotwrap */ LINPHONE_PUBLIC void linphone_core_set_im_encryption_engine(LinphoneCore *lc, LinphoneImEncryptionEngine *imee); @@ -4870,6 +4888,7 @@ LINPHONE_PUBLIC void linphone_core_set_im_encryption_engine(LinphoneCore *lc, Li * @param lc LinphoneCore object * @return the IM Encryption Engine in the core or NULL * @ingroup chatroom + * @donotwrap */ LINPHONE_PUBLIC LinphoneImEncryptionEngine * linphone_core_get_im_encryption_engine(const LinphoneCore *lc); diff --git a/include/linphone/core_utils.h b/include/linphone/core_utils.h index 38b3ea88b..aaac2e5ab 100644 --- a/include/linphone/core_utils.h +++ b/include/linphone/core_utils.h @@ -55,12 +55,12 @@ LINPHONE_DEPRECATED typedef void (*LinphoneEcCalibrationAudioInit)(void *data); LINPHONE_DEPRECATED typedef void (*LinphoneEcCalibrationAudioUninit)(void *data); /** - * * @brief Starts an echo calibration of the sound devices, in order to find adequate settings for the echo canceler automatically. * @deprecated Use #linphone_core_start_echo_canceller_calibration() instead. To set the callbacks create or get an already instantiated * #LinphoneCoreCbs and call #linphone_core_cbs_set_ec_calibration_result(), #linphone_core_cbs_set_ec_calibration_audio_init() and * #linphone_core_cbs_set_ec_callibration_audio_uninit(). Deprecated since 2017-10-16. * @ingroup misc + * @donotwrap **/ LINPHONE_DEPRECATED LINPHONE_PUBLIC int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibrationCallback cb, LinphoneEcCalibrationAudioInit audio_init_cb, LinphoneEcCalibrationAudioUninit audio_uninit_cb, void *cb_data); diff --git a/include/linphone/lpconfig.h b/include/linphone/lpconfig.h index eadab533b..816e2805c 100644 --- a/include/linphone/lpconfig.h +++ b/include/linphone/lpconfig.h @@ -245,12 +245,14 @@ LINPHONE_PUBLIC const char** linphone_config_get_sections_names(LinphoneConfig * LINPHONE_PUBLIC const bctbx_list_t * linphone_config_get_sections_names_list(LpConfig *lpconfig); /** - * Call a function for each section present in the configuration. + * @brief Call a function for each section present in the configuration. + * @donotwrap **/ void linphone_config_for_each_section(const LinphoneConfig *lpconfig, void (*callback)(const char *section, void *ctx), void *ctx); /** - * Call a function for each entry present in a section configuration. + * @brief Call a function for each entry present in a section configuration. + * @donotwrap **/ void linphone_config_for_each_entry(const LinphoneConfig *lpconfig, const char *section, void (*callback)(const char *entry, void *ctx), void *ctx); diff --git a/include/linphone/nat_policy.h b/include/linphone/nat_policy.h index b409a974f..56f63a09f 100644 --- a/include/linphone/nat_policy.h +++ b/include/linphone/nat_policy.h @@ -172,6 +172,7 @@ LINPHONE_PUBLIC void linphone_nat_policy_resolve_stun_server(LinphoneNatPolicy * * WARNING: This function may block for up to 1 second. * @param[in] policy LinphoneNatPolicy object * @return addrinfo representation of the STUN server address. + * @donotwrap */ LINPHONE_PUBLIC const struct addrinfo * linphone_nat_policy_get_stun_server_addrinfo(LinphoneNatPolicy *policy); diff --git a/tools/abstractapi.py b/tools/abstractapi.py index 9f7a4d451..20645dae6 100644 --- a/tools/abstractapi.py +++ b/tools/abstractapi.py @@ -19,13 +19,65 @@ import re import genapixml as CApi import metaname +import logging -class Error(RuntimeError): - pass +logger = logging.getLogger(__name__) -class BlacklistedException(Error): +class Error(Exception): + @property + def reason(self): + return self.args[0] + + def __str__(self): + return str(self.reason) + + @staticmethod + def _name_get_type_as_string(name): + if type(name) is metaname.ClassName: + return 'class' + elif type(name) is metaname.EnumName: + return 'enum' + elif type(name) is metaname.EnumeratorName: + return 'enumerator' + elif type(name) is metaname.MethodName: + return 'function' + else: + raise TypeError('{0} not handled'.format(type(name))) + + +class ParsingError(Error): + @property + def context(self): + return self.args[1] if len(self.args) >= 2 else None + + def __str__(self): + if self.context is None: + return Error.__str__(self) + else: + params = { + 'reason': self.reason, + 'name': self.context.to_c(addBrackets=True), + 'type_': Error._name_get_type_as_string(self.context) + } + return "error while parsing {name} {type_}: {reason}".format(**params) + + +class BlacklistedSymbolError(Error): + @property + def name(self): + return self.args[0] + + def __str__(self): + params = { + 'name': self.name.to_c(addBrackets=True), + 'type_': Error._name_get_type_as_string(self.name) + } + return "{name} {type_} has been blacklisted".format(**params) + + +class TranslationError(Error): pass @@ -154,7 +206,7 @@ class DocumentableObject(Object): if isinstance(self, (Namespace,Enum,Class)): return self elif self.parent is None: - raise Error('{0} is not attached to a namespace object'.format(self)) + return None else: return self.parent.get_namespace_object() @@ -424,17 +476,14 @@ class CParser(object): for enum in self.cProject.enums: try: self.parse_enum(enum) - except Error as e: - print('Could not parse \'{0}\' enum: {1}'.format(enum.name, e.args[0])) + except BlacklistedSymbolError as e: + logger.debug(e) - for _class in self.cProject.classes: + for class_ in self.cProject.classes: try: - self.parse_class(_class) - except BlacklistedException: - pass - except Error as e: - print('Could not parse \'{0}\' class: {1}'.format(_class.name, e.args[0])) - + self.parse_class(class_) + except BlacklistedSymbolError as e: + logger.debug(e) self._clean_all_indexes() self._sortall() @@ -504,8 +553,8 @@ class CParser(object): self._fix_type(method.returnType) for arg in method.args: self._fix_type(arg.type) - except Error as e: - print('warning: some types could not be fixed in {0}() function: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0])) + except ParsingError as e: + raise ParsingError(e, method.name) def _fix_type(self, _type): if isinstance(_type, EnumType) and _type.desc is None: @@ -526,7 +575,7 @@ class CParser(object): if _type.containedTypeName is not None: _type.containedTypeDesc = self.parse_c_base_type(_type.containedTypeName) else: - raise Error('bctbx_list_t type without specified contained type') + raise ParsingError('bctbx_list_t type without specified contained type') def _fix_all_docs(self): for _class in self.classesIndex.values(): @@ -545,13 +594,8 @@ class CParser(object): obj.detailedDescription.resolve_all_references(self) def parse_enum(self, cenum): - if 'associatedTypedef' in dir(cenum): - nameStr = cenum.associatedTypedef.name - else: - nameStr = cenum.name - name = metaname.EnumName() - name.from_camel_case(nameStr, namespace=self.namespace.name) + name.from_camel_case(cenum.publicName, namespace=self.namespace.name) enum = Enum(name) enum.briefDescription = cenum.briefDoc enum.detailedDescription = cenum.detailedDoc @@ -567,16 +611,21 @@ class CParser(object): try: aEnumValue.value_from_string(cEnumValue.value) except ValueError: - raise Error('{0} enum value has an invalid definition ({1})'.format(cEnumValue.name, cEnumValue.value)) + reason = '{0} enum value has an invalid definition ({1})'.format(cEnumValue.name, cEnumValue.value) + context = metaname.EnumeratorName() + context.from_camel_case(cEnumValue.name) + raise ParsingError(reason, context) enum.add_enumerator(aEnumValue) - self.enumsIndex[nameStr] = enum + self.enumsIndex[cenum.publicName] = enum self.enums.append(enum) return enum def parse_class(self, cclass): if cclass.name in self.classBl: - raise BlacklistedException('{0} is blacklisted'.format(cclass.name)); + name = metaname.ClassName() + name.from_snake_case(cclass.name) + raise BlacklistedSymbolError(name) if cclass.name.endswith('Cbs'): _class = self._parse_listener(cclass) @@ -603,8 +652,8 @@ class CParser(object): _class.add_property(absProperty) else: _class.listenerInterface = self.interfacesIndex[cproperty.getter.returnArgument.ctype] - except Error as e: - print('Could not parse {0} property in {1}: {2}'.format(cproperty.name, cclass.name, e.args[0])) + except BlacklistedSymbolError as e: + logger.debug(e) for cMethod in cclass.instanceMethods.values(): try: @@ -617,20 +666,15 @@ class CParser(object): pass else: _class.add_instance_method(method) - - except BlacklistedException: - pass - except Error as e: - print('Could not parse {0} function: {1}'.format(cMethod.name, e.args[0])) - + except BlacklistedSymbolError as e: + logger.debug(e) + for cMethod in cclass.classMethods.values(): try: method = self.parse_method(cMethod, type=Method.Type.Class, namespace=name) _class.add_class_method(method) - except BlacklistedException: - pass - except Error as e: - print('Could not parse {0} function: {1}'.format(cMethod.name, e.args[0])) + except BlacklistedSymbolError as e: + logger.debug(e) return _class @@ -652,27 +696,28 @@ class CParser(object): def _parse_listener(self, cclass): - name = metaname.InterfaceName() - name.from_camel_case(cclass.name, namespace=self.namespace.name) - - if name.words[len(name.words)-1] == 'cbs': - name.words[len(name.words)-1] = 'listener' - else: - raise Error('{0} is not a listener'.format(cclass.name)) - - listener = Interface(name) - listener.briefDescription = cclass.briefDoc - listener.detailedDescription = cclass.detailedDoc - - for property in cclass.properties.values(): - if property.name != 'user_data': - try: - method = self._parse_listener_property(property, listener, cclass.events) - listener.add_method(method) - except Error as e: - print('Could not parse property \'{0}\' of listener \'{1}\': {2}'.format(property.name, cclass.name, e.args[0])) - - return listener + try: + name = metaname.InterfaceName() + name.from_camel_case(cclass.name, namespace=self.namespace.name) + name.words[-1] = 'listener' + + listener = Interface(name) + listener.briefDescription = cclass.briefDoc + listener.detailedDescription = cclass.detailedDoc + + for property in cclass.properties.values(): + if property.name != 'user_data': + try: + method = self._parse_listener_property(property, listener, cclass.events) + listener.add_method(method) + except BlacklistedSymbolError as e: + logger.debug(e) + + return listener + except ParsingError as e: + context = metaname.ClassName() + context.from_camel_case(cclass.name) + raise ParsingError(e, context) def _parse_listener_property(self, property, listener, events): methodName = metaname.MethodName() @@ -685,12 +730,12 @@ class CParser(object): elif property.setter is not None and len(property.setter.arguments) == 2: eventName = property.setter.arguments[1].ctype else: - raise Error('event name for {0} property of {1} listener not found'.format(property.name, listener.name.to_snake_case(fullName=True))) + raise ParsingError('event name for {0} property of {1} listener not found'.format(property.name, listener.name.to_c())) try: event = events[eventName] except KeyError: - raise Error('invalid event name \'{0}\''.format(eventName)) + raise ParsingError('invalid event name \'{0}\''.format(eventName)) method = Method(methodName) method.returnType = self.parse_type(event.returnArgument) @@ -706,27 +751,30 @@ class CParser(object): name = metaname.MethodName() name.from_snake_case(cfunction.name, namespace=namespace) - if self._is_blacklisted(name): - raise BlacklistedException('{0} is blacklisted'.format(name.to_c())); - - method = Method(name, type=type) - method.briefDescription = cfunction.briefDoc - method.detailedDescription = cfunction.detailedDoc - method.deprecated = cfunction.deprecated - method.returnType = self.parse_type(cfunction.returnArgument) - - for arg in cfunction.arguments: - if type == Method.Type.Instance and arg is cfunction.arguments[0]: - method.isconst = ('const' in arg.completeType.split(' ')) - else: - aType = self.parse_type(arg) - argName = metaname.ArgName() - argName.from_snake_case(arg.name) - absArg = Argument(argName, aType) - method.add_arguments(absArg) - - self.methodsIndex[cfunction.name] = method - return method + try: + if self._is_blacklisted(name): + raise BlacklistedSymbolError(name) + + method = Method(name, type=type) + method.briefDescription = cfunction.briefDoc + method.detailedDescription = cfunction.detailedDoc + method.deprecated = cfunction.deprecated + method.returnType = self.parse_type(cfunction.returnArgument) + + for arg in cfunction.arguments: + if type == Method.Type.Instance and arg is cfunction.arguments[0]: + method.isconst = ('const' in arg.completeType.split(' ')) + else: + aType = self.parse_type(arg) + argName = metaname.ArgName() + argName.from_snake_case(arg.name) + absArg = Argument(argName, aType) + method.add_arguments(absArg) + + self.methodsIndex[cfunction.name] = method + return method + except ParsingError as e: + raise ParsingError(e, name) def parse_type(self, cType): if cType.ctype in self.cBaseType or re.match(self.regexFixedSizeInteger, cType.ctype): @@ -742,7 +790,7 @@ class CParser(object): elif cType.ctype.endswith('Mask'): absType = BaseType('integer', isUnsigned=True) else: - raise Error('Unknown C type \'{0}\''.format(cType.ctype)) + raise ParsingError('Unknown C type \'{0}\''.format(cType.ctype)) absType.cDecl = cType.completeType return absType @@ -791,7 +839,7 @@ class CParser(object): elif 'isref' not in param or param['isref'] is False: param['isref'] = True else: - raise Error('Unhandled double-pointer') + raise ParsingError('Unhandled double-pointer') else: matchCtx = re.match(self.regexFixedSizeInteger, elem) if matchCtx: @@ -801,13 +849,13 @@ class CParser(object): param['size'] = int(matchCtx.group(2)) if param['size'] not in [8, 16, 32, 64]: - raise Error('{0} C basic type has an invalid size ({1})'.format(cDecl, param['size'])) + raise ParsingError('{0} C basic type has an invalid size ({1})'.format(cDecl, param['size'])) if name is not None: return BaseType(name, **param) else: - raise Error('could not find type in \'{0}\''.format(cDecl)) + raise ParsingError('could not find type in \'{0}\''.format(cDecl)) class Translator: @@ -935,7 +983,7 @@ class CppLangTranslator(CLikeLangTranslator): if type(_type.parent) is Argument: res += ' &' else: - raise Error('\'{0}\' is not a base abstract type'.format(_type.name)) + raise TranslationError('\'{0}\' is not a base abstract type'.format(_type.name)) if _type.isUnsigned: if _type.name == 'integer' and isinstance(_type.size, int): @@ -953,7 +1001,7 @@ class CppLangTranslator(CLikeLangTranslator): def translate_enum_type(self, _type, showStdNs=True, namespace=None): if _type.desc is None: - raise Error('{0} has not been fixed'.format(_type.name)) + raise TranslationError('{0} has not been fixed'.format(_type.name)) if namespace is not None: nsName = namespace.name if namespace is not GlobalNs else None @@ -965,7 +1013,7 @@ class CppLangTranslator(CLikeLangTranslator): def translate_class_type(self, _type, showStdNs=True, namespace=None): if _type.desc is None: - raise Error('{0} has not been fixed'.format(_type.name)) + raise TranslationError('{0} has not been fixed'.format(_type.name)) if namespace is not None: nsName = namespace.name if namespace is not GlobalNs else None @@ -999,7 +1047,7 @@ class CppLangTranslator(CLikeLangTranslator): def translate_list_type(self, _type, showStdNs=True, namespace=None): if _type.containedTypeDesc is None: - raise Error('{0} has not been fixed'.format(_type.containedTypeName)) + raise TranslationError('{0} has not been fixed'.format(_type.containedTypeName)) elif isinstance(_type.containedTypeDesc, BaseType): res = _type.containedTypeDesc.translate(self) else: @@ -1096,7 +1144,7 @@ class CSharpLangTranslator(CLikeLangTranslator): else: return 'IEnumerable' else: - raise Error('\'{0}\' is not a base abstract type'.format(_type.name)) + raise TranslationError('\'{0}\' is not a base abstract type'.format(_type.name)) return res @@ -1117,15 +1165,15 @@ class CSharpLangTranslator(CLikeLangTranslator): if _type.containedTypeDesc.name == 'string': return 'IEnumerable' else: - raise Error('translation of bctbx_list_t of basic C types is not supported') + raise TranslationError('translation of bctbx_list_t of basic C types is not supported') elif type(_type.containedTypeDesc) is ClassType: ptrType = _type.containedTypeDesc.desc.name.translate(self.nameTranslator) return 'IEnumerable<' + ptrType + '>' else: if _type.containedTypeDesc: - raise Error('translation of bctbx_list_t of enums') + raise TranslationError('translation of bctbx_list_t of enums') else: - raise Error('translation of bctbx_list_t of unknow type !') + raise TranslationError('translation of bctbx_list_t of unknow type !') def translate_argument(self, arg, dllImport=True): return '{0} {1}'.format( diff --git a/tools/genapixml.py b/tools/genapixml.py index 29a0dedf8..53b4481b2 100755 --- a/tools/genapixml.py +++ b/tools/genapixml.py @@ -17,15 +17,20 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. import argparse +import logging import os import six import string import sys import xml.etree.ElementTree as ET import xml.dom.minidom as minidom + import metadoc +logger = logging.getLogger(__name__) + + class CObject: def __init__(self, name): self.name = name.strip() @@ -47,6 +52,10 @@ class CEnum(CObject): CObject.__init__(self, name) self.values = [] self.associatedTypedef = None + + @property + def publicName(self): + return self.associatedTypedef.name if self.associatedTypedef is not None else self.name def addValue(self, value): self.values.append(value) @@ -239,7 +248,6 @@ class CClass(CObject): class Project: def __init__(self): - self.verbose = False self.prettyPrint = False self.enums = [] self.__structs = [] @@ -251,37 +259,28 @@ class Project: def add(self, elem): if isinstance(elem, CClass): - if self.verbose: - print("Adding class " + elem.name) + logger.debug("Adding class " + elem.name) self.classes.append(elem) elif isinstance(elem, CEnum): - if self.verbose: - print("Adding enum " + elem.name) - for ev in elem.values: - print("\t" + ev.name) + msg = 'Adding enum {0}'.format(elem.name) + for value in elem.values: + msg += ('\t{0}'.format(value)) + logger.debug(msg) self.enums.append(elem) elif isinstance(elem, CStruct): - if self.verbose: - print("Adding struct " + elem.name) - for sm in elem.members: - print("\t" + sm.ctype + " " + sm.name) + msg = "Adding struct " + elem.name + for sm in elem.members: + msg += ('\t{0} {1}'.format(sm.ctype, sm.name)) + logger.debug(msg) self.__structs.append(elem) elif isinstance(elem, CTypedef): - if self.verbose: - print("Adding typedef " + elem.name) - print("\t" + elem.definition) + logger.debug('Adding typedef {0}\t{1}'.format(elem.name, elem.definition)) self.__typedefs.append(elem) elif isinstance(elem, CEvent): - if self.verbose: - print("Adding event " + elem.name) - print("\tReturns: " + elem.returnArgument.ctype) - print("\tArguments: " + str(elem.arguments)) + logger.debug('Adding event {0}\tReturns: {1}\tArguments: {2}'.format(elem.name, elem.returnArgument.ctype, elem.arguments)) self.__events.append(elem) elif isinstance(elem, CFunction): - if self.verbose: - print("Adding function " + elem.name) - print("\tReturns: " + elem.returnArgument.ctype) - print("\tArguments: " + str(elem.arguments)) + logger.debug('Adding event {0}\tReturns: {1}\tArguments: {2}'.format(elem.name, elem.returnArgument.ctype, elem.arguments)) self.__functions.append(elem) def __cleanDescription(self, descriptionNode): @@ -330,7 +329,7 @@ class Project: break if not structFound: name = td.definition[7:] - print("Structure with no associated typedef: " + name) + logger.warning("Structure with no associated typedef: " + name) st = CStruct(name) st.associatedTypedef = td self.add(st) @@ -503,7 +502,7 @@ class Project: if arg.description == None: missingDocWarning += "\t'" + arg.name + "' parameter not documented\n"; if missingDocWarning != '': - print(name + ":\n" + missingDocWarning) + logger.warning(name + ":\n" + missingDocWarning) f = CEvent(name, returnarg, argslist) deprecatedNode = node.find(".//xrefsect[xreftitle='Deprecated']") if deprecatedNode is not None: @@ -599,7 +598,7 @@ class Project: if not f.location.endswith('.h'): missingDocWarning += "\tNot documented in a header file ('" + f.location + "')\n"; if missingDocWarning != '': - print(name + ":\n" + missingDocWarning) + logger.warning(name + ":\n" + missingDocWarning) return f def __findCFunction(self, tree): @@ -614,11 +613,10 @@ class Project: for f in xmlfiles: tree = None try: - if self.verbose: - print("Parsing XML file: " + f.name) + logger.debug("Parsing XML file: " + f) tree = ET.parse(f) except ET.ParseError as e: - print(e) + logger.error(e) if tree is not None: trees.append(tree) for tree in trees: @@ -639,7 +637,7 @@ class Project: for c in self.classes: for name, p in six.iteritems(c.properties): if p.getter is None and p.setter is not None: - print("Property '" + name + "' of class '" + c.name + "' has a setter but no getter") + logger.warning("Property '" + name + "' of class '" + c.name + "' has a setter but no getter") class Generator: @@ -764,7 +762,7 @@ class Generator: classNode.append(cclass.detailedDescription) def generate(self, project): - print("Generating XML document of Linphone API to '" + self.__outputfile.name + "'") + logger.info("Generating XML document of Linphone API to '" + self.__outputfile.name + "'") apiNode = ET.Element('api') project.enums.sort(key = lambda e: e.name) if len(project.enums) > 0: @@ -797,7 +795,9 @@ def main(argv = None): args.outputfile = open('api.xml', 'w') project = Project() if args.verbose: - project.verbose = True + logger.setLogLevel(logging.DEBUG) + else: + logger.setLogLevel(logging.INFO) if args.pretty: project.prettyPrint = True project.initFromDir(args.xmldir) diff --git a/tools/metadoc.py b/tools/metadoc.py index e2dcdc091..22655adf7 100644 --- a/tools/metadoc.py +++ b/tools/metadoc.py @@ -14,8 +14,10 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -import metaname + import abstractapi +import logging +import metaname import re @@ -146,7 +148,7 @@ class ClassReference(Reference): try: self.relatedObject = api.classesIndex[self.cname] except KeyError: - print('doc reference pointing on an unknown object ({0})'.format(self.cname)) + logging.warning('doc reference pointing on an unknown object ({0})'.format(self.cname)) class FunctionReference(Reference): @@ -154,7 +156,7 @@ class FunctionReference(Reference): try: self.relatedObject = api.methodsIndex[self.cname] except KeyError: - print('doc reference pointing on an unknown object ({0})'.format(self.cname)) + logging.warning('doc reference pointing on an unknown object ({0})'.format(self.cname)) class Paragraph(MultiChildTreeNode): @@ -443,8 +445,8 @@ class Translator: strPara += part else: strPara += part.translate(self) - except TranslationError as e: - print('error: {0}'.format(e.msg())) + except ReferenceTranslationError: + strPara += part.cname return strPara diff --git a/tools/metaname.py b/tools/metaname.py index 6a76e6f71..3514f9df0 100644 --- a/tools/metaname.py +++ b/tools/metaname.py @@ -144,7 +144,7 @@ class Name(object): class ClassName(Name): - def to_c(self): + def to_c(self, addBrackets=False): return self.to_camel_case(fullName=True) def translate(self, translator, **params): @@ -152,7 +152,7 @@ class ClassName(Name): class InterfaceName(ClassName): - def to_c(self): + def to_c(self, addBrackets=False): return ClassName.to_c(self)[:-8] + 'Cbs' def translate(self, translator, **params): @@ -183,16 +183,19 @@ class MethodName(Name): self.overloadRef = int(suffix) del self.words[-1] - def to_c(self): + def to_c(self, addBrackets=False): suffix = ('_' + str(self.overloadRef)) if self.overloadRef > 0 else '' - return self.to_snake_case(fullName=True) + suffix + cName = self.to_snake_case(fullName=True) + suffix + if addBrackets: + cName += '()' + return cName def translate(self, translator, **params): return translator.translate_method_name(self, **params) class ArgName(Name): - def to_c(self): + def to_c(self, addBrackets=False): return self.to_snake_case() def translate(self, translator, **params): diff --git a/tools/python/apixml2python.py b/tools/python/apixml2python.py index 23c4e9127..e0aac85b4 100755 --- a/tools/python/apixml2python.py +++ b/tools/python/apixml2python.py @@ -42,16 +42,12 @@ blacklisted_events = [ 'LinphoneCoreTextMessageReceivedCb' # not respecting naming convention ] blacklisted_functions = [ - 'linphone_call_log_get_local_stats', # missing rtp_stats_t - 'linphone_call_log_get_remote_stats', # missing rtp_stats_t 'linphone_call_params_get_privacy', # missing LinphonePrivacyMask 'linphone_call_params_set_privacy', # missing LinphonePrivacyMask 'linphone_chat_message_start_file_download', # callback function in parameter 'linphone_chat_message_state_to_string', # There is no use to wrap this function 'linphone_chat_room_send_chat_message', # Use linphone_chat_room_send_chat_message_2 instead 'linphone_chat_room_send_message2', # callback function in parameter - 'linphone_config_for_each_entry', # to be handwritten because of callback - 'linphone_config_for_each_section', # to be handwritten because of callback 'linphone_config_get_range', # to be handwritten because of result via arguments 'linphone_config_load_dict_to_section', # missing LinphoneDictionary 'linphone_config_section_to_dict', # missing LinphoneDictionary @@ -62,10 +58,7 @@ blacklisted_functions = [ 'linphone_core_enable_logs_with_cb', # callback function in parameter 'linphone_core_get_audio_port_range', # to be handwritten because of result via arguments 'linphone_core_get_default_proxy', - 'linphone_core_get_network_simulator_params', # missing OrtpNetworkSimulatorParams - 'linphone_core_get_supported_video_sizes', # missing MSVideoSizeDef 'linphone_core_get_tunnel', # blacklisted LinphoneTunnel - 'linphone_core_get_video_policy', # missing LinphoneVideoPolicy 'linphone_core_get_video_port_range', # to be handwritten because of result via arguments 'linphone_core_new', # replaced by linphone_factory_create_core 'linphone_core_new_with_config', # replaced by linphone_factory_create_core_with_config @@ -75,13 +68,7 @@ blacklisted_functions = [ 'linphone_core_set_log_collection_max_file_size', # need to handle class properties 'linphone_core_set_log_collection_path', # need to handle class properties 'linphone_core_set_log_collection_prefix', # need to handle class properties - 'linphone_core_set_log_file', # There is no use to wrap this function - 'linphone_core_set_log_handler', # Hand-written but put directly in the linphone module - 'linphone_core_set_log_level', # There is no use to wrap this function 'linphone_core_set_log_level_mask', # There is no use to wrap this function - 'linphone_core_set_network_simulator_params', # missing OrtpNetworkSimulatorParams - 'linphone_core_set_video_policy', # missing LinphoneVideoPolicy - 'linphone_nat_policy_get_stun_server_addrinfo', 'linphone_proxy_config_get_privacy', # missing LinphonePrivacyMask 'linphone_proxy_config_normalize_number', # to be handwritten because of result via arguments 'linphone_proxy_config_set_file_transfer_server', # defined but not implemented in linphone core diff --git a/wrappers/cpp/genwrapper.py b/wrappers/cpp/genwrapper.py index 1ec10effc..3e1587f35 100755 --- a/wrappers/cpp/genwrapper.py +++ b/wrappers/cpp/genwrapper.py @@ -21,8 +21,10 @@ import pystache import re import argparse import os +import os.path import sys import errno +import logging sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'tools')) import genapixml as CApi @@ -58,9 +60,12 @@ class CppTranslator(object): def translate_enumerator(self, enumerator): enumeratorDict = { 'name' : enumerator.name.translate(self.nameTranslator), - 'doc' : enumerator.briefDescription.translate(self.docTranslator), 'value' : enumerator.translate_value(self.langTranslator) } + try: + enumeratorDict['doc'] = enumerator.briefDescription.translate(self.docTranslator) + except metadoc.TranslationError as e: + logging.error(e.msg()) return enumeratorDict def translate_class(self, _class): @@ -92,8 +97,11 @@ class CppTranslator(object): if _class.name.to_c() == 'LinphoneCore': classDict['friendClasses'].append({'name': 'Factory'}); - classDict['briefDoc'] = _class.briefDescription.translate(self.docTranslator, tagAsBrief=True) - classDict['detailedDoc'] = _class.detailedDescription.translate(self.docTranslator) + try: + classDict['briefDoc'] = _class.briefDescription.translate(self.docTranslator, tagAsBrief=True) + classDict['detailedDoc'] = _class.detailedDescription.translate(self.docTranslator) + except metadoc.TranslationError as e: + logging.error(e.msg()) if islistenable: classDict['listenerClassName'] = _class.listenerInterface.name.translate(self.nameTranslator) @@ -115,24 +123,15 @@ class CppTranslator(object): classDict['currentCallbacksGetter'] = _class.name.to_snake_case(fullName=True) + '_get_current_callbacks' for _property in _class.properties: - try: - classDict['methods'] += self.translate_property(_property) - except AbsApi.Error as e: - print('error while translating {0} property: {1}'.format(_property.name.to_snake_case(), e.args[0])) + classDict['methods'] += self.translate_property(_property) for method in _class.instanceMethods: - try: - methodDict = self.translate_method(method) - classDict['methods'].append(methodDict) - except AbsApi.Error as e: - print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0])) - + methodDict = self.translate_method(method) + classDict['methods'].append(methodDict) + for method in _class.classMethods: - try: - methodDict = self.translate_method(method) - classDict['staticMethods'].append(methodDict) - except AbsApi.Error as e: - print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0])) + methodDict = self.translate_method(method) + classDict['staticMethods'].append(methodDict) return classDict @@ -175,11 +174,8 @@ class CppTranslator(object): 'methods' : [] } for method in interface.methods: - try: - methodDict = self.translate_method(method, genImpl=False) - intDict['methods'].append(methodDict) - except AbsApi.Error as e: - print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0])) + methodDict = self.translate_method(method, genImpl=False) + intDict['methods'].append(methodDict) return intDict @@ -199,10 +195,14 @@ class CppTranslator(object): 'implPrototype': method.translate_as_prototype(self.langTranslator, namespace=namespace), 'deprecated': method.deprecated, 'suffix': '', - 'briefDoc': method.briefDescription.translate(self.docTranslator, tagAsBrief=True) if method.briefDescription is not None else None, - 'detailedDoc': method.detailedDescription.translate(self.docTranslator) if method.detailedDescription is not None else None } + try: + methodDict['briefDoc'] = method.briefDescription.translate(self.docTranslator, tagAsBrief=True) if method.briefDescription is not None else None + methodDict['detailedDoc'] = method.detailedDescription.translate(self.docTranslator) if method.detailedDescription is not None else None + except metadoc.TranslationError as e: + logging.error(e.msg()) + if type(method.parent) is AbsApi.Interface: if isinstance(method.returnType, AbsApi.BaseType) and method.returnType.name == 'void': methodDict['suffix'] = ' {}' @@ -465,7 +465,7 @@ class GenWrapper(object): if item[1] is not None: header.add_enum(item[1]) else: - print('warning: {0} enum won\'t be translated because of parsing errors'.format(item[0])) + logging.info('{0} enum won\'t be translated because of parsing errors'.format(item[0])) self.render(header, self.includedir + '/enums.hh') self.mainHeader.add_include('enums.hh') @@ -491,44 +491,40 @@ class GenWrapper(object): def render_header(self, _class): if _class is not None: - try: - header = ClassHeader(_class, self.translator) - headerName = _class.name.to_snake_case() + '.hh' - self.mainHeader.add_include(headerName) - self.render(header, self.includedir + '/' + header.filename) - - if type(_class) is not AbsApi.Interface: - self.impl.classes.append(header._class) - - except AbsApi.Error as e: - print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) - -def main(): - argparser = argparse.ArgumentParser(description='Generate source files for the C++ wrapper') - argparser.add_argument('xmldir', type=str, help='Directory where the XML documentation of the Linphone\'s API generated by Doxygen is placed') - argparser.add_argument('-o --output', type=str, help='the directory where to generate the source files', dest='outputdir', default='.') - args = argparser.parse_args() - - includedir = args.outputdir + '/include/linphone++' - srcdir = args.outputdir + '/src' - - try: - os.makedirs(includedir) - except OSError as e: - if e.errno != errno.EEXIST: - print("Cannot create '{0}' directory: {1}".format(includedir, e.strerror)) - sys.exit(1) - - try: - os.makedirs(srcdir) - except OSError as e: - if e.errno != errno.EEXIST: - print("Cannot create '{0}' directory: {1}".format(srcdir, e.strerror)) - sys.exit(1) - - genwrapper = GenWrapper(includedir, srcdir, args.xmldir) - genwrapper.render_all() + header = ClassHeader(_class, self.translator) + headerName = _class.name.to_snake_case() + '.hh' + self.mainHeader.add_include(headerName) + self.render(header, self.includedir + '/' + header.filename) + + if type(_class) is not AbsApi.Interface: + self.impl.classes.append(header._class) if __name__ == '__main__': - main() + try: + argparser = argparse.ArgumentParser(description='Generate source files for the C++ wrapper') + argparser.add_argument('xmldir', type=str, help='Directory where the XML documentation of the Linphone\'s API generated by Doxygen is placed') + argparser.add_argument('-o --output', type=str, help='the directory where to generate the source files', dest='outputdir', default='.') + argparser.add_argument('-v --verbose', help='Show warning and info traces.', action='store_true', default=False, dest='verbose_mode') + argparser.add_argument('-d --debug', help='Show all traces.', action='store_true', default=False, dest='debug_mode') + args = argparser.parse_args() + + if args.debug_mode: + loglevel = logging.DEBUG + elif args.verbose_mode: + loglevel = logging.INFO + else: + loglevel = logging.ERROR + logging.basicConfig(format='%(levelname)s[%(name)s]: %(message)s', level=loglevel) + + includedir = args.outputdir + '/include/linphone++' + srcdir = args.outputdir + '/src' + if not os.path.exists(includedir): + os.makedirs(includedir) + if not os.path.exists(srcdir): + os.makedirs(srcdir) + + genwrapper = GenWrapper(includedir, srcdir, args.xmldir) + genwrapper.render_all() + except AbsApi.Error as e: + logging.critical(e) diff --git a/wrappers/csharp/genwrapper.py b/wrappers/csharp/genwrapper.py index a8b9e268b..de474eea9 100644 --- a/wrappers/csharp/genwrapper.py +++ b/wrappers/csharp/genwrapper.py @@ -17,9 +17,10 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. import argparse +import logging import os -import sys import pystache +import sys sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'tools')) import genapixml as CApi @@ -401,20 +402,20 @@ class CsharpTranslator(object): methodDict = self.translate_method(method, static=True, genImpl=True) classDict['dllImports'].append(methodDict) except AbsApi.Error as e: - print('Could not translate {0}: {1}'.format(method.name.to_c(), e.args[0])) + logging.error('Could not translate {0}: {1}'.format(method.name.to_c(), e.args[0])) for prop in _class.properties: try: classDict['dllImports'] += self.translate_property(prop) except AbsApi.Error as e: - print('error while translating {0} property: {1}'.format(prop.name.to_c(), e.args[0])) + logging.error('error while translating {0} property: {1}'.format(prop.name.to_c(), e.args[0])) for method in _class.instanceMethods: try: methodDict = self.translate_method(method, static=False, genImpl=True) classDict['dllImports'].append(methodDict) except AbsApi.Error as e: - print('Could not translate {0}: {1}'.format(method.name.to_c(), e.args[0])) + logging.error('Could not translate {0}: {1}'.format(method.name.to_c(), e.args[0])) return classDict @@ -469,12 +470,17 @@ def render(renderer, item, path): f.write(content) os.unlink(tmppath) -def main(): + +if __name__ == '__main__': argparser = argparse.ArgumentParser(description='Generate source files for the C# wrapper') argparser.add_argument('xmldir', type=str, help='Directory where the XML documentation of the Linphone\'s API generated by Doxygen is placed') argparser.add_argument('-o --output', type=str, help='the directory where to generate the source files', dest='outputdir', default='.') argparser.add_argument('-n --name', type=str, help='the name of the genarated source file', dest='outputfile', default='LinphoneWrapper.cs') + argparser.add_argument('-v --verbose', action='store_true', dest='verbose_mode', default=False, help='Verbose mode.') args = argparser.parse_args() + + loglevel = logging.INFO if args.verbose_mode else logging.ERROR + logging.basicConfig(format='%(levelname)s[%(name)s]: %(message)s', level=loglevel) entries = os.listdir(args.outputdir) @@ -504,7 +510,7 @@ def main(): impl = EnumImpl(item[1], translator) enums.append(impl) else: - print('warning: {0} enum won\'t be translated because of parsing errors'.format(item[0])) + logging.warning('{0} enum won\'t be translated because of parsing errors'.format(item[0])) interfaces = [] classes = [] @@ -519,10 +525,7 @@ def main(): impl = InterfaceImpl(_class, translator) interfaces.append(impl) except AbsApi.Error as e: - print('Could not translate {0}: {1}'.format(_class.name.to_c(), e.args[0])) + logging.error('Could not translate {0}: {1}'.format(_class.name.to_c(), e.args[0])) wrapper = WrapperImpl(enums, interfaces, classes) render(renderer, wrapper, args.outputdir + "/" + args.outputfile) - -if __name__ == '__main__': - main() diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index 45399eba2..eba6ab482 100644 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -18,13 +18,13 @@ # 02110-1301, USA. import argparse -import os -import sys -import pystache import errno +import logging +import os +import pystache +import sys sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'tools')) -print(sys.path) import genapixml as CApi import abstractapi as AbsApi import metadoc @@ -456,7 +456,7 @@ class JavaTranslator(object): classDict['methods'] += self.translate_property(_property) classDict['jniMethods'] += self.translate_jni_property(_class.name, _property) except AbsApi.Error as e: - print('error while translating {0} property: {1}'.format(_property.name.to_snake_case(), e.args[0])) + logging.error('error while translating {0} property: {1}'.format(_property.name.to_snake_case(), e.args[0])) for method in _class.instanceMethods: try: @@ -465,7 +465,7 @@ class JavaTranslator(object): classDict['methods'].append(methodDict) classDict['jniMethods'].append(jniMethodDict) except AbsApi.Error as e: - print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0])) + logging.error('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0])) for method in _class.classMethods: try: @@ -474,7 +474,7 @@ class JavaTranslator(object): classDict['methods'].append(methodDict) classDict['jniMethods'].append(jniMethodDict) except AbsApi.Error as e: - print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0])) + logging.error('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0])) islistenable = _class.listenerInterface is not None if islistenable: @@ -823,7 +823,7 @@ class GenWrapper(object): self.jni.add_enum(value) if name in ENUMS_LIST: className = ENUMS_LIST[name] - print('Enum ' + name + ' belongs to class ' + className) + logging.info('Enum ' + name + ' belongs to class ' + className) self.classes[className].add_enum(value) self.enums_to_remove.append(name) @@ -859,7 +859,7 @@ class GenWrapper(object): javaenum = JavaEnum(self.package, _class, self.translator) self.enums[javaenum.className] = javaenum except AbsApi.Error as e: - print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) + logging.error('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) def render_java_interface(self, _class): if _class is not None: @@ -869,7 +869,7 @@ class GenWrapper(object): javaInterfaceStub = JavaInterfaceStub(javainterface) self.interfaces[javaInterfaceStub.classNameStub] = javaInterfaceStub except AbsApi.Error as e: - print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) + logging.error('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) self.jni.add_callbacks(javainterface.className, javainterface.jniMethods) def render_java_class(self, _class): @@ -878,20 +878,24 @@ class GenWrapper(object): javaclass = JavaClass(self.package, _class, self.translator) self.classes[javaclass.className] = javaclass except AbsApi.Error as e: - print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) + logging.error('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0])) self.jni.add_methods(javaclass.className, javaclass.jniMethods) ########################################################################## -def main(): +if __name__ == '__main__': argparser = argparse.ArgumentParser(description='Generate source files for the Java wrapper') argparser.add_argument('xmldir', type=str, help='Directory where the XML documentation of the Linphone\'s API generated by Doxygen is placed') argparser.add_argument('-o --output', type=str, help='the directory where to generate the source files', dest='outputdir', default='.') argparser.add_argument('-p --package', type=str, help='the package name for the wrapper', dest='package', default='org.linphone.core') argparser.add_argument('-n --name', type=str, help='the name of the genarated source file', dest='name', default='linphone_jni.cc') argparser.add_argument('-e --exceptions', type=bool, help='enable the wrapping of LinphoneStatus into CoreException', dest='exceptions', default=False) + argparser.add_argument('-v --verbose', action='store_true', dest='verbose_mode', default=False, help='Verbose mode.') args = argparser.parse_args() + loglevel = logging.INFO if args.verbose_mode else logging.ERROR + logging.basicConfig(format='%(levelname)s[%(name)s]: %(message)s', level=loglevel) + srcdir = args.outputdir + '/src' javadir = args.outputdir + '/java' package_dirs = args.package.split('.') @@ -902,18 +906,15 @@ def main(): os.makedirs(srcdir) except OSError as e: if e.errno != errno.EEXIST: - print("Cannot create '{0}' dircetory: {1}".format(srcdir, e.strerror)) + logging.critical("Cannot create '{0}' dircetory: {1}".format(srcdir, e.strerror)) sys.exit(1) try: os.makedirs(javadir) except OSError as e: if e.errno != errno.EEXIST: - print("Cannot create '{0}' dircetory: {1}".format(javadir, e.strerror)) + logging.critical("Cannot create '{0}' dircetory: {1}".format(javadir, e.strerror)) sys.exit(1) genwrapper = GenWrapper(srcdir, javadir, args.package, args.xmldir, args.exceptions) genwrapper.render_all() - -if __name__ == '__main__': - main() From 98d0ae00b0a9750fa5899b2b2ee5aecf603311f2 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 23 Nov 2017 16:07:30 +0100 Subject: [PATCH 0845/2215] feat(MainDb): add logs on chat rooms fetch --- src/core/core-chat-room.cpp | 2 +- src/db/main-db.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 0bff00f42..3b09ef51a 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -130,7 +130,7 @@ shared_ptr Core::findChatRoom (const ChatRoomId &chatRoomId) const { if (it != d->chatRoomsById.cend()) return it->second; - lInfo() << "Unable to find chat room: (peer=" << + lInfo() << "Unable to find chat room in RAM: (peer=" << chatRoomId.getPeerAddress().asString() << ", local=" << chatRoomId.getLocalAddress().asString() << ")."; return shared_ptr(); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 5266f322d..5eb1f214a 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1410,6 +1410,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), dChatRoom->creationTime = Utils::getTmAsTimeT(creationDate); dChatRoom->lastUpdateTime = Utils::getTmAsTimeT(lastUpdateDate); + lInfo() << "Found chat room in DB: (peer=" << + chatRoomId.getPeerAddress().asString() << ", local=" << chatRoomId.getLocalAddress().asString() << ")."; + chatRooms.push_back(chatRoom); } From 60915d8a159424576ad3db515a91cf49d7aad286 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 23 Nov 2017 16:08:48 +0100 Subject: [PATCH 0846/2215] add missing ':' --- src/db/main-db.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 5eb1f214a..493dfe28f 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -179,7 +179,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), ", local=" << localSipAddressId << ", capabilities=" << capabilities << ")."; *session << "INSERT INTO chat_room (" " peer_sip_address_id, local_sip_address_id, creation_date, last_update_date, capabilities, subject" - ") VALUES (:peerSipAddressId, :localSipAddressId, :creationDate, :lastUpdateDate, :capabilities, subject)", + ") VALUES (:peerSipAddressId, :localSipAddressId, :creationDate, :lastUpdateDate, :capabilities, :subject)", soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::use(date), soci::use(date), soci::use(capabilities), soci::use(subject); From ec7fd6d2586e658400d94f593d1de4c8bae24608 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 23 Nov 2017 16:42:20 +0100 Subject: [PATCH 0847/2215] Store ChatMessage in db after sending and upon reception --- src/chat/chat-message/chat-message-p.h | 2 ++ src/chat/chat-message/chat-message.cpp | 15 +++++++++++++-- src/core/core.h | 2 ++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index 92e33a994..6095df842 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -121,6 +121,8 @@ public: LinphoneReason receive(); void send(); + void store(); + private: // TODO: Clean attributes. unsigned int storageId = 0; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index fbed81566..8b286dcaa 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -35,6 +35,8 @@ #include "content/file-content.h" #include "content/content.h" #include "core/core.h" +#include "core/core-p.h" +#include "event-log/conference/conference-chat-message-event.h" #include "logger/logger.h" #include "chat/notification/imdn.h" @@ -428,8 +430,9 @@ LinphoneReason ChatMessagePrivate::receive () { messageToBeStored = true; } } - if (messageToBeStored) - q->store(); + if (messageToBeStored) { + store(); + } return reason; } @@ -560,6 +563,8 @@ void ChatMessagePrivate::send () { q->setImdnMessageId(op->get_call_id()); /* must be known at that time */ + store(); + if (call && linphone_call_get_op(call) == op) { /* In this case, chat delivery status is not notified, so unrefing chat message right now */ /* Might be better fixed by delivering status, but too costly for now */ @@ -573,6 +578,12 @@ void ChatMessagePrivate::send () { } } +void ChatMessagePrivate::store() { + L_Q(); + shared_ptr eventLog = make_shared(time, q->getSharedFromThis()); + q->getChatRoom()->getCore()->getPrivate()->mainDb->addEvent(eventLog); +} + // ----------------------------------------------------------------------------- ChatMessage::ChatMessage (const shared_ptr &chatRoom, ChatMessage::Direction direction) : diff --git a/src/core/core.h b/src/core/core.h index 283615bb8..3291e27ca 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -32,12 +32,14 @@ LINPHONE_BEGIN_NAMESPACE class Address; class ChatRoom; +class ChatMessagePrivate; class ChatRoomId; class CorePrivate; class IdentityAddress; class LINPHONE_PUBLIC Core : public Object { friend class ChatRoom; + friend class ChatMessagePrivate; friend class ClientGroupChatRoom; friend class LocalConferenceEventHandlerPrivate; friend class MainDb; From b12304668a64eab12bc98e947eb762a26856d00f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 23 Nov 2017 17:26:10 +0100 Subject: [PATCH 0848/2215] Added update methods for ChatMessageEvents and ChatMessageContent --- src/db/main-db-event-key.h | 1 + src/db/main-db-p.h | 2 + src/db/main-db.cpp | 80 ++++++++++++++++++++++++++++++++++++++ src/db/main-db.h | 1 + 4 files changed, 84 insertions(+) diff --git a/src/db/main-db-event-key.h b/src/db/main-db-event-key.h index 37ea05c35..5b9c90dbf 100644 --- a/src/db/main-db-event-key.h +++ b/src/db/main-db-event-key.h @@ -33,6 +33,7 @@ class MainDbEventKeyPrivate; class MainDbEventKey : public ClonableObject { friend class MainDb; + friend class MainDbPrivate; public: MainDbEventKey (); diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index d51e9ca0b..85fb696cf 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -41,6 +41,7 @@ private: long long insertSipAddress (const std::string &sipAddress); void insertContent (long long messageEventId, const Content &content); + void updateContent (long long messageEventId, long long messageContentId, const Content &content); long long insertContentType (const std::string &contentType); long long insertChatRoom ( long long peerSipAddressId, @@ -114,6 +115,7 @@ private: long long insertConferenceEvent (const std::shared_ptr &eventLog, long long *chatRoomId = nullptr); long long insertConferenceCallEvent (const std::shared_ptr &eventLog); long long insertConferenceChatMessageEvent (const std::shared_ptr &eventLog); + void updateConferenceChatMessageEvent(const std::shared_ptr &eventLog); long long insertConferenceNotifiedEvent (const std::shared_ptr &eventLog, long long *chatRoomId = nullptr); long long insertConferenceParticipantEvent (const std::shared_ptr &eventLog); long long insertConferenceParticipantDeviceEvent (const std::shared_ptr &eventLog); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 493dfe28f..6752209dc 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -148,6 +148,18 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::use(messageContentId), soci::use(appData.first), soci::use(appData.second); } + void MainDbPrivate::updateContent (long long eventId, long long messageContentId, const Content &content) { + soci::session *session = dbSession.getBackendSession(); + + long long contentTypeId = insertContentType(content.getContentType().asString()); + *session << "UPDATE chat_message_content SET content_type_id=:contentTypeId, body=:body WHERE event_id=:eventId", + soci::use(contentTypeId), soci::use(content.getBodyAsString()), soci::use(eventId); + + for (const auto &appData : content.getAppDataMap()) + *session << "UPDATE chat_message_content_app_data SET name=:name, data=:data WHERE chat_message_content_id=:messageContentId", + soci::use(appData.first), soci::use(appData.second), soci::use(messageContentId); + } + long long MainDbPrivate::insertContentType (const string &contentType) { L_Q(); soci::session *session = dbSession.getBackendSession(); @@ -581,6 +593,27 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return eventId; } + void MainDbPrivate::updateConferenceChatMessageEvent(const std::shared_ptr &eventLog) { + shared_ptr chatMessage = static_pointer_cast(eventLog)->getChatMessage(); + shared_ptr chatRoom = chatMessage->getChatRoom(); + if (!chatRoom) { + lError() << "Unable to get a valid chat room. It was removed from database."; + return; + } + + const EventLogPrivate *dEventLog = eventLog->getPrivate(); + MainDbEventKeyPrivate *dEventKey = dEventLog->dbKey.getPrivate(); + long long eventId = dEventKey->storageId; + + soci::session *session = dbSession.getBackendSession(); + *session << "UPDATE conference_chat_message_event SET state=:state WHERE event_id=:eventId" + , soci::use(static_cast(chatMessage->getState())), soci::use(eventId); + + /*for (const Content *content : chatMessage->getContents()) + updateContent(eventId, *content);*/ + //TODO check if content needs to be inserted, updated or removed + } + long long MainDbPrivate::insertConferenceNotifiedEvent (const shared_ptr &eventLog, long long *chatRoomId) { long long curChatRoomId; long long eventId = insertConferenceEvent(eventLog, &curChatRoomId); @@ -1014,6 +1047,53 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return soFarSoGood; } + bool MainDb::updateEvent (const shared_ptr &eventLog) { + L_D(); + + if (!isConnected()) { + lWarning() << "Unable to update event. Not connected."; + return false; + } + + const EventLogPrivate *dEventLog = eventLog->getPrivate(); + if (!dEventLog->dbKey.isValid()) { + lWarning() << "Unable to update an event that wasn't inserted yet!!!"; + return false; + } + + L_BEGIN_LOG_EXCEPTION + + soci::transaction tr(*d->dbSession.getBackendSession()); + + switch (eventLog->getType()) { + case EventLog::Type::None: + return false; + + case EventLog::Type::ConferenceChatMessage: + d->updateConferenceChatMessageEvent(eventLog); + break; + + case EventLog::Type::ConferenceCreated: + case EventLog::Type::ConferenceDestroyed: + case EventLog::Type::ConferenceCallStart: + case EventLog::Type::ConferenceCallEnd: + case EventLog::Type::ConferenceParticipantAdded: + case EventLog::Type::ConferenceParticipantRemoved: + case EventLog::Type::ConferenceParticipantSetAdmin: + case EventLog::Type::ConferenceParticipantUnsetAdmin: + case EventLog::Type::ConferenceParticipantDeviceAdded: + case EventLog::Type::ConferenceParticipantDeviceRemoved: + case EventLog::Type::ConferenceSubjectChanged: + return false; + } + + tr.commit(); + + L_END_LOG_EXCEPTION + + return true; + } + bool MainDb::deleteEvent (const shared_ptr &eventLog) { EventLogPrivate *dEventLog = eventLog->getPrivate(); if (!dEventLog->dbKey.isValid()) { diff --git a/src/db/main-db.h b/src/db/main-db.h index 5e776482b..289ef0a05 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -56,6 +56,7 @@ public: // --------------------------------------------------------------------------- bool addEvent (const std::shared_ptr &eventLog); + bool updateEvent (const std::shared_ptr &eventLog); static bool deleteEvent (const std::shared_ptr &eventLog); int getEventsCount (FilterMask mask = NoFilter) const; From 191a9f24ba2ad380cff353707d3714662c7226d8 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 23 Nov 2017 17:31:02 +0100 Subject: [PATCH 0849/2215] Store chatEvent in chatMessage and update the database event when chatMessage's state changes --- src/chat/chat-message/chat-message-p.h | 2 ++ src/chat/chat-message/chat-message.cpp | 14 +++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index 6095df842..b7c2d54b2 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -30,6 +30,7 @@ #include "content/content.h" #include "content/file-content.h" #include "content/file-transfer-content.h" +#include "event-log/conference/conference-chat-message-event.h" #include "object/object-p.h" #include "sal/sal.h" @@ -153,6 +154,7 @@ private: // Do not expose. std::weak_ptr chatRoom; + std::weak_ptr chatEvent; ChatRoomId chatRoomId; IdentityAddress fromAddress; IdentityAddress toAddress; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 8b286dcaa..6364db82a 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -36,7 +36,6 @@ #include "content/content.h" #include "core/core.h" #include "core/core-p.h" -#include "event-log/conference/conference-chat-message-event.h" #include "logger/logger.h" #include "chat/notification/imdn.h" @@ -97,6 +96,8 @@ void ChatMessagePrivate::setState (ChatMessage::State s, bool force) { LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); if (cbs && linphone_chat_message_cbs_get_msg_state_changed(cbs)) linphone_chat_message_cbs_get_msg_state_changed(cbs)(msg, linphone_chat_message_get_state(msg)); + + store(); } unsigned int ChatMessagePrivate::getStorageId () const { @@ -580,8 +581,15 @@ void ChatMessagePrivate::send () { void ChatMessagePrivate::store() { L_Q(); - shared_ptr eventLog = make_shared(time, q->getSharedFromThis()); - q->getChatRoom()->getCore()->getPrivate()->mainDb->addEvent(eventLog); + + shared_ptr eventLog = chatEvent.lock(); + if (eventLog) { + q->getChatRoom()->getCore()->getPrivate()->mainDb->updateEvent(eventLog); + } else { + eventLog = make_shared(time, q->getSharedFromThis()); + chatEvent = eventLog; + q->getChatRoom()->getCore()->getPrivate()->mainDb->addEvent(eventLog); + } } // ----------------------------------------------------------------------------- From 8a0b0669600820f1ed3a749e54ec378780f0162a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 24 Nov 2017 10:44:20 +0100 Subject: [PATCH 0850/2215] Changes in transient messages in chat room, replaced by transient event logs --- coreapi/private.h | 1 - coreapi/tester_utils.h | 1 - src/c-wrapper/api/c-chat-room.cpp | 8 --- src/chat/chat-message/chat-message.cpp | 46 ++++++------- src/chat/chat-message/chat-message.h | 1 - src/chat/chat-room/chat-room-p.h | 19 ++---- src/chat/chat-room/chat-room.cpp | 66 +++---------------- .../chat-room/real-time-text-chat-room.cpp | 2 +- src/chat/chat-room/server-group-chat-room-p.h | 1 - .../chat-room/server-group-chat-room-stub.cpp | 2 - .../file-transfer-chat-message-modifier.cpp | 6 -- tester/message_tester.c | 14 ++-- 12 files changed, 43 insertions(+), 124 deletions(-) diff --git a/coreapi/private.h b/coreapi/private.h index efe81bb52..fc2bc54e3 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -489,7 +489,6 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, cons LinphoneChatRoom *_linphone_server_group_chat_room_new (LinphoneCore *core, LinphonePrivate::SalCallOp *op); void linphone_chat_room_release(LinphoneChatRoom *cr); void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call); -bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr); LinphoneChatRoomCbs * linphone_chat_room_cbs_new (void); /**/ diff --git a/coreapi/tester_utils.h b/coreapi/tester_utils.h index 2dade201e..862d1043a 100644 --- a/coreapi/tester_utils.h +++ b/coreapi/tester_utils.h @@ -93,7 +93,6 @@ LINPHONE_PUBLIC mblk_t *_linphone_call_stats_get_received_rtcp (const LinphoneCa LINPHONE_PUBLIC LinphoneQualityReporting *linphone_call_log_get_quality_reporting(LinphoneCallLog *call_log); LINPHONE_PUBLIC reporting_session_report_t **linphone_quality_reporting_get_reports(LinphoneQualityReporting *qreporting); -LINPHONE_PUBLIC bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr); LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_find_chat_room (const LinphoneCore *lc, const LinphoneAddress *peerAddr, const LinphoneAddress *localAddr); LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_from_db(LinphoneCore *lc, LinphoneFriendList *list); diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 7f329f082..3291afc31 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -71,10 +71,6 @@ void linphone_chat_room_release (LinphoneChatRoom *cr) { L_GET_PRIVATE_FROM_C_OBJECT(cr)->release(); } -void linphone_chat_room_remove_transient_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) { - L_GET_PRIVATE_FROM_C_OBJECT(cr)->removeTransientMessage(L_GET_CPP_PTR_FROM_C_OBJECT(msg)); -} - void linphone_chat_room_send_message (LinphoneChatRoom *cr, const char *msg) { L_GET_PRIVATE_FROM_C_OBJECT(cr)->sendMessage(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createMessage(msg)); } @@ -174,10 +170,6 @@ void linphone_chat_room_set_call (LinphoneChatRoom *cr, LinphoneCall *call) { L_GET_PRIVATE_FROM_C_OBJECT(cr, RealTimeTextChatRoom)->call = call; } -bctbx_list_t *linphone_chat_room_get_transient_messages (const LinphoneChatRoom *cr) { - return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_PRIVATE_FROM_C_OBJECT(cr)->getTransientMessages()); -} - void linphone_chat_room_mark_as_read (LinphoneChatRoom *cr) { L_GET_CPP_PTR_FROM_C_OBJECT(cr)->markAsRead(); } diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 6364db82a..8b9a27411 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -518,7 +518,7 @@ void ChatMessagePrivate::send () { if (result == ChatMessageModifier::Result::Error) { sal_error_info_set((SalErrorInfo *)op->get_error_info(), SalReasonNotAcceptable, "SIP", errorCode, "Unable to encrypt IM", nullptr); q->updateState(ChatMessage::State::NotDelivered); - q->store(); + store(); return; } else if (result == ChatMessageModifier::Result::Suspended) { currentSendStep |= ChatMessagePrivate::Step::Encryption; @@ -585,10 +585,32 @@ void ChatMessagePrivate::store() { shared_ptr eventLog = chatEvent.lock(); if (eventLog) { q->getChatRoom()->getCore()->getPrivate()->mainDb->updateEvent(eventLog); + + if (direction == ChatMessage::Direction::Incoming) { + if (!hasFileTransferContent()) { + // Incoming message doesn't have any download waiting anymore, we can remove it's event from the transients + q->getChatRoom()->getPrivate()->removeTransientEvent(eventLog); + } + } else { + if (state == ChatMessage::State::Delivered || state == ChatMessage::State::NotDelivered) { + // Once message has reached this state it won't change anymore so we can remove the event from the transients + q->getChatRoom()->getPrivate()->removeTransientEvent(eventLog); + } + } } else { eventLog = make_shared(time, q->getSharedFromThis()); chatEvent = eventLog; q->getChatRoom()->getCore()->getPrivate()->mainDb->addEvent(eventLog); + + if (direction == ChatMessage::Direction::Incoming) { + if (hasFileTransferContent()) { + // Keep the event in the transient list, message storage can be updated in near future + q->getChatRoom()->getPrivate()->addTransientEvent(eventLog); + } + } else { + // Keep event in transient to be able to store in database state changes + q->getChatRoom()->getPrivate()->addTransientEvent(eventLog); + } } } @@ -760,32 +782,10 @@ void ChatMessage::removeCustomHeader (const string &headerName) { d->customHeaders.erase(headerName); } -void ChatMessage::store () { - L_D(); - - if (d->storageId != 0) { - /* The message has already been stored (probably because of file transfer), update it */ - // TODO: history. - // linphone_chat_message_store_update(L_GET_C_BACK_PTR(this)); - } else { - /* Store the new message */ - // TODO: history. - // linphone_chat_message_store(L_GET_C_BACK_PTR(this)); - } -} - void ChatMessage::updateState (State state) { L_D(); d->setState(state); - // TODO: history. - // linphone_chat_message_store_state(L_GET_C_BACK_PTR(this)); - - if (state == State::Delivered || state == State::NotDelivered) { - shared_ptr chatRoom = getChatRoom(); - if (chatRoom) - chatRoom->getPrivate()->moveTransientMessageToWeakMessages(getSharedFromThis()); - } } void ChatMessage::send () { diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index 952b3abd3..7fdf0e61d 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -65,7 +65,6 @@ public: void sendDisplayNotification (); void setImdnMessageId (const std::string &imdnMessageId); void setIsSecured (bool isSecured); - void store (); // ----- TODO: Remove me. std::shared_ptr getChatRoom () const; diff --git a/src/chat/chat-room/chat-room-p.h b/src/chat/chat-room/chat-room-p.h index a4fd64b20..853c2f557 100644 --- a/src/chat/chat-room/chat-room-p.h +++ b/src/chat/chat-room/chat-room-p.h @@ -25,6 +25,7 @@ #include "chat/notification/is-composing.h" #include "chat-room.h" #include "object/object-p.h" +#include "event-log/event-log.h" // ============================================================================= @@ -37,14 +38,8 @@ public: static int createChatMessageFromDb (void *data, int argc, char **argv, char **colName); - void addTransientMessage (const std::shared_ptr &msg); - void addWeakMessage (const std::shared_ptr &msg); - std::list> getTransientMessages () const { - return transientMessages; - } - - void moveTransientMessageToWeakMessages (const std::shared_ptr &msg); - void removeTransientMessage (const std::shared_ptr &msg); + void addTransientEvent (const std::shared_ptr &log); + void removeTransientEvent (const std::shared_ptr &log); void release (); @@ -55,12 +50,8 @@ public: void sendIsComposingNotification (); int createChatMessageFromDb (int argc, char **argv, char **colName); - std::shared_ptr getTransientMessage (unsigned int storageId) const; - std::shared_ptr getWeakMessage (unsigned int storageId) const; std::list> findMessages (const std::string &messageId); - virtual void storeOrUpdateMessage (const std::shared_ptr &msg); - virtual LinphoneReason messageReceived (SalOp *op, const SalMessage *msg); void realtimeTextReceived (uint32_t character, LinphoneCall *call); @@ -84,9 +75,7 @@ public: ChatRoom::State state = ChatRoom::State::None; bool isComposing = false; std::list
      remoteIsComposing; - std::list> transientMessages; - - std::list> weakMessages; + std::list> transientEvents; // TODO: Remove me. Must be present only in rtt chat room. std::shared_ptr pendingMessage; diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 652c30d83..1cda16c65 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -42,32 +42,16 @@ int ChatRoomPrivate::createChatMessageFromDb (void *data, int argc, char **argv, // ----------------------------------------------------------------------------- -void ChatRoomPrivate::addTransientMessage (const shared_ptr &msg) { - auto iter = find(transientMessages.begin(), transientMessages.end(), msg); - if (iter == transientMessages.end()) - transientMessages.push_back(msg); +void ChatRoomPrivate::addTransientEvent (const shared_ptr &log) { + auto iter = find(transientEvents.begin(), transientEvents.end(), log); + if (iter == transientEvents.end()) + transientEvents.push_back(log); } -void ChatRoomPrivate::addWeakMessage (const shared_ptr &msg) { - weak_ptr weakptr(msg); - weakMessages.push_back(weakptr); -} - -void ChatRoomPrivate::moveTransientMessageToWeakMessages (const shared_ptr &msg) { - auto iter = find(transientMessages.begin(), transientMessages.end(), msg); - if (iter != transientMessages.end()) { - /* msg is not transient anymore, we can remove it from our transient list and unref it */ - addWeakMessage(msg); - removeTransientMessage(msg); - } else { - /* msg has already been removed from the transient messages, do nothing */ - } -} - -void ChatRoomPrivate::removeTransientMessage (const shared_ptr &msg) { - auto iter = find(transientMessages.begin(), transientMessages.end(), msg); - if (iter != transientMessages.end()) { - transientMessages.erase(iter); +void ChatRoomPrivate::removeTransientEvent (const shared_ptr &log) { + auto iter = find(transientEvents.begin(), transientEvents.end(), log); + if (iter != transientEvents.end()) { + transientEvents.erase(iter); } } @@ -75,12 +59,6 @@ void ChatRoomPrivate::removeTransientMessage (const shared_ptr &msg void ChatRoomPrivate::release () { isComposingHandler->stopTimers(); - - for (auto &message : weakMessages) - message.lock()->cancelFileTransfer(); - - for (auto &message : transientMessages) - message->cancelFileTransfer(); } // ----------------------------------------------------------------------------- @@ -175,42 +153,16 @@ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colN return 0; } -shared_ptr ChatRoomPrivate::getTransientMessage (unsigned int storageId) const { - for (auto &message : transientMessages) { - if (message->getPrivate()->getStorageId() == storageId) - return message; - } - return nullptr; -} - -std::shared_ptr ChatRoomPrivate::getWeakMessage (unsigned int storageId) const { - for (auto &message : weakMessages) { - try { - shared_ptr msg(message); - if (msg->getPrivate()->getStorageId() == storageId) - return msg; - } catch(const std::bad_weak_ptr& e) {} - } - return nullptr; -} - list > ChatRoomPrivate::findMessages (const string &messageId) { // TODO: history. return list>(); } -void ChatRoomPrivate::storeOrUpdateMessage (const shared_ptr &msg) { - msg->store(); -} - void ChatRoomPrivate::sendMessage (const shared_ptr &msg) { L_Q(); // TODO: Check direction. - /* Add to transient list */ - addTransientMessage(msg); - msg->getPrivate()->setTime(ms_time(0)); msg->getPrivate()->send(); @@ -222,8 +174,6 @@ void ChatRoomPrivate::sendMessage (const shared_ptr &msg) { cb(cr, L_GET_C_BACK_PTR(event)); } - storeOrUpdateMessage(msg); - if (isComposing) isComposing = false; isComposingHandler->stopIdleTimer(); diff --git a/src/chat/chat-room/real-time-text-chat-room.cpp b/src/chat/chat-room/real-time-text-chat-room.cpp index 6242b51b1..2f3d7a853 100644 --- a/src/chat/chat-room/real-time-text-chat-room.cpp +++ b/src/chat/chat-room/real-time-text-chat-room.cpp @@ -77,7 +77,7 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp pendingMessage->getPrivate()->setDirection(ChatMessage::Direction::Incoming); if (lp_config_get_int(cCore->config, "misc", "store_rtt_messages", 1) == 1) - storeOrUpdateMessage(pendingMessage); + pendingMessage->getPrivate()->store(); chatMessageReceived(pendingMessage); pendingMessage = nullptr; diff --git a/src/chat/chat-room/server-group-chat-room-p.h b/src/chat/chat-room/server-group-chat-room-p.h index 2b003fdac..18c0830da 100644 --- a/src/chat/chat-room/server-group-chat-room-p.h +++ b/src/chat/chat-room/server-group-chat-room-p.h @@ -47,7 +47,6 @@ public: void update (SalCallOp *op); void dispatchMessage (const IdentityAddress &fromAddr, const Content &content); - void storeOrUpdateMessage (const std::shared_ptr &msg) override; LinphoneReason messageReceived (SalOp *op, const SalMessage *msg) override; void setConferenceAddress (const IdentityAddress &confAddr); diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index 1a3999e9f..e0ffc5ef9 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -57,8 +57,6 @@ void ServerGroupChatRoomPrivate::update (SalCallOp *) {} void ServerGroupChatRoomPrivate::dispatchMessage (const IdentityAddress &, const Content &) {} -void ServerGroupChatRoomPrivate::storeOrUpdateMessage (const shared_ptr &) {} - LinphoneReason ServerGroupChatRoomPrivate::messageReceived (SalOp *, const SalMessage *) { return LinphoneReasonNone; } diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.cpp b/src/chat/modifier/file-transfer-chat-message-modifier.cpp index 377be8e81..6016ad50c 100644 --- a/src/chat/modifier/file-transfer-chat-message-modifier.cpp +++ b/src/chat/modifier/file-transfer-chat-message-modifier.cpp @@ -401,9 +401,6 @@ void FileTransferChatMessageModifier::processIoErrorUpload (const belle_sip_io_e lError() << "I/O Error during file upload of msg [" << this << "]"; chatMessage->updateState(ChatMessage::State::NotDelivered); releaseHttpRequest(); - - if (chatRoom) - chatRoom->getPrivate()->removeTransientMessage(chatMessage); } static void _chat_message_process_auth_requested_upload (void *data, belle_sip_auth_event *event) { @@ -415,9 +412,6 @@ void FileTransferChatMessageModifier::processAuthRequestedUpload (const belle_si lError() << "Error during file upload: auth requested for msg [" << this << "]"; chatMessage->updateState(ChatMessage::State::NotDelivered); releaseHttpRequest(); - - if (chatRoom) - chatRoom->getPrivate()->removeTransientMessage(chatMessage); } int FileTransferChatMessageModifier::uploadFile () { diff --git a/tester/message_tester.c b/tester/message_tester.c index 77242f3ef..2f7732039 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -416,15 +416,15 @@ static void text_message_with_send_error(void) { linphone_chat_room_send_chat_message(chat_room,msg); /* check transient msg list: the msg should be in it, and should be the only one */ - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_chat_room_get_transient_messages(chat_room)), 1, unsigned int, "%u"); - BC_ASSERT_PTR_EQUAL(bctbx_list_nth_data(linphone_chat_room_get_transient_messages(chat_room),0), msg); + /*BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_chat_room_get_transient_messages(chat_room)), 1, unsigned int, "%u"); + BC_ASSERT_PTR_EQUAL(bctbx_list_nth_data(linphone_chat_room_get_transient_messages(chat_room),0), msg);*/ BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageNotDelivered,1)); /*BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageInProgress,1, int, "%d");*/ BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageReceived,0, int, "%d"); /* the msg should have been discarded from transient list after an error */ - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_chat_room_get_transient_messages(chat_room)), 0, unsigned int, "%u"); + //BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_chat_room_get_transient_messages(chat_room)), 0, unsigned int, "%u"); sal_set_send_error(linphone_core_get_sal(marie->lc), 0); @@ -449,8 +449,8 @@ static void text_message_with_external_body(void) { linphone_chat_room_send_chat_message(chat_room,msg); /* check transient msg list: the msg should be in it, and should be the only one */ - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_chat_room_get_transient_messages(chat_room)), 1, unsigned int, "%u"); - BC_ASSERT_PTR_EQUAL(bctbx_list_nth_data(linphone_chat_room_get_transient_messages(chat_room),0), msg); + /*BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_chat_room_get_transient_messages(chat_room)), 1, unsigned int, "%u"); + BC_ASSERT_PTR_EQUAL(bctbx_list_nth_data(linphone_chat_room_get_transient_messages(chat_room),0), msg);*/ BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); @@ -458,7 +458,7 @@ static void text_message_with_external_body(void) { BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1, int, "%d"); BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,1, int, "%d"); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_chat_room_get_transient_messages(chat_room)), 0, unsigned int, "%u"); + //BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(linphone_chat_room_get_transient_messages(chat_room)), 0, unsigned int, "%u"); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -2385,7 +2385,6 @@ void file_and_text_message(void) { test_t message_tests[] = { TEST_NO_TAG("File + Text message", file_and_text_message), TEST_NO_TAG("Text message", text_message), - TEST_NO_TAG("Text message within call dialog", text_message_within_call_dialog), TEST_NO_TAG("Text message with credentials from auth callback", text_message_with_credential_from_auth_callback), TEST_NO_TAG("Text message with privacy", text_message_with_privacy), TEST_NO_TAG("Text message compatibility mode", text_message_compatibility_mode), @@ -2454,6 +2453,7 @@ test_t message_tests[] = { TEST_NO_TAG("IM Encryption Engine b64", im_encryption_engine_b64), TEST_NO_TAG("IM Encryption Engine b64 async", im_encryption_engine_b64_async), // Crash currently + TEST_NO_TAG("Text message within call dialog", text_message_within_call_dialog), TEST_NO_TAG("Info message", info_message), TEST_NO_TAG("Info message with body", info_message_with_body), TEST_NO_TAG("Crash during file transfer", crash_during_file_transfer), From a8bd137c9dba49244ae74c70005d0da08210dc16 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 24 Nov 2017 11:41:53 +0100 Subject: [PATCH 0851/2215] workaround for fetching chatroom events --- src/db/main-db.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 6752209dc..22cf39015 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -389,7 +389,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), // 2 - Fetch contents. { soci::session *session = dbSession.getBackendSession(); - const string query = "SELECT content_type.value, body FROM chat_message_content, content_type" + const string query = "SELECT content_type.id, content_type.value, body FROM chat_message_content, content_type" " WHERE event_id = :eventId AND content_type_id = content_type.id"; soci::rowset rows = (session->prepare << query, soci::use(eventId)); for (const auto &row : rows) { @@ -1345,22 +1345,23 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return events; } - string query = "SELECT id, type, date FROM event" - " WHERE id IN (" - " SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" - " )"; - query += buildSqlEventFilter({ + stringstream query; + query << "SELECT id, type, date FROM event" + " WHERE id IN (" + " SELECT event_id FROM conference_event WHERE chat_room_id = " << d->selectChatRoomId(chatRoomId) << + " )"; + query << buildSqlEventFilter({ ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter }, mask, "AND"); - query += " ORDER BY date DESC"; + query << " ORDER BY date DESC"; - if (end >= 0) - query += " LIMIT " + Utils::toString(end + 1 - begin); + if (end > 0) + query << " LIMIT " << Utils::toString(end - begin); else - query += " LIMIT -1"; + query << " LIMIT -1"; if (begin > 0) - query += " OFFSET " + Utils::toString(begin); + query << " OFFSET " << Utils::toString(begin); DurationLogger durationLogger( "Get history range of: (peer=" + chatRoomId.getPeerAddress().asString() + @@ -1373,7 +1374,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = d->dbSession.getBackendSession(); soci::transaction tr(*session); - soci::rowset rows = (session->prepare << query, soci::use(d->selectChatRoomId(chatRoomId))); + soci::rowset rows = (session->prepare << query.str());//, soci::use(static_cast(d->selectChatRoomId(chatRoomId)))); for (const auto &row : rows) { // See: http://soci.sourceforge.net/doc/master/backends/ // `row id` is not supported by soci on Sqlite3. It's necessary to cast id to int... From 9449315cba30823d09cda54b94c321f035deccad Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 24 Nov 2017 11:56:48 +0100 Subject: [PATCH 0852/2215] fetch conference events in the correct order --- src/db/main-db.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 22cf39015..c4ceb2409 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1390,7 +1390,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), ); if (event) - events.push_back(event); + events.push_front(event); else lWarning() << "Unable to fetch event: " << eventId; } From 5483d48236d2b1d2a3715cbe124ddbbe7ee9ff0d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 24 Nov 2017 12:03:36 +0100 Subject: [PATCH 0853/2215] Removed absent method declaration --- src/chat/chat-message/chat-message-p.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index b7c2d54b2..784fd062b 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -148,8 +148,6 @@ private: ContentType cContentType; std::string cText; - std::string createImdnXml(Imdn::Type imdnType, LinphoneReason reason); - // TODO: Remove my comment. VARIABLES OK. // Do not expose. From beadb7bf7d546498f9fb9b4c8bf444706180c047 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 24 Nov 2017 14:05:56 +0100 Subject: [PATCH 0854/2215] feat(MainDb): avoid stringstream --- src/db/main-db.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index c4ceb2409..e728a1180 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1345,23 +1345,23 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return events; } - stringstream query; - query << "SELECT id, type, date FROM event" - " WHERE id IN (" - " SELECT event_id FROM conference_event WHERE chat_room_id = " << d->selectChatRoomId(chatRoomId) << - " )"; - query << buildSqlEventFilter({ + string query = "SELECT id, type, date FROM event" + " WHERE id IN (" + " SELECT event_id FROM conference_event WHERE chat_room_id = " + + Utils::toString(d->selectChatRoomId(chatRoomId)) + + " )"; + query += buildSqlEventFilter({ ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter }, mask, "AND"); - query << " ORDER BY date DESC"; + query += " ORDER BY date DESC"; if (end > 0) - query << " LIMIT " << Utils::toString(end - begin); + query += " LIMIT " + Utils::toString(end - begin); else - query << " LIMIT -1"; + query += " LIMIT -1"; if (begin > 0) - query << " OFFSET " << Utils::toString(begin); + query += " OFFSET " + Utils::toString(begin); DurationLogger durationLogger( "Get history range of: (peer=" + chatRoomId.getPeerAddress().asString() + @@ -1374,7 +1374,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = d->dbSession.getBackendSession(); soci::transaction tr(*session); - soci::rowset rows = (session->prepare << query.str());//, soci::use(static_cast(d->selectChatRoomId(chatRoomId)))); + soci::rowset rows = (session->prepare << query); for (const auto &row : rows) { // See: http://soci.sourceforge.net/doc/master/backends/ // `row id` is not supported by soci on Sqlite3. It's necessary to cast id to int... From b3d1d7f9bb15767e4bfcebf75661ed4dd7bc3d65 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 24 Nov 2017 14:19:39 +0100 Subject: [PATCH 0855/2215] Do not store outgoing IMDNs and IsComposing --- src/chat/chat-message/chat-message.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 8b9a27411..aa69c4a38 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -552,6 +552,13 @@ void ChatMessagePrivate::send () { } else msgOp->send_message(ContentType::PlainText.asString().c_str(), internalContent.getBodyAsString().c_str()); + bool messageToBeStored = false; + for (Content *c : contents) { + if (c->getContentType() == ContentType::FileTransfer || c->getContentType() == ContentType::PlainText) { + messageToBeStored = true; + } + } + for (Content *content : contents) { // Restore FileContents and remove FileTransferContents if (content->getContentType() == ContentType::FileTransfer) { @@ -564,7 +571,9 @@ void ChatMessagePrivate::send () { q->setImdnMessageId(op->get_call_id()); /* must be known at that time */ - store(); + if (messageToBeStored) { + store(); + } if (call && linphone_call_get_op(call) == op) { /* In this case, chat delivery status is not notified, so unrefing chat message right now */ From 5b328c01a800a9357efb7d5276202622a5d34c03 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 24 Nov 2017 14:31:26 +0100 Subject: [PATCH 0856/2215] Did FileContent db storage --- src/db/main-db.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index e728a1180..00220947e 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -142,6 +142,14 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::use(content.getBodyAsString()); long long messageContentId = q->getLastInsertId(); + if (content.getContentType().isFile()) { + const FileContent *fileContent = (const FileContent *)&content; + *session << "INSERT INTO chat_message_file_content (chat_message_content_id, name, size, path) VALUES " + " (:contentId, :name, :size, :path)", + soci::use(messageContentId), soci::use(fileContent->getFileName()), + soci::use(fileContent->getFileSize()), soci::use(fileContent->getFilePath()); + } + for (const auto &appData : content.getAppDataMap()) *session << "INSERT INTO chat_message_content_app_data (chat_message_content_id, name, data) VALUES" " (:messageContentId, :name, :data)", From 758729ba11bb916db702c2141c75179f7f742671 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 24 Nov 2017 14:45:14 +0100 Subject: [PATCH 0857/2215] feat(MainDb): add devices table, replace date to time --- src/db/main-db-p.h | 18 +++--- src/db/main-db.cpp | 136 +++++++++++++++++++++++++++------------------ 2 files changed, 91 insertions(+), 63 deletions(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 85fb696cf..5c547bc68 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -47,10 +47,10 @@ private: long long peerSipAddressId, long long localSipAddressId, int capabilities, - const tm &date, + const tm &creationTime, const std::string &subject ); - long long insertChatRoom (const ChatRoomId &chatRoomId, int capabilities, const tm &date, const std::string &subject); + long long insertChatRoom (const ChatRoomId &chatRoomId, int capabilities, const tm &creationTime, const std::string &subject); void insertChatRoomParticipant (long long chatRoomId, long long sipAddressId, bool isAdmin); void insertChatMessageParticipant (long long messageEventId, long long sipAddressId, int state); @@ -65,49 +65,49 @@ private: std::shared_ptr selectGenericConferenceEvent ( long long eventId, EventLog::Type type, - time_t date, + time_t creationTime, const ChatRoomId &chatRoomId ) const; std::shared_ptr selectConferenceEvent ( long long eventId, EventLog::Type type, - time_t date, + time_t creationTime, const ChatRoomId &chatRoomId ) const; std::shared_ptr selectConferenceCallEvent ( long long eventId, EventLog::Type type, - time_t date, + time_t creationTime, const ChatRoomId &chatRoomId ) const; std::shared_ptr selectConferenceChatMessageEvent ( long long eventId, EventLog::Type type, - time_t date, + time_t creationTime, const ChatRoomId &chatRoomId ) const; std::shared_ptr selectConferenceParticipantEvent ( long long eventId, EventLog::Type type, - time_t date, + time_t creationTime, const ChatRoomId &chatRoomId ) const; std::shared_ptr selectConferenceParticipantDeviceEvent ( long long eventId, EventLog::Type type, - time_t date, + time_t creationTime, const ChatRoomId &chatRoomId ) const; std::shared_ptr selectConferenceSubjectEvent ( long long eventId, EventLog::Type type, - time_t date, + time_t creationTime, const ChatRoomId &chatRoomId ) const; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 00220947e..f7cee7898 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -186,7 +186,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long peerSipAddressId, long long localSipAddressId, int capabilities, - const tm &date, + const tm &creationTime, const string &subject ) { L_Q(); @@ -198,9 +198,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), lInfo() << "Insert new chat room in database: (peer=" << peerSipAddressId << ", local=" << localSipAddressId << ", capabilities=" << capabilities << ")."; *session << "INSERT INTO chat_room (" - " peer_sip_address_id, local_sip_address_id, creation_date, last_update_date, capabilities, subject" - ") VALUES (:peerSipAddressId, :localSipAddressId, :creationDate, :lastUpdateDate, :capabilities, :subject)", - soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::use(date), soci::use(date), + " peer_sip_address_id, local_sip_address_id, creation_time, last_update_time, capabilities, subject" + ") VALUES (:peerSipAddressId, :localSipAddressId, :creationTime, :lastUpdateTime, :capabilities, :subject)", + soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::use(creationTime), soci::use(creationTime), soci::use(capabilities), soci::use(subject); return q->getLastInsertId(); @@ -212,14 +212,14 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long MainDbPrivate::insertChatRoom ( const ChatRoomId &chatRoomId, int capabilities, - const tm &date, + const tm &creationTime, const string &subject ) { return insertChatRoom ( insertSipAddress(chatRoomId.getPeerAddress().asString()), insertSipAddress(chatRoomId.getLocalAddress().asString()), capabilities, - date, + creationTime, subject ); } @@ -289,7 +289,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), shared_ptr MainDbPrivate::selectGenericConferenceEvent ( long long eventId, EventLog::Type type, - time_t date, + time_t creationTime, const ChatRoomId &chatRoomId ) const { switch (type) { @@ -298,27 +298,27 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), case EventLog::Type::ConferenceCreated: case EventLog::Type::ConferenceDestroyed: - return selectConferenceEvent(eventId, type, date, chatRoomId); + return selectConferenceEvent(eventId, type, creationTime, chatRoomId); case EventLog::Type::ConferenceCallStart: case EventLog::Type::ConferenceCallEnd: - return selectConferenceCallEvent(eventId, type, date, chatRoomId); + return selectConferenceCallEvent(eventId, type, creationTime, chatRoomId); case EventLog::Type::ConferenceChatMessage: - return selectConferenceChatMessageEvent(eventId, type, date, chatRoomId); + return selectConferenceChatMessageEvent(eventId, type, creationTime, chatRoomId); case EventLog::Type::ConferenceParticipantAdded: case EventLog::Type::ConferenceParticipantRemoved: case EventLog::Type::ConferenceParticipantSetAdmin: case EventLog::Type::ConferenceParticipantUnsetAdmin: - return selectConferenceParticipantEvent(eventId, type, date, chatRoomId); + return selectConferenceParticipantEvent(eventId, type, creationTime, chatRoomId); case EventLog::Type::ConferenceParticipantDeviceAdded: case EventLog::Type::ConferenceParticipantDeviceRemoved: - return selectConferenceParticipantDeviceEvent(eventId, type, date, chatRoomId); + return selectConferenceParticipantDeviceEvent(eventId, type, creationTime, chatRoomId); case EventLog::Type::ConferenceSubjectChanged: - return selectConferenceSubjectEvent(eventId, type, date, chatRoomId); + return selectConferenceSubjectEvent(eventId, type, creationTime, chatRoomId); } return nullptr; @@ -327,12 +327,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), shared_ptr MainDbPrivate::selectConferenceEvent ( long long, EventLog::Type type, - time_t date, + time_t creationTime, const ChatRoomId &chatRoomId ) const { return make_shared( type, - date, + creationTime, chatRoomId ); } @@ -340,7 +340,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), shared_ptr MainDbPrivate::selectConferenceCallEvent ( long long eventId, EventLog::Type type, - time_t date, + time_t creationTime, const ChatRoomId &chatRoomId ) const { // TODO. @@ -350,7 +350,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), shared_ptr MainDbPrivate::selectConferenceChatMessageEvent ( long long eventId, EventLog::Type type, - time_t date, + time_t creationTime, const ChatRoomId &chatRoomId ) const { L_Q(); @@ -368,20 +368,25 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), { string fromSipAddress; string toSipAddress; + + tm messageTime; + string imdnMessageId; + int state; int direction; int isSecured; soci::session *session = dbSession.getBackendSession(); - *session << "SELECT from_sip_address.value, to_sip_address.value, imdn_message_id, state, direction, is_secured" + *session << "SELECT from_sip_address.value, to_sip_address.value, time, imdn_message_id, state, direction, is_secured" " FROM event, conference_chat_message_event, sip_address AS from_sip_address," " sip_address AS to_sip_address" " WHERE event_id = :eventId" " AND event_id = event.id" " AND from_sip_address_id = from_sip_address.id" " AND to_sip_address_id = to_sip_address.id", soci::into(fromSipAddress), soci::into(toSipAddress), - soci::into(imdnMessageId), soci::into(state), soci::into(direction), soci::into(isSecured), soci::use(eventId); + soci::into(messageTime), soci::into(imdnMessageId), soci::into(state), soci::into(direction), + soci::into(isSecured), soci::use(eventId); chatMessage = shared_ptr(new ChatMessage( chatRoom, @@ -392,6 +397,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), chatMessage->getPrivate()->forceFromAddress(IdentityAddress(fromSipAddress)); chatMessage->getPrivate()->forceToAddress(IdentityAddress(toSipAddress)); + + chatMessage->getPrivate()->setTime(Utils::getTmAsTimeT(messageTime)); } // 2 - Fetch contents. @@ -436,7 +443,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), // TODO: Use cache. return make_shared( - date, + creationTime, chatMessage ); } @@ -444,7 +451,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), shared_ptr MainDbPrivate::selectConferenceParticipantEvent ( long long eventId, EventLog::Type type, - time_t date, + time_t creationTime, const ChatRoomId &chatRoomId ) const { unsigned int notifyId; @@ -460,7 +467,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return make_shared( type, - date, + creationTime, chatRoomId, notifyId, IdentityAddress(participantAddress) @@ -470,7 +477,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), shared_ptr MainDbPrivate::selectConferenceParticipantDeviceEvent ( long long eventId, EventLog::Type type, - time_t date, + time_t creationTime, const ChatRoomId &chatRoomId ) const { unsigned int notifyId; @@ -490,7 +497,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return make_shared( type, - date, + creationTime, chatRoomId, notifyId, IdentityAddress(participantAddress), @@ -501,7 +508,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), shared_ptr MainDbPrivate::selectConferenceSubjectEvent ( long long eventId, EventLog::Type type, - time_t date, + time_t creationTime, const ChatRoomId &chatRoomId ) const { unsigned int notifyId; @@ -515,7 +522,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::into(notifyId), soci::into(subject), soci::use(eventId); return make_shared( - date, + creationTime, chatRoomId, notifyId, subject @@ -528,7 +535,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), L_Q(); soci::session *session = dbSession.getBackendSession(); - *session << "INSERT INTO event (type, date) VALUES (:type, :date)", + *session << "INSERT INTO event (type, creation_time) VALUES (:type, :creationTime)", soci::use(static_cast(eventLog->getType())), soci::use(Utils::getTimeTAsTm(eventLog->getCreationTime())); return q->getLastInsertId(); @@ -553,7 +560,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "INSERT INTO conference_event (event_id, chat_room_id)" " VALUES (:eventId, :chatRoomId)", soci::use(eventId), soci::use(curChatRoomId); - *session << "UPDATE chat_room SET last_update_date = :lastUpdateDate" + *session << "UPDATE chat_room SET last_update_time = :lastUpdateTime" " WHERE id = :chatRoomId", soci::use(Utils::getTimeTAsTm(eventLog->getCreationTime())), soci::use(curChatRoomId); } @@ -587,13 +594,14 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_chat_message_event (" " event_id, from_sip_address_id, to_sip_address_id," - " state, direction, imdn_message_id, is_secured" + " time, state, direction, imdn_message_id, is_secured" ") VALUES (" " :eventId, :localSipaddressId, :remoteSipaddressId," - " :state, :direction, :imdnMessageId, :isSecured" + " :time, :state, :direction, :imdnMessageId, :isSecured" ")", soci::use(eventId), soci::use(fromSipAddressId), soci::use(toSipAddressId), - soci::use(static_cast(chatMessage->getState())), soci::use(static_cast(chatMessage->getDirection())), - soci::use(chatMessage->getImdnMessageId()), soci::use(chatMessage->isSecured() ? 1 : 0); + soci::use(Utils::getTimeTAsTm(chatMessage->getTime())), soci::use(static_cast(chatMessage->getState())), + soci::use(static_cast(chatMessage->getDirection())), soci::use(chatMessage->getImdnMessageId()), + soci::use(chatMessage->isSecured() ? 1 : 0); for (const Content *content : chatMessage->getContents()) insertContent(eventId, *content); @@ -746,7 +754,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), "CREATE TABLE IF NOT EXISTS event (" " id" + primaryKeyStr("BIGINT UNSIGNED") + "," " type TINYINT UNSIGNED NOT NULL," - " date DATE NOT NULL" + " creation_time DATE NOT NULL" ") " + charset; *session << @@ -758,11 +766,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " local_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," - // Dialog creation date. - " creation_date DATE NOT NULL," + // Dialog creation time. + " creation_time DATE NOT NULL," - // Last event date (call, message...). - " last_update_date DATE NOT NULL," + // Last event time (call, message...). + " last_update_time DATE NOT NULL," // ConferenceChatRoom, BasicChatRoom, RTT... " capabilities TINYINT UNSIGNED NOT NULL," @@ -784,12 +792,14 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "CREATE TABLE IF NOT EXISTS chat_room_participant (" + " id" + primaryKeyStr("BIGINT UNSIGNED") + "," + " chat_room_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," " participant_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," " is_admin BOOLEAN NOT NULL," - " PRIMARY KEY (chat_room_id, participant_sip_address_id)," + " UNIQUE (chat_room_id, participant_sip_address_id)," " FOREIGN KEY (chat_room_id)" " REFERENCES chat_room(id)" @@ -799,6 +809,21 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " ON DELETE CASCADE" ") " + charset; + *session << + "CREATE TABLE IF NOT EXISTS chat_room_participant_device (" + " chat_room_participant_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + " participant_device_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + "," + + " PRIMARY KEY (chat_room_participant_id, participant_device_sip_address_id)," + + " FOREIGN KEY (chat_room_participant_id)" + " REFERENCES chat_room_participant(id)" + " ON DELETE CASCADE," + " FOREIGN KEY (participant_device_sip_address_id)" + " REFERENCES sip_address(id)" + " ON DELETE CASCADE" + ") " + charset; + *session << "CREATE TABLE IF NOT EXISTS conference_event (" " event_id" + primaryKeyStr("BIGINT UNSIGNED") + "," @@ -870,6 +895,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " from_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," " to_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," + " time DATE," + // See: https://tools.ietf.org/html/rfc5438#section-6.3 " imdn_message_id VARCHAR(255) NOT NULL," @@ -1161,7 +1188,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), const ChatRoomId &chatRoomId, unsigned int lastNotifyId ) const { - static const string query = "SELECT id, type, date FROM event" + static const string query = "SELECT id, type, creation_time FROM event" " WHERE id IN (" " SELECT event_id FROM conference_notified_event WHERE event_id IN (" " SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" @@ -1353,7 +1380,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return events; } - string query = "SELECT id, type, date FROM event" + string query = "SELECT id, type, creation_time FROM event" " WHERE id IN (" " SELECT event_id FROM conference_event WHERE chat_room_id = " + Utils::toString(d->selectChatRoomId(chatRoomId)) + @@ -1361,7 +1388,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), query += buildSqlEventFilter({ ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter }, mask, "AND"); - query += " ORDER BY date DESC"; + query += " ORDER BY creation_time DESC"; if (end > 0) query += " LIMIT " + Utils::toString(end - begin); @@ -1441,10 +1468,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), // ----------------------------------------------------------------------------- list> MainDb::getChatRooms () const { - static const string query = "SELECT peer_sip_address.value, local_sip_address.value, creation_date, last_update_date, capabilities, subject, last_notify_id" + static const string query = "SELECT peer_sip_address.value, local_sip_address.value, creation_time, last_update_time, capabilities, subject, last_notify_id" " FROM chat_room, sip_address AS peer_sip_address, sip_address AS local_sip_address" " WHERE chat_room.peer_sip_address_id = peer_sip_address.id AND chat_room.local_sip_address_id = local_sip_address.id" - " ORDER BY last_update_date DESC"; + " ORDER BY last_update_time DESC"; L_D(); @@ -1474,8 +1501,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), continue; } - tm creationDate = row.get(2); - tm lastUpdateDate = row.get(3); + tm creationTime = row.get(2); + tm lastUpdateTime = row.get(3); int capabilities = row.get(4); string subject = row.get(5); unsigned int lastNotifyId = static_cast(row.get(6, 0)); @@ -1496,8 +1523,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), continue; // Not fetched. ChatRoomPrivate *dChatRoom = chatRoom->getPrivate(); - dChatRoom->creationTime = Utils::getTmAsTimeT(creationDate); - dChatRoom->lastUpdateTime = Utils::getTmAsTimeT(lastUpdateDate); + dChatRoom->creationTime = Utils::getTmAsTimeT(creationTime); + dChatRoom->lastUpdateTime = Utils::getTmAsTimeT(lastUpdateTime); lInfo() << "Found chat room in DB: (peer=" << chatRoomId.getPeerAddress().asString() << ", local=" << chatRoomId.getLocalAddress().asString() << ")."; @@ -1632,7 +1659,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), continue; } - const tm date = Utils::getTimeTAsTm(message.get(LEGACY_MESSAGE_COL_DATE, 0)); + const tm creationTime = Utils::getTimeTAsTm(message.get(LEGACY_MESSAGE_COL_DATE, 0)); bool isNull; const string url = getValueFromLegacyMessage(message, LEGACY_MESSAGE_COL_URL, isNull); @@ -1674,8 +1701,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } soci::session *session = d->dbSession.getBackendSession(); - *session << "INSERT INTO event (type, date) VALUES (:type, :date)", - soci::use(static_cast(EventLog::Type::ConferenceChatMessage)), soci::use(date); + *session << "INSERT INTO event (type, creation_time) VALUES (:type, :creationTime)", + soci::use(static_cast(EventLog::Type::ConferenceChatMessage)), soci::use(creationTime); long long eventId = getLastInsertId(); long long localSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_LOCAL_ADDRESS)); @@ -1684,7 +1711,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), remoteSipAddressId, localSipAddressId, static_cast(ChatRoom::Capabilities::Basic), - date, + creationTime, "" ); @@ -1693,12 +1720,13 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "INSERT INTO conference_chat_message_event (" " event_id, from_sip_address_id, to_sip_address_id," - " state, direction, imdn_message_id, is_secured" + " time, state, direction, imdn_message_id, is_secured" ") VALUES (" " :eventId, :localSipAddressId, :remoteSipAddressId," - " :state, :direction, '', :isSecured" + " :creationTime, :state, :direction, '', :isSecured" ")", soci::use(eventId), soci::use(localSipAddressId), soci::use(remoteSipAddressId), - soci::use(state), soci::use(direction), soci::use(message.get(LEGACY_MESSAGE_COL_IS_SECURED, 0)); + soci::use(creationTime), soci::use(state), soci::use(direction), + soci::use(message.get(LEGACY_MESSAGE_COL_IS_SECURED, 0)); d->insertContent(eventId, content); d->insertChatRoomParticipant(chatRoomId, remoteSipAddressId, false); From 759ecda219ace50ec01ece8ae71675e702d08158 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 24 Nov 2017 14:45:54 +0100 Subject: [PATCH 0858/2215] This should fix IMDNs & IsComposing being stored --- src/chat/chat-message/chat-message.cpp | 32 +++++++++++--------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index aa69c4a38..4f203bf99 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -425,15 +425,7 @@ LinphoneReason ChatMessagePrivate::receive () { return reason; } - bool messageToBeStored = false; - for (Content *c : contents) { - if (c->getContentType() == ContentType::FileTransfer || c->getContentType() == ContentType::PlainText) { - messageToBeStored = true; - } - } - if (messageToBeStored) { - store(); - } + store(); return reason; } @@ -552,13 +544,6 @@ void ChatMessagePrivate::send () { } else msgOp->send_message(ContentType::PlainText.asString().c_str(), internalContent.getBodyAsString().c_str()); - bool messageToBeStored = false; - for (Content *c : contents) { - if (c->getContentType() == ContentType::FileTransfer || c->getContentType() == ContentType::PlainText) { - messageToBeStored = true; - } - } - for (Content *content : contents) { // Restore FileContents and remove FileTransferContents if (content->getContentType() == ContentType::FileTransfer) { @@ -571,9 +556,7 @@ void ChatMessagePrivate::send () { q->setImdnMessageId(op->get_call_id()); /* must be known at that time */ - if (messageToBeStored) { - store(); - } + store(); if (call && linphone_call_get_op(call) == op) { /* In this case, chat delivery status is not notified, so unrefing chat message right now */ @@ -591,6 +574,17 @@ void ChatMessagePrivate::send () { void ChatMessagePrivate::store() { L_Q(); + bool messageToBeStored = false; + for (Content *c : contents) { + ContentType contentType = c->getContentType(); + if (contentType == ContentType::FileTransfer || contentType == ContentType::PlainText || contentType.isFile()) { + messageToBeStored = true; + } + } + if (!messageToBeStored) { + return; + } + shared_ptr eventLog = chatEvent.lock(); if (eventLog) { q->getChatRoom()->getCore()->getPrivate()->mainDb->updateEvent(eventLog); From dcef9e4f973e4ed965e5b4bbe843e8241afd6dc3 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 24 Nov 2017 14:55:39 +0100 Subject: [PATCH 0859/2215] fix(MainDb): use references when possible --- src/db/main-db.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index f7cee7898..092f8c56d 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -143,11 +143,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long messageContentId = q->getLastInsertId(); if (content.getContentType().isFile()) { - const FileContent *fileContent = (const FileContent *)&content; + const FileContent &fileContent = static_cast(content); *session << "INSERT INTO chat_message_file_content (chat_message_content_id, name, size, path) VALUES " " (:contentId, :name, :size, :path)", - soci::use(messageContentId), soci::use(fileContent->getFileName()), - soci::use(fileContent->getFileSize()), soci::use(fileContent->getFilePath()); + soci::use(messageContentId), soci::use(fileContent.getFileName()), + soci::use(fileContent.getFileSize()), soci::use(fileContent.getFilePath()); } for (const auto &appData : content.getAppDataMap()) From a94805efc2cc36533b576895afd377a3f49cc6ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Fri, 24 Nov 2017 14:55:13 +0100 Subject: [PATCH 0860/2215] Set java/genwrapper.py as executable --- wrappers/java/genwrapper.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 wrappers/java/genwrapper.py diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py old mode 100644 new mode 100755 From 886126a3da1fbc4e3798136f88b237bde703d969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Fri, 24 Nov 2017 14:55:51 +0100 Subject: [PATCH 0861/2215] Remove an unuseful line in coreapi/CMakeLists.txt --- coreapi/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index f0005fc12..d12a73f06 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -110,7 +110,6 @@ set(LINPHONE_SOURCE_FILES_CXX conference.cc tester_utils.cpp ) -set(LINPHONE_INCLUDE_DIRS ${LINPHONE_INCLUDE_DIRS}) if(ENABLE_JAVA_WRAPPER) list(APPEND LINPHONE_SOURCE_FILES_CXX ${LINPHONE_JNI_SOURCES}) set_source_files_properties(${LINPHONE_JNI_SOURCES} PROPERTIES GENERATED TRUE) From 72c9d2836170bc84b46fc685fb7bc3f816b75ea7 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 24 Nov 2017 15:20:42 +0100 Subject: [PATCH 0862/2215] DB update of chat message improvement --- src/chat/chat-message/chat-message.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 4f203bf99..903797412 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -509,8 +509,7 @@ void ChatMessagePrivate::send () { ChatMessageModifier::Result result = ecmm.encode(q->getSharedFromThis(), errorCode); if (result == ChatMessageModifier::Result::Error) { sal_error_info_set((SalErrorInfo *)op->get_error_info(), SalReasonNotAcceptable, "SIP", errorCode, "Unable to encrypt IM", nullptr); - q->updateState(ChatMessage::State::NotDelivered); - store(); + setState(ChatMessage::State::NotDelivered); return; } else if (result == ChatMessageModifier::Result::Suspended) { currentSendStep |= ChatMessagePrivate::Step::Encryption; From c115a448ddadb2639e2ae76a65ef2959127ba777 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 24 Nov 2017 15:26:35 +0100 Subject: [PATCH 0863/2215] Fix chat messages routing issues because of gruu addresses. --- coreapi/linphonecore.c | 24 ++++++++++++------- coreapi/private.h | 1 - include/linphone/core.h | 2 ++ src/c-wrapper/api/c-chat-room.cpp | 12 ++++++++-- src/chat/chat-message/chat-message.cpp | 3 ++- src/chat/chat-room/client-group-chat-room.cpp | 4 +++- src/conference/conference.cpp | 7 ++++-- .../remote-conference-event-handler.cpp | 1 + src/sal/op.h | 4 ---- 9 files changed, 39 insertions(+), 19 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 88c8b1bc9..728f94bfd 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3368,6 +3368,21 @@ const char * linphone_core_get_identity(LinphoneCore *lc){ return from; } +char * linphone_core_get_device_identity(LinphoneCore *lc) { + char *identity = NULL; + LinphoneProxyConfig *proxy = linphone_core_get_default_proxy_config(lc); + if (proxy) { + const LinphoneAddress *contactAddr = linphone_proxy_config_get_contact(proxy); + if (contactAddr) + identity = linphone_address_as_string(contactAddr); + else + identity = bctbx_strdup(linphone_proxy_config_get_identity(proxy)); + } else { + identity = bctbx_strdup(linphone_core_get_primary_contact(lc)); + } + return identity; +} + const char * linphone_core_get_route(LinphoneCore *lc){ LinphoneProxyConfig *proxy=linphone_core_get_default_proxy_config(lc); const char *route=NULL; @@ -3548,11 +3563,9 @@ static void linphone_transfer_routes_to_op(bctbx_list_t *routes, SalOp *op){ void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact, LinphoneProxyConfig *proxy){ bctbx_list_t *routes=NULL; - const LinphoneAddress *contactAddr = nullptr; const char *identity; if (proxy){ - contactAddr = linphone_proxy_config_get_contact(proxy); identity=linphone_proxy_config_get_identity(proxy); if (linphone_proxy_config_get_privacy(proxy)!=LinphonePrivacyDefault) { op->set_privacy(linphone_proxy_config_get_privacy(proxy)); @@ -3565,12 +3578,7 @@ void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const Linphon } op->set_to_address(L_GET_PRIVATE_FROM_C_OBJECT(dest)->getInternalAddress()); - if (op->getUseGruuInFrom() && contactAddr && linphone_address_has_uri_param(contactAddr, "gr")) { - char *contactAddrStr = linphone_address_as_string_uri_only(contactAddr); - op->set_from(contactAddrStr); - bctbx_free(contactAddrStr); - } else - op->set_from(identity); + op->set_from(identity); op->set_sent_custom_header(headers); op->set_realm(linphone_proxy_config_get_realm(proxy)); diff --git a/coreapi/private.h b/coreapi/private.h index fc2bc54e3..da493d8f5 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -452,7 +452,6 @@ void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call); void linphone_call_stop_media_streams(LinphoneCall *call); void linphone_call_delete_upnp_session(LinphoneCall *call); int _linphone_core_apply_transports(LinphoneCore *lc); -const char * linphone_core_get_identity(LinphoneCore *lc); void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose); void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progresses); diff --git a/include/linphone/core.h b/include/linphone/core.h index 166430666..55e8cbe5f 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -1403,6 +1403,8 @@ LINPHONE_PUBLIC const char *linphone_core_get_primary_contact(LinphoneCore *lc); **/ LINPHONE_PUBLIC const char * linphone_core_get_identity(LinphoneCore *lc); +LINPHONE_PUBLIC char * linphone_core_get_device_identity(LinphoneCore *lc); + /** * Tells LinphoneCore to guess local hostname automatically in primary contact. * @ingroup proxies diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 3291afc31..76aca9c08 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -351,8 +351,16 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, cons LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core, addr); linphone_address_unref(addr); string from; - if (proxy) - from = L_GET_CPP_PTR_FROM_C_OBJECT(linphone_proxy_config_get_identity_address(proxy))->asString(); + if (proxy) { + const LinphoneAddress *contactAddr = linphone_proxy_config_get_contact(proxy); + if (contactAddr) { + char *cFrom = linphone_address_as_string(contactAddr); + from = string(cFrom); + bctbx_free(cFrom); + } else { + from = L_GET_CPP_PTR_FROM_C_OBJECT(linphone_proxy_config_get_identity_address(proxy))->asString(); + } + } if (from.empty()) from = linphone_core_get_primary_contact(core); LinphonePrivate::IdentityAddress me(from); diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 903797412..99589a6bf 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -478,7 +478,6 @@ void ChatMessagePrivate::send () { LinphoneAddress *peer = linphone_address_new(q->getToAddress().asString().c_str()); /* Sending out of call */ salOp = op = new SalMessageOp(core->getCCore()->sal); - op->setUseGruuInFrom(true); linphone_configure_op( core->getCCore(), op, peer, getSalCustomHeaders(), !!lp_config_get_int(core->getCCore()->config, "sip", "chat_msg_with_contact", 0) @@ -486,6 +485,8 @@ void ChatMessagePrivate::send () { op->set_user_pointer(L_GET_C_BACK_PTR(q)); /* If out of call, directly store msg */ linphone_address_unref(peer); } + op->set_from(q->getFromAddress().asString().c_str()); + op->set_to(q->getToAddress().asString().c_str()); // --------------------------------------- // Start of message modification diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index a30efac9c..3643d5240 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -64,7 +64,9 @@ shared_ptr ClientGroupChatRoomPrivate::createSession () { shared_ptr focus = qConference->getPrivate()->focus; shared_ptr session = focus->getPrivate()->createSession(*q, &csp, false, q); const Address &myAddress = q->getMe()->getAddress(); - session->configure(LinphoneCallOutgoing, nullptr, nullptr, myAddress, focus->getAddress()); + Address myCleanedAddress(myAddress); + myCleanedAddress.setUriParam("gr"); // Remove gr parameter for INVITE + session->configure(LinphoneCallOutgoing, nullptr, nullptr, myCleanedAddress, focus->getAddress()); session->initiateOutgoing(); return session; } diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 8ea32bedc..52991d8b8 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -234,8 +234,11 @@ shared_ptr Conference::findParticipant (const shared_ptrme->getAddress() == simpleAddr; + IdentityAddress cleanedAddr(addr); + cleanedAddr.setGruu(""); + IdentityAddress cleanedMeAddr(d->me->getAddress()); + cleanedMeAddr.setGruu(""); + return cleanedMeAddr == cleanedAddr; } LINPHONE_END_NAMESPACE diff --git a/src/conference/handlers/remote-conference-event-handler.cpp b/src/conference/handlers/remote-conference-event-handler.cpp index 6bf3718ce..c6be552f1 100644 --- a/src/conference/handlers/remote-conference-event-handler.cpp +++ b/src/conference/handlers/remote-conference-event-handler.cpp @@ -184,6 +184,7 @@ void RemoteConferenceEventHandler::subscribe (const ChatRoomId &chatRoomId) { d->chatRoomId = chatRoomId; LinphoneAddress *lAddr = linphone_address_new(d->chatRoomId.getPeerAddress().asString().c_str()); d->lev = linphone_core_create_subscribe(d->conf->getCore()->getCCore(), lAddr, "conference", 600); + d->lev->op->set_from(d->chatRoomId.getLocalAddress().asString().c_str()); linphone_event_add_custom_header(d->lev, "Last-Notify-Version", Utils::toString(d->lastNotify).c_str()); linphone_address_unref(lAddr); linphone_event_set_internal(d->lev, TRUE); diff --git a/src/sal/op.h b/src/sal/op.h index d461cf7fb..06c009909 100644 --- a/src/sal/op.h +++ b/src/sal/op.h @@ -84,9 +84,6 @@ public: void set_sent_custom_header(SalCustomHeader* ch); - bool getUseGruuInFrom () { return useGruuInFrom; } - void setUseGruuInFrom (bool value) { useGruuInFrom = value; } - void enable_cnx_ip_to_0000_if_sendonly(bool_t yesno) {this->_cnx_ip_to_0000_if_sendonly_enabled = yesno;} bool_t cnx_ip_to_0000_if_sendonly_enabled() const {return this->_cnx_ip_to_0000_if_sendonly_enabled;} @@ -256,7 +253,6 @@ protected: bool_t has_auth_pending = FALSE; bool_t supports_session_timers = FALSE; bool_t op_released = FALSE; - bool useGruuInFrom = false; friend class Sal; }; From 28570e284d8e3dfb8a716b6cd43e7f9e9f9da6e7 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 24 Nov 2017 15:40:51 +0100 Subject: [PATCH 0864/2215] Prevent an insert that is redondent --- src/chat/chat-message/chat-message.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 99589a6bf..f7e02e512 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -556,7 +556,7 @@ void ChatMessagePrivate::send () { q->setImdnMessageId(op->get_call_id()); /* must be known at that time */ - store(); + //store(); // Store will be done right below in the setState(InProgress) if (call && linphone_call_get_op(call) == op) { /* In this case, chat delivery status is not notified, so unrefing chat message right now */ From 418a2cfe247cd1fd9dcb2a07166b1f6341857771 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 24 Nov 2017 15:48:30 +0100 Subject: [PATCH 0865/2215] Fixed outgoing file contents storage fetch --- src/db/main-db.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 092f8c56d..96610b9e1 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -404,11 +404,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), // 2 - Fetch contents. { soci::session *session = dbSession.getBackendSession(); - const string query = "SELECT content_type.id, content_type.value, body FROM chat_message_content, content_type" + const string query = "SELECT chat_message_content.id, content_type.id, content_type.value, body FROM chat_message_content, content_type" " WHERE event_id = :eventId AND content_type_id = content_type.id"; soci::rowset rows = (session->prepare << query, soci::use(eventId)); for (const auto &row : rows) { - ContentType contentType(row.get(1)); + ContentType contentType(row.get(2)); Content *content; if (contentType == ContentType::FileTransfer) From 65978c70ad68de092c9f5eb55325c80b45495add Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 24 Nov 2017 15:56:46 +0100 Subject: [PATCH 0866/2215] feat(MainDb): insert participants on chat room insertion --- src/conference/participant.h | 2 +- src/core/core-chat-room.cpp | 48 +++++++--------- src/core/core-p.h | 3 - src/db/main-db-p.h | 5 +- src/db/main-db.cpp | 106 +++++++++++++++++++++++------------ src/db/main-db.h | 2 +- 6 files changed, 93 insertions(+), 73 deletions(-) diff --git a/src/conference/participant.h b/src/conference/participant.h index 00c0a687a..f80bb77a0 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -52,7 +52,7 @@ public: explicit Participant (const IdentityAddress &address); explicit Participant (IdentityAddress &&address); - const IdentityAddress& getAddress () const; + const IdentityAddress &getAddress () const; bool isAdmin () const; private: diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 3b09ef51a..be48b1dcc 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -80,40 +80,16 @@ shared_ptr CorePrivate::createBasicChatRoom (const ChatRoomId &chatRoo void CorePrivate::insertChatRoom (const shared_ptr &chatRoom) { L_ASSERT(chatRoom); + L_Q(); - const ChatRoomId &chatRoomId = chatRoom->getChatRoomId(); - deleteChatRoom(chatRoomId); + q->deleteChatRoom(chatRoom); chatRooms.push_back(chatRoom); - chatRoomsById[chatRoomId] = chatRoom; -} - -void CorePrivate::deleteChatRoom (const ChatRoomId &chatRoomId) { - auto it = chatRoomsById.find(chatRoomId); - if (it != chatRoomsById.end()) { - auto it = find_if(chatRooms.begin(), chatRooms.end(), [&chatRoomId](const shared_ptr &chatRoom) { - return chatRoomId == chatRoom->getChatRoomId(); - }); - if (it != chatRooms.end()) { - chatRooms.erase(it); - return; - } - lError() << "Unable to remove chat room: (peer=" << - chatRoomId.getPeerAddress().asString() << ", local=" << chatRoomId.getLocalAddress().asString() << ")."; - } + chatRoomsById[chatRoom->getChatRoomId()] = chatRoom; } void CorePrivate::insertChatRoomWithDb (const shared_ptr &chatRoom) { L_ASSERT(chatRoom->getState() == ChatRoom::State::Created); - mainDb->insertChatRoom( - chatRoom->getChatRoomId(), - chatRoom->getCapabilities(), - chatRoom->getSubject() - ); -} - -void CorePrivate::deleteChatRoomWithDb (const ChatRoomId &chatRoomId) { - deleteChatRoom(chatRoomId); - mainDb->deleteChatRoom(chatRoomId); + mainDb->insertChatRoom(chatRoom); } // ----------------------------------------------------------------------------- @@ -209,7 +185,21 @@ shared_ptr Core::getOrCreateBasicChatRoomFromUri (const string &peerAd void Core::deleteChatRoom (const shared_ptr &chatRoom) { CorePrivate *d = chatRoom->getCore()->getPrivate(); - d->deleteChatRoomWithDb(chatRoom->getChatRoomId()); + + const ChatRoomId &chatRoomId = chatRoom->getChatRoomId(); + auto it = d->chatRoomsById.find(chatRoomId); + if (it != d->chatRoomsById.end()) { + auto it = find(d->chatRooms.begin(), d->chatRooms.end(), chatRoom); + if (it != d->chatRooms.end()) { + d->chatRooms.erase(it); + return; + } + lError() << "Unable to remove chat room: (peer=" << + chatRoomId.getPeerAddress().asString() << ", local=" << chatRoomId.getLocalAddress().asString() << ")."; + } + + d->mainDb->deleteChatRoom(chatRoomId); } + LINPHONE_END_NAMESPACE diff --git a/src/core/core-p.h b/src/core/core-p.h index 386c1b140..c5bb47458 100644 --- a/src/core/core-p.h +++ b/src/core/core-p.h @@ -39,9 +39,6 @@ public: LinphoneCore *cCore = nullptr; private: - void deleteChatRoom (const ChatRoomId &chatRoomId); - void deleteChatRoomWithDb (const ChatRoomId &chatRoomId); - std::list> chatRooms; std::unordered_map> chatRoomsById; diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 5c547bc68..9a46ac4e4 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -47,10 +47,9 @@ private: long long peerSipAddressId, long long localSipAddressId, int capabilities, - const tm &creationTime, - const std::string &subject + const tm &creationTime ); - long long insertChatRoom (const ChatRoomId &chatRoomId, int capabilities, const tm &creationTime, const std::string &subject); + long long insertChatRoom (const std::shared_ptr &chatRoom); void insertChatRoomParticipant (long long chatRoomId, long long sipAddressId, bool isAdmin); void insertChatMessageParticipant (long long messageEventId, long long sipAddressId, int state); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 96610b9e1..9064db231 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -186,42 +186,59 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long peerSipAddressId, long long localSipAddressId, int capabilities, - const tm &creationTime, - const string &subject + const tm &creationTime ) { L_Q(); soci::session *session = dbSession.getBackendSession(); long long id = selectChatRoomId(peerSipAddressId, localSipAddressId); - if (id < 0) { - lInfo() << "Insert new chat room in database: (peer=" << peerSipAddressId << - ", local=" << localSipAddressId << ", capabilities=" << capabilities << ")."; - *session << "INSERT INTO chat_room (" - " peer_sip_address_id, local_sip_address_id, creation_time, last_update_time, capabilities, subject" - ") VALUES (:peerSipAddressId, :localSipAddressId, :creationTime, :lastUpdateTime, :capabilities, :subject)", - soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::use(creationTime), soci::use(creationTime), - soci::use(capabilities), soci::use(subject); + if (id >= 0) + return id; - return q->getLastInsertId(); - } + lInfo() << "Insert new chat room in database: (peer=" << peerSipAddressId << + ", local=" << localSipAddressId << ", capabilities=" << capabilities << ")."; + *session << "INSERT INTO chat_room (" + " peer_sip_address_id, local_sip_address_id, creation_time, last_update_time, capabilities" + ") VALUES (:peerSipAddressId, :localSipAddressId, :creationTime, :lastUpdateTime, :capabilities)", + soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::use(creationTime), soci::use(creationTime), + soci::use(capabilities); - return id; + return q->getLastInsertId(); } - long long MainDbPrivate::insertChatRoom ( - const ChatRoomId &chatRoomId, - int capabilities, - const tm &creationTime, - const string &subject - ) { - return insertChatRoom ( - insertSipAddress(chatRoomId.getPeerAddress().asString()), - insertSipAddress(chatRoomId.getLocalAddress().asString()), - capabilities, - creationTime, - subject - ); + long long MainDbPrivate::insertChatRoom (const std::shared_ptr &chatRoom) { + L_Q(); + + soci::session *session = dbSession.getBackendSession(); + + const ChatRoomId &chatRoomId = chatRoom->getChatRoomId(); + long long peerSipAddressId = selectSipAddressId(chatRoomId.getPeerAddress().asString()); + long long localSipAddressId = selectSipAddressId(chatRoomId.getLocalAddress().asString()); + + long long id = selectChatRoomId(peerSipAddressId, localSipAddressId); + if (id >= 0) { + lWarning() << "Unable to insert chat room (it already exists): (peer=" << peerSipAddressId << + ", local=" << localSipAddressId << ")."; + return id; + } + + lInfo() << "Insert new chat room in database: (peer=" << peerSipAddressId << + ", local=" << localSipAddressId << ")."; + + tm creationTime = Utils::getTimeTAsTm(chatRoom->getCreationTime()); + + *session << "INSERT INTO chat_room (" + " peer_sip_address_id, local_sip_address_id, creation_time, last_update_time, capabilities, subject" + ") VALUES (:peerSipAddressId, :localSipAddressId, :creationTime, :lastUpdateTime, :capabilities, :subject)", + soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::use(creationTime), soci::use(creationTime), + soci::use(static_cast(chatRoom->getCapabilities())), soci::use(chatRoom->getSubject()); + + id = q->getLastInsertId(); + for (const auto &participant : chatRoom->getParticipants()) + insertChatRoomParticipant(id, selectSipAddressId(participant->getAddress().asString()), participant->isAdmin()); + + return id; } void MainDbPrivate::insertChatRoomParticipant (long long chatRoomId, long long sipAddressId, bool isAdmin) { @@ -651,18 +668,37 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } long long MainDbPrivate::insertConferenceParticipantEvent (const shared_ptr &eventLog) { - long long eventId = insertConferenceNotifiedEvent(eventLog); + long long chatRoomId; + long long eventId = insertConferenceNotifiedEvent(eventLog, &chatRoomId); if (eventId < 0) return -1; + shared_ptr participantEvent = + static_pointer_cast(eventLog); + long long participantAddressId = insertSipAddress( - static_pointer_cast(eventLog)->getParticipantAddress().asString() + participantEvent->getParticipantAddress().asString() ); soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_participant_event (event_id, participant_sip_address_id)" " VALUES (:eventId, :participantAddressId)", soci::use(eventId), soci::use(participantAddressId); + bool isAdmin = eventLog->getType() == EventLog::Type::ConferenceParticipantSetAdmin; + switch (eventLog->getType()) { + case EventLog::Type::ConferenceParticipantAdded: + case EventLog::Type::ConferenceParticipantSetAdmin: + case EventLog::Type::ConferenceParticipantUnsetAdmin: + insertChatRoomParticipant(chatRoomId, participantAddressId, isAdmin); + break; + + case EventLog::Type::ConferenceParticipantRemoved: + // TODO: Deal with remove. + + default: + break; + } + return eventId; } @@ -1537,7 +1573,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return chatRooms; } - void MainDb::insertChatRoom (const ChatRoomId &chatRoomId, int capabilities, const string &subject) { + void MainDb::insertChatRoom (const shared_ptr &chatRoom) { L_D(); if (!isConnected()) { @@ -1545,18 +1581,17 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return; } + const ChatRoomId &chatRoomId = chatRoom->getChatRoomId(); DurationLogger durationLogger( - "Insert chat room: peer=" + chatRoomId.getPeerAddress().asString() + - ", local=" + chatRoomId.getLocalAddress().asString() + - ", capabilities=" + Utils::toString(capabilities) + - ", subject=" + subject + ")." + "Insert chat room: (peer=" + chatRoomId.getPeerAddress().asString() + + ", local=" + chatRoomId.getLocalAddress().asString() + ")." ); L_BEGIN_LOG_EXCEPTION soci::transaction tr(*d->dbSession.getBackendSession()); - d->insertChatRoom(chatRoomId, capabilities, Utils::getTimeTAsTm(time(0)), subject); + d->insertChatRoom(chatRoom); tr.commit(); @@ -1711,8 +1746,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), remoteSipAddressId, localSipAddressId, static_cast(ChatRoom::Capabilities::Basic), - creationTime, - "" + creationTime ); *session << "INSERT INTO conference_event (event_id, chat_room_id)" diff --git a/src/db/main-db.h b/src/db/main-db.h index 289ef0a05..6c2975efa 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -100,7 +100,7 @@ public: // --------------------------------------------------------------------------- std::list> getChatRooms () const; - void insertChatRoom (const ChatRoomId &chatRoomId, int capabilities, const std::string &subject); + void insertChatRoom (const std::shared_ptr &chatRoom); void deleteChatRoom (const ChatRoomId &chatRoomId); // --------------------------------------------------------------------------- From 8274b3d157abebff8c853c3187c521d4976a9bc9 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 24 Nov 2017 16:00:59 +0100 Subject: [PATCH 0867/2215] Do not create a new focus participant when a client group chat room conference is created, only change its address. --- src/chat/chat-room/client-group-chat-room.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 3643d5240..54160d720 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -285,7 +285,7 @@ void ClientGroupChatRoom::onConferenceCreated (const IdentityAddress &addr) { L_D(); L_D_T(RemoteConference, dConference); dConference->conferenceAddress = addr; - dConference->focus = make_shared(addr); + dConference->focus->getPrivate()->setAddress(addr); d->chatRoomId = ChatRoomId(addr, d->chatRoomId.getLocalAddress()); getCore()->getPrivate()->insertChatRoom(getSharedFromThis()); } From 88dbfba40b34ae9324d2937a671c119bdd026380 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 24 Nov 2017 16:37:45 +0100 Subject: [PATCH 0868/2215] fix(MainDb): insert addresses correctly --- src/db/main-db.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 9064db231..6461c7b5c 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -213,8 +213,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); const ChatRoomId &chatRoomId = chatRoom->getChatRoomId(); - long long peerSipAddressId = selectSipAddressId(chatRoomId.getPeerAddress().asString()); - long long localSipAddressId = selectSipAddressId(chatRoomId.getLocalAddress().asString()); + long long peerSipAddressId = insertSipAddress(chatRoomId.getPeerAddress().asString()); + long long localSipAddressId = insertSipAddress(chatRoomId.getLocalAddress().asString()); long long id = selectChatRoomId(peerSipAddressId, localSipAddressId); if (id >= 0) { @@ -236,7 +236,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), id = q->getLastInsertId(); for (const auto &participant : chatRoom->getParticipants()) - insertChatRoomParticipant(id, selectSipAddressId(participant->getAddress().asString()), participant->isAdmin()); + insertChatRoomParticipant(id, insertSipAddress(participant->getAddress().asString()), participant->isAdmin()); return id; } @@ -1552,8 +1552,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), capabilities & static_cast(ChatRoom::Capabilities::RealTimeText) ); chatRoom->setSubject(subject); - } else if (capabilities & static_cast(ChatRoom::Capabilities::Conference)) + } else if (capabilities & static_cast(ChatRoom::Capabilities::Conference)) { + chatRoom = make_shared(core, chatRoomId, subject); + } if (!chatRoom) continue; // Not fetched. From 140a277410e3e1c051d6239c6ad24d790cd6170b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 24 Nov 2017 16:43:05 +0100 Subject: [PATCH 0869/2215] Fixed fetch body of contents --- src/db/main-db.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 6461c7b5c..7c537f0b5 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -453,7 +453,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), content = new Content(); content->setContentType(contentType); - content->setBody(row.get(2)); + content->setBody(row.get(3)); chatMessage->addContent(*content); } } From a314ffd2c22f834a30fd8c74b2e7bed3d1f2b1e9 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 24 Nov 2017 16:53:54 +0100 Subject: [PATCH 0870/2215] feat(MainDb): fetch chat rooms participants --- src/chat/chat-room/client-group-chat-room.cpp | 4 +++- src/chat/chat-room/client-group-chat-room.h | 3 ++- src/conference/participant.h | 1 + src/db/main-db.cpp | 20 ++++++++++++++++--- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 54160d720..dbb526e49 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -100,7 +100,8 @@ RemoteConference(core, me, nullptr) { ClientGroupChatRoom::ClientGroupChatRoom ( const shared_ptr &core, const ChatRoomId &chatRoomId, - const string &subject + const string &subject, + list> &&participants ) : ChatRoom(*new ClientGroupChatRoomPrivate, core, chatRoomId), RemoteConference(core, chatRoomId.getLocalAddress(), nullptr) { L_D(); @@ -109,6 +110,7 @@ RemoteConference(core, chatRoomId.getLocalAddress(), nullptr) { dConference->focus = make_shared(peerAddress); dConference->conferenceAddress = peerAddress; dConference->subject = subject; + dConference->participants = move(participants); d->state = ChatRoom::State::Created; } diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index a8e569945..c0b240538 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -42,7 +42,8 @@ public: ClientGroupChatRoom ( const std::shared_ptr &core, const ChatRoomId &chatRoomId, - const std::string &subject + const std::string &subject, + std::list> &&participants ); std::shared_ptr getCore () const; diff --git a/src/conference/participant.h b/src/conference/participant.h index f80bb77a0..4dd008c3c 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -43,6 +43,7 @@ class Participant : public Object { friend class LocalConference; friend class LocalConferenceEventHandler; friend class LocalConferenceEventHandlerPrivate; + friend class MainDb; friend class MediaSessionPrivate; friend class RemoteConference; friend class ServerGroupChatRoom; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 7c537f0b5..b30a24bf7 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -27,9 +27,9 @@ #include "linphone/utils/utils.h" #include "chat/chat-message/chat-message-p.h" -#include "chat/chat-room/client-group-chat-room.h" #include "chat/chat-room/chat-room-p.h" -#include "conference/participant.h" +#include "chat/chat-room/client-group-chat-room.h" +#include "conference/participant-p.h" #include "content/content-type.h" #include "content/content.h" #include "core/core-p.h" @@ -1553,8 +1553,22 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), ); chatRoom->setSubject(subject); } else if (capabilities & static_cast(ChatRoom::Capabilities::Conference)) { + list> participants; - chatRoom = make_shared(core, chatRoomId, subject); + string query = "SELECT sip_address.value, is_admin" + " FROM sip_address, chat_room, chat_room_participant" + " WHERE chat_room.id = :chatRoomId" + " AND sip_address.id = chat_room_participant.participant_sip_address_id" + " AND chat_room_participant.chat_room_id = chat_room.id"; + + soci::rowset rows = (session->prepare << query); + for (const auto &row : rows) { + shared_ptr participant = make_shared(IdentityAddress(row.get(0))); + participant->getPrivate()->setAdmin(!!row.get(1)); + participants.push_back(participant); + } + + chatRoom = make_shared(core, chatRoomId, subject, move(participants)); } if (!chatRoom) From daf2432e1dbc124441469afa4575789718942b38 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 27 Nov 2017 09:21:46 +0100 Subject: [PATCH 0871/2215] fix(core-chat-room): do not remove from db if chat room is not in ram --- src/core/core-chat-room.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index be48b1dcc..5d8c8b6e4 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -190,16 +190,10 @@ void Core::deleteChatRoom (const shared_ptr &chatRoom) { auto it = d->chatRoomsById.find(chatRoomId); if (it != d->chatRoomsById.end()) { auto it = find(d->chatRooms.begin(), d->chatRooms.end(), chatRoom); - if (it != d->chatRooms.end()) { - d->chatRooms.erase(it); - return; - } - lError() << "Unable to remove chat room: (peer=" << - chatRoomId.getPeerAddress().asString() << ", local=" << chatRoomId.getLocalAddress().asString() << ")."; + L_ASSERT(it != d->chatRooms.end()); + d->chatRooms.erase(it); + d->mainDb->deleteChatRoom(chatRoomId); } - - d->mainDb->deleteChatRoom(chatRoomId); } - LINPHONE_END_NAMESPACE From 1a68000f3ab7aaab5a064b4d0ed9b0fb48ecc584 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 27 Nov 2017 10:17:51 +0100 Subject: [PATCH 0872/2215] fix(MainDb): insert correctly participants on chat room insertion --- src/db/main-db.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index b30a24bf7..e6e22caaa 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1504,7 +1504,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), // ----------------------------------------------------------------------------- list> MainDb::getChatRooms () const { - static const string query = "SELECT peer_sip_address.value, local_sip_address.value, creation_time, last_update_time, capabilities, subject, last_notify_id" + static const string query = "SELECT chat_room.id, peer_sip_address.value, local_sip_address.value, creation_time, last_update_time, capabilities, subject, last_notify_id" " FROM chat_room, sip_address AS peer_sip_address, sip_address AS local_sip_address" " WHERE chat_room.peer_sip_address_id = peer_sip_address.id AND chat_room.local_sip_address_id = local_sip_address.id" " ORDER BY last_update_time DESC"; @@ -1528,8 +1528,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::rowset rows = (session->prepare << query); for (const auto &row : rows) { ChatRoomId chatRoomId = ChatRoomId( - IdentityAddress(row.get(0)), - IdentityAddress(row.get(1)) + IdentityAddress(row.get(1)), + IdentityAddress(row.get(2)) ); shared_ptr chatRoom = core->findChatRoom(chatRoomId); if (chatRoom) { @@ -1537,11 +1537,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), continue; } - tm creationTime = row.get(2); - tm lastUpdateTime = row.get(3); - int capabilities = row.get(4); - string subject = row.get(5); - unsigned int lastNotifyId = static_cast(row.get(6, 0)); + tm creationTime = row.get(3); + tm lastUpdateTime = row.get(4); + int capabilities = row.get(5); + string subject = row.get(6); + unsigned int lastNotifyId = static_cast(row.get(7, 0)); // TODO: Use me. (void)lastNotifyId; @@ -1555,9 +1555,13 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } else if (capabilities & static_cast(ChatRoom::Capabilities::Conference)) { list> participants; + long long dbChatRoomId = getBackend() == AbstractDb::Sqlite3 + ? static_cast(row.get(0)) + : row.get(0); + string query = "SELECT sip_address.value, is_admin" " FROM sip_address, chat_room, chat_room_participant" - " WHERE chat_room.id = :chatRoomId" + " WHERE chat_room.id = " + Utils::toString(dbChatRoomId) + " AND sip_address.id = chat_room_participant.participant_sip_address_id" " AND chat_room_participant.chat_room_id = chat_room.id"; From caacc7a87f58f6729026cd56d384c6366493746b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 27 Nov 2017 10:55:29 +0100 Subject: [PATCH 0873/2215] Started ChatRoom getLastChatMessage --- include/linphone/api/c-chat-room.h | 7 +++++++ src/c-wrapper/api/c-chat-room.cpp | 4 ++++ src/chat/chat-room/chat-room.cpp | 4 ++++ src/chat/chat-room/chat-room.h | 2 ++ src/db/main-db.cpp | 5 +++++ src/db/main-db.h | 1 + 6 files changed, 23 insertions(+) diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index d4e0d65b9..966f36896 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -202,6 +202,13 @@ LINPHONE_PUBLIC bctbx_list_t *linphone_chat_room_get_history_events (LinphoneCha */ LINPHONE_PUBLIC bctbx_list_t *linphone_chat_room_get_history_range_events (LinphoneChatRoom *cr, int begin, int end); +/** + * Gets the last chat message sent or received in this chat room + * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which last message should be retrieved + * @return the latest #LinphoneChatMessage + */ +LINPHONE_PUBLIC LinphoneChatMessage *linphone_chat_room_get_last_message_in_history(LinphoneChatRoom *cr); + LINPHONE_PUBLIC LinphoneChatMessage * linphone_chat_room_find_message(LinphoneChatRoom *cr, const char *message_id); /** diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 76aca9c08..90ffa6a66 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -217,6 +217,10 @@ bctbx_list_t *linphone_chat_room_get_history_range_events (LinphoneChatRoom *cr, ); } +LinphoneChatMessage *linphone_chat_room_get_last_message_in_history(LinphoneChatRoom *cr) { + return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getLastMessageInHistory()); +} + LinphoneChatMessage *linphone_chat_room_find_message (LinphoneChatRoom *cr, const char *message_id) { return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findMessage(message_id)); } diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 1cda16c65..3578537a6 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -447,6 +447,10 @@ list > ChatRoom::getHistoryRange (int startm, int endm) return list>(); } +shared_ptr ChatRoom::getLastMessageInHistory() const { + return getCore()->getPrivate()->mainDb->getLastChatMessage(getChatRoomId()); +} + int ChatRoom::getUnreadChatMessagesCount () { return getCore()->getPrivate()->mainDb->getUnreadChatMessagesCount(getChatRoomId()); } diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index b7e557353..4e6bc3d9a 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -58,6 +58,8 @@ public: virtual CapabilitiesMask getCapabilities () const = 0; + std::shared_ptr getLastMessageInHistory() const; + // TODO: Remove useless functions. void compose (); std::shared_ptr createFileTransferMessage (const LinphoneContent *initialContent); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index e6e22caaa..41969d42c 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1389,6 +1389,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return list>(); } + shared_ptr MainDb::getLastChatMessage(const ChatRoomId &chatRoomId) const { + // TODO. + return nullptr; + } + list> MainDb::getHistory (const ChatRoomId &chatRoomId, int nLast, FilterMask mask) const { return getHistoryRange(chatRoomId, 0, nLast - 1, mask); } diff --git a/src/db/main-db.h b/src/db/main-db.h index 6c2975efa..28e09437e 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -77,6 +77,7 @@ public: int getUnreadChatMessagesCount (const ChatRoomId &chatRoomId = ChatRoomId()) const; void markChatMessagesAsRead (const ChatRoomId &chatRoomId = ChatRoomId()) const; std::list> getUnreadChatMessages (const ChatRoomId &chatRoomId = ChatRoomId()) const; + std::shared_ptr getLastChatMessage(const ChatRoomId &chatRoomId = ChatRoomId()) const; // --------------------------------------------------------------------------- // Conference events. From 5c941ca6358aa5d1817309aabc8b72edb4c5b3ac Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 27 Nov 2017 11:27:10 +0100 Subject: [PATCH 0874/2215] add chatRoomGetLastMessage implementation --- src/db/main-db.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 41969d42c..49daee670 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1390,8 +1390,14 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } shared_ptr MainDb::getLastChatMessage(const ChatRoomId &chatRoomId) const { - // TODO. - return nullptr; + list> chatList = getHistory (chatRoomId, 1, Filter::ConferenceChatMessageFilter); + if (chatList.size() == 0) + return nullptr; + + L_ASSERT(chatList.size() == 1); + shared_ptr chatEvent = chatList.front(); + L_ASSERT(chatEvent->getType() == EventLog::Type::ConferenceChatMessage); + return static_pointer_cast(chatEvent)->getChatMessage(); } list> MainDb::getHistory (const ChatRoomId &chatRoomId, int nLast, FilterMask mask) const { From a6b6b7aeb4e59b3bb3ab3fba07469253473fb71e Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 27 Nov 2017 11:54:47 +0100 Subject: [PATCH 0875/2215] fix(MainDb): add me in db --- src/chat/chat-room/client-group-chat-room.cpp | 9 +++++---- src/chat/chat-room/client-group-chat-room.h | 3 ++- src/conference/conference-p.h | 7 +++---- src/db/main-db.cpp | 17 +++++++++++++++-- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index dbb526e49..a1d67734a 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -99,19 +99,20 @@ RemoteConference(core, me, nullptr) { ClientGroupChatRoom::ClientGroupChatRoom ( const shared_ptr &core, - const ChatRoomId &chatRoomId, + const IdentityAddress &peerAddress, + shared_ptr &me, const string &subject, list> &&participants -) : ChatRoom(*new ClientGroupChatRoomPrivate, core, chatRoomId), -RemoteConference(core, chatRoomId.getLocalAddress(), nullptr) { +) : ChatRoom(*new ClientGroupChatRoomPrivate, core, ChatRoomId(peerAddress, me->getAddress())), +RemoteConference(core, me->getAddress(), nullptr) { L_D(); L_D_T(RemoteConference, dConference); - const IdentityAddress &peerAddress = chatRoomId.getPeerAddress(); dConference->focus = make_shared(peerAddress); dConference->conferenceAddress = peerAddress; dConference->subject = subject; dConference->participants = move(participants); d->state = ChatRoom::State::Created; + getMe()->getPrivate()->setAdmin(me->isAdmin()); } shared_ptr ClientGroupChatRoom::getCore () const { diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index c0b240538..28ef3ffdd 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -41,7 +41,8 @@ public: ClientGroupChatRoom ( const std::shared_ptr &core, - const ChatRoomId &chatRoomId, + const IdentityAddress &peerAddress, + std::shared_ptr &me, const std::string &subject, std::list> &&participants ); diff --git a/src/conference/conference-p.h b/src/conference/conference-p.h index f738da3a5..242e76dc7 100644 --- a/src/conference/conference-p.h +++ b/src/conference/conference-p.h @@ -37,15 +37,14 @@ public: std::string subject; protected: - Conference *mPublic = nullptr; - std::shared_ptr activeParticipant; + std::shared_ptr me; + + Conference *mPublic = nullptr; private: CallListener *callListener = nullptr; - std::shared_ptr me; - L_DECLARE_PUBLIC(Conference); }; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 49daee670..c7804c371 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -235,6 +235,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::use(static_cast(chatRoom->getCapabilities())), soci::use(chatRoom->getSubject()); id = q->getLastInsertId(); + shared_ptr me = chatRoom->getMe(); + insertChatRoomParticipant(id, insertSipAddress(me->getAddress().asString()), me->isAdmin()); for (const auto &participant : chatRoom->getParticipants()) insertChatRoomParticipant(id, insertSipAddress(participant->getAddress().asString()), participant->isAdmin()); @@ -1577,13 +1579,24 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " AND chat_room_participant.chat_room_id = chat_room.id"; soci::rowset rows = (session->prepare << query); + shared_ptr me; for (const auto &row : rows) { shared_ptr participant = make_shared(IdentityAddress(row.get(0))); participant->getPrivate()->setAdmin(!!row.get(1)); - participants.push_back(participant); + + if (participant->getAddress() == chatRoomId.getPeerAddress()) + me = participant; + else + participants.push_back(participant); } - chatRoom = make_shared(core, chatRoomId, subject, move(participants)); + if (!me) { + lError() << "Unable to find me in: (peer=" + chatRoomId.getPeerAddress().asString() + + ", local=" + chatRoomId.getLocalAddress().asString() + ")."; + continue; + } + + chatRoom = make_shared(core, chatRoomId.getPeerAddress(), me, subject, move(participants)); } if (!chatRoom) From 81ff3c8813d3cd42a3624f903731c63400aec2fe Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 27 Nov 2017 11:55:51 +0100 Subject: [PATCH 0876/2215] fix index issue in data base --- src/c-wrapper/api/c-chat-room.cpp | 5 ++++- src/db/main-db.cpp | 13 +++++-------- src/db/main-db.h | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 90ffa6a66..97b982352 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -218,7 +218,10 @@ bctbx_list_t *linphone_chat_room_get_history_range_events (LinphoneChatRoom *cr, } LinphoneChatMessage *linphone_chat_room_get_last_message_in_history(LinphoneChatRoom *cr) { - return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getLastMessageInHistory()); + shared_ptr cppPtr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getLastMessageInHistory(); + LinphoneChatMessage *object = L_INIT(ChatMessage); + L_SET_CPP_PTR_FROM_C_OBJECT(object, cppPtr); + return object; } LinphoneChatMessage *linphone_chat_room_find_message (LinphoneChatRoom *cr, const char *message_id) { diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index c7804c371..198e1b971 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1391,19 +1391,16 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return list>(); } - shared_ptr MainDb::getLastChatMessage(const ChatRoomId &chatRoomId) const { - list> chatList = getHistory (chatRoomId, 1, Filter::ConferenceChatMessageFilter); - if (chatList.size() == 0) + shared_ptr MainDb::getLastChatMessage (const ChatRoomId &chatRoomId) const { + list> chatList = getHistory(chatRoomId, 1, Filter::ConferenceChatMessageFilter); + if (chatList.empty()) return nullptr; - L_ASSERT(chatList.size() == 1); - shared_ptr chatEvent = chatList.front(); - L_ASSERT(chatEvent->getType() == EventLog::Type::ConferenceChatMessage); - return static_pointer_cast(chatEvent)->getChatMessage(); + return static_pointer_cast(chatList.front())->getChatMessage(); } list> MainDb::getHistory (const ChatRoomId &chatRoomId, int nLast, FilterMask mask) const { - return getHistoryRange(chatRoomId, 0, nLast - 1, mask); + return getHistoryRange(chatRoomId, 0, nLast, mask); } list> MainDb::getHistoryRange ( diff --git a/src/db/main-db.h b/src/db/main-db.h index 28e09437e..c9303b8c1 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -77,7 +77,7 @@ public: int getUnreadChatMessagesCount (const ChatRoomId &chatRoomId = ChatRoomId()) const; void markChatMessagesAsRead (const ChatRoomId &chatRoomId = ChatRoomId()) const; std::list> getUnreadChatMessages (const ChatRoomId &chatRoomId = ChatRoomId()) const; - std::shared_ptr getLastChatMessage(const ChatRoomId &chatRoomId = ChatRoomId()) const; + std::shared_ptr getLastChatMessage (const ChatRoomId &chatRoomId = ChatRoomId()) const; // --------------------------------------------------------------------------- // Conference events. From 7bcfe622746f189b2025c54a4dd8e12de903e425 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 27 Nov 2017 12:00:10 +0100 Subject: [PATCH 0877/2215] manage null case --- src/c-wrapper/api/c-chat-room.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 97b982352..dd3d35c40 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -219,6 +219,9 @@ bctbx_list_t *linphone_chat_room_get_history_range_events (LinphoneChatRoom *cr, LinphoneChatMessage *linphone_chat_room_get_last_message_in_history(LinphoneChatRoom *cr) { shared_ptr cppPtr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getLastMessageInHistory(); + if (!cppPtr) + return nullptr; + LinphoneChatMessage *object = L_INIT(ChatMessage); L_SET_CPP_PTR_FROM_C_OBJECT(object, cppPtr); return object; From 5069a4a5085792e6303b1e0208ba24cd64408a6d Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 27 Nov 2017 12:20:11 +0100 Subject: [PATCH 0878/2215] use coreect address for 'me' and initiate chat room times with now --- src/chat/chat-room/chat-room-p.h | 4 ++-- src/db/main-db.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/chat/chat-room/chat-room-p.h b/src/chat/chat-room/chat-room-p.h index 853c2f557..e3d5d05b7 100644 --- a/src/chat/chat-room/chat-room-p.h +++ b/src/chat/chat-room/chat-room-p.h @@ -90,8 +90,8 @@ public: ChatRoomId chatRoomId; - time_t creationTime = -1; - time_t lastUpdateTime = -1; + time_t creationTime = std::time(nullptr); + time_t lastUpdateTime = std::time(nullptr); private: L_DECLARE_PUBLIC(ChatRoom); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 198e1b971..d48ecf95d 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1581,7 +1581,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), shared_ptr participant = make_shared(IdentityAddress(row.get(0))); participant->getPrivate()->setAdmin(!!row.get(1)); - if (participant->getAddress() == chatRoomId.getPeerAddress()) + if (participant->getAddress() == chatRoomId.getLocalAddress()) me = participant; else participants.push_back(participant); From 9a8181ee3108e7ab713d80edbaf705a457e01440 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 27 Nov 2017 12:24:47 +0100 Subject: [PATCH 0879/2215] Some fixes for call handling. --- coreapi/misc.c | 12 ++++-- src/chat/chat-room/basic-chat-room-p.h | 1 + src/chat/chat-room/basic-chat-room.cpp | 10 +++-- src/chat/chat-room/basic-chat-room.h | 2 +- src/chat/chat-room/client-group-chat-room.cpp | 2 +- src/chat/chat-room/client-group-chat-room.h | 2 +- .../chat-room/server-group-chat-room-stub.cpp | 2 +- src/chat/chat-room/server-group-chat-room.h | 2 +- src/conference/conference-interface.h | 2 +- src/conference/conference.cpp | 2 +- src/conference/conference.h | 2 +- src/conference/local-conference.cpp | 1 + src/conference/session/call-session-p.h | 1 + src/conference/session/call-session.cpp | 39 +++++++++++-------- src/conference/session/media-session.cpp | 4 +- 15 files changed, 51 insertions(+), 33 deletions(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index e7e0a0d9e..77e0ff2ef 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -940,14 +940,20 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, void linphone_core_report_call_log(LinphoneCore *lc, LinphoneCallLog *call_log){ bool_t call_logs_sqlite_db_found = FALSE; + // TODO: This is a workaround that has to be removed ASAP // Do not add calls made to the conference factory in the history char *to = linphone_address_as_string(call_log->to); const char *conference_factory_uri = linphone_core_get_conference_factory_uri(lc); - if (strcmp(conference_factory_uri, to) == 0) { - ms_free(to); + if (conference_factory_uri && (strcmp(conference_factory_uri, to) == 0)) { + bctbx_free(to); return; } - ms_free(to); + if (strstr(to, "chatroom-") == to) { + bctbx_free(to); + return; + } + bctbx_free(to); + // End of workaround #ifdef SQLITE_STORAGE_ENABLED if (lc->logs_db) { diff --git a/src/chat/chat-room/basic-chat-room-p.h b/src/chat/chat-room/basic-chat-room-p.h index 2429431bf..a87164730 100644 --- a/src/chat/chat-room/basic-chat-room-p.h +++ b/src/chat/chat-room/basic-chat-room-p.h @@ -35,6 +35,7 @@ private: void onChatMessageReceived (const std::shared_ptr &chatMessage) override; std::string subject; + std::list> participants; L_DECLARE_PUBLIC(BasicChatRoom); }; diff --git a/src/chat/chat-room/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp index 7b580914c..edaef84c1 100644 --- a/src/chat/chat-room/basic-chat-room.cpp +++ b/src/chat/chat-room/basic-chat-room.cpp @@ -42,7 +42,10 @@ BasicChatRoom::BasicChatRoom ( BasicChatRoomPrivate &p, const std::shared_ptr &core, const ChatRoomId &chatRoomId -) : ChatRoom(p, core, chatRoomId) {} +) : ChatRoom(p, core, chatRoomId) { + L_D(); + d->participants.push_back(make_shared(getPeerAddress())); +} BasicChatRoom::CapabilitiesMask BasicChatRoom::getCapabilities () const { return static_cast(Capabilities::Basic); @@ -87,8 +90,9 @@ int BasicChatRoom::getNbParticipants () const { return 1; } -list> BasicChatRoom::getParticipants () const { - return { make_shared(getPeerAddress()) }; +const list> &BasicChatRoom::getParticipants () const { + L_D(); + return d->participants; } void BasicChatRoom::setParticipantAdminStatus (shared_ptr &, bool) { diff --git a/src/chat/chat-room/basic-chat-room.h b/src/chat/chat-room/basic-chat-room.h index 283a2ad80..bf777e4c8 100644 --- a/src/chat/chat-room/basic-chat-room.h +++ b/src/chat/chat-room/basic-chat-room.h @@ -48,7 +48,7 @@ public: std::shared_ptr getMe () const override; int getNbParticipants () const override; - std::list> getParticipants () const override; + const std::list> &getParticipants () const override; void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) override; diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index a1d67734a..9ce0202b2 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -200,7 +200,7 @@ int ClientGroupChatRoom::getNbParticipants () const { return RemoteConference::getNbParticipants(); } -list> ClientGroupChatRoom::getParticipants () const { +const list> &ClientGroupChatRoom::getParticipants () const { return RemoteConference::getParticipants(); } diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 28ef3ffdd..9e55d915f 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -65,7 +65,7 @@ public: std::shared_ptr getMe () const override; int getNbParticipants () const override; - std::list> getParticipants () const override; + const std::list> &getParticipants () const override; void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) override; diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index e0ffc5ef9..5abf436d2 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -113,7 +113,7 @@ int ServerGroupChatRoom::getNbParticipants () const { return 0; } -list> ServerGroupChatRoom::getParticipants () const { +const list> &ServerGroupChatRoom::getParticipants () const { return LocalConference::getParticipants(); } diff --git a/src/chat/chat-room/server-group-chat-room.h b/src/chat/chat-room/server-group-chat-room.h index 73d0295de..9c8fc9d8a 100644 --- a/src/chat/chat-room/server-group-chat-room.h +++ b/src/chat/chat-room/server-group-chat-room.h @@ -55,7 +55,7 @@ public: std::shared_ptr getMe () const override; int getNbParticipants () const override; - std::list> getParticipants () const override; + const std::list> &getParticipants () const override; void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) override; diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index fd08fc0c3..db6b505c9 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -44,7 +44,7 @@ public: virtual const IdentityAddress &getConferenceAddress () const = 0; virtual std::shared_ptr getMe () const = 0; virtual int getNbParticipants () const = 0; - virtual std::list> getParticipants () const = 0; + virtual const std::list> &getParticipants () const = 0; virtual const std::string &getSubject () const = 0; virtual void join () = 0; virtual void leave () = 0; diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 52991d8b8..7c930cc24 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -88,7 +88,7 @@ int Conference::getNbParticipants () const { return static_cast(d->participants.size()); } -list> Conference::getParticipants () const { +const list> &Conference::getParticipants () const { L_D(); return d->participants; } diff --git a/src/conference/conference.h b/src/conference/conference.h index f7a723cd4..467dde80c 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -55,7 +55,7 @@ public: const IdentityAddress &getConferenceAddress () const override; std::shared_ptr getMe () const override; int getNbParticipants () const override; - std::list> getParticipants () const override; + const std::list> &getParticipants () const override; const std::string &getSubject () const override; void join () override; void leave () override; diff --git a/src/conference/local-conference.cpp b/src/conference/local-conference.cpp index 45c3707c5..cbaeef2db 100644 --- a/src/conference/local-conference.cpp +++ b/src/conference/local-conference.cpp @@ -42,6 +42,7 @@ void LocalConference::addParticipant (const IdentityAddress &addr, const CallSes if (participant) return; participant = make_shared(addr); + participant->getPrivate()->createSession(*this, params, hasMedia, this); d->participants.push_back(participant); if (!d->activeParticipant) d->activeParticipant = participant; diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index c850459ea..6f7e0fc3f 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -37,6 +37,7 @@ public: int computeDuration () const; virtual void initializeParamsAccordingToIncomingCallParams (); virtual void setState (LinphoneCallState newState, const std::string &message); + void startIncomingNotification (); bool startPing (); void setPingTime (int value) { pingTime = value; } diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index fe11ac162..36519991b 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -177,6 +177,27 @@ void CallSessionPrivate::setState(LinphoneCallState newState, const string &mess } } +void CallSessionPrivate::startIncomingNotification () { + L_Q(); + if (listener) + listener->onIncomingCallSessionStarted(q->getSharedFromThis()); + + setState(LinphoneCallIncomingReceived, "Incoming CallSession"); + + /* From now on, the application is aware of the call and supposed to take background task or already submitted notification to the user. + * We can then drop our background task. */ +#if 0 + if (call->bg_task_id!=0) { + sal_end_background_task(call->bg_task_id); + call->bg_task_id=0; + } +#endif + + if (state == LinphoneCallIncomingReceived) { + handleIncomingReceivedStateInIncomingNotification(); + } +} + bool CallSessionPrivate::startPing () { if (core->sip_conf.ping_with_options) { /* Defer the start of the call after the OPTIONS ping for outgoing call or @@ -850,23 +871,7 @@ void CallSession::startIncomingNotification () { return; } - if (d->listener) - d->listener->onIncomingCallSessionStarted(getSharedFromThis()); - - d->setState(LinphoneCallIncomingReceived, "Incoming CallSession"); - - /* From now on, the application is aware of the call and supposed to take background task or already submitted notification to the user. - * We can then drop our background task. */ -#if 0 - if (call->bg_task_id!=0) { - sal_end_background_task(call->bg_task_id); - call->bg_task_id=0; - } -#endif - - if (d->state == LinphoneCallIncomingReceived) { - d->handleIncomingReceivedStateInIncomingNotification(); - } + d->startIncomingNotification(); } int CallSession::startInvite (const Address *destination, const string &subject, const Content *content) { diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 74def1064..806dd4297 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -610,7 +610,7 @@ float MediaSessionPrivate::aggregateQualityRatings (float audioRating, float vid void MediaSessionPrivate::setState (LinphoneCallState newState, const string &message) { L_Q(); /* Take a ref on the session otherwise it might get destroyed during the call to setState */ - shared_ptr session = q->getSharedFromThis(); + shared_ptr sessionRef = q->getSharedFromThis(); CallSessionPrivate::setState(newState, message); updateReportingCallState(); } @@ -2092,7 +2092,7 @@ void MediaSessionPrivate::handleIceEvents (OrtpEvent *ev) { updateLocalMediaDescriptionFromIce(); op->set_local_media_description(localDesc); deferIncomingNotification = false; - static_cast(q)->startIncomingNotification(); + startIncomingNotification(); break; default: break; From cf7aaf8b6cf557b6d28b61802179ba2207afb4d1 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 27 Nov 2017 14:22:50 +0100 Subject: [PATCH 0880/2215] feat(MainDb): deal with participants removed --- src/db/main-db-p.h | 2 ++ src/db/main-db.cpp | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 9a46ac4e4..ee2cfc431 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -57,6 +57,8 @@ private: long long selectChatRoomId (long long peerSipAddressId, long long localSipAddressId) const; long long selectChatRoomId (const ChatRoomId &chatRoomId) const; + void deleteChatRoomParticipant (long long chatRoomId, long long participantSipAddressId); + // --------------------------------------------------------------------------- // Events API. // --------------------------------------------------------------------------- diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index d48ecf95d..a530c76a0 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -303,6 +303,13 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return selectChatRoomId(peerSipAddressId, localSipAddressId); } + void MainDbPrivate::deleteChatRoomParticipant (long long chatRoomId, long long participantSipAddressId) { + soci::session *session = dbSession.getBackendSession(); + *session << "DELETE FROM chat_room_participant" + " WHERE chat_room_id = :chatRoomId AND participant_sip_address_id = :participantSipAddressId", + soci::use(chatRoomId), soci::use(participantSipAddressId); + } + // ----------------------------------------------------------------------------- shared_ptr MainDbPrivate::selectGenericConferenceEvent ( @@ -695,7 +702,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), break; case EventLog::Type::ConferenceParticipantRemoved: - // TODO: Deal with remove. + deleteChatRoomParticipant(chatRoomId, participantAddressId); + break; default: break; From 33c9f56f154ac18f4fad98f7f109b2265304b7d2 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 27 Nov 2017 14:40:02 +0100 Subject: [PATCH 0881/2215] fix(Core): init cpp before before start --- coreapi/linphonecore.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 728f94bfd..79f57875f 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2019,6 +2019,10 @@ static void linphone_core_start(LinphoneCore * lc) { #endif lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon; + + new(&lc->cppCore) std::shared_ptr(); + lc->cppCore = Core::create(lc); + linphone_core_set_state(lc,LinphoneGlobalOn,"Ready"); } @@ -2277,9 +2281,6 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig lc->sal->set_user_pointer(lc); lc->sal->set_callbacks(&linphone_sal_callbacks); - new(&lc->cppCore) std::shared_ptr(); - lc->cppCore = Core::create(lc); - #ifdef TUNNEL_ENABLED lc->tunnel=linphone_core_tunnel_new(lc); #endif From a63b6c76019b84bc5833cf2f9bddea80289b4ba7 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 27 Nov 2017 15:01:56 +0100 Subject: [PATCH 0882/2215] subscribe when creating a chatroom from db + fix creation of basic chat room from db --- src/chat/chat-room/client-group-chat-room.cpp | 5 +++++ src/db/main-db.cpp | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 9ce0202b2..7371bb27c 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -107,12 +107,17 @@ ClientGroupChatRoom::ClientGroupChatRoom ( RemoteConference(core, me->getAddress(), nullptr) { L_D(); L_D_T(RemoteConference, dConference); + dConference->focus = make_shared(peerAddress); dConference->conferenceAddress = peerAddress; dConference->subject = subject; dConference->participants = move(participants); + d->state = ChatRoom::State::Created; + getMe()->getPrivate()->setAdmin(me->isAdmin()); + + dConference->eventHandler->subscribe(getChatRoomId()); } shared_ptr ClientGroupChatRoom::getCore () const { diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index a530c76a0..7231be79c 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -235,6 +235,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::use(static_cast(chatRoom->getCapabilities())), soci::use(chatRoom->getSubject()); id = q->getLastInsertId(); + + if (!chatRoom->canHandleParticipants()) + return id; + shared_ptr me = chatRoom->getMe(); insertChatRoomParticipant(id, insertSipAddress(me->getAddress().asString()), me->isAdmin()); for (const auto &participant : chatRoom->getParticipants()) From 049371e75772c77e90d5e7d9e8fd43d536f2abf9 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 27 Nov 2017 15:30:21 +0100 Subject: [PATCH 0883/2215] fix(MainDb): add a resolve id function (soci workaround) --- src/db/main-db-p.h | 10 ++++++++++ src/db/main-db.cpp | 31 ++++++++++++++----------------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index ee2cfc431..af8fbab2d 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -26,6 +26,10 @@ // ============================================================================= +namespace soci { + class row; +} + LINPHONE_BEGIN_NAMESPACE class Content; @@ -35,6 +39,12 @@ public: std::unordered_map> storageIdToEvent; private: + // --------------------------------------------------------------------------- + // SOCI helpers. + // --------------------------------------------------------------------------- + + long long resolveId (const soci::row &row, int col) const; + // --------------------------------------------------------------------------- // Low level API. // --------------------------------------------------------------------------- diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 7231be79c..495ec386d 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -119,6 +119,15 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), // ----------------------------------------------------------------------------- + long long MainDbPrivate::resolveId (const soci::row &row, int col) const { + L_Q(); + // See: http://soci.sourceforge.net/doc/master/backends/ + // `row id` is not supported by soci on Sqlite3. It's necessary to cast id to int... + return q->getBackend() == AbstractDb::Sqlite3 + ? static_cast(row.get(0)) + : row.get(0); + } + long long MainDbPrivate::insertSipAddress (const string &sipAddress) { L_Q(); soci::session *session = dbSession.getBackendSession(); @@ -444,9 +453,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), if (contentType == ContentType::FileTransfer) content = new FileTransferContent(); else if (contentType.isFile()) { - long long contentId = q->getBackend() == AbstractDb::Sqlite3 - ? static_cast(row.get(0)) - : row.get(0); + long long contentId = resolveId(row, 0); string name; int size; @@ -764,14 +771,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } void MainDbPrivate::invalidConferenceEventsFromQuery (const string &query, long long chatRoomId) { - L_Q(); - soci::session *session = dbSession.getBackendSession(); soci::rowset rows = (session->prepare << query, soci::use(chatRoomId)); for (const auto &row : rows) { - shared_ptr eventLog = getEventFromCache( - q->getBackend() == AbstractDb::Sqlite3 ? static_cast(row.get(0)) : row.get(0) - ); + shared_ptr eventLog = getEventFromCache(resolveId(row, 0)); if (eventLog) { const EventLogPrivate *dEventLog = eventLog->getPrivate(); L_ASSERT(dEventLog->dbKey.isValid()); @@ -1267,7 +1270,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::rowset rows = (session->prepare << query, soci::use(d->selectChatRoomId(chatRoomId)), soci::use(lastNotifyId)); for (const auto &row : rows) { - long long eventId = getBackend() == Sqlite3 ? static_cast(row.get(0)) : row.get(0); + long long eventId = d->resolveId(row, 0); shared_ptr eventLog = d->getEventFromCache(eventId); events.push_back(eventLog ? eventLog : d->selectGenericConferenceEvent( @@ -1469,9 +1472,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::rowset rows = (session->prepare << query); for (const auto &row : rows) { - // See: http://soci.sourceforge.net/doc/master/backends/ - // `row id` is not supported by soci on Sqlite3. It's necessary to cast id to int... - long long eventId = getBackend() == Sqlite3 ? static_cast(row.get(0)) : row.get(0); + long long eventId = d->resolveId(row, 0); shared_ptr event = d->getEventFromCache(eventId); if (!event) @@ -1577,13 +1578,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } else if (capabilities & static_cast(ChatRoom::Capabilities::Conference)) { list> participants; - long long dbChatRoomId = getBackend() == AbstractDb::Sqlite3 - ? static_cast(row.get(0)) - : row.get(0); - string query = "SELECT sip_address.value, is_admin" " FROM sip_address, chat_room, chat_room_participant" - " WHERE chat_room.id = " + Utils::toString(dbChatRoomId) + + " WHERE chat_room.id = " + Utils::toString(d->resolveId(row, 0)) + " AND sip_address.id = chat_room_participant.participant_sip_address_id" " AND chat_room_participant.chat_room_id = chat_room.id"; From f6a6edc78780feaf11c9a7727b5dc3a32903e6d8 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 27 Nov 2017 15:43:33 +0100 Subject: [PATCH 0884/2215] fix(file-transfer-chat-message-modifier): test if transfer server is null --- src/chat/modifier/file-transfer-chat-message-modifier.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.cpp b/src/chat/modifier/file-transfer-chat-message-modifier.cpp index 6016ad50c..c7f9c6438 100644 --- a/src/chat/modifier/file-transfer-chat-message-modifier.cpp +++ b/src/chat/modifier/file-transfer-chat-message-modifier.cpp @@ -430,7 +430,8 @@ int FileTransferChatMessageModifier::uploadFile () { cbs.process_io_error = _chat_message_process_io_error_upload; cbs.process_auth_requested = _chat_message_process_auth_requested_upload; - int err = startHttpTransfer(linphone_core_get_file_transfer_server(chatMessage->getCore()->getCCore()), "POST", &cbs); + const char *url = linphone_core_get_file_transfer_server(chatMessage->getCore()->getCCore()); + int err = startHttpTransfer(url ? url : "", "POST", &cbs); return err; } From 6a1debb72c4b5efc2deb86afd957f51da2a92d21 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 27 Nov 2017 15:55:28 +0100 Subject: [PATCH 0885/2215] fix(MainDb): add space before state value in conference chat message update --- src/db/main-db.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 495ec386d..8f7f9dc68 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1371,7 +1371,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return; string query = "UPDATE FROM conference_chat_message_event" - " SET state = " + Utils::toString(static_cast(ChatMessage::State::Displayed)); + " SET state = " + Utils::toString(static_cast(ChatMessage::State::Displayed)) + " "; query += "WHERE"; if (chatRoomId.isValid()) query += " event_id IN (" From ca159350b8bdaa9147518d581485e26ffe46f8e5 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 27 Nov 2017 16:02:30 +0100 Subject: [PATCH 0886/2215] Some more fixes for call handling. --- src/conference/session/media-session.cpp | 10 ++++------ src/content/content-type.cpp | 5 +++++ src/content/content-type.h | 1 + src/content/content.cpp | 2 +- src/sal/call-op.cpp | 9 ++++++--- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 806dd4297..51f1225d2 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -3143,19 +3143,17 @@ void MediaSessionPrivate::updateStreams (SalMediaDescription *newMd, LinphoneCal ms_message("Playing ringback tone, will restart the streams."); #endif else { -#if 0 - if (call->all_muted && (targetState == LinphoneCallStreamsRunning)) { + if (allMuted && (targetState == LinphoneCallStreamsRunning)) { lInfo() << "Early media finished, unmuting inputs..."; /* We were in early media, now we want to enable real media */ - call->all_muted = FALSE; + allMuted = false; if (audioStream) linphone_core_enable_mic(core, linphone_core_mic_enabled(core)); #ifdef VIDEO_ENABLED if (videoStream && cameraEnabled) - linphone_call_enable_camera(call, linphone_call_camera_enabled(call)); + q->enableCamera(q->cameraEnabled()); #endif } -#endif if (mdChanged == SAL_MEDIA_DESCRIPTION_UNCHANGED) { /* FIXME ZRTP, might be restarted in any cases? */ lInfo() << "No need to restart streams, SDP is unchanged"; @@ -4201,11 +4199,11 @@ LinphoneStatus MediaSession::resume () { if (d->audioStream) audio_stream_play(d->audioStream, nullptr); d->makeLocalMediaDescription(); + sal_media_description_set_dir(d->localDesc, SalStreamSendRecv); if (!d->core->sip_conf.sdp_200_ack) d->op->set_local_media_description(d->localDesc); else d->op->set_local_media_description(nullptr); - sal_media_description_set_dir(d->localDesc, SalStreamSendRecv); string subject = "Call resuming"; if (d->params->getPrivate()->getInConference() && !getCurrentParams()->getPrivate()->getInConference()) subject = "Conference"; diff --git a/src/content/content-type.cpp b/src/content/content-type.cpp index 7245bf36f..b0851de71 100644 --- a/src/content/content-type.cpp +++ b/src/content/content-type.cpp @@ -151,6 +151,11 @@ void ContentType::setParameter (const string ¶meter) { d->parameter = parameter; } +bool ContentType::isEmpty () const { + L_D(); + return d->type.empty() && d->subType.empty(); +} + bool ContentType::isValid () const { L_D(); return !d->type.empty() && !d->subType.empty(); diff --git a/src/content/content-type.h b/src/content/content-type.h index 6969ce843..8da5f1cb5 100644 --- a/src/content/content-type.h +++ b/src/content/content-type.h @@ -45,6 +45,7 @@ public: bool operator== (const std::string &contentType) const = delete; bool operator!= (const std::string &contentType) const = delete; + bool isEmpty () const; bool isValid () const; bool isFile () const; diff --git a/src/content/content.cpp b/src/content/content.cpp index 68d86e9fd..8b309431d 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -153,7 +153,7 @@ bool Content::isEmpty () const { bool Content::isValid () const { L_D(); - return d->contentType.isValid() || d->body.empty(); + return d->contentType.isValid() || (d->contentType.isEmpty() && d->body.empty()); } LinphoneContent *Content::toLinphoneContent () const { diff --git a/src/sal/call-op.cpp b/src/sal/call-op.cpp index bd6d4ba16..bd269be58 100644 --- a/src/sal/call-op.cpp +++ b/src/sal/call-op.cpp @@ -255,7 +255,10 @@ int SalCallOp::parse_sdp_body(const Content &body,belle_sdp_session_description_ return 0; } - *session_desc = belle_sdp_session_description_parse(body.getBodyAsString().c_str()); + string strBody = body.getBodyAsString(); + if (strBody.empty()) + return 0; + *session_desc = belle_sdp_session_description_parse(strBody.c_str()); if (*session_desc == NULL) { ms_error("Failed to parse SDP message."); *error = SalReasonNotAcceptable; @@ -330,7 +333,7 @@ void SalCallOp::sdp_process(){ void SalCallOp::handle_body_from_response(belle_sip_response_t* response) { SalReason reason; - belle_sdp_session_description_t* sdp; + belle_sdp_session_description_t* sdp = nullptr; Content body = extract_body(BELLE_SIP_MESSAGE(response)); if (this->remote_media){ sal_media_description_unref(this->remote_media); @@ -568,7 +571,7 @@ SalReason SalCallOp::process_body_for_invite(belle_sip_request_t* invite) { Content body = extract_body(BELLE_SIP_MESSAGE(invite)); if (!body.isValid()) return SalReasonUnsupportedContent; - if (body.getContentType() == ContentType::Sdp) { + if ((body.getContentType() == ContentType::Sdp) || (body.getContentType().isEmpty() && body.isEmpty())) { belle_sdp_session_description_t* sdp; if (parse_sdp_body(body, &sdp, &reason) == 0) { if (sdp) { From 8a23ea59b7d4ce324b467a13382ed6c6458cbafb Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 27 Nov 2017 16:43:09 +0100 Subject: [PATCH 0887/2215] Fix 2 call-related crashes. --- src/conference/session/call-session.cpp | 2 +- src/conference/session/media-session.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 36519991b..b5d333881 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -1049,7 +1049,7 @@ LinphoneCallState CallSession::getState () const { string CallSession::getRemoteUserAgent () const { L_D(); - if (d->op) + if (d->op && d->op->get_remote_ua()) return d->op->get_remote_ua(); return string(); } diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 51f1225d2..e3a56d749 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -4317,7 +4317,7 @@ LinphoneStatus MediaSession::update (const MediaSessionParams *msp, const string if (d->currentParams == msp) lWarning() << "CallSession::update() is given the current params, this is probably not what you intend to do!"; d->iceAgent->checkSession(IR_Controlling, true); - if (d->params) { + if (msp) { #if 0 call->broken = FALSE; #endif From 5781fcbde2a332a7938be120e5e9d6f8b550c8fc Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 27 Nov 2017 17:11:41 +0100 Subject: [PATCH 0888/2215] Fix SRTP crypto key generation. --- src/conference/session/media-session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index e3a56d749..4f32a203a 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -1158,7 +1158,7 @@ void MediaSessionPrivate::forceStreamsDirAccordingToState (SalMediaDescription * bool MediaSessionPrivate::generateB64CryptoKey (size_t keyLength, char *keyOut, size_t keyOutSize) { uint8_t *tmp = (uint8_t *)ms_malloc0(keyLength); - if (sal_get_random_bytes(tmp, keyLength)) { + if (!sal_get_random_bytes(tmp, keyLength)) { lError() << "Failed to generate random key"; ms_free(tmp); return false; From 1896eff9fe56b97e9639a3892fd24c25db029e1b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 27 Nov 2017 17:45:16 +0100 Subject: [PATCH 0889/2215] Several fixes for calls. --- coreapi/linphonecore.c | 1 + src/c-wrapper/api/c-call.cpp | 25 +++++++++++++++--------- src/call/call.cpp | 5 +++++ src/call/call.h | 1 + src/conference/session/media-session.cpp | 2 +- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 79f57875f..7ef9445b9 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -532,6 +532,7 @@ void linphone_core_set_log_level(OrtpLogLevel loglevel) { void linphone_core_set_log_level_mask(unsigned int loglevel) { //we only have 2 domain for now ortp and belle-sip bctbx_set_log_level_mask(ORTP_LOG_DOMAIN, (int)loglevel); + bctbx_set_log_level_mask("mediastreamer", (int)loglevel); bctbx_set_log_level_mask("bzrtp", (int)loglevel); /*need something to set log lvel for all domains*/ sal_set_log_level((OrtpLogLevel)loglevel); } diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index dc86b5a1c..e1e9c4058 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -38,11 +38,13 @@ L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(Call, _linphone_call_constructor, _linphone_call_destructor, bctbx_list_t *callbacks; /* A list of LinphoneCallCbs object */ LinphoneCallCbs *currentCbs; /* The current LinphoneCallCbs object used to call a callback */ + char *authenticationTokenCache; LinphoneCallParams *currentParamsCache; LinphoneCallParams *paramsCache; LinphoneCallParams *remoteParamsCache; LinphoneAddress *remoteAddressCache; char *remoteContactCache; + char *remoteUserAgentCache; /* TODO: all the fields need to be removed */ struct _LinphoneCore *core; LinphoneErrorInfo *ei; @@ -713,14 +715,13 @@ const LinphoneErrorInfo *linphone_call_get_error_info (const LinphoneCall *call) } const char *linphone_call_get_remote_user_agent (LinphoneCall *call) { -#if 0 - if (call->op){ - return sal_op_get_remote_ua (call->op); - } - return nullptr; -#else - return nullptr; -#endif + string ua = L_GET_CPP_PTR_FROM_C_OBJECT(call)->getRemoteUserAgent(); + if (ua.empty()) + return nullptr; + if (call->remoteUserAgentCache) + bctbx_free(call->remoteUserAgentCache); + call->remoteUserAgentCache = bctbx_strdup(ua.c_str()); + return call->remoteUserAgentCache; } const char * linphone_call_get_remote_contact (LinphoneCall *call) { @@ -734,7 +735,13 @@ const char * linphone_call_get_remote_contact (LinphoneCall *call) { } const char *linphone_call_get_authentication_token (LinphoneCall *call) { - return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(call)->getAuthenticationToken()); + string token = L_GET_CPP_PTR_FROM_C_OBJECT(call)->getAuthenticationToken(); + if (token.empty()) + return nullptr; + if (call->authenticationTokenCache) + bctbx_free(call->authenticationTokenCache); + call->authenticationTokenCache = bctbx_strdup(token.c_str()); + return call->authenticationTokenCache; } bool_t linphone_call_get_authentication_token_verified (const LinphoneCall *call) { diff --git a/src/call/call.cpp b/src/call/call.cpp index 3a6eeef86..d371c5a1b 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -475,6 +475,11 @@ const MediaSessionParams *Call::getRemoteParams () const { return static_cast(d->getActiveSession().get())->getRemoteParams(); } +string Call::getRemoteUserAgent () const { + L_D(); + return d->getActiveSession()->getRemoteUserAgent(); +} + float Call::getSpeakerVolumeGain () const { L_D(); return static_cast(d->getActiveSession().get())->getSpeakerVolumeGain(); diff --git a/src/call/call.h b/src/call/call.h index a3d840c87..0b46058db 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -96,6 +96,7 @@ public: std::string getRemoteAddressAsString () const; std::string getRemoteContact () const; const MediaSessionParams *getRemoteParams () const; + std::string getRemoteUserAgent () const; float getSpeakerVolumeGain () const; LinphoneCallState getState () const; LinphoneCallStats *getStats (LinphoneStreamType type) const; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 4f32a203a..36b04a315 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -926,7 +926,7 @@ int MediaSessionPrivate::selectFixedPort (int streamIndex, pair portRa int MediaSessionPrivate::selectRandomPort (int streamIndex, pair portRange) { for (int nbTries = 0; nbTries < 100; nbTries++) { bool alreadyUsed = false; - int triedPort = (static_cast(ortp_random()) % (portRange.second - portRange.first) + portRange.first) & ~0x1; + int triedPort = static_cast((ortp_random() % (portRange.second - portRange.first) + portRange.first) & ~0x1); if (triedPort < portRange.first) triedPort = portRange.first + 2; for (const bctbx_list_t *elem = linphone_core_get_calls(core); elem != nullptr; elem = bctbx_list_next(elem)) { LinphoneCall *lcall = reinterpret_cast(bctbx_list_get_data(elem)); From 94a51d3ec1b7dd69fd595e1eab50fda72c33dbda Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 27 Nov 2017 18:00:33 +0100 Subject: [PATCH 0890/2215] fix cast build crash --- src/conference/session/media-session.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 36b04a315..684b8a6cd 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -926,7 +926,8 @@ int MediaSessionPrivate::selectFixedPort (int streamIndex, pair portRa int MediaSessionPrivate::selectRandomPort (int streamIndex, pair portRange) { for (int nbTries = 0; nbTries < 100; nbTries++) { bool alreadyUsed = false; - int triedPort = static_cast((ortp_random() % (portRange.second - portRange.first) + portRange.first) & ~0x1); + unsigned int mask = 1; + int triedPort = static_cast((ortp_random() % static_cast((portRange.second - portRange.first) + portRange.first)) & ~mask); if (triedPort < portRange.first) triedPort = portRange.first + 2; for (const bctbx_list_t *elem = linphone_core_get_calls(core); elem != nullptr; elem = bctbx_list_next(elem)) { LinphoneCall *lcall = reinterpret_cast(bctbx_list_get_data(elem)); From ef7ae680ffbe24b4dfc4791d614532a52f1ca199 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 28 Nov 2017 11:12:06 +0100 Subject: [PATCH 0891/2215] Add Message-ID header in CPIM messages. --- src/chat/chat-message/chat-message.cpp | 3 ++- src/chat/cpim/header/cpim-core-headers.cpp | 1 + src/chat/cpim/header/cpim-core-headers.h | 1 + src/chat/cpim/parser/cpim-grammar.cpp | 2 ++ src/chat/cpim/parser/cpim-parser.cpp | 7 +++++++ src/chat/modifier/cpim-chat-message-modifier.cpp | 8 ++++++++ 6 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index f7e02e512..2ceb5f27f 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -554,7 +554,8 @@ void ChatMessagePrivate::send () { } } - q->setImdnMessageId(op->get_call_id()); /* must be known at that time */ + if (q->getImdnMessageId().empty()) + q->setImdnMessageId(op->get_call_id()); /* must be known at that time */ //store(); // Store will be done right below in the setState(InProgress) diff --git a/src/chat/cpim/header/cpim-core-headers.cpp b/src/chat/cpim/header/cpim-core-headers.cpp index 2673f3b6e..be6031056 100644 --- a/src/chat/cpim/header/cpim-core-headers.cpp +++ b/src/chat/cpim/header/cpim-core-headers.cpp @@ -49,6 +49,7 @@ MAKE_CORE_HEADER_IMPL(From); MAKE_CORE_HEADER_IMPL(To); MAKE_CORE_HEADER_IMPL(Cc); MAKE_CORE_HEADER_IMPL(DateTime); +MAKE_CORE_HEADER_IMPL(MessageId); MAKE_CORE_HEADER_IMPL(Ns); MAKE_CORE_HEADER_IMPL(Require); diff --git a/src/chat/cpim/header/cpim-core-headers.h b/src/chat/cpim/header/cpim-core-headers.h index 55bb51f0b..deb052958 100644 --- a/src/chat/cpim/header/cpim-core-headers.h +++ b/src/chat/cpim/header/cpim-core-headers.h @@ -72,6 +72,7 @@ namespace Cpim { MAKE_CORE_HEADER(To, "To"); MAKE_CORE_HEADER(Cc, "cc"); MAKE_CORE_HEADER(DateTime, "DateTime"); + MAKE_CORE_HEADER(MessageId, "Message-ID"); MAKE_CORE_HEADER(Ns, "NS"); MAKE_CORE_HEADER(Require, "Require"); diff --git a/src/chat/cpim/parser/cpim-grammar.cpp b/src/chat/cpim/parser/cpim-grammar.cpp index 245477855..09a7c50c2 100644 --- a/src/chat/cpim/parser/cpim-grammar.cpp +++ b/src/chat/cpim/parser/cpim-grammar.cpp @@ -53,6 +53,8 @@ To-header-value = [ Formal-name ] "<" URI ">" DateTime-header = %d68.97.116.101.84.105.109.101 ": " DateTime-header-value DateTime-header-value = date-time +Message-ID-header = %d77.101.115.115.97.103.101.45.73.68 ": " Token + cc-header = %d99.99 ": " cc-header-value cc-header-value = [ Formal-name ] "<" URI ">" diff --git a/src/chat/cpim/parser/cpim-parser.cpp b/src/chat/cpim/parser/cpim-parser.cpp index b54a9a45b..56adb64d5 100644 --- a/src/chat/cpim/parser/cpim-parser.cpp +++ b/src/chat/cpim/parser/cpim-parser.cpp @@ -130,6 +130,7 @@ namespace Cpim { { "To", &HeaderNode::createCoreHeader }, { "cc", &HeaderNode::createCoreHeader }, { "DateTime", &HeaderNode::createCoreHeader }, + { "Message-ID", &HeaderNode::createCoreHeader }, { "Subject", &HeaderNode::createCoreHeader }, { "NS", &HeaderNode::createCoreHeader }, { "Require", &HeaderNode::createCoreHeader } @@ -394,6 +395,12 @@ bool Cpim::Parser::coreHeaderIsValid(const string &headerV return true; } +template<> +bool Cpim::Parser::coreHeaderIsValid(const string &headerValue) const { + L_D(); + return LinphonePrivate::coreHeaderIsValid(d->grammar, "Message-ID", headerValue); +} + template<> bool Cpim::Parser::coreHeaderIsValid(const string &headerValue) const { L_D(); diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index b3de39ef5..e0ac09768 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -45,6 +45,12 @@ ChatMessageModifier::Result CpimChatMessageModifier::encode (const shared_ptrgetToAddress())); cpimMessage.addMessageHeader(cpimToHeader); + char token[13]; + belle_sip_random_token(token, sizeof(token)); + Cpim::MessageIdHeader cpimMessageIdHeader; + cpimMessageIdHeader.setValue(token); + cpimMessage.addMessageHeader(cpimMessageIdHeader); + message->setImdnMessageId(token); const Content *content; if (!message->getInternalContent().isEmpty()) { @@ -127,6 +133,8 @@ ChatMessageModifier::Result CpimChatMessageModifier::decode (const shared_ptrgetValue()); else if (header->getName() == "To") cpimToAddress = Address(header->getValue()); + else if (header->getName() == "Message-Id") + message->setImdnMessageId(header->getValue()); } } From dfbfd1bf98cdec46d0f7f849308cc71d99da2d4a Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 28 Nov 2017 11:14:23 +0100 Subject: [PATCH 0892/2215] fix(MainDb): see http://soci.sourceforge.net/doc/3.2/exchange.html, Object lifetime and immutability part --- src/db/main-db.cpp | 141 +++++++++++++++++++++++++++------------------ 1 file changed, 86 insertions(+), 55 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 8f7f9dc68..8e0fc9d1e 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -42,6 +42,11 @@ // ============================================================================= +// See: http://soci.sourceforge.net/doc/3.2/exchange.html +// Part: Object lifetime and immutability + +// ----------------------------------------------------------------------------- + using namespace std; LINPHONE_BEGIN_NAMESPACE @@ -145,18 +150,21 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), L_Q(); soci::session *session = dbSession.getBackendSession(); - long long contentTypeId = insertContentType(content.getContentType().asString()); + const long long &contentTypeId = insertContentType(content.getContentType().asString()); + const string &body = content.getBodyAsString(); *session << "INSERT INTO chat_message_content (event_id, content_type_id, body) VALUES" " (:eventId, :contentTypeId, :body)", soci::use(eventId), soci::use(contentTypeId), - soci::use(content.getBodyAsString()); + soci::use(body); - long long messageContentId = q->getLastInsertId(); + const long long &messageContentId = q->getLastInsertId(); if (content.getContentType().isFile()) { const FileContent &fileContent = static_cast(content); + const string &fileName = fileContent.getFileName(); + const size_t &fileSize = fileContent.getFileSize(); + const string &filePath = fileContent.getFilePath(); *session << "INSERT INTO chat_message_file_content (chat_message_content_id, name, size, path) VALUES " " (:contentId, :name, :size, :path)", - soci::use(messageContentId), soci::use(fileContent.getFileName()), - soci::use(fileContent.getFileSize()), soci::use(fileContent.getFilePath()); + soci::use(messageContentId), soci::use(fileName), soci::use(fileSize), soci::use(filePath); } for (const auto &appData : content.getAppDataMap()) @@ -168,9 +176,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), void MainDbPrivate::updateContent (long long eventId, long long messageContentId, const Content &content) { soci::session *session = dbSession.getBackendSession(); - long long contentTypeId = insertContentType(content.getContentType().asString()); + const long long &contentTypeId = insertContentType(content.getContentType().asString()); + const string &body = content.getBodyAsString(); *session << "UPDATE chat_message_content SET content_type_id=:contentTypeId, body=:body WHERE event_id=:eventId", - soci::use(contentTypeId), soci::use(content.getBodyAsString()), soci::use(eventId); + soci::use(contentTypeId), soci::use(body), soci::use(eventId); for (const auto &appData : content.getAppDataMap()) *session << "UPDATE chat_message_content_app_data SET name=:name, data=:data WHERE chat_message_content_id=:messageContentId", @@ -222,8 +231,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); const ChatRoomId &chatRoomId = chatRoom->getChatRoomId(); - long long peerSipAddressId = insertSipAddress(chatRoomId.getPeerAddress().asString()); - long long localSipAddressId = insertSipAddress(chatRoomId.getLocalAddress().asString()); + const long long &peerSipAddressId = insertSipAddress(chatRoomId.getPeerAddress().asString()); + const long long &localSipAddressId = insertSipAddress(chatRoomId.getLocalAddress().asString()); long long id = selectChatRoomId(peerSipAddressId, localSipAddressId); if (id >= 0) { @@ -235,13 +244,14 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), lInfo() << "Insert new chat room in database: (peer=" << peerSipAddressId << ", local=" << localSipAddressId << ")."; - tm creationTime = Utils::getTimeTAsTm(chatRoom->getCreationTime()); - + const tm &creationTime = Utils::getTimeTAsTm(chatRoom->getCreationTime()); + const int &capabilities = static_cast(chatRoom->getCapabilities()); + const string &subject = chatRoom->getSubject(); *session << "INSERT INTO chat_room (" " peer_sip_address_id, local_sip_address_id, creation_time, last_update_time, capabilities, subject" ") VALUES (:peerSipAddressId, :localSipAddressId, :creationTime, :lastUpdateTime, :capabilities, :subject)", soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::use(creationTime), soci::use(creationTime), - soci::use(static_cast(chatRoom->getCapabilities())), soci::use(chatRoom->getSubject()); + soci::use(capabilities), soci::use(subject); id = q->getLastInsertId(); @@ -257,18 +267,20 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } void MainDbPrivate::insertChatRoomParticipant (long long chatRoomId, long long sipAddressId, bool isAdmin) { + // See: https://stackoverflow.com/a/15299655 (cast to reference) + soci::session *session = dbSession.getBackendSession(); soci::statement statement = ( session->prepare << "UPDATE chat_room_participant SET is_admin = :isAdmin" " WHERE chat_room_id = :chatRoomId AND participant_sip_address_id = :sipAddressId", - soci::use(static_cast(isAdmin)), soci::use(chatRoomId), soci::use(sipAddressId) + soci::use(static_cast(isAdmin)), soci::use(chatRoomId), soci::use(sipAddressId) ); statement.execute(true); if (statement.get_affected_rows() == 0) { lInfo() << "Insert new chat room participant in database: `" << sipAddressId << "` (isAdmin=" << isAdmin << ")."; *session << "INSERT INTO chat_room_participant (chat_room_id, participant_sip_address_id, is_admin)" " VALUES (:chatRoomId, :sipAddressId, :isAdmin)", - soci::use(chatRoomId), soci::use(sipAddressId), soci::use(static_cast(isAdmin)); + soci::use(chatRoomId), soci::use(sipAddressId), soci::use(static_cast(isAdmin)); } } @@ -453,7 +465,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), if (contentType == ContentType::FileTransfer) content = new FileTransferContent(); else if (contentType.isFile()) { - long long contentId = resolveId(row, 0); + const long long &contentId = resolveId(row, 0); string name; int size; @@ -572,9 +584,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), L_Q(); soci::session *session = dbSession.getBackendSession(); + const int &type = static_cast(eventLog->getType()); + const tm &creationTime = Utils::getTimeTAsTm(eventLog->getCreationTime()); *session << "INSERT INTO event (type, creation_time) VALUES (:type, :creationTime)", - soci::use(static_cast(eventLog->getType())), - soci::use(Utils::getTimeTAsTm(eventLog->getCreationTime())); + soci::use(type), + soci::use(creationTime); + return q->getLastInsertId(); } @@ -582,7 +597,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), shared_ptr conferenceEvent = static_pointer_cast(eventLog); long long eventId = -1; - long long curChatRoomId = selectChatRoomId(conferenceEvent->getChatRoomId()); + const long long &curChatRoomId = selectChatRoomId(conferenceEvent->getChatRoomId()); if (curChatRoomId < 0) { // A conference event can be inserted in database only if chat room exists. // Otherwise it's an error. @@ -597,8 +612,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "INSERT INTO conference_event (event_id, chat_room_id)" " VALUES (:eventId, :chatRoomId)", soci::use(eventId), soci::use(curChatRoomId); + const tm &lastUpdateTime = Utils::getTimeTAsTm(eventLog->getCreationTime()); *session << "UPDATE chat_room SET last_update_time = :lastUpdateTime" - " WHERE id = :chatRoomId", soci::use(Utils::getTimeTAsTm(eventLog->getCreationTime())), + " WHERE id = :chatRoomId", soci::use(lastUpdateTime), soci::use(curChatRoomId); } @@ -621,14 +637,20 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return -1; } - long long eventId = insertConferenceEvent(eventLog); + const long long &eventId = insertConferenceEvent(eventLog); if (eventId < 0) return -1; - long long fromSipAddressId = insertSipAddress(chatMessage->getFromAddress().asString()); - long long toSipAddressId = insertSipAddress(chatMessage->getToAddress().asString()); - soci::session *session = dbSession.getBackendSession(); + + const long long &fromSipAddressId = insertSipAddress(chatMessage->getFromAddress().asString()); + const long long &toSipAddressId = insertSipAddress(chatMessage->getToAddress().asString()); + const tm &messageTime = Utils::getTimeTAsTm(chatMessage->getTime()); + const int &state = static_cast(chatMessage->getState()); + const int &direction = static_cast(chatMessage->getDirection()); + const string &imdnMessageId = chatMessage->getImdnMessageId(); + const int &isSecured = chatMessage->isSecured() ? 1 : 0; + *session << "INSERT INTO conference_chat_message_event (" " event_id, from_sip_address_id, to_sip_address_id," " time, state, direction, imdn_message_id, is_secured" @@ -636,9 +658,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " :eventId, :localSipaddressId, :remoteSipaddressId," " :time, :state, :direction, :imdnMessageId, :isSecured" ")", soci::use(eventId), soci::use(fromSipAddressId), soci::use(toSipAddressId), - soci::use(Utils::getTimeTAsTm(chatMessage->getTime())), soci::use(static_cast(chatMessage->getState())), - soci::use(static_cast(chatMessage->getDirection())), soci::use(chatMessage->getImdnMessageId()), - soci::use(chatMessage->isSecured() ? 1 : 0); + soci::use(messageTime), soci::use(state), soci::use(direction), + soci::use(imdnMessageId), soci::use(isSecured); for (const Content *content : chatMessage->getContents()) insertContent(eventId, *content); @@ -656,11 +677,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), const EventLogPrivate *dEventLog = eventLog->getPrivate(); MainDbEventKeyPrivate *dEventKey = dEventLog->dbKey.getPrivate(); - long long eventId = dEventKey->storageId; + const long long &eventId = dEventKey->storageId; soci::session *session = dbSession.getBackendSession(); - *session << "UPDATE conference_chat_message_event SET state=:state WHERE event_id=:eventId" - , soci::use(static_cast(chatMessage->getState())), soci::use(eventId); + const int &state = static_cast(chatMessage->getState()); + *session << "UPDATE conference_chat_message_event SET state = :state WHERE event_id = :eventId", + soci::use(state), soci::use(eventId); /*for (const Content *content : chatMessage->getContents()) updateContent(eventId, *content);*/ @@ -669,11 +691,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long MainDbPrivate::insertConferenceNotifiedEvent (const shared_ptr &eventLog, long long *chatRoomId) { long long curChatRoomId; - long long eventId = insertConferenceEvent(eventLog, &curChatRoomId); + const long long &eventId = insertConferenceEvent(eventLog, &curChatRoomId); if (eventId < 0) return -1; - unsigned int lastNotifyId = static_pointer_cast(eventLog)->getNotifyId(); + const unsigned int &lastNotifyId = static_pointer_cast(eventLog)->getNotifyId(); soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_notified_event (event_id, notify_id)" @@ -689,14 +711,14 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long MainDbPrivate::insertConferenceParticipantEvent (const shared_ptr &eventLog) { long long chatRoomId; - long long eventId = insertConferenceNotifiedEvent(eventLog, &chatRoomId); + const long long &eventId = insertConferenceNotifiedEvent(eventLog, &chatRoomId); if (eventId < 0) return -1; shared_ptr participantEvent = static_pointer_cast(eventLog); - long long participantAddressId = insertSipAddress( + const long long &participantAddressId = insertSipAddress( participantEvent->getParticipantAddress().asString() ); @@ -724,11 +746,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } long long MainDbPrivate::insertConferenceParticipantDeviceEvent (const shared_ptr &eventLog) { - long long eventId = insertConferenceParticipantEvent(eventLog); + const long long &eventId = insertConferenceParticipantEvent(eventLog); if (eventId < 0) return -1; - long long deviceAddressId = insertSipAddress( + const long long &deviceAddressId = insertSipAddress( static_pointer_cast(eventLog)->getDeviceAddress().asString() ); @@ -741,7 +763,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long MainDbPrivate::insertConferenceSubjectEvent (const shared_ptr &eventLog) { long long chatRoomId; - long long eventId = insertConferenceNotifiedEvent(eventLog, &chatRoomId); + const long long &eventId = insertConferenceNotifiedEvent(eventLog, &chatRoomId); if (eventId < 0) return -1; @@ -1268,7 +1290,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = d->dbSession.getBackendSession(); soci::transaction tr(*session); - soci::rowset rows = (session->prepare << query, soci::use(d->selectChatRoomId(chatRoomId)), soci::use(lastNotifyId)); + const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); + + soci::rowset rows = (session->prepare << query, soci::use(dbChatRoomId), soci::use(lastNotifyId)); for (const auto &row : rows) { long long eventId = d->resolveId(row, 0); shared_ptr eventLog = d->getEventFromCache(eventId); @@ -1313,7 +1337,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" ")"; - *session << query, soci::use(d->selectChatRoomId(chatRoomId)), soci::into(count); + const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); + *session << query, soci::use(dbChatRoomId), soci::into(count); } L_END_LOG_EXCEPTION @@ -1351,8 +1376,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), if (!chatRoomId.isValid()) *session << query, soci::into(count); - else - *session << query, soci::use(d->selectChatRoomId(chatRoomId)), soci::into(count); + else { + const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); + *session << query, soci::use(dbChatRoomId), soci::into(count); + } L_END_LOG_EXCEPTION @@ -1390,8 +1417,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), if (!chatRoomId.isValid()) *session << query; - else - *session << query, soci::use(d->selectChatRoomId(chatRoomId)); + else { + const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); + *session << query, soci::use(dbChatRoomId); + } L_END_LOG_EXCEPTION } @@ -1515,7 +1544,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), L_BEGIN_LOG_EXCEPTION - long long dbChatRoomId = d->selectChatRoomId(chatRoomId); + const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); d->invalidConferenceEventsFromQuery(query, dbChatRoomId); soci::session *session = d->dbSession.getBackendSession(); @@ -1663,7 +1692,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), L_BEGIN_LOG_EXCEPTION - long long dbChatRoomId = d->selectChatRoomId(chatRoomId); + const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); d->invalidConferenceEventsFromQuery( "SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId", @@ -1736,7 +1765,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), continue; } - const int state = message.get( + const int &state = message.get( LEGACY_MESSAGE_COL_STATE, static_cast(ChatMessage::State::Displayed) ); if (state < 0 || state > static_cast(ChatMessage::State::Displayed)) { @@ -1744,12 +1773,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), continue; } - const tm creationTime = Utils::getTimeTAsTm(message.get(LEGACY_MESSAGE_COL_DATE, 0)); + const tm &creationTime = Utils::getTimeTAsTm(message.get(LEGACY_MESSAGE_COL_DATE, 0)); bool isNull; - const string url = getValueFromLegacyMessage(message, LEGACY_MESSAGE_COL_URL, isNull); + const string &url = getValueFromLegacyMessage(message, LEGACY_MESSAGE_COL_URL, isNull); - const int contentId = message.get(LEGACY_MESSAGE_COL_CONTENT_ID, -1); + const int &contentId = message.get(LEGACY_MESSAGE_COL_CONTENT_ID, -1); ContentType contentType(message.get(LEGACY_MESSAGE_COL_CONTENT_TYPE, "")); if (!contentType.isValid()) contentType = contentId != -1 @@ -1760,7 +1789,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), continue; } - const string text = getValueFromLegacyMessage(message, LEGACY_MESSAGE_COL_TEXT, isNull); + const string &text = getValueFromLegacyMessage(message, LEGACY_MESSAGE_COL_TEXT, isNull); Content content; content.setContentType(contentType); @@ -1786,18 +1815,20 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } soci::session *session = d->dbSession.getBackendSession(); + const int &eventType = static_cast(EventLog::Type::ConferenceChatMessage); *session << "INSERT INTO event (type, creation_time) VALUES (:type, :creationTime)", - soci::use(static_cast(EventLog::Type::ConferenceChatMessage)), soci::use(creationTime); + soci::use(eventType), soci::use(creationTime); - long long eventId = getLastInsertId(); - long long localSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_LOCAL_ADDRESS)); - long long remoteSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_REMOTE_ADDRESS)); - long long chatRoomId = d->insertChatRoom( + const long long &eventId = getLastInsertId(); + const long long &localSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_LOCAL_ADDRESS)); + const long long &remoteSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_REMOTE_ADDRESS)); + const long long &chatRoomId = d->insertChatRoom( remoteSipAddressId, localSipAddressId, static_cast(ChatRoom::Capabilities::Basic), creationTime ); + const int &isSecured = message.get(LEGACY_MESSAGE_COL_IS_SECURED, 0); *session << "INSERT INTO conference_event (event_id, chat_room_id)" " VALUES (:eventId, :chatRoomId)", soci::use(eventId), soci::use(chatRoomId); @@ -1810,7 +1841,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " :creationTime, :state, :direction, '', :isSecured" ")", soci::use(eventId), soci::use(localSipAddressId), soci::use(remoteSipAddressId), soci::use(creationTime), soci::use(state), soci::use(direction), - soci::use(message.get(LEGACY_MESSAGE_COL_IS_SECURED, 0)); + soci::use(isSecured); d->insertContent(eventId, content); d->insertChatRoomParticipant(chatRoomId, remoteSipAddressId, false); From 6b93b7c8c7146f587f585a62d431e5abe9953b8e Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 28 Nov 2017 11:47:59 +0100 Subject: [PATCH 0893/2215] keep removing soci workaround --- src/db/main-db.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 8e0fc9d1e..ee45b91c2 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1470,10 +1470,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return events; } + const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); string query = "SELECT id, type, creation_time FROM event" " WHERE id IN (" - " SELECT event_id FROM conference_event WHERE chat_room_id = " + - Utils::toString(d->selectChatRoomId(chatRoomId)) + + " SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" " )"; query += buildSqlEventFilter({ ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter @@ -1499,7 +1499,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = d->dbSession.getBackendSession(); soci::transaction tr(*session); - soci::rowset rows = (session->prepare << query); + soci::rowset rows = (session->prepare << query, soci::use(dbChatRoomId)); for (const auto &row : rows) { long long eventId = d->resolveId(row, 0); shared_ptr event = d->getEventFromCache(eventId); @@ -1607,13 +1607,14 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } else if (capabilities & static_cast(ChatRoom::Capabilities::Conference)) { list> participants; + const long long &dbChatRoomId = d->resolveId(row, 0); string query = "SELECT sip_address.value, is_admin" " FROM sip_address, chat_room, chat_room_participant" - " WHERE chat_room.id = " + Utils::toString(d->resolveId(row, 0)) + + " WHERE chat_room.id = :chatRoomId" " AND sip_address.id = chat_room_participant.participant_sip_address_id" " AND chat_room_participant.chat_room_id = chat_room.id"; - soci::rowset rows = (session->prepare << query); + soci::rowset rows = (session->prepare << query, soci::use(dbChatRoomId)); shared_ptr me; for (const auto &row : rows) { shared_ptr participant = make_shared(IdentityAddress(row.get(0))); @@ -1776,7 +1777,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), const tm &creationTime = Utils::getTimeTAsTm(message.get(LEGACY_MESSAGE_COL_DATE, 0)); bool isNull; - const string &url = getValueFromLegacyMessage(message, LEGACY_MESSAGE_COL_URL, isNull); + getValueFromLegacyMessage(message, LEGACY_MESSAGE_COL_URL, isNull); const int &contentId = message.get(LEGACY_MESSAGE_COL_CONTENT_ID, -1); ContentType contentType(message.get(LEGACY_MESSAGE_COL_CONTENT_TYPE, "")); From fec65e98d7016e84f305ecb221125888513566cc Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 28 Nov 2017 14:09:57 +0100 Subject: [PATCH 0894/2215] feat(MainDb): add a function to find a message by imdn id --- src/db/main-db.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++--- src/db/main-db.h | 8 +++++- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index ee45b91c2..de08c61b3 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -225,7 +225,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return q->getLastInsertId(); } - long long MainDbPrivate::insertChatRoom (const std::shared_ptr &chatRoom) { + long long MainDbPrivate::insertChatRoom (const shared_ptr &chatRoom) { L_Q(); soci::session *session = dbSession.getBackendSession(); @@ -298,7 +298,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::use(eventId), soci::use(sipAddressId), soci::use(state); } - long long MainDbPrivate::selectSipAddressId (const std::string &sipAddress) const { + long long MainDbPrivate::selectSipAddressId (const string &sipAddress) const { soci::session *session = dbSession.getBackendSession(); long long id; @@ -667,7 +667,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return eventId; } - void MainDbPrivate::updateConferenceChatMessageEvent(const std::shared_ptr &eventLog) { + void MainDbPrivate::updateConferenceChatMessageEvent (const shared_ptr &eventLog) { shared_ptr chatMessage = static_pointer_cast(eventLog)->getChatMessage(); shared_ptr chatRoom = chatMessage->getChatRoom(); if (!chatRoom) { @@ -1443,6 +1443,62 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return static_pointer_cast(chatList.front())->getChatMessage(); } + list> MainDb::findChatMessages ( + const ChatRoomId &chatRoomId, + const string &imdnMessageId + ) const { + L_D(); + + list> chatMessages; + + if (!isConnected()) { + lWarning() << "Unable to find chat messages. Not connected."; + return chatMessages; + } + + const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); + string query = "SELECT id, type, creation_time FROM event" + " WHERE id IN (" + " SELECT event_id FROM conference_event" + " WHERE event_id IN (SELECT event_id FROM conference_chat_message_event WHERE imdn_message_id = :imdnMessageId)" + " AND chat_room_id = :chatRoomId" + " )"; + + DurationLogger durationLogger( + "Find chat messages: (peer=" + chatRoomId.getPeerAddress().asString() + + ", local=" + chatRoomId.getLocalAddress().asString() + ")." + ); + + L_BEGIN_LOG_EXCEPTION + + soci::session *session = d->dbSession.getBackendSession(); + soci::transaction tr(*session); + + soci::rowset rows = (session->prepare << query, soci::use(imdnMessageId), soci::use(dbChatRoomId)); + for (const auto &row : rows) { + long long eventId = d->resolveId(row, 0); + shared_ptr event = d->getEventFromCache(eventId); + + if (!event) + event = d->selectGenericConferenceEvent( + eventId, + static_cast(row.get(1)), + Utils::getTmAsTimeT(row.get(2)), + chatRoomId + ); + + if (event) { + L_ASSERT(event->getType() == EventLog::Type::ConferenceChatMessage); + chatMessages.push_back(static_pointer_cast(event)->getChatMessage()); + } else + lWarning() << "Unable to fetch event: " << eventId; + } + + L_END_LOG_EXCEPTION + + return chatMessages; + } + list> MainDb::getHistory (const ChatRoomId &chatRoomId, int nLast, FilterMask mask) const { return getHistoryRange(chatRoomId, 0, nLast, mask); } diff --git a/src/db/main-db.h b/src/db/main-db.h index c9303b8c1..2cd5de58f 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -77,7 +77,13 @@ public: int getUnreadChatMessagesCount (const ChatRoomId &chatRoomId = ChatRoomId()) const; void markChatMessagesAsRead (const ChatRoomId &chatRoomId = ChatRoomId()) const; std::list> getUnreadChatMessages (const ChatRoomId &chatRoomId = ChatRoomId()) const; - std::shared_ptr getLastChatMessage (const ChatRoomId &chatRoomId = ChatRoomId()) const; + + std::shared_ptr getLastChatMessage (const ChatRoomId &chatRoomId) const; + + std::list> findChatMessages ( + const ChatRoomId &chatRoomId, + const std::string &imdnMessageId + ) const; // --------------------------------------------------------------------------- // Conference events. From 08a2180cbc814cce8cef33a677fdc348e88b00fc Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 28 Nov 2017 13:29:50 +0100 Subject: [PATCH 0895/2215] Fix reception of INFO messages. --- coreapi/callbacks.c | 8 ++++--- coreapi/info.c | 24 ++++++++----------- coreapi/private.h | 2 +- include/linphone/info_message.h | 2 +- src/call/call-listener.h | 1 + src/call/call-p.h | 1 + src/call/call.cpp | 5 ++++ src/conference/conference.cpp | 6 +++++ src/conference/conference.h | 1 + .../session/call-session-listener.h | 1 + src/conference/session/call-session-p.h | 1 + src/conference/session/call-session.cpp | 14 +++++++++++ 12 files changed, 47 insertions(+), 19 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index e83c4bac4..e2a672940 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -640,9 +640,11 @@ static void message_delivery_update(SalOp *op, SalMessageDeliveryStatus status){ } } -static void info_received(SalOp *op, SalBodyHandler *body_handler){ - LinphoneCore *lc=(LinphoneCore *)op->get_sal()->get_user_pointer(); - linphone_core_notify_info_message(lc,op,body_handler); +static void info_received(SalOp *op, SalBodyHandler *body_handler) { + LinphonePrivate::CallSession *session = reinterpret_cast(op->get_user_pointer()); + if (!session) + return; + L_GET_PRIVATE(session)->infoReceived(body_handler); } static void subscribe_response(SalOp *op, SalSubscribeStatus status, int will_retry){ diff --git a/coreapi/info.c b/coreapi/info.c index fb1cd4a17..5b12089bb 100644 --- a/coreapi/info.c +++ b/coreapi/info.c @@ -84,8 +84,10 @@ const char *linphone_info_message_get_header(const LinphoneInfoMessage *im, cons return sal_custom_header_find(im->headers,name); } -void linphone_info_message_set_content(LinphoneInfoMessage *im, const LinphoneContent *content){ - im->content=linphone_content_copy(content); +void linphone_info_message_set_content (LinphoneInfoMessage *im, const LinphoneContent *content) { + if (im->content) + linphone_content_unref(im->content); + im->content = linphone_content_copy(content); } const LinphoneContent * linphone_info_message_get_content(const LinphoneInfoMessage *im){ @@ -96,17 +98,11 @@ SalCustomHeader *linphone_info_message_get_headers (const LinphoneInfoMessage *i return im->headers; } -void linphone_core_notify_info_message ( - LinphoneCore* lc, - LinphonePrivate::SalOp *op, - SalBodyHandler *body_handler -) { - LinphoneCall *call=(LinphoneCall*)op->get_user_pointer(); - if (call){ - LinphoneInfoMessage *info=linphone_core_create_info_message(lc); - info->headers=sal_custom_header_clone(op->get_recv_custom_header()); - if (body_handler) info->content=linphone_content_from_sal_body_handler(body_handler); - linphone_call_notify_info_message_received(call, info); - linphone_info_message_unref(info); +void linphone_info_message_set_headers (LinphoneInfoMessage *im, const SalCustomHeader *headers) { + if (im->headers) { + sal_custom_header_free(im->headers); + im->headers = nullptr; } + if (headers) + im->headers = sal_custom_header_clone(headers); } diff --git a/coreapi/private.h b/coreapi/private.h index da493d8f5..7270f010b 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -1152,7 +1152,6 @@ const char *linphone_core_create_uuid(LinphoneCore *lc); void linphone_configure_op(LinphoneCore *lc, LinphonePrivate::SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact); void linphone_configure_op_with_proxy(LinphoneCore *lc, LinphonePrivate::SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact, LinphoneProxyConfig *proxy); void linphone_call_create_op(LinphoneCall *call); -void linphone_core_notify_info_message(LinphoneCore* lc,LinphonePrivate::SalOp *op, SalBodyHandler *body); LinphoneContent * linphone_content_new(void); LinphoneContent * linphone_content_copy(const LinphoneContent *ref); SalBodyHandler *sal_body_handler_from_content(const LinphoneContent *content); @@ -1586,6 +1585,7 @@ LinphoneNatPolicy * linphone_config_create_nat_policy_from_section(const Linphon SalCustomHeader *linphone_info_message_get_headers (const LinphoneInfoMessage *im); +void linphone_info_message_set_headers (LinphoneInfoMessage *im, const SalCustomHeader *headers); #ifdef __cplusplus diff --git a/include/linphone/info_message.h b/include/linphone/info_message.h index 06a59ee2a..ce92628e6 100644 --- a/include/linphone/info_message.h +++ b/include/linphone/info_message.h @@ -57,7 +57,7 @@ LINPHONE_PUBLIC const char *linphone_info_message_get_header(const LinphoneInfoM * @param content the content described as a #LinphoneContent structure. * All fields of the LinphoneContent are copied, thus the application can destroy/modify/recycloe the content object freely ater the function returns. **/ -LINPHONE_PUBLIC void linphone_info_message_set_content(LinphoneInfoMessage *im, const LinphoneContent *content); +LINPHONE_PUBLIC void linphone_info_message_set_content(LinphoneInfoMessage *im, const LinphoneContent *content); /** * Returns the info message's content as a #LinphoneContent structure. diff --git a/src/call/call-listener.h b/src/call/call-listener.h index 6a2feab41..44f721518 100644 --- a/src/call/call-listener.h +++ b/src/call/call-listener.h @@ -38,6 +38,7 @@ public: virtual void onCheckForAcceptation () = 0; virtual void onIncomingCallStarted () = 0; virtual void onIncomingCallToBeAdded () = 0; + virtual void onInfoReceived (const LinphoneInfoMessage *im) = 0; virtual void onEncryptionChanged (bool activated, const std::string &authToken) = 0; diff --git a/src/call/call-p.h b/src/call/call-p.h index 5c75fa610..a8e5666b2 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -77,6 +77,7 @@ private: void onCheckForAcceptation () override; void onIncomingCallStarted () override; void onIncomingCallToBeAdded () override; + void onInfoReceived (const LinphoneInfoMessage *im) override; void onEncryptionChanged (bool activated, const std::string &authToken) override; void onStatsUpdated (const LinphoneCallStats *stats) override; void onResetCurrentCall () override; diff --git a/src/call/call.cpp b/src/call/call.cpp index d371c5a1b..9d6341f04 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -177,6 +177,11 @@ void CallPrivate::onIncomingCallToBeAdded () { linphone_core_add_call(core, lcall); } +void CallPrivate::onInfoReceived (const LinphoneInfoMessage *im) { + if (lcall) + linphone_call_notify_info_message_received(lcall, im); +} + void CallPrivate::onEncryptionChanged (bool activated, const string &authToken) { if (lcall) linphone_call_notify_encryption_changed(lcall, activated, authToken.empty() ? nullptr : authToken.c_str()); diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 7c930cc24..15424caef 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -170,6 +170,12 @@ void Conference::onIncomingCallSessionStarted (const shared_ptrcallListener->onIncomingCallStarted(); } +void Conference::onInfoReceived (const std::shared_ptr &session, const LinphoneInfoMessage *im) { + L_D(); + if (d->callListener) + d->callListener->onInfoReceived(im); +} + void Conference::onEncryptionChanged (const shared_ptr &session, bool activated, const string &authToken) { L_D(); if (d->callListener) diff --git a/src/conference/conference.h b/src/conference/conference.h index 467dde80c..de8e29de4 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -74,6 +74,7 @@ private: void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) override; void onCheckForAcceptation (const std::shared_ptr &session) override; void onIncomingCallSessionStarted (const std::shared_ptr &session) override; + void onInfoReceived (const std::shared_ptr &session, const LinphoneInfoMessage *im) override; void onEncryptionChanged (const std::shared_ptr &session, bool activated, const std::string &authToken) override; void onStatsUpdated (const LinphoneCallStats *stats) override; void onResetCurrentSession (const std::shared_ptr &session) override; diff --git a/src/conference/session/call-session-listener.h b/src/conference/session/call-session-listener.h index a0d7e9520..0259138dd 100644 --- a/src/conference/session/call-session-listener.h +++ b/src/conference/session/call-session-listener.h @@ -38,6 +38,7 @@ public: virtual void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) = 0; virtual void onCheckForAcceptation (const std::shared_ptr &session) = 0; virtual void onIncomingCallSessionStarted (const std::shared_ptr &session) = 0; + virtual void onInfoReceived (const std::shared_ptr &session, const LinphoneInfoMessage *im) = 0; virtual void onEncryptionChanged (const std::shared_ptr &session, bool activated, const std::string &authToken) = 0; diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index 6f7e0fc3f..a607f26ac 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -49,6 +49,7 @@ public: void ackBeingSent (LinphoneHeaders *headers); virtual void ackReceived (LinphoneHeaders *headers); virtual bool failure (); + void infoReceived (SalBodyHandler *bodyHandler); void pingReply (); virtual void remoteRinging (); virtual void terminated (); diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index b5d333881..d322ba057 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -322,6 +322,20 @@ bool CallSessionPrivate::failure () { return false; } +void CallSessionPrivate::infoReceived (SalBodyHandler *bodyHandler) { + L_Q(); + LinphoneInfoMessage *info = linphone_core_create_info_message(core); + linphone_info_message_set_headers(info, op->get_recv_custom_header()); + if (bodyHandler) { + LinphoneContent *content = linphone_content_from_sal_body_handler(bodyHandler); + linphone_info_message_set_content(info, content); + linphone_content_unref(content); + } + if (listener) + listener->onInfoReceived(q->getSharedFromThis(), info); + linphone_info_message_unref(info); +} + void CallSessionPrivate::pingReply () { L_Q(); if (state == LinphoneCallOutgoingInit) { From 56f8dcc57aad9dc07e2978061dbb1162ba0d74eb Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 28 Nov 2017 13:42:58 +0100 Subject: [PATCH 0896/2215] Fix return value of MediaSession::update(). --- src/conference/session/media-session.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 684b8a6cd..f37983a33 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -4313,6 +4313,7 @@ LinphoneStatus MediaSession::update (const MediaSessionParams *msp, const string L_D(); LinphoneCallState nextState; LinphoneCallState initialState = d->state; + LinphoneStatus result = 0; if (!d->isUpdateAllowed(nextState)) return -1; if (d->currentParams == msp) @@ -4328,7 +4329,7 @@ LinphoneStatus MediaSession::update (const MediaSessionParams *msp, const string lInfo() << "Defer CallSession update to gather ICE candidates"; return 0; } - LinphoneStatus result = d->startUpdate(subject); + result = d->startUpdate(subject); if (result && (d->state != initialState)) { /* Restore initial state */ d->setState(initialState, "Restore initial state"); @@ -4349,7 +4350,7 @@ LinphoneStatus MediaSession::update (const MediaSessionParams *msp, const string } #endif } - return 0; + return result; } // ----------------------------------------------------------------------------- From 25e51fc63a2221e0391619f3895780b7a9fd5df4 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 28 Nov 2017 13:55:03 +0100 Subject: [PATCH 0897/2215] Fix SalCallOp::set_local_media_description() with nullptr parameter. --- src/sal/call-op.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/sal/call-op.cpp b/src/sal/call-op.cpp index bd269be58..43e2179d3 100644 --- a/src/sal/call-op.cpp +++ b/src/sal/call-op.cpp @@ -36,17 +36,21 @@ SalCallOp::~SalCallOp() { } int SalCallOp::set_local_media_description(SalMediaDescription *desc) { - if (desc) sal_media_description_ref(desc); + if (desc) { + sal_media_description_ref(desc); + belle_sip_error_code error; + belle_sdp_session_description_t *sdp = media_description_to_sdp(desc); + vector buffer = marshal_media_description(sdp, error); + if (error != BELLE_SIP_OK) return -1; - belle_sip_error_code error; - belle_sdp_session_description_t *sdp = media_description_to_sdp(desc); - vector buffer = marshal_media_description(sdp, error); - if (error != BELLE_SIP_OK) return -1; + this->local_body.setContentType(ContentType::Sdp); + this->local_body.setBody(move(buffer)); + } else { + this->local_body = Content(); + } - this->local_body.setContentType(ContentType::Sdp); - this->local_body.setBody(move(buffer)); - - if (this->local_media) sal_media_description_unref(this->local_media); + if (this->local_media) + sal_media_description_unref(this->local_media); this->local_media=desc; if (this->remote_media){ From 7d16001da2a4fd8edc8ba55cc0763dc50fdd5224 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 28 Nov 2017 14:46:57 +0100 Subject: [PATCH 0898/2215] Fix creation of player in call. --- src/c-wrapper/api/c-call.cpp | 8 +------- src/call/call-p.h | 3 +++ src/call/call.cpp | 14 ++++++++++++++ src/call/call.h | 1 + 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index e1e9c4058..2294b527b 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -1048,13 +1048,7 @@ void linphone_call_stop_recording (LinphoneCall *call) { } LinphonePlayer *linphone_call_get_player (LinphoneCall *call) { -#if 0 - if (!call->player) - call->player=linphone_call_build_player(call); - return call->player; -#else - return nullptr; -#endif + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getPlayer(); } bool_t linphone_call_media_in_progress (const LinphoneCall *call) { diff --git a/src/call/call-p.h b/src/call/call-p.h index a8e5666b2..a5885c403 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -67,6 +67,8 @@ public: SalCallOp *getOp () const; void setAudioMuted (bool value); + void createPlayer () const; + private: /* CallListener */ void onAckBeingSent (LinphoneHeaders *headers) override; @@ -89,6 +91,7 @@ private: LinphoneCore *core = nullptr; Conference *conference = nullptr; + mutable LinphonePlayer *player = nullptr; CallCallbackObj nextVideoFrameDecoded; diff --git a/src/call/call.cpp b/src/call/call.cpp index 9d6341f04..d68a20330 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -103,6 +103,13 @@ int CallPrivate::startInvite (const Address *destination) { // ----------------------------------------------------------------------------- +void CallPrivate::createPlayer () const { + L_Q(); + player = linphone_call_build_player(L_GET_C_BACK_PTR(q)); +} + +// ----------------------------------------------------------------------------- + void CallPrivate::onAckBeingSent (LinphoneHeaders *headers) { if (lcall) linphone_call_notify_ack_processing(lcall, headers, false); @@ -445,6 +452,13 @@ const MediaSessionParams *Call::getParams () const { return static_cast(d->getActiveSession().get())->getMediaParams(); } +LinphonePlayer *Call::getPlayer () const { + L_D(); + if (!d->player) + d->createPlayer(); + return d->player; +} + float Call::getPlayVolume () const { L_D(); return static_cast(d->getActiveSession().get())->getPlayVolume(); diff --git a/src/call/call.h b/src/call/call.h index 0b46058db..fee720d5a 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -89,6 +89,7 @@ public: float getMicrophoneVolumeGain () const; void *getNativeVideoWindowId () const; const MediaSessionParams *getParams () const; + LinphonePlayer *getPlayer () const; float getPlayVolume () const; LinphoneReason getReason () const; float getRecordVolume () const; From ec74e66eb71af86f946dfe08bcb633fb0a24802c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 28 Nov 2017 14:47:06 +0100 Subject: [PATCH 0899/2215] Fix ogl render. --- src/c-wrapper/api/c-call.cpp | 10 +--------- src/call/call.cpp | 6 ++++++ src/call/call.h | 1 + src/conference/session/media-session-p.h | 1 + src/conference/session/media-session.cpp | 8 ++++++++ src/conference/session/media-session.h | 1 + 6 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 2294b527b..2630d627d 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -1056,15 +1056,7 @@ bool_t linphone_call_media_in_progress (const LinphoneCall *call) { } void linphone_call_ogl_render (const LinphoneCall *call) { -#if 0 - #ifdef VIDEO_ENABLED - - VideoStream *stream = call->videostream; - if (stream && stream->output && ms_filter_get_id(stream->output) == MS_OGL_ID) - ms_filter_call_method(stream->output, MS_OGL_RENDER, nullptr); - - #endif -#endif + L_GET_CPP_PTR_FROM_C_OBJECT(call)->oglRender(); } LinphoneStatus linphone_call_send_info_message (LinphoneCall *call, const LinphoneInfoMessage *info) { diff --git a/src/call/call.cpp b/src/call/call.cpp index d68a20330..b353d2a44 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -17,6 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "c-wrapper/c-wrapper.h" #include "call-p.h" #include "conference/local-conference.h" #include "conference/participant-p.h" @@ -276,6 +277,11 @@ LinphoneStatus Call::decline (const LinphoneErrorInfo *ei) { return d->getActiveSession()->decline(ei); } +void Call::oglRender () const { + L_D(); + static_pointer_cast(d->getActiveSession())->getPrivate()->oglRender(); +} + LinphoneStatus Call::pause () { L_D(); return static_cast(d->getActiveSession().get())->pause(); diff --git a/src/call/call.h b/src/call/call.h index fee720d5a..ca48c4826 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -53,6 +53,7 @@ public: LinphoneStatus acceptUpdate (const MediaSessionParams *msp); LinphoneStatus decline (LinphoneReason reason); LinphoneStatus decline (const LinphoneErrorInfo *ei); + void oglRender () const; LinphoneStatus pause (); LinphoneStatus redirect (const std::string &redirectUri); LinphoneStatus resume (); diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index f47fb3a40..b512e9ec1 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -54,6 +54,7 @@ public: void updating (bool isUpdate) override; void enableSymmetricRtp (bool value); + void oglRender () const; void sendVfu (); void clearIceCheckList (IceCheckList *cl); diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index f37983a33..2a4c85ab5 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -457,6 +458,13 @@ void MediaSessionPrivate::enableSymmetricRtp (bool value) { } } +void MediaSessionPrivate::oglRender () const { +#ifdef VIDEO_ENABLED + if (videoStream && videoStream->output && (ms_filter_get_id(videoStream->output) == MS_OGL_ID)) + ms_filter_call_method(videoStream->output, MS_OGL_RENDER, nullptr); +#endif +} + void MediaSessionPrivate::sendVfu () { #ifdef VIDEO_ENABLED if (videoStream) diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index 2ef160ab5..ef3ca87c2 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -32,6 +32,7 @@ class IceAgent; class MediaSessionPrivate; class LINPHONE_PUBLIC MediaSession : public CallSession { + friend class Call; friend class CallPrivate; friend class IceAgent; From 1358569f85b1e0e92f4aeab972d1c31bb25fd943 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 28 Nov 2017 14:55:17 +0100 Subject: [PATCH 0900/2215] fix how to get Message-ID --- src/chat/modifier/cpim-chat-message-modifier.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index e0ac09768..7d866b4a3 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -133,7 +133,7 @@ ChatMessageModifier::Result CpimChatMessageModifier::decode (const shared_ptrgetValue()); else if (header->getName() == "To") cpimToAddress = Address(header->getValue()); - else if (header->getName() == "Message-Id") + else if (header->getName() == "Message-ID") message->setImdnMessageId(header->getValue()); } } From a21111ca5a5623c399a3bd9c0a522ad28478aab4 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 28 Nov 2017 14:55:59 +0100 Subject: [PATCH 0901/2215] Fetch messages for Message-ID for IMDN --- src/chat/chat-room/chat-room-p.h | 2 +- src/chat/chat-room/chat-room.cpp | 6 +++--- src/core/core.h | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/chat/chat-room/chat-room-p.h b/src/chat/chat-room/chat-room-p.h index e3d5d05b7..36f64e1e8 100644 --- a/src/chat/chat-room/chat-room-p.h +++ b/src/chat/chat-room/chat-room-p.h @@ -50,7 +50,7 @@ public: void sendIsComposingNotification (); int createChatMessageFromDb (int argc, char **argv, char **colName); - std::list> findMessages (const std::string &messageId); + std::list> findMessages (const std::string &messageId) const; virtual LinphoneReason messageReceived (SalOp *op, const SalMessage *msg); void realtimeTextReceived (uint32_t character, LinphoneCall *call); diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 3578537a6..0bdd1e459 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -153,9 +153,9 @@ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colN return 0; } -list > ChatRoomPrivate::findMessages (const string &messageId) { - // TODO: history. - return list>(); +list > ChatRoomPrivate::findMessages (const string &messageId) const { + L_Q(); + return q->getCore()->getPrivate()->mainDb->findChatMessages(q->getChatRoomId(), messageId); } void ChatRoomPrivate::sendMessage (const shared_ptr &msg) { diff --git a/src/core/core.h b/src/core/core.h index 3291e27ca..9a4efbfe1 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -30,15 +30,14 @@ L_DECL_C_STRUCT(LinphoneCore); LINPHONE_BEGIN_NAMESPACE -class Address; class ChatRoom; -class ChatMessagePrivate; class ChatRoomId; class CorePrivate; class IdentityAddress; class LINPHONE_PUBLIC Core : public Object { friend class ChatRoom; + friend class ChatRoomPrivate; friend class ChatMessagePrivate; friend class ClientGroupChatRoom; friend class LocalConferenceEventHandlerPrivate; From db5b8dfcf5f2be1ed9ec9d5d405b439d1e707242 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 28 Nov 2017 15:25:44 +0100 Subject: [PATCH 0902/2215] fix(core): remove useless code --- src/core/core-p.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/core-p.h b/src/core/core-p.h index c5bb47458..da7569d7e 100644 --- a/src/core/core-p.h +++ b/src/core/core-p.h @@ -20,7 +20,6 @@ #ifndef _CORE_P_H_ #define _CORE_P_H_ -#include "chat/chat-room/chat-room-id.h" #include "core.h" #include "db/main-db.h" #include "object/object-p.h" From 9a5f620c51675ad6aafbf71db1208ff3d61cdbf4 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 28 Nov 2017 17:05:27 +0100 Subject: [PATCH 0903/2215] feat(MainDb): refactor main db event key --- src/CMakeLists.txt | 4 +- src/db/main-db-event-key.cpp | 36 ++-------- src/db/main-db-event-key.h | 19 +----- ...{main-db-event-key-p.h => main-db-key-p.h} | 12 ++-- src/db/main-db-key.cpp | 67 +++++++++++++++++++ src/db/main-db-key.h | 54 +++++++++++++++ src/db/main-db.cpp | 11 ++- 7 files changed, 142 insertions(+), 61 deletions(-) rename src/db/{main-db-event-key-p.h => main-db-key-p.h} (82%) create mode 100644 src/db/main-db-key.cpp create mode 100644 src/db/main-db-key.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 30575da1e..f9d78b8fc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -96,8 +96,9 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/platform-helpers/platform-helpers.h db/abstract/abstract-db-p.h db/abstract/abstract-db.h - db/main-db-event-key-p.h db/main-db-event-key.h + db/main-db-key-p.h + db/main-db-key.h db/main-db-p.h db/main-db.h db/session/db-session-p.h @@ -200,6 +201,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES core/platform-helpers/platform-helpers.cpp db/abstract/abstract-db.cpp db/main-db-event-key.cpp + db/main-db-key.cpp db/main-db.cpp db/session/db-session-provider.cpp db/session/db-session.cpp diff --git a/src/db/main-db-event-key.cpp b/src/db/main-db-event-key.cpp index fdc354be9..c9c350d28 100644 --- a/src/db/main-db-event-key.cpp +++ b/src/db/main-db-event-key.cpp @@ -18,7 +18,8 @@ */ #include "core/core-p.h" -#include "main-db-event-key-p.h" +#include "main-db-event-key.h" +#include "main-db-key-p.h" #include "main-db-p.h" // ============================================================================= @@ -29,21 +30,9 @@ LINPHONE_BEGIN_NAMESPACE // ----------------------------------------------------------------------------- -MainDbEventKey::MainDbEventKey () : ClonableObject(*new MainDbEventKeyPrivate) {} +MainDbEventKey::MainDbEventKey () : MainDbKey() {}; -MainDbEventKey::MainDbEventKey (const shared_ptr &core, long long storageId) : MainDbEventKey() { - L_D(); - d->core = core; - d->storageId = storageId; -} - -MainDbEventKey::MainDbEventKey (const MainDbEventKey &src) : MainDbEventKey() { - L_D(); - const MainDbEventKeyPrivate *dSrc = src.getPrivate(); - - d->core = dSrc->core; - d->storageId = dSrc->storageId; -} +MainDbEventKey::MainDbEventKey (const shared_ptr &core, long long storageId) : MainDbKey(core, storageId) {} MainDbEventKey::~MainDbEventKey () { L_D(); @@ -52,21 +41,4 @@ MainDbEventKey::~MainDbEventKey () { d->core.lock()->getPrivate()->mainDb->getPrivate()->storageIdToEvent.erase(d->storageId); } -MainDbEventKey &MainDbEventKey::operator= (const MainDbEventKey &src) { - L_D(); - - if (this != &src) { - const MainDbEventKeyPrivate *dSrc = src.getPrivate(); - d->core = dSrc->core; - d->storageId = dSrc->storageId; - } - - return *this; -} - -bool MainDbEventKey::isValid () const { - L_D(); - return !d->core.expired() && d->storageId >= 0; -} - LINPHONE_END_NAMESPACE diff --git a/src/db/main-db-event-key.h b/src/db/main-db-event-key.h index 5b9c90dbf..8eb7b990b 100644 --- a/src/db/main-db-event-key.h +++ b/src/db/main-db-event-key.h @@ -20,33 +20,20 @@ #ifndef _MAIN_DB_EVENT_KEY_H_ #define _MAIN_DB_EVENT_KEY_H_ -#include - -#include "object/clonable-object.h" +#include "main-db-key.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE -class Core; -class MainDbEventKeyPrivate; - -class MainDbEventKey : public ClonableObject { - friend class MainDb; - friend class MainDbPrivate; - +class MainDbEventKey : public MainDbKey { public: MainDbEventKey (); MainDbEventKey (const std::shared_ptr &core, long long storageId); - MainDbEventKey (const MainDbEventKey &src); ~MainDbEventKey (); - MainDbEventKey &operator= (const MainDbEventKey &src); - - bool isValid () const; - private: - L_DECLARE_PRIVATE(MainDbEventKey); + L_DECLARE_PRIVATE(MainDbKey); }; LINPHONE_END_NAMESPACE diff --git a/src/db/main-db-event-key-p.h b/src/db/main-db-key-p.h similarity index 82% rename from src/db/main-db-event-key-p.h rename to src/db/main-db-key-p.h index 62e4f6eaa..dea7d1180 100644 --- a/src/db/main-db-event-key-p.h +++ b/src/db/main-db-key-p.h @@ -1,5 +1,5 @@ /* - * main-db-event-key-p.h + * main-db-key-p.h * Copyright (C) 2010-2017 Belledonne Communications SARL * * This program is free software; you can redistribute it and/or @@ -17,17 +17,17 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef _MAIN_DB_EVENT_KEY_P_H_ -#define _MAIN_DB_EVENT_KEY_P_H_ +#ifndef _MAIN_DB_KEY_P_H_ +#define _MAIN_DB_KEY_P_H_ -#include "main-db-event-key.h" +#include "main-db-key.h" #include "object/clonable-object-p.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE -class MainDbEventKeyPrivate : public ClonableObjectPrivate { +class MainDbKeyPrivate : public ClonableObjectPrivate { public: std::weak_ptr core; long long storageId = -1; @@ -35,4 +35,4 @@ public: LINPHONE_END_NAMESPACE -#endif // ifndef _MAIN_DB_EVENT_KEY_P_H_ +#endif // ifndef _MAIN_DB_KEY_P_H_ diff --git a/src/db/main-db-key.cpp b/src/db/main-db-key.cpp new file mode 100644 index 000000000..2aef638e9 --- /dev/null +++ b/src/db/main-db-key.cpp @@ -0,0 +1,67 @@ +/* + * main-db-key.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "core/core-p.h" +#include "main-db-key-p.h" +#include "main-db-p.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +// ----------------------------------------------------------------------------- + +MainDbKey::MainDbKey () : ClonableObject(*new MainDbKeyPrivate) {} + +MainDbKey::MainDbKey (const shared_ptr &core, long long storageId) : MainDbKey() { + L_D(); + d->core = core; + d->storageId = storageId; +} + +MainDbKey::MainDbKey (const MainDbKey &src) : MainDbKey() { + L_D(); + const MainDbKeyPrivate *dSrc = src.getPrivate(); + + d->core = dSrc->core; + d->storageId = dSrc->storageId; +} + +MainDbKey::~MainDbKey () {} + +MainDbKey &MainDbKey::operator= (const MainDbKey &src) { + L_D(); + + if (this != &src) { + const MainDbKeyPrivate *dSrc = src.getPrivate(); + d->core = dSrc->core; + d->storageId = dSrc->storageId; + } + + return *this; +} + +bool MainDbKey::isValid () const { + L_D(); + return !d->core.expired() && d->storageId >= 0; +} + +LINPHONE_END_NAMESPACE diff --git a/src/db/main-db-key.h b/src/db/main-db-key.h new file mode 100644 index 000000000..2311a882c --- /dev/null +++ b/src/db/main-db-key.h @@ -0,0 +1,54 @@ +/* + * main-db-key.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _MAIN_DB_KEY_H_ +#define _MAIN_DB_KEY_H_ + +#include + +#include "object/clonable-object.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class Core; +class MainDbKeyPrivate; + +class MainDbKey : public ClonableObject { + friend class MainDb; + friend class MainDbPrivate; + +public: + MainDbKey (); + MainDbKey (const std::shared_ptr &core, long long storageId); + MainDbKey (const MainDbKey &src); + virtual ~MainDbKey () = 0; + + MainDbKey &operator= (const MainDbKey &src); + + bool isValid () const; + +private: + L_DECLARE_PRIVATE(MainDbKey); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _MAIN_DB_KEY_H_ diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index de08c61b3..02708c15f 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -37,7 +37,7 @@ #include "event-log/event-log-p.h" #include "event-log/events.h" #include "logger/logger.h" -#include "main-db-event-key-p.h" +#include "main-db-key-p.h" #include "main-db-p.h" // ============================================================================= @@ -676,7 +676,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } const EventLogPrivate *dEventLog = eventLog->getPrivate(); - MainDbEventKeyPrivate *dEventKey = dEventLog->dbKey.getPrivate(); + MainDbKeyPrivate *dEventKey = static_cast(dEventLog->dbKey).getPrivate(); const long long &eventId = dEventKey->storageId; soci::session *session = dbSession.getBackendSession(); @@ -1143,9 +1143,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), break; } - tr.commit(); - - soFarSoGood = storageId >= 0; + if ((soFarSoGood = storageId >= 0)) + tr.commit(); L_END_LOG_EXCEPTION @@ -1211,7 +1210,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return false; } - MainDbEventKeyPrivate *dEventKey = dEventLog->dbKey.getPrivate(); + MainDbKeyPrivate *dEventKey = static_cast(dEventLog->dbKey).getPrivate(); shared_ptr core = dEventKey->core.lock(); L_ASSERT(core); From afaa84610d4860a787088aaf70f352c70dcd1cff Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 28 Nov 2017 17:09:44 +0100 Subject: [PATCH 0904/2215] fix update of last notify id in chat room + recover it when creating chat room from db --- src/chat/chat-room/client-group-chat-room.cpp | 4 +++- src/chat/chat-room/client-group-chat-room.h | 3 ++- .../remote-conference-event-handler.cpp | 17 ++++++++++++----- .../handlers/remote-conference-event-handler.h | 1 + src/db/main-db.cpp | 7 ++----- 5 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 7371bb27c..1d8660966 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -102,7 +102,8 @@ ClientGroupChatRoom::ClientGroupChatRoom ( const IdentityAddress &peerAddress, shared_ptr &me, const string &subject, - list> &&participants + list> &&participants, + unsigned int lastNotifyId ) : ChatRoom(*new ClientGroupChatRoomPrivate, core, ChatRoomId(peerAddress, me->getAddress())), RemoteConference(core, me->getAddress(), nullptr) { L_D(); @@ -117,6 +118,7 @@ RemoteConference(core, me->getAddress(), nullptr) { getMe()->getPrivate()->setAdmin(me->isAdmin()); + dConference->eventHandler->setLastNotify(lastNotifyId); dConference->eventHandler->subscribe(getChatRoomId()); } diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 9e55d915f..042d7a59f 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -44,7 +44,8 @@ public: const IdentityAddress &peerAddress, std::shared_ptr &me, const std::string &subject, - std::list> &&participants + std::list> &&participants, + unsigned int lastNotifyId ); std::shared_ptr getCore () const; diff --git a/src/conference/handlers/remote-conference-event-handler.cpp b/src/conference/handlers/remote-conference-event-handler.cpp index c6be552f1..a2791164d 100644 --- a/src/conference/handlers/remote-conference-event-handler.cpp +++ b/src/conference/handlers/remote-conference-event-handler.cpp @@ -170,7 +170,6 @@ Object(*new RemoteConferenceEventHandlerPrivate) { L_D(); xercesc::XMLPlatformUtils::Initialize(); d->conf = remoteConference; - // TODO : d->lastNotify = lastNotify } RemoteConferenceEventHandler::~RemoteConferenceEventHandler () { @@ -182,13 +181,16 @@ RemoteConferenceEventHandler::~RemoteConferenceEventHandler () { void RemoteConferenceEventHandler::subscribe (const ChatRoomId &chatRoomId) { L_D(); d->chatRoomId = chatRoomId; - LinphoneAddress *lAddr = linphone_address_new(d->chatRoomId.getPeerAddress().asString().c_str()); + const string &peerAddress = d->chatRoomId.getPeerAddress().asString(); + LinphoneAddress *lAddr = linphone_address_new(peerAddress.c_str()); d->lev = linphone_core_create_subscribe(d->conf->getCore()->getCCore(), lAddr, "conference", 600); d->lev->op->set_from(d->chatRoomId.getLocalAddress().asString().c_str()); - linphone_event_add_custom_header(d->lev, "Last-Notify-Version", Utils::toString(d->lastNotify).c_str()); + const string &lastNotify = Utils::toString(d->lastNotify); + linphone_event_add_custom_header(d->lev, "Last-Notify-Version", lastNotify.c_str()); linphone_address_unref(lAddr); linphone_event_set_internal(d->lev, TRUE); linphone_event_set_user_data(d->lev, this); + lInfo() << "Subscribing to chat room: " << peerAddress << "with last notify: " << lastNotify; linphone_event_send_subscribe(d->lev, nullptr); } @@ -234,9 +236,14 @@ unsigned int RemoteConferenceEventHandler::getLastNotify () const { return d->lastNotify; }; -void RemoteConferenceEventHandler::resetLastNotify () { +void RemoteConferenceEventHandler::setLastNotify (unsigned int lastNotify) { L_D(); - d->lastNotify = 0; + d->lastNotify = lastNotify; } +void RemoteConferenceEventHandler::resetLastNotify () { + setLastNotify(0); +} + + LINPHONE_END_NAMESPACE diff --git a/src/conference/handlers/remote-conference-event-handler.h b/src/conference/handlers/remote-conference-event-handler.h index ecd443e19..2074d0539 100644 --- a/src/conference/handlers/remote-conference-event-handler.h +++ b/src/conference/handlers/remote-conference-event-handler.h @@ -43,6 +43,7 @@ public: const ChatRoomId &getChatRoomId () const; unsigned int getLastNotify () const; + void setLastNotify (unsigned int lastNotify); void resetLastNotify (); private: diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 02708c15f..d3f4f7802 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -700,7 +700,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_notified_event (event_id, notify_id)" " VALUES (:eventId, :notifyId)", soci::use(eventId), soci::use(lastNotifyId); - *session << "UPDATE chat_room SET last_notify_id = :lastNotifyId WHERE peer_sip_address_id = :chatRoomId", + *session << "UPDATE chat_room SET last_notify_id = :lastNotifyId WHERE id = :chatRoomId", soci::use(lastNotifyId), soci::use(curChatRoomId); if (chatRoomId) @@ -1650,9 +1650,6 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), string subject = row.get(6); unsigned int lastNotifyId = static_cast(row.get(7, 0)); - // TODO: Use me. - (void)lastNotifyId; - if (capabilities & static_cast(ChatRoom::Capabilities::Basic)) { chatRoom = core->getPrivate()->createBasicChatRoom( chatRoomId, @@ -1687,7 +1684,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), continue; } - chatRoom = make_shared(core, chatRoomId.getPeerAddress(), me, subject, move(participants)); + chatRoom = make_shared(core, chatRoomId.getPeerAddress(), me, subject, move(participants), lastNotifyId); } if (!chatRoom) From 447076eadcd364815cc105578676d5579b358aa0 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 28 Nov 2017 17:19:20 +0100 Subject: [PATCH 0905/2215] fix(MainDb): avoid event duplication --- src/db/main-db-p.h | 2 +- src/db/main-db.cpp | 33 +++++++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index af8fbab2d..85376da2f 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -36,7 +36,7 @@ class Content; class MainDbPrivate : public AbstractDbPrivate { public: - std::unordered_map> storageIdToEvent; + mutable std::unordered_map> storageIdToEvent; private: // --------------------------------------------------------------------------- diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index d3f4f7802..822b27a05 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -343,33 +343,52 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), time_t creationTime, const ChatRoomId &chatRoomId ) const { + L_Q(); + + shared_ptr eventLog; + switch (type) { case EventLog::Type::None: return nullptr; case EventLog::Type::ConferenceCreated: case EventLog::Type::ConferenceDestroyed: - return selectConferenceEvent(eventId, type, creationTime, chatRoomId); + eventLog = selectConferenceEvent(eventId, type, creationTime, chatRoomId); + break; case EventLog::Type::ConferenceCallStart: case EventLog::Type::ConferenceCallEnd: - return selectConferenceCallEvent(eventId, type, creationTime, chatRoomId); + eventLog = selectConferenceCallEvent(eventId, type, creationTime, chatRoomId); + break; case EventLog::Type::ConferenceChatMessage: - return selectConferenceChatMessageEvent(eventId, type, creationTime, chatRoomId); + eventLog = selectConferenceChatMessageEvent(eventId, type, creationTime, chatRoomId); + break; case EventLog::Type::ConferenceParticipantAdded: case EventLog::Type::ConferenceParticipantRemoved: case EventLog::Type::ConferenceParticipantSetAdmin: case EventLog::Type::ConferenceParticipantUnsetAdmin: - return selectConferenceParticipantEvent(eventId, type, creationTime, chatRoomId); + eventLog = selectConferenceParticipantEvent(eventId, type, creationTime, chatRoomId); + break; case EventLog::Type::ConferenceParticipantDeviceAdded: case EventLog::Type::ConferenceParticipantDeviceRemoved: - return selectConferenceParticipantDeviceEvent(eventId, type, creationTime, chatRoomId); + eventLog = selectConferenceParticipantDeviceEvent(eventId, type, creationTime, chatRoomId); + break; case EventLog::Type::ConferenceSubjectChanged: - return selectConferenceSubjectEvent(eventId, type, creationTime, chatRoomId); + eventLog = selectConferenceSubjectEvent(eventId, type, creationTime, chatRoomId); + break; + } + + if (eventLog) { + EventLogPrivate *dEventLog = eventLog->getPrivate(); + L_ASSERT(!dEventLog->dbKey.isValid()); + dEventLog->dbKey = MainDbEventKey(q->getCore(), eventId); + storageIdToEvent[eventId] = eventLog; + L_ASSERT(dEventLog->dbKey.isValid()); + return eventLog; } return nullptr; @@ -1149,8 +1168,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), L_END_LOG_EXCEPTION if (soFarSoGood) { + L_ASSERT(!dEventLog->dbKey.isValid()); dEventLog->dbKey = MainDbEventKey(getCore(), storageId); d->storageIdToEvent[storageId] = eventLog; + L_ASSERT(dEventLog->dbKey.isValid()); } return soFarSoGood; From 98ef82ed39602b50d62d00512f4d16c3abfddf88 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 29 Nov 2017 10:10:01 +0100 Subject: [PATCH 0906/2215] Updated migration.sh for Java wrapper --- wrappers/java/migration.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/wrappers/java/migration.sh b/wrappers/java/migration.sh index afc602ef7..aad4eca2c 100644 --- a/wrappers/java/migration.sh +++ b/wrappers/java/migration.sh @@ -302,6 +302,7 @@ s/new XmlRpcSessionImpl(LinphoneManager.getLcIfManagerNotDestroyedOrNull(), /Lin # ChatMessageListener onFileTransferSend now returns the Buffer instead of having it as part of his arguments # Core.startEchoCancellerCalibration no longer takes a parameter # XmlRpcSession.createRequest takes first the return arg type and then the name of the method, until now it was the other way around +# ProxyConfig.normalizePhoneNumber returns null if it fails instead of the value given as parameter in the previous version ! # # Factory #Factory.createAccountCreator() => Core.createAccountCreator() From 8bfffceab2394fcd3a49b11ab5575abd0b2bdfa6 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 29 Nov 2017 11:03:30 +0100 Subject: [PATCH 0907/2215] Fixed AndroidPlatformHelpers for devices using old version of Android --- wrappers/java/classes/tools/AndroidPlatformHelper.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/wrappers/java/classes/tools/AndroidPlatformHelper.java b/wrappers/java/classes/tools/AndroidPlatformHelper.java index 0da810886..b22d8fbf0 100644 --- a/wrappers/java/classes/tools/AndroidPlatformHelper.java +++ b/wrappers/java/classes/tools/AndroidPlatformHelper.java @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. package org.linphone.core.tools; import org.linphone.mediastream.Log; +import org.linphone.mediastream.Version; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.MulticastLock; @@ -50,7 +51,7 @@ public class AndroidPlatformHelper { public AndroidPlatformHelper(Object ctx_obj) { mContext = (Context) ctx_obj; - WifiManager wifiMgr = mContext.getSystemService(WifiManager.class); + WifiManager wifiMgr = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mConnectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); @@ -67,7 +68,7 @@ public class AndroidPlatformHelper { } public String[] getDnsServers() { - if (mConnectivityManager == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.M) + if (mConnectivityManager == null || Build.VERSION.SDK_BuildINT < Version.API23_MARSHMALLOW_60) return null; if (mConnectivityManager.getActiveNetwork() == null From bed2dbf6b07843246587c39b0e2e880ba8640da6 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 29 Nov 2017 11:32:00 +0100 Subject: [PATCH 0908/2215] Fixed typo --- wrappers/java/classes/tools/AndroidPlatformHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrappers/java/classes/tools/AndroidPlatformHelper.java b/wrappers/java/classes/tools/AndroidPlatformHelper.java index b22d8fbf0..9b5d2f756 100644 --- a/wrappers/java/classes/tools/AndroidPlatformHelper.java +++ b/wrappers/java/classes/tools/AndroidPlatformHelper.java @@ -68,7 +68,7 @@ public class AndroidPlatformHelper { } public String[] getDnsServers() { - if (mConnectivityManager == null || Build.VERSION.SDK_BuildINT < Version.API23_MARSHMALLOW_60) + if (mConnectivityManager == null || Build.VERSION.SDK_INT < Version.API23_MARSHMALLOW_60) return null; if (mConnectivityManager.getActiveNetwork() == null From 65ab7cdfa34897c79ba283a53490232548d2fb3c Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 29 Nov 2017 11:33:43 +0100 Subject: [PATCH 0909/2215] feat(chat-message): supports cache partially --- src/CMakeLists.txt | 2 + src/chat/chat-message/chat-message-p.h | 8 ++- src/chat/chat-message/chat-message.h | 1 + src/core/core.h | 3 +- src/db/main-db-chat-message-key.cpp | 44 ++++++++++++ src/db/main-db-chat-message-key.h | 41 +++++++++++ src/db/main-db-p.h | 8 ++- src/db/main-db.cpp | 97 ++++++++++++++++++-------- src/db/main-db.h | 1 + 9 files changed, 172 insertions(+), 33 deletions(-) create mode 100644 src/db/main-db-chat-message-key.cpp create mode 100644 src/db/main-db-chat-message-key.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f9d78b8fc..bf085340b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -96,6 +96,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/platform-helpers/platform-helpers.h db/abstract/abstract-db-p.h db/abstract/abstract-db.h + db/main-db-chat-message-key.h db/main-db-event-key.h db/main-db-key-p.h db/main-db-key.h @@ -200,6 +201,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES core/paths/paths.cpp core/platform-helpers/platform-helpers.cpp db/abstract/abstract-db.cpp + db/main-db-chat-message-key.cpp db/main-db-event-key.cpp db/main-db-key.cpp db/main-db.cpp diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index 784fd062b..6d3f2761f 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -30,6 +30,7 @@ #include "content/content.h" #include "content/file-content.h" #include "content/file-transfer-content.h" +#include "db/main-db-chat-message-key.h" #include "event-log/conference/conference-chat-message-event.h" #include "object/object-p.h" #include "sal/sal.h" @@ -148,11 +149,16 @@ private: ContentType cContentType; std::string cText; + std::weak_ptr chatEvent; + // TODO: Remove my comment. VARIABLES OK. // Do not expose. +public: + mutable MainDbChatMessageKey dbKey; + +private: std::weak_ptr chatRoom; - std::weak_ptr chatEvent; ChatRoomId chatRoomId; IdentityAddress fromAddress; IdentityAddress toAddress; diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index 7fdf0e61d..a582dcee8 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -45,6 +45,7 @@ class LINPHONE_PUBLIC ChatMessage : public Object, public CoreAccessor { friend class ChatRoomPrivate; friend class CpimChatMessageModifier; friend class FileTransferChatMessageModifier; + friend class MainDb; friend class MainDbPrivate; friend class RealTimeTextChatRoomPrivate; friend class ServerGroupChatRoomPrivate; diff --git a/src/core/core.h b/src/core/core.h index 9a4efbfe1..9aeab7697 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -36,12 +36,13 @@ class CorePrivate; class IdentityAddress; class LINPHONE_PUBLIC Core : public Object { + friend class ChatMessagePrivate; friend class ChatRoom; friend class ChatRoomPrivate; - friend class ChatMessagePrivate; friend class ClientGroupChatRoom; friend class LocalConferenceEventHandlerPrivate; friend class MainDb; + friend class MainDbChatMessageKey; friend class MainDbEventKey; friend class ServerGroupChatRoomPrivate; diff --git a/src/db/main-db-chat-message-key.cpp b/src/db/main-db-chat-message-key.cpp new file mode 100644 index 000000000..1d327e057 --- /dev/null +++ b/src/db/main-db-chat-message-key.cpp @@ -0,0 +1,44 @@ +/* + * main-db-chat-message-key.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "core/core-p.h" +#include "main-db-chat-message-key.h" +#include "main-db-key-p.h" +#include "main-db-p.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +// ----------------------------------------------------------------------------- + +MainDbChatMessageKey::MainDbChatMessageKey () : MainDbKey() {}; + +MainDbChatMessageKey::MainDbChatMessageKey (const shared_ptr &core, long long storageId) : MainDbKey(core, storageId) {} + +MainDbChatMessageKey::~MainDbChatMessageKey () { + L_D(); + + if (isValid()) + d->core.lock()->getPrivate()->mainDb->getPrivate()->storageIdToChatMessage.erase(d->storageId); +} + +LINPHONE_END_NAMESPACE diff --git a/src/db/main-db-chat-message-key.h b/src/db/main-db-chat-message-key.h new file mode 100644 index 000000000..2a952684f --- /dev/null +++ b/src/db/main-db-chat-message-key.h @@ -0,0 +1,41 @@ +/* + * main-db-chat-message-key.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _MAIN_DB_CHAT_MESSAGE_KEY_H_ +#define _MAIN_DB_CHAT_MESSAGE_KEY_H_ + +#include "main-db-key.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class MainDbChatMessageKey : public MainDbKey { +public: + MainDbChatMessageKey (); + MainDbChatMessageKey (const std::shared_ptr &core, long long storageId); + ~MainDbChatMessageKey (); + +private: + L_DECLARE_PRIVATE(MainDbKey); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _MAIN_DB_CHAT_MESSAGE_KEY_H_ diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 85376da2f..e871661d2 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -37,6 +37,7 @@ class Content; class MainDbPrivate : public AbstractDbPrivate { public: mutable std::unordered_map> storageIdToEvent; + mutable std::unordered_map> storageIdToChatMessage; private: // --------------------------------------------------------------------------- @@ -136,7 +137,12 @@ private: // Cache API. // --------------------------------------------------------------------------- - std::shared_ptr getEventFromCache (long long eventId) const; + void cache (const std::shared_ptr &eventLog, long long storageId) const; + void cache (const std::shared_ptr &chatMessage, long long storageId) const; + + std::shared_ptr getEventFromCache (long long storageId) const; + std::shared_ptr getChatMessageFromCache (long long storageId) const; + void invalidConferenceEventsFromQuery (const std::string &query, long long chatRoomId); L_DECLARE_PUBLIC(MainDb); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 822b27a05..188b3f693 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -343,8 +343,6 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), time_t creationTime, const ChatRoomId &chatRoomId ) const { - L_Q(); - shared_ptr eventLog; switch (type) { @@ -382,16 +380,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), break; } - if (eventLog) { - EventLogPrivate *dEventLog = eventLog->getPrivate(); - L_ASSERT(!dEventLog->dbKey.isValid()); - dEventLog->dbKey = MainDbEventKey(q->getCore(), eventId); - storageIdToEvent[eventId] = eventLog; - L_ASSERT(dEventLog->dbKey.isValid()); - return eventLog; - } + if (eventLog) + cache(eventLog, eventId); - return nullptr; + return eventLog; } shared_ptr MainDbPrivate::selectConferenceEvent ( @@ -426,15 +418,14 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), L_Q(); shared_ptr core = q->getCore(); - shared_ptr chatRoom = core->findChatRoom(chatRoomId); if (!chatRoom) return nullptr; - // TODO: Use cache, do not fetch the same message twice. - // 1 - Fetch chat message. - shared_ptr chatMessage; + shared_ptr chatMessage = getChatMessageFromCache(eventId); + if (chatMessage) + goto end; { string fromSipAddress; string toSipAddress; @@ -509,7 +500,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } } - // TODO: Use cache. + end: return make_shared( creationTime, chatMessage @@ -800,8 +791,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), // ----------------------------------------------------------------------------- - shared_ptr MainDbPrivate::getEventFromCache (long long eventId) const { - auto it = storageIdToEvent.find(eventId); + shared_ptr MainDbPrivate::getEventFromCache (long long storageId) const { + auto it = storageIdToEvent.find(storageId); if (it == storageIdToEvent.cend()) return nullptr; @@ -811,6 +802,37 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return eventLog; } + shared_ptr MainDbPrivate::getChatMessageFromCache (long long storageId) const { + auto it = storageIdToChatMessage.find(storageId); + if (it == storageIdToChatMessage.cend()) + return nullptr; + + shared_ptr chatMessage = it->second.lock(); + // Must exist. If not, implementation bug. + L_ASSERT(chatMessage); + return chatMessage; + } + + void MainDbPrivate::cache (const shared_ptr &eventLog, long long storageId) const { + L_Q(); + + EventLogPrivate *dEventLog = eventLog->getPrivate(); + L_ASSERT(!dEventLog->dbKey.isValid()); + dEventLog->dbKey = MainDbEventKey(q->getCore(), storageId); + storageIdToEvent[storageId] = eventLog; + L_ASSERT(dEventLog->dbKey.isValid()); + } + + void MainDbPrivate::cache (const shared_ptr &chatMessage, long long storageId) const { + L_Q(); + + ChatMessagePrivate *dChatMessage = chatMessage->getPrivate(); + L_ASSERT(!dChatMessage->dbKey.isValid()); + dChatMessage->dbKey = MainDbChatMessageKey(q->getCore(), storageId); + storageIdToChatMessage[storageId] = chatMessage; + L_ASSERT(dChatMessage->dbKey.isValid()); + } + void MainDbPrivate::invalidConferenceEventsFromQuery (const string &query, long long chatRoomId) { soci::session *session = dbSession.getBackendSession(); soci::rowset rows = (session->prepare << query, soci::use(chatRoomId)); @@ -1127,7 +1149,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::transaction tr(*d->dbSession.getBackendSession()); - switch (eventLog->getType()) { + EventLog::Type type = eventLog->getType(); + switch (type) { case EventLog::Type::None: return false; @@ -1162,18 +1185,18 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), break; } - if ((soFarSoGood = storageId >= 0)) + if (storageId >= 0) { tr.commit(); + d->cache(eventLog, storageId); + + if (type == EventLog::Type::ConferenceChatMessage) + d->cache(static_pointer_cast(eventLog)->getChatMessage(), storageId); + + soFarSoGood = true; + } L_END_LOG_EXCEPTION - if (soFarSoGood) { - L_ASSERT(!dEventLog->dbKey.isValid()); - dEventLog->dbKey = MainDbEventKey(getCore(), storageId); - d->storageIdToEvent[storageId] = eventLog; - L_ASSERT(dEventLog->dbKey.isValid()); - } - return soFarSoGood; } @@ -1246,11 +1269,18 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = mainDb.getPrivate()->dbSession.getBackendSession(); *session << "DELETE FROM event WHERE id = :id", soci::use(dEventKey->storageId); - L_END_LOG_EXCEPTION - dEventLog->dbKey = MainDbEventKey(); + if (eventLog->getType() == EventLog::Type::ConferenceChatMessage) + static_pointer_cast( + eventLog + )->getChatMessage()->getPrivate()->dbKey = MainDbChatMessageKey(); + return true; + + L_END_LOG_EXCEPTION + + return false; } int MainDb::getEventsCount (FilterMask mask) const { @@ -1705,7 +1735,14 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), continue; } - chatRoom = make_shared(core, chatRoomId.getPeerAddress(), me, subject, move(participants), lastNotifyId); + chatRoom = make_shared( + core, + chatRoomId.getPeerAddress(), + me, + subject, + move(participants), + lastNotifyId + ); } if (!chatRoom) diff --git a/src/db/main-db.h b/src/db/main-db.h index 2cd5de58f..7c371444e 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -37,6 +37,7 @@ class EventLog; class MainDbPrivate; class MainDb : public AbstractDb, public CoreAccessor { + friend class MainDbChatMessageKey; friend class MainDbEventKey; public: From 2d78e6820a01e298b2e0fa2d516bdab6714cf6ba Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 29 Nov 2017 11:38:32 +0100 Subject: [PATCH 0910/2215] Fix build. --- src/chat/cpim/parser/cpim-parser.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/chat/cpim/parser/cpim-parser.h b/src/chat/cpim/parser/cpim-parser.h index 841b7e18c..c5e0ffb4a 100644 --- a/src/chat/cpim/parser/cpim-parser.h +++ b/src/chat/cpim/parser/cpim-parser.h @@ -70,6 +70,9 @@ namespace Cpim { template<> bool Parser::coreHeaderIsValid(const std::string &headerValue) const; + template<> + bool Parser::coreHeaderIsValid(const std::string &headerValue) const; + template<> bool Parser::coreHeaderIsValid(const std::string &headerValue) const; From 773b60367f7547a179855d0bb584f4ffa4f1eca2 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 29 Nov 2017 11:54:16 +0100 Subject: [PATCH 0911/2215] fix(MainDb): cache chat messageon select --- src/db/main-db.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 188b3f693..ab156bf1f 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -500,6 +500,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } } + cache(chatMessage, eventId); + end: return make_shared( creationTime, From c172fec54db1924b0a408b57d62cad0a77910b75 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 29 Nov 2017 13:06:17 +0100 Subject: [PATCH 0912/2215] Fixed compil --- src/db/main-db.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index ab156bf1f..95e23bb1c 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1145,7 +1145,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } bool soFarSoGood = false; - long long storageId; + long long storageId = 0; L_BEGIN_LOG_EXCEPTION From b23a2af68453ed4ba5cc4c84d94ddddfb5a5d20a Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 29 Nov 2017 13:31:18 +0100 Subject: [PATCH 0913/2215] always update device event when subscribe received --- src/conference/handlers/local-conference-event-handler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conference/handlers/local-conference-event-handler.cpp b/src/conference/handlers/local-conference-event-handler.cpp index 927245f9d..bceacae28 100644 --- a/src/conference/handlers/local-conference-event-handler.cpp +++ b/src/conference/handlers/local-conference-event-handler.cpp @@ -380,9 +380,9 @@ void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) { if (linphone_event_get_subscription_state(lev) == LinphoneSubscriptionActive) { unsigned int lastNotify = static_cast(Utils::stoi(linphone_event_get_custom_header(lev, "Last-Notify-Version"))); + device->setConferenceSubscribeEvent(lev); if (lastNotify == 0) { lInfo() << "Sending initial notify of conference:" << d->conf->getConferenceAddress().asString() << " to: " << device->getAddress().asString(); - device->setConferenceSubscribeEvent(lev); d->notifyFullState(d->createNotifyFullState(), device); } else if (lastNotify < d->lastNotify) { lInfo() << "Sending all missed notify for conference:" << d->conf->getConferenceAddress().asString() << From a0df884b895b5b43b04229ec951eb1047c5ee349 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 29 Nov 2017 13:44:12 +0100 Subject: [PATCH 0914/2215] Fix Android Context not being set in mediastreamer2 --- wrappers/java/classes/tools/AndroidPlatformHelper.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wrappers/java/classes/tools/AndroidPlatformHelper.java b/wrappers/java/classes/tools/AndroidPlatformHelper.java index 9b5d2f756..a202dbc77 100644 --- a/wrappers/java/classes/tools/AndroidPlatformHelper.java +++ b/wrappers/java/classes/tools/AndroidPlatformHelper.java @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. package org.linphone.core.tools; import org.linphone.mediastream.Log; +import org.linphone.mediastream.MediastreamerAndroidContext; import org.linphone.mediastream.Version; import android.net.wifi.WifiManager; @@ -51,6 +52,8 @@ public class AndroidPlatformHelper { public AndroidPlatformHelper(Object ctx_obj) { mContext = (Context) ctx_obj; + MediastreamerAndroidContext.setContext(mContext); + WifiManager wifiMgr = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mConnectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); From e1d909d1c5e9d380bf0c762d5f8ea1294aa8becb Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 29 Nov 2017 14:12:19 +0100 Subject: [PATCH 0915/2215] feat(MainDb): provide a way to fetch messages from db key --- src/chat/chat-message/chat-message-p.h | 2 - src/chat/chat-message/chat-message.cpp | 12 +++--- src/db/main-db.cpp | 56 +++++++++++++++++++++++++- src/db/main-db.h | 3 ++ 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index 6d3f2761f..aecdf91d3 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -149,8 +149,6 @@ private: ContentType cContentType; std::string cText; - std::weak_ptr chatEvent; - // TODO: Remove my comment. VARIABLES OK. // Do not expose. diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 2ceb5f27f..aaae7d964 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -586,9 +586,10 @@ void ChatMessagePrivate::store() { return; } - shared_ptr eventLog = chatEvent.lock(); - if (eventLog) { - q->getChatRoom()->getCore()->getPrivate()->mainDb->updateEvent(eventLog); + unique_ptr &mainDb = q->getChatRoom()->getCore()->getPrivate()->mainDb; + if (dbKey.isValid()) { + shared_ptr eventLog = mainDb->getEventFromKey(dbKey); + mainDb->updateEvent(eventLog); if (direction == ChatMessage::Direction::Incoming) { if (!hasFileTransferContent()) { @@ -602,9 +603,8 @@ void ChatMessagePrivate::store() { } } } else { - eventLog = make_shared(time, q->getSharedFromThis()); - chatEvent = eventLog; - q->getChatRoom()->getCore()->getPrivate()->mainDb->addEvent(eventLog); + shared_ptr eventLog = make_shared(time, q->getSharedFromThis()); + mainDb->addEvent(eventLog); if (direction == ChatMessage::Direction::Incoming) { if (hasFileTransferContent()) { diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 95e23bb1c..f14ddc1ca 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1311,6 +1311,60 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return count; } + shared_ptr MainDb::getEventFromKey (const MainDbKey &dbKey) { + shared_ptr event; + + if (!dbKey.isValid()) { + lWarning() << "Unable to get event from invalid key."; + return event; + } + + unique_ptr &q = dbKey.getPrivate()->core.lock()->getPrivate()->mainDb; + MainDbPrivate *d = q->getPrivate(); + + if (!q->isConnected()) { + lWarning() << "Unable to get event from key. Not connected."; + return event; + } + + const long long &storageId = dbKey.getPrivate()->storageId; + event = d->getEventFromCache(storageId); + if (event) + return event; + + // TODO: Improve. Deal with all events in the future. + static string query = "SELECT peer_sip_address.value, local_sip_address.value, type, event.creation_time" + " FROM event, conference_event, chat_room, sip_address AS peer_sip_address, sip_address as local_sip_address" + " WHERE event.id = :eventId" + " AND conference_event.event_id = event.id" + " AND conference_event.chat_room_id = chat_room.id" + " AND chat_room.peer_sip_address_id = peer_sip_address.id" + " AND chat_room.local_sip_address_id = local_sip_address.id"; + + L_BEGIN_LOG_EXCEPTION + + soci::session *session = d->dbSession.getBackendSession(); + soci::transaction tr(*session); + + string peerSipAddress; + string localSipAddress; + int type; + tm creationTime; + *session << query, soci::into(peerSipAddress), soci::into(localSipAddress), soci::into(type), + soci::into(creationTime), soci::use(storageId); + + event = d->selectGenericConferenceEvent( + storageId, + static_cast(type), + Utils::getTmAsTimeT(creationTime), + ChatRoomId(IdentityAddress(peerSipAddress), IdentityAddress(localSipAddress)) + ); + + L_END_LOG_EXCEPTION + + return event; + } + list> MainDb::getConferenceNotifiedEvents ( const ChatRoomId &chatRoomId, unsigned int lastNotifyId @@ -1449,7 +1503,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), if (getUnreadChatMessagesCount(chatRoomId) == 0) return; - string query = "UPDATE FROM conference_chat_message_event" + string query = "UPDATE conference_chat_message_event" " SET state = " + Utils::toString(static_cast(ChatMessage::State::Displayed)) + " "; query += "WHERE"; if (chatRoomId.isValid()) diff --git a/src/db/main-db.h b/src/db/main-db.h index 7c371444e..ac7fc3cb5 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -34,6 +34,7 @@ class ChatMessage; class ChatRoom; class Core; class EventLog; +class MainDbKey; class MainDbPrivate; class MainDb : public AbstractDb, public CoreAccessor { @@ -61,6 +62,8 @@ public: static bool deleteEvent (const std::shared_ptr &eventLog); int getEventsCount (FilterMask mask = NoFilter) const; + static std::shared_ptr getEventFromKey (const MainDbKey &dbKey); + // --------------------------------------------------------------------------- // Conference notified events. // --------------------------------------------------------------------------- From d7bc4b66ac414e6b6b5c0cd30bedcbcde4a9c05b Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 29 Nov 2017 14:33:34 +0100 Subject: [PATCH 0916/2215] do not notify empty subject --- src/conference/handlers/remote-conference-event-handler.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/conference/handlers/remote-conference-event-handler.cpp b/src/conference/handlers/remote-conference-event-handler.cpp index a2791164d..4f0904dd6 100644 --- a/src/conference/handlers/remote-conference-event-handler.cpp +++ b/src/conference/handlers/remote-conference-event-handler.cpp @@ -55,7 +55,8 @@ void RemoteConferenceEventHandlerPrivate::simpleNotifyReceived (const string &xm if (entityAddress == chatRoomId.getPeerAddress()) { if ( confInfo->getConferenceDescription().present() && - confInfo->getConferenceDescription().get().getSubject().present() + confInfo->getConferenceDescription().get().getSubject().present() && + !confInfo->getConferenceDescription().get().getSubject().get().empty() ) confListener->onSubjectChanged( make_shared( From 6b02c99f77009b61df5777245ab24f7337287bc6 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 29 Nov 2017 15:18:47 +0100 Subject: [PATCH 0917/2215] fix(ChatMessage): remove useless code --- src/c-wrapper/api/c-chat-message.cpp | 8 -------- src/chat/chat-message/chat-message-p.h | 4 ---- src/chat/chat-message/chat-message.cpp | 8 -------- src/chat/chat-room/chat-room.h | 2 +- 4 files changed, 1 insertion(+), 21 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index d53df4dbe..7826ced15 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -138,10 +138,6 @@ void linphone_chat_message_set_outgoing(LinphoneChatMessage *msg) { L_GET_PRIVATE_FROM_C_OBJECT(msg)->setDirection(LinphonePrivate::ChatMessage::Direction::Outgoing); } -unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage *msg) { - return L_GET_PRIVATE_FROM_C_OBJECT(msg)->getStorageId(); -} - LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage *msg) { return ((LinphoneChatMessageState)L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getState()); } @@ -158,10 +154,6 @@ void linphone_chat_message_set_message_id(LinphoneChatMessage *msg, char *id) { L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setImdnMessageId(L_C_TO_STRING(id)); } -void linphone_chat_message_set_storage_id(LinphoneChatMessage *msg, unsigned int id) { - L_GET_PRIVATE_FROM_C_OBJECT(msg)->setStorageId(id); -} - bool_t linphone_chat_message_is_read(LinphoneChatMessage *msg) { return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->isRead(); } diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index aecdf91d3..f57f79cfb 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -73,9 +73,6 @@ public: this->toAddress = toAddress; } - unsigned int getStorageId() const; - void setStorageId(unsigned int id); - belle_http_request_t *getHttpRequest() const; void setHttpRequest(belle_http_request_t *request); @@ -127,7 +124,6 @@ public: private: // TODO: Clean attributes. - unsigned int storageId = 0; time_t time = ::ms_time(0); // TODO: Change me in all files. std::string id; std::string rttMessage; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index aaae7d964..bab4b5db6 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -100,14 +100,6 @@ void ChatMessagePrivate::setState (ChatMessage::State s, bool force) { store(); } -unsigned int ChatMessagePrivate::getStorageId () const { - return storageId; -} - -void ChatMessagePrivate::setStorageId (unsigned int id) { - storageId = id; -} - belle_http_request_t *ChatMessagePrivate::getHttpRequest () const { return fileTransferChatMessageModifier.getHttpRequest(); } diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index 4e6bc3d9a..a4d6c126a 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -58,7 +58,7 @@ public: virtual CapabilitiesMask getCapabilities () const = 0; - std::shared_ptr getLastMessageInHistory() const; + std::shared_ptr getLastMessageInHistory () const; // TODO: Remove useless functions. void compose (); From a23c0e4f202b043a08db2bf232863c195f5c94d2 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 29 Nov 2017 15:28:49 +0100 Subject: [PATCH 0918/2215] Fixed issue with refs for video surfaces in JNI layer --- wrappers/java/genwrapper.py | 9 +++++- wrappers/java/jni.mustache | 61 ++++++++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index eba6ab482..c68127c11 100755 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -358,7 +358,11 @@ class JavaTranslator(object): return methodDict def translate_jni_method(self, className, _method, static=False): - methodDict = {} + jni_blacklist = ['linphone_call_set_native_video_window_id',\ + 'linphone_core_set_native_preview_window_id',\ + 'linphone_core_set_native_video_window_id'] + + methodDict = {'notEmpty': True} methodDict['classCName'] = 'Linphone' + className.to_camel_case() methodDict['className'] = className.to_camel_case() methodDict['classImplName'] = className.to_camel_case() + 'Impl' @@ -378,6 +382,9 @@ class JavaTranslator(object): methodDict['isRealObjectArray'] = False methodDict['isStringObjectArray'] = False methodDict['c_type_return'] = self.translate_as_c_base_type(_method.returnType) + + if methodDict['c_name'] in jni_blacklist: + return {'notEmpty': False} if methodDict['hasListReturn']: if type(_method.returnType) is AbsApi.BaseType and _method.returnType.name == 'string_array': diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index 8513e753c..a6e855736 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -419,6 +419,7 @@ jobject Java_{{jni_package}}FactoryImpl_createCore(JNIEnv *env, jobject thiz, jo ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {{#methods}} +{{#notEmpty}} {{return}} {{name}}({{params}}) { {{#notStatic}}{{classCName}} *cptr = ({{classCName}}*)ptr;{{/notStatic}}{{#strings}} const char* c_{{string}} = GetStringUTFChars(env, {{string}}); @@ -482,9 +483,67 @@ jobject Java_{{jni_package}}FactoryImpl_createCore(JNIEnv *env, jobject thiz, jo env->ReleaseByteArrayElements({{bytesargname}}, (jbyte*)c_{{bytesargname}}, JNI_ABORT); {{/bytes}}{{#hasReturn}}return jni_result;{{/hasReturn}}{{#hasListReturn}}return jni_list_result;{{/hasListReturn}} } - +{{/notEmpty}} {{/methods}} +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Manually wrapped +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Java_org_linphone_core_CallImpl_setNativeVideoWindowId(JNIEnv *env, jobject thiz, jlong ptr, jobject id) { + LinphoneCall *cptr = (LinphoneCall*)ptr; + jobject oldWindow = (jobject) linphone_call_get_native_video_window_id(cptr); + if (oldWindow == id) { + ms_warning("Java_org_linphone_core_CallImpl_setNativeVideoWindowId(): new id (%p) is the same as the current one, skipping...", id); + return; + } + if (id != NULL) { + id = env->NewGlobalRef(id); + ms_message("Java_org_linphone_core_CallImpl_setNativeVideoWindowId(): NewGlobalRef(%p)", id); + } else ms_message("Java_org_linphone_core_CallImpl_setNativeVideoWindowId(): setting to NULL"); + linphone_call_set_native_video_window_id(cptr, (void *)id); + if (oldWindow != NULL) { + ms_message("Java_org_linphone_core_CallImpl_setNativeVideoWindowId(): DeleteGlobalRef(%p)", oldWindow); + env->DeleteGlobalRef(oldWindow); + } +} + +void Java_org_linphone_core_CoreImpl_setNativePreviewWindowId(JNIEnv *env, jobject thiz, jlong ptr, jobject id) { + LinphoneCore *cptr = (LinphoneCore*)ptr; + jobject oldWindow = (jobject) linphone_core_get_native_video_window_id(cptr); + if (oldWindow == id) { + ms_warning("Java_org_linphone_core_CoreImpl_setNativePreviewWindowId(): new id (%p) is the same as the current one, skipping...", id); + return; + } + if (id != NULL) { + id = env->NewGlobalRef(id); + ms_message("Java_org_linphone_core_CoreImpl_setNativePreviewWindowId(): NewGlobalRef(%p)", id); + } else ms_message("Java_org_linphone_core_CoreImpl_setNativePreviewWindowId(): setting to NULL"); + linphone_core_set_native_preview_window_id(cptr, (void *)id); + if (oldWindow != NULL) { + ms_message("Java_org_linphone_core_CoreImpl_setNativePreviewWindowId(): DeleteGlobalRef(%p)", oldWindow); + env->DeleteGlobalRef(oldWindow); + } +} + +void Java_org_linphone_core_CoreImpl_setNativeVideoWindowId(JNIEnv *env, jobject thiz, jlong ptr, jobject id) { + LinphoneCore *cptr = (LinphoneCore*)ptr; + jobject oldWindow = (jobject) linphone_core_get_native_preview_window_id(cptr); + if (oldWindow == id) { + ms_warning("Java_org_linphone_core_CoreImpl_setNativeVideoWindowId(): new id (%p) is the same as the current one, skipping...", id); + return; + } + if (id != NULL) { + id = env->NewGlobalRef(id); + ms_message("Java_org_linphone_core_CoreImpl_setNativeVideoWindowId(): NewGlobalRef(%p)", id); + } else ms_message("Java_org_linphone_core_CoreImpl_setNativeVideoWindowId(): setting to NULL"); + linphone_core_set_native_video_window_id(cptr, (void *)id); + if (oldWindow != NULL) { + ms_message("Java_org_linphone_core_CoreImpl_setNativeVideoWindowId(): DeleteGlobalRef(%p)", oldWindow); + env->DeleteGlobalRef(oldWindow); + } +} + #ifdef __cplusplus } #endif \ No newline at end of file From 220ab0f123a557820a8b58c64e2fcd55ddc58e07 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 29 Nov 2017 15:43:33 +0100 Subject: [PATCH 0919/2215] feat(MainDb): explicit insert of basic chat room --- src/db/main-db-p.h | 3 +-- src/db/main-db.cpp | 7 +++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index e871661d2..d4c90cfd6 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -54,10 +54,9 @@ private: void insertContent (long long messageEventId, const Content &content); void updateContent (long long messageEventId, long long messageContentId, const Content &content); long long insertContentType (const std::string &contentType); - long long insertChatRoom ( + long long insertBasicChatRoom ( long long peerSipAddressId, long long localSipAddressId, - int capabilities, const tm &creationTime ); long long insertChatRoom (const std::shared_ptr &chatRoom); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index f14ddc1ca..013e26474 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -200,10 +200,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return q->getLastInsertId(); } - long long MainDbPrivate::insertChatRoom ( + long long MainDbPrivate::insertBasicChatRoom ( long long peerSipAddressId, long long localSipAddressId, - int capabilities, const tm &creationTime ) { L_Q(); @@ -214,6 +213,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), if (id >= 0) return id; + static const int capabilities = static_cast(ChatRoom::Capabilities::Basic); lInfo() << "Insert new chat room in database: (peer=" << peerSipAddressId << ", local=" << localSipAddressId << ", capabilities=" << capabilities << ")."; *session << "INSERT INTO chat_room (" @@ -1989,10 +1989,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), const long long &eventId = getLastInsertId(); const long long &localSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_LOCAL_ADDRESS)); const long long &remoteSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_REMOTE_ADDRESS)); - const long long &chatRoomId = d->insertChatRoom( + const long long &chatRoomId = d->insertBasicChatRoom( remoteSipAddressId, localSipAddressId, - static_cast(ChatRoom::Capabilities::Basic), creationTime ); const int &isSecured = message.get(LEGACY_MESSAGE_COL_IS_SECURED, 0); From 24d627adf732caf0e78978916c9ca3ef0f930b5e Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 29 Nov 2017 15:45:00 +0100 Subject: [PATCH 0920/2215] fix(c-chat-message): remove linphone_chat_message_get_storage_id --- include/linphone/api/c-chat-message.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index 8b29ed040..c4bcacd1a 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -125,13 +125,6 @@ LINPHONE_PUBLIC void linphone_chat_message_set_content_type(LinphoneChatMessage */ LINPHONE_PUBLIC const char* linphone_chat_message_get_text(LinphoneChatMessage* msg); -/** - * Returns the id used to identify this message in the storage database - * @param message the message - * @return the id - */ -LINPHONE_PUBLIC unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage* msg); - /** * Get the message identifier. * It is used to identify a message so that it can be notified as delivered and/or displayed. From f0ca552ce4b9d5e02c0b3d61b7c7341caa451bb3 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 29 Nov 2017 15:57:33 +0100 Subject: [PATCH 0921/2215] fix(ChatRoom): reuse event from chat message in cb when possible --- src/chat/chat-room/chat-room.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 0bdd1e459..980bb40a7 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -163,14 +163,21 @@ void ChatRoomPrivate::sendMessage (const shared_ptr &msg) { // TODO: Check direction. - msg->getPrivate()->setTime(ms_time(0)); - msg->getPrivate()->send(); + ChatMessagePrivate *dChatMessage = msg->getPrivate(); + dChatMessage->setTime(ms_time(0)); + dChatMessage->send(); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAddedCb cb = linphone_chat_room_cbs_get_chat_message_sent(cbs); - shared_ptr event = make_shared(msg->getTime(), msg); + if (cb) { + shared_ptr event = static_pointer_cast( + q->getCore()->getPrivate()->mainDb->getEventFromKey(dChatMessage->dbKey) + ); + if (!event) + event = make_shared(msg->getTime(), msg); + cb(cr, L_GET_C_BACK_PTR(event)); } From 91a64a746292af23ed74a99ec76cb0c255ff34fa Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 29 Nov 2017 15:59:22 +0100 Subject: [PATCH 0922/2215] fix(ChatRoom): remove useless code --- src/chat/chat-room/chat-room-p.h | 3 --- src/chat/chat-room/chat-room.cpp | 31 ------------------------------- 2 files changed, 34 deletions(-) diff --git a/src/chat/chat-room/chat-room-p.h b/src/chat/chat-room/chat-room-p.h index 36f64e1e8..2f5f0bdac 100644 --- a/src/chat/chat-room/chat-room-p.h +++ b/src/chat/chat-room/chat-room-p.h @@ -36,8 +36,6 @@ class ChatRoomPrivate : public ObjectPrivate, public IsComposingListener { public: ChatRoomPrivate () = default; - static int createChatMessageFromDb (void *data, int argc, char **argv, char **colName); - void addTransientEvent (const std::shared_ptr &log); void removeTransientEvent (const std::shared_ptr &log); @@ -49,7 +47,6 @@ public: void sendIsComposingNotification (); - int createChatMessageFromDb (int argc, char **argv, char **colName); std::list> findMessages (const std::string &messageId) const; virtual LinphoneReason messageReceived (SalOp *op, const SalMessage *msg); diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 980bb40a7..4c70fa249 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -35,13 +35,6 @@ LINPHONE_BEGIN_NAMESPACE // ----------------------------------------------------------------------------- -int ChatRoomPrivate::createChatMessageFromDb (void *data, int argc, char **argv, char **colName) { - ChatRoomPrivate *d = reinterpret_cast(data); - return d->createChatMessageFromDb(argc, argv, colName); -} - -// ----------------------------------------------------------------------------- - void ChatRoomPrivate::addTransientEvent (const shared_ptr &log) { auto iter = find(transientEvents.begin(), transientEvents.end(), log); if (iter == transientEvents.end()) @@ -129,30 +122,6 @@ time_t ChatRoom::getLastUpdateTime () const { // ----------------------------------------------------------------------------- -/** - * DB layout: - * - * | 0 | storage_id - * | 1 | localContact - * | 2 | remoteContact - * | 3 | direction flag (LinphoneChatMessageDir) - * | 4 | message (text content of the message) - * | 5 | time (unused now, used to be string-based timestamp, replaced by the utc timestamp) - * | 6 | read flag (no longer used, replaced by the LinphoneChatMessageStateDisplayed state) - * | 7 | status (LinphoneChatMessageState) - * | 8 | external body url (deprecated file transfer system) - * | 9 | utc timestamp - * | 10 | app data text - * | 11 | linphone content id (LinphoneContent describing a file transfer) - * | 12 | message id (used for IMDN) - * | 13 | content type (of the message field [must be text representable]) - * | 14 | secured flag - */ -int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colName) { - // TODO: history. - return 0; -} - list > ChatRoomPrivate::findMessages (const string &messageId) const { L_Q(); return q->getCore()->getPrivate()->mainDb->findChatMessages(q->getChatRoomId(), messageId); From 52d7652e282e4b44b2faa4bee0ad94edf386e7c3 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 29 Nov 2017 17:32:10 +0100 Subject: [PATCH 0923/2215] feat(EventLog): provide a way to delete event in public interface --- include/linphone/api/c-event-log.h | 6 ++++++ src/c-wrapper/api/c-event-log.cpp | 4 ++++ src/event-log/event-log.cpp | 7 +++++++ src/event-log/event-log.h | 3 +++ 4 files changed, 20 insertions(+) diff --git a/include/linphone/api/c-event-log.h b/include/linphone/api/c-event-log.h index 5ebcae081..077438469 100644 --- a/include/linphone/api/c-event-log.h +++ b/include/linphone/api/c-event-log.h @@ -61,6 +61,12 @@ LINPHONE_PUBLIC LinphoneEventLogType linphone_event_log_get_type (const Linphone */ LINPHONE_PUBLIC time_t linphone_event_log_get_creation_time (const LinphoneEventLog *event_log); +/** + * Delete event log from database. + * @param[in] event_log A #LinphoneEventLog object + */ +LINPHONE_PUBLIC void linphone_event_log_delete_from_database (LinphoneEventLog *event_log); + // ----------------------------------------------------------------------------- // ConferenceEvent. // ----------------------------------------------------------------------------- diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 0a12eefbb..9e8e6aa36 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -190,6 +190,10 @@ time_t linphone_event_log_get_creation_time (const LinphoneEventLog *event_log) return L_GET_CPP_PTR_FROM_C_OBJECT(event_log)->getCreationTime(); } +void linphone_event_log_delete_from_database (LinphoneEventLog *event_log) { + LinphonePrivate::EventLog::deleteFromDatabase(L_GET_CPP_PTR_FROM_C_OBJECT(event_log)); +} + // ----------------------------------------------------------------------------- // ConferenceEvent. // ----------------------------------------------------------------------------- diff --git a/src/event-log/event-log.cpp b/src/event-log/event-log.cpp index 86e92a668..e6d44b787 100644 --- a/src/event-log/event-log.cpp +++ b/src/event-log/event-log.cpp @@ -17,10 +17,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "db/main-db.h" #include "event-log-p.h" // ============================================================================= +using namespace std; + LINPHONE_BEGIN_NAMESPACE EventLog::EventLog () : BaseObject(*new EventLogPrivate) {} @@ -41,4 +44,8 @@ time_t EventLog::getCreationTime () const { return d->creationTime; } +void EventLog::deleteFromDatabase (const shared_ptr &eventLog) { + MainDb::deleteEvent(eventLog); +} + LINPHONE_END_NAMESPACE diff --git a/src/event-log/event-log.h b/src/event-log/event-log.h index b12a4cfc4..660003d77 100644 --- a/src/event-log/event-log.h +++ b/src/event-log/event-log.h @@ -21,6 +21,7 @@ #define _EVENT_LOG_H_ #include +#include #include "linphone/enums/event-log-enums.h" #include "linphone/utils/enum-generator.h" @@ -45,6 +46,8 @@ public: Type getType () const; time_t getCreationTime () const; + static void deleteFromDatabase (const std::shared_ptr &eventLog); + protected: EventLog (EventLogPrivate &p, Type type, time_t creationTime); From cea7ca8bb14a2cf087e6417f5ab49aa45eb04a66 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 30 Nov 2017 09:27:46 +0100 Subject: [PATCH 0924/2215] fix(c-chat-room): delete correctly chat message --- src/c-wrapper/api/c-chat-room.cpp | 9 +++++++-- src/chat/chat-room/chat-room.cpp | 4 ---- src/chat/chat-room/chat-room.h | 1 - 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index dd3d35c40..3fac4d189 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -23,8 +23,9 @@ #include "linphone/api/c-chat-room.h" #include "linphone/wrapper_utils.h" -#include "c-wrapper/c-wrapper.h" #include "address/identity-address.h" +#include "c-wrapper/c-wrapper.h" +#include "chat/chat-message/chat-message-p.h" #include "chat/chat-room/basic-chat-room.h" #include "chat/chat-room/client-group-chat-room.h" #include "chat/chat-room/real-time-text-chat-room-p.h" @@ -183,7 +184,11 @@ int linphone_chat_room_get_history_size (LinphoneChatRoom *cr) { } void linphone_chat_room_delete_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) { - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->deleteMessage(L_GET_CPP_PTR_FROM_C_OBJECT(msg)); + shared_ptr event = LinphonePrivate::MainDb::getEventFromKey( + L_GET_PRIVATE_FROM_C_OBJECT(msg)->dbKey + ); + if (event) + LinphonePrivate::EventLog::deleteFromDatabase(event); } void linphone_chat_room_delete_history (LinphoneChatRoom *cr) { diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 4c70fa249..a49416b49 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -383,10 +383,6 @@ void ChatRoom::deleteHistory () { // TODO: history. } -void ChatRoom::deleteMessage (const shared_ptr &msg) { - // TODO: history. -} - shared_ptr ChatRoom::findMessage (const string &messageId) { L_D(); shared_ptr cm = nullptr; diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index a4d6c126a..6c988a583 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -66,7 +66,6 @@ public: std::shared_ptr createMessage (const std::string &msg); std::shared_ptr createMessage (); void deleteHistory (); - void deleteMessage (const std::shared_ptr &msg); std::shared_ptr findMessage (const std::string &messageId); std::shared_ptr findMessageWithDirection (const std::string &messageId, ChatMessage::Direction direction); std::list> getHistory (int nbMessages); From af709ad4c943c735787d2b5acd6b20c5fc4d9667 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 30 Nov 2017 10:18:12 +0100 Subject: [PATCH 0925/2215] fix(ChatRoom): add delete history impl --- src/chat/chat-room/chat-room.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index a49416b49..b19bb4912 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -380,7 +380,7 @@ shared_ptr ChatRoom::createMessage () { } void ChatRoom::deleteHistory () { - // TODO: history. + getCore()->getPrivate()->mainDb->cleanHistory(getChatRoomId()); } shared_ptr ChatRoom::findMessage (const string &messageId) { From d111d78f71114d0ec0ba01af93a344c1d318cf59 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 30 Nov 2017 11:20:38 +0100 Subject: [PATCH 0926/2215] feat(core-c): provide a way to find chat room --- coreapi/chat.c | 11 +++++++++++ coreapi/tester_utils.cpp | 11 ----------- coreapi/tester_utils.h | 2 -- include/linphone/core.h | 24 +++++++++++++++++++----- src/db/abstract/abstract-db.cpp | 4 ++-- 5 files changed, 32 insertions(+), 20 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index c5b5d1200..2a2fac935 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -104,6 +104,17 @@ LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const c return L_GET_C_BACK_PTR(lc->cppCore->getOrCreateBasicChatRoomFromUri(L_C_TO_STRING(to))); } +LinphoneChatRoom *linphone_core_find_chat_room( + const LinphoneCore *lc, + const LinphoneAddress *peerAddr, + const LinphoneAddress *localAddr +) { + return L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(LinphonePrivate::ChatRoomId( + LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(peerAddr)), + LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(localAddr)) + ))); +} + int linphone_core_message_received(LinphoneCore *lc, LinphonePrivate::SalOp *op, const SalMessage *sal_msg) { LinphoneReason reason = LinphoneReasonNotAcceptable; const char *peerAddress; diff --git a/coreapi/tester_utils.cpp b/coreapi/tester_utils.cpp index f5d50e8e3..600c21bdb 100644 --- a/coreapi/tester_utils.cpp +++ b/coreapi/tester_utils.cpp @@ -56,17 +56,6 @@ bctbx_list_t **linphone_core_get_call_logs_attribute(LinphoneCore *lc) { return &lc->call_logs; } -LinphoneChatRoom * linphone_core_find_chat_room (const LinphoneCore *lc, const LinphoneAddress *peerAddr, const LinphoneAddress *localAddr) { - shared_ptr chatRoom = lc->cppCore->findChatRoom(ChatRoomId( - IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(peerAddr)), - IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(localAddr)) - )); - - if (chatRoom) - return L_GET_C_BACK_PTR(chatRoom); - return nullptr; -} - void linphone_core_cbs_set_auth_info_requested(LinphoneCoreCbs *cbs, LinphoneCoreAuthInfoRequestedCb cb) { cbs->vtable->auth_info_requested = cb; } diff --git a/coreapi/tester_utils.h b/coreapi/tester_utils.h index 862d1043a..32a058161 100644 --- a/coreapi/tester_utils.h +++ b/coreapi/tester_utils.h @@ -93,8 +93,6 @@ LINPHONE_PUBLIC mblk_t *_linphone_call_stats_get_received_rtcp (const LinphoneCa LINPHONE_PUBLIC LinphoneQualityReporting *linphone_call_log_get_quality_reporting(LinphoneCallLog *call_log); LINPHONE_PUBLIC reporting_session_report_t **linphone_quality_reporting_get_reports(LinphoneQualityReporting *qreporting); -LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_find_chat_room (const LinphoneCore *lc, const LinphoneAddress *peerAddr, const LinphoneAddress *localAddr); - LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_from_db(LinphoneCore *lc, LinphoneFriendList *list); LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_lists_from_db(LinphoneCore *lc); LINPHONE_PUBLIC void linphone_friend_invalidate_subscription(LinphoneFriend *lf); diff --git a/include/linphone/core.h b/include/linphone/core.h index 55e8cbe5f..9e627b785 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -3448,7 +3448,7 @@ LINPHONE_PUBLIC void linphone_core_set_preview_video_definition(LinphoneCore *lc /** * @biref Sets the video size for the captured (preview) video. - * + * * This method is for advanced usage where a video capture must be set independently of the size of the stream actually sent through the call. * This allows for example to have the preview window with HD resolution even if due to bandwidth constraint the sent video size is small. * Using this feature increases the CPU consumption, since a rescaling will be done internally. @@ -3501,7 +3501,7 @@ LINPHONE_PUBLIC LinphoneVideoDefinition * linphone_core_get_current_preview_vide /** * @brief Returns the effective video size for the captured video as provided by the camera. - * + * * When preview is disabled or not yet started, this function returns a zeroed video size. * @see #linphone_core_set_preview_video_size() * @ingroup media_parameters @@ -4725,7 +4725,7 @@ LINPHONE_PUBLIC bool_t linphone_core_video_multicast_enabled(const LinphoneCore /** * @brief Set the network simulator parameters. - * + * * Liblinphone has the capabability of simulating the effects of a network (latency, lost packets, jitter, max bandwidth). * Please refer to the oRTP documentation for the meaning of the parameters of the OrtpNetworkSimulatorParams structure. * This function has effect for future calls, but not for currently running calls, though this behavior may be changed in future versions. @@ -4941,7 +4941,7 @@ LINPHONE_PUBLIC const char *linphone_core_get_chat_database_path(const LinphoneC LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, const char *subject); /** - * Get a chat room whose peer is the supplied address. If it does not exist yet, it will be created. + * Get a basic chat room whose peer is the supplied address. If it does not exist yet, it will be created. * No reference is transfered to the application. The LinphoneCore keeps a reference on the chat room. * @param lc the linphone core * @param addr a linphone address. @@ -4950,7 +4950,7 @@ LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_client_group_chat_room(L LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr); /** - * Get a chat room for messaging from a sip uri like sip:joe@sip.linphone.org. If it does not exist yet, it will be created. + * Get a basic chat room for messaging from a sip uri like sip:joe@sip.linphone.org. If it does not exist yet, it will be created. * No reference is transfered to the application. The LinphoneCore keeps a reference on the chat room. * @param lc A #LinphoneCore object * @param to The destination address for messages. @@ -4958,6 +4958,20 @@ LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, **/ LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const char *to); +/** + * Find a chat room. + * No reference is transfered to the application. The LinphoneCore keeps a reference on the chat room. + * @param lc the linphone core + * @param peerAddr a linphone address. + * @param localAddr a linphone address. + * @return #LinphoneChatRoom where messaging can take place. +**/ +LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_find_chat_room ( + const LinphoneCore *lc, + const LinphoneAddress *peerAddr, + const LinphoneAddress *localAddr +); + /** * Removes a chatroom including all message history from the LinphoneCore. * @param lc A #LinphoneCore object diff --git a/src/db/abstract/abstract-db.cpp b/src/db/abstract/abstract-db.cpp index eea755fa7..3f58b5251 100644 --- a/src/db/abstract/abstract-db.cpp +++ b/src/db/abstract/abstract-db.cpp @@ -52,8 +52,8 @@ bool AbstractDb::connect (Backend backend, const string ¶meters) { d->backend = backend; d->dbSession = DbSessionProvider::getInstance()->getSession( - (backend == Mysql ? "mysql://" : "sqlite3://") + parameters - ); + (backend == Mysql ? "mysql://" : "sqlite3://") + parameters + ); if (d->dbSession) { try { From 7c2ce9d173e100d84afb5fb5ef90189a787ddb8d Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 30 Nov 2017 14:14:24 +0100 Subject: [PATCH 0927/2215] notify core when chat room is created instead of instantiated --- src/chat/chat-room/chat-room.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index b19bb4912..00e99d7d7 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -60,7 +60,8 @@ void ChatRoomPrivate::setState (ChatRoom::State newState) { L_Q(); if (newState != state) { state = newState; - if (state == ChatRoom::State::Instantiated) + if (state == ChatRoom::State::Created) + // TODO : Rename from instatiated to created. linphone_core_notify_chat_room_instantiated(q->getCore()->getCCore(), L_GET_C_BACK_PTR(q)); notifyStateChanged(); } From 71757bbce75ec86708bf8da2d6ade003b50be2a3 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 30 Nov 2017 14:15:35 +0100 Subject: [PATCH 0928/2215] feat(MainDb): save chat room read only state --- src/chat/chat-room/basic-chat-room.cpp | 4 ++++ src/chat/chat-room/basic-chat-room.h | 1 + src/chat/chat-room/chat-room.h | 1 + src/chat/chat-room/client-group-chat-room.cpp | 9 +++++++-- src/chat/chat-room/client-group-chat-room.h | 4 +++- src/chat/chat-room/server-group-chat-room-stub.cpp | 4 ++++ src/chat/chat-room/server-group-chat-room.h | 1 + src/db/main-db.cpp | 13 +++++++++---- 8 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/chat/chat-room/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp index edaef84c1..5e9d70d8a 100644 --- a/src/chat/chat-room/basic-chat-room.cpp +++ b/src/chat/chat-room/basic-chat-room.cpp @@ -51,6 +51,10 @@ BasicChatRoom::CapabilitiesMask BasicChatRoom::getCapabilities () const { return static_cast(Capabilities::Basic); } +bool BasicChatRoom::isReadOnly () const { + return false; +} + bool BasicChatRoom::canHandleParticipants () const { return false; } diff --git a/src/chat/chat-room/basic-chat-room.h b/src/chat/chat-room/basic-chat-room.h index bf777e4c8..c546f35d1 100644 --- a/src/chat/chat-room/basic-chat-room.h +++ b/src/chat/chat-room/basic-chat-room.h @@ -33,6 +33,7 @@ class LINPHONE_PUBLIC BasicChatRoom : public ChatRoom { public: CapabilitiesMask getCapabilities () const override; + bool isReadOnly () const override; const IdentityAddress &getConferenceAddress () const override; diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index 6c988a583..f71ee7f84 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -57,6 +57,7 @@ public: time_t getLastUpdateTime () const; virtual CapabilitiesMask getCapabilities () const = 0; + virtual bool isReadOnly () const = 0; std::shared_ptr getLastMessageInHistory () const; diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 1d8660966..ffbca8196 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -103,7 +103,8 @@ ClientGroupChatRoom::ClientGroupChatRoom ( shared_ptr &me, const string &subject, list> &&participants, - unsigned int lastNotifyId + unsigned int lastNotifyId, + bool isReadOnly ) : ChatRoom(*new ClientGroupChatRoomPrivate, core, ChatRoomId(peerAddress, me->getAddress())), RemoteConference(core, me->getAddress(), nullptr) { L_D(); @@ -114,7 +115,7 @@ RemoteConference(core, me->getAddress(), nullptr) { dConference->subject = subject; dConference->participants = move(participants); - d->state = ChatRoom::State::Created; + d->state = isReadOnly ? ChatRoom::State::Created : ChatRoom::State::Terminated; getMe()->getPrivate()->setAdmin(me->isAdmin()); @@ -130,6 +131,10 @@ ClientGroupChatRoom::CapabilitiesMask ClientGroupChatRoom::getCapabilities () co return static_cast(Capabilities::Conference); } +bool ClientGroupChatRoom::isReadOnly () const { + return getState() == State::Created; +} + bool ClientGroupChatRoom::canHandleParticipants () const { return RemoteConference::canHandleParticipants(); } diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 042d7a59f..481b04377 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -45,12 +45,14 @@ public: std::shared_ptr &me, const std::string &subject, std::list> &&participants, - unsigned int lastNotifyId + unsigned int lastNotifyId, + bool isReadOnly ); std::shared_ptr getCore () const; CapabilitiesMask getCapabilities () const override; + bool isReadOnly () const override; const IdentityAddress &getConferenceAddress () const override; diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index 5abf436d2..c0bfb39f1 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -85,6 +85,10 @@ int ServerGroupChatRoom::getCapabilities () const { return 0; } +bool ServerGroupChatRoom::isReadOnly () const { + return true; +} + bool ServerGroupChatRoom::canHandleParticipants () const { return false; } diff --git a/src/chat/chat-room/server-group-chat-room.h b/src/chat/chat-room/server-group-chat-room.h index 9c8fc9d8a..0f68deef5 100644 --- a/src/chat/chat-room/server-group-chat-room.h +++ b/src/chat/chat-room/server-group-chat-room.h @@ -40,6 +40,7 @@ public: ServerGroupChatRoom (const std::shared_ptr &core, SalCallOp *op); CapabilitiesMask getCapabilities () const override; + bool isReadOnly () const override; const IdentityAddress &getConferenceAddress () const override; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 013e26474..a73b10b9a 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -247,11 +247,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), const tm &creationTime = Utils::getTimeTAsTm(chatRoom->getCreationTime()); const int &capabilities = static_cast(chatRoom->getCapabilities()); const string &subject = chatRoom->getSubject(); + const int &flags = chatRoom->isReadOnly(); *session << "INSERT INTO chat_room (" " peer_sip_address_id, local_sip_address_id, creation_time, last_update_time, capabilities, subject" - ") VALUES (:peerSipAddressId, :localSipAddressId, :creationTime, :lastUpdateTime, :capabilities, :subject)", + ") VALUES (:peerSipAddressId, :localSipAddressId, :creationTime, :lastUpdateTime, :capabilities, :subject, :flags)", soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::use(creationTime), soci::use(creationTime), - soci::use(capabilities), soci::use(subject); + soci::use(capabilities), soci::use(subject), soci::use(flags); id = q->getLastInsertId(); @@ -898,6 +899,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " last_notify_id INT UNSIGNED," + " flags INT UNSIGNED DEFAULT 0," + " UNIQUE (peer_sip_address_id, local_sip_address_id)," " FOREIGN KEY (peer_sip_address_id)" @@ -1718,7 +1721,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), // ----------------------------------------------------------------------------- list> MainDb::getChatRooms () const { - static const string query = "SELECT chat_room.id, peer_sip_address.value, local_sip_address.value, creation_time, last_update_time, capabilities, subject, last_notify_id" + static const string query = "SELECT chat_room.id, peer_sip_address.value, local_sip_address.value, " + "creation_time, last_update_time, capabilities, subject, last_notify_id, flags" " FROM chat_room, sip_address AS peer_sip_address, sip_address AS local_sip_address" " WHERE chat_room.peer_sip_address_id = peer_sip_address.id AND chat_room.local_sip_address_id = local_sip_address.id" " ORDER BY last_update_time DESC"; @@ -1797,7 +1801,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), me, subject, move(participants), - lastNotifyId + lastNotifyId, + !!row.get(8, 0) ); } From 310637f2750930e261a0f2d865c2a60dc9bf06c9 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 30 Nov 2017 14:32:31 +0100 Subject: [PATCH 0929/2215] feat(core): add a find one to one chat room function --- src/core/core-chat-room.cpp | 17 +++++++++++++++++ src/core/core.h | 5 +++++ src/db/main-db.cpp | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 5d8c8b6e4..76bdcda8f 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -23,6 +23,7 @@ #include "chat/chat-room/basic-chat-room.h" #include "chat/chat-room/chat-room-p.h" #include "chat/chat-room/real-time-text-chat-room.h" +#include "conference/participant.h" #include "core-p.h" #include "logger/logger.h" @@ -127,6 +128,22 @@ list> Core::findChatRooms (const IdentityAddress &peerAddre return output; } +shared_ptr Core::findOneToOneChatRoom ( + const IdentityAddress &localAddress, + const IdentityAddress &participantAddress +) { + L_D(); + for (const auto &chatRoom : d->chatRooms) { + if ( + chatRoom->getNbParticipants() == 1 && + chatRoom->getLocalAddress() == localAddress && + participantAddress == chatRoom->getParticipants().front()->getAddress() + ) + return chatRoom; + } + return nullptr; +} + shared_ptr Core::createClientGroupChatRoom (const string &subject) { L_D(); return L_GET_CPP_PTR_FROM_C_OBJECT( diff --git a/src/core/core.h b/src/core/core.h index 9aeab7697..f88c7251d 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -70,6 +70,11 @@ public: std::shared_ptr findChatRoom (const ChatRoomId &chatRoomId) const; std::list> findChatRooms (const IdentityAddress &peerAddress) const; + std::shared_ptr findOneToOneChatRoom ( + const IdentityAddress &localAddress, + const IdentityAddress &participantAddress + ); + std::shared_ptr createClientGroupChatRoom (const std::string &subject); std::shared_ptr createClientGroupChatRoom (const std::string &subject, const IdentityAddress &localAddress); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index a73b10b9a..fd55723f6 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -897,7 +897,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), // Chatroom subject. " subject VARCHAR(255)," - " last_notify_id INT UNSIGNED," + " last_notify_id INT UNSIGNED DEFAULT 0," " flags INT UNSIGNED DEFAULT 0," From b0f2d805476c725dadb3d263f4104b7bb36033ec Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 30 Nov 2017 14:41:01 +0100 Subject: [PATCH 0930/2215] SQL duration logger outputs to debug as default --- src/logger/logger.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logger/logger.h b/src/logger/logger.h index 032086556..d388bf77d 100644 --- a/src/logger/logger.h +++ b/src/logger/logger.h @@ -54,7 +54,7 @@ class DurationLoggerPrivate; class DurationLogger : public BaseObject { public: - DurationLogger (const std::string &label, Logger::Level level = Logger::Info); + DurationLogger (const std::string &label, Logger::Level level = Logger::Debug); ~DurationLogger (); private: From f23cfe27957aaf68d5335d2fe560c6016faac37a Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 30 Nov 2017 14:54:59 +0100 Subject: [PATCH 0931/2215] feat(c-core): wrap find one to one chat room function --- coreapi/chat.c | 19 +++++++++++++++---- include/linphone/core.h | 22 ++++++++++++++++++---- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 2a2fac935..65f85d15a 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -106,15 +106,26 @@ LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const c LinphoneChatRoom *linphone_core_find_chat_room( const LinphoneCore *lc, - const LinphoneAddress *peerAddr, - const LinphoneAddress *localAddr + const LinphoneAddress *peer_addr, + const LinphoneAddress *local_addr ) { return L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(LinphonePrivate::ChatRoomId( - LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(peerAddr)), - LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(localAddr)) + LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(peer_addr)), + LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(local_addr)) ))); } +LinphoneChatRoom *linphone_core_find_one_to_one_chat_room ( + const LinphoneCore *lc, + const LinphoneAddress *local_addr, + const LinphoneAddress *participant_addr +) { + return L_GET_C_BACK_PTR(lc->cppCore->findOneToOneChatRoom( + LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(local_addr)), + LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(participant_addr)) + )); +} + int linphone_core_message_received(LinphoneCore *lc, LinphonePrivate::SalOp *op, const SalMessage *sal_msg) { LinphoneReason reason = LinphoneReasonNotAcceptable; const char *peerAddress; diff --git a/include/linphone/core.h b/include/linphone/core.h index 9e627b785..ded1e3156 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -4962,14 +4962,28 @@ LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneC * Find a chat room. * No reference is transfered to the application. The LinphoneCore keeps a reference on the chat room. * @param lc the linphone core - * @param peerAddr a linphone address. - * @param localAddr a linphone address. + * @param peer_addr a linphone address. + * @param local_addr a linphone address. * @return #LinphoneChatRoom where messaging can take place. **/ LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_find_chat_room ( const LinphoneCore *lc, - const LinphoneAddress *peerAddr, - const LinphoneAddress *localAddr + const LinphoneAddress *peer_addr, + const LinphoneAddress *local_addr +); + +/** + * Find a one to one chat room. + * No reference is transfered to the application. The LinphoneCore keeps a reference on the chat room. + * @param lc the linphone core + * @param local_addr a linphone address. + * @param participant_addr a linphone address. + * @return #LinphoneChatRoom where messaging can take place. +**/ +LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_find_one_to_one_chat_room ( + const LinphoneCore *lc, + const LinphoneAddress *local_addr, + const LinphoneAddress *participant_addr ); /** From 286199423fe17ce6cc7fd53a8726e44cc299afbf Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 30 Nov 2017 14:56:50 +0100 Subject: [PATCH 0932/2215] wrap chatroom isReadOnly method --- include/linphone/api/c-chat-room.h | 7 +++++++ src/c-wrapper/api/c-chat-room.cpp | 4 ++++ src/chat/chat-room/client-group-chat-room.cpp | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index 966f36896..a566a5829 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -273,6 +273,13 @@ LINPHONE_PUBLIC LinphoneChatRoomCbs * linphone_chat_room_get_callbacks (const Li */ LINPHONE_PUBLIC LinphoneChatRoomState linphone_chat_room_get_state (const LinphoneChatRoom *cr); +/** + * Return whether or not the chat room is read only. + * @param[in] cr LinphoneChatRoom object + * @return whether or not the chat room is read only + */ +LINPHONE_PUBLIC bool_t linphone_chat_room_is_read_only (const LinphoneChatRoom *cr); + /** * Add a participant to a chat room. This may fail if this type of chat room does not handle participants. * Use linphone_chat_room_can_handle_participants() to know if this chat room handles participants. diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 3fac4d189..667312688 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -244,6 +244,10 @@ LinphoneChatRoomState linphone_chat_room_get_state (const LinphoneChatRoom *cr) return (LinphoneChatRoomState)L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getState(); } +bool_t linphone_chat_room_is_read_only (const LinphoneChatRoom *cr) { + return (bool_t)L_GET_CPP_PTR_FROM_C_OBJECT(cr)->isReadOnly(); +} + void linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr) { L_GET_CPP_PTR_FROM_C_OBJECT(cr)->addParticipant( LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr)), nullptr, false diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index ffbca8196..4ae71e314 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -132,7 +132,7 @@ ClientGroupChatRoom::CapabilitiesMask ClientGroupChatRoom::getCapabilities () co } bool ClientGroupChatRoom::isReadOnly () const { - return getState() == State::Created; + return getState() != State::Created; } bool ClientGroupChatRoom::canHandleParticipants () const { From 7e48b9c95649a2baf825106665c8bf7870f72abd Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 30 Nov 2017 15:03:28 +0100 Subject: [PATCH 0933/2215] fix(MainDb): insert correctly chat room --- src/db/main-db.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index fd55723f6..f1a765f0c 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -249,7 +249,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), const string &subject = chatRoom->getSubject(); const int &flags = chatRoom->isReadOnly(); *session << "INSERT INTO chat_room (" - " peer_sip_address_id, local_sip_address_id, creation_time, last_update_time, capabilities, subject" + " peer_sip_address_id, local_sip_address_id, creation_time, last_update_time, capabilities, subject, flags" ") VALUES (:peerSipAddressId, :localSipAddressId, :creationTime, :lastUpdateTime, :capabilities, :subject, :flags)", soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::use(creationTime), soci::use(creationTime), soci::use(capabilities), soci::use(subject), soci::use(flags); From d532fb79f795eacc9805c2de58dd050bebc762f9 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 30 Nov 2017 15:12:49 +0100 Subject: [PATCH 0934/2215] fix(ClientGroupChatRoom): set correctly state at fetch --- src/chat/chat-room/client-group-chat-room.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 4ae71e314..77700210b 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -115,7 +115,7 @@ RemoteConference(core, me->getAddress(), nullptr) { dConference->subject = subject; dConference->participants = move(participants); - d->state = isReadOnly ? ChatRoom::State::Created : ChatRoom::State::Terminated; + d->state = isReadOnly ? ChatRoom::State::Terminated : ChatRoom::State::Created; getMe()->getPrivate()->setAdmin(me->isAdmin()); From 8b7f6ef64c2df38bf6e84fa1a00e0b84fb25088c Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 30 Nov 2017 15:38:00 +0100 Subject: [PATCH 0935/2215] feat(MainDb): deal with conference terminated event --- include/linphone/enums/event-log-enums.h | 2 +- src/c-wrapper/api/c-event-log.cpp | 2 +- src/chat/chat-room/client-group-chat-room.cpp | 5 +++++ src/db/main-db.cpp | 19 ++++++++++++------- src/event-log/conference/conference-event.cpp | 2 +- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/include/linphone/enums/event-log-enums.h b/include/linphone/enums/event-log-enums.h index b6465b7fb..3a6416d69 100644 --- a/include/linphone/enums/event-log-enums.h +++ b/include/linphone/enums/event-log-enums.h @@ -25,7 +25,7 @@ #define L_ENUM_VALUES_EVENT_LOG_TYPE(F) \ F(None) \ F(ConferenceCreated) \ - F(ConferenceDestroyed) \ + F(ConferenceTerminated) \ F(ConferenceCallStart) \ F(ConferenceCallEnd) \ F(ConferenceChatMessage) \ diff --git a/src/c-wrapper/api/c-event-log.cpp b/src/c-wrapper/api/c-event-log.cpp index 9e8e6aa36..a9337d5e4 100644 --- a/src/c-wrapper/api/c-event-log.cpp +++ b/src/c-wrapper/api/c-event-log.cpp @@ -65,7 +65,7 @@ static bool isConferenceType (LinphoneEventLogType type) { case LinphoneEventLogTypeConferenceCallStart: case LinphoneEventLogTypeConferenceChatMessage: case LinphoneEventLogTypeConferenceCreated: - case LinphoneEventLogTypeConferenceDestroyed: + case LinphoneEventLogTypeConferenceTerminated: case LinphoneEventLogTypeConferenceParticipantAdded: case LinphoneEventLogTypeConferenceParticipantDeviceAdded: case LinphoneEventLogTypeConferenceParticipantDeviceRemoved: diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 77700210b..541da2aa9 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -310,6 +310,11 @@ void ClientGroupChatRoom::onConferenceTerminated (const IdentityAddress &addr) { L_D_T(RemoteConference, dConference); dConference->eventHandler->resetLastNotify(); d->setState(ChatRoom::State::Terminated); + getCore()->getPrivate()->mainDb->addEvent(make_shared( + EventLog::Type::ConferenceTerminated, + time(nullptr), + d->chatRoomId + )); } void ClientGroupChatRoom::onFirstNotifyReceived (const IdentityAddress &addr) { diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index f1a765f0c..1e3002711 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -351,7 +351,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return nullptr; case EventLog::Type::ConferenceCreated: - case EventLog::Type::ConferenceDestroyed: + case EventLog::Type::ConferenceTerminated: eventLog = selectConferenceEvent(eventId, type, creationTime, chatRoomId); break; @@ -454,13 +454,15 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), chatRoom, static_cast(direction) )); - chatMessage->getPrivate()->setState(static_cast(state), true); chatMessage->setIsSecured(static_cast(isSecured)); - chatMessage->getPrivate()->forceFromAddress(IdentityAddress(fromSipAddress)); - chatMessage->getPrivate()->forceToAddress(IdentityAddress(toSipAddress)); + ChatMessagePrivate *dChatMessage = chatMessage->getPrivate(); + dChatMessage->setState(static_cast(state), true); - chatMessage->getPrivate()->setTime(Utils::getTmAsTimeT(messageTime)); + dChatMessage->forceFromAddress(IdentityAddress(fromSipAddress)); + dChatMessage->forceToAddress(IdentityAddress(toSipAddress)); + + dChatMessage->setTime(Utils::getTmAsTimeT(messageTime)); } // 2 - Fetch contents. @@ -629,6 +631,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "UPDATE chat_room SET last_update_time = :lastUpdateTime" " WHERE id = :chatRoomId", soci::use(lastUpdateTime), soci::use(curChatRoomId); + + if (eventLog->getType() == EventLog::Type::ConferenceTerminated) + *session << "UPDATE chat_room SET flags = 0 WHERE id = :chatRoomId", soci::use(curChatRoomId); } if (chatRoomId) @@ -1160,7 +1165,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return false; case EventLog::Type::ConferenceCreated: - case EventLog::Type::ConferenceDestroyed: + case EventLog::Type::ConferenceTerminated: storageId = d->insertConferenceEvent(eventLog); break; @@ -1232,7 +1237,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), break; case EventLog::Type::ConferenceCreated: - case EventLog::Type::ConferenceDestroyed: + case EventLog::Type::ConferenceTerminated: case EventLog::Type::ConferenceCallStart: case EventLog::Type::ConferenceCallEnd: case EventLog::Type::ConferenceParticipantAdded: diff --git a/src/event-log/conference/conference-event.cpp b/src/event-log/conference/conference-event.cpp index 5f6d88bb8..e6f9e9cd8 100644 --- a/src/event-log/conference/conference-event.cpp +++ b/src/event-log/conference/conference-event.cpp @@ -30,7 +30,7 @@ LINPHONE_BEGIN_NAMESPACE ConferenceEvent::ConferenceEvent (Type type, time_t creationTime, const ChatRoomId &chatRoomId) : EventLog(*new ConferenceEventPrivate, type, creationTime) { L_D(); - L_ASSERT(type == Type::ConferenceCreated || type == Type::ConferenceDestroyed); + L_ASSERT(type == Type::ConferenceCreated || type == Type::ConferenceTerminated); d->chatRoomId = chatRoomId; } From 397dbc39fbc3f9ce82070f916e52e7f261c058da Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 30 Nov 2017 15:41:44 +0100 Subject: [PATCH 0936/2215] fix(MainDb): set flags to 1 when chat room is terminated --- src/db/main-db.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 1e3002711..64b91f58d 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -633,7 +633,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::use(curChatRoomId); if (eventLog->getType() == EventLog::Type::ConferenceTerminated) - *session << "UPDATE chat_room SET flags = 0 WHERE id = :chatRoomId", soci::use(curChatRoomId); + *session << "UPDATE chat_room SET flags = 1 WHERE id = :chatRoomId", soci::use(curChatRoomId); } if (chatRoomId) From 47554237c1653c064a840e420e935a01a3d294a3 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 30 Nov 2017 15:57:56 +0100 Subject: [PATCH 0937/2215] feat(MainDb): invalid chat message when event log is not valid --- src/db/main-db.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 64b91f58d..7641e9019 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -845,12 +845,20 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); soci::rowset rows = (session->prepare << query, soci::use(chatRoomId)); for (const auto &row : rows) { - shared_ptr eventLog = getEventFromCache(resolveId(row, 0)); + long long eventId = resolveId(row, 0); + shared_ptr eventLog = getEventFromCache(eventId); if (eventLog) { const EventLogPrivate *dEventLog = eventLog->getPrivate(); L_ASSERT(dEventLog->dbKey.isValid()); dEventLog->dbKey = MainDbEventKey(); } + // TODO: Try to add a better code here... + shared_ptr chatMessage = getChatMessageFromCache(eventId); + if (chatMessage) { + const ChatMessagePrivate *dChatMessage = chatMessage->getPrivate(); + L_ASSERT(dChatMessage->dbKey.isValid()); + dChatMessage->dbKey = MainDbChatMessageKey(); + } } } From b357534bfe66a4332a846bf972f76721a316540d Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 30 Nov 2017 16:06:20 +0100 Subject: [PATCH 0938/2215] fix(MainDb): fix compilation when soci is not enabled --- src/db/main-db.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 7641e9019..596f326e2 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -2060,6 +2060,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return false; } + bool MainDb::updateEvent (const std::shared_ptr &) { + return false; + } + bool MainDb::deleteEvent (const shared_ptr &) { return false; } @@ -2068,6 +2072,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return 0; } + shared_ptr MainDb::getEventFromKey (const MainDbKey &) { + return nullptr; + } + list> MainDb::getConferenceNotifiedEvents ( const ChatRoomId &, unsigned int @@ -2083,6 +2091,14 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return 0; } + shared_ptr MainDb::getLastChatMessage (const ChatRoomId &) const { + return nullptr; + } + + list> MainDb::findChatMessages (const ChatRoomId &, const std::string &) const { + return list>(); + } + void MainDb::markChatMessagesAsRead (const ChatRoomId &) const {} list> MainDb::getUnreadChatMessages (const ChatRoomId &) const { @@ -2101,7 +2117,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return list>(); } - void MainDb::insertChatRoom (const ChatRoomId &, int, const string &) {} + void MainDb::insertChatRoom (const shared_ptr &) {} void MainDb::deleteChatRoom (const ChatRoomId &) {} From 6ef2937a8ea7cb97ef3177557a16a36b628a48de Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 29 Nov 2017 14:20:59 +0100 Subject: [PATCH 0939/2215] Rework call parameters handling. --- src/conference/params/call-session-params-p.h | 6 +- src/conference/params/call-session-params.cpp | 55 ++- src/conference/params/call-session-params.h | 2 +- .../params/media-session-params-p.h | 8 +- .../params/media-session-params.cpp | 112 +++--- src/conference/params/media-session-params.h | 2 +- src/conference/session/call-session-p.h | 3 + src/conference/session/call-session.cpp | 27 +- src/conference/session/media-session-p.h | 31 +- src/conference/session/media-session.cpp | 374 +++++++++--------- 10 files changed, 296 insertions(+), 324 deletions(-) diff --git a/src/conference/params/call-session-params-p.h b/src/conference/params/call-session-params-p.h index 23e3eb2ed..b07fc90d6 100644 --- a/src/conference/params/call-session-params-p.h +++ b/src/conference/params/call-session-params-p.h @@ -33,12 +33,8 @@ LINPHONE_BEGIN_NAMESPACE class CallSessionParamsPrivate : public ClonableObjectPrivate { public: CallSessionParamsPrivate () = default; - CallSessionParamsPrivate (const CallSessionParamsPrivate &src); - virtual ~CallSessionParamsPrivate (); - CallSessionParamsPrivate &operator= (const CallSessionParamsPrivate &src); - - static void clone (const CallSessionParamsPrivate &src, CallSessionParamsPrivate &dst); + void clone (const CallSessionParamsPrivate *src); bool getInConference () const { return inConference; } void setInConference (bool value) { inConference = value; } diff --git a/src/conference/params/call-session-params.cpp b/src/conference/params/call-session-params.cpp index 828d5a50d..27933bcf1 100644 --- a/src/conference/params/call-session-params.cpp +++ b/src/conference/params/call-session-params.cpp @@ -27,35 +27,21 @@ LINPHONE_BEGIN_NAMESPACE // ============================================================================= -CallSessionParamsPrivate::CallSessionParamsPrivate (const CallSessionParamsPrivate &src) : ClonableObjectPrivate () { - clone(src, *this); -} - -CallSessionParamsPrivate::~CallSessionParamsPrivate () { - if (customHeaders) - sal_custom_header_free(customHeaders); -} - -CallSessionParamsPrivate &CallSessionParamsPrivate::operator= (const CallSessionParamsPrivate &src) { - if (this != &src) { - if (customHeaders) - sal_custom_header_free(customHeaders); - clone(src, *this); - } - return *this; -} - -void CallSessionParamsPrivate::clone (const CallSessionParamsPrivate &src, CallSessionParamsPrivate &dst) { - dst.sessionName = src.sessionName; - dst.privacy = src.privacy; - dst.inConference = src.inConference; - dst.internalCallUpdate = src.internalCallUpdate; - dst.noUserConsent = src.noUserConsent; +void CallSessionParamsPrivate::clone (const CallSessionParamsPrivate *src) { + sessionName = src->sessionName; + privacy = src->privacy; + inConference = src->inConference; + internalCallUpdate = src->internalCallUpdate; + noUserConsent = src->noUserConsent; /* The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient. */ - if (src.customHeaders) - dst.customHeaders = sal_custom_header_clone(src.customHeaders); - dst.customContactParameters = src.customContactParameters; - dst.referer = src.referer; + if (customHeaders) { + sal_custom_header_free(customHeaders); + customHeaders = nullptr; + } + if (src->customHeaders) + customHeaders = sal_custom_header_clone(src->customHeaders); + customContactParameters = src->customContactParameters; + referer = src->referer; } // ----------------------------------------------------------------------------- @@ -80,12 +66,21 @@ CallSessionParams::CallSessionParams () : ClonableObject(*new CallSessionParamsP CallSessionParams::CallSessionParams (CallSessionParamsPrivate &p) : ClonableObject(p) {} CallSessionParams::CallSessionParams (const CallSessionParams &src) - : ClonableObject(*new CallSessionParamsPrivate(*src.getPrivate())) {} + : ClonableObject(*new CallSessionParamsPrivate) { + L_D(); + d->clone(src.getPrivate()); +} + +CallSessionParams::~CallSessionParams () { + L_D(); + if (d->customHeaders) + sal_custom_header_free(d->customHeaders); +} CallSessionParams &CallSessionParams::operator= (const CallSessionParams &src) { L_D(); if (this != &src) - *d = *src.getPrivate(); + d->clone(src.getPrivate()); return *this; } diff --git a/src/conference/params/call-session-params.h b/src/conference/params/call-session-params.h index 1d152308f..b5a351597 100644 --- a/src/conference/params/call-session-params.h +++ b/src/conference/params/call-session-params.h @@ -40,7 +40,7 @@ class CallSessionParams : public ClonableObject { public: CallSessionParams (); CallSessionParams (const CallSessionParams &src); - virtual ~CallSessionParams () = default; + virtual ~CallSessionParams (); CallSessionParams &operator= (const CallSessionParams &src); diff --git a/src/conference/params/media-session-params-p.h b/src/conference/params/media-session-params-p.h index f0955fa43..f9621df0c 100644 --- a/src/conference/params/media-session-params-p.h +++ b/src/conference/params/media-session-params-p.h @@ -36,13 +36,7 @@ LINPHONE_BEGIN_NAMESPACE class MediaSessionParamsPrivate : public CallSessionParamsPrivate { public: - MediaSessionParamsPrivate (); - MediaSessionParamsPrivate (const MediaSessionParamsPrivate &src); - virtual ~MediaSessionParamsPrivate (); - - MediaSessionParamsPrivate &operator= (const MediaSessionParamsPrivate &src); - - static void clone (const MediaSessionParamsPrivate &src, MediaSessionParamsPrivate &dst); + void clone (const MediaSessionParamsPrivate *src); void clean (); static SalStreamDir mediaDirectionToSalStreamDir (LinphoneMediaDirection direction); diff --git a/src/conference/params/media-session-params.cpp b/src/conference/params/media-session-params.cpp index dd652d73e..8ffc3dd91 100644 --- a/src/conference/params/media-session-params.cpp +++ b/src/conference/params/media-session-params.cpp @@ -32,61 +32,42 @@ LINPHONE_BEGIN_NAMESPACE // ============================================================================= -MediaSessionParamsPrivate::MediaSessionParamsPrivate () { - memset(customSdpMediaAttributes, 0, sizeof(customSdpMediaAttributes)); -} - -MediaSessionParamsPrivate::MediaSessionParamsPrivate (const MediaSessionParamsPrivate &src) : CallSessionParamsPrivate(src) { - clone(src, *this); -} - -MediaSessionParamsPrivate::~MediaSessionParamsPrivate () { - this->clean(); -} - -MediaSessionParamsPrivate &MediaSessionParamsPrivate::operator= (const MediaSessionParamsPrivate &src) { - if (this != &src) { - this->clean(); - clone(src, *this); - } - return *this; -} - -void MediaSessionParamsPrivate::clone (const MediaSessionParamsPrivate &src, MediaSessionParamsPrivate &dst) { - dst.audioEnabled = src.audioEnabled; - dst.audioBandwidthLimit = src.audioBandwidthLimit; - dst.audioDirection = src.audioDirection; - dst.audioMulticastEnabled = src.audioMulticastEnabled; - dst.usedAudioCodec = src.usedAudioCodec; - dst.videoEnabled = src.videoEnabled; - dst.videoDirection = src.videoDirection; - dst.videoMulticastEnabled = src.videoMulticastEnabled; - dst.usedVideoCodec = src.usedVideoCodec; - dst.receivedFps = src.receivedFps; - dst.receivedVideoDefinition = src.receivedVideoDefinition ? linphone_video_definition_ref(src.receivedVideoDefinition) : nullptr; - dst.sentFps = src.sentFps; - dst.sentVideoDefinition = src.sentVideoDefinition ? linphone_video_definition_ref(src.sentVideoDefinition) : nullptr; - dst.realtimeTextEnabled = src.realtimeTextEnabled; - dst.usedRealtimeTextCodec = src.usedRealtimeTextCodec; - dst.avpfEnabled = src.avpfEnabled; - dst.avpfRrInterval = src.avpfRrInterval; - dst.lowBandwidthEnabled = src.lowBandwidthEnabled; - dst.recordFilePath = src.recordFilePath; - dst.earlyMediaSendingEnabled = src.earlyMediaSendingEnabled; - dst.encryption = src.encryption; - dst.mandatoryMediaEncryptionEnabled = src.mandatoryMediaEncryptionEnabled; - dst._implicitRtcpFbEnabled = src._implicitRtcpFbEnabled; - dst.downBandwidth = src.downBandwidth; - dst.upBandwidth = src.upBandwidth; - dst.downPtime = src.downPtime; - dst.upPtime = src.upPtime; - dst.updateCallWhenIceCompleted = src.updateCallWhenIceCompleted; - if (src.customSdpAttributes) - dst.customSdpAttributes = sal_custom_sdp_attribute_clone(src.customSdpAttributes); - memset(dst.customSdpMediaAttributes, 0, sizeof(dst.customSdpMediaAttributes)); +void MediaSessionParamsPrivate::clone (const MediaSessionParamsPrivate *src) { + clean(); + CallSessionParamsPrivate::clone(src); + audioEnabled = src->audioEnabled; + audioBandwidthLimit = src->audioBandwidthLimit; + audioDirection = src->audioDirection; + audioMulticastEnabled = src->audioMulticastEnabled; + usedAudioCodec = src->usedAudioCodec; + videoEnabled = src->videoEnabled; + videoDirection = src->videoDirection; + videoMulticastEnabled = src->videoMulticastEnabled; + usedVideoCodec = src->usedVideoCodec; + receivedFps = src->receivedFps; + receivedVideoDefinition = src->receivedVideoDefinition ? linphone_video_definition_ref(src->receivedVideoDefinition) : nullptr; + sentFps = src->sentFps; + sentVideoDefinition = src->sentVideoDefinition ? linphone_video_definition_ref(src->sentVideoDefinition) : nullptr; + realtimeTextEnabled = src->realtimeTextEnabled; + usedRealtimeTextCodec = src->usedRealtimeTextCodec; + avpfEnabled = src->avpfEnabled; + avpfRrInterval = src->avpfRrInterval; + lowBandwidthEnabled = src->lowBandwidthEnabled; + recordFilePath = src->recordFilePath; + earlyMediaSendingEnabled = src->earlyMediaSendingEnabled; + encryption = src->encryption; + mandatoryMediaEncryptionEnabled = src->mandatoryMediaEncryptionEnabled; + _implicitRtcpFbEnabled = src->_implicitRtcpFbEnabled; + downBandwidth = src->downBandwidth; + upBandwidth = src->upBandwidth; + downPtime = src->downPtime; + upPtime = src->upPtime; + updateCallWhenIceCompleted = src->updateCallWhenIceCompleted; + if (src->customSdpAttributes) + customSdpAttributes = sal_custom_sdp_attribute_clone(src->customSdpAttributes); for (unsigned int i = 0; i < (unsigned int)LinphoneStreamTypeUnknown; i++) { - if (src.customSdpMediaAttributes[i]) - dst.customSdpMediaAttributes[i] = sal_custom_sdp_attribute_clone(src.customSdpMediaAttributes[i]); + if (src->customSdpMediaAttributes[i]) + customSdpMediaAttributes[i] = sal_custom_sdp_attribute_clone(src->customSdpMediaAttributes[i]); } } @@ -101,6 +82,7 @@ void MediaSessionParamsPrivate::clean () { if (customSdpMediaAttributes[i]) sal_custom_sdp_attribute_free(customSdpMediaAttributes[i]); } + memset(customSdpMediaAttributes, 0, sizeof(customSdpMediaAttributes)); } // ----------------------------------------------------------------------------- @@ -215,17 +197,27 @@ void MediaSessionParamsPrivate::setCustomSdpMediaAttributes (LinphoneStreamType // ============================================================================= -MediaSessionParams::MediaSessionParams () : CallSessionParams(*new MediaSessionParamsPrivate) {} +MediaSessionParams::MediaSessionParams () : CallSessionParams(*new MediaSessionParamsPrivate) { + L_D(); + memset(d->customSdpMediaAttributes, 0, sizeof(d->customSdpMediaAttributes)); +} MediaSessionParams::MediaSessionParams (const MediaSessionParams &src) - : CallSessionParams(*new MediaSessionParamsPrivate(*src.getPrivate())) {} + : CallSessionParams(*new MediaSessionParamsPrivate) { + L_D(); + memset(d->customSdpMediaAttributes, 0, sizeof(d->customSdpMediaAttributes)); + d->clone(src.getPrivate()); +} + +MediaSessionParams::~MediaSessionParams () { + L_D(); + d->clean(); +} MediaSessionParams &MediaSessionParams::operator= (const MediaSessionParams &src) { L_D(); - if (this != &src) { - CallSessionParams::operator=(src); - *d = *src.getPrivate(); - } + if (this != &src) + d->clone(src.getPrivate()); return *this; } diff --git a/src/conference/params/media-session-params.h b/src/conference/params/media-session-params.h index e4603abc1..45143c4fb 100644 --- a/src/conference/params/media-session-params.h +++ b/src/conference/params/media-session-params.h @@ -39,7 +39,7 @@ class MediaSessionParams : public CallSessionParams { public: MediaSessionParams (); MediaSessionParams (const MediaSessionParams &src); - virtual ~MediaSessionParams () = default; + virtual ~MediaSessionParams (); MediaSessionParams &operator= (const MediaSessionParams &src); diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index a607f26ac..e72de9e5e 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -41,8 +41,11 @@ public: bool startPing (); void setPingTime (int value) { pingTime = value; } + LinphoneCore *getCore () const { return core; } + CallSessionParams *getCurrentParams () const { return currentParams; } LinphoneProxyConfig * getDestProxy () const { return destProxy; } SalCallOp * getOp () const { return op; } + void setParams (CallSessionParams *csp); virtual void abort (const std::string &errorMsg); virtual void accepted (); diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index d322ba057..5c2d85aaa 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -43,7 +43,7 @@ LINPHONE_BEGIN_NAMESPACE CallSessionPrivate::CallSessionPrivate (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener) : conference(conference), listener(listener) { if (params) - this->params = new CallSessionParams(*params); + setParams(new CallSessionParams(*params)); currentParams = new CallSessionParams(); core = conference.getCore()->getCCore(); ei = linphone_error_info_new(); @@ -226,6 +226,14 @@ bool CallSessionPrivate::startPing () { // ----------------------------------------------------------------------------- +void CallSessionPrivate::setParams (CallSessionParams *csp) { + if (params) + delete params; + params = csp; +} + +// ----------------------------------------------------------------------------- + void CallSessionPrivate::abort (const string &errorMsg) { op->terminate(); setState(LinphoneCallError, errorMsg); @@ -346,9 +354,8 @@ void CallSessionPrivate::pingReply () { } void CallSessionPrivate::remoteRinging () { - L_Q(); /* Set privacy */ - q->getCurrentParams()->setPrivacy((LinphonePrivacyMask)op->get_privacy()); + currentParams->setPrivacy((LinphonePrivacyMask)op->get_privacy()); #if 0 if (lc->ringstream == NULL) start_remote_ring(lc, call); #endif @@ -452,14 +459,14 @@ void CallSessionPrivate::updating (bool isUpdate) { // ----------------------------------------------------------------------------- -void CallSessionPrivate::accept (const CallSessionParams *params) { +void CallSessionPrivate::accept (const CallSessionParams *csp) { L_Q(); /* Try to be best-effort in giving real local or routable contact address */ setContactOp(); - if (params) { - this->params = new CallSessionParams(*params); - op->set_sent_custom_header(this->params->getPrivate()->getCustomHeaders()); - } + if (csp) + setParams(new CallSessionParams(*csp)); + if (params) + op->set_sent_custom_header(params->getPrivate()->getCustomHeaders()); op->accept(); if (listener) @@ -759,7 +766,7 @@ void CallSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg if (direction == LinphoneCallOutgoing) { d->startPing(); } else if (direction == LinphoneCallIncoming) { - d->params = new CallSessionParams(); + d->setParams(new CallSessionParams()); d->params->initDefault(d->core); } } @@ -964,7 +971,7 @@ LinphoneStatus CallSession::update (const CallSessionParams *csp, const string & if (d->currentParams == csp) lWarning() << "CallSession::update() is given the current params, this is probably not what you intend to do!"; if (csp) - d->params = new CallSessionParams(*csp); + d->setParams(new CallSessionParams(*csp)); d->op->set_local_body(content ? *content : Content()); LinphoneStatus result = d->startUpdate(subject); if (result && (d->state != initialState)) { diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index b512e9ec1..2d7409736 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -62,30 +62,21 @@ public: void prepareStreamsForIceGathering (bool hasVideo); void stopStreamsForIceGathering (); - int getAf () const { - return af; - } + int getAf () const { return af; } - bool getAudioMuted () const { - return audioMuted; - } + bool getAudioMuted () const { return audioMuted; } - LinphoneCore *getCore () const { - return core; - } + MediaSessionParams *getCurrentParams () const { return static_cast(currentParams); } + MediaSessionParams *getParams () const { return static_cast(params); } + MediaSessionParams *getRemoteParams () const { return static_cast(remoteParams); } + void setParams (MediaSessionParams *msp); - IceSession *getIceSession () const { - return iceAgent->getIceSession(); - } + IceSession *getIceSession () const { return iceAgent->getIceSession(); } - SalMediaDescription *getLocalDesc () const { - return localDesc; - } + SalMediaDescription *getLocalDesc () const { return localDesc; } MediaStream *getMediaStream (LinphoneStreamType type) const; - LinphoneNatPolicy *getNatPolicy () const { - return natPolicy; - } + LinphoneNatPolicy *getNatPolicy () const { return natPolicy; } int getRtcpPort (LinphoneStreamType type) const; int getRtpPort (LinphoneStreamType type) const; @@ -253,10 +244,6 @@ private: static const std::string ecStateStore; static const int ecStateMaxLen; - MediaSessionParams *params = nullptr; - mutable MediaSessionParams *currentParams = nullptr; - MediaSessionParams *remoteParams = nullptr; - AudioStream *audioStream = nullptr; OrtpEvQueue *audioStreamEvQueue = nullptr; LinphoneCallStats *audioStats = nullptr; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 2a4c85ab5..b5aff989d 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -69,9 +69,11 @@ const int MediaSessionPrivate::ecStateMaxLen = 1048576; /* 1Mo */ // ============================================================================= MediaSessionPrivate::MediaSessionPrivate (const Conference &conference, const CallSessionParams *csp, CallSessionListener *listener) - : CallSessionPrivate(conference, csp, listener) { + : CallSessionPrivate(conference, nullptr, listener) { if (csp) - params = new MediaSessionParams(*(reinterpret_cast(csp))); + setParams(new MediaSessionParams(*(reinterpret_cast(csp)))); + else + setParams(new MediaSessionParams()); currentParams = new MediaSessionParams(); audioStats = _linphone_call_stats_new(); @@ -93,12 +95,6 @@ MediaSessionPrivate::MediaSessionPrivate (const Conference &conference, const Ca } MediaSessionPrivate::~MediaSessionPrivate () { - if (currentParams) - delete currentParams; - if (params) - delete params; - if (remoteParams) - delete remoteParams; if (audioStats) linphone_call_stats_unref(audioStats); if (videoStats) @@ -133,7 +129,7 @@ void MediaSessionPrivate::accepted () { LinphoneTaskList tl; linphone_task_list_init(&tl); /* Reset the internal call update flag, so it doesn't risk to be copied and used in further re-INVITEs */ - params->getPrivate()->setInternalCallUpdate(false); + getParams()->getPrivate()->setInternalCallUpdate(false); SalMediaDescription *rmd = op->get_remote_media_description(); SalMediaDescription *md = op->get_final_media_description(); if (!md && (prevState == LinphoneCallOutgoingEarlyMedia) && resultDesc) { @@ -165,7 +161,7 @@ void MediaSessionPrivate::accepted () { nextState = LinphoneCallPausedByRemote; nextStateMsg = "Call paused by remote"; } else { - if (!params->getPrivate()->getInConference() && listener) + if (!getParams()->getPrivate()->getInConference() && listener) listener->onSetCurrentSession(q->getSharedFromThis()); nextState = LinphoneCallStreamsRunning; nextStateMsg = "Streams running"; @@ -261,25 +257,25 @@ bool MediaSessionPrivate::failure () { for (int i = 0; i < localDesc->nb_streams; i++) { if (!sal_stream_description_active(&localDesc->streams[i])) continue; - if (params->getMediaEncryption() == LinphoneMediaEncryptionSRTP) { - if (params->avpfEnabled()) { + if (getParams()->getMediaEncryption() == LinphoneMediaEncryptionSRTP) { + if (getParams()->avpfEnabled()) { if (i == 0) lInfo() << "Retrying CallSession [" << q << "] with SAVP"; - params->enableAvpf(false); + getParams()->enableAvpf(false); restartInvite(); return true; } else if (!linphone_core_is_media_encryption_mandatory(core)) { if (i == 0) lInfo() << "Retrying CallSession [" << q << "] with AVP"; - params->setMediaEncryption(LinphoneMediaEncryptionNone); + getParams()->setMediaEncryption(LinphoneMediaEncryptionNone); memset(localDesc->streams[i].crypto, 0, sizeof(localDesc->streams[i].crypto)); restartInvite(); return true; } - } else if (params->avpfEnabled()) { + } else if (getParams()->avpfEnabled()) { if (i == 0) lInfo() << "Retrying CallSession [" << q << "] with AVP"; - params->enableAvpf(false); + getParams()->enableAvpf(false); restartInvite(); return true; } @@ -315,7 +311,7 @@ bool MediaSessionPrivate::failure () { } void MediaSessionPrivate::pausedByRemote () { - MediaSessionParams *newParams = new MediaSessionParams(*params); + MediaSessionParams *newParams = new MediaSessionParams(*getParams()); if (lp_config_get_int(linphone_core_get_config(core), "sip", "inactive_video_on_pause", 0)) newParams->setVideoDirection(LinphoneMediaDirectionInactive); acceptUpdate(newParams, LinphoneCallPausedByRemote, "Call paused by remote"); @@ -324,7 +320,7 @@ void MediaSessionPrivate::pausedByRemote () { void MediaSessionPrivate::remoteRinging () { L_Q(); /* Set privacy */ - q->getCurrentParams()->setPrivacy((LinphonePrivacyMask)op->get_privacy()); + getCurrentParams()->setPrivacy((LinphonePrivacyMask)op->get_privacy()); SalMediaDescription *md = op->get_final_media_description(); if (md) { /* Initialize the remote call params by invoking linphone_call_get_remote_params(). This is useful as the SDP may not be present in the 200Ok */ @@ -412,7 +408,7 @@ void MediaSessionPrivate::updating (bool isUpdate) { /* Refresh the local description, but in paused state, we don't change anything. */ if (!rmd && lp_config_get_int(linphone_core_get_config(core), "sip", "sdp_200_ack_follow_video_policy", 0)) { lInfo() << "Applying default policy for offering SDP on CallSession [" << q << "]"; - params = new MediaSessionParams(); + setParams(new MediaSessionParams()); params->initDefault(core); } makeLocalMediaDescription(); @@ -503,7 +499,7 @@ void MediaSessionPrivate::prepareStreamsForIceGathering (bool hasVideo) { if (hasVideo && videoStream && (videoStream->ms.state == MSStreamInitialized)) video_stream_prepare_video(videoStream); #endif - if (params->realtimeTextEnabled() && (textStream->ms.state == MSStreamInitialized)) + if (getParams()->realtimeTextEnabled() && (textStream->ms.state == MSStreamInitialized)) text_stream_prepare_text(textStream); } @@ -520,6 +516,12 @@ void MediaSessionPrivate::stopStreamsForIceGathering () { // ----------------------------------------------------------------------------- +void MediaSessionPrivate::setParams (MediaSessionParams *msp) { + if (params) + delete params; + params = msp; +} + MediaStream * MediaSessionPrivate::getMediaStream (LinphoneStreamType type) const { switch (type) { case LinphoneStreamTypeAudio: @@ -749,27 +751,27 @@ void MediaSessionPrivate::fixCallParams (SalMediaDescription *rmd) { } const MediaSessionParams *rcp = q->getRemoteParams(); if (rcp) { - if (params->audioEnabled() && !rcp->audioEnabled()) { + if (getParams()->audioEnabled() && !rcp->audioEnabled()) { lInfo() << "CallSession [" << q << "]: disabling audio in our call params because the remote doesn't want it"; - params->enableAudio(false); + getParams()->enableAudio(false); } - if (params->videoEnabled() && !rcp->videoEnabled()) { + if (getParams()->videoEnabled() && !rcp->videoEnabled()) { lInfo() << "CallSession [" << q << "]: disabling video in our call params because the remote doesn't want it"; - params->enableVideo(false); + getParams()->enableVideo(false); } - if (rcp->videoEnabled() && core->video_policy.automatically_accept && linphone_core_video_enabled(core) && !params->videoEnabled()) { + if (rcp->videoEnabled() && core->video_policy.automatically_accept && linphone_core_video_enabled(core) && !getParams()->videoEnabled()) { lInfo() << "CallSession [" << q << "]: re-enabling video in our call params because the remote wants it and the policy allows to automatically accept"; - params->enableVideo(true); + getParams()->enableVideo(true); } - if (rcp->realtimeTextEnabled() && !params->realtimeTextEnabled()) - params->enableRealtimeText(true); + if (rcp->realtimeTextEnabled() && !getParams()->realtimeTextEnabled()) + getParams()->enableRealtimeText(true); } } void MediaSessionPrivate::initializeParamsAccordingToIncomingCallParams () { CallSessionPrivate::initializeParamsAccordingToIncomingCallParams(); - currentParams->getPrivate()->setUpdateCallWhenIceCompleted(params->getPrivate()->getUpdateCallWhenIceCompleted()); - params->enableVideo(linphone_core_video_enabled(core) && core->video_policy.automatically_accept); + getCurrentParams()->getPrivate()->setUpdateCallWhenIceCompleted(getParams()->getPrivate()->getUpdateCallWhenIceCompleted()); + getParams()->enableVideo(linphone_core_video_enabled(core) && core->video_policy.automatically_accept); SalMediaDescription *md = op->get_remote_media_description(); if (md) { /* It is licit to receive an INVITE without SDP, in this case WE choose the media parameters according to policy */ @@ -793,19 +795,19 @@ void MediaSessionPrivate::initializeParamsAccordingToIncomingCallParams () { */ void MediaSessionPrivate::setCompatibleIncomingCallParams (SalMediaDescription *md) { /* Handle AVPF, SRTP and DTLS */ - params->enableAvpf(!!sal_media_description_has_avpf(md)); + getParams()->enableAvpf(!!sal_media_description_has_avpf(md)); if (destProxy) - params->setAvpfRrInterval(static_cast(linphone_proxy_config_get_avpf_rr_interval(destProxy) * 1000)); + getParams()->setAvpfRrInterval(static_cast(linphone_proxy_config_get_avpf_rr_interval(destProxy) * 1000)); else - params->setAvpfRrInterval(static_cast(linphone_core_get_avpf_rr_interval(core) * 1000)); + getParams()->setAvpfRrInterval(static_cast(linphone_core_get_avpf_rr_interval(core) * 1000)); if (sal_media_description_has_zrtp(md) && linphone_core_media_encryption_supported(core, LinphoneMediaEncryptionZRTP)) - params->setMediaEncryption(LinphoneMediaEncryptionZRTP); + getParams()->setMediaEncryption(LinphoneMediaEncryptionZRTP); else if (sal_media_description_has_dtls(md) && media_stream_dtls_supported()) - params->setMediaEncryption(LinphoneMediaEncryptionDTLS); + getParams()->setMediaEncryption(LinphoneMediaEncryptionDTLS); else if (sal_media_description_has_srtp(md) && ms_srtp_supported()) - params->setMediaEncryption(LinphoneMediaEncryptionSRTP); - else if (params->getMediaEncryption() != LinphoneMediaEncryptionZRTP) - params->setMediaEncryption(LinphoneMediaEncryptionNone); + getParams()->setMediaEncryption(LinphoneMediaEncryptionSRTP); + else if (getParams()->getMediaEncryption() != LinphoneMediaEncryptionZRTP) + getParams()->setMediaEncryption(LinphoneMediaEncryptionNone); /* In case of nat64, even ipv4 addresses are reachable from v6. Should be enhanced to manage stream by stream connectivity (I.E v6 or v4) */ /*if (!sal_media_description_has_ipv6(md)){ lInfo() << "The remote SDP doesn't seem to offer any IPv6 connectivity, so disabling IPv6 for this call"; @@ -905,9 +907,9 @@ MSWebCam * MediaSessionPrivate::getVideoDevice () const { // ----------------------------------------------------------------------------- void MediaSessionPrivate::fillMulticastMediaAddresses () { - if (params->audioMulticastEnabled()) + if (getParams()->audioMulticastEnabled()) mediaPorts[mainAudioStreamIndex].multicastIp = linphone_core_get_audio_multicast_addr(core); - if (params->videoMulticastEnabled()) + if (getParams()->videoMulticastEnabled()) mediaPorts[mainVideoStreamIndex].multicastIp = linphone_core_get_video_multicast_addr(core); } @@ -1142,7 +1144,6 @@ void MediaSessionPrivate::selectOutgoingIpVersion () { // ----------------------------------------------------------------------------- void MediaSessionPrivate::forceStreamsDirAccordingToState (SalMediaDescription *md) { - L_Q(); for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { SalStreamDescription *sd = &md->streams[i]; switch (state) { @@ -1159,9 +1160,9 @@ void MediaSessionPrivate::forceStreamsDirAccordingToState (SalMediaDescription * } /* Reflect the stream directions in the call params */ if (i == mainAudioStreamIndex) - q->getCurrentParams()->setAudioDirection(MediaSessionParamsPrivate::salStreamDirToMediaDirection(sd->dir)); + getCurrentParams()->setAudioDirection(MediaSessionParamsPrivate::salStreamDirToMediaDirection(sd->dir)); else if (i == mainVideoStreamIndex) - q->getCurrentParams()->setVideoDirection(MediaSessionParamsPrivate::salStreamDirToMediaDirection(sd->dir)); + getCurrentParams()->setVideoDirection(MediaSessionParamsPrivate::salStreamDirToMediaDirection(sd->dir)); } } @@ -1203,17 +1204,17 @@ void MediaSessionPrivate::makeLocalMediaDescription () { /* Multicast is only set in case of outgoing call */ if (direction == LinphoneCallOutgoing) { - if (params->audioMulticastEnabled()) { + if (getParams()->audioMulticastEnabled()) { md->streams[mainAudioStreamIndex].ttl = linphone_core_get_audio_multicast_ttl(core); md->streams[mainAudioStreamIndex].multicast_role = SalMulticastSender; } - if (params->videoMulticastEnabled()) { + if (getParams()->videoMulticastEnabled()) { md->streams[mainVideoStreamIndex].ttl = linphone_core_get_video_multicast_ttl(core); md->streams[mainVideoStreamIndex].multicast_role = SalMulticastSender; } } - params->getPrivate()->adaptToNetwork(core, pingTime); + getParams()->getPrivate()->adaptToNetwork(core, pingTime); string subject = q->getParams()->getSessionName(); if (!subject.empty()) @@ -1239,31 +1240,31 @@ void MediaSessionPrivate::makeLocalMediaDescription () { strncpy(md->username, linphone_address_get_username(addr), sizeof(md->username)); linphone_address_unref(addr); - int bandwidth = params->getPrivate()->getDownBandwidth(); + int bandwidth = getParams()->getPrivate()->getDownBandwidth(); if (bandwidth) md->bandwidth = bandwidth; else md->bandwidth = linphone_core_get_download_bandwidth(core); - SalCustomSdpAttribute *customSdpAttributes = params->getPrivate()->getCustomSdpAttributes(); + SalCustomSdpAttribute *customSdpAttributes = getParams()->getPrivate()->getCustomSdpAttributes(); if (customSdpAttributes) md->custom_sdp_attributes = sal_custom_sdp_attribute_clone(customSdpAttributes); PayloadTypeHandler pth(core); - bctbx_list_t *l = pth.makeCodecsList(SalAudio, params->getAudioBandwidthLimit(), -1, + bctbx_list_t *l = pth.makeCodecsList(SalAudio, getParams()->getAudioBandwidthLimit(), -1, oldMd ? oldMd->streams[mainAudioStreamIndex].already_assigned_payloads : nullptr); - if (l && params->audioEnabled()) { + if (l && getParams()->audioEnabled()) { strncpy(md->streams[mainAudioStreamIndex].rtp_addr, getPublicIpForStream(mainAudioStreamIndex).c_str(), sizeof(md->streams[mainAudioStreamIndex].rtp_addr)); strncpy(md->streams[mainAudioStreamIndex].rtcp_addr, getPublicIpForStream(mainAudioStreamIndex).c_str(), sizeof(md->streams[mainAudioStreamIndex].rtcp_addr)); strncpy(md->streams[mainAudioStreamIndex].name, "Audio", sizeof(md->streams[mainAudioStreamIndex].name) - 1); md->streams[mainAudioStreamIndex].rtp_port = mediaPorts[mainAudioStreamIndex].rtpPort; md->streams[mainAudioStreamIndex].rtcp_port = mediaPorts[mainAudioStreamIndex].rtcpPort; - md->streams[mainAudioStreamIndex].proto = params->getMediaProto(); - md->streams[mainAudioStreamIndex].dir = params->getPrivate()->getSalAudioDirection(); + md->streams[mainAudioStreamIndex].proto = getParams()->getMediaProto(); + md->streams[mainAudioStreamIndex].dir = getParams()->getPrivate()->getSalAudioDirection(); md->streams[mainAudioStreamIndex].type = SalAudio; md->streams[mainAudioStreamIndex].rtcp_mux = rtcpMux; - int downPtime = params->getPrivate()->getDownPtime(); + int downPtime = getParams()->getPrivate()->getDownPtime(); if (downPtime) md->streams[mainAudioStreamIndex].ptime = downPtime; else @@ -1284,19 +1285,19 @@ void MediaSessionPrivate::makeLocalMediaDescription () { if(l) l = bctbx_list_free_with_data(l, (bctbx_list_free_func)payload_type_destroy); } - SalCustomSdpAttribute *sdpMediaAttributes = params->getPrivate()->getCustomSdpMediaAttributes(LinphoneStreamTypeAudio); + SalCustomSdpAttribute *sdpMediaAttributes = getParams()->getPrivate()->getCustomSdpMediaAttributes(LinphoneStreamTypeAudio); if (sdpMediaAttributes) md->streams[mainAudioStreamIndex].custom_sdp_attributes = sal_custom_sdp_attribute_clone(sdpMediaAttributes); md->streams[mainVideoStreamIndex].proto = md->streams[mainAudioStreamIndex].proto; - md->streams[mainVideoStreamIndex].dir = params->getPrivate()->getSalVideoDirection(); + md->streams[mainVideoStreamIndex].dir = getParams()->getPrivate()->getSalVideoDirection(); md->streams[mainVideoStreamIndex].type = SalVideo; md->streams[mainVideoStreamIndex].rtcp_mux = rtcpMux; strncpy(md->streams[mainVideoStreamIndex].name, "Video", sizeof(md->streams[mainVideoStreamIndex].name) - 1); l = pth.makeCodecsList(SalVideo, 0, -1, oldMd ? oldMd->streams[mainVideoStreamIndex].already_assigned_payloads : nullptr); - if (l && params->videoEnabled()){ + if (l && getParams()->videoEnabled()){ strncpy(md->streams[mainVideoStreamIndex].rtp_addr, getPublicIpForStream(mainVideoStreamIndex).c_str(), sizeof(md->streams[mainVideoStreamIndex].rtp_addr)); strncpy(md->streams[mainVideoStreamIndex].rtcp_addr, getPublicIpForStream(mainVideoStreamIndex).c_str(), sizeof(md->streams[mainVideoStreamIndex].rtcp_addr)); md->streams[mainVideoStreamIndex].rtp_port = mediaPorts[mainVideoStreamIndex].rtpPort; @@ -1315,7 +1316,7 @@ void MediaSessionPrivate::makeLocalMediaDescription () { if(l) l = bctbx_list_free_with_data(l, (bctbx_list_free_func)payload_type_destroy); } - sdpMediaAttributes = params->getPrivate()->getCustomSdpMediaAttributes(LinphoneStreamTypeVideo); + sdpMediaAttributes = getParams()->getPrivate()->getCustomSdpMediaAttributes(LinphoneStreamTypeVideo); if (sdpMediaAttributes) md->streams[mainVideoStreamIndex].custom_sdp_attributes = sal_custom_sdp_attribute_clone(sdpMediaAttributes); @@ -1324,7 +1325,7 @@ void MediaSessionPrivate::makeLocalMediaDescription () { md->streams[mainTextStreamIndex].type = SalText; md->streams[mainTextStreamIndex].rtcp_mux = rtcpMux; strncpy(md->streams[mainTextStreamIndex].name, "Text", sizeof(md->streams[mainTextStreamIndex].name) - 1); - if (params->realtimeTextEnabled()) { + if (getParams()->realtimeTextEnabled()) { strncpy(md->streams[mainTextStreamIndex].rtp_addr, getPublicIpForStream(mainTextStreamIndex).c_str(), sizeof(md->streams[mainTextStreamIndex].rtp_addr)); strncpy(md->streams[mainTextStreamIndex].rtcp_addr, getPublicIpForStream(mainTextStreamIndex).c_str(), sizeof(md->streams[mainTextStreamIndex].rtcp_addr)); @@ -1345,7 +1346,7 @@ void MediaSessionPrivate::makeLocalMediaDescription () { lInfo() << "Don't put text stream on local offer for CallSession [" << q << "]"; md->streams[mainTextStreamIndex].dir = SalStreamInactive; } - sdpMediaAttributes = params->getPrivate()->getCustomSdpMediaAttributes(LinphoneStreamTypeText); + sdpMediaAttributes = getParams()->getPrivate()->getCustomSdpMediaAttributes(LinphoneStreamTypeText); if (sdpMediaAttributes) md->streams[mainTextStreamIndex].custom_sdp_attributes = sal_custom_sdp_attribute_clone(sdpMediaAttributes); @@ -1374,7 +1375,7 @@ void MediaSessionPrivate::makeLocalMediaDescription () { transferAlreadyAssignedPayloadTypes(oldMd, md); localDescChanged = sal_media_description_equals(md, oldMd); sal_media_description_unref(oldMd); - if (params->getPrivate()->getInternalCallUpdate()) { + if (getParams()->getPrivate()->getInternalCallUpdate()) { /* * An internal call update (ICE reINVITE) is not expected to modify the actual media stream parameters. * However, the localDesc may change between first INVITE and ICE reINVITE, for example if the remote party has declined a video stream. @@ -1437,17 +1438,17 @@ void MediaSessionPrivate::setupRtcpFb (SalMediaDescription *md) { continue; md->streams[i].rtcp_fb.generic_nack_enabled = !!lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_fb_generic_nack_enabled", 0); md->streams[i].rtcp_fb.tmmbr_enabled = !!lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_fb_tmmbr_enabled", 1); - md->streams[i].implicit_rtcp_fb = params->getPrivate()->implicitRtcpFbEnabled(); + md->streams[i].implicit_rtcp_fb = getParams()->getPrivate()->implicitRtcpFbEnabled(); for (const bctbx_list_t *it = md->streams[i].payloads; it != nullptr; it = bctbx_list_next(it)) { OrtpPayloadType *pt = reinterpret_cast(bctbx_list_get_data(it)); PayloadTypeAvpfParams avpf_params; - if (!params->avpfEnabled() && !params->getPrivate()->implicitRtcpFbEnabled()) { + if (!getParams()->avpfEnabled() && !getParams()->getPrivate()->implicitRtcpFbEnabled()) { payload_type_unset_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); memset(&avpf_params, 0, sizeof(avpf_params)); } else { payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); avpf_params = payload_type_get_avpf_params(pt); - avpf_params.trr_interval = params->getAvpfRrInterval(); + avpf_params.trr_interval = getParams()->getAvpfRrInterval(); } payload_type_set_avpf_params(pt, avpf_params); } @@ -1487,7 +1488,7 @@ void MediaSessionPrivate::setupZrtpHash (SalMediaDescription *md) { if (sessions[i].zrtp_context) { ms_zrtp_getHelloHash(sessions[i].zrtp_context, md->streams[i].zrtphash, 128); /* Turn on the flag to use it if ZRTP is set */ - md->streams[i].haveZrtpHash = (params->getMediaEncryption() == LinphoneMediaEncryptionZRTP); + md->streams[i].haveZrtpHash = (getParams()->getMediaEncryption() == LinphoneMediaEncryptionZRTP); } else md->streams[i].haveZrtpHash = 0; } @@ -1538,8 +1539,8 @@ SalMulticastRole MediaSessionPrivate::getMulticastRole (SalStreamType type) { SalMediaDescription *remoteDesc = op->get_remote_media_description(); if (!localDesc && !remoteDesc && (direction == LinphoneCallOutgoing)) { /* Well using call dir */ - if (((type == SalAudio) && params->audioMulticastEnabled()) - || ((type == SalVideo) && params->videoMulticastEnabled())) + if (((type == SalAudio) && getParams()->audioMulticastEnabled()) + || ((type == SalVideo) && getParams()->videoMulticastEnabled())) multicastRole = SalMulticastSender; } else if (localDesc && (!remoteDesc || op->is_offerer())) { streamDesc = sal_media_description_find_best_stream(localDesc, type); @@ -1602,9 +1603,9 @@ void MediaSessionPrivate::setDtlsFingerprintOnAllStreams () { } void MediaSessionPrivate::setupDtlsParams (MediaStream *ms) { - if (params->getMediaEncryption() == LinphoneMediaEncryptionDTLS) { - MSDtlsSrtpParams params; - memset(¶ms, 0, sizeof(MSDtlsSrtpParams)); + if (getParams()->getMediaEncryption() == LinphoneMediaEncryptionDTLS) { + MSDtlsSrtpParams dtlsParams; + memset(&dtlsParams, 0, sizeof(MSDtlsSrtpParams)); /* TODO : search for a certificate with CNAME=sip uri(retrieved from variable me) or default : linphone-dtls-default-identity */ /* This will parse the directory to find a matching fingerprint or generate it if not found */ /* returned string must be freed */ @@ -1618,10 +1619,10 @@ void MediaSessionPrivate::setupDtlsParams (MediaStream *ms) { ms_free(fingerprint); } if (key && certificate) { - params.pem_certificate = certificate; - params.pem_pkey = key; - params.role = MSDtlsSrtpRoleUnset; /* Default is unset, then check if we have a result SalMediaDescription */ - media_stream_enable_dtls(ms, ¶ms); + dtlsParams.pem_certificate = certificate; + dtlsParams.pem_pkey = key; + dtlsParams.role = MSDtlsSrtpRoleUnset; /* Default is unset, then check if we have a result SalMediaDescription */ + media_stream_enable_dtls(ms, &dtlsParams); ms_free(certificate); ms_free(key); } else { @@ -1758,9 +1759,9 @@ int MediaSessionPrivate::getIdealAudioBandwidth (const SalMediaDescription *md, } int uploadBandwidth = 0; bool forced = false; - if (params->getPrivate()->getUpBandwidth() > 0) { + if (getParams()->getPrivate()->getUpBandwidth() > 0) { forced = true; - uploadBandwidth = params->getPrivate()->getUpBandwidth(); + uploadBandwidth = getParams()->getPrivate()->getUpBandwidth(); } else uploadBandwidth = linphone_core_get_upload_bandwidth(core); uploadBandwidth = PayloadTypeHandler::getMinBandwidth(uploadBandwidth, remoteBandwidth); @@ -1810,7 +1811,7 @@ RtpProfile * MediaSessionPrivate::makeProfile (const SalMediaDescription *md, co if (desc->type == SalAudio) { updateAllocatedAudioBandwidth(pt, bandwidth); bandwidth = audioBandwidth; - upPtime = params->getPrivate()->getUpPtime(); + upPtime = getParams()->getPrivate()->getUpPtime(); if (!upPtime) upPtime = linphone_core_get_upload_ptime(core); } @@ -2073,7 +2074,7 @@ void MediaSessionPrivate::handleIceEvents (OrtpEvent *ev) { if (iceAgent->hasCompletedCheckList()) { /* At least one ICE session has succeeded, so perform a call update */ if (iceAgent->isControlling() && q->getCurrentParams()->getPrivate()->getUpdateCallWhenIceCompleted()) { - MediaSessionParams *newParams = new MediaSessionParams(*params); + MediaSessionParams *newParams = new MediaSessionParams(*getParams()); newParams->getPrivate()->setInternalCallUpdate(true); q->update(newParams); } @@ -2113,7 +2114,7 @@ void MediaSessionPrivate::handleIceEvents (OrtpEvent *ev) { } } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) { iceAgent->restartSession(IR_Controlling); - q->update(currentParams); + q->update(getCurrentParams()); } } @@ -2548,8 +2549,8 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool const char *rtpAddr = (stream->rtp_addr[0] != '\0') ? stream->rtp_addr : resultDesc->addr; bool isMulticast = !!ms_is_multicast(rtpAddr); bool ok = true; - currentParams->getPrivate()->setUsedAudioCodec(rtp_profile_get_payload(audioProfile, usedPt)); - currentParams->enableAudio(true); + getCurrentParams()->getPrivate()->setUsedAudioCodec(rtp_profile_get_payload(audioProfile, usedPt)); + getCurrentParams()->enableAudio(true); MSSndCard *playcard = core->sound_conf.lsd_card ? core->sound_conf.lsd_card : core->sound_conf.play_sndcard; if (!playcard) lWarning() << "No card defined for playback!"; @@ -2583,7 +2584,7 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool if (core->use_files || (useRtpIo && !useRtpIoEnableLocalOutput)) { captcard = playcard = nullptr; } - if (params->getPrivate()->getInConference()) { + if (getParams()->getPrivate()->getInConference()) { /* First create the graph without soundcard resources */ captcard = playcard = nullptr; } @@ -2605,9 +2606,9 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool if (captcard && (stream->max_rate > 0)) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate); rtp_session_enable_rtcp_mux(audioStream->ms.sessions.rtp_session, stream->rtcp_mux); - if (!params->getPrivate()->getInConference() && !params->getRecordFilePath().empty()) { - audio_stream_mixed_record_open(audioStream, params->getRecordFilePath().c_str()); - currentParams->setRecordFilePath(params->getRecordFilePath()); + if (!getParams()->getPrivate()->getInConference() && !getParams()->getRecordFilePath().empty()) { + audio_stream_mixed_record_open(audioStream, getParams()->getRecordFilePath().c_str()); + getCurrentParams()->setRecordFilePath(getParams()->getRecordFilePath()); } /* Valid local tags are > 0 */ if (sal_stream_description_has_srtp(stream)) { @@ -2621,7 +2622,7 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool } configureRtpSessionForRtcpFb(stream); configureRtpSessionForRtcpXr(SalAudio); - configureAdaptiveRateControl(&audioStream->ms, currentParams->getUsedAudioCodec(), videoWillBeUsed); + configureAdaptiveRateControl(&audioStream->ms, getCurrentParams()->getUsedAudioCodec(), videoWillBeUsed); if (isMulticast) rtp_session_set_multicast_ttl(audioStream->ms.sessions.rtp_session, stream->ttl); MSMediaStreamIO io = MS_MEDIA_STREAM_IO_INITIALIZER; @@ -2677,20 +2678,20 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool setup_ring_player(lc,call); } #endif - if (params->getPrivate()->getInConference() && core->conf_ctx) { + if (getParams()->getPrivate()->getInConference() && core->conf_ctx) { /* Transform the graph to connect it to the conference filter */ #if 0 bool mute = (stream->dir == SalStreamRecvOnly); linphone_conference_on_call_stream_starting(core->conf_ctx, call, mute); #endif } - currentParams->getPrivate()->setInConference(params->getPrivate()->getInConference()); - currentParams->enableLowBandwidth(params->lowBandwidthEnabled()); + getCurrentParams()->getPrivate()->setInConference(getParams()->getPrivate()->getInConference()); + getCurrentParams()->enableLowBandwidth(getParams()->lowBandwidthEnabled()); /* Start ZRTP engine if needed : set here or remote have a zrtp-hash attribute */ SalMediaDescription *remote = op->get_remote_media_description(); const SalStreamDescription *remoteStream = sal_media_description_find_best_stream(remote, SalAudio); if (linphone_core_media_encryption_supported(core, LinphoneMediaEncryptionZRTP) - && ((params->getMediaEncryption() == LinphoneMediaEncryptionZRTP) || (remoteStream->haveZrtpHash == 1))) { + && ((getParams()->getMediaEncryption() == LinphoneMediaEncryptionZRTP) || (remoteStream->haveZrtpHash == 1))) { audio_stream_start_zrtp(audioStream); if (remoteStream->haveZrtpHash == 1) { int retval = ms_zrtp_setPeerHelloHash(audioStream->ms.sessions.zrtp_context, (uint8_t *)remoteStream->zrtphash, strlen((const char *)(remoteStream->zrtphash))); @@ -2711,7 +2712,7 @@ void MediaSessionPrivate::startStreams (LinphoneCallState targetState) { } BCTBX_NO_BREAK; case LinphoneCallOutgoingEarlyMedia: - if (!params->earlyMediaSendingEnabled()) + if (!getParams()->earlyMediaSendingEnabled()) allMuted = true; break; default: @@ -2720,9 +2721,9 @@ void MediaSessionPrivate::startStreams (LinphoneCallState targetState) { break; } - currentParams->getPrivate()->setUsedAudioCodec(nullptr); - currentParams->getPrivate()->setUsedVideoCodec(nullptr); - currentParams->getPrivate()->setUsedRealtimeTextCodec(nullptr); + getCurrentParams()->getPrivate()->setUsedAudioCodec(nullptr); + getCurrentParams()->getPrivate()->setUsedVideoCodec(nullptr); + getCurrentParams()->getPrivate()->setUsedRealtimeTextCodec(nullptr); if (!audioStream && !videoStream) { lFatal() << "startStreams() called without prior init!"; @@ -2745,19 +2746,19 @@ void MediaSessionPrivate::startStreams (LinphoneCallState targetState) { #endif lInfo() << "startStreams() CallSession=[" << q << "] local upload_bandwidth=[" << linphone_core_get_upload_bandwidth(core) << "] kbit/s; local download_bandwidth=[" << linphone_core_get_download_bandwidth(core) << "] kbit/s"; - currentParams->enableAudio(false); + getCurrentParams()->enableAudio(false); if (audioStream) startAudioStream(targetState, videoWillBeUsed); else lWarning() << "startStreams(): no audio stream!"; - currentParams->enableVideo(false); + getCurrentParams()->enableVideo(false); if (videoStream) { if (audioStream) audio_stream_link_video(audioStream, videoStream); startVideoStream(targetState); } /* The on-hold file is to be played once both audio and video are ready */ - if (!onHoldFile.empty() && !params->getPrivate()->getInConference() && audioStream) { + if (!onHoldFile.empty() && !getParams()->getPrivate()->getInConference() && audioStream) { MSFilter *player = audio_stream_open_remote_play(audioStream, onHoldFile.c_str()); if (player) { int pauseTime = 500; @@ -2766,13 +2767,13 @@ void MediaSessionPrivate::startStreams (LinphoneCallState targetState) { } } upBandwidth = linphone_core_get_upload_bandwidth(core); - if (params->realtimeTextEnabled()) + if (getParams()->realtimeTextEnabled()) startTextStream(); setDtlsFingerprintOnAllStreams(); if (!iceAgent->hasCompleted()) { - if (params->getMediaEncryption() == LinphoneMediaEncryptionDTLS) { - currentParams->getPrivate()->setUpdateCallWhenIceCompleted(false); + if (getParams()->getMediaEncryption() == LinphoneMediaEncryptionDTLS) { + getCurrentParams()->getPrivate()->setUpdateCallWhenIceCompleted(false); lInfo() << "Disabling update call when ice completed on call [" << q << "]"; } iceAgent->startConnectivityChecks(); @@ -2794,8 +2795,8 @@ void MediaSessionPrivate::startTextStream () { if (usedPt == -1) lWarning() << "No text stream accepted"; else { - currentParams->getPrivate()->setUsedRealtimeTextCodec(rtp_profile_get_payload(textProfile, usedPt)); - currentParams->enableRealtimeText(true); + getCurrentParams()->getPrivate()->setUsedRealtimeTextCodec(rtp_profile_get_payload(textProfile, usedPt)); + getCurrentParams()->enableRealtimeText(true); if (sal_stream_description_has_srtp(tstream)) { int cryptoIdx = findCryptoIndexFromTag(localStreamDesc->crypto, static_cast(tstream->crypto_local_tag)); if (cryptoIdx >= 0) { @@ -2838,8 +2839,8 @@ void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { if (usedPt == -1) lWarning() << "No video stream accepted"; else { - currentParams->getPrivate()->setUsedVideoCodec(rtp_profile_get_payload(videoProfile, usedPt)); - currentParams->enableVideo(true); + getCurrentParams()->getPrivate()->setUsedVideoCodec(rtp_profile_get_payload(videoProfile, usedPt)); + getCurrentParams()->enableVideo(true); rtp_session_enable_rtcp_mux(videoStream->ms.sessions.rtp_session, vstream->rtcp_mux); if (core->video_conf.preview_vsize.width != 0) video_stream_set_preview_size(videoStream, core->video_conf.preview_vsize); @@ -2897,7 +2898,7 @@ void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { } configureRtpSessionForRtcpFb(vstream); configureRtpSessionForRtcpXr(SalVideo); - configureAdaptiveRateControl(&videoStream->ms, currentParams->getUsedVideoCodec(), true); + configureAdaptiveRateControl(&videoStream->ms, getCurrentParams()->getUsedVideoCodec(), true); log->video_enabled = true; video_stream_set_direction(videoStream, dir); lInfo() << "startVideoStream: device_rotation=" << core->device_rotation; @@ -2940,7 +2941,7 @@ void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { /* Start ZRTP engine if needed : set here or remote have a zrtp-hash attribute */ SalMediaDescription *remote = op->get_remote_media_description(); const SalStreamDescription *remoteStream = sal_media_description_find_best_stream(remote, SalVideo); - if ((params->getMediaEncryption() == LinphoneMediaEncryptionZRTP) || (remoteStream->haveZrtpHash == 1)) { + if ((getParams()->getMediaEncryption() == LinphoneMediaEncryptionZRTP) || (remoteStream->haveZrtpHash == 1)) { /* Audio stream is already encrypted and video stream is active */ if (media_stream_secured(&audioStream->ms) && (media_stream_get_state(&videoStream->ms) == MSStreamStarted)) { video_stream_start_zrtp(videoStream); @@ -2964,7 +2965,6 @@ void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { } void MediaSessionPrivate::stopAudioStream () { - L_Q(); if (audioStream) { updateReportingMediaInfo(LINPHONE_CALL_STATS_AUDIO); media_stream_reclaim_sessions(&audioStream->ms, &sessions[mainAudioStreamIndex]); @@ -2993,7 +2993,7 @@ void MediaSessionPrivate::stopAudioStream () { ortp_ev_queue_destroy(audioStreamEvQueue); audioStreamEvQueue = nullptr; - q->getCurrentParams()->getPrivate()->setUsedAudioCodec(nullptr); + getCurrentParams()->getPrivate()->setUsedAudioCodec(nullptr); } } @@ -3036,7 +3036,6 @@ void MediaSessionPrivate::stopStreams () { } void MediaSessionPrivate::stopTextStream () { - L_Q(); if (textStream) { updateReportingMediaInfo(LINPHONE_CALL_STATS_TEXT); media_stream_reclaim_sessions(&textStream->ms, &sessions[mainTextStreamIndex]); @@ -3049,13 +3048,12 @@ void MediaSessionPrivate::stopTextStream () { ortp_ev_queue_flush(textStreamEvQueue); ortp_ev_queue_destroy(textStreamEvQueue); textStreamEvQueue = nullptr; - q->getCurrentParams()->getPrivate()->setUsedRealtimeTextCodec(nullptr); + getCurrentParams()->getPrivate()->setUsedRealtimeTextCodec(nullptr); } } void MediaSessionPrivate::stopVideoStream () { #ifdef VIDEO_ENABLED - L_Q(); if (videoStream) { updateReportingMediaInfo(LINPHONE_CALL_STATS_VIDEO); media_stream_reclaim_sessions(&videoStream->ms, &sessions[mainVideoStreamIndex]); @@ -3069,7 +3067,7 @@ void MediaSessionPrivate::stopVideoStream () { ortp_ev_queue_flush(videoStreamEvQueue); ortp_ev_queue_destroy(videoStreamEvQueue); videoStreamEvQueue = nullptr; - q->getCurrentParams()->getPrivate()->setUsedVideoCodec(nullptr); + getCurrentParams()->getPrivate()->setUsedVideoCodec(nullptr); } #endif } @@ -3199,7 +3197,7 @@ void MediaSessionPrivate::updateStreams (SalMediaDescription *newMd, LinphoneCal initializeStreams(); } - if (params->earlyMediaSendingEnabled() && (state == LinphoneCallOutgoingEarlyMedia)) + if (getParams()->earlyMediaSendingEnabled() && (state == LinphoneCallOutgoingEarlyMedia)) prepareEarlyMediaForking(); startStreams(targetState); if ((state == LinphoneCallPausing) && pausedByApp && (bctbx_list_size(core->calls) == 1)) @@ -3301,7 +3299,7 @@ void MediaSessionPrivate::audioStreamEncryptionChanged (bool encrypted) { #ifdef VIDEO_ENABLED L_Q(); /* Enable video encryption */ - if ((params->getMediaEncryption() == LinphoneMediaEncryptionZRTP) && q->getCurrentParams()->videoEnabled()) { + if ((getParams()->getMediaEncryption() == LinphoneMediaEncryptionZRTP) && q->getCurrentParams()->videoEnabled()) { lInfo() << "Trying to start ZRTP encryption on video stream"; video_stream_start_zrtp(videoStream); } @@ -3332,15 +3330,15 @@ unsigned int MediaSessionPrivate::getNbActiveStreams () const { bool MediaSessionPrivate::isEncryptionMandatory () const { L_Q(); - if (params->getMediaEncryption() == LinphoneMediaEncryptionDTLS) { + if (getParams()->getMediaEncryption() == LinphoneMediaEncryptionDTLS) { lInfo() << "Forced encryption mandatory on CallSession [" << q << "] due to SRTP-DTLS"; return true; } - return params->mandatoryMediaEncryptionEnabled(); + return getParams()->mandatoryMediaEncryptionEnabled(); } int MediaSessionPrivate::mediaParametersChanged (SalMediaDescription *oldMd, SalMediaDescription *newMd) { - if (params->getPrivate()->getInConference() != currentParams->getPrivate()->getInConference()) + if (getParams()->getPrivate()->getInConference() != getCurrentParams()->getPrivate()->getInConference()) return SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION; if (upBandwidth != linphone_core_get_upload_bandwidth(core)) return SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION; @@ -3362,16 +3360,16 @@ void MediaSessionPrivate::propagateEncryptionChanged () { L_Q(); if (!allStreamsEncrypted()) { lInfo() << "Some streams are not encrypted"; - q->getCurrentParams()->setMediaEncryption(LinphoneMediaEncryptionNone); + getCurrentParams()->setMediaEncryption(LinphoneMediaEncryptionNone); if (listener) listener->onEncryptionChanged(q->getSharedFromThis(), false, authToken); } else { if (!authToken.empty()) { /* ZRTP only is using auth_token */ - q->getCurrentParams()->setMediaEncryption(LinphoneMediaEncryptionZRTP); + getCurrentParams()->setMediaEncryption(LinphoneMediaEncryptionZRTP); } else { /* Otherwise it must be DTLS as SDES doesn't go through this function */ - q->getCurrentParams()->setMediaEncryption(LinphoneMediaEncryptionDTLS); + getCurrentParams()->setMediaEncryption(LinphoneMediaEncryptionDTLS); } lInfo() << "All streams are encrypted, key exchanged using " << ((q->getCurrentParams()->getMediaEncryption() == LinphoneMediaEncryptionZRTP) ? "ZRTP" @@ -3728,7 +3726,7 @@ LinphoneStatus MediaSessionPrivate::startAcceptUpdate (LinphoneCallState nextSta LinphoneStatus MediaSessionPrivate::startUpdate (const string &subject) { fillMulticastMediaAddresses(); - if (!params->getPrivate()->getNoUserConsent()) + if (!getParams()->getPrivate()->getNoUserConsent()) makeLocalMediaDescription(); if (!core->sip_conf.sdp_200_ack) op->set_local_media_description(localDesc); @@ -3769,21 +3767,21 @@ void MediaSessionPrivate::updateCurrentParams () const { CallSessionPrivate::updateCurrentParams(); LinphoneVideoDefinition *vdef = linphone_video_definition_new(MS_VIDEO_SIZE_UNKNOWN_W, MS_VIDEO_SIZE_UNKNOWN_H, nullptr); - currentParams->getPrivate()->setSentVideoDefinition(vdef); - currentParams->getPrivate()->setReceivedVideoDefinition(vdef); + getCurrentParams()->getPrivate()->setSentVideoDefinition(vdef); + getCurrentParams()->getPrivate()->setReceivedVideoDefinition(vdef); linphone_video_definition_unref(vdef); #ifdef VIDEO_ENABLED if (videoStream) { MSVideoSize vsize = video_stream_get_sent_video_size(videoStream); vdef = linphone_video_definition_new(static_cast(vsize.width), static_cast(vsize.height), nullptr); - currentParams->getPrivate()->setSentVideoDefinition(vdef); + getCurrentParams()->getPrivate()->setSentVideoDefinition(vdef); linphone_video_definition_unref(vdef); vsize = video_stream_get_received_video_size(videoStream); vdef = linphone_video_definition_new(static_cast(vsize.width), static_cast(vsize.height), nullptr); - currentParams->getPrivate()->setReceivedVideoDefinition(vdef); + getCurrentParams()->getPrivate()->setReceivedVideoDefinition(vdef); linphone_video_definition_unref(vdef); - currentParams->getPrivate()->setSentFps(video_stream_get_sent_framerate(videoStream)); - currentParams->getPrivate()->setReceivedFps(video_stream_get_received_framerate(videoStream)); + getCurrentParams()->getPrivate()->setSentFps(video_stream_get_sent_framerate(videoStream)); + getCurrentParams()->getPrivate()->setReceivedFps(video_stream_get_received_framerate(videoStream)); } #endif @@ -3796,16 +3794,16 @@ void MediaSessionPrivate::updateCurrentParams () const { * Typically there can be inactive streams for which the media layer has no idea of whether they are encrypted or not. */ - switch (params->getMediaEncryption()) { + switch (getParams()->getMediaEncryption()) { case LinphoneMediaEncryptionZRTP: if (atLeastOneStreamStarted()) { if (allStreamsEncrypted() && !authToken.empty()) - currentParams->setMediaEncryption(LinphoneMediaEncryptionZRTP); + getCurrentParams()->setMediaEncryption(LinphoneMediaEncryptionZRTP); else { /* To avoid too many traces */ - lDebug() << "Encryption was requested to be " << linphone_media_encryption_to_string(params->getMediaEncryption()) + lDebug() << "Encryption was requested to be " << linphone_media_encryption_to_string(getParams()->getMediaEncryption()) << ", but isn't effective (allStreamsEncrypted=" << allStreamsEncrypted() << ", auth_token=" << authToken << ")"; - currentParams->setMediaEncryption(LinphoneMediaEncryptionNone); + getCurrentParams()->setMediaEncryption(LinphoneMediaEncryptionNone); } } /* else don't update the state if all streams are shutdown */ break; @@ -3813,53 +3811,53 @@ void MediaSessionPrivate::updateCurrentParams () const { case LinphoneMediaEncryptionSRTP: if (atLeastOneStreamStarted()) { if ((getNbActiveStreams() == 0) || allStreamsEncrypted()) - currentParams->setMediaEncryption(params->getMediaEncryption()); + getCurrentParams()->setMediaEncryption(getParams()->getMediaEncryption()); else { /* To avoid to many traces */ - lDebug() << "Encryption was requested to be " << linphone_media_encryption_to_string(params->getMediaEncryption()) + lDebug() << "Encryption was requested to be " << linphone_media_encryption_to_string(getParams()->getMediaEncryption()) << ", but isn't effective (allStreamsEncrypted=" << allStreamsEncrypted() << ")"; - currentParams->setMediaEncryption(LinphoneMediaEncryptionNone); + getCurrentParams()->setMediaEncryption(LinphoneMediaEncryptionNone); } } /* else don't update the state if all streams are shutdown */ break; case LinphoneMediaEncryptionNone: /* Check if we actually switched to ZRTP */ if (atLeastOneStreamStarted() && allStreamsEncrypted() && !authToken.empty()) - currentParams->setMediaEncryption(LinphoneMediaEncryptionZRTP); + getCurrentParams()->setMediaEncryption(LinphoneMediaEncryptionZRTP); else - currentParams->setMediaEncryption(LinphoneMediaEncryptionNone); + getCurrentParams()->setMediaEncryption(LinphoneMediaEncryptionNone); break; } SalMediaDescription *md = resultDesc; - currentParams->enableAvpf(allStreamsAvpfEnabled() && sal_media_description_has_avpf(md)); - if (currentParams->avpfEnabled()) - currentParams->setAvpfRrInterval(getAvpfRrInterval()); + getCurrentParams()->enableAvpf(allStreamsAvpfEnabled() && sal_media_description_has_avpf(md)); + if (getCurrentParams()->avpfEnabled()) + getCurrentParams()->setAvpfRrInterval(getAvpfRrInterval()); else - currentParams->setAvpfRrInterval(0); + getCurrentParams()->setAvpfRrInterval(0); if (md) { SalStreamDescription *sd = sal_media_description_find_best_stream(md, SalAudio); - currentParams->setAudioDirection(sd ? MediaSessionParamsPrivate::salStreamDirToMediaDirection(sd->dir) : LinphoneMediaDirectionInactive); - if (currentParams->getAudioDirection() != LinphoneMediaDirectionInactive) { + getCurrentParams()->setAudioDirection(sd ? MediaSessionParamsPrivate::salStreamDirToMediaDirection(sd->dir) : LinphoneMediaDirectionInactive); + if (getCurrentParams()->getAudioDirection() != LinphoneMediaDirectionInactive) { const char *rtpAddr = (sd->rtp_addr[0] != '\0') ? sd->rtp_addr : md->addr; - currentParams->enableAudioMulticast(!!ms_is_multicast(rtpAddr)); + getCurrentParams()->enableAudioMulticast(!!ms_is_multicast(rtpAddr)); } else - currentParams->enableAudioMulticast(false); + getCurrentParams()->enableAudioMulticast(false); sd = sal_media_description_find_best_stream(md, SalVideo); - currentParams->getPrivate()->enableImplicitRtcpFb(sd && sal_stream_description_has_implicit_avpf(sd)); - currentParams->setVideoDirection(sd ? MediaSessionParamsPrivate::salStreamDirToMediaDirection(sd->dir) : LinphoneMediaDirectionInactive); - if (currentParams->getVideoDirection() != LinphoneMediaDirectionInactive) { + getCurrentParams()->getPrivate()->enableImplicitRtcpFb(sd && sal_stream_description_has_implicit_avpf(sd)); + getCurrentParams()->setVideoDirection(sd ? MediaSessionParamsPrivate::salStreamDirToMediaDirection(sd->dir) : LinphoneMediaDirectionInactive); + if (getCurrentParams()->getVideoDirection() != LinphoneMediaDirectionInactive) { const char *rtpAddr = (sd->rtp_addr[0] != '\0') ? sd->rtp_addr : md->addr; - currentParams->enableVideoMulticast(!!ms_is_multicast(rtpAddr)); + getCurrentParams()->enableVideoMulticast(!!ms_is_multicast(rtpAddr)); } else - currentParams->enableVideoMulticast(false); + getCurrentParams()->enableVideoMulticast(false); } } // ----------------------------------------------------------------------------- -void MediaSessionPrivate::accept (const MediaSessionParams *csp) { - if (csp) { - params = new MediaSessionParams(*csp); +void MediaSessionPrivate::accept (const MediaSessionParams *msp) { + if (msp) { + setParams(new MediaSessionParams(*msp)); iceAgent->prepare(localDesc, true); makeLocalMediaDescription(); op->set_local_media_description(localDesc); @@ -3882,7 +3880,7 @@ void MediaSessionPrivate::accept (const MediaSessionParams *csp) { } #endif - CallSessionPrivate::accept(params); + CallSessionPrivate::accept(nullptr); SalMediaDescription *newMd = op->get_final_media_description(); iceAgent->stopIceForInactiveStreams(newMd); @@ -3905,21 +3903,21 @@ LinphoneStatus MediaSessionPrivate::acceptUpdate (const CallSessionParams *csp, return 0; } if (csp) - params = new MediaSessionParams(*static_cast(csp)); + setParams(new MediaSessionParams(*static_cast(csp))); else { if (!op->is_offerer()) { /* Reset call params for multicast because this param is only relevant when offering */ - params->enableAudioMulticast(false); - params->enableVideoMulticast(false); + getParams()->enableAudioMulticast(false); + getParams()->enableVideoMulticast(false); } } - if (params->videoEnabled() && !linphone_core_video_enabled(core)) { + if (getParams()->videoEnabled() && !linphone_core_video_enabled(core)) { lWarning() << "Requested video but video support is globally disabled. Refusing video"; - params->enableVideo(false); + getParams()->enableVideo(false); } if (q->getCurrentParams()->getPrivate()->getInConference()) { lWarning() << "Video isn't supported in conference"; - params->enableVideo(false); + getParams()->enableVideo(false); } /* Update multicast params according to call params */ fillMulticastMediaAddresses(); @@ -4065,10 +4063,10 @@ LinphoneStatus MediaSession::acceptEarlyMedia (const MediaSessionParams *msp) { d->setContactOp(); /* If parameters are passed, update the media description */ if (msp) { - d->params = new MediaSessionParams(*msp); + d->setParams(new MediaSessionParams(*msp)); d->makeLocalMediaDescription(); d->op->set_local_media_description(d->localDesc); - d->op->set_sent_custom_header(d->params->getPrivate()->getCustomHeaders()); + d->op->set_sent_custom_header(d->getParams()->getPrivate()->getCustomHeaders()); } d->op->notify_ringing(true); d->setState(LinphoneCallIncomingEarlyMedia, "Incoming call early media"); @@ -4102,7 +4100,7 @@ void MediaSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cf if (direction == LinphoneCallOutgoing) { d->selectOutgoingIpVersion(); d->getLocalIp(to); - getCurrentParams()->getPrivate()->setUpdateCallWhenIceCompleted(d->params->getPrivate()->getUpdateCallWhenIceCompleted()); + d->getCurrentParams()->getPrivate()->setUpdateCallWhenIceCompleted(d->getParams()->getPrivate()->getUpdateCallWhenIceCompleted()); d->fillMulticastMediaAddresses(); if (d->natPolicy && linphone_nat_policy_ice_enabled(d->natPolicy)) d->iceAgent->checkSession(IR_Controlling, false); @@ -4120,7 +4118,7 @@ void MediaSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cf Address cleanedFrom = from; cleanedFrom.clean(); d->getLocalIp(cleanedFrom); - d->params = new MediaSessionParams(); + d->setParams(new MediaSessionParams()); d->params->initDefault(d->core); d->initializeParamsAccordingToIncomingCallParams(); SalMediaDescription *md = d->op->get_remote_media_description(); @@ -4191,7 +4189,7 @@ LinphoneStatus MediaSession::resume () { lWarning() << "we cannot resume a call that has not been established and paused before"; return -1; } - if (!d->params->getPrivate()->getInConference()) { + if (!d->getParams()->getPrivate()->getInConference()) { if (linphone_core_sound_resources_locked(d->core)) { lWarning() << "Cannot resume MediaSession " << this << " because another call is locking the sound resources"; return -1; @@ -4214,12 +4212,12 @@ LinphoneStatus MediaSession::resume () { else d->op->set_local_media_description(nullptr); string subject = "Call resuming"; - if (d->params->getPrivate()->getInConference() && !getCurrentParams()->getPrivate()->getInConference()) + if (d->getParams()->getPrivate()->getInConference() && !getCurrentParams()->getPrivate()->getInConference()) subject = "Conference"; if (d->op->update(subject.c_str(), false) != 0) return -1; d->setState(LinphoneCallResuming,"Resuming"); - if (!d->params->getPrivate()->getInConference() && d->listener) + if (!d->getParams()->getPrivate()->getInConference() && d->listener) d->listener->onSetCurrentSession(getSharedFromThis()); if (d->core->sip_conf.sdp_200_ack) { /* We are NOT offering, set local media description after sending the call so that we are ready to @@ -4232,8 +4230,8 @@ LinphoneStatus MediaSession::resume () { void MediaSession::sendVfuRequest () { #ifdef VIDEO_ENABLED L_D(); - MediaSessionParams *currentParams = getCurrentParams(); - if ((currentParams->avpfEnabled() || currentParams->getPrivate()->implicitRtcpFbEnabled()) + MediaSessionParams *curParams = getCurrentParams(); + if ((curParams->avpfEnabled() || curParams->getPrivate()->implicitRtcpFbEnabled()) && d->videoStream && media_stream_get_state(&d->videoStream->ms) == MSStreamStarted) { // || sal_media_description_has_implicit_avpf((const SalMediaDescription *)call->resultdesc) lInfo() << "Request Full Intra Request on CallSession [" << this << "]"; video_stream_send_fir(d->videoStream); @@ -4301,18 +4299,18 @@ int MediaSession::startInvite (const Address *destination, const string &subject void MediaSession::startRecording () { L_D(); - if (d->params->getRecordFilePath().empty()) { + if (d->getParams()->getRecordFilePath().empty()) { lError() << "MediaSession::startRecording(): no output file specified. Use linphone_call_params_set_record_file()"; return; } - if (d->audioStream && !d->params->getPrivate()->getInConference()) + if (d->audioStream && !d->getParams()->getPrivate()->getInConference()) audio_stream_mixed_record_start(d->audioStream); d->recordActive = true; } void MediaSession::stopRecording () { L_D(); - if (d->audioStream && !d->params->getPrivate()->getInConference()) + if (d->audioStream && !d->getParams()->getPrivate()->getInConference()) audio_stream_mixed_record_stop(d->audioStream); d->recordActive = false; } @@ -4324,7 +4322,7 @@ LinphoneStatus MediaSession::update (const MediaSessionParams *msp, const string LinphoneStatus result = 0; if (!d->isUpdateAllowed(nextState)) return -1; - if (d->currentParams == msp) + if (d->getCurrentParams() == msp) lWarning() << "CallSession::update() is given the current params, this is probably not what you intend to do!"; d->iceAgent->checkSession(IR_Controlling, true); if (msp) { @@ -4332,7 +4330,7 @@ LinphoneStatus MediaSession::update (const MediaSessionParams *msp, const string call->broken = FALSE; #endif d->setState(nextState, "Updating call"); - d->params = new MediaSessionParams(*msp); + d->setParams(new MediaSessionParams(*msp)); if (d->iceAgent->prepare(d->localDesc, false)) { lInfo() << "Defer CallSession update to gather ICE candidates"; return 0; @@ -4518,7 +4516,7 @@ float MediaSession::getAverageQuality () const { MediaSessionParams * MediaSession::getCurrentParams () const { L_D(); d->updateCurrentParams(); - return d->currentParams; + return d->getCurrentParams(); } float MediaSession::getCurrentQuality () const { @@ -4534,7 +4532,7 @@ float MediaSession::getCurrentQuality () const { const MediaSessionParams * MediaSession::getMediaParams () const { L_D(); - return d->params; + return d->getParams(); } RtpTransport * MediaSession::getMetaRtcpTransport (int streamIndex) const { @@ -4619,43 +4617,43 @@ const MediaSessionParams * MediaSession::getRemoteParams () { for (unsigned int i = 0; i < nbAudioStreams; i++) { SalStreamDescription *sd = sal_media_description_get_active_stream_of_type(md, SalAudio, i); if (sal_stream_description_has_srtp(sd)) - d->remoteParams->setMediaEncryption(LinphoneMediaEncryptionSRTP); + d->getRemoteParams()->setMediaEncryption(LinphoneMediaEncryptionSRTP); } unsigned int nbVideoStreams = sal_media_description_nb_active_streams_of_type(md, SalVideo); for (unsigned int i = 0; i < nbVideoStreams; i++) { SalStreamDescription *sd = sal_media_description_get_active_stream_of_type(md, SalVideo, i); if (sal_stream_description_active(sd)) - d->remoteParams->enableVideo(true); + d->getRemoteParams()->enableVideo(true); if (sal_stream_description_has_srtp(sd)) - d->remoteParams->setMediaEncryption(LinphoneMediaEncryptionSRTP); + d->getRemoteParams()->setMediaEncryption(LinphoneMediaEncryptionSRTP); } unsigned int nbTextStreams = sal_media_description_nb_active_streams_of_type(md, SalText); for (unsigned int i = 0; i < nbTextStreams; i++) { SalStreamDescription *sd = sal_media_description_get_active_stream_of_type(md, SalText, i); if (sal_stream_description_has_srtp(sd)) - d->remoteParams->setMediaEncryption(LinphoneMediaEncryptionSRTP); - d->remoteParams->enableRealtimeText(true); + d->getRemoteParams()->setMediaEncryption(LinphoneMediaEncryptionSRTP); + d->getRemoteParams()->enableRealtimeText(true); } - if (!d->remoteParams->videoEnabled()) { + if (!d->getRemoteParams()->videoEnabled()) { if ((md->bandwidth > 0) && (md->bandwidth <= linphone_core_get_edge_bw(d->core))) - d->remoteParams->enableLowBandwidth(true); + d->getRemoteParams()->enableLowBandwidth(true); } if (md->name[0] != '\0') - d->remoteParams->setSessionName(md->name); + d->getRemoteParams()->setSessionName(md->name); - d->remoteParams->getPrivate()->setCustomSdpAttributes(md->custom_sdp_attributes); - d->remoteParams->getPrivate()->setCustomSdpMediaAttributes(LinphoneStreamTypeAudio, md->streams[d->mainAudioStreamIndex].custom_sdp_attributes); - d->remoteParams->getPrivate()->setCustomSdpMediaAttributes(LinphoneStreamTypeVideo, md->streams[d->mainVideoStreamIndex].custom_sdp_attributes); - d->remoteParams->getPrivate()->setCustomSdpMediaAttributes(LinphoneStreamTypeText, md->streams[d->mainTextStreamIndex].custom_sdp_attributes); + d->getRemoteParams()->getPrivate()->setCustomSdpAttributes(md->custom_sdp_attributes); + d->getRemoteParams()->getPrivate()->setCustomSdpMediaAttributes(LinphoneStreamTypeAudio, md->streams[d->mainAudioStreamIndex].custom_sdp_attributes); + d->getRemoteParams()->getPrivate()->setCustomSdpMediaAttributes(LinphoneStreamTypeVideo, md->streams[d->mainVideoStreamIndex].custom_sdp_attributes); + d->getRemoteParams()->getPrivate()->setCustomSdpMediaAttributes(LinphoneStreamTypeText, md->streams[d->mainTextStreamIndex].custom_sdp_attributes); } const SalCustomHeader *ch = d->op->get_recv_custom_header(); if (ch) { /* Instanciate a remote_params only if a SIP message was received before (custom headers indicates this) */ if (!d->remoteParams) d->remoteParams = new MediaSessionParams(); - d->remoteParams->getPrivate()->setCustomHeaders(ch); + d->getRemoteParams()->getPrivate()->setCustomHeaders(ch); } - return d->remoteParams; + return d->getRemoteParams(); } return nullptr; } From 8b695901f841a04d2dfc6494af858560f3f2c0af Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 30 Nov 2017 11:01:46 +0100 Subject: [PATCH 0940/2215] Use CoreAccessor in call related classes. --- coreapi/linphonecore.c | 2 +- coreapi/misc.c | 2 +- src/c-wrapper/api/c-call-params.cpp | 2 +- src/conference/params/call-session-params.cpp | 2 +- src/conference/params/call-session-params.h | 5 +- .../params/media-session-params.cpp | 28 +- src/conference/params/media-session-params.h | 2 +- src/conference/participant.cpp | 5 +- src/conference/participant.h | 2 + src/conference/session/call-session-p.h | 8 +- src/conference/session/call-session.cpp | 122 ++-- src/conference/session/call-session.h | 8 +- src/conference/session/media-session-p.h | 8 +- src/conference/session/media-session.cpp | 612 ++++++++++-------- src/conference/session/media-session.h | 5 +- src/nat/ice-agent.cpp | 16 +- src/nat/stun-client.cpp | 10 +- src/nat/stun-client.h | 9 +- src/utils/payload-type-handler.cpp | 18 +- src/utils/payload-type-handler.h | 12 +- 20 files changed, 481 insertions(+), 397 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 7ef9445b9..4ae85aa58 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -6883,7 +6883,7 @@ void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m) { } void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params) { - L_GET_CPP_PTR_FROM_C_OBJECT(params)->initDefault(lc); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->initDefault(lc->cppCore); } void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) { diff --git a/coreapi/misc.c b/coreapi/misc.c index 77e0ff2ef..14604b538 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -176,7 +176,7 @@ int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, sock /* this functions runs a simple stun test and return the number of milliseconds to complete the tests, or -1 if the test were failed.*/ int linphone_run_stun_tests(LinphoneCore *lc, int audioPort, int videoPort, int textPort, char *audioCandidateAddr, int *audioCandidatePort, char *videoCandidateAddr, int *videoCandidatePort, char *textCandidateAddr, int *textCandidatePort) { - LinphonePrivate::StunClient *client = new LinphonePrivate::StunClient(lc); + LinphonePrivate::StunClient *client = new LinphonePrivate::StunClient(lc->cppCore); int ret = client->run(audioPort, videoPort, textPort); strncpy(audioCandidateAddr, client->getAudioCandidate().address.c_str(), LINPHONE_IPADDR_SIZE); *audioCandidatePort = client->getAudioCandidate().port; diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index 51e1e7295..4aa6e5006 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -502,7 +502,7 @@ LinphoneCallParams *linphone_call_params_new (LinphoneCore *core) { LinphoneCallParams *params = _linphone_CallParams_init(); auto mediaSessionParams = new LinphonePrivate::MediaSessionParams(); L_SET_CPP_PTR_FROM_C_OBJECT(params, mediaSessionParams); - L_GET_CPP_PTR_FROM_C_OBJECT(params)->initDefault(core); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->initDefault(core->cppCore); delete mediaSessionParams; return params; } diff --git a/src/conference/params/call-session-params.cpp b/src/conference/params/call-session-params.cpp index 27933bcf1..36db52cbe 100644 --- a/src/conference/params/call-session-params.cpp +++ b/src/conference/params/call-session-params.cpp @@ -86,7 +86,7 @@ CallSessionParams &CallSessionParams::operator= (const CallSessionParams &src) { // ----------------------------------------------------------------------------- -void CallSessionParams::initDefault (LinphoneCore *core) { +void CallSessionParams::initDefault (const std::shared_ptr &core) { L_D(); d->inConference = false; d->privacy = LinphonePrivacyDefault; diff --git a/src/conference/params/call-session-params.h b/src/conference/params/call-session-params.h index b5a351597..d98dc6f49 100644 --- a/src/conference/params/call-session-params.h +++ b/src/conference/params/call-session-params.h @@ -20,6 +20,8 @@ #ifndef _CALL_SESSION_PARAMS_H_ #define _CALL_SESSION_PARAMS_H_ +#include + #include "object/clonable-object.h" #include "linphone/types.h" @@ -31,6 +33,7 @@ LINPHONE_BEGIN_NAMESPACE class CallSessionParamsPrivate; +class Core; class CallSessionParams : public ClonableObject { friend class CallSession; @@ -44,7 +47,7 @@ public: CallSessionParams &operator= (const CallSessionParams &src); - virtual void initDefault (LinphoneCore *core); + virtual void initDefault (const std::shared_ptr &core); const std::string& getSessionName () const; void setSessionName (const std::string &sessionName); diff --git a/src/conference/params/media-session-params.cpp b/src/conference/params/media-session-params.cpp index 8ffc3dd91..4a5144bad 100644 --- a/src/conference/params/media-session-params.cpp +++ b/src/conference/params/media-session-params.cpp @@ -22,6 +22,7 @@ #include "media-session-params.h" +#include "core/core.h" #include "logger/logger.h" #include "private.h" @@ -223,27 +224,28 @@ MediaSessionParams &MediaSessionParams::operator= (const MediaSessionParams &src // ----------------------------------------------------------------------------- -void MediaSessionParams::initDefault (LinphoneCore *core) { +void MediaSessionParams::initDefault (const std::shared_ptr &core) { L_D(); CallSessionParams::initDefault(core); + LinphoneCore *cCore = core->getCCore(); d->audioEnabled = true; - d->videoEnabled = linphone_core_video_enabled(core) && core->video_policy.automatically_initiate; - if (!linphone_core_video_enabled(core) && core->video_policy.automatically_initiate) { + d->videoEnabled = linphone_core_video_enabled(cCore) && cCore->video_policy.automatically_initiate; + if (!linphone_core_video_enabled(cCore) && cCore->video_policy.automatically_initiate) { lError() << "LinphoneCore has video disabled for both capture and display, but video policy is to start the call with video. " "This is a possible mis-use of the API. In this case, video is disabled in default LinphoneCallParams"; } - d->realtimeTextEnabled = !!linphone_core_realtime_text_enabled(core); - d->encryption = linphone_core_get_media_encryption(core); - d->avpfEnabled = (linphone_core_get_avpf_mode(core) == LinphoneAVPFEnabled); - d->_implicitRtcpFbEnabled = !!lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_fb_implicit_rtcp_fb", true); - d->avpfRrInterval = static_cast(linphone_core_get_avpf_rr_interval(core)); + d->realtimeTextEnabled = !!linphone_core_realtime_text_enabled(cCore); + d->encryption = linphone_core_get_media_encryption(cCore); + d->avpfEnabled = (linphone_core_get_avpf_mode(cCore) == LinphoneAVPFEnabled); + d->_implicitRtcpFbEnabled = !!lp_config_get_int(linphone_core_get_config(cCore), "rtp", "rtcp_fb_implicit_rtcp_fb", true); + d->avpfRrInterval = static_cast(linphone_core_get_avpf_rr_interval(cCore)); d->audioDirection = LinphoneMediaDirectionSendRecv; d->videoDirection = LinphoneMediaDirectionSendRecv; - d->earlyMediaSendingEnabled = !!lp_config_get_int(linphone_core_get_config(core), "misc", "real_early_media", false); - d->audioMulticastEnabled = !!linphone_core_audio_multicast_enabled(core); - d->videoMulticastEnabled = !!linphone_core_video_multicast_enabled(core); - d->updateCallWhenIceCompleted = !!lp_config_get_int(linphone_core_get_config(core), "sip", "update_call_when_ice_completed", true); - d->mandatoryMediaEncryptionEnabled = !!linphone_core_is_media_encryption_mandatory(core); + d->earlyMediaSendingEnabled = !!lp_config_get_int(linphone_core_get_config(cCore), "misc", "real_early_media", false); + d->audioMulticastEnabled = !!linphone_core_audio_multicast_enabled(cCore); + d->videoMulticastEnabled = !!linphone_core_video_multicast_enabled(cCore); + d->updateCallWhenIceCompleted = !!lp_config_get_int(linphone_core_get_config(cCore), "sip", "update_call_when_ice_completed", true); + d->mandatoryMediaEncryptionEnabled = !!linphone_core_is_media_encryption_mandatory(cCore); } // ----------------------------------------------------------------------------- diff --git a/src/conference/params/media-session-params.h b/src/conference/params/media-session-params.h index 45143c4fb..630c69123 100644 --- a/src/conference/params/media-session-params.h +++ b/src/conference/params/media-session-params.h @@ -43,7 +43,7 @@ public: MediaSessionParams &operator= (const MediaSessionParams &src); - void initDefault (LinphoneCore *core) override; + void initDefault (const std::shared_ptr &core) override; bool audioEnabled () const; bool audioMulticastEnabled () const; diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index d4f8b2746..4379eb0c1 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -35,10 +35,11 @@ LINPHONE_BEGIN_NAMESPACE shared_ptr ParticipantPrivate::createSession ( const Conference &conference, const CallSessionParams *params, bool hasMedia, CallSessionListener *listener ) { + L_Q(); if (hasMedia && (!params || dynamic_cast(params))) { - session = make_shared(conference, params, listener); + session = make_shared(conference.getCore(), q->getSharedFromThis(), params, listener); } else { - session = make_shared(conference, params, listener); + session = make_shared(conference.getCore(), params, listener); } return session; } diff --git a/src/conference/participant.h b/src/conference/participant.h index 4dd008c3c..fbfaa2700 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -50,6 +50,8 @@ class Participant : public Object { friend class ServerGroupChatRoomPrivate; public: + L_OVERRIDE_SHARED_FROM_THIS(Participant); + explicit Participant (const IdentityAddress &address); explicit Participant (IdentityAddress &&address); diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index e72de9e5e..e8d8c2f73 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -31,8 +31,7 @@ LINPHONE_BEGIN_NAMESPACE class CallSessionPrivate : public ObjectPrivate { public: - CallSessionPrivate (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener); - virtual ~CallSessionPrivate (); + CallSessionPrivate () = default; int computeDuration () const; virtual void initializeParamsAccordingToIncomingCallParams (); @@ -41,7 +40,6 @@ public: bool startPing (); void setPingTime (int value) { pingTime = value; } - LinphoneCore *getCore () const { return core; } CallSessionParams *getCurrentParams () const { return currentParams; } LinphoneProxyConfig * getDestProxy () const { return destProxy; } SalCallOp * getOp () const { return op; } @@ -61,6 +59,8 @@ public: virtual void updating (bool isUpdate); protected: + void init (); + void accept (const CallSessionParams *params); virtual LinphoneStatus acceptUpdate (const CallSessionParams *csp, LinphoneCallState nextState, const std::string &stateInfo); LinphoneStatus checkForAcceptation () const; @@ -85,8 +85,6 @@ private: LinphoneAddress * getFixedContact () const; protected: - const Conference &conference; - LinphoneCore *core = nullptr; CallSessionListener *listener = nullptr; CallSessionParams *params = nullptr; diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 5c2d85aaa..aaa317a27 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -40,32 +40,6 @@ LINPHONE_BEGIN_NAMESPACE // ============================================================================= -CallSessionPrivate::CallSessionPrivate (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener) - : conference(conference), listener(listener) { - if (params) - setParams(new CallSessionParams(*params)); - currentParams = new CallSessionParams(); - core = conference.getCore()->getCCore(); - ei = linphone_error_info_new(); -} - -CallSessionPrivate::~CallSessionPrivate () { - if (currentParams) - delete currentParams; - if (params) - delete params; - if (remoteParams) - delete remoteParams; - if (ei) - linphone_error_info_unref(ei); - if (log) - linphone_call_log_unref(log); - if (op) - op->release(); -} - -// ----------------------------------------------------------------------------- - int CallSessionPrivate::computeDuration () const { if (log->connected_date_time == 0) return 0; @@ -108,9 +82,9 @@ void CallSessionPrivate::setState(LinphoneCallState newState, const string &mess switch (newState) { case LinphoneCallOutgoingInit: case LinphoneCallIncomingReceived: - getPlatformHelpers(core)->acquireWifiLock(); - getPlatformHelpers(core)->acquireMcastLock(); - getPlatformHelpers(core)->acquireCpuLock(); + getPlatformHelpers(q->getCore()->getCCore())->acquireWifiLock(); + getPlatformHelpers(q->getCore()->getCCore())->acquireMcastLock(); + getPlatformHelpers(q->getCore()->getCCore())->acquireCpuLock(); break; case LinphoneCallEnd: case LinphoneCallError: @@ -150,9 +124,9 @@ void CallSessionPrivate::setState(LinphoneCallState newState, const string &mess log->connected_date_time = ms_time(nullptr); break; case LinphoneCallReleased: - getPlatformHelpers(core)->acquireWifiLock(); - getPlatformHelpers(core)->acquireMcastLock(); - getPlatformHelpers(core)->acquireCpuLock(); + getPlatformHelpers(q->getCore()->getCCore())->acquireWifiLock(); + getPlatformHelpers(q->getCore()->getCCore())->acquireMcastLock(); + getPlatformHelpers(q->getCore()->getCCore())->acquireCpuLock(); break; default: break; @@ -199,16 +173,17 @@ void CallSessionPrivate::startIncomingNotification () { } bool CallSessionPrivate::startPing () { - if (core->sip_conf.ping_with_options) { + L_Q(); + if (q->getCore()->getCCore()->sip_conf.ping_with_options) { /* Defer the start of the call after the OPTIONS ping for outgoing call or * send an option request back to the caller so that we get a chance to discover our nat'd address * before answering for incoming call */ pingReplied = false; - pingOp = new SalOp(core->sal); + pingOp = new SalOp(q->getCore()->getCCore()->sal); if (direction == LinphoneCallIncoming) { const char *from = pingOp->get_from(); const char *to = pingOp->get_to(); - linphone_configure_op(core, pingOp, log->from, nullptr, false); + linphone_configure_op(q->getCore()->getCCore(), pingOp, log->from, nullptr, false); pingOp->set_route(op->get_network_origin()); pingOp->ping(from, to); } else if (direction == LinphoneCallOutgoing) { @@ -332,7 +307,7 @@ bool CallSessionPrivate::failure () { void CallSessionPrivate::infoReceived (SalBodyHandler *bodyHandler) { L_Q(); - LinphoneInfoMessage *info = linphone_core_create_info_message(core); + LinphoneInfoMessage *info = linphone_core_create_info_message(q->getCore()->getCCore()); linphone_info_message_set_headers(info, op->get_recv_custom_header()); if (bodyHandler) { LinphoneContent *content = linphone_content_from_sal_body_handler(bodyHandler); @@ -391,7 +366,8 @@ void CallSessionPrivate::terminated () { } void CallSessionPrivate::updated (bool isUpdate) { - deferUpdate = !!lp_config_get_int(linphone_core_get_config(core), "sip", "defer_update_default", FALSE); + L_Q(); + deferUpdate = !!lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "sip", "defer_update_default", FALSE); SalErrorInfo sei; memset(&sei, 0, sizeof(sei)); switch (state) { @@ -459,6 +435,13 @@ void CallSessionPrivate::updating (bool isUpdate) { // ----------------------------------------------------------------------------- +void CallSessionPrivate::init () { + currentParams = new CallSessionParams(); + ei = linphone_error_info_new(); +} + +// ----------------------------------------------------------------------------- + void CallSessionPrivate::accept (const CallSessionParams *csp) { L_Q(); /* Try to be best-effort in giving real local or routable contact address */ @@ -508,7 +491,7 @@ void CallSessionPrivate::handleIncomingReceivedStateInIncomingNotification () { /* Try to be best-effort in giving real local or routable contact address for 100Rel case */ setContactOp(); op->notify_ringing(false); - if (op->get_replaces() && lp_config_get_int(linphone_core_get_config(core), "sip", "auto_answer_replacing_calls", 1)) + if (op->get_replaces() && lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "sip", "auto_answer_replacing_calls", 1)) q->accept(); } @@ -658,11 +641,12 @@ void CallSessionPrivate::setContactOp () { // ----------------------------------------------------------------------------- void CallSessionPrivate::completeLog () { + L_Q(); log->duration = computeDuration(); /* Store duration since connected */ log->error_info = linphone_error_info_ref(ei); if (log->status == LinphoneCallMissed) - core->missed_calls++; - linphone_core_report_call_log(core, log); + q->getCore()->getCCore()->missed_calls++; + linphone_core_report_call_log(q->getCore()->getCCore(), log); } void CallSessionPrivate::createOp () { @@ -673,13 +657,13 @@ void CallSessionPrivate::createOpTo (const LinphoneAddress *to) { L_Q(); if (op) op->release(); - op = new SalCallOp(core->sal); + op = new SalCallOp(q->getCore()->getCCore()->sal); op->set_user_pointer(q); #if 0 if (linphone_call_params_get_referer(call->params)) sal_call_set_referer(call->op,linphone_call_params_get_referer(call->params)->op); #endif - linphone_configure_op(core, op, to, q->getParams()->getPrivate()->getCustomHeaders(), false); + linphone_configure_op(q->getCore()->getCCore(), op, to, q->getParams()->getPrivate()->getCustomHeaders(), false); if (q->getParams()->getPrivacy() != LinphonePrivacyDefault) op->set_privacy((SalPrivacyMask)q->getParams()->getPrivacy()); /* else privacy might be set by proxy */ @@ -688,6 +672,7 @@ void CallSessionPrivate::createOpTo (const LinphoneAddress *to) { // ----------------------------------------------------------------------------- LinphoneAddress * CallSessionPrivate::getFixedContact () const { + L_Q(); LinphoneAddress *result = nullptr; if (op && op->get_contact_address()) { /* If already choosed, don't change it */ @@ -703,7 +688,7 @@ LinphoneAddress * CallSessionPrivate::getFixedContact () const { lInfo() << "Contact has been fixed using proxy"; result = linphone_address_clone(linphone_proxy_config_get_contact(destProxy)); } else { - result = linphone_core_get_primary_contact_parsed(core); + result = linphone_core_get_primary_contact_parsed(q->getCore()->getCCore()); if (result) { /* Otherwise use supplied localip */ linphone_address_set_domain(result, nullptr /* localip */); @@ -716,12 +701,36 @@ LinphoneAddress * CallSessionPrivate::getFixedContact () const { // ============================================================================= -CallSession::CallSession (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener) - : Object(*new CallSessionPrivate(conference, params, listener)) { +CallSession::CallSession (const shared_ptr &core, const CallSessionParams *params, CallSessionListener *listener) + : Object(*new CallSessionPrivate), CoreAccessor(core) { + L_D(); + d->listener = listener; + if (params) + d->setParams(new CallSessionParams(*params)); + d->init(); lInfo() << "New CallSession [" << this << "] initialized (LinphoneCore version: " << linphone_core_get_version() << ")"; } -CallSession::CallSession (CallSessionPrivate &p) : Object(p) {} +CallSession::CallSession (CallSessionPrivate &p, const shared_ptr &core) : Object(p), CoreAccessor(core) { + L_D(); + d->init(); +} + +CallSession::~CallSession () { + L_D(); + if (d->currentParams) + delete d->currentParams; + if (d->params) + delete d->params; + if (d->remoteParams) + delete d->remoteParams; + if (d->ei) + linphone_error_info_unref(d->ei); + if (d->log) + linphone_call_log_unref(d->log); + if (d->op) + d->op->release(); +} // ----------------------------------------------------------------------------- @@ -750,7 +759,7 @@ void CallSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg LinphoneAddress *toAddr = linphone_address_new(to.asString().c_str()); if (!d->destProxy) { /* Try to define the destination proxy if it has not already been done to have a correct contact field in the SIP messages */ - d->destProxy = linphone_core_lookup_known_proxy(d->core, toAddr); + d->destProxy = linphone_core_lookup_known_proxy(getCore()->getCCore(), toAddr); } d->log = linphone_call_log_new(direction, fromAddr, toAddr); @@ -758,7 +767,7 @@ void CallSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg /* We already have an op for incoming calls */ d->op = op; d->op->set_user_pointer(this); - op->enable_cnx_ip_to_0000_if_sendonly(!!lp_config_get_default_int(linphone_core_get_config(d->core), + op->enable_cnx_ip_to_0000_if_sendonly(!!lp_config_get_default_int(linphone_core_get_config(getCore()->getCCore()), "sip", "cnx_ip_to_0000_if_sendonly_enabled", 0)); d->log->call_id = ms_strdup(op->get_call_id()); /* Must be known at that time */ } @@ -767,7 +776,7 @@ void CallSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg d->startPing(); } else if (direction == LinphoneCallIncoming) { d->setParams(new CallSessionParams()); - d->params->initDefault(d->core); + d->params->initDefault(getCore()); } } @@ -819,15 +828,15 @@ bool CallSession::initiateOutgoing () { void CallSession::iterate (time_t currentRealTime, bool oneSecondElapsed) { L_D(); int elapsed = (int)(currentRealTime - d->log->start_date_time); - if ((d->state == LinphoneCallOutgoingInit) && (elapsed >= d->core->sip_conf.delayed_timeout)) { + if ((d->state == LinphoneCallOutgoingInit) && (elapsed >= getCore()->getCCore()->sip_conf.delayed_timeout)) { /* Start the call even if the OPTIONS reply did not arrive */ startInvite(nullptr, ""); } if ((d->state == LinphoneCallIncomingReceived) || (d->state == LinphoneCallIncomingEarlyMedia)) { if (oneSecondElapsed) lInfo() << "Incoming call ringing for " << elapsed << " seconds"; - if (elapsed > d->core->sip_conf.inc_timeout) { - lInfo() << "Incoming call timeout (" << d->core->sip_conf.inc_timeout << ")"; + if (elapsed > getCore()->getCCore()->sip_conf.inc_timeout) { + lInfo() << "Incoming call timeout (" << getCore()->getCCore()->sip_conf.inc_timeout << ")"; #if 0 LinphoneReason declineReason = (core->current_call != call) ? LinphoneReasonBusy : LinphoneReasonDeclined; #endif @@ -839,16 +848,15 @@ void CallSession::iterate (time_t currentRealTime, bool oneSecondElapsed) { #endif } } - if ((d->core->sip_conf.in_call_timeout > 0) && (d->log->connected_date_time != 0) - && ((currentRealTime - d->log->connected_date_time) > d->core->sip_conf.in_call_timeout)) { - lInfo() << "In call timeout (" << d->core->sip_conf.in_call_timeout << ")"; + if ((getCore()->getCCore()->sip_conf.in_call_timeout > 0) && (d->log->connected_date_time != 0) + && ((currentRealTime - d->log->connected_date_time) > getCore()->getCCore()->sip_conf.in_call_timeout)) { + lInfo() << "In call timeout (" << getCore()->getCCore()->sip_conf.in_call_timeout << ")"; terminate(); } } LinphoneStatus CallSession::redirect (const string &redirectUri) { - L_D(); - LinphoneAddress *realParsedAddr = linphone_core_interpret_url(d->core, redirectUri.c_str()); + LinphoneAddress *realParsedAddr = linphone_core_interpret_url(getCore()->getCCore(), redirectUri.c_str()); if (!realParsedAddr) { /* Bad url */ lError() << "Bad redirect URI: " << redirectUri; diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index 70470d443..7062f0ec1 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -34,8 +34,9 @@ LINPHONE_BEGIN_NAMESPACE class CallPrivate; class CallSessionPrivate; class Content; +class Core; -class LINPHONE_PUBLIC CallSession : public Object { +class LINPHONE_PUBLIC CallSession : public Object, public CoreAccessor { friend class CallPrivate; friend class ClientGroupChatRoom; friend class ClientGroupChatRoomPrivate; @@ -46,7 +47,8 @@ class LINPHONE_PUBLIC CallSession : public Object { public: L_OVERRIDE_SHARED_FROM_THIS(CallSession); - CallSession (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener); + CallSession (const std::shared_ptr &core, const CallSessionParams *params, CallSessionListener *listener); + virtual ~CallSession (); LinphoneStatus accept (const CallSessionParams *csp = nullptr); LinphoneStatus acceptUpdate (const CallSessionParams *csp); @@ -80,7 +82,7 @@ public: std::string getRemoteUserAgent () const; protected: - explicit CallSession (CallSessionPrivate &p); + explicit CallSession (CallSessionPrivate &p, const std::shared_ptr &core); private: L_DECLARE_PRIVATE(CallSession); diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index 2d7409736..5e19fa222 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -37,8 +37,7 @@ LINPHONE_BEGIN_NAMESPACE class MediaSessionPrivate : public CallSessionPrivate { public: - MediaSessionPrivate (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener); - virtual ~MediaSessionPrivate (); + MediaSessionPrivate () = default; public: static void stunAuthRequestedCb (void *userData, const char *realm, const char *nonce, const char **username, const char **password, const char **ha1); @@ -69,7 +68,9 @@ public: MediaSessionParams *getCurrentParams () const { return static_cast(currentParams); } MediaSessionParams *getParams () const { return static_cast(params); } MediaSessionParams *getRemoteParams () const { return static_cast(remoteParams); } + void setCurrentParams (MediaSessionParams *msp); void setParams (MediaSessionParams *msp); + void setRemoteParams (MediaSessionParams *msp); IceSession *getIceSession () const { return iceAgent->getIceSession(); } @@ -99,6 +100,7 @@ private: static float aggregateQualityRatings (float audioRating, float videoRating); + std::shared_ptr getMe () const; void setState (LinphoneCallState newState, const std::string &message) override; void computeStreamsIndexes (const SalMediaDescription *md); @@ -244,6 +246,8 @@ private: static const std::string ecStateStore; static const int ecStateMaxLen; + std::weak_ptr me; + AudioStream *audioStream = nullptr; OrtpEvQueue *audioStreamEvQueue = nullptr; LinphoneCallStats *audioStats = nullptr; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index b5aff989d..ad39840be 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -26,8 +26,8 @@ #include "call/call-p.h" #include "conference/participant-p.h" #include "conference/params/media-session-params-p.h" - #include "conference/session/media-session.h" +#include "core/core.h" #include "utils/payload-type-handler.h" #include "logger/logger.h" @@ -68,54 +68,6 @@ const int MediaSessionPrivate::ecStateMaxLen = 1048576; /* 1Mo */ // ============================================================================= -MediaSessionPrivate::MediaSessionPrivate (const Conference &conference, const CallSessionParams *csp, CallSessionListener *listener) - : CallSessionPrivate(conference, nullptr, listener) { - if (csp) - setParams(new MediaSessionParams(*(reinterpret_cast(csp)))); - else - setParams(new MediaSessionParams()); - currentParams = new MediaSessionParams(); - - audioStats = _linphone_call_stats_new(); - initStats(audioStats, LinphoneStreamTypeAudio); - videoStats = _linphone_call_stats_new(); - initStats(videoStats, LinphoneStreamTypeVideo); - textStats = _linphone_call_stats_new(); - initStats(textStats, LinphoneStreamTypeText); - - int minPort, maxPort; - linphone_core_get_audio_port_range(core, &minPort, &maxPort); - setPortConfig(mainAudioStreamIndex, make_pair(minPort, maxPort)); - linphone_core_get_video_port_range(core, &minPort, &maxPort); - setPortConfig(mainVideoStreamIndex, make_pair(minPort, maxPort)); - linphone_core_get_text_port_range(core, &minPort, &maxPort); - setPortConfig(mainTextStreamIndex, make_pair(minPort, maxPort)); - - memset(sessions, 0, sizeof(sessions)); -} - -MediaSessionPrivate::~MediaSessionPrivate () { - if (audioStats) - linphone_call_stats_unref(audioStats); - if (videoStats) - linphone_call_stats_unref(videoStats); - if (textStats) - linphone_call_stats_unref(textStats); - if (natPolicy) - linphone_nat_policy_unref(natPolicy); - if (stunClient) - delete stunClient; - delete iceAgent; - if (localDesc) - sal_media_description_unref(localDesc); - if (biggestDesc) - sal_media_description_unref(biggestDesc); - if (resultDesc) - sal_media_description_unref(resultDesc); -} - -// ----------------------------------------------------------------------------- - void MediaSessionPrivate::stunAuthRequestedCb (void *userData, const char *realm, const char *nonce, const char **username, const char **password, const char **ha1) { MediaSessionPrivate *msp = reinterpret_cast(userData); msp->stunAuthRequestedCb(realm, nonce, username, password, ha1); @@ -136,7 +88,7 @@ void MediaSessionPrivate::accepted () { lInfo() << "Using early media SDP since none was received with the 200 OK"; md = resultDesc; } - if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(core, md))) + if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(q->getCore()->getCCore(), md))) md = nullptr; if (md) { /* There is a valid SDP in the response, either offer or answer, and we're able to start/update the streams */ @@ -264,7 +216,7 @@ bool MediaSessionPrivate::failure () { getParams()->enableAvpf(false); restartInvite(); return true; - } else if (!linphone_core_is_media_encryption_mandatory(core)) { + } else if (!linphone_core_is_media_encryption_mandatory(q->getCore()->getCCore())) { if (i == 0) lInfo() << "Retrying CallSession [" << q << "] with AVP"; getParams()->setMediaEncryption(LinphoneMediaEncryptionNone); @@ -311,8 +263,9 @@ bool MediaSessionPrivate::failure () { } void MediaSessionPrivate::pausedByRemote () { + L_Q(); MediaSessionParams *newParams = new MediaSessionParams(*getParams()); - if (lp_config_get_int(linphone_core_get_config(core), "sip", "inactive_video_on_pause", 0)) + if (lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "sip", "inactive_video_on_pause", 0)) newParams->setVideoDirection(LinphoneMediaDirectionInactive); acceptUpdate(newParams, LinphoneCallPausedByRemote, "Call paused by remote"); } @@ -353,7 +306,7 @@ void MediaSessionPrivate::remoteRinging () { #endif } } else { - linphone_core_stop_dtmf_stream(core); + linphone_core_stop_dtmf_stream(q->getCore()->getCCore()); if (state == LinphoneCallOutgoingEarlyMedia) { /* Already doing early media */ return; @@ -406,10 +359,10 @@ void MediaSessionPrivate::updating (bool isUpdate) { fixCallParams(rmd); if (state != LinphoneCallPaused) { /* Refresh the local description, but in paused state, we don't change anything. */ - if (!rmd && lp_config_get_int(linphone_core_get_config(core), "sip", "sdp_200_ack_follow_video_policy", 0)) { + if (!rmd && lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "sip", "sdp_200_ack_follow_video_policy", 0)) { lInfo() << "Applying default policy for offering SDP on CallSession [" << q << "]"; setParams(new MediaSessionParams()); - params->initDefault(core); + params->initDefault(q->getCore()); } makeLocalMediaDescription(); op->set_local_media_description(localDesc); @@ -419,7 +372,7 @@ void MediaSessionPrivate::updating (bool isUpdate) { memset(&sei, 0, sizeof(sei)); expectMediaInAck = false; SalMediaDescription *md = op->get_final_media_description(); - if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(core, md))) { + if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(q->getCore()->getCCore(), md))) { sal_error_info_set(&sei, SalReasonNotAcceptable, "SIP", 0, nullptr, nullptr); op->decline_with_error_info(&sei, nullptr); sal_error_info_reset(&sei); @@ -516,12 +469,24 @@ void MediaSessionPrivate::stopStreamsForIceGathering () { // ----------------------------------------------------------------------------- +void MediaSessionPrivate::setCurrentParams (MediaSessionParams *msp) { + if (currentParams) + delete currentParams; + currentParams = msp; +} + void MediaSessionPrivate::setParams (MediaSessionParams *msp) { if (params) delete params; params = msp; } +void MediaSessionPrivate::setRemoteParams (MediaSessionParams *msp) { + if (remoteParams) + delete remoteParams; + remoteParams = msp; +} + MediaStream * MediaSessionPrivate::getMediaStream (LinphoneStreamType type) const { switch (type) { case LinphoneStreamTypeAudio: @@ -617,6 +582,15 @@ float MediaSessionPrivate::aggregateQualityRatings (float audioRating, float vid // ----------------------------------------------------------------------------- +shared_ptr MediaSessionPrivate::getMe () const { + shared_ptr participant = me.lock(); + if (!participant) { + lWarning() << "Unable to get valid Participant instance"; + throw std::bad_weak_ptr(); + } + return participant; +} + void MediaSessionPrivate::setState (LinphoneCallState newState, const string &message) { L_Q(); /* Take a ref on the session otherwise it might get destroyed during the call to setState */ @@ -759,7 +733,7 @@ void MediaSessionPrivate::fixCallParams (SalMediaDescription *rmd) { lInfo() << "CallSession [" << q << "]: disabling video in our call params because the remote doesn't want it"; getParams()->enableVideo(false); } - if (rcp->videoEnabled() && core->video_policy.automatically_accept && linphone_core_video_enabled(core) && !getParams()->videoEnabled()) { + if (rcp->videoEnabled() && q->getCore()->getCCore()->video_policy.automatically_accept && linphone_core_video_enabled(q->getCore()->getCCore()) && !getParams()->videoEnabled()) { lInfo() << "CallSession [" << q << "]: re-enabling video in our call params because the remote wants it and the policy allows to automatically accept"; getParams()->enableVideo(true); } @@ -769,9 +743,10 @@ void MediaSessionPrivate::fixCallParams (SalMediaDescription *rmd) { } void MediaSessionPrivate::initializeParamsAccordingToIncomingCallParams () { + L_Q(); CallSessionPrivate::initializeParamsAccordingToIncomingCallParams(); getCurrentParams()->getPrivate()->setUpdateCallWhenIceCompleted(getParams()->getPrivate()->getUpdateCallWhenIceCompleted()); - getParams()->enableVideo(linphone_core_video_enabled(core) && core->video_policy.automatically_accept); + getParams()->enableVideo(linphone_core_video_enabled(q->getCore()->getCCore()) && q->getCore()->getCCore()->video_policy.automatically_accept); SalMediaDescription *md = op->get_remote_media_description(); if (md) { /* It is licit to receive an INVITE without SDP, in this case WE choose the media parameters according to policy */ @@ -794,13 +769,14 @@ void MediaSessionPrivate::initializeParamsAccordingToIncomingCallParams () { * Fix call parameters on incoming call to eg. enable AVPF if the incoming call propose it and it is not enabled locally. */ void MediaSessionPrivate::setCompatibleIncomingCallParams (SalMediaDescription *md) { + L_Q(); /* Handle AVPF, SRTP and DTLS */ getParams()->enableAvpf(!!sal_media_description_has_avpf(md)); if (destProxy) getParams()->setAvpfRrInterval(static_cast(linphone_proxy_config_get_avpf_rr_interval(destProxy) * 1000)); else - getParams()->setAvpfRrInterval(static_cast(linphone_core_get_avpf_rr_interval(core) * 1000)); - if (sal_media_description_has_zrtp(md) && linphone_core_media_encryption_supported(core, LinphoneMediaEncryptionZRTP)) + getParams()->setAvpfRrInterval(static_cast(linphone_core_get_avpf_rr_interval(q->getCore()->getCCore()) * 1000)); + if (sal_media_description_has_zrtp(md) && linphone_core_media_encryption_supported(q->getCore()->getCCore(), LinphoneMediaEncryptionZRTP)) getParams()->setMediaEncryption(LinphoneMediaEncryptionZRTP); else if (sal_media_description_has_dtls(md) && media_stream_dtls_supported()) getParams()->setMediaEncryption(LinphoneMediaEncryptionDTLS); @@ -897,26 +873,29 @@ MediaStream * MediaSessionPrivate::getMediaStream (int streamIndex) const { } MSWebCam * MediaSessionPrivate::getVideoDevice () const { + L_Q(); bool paused = (state == LinphoneCallPausing) || (state == LinphoneCallPaused); if (paused || allMuted || !cameraEnabled) - return get_nowebcam_device(core->factory); + return get_nowebcam_device(q->getCore()->getCCore()->factory); else - return core->video_conf.device; + return q->getCore()->getCCore()->video_conf.device; } // ----------------------------------------------------------------------------- void MediaSessionPrivate::fillMulticastMediaAddresses () { + L_Q(); if (getParams()->audioMulticastEnabled()) - mediaPorts[mainAudioStreamIndex].multicastIp = linphone_core_get_audio_multicast_addr(core); + mediaPorts[mainAudioStreamIndex].multicastIp = linphone_core_get_audio_multicast_addr(q->getCore()->getCCore()); if (getParams()->videoMulticastEnabled()) - mediaPorts[mainVideoStreamIndex].multicastIp = linphone_core_get_video_multicast_addr(core); + mediaPorts[mainVideoStreamIndex].multicastIp = linphone_core_get_video_multicast_addr(q->getCore()->getCCore()); } int MediaSessionPrivate::selectFixedPort (int streamIndex, pair portRange) { + L_Q(); for (int triedPort = portRange.first; triedPort < (portRange.first + 100); triedPort += 2) { bool alreadyUsed = false; - for (const bctbx_list_t *elem = linphone_core_get_calls(core); elem != nullptr; elem = bctbx_list_next(elem)) { + for (const bctbx_list_t *elem = linphone_core_get_calls(q->getCore()->getCCore()); elem != nullptr; elem = bctbx_list_next(elem)) { LinphoneCall *lcall = reinterpret_cast(bctbx_list_get_data(elem)); MediaSession *session = dynamic_cast(L_GET_PRIVATE_FROM_C_OBJECT(lcall)->getConference()->getActiveParticipant()->getPrivate()->getSession().get()); int existingPort = session->getPrivate()->mediaPorts[streamIndex].rtpPort; @@ -934,12 +913,13 @@ int MediaSessionPrivate::selectFixedPort (int streamIndex, pair portRa } int MediaSessionPrivate::selectRandomPort (int streamIndex, pair portRange) { + L_Q(); for (int nbTries = 0; nbTries < 100; nbTries++) { bool alreadyUsed = false; unsigned int mask = 1; int triedPort = static_cast((ortp_random() % static_cast((portRange.second - portRange.first) + portRange.first)) & ~mask); if (triedPort < portRange.first) triedPort = portRange.first + 2; - for (const bctbx_list_t *elem = linphone_core_get_calls(core); elem != nullptr; elem = bctbx_list_next(elem)) { + for (const bctbx_list_t *elem = linphone_core_get_calls(q->getCore()->getCCore()); elem != nullptr; elem = bctbx_list_next(elem)) { LinphoneCall *lcall = reinterpret_cast(bctbx_list_get_data(elem)); MediaSession *session = dynamic_cast(L_GET_PRIVATE_FROM_C_OBJECT(lcall)->getConference()->getActiveParticipant()->getPrivate()->getSession().get()); int existingPort = session->getPrivate()->mediaPorts[streamIndex].rtpPort; @@ -989,18 +969,20 @@ void MediaSessionPrivate::setRandomPortConfig (int streamIndex) { // ----------------------------------------------------------------------------- void MediaSessionPrivate::discoverMtu (const Address &remoteAddr) { - if (core->net_conf.mtu == 0) { + L_Q(); + if (q->getCore()->getCCore()->net_conf.mtu == 0) { /* Attempt to discover mtu */ int mtu = ms_discover_mtu(remoteAddr.getDomain().c_str()); if (mtu > 0) { - ms_factory_set_mtu(core->factory, mtu); - lInfo() << "Discovered mtu is " << mtu << ", RTP payload max size is " << ms_factory_get_payload_max_size(core->factory); + ms_factory_set_mtu(q->getCore()->getCCore()->factory, mtu); + lInfo() << "Discovered mtu is " << mtu << ", RTP payload max size is " << ms_factory_get_payload_max_size(q->getCore()->getCCore()->factory); } } } string MediaSessionPrivate::getBindIpForStream (int streamIndex) { - string bindIp = lp_config_get_string(linphone_core_get_config(core), "rtp", "bind_address", (af == AF_INET6) ? "::0" : "0.0.0.0"); + L_Q(); + string bindIp = lp_config_get_string(linphone_core_get_config(q->getCore()->getCCore()), "rtp", "bind_address", (af == AF_INET6) ? "::0" : "0.0.0.0"); PortConfig *pc = &mediaPorts[streamIndex]; if (!pc->multicastIp.empty()){ if (direction == LinphoneCallOutgoing) { @@ -1022,8 +1004,9 @@ string MediaSessionPrivate::getBindIpForStream (int streamIndex) { * Fill the local ip that routes to the internet according to the destination, or guess it by other special means. */ void MediaSessionPrivate::getLocalIp (const Address &remoteAddr) { + L_Q(); /* Next, sometime, override from config */ - const char *ip = lp_config_get_string(linphone_core_get_config(core), "rtp", "bind_address", nullptr); + const char *ip = lp_config_get_string(linphone_core_get_config(q->getCore()->getCCore()), "rtp", "bind_address", nullptr); if (ip) { mediaLocalIp = ip; return; @@ -1061,7 +1044,7 @@ void MediaSessionPrivate::getLocalIp (const Address &remoteAddr) { if (dest || mediaLocalIp.empty() || needMediaLocalIpRefresh) { needMediaLocalIpRefresh = false; char ip[LINPHONE_IPADDR_SIZE]; - linphone_core_get_local_ip(core, af, dest, ip); + linphone_core_get_local_ip(q->getCore()->getCCore(), af, dest, ip); mediaLocalIp = ip; } } @@ -1073,8 +1056,9 @@ string MediaSessionPrivate::getPublicIpForStream (int streamIndex) { } void MediaSessionPrivate::runStunTestsIfNeeded () { + L_Q(); if (linphone_nat_policy_stun_enabled(natPolicy) && !(linphone_nat_policy_ice_enabled(natPolicy) || linphone_nat_policy_turn_enabled(natPolicy))) { - stunClient = new StunClient(core); + stunClient = new StunClient(q->getCore()); int ret = stunClient->run(mediaPorts[mainAudioStreamIndex].rtpPort, mediaPorts[mainVideoStreamIndex].rtpPort, mediaPorts[mainTextStreamIndex].rtpPort); if (ret >= 0) pingTime = ret; @@ -1089,7 +1073,8 @@ void MediaSessionPrivate::runStunTestsIfNeeded () { * are dual stack. */ void MediaSessionPrivate::selectIncomingIpVersion () { - if (linphone_core_ipv6_enabled(core)) { + L_Q(); + if (linphone_core_ipv6_enabled(q->getCore()->getCCore())) { if (destProxy && destProxy->op) af = destProxy->op->get_address_family(); else @@ -1107,7 +1092,8 @@ void MediaSessionPrivate::selectIncomingIpVersion () { * to know if IPv6 is supported by the server. **/ void MediaSessionPrivate::selectOutgoingIpVersion () { - if (!linphone_core_ipv6_enabled(core)) { + L_Q(); + if (!linphone_core_ipv6_enabled(q->getCore()->getCCore())) { af = AF_INET; return; } @@ -1130,7 +1116,7 @@ void MediaSessionPrivate::selectOutgoingIpVersion () { if (haveIpv6) { if (!haveIpv4) af = AF_INET6; - else if (lp_config_get_int(linphone_core_get_config(core), "rtp", "prefer_ipv6", 1)) /* This property tells whether ipv6 is prefered if two versions are available */ + else if (lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "rtp", "prefer_ipv6", 1)) /* This property tells whether ipv6 is prefered if two versions are available */ af = AF_INET6; else af = AF_INET; @@ -1144,6 +1130,7 @@ void MediaSessionPrivate::selectOutgoingIpVersion () { // ----------------------------------------------------------------------------- void MediaSessionPrivate::forceStreamsDirAccordingToState (SalMediaDescription *md) { + L_Q(); for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { SalStreamDescription *sd = &md->streams[i]; switch (state) { @@ -1151,7 +1138,7 @@ void MediaSessionPrivate::forceStreamsDirAccordingToState (SalMediaDescription * case LinphoneCallPaused: if (sd->dir != SalStreamInactive) { sd->dir = SalStreamSendOnly; - if ((sd->type == SalVideo) && lp_config_get_int(linphone_core_get_config(core), "sip", "inactive_video_on_pause", 0)) + if ((sd->type == SalVideo) && lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "sip", "inactive_video_on_pause", 0)) sd->dir = SalStreamInactive; } break; @@ -1198,23 +1185,23 @@ bool MediaSessionPrivate::generateB64CryptoKey (size_t keyLength, char *keyOut, void MediaSessionPrivate::makeLocalMediaDescription () { L_Q(); int maxIndex = 0; - bool rtcpMux = !!lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_mux", 0); + bool rtcpMux = !!lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "rtp", "rtcp_mux", 0); SalMediaDescription *md = sal_media_description_new(); SalMediaDescription *oldMd = localDesc; /* Multicast is only set in case of outgoing call */ if (direction == LinphoneCallOutgoing) { if (getParams()->audioMulticastEnabled()) { - md->streams[mainAudioStreamIndex].ttl = linphone_core_get_audio_multicast_ttl(core); + md->streams[mainAudioStreamIndex].ttl = linphone_core_get_audio_multicast_ttl(q->getCore()->getCCore()); md->streams[mainAudioStreamIndex].multicast_role = SalMulticastSender; } if (getParams()->videoMulticastEnabled()) { - md->streams[mainVideoStreamIndex].ttl = linphone_core_get_video_multicast_ttl(core); + md->streams[mainVideoStreamIndex].ttl = linphone_core_get_video_multicast_ttl(q->getCore()->getCCore()); md->streams[mainVideoStreamIndex].multicast_role = SalMulticastSender; } } - getParams()->getPrivate()->adaptToNetwork(core, pingTime); + getParams()->getPrivate()->adaptToNetwork(q->getCore()->getCCore(), pingTime); string subject = q->getParams()->getSessionName(); if (!subject.empty()) @@ -1234,7 +1221,7 @@ void MediaSessionPrivate::makeLocalMediaDescription () { if (destProxy) { addr = linphone_address_clone(linphone_proxy_config_get_identity_address(destProxy)); } else { - addr = linphone_address_new(linphone_core_get_identity(core)); + addr = linphone_address_new(linphone_core_get_identity(q->getCore()->getCCore())); } if (linphone_address_get_username(addr)) /* Might be null in case of identity without userinfo */ strncpy(md->username, linphone_address_get_username(addr), sizeof(md->username)); @@ -1244,13 +1231,13 @@ void MediaSessionPrivate::makeLocalMediaDescription () { if (bandwidth) md->bandwidth = bandwidth; else - md->bandwidth = linphone_core_get_download_bandwidth(core); + md->bandwidth = linphone_core_get_download_bandwidth(q->getCore()->getCCore()); SalCustomSdpAttribute *customSdpAttributes = getParams()->getPrivate()->getCustomSdpAttributes(); if (customSdpAttributes) md->custom_sdp_attributes = sal_custom_sdp_attribute_clone(customSdpAttributes); - PayloadTypeHandler pth(core); + PayloadTypeHandler pth(q->getCore()); bctbx_list_t *l = pth.makeCodecsList(SalAudio, getParams()->getAudioBandwidthLimit(), -1, oldMd ? oldMd->streams[mainAudioStreamIndex].already_assigned_payloads : nullptr); @@ -1268,12 +1255,12 @@ void MediaSessionPrivate::makeLocalMediaDescription () { if (downPtime) md->streams[mainAudioStreamIndex].ptime = downPtime; else - md->streams[mainAudioStreamIndex].ptime = linphone_core_get_download_ptime(core); + md->streams[mainAudioStreamIndex].ptime = linphone_core_get_download_ptime(q->getCore()->getCCore()); md->streams[mainAudioStreamIndex].max_rate = pth.getMaxCodecSampleRate(l); md->streams[mainAudioStreamIndex].payloads = l; if (audioStream && audioStream->ms.sessions.rtp_session) { md->streams[mainAudioStreamIndex].rtp_ssrc = rtp_session_get_send_ssrc(audioStream->ms.sessions.rtp_session); - strncpy(md->streams[mainAudioStreamIndex].rtcp_cname, conference.getMe()->getAddress().asString().c_str(), sizeof(md->streams[mainAudioStreamIndex].rtcp_cname)); + strncpy(md->streams[mainAudioStreamIndex].rtcp_cname, getMe()->getAddress().asString().c_str(), sizeof(md->streams[mainAudioStreamIndex].rtcp_cname)); } else lWarning() << "Cannot get audio local ssrc for CallSession [" << q << "]"; @@ -1305,7 +1292,7 @@ void MediaSessionPrivate::makeLocalMediaDescription () { md->streams[mainVideoStreamIndex].payloads = l; if (videoStream && videoStream->ms.sessions.rtp_session) { md->streams[mainVideoStreamIndex].rtp_ssrc = rtp_session_get_send_ssrc(videoStream->ms.sessions.rtp_session); - strncpy(md->streams[mainVideoStreamIndex].rtcp_cname, conference.getMe()->getAddress().asString().c_str(), sizeof(md->streams[mainVideoStreamIndex].rtcp_cname)); + strncpy(md->streams[mainVideoStreamIndex].rtcp_cname, getMe()->getAddress().asString().c_str(), sizeof(md->streams[mainVideoStreamIndex].rtcp_cname)); } else lWarning() << "Cannot get video local ssrc for CallSession [" << q << "]"; if (mainVideoStreamIndex > maxIndex) @@ -1337,7 +1324,7 @@ void MediaSessionPrivate::makeLocalMediaDescription () { md->streams[mainTextStreamIndex].payloads = l; if (textStream && textStream->ms.sessions.rtp_session) { md->streams[mainTextStreamIndex].rtp_ssrc = rtp_session_get_send_ssrc(textStream->ms.sessions.rtp_session); - strncpy(md->streams[mainTextStreamIndex].rtcp_cname, conference.getMe()->getAddress().asString().c_str(), sizeof(md->streams[mainTextStreamIndex].rtcp_cname)); + strncpy(md->streams[mainTextStreamIndex].rtcp_cname, getMe()->getAddress().asString().c_str(), sizeof(md->streams[mainTextStreamIndex].rtcp_cname)); } else lWarning() << "Cannot get text local ssrc for CallSession [" << q << "]"; if (mainTextStreamIndex > maxIndex) @@ -1433,11 +1420,12 @@ int MediaSessionPrivate::setupEncryptionKey (SalSrtpCryptoAlgo *crypto, MSCrypto } void MediaSessionPrivate::setupRtcpFb (SalMediaDescription *md) { + L_Q(); for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (!sal_stream_description_active(&md->streams[i])) continue; - md->streams[i].rtcp_fb.generic_nack_enabled = !!lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_fb_generic_nack_enabled", 0); - md->streams[i].rtcp_fb.tmmbr_enabled = !!lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_fb_tmmbr_enabled", 1); + md->streams[i].rtcp_fb.generic_nack_enabled = !!lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "rtp", "rtcp_fb_generic_nack_enabled", 0); + md->streams[i].rtcp_fb.tmmbr_enabled = !!lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "rtp", "rtcp_fb_tmmbr_enabled", 1); md->streams[i].implicit_rtcp_fb = getParams()->getPrivate()->implicitRtcpFbEnabled(); for (const bctbx_list_t *it = md->streams[i].payloads; it != nullptr; it = bctbx_list_next(it)) { OrtpPayloadType *pt = reinterpret_cast(bctbx_list_get_data(it)); @@ -1456,9 +1444,10 @@ void MediaSessionPrivate::setupRtcpFb (SalMediaDescription *md) { } void MediaSessionPrivate::setupRtcpXr (SalMediaDescription *md) { - md->rtcp_xr.enabled = !!lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_xr_enabled", 1); + L_Q(); + md->rtcp_xr.enabled = !!lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "rtp", "rtcp_xr_enabled", 1); if (md->rtcp_xr.enabled) { - const char *rcvr_rtt_mode = lp_config_get_string(linphone_core_get_config(core), "rtp", "rtcp_xr_rcvr_rtt_mode", "all"); + const char *rcvr_rtt_mode = lp_config_get_string(linphone_core_get_config(q->getCore()->getCCore()), "rtp", "rtcp_xr_rcvr_rtt_mode", "all"); if (strcasecmp(rcvr_rtt_mode, "all") == 0) md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttAll; else if (strcasecmp(rcvr_rtt_mode, "sender") == 0) @@ -1466,11 +1455,11 @@ void MediaSessionPrivate::setupRtcpXr (SalMediaDescription *md) { else md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttNone; if (md->rtcp_xr.rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) - md->rtcp_xr.rcvr_rtt_max_size = lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_xr_rcvr_rtt_max_size", 10000); - md->rtcp_xr.stat_summary_enabled = !!lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_xr_stat_summary_enabled", 1); + md->rtcp_xr.rcvr_rtt_max_size = lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "rtp", "rtcp_xr_rcvr_rtt_max_size", 10000); + md->rtcp_xr.stat_summary_enabled = !!lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "rtp", "rtcp_xr_stat_summary_enabled", 1); if (md->rtcp_xr.stat_summary_enabled) md->rtcp_xr.stat_summary_flags = OrtpRtcpXrStatSummaryLoss | OrtpRtcpXrStatSummaryDup | OrtpRtcpXrStatSummaryJitt | OrtpRtcpXrStatSummaryTTL; - md->rtcp_xr.voip_metrics_enabled = !!lp_config_get_int(linphone_core_get_config(core), "rtp", "rtcp_xr_voip_metrics_enabled", 1); + md->rtcp_xr.voip_metrics_enabled = !!lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "rtp", "rtcp_xr_voip_metrics_enabled", 1); } for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (!sal_stream_description_active(&md->streams[i])) @@ -1480,7 +1469,8 @@ void MediaSessionPrivate::setupRtcpXr (SalMediaDescription *md) { } void MediaSessionPrivate::setupZrtpHash (SalMediaDescription *md) { - if (linphone_core_media_encryption_supported(core, LinphoneMediaEncryptionZRTP)) { + L_Q(); + if (linphone_core_media_encryption_supported(q->getCore()->getCCore(), LinphoneMediaEncryptionZRTP)) { /* Set the hello hash for all streams */ for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (!sal_stream_description_active(&md->streams[i])) @@ -1496,8 +1486,9 @@ void MediaSessionPrivate::setupZrtpHash (SalMediaDescription *md) { } void MediaSessionPrivate::setupEncryptionKeys (SalMediaDescription *md) { + L_Q(); SalMediaDescription *oldMd = localDesc; - bool keepSrtpKeys = !!lp_config_get_int(linphone_core_get_config(core), "sip", "keep_srtp_keys", 1); + bool keepSrtpKeys = !!lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "sip", "keep_srtp_keys", 1); for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (!sal_stream_description_active(&md->streams[i])) continue; @@ -1508,7 +1499,7 @@ void MediaSessionPrivate::setupEncryptionKeys (SalMediaDescription *md) { memcpy(&md->streams[i].crypto[j], &oldMd->streams[i].crypto[j], sizeof(SalSrtpCryptoAlgo)); } } else { - const MSCryptoSuite *suites = linphone_core_get_srtp_crypto_suites(core); + const MSCryptoSuite *suites = linphone_core_get_srtp_crypto_suites(q->getCore()->getCCore()); for (int j = 0; (suites != nullptr) && (suites[j] != MS_CRYPTO_SUITE_INVALID) && (j < SAL_CRYPTO_ALGO_MAX); j++) { setupEncryptionKey(&md->streams[i].crypto[j], suites[j], static_cast(j) + 1); } @@ -1603,6 +1594,7 @@ void MediaSessionPrivate::setDtlsFingerprintOnAllStreams () { } void MediaSessionPrivate::setupDtlsParams (MediaStream *ms) { + L_Q(); if (getParams()->getMediaEncryption() == LinphoneMediaEncryptionDTLS) { MSDtlsSrtpParams dtlsParams; memset(&dtlsParams, 0, sizeof(MSDtlsSrtpParams)); @@ -1613,7 +1605,7 @@ void MediaSessionPrivate::setupDtlsParams (MediaStream *ms) { char *key = nullptr; char *fingerprint = nullptr; sal_certificates_chain_parse_directory(&certificate, &key, &fingerprint, - linphone_core_get_user_certificates_path(core), "linphone-dtls-default-identity", SAL_CERTIFICATE_RAW_FORMAT_PEM, true, true); + linphone_core_get_user_certificates_path(q->getCore()->getCCore()), "linphone-dtls-default-identity", SAL_CERTIFICATE_RAW_FORMAT_PEM, true, true); if (fingerprint) { dtlsCertificateFingerprint = fingerprint; ms_free(fingerprint); @@ -1633,10 +1625,11 @@ void MediaSessionPrivate::setupDtlsParams (MediaStream *ms) { } void MediaSessionPrivate::setZrtpCryptoTypesParameters (MSZrtpParams *params) { + L_Q(); if (!params) return; - const MSCryptoSuite *srtpSuites = linphone_core_get_srtp_crypto_suites(core); + const MSCryptoSuite *srtpSuites = linphone_core_get_srtp_crypto_suites(q->getCore()->getCCore()); if (srtpSuites) { for(int i = 0; (srtpSuites[i] != MS_CRYPTO_SUITE_INVALID) && (i < SAL_CRYPTO_ALGO_MAX) && (i < MS_MAX_ZRTP_CRYPTO_TYPES); i++) { switch (srtpSuites[i]) { @@ -1672,15 +1665,15 @@ void MediaSessionPrivate::setZrtpCryptoTypesParameters (MSZrtpParams *params) { } /* linphone_core_get_srtp_crypto_suites is used to determine sensible defaults; here each can be overridden */ - MsZrtpCryptoTypesCount ciphersCount = linphone_core_get_zrtp_cipher_suites(core, params->ciphers); /* if not present in config file, params->ciphers is not modified */ + MsZrtpCryptoTypesCount ciphersCount = linphone_core_get_zrtp_cipher_suites(q->getCore()->getCCore(), params->ciphers); /* if not present in config file, params->ciphers is not modified */ if (ciphersCount != 0) /* Use zrtp_cipher_suites config only when present, keep config from srtp_crypto_suite otherwise */ params->ciphersCount = ciphersCount; - params->hashesCount = linphone_core_get_zrtp_hash_suites(core, params->hashes); - MsZrtpCryptoTypesCount authTagsCount = linphone_core_get_zrtp_auth_suites(core, params->authTags); /* If not present in config file, params->authTags is not modified */ + params->hashesCount = linphone_core_get_zrtp_hash_suites(q->getCore()->getCCore(), params->hashes); + MsZrtpCryptoTypesCount authTagsCount = linphone_core_get_zrtp_auth_suites(q->getCore()->getCCore(), params->authTags); /* If not present in config file, params->authTags is not modified */ if (authTagsCount != 0) params->authTagsCount = authTagsCount; /* Use zrtp_auth_suites config only when present, keep config from srtp_crypto_suite otherwise */ - params->sasTypesCount = linphone_core_get_zrtp_sas_suites(core, params->sasTypes); - params->keyAgreementsCount = linphone_core_get_zrtp_key_agreement_suites(core, params->keyAgreements); + params->sasTypesCount = linphone_core_get_zrtp_sas_suites(q->getCore()->getCCore(), params->sasTypes); + params->keyAgreementsCount = linphone_core_get_zrtp_key_agreement_suites(q->getCore()->getCCore(), params->keyAgreements); } void MediaSessionPrivate::startDtls (MSMediaStreamSessions *sessions, const SalStreamDescription *sd, const SalStreamDescription *remote) { @@ -1750,6 +1743,7 @@ bool MediaSessionPrivate::updateStreamCryptoParameters (const SalStreamDescripti // ----------------------------------------------------------------------------- int MediaSessionPrivate::getIdealAudioBandwidth (const SalMediaDescription *md, const SalStreamDescription *desc) { + L_Q(); int remoteBandwidth = 0; if (desc->bandwidth > 0) remoteBandwidth = desc->bandwidth; @@ -1763,7 +1757,7 @@ int MediaSessionPrivate::getIdealAudioBandwidth (const SalMediaDescription *md, forced = true; uploadBandwidth = getParams()->getPrivate()->getUpBandwidth(); } else - uploadBandwidth = linphone_core_get_upload_bandwidth(core); + uploadBandwidth = linphone_core_get_upload_bandwidth(q->getCore()->getCCore()); uploadBandwidth = PayloadTypeHandler::getMinBandwidth(uploadBandwidth, remoteBandwidth); if (!linphone_core_media_description_contains_video_stream(md) || forced) return uploadBandwidth; @@ -1779,6 +1773,7 @@ int MediaSessionPrivate::getIdealAudioBandwidth (const SalMediaDescription *md, } int MediaSessionPrivate::getVideoBandwidth (const SalMediaDescription *md, const SalStreamDescription *desc) { + L_Q(); int remoteBandwidth = 0; if (desc->bandwidth > 0) remoteBandwidth = desc->bandwidth; @@ -1786,11 +1781,12 @@ int MediaSessionPrivate::getVideoBandwidth (const SalMediaDescription *md, const /* Case where b=AS is given globally, not per stream */ remoteBandwidth = PayloadTypeHandler::getRemainingBandwidthForVideo(md->bandwidth, audioBandwidth); } else - remoteBandwidth = lp_config_get_int(linphone_core_get_config(core), "net", "default_max_bandwidth", 1500); - return PayloadTypeHandler::getMinBandwidth(PayloadTypeHandler::getRemainingBandwidthForVideo(linphone_core_get_upload_bandwidth(core), audioBandwidth), remoteBandwidth); + remoteBandwidth = lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "net", "default_max_bandwidth", 1500); + return PayloadTypeHandler::getMinBandwidth(PayloadTypeHandler::getRemainingBandwidthForVideo(linphone_core_get_upload_bandwidth(q->getCore()->getCCore()), audioBandwidth), remoteBandwidth); } RtpProfile * MediaSessionPrivate::makeProfile (const SalMediaDescription *md, const SalStreamDescription *desc, int *usedPt) { + L_Q(); *usedPt = -1; int bandwidth = 0; if (desc->type == SalAudio) @@ -1813,7 +1809,7 @@ RtpProfile * MediaSessionPrivate::makeProfile (const SalMediaDescription *md, co bandwidth = audioBandwidth; upPtime = getParams()->getPrivate()->getUpPtime(); if (!upPtime) - upPtime = linphone_core_get_upload_ptime(core); + upPtime = linphone_core_get_upload_ptime(q->getCore()->getCCore()); } first = false; } @@ -1857,7 +1853,8 @@ void MediaSessionPrivate::updateAllocatedAudioBandwidth (const PayloadType *pt, // ----------------------------------------------------------------------------- void MediaSessionPrivate::applyJitterBufferParams (RtpSession *session, LinphoneStreamType type) { - LinphoneConfig *config = linphone_core_get_config(core); + L_Q(); + LinphoneConfig *config = linphone_core_get_config(q->getCore()->getCCore()); JBParameters params; rtp_session_get_jitter_buffer_params(session, ¶ms); params.min_size = lp_config_get_int(config, "rtp", "jitter_buffer_min_size", 40); @@ -1873,12 +1870,12 @@ void MediaSessionPrivate::applyJitterBufferParams (RtpSession *session, Linphone switch (type) { case LinphoneStreamTypeAudio: case LinphoneStreamTypeText: /* Let's use the same params for text as for audio */ - params.nom_size = linphone_core_get_audio_jittcomp(core); - params.adaptive = linphone_core_audio_adaptive_jittcomp_enabled(core); + params.nom_size = linphone_core_get_audio_jittcomp(q->getCore()->getCCore()); + params.adaptive = linphone_core_audio_adaptive_jittcomp_enabled(q->getCore()->getCCore()); break; case LinphoneStreamTypeVideo: - params.nom_size = linphone_core_get_video_jittcomp(core); - params.adaptive = linphone_core_video_adaptive_jittcomp_enabled(core); + params.nom_size = linphone_core_get_video_jittcomp(q->getCore()->getCCore()); + params.adaptive = linphone_core_video_adaptive_jittcomp_enabled(q->getCore()->getCCore()); break; case LinphoneStreamTypeUnknown: lFatal() << "applyJitterBufferParams: should not happen"; @@ -1895,11 +1892,12 @@ void MediaSessionPrivate::applyJitterBufferParams (RtpSession *session, Linphone } void MediaSessionPrivate::clearEarlyMediaDestination (MediaStream *ms) { + L_Q(); RtpSession *session = ms->sessions.rtp_session; rtp_session_clear_aux_remote_addr(session); /* Restore symmetric rtp if ICE is not used */ if (!iceAgent->hasSession()) - rtp_session_set_symmetric_rtp(session, linphone_core_symmetric_rtp_enabled(core)); + rtp_session_set_symmetric_rtp(session, linphone_core_symmetric_rtp_enabled(q->getCore()->getCCore())); } void MediaSessionPrivate::clearEarlyMediaDestinations () { @@ -1911,13 +1909,13 @@ void MediaSessionPrivate::clearEarlyMediaDestinations () { void MediaSessionPrivate::configureAdaptiveRateControl (MediaStream *ms, const OrtpPayloadType *pt, bool videoWillBeUsed) { L_Q(); - bool enabled = !!linphone_core_adaptive_rate_control_enabled(core); + bool enabled = !!linphone_core_adaptive_rate_control_enabled(q->getCore()->getCCore()); if (!enabled) { media_stream_enable_adaptive_bitrate_control(ms, false); return; } bool isAdvanced = true; - string algo = linphone_core_get_adaptive_rate_algorithm(core); + string algo = linphone_core_get_adaptive_rate_algorithm(q->getCore()->getCCore()); if (algo == "basic") isAdvanced = false; else if (algo == "advanced") @@ -1931,7 +1929,7 @@ void MediaSessionPrivate::configureAdaptiveRateControl (MediaStream *ms, const O lInfo() << "CallSession [" << q << "] - setting up advanced rate control"; } if (isAdvanced) { - ms_bandwidth_controller_add_stream(core->bw_controller, ms); + ms_bandwidth_controller_add_stream(q->getCore()->getCCore()->bw_controller, ms); media_stream_enable_adaptive_bitrate_control(ms, false); } else { media_stream_set_adaptive_bitrate_algorithm(ms, MSQosAnalyzerAlgorithmSimple); @@ -1995,7 +1993,8 @@ void MediaSessionPrivate::configureRtpSessionForRtcpXr (SalStreamType type) { } RtpSession * MediaSessionPrivate::createAudioRtpIoSession () { - LinphoneConfig *config = linphone_core_get_config(core); + L_Q(); + LinphoneConfig *config = linphone_core_get_config(q->getCore()->getCCore()); const char *rtpmap = lp_config_get_string(config, "sound", "rtp_map", "pcmu/8000/1"); OrtpPayloadType *pt = rtp_profile_get_payload_from_rtpmap(audioProfile, rtpmap); if (!pt) @@ -2005,7 +2004,7 @@ RtpSession * MediaSessionPrivate::createAudioRtpIoSession () { rtp_profile_set_payload(rtpIoAudioProfile, ptnum, payload_type_clone(pt)); const char *localIp = lp_config_get_string(config, "sound", "rtp_local_addr", "127.0.0.1"); int localPort = lp_config_get_int(config, "sound", "rtp_local_port", 17076); - RtpSession *rtpSession = ms_create_duplex_rtp_session(localIp, localPort, -1, ms_factory_get_mtu(core->factory)); + RtpSession *rtpSession = ms_create_duplex_rtp_session(localIp, localPort, -1, ms_factory_get_mtu(q->getCore()->getCCore()->factory)); rtp_session_set_profile(rtpSession, rtpIoAudioProfile); const char *remoteIp = lp_config_get_string(config, "sound", "rtp_remote_addr", "127.0.0.1"); int remotePort = lp_config_get_int(config, "sound", "rtp_remote_port", 17078); @@ -2022,7 +2021,8 @@ RtpSession * MediaSessionPrivate::createAudioRtpIoSession () { RtpSession * MediaSessionPrivate::createVideoRtpIoSession () { #ifdef VIDEO_ENABLED - LinphoneConfig *config = linphone_core_get_config(core); + L_Q(); + LinphoneConfig *config = linphone_core_get_config(q->getCore()->getCCore()); const char *rtpmap = lp_config_get_string(config, "video", "rtp_map", "vp8/90000/1"); OrtpPayloadType *pt = rtp_profile_get_payload_from_rtpmap(videoProfile, rtpmap); if (!pt) @@ -2032,7 +2032,7 @@ RtpSession * MediaSessionPrivate::createVideoRtpIoSession () { rtp_profile_set_payload(rtpIoVideoProfile, ptnum, payload_type_clone(pt)); const char *localIp = lp_config_get_string(config, "video", "rtp_local_addr", "127.0.0.1"); int localPort = lp_config_get_int(config, "video", "rtp_local_port", 19076); - RtpSession *rtpSession = ms_create_duplex_rtp_session(localIp, localPort, -1, ms_factory_get_mtu(core->factory)); + RtpSession *rtpSession = ms_create_duplex_rtp_session(localIp, localPort, -1, ms_factory_get_mtu(q->getCore()->getCCore()->factory)); rtp_session_set_profile(rtpSession, rtpIoVideoProfile); const char *remoteIp = lp_config_get_string(config, "video", "rtp_remote_addr", "127.0.0.1"); int remotePort = lp_config_get_int(config, "video", "rtp_remote_port", 19078); @@ -2083,7 +2083,7 @@ void MediaSessionPrivate::handleIceEvents (OrtpEvent *ev) { iceAgent->updateIceStateInCallStats(); } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) { if (!evd->info.ice_processing_successful) - lWarning() << "No STUN answer from [" << linphone_core_get_stun_server(core) << "], continuing without STUN"; + lWarning() << "No STUN answer from [" << linphone_core_get_stun_server(q->getCore()->getCCore()) << "], continuing without STUN"; iceAgent->gatheringFinished(); switch (state) { case LinphoneCallUpdating: @@ -2203,30 +2203,30 @@ void MediaSessionPrivate::initializeAudioStream () { if (remoteDesc) streamDesc = sal_media_description_find_best_stream(remoteDesc, SalAudio); - audioStream = audio_stream_new2(core->factory, getBindIpForStream(mainAudioStreamIndex).c_str(), + audioStream = audio_stream_new2(q->getCore()->getCCore()->factory, getBindIpForStream(mainAudioStreamIndex).c_str(), (multicastRole == SalMulticastReceiver) ? streamDesc->rtp_port : mediaPorts[mainAudioStreamIndex].rtpPort, (multicastRole == SalMulticastReceiver) ? 0 /* Disabled for now */ : mediaPorts[mainAudioStreamIndex].rtcpPort); if (multicastRole == SalMulticastReceiver) joinMulticastGroup(mainAudioStreamIndex, &audioStream->ms); - rtp_session_enable_network_simulation(audioStream->ms.sessions.rtp_session, &core->net_conf.netsim_params); + rtp_session_enable_network_simulation(audioStream->ms.sessions.rtp_session, &q->getCore()->getCCore()->net_conf.netsim_params); applyJitterBufferParams(audioStream->ms.sessions.rtp_session, LinphoneStreamTypeAudio); - string userAgent = linphone_core_get_user_agent(core); - audio_stream_set_rtcp_information(audioStream, conference.getMe()->getAddress().asString().c_str(), userAgent.c_str()); - rtp_session_set_symmetric_rtp(audioStream->ms.sessions.rtp_session, linphone_core_symmetric_rtp_enabled(core)); + string userAgent = linphone_core_get_user_agent(q->getCore()->getCCore()); + audio_stream_set_rtcp_information(audioStream, getMe()->getAddress().asString().c_str(), userAgent.c_str()); + rtp_session_set_symmetric_rtp(audioStream->ms.sessions.rtp_session, linphone_core_symmetric_rtp_enabled(q->getCore()->getCCore())); setupDtlsParams(&audioStream->ms); /* Initialize zrtp even if we didn't explicitely set it, just in case peer offers it */ - if (linphone_core_media_encryption_supported(core, LinphoneMediaEncryptionZRTP)) { + if (linphone_core_media_encryption_supported(q->getCore()->getCCore(), LinphoneMediaEncryptionZRTP)) { char *peerUri = linphone_address_as_string_uri_only((direction == LinphoneCallIncoming) ? log->from : log->to); char *selfUri = linphone_address_as_string_uri_only((direction == LinphoneCallIncoming) ? log->to : log->from); MSZrtpParams params; memset(¶ms, 0, sizeof(MSZrtpParams)); /* media encryption of current params will be set later when zrtp is activated */ - params.zidCacheDB = linphone_core_get_zrtp_cache_db(core); + params.zidCacheDB = linphone_core_get_zrtp_cache_db(q->getCore()->getCCore()); params.peerUri = peerUri; params.selfUri = selfUri; /* Get key lifespan from config file, default is 0:forever valid */ - params.limeKeyTimeSpan = bctbx_time_string_to_sec(lp_config_get_string(linphone_core_get_config(core), "sip", "lime_key_validity", "0")); + params.limeKeyTimeSpan = bctbx_time_string_to_sec(lp_config_get_string(linphone_core_get_config(q->getCore()->getCCore()), "sip", "lime_key_validity", "0")); setZrtpCryptoTypesParameters(¶ms); audio_stream_enable_zrtp(audioStream, ¶ms); if (peerUri != NULL) ms_free(peerUri); @@ -2235,16 +2235,16 @@ void MediaSessionPrivate::initializeAudioStream () { media_stream_reclaim_sessions(&audioStream->ms, &sessions[mainAudioStreamIndex]); } else { - audioStream = audio_stream_new_with_sessions(core->factory, &sessions[mainAudioStreamIndex]); + audioStream = audio_stream_new_with_sessions(q->getCore()->getCCore()->factory, &sessions[mainAudioStreamIndex]); } if (mediaPorts[mainAudioStreamIndex].rtpPort == -1) setPortConfigFromRtpSession(mainAudioStreamIndex, audioStream->ms.sessions.rtp_session); - int dscp = linphone_core_get_audio_dscp(core); + int dscp = linphone_core_get_audio_dscp(q->getCore()->getCCore()); if (dscp != -1) audio_stream_set_dscp(audioStream, dscp); - if (linphone_core_echo_limiter_enabled(core)) { - string type = lp_config_get_string(linphone_core_get_config(core), "sound", "el_type", "mic"); + if (linphone_core_echo_limiter_enabled(q->getCore()->getCCore())) { + string type = lp_config_get_string(linphone_core_get_config(q->getCore()->getCCore()), "sound", "el_type", "mic"); if (type == "mic") audio_stream_enable_echo_limiter(audioStream, ELControlMic); else if (type == "full") @@ -2253,40 +2253,40 @@ void MediaSessionPrivate::initializeAudioStream () { /* Equalizer location in the graph: 'mic' = in input graph, otherwise in output graph. Any other value than mic will default to output graph for compatibility */ - string location = lp_config_get_string(linphone_core_get_config(core), "sound", "eq_location", "hp"); + string location = lp_config_get_string(linphone_core_get_config(q->getCore()->getCCore()), "sound", "eq_location", "hp"); audioStream->eq_loc = (location == "mic") ? MSEqualizerMic : MSEqualizerHP; lInfo() << "Equalizer location: " << location; audio_stream_enable_gain_control(audioStream, true); - if (linphone_core_echo_cancellation_enabled(core)) { - int len = lp_config_get_int(linphone_core_get_config(core), "sound", "ec_tail_len", 0); - int delay = lp_config_get_int(linphone_core_get_config(core), "sound", "ec_delay", 0); - int framesize = lp_config_get_int(linphone_core_get_config(core), "sound", "ec_framesize", 0); + if (linphone_core_echo_cancellation_enabled(q->getCore()->getCCore())) { + int len = lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "sound", "ec_tail_len", 0); + int delay = lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "sound", "ec_delay", 0); + int framesize = lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "sound", "ec_framesize", 0); audio_stream_set_echo_canceller_params(audioStream, len, delay, framesize); if (audioStream->ec) { char *statestr=reinterpret_cast(ms_malloc0(ecStateMaxLen)); - if (lp_config_relative_file_exists(linphone_core_get_config(core), ecStateStore.c_str()) - && (lp_config_read_relative_file(linphone_core_get_config(core), ecStateStore.c_str(), statestr, ecStateMaxLen) == 0)) { + if (lp_config_relative_file_exists(linphone_core_get_config(q->getCore()->getCCore()), ecStateStore.c_str()) + && (lp_config_read_relative_file(linphone_core_get_config(q->getCore()->getCCore()), ecStateStore.c_str(), statestr, ecStateMaxLen) == 0)) { ms_filter_call_method(audioStream->ec, MS_ECHO_CANCELLER_SET_STATE_STRING, statestr); } ms_free(statestr); } } - audio_stream_enable_automatic_gain_control(audioStream, linphone_core_agc_enabled(core)); - bool_t enabled = !!lp_config_get_int(linphone_core_get_config(core), "sound", "noisegate", 0); + audio_stream_enable_automatic_gain_control(audioStream, linphone_core_agc_enabled(q->getCore()->getCCore())); + bool_t enabled = !!lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "sound", "noisegate", 0); audio_stream_enable_noise_gate(audioStream, enabled); - audio_stream_set_features(audioStream, linphone_core_get_audio_features(core)); + audio_stream_set_features(audioStream, linphone_core_get_audio_features(q->getCore()->getCCore())); - if (core->rtptf) { + if (q->getCore()->getCCore()->rtptf) { RtpTransport *meta_rtp; RtpTransport *meta_rtcp; rtp_session_get_transports(audioStream->ms.sessions.rtp_session, &meta_rtp, &meta_rtcp); if (!meta_rtp_transport_get_endpoint(meta_rtp)) { lInfo() << "CallSession [" << q << "] using custom audio RTP transport endpoint"; - meta_rtp_transport_set_endpoint(meta_rtp, core->rtptf->audio_rtp_func(core->rtptf->audio_rtp_func_data, mediaPorts[mainAudioStreamIndex].rtpPort)); + meta_rtp_transport_set_endpoint(meta_rtp, q->getCore()->getCCore()->rtptf->audio_rtp_func(q->getCore()->getCCore()->rtptf->audio_rtp_func_data, mediaPorts[mainAudioStreamIndex].rtpPort)); } if (!meta_rtp_transport_get_endpoint(meta_rtcp)) - meta_rtp_transport_set_endpoint(meta_rtcp, core->rtptf->audio_rtcp_func(core->rtptf->audio_rtcp_func_data, mediaPorts[mainAudioStreamIndex].rtcpPort)); + meta_rtp_transport_set_endpoint(meta_rtcp, q->getCore()->getCCore()->rtptf->audio_rtcp_func(q->getCore()->getCCore()->rtptf->audio_rtcp_func_data, mediaPorts[mainAudioStreamIndex].rtcpPort)); } audioStreamEvQueue = ortp_ev_queue_new(); @@ -2301,6 +2301,7 @@ void MediaSessionPrivate::initializeStreams () { } void MediaSessionPrivate::initializeTextStream () { + L_Q(); if (textStream) return; if (!sessions[mainTextStreamIndex].rtp_session) { @@ -2312,29 +2313,29 @@ void MediaSessionPrivate::initializeTextStream () { if (remoteDesc) streamDesc = sal_media_description_find_best_stream(remoteDesc, SalText); - textStream = text_stream_new2(core->factory, getBindIpForStream(mainTextStreamIndex).c_str(), + textStream = text_stream_new2(q->getCore()->getCCore()->factory, getBindIpForStream(mainTextStreamIndex).c_str(), (multicastRole == SalMulticastReceiver) ? streamDesc->rtp_port : mediaPorts[mainTextStreamIndex].rtpPort, (multicastRole == SalMulticastReceiver) ? 0 /* Disabled for now */ : mediaPorts[mainTextStreamIndex].rtcpPort); if (multicastRole == SalMulticastReceiver) joinMulticastGroup(mainTextStreamIndex, &textStream->ms); - rtp_session_enable_network_simulation(textStream->ms.sessions.rtp_session, &core->net_conf.netsim_params); + rtp_session_enable_network_simulation(textStream->ms.sessions.rtp_session, &q->getCore()->getCCore()->net_conf.netsim_params); applyJitterBufferParams(textStream->ms.sessions.rtp_session, LinphoneStreamTypeText); - rtp_session_set_symmetric_rtp(textStream->ms.sessions.rtp_session, linphone_core_symmetric_rtp_enabled(core)); + rtp_session_set_symmetric_rtp(textStream->ms.sessions.rtp_session, linphone_core_symmetric_rtp_enabled(q->getCore()->getCCore())); setupDtlsParams(&textStream->ms); media_stream_reclaim_sessions(&textStream->ms, &sessions[mainTextStreamIndex]); } else - textStream = text_stream_new_with_sessions(core->factory, &sessions[mainTextStreamIndex]); + textStream = text_stream_new_with_sessions(q->getCore()->getCCore()->factory, &sessions[mainTextStreamIndex]); if (mediaPorts[mainTextStreamIndex].rtpPort == -1) setPortConfigFromRtpSession(mainTextStreamIndex, textStream->ms.sessions.rtp_session); - if (core->rtptf) { + if (q->getCore()->getCCore()->rtptf) { RtpTransport *meta_rtp; RtpTransport *meta_rtcp; rtp_session_get_transports(textStream->ms.sessions.rtp_session, &meta_rtp, &meta_rtcp); if (!meta_rtp_transport_get_endpoint(meta_rtp)) - meta_rtp_transport_set_endpoint(meta_rtp, core->rtptf->audio_rtp_func(core->rtptf->audio_rtp_func_data, mediaPorts[mainTextStreamIndex].rtpPort)); + meta_rtp_transport_set_endpoint(meta_rtp, q->getCore()->getCCore()->rtptf->audio_rtp_func(q->getCore()->getCCore()->rtptf->audio_rtp_func_data, mediaPorts[mainTextStreamIndex].rtpPort)); if (!meta_rtp_transport_get_endpoint(meta_rtcp)) - meta_rtp_transport_set_endpoint(meta_rtcp, core->rtptf->audio_rtcp_func(core->rtptf->audio_rtcp_func_data, mediaPorts[mainTextStreamIndex].rtcpPort)); + meta_rtp_transport_set_endpoint(meta_rtcp, q->getCore()->getCCore()->rtptf->audio_rtcp_func(q->getCore()->getCCore()->rtptf->audio_rtcp_func_data, mediaPorts[mainTextStreamIndex].rtcpPort)); } textStreamEvQueue = ortp_ev_queue_new(); @@ -2356,53 +2357,53 @@ void MediaSessionPrivate::initializeVideoStream () { if (remoteDesc) streamDesc = sal_media_description_find_best_stream(remoteDesc, SalVideo); - videoStream = video_stream_new2(core->factory, getBindIpForStream(mainVideoStreamIndex).c_str(), + videoStream = video_stream_new2(q->getCore()->getCCore()->factory, getBindIpForStream(mainVideoStreamIndex).c_str(), (multicastRole == SalMulticastReceiver) ? streamDesc->rtp_port : mediaPorts[mainVideoStreamIndex].rtpPort, (multicastRole == SalMulticastReceiver) ? 0 /* Disabled for now */ : mediaPorts[mainVideoStreamIndex].rtcpPort); if (multicastRole == SalMulticastReceiver) joinMulticastGroup(mainVideoStreamIndex, &videoStream->ms); - rtp_session_enable_network_simulation(videoStream->ms.sessions.rtp_session, &core->net_conf.netsim_params); + rtp_session_enable_network_simulation(videoStream->ms.sessions.rtp_session, &q->getCore()->getCCore()->net_conf.netsim_params); applyJitterBufferParams(videoStream->ms.sessions.rtp_session, LinphoneStreamTypeVideo); - string userAgent = linphone_core_get_user_agent(core); - video_stream_set_rtcp_information(videoStream, conference.getMe()->getAddress().asString().c_str(), userAgent.c_str()); - rtp_session_set_symmetric_rtp(videoStream->ms.sessions.rtp_session, linphone_core_symmetric_rtp_enabled(core)); + string userAgent = linphone_core_get_user_agent(q->getCore()->getCCore()); + video_stream_set_rtcp_information(videoStream, getMe()->getAddress().asString().c_str(), userAgent.c_str()); + rtp_session_set_symmetric_rtp(videoStream->ms.sessions.rtp_session, linphone_core_symmetric_rtp_enabled(q->getCore()->getCCore())); setupDtlsParams(&videoStream->ms); /* Initialize zrtp even if we didn't explicitely set it, just in case peer offers it */ - if (linphone_core_media_encryption_supported(core, LinphoneMediaEncryptionZRTP)) + if (linphone_core_media_encryption_supported(q->getCore()->getCCore(), LinphoneMediaEncryptionZRTP)) video_stream_enable_zrtp(videoStream, audioStream); media_stream_reclaim_sessions(&videoStream->ms, &sessions[mainVideoStreamIndex]); } else - videoStream = video_stream_new_with_sessions(core->factory, &sessions[mainVideoStreamIndex]); + videoStream = video_stream_new_with_sessions(q->getCore()->getCCore()->factory, &sessions[mainVideoStreamIndex]); if (mediaPorts[mainVideoStreamIndex].rtpPort == -1) setPortConfigFromRtpSession(mainVideoStreamIndex, videoStream->ms.sessions.rtp_session); - int dscp = linphone_core_get_video_dscp(core); + int dscp = linphone_core_get_video_dscp(q->getCore()->getCCore()); if (dscp!=-1) video_stream_set_dscp(videoStream, dscp); video_stream_enable_display_filter_auto_rotate( videoStream, - !!lp_config_get_int(linphone_core_get_config(core), "video", "display_filter_auto_rotate", 0) + !!lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "video", "display_filter_auto_rotate", 0) ); - int videoRecvBufSize = lp_config_get_int(linphone_core_get_config(core), "video", "recv_buf_size", 0); + int videoRecvBufSize = lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "video", "recv_buf_size", 0); if (videoRecvBufSize > 0) rtp_session_set_recv_buf_size(videoStream->ms.sessions.rtp_session, videoRecvBufSize); - const char *displayFilter = linphone_core_get_video_display_filter(core); + const char *displayFilter = linphone_core_get_video_display_filter(q->getCore()->getCCore()); if (displayFilter) video_stream_set_display_filter_name(videoStream, displayFilter); video_stream_set_event_callback(videoStream, videoStreamEventCb, this); - if (core->rtptf) { + if (q->getCore()->getCCore()->rtptf) { RtpTransport *meta_rtp; RtpTransport *meta_rtcp; rtp_session_get_transports(videoStream->ms.sessions.rtp_session, &meta_rtp, &meta_rtcp); if (!meta_rtp_transport_get_endpoint(meta_rtp)) { lInfo() << "CallSession [" << q << "] using custom video RTP transport endpoint"; - meta_rtp_transport_set_endpoint(meta_rtp, core->rtptf->video_rtp_func(core->rtptf->video_rtp_func_data, mediaPorts[mainVideoStreamIndex].rtpPort)); + meta_rtp_transport_set_endpoint(meta_rtp, q->getCore()->getCCore()->rtptf->video_rtp_func(q->getCore()->getCCore()->rtptf->video_rtp_func_data, mediaPorts[mainVideoStreamIndex].rtpPort)); } if (!meta_rtp_transport_get_endpoint(meta_rtcp)) - meta_rtp_transport_set_endpoint(meta_rtcp, core->rtptf->video_rtcp_func(core->rtptf->video_rtcp_func_data, mediaPorts[mainVideoStreamIndex].rtcpPort)); + meta_rtp_transport_set_endpoint(meta_rtcp, q->getCore()->getCCore()->rtptf->video_rtcp_func(q->getCore()->getCCore()->rtptf->video_rtcp_func_data, mediaPorts[mainVideoStreamIndex].rtcpPort)); } videoStreamEvQueue = ortp_ev_queue_new(); rtp_session_register_event_queue(videoStream->ms.sessions.rtp_session, videoStreamEvQueue); @@ -2416,7 +2417,8 @@ void MediaSessionPrivate::initializeVideoStream () { } void MediaSessionPrivate::parameterizeEqualizer (AudioStream *stream) { - LinphoneConfig *config = linphone_core_get_config(core); + L_Q(); + LinphoneConfig *config = linphone_core_get_config(q->getCore()->getCCore()); const char *eqActive = lp_config_get_string(config, "sound", "eq_active", nullptr); if (eqActive) lWarning() << "'eq_active' linphonerc parameter has no effect anymore. Please use 'mic_eq_active' or 'spk_eq_active' instead"; @@ -2466,15 +2468,16 @@ void MediaSessionPrivate::prepareEarlyMediaForking () { } void MediaSessionPrivate::postConfigureAudioStream (AudioStream *stream, bool muted) { - float micGain = core->sound_conf.soft_mic_lev; + L_Q(); + float micGain = q->getCore()->getCCore()->sound_conf.soft_mic_lev; if (muted) audio_stream_set_mic_gain(stream, 0); else audio_stream_set_mic_gain_db(stream, micGain); - float recvGain = core->sound_conf.soft_play_lev; + float recvGain = q->getCore()->getCCore()->sound_conf.soft_play_lev; if (static_cast(recvGain)) setPlaybackGainDb(stream, recvGain); - LinphoneConfig *config = linphone_core_get_config(core); + LinphoneConfig *config = linphone_core_get_config(q->getCore()->getCCore()); float ngThres = lp_config_get_float(config, "sound", "ng_thres", 0.05f); float ngFloorGain = lp_config_get_float(config, "sound", "ng_floorgain", 0); if (stream->volsend) { @@ -2516,7 +2519,7 @@ void MediaSessionPrivate::postConfigureAudioStream (AudioStream *stream, bool mu void MediaSessionPrivate::postConfigureAudioStreams (bool muted) { L_Q(); postConfigureAudioStream(audioStream, muted); - if (linphone_core_dtmf_received_has_listener(core)) + if (linphone_core_dtmf_received_has_listener(q->getCore()->getCCore())) audio_stream_play_received_dtmfs(audioStream, false); if (recordActive) q->startRecording(); @@ -2538,6 +2541,7 @@ void MediaSessionPrivate::setSymmetricRtp (bool value) { } void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool videoWillBeUsed) { + L_Q(); const SalStreamDescription *stream = sal_media_description_find_best_stream(resultDesc, SalAudio); if (stream && (stream->dir != SalStreamInactive) && (stream->rtp_port != 0)) { int usedPt = -1; @@ -2551,14 +2555,14 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool bool ok = true; getCurrentParams()->getPrivate()->setUsedAudioCodec(rtp_profile_get_payload(audioProfile, usedPt)); getCurrentParams()->enableAudio(true); - MSSndCard *playcard = core->sound_conf.lsd_card ? core->sound_conf.lsd_card : core->sound_conf.play_sndcard; + MSSndCard *playcard = q->getCore()->getCCore()->sound_conf.lsd_card ? q->getCore()->getCCore()->sound_conf.lsd_card : q->getCore()->getCCore()->sound_conf.play_sndcard; if (!playcard) lWarning() << "No card defined for playback!"; - MSSndCard *captcard = core->sound_conf.capt_sndcard; + MSSndCard *captcard = q->getCore()->getCCore()->sound_conf.capt_sndcard; if (!captcard) lWarning() << "No card defined for capture!"; - string playfile = L_C_TO_STRING(core->play_file); - string recfile = L_C_TO_STRING(core->rec_file); + string playfile = L_C_TO_STRING(q->getCore()->getCCore()->play_file); + string recfile = L_C_TO_STRING(q->getCore()->getCCore()->rec_file); /* Don't use file or soundcard capture when placed in recv-only mode */ if ((stream->rtp_port == 0) || (stream->dir == SalStreamRecvOnly) || ((stream->multicast_role == SalMulticastReceiver) && isMulticast)) { captcard = nullptr; @@ -2573,15 +2577,15 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool if (playingRingbackTone) { captcard = nullptr; playfile = ""; /* It is setup later */ - if (lp_config_get_int(linphone_core_get_config(core), "sound", "send_ringback_without_playback", 0) == 1) { + if (lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "sound", "send_ringback_without_playback", 0) == 1) { playcard = nullptr; recfile = ""; } } /* If playfile are supplied don't use soundcards */ - bool useRtpIo = !!lp_config_get_int(linphone_core_get_config(core), "sound", "rtp_io", false); - bool useRtpIoEnableLocalOutput = !!lp_config_get_int(linphone_core_get_config(core), "sound", "rtp_io_enable_local_output", false); - if (core->use_files || (useRtpIo && !useRtpIoEnableLocalOutput)) { + bool useRtpIo = !!lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "sound", "rtp_io", false); + bool useRtpIoEnableLocalOutput = !!lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "sound", "rtp_io_enable_local_output", false); + if (q->getCore()->getCCore()->use_files || (useRtpIo && !useRtpIoEnableLocalOutput)) { captcard = playcard = nullptr; } if (getParams()->getPrivate()->getInConference()) { @@ -2599,7 +2603,7 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool ms_snd_card_set_stream_type(playcard, MS_SND_CARD_STREAM_VOICE); } - bool useEc = captcard && linphone_core_echo_cancellation_enabled(core); + bool useEc = captcard && linphone_core_echo_cancellation_enabled(q->getCore()->getCCore()); audio_stream_enable_echo_canceller(audioStream, useEc); if (playcard && (stream->max_rate > 0)) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate); @@ -2663,7 +2667,7 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool if (ok) { int err = audio_stream_start_from_io(audioStream, audioProfile, rtpAddr, stream->rtp_port, (stream->rtcp_addr[0] != '\0') ? stream->rtcp_addr : resultDesc->addr, - (linphone_core_rtcp_enabled(core) && !isMulticast) ? (stream->rtcp_port ? stream->rtcp_port : stream->rtp_port + 1) : 0, + (linphone_core_rtcp_enabled(q->getCore()->getCCore()) && !isMulticast) ? (stream->rtcp_port ? stream->rtcp_port : stream->rtp_port + 1) : 0, usedPt, &io); if (err == 0) postConfigureAudioStreams((allMuted || audioMuted) && !playingRingbackTone); @@ -2678,11 +2682,11 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool setup_ring_player(lc,call); } #endif - if (getParams()->getPrivate()->getInConference() && core->conf_ctx) { + if (getParams()->getPrivate()->getInConference() && q->getCore()->getCCore()->conf_ctx) { /* Transform the graph to connect it to the conference filter */ #if 0 bool mute = (stream->dir == SalStreamRecvOnly); - linphone_conference_on_call_stream_starting(core->conf_ctx, call, mute); + linphone_conference_on_call_stream_starting(q->getCore()->getCCore()->conf_ctx, call, mute); #endif } getCurrentParams()->getPrivate()->setInConference(getParams()->getPrivate()->getInConference()); @@ -2690,7 +2694,7 @@ void MediaSessionPrivate::startAudioStream (LinphoneCallState targetState, bool /* Start ZRTP engine if needed : set here or remote have a zrtp-hash attribute */ SalMediaDescription *remote = op->get_remote_media_description(); const SalStreamDescription *remoteStream = sal_media_description_find_best_stream(remote, SalAudio); - if (linphone_core_media_encryption_supported(core, LinphoneMediaEncryptionZRTP) + if (linphone_core_media_encryption_supported(q->getCore()->getCCore(), LinphoneMediaEncryptionZRTP) && ((getParams()->getMediaEncryption() == LinphoneMediaEncryptionZRTP) || (remoteStream->haveZrtpHash == 1))) { audio_stream_start_zrtp(audioStream); if (remoteStream->haveZrtpHash == 1) { @@ -2707,7 +2711,7 @@ void MediaSessionPrivate::startStreams (LinphoneCallState targetState) { L_Q(); switch (targetState) { case LinphoneCallIncomingEarlyMedia: - if (linphone_core_get_remote_ringback_tone(core)) { + if (linphone_core_get_remote_ringback_tone(q->getCore()->getCCore())) { playingRingbackTone = true; } BCTBX_NO_BREAK; @@ -2744,8 +2748,8 @@ void MediaSessionPrivate::startStreams (LinphoneCallState targetState) { videoWillBeUsed = true; } #endif - lInfo() << "startStreams() CallSession=[" << q << "] local upload_bandwidth=[" << linphone_core_get_upload_bandwidth(core) - << "] kbit/s; local download_bandwidth=[" << linphone_core_get_download_bandwidth(core) << "] kbit/s"; + lInfo() << "startStreams() CallSession=[" << q << "] local upload_bandwidth=[" << linphone_core_get_upload_bandwidth(q->getCore()->getCCore()) + << "] kbit/s; local download_bandwidth=[" << linphone_core_get_download_bandwidth(q->getCore()->getCCore()) << "] kbit/s"; getCurrentParams()->enableAudio(false); if (audioStream) startAudioStream(targetState, videoWillBeUsed); @@ -2766,7 +2770,7 @@ void MediaSessionPrivate::startStreams (LinphoneCallState targetState) { ms_filter_call_method_noarg(player, MS_PLAYER_START); } } - upBandwidth = linphone_core_get_upload_bandwidth(core); + upBandwidth = linphone_core_get_upload_bandwidth(q->getCore()->getCCore()); if (getParams()->realtimeTextEnabled()) startTextStream(); @@ -2811,7 +2815,7 @@ void MediaSessionPrivate::startTextStream () { if (isMulticast) rtp_session_set_multicast_ttl(textStream->ms.sessions.rtp_session, tstream->ttl); text_stream_start(textStream, textProfile, rtpAddr, tstream->rtp_port, rtcpAddr, - (linphone_core_rtcp_enabled(core) && !isMulticast) ? (tstream->rtcp_port ? tstream->rtcp_port : tstream->rtp_port + 1) : 0, usedPt); + (linphone_core_rtcp_enabled(q->getCore()->getCCore()) && !isMulticast) ? (tstream->rtcp_port ? tstream->rtcp_port : tstream->rtp_port + 1) : 0, usedPt); ms_filter_add_notify_callback(textStream->rttsink, realTimeTextCharacterReceived, q, false); ms_media_stream_sessions_set_encryption_mandatory(&textStream->ms.sessions, isEncryptionMandatory()); } @@ -2825,12 +2829,12 @@ void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { bool reusedPreview = false; /* Shutdown preview */ MSFilter *source = nullptr; - if (core->previewstream) { - if (core->video_conf.reuse_preview_source) - source = video_preview_stop_reuse_source(core->previewstream); + if (q->getCore()->getCCore()->previewstream) { + if (q->getCore()->getCCore()->video_conf.reuse_preview_source) + source = video_preview_stop_reuse_source(q->getCore()->getCCore()->previewstream); else - video_preview_stop(core->previewstream); - core->previewstream = nullptr; + video_preview_stop(q->getCore()->getCCore()->previewstream); + q->getCore()->getCCore()->previewstream = nullptr; } const SalStreamDescription *vstream = sal_media_description_find_best_stream(resultDesc, SalVideo); if (vstream && (vstream->dir != SalStreamInactive) && (vstream->rtp_port != 0)) { @@ -2842,24 +2846,24 @@ void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { getCurrentParams()->getPrivate()->setUsedVideoCodec(rtp_profile_get_payload(videoProfile, usedPt)); getCurrentParams()->enableVideo(true); rtp_session_enable_rtcp_mux(videoStream->ms.sessions.rtp_session, vstream->rtcp_mux); - if (core->video_conf.preview_vsize.width != 0) - video_stream_set_preview_size(videoStream, core->video_conf.preview_vsize); - video_stream_set_fps(videoStream, linphone_core_get_preferred_framerate(core)); - if (lp_config_get_int(linphone_core_get_config(core), "video", "nowebcam_uses_normal_fps", 0)) + if (q->getCore()->getCCore()->video_conf.preview_vsize.width != 0) + video_stream_set_preview_size(videoStream, q->getCore()->getCCore()->video_conf.preview_vsize); + video_stream_set_fps(videoStream, linphone_core_get_preferred_framerate(q->getCore()->getCCore())); + if (lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "video", "nowebcam_uses_normal_fps", 0)) videoStream->staticimage_webcam_fps_optimization = false; - const LinphoneVideoDefinition *vdef = linphone_core_get_preferred_video_definition(core); + const LinphoneVideoDefinition *vdef = linphone_core_get_preferred_video_definition(q->getCore()->getCCore()); MSVideoSize vsize; vsize.width = static_cast(linphone_video_definition_get_width(vdef)); vsize.height = static_cast(linphone_video_definition_get_height(vdef)); video_stream_set_sent_video_size(videoStream, vsize); - video_stream_enable_self_view(videoStream, core->video_conf.selfview); + video_stream_enable_self_view(videoStream, q->getCore()->getCCore()->video_conf.selfview); if (videoWindowId) video_stream_set_native_window_id(videoStream, videoWindowId); - else if (core->video_window_id) - video_stream_set_native_window_id(videoStream, core->video_window_id); - if (core->preview_window_id) - video_stream_set_native_preview_window_id(videoStream, core->preview_window_id); - video_stream_use_preview_video_window(videoStream, core->use_preview_window); + else if (q->getCore()->getCCore()->video_window_id) + video_stream_set_native_window_id(videoStream, q->getCore()->getCCore()->video_window_id); + if (q->getCore()->getCCore()->preview_window_id) + video_stream_set_native_preview_window_id(videoStream, q->getCore()->getCCore()->preview_window_id); + video_stream_use_preview_video_window(videoStream, q->getCore()->getCCore()->use_preview_window); const char *rtpAddr = (vstream->rtp_addr[0] != '\0') ? vstream->rtp_addr : resultDesc->addr; const char *rtcpAddr = (vstream->rtcp_addr[0] != '\0') ? vstream->rtcp_addr : resultDesc->addr; bool isMulticast = ms_is_multicast(rtpAddr); @@ -2870,14 +2874,14 @@ void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { dir = MediaStreamRecvOnly; else dir = MediaStreamSendOnly; - } else if ((vstream->dir == SalStreamSendOnly) && core->video_conf.capture) + } else if ((vstream->dir == SalStreamSendOnly) && q->getCore()->getCCore()->video_conf.capture) dir = MediaStreamSendOnly; - else if ((vstream->dir == SalStreamRecvOnly) && core->video_conf.display) + else if ((vstream->dir == SalStreamRecvOnly) && q->getCore()->getCCore()->video_conf.display) dir = MediaStreamRecvOnly; else if (vstream->dir == SalStreamSendRecv) { - if (core->video_conf.display && core->video_conf.capture) + if (q->getCore()->getCCore()->video_conf.display && q->getCore()->getCCore()->video_conf.capture) dir = MediaStreamSendRecv; - else if (core->video_conf.display) + else if (q->getCore()->getCCore()->video_conf.display) dir = MediaStreamRecvOnly; else dir = MediaStreamSendOnly; @@ -2901,22 +2905,22 @@ void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { configureAdaptiveRateControl(&videoStream->ms, getCurrentParams()->getUsedVideoCodec(), true); log->video_enabled = true; video_stream_set_direction(videoStream, dir); - lInfo() << "startVideoStream: device_rotation=" << core->device_rotation; - video_stream_set_device_rotation(videoStream, core->device_rotation); - video_stream_set_freeze_on_error(videoStream, !!lp_config_get_int(linphone_core_get_config(core), "video", "freeze_on_error", 1)); + lInfo() << "startVideoStream: device_rotation=" << q->getCore()->getCCore()->device_rotation; + video_stream_set_device_rotation(videoStream, q->getCore()->getCCore()->device_rotation); + video_stream_set_freeze_on_error(videoStream, !!lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "video", "freeze_on_error", 1)); if (isMulticast) rtp_session_set_multicast_ttl(videoStream->ms.sessions.rtp_session, vstream->ttl); - video_stream_use_video_preset(videoStream, lp_config_get_string(linphone_core_get_config(core), "video", "preset", nullptr)); - if (core->video_conf.reuse_preview_source && source) { + video_stream_use_video_preset(videoStream, lp_config_get_string(linphone_core_get_config(q->getCore()->getCCore()), "video", "preset", nullptr)); + if (q->getCore()->getCCore()->video_conf.reuse_preview_source && source) { lInfo() << "video_stream_start_with_source kept: " << source; video_stream_start_with_source(videoStream, videoProfile, rtpAddr, vstream->rtp_port, rtcpAddr, - linphone_core_rtcp_enabled(core) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port + 1) : 0, + linphone_core_rtcp_enabled(q->getCore()->getCCore()) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port + 1) : 0, usedPt, -1, cam, source); reusedPreview = true; } else { bool ok = true; MSMediaStreamIO io = MS_MEDIA_STREAM_IO_INITIALIZER; - bool useRtpIo = lp_config_get_int(linphone_core_get_config(core), "video", "rtp_io", false); + bool useRtpIo = lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "video", "rtp_io", false); if (useRtpIo) { io.input.type = io.output.type = MSResourceRtp; io.input.session = io.output.session = createVideoRtpIoSession(); @@ -2931,7 +2935,7 @@ void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { } if (ok) { video_stream_start_from_io(videoStream, videoProfile, rtpAddr, vstream->rtp_port, rtcpAddr, - (linphone_core_rtcp_enabled(core) && !isMulticast) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port + 1) : 0, + (linphone_core_rtcp_enabled(q->getCore()->getCCore()) && !isMulticast) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port + 1) : 0, usedPt, &io); } } @@ -2965,6 +2969,7 @@ void MediaSessionPrivate::startVideoStream (LinphoneCallState targetState) { } void MediaSessionPrivate::stopAudioStream () { + L_Q(); if (audioStream) { updateReportingMediaInfo(LINPHONE_CALL_STATS_AUDIO); media_stream_reclaim_sessions(&audioStream->ms, &sessions[mainAudioStreamIndex]); @@ -2973,7 +2978,7 @@ void MediaSessionPrivate::stopAudioStream () { ms_filter_call_method(audioStream->ec, MS_ECHO_CANCELLER_GET_STATE_STRING, &stateStr); if (stateStr) { lInfo() << "Writing echo canceler state, " << (int)strlen(stateStr) << " bytes"; - lp_config_write_relative_file(linphone_core_get_config(core), ecStateStore.c_str(), stateStr); + lp_config_write_relative_file(linphone_core_get_config(q->getCore()->getCCore()), ecStateStore.c_str(), stateStr); } } audio_stream_get_local_rtp_stats(audioStream, &log->local_stats); @@ -2983,7 +2988,7 @@ void MediaSessionPrivate::stopAudioStream () { linphone_conference_on_call_stream_stopping(lc->conf_ctx, call); } #endif - ms_bandwidth_controller_remove_stream(core->bw_controller, &audioStream->ms); + ms_bandwidth_controller_remove_stream(q->getCore()->getCCore()->bw_controller, &audioStream->ms); audio_stream_stop(audioStream); updateRtpStats(audioStats, mainAudioStreamIndex); audioStream = nullptr; @@ -2998,14 +3003,15 @@ void MediaSessionPrivate::stopAudioStream () { } void MediaSessionPrivate::stopStreams () { + L_Q(); if (audioStream || videoStream || textStream) { if (audioStream && videoStream) audio_stream_unlink_video(audioStream, videoStream); stopAudioStream(); stopVideoStream(); stopTextStream(); - if (core->msevq) - ms_event_queue_skip(core->msevq); + if (q->getCore()->getCCore()->msevq) + ms_event_queue_skip(q->getCore()->getCCore()->msevq); } if (audioProfile) { @@ -3032,7 +3038,7 @@ void MediaSessionPrivate::stopStreams () { rtpIoVideoProfile = nullptr; } - linphone_core_soundcard_hint_check(core); + linphone_core_soundcard_hint_check(q->getCore()->getCCore()); } void MediaSessionPrivate::stopTextStream () { @@ -3054,11 +3060,12 @@ void MediaSessionPrivate::stopTextStream () { void MediaSessionPrivate::stopVideoStream () { #ifdef VIDEO_ENABLED + L_Q(); if (videoStream) { updateReportingMediaInfo(LINPHONE_CALL_STATS_VIDEO); media_stream_reclaim_sessions(&videoStream->ms, &sessions[mainVideoStreamIndex]); fillLogStats(&videoStream->ms); - ms_bandwidth_controller_remove_stream(core->bw_controller, &videoStream->ms); + ms_bandwidth_controller_remove_stream(q->getCore()->getCCore()->bw_controller, &videoStream->ms); video_stream_stop(videoStream); updateRtpStats(videoStats, mainVideoStreamIndex); videoStream = nullptr; @@ -3121,8 +3128,8 @@ void MediaSessionPrivate::updateFrozenPayloads (SalMediaDescription *result) { void MediaSessionPrivate::updateStreams (SalMediaDescription *newMd, LinphoneCallState targetState) { L_Q(); - if (!((state == LinphoneCallIncomingEarlyMedia) && linphone_core_get_ring_during_incoming_early_media(core))) - linphone_core_stop_ringing(core); + if (!((state == LinphoneCallIncomingEarlyMedia) && linphone_core_get_ring_during_incoming_early_media(q->getCore()->getCCore()))) + linphone_core_stop_ringing(q->getCore()->getCCore()); if (!newMd) { lError() << "updateStreams() called with null media description"; return; @@ -3155,7 +3162,7 @@ void MediaSessionPrivate::updateStreams (SalMediaDescription *newMd, LinphoneCal /* We were in early media, now we want to enable real media */ allMuted = false; if (audioStream) - linphone_core_enable_mic(core, linphone_core_mic_enabled(core)); + linphone_core_enable_mic(q->getCore()->getCCore(), linphone_core_mic_enabled(q->getCore()->getCCore())); #ifdef VIDEO_ENABLED if (videoStream && cameraEnabled) q->enableCamera(q->cameraEnabled()); @@ -3200,8 +3207,8 @@ void MediaSessionPrivate::updateStreams (SalMediaDescription *newMd, LinphoneCal if (getParams()->earlyMediaSendingEnabled() && (state == LinphoneCallOutgoingEarlyMedia)) prepareEarlyMediaForking(); startStreams(targetState); - if ((state == LinphoneCallPausing) && pausedByApp && (bctbx_list_size(core->calls) == 1)) - linphone_core_play_named_tone(core, LinphoneToneCallOnHold); + if ((state == LinphoneCallPausing) && pausedByApp && (bctbx_list_size(q->getCore()->getCCore()->calls) == 1)) + linphone_core_play_named_tone(q->getCore()->getCCore(), LinphoneToneCallOnHold); updateFrozenPayloads(newMd); if (oldMd) @@ -3338,9 +3345,10 @@ bool MediaSessionPrivate::isEncryptionMandatory () const { } int MediaSessionPrivate::mediaParametersChanged (SalMediaDescription *oldMd, SalMediaDescription *newMd) { + L_Q(); if (getParams()->getPrivate()->getInConference() != getCurrentParams()->getPrivate()->getInConference()) return SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION; - if (upBandwidth != linphone_core_get_upload_bandwidth(core)) + if (upBandwidth != linphone_core_get_upload_bandwidth(q->getCore()->getCCore())) return SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION; if (localDescChanged) { char *differences = sal_media_description_print_differences(localDescChanged); @@ -3466,7 +3474,7 @@ void MediaSessionPrivate::updateReportingMediaInfo (int statsType) { reporting_session_report_t * report = log->reporting.reports[statsType]; STR_REASSIGN(report->info.call_id, ms_strdup(log->call_id)); - STR_REASSIGN(report->local_metrics.user_agent, ms_strdup(linphone_core_get_user_agent(core))); + STR_REASSIGN(report->local_metrics.user_agent, ms_strdup(linphone_core_get_user_agent(q->getCore()->getCCore()))); STR_REASSIGN(report->remote_metrics.user_agent, ms_strdup(q->getRemoteUserAgent().c_str())); /* RFC states: "LocalGroupID provides the identification for the purposes of aggregation for the local endpoint" */ @@ -3604,6 +3612,7 @@ void MediaSessionPrivate::reportBandwidth () { } void MediaSessionPrivate::reportBandwidthForStream (MediaStream *ms, LinphoneStreamType type) { + L_Q(); LinphoneCallStats *stats = nullptr; if (type == LinphoneStreamTypeAudio) { stats = audioStats; @@ -3622,7 +3631,7 @@ void MediaSessionPrivate::reportBandwidthForStream (MediaStream *ms, LinphoneStr _linphone_call_stats_set_ip_family_of_remote(stats, active ? (ortp_stream_is_ipv6(&ms->sessions.rtp_session->rtp.gs) ? LinphoneAddressFamilyInet6 : LinphoneAddressFamilyInet) : LinphoneAddressFamilyUnspec); - if (core->send_call_stats_periodical_updates) { + if (q->getCore()->getCCore()->send_call_stats_periodical_updates) { if (active) linphone_call_stats_update(stats, ms); _linphone_call_stats_set_updated(stats, _linphone_call_stats_get_updated(stats) | LINPHONE_CALL_STATS_PERIODICAL_UPDATE); @@ -3646,12 +3655,12 @@ void MediaSessionPrivate::handleIncomingReceivedStateInIncomingNotification () { L_Q(); /* Try to be best-effort in giving real local or routable contact address for 100Rel case */ setContactOp(); - bool proposeEarlyMedia = !!lp_config_get_int(linphone_core_get_config(core), "sip", "incoming_calls_early_media", false); + bool proposeEarlyMedia = !!lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "sip", "incoming_calls_early_media", false); if (proposeEarlyMedia) q->acceptEarlyMedia(); else op->notify_ringing(false); - if (op->get_replaces() && !!lp_config_get_int(linphone_core_get_config(core), "sip", "auto_answer_replacing_calls", 1)) + if (op->get_replaces() && !!lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "sip", "auto_answer_replacing_calls", 1)) q->accept(); } @@ -3725,15 +3734,16 @@ LinphoneStatus MediaSessionPrivate::startAcceptUpdate (LinphoneCallState nextSta } LinphoneStatus MediaSessionPrivate::startUpdate (const string &subject) { + L_Q(); fillMulticastMediaAddresses(); if (!getParams()->getPrivate()->getNoUserConsent()) makeLocalMediaDescription(); - if (!core->sip_conf.sdp_200_ack) + if (!q->getCore()->getCCore()->sip_conf.sdp_200_ack) op->set_local_media_description(localDesc); else op->set_local_media_description(nullptr); LinphoneStatus result = CallSessionPrivate::startUpdate(subject); - if (core->sip_conf.sdp_200_ack) { + if (q->getCore()->getCCore()->sip_conf.sdp_200_ack) { /* We are NOT offering, set local media description after sending the call so that we are ready to * process the remote offer when it will arrive. */ op->set_local_media_description(localDesc); @@ -3856,6 +3866,7 @@ void MediaSessionPrivate::updateCurrentParams () const { // ----------------------------------------------------------------------------- void MediaSessionPrivate::accept (const MediaSessionParams *msp) { + L_Q(); if (msp) { setParams(new MediaSessionParams(*msp)); iceAgent->prepare(localDesc, true); @@ -3868,10 +3879,10 @@ void MediaSessionPrivate::accept (const MediaSessionParams *msp) { /* Give a chance a set card prefered sampling frequency */ if (localDesc->streams[0].max_rate > 0) { lInfo() << "Configuring prefered card sampling rate to [" << localDesc->streams[0].max_rate << "]"; - if (core->sound_conf.play_sndcard) - ms_snd_card_set_preferred_sample_rate(core->sound_conf.play_sndcard, localDesc->streams[0].max_rate); - if (core->sound_conf.capt_sndcard) - ms_snd_card_set_preferred_sample_rate(core->sound_conf.capt_sndcard, localDesc->streams[0].max_rate); + if (q->getCore()->getCCore()->sound_conf.play_sndcard) + ms_snd_card_set_preferred_sample_rate(q->getCore()->getCCore()->sound_conf.play_sndcard, localDesc->streams[0].max_rate); + if (q->getCore()->getCCore()->sound_conf.capt_sndcard) + ms_snd_card_set_preferred_sample_rate(q->getCore()->getCCore()->sound_conf.capt_sndcard, localDesc->streams[0].max_rate); } #if 0 @@ -3894,7 +3905,7 @@ void MediaSessionPrivate::accept (const MediaSessionParams *msp) { LinphoneStatus MediaSessionPrivate::acceptUpdate (const CallSessionParams *csp, LinphoneCallState nextState, const string &stateInfo) { L_Q(); SalMediaDescription *desc = op->get_remote_media_description(); - bool keepSdpVersion = !!lp_config_get_int(linphone_core_get_config(core), "sip", "keep_sdp_version", 0); + bool keepSdpVersion = !!lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "sip", "keep_sdp_version", 0); if (keepSdpVersion && (desc->session_id == remoteSessionId) && (desc->session_ver == remoteSessionVer)) { /* Remote has sent an INVITE with the same SDP as before, so send a 200 OK with the same SDP as before. */ lWarning() << "SDP version has not changed, send same SDP as before"; @@ -3911,7 +3922,7 @@ LinphoneStatus MediaSessionPrivate::acceptUpdate (const CallSessionParams *csp, getParams()->enableVideoMulticast(false); } } - if (getParams()->videoEnabled() && !linphone_core_video_enabled(core)) { + if (getParams()->videoEnabled() && !linphone_core_video_enabled(q->getCore()->getCCore())) { lWarning() << "Requested video but video support is globally disabled. Refusing video"; getParams()->enableVideo(false); } @@ -3977,12 +3988,13 @@ void MediaSessionPrivate::realTimeTextCharacterReceived (MSFilter *f, unsigned i // ----------------------------------------------------------------------------- void MediaSessionPrivate::stunAuthRequestedCb (const char *realm, const char *nonce, const char **username, const char **password, const char **ha1) { + L_Q(); /* Get the username from the nat policy or the proxy config */ LinphoneProxyConfig *proxy = nullptr; if (destProxy) proxy = destProxy; else - proxy = linphone_core_get_default_proxy_config(core); + proxy = linphone_core_get_default_proxy_config(q->getCore()->getCCore()); if (!proxy) return; const char * user = nullptr; @@ -4001,7 +4013,7 @@ void MediaSessionPrivate::stunAuthRequestedCb (const char *realm, const char *no if (!user) return; - const LinphoneAuthInfo *authInfo = linphone_core_find_auth_info(core, realm, user, nullptr); + const LinphoneAuthInfo *authInfo = linphone_core_find_auth_info(q->getCore()->getCCore(), realm, user, nullptr); if (!authInfo) { lWarning() << "No auth info found for STUN auth request"; return; @@ -4016,10 +4028,58 @@ void MediaSessionPrivate::stunAuthRequestedCb (const char *realm, const char *no // ============================================================================= -MediaSession::MediaSession (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener) - : CallSession(*new MediaSessionPrivate(conference, params, listener)) { +MediaSession::MediaSession (const shared_ptr &core, shared_ptr me, const CallSessionParams *params, CallSessionListener *listener) + : CallSession(*new MediaSessionPrivate, core) { L_D(); + d->me = me; + d->listener = listener; + + if (params) + d->setParams(new MediaSessionParams(*(reinterpret_cast(params)))); + else + d->setParams(new MediaSessionParams()); + d->setCurrentParams(new MediaSessionParams()); + + d->audioStats = _linphone_call_stats_new(); + d->initStats(d->audioStats, LinphoneStreamTypeAudio); + d->videoStats = _linphone_call_stats_new(); + d->initStats(d->videoStats, LinphoneStreamTypeVideo); + d->textStats = _linphone_call_stats_new(); + d->initStats(d->textStats, LinphoneStreamTypeText); + + int minPort, maxPort; + linphone_core_get_audio_port_range(getCore()->getCCore(), &minPort, &maxPort); + d->setPortConfig(d->mainAudioStreamIndex, make_pair(minPort, maxPort)); + linphone_core_get_video_port_range(getCore()->getCCore(), &minPort, &maxPort); + d->setPortConfig(d->mainVideoStreamIndex, make_pair(minPort, maxPort)); + linphone_core_get_text_port_range(getCore()->getCCore(), &minPort, &maxPort); + d->setPortConfig(d->mainTextStreamIndex, make_pair(minPort, maxPort)); + + memset(d->sessions, 0, sizeof(d->sessions)); d->iceAgent = new IceAgent(*this); + + lInfo() << "New MediaSession [" << this << "] initialized (LinphoneCore version: " << linphone_core_get_version() << ")"; +} + +MediaSession::~MediaSession () { + L_D(); + if (d->audioStats) + linphone_call_stats_unref(d->audioStats); + if (d->videoStats) + linphone_call_stats_unref(d->videoStats); + if (d->textStats) + linphone_call_stats_unref(d->textStats); + if (d->natPolicy) + linphone_nat_policy_unref(d->natPolicy); + if (d->stunClient) + delete d->stunClient; + delete d->iceAgent; + if (d->localDesc) + sal_media_description_unref(d->localDesc); + if (d->biggestDesc) + sal_media_description_unref(d->biggestDesc); + if (d->resultDesc) + sal_media_description_unref(d->resultDesc); } // ----------------------------------------------------------------------------- @@ -4094,7 +4154,7 @@ void MediaSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cf if (d->destProxy) d->natPolicy = linphone_proxy_config_get_nat_policy(d->destProxy); if (!d->natPolicy) - d->natPolicy = linphone_core_get_nat_policy(d->core); + d->natPolicy = linphone_core_get_nat_policy(getCore()->getCCore()); linphone_nat_policy_ref(d->natPolicy); if (direction == LinphoneCallOutgoing) { @@ -4119,7 +4179,7 @@ void MediaSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cf cleanedFrom.clean(); d->getLocalIp(cleanedFrom); d->setParams(new MediaSessionParams()); - d->params->initDefault(d->core); + d->params->initDefault(getCore()); d->initializeParamsAccordingToIncomingCallParams(); SalMediaDescription *md = d->op->get_remote_media_description(); if (d->natPolicy && linphone_nat_policy_ice_enabled(d->natPolicy)) { @@ -4152,7 +4212,7 @@ bool MediaSession::initiateOutgoing () { bool defer = CallSession::initiateOutgoing(); d->initializeStreams(); if (linphone_nat_policy_ice_enabled(d->natPolicy)) { - if (d->core->sip_conf.sdp_200_ack) + if (getCore()->getCCore()->sip_conf.sdp_200_ack) lWarning() << "ICE is not supported when sending INVITE without SDP"; else { /* Defer the start of the call after the ICE gathering process */ @@ -4166,7 +4226,7 @@ void MediaSession::iterate (time_t currentRealTime, bool oneSecondElapsed) { L_D(); int elapsed = (int)(currentRealTime - d->log->start_date_time); d->executeBackgroundTasks(oneSecondElapsed); - if ((d->state == LinphoneCallOutgoingInit) && (elapsed >= d->core->sip_conf.delayed_timeout)) { + if ((d->state == LinphoneCallOutgoingInit) && (elapsed >= getCore()->getCCore()->sip_conf.delayed_timeout)) { if (d->iceAgent->hasSession()) { lWarning() << "ICE candidates gathering from [" << linphone_nat_policy_get_stun_server(d->natPolicy) << "] has not finished yet, proceed with the call without ICE anyway"; d->iceAgent->deleteSession(); @@ -4190,11 +4250,11 @@ LinphoneStatus MediaSession::resume () { return -1; } if (!d->getParams()->getPrivate()->getInConference()) { - if (linphone_core_sound_resources_locked(d->core)) { + if (linphone_core_sound_resources_locked(getCore()->getCCore())) { lWarning() << "Cannot resume MediaSession " << this << " because another call is locking the sound resources"; return -1; } - linphone_core_preempt_sound_resources(d->core); + linphone_core_preempt_sound_resources(getCore()->getCCore()); lInfo() << "Resuming MediaSession " << this; } d->automaticallyPaused = false; @@ -4207,7 +4267,7 @@ LinphoneStatus MediaSession::resume () { audio_stream_play(d->audioStream, nullptr); d->makeLocalMediaDescription(); sal_media_description_set_dir(d->localDesc, SalStreamSendRecv); - if (!d->core->sip_conf.sdp_200_ack) + if (!getCore()->getCCore()->sip_conf.sdp_200_ack) d->op->set_local_media_description(d->localDesc); else d->op->set_local_media_description(nullptr); @@ -4219,7 +4279,7 @@ LinphoneStatus MediaSession::resume () { d->setState(LinphoneCallResuming,"Resuming"); if (!d->getParams()->getPrivate()->getInConference() && d->listener) d->listener->onSetCurrentSession(getSharedFromThis()); - if (d->core->sip_conf.sdp_200_ack) { + if (getCore()->getCCore()->sip_conf.sdp_200_ack) { /* We are NOT offering, set local media description after sending the call so that we are ready to * process the remote offer when it will arrive. */ d->op->set_local_media_description(d->localDesc); @@ -4235,7 +4295,7 @@ void MediaSession::sendVfuRequest () { && d->videoStream && media_stream_get_state(&d->videoStream->ms) == MSStreamStarted) { // || sal_media_description_has_implicit_avpf((const SalMediaDescription *)call->resultdesc) lInfo() << "Request Full Intra Request on CallSession [" << this << "]"; video_stream_send_fir(d->videoStream); - } else if (d->core->sip_conf.vfu_with_info) { + } else if (getCore()->getCCore()->sip_conf.vfu_with_info) { lInfo() << "Request SIP INFO FIR on CallSession [" << this << "]"; if (d->state == LinphoneCallStreamsRunning) d->op->send_vfu_request(); @@ -4250,7 +4310,7 @@ void MediaSession::startIncomingNotification () { d->op->set_local_media_description(d->localDesc); SalMediaDescription *md = d->op->get_final_media_description(); if (md) { - if (sal_media_description_empty(md) || linphone_core_incompatible_security(d->core, md)) { + if (sal_media_description_empty(md) || linphone_core_incompatible_security(getCore()->getCCore(), md)) { LinphoneErrorInfo *ei = linphone_error_info_new(); linphone_error_info_set(ei, nullptr, LinphoneReasonNotAcceptable, 488, "Not acceptable here", nullptr); #if 0 @@ -4269,16 +4329,16 @@ void MediaSession::startIncomingNotification () { int MediaSession::startInvite (const Address *destination, const string &subject, const Content *content) { L_D(); - linphone_core_stop_dtmf_stream(d->core); + linphone_core_stop_dtmf_stream(getCore()->getCCore()); d->makeLocalMediaDescription(); - if (d->core->ringstream && d->core->sound_conf.play_sndcard && d->core->sound_conf.capt_sndcard) { + if (getCore()->getCCore()->ringstream && getCore()->getCCore()->sound_conf.play_sndcard && getCore()->getCCore()->sound_conf.capt_sndcard) { /* Give a chance to set card prefered sampling frequency */ if (d->localDesc->streams[0].max_rate > 0) - ms_snd_card_set_preferred_sample_rate(d->core->sound_conf.play_sndcard, d->localDesc->streams[0].max_rate); - if (!d->core->use_files) - audio_stream_prepare_sound(d->audioStream, d->core->sound_conf.play_sndcard, d->core->sound_conf.capt_sndcard); + ms_snd_card_set_preferred_sample_rate(getCore()->getCCore()->sound_conf.play_sndcard, d->localDesc->streams[0].max_rate); + if (!getCore()->getCCore()->use_files) + audio_stream_prepare_sound(d->audioStream, getCore()->getCCore()->sound_conf.play_sndcard, getCore()->getCCore()->sound_conf.capt_sndcard); } - if (!d->core->sip_conf.sdp_200_ack) { + if (!getCore()->getCCore()->sip_conf.sdp_200_ack) { /* We are offering, set local media description before sending the call */ d->op->set_local_media_description(d->localDesc); } @@ -4289,7 +4349,7 @@ int MediaSession::startInvite (const Address *destination, const string &subject d->stopStreams(); return result; } - if (d->core->sip_conf.sdp_200_ack) { + if (getCore()->getCCore()->sip_conf.sdp_200_ack) { /* We are NOT offering, set local media description after sending the call so that we are ready to process the remote offer when it will arrive. */ d->op->set_local_media_description(d->localDesc); @@ -4343,14 +4403,14 @@ LinphoneStatus MediaSession::update (const MediaSessionParams *msp, const string } else { #ifdef VIDEO_ENABLED if (d->videoStream && (d->state == LinphoneCallStreamsRunning)) { - const LinphoneVideoDefinition *vdef = linphone_core_get_preferred_video_definition(d->core); + const LinphoneVideoDefinition *vdef = linphone_core_get_preferred_video_definition(getCore()->getCCore()); MSVideoSize vsize; vsize.width = static_cast(linphone_video_definition_get_width(vdef)); vsize.height = static_cast(linphone_video_definition_get_height(vdef)); video_stream_set_sent_video_size(d->videoStream, vsize); - video_stream_set_fps(d->videoStream, linphone_core_get_preferred_framerate(d->core)); - if (d->cameraEnabled && (d->videoStream->cam != d->core->video_conf.device)) - video_stream_change_camera(d->videoStream, d->core->video_conf.device); + video_stream_set_fps(d->videoStream, linphone_core_get_preferred_framerate(getCore()->getCCore())); + if (d->cameraEnabled && (d->videoStream->cam != getCore()->getCCore()->video_conf.device)) + video_stream_change_camera(d->videoStream, getCore()->getCCore()->video_conf.device); else video_stream_update_video_params(d->videoStream); } @@ -4425,7 +4485,7 @@ bool MediaSession::cameraEnabled () const { bool MediaSession::echoCancellationEnabled () const { L_D(); if (!d->audioStream || !d->audioStream->ec) - return !!linphone_core_echo_cancellation_enabled(d->core); + return !!linphone_core_echo_cancellation_enabled(getCore()->getCCore()); bool val; ms_filter_call_method(d->audioStream->ec, MS_ECHO_CANCELLER_GET_BYPASS_MODE, &val); @@ -4436,7 +4496,7 @@ bool MediaSession::echoLimiterEnabled () const { L_D(); if (d->audioStream) return d->audioStream->el_type !=ELInactive; - return !!linphone_core_echo_limiter_enabled(d->core); + return !!linphone_core_echo_limiter_enabled(getCore()->getCCore()); } void MediaSession::enableCamera (bool value) { @@ -4473,7 +4533,7 @@ void MediaSession::enableEchoLimiter (bool value) { L_D(); if (d->audioStream) { if (value) { - string type = lp_config_get_string(linphone_core_get_config(d->core), "sound", "el_type", "mic"); + string type = lp_config_get_string(linphone_core_get_config(getCore()->getCCore()), "sound", "el_type", "mic"); if (type == "mic") audio_stream_enable_echo_limiter(d->audioStream, ELControlMic); else if (type == "full") @@ -4610,9 +4670,7 @@ const MediaSessionParams * MediaSession::getRemoteParams () { if (d->op){ SalMediaDescription *md = d->op->get_remote_media_description(); if (md) { - if (d->remoteParams) - delete d->remoteParams; - d->remoteParams = new MediaSessionParams(); + d->setRemoteParams(new MediaSessionParams()); unsigned int nbAudioStreams = sal_media_description_nb_active_streams_of_type(md, SalAudio); for (unsigned int i = 0; i < nbAudioStreams; i++) { SalStreamDescription *sd = sal_media_description_get_active_stream_of_type(md, SalAudio, i); @@ -4635,7 +4693,7 @@ const MediaSessionParams * MediaSession::getRemoteParams () { d->getRemoteParams()->enableRealtimeText(true); } if (!d->getRemoteParams()->videoEnabled()) { - if ((md->bandwidth > 0) && (md->bandwidth <= linphone_core_get_edge_bw(d->core))) + if ((md->bandwidth > 0) && (md->bandwidth <= linphone_core_get_edge_bw(getCore()->getCCore()))) d->getRemoteParams()->enableLowBandwidth(true); } if (md->name[0] != '\0') @@ -4650,7 +4708,7 @@ const MediaSessionParams * MediaSession::getRemoteParams () { if (ch) { /* Instanciate a remote_params only if a SIP message was received before (custom headers indicates this) */ if (!d->remoteParams) - d->remoteParams = new MediaSessionParams(); + d->setRemoteParams(new MediaSessionParams()); d->getRemoteParams()->getPrivate()->setCustomHeaders(ch); } return d->getRemoteParams(); diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index ef3ca87c2..e8021265a 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -28,8 +28,10 @@ LINPHONE_BEGIN_NAMESPACE class CallPrivate; +class Core; class IceAgent; class MediaSessionPrivate; +class Participant; class LINPHONE_PUBLIC MediaSession : public CallSession { friend class Call; @@ -37,7 +39,8 @@ class LINPHONE_PUBLIC MediaSession : public CallSession { friend class IceAgent; public: - MediaSession (const Conference &conference, const CallSessionParams *params, CallSessionListener *listener); + MediaSession (const std::shared_ptr &core, std::shared_ptr me, const CallSessionParams *params, CallSessionListener *listener); + virtual ~MediaSession (); LinphoneStatus accept (const MediaSessionParams *msp = nullptr); LinphoneStatus acceptEarlyMedia (const MediaSessionParams *msp = nullptr); diff --git a/src/nat/ice-agent.cpp b/src/nat/ice-agent.cpp index 1c1937d36..d94aa46b3 100644 --- a/src/nat/ice-agent.cpp +++ b/src/nat/ice-agent.cpp @@ -22,6 +22,7 @@ #include "private.h" #include "conference/session/media-session-p.h" +#include "core/core.h" #include "logger/logger.h" #include "ice-agent.h" @@ -43,7 +44,7 @@ void IceAgent::checkSession (IceRole role, bool isReinvite) { if (iceSession) return; - LinphoneConfig *config = linphone_core_get_config(mediaSession.getPrivate()->getCore()); + LinphoneConfig *config = linphone_core_get_config(mediaSession.getCore()->getCCore()); if (isReinvite && (lp_config_get_int(config, "net", "allow_late_ice", 0) == 0)) return; @@ -128,7 +129,7 @@ bool IceAgent::prepare (const SalMediaDescription *localDesc, bool incomingOffer bool hasVideo = false; if (incomingOffer) { remoteDesc = mediaSession.getPrivate()->getOp()->get_remote_media_description(); - hasVideo = linphone_core_video_enabled(mediaSession.getPrivate()->getCore()) && + hasVideo = linphone_core_video_enabled(mediaSession.getCore()->getCCore()) && linphone_core_media_description_contains_video_stream(remoteDesc); } else hasVideo = mediaSession.getMediaParams()->videoEnabled(); @@ -214,7 +215,7 @@ void IceAgent::updateFromRemoteMediaDescription ( if (!iceParamsFoundInRemoteMediaDescription(remoteDesc)) { // Response from remote does not contain mandatory ICE attributes, delete the session. deleteSession(); - mediaSession.getPrivate()->enableSymmetricRtp(!!linphone_core_symmetric_rtp_enabled(mediaSession.getPrivate()->getCore())); + mediaSession.getPrivate()->enableSymmetricRtp(!!linphone_core_symmetric_rtp_enabled(mediaSession.getCore()->getCCore())); return; } @@ -237,7 +238,7 @@ void IceAgent::updateFromRemoteMediaDescription ( if (ice_session_nb_check_lists(iceSession) == 0) { deleteSession(); - mediaSession.getPrivate()->enableSymmetricRtp(!!linphone_core_symmetric_rtp_enabled(mediaSession.getPrivate()->getCore())); + mediaSession.getPrivate()->enableSymmetricRtp(!!linphone_core_symmetric_rtp_enabled(mediaSession.getCore()->getCCore())); } } @@ -319,7 +320,7 @@ void IceAgent::updateLocalMediaDescriptionFromIce (SalMediaDescription *desc) { if (!sal_stream_description_active(stream) || !cl) continue; if (ice_check_list_state(cl) == ICL_Completed) { - LinphoneConfig *config = linphone_core_get_config(mediaSession.getPrivate()->getCore()); + LinphoneConfig *config = linphone_core_get_config(mediaSession.getCore()->getCCore()); // TODO: Remove `ice_uses_nortpproxy` option, let's say in December 2018. bool useNoRtpProxy = !!lp_config_get_int(config, "sip", "ice_uses_nortpproxy", false); if (useNoRtpProxy) @@ -413,7 +414,7 @@ void IceAgent::addLocalIceCandidates (int family, const char *addr, IceCheckList LinphoneCallStats *audioStats = mediaSession.getPrivate()->getStats(LinphoneStreamTypeAudio); _linphone_call_stats_set_ice_state(audioStats, LinphoneIceStateInProgress); } - LinphoneCore *core = mediaSession.getPrivate()->getCore(); + LinphoneCore *core = mediaSession.getCore()->getCCore(); if (linphone_core_video_enabled(core) && videoCl && (ice_check_list_state(videoCl) != ICL_Completed) && !ice_check_list_candidates_gathered(videoCl)) { int rtpPort = mediaSession.getPrivate()->getRtpPort(LinphoneStreamTypeVideo); int rtcpPort = mediaSession.getPrivate()->getRtcpPort(LinphoneStreamTypeVideo); @@ -583,7 +584,7 @@ int IceAgent::gatherIceCandidates () { lWarning() << "Failed to resolve STUN server for ICE gathering, continuing without STUN"; } else lWarning() << "ICE is used without STUN server"; - LinphoneCore *core = mediaSession.getPrivate()->getCore(); + LinphoneCore *core = mediaSession.getCore()->getCCore(); ice_session_enable_forced_relay(iceSession, core->forced_ice_relay); ice_session_enable_short_turn_refresh(iceSession, core->short_turn_refresh); @@ -649,6 +650,7 @@ const struct addrinfo *IceAgent::getIcePreferredStunServerAddrinfo (const struct if (it->ai_family == AF_INET6) { struct sockaddr_storage ss; socklen_t sslen = sizeof(ss); + memset(&ss, 0, sizeof(ss)); bctbx_sockaddr_remove_nat64_mapping(it->ai_addr, (struct sockaddr *)&ss, &sslen); if (ss.ss_family == AF_INET) break; } diff --git a/src/nat/stun-client.cpp b/src/nat/stun-client.cpp index a6550f46f..09e7f798e 100644 --- a/src/nat/stun-client.cpp +++ b/src/nat/stun-client.cpp @@ -30,13 +30,13 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE int StunClient::run (int audioPort, int videoPort, int textPort) { - if (linphone_core_ipv6_enabled(core)) { + if (linphone_core_ipv6_enabled(getCore()->getCCore())) { lWarning() << "STUN support is not implemented for ipv6"; return -1; } - if (!linphone_core_get_stun_server(core)) + if (!linphone_core_get_stun_server(getCore()->getCCore())) return -1; - const struct addrinfo *ai = linphone_core_get_stun_server_addrinfo(core); + const struct addrinfo *ai = linphone_core_get_stun_server_addrinfo(getCore()->getCCore()); if (!ai) { lError() << "Could not obtain STUN server addrinfo"; return -1; @@ -47,13 +47,13 @@ int StunClient::run (int audioPort, int videoPort, int textPort) { if (sockAudio == -1) return -1; ortp_socket_t sockVideo = -1; - if (linphone_core_video_enabled(core)) { + if (linphone_core_video_enabled(getCore()->getCCore())) { sockVideo = createStunSocket(videoPort); if (sockVideo == -1) return -1; } ortp_socket_t sockText = -1; - if (linphone_core_realtime_text_enabled(core)) { + if (linphone_core_realtime_text_enabled(getCore()->getCCore())) { sockText = createStunSocket(textPort); if (sockText == -1) return -1; diff --git a/src/nat/stun-client.h b/src/nat/stun-client.h index 1de314d6e..9258456f3 100644 --- a/src/nat/stun-client.h +++ b/src/nat/stun-client.h @@ -24,23 +24,25 @@ #include +#include "core/core.h" +#include "core/core-accessor.h" + #include "linphone/utils/general.h" // ============================================================================= L_DECL_C_STRUCT_PREFIX_LESS(SalMediaDescription); -L_DECL_C_STRUCT(LinphoneCore); LINPHONE_BEGIN_NAMESPACE -class StunClient { +class StunClient : public CoreAccessor { struct Candidate { std::string address; int port; }; public: - StunClient (LinphoneCore *core) : core(core) {} + StunClient (const std::shared_ptr &core) : CoreAccessor(core) {} int run (int audioPort, int videoPort, int textPort); void updateMediaDescription (SalMediaDescription *md) const; @@ -62,7 +64,6 @@ public: int sendStunRequest (ortp_socket_t sock, const struct sockaddr *server, socklen_t addrlen, int id, bool changeAddr); private: - LinphoneCore *core = nullptr; Candidate audioCandidate; Candidate videoCandidate; Candidate textCandidate; diff --git a/src/utils/payload-type-handler.cpp b/src/utils/payload-type-handler.cpp index 74ccb749e..8cd84da96 100644 --- a/src/utils/payload-type-handler.cpp +++ b/src/utils/payload-type-handler.cpp @@ -128,7 +128,7 @@ void PayloadTypeHandler::assignPayloadTypeNumbers (const bctbx_list_t *codecs) { } if (number == -1) { - int dynNumber = core->codecs_conf.dyn_pt; + int dynNumber = getCore()->getCCore()->codecs_conf.dyn_pt; while (dynNumber < 127) { if (isPayloadTypeNumberAvailable(codecs, dynNumber, nullptr)) { payload_type_set_number(pt, dynNumber); @@ -159,7 +159,7 @@ void PayloadTypeHandler::assignPayloadTypeNumbers (const bctbx_list_t *codecs) { bctbx_list_t *PayloadTypeHandler::createSpecialPayloadTypes (const bctbx_list_t *codecs) { bctbx_list_t *result = createTelephoneEventPayloadTypes(codecs); - if (linphone_core_generic_comfort_noise_enabled(core)) { + if (linphone_core_generic_comfort_noise_enabled(getCore()->getCCore())) { OrtpPayloadType *cn = payload_type_clone(&payload_type_cn); payload_type_set_number(cn, 13); result = bctbx_list_append(result, cn); @@ -179,8 +179,8 @@ bctbx_list_t *PayloadTypeHandler::createTelephoneEventPayloadTypes (const bctbx_ // Let it choose the number dynamically as for normal codecs. payload_type_set_number(tev, -1); // But for first telephone-event, prefer the number that was configured in the core. - if (!result && isPayloadTypeNumberAvailable(codecs, core->codecs_conf.telephone_event_pt, nullptr)) - payload_type_set_number(tev, core->codecs_conf.telephone_event_pt); + if (!result && isPayloadTypeNumberAvailable(codecs, getCore()->getCCore()->codecs_conf.telephone_event_pt, nullptr)) + payload_type_set_number(tev, getCore()->getCCore()->codecs_conf.telephone_event_pt); result = bctbx_list_append(result, tev); } return result; @@ -189,8 +189,8 @@ bctbx_list_t *PayloadTypeHandler::createTelephoneEventPayloadTypes (const bctbx_ bool PayloadTypeHandler::isPayloadTypeUsable (const OrtpPayloadType *pt) { return isPayloadTypeUsableForBandwidth( pt, getMinBandwidth( - linphone_core_get_download_bandwidth(core), - linphone_core_get_upload_bandwidth(core) + linphone_core_get_download_bandwidth(getCore()->getCCore()), + linphone_core_get_upload_bandwidth(getCore()->getCCore()) ) ); } @@ -276,13 +276,13 @@ bctbx_list_t *PayloadTypeHandler::makeCodecsList (SalStreamType type, int bandwi switch (type) { default: case SalAudio: - allCodecs = core->codecs_conf.audio_codecs; + allCodecs = getCore()->getCCore()->codecs_conf.audio_codecs; break; case SalVideo: - allCodecs = core->codecs_conf.video_codecs; + allCodecs = getCore()->getCCore()->codecs_conf.video_codecs; break; case SalText: - allCodecs = core->codecs_conf.text_codecs; + allCodecs = getCore()->getCCore()->codecs_conf.text_codecs; break; } diff --git a/src/utils/payload-type-handler.h b/src/utils/payload-type-handler.h index f5e284fda..f0198812e 100644 --- a/src/utils/payload-type-handler.h +++ b/src/utils/payload-type-handler.h @@ -23,6 +23,8 @@ #include "linphone/utils/general.h" #include "c-wrapper/internal/c-sal.h" +#include "core/core.h" +#include "core/core-accessor.h" #define PAYLOAD_TYPE_ENABLED PAYLOAD_TYPE_USER_FLAG_0 #define PAYLOAD_TYPE_BITRATE_OVERRIDE PAYLOAD_TYPE_USER_FLAG_3 @@ -30,8 +32,6 @@ // ============================================================================= -L_DECL_C_STRUCT(LinphoneCore); - LINPHONE_BEGIN_NAMESPACE struct VbrCodecBitrate { @@ -40,9 +40,11 @@ struct VbrCodecBitrate { int recommendedBitrate; }; -class PayloadTypeHandler { +class Core; + +class PayloadTypeHandler : public CoreAccessor { public: - explicit PayloadTypeHandler (LinphoneCore *core) : core(core) {} + explicit PayloadTypeHandler (const std::shared_ptr &core) : CoreAccessor(core) {} bctbx_list_t *makeCodecsList (SalStreamType type, int bandwidthLimit, int maxCodecs, const bctbx_list_t *previousList); @@ -69,8 +71,6 @@ private: static const int rtpHeaderSize; static const int ipv4HeaderSize; static const VbrCodecBitrate defaultVbrCodecBitrates[]; - - LinphoneCore *core = nullptr; }; LINPHONE_END_NAMESPACE From 88fb7651f62e5073a61f6b617c8f854603428896 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 30 Nov 2017 14:52:12 +0100 Subject: [PATCH 0941/2215] Call now inherits from Conference instead of including it. --- src/CMakeLists.txt | 6 ++ src/c-wrapper/api/c-call.cpp | 61 ++++++++---- src/call/call-p.h | 26 +---- src/call/call.cpp | 122 ++++++++--------------- src/call/call.h | 18 +--- src/call/local-conference-call-p.h | 42 ++++++++ src/call/local-conference-call.cpp | 57 +++++++++++ src/call/local-conference-call.h | 60 +++++++++++ src/call/remote-conference-call-p.h | 42 ++++++++ src/call/remote-conference-call.cpp | 57 +++++++++++ src/call/remote-conference-call.h | 55 ++++++++++ src/conference/participant.h | 4 + src/conference/session/media-session.cpp | 4 +- 13 files changed, 415 insertions(+), 139 deletions(-) create mode 100644 src/call/local-conference-call-p.h create mode 100644 src/call/local-conference-call.cpp create mode 100644 src/call/local-conference-call.h create mode 100644 src/call/remote-conference-call-p.h create mode 100644 src/call/remote-conference-call.cpp create mode 100644 src/call/remote-conference-call.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bf085340b..443273c1e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,6 +31,10 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES call/call-listener.h call/call-p.h call/call.h + call/local-conference-call-p.h + call/local-conference-call.h + call/remote-conference-call-p.h + call/remote-conference-call.h chat/chat-message/chat-message-p.h chat/chat-message/chat-message.h chat/chat-room/basic-chat-room-p.h @@ -160,6 +164,8 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES c-wrapper/api/c-participant.cpp c-wrapper/internal/c-sal.cpp call/call.cpp + call/local-conference-call.cpp + call/remote-conference-call.cpp chat/chat-message/chat-message.cpp chat/chat-room/basic-chat-room.cpp chat/chat-room/chat-room-id.cpp diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 2630d627d..1208cb20d 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -25,7 +25,10 @@ #include "c-wrapper/c-wrapper.h" #include "call/call-p.h" #include "call/call.h" +#include "call/local-conference-call.h" +#include "call/remote-conference-call.h" #include "conference/params/media-session-params-p.h" +#include "core/core.h" // ============================================================================= @@ -574,7 +577,7 @@ void linphone_call_notify_ack_processing (LinphoneCall *call, LinphoneHeaders *m // ============================================================================= LinphoneCore *linphone_call_get_core (const LinphoneCall *call) { - return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getCore(); + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getCore()->getCCore(); } LinphoneCallState linphone_call_get_state (const LinphoneCall *call) { @@ -1140,26 +1143,44 @@ void linphone_call_set_user_data (LinphoneCall *call, void *ud) { // ============================================================================= LinphoneCall *linphone_call_new_outgoing (LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg) { - LinphoneCall *call = L_INIT(Call); - L_SET_CPP_PTR_FROM_C_OBJECT(call, make_shared(call, lc, LinphoneCallOutgoing, - *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), - cfg, nullptr, L_GET_CPP_PTR_FROM_C_OBJECT(params))); - call->currentParamsCache = linphone_call_params_new_for_wrapper(); - call->paramsCache = linphone_call_params_new_for_wrapper(); - call->remoteParamsCache = linphone_call_params_new_for_wrapper(); - call->remoteAddressCache = linphone_address_new(nullptr); - return call; + LinphoneCall *lcall = L_INIT(Call); + shared_ptr call; + string confType = lp_config_get_string(linphone_core_get_config(lc), "misc", "conference_type", "local"); + if (confType == "remote") { + call = make_shared(lc->cppCore, LinphoneCallOutgoing, + *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), + cfg, nullptr, L_GET_CPP_PTR_FROM_C_OBJECT(params)); + } else { + call = make_shared(lc->cppCore, LinphoneCallOutgoing, + *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), + cfg, nullptr, L_GET_CPP_PTR_FROM_C_OBJECT(params)); + } + L_SET_CPP_PTR_FROM_C_OBJECT(lcall, call); + lcall->currentParamsCache = linphone_call_params_new_for_wrapper(); + lcall->paramsCache = linphone_call_params_new_for_wrapper(); + lcall->remoteParamsCache = linphone_call_params_new_for_wrapper(); + lcall->remoteAddressCache = linphone_address_new(nullptr); + return lcall; } LinphoneCall *linphone_call_new_incoming (LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, LinphonePrivate::SalCallOp *op) { - LinphoneCall *call = L_INIT(Call); - L_SET_CPP_PTR_FROM_C_OBJECT(call, make_shared(call, lc, LinphoneCallIncoming, - *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), - nullptr, op, nullptr)); - call->currentParamsCache = linphone_call_params_new_for_wrapper(); - call->paramsCache = linphone_call_params_new_for_wrapper(); - call->remoteParamsCache = linphone_call_params_new_for_wrapper(); - call->remoteAddressCache = linphone_address_new(nullptr); - L_GET_PRIVATE_FROM_C_OBJECT(call)->initiateIncoming(); - return call; + LinphoneCall *lcall = L_INIT(Call); + shared_ptr call; + string confType = lp_config_get_string(linphone_core_get_config(lc), "misc", "conference_type", "local"); + if (confType == "remote") { + call = make_shared(lc->cppCore, LinphoneCallIncoming, + *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), + nullptr, op, nullptr); + } else { + call = make_shared(lc->cppCore, LinphoneCallIncoming, + *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), + nullptr, op, nullptr); + } + L_SET_CPP_PTR_FROM_C_OBJECT(lcall, call); + lcall->currentParamsCache = linphone_call_params_new_for_wrapper(); + lcall->paramsCache = linphone_call_params_new_for_wrapper(); + lcall->remoteParamsCache = linphone_call_params_new_for_wrapper(); + lcall->remoteAddressCache = linphone_address_new(nullptr); + L_GET_PRIVATE_FROM_C_OBJECT(lcall)->initiateIncoming(); + return lcall; } diff --git a/src/call/call-p.h b/src/call/call-p.h index a5885c403..c2f5ec9a5 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -32,21 +32,10 @@ LINPHONE_BEGIN_NAMESPACE -class CallPrivate : - public ObjectPrivate, - CallListener { +class CallPrivate : public ObjectPrivate, public CallListener { public: - CallPrivate ( - LinphoneCall *call, - LinphoneCore *core, - LinphoneCallDir direction, - const Address &from, - const Address &to, - LinphoneProxyConfig *cfg, - SalOp *op, - const MediaSessionParams *msp - ); - virtual ~CallPrivate (); + CallPrivate () = default; + virtual ~CallPrivate () = default; void initiateIncoming (); bool initiateOutgoing (); @@ -55,11 +44,8 @@ public: int startInvite (const Address *destination); - std::shared_ptr getActiveSession () const; + virtual std::shared_ptr getActiveSession () const { return nullptr; } bool getAudioMuted () const; - Conference *getConference () const { - return conference; - } LinphoneProxyConfig *getDestProxy () const; IceSession *getIceSession () const; @@ -87,10 +73,6 @@ private: void onFirstVideoFrameDecoded () override; void onResetFirstVideoFrameDecoded () override; - LinphoneCall *lcall = nullptr; - - LinphoneCore *core = nullptr; - Conference *conference = nullptr; mutable LinphonePlayer *player = nullptr; CallCallbackObj nextVideoFrameDecoded; diff --git a/src/call/call.cpp b/src/call/call.cpp index b353d2a44..0463764e8 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -19,9 +19,7 @@ #include "c-wrapper/c-wrapper.h" #include "call-p.h" -#include "conference/local-conference.h" -#include "conference/participant-p.h" -#include "conference/remote-conference.h" +#include "conference/session/call-session-p.h" #include "conference/session/media-session-p.h" #include "logger/logger.h" @@ -31,31 +29,6 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -CallPrivate::CallPrivate ( - LinphoneCall *call, - LinphoneCore *core, - LinphoneCallDir direction, - const Address &from, - const Address &to, - LinphoneProxyConfig *cfg, - SalOp *op, - const MediaSessionParams *msp -) : lcall(call), core(core) { - nextVideoFrameDecoded._func = nullptr; - nextVideoFrameDecoded._user_data = nullptr; -} - -CallPrivate::~CallPrivate () { - if (conference) - delete conference; -} - -// ----------------------------------------------------------------------------- - -shared_ptr CallPrivate::getActiveSession () const { - return conference->getActiveParticipant()->getPrivate()->getSession(); -} - bool CallPrivate::getAudioMuted () const { return static_pointer_cast(getActiveSession())->getPrivate()->getAudioMuted(); } @@ -112,21 +85,24 @@ void CallPrivate::createPlayer () const { // ----------------------------------------------------------------------------- void CallPrivate::onAckBeingSent (LinphoneHeaders *headers) { - if (lcall) - linphone_call_notify_ack_processing(lcall, headers, false); + L_Q(); + linphone_call_notify_ack_processing(L_GET_C_BACK_PTR(q), headers, false); } void CallPrivate::onAckReceived (LinphoneHeaders *headers) { - if (lcall) - linphone_call_notify_ack_processing(lcall, headers, true); + L_Q(); + linphone_call_notify_ack_processing(L_GET_C_BACK_PTR(q), headers, true); } void CallPrivate::onCallSetReleased () { - if (lcall) - linphone_call_unref(lcall); + L_Q(); + linphone_call_unref(L_GET_C_BACK_PTR(q)); } void CallPrivate::onCallSetTerminated () { + L_Q(); + LinphoneCall *lcall = L_GET_C_BACK_PTR(q); + LinphoneCore *core = q->getCore()->getCCore(); if (lcall) { if (lcall == core->current_call) { lInfo() << "Resetting the current call"; @@ -150,12 +126,14 @@ void CallPrivate::onCallSetTerminated () { } void CallPrivate::onCallStateChanged (LinphoneCallState state, const string &message) { - if (lcall) - linphone_call_notify_state_changed(lcall, state, message.c_str()); + L_Q(); + linphone_call_notify_state_changed(L_GET_C_BACK_PTR(q), state, message.c_str()); } void CallPrivate::onCheckForAcceptation () { - bctbx_list_t *copy = bctbx_list_copy(linphone_core_get_calls(core)); + L_Q(); + LinphoneCall *lcall = L_GET_C_BACK_PTR(q); + bctbx_list_t *copy = bctbx_list_copy(linphone_core_get_calls(q->getCore()->getCCore())); for (bctbx_list_t *it = copy; it != nullptr; it = bctbx_list_next(it)) { LinphoneCall *call = reinterpret_cast(bctbx_list_get_data(it)); if (call == lcall) continue; @@ -176,78 +154,63 @@ void CallPrivate::onCheckForAcceptation () { } void CallPrivate::onIncomingCallStarted () { - if (lcall) - linphone_core_notify_incoming_call(core, lcall); + L_Q(); + linphone_core_notify_incoming_call(q->getCore()->getCCore(), L_GET_C_BACK_PTR(q)); } void CallPrivate::onIncomingCallToBeAdded () { - if (lcall) /* The call is acceptable so we can now add it to our list */ - linphone_core_add_call(core, lcall); + L_Q(); + /* The call is acceptable so we can now add it to our list */ + linphone_core_add_call(q->getCore()->getCCore(), L_GET_C_BACK_PTR(q)); } void CallPrivate::onInfoReceived (const LinphoneInfoMessage *im) { - if (lcall) - linphone_call_notify_info_message_received(lcall, im); + L_Q(); + linphone_call_notify_info_message_received(L_GET_C_BACK_PTR(q), im); } void CallPrivate::onEncryptionChanged (bool activated, const string &authToken) { - if (lcall) - linphone_call_notify_encryption_changed(lcall, activated, authToken.empty() ? nullptr : authToken.c_str()); + L_Q(); + linphone_call_notify_encryption_changed(L_GET_C_BACK_PTR(q), activated, authToken.empty() ? nullptr : authToken.c_str()); } void CallPrivate::onStatsUpdated (const LinphoneCallStats *stats) { - if (lcall) - linphone_call_notify_stats_updated(lcall, stats); + L_Q(); + linphone_call_notify_stats_updated(L_GET_C_BACK_PTR(q), stats); } void CallPrivate::onResetCurrentCall () { - core->current_call = nullptr; + L_Q(); + q->getCore()->getCCore()->current_call = nullptr; } void CallPrivate::onSetCurrentCall () { - if (lcall) - core->current_call = lcall; + L_Q(); + q->getCore()->getCCore()->current_call = L_GET_C_BACK_PTR(q); } void CallPrivate::onFirstVideoFrameDecoded () { - if (lcall && nextVideoFrameDecoded._func) { - nextVideoFrameDecoded._func(lcall, nextVideoFrameDecoded._user_data); + L_Q(); + if (nextVideoFrameDecoded._func) { + nextVideoFrameDecoded._func(L_GET_C_BACK_PTR(q), nextVideoFrameDecoded._user_data); nextVideoFrameDecoded._func = nullptr; nextVideoFrameDecoded._user_data = nullptr; } } void CallPrivate::onResetFirstVideoFrameDecoded () { - #ifdef VIDEO_ENABLED - if (lcall && nextVideoFrameDecoded._func) - static_cast(getActiveSession().get())->resetFirstVideoFrameDecoded(); - #endif // ifdef VIDEO_ENABLED +#ifdef VIDEO_ENABLED + if (nextVideoFrameDecoded._func) + static_cast(getActiveSession().get())->resetFirstVideoFrameDecoded(); +#endif // ifdef VIDEO_ENABLED } // ============================================================================= -Call::Call ( - LinphoneCall *call, - LinphoneCore *core, - LinphoneCallDir direction, - const Address &from, - const Address &to, - LinphoneProxyConfig *cfg, - SalCallOp *op, - const MediaSessionParams *msp -) : Object(*new CallPrivate(call, core, direction, from, to, cfg, op, msp)) { +Call::Call (CallPrivate &p, shared_ptr core) : Object(p), CoreAccessor(core) { L_D(); - const Address *myAddress = (direction == LinphoneCallIncoming) ? &to : &from; - string confType = lp_config_get_string(linphone_core_get_config(core), "misc", "conference_type", "local"); - if (confType == "remote") { - d->conference = new RemoteConference(core->cppCore, *myAddress, d); - } else { - d->conference = new LocalConference(core->cppCore, *myAddress, d); - } - const Address *remoteAddress = (direction == LinphoneCallIncoming) ? &from : &to; - d->conference->addParticipant(*remoteAddress, msp, true); - shared_ptr participant = d->conference->getParticipants().front(); - participant->getPrivate()->getSession()->configure(direction, cfg, op, from, to); + d->nextVideoFrameDecoded._func = nullptr; + d->nextVideoFrameDecoded._user_data = nullptr; } // ----------------------------------------------------------------------------- @@ -398,11 +361,6 @@ float Call::getAverageQuality () const { return static_cast(d->getActiveSession().get())->getAverageQuality(); } -LinphoneCore *Call::getCore () const { - L_D(); - return d->core; -} - const MediaSessionParams *Call::getCurrentParams () const { L_D(); return static_cast(d->getActiveSession().get())->getCurrentParams(); diff --git a/src/call/call.h b/src/call/call.h index ca48c4826..85c3dfd5f 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -21,6 +21,7 @@ #define _CALL_CALL_H_ #include "conference/params/media-session-params.h" +#include "core/core-accessor.h" #include "object/object.h" // ============================================================================= @@ -32,22 +33,11 @@ class CallPrivate; class CallSessionPrivate; class MediaSessionPrivate; -class Call : public Object { +class Call : public Object, public CoreAccessor { friend class CallSessionPrivate; friend class MediaSessionPrivate; public: - Call ( - LinphoneCall *call, - LinphoneCore *core, - LinphoneCallDir direction, - const Address &from, - const Address &to, - LinphoneProxyConfig *cfg, - SalCallOp *op, - const MediaSessionParams *msp - ); - LinphoneStatus accept (const MediaSessionParams *msp = nullptr); LinphoneStatus acceptEarlyMedia (const MediaSessionParams *msp = nullptr); LinphoneStatus acceptUpdate (const MediaSessionParams *msp); @@ -78,7 +68,6 @@ public: std::string getAuthenticationToken () const; bool getAuthenticationTokenVerified () const; float getAverageQuality () const; - LinphoneCore *getCore () const; const MediaSessionParams *getCurrentParams () const; float getCurrentQuality () const; LinphoneCallDir getDirection () const; @@ -113,6 +102,9 @@ public: void setNextVideoFrameDecodedCallback (LinphoneCallCbFunc cb, void *user_data); void setSpeakerVolumeGain (float value); +protected: + Call (CallPrivate &p, std::shared_ptr core); + private: L_DECLARE_PRIVATE(Call); L_DISABLE_COPY(Call); diff --git a/src/call/local-conference-call-p.h b/src/call/local-conference-call-p.h new file mode 100644 index 000000000..895f89afe --- /dev/null +++ b/src/call/local-conference-call-p.h @@ -0,0 +1,42 @@ +/* + * local-conference-call-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _LOCAL_CONFERENCE_CALL_P_H_ +#define _LOCAL_CONFERENCE_CALL_P_H_ + +#include "call-p.h" +#include "local-conference-call.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class LocalConferenceCallPrivate : public CallPrivate { +public: + LocalConferenceCallPrivate () = default; + + std::shared_ptr getActiveSession () const override; + +private: + L_DECLARE_PUBLIC(LocalConferenceCall); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _LOCAL_CONFERENCE_CALL_P_H_ diff --git a/src/call/local-conference-call.cpp b/src/call/local-conference-call.cpp new file mode 100644 index 000000000..8e95f37d7 --- /dev/null +++ b/src/call/local-conference-call.cpp @@ -0,0 +1,57 @@ +/* + * local-conference-call.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "conference/local-conference-p.h" +#include "conference/participant-p.h" +#include "local-conference-call-p.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +shared_ptr LocalConferenceCallPrivate::getActiveSession () const { + L_Q(); + return q->getActiveParticipant()->getPrivate()->getSession(); +} + +// ============================================================================= + +LocalConferenceCall::LocalConferenceCall ( + shared_ptr core, + LinphoneCallDir direction, + const Address &from, + const Address &to, + LinphoneProxyConfig *cfg, + SalCallOp *op, + const MediaSessionParams *msp + ) + : Call(*new LocalConferenceCallPrivate(), core), + LocalConference(getCore(), IdentityAddress((direction == LinphoneCallIncoming) ? to : from), getPrivate()) { + addParticipant((direction == LinphoneCallIncoming) ? from : to, msp, true); + shared_ptr participant = getParticipants().front(); + participant->getPrivate()->getSession()->configure(direction, cfg, op, from, to); +} + +shared_ptr LocalConferenceCall::getCore () const { + return Call::getCore(); +} + +LINPHONE_END_NAMESPACE diff --git a/src/call/local-conference-call.h b/src/call/local-conference-call.h new file mode 100644 index 000000000..66153c7a8 --- /dev/null +++ b/src/call/local-conference-call.h @@ -0,0 +1,60 @@ +/* + * local-conference-call.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _LOCAL_CONFERENCE_CALL_H_ +#define _LOCAL_CONFERENCE_CALL_H_ + +// From coreapi +#include "private.h" + +#include "call/call.h" +#include "conference/local-conference.h" + +#include "linphone/types.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class Core; +class LocalConferenceCallPrivate; + +class LocalConferenceCall : public Call, public LocalConference { +public: + // TODO: Make me private! + LocalConferenceCall ( + std::shared_ptr core, + LinphoneCallDir direction, + const Address &from, + const Address &to, + LinphoneProxyConfig *cfg, + SalCallOp *op, + const MediaSessionParams *msp + ); + + std::shared_ptr getCore () const; + +private: + L_DECLARE_PRIVATE(LocalConferenceCall); + L_DISABLE_COPY(LocalConferenceCall); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _LOCAL_CONFERENCE_CALL_H_ diff --git a/src/call/remote-conference-call-p.h b/src/call/remote-conference-call-p.h new file mode 100644 index 000000000..9a55f3e4d --- /dev/null +++ b/src/call/remote-conference-call-p.h @@ -0,0 +1,42 @@ +/* + * remote-conference-call-p.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _REMOTE_CONFERENCE_CALL_P_H_ +#define _REMOTE_CONFERENCE_CALL_P_H_ + +#include "call/call-p.h" +#include "remote-conference-call.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class RemoteConferenceCallPrivate : public CallPrivate { +public: + RemoteConferenceCallPrivate () = default; + + std::shared_ptr getActiveSession () const override; + +private: + L_DECLARE_PUBLIC(RemoteConferenceCall); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _REMOTE_CONFERENCE_CALL_P_H_ diff --git a/src/call/remote-conference-call.cpp b/src/call/remote-conference-call.cpp new file mode 100644 index 000000000..59d7feb19 --- /dev/null +++ b/src/call/remote-conference-call.cpp @@ -0,0 +1,57 @@ +/* + * remote-conference-call.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "conference/remote-conference-p.h" +#include "conference/participant-p.h" +#include "remote-conference-call-p.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +shared_ptr RemoteConferenceCallPrivate::getActiveSession () const { + L_Q(); + return q->getActiveParticipant()->getPrivate()->getSession(); +} + +// ============================================================================= + +RemoteConferenceCall::RemoteConferenceCall ( + shared_ptr core, + LinphoneCallDir direction, + const Address &from, + const Address &to, + LinphoneProxyConfig *cfg, + SalCallOp *op, + const MediaSessionParams *msp + ) + : Call(*new RemoteConferenceCallPrivate, core), + RemoteConference(core, IdentityAddress((direction == LinphoneCallIncoming) ? to : from), getPrivate()) { + addParticipant((direction == LinphoneCallIncoming) ? from : to, msp, true); + shared_ptr participant = getParticipants().front(); + participant->getPrivate()->getSession()->configure(direction, cfg, op, from, to); +} + +shared_ptr RemoteConferenceCall::getCore () const { + return Call::getCore(); +} + +LINPHONE_END_NAMESPACE diff --git a/src/call/remote-conference-call.h b/src/call/remote-conference-call.h new file mode 100644 index 000000000..a2505cc80 --- /dev/null +++ b/src/call/remote-conference-call.h @@ -0,0 +1,55 @@ +/* + * remote-conference-call.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _REMOTE_CONFERENCE_CALL_H_ +#define _REMOTE_CONFERENCE_CALL_H_ + +#include "call/call.h" +#include "conference/remote-conference.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class Core; +class RemoteConferenceCallPrivate; + +class LINPHONE_PUBLIC RemoteConferenceCall : public Call, public RemoteConference { +public: + // TODO: Make me private. + RemoteConferenceCall ( + std::shared_ptr core, + LinphoneCallDir direction, + const Address &from, + const Address &to, + LinphoneProxyConfig *cfg, + SalCallOp *op, + const MediaSessionParams *msp + ); + + std::shared_ptr getCore () const; + +private: + L_DECLARE_PRIVATE(RemoteConferenceCall); + L_DISABLE_COPY(RemoteConferenceCall); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _REMOTE_CONFERENCE_CALL_H_ diff --git a/src/conference/participant.h b/src/conference/participant.h index fbfaa2700..f18b7b5ec 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -41,11 +41,15 @@ class Participant : public Object { friend class ClientGroupChatRoomPrivate; friend class Conference; friend class LocalConference; + friend class LocalConferenceCall; + friend class LocalConferenceCallPrivate; friend class LocalConferenceEventHandler; friend class LocalConferenceEventHandlerPrivate; friend class MainDb; friend class MediaSessionPrivate; friend class RemoteConference; + friend class RemoteConferenceCall; + friend class RemoteConferenceCallPrivate; friend class ServerGroupChatRoom; friend class ServerGroupChatRoomPrivate; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index ad39840be..29a802f44 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -897,7 +897,7 @@ int MediaSessionPrivate::selectFixedPort (int streamIndex, pair portRa bool alreadyUsed = false; for (const bctbx_list_t *elem = linphone_core_get_calls(q->getCore()->getCCore()); elem != nullptr; elem = bctbx_list_next(elem)) { LinphoneCall *lcall = reinterpret_cast(bctbx_list_get_data(elem)); - MediaSession *session = dynamic_cast(L_GET_PRIVATE_FROM_C_OBJECT(lcall)->getConference()->getActiveParticipant()->getPrivate()->getSession().get()); + shared_ptr session = static_pointer_cast(L_GET_CPP_PTR_FROM_C_OBJECT(lcall)->getPrivate()->getActiveSession()); int existingPort = session->getPrivate()->mediaPorts[streamIndex].rtpPort; if (existingPort == triedPort) { alreadyUsed = true; @@ -921,7 +921,7 @@ int MediaSessionPrivate::selectRandomPort (int streamIndex, pair portR if (triedPort < portRange.first) triedPort = portRange.first + 2; for (const bctbx_list_t *elem = linphone_core_get_calls(q->getCore()->getCCore()); elem != nullptr; elem = bctbx_list_next(elem)) { LinphoneCall *lcall = reinterpret_cast(bctbx_list_get_data(elem)); - MediaSession *session = dynamic_cast(L_GET_PRIVATE_FROM_C_OBJECT(lcall)->getConference()->getActiveParticipant()->getPrivate()->getSession().get()); + shared_ptr session = static_pointer_cast(L_GET_CPP_PTR_FROM_C_OBJECT(lcall)->getPrivate()->getActiveSession()); int existingPort = session->getPrivate()->mediaPorts[streamIndex].rtpPort; if (existingPort == triedPort) { alreadyUsed = true; From 57e9fbd1c47f50ff672497c24dfb37287aeb413a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 30 Nov 2017 15:46:34 +0100 Subject: [PATCH 0942/2215] Fix once and for all the random port selection in the media session. --- src/conference/session/media-session.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 29a802f44..bd6bb9f82 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -916,8 +916,11 @@ int MediaSessionPrivate::selectRandomPort (int streamIndex, pair portR L_Q(); for (int nbTries = 0; nbTries < 100; nbTries++) { bool alreadyUsed = false; + unsigned int rangeSize = static_cast(portRange.second - portRange.first); + unsigned int randomInRangeSize = ortp_random() % rangeSize; unsigned int mask = 1; - int triedPort = static_cast((ortp_random() % static_cast((portRange.second - portRange.first) + portRange.first)) & ~mask); + unsigned int realRandom = randomInRangeSize + static_cast(portRange.first); + int triedPort = static_cast(realRandom & ~mask); if (triedPort < portRange.first) triedPort = portRange.first + 2; for (const bctbx_list_t *elem = linphone_core_get_calls(q->getCore()->getCCore()); elem != nullptr; elem = bctbx_list_next(elem)) { LinphoneCall *lcall = reinterpret_cast(bctbx_list_get_data(elem)); From 89ed9caeebc3e371bdb92ddf3328978da18ba9eb Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 30 Nov 2017 17:13:22 +0100 Subject: [PATCH 0943/2215] Rename isReadOnly() to hasBeenLeft() in ChatRoom. --- include/linphone/api/c-chat-room.h | 6 +++--- src/c-wrapper/api/c-chat-room.cpp | 4 ++-- src/chat/chat-room/basic-chat-room.cpp | 2 +- src/chat/chat-room/basic-chat-room.h | 2 +- src/chat/chat-room/chat-room.h | 2 +- src/chat/chat-room/client-group-chat-room.cpp | 6 +++--- src/chat/chat-room/client-group-chat-room.h | 4 ++-- src/chat/chat-room/server-group-chat-room-stub.cpp | 2 +- src/chat/chat-room/server-group-chat-room.h | 2 +- src/db/main-db.cpp | 2 +- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index a566a5829..42c6b7dee 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -274,11 +274,11 @@ LINPHONE_PUBLIC LinphoneChatRoomCbs * linphone_chat_room_get_callbacks (const Li LINPHONE_PUBLIC LinphoneChatRoomState linphone_chat_room_get_state (const LinphoneChatRoom *cr); /** - * Return whether or not the chat room is read only. + * Return whether or not the chat room has been left. * @param[in] cr LinphoneChatRoom object - * @return whether or not the chat room is read only + * @return whether or not the chat room has been left */ -LINPHONE_PUBLIC bool_t linphone_chat_room_is_read_only (const LinphoneChatRoom *cr); +LINPHONE_PUBLIC bool_t linphone_chat_room_has_been_left (const LinphoneChatRoom *cr); /** * Add a participant to a chat room. This may fail if this type of chat room does not handle participants. diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 667312688..e4622b267 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -244,8 +244,8 @@ LinphoneChatRoomState linphone_chat_room_get_state (const LinphoneChatRoom *cr) return (LinphoneChatRoomState)L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getState(); } -bool_t linphone_chat_room_is_read_only (const LinphoneChatRoom *cr) { - return (bool_t)L_GET_CPP_PTR_FROM_C_OBJECT(cr)->isReadOnly(); +bool_t linphone_chat_room_has_been_left (const LinphoneChatRoom *cr) { + return (bool_t)L_GET_CPP_PTR_FROM_C_OBJECT(cr)->hasBeenLeft(); } void linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr) { diff --git a/src/chat/chat-room/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp index 5e9d70d8a..885fc025d 100644 --- a/src/chat/chat-room/basic-chat-room.cpp +++ b/src/chat/chat-room/basic-chat-room.cpp @@ -51,7 +51,7 @@ BasicChatRoom::CapabilitiesMask BasicChatRoom::getCapabilities () const { return static_cast(Capabilities::Basic); } -bool BasicChatRoom::isReadOnly () const { +bool BasicChatRoom::hasBeenLeft () const { return false; } diff --git a/src/chat/chat-room/basic-chat-room.h b/src/chat/chat-room/basic-chat-room.h index c546f35d1..18f5531d5 100644 --- a/src/chat/chat-room/basic-chat-room.h +++ b/src/chat/chat-room/basic-chat-room.h @@ -33,7 +33,7 @@ class LINPHONE_PUBLIC BasicChatRoom : public ChatRoom { public: CapabilitiesMask getCapabilities () const override; - bool isReadOnly () const override; + bool hasBeenLeft () const override; const IdentityAddress &getConferenceAddress () const override; diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index f71ee7f84..f1dd42157 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -57,7 +57,7 @@ public: time_t getLastUpdateTime () const; virtual CapabilitiesMask getCapabilities () const = 0; - virtual bool isReadOnly () const = 0; + virtual bool hasBeenLeft () const = 0; std::shared_ptr getLastMessageInHistory () const; diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 541da2aa9..bb72ded64 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -104,7 +104,7 @@ ClientGroupChatRoom::ClientGroupChatRoom ( const string &subject, list> &&participants, unsigned int lastNotifyId, - bool isReadOnly + bool hasBeenLeft ) : ChatRoom(*new ClientGroupChatRoomPrivate, core, ChatRoomId(peerAddress, me->getAddress())), RemoteConference(core, me->getAddress(), nullptr) { L_D(); @@ -115,7 +115,7 @@ RemoteConference(core, me->getAddress(), nullptr) { dConference->subject = subject; dConference->participants = move(participants); - d->state = isReadOnly ? ChatRoom::State::Terminated : ChatRoom::State::Created; + d->state = hasBeenLeft ? ChatRoom::State::Terminated : ChatRoom::State::Created; getMe()->getPrivate()->setAdmin(me->isAdmin()); @@ -131,7 +131,7 @@ ClientGroupChatRoom::CapabilitiesMask ClientGroupChatRoom::getCapabilities () co return static_cast(Capabilities::Conference); } -bool ClientGroupChatRoom::isReadOnly () const { +bool ClientGroupChatRoom::hasBeenLeft () const { return getState() != State::Created; } diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 481b04377..05efc6ae7 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -46,13 +46,13 @@ public: const std::string &subject, std::list> &&participants, unsigned int lastNotifyId, - bool isReadOnly + bool hasBeenLeft ); std::shared_ptr getCore () const; CapabilitiesMask getCapabilities () const override; - bool isReadOnly () const override; + bool hasBeenLeft () const override; const IdentityAddress &getConferenceAddress () const override; diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index c0bfb39f1..cc145aaf5 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -85,7 +85,7 @@ int ServerGroupChatRoom::getCapabilities () const { return 0; } -bool ServerGroupChatRoom::isReadOnly () const { +bool ServerGroupChatRoom::hasBeenLeft () const { return true; } diff --git a/src/chat/chat-room/server-group-chat-room.h b/src/chat/chat-room/server-group-chat-room.h index 0f68deef5..27479e6d1 100644 --- a/src/chat/chat-room/server-group-chat-room.h +++ b/src/chat/chat-room/server-group-chat-room.h @@ -40,7 +40,7 @@ public: ServerGroupChatRoom (const std::shared_ptr &core, SalCallOp *op); CapabilitiesMask getCapabilities () const override; - bool isReadOnly () const override; + bool hasBeenLeft () const override; const IdentityAddress &getConferenceAddress () const override; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 596f326e2..6b391029c 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -247,7 +247,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), const tm &creationTime = Utils::getTimeTAsTm(chatRoom->getCreationTime()); const int &capabilities = static_cast(chatRoom->getCapabilities()); const string &subject = chatRoom->getSubject(); - const int &flags = chatRoom->isReadOnly(); + const int &flags = chatRoom->hasBeenLeft(); *session << "INSERT INTO chat_room (" " peer_sip_address_id, local_sip_address_id, creation_time, last_update_time, capabilities, subject, flags" ") VALUES (:peerSipAddressId, :localSipAddressId, :creationTime, :lastUpdateTime, :capabilities, :subject, :flags)", From 71282b25987f373a9f2217c312a2867270461938 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 1 Dec 2017 10:12:31 +0100 Subject: [PATCH 0944/2215] Implement Call::setParams(). --- src/c-wrapper/api/c-call.cpp | 9 +-------- src/call/call.cpp | 5 +++++ src/call/call.h | 1 + src/conference/session/media-session.cpp | 8 ++++++++ src/conference/session/media-session.h | 1 + 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 1208cb20d..6d890e89d 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -1102,14 +1102,7 @@ const bctbx_list_t *linphone_call_get_callbacks_list(const LinphoneCall *call) { } void linphone_call_set_params (LinphoneCall *call, const LinphoneCallParams *params) { -#if 0 - if ( call->state == LinphoneCallOutgoingInit || call->state == LinphoneCallIncomingReceived){ - _linphone_call_set_new_params(call, params); - } - else { - ms_error("linphone_call_set_params() invalid state %s to call this function", linphone_call_state_to_string(call->state)); - } -#endif + L_GET_CPP_PTR_FROM_C_OBJECT(call)->setParams(L_GET_CPP_PTR_FROM_C_OBJECT(params)); } const LinphoneCallParams *linphone_call_get_params (LinphoneCall *call) { diff --git a/src/call/call.cpp b/src/call/call.cpp index 0463764e8..7f82b6d01 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -525,6 +525,11 @@ void Call::setNextVideoFrameDecodedCallback (LinphoneCallCbFunc cb, void *user_d d->onResetFirstVideoFrameDecoded(); } +void Call::setParams (const MediaSessionParams *msp) { + L_D(); + static_cast(d->getActiveSession().get())->setParams(msp); +} + void Call::setSpeakerVolumeGain (float value) { L_D(); static_cast(d->getActiveSession().get())->setSpeakerVolumeGain(value); diff --git a/src/call/call.h b/src/call/call.h index 85c3dfd5f..980d46d20 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -100,6 +100,7 @@ public: void setMicrophoneVolumeGain (float value); void setNativeVideoWindowId (void *id); void setNextVideoFrameDecodedCallback (LinphoneCallCbFunc cb, void *user_data); + void setParams (const MediaSessionParams *msp); void setSpeakerVolumeGain (float value); protected: diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index bd6bb9f82..6cdbb1561 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -4826,6 +4826,14 @@ void MediaSession::setNativeVideoWindowId (void *id) { #endif } +void MediaSession::setParams (const MediaSessionParams *msp) { + L_D(); + if ((d->state == LinphoneCallOutgoingInit) || (d->state == LinphoneCallIncomingReceived)) + d->setParams(msp ? new MediaSessionParams(*msp) : nullptr); + else + lError() << "MediaSession::setParams(): Invalid state %s", linphone_call_state_to_string(d->state); +} + void MediaSession::setSpeakerVolumeGain (float value) { L_D(); if (d->audioStream) diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index e8021265a..046101931 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -96,6 +96,7 @@ public: void setAuthenticationTokenVerified (bool value); void setMicrophoneVolumeGain (float value); void setNativeVideoWindowId (void *id); + void setParams (const MediaSessionParams *msp); void setSpeakerVolumeGain (float value); private: From 7e6b57a04908cc70fcb44e488ca89bdbf26e3690 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 1 Dec 2017 10:26:06 +0100 Subject: [PATCH 0945/2215] Small improvement of setState on ChatMessage in reception --- src/chat/chat-message/chat-message.cpp | 3 ++- src/chat/chat-room/chat-room.cpp | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index bab4b5db6..25f63b6cf 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -327,11 +327,12 @@ LinphoneReason ChatMessagePrivate::receive () { shared_ptr core = q->getCore(); shared_ptr chatRoom = q->getChatRoom(); + setState(ChatMessage::State::Delivered); + // --------------------------------------- // Start of message modification // --------------------------------------- - if ((currentRecvStep &ChatMessagePrivate::Step::Cpim) == ChatMessagePrivate::Step::Cpim) { lInfo() << "Cpim step already done, skipping"; } else { diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 00e99d7d7..090fd3811 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -183,7 +183,6 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa msg->setInternalContent(content); msg->getPrivate()->setTime(salMsg->time); - msg->getPrivate()->setState(ChatMessage::State::Delivered); msg->setImdnMessageId(op->get_call_id()); const SalCustomHeader *ch = op->get_recv_custom_header(); From e5e123ea96b22b84ac8272ea174ca9effb689ddf Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 1 Dec 2017 10:37:56 +0100 Subject: [PATCH 0946/2215] add doc for wrapping purposes --- include/linphone/proxy_config.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linphone/proxy_config.h b/include/linphone/proxy_config.h index 238cc4b00..ead6e6663 100644 --- a/include/linphone/proxy_config.h +++ b/include/linphone/proxy_config.h @@ -309,6 +309,11 @@ LINPHONE_PUBLIC void linphone_proxy_config_refresh_register(LinphoneProxyConfig **/ LINPHONE_PUBLIC void linphone_proxy_config_pause_register(LinphoneProxyConfig *cfg); +/** + * Return the contact address of the proxy config. + * @param[in] cfg #LinphoneProxyConfig object. + * @return a #LinphoneAddress correspong to the contact address of the proxy config. +**/ LINPHONE_PUBLIC const LinphoneAddress* linphone_proxy_config_get_contact(const LinphoneProxyConfig *cfg); /** From 13a873196e6bad6250a75af8292da9ddea9fef59 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 1 Dec 2017 10:55:35 +0100 Subject: [PATCH 0947/2215] feat(MainDb): add get unread chat messages impl --- src/chat/chat-room/chat-room.cpp | 10 ++----- src/db/main-db.cpp | 47 ++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 090fd3811..c70159a27 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -443,15 +443,9 @@ void ChatRoom::markAsRead () { if (getUnreadChatMessagesCount() == 0) return; - shared_ptr core = getCore(); - if (!core) - return; - - CorePrivate *dCore = core->getPrivate(); + CorePrivate *dCore = getCore()->getPrivate(); const string peerAddress = getPeerAddress().asString(); - list> chatMessages = dCore->mainDb->getUnreadChatMessages(d->chatRoomId); - - for (auto &chatMessage : chatMessages) + for (auto &chatMessage : dCore->mainDb->getUnreadChatMessages(d->chatRoomId)) chatMessage->sendDisplayNotification(); dCore->mainDb->markChatMessagesAsRead(d->chatRoomId); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 6b391029c..376a41663 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1548,13 +1548,56 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } list> MainDb::getUnreadChatMessages (const ChatRoomId &chatRoomId) const { + L_D(); + + list> chatMessages; + + string query = "SELECT event_id, creation_time FROM conference_chat_message_event WHERE"; + if (chatRoomId.isValid()) + query += " event_id IN (" + " SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" + ") AND"; + + query += " direction = " + Utils::toString(static_cast(ChatMessage::Direction::Incoming)) + + + " AND state <> " + Utils::toString(static_cast(ChatMessage::State::Displayed)); + DurationLogger durationLogger( "Get unread chat messages: (peer=" + chatRoomId.getPeerAddress().asString() + ", local=" + chatRoomId.getLocalAddress().asString() + ")." ); - // TODO. - return list>(); + L_BEGIN_LOG_EXCEPTION + + soci::session *session = d->dbSession.getBackendSession(); + soci::transaction tr(*session); + + long long dbChatRoomId; + if (chatRoomId.isValid()) + dbChatRoomId = d->selectChatRoomId(chatRoomId); + + soci::rowset rows = chatRoomId.isValid() + ? (session->prepare << query, soci::use(dbChatRoomId)) + : (session->prepare << query); + + for (const auto &row : rows) { + long long eventId = d->resolveId(row, 0); + shared_ptr event = d->getEventFromCache(eventId); + + if (!event) + event = d->selectGenericConferenceEvent( + eventId, + EventLog::Type::ConferenceChatMessage, + Utils::getTmAsTimeT(row.get(1)), + chatRoomId + ); + + if (event) + chatMessages.push_back(static_pointer_cast(event)->getChatMessage()); + } + + L_END_LOG_EXCEPTION + + return chatMessages; } shared_ptr MainDb::getLastChatMessage (const ChatRoomId &chatRoomId) const { From 873dda108b41e7a8b56b9b50ad7c6602145f2a7f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 1 Dec 2017 11:00:18 +0100 Subject: [PATCH 0948/2215] Fixed findFriend when using an address with a gruu --- coreapi/friendlist.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/coreapi/friendlist.c b/coreapi/friendlist.c index dd8f8af25..2afd78e33 100644 --- a/coreapi/friendlist.c +++ b/coreapi/friendlist.c @@ -761,25 +761,19 @@ void linphone_friend_list_synchronize_friends_from_server(LinphoneFriendList *li } LinphoneFriend * linphone_friend_list_find_friend_by_address(const LinphoneFriendList *list, const LinphoneAddress *address) { + LinphoneAddress *clean_addr = linphone_address_clone(address); + linphone_address_clean(clean_addr); // Remove any gruu param + return linphone_friend_list_find_friend_by_uri(list, linphone_address_as_string_uri_only(clean_addr)); +} + +LinphoneFriend * linphone_friend_list_find_friend_by_uri(const LinphoneFriendList *list, const char *uri) { LinphoneFriend *result = NULL; - char *uri = linphone_address_as_string_uri_only(address); bctbx_iterator_t* it = bctbx_map_cchar_find_key(list->friends_map_uri, uri); if (!bctbx_iterator_cchar_equals(it, bctbx_map_cchar_end(list->friends_map_uri))) { bctbx_pair_t *pair = bctbx_iterator_cchar_get_pair(it); result = (LinphoneFriend *)bctbx_pair_cchar_get_second(pair); } bctbx_iterator_cchar_delete(it); - ms_free(uri); - return result; -} - -LinphoneFriend * linphone_friend_list_find_friend_by_uri(const LinphoneFriendList *list, const char *uri) { - LinphoneFriend *result = NULL; - LinphoneAddress *address = linphone_address_new(uri); - if(address) { - result = linphone_friend_list_find_friend_by_address(list, address); - linphone_address_unref(address); - } return result; } From 04168f9b48549cfa99416724e145df0b2abb9daa Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 1 Dec 2017 11:18:56 +0100 Subject: [PATCH 0949/2215] feat(MainDb): return empty data on soci exceptions --- src/db/main-db.cpp | 47 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 376a41663..f1f65dcf6 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1260,9 +1260,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), tr.commit(); + return true; + L_END_LOG_EXCEPTION - return true; + // Error. + return false; } bool MainDb::deleteEvent (const shared_ptr &eventLog) { @@ -1298,6 +1301,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), L_END_LOG_EXCEPTION + // Error. return false; } @@ -1394,13 +1398,13 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), L_D(); + list> events; + if (!isConnected()) { lWarning() << "Unable to get conference notified events. Not connected."; - return list>(); + return events; } - list> events; - DurationLogger durationLogger( "Get conference notified events of: (peer=" + chatRoomId.getPeerAddress().asString() + ", local=" + chatRoomId.getLocalAddress().asString() + @@ -1427,9 +1431,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), )); } + return events; + L_END_LOG_EXCEPTION - return events; + // Error. + return list>(); } int MainDb::getChatMessagesCount (const ChatRoomId &chatRoomId) const { @@ -1552,6 +1559,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), list> chatMessages; + if (!isConnected()) { + lWarning() << "Unable to get unread chat messages. Not connected."; + return chatMessages; + } + string query = "SELECT event_id, creation_time FROM conference_chat_message_event WHERE"; if (chatRoomId.isValid()) query += " event_id IN (" @@ -1595,9 +1607,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), chatMessages.push_back(static_pointer_cast(event)->getChatMessage()); } + return chatMessages; + L_END_LOG_EXCEPTION - return chatMessages; + // Error. + return list>(); } shared_ptr MainDb::getLastChatMessage (const ChatRoomId &chatRoomId) const { @@ -1659,9 +1674,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), lWarning() << "Unable to fetch event: " << eventId; } + return chatMessages; + L_END_LOG_EXCEPTION - return chatMessages; + // Error. + return list>(); } list> MainDb::getHistory (const ChatRoomId &chatRoomId, int nLast, FilterMask mask) const { @@ -1739,9 +1757,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), lWarning() << "Unable to fetch event: " << eventId; } + return events; + L_END_LOG_EXCEPTION - return events; + // Error. + return list>(); } void MainDb::cleanHistory (const ChatRoomId &chatRoomId, FilterMask mask) { @@ -1785,13 +1806,14 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), L_D(); + list> chatRooms; + if (!isConnected()) { lWarning() << "Unable to get chat rooms. Not connected."; - return list>(); + return chatRooms; } shared_ptr core = getCore(); - list> chatRooms; DurationLogger durationLogger("Get chat rooms."); @@ -1875,9 +1897,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), chatRooms.push_back(chatRoom); } + return chatRooms; + L_END_LOG_EXCEPTION - return chatRooms; + // Error. + return list>(); } void MainDb::insertChatRoom (const shared_ptr &chatRoom) { From 57f638266db0d30b197c87a8ff22ec3d378f3aa1 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 1 Dec 2017 11:43:56 +0100 Subject: [PATCH 0950/2215] feat(MainDb): create server group chat room from database --- .../chat-room/server-group-chat-room-stub.cpp | 13 +++++++-- src/chat/chat-room/server-group-chat-room.h | 9 ++++++ src/db/main-db.cpp | 28 +++++++++++++------ 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index cc145aaf5..cb16dfd7c 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -78,8 +78,17 @@ void ServerGroupChatRoomPrivate::onChatMessageReceived(const shared_ptr &core, SalCallOp *op) : -ChatRoom(*new ServerGroupChatRoomPrivate, core, ChatRoomId(IdentityAddress(op->get_to()), IdentityAddress(op->get_to()))), -LocalConference(core, IdentityAddress(op->get_to()), nullptr) {} + ChatRoom(*new ServerGroupChatRoomPrivate, core, ChatRoomId(IdentityAddress(op->get_to()), IdentityAddress(op->get_to()))), + LocalConference(core, IdentityAddress(op->get_to()), nullptr) {} + +ServerGroupChatRoom::ServerGroupChatRoom ( + const shared_ptr &core, + const IdentityAddress &peerAddress, + const string &subject, + list> &&participants, + unsigned int lastNotifyId +) : ChatRoom(*new ServerGroupChatRoomPrivate, core, ChatRoomId(peerAddress, peerAddress)), + LocalConference(core, peerAddress, nullptr) {} int ServerGroupChatRoom::getCapabilities () const { return 0; diff --git a/src/chat/chat-room/server-group-chat-room.h b/src/chat/chat-room/server-group-chat-room.h index 27479e6d1..8dec5ee67 100644 --- a/src/chat/chat-room/server-group-chat-room.h +++ b/src/chat/chat-room/server-group-chat-room.h @@ -39,6 +39,15 @@ public: // TODO: Make me private! ServerGroupChatRoom (const std::shared_ptr &core, SalCallOp *op); + // TODO: Same idea. + ServerGroupChatRoom ( + const std::shared_ptr &core, + const IdentityAddress &peerAddress, + const std::string &subject, + std::list> &&participants, + unsigned int lastNotifyId + ); + CapabilitiesMask getCapabilities () const override; bool hasBeenLeft () const override; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index f1f65dcf6..f0b17331f 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -29,6 +29,7 @@ #include "chat/chat-message/chat-message-p.h" #include "chat/chat-room/chat-room-p.h" #include "chat/chat-room/client-group-chat-room.h" +#include "chat/chat-room/server-group-chat-room.h" #include "conference/participant-p.h" #include "content/content-type.h" #include "content/content.h" @@ -1873,15 +1874,24 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), continue; } - chatRoom = make_shared( - core, - chatRoomId.getPeerAddress(), - me, - subject, - move(participants), - lastNotifyId, - !!row.get(8, 0) - ); + if (!linphone_core_conference_server_enabled(core->getCCore())) + chatRoom = make_shared( + core, + chatRoomId.getPeerAddress(), + me, + subject, + move(participants), + lastNotifyId, + !!row.get(8, 0) + ); + else + chatRoom = make_shared( + core, + chatRoomId.getPeerAddress(), + subject, + move(participants), + lastNotifyId + ); } if (!chatRoom) From 55e62ee0916b2f24a87004d472fc112a02015250 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 1 Dec 2017 13:56:52 +0100 Subject: [PATCH 0951/2215] fix(MainDb): use chat room id in get unread chat messages function --- src/db/main-db.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index f0b17331f..bb3b87b07 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1565,14 +1565,16 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return chatMessages; } - string query = "SELECT event_id, creation_time FROM conference_chat_message_event WHERE"; + string query = "SELECT id, creation_time FROM event WHERE" + " id IN (" + " SELECT conference_event.event_id FROM conference_event, conference_chat_message_event" + + " WHERE"; if (chatRoomId.isValid()) - query += " event_id IN (" - " SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" - ") AND"; - - query += " direction = " + Utils::toString(static_cast(ChatMessage::Direction::Incoming)) + - + " AND state <> " + Utils::toString(static_cast(ChatMessage::State::Displayed)); + query += " chat_room_id = :chatRoomId AND "; + " conference_event.event_id = conference_chat_message_event.event_id" + " AND direction = " + Utils::toString(static_cast(ChatMessage::Direction::Incoming)) + + " AND state <> " + Utils::toString(static_cast(ChatMessage::State::Displayed)); + ")"; DurationLogger durationLogger( "Get unread chat messages: (peer=" + chatRoomId.getPeerAddress().asString() + From eb3fbf682d8d177807c84aaa4aecd869dc755fde Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 1 Dec 2017 13:59:16 +0100 Subject: [PATCH 0952/2215] no comment --- src/db/main-db.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index bb3b87b07..8df459b1b 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1567,13 +1567,13 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), string query = "SELECT id, creation_time FROM event WHERE" " id IN (" - " SELECT conference_event.event_id FROM conference_event, conference_chat_message_event" + + " SELECT conference_event.event_id FROM conference_event, conference_chat_message_event" " WHERE"; if (chatRoomId.isValid()) query += " chat_room_id = :chatRoomId AND "; - " conference_event.event_id = conference_chat_message_event.event_id" + query += " conference_event.event_id = conference_chat_message_event.event_id" " AND direction = " + Utils::toString(static_cast(ChatMessage::Direction::Incoming)) + - " AND state <> " + Utils::toString(static_cast(ChatMessage::State::Displayed)); + " AND state <> " + Utils::toString(static_cast(ChatMessage::State::Displayed)) + ")"; DurationLogger durationLogger( From 47cf1d436cdfff29a7b3cb0a4cbfc3a758d78240 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 1 Dec 2017 15:13:45 +0100 Subject: [PATCH 0953/2215] fix(c-chat-room): repair get history function --- src/c-wrapper/api/c-chat-room.cpp | 24 +++++++++--------------- src/chat/chat-room/chat-room.cpp | 13 ++++++------- src/chat/chat-room/chat-room.h | 8 +++++--- src/db/main-db.cpp | 14 +++++++------- 4 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index e4622b267..61cbd97e4 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -196,30 +196,24 @@ void linphone_chat_room_delete_history (LinphoneChatRoom *cr) { } bctbx_list_t *linphone_chat_room_get_history_range (LinphoneChatRoom *cr, int startm, int endm) { - return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistoryRange(startm, endm)); + list> chatMessages; + for (auto &event : L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistoryRange(startm, endm)) + if (event->getType() == LinphonePrivate::EventLog::Type::ConferenceChatMessage) + chatMessages.push_back(static_pointer_cast(event)->getChatMessage()); + + return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(chatMessages); } bctbx_list_t *linphone_chat_room_get_history (LinphoneChatRoom *cr, int nb_message) { - return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistory(nb_message)); + return linphone_chat_room_get_history_range(cr, 0, nb_message); } bctbx_list_t *linphone_chat_room_get_history_events (LinphoneChatRoom *cr, int nb_events) { - return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST( - L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore())->mainDb->getHistory( - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getChatRoomId(), - nb_events - ) - ); + return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistory(nb_events)); } bctbx_list_t *linphone_chat_room_get_history_range_events (LinphoneChatRoom *cr, int begin, int end) { - return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST( - L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore())->mainDb->getHistory( - L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getChatRoomId(), - begin, - end - ) - ); + return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistoryRange(begin, end)); } LinphoneChatMessage *linphone_chat_room_get_last_message_in_history(LinphoneChatRoom *cr) { diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index c70159a27..cf2ca6664 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -406,19 +406,18 @@ shared_ptr ChatRoom::findMessageWithDirection (const string &messag return ret; } -list > ChatRoom::getHistory (int nbMessages) { - return getHistoryRange(0, nbMessages - 1); +list> ChatRoom::getHistory (int nLast) { + return getCore()->getPrivate()->mainDb->getHistory(getChatRoomId(), nLast); +} + +list> ChatRoom::getHistoryRange (int begin, int end) { + return getCore()->getPrivate()->mainDb->getHistoryRange(getChatRoomId(), begin, end); } int ChatRoom::getHistorySize () { return getCore()->getPrivate()->mainDb->getChatMessagesCount(getChatRoomId()); } -list > ChatRoom::getHistoryRange (int startm, int endm) { - // TODO: history. - return list>(); -} - shared_ptr ChatRoom::getLastMessageInHistory() const { return getCore()->getPrivate()->mainDb->getLastChatMessage(getChatRoomId()); } diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index f1dd42157..62c387c52 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -29,6 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class ChatRoomPrivate; +class EventLog; class LINPHONE_PUBLIC ChatRoom : public Object, public CoreAccessor, public ConferenceInterface { friend class ChatMessage; @@ -59,6 +60,10 @@ public: virtual CapabilitiesMask getCapabilities () const = 0; virtual bool hasBeenLeft () const = 0; + std::list> getHistory (int nLast); + std::list> getHistoryRange (int begin, int end); + int getHistorySize (); + std::shared_ptr getLastMessageInHistory () const; // TODO: Remove useless functions. @@ -69,9 +74,6 @@ public: void deleteHistory (); std::shared_ptr findMessage (const std::string &messageId); std::shared_ptr findMessageWithDirection (const std::string &messageId, ChatMessage::Direction direction); - std::list> getHistory (int nbMessages); - int getHistorySize (); - std::list> getHistoryRange (int startm, int endm); int getUnreadChatMessagesCount (); bool isRemoteComposing () const; std::list
      getComposingAddresses () const; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 8df459b1b..98615f710 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1566,14 +1566,14 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } string query = "SELECT id, creation_time FROM event WHERE" - " id IN (" - " SELECT conference_event.event_id FROM conference_event, conference_chat_message_event" - " WHERE"; + " id IN (" + " SELECT conference_event.event_id FROM conference_event, conference_chat_message_event" + " WHERE"; if (chatRoomId.isValid()) - query += " chat_room_id = :chatRoomId AND "; - query += " conference_event.event_id = conference_chat_message_event.event_id" - " AND direction = " + Utils::toString(static_cast(ChatMessage::Direction::Incoming)) + - " AND state <> " + Utils::toString(static_cast(ChatMessage::State::Displayed)) + + query += " chat_room_id = :chatRoomId AND "; + query += " conference_event.event_id = conference_chat_message_event.event_id" + " AND direction = " + Utils::toString(static_cast(ChatMessage::Direction::Incoming)) + + " AND state <> " + Utils::toString(static_cast(ChatMessage::State::Displayed)) + ")"; DurationLogger durationLogger( From d835f509439755bc52be3eb8fb2c79f717475c31 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Fri, 1 Dec 2017 17:34:07 +0100 Subject: [PATCH 0954/2215] Add getAddressWithoutGruu to Identity address and create participant without gruu --- src/address/identity-address.cpp | 6 ++++++ src/address/identity-address.h | 2 ++ src/conference/participant.cpp | 7 +------ src/conference/participant.h | 1 - 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/address/identity-address.cpp b/src/address/identity-address.cpp index b4cd58714..16cc1b965 100644 --- a/src/address/identity-address.cpp +++ b/src/address/identity-address.cpp @@ -130,6 +130,12 @@ bool IdentityAddress::setGruu (const string &gruu) { return true; } +IdentityAddress IdentityAddress::getAddressWithoutGruu () const { + IdentityAddress address(*this); + address.setGruu(""); + return address; +} + string IdentityAddress::asString () const { Address tmpAddress(*this); return tmpAddress.asStringUriOnly(); diff --git a/src/address/identity-address.h b/src/address/identity-address.h index 2d131623e..e6b25d429 100644 --- a/src/address/identity-address.h +++ b/src/address/identity-address.h @@ -57,6 +57,8 @@ public: const std::string &getGruu () const; bool setGruu (const std::string &gruu); + IdentityAddress getAddressWithoutGruu () const; + virtual std::string asString () const; private: diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index 4379eb0c1..aa4b475f4 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -88,12 +88,7 @@ void ParticipantPrivate::removeDevice (const IdentityAddress &gruu) { Participant::Participant (const IdentityAddress &address) : Object(*new ParticipantPrivate) { L_D(); - d->addr = address; -} - -Participant::Participant (IdentityAddress &&address) : Object(*new ParticipantPrivate) { - L_D(); - d->addr = address; + d->addr = address.getAddressWithoutGruu(); } // ----------------------------------------------------------------------------- diff --git a/src/conference/participant.h b/src/conference/participant.h index f18b7b5ec..90fce744a 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -57,7 +57,6 @@ public: L_OVERRIDE_SHARED_FROM_THIS(Participant); explicit Participant (const IdentityAddress &address); - explicit Participant (IdentityAddress &&address); const IdentityAddress &getAddress () const; bool isAdmin () const; From d8b1d318b2033b323b05f486f6467b91ba1206e6 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 1 Dec 2017 18:02:12 +0100 Subject: [PATCH 0955/2215] Fixed findFriendByAddress --- coreapi/friendlist.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/coreapi/friendlist.c b/coreapi/friendlist.c index 2afd78e33..ea5d232cd 100644 --- a/coreapi/friendlist.c +++ b/coreapi/friendlist.c @@ -762,8 +762,11 @@ void linphone_friend_list_synchronize_friends_from_server(LinphoneFriendList *li LinphoneFriend * linphone_friend_list_find_friend_by_address(const LinphoneFriendList *list, const LinphoneAddress *address) { LinphoneAddress *clean_addr = linphone_address_clone(address); - linphone_address_clean(clean_addr); // Remove any gruu param - return linphone_friend_list_find_friend_by_uri(list, linphone_address_as_string_uri_only(clean_addr)); + LinphoneFriend *lf; + linphone_address_set_uri_param(clean_addr, "gr", NULL); // Remove any gruu param + lf = linphone_friend_list_find_friend_by_uri(list, linphone_address_as_string_uri_only(clean_addr)); + linphone_address_unref(clean_addr); + return lf; } LinphoneFriend * linphone_friend_list_find_friend_by_uri(const LinphoneFriendList *list, const char *uri) { From 144790b41f69df7613840dfb40f162defd4fb0eb Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 4 Dec 2017 10:07:44 +0100 Subject: [PATCH 0956/2215] Added linphone_address_remove_param method --- coreapi/friendlist.c | 4 +++- include/linphone/api/c-address.h | 7 +++++++ src/address/address.cpp | 10 ++++++++++ src/address/address.h | 1 + src/c-wrapper/api/c-address.cpp | 4 ++++ 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/coreapi/friendlist.c b/coreapi/friendlist.c index ea5d232cd..0e1a5644e 100644 --- a/coreapi/friendlist.c +++ b/coreapi/friendlist.c @@ -763,7 +763,9 @@ void linphone_friend_list_synchronize_friends_from_server(LinphoneFriendList *li LinphoneFriend * linphone_friend_list_find_friend_by_address(const LinphoneFriendList *list, const LinphoneAddress *address) { LinphoneAddress *clean_addr = linphone_address_clone(address); LinphoneFriend *lf; - linphone_address_set_uri_param(clean_addr, "gr", NULL); // Remove any gruu param + if (linphone_address_has_param(clean_addr, "gr")) { + linphone_address_remove_uri_param(clean_addr, "gr"); + } lf = linphone_friend_list_find_friend_by_uri(list, linphone_address_as_string_uri_only(clean_addr)); linphone_address_unref(clean_addr); return lf; diff --git a/include/linphone/api/c-address.h b/include/linphone/api/c-address.h index f5ad85981..63fb4f3e7 100644 --- a/include/linphone/api/c-address.h +++ b/include/linphone/api/c-address.h @@ -254,6 +254,13 @@ LINPHONE_PUBLIC void linphone_address_set_uri_param (LinphoneAddress *address, c LINPHONE_PUBLIC void linphone_address_set_uri_params (LinphoneAddress *address, const char *params); +/** + * Removes the value of a parameter of the URI of the address + * @param[in] address LinphoneAddress object + * @param[in] uri_param_name The name of the parameter + */ +LINPHONE_PUBLIC void linphone_address_remove_uri_param (LinphoneAddress *address, const char *uri_param_name); + /** * Destroys a LinphoneAddress object (actually calls linphone_address_unref()). * @deprecated Use linphone_address_unref() instead diff --git a/src/address/address.cpp b/src/address/address.cpp index 273fe0a20..5f8c30e34 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -403,4 +403,14 @@ bool Address::setUriParams (const string &uriParams) { return true; } +bool Address::removeUriParam(const string &uriParamName) { + L_D(); + + if (!d->internalAddress) + return false; + + sal_address_remove_uri_param(d->internalAddress, L_STRING_TO_C(uriParamName)); + return true; +} + LINPHONE_END_NAMESPACE diff --git a/src/address/address.h b/src/address/address.h index a34a0081a..5ce007018 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -101,6 +101,7 @@ public: const std::string &getUriParamValue (const std::string &uriParamName) const; bool setUriParam (const std::string &uriParamName, const std::string &uriParamValue = ""); bool setUriParams (const std::string &uriParams); + bool removeUriParam(const std::string &uriParamName); private: L_DECLARE_PRIVATE(Address); diff --git a/src/c-wrapper/api/c-address.cpp b/src/c-wrapper/api/c-address.cpp index 98e51434a..9a3147157 100644 --- a/src/c-wrapper/api/c-address.cpp +++ b/src/c-wrapper/api/c-address.cpp @@ -186,6 +186,10 @@ void linphone_address_set_uri_params (LinphoneAddress *address, const char *para L_GET_CPP_PTR_FROM_C_OBJECT(address)->setUriParams(L_C_TO_STRING(params)); } +void linphone_address_remove_uri_param (LinphoneAddress *address, const char *uri_param_name) { + L_GET_CPP_PTR_FROM_C_OBJECT(address)->removeUriParam(L_C_TO_STRING(uri_param_name)); +} + void linphone_address_destroy (LinphoneAddress *address) { belle_sip_object_unref(address); } From 4f40f34a168a0f591287f1c96ad0788f32f56b4b Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 4 Dec 2017 10:10:10 +0100 Subject: [PATCH 0957/2215] feat(MainDb): add const qualifier on some parameters --- src/db/main-db.cpp | 8 ++++---- src/db/main-db.h | 2 +- src/event-log/event-log.cpp | 2 +- src/event-log/event-log.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 98615f710..786123d2f 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1269,8 +1269,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return false; } - bool MainDb::deleteEvent (const shared_ptr &eventLog) { - EventLogPrivate *dEventLog = eventLog->getPrivate(); + bool MainDb::deleteEvent (const shared_ptr &eventLog) { + const EventLogPrivate *dEventLog = eventLog->getPrivate(); if (!dEventLog->dbKey.isValid()) { lWarning() << "Unable to delete invalid event."; return false; @@ -1294,7 +1294,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), dEventLog->dbKey = MainDbEventKey(); if (eventLog->getType() == EventLog::Type::ConferenceChatMessage) - static_pointer_cast( + static_pointer_cast( eventLog )->getChatMessage()->getPrivate()->dbKey = MainDbChatMessageKey(); @@ -2144,7 +2144,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return false; } - bool MainDb::deleteEvent (const shared_ptr &) { + bool MainDb::deleteEvent (const shared_ptr &) { return false; } diff --git a/src/db/main-db.h b/src/db/main-db.h index ac7fc3cb5..907dd4e8c 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -59,7 +59,7 @@ public: bool addEvent (const std::shared_ptr &eventLog); bool updateEvent (const std::shared_ptr &eventLog); - static bool deleteEvent (const std::shared_ptr &eventLog); + static bool deleteEvent (const std::shared_ptr &eventLog); int getEventsCount (FilterMask mask = NoFilter) const; static std::shared_ptr getEventFromKey (const MainDbKey &dbKey); diff --git a/src/event-log/event-log.cpp b/src/event-log/event-log.cpp index e6d44b787..360379aae 100644 --- a/src/event-log/event-log.cpp +++ b/src/event-log/event-log.cpp @@ -44,7 +44,7 @@ time_t EventLog::getCreationTime () const { return d->creationTime; } -void EventLog::deleteFromDatabase (const shared_ptr &eventLog) { +void EventLog::deleteFromDatabase (const shared_ptr &eventLog) { MainDb::deleteEvent(eventLog); } diff --git a/src/event-log/event-log.h b/src/event-log/event-log.h index 660003d77..701756588 100644 --- a/src/event-log/event-log.h +++ b/src/event-log/event-log.h @@ -46,7 +46,7 @@ public: Type getType () const; time_t getCreationTime () const; - static void deleteFromDatabase (const std::shared_ptr &eventLog); + static void deleteFromDatabase (const std::shared_ptr &eventLog); protected: EventLog (EventLogPrivate &p, Type type, time_t creationTime); From 2b8e1cca6499b0821e1b28cfd3a2a6701b9d45de Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 4 Dec 2017 10:25:36 +0100 Subject: [PATCH 0958/2215] fix(core): clean some pieces of code --- src/address/address.cpp | 4 +- src/address/address.h | 2 +- src/address/identity-address.cpp | 4 +- src/c-wrapper/api/c-chat-room.cpp | 2 +- src/chat/chat-room/chat-room.cpp | 112 +++++++++++++++--------------- src/chat/chat-room/chat-room.h | 8 ++- 6 files changed, 65 insertions(+), 67 deletions(-) diff --git a/src/address/address.cpp b/src/address/address.cpp index 5f8c30e34..228bf53ef 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -20,9 +20,9 @@ #include "linphone/utils/utils.h" #include "address-p.h" +#include "address/identity-address.h" #include "c-wrapper/c-wrapper.h" #include "logger/logger.h" -#include "address/identity-address.h" // ============================================================================= @@ -403,7 +403,7 @@ bool Address::setUriParams (const string &uriParams) { return true; } -bool Address::removeUriParam(const string &uriParamName) { +bool Address::removeUriParam (const string &uriParamName) { L_D(); if (!d->internalAddress) diff --git a/src/address/address.h b/src/address/address.h index 5ce007018..8f02ad263 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -101,7 +101,7 @@ public: const std::string &getUriParamValue (const std::string &uriParamName) const; bool setUriParam (const std::string &uriParamName, const std::string &uriParamValue = ""); bool setUriParams (const std::string &uriParams); - bool removeUriParam(const std::string &uriParamName); + bool removeUriParam (const std::string &uriParamName); private: L_DECLARE_PRIVATE(Address); diff --git a/src/address/identity-address.cpp b/src/address/identity-address.cpp index 16cc1b965..2c8800896 100644 --- a/src/address/identity-address.cpp +++ b/src/address/identity-address.cpp @@ -17,10 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "linphone/utils/utils.h" - -#include "identity-address-p.h" #include "c-wrapper/c-wrapper.h" +#include "identity-address-p.h" #include "logger/logger.h" // ============================================================================= diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 61cbd97e4..093ec5750 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -217,7 +217,7 @@ bctbx_list_t *linphone_chat_room_get_history_range_events (LinphoneChatRoom *cr, } LinphoneChatMessage *linphone_chat_room_get_last_message_in_history(LinphoneChatRoom *cr) { - shared_ptr cppPtr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getLastMessageInHistory(); + shared_ptr cppPtr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getLastChatMessageInHistory(); if (!cppPtr) return nullptr; diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index cf2ca6664..ce9e6af53 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -92,37 +92,6 @@ shared_ptr ChatRoomPrivate::createChatMessage (ChatMessage::Directi return shared_ptr(new ChatMessage(q->getSharedFromThis(), direction)); } -// ----------------------------------------------------------------------------- - -const ChatRoomId &ChatRoom::getChatRoomId () const { - L_D(); - return d->chatRoomId; -} - -const IdentityAddress &ChatRoom::getPeerAddress () const { - L_D(); - return d->chatRoomId.getPeerAddress(); -} - -const IdentityAddress &ChatRoom::getLocalAddress () const { - L_D(); - return d->chatRoomId.getLocalAddress(); -} - -// ----------------------------------------------------------------------------- - -time_t ChatRoom::getCreationTime () const { - L_D(); - return d->creationTime; -} - -time_t ChatRoom::getLastUpdateTime () const { - L_D(); - return d->lastUpdateTime; -} - -// ----------------------------------------------------------------------------- - list > ChatRoomPrivate::findMessages (const string &messageId) const { L_Q(); return q->getCore()->getPrivate()->mainDb->findChatMessages(q->getChatRoomId(), messageId); @@ -167,8 +136,6 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa shared_ptr msg; shared_ptr core = q->getCore(); - if (!core) - return reason; LinphoneCore *cCore = core->getCCore(); msg = createChatMessage( @@ -349,6 +316,61 @@ ChatRoom::ChatRoom (ChatRoomPrivate &p, const shared_ptr &core, const Chat // ----------------------------------------------------------------------------- +const ChatRoomId &ChatRoom::getChatRoomId () const { + L_D(); + return d->chatRoomId; +} + +const IdentityAddress &ChatRoom::getPeerAddress () const { + L_D(); + return d->chatRoomId.getPeerAddress(); +} + +const IdentityAddress &ChatRoom::getLocalAddress () const { + L_D(); + return d->chatRoomId.getLocalAddress(); +} + +// ----------------------------------------------------------------------------- + +time_t ChatRoom::getCreationTime () const { + L_D(); + return d->creationTime; +} + +time_t ChatRoom::getLastUpdateTime () const { + L_D(); + return d->lastUpdateTime; +} + +// ----------------------------------------------------------------------------- + +list> ChatRoom::getHistory (int nLast) { + return getCore()->getPrivate()->mainDb->getHistory(getChatRoomId(), nLast); +} + +list> ChatRoom::getHistoryRange (int begin, int end) { + return getCore()->getPrivate()->mainDb->getHistoryRange(getChatRoomId(), begin, end); +} + +int ChatRoom::getHistorySize () { + return getCore()->getPrivate()->mainDb->getChatMessagesCount(getChatRoomId()); +} + +shared_ptr ChatRoom::getLastChatMessageInHistory() const { + return getCore()->getPrivate()->mainDb->getLastChatMessage(getChatRoomId()); +} + +void ChatRoom::deleteHistory () { + getCore()->getPrivate()->mainDb->cleanHistory(getChatRoomId()); +} + +int ChatRoom::getUnreadChatMessagesCount () { + return getCore()->getPrivate()->mainDb->getUnreadChatMessagesCount(getChatRoomId()); +} + +// ----------------------------------------------------------------------------- + void ChatRoom::compose () { L_D(); if (!d->isComposing) { @@ -379,10 +401,6 @@ shared_ptr ChatRoom::createMessage () { return d->createChatMessage(ChatMessage::Direction::Outgoing); } -void ChatRoom::deleteHistory () { - getCore()->getPrivate()->mainDb->cleanHistory(getChatRoomId()); -} - shared_ptr ChatRoom::findMessage (const string &messageId) { L_D(); shared_ptr cm = nullptr; @@ -406,26 +424,6 @@ shared_ptr ChatRoom::findMessageWithDirection (const string &messag return ret; } -list> ChatRoom::getHistory (int nLast) { - return getCore()->getPrivate()->mainDb->getHistory(getChatRoomId(), nLast); -} - -list> ChatRoom::getHistoryRange (int begin, int end) { - return getCore()->getPrivate()->mainDb->getHistoryRange(getChatRoomId(), begin, end); -} - -int ChatRoom::getHistorySize () { - return getCore()->getPrivate()->mainDb->getChatMessagesCount(getChatRoomId()); -} - -shared_ptr ChatRoom::getLastMessageInHistory() const { - return getCore()->getPrivate()->mainDb->getLastChatMessage(getChatRoomId()); -} - -int ChatRoom::getUnreadChatMessagesCount () { - return getCore()->getPrivate()->mainDb->getUnreadChatMessagesCount(getChatRoomId()); -} - bool ChatRoom::isRemoteComposing () const { L_D(); return d->remoteIsComposing.size() > 0; diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index 62c387c52..36dd0e998 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -64,17 +64,19 @@ public: std::list> getHistoryRange (int begin, int end); int getHistorySize (); - std::shared_ptr getLastMessageInHistory () const; + std::shared_ptr getLastChatMessageInHistory () const; + + void deleteHistory (); + + int getUnreadChatMessagesCount (); // TODO: Remove useless functions. void compose (); std::shared_ptr createFileTransferMessage (const LinphoneContent *initialContent); std::shared_ptr createMessage (const std::string &msg); std::shared_ptr createMessage (); - void deleteHistory (); std::shared_ptr findMessage (const std::string &messageId); std::shared_ptr findMessageWithDirection (const std::string &messageId, ChatMessage::Direction direction); - int getUnreadChatMessagesCount (); bool isRemoteComposing () const; std::list
      getComposingAddresses () const; From 2f1d16a3069f5e43186aaf5c4f07adddd79b603f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 4 Dec 2017 11:55:23 +0100 Subject: [PATCH 0959/2215] Use c-wrapper for the Core object. --- coreapi/CMakeLists.txt | 1 + coreapi/account_creator.c | 3 + coreapi/account_creator_service.c | 3 + coreapi/authentication.c | 3 + coreapi/buffer.c | 3 + coreapi/call_log.c | 3 + coreapi/callbacks.c | 30 +- coreapi/chat.c | 16 +- coreapi/conference.cc | 10 +- coreapi/content.c | 3 + coreapi/core_private.h | 35 + coreapi/error_info.c | 3 + coreapi/event.c | 3 + coreapi/factory.c | 3 + coreapi/friend.c | 3 + coreapi/friendlist.c | 3 + coreapi/im_notif_policy.c | 3 + coreapi/linphone_tunnel_config.c | 3 + coreapi/linphonecore.c | 249 +-- coreapi/misc.c | 5 +- coreapi/nat_policy.c | 3 + coreapi/payload_type.c | 3 + coreapi/player.c | 3 + coreapi/presence.c | 3 + coreapi/private.h | 1449 +---------------- coreapi/private_functions.h | 594 +++++++ coreapi/private_structs.h | 834 ++++++++++ coreapi/private_types.h | 70 + coreapi/video_definition.c | 3 + coreapi/xmlrpc.c | 3 + src/CMakeLists.txt | 2 + src/address/address.cpp | 1 + src/address/identity-address.cpp | 4 + src/c-wrapper/api/c-call-params.cpp | 5 +- src/c-wrapper/api/c-call.cpp | 8 +- src/c-wrapper/api/c-chat-room.cpp | 4 +- src/c-wrapper/api/c-core.cpp | 47 + src/c-wrapper/api/c-participant.cpp | 1 + src/c-wrapper/c-wrapper.h | 6 +- src/call/call-p.h | 2 +- src/call/call.cpp | 44 +- src/call/call.h | 3 + .../encryption-chat-message-modifier.cpp | 4 +- src/conference/session/media-session.cpp | 2 +- src/core/core-call.cpp | 192 +++ src/core/core-chat-room.cpp | 2 +- src/core/core-p.h | 16 + src/core/core.cpp | 72 +- src/core/core.h | 20 +- tester/call_single_tester.c | 2 +- tester/conference-event-tester.cpp | 18 +- tester/cpim-tester.cpp | 2 +- tester/main-db-tester.cpp | 2 +- tester/multipart-tester.cpp | 2 +- tools/python/apixml2python.py | 1 - 55 files changed, 2056 insertions(+), 1756 deletions(-) create mode 100644 coreapi/core_private.h create mode 100644 coreapi/private_functions.h create mode 100644 coreapi/private_structs.h create mode 100644 coreapi/private_types.h create mode 100644 src/c-wrapper/api/c-core.cpp create mode 100644 src/core/core-call.cpp diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index d12a73f06..cbb971d70 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -38,6 +38,7 @@ list(APPEND LINPHONE_PRIVATE_HEADER_FILES carddav.h conference_private.h contact_providers_priv.h + core_private.h enum.h lime.h lpc2xml.h diff --git a/coreapi/account_creator.c b/coreapi/account_creator.c index 16d23a221..6e57615fc 100644 --- a/coreapi/account_creator.c +++ b/coreapi/account_creator.c @@ -30,6 +30,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include +// TODO: From coreapi. Remove me later. +#include "private.h" + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneAccountCreatorCbs); BELLE_SIP_INSTANCIATE_VPTR(LinphoneAccountCreatorCbs, belle_sip_object_t, diff --git a/coreapi/account_creator_service.c b/coreapi/account_creator_service.c index 3cf0bbff6..26ee9fc4f 100644 --- a/coreapi/account_creator_service.c +++ b/coreapi/account_creator_service.c @@ -22,6 +22,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneAccountCreatorService); BELLE_SIP_INSTANCIATE_VPTR(LinphoneAccountCreatorService, belle_sip_object_t, diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 59a9db475..9d310da3c 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -28,6 +28,9 @@ #include "c-wrapper/c-wrapper.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + static void _linphone_auth_info_uninit(LinphoneAuthInfo *obj); static void _linphone_auth_info_copy(LinphoneAuthInfo *dst, const LinphoneAuthInfo *src); diff --git a/coreapi/buffer.c b/coreapi/buffer.c index ce28b271a..c3bd79270 100644 --- a/coreapi/buffer.c +++ b/coreapi/buffer.c @@ -21,6 +21,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + static void linphone_buffer_destroy(LinphoneBuffer *buffer) { if (buffer->content) belle_sip_free(buffer->content); } diff --git a/coreapi/call_log.c b/coreapi/call_log.c index abed37602..9ca518db7 100644 --- a/coreapi/call_log.c +++ b/coreapi/call_log.c @@ -35,6 +35,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + typedef struct _CallLogStorageResult { LinphoneCore *core; bctbx_list_t *result; diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index e2a672940..a14a588e0 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -54,22 +54,6 @@ using namespace LinphonePrivate; static void register_failure(SalOp *op); -static bool_t already_a_call_with_remote_address(const LinphoneCore *lc, const LinphoneAddress *remote) { - bctbx_list_t *elem; - ms_message("Searching for already_a_call_with_remote_address."); - - for(elem=lc->calls;elem!=NULL;elem=elem->next){ - const LinphoneCall *call=(LinphoneCall*)elem->data; - const LinphoneAddress *cRemote=linphone_call_get_remote_address(call); - if (linphone_address_weak_equal(cRemote,remote)) { - ms_warning("already_a_call_with_remote_address found."); - return TRUE; - } - } - return FALSE; -} - - static LinphoneCall * look_for_broken_call_to_replace(LinphonePrivate::SalOp *h, LinphoneCore *lc) { const bctbx_list_t *calls = linphone_core_get_calls(lc); const bctbx_list_t *it = calls; @@ -128,7 +112,7 @@ static void call_received(SalCallOp *h) { } else if (sal_address_has_param(h->get_remote_contact_address(), "text")) { linphone_address_unref(toAddr); linphone_address_unref(fromAddr); - shared_ptr chatRoom = lc->cppCore->findChatRoom( + shared_ptr chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom( ChatRoomId(IdentityAddress(h->get_to()), IdentityAddress(h->get_to())) ); if (chatRoom) { @@ -169,7 +153,7 @@ static void call_received(SalCallOp *h) { } } - if (!linphone_core_can_we_add_call(lc)) { /* Busy */ + if (!L_GET_PRIVATE_FROM_C_OBJECT(lc)->canWeAddCall()) { /* Busy */ h->decline(SalReasonBusy, nullptr); LinphoneErrorInfo *ei = linphone_error_info_new(); linphone_error_info_set(ei, nullptr, LinphoneReasonBusy, 486, "Busy - too many calls", nullptr); @@ -186,7 +170,7 @@ static void call_received(SalCallOp *h) { fromAddressToSearchIfMe = linphone_address_new(pAssertedId); else ms_warning("Hidden from identity, don't know if it's me"); - if (fromAddressToSearchIfMe && already_a_call_with_remote_address(lc, fromAddressToSearchIfMe)) { + if (fromAddressToSearchIfMe && L_GET_PRIVATE_FROM_C_OBJECT(lc)->isAlreadyInCallWithAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(fromAddressToSearchIfMe))) { char *addr = linphone_address_as_string(fromAddr); ms_warning("Receiving a call while one with same address [%s] is initiated, refusing this one with busy message", addr); h->decline(SalReasonBusy, nullptr); @@ -767,7 +751,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ if (addr.hasUriParam("method") && (addr.getUriParamValue("method") == "BYE")) { if (linphone_core_conference_server_enabled(lc)) { // Removal of a participant at the server side - shared_ptr chatRoom = lc->cppCore->findChatRoom( + shared_ptr chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom( ChatRoomId(IdentityAddress(op->get_to()), IdentityAddress(op->get_to())) ); if (chatRoom) { @@ -785,7 +769,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ } else { // The server asks a participant to leave a chat room LinphoneChatRoom *cr = L_GET_C_BACK_PTR( - lc->cppCore->findChatRoom(ChatRoomId(addr, IdentityAddress(op->get_to()))) + L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(ChatRoomId(addr, IdentityAddress(op->get_to()))) ); if (cr) { L_GET_CPP_PTR_FROM_C_OBJECT(cr)->leave(); @@ -795,7 +779,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ static_cast(op)->reply(SalReasonDeclined); } } else if (addr.hasParam("admin")) { - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom( + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom( ChatRoomId(IdentityAddress(op->get_to()), IdentityAddress(op->get_to())) )); if (cr) { @@ -814,7 +798,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ return; } } else { - LinphoneChatRoom *cr = L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(ChatRoomId(addr, IdentityAddress(op->get_to())))); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(ChatRoomId(addr, IdentityAddress(op->get_to())))); if (!cr) cr = _linphone_client_group_chat_room_new(lc, addr.asString().c_str(), nullptr); L_GET_CPP_PTR_FROM_C_OBJECT(cr)->join(); diff --git a/coreapi/chat.c b/coreapi/chat.c index 65f85d15a..3dc067c80 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -60,12 +60,12 @@ bool_t linphone_core_chat_enabled(const LinphoneCore *lc) { const bctbx_list_t *linphone_core_get_chat_rooms (LinphoneCore *lc) { if (lc->chat_rooms) bctbx_list_free_with_data(lc->chat_rooms, (bctbx_list_free_func)linphone_chat_room_unref); - lc->chat_rooms = L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(lc->cppCore->getChatRooms()); + lc->chat_rooms = L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getChatRooms()); return lc->chat_rooms; } static LinphoneChatRoom *linphone_chat_room_new (LinphoneCore *core, const LinphoneAddress *addr) { - return L_GET_C_BACK_PTR(core->cppCore->getOrCreateBasicChatRoom( + return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(core)->getOrCreateBasicChatRoom( *L_GET_CPP_PTR_FROM_C_OBJECT(addr), linphone_core_realtime_text_enabled(core) )); @@ -79,11 +79,11 @@ LinphoneChatRoom *_linphone_core_create_chat_room_from_call(LinphoneCall *call){ } LinphoneChatRoom *linphone_core_get_chat_room (LinphoneCore *lc, const LinphoneAddress *addr) { - return L_GET_C_BACK_PTR(lc->cppCore->getOrCreateBasicChatRoom(*L_GET_CPP_PTR_FROM_C_OBJECT(addr))); + return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getOrCreateBasicChatRoom(*L_GET_CPP_PTR_FROM_C_OBJECT(addr))); } LinphoneChatRoom *linphone_core_create_client_group_chat_room (LinphoneCore *lc, const char *subject) { - return L_GET_C_BACK_PTR(lc->cppCore->createClientGroupChatRoom(L_C_TO_STRING(subject))); + return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(lc)->createClientGroupChatRoom(L_C_TO_STRING(subject))); } LinphoneChatRoom *_linphone_core_join_client_group_chat_room (LinphoneCore *lc, const LinphonePrivate::Address &addr) { @@ -101,7 +101,7 @@ void linphone_core_delete_chat_room (LinphoneCore *, LinphoneChatRoom *cr) { } LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const char *to) { - return L_GET_C_BACK_PTR(lc->cppCore->getOrCreateBasicChatRoomFromUri(L_C_TO_STRING(to))); + return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getOrCreateBasicChatRoomFromUri(L_C_TO_STRING(to))); } LinphoneChatRoom *linphone_core_find_chat_room( @@ -109,7 +109,7 @@ LinphoneChatRoom *linphone_core_find_chat_room( const LinphoneAddress *peer_addr, const LinphoneAddress *local_addr ) { - return L_GET_C_BACK_PTR(lc->cppCore->findChatRoom(LinphonePrivate::ChatRoomId( + return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(LinphonePrivate::ChatRoomId( LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(peer_addr)), LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(local_addr)) ))); @@ -120,7 +120,7 @@ LinphoneChatRoom *linphone_core_find_one_to_one_chat_room ( const LinphoneAddress *local_addr, const LinphoneAddress *participant_addr ) { - return L_GET_C_BACK_PTR(lc->cppCore->findOneToOneChatRoom( + return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findOneToOneChatRoom( LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(local_addr)), LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(participant_addr)) )); @@ -137,7 +137,7 @@ int linphone_core_message_received(LinphoneCore *lc, LinphonePrivate::SalOp *op, localAddress = op->get_to(); } - shared_ptr chatRoom = lc->cppCore->findChatRoom( + shared_ptr chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom( LinphonePrivate::ChatRoomId(LinphonePrivate::IdentityAddress(peerAddress), LinphonePrivate::IdentityAddress(localAddress)) ); diff --git a/coreapi/conference.cc b/coreapi/conference.cc index eb88aa5a1..522353ff6 100644 --- a/coreapi/conference.cc +++ b/coreapi/conference.cc @@ -36,6 +36,9 @@ #include "c-wrapper/c-wrapper.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + using namespace std; namespace Linphone { @@ -535,6 +538,7 @@ int LocalConference::remoteParticipantsCount() { int LocalConference::convertConferenceToCall(){ int err=0; +#if 0 bctbx_list_t *calls=m_core->calls; if (remoteParticipantsCount()!=1){ @@ -551,6 +555,7 @@ int LocalConference::convertConferenceToCall(){ break; } } +#endif return err; } @@ -583,6 +588,7 @@ int LocalConference::removeParticipant(const LinphoneAddress *uri) { } int LocalConference::terminate() { +#if 0 bctbx_list_t *calls=m_core->calls; m_terminating =TRUE; @@ -596,11 +602,12 @@ int LocalConference::terminate() { Conference::terminate(); m_terminating = FALSE; - +#endif return 0; } int LocalConference::enter() { +#if 0 if (linphone_core_sound_resources_locked(m_core)) { return -1; } @@ -608,6 +615,7 @@ int LocalConference::enter() { _linphone_call_pause(m_core->current_call); } if (m_localParticipantStream==NULL) addLocalEndpoint(); +#endif return 0; } diff --git a/coreapi/content.c b/coreapi/content.c index 055591ee5..8d20964bd 100644 --- a/coreapi/content.c +++ b/coreapi/content.c @@ -21,6 +21,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + static void linphone_content_set_sal_body_handler(LinphoneContent *content, SalBodyHandler *body_handler) { if (content->body_handler != NULL) { sal_body_handler_unref(content->body_handler); diff --git a/coreapi/core_private.h b/coreapi/core_private.h new file mode 100644 index 000000000..e5d52703e --- /dev/null +++ b/coreapi/core_private.h @@ -0,0 +1,35 @@ +/* + * core_private.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CORE_PRIVATE_H_ +#define _CORE_PRIVATE_H_ + +#include "linphone/types.h" +#include "private_structs.h" +#include "private_types.h" + +struct _LinphoneCore { + belle_sip_object_t base; + std::shared_ptr cppPtr; + std::weak_ptr weakCppPtr; + int owner; + LINPHONE_CORE_STRUCT_FIELDS +}; + +#endif /* _CORE_PRIVATE_H_ */ diff --git a/coreapi/error_info.c b/coreapi/error_info.c index 556cb35f1..a4c29c7f3 100644 --- a/coreapi/error_info.c +++ b/coreapi/error_info.c @@ -21,6 +21,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneErrorInfo); static void linphone_error_info_reset(LinphoneErrorInfo *ei); diff --git a/coreapi/event.c b/coreapi/event.c index d4e8541da..950c4ca2c 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -23,6 +23,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + using namespace LinphonePrivate; const char * linphone_subscription_dir_to_string(LinphoneSubscriptionDir dir){ diff --git a/coreapi/factory.c b/coreapi/factory.c index 80a0a42e7..73e1d0d99 100644 --- a/coreapi/factory.c +++ b/coreapi/factory.c @@ -21,6 +21,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + #ifndef PACKAGE_SOUND_DIR #define PACKAGE_SOUND_DIR "." #endif diff --git a/coreapi/friend.c b/coreapi/friend.c index 1f3b1a378..9f39717c5 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -42,6 +42,9 @@ #include "c-wrapper/c-wrapper.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + using namespace std; using namespace LinphonePrivate; diff --git a/coreapi/friendlist.c b/coreapi/friendlist.c index 0e1a5644e..a0a7e08c1 100644 --- a/coreapi/friendlist.c +++ b/coreapi/friendlist.c @@ -23,6 +23,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneFriendListCbs); BELLE_SIP_INSTANCIATE_VPTR(LinphoneFriendListCbs, belle_sip_object_t, diff --git a/coreapi/im_notif_policy.c b/coreapi/im_notif_policy.c index 9b628a46c..dff428f73 100644 --- a/coreapi/im_notif_policy.c +++ b/coreapi/im_notif_policy.c @@ -21,6 +21,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneImNotifPolicy); BELLE_SIP_INSTANCIATE_VPTR(LinphoneImNotifPolicy, belle_sip_object_t, diff --git a/coreapi/linphone_tunnel_config.c b/coreapi/linphone_tunnel_config.c index f51d9c8e6..a12ac5c41 100644 --- a/coreapi/linphone_tunnel_config.c +++ b/coreapi/linphone_tunnel_config.c @@ -24,6 +24,9 @@ #include "c-wrapper/c-wrapper.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + struct _LinphoneTunnelConfig { belle_sip_object_t base; char *host; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 4ae85aa58..93b6adcc7 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -51,7 +51,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "chat/chat-room/client-group-chat-room-p.h" #include "chat/chat-room/server-group-chat-room-p.h" #include "conference/handlers/remote-conference-event-handler.h" -#include "core/core.h" +#include "core/core-p.h" // For migration purpose. #include "address/address-p.h" @@ -128,7 +128,6 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu static void set_sip_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime); static void set_media_network_reachable(LinphoneCore* lc,bool_t isReachable); static void linphone_core_run_hooks(LinphoneCore *lc); -static void linphone_core_uninit(LinphoneCore *lc); static void linphone_core_zrtp_cache_close(LinphoneCore *lc); void linphone_core_zrtp_cache_db_init(LinphoneCore *lc, const char *fileName); @@ -456,15 +455,6 @@ void linphone_core_cbs_set_ec_calibration_audio_uninit(LinphoneCoreCbs *cbs, Lin } -typedef belle_sip_object_t_vptr_t LinphoneCore_vptr_t; -BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCore); -BELLE_SIP_INSTANCIATE_VPTR(LinphoneCore, belle_sip_object_t, - linphone_core_uninit, // destroy - NULL, // clone - NULL, // Marshall - FALSE -); - void lc_callback_obj_init(LCCallbackObj *obj,LinphoneCoreCbFunc func,void* ud) { obj->_func=func; obj->_user_data=ud; @@ -2021,8 +2011,7 @@ static void linphone_core_start(LinphoneCore * lc) { lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon; - new(&lc->cppCore) std::shared_ptr(); - lc->cppCore = Core::create(lc); + L_GET_PRIVATE_FROM_C_OBJECT(lc)->init(); linphone_core_set_state(lc,LinphoneGlobalOn,"Ready"); } @@ -2142,7 +2131,7 @@ static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEve const LinphoneAddress *resource = linphone_event_get_resource(lev); const LinphoneAddress *from = linphone_event_get_from(lev); - shared_ptr chatRoom = lc->cppCore->findChatRoom(LinphonePrivate::ChatRoomId( + shared_ptr chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(LinphonePrivate::ChatRoomId( IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(resource)), IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(from)) )); @@ -2166,7 +2155,7 @@ static void _linphone_core_conference_subscription_state_changed(LinphoneCore *l state == LinphoneSubscriptionIncomingReceived ) { const LinphoneAddress *resource = linphone_event_get_resource(lev); - shared_ptr chatRoom = lc->cppCore->findChatRoom(LinphonePrivate::ChatRoomId( + shared_ptr chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(LinphonePrivate::ChatRoomId( IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(resource)), IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(resource)) )); @@ -2326,7 +2315,8 @@ static void _linphone_core_set_system_context(LinphoneCore *lc, void *system_con #endif LinphoneCore *_linphone_core_new_with_config(LinphoneCoreCbs *cbs, struct _LpConfig *config, void *userdata, void *system_context) { - LinphoneCore *core = belle_sip_object_new(LinphoneCore); + LinphoneCore *core = L_INIT(Core); + Core::create(core); linphone_core_init(core, cbs, config, userdata, system_context); return core; } @@ -2737,13 +2727,11 @@ bool_t linphone_core_get_rtp_no_xmit_on_audio_mute(const LinphoneCore *lc){ } static void apply_jitter_value(LinphoneCore *lc, int value, MSFormatType stype){ - LinphoneCall *call; - bctbx_list_t *it; - for (it=lc->calls;it!=NULL;it=it->next){ - MediaStream *ms; - call=(LinphoneCall*)it->data; - ms = stype==MSAudio ? linphone_call_get_stream(call, LinphoneStreamTypeAudio) : linphone_call_get_stream(call, LinphoneStreamTypeVideo); - if (ms){ + for (const auto &call : L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getCalls()) { + MediaStream *ms = (stype == MSAudio) + ? L_GET_PRIVATE(call)->getMediaStream(LinphoneStreamTypeAudio) + : L_GET_PRIVATE(call)->getMediaStream(LinphoneStreamTypeVideo); + if (ms) { RtpSession *s=ms->sessions.rtp_session; if (s){ if (value>0){ @@ -3210,8 +3198,6 @@ static void linphone_core_do_plugin_tasks(LinphoneCore *lc){ } void linphone_core_iterate(LinphoneCore *lc){ - bctbx_list_t *calls; - LinphoneCall *call; uint64_t curtime_ms = ms_get_cur_time_ms(); /*monotonic time*/ time_t current_real_time = ms_time(NULL); int64_t diff_time; @@ -3251,7 +3237,6 @@ void linphone_core_iterate(LinphoneCore *lc){ lc->prevtime_ms = curtime_ms; }else{ lc->prevtime_ms += 1000; - } } @@ -3301,17 +3286,10 @@ void linphone_core_iterate(LinphoneCore *lc){ proxy_update(lc); /* We have to iterate for each call */ - calls = lc->calls; - while (calls) { - call = reinterpret_cast(bctbx_list_get_data(calls)); - /* Get immediately a reference to next one in case the one we are going to examine is destroyed - * and removed during linphone_call_start_invite() */ - calls = bctbx_list_next(calls); - L_GET_PRIVATE_FROM_C_OBJECT(call)->iterate(current_real_time, one_second_elapsed); - } + L_GET_PRIVATE_FROM_C_OBJECT(lc)->iterateCalls(current_real_time, one_second_elapsed); if (linphone_core_video_preview_enabled(lc)){ - if (lc->previewstream==NULL && lc->calls==NULL) + if (lc->previewstream==NULL && !L_GET_PRIVATE_FROM_C_OBJECT(lc)->hasCalls()) toggle_video_preview(lc,TRUE); #ifdef VIDEO_ENABLED if (lc->previewstream) video_stream_iterate(lc->previewstream); @@ -3613,9 +3591,8 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const return NULL; } - if(!linphone_core_can_we_add_call(lc)){ + if (!L_GET_PRIVATE_FROM_C_OBJECT(lc)->canWeAddCall()) return NULL; - } cp = linphone_call_params_copy(params); proxy=linphone_core_lookup_known_proxy(lc,addr); @@ -3636,8 +3613,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const call=linphone_call_new_outgoing(lc,parsed_url2,addr,cp,proxy); linphone_address_unref(parsed_url2); - if(linphone_core_add_call(lc,call)!= 0) - { + if (L_GET_PRIVATE_FROM_C_OBJECT(lc)->addCall(L_GET_CPP_PTR_FROM_C_OBJECT(call)) != 0) { ms_warning("we had a problem in adding the call into the invite ... weird"); linphone_call_unref(call); linphone_call_params_unref(cp); @@ -3648,7 +3624,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const /* Unless this call is for a conference, it becomes now the current one*/ if (linphone_call_params_get_local_conference_mode(params) == FALSE) #endif - lc->current_call=call; + L_GET_PRIVATE_FROM_C_OBJECT(lc)->setCurrentCall(L_GET_CPP_PTR_FROM_C_OBJECT(call)); bool defer = L_GET_PRIVATE_FROM_C_OBJECT(call)->initiateOutgoing(); if (!defer) { if (L_GET_PRIVATE_FROM_C_OBJECT(call)->startInvite(nullptr) != 0) { @@ -3689,9 +3665,9 @@ bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ /* Play the ring if this is the only call*/ - if (bctbx_list_size(lc->calls)==1){ + if (linphone_core_get_calls_nb(lc)==1){ MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard; - lc->current_call=call; + L_GET_PRIVATE_FROM_C_OBJECT(lc)->setCurrentCall(L_GET_CPP_PTR_FROM_C_OBJECT(call)); if (lc->ringstream && lc->dmfs_playing_start_time!=0){ linphone_core_stop_dtmf_stream(lc); } @@ -3765,13 +3741,7 @@ LinphoneStatus linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call } LinphoneStatus linphone_core_terminate_all_calls(LinphoneCore *lc) { - bctbx_list_t *calls=lc->calls; - while(calls) { - LinphoneCall *c=(LinphoneCall*)calls->data; - calls=calls->next; - linphone_call_terminate(c); - } - return 0; + return L_GET_CPP_PTR_FROM_C_OBJECT(lc)->terminateAllCalls(); } LinphoneStatus linphone_core_decline_call(LinphoneCore *lc, LinphoneCall *call, LinphoneReason reason) { @@ -3779,31 +3749,29 @@ LinphoneStatus linphone_core_decline_call(LinphoneCore *lc, LinphoneCall *call, } const bctbx_list_t *linphone_core_get_calls(LinphoneCore *lc) { - return lc->calls; + if (lc->callsCache) { + bctbx_list_free(lc->callsCache); + lc->callsCache = NULL; + } + lc->callsCache = L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getCalls()); + return lc->callsCache; } bool_t linphone_core_in_call(const LinphoneCore *lc){ return linphone_core_get_current_call((LinphoneCore *)lc)!=NULL || linphone_core_is_in_conference(lc); } -LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc){ - return lc->current_call; +LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc) { + shared_ptr call = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getCurrentCall(); + return call ? L_GET_C_BACK_PTR(call) : NULL; } LinphoneStatus linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call) { return linphone_call_pause(call); } -LinphoneStatus linphone_core_pause_all_calls(LinphoneCore *lc){ - const bctbx_list_t *elem; - for(elem=lc->calls;elem!=NULL;elem=elem->next){ - LinphoneCall *call=(LinphoneCall *)elem->data; - LinphoneCallState cs=linphone_call_get_state(call); - if (cs==LinphoneCallStreamsRunning || cs==LinphoneCallPausedByRemote){ - _linphone_call_pause(call); - } - } - return 0; +LinphoneStatus linphone_core_pause_all_calls(LinphoneCore *lc) { + return L_GET_CPP_PTR_FROM_C_OBJECT(lc)->pauseAllCalls(); } int linphone_core_preempt_sound_resources(LinphoneCore *lc){ @@ -3830,11 +3798,6 @@ LinphoneStatus linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call) { return linphone_call_resume(call); } -static int remote_address_compare(LinphoneCall *call, const LinphoneAddress *raddr){ - const LinphoneAddress *addr=linphone_call_get_remote_address (call); - return !linphone_address_weak_equal (addr,raddr); -} - LinphoneCall *linphone_core_get_call_by_remote_address(const LinphoneCore *lc, const char *remote_address){ LinphoneCall *call=NULL; LinphoneAddress *raddr=linphone_address_new(remote_address); @@ -3849,11 +3812,9 @@ LinphoneCall *linphone_core_find_call_from_uri(const LinphoneCore *lc, const cha return linphone_core_get_call_by_remote_address(lc, remote_address); } -LinphoneCall *linphone_core_get_call_by_remote_address2(const LinphoneCore *lc, const LinphoneAddress *raddr){ - const bctbx_list_t *elem=bctbx_list_find_custom(lc->calls,(int (*)(const void*,const void *))remote_address_compare,raddr); - - if (elem) return (LinphoneCall*) elem->data; - return NULL; +LinphoneCall *linphone_core_get_call_by_remote_address2(const LinphoneCore *lc, const LinphoneAddress *raddr) { + shared_ptr call = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getCallByRemoteAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(raddr)); + return call ? L_GET_C_BACK_PTR(call) : NULL; } int linphone_core_send_publish(LinphoneCore *lc, LinphonePresenceModel *presence) { @@ -5226,11 +5187,6 @@ void * linphone_core_get_native_video_window_id(const LinphoneCore *lc){ /* unsets the video id for all calls (indeed it may be kept by filters or videostream object itself by paused calls)*/ static void unset_video_window_id(LinphoneCore *lc, bool_t preview, void *id){ -#ifdef VIDEO_ENABLED - LinphoneCall *call; - bctbx_list_t *elem; -#endif - if ((id != NULL) #ifndef _WIN32 && ((unsigned long)id != (unsigned long)-1) @@ -5239,18 +5195,7 @@ static void unset_video_window_id(LinphoneCore *lc, bool_t preview, void *id){ ms_error("Invalid use of unset_video_window_id()"); return; } -#ifdef VIDEO_ENABLED - for(elem=lc->calls;elem!=NULL;elem=elem->next){ - call=(LinphoneCall *) elem->data; - VideoStream *vstream = reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeVideo)); - if (vstream){ - if (preview) - video_stream_set_native_preview_window_id(vstream,id); - else - video_stream_set_native_window_id(vstream,id); - } - } -#endif + L_GET_PRIVATE_FROM_C_OBJECT(lc)->unsetVideoWindowId(!!preview, id); } void linphone_core_set_native_video_window_id(LinphoneCore *lc, void *id){ @@ -5917,8 +5862,6 @@ void sip_config_uninit(LinphoneCore *lc) delete lc->sal; lc->sal=NULL; - lc->cppCore.~shared_ptr(); - if (lc->sip_conf.guessed_contact) ms_free(lc->sip_conf.guessed_contact); if (config->contact) @@ -6060,7 +6003,7 @@ LinphoneXmlRpcSession * linphone_core_create_xml_rpc_session(LinphoneCore *lc, c return linphone_xml_rpc_session_new(lc, url); } -static void linphone_core_uninit(LinphoneCore *lc) +void _linphone_core_uninit(LinphoneCore *lc) { bctbx_list_t *elem = NULL; int i=0; @@ -6068,12 +6011,7 @@ static void linphone_core_uninit(LinphoneCore *lc) linphone_task_list_free(&lc->hooks); lc->video_conf.show_local = FALSE; - while(lc->calls) { - LinphoneCall *the_call = reinterpret_cast(lc->calls->data); - linphone_call_terminate(the_call); - linphone_core_iterate(lc); - ms_usleep(10000); - } + L_GET_PRIVATE_FROM_C_OBJECT(lc)->uninit(); for (elem = lc->friends_lists; elem != NULL; elem = bctbx_list_next(elem)) { LinphoneFriendList *list = (LinphoneFriendList *)elem->data; @@ -6203,15 +6141,19 @@ static void set_sip_network_reachable(LinphoneCore* lc,bool_t is_sip_reachable, linphone_core_invalidate_friend_subscriptions(lc); lc->sal->reset_transports(); /*mark all calls as broken, so that they can be either dropped immediately or restaured when network will be back*/ +#if 0 bctbx_list_for_each(lc->calls, (MSIterateFunc) linphone_call_set_broken); +#endif } } void linphone_core_repair_calls(LinphoneCore *lc){ +#if 0 if (lc->calls && lp_config_get_int(lc->config, "sip", "repair_broken_calls", 1) && lc->media_network_reachable){ /*if we are registered and there were broken calls due to a past network disconnection, attempt to repair them*/ bctbx_list_for_each(lc->calls, (MSIterateFunc) linphone_call_repair_if_broken); } +#endif } static void set_media_network_reachable(LinphoneCore* lc, bool_t is_media_reachable){ @@ -6221,10 +6163,14 @@ static void set_media_network_reachable(LinphoneCore* lc, bool_t is_media_reacha if (!lc->media_network_reachable){ /*mark all calls as broken, so that they can be either dropped immediately or restaured when network will be back*/ +#if 0 bctbx_list_for_each(lc->calls, (MSIterateFunc) linphone_call_set_broken); +#endif }else{ if (lp_config_get_int(lc->config, "net", "recreate_sockets_when_network_is_up", 0)){ +#if 0 bctbx_list_for_each(lc->calls, (MSIterateFunc)linphone_call_refresh_sockets); +#endif } linphone_core_repair_calls(lc); if (lc->bw_controller){ @@ -6287,80 +6233,12 @@ void linphone_core_destroy(LinphoneCore *lc){ linphone_core_unref(lc); } -int linphone_core_get_calls_nb(const LinphoneCore *lc){ - return (int)bctbx_list_size(lc->calls); +int linphone_core_get_calls_nb(const LinphoneCore *lc) { + return (int)L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getCallsNb(); } -/** - * Check if we do not have exceed the number of simultaneous call - * @ingroup call_control -**/ -bool_t linphone_core_can_we_add_call(LinphoneCore *lc) -{ - if(linphone_core_get_calls_nb(lc) < lc->max_calls) - return TRUE; - ms_message("Maximum amount of simultaneous calls reached !"); - return FALSE; -} - -static void notify_soundcard_usage(LinphoneCore *lc, bool_t used){ - MSSndCard *card=lc->sound_conf.capt_sndcard; - if (card && ms_snd_card_get_capabilities(card) & MS_SND_CARD_CAP_IS_SLOW){ - ms_snd_card_set_usage_hint(card,used); - } -} - -void linphone_core_soundcard_hint_check( LinphoneCore* lc){ - bctbx_list_t* the_calls = lc->calls; - LinphoneCall* call = NULL; - bool_t dont_need_sound = TRUE; - bool_t use_rtp_io = !!lp_config_get_int(lc->config, "sound", "rtp_io", FALSE); - bool_t use_rtp_io_enable_local_output = !!lp_config_get_int(lc->config, "sound", "rtp_io_enable_local_output", FALSE); - - /* check if the remaining calls are paused */ - while( the_calls ){ - call = reinterpret_cast(the_calls->data); - if (linphone_call_get_state(call) != LinphoneCallPausing && linphone_call_get_state(call) != LinphoneCallPaused - && linphone_call_get_state(call) != LinphoneCallEnd && linphone_call_get_state(call) != LinphoneCallError){ - dont_need_sound = FALSE; - break; - } - the_calls = the_calls->next; - } - /* if no more calls or all calls are paused, we can free the soundcard */ - if ( (lc->calls==NULL || dont_need_sound) && !lc->use_files && (!use_rtp_io || (use_rtp_io && use_rtp_io_enable_local_output))){ - ms_message("Notifying soundcard that we don't need it anymore for calls."); - notify_soundcard_usage(lc,FALSE); - } -} - -int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call) { - if (linphone_core_can_we_add_call(lc)){ - if (lc->calls==NULL) notify_soundcard_usage(lc,TRUE); - lc->calls = bctbx_list_append(lc->calls,call); - linphone_core_notify_call_created(lc, call); - return 0; - } - return -1; -} - -int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call) { - bctbx_list_t *it; - bctbx_list_t *the_calls = lc->calls; - - it=bctbx_list_find(the_calls,call); - if (it) - { - the_calls = bctbx_list_erase_link(the_calls,it); - } - else - { - ms_warning("could not find the call into the list\n"); - return -1; - } - lc->calls = the_calls; - - return 0; +void linphone_core_soundcard_hint_check(LinphoneCore* lc) { + L_GET_CPP_PTR_FROM_C_OBJECT(lc)->soundcardHintCheck(); } void linphone_core_set_remote_ringback_tone(LinphoneCore *lc, const char *file){ @@ -6754,31 +6632,8 @@ const char *linphone_core_get_user_certificates_path(LinphoneCore *lc){ return lc->user_certificates_path; } -bool_t linphone_core_sound_resources_locked(LinphoneCore *lc){ - bctbx_list_t *elem; - for(elem=lc->calls;elem!=NULL;elem=elem->next) { - LinphoneCall *c=(LinphoneCall*)elem->data; - - if (linphone_call_media_in_progress(c)) { - return TRUE; - } - - switch (linphone_call_get_state(c)) { - case LinphoneCallOutgoingInit: - case LinphoneCallOutgoingProgress: - case LinphoneCallOutgoingRinging: - case LinphoneCallOutgoingEarlyMedia: - case LinphoneCallConnected: - case LinphoneCallRefered: - case LinphoneCallIncomingEarlyMedia: - case LinphoneCallUpdating: - ms_message("Call %p is locking sound resources.",c); - return TRUE; - default: - break; - } - } - return FALSE; +bool_t linphone_core_sound_resources_locked(LinphoneCore *lc) { + return !!L_GET_CPP_PTR_FROM_C_OBJECT(lc)->areSoundResourcesLocked(); } void linphone_core_set_srtp_enabled(LinphoneCore *lc, bool_t enabled) { @@ -6883,7 +6738,7 @@ void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m) { } void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params) { - L_GET_CPP_PTR_FROM_C_OBJECT(params)->initDefault(lc->cppCore); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->initDefault(L_GET_CPP_PTR_FROM_C_OBJECT(lc)); } void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) { @@ -7189,6 +7044,7 @@ LinphoneStatus linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *c } LinphoneStatus linphone_core_add_all_to_conference(LinphoneCore *lc) { +#if 0 bctbx_list_t *calls=lc->calls; while (calls) { LinphoneCall *call=(LinphoneCall*)calls->data; @@ -7200,6 +7056,7 @@ LinphoneStatus linphone_core_add_all_to_conference(LinphoneCore *lc) { if(lc->conf_ctx && linphone_conference_check_class(lc->conf_ctx, LinphoneConferenceClassLocal)) { linphone_core_enter_conference(lc); } +#endif return 0; } diff --git a/coreapi/misc.c b/coreapi/misc.c index 14604b538..ae1384348 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -60,6 +60,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc){ const bctbx_list_t *elem; int maxbw=LinphonePrivate::PayloadTypeHandler::getMinBandwidth(linphone_core_get_download_bandwidth(lc), @@ -176,7 +179,7 @@ int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, sock /* this functions runs a simple stun test and return the number of milliseconds to complete the tests, or -1 if the test were failed.*/ int linphone_run_stun_tests(LinphoneCore *lc, int audioPort, int videoPort, int textPort, char *audioCandidateAddr, int *audioCandidatePort, char *videoCandidateAddr, int *videoCandidatePort, char *textCandidateAddr, int *textCandidatePort) { - LinphonePrivate::StunClient *client = new LinphonePrivate::StunClient(lc->cppCore); + LinphonePrivate::StunClient *client = new LinphonePrivate::StunClient(L_GET_CPP_PTR_FROM_C_OBJECT(lc)); int ret = client->run(audioPort, videoPort, textPort); strncpy(audioCandidateAddr, client->getAudioCandidate().address.c_str(), LINPHONE_IPADDR_SIZE); *audioCandidatePort = client->getAudioCandidate().port; diff --git a/coreapi/nat_policy.c b/coreapi/nat_policy.c index 86f676412..a305fa6a7 100644 --- a/coreapi/nat_policy.c +++ b/coreapi/nat_policy.c @@ -21,6 +21,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + static LinphoneNatPolicy * _linphone_nat_policy_new_with_ref(LinphoneCore *lc, const char *ref) { LinphoneNatPolicy *policy = belle_sip_object_new(LinphoneNatPolicy); policy->lc = lc; diff --git a/coreapi/payload_type.c b/coreapi/payload_type.c index b2b042181..75ccc1f94 100644 --- a/coreapi/payload_type.c +++ b/coreapi/payload_type.c @@ -25,6 +25,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" #include "utils/payload-type-handler.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + struct _LinphonePayloadType { belle_sip_object_t base; OrtpPayloadType *pt; diff --git a/coreapi/player.c b/coreapi/player.c index 1bf49fd7f..39ee83e7b 100644 --- a/coreapi/player.c +++ b/coreapi/player.c @@ -20,6 +20,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphonePlayer); BELLE_SIP_INSTANCIATE_VPTR(LinphonePlayer, belle_sip_object_t, diff --git a/coreapi/presence.c b/coreapi/presence.c index 071981d59..eea5c8980 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -23,6 +23,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + using namespace LinphonePrivate; extern const char *__policy_enum_to_str(LinphoneSubscribePolicy pol); diff --git a/coreapi/private.h b/coreapi/private.h index 7270f010b..37d433c90 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -112,19 +112,15 @@ #endif #endif -#include -#include -#include -#include - #ifdef SQLITE_STORAGE_ENABLED #include #endif -#ifdef __cplusplus -extern "C" { -#endif + +#include "private_structs.h" +#include "private_functions.h" +#include "core_private.h" #define STRING_RESET(field) if (field) bctbx_free(field); (field) = NULL @@ -132,951 +128,11 @@ extern "C" { #define STRING_TRANSFER(field, newvalue) do{ if (field){bctbx_free(field);field=NULL;}; field=newvalue; }while(0) - -struct _LinphoneQualityReporting{ - reporting_session_report_t * reports[3]; /**Store information on audio and video media streams (RFC 6035) */ - bool_t was_video_running; /*Keep video state since last check in order to detect its (de)activation*/ - LinphoneQualityReportingReportSendCb on_report_sent; -}; - -struct _LinphoneCallLog{ - belle_sip_object_t base; - void *user_data; - struct _LinphoneCore *lc; - LinphoneCallDir dir; /**< The direction of the call*/ - LinphoneCallStatus status; /**< The status of the call*/ - LinphoneAddress *from; /**= 6) || __GNUC__ > 4) -#pragma GCC diagnostic push -#endif -#if defined(__clang__) || defined(__GNUC__) -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif -#ifdef _MSC_VER -#pragma deprecated(message_state_changed_cb) -#endif - LinphoneChatMessageStateChangedCb message_state_changed_cb; -#if defined(__clang__) || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) -#pragma GCC diagnostic pop -#endif -};*/ - -typedef struct StunCandidate{ - char addr[64]; - int port; -}StunCandidate; - - -typedef struct _PortConfig{ - char multicast_ip[LINPHONE_IPADDR_SIZE]; - char multicast_bind_ip[LINPHONE_IPADDR_SIZE]; - int rtp_port; - int rtcp_port; -}PortConfig; - -LinphoneCallCbs *_linphone_call_cbs_new(void); - - -void linphone_call_notify_state_changed(LinphoneCall *call, LinphoneCallState cstate, const char *message); -void linphone_call_notify_dtmf_received(LinphoneCall *call, int dtmf); -void linphone_call_notify_encryption_changed(LinphoneCall *call, bool_t on, const char *authentication_token); -void linphone_call_notify_transfer_state_changed(LinphoneCall *call, LinphoneCallState cstate); -void linphone_call_notify_stats_updated(LinphoneCall *call, const LinphoneCallStats *stats); -void linphone_call_notify_info_message_received(LinphoneCall *call, const LinphoneInfoMessage *msg); -void linphone_call_notify_ack_processing(LinphoneCall *call, LinphoneHeaders *msg, bool_t is_received); - -LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg); -LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, LinphonePrivate::SalCallOp *op); -void _linphone_call_set_new_params(LinphoneCall *call, const LinphoneCallParams *params); -void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message); -/* private: */ -LinphoneCallLog * linphone_call_log_new(LinphoneCallDir dir, LinphoneAddress *from, LinphoneAddress * to); -void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state); -LinphonePlayer *linphone_call_build_player(LinphoneCall*call); -void linphone_call_refresh_sockets(LinphoneCall *call); -void linphone_call_replace_op(LinphoneCall *call, LinphonePrivate::SalOp *op); -void linphone_call_reinvite_to_recover_from_connection_loss(LinphoneCall *call); - -LinphonePrivate::SalCallOp *linphone_call_get_op(const LinphoneCall *call); -LinphoneProxyConfig * linphone_call_get_dest_proxy(const LinphoneCall *call); -LINPHONE_PUBLIC MediaStream * linphone_call_get_stream(LinphoneCall *call, LinphoneStreamType type); -LinphoneCallLog * linphone_call_get_log(const LinphoneCall *call); -IceSession * linphone_call_get_ice_session(const LinphoneCall *call); -bool_t linphone_call_get_audio_muted(const LinphoneCall *call); -void linphone_call_set_audio_muted(LinphoneCall *call, bool_t value); -bool_t linphone_call_get_all_muted(const LinphoneCall *call); - -LinphoneCallParams * linphone_call_params_new(LinphoneCore *core); -SalMediaProto get_proto_from_call_params(const LinphoneCallParams *params); -SalStreamDir get_audio_dir_from_call_params(const LinphoneCallParams *params); -SalStreamDir get_video_dir_from_call_params(const LinphoneCallParams *params); -void linphone_call_params_set_custom_headers(LinphoneCallParams *params, const SalCustomHeader *ch); -void linphone_call_params_set_custom_sdp_attributes(LinphoneCallParams *params, const SalCustomSdpAttribute *csa); -void linphone_call_params_set_custom_sdp_media_attributes(LinphoneCallParams *params, LinphoneStreamType type, const SalCustomSdpAttribute *csa); -bool_t linphone_call_params_get_in_conference(const LinphoneCallParams *params); -void linphone_call_params_set_in_conference(LinphoneCallParams *params, bool_t value); -bool_t linphone_call_params_get_internal_call_update(const LinphoneCallParams *params); -void linphone_call_params_set_internal_call_update(LinphoneCallParams *params, bool_t value); -bool_t linphone_call_params_implicit_rtcp_fb_enabled(const LinphoneCallParams *params); -void linphone_call_params_enable_implicit_rtcp_fb(LinphoneCallParams *params, bool_t value); -int linphone_call_params_get_down_bandwidth(const LinphoneCallParams *params); -void linphone_call_params_set_down_bandwidth(LinphoneCallParams *params, int value); -int linphone_call_params_get_up_bandwidth(const LinphoneCallParams *params); -void linphone_call_params_set_up_bandwidth(LinphoneCallParams *params, int value); -int linphone_call_params_get_down_ptime(const LinphoneCallParams *params); -void linphone_call_params_set_down_ptime(LinphoneCallParams *params, int value); -int linphone_call_params_get_up_ptime(const LinphoneCallParams *params); -void linphone_call_params_set_up_ptime(LinphoneCallParams *params, int value); -SalCustomHeader * linphone_call_params_get_custom_headers(const LinphoneCallParams *params); -SalCustomSdpAttribute * linphone_call_params_get_custom_sdp_attributes(const LinphoneCallParams *params); -SalCustomSdpAttribute * linphone_call_params_get_custom_sdp_media_attributes(const LinphoneCallParams *params, LinphoneStreamType type); -LinphoneCall * linphone_call_params_get_referer(const LinphoneCallParams *params); -void linphone_call_params_set_referer(LinphoneCallParams *params, LinphoneCall *referer); -bool_t linphone_call_params_get_update_call_when_ice_completed(const LinphoneCallParams *params); -void linphone_call_params_set_update_call_when_ice_completed(LinphoneCallParams *params, bool_t value); -void linphone_call_params_set_sent_vsize(LinphoneCallParams *params, MSVideoSize vsize); -void linphone_call_params_set_recv_vsize(LinphoneCallParams *params, MSVideoSize vsize); -void linphone_call_params_set_sent_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef); -void linphone_call_params_set_received_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef); -void linphone_call_params_set_sent_fps(LinphoneCallParams *params, float value); -void linphone_call_params_set_received_fps(LinphoneCallParams *params, float value); -void linphone_call_params_set_used_audio_codec(LinphoneCallParams *params, OrtpPayloadType *codec); -void linphone_call_params_set_used_video_codec(LinphoneCallParams *params, OrtpPayloadType *codec); -void linphone_call_params_set_used_text_codec(LinphoneCallParams *params, OrtpPayloadType *codec); -bool_t linphone_call_params_get_no_user_consent(const LinphoneCallParams *params); -void linphone_call_params_set_no_user_consent(LinphoneCallParams *params, bool_t value); - -void linphone_auth_info_write_config(LinphoneConfig *config, LinphoneAuthInfo *obj, int pos); -LinphoneAuthInfo * linphone_auth_info_new_from_config_file(LpConfig *config, int pos); -void linphone_core_write_auth_info(LinphoneCore *lc, LinphoneAuthInfo *ai); -const LinphoneAuthInfo *_linphone_core_find_tls_auth_info(LinphoneCore *lc); -const LinphoneAuthInfo *_linphone_core_find_auth_info(LinphoneCore *lc, const char *realm, const char *username, const char *domain, bool_t ignore_realm); - -void linphone_core_update_proxy_register(LinphoneCore *lc); -const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc); - -int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphonePresenceModel *presence); -void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState rstate, const char *message); -void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig *obj); -void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc); -void _linphone_proxy_config_release(LinphoneProxyConfig *cfg); -void _linphone_proxy_config_unpublish(LinphoneProxyConfig *obj); -void linphone_proxy_config_notify_publish_state_changed(LinphoneProxyConfig *cfg, LinphonePublishState state); -LinphoneEvent *linphone_proxy_config_create_publish(LinphoneProxyConfig *cfg, const char *event, int expires); -/* - * returns service route as defined in as defined by rfc3608, might be a list instead of just one. - * Can be NULL - * */ -const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg); -const LinphoneAddress *_linphone_proxy_config_get_contact_without_params (const LinphoneProxyConfig *cfg); - -void linphone_friend_list_invalidate_subscriptions(LinphoneFriendList *list); -void linphone_friend_list_notify_presence_received(LinphoneFriendList *list, LinphoneEvent *lev, const LinphoneContent *body); -void linphone_friend_list_subscription_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state); -void _linphone_friend_list_release(LinphoneFriendList *list); -/*get rls either from list or core if any*/ -const LinphoneAddress * _linphone_friend_list_get_rls_address(const LinphoneFriendList *list); - -LINPHONE_PUBLIC void linphone_friend_invalidate_subscription(LinphoneFriend *lf); -void linphone_friend_close_subscriptions(LinphoneFriend *lf); -void _linphone_friend_release(LinphoneFriend *lf); -LINPHONE_PUBLIC void linphone_friend_update_subscribes(LinphoneFriend *fr, bool_t only_when_registered); -void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence); -void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc); -void linphone_friend_add_incoming_subscription(LinphoneFriend *lf, LinphonePrivate::SalOp *op); -void linphone_friend_remove_incoming_subscription(LinphoneFriend *lf, LinphonePrivate::SalOp *op); -const char * linphone_friend_phone_number_to_sip_uri(LinphoneFriend *lf, const char *phone_number); -const char * linphone_friend_sip_uri_to_phone_number(LinphoneFriend *lf, const char *uri); -void linphone_friend_clear_presence_models(LinphoneFriend *lf); -LinphoneFriend *linphone_friend_list_find_friend_by_inc_subscribe(const LinphoneFriendList *list, LinphonePrivate::SalOp *op); -LinphoneFriend *linphone_friend_list_find_friend_by_out_subscribe(const LinphoneFriendList *list, LinphonePrivate::SalOp *op); -LinphoneFriend *linphone_core_find_friend_by_out_subscribe(const LinphoneCore *lc, LinphonePrivate::SalOp *op); -LinphoneFriend *linphone_core_find_friend_by_inc_subscribe(const LinphoneCore *lc, LinphonePrivate::SalOp *op); -MSList *linphone_find_friend_by_address(MSList *fl, const LinphoneAddress *addr, LinphoneFriend **lf); -bool_t linphone_core_should_subscribe_friends_only_when_registered(const LinphoneCore *lc); -void linphone_core_update_friends_subscriptions(LinphoneCore *lc); -void _linphone_friend_list_update_subscriptions(LinphoneFriendList *list, LinphoneProxyConfig *cfg, bool_t only_when_registered); -void linphone_core_friends_storage_init(LinphoneCore *lc); -void linphone_core_friends_storage_close(LinphoneCore *lc); -void linphone_core_store_friend_in_db(LinphoneCore *lc, LinphoneFriend *lf); -void linphone_core_remove_friend_from_db(LinphoneCore *lc, LinphoneFriend *lf); -void linphone_core_store_friends_list_in_db(LinphoneCore *lc, LinphoneFriendList *list); -void linphone_core_remove_friends_list_from_db(LinphoneCore *lc, LinphoneFriendList *list); -LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_from_db(LinphoneCore *lc, LinphoneFriendList *list); -LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_lists_from_db(LinphoneCore *lc); -LINPHONE_PUBLIC LinphoneFriendListStatus linphone_friend_list_import_friend(LinphoneFriendList *list, LinphoneFriend *lf, bool_t synchronize); - -int linphone_parse_host_port(const char *input, char *host, size_t hostlen, int *port); -int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen, int default_port); - -bool_t host_has_ipv6_network(void); -bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret); - -static MS2_INLINE void set_string(char **dest, const char *src, bool_t lowercase){ - if (*dest){ - ms_free(*dest); - *dest=NULL; - } - if (src) { - *dest=ms_strdup(src); - if (lowercase) { - char *cur = *dest; - for (; *cur; cur++) *cur = (char)tolower(*cur); - } - } -} - -void linphone_process_authentication(LinphoneCore* lc, LinphonePrivate::SalOp *op); -void linphone_authentication_ok(LinphoneCore *lc, LinphonePrivate::SalOp *op); -void linphone_subscription_new(LinphoneCore *lc, LinphonePrivate::SalSubscribeOp *op, const char *from); -void linphone_core_send_presence(LinphoneCore *lc, LinphonePresenceModel *presence); -void linphone_notify_parse_presence(const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result); -void linphone_notify_convert_presence_to_xml(LinphonePrivate::SalOp *op, SalPresenceModel *presence, const char *contact, char **content); -void linphone_notify_recv(LinphoneCore *lc, LinphonePrivate::SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model); -void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, LinphonePrivate::SalOp *op); -void linphone_core_soundcard_hint_check(LinphoneCore* lc); - - -void linphone_subscription_answered(LinphoneCore *lc, LinphonePrivate::SalOp *op); -void linphone_subscription_closed(LinphoneCore *lc, LinphonePrivate::SalOp *op); - -void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc); - -LINPHONE_PUBLIC int linphone_run_stun_tests(LinphoneCore *lc, int audioPort, int videoPort, int textPort, - char *audioCandidateAddr, int *audioCandidatePort, char *videoCandidateAddr, int *videoCandidatePort, char *textCandidateAddr, int *textCandidatePort); -void linphone_core_resolve_stun_server(LinphoneCore *lc); -LINPHONE_PUBLIC const struct addrinfo *linphone_core_get_stun_server_addrinfo(LinphoneCore *lc); -LINPHONE_PUBLIC void linphone_core_enable_forced_ice_relay(LinphoneCore *lc, bool_t enable); -LINPHONE_PUBLIC void linphone_core_enable_short_turn_refresh(LinphoneCore *lc, bool_t enable); -void linphone_call_update_ice_state_in_call_stats(LinphoneCall *call); -LINPHONE_PUBLIC void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEvent *ev); -void linphone_call_stats_update(LinphoneCallStats *stats, MediaStream *stream); -LinphoneCallStats *_linphone_call_stats_new(void); -void _linphone_call_stats_uninit(LinphoneCallStats *stats); -void _linphone_call_stats_clone(LinphoneCallStats *dst, const LinphoneCallStats *src); -void _linphone_call_stats_set_ice_state (LinphoneCallStats *stats, LinphoneIceState state); -void _linphone_call_stats_set_type (LinphoneCallStats *stats, LinphoneStreamType type); -mblk_t *_linphone_call_stats_get_received_rtcp (const LinphoneCallStats *stats); -void _linphone_call_stats_set_received_rtcp (LinphoneCallStats *stats, mblk_t *m); -void _linphone_call_stats_set_sent_rtcp (LinphoneCallStats *stats, mblk_t *m); -int _linphone_call_stats_get_updated (const LinphoneCallStats *stats); -void _linphone_call_stats_set_updated (LinphoneCallStats *stats, int updated); -void _linphone_call_stats_set_rtp_stats (LinphoneCallStats *stats, const rtp_stats_t *rtpStats); -void _linphone_call_stats_set_download_bandwidth (LinphoneCallStats *stats, float bandwidth); -void _linphone_call_stats_set_upload_bandwidth (LinphoneCallStats *stats, float bandwidth); -void _linphone_call_stats_set_rtcp_download_bandwidth (LinphoneCallStats *stats, float bandwidth); -void _linphone_call_stats_set_rtcp_upload_bandwidth (LinphoneCallStats *stats, float bandwidth); -void _linphone_call_stats_set_ip_family_of_remote (LinphoneCallStats *stats, LinphoneAddressFamily family); -bool_t _linphone_call_stats_rtcp_received_via_mux (const LinphoneCallStats *stats); -void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall *call); -void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md, bool_t is_offer); -void linphone_call_clear_unused_ice_candidates(LinphoneCall *call, const SalMediaDescription *md); -bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md); - -void linphone_core_send_initial_subscribes(LinphoneCore *lc); -void linphone_core_write_friends_config(LinphoneCore* lc); -void linphone_friend_write_to_config_file(LinphoneConfig *config, LinphoneFriend *lf, int index); -LinphoneFriend * linphone_friend_new_from_config_file(struct _LinphoneCore *lc, int index); - -void linphone_proxy_config_update(LinphoneProxyConfig *cfg); -LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri); -const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to); -int linphone_core_get_local_ip_for(int type, const char *dest, char *result); -LINPHONE_PUBLIC void linphone_core_get_local_ip(LinphoneCore *lc, int af, const char *dest, char *result); - -LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore *lc, int index); -void linphone_proxy_config_write_to_config_file(LinphoneConfig* config,LinphoneProxyConfig *obj, int index); - -int linphone_core_message_received(LinphoneCore *lc, LinphonePrivate::SalOp *op, const SalMessage *msg); -void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, uint32_t character, LinphoneCall *call); - -void linphone_call_init_media_streams(LinphoneCall *call); -void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call); -void linphone_call_stop_media_streams(LinphoneCall *call); -void linphone_call_delete_upnp_session(LinphoneCall *call); -int _linphone_core_apply_transports(LinphoneCore *lc); - -void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose); -void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progresses); -void linphone_core_stop_waiting(LinphoneCore *lc); - -int linphone_call_proceed_with_invite_if_ready(LinphoneCall *call, LinphoneProxyConfig *dest_proxy); -int linphone_call_start_invite(LinphoneCall *call, const LinphoneAddress *destination/* = NULL if to be taken from the call log */); -/* - * param automatic_offering aims is to take into account previous answer for video in case of automatic re-invite. - * Purpose is to avoid to re-ask video previously declined */ -int linphone_call_start_update(LinphoneCall *call); -int linphone_call_start_accept_update(LinphoneCall *call, LinphoneCallState next_state, const char *state_info); -void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call); -bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md); -extern LinphonePrivate::Sal::Callbacks linphone_sal_callbacks; -LINPHONE_PUBLIC bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); -LINPHONE_PUBLIC bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc); -bool_t _linphone_core_is_conference_creation (const LinphoneCore *lc, const LinphoneAddress *addr); -LinphoneChatRoom *_linphone_core_create_server_group_chat_room (LinphoneCore *lc, LinphonePrivate::SalCallOp *op); - -void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description); - - -LINPHONE_PUBLIC LinphoneProxyConfigAddressComparisonResult linphone_proxy_config_address_equal(const LinphoneAddress *a, const LinphoneAddress *b); -LINPHONE_PUBLIC LinphoneProxyConfigAddressComparisonResult linphone_proxy_config_is_server_config_changed(const LinphoneProxyConfig* obj); -/** - * unregister without moving the register_enable flag - */ -void _linphone_proxy_config_unregister(LinphoneProxyConfig *obj); -void _linphone_proxy_config_release_ops(LinphoneProxyConfig *obj); - -/*chat*/ -LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, const char *uri, const char *subject); -LinphoneChatRoom *_linphone_server_group_chat_room_new (LinphoneCore *core, LinphonePrivate::SalCallOp *op); -void linphone_chat_room_release(LinphoneChatRoom *cr); -void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call); -LinphoneChatRoomCbs * linphone_chat_room_cbs_new (void); -/**/ - -struct _LinphoneProxyConfig -{ - belle_sip_object_t base; - void *user_data; - struct _LinphoneCore *lc; - LinphoneErrorInfo *ei; - char *reg_proxy; - char *reg_identity; - LinphoneAddress* identity_address; - LinphoneAddress *contact_address; - LinphoneAddress *contact_address_without_params; - char *reg_route; - char *quality_reporting_collector; - char *realm; - char *contact_params; - char *contact_uri_params; - int expires; - int publish_expires; - LinphonePrivate::SalRegisterOp *op; - SalCustomHeader *sent_headers; - char *type; - struct _SipSetupContext *ssctx; - int auth_failures; - char *dial_prefix; - LinphoneRegistrationState state; - LinphoneAVPFMode avpf_mode; - LinphoneNatPolicy *nat_policy; - - bool_t commit; - bool_t reg_sendregister; - bool_t publish; - bool_t dial_escape_plus; - - bool_t send_publish; - bool_t quality_reporting_enabled; - uint8_t avpf_rr_interval; - uint8_t quality_reporting_interval; - - time_t deletion_date; - LinphonePrivacyMask privacy; - /*use to check if server config has changed between edit() and done()*/ - LinphoneAddress *saved_proxy; - LinphoneAddress *saved_identity; - bool_t register_changed; - bool_t unused[3]; - /*---*/ - LinphoneAddress *pending_contact; /*use to store previous contact in case of network failure*/ - LinphoneEvent *presence_publish_event; - unsigned long long previous_publish_config_hash[2]; - - char *refkey; - char *sip_etag; /*publish context*/ -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneProxyConfig); - -struct _LinphoneAuthInfo -{ - belle_sip_object_t base; - char *username; - char *realm; - char *userid; - char *passwd; - char *ha1; - char *domain; - char *tls_cert; - char *tls_key; - char *tls_cert_path; - char *tls_key_path; - char *algorithm; -}; - -typedef enum _LinphoneIsComposingState { - LinphoneIsComposingIdle, - LinphoneIsComposingActive -} LinphoneIsComposingState; - -typedef struct _LinphoneChatMessageCharacter { - uint32_t value; - bool_t has_been_read; -} LinphoneChatMessageCharacter; - - -typedef struct _LinphoneFriendPresence { - char *uri_or_tel; - LinphonePresenceModel *presence; -} LinphoneFriendPresence; - -typedef struct _LinphoneFriendPhoneNumberSipUri { - char *number; - char *uri; -} LinphoneFriendPhoneNumberSipUri; - -struct _LinphoneFriend{ - belle_sip_object_t base; - void *user_data; - LinphoneAddress *uri; - MSList *insubs; /*list of SalOp. There can be multiple instances of a same Friend that subscribe to our presence*/ - LinphonePrivate::SalPresenceOp *outsub; - LinphoneSubscribePolicy pol; - MSList *presence_models; /* list of LinphoneFriendPresence. It associates SIP URIs and phone numbers with their respective presence models. */ - MSList *phone_number_sip_uri_map; /* list of LinphoneFriendPhoneNumberSipUri. It associates phone numbers with their corresponding SIP URIs. */ - struct _LinphoneCore *lc; - BuddyInfo *info; - char *refkey; - bool_t subscribe; - bool_t subscribe_active; - bool_t inc_subscribe_pending; - bool_t commit; - bool_t initial_subscribes_sent; /*used to know if initial subscribe message was sent or not*/ - bool_t presence_received; - LinphoneVcard *vcard; - unsigned int storage_id; - LinphoneFriendList *friend_list; - LinphoneSubscriptionState out_sub_state; -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneFriend); - -struct _LinphoneFriendListCbs { - belle_sip_object_t base; - void *user_data; - LinphoneFriendListCbsContactCreatedCb contact_created_cb; - LinphoneFriendListCbsContactDeletedCb contact_deleted_cb; - LinphoneFriendListCbsContactUpdatedCb contact_updated_cb; - LinphoneFriendListCbsSyncStateChangedCb sync_state_changed_cb; -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneFriendListCbs); - -struct _LinphoneFriendList { - belle_sip_object_t base; - void *user_data; - LinphoneCore *lc; - LinphoneEvent *event; - char *display_name; - char *rls_uri; /*this field is take in sync with rls_addr*/ - LinphoneAddress *rls_addr; - MSList *friends; - bctbx_map_t *friends_map; - bctbx_map_t *friends_map_uri; - unsigned char *content_digest; - int expected_notification_version; - unsigned int storage_id; - char *uri; - MSList *dirty_friends_to_update; - int revision; - LinphoneFriendListCbs *cbs; - bool_t enable_subscriptions; -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneFriendList); - - - -typedef struct sip_config -{ - char *contact; - char *guessed_contact; - MSList *proxies; - MSList *deleted_proxies; - int inc_timeout; /*timeout after an un-answered incoming call is rejected*/ - int in_call_timeout; /*timeout after a call is hangup */ - int delayed_timeout; /*timeout after a delayed call is resumed */ - unsigned int keepalive_period; /* interval in ms between keep alive messages sent to the proxy server*/ - LinphoneSipTransports transports; - bool_t guess_hostname; - bool_t loopback_only; - bool_t ipv6_enabled; - bool_t sdp_200_ack; - bool_t register_only_when_network_is_up; - bool_t register_only_when_upnp_is_ok; - bool_t ping_with_options; - bool_t auto_net_state_mon; - bool_t tcp_tls_keepalive; - bool_t vfu_with_info; /*use to enable vfu request using sip info*/ - bool_t save_auth_info; // if true, auth infos will be write in the config file when they are added to the list -} sip_config_t; - -typedef struct rtp_config -{ - int audio_rtp_min_port; - int audio_rtp_max_port; - int video_rtp_min_port; - int video_rtp_max_port; - int audio_jitt_comp; /*jitter compensation*/ - int video_jitt_comp; /*jitter compensation*/ - int nortp_timeout; - int disable_upnp; - MSCryptoSuite *srtp_suites; - LinphoneAVPFMode avpf_mode; - bool_t rtp_no_xmit_on_audio_mute; - /* stop rtp xmit when audio muted */ - bool_t audio_adaptive_jitt_comp_enabled; - bool_t video_adaptive_jitt_comp_enabled; - bool_t pad; - char* audio_multicast_addr; - bool_t audio_multicast_enabled; - int audio_multicast_ttl; - char* video_multicast_addr; - int video_multicast_ttl; - bool_t video_multicast_enabled; - int text_rtp_min_port; - int text_rtp_max_port; -}rtp_config_t; - - - -typedef struct net_config -{ - char *nat_address; /* may be IP or host name */ - char *nat_address_ip; /* ip translated from nat_address */ - struct addrinfo *stun_addrinfo; - int download_bw; - int upload_bw; - int mtu; - OrtpNetworkSimulatorParams netsim_params; - bool_t nat_sdp_only; -}net_config_t; - - -typedef struct sound_config -{ - struct _MSSndCard * ring_sndcard; /* the playback sndcard currently used */ - struct _MSSndCard * play_sndcard; /* the playback sndcard currently used */ - struct _MSSndCard * capt_sndcard; /* the capture sndcard currently used */ - struct _MSSndCard * lsd_card; /* dummy playback card for Linphone Sound Daemon extension */ - const char **cards; - int latency; /* latency in samples of the current used sound device */ - float soft_play_lev; /*playback gain in db.*/ - float soft_mic_lev; /*mic gain in db.*/ - char rec_lev; - char play_lev; - char ring_lev; - char source; - char *local_ring; - char *remote_ring; - char *ringback_tone; - bool_t ec; - bool_t ea; - bool_t agc; -} sound_config_t; - -typedef struct codecs_config -{ - MSList *audio_codecs; /* list of audio codecs in order of preference*/ - MSList *video_codecs; - MSList *text_codecs; - int dyn_pt; - int telephone_event_pt; -}codecs_config_t; - -typedef struct video_config{ - struct _MSWebCam *device; - const char **cams; - MSVideoSize vsize; - MSVideoSize preview_vsize; /*is 0,0 if no forced preview size is set, in which case vsize field above is used.*/ - LinphoneVideoDefinition *vdef; - LinphoneVideoDefinition *preview_vdef; - float fps; - bool_t capture; - bool_t show_local; - bool_t display; - bool_t selfview; /*during calls*/ - bool_t reuse_preview_source; -}video_config_t; - -typedef struct text_config{ - bool_t enabled; -}text_config_t; - -typedef struct ui_config -{ - int is_daemon; - int is_applet; - unsigned int timer_id; /* the timer id for registration */ -}ui_config_t; - - - -typedef struct autoreplier_config -{ - int enabled; - int after_seconds; /* accept the call after x seconds*/ - int max_users; /* maximum number of user that can call simultaneously */ - int max_rec_time; /* the max time of incoming voice recorded */ - int max_rec_msg; /* maximum number of recorded messages */ - const char *message; /* the path of the file to be played */ -}autoreplier_config_t; - - -typedef struct _LinphoneToneDescription{ - LinphoneReason reason; /*the call error code*/ - LinphoneToneID toneid; /*A tone type to play when this error arrives. This is played using tone generator*/ - char *audiofile; /*An override audio file to play instead, when this error arrives*/ - /*Note that some tones are not affected to any error, in which case it is affected LinphoneReasonNone*/ -}LinphoneToneDescription; - -LinphoneToneDescription * linphone_tone_description_new(LinphoneReason reason, LinphoneToneID id, const char *audiofile); -void linphone_tone_description_destroy(LinphoneToneDescription *obj); -LinphoneToneDescription *linphone_core_get_call_error_tone(const LinphoneCore *lc, LinphoneReason reason); -void linphone_core_play_call_error_tone(LinphoneCore *lc, LinphoneReason reason); -void _linphone_core_set_tone(LinphoneCore *lc, LinphoneReason reason, LinphoneToneID id, const char *audiofile); -LINPHONE_PUBLIC const char *linphone_core_get_tone_file(const LinphoneCore *lc, LinphoneToneID id); - -typedef struct _LinphoneTaskList{ - MSList *hooks; -}LinphoneTaskList; - -void linphone_task_list_init(LinphoneTaskList *t); -void linphone_task_list_add(LinphoneTaskList *t, LinphoneCoreIterateHook hook, void *hook_data); -void linphone_task_list_remove(LinphoneTaskList *t, LinphoneCoreIterateHook hook, void *hook_data); -void linphone_task_list_run(LinphoneTaskList *t); -void linphone_task_list_free(LinphoneTaskList *t); - - -struct _LinphoneCoreCbs { - belle_sip_object_t base; - LinphoneCoreVTable *vtable; - bool_t autorelease; -}; - -LinphoneCoreCbs * _linphone_core_cbs_new(void); -void _linphone_core_cbs_set_v_table(LinphoneCoreCbs *cbs, LinphoneCoreVTable *vtable, bool_t autorelease); - -typedef struct _LCCallbackObj { - LinphoneCoreCbFunc _func; - void *_user_data; -} LCCallbackObj; - -namespace LinphonePrivate { - class Core; -}; - -struct _LinphoneCore -{ - belle_sip_object_t base; - MSFactory* factory; - MSList* vtable_refs; - int vtable_notify_recursion; - LinphonePrivate::Sal *sal; - - // For migration purposes - std::shared_ptr cppCore; - - void *platform_helper; /*is a LinphonePrivate::PlatformHelpers but cannot be used as is because private.h is compiled as C in testers.*/ - - LinphoneGlobalState state; - struct _LpConfig *config; - MSList *default_audio_codecs; - MSList *default_video_codecs; - MSList *default_text_codecs; - net_config_t net_conf; - sip_config_t sip_conf; - rtp_config_t rtp_conf; - sound_config_t sound_conf; - video_config_t video_conf; - text_config_t text_conf; - codecs_config_t codecs_conf; - ui_config_t ui_conf; - autoreplier_config_t autoreplier_conf; - LinphoneProxyConfig *default_proxy; - MSList *friends_lists; - MSList *auth_info; - struct _RingStream *ringstream; - time_t dmfs_playing_start_time; - LCCallbackObj preview_finished_cb; - LinphoneCall *current_call; /* the current call */ - MSList *calls; /* all the processed calls */ - MSList *queued_calls; /* used by the autoreplier */ - MSList *call_logs; - int max_call_logs; - int missed_calls; - VideoPreview *previewstream; - struct _MSEventQueue *msevq; - LinphoneRtpTransportFactories *rtptf; - MSList *bl_reqs; - MSList *subscribers; /* unknown subscribers */ - int minutes_away; - LinphonePresenceModel *presence_model; - void *data; - char *play_file; - char *rec_file; - uint64_t prevtime_ms; - int audio_bw; /*IP bw consumed by audio codec, set as soon as used codec is known, its purpose is to know the remaining bw for video*/ - LinphoneCoreWaitingCallback wait_cb; - void *wait_ctx; - void *video_window_id; - void *preview_window_id; - time_t netup_time; /*time when network went reachable */ - struct _EcCalibrator *ecc; - struct _EchoTester *ect; - LinphoneTaskList hooks; /*tasks periodically executed in linphone_core_iterate()*/ - LinphoneConference *conf_ctx; - char* zrtp_secrets_cache; /**< zrtp cache filename */ - char* user_certificates_path; - LinphoneVideoPolicy video_policy; - time_t network_last_check; - LinphoneNatPolicy *nat_policy; - LinphoneImNotifPolicy *im_notif_policy; - - bool_t use_files; - bool_t apply_nat_settings; - bool_t initial_subscribes_sent; - bool_t bl_refresh; - - bool_t preview_finished; - bool_t auto_net_state_mon; - bool_t sip_network_reachable; - bool_t media_network_reachable; - - bool_t network_reachable_to_be_notified; /*set to true when state must be notified in next iterate*/ - bool_t use_preview_window; - bool_t network_last_status; - bool_t ringstream_autorelease; - - bool_t vtables_running; - bool_t send_call_stats_periodical_updates; - bool_t forced_ice_relay; - bool_t short_turn_refresh; - - char localip[LINPHONE_IPADDR_SIZE]; - int device_rotation; - int max_calls; - LinphoneTunnel *tunnel; - char* device_id; - char *logs_db_file; - char *friends_db_file; -#ifdef SQLITE_STORAGE_ENABLED - sqlite3 *zrtp_cache_db; /**< zrtp sqlite cache, used by both zrtp and lime */ - sqlite3 *logs_db; - sqlite3 *friends_db; - bool_t debug_storage; -#endif - belle_http_provider_t *http_provider; - belle_tls_crypto_config_t *http_crypto_config; - belle_http_request_listener_t *provisioning_http_listener; -#ifdef ENABLE_UPDATE_CHECK - belle_http_request_listener_t *update_check_http_listener; - char *update_check_current_version; -#endif - MSList *tones; - LinphoneReason chat_deny_code; - char *file_transfer_server; - const char **supported_formats; - LinphoneContent *log_collection_upload_information; - LinphoneCoreCbs *current_cbs; // the latest LinphoneCoreCbs object to call a callback, see linphone_core_get_current_cbs() - LinphoneRingtonePlayer *ringtoneplayer; - LinphoneVcardContext *vcard_context; - - /*for tests only*/ - bool_t zrtp_not_available_simulation; - - /* string for TLS auth instead of path to files */ - char *tls_cert; - char *tls_key; - - LinphoneAddress *default_rls_addr; /*default resource list server*/ - LinphoneImEncryptionEngine *im_encryption_engine; - struct _LinphoneAccountCreatorService *default_ac_service; - MSBandwidthController *bw_controller; - - // For migration purpose. - bctbx_list_t *chat_rooms; -}; - #ifdef __cplusplus #define getPlatformHelpers(lc) static_cast(lc->platform_helper) #endif -struct _LinphoneEvent{ - belle_sip_object_t base; - LinphoneErrorInfo *ei; - LinphoneSubscriptionDir dir; - LinphoneCore *lc; - LinphonePrivate::SalEventOp *op; - SalCustomHeader *send_custom_headers; - LinphoneSubscriptionState subscription_state; - LinphonePublishState publish_state; - void *userdata; - char *name; - int expires; - bool_t terminating; - bool_t is_out_of_dialog_op; /*used for out of dialog notify*/ - bool_t internal; - bool_t oneshot; - - // For migration purpose. (Do not use directly!) - // Cache. - LinphoneAddress *to_address; - LinphoneAddress *from_address; - LinphoneAddress *remote_contact_address; -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneEvent); - -LinphoneTunnel *linphone_core_tunnel_new(LinphoneCore *lc); -void linphone_tunnel_configure(LinphoneTunnel *tunnel); -void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, OrtpLogFunc logHandler); - -/** - * Check if we do not have exceed the number of simultaneous call - * - * @ingroup call_control -**/ -bool_t linphone_core_can_we_add_call(LinphoneCore *lc); - -int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call); -int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call); -int linphone_core_get_calls_nb(const LinphoneCore *lc); - -void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); -void linphone_call_update_biggest_desc(LinphoneCall *call, SalMediaDescription *md); -void linphone_call_make_local_media_description(LinphoneCall *call); -void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, LinphoneCall *call, LinphoneCallParams *params); - -bool_t linphone_core_is_payload_type_usable_for_bandwidth(const LinphoneCore *lc, const PayloadType *pt, int bandwidth_limit); - -#define linphone_core_ready(lc) ((lc)->state==LinphoneGlobalOn || (lc)->state==LinphoneGlobalShutdown) -void _linphone_core_configure_resolver(void); - -void linphone_core_initialize_supported_content_types(LinphoneCore *lc); - -struct _EcCalibrator{ - MSFactory *factory; - ms_thread_t thread; - MSSndCard *play_card,*capt_card; - MSFilter *sndread,*det,*rec; - MSFilter *play, *gen, *sndwrite; - MSFilter *read_resampler,*write_resampler; - MSTicker *ticker; -#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) -#pragma GCC diagnostic push -#endif -#ifdef _MSC_VER -#pragma warning(disable : 4996) -#else -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif - LinphoneEcCalibrationCallback cb; - void *cb_data; - LinphoneEcCalibrationAudioInit audio_init_cb; - LinphoneEcCalibrationAudioUninit audio_uninit_cb; -#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) -#pragma GCC diagnostic pop -#endif - int64_t acc; - int delay; - unsigned int rate; - LinphoneEcCalibratorStatus status; - bool_t freq1,freq2,freq3; - bool_t play_cool_tones; -}; - -typedef struct _EcCalibrator EcCalibrator; - -LinphoneEcCalibratorStatus ec_calibrator_get_status(EcCalibrator *ecc); - -void ec_calibrator_destroy(EcCalibrator *ecc); - -struct _EchoTester { - MSFactory *factory; - MSFilter *in,*out; - MSSndCard *capture_card; - MSSndCard *playback_card; - MSTicker *ticker; - unsigned int rate; -}; - -typedef struct _EchoTester EchoTester; - -void linphone_call_set_broken(LinphoneCall *call); -void linphone_call_repair_if_broken(LinphoneCall *call); -void linphone_core_repair_calls(LinphoneCore *lc); -int linphone_core_preempt_sound_resources(LinphoneCore *lc); -int _linphone_call_pause(LinphoneCall *call); - -/*conferencing subsystem*/ -void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted); -bool_t linphone_core_sound_resources_available(LinphoneCore *lc); -void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, LinphoneCall *newcall); -LINPHONE_PUBLIC unsigned int linphone_core_get_audio_features(LinphoneCore *lc); - -void _linphone_core_codec_config_write(LinphoneCore *lc); - #define HOLD_OFF (0) #define HOLD_ON (1) @@ -1093,503 +149,6 @@ void _linphone_core_codec_config_write(LinphoneCore *lc); #endif #endif -LINPHONE_PUBLIC bctbx_list_t * linphone_core_read_call_logs_from_config_file(LinphoneCore *lc); -void call_logs_write_to_config_file(LinphoneCore *lc); -void linphone_core_call_log_storage_init(LinphoneCore *lc); -void linphone_core_call_log_storage_close(LinphoneCore *lc); -void linphone_core_store_call_log(LinphoneCore *lc, LinphoneCallLog *log); -LINPHONE_PUBLIC const MSList *linphone_core_get_call_history(LinphoneCore *lc); -LINPHONE_PUBLIC void linphone_core_delete_call_history(LinphoneCore *lc); -LINPHONE_PUBLIC void linphone_core_delete_call_log(LinphoneCore *lc, LinphoneCallLog *log); -LINPHONE_PUBLIC int linphone_core_get_call_history_size(LinphoneCore *lc); - -int linphone_core_get_edge_bw(LinphoneCore *lc); -int linphone_core_get_edge_ptime(LinphoneCore *lc); - -LinphoneCore *_linphone_core_new_with_config(LinphoneCoreCbs *cbs, struct _LpConfig *config, void *userdata, void *system_context); - -int linphone_upnp_init(LinphoneCore *lc); -void linphone_upnp_destroy(LinphoneCore *lc); - -#ifdef SQLITE_STORAGE_ENABLED -int _linphone_sqlite3_open(const char *db_file, sqlite3 **db); -#endif - -void linphone_chat_message_set_time(LinphoneChatMessage* msg, time_t time); -void linphone_chat_message_set_incoming(LinphoneChatMessage *msg); -void linphone_chat_message_set_outgoing(LinphoneChatMessage *msg); -LinphoneChatMessageStateChangedCb linphone_chat_message_get_message_state_changed_cb(LinphoneChatMessage* msg); -void linphone_chat_message_set_message_state_changed_cb(LinphoneChatMessage* msg, LinphoneChatMessageStateChangedCb cb); -void linphone_chat_message_set_message_state_changed_cb_user_data(LinphoneChatMessage* msg, void *user_data); -void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChatMessage* msg); -void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessageState state); -void linphone_chat_message_set_message_id(LinphoneChatMessage *msg, char *id); -void linphone_chat_message_set_storage_id(LinphoneChatMessage *msg, unsigned int id); -SalCustomHeader * linphone_chat_message_get_sal_custom_headers(const LinphoneChatMessage *msg); -void linphone_chat_message_set_sal_custom_headers(LinphoneChatMessage *msg, SalCustomHeader *header); -belle_http_request_t * linphone_chat_message_get_http_request(const LinphoneChatMessage *msg); -void linphone_chat_message_set_http_request(LinphoneChatMessage *msg, belle_http_request_t *request); -void linphone_chat_message_set_file_transfer_information(LinphoneChatMessage *msg, LinphoneContent *content); -LinphoneChatMessageDir linphone_chat_message_get_direction(const LinphoneChatMessage *msg); -LinphonePrivate::SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg); -void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, LinphonePrivate::SalOp *op); -void linphone_chat_message_destroy(LinphoneChatMessage* msg); -void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state); -void linphone_chat_message_set_is_secured(LinphoneChatMessage *msg, bool_t secured); -void linphone_chat_message_send_delivery_notification(LinphoneChatMessage *cm, LinphoneReason reason); -void linphone_chat_message_send_display_notification(LinphoneChatMessage *cm); -void _linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg, bool_t unref); -int linphone_chat_room_upload_file(LinphoneChatMessage *msg); -LinphoneChatRoom *_linphone_core_create_chat_room_from_call(LinphoneCall *call); -void linphone_chat_room_remove_transient_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg); -void linphone_chat_message_deactivate(LinphoneChatMessage *msg); -void linphone_chat_message_release(LinphoneChatMessage *msg); -void linphone_chat_message_fetch_content_from_database(sqlite3 *db, LinphoneChatMessage *message, int content_id); - -void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID id); -bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc); -const char *linphone_core_create_uuid(LinphoneCore *lc); -void linphone_configure_op(LinphoneCore *lc, LinphonePrivate::SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact); -void linphone_configure_op_with_proxy(LinphoneCore *lc, LinphonePrivate::SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact, LinphoneProxyConfig *proxy); -void linphone_call_create_op(LinphoneCall *call); -LinphoneContent * linphone_content_new(void); -LinphoneContent * linphone_content_copy(const LinphoneContent *ref); -SalBodyHandler *sal_body_handler_from_content(const LinphoneContent *content); -SalReason linphone_reason_to_sal(LinphoneReason reason); -LinphoneReason linphone_reason_from_sal(SalReason reason); -void linphone_error_info_to_sal(const LinphoneErrorInfo* ei, SalErrorInfo* sei); -LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, int expires); -LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, LinphonePrivate::SalEventOp *op, LinphoneSubscriptionDir dir, const char *name); -void linphone_event_unpublish(LinphoneEvent *lev); -/** - * Useful for out of dialog notify - * */ -LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, LinphonePrivate::SalEventOp *op, LinphoneSubscriptionDir dir, const char *name); -void linphone_event_set_internal(LinphoneEvent *lev, bool_t internal); -bool_t linphone_event_is_internal(LinphoneEvent *lev); -void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state); -void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState state); -LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss); -LinphoneContent *linphone_content_from_sal_body_handler(SalBodyHandler *ref); -void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc); -void linphone_core_register_offer_answer_providers(LinphoneCore *lc); - - -struct _LinphoneContent { - belle_sip_object_t base; - void *user_data; - SalBodyHandler *body_handler; - char *name; /**< used by RCS File transfer messages to store the original filename of the file to be downloaded from server */ - char *key; /**< used by RCS File transfer messages to store the key to encrypt file if needed */ - size_t keyLength; /**< Length of key in bytes */ - void *cryptoContext; /**< crypto context used to encrypt file for RCS file transfer */ - bool_t owned_fields; -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneContent); - -struct _LinphoneBuffer { - belle_sip_object_t base; - void *user_data; - uint8_t *content; /**< A pointer to the buffer content */ - size_t size; /**< The size of the buffer content */ -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneBuffer); - -struct _LinphoneNatPolicy { - belle_sip_object_t base; - void *user_data; - LinphoneCore *lc; - belle_sip_resolver_context_t *stun_resolver_context; - struct addrinfo *stun_addrinfo; - char *stun_server; - char *stun_server_username; - char *ref; - bool_t stun_enabled; - bool_t turn_enabled; - bool_t ice_enabled; - bool_t upnp_enabled; -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneNatPolicy); - -bool_t linphone_nat_policy_stun_server_activated(LinphoneNatPolicy *policy); -void linphone_nat_policy_save_to_config(const LinphoneNatPolicy *policy); - -struct _LinphoneImNotifPolicy { - belle_sip_object_t base; - void *user_data; - LinphoneCore *lc; - bool_t send_is_composing; - bool_t recv_is_composing; - bool_t send_imdn_delivered; - bool_t recv_imdn_delivered; - bool_t send_imdn_displayed; - bool_t recv_imdn_displayed; -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneImNotifPolicy); - -void linphone_core_create_im_notif_policy(LinphoneCore *lc); - - -/***************************************************************************** - * XML-RPC interface * - ****************************************************************************/ - -typedef struct _LinphoneXmlRpcArg { - LinphoneXmlRpcArgType type; - union { - int i; - char *s; - } data; -} LinphoneXmlRpcArg; - -struct _LinphoneXmlRpcRequestCbs { - belle_sip_object_t base; - void *user_data; - LinphoneXmlRpcRequestCbsResponseCb response; -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneXmlRpcRequestCbs); - -struct _LinphoneXmlRpcRequest { - belle_sip_object_t base; - void *user_data; - LinphoneXmlRpcRequestCbs *callbacks; - belle_sip_list_t *arg_list; - char *content; /**< The string representation of the XML-RPC request */ - char *method; - LinphoneXmlRpcStatus status; - LinphoneXmlRpcArg response; -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneXmlRpcRequest); - -struct _LinphoneXmlRpcSession { - belle_sip_object_t base; - void *user_data; - LinphoneCore *core; - char *url; - bool_t released; -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneXmlRpcSession); - - - -/***************************************************************************** - * CardDAV interface * - ****************************************************************************/ - -struct _LinphoneCardDavContext { - LinphoneFriendList *friend_list; - int ctag; - void *user_data; - LinphoneCardDavContactCreatedCb contact_created_cb; - LinphoneCardDavContactUpdatedCb contact_updated_cb; - LinphoneCardDavContactRemovedCb contact_removed_cb; - LinphoneCardDavSynchronizationDoneCb sync_done_cb; - LinphoneAuthInfo *auth_info; -}; - -struct _LinphoneCardDavQuery { - LinphoneCardDavContext *context; - char *url; - const char *method; - char *body; - const char *depth; - const char *ifmatch; - belle_http_request_listener_t *http_request_listener; - void *user_data; - LinphoneCardDavQueryType type; -}; - -struct _LinphoneCardDavResponse { - char *etag; - char *url; - char *vcard; -}; - -/***************************************************************************** - * REMOTE PROVISIONING FUNCTIONS * - ****************************************************************************/ - -void linphone_configuring_terminated(LinphoneCore *lc, LinphoneConfiguringState state, const char *message); -int linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri); -LINPHONE_PUBLIC int linphone_remote_provisioning_load_file( LinphoneCore* lc, const char* file_path); - -/***************************************************************************** - * Player interface * - ****************************************************************************/ - -struct _LinphonePlayerCbs { - belle_sip_object_t base; - void *user_data; - LinphonePlayerCbsEofReachedCb eof; -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphonePlayerCbs); - -LinphonePlayerCbs *linphone_player_cbs_new(void); - -struct _LinphonePlayer{ - belle_sip_object_t base; - void *user_data; - int (*open)(LinphonePlayer* player, const char *filename); - int (*start)(LinphonePlayer* player); - int (*pause)(LinphonePlayer* player); - int (*seek)(LinphonePlayer* player, int time_ms); - MSPlayerState (*get_state)(LinphonePlayer* player); - int (*get_duration)(LinphonePlayer *player); - int (*get_position)(LinphonePlayer *player); - void (*close)(LinphonePlayer* player); - void (*destroy)(LinphonePlayer *player); - void *impl; - LinphonePlayerCbs *callbacks; -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphonePlayer); - -LinphonePlayer * linphone_player_new(void); -void _linphone_player_destroy(LinphonePlayer *player); - - -/***************************************************************************** - * XML UTILITY FUNCTIONS * - ****************************************************************************/ - -#define XMLPARSING_BUFFER_LEN 2048 -#define MAX_XPATH_LENGTH 256 - -typedef struct _xmlparsing_context { - xmlDoc *doc; - xmlXPathContextPtr xpath_ctx; - char errorBuffer[XMLPARSING_BUFFER_LEN]; - char warningBuffer[XMLPARSING_BUFFER_LEN]; -} xmlparsing_context_t; - -xmlparsing_context_t * linphone_xmlparsing_context_new(void); -void linphone_xmlparsing_context_destroy(xmlparsing_context_t *ctx); -void linphone_xmlparsing_genericxml_error(void *ctx, const char *fmt, ...); -int linphone_create_xml_xpath_context(xmlparsing_context_t *xml_ctx); -void linphone_xml_xpath_context_set_node(xmlparsing_context_t *xml_ctx, xmlNodePtr node); -char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression); -char * linphone_get_xml_attribute_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression, const char *attribute_name); -void linphone_free_xml_text_content(char *text); -xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression); -void linphone_xml_xpath_context_init_carddav_ns(xmlparsing_context_t *xml_ctx); - -/***************************************************************************** - * OTHER UTILITY FUNCTIONS * - ****************************************************************************/ -char * linphone_timestamp_to_rfc3339_string(time_t timestamp); - - -void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const LinphonePrivate::SalOp *op); - -void payload_type_set_enable(OrtpPayloadType *pt, bool_t value); -bool_t payload_type_enabled(const OrtpPayloadType *pt); - -LinphonePayloadType *linphone_payload_type_new(LinphoneCore *lc, OrtpPayloadType *ortp_pt); -bool_t _linphone_core_check_payload_type_usability(const LinphoneCore *lc, const OrtpPayloadType *pt); -OrtpPayloadType *linphone_payload_type_get_ortp_pt(const LinphonePayloadType *pt); - - -const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc); -MsZrtpCryptoTypesCount linphone_core_get_zrtp_key_agreement_suites(LinphoneCore *lc, MSZrtpKeyAgreement keyAgreements[MS_MAX_ZRTP_CRYPTO_TYPES]); -MsZrtpCryptoTypesCount linphone_core_get_zrtp_cipher_suites(LinphoneCore *lc, MSZrtpCipher ciphers[MS_MAX_ZRTP_CRYPTO_TYPES]); -MsZrtpCryptoTypesCount linphone_core_get_zrtp_hash_suites(LinphoneCore *lc, MSZrtpHash hashes[MS_MAX_ZRTP_CRYPTO_TYPES]); -MsZrtpCryptoTypesCount linphone_core_get_zrtp_auth_suites(LinphoneCore *lc, MSZrtpAuthTag authTags[MS_MAX_ZRTP_CRYPTO_TYPES]); -MsZrtpCryptoTypesCount linphone_core_get_zrtp_sas_suites(LinphoneCore *lc, MSZrtpSasType sasTypes[MS_MAX_ZRTP_CRYPTO_TYPES]); - -struct _LinphoneImEncryptionEngineCbs { - belle_sip_object_t base; - void *user_data; - LinphoneImEncryptionEngineCbsIncomingMessageCb process_incoming_message; - LinphoneImEncryptionEngineCbsOutgoingMessageCb process_outgoing_message; - LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer; - LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb generate_file_transfer_key; - LinphoneImEncryptionEngineCbsDownloadingFileCb process_downlading_file; - LinphoneImEncryptionEngineCbsUploadingFileCb process_uploading_file; -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneImEncryptionEngineCbs); - -LinphoneImEncryptionEngineCbs * linphone_im_encryption_engine_cbs_new(void); - -struct _LinphoneImEncryptionEngine { - belle_sip_object_t base; - void *user_data; - LinphoneCore *lc; - LinphoneImEncryptionEngineCbs *callbacks; -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneImEncryptionEngine); - -struct _LinphoneRange { - belle_sip_object_t base; - void *user_data; - int min; - int max; -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneRange); - -LinphoneRange *linphone_range_new(void); - -struct _LinphoneTransports { - belle_sip_object_t base; - void *user_data; - int udp_port; /**< SIP/UDP port */ - int tcp_port; /**< SIP/TCP port */ - int dtls_port; /**< SIP/DTLS port */ - int tls_port; /**< SIP/TLS port */ -}; - -BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneTransports); - -LINPHONE_PUBLIC LinphoneTransports *linphone_transports_new(void); - -struct _LinphoneVideoActivationPolicy { - belle_sip_object_t base; - void *user_data; - bool_t automatically_initiate; /** +#include +#include +#include + +#include "private_types.h" +#include "tester_utils.h" +#include "sal/op.h" +#include "sal/event-op.h" + +#include "linphone/core_utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +LinphoneCallCbs *_linphone_call_cbs_new(void); + +void linphone_call_notify_state_changed(LinphoneCall *call, LinphoneCallState cstate, const char *message); +void linphone_call_notify_dtmf_received(LinphoneCall *call, int dtmf); +void linphone_call_notify_encryption_changed(LinphoneCall *call, bool_t on, const char *authentication_token); +void linphone_call_notify_transfer_state_changed(LinphoneCall *call, LinphoneCallState cstate); +void linphone_call_notify_stats_updated(LinphoneCall *call, const LinphoneCallStats *stats); +void linphone_call_notify_info_message_received(LinphoneCall *call, const LinphoneInfoMessage *msg); +void linphone_call_notify_ack_processing(LinphoneCall *call, LinphoneHeaders *msg, bool_t is_received); + +LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg); +LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, LinphonePrivate::SalCallOp *op); +void _linphone_call_set_new_params(LinphoneCall *call, const LinphoneCallParams *params); +void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message); +/* private: */ +LinphoneCallLog * linphone_call_log_new(LinphoneCallDir dir, LinphoneAddress *from, LinphoneAddress * to); +void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state); +LinphonePlayer *linphone_call_build_player(LinphoneCall*call); +void linphone_call_refresh_sockets(LinphoneCall *call); +void linphone_call_replace_op(LinphoneCall *call, LinphonePrivate::SalOp *op); +void linphone_call_reinvite_to_recover_from_connection_loss(LinphoneCall *call); + +LinphonePrivate::SalCallOp *linphone_call_get_op(const LinphoneCall *call); +LinphoneProxyConfig * linphone_call_get_dest_proxy(const LinphoneCall *call); +LINPHONE_PUBLIC MediaStream * linphone_call_get_stream(LinphoneCall *call, LinphoneStreamType type); +LinphoneCallLog * linphone_call_get_log(const LinphoneCall *call); +IceSession * linphone_call_get_ice_session(const LinphoneCall *call); +bool_t linphone_call_get_audio_muted(const LinphoneCall *call); +void linphone_call_set_audio_muted(LinphoneCall *call, bool_t value); +bool_t linphone_call_get_all_muted(const LinphoneCall *call); + +LinphoneCallParams * linphone_call_params_new(LinphoneCore *core); +SalMediaProto get_proto_from_call_params(const LinphoneCallParams *params); +SalStreamDir get_audio_dir_from_call_params(const LinphoneCallParams *params); +SalStreamDir get_video_dir_from_call_params(const LinphoneCallParams *params); +void linphone_call_params_set_custom_headers(LinphoneCallParams *params, const SalCustomHeader *ch); +void linphone_call_params_set_custom_sdp_attributes(LinphoneCallParams *params, const SalCustomSdpAttribute *csa); +void linphone_call_params_set_custom_sdp_media_attributes(LinphoneCallParams *params, LinphoneStreamType type, const SalCustomSdpAttribute *csa); +bool_t linphone_call_params_get_in_conference(const LinphoneCallParams *params); +void linphone_call_params_set_in_conference(LinphoneCallParams *params, bool_t value); +bool_t linphone_call_params_get_internal_call_update(const LinphoneCallParams *params); +void linphone_call_params_set_internal_call_update(LinphoneCallParams *params, bool_t value); +bool_t linphone_call_params_implicit_rtcp_fb_enabled(const LinphoneCallParams *params); +void linphone_call_params_enable_implicit_rtcp_fb(LinphoneCallParams *params, bool_t value); +int linphone_call_params_get_down_bandwidth(const LinphoneCallParams *params); +void linphone_call_params_set_down_bandwidth(LinphoneCallParams *params, int value); +int linphone_call_params_get_up_bandwidth(const LinphoneCallParams *params); +void linphone_call_params_set_up_bandwidth(LinphoneCallParams *params, int value); +int linphone_call_params_get_down_ptime(const LinphoneCallParams *params); +void linphone_call_params_set_down_ptime(LinphoneCallParams *params, int value); +int linphone_call_params_get_up_ptime(const LinphoneCallParams *params); +void linphone_call_params_set_up_ptime(LinphoneCallParams *params, int value); +SalCustomHeader * linphone_call_params_get_custom_headers(const LinphoneCallParams *params); +SalCustomSdpAttribute * linphone_call_params_get_custom_sdp_attributes(const LinphoneCallParams *params); +SalCustomSdpAttribute * linphone_call_params_get_custom_sdp_media_attributes(const LinphoneCallParams *params, LinphoneStreamType type); +LinphoneCall * linphone_call_params_get_referer(const LinphoneCallParams *params); +void linphone_call_params_set_referer(LinphoneCallParams *params, LinphoneCall *referer); +bool_t linphone_call_params_get_update_call_when_ice_completed(const LinphoneCallParams *params); +void linphone_call_params_set_update_call_when_ice_completed(LinphoneCallParams *params, bool_t value); +void linphone_call_params_set_sent_vsize(LinphoneCallParams *params, MSVideoSize vsize); +void linphone_call_params_set_recv_vsize(LinphoneCallParams *params, MSVideoSize vsize); +void linphone_call_params_set_sent_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef); +void linphone_call_params_set_received_video_definition(LinphoneCallParams *params, LinphoneVideoDefinition *vdef); +void linphone_call_params_set_sent_fps(LinphoneCallParams *params, float value); +void linphone_call_params_set_received_fps(LinphoneCallParams *params, float value); +void linphone_call_params_set_used_audio_codec(LinphoneCallParams *params, OrtpPayloadType *codec); +void linphone_call_params_set_used_video_codec(LinphoneCallParams *params, OrtpPayloadType *codec); +void linphone_call_params_set_used_text_codec(LinphoneCallParams *params, OrtpPayloadType *codec); +bool_t linphone_call_params_get_no_user_consent(const LinphoneCallParams *params); +void linphone_call_params_set_no_user_consent(LinphoneCallParams *params, bool_t value); + +void linphone_auth_info_write_config(LinphoneConfig *config, LinphoneAuthInfo *obj, int pos); +LinphoneAuthInfo * linphone_auth_info_new_from_config_file(LpConfig *config, int pos); +void _linphone_core_uninit(LinphoneCore *lc); +void linphone_core_write_auth_info(LinphoneCore *lc, LinphoneAuthInfo *ai); +const LinphoneAuthInfo *_linphone_core_find_tls_auth_info(LinphoneCore *lc); +const LinphoneAuthInfo *_linphone_core_find_auth_info(LinphoneCore *lc, const char *realm, const char *username, const char *domain, bool_t ignore_realm); + +void linphone_core_update_proxy_register(LinphoneCore *lc); +const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc); + +int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphonePresenceModel *presence); +void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState rstate, const char *message); +void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig *obj); +void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc); +void _linphone_proxy_config_release(LinphoneProxyConfig *cfg); +void _linphone_proxy_config_unpublish(LinphoneProxyConfig *obj); +void linphone_proxy_config_notify_publish_state_changed(LinphoneProxyConfig *cfg, LinphonePublishState state); +LinphoneEvent *linphone_proxy_config_create_publish(LinphoneProxyConfig *cfg, const char *event, int expires); +/* + * returns service route as defined in as defined by rfc3608, might be a list instead of just one. + * Can be NULL + * */ +const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg); +const LinphoneAddress *_linphone_proxy_config_get_contact_without_params (const LinphoneProxyConfig *cfg); + +void linphone_friend_list_invalidate_subscriptions(LinphoneFriendList *list); +void linphone_friend_list_notify_presence_received(LinphoneFriendList *list, LinphoneEvent *lev, const LinphoneContent *body); +void linphone_friend_list_subscription_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state); +void _linphone_friend_list_release(LinphoneFriendList *list); +/*get rls either from list or core if any*/ +const LinphoneAddress * _linphone_friend_list_get_rls_address(const LinphoneFriendList *list); + +LINPHONE_PUBLIC void linphone_friend_invalidate_subscription(LinphoneFriend *lf); +void linphone_friend_close_subscriptions(LinphoneFriend *lf); +void _linphone_friend_release(LinphoneFriend *lf); +LINPHONE_PUBLIC void linphone_friend_update_subscribes(LinphoneFriend *fr, bool_t only_when_registered); +void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence); +void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc); +void linphone_friend_add_incoming_subscription(LinphoneFriend *lf, LinphonePrivate::SalOp *op); +void linphone_friend_remove_incoming_subscription(LinphoneFriend *lf, LinphonePrivate::SalOp *op); +const char * linphone_friend_phone_number_to_sip_uri(LinphoneFriend *lf, const char *phone_number); +const char * linphone_friend_sip_uri_to_phone_number(LinphoneFriend *lf, const char *uri); +void linphone_friend_clear_presence_models(LinphoneFriend *lf); +LinphoneFriend *linphone_friend_list_find_friend_by_inc_subscribe(const LinphoneFriendList *list, LinphonePrivate::SalOp *op); +LinphoneFriend *linphone_friend_list_find_friend_by_out_subscribe(const LinphoneFriendList *list, LinphonePrivate::SalOp *op); +LinphoneFriend *linphone_core_find_friend_by_out_subscribe(const LinphoneCore *lc, LinphonePrivate::SalOp *op); +LinphoneFriend *linphone_core_find_friend_by_inc_subscribe(const LinphoneCore *lc, LinphonePrivate::SalOp *op); +MSList *linphone_find_friend_by_address(MSList *fl, const LinphoneAddress *addr, LinphoneFriend **lf); +bool_t linphone_core_should_subscribe_friends_only_when_registered(const LinphoneCore *lc); +void linphone_core_update_friends_subscriptions(LinphoneCore *lc); +void _linphone_friend_list_update_subscriptions(LinphoneFriendList *list, LinphoneProxyConfig *cfg, bool_t only_when_registered); +void linphone_core_friends_storage_init(LinphoneCore *lc); +void linphone_core_friends_storage_close(LinphoneCore *lc); +void linphone_core_store_friend_in_db(LinphoneCore *lc, LinphoneFriend *lf); +void linphone_core_remove_friend_from_db(LinphoneCore *lc, LinphoneFriend *lf); +void linphone_core_store_friends_list_in_db(LinphoneCore *lc, LinphoneFriendList *list); +void linphone_core_remove_friends_list_from_db(LinphoneCore *lc, LinphoneFriendList *list); +LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_from_db(LinphoneCore *lc, LinphoneFriendList *list); +LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_lists_from_db(LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneFriendListStatus linphone_friend_list_import_friend(LinphoneFriendList *list, LinphoneFriend *lf, bool_t synchronize); + +int linphone_parse_host_port(const char *input, char *host, size_t hostlen, int *port); +int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen, int default_port); + +bool_t host_has_ipv6_network(void); +bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret); + +static MS2_INLINE void set_string(char **dest, const char *src, bool_t lowercase){ + if (*dest){ + ms_free(*dest); + *dest=NULL; + } + if (src) { + *dest=ms_strdup(src); + if (lowercase) { + char *cur = *dest; + for (; *cur; cur++) *cur = (char)tolower(*cur); + } + } +} + +void linphone_process_authentication(LinphoneCore* lc, LinphonePrivate::SalOp *op); +void linphone_authentication_ok(LinphoneCore *lc, LinphonePrivate::SalOp *op); +void linphone_subscription_new(LinphoneCore *lc, LinphonePrivate::SalSubscribeOp *op, const char *from); +void linphone_core_send_presence(LinphoneCore *lc, LinphonePresenceModel *presence); +void linphone_notify_parse_presence(const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result); +void linphone_notify_convert_presence_to_xml(LinphonePrivate::SalOp *op, SalPresenceModel *presence, const char *contact, char **content); +void linphone_notify_recv(LinphoneCore *lc, LinphonePrivate::SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model); +void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, LinphonePrivate::SalOp *op); +void linphone_core_soundcard_hint_check(LinphoneCore* lc); + + +void linphone_subscription_answered(LinphoneCore *lc, LinphonePrivate::SalOp *op); +void linphone_subscription_closed(LinphoneCore *lc, LinphonePrivate::SalOp *op); + +void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc); + +LINPHONE_PUBLIC int linphone_run_stun_tests(LinphoneCore *lc, int audioPort, int videoPort, int textPort, + char *audioCandidateAddr, int *audioCandidatePort, char *videoCandidateAddr, int *videoCandidatePort, char *textCandidateAddr, int *textCandidatePort); +void linphone_core_resolve_stun_server(LinphoneCore *lc); +LINPHONE_PUBLIC const struct addrinfo *linphone_core_get_stun_server_addrinfo(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_enable_forced_ice_relay(LinphoneCore *lc, bool_t enable); +LINPHONE_PUBLIC void linphone_core_enable_short_turn_refresh(LinphoneCore *lc, bool_t enable); +void linphone_call_update_ice_state_in_call_stats(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEvent *ev); +void linphone_call_stats_update(LinphoneCallStats *stats, MediaStream *stream); +LinphoneCallStats *_linphone_call_stats_new(void); +void _linphone_call_stats_uninit(LinphoneCallStats *stats); +void _linphone_call_stats_clone(LinphoneCallStats *dst, const LinphoneCallStats *src); +void _linphone_call_stats_set_ice_state (LinphoneCallStats *stats, LinphoneIceState state); +void _linphone_call_stats_set_type (LinphoneCallStats *stats, LinphoneStreamType type); +mblk_t *_linphone_call_stats_get_received_rtcp (const LinphoneCallStats *stats); +void _linphone_call_stats_set_received_rtcp (LinphoneCallStats *stats, mblk_t *m); +void _linphone_call_stats_set_sent_rtcp (LinphoneCallStats *stats, mblk_t *m); +int _linphone_call_stats_get_updated (const LinphoneCallStats *stats); +void _linphone_call_stats_set_updated (LinphoneCallStats *stats, int updated); +void _linphone_call_stats_set_rtp_stats (LinphoneCallStats *stats, const rtp_stats_t *rtpStats); +void _linphone_call_stats_set_download_bandwidth (LinphoneCallStats *stats, float bandwidth); +void _linphone_call_stats_set_upload_bandwidth (LinphoneCallStats *stats, float bandwidth); +void _linphone_call_stats_set_rtcp_download_bandwidth (LinphoneCallStats *stats, float bandwidth); +void _linphone_call_stats_set_rtcp_upload_bandwidth (LinphoneCallStats *stats, float bandwidth); +void _linphone_call_stats_set_ip_family_of_remote (LinphoneCallStats *stats, LinphoneAddressFamily family); +bool_t _linphone_call_stats_rtcp_received_via_mux (const LinphoneCallStats *stats); +void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall *call); +void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md, bool_t is_offer); +void linphone_call_clear_unused_ice_candidates(LinphoneCall *call, const SalMediaDescription *md); +bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md); + +void linphone_core_send_initial_subscribes(LinphoneCore *lc); +void linphone_core_write_friends_config(LinphoneCore* lc); +void linphone_friend_write_to_config_file(LinphoneConfig *config, LinphoneFriend *lf, int index); +LinphoneFriend * linphone_friend_new_from_config_file(struct _LinphoneCore *lc, int index); + +void linphone_proxy_config_update(LinphoneProxyConfig *cfg); +LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri); +const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to); +int linphone_core_get_local_ip_for(int type, const char *dest, char *result); +LINPHONE_PUBLIC void linphone_core_get_local_ip(LinphoneCore *lc, int af, const char *dest, char *result); + +LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore *lc, int index); +void linphone_proxy_config_write_to_config_file(LinphoneConfig* config,LinphoneProxyConfig *obj, int index); + +int linphone_core_message_received(LinphoneCore *lc, LinphonePrivate::SalOp *op, const SalMessage *msg); +void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, uint32_t character, LinphoneCall *call); + +void linphone_call_init_media_streams(LinphoneCall *call); +void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call); +void linphone_call_stop_media_streams(LinphoneCall *call); +void linphone_call_delete_upnp_session(LinphoneCall *call); +int _linphone_core_apply_transports(LinphoneCore *lc); + +void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose); +void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progresses); +void linphone_core_stop_waiting(LinphoneCore *lc); + +int linphone_call_proceed_with_invite_if_ready(LinphoneCall *call, LinphoneProxyConfig *dest_proxy); +int linphone_call_start_invite(LinphoneCall *call, const LinphoneAddress *destination/* = NULL if to be taken from the call log */); +/* + * param automatic_offering aims is to take into account previous answer for video in case of automatic re-invite. + * Purpose is to avoid to re-ask video previously declined */ +int linphone_call_start_update(LinphoneCall *call); +int linphone_call_start_accept_update(LinphoneCall *call, LinphoneCallState next_state, const char *state_info); +void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call); +bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md); +extern LinphonePrivate::Sal::Callbacks linphone_sal_callbacks; +LINPHONE_PUBLIC bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); +LINPHONE_PUBLIC bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc); +bool_t _linphone_core_is_conference_creation (const LinphoneCore *lc, const LinphoneAddress *addr); +LinphoneChatRoom *_linphone_core_create_server_group_chat_room (LinphoneCore *lc, LinphonePrivate::SalCallOp *op); + +void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description); + + +LINPHONE_PUBLIC LinphoneProxyConfigAddressComparisonResult linphone_proxy_config_address_equal(const LinphoneAddress *a, const LinphoneAddress *b); +LINPHONE_PUBLIC LinphoneProxyConfigAddressComparisonResult linphone_proxy_config_is_server_config_changed(const LinphoneProxyConfig* obj); +/** + * unregister without moving the register_enable flag + */ +void _linphone_proxy_config_unregister(LinphoneProxyConfig *obj); +void _linphone_proxy_config_release_ops(LinphoneProxyConfig *obj); + +/*chat*/ +LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, const char *uri, const char *subject); +LinphoneChatRoom *_linphone_server_group_chat_room_new (LinphoneCore *core, LinphonePrivate::SalCallOp *op); +void linphone_chat_room_release(LinphoneChatRoom *cr); +void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call); +LinphoneChatRoomCbs * linphone_chat_room_cbs_new (void); +/**/ + +LinphoneToneDescription * linphone_tone_description_new(LinphoneReason reason, LinphoneToneID id, const char *audiofile); +void linphone_tone_description_destroy(LinphoneToneDescription *obj); +LinphoneToneDescription *linphone_core_get_call_error_tone(const LinphoneCore *lc, LinphoneReason reason); +void linphone_core_play_call_error_tone(LinphoneCore *lc, LinphoneReason reason); +void _linphone_core_set_tone(LinphoneCore *lc, LinphoneReason reason, LinphoneToneID id, const char *audiofile); +LINPHONE_PUBLIC const char *linphone_core_get_tone_file(const LinphoneCore *lc, LinphoneToneID id); + +void linphone_task_list_init(LinphoneTaskList *t); +void linphone_task_list_add(LinphoneTaskList *t, LinphoneCoreIterateHook hook, void *hook_data); +void linphone_task_list_remove(LinphoneTaskList *t, LinphoneCoreIterateHook hook, void *hook_data); +void linphone_task_list_run(LinphoneTaskList *t); +void linphone_task_list_free(LinphoneTaskList *t); + +LinphoneCoreCbs * _linphone_core_cbs_new(void); +void _linphone_core_cbs_set_v_table(LinphoneCoreCbs *cbs, LinphoneCoreVTable *vtable, bool_t autorelease); + + +LinphoneTunnel *linphone_core_tunnel_new(LinphoneCore *lc); +void linphone_tunnel_configure(LinphoneTunnel *tunnel); +void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, OrtpLogFunc logHandler); + +int linphone_core_get_calls_nb(const LinphoneCore *lc); + +void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); +void linphone_call_update_biggest_desc(LinphoneCall *call, SalMediaDescription *md); +void linphone_call_make_local_media_description(LinphoneCall *call); +void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, LinphoneCall *call, LinphoneCallParams *params); + +bool_t linphone_core_is_payload_type_usable_for_bandwidth(const LinphoneCore *lc, const PayloadType *pt, int bandwidth_limit); + +#define linphone_core_ready(lc) ((lc)->state==LinphoneGlobalOn || (lc)->state==LinphoneGlobalShutdown) +void _linphone_core_configure_resolver(void); + +void linphone_core_initialize_supported_content_types(LinphoneCore *lc); + +LinphoneEcCalibratorStatus ec_calibrator_get_status(EcCalibrator *ecc); + +void ec_calibrator_destroy(EcCalibrator *ecc); + +void linphone_call_set_broken(LinphoneCall *call); +void linphone_call_repair_if_broken(LinphoneCall *call); +void linphone_core_repair_calls(LinphoneCore *lc); +int linphone_core_preempt_sound_resources(LinphoneCore *lc); +int _linphone_call_pause(LinphoneCall *call); + +/*conferencing subsystem*/ +void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted); +bool_t linphone_core_sound_resources_available(LinphoneCore *lc); +void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, LinphoneCall *newcall); +LINPHONE_PUBLIC unsigned int linphone_core_get_audio_features(LinphoneCore *lc); + +void _linphone_core_codec_config_write(LinphoneCore *lc); + +LINPHONE_PUBLIC bctbx_list_t * linphone_core_read_call_logs_from_config_file(LinphoneCore *lc); +void call_logs_write_to_config_file(LinphoneCore *lc); +void linphone_core_call_log_storage_init(LinphoneCore *lc); +void linphone_core_call_log_storage_close(LinphoneCore *lc); +void linphone_core_store_call_log(LinphoneCore *lc, LinphoneCallLog *log); +LINPHONE_PUBLIC const MSList *linphone_core_get_call_history(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_delete_call_history(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_delete_call_log(LinphoneCore *lc, LinphoneCallLog *log); +LINPHONE_PUBLIC int linphone_core_get_call_history_size(LinphoneCore *lc); + +int linphone_core_get_edge_bw(LinphoneCore *lc); +int linphone_core_get_edge_ptime(LinphoneCore *lc); + +LinphoneCore *_linphone_core_new_with_config(LinphoneCoreCbs *cbs, struct _LpConfig *config, void *userdata, void *system_context); + +int linphone_upnp_init(LinphoneCore *lc); +void linphone_upnp_destroy(LinphoneCore *lc); + +#ifdef SQLITE_STORAGE_ENABLED +int _linphone_sqlite3_open(const char *db_file, sqlite3 **db); +#endif + +void linphone_chat_message_set_time(LinphoneChatMessage* msg, time_t time); +void linphone_chat_message_set_incoming(LinphoneChatMessage *msg); +void linphone_chat_message_set_outgoing(LinphoneChatMessage *msg); +LinphoneChatMessageStateChangedCb linphone_chat_message_get_message_state_changed_cb(LinphoneChatMessage* msg); +void linphone_chat_message_set_message_state_changed_cb(LinphoneChatMessage* msg, LinphoneChatMessageStateChangedCb cb); +void linphone_chat_message_set_message_state_changed_cb_user_data(LinphoneChatMessage* msg, void *user_data); +void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChatMessage* msg); +void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessageState state); +void linphone_chat_message_set_message_id(LinphoneChatMessage *msg, char *id); +void linphone_chat_message_set_storage_id(LinphoneChatMessage *msg, unsigned int id); +SalCustomHeader * linphone_chat_message_get_sal_custom_headers(const LinphoneChatMessage *msg); +void linphone_chat_message_set_sal_custom_headers(LinphoneChatMessage *msg, SalCustomHeader *header); +belle_http_request_t * linphone_chat_message_get_http_request(const LinphoneChatMessage *msg); +void linphone_chat_message_set_http_request(LinphoneChatMessage *msg, belle_http_request_t *request); +void linphone_chat_message_set_file_transfer_information(LinphoneChatMessage *msg, LinphoneContent *content); +LinphoneChatMessageDir linphone_chat_message_get_direction(const LinphoneChatMessage *msg); +LinphonePrivate::SalOp * linphone_chat_message_get_sal_op(const LinphoneChatMessage *msg); +void linphone_chat_message_set_sal_op(LinphoneChatMessage *msg, LinphonePrivate::SalOp *op); +void linphone_chat_message_destroy(LinphoneChatMessage* msg); +void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state); +void linphone_chat_message_set_is_secured(LinphoneChatMessage *msg, bool_t secured); +void linphone_chat_message_send_delivery_notification(LinphoneChatMessage *cm, LinphoneReason reason); +void linphone_chat_message_send_display_notification(LinphoneChatMessage *cm); +void _linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg, bool_t unref); +int linphone_chat_room_upload_file(LinphoneChatMessage *msg); +LinphoneChatRoom *_linphone_core_create_chat_room_from_call(LinphoneCall *call); +void linphone_chat_room_remove_transient_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg); +void linphone_chat_message_deactivate(LinphoneChatMessage *msg); +void linphone_chat_message_release(LinphoneChatMessage *msg); +void linphone_chat_message_fetch_content_from_database(sqlite3 *db, LinphoneChatMessage *message, int content_id); + +void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID id); +bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc); +const char *linphone_core_create_uuid(LinphoneCore *lc); +void linphone_configure_op(LinphoneCore *lc, LinphonePrivate::SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact); +void linphone_configure_op_with_proxy(LinphoneCore *lc, LinphonePrivate::SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact, LinphoneProxyConfig *proxy); +void linphone_call_create_op(LinphoneCall *call); +LinphoneContent * linphone_content_new(void); +LinphoneContent * linphone_content_copy(const LinphoneContent *ref); +SalBodyHandler *sal_body_handler_from_content(const LinphoneContent *content); +SalReason linphone_reason_to_sal(LinphoneReason reason); +LinphoneReason linphone_reason_from_sal(SalReason reason); +void linphone_error_info_to_sal(const LinphoneErrorInfo* ei, SalErrorInfo* sei); +LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, int expires); +LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, LinphonePrivate::SalEventOp *op, LinphoneSubscriptionDir dir, const char *name); +void linphone_event_unpublish(LinphoneEvent *lev); +/** + * Useful for out of dialog notify + * */ +LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, LinphonePrivate::SalEventOp *op, LinphoneSubscriptionDir dir, const char *name); +void linphone_event_set_internal(LinphoneEvent *lev, bool_t internal); +bool_t linphone_event_is_internal(LinphoneEvent *lev); +void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state); +void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState state); +LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss); +LinphoneContent *linphone_content_from_sal_body_handler(SalBodyHandler *ref); +void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc); +void linphone_core_register_offer_answer_providers(LinphoneCore *lc); + +bool_t linphone_nat_policy_stun_server_activated(LinphoneNatPolicy *policy); +void linphone_nat_policy_save_to_config(const LinphoneNatPolicy *policy); + +void linphone_core_create_im_notif_policy(LinphoneCore *lc); + + +/***************************************************************************** + * REMOTE PROVISIONING FUNCTIONS * + ****************************************************************************/ + +void linphone_configuring_terminated(LinphoneCore *lc, LinphoneConfiguringState state, const char *message); +int linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri); +LINPHONE_PUBLIC int linphone_remote_provisioning_load_file( LinphoneCore* lc, const char* file_path); + + +/***************************************************************************** + * Player interface * + ****************************************************************************/ + +LinphonePlayerCbs *linphone_player_cbs_new(void); +LinphonePlayer * linphone_player_new(void); +void _linphone_player_destroy(LinphonePlayer *player); + + +/***************************************************************************** + * XML UTILITY FUNCTIONS * + ****************************************************************************/ + +xmlparsing_context_t * linphone_xmlparsing_context_new(void); +void linphone_xmlparsing_context_destroy(xmlparsing_context_t *ctx); +void linphone_xmlparsing_genericxml_error(void *ctx, const char *fmt, ...); +int linphone_create_xml_xpath_context(xmlparsing_context_t *xml_ctx); +void linphone_xml_xpath_context_set_node(xmlparsing_context_t *xml_ctx, xmlNodePtr node); +char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression); +char * linphone_get_xml_attribute_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression, const char *attribute_name); +void linphone_free_xml_text_content(char *text); +xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression); +void linphone_xml_xpath_context_init_carddav_ns(xmlparsing_context_t *xml_ctx); + +/***************************************************************************** + * OTHER UTILITY FUNCTIONS * + ****************************************************************************/ + +char * linphone_timestamp_to_rfc3339_string(time_t timestamp); + +void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const LinphonePrivate::SalOp *op); + +void payload_type_set_enable(OrtpPayloadType *pt, bool_t value); +bool_t payload_type_enabled(const OrtpPayloadType *pt); + +LinphonePayloadType *linphone_payload_type_new(LinphoneCore *lc, OrtpPayloadType *ortp_pt); +bool_t _linphone_core_check_payload_type_usability(const LinphoneCore *lc, const OrtpPayloadType *pt); +OrtpPayloadType *linphone_payload_type_get_ortp_pt(const LinphonePayloadType *pt); + + +const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc); +MsZrtpCryptoTypesCount linphone_core_get_zrtp_key_agreement_suites(LinphoneCore *lc, MSZrtpKeyAgreement keyAgreements[MS_MAX_ZRTP_CRYPTO_TYPES]); +MsZrtpCryptoTypesCount linphone_core_get_zrtp_cipher_suites(LinphoneCore *lc, MSZrtpCipher ciphers[MS_MAX_ZRTP_CRYPTO_TYPES]); +MsZrtpCryptoTypesCount linphone_core_get_zrtp_hash_suites(LinphoneCore *lc, MSZrtpHash hashes[MS_MAX_ZRTP_CRYPTO_TYPES]); +MsZrtpCryptoTypesCount linphone_core_get_zrtp_auth_suites(LinphoneCore *lc, MSZrtpAuthTag authTags[MS_MAX_ZRTP_CRYPTO_TYPES]); +MsZrtpCryptoTypesCount linphone_core_get_zrtp_sas_suites(LinphoneCore *lc, MSZrtpSasType sasTypes[MS_MAX_ZRTP_CRYPTO_TYPES]); + +LinphoneImEncryptionEngineCbs * linphone_im_encryption_engine_cbs_new(void); + +LinphoneRange *linphone_range_new(void); + +LINPHONE_PUBLIC LinphoneTransports *linphone_transports_new(void); + +LINPHONE_PUBLIC LinphoneVideoActivationPolicy *linphone_video_activation_policy_new(void); + +void linphone_core_notify_global_state_changed(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); +void linphone_core_notify_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message); +void linphone_core_notify_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token); +void linphone_core_notify_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message); +void linphone_core_notify_new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url); +void linphone_core_notify_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain); +void linphone_core_notify_authentication_requested(LinphoneCore *lc, LinphoneAuthInfo *auth_info, LinphoneAuthMethod method); +void linphone_core_notify_call_log_updated(LinphoneCore *lc, LinphoneCallLog *newcl); +void linphone_core_notify_text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message); +void linphone_core_notify_message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message); +void linphone_core_notify_message_received_unable_decrypt(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message); +void linphone_core_notify_file_transfer_recv(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size); +void linphone_core_notify_file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size); +void linphone_core_notify_file_transfer_progress_indication(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total); +void linphone_core_notify_is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room); +void linphone_core_notify_dtmf_received(LinphoneCore* lc, LinphoneCall *call, int dtmf); +/* + * return true if at least a registered vtable has a cb for dtmf received*/ +bool_t linphone_core_dtmf_received_has_listener(const LinphoneCore* lc); +void linphone_core_notify_refer_received(LinphoneCore *lc, const char *refer_to); +void linphone_core_notify_buddy_info_updated(LinphoneCore *lc, LinphoneFriend *lf); +void linphone_core_notify_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state); +void linphone_core_notify_call_stats_updated(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats); +void linphone_core_notify_info_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); +void linphone_core_notify_configuring_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message); +void linphone_core_notify_network_reachable(LinphoneCore *lc, bool_t reachable); + +void linphone_core_notify_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *notified_event, const LinphoneContent *body); +void linphone_core_notify_subscription_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state); +void linphone_core_notify_publish_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphonePublishState state); +void linphone_core_notify_log_collection_upload_state_changed(LinphoneCore *lc, LinphoneCoreLogCollectionUploadState state, const char *info); +void linphone_core_notify_log_collection_upload_progress_indication(LinphoneCore *lc, size_t offset, size_t total); +void linphone_core_notify_friend_list_created(LinphoneCore *lc, LinphoneFriendList *list); +void linphone_core_notify_friend_list_removed(LinphoneCore *lc, LinphoneFriendList *list); +void linphone_core_notify_call_created(LinphoneCore *lc, LinphoneCall *call); +void linphone_core_notify_version_update_check_result_received(LinphoneCore *lc, LinphoneVersionUpdateCheckResult result, const char *version, const char *url); +void linphone_core_notify_chat_room_instantiated (LinphoneCore *lc, LinphoneChatRoom *cr); + +void linphone_core_notify_ec_calibration_result(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms); +void linphone_core_notify_ec_calibration_audio_init(LinphoneCore *lc); +void linphone_core_notify_ec_calibration_audio_uninit(LinphoneCore *lc); + +void set_playback_gain_db(AudioStream *st, float gain); + +LinphoneMediaDirection media_direction_from_sal_stream_dir(SalStreamDir dir); +SalStreamDir sal_dir_from_call_params_dir(LinphoneMediaDirection cpdir); + +/***************************************************************************** + * LINPHONE CONTENT PRIVATE ACCESSORS * + ****************************************************************************/ + +/** + * Get the address of the crypto context associated with a RCS file transfer message if encrypted + * @param[in] content LinphoneContent object. + * @return The address of the pointer to the crypto context. Crypto context is managed(alloc/free) + * by the encryption/decryption functions, so we give the address to store/retrieve the pointer + */ +void ** linphone_content_get_cryptoContext_address(LinphoneContent *content); + +void v_table_reference_destroy(VTableReference *ref); + +LINPHONE_PUBLIC void _linphone_core_add_callbacks(LinphoneCore *lc, LinphoneCoreCbs *vtable, bool_t internal); + +MSWebCam *get_nowebcam_device(MSFactory *f); + +LinphoneLimeState linphone_core_lime_for_file_sharing_enabled(const LinphoneCore *lc); + +int linphone_core_get_default_proxy_config_index(LinphoneCore *lc); + +char *linphone_presence_model_to_xml(LinphonePresenceModel *model) ; + +bool_t linphone_call_state_is_early(LinphoneCallState state); + +void linphone_core_report_call_log(LinphoneCore *lc, LinphoneCallLog *call_log); +void linphone_core_report_early_failed_call(LinphoneCore *lc, LinphoneCallDir dir, LinphoneAddress *from, LinphoneAddress *to, LinphoneErrorInfo *ei); + +LinphoneVideoDefinition * linphone_video_definition_new(unsigned int width, unsigned int height, const char *name); + +LinphoneVideoDefinition * linphone_factory_find_supported_video_definition(const LinphoneFactory *factory, unsigned int width, unsigned int height); +LinphoneVideoDefinition * linphone_factory_find_supported_video_definition_by_name(const LinphoneFactory *factory, const char *name); + +const char* _linphone_config_load_from_xml_string(LpConfig *lpc, const char *buffer); +LinphoneNatPolicy * linphone_config_create_nat_policy_from_section(const LinphoneConfig *config, const char* section); + +SalCustomHeader *linphone_info_message_get_headers (const LinphoneInfoMessage *im); +void linphone_info_message_set_headers (LinphoneInfoMessage *im, const SalCustomHeader *headers); + +#ifdef __cplusplus +} +#endif + +#endif /* _PRIVATE_FUNCTIONS_H_ */ diff --git a/coreapi/private_structs.h b/coreapi/private_structs.h new file mode 100644 index 000000000..40ca4ac56 --- /dev/null +++ b/coreapi/private_structs.h @@ -0,0 +1,834 @@ +/* + * private_structs.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _PRIVATE_STRUCTS_H_ +#define _PRIVATE_STRUCTS_H_ + +#include +#include +#include +#include +#include + +#include "carddav.h" +#include "sal/register-op.h" + +struct _LinphoneQualityReporting{ + reporting_session_report_t * reports[3]; /**Store information on audio and video media streams (RFC 6035) */ + bool_t was_video_running; /*Keep video state since last check in order to detect its (de)activation*/ + LinphoneQualityReportingReportSendCb on_report_sent; +}; + +struct _LinphoneCallLog{ + belle_sip_object_t base; + void *user_data; + struct _LinphoneCore *lc; + LinphoneCallDir dir; /**< The direction of the call*/ + LinphoneCallStatus status; /**< The status of the call*/ + LinphoneAddress *from; /**= 6) || __GNUC__ > 4) +#pragma GCC diagnostic push +#endif +#ifdef _MSC_VER +#pragma warning(disable : 4996) +#else +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + LinphoneEcCalibrationCallback cb; + void *cb_data; + LinphoneEcCalibrationAudioInit audio_init_cb; + LinphoneEcCalibrationAudioUninit audio_uninit_cb; +#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) +#pragma GCC diagnostic pop +#endif + int64_t acc; + int delay; + unsigned int rate; + LinphoneEcCalibratorStatus status; + bool_t freq1,freq2,freq3; + bool_t play_cool_tones; +}; + +struct _EchoTester { + MSFactory *factory; + MSFilter *in,*out; + MSSndCard *capture_card; + MSSndCard *playback_card; + MSTicker *ticker; + unsigned int rate; +}; + +struct _LinphoneContent { + belle_sip_object_t base; + void *user_data; + SalBodyHandler *body_handler; + char *name; /**< used by RCS File transfer messages to store the original filename of the file to be downloaded from server */ + char *key; /**< used by RCS File transfer messages to store the key to encrypt file if needed */ + size_t keyLength; /**< Length of key in bytes */ + void *cryptoContext; /**< crypto context used to encrypt file for RCS file transfer */ + bool_t owned_fields; +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneContent); + +struct _LinphoneBuffer { + belle_sip_object_t base; + void *user_data; + uint8_t *content; /**< A pointer to the buffer content */ + size_t size; /**< The size of the buffer content */ +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneBuffer); + +struct _LinphoneNatPolicy { + belle_sip_object_t base; + void *user_data; + LinphoneCore *lc; + belle_sip_resolver_context_t *stun_resolver_context; + struct addrinfo *stun_addrinfo; + char *stun_server; + char *stun_server_username; + char *ref; + bool_t stun_enabled; + bool_t turn_enabled; + bool_t ice_enabled; + bool_t upnp_enabled; +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneNatPolicy); + +struct _LinphoneImNotifPolicy { + belle_sip_object_t base; + void *user_data; + LinphoneCore *lc; + bool_t send_is_composing; + bool_t recv_is_composing; + bool_t send_imdn_delivered; + bool_t recv_imdn_delivered; + bool_t send_imdn_displayed; + bool_t recv_imdn_displayed; +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneImNotifPolicy); + + +/***************************************************************************** + * XML-RPC interface * + ****************************************************************************/ + +struct _LinphoneXmlRpcArg { + LinphoneXmlRpcArgType type; + union { + int i; + char *s; + } data; +}; + +struct _LinphoneXmlRpcRequestCbs { + belle_sip_object_t base; + void *user_data; + LinphoneXmlRpcRequestCbsResponseCb response; +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneXmlRpcRequestCbs); + +struct _LinphoneXmlRpcRequest { + belle_sip_object_t base; + void *user_data; + LinphoneXmlRpcRequestCbs *callbacks; + belle_sip_list_t *arg_list; + char *content; /**< The string representation of the XML-RPC request */ + char *method; + LinphoneXmlRpcStatus status; + struct _LinphoneXmlRpcArg response; +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneXmlRpcRequest); + +struct _LinphoneXmlRpcSession { + belle_sip_object_t base; + void *user_data; + LinphoneCore *core; + char *url; + bool_t released; +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneXmlRpcSession); + + +/***************************************************************************** + * CardDAV interface * + ****************************************************************************/ + +struct _LinphoneCardDavContext { + LinphoneFriendList *friend_list; + int ctag; + void *user_data; + LinphoneCardDavContactCreatedCb contact_created_cb; + LinphoneCardDavContactUpdatedCb contact_updated_cb; + LinphoneCardDavContactRemovedCb contact_removed_cb; + LinphoneCardDavSynchronizationDoneCb sync_done_cb; + LinphoneAuthInfo *auth_info; +}; + +struct _LinphoneCardDavQuery { + LinphoneCardDavContext *context; + char *url; + const char *method; + char *body; + const char *depth; + const char *ifmatch; + belle_http_request_listener_t *http_request_listener; + void *user_data; + LinphoneCardDavQueryType type; +}; + +struct _LinphoneCardDavResponse { + char *etag; + char *url; + char *vcard; +}; + + +/***************************************************************************** + * Player interface * + ****************************************************************************/ + +struct _LinphonePlayerCbs { + belle_sip_object_t base; + void *user_data; + LinphonePlayerCbsEofReachedCb eof; +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphonePlayerCbs); + +struct _LinphonePlayer{ + belle_sip_object_t base; + void *user_data; + int (*open)(LinphonePlayer* player, const char *filename); + int (*start)(LinphonePlayer* player); + int (*pause)(LinphonePlayer* player); + int (*seek)(LinphonePlayer* player, int time_ms); + MSPlayerState (*get_state)(LinphonePlayer* player); + int (*get_duration)(LinphonePlayer *player); + int (*get_position)(LinphonePlayer *player); + void (*close)(LinphonePlayer* player); + void (*destroy)(LinphonePlayer *player); + void *impl; + LinphonePlayerCbs *callbacks; +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphonePlayer); + + +/***************************************************************************** + * XML UTILITY FUNCTIONS * + ****************************************************************************/ + +#define XMLPARSING_BUFFER_LEN 2048 +#define MAX_XPATH_LENGTH 256 + +struct _xmlparsing_context { + xmlDoc *doc; + xmlXPathContextPtr xpath_ctx; + char errorBuffer[XMLPARSING_BUFFER_LEN]; + char warningBuffer[XMLPARSING_BUFFER_LEN]; +}; + + +/***************************************************************************** + * OTHER UTILITY FUNCTIONS * + ****************************************************************************/ + +struct _LinphoneImEncryptionEngineCbs { + belle_sip_object_t base; + void *user_data; + LinphoneImEncryptionEngineCbsIncomingMessageCb process_incoming_message; + LinphoneImEncryptionEngineCbsOutgoingMessageCb process_outgoing_message; + LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer; + LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb generate_file_transfer_key; + LinphoneImEncryptionEngineCbsDownloadingFileCb process_downlading_file; + LinphoneImEncryptionEngineCbsUploadingFileCb process_uploading_file; +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneImEncryptionEngineCbs); + +struct _LinphoneImEncryptionEngine { + belle_sip_object_t base; + void *user_data; + LinphoneCore *lc; + LinphoneImEncryptionEngineCbs *callbacks; +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneImEncryptionEngine); + +struct _LinphoneRange { + belle_sip_object_t base; + void *user_data; + int min; + int max; +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneRange); + +struct _LinphoneTransports { + belle_sip_object_t base; + void *user_data; + int udp_port; /**< SIP/UDP port */ + int tcp_port; /**< SIP/TCP port */ + int dtls_port; /**< SIP/DTLS port */ + int tls_port; /**< SIP/TLS port */ +}; + +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneTransports); + +struct _LinphoneVideoActivationPolicy { + belle_sip_object_t base; + void *user_data; + bool_t automatically_initiate; /**name) bctbx_free(vdef->name); } diff --git a/coreapi/xmlrpc.c b/coreapi/xmlrpc.c index 368e6c622..459494a9a 100644 --- a/coreapi/xmlrpc.c +++ b/coreapi/xmlrpc.c @@ -25,6 +25,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "c-wrapper/c-wrapper.h" +// TODO: From coreapi. Remove me later. +#include "private.h" + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneXmlRpcRequestCbs); BELLE_SIP_INSTANCIATE_VPTR(LinphoneXmlRpcRequestCbs, belle_sip_object_t, diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 443273c1e..a901d93a3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -159,6 +159,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES c-wrapper/api/c-chat-message.cpp c-wrapper/api/c-chat-room-cbs.cpp c-wrapper/api/c-chat-room.cpp + c-wrapper/api/c-core.cpp c-wrapper/api/c-dial-plan.cpp c-wrapper/api/c-event-log.cpp c-wrapper/api/c-participant.cpp @@ -202,6 +203,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES content/file-content.cpp content/file-transfer-content.cpp core/core-accessor.cpp + core/core-call.cpp core/core-chat-room.cpp core/core.cpp core/paths/paths.cpp diff --git a/src/address/address.cpp b/src/address/address.cpp index 228bf53ef..eaaf13545 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -22,6 +22,7 @@ #include "address-p.h" #include "address/identity-address.h" #include "c-wrapper/c-wrapper.h" +#include "c-wrapper/internal/c-sal.h" #include "logger/logger.h" // ============================================================================= diff --git a/src/address/identity-address.cpp b/src/address/identity-address.cpp index 2c8800896..86dcdee93 100644 --- a/src/address/identity-address.cpp +++ b/src/address/identity-address.cpp @@ -17,6 +17,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "linphone/utils/utils.h" + +#include "address.h" +#include "identity-address-p.h" #include "c-wrapper/c-wrapper.h" #include "identity-address-p.h" #include "logger/logger.h" diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index 4aa6e5006..062f5ee2c 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -18,9 +18,12 @@ */ #include "c-wrapper/c-wrapper.h" +#include "core/core.h" #include "conference/params/call-session-params-p.h" #include "conference/params/media-session-params-p.h" +#include "linphone/call_params.h" + // ============================================================================= L_DECLARE_C_CLONABLE_OBJECT_IMPL(CallParams) @@ -502,7 +505,7 @@ LinphoneCallParams *linphone_call_params_new (LinphoneCore *core) { LinphoneCallParams *params = _linphone_CallParams_init(); auto mediaSessionParams = new LinphonePrivate::MediaSessionParams(); L_SET_CPP_PTR_FROM_C_OBJECT(params, mediaSessionParams); - L_GET_CPP_PTR_FROM_C_OBJECT(params)->initDefault(core->cppCore); + L_GET_CPP_PTR_FROM_C_OBJECT(params)->initDefault(L_GET_CPP_PTR_FROM_C_OBJECT(core)); delete mediaSessionParams; return params; } diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 6d890e89d..274f7e97f 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -1140,11 +1140,11 @@ LinphoneCall *linphone_call_new_outgoing (LinphoneCore *lc, const LinphoneAddres shared_ptr call; string confType = lp_config_get_string(linphone_core_get_config(lc), "misc", "conference_type", "local"); if (confType == "remote") { - call = make_shared(lc->cppCore, LinphoneCallOutgoing, + call = make_shared(L_GET_CPP_PTR_FROM_C_OBJECT(lc), LinphoneCallOutgoing, *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), cfg, nullptr, L_GET_CPP_PTR_FROM_C_OBJECT(params)); } else { - call = make_shared(lc->cppCore, LinphoneCallOutgoing, + call = make_shared(L_GET_CPP_PTR_FROM_C_OBJECT(lc), LinphoneCallOutgoing, *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), cfg, nullptr, L_GET_CPP_PTR_FROM_C_OBJECT(params)); } @@ -1161,11 +1161,11 @@ LinphoneCall *linphone_call_new_incoming (LinphoneCore *lc, const LinphoneAddres shared_ptr call; string confType = lp_config_get_string(linphone_core_get_config(lc), "misc", "conference_type", "local"); if (confType == "remote") { - call = make_shared(lc->cppCore, LinphoneCallIncoming, + call = make_shared(L_GET_CPP_PTR_FROM_C_OBJECT(lc), LinphoneCallIncoming, *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), nullptr, op, nullptr); } else { - call = make_shared(lc->cppCore, LinphoneCallIncoming, + call = make_shared(L_GET_CPP_PTR_FROM_C_OBJECT(lc), LinphoneCallIncoming, *L_GET_CPP_PTR_FROM_C_OBJECT(from), *L_GET_CPP_PTR_FROM_C_OBJECT(to), nullptr, op, nullptr); } diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 093ec5750..ecae6ba28 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -379,7 +379,7 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, cons LinphonePrivate::IdentityAddress me(from); LinphoneChatRoom *cr = L_INIT(ChatRoom); L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared( - core->cppCore, L_C_TO_STRING(uri), me, L_C_TO_STRING(subject)) + L_GET_CPP_PTR_FROM_C_OBJECT(core), L_C_TO_STRING(uri), me, L_C_TO_STRING(subject)) ); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); return cr; @@ -388,7 +388,7 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, cons LinphoneChatRoom *_linphone_server_group_chat_room_new (LinphoneCore *core, LinphonePrivate::SalCallOp *op) { LinphoneChatRoom *cr = L_INIT(ChatRoom); L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared( - core->cppCore, + L_GET_CPP_PTR_FROM_C_OBJECT(core), op )); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); diff --git a/src/c-wrapper/api/c-core.cpp b/src/c-wrapper/api/c-core.cpp new file mode 100644 index 000000000..54e42d7c2 --- /dev/null +++ b/src/c-wrapper/api/c-core.cpp @@ -0,0 +1,47 @@ +/* + * c-core.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "linphone/wrapper_utils.h" + +#include "c-wrapper/c-wrapper.h" +#include "core/core.h" + +#include "private_structs.h" + +// ============================================================================= + +using namespace std; + +static void _linphone_core_constructor (LinphoneCore *lc); +static void _linphone_core_destructor (LinphoneCore *lc); + +L_DECLARE_C_OBJECT_IMPL_WITH_XTORS( + Core, + _linphone_core_constructor, _linphone_core_destructor, + LINPHONE_CORE_STRUCT_FIELDS +) + +static void _linphone_core_constructor (LinphoneCore *lc) { +} + +static void _linphone_core_destructor (LinphoneCore *lc) { + if (lc->callsCache) + bctbx_list_free(lc->callsCache); + _linphone_core_uninit(lc); +} diff --git a/src/c-wrapper/api/c-participant.cpp b/src/c-wrapper/api/c-participant.cpp index af6fc1815..f09603300 100644 --- a/src/c-wrapper/api/c-participant.cpp +++ b/src/c-wrapper/api/c-participant.cpp @@ -19,6 +19,7 @@ #include "linphone/api/c-participant.h" +#include "address/address.h" #include "c-wrapper/c-wrapper.h" #include "conference/participant.h" diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index 41df151db..86045002e 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -25,7 +25,7 @@ #include "internal/c-tools.h" // TODO: From coreapi. Remove me later. -#include "private.h" +#include "private_functions.h" // ============================================================================= // Declare exported C types. @@ -36,12 +36,15 @@ F(Call, Call) \ F(ChatMessage, ChatMessage) \ F(ChatRoom, ChatRoom) \ + F(Core, Core) \ F(DialPlan, DialPlan) \ F(EventLog, EventLog) \ F(MediaSessionParams, CallParams) \ F(Participant, Participant) #define L_REGISTER_SUBTYPES(F) \ + F(Call, LocalConferenceCall) \ + F(Call, RemoteConferenceCall) \ F(ChatRoom, BasicChatRoom) \ F(ChatRoom, ClientGroupChatRoom) \ F(ChatRoom, RealTimeTextChatRoom) \ @@ -78,7 +81,6 @@ BELLE_SIP_TYPE_ID(LinphoneConfig), BELLE_SIP_TYPE_ID(LinphoneContactProvider), BELLE_SIP_TYPE_ID(LinphoneContactSearch), BELLE_SIP_TYPE_ID(LinphoneContent), -BELLE_SIP_TYPE_ID(LinphoneCore), BELLE_SIP_TYPE_ID(LinphoneCoreCbs), BELLE_SIP_TYPE_ID(LinphoneErrorInfo), BELLE_SIP_TYPE_ID(LinphoneEvent), diff --git a/src/call/call-p.h b/src/call/call-p.h index c2f5ec9a5..73f985ee2 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -50,7 +50,7 @@ public: LinphoneProxyConfig *getDestProxy () const; IceSession *getIceSession () const; MediaStream *getMediaStream (LinphoneStreamType type) const; - SalCallOp *getOp () const; + SalCallOp *getOp () const; void setAudioMuted (bool value); void createPlayer () const; diff --git a/src/call/call.cpp b/src/call/call.cpp index 7f82b6d01..10367dae7 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -21,6 +21,7 @@ #include "call-p.h" #include "conference/session/call-session-p.h" #include "conference/session/media-session-p.h" +#include "core/core-p.h" #include "logger/logger.h" // ============================================================================= @@ -101,28 +102,25 @@ void CallPrivate::onCallSetReleased () { void CallPrivate::onCallSetTerminated () { L_Q(); - LinphoneCall *lcall = L_GET_C_BACK_PTR(q); LinphoneCore *core = q->getCore()->getCCore(); - if (lcall) { - if (lcall == core->current_call) { - lInfo() << "Resetting the current call"; - core->current_call = nullptr; - } - if (linphone_core_del_call(core, lcall) != 0) - lError() << "Could not remove the call from the list!!!"; - #if 0 - if (core->conf_ctx) - linphone_conference_on_call_terminating(core->conf_ctx, lcall); - if (lcall->ringing_beep) { - linphone_core_stop_dtmf(core); - lcall->ringing_beep = false; - } - if (lcall->chat_room) - linphone_chat_room_set_call(lcall->chat_room, nullptr); - #endif // if 0 - if (!core->calls) - ms_bandwidth_controller_reset_state(core->bw_controller); + if (q->getSharedFromThis() == q->getCore()->getCurrentCall()) { + lInfo() << "Resetting the current call"; + q->getCore()->getPrivate()->setCurrentCall(nullptr); } + if (q->getCore()->getPrivate()->removeCall(q->getSharedFromThis()) != 0) + lError() << "Could not remove the call from the list!!!"; +#if 0 + if (core->conf_ctx) + linphone_conference_on_call_terminating(core->conf_ctx, lcall); + if (lcall->ringing_beep) { + linphone_core_stop_dtmf(core); + lcall->ringing_beep = false; + } + if (lcall->chat_room) + linphone_chat_room_set_call(lcall->chat_room, nullptr); +#endif // if 0 + if (!q->getCore()->getPrivate()->hasCalls()) + ms_bandwidth_controller_reset_state(core->bw_controller); } void CallPrivate::onCallStateChanged (LinphoneCallState state, const string &message) { @@ -161,7 +159,7 @@ void CallPrivate::onIncomingCallStarted () { void CallPrivate::onIncomingCallToBeAdded () { L_Q(); /* The call is acceptable so we can now add it to our list */ - linphone_core_add_call(q->getCore()->getCCore(), L_GET_C_BACK_PTR(q)); + q->getCore()->getPrivate()->addCall(q->getSharedFromThis()); } void CallPrivate::onInfoReceived (const LinphoneInfoMessage *im) { @@ -181,12 +179,12 @@ void CallPrivate::onStatsUpdated (const LinphoneCallStats *stats) { void CallPrivate::onResetCurrentCall () { L_Q(); - q->getCore()->getCCore()->current_call = nullptr; + q->getCore()->getPrivate()->setCurrentCall(nullptr); } void CallPrivate::onSetCurrentCall () { L_Q(); - q->getCore()->getCCore()->current_call = L_GET_C_BACK_PTR(q); + q->getCore()->getPrivate()->setCurrentCall(q->getSharedFromThis()); } void CallPrivate::onFirstVideoFrameDecoded () { diff --git a/src/call/call.h b/src/call/call.h index 980d46d20..755cb29cb 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -35,9 +35,12 @@ class MediaSessionPrivate; class Call : public Object, public CoreAccessor { friend class CallSessionPrivate; + friend class CorePrivate; friend class MediaSessionPrivate; public: + L_OVERRIDE_SHARED_FROM_THIS(Call); + LinphoneStatus accept (const MediaSessionParams *msp = nullptr); LinphoneStatus acceptEarlyMedia (const MediaSessionParams *msp = nullptr); LinphoneStatus acceptUpdate (const MediaSessionParams *msp); diff --git a/src/chat/modifier/encryption-chat-message-modifier.cpp b/src/chat/modifier/encryption-chat-message-modifier.cpp index cd9193490..75d755f19 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.cpp +++ b/src/chat/modifier/encryption-chat-message-modifier.cpp @@ -38,7 +38,7 @@ ChatMessageModifier::Result EncryptionChatMessageModifier::encode ( int &errorCode ) { shared_ptr chatRoom = message->getChatRoom(); - LinphoneImEncryptionEngine *imee = chatRoom->getCore()->getCCore()->im_encryption_engine; + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(chatRoom->getCore()->getCCore()); if (!imee) return ChatMessageModifier::Result::Skipped; @@ -71,7 +71,7 @@ ChatMessageModifier::Result EncryptionChatMessageModifier::decode ( int &errorCode ) { shared_ptr chatRoom = message->getChatRoom(); - LinphoneImEncryptionEngine *imee = chatRoom->getCore()->getCCore()->im_encryption_engine; + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(chatRoom->getCore()->getCCore()); if (!imee) return ChatMessageModifier::Result::Skipped; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 6cdbb1561..2257b88b6 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -3210,7 +3210,7 @@ void MediaSessionPrivate::updateStreams (SalMediaDescription *newMd, LinphoneCal if (getParams()->earlyMediaSendingEnabled() && (state == LinphoneCallOutgoingEarlyMedia)) prepareEarlyMediaForking(); startStreams(targetState); - if ((state == LinphoneCallPausing) && pausedByApp && (bctbx_list_size(q->getCore()->getCCore()->calls) == 1)) + if ((state == LinphoneCallPausing) && pausedByApp && (q->getCore()->getCallsNb() == 1)) linphone_core_play_named_tone(q->getCore()->getCCore(), LinphoneToneCallOnHold); updateFrozenPayloads(newMd); diff --git a/src/core/core-call.cpp b/src/core/core-call.cpp new file mode 100644 index 000000000..918faf9ca --- /dev/null +++ b/src/core/core-call.cpp @@ -0,0 +1,192 @@ +/* + * core-call.cpp + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include "core-p.h" +#include "call/call-p.h" +#include "logger/logger.h" + +// TODO: Remove me later. +#include "c-wrapper/c-wrapper.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +int CorePrivate::addCall (const shared_ptr &call) { + L_Q(); + L_ASSERT(call); + if (!canWeAddCall()) + return -1; + if (!hasCalls()) + notifySoundcardUsage(true); + calls.push_back(call); + linphone_core_notify_call_created(q->getCCore(), L_GET_C_BACK_PTR(call)); + return 0; +} + +bool CorePrivate::isAlreadyInCallWithAddress (const Address &addr) const { + for (const auto &call : calls) { + if (call->getRemoteAddress().weakEqual(addr)) + return true; + } + return false; +} + +void CorePrivate::iterateCalls (time_t currentRealTime, bool oneSecondElapsed) const { + for (const auto &call : calls) { + call->getPrivate()->iterate(currentRealTime, oneSecondElapsed); + } +} + +bool CorePrivate::canWeAddCall () const { + L_Q(); + if (q->getCallsNb() < static_cast(q->getCCore()->max_calls)) + return true; + lInfo() << "Maximum amount of simultaneous calls reached!"; + return false; +} + +void CorePrivate::notifySoundcardUsage (bool used) { + L_Q(); + MSSndCard *card = q->getCCore()->sound_conf.capt_sndcard; + if (card && (ms_snd_card_get_capabilities(card) & MS_SND_CARD_CAP_IS_SLOW)) + ms_snd_card_set_usage_hint(card, used); +} + +int CorePrivate::removeCall (const shared_ptr &call) { + L_ASSERT(call); + auto iter = find(calls.begin(), calls.end(), call); + if (iter == calls.end()) { + lWarning() << "Could not find the call to remove"; + return -1; + } + calls.erase(iter); + return 0; +} + +void CorePrivate::unsetVideoWindowId (bool preview, void *id) { +#ifdef VIDEO_ENABLED + for (const auto &call : calls) { + VideoStream *vstream = reinterpret_cast(call->getPrivate()->getMediaStream(LinphoneStreamTypeVideo)); + if (vstream) { + if (preview) + video_stream_set_native_preview_window_id(vstream, id); + else + video_stream_set_native_window_id(vstream, id); + } + } +#endif +} + +// ============================================================================= + +bool Core::areSoundResourcesLocked () const { + L_D(); + for (const auto &call : d->calls) { + if (call->mediaInProgress()) + return true; + switch (call->getState()) { + case LinphoneCallOutgoingInit: + case LinphoneCallOutgoingProgress: + case LinphoneCallOutgoingRinging: + case LinphoneCallOutgoingEarlyMedia: + case LinphoneCallConnected: + case LinphoneCallRefered: + case LinphoneCallIncomingEarlyMedia: + case LinphoneCallUpdating: + lInfo() << "Call " << call << " is locking sound resources"; + return true; + default: + break; + } + } + return false; +} + +shared_ptr Core::getCallByRemoteAddress (const Address &addr) const { + L_D(); + for (const auto &call : d->calls) { + if (call->getRemoteAddress().weakEqual(addr)) + return call; + } + return nullptr; +} + +const list> &Core::getCalls () const { + L_D(); + return d->calls; +} + +unsigned int Core::getCallsNb () const { + L_D(); + return static_cast(d->calls.size()); +} + +shared_ptr Core::getCurrentCall () const { + L_D(); + return d->currentCall; +} + +LinphoneStatus Core::pauseAllCalls () { + L_D(); + for (const auto &call : d->calls) { + if ((call->getState() == LinphoneCallStreamsRunning) || (call->getState() == LinphoneCallPausedByRemote)) + call->pause(); + } + return 0; +} + +void Core::soundcardHintCheck () { + L_D(); + bool noNeedForSound = true; + // Check if the remaining calls are paused + for (const auto &call : d->calls) { + if ((call->getState() != LinphoneCallPausing) + && (call->getState() != LinphoneCallPaused) + && (call->getState() != LinphoneCallEnd) + && (call->getState() != LinphoneCallError)) { + noNeedForSound = false; + break; + } + } + // If no more calls or all calls are paused, we can free the soundcard + LinphoneConfig *config = linphone_core_get_config(L_GET_C_BACK_PTR(this)); + bool useRtpIo = !!lp_config_get_int(config, "sound", "rtp_io", FALSE); + bool useRtpIoEnableLocalOutput = !!lp_config_get_int(config, "sound", "rtp_io_enable_local_output", FALSE); + bool useFiles = L_GET_C_BACK_PTR(getSharedFromThis())->use_files; + if ((!d->hasCalls() || noNeedForSound) + && (!useFiles && (!useRtpIo || (useRtpIo && useRtpIoEnableLocalOutput)))) { + lInfo() << "Notifying soundcard that we don't need it anymore for calls"; + d->notifySoundcardUsage(false); + } +} + +LinphoneStatus Core::terminateAllCalls () { + L_D(); + while (!d->calls.empty()) { + d->calls.front()->terminate(); + } + return 0; +} + +LINPHONE_END_NAMESPACE diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 76bdcda8f..3c86e1f03 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -131,7 +131,7 @@ list> Core::findChatRooms (const IdentityAddress &peerAddre shared_ptr Core::findOneToOneChatRoom ( const IdentityAddress &localAddress, const IdentityAddress &participantAddress -) { +) const { L_D(); for (const auto &chatRoom : d->chatRooms) { if ( diff --git a/src/core/core-p.h b/src/core/core-p.h index da7569d7e..3b79cbf58 100644 --- a/src/core/core-p.h +++ b/src/core/core-p.h @@ -30,6 +30,19 @@ LINPHONE_BEGIN_NAMESPACE class CorePrivate : public ObjectPrivate { public: + void init(); + void uninit(); + + int addCall (const std::shared_ptr &call); + bool canWeAddCall () const; + bool hasCalls () const { return !calls.empty(); } + bool isAlreadyInCallWithAddress (const Address &addr) const; + void iterateCalls (time_t currentRealTime, bool oneSecondElapsed) const; + void notifySoundcardUsage (bool used); + int removeCall (const std::shared_ptr &call); + void setCurrentCall (const std::shared_ptr &call) { currentCall = call; } + void unsetVideoWindowId (bool preview, void *id); + void insertChatRoom (const std::shared_ptr &chatRoom); void insertChatRoomWithDb (const std::shared_ptr &chatRoom); std::shared_ptr createBasicChatRoom (const ChatRoomId &chatRoomId, bool isRtt); @@ -38,6 +51,9 @@ public: LinphoneCore *cCore = nullptr; private: + std::list> calls; + std::shared_ptr currentCall; + std::list> chatRooms; std::unordered_map> chatRoomsById; diff --git a/src/core/core.cpp b/src/core/core.cpp index 906b135d7..8977573dd 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -17,12 +17,16 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include + +#include "call/call.h" #include "core-p.h" #include "logger/logger.h" #include "paths/paths.h" // TODO: Remove me later. #include "c-wrapper/c-wrapper.h" +#include "private.h" #define LINPHONE_DB "linphone.db" @@ -32,6 +36,40 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE +void CorePrivate::init () { + L_Q(); + mainDb.reset(new MainDb(q->getSharedFromThis())); + + AbstractDb::Backend backend; + string uri = L_C_TO_STRING(lp_config_get_string(linphone_core_get_config(L_GET_C_BACK_PTR(q)), "storage", "uri", nullptr)); + if (!uri.empty()) + backend = strcmp(lp_config_get_string(linphone_core_get_config(L_GET_C_BACK_PTR(q)), "storage", "backend", nullptr), "mysql") == 0 + ? MainDb::Mysql + : MainDb::Sqlite3; + else { + backend = AbstractDb::Sqlite3; + uri = q->getDataPath() + LINPHONE_DB; + } + + lInfo() << "Opening " LINPHONE_DB " at: " << uri; + if (!mainDb->connect(backend, uri)) + lFatal() << "Unable to open linphone database."; + + for (auto &chatRoom : mainDb->getChatRooms()) + insertChatRoom(chatRoom); +} + +void CorePrivate::uninit () { + L_Q(); + while (!calls.empty()) { + calls.front()->terminate(); + linphone_core_iterate(L_GET_C_BACK_PTR(q)); + ms_usleep(10000); + } +} + +// ============================================================================= + Core::Core () : Object(*new CorePrivate) {} Core::~Core () { @@ -41,36 +79,12 @@ Core::~Core () { shared_ptr Core::create (LinphoneCore *cCore) { // Do not use `make_shared` => Private constructor. shared_ptr core = shared_ptr(new Core); - - CorePrivate *const d = core->getPrivate(); - - d->cCore = cCore; - d->mainDb.reset(new MainDb(core->getSharedFromThis())); - - AbstractDb::Backend backend; - string uri = L_C_TO_STRING(lp_config_get_string(linphone_core_get_config(d->cCore), "storage", "uri", nullptr)); - if (!uri.empty()) - backend = strcmp(lp_config_get_string(linphone_core_get_config(d->cCore), "storage", "backend", nullptr), "mysql") == 0 - ? MainDb::Mysql - : MainDb::Sqlite3; - else { - backend = AbstractDb::Sqlite3; - uri = core->getDataPath() + LINPHONE_DB; - } - - lInfo() << "Opening " LINPHONE_DB " at: " << uri; - if (!d->mainDb->connect(backend, uri)) - lFatal() << "Unable to open linphone database."; - - for (auto &chatRoom : d->mainDb->getChatRooms()) - d->insertChatRoom(chatRoom); - + L_SET_CPP_PTR_FROM_C_OBJECT(cCore, core); return core; } LinphoneCore *Core::getCCore () const { - L_D(); - return d->cCore; + return L_GET_C_BACK_PTR(this); } // ----------------------------------------------------------------------------- @@ -78,13 +92,11 @@ LinphoneCore *Core::getCCore () const { // ----------------------------------------------------------------------------- string Core::getDataPath() const { - L_D(); - return Paths::getPath(Paths::Data, static_cast(d->cCore->platform_helper)); + return Paths::getPath(Paths::Data, static_cast(L_GET_C_BACK_PTR(this)->platform_helper)); } string Core::getConfigPath() const { - L_D(); - return Paths::getPath(Paths::Config, static_cast(d->cCore->platform_helper)); + return Paths::getPath(Paths::Config, static_cast(L_GET_C_BACK_PTR(this)->platform_helper)); } LINPHONE_END_NAMESPACE diff --git a/src/core/core.h b/src/core/core.h index f88c7251d..b74330ac6 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -24,18 +24,23 @@ #include "object/object.h" +#include "linphone/types.h" + // ============================================================================= L_DECL_C_STRUCT(LinphoneCore); LINPHONE_BEGIN_NAMESPACE +class Address; +class Call; class ChatRoom; class ChatRoomId; class CorePrivate; class IdentityAddress; class LINPHONE_PUBLIC Core : public Object { + friend class CallPrivate; friend class ChatMessagePrivate; friend class ChatRoom; friend class ChatRoomPrivate; @@ -61,6 +66,19 @@ public: // TODO: Remove me later. LinphoneCore *getCCore () const; + // --------------------------------------------------------------------------- + // Call. + // --------------------------------------------------------------------------- + + bool areSoundResourcesLocked () const; + std::shared_ptr getCallByRemoteAddress (const Address &addr) const; + const std::list> &getCalls () const; + unsigned int getCallsNb () const; + std::shared_ptr getCurrentCall () const; + LinphoneStatus pauseAllCalls (); + void soundcardHintCheck (); + LinphoneStatus terminateAllCalls (); + // --------------------------------------------------------------------------- // ChatRoom. // --------------------------------------------------------------------------- @@ -73,7 +91,7 @@ public: std::shared_ptr findOneToOneChatRoom ( const IdentityAddress &localAddress, const IdentityAddress &participantAddress - ); + ) const; std::shared_ptr createClientGroupChatRoom (const std::string &subject); std::shared_ptr createClientGroupChatRoom (const std::string &subject, const IdentityAddress &localAddress); diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index 5e79fdd79..f0e5dc34e 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -2541,7 +2541,7 @@ static void call_with_privacy(void) { BC_ASSERT_EQUAL(linphone_call_params_get_privacy(linphone_call_get_current_params(c2)),LinphonePrivacyId, int, "%d"); } - + liblinphone_tester_check_rtcp(pauline, marie); end_call(pauline, marie); /*test proxy config privacy*/ diff --git a/tester/conference-event-tester.cpp b/tester/conference-event-tester.cpp index 5cb142c5b..6f84d5bf6 100644 --- a/tester/conference-event-tester.cpp +++ b/tester/conference-event-tester.cpp @@ -465,7 +465,7 @@ public: string confSubject; }; -ConferenceEventTester::ConferenceEventTester (LinphoneCore *core, const Address &confAddr) : RemoteConference(core->cppCore, confAddr) { +ConferenceEventTester::ConferenceEventTester (LinphoneCore *core, const Address &confAddr) : RemoteConference(core->cppPtr, confAddr) { handler = new RemoteConferenceEventHandler(this); } @@ -806,7 +806,7 @@ void send_first_notify() { Address addr(identityStr); bctbx_free(identityStr); ConferenceEventTester tester(marie->lc, addr); - LocalConference localConf(pauline->lc->cppCore, addr); + LocalConference localConf(pauline->lc->cppPtr, addr); LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); char *bobAddrStr = linphone_address_as_string(cBobAddr); Address bobAddr(bobAddrStr); @@ -851,7 +851,7 @@ void send_added_notify() { Address addr(identityStr); bctbx_free(identityStr); ConferenceEventTester tester(marie->lc, addr); - LocalConference localConf(pauline->lc->cppCore, addr); + LocalConference localConf(pauline->lc->cppPtr, addr); LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); char *bobAddrStr = linphone_address_as_string(cBobAddr); Address bobAddr(bobAddrStr); @@ -912,7 +912,7 @@ void send_removed_notify() { Address addr(identityStr); bctbx_free(identityStr); ConferenceEventTester tester(marie->lc, addr); - LocalConference localConf(pauline->lc->cppCore, addr); + LocalConference localConf(pauline->lc->cppPtr, addr); LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); char *bobAddrStr = linphone_address_as_string(cBobAddr); Address bobAddr(bobAddrStr); @@ -965,7 +965,7 @@ void send_admined_notify() { Address addr(identityStr); bctbx_free(identityStr); ConferenceEventTester tester(marie->lc, addr); - LocalConference localConf(pauline->lc->cppCore, addr); + LocalConference localConf(pauline->lc->cppPtr, addr); LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); char *bobAddrStr = linphone_address_as_string(cBobAddr); Address bobAddr(bobAddrStr); @@ -1017,7 +1017,7 @@ void send_unadmined_notify() { Address addr(identityStr); bctbx_free(identityStr); ConferenceEventTester tester(marie->lc, addr); - LocalConference localConf(pauline->lc->cppCore, addr); + LocalConference localConf(pauline->lc->cppPtr, addr); LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); char *bobAddrStr = linphone_address_as_string(cBobAddr); Address bobAddr(bobAddrStr); @@ -1070,7 +1070,7 @@ void send_subject_changed_notify () { Address addr(identityStr); bctbx_free(identityStr); ConferenceEventTester tester(marie->lc, addr); - LocalConference localConf(pauline->lc->cppCore, addr); + LocalConference localConf(pauline->lc->cppPtr, addr); LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); char *bobAddrStr = linphone_address_as_string(cBobAddr); Address bobAddr(bobAddrStr); @@ -1130,7 +1130,7 @@ void send_device_added_notify() { Address addr(identityStr); bctbx_free(identityStr); ConferenceEventTester tester(marie->lc, addr); - LocalConference localConf(pauline->lc->cppCore, addr); + LocalConference localConf(pauline->lc->cppPtr, addr); LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); char *bobAddrStr = linphone_address_as_string(cBobAddr); Address bobAddr(bobAddrStr); @@ -1182,7 +1182,7 @@ void send_device_removed_notify() { Address addr(identityStr); bctbx_free(identityStr); ConferenceEventTester tester(marie->lc, addr); - LocalConference localConf(pauline->lc->cppCore, addr); + LocalConference localConf(pauline->lc->cppPtr, addr); LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri); char *bobAddrStr = linphone_address_as_string(cBobAddr); Address bobAddr(bobAddrStr); diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index 4653bc7f4..710289a12 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -396,7 +396,7 @@ static void cpim_chat_message_modifier_base(bool_t use_multipart) { lp_config_set_int(config, "sip", "use_cpim", 1); IdentityAddress paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); - shared_ptr marieRoom = marie->lc->cppCore->getOrCreateBasicChatRoom(paulineAddress); + shared_ptr marieRoom = marie->lc->cppPtr->getOrCreateBasicChatRoom(paulineAddress); shared_ptr marieMessage = marieRoom->createMessage("Hello CPIM"); if (use_multipart) { diff --git a/tester/main-db-tester.cpp b/tester/main-db-tester.cpp index e6ee22ba8..ca041b279 100644 --- a/tester/main-db-tester.cpp +++ b/tester/main-db-tester.cpp @@ -45,7 +45,7 @@ class MainDbProvider { public: MainDbProvider () { mCoreManager = linphone_core_manager_new("marie_rc"); - mMainDb = new MainDb(mCoreManager->lc->cppCore->getSharedFromThis()); + mMainDb = new MainDb(mCoreManager->lc->cppPtr->getSharedFromThis()); mMainDb->connect(MainDb::Sqlite3, getDatabasePath()); } diff --git a/tester/multipart-tester.cpp b/tester/multipart-tester.cpp index 9f1c628e5..840058540 100644 --- a/tester/multipart-tester.cpp +++ b/tester/multipart-tester.cpp @@ -41,7 +41,7 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer, bool LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc"); IdentityAddress paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); - shared_ptr marieRoom = pauline->lc->cppCore->getOrCreateBasicChatRoom(paulineAddress); + shared_ptr marieRoom = pauline->lc->cppPtr->getOrCreateBasicChatRoom(paulineAddress); shared_ptr marieMessage = marieRoom->createMessage(); if (first_file_transfer) { diff --git a/tools/python/apixml2python.py b/tools/python/apixml2python.py index e0aac85b4..e998d5c65 100755 --- a/tools/python/apixml2python.py +++ b/tools/python/apixml2python.py @@ -52,7 +52,6 @@ blacklisted_functions = [ 'linphone_config_load_dict_to_section', # missing LinphoneDictionary 'linphone_config_section_to_dict', # missing LinphoneDictionary 'linphone_core_add_listener', - 'linphone_core_can_we_add_call', # private function 'linphone_core_enable_log_collection', # need to handle class properties 'linphone_core_enable_logs', # unhandled argument type FILE 'linphone_core_enable_logs_with_cb', # callback function in parameter From fc61014650d232b98eb83741f02b7f8a0efdd46e Mon Sep 17 00:00:00 2001 From: Erwan Croze Date: Fri, 1 Dec 2017 14:52:07 +0100 Subject: [PATCH 0960/2215] Adding setLastNotify to remote conference event handler --- .../handlers/local-conference-event-handler.cpp | 9 +++++++-- src/conference/handlers/local-conference-event-handler.h | 4 +++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/conference/handlers/local-conference-event-handler.cpp b/src/conference/handlers/local-conference-event-handler.cpp index bceacae28..f705a59fe 100644 --- a/src/conference/handlers/local-conference-event-handler.cpp +++ b/src/conference/handlers/local-conference-event-handler.cpp @@ -346,12 +346,12 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceRemoved // ============================================================================= -LocalConferenceEventHandler::LocalConferenceEventHandler (LocalConference *localConference) : +LocalConferenceEventHandler::LocalConferenceEventHandler (LocalConference *localConference, unsigned int notify) : Object(*new LocalConferenceEventHandlerPrivate) { L_D(); xercesc::XMLPlatformUtils::Initialize(); d->conf = localConference; - // TODO : init d->lastNotify = last notify + d->lastNotify = notify; } LocalConferenceEventHandler::~LocalConferenceEventHandler () { @@ -429,4 +429,9 @@ void LocalConferenceEventHandler::notifyParticipantDeviceRemoved (const Address d->notifyAll(d->createNotifyParticipantDeviceRemoved(addr, gruu)); } +void LocalConferenceEventHandler::setLastNotify (unsigned int lastNotify) { + L_D(); + d->lastNotify = lastNotify; +} + LINPHONE_END_NAMESPACE diff --git a/src/conference/handlers/local-conference-event-handler.h b/src/conference/handlers/local-conference-event-handler.h index bdb14700b..04f45632c 100644 --- a/src/conference/handlers/local-conference-event-handler.h +++ b/src/conference/handlers/local-conference-event-handler.h @@ -35,7 +35,7 @@ class LocalConferenceEventHandlerPrivate; class LocalConferenceEventHandler : public Object { public: - LocalConferenceEventHandler (LocalConference *localConference); + LocalConferenceEventHandler (LocalConference *localConference, unsigned int notify = 0); ~LocalConferenceEventHandler (); void subscribeReceived (LinphoneEvent *lev); @@ -45,6 +45,8 @@ public: void notifySubjectChanged (); void notifyParticipantDeviceAdded (const Address &addr, const Address &gruu); void notifyParticipantDeviceRemoved (const Address &addr, const Address &gruu); + + void setLastNotify (unsigned int lastNotify); private: L_DECLARE_PRIVATE(LocalConferenceEventHandler); From a57290dbcab529a4053bad316211798e3c46341b Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 4 Dec 2017 15:08:17 +0100 Subject: [PATCH 0961/2215] feat(c-chat-room): add new function to get events list size --- include/linphone/api/c-chat-room.h | 7 +++++ src/c-wrapper/api/c-chat-room.cpp | 6 +++- src/chat/chat-room/chat-room.cpp | 6 +++- src/chat/chat-room/chat-room.h | 1 + src/db/main-db.cpp | 48 +++++++++++++++++++++++++----- src/db/main-db.h | 3 ++ 6 files changed, 62 insertions(+), 9 deletions(-) diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index 42c6b7dee..948a3708a 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -202,6 +202,13 @@ LINPHONE_PUBLIC bctbx_list_t *linphone_chat_room_get_history_events (LinphoneCha */ LINPHONE_PUBLIC bctbx_list_t *linphone_chat_room_get_history_range_events (LinphoneChatRoom *cr, int begin, int end); +/** + * Gets the number of events in a chat room. + * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which size has to be computed + * @return the number of events. + */ +LINPHONE_PUBLIC int linphone_chat_room_get_history_events_size(LinphoneChatRoom *cr); + /** * Gets the last chat message sent or received in this chat room * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which last message should be retrieved diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index ecae6ba28..48930535e 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -180,7 +180,7 @@ int linphone_chat_room_get_unread_messages_count (LinphoneChatRoom *cr) { } int linphone_chat_room_get_history_size (LinphoneChatRoom *cr) { - return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistorySize(); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getChatMessagesCount(); } void linphone_chat_room_delete_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) { @@ -216,6 +216,10 @@ bctbx_list_t *linphone_chat_room_get_history_range_events (LinphoneChatRoom *cr, return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistoryRange(begin, end)); } +int linphone_chat_room_get_history_events_size(LinphoneChatRoom *cr) { + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistorySize(); +} + LinphoneChatMessage *linphone_chat_room_get_last_message_in_history(LinphoneChatRoom *cr) { shared_ptr cppPtr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getLastChatMessageInHistory(); if (!cppPtr) diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index ce9e6af53..35a8f31cc 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -354,7 +354,7 @@ list> ChatRoom::getHistoryRange (int begin, int end) { } int ChatRoom::getHistorySize () { - return getCore()->getPrivate()->mainDb->getChatMessagesCount(getChatRoomId()); + return getCore()->getPrivate()->mainDb->getHistorySize(getChatRoomId()); } shared_ptr ChatRoom::getLastChatMessageInHistory() const { @@ -365,6 +365,10 @@ void ChatRoom::deleteHistory () { getCore()->getPrivate()->mainDb->cleanHistory(getChatRoomId()); } +int ChatRoom::getChatMessagesCount () { + return getCore()->getPrivate()->mainDb->getChatMessagesCount(getChatRoomId()); +} + int ChatRoom::getUnreadChatMessagesCount () { return getCore()->getPrivate()->mainDb->getUnreadChatMessagesCount(getChatRoomId()); } diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index 36dd0e998..5b253a1e6 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -68,6 +68,7 @@ public: void deleteHistory (); + int getChatMessagesCount (); int getUnreadChatMessagesCount (); // TODO: Remove useless functions. diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 786123d2f..549c4ffa2 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -469,7 +469,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), // 2 - Fetch contents. { soci::session *session = dbSession.getBackendSession(); - const string query = "SELECT chat_message_content.id, content_type.id, content_type.value, body FROM chat_message_content, content_type" + static const string query = "SELECT chat_message_content.id, content_type.id, content_type.value, body" + " FROM chat_message_content, content_type" " WHERE event_id = :eventId AND content_type_id = content_type.id"; soci::rowset rows = (session->prepare << query, soci::use(eventId)); for (const auto &row : rows) { @@ -1314,7 +1315,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return 0; } - string query = "SELECT COUNT(*) FROM event" + + static string query = "SELECT COUNT(*) FROM event" + buildSqlEventFilter({ ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter }, mask); int count = 0; @@ -1354,7 +1355,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return event; // TODO: Improve. Deal with all events in the future. - static string query = "SELECT peer_sip_address.value, local_sip_address.value, type, event.creation_time" + static const string query = "SELECT peer_sip_address.value, local_sip_address.value, type, event.creation_time" " FROM event, conference_event, chat_room, sip_address AS peer_sip_address, sip_address as local_sip_address" " WHERE event.id = :eventId" " AND conference_event.event_id = event.id" @@ -1639,8 +1640,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return chatMessages; } - const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); - string query = "SELECT id, type, creation_time FROM event" + static const string query = "SELECT id, type, creation_time FROM event" " WHERE id IN (" " SELECT event_id FROM conference_event" " WHERE event_id IN (SELECT event_id FROM conference_chat_message_event WHERE imdn_message_id = :imdnMessageId)" @@ -1657,6 +1657,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = d->dbSession.getBackendSession(); soci::transaction tr(*session); + const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); soci::rowset rows = (session->prepare << query, soci::use(imdnMessageId), soci::use(dbChatRoomId)); for (const auto &row : rows) { long long eventId = d->resolveId(row, 0); @@ -1768,6 +1769,35 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return list>(); } + int MainDb::getHistorySize (const ChatRoomId &chatRoomId, FilterMask mask) const { + L_D(); + + if (!isConnected()) { + lWarning() << "Unable to get history size. Not connected."; + return 0; + } + + int count = 0; + + const string query = "SELECT COUNT(*) FROM event, conference_event" + " WHERE chat_room_id = :chatRoomId" + " AND event_id = event.id" + + buildSqlEventFilter({ + ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter + }, mask, "AND"); + + L_BEGIN_LOG_EXCEPTION + + const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); + + soci::session *session = d->dbSession.getBackendSession(); + *session << query, soci::into(count), soci::use(dbChatRoomId); + + L_END_LOG_EXCEPTION + + return count; + } + void MainDb::cleanHistory (const ChatRoomId &chatRoomId, FilterMask mask) { L_D(); @@ -1776,7 +1806,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return; } - string query = "SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" + + const string query = "SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" + buildSqlEventFilter({ ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter }, mask); @@ -1852,7 +1882,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), list> participants; const long long &dbChatRoomId = d->resolveId(row, 0); - string query = "SELECT sip_address.value, is_admin" + static const string query = "SELECT sip_address.value, is_admin" " FROM sip_address, chat_room, chat_room_participant" " WHERE chat_room.id = :chatRoomId" " AND sip_address.id = chat_room_participant.participant_sip_address_id" @@ -2193,6 +2223,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return list>(); } + int getHistorySize (const ChatRoomId &, FilterMask) const { + return 0; + } + list> MainDb::getChatRooms () const { return list>(); } diff --git a/src/db/main-db.h b/src/db/main-db.h index 907dd4e8c..f91578573 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -104,6 +104,9 @@ public: int end, FilterMask mask = NoFilter ) const; + + int getHistorySize (const ChatRoomId &chatRoomId, FilterMask mask = NoFilter) const; + void cleanHistory (const ChatRoomId &chatRoomId, FilterMask mask = NoFilter); // --------------------------------------------------------------------------- From 05271e86030d983354bd559bd846a7f3f0e03926 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 4 Dec 2017 15:11:54 +0100 Subject: [PATCH 0962/2215] Change the state of ClientGroupChatRoom and ServerGroupChatRoom outside of their constructors. --- src/chat/chat-room/client-group-chat-room.cpp | 6 +----- src/chat/chat-room/client-group-chat-room.h | 3 +-- src/db/main-db.cpp | 16 ++++++++++++---- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index bb72ded64..3ce328667 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -103,11 +103,9 @@ ClientGroupChatRoom::ClientGroupChatRoom ( shared_ptr &me, const string &subject, list> &&participants, - unsigned int lastNotifyId, - bool hasBeenLeft + unsigned int lastNotifyId ) : ChatRoom(*new ClientGroupChatRoomPrivate, core, ChatRoomId(peerAddress, me->getAddress())), RemoteConference(core, me->getAddress(), nullptr) { - L_D(); L_D_T(RemoteConference, dConference); dConference->focus = make_shared(peerAddress); @@ -115,8 +113,6 @@ RemoteConference(core, me->getAddress(), nullptr) { dConference->subject = subject; dConference->participants = move(participants); - d->state = hasBeenLeft ? ChatRoom::State::Terminated : ChatRoom::State::Created; - getMe()->getPrivate()->setAdmin(me->isAdmin()); dConference->eventHandler->setLastNotify(lastNotifyId); diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 05efc6ae7..41f201961 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -45,8 +45,7 @@ public: std::shared_ptr &me, const std::string &subject, std::list> &&participants, - unsigned int lastNotifyId, - bool hasBeenLeft + unsigned int lastNotifyId ); std::shared_ptr getCore () const; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 549c4ffa2..e316e7db2 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1906,17 +1906,22 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), continue; } - if (!linphone_core_conference_server_enabled(core->getCCore())) + if (!linphone_core_conference_server_enabled(core->getCCore())) { + bool hasBeenLeft = !!row.get(8, 0); chatRoom = make_shared( core, chatRoomId.getPeerAddress(), me, subject, move(participants), - lastNotifyId, - !!row.get(8, 0) + lastNotifyId ); - else + chatRoom->getPrivate()->setState(LinphonePrivate::ChatRoom::State::Instantiated); + chatRoom->getPrivate()->setState(hasBeenLeft + ? ChatRoom::State::Terminated + : ChatRoom::State::Created + ); + } else { chatRoom = make_shared( core, chatRoomId.getPeerAddress(), @@ -1924,6 +1929,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), move(participants), lastNotifyId ); + chatRoom->getPrivate()->setState(LinphonePrivate::ChatRoom::State::Instantiated); + chatRoom->getPrivate()->setState(LinphonePrivate::ChatRoom::State::Created); + } } if (!chatRoom) From 181bfa2ec9c36e54d0cfa78f1350e8ae6096abb1 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 4 Dec 2017 15:12:25 +0100 Subject: [PATCH 0963/2215] Change the chat room instantiated callback to chat room state changed. --- coreapi/linphonecore.c | 8 ++++---- coreapi/private_functions.h | 2 +- coreapi/vtables.c | 4 ++-- include/linphone/callbacks.h | 6 +++--- include/linphone/core.h | 10 +++++----- src/chat/chat-room/chat-room.cpp | 5 +---- 6 files changed, 16 insertions(+), 19 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 93b6adcc7..f4cc4c85a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -434,12 +434,12 @@ void linphone_core_cbs_set_version_update_check_result_received(LinphoneCoreCbs cbs->vtable->version_update_check_result_received = cb; } -LinphoneCoreCbsChatRoomInstantiatedCb linphone_core_cbs_get_chat_room_instantiated (LinphoneCoreCbs *cbs) { - return cbs->vtable->chat_room_instantiated; +LinphoneCoreCbsChatRoomStateChangedCb linphone_core_cbs_get_chat_room_state_changed (LinphoneCoreCbs *cbs) { + return cbs->vtable->chat_room_state_changed; } -void linphone_core_cbs_set_chat_room_instantiated (LinphoneCoreCbs *cbs, LinphoneCoreCbsChatRoomInstantiatedCb cb) { - cbs->vtable->chat_room_instantiated = cb; +void linphone_core_cbs_set_chat_room_state_changed (LinphoneCoreCbs *cbs, LinphoneCoreCbsChatRoomStateChangedCb cb) { + cbs->vtable->chat_room_state_changed = cb; } void linphone_core_cbs_set_ec_calibration_result(LinphoneCoreCbs *cbs, LinphoneCoreCbsEcCalibrationResultCb cb) { diff --git a/coreapi/private_functions.h b/coreapi/private_functions.h index 71a2b38db..fcc3c6911 100644 --- a/coreapi/private_functions.h +++ b/coreapi/private_functions.h @@ -536,7 +536,7 @@ void linphone_core_notify_friend_list_created(LinphoneCore *lc, LinphoneFriendLi void linphone_core_notify_friend_list_removed(LinphoneCore *lc, LinphoneFriendList *list); void linphone_core_notify_call_created(LinphoneCore *lc, LinphoneCall *call); void linphone_core_notify_version_update_check_result_received(LinphoneCore *lc, LinphoneVersionUpdateCheckResult result, const char *version, const char *url); -void linphone_core_notify_chat_room_instantiated (LinphoneCore *lc, LinphoneChatRoom *cr); +void linphone_core_notify_chat_room_state_changed (LinphoneCore *lc, LinphoneChatRoom *cr, LinphoneChatRoomState state); void linphone_core_notify_ec_calibration_result(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms); void linphone_core_notify_ec_calibration_audio_init(LinphoneCore *lc); diff --git a/coreapi/vtables.c b/coreapi/vtables.c index 33eab6ccb..aef7785d9 100644 --- a/coreapi/vtables.c +++ b/coreapi/vtables.c @@ -288,8 +288,8 @@ void linphone_core_notify_version_update_check_result_received(LinphoneCore *lc, cleanup_dead_vtable_refs(lc); } -void linphone_core_notify_chat_room_instantiated (LinphoneCore *lc, LinphoneChatRoom *cr) { - NOTIFY_IF_EXIST(chat_room_instantiated, lc, cr); +void linphone_core_notify_chat_room_state_changed (LinphoneCore *lc, LinphoneChatRoom *cr, LinphoneChatRoomState state) { + NOTIFY_IF_EXIST(chat_room_state_changed, lc, cr, state); cleanup_dead_vtable_refs(lc); } diff --git a/include/linphone/callbacks.h b/include/linphone/callbacks.h index b70febf8b..7da93b9f7 100644 --- a/include/linphone/callbacks.h +++ b/include/linphone/callbacks.h @@ -399,11 +399,11 @@ typedef LinphoneCoreCbsFriendListRemovedCb LinphoneCoreFriendListRemovedCb; typedef void (*LinphoneCoreCbsVersionUpdateCheckResultReceivedCb) (LinphoneCore *lc, LinphoneVersionUpdateCheckResult result, const char *version, const char *url); /** - * Callback prototype telling that a LinphoneChatRoom object has been instantiated. This is useful to set the callbacks on the LinphoneChatRoom object. + * Callback prototype telling that a LinphoneChatRoom state has changed. * @param[in] lc LinphoneCore object - * @param[in] cr The LinphoneChatRoom object that has been instantiated + * @param[in] cr The LinphoneChatRoom object for which the state has changed */ -typedef void (*LinphoneCoreCbsChatRoomInstantiatedCb) (LinphoneCore *lc, LinphoneChatRoom *cr); +typedef void (*LinphoneCoreCbsChatRoomStateChangedCb) (LinphoneCore *lc, LinphoneChatRoom *cr, LinphoneChatRoomState state); /** * @} diff --git a/include/linphone/core.h b/include/linphone/core.h index ded1e3156..e6382eb8b 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -185,7 +185,7 @@ typedef struct _LinphoneCoreVTable{ LinphoneCoreFriendListRemovedCb friend_list_removed; LinphoneCoreCbsCallCreatedCb call_created; LinphoneCoreCbsVersionUpdateCheckResultReceivedCb version_update_check_result_received; - LinphoneCoreCbsChatRoomInstantiatedCb chat_room_instantiated; + LinphoneCoreCbsChatRoomStateChangedCb chat_room_state_changed; LinphoneCoreCbsEcCalibrationResultCb ec_calibration_result; LinphoneCoreCbsEcCalibrationAudioInitCb ec_calibration_audio_init; LinphoneCoreCbsEcCalibrationAudioUninitCb ec_calibration_audio_uninit; @@ -666,18 +666,18 @@ LINPHONE_PUBLIC void linphone_core_cbs_set_version_update_check_result_received( LINPHONE_PUBLIC LinphoneCoreCbsVersionUpdateCheckResultReceivedCb linphone_core_cbs_get_version_update_check_result_received(LinphoneCoreCbs *cbs); /** - * Get the chat room instantiated callback. + * Get the chat room state changed callback. * @param[in] cbs LinphoneCoreCbs object * @return The current callback */ -LINPHONE_PUBLIC LinphoneCoreCbsChatRoomInstantiatedCb linphone_core_cbs_get_chat_room_instantiated (LinphoneCoreCbs *cbs); +LINPHONE_PUBLIC LinphoneCoreCbsChatRoomStateChangedCb linphone_core_cbs_get_chat_room_state_changed (LinphoneCoreCbs *cbs); /** - * Set the chat room instantiated callback. + * Set the chat room state changed callback. * @param[in] cbs LinphoneCoreCbs object * @param[in] cb The callback to use */ -LINPHONE_PUBLIC void linphone_core_cbs_set_chat_room_instantiated (LinphoneCoreCbs *cbs, LinphoneCoreCbsChatRoomInstantiatedCb cb); +LINPHONE_PUBLIC void linphone_core_cbs_set_chat_room_state_changed (LinphoneCoreCbs *cbs, LinphoneCoreCbsChatRoomStateChangedCb cb); /** * @brief Sets a callback to call each time the echo-canceler calibration is completed. diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 35a8f31cc..98a0959cb 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -57,12 +57,8 @@ void ChatRoomPrivate::release () { // ----------------------------------------------------------------------------- void ChatRoomPrivate::setState (ChatRoom::State newState) { - L_Q(); if (newState != state) { state = newState; - if (state == ChatRoom::State::Created) - // TODO : Rename from instatiated to created. - linphone_core_notify_chat_room_instantiated(q->getCore()->getCCore(), L_GET_C_BACK_PTR(q)); notifyStateChanged(); } } @@ -272,6 +268,7 @@ void ChatRoomPrivate::notifyIsComposingReceived (const Address &remoteAddr, bool void ChatRoomPrivate::notifyStateChanged () { L_Q(); + linphone_core_notify_chat_room_state_changed(q->getCore()->getCCore(), L_GET_C_BACK_PTR(q), (LinphoneChatRoomState)state); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsStateChangedCb cb = linphone_chat_room_cbs_get_state_changed(cbs); From eb5ab27326daaf993e3364be02db4075289d13d6 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 4 Dec 2017 15:28:55 +0100 Subject: [PATCH 0964/2215] fix(core): rename some methods => Do not set a plural noun before "Count"!!! --- coreapi/linphonecore_jni.cc | 2 +- .../org/linphone/core/LinphoneChatRoom.java | 2 +- .../linphone/core/LinphoneChatRoomImpl.java | 6 +++--- src/c-wrapper/api/c-chat-room.cpp | 4 ++-- src/chat/chat-room/chat-room.cpp | 10 +++++----- src/chat/chat-room/chat-room.h | 4 ++-- src/db/main-db.cpp | 14 +++++++------- src/db/main-db.h | 6 +++--- tester/main-db-tester.cpp | 18 +++++++++--------- 9 files changed, 33 insertions(+), 33 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 49450e0a8..6d5e9734d 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -4497,7 +4497,7 @@ extern "C" jint Java_org_linphone_core_LinphoneChatRoomImpl_getHistorySize (JNI ,jlong ptr) { return (jint) linphone_chat_room_get_history_size((LinphoneChatRoom*)ptr); } -extern "C" jint Java_org_linphone_core_LinphoneChatRoomImpl_getUnreadMessagesCount(JNIEnv* env +extern "C" jint Java_org_linphone_core_LinphoneChatRoomImpl_getUnreadMessageCount(JNIEnv* env ,jobject thiz ,jlong ptr) { return (jint) linphone_chat_room_get_unread_messages_count((LinphoneChatRoom*)ptr); diff --git a/java/common/org/linphone/core/LinphoneChatRoom.java b/java/common/org/linphone/core/LinphoneChatRoom.java index e08378b02..0f08e270f 100644 --- a/java/common/org/linphone/core/LinphoneChatRoom.java +++ b/java/common/org/linphone/core/LinphoneChatRoom.java @@ -80,7 +80,7 @@ public interface LinphoneChatRoom { * Returns the amount of unread messages associated with the peer of this chatRoom. * @return the amount of unread messages */ - int getUnreadMessagesCount(); + int getUnreadMessageCount(); /** * Returns the amount of messages associated with the peer of this chatRoom. diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index f44c6ecf6..0202f2ec0 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -32,7 +32,7 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { private native Object[] getHistoryRange(long ptr, int begin, int end); private native Object[] getHistory(long ptr, int limit); private native void destroy(long ptr); - private native int getUnreadMessagesCount(long ptr); + private native int getUnreadMessageCount(long ptr); private native int getHistorySize(long ptr); private native void deleteHistory(long ptr); private native void compose(long ptr); @@ -101,9 +101,9 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { } } - public int getUnreadMessagesCount() { + public int getUnreadMessageCount() { synchronized(getCore()){ - return getUnreadMessagesCount(nativePtr); + return getUnreadMessageCount(nativePtr); } } diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 48930535e..1702d188d 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -176,11 +176,11 @@ void linphone_chat_room_mark_as_read (LinphoneChatRoom *cr) { } int linphone_chat_room_get_unread_messages_count (LinphoneChatRoom *cr) { - return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getUnreadChatMessagesCount(); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getUnreadChatMessageCount(); } int linphone_chat_room_get_history_size (LinphoneChatRoom *cr) { - return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getChatMessagesCount(); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getChatMessageCount(); } void linphone_chat_room_delete_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) { diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 98a0959cb..b5b5c55df 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -362,12 +362,12 @@ void ChatRoom::deleteHistory () { getCore()->getPrivate()->mainDb->cleanHistory(getChatRoomId()); } -int ChatRoom::getChatMessagesCount () { - return getCore()->getPrivate()->mainDb->getChatMessagesCount(getChatRoomId()); +int ChatRoom::getChatMessageCount () { + return getCore()->getPrivate()->mainDb->getChatMessageCount(getChatRoomId()); } -int ChatRoom::getUnreadChatMessagesCount () { - return getCore()->getPrivate()->mainDb->getUnreadChatMessagesCount(getChatRoomId()); +int ChatRoom::getUnreadChatMessageCount () { + return getCore()->getPrivate()->mainDb->getUnreadChatMessageCount(getChatRoomId()); } // ----------------------------------------------------------------------------- @@ -438,7 +438,7 @@ std::list
      ChatRoom::getComposingAddresses () const { void ChatRoom::markAsRead () { L_D(); - if (getUnreadChatMessagesCount() == 0) + if (getUnreadChatMessageCount() == 0) return; CorePrivate *dCore = getCore()->getPrivate(); diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index 5b253a1e6..b276c83c3 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -68,8 +68,8 @@ public: void deleteHistory (); - int getChatMessagesCount (); - int getUnreadChatMessagesCount (); + int getChatMessageCount (); + int getUnreadChatMessageCount (); // TODO: Remove useless functions. void compose (); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index e316e7db2..22a191fe0 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1307,7 +1307,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return false; } - int MainDb::getEventsCount (FilterMask mask) const { + int MainDb::getEventCount (FilterMask mask) const { L_D(); if (!isConnected()) { @@ -1441,7 +1441,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return list>(); } - int MainDb::getChatMessagesCount (const ChatRoomId &chatRoomId) const { + int MainDb::getChatMessageCount (const ChatRoomId &chatRoomId) const { L_D(); if (!isConnected()) { @@ -1477,7 +1477,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return count; } - int MainDb::getUnreadChatMessagesCount (const ChatRoomId &chatRoomId) const { + int MainDb::getUnreadChatMessageCount (const ChatRoomId &chatRoomId) const { L_D(); if (!isConnected()) { @@ -1525,7 +1525,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return; } - if (getUnreadChatMessagesCount(chatRoomId) == 0) + if (getUnreadChatMessageCount(chatRoomId) == 0) return; string query = "UPDATE conference_chat_message_event" @@ -2186,7 +2186,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return false; } - int MainDb::getEventsCount (FilterMask) const { + int MainDb::getEventCount (FilterMask) const { return 0; } @@ -2201,11 +2201,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return list>(); } - int MainDb::getChatMessagesCount (const ChatRoomId &) const { + int MainDb::getChatMessageCount (const ChatRoomId &) const { return 0; } - int MainDb::getUnreadChatMessagesCount (const ChatRoomId &) const { + int MainDb::getUnreadChatMessageCount (const ChatRoomId &) const { return 0; } diff --git a/src/db/main-db.h b/src/db/main-db.h index f91578573..c3918d581 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -60,7 +60,7 @@ public: bool addEvent (const std::shared_ptr &eventLog); bool updateEvent (const std::shared_ptr &eventLog); static bool deleteEvent (const std::shared_ptr &eventLog); - int getEventsCount (FilterMask mask = NoFilter) const; + int getEventCount (FilterMask mask = NoFilter) const; static std::shared_ptr getEventFromKey (const MainDbKey &dbKey); @@ -77,8 +77,8 @@ public: // Conference chat message events. // --------------------------------------------------------------------------- - int getChatMessagesCount (const ChatRoomId &chatRoomId = ChatRoomId()) const; - int getUnreadChatMessagesCount (const ChatRoomId &chatRoomId = ChatRoomId()) const; + int getChatMessageCount (const ChatRoomId &chatRoomId = ChatRoomId()) const; + int getUnreadChatMessageCount (const ChatRoomId &chatRoomId = ChatRoomId()) const; void markChatMessagesAsRead (const ChatRoomId &chatRoomId = ChatRoomId()) const; std::list> getUnreadChatMessages (const ChatRoomId &chatRoomId = ChatRoomId()) const; diff --git a/tester/main-db-tester.cpp b/tester/main-db-tester.cpp index ca041b279..c8bc44881 100644 --- a/tester/main-db-tester.cpp +++ b/tester/main-db-tester.cpp @@ -73,19 +73,19 @@ static void open_database () { static void get_events_count () { MainDbProvider provider; const MainDb &mainDb = provider.getMainDb(); - BC_ASSERT_EQUAL(mainDb.getEventsCount(), 5175, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceCallFilter), 0, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceInfoFilter), 18, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::ConferenceChatMessageFilter), 5157, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getEventsCount(MainDb::NoFilter), 5175, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventCount(), 5175, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventCount(MainDb::ConferenceCallFilter), 0, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventCount(MainDb::ConferenceInfoFilter), 18, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventCount(MainDb::ConferenceChatMessageFilter), 5157, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getEventCount(MainDb::NoFilter), 5175, int, "%d"); } static void get_messages_count () { MainDbProvider provider; const MainDb &mainDb = provider.getMainDb(); - BC_ASSERT_EQUAL(mainDb.getChatMessagesCount(), 5157, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getChatMessageCount(), 5157, int, "%d"); BC_ASSERT_EQUAL( - mainDb.getChatMessagesCount( + mainDb.getChatMessageCount( ChatRoomId(IdentityAddress("sip:test-3@sip.linphone.org"), IdentityAddress("sip:test-1@sip.linphone.org")) ), 861, int, "%d" @@ -95,9 +95,9 @@ static void get_messages_count () { static void get_unread_messages_count () { MainDbProvider provider; const MainDb &mainDb = provider.getMainDb(); - BC_ASSERT_EQUAL(mainDb.getUnreadChatMessagesCount(), 2, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getUnreadChatMessageCount(), 2, int, "%d"); BC_ASSERT_EQUAL( - mainDb.getUnreadChatMessagesCount( + mainDb.getUnreadChatMessageCount( ChatRoomId(IdentityAddress("sip:test-3@sip.linphone.org"), IdentityAddress("sip:test-1@sip.linphone.org")) ), 0, int, "%d" From 1bbc5446359b5adf0daf019af08d5804f788b516 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 4 Dec 2017 15:35:21 +0100 Subject: [PATCH 0965/2215] refactor code --- src/chat/chat-room/client-group-chat-room.cpp | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 3ce328667..d0bce5c94 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -338,11 +338,11 @@ void ClientGroupChatRoom::onParticipantAdded (const shared_ptrgetPrivate()->mainDb->addEvent(event); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAddedCb cb = linphone_chat_room_cbs_get_participant_added(cbs); - getCore()->getPrivate()->mainDb->addEvent(event); - if (cb) cb(cr, L_GET_C_BACK_PTR(event)); } @@ -360,12 +360,11 @@ void ClientGroupChatRoom::onParticipantRemoved (const shared_ptrparticipants.remove(participant); + getCore()->getPrivate()->mainDb->addEvent(event); LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantRemovedCb cb = linphone_chat_room_cbs_get_participant_removed(cbs); - getCore()->getPrivate()->mainDb->addEvent(event); - if (cb) cb(cr, L_GET_C_BACK_PTR(event)); } @@ -390,11 +389,11 @@ void ClientGroupChatRoom::onParticipantSetAdmin (const shared_ptrgetPrivate()->mainDb->addEvent(event); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAdminStatusChangedCb cb = linphone_chat_room_cbs_get_participant_admin_status_changed(cbs); - getCore()->getPrivate()->mainDb->addEvent(event); - if (cb) cb(cr, L_GET_C_BACK_PTR(event)); } @@ -407,11 +406,11 @@ void ClientGroupChatRoom::onSubjectChanged (const shared_ptrgetPrivate()->mainDb->addEvent(event); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsSubjectChangedCb cb = linphone_chat_room_cbs_get_subject_changed(cbs); - getCore()->getPrivate()->mainDb->addEvent(event); - if (cb) cb(cr, L_GET_C_BACK_PTR(event)); } @@ -432,11 +431,11 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (const shared_ptrgetPrivate()->mainDb->addEvent(event); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantDeviceAddedCb cb = linphone_chat_room_cbs_get_participant_device_added(cbs); - getCore()->getPrivate()->mainDb->addEvent(event); - if (cb) cb(cr, L_GET_C_BACK_PTR(event)); } @@ -455,11 +454,11 @@ void ClientGroupChatRoom::onParticipantDeviceRemoved (const shared_ptrgetPrivate()->removeDevice(event->getDeviceAddress()); + getCore()->getPrivate()->mainDb->addEvent(event); + LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantDeviceRemovedCb cb = linphone_chat_room_cbs_get_participant_device_removed(cbs); - getCore()->getPrivate()->mainDb->addEvent(event); - if (cb) cb(cr, L_GET_C_BACK_PTR(event)); } From d244864db6da5a9ef92d64ef552f725e67b0090d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 4 Dec 2017 15:41:20 +0100 Subject: [PATCH 0966/2215] Fixed android build --- coreapi/conference.cc | 6 +++--- coreapi/linphonecore.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/coreapi/conference.cc b/coreapi/conference.cc index 522353ff6..ca2196dbd 100644 --- a/coreapi/conference.cc +++ b/coreapi/conference.cc @@ -208,7 +208,7 @@ private: MSAudioEndpoint *m_localEndpoint; MSAudioEndpoint *m_recordEndpoint; RtpProfile *m_localDummyProfile; - bool_t m_terminating; + //bool_t m_terminating; }; class RemoteConference: public Conference { @@ -373,8 +373,8 @@ LocalConference::LocalConference(LinphoneCore *core, LinphoneConference *conf, c m_conf(NULL), m_localEndpoint(NULL), m_recordEndpoint(NULL), - m_localDummyProfile(NULL), - m_terminating(FALSE) { + m_localDummyProfile(NULL)/*, + m_terminating(FALSE)*/ { MSAudioConferenceParams ms_conf_params; ms_conf_params.samplerate = lp_config_get_int(m_core->config, "sound","conference_rate",16000); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f4cc4c85a..1308ff063 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2735,11 +2735,11 @@ static void apply_jitter_value(LinphoneCore *lc, int value, MSFormatType stype){ RtpSession *s=ms->sessions.rtp_session; if (s){ if (value>0){ - ms_message("Jitter buffer size set to [%i] ms on call [%p]",value,call); + ms_message("Jitter buffer size set to [%i] ms on call [%p]", value, call.get()); rtp_session_set_jitter_compensation(s,value); rtp_session_enable_jitter_buffer(s,TRUE); }else if (value==0){ - ms_warning("Jitter buffer is disabled per application request on call [%p]",call); + ms_warning("Jitter buffer is disabled per application request on call [%p]", call.get()); rtp_session_enable_jitter_buffer(s,FALSE); } } From cd40d176c090aefa5c756a27772d432c6cbdc119 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 4 Dec 2017 15:45:17 +0100 Subject: [PATCH 0967/2215] Fixed java wrapper --- wrappers/java/jni.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index a6e855736..b79d18361 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -375,7 +375,7 @@ jobject Java_{{jni_package}}FactoryImpl_createCore(JNIEnv *env, jobject thiz, jo linphone_core_cbs_set_user_data(cbs, listener); linphone_core_cbs_set_transfer_state_changed(cbs, linphone_core_on_transfer_state_changed); - linphone_core_cbs_set_chat_room_instantiated(cbs, linphone_core_on_chat_room_instantiated); + linphone_core_cbs_set_chat_room_state_changed(cbs, linphone_core_on_chat_room_state_changed); linphone_core_cbs_set_friend_list_created(cbs, linphone_core_on_friend_list_created); linphone_core_cbs_set_subscription_state_changed(cbs, linphone_core_on_subscription_state_changed); linphone_core_cbs_set_call_log_updated(cbs, linphone_core_on_call_log_updated); From 9e38d94ba771d43422357f1172df7cb1526075c9 Mon Sep 17 00:00:00 2001 From: Erwan Croze Date: Mon, 4 Dec 2017 12:21:50 +0100 Subject: [PATCH 0968/2215] Fix bad unref in callbacks.c call_received --- coreapi/callbacks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index a14a588e0..d3790bdcb 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -110,13 +110,13 @@ static void call_received(SalCallOp *h) { linphone_address_unref(fromAddr); return; } else if (sal_address_has_param(h->get_remote_contact_address(), "text")) { - linphone_address_unref(toAddr); - linphone_address_unref(fromAddr); shared_ptr chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom( ChatRoomId(IdentityAddress(h->get_to()), IdentityAddress(h->get_to())) ); if (chatRoom) { L_GET_PRIVATE(static_pointer_cast(chatRoom))->confirmJoining(h); + linphone_address_unref(toAddr); + linphone_address_unref(fromAddr); return; } } else { From 2c33faac6fcf3c30fb4272f5d57bfcfa9a11fa35 Mon Sep 17 00:00:00 2001 From: Erwan Croze Date: Mon, 4 Dec 2017 14:00:24 +0100 Subject: [PATCH 0969/2215] Fix main-db.cpp for mysql backend --- src/db/main-db.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 22a191fe0..4aec25d34 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -131,7 +131,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), // `row id` is not supported by soci on Sqlite3. It's necessary to cast id to int... return q->getBackend() == AbstractDb::Sqlite3 ? static_cast(row.get(0)) - : row.get(0); + : row.get(0); } long long MainDbPrivate::insertSipAddress (const string &sipAddress) { @@ -1870,7 +1870,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), tm lastUpdateTime = row.get(4); int capabilities = row.get(5); string subject = row.get(6); - unsigned int lastNotifyId = static_cast(row.get(7, 0)); + unsigned int lastNotifyId = static_cast(getBackend() == Backend::Mysql + ? row.get(7, 0) + : row.get(7, 0) + ); if (capabilities & static_cast(ChatRoom::Capabilities::Basic)) { chatRoom = core->getPrivate()->createBasicChatRoom( @@ -1900,14 +1903,13 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), participants.push_back(participant); } - if (!me) { - lError() << "Unable to find me in: (peer=" + chatRoomId.getPeerAddress().asString() + - ", local=" + chatRoomId.getLocalAddress().asString() + ")."; - continue; - } - if (!linphone_core_conference_server_enabled(core->getCCore())) { bool hasBeenLeft = !!row.get(8, 0); + if (!me) { + lError() << "Unable to find me in: (peer=" + chatRoomId.getPeerAddress().asString() + + ", local=" + chatRoomId.getLocalAddress().asString() + ")."; + continue; + } chatRoom = make_shared( core, chatRoomId.getPeerAddress(), From e9805213e275c5ce666e2b3571855c2917a082bd Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 4 Dec 2017 15:49:47 +0100 Subject: [PATCH 0970/2215] fix(conference): replace getNbParticipants to participantCount --- src/c-wrapper/api/c-chat-room.cpp | 2 +- src/chat/chat-room/basic-chat-room.cpp | 2 +- src/chat/chat-room/basic-chat-room.h | 2 +- src/chat/chat-room/client-group-chat-room.cpp | 4 ++-- src/chat/chat-room/client-group-chat-room.h | 2 +- src/chat/chat-room/server-group-chat-room-stub.cpp | 2 +- src/chat/chat-room/server-group-chat-room.h | 2 +- src/conference/conference-interface.h | 2 +- src/conference/conference.cpp | 2 +- src/conference/conference.h | 2 +- src/core/core-chat-room.cpp | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 1702d188d..133704ade 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -287,7 +287,7 @@ LinphoneParticipant *linphone_chat_room_get_me (const LinphoneChatRoom *cr) { } int linphone_chat_room_get_nb_participants (const LinphoneChatRoom *cr) { - return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getNbParticipants(); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getParticipantCount(); } bctbx_list_t *linphone_chat_room_get_participants (const LinphoneChatRoom *cr) { diff --git a/src/chat/chat-room/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp index 885fc025d..3ee9aca79 100644 --- a/src/chat/chat-room/basic-chat-room.cpp +++ b/src/chat/chat-room/basic-chat-room.cpp @@ -90,7 +90,7 @@ shared_ptr BasicChatRoom::getMe () const { return nullptr; } -int BasicChatRoom::getNbParticipants () const { +int BasicChatRoom::getParticipantCount () const { return 1; } diff --git a/src/chat/chat-room/basic-chat-room.h b/src/chat/chat-room/basic-chat-room.h index 18f5531d5..e761ca791 100644 --- a/src/chat/chat-room/basic-chat-room.h +++ b/src/chat/chat-room/basic-chat-room.h @@ -48,7 +48,7 @@ public: std::shared_ptr findParticipant (const IdentityAddress &addr) const override; std::shared_ptr getMe () const override; - int getNbParticipants () const override; + int getParticipantCount () const override; const std::list> &getParticipants () const override; void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) override; diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index d0bce5c94..508853d53 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -204,8 +204,8 @@ shared_ptr ClientGroupChatRoom::getMe () const { return RemoteConference::getMe(); } -int ClientGroupChatRoom::getNbParticipants () const { - return RemoteConference::getNbParticipants(); +int ClientGroupChatRoom::getParticipantCount () const { + return RemoteConference::getParticipantCount(); } const list> &ClientGroupChatRoom::getParticipants () const { diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 41f201961..8513633ea 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -66,7 +66,7 @@ public: std::shared_ptr findParticipant (const IdentityAddress &addr) const override; std::shared_ptr getMe () const override; - int getNbParticipants () const override; + int getParticipantCount () const override; const std::list> &getParticipants () const override; void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) override; diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index cb16dfd7c..0b0a8e8bf 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -122,7 +122,7 @@ shared_ptr ServerGroupChatRoom::getMe () const { return nullptr; } -int ServerGroupChatRoom::getNbParticipants () const { +int ServerGroupChatRoom::getParticipantCount () const { return 0; } diff --git a/src/chat/chat-room/server-group-chat-room.h b/src/chat/chat-room/server-group-chat-room.h index 8dec5ee67..d70442513 100644 --- a/src/chat/chat-room/server-group-chat-room.h +++ b/src/chat/chat-room/server-group-chat-room.h @@ -64,7 +64,7 @@ public: std::shared_ptr findParticipant (const IdentityAddress &addr) const override; std::shared_ptr getMe () const override; - int getNbParticipants () const override; + int getParticipantCount () const override; const std::list> &getParticipants () const override; void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) override; diff --git a/src/conference/conference-interface.h b/src/conference/conference-interface.h index db6b505c9..f7b8fd829 100644 --- a/src/conference/conference-interface.h +++ b/src/conference/conference-interface.h @@ -43,7 +43,7 @@ public: virtual std::shared_ptr findParticipant (const IdentityAddress &addr) const = 0; virtual const IdentityAddress &getConferenceAddress () const = 0; virtual std::shared_ptr getMe () const = 0; - virtual int getNbParticipants () const = 0; + virtual int getParticipantCount () const = 0; virtual const std::list> &getParticipants () const = 0; virtual const std::string &getSubject () const = 0; virtual void join () = 0; diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 15424caef..5d50eaa6f 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -83,7 +83,7 @@ shared_ptr Conference::getMe () const { return d->me; } -int Conference::getNbParticipants () const { +int Conference::getParticipantCount () const { L_D(); return static_cast(d->participants.size()); } diff --git a/src/conference/conference.h b/src/conference/conference.h index de8e29de4..2db432305 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -54,7 +54,7 @@ public: std::shared_ptr findParticipant (const IdentityAddress &addr) const override; const IdentityAddress &getConferenceAddress () const override; std::shared_ptr getMe () const override; - int getNbParticipants () const override; + int getParticipantCount () const override; const std::list> &getParticipants () const override; const std::string &getSubject () const override; void join () override; diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 3c86e1f03..bf75776d8 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -135,7 +135,7 @@ shared_ptr Core::findOneToOneChatRoom ( L_D(); for (const auto &chatRoom : d->chatRooms) { if ( - chatRoom->getNbParticipants() == 1 && + chatRoom->getParticipantCount() == 1 && chatRoom->getLocalAddress() == localAddress && participantAddress == chatRoom->getParticipants().front()->getAddress() ) From b366b4055aebca3efeee69b4acd2de645625038f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 4 Dec 2017 16:15:30 +0100 Subject: [PATCH 0971/2215] Updated proguard rules --- wrappers/java/proguard.mustache | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wrappers/java/proguard.mustache b/wrappers/java/proguard.mustache index 6bb199a26..4ba8b9d44 100644 --- a/wrappers/java/proguard.mustache +++ b/wrappers/java/proguard.mustache @@ -7,6 +7,9 @@ -keep class {{package}}.{{classImplName}} {*;} {{/classes}} +# Liblinphone tools +-keep class org.linphone.core.tools.* {*;} + # Mediastreamer classes -keep class org.linphone.mediastream.Factory {*;} -keep class org.linphone.mediastream.MediastreamerAndroidContext {*;} From 203e06747b0f6d33e7918994446a153b4288cc05 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 4 Dec 2017 16:24:15 +0100 Subject: [PATCH 0972/2215] fix build --- src/db/main-db.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 4aec25d34..a7baed403 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -131,7 +131,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), // `row id` is not supported by soci on Sqlite3. It's necessary to cast id to int... return q->getBackend() == AbstractDb::Sqlite3 ? static_cast(row.get(0)) - : row.get(0); + : static_cast(row.get(0)); } long long MainDbPrivate::insertSipAddress (const string &sipAddress) { @@ -1870,10 +1870,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), tm lastUpdateTime = row.get(4); int capabilities = row.get(5); string subject = row.get(6); - unsigned int lastNotifyId = static_cast(getBackend() == Backend::Mysql + unsigned int lastNotifyId = (getBackend() == Backend::Mysql) ? row.get(7, 0) - : row.get(7, 0) - ); + : static_cast(row.get(7, 0)); if (capabilities & static_cast(ChatRoom::Capabilities::Basic)) { chatRoom = core->getPrivate()->createBasicChatRoom( From 04e028c74f9c293f5e343c9c1f0643e9ab44065f Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 4 Dec 2017 16:56:27 +0100 Subject: [PATCH 0973/2215] create event when creating notify --- .../local-conference-event-handler-p.h | 3 + .../local-conference-event-handler.cpp | 67 +++++++++++++++++-- .../handlers/local-conference-event-handler.h | 21 ++++-- 3 files changed, 77 insertions(+), 14 deletions(-) diff --git a/src/conference/handlers/local-conference-event-handler-p.h b/src/conference/handlers/local-conference-event-handler-p.h index e5822c9a9..24f65b2cc 100644 --- a/src/conference/handlers/local-conference-event-handler-p.h +++ b/src/conference/handlers/local-conference-event-handler-p.h @@ -22,6 +22,7 @@ #include +#include "chat/chat-room/chat-room-id.h" #include "local-conference-event-handler.h" #include "object/object-p.h" #include "xml/conference-info.h" @@ -48,6 +49,8 @@ public: inline unsigned int getLastNotify () const { return lastNotify; }; private: + ChatRoomId chatRoomId; + LocalConference *conf = nullptr; unsigned int lastNotify = 0; diff --git a/src/conference/handlers/local-conference-event-handler.cpp b/src/conference/handlers/local-conference-event-handler.cpp index f705a59fe..ee391c3e9 100644 --- a/src/conference/handlers/local-conference-event-handler.cpp +++ b/src/conference/handlers/local-conference-event-handler.cpp @@ -21,7 +21,6 @@ #include "linphone/utils/utils.h" -#include "chat/chat-room/chat-room-id.h" #include "conference/local-conference.h" #include "conference/participant-p.h" #include "content/content-manager.h" @@ -397,36 +396,85 @@ void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) { device->setConferenceSubscribeEvent(nullptr); } -void LocalConferenceEventHandler::notifyParticipantAdded (const Address &addr) { +shared_ptr LocalConferenceEventHandler::notifyParticipantAdded (const Address &addr) { L_D(); shared_ptr participant = d->conf->findParticipant(addr); d->notifyAllExcept(d->createNotifyParticipantAdded(addr), participant); + shared_ptr event = make_shared( + EventLog::Type::ConferenceParticipantAdded, + time(nullptr), + d->chatRoomId, + d->lastNotify, + addr + ); + return event; } -void LocalConferenceEventHandler::notifyParticipantRemoved (const Address &addr) { +shared_ptr LocalConferenceEventHandler::notifyParticipantRemoved (const Address &addr) { L_D(); shared_ptr participant = d->conf->findParticipant(addr); d->notifyAllExcept(d->createNotifyParticipantRemoved(addr), participant); + shared_ptr event = make_shared( + EventLog::Type::ConferenceParticipantRemoved, + time(nullptr), + d->chatRoomId, + d->lastNotify, + addr + ); + return event; } -void LocalConferenceEventHandler::notifyParticipantSetAdmin (const Address &addr, bool isAdmin) { +shared_ptr LocalConferenceEventHandler::notifyParticipantSetAdmin (const Address &addr, bool isAdmin) { L_D(); d->notifyAll(d->createNotifyParticipantAdmined(addr, isAdmin)); + shared_ptr event = make_shared( + isAdmin ? EventLog::Type::ConferenceParticipantSetAdmin : EventLog::Type::ConferenceParticipantUnsetAdmin, + time(nullptr), + d->chatRoomId, + d->lastNotify, + addr + ); + return event; } -void LocalConferenceEventHandler::notifySubjectChanged () { +shared_ptr LocalConferenceEventHandler::notifySubjectChanged () { L_D(); d->notifyAll(d->createNotifySubjectChanged()); + shared_ptr event = make_shared( + time(nullptr), + d->chatRoomId, + d->lastNotify, + d->conf->getSubject() + ); + return event; } -void LocalConferenceEventHandler::notifyParticipantDeviceAdded (const Address &addr, const Address &gruu) { +shared_ptr LocalConferenceEventHandler::notifyParticipantDeviceAdded (const Address &addr, const Address &gruu) { L_D(); d->notifyAll(d->createNotifyParticipantDeviceAdded(addr, gruu)); + shared_ptr event = make_shared( + EventLog::Type::ConferenceParticipantDeviceAdded, + time(nullptr), + d->chatRoomId, + d->lastNotify, + addr, + gruu + ); + return event; } -void LocalConferenceEventHandler::notifyParticipantDeviceRemoved (const Address &addr, const Address &gruu) { +shared_ptr LocalConferenceEventHandler::notifyParticipantDeviceRemoved (const Address &addr, const Address &gruu) { L_D(); d->notifyAll(d->createNotifyParticipantDeviceRemoved(addr, gruu)); + shared_ptr event = make_shared( + EventLog::Type::ConferenceParticipantDeviceRemoved, + time(nullptr), + d->chatRoomId, + d->lastNotify, + addr, + gruu + ); + return event; } void LocalConferenceEventHandler::setLastNotify (unsigned int lastNotify) { @@ -434,4 +482,9 @@ void LocalConferenceEventHandler::setLastNotify (unsigned int lastNotify) { d->lastNotify = lastNotify; } +void LocalConferenceEventHandler::setChatRoomId (const ChatRoomId &chatRoomId) { + L_D(); + d->chatRoomId = chatRoomId; +} + LINPHONE_END_NAMESPACE diff --git a/src/conference/handlers/local-conference-event-handler.h b/src/conference/handlers/local-conference-event-handler.h index 04f45632c..3e6aef9b1 100644 --- a/src/conference/handlers/local-conference-event-handler.h +++ b/src/conference/handlers/local-conference-event-handler.h @@ -20,6 +20,8 @@ #ifndef _LOCAL_CONFERENCE_EVENT_HANDLER_H_ #define _LOCAL_CONFERENCE_EVENT_HANDLER_H_ +#include + #include "linphone/types.h" #include "address/address.h" @@ -30,6 +32,10 @@ LINPHONE_BEGIN_NAMESPACE +class ChatRoomId; +class ConferenceParticipantDeviceEvent; +class ConferenceParticipantEvent; +class ConferenceSubjectEvent; class LocalConference; class LocalConferenceEventHandlerPrivate; @@ -39,14 +45,15 @@ public: ~LocalConferenceEventHandler (); void subscribeReceived (LinphoneEvent *lev); - void notifyParticipantAdded (const Address &addr); - void notifyParticipantRemoved (const Address &addr); - void notifyParticipantSetAdmin (const Address &addr, bool isAdmin); - void notifySubjectChanged (); - void notifyParticipantDeviceAdded (const Address &addr, const Address &gruu); - void notifyParticipantDeviceRemoved (const Address &addr, const Address &gruu); - + std::shared_ptr notifyParticipantAdded (const Address &addr); + std::shared_ptr notifyParticipantRemoved (const Address &addr); + std::shared_ptr notifyParticipantSetAdmin (const Address &addr, bool isAdmin); + std::shared_ptr notifySubjectChanged (); + std::shared_ptr notifyParticipantDeviceAdded (const Address &addr, const Address &gruu); + std::shared_ptr notifyParticipantDeviceRemoved (const Address &addr, const Address &gruu); + void setLastNotify (unsigned int lastNotify); + void setChatRoomId (const ChatRoomId &chatRoomId); private: L_DECLARE_PRIVATE(LocalConferenceEventHandler); From 8783aca2db07286c1033b4b6d233ea0e3527ce5d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 4 Dec 2017 16:59:03 +0100 Subject: [PATCH 0974/2215] No longer need cCore property in Core C++ object. --- src/chat/chat-room/chat-room.cpp | 4 ++-- src/chat/chat-room/real-time-text-chat-room.cpp | 2 +- src/core/core-chat-room.cpp | 9 +++------ src/core/core-p.h | 1 - 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index b5b5c55df..516a35aa8 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -163,13 +163,13 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa if (msg->getPrivate()->getContentType() == ContentType::ImIsComposing) { isComposingReceived(msg->getFromAddress(), msg->getPrivate()->getText()); increaseMsgCount = FALSE; - if (lp_config_get_int(cCore->config, "sip", "deliver_imdn", 0) != 1) { + if (lp_config_get_int(linphone_core_get_config(cCore), "sip", "deliver_imdn", 0) != 1) { goto end; } } else if (msg->getPrivate()->getContentType() == ContentType::Imdn) { imdnReceived(msg->getPrivate()->getText()); increaseMsgCount = FALSE; - if (lp_config_get_int(cCore->config, "sip", "deliver_imdn", 0) != 1) { + if (lp_config_get_int(linphone_core_get_config(cCore), "sip", "deliver_imdn", 0) != 1) { goto end; } } diff --git a/src/chat/chat-room/real-time-text-chat-room.cpp b/src/chat/chat-room/real-time-text-chat-room.cpp index 2f3d7a853..1a8dde51d 100644 --- a/src/chat/chat-room/real-time-text-chat-room.cpp +++ b/src/chat/chat-room/real-time-text-chat-room.cpp @@ -76,7 +76,7 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp pendingMessage->getPrivate()->setState(ChatMessage::State::Delivered); pendingMessage->getPrivate()->setDirection(ChatMessage::Direction::Incoming); - if (lp_config_get_int(cCore->config, "misc", "store_rtt_messages", 1) == 1) + if (lp_config_get_int(linphone_core_get_config(cCore), "misc", "store_rtt_messages", 1) == 1) pendingMessage->getPrivate()->store(); chatMessageReceived(pendingMessage); diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index bf75776d8..164be345d 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -145,11 +145,10 @@ shared_ptr Core::findOneToOneChatRoom ( } shared_ptr Core::createClientGroupChatRoom (const string &subject) { - L_D(); return L_GET_CPP_PTR_FROM_C_OBJECT( _linphone_client_group_chat_room_new( - d->cCore, - linphone_core_get_conference_factory_uri(d->cCore), + getCCore(), + linphone_core_get_conference_factory_uri(getCCore()), L_STRING_TO_C(subject) ) ); @@ -187,9 +186,7 @@ shared_ptr Core::getOrCreateBasicChatRoom (const IdentityAddress &peer } shared_ptr Core::getOrCreateBasicChatRoomFromUri (const string &peerAddress, bool isRtt) { - L_D(); - - LinphoneAddress *address = linphone_core_interpret_url(d->cCore, L_STRING_TO_C(peerAddress)); + LinphoneAddress *address = linphone_core_interpret_url(getCCore(), L_STRING_TO_C(peerAddress)); if (!address) { lError() << "Cannot make a valid address with: `" << peerAddress << "`."; return nullptr; diff --git a/src/core/core-p.h b/src/core/core-p.h index 3b79cbf58..d5cec3542 100644 --- a/src/core/core-p.h +++ b/src/core/core-p.h @@ -48,7 +48,6 @@ public: std::shared_ptr createBasicChatRoom (const ChatRoomId &chatRoomId, bool isRtt); std::unique_ptr mainDb; - LinphoneCore *cCore = nullptr; private: std::list> calls; From 784154c21e0b83847a6275eed9b2b9153d69500a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 4 Dec 2017 17:10:46 +0100 Subject: [PATCH 0975/2215] Rename getCallsNb() to getCallCount(). --- coreapi/linphonecore.c | 2 +- src/conference/session/media-session.cpp | 2 +- src/core/core-call.cpp | 4 ++-- src/core/core.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1308ff063..0cc6b5c37 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -6234,7 +6234,7 @@ void linphone_core_destroy(LinphoneCore *lc){ } int linphone_core_get_calls_nb(const LinphoneCore *lc) { - return (int)L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getCallsNb(); + return (int)L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getCallCount(); } void linphone_core_soundcard_hint_check(LinphoneCore* lc) { diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 2257b88b6..59a7accc3 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -3210,7 +3210,7 @@ void MediaSessionPrivate::updateStreams (SalMediaDescription *newMd, LinphoneCal if (getParams()->earlyMediaSendingEnabled() && (state == LinphoneCallOutgoingEarlyMedia)) prepareEarlyMediaForking(); startStreams(targetState); - if ((state == LinphoneCallPausing) && pausedByApp && (q->getCore()->getCallsNb() == 1)) + if ((state == LinphoneCallPausing) && pausedByApp && (q->getCore()->getCallCount() == 1)) linphone_core_play_named_tone(q->getCore()->getCCore(), LinphoneToneCallOnHold); updateFrozenPayloads(newMd); diff --git a/src/core/core-call.cpp b/src/core/core-call.cpp index 918faf9ca..3dd816c73 100644 --- a/src/core/core-call.cpp +++ b/src/core/core-call.cpp @@ -60,7 +60,7 @@ void CorePrivate::iterateCalls (time_t currentRealTime, bool oneSecondElapsed) c bool CorePrivate::canWeAddCall () const { L_Q(); - if (q->getCallsNb() < static_cast(q->getCCore()->max_calls)) + if (q->getCallCount() < static_cast(q->getCCore()->max_calls)) return true; lInfo() << "Maximum amount of simultaneous calls reached!"; return false; @@ -137,7 +137,7 @@ const list> &Core::getCalls () const { return d->calls; } -unsigned int Core::getCallsNb () const { +unsigned int Core::getCallCount () const { L_D(); return static_cast(d->calls.size()); } diff --git a/src/core/core.h b/src/core/core.h index b74330ac6..d3f3f395c 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -73,7 +73,7 @@ public: bool areSoundResourcesLocked () const; std::shared_ptr getCallByRemoteAddress (const Address &addr) const; const std::list> &getCalls () const; - unsigned int getCallsNb () const; + unsigned int getCallCount () const; std::shared_ptr getCurrentCall () const; LinphoneStatus pauseAllCalls (); void soundcardHintCheck (); From 979082687f22dd787d5ebaab11b5b72ad9f1281a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 4 Dec 2017 17:23:23 +0100 Subject: [PATCH 0976/2215] Auto generate Core callbacks in JNI wrapper for core constructor --- wrappers/java/genwrapper.py | 4 ++++ wrappers/java/jni.mustache | 37 ++++--------------------------------- 2 files changed, 8 insertions(+), 33 deletions(-) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index c68127c11..5efe73c1f 100755 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -715,6 +715,7 @@ class Jni(object): self.methods = [] self.jni_package = '' self.jni_path = '' + self.coreListener = [] package_dirs = package.split('.') for directory in package_dirs: self.jni_package += directory + '_' @@ -757,6 +758,9 @@ class Jni(object): } for callback in jniInterface.callbacks: interface['callbacksList'].append(callback) + print obj['className'] + if obj['className'] == 'Core': + self.coreListener.append(callback) self.interfaces.append(interface) def add_callbacks(self, name, callbacks): diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache index b79d18361..37178976f 100644 --- a/wrappers/java/jni.mustache +++ b/wrappers/java/jni.mustache @@ -374,39 +374,10 @@ jobject Java_{{jni_package}}FactoryImpl_createCore(JNIEnv *env, jobject thiz, jo LinphoneCore *core = NULL; linphone_core_cbs_set_user_data(cbs, listener); - linphone_core_cbs_set_transfer_state_changed(cbs, linphone_core_on_transfer_state_changed); - linphone_core_cbs_set_chat_room_state_changed(cbs, linphone_core_on_chat_room_state_changed); - linphone_core_cbs_set_friend_list_created(cbs, linphone_core_on_friend_list_created); - linphone_core_cbs_set_subscription_state_changed(cbs, linphone_core_on_subscription_state_changed); - linphone_core_cbs_set_call_log_updated(cbs, linphone_core_on_call_log_updated); - linphone_core_cbs_set_call_state_changed(cbs, linphone_core_on_call_state_changed); - linphone_core_cbs_set_authentication_requested(cbs, linphone_core_on_authentication_requested); - linphone_core_cbs_set_notify_presence_received_for_uri_or_tel(cbs, linphone_core_on_notify_presence_received_for_uri_or_tel); - linphone_core_cbs_set_buddy_info_updated(cbs, linphone_core_on_buddy_info_updated); - linphone_core_cbs_set_network_reachable(cbs, linphone_core_on_network_reachable); - linphone_core_cbs_set_notify_received(cbs, linphone_core_on_notify_received); - linphone_core_cbs_set_new_subscription_requested(cbs, linphone_core_on_new_subscription_requested); - linphone_core_cbs_set_registration_state_changed(cbs, linphone_core_on_registration_state_changed); - linphone_core_cbs_set_notify_presence_received(cbs, linphone_core_on_notify_presence_received); - linphone_core_cbs_set_ec_calibration_audio_init(cbs, linphone_core_on_ec_calibration_audio_init); - linphone_core_cbs_set_message_received(cbs, linphone_core_on_message_received); - linphone_core_cbs_set_ec_calibration_result(cbs, linphone_core_on_ec_calibration_result); - linphone_core_cbs_set_info_received(cbs, linphone_core_on_info_received); - linphone_core_cbs_set_call_stats_updated(cbs, linphone_core_on_call_stats_updated); - linphone_core_cbs_set_friend_list_removed(cbs, linphone_core_on_friend_list_removed); - linphone_core_cbs_set_refer_received(cbs, linphone_core_on_refer_received); - linphone_core_cbs_set_configuring_status(cbs, linphone_core_on_configuring_status); - linphone_core_cbs_set_call_created(cbs, linphone_core_on_call_created); - linphone_core_cbs_set_publish_state_changed(cbs, linphone_core_on_publish_state_changed); - linphone_core_cbs_set_call_encryption_changed(cbs, linphone_core_on_call_encryption_changed); - linphone_core_cbs_set_is_composing_received(cbs, linphone_core_on_is_composing_received); - linphone_core_cbs_set_message_received_unable_decrypt(cbs, linphone_core_on_message_received_unable_decrypt); - linphone_core_cbs_set_log_collection_upload_progress_indication(cbs, linphone_core_on_log_collection_upload_progress_indication); - linphone_core_cbs_set_version_update_check_result_received(cbs, linphone_core_on_version_update_check_result_received); - linphone_core_cbs_set_ec_calibration_audio_uninit(cbs, linphone_core_on_ec_calibration_audio_uninit); - linphone_core_cbs_set_global_state_changed(cbs, linphone_core_on_global_state_changed); - linphone_core_cbs_set_log_collection_upload_state_changed(cbs, linphone_core_on_log_collection_upload_state_changed); - linphone_core_cbs_set_dtmf_received(cbs, linphone_core_on_dtmf_received); + + {{#coreListener}} + linphone_core_cbs_set_{{callback}}(cbs, {{callbackName}}); + {{/coreListener}} core = linphone_factory_create_core_2(linphone_factory_get(), cbs, config_path, factory_config_path, NULL, (void *)jcontext); From 2c9dfd6ca82191a977a1690a66ad3409b6439731 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 4 Dec 2017 17:38:30 +0100 Subject: [PATCH 0977/2215] Add friend class. --- src/core/core.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/core.h b/src/core/core.h index d3f3f395c..76f6ccb2f 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -49,6 +49,7 @@ class LINPHONE_PUBLIC Core : public Object { friend class MainDb; friend class MainDbChatMessageKey; friend class MainDbEventKey; + friend class ServerGroupChatRoom; friend class ServerGroupChatRoomPrivate; public: From 7bb67214006c9bf6046f67757d6618b6c794b41a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 5 Dec 2017 10:38:58 +0100 Subject: [PATCH 0978/2215] Remove contents and insert them again until update algorithm is done --- src/db/main-db-p.h | 1 + src/db/main-db.cpp | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index d4c90cfd6..49a91299f 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -53,6 +53,7 @@ private: long long insertSipAddress (const std::string &sipAddress); void insertContent (long long messageEventId, const Content &content); void updateContent (long long messageEventId, long long messageContentId, const Content &content); + void removeContentsForChatMessageEvent (long long messageEventId); long long insertContentType (const std::string &contentType); long long insertBasicChatRoom ( long long peerSipAddressId, diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index a7baed403..6bcff9775 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -187,6 +187,18 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::use(appData.first), soci::use(appData.second), soci::use(messageContentId); } + void MainDbPrivate::removeContentsForChatMessageEvent (long long eventId) { + soci::session *session = dbSession.getBackendSession(); + + *session << "DELETE FROM chat_message_content WHERE event_id=:eventId", soci::use(eventId); + + //TODO: remove file content if exists + //*session << "DELETE FROM chat_message_file_content WHERE chat_message_content_id=:messageContentId", soci::use(messageContentId); + + //TODO: remove contents' app_data + //*session << "DELETE FROM chat_message_content_app_data WHERE chat_message_content_id=:messageContentId", soci::use(messageContentId); + } + long long MainDbPrivate::insertContentType (const string &contentType) { L_Q(); soci::session *session = dbSession.getBackendSession(); @@ -704,9 +716,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), *session << "UPDATE conference_chat_message_event SET state = :state WHERE event_id = :eventId", soci::use(state), soci::use(eventId); - /*for (const Content *content : chatMessage->getContents()) - updateContent(eventId, *content);*/ - //TODO check if content needs to be inserted, updated or removed + //TODO: improve + removeContentsForChatMessageEvent(eventId); + for (const Content *content : chatMessage->getContents()) + insertContent(eventId, *content); } long long MainDbPrivate::insertConferenceNotifiedEvent (const shared_ptr &eventLog, long long *chatRoomId) { From e045ac0127f7f7c2632ca1703e31d28b256cadf9 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 5 Dec 2017 10:51:54 +0100 Subject: [PATCH 0979/2215] fix fetch of client group chat room --- src/db/main-db.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 6bcff9775..7c0a3abc0 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1909,7 +1909,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), shared_ptr participant = make_shared(IdentityAddress(row.get(0))); participant->getPrivate()->setAdmin(!!row.get(1)); - if (participant->getAddress() == chatRoomId.getLocalAddress()) + if (participant->getAddress() == chatRoomId.getLocalAddress().getAddressWithoutGruu()) me = participant; else participants.push_back(participant); From f04c4a40e137b6ce8cb052f76e93164e5a1586df Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 5 Dec 2017 11:23:44 +0100 Subject: [PATCH 0980/2215] Fix old chat_message_set_app_data api --- src/chat/chat-message/chat-message.cpp | 5 +++-- src/object/app-data-container.cpp | 5 +++-- src/object/app-data-container.h | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 25f63b6cf..91a5f897e 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -188,7 +188,7 @@ const string &ChatMessagePrivate::getAppdata () const { for (const Content *c : contents) { if (c->getContentType().isFile()) { FileContent *fileContent = (FileContent *)c; - return fileContent->getFilePath(); + return fileContent->getAppData("app"); } } return Utils::getEmptyConstRefObject(); @@ -198,7 +198,8 @@ void ChatMessagePrivate::setAppdata (const string &data) { for (const Content *c : contents) { if (c->getContentType().isFile()) { FileContent *fileContent = (FileContent *)c; - return fileContent->setFilePath(data); + fileContent->setAppData("app", data); + break; } } } diff --git a/src/object/app-data-container.cpp b/src/object/app-data-container.cpp index 2f26bc886..297a4f37a 100644 --- a/src/object/app-data-container.cpp +++ b/src/object/app-data-container.cpp @@ -19,6 +19,7 @@ #include +#include "linphone/utils/utils.h" #include "app-data-container.h" // ============================================================================= @@ -62,10 +63,10 @@ const unordered_map &AppDataContainer::getAppDataMap () const { return *d->appData.get(); } -string AppDataContainer::getAppData (const string &name) const { +const string &AppDataContainer::getAppData (const string &name) const { L_D(); auto it = d->appData->find(name); - return it == d->appData->cend() ? string() : it->second; + return it == d->appData->cend() ? Utils::getEmptyConstRefObject() : d->appData->at(name); } void AppDataContainer::setAppData (const string &name, const string &appData) { diff --git a/src/object/app-data-container.h b/src/object/app-data-container.h index 90e2e416e..dec48042c 100644 --- a/src/object/app-data-container.h +++ b/src/object/app-data-container.h @@ -41,7 +41,7 @@ public: const std::unordered_map &getAppDataMap () const; - std::string getAppData (const std::string &name) const; + const std::string &getAppData (const std::string &name) const; void setAppData (const std::string &name, const std::string &appData); void setAppData (const std::string &name, std::string &&appData); From b8b82f7fdb432a3270a73b093ff3448722788e86 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 5 Dec 2017 11:51:37 +0100 Subject: [PATCH 0981/2215] keep fixing fetch of chat room --- src/chat/chat-room/client-group-chat-room.cpp | 5 +++-- src/chat/chat-room/client-group-chat-room.h | 2 +- src/db/main-db.cpp | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index 508853d53..c34281ad4 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -99,15 +99,16 @@ RemoteConference(core, me, nullptr) { ClientGroupChatRoom::ClientGroupChatRoom ( const shared_ptr &core, - const IdentityAddress &peerAddress, + const ChatRoomId &chatRoomId, shared_ptr &me, const string &subject, list> &&participants, unsigned int lastNotifyId -) : ChatRoom(*new ClientGroupChatRoomPrivate, core, ChatRoomId(peerAddress, me->getAddress())), +) : ChatRoom(*new ClientGroupChatRoomPrivate, core, chatRoomId), RemoteConference(core, me->getAddress(), nullptr) { L_D_T(RemoteConference, dConference); + const IdentityAddress &peerAddress = chatRoomId.getPeerAddress(); dConference->focus = make_shared(peerAddress); dConference->conferenceAddress = peerAddress; dConference->subject = subject; diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 8513633ea..2734772ea 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -41,7 +41,7 @@ public: ClientGroupChatRoom ( const std::shared_ptr &core, - const IdentityAddress &peerAddress, + const ChatRoomId &chatRoomId, std::shared_ptr &me, const std::string &subject, std::list> &&participants, diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 7c0a3abc0..f5157904a 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -191,7 +191,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); *session << "DELETE FROM chat_message_content WHERE event_id=:eventId", soci::use(eventId); - + //TODO: remove file content if exists //*session << "DELETE FROM chat_message_file_content WHERE chat_message_content_id=:messageContentId", soci::use(messageContentId); @@ -1924,7 +1924,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } chatRoom = make_shared( core, - chatRoomId.getPeerAddress(), + chatRoomId, me, subject, move(participants), From 385aeb3357513bdc7d92dcb03a194036854be629 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 5 Dec 2017 11:55:54 +0100 Subject: [PATCH 0982/2215] Added fetch contents' app data from db --- src/db/main-db.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index f5157904a..f7c59dc57 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -487,13 +487,13 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::rowset rows = (session->prepare << query, soci::use(eventId)); for (const auto &row : rows) { ContentType contentType(row.get(2)); + const long long &contentId = resolveId(row, 0); Content *content; if (contentType == ContentType::FileTransfer) content = new FileTransferContent(); else if (contentType.isFile()) { - const long long &contentId = resolveId(row, 0); - + // 2.1 - Fetch contents' file informations. string name; int size; string path; @@ -511,6 +511,16 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } else content = new Content(); + // 2.2 - Fetch contents' app data. + static const string content_app_data_query = "SELECT name, data FROM chat_message_content_app_data" + " WHERE chat_message_content_id = :messageContentId"; + soci::rowset content_app_data_rows = (session->prepare << content_app_data_query, soci::use(contentId)); + for (const auto &content_app_data_row : content_app_data_rows) { + string content_app_data_name(content_app_data_row.get(0)); + string content_app_data_value(content_app_data_row.get(1)); + content->setAppData(content_app_data_name, content_app_data_value); + } + content->setContentType(contentType); content->setBody(row.get(3)); chatMessage->addContent(*content); From c865794cac09744fa336a5876108b76bafe48749 Mon Sep 17 00:00:00 2001 From: Erwan Croze Date: Tue, 5 Dec 2017 13:50:15 +0100 Subject: [PATCH 0983/2215] Disable message storage on server side --- src/chat/chat-message/chat-message.cpp | 3 +++ src/chat/chat-room/chat-room.cpp | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 91a5f897e..451f5c78d 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -569,6 +569,9 @@ void ChatMessagePrivate::send () { void ChatMessagePrivate::store() { L_Q(); + // TODO: store message in the future + if (linphone_core_conference_server_enabled(q->getCore()->getCCore())) return; + bool messageToBeStored = false; for (Content *c : contents) { ContentType contentType = c->getContentType(); diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 516a35aa8..25f7500d2 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -106,12 +106,13 @@ void ChatRoomPrivate::sendMessage (const shared_ptr &msg) { LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAddedCb cb = linphone_chat_room_cbs_get_chat_message_sent(cbs); - if (cb) { + // TODO: server currently don't stock message, remove condition in the future + if (cb && !linphone_core_conference_server_enabled(q->getCore()->getCCore())) { shared_ptr event = static_pointer_cast( q->getCore()->getPrivate()->mainDb->getEventFromKey(dChatMessage->dbKey) ); if (!event) - event = make_shared(msg->getTime(), msg); + event = make_shared(time(nullptr), msg); cb(cr, L_GET_C_BACK_PTR(event)); } @@ -200,7 +201,7 @@ void ChatRoomPrivate::chatMessageReceived (const shared_ptr &msg) { LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsParticipantAddedCb cb = linphone_chat_room_cbs_get_chat_message_received(cbs); - shared_ptr event = make_shared(msg->getTime(), msg); + shared_ptr event = make_shared(time(nullptr), msg); if (cb) { cb(cr, L_GET_C_BACK_PTR(event)); } From c91dc4b5ef8a024e857dcadb802620ccb3e8a917 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 5 Dec 2017 13:55:44 +0100 Subject: [PATCH 0984/2215] fix crash in file transfer --- src/chat/chat-message/chat-message.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 451f5c78d..79ad05fd6 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -538,13 +538,17 @@ void ChatMessagePrivate::send () { } else msgOp->send_message(ContentType::PlainText.asString().c_str(), internalContent.getBodyAsString().c_str()); - for (Content *content : contents) { - // Restore FileContents and remove FileTransferContents + // Restore FileContents and remove FileTransferContents + list::iterator i = contents.begin(); + while (i != contents.end()) { + Content *content = *i; if (content->getContentType() == ContentType::FileTransfer) { FileTransferContent *fileTransferContent = (FileTransferContent *)content; - q->removeContent(*content); + contents.erase(i++); q->addContent(*fileTransferContent->getFileContent()); delete fileTransferContent; + } else { + ++i; } } From 4141af833ca6149660501655925d1227d6027698 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 5 Dec 2017 14:48:53 +0100 Subject: [PATCH 0985/2215] Do not add me on serverGroupChatRoom --- src/db/main-db.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index f7c59dc57..62a463c5d 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -272,8 +272,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), if (!chatRoom->canHandleParticipants()) return id; - shared_ptr me = chatRoom->getMe(); - insertChatRoomParticipant(id, insertSipAddress(me->getAddress().asString()), me->isAdmin()); + // Do not add 'me' when creating a server-group-chat-room. + if (chatRoomId.getLocalAddress() != chatRoomId.getPeerAddress()) { + shared_ptr me = chatRoom->getMe(); + insertChatRoomParticipant(id, insertSipAddress(me->getAddress().asString()), me->isAdmin()); + } + for (const auto &participant : chatRoom->getParticipants()) insertChatRoomParticipant(id, insertSipAddress(participant->getAddress().asString()), participant->isAdmin()); From 44de3832bbda7b21489742edacdbcc2918888fc8 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 5 Dec 2017 15:13:20 +0100 Subject: [PATCH 0986/2215] fix(MainDb): do not use snake case --- src/db/main-db.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 62a463c5d..96b84bf36 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -516,14 +516,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), content = new Content(); // 2.2 - Fetch contents' app data. - static const string content_app_data_query = "SELECT name, data FROM chat_message_content_app_data" - " WHERE chat_message_content_id = :messageContentId"; - soci::rowset content_app_data_rows = (session->prepare << content_app_data_query, soci::use(contentId)); - for (const auto &content_app_data_row : content_app_data_rows) { - string content_app_data_name(content_app_data_row.get(0)); - string content_app_data_value(content_app_data_row.get(1)); - content->setAppData(content_app_data_name, content_app_data_value); - } + static const string query = "SELECT name, data FROM chat_message_content_app_data" + " WHERE chat_message_content_id = :contentId"; + soci::rowset rows = (session->prepare << query, soci::use(contentId)); + for (const auto &row : rows) + content->setAppData(row.get(0), row.get(1)); content->setContentType(contentType); content->setBody(row.get(3)); From 56fa68ee4fd4d85ffa73e39a01025edaba9962ac Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 5 Dec 2017 15:17:09 +0100 Subject: [PATCH 0987/2215] fix(AppDataContainer): use iterator in get app data, (at => poor performance) --- src/object/app-data-container.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/object/app-data-container.cpp b/src/object/app-data-container.cpp index 297a4f37a..d5bfce7da 100644 --- a/src/object/app-data-container.cpp +++ b/src/object/app-data-container.cpp @@ -66,7 +66,7 @@ const unordered_map &AppDataContainer::getAppDataMap () const { const string &AppDataContainer::getAppData (const string &name) const { L_D(); auto it = d->appData->find(name); - return it == d->appData->cend() ? Utils::getEmptyConstRefObject() : d->appData->at(name); + return it == d->appData->cend() ? Utils::getEmptyConstRefObject() : it->second; } void AppDataContainer::setAppData (const string &name, const string &appData) { From 72c20adc17c0859c0cfb56ae1604a6e66fddabda Mon Sep 17 00:00:00 2001 From: Erwan Croze Date: Tue, 5 Dec 2017 15:18:51 +0100 Subject: [PATCH 0988/2215] Replace DATE by TIMESTAMP in main-db for db --- src/db/main-db.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 96b84bf36..5fd2337fa 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -912,7 +912,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), "CREATE TABLE IF NOT EXISTS event (" " id" + primaryKeyStr("BIGINT UNSIGNED") + "," " type TINYINT UNSIGNED NOT NULL," - " creation_time DATE NOT NULL" + " creation_time TIMESTAMP NOT NULL" ") " + charset; *session << @@ -925,10 +925,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " local_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," // Dialog creation time. - " creation_time DATE NOT NULL," + " creation_time TIMESTAMP NOT NULL," // Last event time (call, message...). - " last_update_time DATE NOT NULL," + " last_update_time TIMESTAMP NOT NULL," // ConferenceChatRoom, BasicChatRoom, RTT... " capabilities TINYINT UNSIGNED NOT NULL," @@ -1055,7 +1055,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " from_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," " to_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," - " time DATE," + " time TIMESTAMP," // See: https://tools.ietf.org/html/rfc5438#section-6.3 " imdn_message_id VARCHAR(255) NOT NULL," From 8f1ee5a06de87b4e0cb017296d8d4f6088189e5b Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 5 Dec 2017 15:24:14 +0100 Subject: [PATCH 0989/2215] fix(ChatMessage): use "legacy" key instead of "app" for content app data --- src/chat/chat-message/chat-message.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 79ad05fd6..b321c6fa2 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -188,7 +188,7 @@ const string &ChatMessagePrivate::getAppdata () const { for (const Content *c : contents) { if (c->getContentType().isFile()) { FileContent *fileContent = (FileContent *)c; - return fileContent->getAppData("app"); + return fileContent->getAppData("legacy"); } } return Utils::getEmptyConstRefObject(); @@ -198,7 +198,7 @@ void ChatMessagePrivate::setAppdata (const string &data) { for (const Content *c : contents) { if (c->getContentType().isFile()) { FileContent *fileContent = (FileContent *)c; - fileContent->setAppData("app", data); + fileContent->setAppData("legacy", data); break; } } From c48f0f70b5abe32d9dfa20560ae8bf05f62c6a54 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 5 Dec 2017 15:37:05 +0100 Subject: [PATCH 0990/2215] Fixed fileTransferContent values not being set from content's body when fetched from db --- src/chat/chat-message/chat-message-p.h | 2 ++ src/chat/chat-message/chat-message.cpp | 8 +++++++- src/db/main-db.cpp | 8 ++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index f57f79cfb..2665afe0a 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -86,6 +86,8 @@ public: void removeSalCustomHeader(const std::string& name); std::string getSalCustomHeaderValue(const std::string& name); + void loadFileTransferUrlFromBodyToContent(); + // ----------------------------------------------------------------------------- // Deprecated methods only used for C wrapper, to be removed some day... // ----------------------------------------------------------------------------- diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index b321c6fa2..c75adc429 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -305,6 +305,12 @@ bool ChatMessagePrivate::downloadFile () { return false; } +void ChatMessagePrivate::loadFileTransferUrlFromBodyToContent() { + L_Q(); + int errorCode = 0; + fileTransferChatMessageModifier.decode(q->getSharedFromThis(), errorCode); +} + // ----------------------------------------------------------------------------- void ChatMessagePrivate::sendImdn (Imdn::Type imdnType, LinphoneReason reason) { @@ -375,7 +381,7 @@ LinphoneReason ChatMessagePrivate::receive () { lInfo() << "File download step already done, skipping"; } else { // This will check if internal content is FileTransfer and make the appropriate changes - fileTransferChatMessageModifier.decode(q->getSharedFromThis(), errorCode); + loadFileTransferUrlFromBodyToContent(); currentRecvStep |= ChatMessagePrivate::Step::FileUpload; } diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 5fd2337fa..d080f42ec 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -440,6 +440,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), if (!chatRoom) return nullptr; + bool hasFileTransferContent = false; + // 1 - Fetch chat message. shared_ptr chatMessage = getChatMessageFromCache(eventId); if (chatMessage) @@ -528,6 +530,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } } + // 3 - Load external body url from body into FileTransferContent if needed + if (hasFileTransferContent) { + ChatMessagePrivate *dChatMessage = chatMessage->getPrivate(); + dChatMessage->loadFileTransferUrlFromBodyToContent(); + } + cache(chatMessage, eventId); end: From 71c5088307a50a4bd424e63b27b2698381490eec Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 5 Dec 2017 15:53:55 +0100 Subject: [PATCH 0991/2215] Forgot to set hasFileTransferContent to true when fetching message from db --- src/db/main-db.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index d080f42ec..012a835eb 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -496,8 +496,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), const long long &contentId = resolveId(row, 0); Content *content; - if (contentType == ContentType::FileTransfer) + if (contentType == ContentType::FileTransfer) { + hasFileTransferContent = true; content = new FileTransferContent(); + } else if (contentType.isFile()) { // 2.1 - Fetch contents' file informations. string name; From cac63d006f69dd2f3042a03ecd6e39c6016f5cba Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 5 Dec 2017 16:24:42 +0100 Subject: [PATCH 0992/2215] Also set appData to FileTransfer contents --- src/chat/chat-message/chat-message.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index c75adc429..030e997a2 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -186,19 +186,17 @@ void ChatMessagePrivate::setFileTransferFilepath (const string &path) { const string &ChatMessagePrivate::getAppdata () const { for (const Content *c : contents) { - if (c->getContentType().isFile()) { - FileContent *fileContent = (FileContent *)c; - return fileContent->getAppData("legacy"); + if (c->getContentType().isFile() || c->getContentType() == ContentType::FileTransfer) { + return c->getAppData("legacy"); } } return Utils::getEmptyConstRefObject(); } void ChatMessagePrivate::setAppdata (const string &data) { - for (const Content *c : contents) { - if (c->getContentType().isFile()) { - FileContent *fileContent = (FileContent *)c; - fileContent->setAppData("legacy", data); + for (Content *c : contents) { + if (c->getContentType().isFile() || c->getContentType() == ContentType::FileTransfer) { + c->setAppData("legacy", data); break; } } From 36ae94cbe6e594ec8b727af765b200b543d915d3 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 5 Dec 2017 16:48:46 +0100 Subject: [PATCH 0993/2215] feat(MainDb): supports participant device insertion --- src/conference/participant-device.h | 4 +- src/conference/participant.h | 1 + src/db/main-db-p.h | 3 +- src/db/main-db.cpp | 60 +++++++++++++++++++++-------- 4 files changed, 51 insertions(+), 17 deletions(-) diff --git a/src/conference/participant-device.h b/src/conference/participant-device.h index 0190baa66..5110fe48f 100644 --- a/src/conference/participant-device.h +++ b/src/conference/participant-device.h @@ -55,8 +55,10 @@ private: IdentityAddress mGruu; std::shared_ptr mSession; LinphoneEvent *mConferenceSubscribeEvent = nullptr; + + L_DISABLE_COPY(ParticipantDevice); }; LINPHONE_END_NAMESPACE -#endif // ifndef _PARTICIPANT_DEVICE_H_ \ No newline at end of file +#endif // ifndef _PARTICIPANT_DEVICE_H_ diff --git a/src/conference/participant.h b/src/conference/participant.h index 90fce744a..4f1cbfa62 100644 --- a/src/conference/participant.h +++ b/src/conference/participant.h @@ -46,6 +46,7 @@ class Participant : public Object { friend class LocalConferenceEventHandler; friend class LocalConferenceEventHandlerPrivate; friend class MainDb; + friend class MainDbPrivate; friend class MediaSessionPrivate; friend class RemoteConference; friend class RemoteConferenceCall; diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 49a91299f..d6fe4fda6 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -61,7 +61,8 @@ private: const tm &creationTime ); long long insertChatRoom (const std::shared_ptr &chatRoom); - void insertChatRoomParticipant (long long chatRoomId, long long sipAddressId, bool isAdmin); + long long insertChatRoomParticipant (long long chatRoomId, long long sipAddressId, bool isAdmin); + void insertChatRoomParticipantDevice (long long participantId, long long sipAddressId); void insertChatMessageParticipant (long long messageEventId, long long sipAddressId, int state); long long selectSipAddressId (const std::string &sipAddress) const; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 012a835eb..f50bdaa53 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -278,28 +278,58 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), insertChatRoomParticipant(id, insertSipAddress(me->getAddress().asString()), me->isAdmin()); } - for (const auto &participant : chatRoom->getParticipants()) - insertChatRoomParticipant(id, insertSipAddress(participant->getAddress().asString()), participant->isAdmin()); + for (const auto &participant : chatRoom->getParticipants()) { + long long participantId = insertChatRoomParticipant( + id, + insertSipAddress(participant->getAddress().asString()), + participant->isAdmin() + ); + for (const auto &device : participant->getPrivate()->getDevices()) + insertChatRoomParticipantDevice(participantId, insertSipAddress(device->getAddress().asString())); + } return id; } - void MainDbPrivate::insertChatRoomParticipant (long long chatRoomId, long long sipAddressId, bool isAdmin) { - // See: https://stackoverflow.com/a/15299655 (cast to reference) + long long MainDbPrivate::insertChatRoomParticipant (long long chatRoomId, long long sipAddressId, bool isAdmin) { + L_Q(); + long long id = -1; soci::session *session = dbSession.getBackendSession(); - soci::statement statement = ( - session->prepare << "UPDATE chat_room_participant SET is_admin = :isAdmin" - " WHERE chat_room_id = :chatRoomId AND participant_sip_address_id = :sipAddressId", - soci::use(static_cast(isAdmin)), soci::use(chatRoomId), soci::use(sipAddressId) - ); - statement.execute(true); - if (statement.get_affected_rows() == 0) { - lInfo() << "Insert new chat room participant in database: `" << sipAddressId << "` (isAdmin=" << isAdmin << ")."; - *session << "INSERT INTO chat_room_participant (chat_room_id, participant_sip_address_id, is_admin)" - " VALUES (:chatRoomId, :sipAddressId, :isAdmin)", - soci::use(chatRoomId), soci::use(sipAddressId), soci::use(static_cast(isAdmin)); + *session << "SELECT id from chat_room_participant" + " WHERE chat_room_id = :chatRoomId AND participant_sip_address_id = :sipAddressId", + soci::into(id), soci::use(chatRoomId), soci::use(sipAddressId); + + if (id >= 0) { + // See: https://stackoverflow.com/a/15299655 (cast to reference) + *session << "UPDATE chat_room_participant SET is_admin = :isAdmin" + " WHERE id = :id", + soci::use(static_cast(isAdmin)), soci::use(id); + return id; } + + lInfo() << "Insert new chat room participant in database: `" << sipAddressId << "` (isAdmin=" << isAdmin << ")."; + *session << "INSERT INTO chat_room_participant (chat_room_id, participant_sip_address_id, is_admin)" + " VALUES (:chatRoomId, :sipAddressId, :isAdmin)", + soci::use(chatRoomId), soci::use(sipAddressId), soci::use(static_cast(isAdmin)); + + return q->getLastInsertId(); + } + + void MainDbPrivate::insertChatRoomParticipantDevice (long long participantId, long long sipAddressId) { + soci::session *session = dbSession.getBackendSession(); + long long count; + *session << "SELECT COUNT(*) FROM chat_room_participant_device" + " WHERE chat_room_participant_id = :participantId" + " AND participant_device_sip_address_id = :sipAddressId", + soci::into(count), soci::use(participantId), soci::use(sipAddressId); + if (count) + return; + + lInfo() << "Insert new chat room participant device in database: `" << sipAddressId << "`."; + *session << "INSERT INTO chat_room_participant_device (chat_room_participant_id, participant_device_sip_address_id)" + " VALUES (:participantId, :sipAddressId)", + soci::use(participantId), soci::use(sipAddressId); } void MainDbPrivate::insertChatMessageParticipant (long long eventId, long long sipAddressId, int state) { From 52f13d34d0d9a687a25862ee56701a287933209d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 5 Dec 2017 17:03:22 +0100 Subject: [PATCH 0994/2215] Revert "Also set appData to FileTransfer contents" This reverts commit cac63d006f69dd2f3042a03ecd6e39c6016f5cba. --- src/chat/chat-message/chat-message.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 030e997a2..c75adc429 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -186,17 +186,19 @@ void ChatMessagePrivate::setFileTransferFilepath (const string &path) { const string &ChatMessagePrivate::getAppdata () const { for (const Content *c : contents) { - if (c->getContentType().isFile() || c->getContentType() == ContentType::FileTransfer) { - return c->getAppData("legacy"); + if (c->getContentType().isFile()) { + FileContent *fileContent = (FileContent *)c; + return fileContent->getAppData("legacy"); } } return Utils::getEmptyConstRefObject(); } void ChatMessagePrivate::setAppdata (const string &data) { - for (Content *c : contents) { - if (c->getContentType().isFile() || c->getContentType() == ContentType::FileTransfer) { - c->setAppData("legacy", data); + for (const Content *c : contents) { + if (c->getContentType().isFile()) { + FileContent *fileContent = (FileContent *)c; + fileContent->setAppData("legacy", data); break; } } From 008ec55b37d1c62b0b430f3b37143c8220420208 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 5 Dec 2017 15:33:48 +0100 Subject: [PATCH 0995/2215] Handle call repair in CallSession and MediaSession classes. --- coreapi/callbacks.c | 36 +---- coreapi/linphonecore.c | 26 +--- coreapi/private_functions.h | 6 - coreapi/proxy.c | 4 +- coreapi/vtables.c | 5 + src/CMakeLists.txt | 1 + src/c-wrapper/api/c-call.cpp | 173 ---------------------- src/conference/session/call-session-p.h | 16 ++- src/conference/session/call-session.cpp | 176 ++++++++++++++++++++++- src/conference/session/call-session.h | 2 + src/conference/session/media-session-p.h | 6 + src/conference/session/media-session.cpp | 42 ++++-- src/core/core-call.cpp | 38 +++-- src/core/core-listener.h | 39 +++++ src/core/core-p.h | 15 +- src/core/core.cpp | 23 ++- src/core/core.h | 1 + src/nat/ice-agent.cpp | 6 + src/nat/ice-agent.h | 1 + src/sal/call-op.h | 1 + 20 files changed, 358 insertions(+), 259 deletions(-) create mode 100644 src/core/core-listener.h diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index d3790bdcb..28bfcbd3b 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -54,34 +54,11 @@ using namespace LinphonePrivate; static void register_failure(SalOp *op); -static LinphoneCall * look_for_broken_call_to_replace(LinphonePrivate::SalOp *h, LinphoneCore *lc) { - const bctbx_list_t *calls = linphone_core_get_calls(lc); - const bctbx_list_t *it = calls; - while (it != NULL) { -#if 0 - LinphoneCall *replaced_call = NULL; - LinphoneCall *call = (LinphoneCall *)bctbx_list_get_data(it); - SalOp *replaced_op = sal_call_get_replaces(h); - if (replaced_op) replaced_call = (LinphoneCall*)sal_op_get_user_pointer(replaced_op); - if ((call->broken && sal_call_compare_op(h, call->op)) - || ((replaced_call == call) && (strcmp(sal_op_get_from(h), sal_op_get_from(replaced_op)) == 0) && (strcmp(sal_op_get_to(h), sal_op_get_to(replaced_op)) == 0))) { - return call; - } -#endif - it = bctbx_list_next(it); - } - - return NULL; -} - static void call_received(SalCallOp *h) { /* Look if this INVITE is for a call that has already been notified but broken because of network failure */ LinphoneCore *lc = reinterpret_cast(h->get_sal()->get_user_pointer()); - LinphoneCall *replacedCall = look_for_broken_call_to_replace(h, lc); - if (replacedCall) { - linphone_call_replace_op(replacedCall, h); + if (L_GET_PRIVATE_FROM_C_OBJECT(lc)->inviteReplacesABrokenCall(h)) return; - } LinphoneAddress *fromAddr = nullptr; const char *pAssertedId = sal_custom_header_find(h->get_recv_custom_header(), "P-Asserted-Identity"); @@ -314,13 +291,12 @@ static void call_released(SalOp *op) { } static void call_cancel_done(SalOp *op) { -#if 0 - LinphoneCall *call = (LinphoneCall *)sal_op_get_user_pointer(op); - if (call->reinvite_on_cancel_response_requested == TRUE) { - call->reinvite_on_cancel_response_requested = FALSE; - linphone_call_reinvite_to_recover_from_connection_loss(call); + LinphonePrivate::CallSession *session = reinterpret_cast(op->get_user_pointer()); + if (!session) { + ms_warning("Cancel done reported on already terminated CallSession"); + return; } -#endif + L_GET_PRIVATE(session)->cancelDone(); } static void auth_failure(SalOp *op, SalAuthInfo* info) { diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 0cc6b5c37..bc45e07e2 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -6140,39 +6140,15 @@ static void set_sip_network_reachable(LinphoneCore* lc,bool_t is_sip_reachable, if (!lc->sip_network_reachable){ linphone_core_invalidate_friend_subscriptions(lc); lc->sal->reset_transports(); - /*mark all calls as broken, so that they can be either dropped immediately or restaured when network will be back*/ -#if 0 - bctbx_list_for_each(lc->calls, (MSIterateFunc) linphone_call_set_broken); -#endif } } -void linphone_core_repair_calls(LinphoneCore *lc){ -#if 0 - if (lc->calls && lp_config_get_int(lc->config, "sip", "repair_broken_calls", 1) && lc->media_network_reachable){ - /*if we are registered and there were broken calls due to a past network disconnection, attempt to repair them*/ - bctbx_list_for_each(lc->calls, (MSIterateFunc) linphone_call_repair_if_broken); - } -#endif -} - static void set_media_network_reachable(LinphoneCore* lc, bool_t is_media_reachable){ if (lc->media_network_reachable==is_media_reachable) return; // no change, ignore. ms_message("Media network reachability state is now [%s]",is_media_reachable?"UP":"DOWN"); lc->media_network_reachable=is_media_reachable; - if (!lc->media_network_reachable){ - /*mark all calls as broken, so that they can be either dropped immediately or restaured when network will be back*/ -#if 0 - bctbx_list_for_each(lc->calls, (MSIterateFunc) linphone_call_set_broken); -#endif - }else{ - if (lp_config_get_int(lc->config, "net", "recreate_sockets_when_network_is_up", 0)){ -#if 0 - bctbx_list_for_each(lc->calls, (MSIterateFunc)linphone_call_refresh_sockets); -#endif - } - linphone_core_repair_calls(lc); + if (lc->media_network_reachable){ if (lc->bw_controller){ ms_bandwidth_controller_reset_state(lc->bw_controller); } diff --git a/coreapi/private_functions.h b/coreapi/private_functions.h index fcc3c6911..bb1c98d14 100644 --- a/coreapi/private_functions.h +++ b/coreapi/private_functions.h @@ -54,9 +54,6 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const LinphoneCallLog * linphone_call_log_new(LinphoneCallDir dir, LinphoneAddress *from, LinphoneAddress * to); void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state); LinphonePlayer *linphone_call_build_player(LinphoneCall*call); -void linphone_call_refresh_sockets(LinphoneCall *call); -void linphone_call_replace_op(LinphoneCall *call, LinphonePrivate::SalOp *op); -void linphone_call_reinvite_to_recover_from_connection_loss(LinphoneCall *call); LinphonePrivate::SalCallOp *linphone_call_get_op(const LinphoneCall *call); LinphoneProxyConfig * linphone_call_get_dest_proxy(const LinphoneCall *call); @@ -335,9 +332,6 @@ LinphoneEcCalibratorStatus ec_calibrator_get_status(EcCalibrator *ecc); void ec_calibrator_destroy(EcCalibrator *ecc); -void linphone_call_set_broken(LinphoneCall *call); -void linphone_call_repair_if_broken(LinphoneCall *call); -void linphone_core_repair_calls(LinphoneCore *lc); int linphone_core_preempt_sound_resources(LinphoneCore *lc); int _linphone_call_pause(LinphoneCall *call); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 134c2bdf1..c93b02240 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1310,10 +1310,8 @@ void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrat cfg->state=state; } - if (lc){ + if (lc) linphone_core_notify_registration_state_changed(lc,cfg,state,message); - linphone_core_repair_calls(lc); - } } else { /*state already reported*/ } diff --git a/coreapi/vtables.c b/coreapi/vtables.c index aef7785d9..2088a8296 100644 --- a/coreapi/vtables.c +++ b/coreapi/vtables.c @@ -18,6 +18,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "c-wrapper/c-wrapper.h" +#include "core/core-p.h" + #include "private.h" #include "linphone/wrapper_utils.h" @@ -100,6 +103,7 @@ void linphone_core_notify_call_encryption_changed(LinphoneCore *lc, LinphoneCall } void linphone_core_notify_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){ + L_GET_PRIVATE_FROM_C_OBJECT(lc)->notifyRegistrationStateChanged(cfg, cstate, message); NOTIFY_IF_EXIST(registration_state_changed, lc,cfg,cstate,message); cleanup_dead_vtable_refs(lc); } @@ -239,6 +243,7 @@ void linphone_core_notify_configuring_status(LinphoneCore *lc, LinphoneConfiguri } void linphone_core_notify_network_reachable(LinphoneCore *lc, bool_t reachable) { + L_GET_PRIVATE_FROM_C_OBJECT(lc)->notifyNetworkReachable(!!reachable); NOTIFY_IF_EXIST(network_reachable, lc,reachable); cleanup_dead_vtable_refs(lc); } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a901d93a3..d68c0435a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -94,6 +94,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES content/file-content.h content/file-transfer-content.h core/core-accessor.h + core/core-listener.h core/core-p.h core/core.h core/paths/paths.h diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 274f7e97f..0ff3d58a4 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -319,188 +319,15 @@ int linphone_call_start_invite (LinphoneCall *call, const LinphoneAddress *desti return 0; } -void linphone_call_replace_op (LinphoneCall *call, LinphonePrivate::SalOp *op) { -#if 0 - SalOp *oldop = call->op; - LinphoneCallState oldstate = linphone_call_get_state(call); - call->op = op; - sal_op_set_user_pointer(call->op, call); - sal_call_set_local_media_description(call->op, call->localdesc); - switch (linphone_call_get_state(call)) { - case LinphoneCallIncomingEarlyMedia: - case LinphoneCallIncomingReceived: - sal_call_notify_ringing(call->op, (linphone_call_get_state(call) == LinphoneCallIncomingEarlyMedia) ? TRUE : FALSE); - break; - case LinphoneCallConnected: - case LinphoneCallStreamsRunning: - sal_call_accept(call->op); - break; - default: - ms_warning("linphone_call_replace_op(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state)); - break; - } - switch (oldstate) { - case LinphoneCallIncomingEarlyMedia: - case LinphoneCallIncomingReceived: - sal_op_set_user_pointer(oldop, nullptr); /* To make the call does not get terminated by terminating this op. */ - /* Do not terminate a forked INVITE */ - if (sal_call_get_replaces(op)) { - sal_call_terminate(oldop); - } else { - sal_op_kill_dialog(oldop); - } - break; - case LinphoneCallConnected: - case LinphoneCallStreamsRunning: - sal_call_terminate(oldop); - sal_op_kill_dialog(oldop); - break; - default: - break; - } - sal_op_release(oldop); -#endif -} - // ============================================================================= // Private functions. // ============================================================================= -#if 0 -static void linphone_call_repair_by_invite_with_replaces (LinphoneCall *call) { - const char *call_id = sal_op_get_call_id(call->op); - const char *from_tag = sal_call_get_local_tag(call->op); - const char *to_tag = sal_call_get_remote_tag(call->op); - sal_op_kill_dialog(call->op); - linphone_call_create_op(call); - sal_call_set_replaces(call->op, call_id, from_tag, to_tag); - linphone_call_start_invite(call, nullptr); -} -#endif - MediaStream *linphone_call_get_stream (LinphoneCall *call, LinphoneStreamType type) { return L_GET_PRIVATE_FROM_C_OBJECT(call)->getMediaStream(type); } -void linphone_call_set_broken (LinphoneCall *call) { -#if 0 - switch(call->state){ - /*for all the early states, we prefer to drop the call*/ - case LinphoneCallOutgoingInit: - case LinphoneCallOutgoingProgress: - case LinphoneCallOutgoingRinging: - case LinphoneCallOutgoingEarlyMedia: - case LinphoneCallIncomingReceived: - case LinphoneCallIncomingEarlyMedia: - /*during the early states, the SAL layer reports the failure from the dialog or transaction layer, - * hence, there is nothing special to do*/ - //break; - case LinphoneCallStreamsRunning: - case LinphoneCallUpdating: - case LinphoneCallPausing: - case LinphoneCallResuming: - case LinphoneCallPaused: - case LinphoneCallPausedByRemote: - case LinphoneCallUpdatedByRemote: - /*during these states, the dialog is established. A failure of a transaction is not expected to close it. - * Instead we have to repair the dialog by sending a reINVITE*/ - call->broken = TRUE; - call->need_localip_refresh = TRUE; - break; - default: - ms_error("linphone_call_set_broken() unimplemented case."); - break; - } -#endif -} - -void linphone_call_reinvite_to_recover_from_connection_loss (LinphoneCall *call) { -#if 0 - LinphoneCallParams *params; - ms_message("LinphoneCall[%p] is going to be updated (reINVITE) in order to recover from lost connectivity", call); - if (call->ice_session){ - ice_session_reset(call->ice_session, IR_Controlling); - } - params = linphone_core_create_call_params(call->core, call); - linphone_call_update(call, params); - linphone_call_params_unref(params); -#endif -} - -void linphone_call_repair_if_broken (LinphoneCall *call) { -#if 0 - SalErrorInfo sei; - if (!call->broken) return; - if (!call->core->media_network_reachable) return; - - memset(&sei, 0, sizeof(sei)); - - /*Make sure that the proxy from which we received this call, or to which we routed this call is registered first*/ - if (call->dest_proxy){ - /*in all other cases, ie no proxy config, or a proxy config for which no registration was requested, we can start the - * call repair immediately.*/ - if (linphone_proxy_config_register_enabled(call->dest_proxy) - && linphone_proxy_config_get_state(call->dest_proxy) != LinphoneRegistrationOk) return; - } - - switch (call->state){ - case LinphoneCallUpdating: - case LinphoneCallPausing: - if (sal_call_dialog_request_pending(call->op)) { - /* Need to cancel first re-INVITE as described in section 5.5 of RFC 6141 */ - sal_call_cancel_invite(call->op); - call->reinvite_on_cancel_response_requested = TRUE; - } - break; - case LinphoneCallStreamsRunning: - case LinphoneCallPaused: - case LinphoneCallPausedByRemote: - if (!sal_call_dialog_request_pending(call->op)) { - linphone_call_reinvite_to_recover_from_connection_loss(call); - } - break; - case LinphoneCallUpdatedByRemote: - if (sal_call_dialog_request_pending(call->op)) { - sal_error_info_set(&sei, SalReasonServiceUnavailable,"SIP", 0, nullptr, nullptr); - sal_call_decline_with_error_info(call->op, &sei,nullptr); - } - linphone_call_reinvite_to_recover_from_connection_loss(call); - break; - case LinphoneCallOutgoingInit: - case LinphoneCallOutgoingProgress: - sal_call_cancel_invite(call->op); - call->reinvite_on_cancel_response_requested = TRUE; - break; - case LinphoneCallOutgoingEarlyMedia: - case LinphoneCallOutgoingRinging: - linphone_call_repair_by_invite_with_replaces(call); - break; - case LinphoneCallIncomingEarlyMedia: - case LinphoneCallIncomingReceived: - /* Keep the call broken until a forked INVITE is received from the server. */ - break; - default: - ms_warning("linphone_call_repair_if_broken(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state)); - call->broken = FALSE; - break; - } - sal_error_info_reset(&sei); -#endif -} - -void linphone_call_refresh_sockets (LinphoneCall *call) { -#if 0 - int i; - for (i=0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i){ - MSMediaStreamSessions *mss = &call->sessions[i]; - if (mss->rtp_session){ - rtp_session_refresh_sockets(mss->rtp_session); - } - } -#endif -} - LinphonePrivate::SalCallOp * linphone_call_get_op (const LinphoneCall *call) { return L_GET_PRIVATE_FROM_C_OBJECT(call)->getOp(); } diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index e8d8c2f73..5a84788c8 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -29,7 +29,7 @@ LINPHONE_BEGIN_NAMESPACE -class CallSessionPrivate : public ObjectPrivate { +class CallSessionPrivate : public ObjectPrivate, public CoreListener { public: CallSessionPrivate () = default; @@ -43,16 +43,19 @@ public: CallSessionParams *getCurrentParams () const { return currentParams; } LinphoneProxyConfig * getDestProxy () const { return destProxy; } SalCallOp * getOp () const { return op; } + bool isBroken () const { return broken; } void setParams (CallSessionParams *csp); virtual void abort (const std::string &errorMsg); virtual void accepted (); void ackBeingSent (LinphoneHeaders *headers); virtual void ackReceived (LinphoneHeaders *headers); + void cancelDone (); virtual bool failure (); void infoReceived (SalBodyHandler *bodyHandler); void pingReply (); virtual void remoteRinging (); + void replaceOp (SalCallOp *newOp); virtual void terminated (); void updated (bool isUpdate); void updatedByRemote (); @@ -77,6 +80,10 @@ protected: void setContactOp (); + // CoreListener + void onNetworkReachable (bool reachable) override; + void onRegistrationStateChanged (LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const std::string &message) override; + private: void completeLog (); void createOp (); @@ -84,6 +91,10 @@ private: LinphoneAddress * getFixedContact () const; + virtual void reinviteToRecoverFromConnectionLoss (); + void repairByInviteWithReplaces (); + void repairIfBroken (); + protected: CallSessionListener *listener = nullptr; @@ -107,9 +118,12 @@ protected: bool pingReplied = false; int pingTime = 0; + bool broken = false; bool deferIncomingNotification = false; bool deferUpdate = false; + bool needLocalIpRefresh = false; bool nonOpError = false; /* Set when the LinphoneErrorInfo was set at higher level than sal */ + bool reinviteOnCancelResponseRequested = false; private: L_DECLARE_PUBLIC(CallSession); diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index aaa317a27..efcb27718 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -26,7 +26,7 @@ #include "conference/params/call-session-params-p.h" #include "conference/session/call-session-p.h" #include "conference/session/call-session.h" -#include "core/core.h" +#include "core/core-p.h" #include "logger/logger.h" @@ -241,6 +241,13 @@ void CallSessionPrivate::ackReceived (LinphoneHeaders *headers) { listener->onAckReceived(q->getSharedFromThis(), headers); } +void CallSessionPrivate::cancelDone () { + if (reinviteOnCancelResponseRequested) { + reinviteOnCancelResponseRequested = false; + reinviteToRecoverFromConnectionLoss(); + } +} + bool CallSessionPrivate::failure () { L_Q(); const SalErrorInfo *ei = op->get_error_info(); @@ -338,6 +345,47 @@ void CallSessionPrivate::remoteRinging () { setState(LinphoneCallOutgoingRinging, "Remote ringing"); } +void CallSessionPrivate::replaceOp (SalCallOp *newOp) { + L_Q(); + SalCallOp *oldOp = op; + LinphoneCallState oldState = state; + op = newOp; + op->set_user_pointer(q); + op->set_local_media_description(oldOp->get_local_media_description()); + switch (state) { + case LinphoneCallIncomingEarlyMedia: + case LinphoneCallIncomingReceived: + op->notify_ringing((state == LinphoneCallIncomingEarlyMedia) ? true : false); + break; + case LinphoneCallConnected: + case LinphoneCallStreamsRunning: + op->accept(); + break; + default: + lWarning() << "CallSessionPrivate::replaceOp(): don't know what to do in state [" << linphone_call_state_to_string(state) << "]"; + break; + } + switch (oldState) { + case LinphoneCallIncomingEarlyMedia: + case LinphoneCallIncomingReceived: + op->set_user_pointer(nullptr); // In order for the call session to not get terminated by terminating this op + // Do not terminate a forked INVITE + if (op->get_replaces()) + oldOp->terminate(); + else + oldOp->kill_dialog(); + break; + case LinphoneCallConnected: + case LinphoneCallStreamsRunning: + oldOp->terminate(); + oldOp->kill_dialog(); + break; + default: + break; + } + oldOp->release(); +} + void CallSessionPrivate::terminated () { switch (state) { case LinphoneCallEnd: @@ -640,6 +688,45 @@ void CallSessionPrivate::setContactOp () { // ----------------------------------------------------------------------------- +void CallSessionPrivate::onNetworkReachable (bool reachable) { + if (reachable) { + repairIfBroken(); + } else { + switch(state) { + // For all the early states, we prefer to drop the call + case LinphoneCallOutgoingInit: + case LinphoneCallOutgoingProgress: + case LinphoneCallOutgoingRinging: + case LinphoneCallOutgoingEarlyMedia: + case LinphoneCallIncomingReceived: + case LinphoneCallIncomingEarlyMedia: + // During the early states, the SAL layer reports the failure from the dialog or transaction layer, + // hence, there is nothing special to do + case LinphoneCallStreamsRunning: + case LinphoneCallUpdating: + case LinphoneCallPausing: + case LinphoneCallResuming: + case LinphoneCallPaused: + case LinphoneCallPausedByRemote: + case LinphoneCallUpdatedByRemote: + // During these states, the dialog is established. A failure of a transaction is not expected to close it. + // Instead we have to repair the dialog by sending a reINVITE + broken = true; + needLocalIpRefresh = true; + break; + default: + lError() << "CallSessionPrivate::onNetworkReachable(): unimplemented case"; + break; + } + } +} + +void CallSessionPrivate::onRegistrationStateChanged (LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const std::string &message) { + repairIfBroken(); +} + +// ----------------------------------------------------------------------------- + void CallSessionPrivate::completeLog () { L_Q(); log->duration = computeDuration(); /* Store duration since connected */ @@ -699,11 +786,96 @@ LinphoneAddress * CallSessionPrivate::getFixedContact () const { return result; } +// ----------------------------------------------------------------------------- + +void CallSessionPrivate::reinviteToRecoverFromConnectionLoss () { + L_Q(); + lInfo() << "CallSession [" << q << "] is going to be updated (reINVITE) in order to recover from lost connectivity"; + q->update(params); +} + +void CallSessionPrivate::repairByInviteWithReplaces () { + L_Q(); + const char *callId = op->get_call_id(); + const char *fromTag = op->get_local_tag(); + const char *toTag = op->get_remote_tag(); + op->kill_dialog(); + createOp(); + op->set_replaces(callId, fromTag, toTag); + q->startInvite(nullptr); +} + +void CallSessionPrivate::repairIfBroken () { + L_Q(); + LinphoneCore *lc = q->getCore()->getCCore(); + LinphoneConfig *config = linphone_core_get_config(lc); + if (!lp_config_get_int(config, "sip", "repair_broken_calls", 1) || !lc->media_network_reachable || !broken) + return; + + // If we are registered and this session has been broken due to a past network disconnection, + // attempt to repair it + + // Make sure that the proxy from which we received this call, or to which we routed this call is registered first + if (destProxy) { + // In all other cases, ie no proxy config, or a proxy config for which no registration was requested, + // we can start the call session repair immediately. + if (linphone_proxy_config_register_enabled(destProxy) + && (linphone_proxy_config_get_state(destProxy) != LinphoneRegistrationOk)) + return; + } + + SalErrorInfo sei; + memset(&sei, 0, sizeof(sei)); + switch (state) { + case LinphoneCallUpdating: + case LinphoneCallPausing: + if (op->dialog_request_pending()) { + // Need to cancel first re-INVITE as described in section 5.5 of RFC 6141 + op->cancel_invite(); + reinviteOnCancelResponseRequested = true; + } + break; + case LinphoneCallStreamsRunning: + case LinphoneCallPaused: + case LinphoneCallPausedByRemote: + if (!op->dialog_request_pending()) + reinviteToRecoverFromConnectionLoss(); + break; + case LinphoneCallUpdatedByRemote: + if (op->dialog_request_pending()) { + sal_error_info_set(&sei, SalReasonServiceUnavailable, "SIP", 0, nullptr, nullptr); + op->decline_with_error_info(&sei, nullptr); + } + reinviteToRecoverFromConnectionLoss(); + break; + case LinphoneCallOutgoingInit: + case LinphoneCallOutgoingProgress: + op->cancel_invite(); + reinviteOnCancelResponseRequested = true; + break; + case LinphoneCallOutgoingEarlyMedia: + case LinphoneCallOutgoingRinging: + repairByInviteWithReplaces(); + break; + case LinphoneCallIncomingEarlyMedia: + case LinphoneCallIncomingReceived: + // Keep the call broken until a forked INVITE is received from the server + break; + default: + lWarning() << "CallSessionPrivate::repairIfBroken: don't know what to do in state [" + << linphone_call_state_to_string(state); + broken = false; + break; + } + sal_error_info_reset(&sei); +} + // ============================================================================= CallSession::CallSession (const shared_ptr &core, const CallSessionParams *params, CallSessionListener *listener) : Object(*new CallSessionPrivate), CoreAccessor(core) { L_D(); + getCore()->getPrivate()->registerListener(d); d->listener = listener; if (params) d->setParams(new CallSessionParams(*params)); @@ -713,11 +885,13 @@ CallSession::CallSession (const shared_ptr &core, const CallSessionParams CallSession::CallSession (CallSessionPrivate &p, const shared_ptr &core) : Object(p), CoreAccessor(core) { L_D(); + getCore()->getPrivate()->registerListener(d); d->init(); } CallSession::~CallSession () { L_D(); + getCore()->getPrivate()->unregisterListener(d); if (d->currentParams) delete d->currentParams; if (d->params) diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index 7062f0ec1..d1e5ab231 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -25,6 +25,7 @@ #include "conference/conference.h" #include "conference/params/call-session-params.h" #include "conference/session/call-session-listener.h" +#include "core/core-listener.h" #include "sal/call-op.h" // ============================================================================= @@ -41,6 +42,7 @@ class LINPHONE_PUBLIC CallSession : public Object, public CoreAccessor { friend class ClientGroupChatRoom; friend class ClientGroupChatRoomPrivate; friend class Conference; + friend class CorePrivate; friend class ServerGroupChatRoom; friend class ServerGroupChatRoomPrivate; diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index 5e19fa222..b0d9d942a 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -87,6 +87,9 @@ public: SalCallOp * getOp () const { return op; } void setAudioMuted (bool value) { audioMuted = value; } + // CoreListener + void onNetworkReachable (bool reachable) override; + private: static OrtpJitterBufferAlgorithm jitterBufferNameToAlgo (const std::string &name); @@ -235,6 +238,9 @@ private: void accept (const MediaSessionParams *params); LinphoneStatus acceptUpdate (const CallSessionParams *csp, LinphoneCallState nextState, const std::string &stateInfo) override; + void refreshSockets (); + void reinviteToRecoverFromConnectionLoss () override; + #ifdef VIDEO_ENABLED void videoStreamEventCb (const MSFilter *f, const unsigned int eventId, const void *args); #endif // ifdef VIDEO_ENABLED diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 59a7accc3..8b8ed3962 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -539,6 +539,18 @@ int MediaSessionPrivate::getStreamIndex (MediaStream *ms) const { // ----------------------------------------------------------------------------- +void MediaSessionPrivate::onNetworkReachable (bool reachable) { + L_Q(); + if (reachable) { + LinphoneConfig *config = linphone_core_get_config(q->getCore()->getCCore()); + if (lp_config_get_int(config, "net", "recreate_sockets_when_network_is_up", 0)) + refreshSockets(); + } + CallSessionPrivate::onNetworkReachable(reachable); +} + +// ----------------------------------------------------------------------------- + OrtpJitterBufferAlgorithm MediaSessionPrivate::jitterBufferNameToAlgo (const string &name) { if (name == "basic") return OrtpJitterBufferBasic; if (name == "rls") return OrtpJitterBufferRecursiveLeastSquare; @@ -3693,9 +3705,7 @@ LinphoneStatus MediaSessionPrivate::pause () { lError() << "No reason to pause this call, it is already paused or inactive"; return -1; } -#if 0 - call->broken = FALSE; -#endif + broken = false; setState(LinphoneCallPausing, "Pausing call"); makeLocalMediaDescription(); op->set_local_media_description(localDesc); @@ -3945,6 +3955,24 @@ LinphoneStatus MediaSessionPrivate::acceptUpdate (const CallSessionParams *csp, // ----------------------------------------------------------------------------- +void MediaSessionPrivate::refreshSockets () { + for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + MSMediaStreamSessions *mss = &sessions[i]; + if (mss->rtp_session) + rtp_session_refresh_sockets(mss->rtp_session); + } +} + +void MediaSessionPrivate::reinviteToRecoverFromConnectionLoss () { + L_Q(); + lInfo() << "MediaSession [" << q << "] is going to be updated (reINVITE) in order to recover from lost connectivity"; + if (iceAgent->hasSession()) + iceAgent->resetSession(IR_Controlling); + q->update(getParams()); +} + +// ----------------------------------------------------------------------------- + #ifdef VIDEO_ENABLED void MediaSessionPrivate::videoStreamEventCb (const MSFilter *f, const unsigned int eventId, const void *args) { L_Q(); @@ -4261,9 +4289,7 @@ LinphoneStatus MediaSession::resume () { lInfo() << "Resuming MediaSession " << this; } d->automaticallyPaused = false; -#if 0 - call->broken = FALSE; -#endif + d->broken = false; /* Stop playing music immediately. If remote side is a conference it * prevents the participants to hear it while the 200OK comes back. */ if (d->audioStream) @@ -4389,9 +4415,7 @@ LinphoneStatus MediaSession::update (const MediaSessionParams *msp, const string lWarning() << "CallSession::update() is given the current params, this is probably not what you intend to do!"; d->iceAgent->checkSession(IR_Controlling, true); if (msp) { -#if 0 - call->broken = FALSE; -#endif + d->broken = false; d->setState(nextState, "Updating call"); d->setParams(new MediaSessionParams(*msp)); if (d->iceAgent->prepare(d->localDesc, false)) { diff --git a/src/core/core-call.cpp b/src/core/core-call.cpp index 3dd816c73..745577cd1 100644 --- a/src/core/core-call.cpp +++ b/src/core/core-call.cpp @@ -21,6 +21,7 @@ #include "core-p.h" #include "call/call-p.h" +#include "conference/session/call-session-p.h" #include "logger/logger.h" // TODO: Remove me later. @@ -44,6 +45,35 @@ int CorePrivate::addCall (const shared_ptr &call) { return 0; } +bool CorePrivate::canWeAddCall () const { + L_Q(); + if (q->getCallCount() < static_cast(q->getCCore()->max_calls)) + return true; + lInfo() << "Maximum amount of simultaneous calls reached!"; + return false; +} + +bool CorePrivate::inviteReplacesABrokenCall (SalCallOp *op) { + CallSession *replacedSession = nullptr; + SalCallOp *replacedOp = op->get_replaces(); + if (replacedOp) + replacedSession = reinterpret_cast(replacedOp->get_user_pointer()); + for (const auto &call : calls) { + shared_ptr session = call->getPrivate()->getActiveSession(); + if (session + && ((session->getPrivate()->isBroken() && op->compare_op(session->getPrivate()->getOp())) + || ((replacedSession == session.get()) + && (strcmp(op->get_from(), replacedOp->get_from()) == 0) + && (strcmp(op->get_to(), replacedOp->get_to()) == 0))) + ) { + session->getPrivate()->replaceOp(op); + return true; + } + } + + return false; +} + bool CorePrivate::isAlreadyInCallWithAddress (const Address &addr) const { for (const auto &call : calls) { if (call->getRemoteAddress().weakEqual(addr)) @@ -58,14 +88,6 @@ void CorePrivate::iterateCalls (time_t currentRealTime, bool oneSecondElapsed) c } } -bool CorePrivate::canWeAddCall () const { - L_Q(); - if (q->getCallCount() < static_cast(q->getCCore()->max_calls)) - return true; - lInfo() << "Maximum amount of simultaneous calls reached!"; - return false; -} - void CorePrivate::notifySoundcardUsage (bool used) { L_Q(); MSSndCard *card = q->getCCore()->sound_conf.capt_sndcard; diff --git a/src/core/core-listener.h b/src/core/core-listener.h new file mode 100644 index 000000000..789b9e6df --- /dev/null +++ b/src/core/core-listener.h @@ -0,0 +1,39 @@ +/* + * core-listener.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CORE_LISTENER_H_ +#define _CORE_LISTENER_H_ + +#include "linphone/types.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class CoreListener { +public: + virtual ~CoreListener () = default; + + virtual void onNetworkReachable (bool reachable) {} + virtual void onRegistrationStateChanged (LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const std::string &message) {} +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CORE_LISTENER_H_ diff --git a/src/core/core-p.h b/src/core/core-p.h index d5cec3542..e0904c757 100644 --- a/src/core/core-p.h +++ b/src/core/core-p.h @@ -23,19 +23,28 @@ #include "core.h" #include "db/main-db.h" #include "object/object-p.h" +#include "sal/call-op.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE +class CoreListener; + class CorePrivate : public ObjectPrivate { public: - void init(); - void uninit(); + void init (); + void registerListener (CoreListener *listener); + void unregisterListener (CoreListener *listener); + void uninit (); + + void notifyNetworkReachable (bool reachable); + void notifyRegistrationStateChanged (LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const std::string &message); int addCall (const std::shared_ptr &call); bool canWeAddCall () const; bool hasCalls () const { return !calls.empty(); } + bool inviteReplacesABrokenCall (SalCallOp *op); bool isAlreadyInCallWithAddress (const Address &addr) const; void iterateCalls (time_t currentRealTime, bool oneSecondElapsed) const; void notifySoundcardUsage (bool used); @@ -50,6 +59,8 @@ public: std::unique_ptr mainDb; private: + std::list listeners; + std::list> calls; std::shared_ptr currentCall; diff --git a/src/core/core.cpp b/src/core/core.cpp index 8977573dd..035b56f7c 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -20,7 +20,8 @@ #include #include "call/call.h" -#include "core-p.h" +#include "core/core-listener.h" +#include "core/core-p.h" #include "logger/logger.h" #include "paths/paths.h" @@ -59,6 +60,14 @@ void CorePrivate::init () { insertChatRoom(chatRoom); } +void CorePrivate::registerListener (CoreListener *listener) { + listeners.push_back(listener); +} + +void CorePrivate::unregisterListener (CoreListener *listener) { + listeners.remove(listener); +} + void CorePrivate::uninit () { L_Q(); while (!calls.empty()) { @@ -68,6 +77,18 @@ void CorePrivate::uninit () { } } +// ----------------------------------------------------------------------------- + +void CorePrivate::notifyNetworkReachable (bool reachable) { + for (const auto &listener : listeners) + listener->onNetworkReachable(reachable); +} + +void CorePrivate::notifyRegistrationStateChanged (LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const string &message) { + for (const auto &listener : listeners) + listener->onRegistrationStateChanged(cfg, state, message); +} + // ============================================================================= Core::Core () : Object(*new CorePrivate) {} diff --git a/src/core/core.h b/src/core/core.h index 76f6ccb2f..cf82c334c 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -41,6 +41,7 @@ class IdentityAddress; class LINPHONE_PUBLIC Core : public Object { friend class CallPrivate; + friend class CallSession; friend class ChatMessagePrivate; friend class ChatRoom; friend class ChatRoomPrivate; diff --git a/src/nat/ice-agent.cpp b/src/nat/ice-agent.cpp index d94aa46b3..9aef0281f 100644 --- a/src/nat/ice-agent.cpp +++ b/src/nat/ice-agent.cpp @@ -177,6 +177,12 @@ void IceAgent::prepareIceForStream (MediaStream *ms, bool createChecklist) { media_stream_set_ice_check_list(ms, cl); } +void IceAgent::resetSession (IceRole role) { + if (!iceSession) + return; + ice_session_reset(iceSession, role); +} + void IceAgent::restartSession (IceRole role) { if (!iceSession) return; diff --git a/src/nat/ice-agent.h b/src/nat/ice-agent.h index 42c293312..5d69ca864 100644 --- a/src/nat/ice-agent.h +++ b/src/nat/ice-agent.h @@ -59,6 +59,7 @@ public: bool isControlling () const; bool prepare (const SalMediaDescription *localDesc, bool incomingOffer); void prepareIceForStream (MediaStream *ms, bool createChecklist); + void resetSession (IceRole role); void restartSession (IceRole role); void startConnectivityChecks (); void stopIceForInactiveStreams (SalMediaDescription *desc); diff --git a/src/sal/call-op.h b/src/sal/call-op.h index 1144d78d3..80acdf958 100644 --- a/src/sal/call-op.h +++ b/src/sal/call-op.h @@ -30,6 +30,7 @@ public: SalCallOp(Sal *sal): SalOp(sal) {} ~SalCallOp() override; + SalMediaDescription *get_local_media_description () const { return local_media; } int set_local_media_description(SalMediaDescription *desc); int set_local_body(const Content &body); int set_local_body(const Content &&body); From 34a95033a745de0f1e23922e859b9b5da348ee0b Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 5 Dec 2017 18:48:14 +0100 Subject: [PATCH 0996/2215] Also add 'me' devices of a chatroom (for encryption purposes) --- src/db/main-db.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index f50bdaa53..6a21fb586 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -275,7 +275,13 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), // Do not add 'me' when creating a server-group-chat-room. if (chatRoomId.getLocalAddress() != chatRoomId.getPeerAddress()) { shared_ptr me = chatRoom->getMe(); - insertChatRoomParticipant(id, insertSipAddress(me->getAddress().asString()), me->isAdmin()); + long long meId = insertChatRoomParticipant( + id, + insertSipAddress(me->getAddress().asString()), + me->isAdmin() + ); + for (const auto &device : me->getPrivate()->getDevices()) + insertChatRoomParticipantDevice(meId, insertSipAddress(device->getAddress().asString())); } for (const auto &participant : chatRoom->getParticipants()) { From a194a9c77ccab9d79cc225685078219d4fc4d351 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 6 Dec 2017 10:35:19 +0100 Subject: [PATCH 0997/2215] feat(MainDb): update current devices state on devices events --- src/db/main-db-p.h | 5 +-- src/db/main-db.cpp | 88 +++++++++++++++++++++++++++++++++------------- 2 files changed, 66 insertions(+), 27 deletions(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index d6fe4fda6..a9c3e009d 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -52,7 +52,6 @@ private: long long insertSipAddress (const std::string &sipAddress); void insertContent (long long messageEventId, const Content &content); - void updateContent (long long messageEventId, long long messageContentId, const Content &content); void removeContentsForChatMessageEvent (long long messageEventId); long long insertContentType (const std::string &contentType); long long insertBasicChatRoom ( @@ -68,8 +67,10 @@ private: long long selectSipAddressId (const std::string &sipAddress) const; long long selectChatRoomId (long long peerSipAddressId, long long localSipAddressId) const; long long selectChatRoomId (const ChatRoomId &chatRoomId) const; + long long selectChatRoomParticipantId (long long chatRoomId, long long sipAddressId) const; void deleteChatRoomParticipant (long long chatRoomId, long long participantSipAddressId); + void deleteChatRoomParticipantDevice (long long participantId, long long participantDeviceSipAddressId); // --------------------------------------------------------------------------- // Events API. @@ -130,7 +131,7 @@ private: long long insertConferenceChatMessageEvent (const std::shared_ptr &eventLog); void updateConferenceChatMessageEvent(const std::shared_ptr &eventLog); long long insertConferenceNotifiedEvent (const std::shared_ptr &eventLog, long long *chatRoomId = nullptr); - long long insertConferenceParticipantEvent (const std::shared_ptr &eventLog); + long long insertConferenceParticipantEvent (const std::shared_ptr &eventLog, long long *chatRoomId = nullptr); long long insertConferenceParticipantDeviceEvent (const std::shared_ptr &eventLog); long long insertConferenceSubjectEvent (const std::shared_ptr &eventLog); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 6a21fb586..5b9d0d601 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -174,19 +174,6 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::use(messageContentId), soci::use(appData.first), soci::use(appData.second); } - void MainDbPrivate::updateContent (long long eventId, long long messageContentId, const Content &content) { - soci::session *session = dbSession.getBackendSession(); - - const long long &contentTypeId = insertContentType(content.getContentType().asString()); - const string &body = content.getBodyAsString(); - *session << "UPDATE chat_message_content SET content_type_id=:contentTypeId, body=:body WHERE event_id=:eventId", - soci::use(contentTypeId), soci::use(body), soci::use(eventId); - - for (const auto &appData : content.getAppDataMap()) - *session << "UPDATE chat_message_content_app_data SET name=:name, data=:data WHERE chat_message_content_id=:messageContentId", - soci::use(appData.first), soci::use(appData.second), soci::use(messageContentId); - } - void MainDbPrivate::removeContentsForChatMessageEvent (long long eventId) { soci::session *session = dbSession.getBackendSession(); @@ -300,12 +287,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long MainDbPrivate::insertChatRoomParticipant (long long chatRoomId, long long sipAddressId, bool isAdmin) { L_Q(); - long long id = -1; soci::session *session = dbSession.getBackendSession(); - *session << "SELECT id from chat_room_participant" - " WHERE chat_room_id = :chatRoomId AND participant_sip_address_id = :sipAddressId", - soci::into(id), soci::use(chatRoomId), soci::use(sipAddressId); - + long long id = selectChatRoomParticipantId(chatRoomId, sipAddressId); if (id >= 0) { // See: https://stackoverflow.com/a/15299655 (cast to reference) *session << "UPDATE chat_room_participant SET is_admin = :isAdmin" @@ -382,6 +365,15 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return selectChatRoomId(peerSipAddressId, localSipAddressId); } + long long MainDbPrivate::selectChatRoomParticipantId (long long chatRoomId, long long sipAddressId) const { + long long id; + soci::session *session = dbSession.getBackendSession(); + *session << "SELECT id from chat_room_participant" + " WHERE chat_room_id = :chatRoomId AND participant_sip_address_id = :sipAddressId", + soci::into(id), soci::use(chatRoomId), soci::use(sipAddressId); + return session->got_data() ? id : -1; + } + void MainDbPrivate::deleteChatRoomParticipant (long long chatRoomId, long long participantSipAddressId) { soci::session *session = dbSession.getBackendSession(); *session << "DELETE FROM chat_room_participant" @@ -389,6 +381,17 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::use(chatRoomId), soci::use(participantSipAddressId); } + void MainDbPrivate::deleteChatRoomParticipantDevice ( + long long participantId, + long long participantDeviceSipAddressId + ) { + soci::session *session = dbSession.getBackendSession(); + *session << "DELETE FROM chat_room_participant_device" + " WHERE chat_room_participant_id = :participantId" + " AND participant_device_sip_address_id = :participantDeviceSipAddressId", + soci::use(participantId), soci::use(participantDeviceSipAddressId); + } + // ----------------------------------------------------------------------------- shared_ptr MainDbPrivate::selectGenericConferenceEvent ( @@ -799,9 +802,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return eventId; } - long long MainDbPrivate::insertConferenceParticipantEvent (const shared_ptr &eventLog) { - long long chatRoomId; - const long long &eventId = insertConferenceNotifiedEvent(eventLog, &chatRoomId); + long long MainDbPrivate::insertConferenceParticipantEvent ( + const shared_ptr &eventLog, + long long *chatRoomId + ) { + long long curChatRoomId; + const long long &eventId = insertConferenceNotifiedEvent(eventLog, &curChatRoomId); if (eventId < 0) return -1; @@ -821,33 +827,65 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), case EventLog::Type::ConferenceParticipantAdded: case EventLog::Type::ConferenceParticipantSetAdmin: case EventLog::Type::ConferenceParticipantUnsetAdmin: - insertChatRoomParticipant(chatRoomId, participantAddressId, isAdmin); + insertChatRoomParticipant(curChatRoomId, participantAddressId, isAdmin); break; case EventLog::Type::ConferenceParticipantRemoved: - deleteChatRoomParticipant(chatRoomId, participantAddressId); + deleteChatRoomParticipant(curChatRoomId, participantAddressId); break; default: break; } + if (chatRoomId) + *chatRoomId = curChatRoomId; + return eventId; } long long MainDbPrivate::insertConferenceParticipantDeviceEvent (const shared_ptr &eventLog) { - const long long &eventId = insertConferenceParticipantEvent(eventLog); + long long chatRoomId; + const long long &eventId = insertConferenceParticipantEvent(eventLog, &chatRoomId); if (eventId < 0) return -1; + shared_ptr participantDeviceEvent = + static_pointer_cast(eventLog); + + const string participantAddress = participantDeviceEvent->getParticipantAddress().asString(); + const long long &participantAddressId = selectSipAddressId(participantAddress); + if (participantAddressId < 0) { + lError() << "Unable to find sip address id of: `" << participantAddress << "`."; + return -1; + } + const long long &participantId = selectChatRoomParticipantId(chatRoomId, participantAddressId); + if (participantId < 0) { + lError() << "Unable to find valid participant id in database with chat room id = " << chatRoomId << + " and participant address id = " << participantId; + return -1; + } const long long &deviceAddressId = insertSipAddress( - static_pointer_cast(eventLog)->getDeviceAddress().asString() + participantDeviceEvent->getDeviceAddress().asString() ); soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_participant_device_event (event_id, device_sip_address_id)" " VALUES (:eventId, :deviceAddressId)", soci::use(eventId), soci::use(deviceAddressId); + switch (eventLog->getType()) { + case EventLog::Type::ConferenceParticipantDeviceAdded: + insertChatRoomParticipantDevice(participantId, deviceAddressId); + break; + + case EventLog::Type::ConferenceParticipantDeviceRemoved: + deleteChatRoomParticipantDevice(participantId, deviceAddressId); + break; + + default: + break; + } + return eventId; } From f9363b1062345eed79b1b344799f8a01d43ec699 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 6 Dec 2017 10:39:03 +0100 Subject: [PATCH 0998/2215] Correctly handle ClientGroupChatRoom subscriptions. --- .../remote-conference-event-handler-p.h | 10 +++- .../remote-conference-event-handler.cpp | 57 +++++++++++++------ src/core/core-listener.h | 2 +- 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/conference/handlers/remote-conference-event-handler-p.h b/src/conference/handlers/remote-conference-event-handler-p.h index 87992f7b5..b949a5b42 100644 --- a/src/conference/handlers/remote-conference-event-handler-p.h +++ b/src/conference/handlers/remote-conference-event-handler-p.h @@ -23,6 +23,7 @@ #include "linphone/types.h" #include "chat/chat-room/chat-room-id.h" +#include "core/core-listener.h" #include "object/object-p.h" #include "remote-conference-event-handler.h" @@ -30,9 +31,15 @@ LINPHONE_BEGIN_NAMESPACE -class RemoteConferenceEventHandlerPrivate : public ObjectPrivate { +class RemoteConferenceEventHandlerPrivate : public ObjectPrivate, public CoreListener { private: void simpleNotifyReceived (const std::string &xmlBody); + void subscribe (); + void unsubscribe (); + + // CoreListener + void onNetworkReachable (bool reachable) override; + void onRegistrationStateChanged (LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const std::string &message) override; ChatRoomId chatRoomId; @@ -40,6 +47,7 @@ private: LinphoneEvent *lev = nullptr; unsigned int lastNotify = 0; + bool subscriptionWanted = false; L_DECLARE_PUBLIC(RemoteConferenceEventHandler); }; diff --git a/src/conference/handlers/remote-conference-event-handler.cpp b/src/conference/handlers/remote-conference-event-handler.cpp index 4f0904dd6..e4edc7c67 100644 --- a/src/conference/handlers/remote-conference-event-handler.cpp +++ b/src/conference/handlers/remote-conference-event-handler.cpp @@ -166,6 +166,43 @@ void RemoteConferenceEventHandlerPrivate::simpleNotifyReceived (const string &xm // ----------------------------------------------------------------------------- +void RemoteConferenceEventHandlerPrivate::subscribe () { + if (lev || !subscriptionWanted) + return; // Already subscribed or application did not request subscription + const string &peerAddress = chatRoomId.getPeerAddress().asString(); + LinphoneAddress *lAddr = linphone_address_new(peerAddress.c_str()); + lev = linphone_core_create_subscribe(conf->getCore()->getCCore(), lAddr, "conference", 600); + lev->op->set_from(chatRoomId.getLocalAddress().asString().c_str()); + const string &lastNotifyStr = Utils::toString(lastNotify); + linphone_event_add_custom_header(lev, "Last-Notify-Version", lastNotifyStr.c_str()); + linphone_address_unref(lAddr); + linphone_event_set_internal(lev, TRUE); + linphone_event_set_user_data(lev, this); + lInfo() << "Subscribing to chat room: " << peerAddress << "with last notify: " << lastNotifyStr; + linphone_event_send_subscribe(lev, nullptr); +} + +void RemoteConferenceEventHandlerPrivate::unsubscribe () { + if (lev) { + linphone_event_terminate(lev); + lev = nullptr; + } +} + +// ----------------------------------------------------------------------------- + +void RemoteConferenceEventHandlerPrivate::onNetworkReachable (bool reachable) { + if (!reachable) + unsubscribe(); +} + +void RemoteConferenceEventHandlerPrivate::onRegistrationStateChanged (LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const std::string &message) { + if (state == LinphoneRegistrationOk) + subscribe(); +} + +// ----------------------------------------------------------------------------- + RemoteConferenceEventHandler::RemoteConferenceEventHandler (RemoteConference *remoteConference) : Object(*new RemoteConferenceEventHandlerPrivate) { L_D(); @@ -182,25 +219,14 @@ RemoteConferenceEventHandler::~RemoteConferenceEventHandler () { void RemoteConferenceEventHandler::subscribe (const ChatRoomId &chatRoomId) { L_D(); d->chatRoomId = chatRoomId; - const string &peerAddress = d->chatRoomId.getPeerAddress().asString(); - LinphoneAddress *lAddr = linphone_address_new(peerAddress.c_str()); - d->lev = linphone_core_create_subscribe(d->conf->getCore()->getCCore(), lAddr, "conference", 600); - d->lev->op->set_from(d->chatRoomId.getLocalAddress().asString().c_str()); - const string &lastNotify = Utils::toString(d->lastNotify); - linphone_event_add_custom_header(d->lev, "Last-Notify-Version", lastNotify.c_str()); - linphone_address_unref(lAddr); - linphone_event_set_internal(d->lev, TRUE); - linphone_event_set_user_data(d->lev, this); - lInfo() << "Subscribing to chat room: " << peerAddress << "with last notify: " << lastNotify; - linphone_event_send_subscribe(d->lev, nullptr); + d->subscriptionWanted = true; + d->subscribe(); } void RemoteConferenceEventHandler::unsubscribe () { L_D(); - if (d->lev) { - linphone_event_terminate(d->lev); - d->lev = nullptr; - } + d->unsubscribe(); + d->subscriptionWanted = false; } void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) { @@ -246,5 +272,4 @@ void RemoteConferenceEventHandler::resetLastNotify () { setLastNotify(0); } - LINPHONE_END_NAMESPACE diff --git a/src/core/core-listener.h b/src/core/core-listener.h index 789b9e6df..1f69a5d86 100644 --- a/src/core/core-listener.h +++ b/src/core/core-listener.h @@ -31,7 +31,7 @@ public: virtual ~CoreListener () = default; virtual void onNetworkReachable (bool reachable) {} - virtual void onRegistrationStateChanged (LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const std::string &message) {} + virtual void onRegistrationStateChanged (LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const std::string &message) {} }; LINPHONE_END_NAMESPACE From 7792f64b344138985192774da29bd790ffe86412 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 6 Dec 2017 10:56:09 +0100 Subject: [PATCH 0999/2215] feat(MainDb): clean some pieces of code --- src/db/main-db-p.h | 2 +- src/db/main-db.cpp | 37 +++++++++++++++---------------------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index a9c3e009d..bb8f82202 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -52,7 +52,6 @@ private: long long insertSipAddress (const std::string &sipAddress); void insertContent (long long messageEventId, const Content &content); - void removeContentsForChatMessageEvent (long long messageEventId); long long insertContentType (const std::string &contentType); long long insertBasicChatRoom ( long long peerSipAddressId, @@ -69,6 +68,7 @@ private: long long selectChatRoomId (const ChatRoomId &chatRoomId) const; long long selectChatRoomParticipantId (long long chatRoomId, long long sipAddressId) const; + void deleteContents (long long messageEventId); void deleteChatRoomParticipant (long long chatRoomId, long long participantSipAddressId); void deleteChatRoomParticipantDevice (long long participantId, long long participantDeviceSipAddressId); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 5b9d0d601..c08b3b2f4 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -154,36 +154,24 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), const long long &contentTypeId = insertContentType(content.getContentType().asString()); const string &body = content.getBodyAsString(); *session << "INSERT INTO chat_message_content (event_id, content_type_id, body) VALUES" - " (:eventId, :contentTypeId, :body)", soci::use(eventId), soci::use(contentTypeId), + " (:eventId, :contentTypeId, :body)", soci::use(eventId), soci::use(contentTypeId), soci::use(body); - const long long &messageContentId = q->getLastInsertId(); + const long long &chatMessageContentId = q->getLastInsertId(); if (content.getContentType().isFile()) { const FileContent &fileContent = static_cast(content); - const string &fileName = fileContent.getFileName(); - const size_t &fileSize = fileContent.getFileSize(); - const string &filePath = fileContent.getFilePath(); + const string &name = fileContent.getFileName(); + const size_t &size = fileContent.getFileSize(); + const string &path = fileContent.getFilePath(); *session << "INSERT INTO chat_message_file_content (chat_message_content_id, name, size, path) VALUES " - " (:contentId, :name, :size, :path)", - soci::use(messageContentId), soci::use(fileName), soci::use(fileSize), soci::use(filePath); + " (:chatMessageContentId, :name, :size, :path)", + soci::use(chatMessageContentId), soci::use(name), soci::use(size), soci::use(path); } for (const auto &appData : content.getAppDataMap()) *session << "INSERT INTO chat_message_content_app_data (chat_message_content_id, name, data) VALUES" - " (:messageContentId, :name, :data)", - soci::use(messageContentId), soci::use(appData.first), soci::use(appData.second); - } - - void MainDbPrivate::removeContentsForChatMessageEvent (long long eventId) { - soci::session *session = dbSession.getBackendSession(); - - *session << "DELETE FROM chat_message_content WHERE event_id=:eventId", soci::use(eventId); - - //TODO: remove file content if exists - //*session << "DELETE FROM chat_message_file_content WHERE chat_message_content_id=:messageContentId", soci::use(messageContentId); - - //TODO: remove contents' app_data - //*session << "DELETE FROM chat_message_content_app_data WHERE chat_message_content_id=:messageContentId", soci::use(messageContentId); + " (:chatMessageContentId, :name, :data)", + soci::use(chatMessageContentId), soci::use(appData.first), soci::use(appData.second); } long long MainDbPrivate::insertContentType (const string &contentType) { @@ -374,6 +362,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return session->got_data() ? id : -1; } + void MainDbPrivate::deleteContents (long long messageEventId) { + soci::session *session = dbSession.getBackendSession(); + *session << "DELETE FROM chat_message_content WHERE event_id = :messageEventId", soci::use(messageEventId); + } + void MainDbPrivate::deleteChatRoomParticipant (long long chatRoomId, long long participantSipAddressId) { soci::session *session = dbSession.getBackendSession(); *session << "DELETE FROM chat_room_participant" @@ -777,7 +770,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::use(state), soci::use(eventId); //TODO: improve - removeContentsForChatMessageEvent(eventId); + deleteContents(eventId); for (const Content *content : chatMessage->getContents()) insertContent(eventId, *content); } From 2a16139e3ddcd01dc4a7e01b7cfeaedf1feb9215 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 6 Dec 2017 11:05:29 +0100 Subject: [PATCH 1000/2215] Fixed imdn id not being store on outgoing file transfer messages --- src/db/main-db.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index c08b3b2f4..e4f4abd68 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -766,8 +766,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); const int &state = static_cast(chatMessage->getState()); - *session << "UPDATE conference_chat_message_event SET state = :state WHERE event_id = :eventId", - soci::use(state), soci::use(eventId); + const string &imdnMessageId = chatMessage->getImdnMessageId(); + *session << "UPDATE conference_chat_message_event SET state = :state, imdn_message_id = :imdnMessageId WHERE event_id = :eventId", + soci::use(state), soci::use(imdnMessageId), soci::use(eventId); //TODO: improve deleteContents(eventId); From 519153278d68093fc213fd7b623395d70a5fe282 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 6 Dec 2017 11:16:50 +0100 Subject: [PATCH 1001/2215] add error logs when receiving a subscribe for conference event package --- .../handlers/local-conference-event-handler.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/conference/handlers/local-conference-event-handler.cpp b/src/conference/handlers/local-conference-event-handler.cpp index ee391c3e9..f30e6538f 100644 --- a/src/conference/handlers/local-conference-event-handler.cpp +++ b/src/conference/handlers/local-conference-event-handler.cpp @@ -365,15 +365,20 @@ void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) { char *addrStr = linphone_address_as_string(lAddr); shared_ptr participant = d->conf->findParticipant(Address(addrStr)); bctbx_free(addrStr); - if (!participant) + if (!participant) { + lError() << "received SUBSCRIBE corresponds to no participant of the conference; " << d->conf->getConferenceAddress().asString() << ", no NOTIFY sent."; return; + } const LinphoneAddress *lContactAddr = linphone_event_get_remote_contact(lev); char *contactAddrStr = linphone_address_as_string(lContactAddr); Address contactAddr(contactAddrStr); bctbx_free(contactAddrStr); - if (contactAddr.getUriParamValue("gr").empty()) + if (contactAddr.getUriParamValue("gr").empty()) { + lError() << "received SUBSCRIBE for conference: " << d->conf->getConferenceAddress().asString() + << "has no GRUU in it's contact address:" << contactAddr.asString() << ", no NOTIFY sent."; return; + } IdentityAddress gruu(contactAddr); shared_ptr device = participant->getPrivate()->addDevice(gruu); From 59f9c18b8476d537f86677080f467a294a7e7658 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 6 Dec 2017 11:29:36 +0100 Subject: [PATCH 1002/2215] Check registration state before sending subscribe in the remote conference event handler. --- src/conference/handlers/remote-conference-event-handler.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/conference/handlers/remote-conference-event-handler.cpp b/src/conference/handlers/remote-conference-event-handler.cpp index e4edc7c67..aa5f5bce9 100644 --- a/src/conference/handlers/remote-conference-event-handler.cpp +++ b/src/conference/handlers/remote-conference-event-handler.cpp @@ -169,8 +169,14 @@ void RemoteConferenceEventHandlerPrivate::simpleNotifyReceived (const string &xm void RemoteConferenceEventHandlerPrivate::subscribe () { if (lev || !subscriptionWanted) return; // Already subscribed or application did not request subscription + const string &peerAddress = chatRoomId.getPeerAddress().asString(); LinphoneAddress *lAddr = linphone_address_new(peerAddress.c_str()); + LinphoneCore *lc = conf->getCore()->getCCore(); + LinphoneProxyConfig *cfg = linphone_core_lookup_known_proxy(lc, lAddr); + if (!cfg || (linphone_proxy_config_get_state(cfg) != LinphoneRegistrationOk)) + return; + lev = linphone_core_create_subscribe(conf->getCore()->getCCore(), lAddr, "conference", 600); lev->op->set_from(chatRoomId.getLocalAddress().asString().c_str()); const string &lastNotifyStr = Utils::toString(lastNotify); From f92da345a45e63b726300358852f1f4b46e17126 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 6 Dec 2017 11:30:03 +0100 Subject: [PATCH 1003/2215] Keep the gruu address of the client group chat room focus participant. --- src/chat/chat-room/client-group-chat-room.cpp | 10 ++++++--- src/conference/participant-p.h | 4 +++- src/conference/participant.cpp | 22 +++++++++++-------- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index c34281ad4..e176ac8f4 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -66,7 +66,7 @@ shared_ptr ClientGroupChatRoomPrivate::createSession () { const Address &myAddress = q->getMe()->getAddress(); Address myCleanedAddress(myAddress); myCleanedAddress.setUriParam("gr"); // Remove gr parameter for INVITE - session->configure(LinphoneCallOutgoing, nullptr, nullptr, myCleanedAddress, focus->getAddress()); + session->configure(LinphoneCallOutgoing, nullptr, nullptr, myCleanedAddress, focus->getPrivate()->getDevices().front()->getAddress()); session->initiateOutgoing(); return session; } @@ -87,13 +87,15 @@ void ClientGroupChatRoomPrivate::onChatMessageReceived (const shared_ptr &core, - const string &factoryUri, + const string &uri, const IdentityAddress &me, const string &subject ) : ChatRoom(*new ClientGroupChatRoomPrivate, core, ChatRoomId(IdentityAddress(), me)), RemoteConference(core, me, nullptr) { L_D_T(RemoteConference, dConference); - dConference->focus = make_shared(Address(factoryUri)); + IdentityAddress focusAddr(uri); + dConference->focus = make_shared(focusAddr); + dConference->focus->getPrivate()->addDevice(focusAddr); RemoteConference::setSubject(subject); } @@ -298,6 +300,8 @@ void ClientGroupChatRoom::onConferenceCreated (const IdentityAddress &addr) { L_D_T(RemoteConference, dConference); dConference->conferenceAddress = addr; dConference->focus->getPrivate()->setAddress(addr); + dConference->focus->getPrivate()->clearDevices(); + dConference->focus->getPrivate()->addDevice(addr); d->chatRoomId = ChatRoomId(addr, d->chatRoomId.getLocalAddress()); getCore()->getPrivate()->insertChatRoom(getSharedFromThis()); } diff --git a/src/conference/participant-p.h b/src/conference/participant-p.h index 1f5af8552..afc8e66b0 100644 --- a/src/conference/participant-p.h +++ b/src/conference/participant-p.h @@ -40,10 +40,12 @@ public: inline void removeSession () { session.reset(); } inline void setAddress (const IdentityAddress &newAddr) { addr = newAddr; } inline void setAdmin (bool isAdmin) { this->isAdmin = isAdmin; } + + std::shared_ptr addDevice (const IdentityAddress &gruu); + void clearDevices (); std::shared_ptr findDevice (const IdentityAddress &gruu) const; std::shared_ptr findDevice (const std::shared_ptr &session); const std::list> &getDevices () const; - std::shared_ptr addDevice (const IdentityAddress &gruu); void removeDevice (const IdentityAddress &gruu); private: diff --git a/src/conference/participant.cpp b/src/conference/participant.cpp index aa4b475f4..c3011ca03 100644 --- a/src/conference/participant.cpp +++ b/src/conference/participant.cpp @@ -46,6 +46,19 @@ shared_ptr ParticipantPrivate::createSession ( // ----------------------------------------------------------------------------- +shared_ptr ParticipantPrivate::addDevice (const IdentityAddress &gruu) { + shared_ptr device = findDevice(gruu); + if (device) + return device; + device = make_shared(gruu); + devices.push_back(device); + return device; +} + +void ParticipantPrivate::clearDevices () { + devices.clear(); +} + shared_ptr ParticipantPrivate::findDevice (const IdentityAddress &gruu) const { for (const auto &device : devices) { if (device->getAddress() == gruu) @@ -66,15 +79,6 @@ const list> &ParticipantPrivate::getDevices () con return devices; } -shared_ptr ParticipantPrivate::addDevice (const IdentityAddress &gruu) { - shared_ptr device = findDevice(gruu); - if (device) - return device; - device = make_shared(gruu); - devices.push_back(device); - return device; -} - void ParticipantPrivate::removeDevice (const IdentityAddress &gruu) { for (auto it = devices.begin(); it != devices.end(); it++) { if ((*it)->getAddress() == gruu) { From 1616b8062bfed2190a4720702922fe37eceffe0f Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 6 Dec 2017 11:37:14 +0100 Subject: [PATCH 1004/2215] set imdnId when fetching chat message from db --- src/db/main-db.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index e4f4abd68..a7e4d19a6 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -506,7 +506,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), static_cast(direction) )); chatMessage->setIsSecured(static_cast(isSecured)); - + chatMessage->setImdnMessageId(imdnMessageId); ChatMessagePrivate *dChatMessage = chatMessage->getPrivate(); dChatMessage->setState(static_cast(state), true); From 16a6c279eee5afb23167046c6c83495f67f8c3ee Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 6 Dec 2017 12:01:45 +0100 Subject: [PATCH 1005/2215] feat(MainDb): use well-named variables on select/delete functions --- src/db/main-db-p.h | 6 ++--- src/db/main-db.cpp | 56 +++++++++++++++++++++++++++++----------------- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index bb8f82202..5e9041436 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -59,14 +59,14 @@ private: const tm &creationTime ); long long insertChatRoom (const std::shared_ptr &chatRoom); - long long insertChatRoomParticipant (long long chatRoomId, long long sipAddressId, bool isAdmin); - void insertChatRoomParticipantDevice (long long participantId, long long sipAddressId); + long long insertChatRoomParticipant (long long chatRoomId, long long participantSipAddressId, bool isAdmin); + void insertChatRoomParticipantDevice (long long participantId, long long participantDeviceSipAddressId); void insertChatMessageParticipant (long long messageEventId, long long sipAddressId, int state); long long selectSipAddressId (const std::string &sipAddress) const; long long selectChatRoomId (long long peerSipAddressId, long long localSipAddressId) const; long long selectChatRoomId (const ChatRoomId &chatRoomId) const; - long long selectChatRoomParticipantId (long long chatRoomId, long long sipAddressId) const; + long long selectChatRoomParticipantId (long long chatRoomId, long long participantSipAddressId) const; void deleteContents (long long messageEventId); void deleteChatRoomParticipant (long long chatRoomId, long long participantSipAddressId); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index a7e4d19a6..26f1b5d13 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -134,6 +134,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), : static_cast(row.get(0)); } +// ----------------------------------------------------------------------------- + long long MainDbPrivate::insertSipAddress (const string &sipAddress) { L_Q(); soci::session *session = dbSession.getBackendSession(); @@ -224,7 +226,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), long long id = selectChatRoomId(peerSipAddressId, localSipAddressId); if (id >= 0) { - lWarning() << "Unable to insert chat room (it already exists): (peer=" << peerSipAddressId << + lError() << "Unable to insert chat room (it already exists): (peer=" << peerSipAddressId << ", local=" << localSipAddressId << ")."; return id; } @@ -243,7 +245,6 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::use(capabilities), soci::use(subject), soci::use(flags); id = q->getLastInsertId(); - if (!chatRoom->canHandleParticipants()) return id; @@ -272,57 +273,68 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return id; } - long long MainDbPrivate::insertChatRoomParticipant (long long chatRoomId, long long sipAddressId, bool isAdmin) { + long long MainDbPrivate::insertChatRoomParticipant ( + long long chatRoomId, + long long participantSipAddressId, + bool isAdmin + ) { L_Q(); soci::session *session = dbSession.getBackendSession(); - long long id = selectChatRoomParticipantId(chatRoomId, sipAddressId); + long long id = selectChatRoomParticipantId(chatRoomId, participantSipAddressId); if (id >= 0) { // See: https://stackoverflow.com/a/15299655 (cast to reference) - *session << "UPDATE chat_room_participant SET is_admin = :isAdmin" - " WHERE id = :id", + *session << "UPDATE chat_room_participant SET is_admin = :isAdmin WHERE id = :id", soci::use(static_cast(isAdmin)), soci::use(id); return id; } - lInfo() << "Insert new chat room participant in database: `" << sipAddressId << "` (isAdmin=" << isAdmin << ")."; + lInfo() << "Insert new chat room participant in database: `" << participantSipAddressId << + "` (isAdmin=" << isAdmin << ")."; *session << "INSERT INTO chat_room_participant (chat_room_id, participant_sip_address_id, is_admin)" - " VALUES (:chatRoomId, :sipAddressId, :isAdmin)", - soci::use(chatRoomId), soci::use(sipAddressId), soci::use(static_cast(isAdmin)); + " VALUES (:chatRoomId, :participantSipAddressId, :isAdmin)", + soci::use(chatRoomId), soci::use(participantSipAddressId), soci::use(static_cast(isAdmin)); return q->getLastInsertId(); } - void MainDbPrivate::insertChatRoomParticipantDevice (long long participantId, long long sipAddressId) { + void MainDbPrivate::insertChatRoomParticipantDevice ( + long long participantId, + long long participantDeviceSipAddressId + ) { soci::session *session = dbSession.getBackendSession(); long long count; *session << "SELECT COUNT(*) FROM chat_room_participant_device" - " WHERE chat_room_participant_id = :participantId" - " AND participant_device_sip_address_id = :sipAddressId", - soci::into(count), soci::use(participantId), soci::use(sipAddressId); + " WHERE chat_room_participant_id = :participantId" + " AND participant_device_sip_address_id = :participantDeviceSipAddressId", + soci::into(count), soci::use(participantId), soci::use(participantDeviceSipAddressId); if (count) return; - lInfo() << "Insert new chat room participant device in database: `" << sipAddressId << "`."; + lInfo() << "Insert new chat room participant device in database: `" << participantDeviceSipAddressId << "`."; *session << "INSERT INTO chat_room_participant_device (chat_room_participant_id, participant_device_sip_address_id)" - " VALUES (:participantId, :sipAddressId)", - soci::use(participantId), soci::use(sipAddressId); + " VALUES (:participantId, :participantDeviceSipAddressId)", + soci::use(participantId), soci::use(participantDeviceSipAddressId); } void MainDbPrivate::insertChatMessageParticipant (long long eventId, long long sipAddressId, int state) { + // TODO: Deal with read messages. + // Remove if displayed? Think a good alorithm for mark as read. soci::session *session = dbSession.getBackendSession(); soci::statement statement = ( session->prepare << "UPDATE chat_message_participant SET state = :state" - " WHERE event_id = :eventId AND participant_sip_address_id = :sipAddressId", + " WHERE event_id = :eventId AND participant_sip_address_id = :sipAddressId", soci::use(state), soci::use(eventId), soci::use(sipAddressId) ); statement.execute(true); if (statement.get_affected_rows() == 0 && state != static_cast(ChatMessage::State::Displayed)) *session << "INSERT INTO chat_message_participant (event_id, participant_sip_address_id, state)" - " VALUES (:eventId, :sipAddressId, :state)", + " VALUES (:eventId, :sipAddressId, :state)", soci::use(eventId), soci::use(sipAddressId), soci::use(state); } +// ----------------------------------------------------------------------------- + long long MainDbPrivate::selectSipAddressId (const string &sipAddress) const { soci::session *session = dbSession.getBackendSession(); @@ -353,15 +365,17 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return selectChatRoomId(peerSipAddressId, localSipAddressId); } - long long MainDbPrivate::selectChatRoomParticipantId (long long chatRoomId, long long sipAddressId) const { + long long MainDbPrivate::selectChatRoomParticipantId (long long chatRoomId, long long participantSipAddressId) const { long long id; soci::session *session = dbSession.getBackendSession(); *session << "SELECT id from chat_room_participant" - " WHERE chat_room_id = :chatRoomId AND participant_sip_address_id = :sipAddressId", - soci::into(id), soci::use(chatRoomId), soci::use(sipAddressId); + " WHERE chat_room_id = :chatRoomId AND participant_sip_address_id = :participantSipAddressId", + soci::into(id), soci::use(chatRoomId), soci::use(participantSipAddressId); return session->got_data() ? id : -1; } +// ----------------------------------------------------------------------------- + void MainDbPrivate::deleteContents (long long messageEventId) { soci::session *session = dbSession.getBackendSession(); *session << "DELETE FROM chat_message_content WHERE event_id = :messageEventId", soci::use(messageEventId); From 047eba2f1011cc312172a9b52ae3236798a85340 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 6 Dec 2017 12:02:44 +0100 Subject: [PATCH 1006/2215] Add registration of CoreListener in the remote conference event handler. --- src/conference/handlers/remote-conference-event-handler.cpp | 5 ++++- src/core/core.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/conference/handlers/remote-conference-event-handler.cpp b/src/conference/handlers/remote-conference-event-handler.cpp index aa5f5bce9..4d9737249 100644 --- a/src/conference/handlers/remote-conference-event-handler.cpp +++ b/src/conference/handlers/remote-conference-event-handler.cpp @@ -22,7 +22,7 @@ #include "conference/remote-conference.h" #include "content/content-manager.h" #include "content/content.h" -#include "core/core.h" +#include "core/core-p.h" #include "logger/logger.h" #include "remote-conference-event-handler-p.h" #include "xml/conference-info.h" @@ -214,9 +214,12 @@ Object(*new RemoteConferenceEventHandlerPrivate) { L_D(); xercesc::XMLPlatformUtils::Initialize(); d->conf = remoteConference; + d->conf->getCore()->getPrivate()->registerListener(d); } RemoteConferenceEventHandler::~RemoteConferenceEventHandler () { + L_D(); + d->conf->getCore()->getPrivate()->unregisterListener(d); xercesc::XMLPlatformUtils::Terminate(); } diff --git a/src/core/core.h b/src/core/core.h index cf82c334c..8002d1d88 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -50,6 +50,7 @@ class LINPHONE_PUBLIC Core : public Object { friend class MainDb; friend class MainDbChatMessageKey; friend class MainDbEventKey; + friend class RemoteConferenceEventHandler; friend class ServerGroupChatRoom; friend class ServerGroupChatRoomPrivate; From f31f9150f62cb8d27ac98ae55bb6e962be83e8df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Wed, 6 Dec 2017 12:08:37 +0100 Subject: [PATCH 1007/2215] C++ wrapper generator: clean wrapper before generating it again --- wrappers/cpp/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wrappers/cpp/CMakeLists.txt b/wrappers/cpp/CMakeLists.txt index 5fedcd2b0..1042d749d 100644 --- a/wrappers/cpp/CMakeLists.txt +++ b/wrappers/cpp/CMakeLists.txt @@ -21,6 +21,8 @@ ############################################################################ add_custom_command(OUTPUT include/linphone++/linphone.hh src/linphone++.cc + COMMAND ${CMAKE_COMMAND} -E remove_directory include + COMMAND ${CMAKE_COMMAND} -E remove_directory src COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/genwrapper.py" "${PROJECT_BINARY_DIR}/coreapi/help/doc/doxygen/xml" DEPENDS ${PROJECT_SOURCE_DIR}/tools/genapixml.py ${PROJECT_SOURCE_DIR}/tools/metadoc.py From 7d6fc054591a0163e00e2adbdadeea4e06ec6f34 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 6 Dec 2017 13:34:58 +0100 Subject: [PATCH 1008/2215] setImdnMessageId is now private --- src/c-wrapper/api/c-chat-message.cpp | 2 +- src/chat/chat-message/chat-message-p.h | 4 +++- src/chat/chat-message/chat-message.cpp | 15 +++++++-------- src/chat/chat-message/chat-message.h | 1 - src/chat/chat-room/chat-room.cpp | 2 +- src/chat/modifier/cpim-chat-message-modifier.cpp | 4 ++-- src/db/main-db.cpp | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 7826ced15..96c95914e 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -151,7 +151,7 @@ const char* linphone_chat_message_get_message_id(const LinphoneChatMessage *msg) } void linphone_chat_message_set_message_id(LinphoneChatMessage *msg, char *id) { - L_GET_CPP_PTR_FROM_C_OBJECT(msg)->setImdnMessageId(L_C_TO_STRING(id)); + L_GET_PRIVATE_FROM_C_OBJECT(msg)->setImdnMessageId(L_C_TO_STRING(id)); } bool_t linphone_chat_message_is_read(LinphoneChatMessage *msg) { diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index 2665afe0a..c805eb935 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -65,6 +65,8 @@ public: void setIsReadOnly(bool readOnly); + void setImdnMessageId (const std::string &imdnMessageId); + inline void forceFromAddress (const IdentityAddress &fromAddress) { this->fromAddress = fromAddress; } @@ -127,7 +129,7 @@ public: private: // TODO: Clean attributes. time_t time = ::ms_time(0); // TODO: Change me in all files. - std::string id; + std::string imdnId; std::string rttMessage; bool isSecured = false; bool isReadOnly = false; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index c75adc429..958703c7c 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -320,7 +320,7 @@ void ChatMessagePrivate::sendImdn (Imdn::Type imdnType, LinphoneReason reason) { Content *content = new Content(); content->setContentType("message/imdn+xml"); - content->setBody(Imdn::createXml(id, time, imdnType, reason)); + content->setBody(Imdn::createXml(imdnId, time, imdnType, reason)); msg->addContent(*content); msg->getPrivate()->send(); @@ -416,7 +416,7 @@ LinphoneReason ChatMessagePrivate::receive () { setDirection(ChatMessage::Direction::Outgoing); // Check if this is a duplicate message. - if (chatRoom && chatRoom->findMessageWithDirection(q->getImdnMessageId(), direction)) + if (chatRoom && chatRoom->findMessageWithDirection(imdnId, direction)) return core->getCCore()->chat_deny_code; if (errorCode > 0) { @@ -558,8 +558,8 @@ void ChatMessagePrivate::send () { } } - if (q->getImdnMessageId().empty()) - q->setImdnMessageId(op->get_call_id()); /* must be known at that time */ + if (imdnId.empty()) + setImdnMessageId(op->get_call_id()); /* must be known at that time */ //store(); // Store will be done right below in the setState(InProgress) @@ -692,12 +692,11 @@ ChatMessage::State ChatMessage::getState () const { const string &ChatMessage::getImdnMessageId () const { L_D(); - return d->id; + return d->imdnId; } -void ChatMessage::setImdnMessageId (const string &id) { - L_D(); - d->id = id; +void ChatMessagePrivate::setImdnMessageId (const string &id) { + imdnId = id; } bool ChatMessage::isRead () const { diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index a582dcee8..8cb4a09d8 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -64,7 +64,6 @@ public: void updateState (State state); void sendDeliveryNotification (LinphoneReason reason); void sendDisplayNotification (); - void setImdnMessageId (const std::string &imdnMessageId); void setIsSecured (bool isSecured); // ----- TODO: Remove me. diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 25f7500d2..194c02626 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -147,7 +147,7 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa msg->setInternalContent(content); msg->getPrivate()->setTime(salMsg->time); - msg->setImdnMessageId(op->get_call_id()); + msg->getPrivate()->setImdnMessageId(op->get_call_id()); const SalCustomHeader *ch = op->get_recv_custom_header(); if (ch) diff --git a/src/chat/modifier/cpim-chat-message-modifier.cpp b/src/chat/modifier/cpim-chat-message-modifier.cpp index 7d866b4a3..314906e58 100644 --- a/src/chat/modifier/cpim-chat-message-modifier.cpp +++ b/src/chat/modifier/cpim-chat-message-modifier.cpp @@ -50,7 +50,7 @@ ChatMessageModifier::Result CpimChatMessageModifier::encode (const shared_ptrsetImdnMessageId(token); + message->getPrivate()->setImdnMessageId(token); const Content *content; if (!message->getInternalContent().isEmpty()) { @@ -134,7 +134,7 @@ ChatMessageModifier::Result CpimChatMessageModifier::decode (const shared_ptrgetName() == "To") cpimToAddress = Address(header->getValue()); else if (header->getName() == "Message-ID") - message->setImdnMessageId(header->getValue()); + message->getPrivate()->setImdnMessageId(header->getValue()); } } diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 26f1b5d13..c9f211975 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -520,7 +520,6 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), static_cast(direction) )); chatMessage->setIsSecured(static_cast(isSecured)); - chatMessage->setImdnMessageId(imdnMessageId); ChatMessagePrivate *dChatMessage = chatMessage->getPrivate(); dChatMessage->setState(static_cast(state), true); @@ -528,6 +527,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), dChatMessage->forceToAddress(IdentityAddress(toSipAddress)); dChatMessage->setTime(Utils::getTmAsTimeT(messageTime)); + dChatMessage->setImdnMessageId(imdnMessageId); } // 2 - Fetch contents. From 1cbabd0f3d2904658adbf72831a6d1d03c10dee7 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 6 Dec 2017 13:59:42 +0100 Subject: [PATCH 1009/2215] feat(ClientGroupChatRoom): add created event in db on chat room creation --- src/chat/chat-room/client-group-chat-room.cpp | 9 +++- src/db/main-db.cpp | 44 ++++++++++--------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index e176ac8f4..bd2f86cef 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -321,7 +321,14 @@ void ClientGroupChatRoom::onConferenceTerminated (const IdentityAddress &addr) { void ClientGroupChatRoom::onFirstNotifyReceived (const IdentityAddress &addr) { L_D(); d->setState(ChatRoom::State::Created); - getCore()->getPrivate()->insertChatRoomWithDb(getSharedFromThis()); + + CorePrivate *dCore = getCore()->getPrivate(); + dCore->insertChatRoomWithDb(getSharedFromThis()); + dCore->mainDb->addEvent(make_shared( + EventLog::Type::ConferenceCreated, + time(nullptr), + d->chatRoomId + )); } void ClientGroupChatRoom::onParticipantAdded (const shared_ptr &event, bool isFullState) { diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index c9f211975..42611770b 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -483,8 +483,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), shared_ptr core = q->getCore(); shared_ptr chatRoom = core->findChatRoom(chatRoomId); - if (!chatRoom) + if (!chatRoom) { + lError() << "Unable to find chat room storage id of (peer=" + + chatRoomId.getPeerAddress().asString() + + ", local=" + chatRoomId.getLocalAddress().asString() + "`)."; return nullptr; + } bool hasFileTransferContent = false; @@ -506,12 +510,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); *session << "SELECT from_sip_address.value, to_sip_address.value, time, imdn_message_id, state, direction, is_secured" - " FROM event, conference_chat_message_event, sip_address AS from_sip_address," - " sip_address AS to_sip_address" - " WHERE event_id = :eventId" - " AND event_id = event.id" - " AND from_sip_address_id = from_sip_address.id" - " AND to_sip_address_id = to_sip_address.id", soci::into(fromSipAddress), soci::into(toSipAddress), + " FROM event, conference_chat_message_event, sip_address AS from_sip_address, sip_address AS to_sip_address" + " WHERE event_id = :eventId" + " AND event_id = event.id" + " AND from_sip_address_id = from_sip_address.id" + " AND to_sip_address_id = to_sip_address.id", soci::into(fromSipAddress), soci::into(toSipAddress), soci::into(messageTime), soci::into(imdnMessageId), soci::into(state), soci::into(direction), soci::into(isSecured), soci::use(eventId); @@ -520,6 +523,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), static_cast(direction) )); chatMessage->setIsSecured(static_cast(isSecured)); + ChatMessagePrivate *dChatMessage = chatMessage->getPrivate(); dChatMessage->setState(static_cast(state), true); @@ -534,8 +538,8 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), { soci::session *session = dbSession.getBackendSession(); static const string query = "SELECT chat_message_content.id, content_type.id, content_type.value, body" - " FROM chat_message_content, content_type" - " WHERE event_id = :eventId AND content_type_id = content_type.id"; + " FROM chat_message_content, content_type" + " WHERE event_id = :eventId AND content_type_id = content_type.id"; soci::rowset rows = (session->prepare << query, soci::use(eventId)); for (const auto &row : rows) { ContentType contentType(row.get(2)); @@ -553,7 +557,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), string path; *session << "SELECT name, size, path FROM chat_message_file_content" - " WHERE chat_message_content_id = :contentId", + " WHERE chat_message_content_id = :contentId", soci::into(name), soci::into(size), soci::into(path), soci::use(contentId); FileContent *fileContent = new FileContent(); @@ -567,7 +571,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), // 2.2 - Fetch contents' app data. static const string query = "SELECT name, data FROM chat_message_content_app_data" - " WHERE chat_message_content_id = :contentId"; + " WHERE chat_message_content_id = :contentId"; soci::rowset rows = (session->prepare << query, soci::use(contentId)); for (const auto &row : rows) content->setAppData(row.get(0), row.get(1)); @@ -578,11 +582,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), } } - // 3 - Load external body url from body into FileTransferContent if needed - if (hasFileTransferContent) { - ChatMessagePrivate *dChatMessage = chatMessage->getPrivate(); - dChatMessage->loadFileTransferUrlFromBodyToContent(); - } + // 3 - Load external body url from body into FileTransferContent if needed. + if (hasFileTransferContent) + chatMessage->getPrivate()->loadFileTransferUrlFromBodyToContent(); cache(chatMessage, eventId); @@ -661,9 +663,9 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); *session << "SELECT notify_id, subject" - " FROM conference_notified_event, conference_subject_event" - " WHERE conference_subject_event.event_id = :eventId" - " AND conference_notified_event.event_id = conference_subject_event.event_id", + " FROM conference_notified_event, conference_subject_event" + " WHERE conference_subject_event.event_id = :eventId" + " AND conference_notified_event.event_id = conference_subject_event.event_id", soci::into(notifyId), soci::into(subject), soci::use(eventId); return make_shared( @@ -706,11 +708,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_event (event_id, chat_room_id)" - " VALUES (:eventId, :chatRoomId)", soci::use(eventId), soci::use(curChatRoomId); + " VALUES (:eventId, :chatRoomId)", soci::use(eventId), soci::use(curChatRoomId); const tm &lastUpdateTime = Utils::getTimeTAsTm(eventLog->getCreationTime()); *session << "UPDATE chat_room SET last_update_time = :lastUpdateTime" - " WHERE id = :chatRoomId", soci::use(lastUpdateTime), + " WHERE id = :chatRoomId", soci::use(lastUpdateTime), soci::use(curChatRoomId); if (eventLog->getType() == EventLog::Type::ConferenceTerminated) From 3f965bfc940e5dca0ce6c080800848ea02a90a8d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 6 Dec 2017 14:10:46 +0100 Subject: [PATCH 1010/2215] Fix crash in LocalConferenceEventHandler if there are no events to notify. --- .../handlers/local-conference-event-handler.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/conference/handlers/local-conference-event-handler.cpp b/src/conference/handlers/local-conference-event-handler.cpp index f30e6538f..184047002 100644 --- a/src/conference/handlers/local-conference-event-handler.cpp +++ b/src/conference/handlers/local-conference-event-handler.cpp @@ -68,7 +68,7 @@ void LocalConferenceEventHandlerPrivate::notifyParticipant (const string ¬ify } void LocalConferenceEventHandlerPrivate::notifyParticipantDevice (const string ¬ify, const shared_ptr &device) { - if (device->isSubscribedToConferenceEventPackage()) { + if (device->isSubscribedToConferenceEventPackage() && !notify.empty()) { LinphoneEvent *ev = device->getConferenceSubscribeEvent(); LinphoneContent *content = linphone_core_create_content(ev->lc); linphone_content_set_buffer(content, (const uint8_t *)notify.c_str(), strlen(notify.c_str())); @@ -217,6 +217,8 @@ string LocalConferenceEventHandlerPrivate::createNotifyMultipart (int notifyId) contents.push_back(content); } + if (contents.empty()) + return ""; return ContentManager::contentListToMultipart(contents).getBodyAsString(); } @@ -389,8 +391,9 @@ void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) { lInfo() << "Sending initial notify of conference:" << d->conf->getConferenceAddress().asString() << " to: " << device->getAddress().asString(); d->notifyFullState(d->createNotifyFullState(), device); } else if (lastNotify < d->lastNotify) { - lInfo() << "Sending all missed notify for conference:" << d->conf->getConferenceAddress().asString() << - " from: " << lastNotify << " to: " << participant->getAddress().asString(); + lInfo() << "Sending all missed notify [" << lastNotify << "-" << d->lastNotify << + "] for conference:" << d->conf->getConferenceAddress().asString() << + " to: " << participant->getAddress().asString(); d->notifyParticipantDevice(d->createNotifyMultipart(static_cast(lastNotify)), device); } else if (lastNotify > d->lastNotify) { lError() << "last notify received by client: [" << lastNotify <<"] for conference:" << From 6aee9994b9d4a1cb266598614f640ce93e8f0644 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 6 Dec 2017 14:22:37 +0100 Subject: [PATCH 1011/2215] use const string ref when possible --- src/chat/notification/imdn.cpp | 2 +- src/chat/notification/imdn.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chat/notification/imdn.cpp b/src/chat/notification/imdn.cpp index 72ed7eb20..39081659c 100644 --- a/src/chat/notification/imdn.cpp +++ b/src/chat/notification/imdn.cpp @@ -32,7 +32,7 @@ LINPHONE_BEGIN_NAMESPACE const string Imdn::imdnPrefix = "/imdn:imdn"; -string Imdn::createXml (string id, time_t time, Imdn::Type imdnType, LinphoneReason reason) { +string Imdn::createXml (const string &id, time_t time, Imdn::Type imdnType, LinphoneReason reason) { xmlBufferPtr buf; xmlTextWriterPtr writer; int err; diff --git a/src/chat/notification/imdn.h b/src/chat/notification/imdn.h index 15e41905a..de89edb6c 100644 --- a/src/chat/notification/imdn.h +++ b/src/chat/notification/imdn.h @@ -37,7 +37,7 @@ public: Display }; - static std::string createXml(std::string id, time_t time, Imdn::Type imdnType, LinphoneReason reason); + static std::string createXml (const std::string &id, time_t time, Imdn::Type imdnType, LinphoneReason reason); static void parse (ChatRoom &cr, const std::string &content); private: From c5cfbc58929d45916009ff4ba3758dd879965345 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Wed, 6 Dec 2017 14:23:03 +0100 Subject: [PATCH 1012/2215] do not increment lastNotify on a full state --- src/conference/handlers/local-conference-event-handler-p.h | 2 +- src/conference/handlers/local-conference-event-handler.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/conference/handlers/local-conference-event-handler-p.h b/src/conference/handlers/local-conference-event-handler-p.h index 24f65b2cc..e5ffea9d9 100644 --- a/src/conference/handlers/local-conference-event-handler-p.h +++ b/src/conference/handlers/local-conference-event-handler-p.h @@ -52,7 +52,7 @@ private: ChatRoomId chatRoomId; LocalConference *conf = nullptr; - unsigned int lastNotify = 0; + unsigned int lastNotify = 1; std::string createNotify (Xsd::ConferenceInfo::ConferenceType confInfo, int notifyId = -1, bool isFullState = false); std::string createNotifySubjectChanged (const std::string &subject, int notifyId = -1); diff --git a/src/conference/handlers/local-conference-event-handler.cpp b/src/conference/handlers/local-conference-event-handler.cpp index 184047002..cdfa9e304 100644 --- a/src/conference/handlers/local-conference-event-handler.cpp +++ b/src/conference/handlers/local-conference-event-handler.cpp @@ -389,7 +389,7 @@ void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) { device->setConferenceSubscribeEvent(lev); if (lastNotify == 0) { lInfo() << "Sending initial notify of conference:" << d->conf->getConferenceAddress().asString() << " to: " << device->getAddress().asString(); - d->notifyFullState(d->createNotifyFullState(), device); + d->notifyFullState(d->createNotifyFullState(static_cast(d->lastNotify)), device); } else if (lastNotify < d->lastNotify) { lInfo() << "Sending all missed notify [" << lastNotify << "-" << d->lastNotify << "] for conference:" << d->conf->getConferenceAddress().asString() << From d2c6e3fcf4eef414c90ade3ca2f94afd4cc03ebf Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Wed, 6 Dec 2017 14:59:10 +0100 Subject: [PATCH 1013/2215] fix(MainDb): remote static qualifier of query in getEventCount --- src/db/main-db.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 42611770b..61a623279 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -783,12 +783,12 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); const int &state = static_cast(chatMessage->getState()); const string &imdnMessageId = chatMessage->getImdnMessageId(); - *session << "UPDATE conference_chat_message_event SET state = :state, imdn_message_id = :imdnMessageId WHERE event_id = :eventId", + *session << "UPDATE conference_chat_message_event SET state = :state, imdn_message_id = :imdnMessageId" + " WHERE event_id = :eventId", soci::use(state), soci::use(imdnMessageId), soci::use(eventId); - //TODO: improve deleteContents(eventId); - for (const Content *content : chatMessage->getContents()) + for (const auto &content : chatMessage->getContents()) insertContent(eventId, *content); } @@ -802,7 +802,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_notified_event (event_id, notify_id)" - " VALUES (:eventId, :notifyId)", soci::use(eventId), soci::use(lastNotifyId); + " VALUES (:eventId, :notifyId)", soci::use(eventId), soci::use(lastNotifyId); *session << "UPDATE chat_room SET last_notify_id = :lastNotifyId WHERE id = :chatRoomId", soci::use(lastNotifyId), soci::use(curChatRoomId); @@ -881,7 +881,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_participant_device_event (event_id, device_sip_address_id)" - " VALUES (:eventId, :deviceAddressId)", soci::use(eventId), soci::use(deviceAddressId); + " VALUES (:eventId, :deviceAddressId)", soci::use(eventId), soci::use(deviceAddressId); switch (eventLog->getType()) { case EventLog::Type::ConferenceParticipantDeviceAdded: @@ -909,10 +909,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); *session << "INSERT INTO conference_subject_event (event_id, subject)" - " VALUES (:eventId, :subject)", soci::use(eventId), soci::use(subject); + " VALUES (:eventId, :subject)", soci::use(eventId), soci::use(subject); *session << "UPDATE chat_room SET subject = :subject" - " WHERE id = :chatRoomId", soci::use(subject), soci::use(chatRoomId); + " WHERE id = :chatRoomId", soci::use(subject), soci::use(chatRoomId); return eventId; } @@ -1433,7 +1433,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return 0; } - static string query = "SELECT COUNT(*) FROM event" + + string query = "SELECT COUNT(*) FROM event" + buildSqlEventFilter({ ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter }, mask); int count = 0; From badd672bd91a73242c83303aa6fe864c1213e32a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 6 Dec 2017 15:32:08 +0100 Subject: [PATCH 1014/2215] Do not multipart, encrypt or encapsulate with CPIM in an old ChatRoom to maintain backward compatibility --- src/chat/chat-message/chat-message.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 958703c7c..c1bd24bae 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -492,7 +492,7 @@ void ChatMessagePrivate::send () { // Start of message modification // --------------------------------------- - if (applyModifiers) { + if (applyModifiers && q->getChatRoom()->canHandleParticipants()) { // Do not multipart, encrypt or encapsulate with CPIM in an old ChatRoom to maintain backward compatibility if ((currentSendStep &ChatMessagePrivate::Step::Multipart) == ChatMessagePrivate::Step::Multipart) { lInfo() << "Multipart step already done, skipping"; } else { From 4d277538b089fdaaaada694075fb33e3546c7fe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Wed, 6 Dec 2017 15:31:40 +0100 Subject: [PATCH 1015/2215] Makes genapixml.py to interpret \bctbxlist balises while parsing events'arguments --- tools/genapixml.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/genapixml.py b/tools/genapixml.py index 53b4481b2..e7530d412 100755 --- a/tools/genapixml.py +++ b/tools/genapixml.py @@ -489,7 +489,14 @@ class Project: elif spacePos != -1: argType = argdef[0 : spacePos] argName = argdef[spacePos + 1 :] - argslist.addArgument(CArgument(argType, argName, self.enums, self.__structs)) + arg = CArgument(argType, argName, self.enums, self.__structs) + if arg.ctype == 'MSList' or arg.ctype == 'bctbx_list_t': + for argentry in node.findall("detaileddescription/para/parameterlist[@kind='param']/*"): + if argentry.find("parameternamelist[parametername='{0}']".format(argName)) is not None: + containedType = argentry.find("parameterdescription//bctbxlist") + arg.containedType = containedType.text if containedType is not None else None + break + argslist.addArgument(arg) if len(argslist) > 0: paramdescs = node.findall("detaileddescription/para/parameterlist[@kind='param']/parameteritem") if paramdescs: From 6dc6e0d431cbe275b32c370360c6e6a9e5c9898c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 6 Dec 2017 17:17:16 +0100 Subject: [PATCH 1016/2215] Fix DTMF handling. --- coreapi/callbacks.c | 16 +- src/c-wrapper/api/c-call.cpp | 156 +----------------- src/call/call-listener.h | 1 + src/call/call-p.h | 1 + src/call/call.cpp | 20 +++ src/call/call.h | 3 + src/conference/conference.cpp | 6 + src/conference/conference.h | 1 + .../session/call-session-listener.h | 1 + src/conference/session/call-session.cpp | 8 - src/conference/session/media-session-p.h | 26 +-- src/conference/session/media-session.cpp | 88 +++++++++- src/conference/session/media-session.h | 3 + 13 files changed, 155 insertions(+), 175 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 28bfcbd3b..1dd8d1c00 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -366,12 +366,16 @@ static void vfu_request(SalOp *op) { L_GET_PRIVATE(mediaSession)->sendVfu(); } -static void dtmf_received(SalOp *op, char dtmf){ -#if 0 - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - if (!call) return; - linphone_call_notify_dtmf_received(call, dtmf); -#endif +static void dtmf_received(SalOp *op, char dtmf) { + LinphonePrivate::CallSession *session = reinterpret_cast(op->get_user_pointer()); + if (!session) + return; + LinphonePrivate::MediaSession *mediaSession = dynamic_cast(session); + if (!mediaSession) { + ms_warning("DTMF received but no MediaSession!"); + return; + } + L_GET_PRIVATE(mediaSession)->dtmfReceived(dtmf); } static void call_refer_received(SalOp *op, const SalAddress *referto){ diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index 0ff3d58a4..8acfc076f 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -51,37 +51,18 @@ L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(Call, /* TODO: all the fields need to be removed */ struct _LinphoneCore *core; LinphoneErrorInfo *ei; - SalMediaDescription *localdesc; - SalMediaDescription *resultdesc; - struct _LinphoneCallLog *log; LinphonePrivate::SalOp *op; - LinphonePrivate::SalOp *ping_op; LinphoneCallState transfer_state; /*idle if no transfer*/ struct _AudioStream *audiostream; /**/ - struct _VideoStream *videostream; - struct _TextStream *textstream; MSAudioEndpoint *endpoint; /*used for conferencing*/ char *refer_to; - LinphoneCallParams *params; - LinphoneCallParams *current_params; - LinphoneCallParams *remote_params; - LinphoneCallStats *audio_stats; - LinphoneCallStats *video_stats; - LinphoneCallStats *text_stats; LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/ LinphoneCall *transfer_target;/*if this call received a transfer request, then transfer_target points to the new call created to the refer target */ LinphonePlayer *player; - char *dtmf_sequence; /*DTMF sequence needed to be sent using #dtmfs_timer*/ - belle_sip_source_t *dtmfs_timer; /*DTMF timer needed to send a DTMF sequence*/ LinphoneChatRoom *chat_room; LinphoneConference *conf_ref; /**> Point on the associated conference if this call is part of a conference. NULL instead. */ bool_t refer_pending; bool_t defer_update; - bool_t was_automatically_paused; - bool_t paused_by_app; - bool_t broken; /*set to TRUE when the call is in broken state due to network disconnection or transport */ - bool_t need_localip_refresh; - bool_t reinvite_on_cancel_response_requested; bool_t non_op_error; /*set when the LinphoneErrorInfo was set at higher level than sal*/ ) @@ -106,34 +87,10 @@ static void _linphone_call_destructor (LinphoneCall *call) { call->remoteAddressCache = nullptr; } bctbx_list_free_with_data(call->callbacks, (bctbx_list_free_func)linphone_call_cbs_unref); - if (call->audio_stats) { - linphone_call_stats_unref(call->audio_stats); - call->audio_stats = nullptr; - } - if (call->video_stats) { - linphone_call_stats_unref(call->video_stats); - call->video_stats = nullptr; - } - if (call->text_stats) { - linphone_call_stats_unref(call->text_stats); - call->text_stats = nullptr; - } if (call->op) { call->op->release(); call->op=nullptr; } - if (call->resultdesc) { - sal_media_description_unref(call->resultdesc); - call->resultdesc=nullptr; - } - if (call->localdesc) { - sal_media_description_unref(call->localdesc); - call->localdesc=nullptr; - } - if (call->ping_op) { - call->ping_op->release(); - call->ping_op=nullptr; - } if (call->refer_to){ ms_free(call->refer_to); call->refer_to=nullptr; @@ -146,25 +103,6 @@ static void _linphone_call_destructor (LinphoneCall *call) { linphone_call_unref(call->transfer_target); call->transfer_target=nullptr; } - if (call->log) { - linphone_call_log_unref(call->log); - call->log=nullptr; - } - if (call->dtmfs_timer) { - linphone_call_cancel_dtmfs(call); - } - if (call->params){ - linphone_call_params_unref(call->params); - call->params=nullptr; - } - if (call->current_params){ - linphone_call_params_unref(call->current_params); - call->current_params=nullptr; - } - if (call->remote_params) { - linphone_call_params_unref(call->remote_params); - call->remote_params=nullptr; - } if (call->ei) linphone_error_info_unref(call->ei); } @@ -191,18 +129,6 @@ void linphone_call_set_state (LinphoneCall *call, LinphoneCallState cstate, cons void linphone_call_init_media_streams (LinphoneCall *call) {} -#if 0 -static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'}; - -static void linphone_core_dtmf_received (LinphoneCall *call, int dtmf) { - if (dtmf<0 || dtmf>15){ - ms_warning("Bad dtmf value %i",dtmf); - return; - } - linphone_call_notify_dtmf_received(call, dtmf_tab[dtmf]); -} -#endif - /*This function is not static because used internally in linphone-daemon project*/ void _post_configure_audio_stream (AudioStream *st, LinphoneCore *lc, bool_t muted) {} @@ -259,41 +185,6 @@ void linphone_call_set_transfer_state (LinphoneCall *call, LinphoneCallState sta void _linphone_call_set_new_params (LinphoneCall *call, const LinphoneCallParams *params) {} -#if 0 -static int send_dtmf_handler (void *data, unsigned int revents) { - LinphoneCall *call = (LinphoneCall*)data; - /*By default we send DTMF RFC2833 if we do not have enabled SIP_INFO but we can also send RFC2833 and SIP_INFO*/ - if (linphone_core_get_use_rfc2833_for_dtmf(call->core)!=0 || linphone_core_get_use_info_for_dtmf(call->core)==0) - { - /* In Band DTMF */ - if (call->audiostream){ - audio_stream_send_dtmf(call->audiostream,*call->dtmf_sequence); - } - else - { - ms_error("Cannot send RFC2833 DTMF when we are not in communication."); - return FALSE; - } - } - if (linphone_core_get_use_info_for_dtmf(call->core)!=0){ - /* Out of Band DTMF (use INFO method) */ - sal_call_send_dtmf(call->op,*call->dtmf_sequence); - } - - /*this check is needed because linphone_call_send_dtmf does not set the timer since its a single character*/ - if (call->dtmfs_timer) { - memmove(call->dtmf_sequence, call->dtmf_sequence+1, strlen(call->dtmf_sequence)); - } - /* continue only if the dtmf sequence is not empty*/ - if (call->dtmf_sequence && *call->dtmf_sequence!='\0') { - return TRUE; - } else { - linphone_call_cancel_dtmfs(call); - return FALSE; - } -} -#endif - /* Internal version that does not play tone indication*/ int _linphone_call_pause (LinphoneCall *call) { return 0; @@ -607,54 +498,25 @@ void linphone_call_zoom (LinphoneCall *call, float zoom_factor, float cx, float } LinphoneStatus linphone_call_send_dtmf (LinphoneCall *call, char dtmf) { -#if 0 - if (!call){ - ms_warning("linphone_call_send_dtmf(): invalid call, canceling DTMF."); + if (!call) { + ms_warning("linphone_call_send_dtmf(): invalid call, canceling DTMF"); return -1; } - call->dtmf_sequence = &dtmf; - send_dtmf_handler(call,0); - call->dtmf_sequence = nullptr; - return 0; -#else - return 0; -#endif + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->sendDtmf(dtmf); } LinphoneStatus linphone_call_send_dtmfs (LinphoneCall *call, const char *dtmfs) { -#if 0 - if (!call){ - ms_warning("linphone_call_send_dtmfs(): invalid call, canceling DTMF sequence."); + if (!call) { + ms_warning("linphone_call_send_dtmfs(): invalid call, canceling DTMF sequence"); return -1; } - if (call->dtmfs_timer){ - ms_warning("linphone_call_send_dtmfs(): a DTMF sequence is already in place, canceling DTMF sequence."); - return -2; - } - if (dtmfs) { - int delay_ms = lp_config_get_int(call->core->config,"net","dtmf_delay_ms",200); - call->dtmf_sequence = ms_strdup(dtmfs); - call->dtmfs_timer = sal_create_timer(call->core->sal, send_dtmf_handler, call, delay_ms, "DTMF sequence timer"); - } - return 0; -#else - return 0; -#endif + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->sendDtmfs(dtmfs); } void linphone_call_cancel_dtmfs (LinphoneCall *call) { -#if 0 - /*nothing to do*/ - if (!call || !call->dtmfs_timer) return; - - sal_cancel_timer(call->core->sal, call->dtmfs_timer); - belle_sip_object_unref(call->dtmfs_timer); - call->dtmfs_timer = nullptr; - if (call->dtmf_sequence) { - ms_free(call->dtmf_sequence); - call->dtmf_sequence = nullptr; - } -#endif + if (!call) + return; + L_GET_CPP_PTR_FROM_C_OBJECT(call)->cancelDtmfs(); } bool_t linphone_call_is_in_conference (const LinphoneCall *call) { diff --git a/src/call/call-listener.h b/src/call/call-listener.h index 44f721518..066dd5e07 100644 --- a/src/call/call-listener.h +++ b/src/call/call-listener.h @@ -36,6 +36,7 @@ public: virtual void onCallSetTerminated () = 0; virtual void onCallStateChanged (LinphoneCallState state, const std::string &message) = 0; virtual void onCheckForAcceptation () = 0; + virtual void onDtmfReceived (char dtmf) = 0; virtual void onIncomingCallStarted () = 0; virtual void onIncomingCallToBeAdded () = 0; virtual void onInfoReceived (const LinphoneInfoMessage *im) = 0; diff --git a/src/call/call-p.h b/src/call/call-p.h index 73f985ee2..5d4d87838 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -63,6 +63,7 @@ private: void onCallSetTerminated () override; void onCallStateChanged (LinphoneCallState state, const std::string &message) override; void onCheckForAcceptation () override; + void onDtmfReceived (char dtmf) override; void onIncomingCallStarted () override; void onIncomingCallToBeAdded () override; void onInfoReceived (const LinphoneInfoMessage *im) override; diff --git a/src/call/call.cpp b/src/call/call.cpp index 10367dae7..b41bd6d4b 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -151,6 +151,11 @@ void CallPrivate::onCheckForAcceptation () { bctbx_list_free(copy); } +void CallPrivate::onDtmfReceived (char dtmf) { + L_Q(); + linphone_call_notify_dtmf_received(L_GET_C_BACK_PTR(q), dtmf); +} + void CallPrivate::onIncomingCallStarted () { L_Q(); linphone_core_notify_incoming_call(q->getCore()->getCCore(), L_GET_C_BACK_PTR(q)); @@ -228,6 +233,11 @@ LinphoneStatus Call::acceptUpdate (const MediaSessionParams *msp) { return static_cast(d->getActiveSession().get())->acceptUpdate(msp); } +void Call::cancelDtmfs () { + L_D(); + static_pointer_cast(d->getActiveSession())->cancelDtmfs(); +} + LinphoneStatus Call::decline (LinphoneReason reason) { L_D(); return d->getActiveSession()->decline(reason); @@ -258,6 +268,16 @@ LinphoneStatus Call::resume () { return static_cast(d->getActiveSession().get())->resume(); } +LinphoneStatus Call::sendDtmf (char dtmf) { + L_D(); + return static_pointer_cast(d->getActiveSession())->sendDtmf(dtmf); +} + +LinphoneStatus Call::sendDtmfs (const std::string &dtmfs) { + L_D(); + return static_pointer_cast(d->getActiveSession())->sendDtmfs(dtmfs); +} + void Call::sendVfuRequest () { L_D(); static_cast(d->getActiveSession().get())->sendVfuRequest(); diff --git a/src/call/call.h b/src/call/call.h index 755cb29cb..dad14d183 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -44,12 +44,15 @@ public: LinphoneStatus accept (const MediaSessionParams *msp = nullptr); LinphoneStatus acceptEarlyMedia (const MediaSessionParams *msp = nullptr); LinphoneStatus acceptUpdate (const MediaSessionParams *msp); + void cancelDtmfs (); LinphoneStatus decline (LinphoneReason reason); LinphoneStatus decline (const LinphoneErrorInfo *ei); void oglRender () const; LinphoneStatus pause (); LinphoneStatus redirect (const std::string &redirectUri); LinphoneStatus resume (); + LinphoneStatus sendDtmf (char dtmf); + LinphoneStatus sendDtmfs (const std::string &dtmfs); void sendVfuRequest (); void startRecording (); void stopRecording (); diff --git a/src/conference/conference.cpp b/src/conference/conference.cpp index 5d50eaa6f..384611bb9 100644 --- a/src/conference/conference.cpp +++ b/src/conference/conference.cpp @@ -164,6 +164,12 @@ void Conference::onCheckForAcceptation (const shared_ptr &ses d->callListener->onCheckForAcceptation(); } +void Conference::onDtmfReceived (const std::shared_ptr &session, char dtmf) { + L_D(); + if (d->callListener) + d->callListener->onDtmfReceived(dtmf); +} + void Conference::onIncomingCallSessionStarted (const shared_ptr &session) { L_D(); if (d->callListener) diff --git a/src/conference/conference.h b/src/conference/conference.h index 2db432305..7c019e045 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -73,6 +73,7 @@ private: void onCallSessionSetTerminated (const std::shared_ptr &session) override; void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) override; void onCheckForAcceptation (const std::shared_ptr &session) override; + void onDtmfReceived (const std::shared_ptr &session, char dtmf) override; void onIncomingCallSessionStarted (const std::shared_ptr &session) override; void onInfoReceived (const std::shared_ptr &session, const LinphoneInfoMessage *im) override; void onEncryptionChanged (const std::shared_ptr &session, bool activated, const std::string &authToken) override; diff --git a/src/conference/session/call-session-listener.h b/src/conference/session/call-session-listener.h index 0259138dd..7ac9b231e 100644 --- a/src/conference/session/call-session-listener.h +++ b/src/conference/session/call-session-listener.h @@ -37,6 +37,7 @@ public: virtual void onCallSessionSetTerminated (const std::shared_ptr &session) = 0; virtual void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) = 0; virtual void onCheckForAcceptation (const std::shared_ptr &session) = 0; + virtual void onDtmfReceived (const std::shared_ptr &session, char dtmf) = 0; virtual void onIncomingCallSessionStarted (const std::shared_ptr &session) = 0; virtual void onInfoReceived (const std::shared_ptr &session, const LinphoneInfoMessage *im) = 0; diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index efcb27718..b93335ca3 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -132,14 +132,6 @@ void CallSessionPrivate::setState(LinphoneCallState newState, const string &mess break; } - if (newState != LinphoneCallStreamsRunning) { -#if 0 // TODO - if (call->dtmfs_timer!=NULL){ - /*cancelling DTMF sequence, if any*/ - linphone_call_cancel_dtmfs(call); - } -#endif - } if (message.empty()) { lError() << "You must fill a reason when changing call state (from " << linphone_call_state_to_string(prevState) << " to " << linphone_call_state_to_string(state) << ")"; diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index b0d9d942a..0514faea2 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -44,10 +44,12 @@ public: void accepted () override; void ackReceived (LinphoneHeaders *headers) override; + void dtmfReceived (char dtmf); bool failure () override; void pausedByRemote (); void remoteRinging () override; void resumed (); + void telephoneEventReceived (int event); void terminated () override; void updated (bool isUpdate); void updating (bool isUpdate) override; @@ -93,14 +95,14 @@ public: private: static OrtpJitterBufferAlgorithm jitterBufferNameToAlgo (const std::string &name); - #ifdef VIDEO_ENABLED - static void videoStreamEventCb (void *userData, const MSFilter *f, const unsigned int eventId, const void *args); - #endif // ifdef VIDEO_ENABLED - #ifdef TEST_EXT_RENDERER - static void extRendererCb (void *userData, const MSPicture *local, const MSPicture *remote); - #endif // ifdef TEST_EXT_RENDERER +#ifdef VIDEO_ENABLED + static void videoStreamEventCb (void *userData, const MSFilter *f, const unsigned int eventId, const void *args); +#endif // ifdef VIDEO_ENABLED +#ifdef TEST_EXT_RENDERER + static void extRendererCb (void *userData, const MSPicture *local, const MSPicture *remote); +#endif // ifdef TEST_EXT_RENDERER static void realTimeTextCharacterReceived (void *userData, MSFilter *f, unsigned int id, void *arg); - + static int sendDtmf (void *data, unsigned int revents); static float aggregateQualityRatings (float audioRating, float videoRating); std::shared_ptr getMe () const; @@ -241,10 +243,11 @@ private: void refreshSockets (); void reinviteToRecoverFromConnectionLoss () override; - #ifdef VIDEO_ENABLED - void videoStreamEventCb (const MSFilter *f, const unsigned int eventId, const void *args); - #endif // ifdef VIDEO_ENABLED +#ifdef VIDEO_ENABLED + void videoStreamEventCb (const MSFilter *f, const unsigned int eventId, const void *args); +#endif // ifdef VIDEO_ENABLED void realTimeTextCharacterReceived (MSFilter *f, unsigned int id, void *arg); + int sendDtmf (); void stunAuthRequestedCb (const char *realm, const char *nonce, const char **username, const char **password, const char **ha1); @@ -283,6 +286,9 @@ private: // The address family to prefer for RTP path, guessed from signaling path. int af; + std::string dtmfSequence; + belle_sip_source_t *dtmfTimer = nullptr; + std::string mediaLocalIp; PortConfig mediaPorts[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; bool needMediaLocalIpRefresh = false; diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 8b8ed3962..c08df5b41 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -28,6 +28,7 @@ #include "conference/params/media-session-params-p.h" #include "conference/session/media-session.h" #include "core/core.h" +#include "sal/sal.h" #include "utils/payload-type-handler.h" #include "logger/logger.h" @@ -194,6 +195,12 @@ void MediaSessionPrivate::ackReceived (LinphoneHeaders *headers) { } } +void MediaSessionPrivate::dtmfReceived (char dtmf) { + L_Q(); + if (listener) + listener->onDtmfReceived(q->getSharedFromThis(), dtmf); +} + bool MediaSessionPrivate::failure () { L_Q(); const SalErrorInfo *ei = op->get_error_info(); @@ -323,6 +330,15 @@ void MediaSessionPrivate::resumed () { acceptUpdate(nullptr, LinphoneCallStreamsRunning, "Connected (streams running)"); } +void MediaSessionPrivate::telephoneEventReceived (int event) { + static char dtmfTab[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '#', 'A', 'B', 'C', 'D' }; + if ((event < 0) || (event > 15)) { + lWarning() << "Bad dtmf value " << event; + return; + } + dtmfReceived(dtmfTab[event]); +} + void MediaSessionPrivate::terminated () { stopStreams(); CallSessionPrivate::terminated(); @@ -577,6 +593,11 @@ void MediaSessionPrivate::realTimeTextCharacterReceived (void *userData, MSFilte msp->realTimeTextCharacterReceived(f, id, arg); } +int MediaSessionPrivate::sendDtmf (void *data, unsigned int revents) { + MediaSession *session = reinterpret_cast(data); + return session->getPrivate()->sendDtmf(); +} + // ----------------------------------------------------------------------------- float MediaSessionPrivate::aggregateQualityRatings (float audioRating, float videoRating) { @@ -607,6 +628,8 @@ void MediaSessionPrivate::setState (LinphoneCallState newState, const string &me L_Q(); /* Take a ref on the session otherwise it might get destroyed during the call to setState */ shared_ptr sessionRef = q->getSharedFromThis(); + if ((newState != state) && (newState != LinphoneCallStreamsRunning)) + q->cancelDtmfs(); CallSessionPrivate::setState(newState, message); updateReportingCallState(); } @@ -2194,9 +2217,7 @@ void MediaSessionPrivate::handleStreamEvents (int streamIndex) { if (ms) handleIceEvents(ev); } else if (evt == ORTP_EVENT_TELEPHONE_EVENT) { -#if 0 - linphone_core_dtmf_received(call, evd->info.telephone_event); -#endif + telephoneEventReceived(evd->info.telephone_event); } else if (evt == ORTP_EVENT_NEW_VIDEO_BANDWIDTH_ESTIMATION_AVAILABLE) { lInfo() << "Video bandwidth estimation is " << (int)(evd->info.video_bandwidth_available / 1000.) << " kbit/s"; // TODO @@ -4016,6 +4037,34 @@ void MediaSessionPrivate::realTimeTextCharacterReceived (MSFilter *f, unsigned i } } +int MediaSessionPrivate::sendDtmf () { + L_Q(); + LinphoneCore *lc = q->getCore()->getCCore(); + // By default we send DTMF RFC2833 if we do not have enabled SIP_INFO but we can also send RFC2833 and SIP_INFO + if (linphone_core_get_use_rfc2833_for_dtmf(lc) || !linphone_core_get_use_info_for_dtmf(lc)) { + // In Band DTMF + if (audioStream) + audio_stream_send_dtmf(audioStream, dtmfSequence.front()); + else { + lError() << "Cannot send RFC2833 DTMF when we are not in communication"; + return FALSE; + } + } + if (linphone_core_get_use_info_for_dtmf(lc)) { + // Out of Band DTMF (use INFO method) + op->send_dtmf(dtmfSequence.front()); + } + + dtmfSequence.erase(0, 1); + // Continue only if the dtmf sequence is not empty + if (!dtmfSequence.empty()) + return TRUE; + else { + q->cancelDtmfs(); + return FALSE; + } +} + // ----------------------------------------------------------------------------- void MediaSessionPrivate::stunAuthRequestedCb (const char *realm, const char *nonce, const char **username, const char **password, const char **ha1) { @@ -4094,6 +4143,7 @@ MediaSession::MediaSession (const shared_ptr &core, shared_ptraudioStats) linphone_call_stats_unref(d->audioStats); if (d->videoStats) @@ -4176,7 +4226,16 @@ LinphoneStatus MediaSession::acceptUpdate (const MediaSessionParams *msp) { return CallSession::acceptUpdate(msp); } -// ----------------------------------------------------------------------------- +void MediaSession::cancelDtmfs () { + L_D(); + if (!d->dtmfTimer) + return; + + getCore()->getCCore()->sal->cancel_timer(d->dtmfTimer); + belle_sip_object_unref(d->dtmfTimer); + d->dtmfTimer = nullptr; + d->dtmfSequence.clear(); +} void MediaSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalCallOp *op, const Address &from, const Address &to) { L_D(); @@ -4316,6 +4375,27 @@ LinphoneStatus MediaSession::resume () { return 0; } +LinphoneStatus MediaSession::sendDtmf (char dtmf) { + L_D(); + d->dtmfSequence = dtmf; + d->sendDtmf(); + return 0; +} + +LinphoneStatus MediaSession::sendDtmfs (const std::string &dtmfs) { + L_D(); + if (d->dtmfTimer) { + lWarning() << "MediaSession::sendDtmfs(): a DTMF sequence is already in place, canceling DTMF sequence"; + return -2; + } + if (!dtmfs.empty()) { + int delayMs = lp_config_get_int(linphone_core_get_config(getCore()->getCCore()), "net", "dtmf_delay_ms", 200); + d->dtmfSequence = dtmfs; + d->dtmfTimer = getCore()->getCCore()->sal->create_timer(MediaSessionPrivate::sendDtmf, this, delayMs, "DTMF sequence timer"); + } + return 0; +} + void MediaSession::sendVfuRequest () { #ifdef VIDEO_ENABLED L_D(); diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index 046101931..59688f4db 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -45,12 +45,15 @@ public: LinphoneStatus accept (const MediaSessionParams *msp = nullptr); LinphoneStatus acceptEarlyMedia (const MediaSessionParams *msp = nullptr); LinphoneStatus acceptUpdate (const MediaSessionParams *msp); + void cancelDtmfs (); void configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalCallOp *op, const Address &from, const Address &to) override; void initiateIncoming () override; bool initiateOutgoing () override; void iterate (time_t currentRealTime, bool oneSecondElapsed) override; LinphoneStatus pause (); LinphoneStatus resume (); + LinphoneStatus sendDtmf (char dtmf); + LinphoneStatus sendDtmfs (const std::string &dtmfs); void sendVfuRequest (); void startIncomingNotification () override; int startInvite (const Address *destination, const std::string &subject = "", const Content *content = nullptr) override; From 578a88e55237841396615f1e0c57cdb878decf61 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 7 Dec 2017 10:23:42 +0100 Subject: [PATCH 1017/2215] Fixed build --- src/conference/session/media-session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index c08df5b41..5fdc948f6 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -4389,7 +4389,7 @@ LinphoneStatus MediaSession::sendDtmfs (const std::string &dtmfs) { return -2; } if (!dtmfs.empty()) { - int delayMs = lp_config_get_int(linphone_core_get_config(getCore()->getCCore()), "net", "dtmf_delay_ms", 200); + unsigned int delayMs = lp_config_get_int(linphone_core_get_config(getCore()->getCCore()), "net", "dtmf_delay_ms", 200); d->dtmfSequence = dtmfs; d->dtmfTimer = getCore()->getCCore()->sal->create_timer(MediaSessionPrivate::sendDtmf, this, delayMs, "DTMF sequence timer"); } From 6cd4752bdf335c90c18de7fe32d8c636ae152b89 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 7 Dec 2017 10:28:48 +0100 Subject: [PATCH 1018/2215] Fixed signedness conversion issue --- src/conference/session/media-session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 5fdc948f6..6d27e967b 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -4389,7 +4389,7 @@ LinphoneStatus MediaSession::sendDtmfs (const std::string &dtmfs) { return -2; } if (!dtmfs.empty()) { - unsigned int delayMs = lp_config_get_int(linphone_core_get_config(getCore()->getCCore()), "net", "dtmf_delay_ms", 200); + unsigned int delayMs = (unsigned int) lp_config_get_int(linphone_core_get_config(getCore()->getCCore()), "net", "dtmf_delay_ms", 200); d->dtmfSequence = dtmfs; d->dtmfTimer = getCore()->getCCore()->sal->create_timer(MediaSessionPrivate::sendDtmf, this, delayMs, "DTMF sequence timer"); } From a1dc06d352a3dd861a98b56e6a7c0530eaba1000 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 7 Dec 2017 10:53:39 +0100 Subject: [PATCH 1019/2215] fix(MainDb): use a shared timestamp type for sqlite3 and MySql --- src/db/abstract/abstract-db.cpp | 14 ++++++++++++++ src/db/abstract/abstract-db.h | 2 ++ src/db/main-db.cpp | 8 ++++---- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/db/abstract/abstract-db.cpp b/src/db/abstract/abstract-db.cpp index 3f58b5251..1193720d4 100644 --- a/src/db/abstract/abstract-db.cpp +++ b/src/db/abstract/abstract-db.cpp @@ -123,6 +123,20 @@ string AbstractDb::primaryKeyRefStr (const string &type) const { return ""; } +string AbstractDb::timestampType () const { + L_D(); + + switch (d->backend) { + case Mysql: + return " TIMESTAMP"; + case Sqlite3: + return " DATE"; + } + + L_ASSERT(false); + return ""; +} + long long AbstractDb::getLastInsertId () const { long long id = 0; diff --git a/src/db/abstract/abstract-db.h b/src/db/abstract/abstract-db.h index 9987d9647..2d1ab1020 100644 --- a/src/db/abstract/abstract-db.h +++ b/src/db/abstract/abstract-db.h @@ -54,6 +54,8 @@ protected: std::string primaryKeyStr (const std::string &type = "INT") const; std::string primaryKeyRefStr (const std::string &type = "INT") const; + std::string timestampType () const; + long long getLastInsertId () const; void enableForeignKeys (bool status); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 61a623279..9ed69e167 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -1006,7 +1006,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), "CREATE TABLE IF NOT EXISTS event (" " id" + primaryKeyStr("BIGINT UNSIGNED") + "," " type TINYINT UNSIGNED NOT NULL," - " creation_time TIMESTAMP NOT NULL" + " creation_time" + timestampType() + " NOT NULL" ") " + charset; *session << @@ -1019,10 +1019,10 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " local_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," // Dialog creation time. - " creation_time TIMESTAMP NOT NULL," + " creation_time" + timestampType() + " NOT NULL," // Last event time (call, message...). - " last_update_time TIMESTAMP NOT NULL," + " last_update_time" + timestampType() + " NOT NULL," // ConferenceChatRoom, BasicChatRoom, RTT... " capabilities TINYINT UNSIGNED NOT NULL," @@ -1149,7 +1149,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), " from_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," " to_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL," - " time TIMESTAMP," + " time" + timestampType() + " ," // See: https://tools.ietf.org/html/rfc5438#section-6.3 " imdn_message_id VARCHAR(255) NOT NULL," From 65d98ad4d25a051da9196735ccd423e80f8c285b Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 7 Dec 2017 14:07:04 +0100 Subject: [PATCH 1020/2215] fix(MainDb): update correctly last update time on chat room in import case --- src/db/main-db-p.h | 2 +- src/db/main-db.cpp | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 5e9041436..29a681d58 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -53,7 +53,7 @@ private: long long insertSipAddress (const std::string &sipAddress); void insertContent (long long messageEventId, const Content &content); long long insertContentType (const std::string &contentType); - long long insertBasicChatRoom ( + long long insertOrUpdateBasicChatRoom ( long long peerSipAddressId, long long localSipAddressId, const tm &creationTime diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 9ed69e167..b7d863467 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -190,7 +190,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), return q->getLastInsertId(); } - long long MainDbPrivate::insertBasicChatRoom ( + long long MainDbPrivate::insertOrUpdateBasicChatRoom ( long long peerSipAddressId, long long localSipAddressId, const tm &creationTime @@ -200,8 +200,11 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), soci::session *session = dbSession.getBackendSession(); long long id = selectChatRoomId(peerSipAddressId, localSipAddressId); - if (id >= 0) + if (id >= 0) { + *session << "UPDATE chat_room SET last_update_time = :lastUpdateTime WHERE id = :id", + soci::use(creationTime), soci::use(id); return id; + } static const int capabilities = static_cast(ChatRoom::Capabilities::Basic); lInfo() << "Insert new chat room in database: (peer=" << peerSipAddressId << @@ -2244,7 +2247,7 @@ MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), const long long &eventId = getLastInsertId(); const long long &localSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_LOCAL_ADDRESS)); const long long &remoteSipAddressId = d->insertSipAddress(message.get(LEGACY_MESSAGE_COL_REMOTE_ADDRESS)); - const long long &chatRoomId = d->insertBasicChatRoom( + const long long &chatRoomId = d->insertOrUpdateBasicChatRoom( remoteSipAddressId, localSipAddressId, creationTime From b03061b65b97a3f53d4e32c7e3913b3544b51727 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 7 Dec 2017 14:57:34 +0100 Subject: [PATCH 1021/2215] feat(tester): add new db test --- tester/db/linphone.db | Bin 3905536 -> 4382720 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tester/db/linphone.db b/tester/db/linphone.db index 7775bed9c9bc95664051382a63501ebff8522f4b..234a43bca624671509132e4570e8e9f48ea7d148 100644 GIT binary patch literal 4382720 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%0AC+T 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¿yIjn@FzNdV{zTqfSnQh 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

      bM_z+o^vnO?3vS-5 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 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 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 z0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb z1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ! z5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^ zNI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndv zAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnw zfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz z0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8< z2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|Drd zBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J- zkbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(T zKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU z0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb z1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ! z5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^ zNI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndv zAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnw zfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz z0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8< z2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|Drd zBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J- zkbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(T zKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU z0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb z1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ! z5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^ zNI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndv zAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnw zfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz z0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8< z2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|Drd zBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J- zkbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(T zKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU z0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb z1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ! z5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^ zNI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndv zAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnw zfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz z0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8< z2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|Drd zBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J- zkbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(T zKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU z0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb z1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ! z5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^ zNI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndv zAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnw zfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz z0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8< z2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|Drd zBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J- zkbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(T 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